mirror of https://github.com/torvalds/linux.git
EDAC: Remove the legacy EDAC sysfs interface
Commit
1997471069 ("edac: add a new per-dimm API and make the old per-virtual-rank API obsolete")
introduced a new per-DIMM sysfs interface for EDAC making the old
per-virtual-rank sysfs interface obsolete.
Since this new sysfs interface was introduced more than a decade ago, remove
the obsolete legacy interface.
Signed-off-by: Avadhut Naik <avadhut.naik@amd.com>
Signed-off-by: Borislav Petkov (AMD) <bp@alien8.de>
Link: https://lore.kernel.org/20251106015727.1987246-1-avadhut.naik@amd.com
This commit is contained in:
parent
6a85796915
commit
8616025ae6
|
|
@ -406,24 +406,8 @@ index of the MC::
|
|||
|->mc2
|
||||
....
|
||||
|
||||
Under each ``mcX`` directory each ``csrowX`` is again represented by a
|
||||
``csrowX``, where ``X`` is the csrow index::
|
||||
|
||||
.../mc/mc0/
|
||||
|
|
||||
|->csrow0
|
||||
|->csrow2
|
||||
|->csrow3
|
||||
....
|
||||
|
||||
Notice that there is no csrow1, which indicates that csrow0 is composed
|
||||
of a single ranked DIMMs. This should also apply in both Channels, in
|
||||
order to have dual-channel mode be operational. Since both csrow2 and
|
||||
csrow3 are populated, this indicates a dual ranked set of DIMMs for
|
||||
channels 0 and 1.
|
||||
|
||||
Within each of the ``mcX`` and ``csrowX`` directories are several EDAC
|
||||
control and attribute files.
|
||||
Within each of the ``mcX`` directory are several EDAC control and
|
||||
attribute files.
|
||||
|
||||
``mcX`` directories
|
||||
-------------------
|
||||
|
|
@ -569,7 +553,7 @@ this ``X`` memory module:
|
|||
- Unbuffered-DDR
|
||||
|
||||
.. [#f5] On some systems, the memory controller doesn't have any logic
|
||||
to identify the memory module. On such systems, the directory is called ``rankX`` and works on a similar way as the ``csrowX`` directories.
|
||||
to identify the memory module. On such systems, the directory is called ``rankX``.
|
||||
On modern Intel memory controllers, the memory controller identifies the
|
||||
memory modules directly. On such systems, the directory is called ``dimmX``.
|
||||
|
||||
|
|
@ -577,126 +561,6 @@ this ``X`` memory module:
|
|||
symlinks inside the sysfs mapping that are automatically created by
|
||||
the sysfs subsystem. Currently, they serve no purpose.
|
||||
|
||||
``csrowX`` directories
|
||||
----------------------
|
||||
|
||||
When CONFIG_EDAC_LEGACY_SYSFS is enabled, sysfs will contain the ``csrowX``
|
||||
directories. As this API doesn't work properly for Rambus, FB-DIMMs and
|
||||
modern Intel Memory Controllers, this is being deprecated in favor of
|
||||
``dimmX`` directories.
|
||||
|
||||
In the ``csrowX`` directories are EDAC control and attribute files for
|
||||
this ``X`` instance of csrow:
|
||||
|
||||
|
||||
- ``ue_count`` - Total Uncorrectable Errors count attribute file
|
||||
|
||||
This attribute file displays the total count of uncorrectable
|
||||
errors that have occurred on this csrow. If panic_on_ue is set
|
||||
this counter will not have a chance to increment, since EDAC
|
||||
will panic the system.
|
||||
|
||||
|
||||
- ``ce_count`` - Total Correctable Errors count attribute file
|
||||
|
||||
This attribute file displays the total count of correctable
|
||||
errors that have occurred on this csrow. This count is very
|
||||
important to examine. CEs provide early indications that a
|
||||
DIMM is beginning to fail. This count field should be
|
||||
monitored for non-zero values and report such information
|
||||
to the system administrator.
|
||||
|
||||
|
||||
- ``size_mb`` - Total memory managed by this csrow attribute file
|
||||
|
||||
This attribute file displays, in count of megabytes, the memory
|
||||
that this csrow contains.
|
||||
|
||||
|
||||
- ``mem_type`` - Memory Type attribute file
|
||||
|
||||
This attribute file will display what type of memory is currently
|
||||
on this csrow. Normally, either buffered or unbuffered memory.
|
||||
Examples:
|
||||
|
||||
- Registered-DDR
|
||||
- Unbuffered-DDR
|
||||
|
||||
|
||||
- ``edac_mode`` - EDAC Mode of operation attribute file
|
||||
|
||||
This attribute file will display what type of Error detection
|
||||
and correction is being utilized.
|
||||
|
||||
|
||||
- ``dev_type`` - Device type attribute file
|
||||
|
||||
This attribute file will display what type of DRAM device is
|
||||
being utilized on this DIMM.
|
||||
Examples:
|
||||
|
||||
- x1
|
||||
- x2
|
||||
- x4
|
||||
- x8
|
||||
|
||||
|
||||
- ``ch0_ce_count`` - Channel 0 CE Count attribute file
|
||||
|
||||
This attribute file will display the count of CEs on this
|
||||
DIMM located in channel 0.
|
||||
|
||||
|
||||
- ``ch0_ue_count`` - Channel 0 UE Count attribute file
|
||||
|
||||
This attribute file will display the count of UEs on this
|
||||
DIMM located in channel 0.
|
||||
|
||||
|
||||
- ``ch0_dimm_label`` - Channel 0 DIMM Label control file
|
||||
|
||||
|
||||
This control file allows this DIMM to have a label assigned
|
||||
to it. With this label in the module, when errors occur
|
||||
the output can provide the DIMM label in the system log.
|
||||
This becomes vital for panic events to isolate the
|
||||
cause of the UE event.
|
||||
|
||||
DIMM Labels must be assigned after booting, with information
|
||||
that correctly identifies the physical slot with its
|
||||
silk screen label. This information is currently very
|
||||
motherboard specific and determination of this information
|
||||
must occur in userland at this time.
|
||||
|
||||
|
||||
- ``ch1_ce_count`` - Channel 1 CE Count attribute file
|
||||
|
||||
|
||||
This attribute file will display the count of CEs on this
|
||||
DIMM located in channel 1.
|
||||
|
||||
|
||||
- ``ch1_ue_count`` - Channel 1 UE Count attribute file
|
||||
|
||||
|
||||
This attribute file will display the count of UEs on this
|
||||
DIMM located in channel 0.
|
||||
|
||||
|
||||
- ``ch1_dimm_label`` - Channel 1 DIMM Label control file
|
||||
|
||||
This control file allows this DIMM to have a label assigned
|
||||
to it. With this label in the module, when errors occur
|
||||
the output can provide the DIMM label in the system log.
|
||||
This becomes vital for panic events to isolate the
|
||||
cause of the UE event.
|
||||
|
||||
DIMM Labels must be assigned after booting, with information
|
||||
that correctly identifies the physical slot with its
|
||||
silk screen label. This information is currently very
|
||||
motherboard specific and determination of this information
|
||||
must occur in userland at this time.
|
||||
|
||||
|
||||
System Logging
|
||||
--------------
|
||||
|
|
|
|||
|
|
@ -917,7 +917,6 @@ CONFIG_MMC=y
|
|||
CONFIG_MMC_LOONGSON2=m
|
||||
CONFIG_INFINIBAND=m
|
||||
CONFIG_EDAC=y
|
||||
# CONFIG_EDAC_LEGACY_SYSFS is not set
|
||||
CONFIG_EDAC_LOONGSON=y
|
||||
CONFIG_RTC_CLASS=y
|
||||
CONFIG_RTC_DRV_EFI=y
|
||||
|
|
|
|||
|
|
@ -23,14 +23,6 @@ menuconfig EDAC
|
|||
|
||||
if EDAC
|
||||
|
||||
config EDAC_LEGACY_SYSFS
|
||||
bool "EDAC legacy sysfs"
|
||||
default y
|
||||
help
|
||||
Enable the compatibility sysfs nodes.
|
||||
Use 'Y' if your edac utilities aren't ported to work with the newer
|
||||
structures.
|
||||
|
||||
config EDAC_DEBUG
|
||||
bool "Debugging"
|
||||
select DEBUG_FS
|
||||
|
|
|
|||
|
|
@ -115,401 +115,6 @@ static const char * const edac_caps[] = {
|
|||
[EDAC_S16ECD16ED] = "S16ECD16ED"
|
||||
};
|
||||
|
||||
#ifdef CONFIG_EDAC_LEGACY_SYSFS
|
||||
/*
|
||||
* EDAC sysfs CSROW data structures and methods
|
||||
*/
|
||||
|
||||
#define to_csrow(k) container_of(k, struct csrow_info, dev)
|
||||
|
||||
/*
|
||||
* We need it to avoid namespace conflicts between the legacy API
|
||||
* and the per-dimm/per-rank one
|
||||
*/
|
||||
#define DEVICE_ATTR_LEGACY(_name, _mode, _show, _store) \
|
||||
static struct device_attribute dev_attr_legacy_##_name = __ATTR(_name, _mode, _show, _store)
|
||||
|
||||
struct dev_ch_attribute {
|
||||
struct device_attribute attr;
|
||||
unsigned int channel;
|
||||
};
|
||||
|
||||
#define DEVICE_CHANNEL(_name, _mode, _show, _store, _var) \
|
||||
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)
|
||||
|
||||
/* Set of more default csrow<id> attribute show/store functions */
|
||||
static ssize_t csrow_ue_count_show(struct device *dev,
|
||||
struct device_attribute *mattr, char *data)
|
||||
{
|
||||
struct csrow_info *csrow = to_csrow(dev);
|
||||
|
||||
return sysfs_emit(data, "%u\n", csrow->ue_count);
|
||||
}
|
||||
|
||||
static ssize_t csrow_ce_count_show(struct device *dev,
|
||||
struct device_attribute *mattr, char *data)
|
||||
{
|
||||
struct csrow_info *csrow = to_csrow(dev);
|
||||
|
||||
return sysfs_emit(data, "%u\n", csrow->ce_count);
|
||||
}
|
||||
|
||||
static ssize_t csrow_size_show(struct device *dev,
|
||||
struct device_attribute *mattr, char *data)
|
||||
{
|
||||
struct csrow_info *csrow = to_csrow(dev);
|
||||
int i;
|
||||
u32 nr_pages = 0;
|
||||
|
||||
for (i = 0; i < csrow->nr_channels; i++)
|
||||
nr_pages += csrow->channels[i]->dimm->nr_pages;
|
||||
return sysfs_emit(data, "%u\n", PAGES_TO_MiB(nr_pages));
|
||||
}
|
||||
|
||||
static ssize_t csrow_mem_type_show(struct device *dev,
|
||||
struct device_attribute *mattr, char *data)
|
||||
{
|
||||
struct csrow_info *csrow = to_csrow(dev);
|
||||
|
||||
return sysfs_emit(data, "%s\n", edac_mem_types[csrow->channels[0]->dimm->mtype]);
|
||||
}
|
||||
|
||||
static ssize_t csrow_dev_type_show(struct device *dev,
|
||||
struct device_attribute *mattr, char *data)
|
||||
{
|
||||
struct csrow_info *csrow = to_csrow(dev);
|
||||
|
||||
return sysfs_emit(data, "%s\n", dev_types[csrow->channels[0]->dimm->dtype]);
|
||||
}
|
||||
|
||||
static ssize_t csrow_edac_mode_show(struct device *dev,
|
||||
struct device_attribute *mattr,
|
||||
char *data)
|
||||
{
|
||||
struct csrow_info *csrow = to_csrow(dev);
|
||||
|
||||
return sysfs_emit(data, "%s\n", edac_caps[csrow->channels[0]->dimm->edac_mode]);
|
||||
}
|
||||
|
||||
/* show/store functions for DIMM Label attributes */
|
||||
static ssize_t channel_dimm_label_show(struct device *dev,
|
||||
struct device_attribute *mattr,
|
||||
char *data)
|
||||
{
|
||||
struct csrow_info *csrow = to_csrow(dev);
|
||||
unsigned int chan = to_channel(mattr);
|
||||
struct rank_info *rank = csrow->channels[chan];
|
||||
|
||||
/* if field has not been initialized, there is nothing to send */
|
||||
if (!rank->dimm->label[0])
|
||||
return 0;
|
||||
|
||||
return sysfs_emit(data, "%s\n", rank->dimm->label);
|
||||
}
|
||||
|
||||
static ssize_t channel_dimm_label_store(struct device *dev,
|
||||
struct device_attribute *mattr,
|
||||
const char *data, size_t count)
|
||||
{
|
||||
struct csrow_info *csrow = to_csrow(dev);
|
||||
unsigned int chan = to_channel(mattr);
|
||||
struct rank_info *rank = csrow->channels[chan];
|
||||
size_t copy_count = count;
|
||||
|
||||
if (count == 0)
|
||||
return -EINVAL;
|
||||
|
||||
if (data[count - 1] == '\0' || data[count - 1] == '\n')
|
||||
copy_count -= 1;
|
||||
|
||||
if (copy_count == 0 || copy_count >= sizeof(rank->dimm->label))
|
||||
return -EINVAL;
|
||||
|
||||
memcpy(rank->dimm->label, data, copy_count);
|
||||
rank->dimm->label[copy_count] = '\0';
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
/* show function for dynamic chX_ce_count attribute */
|
||||
static ssize_t channel_ce_count_show(struct device *dev,
|
||||
struct device_attribute *mattr, char *data)
|
||||
{
|
||||
struct csrow_info *csrow = to_csrow(dev);
|
||||
unsigned int chan = to_channel(mattr);
|
||||
struct rank_info *rank = csrow->channels[chan];
|
||||
|
||||
return sysfs_emit(data, "%u\n", rank->ce_count);
|
||||
}
|
||||
|
||||
/* cwrow<id>/attribute files */
|
||||
DEVICE_ATTR_LEGACY(size_mb, S_IRUGO, csrow_size_show, NULL);
|
||||
DEVICE_ATTR_LEGACY(dev_type, S_IRUGO, csrow_dev_type_show, NULL);
|
||||
DEVICE_ATTR_LEGACY(mem_type, S_IRUGO, csrow_mem_type_show, NULL);
|
||||
DEVICE_ATTR_LEGACY(edac_mode, S_IRUGO, csrow_edac_mode_show, NULL);
|
||||
DEVICE_ATTR_LEGACY(ue_count, S_IRUGO, csrow_ue_count_show, NULL);
|
||||
DEVICE_ATTR_LEGACY(ce_count, S_IRUGO, csrow_ce_count_show, NULL);
|
||||
|
||||
/* default attributes of the CSROW<id> object */
|
||||
static struct attribute *csrow_attrs[] = {
|
||||
&dev_attr_legacy_dev_type.attr,
|
||||
&dev_attr_legacy_mem_type.attr,
|
||||
&dev_attr_legacy_edac_mode.attr,
|
||||
&dev_attr_legacy_size_mb.attr,
|
||||
&dev_attr_legacy_ue_count.attr,
|
||||
&dev_attr_legacy_ce_count.attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static const struct attribute_group csrow_attr_grp = {
|
||||
.attrs = csrow_attrs,
|
||||
};
|
||||
|
||||
static const struct attribute_group *csrow_attr_groups[] = {
|
||||
&csrow_attr_grp,
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct device_type csrow_attr_type = {
|
||||
.groups = csrow_attr_groups,
|
||||
};
|
||||
|
||||
/*
|
||||
* possible dynamic channel DIMM Label attribute files
|
||||
*
|
||||
*/
|
||||
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,
|
||||
channel_dimm_label_show, channel_dimm_label_store, 1);
|
||||
DEVICE_CHANNEL(ch2_dimm_label, S_IRUGO | S_IWUSR,
|
||||
channel_dimm_label_show, channel_dimm_label_store, 2);
|
||||
DEVICE_CHANNEL(ch3_dimm_label, S_IRUGO | S_IWUSR,
|
||||
channel_dimm_label_show, channel_dimm_label_store, 3);
|
||||
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);
|
||||
DEVICE_CHANNEL(ch8_dimm_label, S_IRUGO | S_IWUSR,
|
||||
channel_dimm_label_show, channel_dimm_label_store, 8);
|
||||
DEVICE_CHANNEL(ch9_dimm_label, S_IRUGO | S_IWUSR,
|
||||
channel_dimm_label_show, channel_dimm_label_store, 9);
|
||||
DEVICE_CHANNEL(ch10_dimm_label, S_IRUGO | S_IWUSR,
|
||||
channel_dimm_label_show, channel_dimm_label_store, 10);
|
||||
DEVICE_CHANNEL(ch11_dimm_label, S_IRUGO | S_IWUSR,
|
||||
channel_dimm_label_show, channel_dimm_label_store, 11);
|
||||
DEVICE_CHANNEL(ch12_dimm_label, S_IRUGO | S_IWUSR,
|
||||
channel_dimm_label_show, channel_dimm_label_store, 12);
|
||||
DEVICE_CHANNEL(ch13_dimm_label, S_IRUGO | S_IWUSR,
|
||||
channel_dimm_label_show, channel_dimm_label_store, 13);
|
||||
DEVICE_CHANNEL(ch14_dimm_label, S_IRUGO | S_IWUSR,
|
||||
channel_dimm_label_show, channel_dimm_label_store, 14);
|
||||
DEVICE_CHANNEL(ch15_dimm_label, S_IRUGO | S_IWUSR,
|
||||
channel_dimm_label_show, channel_dimm_label_store, 15);
|
||||
|
||||
/* Total possible dynamic DIMM Label attribute file table */
|
||||
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,
|
||||
&dev_attr_legacy_ch8_dimm_label.attr.attr,
|
||||
&dev_attr_legacy_ch9_dimm_label.attr.attr,
|
||||
&dev_attr_legacy_ch10_dimm_label.attr.attr,
|
||||
&dev_attr_legacy_ch11_dimm_label.attr.attr,
|
||||
&dev_attr_legacy_ch12_dimm_label.attr.attr,
|
||||
&dev_attr_legacy_ch13_dimm_label.attr.attr,
|
||||
&dev_attr_legacy_ch14_dimm_label.attr.attr,
|
||||
&dev_attr_legacy_ch15_dimm_label.attr.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
/* possible dynamic channel ce_count attribute files */
|
||||
DEVICE_CHANNEL(ch0_ce_count, S_IRUGO,
|
||||
channel_ce_count_show, NULL, 0);
|
||||
DEVICE_CHANNEL(ch1_ce_count, S_IRUGO,
|
||||
channel_ce_count_show, NULL, 1);
|
||||
DEVICE_CHANNEL(ch2_ce_count, S_IRUGO,
|
||||
channel_ce_count_show, NULL, 2);
|
||||
DEVICE_CHANNEL(ch3_ce_count, S_IRUGO,
|
||||
channel_ce_count_show, NULL, 3);
|
||||
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);
|
||||
DEVICE_CHANNEL(ch8_ce_count, S_IRUGO,
|
||||
channel_ce_count_show, NULL, 8);
|
||||
DEVICE_CHANNEL(ch9_ce_count, S_IRUGO,
|
||||
channel_ce_count_show, NULL, 9);
|
||||
DEVICE_CHANNEL(ch10_ce_count, S_IRUGO,
|
||||
channel_ce_count_show, NULL, 10);
|
||||
DEVICE_CHANNEL(ch11_ce_count, S_IRUGO,
|
||||
channel_ce_count_show, NULL, 11);
|
||||
DEVICE_CHANNEL(ch12_ce_count, S_IRUGO,
|
||||
channel_ce_count_show, NULL, 12);
|
||||
DEVICE_CHANNEL(ch13_ce_count, S_IRUGO,
|
||||
channel_ce_count_show, NULL, 13);
|
||||
DEVICE_CHANNEL(ch14_ce_count, S_IRUGO,
|
||||
channel_ce_count_show, NULL, 14);
|
||||
DEVICE_CHANNEL(ch15_ce_count, S_IRUGO,
|
||||
channel_ce_count_show, NULL, 15);
|
||||
|
||||
/* Total possible dynamic ce_count attribute file table */
|
||||
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,
|
||||
&dev_attr_legacy_ch8_ce_count.attr.attr,
|
||||
&dev_attr_legacy_ch9_ce_count.attr.attr,
|
||||
&dev_attr_legacy_ch10_ce_count.attr.attr,
|
||||
&dev_attr_legacy_ch11_ce_count.attr.attr,
|
||||
&dev_attr_legacy_ch12_ce_count.attr.attr,
|
||||
&dev_attr_legacy_ch13_ce_count.attr.attr,
|
||||
&dev_attr_legacy_ch14_ce_count.attr.attr,
|
||||
&dev_attr_legacy_ch15_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 void csrow_release(struct device *dev)
|
||||
{
|
||||
/*
|
||||
* Nothing to do, just unregister sysfs here. The mci
|
||||
* device owns the data and will also release it.
|
||||
*/
|
||||
}
|
||||
|
||||
static inline int nr_pages_per_csrow(struct csrow_info *csrow)
|
||||
{
|
||||
int chan, nr_pages = 0;
|
||||
|
||||
for (chan = 0; chan < csrow->nr_channels; chan++)
|
||||
nr_pages += csrow->channels[chan]->dimm->nr_pages;
|
||||
|
||||
return nr_pages;
|
||||
}
|
||||
|
||||
/* Create a CSROW object under specified edac_mc_device */
|
||||
static int edac_create_csrow_object(struct mem_ctl_info *mci,
|
||||
struct csrow_info *csrow, int index)
|
||||
{
|
||||
int err;
|
||||
|
||||
csrow->dev.type = &csrow_attr_type;
|
||||
csrow->dev.groups = csrow_dev_groups;
|
||||
csrow->dev.release = csrow_release;
|
||||
device_initialize(&csrow->dev);
|
||||
csrow->dev.parent = &mci->dev;
|
||||
csrow->mci = mci;
|
||||
dev_set_name(&csrow->dev, "csrow%d", index);
|
||||
dev_set_drvdata(&csrow->dev, csrow);
|
||||
|
||||
err = device_add(&csrow->dev);
|
||||
if (err) {
|
||||
edac_dbg(1, "failure: create device %s\n", dev_name(&csrow->dev));
|
||||
put_device(&csrow->dev);
|
||||
return err;
|
||||
}
|
||||
|
||||
edac_dbg(0, "device %s created\n", dev_name(&csrow->dev));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Create a CSROW object under specified edac_mc_device */
|
||||
static int edac_create_csrow_objects(struct mem_ctl_info *mci)
|
||||
{
|
||||
int err, i;
|
||||
struct csrow_info *csrow;
|
||||
|
||||
for (i = 0; i < mci->nr_csrows; i++) {
|
||||
csrow = mci->csrows[i];
|
||||
if (!nr_pages_per_csrow(csrow))
|
||||
continue;
|
||||
err = edac_create_csrow_object(mci, mci->csrows[i], i);
|
||||
if (err < 0)
|
||||
goto error;
|
||||
}
|
||||
return 0;
|
||||
|
||||
error:
|
||||
for (--i; i >= 0; i--) {
|
||||
if (device_is_registered(&mci->csrows[i]->dev))
|
||||
device_unregister(&mci->csrows[i]->dev);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static void edac_delete_csrow_objects(struct mem_ctl_info *mci)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < mci->nr_csrows; i++) {
|
||||
if (device_is_registered(&mci->csrows[i]->dev))
|
||||
device_unregister(&mci->csrows[i]->dev);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Per-dimm (or per-rank) devices
|
||||
*/
|
||||
|
|
@ -989,12 +594,6 @@ int edac_create_sysfs_mci_device(struct mem_ctl_info *mci,
|
|||
goto fail;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_EDAC_LEGACY_SYSFS
|
||||
err = edac_create_csrow_objects(mci);
|
||||
if (err < 0)
|
||||
goto fail;
|
||||
#endif
|
||||
|
||||
edac_create_debugfs_nodes(mci);
|
||||
return 0;
|
||||
|
||||
|
|
@ -1019,9 +618,6 @@ void edac_remove_sysfs_mci_device(struct mem_ctl_info *mci)
|
|||
#ifdef CONFIG_EDAC_DEBUG
|
||||
edac_debugfs_remove_recursive(mci->debugfs);
|
||||
#endif
|
||||
#ifdef CONFIG_EDAC_LEGACY_SYSFS
|
||||
edac_delete_csrow_objects(mci);
|
||||
#endif
|
||||
|
||||
mci_for_each_dimm(mci, dimm) {
|
||||
if (!device_is_registered(&dimm->dev))
|
||||
|
|
|
|||
Loading…
Reference in New Issue