xref: /linux/drivers/edac/mem_repair.c (revision c92bda4cb96970b78037d52cfae43844044744b1)
1699ea521SShiju Jose // SPDX-License-Identifier: GPL-2.0
2699ea521SShiju Jose /*
3699ea521SShiju Jose  * The generic EDAC memory repair driver is designed to control the memory
4699ea521SShiju Jose  * devices with memory repair features, such as Post Package Repair (PPR),
5699ea521SShiju Jose  * memory sparing etc. The common sysfs memory repair interface abstracts
6699ea521SShiju Jose  * the control of various arbitrary memory repair functionalities into a
7699ea521SShiju Jose  * unified set of functions.
8699ea521SShiju Jose  *
9699ea521SShiju Jose  * Copyright (c) 2024-2025 HiSilicon Limited.
10699ea521SShiju Jose  */
11699ea521SShiju Jose 
12699ea521SShiju Jose #include <linux/edac.h>
13699ea521SShiju Jose 
14699ea521SShiju Jose enum edac_mem_repair_attributes {
15699ea521SShiju Jose 	MR_TYPE,
16699ea521SShiju Jose 	MR_PERSIST_MODE,
17699ea521SShiju Jose 	MR_SAFE_IN_USE,
18699ea521SShiju Jose 	MR_HPA,
19699ea521SShiju Jose 	MR_MIN_HPA,
20699ea521SShiju Jose 	MR_MAX_HPA,
21699ea521SShiju Jose 	MR_DPA,
22699ea521SShiju Jose 	MR_MIN_DPA,
23699ea521SShiju Jose 	MR_MAX_DPA,
24699ea521SShiju Jose 	MR_NIBBLE_MASK,
2581e42fc1SShiju Jose 	MR_BANK_GROUP,
2681e42fc1SShiju Jose 	MR_BANK,
2781e42fc1SShiju Jose 	MR_RANK,
2881e42fc1SShiju Jose 	MR_ROW,
2981e42fc1SShiju Jose 	MR_COLUMN,
3081e42fc1SShiju Jose 	MR_CHANNEL,
3181e42fc1SShiju Jose 	MR_SUB_CHANNEL,
32699ea521SShiju Jose 	MEM_DO_REPAIR,
33699ea521SShiju Jose 	MR_MAX_ATTRS
34699ea521SShiju Jose };
35699ea521SShiju Jose 
36699ea521SShiju Jose struct edac_mem_repair_dev_attr {
37699ea521SShiju Jose 	struct device_attribute dev_attr;
38699ea521SShiju Jose 	u8 instance;
39699ea521SShiju Jose };
40699ea521SShiju Jose 
41699ea521SShiju Jose struct edac_mem_repair_context {
42699ea521SShiju Jose 	char name[EDAC_FEAT_NAME_LEN];
43699ea521SShiju Jose 	struct edac_mem_repair_dev_attr mem_repair_dev_attr[MR_MAX_ATTRS];
44699ea521SShiju Jose 	struct attribute *mem_repair_attrs[MR_MAX_ATTRS + 1];
45699ea521SShiju Jose 	struct attribute_group group;
46699ea521SShiju Jose };
47699ea521SShiju Jose 
48588ca944SShiju Jose const char * const edac_repair_type[] = {
49588ca944SShiju Jose 	[EDAC_REPAIR_PPR] = "ppr",
50588ca944SShiju Jose 	[EDAC_REPAIR_CACHELINE_SPARING] = "cacheline-sparing",
51588ca944SShiju Jose 	[EDAC_REPAIR_ROW_SPARING] = "row-sparing",
52588ca944SShiju Jose 	[EDAC_REPAIR_BANK_SPARING] = "bank-sparing",
53588ca944SShiju Jose 	[EDAC_REPAIR_RANK_SPARING] = "rank-sparing",
54588ca944SShiju Jose };
55588ca944SShiju Jose EXPORT_SYMBOL_GPL(edac_repair_type);
56588ca944SShiju Jose 
57699ea521SShiju Jose #define TO_MR_DEV_ATTR(_dev_attr)      \
58699ea521SShiju Jose 	container_of(_dev_attr, struct edac_mem_repair_dev_attr, dev_attr)
59699ea521SShiju Jose 
60699ea521SShiju Jose #define MR_ATTR_SHOW(attrib, cb, type, format)			\
61699ea521SShiju Jose static ssize_t attrib##_show(struct device *ras_feat_dev,			\
62699ea521SShiju Jose 			     struct device_attribute *attr, char *buf)		\
63699ea521SShiju Jose {										\
64699ea521SShiju Jose 	u8 inst = TO_MR_DEV_ATTR(attr)->instance;			\
65699ea521SShiju Jose 	struct edac_dev_feat_ctx *ctx = dev_get_drvdata(ras_feat_dev);		\
66699ea521SShiju Jose 	const struct edac_mem_repair_ops *ops =					\
67699ea521SShiju Jose 		ctx->mem_repair[inst].mem_repair_ops;				\
68699ea521SShiju Jose 	type data;								\
69699ea521SShiju Jose 	int ret;								\
70699ea521SShiju Jose 										\
71699ea521SShiju Jose 	ret = ops->cb(ras_feat_dev->parent, ctx->mem_repair[inst].private,	\
72699ea521SShiju Jose 		      &data);							\
73699ea521SShiju Jose 	if (ret)								\
74699ea521SShiju Jose 		return ret;							\
75699ea521SShiju Jose 										\
76699ea521SShiju Jose 	return sysfs_emit(buf, format, data);					\
77699ea521SShiju Jose }
78699ea521SShiju Jose 
79699ea521SShiju Jose MR_ATTR_SHOW(repair_type, get_repair_type, const char *, "%s\n")
80699ea521SShiju Jose MR_ATTR_SHOW(persist_mode, get_persist_mode, bool, "%u\n")
81699ea521SShiju Jose MR_ATTR_SHOW(repair_safe_when_in_use, get_repair_safe_when_in_use, bool, "%u\n")
82699ea521SShiju Jose MR_ATTR_SHOW(hpa, get_hpa, u64, "0x%llx\n")
83699ea521SShiju Jose MR_ATTR_SHOW(min_hpa, get_min_hpa, u64, "0x%llx\n")
84699ea521SShiju Jose MR_ATTR_SHOW(max_hpa, get_max_hpa, u64, "0x%llx\n")
85699ea521SShiju Jose MR_ATTR_SHOW(dpa, get_dpa, u64, "0x%llx\n")
86699ea521SShiju Jose MR_ATTR_SHOW(min_dpa, get_min_dpa, u64, "0x%llx\n")
87699ea521SShiju Jose MR_ATTR_SHOW(max_dpa, get_max_dpa, u64, "0x%llx\n")
88699ea521SShiju Jose MR_ATTR_SHOW(nibble_mask, get_nibble_mask, u32, "0x%x\n")
8981e42fc1SShiju Jose MR_ATTR_SHOW(bank_group, get_bank_group, u32, "%u\n")
9081e42fc1SShiju Jose MR_ATTR_SHOW(bank, get_bank, u32, "%u\n")
9181e42fc1SShiju Jose MR_ATTR_SHOW(rank, get_rank, u32, "%u\n")
9281e42fc1SShiju Jose MR_ATTR_SHOW(row, get_row, u32, "0x%x\n")
9381e42fc1SShiju Jose MR_ATTR_SHOW(column, get_column, u32, "%u\n")
9481e42fc1SShiju Jose MR_ATTR_SHOW(channel, get_channel, u32, "%u\n")
9581e42fc1SShiju Jose MR_ATTR_SHOW(sub_channel, get_sub_channel, u32, "%u\n")
96699ea521SShiju Jose 
97699ea521SShiju Jose #define MR_ATTR_STORE(attrib, cb, type, conv_func)			\
98699ea521SShiju Jose static ssize_t attrib##_store(struct device *ras_feat_dev,			\
99699ea521SShiju Jose 			      struct device_attribute *attr,			\
100699ea521SShiju Jose 			      const char *buf, size_t len)			\
101699ea521SShiju Jose {										\
102699ea521SShiju Jose 	u8 inst = TO_MR_DEV_ATTR(attr)->instance;			\
103699ea521SShiju Jose 	struct edac_dev_feat_ctx *ctx = dev_get_drvdata(ras_feat_dev);		\
104699ea521SShiju Jose 	const struct edac_mem_repair_ops *ops =					\
105699ea521SShiju Jose 		ctx->mem_repair[inst].mem_repair_ops;				\
106699ea521SShiju Jose 	type data;								\
107699ea521SShiju Jose 	int ret;								\
108699ea521SShiju Jose 										\
109699ea521SShiju Jose 	ret = conv_func(buf, 0, &data);						\
110699ea521SShiju Jose 	if (ret < 0)								\
111699ea521SShiju Jose 		return ret;							\
112699ea521SShiju Jose 										\
113699ea521SShiju Jose 	ret = ops->cb(ras_feat_dev->parent, ctx->mem_repair[inst].private,	\
114699ea521SShiju Jose 		      data);							\
115699ea521SShiju Jose 	if (ret)								\
116699ea521SShiju Jose 		return ret;							\
117699ea521SShiju Jose 										\
118699ea521SShiju Jose 	return len;								\
119699ea521SShiju Jose }
120699ea521SShiju Jose 
MR_ATTR_STORE(persist_mode,set_persist_mode,unsigned long,kstrtoul)121699ea521SShiju Jose MR_ATTR_STORE(persist_mode, set_persist_mode, unsigned long, kstrtoul)
122699ea521SShiju Jose MR_ATTR_STORE(hpa, set_hpa, u64, kstrtou64)
123699ea521SShiju Jose MR_ATTR_STORE(dpa, set_dpa, u64, kstrtou64)
124699ea521SShiju Jose MR_ATTR_STORE(nibble_mask, set_nibble_mask, unsigned long, kstrtoul)
12581e42fc1SShiju Jose MR_ATTR_STORE(bank_group, set_bank_group, unsigned long, kstrtoul)
12681e42fc1SShiju Jose MR_ATTR_STORE(bank, set_bank, unsigned long, kstrtoul)
12781e42fc1SShiju Jose MR_ATTR_STORE(rank, set_rank, unsigned long, kstrtoul)
12881e42fc1SShiju Jose MR_ATTR_STORE(row, set_row, unsigned long, kstrtoul)
12981e42fc1SShiju Jose MR_ATTR_STORE(column, set_column, unsigned long, kstrtoul)
13081e42fc1SShiju Jose MR_ATTR_STORE(channel, set_channel, unsigned long, kstrtoul)
13181e42fc1SShiju Jose MR_ATTR_STORE(sub_channel, set_sub_channel, unsigned long, kstrtoul)
132699ea521SShiju Jose 
133699ea521SShiju Jose #define MR_DO_OP(attrib, cb)						\
134699ea521SShiju Jose static ssize_t attrib##_store(struct device *ras_feat_dev,				\
135699ea521SShiju Jose 			      struct device_attribute *attr,				\
136699ea521SShiju Jose 			      const char *buf, size_t len)				\
137699ea521SShiju Jose {											\
138699ea521SShiju Jose 	u8 inst = TO_MR_DEV_ATTR(attr)->instance;				\
139699ea521SShiju Jose 	struct edac_dev_feat_ctx *ctx = dev_get_drvdata(ras_feat_dev);			\
140699ea521SShiju Jose 	const struct edac_mem_repair_ops *ops = ctx->mem_repair[inst].mem_repair_ops;	\
141699ea521SShiju Jose 	unsigned long data;								\
142699ea521SShiju Jose 	int ret;									\
143699ea521SShiju Jose 											\
144699ea521SShiju Jose 	ret = kstrtoul(buf, 0, &data);							\
145699ea521SShiju Jose 	if (ret < 0)									\
146699ea521SShiju Jose 		return ret;								\
147699ea521SShiju Jose 											\
148699ea521SShiju Jose 	ret = ops->cb(ras_feat_dev->parent, ctx->mem_repair[inst].private, data);	\
149699ea521SShiju Jose 	if (ret)									\
150699ea521SShiju Jose 		return ret;								\
151699ea521SShiju Jose 											\
152699ea521SShiju Jose 	return len;									\
153699ea521SShiju Jose }
154699ea521SShiju Jose 
155699ea521SShiju Jose MR_DO_OP(repair, do_repair)
156699ea521SShiju Jose 
157699ea521SShiju Jose static umode_t mem_repair_attr_visible(struct kobject *kobj, struct attribute *a, int attr_id)
158699ea521SShiju Jose {
159699ea521SShiju Jose 	struct device *ras_feat_dev = kobj_to_dev(kobj);
160699ea521SShiju Jose 	struct device_attribute *dev_attr = container_of(a, struct device_attribute, attr);
161699ea521SShiju Jose 	struct edac_dev_feat_ctx *ctx = dev_get_drvdata(ras_feat_dev);
162699ea521SShiju Jose 	u8 inst = TO_MR_DEV_ATTR(dev_attr)->instance;
163699ea521SShiju Jose 	const struct edac_mem_repair_ops *ops = ctx->mem_repair[inst].mem_repair_ops;
164699ea521SShiju Jose 
165699ea521SShiju Jose 	switch (attr_id) {
166699ea521SShiju Jose 	case MR_TYPE:
167699ea521SShiju Jose 		if (ops->get_repair_type)
168699ea521SShiju Jose 			return a->mode;
169699ea521SShiju Jose 		break;
170699ea521SShiju Jose 	case MR_PERSIST_MODE:
171699ea521SShiju Jose 		if (ops->get_persist_mode) {
172699ea521SShiju Jose 			if (ops->set_persist_mode)
173699ea521SShiju Jose 				return a->mode;
174699ea521SShiju Jose 			else
175699ea521SShiju Jose 				return 0444;
176699ea521SShiju Jose 		}
177699ea521SShiju Jose 		break;
178699ea521SShiju Jose 	case MR_SAFE_IN_USE:
179699ea521SShiju Jose 		if (ops->get_repair_safe_when_in_use)
180699ea521SShiju Jose 			return a->mode;
181699ea521SShiju Jose 		break;
182699ea521SShiju Jose 	case MR_HPA:
183699ea521SShiju Jose 		if (ops->get_hpa) {
184699ea521SShiju Jose 			if (ops->set_hpa)
185699ea521SShiju Jose 				return a->mode;
186699ea521SShiju Jose 			else
187699ea521SShiju Jose 				return 0444;
188699ea521SShiju Jose 		}
189699ea521SShiju Jose 		break;
190699ea521SShiju Jose 	case MR_MIN_HPA:
191699ea521SShiju Jose 		if (ops->get_min_hpa)
192699ea521SShiju Jose 			return a->mode;
193699ea521SShiju Jose 		break;
194699ea521SShiju Jose 	case MR_MAX_HPA:
195699ea521SShiju Jose 		if (ops->get_max_hpa)
196699ea521SShiju Jose 			return a->mode;
197699ea521SShiju Jose 		break;
198699ea521SShiju Jose 	case MR_DPA:
199699ea521SShiju Jose 		if (ops->get_dpa) {
200699ea521SShiju Jose 			if (ops->set_dpa)
201699ea521SShiju Jose 				return a->mode;
202699ea521SShiju Jose 			else
203699ea521SShiju Jose 				return 0444;
204699ea521SShiju Jose 		}
205699ea521SShiju Jose 		break;
206699ea521SShiju Jose 	case MR_MIN_DPA:
207699ea521SShiju Jose 		if (ops->get_min_dpa)
208699ea521SShiju Jose 			return a->mode;
209699ea521SShiju Jose 		break;
210699ea521SShiju Jose 	case MR_MAX_DPA:
211699ea521SShiju Jose 		if (ops->get_max_dpa)
212699ea521SShiju Jose 			return a->mode;
213699ea521SShiju Jose 		break;
214699ea521SShiju Jose 	case MR_NIBBLE_MASK:
215699ea521SShiju Jose 		if (ops->get_nibble_mask) {
216699ea521SShiju Jose 			if (ops->set_nibble_mask)
217699ea521SShiju Jose 				return a->mode;
218699ea521SShiju Jose 			else
219699ea521SShiju Jose 				return 0444;
220699ea521SShiju Jose 		}
221699ea521SShiju Jose 		break;
22281e42fc1SShiju Jose 	case MR_BANK_GROUP:
22381e42fc1SShiju Jose 		if (ops->get_bank_group) {
22481e42fc1SShiju Jose 			if (ops->set_bank_group)
22581e42fc1SShiju Jose 				return a->mode;
22681e42fc1SShiju Jose 			else
22781e42fc1SShiju Jose 				return 0444;
22881e42fc1SShiju Jose 		}
22981e42fc1SShiju Jose 		break;
23081e42fc1SShiju Jose 	case MR_BANK:
23181e42fc1SShiju Jose 		if (ops->get_bank) {
23281e42fc1SShiju Jose 			if (ops->set_bank)
23381e42fc1SShiju Jose 				return a->mode;
23481e42fc1SShiju Jose 			else
23581e42fc1SShiju Jose 				return 0444;
23681e42fc1SShiju Jose 		}
23781e42fc1SShiju Jose 		break;
23881e42fc1SShiju Jose 	case MR_RANK:
23981e42fc1SShiju Jose 		if (ops->get_rank) {
24081e42fc1SShiju Jose 			if (ops->set_rank)
24181e42fc1SShiju Jose 				return a->mode;
24281e42fc1SShiju Jose 			else
24381e42fc1SShiju Jose 				return 0444;
24481e42fc1SShiju Jose 		}
24581e42fc1SShiju Jose 		break;
24681e42fc1SShiju Jose 	case MR_ROW:
24781e42fc1SShiju Jose 		if (ops->get_row) {
24881e42fc1SShiju Jose 			if (ops->set_row)
24981e42fc1SShiju Jose 				return a->mode;
25081e42fc1SShiju Jose 			else
25181e42fc1SShiju Jose 				return 0444;
25281e42fc1SShiju Jose 		}
25381e42fc1SShiju Jose 		break;
25481e42fc1SShiju Jose 	case MR_COLUMN:
25581e42fc1SShiju Jose 		if (ops->get_column) {
25681e42fc1SShiju Jose 			if (ops->set_column)
25781e42fc1SShiju Jose 				return a->mode;
25881e42fc1SShiju Jose 			else
25981e42fc1SShiju Jose 				return 0444;
26081e42fc1SShiju Jose 		}
26181e42fc1SShiju Jose 		break;
26281e42fc1SShiju Jose 	case MR_CHANNEL:
26381e42fc1SShiju Jose 		if (ops->get_channel) {
26481e42fc1SShiju Jose 			if (ops->set_channel)
26581e42fc1SShiju Jose 				return a->mode;
26681e42fc1SShiju Jose 			else
26781e42fc1SShiju Jose 				return 0444;
26881e42fc1SShiju Jose 		}
26981e42fc1SShiju Jose 		break;
27081e42fc1SShiju Jose 	case MR_SUB_CHANNEL:
27181e42fc1SShiju Jose 		if (ops->get_sub_channel) {
27281e42fc1SShiju Jose 			if (ops->set_sub_channel)
27381e42fc1SShiju Jose 				return a->mode;
27481e42fc1SShiju Jose 			else
27581e42fc1SShiju Jose 				return 0444;
27681e42fc1SShiju Jose 		}
27781e42fc1SShiju Jose 		break;
278699ea521SShiju Jose 	case MEM_DO_REPAIR:
279699ea521SShiju Jose 		if (ops->do_repair)
280699ea521SShiju Jose 			return a->mode;
281699ea521SShiju Jose 		break;
282699ea521SShiju Jose 	default:
283699ea521SShiju Jose 		break;
284699ea521SShiju Jose 	}
285699ea521SShiju Jose 
286699ea521SShiju Jose 	return 0;
287699ea521SShiju Jose }
288699ea521SShiju Jose 
289699ea521SShiju Jose #define MR_ATTR_RO(_name, _instance)       \
290699ea521SShiju Jose 	((struct edac_mem_repair_dev_attr) { .dev_attr = __ATTR_RO(_name), \
291699ea521SShiju Jose 					     .instance = _instance })
292699ea521SShiju Jose 
293699ea521SShiju Jose #define MR_ATTR_WO(_name, _instance)       \
294699ea521SShiju Jose 	((struct edac_mem_repair_dev_attr) { .dev_attr = __ATTR_WO(_name), \
295699ea521SShiju Jose 					     .instance = _instance })
296699ea521SShiju Jose 
297699ea521SShiju Jose #define MR_ATTR_RW(_name, _instance)       \
298699ea521SShiju Jose 	((struct edac_mem_repair_dev_attr) { .dev_attr = __ATTR_RW(_name), \
299699ea521SShiju Jose 					     .instance = _instance })
300699ea521SShiju Jose 
mem_repair_create_desc(struct device * dev,const struct attribute_group ** attr_groups,u8 instance)301699ea521SShiju Jose static int mem_repair_create_desc(struct device *dev,
302699ea521SShiju Jose 				  const struct attribute_group **attr_groups,
303699ea521SShiju Jose 				  u8 instance)
304699ea521SShiju Jose {
305699ea521SShiju Jose 	struct edac_mem_repair_context *ctx;
306699ea521SShiju Jose 	struct attribute_group *group;
307699ea521SShiju Jose 	int i;
308699ea521SShiju Jose 	struct edac_mem_repair_dev_attr dev_attr[] = {
309699ea521SShiju Jose 		[MR_TYPE]	  = MR_ATTR_RO(repair_type, instance),
310699ea521SShiju Jose 		[MR_PERSIST_MODE] = MR_ATTR_RW(persist_mode, instance),
311699ea521SShiju Jose 		[MR_SAFE_IN_USE]  = MR_ATTR_RO(repair_safe_when_in_use, instance),
312699ea521SShiju Jose 		[MR_HPA]	  = MR_ATTR_RW(hpa, instance),
313699ea521SShiju Jose 		[MR_MIN_HPA]	  = MR_ATTR_RO(min_hpa, instance),
314699ea521SShiju Jose 		[MR_MAX_HPA]	  = MR_ATTR_RO(max_hpa, instance),
315699ea521SShiju Jose 		[MR_DPA]	  = MR_ATTR_RW(dpa, instance),
316699ea521SShiju Jose 		[MR_MIN_DPA]	  = MR_ATTR_RO(min_dpa, instance),
317699ea521SShiju Jose 		[MR_MAX_DPA]	  = MR_ATTR_RO(max_dpa, instance),
318699ea521SShiju Jose 		[MR_NIBBLE_MASK]  = MR_ATTR_RW(nibble_mask, instance),
31981e42fc1SShiju Jose 		[MR_BANK_GROUP]   = MR_ATTR_RW(bank_group, instance),
32081e42fc1SShiju Jose 		[MR_BANK]	  = MR_ATTR_RW(bank, instance),
32181e42fc1SShiju Jose 		[MR_RANK]	  = MR_ATTR_RW(rank, instance),
32281e42fc1SShiju Jose 		[MR_ROW]	  = MR_ATTR_RW(row, instance),
32381e42fc1SShiju Jose 		[MR_COLUMN]	  = MR_ATTR_RW(column, instance),
32481e42fc1SShiju Jose 		[MR_CHANNEL]	  = MR_ATTR_RW(channel, instance),
32581e42fc1SShiju Jose 		[MR_SUB_CHANNEL]  = MR_ATTR_RW(sub_channel, instance),
326699ea521SShiju Jose 		[MEM_DO_REPAIR]	  = MR_ATTR_WO(repair, instance)
327699ea521SShiju Jose 	};
328699ea521SShiju Jose 
329699ea521SShiju Jose 	ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
330699ea521SShiju Jose 	if (!ctx)
331699ea521SShiju Jose 		return -ENOMEM;
332699ea521SShiju Jose 
333699ea521SShiju Jose 	for (i = 0; i < MR_MAX_ATTRS; i++) {
334699ea521SShiju Jose 		memcpy(&ctx->mem_repair_dev_attr[i],
335699ea521SShiju Jose 		       &dev_attr[i], sizeof(dev_attr[i]));
336*1e14ea90SShiju Jose 		sysfs_attr_init(&ctx->mem_repair_dev_attr[i].dev_attr.attr);
337699ea521SShiju Jose 		ctx->mem_repair_attrs[i] =
338699ea521SShiju Jose 			&ctx->mem_repair_dev_attr[i].dev_attr.attr;
339699ea521SShiju Jose 	}
340699ea521SShiju Jose 
341699ea521SShiju Jose 	sprintf(ctx->name, "%s%d", "mem_repair", instance);
342699ea521SShiju Jose 	group = &ctx->group;
343699ea521SShiju Jose 	group->name = ctx->name;
344699ea521SShiju Jose 	group->attrs = ctx->mem_repair_attrs;
345699ea521SShiju Jose 	group->is_visible  = mem_repair_attr_visible;
346699ea521SShiju Jose 	attr_groups[0] = group;
347699ea521SShiju Jose 
348699ea521SShiju Jose 	return 0;
349699ea521SShiju Jose }
350699ea521SShiju Jose 
351699ea521SShiju Jose /**
352699ea521SShiju Jose  * edac_mem_repair_get_desc - get EDAC memory repair descriptors
353699ea521SShiju Jose  * @dev: client device with memory repair feature
354699ea521SShiju Jose  * @attr_groups: pointer to attribute group container
355699ea521SShiju Jose  * @instance: device's memory repair instance number.
356699ea521SShiju Jose  *
357699ea521SShiju Jose  * Return:
358699ea521SShiju Jose  *  * %0	- Success.
359699ea521SShiju Jose  *  * %-EINVAL	- Invalid parameters passed.
360699ea521SShiju Jose  *  * %-ENOMEM	- Dynamic memory allocation failed.
361699ea521SShiju Jose  */
edac_mem_repair_get_desc(struct device * dev,const struct attribute_group ** attr_groups,u8 instance)362699ea521SShiju Jose int edac_mem_repair_get_desc(struct device *dev,
363699ea521SShiju Jose 			     const struct attribute_group **attr_groups, u8 instance)
364699ea521SShiju Jose {
365699ea521SShiju Jose 	if (!dev || !attr_groups)
366699ea521SShiju Jose 		return -EINVAL;
367699ea521SShiju Jose 
368699ea521SShiju Jose 	return mem_repair_create_desc(dev, attr_groups, instance);
369699ea521SShiju Jose }
370