Branch data Line data Source code
1 : : /*
2 : : * edac_mc kernel module
3 : : * (C) 2005-2007 Linux Networx (http://lnxi.com)
4 : : *
5 : : * This file may be distributed under the terms of the
6 : : * GNU General Public License.
7 : : *
8 : : * Written Doug Thompson <norsk5@xmission.com> www.softwarebitmaker.com
9 : : *
10 : : * (c) 2012-2013 - Mauro Carvalho Chehab
11 : : * The entire API were re-written, and ported to use struct device
12 : : *
13 : : */
14 : :
15 : : #include <linux/ctype.h>
16 : : #include <linux/slab.h>
17 : : #include <linux/edac.h>
18 : : #include <linux/bug.h>
19 : : #include <linux/pm_runtime.h>
20 : : #include <linux/uaccess.h>
21 : :
22 : : #include "edac_mc.h"
23 : : #include "edac_module.h"
24 : :
25 : : /* MC EDAC Controls, setable by module parameter, and sysfs */
26 : : static int edac_mc_log_ue = 1;
27 : : static int edac_mc_log_ce = 1;
28 : : static int edac_mc_panic_on_ue;
29 : : static unsigned int edac_mc_poll_msec = 1000;
30 : :
31 : : /* Getter functions for above */
32 : 0 : int edac_mc_get_log_ue(void)
33 : : {
34 : 0 : return edac_mc_log_ue;
35 : : }
36 : :
37 : 0 : int edac_mc_get_log_ce(void)
38 : : {
39 : 0 : return edac_mc_log_ce;
40 : : }
41 : :
42 : 0 : int edac_mc_get_panic_on_ue(void)
43 : : {
44 : 0 : return edac_mc_panic_on_ue;
45 : : }
46 : :
47 : : /* this is temporary */
48 : 0 : unsigned int edac_mc_get_poll_msec(void)
49 : : {
50 : 0 : return edac_mc_poll_msec;
51 : : }
52 : :
53 : 0 : static int edac_set_poll_msec(const char *val, const struct kernel_param *kp)
54 : : {
55 : 0 : unsigned int i;
56 : 0 : int ret;
57 : :
58 [ # # ]: 0 : if (!val)
59 : : return -EINVAL;
60 : :
61 : 0 : ret = kstrtouint(val, 0, &i);
62 [ # # ]: 0 : if (ret)
63 : : return ret;
64 : :
65 [ # # ]: 0 : if (i < 1000)
66 : : return -EINVAL;
67 : :
68 : 0 : *((unsigned int *)kp->arg) = i;
69 : :
70 : : /* notify edac_mc engine to reset the poll period */
71 : 0 : edac_mc_reset_delay_period(i);
72 : :
73 : 0 : return 0;
74 : : }
75 : :
76 : : /* Parameter declarations for above */
77 : : module_param(edac_mc_panic_on_ue, int, 0644);
78 : : MODULE_PARM_DESC(edac_mc_panic_on_ue, "Panic on uncorrected error: 0=off 1=on");
79 : : module_param(edac_mc_log_ue, int, 0644);
80 : : MODULE_PARM_DESC(edac_mc_log_ue,
81 : : "Log uncorrectable error to console: 0=off 1=on");
82 : : module_param(edac_mc_log_ce, int, 0644);
83 : : MODULE_PARM_DESC(edac_mc_log_ce,
84 : : "Log correctable error to console: 0=off 1=on");
85 : : module_param_call(edac_mc_poll_msec, edac_set_poll_msec, param_get_uint,
86 : : &edac_mc_poll_msec, 0644);
87 : : MODULE_PARM_DESC(edac_mc_poll_msec, "Polling period in milliseconds");
88 : :
89 : : static struct device *mci_pdev;
90 : :
91 : : /*
92 : : * various constants for Memory Controllers
93 : : */
94 : : static const char * const dev_types[] = {
95 : : [DEV_UNKNOWN] = "Unknown",
96 : : [DEV_X1] = "x1",
97 : : [DEV_X2] = "x2",
98 : : [DEV_X4] = "x4",
99 : : [DEV_X8] = "x8",
100 : : [DEV_X16] = "x16",
101 : : [DEV_X32] = "x32",
102 : : [DEV_X64] = "x64"
103 : : };
104 : :
105 : : static const char * const edac_caps[] = {
106 : : [EDAC_UNKNOWN] = "Unknown",
107 : : [EDAC_NONE] = "None",
108 : : [EDAC_RESERVED] = "Reserved",
109 : : [EDAC_PARITY] = "PARITY",
110 : : [EDAC_EC] = "EC",
111 : : [EDAC_SECDED] = "SECDED",
112 : : [EDAC_S2ECD2ED] = "S2ECD2ED",
113 : : [EDAC_S4ECD4ED] = "S4ECD4ED",
114 : : [EDAC_S8ECD8ED] = "S8ECD8ED",
115 : : [EDAC_S16ECD16ED] = "S16ECD16ED"
116 : : };
117 : :
118 : : #ifdef CONFIG_EDAC_LEGACY_SYSFS
119 : : /*
120 : : * EDAC sysfs CSROW data structures and methods
121 : : */
122 : :
123 : : #define to_csrow(k) container_of(k, struct csrow_info, dev)
124 : :
125 : : /*
126 : : * We need it to avoid namespace conflicts between the legacy API
127 : : * and the per-dimm/per-rank one
128 : : */
129 : : #define DEVICE_ATTR_LEGACY(_name, _mode, _show, _store) \
130 : : static struct device_attribute dev_attr_legacy_##_name = __ATTR(_name, _mode, _show, _store)
131 : :
132 : : struct dev_ch_attribute {
133 : : struct device_attribute attr;
134 : : unsigned int channel;
135 : : };
136 : :
137 : : #define DEVICE_CHANNEL(_name, _mode, _show, _store, _var) \
138 : : static struct dev_ch_attribute dev_attr_legacy_##_name = \
139 : : { __ATTR(_name, _mode, _show, _store), (_var) }
140 : :
141 : : #define to_channel(k) (container_of(k, struct dev_ch_attribute, attr)->channel)
142 : :
143 : : /* Set of more default csrow<id> attribute show/store functions */
144 : 0 : static ssize_t csrow_ue_count_show(struct device *dev,
145 : : struct device_attribute *mattr, char *data)
146 : : {
147 : 0 : struct csrow_info *csrow = to_csrow(dev);
148 : :
149 : 0 : return sprintf(data, "%u\n", csrow->ue_count);
150 : : }
151 : :
152 : 0 : static ssize_t csrow_ce_count_show(struct device *dev,
153 : : struct device_attribute *mattr, char *data)
154 : : {
155 : 0 : struct csrow_info *csrow = to_csrow(dev);
156 : :
157 : 0 : return sprintf(data, "%u\n", csrow->ce_count);
158 : : }
159 : :
160 : 0 : static ssize_t csrow_size_show(struct device *dev,
161 : : struct device_attribute *mattr, char *data)
162 : : {
163 : 0 : struct csrow_info *csrow = to_csrow(dev);
164 : 0 : int i;
165 : 0 : u32 nr_pages = 0;
166 : :
167 [ # # ]: 0 : for (i = 0; i < csrow->nr_channels; i++)
168 : 0 : nr_pages += csrow->channels[i]->dimm->nr_pages;
169 : 0 : return sprintf(data, "%u\n", PAGES_TO_MiB(nr_pages));
170 : : }
171 : :
172 : 0 : static ssize_t csrow_mem_type_show(struct device *dev,
173 : : struct device_attribute *mattr, char *data)
174 : : {
175 : 0 : struct csrow_info *csrow = to_csrow(dev);
176 : :
177 : 0 : return sprintf(data, "%s\n", edac_mem_types[csrow->channels[0]->dimm->mtype]);
178 : : }
179 : :
180 : 0 : static ssize_t csrow_dev_type_show(struct device *dev,
181 : : struct device_attribute *mattr, char *data)
182 : : {
183 : 0 : struct csrow_info *csrow = to_csrow(dev);
184 : :
185 : 0 : return sprintf(data, "%s\n", dev_types[csrow->channels[0]->dimm->dtype]);
186 : : }
187 : :
188 : 0 : static ssize_t csrow_edac_mode_show(struct device *dev,
189 : : struct device_attribute *mattr,
190 : : char *data)
191 : : {
192 : 0 : struct csrow_info *csrow = to_csrow(dev);
193 : :
194 : 0 : return sprintf(data, "%s\n", edac_caps[csrow->channels[0]->dimm->edac_mode]);
195 : : }
196 : :
197 : : /* show/store functions for DIMM Label attributes */
198 : 0 : static ssize_t channel_dimm_label_show(struct device *dev,
199 : : struct device_attribute *mattr,
200 : : char *data)
201 : : {
202 : 0 : struct csrow_info *csrow = to_csrow(dev);
203 : 0 : unsigned int chan = to_channel(mattr);
204 : 0 : struct rank_info *rank = csrow->channels[chan];
205 : :
206 : : /* if field has not been initialized, there is nothing to send */
207 [ # # ]: 0 : if (!rank->dimm->label[0])
208 : : return 0;
209 : :
210 : 0 : return snprintf(data, sizeof(rank->dimm->label) + 1, "%s\n",
211 : 0 : rank->dimm->label);
212 : : }
213 : :
214 : 0 : static ssize_t channel_dimm_label_store(struct device *dev,
215 : : struct device_attribute *mattr,
216 : : const char *data, size_t count)
217 : : {
218 : 0 : struct csrow_info *csrow = to_csrow(dev);
219 : 0 : unsigned int chan = to_channel(mattr);
220 : 0 : struct rank_info *rank = csrow->channels[chan];
221 : 0 : size_t copy_count = count;
222 : :
223 [ # # ]: 0 : if (count == 0)
224 : : return -EINVAL;
225 : :
226 [ # # ]: 0 : if (data[count - 1] == '\0' || data[count - 1] == '\n')
227 : 0 : copy_count -= 1;
228 : :
229 [ # # ]: 0 : if (copy_count == 0 || copy_count >= sizeof(rank->dimm->label))
230 : : return -EINVAL;
231 : :
232 : 0 : strncpy(rank->dimm->label, data, copy_count);
233 : 0 : rank->dimm->label[copy_count] = '\0';
234 : :
235 : 0 : return count;
236 : : }
237 : :
238 : : /* show function for dynamic chX_ce_count attribute */
239 : 0 : static ssize_t channel_ce_count_show(struct device *dev,
240 : : struct device_attribute *mattr, char *data)
241 : : {
242 : 0 : struct csrow_info *csrow = to_csrow(dev);
243 : 0 : unsigned int chan = to_channel(mattr);
244 : 0 : struct rank_info *rank = csrow->channels[chan];
245 : :
246 : 0 : return sprintf(data, "%u\n", rank->ce_count);
247 : : }
248 : :
249 : : /* cwrow<id>/attribute files */
250 : : DEVICE_ATTR_LEGACY(size_mb, S_IRUGO, csrow_size_show, NULL);
251 : : DEVICE_ATTR_LEGACY(dev_type, S_IRUGO, csrow_dev_type_show, NULL);
252 : : DEVICE_ATTR_LEGACY(mem_type, S_IRUGO, csrow_mem_type_show, NULL);
253 : : DEVICE_ATTR_LEGACY(edac_mode, S_IRUGO, csrow_edac_mode_show, NULL);
254 : : DEVICE_ATTR_LEGACY(ue_count, S_IRUGO, csrow_ue_count_show, NULL);
255 : : DEVICE_ATTR_LEGACY(ce_count, S_IRUGO, csrow_ce_count_show, NULL);
256 : :
257 : : /* default attributes of the CSROW<id> object */
258 : : static struct attribute *csrow_attrs[] = {
259 : : &dev_attr_legacy_dev_type.attr,
260 : : &dev_attr_legacy_mem_type.attr,
261 : : &dev_attr_legacy_edac_mode.attr,
262 : : &dev_attr_legacy_size_mb.attr,
263 : : &dev_attr_legacy_ue_count.attr,
264 : : &dev_attr_legacy_ce_count.attr,
265 : : NULL,
266 : : };
267 : :
268 : : static const struct attribute_group csrow_attr_grp = {
269 : : .attrs = csrow_attrs,
270 : : };
271 : :
272 : : static const struct attribute_group *csrow_attr_groups[] = {
273 : : &csrow_attr_grp,
274 : : NULL
275 : : };
276 : :
277 : 0 : static void csrow_attr_release(struct device *dev)
278 : : {
279 : : /* release device with _edac_mc_free() */
280 : 0 : }
281 : :
282 : : static const struct device_type csrow_attr_type = {
283 : : .groups = csrow_attr_groups,
284 : : .release = csrow_attr_release,
285 : : };
286 : :
287 : : /*
288 : : * possible dynamic channel DIMM Label attribute files
289 : : *
290 : : */
291 : : DEVICE_CHANNEL(ch0_dimm_label, S_IRUGO | S_IWUSR,
292 : : channel_dimm_label_show, channel_dimm_label_store, 0);
293 : : DEVICE_CHANNEL(ch1_dimm_label, S_IRUGO | S_IWUSR,
294 : : channel_dimm_label_show, channel_dimm_label_store, 1);
295 : : DEVICE_CHANNEL(ch2_dimm_label, S_IRUGO | S_IWUSR,
296 : : channel_dimm_label_show, channel_dimm_label_store, 2);
297 : : DEVICE_CHANNEL(ch3_dimm_label, S_IRUGO | S_IWUSR,
298 : : channel_dimm_label_show, channel_dimm_label_store, 3);
299 : : DEVICE_CHANNEL(ch4_dimm_label, S_IRUGO | S_IWUSR,
300 : : channel_dimm_label_show, channel_dimm_label_store, 4);
301 : : DEVICE_CHANNEL(ch5_dimm_label, S_IRUGO | S_IWUSR,
302 : : channel_dimm_label_show, channel_dimm_label_store, 5);
303 : : DEVICE_CHANNEL(ch6_dimm_label, S_IRUGO | S_IWUSR,
304 : : channel_dimm_label_show, channel_dimm_label_store, 6);
305 : : DEVICE_CHANNEL(ch7_dimm_label, S_IRUGO | S_IWUSR,
306 : : channel_dimm_label_show, channel_dimm_label_store, 7);
307 : :
308 : : /* Total possible dynamic DIMM Label attribute file table */
309 : : static struct attribute *dynamic_csrow_dimm_attr[] = {
310 : : &dev_attr_legacy_ch0_dimm_label.attr.attr,
311 : : &dev_attr_legacy_ch1_dimm_label.attr.attr,
312 : : &dev_attr_legacy_ch2_dimm_label.attr.attr,
313 : : &dev_attr_legacy_ch3_dimm_label.attr.attr,
314 : : &dev_attr_legacy_ch4_dimm_label.attr.attr,
315 : : &dev_attr_legacy_ch5_dimm_label.attr.attr,
316 : : &dev_attr_legacy_ch6_dimm_label.attr.attr,
317 : : &dev_attr_legacy_ch7_dimm_label.attr.attr,
318 : : NULL
319 : : };
320 : :
321 : : /* possible dynamic channel ce_count attribute files */
322 : : DEVICE_CHANNEL(ch0_ce_count, S_IRUGO,
323 : : channel_ce_count_show, NULL, 0);
324 : : DEVICE_CHANNEL(ch1_ce_count, S_IRUGO,
325 : : channel_ce_count_show, NULL, 1);
326 : : DEVICE_CHANNEL(ch2_ce_count, S_IRUGO,
327 : : channel_ce_count_show, NULL, 2);
328 : : DEVICE_CHANNEL(ch3_ce_count, S_IRUGO,
329 : : channel_ce_count_show, NULL, 3);
330 : : DEVICE_CHANNEL(ch4_ce_count, S_IRUGO,
331 : : channel_ce_count_show, NULL, 4);
332 : : DEVICE_CHANNEL(ch5_ce_count, S_IRUGO,
333 : : channel_ce_count_show, NULL, 5);
334 : : DEVICE_CHANNEL(ch6_ce_count, S_IRUGO,
335 : : channel_ce_count_show, NULL, 6);
336 : : DEVICE_CHANNEL(ch7_ce_count, S_IRUGO,
337 : : channel_ce_count_show, NULL, 7);
338 : :
339 : : /* Total possible dynamic ce_count attribute file table */
340 : : static struct attribute *dynamic_csrow_ce_count_attr[] = {
341 : : &dev_attr_legacy_ch0_ce_count.attr.attr,
342 : : &dev_attr_legacy_ch1_ce_count.attr.attr,
343 : : &dev_attr_legacy_ch2_ce_count.attr.attr,
344 : : &dev_attr_legacy_ch3_ce_count.attr.attr,
345 : : &dev_attr_legacy_ch4_ce_count.attr.attr,
346 : : &dev_attr_legacy_ch5_ce_count.attr.attr,
347 : : &dev_attr_legacy_ch6_ce_count.attr.attr,
348 : : &dev_attr_legacy_ch7_ce_count.attr.attr,
349 : : NULL
350 : : };
351 : :
352 : 0 : static umode_t csrow_dev_is_visible(struct kobject *kobj,
353 : : struct attribute *attr, int idx)
354 : : {
355 [ # # ]: 0 : struct device *dev = kobj_to_dev(kobj);
356 : 0 : struct csrow_info *csrow = container_of(dev, struct csrow_info, dev);
357 : :
358 [ # # ]: 0 : if (idx >= csrow->nr_channels)
359 : : return 0;
360 : :
361 [ # # ]: 0 : if (idx >= ARRAY_SIZE(dynamic_csrow_ce_count_attr) - 1) {
362 [ # # ]: 0 : WARN_ONCE(1, "idx: %d\n", idx);
363 : 0 : return 0;
364 : : }
365 : :
366 : : /* Only expose populated DIMMs */
367 [ # # ]: 0 : if (!csrow->channels[idx]->dimm->nr_pages)
368 : : return 0;
369 : :
370 : 0 : return attr->mode;
371 : : }
372 : :
373 : :
374 : : static const struct attribute_group csrow_dev_dimm_group = {
375 : : .attrs = dynamic_csrow_dimm_attr,
376 : : .is_visible = csrow_dev_is_visible,
377 : : };
378 : :
379 : : static const struct attribute_group csrow_dev_ce_count_group = {
380 : : .attrs = dynamic_csrow_ce_count_attr,
381 : : .is_visible = csrow_dev_is_visible,
382 : : };
383 : :
384 : : static const struct attribute_group *csrow_dev_groups[] = {
385 : : &csrow_dev_dimm_group,
386 : : &csrow_dev_ce_count_group,
387 : : NULL
388 : : };
389 : :
390 : 0 : static inline int nr_pages_per_csrow(struct csrow_info *csrow)
391 : : {
392 : : int chan, nr_pages = 0;
393 : :
394 [ # # # # ]: 0 : for (chan = 0; chan < csrow->nr_channels; chan++)
395 : 0 : nr_pages += csrow->channels[chan]->dimm->nr_pages;
396 : :
397 : 0 : return nr_pages;
398 : : }
399 : :
400 : : /* Create a CSROW object under specifed edac_mc_device */
401 : 0 : static int edac_create_csrow_object(struct mem_ctl_info *mci,
402 : : struct csrow_info *csrow, int index)
403 : : {
404 : 0 : int err;
405 : :
406 : 0 : csrow->dev.type = &csrow_attr_type;
407 : 0 : csrow->dev.groups = csrow_dev_groups;
408 : 0 : device_initialize(&csrow->dev);
409 : 0 : csrow->dev.parent = &mci->dev;
410 : 0 : csrow->mci = mci;
411 : 0 : dev_set_name(&csrow->dev, "csrow%d", index);
412 : 0 : dev_set_drvdata(&csrow->dev, csrow);
413 : :
414 : 0 : err = device_add(&csrow->dev);
415 [ # # ]: 0 : if (err) {
416 : 0 : edac_dbg(1, "failure: create device %s\n", dev_name(&csrow->dev));
417 : 0 : put_device(&csrow->dev);
418 : 0 : return err;
419 : : }
420 : :
421 : : edac_dbg(0, "device %s created\n", dev_name(&csrow->dev));
422 : :
423 : : return 0;
424 : : }
425 : :
426 : : /* Create a CSROW object under specifed edac_mc_device */
427 : 0 : static int edac_create_csrow_objects(struct mem_ctl_info *mci)
428 : : {
429 : 0 : int err, i;
430 : 0 : struct csrow_info *csrow;
431 : :
432 [ # # ]: 0 : for (i = 0; i < mci->nr_csrows; i++) {
433 : 0 : csrow = mci->csrows[i];
434 [ # # ]: 0 : if (!nr_pages_per_csrow(csrow))
435 : 0 : continue;
436 : 0 : err = edac_create_csrow_object(mci, mci->csrows[i], i);
437 [ # # ]: 0 : if (err < 0)
438 : 0 : goto error;
439 : : }
440 : : return 0;
441 : :
442 : : error:
443 [ # # ]: 0 : for (--i; i >= 0; i--) {
444 : 0 : csrow = mci->csrows[i];
445 [ # # ]: 0 : if (!nr_pages_per_csrow(csrow))
446 : 0 : continue;
447 : 0 : device_unregister(&mci->csrows[i]->dev);
448 : : }
449 : :
450 : : return err;
451 : : }
452 : :
453 : : static void edac_delete_csrow_objects(struct mem_ctl_info *mci)
454 : : {
455 : : int i;
456 : : struct csrow_info *csrow;
457 : :
458 : : for (i = mci->nr_csrows - 1; i >= 0; i--) {
459 : : csrow = mci->csrows[i];
460 : : if (!nr_pages_per_csrow(csrow))
461 : : continue;
462 : : device_unregister(&mci->csrows[i]->dev);
463 : : }
464 : : }
465 : : #endif
466 : :
467 : : /*
468 : : * Per-dimm (or per-rank) devices
469 : : */
470 : :
471 : : #define to_dimm(k) container_of(k, struct dimm_info, dev)
472 : :
473 : : /* show/store functions for DIMM Label attributes */
474 : 0 : static ssize_t dimmdev_location_show(struct device *dev,
475 : : struct device_attribute *mattr, char *data)
476 : : {
477 : 0 : struct dimm_info *dimm = to_dimm(dev);
478 : :
479 : 0 : return edac_dimm_info_location(dimm, data, PAGE_SIZE);
480 : : }
481 : :
482 : 0 : static ssize_t dimmdev_label_show(struct device *dev,
483 : : struct device_attribute *mattr, char *data)
484 : : {
485 : 0 : struct dimm_info *dimm = to_dimm(dev);
486 : :
487 : : /* if field has not been initialized, there is nothing to send */
488 [ # # ]: 0 : if (!dimm->label[0])
489 : : return 0;
490 : :
491 : 0 : return snprintf(data, sizeof(dimm->label) + 1, "%s\n", dimm->label);
492 : : }
493 : :
494 : 0 : static ssize_t dimmdev_label_store(struct device *dev,
495 : : struct device_attribute *mattr,
496 : : const char *data,
497 : : size_t count)
498 : : {
499 : 0 : struct dimm_info *dimm = to_dimm(dev);
500 : 0 : size_t copy_count = count;
501 : :
502 [ # # ]: 0 : if (count == 0)
503 : : return -EINVAL;
504 : :
505 [ # # ]: 0 : if (data[count - 1] == '\0' || data[count - 1] == '\n')
506 : 0 : copy_count -= 1;
507 : :
508 [ # # ]: 0 : if (copy_count == 0 || copy_count >= sizeof(dimm->label))
509 : : return -EINVAL;
510 : :
511 : 0 : strncpy(dimm->label, data, copy_count);
512 : 0 : dimm->label[copy_count] = '\0';
513 : :
514 : 0 : return count;
515 : : }
516 : :
517 : 0 : static ssize_t dimmdev_size_show(struct device *dev,
518 : : struct device_attribute *mattr, char *data)
519 : : {
520 : 0 : struct dimm_info *dimm = to_dimm(dev);
521 : :
522 : 0 : return sprintf(data, "%u\n", PAGES_TO_MiB(dimm->nr_pages));
523 : : }
524 : :
525 : 0 : static ssize_t dimmdev_mem_type_show(struct device *dev,
526 : : struct device_attribute *mattr, char *data)
527 : : {
528 : 0 : struct dimm_info *dimm = to_dimm(dev);
529 : :
530 : 0 : return sprintf(data, "%s\n", edac_mem_types[dimm->mtype]);
531 : : }
532 : :
533 : 0 : static ssize_t dimmdev_dev_type_show(struct device *dev,
534 : : struct device_attribute *mattr, char *data)
535 : : {
536 : 0 : struct dimm_info *dimm = to_dimm(dev);
537 : :
538 : 0 : return sprintf(data, "%s\n", dev_types[dimm->dtype]);
539 : : }
540 : :
541 : 0 : static ssize_t dimmdev_edac_mode_show(struct device *dev,
542 : : struct device_attribute *mattr,
543 : : char *data)
544 : : {
545 : 0 : struct dimm_info *dimm = to_dimm(dev);
546 : :
547 : 0 : return sprintf(data, "%s\n", edac_caps[dimm->edac_mode]);
548 : : }
549 : :
550 : 0 : static ssize_t dimmdev_ce_count_show(struct device *dev,
551 : : struct device_attribute *mattr,
552 : : char *data)
553 : : {
554 : 0 : struct dimm_info *dimm = to_dimm(dev);
555 : 0 : u32 count;
556 : :
557 : 0 : count = dimm->mci->ce_per_layer[dimm->mci->n_layers-1][dimm->idx];
558 : 0 : return sprintf(data, "%u\n", count);
559 : : }
560 : :
561 : 0 : static ssize_t dimmdev_ue_count_show(struct device *dev,
562 : : struct device_attribute *mattr,
563 : : char *data)
564 : : {
565 : 0 : struct dimm_info *dimm = to_dimm(dev);
566 : 0 : u32 count;
567 : :
568 : 0 : count = dimm->mci->ue_per_layer[dimm->mci->n_layers-1][dimm->idx];
569 : 0 : return sprintf(data, "%u\n", count);
570 : : }
571 : :
572 : : /* dimm/rank attribute files */
573 : : static DEVICE_ATTR(dimm_label, S_IRUGO | S_IWUSR,
574 : : dimmdev_label_show, dimmdev_label_store);
575 : : static DEVICE_ATTR(dimm_location, S_IRUGO, dimmdev_location_show, NULL);
576 : : static DEVICE_ATTR(size, S_IRUGO, dimmdev_size_show, NULL);
577 : : static DEVICE_ATTR(dimm_mem_type, S_IRUGO, dimmdev_mem_type_show, NULL);
578 : : static DEVICE_ATTR(dimm_dev_type, S_IRUGO, dimmdev_dev_type_show, NULL);
579 : : static DEVICE_ATTR(dimm_edac_mode, S_IRUGO, dimmdev_edac_mode_show, NULL);
580 : : static DEVICE_ATTR(dimm_ce_count, S_IRUGO, dimmdev_ce_count_show, NULL);
581 : : static DEVICE_ATTR(dimm_ue_count, S_IRUGO, dimmdev_ue_count_show, NULL);
582 : :
583 : : /* attributes of the dimm<id>/rank<id> object */
584 : : static struct attribute *dimm_attrs[] = {
585 : : &dev_attr_dimm_label.attr,
586 : : &dev_attr_dimm_location.attr,
587 : : &dev_attr_size.attr,
588 : : &dev_attr_dimm_mem_type.attr,
589 : : &dev_attr_dimm_dev_type.attr,
590 : : &dev_attr_dimm_edac_mode.attr,
591 : : &dev_attr_dimm_ce_count.attr,
592 : : &dev_attr_dimm_ue_count.attr,
593 : : NULL,
594 : : };
595 : :
596 : : static const struct attribute_group dimm_attr_grp = {
597 : : .attrs = dimm_attrs,
598 : : };
599 : :
600 : : static const struct attribute_group *dimm_attr_groups[] = {
601 : : &dimm_attr_grp,
602 : : NULL
603 : : };
604 : :
605 : 0 : static void dimm_attr_release(struct device *dev)
606 : : {
607 : : /* release device with _edac_mc_free() */
608 : 0 : }
609 : :
610 : : static const struct device_type dimm_attr_type = {
611 : : .groups = dimm_attr_groups,
612 : : .release = dimm_attr_release,
613 : : };
614 : :
615 : : /* Create a DIMM object under specifed memory controller device */
616 : 0 : static int edac_create_dimm_object(struct mem_ctl_info *mci,
617 : : struct dimm_info *dimm)
618 : : {
619 : 0 : int err;
620 : 0 : dimm->mci = mci;
621 : :
622 : 0 : dimm->dev.type = &dimm_attr_type;
623 : 0 : device_initialize(&dimm->dev);
624 : :
625 : 0 : dimm->dev.parent = &mci->dev;
626 [ # # ]: 0 : if (mci->csbased)
627 : 0 : dev_set_name(&dimm->dev, "rank%d", dimm->idx);
628 : : else
629 : 0 : dev_set_name(&dimm->dev, "dimm%d", dimm->idx);
630 : 0 : dev_set_drvdata(&dimm->dev, dimm);
631 : 0 : pm_runtime_forbid(&mci->dev);
632 : :
633 : 0 : err = device_add(&dimm->dev);
634 [ # # ]: 0 : if (err) {
635 : 0 : edac_dbg(1, "failure: create device %s\n", dev_name(&dimm->dev));
636 : 0 : put_device(&dimm->dev);
637 : 0 : return err;
638 : : }
639 : :
640 : : if (IS_ENABLED(CONFIG_EDAC_DEBUG)) {
641 : : char location[80];
642 : :
643 : : edac_dimm_info_location(dimm, location, sizeof(location));
644 : : edac_dbg(0, "device %s created at location %s\n",
645 : : dev_name(&dimm->dev), location);
646 : : }
647 : :
648 : : return 0;
649 : : }
650 : :
651 : : /*
652 : : * Memory controller device
653 : : */
654 : :
655 : : #define to_mci(k) container_of(k, struct mem_ctl_info, dev)
656 : :
657 : 0 : static ssize_t mci_reset_counters_store(struct device *dev,
658 : : struct device_attribute *mattr,
659 : : const char *data, size_t count)
660 : : {
661 : 0 : struct mem_ctl_info *mci = to_mci(dev);
662 : 0 : int cnt, row, chan, i;
663 : 0 : mci->ue_mc = 0;
664 : 0 : mci->ce_mc = 0;
665 : 0 : mci->ue_noinfo_count = 0;
666 : 0 : mci->ce_noinfo_count = 0;
667 : :
668 [ # # ]: 0 : for (row = 0; row < mci->nr_csrows; row++) {
669 : 0 : struct csrow_info *ri = mci->csrows[row];
670 : :
671 : 0 : ri->ue_count = 0;
672 : 0 : ri->ce_count = 0;
673 : :
674 [ # # ]: 0 : for (chan = 0; chan < ri->nr_channels; chan++)
675 : 0 : ri->channels[chan]->ce_count = 0;
676 : : }
677 : :
678 : : cnt = 1;
679 [ # # ]: 0 : for (i = 0; i < mci->n_layers; i++) {
680 : 0 : cnt *= mci->layers[i].size;
681 : 0 : memset(mci->ce_per_layer[i], 0, cnt * sizeof(u32));
682 : 0 : memset(mci->ue_per_layer[i], 0, cnt * sizeof(u32));
683 : : }
684 : :
685 : 0 : mci->start_time = jiffies;
686 : 0 : return count;
687 : : }
688 : :
689 : : /* Memory scrubbing interface:
690 : : *
691 : : * A MC driver can limit the scrubbing bandwidth based on the CPU type.
692 : : * Therefore, ->set_sdram_scrub_rate should be made to return the actual
693 : : * bandwidth that is accepted or 0 when scrubbing is to be disabled.
694 : : *
695 : : * Negative value still means that an error has occurred while setting
696 : : * the scrub rate.
697 : : */
698 : 0 : static ssize_t mci_sdram_scrub_rate_store(struct device *dev,
699 : : struct device_attribute *mattr,
700 : : const char *data, size_t count)
701 : : {
702 : 0 : struct mem_ctl_info *mci = to_mci(dev);
703 : 0 : unsigned long bandwidth = 0;
704 : 0 : int new_bw = 0;
705 : :
706 [ # # ]: 0 : if (kstrtoul(data, 10, &bandwidth) < 0)
707 : : return -EINVAL;
708 : :
709 : 0 : new_bw = mci->set_sdram_scrub_rate(mci, bandwidth);
710 [ # # ]: 0 : if (new_bw < 0) {
711 : 0 : edac_printk(KERN_WARNING, EDAC_MC,
712 : : "Error setting scrub rate to: %lu\n", bandwidth);
713 : 0 : return -EINVAL;
714 : : }
715 : :
716 : 0 : return count;
717 : : }
718 : :
719 : : /*
720 : : * ->get_sdram_scrub_rate() return value semantics same as above.
721 : : */
722 : 0 : static ssize_t mci_sdram_scrub_rate_show(struct device *dev,
723 : : struct device_attribute *mattr,
724 : : char *data)
725 : : {
726 : 0 : struct mem_ctl_info *mci = to_mci(dev);
727 : 0 : int bandwidth = 0;
728 : :
729 : 0 : bandwidth = mci->get_sdram_scrub_rate(mci);
730 [ # # ]: 0 : if (bandwidth < 0) {
731 : 0 : edac_printk(KERN_DEBUG, EDAC_MC, "Error reading scrub rate\n");
732 : 0 : return bandwidth;
733 : : }
734 : :
735 : 0 : return sprintf(data, "%d\n", bandwidth);
736 : : }
737 : :
738 : : /* default attribute files for the MCI object */
739 : 0 : static ssize_t mci_ue_count_show(struct device *dev,
740 : : struct device_attribute *mattr,
741 : : char *data)
742 : : {
743 : 0 : struct mem_ctl_info *mci = to_mci(dev);
744 : :
745 : 0 : return sprintf(data, "%d\n", mci->ue_mc);
746 : : }
747 : :
748 : 0 : static ssize_t mci_ce_count_show(struct device *dev,
749 : : struct device_attribute *mattr,
750 : : char *data)
751 : : {
752 : 0 : struct mem_ctl_info *mci = to_mci(dev);
753 : :
754 : 0 : return sprintf(data, "%d\n", mci->ce_mc);
755 : : }
756 : :
757 : 0 : static ssize_t mci_ce_noinfo_show(struct device *dev,
758 : : struct device_attribute *mattr,
759 : : char *data)
760 : : {
761 : 0 : struct mem_ctl_info *mci = to_mci(dev);
762 : :
763 : 0 : return sprintf(data, "%d\n", mci->ce_noinfo_count);
764 : : }
765 : :
766 : 0 : static ssize_t mci_ue_noinfo_show(struct device *dev,
767 : : struct device_attribute *mattr,
768 : : char *data)
769 : : {
770 : 0 : struct mem_ctl_info *mci = to_mci(dev);
771 : :
772 : 0 : return sprintf(data, "%d\n", mci->ue_noinfo_count);
773 : : }
774 : :
775 : 0 : static ssize_t mci_seconds_show(struct device *dev,
776 : : struct device_attribute *mattr,
777 : : char *data)
778 : : {
779 : 0 : struct mem_ctl_info *mci = to_mci(dev);
780 : :
781 : 0 : return sprintf(data, "%ld\n", (jiffies - mci->start_time) / HZ);
782 : : }
783 : :
784 : 0 : static ssize_t mci_ctl_name_show(struct device *dev,
785 : : struct device_attribute *mattr,
786 : : char *data)
787 : : {
788 : 0 : struct mem_ctl_info *mci = to_mci(dev);
789 : :
790 : 0 : return sprintf(data, "%s\n", mci->ctl_name);
791 : : }
792 : :
793 : 0 : static ssize_t mci_size_mb_show(struct device *dev,
794 : : struct device_attribute *mattr,
795 : : char *data)
796 : : {
797 : 0 : struct mem_ctl_info *mci = to_mci(dev);
798 : 0 : int total_pages = 0, csrow_idx, j;
799 : :
800 [ # # ]: 0 : for (csrow_idx = 0; csrow_idx < mci->nr_csrows; csrow_idx++) {
801 : 0 : struct csrow_info *csrow = mci->csrows[csrow_idx];
802 : :
803 [ # # ]: 0 : for (j = 0; j < csrow->nr_channels; j++) {
804 : 0 : struct dimm_info *dimm = csrow->channels[j]->dimm;
805 : :
806 : 0 : total_pages += dimm->nr_pages;
807 : : }
808 : : }
809 : :
810 : 0 : return sprintf(data, "%u\n", PAGES_TO_MiB(total_pages));
811 : : }
812 : :
813 : 0 : static ssize_t mci_max_location_show(struct device *dev,
814 : : struct device_attribute *mattr,
815 : : char *data)
816 : : {
817 : 0 : struct mem_ctl_info *mci = to_mci(dev);
818 : 0 : int i;
819 : 0 : char *p = data;
820 : :
821 [ # # ]: 0 : for (i = 0; i < mci->n_layers; i++) {
822 : 0 : p += sprintf(p, "%s %d ",
823 : 0 : edac_layer_name[mci->layers[i].type],
824 : 0 : mci->layers[i].size - 1);
825 : : }
826 : :
827 : 0 : return p - data;
828 : : }
829 : :
830 : : /* default Control file */
831 : : static DEVICE_ATTR(reset_counters, S_IWUSR, NULL, mci_reset_counters_store);
832 : :
833 : : /* default Attribute files */
834 : : static DEVICE_ATTR(mc_name, S_IRUGO, mci_ctl_name_show, NULL);
835 : : static DEVICE_ATTR(size_mb, S_IRUGO, mci_size_mb_show, NULL);
836 : : static DEVICE_ATTR(seconds_since_reset, S_IRUGO, mci_seconds_show, NULL);
837 : : static DEVICE_ATTR(ue_noinfo_count, S_IRUGO, mci_ue_noinfo_show, NULL);
838 : : static DEVICE_ATTR(ce_noinfo_count, S_IRUGO, mci_ce_noinfo_show, NULL);
839 : : static DEVICE_ATTR(ue_count, S_IRUGO, mci_ue_count_show, NULL);
840 : : static DEVICE_ATTR(ce_count, S_IRUGO, mci_ce_count_show, NULL);
841 : : static DEVICE_ATTR(max_location, S_IRUGO, mci_max_location_show, NULL);
842 : :
843 : : /* memory scrubber attribute file */
844 : : static DEVICE_ATTR(sdram_scrub_rate, 0, mci_sdram_scrub_rate_show,
845 : : mci_sdram_scrub_rate_store); /* umode set later in is_visible */
846 : :
847 : : static struct attribute *mci_attrs[] = {
848 : : &dev_attr_reset_counters.attr,
849 : : &dev_attr_mc_name.attr,
850 : : &dev_attr_size_mb.attr,
851 : : &dev_attr_seconds_since_reset.attr,
852 : : &dev_attr_ue_noinfo_count.attr,
853 : : &dev_attr_ce_noinfo_count.attr,
854 : : &dev_attr_ue_count.attr,
855 : : &dev_attr_ce_count.attr,
856 : : &dev_attr_max_location.attr,
857 : : &dev_attr_sdram_scrub_rate.attr,
858 : : NULL
859 : : };
860 : :
861 : 0 : static umode_t mci_attr_is_visible(struct kobject *kobj,
862 : : struct attribute *attr, int idx)
863 : : {
864 [ # # ]: 0 : struct device *dev = kobj_to_dev(kobj);
865 : 0 : struct mem_ctl_info *mci = to_mci(dev);
866 : 0 : umode_t mode = 0;
867 : :
868 [ # # ]: 0 : if (attr != &dev_attr_sdram_scrub_rate.attr)
869 : 0 : return attr->mode;
870 [ # # ]: 0 : if (mci->get_sdram_scrub_rate)
871 : 0 : mode |= S_IRUGO;
872 [ # # ]: 0 : if (mci->set_sdram_scrub_rate)
873 : 0 : mode |= S_IWUSR;
874 : : return mode;
875 : : }
876 : :
877 : : static const struct attribute_group mci_attr_grp = {
878 : : .attrs = mci_attrs,
879 : : .is_visible = mci_attr_is_visible,
880 : : };
881 : :
882 : : static const struct attribute_group *mci_attr_groups[] = {
883 : : &mci_attr_grp,
884 : : NULL
885 : : };
886 : :
887 : 0 : static void mci_attr_release(struct device *dev)
888 : : {
889 : : /* release device with _edac_mc_free() */
890 : 0 : }
891 : :
892 : : static const struct device_type mci_attr_type = {
893 : : .groups = mci_attr_groups,
894 : : .release = mci_attr_release,
895 : : };
896 : :
897 : : /*
898 : : * Create a new Memory Controller kobject instance,
899 : : * mc<id> under the 'mc' directory
900 : : *
901 : : * Return:
902 : : * 0 Success
903 : : * !0 Failure
904 : : */
905 : 0 : int edac_create_sysfs_mci_device(struct mem_ctl_info *mci,
906 : : const struct attribute_group **groups)
907 : : {
908 : 0 : struct dimm_info *dimm;
909 : 0 : int err;
910 : :
911 : : /* get the /sys/devices/system/edac subsys reference */
912 : 0 : mci->dev.type = &mci_attr_type;
913 : 0 : device_initialize(&mci->dev);
914 : :
915 : 0 : mci->dev.parent = mci_pdev;
916 : 0 : mci->dev.groups = groups;
917 : 0 : dev_set_name(&mci->dev, "mc%d", mci->mc_idx);
918 : 0 : dev_set_drvdata(&mci->dev, mci);
919 : 0 : pm_runtime_forbid(&mci->dev);
920 : :
921 : 0 : err = device_add(&mci->dev);
922 [ # # ]: 0 : if (err < 0) {
923 : 0 : edac_dbg(1, "failure: create device %s\n", dev_name(&mci->dev));
924 : 0 : put_device(&mci->dev);
925 : 0 : return err;
926 : : }
927 : :
928 : 0 : edac_dbg(0, "device %s created\n", dev_name(&mci->dev));
929 : :
930 : : /*
931 : : * Create the dimm/rank devices
932 : : */
933 [ # # # # ]: 0 : mci_for_each_dimm(mci, dimm) {
934 : : /* Only expose populated DIMMs */
935 [ # # ]: 0 : if (!dimm->nr_pages)
936 : 0 : continue;
937 : :
938 : 0 : err = edac_create_dimm_object(mci, dimm);
939 [ # # ]: 0 : if (err)
940 : 0 : goto fail_unregister_dimm;
941 : : }
942 : :
943 : : #ifdef CONFIG_EDAC_LEGACY_SYSFS
944 : 0 : err = edac_create_csrow_objects(mci);
945 [ # # ]: 0 : if (err < 0)
946 : 0 : goto fail_unregister_dimm;
947 : : #endif
948 : :
949 : : edac_create_debugfs_nodes(mci);
950 : : return 0;
951 : :
952 : 0 : fail_unregister_dimm:
953 [ # # # # ]: 0 : mci_for_each_dimm(mci, dimm) {
954 [ # # ]: 0 : if (device_is_registered(&dimm->dev))
955 : 0 : device_unregister(&dimm->dev);
956 : : }
957 : 0 : device_unregister(&mci->dev);
958 : :
959 : 0 : return err;
960 : : }
961 : :
962 : : /*
963 : : * remove a Memory Controller instance
964 : : */
965 : 0 : void edac_remove_sysfs_mci_device(struct mem_ctl_info *mci)
966 : : {
967 : 0 : struct dimm_info *dimm;
968 : :
969 : 0 : edac_dbg(0, "\n");
970 : :
971 : : #ifdef CONFIG_EDAC_DEBUG
972 : : edac_debugfs_remove_recursive(mci->debugfs);
973 : : #endif
974 : : #ifdef CONFIG_EDAC_LEGACY_SYSFS
975 : 0 : edac_delete_csrow_objects(mci);
976 : : #endif
977 : :
978 [ # # # # ]: 0 : mci_for_each_dimm(mci, dimm) {
979 [ # # ]: 0 : if (dimm->nr_pages == 0)
980 : 0 : continue;
981 : 0 : edac_dbg(1, "unregistering device %s\n", dev_name(&dimm->dev));
982 : 0 : device_unregister(&dimm->dev);
983 : : }
984 : 0 : }
985 : :
986 : 0 : void edac_unregister_sysfs(struct mem_ctl_info *mci)
987 : : {
988 : 0 : edac_dbg(1, "unregistering device %s\n", dev_name(&mci->dev));
989 : 0 : device_unregister(&mci->dev);
990 : 0 : }
991 : :
992 : 0 : static void mc_attr_release(struct device *dev)
993 : : {
994 : : /*
995 : : * There's no container structure here, as this is just the mci
996 : : * parent device, used to create the /sys/devices/mc sysfs node.
997 : : * So, there are no attributes on it.
998 : : */
999 : 0 : edac_dbg(1, "device %s released\n", dev_name(dev));
1000 : 0 : kfree(dev);
1001 : 0 : }
1002 : :
1003 : : static const struct device_type mc_attr_type = {
1004 : : .release = mc_attr_release,
1005 : : };
1006 : : /*
1007 : : * Init/exit code for the module. Basically, creates/removes /sys/class/rc
1008 : : */
1009 : 21 : int __init edac_mc_sysfs_init(void)
1010 : : {
1011 : 21 : int err;
1012 : :
1013 : 21 : mci_pdev = kzalloc(sizeof(*mci_pdev), GFP_KERNEL);
1014 [ + - ]: 21 : if (!mci_pdev)
1015 : : return -ENOMEM;
1016 : :
1017 : 21 : mci_pdev->bus = edac_get_sysfs_subsys();
1018 : 21 : mci_pdev->type = &mc_attr_type;
1019 : 21 : device_initialize(mci_pdev);
1020 : 21 : dev_set_name(mci_pdev, "mc");
1021 : :
1022 : 21 : err = device_add(mci_pdev);
1023 [ - + ]: 21 : if (err < 0) {
1024 : 0 : edac_dbg(1, "failure: create device %s\n", dev_name(mci_pdev));
1025 : 0 : put_device(mci_pdev);
1026 : 0 : return err;
1027 : : }
1028 : :
1029 : : edac_dbg(0, "device %s created\n", dev_name(mci_pdev));
1030 : :
1031 : : return 0;
1032 : : }
1033 : :
1034 : 0 : void edac_mc_sysfs_exit(void)
1035 : : {
1036 : 0 : device_unregister(mci_pdev);
1037 : 0 : }
|