xref: /linux/drivers/misc/cxl/sysfs.c (revision 13e68d8bd05c998cae452a4f3400af1e8edd852e)
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 
6062fa19d4SRyan Grimm static ssize_t reset_adapter_store(struct device *device,
6162fa19d4SRyan Grimm 				   struct device_attribute *attr,
6262fa19d4SRyan Grimm 				   const char *buf, size_t count)
6362fa19d4SRyan Grimm {
6462fa19d4SRyan Grimm 	struct cxl *adapter = to_cxl_adapter(device);
6562fa19d4SRyan Grimm 	int rc;
6662fa19d4SRyan Grimm 	int val;
6762fa19d4SRyan Grimm 
6862fa19d4SRyan Grimm 	rc = sscanf(buf, "%i", &val);
6962fa19d4SRyan Grimm 	if ((rc != 1) || (val != 1))
7062fa19d4SRyan Grimm 		return -EINVAL;
7162fa19d4SRyan Grimm 
7262fa19d4SRyan Grimm 	if ((rc = cxl_reset(adapter)))
7362fa19d4SRyan Grimm 		return rc;
7462fa19d4SRyan Grimm 	return count;
7562fa19d4SRyan Grimm }
7662fa19d4SRyan Grimm 
7795bc11bcSRyan Grimm static ssize_t load_image_on_perst_show(struct device *device,
7895bc11bcSRyan Grimm 				 struct device_attribute *attr,
7995bc11bcSRyan Grimm 				 char *buf)
8095bc11bcSRyan Grimm {
8195bc11bcSRyan Grimm 	struct cxl *adapter = to_cxl_adapter(device);
8295bc11bcSRyan Grimm 
8395bc11bcSRyan Grimm 	if (!adapter->perst_loads_image)
8495bc11bcSRyan Grimm 		return scnprintf(buf, PAGE_SIZE, "none\n");
8595bc11bcSRyan Grimm 
8695bc11bcSRyan Grimm 	if (adapter->perst_select_user)
8795bc11bcSRyan Grimm 		return scnprintf(buf, PAGE_SIZE, "user\n");
8895bc11bcSRyan Grimm 	return scnprintf(buf, PAGE_SIZE, "factory\n");
8995bc11bcSRyan Grimm }
9095bc11bcSRyan Grimm 
9195bc11bcSRyan Grimm static ssize_t load_image_on_perst_store(struct device *device,
9295bc11bcSRyan Grimm 				 struct device_attribute *attr,
9395bc11bcSRyan Grimm 				 const char *buf, size_t count)
9495bc11bcSRyan Grimm {
9595bc11bcSRyan Grimm 	struct cxl *adapter = to_cxl_adapter(device);
9695bc11bcSRyan Grimm 	int rc;
9795bc11bcSRyan Grimm 
9895bc11bcSRyan Grimm 	if (!strncmp(buf, "none", 4))
9995bc11bcSRyan Grimm 		adapter->perst_loads_image = false;
10095bc11bcSRyan Grimm 	else if (!strncmp(buf, "user", 4)) {
10195bc11bcSRyan Grimm 		adapter->perst_select_user = true;
10295bc11bcSRyan Grimm 		adapter->perst_loads_image = true;
10395bc11bcSRyan Grimm 	} else if (!strncmp(buf, "factory", 7)) {
10495bc11bcSRyan Grimm 		adapter->perst_select_user = false;
10595bc11bcSRyan Grimm 		adapter->perst_loads_image = true;
10695bc11bcSRyan Grimm 	} else
10795bc11bcSRyan Grimm 		return -EINVAL;
10895bc11bcSRyan Grimm 
10995bc11bcSRyan Grimm 	if ((rc = cxl_update_image_control(adapter)))
11095bc11bcSRyan Grimm 		return rc;
11195bc11bcSRyan Grimm 
11295bc11bcSRyan Grimm 	return count;
11395bc11bcSRyan Grimm }
11495bc11bcSRyan Grimm 
115*13e68d8bSDaniel Axtens static ssize_t perst_reloads_same_image_show(struct device *device,
116*13e68d8bSDaniel Axtens 				 struct device_attribute *attr,
117*13e68d8bSDaniel Axtens 				 char *buf)
118*13e68d8bSDaniel Axtens {
119*13e68d8bSDaniel Axtens 	struct cxl *adapter = to_cxl_adapter(device);
120*13e68d8bSDaniel Axtens 
121*13e68d8bSDaniel Axtens 	return scnprintf(buf, PAGE_SIZE, "%i\n", adapter->perst_same_image);
122*13e68d8bSDaniel Axtens }
123*13e68d8bSDaniel Axtens 
124*13e68d8bSDaniel Axtens static ssize_t perst_reloads_same_image_store(struct device *device,
125*13e68d8bSDaniel Axtens 				 struct device_attribute *attr,
126*13e68d8bSDaniel Axtens 				 const char *buf, size_t count)
127*13e68d8bSDaniel Axtens {
128*13e68d8bSDaniel Axtens 	struct cxl *adapter = to_cxl_adapter(device);
129*13e68d8bSDaniel Axtens 	int rc;
130*13e68d8bSDaniel Axtens 	int val;
131*13e68d8bSDaniel Axtens 
132*13e68d8bSDaniel Axtens 	rc = sscanf(buf, "%i", &val);
133*13e68d8bSDaniel Axtens 	if ((rc != 1) || !(val == 1 || val == 0))
134*13e68d8bSDaniel Axtens 		return -EINVAL;
135*13e68d8bSDaniel Axtens 
136*13e68d8bSDaniel Axtens 	adapter->perst_same_image = (val == 1 ? true : false);
137*13e68d8bSDaniel Axtens 	return count;
138*13e68d8bSDaniel Axtens }
139*13e68d8bSDaniel Axtens 
140f204e0b8SIan Munsie static struct device_attribute adapter_attrs[] = {
141f204e0b8SIan Munsie 	__ATTR_RO(caia_version),
142f204e0b8SIan Munsie 	__ATTR_RO(psl_revision),
143f204e0b8SIan Munsie 	__ATTR_RO(base_image),
144f204e0b8SIan Munsie 	__ATTR_RO(image_loaded),
14595bc11bcSRyan Grimm 	__ATTR_RW(load_image_on_perst),
146*13e68d8bSDaniel Axtens 	__ATTR_RW(perst_reloads_same_image),
14762fa19d4SRyan Grimm 	__ATTR(reset, S_IWUSR, NULL, reset_adapter_store),
148f204e0b8SIan Munsie };
149f204e0b8SIan Munsie 
150f204e0b8SIan Munsie 
151f204e0b8SIan Munsie /*********  AFU master specific attributes  **********************************/
152f204e0b8SIan Munsie 
153f204e0b8SIan Munsie static ssize_t mmio_size_show_master(struct device *device,
154f204e0b8SIan Munsie 				     struct device_attribute *attr,
155f204e0b8SIan Munsie 				     char *buf)
156f204e0b8SIan Munsie {
157f204e0b8SIan Munsie 	struct cxl_afu *afu = to_afu_chardev_m(device);
158f204e0b8SIan Munsie 
159f204e0b8SIan Munsie 	return scnprintf(buf, PAGE_SIZE, "%llu\n", afu->adapter->ps_size);
160f204e0b8SIan Munsie }
161f204e0b8SIan Munsie 
162f204e0b8SIan Munsie static ssize_t pp_mmio_off_show(struct device *device,
163f204e0b8SIan Munsie 				struct device_attribute *attr,
164f204e0b8SIan Munsie 				char *buf)
165f204e0b8SIan Munsie {
166f204e0b8SIan Munsie 	struct cxl_afu *afu = to_afu_chardev_m(device);
167f204e0b8SIan Munsie 
168f204e0b8SIan Munsie 	return scnprintf(buf, PAGE_SIZE, "%llu\n", afu->pp_offset);
169f204e0b8SIan Munsie }
170f204e0b8SIan Munsie 
171f204e0b8SIan Munsie static ssize_t pp_mmio_len_show(struct device *device,
172f204e0b8SIan Munsie 				struct device_attribute *attr,
173f204e0b8SIan Munsie 				char *buf)
174f204e0b8SIan Munsie {
175f204e0b8SIan Munsie 	struct cxl_afu *afu = to_afu_chardev_m(device);
176f204e0b8SIan Munsie 
177f204e0b8SIan Munsie 	return scnprintf(buf, PAGE_SIZE, "%llu\n", afu->pp_size);
178f204e0b8SIan Munsie }
179f204e0b8SIan Munsie 
180f204e0b8SIan Munsie static struct device_attribute afu_master_attrs[] = {
181f204e0b8SIan Munsie 	__ATTR(mmio_size, S_IRUGO, mmio_size_show_master, NULL),
182f204e0b8SIan Munsie 	__ATTR_RO(pp_mmio_off),
183f204e0b8SIan Munsie 	__ATTR_RO(pp_mmio_len),
184f204e0b8SIan Munsie };
185f204e0b8SIan Munsie 
186f204e0b8SIan Munsie 
187f204e0b8SIan Munsie /*********  AFU attributes  **************************************************/
188f204e0b8SIan Munsie 
189f204e0b8SIan Munsie static ssize_t mmio_size_show(struct device *device,
190f204e0b8SIan Munsie 			      struct device_attribute *attr,
191f204e0b8SIan Munsie 			      char *buf)
192f204e0b8SIan Munsie {
193f204e0b8SIan Munsie 	struct cxl_afu *afu = to_cxl_afu(device);
194f204e0b8SIan Munsie 
195f204e0b8SIan Munsie 	if (afu->pp_size)
196f204e0b8SIan Munsie 		return scnprintf(buf, PAGE_SIZE, "%llu\n", afu->pp_size);
197f204e0b8SIan Munsie 	return scnprintf(buf, PAGE_SIZE, "%llu\n", afu->adapter->ps_size);
198f204e0b8SIan Munsie }
199f204e0b8SIan Munsie 
200f204e0b8SIan Munsie static ssize_t reset_store_afu(struct device *device,
201f204e0b8SIan Munsie 			       struct device_attribute *attr,
202f204e0b8SIan Munsie 			       const char *buf, size_t count)
203f204e0b8SIan Munsie {
204f204e0b8SIan Munsie 	struct cxl_afu *afu = to_cxl_afu(device);
205f204e0b8SIan Munsie 	int rc;
206f204e0b8SIan Munsie 
207f204e0b8SIan Munsie 	/* Not safe to reset if it is currently in use */
208ee41d11dSIan Munsie 	mutex_lock(&afu->contexts_lock);
209f204e0b8SIan Munsie 	if (!idr_is_empty(&afu->contexts_idr)) {
210f204e0b8SIan Munsie 		rc = -EBUSY;
211f204e0b8SIan Munsie 		goto err;
212f204e0b8SIan Munsie 	}
213f204e0b8SIan Munsie 
214b12994fbSMichael Neuling 	if ((rc = __cxl_afu_reset(afu)))
215f204e0b8SIan Munsie 		goto err;
216f204e0b8SIan Munsie 
217f204e0b8SIan Munsie 	rc = count;
218f204e0b8SIan Munsie err:
219ee41d11dSIan Munsie 	mutex_unlock(&afu->contexts_lock);
220f204e0b8SIan Munsie 	return rc;
221f204e0b8SIan Munsie }
222f204e0b8SIan Munsie 
223f204e0b8SIan Munsie static ssize_t irqs_min_show(struct device *device,
224f204e0b8SIan Munsie 			     struct device_attribute *attr,
225f204e0b8SIan Munsie 			     char *buf)
226f204e0b8SIan Munsie {
227f204e0b8SIan Munsie 	struct cxl_afu *afu = to_cxl_afu(device);
228f204e0b8SIan Munsie 
229f204e0b8SIan Munsie 	return scnprintf(buf, PAGE_SIZE, "%i\n", afu->pp_irqs);
230f204e0b8SIan Munsie }
231f204e0b8SIan Munsie 
232f204e0b8SIan Munsie static ssize_t irqs_max_show(struct device *device,
233f204e0b8SIan Munsie 				  struct device_attribute *attr,
234f204e0b8SIan Munsie 				  char *buf)
235f204e0b8SIan Munsie {
236f204e0b8SIan Munsie 	struct cxl_afu *afu = to_cxl_afu(device);
237f204e0b8SIan Munsie 
238f204e0b8SIan Munsie 	return scnprintf(buf, PAGE_SIZE, "%i\n", afu->irqs_max);
239f204e0b8SIan Munsie }
240f204e0b8SIan Munsie 
241f204e0b8SIan Munsie static ssize_t irqs_max_store(struct device *device,
242f204e0b8SIan Munsie 				  struct device_attribute *attr,
243f204e0b8SIan Munsie 				  const char *buf, size_t count)
244f204e0b8SIan Munsie {
245f204e0b8SIan Munsie 	struct cxl_afu *afu = to_cxl_afu(device);
246f204e0b8SIan Munsie 	ssize_t ret;
247f204e0b8SIan Munsie 	int irqs_max;
248f204e0b8SIan Munsie 
249f204e0b8SIan Munsie 	ret = sscanf(buf, "%i", &irqs_max);
250f204e0b8SIan Munsie 	if (ret != 1)
251f204e0b8SIan Munsie 		return -EINVAL;
252f204e0b8SIan Munsie 
253f204e0b8SIan Munsie 	if (irqs_max < afu->pp_irqs)
254f204e0b8SIan Munsie 		return -EINVAL;
255f204e0b8SIan Munsie 
256f204e0b8SIan Munsie 	if (irqs_max > afu->adapter->user_irqs)
257f204e0b8SIan Munsie 		return -EINVAL;
258f204e0b8SIan Munsie 
259f204e0b8SIan Munsie 	afu->irqs_max = irqs_max;
260f204e0b8SIan Munsie 	return count;
261f204e0b8SIan Munsie }
262f204e0b8SIan Munsie 
263f204e0b8SIan Munsie static ssize_t modes_supported_show(struct device *device,
264f204e0b8SIan Munsie 				    struct device_attribute *attr, char *buf)
265f204e0b8SIan Munsie {
266f204e0b8SIan Munsie 	struct cxl_afu *afu = to_cxl_afu(device);
267f204e0b8SIan Munsie 	char *p = buf, *end = buf + PAGE_SIZE;
268f204e0b8SIan Munsie 
269f204e0b8SIan Munsie 	if (afu->modes_supported & CXL_MODE_DEDICATED)
270f204e0b8SIan Munsie 		p += scnprintf(p, end - p, "dedicated_process\n");
271f204e0b8SIan Munsie 	if (afu->modes_supported & CXL_MODE_DIRECTED)
272f204e0b8SIan Munsie 		p += scnprintf(p, end - p, "afu_directed\n");
273f204e0b8SIan Munsie 	return (p - buf);
274f204e0b8SIan Munsie }
275f204e0b8SIan Munsie 
276f204e0b8SIan Munsie static ssize_t prefault_mode_show(struct device *device,
277f204e0b8SIan Munsie 				  struct device_attribute *attr,
278f204e0b8SIan Munsie 				  char *buf)
279f204e0b8SIan Munsie {
280f204e0b8SIan Munsie 	struct cxl_afu *afu = to_cxl_afu(device);
281f204e0b8SIan Munsie 
282f204e0b8SIan Munsie 	switch (afu->prefault_mode) {
283f204e0b8SIan Munsie 	case CXL_PREFAULT_WED:
284f204e0b8SIan Munsie 		return scnprintf(buf, PAGE_SIZE, "work_element_descriptor\n");
285f204e0b8SIan Munsie 	case CXL_PREFAULT_ALL:
286f204e0b8SIan Munsie 		return scnprintf(buf, PAGE_SIZE, "all\n");
287f204e0b8SIan Munsie 	default:
288f204e0b8SIan Munsie 		return scnprintf(buf, PAGE_SIZE, "none\n");
289f204e0b8SIan Munsie 	}
290f204e0b8SIan Munsie }
291f204e0b8SIan Munsie 
292f204e0b8SIan Munsie static ssize_t prefault_mode_store(struct device *device,
293f204e0b8SIan Munsie 			  struct device_attribute *attr,
294f204e0b8SIan Munsie 			  const char *buf, size_t count)
295f204e0b8SIan Munsie {
296f204e0b8SIan Munsie 	struct cxl_afu *afu = to_cxl_afu(device);
297f204e0b8SIan Munsie 	enum prefault_modes mode = -1;
298f204e0b8SIan Munsie 
299f204e0b8SIan Munsie 	if (!strncmp(buf, "work_element_descriptor", 23))
300f204e0b8SIan Munsie 		mode = CXL_PREFAULT_WED;
301f204e0b8SIan Munsie 	if (!strncmp(buf, "all", 3))
302f204e0b8SIan Munsie 		mode = CXL_PREFAULT_ALL;
303f204e0b8SIan Munsie 	if (!strncmp(buf, "none", 4))
304f204e0b8SIan Munsie 		mode = CXL_PREFAULT_NONE;
305f204e0b8SIan Munsie 
306f204e0b8SIan Munsie 	if (mode == -1)
307f204e0b8SIan Munsie 		return -EINVAL;
308f204e0b8SIan Munsie 
309f204e0b8SIan Munsie 	afu->prefault_mode = mode;
310f204e0b8SIan Munsie 	return count;
311f204e0b8SIan Munsie }
312f204e0b8SIan Munsie 
313f204e0b8SIan Munsie static ssize_t mode_show(struct device *device,
314f204e0b8SIan Munsie 			 struct device_attribute *attr,
315f204e0b8SIan Munsie 			 char *buf)
316f204e0b8SIan Munsie {
317f204e0b8SIan Munsie 	struct cxl_afu *afu = to_cxl_afu(device);
318f204e0b8SIan Munsie 
319f204e0b8SIan Munsie 	if (afu->current_mode == CXL_MODE_DEDICATED)
320f204e0b8SIan Munsie 		return scnprintf(buf, PAGE_SIZE, "dedicated_process\n");
321f204e0b8SIan Munsie 	if (afu->current_mode == CXL_MODE_DIRECTED)
322f204e0b8SIan Munsie 		return scnprintf(buf, PAGE_SIZE, "afu_directed\n");
323f204e0b8SIan Munsie 	return scnprintf(buf, PAGE_SIZE, "none\n");
324f204e0b8SIan Munsie }
325f204e0b8SIan Munsie 
326f204e0b8SIan Munsie static ssize_t mode_store(struct device *device, struct device_attribute *attr,
327f204e0b8SIan Munsie 			  const char *buf, size_t count)
328f204e0b8SIan Munsie {
329f204e0b8SIan Munsie 	struct cxl_afu *afu = to_cxl_afu(device);
330f204e0b8SIan Munsie 	int old_mode, mode = -1;
331f204e0b8SIan Munsie 	int rc = -EBUSY;
332f204e0b8SIan Munsie 
333f204e0b8SIan Munsie 	/* can't change this if we have a user */
334ee41d11dSIan Munsie 	mutex_lock(&afu->contexts_lock);
335f204e0b8SIan Munsie 	if (!idr_is_empty(&afu->contexts_idr))
336f204e0b8SIan Munsie 		goto err;
337f204e0b8SIan Munsie 
338f204e0b8SIan Munsie 	if (!strncmp(buf, "dedicated_process", 17))
339f204e0b8SIan Munsie 		mode = CXL_MODE_DEDICATED;
340f204e0b8SIan Munsie 	if (!strncmp(buf, "afu_directed", 12))
341f204e0b8SIan Munsie 		mode = CXL_MODE_DIRECTED;
342f204e0b8SIan Munsie 	if (!strncmp(buf, "none", 4))
343f204e0b8SIan Munsie 		mode = 0;
344f204e0b8SIan Munsie 
345f204e0b8SIan Munsie 	if (mode == -1) {
346f204e0b8SIan Munsie 		rc = -EINVAL;
347f204e0b8SIan Munsie 		goto err;
348f204e0b8SIan Munsie 	}
349f204e0b8SIan Munsie 
350f204e0b8SIan Munsie 	/*
351f204e0b8SIan Munsie 	 * cxl_afu_deactivate_mode needs to be done outside the lock, prevent
352f204e0b8SIan Munsie 	 * other contexts coming in before we are ready:
353f204e0b8SIan Munsie 	 */
354f204e0b8SIan Munsie 	old_mode = afu->current_mode;
355f204e0b8SIan Munsie 	afu->current_mode = 0;
356f204e0b8SIan Munsie 	afu->num_procs = 0;
357f204e0b8SIan Munsie 
358ee41d11dSIan Munsie 	mutex_unlock(&afu->contexts_lock);
359f204e0b8SIan Munsie 
360f204e0b8SIan Munsie 	if ((rc = _cxl_afu_deactivate_mode(afu, old_mode)))
361f204e0b8SIan Munsie 		return rc;
362f204e0b8SIan Munsie 	if ((rc = cxl_afu_activate_mode(afu, mode)))
363f204e0b8SIan Munsie 		return rc;
364f204e0b8SIan Munsie 
365f204e0b8SIan Munsie 	return count;
366f204e0b8SIan Munsie err:
367ee41d11dSIan Munsie 	mutex_unlock(&afu->contexts_lock);
368f204e0b8SIan Munsie 	return rc;
369f204e0b8SIan Munsie }
370f204e0b8SIan Munsie 
371f204e0b8SIan Munsie static ssize_t api_version_show(struct device *device,
372f204e0b8SIan Munsie 				struct device_attribute *attr,
373f204e0b8SIan Munsie 				char *buf)
374f204e0b8SIan Munsie {
375f204e0b8SIan Munsie 	return scnprintf(buf, PAGE_SIZE, "%i\n", CXL_API_VERSION);
376f204e0b8SIan Munsie }
377f204e0b8SIan Munsie 
378f204e0b8SIan Munsie static ssize_t api_version_compatible_show(struct device *device,
379f204e0b8SIan Munsie 					   struct device_attribute *attr,
380f204e0b8SIan Munsie 					   char *buf)
381f204e0b8SIan Munsie {
382f204e0b8SIan Munsie 	return scnprintf(buf, PAGE_SIZE, "%i\n", CXL_API_VERSION_COMPATIBLE);
383f204e0b8SIan Munsie }
384f204e0b8SIan Munsie 
385e36f6fe1SVaibhav Jain static ssize_t afu_eb_read(struct file *filp, struct kobject *kobj,
386e36f6fe1SVaibhav Jain 			       struct bin_attribute *bin_attr, char *buf,
387e36f6fe1SVaibhav Jain 			       loff_t off, size_t count)
388e36f6fe1SVaibhav Jain {
389e36f6fe1SVaibhav Jain 	struct cxl_afu *afu = to_cxl_afu(container_of(kobj,
390e36f6fe1SVaibhav Jain 						      struct device, kobj));
391e36f6fe1SVaibhav Jain 
392e36f6fe1SVaibhav Jain 	return cxl_afu_read_err_buffer(afu, buf, off, count);
393e36f6fe1SVaibhav Jain }
394e36f6fe1SVaibhav Jain 
395f204e0b8SIan Munsie static struct device_attribute afu_attrs[] = {
396f204e0b8SIan Munsie 	__ATTR_RO(mmio_size),
397f204e0b8SIan Munsie 	__ATTR_RO(irqs_min),
398f204e0b8SIan Munsie 	__ATTR_RW(irqs_max),
399f204e0b8SIan Munsie 	__ATTR_RO(modes_supported),
400f204e0b8SIan Munsie 	__ATTR_RW(mode),
401f204e0b8SIan Munsie 	__ATTR_RW(prefault_mode),
402f204e0b8SIan Munsie 	__ATTR_RO(api_version),
403f204e0b8SIan Munsie 	__ATTR_RO(api_version_compatible),
404f204e0b8SIan Munsie 	__ATTR(reset, S_IWUSR, NULL, reset_store_afu),
405f204e0b8SIan Munsie };
406f204e0b8SIan Munsie 
407f204e0b8SIan Munsie int cxl_sysfs_adapter_add(struct cxl *adapter)
408f204e0b8SIan Munsie {
409f204e0b8SIan Munsie 	int i, rc;
410f204e0b8SIan Munsie 
411f204e0b8SIan Munsie 	for (i = 0; i < ARRAY_SIZE(adapter_attrs); i++) {
412f204e0b8SIan Munsie 		if ((rc = device_create_file(&adapter->dev, &adapter_attrs[i])))
413f204e0b8SIan Munsie 			goto err;
414f204e0b8SIan Munsie 	}
415f204e0b8SIan Munsie 	return 0;
416f204e0b8SIan Munsie err:
417f204e0b8SIan Munsie 	for (i--; i >= 0; i--)
418f204e0b8SIan Munsie 		device_remove_file(&adapter->dev, &adapter_attrs[i]);
419f204e0b8SIan Munsie 	return rc;
420f204e0b8SIan Munsie }
421f204e0b8SIan Munsie void cxl_sysfs_adapter_remove(struct cxl *adapter)
422f204e0b8SIan Munsie {
423f204e0b8SIan Munsie 	int i;
424f204e0b8SIan Munsie 
425f204e0b8SIan Munsie 	for (i = 0; i < ARRAY_SIZE(adapter_attrs); i++)
426f204e0b8SIan Munsie 		device_remove_file(&adapter->dev, &adapter_attrs[i]);
427f204e0b8SIan Munsie }
428f204e0b8SIan Munsie 
429b087e619SIan Munsie struct afu_config_record {
430b087e619SIan Munsie 	struct kobject kobj;
431b087e619SIan Munsie 	struct bin_attribute config_attr;
432b087e619SIan Munsie 	struct list_head list;
433b087e619SIan Munsie 	int cr;
434b087e619SIan Munsie 	u16 device;
435b087e619SIan Munsie 	u16 vendor;
436b087e619SIan Munsie 	u32 class;
437b087e619SIan Munsie };
438b087e619SIan Munsie 
439b087e619SIan Munsie #define to_cr(obj) container_of(obj, struct afu_config_record, kobj)
440b087e619SIan Munsie 
441b087e619SIan Munsie static ssize_t vendor_show(struct kobject *kobj,
442b087e619SIan Munsie 			   struct kobj_attribute *attr, char *buf)
443b087e619SIan Munsie {
444b087e619SIan Munsie 	struct afu_config_record *cr = to_cr(kobj);
445b087e619SIan Munsie 
446b087e619SIan Munsie 	return scnprintf(buf, PAGE_SIZE, "0x%.4x\n", cr->vendor);
447b087e619SIan Munsie }
448b087e619SIan Munsie 
449b087e619SIan Munsie static ssize_t device_show(struct kobject *kobj,
450b087e619SIan Munsie 			   struct kobj_attribute *attr, char *buf)
451b087e619SIan Munsie {
452b087e619SIan Munsie 	struct afu_config_record *cr = to_cr(kobj);
453b087e619SIan Munsie 
454b087e619SIan Munsie 	return scnprintf(buf, PAGE_SIZE, "0x%.4x\n", cr->device);
455b087e619SIan Munsie }
456b087e619SIan Munsie 
457b087e619SIan Munsie static ssize_t class_show(struct kobject *kobj,
458b087e619SIan Munsie 			  struct kobj_attribute *attr, char *buf)
459b087e619SIan Munsie {
460b087e619SIan Munsie 	struct afu_config_record *cr = to_cr(kobj);
461b087e619SIan Munsie 
462b087e619SIan Munsie 	return scnprintf(buf, PAGE_SIZE, "0x%.6x\n", cr->class);
463b087e619SIan Munsie }
464b087e619SIan Munsie 
465b087e619SIan Munsie static ssize_t afu_read_config(struct file *filp, struct kobject *kobj,
466b087e619SIan Munsie 			       struct bin_attribute *bin_attr, char *buf,
467b087e619SIan Munsie 			       loff_t off, size_t count)
468b087e619SIan Munsie {
469b087e619SIan Munsie 	struct afu_config_record *cr = to_cr(kobj);
470b087e619SIan Munsie 	struct cxl_afu *afu = to_cxl_afu(container_of(kobj->parent, struct device, kobj));
471b087e619SIan Munsie 
472b087e619SIan Munsie 	u64 i, j, val, size = afu->crs_len;
473b087e619SIan Munsie 
474b087e619SIan Munsie 	if (off > size)
475b087e619SIan Munsie 		return 0;
476b087e619SIan Munsie 	if (off + count > size)
477b087e619SIan Munsie 		count = size - off;
478b087e619SIan Munsie 
479b087e619SIan Munsie 	for (i = 0; i < count;) {
480b087e619SIan Munsie 		val = cxl_afu_cr_read64(afu, cr->cr, off & ~0x7);
481b087e619SIan Munsie 		for (j = off & 0x7; j < 8 && i < count; i++, j++, off++)
482b087e619SIan Munsie 			buf[i] = (val >> (j * 8)) & 0xff;
483b087e619SIan Munsie 	}
484b087e619SIan Munsie 
485b087e619SIan Munsie 	return count;
486b087e619SIan Munsie }
487b087e619SIan Munsie 
488b087e619SIan Munsie static struct kobj_attribute vendor_attribute =
489b087e619SIan Munsie 	__ATTR_RO(vendor);
490b087e619SIan Munsie static struct kobj_attribute device_attribute =
491b087e619SIan Munsie 	__ATTR_RO(device);
492b087e619SIan Munsie static struct kobj_attribute class_attribute =
493b087e619SIan Munsie 	__ATTR_RO(class);
494b087e619SIan Munsie 
495b087e619SIan Munsie static struct attribute *afu_cr_attrs[] = {
496b087e619SIan Munsie 	&vendor_attribute.attr,
497b087e619SIan Munsie 	&device_attribute.attr,
498b087e619SIan Munsie 	&class_attribute.attr,
499b087e619SIan Munsie 	NULL,
500b087e619SIan Munsie };
501b087e619SIan Munsie 
502b087e619SIan Munsie static void release_afu_config_record(struct kobject *kobj)
503b087e619SIan Munsie {
504b087e619SIan Munsie 	struct afu_config_record *cr = to_cr(kobj);
505b087e619SIan Munsie 
506b087e619SIan Munsie 	kfree(cr);
507b087e619SIan Munsie }
508b087e619SIan Munsie 
509b087e619SIan Munsie static struct kobj_type afu_config_record_type = {
510b087e619SIan Munsie 	.sysfs_ops = &kobj_sysfs_ops,
511b087e619SIan Munsie 	.release = release_afu_config_record,
512b087e619SIan Munsie 	.default_attrs = afu_cr_attrs,
513b087e619SIan Munsie };
514b087e619SIan Munsie 
515b087e619SIan Munsie static struct afu_config_record *cxl_sysfs_afu_new_cr(struct cxl_afu *afu, int cr_idx)
516b087e619SIan Munsie {
517b087e619SIan Munsie 	struct afu_config_record *cr;
518b087e619SIan Munsie 	int rc;
519b087e619SIan Munsie 
520b087e619SIan Munsie 	cr = kzalloc(sizeof(struct afu_config_record), GFP_KERNEL);
521b087e619SIan Munsie 	if (!cr)
522b087e619SIan Munsie 		return ERR_PTR(-ENOMEM);
523b087e619SIan Munsie 
524b087e619SIan Munsie 	cr->cr = cr_idx;
525b087e619SIan Munsie 	cr->device = cxl_afu_cr_read16(afu, cr_idx, PCI_DEVICE_ID);
526b087e619SIan Munsie 	cr->vendor = cxl_afu_cr_read16(afu, cr_idx, PCI_VENDOR_ID);
527b087e619SIan Munsie 	cr->class = cxl_afu_cr_read32(afu, cr_idx, PCI_CLASS_REVISION) >> 8;
528b087e619SIan Munsie 
529b087e619SIan Munsie 	/*
530b087e619SIan Munsie 	 * Export raw AFU PCIe like config record. For now this is read only by
531b087e619SIan Munsie 	 * root - we can expand that later to be readable by non-root and maybe
532b087e619SIan Munsie 	 * even writable provided we have a good use-case. Once we suport
533b087e619SIan Munsie 	 * exposing AFUs through a virtual PHB they will get that for free from
534b087e619SIan Munsie 	 * Linux' PCI infrastructure, but until then it's not clear that we
535b087e619SIan Munsie 	 * need it for anything since the main use case is just identifying
536b087e619SIan Munsie 	 * AFUs, which can be done via the vendor, device and class attributes.
537b087e619SIan Munsie 	 */
538b087e619SIan Munsie 	sysfs_bin_attr_init(&cr->config_attr);
539b087e619SIan Munsie 	cr->config_attr.attr.name = "config";
540b087e619SIan Munsie 	cr->config_attr.attr.mode = S_IRUSR;
541b087e619SIan Munsie 	cr->config_attr.size = afu->crs_len;
542b087e619SIan Munsie 	cr->config_attr.read = afu_read_config;
543b087e619SIan Munsie 
544b087e619SIan Munsie 	rc = kobject_init_and_add(&cr->kobj, &afu_config_record_type,
545b087e619SIan Munsie 				  &afu->dev.kobj, "cr%i", cr->cr);
546b087e619SIan Munsie 	if (rc)
547b087e619SIan Munsie 		goto err;
548b087e619SIan Munsie 
549b087e619SIan Munsie 	rc = sysfs_create_bin_file(&cr->kobj, &cr->config_attr);
550b087e619SIan Munsie 	if (rc)
551b087e619SIan Munsie 		goto err1;
552b087e619SIan Munsie 
553b087e619SIan Munsie 	rc = kobject_uevent(&cr->kobj, KOBJ_ADD);
554b087e619SIan Munsie 	if (rc)
555b087e619SIan Munsie 		goto err2;
556b087e619SIan Munsie 
557b087e619SIan Munsie 	return cr;
558b087e619SIan Munsie err2:
559b087e619SIan Munsie 	sysfs_remove_bin_file(&cr->kobj, &cr->config_attr);
560b087e619SIan Munsie err1:
561b087e619SIan Munsie 	kobject_put(&cr->kobj);
562b087e619SIan Munsie 	return ERR_PTR(rc);
563b087e619SIan Munsie err:
564b087e619SIan Munsie 	kfree(cr);
565b087e619SIan Munsie 	return ERR_PTR(rc);
566b087e619SIan Munsie }
567b087e619SIan Munsie 
568b087e619SIan Munsie void cxl_sysfs_afu_remove(struct cxl_afu *afu)
569b087e619SIan Munsie {
570b087e619SIan Munsie 	struct afu_config_record *cr, *tmp;
571b087e619SIan Munsie 	int i;
572b087e619SIan Munsie 
573e36f6fe1SVaibhav Jain 	/* remove the err buffer bin attribute */
574e36f6fe1SVaibhav Jain 	if (afu->eb_len)
575e36f6fe1SVaibhav Jain 		device_remove_bin_file(&afu->dev, &afu->attr_eb);
576e36f6fe1SVaibhav Jain 
577b087e619SIan Munsie 	for (i = 0; i < ARRAY_SIZE(afu_attrs); i++)
578b087e619SIan Munsie 		device_remove_file(&afu->dev, &afu_attrs[i]);
579b087e619SIan Munsie 
580b087e619SIan Munsie 	list_for_each_entry_safe(cr, tmp, &afu->crs, list) {
581b087e619SIan Munsie 		sysfs_remove_bin_file(&cr->kobj, &cr->config_attr);
582b087e619SIan Munsie 		kobject_put(&cr->kobj);
583b087e619SIan Munsie 	}
584b087e619SIan Munsie }
585b087e619SIan Munsie 
586f204e0b8SIan Munsie int cxl_sysfs_afu_add(struct cxl_afu *afu)
587f204e0b8SIan Munsie {
588b087e619SIan Munsie 	struct afu_config_record *cr;
589f204e0b8SIan Munsie 	int i, rc;
590f204e0b8SIan Munsie 
591b087e619SIan Munsie 	INIT_LIST_HEAD(&afu->crs);
592b087e619SIan Munsie 
593f204e0b8SIan Munsie 	for (i = 0; i < ARRAY_SIZE(afu_attrs); i++) {
594f204e0b8SIan Munsie 		if ((rc = device_create_file(&afu->dev, &afu_attrs[i])))
595f204e0b8SIan Munsie 			goto err;
596f204e0b8SIan Munsie 	}
597f204e0b8SIan Munsie 
598e36f6fe1SVaibhav Jain 	/* conditionally create the add the binary file for error info buffer */
599e36f6fe1SVaibhav Jain 	if (afu->eb_len) {
600e36f6fe1SVaibhav Jain 		afu->attr_eb.attr.name = "afu_err_buff";
601e36f6fe1SVaibhav Jain 		afu->attr_eb.attr.mode = S_IRUGO;
602e36f6fe1SVaibhav Jain 		afu->attr_eb.size = afu->eb_len;
603e36f6fe1SVaibhav Jain 		afu->attr_eb.read = afu_eb_read;
604e36f6fe1SVaibhav Jain 
605e36f6fe1SVaibhav Jain 		rc = device_create_bin_file(&afu->dev, &afu->attr_eb);
606e36f6fe1SVaibhav Jain 		if (rc) {
607e36f6fe1SVaibhav Jain 			dev_err(&afu->dev,
608e36f6fe1SVaibhav Jain 				"Unable to create eb attr for the afu. Err(%d)\n",
609e36f6fe1SVaibhav Jain 				rc);
610e36f6fe1SVaibhav Jain 			goto err;
611e36f6fe1SVaibhav Jain 		}
612e36f6fe1SVaibhav Jain 	}
613e36f6fe1SVaibhav Jain 
614b087e619SIan Munsie 	for (i = 0; i < afu->crs_num; i++) {
615b087e619SIan Munsie 		cr = cxl_sysfs_afu_new_cr(afu, i);
616b087e619SIan Munsie 		if (IS_ERR(cr)) {
617b087e619SIan Munsie 			rc = PTR_ERR(cr);
618b087e619SIan Munsie 			goto err1;
619b087e619SIan Munsie 		}
620b087e619SIan Munsie 		list_add(&cr->list, &afu->crs);
621b087e619SIan Munsie 	}
622b087e619SIan Munsie 
623f204e0b8SIan Munsie 	return 0;
624f204e0b8SIan Munsie 
625b087e619SIan Munsie err1:
626b087e619SIan Munsie 	cxl_sysfs_afu_remove(afu);
627b087e619SIan Munsie 	return rc;
628f204e0b8SIan Munsie err:
629e36f6fe1SVaibhav Jain 	/* reset the eb_len as we havent created the bin attr */
630e36f6fe1SVaibhav Jain 	afu->eb_len = 0;
631e36f6fe1SVaibhav Jain 
632f204e0b8SIan Munsie 	for (i--; i >= 0; i--)
633f204e0b8SIan Munsie 		device_remove_file(&afu->dev, &afu_attrs[i]);
634f204e0b8SIan Munsie 	return rc;
635f204e0b8SIan Munsie }
636f204e0b8SIan Munsie 
637f204e0b8SIan Munsie int cxl_sysfs_afu_m_add(struct cxl_afu *afu)
638f204e0b8SIan Munsie {
639f204e0b8SIan Munsie 	int i, rc;
640f204e0b8SIan Munsie 
641f204e0b8SIan Munsie 	for (i = 0; i < ARRAY_SIZE(afu_master_attrs); i++) {
642f204e0b8SIan Munsie 		if ((rc = device_create_file(afu->chardev_m, &afu_master_attrs[i])))
643f204e0b8SIan Munsie 			goto err;
644f204e0b8SIan Munsie 	}
645f204e0b8SIan Munsie 
646f204e0b8SIan Munsie 	return 0;
647f204e0b8SIan Munsie 
648f204e0b8SIan Munsie err:
649f204e0b8SIan Munsie 	for (i--; i >= 0; i--)
650f204e0b8SIan Munsie 		device_remove_file(afu->chardev_m, &afu_master_attrs[i]);
651f204e0b8SIan Munsie 	return rc;
652f204e0b8SIan Munsie }
653f204e0b8SIan Munsie 
654f204e0b8SIan Munsie void cxl_sysfs_afu_m_remove(struct cxl_afu *afu)
655f204e0b8SIan Munsie {
656f204e0b8SIan Munsie 	int i;
657f204e0b8SIan Munsie 
658f204e0b8SIan Munsie 	for (i = 0; i < ARRAY_SIZE(afu_master_attrs); i++)
659f204e0b8SIan Munsie 		device_remove_file(afu->chardev_m, &afu_master_attrs[i]);
660f204e0b8SIan Munsie }
661