edac_mc_sysfs.c 23.2 KB
Newer Older
1 2
/*
 * edac_mc kernel module
3 4
 * (C) 2005-2007 Linux Networx (http://lnxi.com)
 *
5 6 7
 * This file may be distributed under the terms of the
 * GNU General Public License.
 *
8
 * Written Doug Thompson <norsk5@xmission.com> www.softwarebitmaker.com
9 10 11 12
 *
 */

#include <linux/ctype.h>
13
#include <linux/bug.h>
14

15
#include "edac_core.h"
16 17
#include "edac_module.h"

18

19
/* MC EDAC Controls, setable by module parameter, and sysfs */
D
Dave Jiang 已提交
20 21
static int edac_mc_log_ue = 1;
static int edac_mc_log_ce = 1;
22
static int edac_mc_panic_on_ue;
D
Dave Jiang 已提交
23
static int edac_mc_poll_msec = 1000;
24 25

/* Getter functions for above */
D
Dave Jiang 已提交
26
int edac_mc_get_log_ue(void)
27
{
D
Dave Jiang 已提交
28
	return edac_mc_log_ue;
29 30
}

D
Dave Jiang 已提交
31
int edac_mc_get_log_ce(void)
32
{
D
Dave Jiang 已提交
33
	return edac_mc_log_ce;
34 35
}

D
Dave Jiang 已提交
36
int edac_mc_get_panic_on_ue(void)
37
{
D
Dave Jiang 已提交
38
	return edac_mc_panic_on_ue;
39 40
}

41 42 43
/* this is temporary */
int edac_mc_get_poll_msec(void)
{
D
Dave Jiang 已提交
44
	return edac_mc_poll_msec;
45 46
}

A
Arthur Jones 已提交
47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
static int edac_set_poll_msec(const char *val, struct kernel_param *kp)
{
	long l;
	int ret;

	if (!val)
		return -EINVAL;

	ret = strict_strtol(val, 0, &l);
	if (ret == -EINVAL || ((int)l != l))
		return -EINVAL;
	*((int *)kp->arg) = l;

	/* notify edac_mc engine to reset the poll period */
	edac_mc_reset_delay_period(l);

	return 0;
}

66
/* Parameter declarations for above */
D
Dave Jiang 已提交
67 68 69 70
module_param(edac_mc_panic_on_ue, int, 0644);
MODULE_PARM_DESC(edac_mc_panic_on_ue, "Panic on uncorrected error: 0=off 1=on");
module_param(edac_mc_log_ue, int, 0644);
MODULE_PARM_DESC(edac_mc_log_ue,
71
		 "Log uncorrectable error to console: 0=off 1=on");
D
Dave Jiang 已提交
72 73
module_param(edac_mc_log_ce, int, 0644);
MODULE_PARM_DESC(edac_mc_log_ce,
74
		 "Log correctable error to console: 0=off 1=on");
A
Arthur Jones 已提交
75 76
module_param_call(edac_mc_poll_msec, edac_set_poll_msec, param_get_int,
		  &edac_mc_poll_msec, 0644);
D
Dave Jiang 已提交
77
MODULE_PARM_DESC(edac_mc_poll_msec, "Polling period in milliseconds");
78 79 80 81 82 83 84 85 86 87 88 89 90 91 92

/*
 * various constants for Memory Controllers
 */
static const char *mem_types[] = {
	[MEM_EMPTY] = "Empty",
	[MEM_RESERVED] = "Reserved",
	[MEM_UNKNOWN] = "Unknown",
	[MEM_FPM] = "FPM",
	[MEM_EDO] = "EDO",
	[MEM_BEDO] = "BEDO",
	[MEM_SDR] = "Unbuffered-SDR",
	[MEM_RDR] = "Registered-SDR",
	[MEM_DDR] = "Unbuffered-DDR",
	[MEM_RDDR] = "Registered-DDR",
93 94 95
	[MEM_RMBS] = "RMBS",
	[MEM_DDR2] = "Unbuffered-DDR2",
	[MEM_FB_DDR2] = "FullyBuffered-DDR2",
96 97
	[MEM_RDDR2] = "Registered-DDR2",
	[MEM_XDR] = "XDR"
98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127
};

static const char *dev_types[] = {
	[DEV_UNKNOWN] = "Unknown",
	[DEV_X1] = "x1",
	[DEV_X2] = "x2",
	[DEV_X4] = "x4",
	[DEV_X8] = "x8",
	[DEV_X16] = "x16",
	[DEV_X32] = "x32",
	[DEV_X64] = "x64"
};

static const char *edac_caps[] = {
	[EDAC_UNKNOWN] = "Unknown",
	[EDAC_NONE] = "None",
	[EDAC_RESERVED] = "Reserved",
	[EDAC_PARITY] = "PARITY",
	[EDAC_EC] = "EC",
	[EDAC_SECDED] = "SECDED",
	[EDAC_S2ECD2ED] = "S2ECD2ED",
	[EDAC_S4ECD4ED] = "S4ECD4ED",
	[EDAC_S8ECD8ED] = "S8ECD8ED",
	[EDAC_S16ECD16ED] = "S16ECD16ED"
};



static ssize_t memctrl_int_store(void *ptr, const char *buffer, size_t count)
{
128
	int *value = (int *)ptr;
129 130 131 132 133 134 135 136 137 138 139 140

	if (isdigit(*buffer))
		*value = simple_strtoul(buffer, NULL, 0);

	return count;
}


/* EDAC sysfs CSROW data structures and methods
 */

/* Set of more default csrow<id> attribute show/store functions */
141
static ssize_t csrow_ue_count_show(struct csrow_info *csrow, char *data,
142
				int private)
143
{
144
	return sprintf(data, "%u\n", csrow->ue_count);
145 146
}

147
static ssize_t csrow_ce_count_show(struct csrow_info *csrow, char *data,
148
				int private)
149
{
150
	return sprintf(data, "%u\n", csrow->ce_count);
151 152
}

153
static ssize_t csrow_size_show(struct csrow_info *csrow, char *data,
154
				int private)
155
{
156
	return sprintf(data, "%u\n", PAGES_TO_MiB(csrow->nr_pages));
157 158
}

159
static ssize_t csrow_mem_type_show(struct csrow_info *csrow, char *data,
160
				int private)
161
{
162
	return sprintf(data, "%s\n", mem_types[csrow->mtype]);
163 164
}

165
static ssize_t csrow_dev_type_show(struct csrow_info *csrow, char *data,
166
				int private)
167
{
168
	return sprintf(data, "%s\n", dev_types[csrow->dtype]);
169 170
}

171
static ssize_t csrow_edac_mode_show(struct csrow_info *csrow, char *data,
172
				int private)
173
{
174
	return sprintf(data, "%s\n", edac_caps[csrow->edac_mode]);
175 176 177 178
}

/* show/store functions for DIMM Label attributes */
static ssize_t channel_dimm_label_show(struct csrow_info *csrow,
179
				char *data, int channel)
180
{
181 182 183 184 185
	/* if field has not been initialized, there is nothing to send */
	if (!csrow->channels[channel].label[0])
		return 0;

	return snprintf(data, EDAC_MC_LABEL_LEN, "%s\n",
186 187 188 189
			csrow->channels[channel].label);
}

static ssize_t channel_dimm_label_store(struct csrow_info *csrow,
190 191
					const char *data,
					size_t count, int channel)
192 193 194
{
	ssize_t max_size = 0;

195
	max_size = min((ssize_t) count, (ssize_t) EDAC_MC_LABEL_LEN - 1);
196 197 198 199 200 201 202 203
	strncpy(csrow->channels[channel].label, data, max_size);
	csrow->channels[channel].label[max_size] = '\0';

	return max_size;
}

/* show function for dynamic chX_ce_count attribute */
static ssize_t channel_ce_count_show(struct csrow_info *csrow,
204
				char *data, int channel)
205 206 207 208 209 210 211
{
	return sprintf(data, "%u\n", csrow->channels[channel].ce_count);
}

/* csrow specific attribute structure */
struct csrowdev_attribute {
	struct attribute attr;
212 213 214
	 ssize_t(*show) (struct csrow_info *, char *, int);
	 ssize_t(*store) (struct csrow_info *, const char *, size_t, int);
	int private;
215 216 217 218 219 220 221
};

#define to_csrow(k) container_of(k, struct csrow_info, kobj)
#define to_csrowdev_attr(a) container_of(a, struct csrowdev_attribute, attr)

/* Set of show/store higher level functions for default csrow attributes */
static ssize_t csrowdev_show(struct kobject *kobj,
222
			struct attribute *attr, char *buffer)
223 224 225 226 227 228
{
	struct csrow_info *csrow = to_csrow(kobj);
	struct csrowdev_attribute *csrowdev_attr = to_csrowdev_attr(attr);

	if (csrowdev_attr->show)
		return csrowdev_attr->show(csrow,
229
					buffer, csrowdev_attr->private);
230 231 232 233
	return -EIO;
}

static ssize_t csrowdev_store(struct kobject *kobj, struct attribute *attr,
234
			const char *buffer, size_t count)
235 236
{
	struct csrow_info *csrow = to_csrow(kobj);
237
	struct csrowdev_attribute *csrowdev_attr = to_csrowdev_attr(attr);
238 239 240

	if (csrowdev_attr->store)
		return csrowdev_attr->store(csrow,
241 242
					buffer,
					count, csrowdev_attr->private);
243 244 245 246
	return -EIO;
}

static struct sysfs_ops csrowfs_ops = {
247 248
	.show = csrowdev_show,
	.store = csrowdev_store
249 250 251 252 253 254 255 256 257 258 259
};

#define CSROWDEV_ATTR(_name,_mode,_show,_store,_private)	\
static struct csrowdev_attribute attr_##_name = {			\
	.attr = {.name = __stringify(_name), .mode = _mode },	\
	.show   = _show,					\
	.store  = _store,					\
	.private = _private,					\
};

/* default cwrow<id>/attribute files */
260 261 262 263 264 265
CSROWDEV_ATTR(size_mb, S_IRUGO, csrow_size_show, NULL, 0);
CSROWDEV_ATTR(dev_type, S_IRUGO, csrow_dev_type_show, NULL, 0);
CSROWDEV_ATTR(mem_type, S_IRUGO, csrow_mem_type_show, NULL, 0);
CSROWDEV_ATTR(edac_mode, S_IRUGO, csrow_edac_mode_show, NULL, 0);
CSROWDEV_ATTR(ue_count, S_IRUGO, csrow_ue_count_show, NULL, 0);
CSROWDEV_ATTR(ce_count, S_IRUGO, csrow_ce_count_show, NULL, 0);
266 267 268 269 270 271 272 273 274 275 276 277 278

/* default attributes of the CSROW<id> object */
static struct csrowdev_attribute *default_csrow_attr[] = {
	&attr_dev_type,
	&attr_mem_type,
	&attr_edac_mode,
	&attr_size_mb,
	&attr_ue_count,
	&attr_ce_count,
	NULL,
};

/* possible dynamic channel DIMM Label attribute files */
279
CSROWDEV_ATTR(ch0_dimm_label, S_IRUGO | S_IWUSR,
280
	channel_dimm_label_show, channel_dimm_label_store, 0);
281
CSROWDEV_ATTR(ch1_dimm_label, S_IRUGO | S_IWUSR,
282
	channel_dimm_label_show, channel_dimm_label_store, 1);
283
CSROWDEV_ATTR(ch2_dimm_label, S_IRUGO | S_IWUSR,
284
	channel_dimm_label_show, channel_dimm_label_store, 2);
285
CSROWDEV_ATTR(ch3_dimm_label, S_IRUGO | S_IWUSR,
286
	channel_dimm_label_show, channel_dimm_label_store, 3);
287
CSROWDEV_ATTR(ch4_dimm_label, S_IRUGO | S_IWUSR,
288
	channel_dimm_label_show, channel_dimm_label_store, 4);
289
CSROWDEV_ATTR(ch5_dimm_label, S_IRUGO | S_IWUSR,
290
	channel_dimm_label_show, channel_dimm_label_store, 5);
291 292 293

/* Total possible dynamic DIMM Label attribute file table */
static struct csrowdev_attribute *dynamic_csrow_dimm_attr[] = {
294 295 296 297 298 299
	&attr_ch0_dimm_label,
	&attr_ch1_dimm_label,
	&attr_ch2_dimm_label,
	&attr_ch3_dimm_label,
	&attr_ch4_dimm_label,
	&attr_ch5_dimm_label
300 301 302
};

/* possible dynamic channel ce_count attribute files */
303 304 305 306 307 308
CSROWDEV_ATTR(ch0_ce_count, S_IRUGO | S_IWUSR, channel_ce_count_show, NULL, 0);
CSROWDEV_ATTR(ch1_ce_count, S_IRUGO | S_IWUSR, channel_ce_count_show, NULL, 1);
CSROWDEV_ATTR(ch2_ce_count, S_IRUGO | S_IWUSR, channel_ce_count_show, NULL, 2);
CSROWDEV_ATTR(ch3_ce_count, S_IRUGO | S_IWUSR, channel_ce_count_show, NULL, 3);
CSROWDEV_ATTR(ch4_ce_count, S_IRUGO | S_IWUSR, channel_ce_count_show, NULL, 4);
CSROWDEV_ATTR(ch5_ce_count, S_IRUGO | S_IWUSR, channel_ce_count_show, NULL, 5);
309 310 311

/* Total possible dynamic ce_count attribute file table */
static struct csrowdev_attribute *dynamic_csrow_ce_count_attr[] = {
312 313 314 315 316 317
	&attr_ch0_ce_count,
	&attr_ch1_ce_count,
	&attr_ch2_ce_count,
	&attr_ch3_ce_count,
	&attr_ch4_ce_count,
	&attr_ch5_ce_count
318 319 320 321 322 323 324
};

#define EDAC_NR_CHANNELS	6

/* Create dynamic CHANNEL files, indexed by 'chan',  under specifed CSROW */
static int edac_create_channel_files(struct kobject *kobj, int chan)
{
325
	int err = -ENODEV;
326 327 328 329 330 331

	if (chan >= EDAC_NR_CHANNELS)
		return err;

	/* create the DIMM label attribute file */
	err = sysfs_create_file(kobj,
332 333
				(struct attribute *)
				dynamic_csrow_dimm_attr[chan]);
334 335 336 337

	if (!err) {
		/* create the CE Count attribute file */
		err = sysfs_create_file(kobj,
338 339
					(struct attribute *)
					dynamic_csrow_ce_count_attr[chan]);
340
	} else {
341 342
		debugf1("%s()  dimm labels and ce_count files created",
			__func__);
343 344 345 346 347 348 349 350
	}

	return err;
}

/* No memory to release for this kobj */
static void edac_csrow_instance_release(struct kobject *kobj)
{
351
	struct mem_ctl_info *mci;
352 353
	struct csrow_info *cs;

354 355
	debugf1("%s()\n", __func__);

356
	cs = container_of(kobj, struct csrow_info, kobj);
357 358 359
	mci = cs->mci;

	kobject_put(&mci->edac_mci_kobj);
360 361 362 363 364 365
}

/* the kobj_type instance for a CSROW */
static struct kobj_type ktype_csrow = {
	.release = edac_csrow_instance_release,
	.sysfs_ops = &csrowfs_ops,
366
	.default_attrs = (struct attribute **)default_csrow_attr,
367 368 369
};

/* Create a CSROW object under specifed edac_mc_device */
370 371
static int edac_create_csrow_object(struct mem_ctl_info *mci,
					struct csrow_info *csrow, int index)
372
{
373 374
	struct kobject *kobj_mci = &mci->edac_mci_kobj;
	struct kobject *kobj;
375
	int chan;
376
	int err;
377 378

	/* generate ..../edac/mc/mc<id>/csrow<index>   */
379 380 381 382 383 384 385 386 387
	memset(&csrow->kobj, 0, sizeof(csrow->kobj));
	csrow->mci = mci;	/* include container up link */

	/* bump the mci instance's kobject's ref count */
	kobj = kobject_get(&mci->edac_mci_kobj);
	if (!kobj) {
		err = -ENODEV;
		goto err_out;
	}
388 389

	/* Instanstiate the csrow object */
390 391
	err = kobject_init_and_add(&csrow->kobj, &ktype_csrow, kobj_mci,
				   "csrow%d", index);
392 393 394 395
	if (err)
		goto err_release_top_kobj;

	/* At this point, to release a csrow kobj, one must
396
	 * call the kobject_put and allow that tear down
397 398 399 400 401 402 403 404 405 406
	 * to work the releasing
	 */

	/* Create the dyanmic attribute files on this csrow,
	 * namely, the DIMM labels and the channel ce_count
	 */
	for (chan = 0; chan < csrow->nr_channels; chan++) {
		err = edac_create_channel_files(&csrow->kobj, chan);
		if (err) {
			/* special case the unregister here */
407
			kobject_put(&csrow->kobj);
408
			goto err_out;
409 410
		}
	}
411
	kobject_uevent(&csrow->kobj, KOBJ_ADD);
412 413 414 415 416 417 418
	return 0;

	/* error unwind stack */
err_release_top_kobj:
	kobject_put(&mci->edac_mci_kobj);

err_out:
419 420 421 422 423 424
	return err;
}

/* default sysfs methods and data structures for the main MCI kobject */

static ssize_t mci_reset_counters_store(struct mem_ctl_info *mci,
425
					const char *data, size_t count)
426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449
{
	int row, chan;

	mci->ue_noinfo_count = 0;
	mci->ce_noinfo_count = 0;
	mci->ue_count = 0;
	mci->ce_count = 0;

	for (row = 0; row < mci->nr_csrows; row++) {
		struct csrow_info *ri = &mci->csrows[row];

		ri->ue_count = 0;
		ri->ce_count = 0;

		for (chan = 0; chan < ri->nr_channels; chan++)
			ri->channels[chan].ce_count = 0;
	}

	mci->start_time = jiffies;
	return count;
}

/* memory scrubbing */
static ssize_t mci_sdram_scrub_rate_store(struct mem_ctl_info *mci,
450
					const char *data, size_t count)
451 452 453 454 455 456 457
{
	u32 bandwidth = -1;

	if (mci->set_sdram_scrub_rate) {

		memctrl_int_store(&bandwidth, data, count);

458
		if (!(*mci->set_sdram_scrub_rate) (mci, &bandwidth)) {
459
			edac_printk(KERN_DEBUG, EDAC_MC,
460 461
				"Scrub rate set successfully, applied: %d\n",
				bandwidth);
462 463 464
		} else {
			/* FIXME: error codes maybe? */
			edac_printk(KERN_DEBUG, EDAC_MC,
465 466
				"Scrub rate set FAILED, could not apply: %d\n",
				bandwidth);
467 468 469 470
		}
	} else {
		/* FIXME: produce "not implemented" ERROR for user-side. */
		edac_printk(KERN_WARNING, EDAC_MC,
471
			"Memory scrubbing 'set'control is not implemented!\n");
472 473 474 475 476 477 478 479 480
	}
	return count;
}

static ssize_t mci_sdram_scrub_rate_show(struct mem_ctl_info *mci, char *data)
{
	u32 bandwidth = -1;

	if (mci->get_sdram_scrub_rate) {
481
		if (!(*mci->get_sdram_scrub_rate) (mci, &bandwidth)) {
482
			edac_printk(KERN_DEBUG, EDAC_MC,
483 484
				"Scrub rate successfully, fetched: %d\n",
				bandwidth);
485 486 487
		} else {
			/* FIXME: error codes maybe? */
			edac_printk(KERN_DEBUG, EDAC_MC,
488 489
				"Scrub rate fetch FAILED, got: %d\n",
				bandwidth);
490 491 492 493
		}
	} else {
		/* FIXME: produce "not implemented" ERROR for user-side.  */
		edac_printk(KERN_WARNING, EDAC_MC,
494
			"Memory scrubbing 'get' control is not implemented\n");
495 496 497 498 499 500 501
	}
	return sprintf(data, "%d\n", bandwidth);
}

/* default attribute files for the MCI object */
static ssize_t mci_ue_count_show(struct mem_ctl_info *mci, char *data)
{
502
	return sprintf(data, "%d\n", mci->ue_count);
503 504 505 506
}

static ssize_t mci_ce_count_show(struct mem_ctl_info *mci, char *data)
{
507
	return sprintf(data, "%d\n", mci->ce_count);
508 509 510 511
}

static ssize_t mci_ce_noinfo_show(struct mem_ctl_info *mci, char *data)
{
512
	return sprintf(data, "%d\n", mci->ce_noinfo_count);
513 514 515 516
}

static ssize_t mci_ue_noinfo_show(struct mem_ctl_info *mci, char *data)
{
517
	return sprintf(data, "%d\n", mci->ue_noinfo_count);
518 519 520 521
}

static ssize_t mci_seconds_show(struct mem_ctl_info *mci, char *data)
{
522
	return sprintf(data, "%ld\n", (jiffies - mci->start_time) / HZ);
523 524 525 526
}

static ssize_t mci_ctl_name_show(struct mem_ctl_info *mci, char *data)
{
527
	return sprintf(data, "%s\n", mci->ctl_name);
528 529 530 531 532 533 534
}

static ssize_t mci_size_mb_show(struct mem_ctl_info *mci, char *data)
{
	int total_pages, csrow_idx;

	for (total_pages = csrow_idx = 0; csrow_idx < mci->nr_csrows;
535
		csrow_idx++) {
536 537 538 539 540 541 542 543
		struct csrow_info *csrow = &mci->csrows[csrow_idx];

		if (!csrow->nr_pages)
			continue;

		total_pages += csrow->nr_pages;
	}

544
	return sprintf(data, "%u\n", PAGES_TO_MiB(total_pages));
545 546 547
}

#define to_mci(k) container_of(k, struct mem_ctl_info, edac_mci_kobj)
548
#define to_mcidev_attr(a) container_of(a,struct mcidev_sysfs_attribute,attr)
549 550 551

/* MCI show/store functions for top most object */
static ssize_t mcidev_show(struct kobject *kobj, struct attribute *attr,
552
			char *buffer)
553 554
{
	struct mem_ctl_info *mem_ctl_info = to_mci(kobj);
555
	struct mcidev_sysfs_attribute *mcidev_attr = to_mcidev_attr(attr);
556 557 558 559 560 561 562 563

	if (mcidev_attr->show)
		return mcidev_attr->show(mem_ctl_info, buffer);

	return -EIO;
}

static ssize_t mcidev_store(struct kobject *kobj, struct attribute *attr,
564
			const char *buffer, size_t count)
565 566
{
	struct mem_ctl_info *mem_ctl_info = to_mci(kobj);
567
	struct mcidev_sysfs_attribute *mcidev_attr = to_mcidev_attr(attr);
568 569 570 571 572 573 574

	if (mcidev_attr->store)
		return mcidev_attr->store(mem_ctl_info, buffer, count);

	return -EIO;
}

575
/* Intermediate show/store table */
576 577 578 579 580 581
static struct sysfs_ops mci_ops = {
	.show = mcidev_show,
	.store = mcidev_store
};

#define MCIDEV_ATTR(_name,_mode,_show,_store)			\
582
static struct mcidev_sysfs_attribute mci_attr_##_name = {			\
583 584 585 586 587 588
	.attr = {.name = __stringify(_name), .mode = _mode },	\
	.show   = _show,					\
	.store  = _store,					\
};

/* default Control file */
589
MCIDEV_ATTR(reset_counters, S_IWUSR, NULL, mci_reset_counters_store);
590 591

/* default Attribute files */
592 593 594 595 596 597 598
MCIDEV_ATTR(mc_name, S_IRUGO, mci_ctl_name_show, NULL);
MCIDEV_ATTR(size_mb, S_IRUGO, mci_size_mb_show, NULL);
MCIDEV_ATTR(seconds_since_reset, S_IRUGO, mci_seconds_show, NULL);
MCIDEV_ATTR(ue_noinfo_count, S_IRUGO, mci_ue_noinfo_show, NULL);
MCIDEV_ATTR(ce_noinfo_count, S_IRUGO, mci_ce_noinfo_show, NULL);
MCIDEV_ATTR(ue_count, S_IRUGO, mci_ue_count_show, NULL);
MCIDEV_ATTR(ce_count, S_IRUGO, mci_ce_count_show, NULL);
599 600

/* memory scrubber attribute file */
601
MCIDEV_ATTR(sdram_scrub_rate, S_IRUGO | S_IWUSR, mci_sdram_scrub_rate_show,
602
	mci_sdram_scrub_rate_store);
603

604
static struct mcidev_sysfs_attribute *mci_attr[] = {
605 606 607 608 609 610 611 612 613 614 615 616
	&mci_attr_reset_counters,
	&mci_attr_mc_name,
	&mci_attr_size_mb,
	&mci_attr_seconds_since_reset,
	&mci_attr_ue_noinfo_count,
	&mci_attr_ce_noinfo_count,
	&mci_attr_ue_count,
	&mci_attr_ce_count,
	&mci_attr_sdram_scrub_rate,
	NULL
};

617

618 619
/*
 * Release of a MC controlling instance
620 621 622 623 624 625 626
 *
 *	each MC control instance has the following resources upon entry:
 *		a) a ref count on the top memctl kobj
 *		b) a ref count on this module
 *
 *	this function must decrement those ref counts and then
 *	issue a free on the instance's memory
627
 */
628
static void edac_mci_control_release(struct kobject *kobj)
629 630 631 632
{
	struct mem_ctl_info *mci;

	mci = to_mci(kobj);
633 634 635 636 637 638 639 640

	debugf0("%s() mci instance idx=%d releasing\n", __func__, mci->mc_idx);

	/* decrement the module ref count */
	module_put(mci->owner);

	/* free the mci instance memory here */
	kfree(mci);
641 642 643
}

static struct kobj_type ktype_mci = {
644
	.release = edac_mci_control_release,
645
	.sysfs_ops = &mci_ops,
646
	.default_attrs = (struct attribute **)mci_attr,
647 648
};

649 650 651
/* EDAC memory controller sysfs kset:
 *	/sys/devices/system/edac/mc
 */
652
static struct kset *mc_kset;
653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681

/*
 * edac_mc_register_sysfs_main_kobj
 *
 *	setups and registers the main kobject for each mci
 */
int edac_mc_register_sysfs_main_kobj(struct mem_ctl_info *mci)
{
	struct kobject *kobj_mci;
	int err;

	debugf1("%s()\n", __func__);

	kobj_mci = &mci->edac_mci_kobj;

	/* Init the mci's kobject */
	memset(kobj_mci, 0, sizeof(*kobj_mci));

	/* Record which module 'owns' this control structure
	 * and bump the ref count of the module
	 */
	mci->owner = THIS_MODULE;

	/* bump ref count on this module */
	if (!try_module_get(mci->owner)) {
		err = -ENODEV;
		goto fail_out;
	}

682
	/* this instance become part of the mc_kset */
683
	kobj_mci->kset = mc_kset;
684

685
	/* register the mc<id> kobject to the mc_kset */
686 687
	err = kobject_init_and_add(kobj_mci, &ktype_mci, NULL,
				   "mc%d", mci->mc_idx);
688 689 690 691 692
	if (err) {
		debugf1("%s()Failed to register '.../edac/mc%d'\n",
			__func__, mci->mc_idx);
		goto kobj_reg_fail;
	}
693
	kobject_uevent(kobj_mci, KOBJ_ADD);
694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720

	/* At this point, to 'free' the control struct,
	 * edac_mc_unregister_sysfs_main_kobj() must be used
	 */

	debugf1("%s() Registered '.../edac/mc%d' kobject\n",
		__func__, mci->mc_idx);

	return 0;

	/* Error exit stack */

kobj_reg_fail:
	module_put(mci->owner);

fail_out:
	return err;
}

/*
 * edac_mc_register_sysfs_main_kobj
 *
 *	tears down and the main mci kobject from the mc_kset
 */
void edac_mc_unregister_sysfs_main_kobj(struct mem_ctl_info *mci)
{
	/* delete the kobj from the mc_kset */
721
	kobject_put(&mci->edac_mci_kobj);
722 723
}

724 725
#define EDAC_DEVICE_SYMLINK	"device"

726
/*
727
 * edac_create_mci_instance_attributes
728 729 730
 *	create MC driver specific attributes at the topmost level
 *	directory of this mci instance.
 */
731
static int edac_create_mci_instance_attributes(struct mem_ctl_info *mci)
732 733 734 735 736 737 738 739 740
{
	int err;
	struct mcidev_sysfs_attribute *sysfs_attrib;

	/* point to the start of the array and iterate over it
	 * adding each attribute listed to this mci instance's kobject
	 */
	sysfs_attrib = mci->mc_driver_sysfs_attributes;

741
	while (sysfs_attrib && sysfs_attrib->attr.name) {
742 743 744 745 746 747 748 749 750 751 752 753
		err = sysfs_create_file(&mci->edac_mci_kobj,
					(struct attribute*) sysfs_attrib);
		if (err) {
			return err;
		}

		sysfs_attrib++;
	}

	return 0;
}

754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776
/*
 * edac_remove_mci_instance_attributes
 *	remove MC driver specific attributes at the topmost level
 *	directory of this mci instance.
 */
static void edac_remove_mci_instance_attributes(struct mem_ctl_info *mci)
{
	struct mcidev_sysfs_attribute *sysfs_attrib;

	/* point to the start of the array and iterate over it
	 * adding each attribute listed to this mci instance's kobject
	 */
	sysfs_attrib = mci->mc_driver_sysfs_attributes;

	/* loop if there are attributes and until we hit a NULL entry */
	while (sysfs_attrib && sysfs_attrib->attr.name) {
		sysfs_remove_file(&mci->edac_mci_kobj,
					(struct attribute *) sysfs_attrib);
		sysfs_attrib++;
	}
}


777 778 779 780 781 782 783 784 785 786 787 788 789
/*
 * Create a new Memory Controller kobject instance,
 *	mc<id> under the 'mc' directory
 *
 * Return:
 *	0	Success
 *	!0	Failure
 */
int edac_create_sysfs_mci_device(struct mem_ctl_info *mci)
{
	int i;
	int err;
	struct csrow_info *csrow;
790
	struct kobject *kobj_mci = &mci->edac_mci_kobj;
791 792 793 794

	debugf0("%s() idx=%d\n", __func__, mci->mc_idx);

	/* create a symlink for the device */
795
	err = sysfs_create_link(kobj_mci, &mci->dev->kobj,
796
				EDAC_DEVICE_SYMLINK);
797 798
	if (err) {
		debugf1("%s() failure to create symlink\n", __func__);
799
		goto fail0;
800
	}
801

802 803 804 805
	/* If the low level driver desires some attributes,
	 * then create them now for the driver.
	 */
	if (mci->mc_driver_sysfs_attributes) {
806 807 808 809
		err = edac_create_mci_instance_attributes(mci);
		if (err) {
			debugf1("%s() failure to create mci attributes\n",
				__func__);
810
			goto fail0;
811
		}
812 813
	}

814
	/* Make directories for each CSROW object under the mc<id> kobject
815 816 817 818 819 820
	 */
	for (i = 0; i < mci->nr_csrows; i++) {
		csrow = &mci->csrows[i];

		/* Only expose populated CSROWs */
		if (csrow->nr_pages > 0) {
821 822 823 824
			err = edac_create_csrow_object(mci, csrow, i);
			if (err) {
				debugf1("%s() failure: create csrow %d obj\n",
					__func__, i);
825
				goto fail1;
826
			}
827 828 829 830 831 832
		}
	}

	return 0;

	/* CSROW error: backout what has already been registered,  */
833
fail1:
834
	for (i--; i >= 0; i--) {
835
		if (csrow->nr_pages > 0) {
836
			kobject_put(&mci->csrows[i].kobj);
837 838 839
		}
	}

840 841 842 843 844 845
	/* remove the mci instance's attributes, if any */
	edac_remove_mci_instance_attributes(mci);

	/* remove the symlink */
	sysfs_remove_link(kobj_mci, EDAC_DEVICE_SYMLINK);

846
fail0:
847 848 849 850 851 852 853 854 855 856 857 858 859 860 861
	return err;
}

/*
 * remove a Memory Controller instance
 */
void edac_remove_sysfs_mci_device(struct mem_ctl_info *mci)
{
	int i;

	debugf0("%s()\n", __func__);

	/* remove all csrow kobjects */
	for (i = 0; i < mci->nr_csrows; i++) {
		if (mci->csrows[i].nr_pages > 0) {
862
			debugf0("%s()  unreg csrow-%d\n", __func__, i);
863
			kobject_put(&mci->csrows[i].kobj);
864 865 866
		}
	}

867 868 869
	debugf0("%s()  remove_link\n", __func__);

	/* remove the symlink */
870
	sysfs_remove_link(&mci->edac_mci_kobj, EDAC_DEVICE_SYMLINK);
871 872 873 874 875 876 877 878 879

	debugf0("%s()  remove_mci_instance\n", __func__);

	/* remove this mci instance's attribtes */
	edac_remove_mci_instance_attributes(mci);

	debugf0("%s()  unregister this mci kobj\n", __func__);

	/* unregister this instance's kobject */
880
	kobject_put(&mci->edac_mci_kobj);
881
}
882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912




/*
 * edac_setup_sysfs_mc_kset(void)
 *
 * Initialize the mc_kset for the 'mc' entry
 *	This requires creating the top 'mc' directory with a kset
 *	and its controls/attributes.
 *
 *	To this 'mc' kset, instance 'mci' will be grouped as children.
 *
 * Return:  0 SUCCESS
 *         !0 FAILURE error code
 */
int edac_sysfs_setup_mc_kset(void)
{
	int err = 0;
	struct sysdev_class *edac_class;

	debugf1("%s()\n", __func__);

	/* get the /sys/devices/system/edac class reference */
	edac_class = edac_get_edac_class();
	if (edac_class == NULL) {
		debugf1("%s() no edac_class error=%d\n", __func__, err);
		goto fail_out;
	}

	/* Init the MC's kobject */
913 914 915
	mc_kset = kset_create_and_add("mc", NULL, &edac_class->kset.kobj);
	if (!mc_kset) {
		err = -ENOMEM;
916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936
		debugf1("%s() Failed to register '.../edac/mc'\n", __func__);
		goto fail_out;
	}

	debugf1("%s() Registered '.../edac/mc' kobject\n", __func__);

	return 0;


	/* error unwind stack */
fail_out:
	return err;
}

/*
 * edac_sysfs_teardown_mc_kset
 *
 *	deconstruct the mc_ket for memory controllers
 */
void edac_sysfs_teardown_mc_kset(void)
{
937
	kset_unregister(mc_kset);
938 939
}