xref: /linux/drivers/misc/cxl/sysfs.c (revision b6c84ba22ff3a198eb8d5552cf9b8fda1d792e54)
1f204e0b8SIan Munsie /*
2f204e0b8SIan Munsie  * Copyright 2014 IBM Corp.
3f204e0b8SIan Munsie  *
4f204e0b8SIan Munsie  * This program is free software; you can redistribute it and/or
5f204e0b8SIan Munsie  * modify it under the terms of the GNU General Public License
6f204e0b8SIan Munsie  * as published by the Free Software Foundation; either version
7f204e0b8SIan Munsie  * 2 of the License, or (at your option) any later version.
8f204e0b8SIan Munsie  */
9f204e0b8SIan Munsie 
10f204e0b8SIan Munsie #include <linux/kernel.h>
11f204e0b8SIan Munsie #include <linux/device.h>
12f204e0b8SIan Munsie #include <linux/sysfs.h>
13b087e619SIan Munsie #include <linux/pci_regs.h>
14f204e0b8SIan Munsie 
15f204e0b8SIan Munsie #include "cxl.h"
16f204e0b8SIan Munsie 
17f204e0b8SIan Munsie #define to_afu_chardev_m(d) dev_get_drvdata(d)
18f204e0b8SIan Munsie 
19f204e0b8SIan Munsie /*********  Adapter attributes  **********************************************/
20f204e0b8SIan Munsie 
21f204e0b8SIan Munsie static ssize_t caia_version_show(struct device *device,
22f204e0b8SIan Munsie 				 struct device_attribute *attr,
23f204e0b8SIan Munsie 				 char *buf)
24f204e0b8SIan Munsie {
25f204e0b8SIan Munsie 	struct cxl *adapter = to_cxl_adapter(device);
26f204e0b8SIan Munsie 
27f204e0b8SIan Munsie 	return scnprintf(buf, PAGE_SIZE, "%i.%i\n", adapter->caia_major,
28f204e0b8SIan Munsie 			 adapter->caia_minor);
29f204e0b8SIan Munsie }
30f204e0b8SIan Munsie 
31f204e0b8SIan Munsie static ssize_t psl_revision_show(struct device *device,
32f204e0b8SIan Munsie 				 struct device_attribute *attr,
33f204e0b8SIan Munsie 				 char *buf)
34f204e0b8SIan Munsie {
35f204e0b8SIan Munsie 	struct cxl *adapter = to_cxl_adapter(device);
36f204e0b8SIan Munsie 
37f204e0b8SIan Munsie 	return scnprintf(buf, PAGE_SIZE, "%i\n", adapter->psl_rev);
38f204e0b8SIan Munsie }
39f204e0b8SIan Munsie 
40f204e0b8SIan Munsie static ssize_t base_image_show(struct device *device,
41f204e0b8SIan Munsie 			       struct device_attribute *attr,
42f204e0b8SIan Munsie 			       char *buf)
43f204e0b8SIan Munsie {
44f204e0b8SIan Munsie 	struct cxl *adapter = to_cxl_adapter(device);
45f204e0b8SIan Munsie 
46f204e0b8SIan Munsie 	return scnprintf(buf, PAGE_SIZE, "%i\n", adapter->base_image);
47f204e0b8SIan Munsie }
48f204e0b8SIan Munsie 
49f204e0b8SIan Munsie static ssize_t image_loaded_show(struct device *device,
50f204e0b8SIan Munsie 				 struct device_attribute *attr,
51f204e0b8SIan Munsie 				 char *buf)
52f204e0b8SIan Munsie {
53f204e0b8SIan Munsie 	struct cxl *adapter = to_cxl_adapter(device);
54f204e0b8SIan Munsie 
55f204e0b8SIan Munsie 	if (adapter->user_image_loaded)
56f204e0b8SIan Munsie 		return scnprintf(buf, PAGE_SIZE, "user\n");
57f204e0b8SIan Munsie 	return scnprintf(buf, PAGE_SIZE, "factory\n");
58f204e0b8SIan Munsie }
59f204e0b8SIan Munsie 
60e009a7e8SFrederic Barrat static ssize_t psl_timebase_synced_show(struct device *device,
61e009a7e8SFrederic Barrat 					struct device_attribute *attr,
62e009a7e8SFrederic Barrat 					char *buf)
63e009a7e8SFrederic Barrat {
64e009a7e8SFrederic Barrat 	struct cxl *adapter = to_cxl_adapter(device);
65c2be663dSChristophe Lombard 	u64 psl_tb, delta;
66e009a7e8SFrederic Barrat 
67c2be663dSChristophe Lombard 	/* Recompute the status only in native mode */
68c2be663dSChristophe Lombard 	if (cpu_has_feature(CPU_FTR_HVMODE)) {
69c2be663dSChristophe Lombard 		psl_tb = adapter->native->sl_ops->timebase_read(adapter);
70c2be663dSChristophe Lombard 		delta = abs(mftb() - psl_tb);
71c2be663dSChristophe Lombard 
72c2be663dSChristophe Lombard 		/* CORE TB and PSL TB difference <= 16usecs ? */
73c2be663dSChristophe Lombard 		adapter->psl_timebase_synced = (tb_to_ns(delta) < 16000) ? true : false;
74c2be663dSChristophe Lombard 		pr_devel("PSL timebase %s - delta: 0x%016llx\n",
75c2be663dSChristophe Lombard 			 (tb_to_ns(delta) < 16000) ? "synchronized" :
76c2be663dSChristophe Lombard 			 "not synchronized", tb_to_ns(delta));
77c2be663dSChristophe Lombard 	}
78e009a7e8SFrederic Barrat 	return scnprintf(buf, PAGE_SIZE, "%i\n", adapter->psl_timebase_synced);
79e009a7e8SFrederic Barrat }
80e009a7e8SFrederic Barrat 
8162fa19d4SRyan Grimm static ssize_t reset_adapter_store(struct device *device,
8262fa19d4SRyan Grimm 				   struct device_attribute *attr,
8362fa19d4SRyan Grimm 				   const char *buf, size_t count)
8462fa19d4SRyan Grimm {
8562fa19d4SRyan Grimm 	struct cxl *adapter = to_cxl_adapter(device);
8662fa19d4SRyan Grimm 	int rc;
8762fa19d4SRyan Grimm 	int val;
8862fa19d4SRyan Grimm 
8962fa19d4SRyan Grimm 	rc = sscanf(buf, "%i", &val);
9070b565bbSVaibhav Jain 	if ((rc != 1) || (val != 1 && val != -1))
9162fa19d4SRyan Grimm 		return -EINVAL;
9262fa19d4SRyan Grimm 
9370b565bbSVaibhav Jain 	/*
9470b565bbSVaibhav Jain 	 * See if we can lock the context mapping that's only allowed
9570b565bbSVaibhav Jain 	 * when there are no contexts attached to the adapter. Once
9670b565bbSVaibhav Jain 	 * taken this will also prevent any context from getting activated.
9770b565bbSVaibhav Jain 	 */
9870b565bbSVaibhav Jain 	if (val == 1) {
9970b565bbSVaibhav Jain 		rc =  cxl_adapter_context_lock(adapter);
10070b565bbSVaibhav Jain 		if (rc)
10170b565bbSVaibhav Jain 			goto out;
10270b565bbSVaibhav Jain 
10370b565bbSVaibhav Jain 		rc = cxl_ops->adapter_reset(adapter);
10470b565bbSVaibhav Jain 		/* In case reset failed release context lock */
10570b565bbSVaibhav Jain 		if (rc)
10670b565bbSVaibhav Jain 			cxl_adapter_context_unlock(adapter);
10770b565bbSVaibhav Jain 
10870b565bbSVaibhav Jain 	} else if (val == -1) {
10970b565bbSVaibhav Jain 		/* Perform a forced adapter reset */
11070b565bbSVaibhav Jain 		rc = cxl_ops->adapter_reset(adapter);
11170b565bbSVaibhav Jain 	}
11270b565bbSVaibhav Jain 
11370b565bbSVaibhav Jain out:
11470b565bbSVaibhav Jain 	return rc ? rc : count;
11562fa19d4SRyan Grimm }
11662fa19d4SRyan Grimm 
11795bc11bcSRyan Grimm static ssize_t load_image_on_perst_show(struct device *device,
11895bc11bcSRyan Grimm 				 struct device_attribute *attr,
11995bc11bcSRyan Grimm 				 char *buf)
12095bc11bcSRyan Grimm {
12195bc11bcSRyan Grimm 	struct cxl *adapter = to_cxl_adapter(device);
12295bc11bcSRyan Grimm 
12395bc11bcSRyan Grimm 	if (!adapter->perst_loads_image)
12495bc11bcSRyan Grimm 		return scnprintf(buf, PAGE_SIZE, "none\n");
12595bc11bcSRyan Grimm 
12695bc11bcSRyan Grimm 	if (adapter->perst_select_user)
12795bc11bcSRyan Grimm 		return scnprintf(buf, PAGE_SIZE, "user\n");
12895bc11bcSRyan Grimm 	return scnprintf(buf, PAGE_SIZE, "factory\n");
12995bc11bcSRyan Grimm }
13095bc11bcSRyan Grimm 
13195bc11bcSRyan Grimm static ssize_t load_image_on_perst_store(struct device *device,
13295bc11bcSRyan Grimm 				 struct device_attribute *attr,
13395bc11bcSRyan Grimm 				 const char *buf, size_t count)
13495bc11bcSRyan Grimm {
13595bc11bcSRyan Grimm 	struct cxl *adapter = to_cxl_adapter(device);
13695bc11bcSRyan Grimm 	int rc;
13795bc11bcSRyan Grimm 
13895bc11bcSRyan Grimm 	if (!strncmp(buf, "none", 4))
13995bc11bcSRyan Grimm 		adapter->perst_loads_image = false;
14095bc11bcSRyan Grimm 	else if (!strncmp(buf, "user", 4)) {
14195bc11bcSRyan Grimm 		adapter->perst_select_user = true;
14295bc11bcSRyan Grimm 		adapter->perst_loads_image = true;
14395bc11bcSRyan Grimm 	} else if (!strncmp(buf, "factory", 7)) {
14495bc11bcSRyan Grimm 		adapter->perst_select_user = false;
14595bc11bcSRyan Grimm 		adapter->perst_loads_image = true;
14695bc11bcSRyan Grimm 	} else
14795bc11bcSRyan Grimm 		return -EINVAL;
14895bc11bcSRyan Grimm 
14995bc11bcSRyan Grimm 	if ((rc = cxl_update_image_control(adapter)))
15095bc11bcSRyan Grimm 		return rc;
15195bc11bcSRyan Grimm 
15295bc11bcSRyan Grimm 	return count;
15395bc11bcSRyan Grimm }
15495bc11bcSRyan Grimm 
15513e68d8bSDaniel Axtens static ssize_t perst_reloads_same_image_show(struct device *device,
15613e68d8bSDaniel Axtens 				 struct device_attribute *attr,
15713e68d8bSDaniel Axtens 				 char *buf)
15813e68d8bSDaniel Axtens {
15913e68d8bSDaniel Axtens 	struct cxl *adapter = to_cxl_adapter(device);
16013e68d8bSDaniel Axtens 
16113e68d8bSDaniel Axtens 	return scnprintf(buf, PAGE_SIZE, "%i\n", adapter->perst_same_image);
16213e68d8bSDaniel Axtens }
16313e68d8bSDaniel Axtens 
16413e68d8bSDaniel Axtens static ssize_t perst_reloads_same_image_store(struct device *device,
16513e68d8bSDaniel Axtens 				 struct device_attribute *attr,
16613e68d8bSDaniel Axtens 				 const char *buf, size_t count)
16713e68d8bSDaniel Axtens {
16813e68d8bSDaniel Axtens 	struct cxl *adapter = to_cxl_adapter(device);
16913e68d8bSDaniel Axtens 	int rc;
17013e68d8bSDaniel Axtens 	int val;
17113e68d8bSDaniel Axtens 
17213e68d8bSDaniel Axtens 	rc = sscanf(buf, "%i", &val);
17313e68d8bSDaniel Axtens 	if ((rc != 1) || !(val == 1 || val == 0))
17413e68d8bSDaniel Axtens 		return -EINVAL;
17513e68d8bSDaniel Axtens 
17613e68d8bSDaniel Axtens 	adapter->perst_same_image = (val == 1 ? true : false);
17713e68d8bSDaniel Axtens 	return count;
17813e68d8bSDaniel Axtens }
17913e68d8bSDaniel Axtens 
180f204e0b8SIan Munsie static struct device_attribute adapter_attrs[] = {
181f204e0b8SIan Munsie 	__ATTR_RO(caia_version),
182f204e0b8SIan Munsie 	__ATTR_RO(psl_revision),
183f204e0b8SIan Munsie 	__ATTR_RO(base_image),
184f204e0b8SIan Munsie 	__ATTR_RO(image_loaded),
185e009a7e8SFrederic Barrat 	__ATTR_RO(psl_timebase_synced),
18695bc11bcSRyan Grimm 	__ATTR_RW(load_image_on_perst),
18713e68d8bSDaniel Axtens 	__ATTR_RW(perst_reloads_same_image),
18862fa19d4SRyan Grimm 	__ATTR(reset, S_IWUSR, NULL, reset_adapter_store),
189f204e0b8SIan Munsie };
190f204e0b8SIan Munsie 
191f204e0b8SIan Munsie 
192f204e0b8SIan Munsie /*********  AFU master specific attributes  **********************************/
193f204e0b8SIan Munsie 
194f204e0b8SIan Munsie static ssize_t mmio_size_show_master(struct device *device,
195f204e0b8SIan Munsie 				     struct device_attribute *attr,
196f204e0b8SIan Munsie 				     char *buf)
197f204e0b8SIan Munsie {
198f204e0b8SIan Munsie 	struct cxl_afu *afu = to_afu_chardev_m(device);
199f204e0b8SIan Munsie 
200f204e0b8SIan Munsie 	return scnprintf(buf, PAGE_SIZE, "%llu\n", afu->adapter->ps_size);
201f204e0b8SIan Munsie }
202f204e0b8SIan Munsie 
203f204e0b8SIan Munsie static ssize_t pp_mmio_off_show(struct device *device,
204f204e0b8SIan Munsie 				struct device_attribute *attr,
205f204e0b8SIan Munsie 				char *buf)
206f204e0b8SIan Munsie {
207f204e0b8SIan Munsie 	struct cxl_afu *afu = to_afu_chardev_m(device);
208f204e0b8SIan Munsie 
209cbffa3a5SChristophe Lombard 	return scnprintf(buf, PAGE_SIZE, "%llu\n", afu->native->pp_offset);
210f204e0b8SIan Munsie }
211f204e0b8SIan Munsie 
212f204e0b8SIan Munsie static ssize_t pp_mmio_len_show(struct device *device,
213f204e0b8SIan Munsie 				struct device_attribute *attr,
214f204e0b8SIan Munsie 				char *buf)
215f204e0b8SIan Munsie {
216f204e0b8SIan Munsie 	struct cxl_afu *afu = to_afu_chardev_m(device);
217f204e0b8SIan Munsie 
218f204e0b8SIan Munsie 	return scnprintf(buf, PAGE_SIZE, "%llu\n", afu->pp_size);
219f204e0b8SIan Munsie }
220f204e0b8SIan Munsie 
221f204e0b8SIan Munsie static struct device_attribute afu_master_attrs[] = {
222f204e0b8SIan Munsie 	__ATTR(mmio_size, S_IRUGO, mmio_size_show_master, NULL),
223f204e0b8SIan Munsie 	__ATTR_RO(pp_mmio_off),
224f204e0b8SIan Munsie 	__ATTR_RO(pp_mmio_len),
225f204e0b8SIan Munsie };
226f204e0b8SIan Munsie 
227f204e0b8SIan Munsie 
228f204e0b8SIan Munsie /*********  AFU attributes  **************************************************/
229f204e0b8SIan Munsie 
230f204e0b8SIan Munsie static ssize_t mmio_size_show(struct device *device,
231f204e0b8SIan Munsie 			      struct device_attribute *attr,
232f204e0b8SIan Munsie 			      char *buf)
233f204e0b8SIan Munsie {
234f204e0b8SIan Munsie 	struct cxl_afu *afu = to_cxl_afu(device);
235f204e0b8SIan Munsie 
236f204e0b8SIan Munsie 	if (afu->pp_size)
237f204e0b8SIan Munsie 		return scnprintf(buf, PAGE_SIZE, "%llu\n", afu->pp_size);
238f204e0b8SIan Munsie 	return scnprintf(buf, PAGE_SIZE, "%llu\n", afu->adapter->ps_size);
239f204e0b8SIan Munsie }
240f204e0b8SIan Munsie 
241f204e0b8SIan Munsie static ssize_t reset_store_afu(struct device *device,
242f204e0b8SIan Munsie 			       struct device_attribute *attr,
243f204e0b8SIan Munsie 			       const char *buf, size_t count)
244f204e0b8SIan Munsie {
245f204e0b8SIan Munsie 	struct cxl_afu *afu = to_cxl_afu(device);
246f204e0b8SIan Munsie 	int rc;
247f204e0b8SIan Munsie 
248f204e0b8SIan Munsie 	/* Not safe to reset if it is currently in use */
249ee41d11dSIan Munsie 	mutex_lock(&afu->contexts_lock);
250f204e0b8SIan Munsie 	if (!idr_is_empty(&afu->contexts_idr)) {
251f204e0b8SIan Munsie 		rc = -EBUSY;
252f204e0b8SIan Munsie 		goto err;
253f204e0b8SIan Munsie 	}
254f204e0b8SIan Munsie 
2555be587b1SFrederic Barrat 	if ((rc = cxl_ops->afu_reset(afu)))
256f204e0b8SIan Munsie 		goto err;
257f204e0b8SIan Munsie 
258f204e0b8SIan Munsie 	rc = count;
259f204e0b8SIan Munsie err:
260ee41d11dSIan Munsie 	mutex_unlock(&afu->contexts_lock);
261f204e0b8SIan Munsie 	return rc;
262f204e0b8SIan Munsie }
263f204e0b8SIan Munsie 
264f204e0b8SIan Munsie static ssize_t irqs_min_show(struct device *device,
265f204e0b8SIan Munsie 			     struct device_attribute *attr,
266f204e0b8SIan Munsie 			     char *buf)
267f204e0b8SIan Munsie {
268f204e0b8SIan Munsie 	struct cxl_afu *afu = to_cxl_afu(device);
269f204e0b8SIan Munsie 
270f204e0b8SIan Munsie 	return scnprintf(buf, PAGE_SIZE, "%i\n", afu->pp_irqs);
271f204e0b8SIan Munsie }
272f204e0b8SIan Munsie 
273f204e0b8SIan Munsie static ssize_t irqs_max_show(struct device *device,
274f204e0b8SIan Munsie 				  struct device_attribute *attr,
275f204e0b8SIan Munsie 				  char *buf)
276f204e0b8SIan Munsie {
277f204e0b8SIan Munsie 	struct cxl_afu *afu = to_cxl_afu(device);
278f204e0b8SIan Munsie 
279f204e0b8SIan Munsie 	return scnprintf(buf, PAGE_SIZE, "%i\n", afu->irqs_max);
280f204e0b8SIan Munsie }
281f204e0b8SIan Munsie 
282f204e0b8SIan Munsie static ssize_t irqs_max_store(struct device *device,
283f204e0b8SIan Munsie 				  struct device_attribute *attr,
284f204e0b8SIan Munsie 				  const char *buf, size_t count)
285f204e0b8SIan Munsie {
286f204e0b8SIan Munsie 	struct cxl_afu *afu = to_cxl_afu(device);
287f204e0b8SIan Munsie 	ssize_t ret;
288f204e0b8SIan Munsie 	int irqs_max;
289f204e0b8SIan Munsie 
290f204e0b8SIan Munsie 	ret = sscanf(buf, "%i", &irqs_max);
291f204e0b8SIan Munsie 	if (ret != 1)
292f204e0b8SIan Munsie 		return -EINVAL;
293f204e0b8SIan Munsie 
294f204e0b8SIan Munsie 	if (irqs_max < afu->pp_irqs)
295f204e0b8SIan Munsie 		return -EINVAL;
296f204e0b8SIan Munsie 
2974752876cSChristophe Lombard 	if (cpu_has_feature(CPU_FTR_HVMODE)) {
298f204e0b8SIan Munsie 		if (irqs_max > afu->adapter->user_irqs)
299f204e0b8SIan Munsie 			return -EINVAL;
3004752876cSChristophe Lombard 	} else {
3014752876cSChristophe Lombard 		/* pHyp sets a per-AFU limit */
3024752876cSChristophe Lombard 		if (irqs_max > afu->guest->max_ints)
3034752876cSChristophe Lombard 			return -EINVAL;
3044752876cSChristophe Lombard 	}
305f204e0b8SIan Munsie 
306f204e0b8SIan Munsie 	afu->irqs_max = irqs_max;
307f204e0b8SIan Munsie 	return count;
308f204e0b8SIan Munsie }
309f204e0b8SIan Munsie 
310f204e0b8SIan Munsie static ssize_t modes_supported_show(struct device *device,
311f204e0b8SIan Munsie 				    struct device_attribute *attr, char *buf)
312f204e0b8SIan Munsie {
313f204e0b8SIan Munsie 	struct cxl_afu *afu = to_cxl_afu(device);
314f204e0b8SIan Munsie 	char *p = buf, *end = buf + PAGE_SIZE;
315f204e0b8SIan Munsie 
316f204e0b8SIan Munsie 	if (afu->modes_supported & CXL_MODE_DEDICATED)
317f204e0b8SIan Munsie 		p += scnprintf(p, end - p, "dedicated_process\n");
318f204e0b8SIan Munsie 	if (afu->modes_supported & CXL_MODE_DIRECTED)
319f204e0b8SIan Munsie 		p += scnprintf(p, end - p, "afu_directed\n");
320f204e0b8SIan Munsie 	return (p - buf);
321f204e0b8SIan Munsie }
322f204e0b8SIan Munsie 
323f204e0b8SIan Munsie static ssize_t prefault_mode_show(struct device *device,
324f204e0b8SIan Munsie 				  struct device_attribute *attr,
325f204e0b8SIan Munsie 				  char *buf)
326f204e0b8SIan Munsie {
327f204e0b8SIan Munsie 	struct cxl_afu *afu = to_cxl_afu(device);
328f204e0b8SIan Munsie 
329f204e0b8SIan Munsie 	switch (afu->prefault_mode) {
330f204e0b8SIan Munsie 	case CXL_PREFAULT_WED:
331f204e0b8SIan Munsie 		return scnprintf(buf, PAGE_SIZE, "work_element_descriptor\n");
332f204e0b8SIan Munsie 	case CXL_PREFAULT_ALL:
333f204e0b8SIan Munsie 		return scnprintf(buf, PAGE_SIZE, "all\n");
334f204e0b8SIan Munsie 	default:
335f204e0b8SIan Munsie 		return scnprintf(buf, PAGE_SIZE, "none\n");
336f204e0b8SIan Munsie 	}
337f204e0b8SIan Munsie }
338f204e0b8SIan Munsie 
339f204e0b8SIan Munsie static ssize_t prefault_mode_store(struct device *device,
340f204e0b8SIan Munsie 			  struct device_attribute *attr,
341f204e0b8SIan Munsie 			  const char *buf, size_t count)
342f204e0b8SIan Munsie {
343f204e0b8SIan Munsie 	struct cxl_afu *afu = to_cxl_afu(device);
344f204e0b8SIan Munsie 	enum prefault_modes mode = -1;
345f204e0b8SIan Munsie 
346*b6c84ba2SVaibhav Jain 	if (!strncmp(buf, "none", 4))
347*b6c84ba2SVaibhav Jain 		mode = CXL_PREFAULT_NONE;
348*b6c84ba2SVaibhav Jain 	else {
349*b6c84ba2SVaibhav Jain 		if (!radix_enabled()) {
350*b6c84ba2SVaibhav Jain 
351*b6c84ba2SVaibhav Jain 			/* only allowed when not in radix mode */
352f204e0b8SIan Munsie 			if (!strncmp(buf, "work_element_descriptor", 23))
353f204e0b8SIan Munsie 				mode = CXL_PREFAULT_WED;
354f204e0b8SIan Munsie 			if (!strncmp(buf, "all", 3))
355f204e0b8SIan Munsie 				mode = CXL_PREFAULT_ALL;
356*b6c84ba2SVaibhav Jain 		} else {
357*b6c84ba2SVaibhav Jain 			dev_err(device, "Cannot prefault with radix enabled\n");
358*b6c84ba2SVaibhav Jain 		}
359*b6c84ba2SVaibhav Jain 	}
360f204e0b8SIan Munsie 
361f204e0b8SIan Munsie 	if (mode == -1)
362f204e0b8SIan Munsie 		return -EINVAL;
363f204e0b8SIan Munsie 
364f204e0b8SIan Munsie 	afu->prefault_mode = mode;
365f204e0b8SIan Munsie 	return count;
366f204e0b8SIan Munsie }
367f204e0b8SIan Munsie 
368f204e0b8SIan Munsie static ssize_t mode_show(struct device *device,
369f204e0b8SIan Munsie 			 struct device_attribute *attr,
370f204e0b8SIan Munsie 			 char *buf)
371f204e0b8SIan Munsie {
372f204e0b8SIan Munsie 	struct cxl_afu *afu = to_cxl_afu(device);
373f204e0b8SIan Munsie 
374f204e0b8SIan Munsie 	if (afu->current_mode == CXL_MODE_DEDICATED)
375f204e0b8SIan Munsie 		return scnprintf(buf, PAGE_SIZE, "dedicated_process\n");
376f204e0b8SIan Munsie 	if (afu->current_mode == CXL_MODE_DIRECTED)
377f204e0b8SIan Munsie 		return scnprintf(buf, PAGE_SIZE, "afu_directed\n");
378f204e0b8SIan Munsie 	return scnprintf(buf, PAGE_SIZE, "none\n");
379f204e0b8SIan Munsie }
380f204e0b8SIan Munsie 
381f204e0b8SIan Munsie static ssize_t mode_store(struct device *device, struct device_attribute *attr,
382f204e0b8SIan Munsie 			  const char *buf, size_t count)
383f204e0b8SIan Munsie {
384f204e0b8SIan Munsie 	struct cxl_afu *afu = to_cxl_afu(device);
385f204e0b8SIan Munsie 	int old_mode, mode = -1;
386f204e0b8SIan Munsie 	int rc = -EBUSY;
387f204e0b8SIan Munsie 
388f204e0b8SIan Munsie 	/* can't change this if we have a user */
389ee41d11dSIan Munsie 	mutex_lock(&afu->contexts_lock);
390f204e0b8SIan Munsie 	if (!idr_is_empty(&afu->contexts_idr))
391f204e0b8SIan Munsie 		goto err;
392f204e0b8SIan Munsie 
393f204e0b8SIan Munsie 	if (!strncmp(buf, "dedicated_process", 17))
394f204e0b8SIan Munsie 		mode = CXL_MODE_DEDICATED;
395f204e0b8SIan Munsie 	if (!strncmp(buf, "afu_directed", 12))
396f204e0b8SIan Munsie 		mode = CXL_MODE_DIRECTED;
397f204e0b8SIan Munsie 	if (!strncmp(buf, "none", 4))
398f204e0b8SIan Munsie 		mode = 0;
399f204e0b8SIan Munsie 
400f204e0b8SIan Munsie 	if (mode == -1) {
401f204e0b8SIan Munsie 		rc = -EINVAL;
402f204e0b8SIan Munsie 		goto err;
403f204e0b8SIan Munsie 	}
404f204e0b8SIan Munsie 
405f204e0b8SIan Munsie 	/*
4065be587b1SFrederic Barrat 	 * afu_deactivate_mode needs to be done outside the lock, prevent
407f204e0b8SIan Munsie 	 * other contexts coming in before we are ready:
408f204e0b8SIan Munsie 	 */
409f204e0b8SIan Munsie 	old_mode = afu->current_mode;
410f204e0b8SIan Munsie 	afu->current_mode = 0;
411f204e0b8SIan Munsie 	afu->num_procs = 0;
412f204e0b8SIan Munsie 
413ee41d11dSIan Munsie 	mutex_unlock(&afu->contexts_lock);
414f204e0b8SIan Munsie 
4155be587b1SFrederic Barrat 	if ((rc = cxl_ops->afu_deactivate_mode(afu, old_mode)))
416f204e0b8SIan Munsie 		return rc;
4175be587b1SFrederic Barrat 	if ((rc = cxl_ops->afu_activate_mode(afu, mode)))
418f204e0b8SIan Munsie 		return rc;
419f204e0b8SIan Munsie 
420f204e0b8SIan Munsie 	return count;
421f204e0b8SIan Munsie err:
422ee41d11dSIan Munsie 	mutex_unlock(&afu->contexts_lock);
423f204e0b8SIan Munsie 	return rc;
424f204e0b8SIan Munsie }
425f204e0b8SIan Munsie 
426f204e0b8SIan Munsie static ssize_t api_version_show(struct device *device,
427f204e0b8SIan Munsie 				struct device_attribute *attr,
428f204e0b8SIan Munsie 				char *buf)
429f204e0b8SIan Munsie {
430f204e0b8SIan Munsie 	return scnprintf(buf, PAGE_SIZE, "%i\n", CXL_API_VERSION);
431f204e0b8SIan Munsie }
432f204e0b8SIan Munsie 
433f204e0b8SIan Munsie static ssize_t api_version_compatible_show(struct device *device,
434f204e0b8SIan Munsie 					   struct device_attribute *attr,
435f204e0b8SIan Munsie 					   char *buf)
436f204e0b8SIan Munsie {
437f204e0b8SIan Munsie 	return scnprintf(buf, PAGE_SIZE, "%i\n", CXL_API_VERSION_COMPATIBLE);
438f204e0b8SIan Munsie }
439f204e0b8SIan Munsie 
440e36f6fe1SVaibhav Jain static ssize_t afu_eb_read(struct file *filp, struct kobject *kobj,
441e36f6fe1SVaibhav Jain 			       struct bin_attribute *bin_attr, char *buf,
442e36f6fe1SVaibhav Jain 			       loff_t off, size_t count)
443e36f6fe1SVaibhav Jain {
44485016ff3SGeliang Tang 	struct cxl_afu *afu = to_cxl_afu(kobj_to_dev(kobj));
445e36f6fe1SVaibhav Jain 
4465be587b1SFrederic Barrat 	return cxl_ops->afu_read_err_buffer(afu, buf, off, count);
447e36f6fe1SVaibhav Jain }
448e36f6fe1SVaibhav Jain 
449f204e0b8SIan Munsie static struct device_attribute afu_attrs[] = {
450f204e0b8SIan Munsie 	__ATTR_RO(mmio_size),
451f204e0b8SIan Munsie 	__ATTR_RO(irqs_min),
452f204e0b8SIan Munsie 	__ATTR_RW(irqs_max),
453f204e0b8SIan Munsie 	__ATTR_RO(modes_supported),
454f204e0b8SIan Munsie 	__ATTR_RW(mode),
455f204e0b8SIan Munsie 	__ATTR_RW(prefault_mode),
456f204e0b8SIan Munsie 	__ATTR_RO(api_version),
457f204e0b8SIan Munsie 	__ATTR_RO(api_version_compatible),
458f204e0b8SIan Munsie 	__ATTR(reset, S_IWUSR, NULL, reset_store_afu),
459f204e0b8SIan Munsie };
460f204e0b8SIan Munsie 
461f204e0b8SIan Munsie int cxl_sysfs_adapter_add(struct cxl *adapter)
462f204e0b8SIan Munsie {
4634752876cSChristophe Lombard 	struct device_attribute *dev_attr;
464f204e0b8SIan Munsie 	int i, rc;
465f204e0b8SIan Munsie 
466f204e0b8SIan Munsie 	for (i = 0; i < ARRAY_SIZE(adapter_attrs); i++) {
4674752876cSChristophe Lombard 		dev_attr = &adapter_attrs[i];
4684752876cSChristophe Lombard 		if (cxl_ops->support_attributes(dev_attr->attr.name,
4694752876cSChristophe Lombard 						CXL_ADAPTER_ATTRS)) {
4704752876cSChristophe Lombard 			if ((rc = device_create_file(&adapter->dev, dev_attr)))
471f204e0b8SIan Munsie 				goto err;
472f204e0b8SIan Munsie 		}
4734752876cSChristophe Lombard 	}
474f204e0b8SIan Munsie 	return 0;
475f204e0b8SIan Munsie err:
4764752876cSChristophe Lombard 	for (i--; i >= 0; i--) {
4774752876cSChristophe Lombard 		dev_attr = &adapter_attrs[i];
4784752876cSChristophe Lombard 		if (cxl_ops->support_attributes(dev_attr->attr.name,
4794752876cSChristophe Lombard 						CXL_ADAPTER_ATTRS))
4804752876cSChristophe Lombard 			device_remove_file(&adapter->dev, dev_attr);
4814752876cSChristophe Lombard 	}
482f204e0b8SIan Munsie 	return rc;
483f204e0b8SIan Munsie }
4844752876cSChristophe Lombard 
485f204e0b8SIan Munsie void cxl_sysfs_adapter_remove(struct cxl *adapter)
486f204e0b8SIan Munsie {
4874752876cSChristophe Lombard 	struct device_attribute *dev_attr;
488f204e0b8SIan Munsie 	int i;
489f204e0b8SIan Munsie 
4904752876cSChristophe Lombard 	for (i = 0; i < ARRAY_SIZE(adapter_attrs); i++) {
4914752876cSChristophe Lombard 		dev_attr = &adapter_attrs[i];
4924752876cSChristophe Lombard 		if (cxl_ops->support_attributes(dev_attr->attr.name,
4934752876cSChristophe Lombard 						CXL_ADAPTER_ATTRS))
4944752876cSChristophe Lombard 			device_remove_file(&adapter->dev, dev_attr);
4954752876cSChristophe Lombard 	}
496f204e0b8SIan Munsie }
497f204e0b8SIan Munsie 
498b087e619SIan Munsie struct afu_config_record {
499b087e619SIan Munsie 	struct kobject kobj;
500b087e619SIan Munsie 	struct bin_attribute config_attr;
501b087e619SIan Munsie 	struct list_head list;
502b087e619SIan Munsie 	int cr;
503b087e619SIan Munsie 	u16 device;
504b087e619SIan Munsie 	u16 vendor;
505b087e619SIan Munsie 	u32 class;
506b087e619SIan Munsie };
507b087e619SIan Munsie 
508b087e619SIan Munsie #define to_cr(obj) container_of(obj, struct afu_config_record, kobj)
509b087e619SIan Munsie 
510b087e619SIan Munsie static ssize_t vendor_show(struct kobject *kobj,
511b087e619SIan Munsie 			   struct kobj_attribute *attr, char *buf)
512b087e619SIan Munsie {
513b087e619SIan Munsie 	struct afu_config_record *cr = to_cr(kobj);
514b087e619SIan Munsie 
515b087e619SIan Munsie 	return scnprintf(buf, PAGE_SIZE, "0x%.4x\n", cr->vendor);
516b087e619SIan Munsie }
517b087e619SIan Munsie 
518b087e619SIan Munsie static ssize_t device_show(struct kobject *kobj,
519b087e619SIan Munsie 			   struct kobj_attribute *attr, char *buf)
520b087e619SIan Munsie {
521b087e619SIan Munsie 	struct afu_config_record *cr = to_cr(kobj);
522b087e619SIan Munsie 
523b087e619SIan Munsie 	return scnprintf(buf, PAGE_SIZE, "0x%.4x\n", cr->device);
524b087e619SIan Munsie }
525b087e619SIan Munsie 
526b087e619SIan Munsie static ssize_t class_show(struct kobject *kobj,
527b087e619SIan Munsie 			  struct kobj_attribute *attr, char *buf)
528b087e619SIan Munsie {
529b087e619SIan Munsie 	struct afu_config_record *cr = to_cr(kobj);
530b087e619SIan Munsie 
531b087e619SIan Munsie 	return scnprintf(buf, PAGE_SIZE, "0x%.6x\n", cr->class);
532b087e619SIan Munsie }
533b087e619SIan Munsie 
534b087e619SIan Munsie static ssize_t afu_read_config(struct file *filp, struct kobject *kobj,
535b087e619SIan Munsie 			       struct bin_attribute *bin_attr, char *buf,
536b087e619SIan Munsie 			       loff_t off, size_t count)
537b087e619SIan Munsie {
538b087e619SIan Munsie 	struct afu_config_record *cr = to_cr(kobj);
53985016ff3SGeliang Tang 	struct cxl_afu *afu = to_cxl_afu(kobj_to_dev(kobj->parent));
540b087e619SIan Munsie 
5415be587b1SFrederic Barrat 	u64 i, j, val, rc;
542b087e619SIan Munsie 
543b087e619SIan Munsie 	for (i = 0; i < count;) {
5445be587b1SFrederic Barrat 		rc = cxl_ops->afu_cr_read64(afu, cr->cr, off & ~0x7, &val);
5455be587b1SFrederic Barrat 		if (rc)
5465be587b1SFrederic Barrat 			val = ~0ULL;
547b087e619SIan Munsie 		for (j = off & 0x7; j < 8 && i < count; i++, j++, off++)
548b087e619SIan Munsie 			buf[i] = (val >> (j * 8)) & 0xff;
549b087e619SIan Munsie 	}
550b087e619SIan Munsie 
551b087e619SIan Munsie 	return count;
552b087e619SIan Munsie }
553b087e619SIan Munsie 
554b087e619SIan Munsie static struct kobj_attribute vendor_attribute =
555b087e619SIan Munsie 	__ATTR_RO(vendor);
556b087e619SIan Munsie static struct kobj_attribute device_attribute =
557b087e619SIan Munsie 	__ATTR_RO(device);
558b087e619SIan Munsie static struct kobj_attribute class_attribute =
559b087e619SIan Munsie 	__ATTR_RO(class);
560b087e619SIan Munsie 
561b087e619SIan Munsie static struct attribute *afu_cr_attrs[] = {
562b087e619SIan Munsie 	&vendor_attribute.attr,
563b087e619SIan Munsie 	&device_attribute.attr,
564b087e619SIan Munsie 	&class_attribute.attr,
565b087e619SIan Munsie 	NULL,
566b087e619SIan Munsie };
567b087e619SIan Munsie 
568b087e619SIan Munsie static void release_afu_config_record(struct kobject *kobj)
569b087e619SIan Munsie {
570b087e619SIan Munsie 	struct afu_config_record *cr = to_cr(kobj);
571b087e619SIan Munsie 
572b087e619SIan Munsie 	kfree(cr);
573b087e619SIan Munsie }
574b087e619SIan Munsie 
575b087e619SIan Munsie static struct kobj_type afu_config_record_type = {
576b087e619SIan Munsie 	.sysfs_ops = &kobj_sysfs_ops,
577b087e619SIan Munsie 	.release = release_afu_config_record,
578b087e619SIan Munsie 	.default_attrs = afu_cr_attrs,
579b087e619SIan Munsie };
580b087e619SIan Munsie 
581b087e619SIan Munsie static struct afu_config_record *cxl_sysfs_afu_new_cr(struct cxl_afu *afu, int cr_idx)
582b087e619SIan Munsie {
583b087e619SIan Munsie 	struct afu_config_record *cr;
584b087e619SIan Munsie 	int rc;
585b087e619SIan Munsie 
586b087e619SIan Munsie 	cr = kzalloc(sizeof(struct afu_config_record), GFP_KERNEL);
587b087e619SIan Munsie 	if (!cr)
588b087e619SIan Munsie 		return ERR_PTR(-ENOMEM);
589b087e619SIan Munsie 
590b087e619SIan Munsie 	cr->cr = cr_idx;
5915be587b1SFrederic Barrat 
5925be587b1SFrederic Barrat 	rc = cxl_ops->afu_cr_read16(afu, cr_idx, PCI_DEVICE_ID, &cr->device);
5935be587b1SFrederic Barrat 	if (rc)
5945be587b1SFrederic Barrat 		goto err;
5955be587b1SFrederic Barrat 	rc = cxl_ops->afu_cr_read16(afu, cr_idx, PCI_VENDOR_ID, &cr->vendor);
5965be587b1SFrederic Barrat 	if (rc)
5975be587b1SFrederic Barrat 		goto err;
5985be587b1SFrederic Barrat 	rc = cxl_ops->afu_cr_read32(afu, cr_idx, PCI_CLASS_REVISION, &cr->class);
5995be587b1SFrederic Barrat 	if (rc)
6005be587b1SFrederic Barrat 		goto err;
6015be587b1SFrederic Barrat 	cr->class >>= 8;
602b087e619SIan Munsie 
603b087e619SIan Munsie 	/*
604b087e619SIan Munsie 	 * Export raw AFU PCIe like config record. For now this is read only by
605b087e619SIan Munsie 	 * root - we can expand that later to be readable by non-root and maybe
6064752876cSChristophe Lombard 	 * even writable provided we have a good use-case. Once we support
607b087e619SIan Munsie 	 * exposing AFUs through a virtual PHB they will get that for free from
608b087e619SIan Munsie 	 * Linux' PCI infrastructure, but until then it's not clear that we
609b087e619SIan Munsie 	 * need it for anything since the main use case is just identifying
610b087e619SIan Munsie 	 * AFUs, which can be done via the vendor, device and class attributes.
611b087e619SIan Munsie 	 */
612b087e619SIan Munsie 	sysfs_bin_attr_init(&cr->config_attr);
613b087e619SIan Munsie 	cr->config_attr.attr.name = "config";
614b087e619SIan Munsie 	cr->config_attr.attr.mode = S_IRUSR;
615b087e619SIan Munsie 	cr->config_attr.size = afu->crs_len;
616b087e619SIan Munsie 	cr->config_attr.read = afu_read_config;
617b087e619SIan Munsie 
618b087e619SIan Munsie 	rc = kobject_init_and_add(&cr->kobj, &afu_config_record_type,
619b087e619SIan Munsie 				  &afu->dev.kobj, "cr%i", cr->cr);
620b087e619SIan Munsie 	if (rc)
621b087e619SIan Munsie 		goto err;
622b087e619SIan Munsie 
623b087e619SIan Munsie 	rc = sysfs_create_bin_file(&cr->kobj, &cr->config_attr);
624b087e619SIan Munsie 	if (rc)
625b087e619SIan Munsie 		goto err1;
626b087e619SIan Munsie 
627b087e619SIan Munsie 	rc = kobject_uevent(&cr->kobj, KOBJ_ADD);
628b087e619SIan Munsie 	if (rc)
629b087e619SIan Munsie 		goto err2;
630b087e619SIan Munsie 
631b087e619SIan Munsie 	return cr;
632b087e619SIan Munsie err2:
633b087e619SIan Munsie 	sysfs_remove_bin_file(&cr->kobj, &cr->config_attr);
634b087e619SIan Munsie err1:
635b087e619SIan Munsie 	kobject_put(&cr->kobj);
636b087e619SIan Munsie 	return ERR_PTR(rc);
637b087e619SIan Munsie err:
638b087e619SIan Munsie 	kfree(cr);
639b087e619SIan Munsie 	return ERR_PTR(rc);
640b087e619SIan Munsie }
641b087e619SIan Munsie 
642b087e619SIan Munsie void cxl_sysfs_afu_remove(struct cxl_afu *afu)
643b087e619SIan Munsie {
6444752876cSChristophe Lombard 	struct device_attribute *dev_attr;
645b087e619SIan Munsie 	struct afu_config_record *cr, *tmp;
646b087e619SIan Munsie 	int i;
647b087e619SIan Munsie 
648e36f6fe1SVaibhav Jain 	/* remove the err buffer bin attribute */
649e36f6fe1SVaibhav Jain 	if (afu->eb_len)
650e36f6fe1SVaibhav Jain 		device_remove_bin_file(&afu->dev, &afu->attr_eb);
651e36f6fe1SVaibhav Jain 
6524752876cSChristophe Lombard 	for (i = 0; i < ARRAY_SIZE(afu_attrs); i++) {
6534752876cSChristophe Lombard 		dev_attr = &afu_attrs[i];
6544752876cSChristophe Lombard 		if (cxl_ops->support_attributes(dev_attr->attr.name,
6554752876cSChristophe Lombard 						CXL_AFU_ATTRS))
656b087e619SIan Munsie 			device_remove_file(&afu->dev, &afu_attrs[i]);
6574752876cSChristophe Lombard 	}
658b087e619SIan Munsie 
659b087e619SIan Munsie 	list_for_each_entry_safe(cr, tmp, &afu->crs, list) {
660b087e619SIan Munsie 		sysfs_remove_bin_file(&cr->kobj, &cr->config_attr);
661b087e619SIan Munsie 		kobject_put(&cr->kobj);
662b087e619SIan Munsie 	}
663b087e619SIan Munsie }
664b087e619SIan Munsie 
665f204e0b8SIan Munsie int cxl_sysfs_afu_add(struct cxl_afu *afu)
666f204e0b8SIan Munsie {
6674752876cSChristophe Lombard 	struct device_attribute *dev_attr;
668b087e619SIan Munsie 	struct afu_config_record *cr;
669f204e0b8SIan Munsie 	int i, rc;
670f204e0b8SIan Munsie 
671b087e619SIan Munsie 	INIT_LIST_HEAD(&afu->crs);
672b087e619SIan Munsie 
673f204e0b8SIan Munsie 	for (i = 0; i < ARRAY_SIZE(afu_attrs); i++) {
6744752876cSChristophe Lombard 		dev_attr = &afu_attrs[i];
6754752876cSChristophe Lombard 		if (cxl_ops->support_attributes(dev_attr->attr.name,
6764752876cSChristophe Lombard 						CXL_AFU_ATTRS)) {
677f204e0b8SIan Munsie 			if ((rc = device_create_file(&afu->dev, &afu_attrs[i])))
678f204e0b8SIan Munsie 				goto err;
679f204e0b8SIan Munsie 		}
6804752876cSChristophe Lombard 	}
681f204e0b8SIan Munsie 
682e36f6fe1SVaibhav Jain 	/* conditionally create the add the binary file for error info buffer */
683e36f6fe1SVaibhav Jain 	if (afu->eb_len) {
684d6eb71a6SVaibhav Jain 		sysfs_attr_init(&afu->attr_eb.attr);
685d6eb71a6SVaibhav Jain 
686e36f6fe1SVaibhav Jain 		afu->attr_eb.attr.name = "afu_err_buff";
687e36f6fe1SVaibhav Jain 		afu->attr_eb.attr.mode = S_IRUGO;
688e36f6fe1SVaibhav Jain 		afu->attr_eb.size = afu->eb_len;
689e36f6fe1SVaibhav Jain 		afu->attr_eb.read = afu_eb_read;
690e36f6fe1SVaibhav Jain 
691e36f6fe1SVaibhav Jain 		rc = device_create_bin_file(&afu->dev, &afu->attr_eb);
692e36f6fe1SVaibhav Jain 		if (rc) {
693e36f6fe1SVaibhav Jain 			dev_err(&afu->dev,
694e36f6fe1SVaibhav Jain 				"Unable to create eb attr for the afu. Err(%d)\n",
695e36f6fe1SVaibhav Jain 				rc);
696e36f6fe1SVaibhav Jain 			goto err;
697e36f6fe1SVaibhav Jain 		}
698e36f6fe1SVaibhav Jain 	}
699e36f6fe1SVaibhav Jain 
700b087e619SIan Munsie 	for (i = 0; i < afu->crs_num; i++) {
701b087e619SIan Munsie 		cr = cxl_sysfs_afu_new_cr(afu, i);
702b087e619SIan Munsie 		if (IS_ERR(cr)) {
703b087e619SIan Munsie 			rc = PTR_ERR(cr);
704b087e619SIan Munsie 			goto err1;
705b087e619SIan Munsie 		}
706b087e619SIan Munsie 		list_add(&cr->list, &afu->crs);
707b087e619SIan Munsie 	}
708b087e619SIan Munsie 
709f204e0b8SIan Munsie 	return 0;
710f204e0b8SIan Munsie 
711b087e619SIan Munsie err1:
712b087e619SIan Munsie 	cxl_sysfs_afu_remove(afu);
713b087e619SIan Munsie 	return rc;
714f204e0b8SIan Munsie err:
715e36f6fe1SVaibhav Jain 	/* reset the eb_len as we havent created the bin attr */
716e36f6fe1SVaibhav Jain 	afu->eb_len = 0;
717e36f6fe1SVaibhav Jain 
7184752876cSChristophe Lombard 	for (i--; i >= 0; i--) {
7194752876cSChristophe Lombard 		dev_attr = &afu_attrs[i];
7204752876cSChristophe Lombard 		if (cxl_ops->support_attributes(dev_attr->attr.name,
7214752876cSChristophe Lombard 						CXL_AFU_ATTRS))
722f204e0b8SIan Munsie 		device_remove_file(&afu->dev, &afu_attrs[i]);
7234752876cSChristophe Lombard 	}
724f204e0b8SIan Munsie 	return rc;
725f204e0b8SIan Munsie }
726f204e0b8SIan Munsie 
727f204e0b8SIan Munsie int cxl_sysfs_afu_m_add(struct cxl_afu *afu)
728f204e0b8SIan Munsie {
7294752876cSChristophe Lombard 	struct device_attribute *dev_attr;
730f204e0b8SIan Munsie 	int i, rc;
731f204e0b8SIan Munsie 
732f204e0b8SIan Munsie 	for (i = 0; i < ARRAY_SIZE(afu_master_attrs); i++) {
7334752876cSChristophe Lombard 		dev_attr = &afu_master_attrs[i];
7344752876cSChristophe Lombard 		if (cxl_ops->support_attributes(dev_attr->attr.name,
7354752876cSChristophe Lombard 						CXL_AFU_MASTER_ATTRS)) {
736f204e0b8SIan Munsie 			if ((rc = device_create_file(afu->chardev_m, &afu_master_attrs[i])))
737f204e0b8SIan Munsie 				goto err;
738f204e0b8SIan Munsie 		}
7394752876cSChristophe Lombard 	}
740f204e0b8SIan Munsie 
741f204e0b8SIan Munsie 	return 0;
742f204e0b8SIan Munsie 
743f204e0b8SIan Munsie err:
7444752876cSChristophe Lombard 	for (i--; i >= 0; i--) {
7454752876cSChristophe Lombard 		dev_attr = &afu_master_attrs[i];
7464752876cSChristophe Lombard 		if (cxl_ops->support_attributes(dev_attr->attr.name,
7474752876cSChristophe Lombard 						CXL_AFU_MASTER_ATTRS))
748f204e0b8SIan Munsie 			device_remove_file(afu->chardev_m, &afu_master_attrs[i]);
7494752876cSChristophe Lombard 	}
750f204e0b8SIan Munsie 	return rc;
751f204e0b8SIan Munsie }
752f204e0b8SIan Munsie 
753f204e0b8SIan Munsie void cxl_sysfs_afu_m_remove(struct cxl_afu *afu)
754f204e0b8SIan Munsie {
7554752876cSChristophe Lombard 	struct device_attribute *dev_attr;
756f204e0b8SIan Munsie 	int i;
757f204e0b8SIan Munsie 
7584752876cSChristophe Lombard 	for (i = 0; i < ARRAY_SIZE(afu_master_attrs); i++) {
7594752876cSChristophe Lombard 		dev_attr = &afu_master_attrs[i];
7604752876cSChristophe Lombard 		if (cxl_ops->support_attributes(dev_attr->attr.name,
7614752876cSChristophe Lombard 						CXL_AFU_MASTER_ATTRS))
762f204e0b8SIan Munsie 			device_remove_file(afu->chardev_m, &afu_master_attrs[i]);
763f204e0b8SIan Munsie 	}
7644752876cSChristophe Lombard }
765