Blame view

drivers/edac/amd64_edac_inj.c 6.23 KB
b24413180   Greg Kroah-Hartman   License cleanup: ...
1
  // SPDX-License-Identifier: GPL-2.0
eb919690b   Doug Thompson   amd64_edac: add D...
2
  #include "amd64_edac.h"
c56087595   Mauro Carvalho Chehab   amd64_edac: conve...
3
4
5
  static ssize_t amd64_inject_section_show(struct device *dev,
  					 struct device_attribute *mattr,
  					 char *buf)
94baaee49   Borislav Petkov   amd64_edac: beef ...
6
  {
c56087595   Mauro Carvalho Chehab   amd64_edac: conve...
7
  	struct mem_ctl_info *mci = to_mci(dev);
94baaee49   Borislav Petkov   amd64_edac: beef ...
8
9
10
11
  	struct amd64_pvt *pvt = mci->pvt_info;
  	return sprintf(buf, "0x%x
  ", pvt->injection.section);
  }
eb919690b   Doug Thompson   amd64_edac: add D...
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   Mauro Carvalho Chehab   amd64_edac: conve...
18
19
  static ssize_t amd64_inject_section_store(struct device *dev,
  					  struct device_attribute *mattr,
eb919690b   Doug Thompson   amd64_edac: add D...
20
21
  					  const char *data, size_t count)
  {
c56087595   Mauro Carvalho Chehab   amd64_edac: conve...
22
  	struct mem_ctl_info *mci = to_mci(dev);
eb919690b   Doug Thompson   amd64_edac: add D...
23
24
  	struct amd64_pvt *pvt = mci->pvt_info;
  	unsigned long value;
6e71a870b   Borislav Petkov   amd64_edac: Clean...
25
  	int ret;
eb919690b   Doug Thompson   amd64_edac: add D...
26

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

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

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

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

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

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

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

6e71a870b   Borislav Petkov   amd64_edac: Clean...
132
133
  	/* 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...
134

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

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

6e71a870b   Borislav Petkov   amd64_edac: Clean...
139
140
  	/* 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...
141

6e71a870b   Borislav Petkov   amd64_edac: Clean...
142
143
144
145
  	edac_dbg(0, "section=0x%x word_bits=0x%x
  ", section, word_bits);
  
  	return count;
eb919690b   Doug Thompson   amd64_edac: add D...
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   Mauro Carvalho Chehab   amd64_edac: conve...
152
153
  static ssize_t amd64_inject_write_store(struct device *dev,
  					struct device_attribute *mattr,
eb919690b   Doug Thompson   amd64_edac: add D...
154
155
  					const char *data, size_t count)
  {
c56087595   Mauro Carvalho Chehab   amd64_edac: conve...
156
  	struct mem_ctl_info *mci = to_mci(dev);
eb919690b   Doug Thompson   amd64_edac: add D...
157
  	struct amd64_pvt *pvt = mci->pvt_info;
66fed2d46   Borislav Petkov   amd64_edac: Impro...
158
  	u32 section, word_bits, tmp;
eb919690b   Doug Thompson   amd64_edac: add D...
159
  	unsigned long value;
6e71a870b   Borislav Petkov   amd64_edac: Clean...
160
  	int ret;
eb919690b   Doug Thompson   amd64_edac: add D...
161

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

6e71a870b   Borislav Petkov   amd64_edac: Clean...
166
167
  	/* 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...
168

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

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

66fed2d46   Borislav Petkov   amd64_edac: Impro...
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   Borislav Petkov   amd64_edac: Clean...
181
182
  	/* 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...
183

66fed2d46   Borislav Petkov   amd64_edac: Impro...
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   Borislav Petkov   amd64_edac: Clean...
193
194
195
196
  	edac_dbg(0, "section=0x%x word_bits=0x%x
  ", section, word_bits);
  
  	return count;
eb919690b   Doug Thompson   amd64_edac: add D...
197
198
199
200
201
  }
  
  /*
   * update NUM_INJ_ATTRS in case you add new members
   */
c56087595   Mauro Carvalho Chehab   amd64_edac: conve...
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   Borislav Petkov   amd64_edac: Fix b...
209
  static DEVICE_ATTR(inject_write, S_IWUSR,
c56087595   Mauro Carvalho Chehab   amd64_edac: conve...
210
  		   NULL, amd64_inject_write_store);
bbb013b92   Borislav Petkov   amd64_edac: Fix b...
211
  static DEVICE_ATTR(inject_read,  S_IWUSR,
c56087595   Mauro Carvalho Chehab   amd64_edac: conve...
212
  		   NULL, amd64_inject_read_store);
e339f1ec9   Takashi Iwai   EDAC: amd64: Use ...
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   Mauro Carvalho Chehab   amd64_edac: conve...
224
  {
e339f1ec9   Takashi Iwai   EDAC: amd64: Use ...
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   Mauro Carvalho Chehab   amd64_edac: conve...
228

e339f1ec9   Takashi Iwai   EDAC: amd64: Use ...
229
230
231
  	if (pvt->fam < 0x10)
  		return 0;
  	return attr->mode;
c56087595   Mauro Carvalho Chehab   amd64_edac: conve...
232
  }
e339f1ec9   Takashi Iwai   EDAC: amd64: Use ...
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,
  };