Borislav Petkov 7e558c
From: Yazen Ghannam <yazen.ghannam@amd.com>
Borislav Petkov 7e558c
Date: Tue, 22 Oct 2019 20:35:10 +0000
Borislav Petkov 7e558c
Subject: EDAC/amd64: Gather hardware information early
Borislav Petkov 7e558c
Git-commit: 80355a3b2db9d0b713af5169e2cdd7f8fbfdad82
Borislav Petkov 7e558c
Patch-mainline: v5.5-rc1
Borislav Petkov 7e558c
References: bsc#1180552
Borislav Petkov 7e558c
Borislav Petkov 7e558c
Split out gathering hardware information from init_one_instance()
Borislav Petkov 7e558c
into a separate function hw_info_get(). This is necessary so that
Borislav Petkov 7e558c
the information can be cached earlier and used to check if memory is
Borislav Petkov 7e558c
populated and if ECC is enabled on a node.
Borislav Petkov 7e558c
Borislav Petkov 7e558c
Also, define a function hw_info_put() to back out changes made in
Borislav Petkov 7e558c
hw_info_get().
Borislav Petkov 7e558c
Borislav Petkov 7e558c
Check for an allocated PCI device (Function 0 for Family 17h or Function
Borislav Petkov 7e558c
1 for pre-Family 17h) before freeing, since hw_info_put() may be called
Borislav Petkov 7e558c
before PCI siblings are reserved.
Borislav Petkov 7e558c
Borislav Petkov 7e558c
Drop the family check when freeing pvt->umc. This will be NULL on
Borislav Petkov 7e558c
pre-Family 17h systems. However, kfree() is safe and will check for a
Borislav Petkov 7e558c
NULL pointer before freeing.
Borislav Petkov 7e558c
Borislav Petkov 7e558c
Signed-off-by: Yazen Ghannam <yazen.ghannam@amd.com>
Borislav Petkov 7e558c
Signed-off-by: Borislav Petkov <bp@suse.de>
Borislav Petkov 7e558c
Cc: "linux-edac@vger.kernel.org" <linux-edac@vger.kernel.org>
Borislav Petkov 7e558c
Cc: James Morse <james.morse@arm.com>
Borislav Petkov 7e558c
Cc: Mauro Carvalho Chehab <mchehab@kernel.org>
Borislav Petkov 7e558c
Cc: Robert Richter <rrichter@marvell.com>
Borislav Petkov 7e558c
Cc: Tony Luck <tony.luck@intel.com>
Borislav Petkov 7e558c
Link: https://lkml.kernel.org/r/20191106012448.243970-3-Yazen.Ghannam@amd.com
Borislav Petkov 7e558c
---
Borislav Petkov 7e558c
 drivers/edac/amd64_edac.c | 101 +++++++++++++++++++++++-----------------------
Borislav Petkov 7e558c
 1 file changed, 51 insertions(+), 50 deletions(-)
Borislav Petkov 7e558c
Borislav Petkov 7e558c
diff --git a/drivers/edac/amd64_edac.c b/drivers/edac/amd64_edac.c
Borislav Petkov 7e558c
index 83c659e38084..6e1c739b7fad 100644
Borislav Petkov 7e558c
--- a/drivers/edac/amd64_edac.c
Borislav Petkov 7e558c
+++ b/drivers/edac/amd64_edac.c
Borislav Petkov 7e558c
@@ -3418,34 +3418,15 @@ static void compute_num_umcs(void)
Borislav Petkov 7e558c
 	edac_dbg(1, "Number of UMCs: %x", num_umcs);
Borislav Petkov 7e558c
 }
Borislav Petkov 7e558c
 
Borislav Petkov 7e558c
-static int init_one_instance(unsigned int nid)
Borislav Petkov 7e558c
+static int hw_info_get(struct amd64_pvt *pvt)
Borislav Petkov 7e558c
 {
Borislav Petkov 7e558c
-	struct pci_dev *F3 = node_to_amd_nb(nid)->misc;
Borislav Petkov 7e558c
-	struct mem_ctl_info *mci = NULL;
Borislav Petkov 7e558c
-	struct edac_mc_layer layers[2];
Borislav Petkov 7e558c
-	struct amd64_pvt *pvt = NULL;
Borislav Petkov 7e558c
 	u16 pci_id1, pci_id2;
Borislav Petkov 7e558c
-	int err = 0, ret;
Borislav Petkov 7e558c
-
Borislav Petkov 7e558c
-	ret = -ENOMEM;
Borislav Petkov 7e558c
-	pvt = kzalloc(sizeof(struct amd64_pvt), GFP_KERNEL);
Borislav Petkov 7e558c
-	if (!pvt)
Borislav Petkov 7e558c
-		goto err_ret;
Borislav Petkov 7e558c
-
Borislav Petkov 7e558c
-	pvt->mc_node_id	= nid;
Borislav Petkov 7e558c
-	pvt->F3 = F3;
Borislav Petkov 7e558c
-
Borislav Petkov 7e558c
-	ret = -EINVAL;
Borislav Petkov 7e558c
-	fam_type = per_family_init(pvt);
Borislav Petkov 7e558c
-	if (!fam_type)
Borislav Petkov 7e558c
-		goto err_free;
Borislav Petkov 7e558c
+	int ret = -EINVAL;
Borislav Petkov 7e558c
 
Borislav Petkov 7e558c
 	if (pvt->fam >= 0x17) {
Borislav Petkov 7e558c
 		pvt->umc = kcalloc(num_umcs, sizeof(struct amd64_umc), GFP_KERNEL);
Borislav Petkov 7e558c
-		if (!pvt->umc) {
Borislav Petkov 7e558c
-			ret = -ENOMEM;
Borislav Petkov 7e558c
-			goto err_free;
Borislav Petkov 7e558c
-		}
Borislav Petkov 7e558c
+		if (!pvt->umc)
Borislav Petkov 7e558c
+			return -ENOMEM;
Borislav Petkov 7e558c
 
Borislav Petkov 7e558c
 		pci_id1 = fam_type->f0_id;
Borislav Petkov 7e558c
 		pci_id2 = fam_type->f6_id;
Borislav Petkov 7e558c
@@ -3454,21 +3435,37 @@ static int init_one_instance(unsigned int nid)
Borislav Petkov 7e558c
 		pci_id2 = fam_type->f2_id;
Borislav Petkov 7e558c
 	}
Borislav Petkov 7e558c
 
Borislav Petkov 7e558c
-	err = reserve_mc_sibling_devs(pvt, pci_id1, pci_id2);
Borislav Petkov 7e558c
-	if (err)
Borislav Petkov 7e558c
-		goto err_post_init;
Borislav Petkov 7e558c
+	ret = reserve_mc_sibling_devs(pvt, pci_id1, pci_id2);
Borislav Petkov 7e558c
+	if (ret)
Borislav Petkov 7e558c
+		return ret;
Borislav Petkov 7e558c
 
Borislav Petkov 7e558c
 	read_mc_regs(pvt);
Borislav Petkov 7e558c
 
Borislav Petkov 7e558c
+	return 0;
Borislav Petkov 7e558c
+}
Borislav Petkov 7e558c
+
Borislav Petkov 7e558c
+static void hw_info_put(struct amd64_pvt *pvt)
Borislav Petkov 7e558c
+{
Borislav Petkov 7e558c
+	if (pvt->F0 || pvt->F1)
Borislav Petkov 7e558c
+		free_mc_sibling_devs(pvt);
Borislav Petkov 7e558c
+
Borislav Petkov 7e558c
+	kfree(pvt->umc);
Borislav Petkov 7e558c
+}
Borislav Petkov 7e558c
+
Borislav Petkov 7e558c
+static int init_one_instance(struct amd64_pvt *pvt)
Borislav Petkov 7e558c
+{
Borislav Petkov 7e558c
+	struct mem_ctl_info *mci = NULL;
Borislav Petkov 7e558c
+	struct edac_mc_layer layers[2];
Borislav Petkov 7e558c
+	int ret = -EINVAL;
Borislav Petkov 7e558c
+
Borislav Petkov 7e558c
 	/*
Borislav Petkov 7e558c
 	 * We need to determine how many memory channels there are. Then use
Borislav Petkov 7e558c
 	 * that information for calculating the size of the dynamic instance
Borislav Petkov 7e558c
 	 * tables in the 'mci' structure.
Borislav Petkov 7e558c
 	 */
Borislav Petkov 7e558c
-	ret = -EINVAL;
Borislav Petkov 7e558c
 	pvt->channel_count = pvt->ops->early_channel_count(pvt);
Borislav Petkov 7e558c
 	if (pvt->channel_count < 0)
Borislav Petkov 7e558c
-		goto err_siblings;
Borislav Petkov 7e558c
+		return ret;
Borislav Petkov 7e558c
 
Borislav Petkov 7e558c
 	ret = -ENOMEM;
Borislav Petkov 7e558c
 	layers[0].type = EDAC_MC_LAYER_CHIP_SELECT;
Borislav Petkov 7e558c
@@ -3490,9 +3487,9 @@ static int init_one_instance(unsigned int nid)
Borislav Petkov 7e558c
 		layers[1].size = 2;
Borislav Petkov 7e558c
 	layers[1].is_virt_csrow = false;
Borislav Petkov 7e558c
 
Borislav Petkov 7e558c
-	mci = edac_mc_alloc(nid, ARRAY_SIZE(layers), layers, 0);
Borislav Petkov 7e558c
+	mci = edac_mc_alloc(pvt->mc_node_id, ARRAY_SIZE(layers), layers, 0);
Borislav Petkov 7e558c
 	if (!mci)
Borislav Petkov 7e558c
-		goto err_siblings;
Borislav Petkov 7e558c
+		return ret;
Borislav Petkov 7e558c
 
Borislav Petkov 7e558c
 	mci->pvt_info = pvt;
Borislav Petkov 7e558c
 	mci->pdev = &pvt->F3->dev;
Borislav Petkov 7e558c
@@ -3505,31 +3502,17 @@ static int init_one_instance(unsigned int nid)
Borislav Petkov 7e558c
 	ret = -ENODEV;
Borislav Petkov 7e558c
 	if (edac_mc_add_mc_with_groups(mci, amd64_edac_attr_groups)) {
Borislav Petkov 7e558c
 		edac_dbg(1, "failed edac_mc_add_mc()\n");
Borislav Petkov 7e558c
-		goto err_add_mc;
Borislav Petkov 7e558c
+		edac_mc_free(mci);
Borislav Petkov 7e558c
+		return ret;
Borislav Petkov 7e558c
 	}
Borislav Petkov 7e558c
 
Borislav Petkov 7e558c
 	return 0;
Borislav Petkov 7e558c
-
Borislav Petkov 7e558c
-err_add_mc:
Borislav Petkov 7e558c
-	edac_mc_free(mci);
Borislav Petkov 7e558c
-
Borislav Petkov 7e558c
-err_siblings:
Borislav Petkov 7e558c
-	free_mc_sibling_devs(pvt);
Borislav Petkov 7e558c
-
Borislav Petkov 7e558c
-err_post_init:
Borislav Petkov 7e558c
-	if (pvt->fam >= 0x17)
Borislav Petkov 7e558c
-		kfree(pvt->umc);
Borislav Petkov 7e558c
-
Borislav Petkov 7e558c
-err_free:
Borislav Petkov 7e558c
-	kfree(pvt);
Borislav Petkov 7e558c
-
Borislav Petkov 7e558c
-err_ret:
Borislav Petkov 7e558c
-	return ret;
Borislav Petkov 7e558c
 }
Borislav Petkov 7e558c
 
Borislav Petkov 7e558c
 static int probe_one_instance(unsigned int nid)
Borislav Petkov 7e558c
 {
Borislav Petkov 7e558c
 	struct pci_dev *F3 = node_to_amd_nb(nid)->misc;
Borislav Petkov 7e558c
+	struct amd64_pvt *pvt = NULL;
Borislav Petkov 7e558c
 	struct ecc_settings *s;
Borislav Petkov 7e558c
 	int ret;
Borislav Petkov 7e558c
 
Borislav Petkov 7e558c
@@ -3540,6 +3523,21 @@ static int probe_one_instance(unsigned int nid)
Borislav Petkov 7e558c
 
Borislav Petkov 7e558c
 	ecc_stngs[nid] = s;
Borislav Petkov 7e558c
 
Borislav Petkov 7e558c
+	pvt = kzalloc(sizeof(struct amd64_pvt), GFP_KERNEL);
Borislav Petkov 7e558c
+	if (!pvt)
Borislav Petkov 7e558c
+		goto err_settings;
Borislav Petkov 7e558c
+
Borislav Petkov 7e558c
+	pvt->mc_node_id	= nid;
Borislav Petkov 7e558c
+	pvt->F3 = F3;
Borislav Petkov 7e558c
+
Borislav Petkov 7e558c
+	fam_type = per_family_init(pvt);
Borislav Petkov 7e558c
+	if (!fam_type)
Borislav Petkov 7e558c
+		goto err_enable;
Borislav Petkov 7e558c
+
Borislav Petkov 7e558c
+	ret = hw_info_get(pvt);
Borislav Petkov 7e558c
+	if (ret < 0)
Borislav Petkov 7e558c
+		goto err_enable;
Borislav Petkov 7e558c
+
Borislav Petkov 7e558c
 	if (!ecc_enabled(F3, nid)) {
Borislav Petkov 7e558c
 		ret = 0;
Borislav Petkov 7e558c
 
Borislav Petkov 7e558c
@@ -3556,7 +3554,7 @@ static int probe_one_instance(unsigned int nid)
Borislav Petkov 7e558c
 			goto err_enable;
Borislav Petkov 7e558c
 	}
Borislav Petkov 7e558c
 
Borislav Petkov 7e558c
-	ret = init_one_instance(nid);
Borislav Petkov 7e558c
+	ret = init_one_instance(pvt);
Borislav Petkov 7e558c
 	if (ret < 0) {
Borislav Petkov 7e558c
 		amd64_err("Error probing instance: %d\n", nid);
Borislav Petkov 7e558c
 
Borislav Petkov 7e558c
@@ -3569,6 +3567,10 @@ static int probe_one_instance(unsigned int nid)
Borislav Petkov 7e558c
 	return ret;
Borislav Petkov 7e558c
 
Borislav Petkov 7e558c
 err_enable:
Borislav Petkov 7e558c
+	hw_info_put(pvt);
Borislav Petkov 7e558c
+	kfree(pvt);
Borislav Petkov 7e558c
+
Borislav Petkov 7e558c
+err_settings:
Borislav Petkov 7e558c
 	kfree(s);
Borislav Petkov 7e558c
 	ecc_stngs[nid] = NULL;
Borislav Petkov 7e558c
 
Borislav Petkov 7e558c
@@ -3595,14 +3597,13 @@ static void remove_one_instance(unsigned int nid)
Borislav Petkov 7e558c
 
Borislav Petkov 7e558c
 	restore_ecc_error_reporting(s, nid, F3);
Borislav Petkov 7e558c
 
Borislav Petkov 7e558c
-	free_mc_sibling_devs(pvt);
Borislav Petkov 7e558c
-
Borislav Petkov 7e558c
 	kfree(ecc_stngs[nid]);
Borislav Petkov 7e558c
 	ecc_stngs[nid] = NULL;
Borislav Petkov 7e558c
 
Borislav Petkov 7e558c
 	/* Free the EDAC CORE resources */
Borislav Petkov 7e558c
 	mci->pvt_info = NULL;
Borislav Petkov 7e558c
 
Borislav Petkov 7e558c
+	hw_info_put(pvt);
Borislav Petkov 7e558c
 	kfree(pvt);
Borislav Petkov 7e558c
 	edac_mc_free(mci);
Borislav Petkov 7e558c
 }
Borislav Petkov 7e558c