[Skiboot] [PATCH] pci-iov: free memory across fast-reboot

Stewart Smith stewart at linux.vnet.ibm.com
Mon Oct 9 15:06:24 AEDT 2017


pci_set_cap needs a callback to free data and we need to call
that when we're doing __pci_reset()

We also need to free pcrf entries.

In the future, __pci_reset() and pci_remove_bus() need to come
together to be one canonical place on how to free a PCI device
rather than the two we have now. This patch *purely* focuses
on the problem of not leaking memory across fast-reboot.

Signed-off-by: Stewart Smith <stewart at linux.vnet.ibm.com>
---
 core/pci-iov.c |  9 ++++++++-
 core/pci.c     | 14 +++++++++++---
 include/pci.h  |  9 +++++++--
 3 files changed, 26 insertions(+), 6 deletions(-)

diff --git a/core/pci-iov.c b/core/pci-iov.c
index 06fc4c6fa1e3..8fecebc1292a 100644
--- a/core/pci-iov.c
+++ b/core/pci-iov.c
@@ -189,6 +189,13 @@ static void pci_iov_init_VF(struct pci_device *pd, struct pci_device *vf)
 	list_head_init(&vf->children);
 }
 
+static void pci_free_iov_cap(void *data)
+{
+	struct pci_iov *iov = data;
+	free(iov->VFs);
+	free(iov);
+}
+
 void pci_init_iov_cap(struct phb *phb, struct pci_device *pd)
 {
 	int64_t pos;
@@ -254,5 +261,5 @@ void pci_init_iov_cap(struct phb *phb, struct pci_device *pd)
 	iov->pos = pos;
 	iov->enabled = false;
 	pci_iov_update_parameters(iov);
-	pci_set_cap(pd, PCIECAP_ID_SRIOV, pos, iov, true);
+	pci_set_cap(pd, PCIECAP_ID_SRIOV, pos, iov, pci_free_iov_cap, true);
 }
diff --git a/core/pci.c b/core/pci.c
index b6e7e824a498..0809521f8baf 100644
--- a/core/pci.c
+++ b/core/pci.c
@@ -162,7 +162,7 @@ static void pci_init_pcie_cap(struct phb *phb, struct pci_device *pd)
 		return;
 	}
 
-	pci_set_cap(pd, PCI_CFG_CAP_ID_EXP, ecap, NULL, false);
+	pci_set_cap(pd, PCI_CFG_CAP_ID_EXP, ecap, NULL, NULL, false);
 
 	/*
 	 * XXX We observe a problem on some PLX switches where one
@@ -198,7 +198,7 @@ static void pci_init_aer_cap(struct phb *phb, struct pci_device *pd)
 
 	pos = pci_find_ecap(phb, pd->bdfn, PCIECAP_ID_AER, NULL);
 	if (pos > 0)
-		pci_set_cap(pd, PCIECAP_ID_AER, pos, NULL, true);
+		pci_set_cap(pd, PCIECAP_ID_AER, pos, NULL, NULL, true);
 }
 
 static void pci_init_pm_cap(struct phb *phb, struct pci_device *pd)
@@ -207,7 +207,7 @@ static void pci_init_pm_cap(struct phb *phb, struct pci_device *pd)
 
 	pos = pci_find_cap(phb, pd->bdfn, PCI_CFG_CAP_ID_PM);
 	if (pos > 0)
-		pci_set_cap(pd, PCI_CFG_CAP_ID_PM, pos, NULL, false);
+		pci_set_cap(pd, PCI_CFG_CAP_ID_PM, pos, NULL, NULL, false);
 }
 
 void pci_init_capabilities(struct phb *phb, struct pci_device *pd)
@@ -1651,11 +1651,19 @@ void pci_add_device_nodes(struct phb *phb,
 static void __pci_reset(struct list_head *list)
 {
 	struct pci_device *pd;
+	struct pci_cfg_reg_filter *pcrf;
+	int i;
 
 	while ((pd = list_pop(list, struct pci_device, link)) != NULL) {
 		__pci_reset(&pd->children);
 		dt_free(pd->dn);
 		free(pd->slot);
+		while((pcrf = list_pop(&pd->pcrf, struct pci_cfg_reg_filter, link)) != NULL) {
+			free(pcrf);
+		}
+		for(i=0; i < 64; i++)
+			if (pd->cap[i].free_func)
+				pd->cap[i].free_func(pd->cap[i].data);
 		free(pd);
 	}
 }
diff --git a/include/pci.h b/include/pci.h
index d75c8d141111..c085b6b867bd 100644
--- a/include/pci.h
+++ b/include/pci.h
@@ -30,6 +30,7 @@ typedef int64_t (*pci_cfg_reg_func)(void *dev,
 				    struct pci_cfg_reg_filter *pcrf,
 				    uint32_t offset, uint32_t len,
 				    uint32_t *data, bool write);
+typedef void (*pci_cap_free_data_func)(void *data);
 struct pci_cfg_reg_filter {
 	uint32_t		flags;
 #define PCI_REG_FLAG_READ	0x1
@@ -81,6 +82,7 @@ struct pci_device {
 	struct {
 		uint32_t	pos;
 		void		*data;
+		pci_cap_free_data_func free_func;
 	} cap[64];
 	uint32_t		mps;		/* Max payload size capability */
 
@@ -96,17 +98,20 @@ struct pci_device {
 	struct list_node	link;
 };
 
-static inline void pci_set_cap(struct pci_device *pd, int id,
-			       int pos, void *data, bool ext)
+static inline void pci_set_cap(struct pci_device *pd, int id, int pos,
+			       void *data, pci_cap_free_data_func free_func,
+			       bool ext)
 {
 	if (!ext) {
 		pd->cap_list |= (0x1ul << id);
 		pd->cap[id].pos = pos;
 		pd->cap[id].data = data;
+		pd->cap[id].free_func = free_func;
 	} else {
 		pd->cap_list |= (0x1ul << (id + 32));
 		pd->cap[id + 32].pos = pos;
 		pd->cap[id + 32].data = data;
+		pd->cap[id + 32].free_func = free_func;
 	}
 }
 
-- 
2.13.6



More information about the Skiboot mailing list