Blame view

drivers/edac/edac_mc_sysfs.c 27.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
   *
37e59f876   Mauro Carvalho Chehab   [media, edac] Cha...
10
   * (c) 2012-2013 - Mauro Carvalho Chehab
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

78d88e8a3   Mauro Carvalho Chehab   edac: rename edac...
21
  #include "edac_mc.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
  static int edac_set_poll_msec(const char *val, struct kernel_param *kp)
  {
9da21b150   Borislav Petkov   EDAC: Poll timeou...
50
  	unsigned long l;
096846e2b   Arthur Jones   edac: core fix wo...
51
52
53
54
  	int ret;
  
  	if (!val)
  		return -EINVAL;
9da21b150   Borislav Petkov   EDAC: Poll timeou...
55
  	ret = kstrtoul(val, 0, &l);
c542b53da   Jingoo Han   EDAC: Replace str...
56
57
  	if (ret)
  		return ret;
9da21b150   Borislav Petkov   EDAC: Poll timeou...
58
59
  
  	if (l < 1000)
096846e2b   Arthur Jones   edac: core fix wo...
60
  		return -EINVAL;
9da21b150   Borislav Petkov   EDAC: Poll timeou...
61
62
  
  	*((unsigned long *)kp->arg) = l;
096846e2b   Arthur Jones   edac: core fix wo...
63
64
65
66
67
68
  
  	/* notify edac_mc engine to reset the poll period */
  	edac_mc_reset_delay_period(l);
  
  	return 0;
  }
7c9281d76   Douglas Thompson   drivers/edac: spl...
69
  /* Parameter declarations for above */
4de78c687   Dave Jiang   drivers/edac: mod...
70
71
72
73
  module_param(edac_mc_panic_on_ue, int, 0644);
  MODULE_PARM_DESC(edac_mc_panic_on_ue, "Panic on uncorrected error: 0=off 1=on");
  module_param(edac_mc_log_ue, int, 0644);
  MODULE_PARM_DESC(edac_mc_log_ue,
079708b91   Douglas Thompson   drivers/edac: cor...
74
  		 "Log uncorrectable error to console: 0=off 1=on");
4de78c687   Dave Jiang   drivers/edac: mod...
75
76
  module_param(edac_mc_log_ce, int, 0644);
  MODULE_PARM_DESC(edac_mc_log_ce,
079708b91   Douglas Thompson   drivers/edac: cor...
77
  		 "Log correctable error to console: 0=off 1=on");
096846e2b   Arthur Jones   edac: core fix wo...
78
79
  module_param_call(edac_mc_poll_msec, edac_set_poll_msec, param_get_int,
  		  &edac_mc_poll_msec, 0644);
4de78c687   Dave Jiang   drivers/edac: mod...
80
  MODULE_PARM_DESC(edac_mc_poll_msec, "Polling period in milliseconds");
7c9281d76   Douglas Thompson   drivers/edac: spl...
81

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

7c9281d76   Douglas Thompson   drivers/edac: spl...
84
85
86
  /*
   * various constants for Memory Controllers
   */
8b7719e08   Borislav Petkov   EDAC, mc_sysfs.c:...
87
  static const char * const mem_types[] = {
7c9281d76   Douglas Thompson   drivers/edac: spl...
88
89
90
91
92
93
94
95
96
97
  	[MEM_EMPTY] = "Empty",
  	[MEM_RESERVED] = "Reserved",
  	[MEM_UNKNOWN] = "Unknown",
  	[MEM_FPM] = "FPM",
  	[MEM_EDO] = "EDO",
  	[MEM_BEDO] = "BEDO",
  	[MEM_SDR] = "Unbuffered-SDR",
  	[MEM_RDR] = "Registered-SDR",
  	[MEM_DDR] = "Unbuffered-DDR",
  	[MEM_RDDR] = "Registered-DDR",
1a9b85e6b   Dave Jiang   drivers/edac: mc ...
98
99
100
  	[MEM_RMBS] = "RMBS",
  	[MEM_DDR2] = "Unbuffered-DDR2",
  	[MEM_FB_DDR2] = "FullyBuffered-DDR2",
1d5f726cb   Benjamin Herrenschmidt   drivers-edac: add...
101
  	[MEM_RDDR2] = "Registered-DDR2",
b1cfebc92   Yang Shi   edac: add DDR3 me...
102
103
  	[MEM_XDR] = "XDR",
  	[MEM_DDR3] = "Unbuffered-DDR3",
7b8278358   Aristeu Rozanski   edac: add DDR4 an...
104
105
106
  	[MEM_RDDR3] = "Registered-DDR3",
  	[MEM_DDR4] = "Unbuffered-DDR4",
  	[MEM_RDDR4] = "Registered-DDR4"
7c9281d76   Douglas Thompson   drivers/edac: spl...
107
  };
8b7719e08   Borislav Petkov   EDAC, mc_sysfs.c:...
108
  static const char * const dev_types[] = {
7c9281d76   Douglas Thompson   drivers/edac: spl...
109
110
111
112
113
114
115
116
117
  	[DEV_UNKNOWN] = "Unknown",
  	[DEV_X1] = "x1",
  	[DEV_X2] = "x2",
  	[DEV_X4] = "x4",
  	[DEV_X8] = "x8",
  	[DEV_X16] = "x16",
  	[DEV_X32] = "x32",
  	[DEV_X64] = "x64"
  };
8b7719e08   Borislav Petkov   EDAC, mc_sysfs.c:...
118
  static const char * const edac_caps[] = {
7c9281d76   Douglas Thompson   drivers/edac: spl...
119
120
121
122
123
124
125
126
127
128
129
  	[EDAC_UNKNOWN] = "Unknown",
  	[EDAC_NONE] = "None",
  	[EDAC_RESERVED] = "Reserved",
  	[EDAC_PARITY] = "PARITY",
  	[EDAC_EC] = "EC",
  	[EDAC_SECDED] = "SECDED",
  	[EDAC_S2ECD2ED] = "S2ECD2ED",
  	[EDAC_S4ECD4ED] = "S4ECD4ED",
  	[EDAC_S8ECD8ED] = "S8ECD8ED",
  	[EDAC_S16ECD16ED] = "S16ECD16ED"
  };
199747106   Mauro Carvalho Chehab   edac: add a new p...
130
  #ifdef CONFIG_EDAC_LEGACY_SYSFS
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
131
132
133
134
135
136
137
138
139
  /*
   * EDAC sysfs CSROW data structures and methods
   */
  
  #define to_csrow(k) container_of(k, struct csrow_info, dev)
  
  /*
   * We need it to avoid namespace conflicts between the legacy API
   * and the per-dimm/per-rank one
7c9281d76   Douglas Thompson   drivers/edac: spl...
140
   */
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
141
  #define DEVICE_ATTR_LEGACY(_name, _mode, _show, _store) \
fbe2d3616   Stephen Hemminger   EDAC: Make sysfs ...
142
  	static struct device_attribute dev_attr_legacy_##_name = __ATTR(_name, _mode, _show, _store)
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
143
144
145
146
147
148
149
  
  struct dev_ch_attribute {
  	struct device_attribute attr;
  	int channel;
  };
  
  #define DEVICE_CHANNEL(_name, _mode, _show, _store, _var) \
f11135d87   Borislav Petkov   EDAC: edac_mc_sys...
150
  	static struct dev_ch_attribute dev_attr_legacy_##_name = \
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
151
152
153
  		{ __ATTR(_name, _mode, _show, _store), (_var) }
  
  #define to_channel(k) (container_of(k, struct dev_ch_attribute, attr)->channel)
7c9281d76   Douglas Thompson   drivers/edac: spl...
154
155
  
  /* Set of more default csrow<id> attribute show/store functions */
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
156
157
  static ssize_t csrow_ue_count_show(struct device *dev,
  				   struct device_attribute *mattr, char *data)
7c9281d76   Douglas Thompson   drivers/edac: spl...
158
  {
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
159
  	struct csrow_info *csrow = to_csrow(dev);
079708b91   Douglas Thompson   drivers/edac: cor...
160
161
  	return sprintf(data, "%u
  ", csrow->ue_count);
7c9281d76   Douglas Thompson   drivers/edac: spl...
162
  }
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
163
164
  static ssize_t csrow_ce_count_show(struct device *dev,
  				   struct device_attribute *mattr, char *data)
7c9281d76   Douglas Thompson   drivers/edac: spl...
165
  {
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
166
  	struct csrow_info *csrow = to_csrow(dev);
079708b91   Douglas Thompson   drivers/edac: cor...
167
168
  	return sprintf(data, "%u
  ", csrow->ce_count);
7c9281d76   Douglas Thompson   drivers/edac: spl...
169
  }
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
170
171
  static ssize_t csrow_size_show(struct device *dev,
  			       struct device_attribute *mattr, char *data)
7c9281d76   Douglas Thompson   drivers/edac: spl...
172
  {
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
173
  	struct csrow_info *csrow = to_csrow(dev);
a895bf8b1   Mauro Carvalho Chehab   edac: move nr_pag...
174
175
176
177
  	int i;
  	u32 nr_pages = 0;
  
  	for (i = 0; i < csrow->nr_channels; i++)
de3910eb7   Mauro Carvalho Chehab   edac: change the ...
178
  		nr_pages += csrow->channels[i]->dimm->nr_pages;
a895bf8b1   Mauro Carvalho Chehab   edac: move nr_pag...
179
180
  	return sprintf(data, "%u
  ", PAGES_TO_MiB(nr_pages));
7c9281d76   Douglas Thompson   drivers/edac: spl...
181
  }
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
182
183
  static ssize_t csrow_mem_type_show(struct device *dev,
  				   struct device_attribute *mattr, char *data)
7c9281d76   Douglas Thompson   drivers/edac: spl...
184
  {
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
185
  	struct csrow_info *csrow = to_csrow(dev);
de3910eb7   Mauro Carvalho Chehab   edac: change the ...
186
187
  	return sprintf(data, "%s
  ", mem_types[csrow->channels[0]->dimm->mtype]);
7c9281d76   Douglas Thompson   drivers/edac: spl...
188
  }
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
189
190
  static ssize_t csrow_dev_type_show(struct device *dev,
  				   struct device_attribute *mattr, char *data)
7c9281d76   Douglas Thompson   drivers/edac: spl...
191
  {
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
192
  	struct csrow_info *csrow = to_csrow(dev);
de3910eb7   Mauro Carvalho Chehab   edac: change the ...
193
194
  	return sprintf(data, "%s
  ", dev_types[csrow->channels[0]->dimm->dtype]);
7c9281d76   Douglas Thompson   drivers/edac: spl...
195
  }
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
196
197
198
  static ssize_t csrow_edac_mode_show(struct device *dev,
  				    struct device_attribute *mattr,
  				    char *data)
7c9281d76   Douglas Thompson   drivers/edac: spl...
199
  {
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
200
  	struct csrow_info *csrow = to_csrow(dev);
de3910eb7   Mauro Carvalho Chehab   edac: change the ...
201
202
  	return sprintf(data, "%s
  ", edac_caps[csrow->channels[0]->dimm->edac_mode]);
7c9281d76   Douglas Thompson   drivers/edac: spl...
203
204
205
  }
  
  /* show/store functions for DIMM Label attributes */
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
206
207
208
  static ssize_t channel_dimm_label_show(struct device *dev,
  				       struct device_attribute *mattr,
  				       char *data)
7c9281d76   Douglas Thompson   drivers/edac: spl...
209
  {
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
210
211
  	struct csrow_info *csrow = to_csrow(dev);
  	unsigned chan = to_channel(mattr);
de3910eb7   Mauro Carvalho Chehab   edac: change the ...
212
  	struct rank_info *rank = csrow->channels[chan];
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
213

124682c78   Arthur Jones   edac: core fix ad...
214
  	/* if field has not been initialized, there is nothing to send */
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
215
  	if (!rank->dimm->label[0])
124682c78   Arthur Jones   edac: core fix ad...
216
  		return 0;
1ea62c59c   Toshi Kani   EDAC: Fix sysfs d...
217
218
  	return snprintf(data, sizeof(rank->dimm->label) + 1, "%s
  ",
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
219
  			rank->dimm->label);
7c9281d76   Douglas Thompson   drivers/edac: spl...
220
  }
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
221
222
223
  static ssize_t channel_dimm_label_store(struct device *dev,
  					struct device_attribute *mattr,
  					const char *data, size_t count)
7c9281d76   Douglas Thompson   drivers/edac: spl...
224
  {
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
225
226
  	struct csrow_info *csrow = to_csrow(dev);
  	unsigned chan = to_channel(mattr);
de3910eb7   Mauro Carvalho Chehab   edac: change the ...
227
  	struct rank_info *rank = csrow->channels[chan];
438470b84   Toshi Kani   EDAC: Fix sysfs d...
228
  	size_t copy_count = count;
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
229

438470b84   Toshi Kani   EDAC: Fix sysfs d...
230
231
232
233
234
235
  	if (count == 0)
  		return -EINVAL;
  
  	if (data[count - 1] == '\0' || data[count - 1] == '
  ')
  		copy_count -= 1;
d0c9c9301   Toshi Kani   EDAC: Don't allow...
236
  	if (copy_count == 0 || copy_count >= sizeof(rank->dimm->label))
438470b84   Toshi Kani   EDAC: Fix sysfs d...
237
  		return -EINVAL;
7c9281d76   Douglas Thompson   drivers/edac: spl...
238

438470b84   Toshi Kani   EDAC: Fix sysfs d...
239
240
  	strncpy(rank->dimm->label, data, copy_count);
  	rank->dimm->label[copy_count] = '\0';
7c9281d76   Douglas Thompson   drivers/edac: spl...
241

438470b84   Toshi Kani   EDAC: Fix sysfs d...
242
  	return count;
7c9281d76   Douglas Thompson   drivers/edac: spl...
243
244
245
  }
  
  /* show function for dynamic chX_ce_count attribute */
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
246
247
  static ssize_t channel_ce_count_show(struct device *dev,
  				     struct device_attribute *mattr, char *data)
7c9281d76   Douglas Thompson   drivers/edac: spl...
248
  {
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
249
250
  	struct csrow_info *csrow = to_csrow(dev);
  	unsigned chan = to_channel(mattr);
de3910eb7   Mauro Carvalho Chehab   edac: change the ...
251
  	struct rank_info *rank = csrow->channels[chan];
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
252
253
254
  
  	return sprintf(data, "%u
  ", rank->ce_count);
7c9281d76   Douglas Thompson   drivers/edac: spl...
255
  }
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
256
257
258
259
260
261
262
  /* cwrow<id>/attribute files */
  DEVICE_ATTR_LEGACY(size_mb, S_IRUGO, csrow_size_show, NULL);
  DEVICE_ATTR_LEGACY(dev_type, S_IRUGO, csrow_dev_type_show, NULL);
  DEVICE_ATTR_LEGACY(mem_type, S_IRUGO, csrow_mem_type_show, NULL);
  DEVICE_ATTR_LEGACY(edac_mode, S_IRUGO, csrow_edac_mode_show, NULL);
  DEVICE_ATTR_LEGACY(ue_count, S_IRUGO, csrow_ue_count_show, NULL);
  DEVICE_ATTR_LEGACY(ce_count, S_IRUGO, csrow_ce_count_show, NULL);
7c9281d76   Douglas Thompson   drivers/edac: spl...
263

7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
264
265
266
267
268
269
270
271
272
273
  /* default attributes of the CSROW<id> object */
  static struct attribute *csrow_attrs[] = {
  	&dev_attr_legacy_dev_type.attr,
  	&dev_attr_legacy_mem_type.attr,
  	&dev_attr_legacy_edac_mode.attr,
  	&dev_attr_legacy_size_mb.attr,
  	&dev_attr_legacy_ue_count.attr,
  	&dev_attr_legacy_ce_count.attr,
  	NULL,
  };
7c9281d76   Douglas Thompson   drivers/edac: spl...
274

7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
275
276
277
  static struct attribute_group csrow_attr_grp = {
  	.attrs	= csrow_attrs,
  };
7c9281d76   Douglas Thompson   drivers/edac: spl...
278

7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
279
280
281
282
  static const struct attribute_group *csrow_attr_groups[] = {
  	&csrow_attr_grp,
  	NULL
  };
7c9281d76   Douglas Thompson   drivers/edac: spl...
283

de3910eb7   Mauro Carvalho Chehab   edac: change the ...
284
  static void csrow_attr_release(struct device *dev)
7c9281d76   Douglas Thompson   drivers/edac: spl...
285
  {
de3910eb7   Mauro Carvalho Chehab   edac: change the ...
286
  	struct csrow_info *csrow = container_of(dev, struct csrow_info, dev);
956b9ba15   Joe Perches   edac: Convert deb...
287
288
  	edac_dbg(1, "Releasing csrow device %s
  ", dev_name(dev));
de3910eb7   Mauro Carvalho Chehab   edac: change the ...
289
  	kfree(csrow);
7c9281d76   Douglas Thompson   drivers/edac: spl...
290
  }
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
291
292
293
  static struct device_type csrow_attr_type = {
  	.groups		= csrow_attr_groups,
  	.release	= csrow_attr_release,
7c9281d76   Douglas Thompson   drivers/edac: spl...
294
  };
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
295
296
297
298
  /*
   * possible dynamic channel DIMM Label attribute files
   *
   */
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
299
  DEVICE_CHANNEL(ch0_dimm_label, S_IRUGO | S_IWUSR,
052dfb45c   Douglas Thompson   drivers/edac: cle...
300
  	channel_dimm_label_show, channel_dimm_label_store, 0);
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
301
  DEVICE_CHANNEL(ch1_dimm_label, S_IRUGO | S_IWUSR,
052dfb45c   Douglas Thompson   drivers/edac: cle...
302
  	channel_dimm_label_show, channel_dimm_label_store, 1);
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
303
  DEVICE_CHANNEL(ch2_dimm_label, S_IRUGO | S_IWUSR,
052dfb45c   Douglas Thompson   drivers/edac: cle...
304
  	channel_dimm_label_show, channel_dimm_label_store, 2);
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
305
  DEVICE_CHANNEL(ch3_dimm_label, S_IRUGO | S_IWUSR,
052dfb45c   Douglas Thompson   drivers/edac: cle...
306
  	channel_dimm_label_show, channel_dimm_label_store, 3);
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
307
  DEVICE_CHANNEL(ch4_dimm_label, S_IRUGO | S_IWUSR,
052dfb45c   Douglas Thompson   drivers/edac: cle...
308
  	channel_dimm_label_show, channel_dimm_label_store, 4);
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
309
  DEVICE_CHANNEL(ch5_dimm_label, S_IRUGO | S_IWUSR,
052dfb45c   Douglas Thompson   drivers/edac: cle...
310
  	channel_dimm_label_show, channel_dimm_label_store, 5);
bba142957   Borislav Petkov   EDAC: Correct cha...
311
312
313
314
  DEVICE_CHANNEL(ch6_dimm_label, S_IRUGO | S_IWUSR,
  	channel_dimm_label_show, channel_dimm_label_store, 6);
  DEVICE_CHANNEL(ch7_dimm_label, S_IRUGO | S_IWUSR,
  	channel_dimm_label_show, channel_dimm_label_store, 7);
7c9281d76   Douglas Thompson   drivers/edac: spl...
315
316
  
  /* Total possible dynamic DIMM Label attribute file table */
2c1946b6d   Takashi Iwai   EDAC: Use static ...
317
318
319
320
321
322
323
  static struct attribute *dynamic_csrow_dimm_attr[] = {
  	&dev_attr_legacy_ch0_dimm_label.attr.attr,
  	&dev_attr_legacy_ch1_dimm_label.attr.attr,
  	&dev_attr_legacy_ch2_dimm_label.attr.attr,
  	&dev_attr_legacy_ch3_dimm_label.attr.attr,
  	&dev_attr_legacy_ch4_dimm_label.attr.attr,
  	&dev_attr_legacy_ch5_dimm_label.attr.attr,
bba142957   Borislav Petkov   EDAC: Correct cha...
324
325
  	&dev_attr_legacy_ch6_dimm_label.attr.attr,
  	&dev_attr_legacy_ch7_dimm_label.attr.attr,
2c1946b6d   Takashi Iwai   EDAC: Use static ...
326
  	NULL
7c9281d76   Douglas Thompson   drivers/edac: spl...
327
328
329
  };
  
  /* possible dynamic channel ce_count attribute files */
c8c64d165   Srivatsa S. Bhat   EDAC: Don't give ...
330
  DEVICE_CHANNEL(ch0_ce_count, S_IRUGO,
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
331
  		   channel_ce_count_show, NULL, 0);
c8c64d165   Srivatsa S. Bhat   EDAC: Don't give ...
332
  DEVICE_CHANNEL(ch1_ce_count, S_IRUGO,
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
333
  		   channel_ce_count_show, NULL, 1);
c8c64d165   Srivatsa S. Bhat   EDAC: Don't give ...
334
  DEVICE_CHANNEL(ch2_ce_count, S_IRUGO,
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
335
  		   channel_ce_count_show, NULL, 2);
c8c64d165   Srivatsa S. Bhat   EDAC: Don't give ...
336
  DEVICE_CHANNEL(ch3_ce_count, S_IRUGO,
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
337
  		   channel_ce_count_show, NULL, 3);
c8c64d165   Srivatsa S. Bhat   EDAC: Don't give ...
338
  DEVICE_CHANNEL(ch4_ce_count, S_IRUGO,
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
339
  		   channel_ce_count_show, NULL, 4);
c8c64d165   Srivatsa S. Bhat   EDAC: Don't give ...
340
  DEVICE_CHANNEL(ch5_ce_count, S_IRUGO,
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
341
  		   channel_ce_count_show, NULL, 5);
bba142957   Borislav Petkov   EDAC: Correct cha...
342
343
344
345
  DEVICE_CHANNEL(ch6_ce_count, S_IRUGO,
  		   channel_ce_count_show, NULL, 6);
  DEVICE_CHANNEL(ch7_ce_count, S_IRUGO,
  		   channel_ce_count_show, NULL, 7);
7c9281d76   Douglas Thompson   drivers/edac: spl...
346
347
  
  /* Total possible dynamic ce_count attribute file table */
2c1946b6d   Takashi Iwai   EDAC: Use static ...
348
349
350
351
352
353
354
  static struct attribute *dynamic_csrow_ce_count_attr[] = {
  	&dev_attr_legacy_ch0_ce_count.attr.attr,
  	&dev_attr_legacy_ch1_ce_count.attr.attr,
  	&dev_attr_legacy_ch2_ce_count.attr.attr,
  	&dev_attr_legacy_ch3_ce_count.attr.attr,
  	&dev_attr_legacy_ch4_ce_count.attr.attr,
  	&dev_attr_legacy_ch5_ce_count.attr.attr,
bba142957   Borislav Petkov   EDAC: Correct cha...
355
356
  	&dev_attr_legacy_ch6_ce_count.attr.attr,
  	&dev_attr_legacy_ch7_ce_count.attr.attr,
2c1946b6d   Takashi Iwai   EDAC: Use static ...
357
358
359
360
361
362
363
364
365
366
367
  	NULL
  };
  
  static umode_t csrow_dev_is_visible(struct kobject *kobj,
  				    struct attribute *attr, int idx)
  {
  	struct device *dev = kobj_to_dev(kobj);
  	struct csrow_info *csrow = container_of(dev, struct csrow_info, dev);
  
  	if (idx >= csrow->nr_channels)
  		return 0;
bba142957   Borislav Petkov   EDAC: Correct cha...
368
369
370
371
372
373
  
  	if (idx >= ARRAY_SIZE(dynamic_csrow_ce_count_attr) - 1) {
  		WARN_ONCE(1, "idx: %d
  ", idx);
  		return 0;
  	}
2c1946b6d   Takashi Iwai   EDAC: Use static ...
374
375
376
  	/* Only expose populated DIMMs */
  	if (!csrow->channels[idx]->dimm->nr_pages)
  		return 0;
bba142957   Borislav Petkov   EDAC: Correct cha...
377

2c1946b6d   Takashi Iwai   EDAC: Use static ...
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
  	return attr->mode;
  }
  
  
  static const struct attribute_group csrow_dev_dimm_group = {
  	.attrs = dynamic_csrow_dimm_attr,
  	.is_visible = csrow_dev_is_visible,
  };
  
  static const struct attribute_group csrow_dev_ce_count_group = {
  	.attrs = dynamic_csrow_ce_count_attr,
  	.is_visible = csrow_dev_is_visible,
  };
  
  static const struct attribute_group *csrow_dev_groups[] = {
  	&csrow_dev_dimm_group,
  	&csrow_dev_ce_count_group,
  	NULL
7c9281d76   Douglas Thompson   drivers/edac: spl...
396
  };
e39f4ea9b   Mauro Carvalho Chehab   edac: Only expose...
397
398
399
400
401
  static inline int nr_pages_per_csrow(struct csrow_info *csrow)
  {
  	int chan, nr_pages = 0;
  
  	for (chan = 0; chan < csrow->nr_channels; chan++)
de3910eb7   Mauro Carvalho Chehab   edac: change the ...
402
  		nr_pages += csrow->channels[chan]->dimm->nr_pages;
e39f4ea9b   Mauro Carvalho Chehab   edac: Only expose...
403
404
405
  
  	return nr_pages;
  }
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
406
407
408
  /* Create a CSROW object under specifed edac_mc_device */
  static int edac_create_csrow_object(struct mem_ctl_info *mci,
  				    struct csrow_info *csrow, int index)
7c9281d76   Douglas Thompson   drivers/edac: spl...
409
  {
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
410
  	csrow->dev.type = &csrow_attr_type;
88d84ac97   Borislav Petkov   EDAC: Fix lockdep...
411
  	csrow->dev.bus = mci->bus;
2c1946b6d   Takashi Iwai   EDAC: Use static ...
412
  	csrow->dev.groups = csrow_dev_groups;
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
413
414
  	device_initialize(&csrow->dev);
  	csrow->dev.parent = &mci->dev;
921a68996   Borislav Petkov   EDAC: Pass mci pa...
415
  	csrow->mci = mci;
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
416
417
  	dev_set_name(&csrow->dev, "csrow%d", index);
  	dev_set_drvdata(&csrow->dev, csrow);
7c9281d76   Douglas Thompson   drivers/edac: spl...
418

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

2c1946b6d   Takashi Iwai   EDAC: Use static ...
423
  	return device_add(&csrow->dev);
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
424
  }
7c9281d76   Douglas Thompson   drivers/edac: spl...
425
426
  
  /* Create a CSROW object under specifed edac_mc_device */
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
427
  static int edac_create_csrow_objects(struct mem_ctl_info *mci)
7c9281d76   Douglas Thompson   drivers/edac: spl...
428
  {
2c1946b6d   Takashi Iwai   EDAC: Use static ...
429
  	int err, i;
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
430
  	struct csrow_info *csrow;
7c9281d76   Douglas Thompson   drivers/edac: spl...
431

7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
432
  	for (i = 0; i < mci->nr_csrows; i++) {
de3910eb7   Mauro Carvalho Chehab   edac: change the ...
433
  		csrow = mci->csrows[i];
e39f4ea9b   Mauro Carvalho Chehab   edac: Only expose...
434
435
  		if (!nr_pages_per_csrow(csrow))
  			continue;
de3910eb7   Mauro Carvalho Chehab   edac: change the ...
436
  		err = edac_create_csrow_object(mci, mci->csrows[i], i);
3d958823e   Mauro Carvalho Chehab   edac: better repo...
437
438
439
440
441
  		if (err < 0) {
  			edac_dbg(1,
  				 "failure: create csrow objects for csrow %d
  ",
  				 i);
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
442
  			goto error;
3d958823e   Mauro Carvalho Chehab   edac: better repo...
443
  		}
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
444
445
  	}
  	return 0;
8096cfafb   Doug Thompson   drivers/edac: fix...
446

7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
447
448
  error:
  	for (--i; i >= 0; i--) {
de3910eb7   Mauro Carvalho Chehab   edac: change the ...
449
  		csrow = mci->csrows[i];
e39f4ea9b   Mauro Carvalho Chehab   edac: Only expose...
450
451
  		if (!nr_pages_per_csrow(csrow))
  			continue;
de3910eb7   Mauro Carvalho Chehab   edac: change the ...
452
  		put_device(&mci->csrows[i]->dev);
8096cfafb   Doug Thompson   drivers/edac: fix...
453
  	}
7c9281d76   Douglas Thompson   drivers/edac: spl...
454

7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
455
456
  	return err;
  }
8096cfafb   Doug Thompson   drivers/edac: fix...
457

7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
458
459
  static void edac_delete_csrow_objects(struct mem_ctl_info *mci)
  {
2c1946b6d   Takashi Iwai   EDAC: Use static ...
460
  	int i;
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
461
  	struct csrow_info *csrow;
8096cfafb   Doug Thompson   drivers/edac: fix...
462

7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
463
  	for (i = mci->nr_csrows - 1; i >= 0; i--) {
de3910eb7   Mauro Carvalho Chehab   edac: change the ...
464
  		csrow = mci->csrows[i];
e39f4ea9b   Mauro Carvalho Chehab   edac: Only expose...
465
466
  		if (!nr_pages_per_csrow(csrow))
  			continue;
44d22e240   Lans Zhang   EDAC: Cleanup dev...
467
  		device_unregister(&mci->csrows[i]->dev);
7c9281d76   Douglas Thompson   drivers/edac: spl...
468
  	}
7c9281d76   Douglas Thompson   drivers/edac: spl...
469
  }
199747106   Mauro Carvalho Chehab   edac: add a new p...
470
471
472
473
474
475
476
477
478
479
480
481
482
  #endif
  
  /*
   * Per-dimm (or per-rank) devices
   */
  
  #define to_dimm(k) container_of(k, struct dimm_info, dev)
  
  /* show/store functions for DIMM Label attributes */
  static ssize_t dimmdev_location_show(struct device *dev,
  				     struct device_attribute *mattr, char *data)
  {
  	struct dimm_info *dimm = to_dimm(dev);
199747106   Mauro Carvalho Chehab   edac: add a new p...
483

6e84d359b   Mauro Carvalho Chehab   edac_mc: Cleanup ...
484
  	return edac_dimm_info_location(dimm, data, PAGE_SIZE);
199747106   Mauro Carvalho Chehab   edac: add a new p...
485
486
487
488
489
490
491
492
493
494
  }
  
  static ssize_t dimmdev_label_show(struct device *dev,
  				  struct device_attribute *mattr, char *data)
  {
  	struct dimm_info *dimm = to_dimm(dev);
  
  	/* if field has not been initialized, there is nothing to send */
  	if (!dimm->label[0])
  		return 0;
1ea62c59c   Toshi Kani   EDAC: Fix sysfs d...
495
496
  	return snprintf(data, sizeof(dimm->label) + 1, "%s
  ", dimm->label);
199747106   Mauro Carvalho Chehab   edac: add a new p...
497
498
499
500
501
502
503
504
  }
  
  static ssize_t dimmdev_label_store(struct device *dev,
  				   struct device_attribute *mattr,
  				   const char *data,
  				   size_t count)
  {
  	struct dimm_info *dimm = to_dimm(dev);
438470b84   Toshi Kani   EDAC: Fix sysfs d...
505
  	size_t copy_count = count;
199747106   Mauro Carvalho Chehab   edac: add a new p...
506

438470b84   Toshi Kani   EDAC: Fix sysfs d...
507
508
509
510
511
512
  	if (count == 0)
  		return -EINVAL;
  
  	if (data[count - 1] == '\0' || data[count - 1] == '
  ')
  		copy_count -= 1;
d0c9c9301   Toshi Kani   EDAC: Don't allow...
513
  	if (copy_count == 0 || copy_count >= sizeof(dimm->label))
438470b84   Toshi Kani   EDAC: Fix sysfs d...
514
  		return -EINVAL;
199747106   Mauro Carvalho Chehab   edac: add a new p...
515

438470b84   Toshi Kani   EDAC: Fix sysfs d...
516
517
  	strncpy(dimm->label, data, copy_count);
  	dimm->label[copy_count] = '\0';
199747106   Mauro Carvalho Chehab   edac: add a new p...
518

438470b84   Toshi Kani   EDAC: Fix sysfs d...
519
  	return count;
199747106   Mauro Carvalho Chehab   edac: add a new p...
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
  }
  
  static ssize_t dimmdev_size_show(struct device *dev,
  				 struct device_attribute *mattr, char *data)
  {
  	struct dimm_info *dimm = to_dimm(dev);
  
  	return sprintf(data, "%u
  ", PAGES_TO_MiB(dimm->nr_pages));
  }
  
  static ssize_t dimmdev_mem_type_show(struct device *dev,
  				     struct device_attribute *mattr, char *data)
  {
  	struct dimm_info *dimm = to_dimm(dev);
  
  	return sprintf(data, "%s
  ", mem_types[dimm->mtype]);
  }
  
  static ssize_t dimmdev_dev_type_show(struct device *dev,
  				     struct device_attribute *mattr, char *data)
  {
  	struct dimm_info *dimm = to_dimm(dev);
  
  	return sprintf(data, "%s
  ", dev_types[dimm->dtype]);
  }
  
  static ssize_t dimmdev_edac_mode_show(struct device *dev,
  				      struct device_attribute *mattr,
  				      char *data)
  {
  	struct dimm_info *dimm = to_dimm(dev);
  
  	return sprintf(data, "%s
  ", edac_caps[dimm->edac_mode]);
  }
4fb6fde74   Aaron Miller   EDAC: Expose per-...
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
  static ssize_t dimmdev_ce_count_show(struct device *dev,
  				      struct device_attribute *mattr,
  				      char *data)
  {
  	struct dimm_info *dimm = to_dimm(dev);
  	u32 count;
  	int off;
  
  	off = EDAC_DIMM_OFF(dimm->mci->layers,
  			    dimm->mci->n_layers,
  			    dimm->location[0],
  			    dimm->location[1],
  			    dimm->location[2]);
  	count = dimm->mci->ce_per_layer[dimm->mci->n_layers-1][off];
  	return sprintf(data, "%u
  ", count);
  }
  
  static ssize_t dimmdev_ue_count_show(struct device *dev,
  				      struct device_attribute *mattr,
  				      char *data)
  {
  	struct dimm_info *dimm = to_dimm(dev);
  	u32 count;
  	int off;
  
  	off = EDAC_DIMM_OFF(dimm->mci->layers,
  			    dimm->mci->n_layers,
  			    dimm->location[0],
  			    dimm->location[1],
  			    dimm->location[2]);
  	count = dimm->mci->ue_per_layer[dimm->mci->n_layers-1][off];
  	return sprintf(data, "%u
  ", count);
  }
199747106   Mauro Carvalho Chehab   edac: add a new p...
593
594
595
596
597
598
599
600
  /* dimm/rank attribute files */
  static DEVICE_ATTR(dimm_label, S_IRUGO | S_IWUSR,
  		   dimmdev_label_show, dimmdev_label_store);
  static DEVICE_ATTR(dimm_location, S_IRUGO, dimmdev_location_show, NULL);
  static DEVICE_ATTR(size, S_IRUGO, dimmdev_size_show, NULL);
  static DEVICE_ATTR(dimm_mem_type, S_IRUGO, dimmdev_mem_type_show, NULL);
  static DEVICE_ATTR(dimm_dev_type, S_IRUGO, dimmdev_dev_type_show, NULL);
  static DEVICE_ATTR(dimm_edac_mode, S_IRUGO, dimmdev_edac_mode_show, NULL);
4fb6fde74   Aaron Miller   EDAC: Expose per-...
601
602
  static DEVICE_ATTR(dimm_ce_count, S_IRUGO, dimmdev_ce_count_show, NULL);
  static DEVICE_ATTR(dimm_ue_count, S_IRUGO, dimmdev_ue_count_show, NULL);
199747106   Mauro Carvalho Chehab   edac: add a new p...
603
604
605
606
607
608
609
610
611
  
  /* attributes of the dimm<id>/rank<id> object */
  static struct attribute *dimm_attrs[] = {
  	&dev_attr_dimm_label.attr,
  	&dev_attr_dimm_location.attr,
  	&dev_attr_size.attr,
  	&dev_attr_dimm_mem_type.attr,
  	&dev_attr_dimm_dev_type.attr,
  	&dev_attr_dimm_edac_mode.attr,
4fb6fde74   Aaron Miller   EDAC: Expose per-...
612
613
  	&dev_attr_dimm_ce_count.attr,
  	&dev_attr_dimm_ue_count.attr,
199747106   Mauro Carvalho Chehab   edac: add a new p...
614
615
616
617
618
619
620
621
622
623
624
  	NULL,
  };
  
  static struct attribute_group dimm_attr_grp = {
  	.attrs	= dimm_attrs,
  };
  
  static const struct attribute_group *dimm_attr_groups[] = {
  	&dimm_attr_grp,
  	NULL
  };
de3910eb7   Mauro Carvalho Chehab   edac: change the ...
625
  static void dimm_attr_release(struct device *dev)
199747106   Mauro Carvalho Chehab   edac: add a new p...
626
  {
de3910eb7   Mauro Carvalho Chehab   edac: change the ...
627
  	struct dimm_info *dimm = container_of(dev, struct dimm_info, dev);
956b9ba15   Joe Perches   edac: Convert deb...
628
629
  	edac_dbg(1, "Releasing dimm device %s
  ", dev_name(dev));
de3910eb7   Mauro Carvalho Chehab   edac: change the ...
630
  	kfree(dimm);
199747106   Mauro Carvalho Chehab   edac: add a new p...
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
  }
  
  static struct device_type dimm_attr_type = {
  	.groups		= dimm_attr_groups,
  	.release	= dimm_attr_release,
  };
  
  /* Create a DIMM object under specifed memory controller device */
  static int edac_create_dimm_object(struct mem_ctl_info *mci,
  				   struct dimm_info *dimm,
  				   int index)
  {
  	int err;
  	dimm->mci = mci;
  
  	dimm->dev.type = &dimm_attr_type;
88d84ac97   Borislav Petkov   EDAC: Fix lockdep...
647
  	dimm->dev.bus = mci->bus;
199747106   Mauro Carvalho Chehab   edac: add a new p...
648
649
650
  	device_initialize(&dimm->dev);
  
  	dimm->dev.parent = &mci->dev;
9713faecf   Mauro Carvalho Chehab   EDAC: Merge mci.m...
651
  	if (mci->csbased)
199747106   Mauro Carvalho Chehab   edac: add a new p...
652
653
654
655
656
657
658
  		dev_set_name(&dimm->dev, "rank%d", index);
  	else
  		dev_set_name(&dimm->dev, "dimm%d", index);
  	dev_set_drvdata(&dimm->dev, dimm);
  	pm_runtime_forbid(&mci->dev);
  
  	err =  device_add(&dimm->dev);
956b9ba15   Joe Perches   edac: Convert deb...
659
660
  	edac_dbg(0, "creating rank/dimm device %s
  ", dev_name(&dimm->dev));
199747106   Mauro Carvalho Chehab   edac: add a new p...
661
662
663
  
  	return err;
  }
7c9281d76   Douglas Thompson   drivers/edac: spl...
664

7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
665
666
667
668
669
  /*
   * Memory controller device
   */
  
  #define to_mci(k) container_of(k, struct mem_ctl_info, dev)
7c9281d76   Douglas Thompson   drivers/edac: spl...
670

7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
671
672
  static ssize_t mci_reset_counters_store(struct device *dev,
  					struct device_attribute *mattr,
079708b91   Douglas Thompson   drivers/edac: cor...
673
  					const char *data, size_t count)
7c9281d76   Douglas Thompson   drivers/edac: spl...
674
  {
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
675
676
  	struct mem_ctl_info *mci = to_mci(dev);
  	int cnt, row, chan, i;
5926ff502   Mauro Carvalho Chehab   edac: Initialize ...
677
678
  	mci->ue_mc = 0;
  	mci->ce_mc = 0;
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
679
680
  	mci->ue_noinfo_count = 0;
  	mci->ce_noinfo_count = 0;
7c9281d76   Douglas Thompson   drivers/edac: spl...
681
682
  
  	for (row = 0; row < mci->nr_csrows; row++) {
de3910eb7   Mauro Carvalho Chehab   edac: change the ...
683
  		struct csrow_info *ri = mci->csrows[row];
7c9281d76   Douglas Thompson   drivers/edac: spl...
684
685
686
687
688
  
  		ri->ue_count = 0;
  		ri->ce_count = 0;
  
  		for (chan = 0; chan < ri->nr_channels; chan++)
de3910eb7   Mauro Carvalho Chehab   edac: change the ...
689
  			ri->channels[chan]->ce_count = 0;
7c9281d76   Douglas Thompson   drivers/edac: spl...
690
  	}
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
691
692
693
694
695
696
  	cnt = 1;
  	for (i = 0; i < mci->n_layers; i++) {
  		cnt *= mci->layers[i].size;
  		memset(mci->ce_per_layer[i], 0, cnt * sizeof(u32));
  		memset(mci->ue_per_layer[i], 0, cnt * sizeof(u32));
  	}
7c9281d76   Douglas Thompson   drivers/edac: spl...
697
698
699
  	mci->start_time = jiffies;
  	return count;
  }
390944439   Borislav Petkov   EDAC: Fixup scrub...
700
701
702
703
704
705
706
707
708
  /* Memory scrubbing interface:
   *
   * A MC driver can limit the scrubbing bandwidth based on the CPU type.
   * Therefore, ->set_sdram_scrub_rate should be made to return the actual
   * bandwidth that is accepted or 0 when scrubbing is to be disabled.
   *
   * Negative value still means that an error has occurred while setting
   * the scrub rate.
   */
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
709
710
  static ssize_t mci_sdram_scrub_rate_store(struct device *dev,
  					  struct device_attribute *mattr,
eba042a81   Borislav Petkov   edac, mc: Improve...
711
  					  const char *data, size_t count)
7c9281d76   Douglas Thompson   drivers/edac: spl...
712
  {
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
713
  	struct mem_ctl_info *mci = to_mci(dev);
eba042a81   Borislav Petkov   edac, mc: Improve...
714
  	unsigned long bandwidth = 0;
390944439   Borislav Petkov   EDAC: Fixup scrub...
715
  	int new_bw = 0;
7c9281d76   Douglas Thompson   drivers/edac: spl...
716

c7f62fc87   Jingoo Han   EDAC: Replace str...
717
  	if (kstrtoul(data, 10, &bandwidth) < 0)
eba042a81   Borislav Petkov   edac, mc: Improve...
718
  		return -EINVAL;
7c9281d76   Douglas Thompson   drivers/edac: spl...
719

390944439   Borislav Petkov   EDAC: Fixup scrub...
720
  	new_bw = mci->set_sdram_scrub_rate(mci, bandwidth);
4949603a6   Markus Trippelsdorf   EDAC: Remove debu...
721
722
723
724
725
  	if (new_bw < 0) {
  		edac_printk(KERN_WARNING, EDAC_MC,
  			    "Error setting scrub rate to: %lu
  ", bandwidth);
  		return -EINVAL;
7c9281d76   Douglas Thompson   drivers/edac: spl...
726
  	}
390944439   Borislav Petkov   EDAC: Fixup scrub...
727

4949603a6   Markus Trippelsdorf   EDAC: Remove debu...
728
  	return count;
7c9281d76   Douglas Thompson   drivers/edac: spl...
729
  }
390944439   Borislav Petkov   EDAC: Fixup scrub...
730
731
732
  /*
   * ->get_sdram_scrub_rate() return value semantics same as above.
   */
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
733
734
735
  static ssize_t mci_sdram_scrub_rate_show(struct device *dev,
  					 struct device_attribute *mattr,
  					 char *data)
7c9281d76   Douglas Thompson   drivers/edac: spl...
736
  {
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
737
  	struct mem_ctl_info *mci = to_mci(dev);
390944439   Borislav Petkov   EDAC: Fixup scrub...
738
  	int bandwidth = 0;
eba042a81   Borislav Petkov   edac, mc: Improve...
739

390944439   Borislav Petkov   EDAC: Fixup scrub...
740
741
  	bandwidth = mci->get_sdram_scrub_rate(mci);
  	if (bandwidth < 0) {
eba042a81   Borislav Petkov   edac, mc: Improve...
742
743
  		edac_printk(KERN_DEBUG, EDAC_MC, "Error reading scrub rate
  ");
390944439   Borislav Petkov   EDAC: Fixup scrub...
744
  		return bandwidth;
7c9281d76   Douglas Thompson   drivers/edac: spl...
745
  	}
390944439   Borislav Petkov   EDAC: Fixup scrub...
746

390944439   Borislav Petkov   EDAC: Fixup scrub...
747
748
  	return sprintf(data, "%d
  ", bandwidth);
7c9281d76   Douglas Thompson   drivers/edac: spl...
749
750
751
  }
  
  /* default attribute files for the MCI object */
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
752
753
754
  static ssize_t mci_ue_count_show(struct device *dev,
  				 struct device_attribute *mattr,
  				 char *data)
7c9281d76   Douglas Thompson   drivers/edac: spl...
755
  {
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
756
  	struct mem_ctl_info *mci = to_mci(dev);
5926ff502   Mauro Carvalho Chehab   edac: Initialize ...
757
758
  	return sprintf(data, "%d
  ", mci->ue_mc);
7c9281d76   Douglas Thompson   drivers/edac: spl...
759
  }
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
760
761
762
  static ssize_t mci_ce_count_show(struct device *dev,
  				 struct device_attribute *mattr,
  				 char *data)
7c9281d76   Douglas Thompson   drivers/edac: spl...
763
  {
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
764
  	struct mem_ctl_info *mci = to_mci(dev);
5926ff502   Mauro Carvalho Chehab   edac: Initialize ...
765
766
  	return sprintf(data, "%d
  ", mci->ce_mc);
7c9281d76   Douglas Thompson   drivers/edac: spl...
767
  }
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
768
769
770
  static ssize_t mci_ce_noinfo_show(struct device *dev,
  				  struct device_attribute *mattr,
  				  char *data)
7c9281d76   Douglas Thompson   drivers/edac: spl...
771
  {
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
772
  	struct mem_ctl_info *mci = to_mci(dev);
079708b91   Douglas Thompson   drivers/edac: cor...
773
774
  	return sprintf(data, "%d
  ", mci->ce_noinfo_count);
7c9281d76   Douglas Thompson   drivers/edac: spl...
775
  }
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
776
777
778
  static ssize_t mci_ue_noinfo_show(struct device *dev,
  				  struct device_attribute *mattr,
  				  char *data)
7c9281d76   Douglas Thompson   drivers/edac: spl...
779
  {
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
780
  	struct mem_ctl_info *mci = to_mci(dev);
079708b91   Douglas Thompson   drivers/edac: cor...
781
782
  	return sprintf(data, "%d
  ", mci->ue_noinfo_count);
7c9281d76   Douglas Thompson   drivers/edac: spl...
783
  }
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
784
785
786
  static ssize_t mci_seconds_show(struct device *dev,
  				struct device_attribute *mattr,
  				char *data)
7c9281d76   Douglas Thompson   drivers/edac: spl...
787
  {
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
788
  	struct mem_ctl_info *mci = to_mci(dev);
079708b91   Douglas Thompson   drivers/edac: cor...
789
790
  	return sprintf(data, "%ld
  ", (jiffies - mci->start_time) / HZ);
7c9281d76   Douglas Thompson   drivers/edac: spl...
791
  }
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
792
793
794
  static ssize_t mci_ctl_name_show(struct device *dev,
  				 struct device_attribute *mattr,
  				 char *data)
7c9281d76   Douglas Thompson   drivers/edac: spl...
795
  {
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
796
  	struct mem_ctl_info *mci = to_mci(dev);
079708b91   Douglas Thompson   drivers/edac: cor...
797
798
  	return sprintf(data, "%s
  ", mci->ctl_name);
7c9281d76   Douglas Thompson   drivers/edac: spl...
799
  }
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
800
801
802
  static ssize_t mci_size_mb_show(struct device *dev,
  				struct device_attribute *mattr,
  				char *data)
7c9281d76   Douglas Thompson   drivers/edac: spl...
803
  {
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
804
  	struct mem_ctl_info *mci = to_mci(dev);
a895bf8b1   Mauro Carvalho Chehab   edac: move nr_pag...
805
  	int total_pages = 0, csrow_idx, j;
7c9281d76   Douglas Thompson   drivers/edac: spl...
806

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

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

1eef12825   Mauro Carvalho Chehab   amd64_edac: Corre...
813
  			total_pages += dimm->nr_pages;
a895bf8b1   Mauro Carvalho Chehab   edac: move nr_pag...
814
  		}
7c9281d76   Douglas Thompson   drivers/edac: spl...
815
  	}
079708b91   Douglas Thompson   drivers/edac: cor...
816
817
  	return sprintf(data, "%u
  ", PAGES_TO_MiB(total_pages));
7c9281d76   Douglas Thompson   drivers/edac: spl...
818
  }
8ad6c78a6   Mauro Carvalho Chehab   edac: add a sysfs...
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
  static ssize_t mci_max_location_show(struct device *dev,
  				     struct device_attribute *mattr,
  				     char *data)
  {
  	struct mem_ctl_info *mci = to_mci(dev);
  	int i;
  	char *p = data;
  
  	for (i = 0; i < mci->n_layers; i++) {
  		p += sprintf(p, "%s %d ",
  			     edac_layer_name[mci->layers[i].type],
  			     mci->layers[i].size - 1);
  	}
  
  	return p - data;
  }
7c9281d76   Douglas Thompson   drivers/edac: spl...
835
  /* default Control file */
f11135d87   Borislav Petkov   EDAC: edac_mc_sys...
836
  static DEVICE_ATTR(reset_counters, S_IWUSR, NULL, mci_reset_counters_store);
7c9281d76   Douglas Thompson   drivers/edac: spl...
837
838
  
  /* default Attribute files */
f11135d87   Borislav Petkov   EDAC: edac_mc_sys...
839
840
841
842
843
844
845
846
  static DEVICE_ATTR(mc_name, S_IRUGO, mci_ctl_name_show, NULL);
  static DEVICE_ATTR(size_mb, S_IRUGO, mci_size_mb_show, NULL);
  static DEVICE_ATTR(seconds_since_reset, S_IRUGO, mci_seconds_show, NULL);
  static DEVICE_ATTR(ue_noinfo_count, S_IRUGO, mci_ue_noinfo_show, NULL);
  static DEVICE_ATTR(ce_noinfo_count, S_IRUGO, mci_ce_noinfo_show, NULL);
  static DEVICE_ATTR(ue_count, S_IRUGO, mci_ue_count_show, NULL);
  static DEVICE_ATTR(ce_count, S_IRUGO, mci_ce_count_show, NULL);
  static DEVICE_ATTR(max_location, S_IRUGO, mci_max_location_show, NULL);
7c9281d76   Douglas Thompson   drivers/edac: spl...
847
848
  
  /* memory scrubber attribute file */
628ea92f0   Ben Dooks   EDAC: Make dev_at...
849
  static DEVICE_ATTR(sdram_scrub_rate, 0, mci_sdram_scrub_rate_show,
2c1946b6d   Takashi Iwai   EDAC: Use static ...
850
  	    mci_sdram_scrub_rate_store); /* umode set later in is_visible */
7c9281d76   Douglas Thompson   drivers/edac: spl...
851

7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
852
853
854
855
856
857
858
859
860
  static struct attribute *mci_attrs[] = {
  	&dev_attr_reset_counters.attr,
  	&dev_attr_mc_name.attr,
  	&dev_attr_size_mb.attr,
  	&dev_attr_seconds_since_reset.attr,
  	&dev_attr_ue_noinfo_count.attr,
  	&dev_attr_ce_noinfo_count.attr,
  	&dev_attr_ue_count.attr,
  	&dev_attr_ce_count.attr,
8ad6c78a6   Mauro Carvalho Chehab   edac: add a sysfs...
861
  	&dev_attr_max_location.attr,
2c1946b6d   Takashi Iwai   EDAC: Use static ...
862
  	&dev_attr_sdram_scrub_rate.attr,
7c9281d76   Douglas Thompson   drivers/edac: spl...
863
864
  	NULL
  };
2c1946b6d   Takashi Iwai   EDAC: Use static ...
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
  static umode_t mci_attr_is_visible(struct kobject *kobj,
  				   struct attribute *attr, int idx)
  {
  	struct device *dev = kobj_to_dev(kobj);
  	struct mem_ctl_info *mci = to_mci(dev);
  	umode_t mode = 0;
  
  	if (attr != &dev_attr_sdram_scrub_rate.attr)
  		return attr->mode;
  	if (mci->get_sdram_scrub_rate)
  		mode |= S_IRUGO;
  	if (mci->set_sdram_scrub_rate)
  		mode |= S_IWUSR;
  	return mode;
  }
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
880
881
  static struct attribute_group mci_attr_grp = {
  	.attrs	= mci_attrs,
2c1946b6d   Takashi Iwai   EDAC: Use static ...
882
  	.is_visible = mci_attr_is_visible,
cc301b3ae   Mauro Carvalho Chehab   edac: store/show ...
883
  };
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
884
885
886
  static const struct attribute_group *mci_attr_groups[] = {
  	&mci_attr_grp,
  	NULL
cc301b3ae   Mauro Carvalho Chehab   edac: store/show ...
887
  };
de3910eb7   Mauro Carvalho Chehab   edac: change the ...
888
  static void mci_attr_release(struct device *dev)
42a8e397a   Douglas Thompson   drivers/edac: add...
889
  {
de3910eb7   Mauro Carvalho Chehab   edac: change the ...
890
  	struct mem_ctl_info *mci = container_of(dev, struct mem_ctl_info, dev);
956b9ba15   Joe Perches   edac: Convert deb...
891
892
  	edac_dbg(1, "Releasing csrow device %s
  ", dev_name(dev));
de3910eb7   Mauro Carvalho Chehab   edac: change the ...
893
  	kfree(mci);
42a8e397a   Douglas Thompson   drivers/edac: add...
894
  }
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
895
896
897
898
  static struct device_type mci_attr_type = {
  	.groups		= mci_attr_groups,
  	.release	= mci_attr_release,
  };
8096cfafb   Doug Thompson   drivers/edac: fix...
899

8096cfafb   Doug Thompson   drivers/edac: fix...
900
  /*
7c9281d76   Douglas Thompson   drivers/edac: spl...
901
902
903
904
905
906
907
   * Create a new Memory Controller kobject instance,
   *	mc<id> under the 'mc' directory
   *
   * Return:
   *	0	Success
   *	!0	Failure
   */
4e8d230de   Takashi Iwai   EDAC: Allow to pa...
908
909
  int edac_create_sysfs_mci_device(struct mem_ctl_info *mci,
  				 const struct attribute_group **groups)
7c9281d76   Douglas Thompson   drivers/edac: spl...
910
  {
12e26969b   Borislav Petkov   EDAC, mc_sysfs: F...
911
  	char *name;
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
912
  	int i, err;
7c9281d76   Douglas Thompson   drivers/edac: spl...
913

de3910eb7   Mauro Carvalho Chehab   edac: change the ...
914
915
916
917
  	/*
  	 * The memory controller needs its own bus, in order to avoid
  	 * namespace conflicts at /sys/bus/edac.
  	 */
12e26969b   Borislav Petkov   EDAC, mc_sysfs: F...
918
919
  	name = kasprintf(GFP_KERNEL, "mc%d", mci->mc_idx);
  	if (!name)
de3910eb7   Mauro Carvalho Chehab   edac: change the ...
920
  		return -ENOMEM;
88d84ac97   Borislav Petkov   EDAC: Fix lockdep...
921

12e26969b   Borislav Petkov   EDAC, mc_sysfs: F...
922
  	mci->bus->name = name;
88d84ac97   Borislav Petkov   EDAC: Fix lockdep...
923
924
925
926
  	edac_dbg(0, "creating bus %s
  ", mci->bus->name);
  
  	err = bus_register(mci->bus);
12e26969b   Borislav Petkov   EDAC, mc_sysfs: F...
927
928
929
930
  	if (err < 0) {
  		kfree(name);
  		return err;
  	}
7c9281d76   Douglas Thompson   drivers/edac: spl...
931

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

de3910eb7   Mauro Carvalho Chehab   edac: change the ...
936
  	mci->dev.parent = mci_pdev;
88d84ac97   Borislav Petkov   EDAC: Fix lockdep...
937
  	mci->dev.bus = mci->bus;
4e8d230de   Takashi Iwai   EDAC: Allow to pa...
938
  	mci->dev.groups = groups;
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
939
940
941
  	dev_set_name(&mci->dev, "mc%d", mci->mc_idx);
  	dev_set_drvdata(&mci->dev, mci);
  	pm_runtime_forbid(&mci->dev);
956b9ba15   Joe Perches   edac: Convert deb...
942
943
  	edac_dbg(0, "creating device %s
  ", dev_name(&mci->dev));
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
944
945
  	err = device_add(&mci->dev);
  	if (err < 0) {
3d958823e   Mauro Carvalho Chehab   edac: better repo...
946
947
  		edac_dbg(1, "failure: create device %s
  ", dev_name(&mci->dev));
1bf1950c4   Junjie Mao   EDAC: Fix the lea...
948
  		goto fail_unregister_bus;
42a8e397a   Douglas Thompson   drivers/edac: add...
949
  	}
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
950
951
  	/*
  	 * Create the dimm/rank devices
7c9281d76   Douglas Thompson   drivers/edac: spl...
952
  	 */
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
953
  	for (i = 0; i < mci->tot_dimms; i++) {
de3910eb7   Mauro Carvalho Chehab   edac: change the ...
954
  		struct dimm_info *dimm = mci->dimms[i];
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
955
  		/* Only expose populated DIMMs */
1bf1950c4   Junjie Mao   EDAC: Fix the lea...
956
  		if (!dimm->nr_pages)
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
957
  			continue;
1bf1950c4   Junjie Mao   EDAC: Fix the lea...
958

7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
959
  #ifdef CONFIG_EDAC_DEBUG
956b9ba15   Joe Perches   edac: Convert deb...
960
  		edac_dbg(1, "creating dimm%d, located at ", i);
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
961
962
963
964
965
966
967
968
  		if (edac_debug_level >= 1) {
  			int lay;
  			for (lay = 0; lay < mci->n_layers; lay++)
  				printk(KERN_CONT "%s %d ",
  					edac_layer_name[mci->layers[lay].type],
  					dimm->location[lay]);
  			printk(KERN_CONT "
  ");
7c9281d76   Douglas Thompson   drivers/edac: spl...
969
  		}
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
970
  #endif
199747106   Mauro Carvalho Chehab   edac: add a new p...
971
972
  		err = edac_create_dimm_object(mci, dimm, i);
  		if (err) {
956b9ba15   Joe Perches   edac: Convert deb...
973
974
  			edac_dbg(1, "failure: create dimm %d obj
  ", i);
1bf1950c4   Junjie Mao   EDAC: Fix the lea...
975
  			goto fail_unregister_dimm;
199747106   Mauro Carvalho Chehab   edac: add a new p...
976
  		}
7c9281d76   Douglas Thompson   drivers/edac: spl...
977
  	}
199747106   Mauro Carvalho Chehab   edac: add a new p...
978
  #ifdef CONFIG_EDAC_LEGACY_SYSFS
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
979
980
  	err = edac_create_csrow_objects(mci);
  	if (err < 0)
1bf1950c4   Junjie Mao   EDAC: Fix the lea...
981
  		goto fail_unregister_dimm;
199747106   Mauro Carvalho Chehab   edac: add a new p...
982
  #endif
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
983

7ac8bf9bc   Borislav Petkov   EDAC: Carve out d...
984
  	edac_create_debugfs_nodes(mci);
7c9281d76   Douglas Thompson   drivers/edac: spl...
985
  	return 0;
1bf1950c4   Junjie Mao   EDAC: Fix the lea...
986
  fail_unregister_dimm:
079708b91   Douglas Thompson   drivers/edac: cor...
987
  	for (i--; i >= 0; i--) {
de3910eb7   Mauro Carvalho Chehab   edac: change the ...
988
  		struct dimm_info *dimm = mci->dimms[i];
1bf1950c4   Junjie Mao   EDAC: Fix the lea...
989
  		if (!dimm->nr_pages)
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
990
  			continue;
1bf1950c4   Junjie Mao   EDAC: Fix the lea...
991

44d22e240   Lans Zhang   EDAC: Cleanup dev...
992
  		device_unregister(&dimm->dev);
7c9281d76   Douglas Thompson   drivers/edac: spl...
993
  	}
44d22e240   Lans Zhang   EDAC: Cleanup dev...
994
  	device_unregister(&mci->dev);
1bf1950c4   Junjie Mao   EDAC: Fix the lea...
995
  fail_unregister_bus:
88d84ac97   Borislav Petkov   EDAC: Fix lockdep...
996
  	bus_unregister(mci->bus);
12e26969b   Borislav Petkov   EDAC, mc_sysfs: F...
997
  	kfree(name);
7c9281d76   Douglas Thompson   drivers/edac: spl...
998
999
1000
1001
1002
1003
1004
1005
  	return err;
  }
  
  /*
   * remove a Memory Controller instance
   */
  void edac_remove_sysfs_mci_device(struct mem_ctl_info *mci)
  {
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
1006
  	int i;
7c9281d76   Douglas Thompson   drivers/edac: spl...
1007

956b9ba15   Joe Perches   edac: Convert deb...
1008
1009
  	edac_dbg(0, "
  ");
7c9281d76   Douglas Thompson   drivers/edac: spl...
1010

452a6bf95   Mauro Carvalho Chehab   edac: Add debufs ...
1011
  #ifdef CONFIG_EDAC_DEBUG
30f84a891   Tan Xiaojun   EDAC: Use edac_de...
1012
  	edac_debugfs_remove_recursive(mci->debugfs);
452a6bf95   Mauro Carvalho Chehab   edac: Add debufs ...
1013
  #endif
199747106   Mauro Carvalho Chehab   edac: add a new p...
1014
  #ifdef CONFIG_EDAC_LEGACY_SYSFS
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
1015
  	edac_delete_csrow_objects(mci);
199747106   Mauro Carvalho Chehab   edac: add a new p...
1016
  #endif
7c9281d76   Douglas Thompson   drivers/edac: spl...
1017

7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
1018
  	for (i = 0; i < mci->tot_dimms; i++) {
de3910eb7   Mauro Carvalho Chehab   edac: change the ...
1019
  		struct dimm_info *dimm = mci->dimms[i];
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
1020
1021
  		if (dimm->nr_pages == 0)
  			continue;
956b9ba15   Joe Perches   edac: Convert deb...
1022
1023
  		edac_dbg(0, "removing device %s
  ", dev_name(&dimm->dev));
44d22e240   Lans Zhang   EDAC: Cleanup dev...
1024
  		device_unregister(&dimm->dev);
6fe1108f1   Mauro Carvalho Chehab   edac_core: Do a b...
1025
  	}
7c9281d76   Douglas Thompson   drivers/edac: spl...
1026
  }
8096cfafb   Doug Thompson   drivers/edac: fix...
1027

7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
1028
1029
  void edac_unregister_sysfs(struct mem_ctl_info *mci)
  {
ab67b6c22   Tony Luck   EDAC: Fix used af...
1030
  	struct bus_type *bus = mci->bus;
12e26969b   Borislav Petkov   EDAC, mc_sysfs: F...
1031
  	const char *name = mci->bus->name;
956b9ba15   Joe Perches   edac: Convert deb...
1032
1033
  	edac_dbg(1, "Unregistering device %s
  ", dev_name(&mci->dev));
44d22e240   Lans Zhang   EDAC: Cleanup dev...
1034
  	device_unregister(&mci->dev);
ab67b6c22   Tony Luck   EDAC: Fix used af...
1035
  	bus_unregister(bus);
12e26969b   Borislav Petkov   EDAC, mc_sysfs: F...
1036
  	kfree(name);
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
1037
  }
8096cfafb   Doug Thompson   drivers/edac: fix...
1038

de3910eb7   Mauro Carvalho Chehab   edac: change the ...
1039
  static void mc_attr_release(struct device *dev)
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
1040
  {
de3910eb7   Mauro Carvalho Chehab   edac: change the ...
1041
1042
1043
1044
1045
  	/*
  	 * There's no container structure here, as this is just the mci
  	 * parent device, used to create the /sys/devices/mc sysfs node.
  	 * So, there are no attributes on it.
  	 */
956b9ba15   Joe Perches   edac: Convert deb...
1046
1047
  	edac_dbg(1, "Releasing device %s
  ", dev_name(dev));
de3910eb7   Mauro Carvalho Chehab   edac: change the ...
1048
  	kfree(dev);
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
1049
  }
8096cfafb   Doug Thompson   drivers/edac: fix...
1050

7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
1051
1052
1053
  static struct device_type mc_attr_type = {
  	.release	= mc_attr_release,
  };
8096cfafb   Doug Thompson   drivers/edac: fix...
1054
  /*
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
1055
   * Init/exit code for the module. Basically, creates/removes /sys/class/rc
8096cfafb   Doug Thompson   drivers/edac: fix...
1056
   */
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
1057
  int __init edac_mc_sysfs_init(void)
8096cfafb   Doug Thompson   drivers/edac: fix...
1058
  {
7a623c039   Mauro Carvalho Chehab   edac: rewrite the...
1059
  	int err;
8096cfafb   Doug Thompson   drivers/edac: fix...
1060

de3910eb7   Mauro Carvalho Chehab   edac: change the ...
1061
  	mci_pdev = kzalloc(sizeof(*mci_pdev), GFP_KERNEL);
2d56b109e   Denis Kirjanov   EDAC: Handle erro...
1062
1063
  	if (!mci_pdev) {
  		err = -ENOMEM;
733476cf2   Borislav Petkov   EDAC: Rip out the...
1064
  		goto out;
2d56b109e   Denis Kirjanov   EDAC: Handle erro...
1065
  	}
de3910eb7   Mauro Carvalho Chehab   edac: change the ...
1066

d4538000c   Borislav Petkov   EDAC: Remove edac...
1067
  	mci_pdev->bus = edac_get_sysfs_subsys();
de3910eb7   Mauro Carvalho Chehab   edac: change the ...
1068
1069
1070
  	mci_pdev->type = &mc_attr_type;
  	device_initialize(mci_pdev);
  	dev_set_name(mci_pdev, "mc");
8096cfafb   Doug Thompson   drivers/edac: fix...
1071

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

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

8096cfafb   Doug Thompson   drivers/edac: fix...
1079
  	return 0;
2d56b109e   Denis Kirjanov   EDAC: Handle erro...
1080
1081
1082
  
   out_dev_free:
  	kfree(mci_pdev);
2d56b109e   Denis Kirjanov   EDAC: Handle erro...
1083
1084
   out:
  	return err;
8096cfafb   Doug Thompson   drivers/edac: fix...
1085
  }
c6b97bcf8   Alexey Khoroshilov   EDAC: Properly un...
1086
  void edac_mc_sysfs_exit(void)
8096cfafb   Doug Thompson   drivers/edac: fix...
1087
  {
44d22e240   Lans Zhang   EDAC: Cleanup dev...
1088
  	device_unregister(mci_pdev);
8096cfafb   Doug Thompson   drivers/edac: fix...
1089
  }