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