diff options
author | Tony Luck <tony.luck@intel.com> | 2016-04-14 13:22:02 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@kernel.org> | 2016-04-22 04:10:01 -0400 |
commit | ea5dfb5fae81939f777ca569d8cfb599252da2e8 (patch) | |
tree | ad877f65ffb0a4090d17a78069212c8d75662730 /drivers/edac | |
parent | ff15e95c82768d589957dbb17d7eb7dba7904659 (diff) |
x86 EDAC, sb_edac.c: Take account of channel hashing when needed
Haswell and Broadwell can be configured to hash the channel
interleave function using bits [27:12] of the physical address.
On those processor models we must check to see if hashing is
enabled (bit21 of the HASWELL_HASYSDEFEATURE2 register) and
act accordingly.
Based on a patch by patrickg <patrickg@supermicro.com>
Tested-by: Patrick Geary <patrickg@supermicro.com>
Signed-off-by: Tony Luck <tony.luck@intel.com>
Acked-by: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
Cc: Aristeu Rozanski <arozansk@redhat.com>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: linux-edac@vger.kernel.org
Cc: stable@vger.kernel.org
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'drivers/edac')
-rw-r--r-- | drivers/edac/sb_edac.c | 24 |
1 files changed, 23 insertions, 1 deletions
diff --git a/drivers/edac/sb_edac.c b/drivers/edac/sb_edac.c index f4666b0aeba6..468447aff8eb 100644 --- a/drivers/edac/sb_edac.c +++ b/drivers/edac/sb_edac.c | |||
@@ -362,6 +362,7 @@ struct sbridge_pvt { | |||
362 | 362 | ||
363 | /* Memory type detection */ | 363 | /* Memory type detection */ |
364 | bool is_mirrored, is_lockstep, is_close_pg; | 364 | bool is_mirrored, is_lockstep, is_close_pg; |
365 | bool is_chan_hash; | ||
365 | 366 | ||
366 | /* Fifo double buffers */ | 367 | /* Fifo double buffers */ |
367 | struct mce mce_entry[MCE_LOG_LEN]; | 368 | struct mce mce_entry[MCE_LOG_LEN]; |
@@ -1060,6 +1061,20 @@ static inline u8 sad_pkg_ha(u8 pkg) | |||
1060 | return (pkg >> 2) & 0x1; | 1061 | return (pkg >> 2) & 0x1; |
1061 | } | 1062 | } |
1062 | 1063 | ||
1064 | static int haswell_chan_hash(int idx, u64 addr) | ||
1065 | { | ||
1066 | int i; | ||
1067 | |||
1068 | /* | ||
1069 | * XOR even bits from 12:26 to bit0 of idx, | ||
1070 | * odd bits from 13:27 to bit1 | ||
1071 | */ | ||
1072 | for (i = 12; i < 28; i += 2) | ||
1073 | idx ^= (addr >> i) & 3; | ||
1074 | |||
1075 | return idx; | ||
1076 | } | ||
1077 | |||
1063 | /**************************************************************************** | 1078 | /**************************************************************************** |
1064 | Memory check routines | 1079 | Memory check routines |
1065 | ****************************************************************************/ | 1080 | ****************************************************************************/ |
@@ -1616,6 +1631,10 @@ static int get_dimm_config(struct mem_ctl_info *mci) | |||
1616 | KNL_MAX_CHANNELS : NUM_CHANNELS; | 1631 | KNL_MAX_CHANNELS : NUM_CHANNELS; |
1617 | u64 knl_mc_sizes[KNL_MAX_CHANNELS]; | 1632 | u64 knl_mc_sizes[KNL_MAX_CHANNELS]; |
1618 | 1633 | ||
1634 | if (pvt->info.type == HASWELL || pvt->info.type == BROADWELL) { | ||
1635 | pci_read_config_dword(pvt->pci_ha0, HASWELL_HASYSDEFEATURE2, ®); | ||
1636 | pvt->is_chan_hash = GET_BITFIELD(reg, 21, 21); | ||
1637 | } | ||
1619 | if (pvt->info.type == HASWELL || pvt->info.type == BROADWELL || | 1638 | if (pvt->info.type == HASWELL || pvt->info.type == BROADWELL || |
1620 | pvt->info.type == KNIGHTS_LANDING) | 1639 | pvt->info.type == KNIGHTS_LANDING) |
1621 | pci_read_config_dword(pvt->pci_sad1, SAD_TARGET, ®); | 1640 | pci_read_config_dword(pvt->pci_sad1, SAD_TARGET, ®); |
@@ -2122,8 +2141,11 @@ static int get_memory_error_data(struct mem_ctl_info *mci, | |||
2122 | 2141 | ||
2123 | if (ch_way == 3) | 2142 | if (ch_way == 3) |
2124 | idx = addr >> 6; | 2143 | idx = addr >> 6; |
2125 | else | 2144 | else { |
2126 | idx = (addr >> (6 + sck_way + shiftup)) & 0x3; | 2145 | idx = (addr >> (6 + sck_way + shiftup)) & 0x3; |
2146 | if (pvt->is_chan_hash) | ||
2147 | idx = haswell_chan_hash(idx, addr); | ||
2148 | } | ||
2127 | idx = idx % ch_way; | 2149 | idx = idx % ch_way; |
2128 | 2150 | ||
2129 | /* | 2151 | /* |