-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
amd64_edac: add DRAM error injection logic using sysfs
Borislav: - rename sysfs attrs to more conform names - cleanup/fix comments according to BKDG text - fix function return value patterns - cleanup debug calls Reviewed-by: Mauro Carvalho Chehab <mchehab@redhat.com> Signed-off-by: Doug Thompson <dougthompson@xmission.com> Signed-off-by: Borislav Petkov <borislav.petkov@amd.com>
- Loading branch information
Doug Thompson
authored and
Borislav Petkov
committed
Jun 10, 2009
1 parent
fd3d678
commit eb91969
Showing
1 changed file
with
185 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,185 @@ | ||
#include "amd64_edac.h" | ||
|
||
/* | ||
* store error injection section value which refers to one of 4 16-byte sections | ||
* within a 64-byte cacheline | ||
* | ||
* range: 0..3 | ||
*/ | ||
static ssize_t amd64_inject_section_store(struct mem_ctl_info *mci, | ||
const char *data, size_t count) | ||
{ | ||
struct amd64_pvt *pvt = mci->pvt_info; | ||
unsigned long value; | ||
int ret = 0; | ||
|
||
ret = strict_strtoul(data, 10, &value); | ||
if (ret != -EINVAL) { | ||
pvt->injection.section = (u32) value; | ||
return count; | ||
} | ||
return ret; | ||
} | ||
|
||
/* | ||
* store error injection word value which refers to one of 9 16-bit word of the | ||
* 16-byte (128-bit + ECC bits) section | ||
* | ||
* range: 0..8 | ||
*/ | ||
static ssize_t amd64_inject_word_store(struct mem_ctl_info *mci, | ||
const char *data, size_t count) | ||
{ | ||
struct amd64_pvt *pvt = mci->pvt_info; | ||
unsigned long value; | ||
int ret = 0; | ||
|
||
ret = strict_strtoul(data, 10, &value); | ||
if (ret != -EINVAL) { | ||
|
||
value = (value <= 8) ? value : 0; | ||
pvt->injection.word = (u32) value; | ||
|
||
return count; | ||
} | ||
return ret; | ||
} | ||
|
||
/* | ||
* store 16 bit error injection vector which enables injecting errors to the | ||
* corresponding bit within the error injection word above. When used during a | ||
* DRAM ECC read, it holds the contents of the of the DRAM ECC bits. | ||
*/ | ||
static ssize_t amd64_inject_ecc_vector_store(struct mem_ctl_info *mci, | ||
const char *data, size_t count) | ||
{ | ||
struct amd64_pvt *pvt = mci->pvt_info; | ||
unsigned long value; | ||
int ret = 0; | ||
|
||
ret = strict_strtoul(data, 16, &value); | ||
if (ret != -EINVAL) { | ||
|
||
pvt->injection.bit_map = (u32) value & 0xFFFF; | ||
|
||
return count; | ||
} | ||
return ret; | ||
} | ||
|
||
/* | ||
* Do a DRAM ECC read. Assemble staged values in the pvt area, format into | ||
* fields needed by the injection registers and read the NB Array Data Port. | ||
*/ | ||
static ssize_t amd64_inject_read_store(struct mem_ctl_info *mci, | ||
const char *data, size_t count) | ||
{ | ||
struct amd64_pvt *pvt = mci->pvt_info; | ||
unsigned long value; | ||
u32 section, word_bits; | ||
int ret = 0; | ||
|
||
ret = strict_strtoul(data, 10, &value); | ||
if (ret != -EINVAL) { | ||
|
||
/* Form value to choose 16-byte section of cacheline */ | ||
section = F10_NB_ARRAY_DRAM_ECC | | ||
SET_NB_ARRAY_ADDRESS(pvt->injection.section); | ||
pci_write_config_dword(pvt->misc_f3_ctl, | ||
F10_NB_ARRAY_ADDR, section); | ||
|
||
word_bits = SET_NB_DRAM_INJECTION_READ(pvt->injection.word, | ||
pvt->injection.bit_map); | ||
|
||
/* Issue 'word' and 'bit' along with the READ request */ | ||
pci_write_config_dword(pvt->misc_f3_ctl, | ||
F10_NB_ARRAY_DATA, word_bits); | ||
|
||
debugf0("section=0x%x word_bits=0x%x\n", section, word_bits); | ||
|
||
return count; | ||
} | ||
return ret; | ||
} | ||
|
||
/* | ||
* Do a DRAM ECC write. Assemble staged values in the pvt area and format into | ||
* fields needed by the injection registers. | ||
*/ | ||
static ssize_t amd64_inject_write_store(struct mem_ctl_info *mci, | ||
const char *data, size_t count) | ||
{ | ||
struct amd64_pvt *pvt = mci->pvt_info; | ||
unsigned long value; | ||
u32 section, word_bits; | ||
int ret = 0; | ||
|
||
ret = strict_strtoul(data, 10, &value); | ||
if (ret != -EINVAL) { | ||
|
||
/* Form value to choose 16-byte section of cacheline */ | ||
section = F10_NB_ARRAY_DRAM_ECC | | ||
SET_NB_ARRAY_ADDRESS(pvt->injection.section); | ||
pci_write_config_dword(pvt->misc_f3_ctl, | ||
F10_NB_ARRAY_ADDR, section); | ||
|
||
word_bits = SET_NB_DRAM_INJECTION_WRITE(pvt->injection.word, | ||
pvt->injection.bit_map); | ||
|
||
/* Issue 'word' and 'bit' along with the READ request */ | ||
pci_write_config_dword(pvt->misc_f3_ctl, | ||
F10_NB_ARRAY_DATA, word_bits); | ||
|
||
debugf0("section=0x%x word_bits=0x%x\n", section, word_bits); | ||
|
||
return count; | ||
} | ||
return ret; | ||
} | ||
|
||
/* | ||
* update NUM_INJ_ATTRS in case you add new members | ||
*/ | ||
struct mcidev_sysfs_attribute amd64_inj_attrs[] = { | ||
|
||
{ | ||
.attr = { | ||
.name = "inject_section", | ||
.mode = (S_IRUGO | S_IWUSR) | ||
}, | ||
.show = NULL, | ||
.store = amd64_inject_section_store, | ||
}, | ||
{ | ||
.attr = { | ||
.name = "inject_word", | ||
.mode = (S_IRUGO | S_IWUSR) | ||
}, | ||
.show = NULL, | ||
.store = amd64_inject_word_store, | ||
}, | ||
{ | ||
.attr = { | ||
.name = "inject_ecc_vector", | ||
.mode = (S_IRUGO | S_IWUSR) | ||
}, | ||
.show = NULL, | ||
.store = amd64_inject_ecc_vector_store, | ||
}, | ||
{ | ||
.attr = { | ||
.name = "inject_write", | ||
.mode = (S_IRUGO | S_IWUSR) | ||
}, | ||
.show = NULL, | ||
.store = amd64_inject_write_store, | ||
}, | ||
{ | ||
.attr = { | ||
.name = "inject_read", | ||
.mode = (S_IRUGO | S_IWUSR) | ||
}, | ||
.show = NULL, | ||
.store = amd64_inject_read_store, | ||
}, | ||
}; |