powerpc/pci: Introduce pci_remove_device_node_info()
[cascardo/linux.git] / arch / powerpc / kernel / pci_dn.c
index 38102cb..ce10281 100644 (file)
@@ -282,13 +282,9 @@ void remove_dev_pci_data(struct pci_dev *pdev)
 #endif /* CONFIG_PCI_IOV */
 }
 
-/*
- * Traverse_func that inits the PCI fields of the device node.
- * NOTE: this *must* be done before read/write config to the device.
- */
-void *update_dn_pci_info(struct device_node *dn, void *data)
+struct pci_dn *pci_add_device_node_info(struct pci_controller *hose,
+                                       struct device_node *dn)
 {
-       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;
@@ -299,7 +295,7 @@ void *update_dn_pci_info(struct device_node *dn, void *data)
                return NULL;
        dn->data = pdn;
        pdn->node = dn;
-       pdn->phb = phb;
+       pdn->phb = hose;
 #ifdef CONFIG_PPC_POWERNV
        pdn->pe_number = IODA_INVALID_PE;
 #endif
@@ -331,8 +327,32 @@ void *update_dn_pci_info(struct device_node *dn, void *data)
        if (pdn->parent)
                list_add_tail(&pdn->list, &pdn->parent->child_list);
 
-       return NULL;
+       return pdn;
 }
+EXPORT_SYMBOL_GPL(pci_add_device_node_info);
+
+void pci_remove_device_node_info(struct device_node *dn)
+{
+       struct pci_dn *pdn = dn ? PCI_DN(dn) : NULL;
+#ifdef CONFIG_EEH
+       struct eeh_dev *edev = pdn_to_eeh_dev(pdn);
+
+       if (edev)
+               edev->pdn = NULL;
+#endif
+
+       if (!pdn)
+               return;
+
+       WARN_ON(!list_empty(&pdn->child_list));
+       list_del(&pdn->list);
+       if (pdn->parent)
+               of_node_put(pdn->parent->node);
+
+       dn->data = NULL;
+       kfree(pdn);
+}
+EXPORT_SYMBOL_GPL(pci_remove_device_node_info);
 
 /*
  * Traverse a device tree stopping each PCI device in the tree.
@@ -432,6 +452,18 @@ void *traverse_pci_dn(struct pci_dn *root,
        return NULL;
 }
 
+static void *add_pdn(struct device_node *dn, void *data)
+{
+       struct pci_controller *hose = data;
+       struct pci_dn *pdn;
+
+       pdn = pci_add_device_node_info(hose, dn);
+       if (!pdn)
+               return ERR_PTR(-ENOMEM);
+
+       return NULL;
+}
+
 /** 
  * pci_devs_phb_init_dynamic - setup pci devices under this PHB
  * phb: pci-to-host bridge (top-level bridge connecting to cpu)
@@ -446,8 +478,7 @@ void pci_devs_phb_init_dynamic(struct pci_controller *phb)
        struct pci_dn *pdn;
 
        /* PHB nodes themselves must not match */
-       update_dn_pci_info(dn, phb);
-       pdn = dn->data;
+       pdn = pci_add_device_node_info(phb, dn);
        if (pdn) {
                pdn->devfn = pdn->busno = -1;
                pdn->vendor_id = pdn->device_id = pdn->class_code = 0;
@@ -456,7 +487,7 @@ void pci_devs_phb_init_dynamic(struct pci_controller *phb)
        }
 
        /* Update dn->phb ptrs for new phb and children devices */
-       traverse_pci_devices(dn, update_dn_pci_info, phb);
+       traverse_pci_devices(dn, add_pdn, phb);
 }
 
 /**