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