Blame view

drivers/edac/edac_mc_sysfs.c 28.9 KB
7c9281d76   Douglas Thompson   drivers/edac: spl...
1
2
  /*
   * edac_mc kernel module
42a8e397a   Douglas Thompson   drivers/edac: add...
3
4
   * (C) 2005-2007 Linux Networx (http://lnxi.com)
   *
7c9281d76   Douglas Thompson   drivers/edac: spl...
5
6
7
   * This file may be distributed under the terms of the
   * GNU General Public License.
   *
42a8e397a   Douglas Thompson   drivers/edac: add...
8
   * Written Doug Thompson <norsk5@xmission.com> www.softwarebitmaker.com
7c9281d76   Douglas Thompson   drivers/edac: spl...
9
   *
e7100478f   Mauro Carvalho Chehab   edac: only create...
10
   * (c) 2012-2013 - Mauro Carvalho Chehab <mchehab@redhat.com>
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
11
12
   *	The entire API were re-written, and ported to use struct device
   *
7c9281d76   Douglas Thompson   drivers/edac: spl...
13
   */
7c9281d76   Douglas Thompson   drivers/edac: spl...
14
  #include <linux/ctype.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
15
  #include <linux/slab.h>
30e1f7a81   Borislav Petkov   EDAC: Export edac...
16
  #include <linux/edac.h>
8096cfafb   Doug Thompson   drivers/edac: fix...
17
  #include <linux/bug.h>
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
18
  #include <linux/pm_runtime.h>
452a6bf95   Mauro Carvalho Chehab   edac: Add debufs ...
19
  #include <linux/uaccess.h>
7c9281d76   Douglas Thompson   drivers/edac: spl...
20

20bcb7a81   Douglas Thompson   drivers/edac: mod...
21
  #include "edac_core.h"
7c9281d76   Douglas Thompson   drivers/edac: spl...
22
23
24
  #include "edac_module.h"
  
  /* MC EDAC Controls, setable by module parameter, and sysfs */
4de78c687   Dave Jiang   drivers/edac: mod...
25
26
  static int edac_mc_log_ue = 1;
  static int edac_mc_log_ce = 1;
f044091ca   Douglas Thompson   drivers/edac: rem...
27
  static int edac_mc_panic_on_ue;
4de78c687   Dave Jiang   drivers/edac: mod...
28
  static int edac_mc_poll_msec = 1000;
7c9281d76   Douglas Thompson   drivers/edac: spl...
29
30
  
  /* Getter functions for above */
4de78c687   Dave Jiang   drivers/edac: mod...
31
  int edac_mc_get_log_ue(void)
7c9281d76   Douglas Thompson   drivers/edac: spl...
32
  {
4de78c687   Dave Jiang   drivers/edac: mod...
33
  	return edac_mc_log_ue;
7c9281d76   Douglas Thompson   drivers/edac: spl...
34
  }
4de78c687   Dave Jiang   drivers/edac: mod...
35
  int edac_mc_get_log_ce(void)
7c9281d76   Douglas Thompson   drivers/edac: spl...
36
  {
4de78c687   Dave Jiang   drivers/edac: mod...
37
  	return edac_mc_log_ce;
7c9281d76   Douglas Thompson   drivers/edac: spl...
38
  }
4de78c687   Dave Jiang   drivers/edac: mod...
39
  int edac_mc_get_panic_on_ue(void)
7c9281d76   Douglas Thompson   drivers/edac: spl...
40
  {
4de78c687   Dave Jiang   drivers/edac: mod...
41
  	return edac_mc_panic_on_ue;
7c9281d76   Douglas Thompson   drivers/edac: spl...
42
  }
81d87cb13   Dave Jiang   drivers/edac: mod...
43
44
45
  /* this is temporary */
  int edac_mc_get_poll_msec(void)
  {
4de78c687   Dave Jiang   drivers/edac: mod...
46
  	return edac_mc_poll_msec;
7c9281d76   Douglas Thompson   drivers/edac: spl...
47
  }
096846e2b   Arthur Jones   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   Douglas Thompson   drivers/edac: spl...
66
  /* Parameter declarations for above */
4de78c687   Dave Jiang   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   Douglas Thompson   drivers/edac: cor...
71
  		 "Log uncorrectable error to console: 0=off 1=on");
4de78c687   Dave Jiang   drivers/edac: mod...
72
73
  module_param(edac_mc_log_ce, int, 0644);
  MODULE_PARM_DESC(edac_mc_log_ce,
079708b91   Douglas Thompson   drivers/edac: cor...
74
  		 "Log correctable error to console: 0=off 1=on");
096846e2b   Arthur Jones   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   Dave Jiang   drivers/edac: mod...
77
  MODULE_PARM_DESC(edac_mc_poll_msec, "Polling period in milliseconds");
7c9281d76   Douglas Thompson   drivers/edac: spl...
78

de3910eb7   Mauro Carvalho Chehab   edac: change the ...
79
  static struct device *mci_pdev;
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
80

7c9281d76   Douglas Thompson   drivers/edac: spl...
81
82
83
  /*
   * various constants for Memory Controllers
   */
8b7719e08   Borislav Petkov   EDAC, mc_sysfs.c:...
84
  static const char * const mem_types[] = {
7c9281d76   Douglas Thompson   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   Dave Jiang   drivers/edac: mc ...
95
96
97
  	[MEM_RMBS] = "RMBS",
  	[MEM_DDR2] = "Unbuffered-DDR2",
  	[MEM_FB_DDR2] = "FullyBuffered-DDR2",
1d5f726cb   Benjamin Herrenschmidt   drivers-edac: add...
98
  	[MEM_RDDR2] = "Registered-DDR2",
b1cfebc92   Yang Shi   edac: add DDR3 me...
99
100
101
  	[MEM_XDR] = "XDR",
  	[MEM_DDR3] = "Unbuffered-DDR3",
  	[MEM_RDDR3] = "Registered-DDR3"
7c9281d76   Douglas Thompson   drivers/edac: spl...
102
  };
8b7719e08   Borislav Petkov   EDAC, mc_sysfs.c:...
103
  static const char * const dev_types[] = {
7c9281d76   Douglas Thompson   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   Borislav Petkov   EDAC, mc_sysfs.c:...
113
  static const char * const edac_caps[] = {
7c9281d76   Douglas Thompson   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   Mauro Carvalho Chehab   edac: add a new p...
125
  #ifdef CONFIG_EDAC_LEGACY_SYSFS
7a623c039   Mauro Carvalho Chehab   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   Douglas Thompson   drivers/edac: spl...
135
   */
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
136
  #define DEVICE_ATTR_LEGACY(_name, _mode, _show, _store) \
fbe2d3616   Stephen Hemminger   EDAC: Make sysfs ...
137
  	static struct device_attribute dev_attr_legacy_##_name = __ATTR(_name, _mode, _show, _store)
7a623c039   Mauro Carvalho Chehab   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   Douglas Thompson   drivers/edac: spl...
149
150
  
  /* Set of more default csrow<id> attribute show/store functions */
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
151
152
  static ssize_t csrow_ue_count_show(struct device *dev,
  				   struct device_attribute *mattr, char *data)
7c9281d76   Douglas Thompson   drivers/edac: spl...
153
  {
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
154
  	struct csrow_info *csrow = to_csrow(dev);
079708b91   Douglas Thompson   drivers/edac: cor...
155
156
  	return sprintf(data, "%u
  ", csrow->ue_count);
7c9281d76   Douglas Thompson   drivers/edac: spl...
157
  }
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
158
159
  static ssize_t csrow_ce_count_show(struct device *dev,
  				   struct device_attribute *mattr, char *data)
7c9281d76   Douglas Thompson   drivers/edac: spl...
160
  {
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
161
  	struct csrow_info *csrow = to_csrow(dev);
079708b91   Douglas Thompson   drivers/edac: cor...
162
163
  	return sprintf(data, "%u
  ", csrow->ce_count);
7c9281d76   Douglas Thompson   drivers/edac: spl...
164
  }
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
165
166
  static ssize_t csrow_size_show(struct device *dev,
  			       struct device_attribute *mattr, char *data)
7c9281d76   Douglas Thompson   drivers/edac: spl...
167
  {
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
168
  	struct csrow_info *csrow = to_csrow(dev);
a895bf8b1   Mauro Carvalho Chehab   edac: move nr_pag...
169
170
171
172
  	int i;
  	u32 nr_pages = 0;
  
  	for (i = 0; i < csrow->nr_channels; i++)
de3910eb7   Mauro Carvalho Chehab   edac: change the ...
173
  		nr_pages += csrow->channels[i]->dimm->nr_pages;
a895bf8b1   Mauro Carvalho Chehab   edac: move nr_pag...
174
175
  	return sprintf(data, "%u
  ", PAGES_TO_MiB(nr_pages));
7c9281d76   Douglas Thompson   drivers/edac: spl...
176
  }
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
177
178
  static ssize_t csrow_mem_type_show(struct device *dev,
  				   struct device_attribute *mattr, char *data)
7c9281d76   Douglas Thompson   drivers/edac: spl...
179
  {
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
180
  	struct csrow_info *csrow = to_csrow(dev);
de3910eb7   Mauro Carvalho Chehab   edac: change the ...
181
182
  	return sprintf(data, "%s
  ", mem_types[csrow->channels[0]->dimm->mtype]);
7c9281d76   Douglas Thompson   drivers/edac: spl...
183
  }
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
184
185
  static ssize_t csrow_dev_type_show(struct device *dev,
  				   struct device_attribute *mattr, char *data)
7c9281d76   Douglas Thompson   drivers/edac: spl...
186
  {
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
187
  	struct csrow_info *csrow = to_csrow(dev);
de3910eb7   Mauro Carvalho Chehab   edac: change the ...
188
189
  	return sprintf(data, "%s
  ", dev_types[csrow->channels[0]->dimm->dtype]);
7c9281d76   Douglas Thompson   drivers/edac: spl...
190
  }
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
191
192
193
  static ssize_t csrow_edac_mode_show(struct device *dev,
  				    struct device_attribute *mattr,
  				    char *data)
7c9281d76   Douglas Thompson   drivers/edac: spl...
194
  {
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
195
  	struct csrow_info *csrow = to_csrow(dev);
de3910eb7   Mauro Carvalho Chehab   edac: change the ...
196
197
  	return sprintf(data, "%s
  ", edac_caps[csrow->channels[0]->dimm->edac_mode]);
7c9281d76   Douglas Thompson   drivers/edac: spl...
198
199
200
  }
  
  /* show/store functions for DIMM Label attributes */
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
201
202
203
  static ssize_t channel_dimm_label_show(struct device *dev,
  				       struct device_attribute *mattr,
  				       char *data)
7c9281d76   Douglas Thompson   drivers/edac: spl...
204
  {
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
205
206
  	struct csrow_info *csrow = to_csrow(dev);
  	unsigned chan = to_channel(mattr);
de3910eb7   Mauro Carvalho Chehab   edac: change the ...
207
  	struct rank_info *rank = csrow->channels[chan];
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
208

124682c78   Arthur Jones   edac: core fix ad...
209
  	/* if field has not been initialized, there is nothing to send */
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
210
  	if (!rank->dimm->label[0])
124682c78   Arthur Jones   edac: core fix ad...
211
212
213
214
  		return 0;
  
  	return snprintf(data, EDAC_MC_LABEL_LEN, "%s
  ",
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
215
  			rank->dimm->label);
7c9281d76   Douglas Thompson   drivers/edac: spl...
216
  }
7a623c039   Mauro Carvalho Chehab   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   Douglas Thompson   drivers/edac: spl...
220
  {
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
221
222
  	struct csrow_info *csrow = to_csrow(dev);
  	unsigned chan = to_channel(mattr);
de3910eb7   Mauro Carvalho Chehab   edac: change the ...
223
  	struct rank_info *rank = csrow->channels[chan];
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
224

7c9281d76   Douglas Thompson   drivers/edac: spl...
225
  	ssize_t max_size = 0;
079708b91   Douglas Thompson   drivers/edac: cor...
226
  	max_size = min((ssize_t) count, (ssize_t) EDAC_MC_LABEL_LEN - 1);
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
227
228
  	strncpy(rank->dimm->label, data, max_size);
  	rank->dimm->label[max_size] = '\0';
7c9281d76   Douglas Thompson   drivers/edac: spl...
229
230
231
232
233
  
  	return max_size;
  }
  
  /* show function for dynamic chX_ce_count attribute */
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
234
235
  static ssize_t channel_ce_count_show(struct device *dev,
  				     struct device_attribute *mattr, char *data)
7c9281d76   Douglas Thompson   drivers/edac: spl...
236
  {
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
237
238
  	struct csrow_info *csrow = to_csrow(dev);
  	unsigned chan = to_channel(mattr);
de3910eb7   Mauro Carvalho Chehab   edac: change the ...
239
  	struct rank_info *rank = csrow->channels[chan];
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
240
241
242
  
  	return sprintf(data, "%u
  ", rank->ce_count);
7c9281d76   Douglas Thompson   drivers/edac: spl...
243
  }
7a623c039   Mauro Carvalho Chehab   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   Douglas Thompson   drivers/edac: spl...
251

7a623c039   Mauro Carvalho Chehab   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   Douglas Thompson   drivers/edac: spl...
262

7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
263
264
265
  static struct attribute_group csrow_attr_grp = {
  	.attrs	= csrow_attrs,
  };
7c9281d76   Douglas Thompson   drivers/edac: spl...
266

7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
267
268
269
270
  static const struct attribute_group *csrow_attr_groups[] = {
  	&csrow_attr_grp,
  	NULL
  };
7c9281d76   Douglas Thompson   drivers/edac: spl...
271

de3910eb7   Mauro Carvalho Chehab   edac: change the ...
272
  static void csrow_attr_release(struct device *dev)
7c9281d76   Douglas Thompson   drivers/edac: spl...
273
  {
de3910eb7   Mauro Carvalho Chehab   edac: change the ...
274
  	struct csrow_info *csrow = container_of(dev, struct csrow_info, dev);
956b9ba15   Joe Perches   edac: Convert deb...
275
276
  	edac_dbg(1, "Releasing csrow device %s
  ", dev_name(dev));
de3910eb7   Mauro Carvalho Chehab   edac: change the ...
277
  	kfree(csrow);
7c9281d76   Douglas Thompson   drivers/edac: spl...
278
  }
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
279
280
281
  static struct device_type csrow_attr_type = {
  	.groups		= csrow_attr_groups,
  	.release	= csrow_attr_release,
7c9281d76   Douglas Thompson   drivers/edac: spl...
282
  };
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
283
284
285
286
  /*
   * possible dynamic channel DIMM Label attribute files
   *
   */
7c9281d76   Douglas Thompson   drivers/edac: spl...
287

7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
288
  #define EDAC_NR_CHANNELS	6
7c9281d76   Douglas Thompson   drivers/edac: spl...
289

7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
290
  DEVICE_CHANNEL(ch0_dimm_label, S_IRUGO | S_IWUSR,
052dfb45c   Douglas Thompson   drivers/edac: cle...
291
  	channel_dimm_label_show, channel_dimm_label_store, 0);
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
292
  DEVICE_CHANNEL(ch1_dimm_label, S_IRUGO | S_IWUSR,
052dfb45c   Douglas Thompson   drivers/edac: cle...
293
  	channel_dimm_label_show, channel_dimm_label_store, 1);
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
294
  DEVICE_CHANNEL(ch2_dimm_label, S_IRUGO | S_IWUSR,
052dfb45c   Douglas Thompson   drivers/edac: cle...
295
  	channel_dimm_label_show, channel_dimm_label_store, 2);
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
296
  DEVICE_CHANNEL(ch3_dimm_label, S_IRUGO | S_IWUSR,
052dfb45c   Douglas Thompson   drivers/edac: cle...
297
  	channel_dimm_label_show, channel_dimm_label_store, 3);
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
298
  DEVICE_CHANNEL(ch4_dimm_label, S_IRUGO | S_IWUSR,
052dfb45c   Douglas Thompson   drivers/edac: cle...
299
  	channel_dimm_label_show, channel_dimm_label_store, 4);
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
300
  DEVICE_CHANNEL(ch5_dimm_label, S_IRUGO | S_IWUSR,
052dfb45c   Douglas Thompson   drivers/edac: cle...
301
  	channel_dimm_label_show, channel_dimm_label_store, 5);
7c9281d76   Douglas Thompson   drivers/edac: spl...
302
303
  
  /* Total possible dynamic DIMM Label attribute file table */
7a623c039   Mauro Carvalho Chehab   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   Douglas Thompson   drivers/edac: spl...
311
312
313
  };
  
  /* possible dynamic channel ce_count attribute files */
c8c64d165   Srivatsa S. Bhat   EDAC: Don't give ...
314
  DEVICE_CHANNEL(ch0_ce_count, S_IRUGO,
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
315
  		   channel_ce_count_show, NULL, 0);
c8c64d165   Srivatsa S. Bhat   EDAC: Don't give ...
316
  DEVICE_CHANNEL(ch1_ce_count, S_IRUGO,
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
317
  		   channel_ce_count_show, NULL, 1);
c8c64d165   Srivatsa S. Bhat   EDAC: Don't give ...
318
  DEVICE_CHANNEL(ch2_ce_count, S_IRUGO,
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
319
  		   channel_ce_count_show, NULL, 2);
c8c64d165   Srivatsa S. Bhat   EDAC: Don't give ...
320
  DEVICE_CHANNEL(ch3_ce_count, S_IRUGO,
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
321
  		   channel_ce_count_show, NULL, 3);
c8c64d165   Srivatsa S. Bhat   EDAC: Don't give ...
322
  DEVICE_CHANNEL(ch4_ce_count, S_IRUGO,
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
323
  		   channel_ce_count_show, NULL, 4);
c8c64d165   Srivatsa S. Bhat   EDAC: Don't give ...
324
  DEVICE_CHANNEL(ch5_ce_count, S_IRUGO,
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
325
  		   channel_ce_count_show, NULL, 5);
7c9281d76   Douglas Thompson   drivers/edac: spl...
326
327
  
  /* Total possible dynamic ce_count attribute file table */
7a623c039   Mauro Carvalho Chehab   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   Douglas Thompson   drivers/edac: spl...
335
  };
e39f4ea9b   Mauro Carvalho Chehab   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   Mauro Carvalho Chehab   edac: change the ...
341
  		nr_pages += csrow->channels[chan]->dimm->nr_pages;
e39f4ea9b   Mauro Carvalho Chehab   edac: Only expose...
342
343
344
  
  	return nr_pages;
  }
7a623c039   Mauro Carvalho Chehab   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   Douglas Thompson   drivers/edac: spl...
348
  {
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
349
  	int err, chan;
7c9281d76   Douglas Thompson   drivers/edac: spl...
350

7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
351
352
  	if (csrow->nr_channels >= EDAC_NR_CHANNELS)
  		return -ENODEV;
7c9281d76   Douglas Thompson   drivers/edac: spl...
353

7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
354
  	csrow->dev.type = &csrow_attr_type;
f46ef77da   Borislav Petkov   EDAC: Fix lockdep...
355
  	csrow->dev.bus = mci->bus;
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
356
357
  	device_initialize(&csrow->dev);
  	csrow->dev.parent = &mci->dev;
921a68996   Borislav Petkov   EDAC: Pass mci pa...
358
  	csrow->mci = mci;
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
359
360
  	dev_set_name(&csrow->dev, "csrow%d", index);
  	dev_set_drvdata(&csrow->dev, csrow);
7c9281d76   Douglas Thompson   drivers/edac: spl...
361

956b9ba15   Joe Perches   edac: Convert deb...
362
363
364
  	edac_dbg(0, "creating (virtual) csrow node %s
  ",
  		 dev_name(&csrow->dev));
7c9281d76   Douglas Thompson   drivers/edac: spl...
365

7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
366
367
368
  	err = device_add(&csrow->dev);
  	if (err < 0)
  		return err;
7c9281d76   Douglas Thompson   drivers/edac: spl...
369

7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
370
  	for (chan = 0; chan < csrow->nr_channels; chan++) {
e39f4ea9b   Mauro Carvalho Chehab   edac: Only expose...
371
  		/* Only expose populated DIMMs */
de3910eb7   Mauro Carvalho Chehab   edac: change the ...
372
  		if (!csrow->channels[chan]->dimm->nr_pages)
e39f4ea9b   Mauro Carvalho Chehab   edac: Only expose...
373
  			continue;
7a623c039   Mauro Carvalho Chehab   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   Doug Thompson   drivers/edac: fix...
386

7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
387
  	return 0;
8096cfafb   Doug Thompson   drivers/edac: fix...
388

7a623c039   Mauro Carvalho Chehab   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   Douglas Thompson   drivers/edac: spl...
397

7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
398
399
  	return err;
  }
7c9281d76   Douglas Thompson   drivers/edac: spl...
400
401
  
  /* Create a CSROW object under specifed edac_mc_device */
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
402
  static int edac_create_csrow_objects(struct mem_ctl_info *mci)
7c9281d76   Douglas Thompson   drivers/edac: spl...
403
  {
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
404
405
  	int err, i, chan;
  	struct csrow_info *csrow;
7c9281d76   Douglas Thompson   drivers/edac: spl...
406

7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
407
  	for (i = 0; i < mci->nr_csrows; i++) {
de3910eb7   Mauro Carvalho Chehab   edac: change the ...
408
  		csrow = mci->csrows[i];
e39f4ea9b   Mauro Carvalho Chehab   edac: Only expose...
409
410
  		if (!nr_pages_per_csrow(csrow))
  			continue;
de3910eb7   Mauro Carvalho Chehab   edac: change the ...
411
  		err = edac_create_csrow_object(mci, mci->csrows[i], i);
3d958823e   Mauro Carvalho Chehab   edac: better repo...
412
413
414
415
416
  		if (err < 0) {
  			edac_dbg(1,
  				 "failure: create csrow objects for csrow %d
  ",
  				 i);
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
417
  			goto error;
3d958823e   Mauro Carvalho Chehab   edac: better repo...
418
  		}
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
419
420
  	}
  	return 0;
8096cfafb   Doug Thompson   drivers/edac: fix...
421

7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
422
423
  error:
  	for (--i; i >= 0; i--) {
de3910eb7   Mauro Carvalho Chehab   edac: change the ...
424
  		csrow = mci->csrows[i];
e39f4ea9b   Mauro Carvalho Chehab   edac: Only expose...
425
426
  		if (!nr_pages_per_csrow(csrow))
  			continue;
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
427
  		for (chan = csrow->nr_channels - 1; chan >= 0; chan--) {
de3910eb7   Mauro Carvalho Chehab   edac: change the ...
428
  			if (!csrow->channels[chan]->dimm->nr_pages)
e39f4ea9b   Mauro Carvalho Chehab   edac: Only expose...
429
  				continue;
7a623c039   Mauro Carvalho Chehab   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   Mauro Carvalho Chehab   edac: change the ...
435
  		put_device(&mci->csrows[i]->dev);
8096cfafb   Doug Thompson   drivers/edac: fix...
436
  	}
7c9281d76   Douglas Thompson   drivers/edac: spl...
437

7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
438
439
  	return err;
  }
8096cfafb   Doug Thompson   drivers/edac: fix...
440

7a623c039   Mauro Carvalho Chehab   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   Doug Thompson   drivers/edac: fix...
445

7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
446
  	for (i = mci->nr_csrows - 1; i >= 0; i--) {
de3910eb7   Mauro Carvalho Chehab   edac: change the ...
447
  		csrow = mci->csrows[i];
e39f4ea9b   Mauro Carvalho Chehab   edac: Only expose...
448
449
  		if (!nr_pages_per_csrow(csrow))
  			continue;
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
450
  		for (chan = csrow->nr_channels - 1; chan >= 0; chan--) {
de3910eb7   Mauro Carvalho Chehab   edac: change the ...
451
  			if (!csrow->channels[chan]->dimm->nr_pages)
e39f4ea9b   Mauro Carvalho Chehab   edac: Only expose...
452
  				continue;
956b9ba15   Joe Perches   edac: Convert deb...
453
454
455
  			edac_dbg(1, "Removing csrow %d channel %d sysfs nodes
  ",
  				 i, chan);
7a623c039   Mauro Carvalho Chehab   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   Douglas Thompson   drivers/edac: spl...
460
  		}
44d22e240   Lans Zhang   EDAC: Cleanup dev...
461
  		device_unregister(&mci->csrows[i]->dev);
7c9281d76   Douglas Thompson   drivers/edac: spl...
462
  	}
7c9281d76   Douglas Thompson   drivers/edac: spl...
463
  }
199747106   Mauro Carvalho Chehab   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   Mauro Carvalho Chehab   edac: add a new p...
477

6e84d359b   Mauro Carvalho Chehab   edac_mc: Cleanup ...
478
  	return edac_dimm_info_location(dimm, data, PAGE_SIZE);
199747106   Mauro Carvalho Chehab   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   Mauro Carvalho Chehab   edac: change the ...
575
  static void dimm_attr_release(struct device *dev)
199747106   Mauro Carvalho Chehab   edac: add a new p...
576
  {
de3910eb7   Mauro Carvalho Chehab   edac: change the ...
577
  	struct dimm_info *dimm = container_of(dev, struct dimm_info, dev);
956b9ba15   Joe Perches   edac: Convert deb...
578
579
  	edac_dbg(1, "Releasing dimm device %s
  ", dev_name(dev));
de3910eb7   Mauro Carvalho Chehab   edac: change the ...
580
  	kfree(dimm);
199747106   Mauro Carvalho Chehab   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   Borislav Petkov   EDAC: Fix lockdep...
597
  	dimm->dev.bus = mci->bus;
199747106   Mauro Carvalho Chehab   edac: add a new p...
598
599
600
  	device_initialize(&dimm->dev);
  
  	dimm->dev.parent = &mci->dev;
9713faecf   Mauro Carvalho Chehab   EDAC: Merge mci.m...
601
  	if (mci->csbased)
199747106   Mauro Carvalho Chehab   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   Joe Perches   edac: Convert deb...
609
610
  	edac_dbg(0, "creating rank/dimm device %s
  ", dev_name(&dimm->dev));
199747106   Mauro Carvalho Chehab   edac: add a new p...
611
612
613
  
  	return err;
  }
7c9281d76   Douglas Thompson   drivers/edac: spl...
614

7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
615
616
617
618
619
  /*
   * Memory controller device
   */
  
  #define to_mci(k) container_of(k, struct mem_ctl_info, dev)
7c9281d76   Douglas Thompson   drivers/edac: spl...
620

7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
621
622
  static ssize_t mci_reset_counters_store(struct device *dev,
  					struct device_attribute *mattr,
079708b91   Douglas Thompson   drivers/edac: cor...
623
  					const char *data, size_t count)
7c9281d76   Douglas Thompson   drivers/edac: spl...
624
  {
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
625
626
  	struct mem_ctl_info *mci = to_mci(dev);
  	int cnt, row, chan, i;
5926ff502   Mauro Carvalho Chehab   edac: Initialize ...
627
628
  	mci->ue_mc = 0;
  	mci->ce_mc = 0;
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
629
630
  	mci->ue_noinfo_count = 0;
  	mci->ce_noinfo_count = 0;
7c9281d76   Douglas Thompson   drivers/edac: spl...
631
632
  
  	for (row = 0; row < mci->nr_csrows; row++) {
de3910eb7   Mauro Carvalho Chehab   edac: change the ...
633
  		struct csrow_info *ri = mci->csrows[row];
7c9281d76   Douglas Thompson   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   Mauro Carvalho Chehab   edac: change the ...
639
  			ri->channels[chan]->ce_count = 0;
7c9281d76   Douglas Thompson   drivers/edac: spl...
640
  	}
7a623c039   Mauro Carvalho Chehab   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   Douglas Thompson   drivers/edac: spl...
647
648
649
  	mci->start_time = jiffies;
  	return count;
  }
390944439   Borislav Petkov   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   Mauro Carvalho Chehab   edac: rewrite the...
659
660
  static ssize_t mci_sdram_scrub_rate_store(struct device *dev,
  					  struct device_attribute *mattr,
eba042a81   Borislav Petkov   edac, mc: Improve...
661
  					  const char *data, size_t count)
7c9281d76   Douglas Thompson   drivers/edac: spl...
662
  {
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
663
  	struct mem_ctl_info *mci = to_mci(dev);
eba042a81   Borislav Petkov   edac, mc: Improve...
664
  	unsigned long bandwidth = 0;
390944439   Borislav Petkov   EDAC: Fixup scrub...
665
  	int new_bw = 0;
7c9281d76   Douglas Thompson   drivers/edac: spl...
666

eba042a81   Borislav Petkov   edac, mc: Improve...
667
668
  	if (strict_strtoul(data, 10, &bandwidth) < 0)
  		return -EINVAL;
7c9281d76   Douglas Thompson   drivers/edac: spl...
669

390944439   Borislav Petkov   EDAC: Fixup scrub...
670
  	new_bw = mci->set_sdram_scrub_rate(mci, bandwidth);
4949603a6   Markus Trippelsdorf   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   Douglas Thompson   drivers/edac: spl...
676
  	}
390944439   Borislav Petkov   EDAC: Fixup scrub...
677

4949603a6   Markus Trippelsdorf   EDAC: Remove debu...
678
  	return count;
7c9281d76   Douglas Thompson   drivers/edac: spl...
679
  }
390944439   Borislav Petkov   EDAC: Fixup scrub...
680
681
682
  /*
   * ->get_sdram_scrub_rate() return value semantics same as above.
   */
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
683
684
685
  static ssize_t mci_sdram_scrub_rate_show(struct device *dev,
  					 struct device_attribute *mattr,
  					 char *data)
7c9281d76   Douglas Thompson   drivers/edac: spl...
686
  {
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
687
  	struct mem_ctl_info *mci = to_mci(dev);
390944439   Borislav Petkov   EDAC: Fixup scrub...
688
  	int bandwidth = 0;
eba042a81   Borislav Petkov   edac, mc: Improve...
689

390944439   Borislav Petkov   EDAC: Fixup scrub...
690
691
  	bandwidth = mci->get_sdram_scrub_rate(mci);
  	if (bandwidth < 0) {
eba042a81   Borislav Petkov   edac, mc: Improve...
692
693
  		edac_printk(KERN_DEBUG, EDAC_MC, "Error reading scrub rate
  ");
390944439   Borislav Petkov   EDAC: Fixup scrub...
694
  		return bandwidth;
7c9281d76   Douglas Thompson   drivers/edac: spl...
695
  	}
390944439   Borislav Petkov   EDAC: Fixup scrub...
696

390944439   Borislav Petkov   EDAC: Fixup scrub...
697
698
  	return sprintf(data, "%d
  ", bandwidth);
7c9281d76   Douglas Thompson   drivers/edac: spl...
699
700
701
  }
  
  /* default attribute files for the MCI object */
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
702
703
704
  static ssize_t mci_ue_count_show(struct device *dev,
  				 struct device_attribute *mattr,
  				 char *data)
7c9281d76   Douglas Thompson   drivers/edac: spl...
705
  {
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
706
  	struct mem_ctl_info *mci = to_mci(dev);
5926ff502   Mauro Carvalho Chehab   edac: Initialize ...
707
708
  	return sprintf(data, "%d
  ", mci->ue_mc);
7c9281d76   Douglas Thompson   drivers/edac: spl...
709
  }
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
710
711
712
  static ssize_t mci_ce_count_show(struct device *dev,
  				 struct device_attribute *mattr,
  				 char *data)
7c9281d76   Douglas Thompson   drivers/edac: spl...
713
  {
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
714
  	struct mem_ctl_info *mci = to_mci(dev);
5926ff502   Mauro Carvalho Chehab   edac: Initialize ...
715
716
  	return sprintf(data, "%d
  ", mci->ce_mc);
7c9281d76   Douglas Thompson   drivers/edac: spl...
717
  }
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
718
719
720
  static ssize_t mci_ce_noinfo_show(struct device *dev,
  				  struct device_attribute *mattr,
  				  char *data)
7c9281d76   Douglas Thompson   drivers/edac: spl...
721
  {
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
722
  	struct mem_ctl_info *mci = to_mci(dev);
079708b91   Douglas Thompson   drivers/edac: cor...
723
724
  	return sprintf(data, "%d
  ", mci->ce_noinfo_count);
7c9281d76   Douglas Thompson   drivers/edac: spl...
725
  }
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
726
727
728
  static ssize_t mci_ue_noinfo_show(struct device *dev,
  				  struct device_attribute *mattr,
  				  char *data)
7c9281d76   Douglas Thompson   drivers/edac: spl...
729
  {
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
730
  	struct mem_ctl_info *mci = to_mci(dev);
079708b91   Douglas Thompson   drivers/edac: cor...
731
732
  	return sprintf(data, "%d
  ", mci->ue_noinfo_count);
7c9281d76   Douglas Thompson   drivers/edac: spl...
733
  }
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
734
735
736
  static ssize_t mci_seconds_show(struct device *dev,
  				struct device_attribute *mattr,
  				char *data)
7c9281d76   Douglas Thompson   drivers/edac: spl...
737
  {
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
738
  	struct mem_ctl_info *mci = to_mci(dev);
079708b91   Douglas Thompson   drivers/edac: cor...
739
740
  	return sprintf(data, "%ld
  ", (jiffies - mci->start_time) / HZ);
7c9281d76   Douglas Thompson   drivers/edac: spl...
741
  }
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
742
743
744
  static ssize_t mci_ctl_name_show(struct device *dev,
  				 struct device_attribute *mattr,
  				 char *data)
7c9281d76   Douglas Thompson   drivers/edac: spl...
745
  {
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
746
  	struct mem_ctl_info *mci = to_mci(dev);
079708b91   Douglas Thompson   drivers/edac: cor...
747
748
  	return sprintf(data, "%s
  ", mci->ctl_name);
7c9281d76   Douglas Thompson   drivers/edac: spl...
749
  }
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
750
751
752
  static ssize_t mci_size_mb_show(struct device *dev,
  				struct device_attribute *mattr,
  				char *data)
7c9281d76   Douglas Thompson   drivers/edac: spl...
753
  {
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
754
  	struct mem_ctl_info *mci = to_mci(dev);
a895bf8b1   Mauro Carvalho Chehab   edac: move nr_pag...
755
  	int total_pages = 0, csrow_idx, j;
7c9281d76   Douglas Thompson   drivers/edac: spl...
756

a895bf8b1   Mauro Carvalho Chehab   edac: move nr_pag...
757
  	for (csrow_idx = 0; csrow_idx < mci->nr_csrows; csrow_idx++) {
de3910eb7   Mauro Carvalho Chehab   edac: change the ...
758
  		struct csrow_info *csrow = mci->csrows[csrow_idx];
7c9281d76   Douglas Thompson   drivers/edac: spl...
759

1eef12825   Mauro Carvalho Chehab   amd64_edac: Corre...
760
761
  		for (j = 0; j < csrow->nr_channels; j++) {
  			struct dimm_info *dimm = csrow->channels[j]->dimm;
3c0622760   Josh Hunt   EDAC: Fix mc size...
762

1eef12825   Mauro Carvalho Chehab   amd64_edac: Corre...
763
  			total_pages += dimm->nr_pages;
a895bf8b1   Mauro Carvalho Chehab   edac: move nr_pag...
764
  		}
7c9281d76   Douglas Thompson   drivers/edac: spl...
765
  	}
079708b91   Douglas Thompson   drivers/edac: cor...
766
767
  	return sprintf(data, "%u
  ", PAGES_TO_MiB(total_pages));
7c9281d76   Douglas Thompson   drivers/edac: spl...
768
  }
8ad6c78a6   Mauro Carvalho Chehab   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   Mauro Carvalho Chehab   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   Mauro Carvalho Chehab   edac: allow speci...
793
794
795
796
  	u16 errcount = mci->fake_inject_count;
  
  	if (!errcount)
  		errcount = 1;
452a6bf95   Mauro Carvalho Chehab   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   Mauro Carvalho Chehab   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   Mauro Carvalho Chehab   edac: Add debufs ...
805
  		(type == HW_EVENT_ERR_UNCORRECTED) ? "UE" : "CE",
38ced28b2   Mauro Carvalho Chehab   edac: allow speci...
806
  		errcount > 1 ? "s" : "",
452a6bf95   Mauro Carvalho Chehab   edac: Add debufs ...
807
808
809
810
  		mci->fake_inject_layer[0],
  		mci->fake_inject_layer[1],
  		mci->fake_inject_layer[2]
  	       );
38ced28b2   Mauro Carvalho Chehab   edac: allow speci...
811
  	edac_mc_handle_error(type, mci, errcount, 0, 0, 0,
452a6bf95   Mauro Carvalho Chehab   edac: Add debufs ...
812
813
814
  			     mci->fake_inject_layer[0],
  			     mci->fake_inject_layer[1],
  			     mci->fake_inject_layer[2],
03f7eae80   Mauro Carvalho Chehab   edac: remove arch...
815
  			     "FAKE ERROR", "for EDAC testing only");
452a6bf95   Mauro Carvalho Chehab   edac: Add debufs ...
816
817
818
  
  	return count;
  }
452a6bf95   Mauro Carvalho Chehab   edac: Add debufs ...
819
  static const struct file_operations debug_fake_inject_fops = {
db7312a29   Wei Yongjun   EDAC: Convert to ...
820
  	.open = simple_open,
452a6bf95   Mauro Carvalho Chehab   edac: Add debufs ...
821
822
823
824
  	.write = edac_fake_inject_write,
  	.llseek = generic_file_llseek,
  };
  #endif
7c9281d76   Douglas Thompson   drivers/edac: spl...
825
  /* default Control file */
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
826
  DEVICE_ATTR(reset_counters, S_IWUSR, NULL, mci_reset_counters_store);
7c9281d76   Douglas Thompson   drivers/edac: spl...
827
828
  
  /* default Attribute files */
7a623c039   Mauro Carvalho Chehab   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   Mauro Carvalho Chehab   edac: add a sysfs...
836
  DEVICE_ATTR(max_location, S_IRUGO, mci_max_location_show, NULL);
7c9281d76   Douglas Thompson   drivers/edac: spl...
837
838
  
  /* memory scrubber attribute file */
e7100478f   Mauro Carvalho Chehab   edac: only create...
839
  DEVICE_ATTR(sdram_scrub_rate, 0, NULL, NULL);
7c9281d76   Douglas Thompson   drivers/edac: spl...
840

7a623c039   Mauro Carvalho Chehab   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   Mauro Carvalho Chehab   edac: add a sysfs...
850
  	&dev_attr_max_location.attr,
7c9281d76   Douglas Thompson   drivers/edac: spl...
851
852
  	NULL
  };
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
853
854
  static struct attribute_group mci_attr_grp = {
  	.attrs	= mci_attrs,
cc301b3ae   Mauro Carvalho Chehab   edac: store/show ...
855
  };
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
856
857
858
  static const struct attribute_group *mci_attr_groups[] = {
  	&mci_attr_grp,
  	NULL
cc301b3ae   Mauro Carvalho Chehab   edac: store/show ...
859
  };
de3910eb7   Mauro Carvalho Chehab   edac: change the ...
860
  static void mci_attr_release(struct device *dev)
42a8e397a   Douglas Thompson   drivers/edac: add...
861
  {
de3910eb7   Mauro Carvalho Chehab   edac: change the ...
862
  	struct mem_ctl_info *mci = container_of(dev, struct mem_ctl_info, dev);
956b9ba15   Joe Perches   edac: Convert deb...
863
864
  	edac_dbg(1, "Releasing csrow device %s
  ", dev_name(dev));
de3910eb7   Mauro Carvalho Chehab   edac: change the ...
865
  	kfree(mci);
42a8e397a   Douglas Thompson   drivers/edac: add...
866
  }
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
867
868
869
870
  static struct device_type mci_attr_type = {
  	.groups		= mci_attr_groups,
  	.release	= mci_attr_release,
  };
8096cfafb   Doug Thompson   drivers/edac: fix...
871

452a6bf95   Mauro Carvalho Chehab   edac: Add debufs ...
872
  #ifdef CONFIG_EDAC_DEBUG
e7930ba49   Rob Herring   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   Mauro Carvalho Chehab   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   Rob Herring   edac: create top-...
894
895
896
897
  	if (!edac_debugfs)
  		return -ENODEV;
  
  	d = debugfs_create_dir(mci->dev.kobj.name, edac_debugfs);
452a6bf95   Mauro Carvalho Chehab   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   Mauro Carvalho Chehab   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   Mauro Carvalho Chehab   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   Rob Herring   edac: create top-...
924
  	mci->debugfs = parent;
452a6bf95   Mauro Carvalho Chehab   edac: Add debufs ...
925
926
927
928
929
930
  	return 0;
  nomem:
  	debugfs_remove(mci->debugfs);
  	return -ENOMEM;
  }
  #endif
8096cfafb   Doug Thompson   drivers/edac: fix...
931
  /*
7c9281d76   Douglas Thompson   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   Mauro Carvalho Chehab   edac: rewrite the...
941
  	int i, err;
7c9281d76   Douglas Thompson   drivers/edac: spl...
942

de3910eb7   Mauro Carvalho Chehab   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   Borislav Petkov   EDAC: Fix lockdep...
947
948
  	mci->bus->name = kasprintf(GFP_KERNEL, "mc%d", mci->mc_idx);
  	if (!mci->bus->name)
de3910eb7   Mauro Carvalho Chehab   edac: change the ...
949
  		return -ENOMEM;
f46ef77da   Borislav Petkov   EDAC: Fix lockdep...
950
951
952
953
954
  
  	edac_dbg(0, "creating bus %s
  ", mci->bus->name);
  
  	err = bus_register(mci->bus);
de3910eb7   Mauro Carvalho Chehab   edac: change the ...
955
956
  	if (err < 0)
  		return err;
7c9281d76   Douglas Thompson   drivers/edac: spl...
957

7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
958
  	/* get the /sys/devices/system/edac subsys reference */
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
959
960
  	mci->dev.type = &mci_attr_type;
  	device_initialize(&mci->dev);
7c9281d76   Douglas Thompson   drivers/edac: spl...
961

de3910eb7   Mauro Carvalho Chehab   edac: change the ...
962
  	mci->dev.parent = mci_pdev;
f46ef77da   Borislav Petkov   EDAC: Fix lockdep...
963
  	mci->dev.bus = mci->bus;
7a623c039   Mauro Carvalho Chehab   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   Joe Perches   edac: Convert deb...
967
968
  	edac_dbg(0, "creating device %s
  ", dev_name(&mci->dev));
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
969
970
  	err = device_add(&mci->dev);
  	if (err < 0) {
3d958823e   Mauro Carvalho Chehab   edac: better repo...
971
972
  		edac_dbg(1, "failure: create device %s
  ", dev_name(&mci->dev));
f46ef77da   Borislav Petkov   EDAC: Fix lockdep...
973
974
  		bus_unregister(mci->bus);
  		kfree(mci->bus->name);
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
975
  		return err;
42a8e397a   Douglas Thompson   drivers/edac: add...
976
  	}
e7100478f   Mauro Carvalho Chehab   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   Mauro Carvalho Chehab   edac: rewrite the...
994
995
  	/*
  	 * Create the dimm/rank devices
7c9281d76   Douglas Thompson   drivers/edac: spl...
996
  	 */
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
997
  	for (i = 0; i < mci->tot_dimms; i++) {
de3910eb7   Mauro Carvalho Chehab   edac: change the ...
998
  		struct dimm_info *dimm = mci->dimms[i];
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
999
1000
1001
1002
  		/* Only expose populated DIMMs */
  		if (dimm->nr_pages == 0)
  			continue;
  #ifdef CONFIG_EDAC_DEBUG
956b9ba15   Joe Perches   edac: Convert deb...
1003
  		edac_dbg(1, "creating dimm%d, located at ", i);
7a623c039   Mauro Carvalho Chehab   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   Douglas Thompson   drivers/edac: spl...
1012
  		}
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
1013
  #endif
199747106   Mauro Carvalho Chehab   edac: add a new p...
1014
1015
  		err = edac_create_dimm_object(mci, dimm, i);
  		if (err) {
956b9ba15   Joe Perches   edac: Convert deb...
1016
1017
  			edac_dbg(1, "failure: create dimm %d obj
  ", i);
199747106   Mauro Carvalho Chehab   edac: add a new p...
1018
1019
  			goto fail;
  		}
7c9281d76   Douglas Thompson   drivers/edac: spl...
1020
  	}
199747106   Mauro Carvalho Chehab   edac: add a new p...
1021
  #ifdef CONFIG_EDAC_LEGACY_SYSFS
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
1022
1023
1024
  	err = edac_create_csrow_objects(mci);
  	if (err < 0)
  		goto fail;
199747106   Mauro Carvalho Chehab   edac: add a new p...
1025
  #endif
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
1026

452a6bf95   Mauro Carvalho Chehab   edac: Add debufs ...
1027
1028
1029
  #ifdef CONFIG_EDAC_DEBUG
  	edac_create_debug_nodes(mci);
  #endif
7c9281d76   Douglas Thompson   drivers/edac: spl...
1030
  	return 0;
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
1031
  fail:
079708b91   Douglas Thompson   drivers/edac: cor...
1032
  	for (i--; i >= 0; i--) {
de3910eb7   Mauro Carvalho Chehab   edac: change the ...
1033
  		struct dimm_info *dimm = mci->dimms[i];
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
1034
1035
  		if (dimm->nr_pages == 0)
  			continue;
44d22e240   Lans Zhang   EDAC: Cleanup dev...
1036
  		device_unregister(&dimm->dev);
7c9281d76   Douglas Thompson   drivers/edac: spl...
1037
  	}
e7100478f   Mauro Carvalho Chehab   edac: only create...
1038
  fail2:
44d22e240   Lans Zhang   EDAC: Cleanup dev...
1039
  	device_unregister(&mci->dev);
f46ef77da   Borislav Petkov   EDAC: Fix lockdep...
1040
1041
  	bus_unregister(mci->bus);
  	kfree(mci->bus->name);
7c9281d76   Douglas Thompson   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   Mauro Carvalho Chehab   edac: rewrite the...
1050
  	int i;
7c9281d76   Douglas Thompson   drivers/edac: spl...
1051

956b9ba15   Joe Perches   edac: Convert deb...
1052
1053
  	edac_dbg(0, "
  ");
7c9281d76   Douglas Thompson   drivers/edac: spl...
1054

452a6bf95   Mauro Carvalho Chehab   edac: Add debufs ...
1055
1056
1057
  #ifdef CONFIG_EDAC_DEBUG
  	debugfs_remove(mci->debugfs);
  #endif
199747106   Mauro Carvalho Chehab   edac: add a new p...
1058
  #ifdef CONFIG_EDAC_LEGACY_SYSFS
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
1059
  	edac_delete_csrow_objects(mci);
199747106   Mauro Carvalho Chehab   edac: add a new p...
1060
  #endif
7c9281d76   Douglas Thompson   drivers/edac: spl...
1061

7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
1062
  	for (i = 0; i < mci->tot_dimms; i++) {
de3910eb7   Mauro Carvalho Chehab   edac: change the ...
1063
  		struct dimm_info *dimm = mci->dimms[i];
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
1064
1065
  		if (dimm->nr_pages == 0)
  			continue;
956b9ba15   Joe Perches   edac: Convert deb...
1066
1067
  		edac_dbg(0, "removing device %s
  ", dev_name(&dimm->dev));
44d22e240   Lans Zhang   EDAC: Cleanup dev...
1068
  		device_unregister(&dimm->dev);
6fe1108f1   Mauro Carvalho Chehab   edac_core: Do a b...
1069
  	}
7c9281d76   Douglas Thompson   drivers/edac: spl...
1070
  }
8096cfafb   Doug Thompson   drivers/edac: fix...
1071

7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
1072
1073
  void edac_unregister_sysfs(struct mem_ctl_info *mci)
  {
956b9ba15   Joe Perches   edac: Convert deb...
1074
1075
  	edac_dbg(1, "Unregistering device %s
  ", dev_name(&mci->dev));
44d22e240   Lans Zhang   EDAC: Cleanup dev...
1076
  	device_unregister(&mci->dev);
f46ef77da   Borislav Petkov   EDAC: Fix lockdep...
1077
1078
  	bus_unregister(mci->bus);
  	kfree(mci->bus->name);
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
1079
  }
8096cfafb   Doug Thompson   drivers/edac: fix...
1080

de3910eb7   Mauro Carvalho Chehab   edac: change the ...
1081
  static void mc_attr_release(struct device *dev)
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
1082
  {
de3910eb7   Mauro Carvalho Chehab   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   Joe Perches   edac: Convert deb...
1088
1089
  	edac_dbg(1, "Releasing device %s
  ", dev_name(dev));
de3910eb7   Mauro Carvalho Chehab   edac: change the ...
1090
  	kfree(dev);
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
1091
  }
8096cfafb   Doug Thompson   drivers/edac: fix...
1092

7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
1093
1094
1095
  static struct device_type mc_attr_type = {
  	.release	= mc_attr_release,
  };
8096cfafb   Doug Thompson   drivers/edac: fix...
1096
  /*
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
1097
   * Init/exit code for the module. Basically, creates/removes /sys/class/rc
8096cfafb   Doug Thompson   drivers/edac: fix...
1098
   */
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
1099
  int __init edac_mc_sysfs_init(void)
8096cfafb   Doug Thompson   drivers/edac: fix...
1100
  {
fe5ff8b84   Kay Sievers   edac: convert sys...
1101
  	struct bus_type *edac_subsys;
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
1102
  	int err;
8096cfafb   Doug Thompson   drivers/edac: fix...
1103

fe5ff8b84   Kay Sievers   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   Joe Perches   edac: Convert deb...
1107
1108
  		edac_dbg(1, "no edac_subsys
  ");
2d56b109e   Denis Kirjanov   EDAC: Handle erro...
1109
1110
  		err = -EINVAL;
  		goto out;
8096cfafb   Doug Thompson   drivers/edac: fix...
1111
  	}
de3910eb7   Mauro Carvalho Chehab   edac: change the ...
1112
  	mci_pdev = kzalloc(sizeof(*mci_pdev), GFP_KERNEL);
2d56b109e   Denis Kirjanov   EDAC: Handle erro...
1113
1114
1115
1116
  	if (!mci_pdev) {
  		err = -ENOMEM;
  		goto out_put_sysfs;
  	}
de3910eb7   Mauro Carvalho Chehab   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   Doug Thompson   drivers/edac: fix...
1122

de3910eb7   Mauro Carvalho Chehab   edac: change the ...
1123
  	err = device_add(mci_pdev);
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
1124
  	if (err < 0)
2d56b109e   Denis Kirjanov   EDAC: Handle erro...
1125
  		goto out_dev_free;
8096cfafb   Doug Thompson   drivers/edac: fix...
1126

956b9ba15   Joe Perches   edac: Convert deb...
1127
1128
  	edac_dbg(0, "device %s created
  ", dev_name(mci_pdev));
de3910eb7   Mauro Carvalho Chehab   edac: change the ...
1129

8096cfafb   Doug Thompson   drivers/edac: fix...
1130
  	return 0;
2d56b109e   Denis Kirjanov   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   Doug Thompson   drivers/edac: fix...
1138
  }
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
1139
  void __exit edac_mc_sysfs_exit(void)
8096cfafb   Doug Thompson   drivers/edac: fix...
1140
  {
44d22e240   Lans Zhang   EDAC: Cleanup dev...
1141
  	device_unregister(mci_pdev);
fe5ff8b84   Kay Sievers   edac: convert sys...
1142
  	edac_put_sysfs_subsys();
8096cfafb   Doug Thompson   drivers/edac: fix...
1143
  }