Blame view
drivers/edac/edac_mc_sysfs.c
28.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 |
* |
e7100478f edac: only create... |
10 |
* (c) 2012-2013 - Mauro Carvalho Chehab <mchehab@redhat.com> |
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 |
|
20bcb7a81 drivers/edac: mod... |
21 |
#include "edac_core.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 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 |
static int edac_set_poll_msec(const char *val, struct kernel_param *kp) { long l; int ret; if (!val) return -EINVAL; ret = strict_strtol(val, 0, &l); if (ret == -EINVAL || ((int)l != l)) return -EINVAL; *((int *)kp->arg) = l; /* notify edac_mc engine to reset the poll period */ edac_mc_reset_delay_period(l); return 0; } |
7c9281d76 drivers/edac: spl... |
66 |
/* Parameter declarations for above */ |
4de78c687 drivers/edac: mod... |
67 68 69 70 |
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... |
71 |
"Log uncorrectable error to console: 0=off 1=on"); |
4de78c687 drivers/edac: mod... |
72 73 |
module_param(edac_mc_log_ce, int, 0644); MODULE_PARM_DESC(edac_mc_log_ce, |
079708b91 drivers/edac: cor... |
74 |
"Log correctable error to console: 0=off 1=on"); |
096846e2b edac: core fix wo... |
75 76 |
module_param_call(edac_mc_poll_msec, edac_set_poll_msec, param_get_int, &edac_mc_poll_msec, 0644); |
4de78c687 drivers/edac: mod... |
77 |
MODULE_PARM_DESC(edac_mc_poll_msec, "Polling period in milliseconds"); |
7c9281d76 drivers/edac: spl... |
78 |
|
de3910eb7 edac: change the ... |
79 |
static struct device *mci_pdev; |
7a623c039 edac: rewrite the... |
80 |
|
7c9281d76 drivers/edac: spl... |
81 82 83 |
/* * various constants for Memory Controllers */ |
8b7719e08 EDAC, mc_sysfs.c:... |
84 |
static const char * const mem_types[] = { |
7c9281d76 drivers/edac: spl... |
85 86 87 88 89 90 91 92 93 94 |
[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 ... |
95 96 97 |
[MEM_RMBS] = "RMBS", [MEM_DDR2] = "Unbuffered-DDR2", [MEM_FB_DDR2] = "FullyBuffered-DDR2", |
1d5f726cb drivers-edac: add... |
98 |
[MEM_RDDR2] = "Registered-DDR2", |
b1cfebc92 edac: add DDR3 me... |
99 100 101 |
[MEM_XDR] = "XDR", [MEM_DDR3] = "Unbuffered-DDR3", [MEM_RDDR3] = "Registered-DDR3" |
7c9281d76 drivers/edac: spl... |
102 |
}; |
8b7719e08 EDAC, mc_sysfs.c:... |
103 |
static const char * const dev_types[] = { |
7c9281d76 drivers/edac: spl... |
104 105 106 107 108 109 110 111 112 |
[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:... |
113 |
static const char * const edac_caps[] = { |
7c9281d76 drivers/edac: spl... |
114 115 116 117 118 119 120 121 122 123 124 |
[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... |
125 |
#ifdef CONFIG_EDAC_LEGACY_SYSFS |
7a623c039 edac: rewrite the... |
126 127 128 129 130 131 132 133 134 |
/* * 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... |
135 |
*/ |
7a623c039 edac: rewrite the... |
136 |
#define DEVICE_ATTR_LEGACY(_name, _mode, _show, _store) \ |
fbe2d3616 EDAC: Make sysfs ... |
137 |
static struct device_attribute dev_attr_legacy_##_name = __ATTR(_name, _mode, _show, _store) |
7a623c039 edac: rewrite the... |
138 139 140 141 142 143 144 145 146 147 148 |
struct dev_ch_attribute { struct device_attribute attr; int channel; }; #define DEVICE_CHANNEL(_name, _mode, _show, _store, _var) \ struct dev_ch_attribute dev_attr_legacy_##_name = \ { __ATTR(_name, _mode, _show, _store), (_var) } #define to_channel(k) (container_of(k, struct dev_ch_attribute, attr)->channel) |
7c9281d76 drivers/edac: spl... |
149 150 |
/* Set of more default csrow<id> attribute show/store functions */ |
7a623c039 edac: rewrite the... |
151 152 |
static ssize_t csrow_ue_count_show(struct device *dev, struct device_attribute *mattr, char *data) |
7c9281d76 drivers/edac: spl... |
153 |
{ |
7a623c039 edac: rewrite the... |
154 |
struct csrow_info *csrow = to_csrow(dev); |
079708b91 drivers/edac: cor... |
155 156 |
return sprintf(data, "%u ", csrow->ue_count); |
7c9281d76 drivers/edac: spl... |
157 |
} |
7a623c039 edac: rewrite the... |
158 159 |
static ssize_t csrow_ce_count_show(struct device *dev, struct device_attribute *mattr, char *data) |
7c9281d76 drivers/edac: spl... |
160 |
{ |
7a623c039 edac: rewrite the... |
161 |
struct csrow_info *csrow = to_csrow(dev); |
079708b91 drivers/edac: cor... |
162 163 |
return sprintf(data, "%u ", csrow->ce_count); |
7c9281d76 drivers/edac: spl... |
164 |
} |
7a623c039 edac: rewrite the... |
165 166 |
static ssize_t csrow_size_show(struct device *dev, struct device_attribute *mattr, char *data) |
7c9281d76 drivers/edac: spl... |
167 |
{ |
7a623c039 edac: rewrite the... |
168 |
struct csrow_info *csrow = to_csrow(dev); |
a895bf8b1 edac: move nr_pag... |
169 170 171 172 |
int i; u32 nr_pages = 0; for (i = 0; i < csrow->nr_channels; i++) |
de3910eb7 edac: change the ... |
173 |
nr_pages += csrow->channels[i]->dimm->nr_pages; |
a895bf8b1 edac: move nr_pag... |
174 175 |
return sprintf(data, "%u ", PAGES_TO_MiB(nr_pages)); |
7c9281d76 drivers/edac: spl... |
176 |
} |
7a623c039 edac: rewrite the... |
177 178 |
static ssize_t csrow_mem_type_show(struct device *dev, struct device_attribute *mattr, char *data) |
7c9281d76 drivers/edac: spl... |
179 |
{ |
7a623c039 edac: rewrite the... |
180 |
struct csrow_info *csrow = to_csrow(dev); |
de3910eb7 edac: change the ... |
181 182 |
return sprintf(data, "%s ", mem_types[csrow->channels[0]->dimm->mtype]); |
7c9281d76 drivers/edac: spl... |
183 |
} |
7a623c039 edac: rewrite the... |
184 185 |
static ssize_t csrow_dev_type_show(struct device *dev, struct device_attribute *mattr, char *data) |
7c9281d76 drivers/edac: spl... |
186 |
{ |
7a623c039 edac: rewrite the... |
187 |
struct csrow_info *csrow = to_csrow(dev); |
de3910eb7 edac: change the ... |
188 189 |
return sprintf(data, "%s ", dev_types[csrow->channels[0]->dimm->dtype]); |
7c9281d76 drivers/edac: spl... |
190 |
} |
7a623c039 edac: rewrite the... |
191 192 193 |
static ssize_t csrow_edac_mode_show(struct device *dev, struct device_attribute *mattr, char *data) |
7c9281d76 drivers/edac: spl... |
194 |
{ |
7a623c039 edac: rewrite the... |
195 |
struct csrow_info *csrow = to_csrow(dev); |
de3910eb7 edac: change the ... |
196 197 |
return sprintf(data, "%s ", edac_caps[csrow->channels[0]->dimm->edac_mode]); |
7c9281d76 drivers/edac: spl... |
198 199 200 |
} /* show/store functions for DIMM Label attributes */ |
7a623c039 edac: rewrite the... |
201 202 203 |
static ssize_t channel_dimm_label_show(struct device *dev, struct device_attribute *mattr, char *data) |
7c9281d76 drivers/edac: spl... |
204 |
{ |
7a623c039 edac: rewrite the... |
205 206 |
struct csrow_info *csrow = to_csrow(dev); unsigned chan = to_channel(mattr); |
de3910eb7 edac: change the ... |
207 |
struct rank_info *rank = csrow->channels[chan]; |
7a623c039 edac: rewrite the... |
208 |
|
124682c78 edac: core fix ad... |
209 |
/* if field has not been initialized, there is nothing to send */ |
7a623c039 edac: rewrite the... |
210 |
if (!rank->dimm->label[0]) |
124682c78 edac: core fix ad... |
211 212 213 214 |
return 0; return snprintf(data, EDAC_MC_LABEL_LEN, "%s ", |
7a623c039 edac: rewrite the... |
215 |
rank->dimm->label); |
7c9281d76 drivers/edac: spl... |
216 |
} |
7a623c039 edac: rewrite the... |
217 218 219 |
static ssize_t channel_dimm_label_store(struct device *dev, struct device_attribute *mattr, const char *data, size_t count) |
7c9281d76 drivers/edac: spl... |
220 |
{ |
7a623c039 edac: rewrite the... |
221 222 |
struct csrow_info *csrow = to_csrow(dev); unsigned chan = to_channel(mattr); |
de3910eb7 edac: change the ... |
223 |
struct rank_info *rank = csrow->channels[chan]; |
7a623c039 edac: rewrite the... |
224 |
|
7c9281d76 drivers/edac: spl... |
225 |
ssize_t max_size = 0; |
079708b91 drivers/edac: cor... |
226 |
max_size = min((ssize_t) count, (ssize_t) EDAC_MC_LABEL_LEN - 1); |
7a623c039 edac: rewrite the... |
227 228 |
strncpy(rank->dimm->label, data, max_size); rank->dimm->label[max_size] = '\0'; |
7c9281d76 drivers/edac: spl... |
229 230 231 232 233 |
return max_size; } /* show function for dynamic chX_ce_count attribute */ |
7a623c039 edac: rewrite the... |
234 235 |
static ssize_t channel_ce_count_show(struct device *dev, struct device_attribute *mattr, char *data) |
7c9281d76 drivers/edac: spl... |
236 |
{ |
7a623c039 edac: rewrite the... |
237 238 |
struct csrow_info *csrow = to_csrow(dev); unsigned chan = to_channel(mattr); |
de3910eb7 edac: change the ... |
239 |
struct rank_info *rank = csrow->channels[chan]; |
7a623c039 edac: rewrite the... |
240 241 242 |
return sprintf(data, "%u ", rank->ce_count); |
7c9281d76 drivers/edac: spl... |
243 |
} |
7a623c039 edac: rewrite the... |
244 245 246 247 248 249 250 |
/* 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... |
251 |
|
7a623c039 edac: rewrite the... |
252 253 254 255 256 257 258 259 260 261 |
/* 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... |
262 |
|
7a623c039 edac: rewrite the... |
263 264 265 |
static struct attribute_group csrow_attr_grp = { .attrs = csrow_attrs, }; |
7c9281d76 drivers/edac: spl... |
266 |
|
7a623c039 edac: rewrite the... |
267 268 269 270 |
static const struct attribute_group *csrow_attr_groups[] = { &csrow_attr_grp, NULL }; |
7c9281d76 drivers/edac: spl... |
271 |
|
de3910eb7 edac: change the ... |
272 |
static void csrow_attr_release(struct device *dev) |
7c9281d76 drivers/edac: spl... |
273 |
{ |
de3910eb7 edac: change the ... |
274 |
struct csrow_info *csrow = container_of(dev, struct csrow_info, dev); |
956b9ba15 edac: Convert deb... |
275 276 |
edac_dbg(1, "Releasing csrow device %s ", dev_name(dev)); |
de3910eb7 edac: change the ... |
277 |
kfree(csrow); |
7c9281d76 drivers/edac: spl... |
278 |
} |
7a623c039 edac: rewrite the... |
279 280 281 |
static struct device_type csrow_attr_type = { .groups = csrow_attr_groups, .release = csrow_attr_release, |
7c9281d76 drivers/edac: spl... |
282 |
}; |
7a623c039 edac: rewrite the... |
283 284 285 286 |
/* * possible dynamic channel DIMM Label attribute files * */ |
7c9281d76 drivers/edac: spl... |
287 |
|
7a623c039 edac: rewrite the... |
288 |
#define EDAC_NR_CHANNELS 6 |
7c9281d76 drivers/edac: spl... |
289 |
|
7a623c039 edac: rewrite the... |
290 |
DEVICE_CHANNEL(ch0_dimm_label, S_IRUGO | S_IWUSR, |
052dfb45c drivers/edac: cle... |
291 |
channel_dimm_label_show, channel_dimm_label_store, 0); |
7a623c039 edac: rewrite the... |
292 |
DEVICE_CHANNEL(ch1_dimm_label, S_IRUGO | S_IWUSR, |
052dfb45c drivers/edac: cle... |
293 |
channel_dimm_label_show, channel_dimm_label_store, 1); |
7a623c039 edac: rewrite the... |
294 |
DEVICE_CHANNEL(ch2_dimm_label, S_IRUGO | S_IWUSR, |
052dfb45c drivers/edac: cle... |
295 |
channel_dimm_label_show, channel_dimm_label_store, 2); |
7a623c039 edac: rewrite the... |
296 |
DEVICE_CHANNEL(ch3_dimm_label, S_IRUGO | S_IWUSR, |
052dfb45c drivers/edac: cle... |
297 |
channel_dimm_label_show, channel_dimm_label_store, 3); |
7a623c039 edac: rewrite the... |
298 |
DEVICE_CHANNEL(ch4_dimm_label, S_IRUGO | S_IWUSR, |
052dfb45c drivers/edac: cle... |
299 |
channel_dimm_label_show, channel_dimm_label_store, 4); |
7a623c039 edac: rewrite the... |
300 |
DEVICE_CHANNEL(ch5_dimm_label, S_IRUGO | S_IWUSR, |
052dfb45c drivers/edac: cle... |
301 |
channel_dimm_label_show, channel_dimm_label_store, 5); |
7c9281d76 drivers/edac: spl... |
302 303 |
/* Total possible dynamic DIMM Label attribute file table */ |
7a623c039 edac: rewrite the... |
304 305 306 307 308 309 310 |
static struct device_attribute *dynamic_csrow_dimm_attr[] = { &dev_attr_legacy_ch0_dimm_label.attr, &dev_attr_legacy_ch1_dimm_label.attr, &dev_attr_legacy_ch2_dimm_label.attr, &dev_attr_legacy_ch3_dimm_label.attr, &dev_attr_legacy_ch4_dimm_label.attr, &dev_attr_legacy_ch5_dimm_label.attr |
7c9281d76 drivers/edac: spl... |
311 312 313 |
}; /* possible dynamic channel ce_count attribute files */ |
c8c64d165 EDAC: Don't give ... |
314 |
DEVICE_CHANNEL(ch0_ce_count, S_IRUGO, |
7a623c039 edac: rewrite the... |
315 |
channel_ce_count_show, NULL, 0); |
c8c64d165 EDAC: Don't give ... |
316 |
DEVICE_CHANNEL(ch1_ce_count, S_IRUGO, |
7a623c039 edac: rewrite the... |
317 |
channel_ce_count_show, NULL, 1); |
c8c64d165 EDAC: Don't give ... |
318 |
DEVICE_CHANNEL(ch2_ce_count, S_IRUGO, |
7a623c039 edac: rewrite the... |
319 |
channel_ce_count_show, NULL, 2); |
c8c64d165 EDAC: Don't give ... |
320 |
DEVICE_CHANNEL(ch3_ce_count, S_IRUGO, |
7a623c039 edac: rewrite the... |
321 |
channel_ce_count_show, NULL, 3); |
c8c64d165 EDAC: Don't give ... |
322 |
DEVICE_CHANNEL(ch4_ce_count, S_IRUGO, |
7a623c039 edac: rewrite the... |
323 |
channel_ce_count_show, NULL, 4); |
c8c64d165 EDAC: Don't give ... |
324 |
DEVICE_CHANNEL(ch5_ce_count, S_IRUGO, |
7a623c039 edac: rewrite the... |
325 |
channel_ce_count_show, NULL, 5); |
7c9281d76 drivers/edac: spl... |
326 327 |
/* Total possible dynamic ce_count attribute file table */ |
7a623c039 edac: rewrite the... |
328 329 330 331 332 333 334 |
static struct device_attribute *dynamic_csrow_ce_count_attr[] = { &dev_attr_legacy_ch0_ce_count.attr, &dev_attr_legacy_ch1_ce_count.attr, &dev_attr_legacy_ch2_ce_count.attr, &dev_attr_legacy_ch3_ce_count.attr, &dev_attr_legacy_ch4_ce_count.attr, &dev_attr_legacy_ch5_ce_count.attr |
7c9281d76 drivers/edac: spl... |
335 |
}; |
e39f4ea9b edac: Only expose... |
336 337 338 339 340 |
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 ... |
341 |
nr_pages += csrow->channels[chan]->dimm->nr_pages; |
e39f4ea9b edac: Only expose... |
342 343 344 |
return nr_pages; } |
7a623c039 edac: rewrite the... |
345 346 347 |
/* 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... |
348 |
{ |
7a623c039 edac: rewrite the... |
349 |
int err, chan; |
7c9281d76 drivers/edac: spl... |
350 |
|
7a623c039 edac: rewrite the... |
351 352 |
if (csrow->nr_channels >= EDAC_NR_CHANNELS) return -ENODEV; |
7c9281d76 drivers/edac: spl... |
353 |
|
7a623c039 edac: rewrite the... |
354 |
csrow->dev.type = &csrow_attr_type; |
f46ef77da EDAC: Fix lockdep... |
355 |
csrow->dev.bus = mci->bus; |
7a623c039 edac: rewrite the... |
356 357 |
device_initialize(&csrow->dev); csrow->dev.parent = &mci->dev; |
921a68996 EDAC: Pass mci pa... |
358 |
csrow->mci = mci; |
7a623c039 edac: rewrite the... |
359 360 |
dev_set_name(&csrow->dev, "csrow%d", index); dev_set_drvdata(&csrow->dev, csrow); |
7c9281d76 drivers/edac: spl... |
361 |
|
956b9ba15 edac: Convert deb... |
362 363 364 |
edac_dbg(0, "creating (virtual) csrow node %s ", dev_name(&csrow->dev)); |
7c9281d76 drivers/edac: spl... |
365 |
|
7a623c039 edac: rewrite the... |
366 367 368 |
err = device_add(&csrow->dev); if (err < 0) return err; |
7c9281d76 drivers/edac: spl... |
369 |
|
7a623c039 edac: rewrite the... |
370 |
for (chan = 0; chan < csrow->nr_channels; chan++) { |
e39f4ea9b edac: Only expose... |
371 |
/* Only expose populated DIMMs */ |
de3910eb7 edac: change the ... |
372 |
if (!csrow->channels[chan]->dimm->nr_pages) |
e39f4ea9b edac: Only expose... |
373 |
continue; |
7a623c039 edac: rewrite the... |
374 375 376 377 378 379 380 381 382 383 384 385 |
err = device_create_file(&csrow->dev, dynamic_csrow_dimm_attr[chan]); if (err < 0) goto error; err = device_create_file(&csrow->dev, dynamic_csrow_ce_count_attr[chan]); if (err < 0) { device_remove_file(&csrow->dev, dynamic_csrow_dimm_attr[chan]); goto error; } } |
8096cfafb drivers/edac: fix... |
386 |
|
7a623c039 edac: rewrite the... |
387 |
return 0; |
8096cfafb drivers/edac: fix... |
388 |
|
7a623c039 edac: rewrite the... |
389 390 391 392 393 394 395 396 |
error: for (--chan; chan >= 0; chan--) { device_remove_file(&csrow->dev, dynamic_csrow_dimm_attr[chan]); device_remove_file(&csrow->dev, dynamic_csrow_ce_count_attr[chan]); } put_device(&csrow->dev); |
7c9281d76 drivers/edac: spl... |
397 |
|
7a623c039 edac: rewrite the... |
398 399 |
return err; } |
7c9281d76 drivers/edac: spl... |
400 401 |
/* Create a CSROW object under specifed edac_mc_device */ |
7a623c039 edac: rewrite the... |
402 |
static int edac_create_csrow_objects(struct mem_ctl_info *mci) |
7c9281d76 drivers/edac: spl... |
403 |
{ |
7a623c039 edac: rewrite the... |
404 405 |
int err, i, chan; struct csrow_info *csrow; |
7c9281d76 drivers/edac: spl... |
406 |
|
7a623c039 edac: rewrite the... |
407 |
for (i = 0; i < mci->nr_csrows; i++) { |
de3910eb7 edac: change the ... |
408 |
csrow = mci->csrows[i]; |
e39f4ea9b edac: Only expose... |
409 410 |
if (!nr_pages_per_csrow(csrow)) continue; |
de3910eb7 edac: change the ... |
411 |
err = edac_create_csrow_object(mci, mci->csrows[i], i); |
3d958823e edac: better repo... |
412 413 414 415 416 |
if (err < 0) { edac_dbg(1, "failure: create csrow objects for csrow %d ", i); |
7a623c039 edac: rewrite the... |
417 |
goto error; |
3d958823e edac: better repo... |
418 |
} |
7a623c039 edac: rewrite the... |
419 420 |
} return 0; |
8096cfafb drivers/edac: fix... |
421 |
|
7a623c039 edac: rewrite the... |
422 423 |
error: for (--i; i >= 0; i--) { |
de3910eb7 edac: change the ... |
424 |
csrow = mci->csrows[i]; |
e39f4ea9b edac: Only expose... |
425 426 |
if (!nr_pages_per_csrow(csrow)) continue; |
7a623c039 edac: rewrite the... |
427 |
for (chan = csrow->nr_channels - 1; chan >= 0; chan--) { |
de3910eb7 edac: change the ... |
428 |
if (!csrow->channels[chan]->dimm->nr_pages) |
e39f4ea9b edac: Only expose... |
429 |
continue; |
7a623c039 edac: rewrite the... |
430 431 432 433 434 |
device_remove_file(&csrow->dev, dynamic_csrow_dimm_attr[chan]); device_remove_file(&csrow->dev, dynamic_csrow_ce_count_attr[chan]); } |
de3910eb7 edac: change the ... |
435 |
put_device(&mci->csrows[i]->dev); |
8096cfafb drivers/edac: fix... |
436 |
} |
7c9281d76 drivers/edac: spl... |
437 |
|
7a623c039 edac: rewrite the... |
438 439 |
return err; } |
8096cfafb drivers/edac: fix... |
440 |
|
7a623c039 edac: rewrite the... |
441 442 443 444 |
static void edac_delete_csrow_objects(struct mem_ctl_info *mci) { int i, chan; struct csrow_info *csrow; |
8096cfafb drivers/edac: fix... |
445 |
|
7a623c039 edac: rewrite the... |
446 |
for (i = mci->nr_csrows - 1; i >= 0; i--) { |
de3910eb7 edac: change the ... |
447 |
csrow = mci->csrows[i]; |
e39f4ea9b edac: Only expose... |
448 449 |
if (!nr_pages_per_csrow(csrow)) continue; |
7a623c039 edac: rewrite the... |
450 |
for (chan = csrow->nr_channels - 1; chan >= 0; chan--) { |
de3910eb7 edac: change the ... |
451 |
if (!csrow->channels[chan]->dimm->nr_pages) |
e39f4ea9b edac: Only expose... |
452 |
continue; |
956b9ba15 edac: Convert deb... |
453 454 455 |
edac_dbg(1, "Removing csrow %d channel %d sysfs nodes ", i, chan); |
7a623c039 edac: rewrite the... |
456 457 458 459 |
device_remove_file(&csrow->dev, dynamic_csrow_dimm_attr[chan]); device_remove_file(&csrow->dev, dynamic_csrow_ce_count_attr[chan]); |
7c9281d76 drivers/edac: spl... |
460 |
} |
44d22e240 EDAC: Cleanup dev... |
461 |
device_unregister(&mci->csrows[i]->dev); |
7c9281d76 drivers/edac: spl... |
462 |
} |
7c9281d76 drivers/edac: spl... |
463 |
} |
199747106 edac: add a new p... |
464 465 466 467 468 469 470 471 472 473 474 475 476 |
#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... |
477 |
|
6e84d359b edac_mc: Cleanup ... |
478 |
return edac_dimm_info_location(dimm, data, PAGE_SIZE); |
199747106 edac: add a new p... |
479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 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 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 |
} 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; return snprintf(data, EDAC_MC_LABEL_LEN, "%s ", dimm->label); } 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); ssize_t max_size = 0; max_size = min((ssize_t) count, (ssize_t) EDAC_MC_LABEL_LEN - 1); strncpy(dimm->label, data, max_size); dimm->label[max_size] = '\0'; return max_size; } 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]); } /* 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); /* 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, 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 ... |
575 |
static void dimm_attr_release(struct device *dev) |
199747106 edac: add a new p... |
576 |
{ |
de3910eb7 edac: change the ... |
577 |
struct dimm_info *dimm = container_of(dev, struct dimm_info, dev); |
956b9ba15 edac: Convert deb... |
578 579 |
edac_dbg(1, "Releasing dimm device %s ", dev_name(dev)); |
de3910eb7 edac: change the ... |
580 |
kfree(dimm); |
199747106 edac: add a new p... |
581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 |
} 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; |
f46ef77da EDAC: Fix lockdep... |
597 |
dimm->dev.bus = mci->bus; |
199747106 edac: add a new p... |
598 599 600 |
device_initialize(&dimm->dev); dimm->dev.parent = &mci->dev; |
9713faecf EDAC: Merge mci.m... |
601 |
if (mci->csbased) |
199747106 edac: add a new p... |
602 603 604 605 606 607 608 |
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... |
609 610 |
edac_dbg(0, "creating rank/dimm device %s ", dev_name(&dimm->dev)); |
199747106 edac: add a new p... |
611 612 613 |
return err; } |
7c9281d76 drivers/edac: spl... |
614 |
|
7a623c039 edac: rewrite the... |
615 616 617 618 619 |
/* * Memory controller device */ #define to_mci(k) container_of(k, struct mem_ctl_info, dev) |
7c9281d76 drivers/edac: spl... |
620 |
|
7a623c039 edac: rewrite the... |
621 622 |
static ssize_t mci_reset_counters_store(struct device *dev, struct device_attribute *mattr, |
079708b91 drivers/edac: cor... |
623 |
const char *data, size_t count) |
7c9281d76 drivers/edac: spl... |
624 |
{ |
7a623c039 edac: rewrite the... |
625 626 |
struct mem_ctl_info *mci = to_mci(dev); int cnt, row, chan, i; |
5926ff502 edac: Initialize ... |
627 628 |
mci->ue_mc = 0; mci->ce_mc = 0; |
7a623c039 edac: rewrite the... |
629 630 |
mci->ue_noinfo_count = 0; mci->ce_noinfo_count = 0; |
7c9281d76 drivers/edac: spl... |
631 632 |
for (row = 0; row < mci->nr_csrows; row++) { |
de3910eb7 edac: change the ... |
633 |
struct csrow_info *ri = mci->csrows[row]; |
7c9281d76 drivers/edac: spl... |
634 635 636 637 638 |
ri->ue_count = 0; ri->ce_count = 0; for (chan = 0; chan < ri->nr_channels; chan++) |
de3910eb7 edac: change the ... |
639 |
ri->channels[chan]->ce_count = 0; |
7c9281d76 drivers/edac: spl... |
640 |
} |
7a623c039 edac: rewrite the... |
641 642 643 644 645 646 |
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... |
647 648 649 |
mci->start_time = jiffies; return count; } |
390944439 EDAC: Fixup scrub... |
650 651 652 653 654 655 656 657 658 |
/* 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... |
659 660 |
static ssize_t mci_sdram_scrub_rate_store(struct device *dev, struct device_attribute *mattr, |
eba042a81 edac, mc: Improve... |
661 |
const char *data, size_t count) |
7c9281d76 drivers/edac: spl... |
662 |
{ |
7a623c039 edac: rewrite the... |
663 |
struct mem_ctl_info *mci = to_mci(dev); |
eba042a81 edac, mc: Improve... |
664 |
unsigned long bandwidth = 0; |
390944439 EDAC: Fixup scrub... |
665 |
int new_bw = 0; |
7c9281d76 drivers/edac: spl... |
666 |
|
eba042a81 edac, mc: Improve... |
667 668 |
if (strict_strtoul(data, 10, &bandwidth) < 0) return -EINVAL; |
7c9281d76 drivers/edac: spl... |
669 |
|
390944439 EDAC: Fixup scrub... |
670 |
new_bw = mci->set_sdram_scrub_rate(mci, bandwidth); |
4949603a6 EDAC: Remove debu... |
671 672 673 674 675 |
if (new_bw < 0) { edac_printk(KERN_WARNING, EDAC_MC, "Error setting scrub rate to: %lu ", bandwidth); return -EINVAL; |
7c9281d76 drivers/edac: spl... |
676 |
} |
390944439 EDAC: Fixup scrub... |
677 |
|
4949603a6 EDAC: Remove debu... |
678 |
return count; |
7c9281d76 drivers/edac: spl... |
679 |
} |
390944439 EDAC: Fixup scrub... |
680 681 682 |
/* * ->get_sdram_scrub_rate() return value semantics same as above. */ |
7a623c039 edac: rewrite the... |
683 684 685 |
static ssize_t mci_sdram_scrub_rate_show(struct device *dev, struct device_attribute *mattr, char *data) |
7c9281d76 drivers/edac: spl... |
686 |
{ |
7a623c039 edac: rewrite the... |
687 |
struct mem_ctl_info *mci = to_mci(dev); |
390944439 EDAC: Fixup scrub... |
688 |
int bandwidth = 0; |
eba042a81 edac, mc: Improve... |
689 |
|
390944439 EDAC: Fixup scrub... |
690 691 |
bandwidth = mci->get_sdram_scrub_rate(mci); if (bandwidth < 0) { |
eba042a81 edac, mc: Improve... |
692 693 |
edac_printk(KERN_DEBUG, EDAC_MC, "Error reading scrub rate "); |
390944439 EDAC: Fixup scrub... |
694 |
return bandwidth; |
7c9281d76 drivers/edac: spl... |
695 |
} |
390944439 EDAC: Fixup scrub... |
696 |
|
390944439 EDAC: Fixup scrub... |
697 698 |
return sprintf(data, "%d ", bandwidth); |
7c9281d76 drivers/edac: spl... |
699 700 701 |
} /* default attribute files for the MCI object */ |
7a623c039 edac: rewrite the... |
702 703 704 |
static ssize_t mci_ue_count_show(struct device *dev, struct device_attribute *mattr, char *data) |
7c9281d76 drivers/edac: spl... |
705 |
{ |
7a623c039 edac: rewrite the... |
706 |
struct mem_ctl_info *mci = to_mci(dev); |
5926ff502 edac: Initialize ... |
707 708 |
return sprintf(data, "%d ", mci->ue_mc); |
7c9281d76 drivers/edac: spl... |
709 |
} |
7a623c039 edac: rewrite the... |
710 711 712 |
static ssize_t mci_ce_count_show(struct device *dev, struct device_attribute *mattr, char *data) |
7c9281d76 drivers/edac: spl... |
713 |
{ |
7a623c039 edac: rewrite the... |
714 |
struct mem_ctl_info *mci = to_mci(dev); |
5926ff502 edac: Initialize ... |
715 716 |
return sprintf(data, "%d ", mci->ce_mc); |
7c9281d76 drivers/edac: spl... |
717 |
} |
7a623c039 edac: rewrite the... |
718 719 720 |
static ssize_t mci_ce_noinfo_show(struct device *dev, struct device_attribute *mattr, char *data) |
7c9281d76 drivers/edac: spl... |
721 |
{ |
7a623c039 edac: rewrite the... |
722 |
struct mem_ctl_info *mci = to_mci(dev); |
079708b91 drivers/edac: cor... |
723 724 |
return sprintf(data, "%d ", mci->ce_noinfo_count); |
7c9281d76 drivers/edac: spl... |
725 |
} |
7a623c039 edac: rewrite the... |
726 727 728 |
static ssize_t mci_ue_noinfo_show(struct device *dev, struct device_attribute *mattr, char *data) |
7c9281d76 drivers/edac: spl... |
729 |
{ |
7a623c039 edac: rewrite the... |
730 |
struct mem_ctl_info *mci = to_mci(dev); |
079708b91 drivers/edac: cor... |
731 732 |
return sprintf(data, "%d ", mci->ue_noinfo_count); |
7c9281d76 drivers/edac: spl... |
733 |
} |
7a623c039 edac: rewrite the... |
734 735 736 |
static ssize_t mci_seconds_show(struct device *dev, struct device_attribute *mattr, char *data) |
7c9281d76 drivers/edac: spl... |
737 |
{ |
7a623c039 edac: rewrite the... |
738 |
struct mem_ctl_info *mci = to_mci(dev); |
079708b91 drivers/edac: cor... |
739 740 |
return sprintf(data, "%ld ", (jiffies - mci->start_time) / HZ); |
7c9281d76 drivers/edac: spl... |
741 |
} |
7a623c039 edac: rewrite the... |
742 743 744 |
static ssize_t mci_ctl_name_show(struct device *dev, struct device_attribute *mattr, char *data) |
7c9281d76 drivers/edac: spl... |
745 |
{ |
7a623c039 edac: rewrite the... |
746 |
struct mem_ctl_info *mci = to_mci(dev); |
079708b91 drivers/edac: cor... |
747 748 |
return sprintf(data, "%s ", mci->ctl_name); |
7c9281d76 drivers/edac: spl... |
749 |
} |
7a623c039 edac: rewrite the... |
750 751 752 |
static ssize_t mci_size_mb_show(struct device *dev, struct device_attribute *mattr, char *data) |
7c9281d76 drivers/edac: spl... |
753 |
{ |
7a623c039 edac: rewrite the... |
754 |
struct mem_ctl_info *mci = to_mci(dev); |
a895bf8b1 edac: move nr_pag... |
755 |
int total_pages = 0, csrow_idx, j; |
7c9281d76 drivers/edac: spl... |
756 |
|
a895bf8b1 edac: move nr_pag... |
757 |
for (csrow_idx = 0; csrow_idx < mci->nr_csrows; csrow_idx++) { |
de3910eb7 edac: change the ... |
758 |
struct csrow_info *csrow = mci->csrows[csrow_idx]; |
7c9281d76 drivers/edac: spl... |
759 |
|
1eef12825 amd64_edac: Corre... |
760 761 |
for (j = 0; j < csrow->nr_channels; j++) { struct dimm_info *dimm = csrow->channels[j]->dimm; |
3c0622760 EDAC: Fix mc size... |
762 |
|
1eef12825 amd64_edac: Corre... |
763 |
total_pages += dimm->nr_pages; |
a895bf8b1 edac: move nr_pag... |
764 |
} |
7c9281d76 drivers/edac: spl... |
765 |
} |
079708b91 drivers/edac: cor... |
766 767 |
return sprintf(data, "%u ", PAGES_TO_MiB(total_pages)); |
7c9281d76 drivers/edac: spl... |
768 |
} |
8ad6c78a6 edac: add a sysfs... |
769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 |
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; } |
452a6bf95 edac: Add debufs ... |
785 786 787 788 789 790 791 792 |
#ifdef CONFIG_EDAC_DEBUG static ssize_t edac_fake_inject_write(struct file *file, const char __user *data, size_t count, loff_t *ppos) { struct device *dev = file->private_data; struct mem_ctl_info *mci = to_mci(dev); static enum hw_event_mc_err_type type; |
38ced28b2 edac: allow speci... |
793 794 795 796 |
u16 errcount = mci->fake_inject_count; if (!errcount) errcount = 1; |
452a6bf95 edac: Add debufs ... |
797 798 799 800 801 |
type = mci->fake_inject_ue ? HW_EVENT_ERR_UNCORRECTED : HW_EVENT_ERR_CORRECTED; printk(KERN_DEBUG |
38ced28b2 edac: allow speci... |
802 803 804 |
"Generating %d %s fake error%s to %d.%d.%d to test core handling. NOTE: this won't test the driver-specific decoding logic. ", errcount, |
452a6bf95 edac: Add debufs ... |
805 |
(type == HW_EVENT_ERR_UNCORRECTED) ? "UE" : "CE", |
38ced28b2 edac: allow speci... |
806 |
errcount > 1 ? "s" : "", |
452a6bf95 edac: Add debufs ... |
807 808 809 810 |
mci->fake_inject_layer[0], mci->fake_inject_layer[1], mci->fake_inject_layer[2] ); |
38ced28b2 edac: allow speci... |
811 |
edac_mc_handle_error(type, mci, errcount, 0, 0, 0, |
452a6bf95 edac: Add debufs ... |
812 813 814 |
mci->fake_inject_layer[0], mci->fake_inject_layer[1], mci->fake_inject_layer[2], |
03f7eae80 edac: remove arch... |
815 |
"FAKE ERROR", "for EDAC testing only"); |
452a6bf95 edac: Add debufs ... |
816 817 818 |
return count; } |
452a6bf95 edac: Add debufs ... |
819 |
static const struct file_operations debug_fake_inject_fops = { |
db7312a29 EDAC: Convert to ... |
820 |
.open = simple_open, |
452a6bf95 edac: Add debufs ... |
821 822 823 824 |
.write = edac_fake_inject_write, .llseek = generic_file_llseek, }; #endif |
7c9281d76 drivers/edac: spl... |
825 |
/* default Control file */ |
7a623c039 edac: rewrite the... |
826 |
DEVICE_ATTR(reset_counters, S_IWUSR, NULL, mci_reset_counters_store); |
7c9281d76 drivers/edac: spl... |
827 828 |
/* default Attribute files */ |
7a623c039 edac: rewrite the... |
829 830 831 832 833 834 835 |
DEVICE_ATTR(mc_name, S_IRUGO, mci_ctl_name_show, NULL); DEVICE_ATTR(size_mb, S_IRUGO, mci_size_mb_show, NULL); DEVICE_ATTR(seconds_since_reset, S_IRUGO, mci_seconds_show, NULL); DEVICE_ATTR(ue_noinfo_count, S_IRUGO, mci_ue_noinfo_show, NULL); DEVICE_ATTR(ce_noinfo_count, S_IRUGO, mci_ce_noinfo_show, NULL); DEVICE_ATTR(ue_count, S_IRUGO, mci_ue_count_show, NULL); DEVICE_ATTR(ce_count, S_IRUGO, mci_ce_count_show, NULL); |
8ad6c78a6 edac: add a sysfs... |
836 |
DEVICE_ATTR(max_location, S_IRUGO, mci_max_location_show, NULL); |
7c9281d76 drivers/edac: spl... |
837 838 |
/* memory scrubber attribute file */ |
e7100478f edac: only create... |
839 |
DEVICE_ATTR(sdram_scrub_rate, 0, NULL, NULL); |
7c9281d76 drivers/edac: spl... |
840 |
|
7a623c039 edac: rewrite the... |
841 842 843 844 845 846 847 848 849 |
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... |
850 |
&dev_attr_max_location.attr, |
7c9281d76 drivers/edac: spl... |
851 852 |
NULL }; |
7a623c039 edac: rewrite the... |
853 854 |
static struct attribute_group mci_attr_grp = { .attrs = mci_attrs, |
cc301b3ae edac: store/show ... |
855 |
}; |
7a623c039 edac: rewrite the... |
856 857 858 |
static const struct attribute_group *mci_attr_groups[] = { &mci_attr_grp, NULL |
cc301b3ae edac: store/show ... |
859 |
}; |
de3910eb7 edac: change the ... |
860 |
static void mci_attr_release(struct device *dev) |
42a8e397a drivers/edac: add... |
861 |
{ |
de3910eb7 edac: change the ... |
862 |
struct mem_ctl_info *mci = container_of(dev, struct mem_ctl_info, dev); |
956b9ba15 edac: Convert deb... |
863 864 |
edac_dbg(1, "Releasing csrow device %s ", dev_name(dev)); |
de3910eb7 edac: change the ... |
865 |
kfree(mci); |
42a8e397a drivers/edac: add... |
866 |
} |
7a623c039 edac: rewrite the... |
867 868 869 870 |
static struct device_type mci_attr_type = { .groups = mci_attr_groups, .release = mci_attr_release, }; |
8096cfafb drivers/edac: fix... |
871 |
|
452a6bf95 edac: Add debufs ... |
872 |
#ifdef CONFIG_EDAC_DEBUG |
e7930ba49 edac: create top-... |
873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 |
static struct dentry *edac_debugfs; int __init edac_debugfs_init(void) { edac_debugfs = debugfs_create_dir("edac", NULL); if (IS_ERR(edac_debugfs)) { edac_debugfs = NULL; return -ENOMEM; } return 0; } void __exit edac_debugfs_exit(void) { debugfs_remove(edac_debugfs); } |
452a6bf95 edac: Add debufs ... |
889 890 891 892 893 |
int edac_create_debug_nodes(struct mem_ctl_info *mci) { struct dentry *d, *parent; char name[80]; int i; |
e7930ba49 edac: create top-... |
894 895 896 897 |
if (!edac_debugfs) return -ENODEV; d = debugfs_create_dir(mci->dev.kobj.name, edac_debugfs); |
452a6bf95 edac: Add debufs ... |
898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 |
if (!d) return -ENOMEM; parent = d; for (i = 0; i < mci->n_layers; i++) { sprintf(name, "fake_inject_%s", edac_layer_name[mci->layers[i].type]); d = debugfs_create_u8(name, S_IRUGO | S_IWUSR, parent, &mci->fake_inject_layer[i]); if (!d) goto nomem; } d = debugfs_create_bool("fake_inject_ue", S_IRUGO | S_IWUSR, parent, &mci->fake_inject_ue); if (!d) goto nomem; |
38ced28b2 edac: allow speci... |
915 916 917 918 |
d = debugfs_create_u16("fake_inject_count", S_IRUGO | S_IWUSR, parent, &mci->fake_inject_count); if (!d) goto nomem; |
452a6bf95 edac: Add debufs ... |
919 920 921 922 923 |
d = debugfs_create_file("fake_inject", S_IWUSR, parent, &mci->dev, &debug_fake_inject_fops); if (!d) goto nomem; |
e7930ba49 edac: create top-... |
924 |
mci->debugfs = parent; |
452a6bf95 edac: Add debufs ... |
925 926 927 928 929 930 |
return 0; nomem: debugfs_remove(mci->debugfs); return -ENOMEM; } #endif |
8096cfafb drivers/edac: fix... |
931 |
/* |
7c9281d76 drivers/edac: spl... |
932 933 934 935 936 937 938 939 940 |
* Create a new Memory Controller kobject instance, * mc<id> under the 'mc' directory * * Return: * 0 Success * !0 Failure */ int edac_create_sysfs_mci_device(struct mem_ctl_info *mci) { |
7a623c039 edac: rewrite the... |
941 |
int i, err; |
7c9281d76 drivers/edac: spl... |
942 |
|
de3910eb7 edac: change the ... |
943 944 945 946 |
/* * The memory controller needs its own bus, in order to avoid * namespace conflicts at /sys/bus/edac. */ |
f46ef77da EDAC: Fix lockdep... |
947 948 |
mci->bus->name = kasprintf(GFP_KERNEL, "mc%d", mci->mc_idx); if (!mci->bus->name) |
de3910eb7 edac: change the ... |
949 |
return -ENOMEM; |
f46ef77da EDAC: Fix lockdep... |
950 951 952 953 954 |
edac_dbg(0, "creating bus %s ", mci->bus->name); err = bus_register(mci->bus); |
de3910eb7 edac: change the ... |
955 956 |
if (err < 0) return err; |
7c9281d76 drivers/edac: spl... |
957 |
|
7a623c039 edac: rewrite the... |
958 |
/* get the /sys/devices/system/edac subsys reference */ |
7a623c039 edac: rewrite the... |
959 960 |
mci->dev.type = &mci_attr_type; device_initialize(&mci->dev); |
7c9281d76 drivers/edac: spl... |
961 |
|
de3910eb7 edac: change the ... |
962 |
mci->dev.parent = mci_pdev; |
f46ef77da EDAC: Fix lockdep... |
963 |
mci->dev.bus = mci->bus; |
7a623c039 edac: rewrite the... |
964 965 966 |
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... |
967 968 |
edac_dbg(0, "creating device %s ", dev_name(&mci->dev)); |
7a623c039 edac: rewrite the... |
969 970 |
err = device_add(&mci->dev); if (err < 0) { |
3d958823e edac: better repo... |
971 972 |
edac_dbg(1, "failure: create device %s ", dev_name(&mci->dev)); |
f46ef77da EDAC: Fix lockdep... |
973 974 |
bus_unregister(mci->bus); kfree(mci->bus->name); |
7a623c039 edac: rewrite the... |
975 |
return err; |
42a8e397a drivers/edac: add... |
976 |
} |
e7100478f edac: only create... |
977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 |
if (mci->set_sdram_scrub_rate || mci->get_sdram_scrub_rate) { if (mci->get_sdram_scrub_rate) { dev_attr_sdram_scrub_rate.attr.mode |= S_IRUGO; dev_attr_sdram_scrub_rate.show = &mci_sdram_scrub_rate_show; } if (mci->set_sdram_scrub_rate) { dev_attr_sdram_scrub_rate.attr.mode |= S_IWUSR; dev_attr_sdram_scrub_rate.store = &mci_sdram_scrub_rate_store; } err = device_create_file(&mci->dev, &dev_attr_sdram_scrub_rate); if (err) { edac_dbg(1, "failure: create sdram_scrub_rate "); goto fail2; } } |
7a623c039 edac: rewrite the... |
994 995 |
/* * Create the dimm/rank devices |
7c9281d76 drivers/edac: spl... |
996 |
*/ |
7a623c039 edac: rewrite the... |
997 |
for (i = 0; i < mci->tot_dimms; i++) { |
de3910eb7 edac: change the ... |
998 |
struct dimm_info *dimm = mci->dimms[i]; |
7a623c039 edac: rewrite the... |
999 1000 1001 1002 |
/* Only expose populated DIMMs */ if (dimm->nr_pages == 0) continue; #ifdef CONFIG_EDAC_DEBUG |
956b9ba15 edac: Convert deb... |
1003 |
edac_dbg(1, "creating dimm%d, located at ", i); |
7a623c039 edac: rewrite the... |
1004 1005 1006 1007 1008 1009 1010 1011 |
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... |
1012 |
} |
7a623c039 edac: rewrite the... |
1013 |
#endif |
199747106 edac: add a new p... |
1014 1015 |
err = edac_create_dimm_object(mci, dimm, i); if (err) { |
956b9ba15 edac: Convert deb... |
1016 1017 |
edac_dbg(1, "failure: create dimm %d obj ", i); |
199747106 edac: add a new p... |
1018 1019 |
goto fail; } |
7c9281d76 drivers/edac: spl... |
1020 |
} |
199747106 edac: add a new p... |
1021 |
#ifdef CONFIG_EDAC_LEGACY_SYSFS |
7a623c039 edac: rewrite the... |
1022 1023 1024 |
err = edac_create_csrow_objects(mci); if (err < 0) goto fail; |
199747106 edac: add a new p... |
1025 |
#endif |
7a623c039 edac: rewrite the... |
1026 |
|
452a6bf95 edac: Add debufs ... |
1027 1028 1029 |
#ifdef CONFIG_EDAC_DEBUG edac_create_debug_nodes(mci); #endif |
7c9281d76 drivers/edac: spl... |
1030 |
return 0; |
7a623c039 edac: rewrite the... |
1031 |
fail: |
079708b91 drivers/edac: cor... |
1032 |
for (i--; i >= 0; i--) { |
de3910eb7 edac: change the ... |
1033 |
struct dimm_info *dimm = mci->dimms[i]; |
7a623c039 edac: rewrite the... |
1034 1035 |
if (dimm->nr_pages == 0) continue; |
44d22e240 EDAC: Cleanup dev... |
1036 |
device_unregister(&dimm->dev); |
7c9281d76 drivers/edac: spl... |
1037 |
} |
e7100478f edac: only create... |
1038 |
fail2: |
44d22e240 EDAC: Cleanup dev... |
1039 |
device_unregister(&mci->dev); |
f46ef77da EDAC: Fix lockdep... |
1040 1041 |
bus_unregister(mci->bus); kfree(mci->bus->name); |
7c9281d76 drivers/edac: spl... |
1042 1043 1044 1045 1046 1047 1048 1049 |
return err; } /* * remove a Memory Controller instance */ void edac_remove_sysfs_mci_device(struct mem_ctl_info *mci) { |
7a623c039 edac: rewrite the... |
1050 |
int i; |
7c9281d76 drivers/edac: spl... |
1051 |
|
956b9ba15 edac: Convert deb... |
1052 1053 |
edac_dbg(0, " "); |
7c9281d76 drivers/edac: spl... |
1054 |
|
452a6bf95 edac: Add debufs ... |
1055 1056 1057 |
#ifdef CONFIG_EDAC_DEBUG debugfs_remove(mci->debugfs); #endif |
199747106 edac: add a new p... |
1058 |
#ifdef CONFIG_EDAC_LEGACY_SYSFS |
7a623c039 edac: rewrite the... |
1059 |
edac_delete_csrow_objects(mci); |
199747106 edac: add a new p... |
1060 |
#endif |
7c9281d76 drivers/edac: spl... |
1061 |
|
7a623c039 edac: rewrite the... |
1062 |
for (i = 0; i < mci->tot_dimms; i++) { |
de3910eb7 edac: change the ... |
1063 |
struct dimm_info *dimm = mci->dimms[i]; |
7a623c039 edac: rewrite the... |
1064 1065 |
if (dimm->nr_pages == 0) continue; |
956b9ba15 edac: Convert deb... |
1066 1067 |
edac_dbg(0, "removing device %s ", dev_name(&dimm->dev)); |
44d22e240 EDAC: Cleanup dev... |
1068 |
device_unregister(&dimm->dev); |
6fe1108f1 edac_core: Do a b... |
1069 |
} |
7c9281d76 drivers/edac: spl... |
1070 |
} |
8096cfafb drivers/edac: fix... |
1071 |
|
7a623c039 edac: rewrite the... |
1072 1073 |
void edac_unregister_sysfs(struct mem_ctl_info *mci) { |
956b9ba15 edac: Convert deb... |
1074 1075 |
edac_dbg(1, "Unregistering device %s ", dev_name(&mci->dev)); |
44d22e240 EDAC: Cleanup dev... |
1076 |
device_unregister(&mci->dev); |
f46ef77da EDAC: Fix lockdep... |
1077 1078 |
bus_unregister(mci->bus); kfree(mci->bus->name); |
7a623c039 edac: rewrite the... |
1079 |
} |
8096cfafb drivers/edac: fix... |
1080 |
|
de3910eb7 edac: change the ... |
1081 |
static void mc_attr_release(struct device *dev) |
7a623c039 edac: rewrite the... |
1082 |
{ |
de3910eb7 edac: change the ... |
1083 1084 1085 1086 1087 |
/* * 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... |
1088 1089 |
edac_dbg(1, "Releasing device %s ", dev_name(dev)); |
de3910eb7 edac: change the ... |
1090 |
kfree(dev); |
7a623c039 edac: rewrite the... |
1091 |
} |
8096cfafb drivers/edac: fix... |
1092 |
|
7a623c039 edac: rewrite the... |
1093 1094 1095 |
static struct device_type mc_attr_type = { .release = mc_attr_release, }; |
8096cfafb drivers/edac: fix... |
1096 |
/* |
7a623c039 edac: rewrite the... |
1097 |
* Init/exit code for the module. Basically, creates/removes /sys/class/rc |
8096cfafb drivers/edac: fix... |
1098 |
*/ |
7a623c039 edac: rewrite the... |
1099 |
int __init edac_mc_sysfs_init(void) |
8096cfafb drivers/edac: fix... |
1100 |
{ |
fe5ff8b84 edac: convert sys... |
1101 |
struct bus_type *edac_subsys; |
7a623c039 edac: rewrite the... |
1102 |
int err; |
8096cfafb drivers/edac: fix... |
1103 |
|
fe5ff8b84 edac: convert sys... |
1104 1105 1106 |
/* get the /sys/devices/system/edac subsys reference */ edac_subsys = edac_get_sysfs_subsys(); if (edac_subsys == NULL) { |
956b9ba15 edac: Convert deb... |
1107 1108 |
edac_dbg(1, "no edac_subsys "); |
2d56b109e EDAC: Handle erro... |
1109 1110 |
err = -EINVAL; goto out; |
8096cfafb drivers/edac: fix... |
1111 |
} |
de3910eb7 edac: change the ... |
1112 |
mci_pdev = kzalloc(sizeof(*mci_pdev), GFP_KERNEL); |
2d56b109e EDAC: Handle erro... |
1113 1114 1115 1116 |
if (!mci_pdev) { err = -ENOMEM; goto out_put_sysfs; } |
de3910eb7 edac: change the ... |
1117 1118 1119 1120 1121 |
mci_pdev->bus = edac_subsys; mci_pdev->type = &mc_attr_type; device_initialize(mci_pdev); dev_set_name(mci_pdev, "mc"); |
8096cfafb drivers/edac: fix... |
1122 |
|
de3910eb7 edac: change the ... |
1123 |
err = device_add(mci_pdev); |
7a623c039 edac: rewrite the... |
1124 |
if (err < 0) |
2d56b109e EDAC: Handle erro... |
1125 |
goto out_dev_free; |
8096cfafb drivers/edac: fix... |
1126 |
|
956b9ba15 edac: Convert deb... |
1127 1128 |
edac_dbg(0, "device %s created ", dev_name(mci_pdev)); |
de3910eb7 edac: change the ... |
1129 |
|
8096cfafb drivers/edac: fix... |
1130 |
return 0; |
2d56b109e EDAC: Handle erro... |
1131 1132 1133 1134 1135 1136 1137 |
out_dev_free: kfree(mci_pdev); out_put_sysfs: edac_put_sysfs_subsys(); out: return err; |
8096cfafb drivers/edac: fix... |
1138 |
} |
7a623c039 edac: rewrite the... |
1139 |
void __exit edac_mc_sysfs_exit(void) |
8096cfafb drivers/edac: fix... |
1140 |
{ |
44d22e240 EDAC: Cleanup dev... |
1141 |
device_unregister(mci_pdev); |
fe5ff8b84 edac: convert sys... |
1142 |
edac_put_sysfs_subsys(); |
8096cfafb drivers/edac: fix... |
1143 |
} |