aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBorislav Petkov <borislav.petkov@amd.com>2012-08-09 12:41:07 -0400
committerBorislav Petkov <bp@alien8.de>2012-11-28 05:45:01 -0500
commit66fed2d464157eb20c37738d75b281458dfc2cab (patch)
tree2ef45590cacc3c69d9901153f4dc1199e20b7fa1
parent6e71a870b8ff2c1e2d89e5ea27a38cea39cefa3d (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.c10
-rw-r--r--drivers/edac/amd64_edac.h23
-rw-r--r--drivers/edac/amd64_edac_inj.c18
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
63static int __amd64_read_pci_cfg_dword(struct pci_dev *pdev, int offset, 63int __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)
1980static inline void __amd64_decode_bus_error(struct mem_ctl_info *mci, 1980static 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 */
308struct error_injection { 309struct 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
464int __amd64_read_pci_cfg_dword(struct pci_dev *pdev, int offset,
465 u32 *val, const char *func);
463int __amd64_write_pci_cfg_dword(struct pci_dev *pdev, int offset, 466int __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 */
484static inline void disable_caches(void *dummy)
485{
486 write_cr0(read_cr0() | X86_CR0_CD);
487 wbinvd();
488}
489
490static 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;