|
@@ -248,6 +248,8 @@ struct i7core_dev {
|
|
|
};
|
|
|
|
|
|
struct i7core_pvt {
|
|
|
+ struct device addrmatch_dev, chancounts_dev;
|
|
|
+
|
|
|
struct pci_dev *pci_noncore;
|
|
|
struct pci_dev *pci_mcr[MAX_MCR_FUNC + 1];
|
|
|
struct pci_dev *pci_ch[NUM_CHANS][MAX_CHAN_FUNC + 1];
|
|
@@ -662,6 +664,8 @@ static int get_dimm_config(struct mem_ctl_info *mci)
|
|
|
Error insertion routines
|
|
|
****************************************************************************/
|
|
|
|
|
|
+#define to_mci(k) container_of(k, struct mem_ctl_info, dev)
|
|
|
+
|
|
|
/* The i7core has independent error injection features per channel.
|
|
|
However, to have a simpler code, we don't allow enabling error injection
|
|
|
on more than one channel.
|
|
@@ -691,9 +695,11 @@ static int disable_inject(const struct mem_ctl_info *mci)
|
|
|
* bit 0 - refers to the lower 32-byte half cacheline
|
|
|
* bit 1 - refers to the upper 32-byte half cacheline
|
|
|
*/
|
|
|
-static ssize_t i7core_inject_section_store(struct mem_ctl_info *mci,
|
|
|
+static ssize_t i7core_inject_section_store(struct device *dev,
|
|
|
+ struct device_attribute *mattr,
|
|
|
const char *data, size_t count)
|
|
|
{
|
|
|
+ struct mem_ctl_info *mci = to_mci(dev);
|
|
|
struct i7core_pvt *pvt = mci->pvt_info;
|
|
|
unsigned long value;
|
|
|
int rc;
|
|
@@ -709,9 +715,11 @@ static ssize_t i7core_inject_section_store(struct mem_ctl_info *mci,
|
|
|
return count;
|
|
|
}
|
|
|
|
|
|
-static ssize_t i7core_inject_section_show(struct mem_ctl_info *mci,
|
|
|
- char *data)
|
|
|
+static ssize_t i7core_inject_section_show(struct device *dev,
|
|
|
+ struct device_attribute *mattr,
|
|
|
+ char *data)
|
|
|
{
|
|
|
+ struct mem_ctl_info *mci = to_mci(dev);
|
|
|
struct i7core_pvt *pvt = mci->pvt_info;
|
|
|
return sprintf(data, "0x%08x\n", pvt->inject.section);
|
|
|
}
|
|
@@ -724,10 +732,12 @@ static ssize_t i7core_inject_section_show(struct mem_ctl_info *mci,
|
|
|
* bit 1 - inject ECC error
|
|
|
* bit 2 - inject parity error
|
|
|
*/
|
|
|
-static ssize_t i7core_inject_type_store(struct mem_ctl_info *mci,
|
|
|
+static ssize_t i7core_inject_type_store(struct device *dev,
|
|
|
+ struct device_attribute *mattr,
|
|
|
const char *data, size_t count)
|
|
|
{
|
|
|
- struct i7core_pvt *pvt = mci->pvt_info;
|
|
|
+ struct mem_ctl_info *mci = to_mci(dev);
|
|
|
+struct i7core_pvt *pvt = mci->pvt_info;
|
|
|
unsigned long value;
|
|
|
int rc;
|
|
|
|
|
@@ -742,10 +752,13 @@ static ssize_t i7core_inject_type_store(struct mem_ctl_info *mci,
|
|
|
return count;
|
|
|
}
|
|
|
|
|
|
-static ssize_t i7core_inject_type_show(struct mem_ctl_info *mci,
|
|
|
- char *data)
|
|
|
+static ssize_t i7core_inject_type_show(struct device *dev,
|
|
|
+ struct device_attribute *mattr,
|
|
|
+ char *data)
|
|
|
{
|
|
|
+ struct mem_ctl_info *mci = to_mci(dev);
|
|
|
struct i7core_pvt *pvt = mci->pvt_info;
|
|
|
+
|
|
|
return sprintf(data, "0x%08x\n", pvt->inject.type);
|
|
|
}
|
|
|
|
|
@@ -759,9 +772,11 @@ static ssize_t i7core_inject_type_show(struct mem_ctl_info *mci,
|
|
|
* 23:16 and 31:24). Flipping bits in two symbol pairs will cause an
|
|
|
* uncorrectable error to be injected.
|
|
|
*/
|
|
|
-static ssize_t i7core_inject_eccmask_store(struct mem_ctl_info *mci,
|
|
|
- const char *data, size_t count)
|
|
|
+static ssize_t i7core_inject_eccmask_store(struct device *dev,
|
|
|
+ struct device_attribute *mattr,
|
|
|
+ const char *data, size_t count)
|
|
|
{
|
|
|
+ struct mem_ctl_info *mci = to_mci(dev);
|
|
|
struct i7core_pvt *pvt = mci->pvt_info;
|
|
|
unsigned long value;
|
|
|
int rc;
|
|
@@ -777,10 +792,13 @@ static ssize_t i7core_inject_eccmask_store(struct mem_ctl_info *mci,
|
|
|
return count;
|
|
|
}
|
|
|
|
|
|
-static ssize_t i7core_inject_eccmask_show(struct mem_ctl_info *mci,
|
|
|
- char *data)
|
|
|
+static ssize_t i7core_inject_eccmask_show(struct device *dev,
|
|
|
+ struct device_attribute *mattr,
|
|
|
+ char *data)
|
|
|
{
|
|
|
+ struct mem_ctl_info *mci = to_mci(dev);
|
|
|
struct i7core_pvt *pvt = mci->pvt_info;
|
|
|
+
|
|
|
return sprintf(data, "0x%08x\n", pvt->inject.eccmask);
|
|
|
}
|
|
|
|
|
@@ -797,9 +815,11 @@ static ssize_t i7core_inject_eccmask_show(struct mem_ctl_info *mci,
|
|
|
|
|
|
#define DECLARE_ADDR_MATCH(param, limit) \
|
|
|
static ssize_t i7core_inject_store_##param( \
|
|
|
- struct mem_ctl_info *mci, \
|
|
|
- const char *data, size_t count) \
|
|
|
+ struct device *dev, \
|
|
|
+ struct device_attribute *mattr, \
|
|
|
+ const char *data, size_t count) \
|
|
|
{ \
|
|
|
+ struct mem_ctl_info *mci = to_mci(dev); \
|
|
|
struct i7core_pvt *pvt; \
|
|
|
long value; \
|
|
|
int rc; \
|
|
@@ -824,9 +844,11 @@ static ssize_t i7core_inject_store_##param( \
|
|
|
} \
|
|
|
\
|
|
|
static ssize_t i7core_inject_show_##param( \
|
|
|
- struct mem_ctl_info *mci, \
|
|
|
- char *data) \
|
|
|
+ struct device *dev, \
|
|
|
+ struct device_attribute *mattr, \
|
|
|
+ char *data) \
|
|
|
{ \
|
|
|
+ struct mem_ctl_info *mci = to_mci(dev); \
|
|
|
struct i7core_pvt *pvt; \
|
|
|
\
|
|
|
pvt = mci->pvt_info; \
|
|
@@ -838,14 +860,9 @@ static ssize_t i7core_inject_show_##param( \
|
|
|
}
|
|
|
|
|
|
#define ATTR_ADDR_MATCH(param) \
|
|
|
- { \
|
|
|
- .attr = { \
|
|
|
- .name = #param, \
|
|
|
- .mode = (S_IRUGO | S_IWUSR) \
|
|
|
- }, \
|
|
|
- .show = i7core_inject_show_##param, \
|
|
|
- .store = i7core_inject_store_##param, \
|
|
|
- }
|
|
|
+ static DEVICE_ATTR(param, S_IRUGO | S_IWUSR, \
|
|
|
+ i7core_inject_show_##param, \
|
|
|
+ i7core_inject_store_##param)
|
|
|
|
|
|
DECLARE_ADDR_MATCH(channel, 3);
|
|
|
DECLARE_ADDR_MATCH(dimm, 3);
|
|
@@ -854,6 +871,13 @@ DECLARE_ADDR_MATCH(bank, 32);
|
|
|
DECLARE_ADDR_MATCH(page, 0x10000);
|
|
|
DECLARE_ADDR_MATCH(col, 0x4000);
|
|
|
|
|
|
+ATTR_ADDR_MATCH(channel);
|
|
|
+ATTR_ADDR_MATCH(dimm);
|
|
|
+ATTR_ADDR_MATCH(rank);
|
|
|
+ATTR_ADDR_MATCH(bank);
|
|
|
+ATTR_ADDR_MATCH(page);
|
|
|
+ATTR_ADDR_MATCH(col);
|
|
|
+
|
|
|
static int write_and_test(struct pci_dev *dev, const int where, const u32 val)
|
|
|
{
|
|
|
u32 read;
|
|
@@ -899,9 +923,11 @@ static int write_and_test(struct pci_dev *dev, const int where, const u32 val)
|
|
|
* is reliable enough to check if the MC is using the
|
|
|
* three channels. However, this is not clear at the datasheet.
|
|
|
*/
|
|
|
-static ssize_t i7core_inject_enable_store(struct mem_ctl_info *mci,
|
|
|
- const char *data, size_t count)
|
|
|
+static ssize_t i7core_inject_enable_store(struct device *dev,
|
|
|
+ struct device_attribute *mattr,
|
|
|
+ const char *data, size_t count)
|
|
|
{
|
|
|
+ struct mem_ctl_info *mci = to_mci(dev);
|
|
|
struct i7core_pvt *pvt = mci->pvt_info;
|
|
|
u32 injectmask;
|
|
|
u64 mask = 0;
|
|
@@ -1002,9 +1028,11 @@ static ssize_t i7core_inject_enable_store(struct mem_ctl_info *mci,
|
|
|
return count;
|
|
|
}
|
|
|
|
|
|
-static ssize_t i7core_inject_enable_show(struct mem_ctl_info *mci,
|
|
|
- char *data)
|
|
|
+static ssize_t i7core_inject_enable_show(struct device *dev,
|
|
|
+ struct device_attribute *mattr,
|
|
|
+ char *data)
|
|
|
{
|
|
|
+ struct mem_ctl_info *mci = to_mci(dev);
|
|
|
struct i7core_pvt *pvt = mci->pvt_info;
|
|
|
u32 injectmask;
|
|
|
|
|
@@ -1024,12 +1052,14 @@ static ssize_t i7core_inject_enable_show(struct mem_ctl_info *mci,
|
|
|
|
|
|
#define DECLARE_COUNTER(param) \
|
|
|
static ssize_t i7core_show_counter_##param( \
|
|
|
- struct mem_ctl_info *mci, \
|
|
|
- char *data) \
|
|
|
+ struct device *dev, \
|
|
|
+ struct device_attribute *mattr, \
|
|
|
+ char *data) \
|
|
|
{ \
|
|
|
+ struct mem_ctl_info *mci = to_mci(dev); \
|
|
|
struct i7core_pvt *pvt = mci->pvt_info; \
|
|
|
\
|
|
|
- debugf1("%s() \n", __func__); \
|
|
|
+ debugf1("%s()\n", __func__); \
|
|
|
if (!pvt->ce_count_available || (pvt->is_registered)) \
|
|
|
return sprintf(data, "data unavailable\n"); \
|
|
|
return sprintf(data, "%lu\n", \
|
|
@@ -1037,121 +1067,167 @@ static ssize_t i7core_show_counter_##param( \
|
|
|
}
|
|
|
|
|
|
#define ATTR_COUNTER(param) \
|
|
|
- { \
|
|
|
- .attr = { \
|
|
|
- .name = __stringify(udimm##param), \
|
|
|
- .mode = (S_IRUGO | S_IWUSR) \
|
|
|
- }, \
|
|
|
- .show = i7core_show_counter_##param \
|
|
|
- }
|
|
|
+ static DEVICE_ATTR(udimm##param, S_IRUGO | S_IWUSR, \
|
|
|
+ i7core_show_counter_##param, \
|
|
|
+ NULL)
|
|
|
|
|
|
DECLARE_COUNTER(0);
|
|
|
DECLARE_COUNTER(1);
|
|
|
DECLARE_COUNTER(2);
|
|
|
|
|
|
+ATTR_COUNTER(0);
|
|
|
+ATTR_COUNTER(1);
|
|
|
+ATTR_COUNTER(2);
|
|
|
+
|
|
|
/*
|
|
|
- * Sysfs struct
|
|
|
+ * inject_addrmatch device sysfs struct
|
|
|
*/
|
|
|
|
|
|
-static const struct mcidev_sysfs_attribute i7core_addrmatch_attrs[] = {
|
|
|
- ATTR_ADDR_MATCH(channel),
|
|
|
- ATTR_ADDR_MATCH(dimm),
|
|
|
- ATTR_ADDR_MATCH(rank),
|
|
|
- ATTR_ADDR_MATCH(bank),
|
|
|
- ATTR_ADDR_MATCH(page),
|
|
|
- ATTR_ADDR_MATCH(col),
|
|
|
- { } /* End of list */
|
|
|
+static struct attribute *i7core_addrmatch_attrs[] = {
|
|
|
+ &dev_attr_channel.attr,
|
|
|
+ &dev_attr_dimm.attr,
|
|
|
+ &dev_attr_rank.attr,
|
|
|
+ &dev_attr_bank.attr,
|
|
|
+ &dev_attr_page.attr,
|
|
|
+ &dev_attr_col.attr,
|
|
|
+ NULL
|
|
|
};
|
|
|
|
|
|
-static const struct mcidev_sysfs_group i7core_inject_addrmatch = {
|
|
|
- .name = "inject_addrmatch",
|
|
|
- .mcidev_attr = i7core_addrmatch_attrs,
|
|
|
+static struct attribute_group addrmatch_grp = {
|
|
|
+ .attrs = i7core_addrmatch_attrs,
|
|
|
};
|
|
|
|
|
|
-static const struct mcidev_sysfs_attribute i7core_udimm_counters_attrs[] = {
|
|
|
- ATTR_COUNTER(0),
|
|
|
- ATTR_COUNTER(1),
|
|
|
- ATTR_COUNTER(2),
|
|
|
- { .attr = { .name = NULL } }
|
|
|
+static const struct attribute_group *addrmatch_groups[] = {
|
|
|
+ &addrmatch_grp,
|
|
|
+ NULL
|
|
|
};
|
|
|
|
|
|
-static const struct mcidev_sysfs_group i7core_udimm_counters = {
|
|
|
- .name = "all_channel_counts",
|
|
|
- .mcidev_attr = i7core_udimm_counters_attrs,
|
|
|
+static void addrmatch_release(struct device *device)
|
|
|
+{
|
|
|
+ debugf1("Releasing device %s\n", dev_name(device));
|
|
|
+}
|
|
|
+
|
|
|
+static struct device_type addrmatch_type = {
|
|
|
+ .groups = addrmatch_groups,
|
|
|
+ .release = addrmatch_release,
|
|
|
};
|
|
|
|
|
|
-static const struct mcidev_sysfs_attribute i7core_sysfs_rdimm_attrs[] = {
|
|
|
- {
|
|
|
- .attr = {
|
|
|
- .name = "inject_section",
|
|
|
- .mode = (S_IRUGO | S_IWUSR)
|
|
|
- },
|
|
|
- .show = i7core_inject_section_show,
|
|
|
- .store = i7core_inject_section_store,
|
|
|
- }, {
|
|
|
- .attr = {
|
|
|
- .name = "inject_type",
|
|
|
- .mode = (S_IRUGO | S_IWUSR)
|
|
|
- },
|
|
|
- .show = i7core_inject_type_show,
|
|
|
- .store = i7core_inject_type_store,
|
|
|
- }, {
|
|
|
- .attr = {
|
|
|
- .name = "inject_eccmask",
|
|
|
- .mode = (S_IRUGO | S_IWUSR)
|
|
|
- },
|
|
|
- .show = i7core_inject_eccmask_show,
|
|
|
- .store = i7core_inject_eccmask_store,
|
|
|
- }, {
|
|
|
- .grp = &i7core_inject_addrmatch,
|
|
|
- }, {
|
|
|
- .attr = {
|
|
|
- .name = "inject_enable",
|
|
|
- .mode = (S_IRUGO | S_IWUSR)
|
|
|
- },
|
|
|
- .show = i7core_inject_enable_show,
|
|
|
- .store = i7core_inject_enable_store,
|
|
|
- },
|
|
|
- { } /* End of list */
|
|
|
+/*
|
|
|
+ * all_channel_counts sysfs struct
|
|
|
+ */
|
|
|
+
|
|
|
+static struct attribute *i7core_udimm_counters_attrs[] = {
|
|
|
+ &dev_attr_udimm0.attr,
|
|
|
+ &dev_attr_udimm1.attr,
|
|
|
+ &dev_attr_udimm2.attr,
|
|
|
+ NULL
|
|
|
+};
|
|
|
+
|
|
|
+static struct attribute_group all_channel_counts_grp = {
|
|
|
+ .attrs = i7core_udimm_counters_attrs,
|
|
|
};
|
|
|
|
|
|
-static const struct mcidev_sysfs_attribute i7core_sysfs_udimm_attrs[] = {
|
|
|
- {
|
|
|
- .attr = {
|
|
|
- .name = "inject_section",
|
|
|
- .mode = (S_IRUGO | S_IWUSR)
|
|
|
- },
|
|
|
- .show = i7core_inject_section_show,
|
|
|
- .store = i7core_inject_section_store,
|
|
|
- }, {
|
|
|
- .attr = {
|
|
|
- .name = "inject_type",
|
|
|
- .mode = (S_IRUGO | S_IWUSR)
|
|
|
- },
|
|
|
- .show = i7core_inject_type_show,
|
|
|
- .store = i7core_inject_type_store,
|
|
|
- }, {
|
|
|
- .attr = {
|
|
|
- .name = "inject_eccmask",
|
|
|
- .mode = (S_IRUGO | S_IWUSR)
|
|
|
- },
|
|
|
- .show = i7core_inject_eccmask_show,
|
|
|
- .store = i7core_inject_eccmask_store,
|
|
|
- }, {
|
|
|
- .grp = &i7core_inject_addrmatch,
|
|
|
- }, {
|
|
|
- .attr = {
|
|
|
- .name = "inject_enable",
|
|
|
- .mode = (S_IRUGO | S_IWUSR)
|
|
|
- },
|
|
|
- .show = i7core_inject_enable_show,
|
|
|
- .store = i7core_inject_enable_store,
|
|
|
- }, {
|
|
|
- .grp = &i7core_udimm_counters,
|
|
|
- },
|
|
|
- { } /* End of list */
|
|
|
+static const struct attribute_group *all_channel_counts_groups[] = {
|
|
|
+ &all_channel_counts_grp,
|
|
|
+ NULL
|
|
|
};
|
|
|
|
|
|
+static void all_channel_counts_release(struct device *device)
|
|
|
+{
|
|
|
+ debugf1("Releasing device %s\n", dev_name(device));
|
|
|
+}
|
|
|
+
|
|
|
+static struct device_type all_channel_counts_type = {
|
|
|
+ .groups = all_channel_counts_groups,
|
|
|
+ .release = all_channel_counts_release,
|
|
|
+};
|
|
|
+
|
|
|
+/*
|
|
|
+ * inject sysfs attributes
|
|
|
+ */
|
|
|
+
|
|
|
+static DEVICE_ATTR(inject_section, S_IRUGO | S_IWUSR,
|
|
|
+ i7core_inject_section_show, i7core_inject_section_store);
|
|
|
+
|
|
|
+static DEVICE_ATTR(inject_type, S_IRUGO | S_IWUSR,
|
|
|
+ i7core_inject_type_show, i7core_inject_type_store);
|
|
|
+
|
|
|
+
|
|
|
+static DEVICE_ATTR(inject_eccmask, S_IRUGO | S_IWUSR,
|
|
|
+ i7core_inject_eccmask_show, i7core_inject_eccmask_store);
|
|
|
+
|
|
|
+static DEVICE_ATTR(inject_enable, S_IRUGO | S_IWUSR,
|
|
|
+ i7core_inject_enable_show, i7core_inject_enable_store);
|
|
|
+
|
|
|
+static int i7core_create_sysfs_devices(struct mem_ctl_info *mci)
|
|
|
+{
|
|
|
+ struct i7core_pvt *pvt = mci->pvt_info;
|
|
|
+ int rc;
|
|
|
+
|
|
|
+ rc = device_create_file(&mci->dev, &dev_attr_inject_section);
|
|
|
+ if (rc < 0)
|
|
|
+ return rc;
|
|
|
+ rc = device_create_file(&mci->dev, &dev_attr_inject_type);
|
|
|
+ if (rc < 0)
|
|
|
+ return rc;
|
|
|
+ rc = device_create_file(&mci->dev, &dev_attr_inject_eccmask);
|
|
|
+ if (rc < 0)
|
|
|
+ return rc;
|
|
|
+ rc = device_create_file(&mci->dev, &dev_attr_inject_enable);
|
|
|
+ if (rc < 0)
|
|
|
+ return rc;
|
|
|
+
|
|
|
+ pvt->addrmatch_dev.type = &addrmatch_type;
|
|
|
+ pvt->addrmatch_dev.bus = mci->dev.bus;
|
|
|
+ device_initialize(&pvt->addrmatch_dev);
|
|
|
+ pvt->addrmatch_dev.parent = &mci->dev;
|
|
|
+ dev_set_name(&pvt->addrmatch_dev, "inject_addrmatch");
|
|
|
+ dev_set_drvdata(&pvt->addrmatch_dev, mci);
|
|
|
+
|
|
|
+ debugf1("%s(): creating %s\n", __func__,
|
|
|
+ dev_name(&pvt->addrmatch_dev));
|
|
|
+
|
|
|
+ rc = device_add(&pvt->addrmatch_dev);
|
|
|
+ if (rc < 0)
|
|
|
+ return rc;
|
|
|
+
|
|
|
+ if (!pvt->is_registered) {
|
|
|
+ pvt->chancounts_dev.type = &all_channel_counts_type;
|
|
|
+ pvt->chancounts_dev.bus = mci->dev.bus;
|
|
|
+ device_initialize(&pvt->chancounts_dev);
|
|
|
+ pvt->chancounts_dev.parent = &mci->dev;
|
|
|
+ dev_set_name(&pvt->chancounts_dev, "all_channel_counts");
|
|
|
+ dev_set_drvdata(&pvt->chancounts_dev, mci);
|
|
|
+
|
|
|
+ debugf1("%s(): creating %s\n", __func__,
|
|
|
+ dev_name(&pvt->chancounts_dev));
|
|
|
+
|
|
|
+ rc = device_add(&pvt->chancounts_dev);
|
|
|
+ if (rc < 0)
|
|
|
+ return rc;
|
|
|
+ }
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static void i7core_delete_sysfs_devices(struct mem_ctl_info *mci)
|
|
|
+{
|
|
|
+ struct i7core_pvt *pvt = mci->pvt_info;
|
|
|
+
|
|
|
+ debugf1("\n");
|
|
|
+
|
|
|
+ device_remove_file(&mci->dev, &dev_attr_inject_section);
|
|
|
+ device_remove_file(&mci->dev, &dev_attr_inject_type);
|
|
|
+ device_remove_file(&mci->dev, &dev_attr_inject_eccmask);
|
|
|
+ device_remove_file(&mci->dev, &dev_attr_inject_enable);
|
|
|
+
|
|
|
+ if (!pvt->is_registered) {
|
|
|
+ put_device(&pvt->chancounts_dev);
|
|
|
+ device_del(&pvt->chancounts_dev);
|
|
|
+ }
|
|
|
+ put_device(&pvt->addrmatch_dev);
|
|
|
+ device_del(&pvt->addrmatch_dev);
|
|
|
+}
|
|
|
+
|
|
|
/****************************************************************************
|
|
|
Device initialization routines: put/get, init/exit
|
|
|
****************************************************************************/
|
|
@@ -2122,6 +2198,7 @@ static void i7core_unregister_mci(struct i7core_dev *i7core_dev)
|
|
|
i7core_pci_ctl_release(pvt);
|
|
|
|
|
|
/* Remove MC sysfs nodes */
|
|
|
+ i7core_delete_sysfs_devices(mci);
|
|
|
edac_mc_del_mc(mci->pdev);
|
|
|
|
|
|
debugf1("%s: free mci struct\n", mci->ctl_name);
|
|
@@ -2180,10 +2257,6 @@ static int i7core_register_mci(struct i7core_dev *i7core_dev)
|
|
|
if (unlikely(rc < 0))
|
|
|
goto fail0;
|
|
|
|
|
|
- if (pvt->is_registered)
|
|
|
- mci->mc_driver_sysfs_attributes = i7core_sysfs_rdimm_attrs;
|
|
|
- else
|
|
|
- mci->mc_driver_sysfs_attributes = i7core_sysfs_udimm_attrs;
|
|
|
|
|
|
/* Get dimm basic config */
|
|
|
get_dimm_config(mci);
|
|
@@ -2207,6 +2280,13 @@ static int i7core_register_mci(struct i7core_dev *i7core_dev)
|
|
|
rc = -EINVAL;
|
|
|
goto fail0;
|
|
|
}
|
|
|
+ if (i7core_create_sysfs_devices(mci)) {
|
|
|
+ debugf0("MC: " __FILE__
|
|
|
+ ": %s(): failed to create sysfs nodes\n", __func__);
|
|
|
+ edac_mc_del_mc(mci->pdev);
|
|
|
+ rc = -EINVAL;
|
|
|
+ goto fail0;
|
|
|
+ }
|
|
|
|
|
|
/* Default error mask is any memory */
|
|
|
pvt->inject.channel = 0;
|