Commit 9e00df71 authored by Zhangfei Gao's avatar Zhangfei Gao Committed by Herbert Xu

crypto: hisilicon - register zip engine to uacce

Register qm to uacce framework for user crypto driver
Reviewed-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Reviewed-by: default avatarJonathan Cameron <Jonathan.Cameron@huawei.com>
Signed-off-by: default avatarZhangfei Gao <zhangfei.gao@linaro.org>
Signed-off-by: default avatarZhou Wang <wangzhou1@hisilicon.com>
Signed-off-by: default avatarHerbert Xu <herbert@gondor.apana.org.au>
parent 18bead70
...@@ -9,6 +9,9 @@ ...@@ -9,6 +9,9 @@
#include <linux/log2.h> #include <linux/log2.h>
#include <linux/seq_file.h> #include <linux/seq_file.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/uacce.h>
#include <linux/uaccess.h>
#include <uapi/misc/uacce/hisi_qm.h>
#include "qm.h" #include "qm.h"
/* eq/aeq irq enable */ /* eq/aeq irq enable */
...@@ -466,9 +469,14 @@ static void qm_cq_head_update(struct hisi_qp *qp) ...@@ -466,9 +469,14 @@ static void qm_cq_head_update(struct hisi_qp *qp)
static void qm_poll_qp(struct hisi_qp *qp, struct hisi_qm *qm) static void qm_poll_qp(struct hisi_qp *qp, struct hisi_qm *qm)
{ {
struct qm_cqe *cqe = qp->cqe + qp->qp_status.cq_head; if (qp->event_cb) {
qp->event_cb(qp);
return;
}
if (qp->req_cb) { if (qp->req_cb) {
struct qm_cqe *cqe = qp->cqe + qp->qp_status.cq_head;
while (QM_CQE_PHASE(cqe) == qp->qp_status.cqc_phase) { while (QM_CQE_PHASE(cqe) == qp->qp_status.cqc_phase) {
dma_rmb(); dma_rmb();
qp->req_cb(qp, qp->sqe + qm->sqe_size * qp->req_cb(qp, qp->sqe + qm->sqe_size *
...@@ -1273,7 +1281,7 @@ static int qm_qp_ctx_cfg(struct hisi_qp *qp, int qp_id, int pasid) ...@@ -1273,7 +1281,7 @@ static int qm_qp_ctx_cfg(struct hisi_qp *qp, int qp_id, int pasid)
* @qp: The qp we want to start to run. * @qp: The qp we want to start to run.
* @arg: Accelerator specific argument. * @arg: Accelerator specific argument.
* *
* After this function, qp can receive request from user. Return qp_id if * After this function, qp can receive request from user. Return 0 if
* successful, Return -EBUSY if failed. * successful, Return -EBUSY if failed.
*/ */
int hisi_qm_start_qp(struct hisi_qp *qp, unsigned long arg) int hisi_qm_start_qp(struct hisi_qp *qp, unsigned long arg)
...@@ -1318,7 +1326,7 @@ int hisi_qm_start_qp(struct hisi_qp *qp, unsigned long arg) ...@@ -1318,7 +1326,7 @@ int hisi_qm_start_qp(struct hisi_qp *qp, unsigned long arg)
dev_dbg(dev, "queue %d started\n", qp_id); dev_dbg(dev, "queue %d started\n", qp_id);
return qp_id; return 0;
} }
EXPORT_SYMBOL_GPL(hisi_qm_start_qp); EXPORT_SYMBOL_GPL(hisi_qm_start_qp);
...@@ -1399,6 +1407,214 @@ static void hisi_qm_cache_wb(struct hisi_qm *qm) ...@@ -1399,6 +1407,214 @@ 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);
}
static int hisi_qm_get_available_instances(struct uacce_device *uacce)
{
int i, ret;
struct hisi_qm *qm = uacce->priv;
read_lock(&qm->qps_lock);
for (i = 0, ret = 0; i < qm->qp_num; i++)
if (!qm->qp_array[i])
ret++;
read_unlock(&qm->qps_lock);
return ret;
}
static int hisi_qm_uacce_get_queue(struct uacce_device *uacce,
unsigned long arg,
struct uacce_queue *q)
{
struct hisi_qm *qm = uacce->priv;
struct hisi_qp *qp;
u8 alg_type = 0;
qp = hisi_qm_create_qp(qm, alg_type);
if (IS_ERR(qp))
return PTR_ERR(qp);
q->priv = qp;
q->uacce = uacce;
qp->uacce_q = q;
qp->event_cb = qm_qp_event_notifier;
qp->pasid = arg;
return 0;
}
static void hisi_qm_uacce_put_queue(struct uacce_queue *q)
{
struct hisi_qp *qp = q->priv;
hisi_qm_cache_wb(qp->qm);
hisi_qm_release_qp(qp);
}
/* map sq/cq/doorbell to user space */
static int hisi_qm_uacce_mmap(struct uacce_queue *q,
struct vm_area_struct *vma,
struct uacce_qfile_region *qfr)
{
struct hisi_qp *qp = q->priv;
struct hisi_qm *qm = qp->qm;
size_t sz = vma->vm_end - vma->vm_start;
struct pci_dev *pdev = qm->pdev;
struct device *dev = &pdev->dev;
unsigned long vm_pgoff;
int ret;
switch (qfr->type) {
case UACCE_QFRT_MMIO:
if (qm->ver == QM_HW_V2) {
if (sz > PAGE_SIZE * (QM_DOORBELL_PAGE_NR +
QM_DOORBELL_SQ_CQ_BASE_V2 / PAGE_SIZE))
return -EINVAL;
} else {
if (sz > PAGE_SIZE * QM_DOORBELL_PAGE_NR)
return -EINVAL;
}
vma->vm_flags |= VM_IO;
return remap_pfn_range(vma, vma->vm_start,
qm->phys_base >> PAGE_SHIFT,
sz, pgprot_noncached(vma->vm_page_prot));
case UACCE_QFRT_DUS:
if (sz != qp->qdma.size)
return -EINVAL;
/*
* 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;
ret = dma_mmap_coherent(dev, vma, qp->qdma.va,
qp->qdma.dma, sz);
vma->vm_pgoff = vm_pgoff;
return ret;
default:
return -EINVAL;
}
}
static int hisi_qm_uacce_start_queue(struct uacce_queue *q)
{
struct hisi_qp *qp = q->priv;
return hisi_qm_start_qp(qp, qp->pasid);
}
static void hisi_qm_uacce_stop_queue(struct uacce_queue *q)
{
hisi_qm_stop_qp(q->priv);
}
static int qm_set_sqctype(struct uacce_queue *q, u16 type)
{
struct hisi_qm *qm = q->uacce->priv;
struct hisi_qp *qp = q->priv;
write_lock(&qm->qps_lock);
qp->alg_type = type;
write_unlock(&qm->qps_lock);
return 0;
}
static long hisi_qm_uacce_ioctl(struct uacce_queue *q, unsigned int cmd,
unsigned long arg)
{
struct hisi_qp *qp = q->priv;
struct hisi_qp_ctx qp_ctx;
if (cmd == UACCE_CMD_QM_SET_QP_CTX) {
if (copy_from_user(&qp_ctx, (void __user *)arg,
sizeof(struct hisi_qp_ctx)))
return -EFAULT;
if (qp_ctx.qc_type != 0 && qp_ctx.qc_type != 1)
return -EINVAL;
qm_set_sqctype(q, qp_ctx.qc_type);
qp_ctx.id = qp->qp_id;
if (copy_to_user((void __user *)arg, &qp_ctx,
sizeof(struct hisi_qp_ctx)))
return -EFAULT;
} else {
return -EINVAL;
}
return 0;
}
static const struct uacce_ops uacce_qm_ops = {
.get_available_instances = hisi_qm_get_available_instances,
.get_queue = hisi_qm_uacce_get_queue,
.put_queue = hisi_qm_uacce_put_queue,
.start_queue = hisi_qm_uacce_start_queue,
.stop_queue = hisi_qm_uacce_stop_queue,
.mmap = hisi_qm_uacce_mmap,
.ioctl = hisi_qm_uacce_ioctl,
};
static int qm_alloc_uacce(struct hisi_qm *qm)
{
struct pci_dev *pdev = qm->pdev;
struct uacce_device *uacce;
unsigned long mmio_page_nr;
unsigned long dus_page_nr;
struct uacce_interface interface = {
.flags = UACCE_DEV_SVA,
.ops = &uacce_qm_ops,
};
strncpy(interface.name, pdev->driver->name, sizeof(interface.name));
uacce = uacce_alloc(&pdev->dev, &interface);
if (IS_ERR(uacce))
return PTR_ERR(uacce);
if (uacce->flags & UACCE_DEV_SVA) {
qm->use_sva = true;
} else {
/* only consider sva case */
uacce_remove(uacce);
qm->uacce = NULL;
return -EINVAL;
}
uacce->is_vf = pdev->is_virtfn;
uacce->priv = qm;
uacce->algs = qm->algs;
if (qm->ver == QM_HW_V1) {
mmio_page_nr = QM_DOORBELL_PAGE_NR;
uacce->api_ver = HISI_QM_API_VER_BASE;
} else {
mmio_page_nr = QM_DOORBELL_PAGE_NR +
QM_DOORBELL_SQ_CQ_BASE_V2 / PAGE_SIZE;
uacce->api_ver = HISI_QM_API_VER2_BASE;
}
dus_page_nr = (PAGE_SIZE - 1 + qm->sqe_size * QM_Q_DEPTH +
sizeof(struct qm_cqe) * QM_Q_DEPTH) >> PAGE_SHIFT;
uacce->qf_pg_num[UACCE_QFRT_MMIO] = mmio_page_nr;
uacce->qf_pg_num[UACCE_QFRT_DUS] = dus_page_nr;
qm->uacce = uacce;
return 0;
}
/** /**
* hisi_qm_get_free_qp_num() - Get free number of qp in qm. * hisi_qm_get_free_qp_num() - Get free number of qp in qm.
* @qm: The qm which want to get free qp. * @qm: The qm which want to get free qp.
...@@ -1441,10 +1657,14 @@ int hisi_qm_init(struct hisi_qm *qm) ...@@ -1441,10 +1657,14 @@ int hisi_qm_init(struct hisi_qm *qm)
return -EINVAL; return -EINVAL;
} }
ret = qm_alloc_uacce(qm);
if (ret < 0)
dev_warn(&pdev->dev, "fail to alloc uacce (%d)\n", ret);
ret = pci_enable_device_mem(pdev); ret = pci_enable_device_mem(pdev);
if (ret < 0) { if (ret < 0) {
dev_err(&pdev->dev, "Failed to enable device mem!\n"); dev_err(&pdev->dev, "Failed to enable device mem!\n");
return ret; goto err_remove_uacce;
} }
ret = pci_request_mem_regions(pdev, qm->dev_name); ret = pci_request_mem_regions(pdev, qm->dev_name);
...@@ -1453,8 +1673,9 @@ int hisi_qm_init(struct hisi_qm *qm) ...@@ -1453,8 +1673,9 @@ int hisi_qm_init(struct hisi_qm *qm)
goto err_disable_pcidev; goto err_disable_pcidev;
} }
qm->io_base = ioremap(pci_resource_start(pdev, PCI_BAR_2), qm->phys_base = pci_resource_start(pdev, PCI_BAR_2);
pci_resource_len(qm->pdev, PCI_BAR_2)); qm->phys_size = pci_resource_len(qm->pdev, PCI_BAR_2);
qm->io_base = ioremap(qm->phys_base, qm->phys_size);
if (!qm->io_base) { if (!qm->io_base) {
ret = -EIO; ret = -EIO;
goto err_release_mem_regions; goto err_release_mem_regions;
...@@ -1497,6 +1718,9 @@ int hisi_qm_init(struct hisi_qm *qm) ...@@ -1497,6 +1718,9 @@ int hisi_qm_init(struct hisi_qm *qm)
pci_release_mem_regions(pdev); pci_release_mem_regions(pdev);
err_disable_pcidev: err_disable_pcidev:
pci_disable_device(pdev); pci_disable_device(pdev);
err_remove_uacce:
uacce_remove(qm->uacce);
qm->uacce = NULL;
return ret; return ret;
} }
...@@ -1513,6 +1737,9 @@ void hisi_qm_uninit(struct hisi_qm *qm) ...@@ -1513,6 +1737,9 @@ void hisi_qm_uninit(struct hisi_qm *qm)
struct pci_dev *pdev = qm->pdev; struct pci_dev *pdev = qm->pdev;
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
uacce_remove(qm->uacce);
qm->uacce = NULL;
if (qm->use_dma_api && qm->qdma.va) { if (qm->use_dma_api && qm->qdma.va) {
hisi_qm_cache_wb(qm); hisi_qm_cache_wb(qm);
dma_free_coherent(dev, qm->qdma.size, dma_free_coherent(dev, qm->qdma.size,
......
...@@ -77,6 +77,9 @@ ...@@ -77,6 +77,9 @@
#define HISI_ACC_SGL_SGE_NR_MAX 255 #define HISI_ACC_SGL_SGE_NR_MAX 255
/* page number for queue file region */
#define QM_DOORBELL_PAGE_NR 1
enum qp_state { enum qp_state {
QP_STOP, QP_STOP,
}; };
...@@ -180,7 +183,12 @@ struct hisi_qm { ...@@ -180,7 +183,12 @@ struct hisi_qm {
u32 error_mask; u32 error_mask;
u32 msi_mask; u32 msi_mask;
const char *algs;
bool use_dma_api; bool use_dma_api;
bool use_sva;
resource_size_t phys_base;
resource_size_t phys_size;
struct uacce_device *uacce;
}; };
struct hisi_qp_status { struct hisi_qp_status {
...@@ -210,10 +218,13 @@ struct hisi_qp { ...@@ -210,10 +218,13 @@ struct hisi_qp {
struct hisi_qp_ops *hw_ops; struct hisi_qp_ops *hw_ops;
void *qp_ctx; void *qp_ctx;
void (*req_cb)(struct hisi_qp *qp, void *data); void (*req_cb)(struct hisi_qp *qp, void *data);
void (*event_cb)(struct hisi_qp *qp);
struct work_struct work; struct work_struct work;
struct workqueue_struct *wq; struct workqueue_struct *wq;
struct hisi_qm *qm; struct hisi_qm *qm;
u16 pasid;
struct uacce_queue *uacce_q;
}; };
int hisi_qm_init(struct hisi_qm *qm); int hisi_qm_init(struct hisi_qm *qm);
......
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include <linux/pci.h> #include <linux/pci.h>
#include <linux/seq_file.h> #include <linux/seq_file.h>
#include <linux/topology.h> #include <linux/topology.h>
#include <linux/uacce.h>
#include "zip.h" #include "zip.h"
#define PCI_DEVICE_ID_ZIP_PF 0xa250 #define PCI_DEVICE_ID_ZIP_PF 0xa250
...@@ -354,8 +355,14 @@ static void hisi_zip_set_user_domain_and_cache(struct hisi_zip *hisi_zip) ...@@ -354,8 +355,14 @@ static void hisi_zip_set_user_domain_and_cache(struct hisi_zip *hisi_zip)
writel(AXUSER_BASE, base + HZIP_BD_RUSER_32_63); writel(AXUSER_BASE, base + HZIP_BD_RUSER_32_63);
writel(AXUSER_BASE, base + HZIP_SGL_RUSER_32_63); writel(AXUSER_BASE, base + HZIP_SGL_RUSER_32_63);
writel(AXUSER_BASE, base + HZIP_BD_WUSER_32_63); writel(AXUSER_BASE, base + HZIP_BD_WUSER_32_63);
if (hisi_zip->qm.use_sva) {
writel(AXUSER_BASE | AXUSER_SSV, base + HZIP_DATA_RUSER_32_63);
writel(AXUSER_BASE | AXUSER_SSV, base + HZIP_DATA_WUSER_32_63);
} else {
writel(AXUSER_BASE, base + HZIP_DATA_RUSER_32_63); writel(AXUSER_BASE, base + HZIP_DATA_RUSER_32_63);
writel(AXUSER_BASE, base + HZIP_DATA_WUSER_32_63); writel(AXUSER_BASE, base + HZIP_DATA_WUSER_32_63);
}
/* let's open all compression/decompression cores */ /* let's open all compression/decompression cores */
writel(DECOMP_CHECK_ENABLE | ALL_COMP_DECOMP_EN, writel(DECOMP_CHECK_ENABLE | ALL_COMP_DECOMP_EN,
...@@ -842,6 +849,7 @@ static int hisi_zip_probe(struct pci_dev *pdev, const struct pci_device_id *id) ...@@ -842,6 +849,7 @@ static int hisi_zip_probe(struct pci_dev *pdev, const struct pci_device_id *id)
qm->pdev = pdev; qm->pdev = pdev;
qm->ver = rev_id; qm->ver = rev_id;
qm->algs = "zlib\ngzip";
qm->sqe_size = HZIP_SQE_SIZE; qm->sqe_size = HZIP_SQE_SIZE;
qm->dev_name = hisi_zip_name; qm->dev_name = hisi_zip_name;
qm->fun_type = (pdev->device == PCI_DEVICE_ID_ZIP_PF) ? QM_HW_PF : qm->fun_type = (pdev->device == PCI_DEVICE_ID_ZIP_PF) ? QM_HW_PF :
...@@ -885,6 +893,12 @@ static int hisi_zip_probe(struct pci_dev *pdev, const struct pci_device_id *id) ...@@ -885,6 +893,12 @@ static int hisi_zip_probe(struct pci_dev *pdev, const struct pci_device_id *id)
hisi_zip_add_to_list(hisi_zip); hisi_zip_add_to_list(hisi_zip);
if (qm->uacce) {
ret = uacce_register(qm->uacce);
if (ret)
goto err_qm_uninit;
}
if (qm->fun_type == QM_HW_PF && vfs_num > 0) { if (qm->fun_type == QM_HW_PF && vfs_num > 0) {
ret = hisi_zip_sriov_enable(pdev, vfs_num); ret = hisi_zip_sriov_enable(pdev, vfs_num);
if (ret < 0) if (ret < 0)
......
/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */
#ifndef _UAPI_HISI_QM_H
#define _UAPI_HISI_QM_H
#include <linux/types.h>
/**
* struct hisi_qp_ctx - User data for hisi qp.
* @id: qp_index return to user space
* @qc_type: Accelerator algorithm type
*/
struct hisi_qp_ctx {
__u16 id;
__u16 qc_type;
};
#define HISI_QM_API_VER_BASE "hisi_qm_v1"
#define HISI_QM_API_VER2_BASE "hisi_qm_v2"
/* UACCE_CMD_QM_SET_QP_CTX: Set qp algorithm type */
#define UACCE_CMD_QM_SET_QP_CTX _IOWR('H', 10, struct hisi_qp_ctx)
#endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment