Merge tag 'edac_3.9' of git://git.kernel.org/pub/scm/linux/kernel/git/bp/bp
[platform/adaptation/renesas_rcar/renesas_kernel.git] / drivers / edac / amd64_edac.c
index ad8bf2a..910b011 100644 (file)
@@ -31,7 +31,7 @@ static struct ecc_settings **ecc_stngs;
  *
  *FIXME: Produce a better mapping/linearisation.
  */
-struct scrubrate {
+static const struct scrubrate {
        u32 scrubval;           /* bit pattern for scrub rate */
        u32 bandwidth;          /* bandwidth consumed (bytes/sec) */
 } scrubrates[] = {
@@ -239,7 +239,7 @@ static int amd64_get_scrub_rate(struct mem_ctl_info *mci)
  * DRAM base/limit associated with node_id
  */
 static bool amd64_base_limit_match(struct amd64_pvt *pvt, u64 sys_addr,
-                                  unsigned nid)
+                                  u8 nid)
 {
        u64 addr;
 
@@ -265,7 +265,7 @@ static struct mem_ctl_info *find_mc_by_sys_addr(struct mem_ctl_info *mci,
                                                u64 sys_addr)
 {
        struct amd64_pvt *pvt;
-       unsigned node_id;
+       u8 node_id;
        u32 intlv_en, bits;
 
        /*
@@ -602,111 +602,6 @@ static u64 sys_addr_to_input_addr(struct mem_ctl_info *mci, u64 sys_addr)
        return input_addr;
 }
 
-
-/*
- * @input_addr is an InputAddr associated with the node represented by mci.
- * Translate @input_addr to a DramAddr and return the result.
- */
-static u64 input_addr_to_dram_addr(struct mem_ctl_info *mci, u64 input_addr)
-{
-       struct amd64_pvt *pvt;
-       unsigned node_id, intlv_shift;
-       u64 bits, dram_addr;
-       u32 intlv_sel;
-
-       /*
-        * Near the start of section 3.4.4 (p. 70, BKDG #26094, K8, revA-E)
-        * shows how to translate a DramAddr to an InputAddr. Here we reverse
-        * this procedure. When translating from a DramAddr to an InputAddr, the
-        * bits used for node interleaving are discarded.  Here we recover these
-        * bits from the IntlvSel field of the DRAM Limit register (section
-        * 3.4.4.2) for the node that input_addr is associated with.
-        */
-       pvt = mci->pvt_info;
-       node_id = pvt->mc_node_id;
-
-       BUG_ON(node_id > 7);
-
-       intlv_shift = num_node_interleave_bits(dram_intlv_en(pvt, 0));
-       if (intlv_shift == 0) {
-               edac_dbg(1, "    InputAddr 0x%lx translates to DramAddr of same value\n",
-                        (unsigned long)input_addr);
-
-               return input_addr;
-       }
-
-       bits = ((input_addr & GENMASK(12, 35)) << intlv_shift) +
-               (input_addr & 0xfff);
-
-       intlv_sel = dram_intlv_sel(pvt, node_id) & ((1 << intlv_shift) - 1);
-       dram_addr = bits + (intlv_sel << 12);
-
-       edac_dbg(1, "InputAddr 0x%lx translates to DramAddr 0x%lx (%d node interleave bits)\n",
-                (unsigned long)input_addr,
-                (unsigned long)dram_addr, intlv_shift);
-
-       return dram_addr;
-}
-
-/*
- * @dram_addr is a DramAddr that maps to the node represented by mci. Convert
- * @dram_addr to a SysAddr.
- */
-static u64 dram_addr_to_sys_addr(struct mem_ctl_info *mci, u64 dram_addr)
-{
-       struct amd64_pvt *pvt = mci->pvt_info;
-       u64 hole_base, hole_offset, hole_size, base, sys_addr;
-       int ret = 0;
-
-       ret = amd64_get_dram_hole_info(mci, &hole_base, &hole_offset,
-                                     &hole_size);
-       if (!ret) {
-               if ((dram_addr >= hole_base) &&
-                   (dram_addr < (hole_base + hole_size))) {
-                       sys_addr = dram_addr + hole_offset;
-
-                       edac_dbg(1, "using DHAR to translate DramAddr 0x%lx to SysAddr 0x%lx\n",
-                                (unsigned long)dram_addr,
-                                (unsigned long)sys_addr);
-
-                       return sys_addr;
-               }
-       }
-
-       base     = get_dram_base(pvt, pvt->mc_node_id);
-       sys_addr = dram_addr + base;
-
-       /*
-        * The sys_addr we have computed up to this point is a 40-bit value
-        * because the k8 deals with 40-bit values.  However, the value we are
-        * supposed to return is a full 64-bit physical address.  The AMD
-        * x86-64 architecture specifies that the most significant implemented
-        * address bit through bit 63 of a physical address must be either all
-        * 0s or all 1s.  Therefore we sign-extend the 40-bit sys_addr to a
-        * 64-bit value below.  See section 3.4.2 of AMD publication 24592:
-        * AMD x86-64 Architecture Programmer's Manual Volume 1 Application
-        * Programming.
-        */
-       sys_addr |= ~((sys_addr & (1ull << 39)) - 1);
-
-       edac_dbg(1, "    Node %d, DramAddr 0x%lx to SysAddr 0x%lx\n",
-                pvt->mc_node_id, (unsigned long)dram_addr,
-                (unsigned long)sys_addr);
-
-       return sys_addr;
-}
-
-/*
- * @input_addr is an InputAddr associated with the node given by mci. Translate
- * @input_addr to a SysAddr.
- */
-static inline u64 input_addr_to_sys_addr(struct mem_ctl_info *mci,
-                                        u64 input_addr)
-{
-       return dram_addr_to_sys_addr(mci,
-                                    input_addr_to_dram_addr(mci, input_addr));
-}
-
 /* Map the Error address to a PAGE and PAGE OFFSET. */
 static inline void error_address_to_page_and_offset(u64 error_address,
                                                    struct err_info *err)
@@ -939,7 +834,8 @@ static u64 get_error_address(struct mce *m)
                struct amd64_pvt *pvt;
                u64 cc6_base, tmp_addr;
                u32 tmp;
-               u8 mce_nid, intlv_en;
+               u16 mce_nid;
+               u8 intlv_en;
 
                if ((addr & GENMASK(24, 47)) >> 24 != 0x00fdf7)
                        return addr;
@@ -979,10 +875,29 @@ static u64 get_error_address(struct mce *m)
        return addr;
 }
 
+static struct pci_dev *pci_get_related_function(unsigned int vendor,
+                                               unsigned int device,
+                                               struct pci_dev *related)
+{
+       struct pci_dev *dev = NULL;
+
+       while ((dev = pci_get_device(vendor, device, dev))) {
+               if (pci_domain_nr(dev->bus) == pci_domain_nr(related->bus) &&
+                   (dev->bus->number == related->bus->number) &&
+                   (PCI_SLOT(dev->devfn) == PCI_SLOT(related->devfn)))
+                       break;
+       }
+
+       return dev;
+}
+
 static void read_dram_base_limit_regs(struct amd64_pvt *pvt, unsigned range)
 {
+       struct amd_northbridge *nb;
+       struct pci_dev *misc, *f1 = NULL;
        struct cpuinfo_x86 *c = &boot_cpu_data;
        int off = range << 3;
+       u32 llim;
 
        amd64_read_pci_cfg(pvt->F1, DRAM_BASE_LO + off,  &pvt->ranges[range].base.lo);
        amd64_read_pci_cfg(pvt->F1, DRAM_LIMIT_LO + off, &pvt->ranges[range].lim.lo);
@@ -996,30 +911,32 @@ static void read_dram_base_limit_regs(struct amd64_pvt *pvt, unsigned range)
        amd64_read_pci_cfg(pvt->F1, DRAM_BASE_HI + off,  &pvt->ranges[range].base.hi);
        amd64_read_pci_cfg(pvt->F1, DRAM_LIMIT_HI + off, &pvt->ranges[range].lim.hi);
 
-       /* Factor in CC6 save area by reading dst node's limit reg */
-       if (c->x86 == 0x15) {
-               struct pci_dev *f1 = NULL;
-               u8 nid = dram_dst_node(pvt, range);
-               u32 llim;
+       /* F15h: factor in CC6 save area by reading dst node's limit reg */
+       if (c->x86 != 0x15)
+               return;
 
-               f1 = pci_get_domain_bus_and_slot(0, 0, PCI_DEVFN(0x18 + nid, 1));
-               if (WARN_ON(!f1))
-                       return;
+       nb = node_to_amd_nb(dram_dst_node(pvt, range));
+       if (WARN_ON(!nb))
+               return;
+
+       misc = nb->misc;
+       f1 = pci_get_related_function(misc->vendor, PCI_DEVICE_ID_AMD_15H_NB_F1, misc);
+       if (WARN_ON(!f1))
+               return;
 
-               amd64_read_pci_cfg(f1, DRAM_LOCAL_NODE_LIM, &llim);
+       amd64_read_pci_cfg(f1, DRAM_LOCAL_NODE_LIM, &llim);
 
-               pvt->ranges[range].lim.lo &= GENMASK(0, 15);
+       pvt->ranges[range].lim.lo &= GENMASK(0, 15);
 
-                                           /* {[39:27],111b} */
-               pvt->ranges[range].lim.lo |= ((llim & 0x1fff) << 3 | 0x7) << 16;
+                                   /* {[39:27],111b} */
+       pvt->ranges[range].lim.lo |= ((llim & 0x1fff) << 3 | 0x7) << 16;
 
-               pvt->ranges[range].lim.hi &= GENMASK(0, 7);
+       pvt->ranges[range].lim.hi &= GENMASK(0, 7);
 
-                                           /* [47:40] */
-               pvt->ranges[range].lim.hi |= llim >> 13;
+                                   /* [47:40] */
+       pvt->ranges[range].lim.hi |= llim >> 13;
 
-               pci_dev_put(f1);
-       }
+       pci_dev_put(f1);
 }
 
 static void k8_map_sysaddr_to_csrow(struct mem_ctl_info *mci, u64 sys_addr,
@@ -1305,7 +1222,7 @@ static u8 f1x_determine_channel(struct amd64_pvt *pvt, u64 sys_addr,
 }
 
 /* Convert the sys_addr to the normalized DCT address */
-static u64 f1x_get_norm_dct_addr(struct amd64_pvt *pvt, unsigned range,
+static u64 f1x_get_norm_dct_addr(struct amd64_pvt *pvt, u8 range,
                                 u64 sys_addr, bool hi_rng,
                                 u32 dct_sel_base_addr)
 {
@@ -1381,7 +1298,7 @@ static int f10_process_possible_spare(struct amd64_pvt *pvt, u8 dct, int csrow)
  *     -EINVAL:  NOT FOUND
  *     0..csrow = Chip-Select Row
  */
-static int f1x_lookup_addr_in_dct(u64 in_addr, u32 nid, u8 dct)
+static int f1x_lookup_addr_in_dct(u64 in_addr, u8 nid, u8 dct)
 {
        struct mem_ctl_info *mci;
        struct amd64_pvt *pvt;
@@ -1672,23 +1589,6 @@ static struct amd64_family_type amd64_family_types[] = {
        },
 };
 
-static struct pci_dev *pci_get_related_function(unsigned int vendor,
-                                               unsigned int device,
-                                               struct pci_dev *related)
-{
-       struct pci_dev *dev = NULL;
-
-       dev = pci_get_device(vendor, device, dev);
-       while (dev) {
-               if ((dev->bus->number == related->bus->number) &&
-                   (PCI_SLOT(dev->devfn) == PCI_SLOT(related->devfn)))
-                       break;
-               dev = pci_get_device(vendor, device, dev);
-       }
-
-       return dev;
-}
-
 /*
  * These are tables of eigenvectors (one per line) which can be used for the
  * construction of the syndrome tables. The modified syndrome search algorithm
@@ -1696,7 +1596,7 @@ static struct pci_dev *pci_get_related_function(unsigned int vendor,
  *
  * Algorithm courtesy of Ross LaFetra from AMD.
  */
-static u16 x4_vectors[] = {
+static const u16 x4_vectors[] = {
        0x2f57, 0x1afe, 0x66cc, 0xdd88,
        0x11eb, 0x3396, 0x7f4c, 0xeac8,
        0x0001, 0x0002, 0x0004, 0x0008,
@@ -1735,7 +1635,7 @@ static u16 x4_vectors[] = {
        0x19a9, 0x2efe, 0xb5cc, 0x6f88,
 };
 
-static u16 x8_vectors[] = {
+static const u16 x8_vectors[] = {
        0x0145, 0x028a, 0x2374, 0x43c8, 0xa1f0, 0x0520, 0x0a40, 0x1480,
        0x0211, 0x0422, 0x0844, 0x1088, 0x01b0, 0x44e0, 0x23c0, 0xed80,
        0x1011, 0x0116, 0x022c, 0x0458, 0x08b0, 0x8c60, 0x2740, 0x4e80,
@@ -1757,7 +1657,7 @@ static u16 x8_vectors[] = {
        0x0100, 0x0200, 0x0400, 0x0800, 0x1000, 0x2000, 0x4000, 0x8000,
 };
 
-static int decode_syndrome(u16 syndrome, u16 *vectors, unsigned num_vecs,
+static int decode_syndrome(u16 syndrome, const u16 *vectors, unsigned num_vecs,
                           unsigned v_dim)
 {
        unsigned int i, err_sym;
@@ -2181,7 +2081,7 @@ static int init_csrows(struct mem_ctl_info *mci)
 }
 
 /* get all cores on this DCT */
-static void get_cpus_on_this_dct_cpumask(struct cpumask *mask, unsigned nid)
+static void get_cpus_on_this_dct_cpumask(struct cpumask *mask, u16 nid)
 {
        int cpu;
 
@@ -2191,7 +2091,7 @@ static void get_cpus_on_this_dct_cpumask(struct cpumask *mask, unsigned nid)
 }
 
 /* check MCG_CTL on all the cpus on this node */
-static bool amd64_nb_mce_bank_enabled_on_node(unsigned nid)
+static bool amd64_nb_mce_bank_enabled_on_node(u16 nid)
 {
        cpumask_var_t mask;
        int cpu, nbe;
@@ -2224,7 +2124,7 @@ out:
        return ret;
 }
 
-static int toggle_ecc_err_reporting(struct ecc_settings *s, u8 nid, bool on)
+static int toggle_ecc_err_reporting(struct ecc_settings *s, u16 nid, bool on)
 {
        cpumask_var_t cmask;
        int cpu;
@@ -2262,7 +2162,7 @@ static int toggle_ecc_err_reporting(struct ecc_settings *s, u8 nid, bool on)
        return 0;
 }
 
-static bool enable_ecc_error_reporting(struct ecc_settings *s, u8 nid,
+static bool enable_ecc_error_reporting(struct ecc_settings *s, u16 nid,
                                       struct pci_dev *F3)
 {
        bool ret = true;
@@ -2314,7 +2214,7 @@ static bool enable_ecc_error_reporting(struct ecc_settings *s, u8 nid,
        return ret;
 }
 
-static void restore_ecc_error_reporting(struct ecc_settings *s, u8 nid,
+static void restore_ecc_error_reporting(struct ecc_settings *s, u16 nid,
                                        struct pci_dev *F3)
 {
        u32 value, mask = 0x3;          /* UECC/CECC enable */
@@ -2353,7 +2253,7 @@ static const char *ecc_msg =
        "'ecc_enable_override'.\n"
        " (Note that use of the override may cause unknown side effects.)\n";
 
-static bool ecc_enabled(struct pci_dev *F3, u8 nid)
+static bool ecc_enabled(struct pci_dev *F3, u16 nid)
 {
        u32 value;
        u8 ecc_en = 0;
@@ -2474,7 +2374,7 @@ static int amd64_init_one_instance(struct pci_dev *F2)
        struct mem_ctl_info *mci = NULL;
        struct edac_mc_layer layers[2];
        int err = 0, ret;
-       u8 nid = get_node_id(F2);
+       u16 nid = amd_get_node_id(F2);
 
        ret = -ENOMEM;
        pvt = kzalloc(sizeof(struct amd64_pvt), GFP_KERNEL);
@@ -2566,7 +2466,7 @@ err_ret:
 static int amd64_probe_one_instance(struct pci_dev *pdev,
                                    const struct pci_device_id *mc_type)
 {
-       u8 nid = get_node_id(pdev);
+       u16 nid = amd_get_node_id(pdev);
        struct pci_dev *F3 = node_to_amd_nb(nid)->misc;
        struct ecc_settings *s;
        int ret = 0;
@@ -2616,7 +2516,7 @@ static void amd64_remove_one_instance(struct pci_dev *pdev)
 {
        struct mem_ctl_info *mci;
        struct amd64_pvt *pvt;
-       u8 nid = get_node_id(pdev);
+       u16 nid = amd_get_node_id(pdev);
        struct pci_dev *F3 = node_to_amd_nb(nid)->misc;
        struct ecc_settings *s = ecc_stngs[nid];