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