diff options
author | Aristeu Rozanski <aris@redhat.com> | 2014-06-02 14:15:22 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <m.chehab@samsung.com> | 2014-06-26 14:23:46 -0400 |
commit | 9e3754461507147ce5bffba5faaea7c182d64667 (patch) | |
tree | d681cc004f0dba3bb105702f5693e202a7778582 | |
parent | a497c3ba1d97fc69c1e78e7b96435ba8c2cb42ee (diff) |
sb_edac: make memory type detection per memory controller
Haswell has different register, offset to determine memory type and supports
DDR4 in some models. This patch makes it easier to have a different method
depending on the memory controller type.
Cc: Tony Luck <tony.luck@intel.com>
Signed-off-by: Aristeu Rozanski <aris@redhat.com>
Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
-rw-r--r-- | drivers/edac/sb_edac.c | 44 |
1 files changed, 28 insertions, 16 deletions
diff --git a/drivers/edac/sb_edac.c b/drivers/edac/sb_edac.c index deea0dc9999b..44336cb0a561 100644 --- a/drivers/edac/sb_edac.c +++ b/drivers/edac/sb_edac.c | |||
@@ -279,8 +279,6 @@ static const u32 correrrthrsld[] = { | |||
279 | 279 | ||
280 | #define IB_RANK_CFG_A 0x0320 | 280 | #define IB_RANK_CFG_A 0x0320 |
281 | 281 | ||
282 | #define IS_RDIMM_ENABLED(reg) GET_BITFIELD(reg, 11, 11) | ||
283 | |||
284 | /* | 282 | /* |
285 | * sbridge structs | 283 | * sbridge structs |
286 | */ | 284 | */ |
@@ -305,6 +303,7 @@ struct sbridge_info { | |||
305 | const struct interleave_pkg *interleave_pkg; | 303 | const struct interleave_pkg *interleave_pkg; |
306 | u8 max_sad; | 304 | u8 max_sad; |
307 | u8 max_interleave; | 305 | u8 max_interleave; |
306 | enum mem_type (*get_memory_type)(struct sbridge_pvt *pvt); | ||
308 | }; | 307 | }; |
309 | 308 | ||
310 | struct sbridge_channel { | 309 | struct sbridge_channel { |
@@ -588,6 +587,25 @@ static u64 ibridge_get_tohm(struct sbridge_pvt *pvt) | |||
588 | return GET_TOHM(reg); | 587 | return GET_TOHM(reg); |
589 | } | 588 | } |
590 | 589 | ||
590 | static enum mem_type get_memory_type(struct sbridge_pvt *pvt) | ||
591 | { | ||
592 | u32 reg; | ||
593 | enum mem_type mtype; | ||
594 | |||
595 | if (pvt->pci_ddrio) { | ||
596 | pci_read_config_dword(pvt->pci_ddrio, pvt->info.rankcfgr, | ||
597 | ®); | ||
598 | if (GET_BITFIELD(reg, 11, 11)) | ||
599 | /* FIXME: Can also be LRDIMM */ | ||
600 | mtype = MEM_RDDR3; | ||
601 | else | ||
602 | mtype = MEM_DDR3; | ||
603 | } else | ||
604 | mtype = MEM_UNKNOWN; | ||
605 | |||
606 | return mtype; | ||
607 | } | ||
608 | |||
591 | static inline u8 sad_pkg_socket(u8 pkg) | 609 | static inline u8 sad_pkg_socket(u8 pkg) |
592 | { | 610 | { |
593 | /* on Ivy Bridge, nodeID is SASS, where A is HA and S is node id */ | 611 | /* on Ivy Bridge, nodeID is SASS, where A is HA and S is node id */ |
@@ -698,21 +716,13 @@ static int get_dimm_config(struct mem_ctl_info *mci) | |||
698 | pvt->is_close_pg = false; | 716 | pvt->is_close_pg = false; |
699 | } | 717 | } |
700 | 718 | ||
701 | if (pvt->pci_ddrio) { | 719 | mtype = pvt->info.get_memory_type(pvt); |
702 | pci_read_config_dword(pvt->pci_ddrio, pvt->info.rankcfgr, | 720 | if (mtype == MEM_RDDR3) |
703 | ®); | 721 | edac_dbg(0, "Memory is registered\n"); |
704 | if (IS_RDIMM_ENABLED(reg)) { | 722 | else if (mtype == MEM_UNKNOWN) |
705 | /* FIXME: Can also be LRDIMM */ | ||
706 | edac_dbg(0, "Memory is registered\n"); | ||
707 | mtype = MEM_RDDR3; | ||
708 | } else { | ||
709 | edac_dbg(0, "Memory is unregistered\n"); | ||
710 | mtype = MEM_DDR3; | ||
711 | } | ||
712 | } else { | ||
713 | edac_dbg(0, "Cannot determine memory type\n"); | 723 | edac_dbg(0, "Cannot determine memory type\n"); |
714 | mtype = MEM_UNKNOWN; | 724 | else |
715 | } | 725 | edac_dbg(0, "Memory is unregistered\n"); |
716 | 726 | ||
717 | /* On all supported DDR3 DIMM types, there are 8 banks available */ | 727 | /* On all supported DDR3 DIMM types, there are 8 banks available */ |
718 | banks = 8; | 728 | banks = 8; |
@@ -1976,6 +1986,7 @@ static int sbridge_register_mci(struct sbridge_dev *sbridge_dev, enum type type) | |||
1976 | pvt->info.get_tolm = ibridge_get_tolm; | 1986 | pvt->info.get_tolm = ibridge_get_tolm; |
1977 | pvt->info.get_tohm = ibridge_get_tohm; | 1987 | pvt->info.get_tohm = ibridge_get_tohm; |
1978 | pvt->info.dram_rule = ibridge_dram_rule; | 1988 | pvt->info.dram_rule = ibridge_dram_rule; |
1989 | pvt->info.get_memory_type = get_memory_type; | ||
1979 | pvt->info.max_sad = ARRAY_SIZE(ibridge_dram_rule); | 1990 | pvt->info.max_sad = ARRAY_SIZE(ibridge_dram_rule); |
1980 | pvt->info.interleave_list = ibridge_interleave_list; | 1991 | pvt->info.interleave_list = ibridge_interleave_list; |
1981 | pvt->info.max_interleave = ARRAY_SIZE(ibridge_interleave_list); | 1992 | pvt->info.max_interleave = ARRAY_SIZE(ibridge_interleave_list); |
@@ -1991,6 +2002,7 @@ static int sbridge_register_mci(struct sbridge_dev *sbridge_dev, enum type type) | |||
1991 | pvt->info.get_tolm = sbridge_get_tolm; | 2002 | pvt->info.get_tolm = sbridge_get_tolm; |
1992 | pvt->info.get_tohm = sbridge_get_tohm; | 2003 | pvt->info.get_tohm = sbridge_get_tohm; |
1993 | pvt->info.dram_rule = sbridge_dram_rule; | 2004 | pvt->info.dram_rule = sbridge_dram_rule; |
2005 | pvt->info.get_memory_type = get_memory_type; | ||
1994 | pvt->info.max_sad = ARRAY_SIZE(sbridge_dram_rule); | 2006 | pvt->info.max_sad = ARRAY_SIZE(sbridge_dram_rule); |
1995 | pvt->info.interleave_list = sbridge_interleave_list; | 2007 | pvt->info.interleave_list = sbridge_interleave_list; |
1996 | pvt->info.max_interleave = ARRAY_SIZE(sbridge_interleave_list); | 2008 | pvt->info.max_interleave = ARRAY_SIZE(sbridge_interleave_list); |