xref: /linux/drivers/misc/cxl/sysfs.c (revision 3a39d672e7f48b8d6b91a09afa4b55352773b4b5)
12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
2f204e0b8SIan Munsie /*
3f204e0b8SIan Munsie  * Copyright 2014 IBM Corp.
4f204e0b8SIan Munsie  */
5f204e0b8SIan Munsie 
6f204e0b8SIan Munsie #include <linux/kernel.h>
7f204e0b8SIan Munsie #include <linux/device.h>
8f204e0b8SIan Munsie #include <linux/sysfs.h>
9b087e619SIan Munsie #include <linux/pci_regs.h>
10f204e0b8SIan Munsie 
11f204e0b8SIan Munsie #include "cxl.h"
12f204e0b8SIan Munsie 
13f204e0b8SIan Munsie #define to_afu_chardev_m(d) dev_get_drvdata(d)
14f204e0b8SIan Munsie 
15f204e0b8SIan Munsie /*********  Adapter attributes  **********************************************/
16f204e0b8SIan Munsie 
caia_version_show(struct device * device,struct device_attribute * attr,char * buf)17f204e0b8SIan Munsie static ssize_t caia_version_show(struct device *device,
18f204e0b8SIan Munsie 				 struct device_attribute *attr,
19f204e0b8SIan Munsie 				 char *buf)
20f204e0b8SIan Munsie {
21f204e0b8SIan Munsie 	struct cxl *adapter = to_cxl_adapter(device);
22f204e0b8SIan Munsie 
23f204e0b8SIan Munsie 	return scnprintf(buf, PAGE_SIZE, "%i.%i\n", adapter->caia_major,
24f204e0b8SIan Munsie 			 adapter->caia_minor);
25f204e0b8SIan Munsie }
26f204e0b8SIan Munsie 
psl_revision_show(struct device * device,struct device_attribute * attr,char * buf)27f204e0b8SIan Munsie static ssize_t psl_revision_show(struct device *device,
28f204e0b8SIan Munsie 				 struct device_attribute *attr,
29f204e0b8SIan Munsie 				 char *buf)
30f204e0b8SIan Munsie {
31f204e0b8SIan Munsie 	struct cxl *adapter = to_cxl_adapter(device);
32f204e0b8SIan Munsie 
33f204e0b8SIan Munsie 	return scnprintf(buf, PAGE_SIZE, "%i\n", adapter->psl_rev);
34f204e0b8SIan Munsie }
35f204e0b8SIan Munsie 
base_image_show(struct device * device,struct device_attribute * attr,char * buf)36f204e0b8SIan Munsie static ssize_t base_image_show(struct device *device,
37f204e0b8SIan Munsie 			       struct device_attribute *attr,
38f204e0b8SIan Munsie 			       char *buf)
39f204e0b8SIan Munsie {
40f204e0b8SIan Munsie 	struct cxl *adapter = to_cxl_adapter(device);
41f204e0b8SIan Munsie 
42f204e0b8SIan Munsie 	return scnprintf(buf, PAGE_SIZE, "%i\n", adapter->base_image);
43f204e0b8SIan Munsie }
44f204e0b8SIan Munsie 
image_loaded_show(struct device * device,struct device_attribute * attr,char * buf)45f204e0b8SIan Munsie static ssize_t image_loaded_show(struct device *device,
46f204e0b8SIan Munsie 				 struct device_attribute *attr,
47f204e0b8SIan Munsie 				 char *buf)
48f204e0b8SIan Munsie {
49f204e0b8SIan Munsie 	struct cxl *adapter = to_cxl_adapter(device);
50f204e0b8SIan Munsie 
51f204e0b8SIan Munsie 	if (adapter->user_image_loaded)
52f204e0b8SIan Munsie 		return scnprintf(buf, PAGE_SIZE, "user\n");
53f204e0b8SIan Munsie 	return scnprintf(buf, PAGE_SIZE, "factory\n");
54f204e0b8SIan Munsie }
55f204e0b8SIan Munsie 
psl_timebase_synced_show(struct device * device,struct device_attribute * attr,char * buf)56e009a7e8SFrederic Barrat static ssize_t psl_timebase_synced_show(struct device *device,
57e009a7e8SFrederic Barrat 					struct device_attribute *attr,
58e009a7e8SFrederic Barrat 					char *buf)
59e009a7e8SFrederic Barrat {
60e009a7e8SFrederic Barrat 	struct cxl *adapter = to_cxl_adapter(device);
61c2be663dSChristophe Lombard 	u64 psl_tb, delta;
62e009a7e8SFrederic Barrat 
63c2be663dSChristophe Lombard 	/* Recompute the status only in native mode */
64c2be663dSChristophe Lombard 	if (cpu_has_feature(CPU_FTR_HVMODE)) {
65c2be663dSChristophe Lombard 		psl_tb = adapter->native->sl_ops->timebase_read(adapter);
66c2be663dSChristophe Lombard 		delta = abs(mftb() - psl_tb);
67c2be663dSChristophe Lombard 
68c2be663dSChristophe Lombard 		/* CORE TB and PSL TB difference <= 16usecs ? */
69c2be663dSChristophe Lombard 		adapter->psl_timebase_synced = (tb_to_ns(delta) < 16000) ? true : false;
70c2be663dSChristophe Lombard 		pr_devel("PSL timebase %s - delta: 0x%016llx\n",
71c2be663dSChristophe Lombard 			 (tb_to_ns(delta) < 16000) ? "synchronized" :
72c2be663dSChristophe Lombard 			 "not synchronized", tb_to_ns(delta));
73c2be663dSChristophe Lombard 	}
74e009a7e8SFrederic Barrat 	return scnprintf(buf, PAGE_SIZE, "%i\n", adapter->psl_timebase_synced);
75e009a7e8SFrederic Barrat }
76e009a7e8SFrederic Barrat 
tunneled_ops_supported_show(struct device * device,struct device_attribute * attr,char * buf)77497a0790SPhilippe Bergheaud static ssize_t tunneled_ops_supported_show(struct device *device,
78497a0790SPhilippe Bergheaud 					struct device_attribute *attr,
79497a0790SPhilippe Bergheaud 					char *buf)
80497a0790SPhilippe Bergheaud {
81497a0790SPhilippe Bergheaud 	struct cxl *adapter = to_cxl_adapter(device);
82497a0790SPhilippe Bergheaud 
83497a0790SPhilippe Bergheaud 	return scnprintf(buf, PAGE_SIZE, "%i\n", adapter->tunneled_ops_supported);
84497a0790SPhilippe Bergheaud }
85497a0790SPhilippe Bergheaud 
reset_adapter_store(struct device * device,struct device_attribute * attr,const char * buf,size_t count)8662fa19d4SRyan Grimm static ssize_t reset_adapter_store(struct device *device,
8762fa19d4SRyan Grimm 				   struct device_attribute *attr,
8862fa19d4SRyan Grimm 				   const char *buf, size_t count)
8962fa19d4SRyan Grimm {
9062fa19d4SRyan Grimm 	struct cxl *adapter = to_cxl_adapter(device);
9162fa19d4SRyan Grimm 	int rc;
9262fa19d4SRyan Grimm 	int val;
9362fa19d4SRyan Grimm 
9462fa19d4SRyan Grimm 	rc = sscanf(buf, "%i", &val);
9570b565bbSVaibhav Jain 	if ((rc != 1) || (val != 1 && val != -1))
9662fa19d4SRyan Grimm 		return -EINVAL;
9762fa19d4SRyan Grimm 
9870b565bbSVaibhav Jain 	/*
9970b565bbSVaibhav Jain 	 * See if we can lock the context mapping that's only allowed
10070b565bbSVaibhav Jain 	 * when there are no contexts attached to the adapter. Once
10170b565bbSVaibhav Jain 	 * taken this will also prevent any context from getting activated.
10270b565bbSVaibhav Jain 	 */
10370b565bbSVaibhav Jain 	if (val == 1) {
10470b565bbSVaibhav Jain 		rc =  cxl_adapter_context_lock(adapter);
10570b565bbSVaibhav Jain 		if (rc)
10670b565bbSVaibhav Jain 			goto out;
10770b565bbSVaibhav Jain 
10870b565bbSVaibhav Jain 		rc = cxl_ops->adapter_reset(adapter);
10970b565bbSVaibhav Jain 		/* In case reset failed release context lock */
11070b565bbSVaibhav Jain 		if (rc)
11170b565bbSVaibhav Jain 			cxl_adapter_context_unlock(adapter);
11270b565bbSVaibhav Jain 
11370b565bbSVaibhav Jain 	} else if (val == -1) {
11470b565bbSVaibhav Jain 		/* Perform a forced adapter reset */
11570b565bbSVaibhav Jain 		rc = cxl_ops->adapter_reset(adapter);
11670b565bbSVaibhav Jain 	}
11770b565bbSVaibhav Jain 
11870b565bbSVaibhav Jain out:
11970b565bbSVaibhav Jain 	return rc ? rc : count;
12062fa19d4SRyan Grimm }
12162fa19d4SRyan Grimm 
load_image_on_perst_show(struct device * device,struct device_attribute * attr,char * buf)12295bc11bcSRyan Grimm static ssize_t load_image_on_perst_show(struct device *device,
12395bc11bcSRyan Grimm 				 struct device_attribute *attr,
12495bc11bcSRyan Grimm 				 char *buf)
12595bc11bcSRyan Grimm {
12695bc11bcSRyan Grimm 	struct cxl *adapter = to_cxl_adapter(device);
12795bc11bcSRyan Grimm 
12895bc11bcSRyan Grimm 	if (!adapter->perst_loads_image)
12995bc11bcSRyan Grimm 		return scnprintf(buf, PAGE_SIZE, "none\n");
13095bc11bcSRyan Grimm 
13195bc11bcSRyan Grimm 	if (adapter->perst_select_user)
13295bc11bcSRyan Grimm 		return scnprintf(buf, PAGE_SIZE, "user\n");
13395bc11bcSRyan Grimm 	return scnprintf(buf, PAGE_SIZE, "factory\n");
13495bc11bcSRyan Grimm }
13595bc11bcSRyan Grimm 
load_image_on_perst_store(struct device * device,struct device_attribute * attr,const char * buf,size_t count)13695bc11bcSRyan Grimm static ssize_t load_image_on_perst_store(struct device *device,
13795bc11bcSRyan Grimm 				 struct device_attribute *attr,
13895bc11bcSRyan Grimm 				 const char *buf, size_t count)
13995bc11bcSRyan Grimm {
14095bc11bcSRyan Grimm 	struct cxl *adapter = to_cxl_adapter(device);
14195bc11bcSRyan Grimm 	int rc;
14295bc11bcSRyan Grimm 
14395bc11bcSRyan Grimm 	if (!strncmp(buf, "none", 4))
14495bc11bcSRyan Grimm 		adapter->perst_loads_image = false;
14595bc11bcSRyan Grimm 	else if (!strncmp(buf, "user", 4)) {
14695bc11bcSRyan Grimm 		adapter->perst_select_user = true;
14795bc11bcSRyan Grimm 		adapter->perst_loads_image = true;
14895bc11bcSRyan Grimm 	} else if (!strncmp(buf, "factory", 7)) {
14995bc11bcSRyan Grimm 		adapter->perst_select_user = false;
15095bc11bcSRyan Grimm 		adapter->perst_loads_image = true;
15195bc11bcSRyan Grimm 	} else
15295bc11bcSRyan Grimm 		return -EINVAL;
15395bc11bcSRyan Grimm 
15495bc11bcSRyan Grimm 	if ((rc = cxl_update_image_control(adapter)))
15595bc11bcSRyan Grimm 		return rc;
15695bc11bcSRyan Grimm 
15795bc11bcSRyan Grimm 	return count;
15895bc11bcSRyan Grimm }
15995bc11bcSRyan Grimm 
perst_reloads_same_image_show(struct device * device,struct device_attribute * attr,char * buf)16013e68d8bSDaniel Axtens static ssize_t perst_reloads_same_image_show(struct device *device,
16113e68d8bSDaniel Axtens 				 struct device_attribute *attr,
16213e68d8bSDaniel Axtens 				 char *buf)
16313e68d8bSDaniel Axtens {
16413e68d8bSDaniel Axtens 	struct cxl *adapter = to_cxl_adapter(device);
16513e68d8bSDaniel Axtens 
16613e68d8bSDaniel Axtens 	return scnprintf(buf, PAGE_SIZE, "%i\n", adapter->perst_same_image);
16713e68d8bSDaniel Axtens }
16813e68d8bSDaniel Axtens 
perst_reloads_same_image_store(struct device * device,struct device_attribute * attr,const char * buf,size_t count)16913e68d8bSDaniel Axtens static ssize_t perst_reloads_same_image_store(struct device *device,
17013e68d8bSDaniel Axtens 				 struct device_attribute *attr,
17113e68d8bSDaniel Axtens 				 const char *buf, size_t count)
17213e68d8bSDaniel Axtens {
17313e68d8bSDaniel Axtens 	struct cxl *adapter = to_cxl_adapter(device);
17413e68d8bSDaniel Axtens 	int rc;
17513e68d8bSDaniel Axtens 	int val;
17613e68d8bSDaniel Axtens 
17713e68d8bSDaniel Axtens 	rc = sscanf(buf, "%i", &val);
17813e68d8bSDaniel Axtens 	if ((rc != 1) || !(val == 1 || val == 0))
17913e68d8bSDaniel Axtens 		return -EINVAL;
18013e68d8bSDaniel Axtens 
18176ec1ec8SYang Li 	adapter->perst_same_image = (val == 1);
18213e68d8bSDaniel Axtens 	return count;
18313e68d8bSDaniel Axtens }
18413e68d8bSDaniel Axtens 
185f204e0b8SIan Munsie static struct device_attribute adapter_attrs[] = {
186f204e0b8SIan Munsie 	__ATTR_RO(caia_version),
187f204e0b8SIan Munsie 	__ATTR_RO(psl_revision),
188f204e0b8SIan Munsie 	__ATTR_RO(base_image),
189f204e0b8SIan Munsie 	__ATTR_RO(image_loaded),
190e009a7e8SFrederic Barrat 	__ATTR_RO(psl_timebase_synced),
191497a0790SPhilippe Bergheaud 	__ATTR_RO(tunneled_ops_supported),
19295bc11bcSRyan Grimm 	__ATTR_RW(load_image_on_perst),
19313e68d8bSDaniel Axtens 	__ATTR_RW(perst_reloads_same_image),
19462fa19d4SRyan Grimm 	__ATTR(reset, S_IWUSR, NULL, reset_adapter_store),
195f204e0b8SIan Munsie };
196f204e0b8SIan Munsie 
197f204e0b8SIan Munsie 
198f204e0b8SIan Munsie /*********  AFU master specific attributes  **********************************/
199f204e0b8SIan Munsie 
mmio_size_show_master(struct device * device,struct device_attribute * attr,char * buf)200f204e0b8SIan Munsie static ssize_t mmio_size_show_master(struct device *device,
201f204e0b8SIan Munsie 				     struct device_attribute *attr,
202f204e0b8SIan Munsie 				     char *buf)
203f204e0b8SIan Munsie {
204f204e0b8SIan Munsie 	struct cxl_afu *afu = to_afu_chardev_m(device);
205f204e0b8SIan Munsie 
206f204e0b8SIan Munsie 	return scnprintf(buf, PAGE_SIZE, "%llu\n", afu->adapter->ps_size);
207f204e0b8SIan Munsie }
208f204e0b8SIan Munsie 
pp_mmio_off_show(struct device * device,struct device_attribute * attr,char * buf)209f204e0b8SIan Munsie static ssize_t pp_mmio_off_show(struct device *device,
210f204e0b8SIan Munsie 				struct device_attribute *attr,
211f204e0b8SIan Munsie 				char *buf)
212f204e0b8SIan Munsie {
213f204e0b8SIan Munsie 	struct cxl_afu *afu = to_afu_chardev_m(device);
214f204e0b8SIan Munsie 
215cbffa3a5SChristophe Lombard 	return scnprintf(buf, PAGE_SIZE, "%llu\n", afu->native->pp_offset);
216f204e0b8SIan Munsie }
217f204e0b8SIan Munsie 
pp_mmio_len_show(struct device * device,struct device_attribute * attr,char * buf)218f204e0b8SIan Munsie static ssize_t pp_mmio_len_show(struct device *device,
219f204e0b8SIan Munsie 				struct device_attribute *attr,
220f204e0b8SIan Munsie 				char *buf)
221f204e0b8SIan Munsie {
222f204e0b8SIan Munsie 	struct cxl_afu *afu = to_afu_chardev_m(device);
223f204e0b8SIan Munsie 
224f204e0b8SIan Munsie 	return scnprintf(buf, PAGE_SIZE, "%llu\n", afu->pp_size);
225f204e0b8SIan Munsie }
226f204e0b8SIan Munsie 
227f204e0b8SIan Munsie static struct device_attribute afu_master_attrs[] = {
228f204e0b8SIan Munsie 	__ATTR(mmio_size, S_IRUGO, mmio_size_show_master, NULL),
229f204e0b8SIan Munsie 	__ATTR_RO(pp_mmio_off),
230f204e0b8SIan Munsie 	__ATTR_RO(pp_mmio_len),
231f204e0b8SIan Munsie };
232f204e0b8SIan Munsie 
233f204e0b8SIan Munsie 
234f204e0b8SIan Munsie /*********  AFU attributes  **************************************************/
235f204e0b8SIan Munsie 
mmio_size_show(struct device * device,struct device_attribute * attr,char * buf)236f204e0b8SIan Munsie static ssize_t mmio_size_show(struct device *device,
237f204e0b8SIan Munsie 			      struct device_attribute *attr,
238f204e0b8SIan Munsie 			      char *buf)
239f204e0b8SIan Munsie {
240f204e0b8SIan Munsie 	struct cxl_afu *afu = to_cxl_afu(device);
241f204e0b8SIan Munsie 
242f204e0b8SIan Munsie 	if (afu->pp_size)
243f204e0b8SIan Munsie 		return scnprintf(buf, PAGE_SIZE, "%llu\n", afu->pp_size);
244f204e0b8SIan Munsie 	return scnprintf(buf, PAGE_SIZE, "%llu\n", afu->adapter->ps_size);
245f204e0b8SIan Munsie }
246f204e0b8SIan Munsie 
reset_store_afu(struct device * device,struct device_attribute * attr,const char * buf,size_t count)247f204e0b8SIan Munsie static ssize_t reset_store_afu(struct device *device,
248f204e0b8SIan Munsie 			       struct device_attribute *attr,
249f204e0b8SIan Munsie 			       const char *buf, size_t count)
250f204e0b8SIan Munsie {
251f204e0b8SIan Munsie 	struct cxl_afu *afu = to_cxl_afu(device);
252f204e0b8SIan Munsie 	int rc;
253f204e0b8SIan Munsie 
254f204e0b8SIan Munsie 	/* Not safe to reset if it is currently in use */
255ee41d11dSIan Munsie 	mutex_lock(&afu->contexts_lock);
256f204e0b8SIan Munsie 	if (!idr_is_empty(&afu->contexts_idr)) {
257f204e0b8SIan Munsie 		rc = -EBUSY;
258f204e0b8SIan Munsie 		goto err;
259f204e0b8SIan Munsie 	}
260f204e0b8SIan Munsie 
2615be587b1SFrederic Barrat 	if ((rc = cxl_ops->afu_reset(afu)))
262f204e0b8SIan Munsie 		goto err;
263f204e0b8SIan Munsie 
264f204e0b8SIan Munsie 	rc = count;
265f204e0b8SIan Munsie err:
266ee41d11dSIan Munsie 	mutex_unlock(&afu->contexts_lock);
267f204e0b8SIan Munsie 	return rc;
268f204e0b8SIan Munsie }
269f204e0b8SIan Munsie 
irqs_min_show(struct device * device,struct device_attribute * attr,char * buf)270f204e0b8SIan Munsie static ssize_t irqs_min_show(struct device *device,
271f204e0b8SIan Munsie 			     struct device_attribute *attr,
272f204e0b8SIan Munsie 			     char *buf)
273f204e0b8SIan Munsie {
274f204e0b8SIan Munsie 	struct cxl_afu *afu = to_cxl_afu(device);
275f204e0b8SIan Munsie 
276f204e0b8SIan Munsie 	return scnprintf(buf, PAGE_SIZE, "%i\n", afu->pp_irqs);
277f204e0b8SIan Munsie }
278f204e0b8SIan Munsie 
irqs_max_show(struct device * device,struct device_attribute * attr,char * buf)279f204e0b8SIan Munsie static ssize_t irqs_max_show(struct device *device,
280f204e0b8SIan Munsie 				  struct device_attribute *attr,
281f204e0b8SIan Munsie 				  char *buf)
282f204e0b8SIan Munsie {
283f204e0b8SIan Munsie 	struct cxl_afu *afu = to_cxl_afu(device);
284f204e0b8SIan Munsie 
285f204e0b8SIan Munsie 	return scnprintf(buf, PAGE_SIZE, "%i\n", afu->irqs_max);
286f204e0b8SIan Munsie }
287f204e0b8SIan Munsie 
irqs_max_store(struct device * device,struct device_attribute * attr,const char * buf,size_t count)288f204e0b8SIan Munsie static ssize_t irqs_max_store(struct device *device,
289f204e0b8SIan Munsie 				  struct device_attribute *attr,
290f204e0b8SIan Munsie 				  const char *buf, size_t count)
291f204e0b8SIan Munsie {
292f204e0b8SIan Munsie 	struct cxl_afu *afu = to_cxl_afu(device);
293f204e0b8SIan Munsie 	ssize_t ret;
294f204e0b8SIan Munsie 	int irqs_max;
295f204e0b8SIan Munsie 
296f204e0b8SIan Munsie 	ret = sscanf(buf, "%i", &irqs_max);
297f204e0b8SIan Munsie 	if (ret != 1)
298f204e0b8SIan Munsie 		return -EINVAL;
299f204e0b8SIan Munsie 
300f204e0b8SIan Munsie 	if (irqs_max < afu->pp_irqs)
301f204e0b8SIan Munsie 		return -EINVAL;
302f204e0b8SIan Munsie 
3034752876cSChristophe Lombard 	if (cpu_has_feature(CPU_FTR_HVMODE)) {
304f204e0b8SIan Munsie 		if (irqs_max > afu->adapter->user_irqs)
305f204e0b8SIan Munsie 			return -EINVAL;
3064752876cSChristophe Lombard 	} else {
3074752876cSChristophe Lombard 		/* pHyp sets a per-AFU limit */
3084752876cSChristophe Lombard 		if (irqs_max > afu->guest->max_ints)
3094752876cSChristophe Lombard 			return -EINVAL;
3104752876cSChristophe Lombard 	}
311f204e0b8SIan Munsie 
312f204e0b8SIan Munsie 	afu->irqs_max = irqs_max;
313f204e0b8SIan Munsie 	return count;
314f204e0b8SIan Munsie }
315f204e0b8SIan Munsie 
modes_supported_show(struct device * device,struct device_attribute * attr,char * buf)316f204e0b8SIan Munsie static ssize_t modes_supported_show(struct device *device,
317f204e0b8SIan Munsie 				    struct device_attribute *attr, char *buf)
318f204e0b8SIan Munsie {
319f204e0b8SIan Munsie 	struct cxl_afu *afu = to_cxl_afu(device);
320f204e0b8SIan Munsie 	char *p = buf, *end = buf + PAGE_SIZE;
321f204e0b8SIan Munsie 
322f204e0b8SIan Munsie 	if (afu->modes_supported & CXL_MODE_DEDICATED)
323f204e0b8SIan Munsie 		p += scnprintf(p, end - p, "dedicated_process\n");
324f204e0b8SIan Munsie 	if (afu->modes_supported & CXL_MODE_DIRECTED)
325f204e0b8SIan Munsie 		p += scnprintf(p, end - p, "afu_directed\n");
326f204e0b8SIan Munsie 	return (p - buf);
327f204e0b8SIan Munsie }
328f204e0b8SIan Munsie 
prefault_mode_show(struct device * device,struct device_attribute * attr,char * buf)329f204e0b8SIan Munsie static ssize_t prefault_mode_show(struct device *device,
330f204e0b8SIan Munsie 				  struct device_attribute *attr,
331f204e0b8SIan Munsie 				  char *buf)
332f204e0b8SIan Munsie {
333f204e0b8SIan Munsie 	struct cxl_afu *afu = to_cxl_afu(device);
334f204e0b8SIan Munsie 
335f204e0b8SIan Munsie 	switch (afu->prefault_mode) {
336f204e0b8SIan Munsie 	case CXL_PREFAULT_WED:
337f204e0b8SIan Munsie 		return scnprintf(buf, PAGE_SIZE, "work_element_descriptor\n");
338f204e0b8SIan Munsie 	case CXL_PREFAULT_ALL:
339f204e0b8SIan Munsie 		return scnprintf(buf, PAGE_SIZE, "all\n");
340f204e0b8SIan Munsie 	default:
341f204e0b8SIan Munsie 		return scnprintf(buf, PAGE_SIZE, "none\n");
342f204e0b8SIan Munsie 	}
343f204e0b8SIan Munsie }
344f204e0b8SIan Munsie 
prefault_mode_store(struct device * device,struct device_attribute * attr,const char * buf,size_t count)345f204e0b8SIan Munsie static ssize_t prefault_mode_store(struct device *device,
346f204e0b8SIan Munsie 			  struct device_attribute *attr,
347f204e0b8SIan Munsie 			  const char *buf, size_t count)
348f204e0b8SIan Munsie {
349f204e0b8SIan Munsie 	struct cxl_afu *afu = to_cxl_afu(device);
350f204e0b8SIan Munsie 	enum prefault_modes mode = -1;
351f204e0b8SIan Munsie 
352b6c84ba2SVaibhav Jain 	if (!strncmp(buf, "none", 4))
353b6c84ba2SVaibhav Jain 		mode = CXL_PREFAULT_NONE;
354b6c84ba2SVaibhav Jain 	else {
355b6c84ba2SVaibhav Jain 		if (!radix_enabled()) {
356b6c84ba2SVaibhav Jain 
357b6c84ba2SVaibhav Jain 			/* only allowed when not in radix mode */
358f204e0b8SIan Munsie 			if (!strncmp(buf, "work_element_descriptor", 23))
359f204e0b8SIan Munsie 				mode = CXL_PREFAULT_WED;
360f204e0b8SIan Munsie 			if (!strncmp(buf, "all", 3))
361f204e0b8SIan Munsie 				mode = CXL_PREFAULT_ALL;
362b6c84ba2SVaibhav Jain 		} else {
363b6c84ba2SVaibhav Jain 			dev_err(device, "Cannot prefault with radix enabled\n");
364b6c84ba2SVaibhav Jain 		}
365b6c84ba2SVaibhav Jain 	}
366f204e0b8SIan Munsie 
367f204e0b8SIan Munsie 	if (mode == -1)
368f204e0b8SIan Munsie 		return -EINVAL;
369f204e0b8SIan Munsie 
370f204e0b8SIan Munsie 	afu->prefault_mode = mode;
371f204e0b8SIan Munsie 	return count;
372f204e0b8SIan Munsie }
373f204e0b8SIan Munsie 
mode_show(struct device * device,struct device_attribute * attr,char * buf)374f204e0b8SIan Munsie static ssize_t mode_show(struct device *device,
375f204e0b8SIan Munsie 			 struct device_attribute *attr,
376f204e0b8SIan Munsie 			 char *buf)
377f204e0b8SIan Munsie {
378f204e0b8SIan Munsie 	struct cxl_afu *afu = to_cxl_afu(device);
379f204e0b8SIan Munsie 
380f204e0b8SIan Munsie 	if (afu->current_mode == CXL_MODE_DEDICATED)
381f204e0b8SIan Munsie 		return scnprintf(buf, PAGE_SIZE, "dedicated_process\n");
382f204e0b8SIan Munsie 	if (afu->current_mode == CXL_MODE_DIRECTED)
383f204e0b8SIan Munsie 		return scnprintf(buf, PAGE_SIZE, "afu_directed\n");
384f204e0b8SIan Munsie 	return scnprintf(buf, PAGE_SIZE, "none\n");
385f204e0b8SIan Munsie }
386f204e0b8SIan Munsie 
mode_store(struct device * device,struct device_attribute * attr,const char * buf,size_t count)387f204e0b8SIan Munsie static ssize_t mode_store(struct device *device, struct device_attribute *attr,
388f204e0b8SIan Munsie 			  const char *buf, size_t count)
389f204e0b8SIan Munsie {
390f204e0b8SIan Munsie 	struct cxl_afu *afu = to_cxl_afu(device);
391f204e0b8SIan Munsie 	int old_mode, mode = -1;
392f204e0b8SIan Munsie 	int rc = -EBUSY;
393f204e0b8SIan Munsie 
394f204e0b8SIan Munsie 	/* can't change this if we have a user */
395ee41d11dSIan Munsie 	mutex_lock(&afu->contexts_lock);
396f204e0b8SIan Munsie 	if (!idr_is_empty(&afu->contexts_idr))
397f204e0b8SIan Munsie 		goto err;
398f204e0b8SIan Munsie 
399f204e0b8SIan Munsie 	if (!strncmp(buf, "dedicated_process", 17))
400f204e0b8SIan Munsie 		mode = CXL_MODE_DEDICATED;
401f204e0b8SIan Munsie 	if (!strncmp(buf, "afu_directed", 12))
402f204e0b8SIan Munsie 		mode = CXL_MODE_DIRECTED;
403f204e0b8SIan Munsie 	if (!strncmp(buf, "none", 4))
404f204e0b8SIan Munsie 		mode = 0;
405f204e0b8SIan Munsie 
406f204e0b8SIan Munsie 	if (mode == -1) {
407f204e0b8SIan Munsie 		rc = -EINVAL;
408f204e0b8SIan Munsie 		goto err;
409f204e0b8SIan Munsie 	}
410f204e0b8SIan Munsie 
411f204e0b8SIan Munsie 	/*
4125be587b1SFrederic Barrat 	 * afu_deactivate_mode needs to be done outside the lock, prevent
413f204e0b8SIan Munsie 	 * other contexts coming in before we are ready:
414f204e0b8SIan Munsie 	 */
415f204e0b8SIan Munsie 	old_mode = afu->current_mode;
416f204e0b8SIan Munsie 	afu->current_mode = 0;
417f204e0b8SIan Munsie 	afu->num_procs = 0;
418f204e0b8SIan Munsie 
419ee41d11dSIan Munsie 	mutex_unlock(&afu->contexts_lock);
420f204e0b8SIan Munsie 
4215be587b1SFrederic Barrat 	if ((rc = cxl_ops->afu_deactivate_mode(afu, old_mode)))
422f204e0b8SIan Munsie 		return rc;
4235be587b1SFrederic Barrat 	if ((rc = cxl_ops->afu_activate_mode(afu, mode)))
424f204e0b8SIan Munsie 		return rc;
425f204e0b8SIan Munsie 
426f204e0b8SIan Munsie 	return count;
427f204e0b8SIan Munsie err:
428ee41d11dSIan Munsie 	mutex_unlock(&afu->contexts_lock);
429f204e0b8SIan Munsie 	return rc;
430f204e0b8SIan Munsie }
431f204e0b8SIan Munsie 
api_version_show(struct device * device,struct device_attribute * attr,char * buf)432f204e0b8SIan Munsie static ssize_t api_version_show(struct device *device,
433f204e0b8SIan Munsie 				struct device_attribute *attr,
434f204e0b8SIan Munsie 				char *buf)
435f204e0b8SIan Munsie {
436f204e0b8SIan Munsie 	return scnprintf(buf, PAGE_SIZE, "%i\n", CXL_API_VERSION);
437f204e0b8SIan Munsie }
438f204e0b8SIan Munsie 
api_version_compatible_show(struct device * device,struct device_attribute * attr,char * buf)439f204e0b8SIan Munsie static ssize_t api_version_compatible_show(struct device *device,
440f204e0b8SIan Munsie 					   struct device_attribute *attr,
441f204e0b8SIan Munsie 					   char *buf)
442f204e0b8SIan Munsie {
443f204e0b8SIan Munsie 	return scnprintf(buf, PAGE_SIZE, "%i\n", CXL_API_VERSION_COMPATIBLE);
444f204e0b8SIan Munsie }
445f204e0b8SIan Munsie 
afu_eb_read(struct file * filp,struct kobject * kobj,struct bin_attribute * bin_attr,char * buf,loff_t off,size_t count)446e36f6fe1SVaibhav Jain static ssize_t afu_eb_read(struct file *filp, struct kobject *kobj,
447e36f6fe1SVaibhav Jain 			       struct bin_attribute *bin_attr, char *buf,
448e36f6fe1SVaibhav Jain 			       loff_t off, size_t count)
449e36f6fe1SVaibhav Jain {
45085016ff3SGeliang Tang 	struct cxl_afu *afu = to_cxl_afu(kobj_to_dev(kobj));
451e36f6fe1SVaibhav Jain 
4525be587b1SFrederic Barrat 	return cxl_ops->afu_read_err_buffer(afu, buf, off, count);
453e36f6fe1SVaibhav Jain }
454e36f6fe1SVaibhav Jain 
455f204e0b8SIan Munsie static struct device_attribute afu_attrs[] = {
456f204e0b8SIan Munsie 	__ATTR_RO(mmio_size),
457f204e0b8SIan Munsie 	__ATTR_RO(irqs_min),
458f204e0b8SIan Munsie 	__ATTR_RW(irqs_max),
459f204e0b8SIan Munsie 	__ATTR_RO(modes_supported),
460f204e0b8SIan Munsie 	__ATTR_RW(mode),
461f204e0b8SIan Munsie 	__ATTR_RW(prefault_mode),
462f204e0b8SIan Munsie 	__ATTR_RO(api_version),
463f204e0b8SIan Munsie 	__ATTR_RO(api_version_compatible),
464f204e0b8SIan Munsie 	__ATTR(reset, S_IWUSR, NULL, reset_store_afu),
465f204e0b8SIan Munsie };
466f204e0b8SIan Munsie 
cxl_sysfs_adapter_add(struct cxl * adapter)467f204e0b8SIan Munsie int cxl_sysfs_adapter_add(struct cxl *adapter)
468f204e0b8SIan Munsie {
4694752876cSChristophe Lombard 	struct device_attribute *dev_attr;
470f204e0b8SIan Munsie 	int i, rc;
471f204e0b8SIan Munsie 
472f204e0b8SIan Munsie 	for (i = 0; i < ARRAY_SIZE(adapter_attrs); i++) {
4734752876cSChristophe Lombard 		dev_attr = &adapter_attrs[i];
4744752876cSChristophe Lombard 		if (cxl_ops->support_attributes(dev_attr->attr.name,
4754752876cSChristophe Lombard 						CXL_ADAPTER_ATTRS)) {
4764752876cSChristophe Lombard 			if ((rc = device_create_file(&adapter->dev, dev_attr)))
477f204e0b8SIan Munsie 				goto err;
478f204e0b8SIan Munsie 		}
4794752876cSChristophe Lombard 	}
480f204e0b8SIan Munsie 	return 0;
481f204e0b8SIan Munsie err:
4824752876cSChristophe Lombard 	for (i--; i >= 0; i--) {
4834752876cSChristophe Lombard 		dev_attr = &adapter_attrs[i];
4844752876cSChristophe Lombard 		if (cxl_ops->support_attributes(dev_attr->attr.name,
4854752876cSChristophe Lombard 						CXL_ADAPTER_ATTRS))
4864752876cSChristophe Lombard 			device_remove_file(&adapter->dev, dev_attr);
4874752876cSChristophe Lombard 	}
488f204e0b8SIan Munsie 	return rc;
489f204e0b8SIan Munsie }
4904752876cSChristophe Lombard 
cxl_sysfs_adapter_remove(struct cxl * adapter)491f204e0b8SIan Munsie void cxl_sysfs_adapter_remove(struct cxl *adapter)
492f204e0b8SIan Munsie {
4934752876cSChristophe Lombard 	struct device_attribute *dev_attr;
494f204e0b8SIan Munsie 	int i;
495f204e0b8SIan Munsie 
4964752876cSChristophe Lombard 	for (i = 0; i < ARRAY_SIZE(adapter_attrs); i++) {
4974752876cSChristophe Lombard 		dev_attr = &adapter_attrs[i];
4984752876cSChristophe Lombard 		if (cxl_ops->support_attributes(dev_attr->attr.name,
4994752876cSChristophe Lombard 						CXL_ADAPTER_ATTRS))
5004752876cSChristophe Lombard 			device_remove_file(&adapter->dev, dev_attr);
5014752876cSChristophe Lombard 	}
502f204e0b8SIan Munsie }
503f204e0b8SIan Munsie 
504b087e619SIan Munsie struct afu_config_record {
505b087e619SIan Munsie 	struct kobject kobj;
506b087e619SIan Munsie 	struct bin_attribute config_attr;
507b087e619SIan Munsie 	struct list_head list;
508b087e619SIan Munsie 	int cr;
509b087e619SIan Munsie 	u16 device;
510b087e619SIan Munsie 	u16 vendor;
511b087e619SIan Munsie 	u32 class;
512b087e619SIan Munsie };
513b087e619SIan Munsie 
514b087e619SIan Munsie #define to_cr(obj) container_of(obj, struct afu_config_record, kobj)
515b087e619SIan Munsie 
vendor_show(struct kobject * kobj,struct kobj_attribute * attr,char * buf)516b087e619SIan Munsie static ssize_t vendor_show(struct kobject *kobj,
517b087e619SIan Munsie 			   struct kobj_attribute *attr, char *buf)
518b087e619SIan Munsie {
519b087e619SIan Munsie 	struct afu_config_record *cr = to_cr(kobj);
520b087e619SIan Munsie 
521b087e619SIan Munsie 	return scnprintf(buf, PAGE_SIZE, "0x%.4x\n", cr->vendor);
522b087e619SIan Munsie }
523b087e619SIan Munsie 
device_show(struct kobject * kobj,struct kobj_attribute * attr,char * buf)524b087e619SIan Munsie static ssize_t device_show(struct kobject *kobj,
525b087e619SIan Munsie 			   struct kobj_attribute *attr, char *buf)
526b087e619SIan Munsie {
527b087e619SIan Munsie 	struct afu_config_record *cr = to_cr(kobj);
528b087e619SIan Munsie 
529b087e619SIan Munsie 	return scnprintf(buf, PAGE_SIZE, "0x%.4x\n", cr->device);
530b087e619SIan Munsie }
531b087e619SIan Munsie 
class_show(struct kobject * kobj,struct kobj_attribute * attr,char * buf)532b087e619SIan Munsie static ssize_t class_show(struct kobject *kobj,
533b087e619SIan Munsie 			  struct kobj_attribute *attr, char *buf)
534b087e619SIan Munsie {
535b087e619SIan Munsie 	struct afu_config_record *cr = to_cr(kobj);
536b087e619SIan Munsie 
537b087e619SIan Munsie 	return scnprintf(buf, PAGE_SIZE, "0x%.6x\n", cr->class);
538b087e619SIan Munsie }
539b087e619SIan Munsie 
afu_read_config(struct file * filp,struct kobject * kobj,struct bin_attribute * bin_attr,char * buf,loff_t off,size_t count)540b087e619SIan Munsie static ssize_t afu_read_config(struct file *filp, struct kobject *kobj,
541b087e619SIan Munsie 			       struct bin_attribute *bin_attr, char *buf,
542b087e619SIan Munsie 			       loff_t off, size_t count)
543b087e619SIan Munsie {
544b087e619SIan Munsie 	struct afu_config_record *cr = to_cr(kobj);
54585016ff3SGeliang Tang 	struct cxl_afu *afu = to_cxl_afu(kobj_to_dev(kobj->parent));
546b087e619SIan Munsie 
5475be587b1SFrederic Barrat 	u64 i, j, val, rc;
548b087e619SIan Munsie 
549b087e619SIan Munsie 	for (i = 0; i < count;) {
5505be587b1SFrederic Barrat 		rc = cxl_ops->afu_cr_read64(afu, cr->cr, off & ~0x7, &val);
5515be587b1SFrederic Barrat 		if (rc)
5525be587b1SFrederic Barrat 			val = ~0ULL;
553b087e619SIan Munsie 		for (j = off & 0x7; j < 8 && i < count; i++, j++, off++)
554b087e619SIan Munsie 			buf[i] = (val >> (j * 8)) & 0xff;
555b087e619SIan Munsie 	}
556b087e619SIan Munsie 
557b087e619SIan Munsie 	return count;
558b087e619SIan Munsie }
559b087e619SIan Munsie 
560b087e619SIan Munsie static struct kobj_attribute vendor_attribute =
561b087e619SIan Munsie 	__ATTR_RO(vendor);
562b087e619SIan Munsie static struct kobj_attribute device_attribute =
563b087e619SIan Munsie 	__ATTR_RO(device);
564b087e619SIan Munsie static struct kobj_attribute class_attribute =
565b087e619SIan Munsie 	__ATTR_RO(class);
566b087e619SIan Munsie 
567b087e619SIan Munsie static struct attribute *afu_cr_attrs[] = {
568b087e619SIan Munsie 	&vendor_attribute.attr,
569b087e619SIan Munsie 	&device_attribute.attr,
570b087e619SIan Munsie 	&class_attribute.attr,
571b087e619SIan Munsie 	NULL,
572b087e619SIan Munsie };
57363064451SGreg Kroah-Hartman ATTRIBUTE_GROUPS(afu_cr);
574b087e619SIan Munsie 
release_afu_config_record(struct kobject * kobj)575b087e619SIan Munsie static void release_afu_config_record(struct kobject *kobj)
576b087e619SIan Munsie {
577b087e619SIan Munsie 	struct afu_config_record *cr = to_cr(kobj);
578b087e619SIan Munsie 
579b087e619SIan Munsie 	kfree(cr);
580b087e619SIan Munsie }
581b087e619SIan Munsie 
582*5c09cfa5SHongbo Li static const struct kobj_type afu_config_record_type = {
583b087e619SIan Munsie 	.sysfs_ops = &kobj_sysfs_ops,
584b087e619SIan Munsie 	.release = release_afu_config_record,
58563064451SGreg Kroah-Hartman 	.default_groups = afu_cr_groups,
586b087e619SIan Munsie };
587b087e619SIan Munsie 
cxl_sysfs_afu_new_cr(struct cxl_afu * afu,int cr_idx)588b087e619SIan Munsie static struct afu_config_record *cxl_sysfs_afu_new_cr(struct cxl_afu *afu, int cr_idx)
589b087e619SIan Munsie {
590b087e619SIan Munsie 	struct afu_config_record *cr;
591b087e619SIan Munsie 	int rc;
592b087e619SIan Munsie 
593b087e619SIan Munsie 	cr = kzalloc(sizeof(struct afu_config_record), GFP_KERNEL);
594b087e619SIan Munsie 	if (!cr)
595b087e619SIan Munsie 		return ERR_PTR(-ENOMEM);
596b087e619SIan Munsie 
597b087e619SIan Munsie 	cr->cr = cr_idx;
5985be587b1SFrederic Barrat 
5995be587b1SFrederic Barrat 	rc = cxl_ops->afu_cr_read16(afu, cr_idx, PCI_DEVICE_ID, &cr->device);
6005be587b1SFrederic Barrat 	if (rc)
6015be587b1SFrederic Barrat 		goto err;
6025be587b1SFrederic Barrat 	rc = cxl_ops->afu_cr_read16(afu, cr_idx, PCI_VENDOR_ID, &cr->vendor);
6035be587b1SFrederic Barrat 	if (rc)
6045be587b1SFrederic Barrat 		goto err;
6055be587b1SFrederic Barrat 	rc = cxl_ops->afu_cr_read32(afu, cr_idx, PCI_CLASS_REVISION, &cr->class);
6065be587b1SFrederic Barrat 	if (rc)
6075be587b1SFrederic Barrat 		goto err;
6085be587b1SFrederic Barrat 	cr->class >>= 8;
609b087e619SIan Munsie 
610b087e619SIan Munsie 	/*
611b087e619SIan Munsie 	 * Export raw AFU PCIe like config record. For now this is read only by
612b087e619SIan Munsie 	 * root - we can expand that later to be readable by non-root and maybe
6134752876cSChristophe Lombard 	 * even writable provided we have a good use-case. Once we support
614b087e619SIan Munsie 	 * exposing AFUs through a virtual PHB they will get that for free from
615b087e619SIan Munsie 	 * Linux' PCI infrastructure, but until then it's not clear that we
616b087e619SIan Munsie 	 * need it for anything since the main use case is just identifying
617b087e619SIan Munsie 	 * AFUs, which can be done via the vendor, device and class attributes.
618b087e619SIan Munsie 	 */
619b087e619SIan Munsie 	sysfs_bin_attr_init(&cr->config_attr);
620b087e619SIan Munsie 	cr->config_attr.attr.name = "config";
621b087e619SIan Munsie 	cr->config_attr.attr.mode = S_IRUSR;
622b087e619SIan Munsie 	cr->config_attr.size = afu->crs_len;
623b087e619SIan Munsie 	cr->config_attr.read = afu_read_config;
624b087e619SIan Munsie 
625b087e619SIan Munsie 	rc = kobject_init_and_add(&cr->kobj, &afu_config_record_type,
626b087e619SIan Munsie 				  &afu->dev.kobj, "cr%i", cr->cr);
627b087e619SIan Munsie 	if (rc)
62885c5cbebSWang Hai 		goto err1;
629b087e619SIan Munsie 
630b087e619SIan Munsie 	rc = sysfs_create_bin_file(&cr->kobj, &cr->config_attr);
631b087e619SIan Munsie 	if (rc)
632b087e619SIan Munsie 		goto err1;
633b087e619SIan Munsie 
634b087e619SIan Munsie 	rc = kobject_uevent(&cr->kobj, KOBJ_ADD);
635b087e619SIan Munsie 	if (rc)
636b087e619SIan Munsie 		goto err2;
637b087e619SIan Munsie 
638b087e619SIan Munsie 	return cr;
639b087e619SIan Munsie err2:
640b087e619SIan Munsie 	sysfs_remove_bin_file(&cr->kobj, &cr->config_attr);
641b087e619SIan Munsie err1:
642b087e619SIan Munsie 	kobject_put(&cr->kobj);
643b087e619SIan Munsie 	return ERR_PTR(rc);
644b087e619SIan Munsie err:
645b087e619SIan Munsie 	kfree(cr);
646b087e619SIan Munsie 	return ERR_PTR(rc);
647b087e619SIan Munsie }
648b087e619SIan Munsie 
cxl_sysfs_afu_remove(struct cxl_afu * afu)649b087e619SIan Munsie void cxl_sysfs_afu_remove(struct cxl_afu *afu)
650b087e619SIan Munsie {
6514752876cSChristophe Lombard 	struct device_attribute *dev_attr;
652b087e619SIan Munsie 	struct afu_config_record *cr, *tmp;
653b087e619SIan Munsie 	int i;
654b087e619SIan Munsie 
655e36f6fe1SVaibhav Jain 	/* remove the err buffer bin attribute */
656e36f6fe1SVaibhav Jain 	if (afu->eb_len)
657e36f6fe1SVaibhav Jain 		device_remove_bin_file(&afu->dev, &afu->attr_eb);
658e36f6fe1SVaibhav Jain 
6594752876cSChristophe Lombard 	for (i = 0; i < ARRAY_SIZE(afu_attrs); i++) {
6604752876cSChristophe Lombard 		dev_attr = &afu_attrs[i];
6614752876cSChristophe Lombard 		if (cxl_ops->support_attributes(dev_attr->attr.name,
6624752876cSChristophe Lombard 						CXL_AFU_ATTRS))
663b087e619SIan Munsie 			device_remove_file(&afu->dev, &afu_attrs[i]);
6644752876cSChristophe Lombard 	}
665b087e619SIan Munsie 
666b087e619SIan Munsie 	list_for_each_entry_safe(cr, tmp, &afu->crs, list) {
667b087e619SIan Munsie 		sysfs_remove_bin_file(&cr->kobj, &cr->config_attr);
668b087e619SIan Munsie 		kobject_put(&cr->kobj);
669b087e619SIan Munsie 	}
670b087e619SIan Munsie }
671b087e619SIan Munsie 
cxl_sysfs_afu_add(struct cxl_afu * afu)672f204e0b8SIan Munsie int cxl_sysfs_afu_add(struct cxl_afu *afu)
673f204e0b8SIan Munsie {
6744752876cSChristophe Lombard 	struct device_attribute *dev_attr;
675b087e619SIan Munsie 	struct afu_config_record *cr;
676f204e0b8SIan Munsie 	int i, rc;
677f204e0b8SIan Munsie 
678b087e619SIan Munsie 	INIT_LIST_HEAD(&afu->crs);
679b087e619SIan Munsie 
680f204e0b8SIan Munsie 	for (i = 0; i < ARRAY_SIZE(afu_attrs); i++) {
6814752876cSChristophe Lombard 		dev_attr = &afu_attrs[i];
6824752876cSChristophe Lombard 		if (cxl_ops->support_attributes(dev_attr->attr.name,
6834752876cSChristophe Lombard 						CXL_AFU_ATTRS)) {
684f204e0b8SIan Munsie 			if ((rc = device_create_file(&afu->dev, &afu_attrs[i])))
685f204e0b8SIan Munsie 				goto err;
686f204e0b8SIan Munsie 		}
6874752876cSChristophe Lombard 	}
688f204e0b8SIan Munsie 
689e36f6fe1SVaibhav Jain 	/* conditionally create the add the binary file for error info buffer */
690e36f6fe1SVaibhav Jain 	if (afu->eb_len) {
691d6eb71a6SVaibhav Jain 		sysfs_attr_init(&afu->attr_eb.attr);
692d6eb71a6SVaibhav Jain 
693e36f6fe1SVaibhav Jain 		afu->attr_eb.attr.name = "afu_err_buff";
694e36f6fe1SVaibhav Jain 		afu->attr_eb.attr.mode = S_IRUGO;
695e36f6fe1SVaibhav Jain 		afu->attr_eb.size = afu->eb_len;
696e36f6fe1SVaibhav Jain 		afu->attr_eb.read = afu_eb_read;
697e36f6fe1SVaibhav Jain 
698e36f6fe1SVaibhav Jain 		rc = device_create_bin_file(&afu->dev, &afu->attr_eb);
699e36f6fe1SVaibhav Jain 		if (rc) {
700e36f6fe1SVaibhav Jain 			dev_err(&afu->dev,
701e36f6fe1SVaibhav Jain 				"Unable to create eb attr for the afu. Err(%d)\n",
702e36f6fe1SVaibhav Jain 				rc);
703e36f6fe1SVaibhav Jain 			goto err;
704e36f6fe1SVaibhav Jain 		}
705e36f6fe1SVaibhav Jain 	}
706e36f6fe1SVaibhav Jain 
707b087e619SIan Munsie 	for (i = 0; i < afu->crs_num; i++) {
708b087e619SIan Munsie 		cr = cxl_sysfs_afu_new_cr(afu, i);
709b087e619SIan Munsie 		if (IS_ERR(cr)) {
710b087e619SIan Munsie 			rc = PTR_ERR(cr);
711b087e619SIan Munsie 			goto err1;
712b087e619SIan Munsie 		}
713b087e619SIan Munsie 		list_add(&cr->list, &afu->crs);
714b087e619SIan Munsie 	}
715b087e619SIan Munsie 
716f204e0b8SIan Munsie 	return 0;
717f204e0b8SIan Munsie 
718b087e619SIan Munsie err1:
719b087e619SIan Munsie 	cxl_sysfs_afu_remove(afu);
720b087e619SIan Munsie 	return rc;
721f204e0b8SIan Munsie err:
722e36f6fe1SVaibhav Jain 	/* reset the eb_len as we havent created the bin attr */
723e36f6fe1SVaibhav Jain 	afu->eb_len = 0;
724e36f6fe1SVaibhav Jain 
7254752876cSChristophe Lombard 	for (i--; i >= 0; i--) {
7264752876cSChristophe Lombard 		dev_attr = &afu_attrs[i];
7274752876cSChristophe Lombard 		if (cxl_ops->support_attributes(dev_attr->attr.name,
7284752876cSChristophe Lombard 						CXL_AFU_ATTRS))
729f204e0b8SIan Munsie 		device_remove_file(&afu->dev, &afu_attrs[i]);
7304752876cSChristophe Lombard 	}
731f204e0b8SIan Munsie 	return rc;
732f204e0b8SIan Munsie }
733f204e0b8SIan Munsie 
cxl_sysfs_afu_m_add(struct cxl_afu * afu)734f204e0b8SIan Munsie int cxl_sysfs_afu_m_add(struct cxl_afu *afu)
735f204e0b8SIan Munsie {
7364752876cSChristophe Lombard 	struct device_attribute *dev_attr;
737f204e0b8SIan Munsie 	int i, rc;
738f204e0b8SIan Munsie 
739f204e0b8SIan Munsie 	for (i = 0; i < ARRAY_SIZE(afu_master_attrs); i++) {
7404752876cSChristophe Lombard 		dev_attr = &afu_master_attrs[i];
7414752876cSChristophe Lombard 		if (cxl_ops->support_attributes(dev_attr->attr.name,
7424752876cSChristophe Lombard 						CXL_AFU_MASTER_ATTRS)) {
743f204e0b8SIan Munsie 			if ((rc = device_create_file(afu->chardev_m, &afu_master_attrs[i])))
744f204e0b8SIan Munsie 				goto err;
745f204e0b8SIan Munsie 		}
7464752876cSChristophe Lombard 	}
747f204e0b8SIan Munsie 
748f204e0b8SIan Munsie 	return 0;
749f204e0b8SIan Munsie 
750f204e0b8SIan Munsie err:
7514752876cSChristophe Lombard 	for (i--; i >= 0; i--) {
7524752876cSChristophe Lombard 		dev_attr = &afu_master_attrs[i];
7534752876cSChristophe Lombard 		if (cxl_ops->support_attributes(dev_attr->attr.name,
7544752876cSChristophe Lombard 						CXL_AFU_MASTER_ATTRS))
755f204e0b8SIan Munsie 			device_remove_file(afu->chardev_m, &afu_master_attrs[i]);
7564752876cSChristophe Lombard 	}
757f204e0b8SIan Munsie 	return rc;
758f204e0b8SIan Munsie }
759f204e0b8SIan Munsie 
cxl_sysfs_afu_m_remove(struct cxl_afu * afu)760f204e0b8SIan Munsie void cxl_sysfs_afu_m_remove(struct cxl_afu *afu)
761f204e0b8SIan Munsie {
7624752876cSChristophe Lombard 	struct device_attribute *dev_attr;
763f204e0b8SIan Munsie 	int i;
764f204e0b8SIan Munsie 
7654752876cSChristophe Lombard 	for (i = 0; i < ARRAY_SIZE(afu_master_attrs); i++) {
7664752876cSChristophe Lombard 		dev_attr = &afu_master_attrs[i];
7674752876cSChristophe Lombard 		if (cxl_ops->support_attributes(dev_attr->attr.name,
7684752876cSChristophe Lombard 						CXL_AFU_MASTER_ATTRS))
769f204e0b8SIan Munsie 			device_remove_file(afu->chardev_m, &afu_master_attrs[i]);
770f204e0b8SIan Munsie 	}
7714752876cSChristophe Lombard }
772