drm: bridge: dw-hdmi: optimize edid reading process
[firefly-linux-kernel-4.4.55.git] / drivers / edac / edac_mc_sysfs.c
index 67610a6ebf875765682cb50bec4226b42f956fc3..3c8f19f5ac8183ed2dd2fd13fce9c89c9896a7e4 100644 (file)
@@ -7,7 +7,7 @@
  *
  * Written Doug Thompson <norsk5@xmission.com> www.softwarebitmaker.com
  *
- * (c) 2012-2013 - Mauro Carvalho Chehab <mchehab@redhat.com>
+ * (c) 2012-2013 - Mauro Carvalho Chehab
  *     The entire API were re-written, and ported to use struct device
  *
  */
@@ -52,16 +52,20 @@ int edac_mc_get_poll_msec(void)
 
 static int edac_set_poll_msec(const char *val, struct kernel_param *kp)
 {
-       long l;
+       unsigned long l;
        int ret;
 
        if (!val)
                return -EINVAL;
 
-       ret = strict_strtol(val, 0, &l);
-       if (ret == -EINVAL || ((int)l != l))
+       ret = kstrtoul(val, 0, &l);
+       if (ret)
+               return ret;
+
+       if (l < 1000)
                return -EINVAL;
-       *((int *)kp->arg) = l;
+
+       *((unsigned long *)kp->arg) = l;
 
        /* notify edac_mc engine to reset the poll period */
        edac_mc_reset_delay_period(l);
@@ -104,7 +108,9 @@ static const char * const mem_types[] = {
        [MEM_RDDR2] = "Registered-DDR2",
        [MEM_XDR] = "XDR",
        [MEM_DDR3] = "Unbuffered-DDR3",
-       [MEM_RDDR3] = "Registered-DDR3"
+       [MEM_RDDR3] = "Registered-DDR3",
+       [MEM_DDR4] = "Unbuffered-DDR4",
+       [MEM_RDDR4] = "Registered-DDR4"
 };
 
 static const char * const dev_types[] = {
@@ -151,7 +157,7 @@ struct dev_ch_attribute {
 };
 
 #define DEVICE_CHANNEL(_name, _mode, _show, _store, _var) \
-       struct dev_ch_attribute dev_attr_legacy_##_name = \
+       static struct dev_ch_attribute dev_attr_legacy_##_name = \
                { __ATTR(_name, _mode, _show, _store), (_var) }
 
 #define to_channel(k) (container_of(k, struct dev_ch_attribute, attr)->channel)
@@ -223,7 +229,7 @@ static ssize_t channel_dimm_label_show(struct device *dev,
        if (!rank->dimm->label[0])
                return 0;
 
-       return snprintf(data, EDAC_MC_LABEL_LEN, "%s\n",
+       return snprintf(data, sizeof(rank->dimm->label) + 1, "%s\n",
                        rank->dimm->label);
 }
 
@@ -234,14 +240,21 @@ static ssize_t channel_dimm_label_store(struct device *dev,
        struct csrow_info *csrow = to_csrow(dev);
        unsigned chan = to_channel(mattr);
        struct rank_info *rank = csrow->channels[chan];
+       size_t copy_count = count;
+
+       if (count == 0)
+               return -EINVAL;
 
-       ssize_t max_size = 0;
+       if (data[count - 1] == '\0' || data[count - 1] == '\n')
+               copy_count -= 1;
 
-       max_size = min((ssize_t) count, (ssize_t) EDAC_MC_LABEL_LEN - 1);
-       strncpy(rank->dimm->label, data, max_size);
-       rank->dimm->label[max_size] = '\0';
+       if (copy_count == 0 || copy_count >= sizeof(rank->dimm->label))
+               return -EINVAL;
+
+       strncpy(rank->dimm->label, data, copy_count);
+       rank->dimm->label[copy_count] = '\0';
 
-       return max_size;
+       return count;
 }
 
 /* show function for dynamic chX_ce_count attribute */
@@ -300,9 +313,6 @@ static struct device_type csrow_attr_type = {
  * possible dynamic channel DIMM Label attribute files
  *
  */
-
-#define EDAC_NR_CHANNELS       6
-
 DEVICE_CHANNEL(ch0_dimm_label, S_IRUGO | S_IWUSR,
        channel_dimm_label_show, channel_dimm_label_store, 0);
 DEVICE_CHANNEL(ch1_dimm_label, S_IRUGO | S_IWUSR,
@@ -315,15 +325,22 @@ DEVICE_CHANNEL(ch4_dimm_label, S_IRUGO | S_IWUSR,
        channel_dimm_label_show, channel_dimm_label_store, 4);
 DEVICE_CHANNEL(ch5_dimm_label, S_IRUGO | S_IWUSR,
        channel_dimm_label_show, channel_dimm_label_store, 5);
+DEVICE_CHANNEL(ch6_dimm_label, S_IRUGO | S_IWUSR,
+       channel_dimm_label_show, channel_dimm_label_store, 6);
+DEVICE_CHANNEL(ch7_dimm_label, S_IRUGO | S_IWUSR,
+       channel_dimm_label_show, channel_dimm_label_store, 7);
 
 /* Total possible dynamic DIMM Label attribute file table */
-static struct device_attribute *dynamic_csrow_dimm_attr[] = {
-       &dev_attr_legacy_ch0_dimm_label.attr,
-       &dev_attr_legacy_ch1_dimm_label.attr,
-       &dev_attr_legacy_ch2_dimm_label.attr,
-       &dev_attr_legacy_ch3_dimm_label.attr,
-       &dev_attr_legacy_ch4_dimm_label.attr,
-       &dev_attr_legacy_ch5_dimm_label.attr
+static struct attribute *dynamic_csrow_dimm_attr[] = {
+       &dev_attr_legacy_ch0_dimm_label.attr.attr,
+       &dev_attr_legacy_ch1_dimm_label.attr.attr,
+       &dev_attr_legacy_ch2_dimm_label.attr.attr,
+       &dev_attr_legacy_ch3_dimm_label.attr.attr,
+       &dev_attr_legacy_ch4_dimm_label.attr.attr,
+       &dev_attr_legacy_ch5_dimm_label.attr.attr,
+       &dev_attr_legacy_ch6_dimm_label.attr.attr,
+       &dev_attr_legacy_ch7_dimm_label.attr.attr,
+       NULL
 };
 
 /* possible dynamic channel ce_count attribute files */
@@ -339,15 +356,60 @@ DEVICE_CHANNEL(ch4_ce_count, S_IRUGO,
                   channel_ce_count_show, NULL, 4);
 DEVICE_CHANNEL(ch5_ce_count, S_IRUGO,
                   channel_ce_count_show, NULL, 5);
+DEVICE_CHANNEL(ch6_ce_count, S_IRUGO,
+                  channel_ce_count_show, NULL, 6);
+DEVICE_CHANNEL(ch7_ce_count, S_IRUGO,
+                  channel_ce_count_show, NULL, 7);
 
 /* Total possible dynamic ce_count attribute file table */
-static struct device_attribute *dynamic_csrow_ce_count_attr[] = {
-       &dev_attr_legacy_ch0_ce_count.attr,
-       &dev_attr_legacy_ch1_ce_count.attr,
-       &dev_attr_legacy_ch2_ce_count.attr,
-       &dev_attr_legacy_ch3_ce_count.attr,
-       &dev_attr_legacy_ch4_ce_count.attr,
-       &dev_attr_legacy_ch5_ce_count.attr
+static struct attribute *dynamic_csrow_ce_count_attr[] = {
+       &dev_attr_legacy_ch0_ce_count.attr.attr,
+       &dev_attr_legacy_ch1_ce_count.attr.attr,
+       &dev_attr_legacy_ch2_ce_count.attr.attr,
+       &dev_attr_legacy_ch3_ce_count.attr.attr,
+       &dev_attr_legacy_ch4_ce_count.attr.attr,
+       &dev_attr_legacy_ch5_ce_count.attr.attr,
+       &dev_attr_legacy_ch6_ce_count.attr.attr,
+       &dev_attr_legacy_ch7_ce_count.attr.attr,
+       NULL
+};
+
+static umode_t csrow_dev_is_visible(struct kobject *kobj,
+                                   struct attribute *attr, int idx)
+{
+       struct device *dev = kobj_to_dev(kobj);
+       struct csrow_info *csrow = container_of(dev, struct csrow_info, dev);
+
+       if (idx >= csrow->nr_channels)
+               return 0;
+
+       if (idx >= ARRAY_SIZE(dynamic_csrow_ce_count_attr) - 1) {
+               WARN_ONCE(1, "idx: %d\n", idx);
+               return 0;
+       }
+
+       /* Only expose populated DIMMs */
+       if (!csrow->channels[idx]->dimm->nr_pages)
+               return 0;
+
+       return attr->mode;
+}
+
+
+static const struct attribute_group csrow_dev_dimm_group = {
+       .attrs = dynamic_csrow_dimm_attr,
+       .is_visible = csrow_dev_is_visible,
+};
+
+static const struct attribute_group csrow_dev_ce_count_group = {
+       .attrs = dynamic_csrow_ce_count_attr,
+       .is_visible = csrow_dev_is_visible,
+};
+
+static const struct attribute_group *csrow_dev_groups[] = {
+       &csrow_dev_dimm_group,
+       &csrow_dev_ce_count_group,
+       NULL
 };
 
 static inline int nr_pages_per_csrow(struct csrow_info *csrow)
@@ -364,13 +426,9 @@ static inline int nr_pages_per_csrow(struct csrow_info *csrow)
 static int edac_create_csrow_object(struct mem_ctl_info *mci,
                                    struct csrow_info *csrow, int index)
 {
-       int err, chan;
-
-       if (csrow->nr_channels >= EDAC_NR_CHANNELS)
-               return -ENODEV;
-
        csrow->dev.type = &csrow_attr_type;
-       csrow->dev.bus = &mci->bus;
+       csrow->dev.bus = mci->bus;
+       csrow->dev.groups = csrow_dev_groups;
        device_initialize(&csrow->dev);
        csrow->dev.parent = &mci->dev;
        csrow->mci = mci;
@@ -380,45 +438,13 @@ static int edac_create_csrow_object(struct mem_ctl_info *mci,
        edac_dbg(0, "creating (virtual) csrow node %s\n",
                 dev_name(&csrow->dev));
 
-       err = device_add(&csrow->dev);
-       if (err < 0)
-               return err;
-
-       for (chan = 0; chan < csrow->nr_channels; chan++) {
-               /* Only expose populated DIMMs */
-               if (!csrow->channels[chan]->dimm->nr_pages)
-                       continue;
-               err = device_create_file(&csrow->dev,
-                                        dynamic_csrow_dimm_attr[chan]);
-               if (err < 0)
-                       goto error;
-               err = device_create_file(&csrow->dev,
-                                        dynamic_csrow_ce_count_attr[chan]);
-               if (err < 0) {
-                       device_remove_file(&csrow->dev,
-                                          dynamic_csrow_dimm_attr[chan]);
-                       goto error;
-               }
-       }
-
-       return 0;
-
-error:
-       for (--chan; chan >= 0; chan--) {
-               device_remove_file(&csrow->dev,
-                                       dynamic_csrow_dimm_attr[chan]);
-               device_remove_file(&csrow->dev,
-                                          dynamic_csrow_ce_count_attr[chan]);
-       }
-       put_device(&csrow->dev);
-
-       return err;
+       return device_add(&csrow->dev);
 }
 
 /* Create a CSROW object under specifed edac_mc_device */
 static int edac_create_csrow_objects(struct mem_ctl_info *mci)
 {
-       int err, i, chan;
+       int err, i;
        struct csrow_info *csrow;
 
        for (i = 0; i < mci->nr_csrows; i++) {
@@ -440,14 +466,6 @@ error:
                csrow = mci->csrows[i];
                if (!nr_pages_per_csrow(csrow))
                        continue;
-               for (chan = csrow->nr_channels - 1; chan >= 0; chan--) {
-                       if (!csrow->channels[chan]->dimm->nr_pages)
-                               continue;
-                       device_remove_file(&csrow->dev,
-                                               dynamic_csrow_dimm_attr[chan]);
-                       device_remove_file(&csrow->dev,
-                                               dynamic_csrow_ce_count_attr[chan]);
-               }
                put_device(&mci->csrows[i]->dev);
        }
 
@@ -456,23 +474,13 @@ error:
 
 static void edac_delete_csrow_objects(struct mem_ctl_info *mci)
 {
-       int i, chan;
+       int i;
        struct csrow_info *csrow;
 
        for (i = mci->nr_csrows - 1; i >= 0; i--) {
                csrow = mci->csrows[i];
                if (!nr_pages_per_csrow(csrow))
                        continue;
-               for (chan = csrow->nr_channels - 1; chan >= 0; chan--) {
-                       if (!csrow->channels[chan]->dimm->nr_pages)
-                               continue;
-                       edac_dbg(1, "Removing csrow %d channel %d sysfs nodes\n",
-                                i, chan);
-                       device_remove_file(&csrow->dev,
-                                               dynamic_csrow_dimm_attr[chan]);
-                       device_remove_file(&csrow->dev,
-                                               dynamic_csrow_ce_count_attr[chan]);
-               }
                device_unregister(&mci->csrows[i]->dev);
        }
 }
@@ -502,7 +510,7 @@ static ssize_t dimmdev_label_show(struct device *dev,
        if (!dimm->label[0])
                return 0;
 
-       return snprintf(data, EDAC_MC_LABEL_LEN, "%s\n", dimm->label);
+       return snprintf(data, sizeof(dimm->label) + 1, "%s\n", dimm->label);
 }
 
 static ssize_t dimmdev_label_store(struct device *dev,
@@ -511,14 +519,21 @@ static ssize_t dimmdev_label_store(struct device *dev,
                                   size_t count)
 {
        struct dimm_info *dimm = to_dimm(dev);
+       size_t copy_count = count;
 
-       ssize_t max_size = 0;
+       if (count == 0)
+               return -EINVAL;
+
+       if (data[count - 1] == '\0' || data[count - 1] == '\n')
+               copy_count -= 1;
+
+       if (copy_count == 0 || copy_count >= sizeof(dimm->label))
+               return -EINVAL;
 
-       max_size = min((ssize_t) count, (ssize_t) EDAC_MC_LABEL_LEN - 1);
-       strncpy(dimm->label, data, max_size);
-       dimm->label[max_size] = '\0';
+       strncpy(dimm->label, data, copy_count);
+       dimm->label[copy_count] = '\0';
 
-       return max_size;
+       return count;
 }
 
 static ssize_t dimmdev_size_show(struct device *dev,
@@ -605,7 +620,7 @@ static int edac_create_dimm_object(struct mem_ctl_info *mci,
        dimm->mci = mci;
 
        dimm->dev.type = &dimm_attr_type;
-       dimm->dev.bus = &mci->bus;
+       dimm->dev.bus = mci->bus;
        device_initialize(&dimm->dev);
 
        dimm->dev.parent = &mci->dev;
@@ -678,7 +693,7 @@ static ssize_t mci_sdram_scrub_rate_store(struct device *dev,
        unsigned long bandwidth = 0;
        int new_bw = 0;
 
-       if (strict_strtoul(data, 10, &bandwidth) < 0)
+       if (kstrtoul(data, 10, &bandwidth) < 0)
                return -EINVAL;
 
        new_bw = mci->set_sdram_scrub_rate(mci, bandwidth);
@@ -802,62 +817,22 @@ static ssize_t mci_max_location_show(struct device *dev,
        return p - data;
 }
 
-#ifdef CONFIG_EDAC_DEBUG
-static ssize_t edac_fake_inject_write(struct file *file,
-                                     const char __user *data,
-                                     size_t count, loff_t *ppos)
-{
-       struct device *dev = file->private_data;
-       struct mem_ctl_info *mci = to_mci(dev);
-       static enum hw_event_mc_err_type type;
-       u16 errcount = mci->fake_inject_count;
-
-       if (!errcount)
-               errcount = 1;
-
-       type = mci->fake_inject_ue ? HW_EVENT_ERR_UNCORRECTED
-                                  : HW_EVENT_ERR_CORRECTED;
-
-       printk(KERN_DEBUG
-              "Generating %d %s fake error%s to %d.%d.%d to test core handling. NOTE: this won't test the driver-specific decoding logic.\n",
-               errcount,
-               (type == HW_EVENT_ERR_UNCORRECTED) ? "UE" : "CE",
-               errcount > 1 ? "s" : "",
-               mci->fake_inject_layer[0],
-               mci->fake_inject_layer[1],
-               mci->fake_inject_layer[2]
-              );
-       edac_mc_handle_error(type, mci, errcount, 0, 0, 0,
-                            mci->fake_inject_layer[0],
-                            mci->fake_inject_layer[1],
-                            mci->fake_inject_layer[2],
-                            "FAKE ERROR", "for EDAC testing only");
-
-       return count;
-}
-
-static const struct file_operations debug_fake_inject_fops = {
-       .open = simple_open,
-       .write = edac_fake_inject_write,
-       .llseek = generic_file_llseek,
-};
-#endif
-
 /* default Control file */
-DEVICE_ATTR(reset_counters, S_IWUSR, NULL, mci_reset_counters_store);
+static DEVICE_ATTR(reset_counters, S_IWUSR, NULL, mci_reset_counters_store);
 
 /* default Attribute files */
-DEVICE_ATTR(mc_name, S_IRUGO, mci_ctl_name_show, NULL);
-DEVICE_ATTR(size_mb, S_IRUGO, mci_size_mb_show, NULL);
-DEVICE_ATTR(seconds_since_reset, S_IRUGO, mci_seconds_show, NULL);
-DEVICE_ATTR(ue_noinfo_count, S_IRUGO, mci_ue_noinfo_show, NULL);
-DEVICE_ATTR(ce_noinfo_count, S_IRUGO, mci_ce_noinfo_show, NULL);
-DEVICE_ATTR(ue_count, S_IRUGO, mci_ue_count_show, NULL);
-DEVICE_ATTR(ce_count, S_IRUGO, mci_ce_count_show, NULL);
-DEVICE_ATTR(max_location, S_IRUGO, mci_max_location_show, NULL);
+static DEVICE_ATTR(mc_name, S_IRUGO, mci_ctl_name_show, NULL);
+static DEVICE_ATTR(size_mb, S_IRUGO, mci_size_mb_show, NULL);
+static DEVICE_ATTR(seconds_since_reset, S_IRUGO, mci_seconds_show, NULL);
+static DEVICE_ATTR(ue_noinfo_count, S_IRUGO, mci_ue_noinfo_show, NULL);
+static DEVICE_ATTR(ce_noinfo_count, S_IRUGO, mci_ce_noinfo_show, NULL);
+static DEVICE_ATTR(ue_count, S_IRUGO, mci_ue_count_show, NULL);
+static DEVICE_ATTR(ce_count, S_IRUGO, mci_ce_count_show, NULL);
+static DEVICE_ATTR(max_location, S_IRUGO, mci_max_location_show, NULL);
 
 /* memory scrubber attribute file */
-DEVICE_ATTR(sdram_scrub_rate, 0, NULL, NULL);
+DEVICE_ATTR(sdram_scrub_rate, 0, mci_sdram_scrub_rate_show,
+           mci_sdram_scrub_rate_store); /* umode set later in is_visible */
 
 static struct attribute *mci_attrs[] = {
        &dev_attr_reset_counters.attr,
@@ -869,11 +844,29 @@ static struct attribute *mci_attrs[] = {
        &dev_attr_ue_count.attr,
        &dev_attr_ce_count.attr,
        &dev_attr_max_location.attr,
+       &dev_attr_sdram_scrub_rate.attr,
        NULL
 };
 
+static umode_t mci_attr_is_visible(struct kobject *kobj,
+                                  struct attribute *attr, int idx)
+{
+       struct device *dev = kobj_to_dev(kobj);
+       struct mem_ctl_info *mci = to_mci(dev);
+       umode_t mode = 0;
+
+       if (attr != &dev_attr_sdram_scrub_rate.attr)
+               return attr->mode;
+       if (mci->get_sdram_scrub_rate)
+               mode |= S_IRUGO;
+       if (mci->set_sdram_scrub_rate)
+               mode |= S_IWUSR;
+       return mode;
+}
+
 static struct attribute_group mci_attr_grp = {
        .attrs  = mci_attrs,
+       .is_visible = mci_attr_is_visible,
 };
 
 static const struct attribute_group *mci_attr_groups[] = {
@@ -894,71 +887,6 @@ static struct device_type mci_attr_type = {
        .release        = mci_attr_release,
 };
 
-#ifdef CONFIG_EDAC_DEBUG
-static struct dentry *edac_debugfs;
-
-int __init edac_debugfs_init(void)
-{
-       edac_debugfs = debugfs_create_dir("edac", NULL);
-       if (IS_ERR(edac_debugfs)) {
-               edac_debugfs = NULL;
-               return -ENOMEM;
-       }
-       return 0;
-}
-
-void __exit edac_debugfs_exit(void)
-{
-       debugfs_remove(edac_debugfs);
-}
-
-int edac_create_debug_nodes(struct mem_ctl_info *mci)
-{
-       struct dentry *d, *parent;
-       char name[80];
-       int i;
-
-       if (!edac_debugfs)
-               return -ENODEV;
-
-       d = debugfs_create_dir(mci->dev.kobj.name, edac_debugfs);
-       if (!d)
-               return -ENOMEM;
-       parent = d;
-
-       for (i = 0; i < mci->n_layers; i++) {
-               sprintf(name, "fake_inject_%s",
-                            edac_layer_name[mci->layers[i].type]);
-               d = debugfs_create_u8(name, S_IRUGO | S_IWUSR, parent,
-                                     &mci->fake_inject_layer[i]);
-               if (!d)
-                       goto nomem;
-       }
-
-       d = debugfs_create_bool("fake_inject_ue", S_IRUGO | S_IWUSR, parent,
-                               &mci->fake_inject_ue);
-       if (!d)
-               goto nomem;
-
-       d = debugfs_create_u16("fake_inject_count", S_IRUGO | S_IWUSR, parent,
-                               &mci->fake_inject_count);
-       if (!d)
-               goto nomem;
-
-       d = debugfs_create_file("fake_inject", S_IWUSR, parent,
-                               &mci->dev,
-                               &debug_fake_inject_fops);
-       if (!d)
-               goto nomem;
-
-       mci->debugfs = parent;
-       return 0;
-nomem:
-       debugfs_remove(mci->debugfs);
-       return -ENOMEM;
-}
-#endif
-
 /*
  * Create a new Memory Controller kobject instance,
  *     mc<id> under the 'mc' directory
@@ -967,28 +895,37 @@ nomem:
  *     0       Success
  *     !0      Failure
  */
-int edac_create_sysfs_mci_device(struct mem_ctl_info *mci)
+int edac_create_sysfs_mci_device(struct mem_ctl_info *mci,
+                                const struct attribute_group **groups)
 {
+       char *name;
        int i, err;
 
        /*
         * The memory controller needs its own bus, in order to avoid
         * namespace conflicts at /sys/bus/edac.
         */
-       mci->bus.name = kasprintf(GFP_KERNEL, "mc%d", mci->mc_idx);
-       if (!mci->bus.name)
+       name = kasprintf(GFP_KERNEL, "mc%d", mci->mc_idx);
+       if (!name)
                return -ENOMEM;
-       edac_dbg(0, "creating bus %s\n", mci->bus.name);
-       err = bus_register(&mci->bus);
-       if (err < 0)
+
+       mci->bus->name = name;
+
+       edac_dbg(0, "creating bus %s\n", mci->bus->name);
+
+       err = bus_register(mci->bus);
+       if (err < 0) {
+               kfree(name);
                return err;
+       }
 
        /* get the /sys/devices/system/edac subsys reference */
        mci->dev.type = &mci_attr_type;
        device_initialize(&mci->dev);
 
        mci->dev.parent = mci_pdev;
-       mci->dev.bus = &mci->bus;
+       mci->dev.bus = mci->bus;
+       mci->dev.groups = groups;
        dev_set_name(&mci->dev, "mc%d", mci->mc_idx);
        dev_set_drvdata(&mci->dev, mci);
        pm_runtime_forbid(&mci->dev);
@@ -997,35 +934,18 @@ int edac_create_sysfs_mci_device(struct mem_ctl_info *mci)
        err = device_add(&mci->dev);
        if (err < 0) {
                edac_dbg(1, "failure: create device %s\n", dev_name(&mci->dev));
-               bus_unregister(&mci->bus);
-               kfree(mci->bus.name);
-               return err;
+               goto fail_unregister_bus;
        }
 
-       if (mci->set_sdram_scrub_rate || mci->get_sdram_scrub_rate) {
-               if (mci->get_sdram_scrub_rate) {
-                       dev_attr_sdram_scrub_rate.attr.mode |= S_IRUGO;
-                       dev_attr_sdram_scrub_rate.show = &mci_sdram_scrub_rate_show;
-               }
-               if (mci->set_sdram_scrub_rate) {
-                       dev_attr_sdram_scrub_rate.attr.mode |= S_IWUSR;
-                       dev_attr_sdram_scrub_rate.store = &mci_sdram_scrub_rate_store;
-               }
-               err = device_create_file(&mci->dev,
-                                        &dev_attr_sdram_scrub_rate);
-               if (err) {
-                       edac_dbg(1, "failure: create sdram_scrub_rate\n");
-                       goto fail2;
-               }
-       }
        /*
         * Create the dimm/rank devices
         */
        for (i = 0; i < mci->tot_dimms; i++) {
                struct dimm_info *dimm = mci->dimms[i];
                /* Only expose populated DIMMs */
-               if (dimm->nr_pages == 0)
+               if (!dimm->nr_pages)
                        continue;
+
 #ifdef CONFIG_EDAC_DEBUG
                edac_dbg(1, "creating dimm%d, located at ", i);
                if (edac_debug_level >= 1) {
@@ -1040,32 +960,32 @@ int edac_create_sysfs_mci_device(struct mem_ctl_info *mci)
                err = edac_create_dimm_object(mci, dimm, i);
                if (err) {
                        edac_dbg(1, "failure: create dimm %d obj\n", i);
-                       goto fail;
+                       goto fail_unregister_dimm;
                }
        }
 
 #ifdef CONFIG_EDAC_LEGACY_SYSFS
        err = edac_create_csrow_objects(mci);
        if (err < 0)
-               goto fail;
+               goto fail_unregister_dimm;
 #endif
 
-#ifdef CONFIG_EDAC_DEBUG
-       edac_create_debug_nodes(mci);
-#endif
+       edac_create_debugfs_nodes(mci);
        return 0;
 
-fail:
+fail_unregister_dimm:
        for (i--; i >= 0; i--) {
                struct dimm_info *dimm = mci->dimms[i];
-               if (dimm->nr_pages == 0)
+               if (!dimm->nr_pages)
                        continue;
+
                device_unregister(&dimm->dev);
        }
-fail2:
        device_unregister(&mci->dev);
-       bus_unregister(&mci->bus);
-       kfree(mci->bus.name);
+fail_unregister_bus:
+       bus_unregister(mci->bus);
+       kfree(name);
+
        return err;
 }
 
@@ -1079,7 +999,7 @@ void edac_remove_sysfs_mci_device(struct mem_ctl_info *mci)
        edac_dbg(0, "\n");
 
 #ifdef CONFIG_EDAC_DEBUG
-       debugfs_remove(mci->debugfs);
+       edac_debugfs_remove_recursive(mci->debugfs);
 #endif
 #ifdef CONFIG_EDAC_LEGACY_SYSFS
        edac_delete_csrow_objects(mci);
@@ -1096,10 +1016,12 @@ void edac_remove_sysfs_mci_device(struct mem_ctl_info *mci)
 
 void edac_unregister_sysfs(struct mem_ctl_info *mci)
 {
+       const char *name = mci->bus->name;
+
        edac_dbg(1, "Unregistering device %s\n", dev_name(&mci->dev));
        device_unregister(&mci->dev);
-       bus_unregister(&mci->bus);
-       kfree(mci->bus.name);
+       bus_unregister(mci->bus);
+       kfree(name);
 }
 
 static void mc_attr_release(struct device *dev)
@@ -1159,7 +1081,7 @@ int __init edac_mc_sysfs_init(void)
        return err;
 }
 
-void __exit edac_mc_sysfs_exit(void)
+void edac_mc_sysfs_exit(void)
 {
        device_unregister(mci_pdev);
        edac_put_sysfs_subsys();