Commit 7a623c039075e4ea21648d88133fafa6dcfd113d

Authored by Mauro Carvalho Chehab
1 parent b0610bb82a

edac: rewrite the sysfs code to use struct device

The EDAC subsystem uses the old struct sysdev approach,
creating all nodes using the raw sysfs API. This is bad,
as the API is deprecated.

As we'll be changing the EDAC API, let's first port the existing
code to struct device.

There's one drawback on this patch: driver-specific sysfs
nodes, used by mpc85xx_edac, amd64_edac and i7core_edac
 won't be created anymore. While it would be possible to
also port the device-specific code, that would mix kobj with
struct device, with is not recommended. Also, it is easier and nicer
to move the code to the drivers, instead, as the core can get rid
of some complex logic that just emulates what the device_add()
and device_create_file() already does.

The next patches will convert the driver-specific code to use
the device-specific calls. Then, the remaining bits of the old
sysfs API will be removed.

NOTE: a per-MC bus is required, otherwise devices with more than
one memory controller will hit a bug like the one below:

[  819.094946] EDAC DEBUG: find_mci_by_dev: find_mci_by_dev()
[  819.094948] EDAC DEBUG: edac_create_sysfs_mci_device: edac_create_sysfs_mci_device() idx=1
[  819.094952] EDAC DEBUG: edac_create_sysfs_mci_device: edac_create_sysfs_mci_device(): creating device mc1
[  819.094967] EDAC DEBUG: edac_create_sysfs_mci_device: edac_create_sysfs_mci_device creating dimm0, located at channel 0 slot 0
[  819.094984] ------------[ cut here ]------------
[  819.100142] WARNING: at fs/sysfs/dir.c:481 sysfs_add_one+0xc1/0xf0()
[  819.107282] Hardware name: S2600CP
[  819.111078] sysfs: cannot create duplicate filename '/bus/edac/devices/dimm0'
[  819.119062] Modules linked in: sb_edac(+) edac_core ip6table_filter ip6_tables ebtable_nat ebtables ipt_MASQUERADE iptable_nat nf_nat nf_conntrack_ipv4 nf_defrag_ipv4 xt_state nf_conntrack ipt_REJECT xt_CHECKSUM iptable_mangle iptable_filter ip_tables bridge stp llc sunrpc binfmt_misc dm_mirror dm_region_hash dm_log vhost_net macvtap macvlan tun kvm microcode pcspkr iTCO_wdt iTCO_vendor_support igb i2c_i801 i2c_core sg ioatdma dca sr_mod cdrom sd_mod crc_t10dif ahci libahci isci libsas libata scsi_transport_sas scsi_mod wmi dm_mod [last unloaded: scsi_wait_scan]
[  819.175748] Pid: 10902, comm: modprobe Not tainted 3.3.0-0.11.el7.v12.2.x86_64 #1
[  819.184113] Call Trace:
[  819.186868]  [<ffffffff8105adaf>] warn_slowpath_common+0x7f/0xc0
[  819.193573]  [<ffffffff8105aea6>] warn_slowpath_fmt+0x46/0x50
[  819.200000]  [<ffffffff811f53d1>] sysfs_add_one+0xc1/0xf0
[  819.206025]  [<ffffffff811f5cf5>] sysfs_do_create_link+0x135/0x220
[  819.212944]  [<ffffffff811f7023>] ? sysfs_create_group+0x13/0x20
[  819.219656]  [<ffffffff811f5df3>] sysfs_create_link+0x13/0x20
[  819.226109]  [<ffffffff813b04f6>] bus_add_device+0xe6/0x1b0
[  819.232350]  [<ffffffff813ae7cb>] device_add+0x2db/0x460
[  819.238300]  [<ffffffffa0325634>] edac_create_dimm_object+0x84/0xf0 [edac_core]
[  819.246460]  [<ffffffffa0325e18>] edac_create_sysfs_mci_device+0xe8/0x290 [edac_core]
[  819.255215]  [<ffffffffa0322e2a>] edac_mc_add_mc+0x5a/0x2c0 [edac_core]
[  819.262611]  [<ffffffffa03412df>] sbridge_register_mci+0x1bc/0x279 [sb_edac]
[  819.270493]  [<ffffffffa03417a3>] sbridge_probe+0xef/0x175 [sb_edac]
[  819.277630]  [<ffffffff813ba4e8>] ? pm_runtime_enable+0x58/0x90
[  819.284268]  [<ffffffff812f430c>] local_pci_probe+0x5c/0xd0
[  819.290508]  [<ffffffff812f5ba1>] __pci_device_probe+0xf1/0x100
[  819.297117]  [<ffffffff812f5bea>] pci_device_probe+0x3a/0x60
[  819.303457]  [<ffffffff813b1003>] really_probe+0x73/0x270
[  819.309496]  [<ffffffff813b138e>] driver_probe_device+0x4e/0xb0
[  819.316104]  [<ffffffff813b149b>] __driver_attach+0xab/0xb0
[  819.322337]  [<ffffffff813b13f0>] ? driver_probe_device+0xb0/0xb0
[  819.329151]  [<ffffffff813af5d6>] bus_for_each_dev+0x56/0x90
[  819.335489]  [<ffffffff813b0d7e>] driver_attach+0x1e/0x20
[  819.341534]  [<ffffffff813b0980>] bus_add_driver+0x1b0/0x2a0
[  819.347884]  [<ffffffffa0347000>] ? 0xffffffffa0346fff
[  819.353641]  [<ffffffff813b19f6>] driver_register+0x76/0x140
[  819.359980]  [<ffffffff8159f18b>] ? printk+0x51/0x53
[  819.365524]  [<ffffffffa0347000>] ? 0xffffffffa0346fff
[  819.371291]  [<ffffffff812f5896>] __pci_register_driver+0x56/0xd0
[  819.378096]  [<ffffffffa0347054>] sbridge_init+0x54/0x1000 [sb_edac]
[  819.385231]  [<ffffffff8100203f>] do_one_initcall+0x3f/0x170
[  819.391577]  [<ffffffff810bcd2e>] sys_init_module+0xbe/0x230
[  819.397926]  [<ffffffff815bb529>] system_call_fastpath+0x16/0x1b
[  819.404633] ---[ end trace 1654fdd39556689f ]---

This happens because the bus is not being properly initialized.
Instead of putting the memory sub-devices inside the memory controller,
it is putting everything under the same directory:

$ tree /sys/bus/edac/
/sys/bus/edac/
├── devices
│   ├── all_channel_counts -> ../../../devices/system/edac/mc/mc0/all_channel_counts
│   ├── csrow0 -> ../../../devices/system/edac/mc/mc0/csrow0
│   ├── csrow1 -> ../../../devices/system/edac/mc/mc0/csrow1
│   ├── csrow2 -> ../../../devices/system/edac/mc/mc0/csrow2
│   ├── dimm0 -> ../../../devices/system/edac/mc/mc0/dimm0
│   ├── dimm1 -> ../../../devices/system/edac/mc/mc0/dimm1
│   ├── dimm3 -> ../../../devices/system/edac/mc/mc0/dimm3
│   ├── dimm6 -> ../../../devices/system/edac/mc/mc0/dimm6
│   ├── inject_addrmatch -> ../../../devices/system/edac/mc/mc0/inject_addrmatch
│   ├── mc -> ../../../devices/system/edac/mc
│   └── mc0 -> ../../../devices/system/edac/mc/mc0
├── drivers
├── drivers_autoprobe
├── drivers_probe
└── uevent

On a multi-memory controller system, the names "csrow%d" and "dimm%d"
should be under "mc%d", and not at the main hierarchy level.

So, we need to create a per-MC bus, in order to have its own namespace.

Reviewed-by: Aristeu Rozanski <arozansk@redhat.com>
Cc: Doug Thompson <norsk5@yahoo.com>
Cc: Greg K H <gregkh@linuxfoundation.org>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>

Showing 5 changed files with 450 additions and 706 deletions Side-by-side Diff

drivers/edac/edac_mc.c
... ... @@ -218,7 +218,7 @@
218 218 unsigned size, tot_dimms = 1, count = 1;
219 219 unsigned tot_csrows = 1, tot_channels = 1, tot_errcount = 0;
220 220 void *pvt, *p, *ptr = NULL;
221   - int i, j, err, row, chn, n, len;
  221 + int i, j, row, chn, n, len;
222 222 bool per_rank = false;
223 223  
224 224 BUG_ON(n_layers > EDAC_MAX_LAYERS || n_layers == 0);
... ... @@ -374,15 +374,6 @@
374 374 mci->op_state = OP_ALLOC;
375 375 INIT_LIST_HEAD(&mci->grp_kobj_list);
376 376  
377   - /*
378   - * Initialize the 'root' kobj for the edac_mc controller
379   - */
380   - err = edac_mc_register_sysfs_main_kobj(mci);
381   - if (err) {
382   - kfree(mci);
383   - return NULL;
384   - }
385   -
386 377 /* at this point, the root kobj is valid, and in order to
387 378 * 'free' the object, then the function:
388 379 * edac_mc_unregister_sysfs_main_kobj() must be called
... ... @@ -403,7 +394,7 @@
403 394 {
404 395 debugf1("%s()\n", __func__);
405 396  
406   - edac_mc_unregister_sysfs_main_kobj(mci);
  397 + edac_unregister_sysfs(mci);
407 398  
408 399 /* free the mci instance memory here */
409 400 kfree(mci);
drivers/edac/edac_mc_sysfs.c
Changes suppressed. Click to show
... ... @@ -7,17 +7,20 @@
7 7 *
8 8 * Written Doug Thompson <norsk5@xmission.com> www.softwarebitmaker.com
9 9 *
  10 + * (c) 2012 - Mauro Carvalho Chehab <mchehab@redhat.com>
  11 + * The entire API were re-written, and ported to use struct device
  12 + *
10 13 */
11 14  
12 15 #include <linux/ctype.h>
13 16 #include <linux/slab.h>
14 17 #include <linux/edac.h>
15 18 #include <linux/bug.h>
  19 +#include <linux/pm_runtime.h>
16 20  
17 21 #include "edac_core.h"
18 22 #include "edac_module.h"
19 23  
20   -
21 24 /* MC EDAC Controls, setable by module parameter, and sysfs */
22 25 static int edac_mc_log_ue = 1;
23 26 static int edac_mc_log_ce = 1;
... ... @@ -78,6 +81,8 @@
78 81 &edac_mc_poll_msec, 0644);
79 82 MODULE_PARM_DESC(edac_mc_poll_msec, "Polling period in milliseconds");
80 83  
  84 +static struct device mci_pdev;
  85 +
81 86 /*
82 87 * various constants for Memory Controllers
83 88 */
84 89  
85 90  
86 91  
87 92  
88 93  
89 94  
90 95  
91 96  
92 97  
93 98  
94 99  
95 100  
96 101  
97 102  
98 103  
99 104  
100 105  
101 106  
102 107  
103 108  
104 109  
105 110  
106 111  
107 112  
108 113  
109 114  
110 115  
111 116  
112 117  
113 118  
114 119  
115 120  
116 121  
117 122  
118 123  
119 124  
120 125  
121 126  
122 127  
123 128  
124 129  
125 130  
126 131  
127 132  
128 133  
129 134  
130 135  
131 136  
132 137  
133 138  
134 139  
135 140  
136 141  
137 142  
138 143  
139 144  
140 145  
141 146  
142 147  
143 148  
144 149  
145 150  
146 151  
147 152  
... ... @@ -125,308 +130,336 @@
125 130 [EDAC_S16ECD16ED] = "S16ECD16ED"
126 131 };
127 132  
128   -/* EDAC sysfs CSROW data structures and methods
  133 +/*
  134 + * EDAC sysfs CSROW data structures and methods
129 135 */
130 136  
  137 +#define to_csrow(k) container_of(k, struct csrow_info, dev)
  138 +
  139 +/*
  140 + * We need it to avoid namespace conflicts between the legacy API
  141 + * and the per-dimm/per-rank one
  142 + */
  143 +#define DEVICE_ATTR_LEGACY(_name, _mode, _show, _store) \
  144 + struct device_attribute dev_attr_legacy_##_name = __ATTR(_name, _mode, _show, _store)
  145 +
  146 +struct dev_ch_attribute {
  147 + struct device_attribute attr;
  148 + int channel;
  149 +};
  150 +
  151 +#define DEVICE_CHANNEL(_name, _mode, _show, _store, _var) \
  152 + struct dev_ch_attribute dev_attr_legacy_##_name = \
  153 + { __ATTR(_name, _mode, _show, _store), (_var) }
  154 +
  155 +#define to_channel(k) (container_of(k, struct dev_ch_attribute, attr)->channel)
  156 +
131 157 /* Set of more default csrow<id> attribute show/store functions */
132   -static ssize_t csrow_ue_count_show(struct csrow_info *csrow, char *data,
133   - int private)
  158 +static ssize_t csrow_ue_count_show(struct device *dev,
  159 + struct device_attribute *mattr, char *data)
134 160 {
  161 + struct csrow_info *csrow = to_csrow(dev);
  162 +
135 163 return sprintf(data, "%u\n", csrow->ue_count);
136 164 }
137 165  
138   -static ssize_t csrow_ce_count_show(struct csrow_info *csrow, char *data,
139   - int private)
  166 +static ssize_t csrow_ce_count_show(struct device *dev,
  167 + struct device_attribute *mattr, char *data)
140 168 {
  169 + struct csrow_info *csrow = to_csrow(dev);
  170 +
141 171 return sprintf(data, "%u\n", csrow->ce_count);
142 172 }
143 173  
144   -static ssize_t csrow_size_show(struct csrow_info *csrow, char *data,
145   - int private)
  174 +static ssize_t csrow_size_show(struct device *dev,
  175 + struct device_attribute *mattr, char *data)
146 176 {
  177 + struct csrow_info *csrow = to_csrow(dev);
147 178 int i;
148 179 u32 nr_pages = 0;
149 180  
150 181 for (i = 0; i < csrow->nr_channels; i++)
151 182 nr_pages += csrow->channels[i].dimm->nr_pages;
152   -
153 183 return sprintf(data, "%u\n", PAGES_TO_MiB(nr_pages));
154 184 }
155 185  
156   -static ssize_t csrow_mem_type_show(struct csrow_info *csrow, char *data,
157   - int private)
  186 +static ssize_t csrow_mem_type_show(struct device *dev,
  187 + struct device_attribute *mattr, char *data)
158 188 {
  189 + struct csrow_info *csrow = to_csrow(dev);
  190 +
159 191 return sprintf(data, "%s\n", mem_types[csrow->channels[0].dimm->mtype]);
160 192 }
161 193  
162   -static ssize_t csrow_dev_type_show(struct csrow_info *csrow, char *data,
163   - int private)
  194 +static ssize_t csrow_dev_type_show(struct device *dev,
  195 + struct device_attribute *mattr, char *data)
164 196 {
  197 + struct csrow_info *csrow = to_csrow(dev);
  198 +
165 199 return sprintf(data, "%s\n", dev_types[csrow->channels[0].dimm->dtype]);
166 200 }
167 201  
168   -static ssize_t csrow_edac_mode_show(struct csrow_info *csrow, char *data,
169   - int private)
  202 +static ssize_t csrow_edac_mode_show(struct device *dev,
  203 + struct device_attribute *mattr,
  204 + char *data)
170 205 {
  206 + struct csrow_info *csrow = to_csrow(dev);
  207 +
171 208 return sprintf(data, "%s\n", edac_caps[csrow->channels[0].dimm->edac_mode]);
172 209 }
173 210  
174 211 /* show/store functions for DIMM Label attributes */
175   -static ssize_t channel_dimm_label_show(struct csrow_info *csrow,
176   - char *data, int channel)
  212 +static ssize_t channel_dimm_label_show(struct device *dev,
  213 + struct device_attribute *mattr,
  214 + char *data)
177 215 {
  216 + struct csrow_info *csrow = to_csrow(dev);
  217 + unsigned chan = to_channel(mattr);
  218 + struct rank_info *rank = &csrow->channels[chan];
  219 +
178 220 /* if field has not been initialized, there is nothing to send */
179   - if (!csrow->channels[channel].dimm->label[0])
  221 + if (!rank->dimm->label[0])
180 222 return 0;
181 223  
182 224 return snprintf(data, EDAC_MC_LABEL_LEN, "%s\n",
183   - csrow->channels[channel].dimm->label);
  225 + rank->dimm->label);
184 226 }
185 227  
186   -static ssize_t channel_dimm_label_store(struct csrow_info *csrow,
187   - const char *data,
188   - size_t count, int channel)
  228 +static ssize_t channel_dimm_label_store(struct device *dev,
  229 + struct device_attribute *mattr,
  230 + const char *data, size_t count)
189 231 {
  232 + struct csrow_info *csrow = to_csrow(dev);
  233 + unsigned chan = to_channel(mattr);
  234 + struct rank_info *rank = &csrow->channels[chan];
  235 +
190 236 ssize_t max_size = 0;
191 237  
192 238 max_size = min((ssize_t) count, (ssize_t) EDAC_MC_LABEL_LEN - 1);
193   - strncpy(csrow->channels[channel].dimm->label, data, max_size);
194   - csrow->channels[channel].dimm->label[max_size] = '\0';
  239 + strncpy(rank->dimm->label, data, max_size);
  240 + rank->dimm->label[max_size] = '\0';
195 241  
196 242 return max_size;
197 243 }
198 244  
199 245 /* show function for dynamic chX_ce_count attribute */
200   -static ssize_t channel_ce_count_show(struct csrow_info *csrow,
201   - char *data, int channel)
  246 +static ssize_t channel_ce_count_show(struct device *dev,
  247 + struct device_attribute *mattr, char *data)
202 248 {
203   - return sprintf(data, "%u\n", csrow->channels[channel].ce_count);
  249 + struct csrow_info *csrow = to_csrow(dev);
  250 + unsigned chan = to_channel(mattr);
  251 + struct rank_info *rank = &csrow->channels[chan];
  252 +
  253 + return sprintf(data, "%u\n", rank->ce_count);
204 254 }
205 255  
206   -/* csrow specific attribute structure */
207   -struct csrowdev_attribute {
208   - struct attribute attr;
209   - ssize_t(*show) (struct csrow_info *, char *, int);
210   - ssize_t(*store) (struct csrow_info *, const char *, size_t, int);
211   - int private;
  256 +/* cwrow<id>/attribute files */
  257 +DEVICE_ATTR_LEGACY(size_mb, S_IRUGO, csrow_size_show, NULL);
  258 +DEVICE_ATTR_LEGACY(dev_type, S_IRUGO, csrow_dev_type_show, NULL);
  259 +DEVICE_ATTR_LEGACY(mem_type, S_IRUGO, csrow_mem_type_show, NULL);
  260 +DEVICE_ATTR_LEGACY(edac_mode, S_IRUGO, csrow_edac_mode_show, NULL);
  261 +DEVICE_ATTR_LEGACY(ue_count, S_IRUGO, csrow_ue_count_show, NULL);
  262 +DEVICE_ATTR_LEGACY(ce_count, S_IRUGO, csrow_ce_count_show, NULL);
  263 +
  264 +/* default attributes of the CSROW<id> object */
  265 +static struct attribute *csrow_attrs[] = {
  266 + &dev_attr_legacy_dev_type.attr,
  267 + &dev_attr_legacy_mem_type.attr,
  268 + &dev_attr_legacy_edac_mode.attr,
  269 + &dev_attr_legacy_size_mb.attr,
  270 + &dev_attr_legacy_ue_count.attr,
  271 + &dev_attr_legacy_ce_count.attr,
  272 + NULL,
212 273 };
213 274  
214   -#define to_csrow(k) container_of(k, struct csrow_info, kobj)
215   -#define to_csrowdev_attr(a) container_of(a, struct csrowdev_attribute, attr)
  275 +static struct attribute_group csrow_attr_grp = {
  276 + .attrs = csrow_attrs,
  277 +};
216 278  
217   -/* Set of show/store higher level functions for default csrow attributes */
218   -static ssize_t csrowdev_show(struct kobject *kobj,
219   - struct attribute *attr, char *buffer)
220   -{
221   - struct csrow_info *csrow = to_csrow(kobj);
222   - struct csrowdev_attribute *csrowdev_attr = to_csrowdev_attr(attr);
  279 +static const struct attribute_group *csrow_attr_groups[] = {
  280 + &csrow_attr_grp,
  281 + NULL
  282 +};
223 283  
224   - if (csrowdev_attr->show)
225   - return csrowdev_attr->show(csrow,
226   - buffer, csrowdev_attr->private);
227   - return -EIO;
228   -}
229   -
230   -static ssize_t csrowdev_store(struct kobject *kobj, struct attribute *attr,
231   - const char *buffer, size_t count)
  284 +static void csrow_attr_release(struct device *device)
232 285 {
233   - struct csrow_info *csrow = to_csrow(kobj);
234   - struct csrowdev_attribute *csrowdev_attr = to_csrowdev_attr(attr);
235   -
236   - if (csrowdev_attr->store)
237   - return csrowdev_attr->store(csrow,
238   - buffer,
239   - count, csrowdev_attr->private);
240   - return -EIO;
  286 + debugf1("Releasing csrow device %s\n", dev_name(device));
241 287 }
242 288  
243   -static const struct sysfs_ops csrowfs_ops = {
244   - .show = csrowdev_show,
245   - .store = csrowdev_store
  289 +static struct device_type csrow_attr_type = {
  290 + .groups = csrow_attr_groups,
  291 + .release = csrow_attr_release,
246 292 };
247 293  
248   -#define CSROWDEV_ATTR(_name,_mode,_show,_store,_private) \
249   -static struct csrowdev_attribute attr_##_name = { \
250   - .attr = {.name = __stringify(_name), .mode = _mode }, \
251   - .show = _show, \
252   - .store = _store, \
253   - .private = _private, \
254   -};
  294 +/*
  295 + * possible dynamic channel DIMM Label attribute files
  296 + *
  297 + */
255 298  
256   -/* default cwrow<id>/attribute files */
257   -CSROWDEV_ATTR(size_mb, S_IRUGO, csrow_size_show, NULL, 0);
258   -CSROWDEV_ATTR(dev_type, S_IRUGO, csrow_dev_type_show, NULL, 0);
259   -CSROWDEV_ATTR(mem_type, S_IRUGO, csrow_mem_type_show, NULL, 0);
260   -CSROWDEV_ATTR(edac_mode, S_IRUGO, csrow_edac_mode_show, NULL, 0);
261   -CSROWDEV_ATTR(ue_count, S_IRUGO, csrow_ue_count_show, NULL, 0);
262   -CSROWDEV_ATTR(ce_count, S_IRUGO, csrow_ce_count_show, NULL, 0);
  299 +#define EDAC_NR_CHANNELS 6
263 300  
264   -/* default attributes of the CSROW<id> object */
265   -static struct csrowdev_attribute *default_csrow_attr[] = {
266   - &attr_dev_type,
267   - &attr_mem_type,
268   - &attr_edac_mode,
269   - &attr_size_mb,
270   - &attr_ue_count,
271   - &attr_ce_count,
272   - NULL,
273   -};
274   -
275   -/* possible dynamic channel DIMM Label attribute files */
276   -CSROWDEV_ATTR(ch0_dimm_label, S_IRUGO | S_IWUSR,
  301 +DEVICE_CHANNEL(ch0_dimm_label, S_IRUGO | S_IWUSR,
277 302 channel_dimm_label_show, channel_dimm_label_store, 0);
278   -CSROWDEV_ATTR(ch1_dimm_label, S_IRUGO | S_IWUSR,
  303 +DEVICE_CHANNEL(ch1_dimm_label, S_IRUGO | S_IWUSR,
279 304 channel_dimm_label_show, channel_dimm_label_store, 1);
280   -CSROWDEV_ATTR(ch2_dimm_label, S_IRUGO | S_IWUSR,
  305 +DEVICE_CHANNEL(ch2_dimm_label, S_IRUGO | S_IWUSR,
281 306 channel_dimm_label_show, channel_dimm_label_store, 2);
282   -CSROWDEV_ATTR(ch3_dimm_label, S_IRUGO | S_IWUSR,
  307 +DEVICE_CHANNEL(ch3_dimm_label, S_IRUGO | S_IWUSR,
283 308 channel_dimm_label_show, channel_dimm_label_store, 3);
284   -CSROWDEV_ATTR(ch4_dimm_label, S_IRUGO | S_IWUSR,
  309 +DEVICE_CHANNEL(ch4_dimm_label, S_IRUGO | S_IWUSR,
285 310 channel_dimm_label_show, channel_dimm_label_store, 4);
286   -CSROWDEV_ATTR(ch5_dimm_label, S_IRUGO | S_IWUSR,
  311 +DEVICE_CHANNEL(ch5_dimm_label, S_IRUGO | S_IWUSR,
287 312 channel_dimm_label_show, channel_dimm_label_store, 5);
288 313  
289 314 /* Total possible dynamic DIMM Label attribute file table */
290   -static struct csrowdev_attribute *dynamic_csrow_dimm_attr[] = {
291   - &attr_ch0_dimm_label,
292   - &attr_ch1_dimm_label,
293   - &attr_ch2_dimm_label,
294   - &attr_ch3_dimm_label,
295   - &attr_ch4_dimm_label,
296   - &attr_ch5_dimm_label
  315 +static struct device_attribute *dynamic_csrow_dimm_attr[] = {
  316 + &dev_attr_legacy_ch0_dimm_label.attr,
  317 + &dev_attr_legacy_ch1_dimm_label.attr,
  318 + &dev_attr_legacy_ch2_dimm_label.attr,
  319 + &dev_attr_legacy_ch3_dimm_label.attr,
  320 + &dev_attr_legacy_ch4_dimm_label.attr,
  321 + &dev_attr_legacy_ch5_dimm_label.attr
297 322 };
298 323  
299 324 /* possible dynamic channel ce_count attribute files */
300   -CSROWDEV_ATTR(ch0_ce_count, S_IRUGO | S_IWUSR, channel_ce_count_show, NULL, 0);
301   -CSROWDEV_ATTR(ch1_ce_count, S_IRUGO | S_IWUSR, channel_ce_count_show, NULL, 1);
302   -CSROWDEV_ATTR(ch2_ce_count, S_IRUGO | S_IWUSR, channel_ce_count_show, NULL, 2);
303   -CSROWDEV_ATTR(ch3_ce_count, S_IRUGO | S_IWUSR, channel_ce_count_show, NULL, 3);
304   -CSROWDEV_ATTR(ch4_ce_count, S_IRUGO | S_IWUSR, channel_ce_count_show, NULL, 4);
305   -CSROWDEV_ATTR(ch5_ce_count, S_IRUGO | S_IWUSR, channel_ce_count_show, NULL, 5);
  325 +DEVICE_CHANNEL(ch0_ce_count, S_IRUGO | S_IWUSR,
  326 + channel_ce_count_show, NULL, 0);
  327 +DEVICE_CHANNEL(ch1_ce_count, S_IRUGO | S_IWUSR,
  328 + channel_ce_count_show, NULL, 1);
  329 +DEVICE_CHANNEL(ch2_ce_count, S_IRUGO | S_IWUSR,
  330 + channel_ce_count_show, NULL, 2);
  331 +DEVICE_CHANNEL(ch3_ce_count, S_IRUGO | S_IWUSR,
  332 + channel_ce_count_show, NULL, 3);
  333 +DEVICE_CHANNEL(ch4_ce_count, S_IRUGO | S_IWUSR,
  334 + channel_ce_count_show, NULL, 4);
  335 +DEVICE_CHANNEL(ch5_ce_count, S_IRUGO | S_IWUSR,
  336 + channel_ce_count_show, NULL, 5);
306 337  
307 338 /* Total possible dynamic ce_count attribute file table */
308   -static struct csrowdev_attribute *dynamic_csrow_ce_count_attr[] = {
309   - &attr_ch0_ce_count,
310   - &attr_ch1_ce_count,
311   - &attr_ch2_ce_count,
312   - &attr_ch3_ce_count,
313   - &attr_ch4_ce_count,
314   - &attr_ch5_ce_count
  339 +static struct device_attribute *dynamic_csrow_ce_count_attr[] = {
  340 + &dev_attr_legacy_ch0_ce_count.attr,
  341 + &dev_attr_legacy_ch1_ce_count.attr,
  342 + &dev_attr_legacy_ch2_ce_count.attr,
  343 + &dev_attr_legacy_ch3_ce_count.attr,
  344 + &dev_attr_legacy_ch4_ce_count.attr,
  345 + &dev_attr_legacy_ch5_ce_count.attr
315 346 };
316 347  
317   -#define EDAC_NR_CHANNELS 6
318   -
319   -/* Create dynamic CHANNEL files, indexed by 'chan', under specifed CSROW */
320   -static int edac_create_channel_files(struct kobject *kobj, int chan)
  348 +/* Create a CSROW object under specifed edac_mc_device */
  349 +static int edac_create_csrow_object(struct mem_ctl_info *mci,
  350 + struct csrow_info *csrow, int index)
321 351 {
322   - int err = -ENODEV;
  352 + int err, chan;
323 353  
324   - if (chan >= EDAC_NR_CHANNELS)
325   - return err;
  354 + if (csrow->nr_channels >= EDAC_NR_CHANNELS)
  355 + return -ENODEV;
326 356  
327   - /* create the DIMM label attribute file */
328   - err = sysfs_create_file(kobj,
329   - (struct attribute *)
330   - dynamic_csrow_dimm_attr[chan]);
  357 + csrow->dev.type = &csrow_attr_type;
  358 + csrow->dev.bus = &mci->bus;
  359 + device_initialize(&csrow->dev);
  360 + csrow->dev.parent = &mci->dev;
  361 + dev_set_name(&csrow->dev, "csrow%d", index);
  362 + dev_set_drvdata(&csrow->dev, csrow);
331 363  
332   - if (!err) {
333   - /* create the CE Count attribute file */
334   - err = sysfs_create_file(kobj,
335   - (struct attribute *)
336   - dynamic_csrow_ce_count_attr[chan]);
337   - } else {
338   - debugf1("%s() dimm labels and ce_count files created",
339   - __func__);
340   - }
  364 + debugf0("%s(): creating (virtual) csrow node %s\n", __func__,
  365 + dev_name(&csrow->dev));
341 366  
342   - return err;
343   -}
  367 + err = device_add(&csrow->dev);
  368 + if (err < 0)
  369 + return err;
344 370  
345   -/* No memory to release for this kobj */
346   -static void edac_csrow_instance_release(struct kobject *kobj)
347   -{
348   - struct mem_ctl_info *mci;
349   - struct csrow_info *cs;
  371 + for (chan = 0; chan < csrow->nr_channels; chan++) {
  372 + err = device_create_file(&csrow->dev,
  373 + dynamic_csrow_dimm_attr[chan]);
  374 + if (err < 0)
  375 + goto error;
  376 + err = device_create_file(&csrow->dev,
  377 + dynamic_csrow_ce_count_attr[chan]);
  378 + if (err < 0) {
  379 + device_remove_file(&csrow->dev,
  380 + dynamic_csrow_dimm_attr[chan]);
  381 + goto error;
  382 + }
  383 + }
350 384  
351   - debugf1("%s()\n", __func__);
  385 + return 0;
352 386  
353   - cs = container_of(kobj, struct csrow_info, kobj);
354   - mci = cs->mci;
  387 +error:
  388 + for (--chan; chan >= 0; chan--) {
  389 + device_remove_file(&csrow->dev,
  390 + dynamic_csrow_dimm_attr[chan]);
  391 + device_remove_file(&csrow->dev,
  392 + dynamic_csrow_ce_count_attr[chan]);
  393 + }
  394 + put_device(&csrow->dev);
355 395  
356   - kobject_put(&mci->edac_mci_kobj);
  396 + return err;
357 397 }
358 398  
359   -/* the kobj_type instance for a CSROW */
360   -static struct kobj_type ktype_csrow = {
361   - .release = edac_csrow_instance_release,
362   - .sysfs_ops = &csrowfs_ops,
363   - .default_attrs = (struct attribute **)default_csrow_attr,
364   -};
365   -
366 399 /* Create a CSROW object under specifed edac_mc_device */
367   -static int edac_create_csrow_object(struct mem_ctl_info *mci,
368   - struct csrow_info *csrow, int index)
  400 +static int edac_create_csrow_objects(struct mem_ctl_info *mci)
369 401 {
370   - struct kobject *kobj_mci = &mci->edac_mci_kobj;
371   - struct kobject *kobj;
372   - int chan;
373   - int err;
  402 + int err, i, chan;
  403 + struct csrow_info *csrow;
374 404  
375   - /* generate ..../edac/mc/mc<id>/csrow<index> */
376   - memset(&csrow->kobj, 0, sizeof(csrow->kobj));
377   - csrow->mci = mci; /* include container up link */
  405 + for (i = 0; i < mci->nr_csrows; i++) {
  406 + err = edac_create_csrow_object(mci, &mci->csrows[i], i);
  407 + if (err < 0)
  408 + goto error;
  409 + }
  410 + return 0;
378 411  
379   - /* bump the mci instance's kobject's ref count */
380   - kobj = kobject_get(&mci->edac_mci_kobj);
381   - if (!kobj) {
382   - err = -ENODEV;
383   - goto err_out;
  412 +error:
  413 + for (--i; i >= 0; i--) {
  414 + csrow = &mci->csrows[i];
  415 + for (chan = csrow->nr_channels - 1; chan >= 0; chan--) {
  416 + device_remove_file(&csrow->dev,
  417 + dynamic_csrow_dimm_attr[chan]);
  418 + device_remove_file(&csrow->dev,
  419 + dynamic_csrow_ce_count_attr[chan]);
  420 + }
  421 + put_device(&mci->csrows[i].dev);
384 422 }
385 423  
386   - /* Instanstiate the csrow object */
387   - err = kobject_init_and_add(&csrow->kobj, &ktype_csrow, kobj_mci,
388   - "csrow%d", index);
389   - if (err)
390   - goto err_release_top_kobj;
  424 + return err;
  425 +}
391 426  
392   - /* At this point, to release a csrow kobj, one must
393   - * call the kobject_put and allow that tear down
394   - * to work the releasing
395   - */
  427 +static void edac_delete_csrow_objects(struct mem_ctl_info *mci)
  428 +{
  429 + int i, chan;
  430 + struct csrow_info *csrow;
396 431  
397   - /* Create the dyanmic attribute files on this csrow,
398   - * namely, the DIMM labels and the channel ce_count
399   - */
400   - for (chan = 0; chan < csrow->nr_channels; chan++) {
401   - err = edac_create_channel_files(&csrow->kobj, chan);
402   - if (err) {
403   - /* special case the unregister here */
404   - kobject_put(&csrow->kobj);
405   - goto err_out;
  432 + for (i = mci->nr_csrows - 1; i >= 0; i--) {
  433 + csrow = &mci->csrows[i];
  434 + for (chan = csrow->nr_channels - 1; chan >= 0; chan--) {
  435 + debugf1("Removing csrow %d channel %d sysfs nodes\n",
  436 + i, chan);
  437 + device_remove_file(&csrow->dev,
  438 + dynamic_csrow_dimm_attr[chan]);
  439 + device_remove_file(&csrow->dev,
  440 + dynamic_csrow_ce_count_attr[chan]);
406 441 }
  442 + put_device(&mci->csrows[i].dev);
  443 + device_del(&mci->csrows[i].dev);
407 444 }
408   - kobject_uevent(&csrow->kobj, KOBJ_ADD);
409   - return 0;
410   -
411   - /* error unwind stack */
412   -err_release_top_kobj:
413   - kobject_put(&mci->edac_mci_kobj);
414   -
415   -err_out:
416   - return err;
417 445 }
418 446  
419   -/* default sysfs methods and data structures for the main MCI kobject */
  447 +/*
  448 + * Memory controller device
  449 + */
420 450  
421   -static ssize_t mci_reset_counters_store(struct mem_ctl_info *mci,
  451 +#define to_mci(k) container_of(k, struct mem_ctl_info, dev)
  452 +
  453 +static ssize_t mci_reset_counters_store(struct device *dev,
  454 + struct device_attribute *mattr,
422 455 const char *data, size_t count)
423 456 {
424   - int row, chan;
425   -
426   - mci->ue_noinfo_count = 0;
427   - mci->ce_noinfo_count = 0;
  457 + struct mem_ctl_info *mci = to_mci(dev);
  458 + int cnt, row, chan, i;
428 459 mci->ue_mc = 0;
429 460 mci->ce_mc = 0;
  461 + mci->ue_noinfo_count = 0;
  462 + mci->ce_noinfo_count = 0;
430 463  
431 464 for (row = 0; row < mci->nr_csrows; row++) {
432 465 struct csrow_info *ri = &mci->csrows[row];
... ... @@ -438,6 +471,13 @@
438 471 ri->channels[chan].ce_count = 0;
439 472 }
440 473  
  474 + cnt = 1;
  475 + for (i = 0; i < mci->n_layers; i++) {
  476 + cnt *= mci->layers[i].size;
  477 + memset(mci->ce_per_layer[i], 0, cnt * sizeof(u32));
  478 + memset(mci->ue_per_layer[i], 0, cnt * sizeof(u32));
  479 + }
  480 +
441 481 mci->start_time = jiffies;
442 482 return count;
443 483 }
444 484  
... ... @@ -451,9 +491,11 @@
451 491 * Negative value still means that an error has occurred while setting
452 492 * the scrub rate.
453 493 */
454   -static ssize_t mci_sdram_scrub_rate_store(struct mem_ctl_info *mci,
  494 +static ssize_t mci_sdram_scrub_rate_store(struct device *dev,
  495 + struct device_attribute *mattr,
455 496 const char *data, size_t count)
456 497 {
  498 + struct mem_ctl_info *mci = to_mci(dev);
457 499 unsigned long bandwidth = 0;
458 500 int new_bw = 0;
459 501  
460 502  
... ... @@ -476,8 +518,11 @@
476 518 /*
477 519 * ->get_sdram_scrub_rate() return value semantics same as above.
478 520 */
479   -static ssize_t mci_sdram_scrub_rate_show(struct mem_ctl_info *mci, char *data)
  521 +static ssize_t mci_sdram_scrub_rate_show(struct device *dev,
  522 + struct device_attribute *mattr,
  523 + char *data)
480 524 {
  525 + struct mem_ctl_info *mci = to_mci(dev);
481 526 int bandwidth = 0;
482 527  
483 528 if (!mci->get_sdram_scrub_rate)
484 529  
485 530  
486 531  
487 532  
488 533  
489 534  
490 535  
491 536  
492 537  
493 538  
494 539  
495 540  
496 541  
... ... @@ -493,38 +538,65 @@
493 538 }
494 539  
495 540 /* default attribute files for the MCI object */
496   -static ssize_t mci_ue_count_show(struct mem_ctl_info *mci, char *data)
  541 +static ssize_t mci_ue_count_show(struct device *dev,
  542 + struct device_attribute *mattr,
  543 + char *data)
497 544 {
  545 + struct mem_ctl_info *mci = to_mci(dev);
  546 +
498 547 return sprintf(data, "%d\n", mci->ue_mc);
499 548 }
500 549  
501   -static ssize_t mci_ce_count_show(struct mem_ctl_info *mci, char *data)
  550 +static ssize_t mci_ce_count_show(struct device *dev,
  551 + struct device_attribute *mattr,
  552 + char *data)
502 553 {
  554 + struct mem_ctl_info *mci = to_mci(dev);
  555 +
503 556 return sprintf(data, "%d\n", mci->ce_mc);
504 557 }
505 558  
506   -static ssize_t mci_ce_noinfo_show(struct mem_ctl_info *mci, char *data)
  559 +static ssize_t mci_ce_noinfo_show(struct device *dev,
  560 + struct device_attribute *mattr,
  561 + char *data)
507 562 {
  563 + struct mem_ctl_info *mci = to_mci(dev);
  564 +
508 565 return sprintf(data, "%d\n", mci->ce_noinfo_count);
509 566 }
510 567  
511   -static ssize_t mci_ue_noinfo_show(struct mem_ctl_info *mci, char *data)
  568 +static ssize_t mci_ue_noinfo_show(struct device *dev,
  569 + struct device_attribute *mattr,
  570 + char *data)
512 571 {
  572 + struct mem_ctl_info *mci = to_mci(dev);
  573 +
513 574 return sprintf(data, "%d\n", mci->ue_noinfo_count);
514 575 }
515 576  
516   -static ssize_t mci_seconds_show(struct mem_ctl_info *mci, char *data)
  577 +static ssize_t mci_seconds_show(struct device *dev,
  578 + struct device_attribute *mattr,
  579 + char *data)
517 580 {
  581 + struct mem_ctl_info *mci = to_mci(dev);
  582 +
518 583 return sprintf(data, "%ld\n", (jiffies - mci->start_time) / HZ);
519 584 }
520 585  
521   -static ssize_t mci_ctl_name_show(struct mem_ctl_info *mci, char *data)
  586 +static ssize_t mci_ctl_name_show(struct device *dev,
  587 + struct device_attribute *mattr,
  588 + char *data)
522 589 {
  590 + struct mem_ctl_info *mci = to_mci(dev);
  591 +
523 592 return sprintf(data, "%s\n", mci->ctl_name);
524 593 }
525 594  
526   -static ssize_t mci_size_mb_show(struct mem_ctl_info *mci, char *data)
  595 +static ssize_t mci_size_mb_show(struct device *dev,
  596 + struct device_attribute *mattr,
  597 + char *data)
527 598 {
  599 + struct mem_ctl_info *mci = to_mci(dev);
528 600 int total_pages = 0, csrow_idx, j;
529 601  
530 602 for (csrow_idx = 0; csrow_idx < mci->nr_csrows; csrow_idx++) {
531 603  
532 604  
533 605  
534 606  
535 607  
536 608  
537 609  
538 610  
539 611  
540 612  
541 613  
542 614  
... ... @@ -540,363 +612,56 @@
540 612 return sprintf(data, "%u\n", PAGES_TO_MiB(total_pages));
541 613 }
542 614  
543   -#define to_mci(k) container_of(k, struct mem_ctl_info, edac_mci_kobj)
544   -#define to_mcidev_attr(a) container_of(a,struct mcidev_sysfs_attribute,attr)
545   -
546   -/* MCI show/store functions for top most object */
547   -static ssize_t mcidev_show(struct kobject *kobj, struct attribute *attr,
548   - char *buffer)
549   -{
550   - struct mem_ctl_info *mem_ctl_info = to_mci(kobj);
551   - struct mcidev_sysfs_attribute *mcidev_attr = to_mcidev_attr(attr);
552   -
553   - debugf1("%s() mem_ctl_info %p\n", __func__, mem_ctl_info);
554   -
555   - if (mcidev_attr->show)
556   - return mcidev_attr->show(mem_ctl_info, buffer);
557   -
558   - return -EIO;
559   -}
560   -
561   -static ssize_t mcidev_store(struct kobject *kobj, struct attribute *attr,
562   - const char *buffer, size_t count)
563   -{
564   - struct mem_ctl_info *mem_ctl_info = to_mci(kobj);
565   - struct mcidev_sysfs_attribute *mcidev_attr = to_mcidev_attr(attr);
566   -
567   - debugf1("%s() mem_ctl_info %p\n", __func__, mem_ctl_info);
568   -
569   - if (mcidev_attr->store)
570   - return mcidev_attr->store(mem_ctl_info, buffer, count);
571   -
572   - return -EIO;
573   -}
574   -
575   -/* Intermediate show/store table */
576   -static const struct sysfs_ops mci_ops = {
577   - .show = mcidev_show,
578   - .store = mcidev_store
579   -};
580   -
581   -#define MCIDEV_ATTR(_name,_mode,_show,_store) \
582   -static struct mcidev_sysfs_attribute mci_attr_##_name = { \
583   - .attr = {.name = __stringify(_name), .mode = _mode }, \
584   - .show = _show, \
585   - .store = _store, \
586   -};
587   -
588 615 /* default Control file */
589   -MCIDEV_ATTR(reset_counters, S_IWUSR, NULL, mci_reset_counters_store);
  616 +DEVICE_ATTR(reset_counters, S_IWUSR, NULL, mci_reset_counters_store);
590 617  
591 618 /* default Attribute files */
592   -MCIDEV_ATTR(mc_name, S_IRUGO, mci_ctl_name_show, NULL);
593   -MCIDEV_ATTR(size_mb, S_IRUGO, mci_size_mb_show, NULL);
594   -MCIDEV_ATTR(seconds_since_reset, S_IRUGO, mci_seconds_show, NULL);
595   -MCIDEV_ATTR(ue_noinfo_count, S_IRUGO, mci_ue_noinfo_show, NULL);
596   -MCIDEV_ATTR(ce_noinfo_count, S_IRUGO, mci_ce_noinfo_show, NULL);
597   -MCIDEV_ATTR(ue_count, S_IRUGO, mci_ue_count_show, NULL);
598   -MCIDEV_ATTR(ce_count, S_IRUGO, mci_ce_count_show, NULL);
  619 +DEVICE_ATTR(mc_name, S_IRUGO, mci_ctl_name_show, NULL);
  620 +DEVICE_ATTR(size_mb, S_IRUGO, mci_size_mb_show, NULL);
  621 +DEVICE_ATTR(seconds_since_reset, S_IRUGO, mci_seconds_show, NULL);
  622 +DEVICE_ATTR(ue_noinfo_count, S_IRUGO, mci_ue_noinfo_show, NULL);
  623 +DEVICE_ATTR(ce_noinfo_count, S_IRUGO, mci_ce_noinfo_show, NULL);
  624 +DEVICE_ATTR(ue_count, S_IRUGO, mci_ue_count_show, NULL);
  625 +DEVICE_ATTR(ce_count, S_IRUGO, mci_ce_count_show, NULL);
599 626  
600 627 /* memory scrubber attribute file */
601   -MCIDEV_ATTR(sdram_scrub_rate, S_IRUGO | S_IWUSR, mci_sdram_scrub_rate_show,
  628 +DEVICE_ATTR(sdram_scrub_rate, S_IRUGO | S_IWUSR, mci_sdram_scrub_rate_show,
602 629 mci_sdram_scrub_rate_store);
603 630  
604   -static struct mcidev_sysfs_attribute *mci_attr[] = {
605   - &mci_attr_reset_counters,
606   - &mci_attr_mc_name,
607   - &mci_attr_size_mb,
608   - &mci_attr_seconds_since_reset,
609   - &mci_attr_ue_noinfo_count,
610   - &mci_attr_ce_noinfo_count,
611   - &mci_attr_ue_count,
612   - &mci_attr_ce_count,
613   - &mci_attr_sdram_scrub_rate,
  631 +static struct attribute *mci_attrs[] = {
  632 + &dev_attr_reset_counters.attr,
  633 + &dev_attr_mc_name.attr,
  634 + &dev_attr_size_mb.attr,
  635 + &dev_attr_seconds_since_reset.attr,
  636 + &dev_attr_ue_noinfo_count.attr,
  637 + &dev_attr_ce_noinfo_count.attr,
  638 + &dev_attr_ue_count.attr,
  639 + &dev_attr_ce_count.attr,
  640 + &dev_attr_sdram_scrub_rate.attr,
614 641 NULL
615 642 };
616 643  
  644 +static struct attribute_group mci_attr_grp = {
  645 + .attrs = mci_attrs,
  646 +};
617 647  
618   -/*
619   - * Release of a MC controlling instance
620   - *
621   - * each MC control instance has the following resources upon entry:
622   - * a) a ref count on the top memctl kobj
623   - * b) a ref count on this module
624   - *
625   - * this function must decrement those ref counts and then
626   - * issue a free on the instance's memory
627   - */
628   -static void edac_mci_control_release(struct kobject *kobj)
629   -{
630   - struct mem_ctl_info *mci;
631   -
632   - mci = to_mci(kobj);
633   -
634   - debugf0("%s() mci instance idx=%d releasing\n", __func__, mci->mc_idx);
635   -
636   - /* decrement the module ref count */
637   - module_put(mci->owner);
638   -}
639   -
640   -static struct kobj_type ktype_mci = {
641   - .release = edac_mci_control_release,
642   - .sysfs_ops = &mci_ops,
643   - .default_attrs = (struct attribute **)mci_attr,
  648 +static const struct attribute_group *mci_attr_groups[] = {
  649 + &mci_attr_grp,
  650 + NULL
644 651 };
645 652  
646   -/* EDAC memory controller sysfs kset:
647   - * /sys/devices/system/edac/mc
648   - */
649   -static struct kset *mc_kset;
650   -
651   -/*
652   - * edac_mc_register_sysfs_main_kobj
653   - *
654   - * setups and registers the main kobject for each mci
655   - */
656   -int edac_mc_register_sysfs_main_kobj(struct mem_ctl_info *mci)
  653 +static void mci_attr_release(struct device *device)
657 654 {
658   - struct kobject *kobj_mci;
659   - int err;
660   -
661   - debugf1("%s()\n", __func__);
662   -
663   - kobj_mci = &mci->edac_mci_kobj;
664   -
665   - /* Init the mci's kobject */
666   - memset(kobj_mci, 0, sizeof(*kobj_mci));
667   -
668   - /* Record which module 'owns' this control structure
669   - * and bump the ref count of the module
670   - */
671   - mci->owner = THIS_MODULE;
672   -
673   - /* bump ref count on this module */
674   - if (!try_module_get(mci->owner)) {
675   - err = -ENODEV;
676   - goto fail_out;
677   - }
678   -
679   - /* this instance become part of the mc_kset */
680   - kobj_mci->kset = mc_kset;
681   -
682   - /* register the mc<id> kobject to the mc_kset */
683   - err = kobject_init_and_add(kobj_mci, &ktype_mci, NULL,
684   - "mc%d", mci->mc_idx);
685   - if (err) {
686   - debugf1("%s()Failed to register '.../edac/mc%d'\n",
687   - __func__, mci->mc_idx);
688   - goto kobj_reg_fail;
689   - }
690   - kobject_uevent(kobj_mci, KOBJ_ADD);
691   -
692   - /* At this point, to 'free' the control struct,
693   - * edac_mc_unregister_sysfs_main_kobj() must be used
694   - */
695   -
696   - debugf1("%s() Registered '.../edac/mc%d' kobject\n",
697   - __func__, mci->mc_idx);
698   -
699   - return 0;
700   -
701   - /* Error exit stack */
702   -
703   -kobj_reg_fail:
704   - module_put(mci->owner);
705   -
706   -fail_out:
707   - return err;
  655 + debugf1("Releasing mci device %s\n", dev_name(device));
708 656 }
709 657  
710   -/*
711   - * edac_mc_register_sysfs_main_kobj
712   - *
713   - * tears down and the main mci kobject from the mc_kset
714   - */
715   -void edac_mc_unregister_sysfs_main_kobj(struct mem_ctl_info *mci)
716   -{
717   - debugf1("%s()\n", __func__);
718   -
719   - /* delete the kobj from the mc_kset */
720   - kobject_put(&mci->edac_mci_kobj);
721   -}
722   -
723   -#define EDAC_DEVICE_SYMLINK "device"
724   -
725   -#define grp_to_mci(k) (container_of(k, struct mcidev_sysfs_group_kobj, kobj)->mci)
726   -
727   -/* MCI show/store functions for top most object */
728   -static ssize_t inst_grp_show(struct kobject *kobj, struct attribute *attr,
729   - char *buffer)
730   -{
731   - struct mem_ctl_info *mem_ctl_info = grp_to_mci(kobj);
732   - struct mcidev_sysfs_attribute *mcidev_attr = to_mcidev_attr(attr);
733   -
734   - debugf1("%s() mem_ctl_info %p\n", __func__, mem_ctl_info);
735   -
736   - if (mcidev_attr->show)
737   - return mcidev_attr->show(mem_ctl_info, buffer);
738   -
739   - return -EIO;
740   -}
741   -
742   -static ssize_t inst_grp_store(struct kobject *kobj, struct attribute *attr,
743   - const char *buffer, size_t count)
744   -{
745   - struct mem_ctl_info *mem_ctl_info = grp_to_mci(kobj);
746   - struct mcidev_sysfs_attribute *mcidev_attr = to_mcidev_attr(attr);
747   -
748   - debugf1("%s() mem_ctl_info %p\n", __func__, mem_ctl_info);
749   -
750   - if (mcidev_attr->store)
751   - return mcidev_attr->store(mem_ctl_info, buffer, count);
752   -
753   - return -EIO;
754   -}
755   -
756   -/* No memory to release for this kobj */
757   -static void edac_inst_grp_release(struct kobject *kobj)
758   -{
759   - struct mcidev_sysfs_group_kobj *grp;
760   - struct mem_ctl_info *mci;
761   -
762   - debugf1("%s()\n", __func__);
763   -
764   - grp = container_of(kobj, struct mcidev_sysfs_group_kobj, kobj);
765   - mci = grp->mci;
766   -}
767   -
768   -/* Intermediate show/store table */
769   -static struct sysfs_ops inst_grp_ops = {
770   - .show = inst_grp_show,
771   - .store = inst_grp_store
  658 +static struct device_type mci_attr_type = {
  659 + .groups = mci_attr_groups,
  660 + .release = mci_attr_release,
772 661 };
773 662  
774   -/* the kobj_type instance for a instance group */
775   -static struct kobj_type ktype_inst_grp = {
776   - .release = edac_inst_grp_release,
777   - .sysfs_ops = &inst_grp_ops,
778   -};
779 663  
780   -
781 664 /*
782   - * edac_create_mci_instance_attributes
783   - * create MC driver specific attributes bellow an specified kobj
784   - * This routine calls itself recursively, in order to create an entire
785   - * object tree.
786   - */
787   -static int edac_create_mci_instance_attributes(struct mem_ctl_info *mci,
788   - const struct mcidev_sysfs_attribute *sysfs_attrib,
789   - struct kobject *kobj)
790   -{
791   - int err;
792   -
793   - debugf4("%s()\n", __func__);
794   -
795   - while (sysfs_attrib) {
796   - debugf4("%s() sysfs_attrib = %p\n",__func__, sysfs_attrib);
797   - if (sysfs_attrib->grp) {
798   - struct mcidev_sysfs_group_kobj *grp_kobj;
799   -
800   - grp_kobj = kzalloc(sizeof(*grp_kobj), GFP_KERNEL);
801   - if (!grp_kobj)
802   - return -ENOMEM;
803   -
804   - grp_kobj->grp = sysfs_attrib->grp;
805   - grp_kobj->mci = mci;
806   - list_add_tail(&grp_kobj->list, &mci->grp_kobj_list);
807   -
808   - debugf0("%s() grp %s, mci %p\n", __func__,
809   - sysfs_attrib->grp->name, mci);
810   -
811   - err = kobject_init_and_add(&grp_kobj->kobj,
812   - &ktype_inst_grp,
813   - &mci->edac_mci_kobj,
814   - sysfs_attrib->grp->name);
815   - if (err < 0) {
816   - printk(KERN_ERR "kobject_init_and_add failed: %d\n", err);
817   - return err;
818   - }
819   - err = edac_create_mci_instance_attributes(mci,
820   - grp_kobj->grp->mcidev_attr,
821   - &grp_kobj->kobj);
822   -
823   - if (err < 0)
824   - return err;
825   - } else if (sysfs_attrib->attr.name) {
826   - debugf4("%s() file %s\n", __func__,
827   - sysfs_attrib->attr.name);
828   -
829   - err = sysfs_create_file(kobj, &sysfs_attrib->attr);
830   - if (err < 0) {
831   - printk(KERN_ERR "sysfs_create_file failed: %d\n", err);
832   - return err;
833   - }
834   - } else
835   - break;
836   -
837   - sysfs_attrib++;
838   - }
839   -
840   - return 0;
841   -}
842   -
843   -/*
844   - * edac_remove_mci_instance_attributes
845   - * remove MC driver specific attributes at the topmost level
846   - * directory of this mci instance.
847   - */
848   -static void edac_remove_mci_instance_attributes(struct mem_ctl_info *mci,
849   - const struct mcidev_sysfs_attribute *sysfs_attrib,
850   - struct kobject *kobj, int count)
851   -{
852   - struct mcidev_sysfs_group_kobj *grp_kobj, *tmp;
853   -
854   - debugf1("%s()\n", __func__);
855   -
856   - /*
857   - * loop if there are attributes and until we hit a NULL entry
858   - * Remove first all the attributes
859   - */
860   - while (sysfs_attrib) {
861   - debugf4("%s() sysfs_attrib = %p\n",__func__, sysfs_attrib);
862   - if (sysfs_attrib->grp) {
863   - debugf4("%s() seeking for group %s\n",
864   - __func__, sysfs_attrib->grp->name);
865   - list_for_each_entry(grp_kobj,
866   - &mci->grp_kobj_list, list) {
867   - debugf4("%s() grp_kobj->grp = %p\n",__func__, grp_kobj->grp);
868   - if (grp_kobj->grp == sysfs_attrib->grp) {
869   - edac_remove_mci_instance_attributes(mci,
870   - grp_kobj->grp->mcidev_attr,
871   - &grp_kobj->kobj, count + 1);
872   - debugf4("%s() group %s\n", __func__,
873   - sysfs_attrib->grp->name);
874   - kobject_put(&grp_kobj->kobj);
875   - }
876   - }
877   - debugf4("%s() end of seeking for group %s\n",
878   - __func__, sysfs_attrib->grp->name);
879   - } else if (sysfs_attrib->attr.name) {
880   - debugf4("%s() file %s\n", __func__,
881   - sysfs_attrib->attr.name);
882   - sysfs_remove_file(kobj, &sysfs_attrib->attr);
883   - } else
884   - break;
885   - sysfs_attrib++;
886   - }
887   -
888   - /* Remove the group objects */
889   - if (count)
890   - return;
891   - list_for_each_entry_safe(grp_kobj, tmp,
892   - &mci->grp_kobj_list, list) {
893   - list_del(&grp_kobj->list);
894   - kfree(grp_kobj);
895   - }
896   -}
897   -
898   -
899   -/*
900 665 * Create a new Memory Controller kobject instance,
901 666 * mc<id> under the 'mc' directory
902 667 *
903 668  
904 669  
905 670  
906 671  
907 672  
908 673  
909 674  
910 675  
911 676  
912 677  
913 678  
914 679  
... ... @@ -906,77 +671,80 @@
906 671 */
907 672 int edac_create_sysfs_mci_device(struct mem_ctl_info *mci)
908 673 {
909   - int i, j;
910   - int err;
911   - struct csrow_info *csrow;
912   - struct kobject *kobj_mci = &mci->edac_mci_kobj;
  674 + int i, err;
913 675  
914 676 debugf0("%s() idx=%d\n", __func__, mci->mc_idx);
915 677  
916   - INIT_LIST_HEAD(&mci->grp_kobj_list);
  678 + /* get the /sys/devices/system/edac subsys reference */
917 679  
918   - /* create a symlink for the device */
919   - err = sysfs_create_link(kobj_mci, &mci->pdev->kobj,
920   - EDAC_DEVICE_SYMLINK);
921   - if (err) {
922   - debugf1("%s() failure to create symlink\n", __func__);
923   - goto fail0;
924   - }
  680 + mci->dev.type = &mci_attr_type;
  681 + device_initialize(&mci->dev);
925 682  
926   - /* If the low level driver desires some attributes,
927   - * then create them now for the driver.
928   - */
929   - if (mci->mc_driver_sysfs_attributes) {
930   - err = edac_create_mci_instance_attributes(mci,
931   - mci->mc_driver_sysfs_attributes,
932   - &mci->edac_mci_kobj);
933   - if (err) {
934   - debugf1("%s() failure to create mci attributes\n",
935   - __func__);
936   - goto fail0;
937   - }
938   - }
  683 + mci->dev.parent = &mci_pdev;
  684 + mci->dev.bus = &mci->bus;
  685 + dev_set_name(&mci->dev, "mc%d", mci->mc_idx);
  686 + dev_set_drvdata(&mci->dev, mci);
  687 + pm_runtime_forbid(&mci->dev);
939 688  
940   - /* Make directories for each CSROW object under the mc<id> kobject
  689 + /*
  690 + * The memory controller needs its own bus, in order to avoid
  691 + * namespace conflicts at /sys/bus/edac.
941 692 */
942   - for (i = 0; i < mci->nr_csrows; i++) {
943   - int nr_pages = 0;
  693 + debugf0("creating bus %s\n",mci->bus.name);
  694 + mci->bus.name = kstrdup(dev_name(&mci->dev), GFP_KERNEL);
  695 + err = bus_register(&mci->bus);
  696 + if (err < 0)
  697 + return err;
944 698  
945   - csrow = &mci->csrows[i];
946   - for (j = 0; j < csrow->nr_channels; j++)
947   - nr_pages += csrow->channels[j].dimm->nr_pages;
  699 + debugf0("%s(): creating device %s\n", __func__,
  700 + dev_name(&mci->dev));
  701 + err = device_add(&mci->dev);
  702 + if (err < 0) {
  703 + bus_unregister(&mci->bus);
  704 + kfree(mci->bus.name);
  705 + return err;
  706 + }
948 707  
949   - if (nr_pages > 0) {
950   - err = edac_create_csrow_object(mci, csrow, i);
951   - if (err) {
952   - debugf1("%s() failure: create csrow %d obj\n",
953   - __func__, i);
954   - goto fail1;
955   - }
  708 + /*
  709 + * Create the dimm/rank devices
  710 + */
  711 + for (i = 0; i < mci->tot_dimms; i++) {
  712 + struct dimm_info *dimm = &mci->dimms[i];
  713 + /* Only expose populated DIMMs */
  714 + if (dimm->nr_pages == 0)
  715 + continue;
  716 +#ifdef CONFIG_EDAC_DEBUG
  717 + debugf1("%s creating dimm%d, located at ",
  718 + __func__, i);
  719 + if (edac_debug_level >= 1) {
  720 + int lay;
  721 + for (lay = 0; lay < mci->n_layers; lay++)
  722 + printk(KERN_CONT "%s %d ",
  723 + edac_layer_name[mci->layers[lay].type],
  724 + dimm->location[lay]);
  725 + printk(KERN_CONT "\n");
956 726 }
  727 +#endif
957 728 }
958 729  
  730 + err = edac_create_csrow_objects(mci);
  731 + if (err < 0)
  732 + goto fail;
  733 +
959 734 return 0;
960 735  
961   -fail1:
  736 +fail:
962 737 for (i--; i >= 0; i--) {
963   - int nr_pages = 0;
964   -
965   - csrow = &mci->csrows[i];
966   - for (j = 0; j < csrow->nr_channels; j++)
967   - nr_pages += csrow->channels[j].dimm->nr_pages;
968   - if (nr_pages > 0)
969   - kobject_put(&mci->csrows[i].kobj);
  738 + struct dimm_info *dimm = &mci->dimms[i];
  739 + if (dimm->nr_pages == 0)
  740 + continue;
  741 + put_device(&dimm->dev);
  742 + device_del(&dimm->dev);
970 743 }
971   -
972   - /* remove the mci instance's attributes, if any */
973   - edac_remove_mci_instance_attributes(mci,
974   - mci->mc_driver_sysfs_attributes, &mci->edac_mci_kobj, 0);
975   -
976   - /* remove the symlink */
977   - sysfs_remove_link(kobj_mci, EDAC_DEVICE_SYMLINK);
978   -
979   -fail0:
  744 + put_device(&mci->dev);
  745 + device_del(&mci->dev);
  746 + bus_unregister(&mci->bus);
  747 + kfree(mci->bus.name);
980 748 return err;
981 749 }
982 750  
983 751  
984 752  
985 753  
986 754  
987 755  
988 756  
989 757  
990 758  
991 759  
992 760  
993 761  
994 762  
995 763  
996 764  
997 765  
998 766  
999 767  
... ... @@ -985,98 +753,71 @@
985 753 */
986 754 void edac_remove_sysfs_mci_device(struct mem_ctl_info *mci)
987 755 {
988   - struct csrow_info *csrow;
989   - int i, j;
  756 + int i;
990 757  
991 758 debugf0("%s()\n", __func__);
992 759  
993   - /* remove all csrow kobjects */
994   - debugf4("%s() unregister this mci kobj\n", __func__);
995   - for (i = 0; i < mci->nr_csrows; i++) {
996   - int nr_pages = 0;
  760 + edac_delete_csrow_objects(mci);
997 761  
998   - csrow = &mci->csrows[i];
999   - for (j = 0; j < csrow->nr_channels; j++)
1000   - nr_pages += csrow->channels[j].dimm->nr_pages;
1001   - if (nr_pages > 0) {
1002   - debugf0("%s() unreg csrow-%d\n", __func__, i);
1003   - kobject_put(&mci->csrows[i].kobj);
1004   - }
  762 + for (i = 0; i < mci->tot_dimms; i++) {
  763 + struct dimm_info *dimm = &mci->dimms[i];
  764 + if (dimm->nr_pages == 0)
  765 + continue;
  766 + debugf0("%s(): removing device %s\n", __func__,
  767 + dev_name(&dimm->dev));
  768 + put_device(&dimm->dev);
  769 + device_del(&dimm->dev);
1005 770 }
  771 +}
1006 772  
1007   - /* remove this mci instance's attribtes */
1008   - if (mci->mc_driver_sysfs_attributes) {
1009   - debugf4("%s() unregister mci private attributes\n", __func__);
1010   - edac_remove_mci_instance_attributes(mci,
1011   - mci->mc_driver_sysfs_attributes,
1012   - &mci->edac_mci_kobj, 0);
1013   - }
  773 +void edac_unregister_sysfs(struct mem_ctl_info *mci)
  774 +{
  775 + debugf1("Unregistering device %s\n", dev_name(&mci->dev));
  776 + put_device(&mci->dev);
  777 + device_del(&mci->dev);
  778 + bus_unregister(&mci->bus);
  779 + kfree(mci->bus.name);
  780 +}
1014 781  
1015   - /* remove the symlink */
1016   - debugf4("%s() remove_link\n", __func__);
1017   - sysfs_remove_link(&mci->edac_mci_kobj, EDAC_DEVICE_SYMLINK);
1018   -
1019   - /* unregister this instance's kobject */
1020   - debugf4("%s() remove_mci_instance\n", __func__);
1021   - kobject_put(&mci->edac_mci_kobj);
  782 +static void mc_attr_release(struct device *device)
  783 +{
  784 + debugf1("Releasing device %s\n", dev_name(device));
1022 785 }
1023 786  
1024   -
1025   -
1026   -
  787 +static struct device_type mc_attr_type = {
  788 + .release = mc_attr_release,
  789 +};
1027 790 /*
1028   - * edac_setup_sysfs_mc_kset(void)
1029   - *
1030   - * Initialize the mc_kset for the 'mc' entry
1031   - * This requires creating the top 'mc' directory with a kset
1032   - * and its controls/attributes.
1033   - *
1034   - * To this 'mc' kset, instance 'mci' will be grouped as children.
1035   - *
1036   - * Return: 0 SUCCESS
1037   - * !0 FAILURE error code
  791 + * Init/exit code for the module. Basically, creates/removes /sys/class/rc
1038 792 */
1039   -int edac_sysfs_setup_mc_kset(void)
  793 +int __init edac_mc_sysfs_init(void)
1040 794 {
1041   - int err = -EINVAL;
1042 795 struct bus_type *edac_subsys;
  796 + int err;
1043 797  
1044   - debugf1("%s()\n", __func__);
1045   -
1046 798 /* get the /sys/devices/system/edac subsys reference */
1047 799 edac_subsys = edac_get_sysfs_subsys();
1048 800 if (edac_subsys == NULL) {
1049   - debugf1("%s() no edac_subsys error=%d\n", __func__, err);
1050   - goto fail_out;
  801 + debugf1("%s() no edac_subsys\n", __func__);
  802 + return -EINVAL;
1051 803 }
1052 804  
1053   - /* Init the MC's kobject */
1054   - mc_kset = kset_create_and_add("mc", NULL, &edac_subsys->dev_root->kobj);
1055   - if (!mc_kset) {
1056   - err = -ENOMEM;
1057   - debugf1("%s() Failed to register '.../edac/mc'\n", __func__);
1058   - goto fail_kset;
1059   - }
  805 + mci_pdev.bus = edac_subsys;
  806 + mci_pdev.type = &mc_attr_type;
  807 + device_initialize(&mci_pdev);
  808 + dev_set_name(&mci_pdev, "mc");
1060 809  
1061   - debugf1("%s() Registered '.../edac/mc' kobject\n", __func__);
  810 + err = device_add(&mci_pdev);
  811 + if (err < 0)
  812 + return err;
1062 813  
1063 814 return 0;
1064   -
1065   -fail_kset:
1066   - edac_put_sysfs_subsys();
1067   -
1068   -fail_out:
1069   - return err;
1070 815 }
1071 816  
1072   -/*
1073   - * edac_sysfs_teardown_mc_kset
1074   - *
1075   - * deconstruct the mc_ket for memory controllers
1076   - */
1077   -void edac_sysfs_teardown_mc_kset(void)
  817 +void __exit edac_mc_sysfs_exit(void)
1078 818 {
1079   - kset_unregister(mc_kset);
  819 + put_device(&mci_pdev);
  820 + device_del(&mci_pdev);
1080 821 edac_put_sysfs_subsys();
1081 822 }
drivers/edac/edac_module.c
... ... @@ -90,10 +90,7 @@
90 90 */
91 91 edac_pci_clear_parity_errors();
92 92  
93   - /*
94   - * now set up the mc_kset under the edac class object
95   - */
96   - err = edac_sysfs_setup_mc_kset();
  93 + err = edac_mc_sysfs_init();
97 94 if (err)
98 95 goto error;
99 96  
100 97  
... ... @@ -101,15 +98,11 @@
101 98 err = edac_workqueue_setup();
102 99 if (err) {
103 100 edac_printk(KERN_ERR, EDAC_MC, "init WorkQueue failure\n");
104   - goto workq_fail;
  101 + goto error;
105 102 }
106 103  
107 104 return 0;
108 105  
109   - /* Error teardown stack */
110   -workq_fail:
111   - edac_sysfs_teardown_mc_kset();
112   -
113 106 error:
114 107 return err;
115 108 }
... ... @@ -124,7 +117,7 @@
124 117  
125 118 /* tear down the various subsystems */
126 119 edac_workqueue_teardown();
127   - edac_sysfs_teardown_mc_kset();
  120 + edac_mc_sysfs_exit();
128 121 }
129 122  
130 123 /*
drivers/edac/edac_module.h
... ... @@ -19,12 +19,12 @@
19 19 *
20 20 * edac_mc objects
21 21 */
22   -extern int edac_sysfs_setup_mc_kset(void);
23   -extern void edac_sysfs_teardown_mc_kset(void);
24   -extern int edac_mc_register_sysfs_main_kobj(struct mem_ctl_info *mci);
25   -extern void edac_mc_unregister_sysfs_main_kobj(struct mem_ctl_info *mci);
  22 + /* on edac_mc_sysfs.c */
  23 +int edac_mc_sysfs_init(void);
  24 +void edac_mc_sysfs_exit(void);
26 25 extern int edac_create_sysfs_mci_device(struct mem_ctl_info *mci);
27 26 extern void edac_remove_sysfs_mci_device(struct mem_ctl_info *mci);
  27 +void edac_unregister_sysfs(struct mem_ctl_info *mci);
28 28 extern int edac_get_log_ue(void);
29 29 extern int edac_get_log_ce(void);
30 30 extern int edac_get_panic_on_ue(void);
... ... @@ -34,6 +34,7 @@
34 34 extern int edac_get_poll_msec(void);
35 35 extern int edac_mc_get_poll_msec(void);
36 36  
  37 + /* on edac_device.c */
37 38 extern int edac_device_register_sysfs_main_kobj(
38 39 struct edac_device_ctl_info *edac_dev);
39 40 extern void edac_device_unregister_sysfs_main_kobj(
include/linux/edac.h
... ... @@ -13,6 +13,7 @@
13 13 #define _LINUX_EDAC_H_
14 14  
15 15 #include <linux/atomic.h>
  16 +#include <linux/device.h>
16 17 #include <linux/kobject.h>
17 18 #include <linux/completion.h>
18 19 #include <linux/workqueue.h>
19 20  
20 21  
... ... @@ -448,14 +449,15 @@
448 449 __p; \
449 450 })
450 451  
451   -
452   -/* FIXME: add the proper per-location error counts */
453 452 struct dimm_info {
  453 + struct device dev;
  454 +
454 455 char label[EDAC_MC_LABEL_LEN + 1]; /* DIMM label on motherboard */
455 456  
456 457 /* Memory location data */
457 458 unsigned location[EDAC_MAX_LAYERS];
458 459  
  460 + struct kobject kobj; /* sysfs kobject for this csrow */
459 461 struct mem_ctl_info *mci; /* the parent */
460 462  
461 463 u32 grain; /* granularity of reported error in bytes */
... ... @@ -484,6 +486,8 @@
484 486 * patches in this series will fix this issue.
485 487 */
486 488 struct rank_info {
  489 + struct device dev;
  490 +
487 491 int chan_idx;
488 492 struct csrow_info *csrow;
489 493 struct dimm_info *dimm;
... ... @@ -492,6 +496,8 @@
492 496 };
493 497  
494 498 struct csrow_info {
  499 + struct device dev;
  500 +
495 501 /* Used only by edac_mc_find_csrow_by_page() */
496 502 unsigned long first_page; /* first page number in csrow */
497 503 unsigned long last_page; /* last page number in csrow */
... ... @@ -517,15 +523,6 @@
517 523 const struct mcidev_sysfs_attribute *mcidev_attr; /* group attributes */
518 524 };
519 525  
520   -struct mcidev_sysfs_group_kobj {
521   - struct list_head list; /* list for all instances within a mc */
522   -
523   - struct kobject kobj; /* kobj for the group */
524   -
525   - const struct mcidev_sysfs_group *grp; /* group description table */
526   - struct mem_ctl_info *mci; /* the parent */
527   -};
528   -
529 526 /* mcidev_sysfs_attribute structure
530 527 * used for driver sysfs attributes and in mem_ctl_info
531 528 * sysfs top level entries
532 529  
533 530  
... ... @@ -536,13 +533,27 @@
536 533 const struct mcidev_sysfs_group *grp; /* Points to a group of attributes */
537 534  
538 535 /* Ops for show/store values at the attribute - not used on group */
539   - ssize_t (*show)(struct mem_ctl_info *,char *);
540   - ssize_t (*store)(struct mem_ctl_info *, const char *,size_t);
  536 + ssize_t (*show)(struct mem_ctl_info *, char *);
  537 + ssize_t (*store)(struct mem_ctl_info *, const char *, size_t);
  538 +
  539 + void *priv;
541 540 };
542 541  
  542 +/*
  543 + * struct errcount_attribute - used to store the several error counts
  544 + */
  545 +struct errcount_attribute_data {
  546 + int n_layers;
  547 + int pos[EDAC_MAX_LAYERS];
  548 + int layer0, layer1, layer2;
  549 +};
  550 +
543 551 /* MEMORY controller information structure
544 552 */
545 553 struct mem_ctl_info {
  554 + struct device dev;
  555 + struct bus_type bus;
  556 +
546 557 struct list_head link; /* for global list of mem_ctl_info structs */
547 558  
548 559 struct module *owner; /* Module owner of this control struct */
... ... @@ -587,7 +598,15 @@
587 598 struct csrow_info *csrows;
588 599 unsigned nr_csrows, num_cschannel;
589 600  
590   - /* Memory Controller hierarchy */
  601 + /*
  602 + * Memory Controller hierarchy
  603 + *
  604 + * There are basically two types of memory controller: the ones that
  605 + * sees memory sticks ("dimms"), and the ones that sees memory ranks.
  606 + * All old memory controllers enumerate memories per rank, but most
  607 + * of the recent drivers enumerate memories per DIMM, instead.
  608 + * When the memory controller is per rank, mem_is_per_rank is true.
  609 + */
591 610 unsigned n_layers;
592 611 struct edac_mc_layer *layers;
593 612 bool mem_is_per_rank;