amd64_edac: Add Bulldozer support
Subsystems (4)
cover amd64_edac: Add Bulldozer support
From: Borislav Petkov <[email protected]>
Hi all,
the following patchset that adds support for our upcoming F15h CPUs. Besides adding a new family support, it cleans up a lot in the driver and the diffstat says it all:
arch/x86/kernel/amd_nb.c | 2 +- drivers/edac/amd64_edac.c | 1412 +++++++++++++++++++---------------------- drivers/edac/amd64_edac.h | 357 ++++------- drivers/edac/amd64_edac_inj.c | 8 +- drivers/edac/edac_mc_sysfs.c | 26 +- drivers/edac/mce_amd.c | 8 +- drivers/edac/mce_amd.h | 28 +- include/linux/pci_ids.h | 2 +- 8 files changed, 825 insertions(+), 1018 deletions(-)
@Greg/@Ingo: Guys, let me know if patch 27/30 should be rerouted over your trees or would you rather like to ACK it?
Any comments/suggestions are welcome.
Thanks.
PATCH 1/30 EDAC: Shut up sysfs registration debug code
From: Borislav Petkov <[email protected]>
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.
--- drivers/edac/edac_mc_sysfs.c | 26 +++++++++++++------------- 1 files changed, 13 insertions(+), 13 deletions(-)
drivers/edac/edac_mc_sysfs.c +13 -13
@@ -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); }
Signature · 1 line
1.7.4.rc2
PATCH 2/30 amd64_edac: Add support for F15h DCT PCI config accesses
In reply to Borislav PetkovFrom: Borislav Petkov <[email protected]>
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.
--- 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(-)
drivers/edac/amd64_edac.c +117 -47
@@ -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 */
drivers/edac/amd64_edac.h +25 -24
90 lines not on this page · raw message
drivers/edac/amd64_edac_inj.c +4 -4
@@ -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);
Signature · 1 line
1.7.4.rc2
PATCH 3/30 amd64_edac: Remove DRAM base/limit subfields caching
In reply to Borislav PetkovFrom: Borislav Petkov <[email protected]>
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.
--- drivers/edac/amd64_edac.c | 230 +++++++++++++-------------------------------- drivers/edac/amd64_edac.h | 73 ++++++++++----- 2 files changed, 115 insertions(+), 188 deletions(-)
drivers/edac/amd64_edac.c +64 -166
@@ -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; }
@@ -477,19 +459,6 @@ static int input_addr_to_csrow(struct mem_ctl_info *mci, u64 input_addr) }/* -* 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, * *hole_offset, and *hole_size. Function returns 0 if info is valid or 1 if
@@ -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);
drivers/edac/amd64_edac.h +51 -22
118 lines not on this page · raw message
Signature · 1 line
1.7.4.rc2
PATCH 4/30 amd64_edac: Cleanup DHAR handling
In reply to Borislav PetkovFrom: Borislav Petkov <[email protected]>
Adjust to F15h, simplify code, fixup macros.
--- drivers/edac/amd64_edac.c | 36 ++++++++++++++++++------------------ drivers/edac/amd64_edac.h | 11 +++++------ 2 files changed, 23 insertions(+), 24 deletions(-)
drivers/edac/amd64_edac.c +18 -18
@@ -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);
drivers/edac/amd64_edac.h +5 -6
@@ -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
Signature · 1 line
1.7.4.rc2
PATCH 5/30 amd64_edac: Cleanup chipselect handling
In reply to Borislav PetkovFrom: Borislav Petkov <[email protected]>
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.
--- drivers/edac/amd64_edac.c | 293 +++++++++++++++++---------------------------- drivers/edac/amd64_edac.h | 81 ++++--------- 2 files changed, 136 insertions(+), 238 deletions(-)
drivers/edac/amd64_edac.c +111 -182
@@ -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;
drivers/edac/amd64_edac.h +25 -56
111 lines not on this page · raw message
Signature · 1 line
1.7.4.rc2
Re: [PATCH 05/30] amd64_edac: Cleanup chipselect handling
Em 10-02-2011 15:15, Borislav Petkov escreveu:
Quoted 11 lines
From: Borislav Petkov <[email protected]>
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 <[email protected]>
Hi Borislav,
drivers/edac/amd64_edac.h line 169
Quoted 13 lines
drivers/edac/amd64_edac.h +7
-0@@ -160,6 +160,14 @@#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)) +
This is a nice macro that could be useful outside amd64. It is probably a good idea to move it to include/linux/bitops.h.
Cheers,
Mauro.
Re: [PATCH 05/30] amd64_edac: Cleanup chipselect handling
Quoted 20 lines · Mauro Carvalho Chehab
Em 10-02-2011 15:15, Borislav Petkov escreveu:
Quoted 11 lines
From: Borislav Petkov <[email protected]>
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 <[email protected]>Hi Borislav,
Quoted 5 lines
drivers/edac/amd64_edac.h +0
-0@@ -160,6 +160,14 @@#define OFF false
Quoted 11 lines
drivers/edac/amd64_edac.h line 169
Quoted 8 lines
drivers/edac/amd64_edac.h +7
-0/* +* 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)) +This is a nice macro that could be useful outside amd64. It is probably a good idea to move it to
include/linux/bitops.h.
I'd suggest rather <drivers/edac/edac_core.h> if you want to use it in EDAC. But if we have more users, I don't have a problem with putting it there (or somewhere else generic enough if people have a better suggestion).
Signature · 8 lines
Regards/Gruss, Boris. Advanced Micro Devices GmbH Einsteinring 24, 85609 Dornach General Managers: Alberto Bozzo, Andrew Bowd Registration: Dornach, Gemeinde Aschheim, Landkreis Muenchen Registergericht Muenchen, HRB Nr. 43632
Re: [PATCH 05/30] amd64_edac: Cleanup chipselect handling
Em 29-03-2011 12:16, Borislav Petkov escreveu:
Quoted 33 lines · Mauro Carvalho Chehab
Quoted 20 lines
Em 10-02-2011 15:15, Borislav Petkov escreveu:
Quoted 11 lines
From: Borislav Petkov <[email protected]>
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 <[email protected]>Hi Borislav,
Quoted 5 lines
drivers/edac/amd64_edac.h +0
-0@@ -160,6 +160,14 @@#define OFF falseQuoted 11 lines
drivers/edac/amd64_edac.h line 169
Quoted 8 lines
drivers/edac/amd64_edac.h +7
-0/* +* 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)) +This is a nice macro that could be useful outside amd64. It is probably a good idea to move it to
include/linux/bitops.h.
Quoted 4 lines
I'd suggest rather <
drivers/edac/edac_core.h> if you want to use it in EDAC. But if we have more users, I don't have a problem with putting it there (or somewhere else generic enough if people have a better suggestion).
Yeah, other edac drivers could benefit of using it, and also could benefit on a variant that would do an AND operation and shift it, something like (untested):
/*
* Create a contiguous bitmask starting at bit position @lo and ending at
* position @hi. For example
*
* APPLY_BITMASK(v, 21, 39) will return the result of:
* (v & 0x000000ffffe00000) >> 21
*/
#define APPLY_BITMASK(v, lo, hi) (((v) & ((1ULL << ((hi) - (lo) + 1)) - 1) << (lo)) >> (lo))
Almost all edac drivers do something like the above, for example, to get DIMM rows/cols/banks, etc.
Probably, the most complex part is to find a nice name for it ;)
Yet, I think non-edac drivers could also benefit of such macro, and, as this is not edac-specific, I think it would be better to add it at bitops.h.
Cheers,
Mauro
Re: [PATCH 05/30] amd64_edac: Cleanup chipselect handling
Quoted 19 lines · Mauro Carvalho Chehab
Quoted 11 lines
Quoted 10 lines
drivers/edac/amd64_edac.h line 169
Quoted 7 lines
+ * Create a contiguous bitmask starting at bit position @lo and ending at
+ * position @hi. For example
+ *
+ *GENMASK(21, 39)gives us the 64bit vector0x000000ffffe00000.
+ */drivers/edac/amd64_edac.h +2
-0+#define GENMASK (lo, hi) (((1ULL << ((hi) - (lo) + 1)) - 1) << (lo)) +This is a nice macro that could be useful outside amd64. It is probably a good idea to move it to
include/linux/bitops.h.Quoted 4 lines
I'd suggest rather <
drivers/edac/edac_core.h> if you want to use it in EDAC. But if we have more users, I don't have a problem with putting it there (or somewhere else generic enough if people have a better suggestion).Yeah, other edac drivers could benefit of using it, and also could benefit on a variant that would do an AND operation and shift it, something like (untested):
Quoted 8 lines
/*
* Create a contiguous bitmask starting at bit position @lo and ending at
* position @hi. For example
*
*APPLY_BITMASK(v, 21, 39)will return the result of:
* (v &0x000000ffffe00000) >> 21
*/
#defineAPPLY_BITMASK(v, lo, hi)(((v) & ((1ULL << ((hi) - (lo) + 1)) - 1) << (lo)) >> (lo))
The macro definition doesn't match the comment. In the comment you do a bitwise AND first and shift the result then. The way you've written it, it does
((v & 0x000000000007ffff << 21) >> 21)
you need to fixup the brackets:
#define APPLY_BITMASK(v, lo, hi) (((v) & (((1ULL << ((hi) - (lo) + 1)) - 1) << (lo))) >> (lo))
Also, this doesn't only apply it but shifts too, so it should be
#define APPLY_BITMASK_AND_SHIFT(...)
But this macro gets too special to put it in shared code.
Quoted 6 lines
Almost all edac drivers do something like the above, for example, to get DIMM rows/cols/banks, etc.
Probably, the most complex part is to find a nice name for it ;)
Yet, I think non-edac drivers could also benefit of such macro, and, as this is not edac-specific, I think it would be better to add it at
bitops.h.
No, this should go into generic code only if it has users - "it might benefit" is not strong-enough an argument for polluting generic code. I'd leave it in edac_core.h and push it somewhere more generic only when I need it in other subsystems.
Signature · 8 lines
Regards/Gruss, Boris. Advanced Micro Devices GmbH Einsteinring 24, 85609 Dornach General Managers: Alberto Bozzo, Andrew Bowd Registration: Dornach, Gemeinde Aschheim, Landkreis Muenchen Registergericht Muenchen, HRB Nr. 43632
Re: [PATCH 05/30] amd64_edac: Cleanup chipselect handling
Em 29-03-2011 13:02, Borislav Petkov escreveu:
Quoted 29 lines · Mauro Carvalho Chehab
Quoted 19 lines
Quoted 11 lines
Quoted 10 lines
drivers/edac/amd64_edac.h line 169
Quoted 7 lines
+ * Create a contiguous bitmask starting at bit position @lo and ending at
+ * position @hi. For example
+ *
+ *GENMASK(21, 39)gives us the 64bit vector0x000000ffffe00000.
+ */drivers/edac/amd64_edac.h +2
-0+#define GENMASK (lo, hi) (((1ULL << ((hi) - (lo) + 1)) - 1) << (lo)) +This is a nice macro that could be useful outside amd64. It is probably a good idea to move it to
include/linux/bitops.h.Quoted 4 lines
I'd suggest rather <
drivers/edac/edac_core.h> if you want to use it in EDAC. But if we have more users, I don't have a problem with putting it there (or somewhere else generic enough if people have a better suggestion).Yeah, other edac drivers could benefit of using it, and also could benefit on a variant that would do an AND operation and shift it, something like (untested):
Quoted 8 lines
/*
* Create a contiguous bitmask starting at bit position @lo and ending at
* position @hi. For example
*
*APPLY_BITMASK(v, 21, 39)will return the result of:
* (v &0x000000ffffe00000) >> 21
*/
#defineAPPLY_BITMASK(v, lo, hi)(((v) & ((1ULL << ((hi) - (lo) + 1)) - 1) << (lo)) >> (lo))
Quoted 6 lines
The macro definition doesn't match the comment. In the comment you do a bitwise AND first and shift the result then. The way you've written it, it does
((v & 0x000000000007ffff << 21) >> 21)you need to fixup the brackets:
Ah, yes. As I said, it was untested ;) I was in the middle of reviewing lots of edac patches, but I didn't want to loose the idea, so I was quick on my reply ;)
Quoted 6 lines
#define
APPLY_BITMASK(v, lo, hi)(((v) & (((1ULL << ((hi) - (lo) + 1)) - 1) << (lo))) >> (lo))Also, this doesn't only apply it but shifts too, so it should be
#define
APPLY_BITMASK_AND_SHIFT(...)
Yeah, that name sounds better ;)
Quoted 2 lines
But this macro gets too special to put it in shared code.
Ok.
Quoted 5 lines
Quoted 5 lines
Almost all edac drivers do something like the above, for example, to get DIMM rows/cols/banks, etc.
Probably, the most complex part is to find a nice name for it ;)
Quoted 7 lines
Quoted 2 lines
Yet, I think non-edac drivers could also benefit of such macro, and, as this is not edac-specific, I think it would be better to add it at
bitops.h.No, this should go into generic code only if it has users - "it might benefit" is not strong-enough an argument for polluting generic code. I'd leave it in
edac_core.hand push it somewhere more generic only when I need it in other subsystems.
Works for me.
Thanks!
Mauro
PATCH 6/30 amd64_edac: Sanitize channel extraction
In reply to Borislav PetkovFrom: Borislav Petkov <[email protected]>
Cleanup and simplify f10_determine_channel(); make it more readable. Also drop f10_map_intlv_en_to_shift() in favor of simply counting the bits in F1x124[DramIntlvEn] which is equivalent.
There should be no functionality change resulting from this patch.
--- drivers/edac/amd64_edac.c | 84 ++++++++++++++++++-------------------------- 1 files changed, 34 insertions(+), 50 deletions(-)
drivers/edac/amd64_edac.c +34 -50
@@ -1198,62 +1198,48 @@ static void f10_read_dram_ctl_register(struct amd64_pvt *pvt) }/* -* determine channel based on the interleaving mode: F10h BKDG, 2.8.9 Memory +* Determine channel (DCT) based on the interleaving mode: F10h BKDG, 2.8.9 Memory * Interleaving Modes. */ static u8 f10_determine_channel (struct amd64_pvt *pvt,u64 sys_addr, -int hi_range_sel,u32 intlv_en) +bool hi_range_sel,u8 intlv_en) { -u32 temp, dct_sel_high = (pvt->dct_sel_low >>1 ) &1 ; -u8 cs; +u32 dct_sel_high = (pvt->dct_sel_low >>1 ) &1 ;if (dct_ganging_enabled (pvt)) - cs =0 ; -else if (hi_range_sel) - cs = dct_sel_high; -else if (dct_interleave_enabled (pvt)) { -/* -* see F2x110[DctSelIntLvAddr] - channel interleave mode -*/ -if (dct_sel_interleave_addr (pvt) ==0 ) - cs = sys_addr >>6 &1 ; -else if ((dct_sel_interleave_addr (pvt) >>1 ) &1 ) { - temp =hweight_long ((u32) ((sys_addr >>16 ) &0x1F )) %2 ; - -if (dct_sel_interleave_addr (pvt) &1 ) - cs = (sys_addr >>9 &1 ) ^ temp; -else - cs = (sys_addr >>6 &1 ) ^ temp; - }else if (intlv_en &4 ) - cs = sys_addr >>15 &1 ; -else if (intlv_en &2 ) - cs = sys_addr >>14 &1 ; -else if (intlv_en &1 ) - cs = sys_addr >>13 &1 ; -else - cs = sys_addr >>12 &1 ; - }else if (dct_high_range_enabled (pvt) && !dct_ganging_enabled (pvt)) - cs = ~dct_sel_high &1 ; -else - cs =0 ; +return 0 ; -return cs; -} +if (hi_range_sel) +return dct_sel_high; -static inline u32 f10_map_intlv_en_to_shift (u32 intlv_en) -{ -if (intlv_en ==1 ) -return 1 ; -else if (intlv_en ==3 ) -return 2 ; -else if (intlv_en ==7 ) -return 3 ; +/* +* see F2x110[DctSelIntLvAddr] - channel interleave mode +*/ +if (dct_interleave_enabled (pvt)) { +u8 intlv_addr =dct_sel_interleave_addr (pvt); + +/* return DCT select function: 0=DCT0, 1=DCT1 */ +if (!intlv_addr) +return sys_addr >>6 &1 ; + +if (intlv_addr &0x2 ) { +u8 shift = intlv_addr &0x1 ?9 :6 ; +u32 temp =hweight_long ((u32) ((sys_addr >>16 ) &0x1F )) %2 ; + +return ((sys_addr >> shift) &1 ) ^ temp; + } + +return (sys_addr >> (12 +hweight8 (intlv_en))) &1 ; + } + +if (dct_high_range_enabled (pvt)) +return ~dct_sel_high &1 ;return 0 ; }/* See F10h BKDG, 2.8.10.2 DctSelBaseOffset Programming */ -static inline u64 f10_get_base_addr_offset(u64 sys_addr, int hi_range_sel, +static inline u64 f10_get_base_addr_offset(u64 sys_addr, bool hi_range_sel, u32 dct_sel_base_addr, u64 dct_sel_base_off, u32 hole_valid, u64 hole_off,
@@ -1359,15 +1345,15 @@ static int f10_lookup_addr_in_dct(u64 in_addr, u32 nid, u8 dct)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 ; +int cs_found = -EINVAL ;u64 chan_addr, dct_sel_base_off;u64 hole_off;u32 hole_valid, tmp, dct_sel_base; -u32 intlv_shift;u8 channel; +bool high_range = false;u8 node_id =dram_dst_node (pvt, range); -u32 intlv_en =dram_intlv_en (pvt, range); +u8 intlv_en =dram_intlv_en (pvt, range);u32 intlv_sel =dram_intlv_sel (pvt, range);u64 dram_base =get_dram_base (pvt, range);
@@ -1398,7 +1384,7 @@ static int f10_match_to_this_node(struct amd64_pvt *pvt, int range,if (dct_high_range_enabled (pvt) && !dct_ganging_enabled (pvt) && ((sys_addr >>27 ) >= (dct_sel_base >>11 ))) - high_range =1 ; + high_range = true; channel =f10_determine_channel (pvt, sys_addr, high_range, intlv_en);
@@ -1406,12 +1392,10 @@ static int f10_match_to_this_node(struct amd64_pvt *pvt, int range, dct_sel_base_off, hole_valid, hole_off, dram_base); - intlv_shift =f10_map_intlv_en_to_shift (intlv_en); -/* remove Node ID (in case of memory interleaving) */ tmp = chan_addr &0xFC0 ; - chan_addr = ((chan_addr >> intlv_shift) &0xFFFFFFFFF000ULL ) | tmp; + chan_addr = ((chan_addr >>hweight8 (intlv_en)) &0xFFFFFFFFF000ULL ) | tmp;/* remove channel interleave and hash */ if (dct_interleave_enabled(pvt) &&
Signature · 1 line
1.7.4.rc2
PATCH 7/30 amd64_edac: Sanitize f10_get_base_addr_offset
In reply to Borislav PetkovFrom: Borislav Petkov <[email protected]>
This function maps the system address to the normalized DCT address. Document what the code does for more clarity and wrap insane bitmasks in a more understandable macro which generates them. Also, reduce number of arguments passed to the function. Finally, rename this function to what it actually does.
No functional change.
--- drivers/edac/amd64_edac.c | 83 ++++++++++++++++++++++++-------------------- drivers/edac/amd64_edac.h | 15 +++----- 2 files changed, 50 insertions(+), 48 deletions(-)
drivers/edac/amd64_edac.c +45 -38
@@ -460,13 +460,12 @@ int amd64_get_dram_hole_info(struct mem_ctl_info *mci, u64 *hole_base, }/* valid for Fam10h and above */ -if (boot_cpu_data.x86 >=0x10 && - (pvt->dhar &DRAM_MEM_HOIST_VALID ) ==0 ) { +if (boot_cpu_data.x86 >=0x10 && !dhar_mem_hoist_valid (pvt)) {debugf1 (" Dram Memory Hoisting is DISABLED on this system\n" );return 1 ; } -if ((pvt->dhar &DHAR_VALID ) ==0 ) { +if (!dhar_valid (pvt)) {debugf1 (" Dram Memory Hoisting is DISABLED on this node %d\n" , pvt->mc_node_id);return 1 ;
@@ -859,8 +858,7 @@ static void dump_misc_regs(struct amd64_pvt *pvt) (boot_cpu_data.x86 ==0xf ) ?k8_dhar_offset (pvt) : f10_dhar_offset(pvt)); -debugf1 (" DramHoleValid: %s\n" , - (pvt->dhar &DHAR_VALID ) ?"yes" :"no" ); +debugf1 (" DramHoleValid: %s\n" ,dhar_valid (pvt) ?"yes" :"no" );amd64_debug_display_dimm_sizes (0 , pvt);
@@ -1238,30 +1236,53 @@ static u8 f10_determine_channel(struct amd64_pvt *pvt, u64 sys_addr,return 0 ; } -/* See F10h BKDG, 2.8.10.2 DctSelBaseOffset Programming */ -static inline u64 f10_get_base_addr_offset (u64 sys_addr,bool hi_range_sel, -u32 dct_sel_base_addr, -u64 dct_sel_base_off, -u32 hole_valid,u64 hole_off, -u64 dram_base) +/* Convert the sys_addr to the normalized DCT address */ +static u64 f10_get_norm_dct_addr (struct amd64_pvt *pvt,int range, +u64 sys_addr,bool hi_rng, +u32 dct_sel_base_addr) {u64 chan_off; +u64 dram_base =get_dram_base (pvt, range); +u64 hole_off =f10_dhar_offset (pvt); +u32 hole_valid =dhar_valid (pvt); +u64 dct_sel_base_off = (pvt->dct_sel_hi &0xFFFFFC00 ) <<16 ; -if (hi_range_sel) { -if (!(dct_sel_base_addr &0xFFFF0000 ) && - hole_valid && (sys_addr >=0x100000000ULL )) +if (hi_rng) { +/* +* if +* base address of high range is below 4Gb +* (bits [47:27] at [31:11]) +* DRAM address space on this DCT is hoisted above 4Gb && +* sys_addr > 4Gb +* +* remove hole offset from sys_addr +* else +* remove high range offset from sys_addr +*/ +if ((!(dct_sel_base_addr >>16 ) || + dct_sel_base_addr <dhar_base (pvt)) && + hole_valid && + (sys_addr >=BIT_64 (32 ))) chan_off = hole_off;else chan_off = dct_sel_base_off; }else { -if (hole_valid && (sys_addr >=0x100000000ULL )) +/* +* if +* we have a valid hole && +* sys_addr > 4Gb +* +* remove hole +* else +* remove dram base to normalize to DCT address +*/ +if (hole_valid && (sys_addr >=BIT_64 (32 ))) chan_off = hole_off;else - chan_off = dram_base &0xFFFFF8000000ULL ; + chan_off = dram_base; } -return (sys_addr &0x0000FFFFFFFFFFC0ULL ) - - (chan_off &0x0000FFFFFF800000ULL ); +return (sys_addr &GENMASK (6 ,47 )) - (chan_off &GENMASK (23 ,47 )); }/* Hack for the time being - Can we get this from BIOS?? */
@@ -1346,30 +1367,17 @@ 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; -u64 chan_addr, dct_sel_base_off; -u64 hole_off; -u32 hole_valid, tmp, dct_sel_base; +u64 chan_addr; +u32 tmp, dct_sel_base;u8 channel;bool high_range = false;u8 node_id =dram_dst_node (pvt, range);u8 intlv_en =dram_intlv_en (pvt, range);u32 intlv_sel =dram_intlv_sel (pvt, range); -u64 dram_base =get_dram_base (pvt, 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 -* nodes' DHAR. -*/ - 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%016llx HoleValid=%d IntlvSel=0x%x\n" , - hole_off, hole_valid, intlv_sel); +debugf1 ("(range %d) SystemAddr= 0x%llx Limit=0x%llx\n" , + range, sys_addr,get_dram_limit (pvt, range));if (intlv_en && (intlv_sel != ((sys_addr >>12 ) & intlv_en)))
@@ -1388,9 +1396,8 @@ static int f10_match_to_this_node(struct amd64_pvt *pvt, int range, channel =f10_determine_channel (pvt, sys_addr, high_range, intlv_en); - chan_addr =f10_get_base_addr_offset (sys_addr, high_range, dct_sel_base, - dct_sel_base_off, hole_valid, - hole_off, dram_base); + chan_addr =f10_get_norm_dct_addr (pvt, range, sys_addr, + high_range, dct_sel_base);/* remove Node ID (in case of memory interleaving) */ tmp = chan_addr &0xFC0 ;
drivers/edac/amd64_edac.h +5 -10
@@ -184,18 +184,13 @@#define dram_dst_node (pvt, i) (pvt->ranges[i].lim.lo & 0x7)#define DHAR 0xf0 -#define DHAR_VALID BIT(0) -#define DRAM_MEM_HOIST_VALID BIT(1) +#define dhar_valid (pvt) ((pvt)->dhar & BIT(0)) +#define dhar_mem_hoist_valid (pvt) ((pvt)->dhar & BIT(1)) +#define dhar_base (pvt) ((pvt)->dhar & 0xff000000) +#define k8_dhar_offset (pvt) (((pvt)->dhar & 0x0000ff00) << 16) -#define DHAR_BASE_MASK 0xff000000 -#define dhar_base (pvt) ((pvt)->dhar & DHAR_BASE_MASK) - -#define K8_DHAR_OFFSET_MASK 0x0000ff00 -#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 (pvt) (((pvt)->dhar & F10_DHAR_OFFSET_MASK) << 16) +#define f10_dhar_offset (pvt) (((pvt)->dhar & 0x0000ff80) << 16)#define DCT_CFG_SEL 0x10C
Signature · 1 line
1.7.4.rc2
PATCH 8/30 amd64_edac: Replace huge bitmasks with a macro
In reply to Borislav PetkovFrom: Borislav Petkov <[email protected]>
Replace hard to read hex constants with a continuous masks macro.
--- drivers/edac/amd64_edac.c | 19 +++++++++---------- 1 files changed, 9 insertions(+), 10 deletions(-)
drivers/edac/amd64_edac.c +9 -10
@@ -570,7 +570,7 @@ static u64 sys_addr_to_dram_addr(struct mem_ctl_info *mci, u64 sys_addr)* section 3.4.2 of AMD publication 24592: AMD x86-64 Architecture * Programmer's Manual Volume 1 Application Programming. */ - dram_addr = (sys_addr &0xffffffffffull ) - dram_base; + dram_addr = (sys_addr &GENMASK (0 ,39 )) - dram_base; debugf2("using DRAM Base register to translate SysAddr 0x%lx to " "DramAddr 0x%lx\n", (unsigned long)sys_addr,
@@ -607,8 +607,8 @@ static u64 dram_addr_to_input_addr(struct mem_ctl_info *mci, u64 dram_addr)* concerning translating a DramAddr to an InputAddr. */ intlv_shift =num_node_interleave_bits (dram_intlv_en (pvt,0 )); - input_addr = ((dram_addr >> intlv_shift) &0xffffff000ull ) + - (dram_addr &0xfff ); + input_addr = ((dram_addr >> intlv_shift) &GENMASK (12 ,35 )) + + (dram_addr &0xfff ); debugf2(" Intlv Shift=%d DramAddr=0x%lx maps to InputAddr=0x%lx\n", intlv_shift, (unsigned long)dram_addr,
@@ -667,8 +667,8 @@ static u64 input_addr_to_dram_addr(struct mem_ctl_info *mci, u64 input_addr)return input_addr; } - bits = ((input_addr &0xffffff000ull ) << intlv_shift) + - (input_addr &0xfff ); + 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 );
@@ -1399,21 +1399,20 @@ static int f10_match_to_this_node(struct amd64_pvt *pvt, int range, chan_addr =f10_get_norm_dct_addr (pvt, range, sys_addr, high_range, dct_sel_base); -/* remove Node ID (in case of memory interleaving) */ +/* remove Node ID (in case of node interleaving) */ tmp = chan_addr &0xFC0 ; - chan_addr = ((chan_addr >>hweight8 (intlv_en)) &0xFFFFFFFFF000ULL ) | tmp; + chan_addr = ((chan_addr >>hweight8 (intlv_en)) &GENMASK (12 ,47 )) | tmp;/* remove channel interleave and hash */ if (dct_interleave_enabled (pvt) && !dct_high_range_enabled (pvt) && !dct_ganging_enabled (pvt)) {if (dct_sel_interleave_addr (pvt) !=1 ) - chan_addr = (chan_addr >>1 ) &0xFFFFFFFFFFFFFFC0ULL ; + chan_addr = (chan_addr >>1 ) &GENMASK (6 ,63 );else { tmp = chan_addr &0xFC0 ; - chan_addr = ((chan_addr &0xFFFFFFFFFFFFC000ULL ) >>1 ) - | tmp; + chan_addr = ((chan_addr &GENMASK (14 ,63 )) >>1 ) | tmp; } }
Signature · 1 line
1.7.4.rc2
PATCH 9/30 amd64_edac: Cleanup DBAM handling
In reply to Borislav PetkovFrom: Borislav Petkov <[email protected]>
Do not read DBAM regs twice and simplify code around them.
There should be no functional change resulting from this patch.
--- drivers/edac/amd64_edac.c | 27 ++++++++------------------- 1 files changed, 8 insertions(+), 19 deletions(-)
drivers/edac/amd64_edac.c +8 -19
@@ -875,12 +875,6 @@ static void dump_misc_regs(struct amd64_pvt *pvt)amd64_dump_dramcfg_low (pvt->dclr1,1 ); } -static void amd64_read_dbam_reg (struct amd64_pvt *pvt) -{ -amd64_read_dct_pci_cfg (pvt,DBAM0 , &pvt->dbam0); -amd64_read_dct_pci_cfg (pvt,DBAM1 , &pvt->dbam1); -} -/* * see BKDG, F2x[1,0][5C:40], F2[1,0][6C:60] */
@@ -1098,9 +1092,7 @@ static int k8_dbam_to_chip_select(struct amd64_pvt *pvt, int cs_mode)*/ static int f10_early_channel_count (struct amd64_pvt *pvt) { -int dbams[] = {DBAM0 ,DBAM1 };int i, j, channels =0 ; -u32 dbam;/* If we are in 128 bit mode, then we are using 2 channels */ if (pvt->dclr0 &F10_WIDTH_128 ) {
@@ -1123,9 +1115,8 @@ static int f10_early_channel_count(struct amd64_pvt *pvt)* is more than just one DIMM present in unganged mode. Need to check * both controllers since DIMMs can be placed in either one. */ -for (i =0 ; i <ARRAY_SIZE (dbams); i++) { -if (amd64_read_dct_pci_cfg (pvt, dbams[i], &dbam)) - goto err_reg; +for (i =0 ; i <2 ; i++) { +u32 dbam = (i ? pvt->dbam1 : pvt->dbam0);for (j =0 ; j <4 ; j++) {if (DBAM_DIMM (j, dbam) >0 ) {
@@ -1141,10 +1132,6 @@ static int f10_early_channel_count(struct amd64_pvt *pvt)amd64_info ("MCT channel count: %d\n" , channels);return channels; - -err_reg: -return -1 ; - }static int f10_dbam_to_chip_select (struct amd64_pvt *pvt,int cs_mode)
@@ -1504,8 +1491,8 @@ static void f10_map_sysaddr_to_csrow(struct mem_ctl_info *mci,static void amd64_debug_display_dimm_sizes (int ctrl,struct amd64_pvt *pvt) {int dimm, size0, size1, factor =0 ; -u32 dbam; -u32 *dcsb; +u32 *dcsb = ctrl ? pvt->csels[1 ].csbases : pvt->csels[0 ].csbases; +u32 dbam = ctrl ? pvt->dbam1 : pvt->dbam0;if (boot_cpu_data.x86 ==0xf ) {if (pvt->dclr0 &F10_WIDTH_128 )
@@ -1969,7 +1956,7 @@ static void read_mc_regs(struct amd64_pvt *pvt)read_dct_base_mask (pvt);amd64_read_pci_cfg (pvt->F1,DHAR , &pvt->dhar); -amd64_read_dbam_reg (pvt); +amd64_read_dct_pci_cfg (pvt,DBAM0 , &pvt->dbam0);amd64_read_pci_cfg (pvt->F3,F10_ONLINE_SPARE , &pvt->online_spare);
@@ -1981,8 +1968,10 @@ static void read_mc_regs(struct amd64_pvt *pvt)amd64_read_dct_pci_cfg (pvt,F10_DCHR_1 , &pvt->dchr1); } -if (boot_cpu_data.x86 >=0x10 ) +if (boot_cpu_data.x86 >=0x10 ) {amd64_read_pci_cfg (pvt->F3,EXT_NB_MCA_CFG , &tmp); +amd64_read_dct_pci_cfg (pvt,DBAM1 , &pvt->dbam1); + } if (boot_cpu_data.x86 == 0x10 && boot_cpu_data.x86_model > 7 &&
Signature · 1 line
1.7.4.rc2
PATCH 10/30 amd64_edac: Cleanup Dram Configuration registers handling
In reply to Borislav PetkovFrom: Borislav Petkov <[email protected]>
* Restrict DCT ganged mode check since only Fam10h supports it
* Adjust DRAM type detection for BD since it only supports DDR3
* Remove second and thus unneeded DCLR read in k8_early_channel_count() - we do that in read_mc_regs()
* Cleanup comments and remove family names from register macros
* Remove unused defines
There should be no functional change resulting from this patch.
--- drivers/edac/amd64_edac.c | 42 +++++++++++++++++------------------------- drivers/edac/amd64_edac.h | 19 +++++++------------ 2 files changed, 24 insertions(+), 37 deletions(-)
drivers/edac/amd64_edac.c +17 -25
@@ -799,7 +799,7 @@ static u16 extract_syndrome(struct err_regs *err)*/ static enum edac_type amd64_determine_edac_cap (struct amd64_pvt *pvt) { -int bit; +u8 bit;enum dev_type edac_cap =EDAC_FLAG_NONE ; bit = (boot_cpu_data.x86 >0xf || pvt->ext_model >=K8_REV_F )
@@ -826,8 +826,9 @@ static void amd64_dump_dramcfg_low(u32 dclr, int chan)debugf1 (" PAR/ERR parity: %s\n" , (dclr &BIT (8 )) ?"enabled" :"disabled" ); -debugf1 (" DCT 128bit mode width: %s\n" , - (dclr &BIT (11 )) ?"128b" :"64b" ); +if (boot_cpu_data.x86 ==0x10 ) +debugf1 (" DCT 128bit mode width: %s\n" , + (dclr &BIT (11 )) ?"128b" :"64b" ); debugf1(" x4 logical DIMMs present: L0: %s L1: %s L2: %s L3: %s\n", (dclr & BIT(12)) ? "yes" : "no",
@@ -939,7 +940,10 @@ static enum mem_type amd64_determine_memory_type(struct amd64_pvt *pvt, int cs) {enum mem_type type; -if (boot_cpu_data.x86 >=0x10 || pvt->ext_model >=K8_REV_F ) { +/* F15h supports only DDR3 */ +if (boot_cpu_data.x86 >=0x15 ) + type = (pvt->dclr0 &BIT (16 )) ?MEM_DDR3 :MEM_RDDR3 ; +else if (boot_cpu_data.x86 ==0x10 || pvt->ext_model >=K8_REV_F ) {if (pvt->dchr0 &DDR3_MODE ) type = (pvt->dclr0 &BIT (16 )) ?MEM_DDR3 :MEM_RDDR3 ;else
@@ -953,22 +957,10 @@ static enum mem_type amd64_determine_memory_type(struct amd64_pvt *pvt, int cs)return type; } -/* -* Read the DRAM Configuration Low register. It differs between CG, D & E revs -* and the later RevF memory controllers (DDR vs DDR2) -* -* Return: -* number of memory channels in operation -* Pass back: -* contents of the DCL0_LOW register -*/ +/* Get the number of DCT channels the memory controller is using. */ static int k8_early_channel_count (struct amd64_pvt *pvt) { -int flag, err =0 ; - - err =amd64_read_dct_pci_cfg (pvt,F10_DCLR_0 , &pvt->dclr0); -if (err) -return err; +int flag;if (pvt->ext_model >=K8_REV_F )/* RevF (NPT) and later */
@@ -983,7 +975,7 @@ static int k8_early_channel_count(struct amd64_pvt *pvt)return (flag) ?2 :1 ; } -/* extract the ERROR ADDRESS for the K8 CPUs */ +/* Extract the ERROR ADDRESS for the K8 CPUs */ static u64 k8_get_error_address (struct mem_ctl_info *mci,struct err_regs *info) {
@@ -1486,7 +1478,7 @@ static void f10_map_sysaddr_to_csrow(struct mem_ctl_info *mci,/* * debug routine to display the memory sizes of all logical DIMMs and its -* CSROWs as well +* CSROWs */ static void amd64_debug_display_dimm_sizes (int ctrl,struct amd64_pvt *pvt) {
@@ -1960,12 +1952,12 @@ static void read_mc_regs(struct amd64_pvt *pvt)amd64_read_pci_cfg (pvt->F3,F10_ONLINE_SPARE , &pvt->online_spare); -amd64_read_dct_pci_cfg (pvt,F10_DCLR_0 , &pvt->dclr0); -amd64_read_dct_pci_cfg (pvt,F10_DCHR_0 , &pvt->dchr0); +amd64_read_dct_pci_cfg (pvt,DCLR0 , &pvt->dclr0); +amd64_read_dct_pci_cfg (pvt,DCHR0 , &pvt->dchr0); -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 (!dct_ganging_enabled (pvt) && boot_cpu_data.x86 >0xf ) { +amd64_read_dct_pci_cfg (pvt,DCLR1 , &pvt->dclr1); +amd64_read_dct_pci_cfg (pvt,DCHR1 , &pvt->dchr1); }if (boot_cpu_data.x86 >=0x10 ) {
drivers/edac/amd64_edac.h +7 -12
@@ -218,27 +218,23 @@#define DBAM_MAX_VALUE 11 - -#define F10_DCLR_0 0x90 -#define F10_DCLR_1 0x190 +#define DCLR0 0x90 +#define DCLR1 0x190#define REVE_WIDTH_128 BIT(16)#define F10_WIDTH_128 BIT(11) - -#define F10_DCHR_0 0x94 -#define F10_DCHR_1 0x194 - -#define F10_DCHR_FOUR_RANK_DIMM BIT(18) +#define DCHR0 0x94 +#define DCHR1 0x194#define DDR3_MODE BIT(8) -#define F10_DCHR_MblMode BIT(6) -#define F10_DCTL_SEL_LOW 0x110#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_ganging_enabled (pvt) ((boot_cpu_data.x86 == 0x10) && ((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))
@@ -262,7 +258,6 @@#define K8_NBSL 0x48 -/* Family F10h: Normalized Extended Error Codes */ #define F10_NBSL_EXT_ERR_RES 0x0#define F10_NBSL_EXT_ERR_ECC 0x8
Signature · 1 line
1.7.4.rc2
PATCH 11/30 amd64_edac: Cleanup DCT Select Low/High code
In reply to Borislav PetkovFrom: Borislav Petkov <[email protected]>
Shorten macro names, remove family name from macros, fix macro arguments, shorten debug strings.
No functionality change.
--- drivers/edac/amd64_edac.c | 20 ++++++++++---------- drivers/edac/amd64_edac.h | 24 ++++++++++++------------ 2 files changed, 22 insertions(+), 22 deletions(-)
drivers/edac/amd64_edac.c +10 -10
@@ -1148,11 +1148,11 @@ static u64 f10_get_error_address(struct mem_ctl_info *mci,static void f10_read_dram_ctl_register (struct amd64_pvt *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)); +if (!amd64_read_dct_pci_cfg (pvt,DCT_SEL_LO , &pvt->dct_sel_lo)) { +debugf0 ("F2x110 (DCTSelLow): 0x%08x, High range addrs at: 0x%x\n" , + pvt->dct_sel_lo,dct_sel_baseaddr (pvt)); -debugf0 (" DCT mode: %s, All DCTs on: %s\n" , +debugf0 (" mode: %s, All DCTs on: %s\n" , (dct_ganging_enabled (pvt) ?"ganged" :"unganged" ), (dct_dram_enabled (pvt) ?"yes" :"no" ));
@@ -1160,18 +1160,18 @@ static void f10_read_dram_ctl_register(struct amd64_pvt *pvt)debugf0 (" Address range split per DCT: %s\n" , (dct_high_range_enabled (pvt) ?"yes" :"no" )); -debugf0 (" DCT data interleave for ECC: %s, " +debugf0 (" data interleave for ECC: %s, " "DRAM cleared since last warm reset: %s\n" , (dct_data_intlv_enabled (pvt) ?"enabled" :"disabled" ), (dct_memory_cleared (pvt) ?"yes" :"no" )); -debugf0 (" DCT channel interleave: %s, " -"DCT interleave bits selector: 0x%x\n" , +debugf0 (" channel interleave: %s, " +"interleave bits selector: 0x%x\n" , (dct_interleave_enabled (pvt) ?"enabled" :"disabled" ),dct_sel_interleave_addr (pvt)); } -amd64_read_dct_pci_cfg (pvt,F10_DCTL_SEL_HIGH , &pvt->dct_sel_hi); +amd64_read_dct_pci_cfg (pvt,DCT_SEL_HI , &pvt->dct_sel_hi); }/*
@@ -1181,7 +1181,7 @@ static void f10_read_dram_ctl_register(struct amd64_pvt *pvt)static u8 f10_determine_channel (struct amd64_pvt *pvt,u64 sys_addr,bool hi_range_sel,u8 intlv_en) { -u32 dct_sel_high = (pvt->dct_sel_low >>1 ) &1 ; +u32 dct_sel_high = (pvt->dct_sel_lo >>1 ) &1 ;if (dct_ganging_enabled (pvt))return 0 ;
@@ -1955,7 +1955,7 @@ static void read_mc_regs(struct amd64_pvt *pvt)amd64_read_dct_pci_cfg (pvt,DCLR0 , &pvt->dclr0);amd64_read_dct_pci_cfg (pvt,DCHR0 , &pvt->dchr0); -if (!dct_ganging_enabled (pvt) && boot_cpu_data.x86 >0xf ) { +if (!dct_ganging_enabled (pvt)) {amd64_read_dct_pci_cfg (pvt,DCLR1 , &pvt->dclr1);amd64_read_dct_pci_cfg (pvt,DCHR1 , &pvt->dchr1); }
drivers/edac/amd64_edac.h +12 -12
@@ -227,19 +227,19 @@#define DCHR1 0x194#define DDR3_MODE BIT(8) -#define F10_DCTL_SEL_LOW 0x110 -#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_SEL_LO 0x110 +#define dct_sel_baseaddr (pvt) ((pvt)->dct_sel_lo & 0xFFFFF800) +#define dct_sel_interleave_addr (pvt) (((pvt)->dct_sel_lo >> 6) & 0x3) +#define dct_high_range_enabled (pvt) ((pvt)->dct_sel_lo & BIT(0)) +#define dct_interleave_enabled (pvt) ((pvt)->dct_sel_lo & BIT(2)) -#define dct_ganging_enabled (pvt) ((boot_cpu_data.x86 == 0x10) && ((pvt)->dct_sel_low & BIT(4))) +#define dct_ganging_enabled (pvt) ((boot_cpu_data.x86 == 0x10) && ((pvt)->dct_sel_lo & 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 dct_data_intlv_enabled (pvt) ((pvt)->dct_sel_lo & BIT(5)) +#define dct_dram_enabled (pvt) ((pvt)->dct_sel_lo & BIT(8)) +#define dct_memory_cleared (pvt) ((pvt)->dct_sel_lo & BIT(10)) -#define F10_DCTL_SEL_HIGH 0x114 +#define DCT_SEL_HI 0x114/* * Function 3 - Misc Control
@@ -419,8 +419,8 @@ struct amd64_pvt {u64 top_mem;/* top of memory below 4GB */ u64 top_mem2;/* top of memory above 4GB */ -u32 dct_sel_low;/* DRAM Controller Select Low Reg */ -u32 dct_sel_hi;/* DRAM Controller Select High Reg */ +u32 dct_sel_lo;/* DRAM Controller Select Low */ +u32 dct_sel_hi;/* DRAM Controller Select High */ u32 online_spare;/* On-Line spare Reg */ /* x4 or x8 syndromes in use */
Signature · 1 line
1.7.4.rc2
PATCH 12/30 amd64_edac: Cleanup NBCTL code
In reply to Borislav PetkovFrom: Borislav Petkov <[email protected]>
Remove family names from macro names, drop single bit defines and comment their meaning instead.
No functional change.
--- drivers/edac/amd64_edac.c | 14 +++++++------- drivers/edac/amd64_edac.h | 8 +------- 2 files changed, 8 insertions(+), 14 deletions(-)
drivers/edac/amd64_edac.c +7 -7
@@ -2196,21 +2196,20 @@ static bool enable_ecc_error_reporting(struct ecc_settings *s, u8 nid, struct pci_dev *F3) {bool ret = true; -u32 value, mask = K8_NBCTL_CECCEn | K8_NBCTL_UECCEn; +u32 value, mask =0x3 ;/* UECC/CECC enable */ if (toggle_ecc_err_reporting (s, nid,ON )) {amd64_warn ("Error enabling ECC reporting over MCGCTL!\n" );return false; } -amd64_read_pci_cfg (F3 ,K8_NBCTL , &value); +amd64_read_pci_cfg (F3 ,NBCTL , &value); -/* turn on UECCEn and CECCEn bits */ s->old_nbctl = value & mask; s->nbctl_valid = true; value |= mask; -amd64_write_pci_cfg (F3 ,K8_NBCTL , value); +amd64_write_pci_cfg (F3 ,NBCTL , value);amd64_read_pci_cfg (F3 ,K8_NBCFG , &value);
@@ -2250,16 +2249,17 @@ static bool enable_ecc_error_reporting(struct ecc_settings *s, u8 nid,static void restore_ecc_error_reporting (struct ecc_settings *s,u8 nid,struct pci_dev *F3 ) { -u32 value, mask = K8_NBCTL_CECCEn | K8_NBCTL_UECCEn; +u32 value, mask =0x3 ;/* UECC/CECC enable */ +if (!s->nbctl_valid)return ; -amd64_read_pci_cfg (F3 ,K8_NBCTL , &value); +amd64_read_pci_cfg (F3 ,NBCTL , &value); value &= ~mask; value |= s->old_nbctl; -amd64_write_pci_cfg (F3 ,K8_NBCTL , value); +amd64_write_pci_cfg (F3 ,NBCTL , value);/* restore previous BIOS DRAM ECC "off" setting we force-enabled */ if (!s->flags.nb_ecc_prev) {
drivers/edac/amd64_edac.h +1 -7
@@ -244,13 +244,7 @@/* * Function 3 - Misc Control */ -#define K8_NBCTL 0x40 - -/* Correctable ECC error reporting enable */ -#define K8_NBCTL_CECCEn BIT(0) - -/* UnCorrectable ECC error reporting enable */ -#define K8_NBCTL_UECCEn BIT(1) +#define NBCTL 0x40#define K8_NBCFG 0x44#define K8_NBCFG_CHIPKILL BIT(23)
Signature · 1 line
1.7.4.rc2
PATCH 13/30 amd64_edac: Cleanup NBCFG handling
In reply to Borislav PetkovFrom: Borislav Petkov <[email protected]>
The fact whether we are chipkill capable or not does not have any bearing when computing the channel index on a ganged DCT configuration so remove that. Also, simplify debug statements. Finally, remove old error injection leftovers, while at it.
--- drivers/edac/amd64_edac.c | 45 +++++++++++++++++++++------------------------ drivers/edac/amd64_edac.h | 9 +++------ 2 files changed, 24 insertions(+), 30 deletions(-)
drivers/edac/amd64_edac.c +21 -24
@@ -1011,7 +1011,7 @@ static void k8_map_sysaddr_to_csrow(struct mem_ctl_info *mci, syndrome =extract_syndrome (err_info);/* CHIPKILL enabled */ -if (err_info->nbcfg &K8_NBCFG_CHIPKILL ) { +if (err_info->nbcfg &NBCFG_CHIPKILL ) { channel =get_channel_from_ecc_syndrome (mci, syndrome);if (channel <0 ) {/*
@@ -1461,7 +1461,7 @@ static void f10_map_sysaddr_to_csrow(struct mem_ctl_info *mci,* ganged. Otherwise @chan should already contain the channel at * this point. */ -if (dct_ganging_enabled (pvt) && (pvt->nbcfg &K8_NBCFG_CHIPKILL )) +if (dct_ganging_enabled (pvt)) chan =get_channel_from_ecc_syndrome (mci, syndrome);if (chan >=0 )
@@ -2050,14 +2050,13 @@ static int init_csrows(struct mem_ctl_info *mci)u32 val;int i, empty =1 ; -amd64_read_pci_cfg (pvt->F3,K8_NBCFG , &val); +amd64_read_pci_cfg (pvt->F3,NBCFG , &val); pvt->nbcfg = val; - pvt->ctl_error_info.nbcfg = val;debugf0 ("node %d, NBCFG=0x%08x[ChipKillEccCap: %d|DramEccEn: %d]\n" , pvt->mc_node_id, val, - !!(val &K8_NBCFG_CHIPKILL ), !!(val &K8_NBCFG_ECC_ENABLE )); + !!(val &NBCFG_CHIPKILL ), !!(val &NBCFG_ECC_ENABLE ));for_each_chip_select (i,0 , pvt) { csrow = &mci->csrows[i];
@@ -2099,9 +2098,9 @@ static int init_csrows(struct mem_ctl_info *mci)/* * determine whether CHIPKILL or JUST ECC or NO ECC is operating */ -if (pvt->nbcfg &K8_NBCFG_ECC_ENABLE ) +if (pvt->nbcfg &NBCFG_ECC_ENABLE ) csrow->edac_mode = - (pvt->nbcfg &K8_NBCFG_CHIPKILL ) ? + (pvt->nbcfg &NBCFG_CHIPKILL ) ?EDAC_S4ECD4ED :EDAC_SECDED ;else csrow->edac_mode =EDAC_NONE ;
@@ -2211,24 +2210,23 @@ static bool enable_ecc_error_reporting(struct ecc_settings *s, u8 nid, value |= mask;amd64_write_pci_cfg (F3 ,NBCTL , value); -amd64_read_pci_cfg (F3 ,K8_NBCFG , &value); +amd64_read_pci_cfg (F3 ,NBCFG , &value); -debugf0 ("1: node %d, NBCFG=0x%08x[ChipKillEccCap: %d|DramEccEn: %d]\n" , - nid, value, - !!(value &K8_NBCFG_CHIPKILL ), !!(value &K8_NBCFG_ECC_ENABLE )); +debugf0 ("1: node %d, NBCFG=0x%08x[DramEccEn: %d]\n" , + nid, value, !!(value &NBCFG_ECC_ENABLE )); -if (!(value &K8_NBCFG_ECC_ENABLE )) { +if (!(value &NBCFG_ECC_ENABLE )) {amd64_warn ("DRAM ECC disabled on this node, enabling...\n" ); s->flags.nb_ecc_prev =0 ;/* Attempt to turn on DRAM ECC Enable */ - value |=K8_NBCFG_ECC_ENABLE ; -amd64_write_pci_cfg (F3 ,K8_NBCFG , value); + value |=NBCFG_ECC_ENABLE ; +amd64_write_pci_cfg (F3 ,NBCFG , value); -amd64_read_pci_cfg (F3 ,K8_NBCFG , &value); +amd64_read_pci_cfg (F3 ,NBCFG , &value); -if (!(value &K8_NBCFG_ECC_ENABLE )) { +if (!(value &NBCFG_ECC_ENABLE )) {amd64_warn ("Hardware rejected DRAM ECC enable," "check memory DIMM configuration.\n" ); ret = false;
@@ -2239,9 +2237,8 @@ static bool enable_ecc_error_reporting(struct ecc_settings *s, u8 nid, s->flags.nb_ecc_prev =1 ; } -debugf0 ("2: node %d, NBCFG=0x%08x[ChipKillEccCap: %d|DramEccEn: %d]\n" , - nid, value, - !!(value &K8_NBCFG_CHIPKILL ), !!(value &K8_NBCFG_ECC_ENABLE )); +debugf0 ("2: node %d, NBCFG=0x%08x[DramEccEn: %d]\n" , + nid, value, !!(value &NBCFG_ECC_ENABLE ));return ret; }
@@ -2263,9 +2260,9 @@ static void restore_ecc_error_reporting(struct ecc_settings *s, u8 nid,/* 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 ; -amd64_write_pci_cfg (F3 ,K8_NBCFG , value); +amd64_read_pci_cfg (F3 ,NBCFG , &value); + value &= ~NBCFG_ECC_ENABLE ; +amd64_write_pci_cfg (F3 ,NBCFG , value); }/* restore the NB Enable MCGCTL bit */
@@ -2291,9 +2288,9 @@ static bool ecc_enabled(struct pci_dev *F3, u8 nid)u8 ecc_en =0 ;bool nb_mce_en = false; -amd64_read_pci_cfg (F3 ,K8_NBCFG , &value); +amd64_read_pci_cfg (F3 ,NBCFG , &value); - ecc_en = !!(value &K8_NBCFG_ECC_ENABLE ); + ecc_en = !!(value &NBCFG_ECC_ENABLE );amd64_info ("DRAM ECC %s.\n" , (ecc_en ?"enabled" :"disabled" )); nb_mce_en =amd64_nb_mce_bank_enabled_on_node (nid);
drivers/edac/amd64_edac.h +3 -6
@@ -246,9 +246,9 @@*/ #define NBCTL 0x40 -#define K8_NBCFG 0x44 -#define K8_NBCFG_CHIPKILL BIT(23) -#define K8_NBCFG_ECC_ENABLE BIT(22) +#define NBCFG 0x44 +#define NBCFG_CHIPKILL BIT(23) +#define NBCFG_ECC_ENABLE BIT(22)#define K8_NBSL 0x48
@@ -420,9 +420,6 @@ struct amd64_pvt {/* x4 or x8 syndromes in use */ u8 syn_type; -/* temp storage for when input is received from sysfs */ -struct err_regs ctl_error_info; -/* place to store error injection parameters prior to issue */ struct error_injection injection;
Signature · 1 line
1.7.4.rc2
PATCH 14/30 amd64_edac: Cleanup NBSH cruft
In reply to Borislav PetkovFrom: Borislav Petkov <[email protected]>
Remove reporting of errors with UC bit set - this is done by the MCE decoding code anyway and this driver deals with DRAM ECC errors only. UC (NB uncorrectable error) doesn't necessarily mean it is a DRAM error. Remove unused macros while at it.
--- drivers/edac/amd64_edac.c | 15 ++------------- drivers/edac/mce_amd.c | 2 +- drivers/edac/mce_amd.h | 18 +++++------------- 3 files changed, 8 insertions(+), 27 deletions(-)
drivers/edac/amd64_edac.c +2 -13
@@ -1748,7 +1748,7 @@ static void amd64_handle_ce(struct mem_ctl_info *mci,u64 sys_addr;/* Ensure that the Error Address is VALID */ -if (!(info->nbsh &K8_NBSH_VALID_ERROR_ADDR )) { +if (!(info->nbsh &NBSH_VALID_ERROR_ADDR )) {amd64_mc_err (mci,"HW has no ERROR_ADDRESS available\n" );edac_mc_handle_ce_no_info (mci,EDAC_MOD_STR );return ;
@@ -1773,7 +1773,7 @@ static void amd64_handle_ue(struct mem_ctl_info *mci, log_mci = mci; -if (!(info->nbsh &K8_NBSH_VALID_ERROR_ADDR )) { +if (!(info->nbsh &NBSH_VALID_ERROR_ADDR )) {amd64_mc_err (mci,"HW has no ERROR_ADDRESS available\n" );edac_mc_handle_ue_no_info (log_mci,EDAC_MOD_STR );return ;
@@ -1839,17 +1839,6 @@ void amd64_decode_bus_error(int node_id, struct mce *m, u32 nbcfg) regs.nbcfg = nbcfg;__amd64_decode_bus_error (mci, ®s); - -/* -* Check the UE bit of the NB status high register, if set generate some -* logs. If NOT a GART error, then process the event as a NO-INFO event. -* If it was a GART error, skip that process. -* -* FIXME: this should go somewhere else, if at all. -*/ -if (regs.nbsh &K8_NBSH_UC_ERR && !report_gart_errors) -edac_mc_handle_ue_no_info (mci,"UE bit is set" ); - }/*
drivers/edac/mce_amd.c +1 -1
@@ -604,7 +604,7 @@ void amd_decode_nb_mce(int node_id, struct mce *m, u32 nbcfg)/* F10h, revD can disable ErrCpu[3:0] through ErrCpuVal */ if ((boot_cpu_data.x86 ==0x10 ) && (boot_cpu_data.x86_model >7 )) { -if (nbsh &K8_NBSH_ERR_CPU_VAL ) +if (nbsh &NBSH_ERR_CPU_VAL ) core = nbsh & nb_err_cpumask; }else {u8 assoc_cpus = nbsh & nb_err_cpumask;
drivers/edac/mce_amd.h +5 -13
@@ -31,19 +31,11 @@#define R4 (x) (((x) >> 4) & 0xf)#define R4_MSG (x) ((R4(x) < 9) ? rrrr_msgs[R4(x)] : "Wrong R4!") -#define K8_NBSH 0x4C - -#define K8_NBSH_VALID_BIT BIT(31) -#define K8_NBSH_OVERFLOW BIT(30) -#define K8_NBSH_UC_ERR BIT(29) -#define K8_NBSH_ERR_EN BIT(28) -#define K8_NBSH_MISCV BIT(27) -#define K8_NBSH_VALID_ERROR_ADDR BIT(26) -#define K8_NBSH_PCC BIT(25) -#define K8_NBSH_ERR_CPU_VAL BIT(24) -#define K8_NBSH_CECC BIT(14) -#define K8_NBSH_UECC BIT(13) -#define K8_NBSH_ERR_SCRUBER BIT(8) +/* +* F3x4C bits (MCi_STATUS' high half) +*/ +#define NBSH_VALID_ERROR_ADDR BIT(26) +#define NBSH_ERR_CPU_VAL BIT(24)enum tt_ids {TT_INSTR =0 ,
Signature · 1 line
1.7.4.rc2
PATCH 15/30 amd64_edac: Cleanup old defines cruft
In reply to Borislav PetkovFrom: Borislav Petkov <[email protected]>
Remove unused defines, drop family names from define names.
--- drivers/edac/amd64_edac.c | 26 ++++++++-------- drivers/edac/amd64_edac.h | 72 +++++--------------------------------------- 2 files changed, 22 insertions(+), 76 deletions(-)
drivers/edac/amd64_edac.c +13 -13
@@ -229,7 +229,7 @@ static int __amd64_set_scrub_rate(struct pci_dev *ctl, u32 new_bw, u32 min_rate) scrubval = scrubrates[i].scrubval; -pci_write_bits32 (ctl,K8_SCRCTRL , scrubval,0x001F ); +pci_write_bits32 (ctl,SCRCTRL , scrubval,0x001F );if (scrubval)return scrubrates[i].bandwidth;
@@ -250,7 +250,7 @@ static int amd64_get_scrub_rate(struct mem_ctl_info *mci)u32 scrubval =0 ;int i, retval = -EINVAL ; -amd64_read_pci_cfg (pvt->F3,K8_SCRCTRL , &scrubval); +amd64_read_pci_cfg (pvt->F3,SCRCTRL , &scrubval); scrubval = scrubval &0x001F ;
@@ -843,11 +843,11 @@ static void dump_misc_regs(struct amd64_pvt *pvt)debugf1 ("F3xE8 (NB Cap): 0x%08x\n" , pvt->nbcap);debugf1 (" NB two channel DRAM capable: %s\n" , - (pvt->nbcap &K8_NBCAP_DCT_DUAL ) ?"yes" :"no" ); + (pvt->nbcap &NBCAP_DCT_DUAL ) ?"yes" :"no" );debugf1 (" ECC capable: %s, ChipKill ECC capable: %s\n" , - (pvt->nbcap &K8_NBCAP_SECDED ) ?"yes" :"no" , - (pvt->nbcap &K8_NBCAP_CHIPKILL ) ?"yes" :"no" ); + (pvt->nbcap &NBCAP_SECDED ) ?"yes" :"no" , + (pvt->nbcap &NBCAP_CHIPKILL ) ?"yes" :"no" );amd64_dump_dramcfg_low (pvt->dclr0,0 );
@@ -1814,7 +1814,7 @@ static inline void __amd64_decode_bus_error(struct mem_ctl_info *mci,int ecc_type = (info->nbsh >>13 ) &0x3 ;/* Bail early out if this was an 'observed' error */ -if (PP (ec) ==K8_NBSL_PP_OBS ) +if (PP (ec) ==NBSL_PP_OBS )return ;/* Do only ECC errors */
@@ -1906,7 +1906,7 @@ static void read_mc_regs(struct amd64_pvt *pvt) }else debugf0 (" TOP_MEM2 disabled.\n" ); -amd64_read_pci_cfg (pvt->F3,K8_NBCAP , &pvt->nbcap); +amd64_read_pci_cfg (pvt->F3,NBCAP , &pvt->nbcap);if (pvt->ops->read_dram_ctl_register) pvt->ops->read_dram_ctl_register (pvt);
@@ -2126,7 +2126,7 @@ static bool amd64_nb_mce_bank_enabled_on_node(int nid)for_each_cpu (cpu, mask) {struct msr *reg =per_cpu_ptr (msrs, cpu); - nbe = reg->l &K8_MSR_MCGCTL_NBE ; + nbe = reg->l &MSR_MCGCTL_NBE ; debugf0("core: %u, MCG_CTL: 0x%llx, NB MSR is %s\n", cpu, reg->q,
@@ -2161,16 +2161,16 @@ static int toggle_ecc_err_reporting(struct ecc_settings *s, u8 nid, bool on)struct msr *reg =per_cpu_ptr (msrs, cpu);if (on) { -if (reg->l &K8_MSR_MCGCTL_NBE ) +if (reg->l &MSR_MCGCTL_NBE ) s->flags.nb_mce_enable =1 ; - reg->l |=K8_MSR_MCGCTL_NBE ; + reg->l |=MSR_MCGCTL_NBE ; }else {/* * Turn off NB MCE reporting only when it was off before */ if (!s->flags.nb_mce_enable) - reg->l &= ~K8_MSR_MCGCTL_NBE ; + reg->l &= ~MSR_MCGCTL_NBE ; } }wrmsr_on_cpus (cmask,MSR_IA32_MCG_CTL , msrs);
@@ -2324,10 +2324,10 @@ static void setup_mci_misc_attrs(struct mem_ctl_info *mci) mci->mtype_cap =MEM_FLAG_DDR2 |MEM_FLAG_RDDR2 ; mci->edac_ctl_cap =EDAC_FLAG_NONE ; -if (pvt->nbcap &K8_NBCAP_SECDED ) +if (pvt->nbcap &NBCAP_SECDED ) mci->edac_ctl_cap |=EDAC_FLAG_SECDED ; -if (pvt->nbcap &K8_NBCAP_CHIPKILL ) +if (pvt->nbcap &NBCAP_CHIPKILL ) mci->edac_ctl_cap |=EDAC_FLAG_S4ECD4ED ; mci->edac_cap =amd64_determine_edac_cap (pvt);
drivers/edac/amd64_edac.h +9 -63
102 lines not on this page · raw message
Signature · 1 line
1.7.4.rc2
PATCH 16/30 amd64_edac: Adjust channel counting to F15h
In reply to Borislav PetkovFrom: Borislav Petkov <[email protected]>
The only difference is that F10h used to sport ganged DCTs and F15h doesn't so adjust the F10h routine and reuse it.
--- drivers/edac/amd64_edac.c | 13 ++++++------- 1 files changed, 6 insertions(+), 7 deletions(-)
drivers/edac/amd64_edac.c +6 -7
@@ -1082,15 +1082,13 @@ static int k8_dbam_to_chip_select(struct amd64_pvt *pvt, int cs_mode)* Pass back: * contents of the DCL0_LOW register */ -static int f10_early_channel_count (struct amd64_pvt *pvt) +static int f1x_early_channel_count (struct amd64_pvt *pvt) {int i, j, channels =0 ; -/* If we are in 128 bit mode, then we are using 2 channels */ -if (pvt->dclr0 &F10_WIDTH_128 ) { - channels =2 ; -return channels; - } +/* On F10h, if we are in 128 bit mode, then we are using 2 channels */ +if (boot_cpu_data.x86 ==0x10 && (pvt->dclr0 &F10_WIDTH_128 )) +return 2 ;/* * Need to check if in unganged mode: In such, there are 2 channels,
@@ -1540,7 +1538,7 @@ static struct amd64_family_type amd64_family_types[] = { .f1_id = PCI_DEVICE_ID_AMD_10H_NB_MAP, .f3_id = PCI_DEVICE_ID_AMD_10H_NB_MISC, .ops = { - .early_channel_count = f10_early_channel_count, + .early_channel_count = f1x_early_channel_count, .get_error_address = f10_get_error_address, .read_dram_ctl_register = f10_read_dram_ctl_register, .map_sysaddr_to_csrow = f10_map_sysaddr_to_csrow,
@@ -1551,6 +1549,7 @@ static struct amd64_family_type amd64_family_types[] = { [F15_CPUS] = { .ctl_name = "F15h", .ops = { + .early_channel_count = f1x_early_channel_count, .read_dct_pci_cfg = f15_read_dct_pci_cfg, } },
Signature · 1 line
1.7.4.rc2
PATCH 17/30 amd64_edac: Simplify decoding path
In reply to Borislav PetkovFrom: Borislav Petkov <[email protected]>
Use the struct mce directly instead of copying from it into a custom struct err_regs.
No functionality change.
--- drivers/edac/amd64_edac.c | 76 ++++++++++++++++----------------------------- drivers/edac/amd64_edac.h | 12 +++++-- drivers/edac/mce_amd.h | 12 ------- 3 files changed, 35 insertions(+), 65 deletions(-)
drivers/edac/amd64_edac.c +27 -49
@@ -788,11 +788,6 @@ static int sys_addr_to_csrow(struct mem_ctl_info *mci, u64 sys_addr)static int get_channel_from_ecc_syndrome (struct mem_ctl_info *,u16 ); -static u16 extract_syndrome (struct err_regs *err) -{ -return ((err->nbsh >>15 ) &0xff ) | ((err->nbsl >>16 ) &0xff00 ); -} -/* * Determine if the DIMMs have ECC enabled. ECC is enabled ONLY if all the DIMMs * are ECC capable.
@@ -975,12 +970,10 @@ static int k8_early_channel_count(struct amd64_pvt *pvt)return (flag) ?2 :1 ; } -/* Extract the ERROR ADDRESS for the K8 CPUs */ -static u64 k8_get_error_address (struct mem_ctl_info *mci, -struct err_regs *info) +static u64 k8_get_error_address (struct mem_ctl_info *mci,struct mce *m) { -return (((u64) (info->nbeah &0xff )) <<32 ) + - (info->nbeal & ~0x03 ); +/* ErrAddr[39:3] */ +return m->addr &GENMASK (3 ,39 ); }static void read_dram_base_limit_regs (struct amd64_pvt *pvt,unsigned range)
@@ -1000,18 +993,16 @@ static void read_dram_base_limit_regs(struct amd64_pvt *pvt, unsigned range)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, -struct err_regs *err_info,u64 sys_addr) +static void k8_map_sysaddr_to_csrow (struct mem_ctl_info *mci,u64 sys_addr, +u16 syndrome) {struct mem_ctl_info *src_mci; +struct amd64_pvt *pvt = mci->pvt_info;int channel, csrow;u32 page, offset; -u16 syndrome; - - syndrome =extract_syndrome (err_info);/* CHIPKILL enabled */ -if (err_info->nbcfg &NBCFG_CHIPKILL ) { +if (pvt->nbcfg &NBCFG_CHIPKILL ) { channel =get_channel_from_ecc_syndrome (mci, syndrome);if (channel <0 ) {/*
@@ -1136,11 +1127,9 @@ static int f10_dbam_to_chip_select(struct amd64_pvt *pvt, int cs_mode)return dbam_map[cs_mode]; } -static u64 f10_get_error_address (struct mem_ctl_info *mci, -struct err_regs *info) +static u64 f10_get_error_address (struct mem_ctl_info *mci,struct mce *m) { -return (((u64) (info->nbeah &0xffff )) <<32 ) + - (info->nbeal & ~0x01 ); +return m->addr &GENMASK (1 ,47 ); }static void f10_read_dram_ctl_register (struct amd64_pvt *pvt)
@@ -1434,14 +1423,12 @@ static int f10_translate_sysaddr_to_cs(struct amd64_pvt *pvt, u64 sys_addr,* The @sys_addr is usually an error address received from the hardware * (MCX_ADDR). */ -static void f10_map_sysaddr_to_csrow (struct mem_ctl_info *mci, -struct err_regs *err_info, -u64 sys_addr) +static void f10_map_sysaddr_to_csrow (struct mem_ctl_info *mci,u64 sys_addr, +u16 syndrome) {struct amd64_pvt *pvt = mci->pvt_info;u32 page, offset;int nid, csrow, chan =0 ; -u16 syndrome; csrow =f10_translate_sysaddr_to_cs (pvt, sys_addr, &nid, &chan);
@@ -1452,8 +1439,6 @@ static void f10_map_sysaddr_to_csrow(struct mem_ctl_info *mci,error_address_to_page_and_offset (sys_addr, &page, &offset); - syndrome =extract_syndrome (err_info); -/* * We need the syndromes for channel detection only when we're * ganged. Otherwise @chan should already contain the channel at
@@ -1740,29 +1725,29 @@ static int get_channel_from_ecc_syndrome(struct mem_ctl_info *mci, u16 syndrome)* Handle any Correctable Errors (CEs) that have occurred. Check for valid ERROR * ADDRESS and process. */ -static void amd64_handle_ce (struct mem_ctl_info *mci, -struct err_regs *info) +static void amd64_handle_ce (struct mem_ctl_info *mci,struct mce *m) {struct amd64_pvt *pvt = mci->pvt_info;u64 sys_addr; +u16 syndrome;/* Ensure that the Error Address is VALID */ -if (!(info->nbsh &NBSH_VALID_ERROR_ADDR )) { +if (!(m->status &MCI_STATUS_ADDRV )) {amd64_mc_err (mci,"HW has no ERROR_ADDRESS available\n" );edac_mc_handle_ce_no_info (mci,EDAC_MOD_STR );return ; } - sys_addr = pvt->ops->get_error_address (mci, info); + sys_addr = pvt->ops->get_error_address (mci, m); + syndrome =extract_syndrome (m->status);amd64_mc_err (mci,"CE ERROR_ADDRESS= 0x%llx\n" , sys_addr); - pvt->ops->map_sysaddr_to_csrow (mci, info, sys_addr); + pvt->ops->map_sysaddr_to_csrow (mci, sys_addr, syndrome); }/* Handle any Un-correctable Errors (UEs) */ -static void amd64_handle_ue (struct mem_ctl_info *mci, -struct err_regs *info) +static void amd64_handle_ue (struct mem_ctl_info *mci,struct mce *m) {struct amd64_pvt *pvt = mci->pvt_info;struct mem_ctl_info *log_mci, *src_mci =NULL ;
@@ -1772,13 +1757,13 @@ static void amd64_handle_ue(struct mem_ctl_info *mci, log_mci = mci; -if (!(info->nbsh &NBSH_VALID_ERROR_ADDR )) { +if (!(m->status &MCI_STATUS_ADDRV )) {amd64_mc_err (mci,"HW has no ERROR_ADDRESS available\n" );edac_mc_handle_ue_no_info (log_mci,EDAC_MOD_STR );return ; } - sys_addr = pvt->ops->get_error_address (mci, info); + sys_addr = pvt->ops->get_error_address (mci, m);/* * Find out which node the error address belongs to. This may be
@@ -1806,11 +1791,11 @@ static void amd64_handle_ue(struct mem_ctl_info *mci, }static inline void __amd64_decode_bus_error (struct mem_ctl_info *mci, -struct err_regs *info) +struct mce *m) { -u16 ec =EC (info->nbsl); -u8 xec =XEC (info->nbsl,0x1f ); -int ecc_type = (info->nbsh >>13 ) &0x3 ; +u16 ec =EC (m->status); +u8 xec =XEC (m->status,0x1f ); +u8 ecc_type = (m->status >>45 ) &0x3 ;/* Bail early out if this was an 'observed' error */ if (PP (ec) ==NBSL_PP_OBS )
@@ -1821,23 +1806,16 @@ static inline void __amd64_decode_bus_error(struct mem_ctl_info *mci,return ;if (ecc_type ==2 ) -amd64_handle_ce (mci, info); +amd64_handle_ce (mci, m);else if (ecc_type ==1 ) -amd64_handle_ue (mci, info); +amd64_handle_ue (mci, m); }void amd64_decode_bus_error (int node_id,struct mce *m,u32 nbcfg) {struct mem_ctl_info *mci = mcis[node_id]; -struct err_regs regs; - - regs.nbsl = (u32 ) m->status; - regs.nbsh = (u32)(m->status >>32 ); - regs.nbeal = (u32 ) m->addr; - regs.nbeah = (u32)(m->addr >>32 ); - regs.nbcfg = nbcfg; -__amd64_decode_bus_error (mci, ®s); +__amd64_decode_bus_error (mci, m); }/*
drivers/edac/amd64_edac.h +8 -4
@@ -397,6 +397,11 @@ static inline u64 get_dram_limit(struct amd64_pvt *pvt, unsigned i)return (((u64 )pvt->ranges[i].lim.hi &0x000000ff ) <<40 ) | lim; } +static inline u16 extract_syndrome (u64 status) +{ +return ((status >>47 ) &0xff ) | ((status >>16 ) &0xff00 ); +} +/* * per-node ECC settings descriptor */
@@ -440,11 +445,10 @@ extern struct mcidev_sysfs_attribute amd64_dbg_attrs[NUM_DBG_ATTRS],struct low_ops {int (*early_channel_count) (struct amd64_pvt *pvt); -u64 (*get_error_address) (struct mem_ctl_info *mci, -struct err_regs *info); +u64 (*get_error_address) (struct mem_ctl_info *mci,struct mce *m);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); +void (*map_sysaddr_to_csrow) (struct mem_ctl_info *mci,u64 sys_addr, +u16 syndrome);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);
drivers/edac/mce_amd.h +0 -12
@@ -34,7 +34,6 @@/* * F3x4C bits (MCi_STATUS' high half) */ -#define NBSH_VALID_ERROR_ADDR BIT(26)#define NBSH_ERR_CPU_VAL BIT(24)enum tt_ids {
@@ -78,17 +77,6 @@ extern const char *to_msgs[];extern const char *ii_msgs[];/* -* relevant NB regs -*/ -struct err_regs { -u32 nbcfg; -u32 nbsh; -u32 nbsl; -u32 nbeah; -u32 nbeal; -}; - -/* * per-family decoder ops */ struct amd_decoder_ops {
Signature · 1 line
1.7.4.rc2
PATCH 18/30 amd64_edac: Unify get_error_address
In reply to Borislav PetkovFrom: Borislav Petkov <[email protected]>
The address bits from MC4_STATUS differ only between K8 and the rest so no need for a per-family method.
No functional change.
--- drivers/edac/amd64_edac.c | 26 +++++++++++++------------- drivers/edac/amd64_edac.h | 2 -- 2 files changed, 13 insertions(+), 15 deletions(-)
drivers/edac/amd64_edac.c +13 -13
@@ -970,10 +970,18 @@ static int k8_early_channel_count(struct amd64_pvt *pvt)return (flag) ?2 :1 ; } -static u64 k8_get_error_address (struct mem_ctl_info *mci,struct mce *m) +/* On F10h and later ErrAddr is MC4_ADDR[47:1] */ +static u64 get_error_address (struct mce *m) { -/* ErrAddr[39:3] */ -return m->addr &GENMASK (3 ,39 ); +u8 start_bit =1 ; +u8 end_bit =47 ; + +if (boot_cpu_data.x86 ==0xf ) { + start_bit =3 ; + end_bit =39 ; + } + +return m->addr &GENMASK (start_bit, end_bit); }static void read_dram_base_limit_regs (struct amd64_pvt *pvt,unsigned range)
@@ -1127,11 +1135,6 @@ static int f10_dbam_to_chip_select(struct amd64_pvt *pvt, int cs_mode)return dbam_map[cs_mode]; } -static u64 f10_get_error_address (struct mem_ctl_info *mci,struct mce *m) -{ -return m->addr &GENMASK (1 ,47 ); -} -static void f10_read_dram_ctl_register (struct amd64_pvt *pvt) {
@@ -1512,7 +1515,6 @@ static struct amd64_family_type amd64_family_types[] = { .f3_id = PCI_DEVICE_ID_AMD_K8_NB_MISC, .ops = { .early_channel_count = k8_early_channel_count, - .get_error_address = k8_get_error_address, .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,
@@ -1524,7 +1526,6 @@ static struct amd64_family_type amd64_family_types[] = { .f3_id = PCI_DEVICE_ID_AMD_10H_NB_MISC, .ops = { .early_channel_count = f1x_early_channel_count, - .get_error_address = f10_get_error_address, .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,
@@ -1738,7 +1739,7 @@ static void amd64_handle_ce(struct mem_ctl_info *mci, struct mce *m)return ; } - sys_addr = pvt->ops->get_error_address (mci, m); + sys_addr =get_error_address (m); syndrome =extract_syndrome (m->status);amd64_mc_err (mci,"CE ERROR_ADDRESS= 0x%llx\n" , sys_addr);
@@ -1749,7 +1750,6 @@ static void amd64_handle_ce(struct mem_ctl_info *mci, struct mce *m)/* Handle any Un-correctable Errors (UEs) */ static void amd64_handle_ue (struct mem_ctl_info *mci,struct mce *m) { -struct amd64_pvt *pvt = mci->pvt_info;struct mem_ctl_info *log_mci, *src_mci =NULL ;int csrow;u64 sys_addr;
@@ -1763,7 +1763,7 @@ static void amd64_handle_ue(struct mem_ctl_info *mci, struct mce *m)return ; } - sys_addr = pvt->ops->get_error_address (mci, m); + sys_addr =get_error_address (m);/* * Find out which node the error address belongs to. This may be
drivers/edac/amd64_edac.h +0 -2
@@ -444,8 +444,6 @@ extern struct mcidev_sysfs_attribute amd64_dbg_attrs[NUM_DBG_ATTRS],*/ struct low_ops {int (*early_channel_count) (struct amd64_pvt *pvt); - -u64 (*get_error_address) (struct mem_ctl_info *mci,struct mce *m);void (*read_dram_ctl_register) (struct amd64_pvt *pvt);void (*map_sysaddr_to_csrow) (struct mem_ctl_info *mci,u64 sys_addr,u16 syndrome);
Signature · 1 line
1.7.4.rc2
PATCH 19/30 amd64_edac: Add support for interleaved region swapping
In reply to Borislav PetkovFrom: Borislav Petkov <[email protected]>
On revC3 and revE Fam10h machines and later, non-interleaved graphics framebuffer memory under the 16G mark can be swapped with a region located at the bottom of memory so that the GPU can use the interleaved region and thus two channels. Add support for that.
--- drivers/edac/amd64_edac.c | 38 ++++++++++++++++++++++++++++++++++++++ drivers/edac/amd64_edac.h | 2 ++ 2 files changed, 40 insertions(+), 0 deletions(-)
drivers/edac/amd64_edac.c +38 -0
@@ -1331,6 +1331,42 @@ static int f10_lookup_addr_in_dct(u64 in_addr, u32 nid, u8 dct)return cs_found; } +/* +* See F2x10C. Non-interleaved graphics framebuffer memory under the 16G is +* swapped with a region located at the bottom of memory so that the GPU can use +* the interleaved region and thus two channels. +*/ +static u64 f10_swap_interleaved_region (struct amd64_pvt *pvt,u64 sys_addr) +{ +u32 swap_reg, swap_base, swap_limit, rgn_size, tmp_addr; + +if (boot_cpu_data.x86 ==0x10 ) { +/* only revC3 and revE have that feature */ +if (boot_cpu_data.x86_model <4 || + (boot_cpu_data.x86_model <0xa && + boot_cpu_data.x86_mask <3 )) +return sys_addr; + } + +amd64_read_dct_pci_cfg (pvt,SWAP_INTLV_REG , &swap_reg); + +if (!(swap_reg &0x1 )) +return sys_addr; + + swap_base = (swap_reg >>3 ) &0x7f ; + swap_limit = (swap_reg >>11 ) &0x7f ; + rgn_size = (swap_reg >>20 ) &0x7f ; + tmp_addr = sys_addr >>27 ; + +if (!(sys_addr >>34 ) && + (((tmp_addr >= swap_base) && + (tmp_addr <= swap_limit)) || + (tmp_addr < rgn_size))) +return sys_addr ^ (u64 )swap_base <<27 ; + +return sys_addr; +} +/* For a given @dram_range, check if @sys_addr falls within it. */ static int f10_match_to_this_node (struct amd64_pvt *pvt,int range,u64 sys_addr,int *nid,int *chan_sel)
@@ -1352,6 +1388,8 @@ static int f10_match_to_this_node(struct amd64_pvt *pvt, int range, (intlv_sel != ((sys_addr >> 12) & intlv_en)))return -EINVAL ; + sys_addr =f10_swap_interleaved_region (pvt, sys_addr); + dct_sel_base =dct_sel_baseaddr (pvt);/*
drivers/edac/amd64_edac.h +2 -0
@@ -239,6 +239,8 @@#define dct_dram_enabled (pvt) ((pvt)->dct_sel_lo & BIT(8))#define dct_memory_cleared (pvt) ((pvt)->dct_sel_lo & BIT(10)) +#define SWAP_INTLV_REG 0x10c +#define DCT_SEL_HI 0x114/*
Signature · 1 line
1.7.4.rc2
PATCH 20/30 amd64_edac: Correct node interleaving removal
In reply to Borislav PetkovFrom: Borislav Petkov <[email protected]>
When node interleaving is enabled, a subset of the addr[14:12] bits has to be removed in order to get the normalized DCT address of the DRAM channel. The actual number of bits to remove is determined by F1x[1, 0][7C:40][IntlvEn]. Do this correctly.
--- drivers/edac/amd64_edac.c | 8 ++++---- 1 files changed, 4 insertions(+), 4 deletions(-)
drivers/edac/amd64_edac.c +4 -4
@@ -1406,10 +1406,10 @@ static int f10_match_to_this_node(struct amd64_pvt *pvt, int range, chan_addr =f10_get_norm_dct_addr (pvt, range, sys_addr, high_range, dct_sel_base); -/* remove Node ID (in case of node interleaving) */ - tmp = chan_addr &0xFC0 ; - - chan_addr = ((chan_addr >>hweight8 (intlv_en)) &GENMASK (12 ,47 )) | tmp; +/* Remove node interleaving, see F1x120 */ +if (intlv_en) + chan_addr = ((chan_addr >> (12 +hweight8 (intlv_en))) <<12 ) | + (chan_addr &0xfff );/* remove channel interleave and hash */ if (dct_interleave_enabled(pvt) &&
Signature · 1 line
1.7.4.rc2
PATCH 21/30 amd64_edac: Fix channel interleave removal
In reply to Borislav PetkovFrom: Borislav Petkov <[email protected]>
Remove the channel interleave select bit properly. See F2x110[DctSelIntLvAddr] for details.
--- drivers/edac/amd64_edac.c | 26 +++++++++++++++++--------- 1 files changed, 17 insertions(+), 9 deletions(-)
drivers/edac/amd64_edac.c +17 -9
@@ -1373,7 +1373,7 @@ static int f10_match_to_this_node(struct amd64_pvt *pvt, int range, {int cs_found = -EINVAL ;u64 chan_addr; -u32 tmp, dct_sel_base; +u32 dct_sel_base;u8 channel;bool high_range = false;
@@ -1411,19 +1411,27 @@ static int f10_match_to_this_node(struct amd64_pvt *pvt, int range, chan_addr = ((chan_addr >> (12 +hweight8 (intlv_en))) <<12 ) | (chan_addr &0xfff ); -/* remove channel interleave and hash */ +/* remove channel interleave */ if (dct_interleave_enabled (pvt) && !dct_high_range_enabled (pvt) && !dct_ganging_enabled (pvt)) { -if (dct_sel_interleave_addr (pvt) !=1 ) - chan_addr = (chan_addr >>1 ) &GENMASK (6 ,63 ); -else { - tmp = chan_addr &0xFC0 ; - chan_addr = ((chan_addr &GENMASK (14 ,63 )) >>1 ) | tmp; - } + +if (dct_sel_interleave_addr (pvt) !=1 ) { +if (dct_sel_interleave_addr (pvt) ==0x3 ) +/* hash 9 */ + chan_addr = ((chan_addr >>10 ) <<9 ) | + (chan_addr &0x1ff ); +else +/* A[6] or hash 6 */ + chan_addr = ((chan_addr >>7 ) <<6 ) | + (chan_addr &0x3f ); + }else +/* A[12] */ + chan_addr = ((chan_addr >>13 ) <<12 ) | + (chan_addr &0xfff ); } -debugf1 (" (ChannelAddrLong=0x%llx)\n" , chan_addr); +debugf1 (" Normalized DCT addr: 0x%llx\n" , chan_addr); cs_found =f10_lookup_addr_in_dct (chan_addr, node_id, channel);
Signature · 1 line
1.7.4.rc2
PATCH 22/30 amd64_edac: Revamp online spare handling
In reply to Borislav PetkovFrom: Borislav Petkov <[email protected]>
Replace per-DCT macros with smarter ones, drop hack and look for the spare rank on all chip selects on a channel.
--- drivers/edac/amd64_edac.c | 32 ++++++++++++++------------------ drivers/edac/amd64_edac.h | 6 ++---- 2 files changed, 16 insertions(+), 22 deletions(-)
drivers/edac/amd64_edac.c +13 -17
@@ -393,6 +393,9 @@ static void get_cs_base_and_mask(struct amd64_pvt *pvt, int csrow, u8 dct,#define for_each_chip_select (i, dct, pvt) \ for (i = 0; i < pvt->csels[dct].b_cnt; i++) +#define chip_select_base (i, dct, pvt) \ + pvt->csels[dct].csbases[i] +#define for_each_chip_select_mask (i, dct, pvt) \ for (i = 0; i < pvt->csels[dct].m_cnt; i++)
@@ -1254,30 +1257,23 @@ static u64 f10_get_norm_dct_addr(struct amd64_pvt *pvt, int range,return (sys_addr &GENMASK (6 ,47 )) - (chan_off &GENMASK (23 ,47 )); } -/* Hack for the time being - Can we get this from BIOS?? */ -#define CH0SPARE_RANK 0 -#define CH1SPARE_RANK 1 -/* * checks if the csrow passed in is marked as SPARED, if so returns the new * spare row */ static int f10_process_possible_spare (struct amd64_pvt *pvt,u8 dct,int csrow) { -u32 swap_done; -u32 bad_dram_cs; +int tmp_cs; -/* Depending on channel, isolate respective SPARING info */ -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)) - csrow =CH1SPARE_RANK ; - }else { - swap_done =F10_ONLINE_SPARE_SWAPDONE0 (pvt->online_spare); - bad_dram_cs =F10_ONLINE_SPARE_BADDRAM_CS0 (pvt->online_spare); -if (swap_done && (csrow == bad_dram_cs)) - csrow =CH0SPARE_RANK ; +if (online_spare_swap_done (pvt, dct) && + csrow ==online_spare_bad_dramcs (pvt, dct)) { + +for_each_chip_select (tmp_cs, dct, pvt) { +if (chip_select_base (tmp_cs, dct, pvt) &0x2 ) { + csrow = tmp_cs; +break ; + } + } }return csrow; }
drivers/edac/amd64_edac.h +2 -4
@@ -259,10 +259,8 @@#define SCRCTRL 0x58#define F10_ONLINE_SPARE 0xB0 -#define F10_ONLINE_SPARE_SWAPDONE0 (x) ((x) & BIT(1)) -#define F10_ONLINE_SPARE_SWAPDONE1 (x) ((x) & BIT(3)) -#define F10_ONLINE_SPARE_BADDRAM_CS0 (x) (((x) >> 4) & 0x00000007) -#define F10_ONLINE_SPARE_BADDRAM_CS1 (x) (((x) >> 8) & 0x00000007) +#define online_spare_swap_done (pvt, c) (((pvt)->online_spare >> (1 + 2 * (c))) & 0x1) +#define online_spare_bad_dramcs (pvt, c) (((pvt)->online_spare >> (4 + 4 * (c))) & 0x7)#define F10_NB_ARRAY_ADDR 0xB8#define F10_NB_ARRAY_DRAM_ECC BIT(31)
Signature · 1 line
1.7.4.rc2
PATCH 23/30 amd64_edac: Beef up early exit reporting
In reply to Borislav PetkovFrom: Borislav Petkov <[email protected]>
Add paranoid checks for the sys address before going off and decoding it.
--- drivers/edac/amd64_edac.c | 13 ++++++++++++- 1 files changed, 12 insertions(+), 1 deletions(-)
drivers/edac/amd64_edac.c +12 -1
@@ -1380,9 +1380,20 @@ static int f10_match_to_this_node(struct amd64_pvt *pvt, int range,debugf1 ("(range %d) SystemAddr= 0x%llx Limit=0x%llx\n" , range, sys_addr,get_dram_limit (pvt, range)); +if (dhar_valid (pvt) && +dhar_base (pvt) <= sys_addr && + sys_addr <BIT_64 (32 )) { +amd64_warn ("Huh? Address is in the MMIO hole: 0x%016llx\n" , + sys_addr); +return -EINVAL ; + } +if (intlv_en && - (intlv_sel != ((sys_addr >>12 ) & intlv_en))) + (intlv_sel != ((sys_addr >>12 ) & intlv_en))) { +amd64_warn ("Botched intlv bits, en: 0x%x, sel: 0x%x\n" , + intlv_en, intlv_sel);return -EINVAL ; + } sys_addr =f10_swap_interleaved_region (pvt, sys_addr);
Signature · 1 line
1.7.4.rc2
PATCH 24/30 amd64_edac: Adjust sys_addr to chip select conversion routine to F15h
In reply to Borislav PetkovFrom: Borislav Petkov <[email protected]>
F15h sys_addr to chip select mapping is almost identical to F10h's so reuse that. Rename functions on that path accordingly.
--- drivers/edac/amd64_edac.c | 29 +++++++++++++++-------------- 1 files changed, 15 insertions(+), 14 deletions(-)
drivers/edac/amd64_edac.c +15 -14
@@ -1171,7 +1171,7 @@ static void f10_read_dram_ctl_register(struct amd64_pvt *pvt)* Determine channel (DCT) based on the interleaving mode: F10h BKDG, 2.8.9 Memory * Interleaving Modes. */ -static u8 f10_determine_channel (struct amd64_pvt *pvt,u64 sys_addr, +static u8 f1x_determine_channel (struct amd64_pvt *pvt,u64 sys_addr,bool hi_range_sel,u8 intlv_en) {u32 dct_sel_high = (pvt->dct_sel_lo >>1 ) &1 ;
@@ -1209,7 +1209,7 @@ static u8 f10_determine_channel(struct amd64_pvt *pvt, u64 sys_addr, }/* Convert the sys_addr to the normalized DCT address */ -static u64 f10_get_norm_dct_addr (struct amd64_pvt *pvt,int range, +static u64 f1x_get_norm_dct_addr (struct amd64_pvt *pvt,int range,u64 sys_addr,bool hi_rng,u32 dct_sel_base_addr) {
@@ -1286,7 +1286,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 f10_lookup_addr_in_dct (u64 in_addr,u32 nid,u8 dct) +static int f1x_lookup_addr_in_dct (u64 in_addr,u32 nid,u8 dct) {struct mem_ctl_info *mci;struct amd64_pvt *pvt;
@@ -1332,7 +1332,7 @@ static int f10_lookup_addr_in_dct(u64 in_addr, u32 nid, u8 dct)* swapped with a region located at the bottom of memory so that the GPU can use * the interleaved region and thus two channels. */ -static u64 f10_swap_interleaved_region (struct amd64_pvt *pvt,u64 sys_addr) +static u64 f1x_swap_interleaved_region (struct amd64_pvt *pvt,u64 sys_addr) {u32 swap_reg, swap_base, swap_limit, rgn_size, tmp_addr;
@@ -1364,7 +1364,7 @@ static u64 f10_swap_interleaved_region(struct amd64_pvt *pvt, u64 sys_addr) }/* For a given @dram_range, check if @sys_addr falls within it. */ -static int f10_match_to_this_node (struct amd64_pvt *pvt,int range, +static int f1x_match_to_this_node (struct amd64_pvt *pvt,int range,u64 sys_addr,int *nid,int *chan_sel) {int cs_found = -EINVAL ;
@@ -1395,7 +1395,7 @@ static int f10_match_to_this_node(struct amd64_pvt *pvt, int range,return -EINVAL ; } - sys_addr =f10_swap_interleaved_region (pvt, sys_addr); + sys_addr =f1x_swap_interleaved_region (pvt, sys_addr); dct_sel_base =dct_sel_baseaddr (pvt);
@@ -1408,9 +1408,9 @@ static int f10_match_to_this_node(struct amd64_pvt *pvt, int range, ((sys_addr >> 27) >= (dct_sel_base >> 11))) high_range = true; - channel =f10_determine_channel (pvt, sys_addr, high_range, intlv_en); + channel =f1x_determine_channel (pvt, sys_addr, high_range, intlv_en); - chan_addr =f10_get_norm_dct_addr (pvt, range, sys_addr, + chan_addr =f1x_get_norm_dct_addr (pvt, range, sys_addr, high_range, dct_sel_base);/* Remove node interleaving, see F1x120 */
@@ -1440,7 +1440,7 @@ static int f10_match_to_this_node(struct amd64_pvt *pvt, int range,debugf1 (" Normalized DCT addr: 0x%llx\n" , chan_addr); - cs_found =f10_lookup_addr_in_dct (chan_addr, node_id, channel); + cs_found =f1x_lookup_addr_in_dct (chan_addr, node_id, channel);if (cs_found >=0 ) { *nid = node_id;
@@ -1449,7 +1449,7 @@ static int f10_match_to_this_node(struct amd64_pvt *pvt, int range,return cs_found; } -static int f10_translate_sysaddr_to_cs (struct amd64_pvt *pvt,u64 sys_addr, +static int f1x_translate_sysaddr_to_cs (struct amd64_pvt *pvt,u64 sys_addr,int *node,int *chan_sel) {int range, cs_found = -EINVAL ;
@@ -1462,7 +1462,7 @@ static int f10_translate_sysaddr_to_cs(struct amd64_pvt *pvt, u64 sys_addr,if ((get_dram_base (pvt, range) <= sys_addr) && (get_dram_limit (pvt, range) >= sys_addr)) { - cs_found =f10_match_to_this_node (pvt, range, + cs_found =f1x_match_to_this_node (pvt, range, sys_addr, node, chan_sel);if (cs_found >=0 )
@@ -1479,14 +1479,14 @@ static int f10_translate_sysaddr_to_cs(struct amd64_pvt *pvt, u64 sys_addr,* The @sys_addr is usually an error address received from the hardware * (MCX_ADDR). */ -static void f10_map_sysaddr_to_csrow (struct mem_ctl_info *mci,u64 sys_addr, +static void f1x_map_sysaddr_to_csrow (struct mem_ctl_info *mci,u64 sys_addr,u16 syndrome) {struct amd64_pvt *pvt = mci->pvt_info;u32 page, offset;int nid, csrow, chan =0 ; - csrow =f10_translate_sysaddr_to_cs (pvt, sys_addr, &nid, &chan); + csrow =f1x_translate_sysaddr_to_cs (pvt, sys_addr, &nid, &chan);if (csrow <0 ) {edac_mc_handle_ce_no_info (mci,EDAC_MOD_STR );
@@ -1580,7 +1580,7 @@ static struct amd64_family_type amd64_family_types[] = { .ops = { .early_channel_count = f1x_early_channel_count, .read_dram_ctl_register = f10_read_dram_ctl_register, - .map_sysaddr_to_csrow = f10_map_sysaddr_to_csrow, + .map_sysaddr_to_csrow = f1x_map_sysaddr_to_csrow, .dbam_to_cs = f10_dbam_to_chip_select, .read_dct_pci_cfg = f10_read_dct_pci_cfg, }
@@ -1589,6 +1589,7 @@ static struct amd64_family_type amd64_family_types[] = { .ctl_name = "F15h", .ops = { .early_channel_count = f1x_early_channel_count, + .map_sysaddr_to_csrow = f1x_map_sysaddr_to_csrow, .read_dct_pci_cfg = f15_read_dct_pci_cfg, } },
Signature · 1 line
1.7.4.rc2
PATCH 25/30 amd64_edac: Sanitize ->read_dram_ctl_register
In reply to Borislav PetkovFrom: Borislav Petkov <[email protected]>
This function is relevant for F10h and higher, and it has only one callsite so drop its function pointer from the low_ops struct.
--- drivers/edac/amd64_edac.c | 14 +++++++------- drivers/edac/amd64_edac.h | 2 -- 2 files changed, 7 insertions(+), 9 deletions(-)
drivers/edac/amd64_edac.c +7 -7
@@ -1138,16 +1138,18 @@ static int f10_dbam_to_chip_select(struct amd64_pvt *pvt, int cs_mode)return dbam_map[cs_mode]; } -static void f10_read_dram_ctl_register (struct amd64_pvt *pvt) +static void read_dram_ctl_register (struct amd64_pvt *pvt) { +if (boot_cpu_data.x86 ==0xf ) +return ; +if (!amd64_read_dct_pci_cfg (pvt,DCT_SEL_LO , &pvt->dct_sel_lo)) {debugf0 ("F2x110 (DCTSelLow): 0x%08x, High range addrs at: 0x%x\n" , pvt->dct_sel_lo,dct_sel_baseaddr (pvt)); -debugf0 (" mode: %s, All DCTs on: %s\n" , - (dct_ganging_enabled (pvt) ?"ganged" :"unganged" ), - (dct_dram_enabled (pvt) ?"yes" :"no" )); +debugf0 (" DCTs operate in %s mode.\n" , + (dct_ganging_enabled (pvt) ?"ganged" :"unganged" ));if (!dct_ganging_enabled (pvt)) debugf0(" Address range split per DCT: %s\n",
@@ -1579,7 +1581,6 @@ static struct amd64_family_type amd64_family_types[] = { .f3_id = PCI_DEVICE_ID_AMD_10H_NB_MISC, .ops = { .early_channel_count = f1x_early_channel_count, - .read_dram_ctl_register = f10_read_dram_ctl_register, .map_sysaddr_to_csrow = f1x_map_sysaddr_to_csrow, .dbam_to_cs = f10_dbam_to_chip_select, .read_dct_pci_cfg = f10_read_dct_pci_cfg,
@@ -1939,8 +1940,7 @@ static void read_mc_regs(struct amd64_pvt *pvt)amd64_read_pci_cfg (pvt->F3,NBCAP , &pvt->nbcap); -if (pvt->ops->read_dram_ctl_register) - pvt->ops->read_dram_ctl_register (pvt); +read_dram_ctl_register (pvt);for (range =0 ; range <DRAM_RANGES ; range++) {u8 rw;
drivers/edac/amd64_edac.h +0 -2
@@ -236,7 +236,6 @@#define dct_ganging_enabled (pvt) ((boot_cpu_data.x86 == 0x10) && ((pvt)->dct_sel_lo & BIT(4)))#define dct_data_intlv_enabled (pvt) ((pvt)->dct_sel_lo & BIT(5)) -#define dct_dram_enabled (pvt) ((pvt)->dct_sel_lo & BIT(8))#define dct_memory_cleared (pvt) ((pvt)->dct_sel_lo & BIT(10))#define SWAP_INTLV_REG 0x10c
@@ -444,7 +443,6 @@ extern struct mcidev_sysfs_attribute amd64_dbg_attrs[NUM_DBG_ATTRS],*/ struct low_ops {int (*early_channel_count) (struct amd64_pvt *pvt); -void (*read_dram_ctl_register) (struct amd64_pvt *pvt);void (*map_sysaddr_to_csrow) (struct mem_ctl_info *mci,u64 sys_addr,u16 syndrome);int (*dbam_to_cs) (struct amd64_pvt *pvt,int cs_mode);
Signature · 1 line
1.7.4.rc2
PATCH 26/30 amd64_edac: Improve DRAM address mapping
In reply to Borislav PetkovFrom: Borislav Petkov <[email protected]>
Drop static tables which map the bits in F2x80 to a chip select size in favor of functions doing the mapping with some bit fiddling. Also, add F15 support.
--- drivers/edac/amd64_edac.c | 149 ++++++++++++++++++++++++-------------------- drivers/edac/amd64_edac.h | 4 +- 2 files changed, 83 insertions(+), 70 deletions(-)
drivers/edac/amd64_edac.c +81 -68
@@ -25,59 +25,12 @@ static struct mem_ctl_info **mcis;static struct ecc_settings **ecc_stngs;/* -* Address to DRAM bank mapping: see F2x80 for K8 and F2x[1,0]80 for Fam10 and -* later. -*/ -static int ddr2_dbam_revCG[] = { - [0 ] =32 , - [1 ] =64 , - [2 ] =128 , - [3 ] =256 , - [4 ] =512 , - [5 ] =1024 , - [6 ] =2048 , -}; - -static int ddr2_dbam_revD[] = { - [0 ] =32 , - [1 ] =64 , - [2 ...3 ] =128 , - [4 ] =256 , - [5 ] =512 , - [6 ] =256 , - [7 ] =512 , - [8 ...9 ] =1024 , - [10 ] =2048 , -}; - -static int ddr2_dbam[] = { [0 ] =128 , - [1 ] =256 , - [2 ...4 ] =512 , - [5 ...6 ] =1024 , - [7 ...8 ] =2048 , - [9 ...10 ] =4096 , - [11 ] =8192 , -}; - -static int ddr3_dbam[] = { [0 ] =-1 , - [1 ] =256 , - [2 ] =512 , - [3 ...4 ] =-1 , - [5 ...6 ] =1024 , - [7 ...8 ] =2048 , - [9 ...10 ] =4096 , - [11 ] =8192 , -}; - -/* * Valid scrub rates for the K8 hardware memory scrubber. We map the scrubbing * bandwidth to a valid bit pattern. The 'set' operation finds the 'matching- * or higher value'. * *FIXME: Produce a better mapping/linearisation. */ - -struct scrubrate {u32 scrubval;/* bit pattern for scrub rate */ u32 bandwidth;/* bandwidth consumed (bytes/sec) */
@@ -962,7 +915,7 @@ static int k8_early_channel_count(struct amd64_pvt *pvt)if (pvt->ext_model >=K8_REV_F )/* RevF (NPT) and later */ - flag = pvt->dclr0 &F10_WIDTH_128 ; + flag = pvt->dclr0 &WIDTH_128 ;else /* RevE and earlier */ flag = pvt->dclr0 &REVE_WIDTH_128 ;
@@ -1062,18 +1015,41 @@ static void k8_map_sysaddr_to_csrow(struct mem_ctl_info *mci, u64 sys_addr, } } -static int k8_dbam_to_chip_select (struct amd64_pvt *pvt,int cs_mode) +static int ddr2_cs_size (unsigned i,bool dct_width) { -int *dbam_map; +unsigned shift =0 ; -if (pvt->ext_model >=K8_REV_F ) - dbam_map = ddr2_dbam; -else if (pvt->ext_model >=K8_REV_D ) - dbam_map = ddr2_dbam_revD; +if (i <=2 ) + shift = i; +else if (!(i &0x1 )) + shift = i >>1 ;else - dbam_map = ddr2_dbam_revCG; + shift = (i +1 ) >>1 ; + +return 128 << (shift + !!dct_width); +} + +static int k8_dbam_to_chip_select (struct amd64_pvt *pvt,u8 dct, +unsigned cs_mode) +{ +u32 dclr = dct ? pvt->dclr1 : pvt->dclr0; + +if (pvt->ext_model >=K8_REV_F ) { +WARN_ON (cs_mode >11 ); +return ddr2_cs_size (cs_mode, dclr &WIDTH_128 ); + } +else if (pvt->ext_model >=K8_REV_D ) { +WARN_ON (cs_mode >10 ); -return dbam_map[cs_mode]; +if (cs_mode ==3 || cs_mode ==8 ) +return 32 << (cs_mode -1 ); +else +return 32 << cs_mode; + } +else { +WARN_ON (cs_mode >6 ); +return 32 << cs_mode; + } }/*
@@ -1089,7 +1065,7 @@ static int f1x_early_channel_count(struct amd64_pvt *pvt)int i, j, channels =0 ;/* On F10h, if we are in 128 bit mode, then we are using 2 channels */ -if (boot_cpu_data.x86 ==0x10 && (pvt->dclr0 &F10_WIDTH_128 )) +if (boot_cpu_data.x86 ==0x10 && (pvt->dclr0 &WIDTH_128 ))return 2 ;/*
@@ -1126,16 +1102,50 @@ static int f1x_early_channel_count(struct amd64_pvt *pvt)return channels; } -static int f10_dbam_to_chip_select (struct amd64_pvt *pvt,int cs_mode) +static int ddr3_cs_size (unsigned i,bool dct_width) +{ +unsigned shift =0 ; +int cs_size =0 ; + +if (i ==0 || i ==3 || i ==4 ) + cs_size =-1 ; +else if (i <=2 ) + shift = i; +else if (i ==12 ) + shift =7 ; +else if (!(i &0x1 )) + shift = i >>1 ; +else + shift = (i +1 ) >>1 ; + +if (cs_size !=-1 ) + cs_size = (128 * (1 << !!dct_width)) << shift; + +return cs_size; +} + +static int f10_dbam_to_chip_select (struct amd64_pvt *pvt,u8 dct, +unsigned cs_mode) { -int *dbam_map; +u32 dclr = dct ? pvt->dclr1 : pvt->dclr0; + +WARN_ON (cs_mode >11 );if (pvt->dchr0 &DDR3_MODE || pvt->dchr1 &DDR3_MODE ) - dbam_map = ddr3_dbam; +return ddr3_cs_size (cs_mode, dclr &WIDTH_128 );else - dbam_map = ddr2_dbam; +return ddr2_cs_size (cs_mode, dclr &WIDTH_128 ); +} + +/* +* F15h supports only 64bit DCT interfaces +*/ +static int f15_dbam_to_chip_select (struct amd64_pvt *pvt,u8 dct, +unsigned cs_mode) +{ +WARN_ON (cs_mode >12 ); -return dbam_map[cs_mode]; +return ddr3_cs_size (cs_mode, false); }static void read_dram_ctl_register (struct amd64_pvt *pvt)
@@ -1528,7 +1538,7 @@ static void amd64_debug_display_dimm_sizes(int ctrl, struct amd64_pvt *pvt)u32 dbam = ctrl ? pvt->dbam1 : pvt->dbam0;if (boot_cpu_data.x86 ==0xf ) { -if (pvt->dclr0 &F10_WIDTH_128 ) +if (pvt->dclr0 &WIDTH_128 ) factor =1 ;/* K8 families < revF not supported yet */
@@ -1551,11 +1561,13 @@ static void amd64_debug_display_dimm_sizes(int ctrl, struct amd64_pvt *pvt) size0 =0 ;if (dcsb[dimm*2 ] &DCSB_CS_ENABLE ) - size0 = pvt->ops->dbam_to_cs (pvt,DBAM_DIMM (dimm, dbam)); + size0 = pvt->ops->dbam_to_cs (pvt, ctrl, +DBAM_DIMM (dimm, dbam)); size1 =0 ;if (dcsb[dimm*2 +1 ] &DCSB_CS_ENABLE ) - size1 = pvt->ops->dbam_to_cs (pvt,DBAM_DIMM (dimm, dbam)); + size1 = pvt->ops->dbam_to_cs (pvt, ctrl, +DBAM_DIMM (dimm, dbam)); amd64_info(EDAC_MC ": %d: %5dMB %d: %5dMB\n", dimm * 2, size0 << factor,
@@ -1591,6 +1603,7 @@ static struct amd64_family_type amd64_family_types[] = { .ops = { .early_channel_count = f1x_early_channel_count, .map_sysaddr_to_csrow = f1x_map_sysaddr_to_csrow, + .dbam_to_cs = f15_dbam_to_chip_select, .read_dct_pci_cfg = f15_read_dct_pci_cfg, } },
@@ -2030,7 +2043,7 @@ static void read_mc_regs(struct amd64_pvt *pvt)* encompasses * */ -static u32 amd64_csrow_nr_pages (int csrow_nr,struct amd64_pvt *pvt) +static u32 amd64_csrow_nr_pages (struct amd64_pvt *pvt,u8 dct,int csrow_nr) {u32 cs_mode, nr_pages;
@@ -2043,7 +2056,7 @@ static u32 amd64_csrow_nr_pages(int csrow_nr, struct amd64_pvt *pvt)*/ cs_mode = (pvt->dbam0 >> ((csrow_nr /2 ) *4 )) &0xF ; - nr_pages = pvt->ops->dbam_to_cs (pvt, cs_mode) << (20 -PAGE_SHIFT ); + nr_pages = pvt->ops->dbam_to_cs (pvt, dct, cs_mode) << (20 -PAGE_SHIFT );/* * If dual channel then double the memory size of single channel.
@@ -2091,7 +2104,7 @@ static int init_csrows(struct mem_ctl_info *mci) i, pvt->mc_node_id); empty =0 ; - csrow->nr_pages =amd64_csrow_nr_pages (i, pvt); + csrow->nr_pages =amd64_csrow_nr_pages (pvt,0 , i);find_csrow_limits (mci, i, &input_addr_min, &input_addr_max); sys_addr =input_addr_to_sys_addr (mci, input_addr_min); csrow->first_page = (u32) (sys_addr >>PAGE_SHIFT );
drivers/edac/amd64_edac.h +2 -2
@@ -221,7 +221,7 @@#define DCLR0 0x90#define DCLR1 0x190#define REVE_WIDTH_128 BIT(16) -#define F10_WIDTH_128 BIT(11) +#define WIDTH_128 BIT(11)#define DCHR0 0x94#define DCHR1 0x194
@@ -445,7 +445,7 @@ struct low_ops {int (*early_channel_count) (struct amd64_pvt *pvt);void (*map_sysaddr_to_csrow) (struct mem_ctl_info *mci,u64 sys_addr,u16 syndrome); -int (*dbam_to_cs) (struct amd64_pvt *pvt,int cs_mode); +int (*dbam_to_cs) (struct amd64_pvt *pvt,u8 dct,unsigned cs_mode);int (*read_dct_pci_cfg) (struct amd64_pvt *pvt,int offset,u32 *val,const char *func); };
Signature · 1 line
1.7.4.rc2
PATCH 27/30 PCI: Rename CPU PCI id define
In reply to Borislav PetkovFrom: Borislav Petkov <[email protected]>
With increasing number of PCI function ids, add the PCI function id in the define name instead of its symbolic name in the BKDG for more clarity.
--- arch/x86/kernel/amd_nb.c | 2 +- include/linux/pci_ids.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-)
arch/x86/kernel/amd_nb.c +1 -1
@@ -15,7 +15,7 @@ static u32 *flush_words;struct pci_device_id amd_nb_misc_ids[] = { {PCI_DEVICE (PCI_VENDOR_ID_AMD ,PCI_DEVICE_ID_AMD_K8_NB_MISC ) }, {PCI_DEVICE (PCI_VENDOR_ID_AMD ,PCI_DEVICE_ID_AMD_10H_NB_MISC ) }, - {PCI_DEVICE (PCI_VENDOR_ID_AMD ,PCI_DEVICE_ID_AMD_15H_NB_MISC ) }, + {PCI_DEVICE (PCI_VENDOR_ID_AMD ,PCI_DEVICE_ID_AMD_15H_NB_F3 ) }, {} };EXPORT_SYMBOL (amd_nb_misc_ids);
include/linux/pci_ids.h +1 -1
@@ -517,7 +517,7 @@#define PCI_DEVICE_ID_AMD_11H_NB_DRAM 0x1302#define PCI_DEVICE_ID_AMD_11H_NB_MISC 0x1303#define PCI_DEVICE_ID_AMD_11H_NB_LINK 0x1304 -#define PCI_DEVICE_ID_AMD_15H_NB_MISC 0x1603 +#define PCI_DEVICE_ID_AMD_15H_NB_F3 0x1603#define PCI_DEVICE_ID_AMD_CNB17H_F3 0x1703#define PCI_DEVICE_ID_AMD_LANCE 0x2000#define PCI_DEVICE_ID_AMD_LANCE_HOME 0x2001
Signature · 1 line
1.7.4.rc2
PATCH 28/30 amd64_edac: Simplify scrubrate setting
In reply to Borislav PetkovFrom: Borislav Petkov <[email protected]>
Drop per-instance variable and compute min scrubrate dynamically.
--- drivers/edac/amd64_edac.c | 8 +++++--- drivers/edac/amd64_edac.h | 10 ---------- 2 files changed, 5 insertions(+), 13 deletions(-)
drivers/edac/amd64_edac.c +5 -3
@@ -193,8 +193,12 @@ static int __amd64_set_scrub_rate(struct pci_dev *ctl, u32 new_bw, u32 min_rate)static int amd64_set_scrub_rate (struct mem_ctl_info *mci,u32 bw) {struct amd64_pvt *pvt = mci->pvt_info; +u32 min_scrubrate =0x5 ; -return __amd64_set_scrub_rate (pvt->F3, bw, pvt->min_scrubrate); +if (boot_cpu_data.x86 ==0xf ) + min_scrubrate =0x0 ; + +return __amd64_set_scrub_rate (pvt->F3, bw, min_scrubrate); }static int amd64_get_scrub_rate (struct mem_ctl_info *mci)
@@ -2399,13 +2403,11 @@ static struct amd64_family_type *amd64_per_family_init(struct amd64_pvt *pvt) fam_type = &amd64_family_types[K8_CPUS ]; pvt->ops = &amd64_family_types[K8_CPUS ].ops; pvt->ctl_name = fam_type->ctl_name; - pvt->min_scrubrate =K8_MIN_SCRUB_RATE_BITS ;break ;case 0x10 : fam_type = &amd64_family_types[F10_CPUS ]; pvt->ops = &amd64_family_types[F10_CPUS ].ops; pvt->ctl_name = fam_type->ctl_name; - pvt->min_scrubrate =F10_MIN_SCRUB_RATE_BITS ;break ;default :
drivers/edac/amd64_edac.h +0 -10
@@ -368,9 +368,6 @@ struct amd64_pvt {/* place to store error injection parameters prior to issue */ struct error_injection injection; -/* DCT per-family scrubrate setting */ -u32 min_scrubrate; -/* family name this instance is running on */ const char *ctl_name;
@@ -468,12 +465,5 @@ int __amd64_write_pci_cfg_dword(struct pci_dev *pdev, int offset,#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 -* modify the necessary skip values for the supported CPU. -*/ -#define K8_MIN_SCRUB_RATE_BITS 0x0 -#define F10_MIN_SCRUB_RATE_BITS 0x5 -int amd64_get_dram_hole_info (struct mem_ctl_info *mci,u64 *hole_base,u64 *hole_offset,u64 *hole_size);
Signature · 1 line
1.7.4.rc2
PATCH 29/30 amd64_edac: Adjust ECC symbol size to F15h
In reply to Borislav PetkovFrom: Borislav Petkov <[email protected]>
F15h has the same ECC symbol size options as F10h revD and later so adjust checks to that. Simplify code a bit.
--- drivers/edac/amd64_edac.c | 32 +++++++++++++++----------------- drivers/edac/amd64_edac.h | 2 +- 2 files changed, 16 insertions(+), 18 deletions(-)
drivers/edac/amd64_edac.c +15 -17
@@ -824,7 +824,7 @@ static void dump_misc_regs(struct amd64_pvt *pvt)amd64_debug_display_dimm_sizes (1 , pvt); -amd64_info ("using %s syndromes.\n" , ((pvt->syn_type ==8 ) ?"x8" :"x4" )); +amd64_info ("using %s syndromes.\n" , ((pvt->ecc_sym_sz ==8 ) ?"x8" :"x4" ));/* Only if NOT ganged does dclr1 have valid info */ if (!dct_ganging_enabled (pvt))
@@ -1778,20 +1778,20 @@ static int get_channel_from_ecc_syndrome(struct mem_ctl_info *mci, u16 syndrome)struct amd64_pvt *pvt = mci->pvt_info;int err_sym =-1 ; -if (pvt->syn_type ==8 ) +if (pvt->ecc_sym_sz ==8 ) err_sym =decode_syndrome (syndrome, x8_vectors,ARRAY_SIZE (x8_vectors), - pvt->syn_type); -else if (pvt->syn_type ==4 ) + pvt->ecc_sym_sz); +else if (pvt->ecc_sym_sz ==4 ) err_sym =decode_syndrome (syndrome, x4_vectors,ARRAY_SIZE (x4_vectors), - pvt->syn_type); + pvt->ecc_sym_sz);else { -amd64_warn ("Illegal syndrome type: %u\n" , pvt->syn_type); +amd64_warn ("Illegal syndrome type: %u\n" , pvt->ecc_sym_sz);return err_sym; } -return map_err_sym_to_channel (err_sym, pvt->syn_type); +return map_err_sym_to_channel (err_sym, pvt->ecc_sym_sz); }/*
@@ -1936,6 +1936,7 @@ static void free_mc_sibling_devs(struct amd64_pvt *pvt)*/ static void read_mc_regs (struct amd64_pvt *pvt) { +struct cpuinfo_x86 *c = &boot_cpu_data;u64 msr_val;u32 tmp;int range;
@@ -1997,19 +1998,16 @@ static void read_mc_regs(struct amd64_pvt *pvt)amd64_read_dct_pci_cfg (pvt,DCHR1 , &pvt->dchr1); } -if (boot_cpu_data.x86 >=0x10 ) { + pvt->ecc_sym_sz =4 ; + +if (c->x86 >=0x10 ) {amd64_read_pci_cfg (pvt->F3,EXT_NB_MCA_CFG , &tmp);amd64_read_dct_pci_cfg (pvt,DBAM1 , &pvt->dbam1); - } - -if (boot_cpu_data.x86 ==0x10 && - boot_cpu_data.x86_model >7 && -/* F3x180[EccSymbolSize]=1 => x8 symbols */ - tmp &BIT (25 )) - pvt->syn_type =8 ; -else - pvt->syn_type =4 ; +/* F10h, revD and later can do x8 ECC too */ +if ((c->x86 >0x10 || c->x86_model >7 ) && tmp &BIT (25 )) + pvt->ecc_sym_sz =8 ; + }dump_misc_regs (pvt); }
drivers/edac/amd64_edac.h +1 -1
@@ -363,7 +363,7 @@ struct amd64_pvt {u32 online_spare;/* On-Line spare Reg */ /* x4 or x8 syndromes in use */ -u8 syn_type; +u8 ecc_sym_sz;/* place to store error injection parameters prior to issue */ struct error_injection injection;
Signature · 1 line
1.7.4.rc2
PATCH 30/30 amd64_edac: Enable driver on F15h
In reply to Borislav PetkovFrom: Borislav Petkov <[email protected]>
Add the PCI device ids required for driver registration. Remove pvt->ctl_name and use the family descriptor directly, instead. Then, bump driver version and fixup its format. Finally, enable DRAM ECC decoding on F15h.
--- drivers/edac/amd64_edac.c | 30 +++++++++++++++++++++++------- drivers/edac/amd64_edac.h | 8 +++----- drivers/edac/mce_amd.c | 6 +++--- 3 files changed, 29 insertions(+), 15 deletions(-)
drivers/edac/amd64_edac.c +23 -7
@@ -1604,6 +1604,8 @@ static struct amd64_family_type amd64_family_types[] = { }, [F15_CPUS] = { .ctl_name = "F15h", + .f1_id = PCI_DEVICE_ID_AMD_15H_NB_F1, + .f3_id = PCI_DEVICE_ID_AMD_15H_NB_F3, .ops = { .early_channel_count = f1x_early_channel_count, .map_sysaddr_to_csrow = f1x_map_sysaddr_to_csrow,
@@ -2363,7 +2365,8 @@ static void set_mc_sysfs_attrs(struct mem_ctl_info *mci) mci->mc_driver_sysfs_attributes = sysfs_attrs; } -static void setup_mci_misc_attrs (struct mem_ctl_info *mci) +static void setup_mci_misc_attrs (struct mem_ctl_info *mci, +struct amd64_family_type *fam) {struct amd64_pvt *pvt = mci->pvt_info;
@@ -2379,7 +2382,7 @@ static void setup_mci_misc_attrs(struct mem_ctl_info *mci) mci->edac_cap =amd64_determine_edac_cap (pvt); mci->mod_name =EDAC_MOD_STR ; mci->mod_ver =EDAC_AMD64_VERSION ; - mci->ctl_name = pvt->ctl_name; + mci->ctl_name = fam->ctl_name; mci->dev_name =pci_name (pvt->F2); mci->ctl_page_to_phys =NULL ;
@@ -2400,12 +2403,16 @@ static struct amd64_family_type *amd64_per_family_init(struct amd64_pvt *pvt)case 0xf : fam_type = &amd64_family_types[K8_CPUS ]; pvt->ops = &amd64_family_types[K8_CPUS ].ops; - pvt->ctl_name = fam_type->ctl_name;break ; +case 0x10 : fam_type = &amd64_family_types[F10_CPUS ]; pvt->ops = &amd64_family_types[F10_CPUS ].ops; - pvt->ctl_name = fam_type->ctl_name; +break ; + +case 0x15 : + fam_type = &amd64_family_types[F15_CPUS ]; + pvt->ops = &amd64_family_types[F15_CPUS ].ops;break ;default :
@@ -2415,7 +2422,7 @@ static struct amd64_family_type *amd64_per_family_init(struct amd64_pvt *pvt) pvt->ext_model = boot_cpu_data.x86_model >>4 ; - amd64_info("%s %sdetected (node %d).\n", pvt->ctl_name, + amd64_info("%s %sdetected (node %d).\n", fam_type->ctl_name, (fam == 0xf ? (pvt->ext_model >= K8_REV_F ? "revF or later " : "revE or earlier ")
@@ -2469,7 +2476,7 @@ static int amd64_init_one_instance(struct pci_dev *F2) mci->pvt_info = pvt; mci->dev = &pvt->F2->dev; -setup_mci_misc_attrs (mci); +setup_mci_misc_attrs (mci, fam_type);if (init_csrows (mci)) mci->edac_cap =EDAC_FLAG_NONE ;
@@ -2612,6 +2619,15 @@ static const struct pci_device_id amd64_pci_table[] __devinitdata = { .class = 0, .class_mask = 0, }, + { + .vendor = PCI_VENDOR_ID_AMD, + .device = PCI_DEVICE_ID_AMD_15H_NB_F2, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .class = 0, + .class_mask = 0, + }, + {0, } };MODULE_DEVICE_TABLE (pci, amd64_pci_table);
@@ -2652,7 +2668,7 @@ static int __init amd64_edac_init(void) {int err = -ENODEV ; -edac_printk (KERN_INFO ,EDAC_MOD_STR ,EDAC_AMD64_VERSION "\n" ); +printk (KERN_INFO "AMD64 EDAC driver v%s\n" ,EDAC_AMD64_VERSION );opstate_init ();
drivers/edac/amd64_edac.h +3 -5
@@ -144,7 +144,7 @@* sections 3.5.4 and 3.5.5 for more information. */ -#define EDAC_AMD64_VERSION "v3.3.0" +#define EDAC_AMD64_VERSION "3.4.0"#define EDAC_MOD_STR "amd64_edac"/* Extended Model from CPUID, for CPU Revision numbers */
@@ -170,6 +170,8 @@/* * PCI-defined configuration space registers */ +#define PCI_DEVICE_ID_AMD_15H_NB_F1 0x1601 +#define PCI_DEVICE_ID_AMD_15H_NB_F2 0x1602/*
@@ -367,10 +369,6 @@ struct amd64_pvt {/* place to store error injection parameters prior to issue */ struct error_injection injection; - -/* family name this instance is running on */ -const char *ctl_name; - };static inline u64 get_dram_base (struct amd64_pvt *pvt,unsigned i)
drivers/edac/mce_amd.c +3 -3
@@ -594,6 +594,7 @@ static bool nb_noop_mce(u16 ec, u8 xec)void amd_decode_nb_mce (int node_id,struct mce *m,u32 nbcfg) { +struct cpuinfo_x86 *c = &boot_cpu_data;u16 ec =EC (m->status);u8 xec =XEC (m->status,0x1f );u32 nbsh = (u32)(m->status >>32 );
@@ -602,8 +603,7 @@ void amd_decode_nb_mce(int node_id, struct mce *m, u32 nbcfg)pr_emerg (HW_ERR "Northbridge Error (node %d" , node_id);/* F10h, revD can disable ErrCpu[3:0] through ErrCpuVal */ -if ((boot_cpu_data.x86 ==0x10 ) && - (boot_cpu_data.x86_model >7 )) { +if (c->x86 ==0x10 && c->x86_model >7 ) {if (nbsh &NBSH_ERR_CPU_VAL ) core = nbsh & nb_err_cpumask; }else {
@@ -646,7 +646,7 @@ void amd_decode_nb_mce(int node_id, struct mce *m, u32 nbcfg)if (!fam_ops->nb_mce (ec, xec)) goto wrong_nb_mce; -if (boot_cpu_data.x86 ==0xf || boot_cpu_data.x86 ==0x10 ) +if (c->x86 ==0xf || c->x86 ==0x10 || c->x86 ==0x15 )if ((xec ==0x8 || xec ==0x0 ) && nb_bus_decoder)nb_bus_decoder (node_id, m, nbcfg);
Signature · 1 line
1.7.4.rc2
Quoted 18 lines · Borislav Petkov
From: Borislav Petkov <[email protected]>
Hi all,
the following patchset that adds support for our upcoming F15h CPUs. Besides adding a new family support, it cleans up a lot in the driver and the diffstat says it all:
arch/x86/kernel/amd_nb.c | 2 +- drivers/edac/amd64_edac.c | 1412 +++++++++++++++++++---------------------- drivers/edac/amd64_edac.h | 357 ++++------- drivers/edac/amd64_edac_inj.c | 8 +- drivers/edac/edac_mc_sysfs.c | 26 +- drivers/edac/mce_amd.c | 8 +- drivers/edac/mce_amd.h | 28 +- include/linux/pci_ids.h | 2 +- 8 files changed, 825 insertions(+), 1018 deletions(-)
Quoted 2 lines
@Greg/@Ingo: Guys, let me know if patch 27/30 should be rerouted over your trees or would you rather like to ACK it?
I don't need to ack it or take it as it doesn't pertain to any of the files I maintain :)
greg k-h
Quoted 19 lines · Greg KH
Quoted 18 lines · Borislav Petkov
From: Borislav Petkov <[email protected]>
Hi all,
the following patchset that adds support for our upcoming F15h CPUs. Besides adding a new family support, it cleans up a lot in the driver and the diffstat says it all:
arch/x86/kernel/amd_nb.c | 2 +- drivers/edac/amd64_edac.c | 1412 +++++++++++++++++++---------------------- drivers/edac/amd64_edac.h | 357 ++++------- drivers/edac/amd64_edac_inj.c | 8 +- drivers/edac/edac_mc_sysfs.c | 26 +- drivers/edac/mce_amd.c | 8 +- drivers/edac/mce_amd.h | 28 +- include/linux/pci_ids.h | 2 +- 8 files changed, 825 insertions(+), 1018 deletions(-)
Quoted 5 lines
Quoted 2 lines
@Greg/@Ingo: Guys, let me know if patch 27/30 should be rerouted over your trees or would you rather like to ACK it?
I don't need to ack it or take it as it doesn't pertain to any of the files I maintain :)
Ah, sorry for the confusion, it should be Jesse Barnes instead, added to Cc.
Jesse, do you want the patch at
http://marc.info/?l=linux-edac&m=129735827731488&w=2 rerouted over your tree or would you rather ack it?
Same question for Ingo, for the <arch/x86/kernel/amd_nb.c> part.
Thanks.
Signature · 8 lines
Regards/Gruss, Boris. Advanced Micro Devices GmbH Einsteinring 24, 85609 Dornach General Managers: Alberto Bozzo, Andrew Bowd Registration: Dornach, Gemeinde Aschheim, Landkreis Muenchen Registergericht Muenchen, HRB Nr. 43632
Jesse Barnes
Acked-byQuoted 26 lines · On Thu, 10 Feb 2011 20:20:34 +0100 Borislav Petkov <[email protected]> wrote:
Quoted 19 lines · Greg KH
Quoted 18 lines · Borislav Petkov
From: Borislav Petkov <[email protected]>
Hi all,
the following patchset that adds support for our upcoming F15h CPUs. Besides adding a new family support, it cleans up a lot in the driver and the diffstat says it all:
arch/x86/kernel/amd_nb.c | 2 +- drivers/edac/amd64_edac.c | 1412 +++++++++++++++++++---------------------- drivers/edac/amd64_edac.h | 357 ++++------- drivers/edac/amd64_edac_inj.c | 8 +- drivers/edac/edac_mc_sysfs.c | 26 +- drivers/edac/mce_amd.c | 8 +- drivers/edac/mce_amd.h | 28 +- include/linux/pci_ids.h | 2 +- 8 files changed, 825 insertions(+), 1018 deletions(-)Quoted 5 lines
Quoted 2 lines
@Greg/@Ingo: Guys, let me know if patch 27/30 should be rerouted over your trees or would you rather like to ACK it?
I don't need to ack it or take it as it doesn't pertain to any of the files I maintain :)
Quoted 6 lines
Ah, sorry for the confusion, it should be Jesse Barnes instead, added to Cc.
Jesse, do you want the patch at
http://marc.info/?l=linux-edac&m=129735827731488&w=2 rerouted over your tree or would you rather ack it?
You can have my ack:
Though if that's the only place that PCI ID is used, you may as well just put it into the corresponding file and remove it from pci_ids.h altogether.
Signature · 1 line
Jesse Barnes, Intel Open Source Technology Center
Borislav Petkov
maintainerQuoted 7 lines · Jesse Barnes
Quoted 3 lines
Jesse, do you want the patch at
http://marc.info/?l=linux-edac&m=129735827731488&w=2 rerouted over your tree or would you rather ack it?You can have my ack:
Acked-by Jesse Barnes <[email protected]>
Thanks.
Quoted 3 lines
Though if that's the only place that PCI ID is used, you may as well just put it into the corresponding file and remove it from
pci_ids.haltogether.
Yeah, this patchset adds another user of PCI_DEVICE_ID_AMD_15H_NB_F3 in amd64_edac.c, this was the reasoning to move it to pci_ids.h
In contrast, I'm also introducing PCI_DEVICE_ID_AMD_15H_NB_F[12] which are used only in this driver and thus I've left them in its header. We'll move them to pci_ids.h only if some other user of them appears.
Thanks.
Signature · 2 lines
Regards/Gruss,
Boris.