On Tue, 5 Nov 2019 15:43:31 +0800 zhangfei <zhangfei.gao@xxxxxxxxxx> wrote: > Hi, Jonathan > > Thanks for the suggestions > > On 2019/11/1 上午1:13, Jonathan Cameron wrote: > > On Tue, 29 Oct 2019 14:40: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 > >> 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. > >> > >> Signed-off-by: Kenneth Lee <liguozhu@xxxxxxxxxxxxx> > >> Signed-off-by: Zaibo Xu <xuzaibo@xxxxxxxxxx> > >> Signed-off-by: Zhou Wang <wangzhou1@xxxxxxxxxxxxx> > >> Signed-off-by: Zhangfei Gao <zhangfei.gao@xxxxxxxxxx> > > Great, much more compact. > > > > I've not gone through this in detail yet but a few initial comments inline. > > > > Thanks, > > > > Jonathan > > > >> --- > >> Documentation/ABI/testing/sysfs-driver-uacce | 53 +++ > >> drivers/misc/Kconfig | 1 + > >> drivers/misc/Makefile | 1 + > >> drivers/misc/uacce/Kconfig | 13 + > >> drivers/misc/uacce/Makefile | 2 + > >> drivers/misc/uacce/uacce.c | 574 +++++++++++++++++++++++++++ > >> include/linux/uacce.h | 163 ++++++++ > >> include/uapi/misc/uacce/uacce.h | 38 ++ > >> 8 files changed, 845 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 > >> > >> diff --git a/Documentation/ABI/testing/sysfs-driver-uacce b/Documentation/ABI/testing/sysfs-driver-uacce > >> new file mode 100644 > >> index 0000000..35699dc > >> --- /dev/null > >> +++ b/Documentation/ABI/testing/sysfs-driver-uacce > >> @@ -0,0 +1,53 @@ > >> +What: /sys/class/uacce/<dev_name>/id > >> +Date: Oct 2019 > >> +KernelVersion: 5.5 > >> +Contact: linux-accelerators@xxxxxxxxxxxxxxxx > >> +Description: Id of the device. > >> + > >> +What: /sys/class/uacce/<dev_name>/api > >> +Date: Oct 2019 > >> +KernelVersion: 5.5 > >> +Contact: linux-accelerators@xxxxxxxxxxxxxxxx > >> +Description: Api of the device, used by application to match the correct driver > >> + > >> +What: /sys/class/uacce/<dev_name>/flags > >> +Date: Oct 2019 > >> +KernelVersion: 5.5 > >> +Contact: linux-accelerators@xxxxxxxxxxxxxxxx > >> +Description: Attributes of the device, see UACCE_DEV_xxx flag defined in uacce.h > >> + > >> +What: /sys/class/uacce/<dev_name>/available_instances > >> +Date: Oct 2019 > >> +KernelVersion: 5.5 > >> +Contact: linux-accelerators@xxxxxxxxxxxxxxxx > >> +Description: Available instances left of the device > >> + > >> +What: /sys/class/uacce/<dev_name>/algorithms > >> +Date: Oct 2019 > >> +KernelVersion: 5.5 > >> +Contact: linux-accelerators@xxxxxxxxxxxxxxxx > >> +Description: Algorithms supported by this accelerator > > How are they separated? Userspace code needs to know that. > > (comma, tab, newline?) > Yes, will add "separated by new line" > > > >> + > >> +What: /sys/class/uacce/<dev_name>/qfrt_mmio_size > > qfrt is not the most obvious naming ever. Do we care beyond its > > a region for this interface? region_mmio_size maybe? > OK, > > > >> +Date: Oct 2019 > >> +KernelVersion: 5.5 > >> +Contact: linux-accelerators@xxxxxxxxxxxxxxxx > >> +Description: Page size of mmio region queue file > > Size of page in this region, or number of pages in the region? > Change to "Page numbers of mmio region queue file" Number of pages used by queue in mmio region? > > > >> + > >> +What: /sys/class/uacce/<dev_name>/qfrt_dus_size > >> +Date: Oct 2019 > >> +KernelVersion: 5.5 > >> +Contact: linux-accelerators@xxxxxxxxxxxxxxxx > >> +Description: Page size of dus region queue file > >> + > >> +What: /sys/class/uacce/<dev_name>/numa_distance > >> +Date: Oct 2019 > >> +KernelVersion: 5.5 > >> +Contact: linux-accelerators@xxxxxxxxxxxxxxxx > >> +Description: Distance of device node to cpu node > > I wonder if we should be doing this in here. There are other standard > > ways of obtaining this for the device. Follow parent and check node_id > > there then use the /sys/bus/node path to find out the distances. > Could you clarify more about this method. > The purpose here is cpu searching the nearest device(zip) doing work. > Does user application know which node it is running and compare distance? Exactly. The parent device will typically be a pci device. The parent link will point somewhere like /sys/bus/pci/devices/000:00:10.0/ Under that directory is a numa_node file which will give you which node the device is assigned to. Using that number (N) read /sys/bus/node/devices/nodeN/distance Which should be the same as what you have from this interface. It also provides access to info on latency and bandwidth etc if HMAT is provided - so more info to make a decision than your new interface here provides. > >> + > >> +What: /sys/class/uacce/<dev_name>/node_id > >> +Date: Oct 2019 > >> +KernelVersion: 5.5 > >> +Contact: linux-accelerators@xxxxxxxxxxxxxxxx > >> +Description: Id of the numa node > >> diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig > >> index c55b637..929feb0 100644 > >> --- a/drivers/misc/Kconfig > >> +++ b/drivers/misc/Kconfig > >> @@ -481,4 +481,5 @@ source "drivers/misc/cxl/Kconfig" > >> source "drivers/misc/ocxl/Kconfig" > >> source "drivers/misc/cardreader/Kconfig" > >> source "drivers/misc/habanalabs/Kconfig" > >> +source "drivers/misc/uacce/Kconfig" > >> endmenu > >> diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile > >> index c1860d3..9abf292 100644 > >> --- a/drivers/misc/Makefile > >> +++ b/drivers/misc/Makefile > >> @@ -56,4 +56,5 @@ obj-$(CONFIG_OCXL) += ocxl/ > >> obj-y += cardreader/ > >> obj-$(CONFIG_PVPANIC) += pvpanic.o > >> obj-$(CONFIG_HABANA_AI) += habanalabs/ > >> +obj-$(CONFIG_UACCE) += uacce/ > >> obj-$(CONFIG_XILINX_SDFEC) += xilinx_sdfec.o > >> diff --git a/drivers/misc/uacce/Kconfig b/drivers/misc/uacce/Kconfig > >> new file mode 100644 > >> index 0000000..5e39b60 > >> --- /dev/null > >> +++ b/drivers/misc/uacce/Kconfig > >> @@ -0,0 +1,13 @@ > >> +config UACCE > >> + tristate "Accelerator Framework for User Land" > >> + depends on IOMMU_API > >> + help > >> + UACCE provides interface for the user process to access the hardware > >> + without interaction with the kernel space in data path. > >> + > >> + The user-space interface is described in > >> + include/uapi/misc/uacce/uacce.h > >> + > >> + See Documentation/misc-devices/uacce.rst for more details. > >> + > >> + If you don't know what to do here, say N. > > Pessimist :) Everyone should want uacce so don't put them off. Having said > > that perhaps for now it should be hidden and enabled on a driver by driver > > basis? > > > >> diff --git a/drivers/misc/uacce/Makefile b/drivers/misc/uacce/Makefile > >> new file mode 100644 > >> index 0000000..5b4374e > >> --- /dev/null > >> +++ b/drivers/misc/uacce/Makefile > >> @@ -0,0 +1,2 @@ > >> +# SPDX-License-Identifier: GPL-2.0-or-later > >> +obj-$(CONFIG_UACCE) += uacce.o > >> diff --git a/drivers/misc/uacce/uacce.c b/drivers/misc/uacce/uacce.c > >> new file mode 100644 > >> index 0000000..2b6b038 > >> --- /dev/null > >> +++ b/drivers/misc/uacce/uacce.c > >> @@ -0,0 +1,574 @@ > >> +// SPDX-License-Identifier: GPL-2.0-or-later > >> +#include <linux/compat.h> > >> +#include <linux/dma-iommu.h> > >> +#include <linux/module.h> > >> +#include <linux/poll.h> > >> +#include <linux/uacce.h> > >> + > >> +static struct class *uacce_class; > >> +static dev_t uacce_devt; > >> +static DEFINE_MUTEX(uacce_mutex); > >> +static DEFINE_XARRAY_ALLOC(uacce_xa); > >> + > >> +static int uacce_start_queue(struct uacce_queue *q) > >> +{ > >> + int ret = -EINVAL; > >> + > >> + mutex_lock(&uacce_mutex); > >> + > >> + if (q->state != UACCE_Q_INIT) > >> + goto out_with_lock; > >> + > >> + if (q->uacce->ops->start_queue) { > >> + ret = q->uacce->ops->start_queue(q); > >> + if (ret < 0) > >> + goto out_with_lock; > >> + } > >> + > >> + q->state = UACCE_Q_STARTED; > > out_with_lock: > >> + mutex_unlock(&uacce_mutex); > >> + > > return ret; > > Though need to handle ret a bit differently above... > OK > > > > +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 = 0; > > + unsigned int flags = 0; > > + int ret; > > + > > + if (vma->vm_pgoff < UACCE_QFRT_MAX) > > + type = vma->vm_pgoff; > > + > > + vma->vm_flags |= VM_DONTCOPY | VM_DONTEXPAND | VM_WIPEONFORK; > > + vma->vm_ops = &uacce_vm_ops; > > + vma->vm_private_data = q; > > + > > + mutex_lock(&uacce_mutex); > > + > > + if (q->qfrs[type]) { > > + ret = -EEXIST; > > + goto out_with_lock; > > + } > > + > > + switch (type) { > > + case UACCE_QFRT_MMIO: > > + flags = UACCE_QFRF_SELFMT; > > + break; > > + > > + case UACCE_QFRT_DUS: > > + if (uacce->flags & UACCE_DEV_SVA) { > > + flags = UACCE_QFRF_SELFMT; > > + break; > > + } > > + break; > > + > > + default: > > + WARN_ON(&uacce->dev); > > + break; > > + } > > + > > + qfr = uacce_create_region(q, vma, type, flags); > > + if (IS_ERR(qfr)) { > > + ret = PTR_ERR(qfr); > > + goto out_with_lock; > > + } > > + q->qfrs[type] = qfr; > > + > > Could put > > out_with_lock: > > here and return ret instead of 0. > > You'll need to set ret to default to 0 in that > > case though. > OK > > > > +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", uacce->algs); > > Any risk algs won't have the \n? > > I'd kind of expect it to be a null termated arrays to allow the core > > to format it however it wants to. > Yes, adding \n is better. This may then add a bonus new line if you have multiple lines already in the string. Probably doesn't do much harm, but it's not ideal. > > > >> +} > >> + > >> +static ssize_t qfrt_mmio_size_show(struct device *dev, > >> + struct device_attribute *attr, char *buf) > >> +{ > >> + struct uacce_device *uacce = to_uacce_device(dev); > >> + > >> + return sprintf(buf, "%lu\n", > >> + uacce->qf_pg_size[UACCE_QFRT_MMIO] << PAGE_SHIFT); > >> +} > >> + > >> +static ssize_t qfrt_dus_size_show(struct device *dev, > >> + struct device_attribute *attr, char *buf) > >> +{ > >> + struct uacce_device *uacce = to_uacce_device(dev); > >> + > >> + return sprintf(buf, "%lu\n", > >> + uacce->qf_pg_size[UACCE_QFRT_DUS] << PAGE_SHIFT); > >> +} > >> + > >> +static DEVICE_ATTR_RO(id); > >> +static DEVICE_ATTR_RO(api); > >> +static DEVICE_ATTR_RO(numa_distance); > >> +static DEVICE_ATTR_RO(node_id); > >> +static DEVICE_ATTR_RO(flags); > >> +static DEVICE_ATTR_RO(available_instances); > >> +static DEVICE_ATTR_RO(algorithms); > >> +static DEVICE_ATTR_RO(qfrt_mmio_size); > >> +static DEVICE_ATTR_RO(qfrt_dus_size); > >> + > >> +static struct attribute *uacce_dev_attrs[] = { > >> + &dev_attr_id.attr, > >> + &dev_attr_api.attr, > >> + &dev_attr_node_id.attr, > >> + &dev_attr_numa_distance.attr, > >> + &dev_attr_flags.attr, > >> + &dev_attr_available_instances.attr, > >> + &dev_attr_algorithms.attr, > >> + &dev_attr_qfrt_mmio_size.attr, > >> + &dev_attr_qfrt_dus_size.attr, > >> + NULL, > >> +}; > >> +ATTRIBUTE_GROUPS(uacce_dev); > >> + > >> +static void uacce_release(struct device *dev) > >> +{ > >> + struct uacce_device *uacce = to_uacce_device(dev); > >> + > >> + kfree(uacce); > >> +} > >> + > >> +/** > >> + * uacce_register - register an accelerator > > This isn't quite correct kernel-doc. Please run the > > generation script over it and fix any warnings. > > > > uacce_register() - register an accelerator > Sure, will add (), though no warning reported from ./scripts/kernel-doc I checked that one for another review yesterday. Seems the kernel suggested kernel-doc style isn't actually enforced and the brackets are optional for functions. It assumes anything it hasn't identified as something else must be a function hence this is the one case where careful matching doesn't apply (unlike struct, enum etc). > > > >> + * @parent: pointer of uacce parent device > >> + * @interface: pointer of uacce_interface for register > >> + */ > >> +struct uacce_device *uacce_register(struct device *parent, > >> + struct uacce_interface *interface) > >> +{ > >> + unsigned int flags = interface->flags; > >> + struct uacce_device *uacce; > >> + int ret; > >> + > >> + uacce = kzalloc(sizeof(struct uacce_device), GFP_KERNEL); > >> + if (!uacce) > >> + return ERR_PTR(-ENOMEM); > >> + > >> + if (flags & UACCE_DEV_SVA) { > >> + ret = iommu_dev_enable_feature(parent, IOMMU_DEV_FEAT_SVA); > >> + if (ret) > >> + flags &= ~UACCE_DEV_SVA; > >> + } > >> + > >> + uacce->pdev = parent; > >> + uacce->flags = flags; > >> + uacce->ops = interface->ops; > >> + > >> + ret = xa_alloc(&uacce_xa, &uacce->dev_id, uacce, xa_limit_32b, > >> + GFP_KERNEL); > >> + if (ret < 0) > >> + goto err_with_uacce; > >> + > >> + uacce->cdev = cdev_alloc(); > > If we can embed this (see below) then use cdev_init instead. > > > >> + if (!uacce->cdev) { > >> + ret = -ENOMEM; > >> + goto err_with_xa; > >> + } > >> + > >> + INIT_LIST_HEAD(&uacce->qs); > >> + mutex_init(&uacce->q_lock); > >> + uacce->cdev->ops = &uacce_fops; > >> + uacce->cdev->owner = THIS_MODULE; > >> + device_initialize(&uacce->dev); > >> + uacce->dev.devt = MKDEV(MAJOR(uacce_devt), uacce->dev_id); > >> + uacce->dev.class = uacce_class; > >> + uacce->dev.groups = uacce_dev_groups; > >> + uacce->dev.parent = uacce->pdev; > >> + uacce->dev.release = uacce_release; > >> + dev_set_name(&uacce->dev, "%s-%d", interface->name, uacce->dev_id); > >> + ret = cdev_device_add(uacce->cdev, &uacce->dev); > >> + if (ret) > >> + goto err_with_xa; > >> + > >> + return uacce; > >> + > >> +err_with_xa: > >> + if (uacce->cdev) > >> + cdev_del(uacce->cdev); > > Why not use a separate label to handle the above rather than checking if > > it's set? > ok, > > > >> + xa_erase(&uacce_xa, uacce->dev_id); > >> +err_with_uacce: > >> + if (flags & UACCE_DEV_SVA) > >> + iommu_dev_disable_feature(uacce->pdev, IOMMU_DEV_FEAT_SVA); > >> + kfree(uacce); > >> + return ERR_PTR(ret); > >> +} > >> +EXPORT_SYMBOL_GPL(uacce_register); > >> + > >> +/** > >> + * uacce_unregister - unregisters an accelerator > >> + * @uacce: the accelerator to unregister > >> + */ > >> +void uacce_unregister(struct uacce_device *uacce) > >> +{ > >> + if (!uacce) > >> + return; > >> + > > I'd like to see a comment here on why we are doing things not unwinding > > actions from uacce_register. > OK will add comments. > Here is "ensure no open queue remains" > >> + mutex_lock(&uacce->q_lock); > >> + if (!list_empty(&uacce->qs)) { > >> + struct uacce_queue *q; > >> + > >> + list_for_each_entry(q, &uacce->qs, list) { > >> + uacce_put_queue(q); > >> + if (uacce->flags & UACCE_DEV_SVA) > >> + iommu_sva_unbind_device(q->handle); > >> + } > >> + } > >> + mutex_unlock(&uacce->q_lock); > >> + > > For these next parts which are the unwind of uacce_register, why are they not > > in the reverse order of what is happening in there (where possible given > > device lifespan). That is why do we not disable the iommu feature much later? > First close all queues, then disable sva feature. > > > >> + if (uacce->flags & UACCE_DEV_SVA) > >> + iommu_dev_disable_feature(uacce->pdev, IOMMU_DEV_FEAT_SVA); > >> + > >> + cdev_device_del(uacce->cdev, &uacce->dev); > >> + xa_erase(&uacce_xa, uacce->dev_id); > >> + put_device(&uacce->dev); > >> +} > >> +EXPORT_SYMBOL_GPL(uacce_unregister); > >> + > >> +static int __init uacce_init(void) > >> +{ > >> + int ret; > >> + > >> + uacce_class = class_create(THIS_MODULE, UACCE_NAME); > >> + if (IS_ERR(uacce_class)) > >> + return PTR_ERR(uacce_class); > >> + > >> + ret = alloc_chrdev_region(&uacce_devt, 0, MINORMASK, UACCE_NAME); > >> + if (ret) { > >> + class_destroy(uacce_class); > >> + return ret; > > drop the return ret out of these brackets. i.e. > > > > if (ret) > > class_destroy(uacce_class) > > > > return ret; > sure, thanks > > > >> + } > >> + > >> + return 0; > >> +} > >> + > >> +static __exit void uacce_exit(void) > >> +{ > >> + unregister_chrdev_region(uacce_devt, MINORMASK); > >> + class_destroy(uacce_class); > >> +} > >> + > >> +subsys_initcall(uacce_init); > >> +module_exit(uacce_exit); > >> + > >> +MODULE_LICENSE("GPL"); > >> +MODULE_AUTHOR("Hisilicon Tech. Co., Ltd."); > >> +MODULE_DESCRIPTION("Accelerator interface for Userland applications"); > >> diff --git a/include/linux/uacce.h b/include/linux/uacce.h > >> new file mode 100644 > >> index 0000000..04c8643 > >> --- /dev/null > >> +++ b/include/linux/uacce.h > >> @@ -0,0 +1,163 @@ > >> +/* SPDX-License-Identifier: GPL-2.0-or-later */ > >> +#ifndef _LINUX_UACCE_H > >> +#define _LINUX_UACCE_H > >> + > >> +#include <linux/cdev.h> > >> +#include <uapi/misc/uacce/uacce.h> > >> + > >> +#define UACCE_NAME "uacce" > >> +#define UACCE_QFRT_MAX 16 > > What does QFRT stand for? > change to UACCE_MAX_REGION Much better > >> +#define UACCE_MAX_NAME_SIZE 64 > >> + > >> +struct uacce_queue; > >> +struct uacce_device; > >> + > >> +/** > >> + * enum uacce_qfr_flag: queue file flag: > >> + * @UACCE_QFRF_SELFMT: self maintained qfr > >> + */ > >> +enum uacce_qfr_flag { > >> + UACCE_QFRF_SELFMT = BIT(0), > >> +}; > > Same issue with enums for flags. Doesn't make much sense to me. > > Only one value can be taken which doesn't make it a flag. > > > >> + > >> +/** > >> + * struct uacce_qfile_region - structure of queue file region > >> + * @type: type of the qfr > >> + * @flags: flags of qfr > >> + * @prot: qfr protection flag > >> + */ > >> +struct uacce_qfile_region { > >> + enum uacce_qfrt type; > >> + enum uacce_qfr_flag flags; > >> + u32 prot; > >> +}; > >> + > >> +/** > >> + * struct uacce_ops - uacce device operations > >> + * @get_available_instances: get available instances left of the device > >> + * @get_queue: get a queue from the device > >> + * @put_queue: free a queue to the device > >> + * @start_queue: make the queue start work after get_queue > >> + * @stop_queue: make the queue stop work before put_queue > >> + * @is_q_updated: check whether the task is finished > >> + * @mask_notify: mask the task irq of queue > >> + * @mmap: mmap addresses of queue to user space > >> + * @reset: reset the uacce device > >> + * @reset_queue: reset the queue > >> + * @ioctl: ioctl for user space users of the queue > >> + */ > >> +struct uacce_ops { > >> + int (*get_available_instances)(struct uacce_device *uacce); > >> + int (*get_queue)(struct uacce_device *uacce, unsigned long arg, > >> + struct uacce_queue *q); > >> + void (*put_queue)(struct uacce_queue *q); > >> + int (*start_queue)(struct uacce_queue *q); > >> + void (*stop_queue)(struct uacce_queue *q); > >> + int (*is_q_updated)(struct uacce_queue *q); > >> + void (*mask_notify)(struct uacce_queue *q, int event_mask); > >> + int (*mmap)(struct uacce_queue *q, struct vm_area_struct *vma, > >> + struct uacce_qfile_region *qfr); > >> + int (*reset)(struct uacce_device *uacce); > >> + int (*reset_queue)(struct uacce_queue *q); > > Some of these aren't used on only existing driver. Introduce them only > > in the series that uses them. > OK > > > >> + long (*ioctl)(struct uacce_queue *q, unsigned int cmd, > >> + unsigned long arg); > >> +}; > >> + > >> +/** > >> + * struct uacce_interface > > I think this needs a description for kernel doc (even if it's obvious!) > > Could be wrong though. > OK > > > >> + * @name: the uacce device name. Will show up in sysfs > >> + * @flags: uacce device attributes > >> + * @ops: pointer to the struct uacce_ops > >> + * > >> + * This structure is used for the uacce_register() > >> + */ > >> +struct uacce_interface { > >> + char name[UACCE_MAX_NAME_SIZE]; > >> + enum uacce_dev_flag flags; > >> + struct uacce_ops *ops; > >> +}; > >> + > >> +enum uacce_q_state { > >> + UACCE_Q_INIT, > >> + UACCE_Q_STARTED, > >> + UACCE_Q_ZOMBIE, > >> +}; > >> + > >> +/** > >> + * struct uacce_queue > >> + * @uacce: pointer to uacce > >> + * @priv: private pointer > >> + * @wait: wait queue head > >> + * @pasid: pasid of the queue > >> + * @pid: pid of the process using the queue > >> + * @handle: iommu_sva handle return from iommu_sva_bind_device > >> + * @list: queue list > >> + * @qfrs: pointer of qfr regions > >> + * @state: queue state machine > >> + */ > >> +struct uacce_queue { > >> + struct uacce_device *uacce; > >> + void *priv; > >> + wait_queue_head_t wait; > >> + int pasid; > >> + pid_t pid; > >> + struct iommu_sva *handle; > >> + struct list_head list; > >> + struct uacce_qfile_region *qfrs[UACCE_QFRT_MAX]; > >> + enum uacce_q_state state; > >> +}; > >> + > >> +/** > >> + * struct uacce_device > >> + * @algs: supported algorithms > >> + * @api_ver: api version > >> + * @qf_pg_size: page size of the queue file regions > >> + * @ops: pointer to the struct uacce_ops > >> + * @pdev: pointer to the parent device > >> + * @is_vf: whether virtual function > >> + * @flags: uacce attributes > >> + * @dev_id: id of the uacce device > >> + * @prot: uacce protection flag > >> + * @cdev: cdev of the uacce > >> + * @dev: dev of the uacce > >> + * @priv: private pointer of the uacce > >> + * @qs: list head of queue->list > >> + * @q_lock: lock for qs > >> + */ > >> +struct uacce_device { > >> + const char *algs; > >> + const char *api_ver; > >> + unsigned long qf_pg_size[UACCE_QFRT_MAX]; > >> + struct uacce_ops *ops; > > Can we make this ops structure a point to a constant struct? > > I'm guessing it'll be fixed for a given driver. > OK > > > >> + struct device *pdev; > > Perhaps just call it parent. pdev will be confusing with > > pci devices. > OK > > > >> + bool is_vf; > >> + u32 flags; > >> + u32 dev_id; > >> + u32 prot; > >> + struct cdev *cdev; > > Can we embed the cdev structure rather than use a pointer > > and separate allocation? > NO, we can't. > We originally embed the cdev structure, and Greg reminded us these two > structure have different lifetime. > https://lkml.org/lkml/2019/8/28/771 Ok. Fair enough. > >> + struct device dev; > >> + void *priv; > >> + struct list_head qs; > >> + struct mutex q_lock; > >> +}; > >> + > >> +#if IS_ENABLED(CONFIG_UACCE) > >> + > >> +struct uacce_device *uacce_register(struct device *parent, > >> + struct uacce_interface *interface); > >> +void uacce_unregister(struct uacce_device *uacce); > >> + > >> +#else /* CONFIG_UACCE */ > >> + > >> +static inline > >> +struct uacce_device *uacce_register(struct device *parent, > >> + struct uacce_interface *interface) > >> +{ > >> + return ERR_PTR(-ENODEV); > >> +} > >> + > >> +static inline void uacce_unregister(struct uacce_device *uacce) {} > >> + > >> +#endif /* CONFIG_UACCE */ > >> + > >> +#endif /* _LINUX_UACCE_H */ > >> diff --git a/include/uapi/misc/uacce/uacce.h b/include/uapi/misc/uacce/uacce.h > >> new file mode 100644 > >> index 0000000..a4f9378 > >> --- /dev/null > >> +++ b/include/uapi/misc/uacce/uacce.h > >> @@ -0,0 +1,38 @@ > >> +/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */ > >> +#ifndef _UAPIUUACCE_H > >> +#define _UAPIUUACCE_H > >> + > >> +#include <linux/types.h> > >> +#include <linux/ioctl.h> > >> + > >> +/* UACCE_CMD_START_Q: Start the queue */ > >> +#define UACCE_CMD_START_Q _IO('W', 0) > >> + > >> +/** > >> + * UACCE_CMD_PUT_Q: > >> + * User actively stop queue and free queue resource immediately > >> + * Optimization method since close fd may delay > >> + */ > >> +#define UACCE_CMD_PUT_Q _IO('W', 1) > >> + > >> +/** > >> + * enum uacce_dev_flag: Device flags: > >> + * @UACCE_DEV_SVA: Shared Virtual Addresses > >> + * Support PASID > >> + * Support device page faults (PCI PRI or SMMU Stall) > >> + */ > >> +enum uacce_dev_flag { > >> + UACCE_DEV_SVA = BIT(0), > > As mentioned in docs review, this doesn't look like an enum to me. > > Just use #define for the bit and a suitable sized integer for any > > calls using it. > OK, but there are still more features in the future patch. That's not the issue. An enum should (more or less) use concurrent values. A = 0, B = 1, C = 2, etc and an instance of it should only take one of them. Once you are using it as values for a bitmap, the typing becomes irrelevant as you can't really use it to enforce anything, so you should just use. #define UACCE_DEV_SVA BIT(0) #define UACCE_DEV_SOMETHING BIT(1) etc > > Thanks >