Commit 5c4cdb5a authored by Mauro Carvalho Chehab's avatar Mauro Carvalho Chehab

i7core_edac: convert it to use struct device

Instead of relying on a complex logic inside the edac core to create
a "device tree-like" sysfs struct, just use device_add.
Reviewed-by: default avatarAristeu Rozanski <arozansk@redhat.com>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@redhat.com>
parent c5608759
......@@ -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;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment