edac_mc_sysfs.c

来自「linux 内核源代码」· C语言 代码 · 共 1,043 行 · 第 1/2 页

C
1,043
字号
static ssize_t mci_ue_noinfo_show(struct mem_ctl_info *mci, char *data){	return sprintf(data, "%d\n", mci->ue_noinfo_count);}static ssize_t mci_seconds_show(struct mem_ctl_info *mci, char *data){	return sprintf(data, "%ld\n", (jiffies - mci->start_time) / HZ);}static ssize_t mci_ctl_name_show(struct mem_ctl_info *mci, char *data){	return sprintf(data, "%s\n", mci->ctl_name);}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;		csrow_idx++) {		struct csrow_info *csrow = &mci->csrows[csrow_idx];		if (!csrow->nr_pages)			continue;		total_pages += csrow->nr_pages;	}	return sprintf(data, "%u\n", PAGES_TO_MiB(total_pages));}#define to_mci(k) container_of(k, struct mem_ctl_info, edac_mci_kobj)#define to_mcidev_attr(a) container_of(a,struct mcidev_sysfs_attribute,attr)/* MCI show/store functions for top most object */static ssize_t mcidev_show(struct kobject *kobj, struct attribute *attr,			char *buffer){	struct mem_ctl_info *mem_ctl_info = to_mci(kobj);	struct mcidev_sysfs_attribute *mcidev_attr = to_mcidev_attr(attr);	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,			const char *buffer, size_t count){	struct mem_ctl_info *mem_ctl_info = to_mci(kobj);	struct mcidev_sysfs_attribute *mcidev_attr = to_mcidev_attr(attr);	if (mcidev_attr->store)		return mcidev_attr->store(mem_ctl_info, buffer, count);	return -EIO;}/* Intermediate show/store table */static struct sysfs_ops mci_ops = {	.show = mcidev_show,	.store = mcidev_store};#define MCIDEV_ATTR(_name,_mode,_show,_store)			\static struct mcidev_sysfs_attribute mci_attr_##_name = {			\	.attr = {.name = __stringify(_name), .mode = _mode },	\	.show   = _show,					\	.store  = _store,					\};/* default Control file */MCIDEV_ATTR(reset_counters, S_IWUSR, NULL, mci_reset_counters_store);/* default Attribute files */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);/* memory scrubber attribute file */MCIDEV_ATTR(sdram_scrub_rate, S_IRUGO | S_IWUSR, mci_sdram_scrub_rate_show,	mci_sdram_scrub_rate_store);static struct mcidev_sysfs_attribute *mci_attr[] = {	&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};/* * Release of a MC controlling instance * *	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 */static void edac_mci_control_release(struct kobject *kobj){	struct mem_ctl_info *mci;	mci = to_mci(kobj);	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);}static struct kobj_type ktype_mci = {	.release = edac_mci_control_release,	.sysfs_ops = &mci_ops,	.default_attrs = (struct attribute **)mci_attr,};/* show/store, tables, etc for the MC kset */struct memctrl_dev_attribute {	struct attribute attr;	void *value;	 ssize_t(*show) (void *, char *);	 ssize_t(*store) (void *, const char *, size_t);};/* Set of show/store abstract level functions for memory control object */static ssize_t memctrl_dev_show(struct kobject *kobj,				struct attribute *attr, char *buffer){	struct memctrl_dev_attribute *memctrl_dev;	memctrl_dev = (struct memctrl_dev_attribute *)attr;	if (memctrl_dev->show)		return memctrl_dev->show(memctrl_dev->value, buffer);	return -EIO;}static ssize_t memctrl_dev_store(struct kobject *kobj, struct attribute *attr,				 const char *buffer, size_t count){	struct memctrl_dev_attribute *memctrl_dev;	memctrl_dev = (struct memctrl_dev_attribute *)attr;	if (memctrl_dev->store)		return memctrl_dev->store(memctrl_dev->value, buffer, count);	return -EIO;}static struct sysfs_ops memctrlfs_ops = {	.show = memctrl_dev_show,	.store = memctrl_dev_store};#define MEMCTRL_ATTR(_name, _mode, _show, _store)			\static struct memctrl_dev_attribute attr_##_name = {			\	.attr = {.name = __stringify(_name), .mode = _mode },	\	.value  = &_name,					\	.show   = _show,					\	.store  = _store,					\};#define MEMCTRL_STRING_ATTR(_name, _data, _mode, _show, _store)	\static struct memctrl_dev_attribute attr_##_name = {			\	.attr = {.name = __stringify(_name), .mode = _mode },	\	.value  = _data,					\	.show   = _show,					\	.store  = _store,					\};/* csrow<id> control files */MEMCTRL_ATTR(edac_mc_panic_on_ue,	S_IRUGO | S_IWUSR, memctrl_int_show, memctrl_int_store);MEMCTRL_ATTR(edac_mc_log_ue,	S_IRUGO | S_IWUSR, memctrl_int_show, memctrl_int_store);MEMCTRL_ATTR(edac_mc_log_ce,	S_IRUGO | S_IWUSR, memctrl_int_show, memctrl_int_store);MEMCTRL_ATTR(edac_mc_poll_msec,	S_IRUGO | S_IWUSR, memctrl_int_show, poll_msec_int_store);/* Base Attributes of the memory ECC object */static struct memctrl_dev_attribute *memctrl_attr[] = {	&attr_edac_mc_panic_on_ue,	&attr_edac_mc_log_ue,	&attr_edac_mc_log_ce,	&attr_edac_mc_poll_msec,	NULL,};/* the ktype for the mc_kset internal kobj */static struct kobj_type ktype_mc_set_attribs = {	.sysfs_ops = &memctrlfs_ops,	.default_attrs = (struct attribute **)memctrl_attr,};/* EDAC memory controller sysfs kset: *	/sys/devices/system/edac/mc */static struct kset mc_kset = {	.kobj = {.ktype = &ktype_mc_set_attribs },	.ktype = &ktype_mci,};/* * 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));	/* this instance become part of the mc_kset */	kobj_mci->kset = &mc_kset;	/* set the name of the mc<id> object */	err = kobject_set_name(kobj_mci, "mc%d", mci->mc_idx);	if (err)		goto fail_out;	/* 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;	}	/* register the mc<id> kobject to the mc_kset */	err = kobject_register(kobj_mci);	if (err) {		debugf1("%s()Failed to register '.../edac/mc%d'\n",			__func__, mci->mc_idx);		goto kobj_reg_fail;	}	/* 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 */	kobject_unregister(&mci->edac_mci_kobj);}#define EDAC_DEVICE_SYMLINK	"device"/* * edac_create_mci_instance_attributes *	create MC driver specific attributes at the topmost level *	directory of this mci instance. */static int edac_create_mci_instance_attributes(struct mem_ctl_info *mci){	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;	while (sysfs_attrib && sysfs_attrib->attr.name) {		err = sysfs_create_file(&mci->edac_mci_kobj,					(struct attribute*) sysfs_attrib);		if (err) {			return err;		}		sysfs_attrib++;	}	return 0;}/* * 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++;	}}/* * 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;	struct kobject *kobj_mci = &mci->edac_mci_kobj;	debugf0("%s() idx=%d\n", __func__, mci->mc_idx);	/* create a symlink for the device */	err = sysfs_create_link(kobj_mci, &mci->dev->kobj,				EDAC_DEVICE_SYMLINK);	if (err) {		debugf1("%s() failure to create symlink\n", __func__);		goto fail0;	}	/* If the low level driver desires some attributes,	 * then create them now for the driver.	 */	if (mci->mc_driver_sysfs_attributes) {		err = edac_create_mci_instance_attributes(mci);		if (err) {			debugf1("%s() failure to create mci attributes\n",				__func__);			goto fail0;		}	}	/* Make directories for each CSROW object under the mc<id> kobject	 */	for (i = 0; i < mci->nr_csrows; i++) {		csrow = &mci->csrows[i];		/* Only expose populated CSROWs */		if (csrow->nr_pages > 0) {			err = edac_create_csrow_object(mci, csrow, i);			if (err) {				debugf1("%s() failure: create csrow %d obj\n",					__func__, i);				goto fail1;			}		}	}	return 0;	/* CSROW error: backout what has already been registered,  */fail1:	for (i--; i >= 0; i--) {		if (csrow->nr_pages > 0) {			kobject_unregister(&mci->csrows[i].kobj);		}	}	/* 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);fail0:	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) {			debugf0("%s()  unreg csrow-%d\n", __func__, i);			kobject_unregister(&mci->csrows[i].kobj);		}	}	debugf0("%s()  remove_link\n", __func__);	/* remove the symlink */	sysfs_remove_link(&mci->edac_mci_kobj, EDAC_DEVICE_SYMLINK);	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 */	kobject_unregister(&mci->edac_mci_kobj);}/* * 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 */	kobject_set_name(&mc_kset.kobj, "mc");	mc_kset.kobj.parent = &edac_class->kset.kobj;	/* register the mc_kset */	err = kset_register(&mc_kset);	if (err) {		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){	kset_unregister(&mc_kset);}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?