From e01fd687185444944b0b5b0f8c739ae4b33eb029 Mon Sep 17 00:00:00 2001 From: Alex Williamson Date: Sun, 3 Mar 2013 10:21:26 -0700 Subject: pci: Add PCI VGA helpers Allow devices to register VGA memory regions for handling PCI spec defined VGA I/O port and MMIO areas. PCI will attach these to the bus address spaces and enable them according to the device command register value. Signed-off-by: Alex Williamson Signed-off-by: Michael S. Tsirkin --- hw/pci/pci.c | 61 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) (limited to 'hw/pci/pci.c') diff --git a/hw/pci/pci.c b/hw/pci/pci.c index 2f45c8f02f..ed43111bce 100644 --- a/hw/pci/pci.c +++ b/hw/pci/pci.c @@ -875,6 +875,8 @@ static void pci_unregister_io_regions(PCIDevice *pci_dev) continue; memory_region_del_subregion(r->address_space, r->memory); } + + pci_unregister_vga(pci_dev); } static int pci_unregister_device(DeviceState *dev) @@ -937,6 +939,63 @@ void pci_register_bar(PCIDevice *pci_dev, int region_num, : pci_dev->bus->address_space_mem; } +static void pci_update_vga(PCIDevice *pci_dev) +{ + uint16_t cmd; + + if (!pci_dev->has_vga) { + return; + } + + cmd = pci_get_word(pci_dev->config + PCI_COMMAND); + + memory_region_set_enabled(pci_dev->vga_regions[QEMU_PCI_VGA_MEM], + cmd & PCI_COMMAND_MEMORY); + memory_region_set_enabled(pci_dev->vga_regions[QEMU_PCI_VGA_IO_LO], + cmd & PCI_COMMAND_IO); + memory_region_set_enabled(pci_dev->vga_regions[QEMU_PCI_VGA_IO_HI], + cmd & PCI_COMMAND_IO); +} + +void pci_register_vga(PCIDevice *pci_dev, MemoryRegion *mem, + MemoryRegion *io_lo, MemoryRegion *io_hi) +{ + assert(!pci_dev->has_vga); + + assert(memory_region_size(mem) == QEMU_PCI_VGA_MEM_SIZE); + pci_dev->vga_regions[QEMU_PCI_VGA_MEM] = mem; + memory_region_add_subregion_overlap(pci_dev->bus->address_space_mem, + QEMU_PCI_VGA_MEM_BASE, mem, 1); + + assert(memory_region_size(io_lo) == QEMU_PCI_VGA_IO_LO_SIZE); + pci_dev->vga_regions[QEMU_PCI_VGA_IO_LO] = io_lo; + memory_region_add_subregion_overlap(pci_dev->bus->address_space_io, + QEMU_PCI_VGA_IO_LO_BASE, io_lo, 1); + + assert(memory_region_size(io_hi) == QEMU_PCI_VGA_IO_HI_SIZE); + pci_dev->vga_regions[QEMU_PCI_VGA_IO_HI] = io_hi; + memory_region_add_subregion_overlap(pci_dev->bus->address_space_io, + QEMU_PCI_VGA_IO_HI_BASE, io_hi, 1); + pci_dev->has_vga = true; + + pci_update_vga(pci_dev); +} + +void pci_unregister_vga(PCIDevice *pci_dev) +{ + if (!pci_dev->has_vga) { + return; + } + + memory_region_del_subregion(pci_dev->bus->address_space_mem, + pci_dev->vga_regions[QEMU_PCI_VGA_MEM]); + memory_region_del_subregion(pci_dev->bus->address_space_io, + pci_dev->vga_regions[QEMU_PCI_VGA_IO_LO]); + memory_region_del_subregion(pci_dev->bus->address_space_io, + pci_dev->vga_regions[QEMU_PCI_VGA_IO_HI]); + pci_dev->has_vga = false; +} + pcibus_t pci_get_bar_addr(PCIDevice *pci_dev, int region_num) { return pci_dev->io_regions[region_num].addr; @@ -1036,6 +1095,8 @@ static void pci_update_mappings(PCIDevice *d) r->addr, r->memory, 1); } } + + pci_update_vga(d); } static inline int pci_irq_disabled(PCIDevice *d) -- cgit 1.4.1 From ba7d8515c1e929baccea9f53d06d131fd2b007a1 Mon Sep 17 00:00:00 2001 From: Alex Williamson Date: Sun, 3 Mar 2013 10:21:32 -0700 Subject: pci: Teach PCI Bridges about VGA routing Each PCI Bridge has a set of implied VGA regions that are enabled when the VGA bit is set in the bridge control register. This allows VGA devices behind bridges. Unfortunately with VGA Enable, which we formerly allowed but didn't back, comes along some required VGA baggage. VGA Palette Snooping is required, along with VGA 16-bit decoding. We don't yet have support for palette snooping. We also don't have support for 10-bit VGA aliases, the default mode, but we enable the register, even on root ports, to avoid confusing guests. Fortunately there's likely nothing from this century that requires these features, so the missing bits are noted with TODOs. Signed-off-by: Alex Williamson Signed-off-by: Michael S. Tsirkin --- hw/pci/pci.c | 4 ++++ hw/pci/pci_bridge.c | 44 ++++++++++++++++++++++++++++++++++++++++++-- hw/pci/pci_bus.h | 7 +++++++ hw/pci/pcie_port.c | 2 ++ 4 files changed, 55 insertions(+), 2 deletions(-) (limited to 'hw/pci/pci.c') diff --git a/hw/pci/pci.c b/hw/pci/pci.c index ed43111bce..a88160236e 100644 --- a/hw/pci/pci.c +++ b/hw/pci/pci.c @@ -674,6 +674,10 @@ static void pci_init_mask_bridge(PCIDevice *d) #define PCI_BRIDGE_CTL_SEC_DISCARD 0x200 /* Secondary discard timer */ #define PCI_BRIDGE_CTL_DISCARD_STATUS 0x400 /* Discard timer status */ #define PCI_BRIDGE_CTL_DISCARD_SERR 0x800 /* Discard timer SERR# enable */ +/* + * TODO: Bridges default to 10-bit VGA decoding but we currently only + * implement 16-bit decoding (no alias support). + */ pci_set_word(d->wmask + PCI_BRIDGE_CONTROL, PCI_BRIDGE_CTL_PARITY | PCI_BRIDGE_CTL_SERR | diff --git a/hw/pci/pci_bridge.c b/hw/pci/pci_bridge.c index 995842a72d..edb8c8d9c9 100644 --- a/hw/pci/pci_bridge.c +++ b/hw/pci/pci_bridge.c @@ -151,6 +151,28 @@ static void pci_bridge_init_alias(PCIBridge *bridge, MemoryRegion *alias, memory_region_add_subregion_overlap(parent_space, base, alias, 1); } +static void pci_bridge_init_vga_aliases(PCIBridge *br, PCIBus *parent, + MemoryRegion *alias_vga) +{ + uint16_t brctl = pci_get_word(br->dev.config + PCI_BRIDGE_CONTROL); + + memory_region_init_alias(&alias_vga[QEMU_PCI_VGA_IO_LO], + "pci_bridge_vga_io_lo", &br->address_space_io, + QEMU_PCI_VGA_IO_LO_BASE, QEMU_PCI_VGA_IO_LO_SIZE); + memory_region_init_alias(&alias_vga[QEMU_PCI_VGA_IO_HI], + "pci_bridge_vga_io_hi", &br->address_space_io, + QEMU_PCI_VGA_IO_HI_BASE, QEMU_PCI_VGA_IO_HI_SIZE); + memory_region_init_alias(&alias_vga[QEMU_PCI_VGA_MEM], + "pci_bridge_vga_mem", &br->address_space_mem, + QEMU_PCI_VGA_MEM_BASE, QEMU_PCI_VGA_MEM_SIZE); + + if (brctl & PCI_BRIDGE_CTL_VGA) { + pci_register_vga(&br->dev, &alias_vga[QEMU_PCI_VGA_MEM], + &alias_vga[QEMU_PCI_VGA_IO_LO], + &alias_vga[QEMU_PCI_VGA_IO_HI]); + } +} + static PCIBridgeWindows *pci_bridge_region_init(PCIBridge *br) { PCIBus *parent = br->dev.bus; @@ -175,7 +197,8 @@ static PCIBridgeWindows *pci_bridge_region_init(PCIBridge *br) &br->address_space_io, parent->address_space_io, cmd & PCI_COMMAND_IO); - /* TODO: optinal VGA and VGA palette snooping support. */ + + pci_bridge_init_vga_aliases(br, parent, w->alias_vga); return w; } @@ -187,6 +210,7 @@ static void pci_bridge_region_del(PCIBridge *br, PCIBridgeWindows *w) memory_region_del_subregion(parent->address_space_io, &w->alias_io); memory_region_del_subregion(parent->address_space_mem, &w->alias_mem); memory_region_del_subregion(parent->address_space_mem, &w->alias_pref_mem); + pci_unregister_vga(&br->dev); } static void pci_bridge_region_cleanup(PCIBridge *br, PCIBridgeWindows *w) @@ -194,6 +218,9 @@ static void pci_bridge_region_cleanup(PCIBridge *br, PCIBridgeWindows *w) memory_region_destroy(&w->alias_io); memory_region_destroy(&w->alias_mem); memory_region_destroy(&w->alias_pref_mem); + memory_region_destroy(&w->alias_vga[QEMU_PCI_VGA_IO_LO]); + memory_region_destroy(&w->alias_vga[QEMU_PCI_VGA_IO_HI]); + memory_region_destroy(&w->alias_vga[QEMU_PCI_VGA_MEM]); g_free(w); } @@ -227,7 +254,10 @@ void pci_bridge_write_config(PCIDevice *d, /* memory base/limit, prefetchable base/limit and io base/limit upper 16 */ - ranges_overlap(address, len, PCI_MEMORY_BASE, 20)) { + ranges_overlap(address, len, PCI_MEMORY_BASE, 20) || + + /* vga enable */ + ranges_overlap(address, len, PCI_BRIDGE_CONTROL, 2)) { pci_bridge_update_mappings(s); } @@ -306,6 +336,16 @@ int pci_bridge_initfn(PCIDevice *dev) pci_word_test_and_set_mask(dev->config + PCI_STATUS, PCI_STATUS_66MHZ | PCI_STATUS_FAST_BACK); + + /* + * TODO: We implement VGA Enable in the Bridge Control Register + * therefore per the PCI to PCI bridge spec we must also implement + * VGA Palette Snooping. When done, set this bit writable: + * + * pci_word_test_and_set_mask(dev->wmask + PCI_COMMAND, + * PCI_COMMAND_VGA_PALETTE); + */ + pci_config_set_class(dev->config, PCI_CLASS_BRIDGE_PCI); dev->config[PCI_HEADER_TYPE] = (dev->config[PCI_HEADER_TYPE] & PCI_HEADER_TYPE_MULTI_FUNCTION) | diff --git a/hw/pci/pci_bus.h b/hw/pci/pci_bus.h index f905b9e11e..aef559ae1f 100644 --- a/hw/pci/pci_bus.h +++ b/hw/pci/pci_bus.h @@ -47,6 +47,13 @@ struct PCIBridgeWindows { MemoryRegion alias_pref_mem; MemoryRegion alias_mem; MemoryRegion alias_io; + /* + * When bridge control VGA forwarding is enabled, bridges will + * provide positive decode on the PCI VGA defined I/O port and + * MMIO ranges. When enabled forwarding is only qualified on the + * I/O and memory enable bits in the bridge command register. + */ + MemoryRegion alias_vga[QEMU_PCI_VGA_NUM_REGIONS]; }; struct PCIBridge { diff --git a/hw/pci/pcie_port.c b/hw/pci/pcie_port.c index 33a6b0a08a..1be107b0c9 100644 --- a/hw/pci/pcie_port.c +++ b/hw/pci/pcie_port.c @@ -28,10 +28,12 @@ void pcie_port_init_reg(PCIDevice *d) pci_set_word(d->config + PCI_SEC_STATUS, 0); /* Unlike conventional pci bridge, some bits are hardwired to 0. */ +#define PCI_BRIDGE_CTL_VGA_16BIT 0x10 /* VGA 16-bit decode */ pci_set_word(d->wmask + PCI_BRIDGE_CONTROL, PCI_BRIDGE_CTL_PARITY | PCI_BRIDGE_CTL_ISA | PCI_BRIDGE_CTL_VGA | + PCI_BRIDGE_CTL_VGA_16BIT | /* Req, but no alias support yet */ PCI_BRIDGE_CTL_SERR | PCI_BRIDGE_CTL_BUS_RESET); } -- cgit 1.4.1 From 45eb768c706d3a5fbe55224c589e8b4e252781d9 Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Mon, 4 Mar 2013 11:23:49 +0200 Subject: pci_bridge: factor out common code Reuse common code in pcie_port, override the hardwired-to-0 bits per PCI Express spec. No functional change but makes the code easier to follow. Signed-off-by: Michael S. Tsirkin --- hw/pci/pci.c | 14 ++++---------- hw/pci/pci_bridge.h | 7 +++++++ hw/pci/pcie_port.c | 20 +++++++++++--------- 3 files changed, 22 insertions(+), 19 deletions(-) (limited to 'hw/pci/pci.c') diff --git a/hw/pci/pci.c b/hw/pci/pci.c index a88160236e..8772707b81 100644 --- a/hw/pci/pci.c +++ b/hw/pci/pci.c @@ -668,16 +668,10 @@ static void pci_init_mask_bridge(PCIDevice *d) pci_word_test_and_set_mask(d->config + PCI_PREF_MEMORY_LIMIT, PCI_PREF_RANGE_TYPE_64); -/* TODO: add this define to pci_regs.h in linux and then in qemu. */ -#define PCI_BRIDGE_CTL_VGA_16BIT 0x10 /* VGA 16-bit decode */ -#define PCI_BRIDGE_CTL_DISCARD 0x100 /* Primary discard timer */ -#define PCI_BRIDGE_CTL_SEC_DISCARD 0x200 /* Secondary discard timer */ -#define PCI_BRIDGE_CTL_DISCARD_STATUS 0x400 /* Discard timer status */ -#define PCI_BRIDGE_CTL_DISCARD_SERR 0x800 /* Discard timer SERR# enable */ -/* - * TODO: Bridges default to 10-bit VGA decoding but we currently only - * implement 16-bit decoding (no alias support). - */ + /* + * TODO: Bridges default to 10-bit VGA decoding but we currently only + * implement 16-bit decoding (no alias support). + */ pci_set_word(d->wmask + PCI_BRIDGE_CONTROL, PCI_BRIDGE_CTL_PARITY | PCI_BRIDGE_CTL_SERR | diff --git a/hw/pci/pci_bridge.h b/hw/pci/pci_bridge.h index 455cb6677a..9d25c1beb1 100644 --- a/hw/pci/pci_bridge.h +++ b/hw/pci/pci_bridge.h @@ -55,6 +55,13 @@ void pci_bridge_exitfn(PCIDevice *pci_dev); void pci_bridge_map_irq(PCIBridge *br, const char* bus_name, pci_map_irq_fn map_irq); +/* TODO: add this define to pci_regs.h in linux and then in qemu. */ +#define PCI_BRIDGE_CTL_VGA_16BIT 0x10 /* VGA 16-bit decode */ +#define PCI_BRIDGE_CTL_DISCARD 0x100 /* Primary discard timer */ +#define PCI_BRIDGE_CTL_SEC_DISCARD 0x200 /* Secondary discard timer */ +#define PCI_BRIDGE_CTL_DISCARD_STATUS 0x400 /* Discard timer status */ +#define PCI_BRIDGE_CTL_DISCARD_SERR 0x800 /* Discard timer SERR# enable */ + #endif /* QEMU_PCI_BRIDGE_H */ /* * Local variables: diff --git a/hw/pci/pcie_port.c b/hw/pci/pcie_port.c index 1be107b0c9..91b53a0fc2 100644 --- a/hw/pci/pcie_port.c +++ b/hw/pci/pcie_port.c @@ -27,15 +27,17 @@ void pcie_port_init_reg(PCIDevice *d) pci_set_word(d->config + PCI_STATUS, 0); pci_set_word(d->config + PCI_SEC_STATUS, 0); - /* Unlike conventional pci bridge, some bits are hardwired to 0. */ -#define PCI_BRIDGE_CTL_VGA_16BIT 0x10 /* VGA 16-bit decode */ - pci_set_word(d->wmask + PCI_BRIDGE_CONTROL, - PCI_BRIDGE_CTL_PARITY | - PCI_BRIDGE_CTL_ISA | - PCI_BRIDGE_CTL_VGA | - PCI_BRIDGE_CTL_VGA_16BIT | /* Req, but no alias support yet */ - PCI_BRIDGE_CTL_SERR | - PCI_BRIDGE_CTL_BUS_RESET); + /* + * Unlike conventional pci bridge, for some bits the spec states: + * Does not apply to PCI Express and must be hardwired to 0. + */ + pci_word_test_and_clear_mask(d->wmask + PCI_BRIDGE_CONTROL, + PCI_BRIDGE_CTL_MASTER_ABORT | + PCI_BRIDGE_CTL_FAST_BACK | + PCI_BRIDGE_CTL_DISCARD | + PCI_BRIDGE_CTL_SEC_DISCARD | + PCI_BRIDGE_CTL_DISCARD_STATUS | + PCI_BRIDGE_CTL_DISCARD_SERR); } /************************************************************************** -- cgit 1.4.1 From e5368f0da75c1c668e85398aa930be2f4273e684 Mon Sep 17 00:00:00 2001 From: Alex Williamson Date: Thu, 7 Mar 2013 11:29:19 -0700 Subject: pci: Fix INTx routing notifier recursion For some reason we recurse to fire the INTx routing notifier for each child of a bus, for each possible device of a bus. That means that if we add a root port, the notifier gets called for that bridge 256 times. If we add an upstream switch behind that root port, 256^2. But of course we need a downstream switch, 256^3. This starts to be noticeable. Stop the insanity. Signed-off-by: Alex Williamson Signed-off-by: Michael S. Tsirkin --- hw/pci/pci.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'hw/pci/pci.c') diff --git a/hw/pci/pci.c b/hw/pci/pci.c index 8772707b81..f24c389627 100644 --- a/hw/pci/pci.c +++ b/hw/pci/pci.c @@ -1215,9 +1215,10 @@ void pci_bus_fire_intx_routing_notifier(PCIBus *bus) if (dev && dev->intx_routing_notifier) { dev->intx_routing_notifier(dev); } - QLIST_FOREACH(sec, &bus->child, sibling) { - pci_bus_fire_intx_routing_notifier(sec); - } + } + + QLIST_FOREACH(sec, &bus->child, sibling) { + pci_bus_fire_intx_routing_notifier(sec); } } -- cgit 1.4.1 From 8c7f3dd05e4f1ee90000c89e428e69ae2e6bd691 Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Mon, 11 Mar 2013 10:20:20 +0100 Subject: pci: refuse empty ROM files A zero size ROM file is invalid and should produce a warning. Attempting to use a zero size file ends up hitting an assertion qemu_ram_set_idstr() because RAMBlocks with duplicate addresses are allocated - due to zero size the allocator doesn't increment the next available RAMBlock offset. Also convert __FUNCTION__ to __func__ while we're touching this code. There are no other __FUNCTION__ instances in pci.c anymore. Reported-by: Milos Ivanovic Signed-off-by: Stefan Hajnoczi Signed-off-by: Michael S. Tsirkin --- hw/pci/pci.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'hw/pci/pci.c') diff --git a/hw/pci/pci.c b/hw/pci/pci.c index f24c389627..81028cb083 100644 --- a/hw/pci/pci.c +++ b/hw/pci/pci.c @@ -1912,7 +1912,12 @@ static int pci_add_option_rom(PCIDevice *pdev, bool is_default_rom) size = get_image_size(path); if (size < 0) { error_report("%s: failed to find romfile \"%s\"", - __FUNCTION__, pdev->romfile); + __func__, pdev->romfile); + g_free(path); + return -1; + } else if (size == 0) { + error_report("%s: ignoring empty romfile \"%s\"", + __func__, pdev->romfile); g_free(path); return -1; } -- cgit 1.4.1 From 3a861c466cee46fed042d76100fa0fd9644f3091 Mon Sep 17 00:00:00 2001 From: Alex Williamson Date: Thu, 14 Mar 2013 16:00:59 -0600 Subject: pci: Create and register a new PCI Express TypeInfo This will allow us to differentiate Express and Legacy buses. Signed-off-by: Alex Williamson Signed-off-by: Michael S. Tsirkin --- hw/pci/pci.c | 6 ++++++ hw/pci/pci_bus.h | 1 + 2 files changed, 7 insertions(+) (limited to 'hw/pci/pci.c') diff --git a/hw/pci/pci.c b/hw/pci/pci.c index 81028cb083..74f449d38e 100644 --- a/hw/pci/pci.c +++ b/hw/pci/pci.c @@ -75,6 +75,11 @@ static const TypeInfo pci_bus_info = { .class_init = pci_bus_class_init, }; +static const TypeInfo pcie_bus_info = { + .name = TYPE_PCIE_BUS, + .parent = TYPE_PCI_BUS, +}; + static PCIBus *pci_find_bus_nr(PCIBus *bus, int bus_num); static void pci_update_mappings(PCIDevice *d); static void pci_set_irq(void *opaque, int irq_num, int level); @@ -2236,6 +2241,7 @@ static const TypeInfo pci_device_type_info = { static void pci_register_types(void) { type_register_static(&pci_bus_info); + type_register_static(&pcie_bus_info); type_register_static(&pci_device_type_info); } diff --git a/hw/pci/pci_bus.h b/hw/pci/pci_bus.h index aef559ae1f..6d3155f14b 100644 --- a/hw/pci/pci_bus.h +++ b/hw/pci/pci_bus.h @@ -10,6 +10,7 @@ #define TYPE_PCI_BUS "PCI" #define PCI_BUS(obj) OBJECT_CHECK(PCIBus, (obj), TYPE_PCI_BUS) +#define TYPE_PCIE_BUS "PCIE" struct PCIBus { BusState qbus; -- cgit 1.4.1 From 60a0e44320cc2601236450fbe95d952830192a1d Mon Sep 17 00:00:00 2001 From: Alex Williamson Date: Thu, 14 Mar 2013 16:01:11 -0600 Subject: pci: Allow PCI bus creation interfaces to specify the type of bus No change to any types. Signed-off-by: Alex Williamson Signed-off-by: Michael S. Tsirkin --- hw/alpha_typhoon.c | 2 +- hw/apb_pci.c | 4 ++-- hw/bonito.c | 2 +- hw/dec_pci.c | 7 ++++++- hw/grackle_pci.c | 2 +- hw/gt64xxx.c | 2 +- hw/i82801b11.c | 2 +- hw/ioh3420.c | 2 +- hw/pci/pci.c | 12 ++++++------ hw/pci/pci.h | 6 +++--- hw/pci/pci_bridge.c | 5 ++--- hw/pci/pci_bridge.h | 2 +- hw/pci_bridge_dev.c | 2 +- hw/piix_pci.c | 2 +- hw/ppc4xx_pci.c | 2 +- hw/ppce500_pci.c | 2 +- hw/prep_pci.c | 2 +- hw/q35.c | 3 ++- hw/sh_pci.c | 2 +- hw/spapr_pci.c | 2 +- hw/unin_pci.c | 4 ++-- hw/versatile_pci.c | 2 +- hw/xio3130_downstream.c | 2 +- hw/xio3130_upstream.c | 2 +- 24 files changed, 40 insertions(+), 35 deletions(-) (limited to 'hw/pci/pci.c') diff --git a/hw/alpha_typhoon.c b/hw/alpha_typhoon.c index 770dc8cf0d..b1e0044a35 100644 --- a/hw/alpha_typhoon.c +++ b/hw/alpha_typhoon.c @@ -775,7 +775,7 @@ PCIBus *typhoon_init(ram_addr_t ram_size, ISABus **isa_bus, b = pci_register_bus(dev, "pci", typhoon_set_irq, sys_map_irq, s, - &s->pchip.reg_mem, addr_space_io, 0, 64); + &s->pchip.reg_mem, addr_space_io, 0, 64, TYPE_PCI_BUS); phb->bus = b; /* Pchip0 PCI special/interrupt acknowledge, 0x801.F800.0000, 64MB. */ diff --git a/hw/apb_pci.c b/hw/apb_pci.c index 7992d6f6fd..754ca6ca8f 100644 --- a/hw/apb_pci.c +++ b/hw/apb_pci.c @@ -329,7 +329,7 @@ static int apb_pci_bridge_initfn(PCIDevice *dev) { int rc; - rc = pci_bridge_initfn(dev); + rc = pci_bridge_initfn(dev, TYPE_PCI_BUS); if (rc < 0) { return rc; } @@ -381,7 +381,7 @@ PCIBus *pci_apb_init(hwaddr special_base, pci_apb_set_irq, pci_pbm_map_irq, d, &d->pci_mmio, get_system_io(), - 0, 32); + 0, 32, TYPE_PCI_BUS); *pbm_irqs = d->pbm_irqs; d->ivec_irqs = ivec_irqs; diff --git a/hw/bonito.c b/hw/bonito.c index 3456e7840e..e58655a64d 100644 --- a/hw/bonito.c +++ b/hw/bonito.c @@ -707,7 +707,7 @@ static int bonito_pcihost_initfn(SysBusDevice *dev) phb->bus = pci_register_bus(DEVICE(dev), "pci", pci_bonito_set_irq, pci_bonito_map_irq, dev, get_system_memory(), get_system_io(), - 0x28, 32); + 0x28, 32, TYPE_PCI_BUS); return 0; } diff --git a/hw/dec_pci.c b/hw/dec_pci.c index 64a50924f6..6ec3d226bd 100644 --- a/hw/dec_pci.c +++ b/hw/dec_pci.c @@ -51,12 +51,17 @@ static int dec_map_irq(PCIDevice *pci_dev, int irq_num) return irq_num; } +static int dec_pci_bridge_initfn(PCIDevice *pci_dev) +{ + return pci_bridge_initfn(pci_dev, TYPE_PCI_BUS); +} + static void dec_21154_pci_bridge_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); - k->init = pci_bridge_initfn; + k->init = dec_pci_bridge_initfn; k->exit = pci_bridge_exitfn; k->vendor_id = PCI_VENDOR_ID_DEC; k->device_id = PCI_DEVICE_ID_DEC_21154; diff --git a/hw/grackle_pci.c b/hw/grackle_pci.c index 11e47d560e..69344d9f6a 100644 --- a/hw/grackle_pci.c +++ b/hw/grackle_pci.c @@ -88,7 +88,7 @@ PCIBus *pci_grackle_init(uint32_t base, qemu_irq *pic, pic, &d->pci_mmio, address_space_io, - 0, 4); + 0, 4, TYPE_PCI_BUS); pci_create_simple(phb->bus, 0, "grackle"); diff --git a/hw/gt64xxx.c b/hw/gt64xxx.c index c73a58a045..37be9c2a56 100644 --- a/hw/gt64xxx.c +++ b/hw/gt64xxx.c @@ -1107,7 +1107,7 @@ PCIBus *gt64120_register(qemu_irq *pic) pic, get_system_memory(), get_system_io(), - PCI_DEVFN(18, 0), 4); + PCI_DEVFN(18, 0), 4, TYPE_PCI_BUS); memory_region_init_io(&d->ISD_mem, &isd_mem_ops, d, "isd-mem", 0x1000); pci_create_simple(phb->bus, PCI_DEVFN(0, 0), "gt64120_pci"); diff --git a/hw/i82801b11.c b/hw/i82801b11.c index 992095c80f..8b4a9c6e54 100644 --- a/hw/i82801b11.c +++ b/hw/i82801b11.c @@ -59,7 +59,7 @@ static int i82801b11_bridge_initfn(PCIDevice *d) { int rc; - rc = pci_bridge_initfn(d); + rc = pci_bridge_initfn(d, TYPE_PCI_BUS); if (rc < 0) { return rc; } diff --git a/hw/ioh3420.c b/hw/ioh3420.c index 43f855427b..74d84d4dda 100644 --- a/hw/ioh3420.c +++ b/hw/ioh3420.c @@ -97,7 +97,7 @@ static int ioh3420_initfn(PCIDevice *d) PCIESlot *s = DO_UPCAST(PCIESlot, port, p); int rc; - rc = pci_bridge_initfn(d); + rc = pci_bridge_initfn(d, TYPE_PCI_BUS); if (rc < 0) { return rc; } diff --git a/hw/pci/pci.c b/hw/pci/pci.c index 74f449d38e..7c5f2e283d 100644 --- a/hw/pci/pci.c +++ b/hw/pci/pci.c @@ -301,9 +301,9 @@ void pci_bus_new_inplace(PCIBus *bus, DeviceState *parent, const char *name, MemoryRegion *address_space_mem, MemoryRegion *address_space_io, - uint8_t devfn_min) + uint8_t devfn_min, const char *typename) { - qbus_create_inplace(bus, TYPE_PCI_BUS, parent, name); + qbus_create_inplace(bus, typename, parent, name); pci_bus_init(bus, parent, name, address_space_mem, address_space_io, devfn_min); } @@ -311,11 +311,11 @@ void pci_bus_new_inplace(PCIBus *bus, DeviceState *parent, PCIBus *pci_bus_new(DeviceState *parent, const char *name, MemoryRegion *address_space_mem, MemoryRegion *address_space_io, - uint8_t devfn_min) + uint8_t devfn_min, const char *typename) { PCIBus *bus; - bus = PCI_BUS(qbus_create(TYPE_PCI_BUS, parent, name)); + bus = PCI_BUS(qbus_create(typename, parent, name)); pci_bus_init(bus, parent, name, address_space_mem, address_space_io, devfn_min); return bus; @@ -343,12 +343,12 @@ PCIBus *pci_register_bus(DeviceState *parent, const char *name, void *irq_opaque, MemoryRegion *address_space_mem, MemoryRegion *address_space_io, - uint8_t devfn_min, int nirq) + uint8_t devfn_min, int nirq, const char *typename) { PCIBus *bus; bus = pci_bus_new(parent, name, address_space_mem, - address_space_io, devfn_min); + address_space_io, devfn_min, typename); pci_bus_irqs(bus, set_irq, map_irq, irq_opaque, nirq); return bus; } diff --git a/hw/pci/pci.h b/hw/pci/pci.h index 37fb52222f..10aeaf0cc6 100644 --- a/hw/pci/pci.h +++ b/hw/pci/pci.h @@ -348,11 +348,11 @@ void pci_bus_new_inplace(PCIBus *bus, DeviceState *parent, const char *name, MemoryRegion *address_space_mem, MemoryRegion *address_space_io, - uint8_t devfn_min); + uint8_t devfn_min, const char *typename); PCIBus *pci_bus_new(DeviceState *parent, const char *name, MemoryRegion *address_space_mem, MemoryRegion *address_space_io, - uint8_t devfn_min); + uint8_t devfn_min, const char *typename); void pci_bus_irqs(PCIBus *bus, pci_set_irq_fn set_irq, pci_map_irq_fn map_irq, void *irq_opaque, int nirq); int pci_bus_get_irq_level(PCIBus *bus, int irq_num); @@ -364,7 +364,7 @@ PCIBus *pci_register_bus(DeviceState *parent, const char *name, void *irq_opaque, MemoryRegion *address_space_mem, MemoryRegion *address_space_io, - uint8_t devfn_min, int nirq); + uint8_t devfn_min, int nirq, const char *typename); void pci_bus_set_route_irq_fn(PCIBus *, pci_route_irq_fn); PCIINTxRoute pci_device_route_intx_to_irq(PCIDevice *dev, int pin); bool pci_intx_route_changed(PCIINTxRoute *old, PCIINTxRoute *new); diff --git a/hw/pci/pci_bridge.c b/hw/pci/pci_bridge.c index bf93ac6ed1..24be6c5067 100644 --- a/hw/pci/pci_bridge.c +++ b/hw/pci/pci_bridge.c @@ -328,7 +328,7 @@ void pci_bridge_reset(DeviceState *qdev) } /* default qdev initialization function for PCI-to-PCI bridge */ -int pci_bridge_initfn(PCIDevice *dev) +int pci_bridge_initfn(PCIDevice *dev, const char *typename) { PCIBus *parent = dev->bus; PCIBridge *br = DO_UPCAST(PCIBridge, dev, dev); @@ -363,8 +363,7 @@ int pci_bridge_initfn(PCIDevice *dev) br->bus_name = dev->qdev.id; } - qbus_create_inplace(&sec_bus->qbus, TYPE_PCI_BUS, &dev->qdev, - br->bus_name); + qbus_create_inplace(&sec_bus->qbus, typename, &dev->qdev, br->bus_name); sec_bus->parent_dev = dev; sec_bus->map_irq = br->map_irq ? br->map_irq : pci_swizzle_map_irq_fn; sec_bus->address_space_mem = &br->address_space_mem; diff --git a/hw/pci/pci_bridge.h b/hw/pci/pci_bridge.h index e549b78a38..1868f7aea8 100644 --- a/hw/pci/pci_bridge.h +++ b/hw/pci/pci_bridge.h @@ -43,7 +43,7 @@ void pci_bridge_disable_base_limit(PCIDevice *dev); void pci_bridge_reset_reg(PCIDevice *dev); void pci_bridge_reset(DeviceState *qdev); -int pci_bridge_initfn(PCIDevice *pci_dev); +int pci_bridge_initfn(PCIDevice *pci_dev, const char *typename); void pci_bridge_exitfn(PCIDevice *pci_dev); diff --git a/hw/pci_bridge_dev.c b/hw/pci_bridge_dev.c index 840ef43f00..971b432474 100644 --- a/hw/pci_bridge_dev.c +++ b/hw/pci_bridge_dev.c @@ -42,7 +42,7 @@ static int pci_bridge_dev_initfn(PCIDevice *dev) PCIBridgeDev *bridge_dev = DO_UPCAST(PCIBridgeDev, bridge, br); int err; - err = pci_bridge_initfn(dev); + err = pci_bridge_initfn(dev, TYPE_PCI_BUS); if (err) { goto bridge_error; } diff --git a/hw/piix_pci.c b/hw/piix_pci.c index e10bc1c6a0..ce397797fc 100644 --- a/hw/piix_pci.c +++ b/hw/piix_pci.c @@ -245,7 +245,7 @@ static PCIBus *i440fx_common_init(const char *device_name, dev = qdev_create(NULL, "i440FX-pcihost"); s = PCI_HOST_BRIDGE(dev); b = pci_bus_new(dev, NULL, pci_address_space, - address_space_io, 0); + address_space_io, 0, TYPE_PCI_BUS); s->bus = b; object_property_add_child(qdev_get_machine(), "i440fx", OBJECT(dev), NULL); qdev_init_nofail(dev); diff --git a/hw/ppc4xx_pci.c b/hw/ppc4xx_pci.c index f3bbe88529..854e17048f 100644 --- a/hw/ppc4xx_pci.c +++ b/hw/ppc4xx_pci.c @@ -349,7 +349,7 @@ static int ppc4xx_pcihost_initfn(SysBusDevice *dev) b = pci_register_bus(DEVICE(dev), NULL, ppc4xx_pci_set_irq, ppc4xx_pci_map_irq, s->irq, get_system_memory(), - get_system_io(), 0, 4); + get_system_io(), 0, 4, TYPE_PCI_BUS); h->bus = b; pci_create_simple(b, 0, "ppc4xx-host-bridge"); diff --git a/hw/ppce500_pci.c b/hw/ppce500_pci.c index 310ae1c03d..abc7ebe1bf 100644 --- a/hw/ppce500_pci.c +++ b/hw/ppce500_pci.c @@ -356,7 +356,7 @@ static int e500_pcihost_initfn(SysBusDevice *dev) b = pci_register_bus(DEVICE(dev), NULL, mpc85xx_pci_set_irq, mpc85xx_pci_map_irq, s->irq, address_space_mem, - &s->pio, PCI_DEVFN(s->first_slot, 0), 4); + &s->pio, PCI_DEVFN(s->first_slot, 0), 4, TYPE_PCI_BUS); h->bus = b; pci_create_simple(b, 0, "e500-host-bridge"); diff --git a/hw/prep_pci.c b/hw/prep_pci.c index d21e87671e..58df2452cd 100644 --- a/hw/prep_pci.c +++ b/hw/prep_pci.c @@ -154,7 +154,7 @@ static void raven_pcihost_initfn(Object *obj) DeviceState *pci_dev; pci_bus_new_inplace(&s->pci_bus, DEVICE(obj), NULL, - address_space_mem, address_space_io, 0); + address_space_mem, address_space_io, 0, TYPE_PCI_BUS); h->bus = &s->pci_bus; object_initialize(&s->pci_dev, TYPE_RAVEN_PCI_DEVICE); diff --git a/hw/q35.c b/hw/q35.c index 0a25b8bf1f..37592bc088 100644 --- a/hw/q35.c +++ b/hw/q35.c @@ -54,7 +54,8 @@ static int q35_host_init(SysBusDevice *dev) return -1; } b = pci_bus_new(&s->host.pci.busdev.qdev, "pcie.0", - s->mch.pci_address_space, s->mch.address_space_io, 0); + s->mch.pci_address_space, s->mch.address_space_io, + 0, TYPE_PCI_BUS); s->host.pci.bus = b; qdev_set_parent_bus(DEVICE(&s->mch), BUS(b)); qdev_init_nofail(DEVICE(&s->mch)); diff --git a/hw/sh_pci.c b/hw/sh_pci.c index 96535dbe01..e3e7550ae7 100644 --- a/hw/sh_pci.c +++ b/hw/sh_pci.c @@ -124,7 +124,7 @@ static int sh_pci_device_init(SysBusDevice *dev) s->irq, get_system_memory(), get_system_io(), - PCI_DEVFN(0, 0), 4); + PCI_DEVFN(0, 0), 4, TYPE_PCI_BUS); memory_region_init_io(&s->memconfig_p4, &sh_pci_reg_ops, s, "sh_pci", 0x224); memory_region_init_alias(&s->memconfig_a7, "sh_pci.2", &s->memconfig_p4, diff --git a/hw/spapr_pci.c b/hw/spapr_pci.c index 36adbc5592..20b9015502 100644 --- a/hw/spapr_pci.c +++ b/hw/spapr_pci.c @@ -624,7 +624,7 @@ static int spapr_phb_init(SysBusDevice *s) bus = pci_register_bus(DEVICE(s), sphb->busname, pci_spapr_set_irq, pci_spapr_map_irq, sphb, &sphb->memspace, &sphb->iospace, - PCI_DEVFN(0, 0), PCI_NUM_PINS); + PCI_DEVFN(0, 0), PCI_NUM_PINS, TYPE_PCI_BUS); phb->bus = bus; sphb->dma_window_start = 0; diff --git a/hw/unin_pci.c b/hw/unin_pci.c index cb95ad1f5e..fff235d523 100644 --- a/hw/unin_pci.c +++ b/hw/unin_pci.c @@ -239,7 +239,7 @@ PCIBus *pci_pmac_init(qemu_irq *pic, pic, &d->pci_mmio, address_space_io, - PCI_DEVFN(11, 0), 4); + PCI_DEVFN(11, 0), 4, TYPE_PCI_BUS); #if 0 pci_create_simple(h->bus, PCI_DEVFN(11, 0), "uni-north"); @@ -305,7 +305,7 @@ PCIBus *pci_pmac_u3_init(qemu_irq *pic, pic, &d->pci_mmio, address_space_io, - PCI_DEVFN(11, 0), 4); + PCI_DEVFN(11, 0), 4, TYPE_PCI_BUS); sysbus_mmio_map(s, 0, 0xf0800000); sysbus_mmio_map(s, 1, 0xf0c00000); diff --git a/hw/versatile_pci.c b/hw/versatile_pci.c index 0b97a4073d..d67ca796fb 100644 --- a/hw/versatile_pci.c +++ b/hw/versatile_pci.c @@ -70,7 +70,7 @@ static int pci_vpb_init(SysBusDevice *dev) bus = pci_register_bus(&dev->qdev, "pci", pci_vpb_set_irq, pci_vpb_map_irq, s->irq, get_system_memory(), get_system_io(), - PCI_DEVFN(11, 0), 4); + PCI_DEVFN(11, 0), 4, TYPE_PCI_BUS); /* ??? Register memory space. */ diff --git a/hw/xio3130_downstream.c b/hw/xio3130_downstream.c index 4bccd0ddcd..a76d89bb6f 100644 --- a/hw/xio3130_downstream.c +++ b/hw/xio3130_downstream.c @@ -61,7 +61,7 @@ static int xio3130_downstream_initfn(PCIDevice *d) PCIESlot *s = DO_UPCAST(PCIESlot, port, p); int rc; - rc = pci_bridge_initfn(d); + rc = pci_bridge_initfn(d, TYPE_PCI_BUS); if (rc < 0) { return rc; } diff --git a/hw/xio3130_upstream.c b/hw/xio3130_upstream.c index 82556aaadc..d8fd19e196 100644 --- a/hw/xio3130_upstream.c +++ b/hw/xio3130_upstream.c @@ -57,7 +57,7 @@ static int xio3130_upstream_initfn(PCIDevice *d) PCIEPort *p = DO_UPCAST(PCIEPort, br, br); int rc; - rc = pci_bridge_initfn(d); + rc = pci_bridge_initfn(d, TYPE_PCI_BUS); if (rc < 0) { return rc; } -- cgit 1.4.1 From 8c0bf9e24242c89c1abbd708c714dd2a89febbd2 Mon Sep 17 00:00:00 2001 From: Alex Williamson Date: Thu, 14 Mar 2013 16:01:23 -0600 Subject: pci: Create pci_bus_is_express helper For testing the bus type. Signed-off-by: Alex Williamson Signed-off-by: Michael S. Tsirkin --- hw/pci/pci.c | 5 +++++ hw/pci/pci.h | 1 + 2 files changed, 6 insertions(+) (limited to 'hw/pci/pci.c') diff --git a/hw/pci/pci.c b/hw/pci/pci.c index 7c5f2e283d..7f28101cb4 100644 --- a/hw/pci/pci.c +++ b/hw/pci/pci.c @@ -297,6 +297,11 @@ static void pci_bus_init(PCIBus *bus, DeviceState *parent, vmstate_register(NULL, -1, &vmstate_pcibus, bus); } +bool pci_bus_is_express(PCIBus *bus) +{ + return object_dynamic_cast(OBJECT(bus), TYPE_PCIE_BUS); +} + void pci_bus_new_inplace(PCIBus *bus, DeviceState *parent, const char *name, MemoryRegion *address_space_mem, diff --git a/hw/pci/pci.h b/hw/pci/pci.h index 10aeaf0cc6..d715e6f09d 100644 --- a/hw/pci/pci.h +++ b/hw/pci/pci.h @@ -344,6 +344,7 @@ typedef int (*pci_hotplug_fn)(DeviceState *qdev, PCIDevice *pci_dev, #define PCI_BUS(obj) OBJECT_CHECK(PCIBus, (obj), TYPE_PCI_BUS) #define TYPE_PCIE_BUS "PCIE" +bool pci_bus_is_express(PCIBus *bus); void pci_bus_new_inplace(PCIBus *bus, DeviceState *parent, const char *name, MemoryRegion *address_space_mem, -- cgit 1.4.1 From 0889464a5050c25611d08ca33d8447796c88c7f7 Mon Sep 17 00:00:00 2001 From: Alex Williamson Date: Thu, 14 Mar 2013 16:01:29 -0600 Subject: pci: Create and use API to determine root buses Signed-off-by: Alex Williamson Signed-off-by: Michael S. Tsirkin --- hw/pci/pci.c | 13 +++++++++---- hw/pci/pci.h | 1 + 2 files changed, 10 insertions(+), 4 deletions(-) (limited to 'hw/pci/pci.c') diff --git a/hw/pci/pci.c b/hw/pci/pci.c index 7f28101cb4..d5257ed4c5 100644 --- a/hw/pci/pci.c +++ b/hw/pci/pci.c @@ -302,6 +302,11 @@ bool pci_bus_is_express(PCIBus *bus) return object_dynamic_cast(OBJECT(bus), TYPE_PCIE_BUS); } +bool pci_bus_is_root(PCIBus *bus) +{ + return !bus->parent_dev; +} + void pci_bus_new_inplace(PCIBus *bus, DeviceState *parent, const char *name, MemoryRegion *address_space_mem, @@ -360,7 +365,7 @@ PCIBus *pci_register_bus(DeviceState *parent, const char *name, int pci_bus_num(PCIBus *s) { - if (!s->parent_dev) + if (pci_bus_is_root(s)) return 0; /* pci host bridge */ return s->parent_dev->config[PCI_SECONDARY_BUS]; } @@ -1186,7 +1191,7 @@ static void pci_set_irq(void *opaque, int irq_num, int level) /* Special hooks used by device assignment */ void pci_bus_set_route_irq_fn(PCIBus *bus, pci_route_irq_fn route_intx_to_irq) { - assert(!bus->parent_dev); + assert(pci_bus_is_root(bus)); bus->route_intx_to_irq = route_intx_to_irq; } @@ -1651,7 +1656,7 @@ static PCIBus *pci_find_bus_nr(PCIBus *bus, int bus_num) } /* Consider all bus numbers in range for the host pci bridge. */ - if (bus->parent_dev && + if (!pci_bus_is_root(bus) && !pci_secondary_bus_in_range(bus->parent_dev, bus_num)) { return NULL; } @@ -1659,7 +1664,7 @@ static PCIBus *pci_find_bus_nr(PCIBus *bus, int bus_num) /* try child bus */ for (; bus; bus = sec) { QLIST_FOREACH(sec, &bus->child, sibling) { - assert(sec->parent_dev); + assert(!pci_bus_is_root(sec)); if (sec->parent_dev->config[PCI_SECONDARY_BUS] == bus_num) { return sec; } diff --git a/hw/pci/pci.h b/hw/pci/pci.h index d715e6f09d..774369cd9e 100644 --- a/hw/pci/pci.h +++ b/hw/pci/pci.h @@ -345,6 +345,7 @@ typedef int (*pci_hotplug_fn)(DeviceState *qdev, PCIDevice *pci_dev, #define TYPE_PCIE_BUS "PCIE" bool pci_bus_is_express(PCIBus *bus); +bool pci_bus_is_root(PCIBus *bus); void pci_bus_new_inplace(PCIBus *bus, DeviceState *parent, const char *name, MemoryRegion *address_space_mem, -- cgit 1.4.1