aboutsummaryrefslogtreecommitdiff
path: root/hw
diff options
context:
space:
mode:
Diffstat (limited to 'hw')
-rw-r--r--hw/apb_pci.c3
-rw-r--r--hw/pci.c52
-rw-r--r--hw/piix4.c2
-rw-r--r--hw/piix_pci.c2
4 files changed, 52 insertions, 7 deletions
diff --git a/hw/apb_pci.c b/hw/apb_pci.c
index fd11459980..0ecac55792 100644
--- a/hw/apb_pci.c
+++ b/hw/apb_pci.c
@@ -312,9 +312,6 @@ static void apb_pci_bridge_init(PCIBus *b)
PCI_STATUS_FAST_BACK | PCI_STATUS_66MHZ |
PCI_STATUS_DEVSEL_MEDIUM);
pci_set_byte(dev->config + PCI_REVISION_ID, 0x11);
- pci_set_byte(dev->config + PCI_HEADER_TYPE,
- pci_get_byte(dev->config + PCI_HEADER_TYPE) |
- PCI_HEADER_TYPE_MULTI_FUNCTION);
}
PCIBus *pci_apb_init(target_phys_addr_t special_base,
diff --git a/hw/pci.c b/hw/pci.c
index 6d1cbb1778..a3c28738c6 100644
--- a/hw/pci.c
+++ b/hw/pci.c
@@ -584,6 +584,54 @@ static void pci_init_wmask_bridge(PCIDevice *d)
pci_set_word(d->wmask + PCI_BRIDGE_CONTROL, 0xffff);
}
+static int pci_init_multifunction(PCIBus *bus, PCIDevice *dev)
+{
+ uint8_t slot = PCI_SLOT(dev->devfn);
+ uint8_t func;
+
+ if (dev->cap_present & QEMU_PCI_CAP_MULTIFUNCTION) {
+ dev->config[PCI_HEADER_TYPE] |= PCI_HEADER_TYPE_MULTI_FUNCTION;
+ }
+
+ /*
+ * multifuction bit is interpreted in two ways as follows.
+ * - all functions must set the bit to 1.
+ * Example: Intel X53
+ * - function 0 must set the bit, but the rest function (> 0)
+ * is allowed to leave the bit to 0.
+ * Example: PIIX3(also in qemu), PIIX4(also in qemu), ICH10,
+ *
+ * So OS (at least Linux) checks the bit of only function 0,
+ * and doesn't see the bit of function > 0.
+ *
+ * The below check allows both interpretation.
+ */
+ if (PCI_FUNC(dev->devfn)) {
+ PCIDevice *f0 = bus->devices[PCI_DEVFN(slot, 0)];
+ if (f0 && !(f0->cap_present & QEMU_PCI_CAP_MULTIFUNCTION)) {
+ /* function 0 should set multifunction bit */
+ error_report("PCI: single function device can't be populated "
+ "in function %x.%x", slot, PCI_FUNC(dev->devfn));
+ return -1;
+ }
+ return 0;
+ }
+
+ if (dev->cap_present & QEMU_PCI_CAP_MULTIFUNCTION) {
+ return 0;
+ }
+ /* function 0 indicates single function, so function > 0 must be NULL */
+ for (func = 1; func < PCI_FUNC_MAX; ++func) {
+ if (bus->devices[PCI_DEVFN(slot, func)]) {
+ error_report("PCI: %x.0 indicates single function, "
+ "but %x.%x is already populated.",
+ slot, slot, func);
+ return -1;
+ }
+ }
+ return 0;
+}
+
static void pci_config_alloc(PCIDevice *pci_dev)
{
int config_size = pci_config_size(pci_dev);
@@ -637,6 +685,10 @@ static PCIDevice *do_pci_register_device(PCIDevice *pci_dev, PCIBus *bus,
if (is_bridge) {
pci_init_wmask_bridge(pci_dev);
}
+ if (pci_init_multifunction(bus, pci_dev)) {
+ pci_config_free(pci_dev);
+ return NULL;
+ }
if (!config_read)
config_read = pci_default_read_config;
diff --git a/hw/piix4.c b/hw/piix4.c
index 902d6daca0..5489386d68 100644
--- a/hw/piix4.c
+++ b/hw/piix4.c
@@ -93,8 +93,6 @@ static int piix4_initfn(PCIDevice *d)
pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_INTEL);
pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_INTEL_82371AB_0); // 82371AB/EB/MB PIIX4 PCI-to-ISA bridge
pci_config_set_class(pci_conf, PCI_CLASS_BRIDGE_ISA);
- pci_conf[PCI_HEADER_TYPE] =
- PCI_HEADER_TYPE_NORMAL | PCI_HEADER_TYPE_MULTI_FUNCTION; // header_type = PCI_multifunction, generic
piix4_dev = d;
qemu_register_reset(piix4_reset, d);
diff --git a/hw/piix_pci.c b/hw/piix_pci.c
index 3426686e6b..f152a0ff06 100644
--- a/hw/piix_pci.c
+++ b/hw/piix_pci.c
@@ -335,8 +335,6 @@ static int piix3_initfn(PCIDevice *dev)
pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_INTEL);
pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_INTEL_82371SB_0); // 82371SB PIIX3 PCI-to-ISA bridge (Step A1)
pci_config_set_class(pci_conf, PCI_CLASS_BRIDGE_ISA);
- pci_conf[PCI_HEADER_TYPE] =
- PCI_HEADER_TYPE_NORMAL | PCI_HEADER_TYPE_MULTI_FUNCTION; // header_type = PCI_multifunction, generic
qemu_register_reset(piix3_reset, d);
return 0;