xref: /linux/drivers/misc/cxl/sysfs.c (revision 70b565bbdb911023373e035225ab10077e4ab937)
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);
65e009a7e8SFrederic Barrat 
66e009a7e8SFrederic Barrat 	return scnprintf(buf, PAGE_SIZE, "%i\n", adapter->psl_timebase_synced);
67e009a7e8SFrederic Barrat }
68e009a7e8SFrederic Barrat 
6962fa19d4SRyan Grimm static ssize_t reset_adapter_store(struct device *device,
7062fa19d4SRyan Grimm 				   struct device_attribute *attr,
7162fa19d4SRyan Grimm 				   const char *buf, size_t count)
7262fa19d4SRyan Grimm {
7362fa19d4SRyan Grimm 	struct cxl *adapter = to_cxl_adapter(device);
7462fa19d4SRyan Grimm 	int rc;
7562fa19d4SRyan Grimm 	int val;
7662fa19d4SRyan Grimm 
7762fa19d4SRyan Grimm 	rc = sscanf(buf, "%i", &val);
78*70b565bbSVaibhav Jain 	if ((rc != 1) || (val != 1 && val != -1))
7962fa19d4SRyan Grimm 		return -EINVAL;
8062fa19d4SRyan Grimm 
81*70b565bbSVaibhav Jain 	/*
82*70b565bbSVaibhav Jain 	 * See if we can lock the context mapping that's only allowed
83*70b565bbSVaibhav Jain 	 * when there are no contexts attached to the adapter. Once
84*70b565bbSVaibhav Jain 	 * taken this will also prevent any context from getting activated.
85*70b565bbSVaibhav Jain 	 */
86*70b565bbSVaibhav Jain 	if (val == 1) {
87*70b565bbSVaibhav Jain 		rc =  cxl_adapter_context_lock(adapter);
88*70b565bbSVaibhav Jain 		if (rc)
89*70b565bbSVaibhav Jain 			goto out;
90*70b565bbSVaibhav Jain 
91*70b565bbSVaibhav Jain 		rc = cxl_ops->adapter_reset(adapter);
92*70b565bbSVaibhav Jain 		/* In case reset failed release context lock */
93*70b565bbSVaibhav Jain 		if (rc)
94*70b565bbSVaibhav Jain 			cxl_adapter_context_unlock(adapter);
95*70b565bbSVaibhav Jain 
96*70b565bbSVaibhav Jain 	} else if (val == -1) {
97*70b565bbSVaibhav Jain 		/* Perform a forced adapter reset */
98*70b565bbSVaibhav Jain 		rc = cxl_ops->adapter_reset(adapter);
99*70b565bbSVaibhav Jain 	}
100*70b565bbSVaibhav Jain 
101*70b565bbSVaibhav Jain out:
102*70b565bbSVaibhav Jain 	return rc ? rc : count;
10362fa19d4SRyan Grimm }
10462fa19d4SRyan Grimm 
10595bc11bcSRyan Grimm static ssize_t load_image_on_perst_show(struct device *device,
10695bc11bcSRyan Grimm 				 struct device_attribute *attr,
10795bc11bcSRyan Grimm 				 char *buf)
10895bc11bcSRyan Grimm {
10995bc11bcSRyan Grimm 	struct cxl *adapter = to_cxl_adapter(device);
11095bc11bcSRyan Grimm 
11195bc11bcSRyan Grimm 	if (!adapter->perst_loads_image)
11295bc11bcSRyan Grimm 		return scnprintf(buf, PAGE_SIZE, "none\n");
11395bc11bcSRyan Grimm 
11495bc11bcSRyan Grimm 	if (adapter->perst_select_user)
11595bc11bcSRyan Grimm 		return scnprintf(buf, PAGE_SIZE, "user\n");
11695bc11bcSRyan Grimm 	return scnprintf(buf, PAGE_SIZE, "factory\n");
11795bc11bcSRyan Grimm }
11895bc11bcSRyan Grimm 
11995bc11bcSRyan Grimm static ssize_t load_image_on_perst_store(struct device *device,
12095bc11bcSRyan Grimm 				 struct device_attribute *attr,
12195bc11bcSRyan Grimm 				 const char *buf, size_t count)
12295bc11bcSRyan Grimm {
12395bc11bcSRyan Grimm 	struct cxl *adapter = to_cxl_adapter(device);
12495bc11bcSRyan Grimm 	int rc;
12595bc11bcSRyan Grimm 
12695bc11bcSRyan Grimm 	if (!strncmp(buf, "none", 4))
12795bc11bcSRyan Grimm 		adapter->perst_loads_image = false;
12895bc11bcSRyan Grimm 	else if (!strncmp(buf, "user", 4)) {
12995bc11bcSRyan Grimm 		adapter->perst_select_user = true;
13095bc11bcSRyan Grimm 		adapter->perst_loads_image = true;
13195bc11bcSRyan Grimm 	} else if (!strncmp(buf, "factory", 7)) {
13295bc11bcSRyan Grimm 		adapter->perst_select_user = false;
13395bc11bcSRyan Grimm 		adapter->perst_loads_image = true;
13495bc11bcSRyan Grimm 	} else
13595bc11bcSRyan Grimm 		return -EINVAL;
13695bc11bcSRyan Grimm 
13795bc11bcSRyan Grimm 	if ((rc = cxl_update_image_control(adapter)))
13895bc11bcSRyan Grimm 		return rc;
13995bc11bcSRyan Grimm 
14095bc11bcSRyan Grimm 	return count;
14195bc11bcSRyan Grimm }
14295bc11bcSRyan Grimm 
14313e68d8bSDaniel Axtens static ssize_t perst_reloads_same_image_show(struct device *device,
14413e68d8bSDaniel Axtens 				 struct device_attribute *attr,
14513e68d8bSDaniel Axtens 				 char *buf)
14613e68d8bSDaniel Axtens {
14713e68d8bSDaniel Axtens 	struct cxl *adapter = to_cxl_adapter(device);
14813e68d8bSDaniel Axtens 
14913e68d8bSDaniel Axtens 	return scnprintf(buf, PAGE_SIZE, "%i\n", adapter->perst_same_image);
15013e68d8bSDaniel Axtens }
15113e68d8bSDaniel Axtens 
15213e68d8bSDaniel Axtens static ssize_t perst_reloads_same_image_store(struct device *device,
15313e68d8bSDaniel Axtens 				 struct device_attribute *attr,
15413e68d8bSDaniel Axtens 				 const char *buf, size_t count)
15513e68d8bSDaniel Axtens {
15613e68d8bSDaniel Axtens 	struct cxl *adapter = to_cxl_adapter(device);
15713e68d8bSDaniel Axtens 	int rc;
15813e68d8bSDaniel Axtens 	int val;
15913e68d8bSDaniel Axtens 
16013e68d8bSDaniel Axtens 	rc = sscanf(buf, "%i", &val);
16113e68d8bSDaniel Axtens 	if ((rc != 1) || !(val == 1 || val == 0))
16213e68d8bSDaniel Axtens 		return -EINVAL;
16313e68d8bSDaniel Axtens 
16413e68d8bSDaniel Axtens 	adapter->perst_same_image = (val == 1 ? true : false);
16513e68d8bSDaniel Axtens 	return count;
16613e68d8bSDaniel Axtens }
16713e68d8bSDaniel Axtens 
168f204e0b8SIan Munsie static struct device_attribute adapter_attrs[] = {
169f204e0b8SIan Munsie 	__ATTR_RO(caia_version),
170f204e0b8SIan Munsie 	__ATTR_RO(psl_revision),
171f204e0b8SIan Munsie 	__ATTR_RO(base_image),
172f204e0b8SIan Munsie 	__ATTR_RO(image_loaded),
173e009a7e8SFrederic Barrat 	__ATTR_RO(psl_timebase_synced),
17495bc11bcSRyan Grimm 	__ATTR_RW(load_image_on_perst),
17513e68d8bSDaniel Axtens 	__ATTR_RW(perst_reloads_same_image),
17662fa19d4SRyan Grimm 	__ATTR(reset, S_IWUSR, NULL, reset_adapter_store),
177f204e0b8SIan Munsie };
178f204e0b8SIan Munsie 
179f204e0b8SIan Munsie 
180f204e0b8SIan Munsie /*********  AFU master specific attributes  **********************************/
181f204e0b8SIan Munsie 
182f204e0b8SIan Munsie static ssize_t mmio_size_show_master(struct device *device,
183f204e0b8SIan Munsie 				     struct device_attribute *attr,
184f204e0b8SIan Munsie 				     char *buf)
185f204e0b8SIan Munsie {
186f204e0b8SIan Munsie 	struct cxl_afu *afu = to_afu_chardev_m(device);
187f204e0b8SIan Munsie 
188f204e0b8SIan Munsie 	return scnprintf(buf, PAGE_SIZE, "%llu\n", afu->adapter->ps_size);
189f204e0b8SIan Munsie }
190f204e0b8SIan Munsie 
191f204e0b8SIan Munsie static ssize_t pp_mmio_off_show(struct device *device,
192f204e0b8SIan Munsie 				struct device_attribute *attr,
193f204e0b8SIan Munsie 				char *buf)
194f204e0b8SIan Munsie {
195f204e0b8SIan Munsie 	struct cxl_afu *afu = to_afu_chardev_m(device);
196f204e0b8SIan Munsie 
197cbffa3a5SChristophe Lombard 	return scnprintf(buf, PAGE_SIZE, "%llu\n", afu->native->pp_offset);
198f204e0b8SIan Munsie }
199f204e0b8SIan Munsie 
200f204e0b8SIan Munsie static ssize_t pp_mmio_len_show(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->pp_size);
207f204e0b8SIan Munsie }
208f204e0b8SIan Munsie 
209f204e0b8SIan Munsie static struct device_attribute afu_master_attrs[] = {
210f204e0b8SIan Munsie 	__ATTR(mmio_size, S_IRUGO, mmio_size_show_master, NULL),
211f204e0b8SIan Munsie 	__ATTR_RO(pp_mmio_off),
212f204e0b8SIan Munsie 	__ATTR_RO(pp_mmio_len),
213f204e0b8SIan Munsie };
214f204e0b8SIan Munsie 
215f204e0b8SIan Munsie 
216f204e0b8SIan Munsie /*********  AFU attributes  **************************************************/
217f204e0b8SIan Munsie 
218f204e0b8SIan Munsie static ssize_t mmio_size_show(struct device *device,
219f204e0b8SIan Munsie 			      struct device_attribute *attr,
220f204e0b8SIan Munsie 			      char *buf)
221f204e0b8SIan Munsie {
222f204e0b8SIan Munsie 	struct cxl_afu *afu = to_cxl_afu(device);
223f204e0b8SIan Munsie 
224f204e0b8SIan Munsie 	if (afu->pp_size)
225f204e0b8SIan Munsie 		return scnprintf(buf, PAGE_SIZE, "%llu\n", afu->pp_size);
226f204e0b8SIan Munsie 	return scnprintf(buf, PAGE_SIZE, "%llu\n", afu->adapter->ps_size);
227f204e0b8SIan Munsie }
228f204e0b8SIan Munsie 
229f204e0b8SIan Munsie static ssize_t reset_store_afu(struct device *device,
230f204e0b8SIan Munsie 			       struct device_attribute *attr,
231f204e0b8SIan Munsie 			       const char *buf, size_t count)
232f204e0b8SIan Munsie {
233f204e0b8SIan Munsie 	struct cxl_afu *afu = to_cxl_afu(device);
234f204e0b8SIan Munsie 	int rc;
235f204e0b8SIan Munsie 
236f204e0b8SIan Munsie 	/* Not safe to reset if it is currently in use */
237ee41d11dSIan Munsie 	mutex_lock(&afu->contexts_lock);
238f204e0b8SIan Munsie 	if (!idr_is_empty(&afu->contexts_idr)) {
239f204e0b8SIan Munsie 		rc = -EBUSY;
240f204e0b8SIan Munsie 		goto err;
241f204e0b8SIan Munsie 	}
242f204e0b8SIan Munsie 
2435be587b1SFrederic Barrat 	if ((rc = cxl_ops->afu_reset(afu)))
244f204e0b8SIan Munsie 		goto err;
245f204e0b8SIan Munsie 
246f204e0b8SIan Munsie 	rc = count;
247f204e0b8SIan Munsie err:
248ee41d11dSIan Munsie 	mutex_unlock(&afu->contexts_lock);
249f204e0b8SIan Munsie 	return rc;
250f204e0b8SIan Munsie }
251f204e0b8SIan Munsie 
252f204e0b8SIan Munsie static ssize_t irqs_min_show(struct device *device,
253f204e0b8SIan Munsie 			     struct device_attribute *attr,
254f204e0b8SIan Munsie 			     char *buf)
255f204e0b8SIan Munsie {
256f204e0b8SIan Munsie 	struct cxl_afu *afu = to_cxl_afu(device);
257f204e0b8SIan Munsie 
258f204e0b8SIan Munsie 	return scnprintf(buf, PAGE_SIZE, "%i\n", afu->pp_irqs);
259f204e0b8SIan Munsie }
260f204e0b8SIan Munsie 
261f204e0b8SIan Munsie static ssize_t irqs_max_show(struct device *device,
262f204e0b8SIan Munsie 				  struct device_attribute *attr,
263f204e0b8SIan Munsie 				  char *buf)
264f204e0b8SIan Munsie {
265f204e0b8SIan Munsie 	struct cxl_afu *afu = to_cxl_afu(device);
266f204e0b8SIan Munsie 
267f204e0b8SIan Munsie 	return scnprintf(buf, PAGE_SIZE, "%i\n", afu->irqs_max);
268f204e0b8SIan Munsie }
269f204e0b8SIan Munsie 
270f204e0b8SIan Munsie static ssize_t irqs_max_store(struct device *device,
271f204e0b8SIan Munsie 				  struct device_attribute *attr,
272f204e0b8SIan Munsie 				  const char *buf, size_t count)
273f204e0b8SIan Munsie {
274f204e0b8SIan Munsie 	struct cxl_afu *afu = to_cxl_afu(device);
275f204e0b8SIan Munsie 	ssize_t ret;
276f204e0b8SIan Munsie 	int irqs_max;
277f204e0b8SIan Munsie 
278f204e0b8SIan Munsie 	ret = sscanf(buf, "%i", &irqs_max);
279f204e0b8SIan Munsie 	if (ret != 1)
280f204e0b8SIan Munsie 		return -EINVAL;
281f204e0b8SIan Munsie 
282f204e0b8SIan Munsie 	if (irqs_max < afu->pp_irqs)
283f204e0b8SIan Munsie 		return -EINVAL;
284f204e0b8SIan Munsie 
2854752876cSChristophe Lombard 	if (cpu_has_feature(CPU_FTR_HVMODE)) {
286f204e0b8SIan Munsie 		if (irqs_max > afu->adapter->user_irqs)
287f204e0b8SIan Munsie 			return -EINVAL;
2884752876cSChristophe Lombard 	} else {
2894752876cSChristophe Lombard 		/* pHyp sets a per-AFU limit */
2904752876cSChristophe Lombard 		if (irqs_max > afu->guest->max_ints)
2914752876cSChristophe Lombard 			return -EINVAL;
2924752876cSChristophe Lombard 	}
293f204e0b8SIan Munsie 
294f204e0b8SIan Munsie 	afu->irqs_max = irqs_max;
295f204e0b8SIan Munsie 	return count;
296f204e0b8SIan Munsie }
297f204e0b8SIan Munsie 
298f204e0b8SIan Munsie static ssize_t modes_supported_show(struct device *device,
299f204e0b8SIan Munsie 				    struct device_attribute *attr, char *buf)
300f204e0b8SIan Munsie {
301f204e0b8SIan Munsie 	struct cxl_afu *afu = to_cxl_afu(device);
302f204e0b8SIan Munsie 	char *p = buf, *end = buf + PAGE_SIZE;
303f204e0b8SIan Munsie 
304f204e0b8SIan Munsie 	if (afu->modes_supported & CXL_MODE_DEDICATED)
305f204e0b8SIan Munsie 		p += scnprintf(p, end - p, "dedicated_process\n");
306f204e0b8SIan Munsie 	if (afu->modes_supported & CXL_MODE_DIRECTED)
307f204e0b8SIan Munsie 		p += scnprintf(p, end - p, "afu_directed\n");
308f204e0b8SIan Munsie 	return (p - buf);
309f204e0b8SIan Munsie }
310f204e0b8SIan Munsie 
311f204e0b8SIan Munsie static ssize_t prefault_mode_show(struct device *device,
312f204e0b8SIan Munsie 				  struct device_attribute *attr,
313f204e0b8SIan Munsie 				  char *buf)
314f204e0b8SIan Munsie {
315f204e0b8SIan Munsie 	struct cxl_afu *afu = to_cxl_afu(device);
316f204e0b8SIan Munsie 
317f204e0b8SIan Munsie 	switch (afu->prefault_mode) {
318f204e0b8SIan Munsie 	case CXL_PREFAULT_WED:
319f204e0b8SIan Munsie 		return scnprintf(buf, PAGE_SIZE, "work_element_descriptor\n");
320f204e0b8SIan Munsie 	case CXL_PREFAULT_ALL:
321f204e0b8SIan Munsie 		return scnprintf(buf, PAGE_SIZE, "all\n");
322f204e0b8SIan Munsie 	default:
323f204e0b8SIan Munsie 		return scnprintf(buf, PAGE_SIZE, "none\n");
324f204e0b8SIan Munsie 	}
325f204e0b8SIan Munsie }
326f204e0b8SIan Munsie 
327f204e0b8SIan Munsie static ssize_t prefault_mode_store(struct device *device,
328f204e0b8SIan Munsie 			  struct device_attribute *attr,
329f204e0b8SIan Munsie 			  const char *buf, size_t count)
330f204e0b8SIan Munsie {
331f204e0b8SIan Munsie 	struct cxl_afu *afu = to_cxl_afu(device);
332f204e0b8SIan Munsie 	enum prefault_modes mode = -1;
333f204e0b8SIan Munsie 
334f204e0b8SIan Munsie 	if (!strncmp(buf, "work_element_descriptor", 23))
335f204e0b8SIan Munsie 		mode = CXL_PREFAULT_WED;
336f204e0b8SIan Munsie 	if (!strncmp(buf, "all", 3))
337f204e0b8SIan Munsie 		mode = CXL_PREFAULT_ALL;
338f204e0b8SIan Munsie 	if (!strncmp(buf, "none", 4))
339f204e0b8SIan Munsie 		mode = CXL_PREFAULT_NONE;
340f204e0b8SIan Munsie 
341f204e0b8SIan Munsie 	if (mode == -1)
342f204e0b8SIan Munsie 		return -EINVAL;
343f204e0b8SIan Munsie 
344f204e0b8SIan Munsie 	afu->prefault_mode = mode;
345f204e0b8SIan Munsie 	return count;
346f204e0b8SIan Munsie }
347f204e0b8SIan Munsie 
348f204e0b8SIan Munsie static ssize_t mode_show(struct device *device,
349f204e0b8SIan Munsie 			 struct device_attribute *attr,
350f204e0b8SIan Munsie 			 char *buf)
351f204e0b8SIan Munsie {
352f204e0b8SIan Munsie 	struct cxl_afu *afu = to_cxl_afu(device);
353f204e0b8SIan Munsie 
354f204e0b8SIan Munsie 	if (afu->current_mode == CXL_MODE_DEDICATED)
355f204e0b8SIan Munsie 		return scnprintf(buf, PAGE_SIZE, "dedicated_process\n");
356f204e0b8SIan Munsie 	if (afu->current_mode == CXL_MODE_DIRECTED)
357f204e0b8SIan Munsie 		return scnprintf(buf, PAGE_SIZE, "afu_directed\n");
358f204e0b8SIan Munsie 	return scnprintf(buf, PAGE_SIZE, "none\n");
359f204e0b8SIan Munsie }
360f204e0b8SIan Munsie 
361f204e0b8SIan Munsie static ssize_t mode_store(struct device *device, struct device_attribute *attr,
362f204e0b8SIan Munsie 			  const char *buf, size_t count)
363f204e0b8SIan Munsie {
364f204e0b8SIan Munsie 	struct cxl_afu *afu = to_cxl_afu(device);
365f204e0b8SIan Munsie 	int old_mode, mode = -1;
366f204e0b8SIan Munsie 	int rc = -EBUSY;
367f204e0b8SIan Munsie 
368f204e0b8SIan Munsie 	/* can't change this if we have a user */
369ee41d11dSIan Munsie 	mutex_lock(&afu->contexts_lock);
370f204e0b8SIan Munsie 	if (!idr_is_empty(&afu->contexts_idr))
371f204e0b8SIan Munsie 		goto err;
372f204e0b8SIan Munsie 
373f204e0b8SIan Munsie 	if (!strncmp(buf, "dedicated_process", 17))
374f204e0b8SIan Munsie 		mode = CXL_MODE_DEDICATED;
375f204e0b8SIan Munsie 	if (!strncmp(buf, "afu_directed", 12))
376f204e0b8SIan Munsie 		mode = CXL_MODE_DIRECTED;
377f204e0b8SIan Munsie 	if (!strncmp(buf, "none", 4))
378f204e0b8SIan Munsie 		mode = 0;
379f204e0b8SIan Munsie 
380f204e0b8SIan Munsie 	if (mode == -1) {
381f204e0b8SIan Munsie 		rc = -EINVAL;
382f204e0b8SIan Munsie 		goto err;
383f204e0b8SIan Munsie 	}
384f204e0b8SIan Munsie 
385f204e0b8SIan Munsie 	/*
3865be587b1SFrederic Barrat 	 * afu_deactivate_mode needs to be done outside the lock, prevent
387f204e0b8SIan Munsie 	 * other contexts coming in before we are ready:
388f204e0b8SIan Munsie 	 */
389f204e0b8SIan Munsie 	old_mode = afu->current_mode;
390f204e0b8SIan Munsie 	afu->current_mode = 0;
391f204e0b8SIan Munsie 	afu->num_procs = 0;
392f204e0b8SIan Munsie 
393ee41d11dSIan Munsie 	mutex_unlock(&afu->contexts_lock);
394f204e0b8SIan Munsie 
3955be587b1SFrederic Barrat 	if ((rc = cxl_ops->afu_deactivate_mode(afu, old_mode)))
396f204e0b8SIan Munsie 		return rc;
3975be587b1SFrederic Barrat 	if ((rc = cxl_ops->afu_activate_mode(afu, mode)))
398f204e0b8SIan Munsie 		return rc;
399f204e0b8SIan Munsie 
400f204e0b8SIan Munsie 	return count;
401f204e0b8SIan Munsie err:
402ee41d11dSIan Munsie 	mutex_unlock(&afu->contexts_lock);
403f204e0b8SIan Munsie 	return rc;
404f204e0b8SIan Munsie }
405f204e0b8SIan Munsie 
406f204e0b8SIan Munsie static ssize_t api_version_show(struct device *device,
407f204e0b8SIan Munsie 				struct device_attribute *attr,
408f204e0b8SIan Munsie 				char *buf)
409f204e0b8SIan Munsie {
410f204e0b8SIan Munsie 	return scnprintf(buf, PAGE_SIZE, "%i\n", CXL_API_VERSION);
411f204e0b8SIan Munsie }
412f204e0b8SIan Munsie 
413f204e0b8SIan Munsie static ssize_t api_version_compatible_show(struct device *device,
414f204e0b8SIan Munsie 					   struct device_attribute *attr,
415f204e0b8SIan Munsie 					   char *buf)
416f204e0b8SIan Munsie {
417f204e0b8SIan Munsie 	return scnprintf(buf, PAGE_SIZE, "%i\n", CXL_API_VERSION_COMPATIBLE);
418f204e0b8SIan Munsie }
419f204e0b8SIan Munsie 
420e36f6fe1SVaibhav Jain static ssize_t afu_eb_read(struct file *filp, struct kobject *kobj,
421e36f6fe1SVaibhav Jain 			       struct bin_attribute *bin_attr, char *buf,
422e36f6fe1SVaibhav Jain 			       loff_t off, size_t count)
423e36f6fe1SVaibhav Jain {
42485016ff3SGeliang Tang 	struct cxl_afu *afu = to_cxl_afu(kobj_to_dev(kobj));
425e36f6fe1SVaibhav Jain 
4265be587b1SFrederic Barrat 	return cxl_ops->afu_read_err_buffer(afu, buf, off, count);
427e36f6fe1SVaibhav Jain }
428e36f6fe1SVaibhav Jain 
429f204e0b8SIan Munsie static struct device_attribute afu_attrs[] = {
430f204e0b8SIan Munsie 	__ATTR_RO(mmio_size),
431f204e0b8SIan Munsie 	__ATTR_RO(irqs_min),
432f204e0b8SIan Munsie 	__ATTR_RW(irqs_max),
433f204e0b8SIan Munsie 	__ATTR_RO(modes_supported),
434f204e0b8SIan Munsie 	__ATTR_RW(mode),
435f204e0b8SIan Munsie 	__ATTR_RW(prefault_mode),
436f204e0b8SIan Munsie 	__ATTR_RO(api_version),
437f204e0b8SIan Munsie 	__ATTR_RO(api_version_compatible),
438f204e0b8SIan Munsie 	__ATTR(reset, S_IWUSR, NULL, reset_store_afu),
439f204e0b8SIan Munsie };
440f204e0b8SIan Munsie 
441f204e0b8SIan Munsie int cxl_sysfs_adapter_add(struct cxl *adapter)
442f204e0b8SIan Munsie {
4434752876cSChristophe Lombard 	struct device_attribute *dev_attr;
444f204e0b8SIan Munsie 	int i, rc;
445f204e0b8SIan Munsie 
446f204e0b8SIan Munsie 	for (i = 0; i < ARRAY_SIZE(adapter_attrs); i++) {
4474752876cSChristophe Lombard 		dev_attr = &adapter_attrs[i];
4484752876cSChristophe Lombard 		if (cxl_ops->support_attributes(dev_attr->attr.name,
4494752876cSChristophe Lombard 						CXL_ADAPTER_ATTRS)) {
4504752876cSChristophe Lombard 			if ((rc = device_create_file(&adapter->dev, dev_attr)))
451f204e0b8SIan Munsie 				goto err;
452f204e0b8SIan Munsie 		}
4534752876cSChristophe Lombard 	}
454f204e0b8SIan Munsie 	return 0;
455f204e0b8SIan Munsie err:
4564752876cSChristophe Lombard 	for (i--; i >= 0; i--) {
4574752876cSChristophe Lombard 		dev_attr = &adapter_attrs[i];
4584752876cSChristophe Lombard 		if (cxl_ops->support_attributes(dev_attr->attr.name,
4594752876cSChristophe Lombard 						CXL_ADAPTER_ATTRS))
4604752876cSChristophe Lombard 			device_remove_file(&adapter->dev, dev_attr);
4614752876cSChristophe Lombard 	}
462f204e0b8SIan Munsie 	return rc;
463f204e0b8SIan Munsie }
4644752876cSChristophe Lombard 
465f204e0b8SIan Munsie void cxl_sysfs_adapter_remove(struct cxl *adapter)
466f204e0b8SIan Munsie {
4674752876cSChristophe Lombard 	struct device_attribute *dev_attr;
468f204e0b8SIan Munsie 	int i;
469f204e0b8SIan Munsie 
4704752876cSChristophe Lombard 	for (i = 0; i < ARRAY_SIZE(adapter_attrs); i++) {
4714752876cSChristophe Lombard 		dev_attr = &adapter_attrs[i];
4724752876cSChristophe Lombard 		if (cxl_ops->support_attributes(dev_attr->attr.name,
4734752876cSChristophe Lombard 						CXL_ADAPTER_ATTRS))
4744752876cSChristophe Lombard 			device_remove_file(&adapter->dev, dev_attr);
4754752876cSChristophe Lombard 	}
476f204e0b8SIan Munsie }
477f204e0b8SIan Munsie 
478b087e619SIan Munsie struct afu_config_record {
479b087e619SIan Munsie 	struct kobject kobj;
480b087e619SIan Munsie 	struct bin_attribute config_attr;
481b087e619SIan Munsie 	struct list_head list;
482b087e619SIan Munsie 	int cr;
483b087e619SIan Munsie 	u16 device;
484b087e619SIan Munsie 	u16 vendor;
485b087e619SIan Munsie 	u32 class;
486b087e619SIan Munsie };
487b087e619SIan Munsie 
488b087e619SIan Munsie #define to_cr(obj) container_of(obj, struct afu_config_record, kobj)
489b087e619SIan Munsie 
490b087e619SIan Munsie static ssize_t vendor_show(struct kobject *kobj,
491b087e619SIan Munsie 			   struct kobj_attribute *attr, char *buf)
492b087e619SIan Munsie {
493b087e619SIan Munsie 	struct afu_config_record *cr = to_cr(kobj);
494b087e619SIan Munsie 
495b087e619SIan Munsie 	return scnprintf(buf, PAGE_SIZE, "0x%.4x\n", cr->vendor);
496b087e619SIan Munsie }
497b087e619SIan Munsie 
498b087e619SIan Munsie static ssize_t device_show(struct kobject *kobj,
499b087e619SIan Munsie 			   struct kobj_attribute *attr, char *buf)
500b087e619SIan Munsie {
501b087e619SIan Munsie 	struct afu_config_record *cr = to_cr(kobj);
502b087e619SIan Munsie 
503b087e619SIan Munsie 	return scnprintf(buf, PAGE_SIZE, "0x%.4x\n", cr->device);
504b087e619SIan Munsie }
505b087e619SIan Munsie 
506b087e619SIan Munsie static ssize_t class_show(struct kobject *kobj,
507b087e619SIan Munsie 			  struct kobj_attribute *attr, char *buf)
508b087e619SIan Munsie {
509b087e619SIan Munsie 	struct afu_config_record *cr = to_cr(kobj);
510b087e619SIan Munsie 
511b087e619SIan Munsie 	return scnprintf(buf, PAGE_SIZE, "0x%.6x\n", cr->class);
512b087e619SIan Munsie }
513b087e619SIan Munsie 
514b087e619SIan Munsie static ssize_t afu_read_config(struct file *filp, struct kobject *kobj,
515b087e619SIan Munsie 			       struct bin_attribute *bin_attr, char *buf,
516b087e619SIan Munsie 			       loff_t off, size_t count)
517b087e619SIan Munsie {
518b087e619SIan Munsie 	struct afu_config_record *cr = to_cr(kobj);
51985016ff3SGeliang Tang 	struct cxl_afu *afu = to_cxl_afu(kobj_to_dev(kobj->parent));
520b087e619SIan Munsie 
5215be587b1SFrederic Barrat 	u64 i, j, val, rc;
522b087e619SIan Munsie 
523b087e619SIan Munsie 	for (i = 0; i < count;) {
5245be587b1SFrederic Barrat 		rc = cxl_ops->afu_cr_read64(afu, cr->cr, off & ~0x7, &val);
5255be587b1SFrederic Barrat 		if (rc)
5265be587b1SFrederic Barrat 			val = ~0ULL;
527b087e619SIan Munsie 		for (j = off & 0x7; j < 8 && i < count; i++, j++, off++)
528b087e619SIan Munsie 			buf[i] = (val >> (j * 8)) & 0xff;
529b087e619SIan Munsie 	}
530b087e619SIan Munsie 
531b087e619SIan Munsie 	return count;
532b087e619SIan Munsie }
533b087e619SIan Munsie 
534b087e619SIan Munsie static struct kobj_attribute vendor_attribute =
535b087e619SIan Munsie 	__ATTR_RO(vendor);
536b087e619SIan Munsie static struct kobj_attribute device_attribute =
537b087e619SIan Munsie 	__ATTR_RO(device);
538b087e619SIan Munsie static struct kobj_attribute class_attribute =
539b087e619SIan Munsie 	__ATTR_RO(class);
540b087e619SIan Munsie 
541b087e619SIan Munsie static struct attribute *afu_cr_attrs[] = {
542b087e619SIan Munsie 	&vendor_attribute.attr,
543b087e619SIan Munsie 	&device_attribute.attr,
544b087e619SIan Munsie 	&class_attribute.attr,
545b087e619SIan Munsie 	NULL,
546b087e619SIan Munsie };
547b087e619SIan Munsie 
548b087e619SIan Munsie static void release_afu_config_record(struct kobject *kobj)
549b087e619SIan Munsie {
550b087e619SIan Munsie 	struct afu_config_record *cr = to_cr(kobj);
551b087e619SIan Munsie 
552b087e619SIan Munsie 	kfree(cr);
553b087e619SIan Munsie }
554b087e619SIan Munsie 
555b087e619SIan Munsie static struct kobj_type afu_config_record_type = {
556b087e619SIan Munsie 	.sysfs_ops = &kobj_sysfs_ops,
557b087e619SIan Munsie 	.release = release_afu_config_record,
558b087e619SIan Munsie 	.default_attrs = afu_cr_attrs,
559b087e619SIan Munsie };
560b087e619SIan Munsie 
561b087e619SIan Munsie static struct afu_config_record *cxl_sysfs_afu_new_cr(struct cxl_afu *afu, int cr_idx)
562b087e619SIan Munsie {
563b087e619SIan Munsie 	struct afu_config_record *cr;
564b087e619SIan Munsie 	int rc;
565b087e619SIan Munsie 
566b087e619SIan Munsie 	cr = kzalloc(sizeof(struct afu_config_record), GFP_KERNEL);
567b087e619SIan Munsie 	if (!cr)
568b087e619SIan Munsie 		return ERR_PTR(-ENOMEM);
569b087e619SIan Munsie 
570b087e619SIan Munsie 	cr->cr = cr_idx;
5715be587b1SFrederic Barrat 
5725be587b1SFrederic Barrat 	rc = cxl_ops->afu_cr_read16(afu, cr_idx, PCI_DEVICE_ID, &cr->device);
5735be587b1SFrederic Barrat 	if (rc)
5745be587b1SFrederic Barrat 		goto err;
5755be587b1SFrederic Barrat 	rc = cxl_ops->afu_cr_read16(afu, cr_idx, PCI_VENDOR_ID, &cr->vendor);
5765be587b1SFrederic Barrat 	if (rc)
5775be587b1SFrederic Barrat 		goto err;
5785be587b1SFrederic Barrat 	rc = cxl_ops->afu_cr_read32(afu, cr_idx, PCI_CLASS_REVISION, &cr->class);
5795be587b1SFrederic Barrat 	if (rc)
5805be587b1SFrederic Barrat 		goto err;
5815be587b1SFrederic Barrat 	cr->class >>= 8;
582b087e619SIan Munsie 
583b087e619SIan Munsie 	/*
584b087e619SIan Munsie 	 * Export raw AFU PCIe like config record. For now this is read only by
585b087e619SIan Munsie 	 * root - we can expand that later to be readable by non-root and maybe
5864752876cSChristophe Lombard 	 * even writable provided we have a good use-case. Once we support
587b087e619SIan Munsie 	 * exposing AFUs through a virtual PHB they will get that for free from
588b087e619SIan Munsie 	 * Linux' PCI infrastructure, but until then it's not clear that we
589b087e619SIan Munsie 	 * need it for anything since the main use case is just identifying
590b087e619SIan Munsie 	 * AFUs, which can be done via the vendor, device and class attributes.
591b087e619SIan Munsie 	 */
592b087e619SIan Munsie 	sysfs_bin_attr_init(&cr->config_attr);
593b087e619SIan Munsie 	cr->config_attr.attr.name = "config";
594b087e619SIan Munsie 	cr->config_attr.attr.mode = S_IRUSR;
595b087e619SIan Munsie 	cr->config_attr.size = afu->crs_len;
596b087e619SIan Munsie 	cr->config_attr.read = afu_read_config;
597b087e619SIan Munsie 
598b087e619SIan Munsie 	rc = kobject_init_and_add(&cr->kobj, &afu_config_record_type,
599b087e619SIan Munsie 				  &afu->dev.kobj, "cr%i", cr->cr);
600b087e619SIan Munsie 	if (rc)
601b087e619SIan Munsie 		goto err;
602b087e619SIan Munsie 
603b087e619SIan Munsie 	rc = sysfs_create_bin_file(&cr->kobj, &cr->config_attr);
604b087e619SIan Munsie 	if (rc)
605b087e619SIan Munsie 		goto err1;
606b087e619SIan Munsie 
607b087e619SIan Munsie 	rc = kobject_uevent(&cr->kobj, KOBJ_ADD);
608b087e619SIan Munsie 	if (rc)
609b087e619SIan Munsie 		goto err2;
610b087e619SIan Munsie 
611b087e619SIan Munsie 	return cr;
612b087e619SIan Munsie err2:
613b087e619SIan Munsie 	sysfs_remove_bin_file(&cr->kobj, &cr->config_attr);
614b087e619SIan Munsie err1:
615b087e619SIan Munsie 	kobject_put(&cr->kobj);
616b087e619SIan Munsie 	return ERR_PTR(rc);
617b087e619SIan Munsie err:
618b087e619SIan Munsie 	kfree(cr);
619b087e619SIan Munsie 	return ERR_PTR(rc);
620b087e619SIan Munsie }
621b087e619SIan Munsie 
622b087e619SIan Munsie void cxl_sysfs_afu_remove(struct cxl_afu *afu)
623b087e619SIan Munsie {
6244752876cSChristophe Lombard 	struct device_attribute *dev_attr;
625b087e619SIan Munsie 	struct afu_config_record *cr, *tmp;
626b087e619SIan Munsie 	int i;
627b087e619SIan Munsie 
628e36f6fe1SVaibhav Jain 	/* remove the err buffer bin attribute */
629e36f6fe1SVaibhav Jain 	if (afu->eb_len)
630e36f6fe1SVaibhav Jain 		device_remove_bin_file(&afu->dev, &afu->attr_eb);
631e36f6fe1SVaibhav Jain 
6324752876cSChristophe Lombard 	for (i = 0; i < ARRAY_SIZE(afu_attrs); i++) {
6334752876cSChristophe Lombard 		dev_attr = &afu_attrs[i];
6344752876cSChristophe Lombard 		if (cxl_ops->support_attributes(dev_attr->attr.name,
6354752876cSChristophe Lombard 						CXL_AFU_ATTRS))
636b087e619SIan Munsie 			device_remove_file(&afu->dev, &afu_attrs[i]);
6374752876cSChristophe Lombard 	}
638b087e619SIan Munsie 
639b087e619SIan Munsie 	list_for_each_entry_safe(cr, tmp, &afu->crs, list) {
640b087e619SIan Munsie 		sysfs_remove_bin_file(&cr->kobj, &cr->config_attr);
641b087e619SIan Munsie 		kobject_put(&cr->kobj);
642b087e619SIan Munsie 	}
643b087e619SIan Munsie }
644b087e619SIan Munsie 
645f204e0b8SIan Munsie int cxl_sysfs_afu_add(struct cxl_afu *afu)
646f204e0b8SIan Munsie {
6474752876cSChristophe Lombard 	struct device_attribute *dev_attr;
648b087e619SIan Munsie 	struct afu_config_record *cr;
649f204e0b8SIan Munsie 	int i, rc;
650f204e0b8SIan Munsie 
651b087e619SIan Munsie 	INIT_LIST_HEAD(&afu->crs);
652b087e619SIan Munsie 
653f204e0b8SIan Munsie 	for (i = 0; i < ARRAY_SIZE(afu_attrs); i++) {
6544752876cSChristophe Lombard 		dev_attr = &afu_attrs[i];
6554752876cSChristophe Lombard 		if (cxl_ops->support_attributes(dev_attr->attr.name,
6564752876cSChristophe Lombard 						CXL_AFU_ATTRS)) {
657f204e0b8SIan Munsie 			if ((rc = device_create_file(&afu->dev, &afu_attrs[i])))
658f204e0b8SIan Munsie 				goto err;
659f204e0b8SIan Munsie 		}
6604752876cSChristophe Lombard 	}
661f204e0b8SIan Munsie 
662e36f6fe1SVaibhav Jain 	/* conditionally create the add the binary file for error info buffer */
663e36f6fe1SVaibhav Jain 	if (afu->eb_len) {
664d6eb71a6SVaibhav Jain 		sysfs_attr_init(&afu->attr_eb.attr);
665d6eb71a6SVaibhav Jain 
666e36f6fe1SVaibhav Jain 		afu->attr_eb.attr.name = "afu_err_buff";
667e36f6fe1SVaibhav Jain 		afu->attr_eb.attr.mode = S_IRUGO;
668e36f6fe1SVaibhav Jain 		afu->attr_eb.size = afu->eb_len;
669e36f6fe1SVaibhav Jain 		afu->attr_eb.read = afu_eb_read;
670e36f6fe1SVaibhav Jain 
671e36f6fe1SVaibhav Jain 		rc = device_create_bin_file(&afu->dev, &afu->attr_eb);
672e36f6fe1SVaibhav Jain 		if (rc) {
673e36f6fe1SVaibhav Jain 			dev_err(&afu->dev,
674e36f6fe1SVaibhav Jain 				"Unable to create eb attr for the afu. Err(%d)\n",
675e36f6fe1SVaibhav Jain 				rc);
676e36f6fe1SVaibhav Jain 			goto err;
677e36f6fe1SVaibhav Jain 		}
678e36f6fe1SVaibhav Jain 	}
679e36f6fe1SVaibhav Jain 
680b087e619SIan Munsie 	for (i = 0; i < afu->crs_num; i++) {
681b087e619SIan Munsie 		cr = cxl_sysfs_afu_new_cr(afu, i);
682b087e619SIan Munsie 		if (IS_ERR(cr)) {
683b087e619SIan Munsie 			rc = PTR_ERR(cr);
684b087e619SIan Munsie 			goto err1;
685b087e619SIan Munsie 		}
686b087e619SIan Munsie 		list_add(&cr->list, &afu->crs);
687b087e619SIan Munsie 	}
688b087e619SIan Munsie 
689f204e0b8SIan Munsie 	return 0;
690f204e0b8SIan Munsie 
691b087e619SIan Munsie err1:
692b087e619SIan Munsie 	cxl_sysfs_afu_remove(afu);
693b087e619SIan Munsie 	return rc;
694f204e0b8SIan Munsie err:
695e36f6fe1SVaibhav Jain 	/* reset the eb_len as we havent created the bin attr */
696e36f6fe1SVaibhav Jain 	afu->eb_len = 0;
697e36f6fe1SVaibhav Jain 
6984752876cSChristophe Lombard 	for (i--; i >= 0; i--) {
6994752876cSChristophe Lombard 		dev_attr = &afu_attrs[i];
7004752876cSChristophe Lombard 		if (cxl_ops->support_attributes(dev_attr->attr.name,
7014752876cSChristophe Lombard 						CXL_AFU_ATTRS))
702f204e0b8SIan Munsie 		device_remove_file(&afu->dev, &afu_attrs[i]);
7034752876cSChristophe Lombard 	}
704f204e0b8SIan Munsie 	return rc;
705f204e0b8SIan Munsie }
706f204e0b8SIan Munsie 
707f204e0b8SIan Munsie int cxl_sysfs_afu_m_add(struct cxl_afu *afu)
708f204e0b8SIan Munsie {
7094752876cSChristophe Lombard 	struct device_attribute *dev_attr;
710f204e0b8SIan Munsie 	int i, rc;
711f204e0b8SIan Munsie 
712f204e0b8SIan Munsie 	for (i = 0; i < ARRAY_SIZE(afu_master_attrs); i++) {
7134752876cSChristophe Lombard 		dev_attr = &afu_master_attrs[i];
7144752876cSChristophe Lombard 		if (cxl_ops->support_attributes(dev_attr->attr.name,
7154752876cSChristophe Lombard 						CXL_AFU_MASTER_ATTRS)) {
716f204e0b8SIan Munsie 			if ((rc = device_create_file(afu->chardev_m, &afu_master_attrs[i])))
717f204e0b8SIan Munsie 				goto err;
718f204e0b8SIan Munsie 		}
7194752876cSChristophe Lombard 	}
720f204e0b8SIan Munsie 
721f204e0b8SIan Munsie 	return 0;
722f204e0b8SIan Munsie 
723f204e0b8SIan Munsie err:
7244752876cSChristophe Lombard 	for (i--; i >= 0; i--) {
7254752876cSChristophe Lombard 		dev_attr = &afu_master_attrs[i];
7264752876cSChristophe Lombard 		if (cxl_ops->support_attributes(dev_attr->attr.name,
7274752876cSChristophe Lombard 						CXL_AFU_MASTER_ATTRS))
728f204e0b8SIan Munsie 			device_remove_file(afu->chardev_m, &afu_master_attrs[i]);
7294752876cSChristophe Lombard 	}
730f204e0b8SIan Munsie 	return rc;
731f204e0b8SIan Munsie }
732f204e0b8SIan Munsie 
733f204e0b8SIan Munsie void cxl_sysfs_afu_m_remove(struct cxl_afu *afu)
734f204e0b8SIan Munsie {
7354752876cSChristophe Lombard 	struct device_attribute *dev_attr;
736f204e0b8SIan Munsie 	int i;
737f204e0b8SIan Munsie 
7384752876cSChristophe Lombard 	for (i = 0; i < ARRAY_SIZE(afu_master_attrs); i++) {
7394752876cSChristophe Lombard 		dev_attr = &afu_master_attrs[i];
7404752876cSChristophe Lombard 		if (cxl_ops->support_attributes(dev_attr->attr.name,
7414752876cSChristophe Lombard 						CXL_AFU_MASTER_ATTRS))
742f204e0b8SIan Munsie 			device_remove_file(afu->chardev_m, &afu_master_attrs[i]);
743f204e0b8SIan Munsie 	}
7444752876cSChristophe Lombard }
745