Merge tag 'for-linus' of git://git.kernel.org/pub/scm/virt/kvm/kvm
[firefly-linux-kernel-4.4.55.git] / arch / powerpc / kernel / pci_dn.c
index 83df3075d3df50b0b28ab5b53f14d5a1937031dd..b3b4df91b792cc59e533c7465b7543da37756de6 100644 (file)
 #include <asm/ppc-pci.h>
 #include <asm/firmware.h>
 
+/*
+ * The function is used to find the firmware data of one
+ * specific PCI device, which is attached to the indicated
+ * PCI bus. For VFs, their firmware data is linked to that
+ * one of PF's bridge. For other devices, their firmware
+ * data is linked to that of their bridge.
+ */
+static struct pci_dn *pci_bus_to_pdn(struct pci_bus *bus)
+{
+       struct pci_bus *pbus;
+       struct device_node *dn;
+       struct pci_dn *pdn;
+
+       /*
+        * We probably have virtual bus which doesn't
+        * have associated bridge.
+        */
+       pbus = bus;
+       while (pbus) {
+               if (pci_is_root_bus(pbus) || pbus->self)
+                       break;
+
+               pbus = pbus->parent;
+       }
+
+       /*
+        * Except virtual bus, all PCI buses should
+        * have device nodes.
+        */
+       dn = pci_bus_to_OF_node(pbus);
+       pdn = dn ? PCI_DN(dn) : NULL;
+
+       return pdn;
+}
+
+struct pci_dn *pci_get_pdn_by_devfn(struct pci_bus *bus,
+                                   int devfn)
+{
+       struct device_node *dn = NULL;
+       struct pci_dn *parent, *pdn;
+       struct pci_dev *pdev = NULL;
+
+       /* Fast path: fetch from PCI device */
+       list_for_each_entry(pdev, &bus->devices, bus_list) {
+               if (pdev->devfn == devfn) {
+                       if (pdev->dev.archdata.pci_data)
+                               return pdev->dev.archdata.pci_data;
+
+                       dn = pci_device_to_OF_node(pdev);
+                       break;
+               }
+       }
+
+       /* Fast path: fetch from device node */
+       pdn = dn ? PCI_DN(dn) : NULL;
+       if (pdn)
+               return pdn;
+
+       /* Slow path: fetch from firmware data hierarchy */
+       parent = pci_bus_to_pdn(bus);
+       if (!parent)
+               return NULL;
+
+       list_for_each_entry(pdn, &parent->child_list, list) {
+               if (pdn->busno == bus->number &&
+                    pdn->devfn == devfn)
+                        return pdn;
+        }
+
+       return NULL;
+}
+
 struct pci_dn *pci_get_pdn(struct pci_dev *pdev)
 {
-       struct device_node *dn = pci_device_to_OF_node(pdev);
-       if (!dn)
+       struct device_node *dn;
+       struct pci_dn *parent, *pdn;
+
+       /* Search device directly */
+       if (pdev->dev.archdata.pci_data)
+               return pdev->dev.archdata.pci_data;
+
+       /* Check device node */
+       dn = pci_device_to_OF_node(pdev);
+       pdn = dn ? PCI_DN(dn) : NULL;
+       if (pdn)
+               return pdn;
+
+       /*
+        * VFs don't have device nodes. We hook their
+        * firmware data to PF's bridge.
+        */
+       parent = pci_bus_to_pdn(pdev->bus);
+       if (!parent)
+               return NULL;
+
+       list_for_each_entry(pdn, &parent->child_list, list) {
+               if (pdn->busno == pdev->bus->number &&
+                   pdn->devfn == pdev->devfn)
+                       return pdn;
+       }
+
+       return NULL;
+}
+
+#ifdef CONFIG_PCI_IOV
+static struct pci_dn *add_one_dev_pci_data(struct pci_dn *parent,
+                                          struct pci_dev *pdev,
+                                          int busno, int devfn)
+{
+       struct pci_dn *pdn;
+
+       /* Except PHB, we always have the parent */
+       if (!parent)
+               return NULL;
+
+       pdn = kzalloc(sizeof(*pdn), GFP_KERNEL);
+       if (!pdn) {
+               dev_warn(&pdev->dev, "%s: Out of memory!\n", __func__);
                return NULL;
-       return PCI_DN(dn);
+       }
+
+       pdn->phb = parent->phb;
+       pdn->parent = parent;
+       pdn->busno = busno;
+       pdn->devfn = devfn;
+#ifdef CONFIG_PPC_POWERNV
+       pdn->pe_number = IODA_INVALID_PE;
+#endif
+       INIT_LIST_HEAD(&pdn->child_list);
+       INIT_LIST_HEAD(&pdn->list);
+       list_add_tail(&pdn->list, &parent->child_list);
+
+       /*
+        * If we already have PCI device instance, lets
+        * bind them.
+        */
+       if (pdev)
+               pdev->dev.archdata.pci_data = pdn;
+
+       return pdn;
+}
+#endif
+
+struct pci_dn *add_dev_pci_data(struct pci_dev *pdev)
+{
+#ifdef CONFIG_PCI_IOV
+       struct pci_dn *parent, *pdn;
+       int i;
+
+       /* Only support IOV for now */
+       if (!pdev->is_physfn)
+               return pci_get_pdn(pdev);
+
+       /* Check if VFs have been populated */
+       pdn = pci_get_pdn(pdev);
+       if (!pdn || (pdn->flags & PCI_DN_FLAG_IOV_VF))
+               return NULL;
+
+       pdn->flags |= PCI_DN_FLAG_IOV_VF;
+       parent = pci_bus_to_pdn(pdev->bus);
+       if (!parent)
+               return NULL;
+
+       for (i = 0; i < pci_sriov_get_totalvfs(pdev); i++) {
+               pdn = add_one_dev_pci_data(parent, NULL,
+                                          pci_iov_virtfn_bus(pdev, i),
+                                          pci_iov_virtfn_devfn(pdev, i));
+               if (!pdn) {
+                       dev_warn(&pdev->dev, "%s: Cannot create firmware data for VF#%d\n",
+                                __func__, i);
+                       return NULL;
+               }
+       }
+#endif /* CONFIG_PCI_IOV */
+
+       return pci_get_pdn(pdev);
+}
+
+void remove_dev_pci_data(struct pci_dev *pdev)
+{
+#ifdef CONFIG_PCI_IOV
+       struct pci_dn *parent;
+       struct pci_dn *pdn, *tmp;
+       int i;
+
+       /*
+        * VF and VF PE are created/released dynamically, so we need to
+        * bind/unbind them.  Otherwise the VF and VF PE would be mismatched
+        * when re-enabling SR-IOV.
+        */
+       if (pdev->is_virtfn) {
+               pdn = pci_get_pdn(pdev);
+#ifdef CONFIG_PPC_POWERNV
+               pdn->pe_number = IODA_INVALID_PE;
+#endif
+               return;
+       }
+
+       /* Only support IOV PF for now */
+       if (!pdev->is_physfn)
+               return;
+
+       /* Check if VFs have been populated */
+       pdn = pci_get_pdn(pdev);
+       if (!pdn || !(pdn->flags & PCI_DN_FLAG_IOV_VF))
+               return;
+
+       pdn->flags &= ~PCI_DN_FLAG_IOV_VF;
+       parent = pci_bus_to_pdn(pdev->bus);
+       if (!parent)
+               return;
+
+       /*
+        * We might introduce flag to pci_dn in future
+        * so that we can release VF's firmware data in
+        * a batch mode.
+        */
+       for (i = 0; i < pci_sriov_get_totalvfs(pdev); i++) {
+               list_for_each_entry_safe(pdn, tmp,
+                       &parent->child_list, list) {
+                       if (pdn->busno != pci_iov_virtfn_bus(pdev, i) ||
+                           pdn->devfn != pci_iov_virtfn_devfn(pdev, i))
+                               continue;
+
+                       if (!list_empty(&pdn->list))
+                               list_del(&pdn->list);
+
+                       kfree(pdn);
+               }
+       }
+#endif /* CONFIG_PCI_IOV */
 }
 
 /*
@@ -49,6 +274,7 @@ void *update_dn_pci_info(struct device_node *dn, void *data)
        struct pci_controller *phb = data;
        const __be32 *type = of_get_property(dn, "ibm,pci-config-space-type", NULL);
        const __be32 *regs;
+       struct device_node *parent;
        struct pci_dn *pdn;
 
        pdn = zalloc_maybe_bootmem(sizeof(*pdn), GFP_KERNEL);
@@ -69,7 +295,25 @@ void *update_dn_pci_info(struct device_node *dn, void *data)
                pdn->devfn = (addr >> 8) & 0xff;
        }
 
+       /* vendor/device IDs and class code */
+       regs = of_get_property(dn, "vendor-id", NULL);
+       pdn->vendor_id = regs ? of_read_number(regs, 1) : 0;
+       regs = of_get_property(dn, "device-id", NULL);
+       pdn->device_id = regs ? of_read_number(regs, 1) : 0;
+       regs = of_get_property(dn, "class-code", NULL);
+       pdn->class_code = regs ? of_read_number(regs, 1) : 0;
+
+       /* Extended config space */
        pdn->pci_ext_config_space = (type && of_read_number(type, 1) == 1);
+
+       /* Attach to parent node */
+       INIT_LIST_HEAD(&pdn->child_list);
+       INIT_LIST_HEAD(&pdn->list);
+       parent = of_get_parent(dn);
+       pdn->parent = parent ? PCI_DN(parent) : NULL;
+       if (pdn->parent)
+               list_add_tail(&pdn->list, &pdn->parent->child_list);
+
        return NULL;
 }
 
@@ -131,6 +375,46 @@ void *traverse_pci_devices(struct device_node *start, traverse_func pre,
        return NULL;
 }
 
+static struct pci_dn *pci_dn_next_one(struct pci_dn *root,
+                                     struct pci_dn *pdn)
+{
+       struct list_head *next = pdn->child_list.next;
+
+       if (next != &pdn->child_list)
+               return list_entry(next, struct pci_dn, list);
+
+       while (1) {
+               if (pdn == root)
+                       return NULL;
+
+               next = pdn->list.next;
+               if (next != &pdn->parent->child_list)
+                       break;
+
+               pdn = pdn->parent;
+       }
+
+       return list_entry(next, struct pci_dn, list);
+}
+
+void *traverse_pci_dn(struct pci_dn *root,
+                     void *(*fn)(struct pci_dn *, void *),
+                     void *data)
+{
+       struct pci_dn *pdn = root;
+       void *ret;
+
+       /* Only scan the child nodes */
+       for (pdn = pci_dn_next_one(root, pdn); pdn;
+            pdn = pci_dn_next_one(root, pdn)) {
+               ret = fn(pdn, data);
+               if (ret)
+                       return ret;
+       }
+
+       return NULL;
+}
+
 /** 
  * pci_devs_phb_init_dynamic - setup pci devices under this PHB
  * phb: pci-to-host bridge (top-level bridge connecting to cpu)
@@ -147,8 +431,12 @@ void pci_devs_phb_init_dynamic(struct pci_controller *phb)
        /* PHB nodes themselves must not match */
        update_dn_pci_info(dn, phb);
        pdn = dn->data;
-       if (pdn)
+       if (pdn) {
                pdn->devfn = pdn->busno = -1;
+               pdn->vendor_id = pdn->device_id = pdn->class_code = 0;
+               pdn->phb = phb;
+               phb->pci_data = pdn;
+       }
 
        /* Update dn->phb ptrs for new phb and children devices */
        traverse_pci_devices(dn, update_dn_pci_info, phb);
@@ -171,3 +459,16 @@ void __init pci_devs_phb_init(void)
        list_for_each_entry_safe(phb, tmp, &hose_list, list_node)
                pci_devs_phb_init_dynamic(phb);
 }
+
+static void pci_dev_pdn_setup(struct pci_dev *pdev)
+{
+       struct pci_dn *pdn;
+
+       if (pdev->dev.archdata.pci_data)
+               return;
+
+       /* Setup the fast path */
+       pdn = pci_get_pdn(pdev);
+       pdev->dev.archdata.pci_data = pdn;
+}
+DECLARE_PCI_FIXUP_EARLY(PCI_ANY_ID, PCI_ANY_ID, pci_dev_pdn_setup);