EDAC, sb_edac: Check if ECC enabled when at least one DIMM is present
This is based on previous work by Patrick Geary, see Link. Additional cleanups ontop: - Remove the code to read MCMTR from pci_ha1_ta and CHN_TO_HA macro, now that TA0 and TA1 are unified. - Remove get_pdev_same_bus(), since in get_dimm_config() the variable "pvt->pci_ta" for KNL is also ready, we can simply use pci_read_config_dword(pvt->pci_ta, KNL_MCMTR, &pvt->info.mcmtr) to read MCMTR. Signed-off-by: Qiuxu Zhuo <qiuxu.zhuo@intel.com> Cc: linux-edac <linux-edac@vger.kernel.org> Link: https://lkml.kernel.org/r/57884350.1030401@supermicro.com Link: http://lkml.kernel.org/r/20170523000910.87925-1-qiuxu.zhuo@intel.com [ Make __populate_dimms() return int. ] Signed-off-by: Borislav Petkov <bp@suse.de>
This commit is contained in:
parent
3286d3eb90
commit
4d475dde79
|
@ -1060,79 +1060,6 @@ static int haswell_chan_hash(int idx, u64 addr)
|
||||||
return idx;
|
return idx;
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************
|
|
||||||
Memory check routines
|
|
||||||
****************************************************************************/
|
|
||||||
static struct pci_dev *get_pdev_same_bus(u8 bus, u32 id)
|
|
||||||
{
|
|
||||||
struct pci_dev *pdev = NULL;
|
|
||||||
|
|
||||||
do {
|
|
||||||
pdev = pci_get_device(PCI_VENDOR_ID_INTEL, id, pdev);
|
|
||||||
if (pdev && pdev->bus->number == bus)
|
|
||||||
break;
|
|
||||||
} while (pdev);
|
|
||||||
|
|
||||||
return pdev;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* check_if_ecc_is_active() - Checks if ECC is active
|
|
||||||
* @bus: Device bus
|
|
||||||
* @type: Memory controller type
|
|
||||||
* returns: 0 in case ECC is active, -ENODEV if it can't be determined or
|
|
||||||
* disabled
|
|
||||||
*/
|
|
||||||
static int check_if_ecc_is_active(const u8 bus, enum type type)
|
|
||||||
{
|
|
||||||
struct pci_dev *pdev = NULL;
|
|
||||||
u32 mcmtr, id;
|
|
||||||
|
|
||||||
switch (type) {
|
|
||||||
case IVY_BRIDGE:
|
|
||||||
id = PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TA;
|
|
||||||
break;
|
|
||||||
case HASWELL:
|
|
||||||
id = PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0_TA;
|
|
||||||
break;
|
|
||||||
case SANDY_BRIDGE:
|
|
||||||
id = PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TA;
|
|
||||||
break;
|
|
||||||
case BROADWELL:
|
|
||||||
id = PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA0_TA;
|
|
||||||
break;
|
|
||||||
case KNIGHTS_LANDING:
|
|
||||||
/*
|
|
||||||
* KNL doesn't group things by bus the same way
|
|
||||||
* SB/IB/Haswell does.
|
|
||||||
*/
|
|
||||||
id = PCI_DEVICE_ID_INTEL_KNL_IMC_TA;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return -ENODEV;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (type != KNIGHTS_LANDING)
|
|
||||||
pdev = get_pdev_same_bus(bus, id);
|
|
||||||
else
|
|
||||||
pdev = pci_get_device(PCI_VENDOR_ID_INTEL, id, 0);
|
|
||||||
|
|
||||||
if (!pdev) {
|
|
||||||
sbridge_printk(KERN_ERR, "Couldn't find PCI device "
|
|
||||||
"%04x:%04x! on bus %02d\n",
|
|
||||||
PCI_VENDOR_ID_INTEL, id, bus);
|
|
||||||
return -ENODEV;
|
|
||||||
}
|
|
||||||
|
|
||||||
pci_read_config_dword(pdev,
|
|
||||||
type == KNIGHTS_LANDING ? KNL_MCMTR : MCMTR, &mcmtr);
|
|
||||||
if (!IS_ECC_ENABLED(mcmtr)) {
|
|
||||||
sbridge_printk(KERN_ERR, "ECC is disabled. Aborting\n");
|
|
||||||
return -ENODEV;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Low bits of TAD limit, and some metadata. */
|
/* Low bits of TAD limit, and some metadata. */
|
||||||
static const u32 knl_tad_dram_limit_lo[] = {
|
static const u32 knl_tad_dram_limit_lo[] = {
|
||||||
0x400, 0x500, 0x600, 0x700,
|
0x400, 0x500, 0x600, 0x700,
|
||||||
|
@ -1620,9 +1547,9 @@ static void get_source_id(struct mem_ctl_info *mci)
|
||||||
pvt->sbridge_dev->source_id = SOURCE_ID(reg);
|
pvt->sbridge_dev->source_id = SOURCE_ID(reg);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void __populate_dimms(struct mem_ctl_info *mci,
|
static int __populate_dimms(struct mem_ctl_info *mci,
|
||||||
u64 knl_mc_sizes[KNL_MAX_CHANNELS],
|
u64 knl_mc_sizes[KNL_MAX_CHANNELS],
|
||||||
enum edac_type mode)
|
enum edac_type mode)
|
||||||
{
|
{
|
||||||
struct sbridge_pvt *pvt = mci->pvt_info;
|
struct sbridge_pvt *pvt = mci->pvt_info;
|
||||||
int channels = pvt->info.type == KNIGHTS_LANDING ? KNL_MAX_CHANNELS
|
int channels = pvt->info.type == KNIGHTS_LANDING ? KNL_MAX_CHANNELS
|
||||||
|
@ -1671,6 +1598,12 @@ static void __populate_dimms(struct mem_ctl_info *mci,
|
||||||
}
|
}
|
||||||
edac_dbg(4, "Channel #%d MTR%d = %x\n", i, j, mtr);
|
edac_dbg(4, "Channel #%d MTR%d = %x\n", i, j, mtr);
|
||||||
if (IS_DIMM_PRESENT(mtr)) {
|
if (IS_DIMM_PRESENT(mtr)) {
|
||||||
|
if (!IS_ECC_ENABLED(pvt->info.mcmtr)) {
|
||||||
|
sbridge_printk(KERN_ERR, "CPU SrcID #%d, Ha #%d, Channel #%d has DIMMs, but ECC is disabled\n",
|
||||||
|
pvt->sbridge_dev->source_id,
|
||||||
|
pvt->sbridge_dev->dom, i);
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
pvt->channel[i].dimms++;
|
pvt->channel[i].dimms++;
|
||||||
|
|
||||||
ranks = numrank(pvt->info.type, mtr);
|
ranks = numrank(pvt->info.type, mtr);
|
||||||
|
@ -1704,6 +1637,8 @@ static void __populate_dimms(struct mem_ctl_info *mci,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int get_dimm_config(struct mem_ctl_info *mci)
|
static int get_dimm_config(struct mem_ctl_info *mci)
|
||||||
|
@ -1732,6 +1667,7 @@ static int get_dimm_config(struct mem_ctl_info *mci)
|
||||||
|
|
||||||
if (knl_get_dimm_capacity(pvt, knl_mc_sizes) != 0)
|
if (knl_get_dimm_capacity(pvt, knl_mc_sizes) != 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
pci_read_config_dword(pvt->pci_ta, KNL_MCMTR, &pvt->info.mcmtr);
|
||||||
} else {
|
} else {
|
||||||
pci_read_config_dword(pvt->pci_ras, RASENABLES, ®);
|
pci_read_config_dword(pvt->pci_ras, RASENABLES, ®);
|
||||||
if (IS_MIRROR_ENABLED(reg)) {
|
if (IS_MIRROR_ENABLED(reg)) {
|
||||||
|
@ -1761,9 +1697,7 @@ static int get_dimm_config(struct mem_ctl_info *mci)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
__populate_dimms(mci, knl_mc_sizes, mode);
|
return __populate_dimms(mci, knl_mc_sizes, mode);
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void get_memory_layout(const struct mem_ctl_info *mci)
|
static void get_memory_layout(const struct mem_ctl_info *mci)
|
||||||
|
@ -3180,11 +3114,6 @@ static int sbridge_register_mci(struct sbridge_dev *sbridge_dev, enum type type)
|
||||||
struct pci_dev *pdev = sbridge_dev->pdev[0];
|
struct pci_dev *pdev = sbridge_dev->pdev[0];
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
/* Check the number of active and not disabled channels */
|
|
||||||
rc = check_if_ecc_is_active(sbridge_dev->bus, type);
|
|
||||||
if (unlikely(rc < 0))
|
|
||||||
return rc;
|
|
||||||
|
|
||||||
/* allocate a new MC control structure */
|
/* allocate a new MC control structure */
|
||||||
layers[0].type = EDAC_MC_LAYER_CHANNEL;
|
layers[0].type = EDAC_MC_LAYER_CHANNEL;
|
||||||
layers[0].size = type == KNIGHTS_LANDING ?
|
layers[0].size = type == KNIGHTS_LANDING ?
|
||||||
|
@ -3347,7 +3276,11 @@ static int sbridge_register_mci(struct sbridge_dev *sbridge_dev, enum type type)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Get dimm basic config and the memory layout */
|
/* Get dimm basic config and the memory layout */
|
||||||
get_dimm_config(mci);
|
rc = get_dimm_config(mci);
|
||||||
|
if (rc < 0) {
|
||||||
|
edac_dbg(0, "MC: failed to get_dimm_config()\n");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
get_memory_layout(mci);
|
get_memory_layout(mci);
|
||||||
|
|
||||||
/* record ptr to the generic device */
|
/* record ptr to the generic device */
|
||||||
|
|
Loading…
Reference in New Issue