未验证 提交 edb5d824 编写于 作者: O openeuler-ci-bot 提交者: Gitee

!803 ACC support no-sva feature

Merge Pull Request from: @xiao_jiang_shui 
 
ACC support no-sva feature
issue:https://gitee.com/openeuler/kernel/issues/I773SD
 
 
Link:https://gitee.com/openeuler/kernel/pulls/803 

Reviewed-by: Yang Shen <shenyang39@huawei.com> 
Signed-off-by: Zheng Zengkai <zhengzengkai@huawei.com> 
......@@ -11,7 +11,6 @@
#include <linux/pci.h>
#include <linux/pm_runtime.h>
#include <linux/topology.h>
#include <linux/uacce.h>
#include "hpre.h"
#define HPRE_QM_ABNML_INT_MASK 0x100004
......@@ -366,7 +365,7 @@ static int hpre_set_qm_algs(struct hisi_qm *qm)
u32 alg_msk;
int i;
if (!qm->use_sva)
if (!qm->use_uacce)
return 0;
algs = devm_kzalloc(dev, HPRE_DEV_ALG_MAX_LEN * sizeof(char), GFP_KERNEL);
......@@ -1398,12 +1397,10 @@ static int hpre_probe(struct pci_dev *pdev, const struct pci_device_id *id)
goto err_with_qm_start;
}
if (qm->uacce) {
ret = uacce_register(qm->uacce);
if (ret) {
pci_err(pdev, "failed to register uacce (%d)!\n", ret);
goto err_with_alg_register;
}
ret = qm_register_uacce(qm);
if (ret) {
pci_err(pdev, "Failed to register uacce (%d)!\n", ret);
goto err_with_alg_register;
}
if (qm->fun_type == QM_HW_PF && vfs_num) {
......
......@@ -7,12 +7,12 @@
#include <linux/dma-mapping.h>
#include <linux/idr.h>
#include <linux/io.h>
#include <linux/iommu.h>
#include <linux/irqreturn.h>
#include <linux/log2.h>
#include <linux/pm_runtime.h>
#include <linux/seq_file.h>
#include <linux/slab.h>
#include <linux/uacce.h>
#include <linux/uaccess.h>
#include <uapi/misc/uacce/hisi_qm.h>
#include <linux/hisi_acc_qm.h>
......@@ -829,6 +829,33 @@ static void qm_cq_head_update(struct hisi_qp *qp)
}
}
static void qm_poll_user_event_cb(struct hisi_qp *qp)
{
struct qm_cqe *cqe = qp->cqe + qp->qp_status.cq_head;
struct uacce_queue *q = qp->uacce_q;
bool updated = 0;
/*
* If multi thread poll one queue, each thread will produce
* one event, so we query one cqe and break out of the loop.
* If only one thread poll one queue, we need query all cqe
* to ensure that we poll a cleaned queue next time.
*/
while (QM_CQE_PHASE(cqe) == qp->qp_status.cqc_phase) {
dma_rmb();
qm_cq_head_update(qp);
cqe = qp->cqe + qp->qp_status.cq_head;
updated = 1;
if (!wq_has_single_sleeper(&q->wait))
break;
}
if (updated) {
atomic_inc(&qp->qp_status.complete_task);
qp->event_cb(qp);
}
}
static void qm_poll_req_cb(struct hisi_qp *qp)
{
struct qm_cqe *cqe = qp->cqe + qp->qp_status.cq_head;
......@@ -896,7 +923,7 @@ static void qm_work_process(struct work_struct *work)
continue;
if (qp->event_cb) {
qp->event_cb(qp);
qm_poll_user_event_cb(qp);
continue;
}
......@@ -2306,7 +2333,7 @@ static void hisi_qm_cache_wb(struct hisi_qm *qm)
static void qm_qp_event_notifier(struct hisi_qp *qp)
{
wake_up_interruptible(&qp->uacce_q->wait);
uacce_wake_up(qp->uacce_q);
}
/* This function returns free number of qp in qm. */
......@@ -2447,18 +2474,8 @@ static void hisi_qm_uacce_stop_queue(struct uacce_queue *q)
static int hisi_qm_is_q_updated(struct uacce_queue *q)
{
struct hisi_qp *qp = q->priv;
struct qm_cqe *cqe = qp->cqe + qp->qp_status.cq_head;
int updated = 0;
while (QM_CQE_PHASE(cqe) == qp->qp_status.cqc_phase) {
/* make sure to read data from memory */
dma_rmb();
qm_cq_head_update(qp);
cqe = qp->cqe + qp->qp_status.cq_head;
updated = 1;
}
return updated;
return atomic_add_unless(&qp->qp_status.complete_task, -1, 0);
}
static void qm_set_sqctype(struct uacce_queue *q, u16 type)
......@@ -2489,7 +2506,7 @@ static long hisi_qm_uacce_ioctl(struct uacce_queue *q, unsigned int cmd,
qm_set_sqctype(q, qp_ctx.qc_type);
qp_ctx.id = qp->qp_id;
if (copy_to_user((void __user *)arg, &qp_ctx,
if (copy_to_user((void __user *)(uintptr_t)arg, &qp_ctx,
sizeof(struct hisi_qp_ctx)))
return -EFAULT;
......@@ -2513,6 +2530,78 @@ static long hisi_qm_uacce_ioctl(struct uacce_queue *q, unsigned int cmd,
return -EINVAL;
}
static enum uacce_dev_state hisi_qm_get_state(struct uacce_device *uacce)
{
struct hisi_qm *qm = uacce->priv;
enum qm_state curr;
curr = atomic_read(&qm->status.flags);
if (curr == QM_STOP)
return UACCE_DEV_ERR;
return UACCE_DEV_NORMAL;
}
static void qm_uacce_api_ver_init(struct hisi_qm *qm)
{
struct uacce_device *uacce = qm->uacce;
if (uacce->flags & UACCE_DEV_IOMMU) {
qm->use_sva = uacce->flags & UACCE_DEV_SVA ? true : false;
if (qm->ver == QM_HW_V1)
uacce->api_ver = HISI_QM_API_VER_BASE;
else if (qm->ver == QM_HW_V2)
uacce->api_ver = HISI_QM_API_VER2_BASE;
else
uacce->api_ver = HISI_QM_API_VER3_BASE;
} else {
qm->use_sva = false;
if (qm->ver == QM_HW_V1)
uacce->api_ver = HISI_QM_API_VER_BASE
UACCE_API_VER_NOIOMMU_SUBFIX;
else if (qm->ver == QM_HW_V2)
uacce->api_ver = HISI_QM_API_VER2_BASE
UACCE_API_VER_NOIOMMU_SUBFIX;
else
uacce->api_ver = HISI_QM_API_VER3_BASE
UACCE_API_VER_NOIOMMU_SUBFIX;
}
}
static void qm_uacce_base_init(struct hisi_qm *qm)
{
unsigned long dus_page_nr, mmio_page_nr;
struct uacce_device *uacce = qm->uacce;
struct pci_dev *pdev = qm->pdev;
u16 sq_depth, cq_depth;
qm_uacce_api_ver_init(qm);
if (qm->ver == QM_HW_V1)
mmio_page_nr = QM_DOORBELL_PAGE_NR;
else if (qm->ver == QM_HW_V2 ||
!test_bit(QM_SUPPORT_DB_ISOLATION, &qm->caps))
mmio_page_nr = QM_DOORBELL_PAGE_NR +
QM_DOORBELL_SQ_CQ_BASE_V2 / PAGE_SIZE;
else
mmio_page_nr = QM_QP_DB_INTERVAL / PAGE_SIZE;
uacce->is_vf = pdev->is_virtfn;
uacce->priv = qm;
uacce->algs = qm->algs;
uacce->parent = &pdev->dev;
qm_get_xqc_depth(qm, &sq_depth, &cq_depth, QM_QP_DEPTH_CAP);
/* Add one more page for device or qp status */
dus_page_nr = (PAGE_SIZE - 1 + qm->sqe_size * sq_depth +
sizeof(struct qm_cqe) * cq_depth + PAGE_SIZE) >>
PAGE_SHIFT;
uacce->qf_pg_num[UACCE_QFRT_MMIO] = mmio_page_nr;
uacce->qf_pg_num[UACCE_QFRT_DUS] = dus_page_nr;
}
/**
* qm_hw_err_isolate() - Try to set the isolation status of the uacce device
* according to user's configuration of error threshold.
......@@ -2628,6 +2717,7 @@ static const struct uacce_ops uacce_qm_ops = {
.stop_queue = hisi_qm_uacce_stop_queue,
.mmap = hisi_qm_uacce_mmap,
.ioctl = hisi_qm_uacce_ioctl,
.get_dev_state = hisi_qm_get_state,
.is_q_updated = hisi_qm_is_q_updated,
.get_isolate_state = hisi_qm_get_isolate_state,
.isolate_err_threshold_write = hisi_qm_isolate_threshold_write,
......@@ -2638,7 +2728,7 @@ static void qm_remove_uacce(struct hisi_qm *qm)
{
struct uacce_device *uacce = qm->uacce;
if (qm->use_sva) {
if (qm->use_uacce) {
qm_hw_err_destroy(qm);
uacce_remove(uacce);
qm->uacce = NULL;
......@@ -2648,61 +2738,42 @@ static void qm_remove_uacce(struct hisi_qm *qm)
static int qm_alloc_uacce(struct hisi_qm *qm)
{
struct pci_dev *pdev = qm->pdev;
struct uacce_interface interface;
struct uacce_device *uacce;
unsigned long mmio_page_nr;
unsigned long dus_page_nr;
u16 sq_depth, cq_depth;
struct uacce_interface interface = {
.flags = UACCE_DEV_SVA,
.ops = &uacce_qm_ops,
};
int ret;
ret = strscpy(interface.name, dev_driver_string(&pdev->dev),
sizeof(interface.name));
if (ret < 0)
return -ENAMETOOLONG;
int name_len;
uacce = uacce_alloc(&pdev->dev, &interface);
if (IS_ERR(uacce))
return PTR_ERR(uacce);
if (!qm->use_uacce)
return 0;
if (uacce->flags & UACCE_DEV_SVA) {
qm->use_sva = true;
} else {
/* only consider sva case */
qm_remove_uacce(qm);
name_len = strlen(pdev->driver->name);
if (name_len >= UACCE_MAX_NAME_SIZE) {
pci_err(pdev, "The driver name(%d) is longer than %d!\n",
name_len, UACCE_MAX_NAME_SIZE);
return -EINVAL;
}
uacce->is_vf = pdev->is_virtfn;
uacce->priv = qm;
if (qm->ver == QM_HW_V1)
uacce->api_ver = HISI_QM_API_VER_BASE;
else if (qm->ver == QM_HW_V2)
uacce->api_ver = HISI_QM_API_VER2_BASE;
else
uacce->api_ver = HISI_QM_API_VER3_BASE;
if (qm->ver == QM_HW_V1)
mmio_page_nr = QM_DOORBELL_PAGE_NR;
else if (!test_bit(QM_SUPPORT_DB_ISOLATION, &qm->caps))
mmio_page_nr = QM_DOORBELL_PAGE_NR +
QM_DOORBELL_SQ_CQ_BASE_V2 / PAGE_SIZE;
else
mmio_page_nr = qm->db_interval / PAGE_SIZE;
strncpy(interface.name, pdev->driver->name, name_len);
interface.name[name_len] = '\0';
qm_get_xqc_depth(qm, &sq_depth, &cq_depth, QM_QP_DEPTH_CAP);
interface.flags = qm->use_iommu ? UACCE_DEV_IOMMU : UACCE_DEV_NOIOMMU;
if (qm->mode == UACCE_MODE_SVA) {
if (!qm->use_iommu) {
pci_err(pdev, "iommu not support sva!\n");
return -EINVAL;
}
/* Add one more page for device or qp status */
dus_page_nr = (PAGE_SIZE - 1 + qm->sqe_size * sq_depth +
sizeof(struct qm_cqe) * cq_depth + PAGE_SIZE) >>
PAGE_SHIFT;
interface.flags |= UACCE_DEV_SVA;
}
uacce->qf_pg_num[UACCE_QFRT_MMIO] = mmio_page_nr;
uacce->qf_pg_num[UACCE_QFRT_DUS] = dus_page_nr;
interface.ops = &uacce_qm_ops;
uacce = uacce_alloc(&pdev->dev, &interface);
if (IS_ERR(uacce)) {
pci_err(pdev, "fail to alloc uacce device\n!");
return PTR_ERR(uacce);
}
qm->uacce = uacce;
qm_uacce_base_init(qm);
qm->uacce = uacce;
INIT_LIST_HEAD(&qm->isolate_data.qm_hw_errs);
mutex_init(&qm->isolate_data.isolate_lock);
......@@ -2710,6 +2781,16 @@ static int qm_alloc_uacce(struct hisi_qm *qm)
return 0;
}
int qm_register_uacce(struct hisi_qm *qm)
{
if (!qm->use_uacce)
return 0;
dev_info(&qm->pdev->dev, "qm register to uacce\n");
return uacce_register(qm->uacce);
}
EXPORT_SYMBOL_GPL(qm_register_uacce);
/**
* qm_frozen() - Try to froze QM to cut continuous queue request. If
* there is user on the QM, return failure without doing anything.
......@@ -2840,7 +2921,20 @@ static int hisi_qp_memory_init(struct hisi_qm *qm, size_t dma_size, int id,
return ret;
}
static void hisi_qm_pre_init(struct hisi_qm *qm)
static inline bool is_iommu_used(struct device *dev)
{
struct iommu_domain *domain;
domain = iommu_get_domain_for_dev(dev);
if (domain) {
dev_info(dev, "iommu domain type = %u\n", domain->type);
return domain->type & __IOMMU_DOMAIN_PAGING;
}
return false;
}
static int hisi_qm_pre_init(struct hisi_qm *qm)
{
struct pci_dev *pdev = qm->pdev;
......@@ -2851,15 +2945,30 @@ static void hisi_qm_pre_init(struct hisi_qm *qm)
else
qm->ops = &qm_hw_ops_v3;
switch (qm->mode) {
case UACCE_MODE_NOUACCE:
qm->use_uacce = false;
break;
case UACCE_MODE_SVA:
case UACCE_MODE_NOIOMMU:
qm->use_uacce = true;
break;
default:
pci_err(pdev, "uacce mode error!\n");
return -EINVAL;
}
pci_set_drvdata(pdev, qm);
mutex_init(&qm->mailbox_lock);
init_rwsem(&qm->qps_lock);
qm->qp_in_used = 0;
qm->misc_ctl = false;
qm->use_iommu = is_iommu_used(&pdev->dev);
if (test_bit(QM_SUPPORT_RPM, &qm->caps)) {
if (!acpi_device_power_manageable(ACPI_COMPANION(&pdev->dev)))
dev_info(&pdev->dev, "_PS0 and _PR0 are not defined");
}
return 0;
}
static void qm_cmd_uninit(struct hisi_qm *qm)
......@@ -2960,6 +3069,7 @@ void hisi_qm_uninit(struct hisi_qm *qm)
hisi_qm_set_state(qm, VF_NOT_READY);
up_write(&qm->qps_lock);
qm_remove_uacce(qm);
qm_irqs_unregister(qm);
hisi_qm_pci_uninit(qm);
if (qm->use_sva) {
......@@ -4197,7 +4307,7 @@ static int qm_controller_reset_prepare(struct hisi_qm *qm)
return ret;
}
if (qm->use_sva) {
if (qm->use_uacce) {
ret = qm_hw_err_isolate(qm);
if (ret)
pci_err(pdev, "failed to isolate hw err!\n");
......@@ -4688,6 +4798,8 @@ void hisi_qm_dev_shutdown(struct pci_dev *pdev)
ret = hisi_qm_stop(qm, QM_NORMAL);
if (ret)
dev_err(&pdev->dev, "Fail to stop qm in shutdown!\n");
qm_remove_uacce(qm);
}
EXPORT_SYMBOL_GPL(hisi_qm_dev_shutdown);
......@@ -5406,7 +5518,9 @@ int hisi_qm_init(struct hisi_qm *qm)
struct device *dev = &pdev->dev;
int ret;
hisi_qm_pre_init(qm);
ret = hisi_qm_pre_init(qm);
if (ret)
return ret;
ret = hisi_qm_pci_init(qm);
if (ret)
......@@ -5425,10 +5539,10 @@ int hisi_qm_init(struct hisi_qm *qm)
}
}
if (qm->mode == UACCE_MODE_SVA) {
ret = qm_alloc_uacce(qm);
if (ret < 0)
dev_warn(dev, "fail to alloc uacce (%d)\n", ret);
ret = qm_alloc_uacce(qm);
if (ret < 0) {
dev_err(dev, "failed to alloc uacce (%d)\n", ret);
goto err_irq_register;
}
ret = hisi_qm_memory_init(qm);
......
......@@ -189,7 +189,6 @@ struct sec_dev {
struct hisi_qm qm;
struct sec_debug debug;
u32 ctx_q_num;
bool iommu_used;
};
enum sec_cap_type {
......
......@@ -599,7 +599,7 @@ static int sec_ctx_base_init(struct sec_ctx *ctx)
ctx->dev = &sec->qm.pdev->dev;
ctx->hlf_q_num = sec->ctx_q_num >> 1;
ctx->pbuf_supported = ctx->sec->iommu_used;
ctx->pbuf_supported = sec->qm.use_iommu;
/* Half of queue depth is taken as fake requests limit in the queue. */
ctx->fake_req_limit = ctx->qps[0]->sq_depth >> 1;
......
......@@ -1082,7 +1082,7 @@ static int sec_set_qm_algs(struct hisi_qm *qm)
u64 alg_mask;
int i;
if (!qm->use_sva)
if (!qm->use_uacce)
return 0;
algs = devm_kzalloc(dev, SEC_DEV_ALG_MAX_LEN * sizeof(char), GFP_KERNEL);
......@@ -1177,23 +1177,6 @@ static void sec_probe_uninit(struct hisi_qm *qm)
hisi_qm_dev_err_uninit(qm);
}
static void sec_iommu_used_check(struct sec_dev *sec)
{
struct iommu_domain *domain;
struct device *dev = &sec->qm.pdev->dev;
domain = iommu_get_domain_for_dev(dev);
/* Check if iommu is used */
sec->iommu_used = false;
if (domain) {
if (domain->type & __IOMMU_DOMAIN_PAGING)
sec->iommu_used = true;
dev_info(dev, "SMMU Opened, the iommu type = %u\n",
domain->type);
}
}
static int sec_probe(struct pci_dev *pdev, const struct pci_device_id *id)
{
struct sec_dev *sec;
......@@ -1212,7 +1195,6 @@ static int sec_probe(struct pci_dev *pdev, const struct pci_device_id *id)
}
sec->ctx_q_num = ctx_q_num;
sec_iommu_used_check(sec);
ret = sec_probe_init(sec);
if (ret) {
......
......@@ -421,7 +421,7 @@ static int hisi_zip_set_qm_algs(struct hisi_qm *qm)
u32 alg_mask;
int i;
if (!qm->use_sva)
if (!qm->use_uacce)
return 0;
algs = devm_kzalloc(dev, HZIP_DEV_ALG_MAX_LEN * sizeof(char), GFP_KERNEL);
......
config UACCE
menuconfig UACCE
tristate "Accelerator Framework for User Land"
depends on IOMMU_API
select ANON_INODES
help
UACCE provides interface for the user process to access the hardware
without interaction with the kernel space in data path.
......
// SPDX-License-Identifier: GPL-2.0-or-later
#include <linux/compat.h>
#include <linux/dma-mapping.h>
#include <linux/file.h>
#include <linux/iommu.h>
#include <linux/module.h>
#include <linux/poll.h>
#include <linux/slab.h>
#include <linux/uacce.h>
#include <linux/wait.h>
static struct class *uacce_class;
static dev_t uacce_devt;
static DEFINE_XARRAY_ALLOC(uacce_xa);
static const struct file_operations uacce_fops;
static struct uacce_qfile_region noiommu_ss_default_qfr = {
.type = UACCE_QFRT_SS,
};
static int cdev_get(struct device *dev, void *data)
{
struct uacce_device *uacce;
struct device **t_dev = data;
uacce = container_of(dev, struct uacce_device, dev);
if (uacce->parent == *t_dev) {
*t_dev = dev;
return 1;
}
return 0;
}
/**
* dev_to_uacce - Get structure uacce device from its parent device
* @dev: the device
*/
struct uacce_device *dev_to_uacce(struct device *dev)
{
struct device **tdev = &dev;
int ret;
ret = class_for_each_device(uacce_class, NULL, tdev, cdev_get);
if (ret) {
dev = *tdev;
return container_of(dev, struct uacce_device, dev);
}
return NULL;
}
EXPORT_SYMBOL_GPL(dev_to_uacce);
/*
* If the parent driver or the device disappears, the queue state is invalid and
......@@ -49,10 +88,152 @@ static int uacce_put_queue(struct uacce_queue *q)
uacce->ops->put_queue(q);
q->state = UACCE_Q_ZOMBIE;
atomic_dec(&uacce->ref);
return 0;
}
static long uacce_cmd_share_qfr(struct uacce_queue *src, int fd)
{
struct device *dev = &src->uacce->dev;
struct file *filep = fget(fd);
struct uacce_queue *tgt;
int ret = -EINVAL;
if (!filep) {
dev_err(dev, "filep is NULL!\n");
return ret;
}
if (filep->f_op != &uacce_fops) {
dev_err(dev, "file ops mismatch!\n");
goto out_with_fd;
}
tgt = filep->private_data;
if (!tgt) {
dev_err(dev, "target queue is not exist!\n");
goto out_with_fd;
}
mutex_lock(&src->mutex);
if (tgt->state == UACCE_Q_ZOMBIE || src->state == UACCE_Q_ZOMBIE) {
dev_err(dev, "target or source queue is zombie!\n");
goto out_with_fd;
}
if (!src->qfrs[UACCE_QFRT_SS] || tgt->qfrs[UACCE_QFRT_SS]) {
dev_err(dev, "src q's SS not exists or target q's SS exists!\n");
goto out_with_fd;
}
/* In No-IOMMU mode, taget queue uses default SS qfr */
tgt->qfrs[UACCE_QFRT_SS] = &noiommu_ss_default_qfr;
ret = 0;
out_with_fd:
mutex_unlock(&src->mutex);
fput(filep);
return ret;
}
static long uacce_get_ss_dma(struct uacce_queue *q, void __user *arg)
{
struct uacce_device *uacce = q->uacce;
struct uacce_dma_slice *slice;
unsigned long slice_idx = 0;
unsigned long dma, size;
unsigned int max_idx;
long ret = -EFAULT;
if (q->state == UACCE_Q_ZOMBIE) {
dev_err(&uacce->dev, "queue is zombie!\n");
ret = -EINVAL;
goto param_check;
}
if (!q->qfrs[UACCE_QFRT_SS]) {
dev_err(&uacce->dev, "no ss dma region!\n");
ret = -EINVAL;
goto param_check;
}
slice = q->qfrs[UACCE_QFRT_SS]->dma_list;
if (copy_from_user(&slice_idx, arg, sizeof(unsigned long))) {
dev_err(&uacce->dev, "copy_from_user fail!\n");
goto param_check;
}
if (slice[0].total_num - 1 < slice_idx) {
dev_err(&uacce->dev, "no ss slice idx %lu err, total %u!\n",
slice_idx, slice[0].total_num);
ret = -EINVAL;
goto param_check;
}
dma = slice[slice_idx].dma;
size = slice[slice_idx].size;
if (!size) {
max_idx = slice[0].total_num - 1;
dev_err(&uacce->dev, "%luth ss region[0x%lx, %lu] no exist, range[[0](0x%llx, %llu) -> [%u](0x%llx, %llu)]\n",
slice_idx, dma, size,
slice[0].dma, slice[0].size, max_idx,
slice[max_idx].dma, slice[max_idx].size);
ret = -ENODEV;
goto param_check;
}
dma = dma | ((size >> UACCE_GRAN_SHIFT) & UACCE_GRAN_NUM_MASK);
if (copy_to_user(arg, &dma, sizeof(unsigned long))) {
dev_err(&uacce->dev, "copy_to_user fail!\n");
goto param_check;
}
ret = (long)(slice[0].total_num - 1 - slice_idx);
param_check:
return ret;
}
static void uacce_free_dma_buffers(struct uacce_queue *q)
{
struct uacce_qfile_region *qfr = q->qfrs[UACCE_QFRT_SS];
struct device *pdev = q->uacce->parent;
int i = 0;
if (module_refcount(pdev->driver->owner) > 0)
module_put(pdev->driver->owner);
if (!qfr->dma_list)
return;
while (i < qfr->dma_list[0].total_num) {
WARN_ON(!qfr->dma_list[i].size || !qfr->dma_list[i].dma);
dev_dbg(pdev, "free dma qfr (kaddr=%lx, dma=%llx)\n",
(unsigned long)(uintptr_t)qfr->dma_list[i].kaddr,
qfr->dma_list[i].dma);
dma_free_coherent(pdev, qfr->dma_list[i].size,
qfr->dma_list[i].kaddr,
qfr->dma_list[i].dma);
i++;
}
kfree(qfr->dma_list);
qfr->dma_list = NULL;
}
/**
* uacce_wake_up - Wake up the process who is waiting this queue
* @q: the accelerator queue to wake up
*/
void uacce_wake_up(struct uacce_queue *q)
{
if (unlikely(!q))
return;
wake_up_interruptible(&q->wait);
}
EXPORT_SYMBOL_GPL(uacce_wake_up);
static long uacce_fops_unl_ioctl(struct file *filep,
unsigned int cmd, unsigned long arg)
{
......@@ -79,6 +260,12 @@ static long uacce_fops_unl_ioctl(struct file *filep,
case UACCE_CMD_PUT_Q:
ret = uacce_put_queue(q);
break;
case UACCE_CMD_SHARE_SVAS:
ret = uacce_cmd_share_qfr(q, (int)arg);
break;
case UACCE_CMD_GET_SS_DMA:
ret = uacce_get_ss_dma(q, (void __user *)(uintptr_t)arg);
break;
default:
if (uacce->ops->ioctl)
ret = uacce->ops->ioctl(q, cmd, arg);
......@@ -94,7 +281,7 @@ static long uacce_fops_unl_ioctl(struct file *filep,
static long uacce_fops_compat_ioctl(struct file *filep,
unsigned int cmd, unsigned long arg)
{
arg = (unsigned long)compat_ptr(arg);
arg = (unsigned long)(uintptr_t)compat_ptr(arg);
return uacce_fops_unl_ioctl(filep, cmd, arg);
}
......@@ -157,6 +344,7 @@ static int uacce_fops_open(struct inode *inode, struct file *filep)
goto out_with_mem;
q->uacce = uacce;
q->filep = filep;
if (uacce->ops->get_queue) {
ret = uacce->ops->get_queue(uacce, q->pasid, q);
......@@ -164,6 +352,7 @@ static int uacce_fops_open(struct inode *inode, struct file *filep)
goto out_with_bond;
}
atomic_inc(&uacce->ref);
init_waitqueue_head(&q->wait);
filep->private_data = q;
uacce->inode = inode;
......@@ -185,6 +374,7 @@ static int uacce_fops_open(struct inode *inode, struct file *filep)
static int uacce_fops_release(struct inode *inode, struct file *filep)
{
struct uacce_queue *q = filep->private_data;
struct uacce_qfile_region *ss = q->qfrs[UACCE_QFRT_SS];
struct uacce_device *uacce = q->uacce;
mutex_lock(&uacce->mutex);
......@@ -192,26 +382,261 @@ static int uacce_fops_release(struct inode *inode, struct file *filep)
uacce_unbind_queue(q);
list_del(&q->list);
mutex_unlock(&uacce->mutex);
if (ss && ss != &noiommu_ss_default_qfr) {
uacce_free_dma_buffers(q);
kfree(ss);
}
kfree(q);
return 0;
}
static vm_fault_t uacce_vma_fault(struct vm_fault *vmf)
{
if (vmf->flags & (FAULT_FLAG_MKWRITE | FAULT_FLAG_WRITE))
return VM_FAULT_SIGBUS;
return 0;
}
static void uacce_vma_close(struct vm_area_struct *vma)
{
struct uacce_queue *q = vma->vm_private_data;
struct uacce_qfile_region *qfr = NULL;
struct uacce_device *uacce = q->uacce;
struct device *dev = &q->uacce->dev;
if (vma->vm_pgoff < UACCE_MAX_REGION)
qfr = q->qfrs[vma->vm_pgoff];
if (vma->vm_pgoff >= UACCE_MAX_REGION)
return;
kfree(qfr);
qfr = q->qfrs[vma->vm_pgoff];
if (!qfr) {
dev_err(dev, "qfr NULL, type %lu!\n", vma->vm_pgoff);
return;
}
if (qfr->type == UACCE_QFRT_SS &&
atomic_read(&current->active_mm->mm_users) > 0) {
if ((q->state == UACCE_Q_STARTED) && uacce->ops->stop_queue)
uacce->ops->stop_queue(q);
uacce_free_dma_buffers(q);
kfree(qfr);
q->qfrs[vma->vm_pgoff] = NULL;
} else if (qfr->type != UACCE_QFRT_SS) {
kfree(qfr);
q->qfrs[vma->vm_pgoff] = NULL;
}
}
static const struct vm_operations_struct uacce_vm_ops = {
.fault = uacce_vma_fault,
.close = uacce_vma_close,
};
static int get_sort_base(struct uacce_dma_slice *list, int low, int high,
struct uacce_dma_slice *tmp)
{
tmp->kaddr = list[low].kaddr;
tmp->size = list[low].size;
tmp->dma = list[low].dma;
if (low > high)
return -EINVAL;
else if (low == high)
return 0;
while (low < high) {
while (low < high && list[high].dma > tmp->dma)
high--;
list[low].kaddr = list[high].kaddr;
list[low].dma = list[high].dma;
list[low].size = list[high].size;
while (low < high && list[low].dma < tmp->dma)
low++;
list[high].kaddr = list[low].kaddr;
list[high].dma = list[low].dma;
list[high].size = list[low].size;
}
list[low].kaddr = tmp->kaddr;
list[low].dma = tmp->dma;
list[low].size = tmp->size;
return low;
}
static int uacce_sort_dma_buffers(struct uacce_dma_slice *list, int low,
int high, struct uacce_dma_slice *tmp)
{
int *idx_list;
int top = 0;
int pilot;
idx_list = kcalloc(list[0].total_num, sizeof(int),
GFP_KERNEL | __GFP_ZERO);
if (!idx_list)
return -ENOMEM;
pilot = get_sort_base(list, low, high, tmp);
if (pilot <= 0) {
if (pilot)
pr_err("fail to sort base!\n");
kfree(idx_list);
return pilot;
}
if (pilot > low + 1) {
idx_list[top++] = low;
idx_list[top++] = pilot - 1;
}
if (pilot < high - 1) {
idx_list[top++] = pilot + 1;
idx_list[top++] = high;
}
while (top > 0) {
high = idx_list[--top];
low = idx_list[--top];
pilot = get_sort_base(list, low, high, tmp);
if (pilot > low + 1) {
idx_list[top++] = low;
idx_list[top++] = pilot - 1;
}
if (pilot < high - 1) {
idx_list[top++] = pilot + 1;
idx_list[top++] = high;
}
}
kfree(idx_list);
return 0;
}
static int uacce_alloc_dma_buffers(struct uacce_queue *q,
struct vm_area_struct *vma)
{
struct uacce_qfile_region *qfr = q->qfrs[UACCE_QFRT_SS];
unsigned long size = vma->vm_end - vma->vm_start;
unsigned long max_size = PAGE_SIZE << (MAX_ORDER - 1);
struct device *pdev = q->uacce->parent;
struct uacce_device *uacce = q->uacce;
unsigned long start = vma->vm_start;
struct uacce_dma_slice *slice;
unsigned long ss_num;
int ret, i;
/*
* When IOMMU closed, set maximum slice size is 128M, default is 4M
* when IOMMU opened, set maxinum slice size base on actual size
*/
if (uacce->flags & UACCE_DEV_IOMMU)
max_size = size;
else if (max_size > UACCE_GRAN_NUM_MASK << UACCE_GRAN_SHIFT)
max_size = (UACCE_GRAN_NUM_MASK + 1) << (UACCE_GRAN_SHIFT - 1);
ss_num = size / max_size + (size % max_size ? 1 : 0);
slice = kcalloc(ss_num + 1, sizeof(*slice), GFP_KERNEL | __GFP_ZERO);
if (!slice)
return -ENOMEM;
(void)try_module_get(pdev->driver->owner);
qfr->dma_list = slice;
for (i = 0; i < ss_num; i++) {
if (start + max_size > vma->vm_end)
size = vma->vm_end - start;
else
size = max_size;
dev_dbg(pdev, "allocate dma %ld pages\n",
(size + PAGE_SIZE - 1) >> PAGE_SHIFT);
slice[i].kaddr = dma_alloc_coherent(pdev, (size +
PAGE_SIZE - 1) & PAGE_MASK,
&slice[i].dma, GFP_KERNEL);
if (!slice[i].kaddr) {
dev_err(pdev, "Get dma slice(sz=%lu,dma=0x%llx) fail!\n",
size, slice[i].dma);
slice[0].total_num = i;
uacce_free_dma_buffers(q);
return -ENOMEM;
}
slice[i].size = (size + PAGE_SIZE - 1) & PAGE_MASK;
slice[i].total_num = ss_num;
start += size;
}
ret = uacce_sort_dma_buffers(slice, 0, slice[0].total_num - 1,
&slice[ss_num]);
if (ret) {
dev_err(pdev, "failed to sort dma buffers.\n");
uacce_free_dma_buffers(q);
return ret;
}
return 0;
}
static int uacce_mmap_dma_buffers(struct uacce_queue *q,
struct vm_area_struct *vma)
{
struct uacce_qfile_region *qfr = q->qfrs[UACCE_QFRT_SS];
struct uacce_dma_slice *slice = qfr->dma_list;
struct device *pdev = q->uacce->parent;
unsigned long vm_pgoff;
int ret = 0;
int i = 0;
/*
* dma_mmap_coherent() requires vm_pgoff as 0
* restore vm_pfoff to initial value for mmap()
*/
vm_pgoff = vma->vm_pgoff;
vma->vm_pgoff = 0;
while (i < slice[0].total_num && slice[i].size) {
vma->vm_end = vma->vm_start + slice[i].size;
ret = dma_mmap_coherent(pdev, vma, slice[i].kaddr,
slice[i].dma,
slice[i].size);
if (ret) {
dev_err(pdev, "dma mmap fail(dma=0x%llx,size=0x%llx)!\n",
slice[i].dma, slice[i].size);
goto DMA_MMAP_FAIL;
}
i++;
vma->vm_start = vma->vm_end;
}
/* System unmap_region will clean the results, we need do nothing */
DMA_MMAP_FAIL:
vma->vm_pgoff = vm_pgoff;
vma->vm_start = qfr->iova;
vma->vm_end = vma->vm_start + (qfr->nr_pages << PAGE_SHIFT);
return ret;
}
static int uacce_create_region(struct uacce_queue *q,
struct vm_area_struct *vma,
struct uacce_qfile_region *qfr)
{
int ret;
qfr->iova = vma->vm_start;
qfr->nr_pages = vma_pages(vma);
/* allocate memory */
ret = uacce_alloc_dma_buffers(q, vma);
if (ret)
return ret;
ret = uacce_mmap_dma_buffers(q, vma);
if (ret)
goto err_with_pages;
return ret;
err_with_pages:
uacce_free_dma_buffers(q);
return ret;
}
static int uacce_fops_mmap(struct file *filep, struct vm_area_struct *vma)
{
struct uacce_queue *q = filep->private_data;
......@@ -225,6 +650,9 @@ static int uacce_fops_mmap(struct file *filep, struct vm_area_struct *vma)
else
return -EINVAL;
if (q->qfrs[type])
return -EEXIST;
qfr = kzalloc(sizeof(*qfr), GFP_KERNEL);
if (!qfr)
return -ENOMEM;
......@@ -240,10 +668,7 @@ static int uacce_fops_mmap(struct file *filep, struct vm_area_struct *vma)
goto out_with_lock;
}
if (q->qfrs[type]) {
ret = -EEXIST;
goto out_with_lock;
}
q->qfrs[type] = qfr;
switch (type) {
case UACCE_QFRT_MMIO:
......@@ -258,12 +683,17 @@ static int uacce_fops_mmap(struct file *filep, struct vm_area_struct *vma)
goto out_with_lock;
break;
case UACCE_QFRT_SS:
ret = uacce_create_region(q, vma, qfr);
if (ret)
goto out_with_lock;
break;
default:
ret = -EINVAL;
goto out_with_lock;
}
q->qfrs[type] = qfr;
mutex_unlock(&q->mutex);
return ret;
......@@ -271,6 +701,7 @@ static int uacce_fops_mmap(struct file *filep, struct vm_area_struct *vma)
out_with_lock:
mutex_unlock(&q->mutex);
kfree(qfr);
q->qfrs[type] = NULL;
return ret;
}
......@@ -394,6 +825,9 @@ static ssize_t isolate_strategy_store(struct device *dev, struct device_attribut
if (val > UACCE_MAX_ERR_THRESHOLD)
return -EINVAL;
if (atomic_read(&uacce->ref))
return -EBUSY;
ret = uacce->ops->isolate_err_threshold_write(uacce, val);
if (ret)
return ret;
......@@ -401,24 +835,63 @@ static ssize_t isolate_strategy_store(struct device *dev, struct device_attribut
return count;
}
static ssize_t dev_state_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct uacce_device *uacce = to_uacce_device(dev);
return sysfs_emit(buf, "%d\n", uacce->ops->get_dev_state(uacce));
}
static ssize_t node_id_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct uacce_device *uacce = to_uacce_device(dev);
int node_id = -1;
#ifdef CONFIG_NUMA
node_id = uacce->parent->numa_node;
#endif
return sysfs_emit(buf, "%d\n", node_id);
}
static ssize_t numa_distance_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct uacce_device *uacce = to_uacce_device(dev);
int distance = 0;
#ifdef CONFIG_NUMA
distance = node_distance(uacce->parent->numa_node,
cpu_to_node(smp_processor_id()));
#endif
return sysfs_emit(buf, "%d\n", distance);
}
static DEVICE_ATTR_RO(api);
static DEVICE_ATTR_RO(flags);
static DEVICE_ATTR_RO(node_id);
static DEVICE_ATTR_RO(available_instances);
static DEVICE_ATTR_RO(algorithms);
static DEVICE_ATTR_RO(region_mmio_size);
static DEVICE_ATTR_RO(region_dus_size);
static DEVICE_ATTR_RO(isolate);
static DEVICE_ATTR_RW(isolate_strategy);
static DEVICE_ATTR_RO(dev_state);
static DEVICE_ATTR_RO(numa_distance);
static struct attribute *uacce_dev_attrs[] = {
&dev_attr_api.attr,
&dev_attr_flags.attr,
&dev_attr_node_id.attr,
&dev_attr_available_instances.attr,
&dev_attr_algorithms.attr,
&dev_attr_region_mmio_size.attr,
&dev_attr_region_dus_size.attr,
&dev_attr_isolate.attr,
&dev_attr_isolate_strategy.attr,
&dev_attr_dev_state.attr,
&dev_attr_numa_distance.attr,
NULL,
};
......@@ -504,14 +977,18 @@ static void uacce_disable_sva(struct uacce_device *uacce)
struct uacce_device *uacce_alloc(struct device *parent,
struct uacce_interface *interface)
{
unsigned int flags = interface->flags;
struct uacce_device *uacce;
unsigned int flags;
int ret;
if (!parent || !interface)
return ERR_PTR(-EINVAL);
uacce = kzalloc(sizeof(struct uacce_device), GFP_KERNEL);
if (!uacce)
return ERR_PTR(-ENOMEM);
flags = interface->flags;
flags = uacce_enable_sva(parent, flags);
uacce->parent = parent;
......@@ -531,7 +1008,10 @@ struct uacce_device *uacce_alloc(struct device *parent,
uacce->dev.groups = uacce_dev_groups;
uacce->dev.parent = uacce->parent;
uacce->dev.release = uacce_release;
dev_set_name(&uacce->dev, "%s-%d", interface->name, uacce->dev_id);
dev_set_name(&uacce->dev, "%s-%u", interface->name, uacce->dev_id);
if (flags & UACCE_DEV_NOIOMMU)
dev_warn(&uacce->dev, "register to noiommu mode, it's not safe for kernel\n");
return uacce;
......@@ -626,8 +1106,12 @@ static int __init uacce_init(void)
ret = alloc_chrdev_region(&uacce_devt, 0, MINORMASK, UACCE_NAME);
if (ret)
class_destroy(uacce_class);
goto destroy_class;
return 0;
destroy_class:
class_destroy(uacce_class);
return ret;
}
......
......@@ -8,6 +8,7 @@
#include <linux/iopoll.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/uacce.h>
#define QM_QNUM_V1 4096
#define QM_QNUM_V2 1024
......@@ -360,7 +361,9 @@ struct hisi_qm {
struct work_struct cmd_process;
const char *algs;
bool use_uacce;
bool use_sva;
bool use_iommu;
resource_size_t phys_base;
resource_size_t db_phys_base;
......@@ -378,6 +381,7 @@ struct hisi_qp_status {
u16 cq_head;
bool cqc_phase;
atomic_t flags;
atomic_t complete_task;
};
struct hisi_qp_ops {
......@@ -468,7 +472,7 @@ static inline int mode_set(const char *val, const struct kernel_param *kp)
return -EINVAL;
ret = kstrtou32(val, 10, &n);
if (ret != 0 || (n != UACCE_MODE_SVA &&
if (ret != 0 || (n != UACCE_MODE_NOIOMMU && n != UACCE_MODE_SVA &&
n != UACCE_MODE_NOUACCE))
return -EINVAL;
......@@ -486,6 +490,7 @@ static inline void hisi_qm_init_list(struct hisi_qm_list *qm_list)
mutex_init(&qm_list->lock);
}
int qm_register_uacce(struct hisi_qm *qm);
int hisi_qm_init(struct hisi_qm *qm);
void hisi_qm_uninit(struct hisi_qm *qm);
int hisi_qm_start(struct hisi_qm *qm);
......
......@@ -3,22 +3,45 @@
#define _LINUX_UACCE_H
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/fs.h>
#include <linux/list.h>
#include <linux/iommu.h>
#include <uapi/misc/uacce/uacce.h>
#define UACCE_NAME "uacce"
#define UACCE_MAX_REGION 2
#define UACCE_MAX_REGION 3
#define UACCE_MAX_NAME_SIZE 64
#define UACCE_MAX_ERR_THRESHOLD 65535
struct uacce_queue;
struct uacce_device;
struct uacce_err_isolate {
u32 hw_err_isolate_hz; /* user cfg freq which triggers isolation */
atomic_t is_isolate;
};
struct uacce_dma_slice {
void *kaddr; /* kernel address for ss */
dma_addr_t dma; /* dma address, if created by dma api */
u64 size; /* Size of this dma slice */
u32 total_num; /* Total slices in this dma list */
};
/**
* struct uacce_qfile_region - structure of queue file region
* @type: type of the region
*/
struct uacce_qfile_region {
enum uacce_qfrt type;
unsigned long iova; /* iova share between user and device space */
unsigned long nr_pages;
int prot;
unsigned int flags;
struct list_head qs; /* qs sharing the same region, for ss */
void *kaddr; /* kernel address for dko */
struct uacce_dma_slice *dma_list;
};
/**
......@@ -29,11 +52,14 @@ struct uacce_qfile_region {
* @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
* @ioctl: ioctl for user space users of the queue
* @get_isolate_state: get the device state after set the isolate strategy
* @isolate_err_threshold_write: stored the isolate error threshold to the device
* @isolate_err_threshold_read: read the isolate error threshold value from the device
* @reset: reset the WD device
* @reset_queue: reset the queue
*/
struct uacce_ops {
int (*get_available_instances)(struct uacce_device *uacce);
......@@ -42,6 +68,7 @@ struct uacce_ops {
void (*put_queue)(struct uacce_queue *q);
int (*start_queue)(struct uacce_queue *q);
void (*stop_queue)(struct uacce_queue *q);
void (*dump_queue)(const 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);
......@@ -50,6 +77,7 @@ struct uacce_ops {
enum uacce_dev_state (*get_isolate_state)(struct uacce_device *uacce);
int (*isolate_err_threshold_write)(struct uacce_device *uacce, u32 num);
u32 (*isolate_err_threshold_read)(struct uacce_device *uacce);
enum uacce_dev_state (*get_dev_state)(struct uacce_device *uacce);
};
/**
......@@ -65,6 +93,7 @@ struct uacce_interface {
};
enum uacce_dev_state {
UACCE_DEV_ERR = -1,
UACCE_DEV_NORMAL,
UACCE_DEV_ISOLATE,
};
......@@ -89,11 +118,14 @@ enum uacce_q_state {
*/
struct uacce_queue {
struct uacce_device *uacce;
u32 flags;
atomic_t status;
void *priv;
wait_queue_head_t wait;
struct list_head list;
struct uacce_qfile_region *qfrs[UACCE_MAX_REGION];
struct mutex mutex;
struct file *filep;
enum uacce_q_state state;
u32 pasid;
struct iommu_sva *handle;
......@@ -114,11 +146,13 @@ struct uacce_queue {
* @mutex: protects uacce operation
* @priv: private pointer of the uacce
* @queues: list of queues
* @ref: reference of the uacce
* @inode: core vfs
*/
struct uacce_device {
const char *algs;
const char *api_ver;
int status;
const struct uacce_ops *ops;
unsigned long qf_pg_num[UACCE_MAX_REGION];
struct device *parent;
......@@ -129,6 +163,8 @@ struct uacce_device {
struct device dev;
struct mutex mutex;
void *priv;
atomic_t ref;
struct uacce_err_isolate *isolate;
struct list_head queues;
struct inode *inode;
};
......@@ -139,7 +175,8 @@ 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);
struct uacce_device *dev_to_uacce(struct device *dev);
void uacce_wake_up(struct uacce_queue *q);
#else /* CONFIG_UACCE */
static inline
......@@ -156,6 +193,11 @@ static inline int uacce_register(struct uacce_device *uacce)
static inline void uacce_remove(struct uacce_device *uacce) {}
static inline struct uacce_device *dev_to_uacce(struct device *dev)
{
return NULL;
}
static inline void uacce_wake_up(struct uacce_queue *q) {}
#endif /* CONFIG_UACCE */
#endif /* _LINUX_UACCE_H */
......@@ -3,6 +3,33 @@
#define _UAPI_HISI_QM_H
#include <linux/types.h>
#define QM_CQE_SIZE 16
/* default queue depth for sq/cq/eq */
#define QM_Q_DEPTH 1024
/* page number for queue file region */
#define QM_DOORBELL_PAGE_NR 1
#define QM_DKO_PAGE_NR 4
#define QM_DUS_PAGE_NR 36
#define QM_DOORBELL_PG_START 0
#define QM_DKO_PAGE_START (QM_DOORBELL_PG_START + QM_DOORBELL_PAGE_NR)
#define QM_DUS_PAGE_START (QM_DKO_PAGE_START + QM_DKO_PAGE_NR)
#define QM_SS_PAGE_START (QM_DUS_PAGE_START + QM_DUS_PAGE_NR)
#define QM_DOORBELL_OFFSET 0x340
#define QM_V2_DOORBELL_OFFSET 0x1000
struct cqe {
__le32 rsvd0;
__le16 cmd_id;
__le16 rsvd1;
__le16 sq_head;
__le16 sq_num;
__le16 rsvd2;
__le16 w7;
};
/**
* struct hisi_qp_ctx - User data for hisi qp.
......
/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */
/* SPDX-License-Identifier: GPL-2.0-or-later WITH Linux-syscall-note */
/* Copyright (c) 2018-2019 HiSilicon Limited. */
#ifndef _UAPIUUACCE_H
#define _UAPIUUACCE_H
#include <linux/types.h>
#include <linux/ioctl.h>
#define UACCE_CLASS_NAME "uacce"
/*
* UACCE_CMD_START_Q: Start queue
*/
......@@ -17,22 +19,57 @@
*/
#define UACCE_CMD_PUT_Q _IO('W', 1)
/*
* UACCE Device flags:
* UACCE_DEV_SVA: Shared Virtual Addresses
* Support PASID
* Support device page faults (PCI PRI or SMMU Stall)
#define UACCE_CMD_SHARE_SVAS _IO('W', 2)
#define UACCE_CMD_GET_SS_DMA _IOR('W', 3, unsigned long)
/**
* UACCE Device Attributes:
*
* NOIOMMU: the device has no IOMMU support
* can do ssva, but no map to the dev
* IOMMU: the device has IOMMU support and enable __IOMMU_DOMAIN_PAGING
* PASID: the device has IOMMU which support PASID setting
* can do ssva, mapped to dev per process
* FAULT_FROM_DEV: the device has IOMMU which can do page fault request
* no need for ssva, should be used with PASID
* KMAP_DUS: map the Device user-shared space to kernel
* DRVMAP_DUS: Driver self-maintain its DUS
* SVA: full function device
* SHARE_DOMAIN: no PASID, can do ssva only for one process and the kernel
*/
#define UACCE_DEV_SVA BIT(0)
#define UACCE_DEV_NOIOMMU BIT(1)
#define UACCE_DEV_IOMMU BIT(7)
/* uacce mode of the driver */
#define UACCE_MODE_NOUACCE 0 /* don't use uacce */
#define UACCE_MODE_SVA 1 /* use uacce sva mode */
#define UACCE_MODE_NOIOMMU 2 /* use uacce noiommu mode */
#define UACCE_API_VER_NOIOMMU_SUBFIX "_noiommu"
#define UACCE_QFR_NA ((unsigned long)-1)
/**
* enum uacce_qfrt: queue file region type
* @UACCE_QFRT_MMIO: device mmio region
* @UACCE_QFRT_DUS: device user share region
* @UACCE_QFRT_SS: static share memory(no-sva)
*/
enum uacce_qfrt {
UACCE_QFRT_MMIO = 0,
UACCE_QFRT_DUS = 1,
UACCE_QFRT_MMIO = 0, /* device mmio region */
UACCE_QFRT_DUS, /* device user share */
UACCE_QFRT_SS, /* static share memory */
UACCE_QFRT_MAX,
};
#define UACCE_QFRT_INVALID UACCE_QFRT_MAX
/* Pass DMA SS region slice size by granularity 64KB */
#define UACCE_GRAN_SIZE 0x10000ull
#define UACCE_GRAN_SHIFT 16
#define UACCE_GRAN_NUM_MASK 0xfffull
#endif
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册