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