edac_pci_sysfs.c

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

C
764
字号
/* * (C) 2005, 2006 Linux Networx (http://lnxi.com) * This file may be distributed under the terms of the * GNU General Public License. * * Written Doug Thompson <norsk5@xmission.com> * */#include <linux/module.h>#include <linux/sysdev.h>#include <linux/ctype.h>#include "edac_core.h"#include "edac_module.h"/* Turn off this whole feature if PCI is not configured */#ifdef CONFIG_PCI#define EDAC_PCI_SYMLINK	"device"/* data variables exported via sysfs */static int check_pci_errors;		/* default NO check PCI parity */static int edac_pci_panic_on_pe;	/* default NO panic on PCI Parity */static int edac_pci_log_pe = 1;		/* log PCI parity errors */static int edac_pci_log_npe = 1;	/* log PCI non-parity error errors */static int edac_pci_poll_msec = 1000;	/* one second workq period */static atomic_t pci_parity_count = ATOMIC_INIT(0);static atomic_t pci_nonparity_count = ATOMIC_INIT(0);static struct kobject edac_pci_top_main_kobj;static atomic_t edac_pci_sysfs_refcount = ATOMIC_INIT(0);/* getter functions for the data variables */int edac_pci_get_check_errors(void){	return check_pci_errors;}int edac_pci_get_log_pe(void){	return edac_pci_log_pe;}int edac_pci_get_log_npe(void){	return edac_pci_log_npe;}int edac_pci_get_panic_on_pe(void){	return edac_pci_panic_on_pe;}int edac_pci_get_poll_msec(void){	return edac_pci_poll_msec;}/**************************** EDAC PCI sysfs instance *******************/static ssize_t instance_pe_count_show(struct edac_pci_ctl_info *pci, char *data){	return sprintf(data, "%u\n", atomic_read(&pci->counters.pe_count));}static ssize_t instance_npe_count_show(struct edac_pci_ctl_info *pci,				char *data){	return sprintf(data, "%u\n", atomic_read(&pci->counters.npe_count));}#define to_instance(k) container_of(k, struct edac_pci_ctl_info, kobj)#define to_instance_attr(a) container_of(a, struct instance_attribute, attr)/* DEVICE instance kobject release() function */static void edac_pci_instance_release(struct kobject *kobj){	struct edac_pci_ctl_info *pci;	debugf0("%s()\n", __func__);	/* Form pointer to containing struct, the pci control struct */	pci = to_instance(kobj);	/* decrement reference count on top main kobj */	kobject_put(&edac_pci_top_main_kobj);	kfree(pci);	/* Free the control struct */}/* instance specific attribute structure */struct instance_attribute {	struct attribute attr;	ssize_t(*show) (struct edac_pci_ctl_info *, char *);	ssize_t(*store) (struct edac_pci_ctl_info *, const char *, size_t);};/* Function to 'show' fields from the edac_pci 'instance' structure */static ssize_t edac_pci_instance_show(struct kobject *kobj,				struct attribute *attr, char *buffer){	struct edac_pci_ctl_info *pci = to_instance(kobj);	struct instance_attribute *instance_attr = to_instance_attr(attr);	if (instance_attr->show)		return instance_attr->show(pci, buffer);	return -EIO;}/* Function to 'store' fields into the edac_pci 'instance' structure */static ssize_t edac_pci_instance_store(struct kobject *kobj,				struct attribute *attr,				const char *buffer, size_t count){	struct edac_pci_ctl_info *pci = to_instance(kobj);	struct instance_attribute *instance_attr = to_instance_attr(attr);	if (instance_attr->store)		return instance_attr->store(pci, buffer, count);	return -EIO;}/* fs_ops table */static struct sysfs_ops pci_instance_ops = {	.show = edac_pci_instance_show,	.store = edac_pci_instance_store};#define INSTANCE_ATTR(_name, _mode, _show, _store)	\static struct instance_attribute attr_instance_##_name = {	\	.attr	= {.name = __stringify(_name), .mode = _mode },	\	.show	= _show,					\	.store	= _store,					\};INSTANCE_ATTR(pe_count, S_IRUGO, instance_pe_count_show, NULL);INSTANCE_ATTR(npe_count, S_IRUGO, instance_npe_count_show, NULL);/* pci instance attributes */static struct instance_attribute *pci_instance_attr[] = {	&attr_instance_pe_count,	&attr_instance_npe_count,	NULL};/* the ktype for a pci instance */static struct kobj_type ktype_pci_instance = {	.release = edac_pci_instance_release,	.sysfs_ops = &pci_instance_ops,	.default_attrs = (struct attribute **)pci_instance_attr,};/* * edac_pci_create_instance_kobj * *	construct one EDAC PCI instance's kobject for use */static int edac_pci_create_instance_kobj(struct edac_pci_ctl_info *pci, int idx){	struct kobject *main_kobj;	int err;	debugf0("%s()\n", __func__);	/* Set the parent and the instance's ktype */	pci->kobj.parent = &edac_pci_top_main_kobj;	pci->kobj.ktype = &ktype_pci_instance;	err = kobject_set_name(&pci->kobj, "pci%d", idx);	if (err)		return err;	/* First bump the ref count on the top main kobj, which will	 * track the number of PCI instances we have, and thus nest	 * properly on keeping the module loaded	 */	main_kobj = kobject_get(&edac_pci_top_main_kobj);	if (!main_kobj) {		err = -ENODEV;		goto error_out;	}	/* And now register this new kobject under the main kobj */	err = kobject_register(&pci->kobj);	if (err != 0) {		debugf2("%s() failed to register instance pci%d\n",			__func__, idx);		kobject_put(&edac_pci_top_main_kobj);		goto error_out;	}	debugf1("%s() Register instance 'pci%d' kobject\n", __func__, idx);	return 0;	/* Error unwind statck */error_out:	return err;}/* * edac_pci_unregister_sysfs_instance_kobj * *	unregister the kobj for the EDAC PCI instance */void edac_pci_unregister_sysfs_instance_kobj(struct edac_pci_ctl_info *pci){	debugf0("%s()\n", __func__);	/* Unregister the instance kobject and allow its release	 * function release the main reference count and then	 * kfree the memory	 */	kobject_unregister(&pci->kobj);}/***************************** EDAC PCI sysfs root **********************/#define to_edacpci(k) container_of(k, struct edac_pci_ctl_info, kobj)#define to_edacpci_attr(a) container_of(a, struct edac_pci_attr, attr)/* simple show/store functions for attributes */static ssize_t edac_pci_int_show(void *ptr, char *buffer){	int *value = ptr;	return sprintf(buffer, "%d\n", *value);}static ssize_t edac_pci_int_store(void *ptr, const char *buffer, size_t count){	int *value = ptr;	if (isdigit(*buffer))		*value = simple_strtoul(buffer, NULL, 0);	return count;}struct edac_pci_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 PCI Parity object */static ssize_t edac_pci_dev_show(struct kobject *kobj, struct attribute *attr,				 char *buffer){	struct edac_pci_dev_attribute *edac_pci_dev;	edac_pci_dev = (struct edac_pci_dev_attribute *)attr;	if (edac_pci_dev->show)		return edac_pci_dev->show(edac_pci_dev->value, buffer);	return -EIO;}static ssize_t edac_pci_dev_store(struct kobject *kobj,				struct attribute *attr, const char *buffer,				size_t count){	struct edac_pci_dev_attribute *edac_pci_dev;	edac_pci_dev = (struct edac_pci_dev_attribute *)attr;	if (edac_pci_dev->show)		return edac_pci_dev->store(edac_pci_dev->value, buffer, count);	return -EIO;}static struct sysfs_ops edac_pci_sysfs_ops = {	.show = edac_pci_dev_show,	.store = edac_pci_dev_store};#define EDAC_PCI_ATTR(_name,_mode,_show,_store)			\static struct edac_pci_dev_attribute edac_pci_attr_##_name = {		\	.attr = {.name = __stringify(_name), .mode = _mode },	\	.value  = &_name,					\	.show   = _show,					\	.store  = _store,					\};#define EDAC_PCI_STRING_ATTR(_name,_data,_mode,_show,_store)	\static struct edac_pci_dev_attribute edac_pci_attr_##_name = {		\	.attr = {.name = __stringify(_name), .mode = _mode },	\	.value  = _data,					\	.show   = _show,					\	.store  = _store,					\};/* PCI Parity control files */EDAC_PCI_ATTR(check_pci_errors, S_IRUGO | S_IWUSR, edac_pci_int_show,	edac_pci_int_store);EDAC_PCI_ATTR(edac_pci_log_pe, S_IRUGO | S_IWUSR, edac_pci_int_show,	edac_pci_int_store);EDAC_PCI_ATTR(edac_pci_log_npe, S_IRUGO | S_IWUSR, edac_pci_int_show,	edac_pci_int_store);EDAC_PCI_ATTR(edac_pci_panic_on_pe, S_IRUGO | S_IWUSR, edac_pci_int_show,	edac_pci_int_store);EDAC_PCI_ATTR(pci_parity_count, S_IRUGO, edac_pci_int_show, NULL);EDAC_PCI_ATTR(pci_nonparity_count, S_IRUGO, edac_pci_int_show, NULL);/* Base Attributes of the memory ECC object */static struct edac_pci_dev_attribute *edac_pci_attr[] = {	&edac_pci_attr_check_pci_errors,	&edac_pci_attr_edac_pci_log_pe,	&edac_pci_attr_edac_pci_log_npe,	&edac_pci_attr_edac_pci_panic_on_pe,	&edac_pci_attr_pci_parity_count,	&edac_pci_attr_pci_nonparity_count,	NULL,};/* * edac_pci_release_main_kobj * *	This release function is called when the reference count to the *	passed kobj goes to zero. * *	This kobj is the 'main' kobject that EDAC PCI instances *	link to, and thus provide for proper nesting counts */static void edac_pci_release_main_kobj(struct kobject *kobj){	debugf0("%s() here to module_put(THIS_MODULE)\n", __func__);	/* last reference to top EDAC PCI kobject has been removed,	 * NOW release our ref count on the core module	 */	module_put(THIS_MODULE);}/* ktype struct for the EDAC PCI main kobj */static struct kobj_type ktype_edac_pci_main_kobj = {	.release = edac_pci_release_main_kobj,	.sysfs_ops = &edac_pci_sysfs_ops,	.default_attrs = (struct attribute **)edac_pci_attr,};/** * edac_pci_main_kobj_setup() * *	setup the sysfs for EDAC PCI attributes *	assumes edac_class has already been initialized */int edac_pci_main_kobj_setup(void){	int err;	struct sysdev_class *edac_class;	debugf0("%s()\n", __func__);	/* check and count if we have already created the main kobject */	if (atomic_inc_return(&edac_pci_sysfs_refcount) != 1)		return 0;	/* First time, so create the main kobject and its	 * controls and atributes	 */	edac_class = edac_get_edac_class();	if (edac_class == NULL) {		debugf1("%s() no edac_class\n", __func__);		err = -ENODEV;		goto decrement_count_fail;	}	/* Need the kobject hook ups, and name setting */	edac_pci_top_main_kobj.ktype = &ktype_edac_pci_main_kobj;	edac_pci_top_main_kobj.parent = &edac_class->kset.kobj;	err = kobject_set_name(&edac_pci_top_main_kobj, "pci");	if (err)		goto decrement_count_fail;	/* Bump the reference count on this module to ensure the	 * modules isn't unloaded until we deconstruct the top	 * level main kobj for EDAC PCI	 */	if (!try_module_get(THIS_MODULE)) {		debugf1("%s() try_module_get() failed\n", __func__);		err = -ENODEV;		goto decrement_count_fail;

⌨️ 快捷键说明

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