diff options
author | Borislav Petkov <borislav.petkov@amd.com> | 2012-08-09 12:41:07 -0400 |
---|---|---|
committer | Borislav Petkov <bp@alien8.de> | 2012-11-28 05:45:01 -0500 |
commit | 66fed2d464157eb20c37738d75b281458dfc2cab (patch) | |
tree | 2ef45590cacc3c69d9901153f4dc1199e20b7fa1 | |
parent | 6e71a870b8ff2c1e2d89e5ea27a38cea39cefa3d (diff) |
amd64_edac: Improve error injection
When injecting DRAM ECC errors over the F3xB[8,C] interface, the machine
does this by injecting the error in the next non-cached access. This
takes relatively long time on a normal system so that in order for us to
expedite it, we disable the caches around the injection.
Signed-off-by: Borislav Petkov <borislav.petkov@amd.com>
-rw-r--r-- | drivers/edac/amd64_edac.c | 10 | ||||
-rw-r--r-- | drivers/edac/amd64_edac.h | 23 | ||||
-rw-r--r-- | drivers/edac/amd64_edac_inj.c | 18 |
3 files changed, 41 insertions, 10 deletions
diff --git a/drivers/edac/amd64_edac.c b/drivers/edac/amd64_edac.c index 5960a8a07fd2..351496af9e8d 100644 --- a/drivers/edac/amd64_edac.c +++ b/drivers/edac/amd64_edac.c | |||
@@ -60,8 +60,8 @@ struct scrubrate { | |||
60 | { 0x00, 0UL}, /* scrubbing off */ | 60 | { 0x00, 0UL}, /* scrubbing off */ |
61 | }; | 61 | }; |
62 | 62 | ||
63 | static int __amd64_read_pci_cfg_dword(struct pci_dev *pdev, int offset, | 63 | int __amd64_read_pci_cfg_dword(struct pci_dev *pdev, int offset, |
64 | u32 *val, const char *func) | 64 | u32 *val, const char *func) |
65 | { | 65 | { |
66 | int err = 0; | 66 | int err = 0; |
67 | 67 | ||
@@ -1980,11 +1980,11 @@ static void amd64_handle_ue(struct mem_ctl_info *mci, struct mce *m) | |||
1980 | static inline void __amd64_decode_bus_error(struct mem_ctl_info *mci, | 1980 | static inline void __amd64_decode_bus_error(struct mem_ctl_info *mci, |
1981 | struct mce *m) | 1981 | struct mce *m) |
1982 | { | 1982 | { |
1983 | u16 ec = EC(m->status); | ||
1984 | u8 xec = XEC(m->status, 0x1f); | ||
1985 | u8 ecc_type = (m->status >> 45) & 0x3; | 1983 | u8 ecc_type = (m->status >> 45) & 0x3; |
1984 | u8 xec = XEC(m->status, 0x1f); | ||
1985 | u16 ec = EC(m->status); | ||
1986 | 1986 | ||
1987 | /* Bail early out if this was an 'observed' error */ | 1987 | /* Bail out early if this was an 'observed' error */ |
1988 | if (PP(ec) == NBSL_PP_OBS) | 1988 | if (PP(ec) == NBSL_PP_OBS) |
1989 | return; | 1989 | return; |
1990 | 1990 | ||
diff --git a/drivers/edac/amd64_edac.h b/drivers/edac/amd64_edac.h index 19a12a4fbf45..cf7981e1f063 100644 --- a/drivers/edac/amd64_edac.h +++ b/drivers/edac/amd64_edac.h | |||
@@ -273,9 +273,10 @@ | |||
273 | #define SET_NB_ARRAY_ADDR(section) (((section) & 0x3) << 1) | 273 | #define SET_NB_ARRAY_ADDR(section) (((section) & 0x3) << 1) |
274 | 274 | ||
275 | #define F10_NB_ARRAY_DATA 0xBC | 275 | #define F10_NB_ARRAY_DATA 0xBC |
276 | #define F10_NB_ARR_ECC_WR_REQ BIT(17) | ||
276 | #define SET_NB_DRAM_INJECTION_WRITE(inj) \ | 277 | #define SET_NB_DRAM_INJECTION_WRITE(inj) \ |
277 | (BIT(((inj.word) & 0xF) + 20) | \ | 278 | (BIT(((inj.word) & 0xF) + 20) | \ |
278 | BIT(17) | inj.bit_map) | 279 | F10_NB_ARR_ECC_WR_REQ | inj.bit_map) |
279 | #define SET_NB_DRAM_INJECTION_READ(inj) \ | 280 | #define SET_NB_DRAM_INJECTION_READ(inj) \ |
280 | (BIT(((inj.word) & 0xF) + 20) | \ | 281 | (BIT(((inj.word) & 0xF) + 20) | \ |
281 | BIT(16) | inj.bit_map) | 282 | BIT(16) | inj.bit_map) |
@@ -306,9 +307,9 @@ enum amd_families { | |||
306 | 307 | ||
307 | /* Error injection control structure */ | 308 | /* Error injection control structure */ |
308 | struct error_injection { | 309 | struct error_injection { |
309 | u32 section; | 310 | u32 section; |
310 | u32 word; | 311 | u32 word; |
311 | u32 bit_map; | 312 | u32 bit_map; |
312 | }; | 313 | }; |
313 | 314 | ||
314 | /* low and high part of PCI config space regs */ | 315 | /* low and high part of PCI config space regs */ |
@@ -460,6 +461,8 @@ struct amd64_family_type { | |||
460 | struct low_ops ops; | 461 | struct low_ops ops; |
461 | }; | 462 | }; |
462 | 463 | ||
464 | int __amd64_read_pci_cfg_dword(struct pci_dev *pdev, int offset, | ||
465 | u32 *val, const char *func); | ||
463 | int __amd64_write_pci_cfg_dword(struct pci_dev *pdev, int offset, | 466 | int __amd64_write_pci_cfg_dword(struct pci_dev *pdev, int offset, |
464 | u32 val, const char *func); | 467 | u32 val, const char *func); |
465 | 468 | ||
@@ -476,3 +479,15 @@ int amd64_get_dram_hole_info(struct mem_ctl_info *mci, u64 *hole_base, | |||
476 | u64 *hole_offset, u64 *hole_size); | 479 | u64 *hole_offset, u64 *hole_size); |
477 | 480 | ||
478 | #define to_mci(k) container_of(k, struct mem_ctl_info, dev) | 481 | #define to_mci(k) container_of(k, struct mem_ctl_info, dev) |
482 | |||
483 | /* Injection helpers */ | ||
484 | static inline void disable_caches(void *dummy) | ||
485 | { | ||
486 | write_cr0(read_cr0() | X86_CR0_CD); | ||
487 | wbinvd(); | ||
488 | } | ||
489 | |||
490 | static inline void enable_caches(void *dummy) | ||
491 | { | ||
492 | write_cr0(read_cr0() & ~X86_CR0_CD); | ||
493 | } | ||
diff --git a/drivers/edac/amd64_edac_inj.c b/drivers/edac/amd64_edac_inj.c index 8977e2fa61da..8c171fa1cb9b 100644 --- a/drivers/edac/amd64_edac_inj.c +++ b/drivers/edac/amd64_edac_inj.c | |||
@@ -153,8 +153,8 @@ static ssize_t amd64_inject_write_store(struct device *dev, | |||
153 | { | 153 | { |
154 | struct mem_ctl_info *mci = to_mci(dev); | 154 | struct mem_ctl_info *mci = to_mci(dev); |
155 | struct amd64_pvt *pvt = mci->pvt_info; | 155 | struct amd64_pvt *pvt = mci->pvt_info; |
156 | u32 section, word_bits, tmp; | ||
156 | unsigned long value; | 157 | unsigned long value; |
157 | u32 section, word_bits; | ||
158 | int ret; | 158 | int ret; |
159 | 159 | ||
160 | ret = strict_strtoul(data, 10, &value); | 160 | ret = strict_strtoul(data, 10, &value); |
@@ -168,9 +168,25 @@ static ssize_t amd64_inject_write_store(struct device *dev, | |||
168 | 168 | ||
169 | word_bits = SET_NB_DRAM_INJECTION_WRITE(pvt->injection); | 169 | word_bits = SET_NB_DRAM_INJECTION_WRITE(pvt->injection); |
170 | 170 | ||
171 | pr_notice_once("Don't forget to decrease MCE polling interval in\n" | ||
172 | "/sys/bus/machinecheck/devices/machinecheck<CPUNUM>/check_interval\n" | ||
173 | "so that you can get the error report faster.\n"); | ||
174 | |||
175 | on_each_cpu(disable_caches, NULL, 1); | ||
176 | |||
171 | /* Issue 'word' and 'bit' along with the READ request */ | 177 | /* Issue 'word' and 'bit' along with the READ request */ |
172 | amd64_write_pci_cfg(pvt->F3, F10_NB_ARRAY_DATA, word_bits); | 178 | amd64_write_pci_cfg(pvt->F3, F10_NB_ARRAY_DATA, word_bits); |
173 | 179 | ||
180 | retry: | ||
181 | /* wait until injection happens */ | ||
182 | amd64_read_pci_cfg(pvt->F3, F10_NB_ARRAY_DATA, &tmp); | ||
183 | if (tmp & F10_NB_ARR_ECC_WR_REQ) { | ||
184 | cpu_relax(); | ||
185 | goto retry; | ||
186 | } | ||
187 | |||
188 | on_each_cpu(enable_caches, NULL, 1); | ||
189 | |||
174 | edac_dbg(0, "section=0x%x word_bits=0x%x\n", section, word_bits); | 190 | edac_dbg(0, "section=0x%x word_bits=0x%x\n", section, word_bits); |
175 | 191 | ||
176 | return count; | 192 | return count; |