On Mon, 16 Dec 2019 11:08:15 +0800 Zhangfei Gao <zhangfei.gao@xxxxxxxxxx> wrote: > From: Kenneth Lee <liguozhu@xxxxxxxxxxxxx> > > Uacce (Unified/User-space-access-intended Accelerator Framework) targets to > provide Shared Virtual Addressing (SVA) between accelerators and processes. > So accelerator can access any data structure of the main cpu. > This differs from the data sharing between cpu and io device, which share > only data content rather than address. > Since unified address, hardware and user space of process can share the > same virtual address in the communication. > > Uacce create a chrdev for every registration, the queue is allocated to > the process when the chrdev is opened. Then the process can access the > hardware resource by interact with the queue file. By mmap the queue > file space to user space, the process can directly put requests to the > hardware without syscall to the kernel space. > > The IOMMU core only tracks mm<->device bonds at the moment, because it > only needs to handle IOTLB invalidation and PASID table entries. However > uacce needs a finer granularity since multiple queues from the same > device can be bound to an mm. When the mm exits, all bound queues must > be stopped so that the IOMMU can safely clear the PASID table entry and > reallocate the PASID. > > An intermediate struct uacce_mm links uacce devices and queues. > Note that an mm may be bound to multiple devices but an uacce_mm > structure only ever belongs to a single device, because we don't need > anything more complex (if multiple devices are bound to one mm, then > we'll create one uacce_mm for each bond). > > uacce_device --+-- uacce_mm --+-- uacce_queue > | '-- uacce_queue > | > '-- uacce_mm --+-- uacce_queue > +-- uacce_queue > '-- uacce_queue > > Signed-off-by: Kenneth Lee <liguozhu@xxxxxxxxxxxxx> > Signed-off-by: Zaibo Xu <xuzaibo@xxxxxxxxxx> > Signed-off-by: Zhou Wang <wangzhou1@xxxxxxxxxxxxx> > Signed-off-by: Jean-Philippe Brucker <jean-philippe@xxxxxxxxxx> > Signed-off-by: Zhangfei Gao <zhangfei.gao@xxxxxxxxxx> Hi, Two small things I'd missed previously. Fix those and for what it's worth Reviewed-by: Jonathan Cameron <Jonathan.Cameron@xxxxxxxxxx> > --- > Documentation/ABI/testing/sysfs-driver-uacce | 37 ++ > drivers/misc/Kconfig | 1 + > drivers/misc/Makefile | 1 + > drivers/misc/uacce/Kconfig | 13 + > drivers/misc/uacce/Makefile | 2 + > drivers/misc/uacce/uacce.c | 628 +++++++++++++++++++++++++++ > include/linux/uacce.h | 161 +++++++ > include/uapi/misc/uacce/uacce.h | 38 ++ > 8 files changed, 881 insertions(+) > create mode 100644 Documentation/ABI/testing/sysfs-driver-uacce > create mode 100644 drivers/misc/uacce/Kconfig > create mode 100644 drivers/misc/uacce/Makefile > create mode 100644 drivers/misc/uacce/uacce.c > create mode 100644 include/linux/uacce.h > create mode 100644 include/uapi/misc/uacce/uacce.h > ... > + > +What: /sys/class/uacce/<dev_name>/available_instances > +Date: Dec 2019 > +KernelVersion: 5.6 > +Contact: linux-accelerators@xxxxxxxxxxxxxxxx > +Description: Available instances left of the device > + Return -ENODEV if uacce_ops get_available_instances is not provided > + See below. It doesn't "return" it prints it currently. ... > +static int uacce_fops_mmap(struct file *filep, struct vm_area_struct *vma) > +{ > + struct uacce_queue *q = filep->private_data; > + struct uacce_device *uacce = q->uacce; > + struct uacce_qfile_region *qfr; > + enum uacce_qfrt type = UACCE_MAX_REGION; > + int ret = 0; > + > + if (vma->vm_pgoff < UACCE_MAX_REGION) > + type = vma->vm_pgoff; > + else > + return -EINVAL; > + > + qfr = kzalloc(sizeof(*qfr), GFP_KERNEL); > + if (!qfr) > + return -ENOMEM; > + > + vma->vm_flags |= VM_DONTCOPY | VM_DONTEXPAND | VM_WIPEONFORK; > + vma->vm_ops = &uacce_vm_ops; > + vma->vm_private_data = q; > + qfr->type = type; > + > + mutex_lock(&uacce_mutex); > + > + if (q->state != UACCE_Q_INIT && q->state != UACCE_Q_STARTED) { > + ret = -EINVAL; > + goto out_with_lock; > + } > + > + if (q->qfrs[type]) { > + ret = -EEXIST; > + goto out_with_lock; > + } > + > + switch (type) { > + case UACCE_QFRT_MMIO: > + if (!uacce->ops->mmap) { > + ret = -EINVAL; > + goto out_with_lock; > + } > + > + ret = uacce->ops->mmap(q, vma, qfr); > + if (ret) > + goto out_with_lock; > + > + break; > + > + case UACCE_QFRT_DUS: > + if (uacce->flags & UACCE_DEV_SVA) { > + if (!uacce->ops->mmap) { > + ret = -EINVAL; > + goto out_with_lock; > + } > + > + ret = uacce->ops->mmap(q, vma, qfr); > + if (ret) > + goto out_with_lock; > + } Slightly odd corner case, but what stops us getting here with the UACCE_DEV_SVA flag not set? If that happened I'd expect to return an error but looks like we return 0. > + break; > + > + default: > + ret = -EINVAL; > + goto out_with_lock; > + } > + > + q->qfrs[type] = qfr; > + mutex_unlock(&uacce_mutex); > + > + return ret; > + > +out_with_lock: > + mutex_unlock(&uacce_mutex); > + kfree(qfr); > + return ret; > +} ... > +static ssize_t available_instances_show(struct device *dev, > + struct device_attribute *attr, > + char *buf) > +{ > + struct uacce_device *uacce = to_uacce_device(dev); > + int val = -ENODEV; > + > + if (uacce->ops->get_available_instances) > + val = uacce->ops->get_available_instances(uacce); > + > + return sprintf(buf, "%d\n", val); It's unusual to pass an error value back as a string. I'd expect some logic like.. if (val < 0) return val; return sprintf(buf, "%d\n", val); Note this is the documented behavior "returns -ENODEV". > +} > + > +static ssize_t algorithms_show(struct device *dev, > + struct device_attribute *attr, char *buf) > +{ > + struct uacce_device *uacce = to_uacce_device(dev); > + > + return sprintf(buf, "%s\n", uacce->algs); > +} > + ...