xref: /OK3568_Linux_fs/kernel/drivers/misc/cxl/sysfs.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-or-later
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * Copyright 2014 IBM Corp.
4*4882a593Smuzhiyun  */
5*4882a593Smuzhiyun 
6*4882a593Smuzhiyun #include <linux/kernel.h>
7*4882a593Smuzhiyun #include <linux/device.h>
8*4882a593Smuzhiyun #include <linux/sysfs.h>
9*4882a593Smuzhiyun #include <linux/pci_regs.h>
10*4882a593Smuzhiyun 
11*4882a593Smuzhiyun #include "cxl.h"
12*4882a593Smuzhiyun 
13*4882a593Smuzhiyun #define to_afu_chardev_m(d) dev_get_drvdata(d)
14*4882a593Smuzhiyun 
15*4882a593Smuzhiyun /*********  Adapter attributes  **********************************************/
16*4882a593Smuzhiyun 
caia_version_show(struct device * device,struct device_attribute * attr,char * buf)17*4882a593Smuzhiyun static ssize_t caia_version_show(struct device *device,
18*4882a593Smuzhiyun 				 struct device_attribute *attr,
19*4882a593Smuzhiyun 				 char *buf)
20*4882a593Smuzhiyun {
21*4882a593Smuzhiyun 	struct cxl *adapter = to_cxl_adapter(device);
22*4882a593Smuzhiyun 
23*4882a593Smuzhiyun 	return scnprintf(buf, PAGE_SIZE, "%i.%i\n", adapter->caia_major,
24*4882a593Smuzhiyun 			 adapter->caia_minor);
25*4882a593Smuzhiyun }
26*4882a593Smuzhiyun 
psl_revision_show(struct device * device,struct device_attribute * attr,char * buf)27*4882a593Smuzhiyun static ssize_t psl_revision_show(struct device *device,
28*4882a593Smuzhiyun 				 struct device_attribute *attr,
29*4882a593Smuzhiyun 				 char *buf)
30*4882a593Smuzhiyun {
31*4882a593Smuzhiyun 	struct cxl *adapter = to_cxl_adapter(device);
32*4882a593Smuzhiyun 
33*4882a593Smuzhiyun 	return scnprintf(buf, PAGE_SIZE, "%i\n", adapter->psl_rev);
34*4882a593Smuzhiyun }
35*4882a593Smuzhiyun 
base_image_show(struct device * device,struct device_attribute * attr,char * buf)36*4882a593Smuzhiyun static ssize_t base_image_show(struct device *device,
37*4882a593Smuzhiyun 			       struct device_attribute *attr,
38*4882a593Smuzhiyun 			       char *buf)
39*4882a593Smuzhiyun {
40*4882a593Smuzhiyun 	struct cxl *adapter = to_cxl_adapter(device);
41*4882a593Smuzhiyun 
42*4882a593Smuzhiyun 	return scnprintf(buf, PAGE_SIZE, "%i\n", adapter->base_image);
43*4882a593Smuzhiyun }
44*4882a593Smuzhiyun 
image_loaded_show(struct device * device,struct device_attribute * attr,char * buf)45*4882a593Smuzhiyun static ssize_t image_loaded_show(struct device *device,
46*4882a593Smuzhiyun 				 struct device_attribute *attr,
47*4882a593Smuzhiyun 				 char *buf)
48*4882a593Smuzhiyun {
49*4882a593Smuzhiyun 	struct cxl *adapter = to_cxl_adapter(device);
50*4882a593Smuzhiyun 
51*4882a593Smuzhiyun 	if (adapter->user_image_loaded)
52*4882a593Smuzhiyun 		return scnprintf(buf, PAGE_SIZE, "user\n");
53*4882a593Smuzhiyun 	return scnprintf(buf, PAGE_SIZE, "factory\n");
54*4882a593Smuzhiyun }
55*4882a593Smuzhiyun 
psl_timebase_synced_show(struct device * device,struct device_attribute * attr,char * buf)56*4882a593Smuzhiyun static ssize_t psl_timebase_synced_show(struct device *device,
57*4882a593Smuzhiyun 					struct device_attribute *attr,
58*4882a593Smuzhiyun 					char *buf)
59*4882a593Smuzhiyun {
60*4882a593Smuzhiyun 	struct cxl *adapter = to_cxl_adapter(device);
61*4882a593Smuzhiyun 	u64 psl_tb, delta;
62*4882a593Smuzhiyun 
63*4882a593Smuzhiyun 	/* Recompute the status only in native mode */
64*4882a593Smuzhiyun 	if (cpu_has_feature(CPU_FTR_HVMODE)) {
65*4882a593Smuzhiyun 		psl_tb = adapter->native->sl_ops->timebase_read(adapter);
66*4882a593Smuzhiyun 		delta = abs(mftb() - psl_tb);
67*4882a593Smuzhiyun 
68*4882a593Smuzhiyun 		/* CORE TB and PSL TB difference <= 16usecs ? */
69*4882a593Smuzhiyun 		adapter->psl_timebase_synced = (tb_to_ns(delta) < 16000) ? true : false;
70*4882a593Smuzhiyun 		pr_devel("PSL timebase %s - delta: 0x%016llx\n",
71*4882a593Smuzhiyun 			 (tb_to_ns(delta) < 16000) ? "synchronized" :
72*4882a593Smuzhiyun 			 "not synchronized", tb_to_ns(delta));
73*4882a593Smuzhiyun 	}
74*4882a593Smuzhiyun 	return scnprintf(buf, PAGE_SIZE, "%i\n", adapter->psl_timebase_synced);
75*4882a593Smuzhiyun }
76*4882a593Smuzhiyun 
tunneled_ops_supported_show(struct device * device,struct device_attribute * attr,char * buf)77*4882a593Smuzhiyun static ssize_t tunneled_ops_supported_show(struct device *device,
78*4882a593Smuzhiyun 					struct device_attribute *attr,
79*4882a593Smuzhiyun 					char *buf)
80*4882a593Smuzhiyun {
81*4882a593Smuzhiyun 	struct cxl *adapter = to_cxl_adapter(device);
82*4882a593Smuzhiyun 
83*4882a593Smuzhiyun 	return scnprintf(buf, PAGE_SIZE, "%i\n", adapter->tunneled_ops_supported);
84*4882a593Smuzhiyun }
85*4882a593Smuzhiyun 
reset_adapter_store(struct device * device,struct device_attribute * attr,const char * buf,size_t count)86*4882a593Smuzhiyun static ssize_t reset_adapter_store(struct device *device,
87*4882a593Smuzhiyun 				   struct device_attribute *attr,
88*4882a593Smuzhiyun 				   const char *buf, size_t count)
89*4882a593Smuzhiyun {
90*4882a593Smuzhiyun 	struct cxl *adapter = to_cxl_adapter(device);
91*4882a593Smuzhiyun 	int rc;
92*4882a593Smuzhiyun 	int val;
93*4882a593Smuzhiyun 
94*4882a593Smuzhiyun 	rc = sscanf(buf, "%i", &val);
95*4882a593Smuzhiyun 	if ((rc != 1) || (val != 1 && val != -1))
96*4882a593Smuzhiyun 		return -EINVAL;
97*4882a593Smuzhiyun 
98*4882a593Smuzhiyun 	/*
99*4882a593Smuzhiyun 	 * See if we can lock the context mapping that's only allowed
100*4882a593Smuzhiyun 	 * when there are no contexts attached to the adapter. Once
101*4882a593Smuzhiyun 	 * taken this will also prevent any context from getting activated.
102*4882a593Smuzhiyun 	 */
103*4882a593Smuzhiyun 	if (val == 1) {
104*4882a593Smuzhiyun 		rc =  cxl_adapter_context_lock(adapter);
105*4882a593Smuzhiyun 		if (rc)
106*4882a593Smuzhiyun 			goto out;
107*4882a593Smuzhiyun 
108*4882a593Smuzhiyun 		rc = cxl_ops->adapter_reset(adapter);
109*4882a593Smuzhiyun 		/* In case reset failed release context lock */
110*4882a593Smuzhiyun 		if (rc)
111*4882a593Smuzhiyun 			cxl_adapter_context_unlock(adapter);
112*4882a593Smuzhiyun 
113*4882a593Smuzhiyun 	} else if (val == -1) {
114*4882a593Smuzhiyun 		/* Perform a forced adapter reset */
115*4882a593Smuzhiyun 		rc = cxl_ops->adapter_reset(adapter);
116*4882a593Smuzhiyun 	}
117*4882a593Smuzhiyun 
118*4882a593Smuzhiyun out:
119*4882a593Smuzhiyun 	return rc ? rc : count;
120*4882a593Smuzhiyun }
121*4882a593Smuzhiyun 
load_image_on_perst_show(struct device * device,struct device_attribute * attr,char * buf)122*4882a593Smuzhiyun static ssize_t load_image_on_perst_show(struct device *device,
123*4882a593Smuzhiyun 				 struct device_attribute *attr,
124*4882a593Smuzhiyun 				 char *buf)
125*4882a593Smuzhiyun {
126*4882a593Smuzhiyun 	struct cxl *adapter = to_cxl_adapter(device);
127*4882a593Smuzhiyun 
128*4882a593Smuzhiyun 	if (!adapter->perst_loads_image)
129*4882a593Smuzhiyun 		return scnprintf(buf, PAGE_SIZE, "none\n");
130*4882a593Smuzhiyun 
131*4882a593Smuzhiyun 	if (adapter->perst_select_user)
132*4882a593Smuzhiyun 		return scnprintf(buf, PAGE_SIZE, "user\n");
133*4882a593Smuzhiyun 	return scnprintf(buf, PAGE_SIZE, "factory\n");
134*4882a593Smuzhiyun }
135*4882a593Smuzhiyun 
load_image_on_perst_store(struct device * device,struct device_attribute * attr,const char * buf,size_t count)136*4882a593Smuzhiyun static ssize_t load_image_on_perst_store(struct device *device,
137*4882a593Smuzhiyun 				 struct device_attribute *attr,
138*4882a593Smuzhiyun 				 const char *buf, size_t count)
139*4882a593Smuzhiyun {
140*4882a593Smuzhiyun 	struct cxl *adapter = to_cxl_adapter(device);
141*4882a593Smuzhiyun 	int rc;
142*4882a593Smuzhiyun 
143*4882a593Smuzhiyun 	if (!strncmp(buf, "none", 4))
144*4882a593Smuzhiyun 		adapter->perst_loads_image = false;
145*4882a593Smuzhiyun 	else if (!strncmp(buf, "user", 4)) {
146*4882a593Smuzhiyun 		adapter->perst_select_user = true;
147*4882a593Smuzhiyun 		adapter->perst_loads_image = true;
148*4882a593Smuzhiyun 	} else if (!strncmp(buf, "factory", 7)) {
149*4882a593Smuzhiyun 		adapter->perst_select_user = false;
150*4882a593Smuzhiyun 		adapter->perst_loads_image = true;
151*4882a593Smuzhiyun 	} else
152*4882a593Smuzhiyun 		return -EINVAL;
153*4882a593Smuzhiyun 
154*4882a593Smuzhiyun 	if ((rc = cxl_update_image_control(adapter)))
155*4882a593Smuzhiyun 		return rc;
156*4882a593Smuzhiyun 
157*4882a593Smuzhiyun 	return count;
158*4882a593Smuzhiyun }
159*4882a593Smuzhiyun 
perst_reloads_same_image_show(struct device * device,struct device_attribute * attr,char * buf)160*4882a593Smuzhiyun static ssize_t perst_reloads_same_image_show(struct device *device,
161*4882a593Smuzhiyun 				 struct device_attribute *attr,
162*4882a593Smuzhiyun 				 char *buf)
163*4882a593Smuzhiyun {
164*4882a593Smuzhiyun 	struct cxl *adapter = to_cxl_adapter(device);
165*4882a593Smuzhiyun 
166*4882a593Smuzhiyun 	return scnprintf(buf, PAGE_SIZE, "%i\n", adapter->perst_same_image);
167*4882a593Smuzhiyun }
168*4882a593Smuzhiyun 
perst_reloads_same_image_store(struct device * device,struct device_attribute * attr,const char * buf,size_t count)169*4882a593Smuzhiyun static ssize_t perst_reloads_same_image_store(struct device *device,
170*4882a593Smuzhiyun 				 struct device_attribute *attr,
171*4882a593Smuzhiyun 				 const char *buf, size_t count)
172*4882a593Smuzhiyun {
173*4882a593Smuzhiyun 	struct cxl *adapter = to_cxl_adapter(device);
174*4882a593Smuzhiyun 	int rc;
175*4882a593Smuzhiyun 	int val;
176*4882a593Smuzhiyun 
177*4882a593Smuzhiyun 	rc = sscanf(buf, "%i", &val);
178*4882a593Smuzhiyun 	if ((rc != 1) || !(val == 1 || val == 0))
179*4882a593Smuzhiyun 		return -EINVAL;
180*4882a593Smuzhiyun 
181*4882a593Smuzhiyun 	adapter->perst_same_image = (val == 1 ? true : false);
182*4882a593Smuzhiyun 	return count;
183*4882a593Smuzhiyun }
184*4882a593Smuzhiyun 
185*4882a593Smuzhiyun static struct device_attribute adapter_attrs[] = {
186*4882a593Smuzhiyun 	__ATTR_RO(caia_version),
187*4882a593Smuzhiyun 	__ATTR_RO(psl_revision),
188*4882a593Smuzhiyun 	__ATTR_RO(base_image),
189*4882a593Smuzhiyun 	__ATTR_RO(image_loaded),
190*4882a593Smuzhiyun 	__ATTR_RO(psl_timebase_synced),
191*4882a593Smuzhiyun 	__ATTR_RO(tunneled_ops_supported),
192*4882a593Smuzhiyun 	__ATTR_RW(load_image_on_perst),
193*4882a593Smuzhiyun 	__ATTR_RW(perst_reloads_same_image),
194*4882a593Smuzhiyun 	__ATTR(reset, S_IWUSR, NULL, reset_adapter_store),
195*4882a593Smuzhiyun };
196*4882a593Smuzhiyun 
197*4882a593Smuzhiyun 
198*4882a593Smuzhiyun /*********  AFU master specific attributes  **********************************/
199*4882a593Smuzhiyun 
mmio_size_show_master(struct device * device,struct device_attribute * attr,char * buf)200*4882a593Smuzhiyun static ssize_t mmio_size_show_master(struct device *device,
201*4882a593Smuzhiyun 				     struct device_attribute *attr,
202*4882a593Smuzhiyun 				     char *buf)
203*4882a593Smuzhiyun {
204*4882a593Smuzhiyun 	struct cxl_afu *afu = to_afu_chardev_m(device);
205*4882a593Smuzhiyun 
206*4882a593Smuzhiyun 	return scnprintf(buf, PAGE_SIZE, "%llu\n", afu->adapter->ps_size);
207*4882a593Smuzhiyun }
208*4882a593Smuzhiyun 
pp_mmio_off_show(struct device * device,struct device_attribute * attr,char * buf)209*4882a593Smuzhiyun static ssize_t pp_mmio_off_show(struct device *device,
210*4882a593Smuzhiyun 				struct device_attribute *attr,
211*4882a593Smuzhiyun 				char *buf)
212*4882a593Smuzhiyun {
213*4882a593Smuzhiyun 	struct cxl_afu *afu = to_afu_chardev_m(device);
214*4882a593Smuzhiyun 
215*4882a593Smuzhiyun 	return scnprintf(buf, PAGE_SIZE, "%llu\n", afu->native->pp_offset);
216*4882a593Smuzhiyun }
217*4882a593Smuzhiyun 
pp_mmio_len_show(struct device * device,struct device_attribute * attr,char * buf)218*4882a593Smuzhiyun static ssize_t pp_mmio_len_show(struct device *device,
219*4882a593Smuzhiyun 				struct device_attribute *attr,
220*4882a593Smuzhiyun 				char *buf)
221*4882a593Smuzhiyun {
222*4882a593Smuzhiyun 	struct cxl_afu *afu = to_afu_chardev_m(device);
223*4882a593Smuzhiyun 
224*4882a593Smuzhiyun 	return scnprintf(buf, PAGE_SIZE, "%llu\n", afu->pp_size);
225*4882a593Smuzhiyun }
226*4882a593Smuzhiyun 
227*4882a593Smuzhiyun static struct device_attribute afu_master_attrs[] = {
228*4882a593Smuzhiyun 	__ATTR(mmio_size, S_IRUGO, mmio_size_show_master, NULL),
229*4882a593Smuzhiyun 	__ATTR_RO(pp_mmio_off),
230*4882a593Smuzhiyun 	__ATTR_RO(pp_mmio_len),
231*4882a593Smuzhiyun };
232*4882a593Smuzhiyun 
233*4882a593Smuzhiyun 
234*4882a593Smuzhiyun /*********  AFU attributes  **************************************************/
235*4882a593Smuzhiyun 
mmio_size_show(struct device * device,struct device_attribute * attr,char * buf)236*4882a593Smuzhiyun static ssize_t mmio_size_show(struct device *device,
237*4882a593Smuzhiyun 			      struct device_attribute *attr,
238*4882a593Smuzhiyun 			      char *buf)
239*4882a593Smuzhiyun {
240*4882a593Smuzhiyun 	struct cxl_afu *afu = to_cxl_afu(device);
241*4882a593Smuzhiyun 
242*4882a593Smuzhiyun 	if (afu->pp_size)
243*4882a593Smuzhiyun 		return scnprintf(buf, PAGE_SIZE, "%llu\n", afu->pp_size);
244*4882a593Smuzhiyun 	return scnprintf(buf, PAGE_SIZE, "%llu\n", afu->adapter->ps_size);
245*4882a593Smuzhiyun }
246*4882a593Smuzhiyun 
reset_store_afu(struct device * device,struct device_attribute * attr,const char * buf,size_t count)247*4882a593Smuzhiyun static ssize_t reset_store_afu(struct device *device,
248*4882a593Smuzhiyun 			       struct device_attribute *attr,
249*4882a593Smuzhiyun 			       const char *buf, size_t count)
250*4882a593Smuzhiyun {
251*4882a593Smuzhiyun 	struct cxl_afu *afu = to_cxl_afu(device);
252*4882a593Smuzhiyun 	int rc;
253*4882a593Smuzhiyun 
254*4882a593Smuzhiyun 	/* Not safe to reset if it is currently in use */
255*4882a593Smuzhiyun 	mutex_lock(&afu->contexts_lock);
256*4882a593Smuzhiyun 	if (!idr_is_empty(&afu->contexts_idr)) {
257*4882a593Smuzhiyun 		rc = -EBUSY;
258*4882a593Smuzhiyun 		goto err;
259*4882a593Smuzhiyun 	}
260*4882a593Smuzhiyun 
261*4882a593Smuzhiyun 	if ((rc = cxl_ops->afu_reset(afu)))
262*4882a593Smuzhiyun 		goto err;
263*4882a593Smuzhiyun 
264*4882a593Smuzhiyun 	rc = count;
265*4882a593Smuzhiyun err:
266*4882a593Smuzhiyun 	mutex_unlock(&afu->contexts_lock);
267*4882a593Smuzhiyun 	return rc;
268*4882a593Smuzhiyun }
269*4882a593Smuzhiyun 
irqs_min_show(struct device * device,struct device_attribute * attr,char * buf)270*4882a593Smuzhiyun static ssize_t irqs_min_show(struct device *device,
271*4882a593Smuzhiyun 			     struct device_attribute *attr,
272*4882a593Smuzhiyun 			     char *buf)
273*4882a593Smuzhiyun {
274*4882a593Smuzhiyun 	struct cxl_afu *afu = to_cxl_afu(device);
275*4882a593Smuzhiyun 
276*4882a593Smuzhiyun 	return scnprintf(buf, PAGE_SIZE, "%i\n", afu->pp_irqs);
277*4882a593Smuzhiyun }
278*4882a593Smuzhiyun 
irqs_max_show(struct device * device,struct device_attribute * attr,char * buf)279*4882a593Smuzhiyun static ssize_t irqs_max_show(struct device *device,
280*4882a593Smuzhiyun 				  struct device_attribute *attr,
281*4882a593Smuzhiyun 				  char *buf)
282*4882a593Smuzhiyun {
283*4882a593Smuzhiyun 	struct cxl_afu *afu = to_cxl_afu(device);
284*4882a593Smuzhiyun 
285*4882a593Smuzhiyun 	return scnprintf(buf, PAGE_SIZE, "%i\n", afu->irqs_max);
286*4882a593Smuzhiyun }
287*4882a593Smuzhiyun 
irqs_max_store(struct device * device,struct device_attribute * attr,const char * buf,size_t count)288*4882a593Smuzhiyun static ssize_t irqs_max_store(struct device *device,
289*4882a593Smuzhiyun 				  struct device_attribute *attr,
290*4882a593Smuzhiyun 				  const char *buf, size_t count)
291*4882a593Smuzhiyun {
292*4882a593Smuzhiyun 	struct cxl_afu *afu = to_cxl_afu(device);
293*4882a593Smuzhiyun 	ssize_t ret;
294*4882a593Smuzhiyun 	int irqs_max;
295*4882a593Smuzhiyun 
296*4882a593Smuzhiyun 	ret = sscanf(buf, "%i", &irqs_max);
297*4882a593Smuzhiyun 	if (ret != 1)
298*4882a593Smuzhiyun 		return -EINVAL;
299*4882a593Smuzhiyun 
300*4882a593Smuzhiyun 	if (irqs_max < afu->pp_irqs)
301*4882a593Smuzhiyun 		return -EINVAL;
302*4882a593Smuzhiyun 
303*4882a593Smuzhiyun 	if (cpu_has_feature(CPU_FTR_HVMODE)) {
304*4882a593Smuzhiyun 		if (irqs_max > afu->adapter->user_irqs)
305*4882a593Smuzhiyun 			return -EINVAL;
306*4882a593Smuzhiyun 	} else {
307*4882a593Smuzhiyun 		/* pHyp sets a per-AFU limit */
308*4882a593Smuzhiyun 		if (irqs_max > afu->guest->max_ints)
309*4882a593Smuzhiyun 			return -EINVAL;
310*4882a593Smuzhiyun 	}
311*4882a593Smuzhiyun 
312*4882a593Smuzhiyun 	afu->irqs_max = irqs_max;
313*4882a593Smuzhiyun 	return count;
314*4882a593Smuzhiyun }
315*4882a593Smuzhiyun 
modes_supported_show(struct device * device,struct device_attribute * attr,char * buf)316*4882a593Smuzhiyun static ssize_t modes_supported_show(struct device *device,
317*4882a593Smuzhiyun 				    struct device_attribute *attr, char *buf)
318*4882a593Smuzhiyun {
319*4882a593Smuzhiyun 	struct cxl_afu *afu = to_cxl_afu(device);
320*4882a593Smuzhiyun 	char *p = buf, *end = buf + PAGE_SIZE;
321*4882a593Smuzhiyun 
322*4882a593Smuzhiyun 	if (afu->modes_supported & CXL_MODE_DEDICATED)
323*4882a593Smuzhiyun 		p += scnprintf(p, end - p, "dedicated_process\n");
324*4882a593Smuzhiyun 	if (afu->modes_supported & CXL_MODE_DIRECTED)
325*4882a593Smuzhiyun 		p += scnprintf(p, end - p, "afu_directed\n");
326*4882a593Smuzhiyun 	return (p - buf);
327*4882a593Smuzhiyun }
328*4882a593Smuzhiyun 
prefault_mode_show(struct device * device,struct device_attribute * attr,char * buf)329*4882a593Smuzhiyun static ssize_t prefault_mode_show(struct device *device,
330*4882a593Smuzhiyun 				  struct device_attribute *attr,
331*4882a593Smuzhiyun 				  char *buf)
332*4882a593Smuzhiyun {
333*4882a593Smuzhiyun 	struct cxl_afu *afu = to_cxl_afu(device);
334*4882a593Smuzhiyun 
335*4882a593Smuzhiyun 	switch (afu->prefault_mode) {
336*4882a593Smuzhiyun 	case CXL_PREFAULT_WED:
337*4882a593Smuzhiyun 		return scnprintf(buf, PAGE_SIZE, "work_element_descriptor\n");
338*4882a593Smuzhiyun 	case CXL_PREFAULT_ALL:
339*4882a593Smuzhiyun 		return scnprintf(buf, PAGE_SIZE, "all\n");
340*4882a593Smuzhiyun 	default:
341*4882a593Smuzhiyun 		return scnprintf(buf, PAGE_SIZE, "none\n");
342*4882a593Smuzhiyun 	}
343*4882a593Smuzhiyun }
344*4882a593Smuzhiyun 
prefault_mode_store(struct device * device,struct device_attribute * attr,const char * buf,size_t count)345*4882a593Smuzhiyun static ssize_t prefault_mode_store(struct device *device,
346*4882a593Smuzhiyun 			  struct device_attribute *attr,
347*4882a593Smuzhiyun 			  const char *buf, size_t count)
348*4882a593Smuzhiyun {
349*4882a593Smuzhiyun 	struct cxl_afu *afu = to_cxl_afu(device);
350*4882a593Smuzhiyun 	enum prefault_modes mode = -1;
351*4882a593Smuzhiyun 
352*4882a593Smuzhiyun 	if (!strncmp(buf, "none", 4))
353*4882a593Smuzhiyun 		mode = CXL_PREFAULT_NONE;
354*4882a593Smuzhiyun 	else {
355*4882a593Smuzhiyun 		if (!radix_enabled()) {
356*4882a593Smuzhiyun 
357*4882a593Smuzhiyun 			/* only allowed when not in radix mode */
358*4882a593Smuzhiyun 			if (!strncmp(buf, "work_element_descriptor", 23))
359*4882a593Smuzhiyun 				mode = CXL_PREFAULT_WED;
360*4882a593Smuzhiyun 			if (!strncmp(buf, "all", 3))
361*4882a593Smuzhiyun 				mode = CXL_PREFAULT_ALL;
362*4882a593Smuzhiyun 		} else {
363*4882a593Smuzhiyun 			dev_err(device, "Cannot prefault with radix enabled\n");
364*4882a593Smuzhiyun 		}
365*4882a593Smuzhiyun 	}
366*4882a593Smuzhiyun 
367*4882a593Smuzhiyun 	if (mode == -1)
368*4882a593Smuzhiyun 		return -EINVAL;
369*4882a593Smuzhiyun 
370*4882a593Smuzhiyun 	afu->prefault_mode = mode;
371*4882a593Smuzhiyun 	return count;
372*4882a593Smuzhiyun }
373*4882a593Smuzhiyun 
mode_show(struct device * device,struct device_attribute * attr,char * buf)374*4882a593Smuzhiyun static ssize_t mode_show(struct device *device,
375*4882a593Smuzhiyun 			 struct device_attribute *attr,
376*4882a593Smuzhiyun 			 char *buf)
377*4882a593Smuzhiyun {
378*4882a593Smuzhiyun 	struct cxl_afu *afu = to_cxl_afu(device);
379*4882a593Smuzhiyun 
380*4882a593Smuzhiyun 	if (afu->current_mode == CXL_MODE_DEDICATED)
381*4882a593Smuzhiyun 		return scnprintf(buf, PAGE_SIZE, "dedicated_process\n");
382*4882a593Smuzhiyun 	if (afu->current_mode == CXL_MODE_DIRECTED)
383*4882a593Smuzhiyun 		return scnprintf(buf, PAGE_SIZE, "afu_directed\n");
384*4882a593Smuzhiyun 	return scnprintf(buf, PAGE_SIZE, "none\n");
385*4882a593Smuzhiyun }
386*4882a593Smuzhiyun 
mode_store(struct device * device,struct device_attribute * attr,const char * buf,size_t count)387*4882a593Smuzhiyun static ssize_t mode_store(struct device *device, struct device_attribute *attr,
388*4882a593Smuzhiyun 			  const char *buf, size_t count)
389*4882a593Smuzhiyun {
390*4882a593Smuzhiyun 	struct cxl_afu *afu = to_cxl_afu(device);
391*4882a593Smuzhiyun 	int old_mode, mode = -1;
392*4882a593Smuzhiyun 	int rc = -EBUSY;
393*4882a593Smuzhiyun 
394*4882a593Smuzhiyun 	/* can't change this if we have a user */
395*4882a593Smuzhiyun 	mutex_lock(&afu->contexts_lock);
396*4882a593Smuzhiyun 	if (!idr_is_empty(&afu->contexts_idr))
397*4882a593Smuzhiyun 		goto err;
398*4882a593Smuzhiyun 
399*4882a593Smuzhiyun 	if (!strncmp(buf, "dedicated_process", 17))
400*4882a593Smuzhiyun 		mode = CXL_MODE_DEDICATED;
401*4882a593Smuzhiyun 	if (!strncmp(buf, "afu_directed", 12))
402*4882a593Smuzhiyun 		mode = CXL_MODE_DIRECTED;
403*4882a593Smuzhiyun 	if (!strncmp(buf, "none", 4))
404*4882a593Smuzhiyun 		mode = 0;
405*4882a593Smuzhiyun 
406*4882a593Smuzhiyun 	if (mode == -1) {
407*4882a593Smuzhiyun 		rc = -EINVAL;
408*4882a593Smuzhiyun 		goto err;
409*4882a593Smuzhiyun 	}
410*4882a593Smuzhiyun 
411*4882a593Smuzhiyun 	/*
412*4882a593Smuzhiyun 	 * afu_deactivate_mode needs to be done outside the lock, prevent
413*4882a593Smuzhiyun 	 * other contexts coming in before we are ready:
414*4882a593Smuzhiyun 	 */
415*4882a593Smuzhiyun 	old_mode = afu->current_mode;
416*4882a593Smuzhiyun 	afu->current_mode = 0;
417*4882a593Smuzhiyun 	afu->num_procs = 0;
418*4882a593Smuzhiyun 
419*4882a593Smuzhiyun 	mutex_unlock(&afu->contexts_lock);
420*4882a593Smuzhiyun 
421*4882a593Smuzhiyun 	if ((rc = cxl_ops->afu_deactivate_mode(afu, old_mode)))
422*4882a593Smuzhiyun 		return rc;
423*4882a593Smuzhiyun 	if ((rc = cxl_ops->afu_activate_mode(afu, mode)))
424*4882a593Smuzhiyun 		return rc;
425*4882a593Smuzhiyun 
426*4882a593Smuzhiyun 	return count;
427*4882a593Smuzhiyun err:
428*4882a593Smuzhiyun 	mutex_unlock(&afu->contexts_lock);
429*4882a593Smuzhiyun 	return rc;
430*4882a593Smuzhiyun }
431*4882a593Smuzhiyun 
api_version_show(struct device * device,struct device_attribute * attr,char * buf)432*4882a593Smuzhiyun static ssize_t api_version_show(struct device *device,
433*4882a593Smuzhiyun 				struct device_attribute *attr,
434*4882a593Smuzhiyun 				char *buf)
435*4882a593Smuzhiyun {
436*4882a593Smuzhiyun 	return scnprintf(buf, PAGE_SIZE, "%i\n", CXL_API_VERSION);
437*4882a593Smuzhiyun }
438*4882a593Smuzhiyun 
api_version_compatible_show(struct device * device,struct device_attribute * attr,char * buf)439*4882a593Smuzhiyun static ssize_t api_version_compatible_show(struct device *device,
440*4882a593Smuzhiyun 					   struct device_attribute *attr,
441*4882a593Smuzhiyun 					   char *buf)
442*4882a593Smuzhiyun {
443*4882a593Smuzhiyun 	return scnprintf(buf, PAGE_SIZE, "%i\n", CXL_API_VERSION_COMPATIBLE);
444*4882a593Smuzhiyun }
445*4882a593Smuzhiyun 
afu_eb_read(struct file * filp,struct kobject * kobj,struct bin_attribute * bin_attr,char * buf,loff_t off,size_t count)446*4882a593Smuzhiyun static ssize_t afu_eb_read(struct file *filp, struct kobject *kobj,
447*4882a593Smuzhiyun 			       struct bin_attribute *bin_attr, char *buf,
448*4882a593Smuzhiyun 			       loff_t off, size_t count)
449*4882a593Smuzhiyun {
450*4882a593Smuzhiyun 	struct cxl_afu *afu = to_cxl_afu(kobj_to_dev(kobj));
451*4882a593Smuzhiyun 
452*4882a593Smuzhiyun 	return cxl_ops->afu_read_err_buffer(afu, buf, off, count);
453*4882a593Smuzhiyun }
454*4882a593Smuzhiyun 
455*4882a593Smuzhiyun static struct device_attribute afu_attrs[] = {
456*4882a593Smuzhiyun 	__ATTR_RO(mmio_size),
457*4882a593Smuzhiyun 	__ATTR_RO(irqs_min),
458*4882a593Smuzhiyun 	__ATTR_RW(irqs_max),
459*4882a593Smuzhiyun 	__ATTR_RO(modes_supported),
460*4882a593Smuzhiyun 	__ATTR_RW(mode),
461*4882a593Smuzhiyun 	__ATTR_RW(prefault_mode),
462*4882a593Smuzhiyun 	__ATTR_RO(api_version),
463*4882a593Smuzhiyun 	__ATTR_RO(api_version_compatible),
464*4882a593Smuzhiyun 	__ATTR(reset, S_IWUSR, NULL, reset_store_afu),
465*4882a593Smuzhiyun };
466*4882a593Smuzhiyun 
cxl_sysfs_adapter_add(struct cxl * adapter)467*4882a593Smuzhiyun int cxl_sysfs_adapter_add(struct cxl *adapter)
468*4882a593Smuzhiyun {
469*4882a593Smuzhiyun 	struct device_attribute *dev_attr;
470*4882a593Smuzhiyun 	int i, rc;
471*4882a593Smuzhiyun 
472*4882a593Smuzhiyun 	for (i = 0; i < ARRAY_SIZE(adapter_attrs); i++) {
473*4882a593Smuzhiyun 		dev_attr = &adapter_attrs[i];
474*4882a593Smuzhiyun 		if (cxl_ops->support_attributes(dev_attr->attr.name,
475*4882a593Smuzhiyun 						CXL_ADAPTER_ATTRS)) {
476*4882a593Smuzhiyun 			if ((rc = device_create_file(&adapter->dev, dev_attr)))
477*4882a593Smuzhiyun 				goto err;
478*4882a593Smuzhiyun 		}
479*4882a593Smuzhiyun 	}
480*4882a593Smuzhiyun 	return 0;
481*4882a593Smuzhiyun err:
482*4882a593Smuzhiyun 	for (i--; i >= 0; i--) {
483*4882a593Smuzhiyun 		dev_attr = &adapter_attrs[i];
484*4882a593Smuzhiyun 		if (cxl_ops->support_attributes(dev_attr->attr.name,
485*4882a593Smuzhiyun 						CXL_ADAPTER_ATTRS))
486*4882a593Smuzhiyun 			device_remove_file(&adapter->dev, dev_attr);
487*4882a593Smuzhiyun 	}
488*4882a593Smuzhiyun 	return rc;
489*4882a593Smuzhiyun }
490*4882a593Smuzhiyun 
cxl_sysfs_adapter_remove(struct cxl * adapter)491*4882a593Smuzhiyun void cxl_sysfs_adapter_remove(struct cxl *adapter)
492*4882a593Smuzhiyun {
493*4882a593Smuzhiyun 	struct device_attribute *dev_attr;
494*4882a593Smuzhiyun 	int i;
495*4882a593Smuzhiyun 
496*4882a593Smuzhiyun 	for (i = 0; i < ARRAY_SIZE(adapter_attrs); i++) {
497*4882a593Smuzhiyun 		dev_attr = &adapter_attrs[i];
498*4882a593Smuzhiyun 		if (cxl_ops->support_attributes(dev_attr->attr.name,
499*4882a593Smuzhiyun 						CXL_ADAPTER_ATTRS))
500*4882a593Smuzhiyun 			device_remove_file(&adapter->dev, dev_attr);
501*4882a593Smuzhiyun 	}
502*4882a593Smuzhiyun }
503*4882a593Smuzhiyun 
504*4882a593Smuzhiyun struct afu_config_record {
505*4882a593Smuzhiyun 	struct kobject kobj;
506*4882a593Smuzhiyun 	struct bin_attribute config_attr;
507*4882a593Smuzhiyun 	struct list_head list;
508*4882a593Smuzhiyun 	int cr;
509*4882a593Smuzhiyun 	u16 device;
510*4882a593Smuzhiyun 	u16 vendor;
511*4882a593Smuzhiyun 	u32 class;
512*4882a593Smuzhiyun };
513*4882a593Smuzhiyun 
514*4882a593Smuzhiyun #define to_cr(obj) container_of(obj, struct afu_config_record, kobj)
515*4882a593Smuzhiyun 
vendor_show(struct kobject * kobj,struct kobj_attribute * attr,char * buf)516*4882a593Smuzhiyun static ssize_t vendor_show(struct kobject *kobj,
517*4882a593Smuzhiyun 			   struct kobj_attribute *attr, char *buf)
518*4882a593Smuzhiyun {
519*4882a593Smuzhiyun 	struct afu_config_record *cr = to_cr(kobj);
520*4882a593Smuzhiyun 
521*4882a593Smuzhiyun 	return scnprintf(buf, PAGE_SIZE, "0x%.4x\n", cr->vendor);
522*4882a593Smuzhiyun }
523*4882a593Smuzhiyun 
device_show(struct kobject * kobj,struct kobj_attribute * attr,char * buf)524*4882a593Smuzhiyun static ssize_t device_show(struct kobject *kobj,
525*4882a593Smuzhiyun 			   struct kobj_attribute *attr, char *buf)
526*4882a593Smuzhiyun {
527*4882a593Smuzhiyun 	struct afu_config_record *cr = to_cr(kobj);
528*4882a593Smuzhiyun 
529*4882a593Smuzhiyun 	return scnprintf(buf, PAGE_SIZE, "0x%.4x\n", cr->device);
530*4882a593Smuzhiyun }
531*4882a593Smuzhiyun 
class_show(struct kobject * kobj,struct kobj_attribute * attr,char * buf)532*4882a593Smuzhiyun static ssize_t class_show(struct kobject *kobj,
533*4882a593Smuzhiyun 			  struct kobj_attribute *attr, char *buf)
534*4882a593Smuzhiyun {
535*4882a593Smuzhiyun 	struct afu_config_record *cr = to_cr(kobj);
536*4882a593Smuzhiyun 
537*4882a593Smuzhiyun 	return scnprintf(buf, PAGE_SIZE, "0x%.6x\n", cr->class);
538*4882a593Smuzhiyun }
539*4882a593Smuzhiyun 
afu_read_config(struct file * filp,struct kobject * kobj,struct bin_attribute * bin_attr,char * buf,loff_t off,size_t count)540*4882a593Smuzhiyun static ssize_t afu_read_config(struct file *filp, struct kobject *kobj,
541*4882a593Smuzhiyun 			       struct bin_attribute *bin_attr, char *buf,
542*4882a593Smuzhiyun 			       loff_t off, size_t count)
543*4882a593Smuzhiyun {
544*4882a593Smuzhiyun 	struct afu_config_record *cr = to_cr(kobj);
545*4882a593Smuzhiyun 	struct cxl_afu *afu = to_cxl_afu(kobj_to_dev(kobj->parent));
546*4882a593Smuzhiyun 
547*4882a593Smuzhiyun 	u64 i, j, val, rc;
548*4882a593Smuzhiyun 
549*4882a593Smuzhiyun 	for (i = 0; i < count;) {
550*4882a593Smuzhiyun 		rc = cxl_ops->afu_cr_read64(afu, cr->cr, off & ~0x7, &val);
551*4882a593Smuzhiyun 		if (rc)
552*4882a593Smuzhiyun 			val = ~0ULL;
553*4882a593Smuzhiyun 		for (j = off & 0x7; j < 8 && i < count; i++, j++, off++)
554*4882a593Smuzhiyun 			buf[i] = (val >> (j * 8)) & 0xff;
555*4882a593Smuzhiyun 	}
556*4882a593Smuzhiyun 
557*4882a593Smuzhiyun 	return count;
558*4882a593Smuzhiyun }
559*4882a593Smuzhiyun 
560*4882a593Smuzhiyun static struct kobj_attribute vendor_attribute =
561*4882a593Smuzhiyun 	__ATTR_RO(vendor);
562*4882a593Smuzhiyun static struct kobj_attribute device_attribute =
563*4882a593Smuzhiyun 	__ATTR_RO(device);
564*4882a593Smuzhiyun static struct kobj_attribute class_attribute =
565*4882a593Smuzhiyun 	__ATTR_RO(class);
566*4882a593Smuzhiyun 
567*4882a593Smuzhiyun static struct attribute *afu_cr_attrs[] = {
568*4882a593Smuzhiyun 	&vendor_attribute.attr,
569*4882a593Smuzhiyun 	&device_attribute.attr,
570*4882a593Smuzhiyun 	&class_attribute.attr,
571*4882a593Smuzhiyun 	NULL,
572*4882a593Smuzhiyun };
573*4882a593Smuzhiyun 
release_afu_config_record(struct kobject * kobj)574*4882a593Smuzhiyun static void release_afu_config_record(struct kobject *kobj)
575*4882a593Smuzhiyun {
576*4882a593Smuzhiyun 	struct afu_config_record *cr = to_cr(kobj);
577*4882a593Smuzhiyun 
578*4882a593Smuzhiyun 	kfree(cr);
579*4882a593Smuzhiyun }
580*4882a593Smuzhiyun 
581*4882a593Smuzhiyun static struct kobj_type afu_config_record_type = {
582*4882a593Smuzhiyun 	.sysfs_ops = &kobj_sysfs_ops,
583*4882a593Smuzhiyun 	.release = release_afu_config_record,
584*4882a593Smuzhiyun 	.default_attrs = afu_cr_attrs,
585*4882a593Smuzhiyun };
586*4882a593Smuzhiyun 
cxl_sysfs_afu_new_cr(struct cxl_afu * afu,int cr_idx)587*4882a593Smuzhiyun static struct afu_config_record *cxl_sysfs_afu_new_cr(struct cxl_afu *afu, int cr_idx)
588*4882a593Smuzhiyun {
589*4882a593Smuzhiyun 	struct afu_config_record *cr;
590*4882a593Smuzhiyun 	int rc;
591*4882a593Smuzhiyun 
592*4882a593Smuzhiyun 	cr = kzalloc(sizeof(struct afu_config_record), GFP_KERNEL);
593*4882a593Smuzhiyun 	if (!cr)
594*4882a593Smuzhiyun 		return ERR_PTR(-ENOMEM);
595*4882a593Smuzhiyun 
596*4882a593Smuzhiyun 	cr->cr = cr_idx;
597*4882a593Smuzhiyun 
598*4882a593Smuzhiyun 	rc = cxl_ops->afu_cr_read16(afu, cr_idx, PCI_DEVICE_ID, &cr->device);
599*4882a593Smuzhiyun 	if (rc)
600*4882a593Smuzhiyun 		goto err;
601*4882a593Smuzhiyun 	rc = cxl_ops->afu_cr_read16(afu, cr_idx, PCI_VENDOR_ID, &cr->vendor);
602*4882a593Smuzhiyun 	if (rc)
603*4882a593Smuzhiyun 		goto err;
604*4882a593Smuzhiyun 	rc = cxl_ops->afu_cr_read32(afu, cr_idx, PCI_CLASS_REVISION, &cr->class);
605*4882a593Smuzhiyun 	if (rc)
606*4882a593Smuzhiyun 		goto err;
607*4882a593Smuzhiyun 	cr->class >>= 8;
608*4882a593Smuzhiyun 
609*4882a593Smuzhiyun 	/*
610*4882a593Smuzhiyun 	 * Export raw AFU PCIe like config record. For now this is read only by
611*4882a593Smuzhiyun 	 * root - we can expand that later to be readable by non-root and maybe
612*4882a593Smuzhiyun 	 * even writable provided we have a good use-case. Once we support
613*4882a593Smuzhiyun 	 * exposing AFUs through a virtual PHB they will get that for free from
614*4882a593Smuzhiyun 	 * Linux' PCI infrastructure, but until then it's not clear that we
615*4882a593Smuzhiyun 	 * need it for anything since the main use case is just identifying
616*4882a593Smuzhiyun 	 * AFUs, which can be done via the vendor, device and class attributes.
617*4882a593Smuzhiyun 	 */
618*4882a593Smuzhiyun 	sysfs_bin_attr_init(&cr->config_attr);
619*4882a593Smuzhiyun 	cr->config_attr.attr.name = "config";
620*4882a593Smuzhiyun 	cr->config_attr.attr.mode = S_IRUSR;
621*4882a593Smuzhiyun 	cr->config_attr.size = afu->crs_len;
622*4882a593Smuzhiyun 	cr->config_attr.read = afu_read_config;
623*4882a593Smuzhiyun 
624*4882a593Smuzhiyun 	rc = kobject_init_and_add(&cr->kobj, &afu_config_record_type,
625*4882a593Smuzhiyun 				  &afu->dev.kobj, "cr%i", cr->cr);
626*4882a593Smuzhiyun 	if (rc)
627*4882a593Smuzhiyun 		goto err1;
628*4882a593Smuzhiyun 
629*4882a593Smuzhiyun 	rc = sysfs_create_bin_file(&cr->kobj, &cr->config_attr);
630*4882a593Smuzhiyun 	if (rc)
631*4882a593Smuzhiyun 		goto err1;
632*4882a593Smuzhiyun 
633*4882a593Smuzhiyun 	rc = kobject_uevent(&cr->kobj, KOBJ_ADD);
634*4882a593Smuzhiyun 	if (rc)
635*4882a593Smuzhiyun 		goto err2;
636*4882a593Smuzhiyun 
637*4882a593Smuzhiyun 	return cr;
638*4882a593Smuzhiyun err2:
639*4882a593Smuzhiyun 	sysfs_remove_bin_file(&cr->kobj, &cr->config_attr);
640*4882a593Smuzhiyun err1:
641*4882a593Smuzhiyun 	kobject_put(&cr->kobj);
642*4882a593Smuzhiyun 	return ERR_PTR(rc);
643*4882a593Smuzhiyun err:
644*4882a593Smuzhiyun 	kfree(cr);
645*4882a593Smuzhiyun 	return ERR_PTR(rc);
646*4882a593Smuzhiyun }
647*4882a593Smuzhiyun 
cxl_sysfs_afu_remove(struct cxl_afu * afu)648*4882a593Smuzhiyun void cxl_sysfs_afu_remove(struct cxl_afu *afu)
649*4882a593Smuzhiyun {
650*4882a593Smuzhiyun 	struct device_attribute *dev_attr;
651*4882a593Smuzhiyun 	struct afu_config_record *cr, *tmp;
652*4882a593Smuzhiyun 	int i;
653*4882a593Smuzhiyun 
654*4882a593Smuzhiyun 	/* remove the err buffer bin attribute */
655*4882a593Smuzhiyun 	if (afu->eb_len)
656*4882a593Smuzhiyun 		device_remove_bin_file(&afu->dev, &afu->attr_eb);
657*4882a593Smuzhiyun 
658*4882a593Smuzhiyun 	for (i = 0; i < ARRAY_SIZE(afu_attrs); i++) {
659*4882a593Smuzhiyun 		dev_attr = &afu_attrs[i];
660*4882a593Smuzhiyun 		if (cxl_ops->support_attributes(dev_attr->attr.name,
661*4882a593Smuzhiyun 						CXL_AFU_ATTRS))
662*4882a593Smuzhiyun 			device_remove_file(&afu->dev, &afu_attrs[i]);
663*4882a593Smuzhiyun 	}
664*4882a593Smuzhiyun 
665*4882a593Smuzhiyun 	list_for_each_entry_safe(cr, tmp, &afu->crs, list) {
666*4882a593Smuzhiyun 		sysfs_remove_bin_file(&cr->kobj, &cr->config_attr);
667*4882a593Smuzhiyun 		kobject_put(&cr->kobj);
668*4882a593Smuzhiyun 	}
669*4882a593Smuzhiyun }
670*4882a593Smuzhiyun 
cxl_sysfs_afu_add(struct cxl_afu * afu)671*4882a593Smuzhiyun int cxl_sysfs_afu_add(struct cxl_afu *afu)
672*4882a593Smuzhiyun {
673*4882a593Smuzhiyun 	struct device_attribute *dev_attr;
674*4882a593Smuzhiyun 	struct afu_config_record *cr;
675*4882a593Smuzhiyun 	int i, rc;
676*4882a593Smuzhiyun 
677*4882a593Smuzhiyun 	INIT_LIST_HEAD(&afu->crs);
678*4882a593Smuzhiyun 
679*4882a593Smuzhiyun 	for (i = 0; i < ARRAY_SIZE(afu_attrs); i++) {
680*4882a593Smuzhiyun 		dev_attr = &afu_attrs[i];
681*4882a593Smuzhiyun 		if (cxl_ops->support_attributes(dev_attr->attr.name,
682*4882a593Smuzhiyun 						CXL_AFU_ATTRS)) {
683*4882a593Smuzhiyun 			if ((rc = device_create_file(&afu->dev, &afu_attrs[i])))
684*4882a593Smuzhiyun 				goto err;
685*4882a593Smuzhiyun 		}
686*4882a593Smuzhiyun 	}
687*4882a593Smuzhiyun 
688*4882a593Smuzhiyun 	/* conditionally create the add the binary file for error info buffer */
689*4882a593Smuzhiyun 	if (afu->eb_len) {
690*4882a593Smuzhiyun 		sysfs_attr_init(&afu->attr_eb.attr);
691*4882a593Smuzhiyun 
692*4882a593Smuzhiyun 		afu->attr_eb.attr.name = "afu_err_buff";
693*4882a593Smuzhiyun 		afu->attr_eb.attr.mode = S_IRUGO;
694*4882a593Smuzhiyun 		afu->attr_eb.size = afu->eb_len;
695*4882a593Smuzhiyun 		afu->attr_eb.read = afu_eb_read;
696*4882a593Smuzhiyun 
697*4882a593Smuzhiyun 		rc = device_create_bin_file(&afu->dev, &afu->attr_eb);
698*4882a593Smuzhiyun 		if (rc) {
699*4882a593Smuzhiyun 			dev_err(&afu->dev,
700*4882a593Smuzhiyun 				"Unable to create eb attr for the afu. Err(%d)\n",
701*4882a593Smuzhiyun 				rc);
702*4882a593Smuzhiyun 			goto err;
703*4882a593Smuzhiyun 		}
704*4882a593Smuzhiyun 	}
705*4882a593Smuzhiyun 
706*4882a593Smuzhiyun 	for (i = 0; i < afu->crs_num; i++) {
707*4882a593Smuzhiyun 		cr = cxl_sysfs_afu_new_cr(afu, i);
708*4882a593Smuzhiyun 		if (IS_ERR(cr)) {
709*4882a593Smuzhiyun 			rc = PTR_ERR(cr);
710*4882a593Smuzhiyun 			goto err1;
711*4882a593Smuzhiyun 		}
712*4882a593Smuzhiyun 		list_add(&cr->list, &afu->crs);
713*4882a593Smuzhiyun 	}
714*4882a593Smuzhiyun 
715*4882a593Smuzhiyun 	return 0;
716*4882a593Smuzhiyun 
717*4882a593Smuzhiyun err1:
718*4882a593Smuzhiyun 	cxl_sysfs_afu_remove(afu);
719*4882a593Smuzhiyun 	return rc;
720*4882a593Smuzhiyun err:
721*4882a593Smuzhiyun 	/* reset the eb_len as we havent created the bin attr */
722*4882a593Smuzhiyun 	afu->eb_len = 0;
723*4882a593Smuzhiyun 
724*4882a593Smuzhiyun 	for (i--; i >= 0; i--) {
725*4882a593Smuzhiyun 		dev_attr = &afu_attrs[i];
726*4882a593Smuzhiyun 		if (cxl_ops->support_attributes(dev_attr->attr.name,
727*4882a593Smuzhiyun 						CXL_AFU_ATTRS))
728*4882a593Smuzhiyun 		device_remove_file(&afu->dev, &afu_attrs[i]);
729*4882a593Smuzhiyun 	}
730*4882a593Smuzhiyun 	return rc;
731*4882a593Smuzhiyun }
732*4882a593Smuzhiyun 
cxl_sysfs_afu_m_add(struct cxl_afu * afu)733*4882a593Smuzhiyun int cxl_sysfs_afu_m_add(struct cxl_afu *afu)
734*4882a593Smuzhiyun {
735*4882a593Smuzhiyun 	struct device_attribute *dev_attr;
736*4882a593Smuzhiyun 	int i, rc;
737*4882a593Smuzhiyun 
738*4882a593Smuzhiyun 	for (i = 0; i < ARRAY_SIZE(afu_master_attrs); i++) {
739*4882a593Smuzhiyun 		dev_attr = &afu_master_attrs[i];
740*4882a593Smuzhiyun 		if (cxl_ops->support_attributes(dev_attr->attr.name,
741*4882a593Smuzhiyun 						CXL_AFU_MASTER_ATTRS)) {
742*4882a593Smuzhiyun 			if ((rc = device_create_file(afu->chardev_m, &afu_master_attrs[i])))
743*4882a593Smuzhiyun 				goto err;
744*4882a593Smuzhiyun 		}
745*4882a593Smuzhiyun 	}
746*4882a593Smuzhiyun 
747*4882a593Smuzhiyun 	return 0;
748*4882a593Smuzhiyun 
749*4882a593Smuzhiyun err:
750*4882a593Smuzhiyun 	for (i--; i >= 0; i--) {
751*4882a593Smuzhiyun 		dev_attr = &afu_master_attrs[i];
752*4882a593Smuzhiyun 		if (cxl_ops->support_attributes(dev_attr->attr.name,
753*4882a593Smuzhiyun 						CXL_AFU_MASTER_ATTRS))
754*4882a593Smuzhiyun 			device_remove_file(afu->chardev_m, &afu_master_attrs[i]);
755*4882a593Smuzhiyun 	}
756*4882a593Smuzhiyun 	return rc;
757*4882a593Smuzhiyun }
758*4882a593Smuzhiyun 
cxl_sysfs_afu_m_remove(struct cxl_afu * afu)759*4882a593Smuzhiyun void cxl_sysfs_afu_m_remove(struct cxl_afu *afu)
760*4882a593Smuzhiyun {
761*4882a593Smuzhiyun 	struct device_attribute *dev_attr;
762*4882a593Smuzhiyun 	int i;
763*4882a593Smuzhiyun 
764*4882a593Smuzhiyun 	for (i = 0; i < ARRAY_SIZE(afu_master_attrs); i++) {
765*4882a593Smuzhiyun 		dev_attr = &afu_master_attrs[i];
766*4882a593Smuzhiyun 		if (cxl_ops->support_attributes(dev_attr->attr.name,
767*4882a593Smuzhiyun 						CXL_AFU_MASTER_ATTRS))
768*4882a593Smuzhiyun 			device_remove_file(afu->chardev_m, &afu_master_attrs[i]);
769*4882a593Smuzhiyun 	}
770*4882a593Smuzhiyun }
771