[v2,3/4] core/pci: Release IOV capability on removing device

Message ID 1497854809-26032-4-git-send-email-gwshan@linux.vnet.ibm.com
State New
Headers show

Commit Message

Gavin Shan June 19, 2017, 6:46 a.m.
This introduces helper function pci_release_dev(), release the
specified PCI device, to be shared in fast-reboot and PCI hot
remove path. From there, pci_release_capabilities() and
pci_release_iov_cap() is called to free memory allocated for
IOV capability and VFs.

Signed-off-by: Gavin Shan <gwshan@linux.vnet.ibm.com>
---
 core/pci-iov.c    | 14 ++++++++++++++
 core/pci.c        | 52 +++++++++++++++++++++++++++++++++-------------------
 include/pci-iov.h |  2 +-
 3 files changed, 48 insertions(+), 20 deletions(-)

Patch

diff --git a/core/pci-iov.c b/core/pci-iov.c
index 627f300..9866b22 100644
--- a/core/pci-iov.c
+++ b/core/pci-iov.c
@@ -256,3 +256,17 @@  void pci_init_iov_cap(struct phb *phb, struct pci_device *pd)
 	pci_iov_update_parameters(iov);
 	pci_set_cap(pd, PCIECAP_ID_SRIOV, pos, true);
 }
+
+void pci_release_iov_cap(struct pci_device *pd)
+{
+	if (!pd->iov)
+		return;
+
+	if (pd->iov->VFs) {
+		free(pd->iov->VFs);
+		pd->iov->VFs = NULL;
+	}
+
+	free(pd->iov);
+	pd->iov = NULL;
+}
diff --git a/core/pci.c b/core/pci.c
index 1aa906a..684c054 100644
--- a/core/pci.c
+++ b/core/pci.c
@@ -218,6 +218,11 @@  void pci_init_capabilities(struct phb *phb, struct pci_device *pd)
 	pci_init_pm_cap(phb, pd);
 }
 
+static void pci_release_capabilities(struct pci_device *pd)
+{
+	pci_release_iov_cap(pd);
+}
+
 static struct pci_device *pci_scan_one(struct phb *phb, struct pci_device *parent,
 				       uint16_t bdfn)
 {
@@ -673,6 +678,26 @@  static void pci_cleanup_bridge(struct phb *phb, struct pci_device *pd)
 	pci_cfg_write16(phb, pd->bdfn, PCI_CFG_CMD, cmd);	
 }
 
+static void pci_release_dev(struct phb *phb, struct pci_device *pd)
+{
+	if (phb->ops->device_remove)
+		phb->ops->device_remove(phb, pd);
+
+	pci_release_capabilities(pd);
+	if (pd->dn) {
+		dt_free(pd->dn);
+		pd->dn = NULL;
+	}
+
+	if (pd->slot) {
+		free(pd->slot);
+		pd->slot = NULL;
+	}
+
+	list_del(&pd->link);
+	free(pd);
+}
+
 /* Remove all subordinate PCI devices leading from the indicated
  * PCI bus. It's used to remove all PCI devices behind one PCI
  * slot at unplugging time
@@ -684,18 +709,7 @@  void pci_remove_bus(struct phb *phb, struct list_head *list)
 	list_for_each_safe(list, pd, tmp, link) {
 		pci_remove_bus(phb, &pd->children);
 
-		if (phb->ops->device_remove)
-			phb->ops->device_remove(phb, pd);
-
-		/* Release device node and PCI slot */
-		if (pd->dn)
-			dt_free(pd->dn);
-		if (pd->slot)
-			free(pd->slot);
-
-		/* Remove from parent list and release itself */
-		list_del(&pd->link);
-		free(pd);
+		pci_release_dev(phb, pd);
 	}
 }
 
@@ -1631,14 +1645,14 @@  void pci_add_device_nodes(struct phb *phb,
 	}
 }
 
-static void __pci_reset(struct list_head *list)
+static void __pci_reset(struct phb *phb, struct list_head *list)
 {
-	struct pci_device *pd;
+	struct pci_device *pd, *tmp;
 
-	while ((pd = list_pop(list, struct pci_device, link)) != NULL) {
-		__pci_reset(&pd->children);
-		dt_free(pd->dn);
-		free(pd);
+	list_for_each_safe(list, pd, tmp, link) {
+		__pci_reset(phb, &pd->children);
+
+		pci_release_dev(phb, pd);
 	}
 }
 
@@ -1657,7 +1671,7 @@  void pci_reset(void)
 		struct phb *phb = phbs[i];
 		if (!phb)
 			continue;
-		__pci_reset(&phb->devices);
+		__pci_reset(phb, &phb->devices);
 
 		slot = phb->slot;
 		if (!slot || !slot->ops.creset) {
diff --git a/include/pci-iov.h b/include/pci-iov.h
index 787b2cd..18da320 100644
--- a/include/pci-iov.h
+++ b/include/pci-iov.h
@@ -33,5 +33,5 @@  struct pci_iov {
 };
 
 extern void pci_init_iov_cap(struct phb *phb, struct pci_device *pd);
-
+extern void pci_release_iov_cap(struct pci_device *pd);
 #endif