1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * The generic EDAC memory repair driver is designed to control the memory 4 * devices with memory repair features, such as Post Package Repair (PPR), 5 * memory sparing etc. The common sysfs memory repair interface abstracts 6 * the control of various arbitrary memory repair functionalities into a 7 * unified set of functions. 8 * 9 * Copyright (c) 2024-2025 HiSilicon Limited. 10 */ 11 12 #include <linux/edac.h> 13 14 enum edac_mem_repair_attributes { 15 MR_TYPE, 16 MR_PERSIST_MODE, 17 MR_SAFE_IN_USE, 18 MR_HPA, 19 MR_MIN_HPA, 20 MR_MAX_HPA, 21 MR_DPA, 22 MR_MIN_DPA, 23 MR_MAX_DPA, 24 MR_NIBBLE_MASK, 25 MR_BANK_GROUP, 26 MR_BANK, 27 MR_RANK, 28 MR_ROW, 29 MR_COLUMN, 30 MR_CHANNEL, 31 MR_SUB_CHANNEL, 32 MEM_DO_REPAIR, 33 MR_MAX_ATTRS 34 }; 35 36 struct edac_mem_repair_dev_attr { 37 struct device_attribute dev_attr; 38 u8 instance; 39 }; 40 41 struct edac_mem_repair_context { 42 char name[EDAC_FEAT_NAME_LEN]; 43 struct edac_mem_repair_dev_attr mem_repair_dev_attr[MR_MAX_ATTRS]; 44 struct attribute *mem_repair_attrs[MR_MAX_ATTRS + 1]; 45 struct attribute_group group; 46 }; 47 48 #define TO_MR_DEV_ATTR(_dev_attr) \ 49 container_of(_dev_attr, struct edac_mem_repair_dev_attr, dev_attr) 50 51 #define MR_ATTR_SHOW(attrib, cb, type, format) \ 52 static ssize_t attrib##_show(struct device *ras_feat_dev, \ 53 struct device_attribute *attr, char *buf) \ 54 { \ 55 u8 inst = TO_MR_DEV_ATTR(attr)->instance; \ 56 struct edac_dev_feat_ctx *ctx = dev_get_drvdata(ras_feat_dev); \ 57 const struct edac_mem_repair_ops *ops = \ 58 ctx->mem_repair[inst].mem_repair_ops; \ 59 type data; \ 60 int ret; \ 61 \ 62 ret = ops->cb(ras_feat_dev->parent, ctx->mem_repair[inst].private, \ 63 &data); \ 64 if (ret) \ 65 return ret; \ 66 \ 67 return sysfs_emit(buf, format, data); \ 68 } 69 70 MR_ATTR_SHOW(repair_type, get_repair_type, const char *, "%s\n") 71 MR_ATTR_SHOW(persist_mode, get_persist_mode, bool, "%u\n") 72 MR_ATTR_SHOW(repair_safe_when_in_use, get_repair_safe_when_in_use, bool, "%u\n") 73 MR_ATTR_SHOW(hpa, get_hpa, u64, "0x%llx\n") 74 MR_ATTR_SHOW(min_hpa, get_min_hpa, u64, "0x%llx\n") 75 MR_ATTR_SHOW(max_hpa, get_max_hpa, u64, "0x%llx\n") 76 MR_ATTR_SHOW(dpa, get_dpa, u64, "0x%llx\n") 77 MR_ATTR_SHOW(min_dpa, get_min_dpa, u64, "0x%llx\n") 78 MR_ATTR_SHOW(max_dpa, get_max_dpa, u64, "0x%llx\n") 79 MR_ATTR_SHOW(nibble_mask, get_nibble_mask, u32, "0x%x\n") 80 MR_ATTR_SHOW(bank_group, get_bank_group, u32, "%u\n") 81 MR_ATTR_SHOW(bank, get_bank, u32, "%u\n") 82 MR_ATTR_SHOW(rank, get_rank, u32, "%u\n") 83 MR_ATTR_SHOW(row, get_row, u32, "0x%x\n") 84 MR_ATTR_SHOW(column, get_column, u32, "%u\n") 85 MR_ATTR_SHOW(channel, get_channel, u32, "%u\n") 86 MR_ATTR_SHOW(sub_channel, get_sub_channel, u32, "%u\n") 87 88 #define MR_ATTR_STORE(attrib, cb, type, conv_func) \ 89 static ssize_t attrib##_store(struct device *ras_feat_dev, \ 90 struct device_attribute *attr, \ 91 const char *buf, size_t len) \ 92 { \ 93 u8 inst = TO_MR_DEV_ATTR(attr)->instance; \ 94 struct edac_dev_feat_ctx *ctx = dev_get_drvdata(ras_feat_dev); \ 95 const struct edac_mem_repair_ops *ops = \ 96 ctx->mem_repair[inst].mem_repair_ops; \ 97 type data; \ 98 int ret; \ 99 \ 100 ret = conv_func(buf, 0, &data); \ 101 if (ret < 0) \ 102 return ret; \ 103 \ 104 ret = ops->cb(ras_feat_dev->parent, ctx->mem_repair[inst].private, \ 105 data); \ 106 if (ret) \ 107 return ret; \ 108 \ 109 return len; \ 110 } 111 112 MR_ATTR_STORE(persist_mode, set_persist_mode, unsigned long, kstrtoul) 113 MR_ATTR_STORE(hpa, set_hpa, u64, kstrtou64) 114 MR_ATTR_STORE(dpa, set_dpa, u64, kstrtou64) 115 MR_ATTR_STORE(nibble_mask, set_nibble_mask, unsigned long, kstrtoul) 116 MR_ATTR_STORE(bank_group, set_bank_group, unsigned long, kstrtoul) 117 MR_ATTR_STORE(bank, set_bank, unsigned long, kstrtoul) 118 MR_ATTR_STORE(rank, set_rank, unsigned long, kstrtoul) 119 MR_ATTR_STORE(row, set_row, unsigned long, kstrtoul) 120 MR_ATTR_STORE(column, set_column, unsigned long, kstrtoul) 121 MR_ATTR_STORE(channel, set_channel, unsigned long, kstrtoul) 122 MR_ATTR_STORE(sub_channel, set_sub_channel, unsigned long, kstrtoul) 123 124 #define MR_DO_OP(attrib, cb) \ 125 static ssize_t attrib##_store(struct device *ras_feat_dev, \ 126 struct device_attribute *attr, \ 127 const char *buf, size_t len) \ 128 { \ 129 u8 inst = TO_MR_DEV_ATTR(attr)->instance; \ 130 struct edac_dev_feat_ctx *ctx = dev_get_drvdata(ras_feat_dev); \ 131 const struct edac_mem_repair_ops *ops = ctx->mem_repair[inst].mem_repair_ops; \ 132 unsigned long data; \ 133 int ret; \ 134 \ 135 ret = kstrtoul(buf, 0, &data); \ 136 if (ret < 0) \ 137 return ret; \ 138 \ 139 ret = ops->cb(ras_feat_dev->parent, ctx->mem_repair[inst].private, data); \ 140 if (ret) \ 141 return ret; \ 142 \ 143 return len; \ 144 } 145 146 MR_DO_OP(repair, do_repair) 147 148 static umode_t mem_repair_attr_visible(struct kobject *kobj, struct attribute *a, int attr_id) 149 { 150 struct device *ras_feat_dev = kobj_to_dev(kobj); 151 struct device_attribute *dev_attr = container_of(a, struct device_attribute, attr); 152 struct edac_dev_feat_ctx *ctx = dev_get_drvdata(ras_feat_dev); 153 u8 inst = TO_MR_DEV_ATTR(dev_attr)->instance; 154 const struct edac_mem_repair_ops *ops = ctx->mem_repair[inst].mem_repair_ops; 155 156 switch (attr_id) { 157 case MR_TYPE: 158 if (ops->get_repair_type) 159 return a->mode; 160 break; 161 case MR_PERSIST_MODE: 162 if (ops->get_persist_mode) { 163 if (ops->set_persist_mode) 164 return a->mode; 165 else 166 return 0444; 167 } 168 break; 169 case MR_SAFE_IN_USE: 170 if (ops->get_repair_safe_when_in_use) 171 return a->mode; 172 break; 173 case MR_HPA: 174 if (ops->get_hpa) { 175 if (ops->set_hpa) 176 return a->mode; 177 else 178 return 0444; 179 } 180 break; 181 case MR_MIN_HPA: 182 if (ops->get_min_hpa) 183 return a->mode; 184 break; 185 case MR_MAX_HPA: 186 if (ops->get_max_hpa) 187 return a->mode; 188 break; 189 case MR_DPA: 190 if (ops->get_dpa) { 191 if (ops->set_dpa) 192 return a->mode; 193 else 194 return 0444; 195 } 196 break; 197 case MR_MIN_DPA: 198 if (ops->get_min_dpa) 199 return a->mode; 200 break; 201 case MR_MAX_DPA: 202 if (ops->get_max_dpa) 203 return a->mode; 204 break; 205 case MR_NIBBLE_MASK: 206 if (ops->get_nibble_mask) { 207 if (ops->set_nibble_mask) 208 return a->mode; 209 else 210 return 0444; 211 } 212 break; 213 case MR_BANK_GROUP: 214 if (ops->get_bank_group) { 215 if (ops->set_bank_group) 216 return a->mode; 217 else 218 return 0444; 219 } 220 break; 221 case MR_BANK: 222 if (ops->get_bank) { 223 if (ops->set_bank) 224 return a->mode; 225 else 226 return 0444; 227 } 228 break; 229 case MR_RANK: 230 if (ops->get_rank) { 231 if (ops->set_rank) 232 return a->mode; 233 else 234 return 0444; 235 } 236 break; 237 case MR_ROW: 238 if (ops->get_row) { 239 if (ops->set_row) 240 return a->mode; 241 else 242 return 0444; 243 } 244 break; 245 case MR_COLUMN: 246 if (ops->get_column) { 247 if (ops->set_column) 248 return a->mode; 249 else 250 return 0444; 251 } 252 break; 253 case MR_CHANNEL: 254 if (ops->get_channel) { 255 if (ops->set_channel) 256 return a->mode; 257 else 258 return 0444; 259 } 260 break; 261 case MR_SUB_CHANNEL: 262 if (ops->get_sub_channel) { 263 if (ops->set_sub_channel) 264 return a->mode; 265 else 266 return 0444; 267 } 268 break; 269 case MEM_DO_REPAIR: 270 if (ops->do_repair) 271 return a->mode; 272 break; 273 default: 274 break; 275 } 276 277 return 0; 278 } 279 280 #define MR_ATTR_RO(_name, _instance) \ 281 ((struct edac_mem_repair_dev_attr) { .dev_attr = __ATTR_RO(_name), \ 282 .instance = _instance }) 283 284 #define MR_ATTR_WO(_name, _instance) \ 285 ((struct edac_mem_repair_dev_attr) { .dev_attr = __ATTR_WO(_name), \ 286 .instance = _instance }) 287 288 #define MR_ATTR_RW(_name, _instance) \ 289 ((struct edac_mem_repair_dev_attr) { .dev_attr = __ATTR_RW(_name), \ 290 .instance = _instance }) 291 292 static int mem_repair_create_desc(struct device *dev, 293 const struct attribute_group **attr_groups, 294 u8 instance) 295 { 296 struct edac_mem_repair_context *ctx; 297 struct attribute_group *group; 298 int i; 299 struct edac_mem_repair_dev_attr dev_attr[] = { 300 [MR_TYPE] = MR_ATTR_RO(repair_type, instance), 301 [MR_PERSIST_MODE] = MR_ATTR_RW(persist_mode, instance), 302 [MR_SAFE_IN_USE] = MR_ATTR_RO(repair_safe_when_in_use, instance), 303 [MR_HPA] = MR_ATTR_RW(hpa, instance), 304 [MR_MIN_HPA] = MR_ATTR_RO(min_hpa, instance), 305 [MR_MAX_HPA] = MR_ATTR_RO(max_hpa, instance), 306 [MR_DPA] = MR_ATTR_RW(dpa, instance), 307 [MR_MIN_DPA] = MR_ATTR_RO(min_dpa, instance), 308 [MR_MAX_DPA] = MR_ATTR_RO(max_dpa, instance), 309 [MR_NIBBLE_MASK] = MR_ATTR_RW(nibble_mask, instance), 310 [MR_BANK_GROUP] = MR_ATTR_RW(bank_group, instance), 311 [MR_BANK] = MR_ATTR_RW(bank, instance), 312 [MR_RANK] = MR_ATTR_RW(rank, instance), 313 [MR_ROW] = MR_ATTR_RW(row, instance), 314 [MR_COLUMN] = MR_ATTR_RW(column, instance), 315 [MR_CHANNEL] = MR_ATTR_RW(channel, instance), 316 [MR_SUB_CHANNEL] = MR_ATTR_RW(sub_channel, instance), 317 [MEM_DO_REPAIR] = MR_ATTR_WO(repair, instance) 318 }; 319 320 ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); 321 if (!ctx) 322 return -ENOMEM; 323 324 for (i = 0; i < MR_MAX_ATTRS; i++) { 325 memcpy(&ctx->mem_repair_dev_attr[i], 326 &dev_attr[i], sizeof(dev_attr[i])); 327 ctx->mem_repair_attrs[i] = 328 &ctx->mem_repair_dev_attr[i].dev_attr.attr; 329 } 330 331 sprintf(ctx->name, "%s%d", "mem_repair", instance); 332 group = &ctx->group; 333 group->name = ctx->name; 334 group->attrs = ctx->mem_repair_attrs; 335 group->is_visible = mem_repair_attr_visible; 336 attr_groups[0] = group; 337 338 return 0; 339 } 340 341 /** 342 * edac_mem_repair_get_desc - get EDAC memory repair descriptors 343 * @dev: client device with memory repair feature 344 * @attr_groups: pointer to attribute group container 345 * @instance: device's memory repair instance number. 346 * 347 * Return: 348 * * %0 - Success. 349 * * %-EINVAL - Invalid parameters passed. 350 * * %-ENOMEM - Dynamic memory allocation failed. 351 */ 352 int edac_mem_repair_get_desc(struct device *dev, 353 const struct attribute_group **attr_groups, u8 instance) 354 { 355 if (!dev || !attr_groups) 356 return -EINVAL; 357 358 return mem_repair_create_desc(dev, attr_groups, instance); 359 } 360