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