blob: ed4ad461143c1a160d05e95da9f6e2fc4aff4cab [file] [log] [blame]
Ian Munsief204e0b2014-10-08 19:55:02 +11001/*
2 * Copyright 2014 IBM Corp.
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version
7 * 2 of the License, or (at your option) any later version.
8 */
9
10#include <linux/kernel.h>
11#include <linux/device.h>
12#include <linux/sysfs.h>
13
14#include "cxl.h"
15
16#define to_afu_chardev_m(d) dev_get_drvdata(d)
17
18/********* Adapter attributes **********************************************/
19
20static ssize_t caia_version_show(struct device *device,
21 struct device_attribute *attr,
22 char *buf)
23{
24 struct cxl *adapter = to_cxl_adapter(device);
25
26 return scnprintf(buf, PAGE_SIZE, "%i.%i\n", adapter->caia_major,
27 adapter->caia_minor);
28}
29
30static ssize_t psl_revision_show(struct device *device,
31 struct device_attribute *attr,
32 char *buf)
33{
34 struct cxl *adapter = to_cxl_adapter(device);
35
36 return scnprintf(buf, PAGE_SIZE, "%i\n", adapter->psl_rev);
37}
38
39static ssize_t base_image_show(struct device *device,
40 struct device_attribute *attr,
41 char *buf)
42{
43 struct cxl *adapter = to_cxl_adapter(device);
44
45 return scnprintf(buf, PAGE_SIZE, "%i\n", adapter->base_image);
46}
47
48static ssize_t image_loaded_show(struct device *device,
49 struct device_attribute *attr,
50 char *buf)
51{
52 struct cxl *adapter = to_cxl_adapter(device);
53
54 if (adapter->user_image_loaded)
55 return scnprintf(buf, PAGE_SIZE, "user\n");
56 return scnprintf(buf, PAGE_SIZE, "factory\n");
57}
58
Ryan Grimm95bc11b2015-01-19 11:52:49 -060059static ssize_t load_image_on_perst_show(struct device *device,
60 struct device_attribute *attr,
61 char *buf)
62{
63 struct cxl *adapter = to_cxl_adapter(device);
64
65 if (!adapter->perst_loads_image)
66 return scnprintf(buf, PAGE_SIZE, "none\n");
67
68 if (adapter->perst_select_user)
69 return scnprintf(buf, PAGE_SIZE, "user\n");
70 return scnprintf(buf, PAGE_SIZE, "factory\n");
71}
72
73static ssize_t load_image_on_perst_store(struct device *device,
74 struct device_attribute *attr,
75 const char *buf, size_t count)
76{
77 struct cxl *adapter = to_cxl_adapter(device);
78 int rc;
79
80 if (!strncmp(buf, "none", 4))
81 adapter->perst_loads_image = false;
82 else if (!strncmp(buf, "user", 4)) {
83 adapter->perst_select_user = true;
84 adapter->perst_loads_image = true;
85 } else if (!strncmp(buf, "factory", 7)) {
86 adapter->perst_select_user = false;
87 adapter->perst_loads_image = true;
88 } else
89 return -EINVAL;
90
91 if ((rc = cxl_update_image_control(adapter)))
92 return rc;
93
94 return count;
95}
96
Ian Munsief204e0b2014-10-08 19:55:02 +110097static struct device_attribute adapter_attrs[] = {
98 __ATTR_RO(caia_version),
99 __ATTR_RO(psl_revision),
100 __ATTR_RO(base_image),
101 __ATTR_RO(image_loaded),
Ryan Grimm95bc11b2015-01-19 11:52:49 -0600102 __ATTR_RW(load_image_on_perst),
Ian Munsief204e0b2014-10-08 19:55:02 +1100103};
104
105
106/********* AFU master specific attributes **********************************/
107
108static ssize_t mmio_size_show_master(struct device *device,
109 struct device_attribute *attr,
110 char *buf)
111{
112 struct cxl_afu *afu = to_afu_chardev_m(device);
113
114 return scnprintf(buf, PAGE_SIZE, "%llu\n", afu->adapter->ps_size);
115}
116
117static ssize_t pp_mmio_off_show(struct device *device,
118 struct device_attribute *attr,
119 char *buf)
120{
121 struct cxl_afu *afu = to_afu_chardev_m(device);
122
123 return scnprintf(buf, PAGE_SIZE, "%llu\n", afu->pp_offset);
124}
125
126static ssize_t pp_mmio_len_show(struct device *device,
127 struct device_attribute *attr,
128 char *buf)
129{
130 struct cxl_afu *afu = to_afu_chardev_m(device);
131
132 return scnprintf(buf, PAGE_SIZE, "%llu\n", afu->pp_size);
133}
134
135static struct device_attribute afu_master_attrs[] = {
136 __ATTR(mmio_size, S_IRUGO, mmio_size_show_master, NULL),
137 __ATTR_RO(pp_mmio_off),
138 __ATTR_RO(pp_mmio_len),
139};
140
141
142/********* AFU attributes **************************************************/
143
144static ssize_t mmio_size_show(struct device *device,
145 struct device_attribute *attr,
146 char *buf)
147{
148 struct cxl_afu *afu = to_cxl_afu(device);
149
150 if (afu->pp_size)
151 return scnprintf(buf, PAGE_SIZE, "%llu\n", afu->pp_size);
152 return scnprintf(buf, PAGE_SIZE, "%llu\n", afu->adapter->ps_size);
153}
154
155static ssize_t reset_store_afu(struct device *device,
156 struct device_attribute *attr,
157 const char *buf, size_t count)
158{
159 struct cxl_afu *afu = to_cxl_afu(device);
160 int rc;
161
162 /* Not safe to reset if it is currently in use */
Ian Munsieee41d112014-12-08 19:17:55 +1100163 mutex_lock(&afu->contexts_lock);
Ian Munsief204e0b2014-10-08 19:55:02 +1100164 if (!idr_is_empty(&afu->contexts_idr)) {
165 rc = -EBUSY;
166 goto err;
167 }
168
169 if ((rc = cxl_afu_reset(afu)))
170 goto err;
171
172 rc = count;
173err:
Ian Munsieee41d112014-12-08 19:17:55 +1100174 mutex_unlock(&afu->contexts_lock);
Ian Munsief204e0b2014-10-08 19:55:02 +1100175 return rc;
176}
177
178static ssize_t irqs_min_show(struct device *device,
179 struct device_attribute *attr,
180 char *buf)
181{
182 struct cxl_afu *afu = to_cxl_afu(device);
183
184 return scnprintf(buf, PAGE_SIZE, "%i\n", afu->pp_irqs);
185}
186
187static ssize_t irqs_max_show(struct device *device,
188 struct device_attribute *attr,
189 char *buf)
190{
191 struct cxl_afu *afu = to_cxl_afu(device);
192
193 return scnprintf(buf, PAGE_SIZE, "%i\n", afu->irqs_max);
194}
195
196static ssize_t irqs_max_store(struct device *device,
197 struct device_attribute *attr,
198 const char *buf, size_t count)
199{
200 struct cxl_afu *afu = to_cxl_afu(device);
201 ssize_t ret;
202 int irqs_max;
203
204 ret = sscanf(buf, "%i", &irqs_max);
205 if (ret != 1)
206 return -EINVAL;
207
208 if (irqs_max < afu->pp_irqs)
209 return -EINVAL;
210
211 if (irqs_max > afu->adapter->user_irqs)
212 return -EINVAL;
213
214 afu->irqs_max = irqs_max;
215 return count;
216}
217
218static ssize_t modes_supported_show(struct device *device,
219 struct device_attribute *attr, char *buf)
220{
221 struct cxl_afu *afu = to_cxl_afu(device);
222 char *p = buf, *end = buf + PAGE_SIZE;
223
224 if (afu->modes_supported & CXL_MODE_DEDICATED)
225 p += scnprintf(p, end - p, "dedicated_process\n");
226 if (afu->modes_supported & CXL_MODE_DIRECTED)
227 p += scnprintf(p, end - p, "afu_directed\n");
228 return (p - buf);
229}
230
231static ssize_t prefault_mode_show(struct device *device,
232 struct device_attribute *attr,
233 char *buf)
234{
235 struct cxl_afu *afu = to_cxl_afu(device);
236
237 switch (afu->prefault_mode) {
238 case CXL_PREFAULT_WED:
239 return scnprintf(buf, PAGE_SIZE, "work_element_descriptor\n");
240 case CXL_PREFAULT_ALL:
241 return scnprintf(buf, PAGE_SIZE, "all\n");
242 default:
243 return scnprintf(buf, PAGE_SIZE, "none\n");
244 }
245}
246
247static ssize_t prefault_mode_store(struct device *device,
248 struct device_attribute *attr,
249 const char *buf, size_t count)
250{
251 struct cxl_afu *afu = to_cxl_afu(device);
252 enum prefault_modes mode = -1;
253
254 if (!strncmp(buf, "work_element_descriptor", 23))
255 mode = CXL_PREFAULT_WED;
256 if (!strncmp(buf, "all", 3))
257 mode = CXL_PREFAULT_ALL;
258 if (!strncmp(buf, "none", 4))
259 mode = CXL_PREFAULT_NONE;
260
261 if (mode == -1)
262 return -EINVAL;
263
264 afu->prefault_mode = mode;
265 return count;
266}
267
268static ssize_t mode_show(struct device *device,
269 struct device_attribute *attr,
270 char *buf)
271{
272 struct cxl_afu *afu = to_cxl_afu(device);
273
274 if (afu->current_mode == CXL_MODE_DEDICATED)
275 return scnprintf(buf, PAGE_SIZE, "dedicated_process\n");
276 if (afu->current_mode == CXL_MODE_DIRECTED)
277 return scnprintf(buf, PAGE_SIZE, "afu_directed\n");
278 return scnprintf(buf, PAGE_SIZE, "none\n");
279}
280
281static ssize_t mode_store(struct device *device, struct device_attribute *attr,
282 const char *buf, size_t count)
283{
284 struct cxl_afu *afu = to_cxl_afu(device);
285 int old_mode, mode = -1;
286 int rc = -EBUSY;
287
288 /* can't change this if we have a user */
Ian Munsieee41d112014-12-08 19:17:55 +1100289 mutex_lock(&afu->contexts_lock);
Ian Munsief204e0b2014-10-08 19:55:02 +1100290 if (!idr_is_empty(&afu->contexts_idr))
291 goto err;
292
293 if (!strncmp(buf, "dedicated_process", 17))
294 mode = CXL_MODE_DEDICATED;
295 if (!strncmp(buf, "afu_directed", 12))
296 mode = CXL_MODE_DIRECTED;
297 if (!strncmp(buf, "none", 4))
298 mode = 0;
299
300 if (mode == -1) {
301 rc = -EINVAL;
302 goto err;
303 }
304
305 /*
306 * cxl_afu_deactivate_mode needs to be done outside the lock, prevent
307 * other contexts coming in before we are ready:
308 */
309 old_mode = afu->current_mode;
310 afu->current_mode = 0;
311 afu->num_procs = 0;
312
Ian Munsieee41d112014-12-08 19:17:55 +1100313 mutex_unlock(&afu->contexts_lock);
Ian Munsief204e0b2014-10-08 19:55:02 +1100314
315 if ((rc = _cxl_afu_deactivate_mode(afu, old_mode)))
316 return rc;
317 if ((rc = cxl_afu_activate_mode(afu, mode)))
318 return rc;
319
320 return count;
321err:
Ian Munsieee41d112014-12-08 19:17:55 +1100322 mutex_unlock(&afu->contexts_lock);
Ian Munsief204e0b2014-10-08 19:55:02 +1100323 return rc;
324}
325
326static ssize_t api_version_show(struct device *device,
327 struct device_attribute *attr,
328 char *buf)
329{
330 return scnprintf(buf, PAGE_SIZE, "%i\n", CXL_API_VERSION);
331}
332
333static ssize_t api_version_compatible_show(struct device *device,
334 struct device_attribute *attr,
335 char *buf)
336{
337 return scnprintf(buf, PAGE_SIZE, "%i\n", CXL_API_VERSION_COMPATIBLE);
338}
339
340static struct device_attribute afu_attrs[] = {
341 __ATTR_RO(mmio_size),
342 __ATTR_RO(irqs_min),
343 __ATTR_RW(irqs_max),
344 __ATTR_RO(modes_supported),
345 __ATTR_RW(mode),
346 __ATTR_RW(prefault_mode),
347 __ATTR_RO(api_version),
348 __ATTR_RO(api_version_compatible),
349 __ATTR(reset, S_IWUSR, NULL, reset_store_afu),
350};
351
352
353
354int cxl_sysfs_adapter_add(struct cxl *adapter)
355{
356 int i, rc;
357
358 for (i = 0; i < ARRAY_SIZE(adapter_attrs); i++) {
359 if ((rc = device_create_file(&adapter->dev, &adapter_attrs[i])))
360 goto err;
361 }
362 return 0;
363err:
364 for (i--; i >= 0; i--)
365 device_remove_file(&adapter->dev, &adapter_attrs[i]);
366 return rc;
367}
368void cxl_sysfs_adapter_remove(struct cxl *adapter)
369{
370 int i;
371
372 for (i = 0; i < ARRAY_SIZE(adapter_attrs); i++)
373 device_remove_file(&adapter->dev, &adapter_attrs[i]);
374}
375
376int cxl_sysfs_afu_add(struct cxl_afu *afu)
377{
378 int i, rc;
379
380 for (i = 0; i < ARRAY_SIZE(afu_attrs); i++) {
381 if ((rc = device_create_file(&afu->dev, &afu_attrs[i])))
382 goto err;
383 }
384
385 return 0;
386
387err:
388 for (i--; i >= 0; i--)
389 device_remove_file(&afu->dev, &afu_attrs[i]);
390 return rc;
391}
392
393void cxl_sysfs_afu_remove(struct cxl_afu *afu)
394{
395 int i;
396
397 for (i = 0; i < ARRAY_SIZE(afu_attrs); i++)
398 device_remove_file(&afu->dev, &afu_attrs[i]);
399}
400
401int cxl_sysfs_afu_m_add(struct cxl_afu *afu)
402{
403 int i, rc;
404
405 for (i = 0; i < ARRAY_SIZE(afu_master_attrs); i++) {
406 if ((rc = device_create_file(afu->chardev_m, &afu_master_attrs[i])))
407 goto err;
408 }
409
410 return 0;
411
412err:
413 for (i--; i >= 0; i--)
414 device_remove_file(afu->chardev_m, &afu_master_attrs[i]);
415 return rc;
416}
417
418void cxl_sysfs_afu_m_remove(struct cxl_afu *afu)
419{
420 int i;
421
422 for (i = 0; i < ARRAY_SIZE(afu_master_attrs); i++)
423 device_remove_file(afu->chardev_m, &afu_master_attrs[i]);
424}