Commit 68ffeca4 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'linux_next' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-edac

Pull EDAC updates from Mauro Carvalho Chehab.

* 'linux_next' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-edac:
  sb_edac: add support for Haswell based systems
  sb_edac: Fix mix tab/spaces alignments
  edac: add DDR4 and RDDR4
  sb_edac: remove bogus assumption on mc ordering
  sb_edac: make minimal use of channel_mask
  sb_edac: fix socket detection on Ivy Bridge controllers
  sb_edac: update Kconfig description
  sb_edac: search devices using product id
  sb_edac: make RIR limit retrieval per model
  sb_edac: make node id retrieval per model
  sb_edac: make memory type detection per memory controller
parents c9d26423 50d1bb93
...@@ -253,12 +253,12 @@ config EDAC_I7300 ...@@ -253,12 +253,12 @@ config EDAC_I7300
Clarksboro MCH (Intel 7300 chipset). Clarksboro MCH (Intel 7300 chipset).
config EDAC_SBRIDGE config EDAC_SBRIDGE
tristate "Intel Sandy-Bridge Integrated MC" tristate "Intel Sandy-Bridge/Ivy-Bridge/Haswell Integrated MC"
depends on EDAC_MM_EDAC && PCI && X86_64 && X86_MCE_INTEL depends on EDAC_MM_EDAC && PCI && X86_64 && X86_MCE_INTEL
depends on PCI_MMCONFIG depends on PCI_MMCONFIG
help help
Support for error detection and correction the Intel Support for error detection and correction the Intel
Sandy Bridge Integrated Memory Controller. Sandy Bridge, Ivy Bridge and Haswell Integrated Memory Controllers.
config EDAC_MPC85XX config EDAC_MPC85XX
tristate "Freescale MPC83xx / MPC85xx" tristate "Freescale MPC83xx / MPC85xx"
......
...@@ -108,7 +108,9 @@ static const char * const mem_types[] = { ...@@ -108,7 +108,9 @@ static const char * const mem_types[] = {
[MEM_RDDR2] = "Registered-DDR2", [MEM_RDDR2] = "Registered-DDR2",
[MEM_XDR] = "XDR", [MEM_XDR] = "XDR",
[MEM_DDR3] = "Unbuffered-DDR3", [MEM_DDR3] = "Unbuffered-DDR3",
[MEM_RDDR3] = "Registered-DDR3" [MEM_RDDR3] = "Registered-DDR3",
[MEM_DDR4] = "Unbuffered-DDR4",
[MEM_RDDR4] = "Registered-DDR4"
}; };
static const char * const dev_types[] = { static const char * const dev_types[] = {
......
...@@ -99,6 +99,7 @@ static const u32 ibridge_dram_rule[] = { ...@@ -99,6 +99,7 @@ static const u32 ibridge_dram_rule[] = {
#define DRAM_ATTR(reg) GET_BITFIELD(reg, 2, 3) #define DRAM_ATTR(reg) GET_BITFIELD(reg, 2, 3)
#define INTERLEAVE_MODE(reg) GET_BITFIELD(reg, 1, 1) #define INTERLEAVE_MODE(reg) GET_BITFIELD(reg, 1, 1)
#define DRAM_RULE_ENABLE(reg) GET_BITFIELD(reg, 0, 0) #define DRAM_RULE_ENABLE(reg) GET_BITFIELD(reg, 0, 0)
#define A7MODE(reg) GET_BITFIELD(reg, 26, 26)
static char *get_dram_attr(u32 reg) static char *get_dram_attr(u32 reg)
{ {
...@@ -164,6 +165,8 @@ static inline int sad_pkg(const struct interleave_pkg *table, u32 reg, ...@@ -164,6 +165,8 @@ static inline int sad_pkg(const struct interleave_pkg *table, u32 reg,
#define TOLM 0x80 #define TOLM 0x80
#define TOHM 0x84 #define TOHM 0x84
#define HASWELL_TOHM_0 0xd4
#define HASWELL_TOHM_1 0xd8
#define GET_TOLM(reg) ((GET_BITFIELD(reg, 0, 3) << 28) | 0x3ffffff) #define GET_TOLM(reg) ((GET_BITFIELD(reg, 0, 3) << 28) | 0x3ffffff)
#define GET_TOHM(reg) ((GET_BITFIELD(reg, 0, 20) << 25) | 0x3ffffff) #define GET_TOHM(reg) ((GET_BITFIELD(reg, 0, 20) << 25) | 0x3ffffff)
...@@ -176,8 +179,6 @@ static inline int sad_pkg(const struct interleave_pkg *table, u32 reg, ...@@ -176,8 +179,6 @@ static inline int sad_pkg(const struct interleave_pkg *table, u32 reg,
#define SAD_CONTROL 0xf4 #define SAD_CONTROL 0xf4
#define NODE_ID(reg) GET_BITFIELD(reg, 0, 2)
/* Device 14 function 0 */ /* Device 14 function 0 */
static const u32 tad_dram_rule[] = { static const u32 tad_dram_rule[] = {
...@@ -235,7 +236,6 @@ static const u32 rir_way_limit[] = { ...@@ -235,7 +236,6 @@ static const u32 rir_way_limit[] = {
#define IS_RIR_VALID(reg) GET_BITFIELD(reg, 31, 31) #define IS_RIR_VALID(reg) GET_BITFIELD(reg, 31, 31)
#define RIR_WAY(reg) GET_BITFIELD(reg, 28, 29) #define RIR_WAY(reg) GET_BITFIELD(reg, 28, 29)
#define RIR_LIMIT(reg) ((GET_BITFIELD(reg, 1, 10) << 29)| 0x1fffffff)
#define MAX_RIR_WAY 8 #define MAX_RIR_WAY 8
...@@ -279,8 +279,6 @@ static const u32 correrrthrsld[] = { ...@@ -279,8 +279,6 @@ static const u32 correrrthrsld[] = {
#define IB_RANK_CFG_A 0x0320 #define IB_RANK_CFG_A 0x0320
#define IS_RDIMM_ENABLED(reg) GET_BITFIELD(reg, 11, 11)
/* /*
* sbridge structs * sbridge structs
*/ */
...@@ -291,6 +289,7 @@ static const u32 correrrthrsld[] = { ...@@ -291,6 +289,7 @@ static const u32 correrrthrsld[] = {
enum type { enum type {
SANDY_BRIDGE, SANDY_BRIDGE,
IVY_BRIDGE, IVY_BRIDGE,
HASWELL,
}; };
struct sbridge_pvt; struct sbridge_pvt;
...@@ -300,11 +299,15 @@ struct sbridge_info { ...@@ -300,11 +299,15 @@ struct sbridge_info {
u32 rankcfgr; u32 rankcfgr;
u64 (*get_tolm)(struct sbridge_pvt *pvt); u64 (*get_tolm)(struct sbridge_pvt *pvt);
u64 (*get_tohm)(struct sbridge_pvt *pvt); u64 (*get_tohm)(struct sbridge_pvt *pvt);
u64 (*rir_limit)(u32 reg);
const u32 *dram_rule; const u32 *dram_rule;
const u32 *interleave_list; const u32 *interleave_list;
const struct interleave_pkg *interleave_pkg; const struct interleave_pkg *interleave_pkg;
u8 max_sad; u8 max_sad;
u8 max_interleave; u8 max_interleave;
u8 (*get_node_id)(struct sbridge_pvt *pvt);
enum mem_type (*get_memory_type)(struct sbridge_pvt *pvt);
struct pci_dev *pci_vtd;
}; };
struct sbridge_channel { struct sbridge_channel {
...@@ -313,9 +316,7 @@ struct sbridge_channel { ...@@ -313,9 +316,7 @@ struct sbridge_channel {
}; };
struct pci_id_descr { struct pci_id_descr {
int dev; int dev_id;
int func;
int dev_id;
int optional; int optional;
}; };
...@@ -338,6 +339,7 @@ struct sbridge_pvt { ...@@ -338,6 +339,7 @@ struct sbridge_pvt {
struct pci_dev *pci_sad0, *pci_sad1; struct pci_dev *pci_sad0, *pci_sad1;
struct pci_dev *pci_ha0, *pci_ha1; struct pci_dev *pci_ha0, *pci_ha1;
struct pci_dev *pci_br0, *pci_br1; struct pci_dev *pci_br0, *pci_br1;
struct pci_dev *pci_ha1_ta;
struct pci_dev *pci_tad[NUM_CHANNELS]; struct pci_dev *pci_tad[NUM_CHANNELS];
struct sbridge_dev *sbridge_dev; struct sbridge_dev *sbridge_dev;
...@@ -362,31 +364,29 @@ struct sbridge_pvt { ...@@ -362,31 +364,29 @@ struct sbridge_pvt {
u64 tolm, tohm; u64 tolm, tohm;
}; };
#define PCI_DESCR(device, function, device_id, opt) \ #define PCI_DESCR(device_id, opt) \
.dev = (device), \ .dev_id = (device_id), \
.func = (function), \
.dev_id = (device_id), \
.optional = opt .optional = opt
static const struct pci_id_descr pci_dev_descr_sbridge[] = { static const struct pci_id_descr pci_dev_descr_sbridge[] = {
/* Processor Home Agent */ /* Processor Home Agent */
{ PCI_DESCR(14, 0, PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_HA0, 0) }, { PCI_DESCR(PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_HA0, 0) },
/* Memory controller */ /* Memory controller */
{ PCI_DESCR(15, 0, PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TA, 0) }, { PCI_DESCR(PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TA, 0) },
{ PCI_DESCR(15, 1, PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_RAS, 0) }, { PCI_DESCR(PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_RAS, 0) },
{ PCI_DESCR(15, 2, PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TAD0, 0) }, { PCI_DESCR(PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TAD0, 0) },
{ PCI_DESCR(15, 3, PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TAD1, 0) }, { PCI_DESCR(PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TAD1, 0) },
{ PCI_DESCR(15, 4, PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TAD2, 0) }, { PCI_DESCR(PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TAD2, 0) },
{ PCI_DESCR(15, 5, PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TAD3, 0) }, { PCI_DESCR(PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TAD3, 0) },
{ PCI_DESCR(17, 0, PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_DDRIO, 1) }, { PCI_DESCR(PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_DDRIO, 1) },
/* System Address Decoder */ /* System Address Decoder */
{ PCI_DESCR(12, 6, PCI_DEVICE_ID_INTEL_SBRIDGE_SAD0, 0) }, { PCI_DESCR(PCI_DEVICE_ID_INTEL_SBRIDGE_SAD0, 0) },
{ PCI_DESCR(12, 7, PCI_DEVICE_ID_INTEL_SBRIDGE_SAD1, 0) }, { PCI_DESCR(PCI_DEVICE_ID_INTEL_SBRIDGE_SAD1, 0) },
/* Broadcast Registers */ /* Broadcast Registers */
{ PCI_DESCR(13, 6, PCI_DEVICE_ID_INTEL_SBRIDGE_BR, 0) }, { PCI_DESCR(PCI_DEVICE_ID_INTEL_SBRIDGE_BR, 0) },
}; };
#define PCI_ID_TABLE_ENTRY(A) { .descr=A, .n_devs = ARRAY_SIZE(A) } #define PCI_ID_TABLE_ENTRY(A) { .descr=A, .n_devs = ARRAY_SIZE(A) }
...@@ -423,34 +423,34 @@ static const struct pci_id_table pci_dev_descr_sbridge_table[] = { ...@@ -423,34 +423,34 @@ static const struct pci_id_table pci_dev_descr_sbridge_table[] = {
static const struct pci_id_descr pci_dev_descr_ibridge[] = { static const struct pci_id_descr pci_dev_descr_ibridge[] = {
/* Processor Home Agent */ /* Processor Home Agent */
{ PCI_DESCR(14, 0, PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0, 0) }, { PCI_DESCR(PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0, 0) },
/* Memory controller */ /* Memory controller */
{ PCI_DESCR(15, 0, PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TA, 0) }, { PCI_DESCR(PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TA, 0) },
{ PCI_DESCR(15, 1, PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_RAS, 0) }, { PCI_DESCR(PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_RAS, 0) },
{ PCI_DESCR(15, 2, PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TAD0, 0) }, { PCI_DESCR(PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TAD0, 0) },
{ PCI_DESCR(15, 3, PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TAD1, 0) }, { PCI_DESCR(PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TAD1, 0) },
{ PCI_DESCR(15, 4, PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TAD2, 0) }, { PCI_DESCR(PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TAD2, 0) },
{ PCI_DESCR(15, 5, PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TAD3, 0) }, { PCI_DESCR(PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TAD3, 0) },
/* System Address Decoder */ /* System Address Decoder */
{ PCI_DESCR(22, 0, PCI_DEVICE_ID_INTEL_IBRIDGE_SAD, 0) }, { PCI_DESCR(PCI_DEVICE_ID_INTEL_IBRIDGE_SAD, 0) },
/* Broadcast Registers */ /* Broadcast Registers */
{ PCI_DESCR(22, 1, PCI_DEVICE_ID_INTEL_IBRIDGE_BR0, 1) }, { PCI_DESCR(PCI_DEVICE_ID_INTEL_IBRIDGE_BR0, 1) },
{ PCI_DESCR(22, 2, PCI_DEVICE_ID_INTEL_IBRIDGE_BR1, 0) }, { PCI_DESCR(PCI_DEVICE_ID_INTEL_IBRIDGE_BR1, 0) },
/* Optional, mode 2HA */ /* Optional, mode 2HA */
{ PCI_DESCR(28, 0, PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA1, 1) }, { PCI_DESCR(PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA1, 1) },
#if 0 #if 0
{ PCI_DESCR(29, 0, PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA1_TA, 1) }, { PCI_DESCR(PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA1_TA, 1) },
{ PCI_DESCR(29, 1, PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA1_RAS, 1) }, { PCI_DESCR(PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA1_RAS, 1) },
#endif #endif
{ PCI_DESCR(29, 2, PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA1_TAD0, 1) }, { PCI_DESCR(PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA1_TAD0, 1) },
{ PCI_DESCR(29, 3, PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA1_TAD1, 1) }, { PCI_DESCR(PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA1_TAD1, 1) },
{ PCI_DESCR(17, 0, PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_1HA_DDRIO0, 1) }, { PCI_DESCR(PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_1HA_DDRIO0, 1) },
{ PCI_DESCR(17, 4, PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_2HA_DDRIO0, 1) }, { PCI_DESCR(PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_2HA_DDRIO0, 1) },
}; };
static const struct pci_id_table pci_dev_descr_ibridge_table[] = { static const struct pci_id_table pci_dev_descr_ibridge_table[] = {
...@@ -458,12 +458,80 @@ static const struct pci_id_table pci_dev_descr_ibridge_table[] = { ...@@ -458,12 +458,80 @@ static const struct pci_id_table pci_dev_descr_ibridge_table[] = {
{0,} /* 0 terminated list. */ {0,} /* 0 terminated list. */
}; };
/* Haswell support */
/* EN processor:
* - 1 IMC
* - 3 DDR3 channels, 2 DPC per channel
* EP processor:
* - 1 or 2 IMC
* - 4 DDR4 channels, 3 DPC per channel
* EP 4S processor:
* - 2 IMC
* - 4 DDR4 channels, 3 DPC per channel
* EX processor:
* - 2 IMC
* - each IMC interfaces with a SMI 2 channel
* - each SMI channel interfaces with a scalable memory buffer
* - each scalable memory buffer supports 4 DDR3/DDR4 channels, 3 DPC
*/
#define HASWELL_DDRCRCLKCONTROLS 0xa10
#define HASWELL_HASYSDEFEATURE2 0x84
#define PCI_DEVICE_ID_INTEL_HASWELL_IMC_VTD_MISC 0x2f28
#define PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0 0x2fa0
#define PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA1 0x2f60
#define PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0_TA 0x2fa8
#define PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0_THERMAL 0x2f71
#define PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA1_TA 0x2f68
#define PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA1_THERMAL 0x2f79
#define PCI_DEVICE_ID_INTEL_HASWELL_IMC_CBO_SAD0 0x2ffc
#define PCI_DEVICE_ID_INTEL_HASWELL_IMC_CBO_SAD1 0x2ffd
#define PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0_TAD0 0x2faa
#define PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0_TAD1 0x2fab
#define PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0_TAD2 0x2fac
#define PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0_TAD3 0x2fad
#define PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA1_TAD0 0x2f6a
#define PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA1_TAD1 0x2f6b
#define PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA1_TAD2 0x2f6c
#define PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA1_TAD3 0x2f6d
#define PCI_DEVICE_ID_INTEL_HASWELL_IMC_DDRIO0 0x2fbd
static const struct pci_id_descr pci_dev_descr_haswell[] = {
/* first item must be the HA */
{ PCI_DESCR(PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0, 0) },
{ PCI_DESCR(PCI_DEVICE_ID_INTEL_HASWELL_IMC_CBO_SAD0, 0) },
{ PCI_DESCR(PCI_DEVICE_ID_INTEL_HASWELL_IMC_CBO_SAD1, 0) },
{ PCI_DESCR(PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA1, 1) },
{ PCI_DESCR(PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0_TA, 0) },
{ PCI_DESCR(PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0_THERMAL, 0) },
{ PCI_DESCR(PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0_TAD0, 0) },
{ PCI_DESCR(PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0_TAD1, 0) },
{ PCI_DESCR(PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0_TAD2, 1) },
{ PCI_DESCR(PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0_TAD3, 1) },
{ PCI_DESCR(PCI_DEVICE_ID_INTEL_HASWELL_IMC_DDRIO0, 1) },
{ PCI_DESCR(PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA1_TA, 1) },
{ PCI_DESCR(PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA1_THERMAL, 1) },
{ PCI_DESCR(PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA1_TAD0, 1) },
{ PCI_DESCR(PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA1_TAD1, 1) },
{ PCI_DESCR(PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA1_TAD2, 1) },
{ PCI_DESCR(PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA1_TAD3, 1) },
};
static const struct pci_id_table pci_dev_descr_haswell_table[] = {
PCI_ID_TABLE_ENTRY(pci_dev_descr_haswell),
{0,} /* 0 terminated list. */
};
/* /*
* pci_device_id table for which devices we are looking for * pci_device_id table for which devices we are looking for
*/ */
static const struct pci_device_id sbridge_pci_tbl[] = { static const struct pci_device_id sbridge_pci_tbl[] = {
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TA)}, {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TA)},
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TA)}, {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TA)},
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0)},
{0,} /* 0 terminated list. */ {0,} /* 0 terminated list. */
}; };
...@@ -472,13 +540,17 @@ static const struct pci_device_id sbridge_pci_tbl[] = { ...@@ -472,13 +540,17 @@ static const struct pci_device_id sbridge_pci_tbl[] = {
Ancillary status routines Ancillary status routines
****************************************************************************/ ****************************************************************************/
static inline int numrank(u32 mtr) static inline int numrank(enum type type, u32 mtr)
{ {
int ranks = (1 << RANK_CNT_BITS(mtr)); int ranks = (1 << RANK_CNT_BITS(mtr));
int max = 4;
if (ranks > 4) { if (type == HASWELL)
edac_dbg(0, "Invalid number of ranks: %d (max = 4) raw value = %x (%04x)\n", max = 8;
ranks, (unsigned int)RANK_CNT_BITS(mtr), mtr);
if (ranks > max) {
edac_dbg(0, "Invalid number of ranks: %d (max = %i) raw value = %x (%04x)\n",
ranks, max, (unsigned int)RANK_CNT_BITS(mtr), mtr);
return -EINVAL; return -EINVAL;
} }
...@@ -588,10 +660,107 @@ static u64 ibridge_get_tohm(struct sbridge_pvt *pvt) ...@@ -588,10 +660,107 @@ static u64 ibridge_get_tohm(struct sbridge_pvt *pvt)
return GET_TOHM(reg); return GET_TOHM(reg);
} }
static u64 rir_limit(u32 reg)
{
return ((u64)GET_BITFIELD(reg, 1, 10) << 29) | 0x1fffffff;
}
static enum mem_type get_memory_type(struct sbridge_pvt *pvt)
{
u32 reg;
enum mem_type mtype;
if (pvt->pci_ddrio) {
pci_read_config_dword(pvt->pci_ddrio, pvt->info.rankcfgr,
&reg);
if (GET_BITFIELD(reg, 11, 11))
/* FIXME: Can also be LRDIMM */
mtype = MEM_RDDR3;
else
mtype = MEM_DDR3;
} else
mtype = MEM_UNKNOWN;
return mtype;
}
static enum mem_type haswell_get_memory_type(struct sbridge_pvt *pvt)
{
u32 reg;
bool registered = false;
enum mem_type mtype = MEM_UNKNOWN;
if (!pvt->pci_ddrio)
goto out;
pci_read_config_dword(pvt->pci_ddrio,
HASWELL_DDRCRCLKCONTROLS, &reg);
/* Is_Rdimm */
if (GET_BITFIELD(reg, 16, 16))
registered = true;
pci_read_config_dword(pvt->pci_ta, MCMTR, &reg);
if (GET_BITFIELD(reg, 14, 14)) {
if (registered)
mtype = MEM_RDDR4;
else
mtype = MEM_DDR4;
} else {
if (registered)
mtype = MEM_RDDR3;
else
mtype = MEM_DDR3;
}
out:
return mtype;
}
static u8 get_node_id(struct sbridge_pvt *pvt)
{
u32 reg;
pci_read_config_dword(pvt->pci_br0, SAD_CONTROL, &reg);
return GET_BITFIELD(reg, 0, 2);
}
static u8 haswell_get_node_id(struct sbridge_pvt *pvt)
{
u32 reg;
pci_read_config_dword(pvt->pci_sad1, SAD_CONTROL, &reg);
return GET_BITFIELD(reg, 0, 3);
}
static u64 haswell_get_tolm(struct sbridge_pvt *pvt)
{
u32 reg;
pci_read_config_dword(pvt->info.pci_vtd, TOLM, &reg);
return (GET_BITFIELD(reg, 26, 31) << 26) | 0x1ffffff;
}
static u64 haswell_get_tohm(struct sbridge_pvt *pvt)
{
u64 rc;
u32 reg;
pci_read_config_dword(pvt->info.pci_vtd, HASWELL_TOHM_0, &reg);
rc = GET_BITFIELD(reg, 26, 31);
pci_read_config_dword(pvt->info.pci_vtd, HASWELL_TOHM_1, &reg);
rc = ((reg << 6) | rc) << 26;
return rc | 0x1ffffff;
}
static u64 haswell_rir_limit(u32 reg)
{
return (((u64)GET_BITFIELD(reg, 1, 11) + 1) << 29) - 1;
}
static inline u8 sad_pkg_socket(u8 pkg) static inline u8 sad_pkg_socket(u8 pkg)
{ {
/* on Ivy Bridge, nodeID is SASS, where A is HA and S is node id */ /* on Ivy Bridge, nodeID is SASS, where A is HA and S is node id */
return (pkg >> 3) | (pkg & 0x3); return ((pkg >> 3) << 2) | (pkg & 0x3);
} }
static inline u8 sad_pkg_ha(u8 pkg) static inline u8 sad_pkg_ha(u8 pkg)
...@@ -602,44 +771,43 @@ static inline u8 sad_pkg_ha(u8 pkg) ...@@ -602,44 +771,43 @@ static inline u8 sad_pkg_ha(u8 pkg)
/**************************************************************************** /****************************************************************************
Memory check routines Memory check routines
****************************************************************************/ ****************************************************************************/
static struct pci_dev *get_pdev_slot_func(u8 bus, unsigned slot, static struct pci_dev *get_pdev_same_bus(u8 bus, u32 id)
unsigned func)
{ {
struct sbridge_dev *sbridge_dev = get_sbridge_dev(bus); struct pci_dev *pdev = NULL;
int i;
if (!sbridge_dev)
return NULL;
for (i = 0; i < sbridge_dev->n_devs; i++) {
if (!sbridge_dev->pdev[i])
continue;
if (PCI_SLOT(sbridge_dev->pdev[i]->devfn) == slot && do {
PCI_FUNC(sbridge_dev->pdev[i]->devfn) == func) { pdev = pci_get_device(PCI_VENDOR_ID_INTEL, id, pdev);
edac_dbg(1, "Associated %02x.%02x.%d with %p\n", if (pdev && pdev->bus->number == bus)
bus, slot, func, sbridge_dev->pdev[i]); break;
return sbridge_dev->pdev[i]; } while (pdev);
}
}
return NULL; return pdev;
} }
/** /**
* check_if_ecc_is_active() - Checks if ECC is active * check_if_ecc_is_active() - Checks if ECC is active
* bus: Device bus * @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) static int check_if_ecc_is_active(const u8 bus, enum type type)
{ {
struct pci_dev *pdev = NULL; struct pci_dev *pdev = NULL;
u32 mcmtr; u32 mcmtr, id;
if (type == IVY_BRIDGE)
id = PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TA;
else if (type == HASWELL)
id = PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0_TA;
else
id = PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TA;
pdev = get_pdev_slot_func(bus, 15, 0); pdev = get_pdev_same_bus(bus, id);
if (!pdev) { if (!pdev) {
sbridge_printk(KERN_ERR, "Couldn't find PCI device " sbridge_printk(KERN_ERR, "Couldn't find PCI device "
"%2x.%02d.%d!!!\n", "%04x:%04x! on bus %02d\n",
bus, 15, 0); PCI_VENDOR_ID_INTEL, id, bus);
return -ENODEV; return -ENODEV;
} }
...@@ -661,11 +829,14 @@ static int get_dimm_config(struct mem_ctl_info *mci) ...@@ -661,11 +829,14 @@ static int get_dimm_config(struct mem_ctl_info *mci)
enum edac_type mode; enum edac_type mode;
enum mem_type mtype; enum mem_type mtype;
pci_read_config_dword(pvt->pci_br0, SAD_TARGET, &reg); if (pvt->info.type == HASWELL)
pci_read_config_dword(pvt->pci_sad1, SAD_TARGET, &reg);
else
pci_read_config_dword(pvt->pci_br0, SAD_TARGET, &reg);
pvt->sbridge_dev->source_id = SOURCE_ID(reg); pvt->sbridge_dev->source_id = SOURCE_ID(reg);
pci_read_config_dword(pvt->pci_br0, SAD_CONTROL, &reg); pvt->sbridge_dev->node_id = pvt->info.get_node_id(pvt);
pvt->sbridge_dev->node_id = NODE_ID(reg);
edac_dbg(0, "mc#%d: Node ID: %d, source ID: %d\n", edac_dbg(0, "mc#%d: Node ID: %d, source ID: %d\n",
pvt->sbridge_dev->mc, pvt->sbridge_dev->mc,
pvt->sbridge_dev->node_id, pvt->sbridge_dev->node_id,
...@@ -698,24 +869,18 @@ static int get_dimm_config(struct mem_ctl_info *mci) ...@@ -698,24 +869,18 @@ static int get_dimm_config(struct mem_ctl_info *mci)
pvt->is_close_pg = false; pvt->is_close_pg = false;
} }
if (pvt->pci_ddrio) { mtype = pvt->info.get_memory_type(pvt);
pci_read_config_dword(pvt->pci_ddrio, pvt->info.rankcfgr, if (mtype == MEM_RDDR3 || mtype == MEM_RDDR4)
&reg); edac_dbg(0, "Memory is registered\n");
if (IS_RDIMM_ENABLED(reg)) { else if (mtype == MEM_UNKNOWN)
/* FIXME: Can also be LRDIMM */
edac_dbg(0, "Memory is registered\n");
mtype = MEM_RDDR3;
} else {
edac_dbg(0, "Memory is unregistered\n");
mtype = MEM_DDR3;
}
} else {
edac_dbg(0, "Cannot determine memory type\n"); edac_dbg(0, "Cannot determine memory type\n");
mtype = MEM_UNKNOWN; else
} edac_dbg(0, "Memory is unregistered\n");
/* On all supported DDR3 DIMM types, there are 8 banks available */ if (mtype == MEM_DDR4 || MEM_RDDR4)
banks = 8; banks = 16;
else
banks = 8;
for (i = 0; i < NUM_CHANNELS; i++) { for (i = 0; i < NUM_CHANNELS; i++) {
u32 mtr; u32 mtr;
...@@ -729,11 +894,10 @@ static int get_dimm_config(struct mem_ctl_info *mci) ...@@ -729,11 +894,10 @@ static int get_dimm_config(struct mem_ctl_info *mci)
if (IS_DIMM_PRESENT(mtr)) { if (IS_DIMM_PRESENT(mtr)) {
pvt->channel[i].dimms++; pvt->channel[i].dimms++;
ranks = numrank(mtr); ranks = numrank(pvt->info.type, mtr);
rows = numrow(mtr); rows = numrow(mtr);
cols = numcol(mtr); cols = numcol(mtr);
/* DDR3 has 8 I/O banks */
size = ((u64)rows * cols * banks * ranks) >> (20 - 3); size = ((u64)rows * cols * banks * ranks) >> (20 - 3);
npages = MiB_TO_PAGES(size); npages = MiB_TO_PAGES(size);
...@@ -744,7 +908,17 @@ static int get_dimm_config(struct mem_ctl_info *mci) ...@@ -744,7 +908,17 @@ static int get_dimm_config(struct mem_ctl_info *mci)
dimm->nr_pages = npages; dimm->nr_pages = npages;
dimm->grain = 32; dimm->grain = 32;
dimm->dtype = (banks == 8) ? DEV_X8 : DEV_X4; switch (banks) {
case 16:
dimm->dtype = DEV_X16;
break;
case 8:
dimm->dtype = DEV_X8;
break;
case 4:
dimm->dtype = DEV_X4;
break;
}
dimm->mtype = mtype; dimm->mtype = mtype;
dimm->edac_mode = mode; dimm->edac_mode = mode;
snprintf(dimm->label, sizeof(dimm->label), snprintf(dimm->label, sizeof(dimm->label),
...@@ -887,7 +1061,7 @@ static void get_memory_layout(const struct mem_ctl_info *mci) ...@@ -887,7 +1061,7 @@ static void get_memory_layout(const struct mem_ctl_info *mci)
if (!IS_RIR_VALID(reg)) if (!IS_RIR_VALID(reg))
continue; continue;
tmp_mb = RIR_LIMIT(reg) >> 20; tmp_mb = pvt->info.rir_limit(reg) >> 20;
rir_way = 1 << RIR_WAY(reg); rir_way = 1 << RIR_WAY(reg);
mb = div_u64_rem(tmp_mb, 1000, &kb); mb = div_u64_rem(tmp_mb, 1000, &kb);
edac_dbg(0, "CH#%d RIR#%d, limit: %u.%03u GB (0x%016Lx), way: %d, reg=0x%08x\n", edac_dbg(0, "CH#%d RIR#%d, limit: %u.%03u GB (0x%016Lx), way: %d, reg=0x%08x\n",
...@@ -936,11 +1110,11 @@ static int get_memory_error_data(struct mem_ctl_info *mci, ...@@ -936,11 +1110,11 @@ static int get_memory_error_data(struct mem_ctl_info *mci,
struct mem_ctl_info *new_mci; struct mem_ctl_info *new_mci;
struct sbridge_pvt *pvt = mci->pvt_info; struct sbridge_pvt *pvt = mci->pvt_info;
struct pci_dev *pci_ha; struct pci_dev *pci_ha;
int n_rir, n_sads, n_tads, sad_way, sck_xch; int n_rir, n_sads, n_tads, sad_way, sck_xch;
int sad_interl, idx, base_ch; int sad_interl, idx, base_ch;
int interleave_mode; int interleave_mode, shiftup = 0;
unsigned sad_interleave[pvt->info.max_interleave]; unsigned sad_interleave[pvt->info.max_interleave];
u32 reg; u32 reg, dram_rule;
u8 ch_way, sck_way, pkg, sad_ha = 0; u8 ch_way, sck_way, pkg, sad_ha = 0;
u32 tad_offset; u32 tad_offset;
u32 rir_way; u32 rir_way;
...@@ -987,8 +1161,9 @@ static int get_memory_error_data(struct mem_ctl_info *mci, ...@@ -987,8 +1161,9 @@ static int get_memory_error_data(struct mem_ctl_info *mci,
sprintf(msg, "Can't discover the memory socket"); sprintf(msg, "Can't discover the memory socket");
return -EINVAL; return -EINVAL;
} }
*area_type = get_dram_attr(reg); dram_rule = reg;
interleave_mode = INTERLEAVE_MODE(reg); *area_type = get_dram_attr(dram_rule);
interleave_mode = INTERLEAVE_MODE(dram_rule);
pci_read_config_dword(pvt->pci_sad0, pvt->info.interleave_list[n_sads], pci_read_config_dword(pvt->pci_sad0, pvt->info.interleave_list[n_sads],
&reg); &reg);
...@@ -1033,6 +1208,36 @@ static int get_memory_error_data(struct mem_ctl_info *mci, ...@@ -1033,6 +1208,36 @@ static int get_memory_error_data(struct mem_ctl_info *mci,
*socket = sad_interleave[idx]; *socket = sad_interleave[idx];
edac_dbg(0, "SAD interleave index: %d (wayness %d) = CPU socket %d\n", edac_dbg(0, "SAD interleave index: %d (wayness %d) = CPU socket %d\n",
idx, sad_way, *socket); idx, sad_way, *socket);
} else if (pvt->info.type == HASWELL) {
int bits, a7mode = A7MODE(dram_rule);
if (a7mode) {
/* A7 mode swaps P9 with P6 */
bits = GET_BITFIELD(addr, 7, 8) << 1;
bits |= GET_BITFIELD(addr, 9, 9);
} else
bits = GET_BITFIELD(addr, 7, 9);
if (interleave_mode) {
/* interleave mode will XOR {8,7,6} with {18,17,16} */
idx = GET_BITFIELD(addr, 16, 18);
idx ^= bits;
} else
idx = bits;
pkg = sad_pkg(pvt->info.interleave_pkg, reg, idx);
*socket = sad_pkg_socket(pkg);
sad_ha = sad_pkg_ha(pkg);
if (a7mode) {
/* MCChanShiftUpEnable */
pci_read_config_dword(pvt->pci_ha0,
HASWELL_HASYSDEFEATURE2, &reg);
shiftup = GET_BITFIELD(reg, 22, 22);
}
edac_dbg(0, "SAD interleave package: %d = CPU socket %d, HA %i, shiftup: %i\n",
idx, *socket, sad_ha, shiftup);
} else { } else {
/* Ivy Bridge's SAD mode doesn't support XOR interleave mode */ /* Ivy Bridge's SAD mode doesn't support XOR interleave mode */
idx = (addr >> 6) & 7; idx = (addr >> 6) & 7;
...@@ -1090,7 +1295,7 @@ static int get_memory_error_data(struct mem_ctl_info *mci, ...@@ -1090,7 +1295,7 @@ static int get_memory_error_data(struct mem_ctl_info *mci,
if (ch_way == 3) if (ch_way == 3)
idx = addr >> 6; idx = addr >> 6;
else else
idx = addr >> (6 + sck_way); idx = (addr >> (6 + sck_way + shiftup)) & 0x3;
idx = idx % ch_way; idx = idx % ch_way;
/* /*
...@@ -1181,7 +1386,7 @@ static int get_memory_error_data(struct mem_ctl_info *mci, ...@@ -1181,7 +1386,7 @@ static int get_memory_error_data(struct mem_ctl_info *mci,
if (!IS_RIR_VALID(reg)) if (!IS_RIR_VALID(reg))
continue; continue;
limit = RIR_LIMIT(reg); limit = pvt->info.rir_limit(reg);
mb = div_u64_rem(limit >> 20, 1000, &kb); mb = div_u64_rem(limit >> 20, 1000, &kb);
edac_dbg(0, "RIR#%d, limit: %u.%03u GB (0x%016Lx), way: %d\n", edac_dbg(0, "RIR#%d, limit: %u.%03u GB (0x%016Lx), way: %d\n",
n_rir, n_rir,
...@@ -1197,6 +1402,7 @@ static int get_memory_error_data(struct mem_ctl_info *mci, ...@@ -1197,6 +1402,7 @@ static int get_memory_error_data(struct mem_ctl_info *mci,
return -EINVAL; return -EINVAL;
} }
rir_way = RIR_WAY(reg); rir_way = RIR_WAY(reg);
if (pvt->is_close_pg) if (pvt->is_close_pg)
idx = (ch_addr >> 6); idx = (ch_addr >> 6);
else else
...@@ -1259,13 +1465,11 @@ static int sbridge_get_onedevice(struct pci_dev **prev, ...@@ -1259,13 +1465,11 @@ static int sbridge_get_onedevice(struct pci_dev **prev,
{ {
struct sbridge_dev *sbridge_dev; struct sbridge_dev *sbridge_dev;
const struct pci_id_descr *dev_descr = &table->descr[devno]; const struct pci_id_descr *dev_descr = &table->descr[devno];
struct pci_dev *pdev = NULL; struct pci_dev *pdev = NULL;
u8 bus = 0; u8 bus = 0;
sbridge_printk(KERN_DEBUG, sbridge_printk(KERN_DEBUG,
"Seeking for: dev %02x.%d PCI ID %04x:%04x\n", "Seeking for: PCI ID %04x:%04x\n",
dev_descr->dev, dev_descr->func,
PCI_VENDOR_ID_INTEL, dev_descr->dev_id); PCI_VENDOR_ID_INTEL, dev_descr->dev_id);
pdev = pci_get_device(PCI_VENDOR_ID_INTEL, pdev = pci_get_device(PCI_VENDOR_ID_INTEL,
...@@ -1280,12 +1484,12 @@ static int sbridge_get_onedevice(struct pci_dev **prev, ...@@ -1280,12 +1484,12 @@ static int sbridge_get_onedevice(struct pci_dev **prev,
if (dev_descr->optional) if (dev_descr->optional)
return 0; return 0;
/* if the HA wasn't found */
if (devno == 0) if (devno == 0)
return -ENODEV; return -ENODEV;
sbridge_printk(KERN_INFO, sbridge_printk(KERN_INFO,
"Device not found: dev %02x.%d PCI ID %04x:%04x\n", "Device not found: %04x:%04x\n",
dev_descr->dev, dev_descr->func,
PCI_VENDOR_ID_INTEL, dev_descr->dev_id); PCI_VENDOR_ID_INTEL, dev_descr->dev_id);
/* End of list, leave */ /* End of list, leave */
...@@ -1305,9 +1509,7 @@ static int sbridge_get_onedevice(struct pci_dev **prev, ...@@ -1305,9 +1509,7 @@ static int sbridge_get_onedevice(struct pci_dev **prev,
if (sbridge_dev->pdev[devno]) { if (sbridge_dev->pdev[devno]) {
sbridge_printk(KERN_ERR, sbridge_printk(KERN_ERR,
"Duplicated device for " "Duplicated device for %04x:%04x\n",
"dev %02x:%d.%d PCI ID %04x:%04x\n",
bus, dev_descr->dev, dev_descr->func,
PCI_VENDOR_ID_INTEL, dev_descr->dev_id); PCI_VENDOR_ID_INTEL, dev_descr->dev_id);
pci_dev_put(pdev); pci_dev_put(pdev);
return -ENODEV; return -ENODEV;
...@@ -1315,30 +1517,15 @@ static int sbridge_get_onedevice(struct pci_dev **prev, ...@@ -1315,30 +1517,15 @@ static int sbridge_get_onedevice(struct pci_dev **prev,
sbridge_dev->pdev[devno] = pdev; sbridge_dev->pdev[devno] = pdev;
/* Sanity check */
if (unlikely(PCI_SLOT(pdev->devfn) != dev_descr->dev ||
PCI_FUNC(pdev->devfn) != dev_descr->func)) {
sbridge_printk(KERN_ERR,
"Device PCI ID %04x:%04x "
"has dev %02x:%d.%d instead of dev %02x:%02x.%d\n",
PCI_VENDOR_ID_INTEL, dev_descr->dev_id,
bus, PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn),
bus, dev_descr->dev, dev_descr->func);
return -ENODEV;
}
/* Be sure that the device is enabled */ /* Be sure that the device is enabled */
if (unlikely(pci_enable_device(pdev) < 0)) { if (unlikely(pci_enable_device(pdev) < 0)) {
sbridge_printk(KERN_ERR, sbridge_printk(KERN_ERR,
"Couldn't enable " "Couldn't enable %04x:%04x\n",
"dev %02x:%d.%d PCI ID %04x:%04x\n",
bus, dev_descr->dev, dev_descr->func,
PCI_VENDOR_ID_INTEL, dev_descr->dev_id); PCI_VENDOR_ID_INTEL, dev_descr->dev_id);
return -ENODEV; return -ENODEV;
} }
edac_dbg(0, "Detected dev %02x:%d.%d PCI ID %04x:%04x\n", edac_dbg(0, "Detected %04x:%04x\n",
bus, dev_descr->dev, dev_descr->func,
PCI_VENDOR_ID_INTEL, dev_descr->dev_id); PCI_VENDOR_ID_INTEL, dev_descr->dev_id);
/* /*
...@@ -1355,10 +1542,9 @@ static int sbridge_get_onedevice(struct pci_dev **prev, ...@@ -1355,10 +1542,9 @@ static int sbridge_get_onedevice(struct pci_dev **prev,
/* /*
* sbridge_get_all_devices - Find and perform 'get' operation on the MCH's * sbridge_get_all_devices - Find and perform 'get' operation on the MCH's
* device/functions we want to reference for this driver. * devices we want to reference for this driver.
* Need to 'get' device 16 func 1 and func 2.
* @num_mc: pointer to the memory controllers count, to be incremented in case * @num_mc: pointer to the memory controllers count, to be incremented in case
* of success. * of success.
* @table: model specific table * @table: model specific table
* *
* returns 0 in case of success or error code * returns 0 in case of success or error code
...@@ -1396,79 +1582,51 @@ static int sbridge_mci_bind_devs(struct mem_ctl_info *mci, ...@@ -1396,79 +1582,51 @@ static int sbridge_mci_bind_devs(struct mem_ctl_info *mci,
{ {
struct sbridge_pvt *pvt = mci->pvt_info; struct sbridge_pvt *pvt = mci->pvt_info;
struct pci_dev *pdev; struct pci_dev *pdev;
int i, func, slot; int i;
for (i = 0; i < sbridge_dev->n_devs; i++) { for (i = 0; i < sbridge_dev->n_devs; i++) {
pdev = sbridge_dev->pdev[i]; pdev = sbridge_dev->pdev[i];
if (!pdev) if (!pdev)
continue; continue;
slot = PCI_SLOT(pdev->devfn);
func = PCI_FUNC(pdev->devfn); switch (pdev->device) {
switch (slot) { case PCI_DEVICE_ID_INTEL_SBRIDGE_SAD0:
case 12: pvt->pci_sad0 = pdev;
switch (func) {
case 6:
pvt->pci_sad0 = pdev;
break;
case 7:
pvt->pci_sad1 = pdev;
break;
default:
goto error;
}
break; break;
case 13: case PCI_DEVICE_ID_INTEL_SBRIDGE_SAD1:
switch (func) { pvt->pci_sad1 = pdev;
case 6:
pvt->pci_br0 = pdev;
break;
default:
goto error;
}
break; break;
case 14: case PCI_DEVICE_ID_INTEL_SBRIDGE_BR:
switch (func) { pvt->pci_br0 = pdev;
case 0:
pvt->pci_ha0 = pdev;
break;
default:
goto error;
}
break; break;
case 15: case PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_HA0:
switch (func) { pvt->pci_ha0 = pdev;
case 0:
pvt->pci_ta = pdev;
break;
case 1:
pvt->pci_ras = pdev;
break;
case 2:
case 3:
case 4:
case 5:
pvt->pci_tad[func - 2] = pdev;
break;
default:
goto error;
}
break; break;
case 17: case PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TA:
switch (func) { pvt->pci_ta = pdev;
case 0: break;
pvt->pci_ddrio = pdev; case PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_RAS:
break; pvt->pci_ras = pdev;
default: break;
goto error; case PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TAD0:
} case PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TAD1:
case PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TAD2:
case PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TAD3:
{
int id = pdev->device - PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TAD0;
pvt->pci_tad[id] = pdev;
}
break;
case PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_DDRIO:
pvt->pci_ddrio = pdev;
break; break;
default: default:
goto error; goto error;
} }
edac_dbg(0, "Associated PCI %02x.%02d.%d with dev = %p\n", edac_dbg(0, "Associated PCI %02x:%02x, bus %d with dev = %p\n",
pdev->vendor, pdev->device,
sbridge_dev->bus, sbridge_dev->bus,
PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn),
pdev); pdev);
} }
...@@ -1488,9 +1646,8 @@ static int sbridge_mci_bind_devs(struct mem_ctl_info *mci, ...@@ -1488,9 +1646,8 @@ static int sbridge_mci_bind_devs(struct mem_ctl_info *mci,
return -ENODEV; return -ENODEV;
error: error:
sbridge_printk(KERN_ERR, "Device %d, function %d " sbridge_printk(KERN_ERR, "Unexpected device %02x:%02x\n",
"is out of the expected range\n", PCI_VENDOR_ID_INTEL, pdev->device);
slot, func);
return -EINVAL; return -EINVAL;
} }
...@@ -1499,7 +1656,7 @@ static int ibridge_mci_bind_devs(struct mem_ctl_info *mci, ...@@ -1499,7 +1656,7 @@ static int ibridge_mci_bind_devs(struct mem_ctl_info *mci,
{ {
struct sbridge_pvt *pvt = mci->pvt_info; struct sbridge_pvt *pvt = mci->pvt_info;
struct pci_dev *pdev, *tmp; struct pci_dev *pdev, *tmp;
int i, func, slot; int i;
bool mode_2ha = false; bool mode_2ha = false;
tmp = pci_get_device(PCI_VENDOR_ID_INTEL, tmp = pci_get_device(PCI_VENDOR_ID_INTEL,
...@@ -1513,79 +1670,60 @@ static int ibridge_mci_bind_devs(struct mem_ctl_info *mci, ...@@ -1513,79 +1670,60 @@ static int ibridge_mci_bind_devs(struct mem_ctl_info *mci,
pdev = sbridge_dev->pdev[i]; pdev = sbridge_dev->pdev[i];
if (!pdev) if (!pdev)
continue; continue;
slot = PCI_SLOT(pdev->devfn);
func = PCI_FUNC(pdev->devfn);
switch (slot) { switch (pdev->device) {
case 14: case PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0:
if (func == 0) { pvt->pci_ha0 = pdev;
pvt->pci_ha0 = pdev; break;
break; case PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TA:
} pvt->pci_ta = pdev;
goto error; case PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_RAS:
case 15: pvt->pci_ras = pdev;
switch (func) { break;
case 0: case PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TAD2:
pvt->pci_ta = pdev; case PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TAD3:
break; /* if we have 2 HAs active, channels 2 and 3
case 1: * are in other device */
pvt->pci_ras = pdev; if (mode_2ha)
break;
case 4:
case 5:
/* if we have 2 HAs active, channels 2 and 3
* are in other device */
if (mode_2ha)
break;
/* fall through */
case 2:
case 3:
pvt->pci_tad[func - 2] = pdev;
break; break;
default: /* fall through */
goto error; case PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TAD0:
} case PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TAD1:
{
int id = pdev->device - PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TAD0;
pvt->pci_tad[id] = pdev;
}
break; break;
case 17: case PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_2HA_DDRIO0:
if (func == 4) { pvt->pci_ddrio = pdev;
break;
case PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_1HA_DDRIO0:
if (!mode_2ha)
pvt->pci_ddrio = pdev; pvt->pci_ddrio = pdev;
break;
} else if (func == 0) {
if (!mode_2ha)
pvt->pci_ddrio = pdev;
break;
}
goto error;
case 22:
switch (func) {
case 0:
pvt->pci_sad0 = pdev;
break;
case 1:
pvt->pci_br0 = pdev;
break;
case 2:
pvt->pci_br1 = pdev;
break;
default:
goto error;
}
break; break;
case 28: case PCI_DEVICE_ID_INTEL_IBRIDGE_SAD:
if (func == 0) { pvt->pci_sad0 = pdev;
pvt->pci_ha1 = pdev; break;
break; case PCI_DEVICE_ID_INTEL_IBRIDGE_BR0:
} pvt->pci_br0 = pdev;
goto error; break;
case 29: case PCI_DEVICE_ID_INTEL_IBRIDGE_BR1:
pvt->pci_br1 = pdev;
break;
case PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA1:
pvt->pci_ha1 = pdev;
break;
case PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA1_TAD0:
case PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA1_TAD1:
{
int id = pdev->device - PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA1_TAD0 + 2;
/* we shouldn't have this device if we have just one /* we shouldn't have this device if we have just one
* HA present */ * HA present */
WARN_ON(!mode_2ha); WARN_ON(!mode_2ha);
if (func == 2 || func == 3) { pvt->pci_tad[id] = pdev;
pvt->pci_tad[func] = pdev; }
break; break;
}
goto error;
default: default:
goto error; goto error;
} }
...@@ -1614,11 +1752,111 @@ static int ibridge_mci_bind_devs(struct mem_ctl_info *mci, ...@@ -1614,11 +1752,111 @@ static int ibridge_mci_bind_devs(struct mem_ctl_info *mci,
error: error:
sbridge_printk(KERN_ERR, sbridge_printk(KERN_ERR,
"Device %d, function %d is out of the expected range\n", "Unexpected device %02x:%02x\n", PCI_VENDOR_ID_INTEL,
slot, func); pdev->device);
return -EINVAL; return -EINVAL;
} }
static int haswell_mci_bind_devs(struct mem_ctl_info *mci,
struct sbridge_dev *sbridge_dev)
{
struct sbridge_pvt *pvt = mci->pvt_info;
struct pci_dev *pdev, *tmp;
int i;
bool mode_2ha = false;
tmp = pci_get_device(PCI_VENDOR_ID_INTEL,
PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA1, NULL);
if (tmp) {
mode_2ha = true;
pci_dev_put(tmp);
}
/* there's only one device per system; not tied to any bus */
if (pvt->info.pci_vtd == NULL)
/* result will be checked later */
pvt->info.pci_vtd = pci_get_device(PCI_VENDOR_ID_INTEL,
PCI_DEVICE_ID_INTEL_HASWELL_IMC_VTD_MISC,
NULL);
for (i = 0; i < sbridge_dev->n_devs; i++) {
pdev = sbridge_dev->pdev[i];
if (!pdev)
continue;
switch (pdev->device) {
case PCI_DEVICE_ID_INTEL_HASWELL_IMC_CBO_SAD0:
pvt->pci_sad0 = pdev;
break;
case PCI_DEVICE_ID_INTEL_HASWELL_IMC_CBO_SAD1:
pvt->pci_sad1 = pdev;
break;
case PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0:
pvt->pci_ha0 = pdev;
break;
case PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0_TA:
pvt->pci_ta = pdev;
break;
case PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0_THERMAL:
pvt->pci_ras = pdev;
break;
case PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0_TAD0:
pvt->pci_tad[0] = pdev;
break;
case PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0_TAD1:
pvt->pci_tad[1] = pdev;
break;
case PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0_TAD2:
if (!mode_2ha)
pvt->pci_tad[2] = pdev;
break;
case PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0_TAD3:
if (!mode_2ha)
pvt->pci_tad[3] = pdev;
break;
case PCI_DEVICE_ID_INTEL_HASWELL_IMC_DDRIO0:
pvt->pci_ddrio = pdev;
break;
case PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA1:
pvt->pci_ha1 = pdev;
break;
case PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA1_TA:
pvt->pci_ha1_ta = pdev;
break;
case PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA1_TAD0:
if (mode_2ha)
pvt->pci_tad[2] = pdev;
break;
case PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA1_TAD1:
if (mode_2ha)
pvt->pci_tad[3] = pdev;
break;
default:
break;
}
edac_dbg(0, "Associated PCI %02x.%02d.%d with dev = %p\n",
sbridge_dev->bus,
PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn),
pdev);
}
/* Check if everything were registered */
if (!pvt->pci_sad0 || !pvt->pci_ha0 || !pvt->pci_sad1 ||
!pvt->pci_ras || !pvt->pci_ta || !pvt->info.pci_vtd)
goto enodev;
for (i = 0; i < NUM_CHANNELS; i++) {
if (!pvt->pci_tad[i])
goto enodev;
}
return 0;
enodev:
sbridge_printk(KERN_ERR, "Some needed devices are missing\n");
return -ENODEV;
}
/**************************************************************************** /****************************************************************************
Error check routines Error check routines
****************************************************************************/ ****************************************************************************/
...@@ -1736,6 +1974,9 @@ static void sbridge_mce_output_error(struct mem_ctl_info *mci, ...@@ -1736,6 +1974,9 @@ static void sbridge_mce_output_error(struct mem_ctl_info *mci,
* EDAC core should be handling the channel mask, in order to point * EDAC core should be handling the channel mask, in order to point
* to the group of dimm's where the error may be happening. * to the group of dimm's where the error may be happening.
*/ */
if (!pvt->is_lockstep && !pvt->is_mirrored && !pvt->is_close_pg)
channel = first_channel;
snprintf(msg, sizeof(msg), snprintf(msg, sizeof(msg),
"%s%s area:%s err_code:%04x:%04x socket:%d channel_mask:%ld rank:%d", "%s%s area:%s err_code:%04x:%04x socket:%d channel_mask:%ld rank:%d",
overflow ? " OVERFLOW" : "", overflow ? " OVERFLOW" : "",
...@@ -1865,10 +2106,6 @@ static int sbridge_mce_check_error(struct notifier_block *nb, unsigned long val, ...@@ -1865,10 +2106,6 @@ static int sbridge_mce_check_error(struct notifier_block *nb, unsigned long val,
"%u APIC %x\n", mce->cpuvendor, mce->cpuid, "%u APIC %x\n", mce->cpuvendor, mce->cpuid,
mce->time, mce->socketid, mce->apicid); mce->time, mce->socketid, mce->apicid);
/* Only handle if it is the right mc controller */
if (cpu_data(mce->cpu).phys_proc_id != pvt->sbridge_dev->mc)
return NOTIFY_DONE;
smp_rmb(); smp_rmb();
if ((pvt->mce_out + 1) % MCE_LOG_LEN == pvt->mce_in) { if ((pvt->mce_out + 1) % MCE_LOG_LEN == pvt->mce_in) {
smp_wmb(); smp_wmb();
...@@ -1932,7 +2169,7 @@ static int sbridge_register_mci(struct sbridge_dev *sbridge_dev, enum type type) ...@@ -1932,7 +2169,7 @@ static int sbridge_register_mci(struct sbridge_dev *sbridge_dev, enum type type)
int rc; int rc;
/* Check the number of active and not disabled channels */ /* Check the number of active and not disabled channels */
rc = check_if_ecc_is_active(sbridge_dev->bus); rc = check_if_ecc_is_active(sbridge_dev->bus, type);
if (unlikely(rc < 0)) if (unlikely(rc < 0))
return rc; return rc;
...@@ -1971,11 +2208,15 @@ static int sbridge_register_mci(struct sbridge_dev *sbridge_dev, enum type type) ...@@ -1971,11 +2208,15 @@ static int sbridge_register_mci(struct sbridge_dev *sbridge_dev, enum type type)
mci->edac_check = sbridge_check_error; mci->edac_check = sbridge_check_error;
pvt->info.type = type; pvt->info.type = type;
if (type == IVY_BRIDGE) { switch (type) {
case IVY_BRIDGE:
pvt->info.rankcfgr = IB_RANK_CFG_A; pvt->info.rankcfgr = IB_RANK_CFG_A;
pvt->info.get_tolm = ibridge_get_tolm; pvt->info.get_tolm = ibridge_get_tolm;
pvt->info.get_tohm = ibridge_get_tohm; pvt->info.get_tohm = ibridge_get_tohm;
pvt->info.dram_rule = ibridge_dram_rule; pvt->info.dram_rule = ibridge_dram_rule;
pvt->info.get_memory_type = get_memory_type;
pvt->info.get_node_id = get_node_id;
pvt->info.rir_limit = rir_limit;
pvt->info.max_sad = ARRAY_SIZE(ibridge_dram_rule); pvt->info.max_sad = ARRAY_SIZE(ibridge_dram_rule);
pvt->info.interleave_list = ibridge_interleave_list; pvt->info.interleave_list = ibridge_interleave_list;
pvt->info.max_interleave = ARRAY_SIZE(ibridge_interleave_list); pvt->info.max_interleave = ARRAY_SIZE(ibridge_interleave_list);
...@@ -1986,11 +2227,15 @@ static int sbridge_register_mci(struct sbridge_dev *sbridge_dev, enum type type) ...@@ -1986,11 +2227,15 @@ static int sbridge_register_mci(struct sbridge_dev *sbridge_dev, enum type type)
rc = ibridge_mci_bind_devs(mci, sbridge_dev); rc = ibridge_mci_bind_devs(mci, sbridge_dev);
if (unlikely(rc < 0)) if (unlikely(rc < 0))
goto fail0; goto fail0;
} else { break;
case SANDY_BRIDGE:
pvt->info.rankcfgr = SB_RANK_CFG_A; pvt->info.rankcfgr = SB_RANK_CFG_A;
pvt->info.get_tolm = sbridge_get_tolm; pvt->info.get_tolm = sbridge_get_tolm;
pvt->info.get_tohm = sbridge_get_tohm; pvt->info.get_tohm = sbridge_get_tohm;
pvt->info.dram_rule = sbridge_dram_rule; pvt->info.dram_rule = sbridge_dram_rule;
pvt->info.get_memory_type = get_memory_type;
pvt->info.get_node_id = get_node_id;
pvt->info.rir_limit = rir_limit;
pvt->info.max_sad = ARRAY_SIZE(sbridge_dram_rule); pvt->info.max_sad = ARRAY_SIZE(sbridge_dram_rule);
pvt->info.interleave_list = sbridge_interleave_list; pvt->info.interleave_list = sbridge_interleave_list;
pvt->info.max_interleave = ARRAY_SIZE(sbridge_interleave_list); pvt->info.max_interleave = ARRAY_SIZE(sbridge_interleave_list);
...@@ -2001,8 +2246,27 @@ static int sbridge_register_mci(struct sbridge_dev *sbridge_dev, enum type type) ...@@ -2001,8 +2246,27 @@ static int sbridge_register_mci(struct sbridge_dev *sbridge_dev, enum type type)
rc = sbridge_mci_bind_devs(mci, sbridge_dev); rc = sbridge_mci_bind_devs(mci, sbridge_dev);
if (unlikely(rc < 0)) if (unlikely(rc < 0))
goto fail0; goto fail0;
} break;
case HASWELL:
/* rankcfgr isn't used */
pvt->info.get_tolm = haswell_get_tolm;
pvt->info.get_tohm = haswell_get_tohm;
pvt->info.dram_rule = ibridge_dram_rule;
pvt->info.get_memory_type = haswell_get_memory_type;
pvt->info.get_node_id = haswell_get_node_id;
pvt->info.rir_limit = haswell_rir_limit;
pvt->info.max_sad = ARRAY_SIZE(ibridge_dram_rule);
pvt->info.interleave_list = ibridge_interleave_list;
pvt->info.max_interleave = ARRAY_SIZE(ibridge_interleave_list);
pvt->info.interleave_pkg = ibridge_interleave_pkg;
mci->ctl_name = kasprintf(GFP_KERNEL, "Haswell Socket#%d", mci->mc_idx);
/* Store pci devices at mci for faster access */
rc = haswell_mci_bind_devs(mci, sbridge_dev);
if (unlikely(rc < 0))
goto fail0;
break;
}
/* Get dimm basic config and the memory layout */ /* Get dimm basic config and the memory layout */
get_dimm_config(mci); get_dimm_config(mci);
...@@ -2037,10 +2301,10 @@ static int sbridge_register_mci(struct sbridge_dev *sbridge_dev, enum type type) ...@@ -2037,10 +2301,10 @@ static int sbridge_register_mci(struct sbridge_dev *sbridge_dev, enum type type)
static int sbridge_probe(struct pci_dev *pdev, const struct pci_device_id *id) static int sbridge_probe(struct pci_dev *pdev, const struct pci_device_id *id)
{ {
int rc; int rc = -ENODEV;
u8 mc, num_mc = 0; u8 mc, num_mc = 0;
struct sbridge_dev *sbridge_dev; struct sbridge_dev *sbridge_dev;
enum type type; enum type type = SANDY_BRIDGE;
/* get the pci devices we want to reserve for our use */ /* get the pci devices we want to reserve for our use */
mutex_lock(&sbridge_edac_lock); mutex_lock(&sbridge_edac_lock);
...@@ -2054,12 +2318,19 @@ static int sbridge_probe(struct pci_dev *pdev, const struct pci_device_id *id) ...@@ -2054,12 +2318,19 @@ static int sbridge_probe(struct pci_dev *pdev, const struct pci_device_id *id)
} }
probed++; probed++;
if (pdev->device == PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TA) { switch (pdev->device) {
case PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TA:
rc = sbridge_get_all_devices(&num_mc, pci_dev_descr_ibridge_table); rc = sbridge_get_all_devices(&num_mc, pci_dev_descr_ibridge_table);
type = IVY_BRIDGE; type = IVY_BRIDGE;
} else { break;
case PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TA:
rc = sbridge_get_all_devices(&num_mc, pci_dev_descr_sbridge_table); rc = sbridge_get_all_devices(&num_mc, pci_dev_descr_sbridge_table);
type = SANDY_BRIDGE; type = SANDY_BRIDGE;
break;
case PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0:
rc = sbridge_get_all_devices(&num_mc, pci_dev_descr_haswell_table);
type = HASWELL;
break;
} }
if (unlikely(rc < 0)) if (unlikely(rc < 0))
goto fail0; goto fail0;
...@@ -2068,6 +2339,7 @@ static int sbridge_probe(struct pci_dev *pdev, const struct pci_device_id *id) ...@@ -2068,6 +2339,7 @@ static int sbridge_probe(struct pci_dev *pdev, const struct pci_device_id *id)
list_for_each_entry(sbridge_dev, &sbridge_edac_list, list) { list_for_each_entry(sbridge_dev, &sbridge_edac_list, list) {
edac_dbg(0, "Registering MC#%d (%d of %d)\n", edac_dbg(0, "Registering MC#%d (%d of %d)\n",
mc, mc + 1, num_mc); mc, mc + 1, num_mc);
sbridge_dev->mc = mc++; sbridge_dev->mc = mc++;
rc = sbridge_register_mci(sbridge_dev, type); rc = sbridge_register_mci(sbridge_dev, type);
if (unlikely(rc < 0)) if (unlikely(rc < 0))
......
...@@ -194,6 +194,9 @@ static inline char *mc_event_error_type(const unsigned int err_type) ...@@ -194,6 +194,9 @@ static inline char *mc_event_error_type(const unsigned int err_type)
* @MEM_DDR3: DDR3 RAM * @MEM_DDR3: DDR3 RAM
* @MEM_RDDR3: Registered DDR3 RAM * @MEM_RDDR3: Registered DDR3 RAM
* This is a variant of the DDR3 memories. * This is a variant of the DDR3 memories.
* @MEM_DDR4: DDR4 RAM
* @MEM_RDDR4: Registered DDR4 RAM
* This is a variant of the DDR4 memories.
*/ */
enum mem_type { enum mem_type {
MEM_EMPTY = 0, MEM_EMPTY = 0,
...@@ -213,6 +216,8 @@ enum mem_type { ...@@ -213,6 +216,8 @@ enum mem_type {
MEM_XDR, MEM_XDR,
MEM_DDR3, MEM_DDR3,
MEM_RDDR3, MEM_RDDR3,
MEM_DDR4,
MEM_RDDR4,
}; };
#define MEM_FLAG_EMPTY BIT(MEM_EMPTY) #define MEM_FLAG_EMPTY BIT(MEM_EMPTY)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment