Blame view
drivers/edac/amd64_edac_inj.c
6.23 KB
b24413180
|
1 |
// SPDX-License-Identifier: GPL-2.0 |
eb919690b
|
2 |
#include "amd64_edac.h" |
c56087595
|
3 4 5 |
static ssize_t amd64_inject_section_show(struct device *dev, struct device_attribute *mattr, char *buf) |
94baaee49
|
6 |
{ |
c56087595
|
7 |
struct mem_ctl_info *mci = to_mci(dev); |
94baaee49
|
8 9 10 11 |
struct amd64_pvt *pvt = mci->pvt_info; return sprintf(buf, "0x%x ", pvt->injection.section); } |
eb919690b
|
12 13 14 15 16 17 |
/* * store error injection section value which refers to one of 4 16-byte sections * within a 64-byte cacheline * * range: 0..3 */ |
c56087595
|
18 19 |
static ssize_t amd64_inject_section_store(struct device *dev, struct device_attribute *mattr, |
eb919690b
|
20 21 |
const char *data, size_t count) { |
c56087595
|
22 |
struct mem_ctl_info *mci = to_mci(dev); |
eb919690b
|
23 24 |
struct amd64_pvt *pvt = mci->pvt_info; unsigned long value; |
6e71a870b
|
25 |
int ret; |
eb919690b
|
26 |
|
c7f62fc87
|
27 |
ret = kstrtoul(data, 10, &value); |
6e71a870b
|
28 29 |
if (ret < 0) return ret; |
94baaee49
|
30 |
|
6e71a870b
|
31 32 33 34 |
if (value > 3) { amd64_warn("%s: invalid section 0x%lx ", __func__, value); return -EINVAL; |
eb919690b
|
35 |
} |
6e71a870b
|
36 37 38 |
pvt->injection.section = (u32) value; return count; |
eb919690b
|
39 |
} |
c56087595
|
40 41 42 |
static ssize_t amd64_inject_word_show(struct device *dev, struct device_attribute *mattr, char *buf) |
94baaee49
|
43 |
{ |
c56087595
|
44 |
struct mem_ctl_info *mci = to_mci(dev); |
94baaee49
|
45 46 47 48 |
struct amd64_pvt *pvt = mci->pvt_info; return sprintf(buf, "0x%x ", pvt->injection.word); } |
eb919690b
|
49 50 51 52 53 54 |
/* * 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 */ |
c56087595
|
55 56 57 |
static ssize_t amd64_inject_word_store(struct device *dev, struct device_attribute *mattr, const char *data, size_t count) |
eb919690b
|
58 |
{ |
c56087595
|
59 |
struct mem_ctl_info *mci = to_mci(dev); |
eb919690b
|
60 61 |
struct amd64_pvt *pvt = mci->pvt_info; unsigned long value; |
6e71a870b
|
62 |
int ret; |
eb919690b
|
63 |
|
c7f62fc87
|
64 |
ret = kstrtoul(data, 10, &value); |
6e71a870b
|
65 66 |
if (ret < 0) return ret; |
eb919690b
|
67 |
|
6e71a870b
|
68 69 70 71 |
if (value > 8) { amd64_warn("%s: invalid word 0x%lx ", __func__, value); return -EINVAL; |
eb919690b
|
72 |
} |
6e71a870b
|
73 74 75 |
pvt->injection.word = (u32) value; return count; |
eb919690b
|
76 |
} |
c56087595
|
77 78 79 |
static ssize_t amd64_inject_ecc_vector_show(struct device *dev, struct device_attribute *mattr, char *buf) |
94baaee49
|
80 |
{ |
c56087595
|
81 |
struct mem_ctl_info *mci = to_mci(dev); |
94baaee49
|
82 83 84 85 |
struct amd64_pvt *pvt = mci->pvt_info; return sprintf(buf, "0x%x ", pvt->injection.bit_map); } |
eb919690b
|
86 87 88 89 90 |
/* * 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. */ |
c56087595
|
91 92 93 |
static ssize_t amd64_inject_ecc_vector_store(struct device *dev, struct device_attribute *mattr, const char *data, size_t count) |
eb919690b
|
94 |
{ |
c56087595
|
95 |
struct mem_ctl_info *mci = to_mci(dev); |
eb919690b
|
96 97 |
struct amd64_pvt *pvt = mci->pvt_info; unsigned long value; |
6e71a870b
|
98 |
int ret; |
eb919690b
|
99 |
|
c7f62fc87
|
100 |
ret = kstrtoul(data, 16, &value); |
6e71a870b
|
101 102 |
if (ret < 0) return ret; |
eb919690b
|
103 |
|
6e71a870b
|
104 105 106 107 |
if (value & 0xFFFF0000) { amd64_warn("%s: invalid EccVector: 0x%lx ", __func__, value); return -EINVAL; |
eb919690b
|
108 |
} |
6e71a870b
|
109 110 111 |
pvt->injection.bit_map = (u32) value; return count; |
eb919690b
|
112 113 114 115 116 117 |
} /* * 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. */ |
c56087595
|
118 119 120 |
static ssize_t amd64_inject_read_store(struct device *dev, struct device_attribute *mattr, const char *data, size_t count) |
eb919690b
|
121 |
{ |
c56087595
|
122 |
struct mem_ctl_info *mci = to_mci(dev); |
eb919690b
|
123 124 125 |
struct amd64_pvt *pvt = mci->pvt_info; unsigned long value; u32 section, word_bits; |
6e71a870b
|
126 |
int ret; |
eb919690b
|
127 |
|
c7f62fc87
|
128 |
ret = kstrtoul(data, 10, &value); |
6e71a870b
|
129 130 |
if (ret < 0) return ret; |
eb919690b
|
131 |
|
6e71a870b
|
132 133 |
/* Form value to choose 16-byte section of cacheline */ section = F10_NB_ARRAY_DRAM | SET_NB_ARRAY_ADDR(pvt->injection.section); |
eb919690b
|
134 |
|
6e71a870b
|
135 |
amd64_write_pci_cfg(pvt->F3, F10_NB_ARRAY_ADDR, section); |
eb919690b
|
136 |
|
6e71a870b
|
137 |
word_bits = SET_NB_DRAM_INJECTION_READ(pvt->injection); |
eb919690b
|
138 |
|
6e71a870b
|
139 140 |
/* Issue 'word' and 'bit' along with the READ request */ amd64_write_pci_cfg(pvt->F3, F10_NB_ARRAY_DATA, word_bits); |
eb919690b
|
141 |
|
6e71a870b
|
142 143 144 145 |
edac_dbg(0, "section=0x%x word_bits=0x%x ", section, word_bits); return count; |
eb919690b
|
146 147 148 149 150 151 |
} /* * Do a DRAM ECC write. Assemble staged values in the pvt area and format into * fields needed by the injection registers. */ |
c56087595
|
152 153 |
static ssize_t amd64_inject_write_store(struct device *dev, struct device_attribute *mattr, |
eb919690b
|
154 155 |
const char *data, size_t count) { |
c56087595
|
156 |
struct mem_ctl_info *mci = to_mci(dev); |
eb919690b
|
157 |
struct amd64_pvt *pvt = mci->pvt_info; |
66fed2d46
|
158 |
u32 section, word_bits, tmp; |
eb919690b
|
159 |
unsigned long value; |
6e71a870b
|
160 |
int ret; |
eb919690b
|
161 |
|
c7f62fc87
|
162 |
ret = kstrtoul(data, 10, &value); |
6e71a870b
|
163 164 |
if (ret < 0) return ret; |
eb919690b
|
165 |
|
6e71a870b
|
166 167 |
/* Form value to choose 16-byte section of cacheline */ section = F10_NB_ARRAY_DRAM | SET_NB_ARRAY_ADDR(pvt->injection.section); |
eb919690b
|
168 |
|
6e71a870b
|
169 |
amd64_write_pci_cfg(pvt->F3, F10_NB_ARRAY_ADDR, section); |
eb919690b
|
170 |
|
6e71a870b
|
171 |
word_bits = SET_NB_DRAM_INJECTION_WRITE(pvt->injection); |
eb919690b
|
172 |
|
66fed2d46
|
173 174 175 176 177 178 179 180 |
pr_notice_once("Don't forget to decrease MCE polling interval in " "/sys/bus/machinecheck/devices/machinecheck<CPUNUM>/check_interval " "so that you can get the error report faster. "); on_each_cpu(disable_caches, NULL, 1); |
6e71a870b
|
181 182 |
/* Issue 'word' and 'bit' along with the READ request */ amd64_write_pci_cfg(pvt->F3, F10_NB_ARRAY_DATA, word_bits); |
eb919690b
|
183 |
|
66fed2d46
|
184 185 186 187 188 189 190 191 192 |
retry: /* wait until injection happens */ amd64_read_pci_cfg(pvt->F3, F10_NB_ARRAY_DATA, &tmp); if (tmp & F10_NB_ARR_ECC_WR_REQ) { cpu_relax(); goto retry; } on_each_cpu(enable_caches, NULL, 1); |
6e71a870b
|
193 194 195 196 |
edac_dbg(0, "section=0x%x word_bits=0x%x ", section, word_bits); return count; |
eb919690b
|
197 198 199 200 201 |
} /* * update NUM_INJ_ATTRS in case you add new members */ |
c56087595
|
202 203 204 205 206 207 208 |
static DEVICE_ATTR(inject_section, S_IRUGO | S_IWUSR, amd64_inject_section_show, amd64_inject_section_store); static DEVICE_ATTR(inject_word, S_IRUGO | S_IWUSR, amd64_inject_word_show, amd64_inject_word_store); static DEVICE_ATTR(inject_ecc_vector, S_IRUGO | S_IWUSR, amd64_inject_ecc_vector_show, amd64_inject_ecc_vector_store); |
bbb013b92
|
209 |
static DEVICE_ATTR(inject_write, S_IWUSR, |
c56087595
|
210 |
NULL, amd64_inject_write_store); |
bbb013b92
|
211 |
static DEVICE_ATTR(inject_read, S_IWUSR, |
c56087595
|
212 |
NULL, amd64_inject_read_store); |
e339f1ec9
|
213 214 215 216 217 218 219 220 221 222 223 |
static struct attribute *amd64_edac_inj_attrs[] = { &dev_attr_inject_section.attr, &dev_attr_inject_word.attr, &dev_attr_inject_ecc_vector.attr, &dev_attr_inject_write.attr, &dev_attr_inject_read.attr, NULL }; static umode_t amd64_edac_inj_is_visible(struct kobject *kobj, struct attribute *attr, int idx) |
c56087595
|
224 |
{ |
e339f1ec9
|
225 226 227 |
struct device *dev = kobj_to_dev(kobj); struct mem_ctl_info *mci = container_of(dev, struct mem_ctl_info, dev); struct amd64_pvt *pvt = mci->pvt_info; |
c56087595
|
228 |
|
e339f1ec9
|
229 230 231 |
if (pvt->fam < 0x10) return 0; return attr->mode; |
c56087595
|
232 |
} |
e339f1ec9
|
233 234 235 236 237 |
const struct attribute_group amd64_edac_inj_group = { .attrs = amd64_edac_inj_attrs, .is_visible = amd64_edac_inj_is_visible, }; |