Patchwork [v3,2/3] pci: set PCI multi-function bit appropriately.

login
register
mail settings
Submitter Isaku Yamahata
Date June 18, 2010, 6:58 a.m.
Message ID <cfa5364c3e60fa5d98e427a5d206777ccf693bbe.1276843956.git.yamahata@valinux.co.jp>
Download mbox | patch
Permalink /patch/56140/
State New
Headers show

Comments

Isaku Yamahata - June 18, 2010, 6:58 a.m.
Set PCI multi-function bit appropriately.
PCI address, devfn ,is exported to users as addr property,
so users can populate pci function(PCIDevice in qemu)
at arbitrary devfn.
It means each function(PCIDevice) don't know whether pci device
(PCIDevice[8]) is multi function or not.
So this patch makes pci generic layer set the bit appropriately.

Signed-off-by: Isaku Yamahata <yamahata@valinux.co.jp>

---
changes v2 -> v3:
- introduce PCI_FUNC_MAX
- more commit log

changes v1 -> v2:
don't set header type register in configuration space.
---
 hw/pci.c |   27 +++++++++++++++++++++++++++
 hw/pci.h |    1 +
 2 files changed, 28 insertions(+), 0 deletions(-)

Patch

diff --git a/hw/pci.c b/hw/pci.c
index 62308df..d17770e 100644
--- a/hw/pci.c
+++ b/hw/pci.c
@@ -574,6 +574,32 @@  static void pci_init_wmask_bridge(PCIDevice *d)
     pci_set_word(d->wmask + PCI_BRIDGE_CONTROL, 0xffff);
 }
 
+static void pci_init_multifunction(PCIBus *bus, PCIDevice *dev)
+{
+    uint8_t slot = PCI_SLOT(dev->devfn);
+    uint8_t func;
+
+    /* we are here before bus->devices[dev->devfn] = dev */
+    assert(bus->devices[dev->devfn] == NULL);
+
+    for (func = 0; func < PCI_FUNC_MAX; ++func) {
+        if (bus->devices[PCI_DEVFN(slot, func)]) {
+            break;
+        }
+    }
+    if (func == PCI_FUNC_MAX) {
+        return;
+    }
+
+    for (func = 0; func < PCI_FUNC_MAX; ++func) {
+        if (bus->devices[PCI_DEVFN(slot, func)]) {
+            bus->devices[PCI_DEVFN(slot, func)]->config[PCI_HEADER_TYPE] |=
+                PCI_HEADER_TYPE_MULTI_FUNCTION;
+        }
+    }
+    dev->config[PCI_HEADER_TYPE] |= PCI_HEADER_TYPE_MULTI_FUNCTION;
+}
+
 static void pci_config_alloc(PCIDevice *pci_dev)
 {
     int config_size = pci_config_size(pci_dev);
@@ -627,6 +653,7 @@  static PCIDevice *do_pci_register_device(PCIDevice *pci_dev, PCIBus *bus,
     if (is_bridge) {
         pci_init_wmask_bridge(pci_dev);
     }
+    pci_init_multifunction(bus, pci_dev);
 
     if (!config_read)
         config_read = pci_default_read_config;
diff --git a/hw/pci.h b/hw/pci.h
index 4d682d4..76adc66 100644
--- a/hw/pci.h
+++ b/hw/pci.h
@@ -14,6 +14,7 @@ 
 #define PCI_DEVFN(slot, func)   ((((slot) & 0x1f) << 3) | ((func) & 0x07))
 #define PCI_SLOT(devfn)         (((devfn) >> 3) & 0x1f)
 #define PCI_FUNC(devfn)         ((devfn) & 0x07)
+#define PCI_FUNC_MAX            8
 
 /* Class, Vendor and Device IDs from Linux's pci_ids.h */
 #include "pci_ids.h"