^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) * edac_mc kernel module
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * (C) 2005-2007 Linux Networx (http://lnxi.com)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * This file may be distributed under the terms of the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * GNU General Public License.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) * Written Doug Thompson <norsk5@xmission.com> www.softwarebitmaker.com
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) * (c) 2012-2013 - Mauro Carvalho Chehab
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) * The entire API were re-written, and ported to use struct device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/ctype.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <linux/edac.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <linux/bug.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include <linux/pm_runtime.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #include <linux/uaccess.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #include "edac_mc.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #include "edac_module.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) /* MC EDAC Controls, setable by module parameter, and sysfs */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) static int edac_mc_log_ue = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) static int edac_mc_log_ce = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) static int edac_mc_panic_on_ue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) static unsigned int edac_mc_poll_msec = 1000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) /* Getter functions for above */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) int edac_mc_get_log_ue(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) return edac_mc_log_ue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) int edac_mc_get_log_ce(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) return edac_mc_log_ce;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) int edac_mc_get_panic_on_ue(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) return edac_mc_panic_on_ue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) /* this is temporary */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) unsigned int edac_mc_get_poll_msec(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) return edac_mc_poll_msec;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) static int edac_set_poll_msec(const char *val, const struct kernel_param *kp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) unsigned int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) if (!val)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) ret = kstrtouint(val, 0, &i);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) if (i < 1000)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) *((unsigned int *)kp->arg) = i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) /* notify edac_mc engine to reset the poll period */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) edac_mc_reset_delay_period(i);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) /* Parameter declarations for above */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) module_param(edac_mc_panic_on_ue, int, 0644);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) MODULE_PARM_DESC(edac_mc_panic_on_ue, "Panic on uncorrected error: 0=off 1=on");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) module_param(edac_mc_log_ue, int, 0644);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) MODULE_PARM_DESC(edac_mc_log_ue,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) "Log uncorrectable error to console: 0=off 1=on");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) module_param(edac_mc_log_ce, int, 0644);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) MODULE_PARM_DESC(edac_mc_log_ce,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) "Log correctable error to console: 0=off 1=on");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) module_param_call(edac_mc_poll_msec, edac_set_poll_msec, param_get_uint,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) &edac_mc_poll_msec, 0644);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) MODULE_PARM_DESC(edac_mc_poll_msec, "Polling period in milliseconds");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) static struct device *mci_pdev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) * various constants for Memory Controllers
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) static const char * const dev_types[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) [DEV_UNKNOWN] = "Unknown",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) [DEV_X1] = "x1",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) [DEV_X2] = "x2",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) [DEV_X4] = "x4",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) [DEV_X8] = "x8",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) [DEV_X16] = "x16",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) [DEV_X32] = "x32",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) [DEV_X64] = "x64"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) static const char * const edac_caps[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) [EDAC_UNKNOWN] = "Unknown",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) [EDAC_NONE] = "None",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) [EDAC_RESERVED] = "Reserved",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) [EDAC_PARITY] = "PARITY",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) [EDAC_EC] = "EC",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) [EDAC_SECDED] = "SECDED",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) [EDAC_S2ECD2ED] = "S2ECD2ED",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) [EDAC_S4ECD4ED] = "S4ECD4ED",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) [EDAC_S8ECD8ED] = "S8ECD8ED",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) [EDAC_S16ECD16ED] = "S16ECD16ED"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) #ifdef CONFIG_EDAC_LEGACY_SYSFS
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) * EDAC sysfs CSROW data structures and methods
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) #define to_csrow(k) container_of(k, struct csrow_info, dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) * We need it to avoid namespace conflicts between the legacy API
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) * and the per-dimm/per-rank one
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) #define DEVICE_ATTR_LEGACY(_name, _mode, _show, _store) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) static struct device_attribute dev_attr_legacy_##_name = __ATTR(_name, _mode, _show, _store)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) struct dev_ch_attribute {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) struct device_attribute attr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) unsigned int channel;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) #define DEVICE_CHANNEL(_name, _mode, _show, _store, _var) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) static struct dev_ch_attribute dev_attr_legacy_##_name = \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) { __ATTR(_name, _mode, _show, _store), (_var) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) #define to_channel(k) (container_of(k, struct dev_ch_attribute, attr)->channel)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) /* Set of more default csrow<id> attribute show/store functions */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) static ssize_t csrow_ue_count_show(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) struct device_attribute *mattr, char *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) struct csrow_info *csrow = to_csrow(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) return sprintf(data, "%u\n", csrow->ue_count);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) static ssize_t csrow_ce_count_show(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) struct device_attribute *mattr, char *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) struct csrow_info *csrow = to_csrow(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) return sprintf(data, "%u\n", csrow->ce_count);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) static ssize_t csrow_size_show(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) struct device_attribute *mattr, char *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) struct csrow_info *csrow = to_csrow(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) u32 nr_pages = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) for (i = 0; i < csrow->nr_channels; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) nr_pages += csrow->channels[i]->dimm->nr_pages;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) return sprintf(data, "%u\n", PAGES_TO_MiB(nr_pages));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) static ssize_t csrow_mem_type_show(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) struct device_attribute *mattr, char *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) struct csrow_info *csrow = to_csrow(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) return sprintf(data, "%s\n", edac_mem_types[csrow->channels[0]->dimm->mtype]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) static ssize_t csrow_dev_type_show(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) struct device_attribute *mattr, char *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) struct csrow_info *csrow = to_csrow(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) return sprintf(data, "%s\n", dev_types[csrow->channels[0]->dimm->dtype]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) static ssize_t csrow_edac_mode_show(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) struct device_attribute *mattr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) char *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) struct csrow_info *csrow = to_csrow(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) return sprintf(data, "%s\n", edac_caps[csrow->channels[0]->dimm->edac_mode]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) /* show/store functions for DIMM Label attributes */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) static ssize_t channel_dimm_label_show(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) struct device_attribute *mattr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) char *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) struct csrow_info *csrow = to_csrow(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) unsigned int chan = to_channel(mattr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) struct rank_info *rank = csrow->channels[chan];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) /* if field has not been initialized, there is nothing to send */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) if (!rank->dimm->label[0])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) return snprintf(data, sizeof(rank->dimm->label) + 1, "%s\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) rank->dimm->label);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) static ssize_t channel_dimm_label_store(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) struct device_attribute *mattr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) const char *data, size_t count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) struct csrow_info *csrow = to_csrow(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) unsigned int chan = to_channel(mattr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) struct rank_info *rank = csrow->channels[chan];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) size_t copy_count = count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) if (count == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) if (data[count - 1] == '\0' || data[count - 1] == '\n')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) copy_count -= 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) if (copy_count == 0 || copy_count >= sizeof(rank->dimm->label))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) strncpy(rank->dimm->label, data, copy_count);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) rank->dimm->label[copy_count] = '\0';
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) return count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) /* show function for dynamic chX_ce_count attribute */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) static ssize_t channel_ce_count_show(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) struct device_attribute *mattr, char *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) struct csrow_info *csrow = to_csrow(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) unsigned int chan = to_channel(mattr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) struct rank_info *rank = csrow->channels[chan];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) return sprintf(data, "%u\n", rank->ce_count);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) /* cwrow<id>/attribute files */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) DEVICE_ATTR_LEGACY(size_mb, S_IRUGO, csrow_size_show, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) DEVICE_ATTR_LEGACY(dev_type, S_IRUGO, csrow_dev_type_show, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) DEVICE_ATTR_LEGACY(mem_type, S_IRUGO, csrow_mem_type_show, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) DEVICE_ATTR_LEGACY(edac_mode, S_IRUGO, csrow_edac_mode_show, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) DEVICE_ATTR_LEGACY(ue_count, S_IRUGO, csrow_ue_count_show, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) DEVICE_ATTR_LEGACY(ce_count, S_IRUGO, csrow_ce_count_show, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) /* default attributes of the CSROW<id> object */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) static struct attribute *csrow_attrs[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) &dev_attr_legacy_dev_type.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) &dev_attr_legacy_mem_type.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) &dev_attr_legacy_edac_mode.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) &dev_attr_legacy_size_mb.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) &dev_attr_legacy_ue_count.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) &dev_attr_legacy_ce_count.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) NULL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) static const struct attribute_group csrow_attr_grp = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) .attrs = csrow_attrs,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) static const struct attribute_group *csrow_attr_groups[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) &csrow_attr_grp,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) NULL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) static const struct device_type csrow_attr_type = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) .groups = csrow_attr_groups,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) * possible dynamic channel DIMM Label attribute files
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) DEVICE_CHANNEL(ch0_dimm_label, S_IRUGO | S_IWUSR,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) channel_dimm_label_show, channel_dimm_label_store, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) DEVICE_CHANNEL(ch1_dimm_label, S_IRUGO | S_IWUSR,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) channel_dimm_label_show, channel_dimm_label_store, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) DEVICE_CHANNEL(ch2_dimm_label, S_IRUGO | S_IWUSR,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) channel_dimm_label_show, channel_dimm_label_store, 2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) DEVICE_CHANNEL(ch3_dimm_label, S_IRUGO | S_IWUSR,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) channel_dimm_label_show, channel_dimm_label_store, 3);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) DEVICE_CHANNEL(ch4_dimm_label, S_IRUGO | S_IWUSR,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) channel_dimm_label_show, channel_dimm_label_store, 4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) DEVICE_CHANNEL(ch5_dimm_label, S_IRUGO | S_IWUSR,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) channel_dimm_label_show, channel_dimm_label_store, 5);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) DEVICE_CHANNEL(ch6_dimm_label, S_IRUGO | S_IWUSR,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) channel_dimm_label_show, channel_dimm_label_store, 6);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) DEVICE_CHANNEL(ch7_dimm_label, S_IRUGO | S_IWUSR,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) channel_dimm_label_show, channel_dimm_label_store, 7);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) /* Total possible dynamic DIMM Label attribute file table */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) static struct attribute *dynamic_csrow_dimm_attr[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) &dev_attr_legacy_ch0_dimm_label.attr.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) &dev_attr_legacy_ch1_dimm_label.attr.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) &dev_attr_legacy_ch2_dimm_label.attr.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) &dev_attr_legacy_ch3_dimm_label.attr.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) &dev_attr_legacy_ch4_dimm_label.attr.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) &dev_attr_legacy_ch5_dimm_label.attr.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) &dev_attr_legacy_ch6_dimm_label.attr.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) &dev_attr_legacy_ch7_dimm_label.attr.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) NULL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) /* possible dynamic channel ce_count attribute files */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) DEVICE_CHANNEL(ch0_ce_count, S_IRUGO,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) channel_ce_count_show, NULL, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) DEVICE_CHANNEL(ch1_ce_count, S_IRUGO,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) channel_ce_count_show, NULL, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) DEVICE_CHANNEL(ch2_ce_count, S_IRUGO,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) channel_ce_count_show, NULL, 2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) DEVICE_CHANNEL(ch3_ce_count, S_IRUGO,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) channel_ce_count_show, NULL, 3);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) DEVICE_CHANNEL(ch4_ce_count, S_IRUGO,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) channel_ce_count_show, NULL, 4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) DEVICE_CHANNEL(ch5_ce_count, S_IRUGO,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) channel_ce_count_show, NULL, 5);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) DEVICE_CHANNEL(ch6_ce_count, S_IRUGO,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) channel_ce_count_show, NULL, 6);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) DEVICE_CHANNEL(ch7_ce_count, S_IRUGO,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) channel_ce_count_show, NULL, 7);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) /* Total possible dynamic ce_count attribute file table */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) static struct attribute *dynamic_csrow_ce_count_attr[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) &dev_attr_legacy_ch0_ce_count.attr.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) &dev_attr_legacy_ch1_ce_count.attr.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) &dev_attr_legacy_ch2_ce_count.attr.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) &dev_attr_legacy_ch3_ce_count.attr.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) &dev_attr_legacy_ch4_ce_count.attr.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) &dev_attr_legacy_ch5_ce_count.attr.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) &dev_attr_legacy_ch6_ce_count.attr.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) &dev_attr_legacy_ch7_ce_count.attr.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) NULL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) static umode_t csrow_dev_is_visible(struct kobject *kobj,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) struct attribute *attr, int idx)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) struct device *dev = kobj_to_dev(kobj);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) struct csrow_info *csrow = container_of(dev, struct csrow_info, dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) if (idx >= csrow->nr_channels)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) if (idx >= ARRAY_SIZE(dynamic_csrow_ce_count_attr) - 1) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) WARN_ONCE(1, "idx: %d\n", idx);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) /* Only expose populated DIMMs */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) if (!csrow->channels[idx]->dimm->nr_pages)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) return attr->mode;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) static const struct attribute_group csrow_dev_dimm_group = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) .attrs = dynamic_csrow_dimm_attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) .is_visible = csrow_dev_is_visible,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) static const struct attribute_group csrow_dev_ce_count_group = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) .attrs = dynamic_csrow_ce_count_attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) .is_visible = csrow_dev_is_visible,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) static const struct attribute_group *csrow_dev_groups[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) &csrow_dev_dimm_group,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) &csrow_dev_ce_count_group,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) NULL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) static void csrow_release(struct device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) * Nothing to do, just unregister sysfs here. The mci
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) * device owns the data and will also release it.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) static inline int nr_pages_per_csrow(struct csrow_info *csrow)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) int chan, nr_pages = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) for (chan = 0; chan < csrow->nr_channels; chan++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) nr_pages += csrow->channels[chan]->dimm->nr_pages;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) return nr_pages;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) /* Create a CSROW object under specifed edac_mc_device */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) static int edac_create_csrow_object(struct mem_ctl_info *mci,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) struct csrow_info *csrow, int index)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) csrow->dev.type = &csrow_attr_type;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) csrow->dev.groups = csrow_dev_groups;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) csrow->dev.release = csrow_release;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) device_initialize(&csrow->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) csrow->dev.parent = &mci->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) csrow->mci = mci;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) dev_set_name(&csrow->dev, "csrow%d", index);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) dev_set_drvdata(&csrow->dev, csrow);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) err = device_add(&csrow->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) if (err) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) edac_dbg(1, "failure: create device %s\n", dev_name(&csrow->dev));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) put_device(&csrow->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) edac_dbg(0, "device %s created\n", dev_name(&csrow->dev));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) /* Create a CSROW object under specifed edac_mc_device */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) static int edac_create_csrow_objects(struct mem_ctl_info *mci)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) int err, i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) struct csrow_info *csrow;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) for (i = 0; i < mci->nr_csrows; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) csrow = mci->csrows[i];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) if (!nr_pages_per_csrow(csrow))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) err = edac_create_csrow_object(mci, mci->csrows[i], i);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) if (err < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) goto error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) error:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) for (--i; i >= 0; i--) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) if (device_is_registered(&mci->csrows[i]->dev))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) device_unregister(&mci->csrows[i]->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) static void edac_delete_csrow_objects(struct mem_ctl_info *mci)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) for (i = 0; i < mci->nr_csrows; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) if (device_is_registered(&mci->csrows[i]->dev))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) device_unregister(&mci->csrows[i]->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467) * Per-dimm (or per-rank) devices
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470) #define to_dimm(k) container_of(k, struct dimm_info, dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472) /* show/store functions for DIMM Label attributes */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473) static ssize_t dimmdev_location_show(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) struct device_attribute *mattr, char *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) struct dimm_info *dimm = to_dimm(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477) ssize_t count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) count = edac_dimm_info_location(dimm, data, PAGE_SIZE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) count += scnprintf(data + count, PAGE_SIZE - count, "\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482) return count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485) static ssize_t dimmdev_label_show(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486) struct device_attribute *mattr, char *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488) struct dimm_info *dimm = to_dimm(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490) /* if field has not been initialized, there is nothing to send */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491) if (!dimm->label[0])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494) return snprintf(data, sizeof(dimm->label) + 1, "%s\n", dimm->label);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497) static ssize_t dimmdev_label_store(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498) struct device_attribute *mattr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) const char *data,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) size_t count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502) struct dimm_info *dimm = to_dimm(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503) size_t copy_count = count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) if (count == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508) if (data[count - 1] == '\0' || data[count - 1] == '\n')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509) copy_count -= 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511) if (copy_count == 0 || copy_count >= sizeof(dimm->label))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514) strncpy(dimm->label, data, copy_count);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515) dimm->label[copy_count] = '\0';
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517) return count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520) static ssize_t dimmdev_size_show(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521) struct device_attribute *mattr, char *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523) struct dimm_info *dimm = to_dimm(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525) return sprintf(data, "%u\n", PAGES_TO_MiB(dimm->nr_pages));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528) static ssize_t dimmdev_mem_type_show(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529) struct device_attribute *mattr, char *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531) struct dimm_info *dimm = to_dimm(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533) return sprintf(data, "%s\n", edac_mem_types[dimm->mtype]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536) static ssize_t dimmdev_dev_type_show(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537) struct device_attribute *mattr, char *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539) struct dimm_info *dimm = to_dimm(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541) return sprintf(data, "%s\n", dev_types[dimm->dtype]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544) static ssize_t dimmdev_edac_mode_show(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545) struct device_attribute *mattr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546) char *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548) struct dimm_info *dimm = to_dimm(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550) return sprintf(data, "%s\n", edac_caps[dimm->edac_mode]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553) static ssize_t dimmdev_ce_count_show(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554) struct device_attribute *mattr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555) char *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557) struct dimm_info *dimm = to_dimm(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559) return sprintf(data, "%u\n", dimm->ce_count);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562) static ssize_t dimmdev_ue_count_show(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563) struct device_attribute *mattr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564) char *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566) struct dimm_info *dimm = to_dimm(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568) return sprintf(data, "%u\n", dimm->ue_count);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571) /* dimm/rank attribute files */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572) static DEVICE_ATTR(dimm_label, S_IRUGO | S_IWUSR,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573) dimmdev_label_show, dimmdev_label_store);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574) static DEVICE_ATTR(dimm_location, S_IRUGO, dimmdev_location_show, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575) static DEVICE_ATTR(size, S_IRUGO, dimmdev_size_show, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576) static DEVICE_ATTR(dimm_mem_type, S_IRUGO, dimmdev_mem_type_show, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 577) static DEVICE_ATTR(dimm_dev_type, S_IRUGO, dimmdev_dev_type_show, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 578) static DEVICE_ATTR(dimm_edac_mode, S_IRUGO, dimmdev_edac_mode_show, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 579) static DEVICE_ATTR(dimm_ce_count, S_IRUGO, dimmdev_ce_count_show, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 580) static DEVICE_ATTR(dimm_ue_count, S_IRUGO, dimmdev_ue_count_show, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 581)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 582) /* attributes of the dimm<id>/rank<id> object */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 583) static struct attribute *dimm_attrs[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 584) &dev_attr_dimm_label.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 585) &dev_attr_dimm_location.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 586) &dev_attr_size.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 587) &dev_attr_dimm_mem_type.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 588) &dev_attr_dimm_dev_type.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 589) &dev_attr_dimm_edac_mode.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 590) &dev_attr_dimm_ce_count.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 591) &dev_attr_dimm_ue_count.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 592) NULL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 593) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 594)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 595) static const struct attribute_group dimm_attr_grp = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 596) .attrs = dimm_attrs,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 597) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 598)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 599) static const struct attribute_group *dimm_attr_groups[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 600) &dimm_attr_grp,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 601) NULL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 602) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 603)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 604) static const struct device_type dimm_attr_type = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 605) .groups = dimm_attr_groups,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 606) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 607)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 608) static void dimm_release(struct device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 609) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 610) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 611) * Nothing to do, just unregister sysfs here. The mci
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 612) * device owns the data and will also release it.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 613) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 614) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 615)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 616) /* Create a DIMM object under specifed memory controller device */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 617) static int edac_create_dimm_object(struct mem_ctl_info *mci,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 618) struct dimm_info *dimm)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 619) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 620) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 621) dimm->mci = mci;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 622)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 623) dimm->dev.type = &dimm_attr_type;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 624) dimm->dev.release = dimm_release;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 625) device_initialize(&dimm->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 626)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 627) dimm->dev.parent = &mci->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 628) if (mci->csbased)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 629) dev_set_name(&dimm->dev, "rank%d", dimm->idx);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 630) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 631) dev_set_name(&dimm->dev, "dimm%d", dimm->idx);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 632) dev_set_drvdata(&dimm->dev, dimm);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 633) pm_runtime_forbid(&mci->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 634)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 635) err = device_add(&dimm->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 636) if (err) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 637) edac_dbg(1, "failure: create device %s\n", dev_name(&dimm->dev));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 638) put_device(&dimm->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 639) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 640) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 641)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 642) if (IS_ENABLED(CONFIG_EDAC_DEBUG)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 643) char location[80];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 644)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 645) edac_dimm_info_location(dimm, location, sizeof(location));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 646) edac_dbg(0, "device %s created at location %s\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 647) dev_name(&dimm->dev), location);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 648) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 649)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 650) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 651) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 652)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 653) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 654) * Memory controller device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 655) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 656)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 657) #define to_mci(k) container_of(k, struct mem_ctl_info, dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 658)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 659) static ssize_t mci_reset_counters_store(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 660) struct device_attribute *mattr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 661) const char *data, size_t count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 662) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 663) struct mem_ctl_info *mci = to_mci(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 664) struct dimm_info *dimm;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 665) int row, chan;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 666)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 667) mci->ue_mc = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 668) mci->ce_mc = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 669) mci->ue_noinfo_count = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 670) mci->ce_noinfo_count = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 671)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 672) for (row = 0; row < mci->nr_csrows; row++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 673) struct csrow_info *ri = mci->csrows[row];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 674)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 675) ri->ue_count = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 676) ri->ce_count = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 677)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 678) for (chan = 0; chan < ri->nr_channels; chan++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 679) ri->channels[chan]->ce_count = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 680) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 681)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 682) mci_for_each_dimm(mci, dimm) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 683) dimm->ue_count = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 684) dimm->ce_count = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 685) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 686)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 687) mci->start_time = jiffies;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 688) return count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 689) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 690)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 691) /* Memory scrubbing interface:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 692) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 693) * A MC driver can limit the scrubbing bandwidth based on the CPU type.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 694) * Therefore, ->set_sdram_scrub_rate should be made to return the actual
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 695) * bandwidth that is accepted or 0 when scrubbing is to be disabled.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 696) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 697) * Negative value still means that an error has occurred while setting
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 698) * the scrub rate.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 699) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 700) static ssize_t mci_sdram_scrub_rate_store(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 701) struct device_attribute *mattr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 702) const char *data, size_t count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 703) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 704) struct mem_ctl_info *mci = to_mci(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 705) unsigned long bandwidth = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 706) int new_bw = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 707)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 708) if (kstrtoul(data, 10, &bandwidth) < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 709) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 710)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 711) new_bw = mci->set_sdram_scrub_rate(mci, bandwidth);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 712) if (new_bw < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 713) edac_printk(KERN_WARNING, EDAC_MC,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 714) "Error setting scrub rate to: %lu\n", bandwidth);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 715) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 716) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 717)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 718) return count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 719) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 720)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 721) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 722) * ->get_sdram_scrub_rate() return value semantics same as above.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 723) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 724) static ssize_t mci_sdram_scrub_rate_show(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 725) struct device_attribute *mattr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 726) char *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 727) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 728) struct mem_ctl_info *mci = to_mci(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 729) int bandwidth = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 730)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 731) bandwidth = mci->get_sdram_scrub_rate(mci);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 732) if (bandwidth < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 733) edac_printk(KERN_DEBUG, EDAC_MC, "Error reading scrub rate\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 734) return bandwidth;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 735) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 736)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 737) return sprintf(data, "%d\n", bandwidth);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 738) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 739)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 740) /* default attribute files for the MCI object */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 741) static ssize_t mci_ue_count_show(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 742) struct device_attribute *mattr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 743) char *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 744) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 745) struct mem_ctl_info *mci = to_mci(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 746)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 747) return sprintf(data, "%d\n", mci->ue_mc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 748) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 749)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 750) static ssize_t mci_ce_count_show(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 751) struct device_attribute *mattr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 752) char *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 753) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 754) struct mem_ctl_info *mci = to_mci(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 755)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 756) return sprintf(data, "%d\n", mci->ce_mc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 757) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 758)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 759) static ssize_t mci_ce_noinfo_show(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 760) struct device_attribute *mattr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 761) char *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 762) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 763) struct mem_ctl_info *mci = to_mci(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 764)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 765) return sprintf(data, "%d\n", mci->ce_noinfo_count);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 766) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 767)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 768) static ssize_t mci_ue_noinfo_show(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 769) struct device_attribute *mattr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 770) char *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 771) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 772) struct mem_ctl_info *mci = to_mci(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 773)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 774) return sprintf(data, "%d\n", mci->ue_noinfo_count);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 775) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 776)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 777) static ssize_t mci_seconds_show(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 778) struct device_attribute *mattr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 779) char *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 780) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 781) struct mem_ctl_info *mci = to_mci(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 782)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 783) return sprintf(data, "%ld\n", (jiffies - mci->start_time) / HZ);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 784) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 785)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 786) static ssize_t mci_ctl_name_show(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 787) struct device_attribute *mattr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 788) char *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 789) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 790) struct mem_ctl_info *mci = to_mci(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 791)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 792) return sprintf(data, "%s\n", mci->ctl_name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 793) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 794)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 795) static ssize_t mci_size_mb_show(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 796) struct device_attribute *mattr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 797) char *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 798) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 799) struct mem_ctl_info *mci = to_mci(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 800) int total_pages = 0, csrow_idx, j;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 801)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 802) for (csrow_idx = 0; csrow_idx < mci->nr_csrows; csrow_idx++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 803) struct csrow_info *csrow = mci->csrows[csrow_idx];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 804)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 805) for (j = 0; j < csrow->nr_channels; j++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 806) struct dimm_info *dimm = csrow->channels[j]->dimm;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 807)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 808) total_pages += dimm->nr_pages;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 809) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 810) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 811)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 812) return sprintf(data, "%u\n", PAGES_TO_MiB(total_pages));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 813) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 814)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 815) static ssize_t mci_max_location_show(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 816) struct device_attribute *mattr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 817) char *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 818) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 819) struct mem_ctl_info *mci = to_mci(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 820) int len = PAGE_SIZE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 821) char *p = data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 822) int i, n;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 823)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 824) for (i = 0; i < mci->n_layers; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 825) n = scnprintf(p, len, "%s %d ",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 826) edac_layer_name[mci->layers[i].type],
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 827) mci->layers[i].size - 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 828) len -= n;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 829) if (len <= 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 830) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 831)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 832) p += n;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 833) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 834)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 835) p += scnprintf(p, len, "\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 836) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 837) return p - data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 838) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 839)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 840) /* default Control file */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 841) static DEVICE_ATTR(reset_counters, S_IWUSR, NULL, mci_reset_counters_store);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 842)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 843) /* default Attribute files */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 844) static DEVICE_ATTR(mc_name, S_IRUGO, mci_ctl_name_show, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 845) static DEVICE_ATTR(size_mb, S_IRUGO, mci_size_mb_show, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 846) static DEVICE_ATTR(seconds_since_reset, S_IRUGO, mci_seconds_show, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 847) static DEVICE_ATTR(ue_noinfo_count, S_IRUGO, mci_ue_noinfo_show, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 848) static DEVICE_ATTR(ce_noinfo_count, S_IRUGO, mci_ce_noinfo_show, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 849) static DEVICE_ATTR(ue_count, S_IRUGO, mci_ue_count_show, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 850) static DEVICE_ATTR(ce_count, S_IRUGO, mci_ce_count_show, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 851) static DEVICE_ATTR(max_location, S_IRUGO, mci_max_location_show, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 852)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 853) /* memory scrubber attribute file */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 854) static DEVICE_ATTR(sdram_scrub_rate, 0, mci_sdram_scrub_rate_show,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 855) mci_sdram_scrub_rate_store); /* umode set later in is_visible */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 856)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 857) static struct attribute *mci_attrs[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 858) &dev_attr_reset_counters.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 859) &dev_attr_mc_name.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 860) &dev_attr_size_mb.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 861) &dev_attr_seconds_since_reset.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 862) &dev_attr_ue_noinfo_count.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 863) &dev_attr_ce_noinfo_count.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 864) &dev_attr_ue_count.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 865) &dev_attr_ce_count.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 866) &dev_attr_max_location.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 867) &dev_attr_sdram_scrub_rate.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 868) NULL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 869) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 870)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 871) static umode_t mci_attr_is_visible(struct kobject *kobj,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 872) struct attribute *attr, int idx)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 873) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 874) struct device *dev = kobj_to_dev(kobj);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 875) struct mem_ctl_info *mci = to_mci(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 876) umode_t mode = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 877)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 878) if (attr != &dev_attr_sdram_scrub_rate.attr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 879) return attr->mode;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 880) if (mci->get_sdram_scrub_rate)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 881) mode |= S_IRUGO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 882) if (mci->set_sdram_scrub_rate)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 883) mode |= S_IWUSR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 884) return mode;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 885) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 886)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 887) static const struct attribute_group mci_attr_grp = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 888) .attrs = mci_attrs,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 889) .is_visible = mci_attr_is_visible,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 890) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 891)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 892) static const struct attribute_group *mci_attr_groups[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 893) &mci_attr_grp,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 894) NULL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 895) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 896)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 897) static const struct device_type mci_attr_type = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 898) .groups = mci_attr_groups,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 899) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 900)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 901) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 902) * Create a new Memory Controller kobject instance,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 903) * mc<id> under the 'mc' directory
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 904) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 905) * Return:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 906) * 0 Success
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 907) * !0 Failure
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 908) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 909) int edac_create_sysfs_mci_device(struct mem_ctl_info *mci,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 910) const struct attribute_group **groups)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 911) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 912) struct dimm_info *dimm;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 913) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 914)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 915) /* get the /sys/devices/system/edac subsys reference */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 916) mci->dev.type = &mci_attr_type;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 917) mci->dev.parent = mci_pdev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 918) mci->dev.groups = groups;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 919) dev_set_name(&mci->dev, "mc%d", mci->mc_idx);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 920) dev_set_drvdata(&mci->dev, mci);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 921) pm_runtime_forbid(&mci->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 922)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 923) err = device_add(&mci->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 924) if (err < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 925) edac_dbg(1, "failure: create device %s\n", dev_name(&mci->dev));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 926) /* no put_device() here, free mci with _edac_mc_free() */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 927) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 928) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 929)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 930) edac_dbg(0, "device %s created\n", dev_name(&mci->dev));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 931)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 932) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 933) * Create the dimm/rank devices
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 934) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 935) mci_for_each_dimm(mci, dimm) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 936) /* Only expose populated DIMMs */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 937) if (!dimm->nr_pages)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 938) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 939)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 940) err = edac_create_dimm_object(mci, dimm);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 941) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 942) goto fail;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 943) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 944)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 945) #ifdef CONFIG_EDAC_LEGACY_SYSFS
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 946) err = edac_create_csrow_objects(mci);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 947) if (err < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 948) goto fail;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 949) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 950)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 951) edac_create_debugfs_nodes(mci);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 952) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 953)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 954) fail:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 955) edac_remove_sysfs_mci_device(mci);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 956)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 957) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 958) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 959)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 960) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 961) * remove a Memory Controller instance
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 962) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 963) void edac_remove_sysfs_mci_device(struct mem_ctl_info *mci)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 964) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 965) struct dimm_info *dimm;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 966)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 967) if (!device_is_registered(&mci->dev))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 968) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 969)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 970) edac_dbg(0, "\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 971)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 972) #ifdef CONFIG_EDAC_DEBUG
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 973) edac_debugfs_remove_recursive(mci->debugfs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 974) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 975) #ifdef CONFIG_EDAC_LEGACY_SYSFS
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 976) edac_delete_csrow_objects(mci);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 977) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 978)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 979) mci_for_each_dimm(mci, dimm) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 980) if (!device_is_registered(&dimm->dev))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 981) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 982) edac_dbg(1, "unregistering device %s\n", dev_name(&dimm->dev));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 983) device_unregister(&dimm->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 984) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 985)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 986) /* only remove the device, but keep mci */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 987) device_del(&mci->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 988) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 989)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 990) static void mc_attr_release(struct device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 991) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 992) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 993) * There's no container structure here, as this is just the mci
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 994) * parent device, used to create the /sys/devices/mc sysfs node.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 995) * So, there are no attributes on it.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 996) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 997) edac_dbg(1, "device %s released\n", dev_name(dev));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 998) kfree(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 999) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1000)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1001) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1002) * Init/exit code for the module. Basically, creates/removes /sys/class/rc
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1003) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1004) int __init edac_mc_sysfs_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1005) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1006) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1007)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1008) mci_pdev = kzalloc(sizeof(*mci_pdev), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1009) if (!mci_pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1010) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1011)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1012) mci_pdev->bus = edac_get_sysfs_subsys();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1013) mci_pdev->release = mc_attr_release;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1014) mci_pdev->init_name = "mc";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1015)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1016) err = device_register(mci_pdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1017) if (err < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1018) edac_dbg(1, "failure: create device %s\n", dev_name(mci_pdev));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1019) put_device(mci_pdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1020) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1021) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1022)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1023) edac_dbg(0, "device %s created\n", dev_name(mci_pdev));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1024)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1025) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1026) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1027)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1028) void edac_mc_sysfs_exit(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1029) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1030) device_unregister(mci_pdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1031) }