xref: /openbmc/qemu/hw/pci-host/astro.c (revision ba7d12eb)
1e029bb00SHelge Deller /*
2e029bb00SHelge Deller  * HP-PARISC Astro/Pluto/Ike/REO system bus adapter (SBA)
3e029bb00SHelge Deller  * with Elroy PCI bus (LBA) adapter emulation
4e029bb00SHelge Deller  * Found in C3000 and similar machines
5e029bb00SHelge Deller  *
6e029bb00SHelge Deller  * (C) 2023 by Helge Deller <deller@gmx.de>
7e029bb00SHelge Deller  *
8e029bb00SHelge Deller  * This work is licensed under the GNU GPL license version 2 or later.
9e029bb00SHelge Deller  *
10e029bb00SHelge Deller  * Chip documentation is available at:
11e029bb00SHelge Deller  * https://parisc.wiki.kernel.org/index.php/Technical_Documentation
12e029bb00SHelge Deller  *
13e029bb00SHelge Deller  * TODO:
14e029bb00SHelge Deller  * - All user-added devices are currently attached to the first
15e029bb00SHelge Deller  *   Elroy (PCI bus) only for now. To fix this additional work in
16e029bb00SHelge Deller  *   SeaBIOS and this driver is needed. See "user_creatable" flag below.
17e029bb00SHelge Deller  * - GMMIO (Greater than 4 GB MMIO) register
18e029bb00SHelge Deller  */
19e029bb00SHelge Deller 
20e029bb00SHelge Deller #define TYPE_ASTRO_IOMMU_MEMORY_REGION "astro-iommu-memory-region"
21e029bb00SHelge Deller 
22e029bb00SHelge Deller #include "qemu/osdep.h"
23e029bb00SHelge Deller #include "qemu/module.h"
24e029bb00SHelge Deller #include "qemu/units.h"
25e029bb00SHelge Deller #include "qapi/error.h"
26e029bb00SHelge Deller #include "hw/irq.h"
27e029bb00SHelge Deller #include "hw/pci/pci_device.h"
28e029bb00SHelge Deller #include "hw/pci/pci_bus.h"
29e029bb00SHelge Deller #include "hw/qdev-properties.h"
30e029bb00SHelge Deller #include "hw/pci-host/astro.h"
31e029bb00SHelge Deller #include "hw/hppa/hppa_hardware.h"
32e029bb00SHelge Deller #include "migration/vmstate.h"
33e029bb00SHelge Deller #include "trace.h"
34e029bb00SHelge Deller #include "qom/object.h"
35e029bb00SHelge Deller 
36e029bb00SHelge Deller /*
37e029bb00SHelge Deller  * Helper functions
38e029bb00SHelge Deller  */
39e029bb00SHelge Deller 
40e029bb00SHelge Deller static uint64_t mask_32bit_val(hwaddr addr, unsigned size, uint64_t val)
41e029bb00SHelge Deller {
42e029bb00SHelge Deller     if (size == 8) {
43e029bb00SHelge Deller         return val;
44e029bb00SHelge Deller     }
45e029bb00SHelge Deller     if (addr & 4) {
46e029bb00SHelge Deller         val >>= 32;
47e029bb00SHelge Deller     } else {
48e029bb00SHelge Deller         val = (uint32_t) val;
49e029bb00SHelge Deller     }
50e029bb00SHelge Deller     return val;
51e029bb00SHelge Deller }
52e029bb00SHelge Deller 
53e029bb00SHelge Deller static void put_val_in_int64(uint64_t *p, hwaddr addr, unsigned size,
54e029bb00SHelge Deller                              uint64_t val)
55e029bb00SHelge Deller {
56e029bb00SHelge Deller     if (size == 8) {
57e029bb00SHelge Deller         *p = val;
58e029bb00SHelge Deller     } else if (size == 4) {
59e029bb00SHelge Deller         if (addr & 4) {
60e029bb00SHelge Deller             *p = ((*p << 32) >> 32) | (val << 32);
61e029bb00SHelge Deller         } else {
62e029bb00SHelge Deller             *p = ((*p >> 32) << 32) | (uint32_t) val;
63e029bb00SHelge Deller         }
64e029bb00SHelge Deller     }
65e029bb00SHelge Deller }
66e029bb00SHelge Deller 
67e029bb00SHelge Deller static void put_val_in_arrary(uint64_t *array, hwaddr start_addr,
68e029bb00SHelge Deller                               hwaddr addr, unsigned size, uint64_t val)
69e029bb00SHelge Deller {
70e029bb00SHelge Deller     int index;
71e029bb00SHelge Deller 
72e029bb00SHelge Deller     index = (addr - start_addr) / 8;
73e029bb00SHelge Deller     put_val_in_int64(&array[index], addr, size, val);
74e029bb00SHelge Deller }
75e029bb00SHelge Deller 
76e029bb00SHelge Deller 
77e029bb00SHelge Deller /*
78e029bb00SHelge Deller  * The Elroy PCI host bridge. We have at least 4 of those under Astro.
79e029bb00SHelge Deller  */
80e029bb00SHelge Deller 
81e029bb00SHelge Deller static MemTxResult elroy_chip_read_with_attrs(void *opaque, hwaddr addr,
82e029bb00SHelge Deller                                              uint64_t *data, unsigned size,
83e029bb00SHelge Deller                                              MemTxAttrs attrs)
84e029bb00SHelge Deller {
85e029bb00SHelge Deller     MemTxResult ret = MEMTX_OK;
86e029bb00SHelge Deller     ElroyState *s = opaque;
87e029bb00SHelge Deller     uint64_t val = -1;
88e029bb00SHelge Deller     int index;
89e029bb00SHelge Deller 
90e029bb00SHelge Deller     switch ((addr >> 3) << 3) {
91e029bb00SHelge Deller     case 0x0008:
92e029bb00SHelge Deller         val = 0x6000005; /* func_class */
93e029bb00SHelge Deller         break;
94e029bb00SHelge Deller     case 0x0058:
95e029bb00SHelge Deller         /*
96e029bb00SHelge Deller          * Scratch register, but firmware initializes it with the
97e029bb00SHelge Deller          * PCI BUS number and Linux/HP-UX uses it then.
98e029bb00SHelge Deller          */
99e029bb00SHelge Deller         val = s->pci_bus_num;
100e029bb00SHelge Deller         /* Upper byte holds the end of this bus number */
101e029bb00SHelge Deller         val |= s->pci_bus_num << 8;
102e029bb00SHelge Deller         break;
103e029bb00SHelge Deller     case 0x0080:
104e029bb00SHelge Deller         val = s->arb_mask; /* set ARB mask */
105e029bb00SHelge Deller         break;
106e029bb00SHelge Deller     case 0x0108:
107e029bb00SHelge Deller         val = s->status_control;
108e029bb00SHelge Deller         break;
109e029bb00SHelge Deller     case 0x200 ... 0x250 - 1: /* LMMIO, GMMIO, WLMMIO, WGMMIO, ... */
110e029bb00SHelge Deller         index = (addr - 0x200) / 8;
111e029bb00SHelge Deller         val = s->mmio_base[index];
112e029bb00SHelge Deller         break;
113e029bb00SHelge Deller     case 0x0680:
114e029bb00SHelge Deller         val = s->error_config;
115e029bb00SHelge Deller         break;
116e029bb00SHelge Deller     case 0x0688:
117e029bb00SHelge Deller         val = 0;                /* ERROR_STATUS */
118e029bb00SHelge Deller         break;
119e029bb00SHelge Deller     case 0x0800:                /* IOSAPIC_REG_SELECT */
120e029bb00SHelge Deller         val = s->iosapic_reg_select;
121e029bb00SHelge Deller         break;
122e029bb00SHelge Deller     case 0x0808:
123e029bb00SHelge Deller         val = UINT64_MAX;            /* XXX: tbc. */
124e029bb00SHelge Deller         g_assert_not_reached();
125e029bb00SHelge Deller         break;
126e029bb00SHelge Deller     case 0x0810:                /* IOSAPIC_REG_WINDOW */
127e029bb00SHelge Deller         switch (s->iosapic_reg_select) {
128e029bb00SHelge Deller         case 0x01:              /* IOSAPIC_REG_VERSION */
129e029bb00SHelge Deller             val = (32 << 16) | 1; /* upper 16bit holds max entries */
130e029bb00SHelge Deller             break;
131e029bb00SHelge Deller         default:
132e029bb00SHelge Deller             if (s->iosapic_reg_select < ARRAY_SIZE(s->iosapic_reg)) {
133e029bb00SHelge Deller                 val = s->iosapic_reg[s->iosapic_reg_select];
134e029bb00SHelge Deller             } else {
135e029bb00SHelge Deller                 trace_iosapic_reg_read(s->iosapic_reg_select, size, val);
136e029bb00SHelge Deller                 g_assert_not_reached();
137e029bb00SHelge Deller             }
138e029bb00SHelge Deller         }
139e029bb00SHelge Deller         trace_iosapic_reg_read(s->iosapic_reg_select, size, val);
140e029bb00SHelge Deller         break;
141e029bb00SHelge Deller     default:
142e029bb00SHelge Deller         trace_elroy_read(addr, size, val);
143e029bb00SHelge Deller         g_assert_not_reached();
144e029bb00SHelge Deller     }
145e029bb00SHelge Deller     trace_elroy_read(addr, size, val);
146e029bb00SHelge Deller 
147e029bb00SHelge Deller     /* for 32-bit accesses mask return value */
148e029bb00SHelge Deller     val = mask_32bit_val(addr, size, val);
149e029bb00SHelge Deller 
150e029bb00SHelge Deller     trace_astro_chip_read(addr, size, val);
151e029bb00SHelge Deller     *data = val;
152e029bb00SHelge Deller     return ret;
153e029bb00SHelge Deller }
154e029bb00SHelge Deller 
155e029bb00SHelge Deller 
156e029bb00SHelge Deller static MemTxResult elroy_chip_write_with_attrs(void *opaque, hwaddr addr,
157e029bb00SHelge Deller                                               uint64_t val, unsigned size,
158e029bb00SHelge Deller                                               MemTxAttrs attrs)
159e029bb00SHelge Deller {
160e029bb00SHelge Deller     ElroyState *s = opaque;
161e029bb00SHelge Deller     int i;
162e029bb00SHelge Deller 
163e029bb00SHelge Deller     trace_elroy_write(addr, size, val);
164e029bb00SHelge Deller 
165e029bb00SHelge Deller     switch ((addr >> 3) << 3) {
166e029bb00SHelge Deller     case 0x080:
167e029bb00SHelge Deller         put_val_in_int64(&s->arb_mask, addr, size, val);
168e029bb00SHelge Deller         break;
169e029bb00SHelge Deller     case 0x0108:
170e029bb00SHelge Deller         put_val_in_int64(&s->status_control, addr, size, val);
171e029bb00SHelge Deller         break;
172e029bb00SHelge Deller     case 0x200 ... 0x250 - 1:   /* LMMIO, GMMIO, WLMMIO, WGMMIO, ... */
173e029bb00SHelge Deller         put_val_in_arrary(s->mmio_base, 0x200, addr, size, val);
174e029bb00SHelge Deller         break;
175e029bb00SHelge Deller     case 0x0680:
176e029bb00SHelge Deller         put_val_in_int64(&s->error_config, addr, size, val);
177e029bb00SHelge Deller         break;
178e029bb00SHelge Deller     case 0x0800:                /* IOSAPIC_REG_SELECT */
179e029bb00SHelge Deller         s->iosapic_reg_select = val;
180e029bb00SHelge Deller         break;
181e029bb00SHelge Deller     case 0x0810:                /* IOSAPIC_REG_WINDOW */
182e029bb00SHelge Deller         trace_iosapic_reg_write(s->iosapic_reg_select, size, val);
183e029bb00SHelge Deller         if (s->iosapic_reg_select < ARRAY_SIZE(s->iosapic_reg)) {
184e029bb00SHelge Deller             s->iosapic_reg[s->iosapic_reg_select] = val;
185e029bb00SHelge Deller         } else {
186e029bb00SHelge Deller             g_assert_not_reached();
187e029bb00SHelge Deller         }
188e029bb00SHelge Deller         break;
189e029bb00SHelge Deller     case 0x0840:                /* IOSAPIC_REG_EOI */
190e029bb00SHelge Deller         val = le64_to_cpu(val);
191e029bb00SHelge Deller         val &= 63;
192e029bb00SHelge Deller         for (i = 0; i < ELROY_IRQS; i++) {
193e029bb00SHelge Deller             if ((s->iosapic_reg[0x10 + 2 * i] & 63) == val) {
194e029bb00SHelge Deller                 s->ilr &= ~(1ull << i);
195e029bb00SHelge Deller             }
196e029bb00SHelge Deller         }
197e029bb00SHelge Deller         break;
198e029bb00SHelge Deller     default:
199e029bb00SHelge Deller         g_assert_not_reached();
200e029bb00SHelge Deller     }
201e029bb00SHelge Deller     return MEMTX_OK;
202e029bb00SHelge Deller }
203e029bb00SHelge Deller 
204e029bb00SHelge Deller static const MemoryRegionOps elroy_chip_ops = {
205e029bb00SHelge Deller     .read_with_attrs = elroy_chip_read_with_attrs,
206e029bb00SHelge Deller     .write_with_attrs = elroy_chip_write_with_attrs,
207e029bb00SHelge Deller     .endianness = DEVICE_LITTLE_ENDIAN,
208e029bb00SHelge Deller     .valid = {
209e029bb00SHelge Deller         .min_access_size = 4,
210e029bb00SHelge Deller         .max_access_size = 8,
211e029bb00SHelge Deller     },
212e029bb00SHelge Deller     .impl = {
213e029bb00SHelge Deller         .min_access_size = 4,
214e029bb00SHelge Deller         .max_access_size = 8,
215e029bb00SHelge Deller     },
216e029bb00SHelge Deller };
217e029bb00SHelge Deller 
218e029bb00SHelge Deller 
219e029bb00SHelge Deller /* Unlike pci_config_data_le_ops, no check of high bit set in config_reg.  */
220e029bb00SHelge Deller 
221e029bb00SHelge Deller static uint64_t elroy_config_data_read(void *opaque, hwaddr addr, unsigned len)
222e029bb00SHelge Deller {
223e029bb00SHelge Deller     uint64_t val;
224e029bb00SHelge Deller 
225e029bb00SHelge Deller     PCIHostState *s = opaque;
226e029bb00SHelge Deller     val = pci_data_read(s->bus, s->config_reg | (addr & 3), len);
227e029bb00SHelge Deller     trace_elroy_pci_config_data_read(s->config_reg | (addr & 3), len, val);
228e029bb00SHelge Deller     return val;
229e029bb00SHelge Deller }
230e029bb00SHelge Deller 
231e029bb00SHelge Deller static void elroy_config_data_write(void *opaque, hwaddr addr,
232e029bb00SHelge Deller                                    uint64_t val, unsigned len)
233e029bb00SHelge Deller {
234e029bb00SHelge Deller     PCIHostState *s = opaque;
235e029bb00SHelge Deller     pci_data_write(s->bus, s->config_reg | (addr & 3), val, len);
236e029bb00SHelge Deller     trace_elroy_pci_config_data_write(s->config_reg | (addr & 3), len, val);
237e029bb00SHelge Deller }
238e029bb00SHelge Deller 
239e029bb00SHelge Deller static const MemoryRegionOps elroy_config_data_ops = {
240e029bb00SHelge Deller     .read = elroy_config_data_read,
241e029bb00SHelge Deller     .write = elroy_config_data_write,
242e029bb00SHelge Deller     .endianness = DEVICE_LITTLE_ENDIAN,
243e029bb00SHelge Deller };
244e029bb00SHelge Deller 
245e029bb00SHelge Deller static uint64_t elroy_config_addr_read(void *opaque, hwaddr addr, unsigned len)
246e029bb00SHelge Deller {
247e029bb00SHelge Deller     ElroyState *s = opaque;
248e029bb00SHelge Deller     return s->config_reg_elroy;
249e029bb00SHelge Deller }
250e029bb00SHelge Deller 
251e029bb00SHelge Deller static void elroy_config_addr_write(void *opaque, hwaddr addr,
252e029bb00SHelge Deller                                    uint64_t val, unsigned len)
253e029bb00SHelge Deller {
254e029bb00SHelge Deller     PCIHostState *s = opaque;
255e029bb00SHelge Deller     ElroyState *es = opaque;
256e029bb00SHelge Deller     es->config_reg_elroy = val; /* keep a copy of original value */
257e029bb00SHelge Deller     s->config_reg = val;
258e029bb00SHelge Deller }
259e029bb00SHelge Deller 
260e029bb00SHelge Deller static const MemoryRegionOps elroy_config_addr_ops = {
261e029bb00SHelge Deller     .read = elroy_config_addr_read,
262e029bb00SHelge Deller     .write = elroy_config_addr_write,
263e029bb00SHelge Deller     .valid.min_access_size = 4,
264e029bb00SHelge Deller     .valid.max_access_size = 8,
265e029bb00SHelge Deller     .endianness = DEVICE_LITTLE_ENDIAN,
266e029bb00SHelge Deller };
267e029bb00SHelge Deller 
268e029bb00SHelge Deller 
269e029bb00SHelge Deller /*
270e029bb00SHelge Deller  * A subroutine of astro_translate_iommu that builds an IOMMUTLBEntry using the
271e029bb00SHelge Deller  * given translated address and mask.
272e029bb00SHelge Deller  */
273e029bb00SHelge Deller static bool make_iommu_tlbe(hwaddr addr, hwaddr taddr, hwaddr mask,
274e029bb00SHelge Deller                             IOMMUTLBEntry *ret)
275e029bb00SHelge Deller {
276e029bb00SHelge Deller     hwaddr tce_mask = ~((1ull << 12) - 1);
277e029bb00SHelge Deller     ret->target_as = &address_space_memory;
278e029bb00SHelge Deller     ret->iova = addr & tce_mask;
279e029bb00SHelge Deller     ret->translated_addr = taddr & tce_mask;
280e029bb00SHelge Deller     ret->addr_mask = ~tce_mask;
281e029bb00SHelge Deller     ret->perm = IOMMU_RW;
282e029bb00SHelge Deller     return true;
283e029bb00SHelge Deller }
284e029bb00SHelge Deller 
285e029bb00SHelge Deller /* Handle PCI-to-system address translation.  */
286e029bb00SHelge Deller static IOMMUTLBEntry astro_translate_iommu(IOMMUMemoryRegion *iommu,
287e029bb00SHelge Deller                                              hwaddr addr,
288e029bb00SHelge Deller                                              IOMMUAccessFlags flag,
289e029bb00SHelge Deller                                              int iommu_idx)
290e029bb00SHelge Deller {
291e029bb00SHelge Deller     AstroState *s = container_of(iommu, AstroState, iommu);
292e029bb00SHelge Deller     IOMMUTLBEntry ret = {
293e029bb00SHelge Deller         .target_as = &address_space_memory,
294e029bb00SHelge Deller         .iova = addr,
295e029bb00SHelge Deller         .translated_addr = 0,
296e029bb00SHelge Deller         .addr_mask = ~(hwaddr)0,
297e029bb00SHelge Deller         .perm = IOMMU_NONE,
298e029bb00SHelge Deller     };
299e029bb00SHelge Deller     hwaddr pdir_ptr, index, a, ibase;
300e029bb00SHelge Deller     hwaddr addr_mask = 0xfff; /* 4k translation */
301e029bb00SHelge Deller     uint64_t entry;
302e029bb00SHelge Deller 
303e029bb00SHelge Deller #define IOVP_SHIFT              12   /* equals PAGE_SHIFT */
304e029bb00SHelge Deller #define PDIR_INDEX(iovp)        ((iovp) >> IOVP_SHIFT)
305e029bb00SHelge Deller #define IOVP_MASK               PAGE_MASK
306e029bb00SHelge Deller #define SBA_PDIR_VALID_BIT      0x8000000000000000ULL
307e029bb00SHelge Deller 
308e029bb00SHelge Deller     /* "range enable" flag cleared? */
309e029bb00SHelge Deller     if ((s->tlb_ibase & 1) == 0) {
310e029bb00SHelge Deller         make_iommu_tlbe(addr, addr, addr_mask, &ret);
311e029bb00SHelge Deller         return ret;
312e029bb00SHelge Deller     }
313e029bb00SHelge Deller 
314e029bb00SHelge Deller     a = addr;
315e029bb00SHelge Deller     ibase = s->tlb_ibase & ~1ULL;
316e029bb00SHelge Deller     if ((a & s->tlb_imask) != ibase) {
317e029bb00SHelge Deller         /* do not translate this one! */
318e029bb00SHelge Deller         make_iommu_tlbe(addr, addr, addr_mask, &ret);
319e029bb00SHelge Deller         return ret;
320e029bb00SHelge Deller     }
321e029bb00SHelge Deller     index = PDIR_INDEX(a);
322e029bb00SHelge Deller     pdir_ptr = s->tlb_pdir_base + index * sizeof(entry);
323e029bb00SHelge Deller     entry = ldq_le_phys(&address_space_memory, pdir_ptr);
324e029bb00SHelge Deller     if (!(entry & SBA_PDIR_VALID_BIT)) { /* I/O PDIR entry valid ? */
325e029bb00SHelge Deller         g_assert_not_reached();
326e029bb00SHelge Deller         goto failure;
327e029bb00SHelge Deller     }
328e029bb00SHelge Deller     entry &= ~SBA_PDIR_VALID_BIT;
329e029bb00SHelge Deller     entry >>= IOVP_SHIFT;
330e029bb00SHelge Deller     entry <<= 12;
331e029bb00SHelge Deller     entry |= addr & 0xfff;
332e029bb00SHelge Deller     make_iommu_tlbe(addr, entry, addr_mask, &ret);
333e029bb00SHelge Deller     goto success;
334e029bb00SHelge Deller 
335e029bb00SHelge Deller  failure:
336e029bb00SHelge Deller     ret = (IOMMUTLBEntry) { .perm = IOMMU_NONE };
337e029bb00SHelge Deller  success:
338e029bb00SHelge Deller     return ret;
339e029bb00SHelge Deller }
340e029bb00SHelge Deller 
341e029bb00SHelge Deller static AddressSpace *elroy_pcihost_set_iommu(PCIBus *bus, void *opaque,
342e029bb00SHelge Deller                                             int devfn)
343e029bb00SHelge Deller {
344e029bb00SHelge Deller     ElroyState *s = opaque;
345e029bb00SHelge Deller     return &s->astro->iommu_as;
346e029bb00SHelge Deller }
347e029bb00SHelge Deller 
348*ba7d12ebSYi Liu static const PCIIOMMUOps elroy_pcihost_iommu_ops = {
349*ba7d12ebSYi Liu     .get_address_space = elroy_pcihost_set_iommu,
350*ba7d12ebSYi Liu };
351*ba7d12ebSYi Liu 
352e029bb00SHelge Deller /*
353e029bb00SHelge Deller  * Encoding in IOSAPIC:
354e029bb00SHelge Deller  * base_addr == 0xfffa0000, we want to get 0xa0ff0000.
355e029bb00SHelge Deller  * eid  0x0ff00000 -> 0x00ff0000
356e029bb00SHelge Deller  * id   0x000ff000 -> 0xff000000
357e029bb00SHelge Deller  */
358e029bb00SHelge Deller #define SWIZZLE_HPA(a) \
359e029bb00SHelge Deller         ((((a) & 0x0ff00000) >> 4) | (((a) & 0x000ff000) << 12))
360e029bb00SHelge Deller #define UNSWIZZLE_HPA(a) \
361e029bb00SHelge Deller         (((((a) << 4) & 0x0ff00000) | (((a) >> 12) & 0x000ff000) | 0xf0000000))
362e029bb00SHelge Deller 
363e029bb00SHelge Deller /* bits in the "low" I/O Sapic IRdT entry */
364e029bb00SHelge Deller #define IOSAPIC_IRDT_DISABLE      0x10000 /* if bit is set, mask this irq */
365e029bb00SHelge Deller #define IOSAPIC_IRDT_PO_LOW       0x02000
366e029bb00SHelge Deller #define IOSAPIC_IRDT_LEVEL_TRIG   0x08000
367e029bb00SHelge Deller #define IOSAPIC_IRDT_MODE_LPRI    0x00100
368e029bb00SHelge Deller 
369e029bb00SHelge Deller #define CPU_IRQ_OFFSET            2
370e029bb00SHelge Deller 
371e029bb00SHelge Deller static void elroy_set_irq(void *opaque, int irq, int level)
372e029bb00SHelge Deller {
373e029bb00SHelge Deller     ElroyState *s = opaque;
374e029bb00SHelge Deller     uint32_t bit;
375e029bb00SHelge Deller     uint32_t old_ilr = s->ilr;
376e029bb00SHelge Deller     hwaddr cpu_hpa;
377e029bb00SHelge Deller     uint32_t val;
378e029bb00SHelge Deller 
379e029bb00SHelge Deller     val     = s->iosapic_reg[0x10 + 2 * irq];
380e029bb00SHelge Deller     cpu_hpa = s->iosapic_reg[0x11 + 2 * irq];
381e029bb00SHelge Deller     /* low nibble of val has value to write into CPU irq reg */
382e029bb00SHelge Deller     bit     = 1u << (val & (ELROY_IRQS - 1));
383e029bb00SHelge Deller     cpu_hpa = UNSWIZZLE_HPA(cpu_hpa);
384e029bb00SHelge Deller 
385e029bb00SHelge Deller     if (level && (!(val & IOSAPIC_IRDT_DISABLE)) && cpu_hpa) {
386e029bb00SHelge Deller         uint32_t ena = bit & ~old_ilr;
387e029bb00SHelge Deller         s->ilr = old_ilr | bit;
388e029bb00SHelge Deller         if (ena != 0) {
389e029bb00SHelge Deller             stl_be_phys(&address_space_memory, cpu_hpa, val & 63);
390e029bb00SHelge Deller         }
391e029bb00SHelge Deller     } else {
392e029bb00SHelge Deller         s->ilr = old_ilr & ~bit;
393e029bb00SHelge Deller     }
394e029bb00SHelge Deller }
395e029bb00SHelge Deller 
396e029bb00SHelge Deller static int elroy_pci_map_irq(PCIDevice *d, int irq_num)
397e029bb00SHelge Deller {
398e029bb00SHelge Deller     int slot = PCI_SLOT(d->devfn);
399e029bb00SHelge Deller 
400e029bb00SHelge Deller     assert(irq_num >= 0 && irq_num < ELROY_IRQS);
401e029bb00SHelge Deller     return slot & (ELROY_IRQS - 1);
402e029bb00SHelge Deller }
403e029bb00SHelge Deller 
404e029bb00SHelge Deller static void elroy_reset(DeviceState *dev)
405e029bb00SHelge Deller {
406e029bb00SHelge Deller     ElroyState *s = ELROY_PCI_HOST_BRIDGE(dev);
407e029bb00SHelge Deller     int irq;
408e029bb00SHelge Deller 
409e029bb00SHelge Deller     /*
410e029bb00SHelge Deller      * Make sure to disable interrupts at reboot, otherwise the Linux kernel
411e029bb00SHelge Deller      * serial8250_config_port() in drivers/tty/serial/8250/8250_port.c
412e029bb00SHelge Deller      * will hang during autoconfig().
413e029bb00SHelge Deller      */
414e029bb00SHelge Deller     s->ilr = 0;
415e029bb00SHelge Deller     for (irq = 0; irq < ELROY_IRQS; irq++) {
416e029bb00SHelge Deller         s->iosapic_reg[0x10 + 2 * irq] = IOSAPIC_IRDT_PO_LOW |
417e029bb00SHelge Deller                 IOSAPIC_IRDT_LEVEL_TRIG | (irq + CPU_IRQ_OFFSET) |
418e029bb00SHelge Deller                 IOSAPIC_IRDT_DISABLE;
419e029bb00SHelge Deller         s->iosapic_reg[0x11 + 2 * irq] = SWIZZLE_HPA(CPU_HPA);
420e029bb00SHelge Deller     }
421e029bb00SHelge Deller }
422e029bb00SHelge Deller 
423e029bb00SHelge Deller static void elroy_pcihost_init(Object *obj)
424e029bb00SHelge Deller {
425e029bb00SHelge Deller     ElroyState *s = ELROY_PCI_HOST_BRIDGE(obj);
426e029bb00SHelge Deller     PCIHostState *phb = PCI_HOST_BRIDGE(obj);
427e029bb00SHelge Deller     SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
428e029bb00SHelge Deller 
429e029bb00SHelge Deller     /* Elroy config access from CPU.  */
430e029bb00SHelge Deller     memory_region_init_io(&s->this_mem, OBJECT(s), &elroy_chip_ops,
431e029bb00SHelge Deller                           s, "elroy", 0x2000);
432e029bb00SHelge Deller 
433e029bb00SHelge Deller     /* Elroy PCI config. */
434e029bb00SHelge Deller     memory_region_init_io(&phb->conf_mem, OBJECT(phb),
435e029bb00SHelge Deller                           &elroy_config_addr_ops, DEVICE(s),
436e029bb00SHelge Deller                           "pci-conf-idx", 8);
437e029bb00SHelge Deller     memory_region_init_io(&phb->data_mem, OBJECT(phb),
438e029bb00SHelge Deller                           &elroy_config_data_ops, DEVICE(s),
439e029bb00SHelge Deller                           "pci-conf-data", 8);
440e029bb00SHelge Deller     memory_region_add_subregion(&s->this_mem, 0x40,
441e029bb00SHelge Deller                                 &phb->conf_mem);
442e029bb00SHelge Deller     memory_region_add_subregion(&s->this_mem, 0x48,
443e029bb00SHelge Deller                                 &phb->data_mem);
444e029bb00SHelge Deller 
445e029bb00SHelge Deller     /* Elroy PCI bus memory.  */
446e029bb00SHelge Deller     memory_region_init(&s->pci_mmio, OBJECT(s), "pci-mmio", UINT64_MAX);
447e029bb00SHelge Deller     memory_region_init_io(&s->pci_io, OBJECT(s), &unassigned_io_ops, obj,
448e029bb00SHelge Deller                             "pci-isa-mmio",
449e029bb00SHelge Deller                             ((uint32_t) IOS_DIST_BASE_SIZE) / ROPES_PER_IOC);
450e029bb00SHelge Deller 
451e029bb00SHelge Deller     phb->bus = pci_register_root_bus(DEVICE(s), "pci",
452e029bb00SHelge Deller                                      elroy_set_irq, elroy_pci_map_irq, s,
453e029bb00SHelge Deller                                      &s->pci_mmio, &s->pci_io,
454e029bb00SHelge Deller                                      PCI_DEVFN(0, 0), ELROY_IRQS, TYPE_PCI_BUS);
455e029bb00SHelge Deller 
456e029bb00SHelge Deller     sysbus_init_mmio(sbd, &s->this_mem);
457e029bb00SHelge Deller 
458e029bb00SHelge Deller     qdev_init_gpio_in(DEVICE(obj), elroy_set_irq, ELROY_IRQS);
459e029bb00SHelge Deller }
460e029bb00SHelge Deller 
461e029bb00SHelge Deller static Property elroy_pcihost_properties[] = {
462e029bb00SHelge Deller     DEFINE_PROP_END_OF_LIST(),
463e029bb00SHelge Deller };
464e029bb00SHelge Deller 
465e029bb00SHelge Deller static const VMStateDescription vmstate_elroy = {
466e029bb00SHelge Deller     .name = "Elroy",
467e029bb00SHelge Deller     .version_id = 1,
468e029bb00SHelge Deller     .minimum_version_id = 1,
469e029bb00SHelge Deller     .fields = (VMStateField[]) {
470e029bb00SHelge Deller         VMSTATE_UINT64(hpa, ElroyState),
471e029bb00SHelge Deller         VMSTATE_UINT32(pci_bus_num, ElroyState),
472e029bb00SHelge Deller         VMSTATE_UINT64(config_address, ElroyState),
473e029bb00SHelge Deller         VMSTATE_UINT64(config_reg_elroy, ElroyState),
474e029bb00SHelge Deller         VMSTATE_UINT64(status_control, ElroyState),
475e029bb00SHelge Deller         VMSTATE_UINT64(arb_mask, ElroyState),
476e029bb00SHelge Deller         VMSTATE_UINT64_ARRAY(mmio_base, ElroyState, (0x0250 - 0x200) / 8),
477e029bb00SHelge Deller         VMSTATE_UINT64(error_config, ElroyState),
478e029bb00SHelge Deller         VMSTATE_UINT32(iosapic_reg_select, ElroyState),
479e029bb00SHelge Deller         VMSTATE_UINT64_ARRAY(iosapic_reg, ElroyState, 0x20),
480e029bb00SHelge Deller         VMSTATE_UINT32(ilr, ElroyState),
481e029bb00SHelge Deller         VMSTATE_END_OF_LIST()
482e029bb00SHelge Deller     }
483e029bb00SHelge Deller };
484e029bb00SHelge Deller 
485e029bb00SHelge Deller static void elroy_pcihost_class_init(ObjectClass *klass, void *data)
486e029bb00SHelge Deller {
487e029bb00SHelge Deller     DeviceClass *dc = DEVICE_CLASS(klass);
488e029bb00SHelge Deller 
489e029bb00SHelge Deller     dc->reset = elroy_reset;
490e029bb00SHelge Deller     device_class_set_props(dc, elroy_pcihost_properties);
491e029bb00SHelge Deller     dc->vmsd = &vmstate_elroy;
492e029bb00SHelge Deller     dc->user_creatable = false;
493e029bb00SHelge Deller }
494e029bb00SHelge Deller 
495e029bb00SHelge Deller static const TypeInfo elroy_pcihost_info = {
496e029bb00SHelge Deller     .name          = TYPE_ELROY_PCI_HOST_BRIDGE,
497e029bb00SHelge Deller     .parent        = TYPE_PCI_HOST_BRIDGE,
498e029bb00SHelge Deller     .instance_init = elroy_pcihost_init,
499e029bb00SHelge Deller     .instance_size = sizeof(ElroyState),
500e029bb00SHelge Deller     .class_init    = elroy_pcihost_class_init,
501e029bb00SHelge Deller };
502e029bb00SHelge Deller 
503e029bb00SHelge Deller static void elroy_register_types(void)
504e029bb00SHelge Deller {
505e029bb00SHelge Deller     type_register_static(&elroy_pcihost_info);
506e029bb00SHelge Deller }
507e029bb00SHelge Deller 
508e029bb00SHelge Deller type_init(elroy_register_types)
509e029bb00SHelge Deller 
510e029bb00SHelge Deller 
511e029bb00SHelge Deller static ElroyState *elroy_init(int num)
512e029bb00SHelge Deller {
513e029bb00SHelge Deller     DeviceState *dev;
514e029bb00SHelge Deller 
515e029bb00SHelge Deller     dev = qdev_new(TYPE_ELROY_PCI_HOST_BRIDGE);
516e029bb00SHelge Deller     dev->id = g_strdup_printf("elroy%d", num);
517e029bb00SHelge Deller     sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
518e029bb00SHelge Deller 
519e029bb00SHelge Deller     return ELROY_PCI_HOST_BRIDGE(dev);
520e029bb00SHelge Deller }
521e029bb00SHelge Deller 
522e029bb00SHelge Deller /*
523e029bb00SHelge Deller  * Astro Runway chip.
524e029bb00SHelge Deller  */
525e029bb00SHelge Deller 
526e029bb00SHelge Deller static MemTxResult astro_chip_read_with_attrs(void *opaque, hwaddr addr,
527e029bb00SHelge Deller                                              uint64_t *data, unsigned size,
528e029bb00SHelge Deller                                              MemTxAttrs attrs)
529e029bb00SHelge Deller {
530e029bb00SHelge Deller     AstroState *s = opaque;
531e029bb00SHelge Deller     MemTxResult ret = MEMTX_OK;
532e029bb00SHelge Deller     uint64_t val = -1;
533e029bb00SHelge Deller     int index;
534e029bb00SHelge Deller 
535e029bb00SHelge Deller     switch ((addr >> 3) << 3) {
536e029bb00SHelge Deller     /* R2I registers */
537e029bb00SHelge Deller     case 0x0000:        /* ID */
538e029bb00SHelge Deller         val = (0x01 << 3) | 0x01ULL;
539e029bb00SHelge Deller         break;
540e029bb00SHelge Deller     case 0x0008:        /* IOC_CTRL */
541e029bb00SHelge Deller         val = s->ioc_ctrl;
542e029bb00SHelge Deller         break;
543e029bb00SHelge Deller     case 0x0010:        /* TOC_CLIENT_ID */
544e029bb00SHelge Deller         break;
545e029bb00SHelge Deller     case 0x0030:        /* HP-UX 10.20 and 11.11 reads it. No idea. */
546e029bb00SHelge Deller         val = -1;
547e029bb00SHelge Deller         break;
548e029bb00SHelge Deller     case 0x0300 ... 0x03d8:     /* LMMIO_DIRECT0_BASE... */
549e029bb00SHelge Deller         index = (addr - 0x300) / 8;
550e029bb00SHelge Deller         val = s->ioc_ranges[index];
551e029bb00SHelge Deller         break;
552e029bb00SHelge Deller     case 0x10200:
553e029bb00SHelge Deller         val = 0;
554e029bb00SHelge Deller         break;
555e029bb00SHelge Deller     case 0x10220:
556e029bb00SHelge Deller     case 0x10230:        /* HP-UX 11.11 reads it. No idea. */
557e029bb00SHelge Deller         val = -1;
558e029bb00SHelge Deller         break;
559e029bb00SHelge Deller     case 0x22108:        /* IOC STATUS_CONTROL */
560e029bb00SHelge Deller         val = s->ioc_status_ctrl;
561e029bb00SHelge Deller         break;
562e029bb00SHelge Deller     case 0x20200 ... 0x20240 - 1: /* IOC Rope0_Control ... */
563e029bb00SHelge Deller         index = (addr - 0x20200) / 8;
564e029bb00SHelge Deller         val = s->ioc_rope_control[index];
565e029bb00SHelge Deller         break;
566e029bb00SHelge Deller     case 0x20040:        /* IOC Rope config */
567e029bb00SHelge Deller         val = s->ioc_rope_config;
568e029bb00SHelge Deller         break;
569e029bb00SHelge Deller     case 0x20050:        /* IOC Rope debug */
570e029bb00SHelge Deller         val = 0;
571e029bb00SHelge Deller         break;
572e029bb00SHelge Deller     case 0x20108:        /* IOC STATUS_CONTROL */
573e029bb00SHelge Deller         val = s->ioc_status_control;
574e029bb00SHelge Deller         break;
575e029bb00SHelge Deller     case 0x20310:        /* IOC_PCOM */
576e029bb00SHelge Deller         val = s->tlb_pcom;
577e029bb00SHelge Deller         /* TODO: flush iommu */
578e029bb00SHelge Deller         break;
579e029bb00SHelge Deller     case 0x20400:
580e029bb00SHelge Deller         val = s->ioc_flush_control;
581e029bb00SHelge Deller         break;
582e029bb00SHelge Deller     /* empty placeholders for non-existent elroys */
583e029bb00SHelge Deller #define EMPTY_PORT(x) case x:    case x+8:   val = 0;          break; \
584e029bb00SHelge Deller                       case x+40: case x+48:  val = UINT64_MAX; break;
585e029bb00SHelge Deller         EMPTY_PORT(0x30000)
586e029bb00SHelge Deller         EMPTY_PORT(0x32000)
587e029bb00SHelge Deller         EMPTY_PORT(0x34000)
588e029bb00SHelge Deller         EMPTY_PORT(0x36000)
589e029bb00SHelge Deller         EMPTY_PORT(0x38000)
590e029bb00SHelge Deller         EMPTY_PORT(0x3a000)
591e029bb00SHelge Deller         EMPTY_PORT(0x3c000)
592e029bb00SHelge Deller         EMPTY_PORT(0x3e000)
593e029bb00SHelge Deller #undef EMPTY_PORT
594e029bb00SHelge Deller 
595e029bb00SHelge Deller     default:
596e029bb00SHelge Deller         trace_astro_chip_read(addr, size, val);
597e029bb00SHelge Deller         g_assert_not_reached();
598e029bb00SHelge Deller     }
599e029bb00SHelge Deller 
600e029bb00SHelge Deller     /* for 32-bit accesses mask return value */
601e029bb00SHelge Deller     val = mask_32bit_val(addr, size, val);
602e029bb00SHelge Deller 
603e029bb00SHelge Deller     trace_astro_chip_read(addr, size, val);
604e029bb00SHelge Deller     *data = val;
605e029bb00SHelge Deller     return ret;
606e029bb00SHelge Deller }
607e029bb00SHelge Deller 
608e029bb00SHelge Deller static MemTxResult astro_chip_write_with_attrs(void *opaque, hwaddr addr,
609e029bb00SHelge Deller                                               uint64_t val, unsigned size,
610e029bb00SHelge Deller                                               MemTxAttrs attrs)
611e029bb00SHelge Deller {
612e029bb00SHelge Deller     AstroState *s = opaque;
613e029bb00SHelge Deller 
614e029bb00SHelge Deller     trace_astro_chip_write(addr, size, val);
615e029bb00SHelge Deller 
616e029bb00SHelge Deller     switch ((addr >> 3) << 3) {
617e029bb00SHelge Deller     case 0x0000:        /* ID */
618e029bb00SHelge Deller         break;
619e029bb00SHelge Deller     case 0x0008:        /* IOC_CTRL */
620e029bb00SHelge Deller         val &= 0x0ffffff;
621e029bb00SHelge Deller         put_val_in_int64(&s->ioc_ctrl, addr, size, val);
622e029bb00SHelge Deller         break;
623e029bb00SHelge Deller     case 0x0010:        /* TOC_CLIENT_ID */
624e029bb00SHelge Deller         break;
625e029bb00SHelge Deller     case 0x0030:        /* HP-UX 10.20 and 11.11 reads it. No idea. */
626e029bb00SHelge Deller         break;
627e029bb00SHelge Deller     case 0x0300 ... 0x03d8 - 1: /* LMMIO_DIRECT0_BASE... */
628e029bb00SHelge Deller         put_val_in_arrary(s->ioc_ranges, 0x300, addr, size, val);
629e029bb00SHelge Deller         break;
630e029bb00SHelge Deller     case 0x10200:
631e029bb00SHelge Deller     case 0x10220:
632e029bb00SHelge Deller     case 0x10230:        /* HP-UX 11.11 reads it. No idea. */
633e029bb00SHelge Deller         break;
634e029bb00SHelge Deller     case 0x22108:        /* IOC STATUS_CONTROL */
635e029bb00SHelge Deller         put_val_in_int64(&s->ioc_status_ctrl, addr, size, val);
636e029bb00SHelge Deller         break;
637e029bb00SHelge Deller     case 0x20200 ... 0x20240 - 1: /* IOC Rope0_Control ... */
638e029bb00SHelge Deller         put_val_in_arrary(s->ioc_rope_control, 0x20200, addr, size, val);
639e029bb00SHelge Deller         break;
640e029bb00SHelge Deller     case 0x20040:        /* IOC Rope config */
641e029bb00SHelge Deller         put_val_in_int64(&s->ioc_rope_config, addr, size, val);
642e029bb00SHelge Deller         break;
643e029bb00SHelge Deller     case 0x20300:
644e029bb00SHelge Deller         put_val_in_int64(&s->tlb_ibase, addr, size, val);
645e029bb00SHelge Deller         break;
646e029bb00SHelge Deller     case 0x20308:
647e029bb00SHelge Deller         put_val_in_int64(&s->tlb_imask, addr, size, val);
648e029bb00SHelge Deller         break;
649e029bb00SHelge Deller     case 0x20310:
650e029bb00SHelge Deller         put_val_in_int64(&s->tlb_pcom, addr, size, val);
651e029bb00SHelge Deller         /* TODO: flush iommu */
652e029bb00SHelge Deller         break;
653e029bb00SHelge Deller     case 0x20318:
654e029bb00SHelge Deller         put_val_in_int64(&s->tlb_tcnfg, addr, size, val);
655e029bb00SHelge Deller         break;
656e029bb00SHelge Deller     case 0x20320:
657e029bb00SHelge Deller         put_val_in_int64(&s->tlb_pdir_base, addr, size, val);
658e029bb00SHelge Deller         break;
659e029bb00SHelge Deller     /*
660e029bb00SHelge Deller      * empty placeholders for non-existent elroys, e.g.
661e029bb00SHelge Deller      * func_class, pci config & data
662e029bb00SHelge Deller      */
663e029bb00SHelge Deller #define EMPTY_PORT(x) case x: case x+8: case x+0x40: case x+0x48:
664e029bb00SHelge Deller         EMPTY_PORT(0x30000)
665e029bb00SHelge Deller         EMPTY_PORT(0x32000)
666e029bb00SHelge Deller         EMPTY_PORT(0x34000)
667e029bb00SHelge Deller         EMPTY_PORT(0x36000)
668e029bb00SHelge Deller         EMPTY_PORT(0x38000)
669e029bb00SHelge Deller         EMPTY_PORT(0x3a000)
670e029bb00SHelge Deller         EMPTY_PORT(0x3c000)
671e029bb00SHelge Deller         EMPTY_PORT(0x3e000)
672e029bb00SHelge Deller         break;
673e029bb00SHelge Deller #undef EMPTY_PORT
674e029bb00SHelge Deller 
675e029bb00SHelge Deller     default:
676e029bb00SHelge Deller         /* Controlled by astro_chip_mem_valid above.  */
677e029bb00SHelge Deller         trace_astro_chip_write(addr, size, val);
678e029bb00SHelge Deller         g_assert_not_reached();
679e029bb00SHelge Deller     }
680e029bb00SHelge Deller     return MEMTX_OK;
681e029bb00SHelge Deller }
682e029bb00SHelge Deller 
683e029bb00SHelge Deller static const MemoryRegionOps astro_chip_ops = {
684e029bb00SHelge Deller     .read_with_attrs = astro_chip_read_with_attrs,
685e029bb00SHelge Deller     .write_with_attrs = astro_chip_write_with_attrs,
686e029bb00SHelge Deller     .endianness = DEVICE_LITTLE_ENDIAN,
687e029bb00SHelge Deller     .valid = {
688e029bb00SHelge Deller         .min_access_size = 4,
689e029bb00SHelge Deller         .max_access_size = 8,
690e029bb00SHelge Deller     },
691e029bb00SHelge Deller     .impl = {
692e029bb00SHelge Deller         .min_access_size = 4,
693e029bb00SHelge Deller         .max_access_size = 8,
694e029bb00SHelge Deller     },
695e029bb00SHelge Deller };
696e029bb00SHelge Deller 
697e029bb00SHelge Deller static const VMStateDescription vmstate_astro = {
698e029bb00SHelge Deller     .name = "Astro",
699e029bb00SHelge Deller     .version_id = 1,
700e029bb00SHelge Deller     .minimum_version_id = 1,
701e029bb00SHelge Deller     .fields = (VMStateField[]) {
702e029bb00SHelge Deller         VMSTATE_UINT64(ioc_ctrl, AstroState),
703e029bb00SHelge Deller         VMSTATE_UINT64(ioc_status_ctrl, AstroState),
704e029bb00SHelge Deller         VMSTATE_UINT64_ARRAY(ioc_ranges, AstroState, (0x03d8 - 0x300) / 8),
705e029bb00SHelge Deller         VMSTATE_UINT64(ioc_rope_config, AstroState),
706e029bb00SHelge Deller         VMSTATE_UINT64(ioc_status_control, AstroState),
707e029bb00SHelge Deller         VMSTATE_UINT64(ioc_flush_control, AstroState),
708e029bb00SHelge Deller         VMSTATE_UINT64_ARRAY(ioc_rope_control, AstroState, 8),
709e029bb00SHelge Deller         VMSTATE_UINT64(tlb_ibase, AstroState),
710e029bb00SHelge Deller         VMSTATE_UINT64(tlb_imask, AstroState),
711e029bb00SHelge Deller         VMSTATE_UINT64(tlb_pcom, AstroState),
712e029bb00SHelge Deller         VMSTATE_UINT64(tlb_tcnfg, AstroState),
713e029bb00SHelge Deller         VMSTATE_UINT64(tlb_pdir_base, AstroState),
714e029bb00SHelge Deller         VMSTATE_END_OF_LIST()
715e029bb00SHelge Deller     }
716e029bb00SHelge Deller };
717e029bb00SHelge Deller 
718e029bb00SHelge Deller static void astro_reset(DeviceState *dev)
719e029bb00SHelge Deller {
720e029bb00SHelge Deller     AstroState *s = ASTRO_CHIP(dev);
721e029bb00SHelge Deller     int i;
722e029bb00SHelge Deller 
723e029bb00SHelge Deller     s->ioc_ctrl = 0x29cf;
724e029bb00SHelge Deller     s->ioc_rope_config = 0xc5f;
725e029bb00SHelge Deller     s->ioc_flush_control = 0xb03;
726e029bb00SHelge Deller     s->ioc_status_control = 0;
727e029bb00SHelge Deller     memset(&s->ioc_rope_control, 0, sizeof(s->ioc_rope_control));
728e029bb00SHelge Deller 
729e029bb00SHelge Deller     /*
730e029bb00SHelge Deller      * The SBA BASE/MASK registers control CPU -> IO routing.
731e029bb00SHelge Deller      * The LBA BASE/MASK registers control IO -> System routing (in Elroy)
732e029bb00SHelge Deller      */
733e029bb00SHelge Deller     memset(&s->ioc_ranges, 0, sizeof(s->ioc_ranges));
734e029bb00SHelge Deller     s->ioc_ranges[(0x360 - 0x300) / 8] = LMMIO_DIST_BASE_ADDR | 0x01; /* LMMIO_DIST_BASE (SBA) */
735e029bb00SHelge Deller     s->ioc_ranges[(0x368 - 0x300) / 8] = 0xfc000000;          /* LMMIO_DIST_MASK */
736e029bb00SHelge Deller     s->ioc_ranges[(0x370 - 0x300) / 8] = 0;                   /* LMMIO_DIST_ROUTE */
737e029bb00SHelge Deller     s->ioc_ranges[(0x390 - 0x300) / 8] = IOS_DIST_BASE_ADDR | 0x01; /* IOS_DIST_BASE */
738e029bb00SHelge Deller     s->ioc_ranges[(0x398 - 0x300) / 8] = 0xffffff0000;        /* IOS_DIST_MASK    */
739e029bb00SHelge Deller     s->ioc_ranges[(0x3a0 - 0x300) / 8] = 0x3400000000000000ULL; /* IOS_DIST_ROUTE */
740e029bb00SHelge Deller     s->ioc_ranges[(0x3c0 - 0x300) / 8] = 0xfffee00000;        /* IOS_DIRECT_BASE  */
741e029bb00SHelge Deller     s->ioc_ranges[(0x3c8 - 0x300) / 8] = 0xffffff0000;        /* IOS_DIRECT_MASK  */
742e029bb00SHelge Deller     s->ioc_ranges[(0x3d0 - 0x300) / 8] = 0x0;                 /* IOS_DIRECT_ROUTE */
743e029bb00SHelge Deller 
744e029bb00SHelge Deller     s->tlb_ibase = 0;
745e029bb00SHelge Deller     s->tlb_imask = 0;
746e029bb00SHelge Deller     s->tlb_pcom = 0;
747e029bb00SHelge Deller     s->tlb_tcnfg = 0;
748e029bb00SHelge Deller     s->tlb_pdir_base = 0;
749e029bb00SHelge Deller 
750e029bb00SHelge Deller     for (i = 0; i < ELROY_NUM; i++) {
751e029bb00SHelge Deller         elroy_reset(DEVICE(s->elroy[i]));
752e029bb00SHelge Deller     }
753e029bb00SHelge Deller }
754e029bb00SHelge Deller 
755e029bb00SHelge Deller static void astro_init(Object *obj)
756e029bb00SHelge Deller {
757e029bb00SHelge Deller }
758e029bb00SHelge Deller 
759e029bb00SHelge Deller static void astro_realize(DeviceState *obj, Error **errp)
760e029bb00SHelge Deller {
761e029bb00SHelge Deller     AstroState *s = ASTRO_CHIP(obj);
762e029bb00SHelge Deller     SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
763e029bb00SHelge Deller     int i;
764e029bb00SHelge Deller 
765e029bb00SHelge Deller     memory_region_init_io(&s->this_mem, OBJECT(s), &astro_chip_ops,
766e029bb00SHelge Deller                           s, "astro", 0x40000);
767e029bb00SHelge Deller     sysbus_init_mmio(sbd, &s->this_mem);
768e029bb00SHelge Deller 
769e029bb00SHelge Deller     /* Host memory as seen from Elroys PCI side, via the IOMMU.  */
770e029bb00SHelge Deller     memory_region_init_iommu(&s->iommu, sizeof(s->iommu),
771e029bb00SHelge Deller                              TYPE_ASTRO_IOMMU_MEMORY_REGION, OBJECT(s),
772e029bb00SHelge Deller                              "iommu-astro", UINT64_MAX);
773e029bb00SHelge Deller     address_space_init(&s->iommu_as, MEMORY_REGION(&s->iommu),
774e029bb00SHelge Deller                        "bm-pci");
775e029bb00SHelge Deller 
776e029bb00SHelge Deller     /* Create Elroys (PCI host bus chips).  */
777e029bb00SHelge Deller     for (i = 0; i < ELROY_NUM; i++) {
778e029bb00SHelge Deller         static const int elroy_hpa_offsets[ELROY_NUM] = {
779e029bb00SHelge Deller                     0x30000, 0x32000, 0x38000, 0x3c000 };
780e029bb00SHelge Deller         static const char elroy_rope_nr[ELROY_NUM] = {
781e029bb00SHelge Deller                     0, 1, 4, 6 }; /* busnum path, e.g. [10:6] */
782e029bb00SHelge Deller         int addr_offset;
783e029bb00SHelge Deller         ElroyState *elroy;
784e029bb00SHelge Deller         hwaddr map_addr;
785e029bb00SHelge Deller         uint64_t map_size;
786e029bb00SHelge Deller         int rope;
787e029bb00SHelge Deller 
788e029bb00SHelge Deller         addr_offset = elroy_hpa_offsets[i];
789e029bb00SHelge Deller         rope = elroy_rope_nr[i];
790e029bb00SHelge Deller 
791e029bb00SHelge Deller         elroy = elroy_init(i);
792e029bb00SHelge Deller         s->elroy[i] = elroy;
793e029bb00SHelge Deller         elroy->hpa = ASTRO_HPA + addr_offset;
794e029bb00SHelge Deller         elroy->pci_bus_num = i;
795e029bb00SHelge Deller         elroy->astro = s;
796e029bb00SHelge Deller 
797e029bb00SHelge Deller         /*
798e029bb00SHelge Deller          * NOTE: we only allow PCI devices on first Elroy for now.
799e029bb00SHelge Deller          * SeaBIOS will not find devices on the other busses.
800e029bb00SHelge Deller          */
801e029bb00SHelge Deller         if (i > 0) {
802e029bb00SHelge Deller             qbus_mark_full(&PCI_HOST_BRIDGE(elroy)->bus->qbus);
803e029bb00SHelge Deller         }
804e029bb00SHelge Deller 
805e029bb00SHelge Deller         /* map elroy config addresses into Astro space */
806e029bb00SHelge Deller         memory_region_add_subregion(&s->this_mem, addr_offset,
807e029bb00SHelge Deller                                     &elroy->this_mem);
808e029bb00SHelge Deller 
809e029bb00SHelge Deller         /* LMMIO */
810e029bb00SHelge Deller         elroy->mmio_base[(0x0200 - 0x200) / 8] = 0xf0000001;
811e029bb00SHelge Deller         elroy->mmio_base[(0x0208 - 0x200) / 8] = 0xf8000000;
812e029bb00SHelge Deller         /* GMMIO */
813e029bb00SHelge Deller         elroy->mmio_base[(0x0210 - 0x200) / 8] = 0x000000f800000001;
814e029bb00SHelge Deller         elroy->mmio_base[(0x0218 - 0x200) / 8] = 0x000000ff80000000;
815e029bb00SHelge Deller         /* WLMMIO */
816e029bb00SHelge Deller         elroy->mmio_base[(0x0220 - 0x200) / 8] = 0xf0000001;
817e029bb00SHelge Deller         elroy->mmio_base[(0x0228 - 0x200) / 8] = 0xf0000000;
818e029bb00SHelge Deller         /* WGMMIO */
819e029bb00SHelge Deller         elroy->mmio_base[(0x0230 - 0x200) / 8] = 0x000000f800000001;
820e029bb00SHelge Deller         elroy->mmio_base[(0x0238 - 0x200) / 8] = 0x000000fc00000000;
821e029bb00SHelge Deller         /* IOS_BASE */
822e029bb00SHelge Deller         map_size = IOS_DIST_BASE_SIZE / ROPES_PER_IOC;
823e029bb00SHelge Deller         elroy->mmio_base[(0x0240 - 0x200) / 8] = rope * map_size | 0x01;
824e029bb00SHelge Deller         elroy->mmio_base[(0x0248 - 0x200) / 8] = 0x0000e000;
825e029bb00SHelge Deller 
826e029bb00SHelge Deller         /* map elroys mmio */
827e029bb00SHelge Deller         map_size = LMMIO_DIST_BASE_SIZE / ROPES_PER_IOC;
828e029bb00SHelge Deller         map_addr = (uint32_t) (LMMIO_DIST_BASE_ADDR + rope * map_size);
829e029bb00SHelge Deller         memory_region_init_alias(&elroy->pci_mmio_alias, OBJECT(elroy),
830e029bb00SHelge Deller                                  "pci-mmio-alias",
831e029bb00SHelge Deller                                  &elroy->pci_mmio, map_addr, map_size);
832e029bb00SHelge Deller         memory_region_add_subregion(get_system_memory(), map_addr,
833e029bb00SHelge Deller                                  &elroy->pci_mmio_alias);
834e029bb00SHelge Deller 
835e029bb00SHelge Deller         map_size = IOS_DIST_BASE_SIZE / ROPES_PER_IOC;
836e029bb00SHelge Deller         map_addr = (uint32_t) (IOS_DIST_BASE_ADDR + rope * map_size);
837e029bb00SHelge Deller         memory_region_add_subregion(get_system_memory(), map_addr,
838e029bb00SHelge Deller                                  &elroy->pci_io);
839e029bb00SHelge Deller 
840e029bb00SHelge Deller         /* Host memory as seen from the PCI side, via the IOMMU.  */
841*ba7d12ebSYi Liu         pci_setup_iommu(PCI_HOST_BRIDGE(elroy)->bus, &elroy_pcihost_iommu_ops,
842e029bb00SHelge Deller                                  elroy);
843e029bb00SHelge Deller     }
844e029bb00SHelge Deller }
845e029bb00SHelge Deller 
846e029bb00SHelge Deller static void astro_class_init(ObjectClass *klass, void *data)
847e029bb00SHelge Deller {
848e029bb00SHelge Deller     DeviceClass *dc = DEVICE_CLASS(klass);
849e029bb00SHelge Deller 
850e029bb00SHelge Deller     dc->reset = astro_reset;
851e029bb00SHelge Deller     dc->vmsd = &vmstate_astro;
852e029bb00SHelge Deller     dc->realize = astro_realize;
853e029bb00SHelge Deller     /*
854e029bb00SHelge Deller      * astro with elroys are hard part of the newer PA2.0 machines and can not
855e029bb00SHelge Deller      * be created without that hardware
856e029bb00SHelge Deller      */
857e029bb00SHelge Deller     dc->user_creatable = false;
858e029bb00SHelge Deller }
859e029bb00SHelge Deller 
860e029bb00SHelge Deller static const TypeInfo astro_chip_info = {
861e029bb00SHelge Deller     .name          = TYPE_ASTRO_CHIP,
862e029bb00SHelge Deller     .parent        = TYPE_SYS_BUS_DEVICE,
863e029bb00SHelge Deller     .instance_init = astro_init,
864e029bb00SHelge Deller     .instance_size = sizeof(AstroState),
865e029bb00SHelge Deller     .class_init    = astro_class_init,
866e029bb00SHelge Deller };
867e029bb00SHelge Deller 
868e029bb00SHelge Deller static void astro_iommu_memory_region_class_init(ObjectClass *klass,
869e029bb00SHelge Deller                                                    void *data)
870e029bb00SHelge Deller {
871e029bb00SHelge Deller     IOMMUMemoryRegionClass *imrc = IOMMU_MEMORY_REGION_CLASS(klass);
872e029bb00SHelge Deller 
873e029bb00SHelge Deller     imrc->translate = astro_translate_iommu;
874e029bb00SHelge Deller }
875e029bb00SHelge Deller 
876e029bb00SHelge Deller static const TypeInfo astro_iommu_memory_region_info = {
877e029bb00SHelge Deller     .parent = TYPE_IOMMU_MEMORY_REGION,
878e029bb00SHelge Deller     .name = TYPE_ASTRO_IOMMU_MEMORY_REGION,
879e029bb00SHelge Deller     .class_init = astro_iommu_memory_region_class_init,
880e029bb00SHelge Deller };
881e029bb00SHelge Deller 
882e029bb00SHelge Deller 
883e029bb00SHelge Deller static void astro_register_types(void)
884e029bb00SHelge Deller {
885e029bb00SHelge Deller     type_register_static(&astro_chip_info);
886e029bb00SHelge Deller     type_register_static(&astro_iommu_memory_region_info);
887e029bb00SHelge Deller }
888e029bb00SHelge Deller 
889e029bb00SHelge Deller type_init(astro_register_types)
890