diff options
Diffstat (limited to 'hw')
-rw-r--r-- | hw/apb_pci.c | 3 | ||||
-rw-r--r-- | hw/pci.c | 52 | ||||
-rw-r--r-- | hw/piix4.c | 2 | ||||
-rw-r--r-- | hw/piix_pci.c | 2 |
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, @@ -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; |