blob: 0d66ae68d4681a9bb1ceedfca97fcafbde144d2c [file] [log] [blame]
Doug Thompsoneb919692009-05-05 20:07:11 +02001#include "amd64_edac.h"
2
Mauro Carvalho Chehabc5608752012-03-21 14:00:44 -03003static ssize_t amd64_inject_section_show(struct device *dev,
4 struct device_attribute *mattr,
5 char *buf)
Borislav Petkov94baaee2009-09-24 11:05:30 +02006{
Mauro Carvalho Chehabc5608752012-03-21 14:00:44 -03007 struct mem_ctl_info *mci = to_mci(dev);
Borislav Petkov94baaee2009-09-24 11:05:30 +02008 struct amd64_pvt *pvt = mci->pvt_info;
9 return sprintf(buf, "0x%x\n", pvt->injection.section);
10}
11
Doug Thompsoneb919692009-05-05 20:07:11 +020012/*
13 * store error injection section value which refers to one of 4 16-byte sections
14 * within a 64-byte cacheline
15 *
16 * range: 0..3
17 */
Mauro Carvalho Chehabc5608752012-03-21 14:00:44 -030018static ssize_t amd64_inject_section_store(struct device *dev,
19 struct device_attribute *mattr,
Doug Thompsoneb919692009-05-05 20:07:11 +020020 const char *data, size_t count)
21{
Mauro Carvalho Chehabc5608752012-03-21 14:00:44 -030022 struct mem_ctl_info *mci = to_mci(dev);
Doug Thompsoneb919692009-05-05 20:07:11 +020023 struct amd64_pvt *pvt = mci->pvt_info;
24 unsigned long value;
Borislav Petkov6e71a872012-08-09 18:23:53 +020025 int ret;
Doug Thompsoneb919692009-05-05 20:07:11 +020026
Jingoo Hanc7f62fc2013-06-01 16:08:22 +090027 ret = kstrtoul(data, 10, &value);
Borislav Petkov6e71a872012-08-09 18:23:53 +020028 if (ret < 0)
29 return ret;
Borislav Petkov94baaee2009-09-24 11:05:30 +020030
Borislav Petkov6e71a872012-08-09 18:23:53 +020031 if (value > 3) {
32 amd64_warn("%s: invalid section 0x%lx\n", __func__, value);
33 return -EINVAL;
Doug Thompsoneb919692009-05-05 20:07:11 +020034 }
Borislav Petkov6e71a872012-08-09 18:23:53 +020035
36 pvt->injection.section = (u32) value;
37 return count;
Doug Thompsoneb919692009-05-05 20:07:11 +020038}
39
Mauro Carvalho Chehabc5608752012-03-21 14:00:44 -030040static ssize_t amd64_inject_word_show(struct device *dev,
41 struct device_attribute *mattr,
42 char *buf)
Borislav Petkov94baaee2009-09-24 11:05:30 +020043{
Mauro Carvalho Chehabc5608752012-03-21 14:00:44 -030044 struct mem_ctl_info *mci = to_mci(dev);
Borislav Petkov94baaee2009-09-24 11:05:30 +020045 struct amd64_pvt *pvt = mci->pvt_info;
46 return sprintf(buf, "0x%x\n", pvt->injection.word);
47}
48
Doug Thompsoneb919692009-05-05 20:07:11 +020049/*
50 * store error injection word value which refers to one of 9 16-bit word of the
51 * 16-byte (128-bit + ECC bits) section
52 *
53 * range: 0..8
54 */
Mauro Carvalho Chehabc5608752012-03-21 14:00:44 -030055static ssize_t amd64_inject_word_store(struct device *dev,
56 struct device_attribute *mattr,
57 const char *data, size_t count)
Doug Thompsoneb919692009-05-05 20:07:11 +020058{
Mauro Carvalho Chehabc5608752012-03-21 14:00:44 -030059 struct mem_ctl_info *mci = to_mci(dev);
Doug Thompsoneb919692009-05-05 20:07:11 +020060 struct amd64_pvt *pvt = mci->pvt_info;
61 unsigned long value;
Borislav Petkov6e71a872012-08-09 18:23:53 +020062 int ret;
Doug Thompsoneb919692009-05-05 20:07:11 +020063
Jingoo Hanc7f62fc2013-06-01 16:08:22 +090064 ret = kstrtoul(data, 10, &value);
Borislav Petkov6e71a872012-08-09 18:23:53 +020065 if (ret < 0)
66 return ret;
Doug Thompsoneb919692009-05-05 20:07:11 +020067
Borislav Petkov6e71a872012-08-09 18:23:53 +020068 if (value > 8) {
69 amd64_warn("%s: invalid word 0x%lx\n", __func__, value);
70 return -EINVAL;
Doug Thompsoneb919692009-05-05 20:07:11 +020071 }
Borislav Petkov6e71a872012-08-09 18:23:53 +020072
73 pvt->injection.word = (u32) value;
74 return count;
Doug Thompsoneb919692009-05-05 20:07:11 +020075}
76
Mauro Carvalho Chehabc5608752012-03-21 14:00:44 -030077static ssize_t amd64_inject_ecc_vector_show(struct device *dev,
78 struct device_attribute *mattr,
79 char *buf)
Borislav Petkov94baaee2009-09-24 11:05:30 +020080{
Mauro Carvalho Chehabc5608752012-03-21 14:00:44 -030081 struct mem_ctl_info *mci = to_mci(dev);
Borislav Petkov94baaee2009-09-24 11:05:30 +020082 struct amd64_pvt *pvt = mci->pvt_info;
83 return sprintf(buf, "0x%x\n", pvt->injection.bit_map);
84}
85
Doug Thompsoneb919692009-05-05 20:07:11 +020086/*
87 * store 16 bit error injection vector which enables injecting errors to the
88 * corresponding bit within the error injection word above. When used during a
89 * DRAM ECC read, it holds the contents of the of the DRAM ECC bits.
90 */
Mauro Carvalho Chehabc5608752012-03-21 14:00:44 -030091static ssize_t amd64_inject_ecc_vector_store(struct device *dev,
92 struct device_attribute *mattr,
93 const char *data, size_t count)
Doug Thompsoneb919692009-05-05 20:07:11 +020094{
Mauro Carvalho Chehabc5608752012-03-21 14:00:44 -030095 struct mem_ctl_info *mci = to_mci(dev);
Doug Thompsoneb919692009-05-05 20:07:11 +020096 struct amd64_pvt *pvt = mci->pvt_info;
97 unsigned long value;
Borislav Petkov6e71a872012-08-09 18:23:53 +020098 int ret;
Doug Thompsoneb919692009-05-05 20:07:11 +020099
Jingoo Hanc7f62fc2013-06-01 16:08:22 +0900100 ret = kstrtoul(data, 16, &value);
Borislav Petkov6e71a872012-08-09 18:23:53 +0200101 if (ret < 0)
102 return ret;
Doug Thompsoneb919692009-05-05 20:07:11 +0200103
Borislav Petkov6e71a872012-08-09 18:23:53 +0200104 if (value & 0xFFFF0000) {
105 amd64_warn("%s: invalid EccVector: 0x%lx\n", __func__, value);
106 return -EINVAL;
Doug Thompsoneb919692009-05-05 20:07:11 +0200107 }
Borislav Petkov6e71a872012-08-09 18:23:53 +0200108
109 pvt->injection.bit_map = (u32) value;
110 return count;
Doug Thompsoneb919692009-05-05 20:07:11 +0200111}
112
113/*
114 * Do a DRAM ECC read. Assemble staged values in the pvt area, format into
115 * fields needed by the injection registers and read the NB Array Data Port.
116 */
Mauro Carvalho Chehabc5608752012-03-21 14:00:44 -0300117static ssize_t amd64_inject_read_store(struct device *dev,
118 struct device_attribute *mattr,
119 const char *data, size_t count)
Doug Thompsoneb919692009-05-05 20:07:11 +0200120{
Mauro Carvalho Chehabc5608752012-03-21 14:00:44 -0300121 struct mem_ctl_info *mci = to_mci(dev);
Doug Thompsoneb919692009-05-05 20:07:11 +0200122 struct amd64_pvt *pvt = mci->pvt_info;
123 unsigned long value;
124 u32 section, word_bits;
Borislav Petkov6e71a872012-08-09 18:23:53 +0200125 int ret;
Doug Thompsoneb919692009-05-05 20:07:11 +0200126
Jingoo Hanc7f62fc2013-06-01 16:08:22 +0900127 ret = kstrtoul(data, 10, &value);
Borislav Petkov6e71a872012-08-09 18:23:53 +0200128 if (ret < 0)
129 return ret;
Doug Thompsoneb919692009-05-05 20:07:11 +0200130
Borislav Petkov6e71a872012-08-09 18:23:53 +0200131 /* Form value to choose 16-byte section of cacheline */
132 section = F10_NB_ARRAY_DRAM | SET_NB_ARRAY_ADDR(pvt->injection.section);
Doug Thompsoneb919692009-05-05 20:07:11 +0200133
Borislav Petkov6e71a872012-08-09 18:23:53 +0200134 amd64_write_pci_cfg(pvt->F3, F10_NB_ARRAY_ADDR, section);
Doug Thompsoneb919692009-05-05 20:07:11 +0200135
Borislav Petkov6e71a872012-08-09 18:23:53 +0200136 word_bits = SET_NB_DRAM_INJECTION_READ(pvt->injection);
Doug Thompsoneb919692009-05-05 20:07:11 +0200137
Borislav Petkov6e71a872012-08-09 18:23:53 +0200138 /* Issue 'word' and 'bit' along with the READ request */
139 amd64_write_pci_cfg(pvt->F3, F10_NB_ARRAY_DATA, word_bits);
Doug Thompsoneb919692009-05-05 20:07:11 +0200140
Borislav Petkov6e71a872012-08-09 18:23:53 +0200141 edac_dbg(0, "section=0x%x word_bits=0x%x\n", section, word_bits);
142
143 return count;
Doug Thompsoneb919692009-05-05 20:07:11 +0200144}
145
146/*
147 * Do a DRAM ECC write. Assemble staged values in the pvt area and format into
148 * fields needed by the injection registers.
149 */
Mauro Carvalho Chehabc5608752012-03-21 14:00:44 -0300150static ssize_t amd64_inject_write_store(struct device *dev,
151 struct device_attribute *mattr,
Doug Thompsoneb919692009-05-05 20:07:11 +0200152 const char *data, size_t count)
153{
Mauro Carvalho Chehabc5608752012-03-21 14:00:44 -0300154 struct mem_ctl_info *mci = to_mci(dev);
Doug Thompsoneb919692009-05-05 20:07:11 +0200155 struct amd64_pvt *pvt = mci->pvt_info;
Borislav Petkov66fed2d2012-08-09 18:41:07 +0200156 u32 section, word_bits, tmp;
Doug Thompsoneb919692009-05-05 20:07:11 +0200157 unsigned long value;
Borislav Petkov6e71a872012-08-09 18:23:53 +0200158 int ret;
Doug Thompsoneb919692009-05-05 20:07:11 +0200159
Jingoo Hanc7f62fc2013-06-01 16:08:22 +0900160 ret = kstrtoul(data, 10, &value);
Borislav Petkov6e71a872012-08-09 18:23:53 +0200161 if (ret < 0)
162 return ret;
Doug Thompsoneb919692009-05-05 20:07:11 +0200163
Borislav Petkov6e71a872012-08-09 18:23:53 +0200164 /* Form value to choose 16-byte section of cacheline */
165 section = F10_NB_ARRAY_DRAM | SET_NB_ARRAY_ADDR(pvt->injection.section);
Doug Thompsoneb919692009-05-05 20:07:11 +0200166
Borislav Petkov6e71a872012-08-09 18:23:53 +0200167 amd64_write_pci_cfg(pvt->F3, F10_NB_ARRAY_ADDR, section);
Doug Thompsoneb919692009-05-05 20:07:11 +0200168
Borislav Petkov6e71a872012-08-09 18:23:53 +0200169 word_bits = SET_NB_DRAM_INJECTION_WRITE(pvt->injection);
Doug Thompsoneb919692009-05-05 20:07:11 +0200170
Borislav Petkov66fed2d2012-08-09 18:41:07 +0200171 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
Borislav Petkov6e71a872012-08-09 18:23:53 +0200177 /* Issue 'word' and 'bit' along with the READ request */
178 amd64_write_pci_cfg(pvt->F3, F10_NB_ARRAY_DATA, word_bits);
Doug Thompsoneb919692009-05-05 20:07:11 +0200179
Borislav Petkov66fed2d2012-08-09 18:41:07 +0200180 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
Borislav Petkov6e71a872012-08-09 18:23:53 +0200190 edac_dbg(0, "section=0x%x word_bits=0x%x\n", section, word_bits);
191
192 return count;
Doug Thompsoneb919692009-05-05 20:07:11 +0200193}
194
195/*
196 * update NUM_INJ_ATTRS in case you add new members
197 */
Doug Thompsoneb919692009-05-05 20:07:11 +0200198
Mauro Carvalho Chehabc5608752012-03-21 14:00:44 -0300199static DEVICE_ATTR(inject_section, S_IRUGO | S_IWUSR,
200 amd64_inject_section_show, amd64_inject_section_store);
201static DEVICE_ATTR(inject_word, S_IRUGO | S_IWUSR,
202 amd64_inject_word_show, amd64_inject_word_store);
203static DEVICE_ATTR(inject_ecc_vector, S_IRUGO | S_IWUSR,
204 amd64_inject_ecc_vector_show, amd64_inject_ecc_vector_store);
Borislav Petkovbbb013b2013-05-12 13:03:56 +0200205static DEVICE_ATTR(inject_write, S_IWUSR,
Mauro Carvalho Chehabc5608752012-03-21 14:00:44 -0300206 NULL, amd64_inject_write_store);
Borislav Petkovbbb013b2013-05-12 13:03:56 +0200207static DEVICE_ATTR(inject_read, S_IWUSR,
Mauro Carvalho Chehabc5608752012-03-21 14:00:44 -0300208 NULL, amd64_inject_read_store);
209
210
211int amd64_create_sysfs_inject_files(struct mem_ctl_info *mci)
212{
213 int rc;
214
215 rc = device_create_file(&mci->dev, &dev_attr_inject_section);
216 if (rc < 0)
217 return rc;
218 rc = device_create_file(&mci->dev, &dev_attr_inject_word);
219 if (rc < 0)
220 return rc;
221 rc = device_create_file(&mci->dev, &dev_attr_inject_ecc_vector);
222 if (rc < 0)
223 return rc;
224 rc = device_create_file(&mci->dev, &dev_attr_inject_write);
225 if (rc < 0)
226 return rc;
227 rc = device_create_file(&mci->dev, &dev_attr_inject_read);
228 if (rc < 0)
229 return rc;
230
231 return 0;
232}
233
234void amd64_remove_sysfs_inject_files(struct mem_ctl_info *mci)
235{
236 device_remove_file(&mci->dev, &dev_attr_inject_section);
237 device_remove_file(&mci->dev, &dev_attr_inject_word);
238 device_remove_file(&mci->dev, &dev_attr_inject_ecc_vector);
239 device_remove_file(&mci->dev, &dev_attr_inject_write);
240 device_remove_file(&mci->dev, &dev_attr_inject_read);
241}