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