xref: /OK3568_Linux_fs/kernel/drivers/misc/ocxl/sysfs.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0+
2*4882a593Smuzhiyun // Copyright 2017 IBM Corp.
3*4882a593Smuzhiyun #include <linux/sysfs.h>
4*4882a593Smuzhiyun #include "ocxl_internal.h"
5*4882a593Smuzhiyun 
to_afu(struct device * device)6*4882a593Smuzhiyun static inline struct ocxl_afu *to_afu(struct device *device)
7*4882a593Smuzhiyun {
8*4882a593Smuzhiyun 	struct ocxl_file_info *info = container_of(device, struct ocxl_file_info, dev);
9*4882a593Smuzhiyun 
10*4882a593Smuzhiyun 	return info->afu;
11*4882a593Smuzhiyun }
12*4882a593Smuzhiyun 
global_mmio_size_show(struct device * device,struct device_attribute * attr,char * buf)13*4882a593Smuzhiyun static ssize_t global_mmio_size_show(struct device *device,
14*4882a593Smuzhiyun 				struct device_attribute *attr,
15*4882a593Smuzhiyun 				char *buf)
16*4882a593Smuzhiyun {
17*4882a593Smuzhiyun 	struct ocxl_afu *afu = to_afu(device);
18*4882a593Smuzhiyun 
19*4882a593Smuzhiyun 	return scnprintf(buf, PAGE_SIZE, "%d\n",
20*4882a593Smuzhiyun 			afu->config.global_mmio_size);
21*4882a593Smuzhiyun }
22*4882a593Smuzhiyun 
pp_mmio_size_show(struct device * device,struct device_attribute * attr,char * buf)23*4882a593Smuzhiyun static ssize_t pp_mmio_size_show(struct device *device,
24*4882a593Smuzhiyun 				struct device_attribute *attr,
25*4882a593Smuzhiyun 				char *buf)
26*4882a593Smuzhiyun {
27*4882a593Smuzhiyun 	struct ocxl_afu *afu = to_afu(device);
28*4882a593Smuzhiyun 
29*4882a593Smuzhiyun 	return scnprintf(buf, PAGE_SIZE, "%d\n",
30*4882a593Smuzhiyun 			afu->config.pp_mmio_stride);
31*4882a593Smuzhiyun }
32*4882a593Smuzhiyun 
afu_version_show(struct device * device,struct device_attribute * attr,char * buf)33*4882a593Smuzhiyun static ssize_t afu_version_show(struct device *device,
34*4882a593Smuzhiyun 				struct device_attribute *attr,
35*4882a593Smuzhiyun 				char *buf)
36*4882a593Smuzhiyun {
37*4882a593Smuzhiyun 	struct ocxl_afu *afu = to_afu(device);
38*4882a593Smuzhiyun 
39*4882a593Smuzhiyun 	return scnprintf(buf, PAGE_SIZE, "%hhu:%hhu\n",
40*4882a593Smuzhiyun 			afu->config.version_major,
41*4882a593Smuzhiyun 			afu->config.version_minor);
42*4882a593Smuzhiyun }
43*4882a593Smuzhiyun 
contexts_show(struct device * device,struct device_attribute * attr,char * buf)44*4882a593Smuzhiyun static ssize_t contexts_show(struct device *device,
45*4882a593Smuzhiyun 		struct device_attribute *attr,
46*4882a593Smuzhiyun 		char *buf)
47*4882a593Smuzhiyun {
48*4882a593Smuzhiyun 	struct ocxl_afu *afu = to_afu(device);
49*4882a593Smuzhiyun 
50*4882a593Smuzhiyun 	return scnprintf(buf, PAGE_SIZE, "%d/%d\n",
51*4882a593Smuzhiyun 			afu->pasid_count, afu->pasid_max);
52*4882a593Smuzhiyun }
53*4882a593Smuzhiyun 
reload_on_reset_show(struct device * device,struct device_attribute * attr,char * buf)54*4882a593Smuzhiyun static ssize_t reload_on_reset_show(struct device *device,
55*4882a593Smuzhiyun 				    struct device_attribute *attr,
56*4882a593Smuzhiyun 				    char *buf)
57*4882a593Smuzhiyun {
58*4882a593Smuzhiyun 	struct ocxl_afu *afu = to_afu(device);
59*4882a593Smuzhiyun 	struct ocxl_fn *fn = afu->fn;
60*4882a593Smuzhiyun 	struct pci_dev *pci_dev = to_pci_dev(fn->dev.parent);
61*4882a593Smuzhiyun 	int val;
62*4882a593Smuzhiyun 
63*4882a593Smuzhiyun 	if (ocxl_config_get_reset_reload(pci_dev, &val))
64*4882a593Smuzhiyun 		return scnprintf(buf, PAGE_SIZE, "unavailable\n");
65*4882a593Smuzhiyun 
66*4882a593Smuzhiyun 	return scnprintf(buf, PAGE_SIZE, "%d\n", val);
67*4882a593Smuzhiyun }
68*4882a593Smuzhiyun 
reload_on_reset_store(struct device * device,struct device_attribute * attr,const char * buf,size_t count)69*4882a593Smuzhiyun static ssize_t reload_on_reset_store(struct device *device,
70*4882a593Smuzhiyun 				     struct device_attribute *attr,
71*4882a593Smuzhiyun 				     const char *buf, size_t count)
72*4882a593Smuzhiyun {
73*4882a593Smuzhiyun 	struct ocxl_afu *afu = to_afu(device);
74*4882a593Smuzhiyun 	struct ocxl_fn *fn = afu->fn;
75*4882a593Smuzhiyun 	struct pci_dev *pci_dev = to_pci_dev(fn->dev.parent);
76*4882a593Smuzhiyun 	int rc, val;
77*4882a593Smuzhiyun 
78*4882a593Smuzhiyun 	rc = kstrtoint(buf, 0, &val);
79*4882a593Smuzhiyun 	if (rc || (val != 0 && val != 1))
80*4882a593Smuzhiyun 		return -EINVAL;
81*4882a593Smuzhiyun 
82*4882a593Smuzhiyun 	if (ocxl_config_set_reset_reload(pci_dev, val))
83*4882a593Smuzhiyun 		return -ENODEV;
84*4882a593Smuzhiyun 
85*4882a593Smuzhiyun 	return count;
86*4882a593Smuzhiyun }
87*4882a593Smuzhiyun 
88*4882a593Smuzhiyun static struct device_attribute afu_attrs[] = {
89*4882a593Smuzhiyun 	__ATTR_RO(global_mmio_size),
90*4882a593Smuzhiyun 	__ATTR_RO(pp_mmio_size),
91*4882a593Smuzhiyun 	__ATTR_RO(afu_version),
92*4882a593Smuzhiyun 	__ATTR_RO(contexts),
93*4882a593Smuzhiyun 	__ATTR_RW(reload_on_reset),
94*4882a593Smuzhiyun };
95*4882a593Smuzhiyun 
global_mmio_read(struct file * filp,struct kobject * kobj,struct bin_attribute * bin_attr,char * buf,loff_t off,size_t count)96*4882a593Smuzhiyun static ssize_t global_mmio_read(struct file *filp, struct kobject *kobj,
97*4882a593Smuzhiyun 				struct bin_attribute *bin_attr, char *buf,
98*4882a593Smuzhiyun 				loff_t off, size_t count)
99*4882a593Smuzhiyun {
100*4882a593Smuzhiyun 	struct ocxl_afu *afu = to_afu(kobj_to_dev(kobj));
101*4882a593Smuzhiyun 
102*4882a593Smuzhiyun 	if (count == 0 || off < 0 ||
103*4882a593Smuzhiyun 		off >= afu->config.global_mmio_size)
104*4882a593Smuzhiyun 		return 0;
105*4882a593Smuzhiyun 	memcpy_fromio(buf, afu->global_mmio_ptr + off, count);
106*4882a593Smuzhiyun 	return count;
107*4882a593Smuzhiyun }
108*4882a593Smuzhiyun 
global_mmio_fault(struct vm_fault * vmf)109*4882a593Smuzhiyun static vm_fault_t global_mmio_fault(struct vm_fault *vmf)
110*4882a593Smuzhiyun {
111*4882a593Smuzhiyun 	struct vm_area_struct *vma = vmf->vma;
112*4882a593Smuzhiyun 	struct ocxl_afu *afu = vma->vm_private_data;
113*4882a593Smuzhiyun 	unsigned long offset;
114*4882a593Smuzhiyun 
115*4882a593Smuzhiyun 	if (vmf->pgoff >= (afu->config.global_mmio_size >> PAGE_SHIFT))
116*4882a593Smuzhiyun 		return VM_FAULT_SIGBUS;
117*4882a593Smuzhiyun 
118*4882a593Smuzhiyun 	offset = vmf->pgoff;
119*4882a593Smuzhiyun 	offset += (afu->global_mmio_start >> PAGE_SHIFT);
120*4882a593Smuzhiyun 	return vmf_insert_pfn(vma, vmf->address, offset);
121*4882a593Smuzhiyun }
122*4882a593Smuzhiyun 
123*4882a593Smuzhiyun static const struct vm_operations_struct global_mmio_vmops = {
124*4882a593Smuzhiyun 	.fault = global_mmio_fault,
125*4882a593Smuzhiyun };
126*4882a593Smuzhiyun 
global_mmio_mmap(struct file * filp,struct kobject * kobj,struct bin_attribute * bin_attr,struct vm_area_struct * vma)127*4882a593Smuzhiyun static int global_mmio_mmap(struct file *filp, struct kobject *kobj,
128*4882a593Smuzhiyun 			struct bin_attribute *bin_attr,
129*4882a593Smuzhiyun 			struct vm_area_struct *vma)
130*4882a593Smuzhiyun {
131*4882a593Smuzhiyun 	struct ocxl_afu *afu = to_afu(kobj_to_dev(kobj));
132*4882a593Smuzhiyun 
133*4882a593Smuzhiyun 	if ((vma_pages(vma) + vma->vm_pgoff) >
134*4882a593Smuzhiyun 		(afu->config.global_mmio_size >> PAGE_SHIFT))
135*4882a593Smuzhiyun 		return -EINVAL;
136*4882a593Smuzhiyun 
137*4882a593Smuzhiyun 	vma->vm_flags |= VM_IO | VM_PFNMAP;
138*4882a593Smuzhiyun 	vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
139*4882a593Smuzhiyun 	vma->vm_ops = &global_mmio_vmops;
140*4882a593Smuzhiyun 	vma->vm_private_data = afu;
141*4882a593Smuzhiyun 	return 0;
142*4882a593Smuzhiyun }
143*4882a593Smuzhiyun 
ocxl_sysfs_register_afu(struct ocxl_file_info * info)144*4882a593Smuzhiyun int ocxl_sysfs_register_afu(struct ocxl_file_info *info)
145*4882a593Smuzhiyun {
146*4882a593Smuzhiyun 	int i, rc;
147*4882a593Smuzhiyun 
148*4882a593Smuzhiyun 	for (i = 0; i < ARRAY_SIZE(afu_attrs); i++) {
149*4882a593Smuzhiyun 		rc = device_create_file(&info->dev, &afu_attrs[i]);
150*4882a593Smuzhiyun 		if (rc)
151*4882a593Smuzhiyun 			goto err;
152*4882a593Smuzhiyun 	}
153*4882a593Smuzhiyun 
154*4882a593Smuzhiyun 	sysfs_attr_init(&info->attr_global_mmio.attr);
155*4882a593Smuzhiyun 	info->attr_global_mmio.attr.name = "global_mmio_area";
156*4882a593Smuzhiyun 	info->attr_global_mmio.attr.mode = 0600;
157*4882a593Smuzhiyun 	info->attr_global_mmio.size = info->afu->config.global_mmio_size;
158*4882a593Smuzhiyun 	info->attr_global_mmio.read = global_mmio_read;
159*4882a593Smuzhiyun 	info->attr_global_mmio.mmap = global_mmio_mmap;
160*4882a593Smuzhiyun 	rc = device_create_bin_file(&info->dev, &info->attr_global_mmio);
161*4882a593Smuzhiyun 	if (rc) {
162*4882a593Smuzhiyun 		dev_err(&info->dev, "Unable to create global mmio attr for afu: %d\n", rc);
163*4882a593Smuzhiyun 		goto err;
164*4882a593Smuzhiyun 	}
165*4882a593Smuzhiyun 
166*4882a593Smuzhiyun 	return 0;
167*4882a593Smuzhiyun 
168*4882a593Smuzhiyun err:
169*4882a593Smuzhiyun 	for (i--; i >= 0; i--)
170*4882a593Smuzhiyun 		device_remove_file(&info->dev, &afu_attrs[i]);
171*4882a593Smuzhiyun 
172*4882a593Smuzhiyun 	return rc;
173*4882a593Smuzhiyun }
174*4882a593Smuzhiyun 
ocxl_sysfs_unregister_afu(struct ocxl_file_info * info)175*4882a593Smuzhiyun void ocxl_sysfs_unregister_afu(struct ocxl_file_info *info)
176*4882a593Smuzhiyun {
177*4882a593Smuzhiyun 	int i;
178*4882a593Smuzhiyun 
179*4882a593Smuzhiyun 	/*
180*4882a593Smuzhiyun 	 * device_remove_bin_file is safe to call if the file is not added as
181*4882a593Smuzhiyun 	 * the files are removed by name, and early exit if not found
182*4882a593Smuzhiyun 	 */
183*4882a593Smuzhiyun 	for (i = 0; i < ARRAY_SIZE(afu_attrs); i++)
184*4882a593Smuzhiyun 		device_remove_file(&info->dev, &afu_attrs[i]);
185*4882a593Smuzhiyun 	device_remove_bin_file(&info->dev, &info->attr_global_mmio);
186*4882a593Smuzhiyun }
187