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