1 // SPDX-License-Identifier: GPL-2.0
2 #include "amd64_edac.h"
4 static ssize_t
amd64_inject_section_show(struct device
*dev
,
5 struct device_attribute
*mattr
,
8 struct mem_ctl_info
*mci
= to_mci(dev
);
9 struct amd64_pvt
*pvt
= mci
->pvt_info
;
10 return sprintf(buf
, "0x%x\n", pvt
->injection
.section
);
14 * store error injection section value which refers to one of 4 16-byte sections
15 * within a 64-byte cacheline
19 static ssize_t
amd64_inject_section_store(struct device
*dev
,
20 struct device_attribute
*mattr
,
21 const char *data
, size_t count
)
23 struct mem_ctl_info
*mci
= to_mci(dev
);
24 struct amd64_pvt
*pvt
= mci
->pvt_info
;
28 ret
= kstrtoul(data
, 10, &value
);
33 amd64_warn("%s: invalid section 0x%lx\n", __func__
, value
);
37 pvt
->injection
.section
= (u32
) value
;
41 static ssize_t
amd64_inject_word_show(struct device
*dev
,
42 struct device_attribute
*mattr
,
45 struct mem_ctl_info
*mci
= to_mci(dev
);
46 struct amd64_pvt
*pvt
= mci
->pvt_info
;
47 return sprintf(buf
, "0x%x\n", pvt
->injection
.word
);
51 * store error injection word value which refers to one of 9 16-bit word of the
52 * 16-byte (128-bit + ECC bits) section
56 static ssize_t
amd64_inject_word_store(struct device
*dev
,
57 struct device_attribute
*mattr
,
58 const char *data
, size_t count
)
60 struct mem_ctl_info
*mci
= to_mci(dev
);
61 struct amd64_pvt
*pvt
= mci
->pvt_info
;
65 ret
= kstrtoul(data
, 10, &value
);
70 amd64_warn("%s: invalid word 0x%lx\n", __func__
, value
);
74 pvt
->injection
.word
= (u32
) value
;
78 static ssize_t
amd64_inject_ecc_vector_show(struct device
*dev
,
79 struct device_attribute
*mattr
,
82 struct mem_ctl_info
*mci
= to_mci(dev
);
83 struct amd64_pvt
*pvt
= mci
->pvt_info
;
84 return sprintf(buf
, "0x%x\n", pvt
->injection
.bit_map
);
88 * store 16 bit error injection vector which enables injecting errors to the
89 * corresponding bit within the error injection word above. When used during a
90 * DRAM ECC read, it holds the contents of the of the DRAM ECC bits.
92 static ssize_t
amd64_inject_ecc_vector_store(struct device
*dev
,
93 struct device_attribute
*mattr
,
94 const char *data
, size_t count
)
96 struct mem_ctl_info
*mci
= to_mci(dev
);
97 struct amd64_pvt
*pvt
= mci
->pvt_info
;
101 ret
= kstrtoul(data
, 16, &value
);
105 if (value
& 0xFFFF0000) {
106 amd64_warn("%s: invalid EccVector: 0x%lx\n", __func__
, value
);
110 pvt
->injection
.bit_map
= (u32
) value
;
115 * Do a DRAM ECC read. Assemble staged values in the pvt area, format into
116 * fields needed by the injection registers and read the NB Array Data Port.
118 static ssize_t
amd64_inject_read_store(struct device
*dev
,
119 struct device_attribute
*mattr
,
120 const char *data
, size_t count
)
122 struct mem_ctl_info
*mci
= to_mci(dev
);
123 struct amd64_pvt
*pvt
= mci
->pvt_info
;
125 u32 section
, word_bits
;
128 ret
= kstrtoul(data
, 10, &value
);
132 /* Form value to choose 16-byte section of cacheline */
133 section
= F10_NB_ARRAY_DRAM
| SET_NB_ARRAY_ADDR(pvt
->injection
.section
);
135 amd64_write_pci_cfg(pvt
->F3
, F10_NB_ARRAY_ADDR
, section
);
137 word_bits
= SET_NB_DRAM_INJECTION_READ(pvt
->injection
);
139 /* Issue 'word' and 'bit' along with the READ request */
140 amd64_write_pci_cfg(pvt
->F3
, F10_NB_ARRAY_DATA
, word_bits
);
142 edac_dbg(0, "section=0x%x word_bits=0x%x\n", section
, word_bits
);
148 * Do a DRAM ECC write. Assemble staged values in the pvt area and format into
149 * fields needed by the injection registers.
151 static ssize_t
amd64_inject_write_store(struct device
*dev
,
152 struct device_attribute
*mattr
,
153 const char *data
, size_t count
)
155 struct mem_ctl_info
*mci
= to_mci(dev
);
156 struct amd64_pvt
*pvt
= mci
->pvt_info
;
157 u32 section
, word_bits
, tmp
;
161 ret
= kstrtoul(data
, 10, &value
);
165 /* Form value to choose 16-byte section of cacheline */
166 section
= F10_NB_ARRAY_DRAM
| SET_NB_ARRAY_ADDR(pvt
->injection
.section
);
168 amd64_write_pci_cfg(pvt
->F3
, F10_NB_ARRAY_ADDR
, section
);
170 word_bits
= SET_NB_DRAM_INJECTION_WRITE(pvt
->injection
);
172 pr_notice_once("Don't forget to decrease MCE polling interval in\n"
173 "/sys/bus/machinecheck/devices/machinecheck<CPUNUM>/check_interval\n"
174 "so that you can get the error report faster.\n");
176 on_each_cpu(disable_caches
, NULL
, 1);
178 /* Issue 'word' and 'bit' along with the READ request */
179 amd64_write_pci_cfg(pvt
->F3
, F10_NB_ARRAY_DATA
, word_bits
);
182 /* wait until injection happens */
183 amd64_read_pci_cfg(pvt
->F3
, F10_NB_ARRAY_DATA
, &tmp
);
184 if (tmp
& F10_NB_ARR_ECC_WR_REQ
) {
189 on_each_cpu(enable_caches
, NULL
, 1);
191 edac_dbg(0, "section=0x%x word_bits=0x%x\n", section
, word_bits
);
197 * update NUM_INJ_ATTRS in case you add new members
200 static DEVICE_ATTR(inject_section
, S_IRUGO
| S_IWUSR
,
201 amd64_inject_section_show
, amd64_inject_section_store
);
202 static DEVICE_ATTR(inject_word
, S_IRUGO
| S_IWUSR
,
203 amd64_inject_word_show
, amd64_inject_word_store
);
204 static DEVICE_ATTR(inject_ecc_vector
, S_IRUGO
| S_IWUSR
,
205 amd64_inject_ecc_vector_show
, amd64_inject_ecc_vector_store
);
206 static DEVICE_ATTR(inject_write
, S_IWUSR
,
207 NULL
, amd64_inject_write_store
);
208 static DEVICE_ATTR(inject_read
, S_IWUSR
,
209 NULL
, amd64_inject_read_store
);
211 static struct attribute
*amd64_edac_inj_attrs
[] = {
212 &dev_attr_inject_section
.attr
,
213 &dev_attr_inject_word
.attr
,
214 &dev_attr_inject_ecc_vector
.attr
,
215 &dev_attr_inject_write
.attr
,
216 &dev_attr_inject_read
.attr
,
220 static umode_t
amd64_edac_inj_is_visible(struct kobject
*kobj
,
221 struct attribute
*attr
, int idx
)
223 struct device
*dev
= kobj_to_dev(kobj
);
224 struct mem_ctl_info
*mci
= container_of(dev
, struct mem_ctl_info
, dev
);
225 struct amd64_pvt
*pvt
= mci
->pvt_info
;
232 const struct attribute_group amd64_edac_inj_group
= {
233 .attrs
= amd64_edac_inj_attrs
,
234 .is_visible
= amd64_edac_inj_is_visible
,