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