![Kenneth Lee](/assets/img/avatar_default.png)
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 Reviewed-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Reviewed-by: Jonathan Cameron <Jonathan.Cameron@huawei.com> Signed-off-by: Kenneth Lee <liguozhu@hisilicon.com> Signed-off-by: Zaibo Xu <xuzaibo@huawei.com> Signed-off-by: Zhou Wang <wangzhou1@hisilicon.com> Signed-off-by: Jean-Philippe Brucker <jean-philippe@linaro.org> Signed-off-by: Zhangfei Gao <zhangfei.gao@linaro.org> Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
162 lines
4 KiB
C
162 lines
4 KiB
C
/* 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_MAX_REGION 2
|
|
#define UACCE_MAX_NAME_SIZE 64
|
|
|
|
struct uacce_queue;
|
|
struct uacce_device;
|
|
|
|
/**
|
|
* struct uacce_qfile_region - structure of queue file region
|
|
* @type: type of the region
|
|
*/
|
|
struct uacce_qfile_region {
|
|
enum uacce_qfrt type;
|
|
};
|
|
|
|
/**
|
|
* 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
|
|
* @mmap: mmap addresses of queue to user space
|
|
* @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);
|
|
int (*mmap)(struct uacce_queue *q, struct vm_area_struct *vma,
|
|
struct uacce_qfile_region *qfr);
|
|
long (*ioctl)(struct uacce_queue *q, unsigned int cmd,
|
|
unsigned long arg);
|
|
};
|
|
|
|
/**
|
|
* struct uacce_interface - interface required for uacce_register()
|
|
* @name: the uacce device name. Will show up in sysfs
|
|
* @flags: uacce device attributes
|
|
* @ops: pointer to the struct uacce_ops
|
|
*/
|
|
struct uacce_interface {
|
|
char name[UACCE_MAX_NAME_SIZE];
|
|
unsigned int flags;
|
|
const struct uacce_ops *ops;
|
|
};
|
|
|
|
enum uacce_q_state {
|
|
UACCE_Q_ZOMBIE = 0,
|
|
UACCE_Q_INIT,
|
|
UACCE_Q_STARTED,
|
|
};
|
|
|
|
/**
|
|
* struct uacce_queue
|
|
* @uacce: pointer to uacce
|
|
* @priv: private pointer
|
|
* @wait: wait queue head
|
|
* @list: index into uacce_mm
|
|
* @uacce_mm: the corresponding mm
|
|
* @qfrs: pointer of qfr regions
|
|
* @state: queue state machine
|
|
*/
|
|
struct uacce_queue {
|
|
struct uacce_device *uacce;
|
|
void *priv;
|
|
wait_queue_head_t wait;
|
|
struct list_head list;
|
|
struct uacce_mm *uacce_mm;
|
|
struct uacce_qfile_region *qfrs[UACCE_MAX_REGION];
|
|
enum uacce_q_state state;
|
|
};
|
|
|
|
/**
|
|
* struct uacce_device
|
|
* @algs: supported algorithms
|
|
* @api_ver: api version
|
|
* @ops: pointer to the struct uacce_ops
|
|
* @qf_pg_num: page numbers of the queue file regions
|
|
* @parent: pointer to the parent device
|
|
* @is_vf: whether virtual function
|
|
* @flags: uacce attributes
|
|
* @dev_id: id of the uacce device
|
|
* @cdev: cdev of the uacce
|
|
* @dev: dev of the uacce
|
|
* @priv: private pointer of the uacce
|
|
* @mm_list: list head of uacce_mm->list
|
|
* @mm_lock: lock for mm_list
|
|
*/
|
|
struct uacce_device {
|
|
const char *algs;
|
|
const char *api_ver;
|
|
const struct uacce_ops *ops;
|
|
unsigned long qf_pg_num[UACCE_MAX_REGION];
|
|
struct device *parent;
|
|
bool is_vf;
|
|
u32 flags;
|
|
u32 dev_id;
|
|
struct cdev *cdev;
|
|
struct device dev;
|
|
void *priv;
|
|
struct list_head mm_list;
|
|
struct mutex mm_lock;
|
|
};
|
|
|
|
/**
|
|
* struct uacce_mm - keep track of queues bound to a process
|
|
* @list: index into uacce_device
|
|
* @queues: list of queues
|
|
* @mm: the mm struct
|
|
* @lock: protects the list of queues
|
|
* @pasid: pasid of the uacce_mm
|
|
* @handle: iommu_sva handle return from iommu_sva_bind_device
|
|
*/
|
|
struct uacce_mm {
|
|
struct list_head list;
|
|
struct list_head queues;
|
|
struct mm_struct *mm;
|
|
struct mutex lock;
|
|
int pasid;
|
|
struct iommu_sva *handle;
|
|
};
|
|
|
|
#if IS_ENABLED(CONFIG_UACCE)
|
|
|
|
struct uacce_device *uacce_alloc(struct device *parent,
|
|
struct uacce_interface *interface);
|
|
int uacce_register(struct uacce_device *uacce);
|
|
void uacce_remove(struct uacce_device *uacce);
|
|
|
|
#else /* CONFIG_UACCE */
|
|
|
|
static inline
|
|
struct uacce_device *uacce_alloc(struct device *parent,
|
|
struct uacce_interface *interface)
|
|
{
|
|
return ERR_PTR(-ENODEV);
|
|
}
|
|
|
|
static inline int uacce_register(struct uacce_device *uacce)
|
|
{
|
|
return -EINVAL;
|
|
}
|
|
|
|
static inline void uacce_remove(struct uacce_device *uacce) {}
|
|
|
|
#endif /* CONFIG_UACCE */
|
|
|
|
#endif /* _LINUX_UACCE_H */
|