From 936fc3afaa8abc20dfea306c9b6d19a6e7ca5caf Mon Sep 17 00:00:00 2001 From: Yazen Ghannam Date: Thu, 17 Nov 2016 17:57:36 -0500 Subject: [PATCH] EDAC, amd64: Reserve correct PCI devices on AMD Fam17h Fam17h needs PCI device functions 0 and 6 instead of 1 and 2 as on older systems. Update struct amd64_pvt to hold the new functions and reserve them if on Fam17h. Also, allocate an array of UMC structs within our newly allocated PVT struct. Signed-off-by: Yazen Ghannam Cc: Aravind Gopalakrishnan Cc: linux-edac Cc: x86-ml Link: http://lkml.kernel.org/r/1479423463-8536-11-git-send-email-Yazen.Ghannam@amd.com [ init_one_instance() error handling, shorten lines, unbreak >80 cols lines. ] Signed-off-by: Borislav Petkov --- drivers/edac/amd64_edac.c | 85 +++++++++++++++++++++++++++++++-------- drivers/edac/amd64_edac.h | 2 +- 2 files changed, 69 insertions(+), 18 deletions(-) diff --git a/drivers/edac/amd64_edac.c b/drivers/edac/amd64_edac.c index bb70392bb115..1f3de3402d48 100644 --- a/drivers/edac/amd64_edac.c +++ b/drivers/edac/amd64_edac.c @@ -2274,30 +2274,55 @@ static inline void decode_bus_error(int node_id, struct mce *m) /* * Use pvt->F3 which contains the F3 CPU PCI device to get the related * F1 (AddrMap) and F2 (Dct) devices. Return negative value on error. + * Reserve F0 and F6 on systems with a UMC. */ -static int reserve_mc_sibling_devs(struct amd64_pvt *pvt, u16 f1_id, u16 f2_id) +static int +reserve_mc_sibling_devs(struct amd64_pvt *pvt, u16 pci_id1, u16 pci_id2) { + if (pvt->umc) { + pvt->F0 = pci_get_related_function(pvt->F3->vendor, pci_id1, pvt->F3); + if (!pvt->F0) { + amd64_err("error F0 device not found: vendor %x device 0x%x (broken BIOS?)\n", + PCI_VENDOR_ID_AMD, pci_id1); + return -ENODEV; + } + + pvt->F6 = pci_get_related_function(pvt->F3->vendor, pci_id2, pvt->F3); + if (!pvt->F6) { + pci_dev_put(pvt->F0); + pvt->F0 = NULL; + + amd64_err("error F6 device not found: vendor %x device 0x%x (broken BIOS?)\n", + PCI_VENDOR_ID_AMD, pci_id2); + + return -ENODEV; + } + edac_dbg(1, "F0: %s\n", pci_name(pvt->F0)); + edac_dbg(1, "F3: %s\n", pci_name(pvt->F3)); + edac_dbg(1, "F6: %s\n", pci_name(pvt->F6)); + + return 0; + } + /* Reserve the ADDRESS MAP Device */ - pvt->F1 = pci_get_related_function(pvt->F3->vendor, f1_id, pvt->F3); + pvt->F1 = pci_get_related_function(pvt->F3->vendor, pci_id1, pvt->F3); if (!pvt->F1) { - amd64_err("error address map device not found: " - "vendor %x device 0x%x (broken BIOS?)\n", - PCI_VENDOR_ID_AMD, f1_id); + amd64_err("error address map device not found: vendor %x device 0x%x (broken BIOS?)\n", + PCI_VENDOR_ID_AMD, pci_id1); return -ENODEV; } /* Reserve the DCT Device */ - pvt->F2 = pci_get_related_function(pvt->F3->vendor, f2_id, pvt->F3); + pvt->F2 = pci_get_related_function(pvt->F3->vendor, pci_id2, pvt->F3); if (!pvt->F2) { pci_dev_put(pvt->F1); pvt->F1 = NULL; - amd64_err("error F2 device not found: " - "vendor %x device 0x%x (broken BIOS?)\n", - PCI_VENDOR_ID_AMD, f2_id); - - return -ENODEV; + amd64_err("error F2 device not found: vendor %x device 0x%x (broken BIOS?)\n", + PCI_VENDOR_ID_AMD, pci_id2); + return -ENODEV; } + edac_dbg(1, "F1: %s\n", pci_name(pvt->F1)); edac_dbg(1, "F2: %s\n", pci_name(pvt->F2)); edac_dbg(1, "F3: %s\n", pci_name(pvt->F3)); @@ -2307,8 +2332,13 @@ static int reserve_mc_sibling_devs(struct amd64_pvt *pvt, u16 f1_id, u16 f2_id) static void free_mc_sibling_devs(struct amd64_pvt *pvt) { - pci_dev_put(pvt->F1); - pci_dev_put(pvt->F2); + if (pvt->umc) { + pci_dev_put(pvt->F0); + pci_dev_put(pvt->F6); + } else { + pci_dev_put(pvt->F1); + pci_dev_put(pvt->F2); + } } /* @@ -2864,6 +2894,7 @@ static int init_one_instance(unsigned int nid) struct mem_ctl_info *mci = NULL; struct edac_mc_layer layers[2]; struct amd64_pvt *pvt = NULL; + u16 pci_id1, pci_id2; int err = 0, ret; ret = -ENOMEM; @@ -2879,10 +2910,23 @@ static int init_one_instance(unsigned int nid) if (!fam_type) goto err_free; - ret = -ENODEV; - err = reserve_mc_sibling_devs(pvt, fam_type->f1_id, fam_type->f2_id); + if (pvt->fam >= 0x17) { + pvt->umc = kcalloc(NUM_UMCS, sizeof(struct amd64_umc), GFP_KERNEL); + if (!pvt->umc) { + ret = -ENOMEM; + goto err_free; + } + + pci_id1 = fam_type->f0_id; + pci_id2 = fam_type->f6_id; + } else { + pci_id1 = fam_type->f1_id; + pci_id2 = fam_type->f2_id; + } + + err = reserve_mc_sibling_devs(pvt, pci_id1, pci_id2); if (err) - goto err_free; + goto err_post_init; read_mc_regs(pvt); @@ -2942,6 +2986,10 @@ err_add_mc: err_siblings: free_mc_sibling_devs(pvt); +err_post_init: + if (pvt->fam >= 0x17) + kfree(pvt->umc); + err_free: kfree(pvt); @@ -3044,7 +3092,10 @@ static void setup_pci_device(void) return; pvt = mci->pvt_info; - pci_ctl = edac_pci_create_generic_ctl(&pvt->F2->dev, EDAC_MOD_STR); + if (pvt->umc) + pci_ctl = edac_pci_create_generic_ctl(&pvt->F0->dev, EDAC_MOD_STR); + else + pci_ctl = edac_pci_create_generic_ctl(&pvt->F2->dev, EDAC_MOD_STR); if (!pci_ctl) { pr_warn("%s(): Unable to create PCI control\n", __func__); pr_warn("%s(): PCI error report via EDAC not set\n", __func__); diff --git a/drivers/edac/amd64_edac.h b/drivers/edac/amd64_edac.h index ada39f165a9b..4ca7d249f02e 100644 --- a/drivers/edac/amd64_edac.h +++ b/drivers/edac/amd64_edac.h @@ -309,7 +309,7 @@ struct amd64_pvt { struct low_ops *ops; /* pci_device handles which we utilize */ - struct pci_dev *F1, *F2, *F3; + struct pci_dev *F0, *F1, *F2, *F3, *F6; u16 mc_node_id; /* MC index of this MC node */ u8 fam; /* CPU family */