linux/drivers/misc/ocxl/sysfs.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2// Copyright 2017 IBM Corp.
   3#include <linux/sysfs.h>
   4#include "ocxl_internal.h"
   5
   6static 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
  16static 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
  26static 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
  37static 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
  47static 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
  54static 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
  67static 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
  82static const struct vm_operations_struct global_mmio_vmops = {
  83        .fault = global_mmio_fault,
  84};
  85
  86static 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
 103int 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
 129err:
 130        for (i--; i >= 0; i--)
 131                device_remove_file(&afu->dev, &afu_attrs[i]);
 132        return rc;
 133}
 134
 135void 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