15ef3166eSFrederic Barrat // SPDX-License-Identifier: GPL-2.0+
25ef3166eSFrederic Barrat // Copyright 2017 IBM Corp.
35ef3166eSFrederic Barrat #include <linux/sysfs.h>
45ef3166eSFrederic Barrat #include "ocxl_internal.h"
55ef3166eSFrederic Barrat
to_afu(struct device * device)675ca758aSAlastair D'Silva static inline struct ocxl_afu *to_afu(struct device *device)
775ca758aSAlastair D'Silva {
875ca758aSAlastair D'Silva struct ocxl_file_info *info = container_of(device, struct ocxl_file_info, dev);
975ca758aSAlastair D'Silva
1075ca758aSAlastair D'Silva return info->afu;
1175ca758aSAlastair D'Silva }
1275ca758aSAlastair D'Silva
global_mmio_size_show(struct device * device,struct device_attribute * attr,char * buf)135ef3166eSFrederic Barrat static ssize_t global_mmio_size_show(struct device *device,
145ef3166eSFrederic Barrat struct device_attribute *attr,
155ef3166eSFrederic Barrat char *buf)
165ef3166eSFrederic Barrat {
1775ca758aSAlastair D'Silva struct ocxl_afu *afu = to_afu(device);
185ef3166eSFrederic Barrat
195ef3166eSFrederic Barrat return scnprintf(buf, PAGE_SIZE, "%d\n",
205ef3166eSFrederic Barrat afu->config.global_mmio_size);
215ef3166eSFrederic Barrat }
225ef3166eSFrederic Barrat
pp_mmio_size_show(struct device * device,struct device_attribute * attr,char * buf)235ef3166eSFrederic Barrat static ssize_t pp_mmio_size_show(struct device *device,
245ef3166eSFrederic Barrat struct device_attribute *attr,
255ef3166eSFrederic Barrat char *buf)
265ef3166eSFrederic Barrat {
2775ca758aSAlastair D'Silva struct ocxl_afu *afu = to_afu(device);
285ef3166eSFrederic Barrat
295ef3166eSFrederic Barrat return scnprintf(buf, PAGE_SIZE, "%d\n",
305ef3166eSFrederic Barrat afu->config.pp_mmio_stride);
315ef3166eSFrederic Barrat }
325ef3166eSFrederic Barrat
afu_version_show(struct device * device,struct device_attribute * attr,char * buf)335ef3166eSFrederic Barrat static ssize_t afu_version_show(struct device *device,
345ef3166eSFrederic Barrat struct device_attribute *attr,
355ef3166eSFrederic Barrat char *buf)
365ef3166eSFrederic Barrat {
3775ca758aSAlastair D'Silva struct ocxl_afu *afu = to_afu(device);
385ef3166eSFrederic Barrat
395ef3166eSFrederic Barrat return scnprintf(buf, PAGE_SIZE, "%hhu:%hhu\n",
405ef3166eSFrederic Barrat afu->config.version_major,
415ef3166eSFrederic Barrat afu->config.version_minor);
425ef3166eSFrederic Barrat }
435ef3166eSFrederic Barrat
contexts_show(struct device * device,struct device_attribute * attr,char * buf)445ef3166eSFrederic Barrat static ssize_t contexts_show(struct device *device,
455ef3166eSFrederic Barrat struct device_attribute *attr,
465ef3166eSFrederic Barrat char *buf)
475ef3166eSFrederic Barrat {
4875ca758aSAlastair D'Silva struct ocxl_afu *afu = to_afu(device);
495ef3166eSFrederic Barrat
505ef3166eSFrederic Barrat return scnprintf(buf, PAGE_SIZE, "%d/%d\n",
515ef3166eSFrederic Barrat afu->pasid_count, afu->pasid_max);
525ef3166eSFrederic Barrat }
535ef3166eSFrederic Barrat
reload_on_reset_show(struct device * device,struct device_attribute * attr,char * buf)5487db7579SPhilippe Bergheaud static ssize_t reload_on_reset_show(struct device *device,
5587db7579SPhilippe Bergheaud struct device_attribute *attr,
5687db7579SPhilippe Bergheaud char *buf)
5787db7579SPhilippe Bergheaud {
5887db7579SPhilippe Bergheaud struct ocxl_afu *afu = to_afu(device);
5987db7579SPhilippe Bergheaud struct ocxl_fn *fn = afu->fn;
6087db7579SPhilippe Bergheaud struct pci_dev *pci_dev = to_pci_dev(fn->dev.parent);
6187db7579SPhilippe Bergheaud int val;
6287db7579SPhilippe Bergheaud
6387db7579SPhilippe Bergheaud if (ocxl_config_get_reset_reload(pci_dev, &val))
6487db7579SPhilippe Bergheaud return scnprintf(buf, PAGE_SIZE, "unavailable\n");
6587db7579SPhilippe Bergheaud
6687db7579SPhilippe Bergheaud return scnprintf(buf, PAGE_SIZE, "%d\n", val);
6787db7579SPhilippe Bergheaud }
6887db7579SPhilippe Bergheaud
reload_on_reset_store(struct device * device,struct device_attribute * attr,const char * buf,size_t count)6987db7579SPhilippe Bergheaud static ssize_t reload_on_reset_store(struct device *device,
7087db7579SPhilippe Bergheaud struct device_attribute *attr,
7187db7579SPhilippe Bergheaud const char *buf, size_t count)
7287db7579SPhilippe Bergheaud {
7387db7579SPhilippe Bergheaud struct ocxl_afu *afu = to_afu(device);
7487db7579SPhilippe Bergheaud struct ocxl_fn *fn = afu->fn;
7587db7579SPhilippe Bergheaud struct pci_dev *pci_dev = to_pci_dev(fn->dev.parent);
7687db7579SPhilippe Bergheaud int rc, val;
7787db7579SPhilippe Bergheaud
7887db7579SPhilippe Bergheaud rc = kstrtoint(buf, 0, &val);
7987db7579SPhilippe Bergheaud if (rc || (val != 0 && val != 1))
8087db7579SPhilippe Bergheaud return -EINVAL;
8187db7579SPhilippe Bergheaud
8287db7579SPhilippe Bergheaud if (ocxl_config_set_reset_reload(pci_dev, val))
8387db7579SPhilippe Bergheaud return -ENODEV;
8487db7579SPhilippe Bergheaud
8587db7579SPhilippe Bergheaud return count;
8687db7579SPhilippe Bergheaud }
8787db7579SPhilippe Bergheaud
885ef3166eSFrederic Barrat static struct device_attribute afu_attrs[] = {
895ef3166eSFrederic Barrat __ATTR_RO(global_mmio_size),
905ef3166eSFrederic Barrat __ATTR_RO(pp_mmio_size),
915ef3166eSFrederic Barrat __ATTR_RO(afu_version),
925ef3166eSFrederic Barrat __ATTR_RO(contexts),
9387db7579SPhilippe Bergheaud __ATTR_RW(reload_on_reset),
945ef3166eSFrederic Barrat };
955ef3166eSFrederic Barrat
global_mmio_read(struct file * filp,struct kobject * kobj,struct bin_attribute * bin_attr,char * buf,loff_t off,size_t count)965ef3166eSFrederic Barrat static ssize_t global_mmio_read(struct file *filp, struct kobject *kobj,
975ef3166eSFrederic Barrat struct bin_attribute *bin_attr, char *buf,
985ef3166eSFrederic Barrat loff_t off, size_t count)
995ef3166eSFrederic Barrat {
10075ca758aSAlastair D'Silva struct ocxl_afu *afu = to_afu(kobj_to_dev(kobj));
1015ef3166eSFrederic Barrat
1025ef3166eSFrederic Barrat if (count == 0 || off < 0 ||
1035ef3166eSFrederic Barrat off >= afu->config.global_mmio_size)
1045ef3166eSFrederic Barrat return 0;
1055ef3166eSFrederic Barrat memcpy_fromio(buf, afu->global_mmio_ptr + off, count);
1065ef3166eSFrederic Barrat return count;
1075ef3166eSFrederic Barrat }
1085ef3166eSFrederic Barrat
global_mmio_fault(struct vm_fault * vmf)109a545cf03SSouptick Joarder static vm_fault_t global_mmio_fault(struct vm_fault *vmf)
1105ef3166eSFrederic Barrat {
1115ef3166eSFrederic Barrat struct vm_area_struct *vma = vmf->vma;
1125ef3166eSFrederic Barrat struct ocxl_afu *afu = vma->vm_private_data;
1135ef3166eSFrederic Barrat unsigned long offset;
1145ef3166eSFrederic Barrat
1155ef3166eSFrederic Barrat if (vmf->pgoff >= (afu->config.global_mmio_size >> PAGE_SHIFT))
1165ef3166eSFrederic Barrat return VM_FAULT_SIGBUS;
1175ef3166eSFrederic Barrat
1185ef3166eSFrederic Barrat offset = vmf->pgoff;
1195ef3166eSFrederic Barrat offset += (afu->global_mmio_start >> PAGE_SHIFT);
120a545cf03SSouptick Joarder return vmf_insert_pfn(vma, vmf->address, offset);
1215ef3166eSFrederic Barrat }
1225ef3166eSFrederic Barrat
1235ef3166eSFrederic Barrat static const struct vm_operations_struct global_mmio_vmops = {
1245ef3166eSFrederic Barrat .fault = global_mmio_fault,
1255ef3166eSFrederic Barrat };
1265ef3166eSFrederic Barrat
global_mmio_mmap(struct file * filp,struct kobject * kobj,struct bin_attribute * bin_attr,struct vm_area_struct * vma)1275ef3166eSFrederic Barrat static int global_mmio_mmap(struct file *filp, struct kobject *kobj,
1285ef3166eSFrederic Barrat struct bin_attribute *bin_attr,
1295ef3166eSFrederic Barrat struct vm_area_struct *vma)
1305ef3166eSFrederic Barrat {
13175ca758aSAlastair D'Silva struct ocxl_afu *afu = to_afu(kobj_to_dev(kobj));
1325ef3166eSFrederic Barrat
1335ef3166eSFrederic Barrat if ((vma_pages(vma) + vma->vm_pgoff) >
1345ef3166eSFrederic Barrat (afu->config.global_mmio_size >> PAGE_SHIFT))
1355ef3166eSFrederic Barrat return -EINVAL;
1365ef3166eSFrederic Barrat
137*1c71222eSSuren Baghdasaryan vm_flags_set(vma, VM_IO | VM_PFNMAP);
1385ef3166eSFrederic Barrat vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
1395ef3166eSFrederic Barrat vma->vm_ops = &global_mmio_vmops;
1405ef3166eSFrederic Barrat vma->vm_private_data = afu;
1415ef3166eSFrederic Barrat return 0;
1425ef3166eSFrederic Barrat }
1435ef3166eSFrederic Barrat
ocxl_sysfs_register_afu(struct ocxl_file_info * info)14475ca758aSAlastair D'Silva int ocxl_sysfs_register_afu(struct ocxl_file_info *info)
1455ef3166eSFrederic Barrat {
1465ef3166eSFrederic Barrat int i, rc;
1475ef3166eSFrederic Barrat
1485ef3166eSFrederic Barrat for (i = 0; i < ARRAY_SIZE(afu_attrs); i++) {
14975ca758aSAlastair D'Silva rc = device_create_file(&info->dev, &afu_attrs[i]);
1505ef3166eSFrederic Barrat if (rc)
1515ef3166eSFrederic Barrat goto err;
1525ef3166eSFrederic Barrat }
1535ef3166eSFrederic Barrat
15475ca758aSAlastair D'Silva sysfs_attr_init(&info->attr_global_mmio.attr);
15575ca758aSAlastair D'Silva info->attr_global_mmio.attr.name = "global_mmio_area";
15675ca758aSAlastair D'Silva info->attr_global_mmio.attr.mode = 0600;
15775ca758aSAlastair D'Silva info->attr_global_mmio.size = info->afu->config.global_mmio_size;
15875ca758aSAlastair D'Silva info->attr_global_mmio.read = global_mmio_read;
15975ca758aSAlastair D'Silva info->attr_global_mmio.mmap = global_mmio_mmap;
16075ca758aSAlastair D'Silva rc = device_create_bin_file(&info->dev, &info->attr_global_mmio);
1615ef3166eSFrederic Barrat if (rc) {
16275ca758aSAlastair D'Silva dev_err(&info->dev, "Unable to create global mmio attr for afu: %d\n", rc);
1635ef3166eSFrederic Barrat goto err;
1645ef3166eSFrederic Barrat }
1655ef3166eSFrederic Barrat
1665ef3166eSFrederic Barrat return 0;
1675ef3166eSFrederic Barrat
1685ef3166eSFrederic Barrat err:
1695ef3166eSFrederic Barrat for (i--; i >= 0; i--)
17075ca758aSAlastair D'Silva device_remove_file(&info->dev, &afu_attrs[i]);
17175ca758aSAlastair D'Silva
1725ef3166eSFrederic Barrat return rc;
1735ef3166eSFrederic Barrat }
1745ef3166eSFrederic Barrat
ocxl_sysfs_unregister_afu(struct ocxl_file_info * info)17575ca758aSAlastair D'Silva void ocxl_sysfs_unregister_afu(struct ocxl_file_info *info)
1765ef3166eSFrederic Barrat {
1775ef3166eSFrederic Barrat int i;
1785ef3166eSFrederic Barrat
17975ca758aSAlastair D'Silva /*
18075ca758aSAlastair D'Silva * device_remove_bin_file is safe to call if the file is not added as
18175ca758aSAlastair D'Silva * the files are removed by name, and early exit if not found
18275ca758aSAlastair D'Silva */
1835ef3166eSFrederic Barrat for (i = 0; i < ARRAY_SIZE(afu_attrs); i++)
18475ca758aSAlastair D'Silva device_remove_file(&info->dev, &afu_attrs[i]);
18575ca758aSAlastair D'Silva device_remove_bin_file(&info->dev, &info->attr_global_mmio);
1865ef3166eSFrederic Barrat }
187