Re: [PATCH v2 06/15] misc: nnpi: Allow usermode to manage host resources

From: Dave Airlie
Date: Mon May 17 2021 - 03:02:53 EST


On Thu, 13 May 2021 at 19:55, Guy Zadicario <guy.zadicario@xxxxxxxxx> wrote:
>
> Provide an IOCTL interface for creating and destroying host memory
> resources through a character device (/dev/nnpi_host).
>
> There is a single instance of this character device in the system
> regardless of the number of NNP-I devices attached because it
> controls host resources which may be shared between different devices.
>
> A nnp_user object, created when an application opens this character
> device, identifies the user (client) of the driver and holds a list of
> all host resources allocated by that user through the opened file
> descriptor.
>
> Host memory resources created through this character device can be mapped
> to device access through IOCTLs made to a different, per-device, chardev
> (will be introduced on next commits).
>
> All resources will be destroyed when the application closes the connection
> or exits.
>
> The IOCTL interface is defined in: include/uapi/misc/intel_nnpi.h
>
> Signed-off-by: Guy Zadicario <guy.zadicario@xxxxxxxxx>
> Reviewed-by: Alexander Shishkin <alexander.shishkin@xxxxxxxxxxxxxxx>
> ---
> MAINTAINERS | 1 +
> drivers/misc/intel-nnpi/Makefile | 2 +-
> drivers/misc/intel-nnpi/device.c | 14 ++
> drivers/misc/intel-nnpi/host_chardev.c | 346 +++++++++++++++++++++++++++++++++
> drivers/misc/intel-nnpi/host_chardev.h | 12 ++
> drivers/misc/intel-nnpi/nnp_user.c | 131 +++++++++++++
> drivers/misc/intel-nnpi/nnp_user.h | 79 ++++++++
> include/uapi/misc/intel_nnpi.h | 150 ++++++++++++++
> 8 files changed, 734 insertions(+), 1 deletion(-)
> create mode 100644 drivers/misc/intel-nnpi/host_chardev.c
> create mode 100644 drivers/misc/intel-nnpi/host_chardev.h
> create mode 100644 drivers/misc/intel-nnpi/nnp_user.c
> create mode 100644 drivers/misc/intel-nnpi/nnp_user.h
> create mode 100644 include/uapi/misc/intel_nnpi.h
>
> diff --git a/MAINTAINERS b/MAINTAINERS
> index ff0c3d7..42f3e54 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -9320,6 +9320,7 @@ INTEL NNP-I PCI DRIVER
> M: Guy Zadicario <guy.zadicario@xxxxxxxxx>
> S: Supported
> F: drivers/misc/intel-nnpi/
> +F: include/uapi/misc/intel_nnpi.h
>
> INTEL P-Unit IPC DRIVER
> M: Zha Qipeng <qipeng.zha@xxxxxxxxx>
> diff --git a/drivers/misc/intel-nnpi/Makefile b/drivers/misc/intel-nnpi/Makefile
> index 3713d51..da2863b 100644
> --- a/drivers/misc/intel-nnpi/Makefile
> +++ b/drivers/misc/intel-nnpi/Makefile
> @@ -5,7 +5,7 @@
>
> obj-$(CONFIG_INTEL_NNPI) := intel_nnpi.o intel_nnpi_pcie.o
>
> -intel_nnpi-y := device.o msg_scheduler.o hostres.o
> +intel_nnpi-y := device.o msg_scheduler.o hostres.o host_chardev.o nnp_user.o
>
> intel_nnpi_pcie-y := nnp_pcie.o
>
> diff --git a/drivers/misc/intel-nnpi/device.c b/drivers/misc/intel-nnpi/device.c
> index 60c5a94..0f98398 100644
> --- a/drivers/misc/intel-nnpi/device.c
> +++ b/drivers/misc/intel-nnpi/device.c
> @@ -8,6 +8,7 @@
> #include <linux/module.h>
>
> #include "device.h"
> +#include "host_chardev.h"
> #include "msg_scheduler.h"
>
> static DEFINE_IDA(dev_ida);
> @@ -99,6 +100,19 @@ void nnpdev_destroy(struct nnp_device *nnpdev)
> }
> EXPORT_SYMBOL(nnpdev_destroy);
>
> +static int __init nnp_init(void)
> +{
> + return nnp_init_host_interface();
> +}
> +subsys_initcall(nnp_init);
> +
> +static void __exit nnp_cleanup(void)
> +{
> + nnp_release_host_interface();
> + /* dev_ida is already empty here - no point calling ida_destroy */
> +}
> +module_exit(nnp_cleanup);
> +
> MODULE_LICENSE("GPL");
> MODULE_DESCRIPTION("Intel(R) NNPI Framework");
> MODULE_AUTHOR("Intel Corporation");
> diff --git a/drivers/misc/intel-nnpi/host_chardev.c b/drivers/misc/intel-nnpi/host_chardev.c
> new file mode 100644
> index 0000000..6048fda
> --- /dev/null
> +++ b/drivers/misc/intel-nnpi/host_chardev.c
> @@ -0,0 +1,346 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/* Copyright (C) 2019-2021 Intel Corporation */
> +
> +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
> +
> +#include <linux/cdev.h>
> +#include <linux/device.h>
> +#include <linux/file.h>
> +#include <linux/fs.h>
> +#include <linux/hashtable.h>
> +#include <linux/idr.h>
> +#include <linux/printk.h>
> +#include <linux/slab.h>
> +#include <uapi/misc/intel_nnpi.h>
> +
> +#include "device.h"
> +#include "host_chardev.h"
> +#include "ipc_protocol.h"
> +#include "nnp_user.h"
> +
> +static struct cdev cdev;
> +static dev_t devnum;
> +static struct class *class;
> +static struct device *dev;
> +
> +static inline int is_host_file(struct file *f);
> +
> +static enum dma_data_direction to_dma_dir(unsigned int nnp_dir)
> +{
> + /* Ignore IOCTL_INF_RES_NETWORK */
> + switch (nnp_dir & (IOCTL_INF_RES_INPUT | IOCTL_INF_RES_OUTPUT)) {
> + case (IOCTL_INF_RES_INPUT | IOCTL_INF_RES_OUTPUT):
> + return DMA_BIDIRECTIONAL;
> + case IOCTL_INF_RES_INPUT:
> + return DMA_TO_DEVICE;
> + case IOCTL_INF_RES_OUTPUT:
> + return DMA_FROM_DEVICE;
> + default:
> + break;
> + }
> +
> + return DMA_NONE;
> +}
> +
> +static long create_hostres(struct nnp_user_info *user_info, void __user *arg,
> + unsigned int size)
> +{
> + int ret;
> + struct nnpdrv_ioctl_create_hostres req;
> + struct host_resource *hostres;
> + struct user_hostres *user_hostres_entry;
> + void __user *uptr;
> + unsigned int io_size = sizeof(req);
> +
> + if (size != io_size)
> + return -EINVAL;
> +
> + if (copy_from_user(&req, arg, io_size))
> + return -EFAULT;
> +
> + if (req.usage_flags & ~IOCTL_RES_USAGE_VALID_MASK)
> + return -EINVAL;
> +
> + uptr = u64_to_user_ptr(req.user_ptr);
> + hostres = nnp_hostres_from_usermem(uptr, req.size,
> + to_dma_dir(req.usage_flags));
> +
> + if (IS_ERR(hostres))
> + return PTR_ERR(hostres);
> +
> + ret = nnp_user_add_hostres(user_info, hostres, &user_hostres_entry);
> + if (ret < 0) {
> + nnp_hostres_put(hostres);
> + return ret;
> + }
> +
> + req.size = nnp_hostres_size(hostres);
> +
> + /*
> + * The created user_hostres_entry holds refcount to the resource,
> + * no need to keep another one here.
> + */
> + nnp_hostres_put(hostres);
> +
> + req.user_handle = user_hostres_entry->user_handle;
> + if (copy_to_user(arg, &req, io_size)) {
> + ret = -EFAULT;
> + goto destroy_hostres_entry;
> + }
> +
> + return 0;
> +
> +destroy_hostres_entry:
> + nnp_user_remove_hostres(user_hostres_entry);
> +
> + return ret;
> +}
> +
> +static long destroy_hostres(struct nnp_user_info *user_info, void __user *arg,
> + unsigned int size)
> +{
> + struct nnpdrv_ioctl_destroy_hostres destroy_args;
> + struct user_hostres *user_hostres_entry;
> + unsigned int io_size = sizeof(destroy_args);
> + int ret = 0;
> +
> + if (size != io_size)
> + return -EINVAL;
> +
> + if (copy_from_user(&destroy_args, arg, io_size))
> + return -EFAULT;
> +
> + /* errno must be cleared on entry */
> + if (destroy_args.o_errno)
> + return -EINVAL;
> +
> + mutex_lock(&user_info->mutex);
> + user_hostres_entry = idr_find(&user_info->idr, destroy_args.user_handle);
> + if (user_hostres_entry) {
> + nnp_user_remove_hostres_locked(user_hostres_entry);
> + } else {
> + destroy_args.o_errno = NNPER_NO_SUCH_RESOURCE;
> + if (copy_to_user(arg, &destroy_args, io_size))
> + ret = -EFAULT;
> + }
> +
> + mutex_unlock(&user_info->mutex);
> + return ret;
> +}
> +
> +static long lock_hostres(struct nnp_user_info *user_info, void __user *arg,
> + unsigned int size)
> +{
> + int ret = 0;
> + struct nnpdrv_ioctl_lock_hostres lock_args;
> + struct user_hostres *user_hostres_entry;
> + unsigned int io_size = sizeof(lock_args);
> +
> + if (size != io_size)
> + return -EINVAL;
> +
> + if (copy_from_user(&lock_args, arg, io_size))
> + return -EFAULT;
> +
> + /* errno must be cleared on entry */
> + if (lock_args.o_errno)
> + return -EINVAL;
> +
> + mutex_lock(&user_info->mutex);
> + user_hostres_entry = idr_find(&user_info->idr, lock_args.user_handle);
> + if (user_hostres_entry) {
> + ret = nnp_hostres_user_lock(user_hostres_entry->hostres);
> + } else {
> + lock_args.o_errno = NNPER_NO_SUCH_RESOURCE;
> + if (copy_to_user(arg, &lock_args, io_size))
> + ret = -EFAULT;
> + }
> +
> + mutex_unlock(&user_info->mutex);
> + return ret;
> +}
> +
> +static long unlock_hostres(struct nnp_user_info *user_info, void __user *arg,
> + unsigned int size)
> +{
> + int ret = 0;
> + struct user_hostres *user_hostres_entry;
> + struct nnpdrv_ioctl_lock_hostres lock_args;
> + unsigned int io_size = sizeof(lock_args);
> +
> + if (size != io_size)
> + return -EINVAL;
> +
> + if (copy_from_user(&lock_args, arg, io_size))
> + return -EFAULT;
> +
> + /* errno must be cleared on entry */
> + if (lock_args.o_errno)
> + return -EINVAL;
> +
> + mutex_lock(&user_info->mutex);
> + user_hostres_entry = idr_find(&user_info->idr, lock_args.user_handle);
> + if (user_hostres_entry) {
> + ret = nnp_hostres_user_unlock(user_hostres_entry->hostres);
> + } else {
> + lock_args.o_errno = NNPER_NO_SUCH_RESOURCE;
> + if (copy_to_user(arg, &lock_args, sizeof(lock_args)))
> + ret = -EFAULT;
> + }
> +
> + mutex_unlock(&user_info->mutex);
> + return ret;
> +}
> +
> +struct file *nnp_host_file_get(int host_fd)
> +{
> + struct file *host_file;
> +
> + host_file = fget(host_fd);
> + if (is_host_file(host_file))
> + return host_file;
> +
> + if (host_file)
> + fput(host_file);
> +
> + return NULL;
> +}
> +
> +/*
> + * Inference host cdev (/dev/nnpi_host) file operation functions
> + */
> +
> +static int host_open(struct inode *inode, struct file *f)
> +{
> + struct nnp_user_info *user_info;
> +
> + if (!is_host_file(f))
> + return -EINVAL;
> +
> + user_info = kzalloc(sizeof(*user_info), GFP_KERNEL);
> + if (!user_info)
> + return -ENOMEM;
> +
> + nnp_user_init(user_info);
> +
> + f->private_data = user_info;
> +
> + return 0;
> +}
> +
> +static int host_release(struct inode *inode, struct file *f)
> +{
> + struct nnp_user_info *user_info;
> +
> + if (!is_host_file(f))
> + return -EINVAL;
> +
> + user_info = f->private_data;
> +
> + nnp_user_destroy_all(user_info);
> + f->private_data = NULL;
> +
> + return 0;
> +}
> +
> +static long host_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
> +{
> + long ret = 0;
> + struct nnp_user_info *user_info = f->private_data;
> + unsigned int ioc_nr, size;
> +
> + if (!is_host_file(f))
> + return -ENOTTY;
> +
> + if (_IOC_TYPE(cmd) != 'h')
> + return -EINVAL;
> +
> + ioc_nr = _IOC_NR(cmd);
> + size = _IOC_SIZE(cmd);
> +
> + switch (ioc_nr) {
> + case _IOC_NR(IOCTL_INF_CREATE_HOST_RESOURCE):
> + ret = create_hostres(user_info, (void __user *)arg, size);
> + break;
> + case _IOC_NR(IOCTL_INF_DESTROY_HOST_RESOURCE):
> + ret = destroy_hostres(user_info, (void __user *)arg, size);
> + break;
> + case _IOC_NR(IOCTL_INF_UNLOCK_HOST_RESOURCE):
> + ret = unlock_hostres(user_info, (void __user *)arg, size);
> + break;
> + case _IOC_NR(IOCTL_INF_LOCK_HOST_RESOURCE):
> + ret = lock_hostres(user_info, (void __user *)arg, size);
> + break;
> + default:
> + ret = -EINVAL;
> + }
> +
> + return ret;
> +}
> +
> +static const struct file_operations host_fops = {
> + .owner = THIS_MODULE,
> + .open = host_open,
> + .release = host_release,
> + .unlocked_ioctl = host_ioctl,
> + .compat_ioctl = host_ioctl,
> +};
> +
> +static inline int is_host_file(struct file *f)
> +{
> + return f && f->f_op == &host_fops;
> +}
> +
> +int nnp_init_host_interface(void)
> +{
> + int ret;
> +
> + ret = alloc_chrdev_region(&devnum, 0, 1, NNPDRV_INF_HOST_DEV_NAME);
> + if (ret < 0)
> + return ret;
> +
> + cdev_init(&cdev, &host_fops);
> + cdev.owner = THIS_MODULE;
> +
> + ret = cdev_add(&cdev, devnum, 1);
> + if (ret < 0)
> + goto err_region;
> +
> + class = class_create(THIS_MODULE, NNPDRV_INF_HOST_DEV_NAME);
> + if (IS_ERR(class)) {
> + ret = PTR_ERR(class);
> + goto err_cdev;
> + }
> +
> + dev = device_create(class, NULL, devnum, NULL, NNPDRV_INF_HOST_DEV_NAME);
> + if (IS_ERR(dev)) {
> + ret = PTR_ERR(dev);
> + goto err_class;
> + }
> +
> + ret = nnp_hostres_init_sysfs(dev);
> + if (ret < 0)
> + goto err_device;
> +
> + return 0;
> +
> +err_device:
> + device_destroy(class, devnum);
> +err_class:
> + class_destroy(class);
> +err_cdev:
> + cdev_del(&cdev);
> +err_region:
> + unregister_chrdev_region(devnum, 1);
> +
> + return ret;
> +}
> +
> +void nnp_release_host_interface(void)
> +{
> + nnp_hostres_fini_sysfs(dev);
> + device_destroy(class, devnum);
> + class_destroy(class);
> + cdev_del(&cdev);
> + unregister_chrdev_region(devnum, 1);
> +}
> diff --git a/drivers/misc/intel-nnpi/host_chardev.h b/drivers/misc/intel-nnpi/host_chardev.h
> new file mode 100644
> index 0000000..5812e0f
> --- /dev/null
> +++ b/drivers/misc/intel-nnpi/host_chardev.h
> @@ -0,0 +1,12 @@
> +/* SPDX-License-Identifier: GPL-2.0-only */
> +/* Copyright (C) 2019-2021 Intel Corporation */
> +
> +#ifndef _NNPDRV_INFERENCE_H
> +#define _NNPDRV_INFERENCE_H
> +
> +int nnp_init_host_interface(void);
> +void nnp_release_host_interface(void);
> +
> +struct file *nnp_host_file_get(int host_fd);
> +
> +#endif
> diff --git a/drivers/misc/intel-nnpi/nnp_user.c b/drivers/misc/intel-nnpi/nnp_user.c
> new file mode 100644
> index 0000000..51d7418
> --- /dev/null
> +++ b/drivers/misc/intel-nnpi/nnp_user.c
> @@ -0,0 +1,131 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/* Copyright (C) 2019-2021 Intel Corporation */
> +
> +#include <linux/slab.h>
> +
> +#include "nnp_user.h"
> +
> +void nnp_user_init(struct nnp_user_info *user_info)
> +{
> + INIT_LIST_HEAD(&user_info->hostres_list);
> + mutex_init(&user_info->mutex);
> + kref_init(&user_info->ref);
> + idr_init(&user_info->idr);
> +}
> +
> +void nnp_user_get(struct nnp_user_info *user_info)
> +{
> + kref_get(&user_info->ref);
> +}
> +
> +static void nnp_user_release(struct kref *kref)
> +{
> + struct nnp_user_info *user_info =
> + container_of(kref, struct nnp_user_info, ref);
> + struct completion *completion = user_info->close_completion;
> +
> + idr_destroy(&user_info->idr);
> + kfree(user_info);
> + complete(completion);
> +}
> +
> +void nnp_user_put(struct nnp_user_info *user_info)
> +{
> + kref_put(&user_info->ref, nnp_user_release);
> +}
> +
> +int nnp_user_add_hostres(struct nnp_user_info *user_info,
> + struct host_resource *hostres,
> + struct user_hostres **user_hostres_entry)
> +{
> + struct user_hostres *hr_entry;
> + int id;
> +
> + hr_entry = kmalloc(sizeof(*hr_entry), GFP_KERNEL);
> + if (!hr_entry)
> + return -ENOMEM;
> +
> + /*
> + * Increment refcount to hostres for the entry reference.
> + * (caller holds reference to it, so we know it exist).
> + */
> + nnp_hostres_get(hostres);
> + hr_entry->hostres = hostres;
> +
> + /*
> + * We are called from ioctl of file that own this user_info,
> + * So it safe to assume it exist.
> + */
> + nnp_user_get(user_info);
> + hr_entry->user_info = user_info;
> +
> + mutex_lock(&user_info->mutex);
> + /*
> + * We allocate handle starting from 1 and not 0 to allow
> + * user-space treat zero as invalid handle
> + */
> + id = idr_alloc(&user_info->idr, hr_entry, 1, -1, GFP_KERNEL);
> + if (id < 0) {
> + nnp_user_put(user_info);
> + nnp_hostres_put(hostres);
> + kfree(hr_entry);
> + mutex_unlock(&user_info->mutex);
> + return -ENOSPC;
> + }
> + hr_entry->user_handle = id;
> + list_add(&hr_entry->node, &user_info->hostres_list);
> + mutex_unlock(&user_info->mutex);
> +
> + *user_hostres_entry = hr_entry;
> +
> + return 0;
> +}
> +
> +void nnp_user_remove_hostres_locked(struct user_hostres *hr_entry)
> +{
> + struct nnp_user_info *user_info = hr_entry->user_info;
> +
> + idr_remove(&user_info->idr, hr_entry->user_handle);
> + list_del(&hr_entry->node);
> +
> + nnp_hostres_put(hr_entry->hostres);
> +
> + kfree(hr_entry);
> + nnp_user_put(user_info);
> +}
> +
> +void nnp_user_remove_hostres(struct user_hostres *hr_entry)
> +{
> + struct nnp_user_info *user_info = hr_entry->user_info;
> +
> + mutex_lock(&user_info->mutex);
> + nnp_user_remove_hostres_locked(hr_entry);
> + mutex_unlock(&user_info->mutex);
> +}
> +
> +void nnp_user_destroy_all(struct nnp_user_info *user_info)
> +{
> + struct user_hostres *user_hostres_entry;
> + DECLARE_COMPLETION_ONSTACK(completion);
> +
> + mutex_lock(&user_info->mutex);
> +
> + /* destroy all hostreses owned by the "user" */
> + while (!list_empty(&user_info->hostres_list)) {
> + user_hostres_entry = list_first_entry(&user_info->hostres_list,
> + struct user_hostres, node);
> + /*
> + * We can safely destroy this object without checking
> + * its refcount since we get here only after the host char-dev
> + * as well as all cmd_chan char-devs that may hold temporary
> + * reference to this object are already released.
> + */
> + nnp_user_remove_hostres_locked(user_hostres_entry);
> + }
> + mutex_unlock(&user_info->mutex);
> +
> + /* wait for all channels and hostreses to be destroyed */
> + user_info->close_completion = &completion;
> + nnp_user_put(user_info);
> + wait_for_completion(&completion);
> +}
> diff --git a/drivers/misc/intel-nnpi/nnp_user.h b/drivers/misc/intel-nnpi/nnp_user.h
> new file mode 100644
> index 0000000..429ac13
> --- /dev/null
> +++ b/drivers/misc/intel-nnpi/nnp_user.h
> @@ -0,0 +1,79 @@
> +/* SPDX-License-Identifier: GPL-2.0-only */
> +/* Copyright (C) 2019-2021 Intel Corporation */
> +
> +#ifndef _NNPDRV_INF_PROC_H
> +#define _NNPDRV_INF_PROC_H
> +
> +#include <linux/kref.h>
> +#include <linux/types.h>
> +
> +#include "hostres.h"
> +
> +/**
> + * struct nnp_user_info - structure for per-user info
> + * @ref: refcount to this "user" object
> + * @hostres_list: list of host resources
> + * @close_completion: used to wait for all channels of this user to be
> + * destroyed before closing the user.
> + * @mutex: protects hostres_list and idr modifications
> + * @idr: used to generate user handles to created host resources
> + * @user_list_node: list node to attach this struct in "list of users".
> + *
> + * structure to hold per-user info,
> + * a "user" is created for each open made to the host char dev (/dev/nnpi_host).
> + * It holds a list of all host resources created through requests from
> + * the same client ("user").
> + * device communication "channels", created by device char dev (/dev/nnpi%d)
> + * must be correlated with a "user" object which is supplied from user-space
> + * by the opened file descriptor to /dev/nnpi_host. Such "channel" may access
> + * only host resources created by the same "user".
> + * The lifetime of this object last at least for the duration of the host char
> + * device file struct but can last longer if some channel objects still hold
> + * a reference to it (this is why @ref is needed).
> + */
> +struct nnp_user_info {
> + struct kref ref;
> + struct list_head hostres_list;
> + struct completion *close_completion;
> + struct mutex mutex;
> + struct idr idr;
> + struct list_head user_list_node;
> +};
> +
> +/**
> + * struct user_hostres - structure for host resource created by user
> + * @node: list node to attach this struct to nnp_user_info::hostres_list
> + * @hostres: the actual host resource object
> + * @user_handle: handle allocated from idr object, used as handle to this
> + * object in ioctl ABI.
> + * @user_info: pointer to "user" which created this resource.
> + * it is used only during destruction of the object.
> + *
> + * structure for a host resource object which created through host char dev
> + * request. The lifetime of this structure ends when the user request to
> + * destroy it through ioctl call. The underlying @hostres may still continue
> + * to exist if command channel (cmd_chan) objects has mapped the resource to
> + * device access.
> + */
> +struct user_hostres {
> + struct list_head node;
> + struct host_resource *hostres;
> + int user_handle;
> + struct nnp_user_info *user_info;
> +};
> +
> +void nnp_user_init(struct nnp_user_info *user_info);
> +
> +void nnp_user_get(struct nnp_user_info *user_info);
> +void nnp_user_put(struct nnp_user_info *user_info);
> +
> +int nnp_user_add_hostres(struct nnp_user_info *user_info,
> + struct host_resource *hostres,
> + struct user_hostres **user_hostres_entry);
> +
> +void nnp_user_remove_hostres(struct user_hostres *hr_entry);
> +void nnp_user_remove_hostres_locked(struct user_hostres *hr_entry);
> +
> +void nnp_user_destroy_all(struct nnp_user_info *user_info);
> +
> +#endif
> diff --git a/include/uapi/misc/intel_nnpi.h b/include/uapi/misc/intel_nnpi.h
> new file mode 100644
> index 0000000..5114aea
> --- /dev/null
> +++ b/include/uapi/misc/intel_nnpi.h
> @@ -0,0 +1,150 @@
> +/* SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note */
> +/* Copyright (C) 2019-2021 Intel Corporation */
> +
> +#ifndef _NNP_UAPI_H
> +#define _NNP_UAPI_H
> +
> +#include <linux/types.h>
> +#include <linux/ioctl.h>
> +#include <stdbool.h>
> +
> +#define NNPDRV_INF_HOST_DEV_NAME "nnpi_host"
> +
> +/*
> + * ioctls for /dev/nnpi_host device
> + */
> +
> +/*
> + * IOCTL_INF_CREATE_HOST_RESOURCE:
> + *
> + * A request to create a host memory resource object that can then be mapped
> + * and accessed by the NNP-I device's DMA engine.
> + * The created host resource is pinned in memory for its entire lifecycle.

Drive-by comments, but who has access to this interface? non-root?

How much memory can they pin with it?

Pinning is not a nice way to do things, you likely need some sort of
memory manager and fencing system.

Dave.