edac_device_sysfs.c
来自「linux 内核源代码」· C语言 代码 · 共 897 行 · 第 1/2 页
C
897 行
/* * file for managing the edac_device class of devices for EDAC * * (C) 2007 SoftwareBitMaker (http://www.softwarebitmaker.com) * * This file may be distributed under the terms of the * GNU General Public License. * * Written Doug Thompson <norsk5@xmission.com> * */#include <linux/ctype.h>#include <linux/module.h>#include "edac_core.h"#include "edac_module.h"#define EDAC_DEVICE_SYMLINK "device"#define to_edacdev(k) container_of(k, struct edac_device_ctl_info, kobj)#define to_edacdev_attr(a) container_of(a, struct edacdev_attribute, attr)/* * Set of edac_device_ctl_info attribute store/show functions *//* 'log_ue' */static ssize_t edac_device_ctl_log_ue_show(struct edac_device_ctl_info *ctl_info, char *data){ return sprintf(data, "%u\n", ctl_info->log_ue);}static ssize_t edac_device_ctl_log_ue_store(struct edac_device_ctl_info *ctl_info, const char *data, size_t count){ /* if parameter is zero, turn off flag, if non-zero turn on flag */ ctl_info->log_ue = (simple_strtoul(data, NULL, 0) != 0); return count;}/* 'log_ce' */static ssize_t edac_device_ctl_log_ce_show(struct edac_device_ctl_info *ctl_info, char *data){ return sprintf(data, "%u\n", ctl_info->log_ce);}static ssize_t edac_device_ctl_log_ce_store(struct edac_device_ctl_info *ctl_info, const char *data, size_t count){ /* if parameter is zero, turn off flag, if non-zero turn on flag */ ctl_info->log_ce = (simple_strtoul(data, NULL, 0) != 0); return count;}/* 'panic_on_ue' */static ssize_t edac_device_ctl_panic_on_ue_show(struct edac_device_ctl_info *ctl_info, char *data){ return sprintf(data, "%u\n", ctl_info->panic_on_ue);}static ssize_t edac_device_ctl_panic_on_ue_store(struct edac_device_ctl_info *ctl_info, const char *data, size_t count){ /* if parameter is zero, turn off flag, if non-zero turn on flag */ ctl_info->panic_on_ue = (simple_strtoul(data, NULL, 0) != 0); return count;}/* 'poll_msec' show and store functions*/static ssize_t edac_device_ctl_poll_msec_show(struct edac_device_ctl_info *ctl_info, char *data){ return sprintf(data, "%u\n", ctl_info->poll_msec);}static ssize_t edac_device_ctl_poll_msec_store(struct edac_device_ctl_info *ctl_info, const char *data, size_t count){ unsigned long value; /* get the value and enforce that it is non-zero, must be at least * one millisecond for the delay period, between scans * Then cancel last outstanding delay for the work request * and set a new one. */ value = simple_strtoul(data, NULL, 0); edac_device_reset_delay_period(ctl_info, value); return count;}/* edac_device_ctl_info specific attribute structure */struct ctl_info_attribute { struct attribute attr; ssize_t(*show) (struct edac_device_ctl_info *, char *); ssize_t(*store) (struct edac_device_ctl_info *, const char *, size_t);};#define to_ctl_info(k) container_of(k, struct edac_device_ctl_info, kobj)#define to_ctl_info_attr(a) container_of(a,struct ctl_info_attribute,attr)/* Function to 'show' fields from the edac_dev 'ctl_info' structure */static ssize_t edac_dev_ctl_info_show(struct kobject *kobj, struct attribute *attr, char *buffer){ struct edac_device_ctl_info *edac_dev = to_ctl_info(kobj); struct ctl_info_attribute *ctl_info_attr = to_ctl_info_attr(attr); if (ctl_info_attr->show) return ctl_info_attr->show(edac_dev, buffer); return -EIO;}/* Function to 'store' fields into the edac_dev 'ctl_info' structure */static ssize_t edac_dev_ctl_info_store(struct kobject *kobj, struct attribute *attr, const char *buffer, size_t count){ struct edac_device_ctl_info *edac_dev = to_ctl_info(kobj); struct ctl_info_attribute *ctl_info_attr = to_ctl_info_attr(attr); if (ctl_info_attr->store) return ctl_info_attr->store(edac_dev, buffer, count); return -EIO;}/* edac_dev file operations for an 'ctl_info' */static struct sysfs_ops device_ctl_info_ops = { .show = edac_dev_ctl_info_show, .store = edac_dev_ctl_info_store};#define CTL_INFO_ATTR(_name,_mode,_show,_store) \static struct ctl_info_attribute attr_ctl_info_##_name = { \ .attr = {.name = __stringify(_name), .mode = _mode }, \ .show = _show, \ .store = _store, \};/* Declare the various ctl_info attributes here and their respective ops */CTL_INFO_ATTR(log_ue, S_IRUGO | S_IWUSR, edac_device_ctl_log_ue_show, edac_device_ctl_log_ue_store);CTL_INFO_ATTR(log_ce, S_IRUGO | S_IWUSR, edac_device_ctl_log_ce_show, edac_device_ctl_log_ce_store);CTL_INFO_ATTR(panic_on_ue, S_IRUGO | S_IWUSR, edac_device_ctl_panic_on_ue_show, edac_device_ctl_panic_on_ue_store);CTL_INFO_ATTR(poll_msec, S_IRUGO | S_IWUSR, edac_device_ctl_poll_msec_show, edac_device_ctl_poll_msec_store);/* Base Attributes of the EDAC_DEVICE ECC object */static struct ctl_info_attribute *device_ctrl_attr[] = { &attr_ctl_info_panic_on_ue, &attr_ctl_info_log_ue, &attr_ctl_info_log_ce, &attr_ctl_info_poll_msec, NULL,};/* * edac_device_ctrl_master_release * * called when the reference count for the 'main' kobj * for a edac_device control struct reaches zero * * Reference count model: * One 'main' kobject for each control structure allocated. * That main kobj is initially set to one AND * the reference count for the EDAC 'core' module is * bumped by one, thus added 'keep in memory' dependency. * * Each new internal kobj (in instances and blocks) then * bumps the 'main' kobject. * * When they are released their release functions decrement * the 'main' kobj. * * When the main kobj reaches zero (0) then THIS function * is called which then decrements the EDAC 'core' module. * When the module reference count reaches zero then the * module no longer has dependency on keeping the release * function code in memory and module can be unloaded. * * This will support several control objects as well, each * with its own 'main' kobj. */static void edac_device_ctrl_master_release(struct kobject *kobj){ struct edac_device_ctl_info *edac_dev = to_edacdev(kobj); debugf4("%s() control index=%d\n", __func__, edac_dev->dev_idx); /* decrement the EDAC CORE module ref count */ module_put(edac_dev->owner); /* free the control struct containing the 'main' kobj * passed in to this routine */ kfree(edac_dev);}/* ktype for the main (master) kobject */static struct kobj_type ktype_device_ctrl = { .release = edac_device_ctrl_master_release, .sysfs_ops = &device_ctl_info_ops, .default_attrs = (struct attribute **)device_ctrl_attr,};/* * edac_device_register_sysfs_main_kobj * * perform the high level setup for the new edac_device instance * * Return: 0 SUCCESS * !0 FAILURE */int edac_device_register_sysfs_main_kobj(struct edac_device_ctl_info *edac_dev){ struct sysdev_class *edac_class; int err; debugf1("%s()\n", __func__); /* get the /sys/devices/system/edac reference */ edac_class = edac_get_edac_class(); if (edac_class == NULL) { debugf1("%s() no edac_class error\n", __func__); err = -ENODEV; goto err_out; } /* Point to the 'edac_class' this instance 'reports' to */ edac_dev->edac_class = edac_class; /* Init the devices's kobject */ memset(&edac_dev->kobj, 0, sizeof(struct kobject)); edac_dev->kobj.ktype = &ktype_device_ctrl; /* set this new device under the edac_class kobject */ edac_dev->kobj.parent = &edac_class->kset.kobj; /* generate sysfs "..../edac/<name>" */ debugf4("%s() set name of kobject to: %s\n", __func__, edac_dev->name); err = kobject_set_name(&edac_dev->kobj, "%s", edac_dev->name); if (err) goto err_out; /* Record which module 'owns' this control structure * and bump the ref count of the module */ edac_dev->owner = THIS_MODULE; if (!try_module_get(edac_dev->owner)) { err = -ENODEV; goto err_out; } /* register */ err = kobject_register(&edac_dev->kobj); if (err) { debugf1("%s()Failed to register '.../edac/%s'\n", __func__, edac_dev->name); goto err_kobj_reg; } /* At this point, to 'free' the control struct, * edac_device_unregister_sysfs_main_kobj() must be used */ debugf4("%s() Registered '.../edac/%s' kobject\n", __func__, edac_dev->name); return 0; /* Error exit stack */err_kobj_reg: module_put(edac_dev->owner);err_out: return err;}/* * edac_device_unregister_sysfs_main_kobj: * the '..../edac/<name>' kobject */void edac_device_unregister_sysfs_main_kobj( struct edac_device_ctl_info *edac_dev){ debugf0("%s()\n", __func__); debugf4("%s() name of kobject is: %s\n", __func__, kobject_name(&edac_dev->kobj)); /* * Unregister the edac device's kobject and * allow for reference count to reach 0 at which point * the callback will be called to: * a) module_put() this module * b) 'kfree' the memory */ kobject_unregister(&edac_dev->kobj);}/* edac_dev -> instance information *//* * Set of low-level instance attribute show functions */static ssize_t instance_ue_count_show(struct edac_device_instance *instance, char *data){ return sprintf(data, "%u\n", instance->counters.ue_count);}static ssize_t instance_ce_count_show(struct edac_device_instance *instance, char *data){ return sprintf(data, "%u\n", instance->counters.ce_count);}#define to_instance(k) container_of(k, struct edac_device_instance, kobj)#define to_instance_attr(a) container_of(a,struct instance_attribute,attr)/* DEVICE instance kobject release() function */static void edac_device_ctrl_instance_release(struct kobject *kobj){ struct edac_device_instance *instance; debugf1("%s()\n", __func__); /* map from this kobj to the main control struct * and then dec the main kobj count */ instance = to_instance(kobj); kobject_put(&instance->ctl->kobj);}/* instance specific attribute structure */struct instance_attribute { struct attribute attr; ssize_t(*show) (struct edac_device_instance *, char *); ssize_t(*store) (struct edac_device_instance *, const char *, size_t);};/* Function to 'show' fields from the edac_dev 'instance' structure */static ssize_t edac_dev_instance_show(struct kobject *kobj, struct attribute *attr, char *buffer){ struct edac_device_instance *instance = to_instance(kobj); struct instance_attribute *instance_attr = to_instance_attr(attr); if (instance_attr->show) return instance_attr->show(instance, buffer); return -EIO;}/* Function to 'store' fields into the edac_dev 'instance' structure */static ssize_t edac_dev_instance_store(struct kobject *kobj, struct attribute *attr, const char *buffer, size_t count){ struct edac_device_instance *instance = to_instance(kobj); struct instance_attribute *instance_attr = to_instance_attr(attr); if (instance_attr->store) return instance_attr->store(instance, buffer, count); return -EIO;}/* edac_dev file operations for an 'instance' */static struct sysfs_ops device_instance_ops = { .show = edac_dev_instance_show, .store = edac_dev_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, \};/* * Define attributes visible for the edac_device instance object * Each contains a pointer to a show and an optional set * function pointer that does the low level output/input */INSTANCE_ATTR(ce_count, S_IRUGO, instance_ce_count_show, NULL);INSTANCE_ATTR(ue_count, S_IRUGO, instance_ue_count_show, NULL);/* list of edac_dev 'instance' attributes */static struct instance_attribute *device_instance_attr[] = { &attr_instance_ce_count, &attr_instance_ue_count, NULL,};/* The 'ktype' for each edac_dev 'instance' */static struct kobj_type ktype_instance_ctrl = { .release = edac_device_ctrl_instance_release, .sysfs_ops = &device_instance_ops, .default_attrs = (struct attribute **)device_instance_attr,};/* edac_dev -> instance -> block information */#define to_block(k) container_of(k, struct edac_device_block, kobj)#define to_block_attr(a) \ container_of(a, struct edac_dev_sysfs_block_attribute, attr)/* * Set of low-level block attribute show functions */static ssize_t block_ue_count_show(struct kobject *kobj, struct attribute *attr, char *data){ struct edac_device_block *block = to_block(kobj); return sprintf(data, "%u\n", block->counters.ue_count);}static ssize_t block_ce_count_show(struct kobject *kobj, struct attribute *attr, char *data){ struct edac_device_block *block = to_block(kobj); return sprintf(data, "%u\n", block->counters.ce_count);}/* DEVICE block kobject release() function */static void edac_device_ctrl_block_release(struct kobject *kobj){ struct edac_device_block *block; debugf1("%s()\n", __func__); /* get the container of the kobj */
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?