+/* 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 },
+};
+
+
+/*
+ * 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;
+ }
+
+ /* this instance become part of the mc_kset */
+ kobj_mci->kset = &mc_kset;
+
+ /* register the mc<id> kobject to the mc_kset */
+ err = kobject_init_and_add(kobj_mci, &ktype_mci, NULL,
+ "mc%d", mci->mc_idx);
+ if (err) {
+ debugf1("%s()Failed to register '.../edac/mc%d'\n",
+ __func__, mci->mc_idx);
+ goto kobj_reg_fail;
+ }
+ kobject_uevent(kobj_mci, KOBJ_ADD);
+
+ /* 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_put(&mci->edac_mci_kobj);
+}