Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
amd64_edac_inj.c
Go to the documentation of this file.
1 #include "amd64_edac.h"
2 
3 static ssize_t amd64_inject_section_show(struct device *dev,
4  struct device_attribute *mattr,
5  char *buf)
6 {
7  struct mem_ctl_info *mci = to_mci(dev);
8  struct amd64_pvt *pvt = mci->pvt_info;
9  return sprintf(buf, "0x%x\n", pvt->injection.section);
10 }
11 
12 /*
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  */
18 static ssize_t amd64_inject_section_store(struct device *dev,
19  struct device_attribute *mattr,
20  const char *data, size_t count)
21 {
22  struct mem_ctl_info *mci = to_mci(dev);
23  struct amd64_pvt *pvt = mci->pvt_info;
24  unsigned long value;
25  int ret = 0;
26 
27  ret = strict_strtoul(data, 10, &value);
28  if (ret != -EINVAL) {
29 
30  if (value > 3) {
31  amd64_warn("%s: invalid section 0x%lx\n", __func__, value);
32  return -EINVAL;
33  }
34 
35  pvt->injection.section = (u32) value;
36  return count;
37  }
38  return ret;
39 }
40 
41 static ssize_t amd64_inject_word_show(struct device *dev,
42  struct device_attribute *mattr,
43  char *buf)
44 {
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);
48 }
49 
50 /*
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
53  *
54  * range: 0..8
55  */
56 static ssize_t amd64_inject_word_store(struct device *dev,
57  struct device_attribute *mattr,
58  const char *data, size_t count)
59 {
60  struct mem_ctl_info *mci = to_mci(dev);
61  struct amd64_pvt *pvt = mci->pvt_info;
62  unsigned long value;
63  int ret = 0;
64 
65  ret = strict_strtoul(data, 10, &value);
66  if (ret != -EINVAL) {
67 
68  if (value > 8) {
69  amd64_warn("%s: invalid word 0x%lx\n", __func__, value);
70  return -EINVAL;
71  }
72 
73  pvt->injection.word = (u32) value;
74  return count;
75  }
76  return ret;
77 }
78 
79 static ssize_t amd64_inject_ecc_vector_show(struct device *dev,
80  struct device_attribute *mattr,
81  char *buf)
82 {
83  struct mem_ctl_info *mci = to_mci(dev);
84  struct amd64_pvt *pvt = mci->pvt_info;
85  return sprintf(buf, "0x%x\n", pvt->injection.bit_map);
86 }
87 
88 /*
89  * store 16 bit error injection vector which enables injecting errors to the
90  * corresponding bit within the error injection word above. When used during a
91  * DRAM ECC read, it holds the contents of the of the DRAM ECC bits.
92  */
93 static ssize_t amd64_inject_ecc_vector_store(struct device *dev,
94  struct device_attribute *mattr,
95  const char *data, size_t count)
96 {
97  struct mem_ctl_info *mci = to_mci(dev);
98  struct amd64_pvt *pvt = mci->pvt_info;
99  unsigned long value;
100  int ret = 0;
101 
102  ret = strict_strtoul(data, 16, &value);
103  if (ret != -EINVAL) {
104 
105  if (value & 0xFFFF0000) {
106  amd64_warn("%s: invalid EccVector: 0x%lx\n",
107  __func__, value);
108  return -EINVAL;
109  }
110 
111  pvt->injection.bit_map = (u32) value;
112  return count;
113  }
114  return ret;
115 }
116 
117 /*
118  * Do a DRAM ECC read. Assemble staged values in the pvt area, format into
119  * fields needed by the injection registers and read the NB Array Data Port.
120  */
121 static ssize_t amd64_inject_read_store(struct device *dev,
122  struct device_attribute *mattr,
123  const char *data, size_t count)
124 {
125  struct mem_ctl_info *mci = to_mci(dev);
126  struct amd64_pvt *pvt = mci->pvt_info;
127  unsigned long value;
128  u32 section, word_bits;
129  int ret = 0;
130 
131  ret = strict_strtoul(data, 10, &value);
132  if (ret != -EINVAL) {
133 
134  /* Form value to choose 16-byte section of cacheline */
135  section = F10_NB_ARRAY_DRAM_ECC |
136  SET_NB_ARRAY_ADDRESS(pvt->injection.section);
137  amd64_write_pci_cfg(pvt->F3, F10_NB_ARRAY_ADDR, section);
138 
139  word_bits = SET_NB_DRAM_INJECTION_READ(pvt->injection.word,
140  pvt->injection.bit_map);
141 
142  /* Issue 'word' and 'bit' along with the READ request */
143  amd64_write_pci_cfg(pvt->F3, F10_NB_ARRAY_DATA, word_bits);
144 
145  edac_dbg(0, "section=0x%x word_bits=0x%x\n",
146  section, word_bits);
147 
148  return count;
149  }
150  return ret;
151 }
152 
153 /*
154  * Do a DRAM ECC write. Assemble staged values in the pvt area and format into
155  * fields needed by the injection registers.
156  */
157 static ssize_t amd64_inject_write_store(struct device *dev,
158  struct device_attribute *mattr,
159  const char *data, size_t count)
160 {
161  struct mem_ctl_info *mci = to_mci(dev);
162  struct amd64_pvt *pvt = mci->pvt_info;
163  unsigned long value;
164  u32 section, word_bits;
165  int ret = 0;
166 
167  ret = strict_strtoul(data, 10, &value);
168  if (ret != -EINVAL) {
169 
170  /* Form value to choose 16-byte section of cacheline */
171  section = F10_NB_ARRAY_DRAM_ECC |
172  SET_NB_ARRAY_ADDRESS(pvt->injection.section);
173  amd64_write_pci_cfg(pvt->F3, F10_NB_ARRAY_ADDR, section);
174 
175  word_bits = SET_NB_DRAM_INJECTION_WRITE(pvt->injection.word,
176  pvt->injection.bit_map);
177 
178  /* Issue 'word' and 'bit' along with the READ request */
179  amd64_write_pci_cfg(pvt->F3, F10_NB_ARRAY_DATA, word_bits);
180 
181  edac_dbg(0, "section=0x%x word_bits=0x%x\n",
182  section, word_bits);
183 
184  return count;
185  }
186  return ret;
187 }
188 
189 /*
190  * update NUM_INJ_ATTRS in case you add new members
191  */
192 
193 static DEVICE_ATTR(inject_section, S_IRUGO | S_IWUSR,
194  amd64_inject_section_show, amd64_inject_section_store);
195 static DEVICE_ATTR(inject_word, S_IRUGO | S_IWUSR,
196  amd64_inject_word_show, amd64_inject_word_store);
197 static DEVICE_ATTR(inject_ecc_vector, S_IRUGO | S_IWUSR,
198  amd64_inject_ecc_vector_show, amd64_inject_ecc_vector_store);
199 static DEVICE_ATTR(inject_write, S_IRUGO | S_IWUSR,
200  NULL, amd64_inject_write_store);
201 static DEVICE_ATTR(inject_read, S_IRUGO | S_IWUSR,
202  NULL, amd64_inject_read_store);
203 
204 
206 {
207  int rc;
208 
209  rc = device_create_file(&mci->dev, &dev_attr_inject_section);
210  if (rc < 0)
211  return rc;
212  rc = device_create_file(&mci->dev, &dev_attr_inject_word);
213  if (rc < 0)
214  return rc;
215  rc = device_create_file(&mci->dev, &dev_attr_inject_ecc_vector);
216  if (rc < 0)
217  return rc;
218  rc = device_create_file(&mci->dev, &dev_attr_inject_write);
219  if (rc < 0)
220  return rc;
221  rc = device_create_file(&mci->dev, &dev_attr_inject_read);
222  if (rc < 0)
223  return rc;
224 
225  return 0;
226 }
227 
229 {
230  device_remove_file(&mci->dev, &dev_attr_inject_section);
231  device_remove_file(&mci->dev, &dev_attr_inject_word);
232  device_remove_file(&mci->dev, &dev_attr_inject_ecc_vector);
233  device_remove_file(&mci->dev, &dev_attr_inject_write);
234  device_remove_file(&mci->dev, &dev_attr_inject_read);
235 }