Blame view

drivers/edac/amd64_edac_inj.c 6.41 KB
eb919690b   Doug Thompson   amd64_edac: add D...
1
  #include "amd64_edac.h"
c56087595   Mauro Carvalho Chehab   amd64_edac: conve...
2
3
4
  static ssize_t amd64_inject_section_show(struct device *dev,
  					 struct device_attribute *mattr,
  					 char *buf)
94baaee49   Borislav Petkov   amd64_edac: beef ...
5
  {
c56087595   Mauro Carvalho Chehab   amd64_edac: conve...
6
  	struct mem_ctl_info *mci = to_mci(dev);
94baaee49   Borislav Petkov   amd64_edac: beef ...
7
8
9
10
  	struct amd64_pvt *pvt = mci->pvt_info;
  	return sprintf(buf, "0x%x
  ", pvt->injection.section);
  }
eb919690b   Doug Thompson   amd64_edac: add D...
11
12
13
14
15
16
  /*
   * store error injection section value which refers to one of 4 16-byte sections
   * within a 64-byte cacheline
   *
   * range: 0..3
   */
c56087595   Mauro Carvalho Chehab   amd64_edac: conve...
17
18
  static ssize_t amd64_inject_section_store(struct device *dev,
  					  struct device_attribute *mattr,
eb919690b   Doug Thompson   amd64_edac: add D...
19
20
  					  const char *data, size_t count)
  {
c56087595   Mauro Carvalho Chehab   amd64_edac: conve...
21
  	struct mem_ctl_info *mci = to_mci(dev);
eb919690b   Doug Thompson   amd64_edac: add D...
22
23
  	struct amd64_pvt *pvt = mci->pvt_info;
  	unsigned long value;
6e71a870b   Borislav Petkov   amd64_edac: Clean...
24
  	int ret;
eb919690b   Doug Thompson   amd64_edac: add D...
25

c7f62fc87   Jingoo Han   EDAC: Replace str...
26
  	ret = kstrtoul(data, 10, &value);
6e71a870b   Borislav Petkov   amd64_edac: Clean...
27
28
  	if (ret < 0)
  		return ret;
94baaee49   Borislav Petkov   amd64_edac: beef ...
29

6e71a870b   Borislav Petkov   amd64_edac: Clean...
30
31
32
33
  	if (value > 3) {
  		amd64_warn("%s: invalid section 0x%lx
  ", __func__, value);
  		return -EINVAL;
eb919690b   Doug Thompson   amd64_edac: add D...
34
  	}
6e71a870b   Borislav Petkov   amd64_edac: Clean...
35
36
37
  
  	pvt->injection.section = (u32) value;
  	return count;
eb919690b   Doug Thompson   amd64_edac: add D...
38
  }
c56087595   Mauro Carvalho Chehab   amd64_edac: conve...
39
40
41
  static ssize_t amd64_inject_word_show(struct device *dev,
  					struct device_attribute *mattr,
  					char *buf)
94baaee49   Borislav Petkov   amd64_edac: beef ...
42
  {
c56087595   Mauro Carvalho Chehab   amd64_edac: conve...
43
  	struct mem_ctl_info *mci = to_mci(dev);
94baaee49   Borislav Petkov   amd64_edac: beef ...
44
45
46
47
  	struct amd64_pvt *pvt = mci->pvt_info;
  	return sprintf(buf, "0x%x
  ", pvt->injection.word);
  }
eb919690b   Doug Thompson   amd64_edac: add D...
48
49
50
51
52
53
  /*
   * 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   Mauro Carvalho Chehab   amd64_edac: conve...
54
55
56
  static ssize_t amd64_inject_word_store(struct device *dev,
  				       struct device_attribute *mattr,
  				       const char *data, size_t count)
eb919690b   Doug Thompson   amd64_edac: add D...
57
  {
c56087595   Mauro Carvalho Chehab   amd64_edac: conve...
58
  	struct mem_ctl_info *mci = to_mci(dev);
eb919690b   Doug Thompson   amd64_edac: add D...
59
60
  	struct amd64_pvt *pvt = mci->pvt_info;
  	unsigned long value;
6e71a870b   Borislav Petkov   amd64_edac: Clean...
61
  	int ret;
eb919690b   Doug Thompson   amd64_edac: add D...
62

c7f62fc87   Jingoo Han   EDAC: Replace str...
63
  	ret = kstrtoul(data, 10, &value);
6e71a870b   Borislav Petkov   amd64_edac: Clean...
64
65
  	if (ret < 0)
  		return ret;
eb919690b   Doug Thompson   amd64_edac: add D...
66

6e71a870b   Borislav Petkov   amd64_edac: Clean...
67
68
69
70
  	if (value > 8) {
  		amd64_warn("%s: invalid word 0x%lx
  ", __func__, value);
  		return -EINVAL;
eb919690b   Doug Thompson   amd64_edac: add D...
71
  	}
6e71a870b   Borislav Petkov   amd64_edac: Clean...
72
73
74
  
  	pvt->injection.word = (u32) value;
  	return count;
eb919690b   Doug Thompson   amd64_edac: add D...
75
  }
c56087595   Mauro Carvalho Chehab   amd64_edac: conve...
76
77
78
  static ssize_t amd64_inject_ecc_vector_show(struct device *dev,
  					    struct device_attribute *mattr,
  					    char *buf)
94baaee49   Borislav Petkov   amd64_edac: beef ...
79
  {
c56087595   Mauro Carvalho Chehab   amd64_edac: conve...
80
  	struct mem_ctl_info *mci = to_mci(dev);
94baaee49   Borislav Petkov   amd64_edac: beef ...
81
82
83
84
  	struct amd64_pvt *pvt = mci->pvt_info;
  	return sprintf(buf, "0x%x
  ", pvt->injection.bit_map);
  }
eb919690b   Doug Thompson   amd64_edac: add D...
85
86
87
88
89
  /*
   * 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   Mauro Carvalho Chehab   amd64_edac: conve...
90
91
92
  static ssize_t amd64_inject_ecc_vector_store(struct device *dev,
  				       struct device_attribute *mattr,
  				       const char *data, size_t count)
eb919690b   Doug Thompson   amd64_edac: add D...
93
  {
c56087595   Mauro Carvalho Chehab   amd64_edac: conve...
94
  	struct mem_ctl_info *mci = to_mci(dev);
eb919690b   Doug Thompson   amd64_edac: add D...
95
96
  	struct amd64_pvt *pvt = mci->pvt_info;
  	unsigned long value;
6e71a870b   Borislav Petkov   amd64_edac: Clean...
97
  	int ret;
eb919690b   Doug Thompson   amd64_edac: add D...
98

c7f62fc87   Jingoo Han   EDAC: Replace str...
99
  	ret = kstrtoul(data, 16, &value);
6e71a870b   Borislav Petkov   amd64_edac: Clean...
100
101
  	if (ret < 0)
  		return ret;
eb919690b   Doug Thompson   amd64_edac: add D...
102

6e71a870b   Borislav Petkov   amd64_edac: Clean...
103
104
105
106
  	if (value & 0xFFFF0000) {
  		amd64_warn("%s: invalid EccVector: 0x%lx
  ", __func__, value);
  		return -EINVAL;
eb919690b   Doug Thompson   amd64_edac: add D...
107
  	}
6e71a870b   Borislav Petkov   amd64_edac: Clean...
108
109
110
  
  	pvt->injection.bit_map = (u32) value;
  	return count;
eb919690b   Doug Thompson   amd64_edac: add D...
111
112
113
114
115
116
  }
  
  /*
   * 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   Mauro Carvalho Chehab   amd64_edac: conve...
117
118
119
  static ssize_t amd64_inject_read_store(struct device *dev,
  				       struct device_attribute *mattr,
  				       const char *data, size_t count)
eb919690b   Doug Thompson   amd64_edac: add D...
120
  {
c56087595   Mauro Carvalho Chehab   amd64_edac: conve...
121
  	struct mem_ctl_info *mci = to_mci(dev);
eb919690b   Doug Thompson   amd64_edac: add D...
122
123
124
  	struct amd64_pvt *pvt = mci->pvt_info;
  	unsigned long value;
  	u32 section, word_bits;
6e71a870b   Borislav Petkov   amd64_edac: Clean...
125
  	int ret;
eb919690b   Doug Thompson   amd64_edac: add D...
126

c7f62fc87   Jingoo Han   EDAC: Replace str...
127
  	ret = kstrtoul(data, 10, &value);
6e71a870b   Borislav Petkov   amd64_edac: Clean...
128
129
  	if (ret < 0)
  		return ret;
eb919690b   Doug Thompson   amd64_edac: add D...
130

6e71a870b   Borislav Petkov   amd64_edac: Clean...
131
132
  	/* Form value to choose 16-byte section of cacheline */
  	section = F10_NB_ARRAY_DRAM | SET_NB_ARRAY_ADDR(pvt->injection.section);
eb919690b   Doug Thompson   amd64_edac: add D...
133

6e71a870b   Borislav Petkov   amd64_edac: Clean...
134
  	amd64_write_pci_cfg(pvt->F3, F10_NB_ARRAY_ADDR, section);
eb919690b   Doug Thompson   amd64_edac: add D...
135

6e71a870b   Borislav Petkov   amd64_edac: Clean...
136
  	word_bits = SET_NB_DRAM_INJECTION_READ(pvt->injection);
eb919690b   Doug Thompson   amd64_edac: add D...
137

6e71a870b   Borislav Petkov   amd64_edac: Clean...
138
139
  	/* Issue 'word' and 'bit' along with the READ request */
  	amd64_write_pci_cfg(pvt->F3, F10_NB_ARRAY_DATA, word_bits);
eb919690b   Doug Thompson   amd64_edac: add D...
140

6e71a870b   Borislav Petkov   amd64_edac: Clean...
141
142
143
144
  	edac_dbg(0, "section=0x%x word_bits=0x%x
  ", section, word_bits);
  
  	return count;
eb919690b   Doug Thompson   amd64_edac: add D...
145
146
147
148
149
150
  }
  
  /*
   * Do a DRAM ECC write. Assemble staged values in the pvt area and format into
   * fields needed by the injection registers.
   */
c56087595   Mauro Carvalho Chehab   amd64_edac: conve...
151
152
  static ssize_t amd64_inject_write_store(struct device *dev,
  					struct device_attribute *mattr,
eb919690b   Doug Thompson   amd64_edac: add D...
153
154
  					const char *data, size_t count)
  {
c56087595   Mauro Carvalho Chehab   amd64_edac: conve...
155
  	struct mem_ctl_info *mci = to_mci(dev);
eb919690b   Doug Thompson   amd64_edac: add D...
156
  	struct amd64_pvt *pvt = mci->pvt_info;
66fed2d46   Borislav Petkov   amd64_edac: Impro...
157
  	u32 section, word_bits, tmp;
eb919690b   Doug Thompson   amd64_edac: add D...
158
  	unsigned long value;
6e71a870b   Borislav Petkov   amd64_edac: Clean...
159
  	int ret;
eb919690b   Doug Thompson   amd64_edac: add D...
160

c7f62fc87   Jingoo Han   EDAC: Replace str...
161
  	ret = kstrtoul(data, 10, &value);
6e71a870b   Borislav Petkov   amd64_edac: Clean...
162
163
  	if (ret < 0)
  		return ret;
eb919690b   Doug Thompson   amd64_edac: add D...
164

6e71a870b   Borislav Petkov   amd64_edac: Clean...
165
166
  	/* Form value to choose 16-byte section of cacheline */
  	section = F10_NB_ARRAY_DRAM | SET_NB_ARRAY_ADDR(pvt->injection.section);
eb919690b   Doug Thompson   amd64_edac: add D...
167

6e71a870b   Borislav Petkov   amd64_edac: Clean...
168
  	amd64_write_pci_cfg(pvt->F3, F10_NB_ARRAY_ADDR, section);
eb919690b   Doug Thompson   amd64_edac: add D...
169

6e71a870b   Borislav Petkov   amd64_edac: Clean...
170
  	word_bits = SET_NB_DRAM_INJECTION_WRITE(pvt->injection);
eb919690b   Doug Thompson   amd64_edac: add D...
171

66fed2d46   Borislav Petkov   amd64_edac: Impro...
172
173
174
175
176
177
178
179
  	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   Borislav Petkov   amd64_edac: Clean...
180
181
  	/* Issue 'word' and 'bit' along with the READ request */
  	amd64_write_pci_cfg(pvt->F3, F10_NB_ARRAY_DATA, word_bits);
eb919690b   Doug Thompson   amd64_edac: add D...
182

66fed2d46   Borislav Petkov   amd64_edac: Impro...
183
184
185
186
187
188
189
190
191
   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   Borislav Petkov   amd64_edac: Clean...
192
193
194
195
  	edac_dbg(0, "section=0x%x word_bits=0x%x
  ", section, word_bits);
  
  	return count;
eb919690b   Doug Thompson   amd64_edac: add D...
196
197
198
199
200
  }
  
  /*
   * update NUM_INJ_ATTRS in case you add new members
   */
c56087595   Mauro Carvalho Chehab   amd64_edac: conve...
201
202
203
204
205
206
207
  
  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   Borislav Petkov   amd64_edac: Fix b...
208
  static DEVICE_ATTR(inject_write, S_IWUSR,
c56087595   Mauro Carvalho Chehab   amd64_edac: conve...
209
  		   NULL, amd64_inject_write_store);
bbb013b92   Borislav Petkov   amd64_edac: Fix b...
210
  static DEVICE_ATTR(inject_read,  S_IWUSR,
c56087595   Mauro Carvalho Chehab   amd64_edac: conve...
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
  		   NULL, amd64_inject_read_store);
  
  
  int amd64_create_sysfs_inject_files(struct mem_ctl_info *mci)
  {
  	int rc;
  
  	rc = device_create_file(&mci->dev, &dev_attr_inject_section);
  	if (rc < 0)
  		return rc;
  	rc = device_create_file(&mci->dev, &dev_attr_inject_word);
  	if (rc < 0)
  		return rc;
  	rc = device_create_file(&mci->dev, &dev_attr_inject_ecc_vector);
  	if (rc < 0)
  		return rc;
  	rc = device_create_file(&mci->dev, &dev_attr_inject_write);
  	if (rc < 0)
  		return rc;
  	rc = device_create_file(&mci->dev, &dev_attr_inject_read);
  	if (rc < 0)
  		return rc;
  
  	return 0;
  }
  
  void amd64_remove_sysfs_inject_files(struct mem_ctl_info *mci)
  {
  	device_remove_file(&mci->dev, &dev_attr_inject_section);
  	device_remove_file(&mci->dev, &dev_attr_inject_word);
  	device_remove_file(&mci->dev, &dev_attr_inject_ecc_vector);
  	device_remove_file(&mci->dev, &dev_attr_inject_write);
  	device_remove_file(&mci->dev, &dev_attr_inject_read);
  }