aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/edac/edac_mc_sysfs.c
diff options
context:
space:
mode:
authorMauro Carvalho Chehab <mchehab@redhat.com>2012-04-16 15:41:11 -0400
committerMauro Carvalho Chehab <mchehab@redhat.com>2012-06-11 12:23:30 -0400
commit7a623c039075e4ea21648d88133fafa6dcfd113d (patch)
tree125ecf3c32161ca5242237ce177c79109b0a8caa /drivers/edac/edac_mc_sysfs.c
parentb0610bb82abd1c4ac97c33f0312cd7fd72eaa325 (diff)
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>
Diffstat (limited to 'drivers/edac/edac_mc_sysfs.c')
-rw-r--r--drivers/edac/edac_mc_sysfs.c1074
1 files changed, 407 insertions, 667 deletions
diff --git a/drivers/edac/edac_mc_sysfs.c b/drivers/edac/edac_mc_sysfs.c
index 595371941ef9..7002c9cab999 100644
--- a/drivers/edac/edac_mc_sysfs.c
+++ b/drivers/edac/edac_mc_sysfs.c
@@ -7,17 +7,20 @@
7 * 7 *
8 * Written Doug Thompson <norsk5@xmission.com> www.softwarebitmaker.com 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#include <linux/ctype.h> 15#include <linux/ctype.h>
13#include <linux/slab.h> 16#include <linux/slab.h>
14#include <linux/edac.h> 17#include <linux/edac.h>
15#include <linux/bug.h> 18#include <linux/bug.h>
19#include <linux/pm_runtime.h>
16 20
17#include "edac_core.h" 21#include "edac_core.h"
18#include "edac_module.h" 22#include "edac_module.h"
19 23
20
21/* MC EDAC Controls, setable by module parameter, and sysfs */ 24/* MC EDAC Controls, setable by module parameter, and sysfs */
22static int edac_mc_log_ue = 1; 25static int edac_mc_log_ue = 1;
23static int edac_mc_log_ce = 1; 26static int edac_mc_log_ce = 1;
@@ -78,6 +81,8 @@ module_param_call(edac_mc_poll_msec, edac_set_poll_msec, param_get_int,
78 &edac_mc_poll_msec, 0644); 81 &edac_mc_poll_msec, 0644);
79MODULE_PARM_DESC(edac_mc_poll_msec, "Polling period in milliseconds"); 82MODULE_PARM_DESC(edac_mc_poll_msec, "Polling period in milliseconds");
80 83
84static struct device mci_pdev;
85
81/* 86/*
82 * various constants for Memory Controllers 87 * various constants for Memory Controllers
83 */ 88 */
@@ -125,308 +130,336 @@ static const char *edac_caps[] = {
125 [EDAC_S16ECD16ED] = "S16ECD16ED" 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
135 */
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
129 */ 142 */
143#define DEVICE_ATTR_LEGACY(_name, _mode, _show, _store) \
144 struct device_attribute dev_attr_legacy_##_name = __ATTR(_name, _mode, _show, _store)
145
146struct 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)
130 156
131/* Set of more default csrow<id> attribute show/store functions */ 157/* Set of more default csrow<id> attribute show/store functions */
132static ssize_t csrow_ue_count_show(struct csrow_info *csrow, char *data, 158static ssize_t csrow_ue_count_show(struct device *dev,
133 int private) 159 struct device_attribute *mattr, char *data)
134{ 160{
161 struct csrow_info *csrow = to_csrow(dev);
162
135 return sprintf(data, "%u\n", csrow->ue_count); 163 return sprintf(data, "%u\n", csrow->ue_count);
136} 164}
137 165
138static ssize_t csrow_ce_count_show(struct csrow_info *csrow, char *data, 166static ssize_t csrow_ce_count_show(struct device *dev,
139 int private) 167 struct device_attribute *mattr, char *data)
140{ 168{
169 struct csrow_info *csrow = to_csrow(dev);
170
141 return sprintf(data, "%u\n", csrow->ce_count); 171 return sprintf(data, "%u\n", csrow->ce_count);
142} 172}
143 173
144static ssize_t csrow_size_show(struct csrow_info *csrow, char *data, 174static ssize_t csrow_size_show(struct device *dev,
145 int private) 175 struct device_attribute *mattr, char *data)
146{ 176{
177 struct csrow_info *csrow = to_csrow(dev);
147 int i; 178 int i;
148 u32 nr_pages = 0; 179 u32 nr_pages = 0;
149 180
150 for (i = 0; i < csrow->nr_channels; i++) 181 for (i = 0; i < csrow->nr_channels; i++)
151 nr_pages += csrow->channels[i].dimm->nr_pages; 182 nr_pages += csrow->channels[i].dimm->nr_pages;
152
153 return sprintf(data, "%u\n", PAGES_TO_MiB(nr_pages)); 183 return sprintf(data, "%u\n", PAGES_TO_MiB(nr_pages));
154} 184}
155 185
156static ssize_t csrow_mem_type_show(struct csrow_info *csrow, char *data, 186static ssize_t csrow_mem_type_show(struct device *dev,
157 int private) 187 struct device_attribute *mattr, char *data)
158{ 188{
189 struct csrow_info *csrow = to_csrow(dev);
190
159 return sprintf(data, "%s\n", mem_types[csrow->channels[0].dimm->mtype]); 191 return sprintf(data, "%s\n", mem_types[csrow->channels[0].dimm->mtype]);
160} 192}
161 193
162static ssize_t csrow_dev_type_show(struct csrow_info *csrow, char *data, 194static ssize_t csrow_dev_type_show(struct device *dev,
163 int private) 195 struct device_attribute *mattr, char *data)
164{ 196{
197 struct csrow_info *csrow = to_csrow(dev);
198
165 return sprintf(data, "%s\n", dev_types[csrow->channels[0].dimm->dtype]); 199 return sprintf(data, "%s\n", dev_types[csrow->channels[0].dimm->dtype]);
166} 200}
167 201
168static ssize_t csrow_edac_mode_show(struct csrow_info *csrow, char *data, 202static ssize_t csrow_edac_mode_show(struct device *dev,
169 int private) 203 struct device_attribute *mattr,
204 char *data)
170{ 205{
206 struct csrow_info *csrow = to_csrow(dev);
207
171 return sprintf(data, "%s\n", edac_caps[csrow->channels[0].dimm->edac_mode]); 208 return sprintf(data, "%s\n", edac_caps[csrow->channels[0].dimm->edac_mode]);
172} 209}
173 210
174/* show/store functions for DIMM Label attributes */ 211/* show/store functions for DIMM Label attributes */
175static ssize_t channel_dimm_label_show(struct csrow_info *csrow, 212static ssize_t channel_dimm_label_show(struct device *dev,
176 char *data, int channel) 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 /* if field has not been initialized, there is nothing to send */ 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 return 0; 222 return 0;
181 223
182 return snprintf(data, EDAC_MC_LABEL_LEN, "%s\n", 224 return snprintf(data, EDAC_MC_LABEL_LEN, "%s\n",
183 csrow->channels[channel].dimm->label); 225 rank->dimm->label);
184} 226}
185 227
186static ssize_t channel_dimm_label_store(struct csrow_info *csrow, 228static ssize_t channel_dimm_label_store(struct device *dev,
187 const char *data, 229 struct device_attribute *mattr,
188 size_t count, int channel) 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 ssize_t max_size = 0; 236 ssize_t max_size = 0;
191 237
192 max_size = min((ssize_t) count, (ssize_t) EDAC_MC_LABEL_LEN - 1); 238 max_size = min((ssize_t) count, (ssize_t) EDAC_MC_LABEL_LEN - 1);
193 strncpy(csrow->channels[channel].dimm->label, data, max_size); 239 strncpy(rank->dimm->label, data, max_size);
194 csrow->channels[channel].dimm->label[max_size] = '\0'; 240 rank->dimm->label[max_size] = '\0';
195 241
196 return max_size; 242 return max_size;
197} 243}
198 244
199/* show function for dynamic chX_ce_count attribute */ 245/* show function for dynamic chX_ce_count attribute */
200static ssize_t channel_ce_count_show(struct csrow_info *csrow, 246static ssize_t channel_ce_count_show(struct device *dev,
201 char *data, int channel) 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 */ 256/* cwrow<id>/attribute files */
207struct csrowdev_attribute { 257DEVICE_ATTR_LEGACY(size_mb, S_IRUGO, csrow_size_show, NULL);
208 struct attribute attr; 258DEVICE_ATTR_LEGACY(dev_type, S_IRUGO, csrow_dev_type_show, NULL);
209 ssize_t(*show) (struct csrow_info *, char *, int); 259DEVICE_ATTR_LEGACY(mem_type, S_IRUGO, csrow_mem_type_show, NULL);
210 ssize_t(*store) (struct csrow_info *, const char *, size_t, int); 260DEVICE_ATTR_LEGACY(edac_mode, S_IRUGO, csrow_edac_mode_show, NULL);
211 int private; 261DEVICE_ATTR_LEGACY(ue_count, S_IRUGO, csrow_ue_count_show, NULL);
212}; 262DEVICE_ATTR_LEGACY(ce_count, S_IRUGO, csrow_ce_count_show, NULL);
213 263
214#define to_csrow(k) container_of(k, struct csrow_info, kobj) 264/* default attributes of the CSROW<id> object */
215#define to_csrowdev_attr(a) container_of(a, struct csrowdev_attribute, attr) 265static 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,
273};
216 274
217/* Set of show/store higher level functions for default csrow attributes */ 275static struct attribute_group csrow_attr_grp = {
218static ssize_t csrowdev_show(struct kobject *kobj, 276 .attrs = csrow_attrs,
219 struct attribute *attr, char *buffer) 277};
220{
221 struct csrow_info *csrow = to_csrow(kobj);
222 struct csrowdev_attribute *csrowdev_attr = to_csrowdev_attr(attr);
223 278
224 if (csrowdev_attr->show) 279static const struct attribute_group *csrow_attr_groups[] = {
225 return csrowdev_attr->show(csrow, 280 &csrow_attr_grp,
226 buffer, csrowdev_attr->private); 281 NULL
227 return -EIO; 282};
228}
229 283
230static ssize_t csrowdev_store(struct kobject *kobj, struct attribute *attr, 284static void csrow_attr_release(struct device *device)
231 const char *buffer, size_t count)
232{ 285{
233 struct csrow_info *csrow = to_csrow(kobj); 286 debugf1("Releasing csrow device %s\n", dev_name(device));
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;
241} 287}
242 288
243static const struct sysfs_ops csrowfs_ops = { 289static struct device_type csrow_attr_type = {
244 .show = csrowdev_show, 290 .groups = csrow_attr_groups,
245 .store = csrowdev_store 291 .release = csrow_attr_release,
246}; 292};
247 293
248#define CSROWDEV_ATTR(_name,_mode,_show,_store,_private) \ 294/*
249static struct csrowdev_attribute attr_##_name = { \ 295 * possible dynamic channel DIMM Label attribute files
250 .attr = {.name = __stringify(_name), .mode = _mode }, \ 296 *
251 .show = _show, \ 297 */
252 .store = _store, \
253 .private = _private, \
254};
255
256/* default cwrow<id>/attribute files */
257CSROWDEV_ATTR(size_mb, S_IRUGO, csrow_size_show, NULL, 0);
258CSROWDEV_ATTR(dev_type, S_IRUGO, csrow_dev_type_show, NULL, 0);
259CSROWDEV_ATTR(mem_type, S_IRUGO, csrow_mem_type_show, NULL, 0);
260CSROWDEV_ATTR(edac_mode, S_IRUGO, csrow_edac_mode_show, NULL, 0);
261CSROWDEV_ATTR(ue_count, S_IRUGO, csrow_ue_count_show, NULL, 0);
262CSROWDEV_ATTR(ce_count, S_IRUGO, csrow_ce_count_show, NULL, 0);
263 298
264/* default attributes of the CSROW<id> object */ 299#define EDAC_NR_CHANNELS 6
265static 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 300
275/* possible dynamic channel DIMM Label attribute files */ 301DEVICE_CHANNEL(ch0_dimm_label, S_IRUGO | S_IWUSR,
276CSROWDEV_ATTR(ch0_dimm_label, S_IRUGO | S_IWUSR,
277 channel_dimm_label_show, channel_dimm_label_store, 0); 302 channel_dimm_label_show, channel_dimm_label_store, 0);
278CSROWDEV_ATTR(ch1_dimm_label, S_IRUGO | S_IWUSR, 303DEVICE_CHANNEL(ch1_dimm_label, S_IRUGO | S_IWUSR,
279 channel_dimm_label_show, channel_dimm_label_store, 1); 304 channel_dimm_label_show, channel_dimm_label_store, 1);
280CSROWDEV_ATTR(ch2_dimm_label, S_IRUGO | S_IWUSR, 305DEVICE_CHANNEL(ch2_dimm_label, S_IRUGO | S_IWUSR,
281 channel_dimm_label_show, channel_dimm_label_store, 2); 306 channel_dimm_label_show, channel_dimm_label_store, 2);
282CSROWDEV_ATTR(ch3_dimm_label, S_IRUGO | S_IWUSR, 307DEVICE_CHANNEL(ch3_dimm_label, S_IRUGO | S_IWUSR,
283 channel_dimm_label_show, channel_dimm_label_store, 3); 308 channel_dimm_label_show, channel_dimm_label_store, 3);
284CSROWDEV_ATTR(ch4_dimm_label, S_IRUGO | S_IWUSR, 309DEVICE_CHANNEL(ch4_dimm_label, S_IRUGO | S_IWUSR,
285 channel_dimm_label_show, channel_dimm_label_store, 4); 310 channel_dimm_label_show, channel_dimm_label_store, 4);
286CSROWDEV_ATTR(ch5_dimm_label, S_IRUGO | S_IWUSR, 311DEVICE_CHANNEL(ch5_dimm_label, S_IRUGO | S_IWUSR,
287 channel_dimm_label_show, channel_dimm_label_store, 5); 312 channel_dimm_label_show, channel_dimm_label_store, 5);
288 313
289/* Total possible dynamic DIMM Label attribute file table */ 314/* Total possible dynamic DIMM Label attribute file table */
290static struct csrowdev_attribute *dynamic_csrow_dimm_attr[] = { 315static struct device_attribute *dynamic_csrow_dimm_attr[] = {
291 &attr_ch0_dimm_label, 316 &dev_attr_legacy_ch0_dimm_label.attr,
292 &attr_ch1_dimm_label, 317 &dev_attr_legacy_ch1_dimm_label.attr,
293 &attr_ch2_dimm_label, 318 &dev_attr_legacy_ch2_dimm_label.attr,
294 &attr_ch3_dimm_label, 319 &dev_attr_legacy_ch3_dimm_label.attr,
295 &attr_ch4_dimm_label, 320 &dev_attr_legacy_ch4_dimm_label.attr,
296 &attr_ch5_dimm_label 321 &dev_attr_legacy_ch5_dimm_label.attr
297}; 322};
298 323
299/* possible dynamic channel ce_count attribute files */ 324/* possible dynamic channel ce_count attribute files */
300CSROWDEV_ATTR(ch0_ce_count, S_IRUGO | S_IWUSR, channel_ce_count_show, NULL, 0); 325DEVICE_CHANNEL(ch0_ce_count, S_IRUGO | S_IWUSR,
301CSROWDEV_ATTR(ch1_ce_count, S_IRUGO | S_IWUSR, channel_ce_count_show, NULL, 1); 326 channel_ce_count_show, NULL, 0);
302CSROWDEV_ATTR(ch2_ce_count, S_IRUGO | S_IWUSR, channel_ce_count_show, NULL, 2); 327DEVICE_CHANNEL(ch1_ce_count, S_IRUGO | S_IWUSR,
303CSROWDEV_ATTR(ch3_ce_count, S_IRUGO | S_IWUSR, channel_ce_count_show, NULL, 3); 328 channel_ce_count_show, NULL, 1);
304CSROWDEV_ATTR(ch4_ce_count, S_IRUGO | S_IWUSR, channel_ce_count_show, NULL, 4); 329DEVICE_CHANNEL(ch2_ce_count, S_IRUGO | S_IWUSR,
305CSROWDEV_ATTR(ch5_ce_count, S_IRUGO | S_IWUSR, channel_ce_count_show, NULL, 5); 330 channel_ce_count_show, NULL, 2);
331DEVICE_CHANNEL(ch3_ce_count, S_IRUGO | S_IWUSR,
332 channel_ce_count_show, NULL, 3);
333DEVICE_CHANNEL(ch4_ce_count, S_IRUGO | S_IWUSR,
334 channel_ce_count_show, NULL, 4);
335DEVICE_CHANNEL(ch5_ce_count, S_IRUGO | S_IWUSR,
336 channel_ce_count_show, NULL, 5);
306 337
307/* Total possible dynamic ce_count attribute file table */ 338/* Total possible dynamic ce_count attribute file table */
308static struct csrowdev_attribute *dynamic_csrow_ce_count_attr[] = { 339static struct device_attribute *dynamic_csrow_ce_count_attr[] = {
309 &attr_ch0_ce_count, 340 &dev_attr_legacy_ch0_ce_count.attr,
310 &attr_ch1_ce_count, 341 &dev_attr_legacy_ch1_ce_count.attr,
311 &attr_ch2_ce_count, 342 &dev_attr_legacy_ch2_ce_count.attr,
312 &attr_ch3_ce_count, 343 &dev_attr_legacy_ch3_ce_count.attr,
313 &attr_ch4_ce_count, 344 &dev_attr_legacy_ch4_ce_count.attr,
314 &attr_ch5_ce_count 345 &dev_attr_legacy_ch5_ce_count.attr
315}; 346};
316 347
317#define EDAC_NR_CHANNELS 6 348/* Create a CSROW object under specifed edac_mc_device */
318 349static int edac_create_csrow_object(struct mem_ctl_info *mci,
319/* Create dynamic CHANNEL files, indexed by 'chan', under specifed CSROW */ 350 struct csrow_info *csrow, int index)
320static int edac_create_channel_files(struct kobject *kobj, int chan)
321{ 351{
322 int err = -ENODEV; 352 int err, chan;
323 353
324 if (chan >= EDAC_NR_CHANNELS) 354 if (csrow->nr_channels >= EDAC_NR_CHANNELS)
325 return err; 355 return -ENODEV;
326 356
327 /* create the DIMM label attribute file */ 357 csrow->dev.type = &csrow_attr_type;
328 err = sysfs_create_file(kobj, 358 csrow->dev.bus = &mci->bus;
329 (struct attribute *) 359 device_initialize(&csrow->dev);
330 dynamic_csrow_dimm_attr[chan]); 360 csrow->dev.parent = &mci->dev;
331 361 dev_set_name(&csrow->dev, "csrow%d", index);
332 if (!err) { 362 dev_set_drvdata(&csrow->dev, csrow);
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 }
341 363
342 return err; 364 debugf0("%s(): creating (virtual) csrow node %s\n", __func__,
343} 365 dev_name(&csrow->dev));
344 366
345/* No memory to release for this kobj */ 367 err = device_add(&csrow->dev);
346static void edac_csrow_instance_release(struct kobject *kobj) 368 if (err < 0)
347{ 369 return err;
348 struct mem_ctl_info *mci;
349 struct csrow_info *cs;
350 370
351 debugf1("%s()\n", __func__); 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 }
352 384
353 cs = container_of(kobj, struct csrow_info, kobj); 385 return 0;
354 mci = cs->mci;
355 386
356 kobject_put(&mci->edac_mci_kobj); 387error:
357} 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);
358 395
359/* the kobj_type instance for a CSROW */ 396 return err;
360static struct kobj_type ktype_csrow = { 397}
361 .release = edac_csrow_instance_release,
362 .sysfs_ops = &csrowfs_ops,
363 .default_attrs = (struct attribute **)default_csrow_attr,
364};
365 398
366/* Create a CSROW object under specifed edac_mc_device */ 399/* Create a CSROW object under specifed edac_mc_device */
367static int edac_create_csrow_object(struct mem_ctl_info *mci, 400static int edac_create_csrow_objects(struct mem_ctl_info *mci)
368 struct csrow_info *csrow, int index)
369{ 401{
370 struct kobject *kobj_mci = &mci->edac_mci_kobj; 402 int err, i, chan;
371 struct kobject *kobj; 403 struct csrow_info *csrow;
372 int chan;
373 int err;
374 404
375 /* generate ..../edac/mc/mc<id>/csrow<index> */ 405 for (i = 0; i < mci->nr_csrows; i++) {
376 memset(&csrow->kobj, 0, sizeof(csrow->kobj)); 406 err = edac_create_csrow_object(mci, &mci->csrows[i], i);
377 csrow->mci = mci; /* include container up link */ 407 if (err < 0)
408 goto error;
409 }
410 return 0;
378 411
379 /* bump the mci instance's kobject's ref count */ 412error:
380 kobj = kobject_get(&mci->edac_mci_kobj); 413 for (--i; i >= 0; i--) {
381 if (!kobj) { 414 csrow = &mci->csrows[i];
382 err = -ENODEV; 415 for (chan = csrow->nr_channels - 1; chan >= 0; chan--) {
383 goto err_out; 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 */ 424 return err;
387 err = kobject_init_and_add(&csrow->kobj, &ktype_csrow, kobj_mci, 425}
388 "csrow%d", index);
389 if (err)
390 goto err_release_top_kobj;
391 426
392 /* At this point, to release a csrow kobj, one must 427static void edac_delete_csrow_objects(struct mem_ctl_info *mci)
393 * call the kobject_put and allow that tear down 428{
394 * to work the releasing 429 int i, chan;
395 */ 430 struct csrow_info *csrow;
396 431
397 /* Create the dyanmic attribute files on this csrow, 432 for (i = mci->nr_csrows - 1; i >= 0; i--) {
398 * namely, the DIMM labels and the channel ce_count 433 csrow = &mci->csrows[i];
399 */ 434 for (chan = csrow->nr_channels - 1; chan >= 0; chan--) {
400 for (chan = 0; chan < csrow->nr_channels; chan++) { 435 debugf1("Removing csrow %d channel %d sysfs nodes\n",
401 err = edac_create_channel_files(&csrow->kobj, chan); 436 i, chan);
402 if (err) { 437 device_remove_file(&csrow->dev,
403 /* special case the unregister here */ 438 dynamic_csrow_dimm_attr[chan]);
404 kobject_put(&csrow->kobj); 439 device_remove_file(&csrow->dev,
405 goto err_out; 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 */
412err_release_top_kobj:
413 kobject_put(&mci->edac_mci_kobj);
414
415err_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 */
450
451#define to_mci(k) container_of(k, struct mem_ctl_info, dev)
420 452
421static ssize_t mci_reset_counters_store(struct mem_ctl_info *mci, 453static ssize_t mci_reset_counters_store(struct device *dev,
454 struct device_attribute *mattr,
422 const char *data, size_t count) 455 const char *data, size_t count)
423{ 456{
424 int row, chan; 457 struct mem_ctl_info *mci = to_mci(dev);
425 458 int cnt, row, chan, i;
426 mci->ue_noinfo_count = 0;
427 mci->ce_noinfo_count = 0;
428 mci->ue_mc = 0; 459 mci->ue_mc = 0;
429 mci->ce_mc = 0; 460 mci->ce_mc = 0;
461 mci->ue_noinfo_count = 0;
462 mci->ce_noinfo_count = 0;
430 463
431 for (row = 0; row < mci->nr_csrows; row++) { 464 for (row = 0; row < mci->nr_csrows; row++) {
432 struct csrow_info *ri = &mci->csrows[row]; 465 struct csrow_info *ri = &mci->csrows[row];
@@ -438,6 +471,13 @@ static ssize_t mci_reset_counters_store(struct mem_ctl_info *mci,
438 ri->channels[chan].ce_count = 0; 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 mci->start_time = jiffies; 481 mci->start_time = jiffies;
442 return count; 482 return count;
443} 483}
@@ -451,9 +491,11 @@ static ssize_t mci_reset_counters_store(struct mem_ctl_info *mci,
451 * Negative value still means that an error has occurred while setting 491 * Negative value still means that an error has occurred while setting
452 * the scrub rate. 492 * the scrub rate.
453 */ 493 */
454static ssize_t mci_sdram_scrub_rate_store(struct mem_ctl_info *mci, 494static ssize_t mci_sdram_scrub_rate_store(struct device *dev,
495 struct device_attribute *mattr,
455 const char *data, size_t count) 496 const char *data, size_t count)
456{ 497{
498 struct mem_ctl_info *mci = to_mci(dev);
457 unsigned long bandwidth = 0; 499 unsigned long bandwidth = 0;
458 int new_bw = 0; 500 int new_bw = 0;
459 501
@@ -476,8 +518,11 @@ static ssize_t mci_sdram_scrub_rate_store(struct mem_ctl_info *mci,
476/* 518/*
477 * ->get_sdram_scrub_rate() return value semantics same as above. 519 * ->get_sdram_scrub_rate() return value semantics same as above.
478 */ 520 */
479static ssize_t mci_sdram_scrub_rate_show(struct mem_ctl_info *mci, char *data) 521static 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 int bandwidth = 0; 526 int bandwidth = 0;
482 527
483 if (!mci->get_sdram_scrub_rate) 528 if (!mci->get_sdram_scrub_rate)
@@ -493,38 +538,65 @@ static ssize_t mci_sdram_scrub_rate_show(struct mem_ctl_info *mci, char *data)
493} 538}
494 539
495/* default attribute files for the MCI object */ 540/* default attribute files for the MCI object */
496static ssize_t mci_ue_count_show(struct mem_ctl_info *mci, char *data) 541static 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 return sprintf(data, "%d\n", mci->ue_mc); 547 return sprintf(data, "%d\n", mci->ue_mc);
499} 548}
500 549
501static ssize_t mci_ce_count_show(struct mem_ctl_info *mci, char *data) 550static 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 return sprintf(data, "%d\n", mci->ce_mc); 556 return sprintf(data, "%d\n", mci->ce_mc);
504} 557}
505 558
506static ssize_t mci_ce_noinfo_show(struct mem_ctl_info *mci, char *data) 559static 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 return sprintf(data, "%d\n", mci->ce_noinfo_count); 565 return sprintf(data, "%d\n", mci->ce_noinfo_count);
509} 566}
510 567
511static ssize_t mci_ue_noinfo_show(struct mem_ctl_info *mci, char *data) 568static 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 return sprintf(data, "%d\n", mci->ue_noinfo_count); 574 return sprintf(data, "%d\n", mci->ue_noinfo_count);
514} 575}
515 576
516static ssize_t mci_seconds_show(struct mem_ctl_info *mci, char *data) 577static 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 return sprintf(data, "%ld\n", (jiffies - mci->start_time) / HZ); 583 return sprintf(data, "%ld\n", (jiffies - mci->start_time) / HZ);
519} 584}
520 585
521static ssize_t mci_ctl_name_show(struct mem_ctl_info *mci, char *data) 586static 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 return sprintf(data, "%s\n", mci->ctl_name); 592 return sprintf(data, "%s\n", mci->ctl_name);
524} 593}
525 594
526static ssize_t mci_size_mb_show(struct mem_ctl_info *mci, char *data) 595static 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 int total_pages = 0, csrow_idx, j; 600 int total_pages = 0, csrow_idx, j;
529 601
530 for (csrow_idx = 0; csrow_idx < mci->nr_csrows; csrow_idx++) { 602 for (csrow_idx = 0; csrow_idx < mci->nr_csrows; csrow_idx++) {
@@ -540,360 +612,53 @@ static ssize_t mci_size_mb_show(struct mem_ctl_info *mci, char *data)
540 return sprintf(data, "%u\n", PAGES_TO_MiB(total_pages)); 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 */
547static 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
561static 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 */
576static const struct sysfs_ops mci_ops = {
577 .show = mcidev_show,
578 .store = mcidev_store
579};
580
581#define MCIDEV_ATTR(_name,_mode,_show,_store) \
582static struct mcidev_sysfs_attribute mci_attr_##_name = { \
583 .attr = {.name = __stringify(_name), .mode = _mode }, \
584 .show = _show, \
585 .store = _store, \
586};
587
588/* default Control file */ 615/* default Control file */
589MCIDEV_ATTR(reset_counters, S_IWUSR, NULL, mci_reset_counters_store); 616DEVICE_ATTR(reset_counters, S_IWUSR, NULL, mci_reset_counters_store);
590 617
591/* default Attribute files */ 618/* default Attribute files */
592MCIDEV_ATTR(mc_name, S_IRUGO, mci_ctl_name_show, NULL); 619DEVICE_ATTR(mc_name, S_IRUGO, mci_ctl_name_show, NULL);
593MCIDEV_ATTR(size_mb, S_IRUGO, mci_size_mb_show, NULL); 620DEVICE_ATTR(size_mb, S_IRUGO, mci_size_mb_show, NULL);
594MCIDEV_ATTR(seconds_since_reset, S_IRUGO, mci_seconds_show, NULL); 621DEVICE_ATTR(seconds_since_reset, S_IRUGO, mci_seconds_show, NULL);
595MCIDEV_ATTR(ue_noinfo_count, S_IRUGO, mci_ue_noinfo_show, NULL); 622DEVICE_ATTR(ue_noinfo_count, S_IRUGO, mci_ue_noinfo_show, NULL);
596MCIDEV_ATTR(ce_noinfo_count, S_IRUGO, mci_ce_noinfo_show, NULL); 623DEVICE_ATTR(ce_noinfo_count, S_IRUGO, mci_ce_noinfo_show, NULL);
597MCIDEV_ATTR(ue_count, S_IRUGO, mci_ue_count_show, NULL); 624DEVICE_ATTR(ue_count, S_IRUGO, mci_ue_count_show, NULL);
598MCIDEV_ATTR(ce_count, S_IRUGO, mci_ce_count_show, NULL); 625DEVICE_ATTR(ce_count, S_IRUGO, mci_ce_count_show, NULL);
599 626
600/* memory scrubber attribute file */ 627/* memory scrubber attribute file */
601MCIDEV_ATTR(sdram_scrub_rate, S_IRUGO | S_IWUSR, mci_sdram_scrub_rate_show, 628DEVICE_ATTR(sdram_scrub_rate, S_IRUGO | S_IWUSR, mci_sdram_scrub_rate_show,
602 mci_sdram_scrub_rate_store); 629 mci_sdram_scrub_rate_store);
603 630
604static struct mcidev_sysfs_attribute *mci_attr[] = { 631static struct attribute *mci_attrs[] = {
605 &mci_attr_reset_counters, 632 &dev_attr_reset_counters.attr,
606 &mci_attr_mc_name, 633 &dev_attr_mc_name.attr,
607 &mci_attr_size_mb, 634 &dev_attr_size_mb.attr,
608 &mci_attr_seconds_since_reset, 635 &dev_attr_seconds_since_reset.attr,
609 &mci_attr_ue_noinfo_count, 636 &dev_attr_ue_noinfo_count.attr,
610 &mci_attr_ce_noinfo_count, 637 &dev_attr_ce_noinfo_count.attr,
611 &mci_attr_ue_count, 638 &dev_attr_ue_count.attr,
612 &mci_attr_ce_count, 639 &dev_attr_ce_count.attr,
613 &mci_attr_sdram_scrub_rate, 640 &dev_attr_sdram_scrub_rate.attr,
614 NULL 641 NULL
615}; 642};
616 643
617 644static struct attribute_group mci_attr_grp = {
618/* 645 .attrs = mci_attrs,
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 */
628static 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
640static struct kobj_type ktype_mci = {
641 .release = edac_mci_control_release,
642 .sysfs_ops = &mci_ops,
643 .default_attrs = (struct attribute **)mci_attr,
644};
645
646/* EDAC memory controller sysfs kset:
647 * /sys/devices/system/edac/mc
648 */
649static 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 */
656int edac_mc_register_sysfs_main_kobj(struct mem_ctl_info *mci)
657{
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
703kobj_reg_fail:
704 module_put(mci->owner);
705
706fail_out:
707 return err;
708}
709
710/*
711 * edac_mc_register_sysfs_main_kobj
712 *
713 * tears down and the main mci kobject from the mc_kset
714 */
715void 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 */
728static 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
742static 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 */
757static 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 */
769static struct sysfs_ops inst_grp_ops = {
770 .show = inst_grp_show,
771 .store = inst_grp_store
772}; 646};
773 647
774/* the kobj_type instance for a instance group */ 648static const struct attribute_group *mci_attr_groups[] = {
775static struct kobj_type ktype_inst_grp = { 649 &mci_attr_grp,
776 .release = edac_inst_grp_release, 650 NULL
777 .sysfs_ops = &inst_grp_ops,
778}; 651};
779 652
780 653static void mci_attr_release(struct device *device)
781/*
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 */
787static int edac_create_mci_instance_attributes(struct mem_ctl_info *mci,
788 const struct mcidev_sysfs_attribute *sysfs_attrib,
789 struct kobject *kobj)
790{ 654{
791 int err; 655 debugf1("Releasing mci device %s\n", dev_name(device));
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} 656}
842 657
843/* 658static struct device_type mci_attr_type = {
844 * edac_remove_mci_instance_attributes 659 .groups = mci_attr_groups,
845 * remove MC driver specific attributes at the topmost level 660 .release = mci_attr_release,
846 * directory of this mci instance. 661};
847 */
848static 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 662
898 663
899/* 664/*
@@ -906,77 +671,80 @@ static void edac_remove_mci_instance_attributes(struct mem_ctl_info *mci,
906 */ 671 */
907int edac_create_sysfs_mci_device(struct mem_ctl_info *mci) 672int edac_create_sysfs_mci_device(struct mem_ctl_info *mci)
908{ 673{
909 int i, j; 674 int i, err;
910 int err;
911 struct csrow_info *csrow;
912 struct kobject *kobj_mci = &mci->edac_mci_kobj;
913 675
914 debugf0("%s() idx=%d\n", __func__, mci->mc_idx); 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 */ 680 mci->dev.type = &mci_attr_type;
919 err = sysfs_create_link(kobj_mci, &mci->pdev->kobj, 681 device_initialize(&mci->dev);
920 EDAC_DEVICE_SYMLINK);
921 if (err) {
922 debugf1("%s() failure to create symlink\n", __func__);
923 goto fail0;
924 }
925 682
926 /* If the low level driver desires some attributes, 683 mci->dev.parent = &mci_pdev;
927 * then create them now for the driver. 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);
688
689 /*
690 * The memory controller needs its own bus, in order to avoid
691 * namespace conflicts at /sys/bus/edac.
928 */ 692 */
929 if (mci->mc_driver_sysfs_attributes) { 693 debugf0("creating bus %s\n",mci->bus.name);
930 err = edac_create_mci_instance_attributes(mci, 694 mci->bus.name = kstrdup(dev_name(&mci->dev), GFP_KERNEL);
931 mci->mc_driver_sysfs_attributes, 695 err = bus_register(&mci->bus);
932 &mci->edac_mci_kobj); 696 if (err < 0)
933 if (err) { 697 return err;
934 debugf1("%s() failure to create mci attributes\n", 698
935 __func__); 699 debugf0("%s(): creating device %s\n", __func__,
936 goto fail0; 700 dev_name(&mci->dev));
937 } 701 err = device_add(&mci->dev);
702 if (err < 0) {
703 bus_unregister(&mci->bus);
704 kfree(mci->bus.name);
705 return err;
938 } 706 }
939 707
940 /* Make directories for each CSROW object under the mc<id> kobject 708 /*
709 * Create the dimm/rank devices
941 */ 710 */
942 for (i = 0; i < mci->nr_csrows; i++) { 711 for (i = 0; i < mci->tot_dimms; i++) {
943 int nr_pages = 0; 712 struct dimm_info *dimm = &mci->dimms[i];
944 713 /* Only expose populated DIMMs */
945 csrow = &mci->csrows[i]; 714 if (dimm->nr_pages == 0)
946 for (j = 0; j < csrow->nr_channels; j++) 715 continue;
947 nr_pages += csrow->channels[j].dimm->nr_pages; 716#ifdef CONFIG_EDAC_DEBUG
948 717 debugf1("%s creating dimm%d, located at ",
949 if (nr_pages > 0) { 718 __func__, i);
950 err = edac_create_csrow_object(mci, csrow, i); 719 if (edac_debug_level >= 1) {
951 if (err) { 720 int lay;
952 debugf1("%s() failure: create csrow %d obj\n", 721 for (lay = 0; lay < mci->n_layers; lay++)
953 __func__, i); 722 printk(KERN_CONT "%s %d ",
954 goto fail1; 723 edac_layer_name[mci->layers[lay].type],
955 } 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 return 0; 734 return 0;
960 735
961fail1: 736fail:
962 for (i--; i >= 0; i--) { 737 for (i--; i >= 0; i--) {
963 int nr_pages = 0; 738 struct dimm_info *dimm = &mci->dimms[i];
964 739 if (dimm->nr_pages == 0)
965 csrow = &mci->csrows[i]; 740 continue;
966 for (j = 0; j < csrow->nr_channels; j++) 741 put_device(&dimm->dev);
967 nr_pages += csrow->channels[j].dimm->nr_pages; 742 device_del(&dimm->dev);
968 if (nr_pages > 0)
969 kobject_put(&mci->csrows[i].kobj);
970 } 743 }
971 744 put_device(&mci->dev);
972 /* remove the mci instance's attributes, if any */ 745 device_del(&mci->dev);
973 edac_remove_mci_instance_attributes(mci, 746 bus_unregister(&mci->bus);
974 mci->mc_driver_sysfs_attributes, &mci->edac_mci_kobj, 0); 747 kfree(mci->bus.name);
975
976 /* remove the symlink */
977 sysfs_remove_link(kobj_mci, EDAC_DEVICE_SYMLINK);
978
979fail0:
980 return err; 748 return err;
981} 749}
982 750
@@ -985,98 +753,70 @@ fail0:
985 */ 753 */
986void edac_remove_sysfs_mci_device(struct mem_ctl_info *mci) 754void edac_remove_sysfs_mci_device(struct mem_ctl_info *mci)
987{ 755{
988 struct csrow_info *csrow; 756 int i;
989 int i, j;
990 757
991 debugf0("%s()\n", __func__); 758 debugf0("%s()\n", __func__);
992 759
993 /* remove all csrow kobjects */ 760 edac_delete_csrow_objects(mci);
994 debugf4("%s() unregister this mci kobj\n", __func__);
995 for (i = 0; i < mci->nr_csrows; i++) {
996 int nr_pages = 0;
997
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 }
1005 }
1006 761
1007 /* remove this mci instance's attribtes */ 762 for (i = 0; i < mci->tot_dimms; i++) {
1008 if (mci->mc_driver_sysfs_attributes) { 763 struct dimm_info *dimm = &mci->dimms[i];
1009 debugf4("%s() unregister mci private attributes\n", __func__); 764 if (dimm->nr_pages == 0)
1010 edac_remove_mci_instance_attributes(mci, 765 continue;
1011 mci->mc_driver_sysfs_attributes, 766 debugf0("%s(): removing device %s\n", __func__,
1012 &mci->edac_mci_kobj, 0); 767 dev_name(&dimm->dev));
768 put_device(&dimm->dev);
769 device_del(&dimm->dev);
1013 } 770 }
1014
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);
1022} 771}
1023 772
773void 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}
1024 781
782static void mc_attr_release(struct device *device)
783{
784 debugf1("Releasing device %s\n", dev_name(device));
785}
1025 786
1026 787static struct device_type mc_attr_type = {
788 .release = mc_attr_release,
789};
1027/* 790/*
1028 * edac_setup_sysfs_mc_kset(void) 791 * Init/exit code for the module. Basically, creates/removes /sys/class/rc
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
1038 */ 792 */
1039int edac_sysfs_setup_mc_kset(void) 793int __init edac_mc_sysfs_init(void)
1040{ 794{
1041 int err = -EINVAL;
1042 struct bus_type *edac_subsys; 795 struct bus_type *edac_subsys;
1043 796 int err;
1044 debugf1("%s()\n", __func__);
1045 797
1046 /* get the /sys/devices/system/edac subsys reference */ 798 /* get the /sys/devices/system/edac subsys reference */
1047 edac_subsys = edac_get_sysfs_subsys(); 799 edac_subsys = edac_get_sysfs_subsys();
1048 if (edac_subsys == NULL) { 800 if (edac_subsys == NULL) {
1049 debugf1("%s() no edac_subsys error=%d\n", __func__, err); 801 debugf1("%s() no edac_subsys\n", __func__);
1050 goto fail_out; 802 return -EINVAL;
1051 } 803 }
1052 804
1053 /* Init the MC's kobject */ 805 mci_pdev.bus = edac_subsys;
1054 mc_kset = kset_create_and_add("mc", NULL, &edac_subsys->dev_root->kobj); 806 mci_pdev.type = &mc_attr_type;
1055 if (!mc_kset) { 807 device_initialize(&mci_pdev);
1056 err = -ENOMEM; 808 dev_set_name(&mci_pdev, "mc");
1057 debugf1("%s() Failed to register '.../edac/mc'\n", __func__);
1058 goto fail_kset;
1059 }
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 return 0; 814 return 0;
1064
1065fail_kset:
1066 edac_put_sysfs_subsys();
1067
1068fail_out:
1069 return err;
1070} 815}
1071 816
1072/* 817void __exit edac_mc_sysfs_exit(void)
1073 * edac_sysfs_teardown_mc_kset
1074 *
1075 * deconstruct the mc_ket for memory controllers
1076 */
1077void edac_sysfs_teardown_mc_kset(void)
1078{ 818{
1079 kset_unregister(mc_kset); 819 put_device(&mci_pdev);
820 device_del(&mci_pdev);
1080 edac_put_sysfs_subsys(); 821 edac_put_sysfs_subsys();
1081} 822}
1082