aboutsummaryrefslogtreecommitdiff
path: root/hw/pci
diff options
context:
space:
mode:
authorAnthony Liguori <aliguori@us.ibm.com>2013-03-26 16:16:43 -0500
committerAnthony Liguori <aliguori@us.ibm.com>2013-03-26 16:16:43 -0500
commit404e7a4f4af753bd2aef649adf79e7434fb6dc31 (patch)
tree43a43089f2e5cab27bd5d514ba2e9753d9c760af /hw/pci
parent18501ae6e825d8da72369fd091018ef71071bd87 (diff)
parent6214e73cc5b75a4f8d89a70d71727edfa47a81b3 (diff)
Merge remote-tracking branch 'mst/tags/for_anthony' into staging
virtio,pci,qom Work by Alex to support VGA assignment, pci and virtio fixes by Stefan, Jason and myself, and a new qmp event for hotplug support by myself. Signed-off-by: Michael S. Tsirkin <mst@redhat.com> # gpg: Signature made Tue 26 Mar 2013 02:02:24 PM CDT using RSA key ID D28D5469 # gpg: Can't check signature: public key not found # By Alex Williamson (13) and others # Via Michael S. Tsirkin * mst/tags/for_anthony: (23 commits) pcie: Add endpoint capability initialization wrapper roms: switch oldnoconfig to olddefconfig pcie: Mangle types to match topology pci: Create and use API to determine root buses pci: Create pci_bus_is_express helper pci: Q35, Root Ports, and Switches create PCI Express buses pci: Allow PCI bus creation interfaces to specify the type of bus pci: Move PCI and PCIE type defines pci: Create and register a new PCI Express TypeInfo exec: assert that RAMBlock size is non-zero pci: refuse empty ROM files pci_bridge: Remove duplicate IRQ swizzle function pci_bridge: Use a default map_irq function pci: Fix INTx routing notifier recursion pci_bridge: drop formatting from source pci_bridge: factor out common code pci: Teach PCI Bridges about VGA routing pci: Add PCI VGA helpers virtio-pci: guest notifier mask without non-irqfd virtio-net: remove layout assumptions for mq ctrl ...
Diffstat (limited to 'hw/pci')
-rw-r--r--hw/pci/pci.c121
-rw-r--r--hw/pci/pci.h34
-rw-r--r--hw/pci/pci_bridge.c51
-rw-r--r--hw/pci/pci_bridge.h17
-rw-r--r--hw/pci/pci_bus.h10
-rw-r--r--hw/pci/pcie.c16
-rw-r--r--hw/pci/pcie.h1
-rw-r--r--hw/pci/pcie_port.c18
8 files changed, 220 insertions, 48 deletions
diff --git a/hw/pci/pci.c b/hw/pci/pci.c
index 2f45c8f02f..d5257ed4c5 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);
@@ -292,13 +297,23 @@ 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);
+}
+
+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,
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);
}
@@ -306,11 +321,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;
@@ -338,19 +353,19 @@ 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;
}
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];
}
@@ -668,12 +683,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).
+ */
pci_set_word(d->wmask + PCI_BRIDGE_CONTROL,
PCI_BRIDGE_CTL_PARITY |
PCI_BRIDGE_CTL_SERR |
@@ -875,6 +888,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 +952,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 +1108,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)
@@ -1117,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;
}
@@ -1156,9 +1230,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);
}
}
@@ -1581,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;
}
@@ -1589,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;
}
@@ -1852,7 +1927,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;
}
@@ -2171,6 +2251,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.h b/hw/pci/pci.h
index 3beb70bf9a..9ea67a3832 100644
--- a/hw/pci/pci.h
+++ b/hw/pci/pci.h
@@ -109,6 +109,20 @@ typedef struct PCIIORegion {
#define PCI_ROM_SLOT 6
#define PCI_NUM_REGIONS 7
+enum {
+ QEMU_PCI_VGA_MEM,
+ QEMU_PCI_VGA_IO_LO,
+ QEMU_PCI_VGA_IO_HI,
+ QEMU_PCI_VGA_NUM_REGIONS,
+};
+
+#define QEMU_PCI_VGA_MEM_BASE 0xa0000
+#define QEMU_PCI_VGA_MEM_SIZE 0x20000
+#define QEMU_PCI_VGA_IO_LO_BASE 0x3b0
+#define QEMU_PCI_VGA_IO_LO_SIZE 0xc
+#define QEMU_PCI_VGA_IO_HI_BASE 0x3c0
+#define QEMU_PCI_VGA_IO_HI_SIZE 0x20
+
#include "hw/pci/pci_regs.h"
/* PCI HEADER_TYPE */
@@ -235,6 +249,10 @@ struct PCIDevice {
/* IRQ objects for the INTA-INTD pins. */
qemu_irq *irq;
+ /* Legacy PCI VGA regions */
+ MemoryRegion *vga_regions[QEMU_PCI_VGA_NUM_REGIONS];
+ bool has_vga;
+
/* Current IRQ levels. Used internally by the generic PCI code. */
uint8_t irq_state;
@@ -288,6 +306,9 @@ struct PCIDevice {
void pci_register_bar(PCIDevice *pci_dev, int region_num,
uint8_t attr, MemoryRegion *memory);
+void pci_register_vga(PCIDevice *pci_dev, MemoryRegion *mem,
+ MemoryRegion *io_lo, MemoryRegion *io_hi);
+void pci_unregister_vga(PCIDevice *pci_dev);
pcibus_t pci_get_bar_addr(PCIDevice *pci_dev, int region_num);
int pci_add_capability(PCIDevice *pdev, uint8_t cap_id,
@@ -319,15 +340,22 @@ typedef enum {
typedef int (*pci_hotplug_fn)(DeviceState *qdev, PCIDevice *pci_dev,
PCIHotplugState state);
+
+#define TYPE_PCI_BUS "PCI"
+#define PCI_BUS(obj) OBJECT_CHECK(PCIBus, (obj), TYPE_PCI_BUS)
+#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,
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);
@@ -339,7 +367,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 995842a72d..24be6c5067 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);
}
@@ -298,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);
@@ -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) |
@@ -323,10 +363,9 @@ 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;
+ sec_bus->map_irq = br->map_irq ? br->map_irq : pci_swizzle_map_irq_fn;
sec_bus->address_space_mem = &br->address_space_mem;
memory_region_init(&br->address_space_mem, "pci_bridge_pci", INT64_MAX);
sec_bus->address_space_io = &br->address_space_io;
diff --git a/hw/pci/pci_bridge.h b/hw/pci/pci_bridge.h
index 455cb6677a..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);
@@ -55,12 +55,11 @@ 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:
- * c-indent-level: 4
- * c-basic-offset: 4
- * tab-width: 8
- * indent-tab-mode: nil
- * End:
- */
diff --git a/hw/pci/pci_bus.h b/hw/pci/pci_bus.h
index f905b9e11e..6ee443cf88 100644
--- a/hw/pci/pci_bus.h
+++ b/hw/pci/pci_bus.h
@@ -8,9 +8,6 @@
* use accessor functions in pci.h, pci_bridge.h
*/
-#define TYPE_PCI_BUS "PCI"
-#define PCI_BUS(obj) OBJECT_CHECK(PCIBus, (obj), TYPE_PCI_BUS)
-
struct PCIBus {
BusState qbus;
PCIDMAContextFunc dma_context_fn;
@@ -47,6 +44,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.c b/hw/pci/pcie.c
index 485c94c1b2..62bd0b8b3e 100644
--- a/hw/pci/pcie.c
+++ b/hw/pci/pcie.c
@@ -87,6 +87,22 @@ int pcie_cap_init(PCIDevice *dev, uint8_t offset, uint8_t type, uint8_t port)
return pos;
}
+int pcie_endpoint_cap_init(PCIDevice *dev, uint8_t offset)
+{
+ uint8_t type = PCI_EXP_TYPE_ENDPOINT;
+
+ /*
+ * Windows guests will report Code 10, device cannot start, if
+ * a regular Endpoint type is exposed on a root complex. These
+ * should instead be Root Complex Integrated Endpoints.
+ */
+ if (pci_bus_is_express(dev->bus) && pci_bus_is_root(dev->bus)) {
+ type = PCI_EXP_TYPE_RC_END;
+ }
+
+ return pcie_cap_init(dev, offset, type, 0);
+}
+
void pcie_cap_exit(PCIDevice *dev)
{
pci_del_capability(dev, PCI_CAP_ID_EXP, PCI_EXP_VER2_SIZEOF);
diff --git a/hw/pci/pcie.h b/hw/pci/pcie.h
index 31604e2742..c010007c5e 100644
--- a/hw/pci/pcie.h
+++ b/hw/pci/pcie.h
@@ -95,6 +95,7 @@ struct PCIExpressDevice {
/* PCI express capability helper functions */
int pcie_cap_init(PCIDevice *dev, uint8_t offset, uint8_t type, uint8_t port);
+int pcie_endpoint_cap_init(PCIDevice *dev, uint8_t offset);
void pcie_cap_exit(PCIDevice *dev);
uint8_t pcie_cap_get_type(const PCIDevice *dev);
void pcie_cap_flags_set_vector(PCIDevice *dev, uint8_t vector);
diff --git a/hw/pci/pcie_port.c b/hw/pci/pcie_port.c
index 33a6b0a08a..91b53a0fc2 100644
--- a/hw/pci/pcie_port.c
+++ b/hw/pci/pcie_port.c
@@ -27,13 +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. */
- pci_set_word(d->wmask + PCI_BRIDGE_CONTROL,
- PCI_BRIDGE_CTL_PARITY |
- PCI_BRIDGE_CTL_ISA |
- PCI_BRIDGE_CTL_VGA |
- 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);
}
/**************************************************************************