Revision 80b3ada7 hw/pci.c
b/hw/pci.c | ||
---|---|---|
35 | 35 |
SetIRQFunc *low_set_irq; |
36 | 36 |
void *irq_opaque; |
37 | 37 |
PCIDevice *devices[256]; |
38 |
PCIDevice *parent_dev; |
|
39 |
PCIBus *next; |
|
38 | 40 |
/* The bus IRQ state is the logical OR of the connected devices. |
39 | 41 |
Keep a count of the number of devices with raised IRQs. */ |
40 |
int irq_count[4];
|
|
42 |
int irq_count[]; |
|
41 | 43 |
}; |
42 | 44 |
|
43 | 45 |
static void pci_update_mappings(PCIDevice *d); |
... | ... | |
47 | 49 |
static PCIBus *first_bus; |
48 | 50 |
|
49 | 51 |
PCIBus *pci_register_bus(pci_set_irq_fn set_irq, pci_map_irq_fn map_irq, |
50 |
void *pic, int devfn_min) |
|
52 |
void *pic, int devfn_min, int nirq)
|
|
51 | 53 |
{ |
52 | 54 |
PCIBus *bus; |
53 |
bus = qemu_mallocz(sizeof(PCIBus)); |
|
55 |
bus = qemu_mallocz(sizeof(PCIBus) + (nirq * sizeof(int)));
|
|
54 | 56 |
bus->set_irq = set_irq; |
55 | 57 |
bus->map_irq = map_irq; |
56 | 58 |
bus->irq_opaque = pic; |
57 | 59 |
bus->devfn_min = devfn_min; |
58 |
memset(bus->irq_count, 0, sizeof(bus->irq_count)); |
|
59 | 60 |
first_bus = bus; |
60 | 61 |
return bus; |
61 | 62 |
} |
62 | 63 |
|
64 |
PCIBus *pci_register_secondary_bus(PCIDevice *dev, pci_map_irq_fn map_irq) |
|
65 |
{ |
|
66 |
PCIBus *bus; |
|
67 |
bus = qemu_mallocz(sizeof(PCIBus)); |
|
68 |
bus->map_irq = map_irq; |
|
69 |
bus->parent_dev = dev; |
|
70 |
bus->next = dev->bus->next; |
|
71 |
dev->bus->next = bus; |
|
72 |
return bus; |
|
73 |
} |
|
74 |
|
|
63 | 75 |
int pci_bus_num(PCIBus *s) |
64 | 76 |
{ |
65 | 77 |
return s->bus_num; |
... | ... | |
351 | 363 |
addr, val, len); |
352 | 364 |
#endif |
353 | 365 |
bus_num = (addr >> 16) & 0xff; |
354 |
if (bus_num != 0) |
|
366 |
while (s && s->bus_num != bus_num) |
|
367 |
s = s->next; |
|
368 |
if (!s) |
|
355 | 369 |
return; |
356 | 370 |
pci_dev = s->devices[(addr >> 8) & 0xff]; |
357 | 371 |
if (!pci_dev) |
... | ... | |
372 | 386 |
uint32_t val; |
373 | 387 |
|
374 | 388 |
bus_num = (addr >> 16) & 0xff; |
375 |
if (bus_num != 0) |
|
389 |
while (s && s->bus_num != bus_num) |
|
390 |
s= s->next; |
|
391 |
if (!s) |
|
376 | 392 |
goto fail; |
377 | 393 |
pci_dev = s->devices[(addr >> 8) & 0xff]; |
378 | 394 |
if (!pci_dev) { |
... | ... | |
411 | 427 |
/* 0 <= irq_num <= 3. level must be 0 or 1 */ |
412 | 428 |
void pci_set_irq(PCIDevice *pci_dev, int irq_num, int level) |
413 | 429 |
{ |
414 |
PCIBus *bus = pci_dev->bus; |
|
430 |
PCIBus *bus; |
|
431 |
int change; |
|
432 |
|
|
433 |
change = level - pci_dev->irq_state[irq_num]; |
|
434 |
if (!change) |
|
435 |
return; |
|
415 | 436 |
|
416 |
irq_num = bus->map_irq(pci_dev, irq_num); |
|
417 |
bus->irq_count[irq_num] += level - pci_dev->irq_state[irq_num]; |
|
418 | 437 |
pci_dev->irq_state[irq_num] = level; |
438 |
bus = pci_dev->bus; |
|
439 |
while (!bus->set_irq) { |
|
440 |
irq_num = bus->map_irq(pci_dev, irq_num); |
|
441 |
pci_dev = bus->parent_dev; |
|
442 |
bus = pci_dev->bus; |
|
443 |
} |
|
444 |
bus->irq_count[irq_num] += change; |
|
419 | 445 |
bus->set_irq(bus->irq_opaque, irq_num, bus->irq_count[irq_num] != 0); |
420 | 446 |
} |
421 | 447 |
|
... | ... | |
465 | 491 |
if (d->config[PCI_INTERRUPT_PIN] != 0) { |
466 | 492 |
term_printf(" IRQ %d.\n", d->config[PCI_INTERRUPT_LINE]); |
467 | 493 |
} |
494 |
if (class == 0x0604) { |
|
495 |
term_printf(" BUS %d.\n", d->config[0x19]); |
|
496 |
} |
|
468 | 497 |
for(i = 0;i < PCI_NUM_REGIONS; i++) { |
469 | 498 |
r = &d->io_regions[i]; |
470 | 499 |
if (r->size != 0) { |
... | ... | |
478 | 507 |
} |
479 | 508 |
} |
480 | 509 |
} |
510 |
if (class == 0x0604 && d->config[0x19] != 0) { |
|
511 |
pci_for_each_device(d->config[0x19], pci_info_device); |
|
512 |
} |
|
481 | 513 |
} |
482 | 514 |
|
483 |
void pci_for_each_device(void (*fn)(PCIDevice *d)) |
|
515 |
void pci_for_each_device(int bus_num, void (*fn)(PCIDevice *d))
|
|
484 | 516 |
{ |
485 | 517 |
PCIBus *bus = first_bus; |
486 | 518 |
PCIDevice *d; |
487 | 519 |
int devfn; |
488 | 520 |
|
521 |
while (bus && bus->bus_num != bus_num) |
|
522 |
bus = bus->next; |
|
489 | 523 |
if (bus) { |
490 | 524 |
for(devfn = 0; devfn < 256; devfn++) { |
491 | 525 |
d = bus->devices[devfn]; |
... | ... | |
497 | 531 |
|
498 | 532 |
void pci_info(void) |
499 | 533 |
{ |
500 |
pci_for_each_device(pci_info_device); |
|
534 |
pci_for_each_device(0, pci_info_device);
|
|
501 | 535 |
} |
502 | 536 |
|
503 | 537 |
/* Initialize a PCI NIC. */ |
... | ... | |
515 | 549 |
} |
516 | 550 |
} |
517 | 551 |
|
552 |
typedef struct { |
|
553 |
PCIDevice dev; |
|
554 |
PCIBus *bus; |
|
555 |
} PCIBridge; |
|
556 |
|
|
557 |
void pci_bridge_write_config(PCIDevice *d, |
|
558 |
uint32_t address, uint32_t val, int len) |
|
559 |
{ |
|
560 |
PCIBridge *s = (PCIBridge *)d; |
|
561 |
|
|
562 |
if (address == 0x19 || (address == 0x18 && len > 1)) { |
|
563 |
if (address == 0x19) |
|
564 |
s->bus->bus_num = val & 0xff; |
|
565 |
else |
|
566 |
s->bus->bus_num = (val >> 8) & 0xff; |
|
567 |
#if defined(DEBUG_PCI) |
|
568 |
printf ("pci-bridge: %s: Assigned bus %d\n", d->name, s->bus->bus_num); |
|
569 |
#endif |
|
570 |
} |
|
571 |
pci_default_write_config(d, address, val, len); |
|
572 |
} |
|
573 |
|
|
574 |
PCIBus *pci_bridge_init(PCIBus *bus, int devfn, uint32_t id, |
|
575 |
pci_map_irq_fn map_irq, const char *name) |
|
576 |
{ |
|
577 |
PCIBridge *s; |
|
578 |
s = (PCIBridge *)pci_register_device(bus, name, sizeof(PCIBridge), |
|
579 |
devfn, NULL, pci_bridge_write_config); |
|
580 |
s->dev.config[0x00] = id >> 16; |
|
581 |
s->dev.config[0x01] = id > 24; |
|
582 |
s->dev.config[0x02] = id; // device_id |
|
583 |
s->dev.config[0x03] = id >> 8; |
|
584 |
s->dev.config[0x04] = 0x06; // command = bus master, pci mem |
|
585 |
s->dev.config[0x05] = 0x00; |
|
586 |
s->dev.config[0x06] = 0xa0; // status = fast back-to-back, 66MHz, no error |
|
587 |
s->dev.config[0x07] = 0x00; // status = fast devsel |
|
588 |
s->dev.config[0x08] = 0x00; // revision |
|
589 |
s->dev.config[0x09] = 0x00; // programming i/f |
|
590 |
s->dev.config[0x0A] = 0x04; // class_sub = PCI to PCI bridge |
|
591 |
s->dev.config[0x0B] = 0x06; // class_base = PCI_bridge |
|
592 |
s->dev.config[0x0D] = 0x10; // latency_timer |
|
593 |
s->dev.config[0x0E] = 0x81; // header_type |
|
594 |
s->dev.config[0x1E] = 0xa0; // secondary status |
|
595 |
|
|
596 |
s->bus = pci_register_secondary_bus(&s->dev, map_irq); |
|
597 |
return s->bus; |
|
598 |
} |
Also available in: Unified diff