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 + -
显示快捷键?