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 vm_fault_t 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 return vmf_insert_pfn(vma, vmf->address, offset); 79 } 80 81 static const struct vm_operations_struct global_mmio_vmops = { 82 .fault = global_mmio_fault, 83 }; 84 85 static int global_mmio_mmap(struct file *filp, struct kobject *kobj, 86 struct bin_attribute *bin_attr, 87 struct vm_area_struct *vma) 88 { 89 struct ocxl_afu *afu = to_ocxl_afu(kobj_to_dev(kobj)); 90 91 if ((vma_pages(vma) + vma->vm_pgoff) > 92 (afu->config.global_mmio_size >> PAGE_SHIFT)) 93 return -EINVAL; 94 95 vma->vm_flags |= VM_IO | VM_PFNMAP; 96 vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); 97 vma->vm_ops = &global_mmio_vmops; 98 vma->vm_private_data = afu; 99 return 0; 100 } 101 102 int ocxl_sysfs_add_afu(struct ocxl_afu *afu) 103 { 104 int i, rc; 105 106 for (i = 0; i < ARRAY_SIZE(afu_attrs); i++) { 107 rc = device_create_file(&afu->dev, &afu_attrs[i]); 108 if (rc) 109 goto err; 110 } 111 112 sysfs_attr_init(&afu->attr_global_mmio.attr); 113 afu->attr_global_mmio.attr.name = "global_mmio_area"; 114 afu->attr_global_mmio.attr.mode = 0600; 115 afu->attr_global_mmio.size = afu->config.global_mmio_size; 116 afu->attr_global_mmio.read = global_mmio_read; 117 afu->attr_global_mmio.mmap = global_mmio_mmap; 118 rc = device_create_bin_file(&afu->dev, &afu->attr_global_mmio); 119 if (rc) { 120 dev_err(&afu->dev, 121 "Unable to create global mmio attr for afu: %d\n", 122 rc); 123 goto err; 124 } 125 126 return 0; 127 128 err: 129 for (i--; i >= 0; i--) 130 device_remove_file(&afu->dev, &afu_attrs[i]); 131 return rc; 132 } 133 134 void ocxl_sysfs_remove_afu(struct ocxl_afu *afu) 135 { 136 int i; 137 138 for (i = 0; i < ARRAY_SIZE(afu_attrs); i++) 139 device_remove_file(&afu->dev, &afu_attrs[i]); 140 device_remove_bin_file(&afu->dev, &afu->attr_global_mmio); 141 } 142