1
2
3
4
5
6
7
8
9
10#include "qemu/osdep.h"
11#include "hw/sysbus.h"
12#include "hw/pci/pci.h"
13#include "hw/pci/pci_bus.h"
14#include "hw/pci/pci_host.h"
15#include "qemu/log.h"
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63enum {
64 PCI_VPB_IRQMAP_ASSUME_OK,
65 PCI_VPB_IRQMAP_BROKEN,
66 PCI_VPB_IRQMAP_FORCE_OK,
67};
68
69typedef struct {
70 PCIHostState parent_obj;
71
72 qemu_irq irq[4];
73 MemoryRegion controlregs;
74 MemoryRegion mem_config;
75 MemoryRegion mem_config2;
76
77 MemoryRegion pci_io_space;
78 MemoryRegion pci_mem_space;
79
80
81
82 MemoryRegion pci_io_window;
83 MemoryRegion pci_mem_window[3];
84 PCIBus pci_bus;
85 PCIDevice pci_dev;
86
87
88 int realview;
89 uint32_t mem_win_size[3];
90 uint8_t irq_mapping_prop;
91
92
93 uint32_t imap[3];
94 uint32_t smap[3];
95 uint32_t selfid;
96 uint32_t flags;
97 uint8_t irq_mapping;
98} PCIVPBState;
99
100static void pci_vpb_update_window(PCIVPBState *s, int i)
101{
102
103
104
105
106
107
108 hwaddr offset;
109 if (s->realview) {
110
111
112
113 offset = s->imap[i] & ~(s->mem_win_size[i] - 1);
114 } else {
115
116 offset = s->imap[i] << 28;
117 }
118 memory_region_set_alias_offset(&s->pci_mem_window[i], offset);
119}
120
121static void pci_vpb_update_all_windows(PCIVPBState *s)
122{
123
124 int i;
125
126 for (i = 0; i < 3; i++) {
127 pci_vpb_update_window(s, i);
128 }
129}
130
131static int pci_vpb_post_load(void *opaque, int version_id)
132{
133 PCIVPBState *s = opaque;
134 pci_vpb_update_all_windows(s);
135 return 0;
136}
137
138static const VMStateDescription pci_vpb_vmstate = {
139 .name = "versatile-pci",
140 .version_id = 1,
141 .minimum_version_id = 1,
142 .post_load = pci_vpb_post_load,
143 .fields = (VMStateField[]) {
144 VMSTATE_UINT32_ARRAY(imap, PCIVPBState, 3),
145 VMSTATE_UINT32_ARRAY(smap, PCIVPBState, 3),
146 VMSTATE_UINT32(selfid, PCIVPBState),
147 VMSTATE_UINT32(flags, PCIVPBState),
148 VMSTATE_UINT8(irq_mapping, PCIVPBState),
149 VMSTATE_END_OF_LIST()
150 }
151};
152
153#define TYPE_VERSATILE_PCI "versatile_pci"
154#define PCI_VPB(obj) \
155 OBJECT_CHECK(PCIVPBState, (obj), TYPE_VERSATILE_PCI)
156
157#define TYPE_VERSATILE_PCI_HOST "versatile_pci_host"
158#define PCI_VPB_HOST(obj) \
159 OBJECT_CHECK(PCIDevice, (obj), TYPE_VERSATILE_PCIHOST)
160
161typedef enum {
162 PCI_IMAP0 = 0x0,
163 PCI_IMAP1 = 0x4,
164 PCI_IMAP2 = 0x8,
165 PCI_SELFID = 0xc,
166 PCI_FLAGS = 0x10,
167 PCI_SMAP0 = 0x14,
168 PCI_SMAP1 = 0x18,
169 PCI_SMAP2 = 0x1c,
170} PCIVPBControlRegs;
171
172static void pci_vpb_reg_write(void *opaque, hwaddr addr,
173 uint64_t val, unsigned size)
174{
175 PCIVPBState *s = opaque;
176
177 switch (addr) {
178 case PCI_IMAP0:
179 case PCI_IMAP1:
180 case PCI_IMAP2:
181 {
182 int win = (addr - PCI_IMAP0) >> 2;
183 s->imap[win] = val;
184 pci_vpb_update_window(s, win);
185 break;
186 }
187 case PCI_SELFID:
188 s->selfid = val;
189 break;
190 case PCI_FLAGS:
191 s->flags = val;
192 break;
193 case PCI_SMAP0:
194 case PCI_SMAP1:
195 case PCI_SMAP2:
196 {
197 int win = (addr - PCI_SMAP0) >> 2;
198 s->smap[win] = val;
199 break;
200 }
201 default:
202 qemu_log_mask(LOG_GUEST_ERROR,
203 "pci_vpb_reg_write: Bad offset %x\n", (int)addr);
204 break;
205 }
206}
207
208static uint64_t pci_vpb_reg_read(void *opaque, hwaddr addr,
209 unsigned size)
210{
211 PCIVPBState *s = opaque;
212
213 switch (addr) {
214 case PCI_IMAP0:
215 case PCI_IMAP1:
216 case PCI_IMAP2:
217 {
218 int win = (addr - PCI_IMAP0) >> 2;
219 return s->imap[win];
220 }
221 case PCI_SELFID:
222 return s->selfid;
223 case PCI_FLAGS:
224 return s->flags;
225 case PCI_SMAP0:
226 case PCI_SMAP1:
227 case PCI_SMAP2:
228 {
229 int win = (addr - PCI_SMAP0) >> 2;
230 return s->smap[win];
231 }
232 default:
233 qemu_log_mask(LOG_GUEST_ERROR,
234 "pci_vpb_reg_read: Bad offset %x\n", (int)addr);
235 return 0;
236 }
237}
238
239static const MemoryRegionOps pci_vpb_reg_ops = {
240 .read = pci_vpb_reg_read,
241 .write = pci_vpb_reg_write,
242 .endianness = DEVICE_NATIVE_ENDIAN,
243 .valid = {
244 .min_access_size = 4,
245 .max_access_size = 4,
246 },
247};
248
249static int pci_vpb_broken_irq(int slot, int irq)
250{
251
252
253
254
255
256
257
258 slot %= PCI_NUM_PINS;
259
260 if (irq == 27) {
261 if (slot == 2) {
262
263
264
265 return PCI_VPB_IRQMAP_ASSUME_OK;
266 }
267
268 return PCI_VPB_IRQMAP_BROKEN;
269 }
270 if (irq == slot + 27) {
271
272 return PCI_VPB_IRQMAP_BROKEN;
273 }
274 if (irq == slot + 27 + 64) {
275
276 return PCI_VPB_IRQMAP_BROKEN;
277 }
278
279
280
281 return PCI_VPB_IRQMAP_FORCE_OK;
282}
283
284static void pci_vpb_config_write(void *opaque, hwaddr addr,
285 uint64_t val, unsigned size)
286{
287 PCIVPBState *s = opaque;
288 if (!s->realview && (addr & 0xff) == PCI_INTERRUPT_LINE
289 && s->irq_mapping == PCI_VPB_IRQMAP_ASSUME_OK) {
290 uint8_t devfn = addr >> 8;
291 s->irq_mapping = pci_vpb_broken_irq(PCI_SLOT(devfn), val);
292 }
293 pci_data_write(&s->pci_bus, addr, val, size);
294}
295
296static uint64_t pci_vpb_config_read(void *opaque, hwaddr addr,
297 unsigned size)
298{
299 PCIVPBState *s = opaque;
300 uint32_t val;
301 val = pci_data_read(&s->pci_bus, addr, size);
302 return val;
303}
304
305static const MemoryRegionOps pci_vpb_config_ops = {
306 .read = pci_vpb_config_read,
307 .write = pci_vpb_config_write,
308 .endianness = DEVICE_NATIVE_ENDIAN,
309};
310
311static int pci_vpb_map_irq(PCIDevice *d, int irq_num)
312{
313 PCIVPBState *s = container_of(pci_get_bus(d), PCIVPBState, pci_bus);
314
315 if (s->irq_mapping == PCI_VPB_IRQMAP_BROKEN) {
316
317
318
319 return irq_num;
320 }
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336 return pci_swizzle_map_irq_fn(d, irq_num + 2);
337}
338
339static int pci_vpb_rv_map_irq(PCIDevice *d, int irq_num)
340{
341
342
343
344
345
346
347
348
349
350
351
352
353 return pci_swizzle_map_irq_fn(d, irq_num + 3);
354}
355
356static void pci_vpb_set_irq(void *opaque, int irq_num, int level)
357{
358 qemu_irq *pic = opaque;
359
360 qemu_set_irq(pic[irq_num], level);
361}
362
363static void pci_vpb_reset(DeviceState *d)
364{
365 PCIVPBState *s = PCI_VPB(d);
366
367 s->imap[0] = 0;
368 s->imap[1] = 0;
369 s->imap[2] = 0;
370 s->smap[0] = 0;
371 s->smap[1] = 0;
372 s->smap[2] = 0;
373 s->selfid = 0;
374 s->flags = 0;
375 s->irq_mapping = s->irq_mapping_prop;
376
377 pci_vpb_update_all_windows(s);
378}
379
380static void pci_vpb_init(Object *obj)
381{
382 PCIVPBState *s = PCI_VPB(obj);
383
384
385 s->mem_win_size[0] = 0x0c000000;
386 s->mem_win_size[1] = 0x10000000;
387 s->mem_win_size[2] = 0x10000000;
388}
389
390static void pci_vpb_realize(DeviceState *dev, Error **errp)
391{
392 PCIVPBState *s = PCI_VPB(dev);
393 PCIHostState *h = PCI_HOST_BRIDGE(dev);
394 SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
395 pci_map_irq_fn mapfn;
396 int i;
397
398 memory_region_init(&s->pci_io_space, OBJECT(s), "pci_io", 1ULL << 32);
399 memory_region_init(&s->pci_mem_space, OBJECT(s), "pci_mem", 1ULL << 32);
400
401 pci_root_bus_new_inplace(&s->pci_bus, sizeof(s->pci_bus), dev, "pci",
402 &s->pci_mem_space, &s->pci_io_space,
403 PCI_DEVFN(11, 0), TYPE_PCI_BUS);
404 h->bus = &s->pci_bus;
405
406 object_initialize(&s->pci_dev, sizeof(s->pci_dev), TYPE_VERSATILE_PCI_HOST);
407 qdev_set_parent_bus(DEVICE(&s->pci_dev), BUS(&s->pci_bus));
408
409 for (i = 0; i < 4; i++) {
410 sysbus_init_irq(sbd, &s->irq[i]);
411 }
412
413 if (s->realview) {
414 mapfn = pci_vpb_rv_map_irq;
415 } else {
416 mapfn = pci_vpb_map_irq;
417 }
418
419 pci_bus_irqs(&s->pci_bus, pci_vpb_set_irq, mapfn, s->irq, 4);
420
421
422
423
424
425
426
427
428 memory_region_init_io(&s->controlregs, OBJECT(s), &pci_vpb_reg_ops, s,
429 "pci-vpb-regs", 0x1000);
430 sysbus_init_mmio(sbd, &s->controlregs);
431 memory_region_init_io(&s->mem_config, OBJECT(s), &pci_vpb_config_ops, s,
432 "pci-vpb-selfconfig", 0x1000000);
433 sysbus_init_mmio(sbd, &s->mem_config);
434 memory_region_init_io(&s->mem_config2, OBJECT(s), &pci_vpb_config_ops, s,
435 "pci-vpb-config", 0x1000000);
436 sysbus_init_mmio(sbd, &s->mem_config2);
437
438
439
440
441 memory_region_init_alias(&s->pci_io_window, OBJECT(s), "pci-vbp-io-window",
442 &s->pci_io_space, 0, 0x100000);
443
444 sysbus_init_mmio(sbd, &s->pci_io_space);
445
446
447
448
449
450 for (i = 0; i < 3; i++) {
451 memory_region_init_alias(&s->pci_mem_window[i], OBJECT(s), "pci-vbp-window",
452 &s->pci_mem_space, 0, s->mem_win_size[i]);
453 sysbus_init_mmio(sbd, &s->pci_mem_window[i]);
454 }
455
456
457 object_property_set_bool(OBJECT(&s->pci_bus), true, "realized", errp);
458 object_property_set_bool(OBJECT(&s->pci_dev), true, "realized", errp);
459}
460
461static void versatile_pci_host_realize(PCIDevice *d, Error **errp)
462{
463 pci_set_word(d->config + PCI_STATUS,
464 PCI_STATUS_66MHZ | PCI_STATUS_DEVSEL_MEDIUM);
465 pci_set_byte(d->config + PCI_LATENCY_TIMER, 0x10);
466}
467
468static void versatile_pci_host_class_init(ObjectClass *klass, void *data)
469{
470 PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
471 DeviceClass *dc = DEVICE_CLASS(klass);
472
473 k->realize = versatile_pci_host_realize;
474 k->vendor_id = PCI_VENDOR_ID_XILINX;
475 k->device_id = PCI_DEVICE_ID_XILINX_XC2VP30;
476 k->class_id = PCI_CLASS_PROCESSOR_CO;
477
478
479
480
481 dc->user_creatable = false;
482}
483
484static const TypeInfo versatile_pci_host_info = {
485 .name = TYPE_VERSATILE_PCI_HOST,
486 .parent = TYPE_PCI_DEVICE,
487 .instance_size = sizeof(PCIDevice),
488 .class_init = versatile_pci_host_class_init,
489 .interfaces = (InterfaceInfo[]) {
490 { INTERFACE_CONVENTIONAL_PCI_DEVICE },
491 { },
492 },
493};
494
495static Property pci_vpb_properties[] = {
496 DEFINE_PROP_UINT8("broken-irq-mapping", PCIVPBState, irq_mapping_prop,
497 PCI_VPB_IRQMAP_ASSUME_OK),
498 DEFINE_PROP_END_OF_LIST()
499};
500
501static void pci_vpb_class_init(ObjectClass *klass, void *data)
502{
503 DeviceClass *dc = DEVICE_CLASS(klass);
504
505 dc->realize = pci_vpb_realize;
506 dc->reset = pci_vpb_reset;
507 dc->vmsd = &pci_vpb_vmstate;
508 dc->props = pci_vpb_properties;
509}
510
511static const TypeInfo pci_vpb_info = {
512 .name = TYPE_VERSATILE_PCI,
513 .parent = TYPE_PCI_HOST_BRIDGE,
514 .instance_size = sizeof(PCIVPBState),
515 .instance_init = pci_vpb_init,
516 .class_init = pci_vpb_class_init,
517};
518
519static void pci_realview_init(Object *obj)
520{
521 PCIVPBState *s = PCI_VPB(obj);
522
523 s->realview = 1;
524
525 s->mem_win_size[0] = 0x01000000;
526 s->mem_win_size[1] = 0x04000000;
527 s->mem_win_size[2] = 0x08000000;
528}
529
530static const TypeInfo pci_realview_info = {
531 .name = "realview_pci",
532 .parent = TYPE_VERSATILE_PCI,
533 .instance_init = pci_realview_init,
534};
535
536static void versatile_pci_register_types(void)
537{
538 type_register_static(&pci_vpb_info);
539 type_register_static(&pci_realview_info);
540 type_register_static(&versatile_pci_host_info);
541}
542
543type_init(versatile_pci_register_types)
544