From b6a280bb96e0981a527d26cfb0fad203cb9bd808 Mon Sep 17 00:00:00 2001 From: Borislav Petkov Date: Thu, 13 Jan 2011 19:03:28 +0100 Subject: EDAC: Shut up sysfs registration debug code Raise the debug level of these routines so that their output get issued out only when the highest debug level is selected. Otherwise, don't pollute driver debug output. Signed-off-by: Borislav Petkov --- drivers/edac/edac_mc_sysfs.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) (limited to 'drivers/edac') diff --git a/drivers/edac/edac_mc_sysfs.c b/drivers/edac/edac_mc_sysfs.c index 39d97cfdf58c..73196f7b7229 100644 --- a/drivers/edac/edac_mc_sysfs.c +++ b/drivers/edac/edac_mc_sysfs.c @@ -785,10 +785,10 @@ static int edac_create_mci_instance_attributes(struct mem_ctl_info *mci, { int err; - debugf1("%s()\n", __func__); + debugf4("%s()\n", __func__); while (sysfs_attrib) { - debugf1("%s() sysfs_attrib = %p\n",__func__, sysfs_attrib); + debugf4("%s() sysfs_attrib = %p\n",__func__, sysfs_attrib); if (sysfs_attrib->grp) { struct mcidev_sysfs_group_kobj *grp_kobj; @@ -818,7 +818,7 @@ static int edac_create_mci_instance_attributes(struct mem_ctl_info *mci, if (err < 0) return err; } else if (sysfs_attrib->attr.name) { - debugf0("%s() file %s\n", __func__, + debugf4("%s() file %s\n", __func__, sysfs_attrib->attr.name); err = sysfs_create_file(kobj, &sysfs_attrib->attr); @@ -853,26 +853,26 @@ static void edac_remove_mci_instance_attributes(struct mem_ctl_info *mci, * Remove first all the atributes */ while (sysfs_attrib) { - debugf1("%s() sysfs_attrib = %p\n",__func__, sysfs_attrib); + debugf4("%s() sysfs_attrib = %p\n",__func__, sysfs_attrib); if (sysfs_attrib->grp) { - debugf1("%s() seeking for group %s\n", + debugf4("%s() seeking for group %s\n", __func__, sysfs_attrib->grp->name); list_for_each_entry(grp_kobj, &mci->grp_kobj_list, list) { - debugf1("%s() grp_kobj->grp = %p\n",__func__, grp_kobj->grp); + debugf4("%s() grp_kobj->grp = %p\n",__func__, grp_kobj->grp); if (grp_kobj->grp == sysfs_attrib->grp) { edac_remove_mci_instance_attributes(mci, grp_kobj->grp->mcidev_attr, &grp_kobj->kobj, count + 1); - debugf0("%s() group %s\n", __func__, + debugf4("%s() group %s\n", __func__, sysfs_attrib->grp->name); kobject_put(&grp_kobj->kobj); } } - debugf1("%s() end of seeking for group %s\n", + debugf4("%s() end of seeking for group %s\n", __func__, sysfs_attrib->grp->name); } else if (sysfs_attrib->attr.name) { - debugf0("%s() file %s\n", __func__, + debugf4("%s() file %s\n", __func__, sysfs_attrib->attr.name); sysfs_remove_file(kobj, &sysfs_attrib->attr); } else @@ -979,7 +979,7 @@ void edac_remove_sysfs_mci_device(struct mem_ctl_info *mci) debugf0("%s()\n", __func__); /* remove all csrow kobjects */ - debugf0("%s() unregister this mci kobj\n", __func__); + debugf4("%s() unregister this mci kobj\n", __func__); for (i = 0; i < mci->nr_csrows; i++) { if (mci->csrows[i].nr_pages > 0) { debugf0("%s() unreg csrow-%d\n", __func__, i); @@ -989,18 +989,18 @@ void edac_remove_sysfs_mci_device(struct mem_ctl_info *mci) /* remove this mci instance's attribtes */ if (mci->mc_driver_sysfs_attributes) { - debugf0("%s() unregister mci private attributes\n", __func__); + debugf4("%s() unregister mci private attributes\n", __func__); edac_remove_mci_instance_attributes(mci, mci->mc_driver_sysfs_attributes, &mci->edac_mci_kobj, 0); } /* remove the symlink */ - debugf0("%s() remove_link\n", __func__); + debugf4("%s() remove_link\n", __func__); sysfs_remove_link(&mci->edac_mci_kobj, EDAC_DEVICE_SYMLINK); /* unregister this instance's kobject */ - debugf0("%s() remove_mci_instance\n", __func__); + debugf4("%s() remove_mci_instance\n", __func__); kobject_put(&mci->edac_mci_kobj); } -- cgit v1.2.3 From b2b0c605436e343a9a24f00e7fc8fb89a8316e20 Mon Sep 17 00:00:00 2001 From: Borislav Petkov Date: Fri, 8 Oct 2010 18:32:29 +0200 Subject: amd64_edac: Add support for F15h DCT PCI config accesses F15h "multiplexes" between the configuration space of the two DRAM controllers by toggling D18F1x10C[DctCfgSel] while F10h has a different set of registers for DCT0, and DCT1 in extended PCI config space. Add DCT configuration space accessors per family thus wrapping all the different access prerequisites. Clean up code while at it, shorten names. Signed-off-by: Borislav Petkov --- drivers/edac/amd64_edac.c | 164 ++++++++++++++++++++++++++++++------------ drivers/edac/amd64_edac.h | 49 ++++++------- drivers/edac/amd64_edac_inj.c | 8 +-- 3 files changed, 146 insertions(+), 75 deletions(-) (limited to 'drivers/edac') diff --git a/drivers/edac/amd64_edac.c b/drivers/edac/amd64_edac.c index 23e03554f0d3..ae5adac3733f 100644 --- a/drivers/edac/amd64_edac.c +++ b/drivers/edac/amd64_edac.c @@ -107,6 +107,79 @@ struct scrubrate { { 0x00, 0UL}, /* scrubbing off */ }; +static int __amd64_read_pci_cfg_dword(struct pci_dev *pdev, int offset, + u32 *val, const char *func) +{ + int err = 0; + + err = pci_read_config_dword(pdev, offset, val); + if (err) + amd64_warn("%s: error reading F%dx%03x.\n", + func, PCI_FUNC(pdev->devfn), offset); + + return err; +} + +int __amd64_write_pci_cfg_dword(struct pci_dev *pdev, int offset, + u32 val, const char *func) +{ + int err = 0; + + err = pci_write_config_dword(pdev, offset, val); + if (err) + amd64_warn("%s: error writing to F%dx%03x.\n", + func, PCI_FUNC(pdev->devfn), offset); + + return err; +} + +/* + * + * Depending on the family, F2 DCT reads need special handling: + * + * K8: has a single DCT only + * + * F10h: each DCT has its own set of regs + * DCT0 -> F2x040.. + * DCT1 -> F2x140.. + * + * F15h: we select which DCT we access using F1x10C[DctCfgSel] + * + */ +static int k8_read_dct_pci_cfg(struct amd64_pvt *pvt, int addr, u32 *val, + const char *func) +{ + if (addr >= 0x100) + return -EINVAL; + + return __amd64_read_pci_cfg_dword(pvt->F2, addr, val, func); +} + +static int f10_read_dct_pci_cfg(struct amd64_pvt *pvt, int addr, u32 *val, + const char *func) +{ + return __amd64_read_pci_cfg_dword(pvt->F2, addr, val, func); +} + +static int f15_read_dct_pci_cfg(struct amd64_pvt *pvt, int addr, u32 *val, + const char *func) +{ + u32 reg = 0; + u8 dct = 0; + + if (addr >= 0x140 && addr <= 0x1a0) { + dct = 1; + addr -= 0x100; + } + + amd64_read_pci_cfg(pvt->F1, DCT_CFG_SEL, ®); + reg &= 0xfffffffe; + reg |= dct; + amd64_write_pci_cfg(pvt->F1, DCT_CFG_SEL, reg); + + return __amd64_read_pci_cfg_dword(pvt->F2, addr, val, func); +} + /* * Memory scrubber control interface. For K8, memory scrubbing is handled by * hardware and can involve L2 cache, dcache as well as the main memory. With @@ -824,7 +897,7 @@ static void amd64_dump_dramcfg_low(u32 dclr, int chan) } /* Display and decode various NB registers for debug purposes. */ -static void amd64_dump_misc_regs(struct amd64_pvt *pvt) +static void dump_misc_regs(struct amd64_pvt *pvt) { debugf1("F3xE8 (NB Cap): 0x%08x\n", pvt->nbcap); @@ -864,13 +937,10 @@ static void amd64_dump_misc_regs(struct amd64_pvt *pvt) amd64_dump_dramcfg_low(pvt->dclr1, 1); } -/* Read in both of DBAM registers */ static void amd64_read_dbam_reg(struct amd64_pvt *pvt) { - amd64_read_pci_cfg(pvt->F2, DBAM0, &pvt->dbam0); - - if (boot_cpu_data.x86 >= 0x10) - amd64_read_pci_cfg(pvt->F2, DBAM1, &pvt->dbam1); + amd64_read_dct_pci_cfg(pvt, DBAM0, &pvt->dbam0); + amd64_read_dct_pci_cfg(pvt, DBAM1, &pvt->dbam1); } /* @@ -925,7 +995,7 @@ static void amd64_set_dct_base_and_mask(struct amd64_pvt *pvt) /* * Function 2 Offset F10_DCSB0; read in the DCS Base and DCS Mask hw registers */ -static void amd64_read_dct_base_mask(struct amd64_pvt *pvt) +static void read_dct_base_mask(struct amd64_pvt *pvt) { int cs, reg; @@ -933,37 +1003,33 @@ static void amd64_read_dct_base_mask(struct amd64_pvt *pvt) for (cs = 0; cs < pvt->cs_count; cs++) { reg = K8_DCSB0 + (cs * 4); - if (!amd64_read_pci_cfg(pvt->F2, reg, &pvt->dcsb0[cs])) + + if (!amd64_read_dct_pci_cfg(pvt, reg, &pvt->dcsb0[cs])) debugf0(" DCSB0[%d]=0x%08x reg: F2x%x\n", cs, pvt->dcsb0[cs], reg); - /* If DCT are NOT ganged, then read in DCT1's base */ - if (boot_cpu_data.x86 >= 0x10 && !dct_ganging_enabled(pvt)) { + if (!dct_ganging_enabled(pvt)) { reg = F10_DCSB1 + (cs * 4); - if (!amd64_read_pci_cfg(pvt->F2, reg, - &pvt->dcsb1[cs])) + + if (!amd64_read_dct_pci_cfg(pvt, reg, &pvt->dcsb1[cs])) debugf0(" DCSB1[%d]=0x%08x reg: F2x%x\n", cs, pvt->dcsb1[cs], reg); - } else { - pvt->dcsb1[cs] = 0; } } for (cs = 0; cs < pvt->num_dcsm; cs++) { reg = K8_DCSM0 + (cs * 4); - if (!amd64_read_pci_cfg(pvt->F2, reg, &pvt->dcsm0[cs])) + + if (!amd64_read_dct_pci_cfg(pvt, reg, &pvt->dcsm0[cs])) debugf0(" DCSM0[%d]=0x%08x reg: F2x%x\n", cs, pvt->dcsm0[cs], reg); - /* If DCT are NOT ganged, then read in DCT1's mask */ - if (boot_cpu_data.x86 >= 0x10 && !dct_ganging_enabled(pvt)) { + if (!dct_ganging_enabled(pvt)) { reg = F10_DCSM1 + (cs * 4); - if (!amd64_read_pci_cfg(pvt->F2, reg, - &pvt->dcsm1[cs])) + + if (!amd64_read_dct_pci_cfg(pvt, reg, &pvt->dcsm1[cs])) debugf0(" DCSM1[%d]=0x%08x reg: F2x%x\n", cs, pvt->dcsm1[cs], reg); - } else { - pvt->dcsm1[cs] = 0; } } } @@ -999,7 +1065,7 @@ static int k8_early_channel_count(struct amd64_pvt *pvt) { int flag, err = 0; - err = amd64_read_pci_cfg(pvt->F2, F10_DCLR_0, &pvt->dclr0); + err = amd64_read_dct_pci_cfg(pvt, F10_DCLR_0, &pvt->dclr0); if (err) return err; @@ -1163,7 +1229,7 @@ static int f10_early_channel_count(struct amd64_pvt *pvt) * both controllers since DIMMs can be placed in either one. */ for (i = 0; i < ARRAY_SIZE(dbams); i++) { - if (amd64_read_pci_cfg(pvt->F2, dbams[i], &dbam)) + if (amd64_read_dct_pci_cfg(pvt, dbams[i], &dbam)) goto err_reg; for (j = 0; j < 4; j++) { @@ -1255,12 +1321,9 @@ static void f10_read_dram_base_limit(struct amd64_pvt *pvt, int dram) static void f10_read_dram_ctl_register(struct amd64_pvt *pvt) { - if (!amd64_read_pci_cfg(pvt->F2, F10_DCTL_SEL_LOW, - &pvt->dram_ctl_select_low)) { - debugf0("F2x110 (DCTL Sel. Low): 0x%08x, " - "High range addresses at: 0x%x\n", - pvt->dram_ctl_select_low, - dct_sel_baseaddr(pvt)); + if (!amd64_read_dct_pci_cfg(pvt, F10_DCTL_SEL_LOW, &pvt->dct_sel_low)) { + debugf0("F2x110 (DCTL Sel. Low): 0x%08x, High range addrs at: 0x%x\n", + pvt->dct_sel_low, dct_sel_baseaddr(pvt)); debugf0(" DCT mode: %s, All DCTs on: %s\n", (dct_ganging_enabled(pvt) ? "ganged" : "unganged"), @@ -1281,8 +1344,7 @@ static void f10_read_dram_ctl_register(struct amd64_pvt *pvt) dct_sel_interleave_addr(pvt)); } - amd64_read_pci_cfg(pvt->F2, F10_DCTL_SEL_HIGH, - &pvt->dram_ctl_select_high); + amd64_read_dct_pci_cfg(pvt, F10_DCTL_SEL_HIGH, &pvt->dct_sel_hi); } /* @@ -1292,7 +1354,7 @@ static void f10_read_dram_ctl_register(struct amd64_pvt *pvt) static u32 f10_determine_channel(struct amd64_pvt *pvt, u64 sys_addr, int hi_range_sel, u32 intlv_en) { - u32 cs, temp, dct_sel_high = (pvt->dram_ctl_select_low >> 1) & 1; + u32 cs, temp, dct_sel_high = (pvt->dct_sel_low >> 1) & 1; if (dct_ganging_enabled(pvt)) cs = 0; @@ -1481,7 +1543,7 @@ static int f10_match_to_this_node(struct amd64_pvt *pvt, int dram_range, */ hole_off = (pvt->dhar & 0x0000FF80); hole_valid = (pvt->dhar & 0x1); - dct_sel_base_off = (pvt->dram_ctl_select_high & 0xFFFFFC00) << 16; + dct_sel_base_off = (pvt->dct_sel_hi & 0xFFFFFC00) << 16; debugf1(" HoleOffset=0x%x HoleValid=0x%x IntlvSel=0x%x\n", hole_off, hole_valid, intlv_sel); @@ -1668,6 +1730,7 @@ static struct amd64_family_type amd64_family_types[] = { .read_dram_base_limit = k8_read_dram_base_limit, .map_sysaddr_to_csrow = k8_map_sysaddr_to_csrow, .dbam_to_cs = k8_dbam_to_chip_select, + .read_dct_pci_cfg = k8_read_dct_pci_cfg, } }, [F10_CPUS] = { @@ -1681,6 +1744,13 @@ static struct amd64_family_type amd64_family_types[] = { .read_dram_ctl_register = f10_read_dram_ctl_register, .map_sysaddr_to_csrow = f10_map_sysaddr_to_csrow, .dbam_to_cs = f10_dbam_to_chip_select, + .read_dct_pci_cfg = f10_read_dct_pci_cfg, + } + }, + [F15_CPUS] = { + .ctl_name = "F15h", + .ops = { + .read_dct_pci_cfg = f15_read_dct_pci_cfg, } }, }; @@ -2081,24 +2151,24 @@ static void read_mc_regs(struct amd64_pvt *pvt) } } - amd64_read_dct_base_mask(pvt); + read_dct_base_mask(pvt); amd64_read_pci_cfg(pvt->F1, K8_DHAR, &pvt->dhar); amd64_read_dbam_reg(pvt); amd64_read_pci_cfg(pvt->F3, F10_ONLINE_SPARE, &pvt->online_spare); - amd64_read_pci_cfg(pvt->F2, F10_DCLR_0, &pvt->dclr0); - amd64_read_pci_cfg(pvt->F2, F10_DCHR_0, &pvt->dchr0); + amd64_read_dct_pci_cfg(pvt, F10_DCLR_0, &pvt->dclr0); + amd64_read_dct_pci_cfg(pvt, F10_DCHR_0, &pvt->dchr0); - if (boot_cpu_data.x86 >= 0x10) { - if (!dct_ganging_enabled(pvt)) { - amd64_read_pci_cfg(pvt->F2, F10_DCLR_1, &pvt->dclr1); - amd64_read_pci_cfg(pvt->F2, F10_DCHR_1, &pvt->dchr1); - } - amd64_read_pci_cfg(pvt->F3, EXT_NB_MCA_CFG, &tmp); + if (!dct_ganging_enabled(pvt)) { + amd64_read_dct_pci_cfg(pvt, F10_DCLR_1, &pvt->dclr1); + amd64_read_dct_pci_cfg(pvt, F10_DCHR_1, &pvt->dchr1); } + if (boot_cpu_data.x86 >= 0x10) + amd64_read_pci_cfg(pvt->F3, EXT_NB_MCA_CFG, &tmp); + if (boot_cpu_data.x86 == 0x10 && boot_cpu_data.x86_model > 7 && /* F3x180[EccSymbolSize]=1 => x8 symbols */ @@ -2107,7 +2177,7 @@ static void read_mc_regs(struct amd64_pvt *pvt) else pvt->syn_type = 4; - amd64_dump_misc_regs(pvt); + dump_misc_regs(pvt); } /* @@ -2342,7 +2412,7 @@ static bool enable_ecc_error_reporting(struct ecc_settings *s, u8 nid, s->nbctl_valid = true; value |= mask; - pci_write_config_dword(F3, K8_NBCTL, value); + amd64_write_pci_cfg(F3, K8_NBCTL, value); amd64_read_pci_cfg(F3, K8_NBCFG, &value); @@ -2357,7 +2427,7 @@ static bool enable_ecc_error_reporting(struct ecc_settings *s, u8 nid, /* Attempt to turn on DRAM ECC Enable */ value |= K8_NBCFG_ECC_ENABLE; - pci_write_config_dword(F3, K8_NBCFG, value); + amd64_write_pci_cfg(F3, K8_NBCFG, value); amd64_read_pci_cfg(F3, K8_NBCFG, &value); @@ -2391,13 +2461,13 @@ static void restore_ecc_error_reporting(struct ecc_settings *s, u8 nid, value &= ~mask; value |= s->old_nbctl; - pci_write_config_dword(F3, K8_NBCTL, value); + amd64_write_pci_cfg(F3, K8_NBCTL, value); /* restore previous BIOS DRAM ECC "off" setting we force-enabled */ if (!s->flags.nb_ecc_prev) { amd64_read_pci_cfg(F3, K8_NBCFG, &value); value &= ~K8_NBCFG_ECC_ENABLE; - pci_write_config_dword(F3, K8_NBCFG, value); + amd64_write_pci_cfg(F3, K8_NBCFG, value); } /* restore the NB Enable MCGCTL bit */ diff --git a/drivers/edac/amd64_edac.h b/drivers/edac/amd64_edac.h index 613ec72b0f65..91c266b9f6cf 100644 --- a/drivers/edac/amd64_edac.h +++ b/drivers/edac/amd64_edac.h @@ -184,6 +184,7 @@ /* NOTE: Extra mask bit vs K8 */ #define f10_dhar_offset(dhar) ((dhar & F10_DHAR_OFFSET_MASK) << 16) +#define DCT_CFG_SEL 0x10C /* F10 High BASE/LIMIT registers */ #define F10_DRAM_BASE_HIGH 0x140 @@ -257,14 +258,14 @@ #define F10_DCTL_SEL_LOW 0x110 -#define dct_sel_baseaddr(pvt) ((pvt->dram_ctl_select_low) & 0xFFFFF800) -#define dct_sel_interleave_addr(pvt) (((pvt->dram_ctl_select_low) >> 6) & 0x3) -#define dct_high_range_enabled(pvt) (pvt->dram_ctl_select_low & BIT(0)) -#define dct_interleave_enabled(pvt) (pvt->dram_ctl_select_low & BIT(2)) -#define dct_ganging_enabled(pvt) (pvt->dram_ctl_select_low & BIT(4)) -#define dct_data_intlv_enabled(pvt) (pvt->dram_ctl_select_low & BIT(5)) -#define dct_dram_enabled(pvt) (pvt->dram_ctl_select_low & BIT(8)) -#define dct_memory_cleared(pvt) (pvt->dram_ctl_select_low & BIT(10)) +#define dct_sel_baseaddr(pvt) ((pvt->dct_sel_low) & 0xFFFFF800) +#define dct_sel_interleave_addr(pvt) (((pvt->dct_sel_low) >> 6) & 0x3) +#define dct_high_range_enabled(pvt) (pvt->dct_sel_low & BIT(0)) +#define dct_interleave_enabled(pvt) (pvt->dct_sel_low & BIT(2)) +#define dct_ganging_enabled(pvt) (pvt->dct_sel_low & BIT(4)) +#define dct_data_intlv_enabled(pvt) (pvt->dct_sel_low & BIT(5)) +#define dct_dram_enabled(pvt) (pvt->dct_sel_low & BIT(8)) +#define dct_memory_cleared(pvt) (pvt->dct_sel_low & BIT(10)) #define F10_DCTL_SEL_HIGH 0x114 @@ -380,9 +381,11 @@ static inline int get_node_id(struct pci_dev *pdev) return PCI_SLOT(pdev->devfn) - 0x18; } -enum amd64_chipset_families { +enum amd_families { K8_CPUS = 0, F10_CPUS, + F15_CPUS, + NUM_FAMILIES, }; /* Error injection control structure */ @@ -448,9 +451,9 @@ struct amd64_pvt { u64 top_mem; /* top of memory below 4GB */ u64 top_mem2; /* top of memory above 4GB */ - u32 dram_ctl_select_low; /* DRAM Controller Select Low Reg */ - u32 dram_ctl_select_high; /* DRAM Controller Select High Reg */ - u32 online_spare; /* On-Line spare Reg */ + u32 dct_sel_low; /* DRAM Controller Select Low Reg */ + u32 dct_sel_hi; /* DRAM Controller Select High Reg */ + u32 online_spare; /* On-Line spare Reg */ /* x4 or x8 syndromes in use */ u8 syn_type; @@ -519,6 +522,8 @@ struct low_ops { void (*map_sysaddr_to_csrow) (struct mem_ctl_info *mci, struct err_regs *info, u64 SystemAddr); int (*dbam_to_cs) (struct amd64_pvt *pvt, int cs_mode); + int (*read_dct_pci_cfg) (struct amd64_pvt *pvt, int offset, + u32 *val, const char *func); }; struct amd64_family_type { @@ -527,21 +532,17 @@ struct amd64_family_type { struct low_ops ops; }; -static inline int amd64_read_pci_cfg_dword(struct pci_dev *pdev, int offset, - u32 *val, const char *func) -{ - int err = 0; +int __amd64_write_pci_cfg_dword(struct pci_dev *pdev, int offset, + u32 val, const char *func); - err = pci_read_config_dword(pdev, offset, val); - if (err) - amd64_warn("%s: error reading F%dx%x.\n", - func, PCI_FUNC(pdev->devfn), offset); +#define amd64_read_pci_cfg(pdev, offset, val) \ + __amd64_read_pci_cfg_dword(pdev, offset, val, __func__) - return err; -} +#define amd64_write_pci_cfg(pdev, offset, val) \ + __amd64_write_pci_cfg_dword(pdev, offset, val, __func__) -#define amd64_read_pci_cfg(pdev, offset, val) \ - amd64_read_pci_cfg_dword(pdev, offset, val, __func__) +#define amd64_read_dct_pci_cfg(pvt, offset, val) \ + pvt->ops->read_dct_pci_cfg(pvt, offset, val, __func__) /* * For future CPU versions, verify the following as new 'slow' rates appear and diff --git a/drivers/edac/amd64_edac_inj.c b/drivers/edac/amd64_edac_inj.c index 688478de1cbd..303f10e03dda 100644 --- a/drivers/edac/amd64_edac_inj.c +++ b/drivers/edac/amd64_edac_inj.c @@ -117,13 +117,13 @@ static ssize_t amd64_inject_read_store(struct mem_ctl_info *mci, /* Form value to choose 16-byte section of cacheline */ section = F10_NB_ARRAY_DRAM_ECC | SET_NB_ARRAY_ADDRESS(pvt->injection.section); - pci_write_config_dword(pvt->F3, F10_NB_ARRAY_ADDR, section); + amd64_write_pci_cfg(pvt->F3, F10_NB_ARRAY_ADDR, section); word_bits = SET_NB_DRAM_INJECTION_READ(pvt->injection.word, pvt->injection.bit_map); /* Issue 'word' and 'bit' along with the READ request */ - pci_write_config_dword(pvt->F3, F10_NB_ARRAY_DATA, word_bits); + amd64_write_pci_cfg(pvt->F3, F10_NB_ARRAY_DATA, word_bits); debugf0("section=0x%x word_bits=0x%x\n", section, word_bits); @@ -150,13 +150,13 @@ static ssize_t amd64_inject_write_store(struct mem_ctl_info *mci, /* Form value to choose 16-byte section of cacheline */ section = F10_NB_ARRAY_DRAM_ECC | SET_NB_ARRAY_ADDRESS(pvt->injection.section); - pci_write_config_dword(pvt->F3, F10_NB_ARRAY_ADDR, section); + amd64_write_pci_cfg(pvt->F3, F10_NB_ARRAY_ADDR, section); word_bits = SET_NB_DRAM_INJECTION_WRITE(pvt->injection.word, pvt->injection.bit_map); /* Issue 'word' and 'bit' along with the READ request */ - pci_write_config_dword(pvt->F3, F10_NB_ARRAY_DATA, word_bits); + amd64_write_pci_cfg(pvt->F3, F10_NB_ARRAY_DATA, word_bits); debugf0("section=0x%x word_bits=0x%x\n", section, word_bits); -- cgit v1.2.3 From 7f19bf755ced6fa16dbf118c0eff60586760496b Mon Sep 17 00:00:00 2001 From: Borislav Petkov Date: Thu, 21 Oct 2010 18:52:53 +0200 Subject: amd64_edac: Remove DRAM base/limit subfields caching Add a struct representing the DRAM base/limit range pairs and remove all cached subfields. Replace them with accessor functions, which actually saves us some space: text data bss dec hex filename 14712 1577 336 16625 40f1 drivers/edac/amd64_edac_mod.o.after 14831 1609 336 16776 4188 drivers/edac/amd64_edac_mod.o.before Also, it simplifies the code a lot allowing to merge the K8 and F10h routines. No functional change. Signed-off-by: Borislav Petkov --- drivers/edac/amd64_edac.c | 230 +++++++++++++--------------------------------- drivers/edac/amd64_edac.h | 73 ++++++++++----- 2 files changed, 115 insertions(+), 188 deletions(-) (limited to 'drivers/edac') diff --git a/drivers/edac/amd64_edac.c b/drivers/edac/amd64_edac.c index ae5adac3733f..683fd3c716a0 100644 --- a/drivers/edac/amd64_edac.c +++ b/drivers/edac/amd64_edac.c @@ -296,32 +296,13 @@ static u32 amd64_get_dct_mask(struct amd64_pvt *pvt, int dct, int csrow) return pvt->dcsm1[amd64_map_to_dcs_mask(pvt, csrow)]; } - /* - * In *base and *limit, pass back the full 40-bit base and limit physical - * addresses for the node given by node_id. This information is obtained from - * DRAM Base (section 3.4.4.1) and DRAM Limit (section 3.4.4.2) registers. The - * base and limit addresses are of type SysAddr, as defined at the start of - * section 3.4.4 (p. 70). They are the lowest and highest physical addresses - * in the address range they represent. + * returns true if the SysAddr given by sys_addr matches the + * DRAM base/limit associated with node_id */ -static void amd64_get_base_and_limit(struct amd64_pvt *pvt, int node_id, - u64 *base, u64 *limit) +static bool amd64_base_limit_match(struct amd64_pvt *pvt, u64 sys_addr, int nid) { - *base = pvt->dram_base[node_id]; - *limit = pvt->dram_limit[node_id]; -} - -/* - * Return 1 if the SysAddr given by sys_addr matches the base/limit associated - * with node_id - */ -static int amd64_base_limit_match(struct amd64_pvt *pvt, - u64 sys_addr, int node_id) -{ - u64 base, limit, addr; - - amd64_get_base_and_limit(pvt, node_id, &base, &limit); + u64 addr; /* The K8 treats this as a 40-bit value. However, bits 63-40 will be * all ones if the most significant implemented address bit is 1. @@ -331,7 +312,8 @@ static int amd64_base_limit_match(struct amd64_pvt *pvt, */ addr = sys_addr & 0x000000ffffffffffull; - return (addr >= base) && (addr <= limit); + return ((addr >= get_dram_base(pvt, nid)) && + (addr <= get_dram_limit(pvt, nid))); } /* @@ -358,10 +340,10 @@ static struct mem_ctl_info *find_mc_by_sys_addr(struct mem_ctl_info *mci, * registers. Therefore we arbitrarily choose to read it from the * register for node 0. */ - intlv_en = pvt->dram_IntlvEn[0]; + intlv_en = dram_intlv_en(pvt, 0); if (intlv_en == 0) { - for (node_id = 0; node_id < DRAM_REG_COUNT; node_id++) { + for (node_id = 0; node_id < DRAM_RANGES; node_id++) { if (amd64_base_limit_match(pvt, sys_addr, node_id)) goto found; } @@ -378,10 +360,10 @@ static struct mem_ctl_info *find_mc_by_sys_addr(struct mem_ctl_info *mci, bits = (((u32) sys_addr) >> 12) & intlv_en; for (node_id = 0; ; ) { - if ((pvt->dram_IntlvSel[node_id] & intlv_en) == bits) + if ((dram_intlv_sel(pvt, node_id) & intlv_en) == bits) break; /* intlv_sel field matches */ - if (++node_id >= DRAM_REG_COUNT) + if (++node_id >= DRAM_RANGES) goto err_no_match; } @@ -476,19 +458,6 @@ static int input_addr_to_csrow(struct mem_ctl_info *mci, u64 input_addr) return -1; } -/* - * Return the base value defined by the DRAM Base register for the node - * represented by mci. This function returns the full 40-bit value despite the - * fact that the register only stores bits 39-24 of the value. See section - * 3.4.4.1 (BKDG #26094, K8, revA-E) - */ -static inline u64 get_dram_base(struct mem_ctl_info *mci) -{ - struct amd64_pvt *pvt = mci->pvt_info; - - return pvt->dram_base[pvt->mc_node_id]; -} - /* * Obtain info from the DRAM Hole Address Register (section 3.4.8, pub #26094) * for the node represented by mci. Info is passed back in *hole_base, @@ -598,10 +567,11 @@ EXPORT_SYMBOL_GPL(amd64_get_dram_hole_info); */ static u64 sys_addr_to_dram_addr(struct mem_ctl_info *mci, u64 sys_addr) { + struct amd64_pvt *pvt = mci->pvt_info; u64 dram_base, hole_base, hole_offset, hole_size, dram_addr; int ret = 0; - dram_base = get_dram_base(mci); + dram_base = get_dram_base(pvt, pvt->mc_node_id); ret = amd64_get_dram_hole_info(mci, &hole_base, &hole_offset, &hole_size); @@ -665,7 +635,7 @@ static u64 dram_addr_to_input_addr(struct mem_ctl_info *mci, u64 dram_addr) * See the start of section 3.4.4 (p. 70, BKDG #26094, K8, revA-E) * concerning translating a DramAddr to an InputAddr. */ - intlv_shift = num_node_interleave_bits(pvt->dram_IntlvEn[0]); + intlv_shift = num_node_interleave_bits(dram_intlv_en(pvt, 0)); input_addr = ((dram_addr >> intlv_shift) & 0xffffff000ull) + (dram_addr & 0xfff); @@ -717,7 +687,7 @@ static u64 input_addr_to_dram_addr(struct mem_ctl_info *mci, u64 input_addr) node_id = pvt->mc_node_id; BUG_ON((node_id < 0) || (node_id > 7)); - intlv_shift = num_node_interleave_bits(pvt->dram_IntlvEn[0]); + intlv_shift = num_node_interleave_bits(dram_intlv_en(pvt, 0)); if (intlv_shift == 0) { debugf1(" InputAddr 0x%lx translates to DramAddr of " @@ -729,7 +699,7 @@ static u64 input_addr_to_dram_addr(struct mem_ctl_info *mci, u64 input_addr) bits = ((input_addr & 0xffffff000ull) << intlv_shift) + (input_addr & 0xfff); - intlv_sel = pvt->dram_IntlvSel[node_id] & ((1 << intlv_shift) - 1); + intlv_sel = dram_intlv_sel(pvt, node_id) & ((1 << intlv_shift) - 1); dram_addr = bits + (intlv_sel << 12); debugf1("InputAddr 0x%lx translates to DramAddr 0x%lx " @@ -746,7 +716,7 @@ static u64 input_addr_to_dram_addr(struct mem_ctl_info *mci, u64 input_addr) 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, limit, sys_addr; + u64 hole_base, hole_offset, hole_size, base, sys_addr; int ret = 0; ret = amd64_get_dram_hole_info(mci, &hole_base, &hole_offset, @@ -764,7 +734,7 @@ static u64 dram_addr_to_sys_addr(struct mem_ctl_info *mci, u64 dram_addr) } } - amd64_get_base_and_limit(pvt, pvt->mc_node_id, &base, &limit); + base = get_dram_base(pvt, pvt->mc_node_id); sys_addr = dram_addr + base; /* @@ -1090,33 +1060,21 @@ static u64 k8_get_error_address(struct mem_ctl_info *mci, (info->nbeal & ~0x03); } -/* - * Read the Base and Limit registers for K8 based Memory controllers; extract - * fields from the 'raw' reg into separate data fields - * - * Isolates: BASE, LIMIT, IntlvEn, IntlvSel, RW_EN - */ -static void k8_read_dram_base_limit(struct amd64_pvt *pvt, int dram) +static void read_dram_base_limit_regs(struct amd64_pvt *pvt, unsigned range) { - u32 low; - u32 off = dram << 3; /* 8 bytes between DRAM entries */ + u32 off = range << 3; - amd64_read_pci_cfg(pvt->F1, K8_DRAM_BASE_LOW + off, &low); + 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); - /* Extract parts into separate data entries */ - pvt->dram_base[dram] = ((u64) low & 0xFFFF0000) << 8; - pvt->dram_IntlvEn[dram] = (low >> 8) & 0x7; - pvt->dram_rw_en[dram] = (low & 0x3); + if (boot_cpu_data.x86 == 0xf) + return; - amd64_read_pci_cfg(pvt->F1, K8_DRAM_LIMIT_LOW + off, &low); + if (!dram_rw(pvt, range)) + return; - /* - * Extract parts into separate data entries. Limit is the HIGHEST memory - * location of the region, so lower 24 bits need to be all ones - */ - pvt->dram_limit[dram] = (((u64) low & 0xFFFF0000) << 8) | 0x00FFFFFF; - pvt->dram_IntlvSel[dram] = (low >> 8) & 0x7; - pvt->dram_DstNode[dram] = (low & 0x7); + 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); } static void k8_map_sysaddr_to_csrow(struct mem_ctl_info *mci, @@ -1271,53 +1229,6 @@ static u64 f10_get_error_address(struct mem_ctl_info *mci, (info->nbeal & ~0x01); } -/* - * Read the Base and Limit registers for F10 based Memory controllers. Extract - * fields from the 'raw' reg into separate data fields. - * - * Isolates: BASE, LIMIT, IntlvEn, IntlvSel, RW_EN. - */ -static void f10_read_dram_base_limit(struct amd64_pvt *pvt, int dram) -{ - u32 high_offset, low_offset, high_base, low_base, high_limit, low_limit; - - low_offset = K8_DRAM_BASE_LOW + (dram << 3); - high_offset = F10_DRAM_BASE_HIGH + (dram << 3); - - /* read the 'raw' DRAM BASE Address register */ - amd64_read_pci_cfg(pvt->F1, low_offset, &low_base); - amd64_read_pci_cfg(pvt->F1, high_offset, &high_base); - - /* Extract parts into separate data entries */ - pvt->dram_rw_en[dram] = (low_base & 0x3); - - if (pvt->dram_rw_en[dram] == 0) - return; - - pvt->dram_IntlvEn[dram] = (low_base >> 8) & 0x7; - - pvt->dram_base[dram] = (((u64)high_base & 0x000000FF) << 40) | - (((u64)low_base & 0xFFFF0000) << 8); - - low_offset = K8_DRAM_LIMIT_LOW + (dram << 3); - high_offset = F10_DRAM_LIMIT_HIGH + (dram << 3); - - /* read the 'raw' LIMIT registers */ - amd64_read_pci_cfg(pvt->F1, low_offset, &low_limit); - amd64_read_pci_cfg(pvt->F1, high_offset, &high_limit); - - pvt->dram_DstNode[dram] = (low_limit & 0x7); - pvt->dram_IntlvSel[dram] = (low_limit >> 8) & 0x7; - - /* - * Extract address values and form a LIMIT address. Limit is the HIGHEST - * memory location of the region, so low 24 bits need to be all ones. - */ - pvt->dram_limit[dram] = (((u64)high_limit & 0x000000FF) << 40) | - (((u64) low_limit & 0xFFFF0000) << 8) | - 0x00FFFFFF; -} - static void f10_read_dram_ctl_register(struct amd64_pvt *pvt) { @@ -1520,22 +1431,21 @@ static int f10_lookup_addr_in_dct(u32 in_addr, u32 nid, u32 cs) } /* For a given @dram_range, check if @sys_addr falls within it. */ -static int f10_match_to_this_node(struct amd64_pvt *pvt, int dram_range, +static int f10_match_to_this_node(struct amd64_pvt *pvt, int range, u64 sys_addr, int *nid, int *chan_sel) { - int node_id, cs_found = -EINVAL, high_range = 0; - u32 intlv_en, intlv_sel, intlv_shift, hole_off; + int cs_found = -EINVAL, high_range = 0; + u32 intlv_shift, hole_off; u32 hole_valid, tmp, dct_sel_base, channel; - u64 dram_base, chan_addr, dct_sel_base_off; - - dram_base = pvt->dram_base[dram_range]; - intlv_en = pvt->dram_IntlvEn[dram_range]; + u64 chan_addr, dct_sel_base_off; - node_id = pvt->dram_DstNode[dram_range]; - intlv_sel = pvt->dram_IntlvSel[dram_range]; + u8 node_id = dram_dst_node(pvt, range); + u32 intlv_en = dram_intlv_en(pvt, range); + u32 intlv_sel = dram_intlv_sel(pvt, range); + u64 dram_base = get_dram_base(pvt, range); - debugf1("(dram=%d) Base=0x%llx SystemAddr= 0x%llx Limit=0x%llx\n", - dram_range, dram_base, sys_addr, pvt->dram_limit[dram_range]); + debugf1("(range %d) Base=0x%llx SystemAddr= 0x%llx Limit=0x%llx\n", + range, dram_base, sys_addr, get_dram_limit(pvt, range)); /* * This assumes that one node's DHAR is the same as all the other @@ -1604,20 +1514,17 @@ static int f10_match_to_this_node(struct amd64_pvt *pvt, int dram_range, static int f10_translate_sysaddr_to_cs(struct amd64_pvt *pvt, u64 sys_addr, int *node, int *chan_sel) { - int dram_range, cs_found = -EINVAL; - u64 dram_base, dram_limit; + int range, cs_found = -EINVAL; - for (dram_range = 0; dram_range < DRAM_REG_COUNT; dram_range++) { + for (range = 0; range < DRAM_RANGES; range++) { - if (!pvt->dram_rw_en[dram_range]) + if (!dram_rw(pvt, range)) continue; - dram_base = pvt->dram_base[dram_range]; - dram_limit = pvt->dram_limit[dram_range]; + if ((get_dram_base(pvt, range) <= sys_addr) && + (get_dram_limit(pvt, range) >= sys_addr)) { - if ((dram_base <= sys_addr) && (sys_addr <= dram_limit)) { - - cs_found = f10_match_to_this_node(pvt, dram_range, + cs_found = f10_match_to_this_node(pvt, range, sys_addr, node, chan_sel); if (cs_found >= 0) @@ -1727,7 +1634,6 @@ static struct amd64_family_type amd64_family_types[] = { .ops = { .early_channel_count = k8_early_channel_count, .get_error_address = k8_get_error_address, - .read_dram_base_limit = k8_read_dram_base_limit, .map_sysaddr_to_csrow = k8_map_sysaddr_to_csrow, .dbam_to_cs = k8_dbam_to_chip_select, .read_dct_pci_cfg = k8_read_dct_pci_cfg, @@ -1740,7 +1646,6 @@ static struct amd64_family_type amd64_family_types[] = { .ops = { .early_channel_count = f10_early_channel_count, .get_error_address = f10_get_error_address, - .read_dram_base_limit = f10_read_dram_base_limit, .read_dram_ctl_register = f10_read_dram_ctl_register, .map_sysaddr_to_csrow = f10_map_sysaddr_to_csrow, .dbam_to_cs = f10_dbam_to_chip_select, @@ -2099,7 +2004,7 @@ static void read_mc_regs(struct amd64_pvt *pvt) { u64 msr_val; u32 tmp; - int dram; + int range; /* * Retrieve TOP_MEM and TOP_MEM2; no masking off of reserved bits since @@ -2121,34 +2026,27 @@ static void read_mc_regs(struct amd64_pvt *pvt) if (pvt->ops->read_dram_ctl_register) pvt->ops->read_dram_ctl_register(pvt); - for (dram = 0; dram < DRAM_REG_COUNT; dram++) { - /* - * Call CPU specific READ function to get the DRAM Base and - * Limit values from the DCT. - */ - pvt->ops->read_dram_base_limit(pvt, dram); + for (range = 0; range < DRAM_RANGES; range++) { + u8 rw; - /* - * Only print out debug info on rows with both R and W Enabled. - * Normal processing, compiler should optimize this whole 'if' - * debug output block away. - */ - if (pvt->dram_rw_en[dram] != 0) { - debugf1(" DRAM-BASE[%d]: 0x%016llx " - "DRAM-LIMIT: 0x%016llx\n", - dram, - pvt->dram_base[dram], - pvt->dram_limit[dram]); - - debugf1(" IntlvEn=%s %s %s " - "IntlvSel=%d DstNode=%d\n", - pvt->dram_IntlvEn[dram] ? - "Enabled" : "Disabled", - (pvt->dram_rw_en[dram] & 0x2) ? "W" : "!W", - (pvt->dram_rw_en[dram] & 0x1) ? "R" : "!R", - pvt->dram_IntlvSel[dram], - pvt->dram_DstNode[dram]); - } + /* read settings for this DRAM range */ + read_dram_base_limit_regs(pvt, range); + + rw = dram_rw(pvt, range); + if (!rw) + continue; + + debugf1(" DRAM range[%d], base: 0x%016llx; limit: 0x%016llx\n", + range, + get_dram_base(pvt, range), + get_dram_limit(pvt, range)); + + debugf1(" IntlvEn=%s; Range access: %s%s IntlvSel=%d DstNode=%d\n", + dram_intlv_en(pvt, range) ? "Enabled" : "Disabled", + (rw & 0x1) ? "R" : "-", + (rw & 0x2) ? "W" : "-", + dram_intlv_sel(pvt, range), + dram_dst_node(pvt, range)); } read_dct_base_mask(pvt); diff --git a/drivers/edac/amd64_edac.h b/drivers/edac/amd64_edac.h index 91c266b9f6cf..93af3575e427 100644 --- a/drivers/edac/amd64_edac.h +++ b/drivers/edac/amd64_edac.h @@ -153,8 +153,8 @@ #define K8_REV_F 4 /* Hardware limit on ChipSelect rows per MC and processors per system */ -#define MAX_CS_COUNT 8 -#define DRAM_REG_COUNT 8 +#define NUM_CHIPSELECTS 8 +#define DRAM_RANGES 8 #define ON true #define OFF false @@ -167,8 +167,14 @@ /* * Function 1 - Address Map */ -#define K8_DRAM_BASE_LOW 0x40 -#define K8_DRAM_LIMIT_LOW 0x44 +#define DRAM_BASE_LO 0x40 +#define DRAM_LIMIT_LO 0x44 + +#define dram_intlv_en(pvt, i) ((pvt->ranges[i].base.lo >> 8) & 0x7) +#define dram_rw(pvt, i) (pvt->ranges[i].base.lo & 0x3) +#define dram_intlv_sel(pvt, i) ((pvt->ranges[i].lim.lo >> 8) & 0x7) +#define dram_dst_node(pvt, i) (pvt->ranges[i].lim.lo & 0x7) + #define K8_DHAR 0xf0 #define DHAR_VALID BIT(0) @@ -186,9 +192,8 @@ #define DCT_CFG_SEL 0x10C -/* F10 High BASE/LIMIT registers */ -#define F10_DRAM_BASE_HIGH 0x140 -#define F10_DRAM_LIMIT_HIGH 0x144 +#define DRAM_BASE_HI 0x140 +#define DRAM_LIMIT_HI 0x144 /* @@ -395,6 +400,19 @@ struct error_injection { u32 bit_map; }; +/* low and high part of PCI config space regs */ +struct reg_pair { + u32 lo, hi; +}; + +/* + * See F1x[1, 0][7C:40] DRAM Base/Limit Registers + */ +struct dram_range { + struct reg_pair base; + struct reg_pair lim; +}; + struct amd64_pvt { struct low_ops *ops; @@ -418,23 +436,15 @@ struct amd64_pvt { u32 dbam1; /* DRAM Base Address Mapping reg for DCT1 */ /* DRAM CS Base Address Registers F2x[1,0][5C:40] */ - u32 dcsb0[MAX_CS_COUNT]; - u32 dcsb1[MAX_CS_COUNT]; + u32 dcsb0[NUM_CHIPSELECTS]; + u32 dcsb1[NUM_CHIPSELECTS]; /* DRAM CS Mask Registers F2x[1,0][6C:60] */ - u32 dcsm0[MAX_CS_COUNT]; - u32 dcsm1[MAX_CS_COUNT]; + u32 dcsm0[NUM_CHIPSELECTS]; + u32 dcsm1[NUM_CHIPSELECTS]; - /* - * Decoded parts of DRAM BASE and LIMIT Registers - * F1x[78,70,68,60,58,50,48,40] - */ - u64 dram_base[DRAM_REG_COUNT]; - u64 dram_limit[DRAM_REG_COUNT]; - u8 dram_IntlvSel[DRAM_REG_COUNT]; - u8 dram_IntlvEn[DRAM_REG_COUNT]; - u8 dram_DstNode[DRAM_REG_COUNT]; - u8 dram_rw_en[DRAM_REG_COUNT]; + /* DRAM base and limit pairs F1x[78,70,68,60,58,50,48,40] */ + struct dram_range ranges[DRAM_RANGES]; /* * The following fields are set at (load) run time, after CPU revision @@ -472,6 +482,26 @@ struct amd64_pvt { }; +static inline u64 get_dram_base(struct amd64_pvt *pvt, unsigned i) +{ + u64 addr = ((u64)pvt->ranges[i].base.lo & 0xffff0000) << 8; + + if (boot_cpu_data.x86 == 0xf) + return addr; + + return (((u64)pvt->ranges[i].base.hi & 0x000000ff) << 40) | addr; +} + +static inline u64 get_dram_limit(struct amd64_pvt *pvt, unsigned i) +{ + u64 lim = (((u64)pvt->ranges[i].lim.lo & 0xffff0000) << 8) | 0x00ffffff; + + if (boot_cpu_data.x86 == 0xf) + return lim; + + return (((u64)pvt->ranges[i].lim.hi & 0x000000ff) << 40) | lim; +} + /* * per-node ECC settings descriptor */ @@ -517,7 +547,6 @@ struct low_ops { u64 (*get_error_address) (struct mem_ctl_info *mci, struct err_regs *info); - void (*read_dram_base_limit) (struct amd64_pvt *pvt, int dram); void (*read_dram_ctl_register) (struct amd64_pvt *pvt); void (*map_sysaddr_to_csrow) (struct mem_ctl_info *mci, struct err_regs *info, u64 SystemAddr); -- cgit v1.2.3 From bc21fa578742924aa129a493657f797c13d34ad2 Mon Sep 17 00:00:00 2001 From: Borislav Petkov Date: Thu, 11 Nov 2010 17:29:13 +0100 Subject: amd64_edac: Cleanup DHAR handling Adjust to F15h, simplify code, fixup macros. Signed-off-by: Borislav Petkov --- drivers/edac/amd64_edac.c | 36 ++++++++++++++++++------------------ drivers/edac/amd64_edac.h | 11 +++++------ 2 files changed, 23 insertions(+), 24 deletions(-) (limited to 'drivers/edac') diff --git a/drivers/edac/amd64_edac.c b/drivers/edac/amd64_edac.c index 683fd3c716a0..62b4ae9eb337 100644 --- a/drivers/edac/amd64_edac.c +++ b/drivers/edac/amd64_edac.c @@ -487,9 +487,9 @@ int amd64_get_dram_hole_info(struct mem_ctl_info *mci, u64 *hole_base, return 1; } - /* only valid for Fam10h */ - if (boot_cpu_data.x86 == 0x10 && - (pvt->dhar & F10_DRAM_MEM_HOIST_VALID) == 0) { + /* valid for Fam10h and above */ + if (boot_cpu_data.x86 >= 0x10 && + (pvt->dhar & DRAM_MEM_HOIST_VALID) == 0) { debugf1(" Dram Memory Hoisting is DISABLED on this system\n"); return 1; } @@ -518,15 +518,15 @@ int amd64_get_dram_hole_info(struct mem_ctl_info *mci, u64 *hole_base, * addresses in the hole so that they start at 0x100000000. */ - base = dhar_base(pvt->dhar); + base = dhar_base(pvt); *hole_base = base; *hole_size = (0x1ull << 32) - base; if (boot_cpu_data.x86 > 0xf) - *hole_offset = f10_dhar_offset(pvt->dhar); + *hole_offset = f10_dhar_offset(pvt); else - *hole_offset = k8_dhar_offset(pvt->dhar); + *hole_offset = k8_dhar_offset(pvt); debugf1(" DHAR info for node %d base 0x%lx offset 0x%lx size 0x%lx\n", pvt->mc_node_id, (unsigned long)*hole_base, @@ -884,10 +884,9 @@ static void dump_misc_regs(struct amd64_pvt *pvt) debugf1("F1xF0 (DRAM Hole Address): 0x%08x, base: 0x%08x, " "offset: 0x%08x\n", - pvt->dhar, - dhar_base(pvt->dhar), - (boot_cpu_data.x86 == 0xf) ? k8_dhar_offset(pvt->dhar) - : f10_dhar_offset(pvt->dhar)); + pvt->dhar, dhar_base(pvt), + (boot_cpu_data.x86 == 0xf) ? k8_dhar_offset(pvt) + : f10_dhar_offset(pvt)); debugf1(" DramHoleValid: %s\n", (pvt->dhar & DHAR_VALID) ? "yes" : "no"); @@ -1316,7 +1315,7 @@ static inline u32 f10_map_intlv_en_to_shift(u32 intlv_en) static inline u64 f10_get_base_addr_offset(u64 sys_addr, int hi_range_sel, u32 dct_sel_base_addr, u64 dct_sel_base_off, - u32 hole_valid, u32 hole_off, + u32 hole_valid, u64 hole_off, u64 dram_base) { u64 chan_off; @@ -1324,12 +1323,12 @@ static inline u64 f10_get_base_addr_offset(u64 sys_addr, int hi_range_sel, if (hi_range_sel) { if (!(dct_sel_base_addr & 0xFFFF0000) && hole_valid && (sys_addr >= 0x100000000ULL)) - chan_off = hole_off << 16; + chan_off = hole_off; else chan_off = dct_sel_base_off; } else { if (hole_valid && (sys_addr >= 0x100000000ULL)) - chan_off = hole_off << 16; + chan_off = hole_off; else chan_off = dram_base & 0xFFFFF8000000ULL; } @@ -1435,7 +1434,8 @@ static int f10_match_to_this_node(struct amd64_pvt *pvt, int range, u64 sys_addr, int *nid, int *chan_sel) { int cs_found = -EINVAL, high_range = 0; - u32 intlv_shift, hole_off; + u32 intlv_shift; + u64 hole_off; u32 hole_valid, tmp, dct_sel_base, channel; u64 chan_addr, dct_sel_base_off; @@ -1451,11 +1451,11 @@ static int f10_match_to_this_node(struct amd64_pvt *pvt, int range, * This assumes that one node's DHAR is the same as all the other * nodes' DHAR. */ - hole_off = (pvt->dhar & 0x0000FF80); - hole_valid = (pvt->dhar & 0x1); + hole_off = f10_dhar_offset(pvt); + hole_valid = (pvt->dhar & DHAR_VALID); dct_sel_base_off = (pvt->dct_sel_hi & 0xFFFFFC00) << 16; - debugf1(" HoleOffset=0x%x HoleValid=0x%x IntlvSel=0x%x\n", + debugf1(" HoleOffset=0x%016llx HoleValid=%d IntlvSel=0x%x\n", hole_off, hole_valid, intlv_sel); if (intlv_en && @@ -2051,7 +2051,7 @@ static void read_mc_regs(struct amd64_pvt *pvt) read_dct_base_mask(pvt); - amd64_read_pci_cfg(pvt->F1, K8_DHAR, &pvt->dhar); + amd64_read_pci_cfg(pvt->F1, DHAR, &pvt->dhar); amd64_read_dbam_reg(pvt); amd64_read_pci_cfg(pvt->F3, F10_ONLINE_SPARE, &pvt->online_spare); diff --git a/drivers/edac/amd64_edac.h b/drivers/edac/amd64_edac.h index 93af3575e427..a2bc9a650fff 100644 --- a/drivers/edac/amd64_edac.h +++ b/drivers/edac/amd64_edac.h @@ -175,20 +175,19 @@ #define dram_intlv_sel(pvt, i) ((pvt->ranges[i].lim.lo >> 8) & 0x7) #define dram_dst_node(pvt, i) (pvt->ranges[i].lim.lo & 0x7) -#define K8_DHAR 0xf0 - +#define DHAR 0xf0 #define DHAR_VALID BIT(0) -#define F10_DRAM_MEM_HOIST_VALID BIT(1) +#define DRAM_MEM_HOIST_VALID BIT(1) #define DHAR_BASE_MASK 0xff000000 -#define dhar_base(dhar) (dhar & DHAR_BASE_MASK) +#define dhar_base(pvt) ((pvt)->dhar & DHAR_BASE_MASK) #define K8_DHAR_OFFSET_MASK 0x0000ff00 -#define k8_dhar_offset(dhar) ((dhar & K8_DHAR_OFFSET_MASK) << 16) +#define k8_dhar_offset(pvt) (((pvt)->dhar & K8_DHAR_OFFSET_MASK) << 16) #define F10_DHAR_OFFSET_MASK 0x0000ff80 /* NOTE: Extra mask bit vs K8 */ -#define f10_dhar_offset(dhar) ((dhar & F10_DHAR_OFFSET_MASK) << 16) +#define f10_dhar_offset(pvt) (((pvt)->dhar & F10_DHAR_OFFSET_MASK) << 16) #define DCT_CFG_SEL 0x10C -- cgit v1.2.3 From 11c75eadaf75fe6320325aa13dc135f26ad724b8 Mon Sep 17 00:00:00 2001 From: Borislav Petkov Date: Mon, 29 Nov 2010 19:49:02 +0100 Subject: amd64_edac: Cleanup chipselect handling Add a struct representing the DRAM chip select base/limit register pairs. Concentrate all CS handling in a single function. Also, add CS looping macros for cleaner, more readable code. While at it, adjust code to F15h. Finally, do smaller macro names cleanups (remove family names from register macros) and debug messages clarification. No functional change. Signed-off-by: Borislav Petkov --- drivers/edac/amd64_edac.c | 293 ++++++++++++++++++---------------------------- drivers/edac/amd64_edac.h | 81 ++++--------- 2 files changed, 136 insertions(+), 238 deletions(-) (limited to 'drivers/edac') diff --git a/drivers/edac/amd64_edac.c b/drivers/edac/amd64_edac.c index 62b4ae9eb337..306850879f20 100644 --- a/drivers/edac/amd64_edac.c +++ b/drivers/edac/amd64_edac.c @@ -265,37 +265,6 @@ static int amd64_get_scrub_rate(struct mem_ctl_info *mci) return retval; } -/* Map from a CSROW entry to the mask entry that operates on it */ -static inline u32 amd64_map_to_dcs_mask(struct amd64_pvt *pvt, int csrow) -{ - if (boot_cpu_data.x86 == 0xf && pvt->ext_model < K8_REV_F) - return csrow; - else - return csrow >> 1; -} - -/* return the 'base' address the i'th CS entry of the 'dct' DRAM controller */ -static u32 amd64_get_dct_base(struct amd64_pvt *pvt, int dct, int csrow) -{ - if (dct == 0) - return pvt->dcsb0[csrow]; - else - return pvt->dcsb1[csrow]; -} - -/* - * Return the 'mask' address the i'th CS entry. This function is needed because - * there number of DCSM registers on Rev E and prior vs Rev F and later is - * different. - */ -static u32 amd64_get_dct_mask(struct amd64_pvt *pvt, int dct, int csrow) -{ - if (dct == 0) - return pvt->dcsm0[amd64_map_to_dcs_mask(pvt, csrow)]; - else - return pvt->dcsm1[amd64_map_to_dcs_mask(pvt, csrow)]; -} - /* * returns true if the SysAddr given by sys_addr matches the * DRAM base/limit associated with node_id @@ -386,37 +355,47 @@ err_no_match: } /* - * Extract the DRAM CS base address from selected csrow register. + * compute the CS base address of the @csrow on the DRAM controller @dct. + * For details see F2x[5C:40] in the processor's BKDG */ -static u64 base_from_dct_base(struct amd64_pvt *pvt, int csrow) +static void get_cs_base_and_mask(struct amd64_pvt *pvt, int csrow, u8 dct, + u64 *base, u64 *mask) { - return ((u64) (amd64_get_dct_base(pvt, 0, csrow) & pvt->dcsb_base)) << - pvt->dcs_shift; -} + u64 csbase, csmask, base_bits, mask_bits; + u8 addr_shift; -/* - * Extract the mask from the dcsb0[csrow] entry in a CPU revision-specific way. - */ -static u64 mask_from_dct_mask(struct amd64_pvt *pvt, int csrow) -{ - u64 dcsm_bits, other_bits; - u64 mask; - - /* Extract bits from DRAM CS Mask. */ - dcsm_bits = amd64_get_dct_mask(pvt, 0, csrow) & pvt->dcsm_mask; + if (boot_cpu_data.x86 == 0xf && pvt->ext_model < K8_REV_F) { + csbase = pvt->csels[dct].csbases[csrow]; + csmask = pvt->csels[dct].csmasks[csrow]; + base_bits = GENMASK(21, 31) | GENMASK(9, 15); + mask_bits = GENMASK(21, 29) | GENMASK(9, 15); + addr_shift = 4; + } else { + csbase = pvt->csels[dct].csbases[csrow]; + csmask = pvt->csels[dct].csmasks[csrow >> 1]; + addr_shift = 8; - other_bits = pvt->dcsm_mask; - other_bits = ~(other_bits << pvt->dcs_shift); + if (boot_cpu_data.x86 == 0x15) + base_bits = mask_bits = GENMASK(19,30) | GENMASK(5,13); + else + base_bits = mask_bits = GENMASK(19,28) | GENMASK(5,13); + } - /* - * The extracted bits from DCSM belong in the spaces represented by - * the cleared bits in other_bits. - */ - mask = (dcsm_bits << pvt->dcs_shift) | other_bits; + *base = (csbase & base_bits) << addr_shift; - return mask; + *mask = ~0ULL; + /* poke holes for the csmask */ + *mask &= ~(mask_bits << addr_shift); + /* OR them in */ + *mask |= (csmask & mask_bits) << addr_shift; } +#define for_each_chip_select(i, dct, pvt) \ + for (i = 0; i < pvt->csels[dct].b_cnt; i++) + +#define for_each_chip_select_mask(i, dct, pvt) \ + for (i = 0; i < pvt->csels[dct].m_cnt; i++) + /* * @input_addr is an InputAddr associated with the node given by mci. Return the * csrow that input_addr maps to, or -1 on failure (no csrow claims input_addr). @@ -429,19 +408,13 @@ static int input_addr_to_csrow(struct mem_ctl_info *mci, u64 input_addr) pvt = mci->pvt_info; - /* - * Here we use the DRAM CS Base and DRAM CS Mask registers. For each CS - * base/mask register pair, test the condition shown near the start of - * section 3.5.4 (p. 84, BKDG #26094, K8, revA-E). - */ - for (csrow = 0; csrow < pvt->cs_count; csrow++) { - - /* This DRAM chip select is disabled on this node */ - if ((pvt->dcsb0[csrow] & K8_DCSB_CS_ENABLE) == 0) + for_each_chip_select(csrow, 0, pvt) { + if (!csrow_enabled(csrow, 0, pvt)) continue; - base = base_from_dct_base(pvt, csrow); - mask = ~mask_from_dct_mask(pvt, csrow); + get_cs_base_and_mask(pvt, csrow, 0, &base, &mask); + + mask = ~mask; if ((input_addr & mask) == (base & mask)) { debugf2("InputAddr 0x%lx matches csrow %d (node %d)\n", @@ -451,7 +424,6 @@ static int input_addr_to_csrow(struct mem_ctl_info *mci, u64 input_addr) return csrow; } } - debugf2("no matching csrow for InputAddr 0x%lx (MC node %d)\n", (unsigned long)input_addr, pvt->mc_node_id); @@ -779,13 +751,12 @@ static void find_csrow_limits(struct mem_ctl_info *mci, int csrow, u64 base, mask; pvt = mci->pvt_info; - BUG_ON((csrow < 0) || (csrow >= pvt->cs_count)); + BUG_ON((csrow < 0) || (csrow >= pvt->csels[0].b_cnt)); - base = base_from_dct_base(pvt, csrow); - mask = mask_from_dct_mask(pvt, csrow); + get_cs_base_and_mask(pvt, csrow, 0, &base, &mask); *input_addr_min = base & ~mask; - *input_addr_max = base | mask | pvt->dcs_mask_notused; + *input_addr_max = base | mask; } /* Map the Error address to a PAGE and PAGE OFFSET. */ @@ -913,93 +884,62 @@ static void amd64_read_dbam_reg(struct amd64_pvt *pvt) } /* - * NOTE: CPU Revision Dependent code: Rev E and Rev F - * - * Set the DCSB and DCSM mask values depending on the CPU revision value. Also - * set the shift factor for the DCSB and DCSM values. - * - * ->dcs_mask_notused, RevE: - * - * To find the max InputAddr for the csrow, start with the base address and set - * all bits that are "don't care" bits in the test at the start of section - * 3.5.4 (p. 84). - * - * The "don't care" bits are all set bits in the mask and all bits in the gaps - * between bit ranges [35:25] and [19:13]. The value REV_E_DCS_NOTUSED_BITS - * represents bits [24:20] and [12:0], which are all bits in the above-mentioned - * gaps. - * - * ->dcs_mask_notused, RevF and later: - * - * To find the max InputAddr for the csrow, start with the base address and set - * all bits that are "don't care" bits in the test at the start of NPT section - * 4.5.4 (p. 87). - * - * The "don't care" bits are all set bits in the mask and all bits in the gaps - * between bit ranges [36:27] and [21:13]. - * - * The value REV_F_F1Xh_DCS_NOTUSED_BITS represents bits [26:22] and [12:0], - * which are all bits in the above-mentioned gaps. + * see BKDG, F2x[1,0][5C:40], F2[1,0][6C:60] */ -static void amd64_set_dct_base_and_mask(struct amd64_pvt *pvt) +static void prep_chip_selects(struct amd64_pvt *pvt) { - if (boot_cpu_data.x86 == 0xf && pvt->ext_model < K8_REV_F) { - pvt->dcsb_base = REV_E_DCSB_BASE_BITS; - pvt->dcsm_mask = REV_E_DCSM_MASK_BITS; - pvt->dcs_mask_notused = REV_E_DCS_NOTUSED_BITS; - pvt->dcs_shift = REV_E_DCS_SHIFT; - pvt->cs_count = 8; - pvt->num_dcsm = 8; + pvt->csels[0].b_cnt = pvt->csels[1].b_cnt = 8; + pvt->csels[0].m_cnt = pvt->csels[1].m_cnt = 8; } else { - pvt->dcsb_base = REV_F_F1Xh_DCSB_BASE_BITS; - pvt->dcsm_mask = REV_F_F1Xh_DCSM_MASK_BITS; - pvt->dcs_mask_notused = REV_F_F1Xh_DCS_NOTUSED_BITS; - pvt->dcs_shift = REV_F_F1Xh_DCS_SHIFT; - pvt->cs_count = 8; - pvt->num_dcsm = 4; + pvt->csels[0].b_cnt = pvt->csels[1].b_cnt = 8; + pvt->csels[0].m_cnt = pvt->csels[1].m_cnt = 4; } } /* - * Function 2 Offset F10_DCSB0; read in the DCS Base and DCS Mask hw registers + * Function 2 Offset F10_DCSB0; read in the DCS Base and DCS Mask registers */ static void read_dct_base_mask(struct amd64_pvt *pvt) { - int cs, reg; + int cs; - amd64_set_dct_base_and_mask(pvt); + prep_chip_selects(pvt); - for (cs = 0; cs < pvt->cs_count; cs++) { - reg = K8_DCSB0 + (cs * 4); + for_each_chip_select(cs, 0, pvt) { + u32 reg0 = DCSB0 + (cs * 4); + u32 reg1 = DCSB1 + (cs * 4); + u32 *base0 = &pvt->csels[0].csbases[cs]; + u32 *base1 = &pvt->csels[1].csbases[cs]; - if (!amd64_read_dct_pci_cfg(pvt, reg, &pvt->dcsb0[cs])) + if (!amd64_read_dct_pci_cfg(pvt, reg0, base0)) debugf0(" DCSB0[%d]=0x%08x reg: F2x%x\n", - cs, pvt->dcsb0[cs], reg); + cs, *base0, reg0); - if (!dct_ganging_enabled(pvt)) { - reg = F10_DCSB1 + (cs * 4); + if (boot_cpu_data.x86 == 0xf || dct_ganging_enabled(pvt)) + continue; - if (!amd64_read_dct_pci_cfg(pvt, reg, &pvt->dcsb1[cs])) - debugf0(" DCSB1[%d]=0x%08x reg: F2x%x\n", - cs, pvt->dcsb1[cs], reg); - } + if (!amd64_read_dct_pci_cfg(pvt, reg1, base1)) + debugf0(" DCSB1[%d]=0x%08x reg: F2x%x\n", + cs, *base1, reg1); } - for (cs = 0; cs < pvt->num_dcsm; cs++) { - reg = K8_DCSM0 + (cs * 4); + for_each_chip_select_mask(cs, 0, pvt) { + u32 reg0 = DCSM0 + (cs * 4); + u32 reg1 = DCSM1 + (cs * 4); + u32 *mask0 = &pvt->csels[0].csmasks[cs]; + u32 *mask1 = &pvt->csels[1].csmasks[cs]; - if (!amd64_read_dct_pci_cfg(pvt, reg, &pvt->dcsm0[cs])) + if (!amd64_read_dct_pci_cfg(pvt, reg0, mask0)) debugf0(" DCSM0[%d]=0x%08x reg: F2x%x\n", - cs, pvt->dcsm0[cs], reg); + cs, *mask0, reg0); - if (!dct_ganging_enabled(pvt)) { - reg = F10_DCSM1 + (cs * 4); + if (boot_cpu_data.x86 == 0xf || dct_ganging_enabled(pvt)) + continue; - if (!amd64_read_dct_pci_cfg(pvt, reg, &pvt->dcsm1[cs])) - debugf0(" DCSM1[%d]=0x%08x reg: F2x%x\n", - cs, pvt->dcsm1[cs], reg); - } + if (!amd64_read_dct_pci_cfg(pvt, reg1, mask1)) + debugf0(" DCSM1[%d]=0x%08x reg: F2x%x\n", + cs, *mask1, reg1); } } @@ -1261,10 +1201,11 @@ static void f10_read_dram_ctl_register(struct amd64_pvt *pvt) * determine channel based on the interleaving mode: F10h BKDG, 2.8.9 Memory * Interleaving Modes. */ -static u32 f10_determine_channel(struct amd64_pvt *pvt, u64 sys_addr, +static u8 f10_determine_channel(struct amd64_pvt *pvt, u64 sys_addr, int hi_range_sel, u32 intlv_en) { - u32 cs, temp, dct_sel_high = (pvt->dct_sel_low >> 1) & 1; + u32 temp, dct_sel_high = (pvt->dct_sel_low >> 1) & 1; + u8 cs; if (dct_ganging_enabled(pvt)) cs = 0; @@ -1345,14 +1286,13 @@ static inline u64 f10_get_base_addr_offset(u64 sys_addr, int hi_range_sel, * checks if the csrow passed in is marked as SPARED, if so returns the new * spare row */ -static inline int f10_process_possible_spare(int csrow, - u32 cs, struct amd64_pvt *pvt) +static int f10_process_possible_spare(struct amd64_pvt *pvt, u8 dct, int csrow) { u32 swap_done; u32 bad_dram_cs; /* Depending on channel, isolate respective SPARING info */ - if (cs) { + if (dct) { swap_done = F10_ONLINE_SPARE_SWAPDONE1(pvt->online_spare); bad_dram_cs = F10_ONLINE_SPARE_BADDRAM_CS1(pvt->online_spare); if (swap_done && (csrow == bad_dram_cs)) @@ -1374,11 +1314,11 @@ static inline int f10_process_possible_spare(int csrow, * -EINVAL: NOT FOUND * 0..csrow = Chip-Select Row */ -static int f10_lookup_addr_in_dct(u32 in_addr, u32 nid, u32 cs) +static int f10_lookup_addr_in_dct(u64 in_addr, u32 nid, u8 dct) { struct mem_ctl_info *mci; struct amd64_pvt *pvt; - u32 cs_base, cs_mask; + u64 cs_base, cs_mask; int cs_found = -EINVAL; int csrow; @@ -1388,39 +1328,25 @@ static int f10_lookup_addr_in_dct(u32 in_addr, u32 nid, u32 cs) pvt = mci->pvt_info; - debugf1("InputAddr=0x%x channelselect=%d\n", in_addr, cs); - - for (csrow = 0; csrow < pvt->cs_count; csrow++) { + debugf1("input addr: 0x%llx, DCT: %d\n", in_addr, dct); - cs_base = amd64_get_dct_base(pvt, cs, csrow); - if (!(cs_base & K8_DCSB_CS_ENABLE)) + for_each_chip_select(csrow, dct, pvt) { + if (!csrow_enabled(csrow, dct, pvt)) continue; - /* - * We have an ENABLED CSROW, Isolate just the MASK bits of the - * target: [28:19] and [13:5], which map to [36:27] and [21:13] - * of the actual address. - */ - cs_base &= REV_F_F1Xh_DCSB_BASE_BITS; - - /* - * Get the DCT Mask, and ENABLE the reserved bits: [18:16] and - * [4:0] to become ON. Then mask off bits [28:0] ([36:8]) - */ - cs_mask = amd64_get_dct_mask(pvt, cs, csrow); + get_cs_base_and_mask(pvt, csrow, dct, &cs_base, &cs_mask); - debugf1(" CSROW=%d CSBase=0x%x RAW CSMask=0x%x\n", - csrow, cs_base, cs_mask); + debugf1(" CSROW=%d CSBase=0x%llx CSMask=0x%llx\n", + csrow, cs_base, cs_mask); - cs_mask = (cs_mask | 0x0007C01F) & 0x1FFFFFFF; + cs_mask = ~cs_mask; - debugf1(" Final CSMask=0x%x\n", cs_mask); - debugf1(" (InputAddr & ~CSMask)=0x%x " - "(CSBase & ~CSMask)=0x%x\n", - (in_addr & ~cs_mask), (cs_base & ~cs_mask)); + debugf1(" (InputAddr & ~CSMask)=0x%llx " + "(CSBase & ~CSMask)=0x%llx\n", + (in_addr & cs_mask), (cs_base & cs_mask)); - if ((in_addr & ~cs_mask) == (cs_base & ~cs_mask)) { - cs_found = f10_process_possible_spare(csrow, cs, pvt); + if ((in_addr & cs_mask) == (cs_base & cs_mask)) { + cs_found = f10_process_possible_spare(pvt, dct, csrow); debugf1(" MATCH csrow=%d\n", cs_found); break; @@ -1434,10 +1360,11 @@ static int f10_match_to_this_node(struct amd64_pvt *pvt, int range, u64 sys_addr, int *nid, int *chan_sel) { int cs_found = -EINVAL, high_range = 0; - u32 intlv_shift; - u64 hole_off; - u32 hole_valid, tmp, dct_sel_base, channel; u64 chan_addr, dct_sel_base_off; + u64 hole_off; + u32 hole_valid, tmp, dct_sel_base; + u32 intlv_shift; + u8 channel; u8 node_id = dram_dst_node(pvt, range); u32 intlv_en = dram_intlv_en(pvt, range); @@ -1499,10 +1426,9 @@ static int f10_match_to_this_node(struct amd64_pvt *pvt, int range, } } - debugf1(" (ChannelAddrLong=0x%llx) >> 8 becomes InputAddr=0x%x\n", - chan_addr, (u32)(chan_addr >> 8)); + debugf1(" (ChannelAddrLong=0x%llx)\n", chan_addr); - cs_found = f10_lookup_addr_in_dct(chan_addr >> 8, node_id, channel); + cs_found = f10_lookup_addr_in_dct(chan_addr, node_id, channel); if (cs_found >= 0) { *nid = node_id; @@ -1603,7 +1529,8 @@ static void amd64_debug_display_dimm_sizes(int ctrl, struct amd64_pvt *pvt) } dbam = (ctrl && !dct_ganging_enabled(pvt)) ? pvt->dbam1 : pvt->dbam0; - dcsb = (ctrl && !dct_ganging_enabled(pvt)) ? pvt->dcsb1 : pvt->dcsb0; + dcsb = (ctrl && !dct_ganging_enabled(pvt)) ? pvt->csels[1].csbases + : pvt->csels[0].csbases; debugf1("F2x%d80 (DRAM Bank Address Mapping): 0x%08x\n", ctrl, dbam); @@ -1613,11 +1540,11 @@ static void amd64_debug_display_dimm_sizes(int ctrl, struct amd64_pvt *pvt) for (dimm = 0; dimm < 4; dimm++) { size0 = 0; - if (dcsb[dimm*2] & K8_DCSB_CS_ENABLE) + if (dcsb[dimm*2] & DCSB_CS_ENABLE) size0 = pvt->ops->dbam_to_cs(pvt, DBAM_DIMM(dimm, dbam)); size1 = 0; - if (dcsb[dimm*2 + 1] & K8_DCSB_CS_ENABLE) + if (dcsb[dimm*2 + 1] & DCSB_CS_ENABLE) size1 = pvt->ops->dbam_to_cs(pvt, DBAM_DIMM(dimm, dbam)); amd64_info(EDAC_MC ": %d: %5dMB %d: %5dMB\n", @@ -2082,7 +2009,7 @@ static void read_mc_regs(struct amd64_pvt *pvt) * NOTE: CPU Revision Dependent code * * Input: - * @csrow_nr ChipSelect Row Number (0..pvt->cs_count-1) + * @csrow_nr ChipSelect Row Number (0..NUM_CHIPSELECTS-1) * k8 private pointer to --> * DRAM Bank Address mapping register * node_id @@ -2148,7 +2075,7 @@ static int init_csrows(struct mem_ctl_info *mci) { struct csrow_info *csrow; struct amd64_pvt *pvt = mci->pvt_info; - u64 input_addr_min, input_addr_max, sys_addr; + u64 input_addr_min, input_addr_max, sys_addr, base, mask; u32 val; int i, empty = 1; @@ -2161,10 +2088,10 @@ static int init_csrows(struct mem_ctl_info *mci) pvt->mc_node_id, val, !!(val & K8_NBCFG_CHIPKILL), !!(val & K8_NBCFG_ECC_ENABLE)); - for (i = 0; i < pvt->cs_count; i++) { + for_each_chip_select(i, 0, pvt) { csrow = &mci->csrows[i]; - if ((pvt->dcsb0[i] & K8_DCSB_CS_ENABLE) == 0) { + if (!csrow_enabled(i, 0, pvt)) { debugf1("----CSROW %d EMPTY for node %d\n", i, pvt->mc_node_id); continue; @@ -2180,7 +2107,9 @@ static int init_csrows(struct mem_ctl_info *mci) csrow->first_page = (u32) (sys_addr >> PAGE_SHIFT); sys_addr = input_addr_to_sys_addr(mci, input_addr_max); csrow->last_page = (u32) (sys_addr >> PAGE_SHIFT); - csrow->page_mask = ~mask_from_dct_mask(pvt, i); + + get_cs_base_and_mask(pvt, i, 0, &base, &mask); + csrow->page_mask = ~mask; /* 8 bytes of resolution */ csrow->mtype = amd64_determine_memory_type(pvt, i); @@ -2532,7 +2461,7 @@ static int amd64_init_one_instance(struct pci_dev *F2) goto err_siblings; ret = -ENOMEM; - mci = edac_mc_alloc(0, pvt->cs_count, pvt->channel_count, nid); + mci = edac_mc_alloc(0, pvt->csels[0].b_cnt, pvt->channel_count, nid); if (!mci) goto err_siblings; diff --git a/drivers/edac/amd64_edac.h b/drivers/edac/amd64_edac.h index a2bc9a650fff..1964f89a28bc 100644 --- a/drivers/edac/amd64_edac.h +++ b/drivers/edac/amd64_edac.h @@ -159,6 +159,14 @@ #define ON true #define OFF false +/* + * Create a contiguous bitmask starting at bit position @lo and ending at + * position @hi. For example + * + * GENMASK(21, 39) gives us the 64bit vector 0x000000ffffe00000. + */ +#define GENMASK(lo, hi) (((1ULL << ((hi) - (lo) + 1)) - 1) << (lo)) + /* * PCI-defined configuration space registers */ @@ -198,45 +206,14 @@ /* * Function 2 - DRAM controller */ -#define K8_DCSB0 0x40 -#define F10_DCSB1 0x140 - -#define K8_DCSB_CS_ENABLE BIT(0) -#define K8_DCSB_NPT_SPARE BIT(1) -#define K8_DCSB_NPT_TESTFAIL BIT(2) - -/* - * REV E: select [31:21] and [15:9] from DCSB and the shift amount to form - * the address - */ -#define REV_E_DCSB_BASE_BITS (0xFFE0FE00ULL) -#define REV_E_DCS_SHIFT 4 - -#define REV_F_F1Xh_DCSB_BASE_BITS (0x1FF83FE0ULL) -#define REV_F_F1Xh_DCS_SHIFT 8 - -/* - * REV F and later: selects [28:19] and [13:5] from DCSB and the shift amount - * to form the address - */ -#define REV_F_DCSB_BASE_BITS (0x1FF83FE0ULL) -#define REV_F_DCS_SHIFT 8 - -/* DRAM CS Mask Registers */ -#define K8_DCSM0 0x60 -#define F10_DCSM1 0x160 - -/* REV E: select [29:21] and [15:9] from DCSM */ -#define REV_E_DCSM_MASK_BITS 0x3FE0FE00 - -/* unused bits [24:20] and [12:0] */ -#define REV_E_DCS_NOTUSED_BITS 0x01F01FFF +#define DCSB0 0x40 +#define DCSB1 0x140 +#define DCSB_CS_ENABLE BIT(0) -/* REV F and later: select [28:19] and [13:5] from DCSM */ -#define REV_F_F1Xh_DCSM_MASK_BITS 0x1FF83FE0 +#define DCSM0 0x60 +#define DCSM1 0x160 -/* unused bits [26:22] and [12:0] */ -#define REV_F_F1Xh_DCS_NOTUSED_BITS 0x07C01FFF +#define csrow_enabled(i, dct, pvt) ((pvt)->csels[(dct)].csbases[(i)] & DCSB_CS_ENABLE) #define DBAM0 0x80 #define DBAM1 0x180 @@ -412,6 +389,15 @@ struct dram_range { struct reg_pair lim; }; +/* A DCT chip selects collection */ +struct chip_select { + u32 csbases[NUM_CHIPSELECTS]; + u8 b_cnt; + + u32 csmasks[NUM_CHIPSELECTS]; + u8 m_cnt; +}; + struct amd64_pvt { struct low_ops *ops; @@ -434,29 +420,12 @@ struct amd64_pvt { u32 dbam0; /* DRAM Base Address Mapping reg for DCT0 */ u32 dbam1; /* DRAM Base Address Mapping reg for DCT1 */ - /* DRAM CS Base Address Registers F2x[1,0][5C:40] */ - u32 dcsb0[NUM_CHIPSELECTS]; - u32 dcsb1[NUM_CHIPSELECTS]; - - /* DRAM CS Mask Registers F2x[1,0][6C:60] */ - u32 dcsm0[NUM_CHIPSELECTS]; - u32 dcsm1[NUM_CHIPSELECTS]; + /* one for each DCT */ + struct chip_select csels[2]; /* DRAM base and limit pairs F1x[78,70,68,60,58,50,48,40] */ struct dram_range ranges[DRAM_RANGES]; - /* - * The following fields are set at (load) run time, after CPU revision - * has been determined, since the dct_base and dct_mask registers vary - * based on revision - */ - u32 dcsb_base; /* DCSB base bits */ - u32 dcsm_mask; /* DCSM mask bits */ - u32 cs_count; /* num chip selects (== num DCSB registers) */ - u32 num_dcsm; /* Number of DCSM registers */ - u32 dcs_mask_notused; /* DCSM notused mask bits */ - u32 dcs_shift; /* DCSB and DCSM shift value */ - u64 top_mem; /* top of memor