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
[email protected]
https://lists.sourceforge.net/lists/listinfo/kvm-devel