Commit 1a370f4c authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag 'edac_for_4.1' of git://git.kernel.org/pub/scm/linux/kernel/git/bp/bp

Pull EDAC updates from Borislav Petkov:

 - convert a bunch of drivers to static attribute groups (Takashi Iwai)

 - misc cleanups

* tag 'edac_for_4.1' of git://git.kernel.org/pub/scm/linux/kernel/git/bp/bp:
  EDAC: Constify of_device_id array
  EDAC, i82443bxgx: Don't export static symbol
  EDAC, amd64_edac: Get rid of per-node driver instances
  EDAC: Properly unwind on failure path in edac_init()
  EDAC: highbank: Use static attribute groups for sysfs entries
  EDAC: octeon: Use static attribute groups for sysfs entries
  EDAC: mpc85xx: Use static attribute groups for sysfs entries
  EDAC: i7core: Use static attribute groups for sysfs entries
  EDAC: i7core: Return proper error codes for kzalloc() errors
  EDAC: amd64: Use static attribute groups
  EDAC: Allow to pass driver-specific attribute groups
  EDAC: Use static attribute groups for managing sysfs entries
  EDAC: Delete unnecessary checks before pci_dev_put()
parents 4b5ca741 1afaa055
......@@ -20,8 +20,7 @@ static struct msr __percpu *msrs;
*/
static atomic_t drv_instances = ATOMIC_INIT(0);
/* Per-node driver instances */
static struct mem_ctl_info **mcis;
/* Per-node stuff */
static struct ecc_settings **ecc_stngs;
/*
......@@ -903,9 +902,17 @@ static int k8_early_channel_count(struct amd64_pvt *pvt)
/* On F10h and later ErrAddr is MC4_ADDR[47:1] */
static u64 get_error_address(struct amd64_pvt *pvt, struct mce *m)
{
u64 addr;
u16 mce_nid = amd_get_nb_id(m->extcpu);
struct mem_ctl_info *mci;
u8 start_bit = 1;
u8 end_bit = 47;
u64 addr;
mci = edac_mc_find(mce_nid);
if (!mci)
return 0;
pvt = mci->pvt_info;
if (pvt->fam == 0xf) {
start_bit = 3;
......@@ -918,17 +925,13 @@ static u64 get_error_address(struct amd64_pvt *pvt, struct mce *m)
* Erratum 637 workaround
*/
if (pvt->fam == 0x15) {
struct amd64_pvt *pvt;
u64 cc6_base, tmp_addr;
u32 tmp;
u16 mce_nid;
u8 intlv_en;
if ((addr & GENMASK_ULL(47, 24)) >> 24 != 0x00fdf7)
return addr;
mce_nid = amd_get_nb_id(m->extcpu);
pvt = mcis[mce_nid]->pvt_info;
amd64_read_pci_cfg(pvt->F1, DRAM_LOCAL_NODE_LIM, &tmp);
intlv_en = tmp >> 21 & 0x7;
......@@ -1511,7 +1514,7 @@ static int f1x_lookup_addr_in_dct(u64 in_addr, u8 nid, u8 dct)
int cs_found = -EINVAL;
int csrow;
mci = mcis[nid];
mci = edac_mc_find(nid);
if (!mci)
return cs_found;
......@@ -2663,34 +2666,6 @@ static bool ecc_enabled(struct pci_dev *F3, u16 nid)
return true;
}
static int set_mc_sysfs_attrs(struct mem_ctl_info *mci)
{
struct amd64_pvt *pvt = mci->pvt_info;
int rc;
rc = amd64_create_sysfs_dbg_files(mci);
if (rc < 0)
return rc;
if (pvt->fam >= 0x10) {
rc = amd64_create_sysfs_inject_files(mci);
if (rc < 0)
return rc;
}
return 0;
}
static void del_mc_sysfs_attrs(struct mem_ctl_info *mci)
{
struct amd64_pvt *pvt = mci->pvt_info;
amd64_remove_sysfs_dbg_files(mci);
if (pvt->fam >= 0x10)
amd64_remove_sysfs_inject_files(mci);
}
static void setup_mci_misc_attrs(struct mem_ctl_info *mci,
struct amd64_family_type *fam)
{
......@@ -2778,6 +2753,16 @@ static struct amd64_family_type *per_family_init(struct amd64_pvt *pvt)
return fam_type;
}
static const struct attribute_group *amd64_edac_attr_groups[] = {
#ifdef CONFIG_EDAC_DEBUG
&amd64_edac_dbg_group,
#endif
#ifdef CONFIG_EDAC_AMD64_ERROR_INJECTION
&amd64_edac_inj_group,
#endif
NULL
};
static int init_one_instance(struct pci_dev *F2)
{
struct amd64_pvt *pvt = NULL;
......@@ -2844,14 +2829,10 @@ static int init_one_instance(struct pci_dev *F2)
mci->edac_cap = EDAC_FLAG_NONE;
ret = -ENODEV;
if (edac_mc_add_mc(mci)) {
if (edac_mc_add_mc_with_groups(mci, amd64_edac_attr_groups)) {
edac_dbg(1, "failed edac_mc_add_mc()\n");
goto err_add_mc;
}
if (set_mc_sysfs_attrs(mci)) {
edac_dbg(1, "failed edac_mc_add_mc()\n");
goto err_add_sysfs;
}
/* register stuff with EDAC MCE */
if (report_gart_errors)
......@@ -2859,14 +2840,10 @@ static int init_one_instance(struct pci_dev *F2)
amd_register_ecc_decoder(decode_bus_error);
mcis[nid] = mci;
atomic_inc(&drv_instances);
return 0;
err_add_sysfs:
edac_mc_del_mc(mci->pdev);
err_add_mc:
edac_mc_free(mci);
......@@ -2940,7 +2917,6 @@ static void remove_one_instance(struct pci_dev *pdev)
mci = find_mci_by_dev(&pdev->dev);
WARN_ON(!mci);
del_mc_sysfs_attrs(mci);
/* Remove from EDAC CORE tracking list */
mci = edac_mc_del_mc(&pdev->dev);
if (!mci)
......@@ -2961,7 +2937,6 @@ static void remove_one_instance(struct pci_dev *pdev)
/* Free the EDAC CORE resources */
mci->pvt_info = NULL;
mcis[nid] = NULL;
kfree(pvt);
edac_mc_free(mci);
......@@ -2999,7 +2974,7 @@ static void setup_pci_device(void)
if (pci_ctl)
return;
mci = mcis[0];
mci = edac_mc_find(0);
if (!mci)
return;
......@@ -3023,9 +2998,8 @@ static int __init amd64_edac_init(void)
goto err_ret;
err = -ENOMEM;
mcis = kzalloc(amd_nb_num() * sizeof(mcis[0]), GFP_KERNEL);
ecc_stngs = kzalloc(amd_nb_num() * sizeof(ecc_stngs[0]), GFP_KERNEL);
if (!(mcis && ecc_stngs))
if (!ecc_stngs)
goto err_free;
msrs = msrs_alloc();
......@@ -3056,9 +3030,6 @@ static int __init amd64_edac_init(void)
msrs = NULL;
err_free:
kfree(mcis);
mcis = NULL;
kfree(ecc_stngs);
ecc_stngs = NULL;
......@@ -3076,9 +3047,6 @@ static void __exit amd64_edac_exit(void)
kfree(ecc_stngs);
ecc_stngs = NULL;
kfree(mcis);
mcis = NULL;
msrs_free(msrs);
msrs = NULL;
}
......
......@@ -453,31 +453,11 @@ struct ecc_settings {
};
#ifdef CONFIG_EDAC_DEBUG
int amd64_create_sysfs_dbg_files(struct mem_ctl_info *mci);
void amd64_remove_sysfs_dbg_files(struct mem_ctl_info *mci);
#else
static inline int amd64_create_sysfs_dbg_files(struct mem_ctl_info *mci)
{
return 0;
}
static void inline amd64_remove_sysfs_dbg_files(struct mem_ctl_info *mci)
{
}
extern const struct attribute_group amd64_edac_dbg_group;
#endif
#ifdef CONFIG_EDAC_AMD64_ERROR_INJECTION
int amd64_create_sysfs_inject_files(struct mem_ctl_info *mci);
void amd64_remove_sysfs_inject_files(struct mem_ctl_info *mci);
#else
static inline int amd64_create_sysfs_inject_files(struct mem_ctl_info *mci)
{
return 0;
}
static inline void amd64_remove_sysfs_inject_files(struct mem_ctl_info *mci)
{
}
extern const struct attribute_group amd64_edac_inj_group;
#endif
/*
......
......@@ -40,34 +40,15 @@ static DEVICE_ATTR(topmem, S_IRUGO, amd64_top_mem_show, NULL);
static DEVICE_ATTR(topmem2, S_IRUGO, amd64_top_mem2_show, NULL);
static DEVICE_ATTR(dram_hole, S_IRUGO, amd64_hole_show, NULL);
int amd64_create_sysfs_dbg_files(struct mem_ctl_info *mci)
{
int rc;
rc = device_create_file(&mci->dev, &dev_attr_dhar);
if (rc < 0)
return rc;
rc = device_create_file(&mci->dev, &dev_attr_dbam);
if (rc < 0)
return rc;
rc = device_create_file(&mci->dev, &dev_attr_topmem);
if (rc < 0)
return rc;
rc = device_create_file(&mci->dev, &dev_attr_topmem2);
if (rc < 0)
return rc;
rc = device_create_file(&mci->dev, &dev_attr_dram_hole);
if (rc < 0)
return rc;
return 0;
}
void amd64_remove_sysfs_dbg_files(struct mem_ctl_info *mci)
{
device_remove_file(&mci->dev, &dev_attr_dhar);
device_remove_file(&mci->dev, &dev_attr_dbam);
device_remove_file(&mci->dev, &dev_attr_topmem);
device_remove_file(&mci->dev, &dev_attr_topmem2);
device_remove_file(&mci->dev, &dev_attr_dram_hole);
}
static struct attribute *amd64_edac_dbg_attrs[] = {
&dev_attr_dhar.attr,
&dev_attr_dbam.attr,
&dev_attr_topmem.attr,
&dev_attr_topmem2.attr,
&dev_attr_dram_hole.attr,
NULL
};
const struct attribute_group amd64_edac_dbg_group = {
.attrs = amd64_edac_dbg_attrs,
};
......@@ -207,35 +207,28 @@ static DEVICE_ATTR(inject_write, S_IWUSR,
static DEVICE_ATTR(inject_read, S_IWUSR,
NULL, amd64_inject_read_store);
int amd64_create_sysfs_inject_files(struct mem_ctl_info *mci)
static struct attribute *amd64_edac_inj_attrs[] = {
&dev_attr_inject_section.attr,
&dev_attr_inject_word.attr,
&dev_attr_inject_ecc_vector.attr,
&dev_attr_inject_write.attr,
&dev_attr_inject_read.attr,
NULL
};
static umode_t amd64_edac_inj_is_visible(struct kobject *kobj,
struct attribute *attr, int idx)
{
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_word);
if (rc < 0)
return rc;
rc = device_create_file(&mci->dev, &dev_attr_inject_ecc_vector);
if (rc < 0)
return rc;
rc = device_create_file(&mci->dev, &dev_attr_inject_write);
if (rc < 0)
return rc;
rc = device_create_file(&mci->dev, &dev_attr_inject_read);
if (rc < 0)
return rc;
return 0;
}
struct device *dev = kobj_to_dev(kobj);
struct mem_ctl_info *mci = container_of(dev, struct mem_ctl_info, dev);
struct amd64_pvt *pvt = mci->pvt_info;
void amd64_remove_sysfs_inject_files(struct mem_ctl_info *mci)
{
device_remove_file(&mci->dev, &dev_attr_inject_section);
device_remove_file(&mci->dev, &dev_attr_inject_word);
device_remove_file(&mci->dev, &dev_attr_inject_ecc_vector);
device_remove_file(&mci->dev, &dev_attr_inject_write);
device_remove_file(&mci->dev, &dev_attr_inject_read);
if (pvt->fam < 0x10)
return 0;
return attr->mode;
}
const struct attribute_group amd64_edac_inj_group = {
.attrs = amd64_edac_inj_attrs,
.is_visible = amd64_edac_inj_is_visible,
};
......@@ -446,7 +446,9 @@ struct mem_ctl_info *edac_mc_alloc(unsigned mc_num,
unsigned n_layers,
struct edac_mc_layer *layers,
unsigned sz_pvt);
extern int edac_mc_add_mc(struct mem_ctl_info *mci);
extern int edac_mc_add_mc_with_groups(struct mem_ctl_info *mci,
const struct attribute_group **groups);
#define edac_mc_add_mc(mci) edac_mc_add_mc_with_groups(mci, NULL)
extern void edac_mc_free(struct mem_ctl_info *mci);
extern struct mem_ctl_info *edac_mc_find(int idx);
extern struct mem_ctl_info *find_mci_by_dev(struct device *dev);
......
......@@ -710,9 +710,10 @@ struct mem_ctl_info *edac_mc_find(int idx)
EXPORT_SYMBOL(edac_mc_find);
/**
* edac_mc_add_mc: Insert the 'mci' structure into the mci global list and
* create sysfs entries associated with mci structure
* edac_mc_add_mc_with_groups: Insert the 'mci' structure into the mci
* global list and create sysfs entries associated with mci structure
* @mci: pointer to the mci structure to be added to the list
* @groups: optional attribute groups for the driver-specific sysfs entries
*
* Return:
* 0 Success
......@@ -720,7 +721,8 @@ EXPORT_SYMBOL(edac_mc_find);
*/
/* FIXME - should a warning be printed if no error detection? correction? */
int edac_mc_add_mc(struct mem_ctl_info *mci)
int edac_mc_add_mc_with_groups(struct mem_ctl_info *mci,
const struct attribute_group **groups)
{
int ret = -EINVAL;
edac_dbg(0, "\n");
......@@ -771,7 +773,7 @@ int edac_mc_add_mc(struct mem_ctl_info *mci)
mci->bus = &mc_bus[mci->mc_idx];
if (edac_create_sysfs_mci_device(mci)) {
if (edac_create_sysfs_mci_device(mci, groups)) {
edac_mc_printk(mci, KERN_WARNING,
"failed to create sysfs device\n");
goto fail1;
......@@ -805,7 +807,7 @@ int edac_mc_add_mc(struct mem_ctl_info *mci)
mutex_unlock(&mem_ctls_mutex);
return ret;
}
EXPORT_SYMBOL_GPL(edac_mc_add_mc);
EXPORT_SYMBOL_GPL(edac_mc_add_mc_with_groups);
/**
* edac_mc_del_mc: Remove sysfs entries for specified mci structure and
......
......@@ -323,13 +323,14 @@ DEVICE_CHANNEL(ch5_dimm_label, S_IRUGO | S_IWUSR,
channel_dimm_label_show, channel_dimm_label_store, 5);
/* 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,
NULL
};
/* possible dynamic channel ce_count attribute files */
......@@ -347,13 +348,45 @@ DEVICE_CHANNEL(ch5_ce_count, S_IRUGO,
channel_ce_count_show, NULL, 5);
/* 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,
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;
/* 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)
......@@ -370,13 +403,12 @@ 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.groups = csrow_dev_groups;
device_initialize(&csrow->dev);
csrow->dev.parent = &mci->dev;
csrow->mci = mci;
......@@ -386,45 +418,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++) {
......@@ -446,14 +446,6 @@ static int edac_create_csrow_objects(struct mem_ctl_info *mci)
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);
}
......@@ -462,23 +454,13 @@ static int edac_create_csrow_objects(struct mem_ctl_info *mci)
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);
}
}
......@@ -863,7 +845,8 @@ 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 */
static 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,
......@@ -875,11 +858,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[] = {
......@@ -913,7 +914,7 @@ int __init edac_debugfs_init(void)
return 0;
}
void __exit edac_debugfs_exit(void)
void edac_debugfs_exit(void)
{
debugfs_remove(edac_debugfs);
}
......@@ -973,7 +974,8 @@ static int edac_create_debug_nodes(struct mem_ctl_info *mci)
* 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)
{
int i, err;
......@@ -997,6 +999,7 @@ int edac_create_sysfs_mci_device(struct mem_ctl_info *mci)
mci->dev.parent = mci_pdev;