aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/edac
diff options
context:
space:
mode:
authorDaniel J Blueman <daniel@numascale-asia.com>2012-11-30 03:44:19 -0500
committerBorislav Petkov <bp@suse.de>2013-01-10 10:17:59 -0500
commite2c0bffea2574c088d86a9f1f661a84bc8fea2fd (patch)
treeaa660ed07334a579f6a84347c0bd14ef4a43ecdb /drivers/edac
parent8b84c8df38d5796da2e8cd051666d203ddabcb62 (diff)
amd64_edac: Fix PCI function lookup
Fix locating sibling memory controller PCI functions by using the correct PCI domain and use a northbridge descriptor only if found. We need to at least warn if it wasn't found so that it gets fixed and we don't go off with wrong results. Signed-off-by: Daniel J Blueman <daniel@numascale-asia.com> Link: http://lkml.kernel.org/r/1354265060-22956-1-git-send-email-daniel@numascale-asia.com [Boris: remove wrong comment, sanitize code and warn if NB desc lookup fails] Signed-off-by: Borislav Petkov <bp@alien8.de>
Diffstat (limited to 'drivers/edac')
-rw-r--r--drivers/edac/amd64_edac.c72
1 files changed, 38 insertions, 34 deletions
diff --git a/drivers/edac/amd64_edac.c b/drivers/edac/amd64_edac.c
index 29be39d02076..da76912a873d 100644
--- a/drivers/edac/amd64_edac.c
+++ b/drivers/edac/amd64_edac.c
@@ -980,10 +980,29 @@ static u64 get_error_address(struct mce *m)
980 return addr; 980 return addr;
981} 981}
982 982
983static struct pci_dev *pci_get_related_function(unsigned int vendor,
984 unsigned int device,
985 struct pci_dev *related)
986{
987 struct pci_dev *dev = NULL;
988
989 while ((dev = pci_get_device(vendor, device, dev))) {
990 if (pci_domain_nr(dev->bus) == pci_domain_nr(related->bus) &&
991 (dev->bus->number == related->bus->number) &&
992 (PCI_SLOT(dev->devfn) == PCI_SLOT(related->devfn)))
993 break;
994 }
995
996 return dev;
997}
998
983static void read_dram_base_limit_regs(struct amd64_pvt *pvt, unsigned range) 999static void read_dram_base_limit_regs(struct amd64_pvt *pvt, unsigned range)
984{ 1000{
1001 struct amd_northbridge *nb;
1002 struct pci_dev *misc, *f1 = NULL;
985 struct cpuinfo_x86 *c = &boot_cpu_data; 1003 struct cpuinfo_x86 *c = &boot_cpu_data;
986 int off = range << 3; 1004 int off = range << 3;
1005 u32 llim;
987 1006
988 amd64_read_pci_cfg(pvt->F1, DRAM_BASE_LO + off, &pvt->ranges[range].base.lo); 1007 amd64_read_pci_cfg(pvt->F1, DRAM_BASE_LO + off, &pvt->ranges[range].base.lo);
989 amd64_read_pci_cfg(pvt->F1, DRAM_LIMIT_LO + off, &pvt->ranges[range].lim.lo); 1008 amd64_read_pci_cfg(pvt->F1, DRAM_LIMIT_LO + off, &pvt->ranges[range].lim.lo);
@@ -997,30 +1016,32 @@ static void read_dram_base_limit_regs(struct amd64_pvt *pvt, unsigned range)
997 amd64_read_pci_cfg(pvt->F1, DRAM_BASE_HI + off, &pvt->ranges[range].base.hi); 1016 amd64_read_pci_cfg(pvt->F1, DRAM_BASE_HI + off, &pvt->ranges[range].base.hi);
998 amd64_read_pci_cfg(pvt->F1, DRAM_LIMIT_HI + off, &pvt->ranges[range].lim.hi); 1017 amd64_read_pci_cfg(pvt->F1, DRAM_LIMIT_HI + off, &pvt->ranges[range].lim.hi);
999 1018
1000 /* Factor in CC6 save area by reading dst node's limit reg */ 1019 /* F15h: factor in CC6 save area by reading dst node's limit reg */
1001 if (c->x86 == 0x15) { 1020 if (c->x86 != 0x15)
1002 struct pci_dev *f1 = NULL; 1021 return;
1003 u8 nid = dram_dst_node(pvt, range);
1004 u32 llim;
1005 1022
1006 f1 = pci_get_domain_bus_and_slot(0, 0, PCI_DEVFN(0x18 + nid, 1)); 1023 nb = node_to_amd_nb(dram_dst_node(pvt, range));
1007 if (WARN_ON(!f1)) 1024 if (WARN_ON(!nb))
1008 return; 1025 return;
1009 1026
1010 amd64_read_pci_cfg(f1, DRAM_LOCAL_NODE_LIM, &llim); 1027 misc = nb->misc;
1028 f1 = pci_get_related_function(misc->vendor, PCI_DEVICE_ID_AMD_15H_NB_F1, misc);
1029 if (WARN_ON(!f1))
1030 return;
1011 1031
1012 pvt->ranges[range].lim.lo &= GENMASK(0, 15); 1032 amd64_read_pci_cfg(f1, DRAM_LOCAL_NODE_LIM, &llim);
1013 1033
1014 /* {[39:27],111b} */ 1034 pvt->ranges[range].lim.lo &= GENMASK(0, 15);
1015 pvt->ranges[range].lim.lo |= ((llim & 0x1fff) << 3 | 0x7) << 16;
1016 1035
1017 pvt->ranges[range].lim.hi &= GENMASK(0, 7); 1036 /* {[39:27],111b} */
1037 pvt->ranges[range].lim.lo |= ((llim & 0x1fff) << 3 | 0x7) << 16;
1018 1038
1019 /* [47:40] */ 1039 pvt->ranges[range].lim.hi &= GENMASK(0, 7);
1020 pvt->ranges[range].lim.hi |= llim >> 13;
1021 1040
1022 pci_dev_put(f1); 1041 /* [47:40] */
1023 } 1042 pvt->ranges[range].lim.hi |= llim >> 13;
1043
1044 pci_dev_put(f1);
1024} 1045}
1025 1046
1026static void k8_map_sysaddr_to_csrow(struct mem_ctl_info *mci, u64 sys_addr, 1047static void k8_map_sysaddr_to_csrow(struct mem_ctl_info *mci, u64 sys_addr,
@@ -1673,23 +1694,6 @@ static struct amd64_family_type amd64_family_types[] = {
1673 }, 1694 },
1674}; 1695};
1675 1696
1676static struct pci_dev *pci_get_related_function(unsigned int vendor,
1677 unsigned int device,
1678 struct pci_dev *related)
1679{
1680 struct pci_dev *dev = NULL;
1681
1682 dev = pci_get_device(vendor, device, dev);
1683 while (dev) {
1684 if ((dev->bus->number == related->bus->number) &&
1685 (PCI_SLOT(dev->devfn) == PCI_SLOT(related->devfn)))
1686 break;
1687 dev = pci_get_device(vendor, device, dev);
1688 }
1689
1690 return dev;
1691}
1692
1693/* 1697/*
1694 * These are tables of eigenvectors (one per line) which can be used for the 1698 * These are tables of eigenvectors (one per line) which can be used for the
1695 * construction of the syndrome tables. The modified syndrome search algorithm 1699 * construction of the syndrome tables. The modified syndrome search algorithm