1 // SPDX-License-Identifier: GPL-2.0+ 2 // Copyright 2017 IBM Corp. 3 #include <linux/sysfs.h> 4 #include "ocxl_internal.h" 5 6 static ssize_t global_mmio_size_show(struct device *device, 7 struct device_attribute *attr, 8 char *buf) 9 { 10 struct ocxl_afu *afu = to_ocxl_afu(device); 11 12 return scnprintf(buf, PAGE_SIZE, "%d\n", 13 afu->config.global_mmio_size); 14 } 15 16 static ssize_t pp_mmio_size_show(struct device *device, 17 struct device_attribute *attr, 18 char *buf) 19 { 20 struct ocxl_afu *afu = to_ocxl_afu(device); 21 22 return scnprintf(buf, PAGE_SIZE, "%d\n", 23 afu->config.pp_mmio_stride); 24 } 25 26 static ssize_t afu_version_show(struct device *device, 27 struct device_attribute *attr, 28 char *buf) 29 { 30 struct ocxl_afu *afu = to_ocxl_afu(device); 31 32 return scnprintf(buf, PAGE_SIZE, "%hhu:%hhu\n", 33 afu->config.version_major, 34 afu->config.version_minor); 35 } 36 37 static ssize_t contexts_show(struct device *device, 38 struct device_attribute *attr, 39 char *buf) 40 { 41 struct ocxl_afu *afu = to_ocxl_afu(device); 42 43 return scnprintf(buf, PAGE_SIZE, "%d/%d\n", 44 afu->pasid_count, afu->pasid_max); 45 } 46 47 static struct device_attribute afu_attrs[] = { 48 __ATTR_RO(global_mmio_size), 49 __ATTR_RO(pp_mmio_size), 50 __ATTR_RO(afu_version), 51 __ATTR_RO(contexts), 52 }; 53 54 static ssize_t global_mmio_read(struct file *filp, struct kobject *kobj, 55 struct bin_attribute *bin_attr, char *buf, 56 loff_t off, size_t count) 57 { 58 struct ocxl_afu *afu = to_ocxl_afu(kobj_to_dev(kobj)); 59 60 if (count == 0 || off < 0 || 61 off >= afu->config.global_mmio_size) 62 return 0; 63 memcpy_fromio(buf, afu->global_mmio_ptr + off, count); 64 return count; 65 } 66 67 static int global_mmio_fault(struct vm_fault *vmf) 68 { 69 struct vm_area_struct *vma = vmf->vma; 70 struct ocxl_afu *afu = vma->vm_private_data; 71 unsigned long offset; 72 73 if (vmf->pgoff >= (afu->config.global_mmio_size >> PAGE_SHIFT)) 74 return VM_FAULT_SIGBUS; 75 76 offset = vmf->pgoff; 77 offset += (afu->global_mmio_start >> PAGE_SHIFT); 78 vm_insert_pfn(vma, vmf->address, offset); 79 return VM_FAULT_NOPAGE; 80 } 81 82 static const struct vm_operations_struct global_mmio_vmops = { 83 .fault = global_mmio_fault, 84 }; 85 86 static int global_mmio_mmap(struct file *filp, struct kobject *kobj, 87 struct bin_attribute *bin_attr, 88 struct vm_area_struct *vma) 89 { 90 struct ocxl_afu *afu = to_ocxl_afu(kobj_to_dev(kobj)); 91 92 if ((vma_pages(vma) + vma->vm_pgoff) > 93 (afu->config.global_mmio_size >> PAGE_SHIFT)) 94 return -EINVAL; 95 96 vma->vm_flags |= VM_IO | VM_PFNMAP; 97 vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); 98 vma->vm_ops = &global_mmio_vmops; 99 vma->vm_private_data = afu; 100 return 0; 101 } 102 103 int ocxl_sysfs_add_afu(struct ocxl_afu *afu) 104 { 105 int i, rc; 106 107 for (i = 0; i < ARRAY_SIZE(afu_attrs); i++) { 108 rc = device_create_file(&afu->dev, &afu_attrs[i]); 109 if (rc) 110 goto err; 111 } 112 113 sysfs_attr_init(&afu->attr_global_mmio.attr); 114 afu->attr_global_mmio.attr.name = "global_mmio_area"; 115 afu->attr_global_mmio.attr.mode = 0600; 116 afu->attr_global_mmio.size = afu->config.global_mmio_size; 117 afu->attr_global_mmio.read = global_mmio_read; 118 afu->attr_global_mmio.mmap = global_mmio_mmap; 119 rc = device_create_bin_file(&afu->dev, &afu->attr_global_mmio); 120 if (rc) { 121 dev_err(&afu->dev, 122 "Unable to create global mmio attr for afu: %d\n", 123 rc); 124 goto err; 125 } 126 127 return 0; 128 129 err: 130 for (i--; i >= 0; i--) 131 device_remove_file(&afu->dev, &afu_attrs[i]); 132 return rc; 133 } 134 135 void ocxl_sysfs_remove_afu(struct ocxl_afu *afu) 136 { 137 int i; 138 139 for (i = 0; i < ARRAY_SIZE(afu_attrs); i++) 140 device_remove_file(&afu->dev, &afu_attrs[i]); 141 device_remove_bin_file(&afu->dev, &afu->attr_global_mmio); 142 } 143