Initialize and configure 3 PCI bridges (Intel 82801 PCI Bridge rev d9), which have no special handling (quirks) in current Linux versions.
IO base/limit registers are initialized with zero and read-only, indicating that the bridge does not support IO address ranges. To avoid potentially breaking SPARC, a separate pci_set_irq function is introduced to handle the flat IRQ space. Signed-off-by: Marcelo Tosatti <[EMAIL PROTECTED]> Index: kvm-userspace.pci3/qemu/hw/pci.c =================================================================== --- kvm-userspace.pci3.orig/qemu/hw/pci.c +++ kvm-userspace.pci3/qemu/hw/pci.c @@ -528,6 +528,8 @@ uint32_t pci_data_read(void *opaque, uin /***********************************************************/ /* generic PCI irq support */ +/* SPARC uses the IRQ assigned to the bridge device for its children??? */ +#ifdef TARGET_SPARC /* 0 <= irq_num <= 3. level must be 0 or 1 */ static void pci_set_irq(void *opaque, int irq_num, int level) { @@ -550,6 +552,33 @@ static void pci_set_irq(void *opaque, in bus->irq_count[irq_num] += change; bus->set_irq(bus->irq_opaque, irq_num, bus->irq_count[irq_num] != 0); } +#else +/* 0 <= irq_num <= 3. level must be 0 or 1 */ +static void pci_set_irq(void *opaque, int irq_num, int level) +{ + PCIDevice *pci_dev = (PCIDevice *)opaque; + PCIDevice *host_dev; + PCIBus *bus; + int change; + + change = level - pci_dev->irq_state[irq_num]; + if (!change) + return; + + pci_dev->irq_state[irq_num] = level; + host_dev = pci_dev; + for (;;) { + bus = host_dev->bus; + if (bus->set_irq) { + irq_num = bus->map_irq(pci_dev, irq_num); + break; + } + host_dev = bus->parent_dev; + } + bus->irq_count[irq_num] += change; + bus->set_irq(bus->irq_opaque, irq_num, bus->irq_count[irq_num] != 0); +} +#endif /***********************************************************/ /* monitor info on PCI */ @@ -706,11 +735,6 @@ PCIDevice *pci_nic_init(PCIBus *bus, NIC return pci_dev; } -typedef struct { - PCIDevice dev; - PCIBus *bus; -} PCIBridge; - static void pci_bridge_write_config(PCIDevice *d, uint32_t address, uint32_t val, int len) { @@ -725,6 +749,13 @@ static void pci_bridge_write_config(PCID printf ("pci-bridge: %s: Assigned bus %d\n", d->name, s->bus->bus_num); #endif } +#ifdef TARGET_I386 + /* on x86 the bridges do not implement I/O address ranges, I/O base/limit + * registers are read-only and should return 0. + */ + if (address == 0x1c || address == 0x1d) + return; +#endif pci_default_write_config(d, address, val, len); } @@ -755,7 +786,7 @@ PCIDevice *pci_find_device(int bus_num, return NULL; } -PCIBus *pci_bridge_init(PCIBus *bus, int devfn, uint32_t id, +PCIBridge *pci_bridge_init(PCIBus *bus, int devfn, uint32_t id, pci_map_irq_fn map_irq, const char *name) { PCIBridge *s; @@ -778,5 +809,5 @@ PCIBus *pci_bridge_init(PCIBus *bus, int s->dev.config[0x1E] = 0xa0; // secondary status s->bus = pci_register_secondary_bus(&s->dev, map_irq); - return s->bus; + return s; } Index: kvm-userspace.pci3/bios/rombios32.c =================================================================== --- kvm-userspace.pci3.orig/bios/rombios32.c +++ kvm-userspace.pci3/bios/rombios32.c @@ -652,6 +652,30 @@ static void bios_lock_shadow_ram(void) pci_config_writeb(d, 0x59, v); } +static int nr_bridges = 1; +static int current_bridge = 0; + +static void pci_bios_count_p2p(PCIDevice *d) +{ + uint16_t vendor_id, device_id; + + vendor_id = pci_config_readw(d, PCI_VENDOR_ID); + device_id = pci_config_readw(d, PCI_DEVICE_ID); + if (vendor_id == 0x8086 && device_id == 0x244e) + nr_bridges++; +} + +int fls(int i) +{ + int bit; + + for (bit=31; bit >= 0; bit--) + if (i & (1 << bit)) + return bit+1; + + return 0; +} + static void pci_bios_init_bridges(PCIDevice *d) { uint16_t vendor_id, device_id; @@ -681,6 +705,20 @@ static void pci_bios_init_bridges(PCIDev } else if (vendor_id == 0x8086 && device_id == 0x1237) { /* i440 PCI bridge */ bios_shadow_init(d); + } else if (vendor_id == 0x8086 && device_id == 0x244e) { + int len, base; + + len = (0xfebfffff - 0xf0000000) / nr_bridges; + if (len & (len-1)) + len = 1 << fls(len); + + /* memory IO */ + base = (0xf0000000+len) + (current_bridge*len); + base >>= 16; + pci_config_writew(d, 0x20, base); + pci_config_writew(d, 0x22, base); + + current_bridge++; } } @@ -775,6 +813,8 @@ static void pci_bios_init_device(PCIDevi pci_set_io_region_addr(d, 0, 0x80800000); } break; + case 0x0604: + break; default: default_map: /* default memory mappings */ @@ -859,6 +899,8 @@ void pci_bios_init(void) if (pci_bios_bigmem_addr < 0x90000000) pci_bios_bigmem_addr = 0x90000000; + pci_for_each_device(pci_bios_count_p2p); + pci_for_each_device(pci_bios_init_bridges); pci_for_each_device(pci_bios_init_device); Index: kvm-userspace.pci3/qemu/hw/piix_pci.c =================================================================== --- kvm-userspace.pci3.orig/qemu/hw/piix_pci.c +++ kvm-userspace.pci3/qemu/hw/piix_pci.c @@ -172,6 +172,7 @@ static int i440fx_load(QEMUFile* f, void PCIBus *i440fx_init(PCIDevice **pi440fx_state, qemu_irq *pic) { PCIBus *b; + PCIBridge *b1, *b2, *b3; PCIDevice *d; I440FXState *s; @@ -203,6 +204,15 @@ PCIBus *i440fx_init(PCIDevice **pi440fx_ d->config[0x72] = 0x02; /* SMRAM */ + b1 = pci_bridge_init(s->bus, 24, 0x8086244e, pci_slot_get_pirq, + "first PCI-to-PCI bridge "); + b2 = pci_bridge_init(s->bus, 32, 0x8086244e, pci_slot_get_pirq, + "second PCI-to-PCI bridge"); + b3 = pci_bridge_init(s->bus, 40, 0x8086244e, pci_slot_get_pirq, + "third PCI-to-PCI bridge"); + b1->dev.config[0x1c] = b2->dev.config[0x1c] = b3->dev.config[0x1c] = 0; + b1->dev.config[0x1d] = b2->dev.config[0x1d] = b3->dev.config[0x1d] = 0; + register_savevm("I440FX", 0, 2, i440fx_save, i440fx_load, d); *pi440fx_state = d; return b; Index: kvm-userspace.pci3/qemu/hw/apb_pci.c =================================================================== --- kvm-userspace.pci3.orig/qemu/hw/apb_pci.c +++ kvm-userspace.pci3/qemu/hw/apb_pci.c @@ -214,7 +214,7 @@ PCIBus *pci_apb_init(target_phys_addr_t APBState *s; PCIDevice *d; int pci_mem_config, pci_mem_data, apb_config, pci_ioport; - PCIBus *secondary; + PCIBridge *secondary; s = qemu_mallocz(sizeof(APBState)); /* Ultrasparc PBM main bus */ @@ -254,7 +254,7 @@ PCIBus *pci_apb_init(target_phys_addr_t /* APB secondary busses */ secondary = pci_bridge_init(s->bus, 8, 0x108e5000, pci_apb_map_irq, "Advanced PCI Bus secondary bridge 1"); pci_bridge_init(s->bus, 9, 0x108e5000, pci_apb_map_irq, "Advanced PCI Bus secondary bridge 2"); - return secondary; + return secondary->bus; } Index: kvm-userspace.pci3/qemu/hw/pci.h =================================================================== --- kvm-userspace.pci3.orig/qemu/hw/pci.h +++ kvm-userspace.pci3/qemu/hw/pci.h @@ -70,6 +70,11 @@ struct PCIDevice { int irq_state[4]; }; +typedef struct { + PCIDevice dev; + PCIBus *bus; +} PCIBridge; + PCIDevice *pci_register_device(PCIBus *bus, const char *name, int instance_size, int devfn, PCIConfigReadFunc *config_read, @@ -102,7 +107,7 @@ PCIBus *pci_find_bus(int bus_num); PCIDevice *pci_find_device(int bus_num, int slot); void pci_info(void); -PCIBus *pci_bridge_init(PCIBus *bus, int devfn, uint32_t id, +PCIBridge *pci_bridge_init(PCIBus *bus, int devfn, uint32_t id, pci_map_irq_fn map_irq, const char *name); /* lsi53c895a.c */ -- ------------------------------------------------------------------------- This SF.net email is sponsored by the 2008 JavaOne(SM) Conference Don't miss this year's exciting event. There's still time to save $100. Use priority code J8TL2D2. http://ad.doubleclick.net/clk;198757673;13503038;p?http://java.sun.com/javaone _______________________________________________ kvm-devel mailing list kvm-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/kvm-devel