driver: update hisilicon hardware crypto engine

keep the hisilicon crypto driver up to 1.3.11, autoprobe
the modules when hardware enabled.

Signed-off-by: sumiyawang <sumiyawang@tencent.com>
This commit is contained in:
sumiyawang 2023-01-10 20:12:07 +08:00 committed by Jianping Liu
parent fa3c010699
commit a0fc351741
47 changed files with 15534 additions and 5938 deletions

View File

@ -1,39 +1,2 @@
# SPDX-License-Identifier: GPL-2.0
config CRYPTO_DEV_HISI_SEC
tristate "Support for Hisilicon SEC crypto block cipher accelerator"
select CRYPTO_BLKCIPHER
select CRYPTO_ALGAPI
select CRYPTO_LIB_DES
select SG_SPLIT
depends on ARM64 || COMPILE_TEST
depends on HAS_IOMEM
help
Support for Hisilicon SEC Engine in Hip06 and Hip07
To compile this as a module, choose M here: the module
will be called hisi_sec.
config CRYPTO_DEV_HISI_QM
tristate
depends on ARM64 && PCI && PCI_MSI
select NEED_SG_DMA_LENGTH
help
HiSilicon accelerator engines use a common queue management
interface. Specific engine driver may use this module.
config CRYPTO_HISI_SGL
tristate
depends on ARM64
help
HiSilicon accelerator engines use a common hardware scatterlist
interface for data format. Specific engine driver may use this
module.
config CRYPTO_DEV_HISI_ZIP
tristate "Support for HiSilicon ZIP accelerator"
depends on ARM64 && PCI && PCI_MSI
select CRYPTO_DEV_HISI_QM
select CRYPTO_HISI_SGL
help
Support for HiSilicon ZIP Driver
source "drivers/crypto/hisilicon/hisilicon/Kconfig"
source "drivers/crypto/hisilicon/uacce/Kconfig"

View File

@ -1,5 +1,2 @@
# SPDX-License-Identifier: GPL-2.0
obj-$(CONFIG_CRYPTO_DEV_HISI_SEC) += sec/
obj-$(CONFIG_CRYPTO_DEV_HISI_QM) += qm.o
obj-$(CONFIG_CRYPTO_HISI_SGL) += sgl.o
obj-$(CONFIG_CRYPTO_DEV_HISI_ZIP) += zip/
obj-m += uacce/
obj-m += hisilicon/

View File

@ -0,0 +1,46 @@
# SPDX-License-Identifier: GPL-2.0
config CRYPTO_DEV_HISI_QM
tristate
depends on ARM64 && PCI
config CRYPTO_QM_UACCE
bool "enable UACCE support for all acceleartor with Hisi QM"
depends on CRYPTO_DEV_HISI_QM
select UACCE
help
Support UACCE interface in Hisi QM.
config CRYPTO_DEV_HISI_ZIP
tristate "Support for HISI ZIP Driver"
depends on ARM64 && ACPI
select CRYPTO_DEV_HISI_QM
help
Support for HiSilicon HIP08 ZIP Driver.
config CRYPTO_DEV_HISI_HPRE
tristate "Support for HISI HPRE accelerator"
depends on PCI && PCI_MSI && ACPI
depends on ARM64
select CRYPTO_DEV_HISI_QM
select CRYPTO_DH
select CRYPTO_RSA
help
Support for HiSilicon HPRE(High Performance RSA Engine)
accelerator, which can accelerate RSA and DH algorithms.
config CRYPTO_DEV_HISI_SEC2
tristate "Support for HISI SEC Driver"
depends on ARM64 && ACPI
select CRYPTO_DEV_HISI_QM
select CRYPTO_BLKCIPHER
select CRYPTO_ALGAPI
help
Support for HiSilicon HIP09 SEC Driver.
config CRYPTO_DEV_HISI_RDE
tristate "Support for HISI RDE Driver"
depends on ARM64 && ACPI
select CRYPTO_DEV_HISI_QM
help
Support for HiSilicon HIP09 RDE Driver.

View File

@ -0,0 +1,7 @@
# SPDX-License-Identifier: GPL-2.0
obj-$(CONFIG_CRYPTO_DEV_HISI_QM) += hisi_qm.o
hisi_qm-objs = qm.o sgl.o
obj-$(CONFIG_CRYPTO_DEV_HISI_ZIP) += zip/
obj-$(CONFIG_CRYPTO_DEV_HISI_HPRE) += hpre/
obj-$(CONFIG_CRYPTO_DEV_HISI_SEC2) += sec2/
obj-$(CONFIG_CRYPTO_DEV_HISI_RDE) += rde/

View File

@ -0,0 +1,2 @@
obj-$(CONFIG_CRYPTO_DEV_HISI_HPRE) += hisi_hpre.o
hisi_hpre-objs = hpre_main.o hpre_crypto.o

View File

@ -0,0 +1,96 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/* Copyright (c) 2019 HiSilicon Limited. */
#ifndef __HISI_HPRE_H
#define __HISI_HPRE_H
#include <linux/list.h>
#include "../qm.h"
#define HPRE_SQE_SIZE sizeof(struct hpre_sqe)
#define HPRE_PF_DEF_Q_NUM 256
#define HPRE_PF_DEF_Q_BASE 0
enum {
HPRE_CLUSTER0,
HPRE_CLUSTER1,
HPRE_CLUSTER2,
HPRE_CLUSTER3,
HPRE_CLUSTERS_NUM,
};
enum hpre_ctrl_dbgfs_file {
HPRE_CURRENT_QM,
HPRE_CLEAR_ENABLE,
HPRE_CLUSTER_CTRL,
HPRE_DEBUG_FILE_NUM,
};
enum hpre_dfx_dbgfs_file {
HPRE_SEND_CNT,
HPRE_RECV_CNT,
HPRE_SEND_FAIL_CNT,
HPRE_SEND_BUSY_CNT,
HPRE_OVER_THRHLD_CNT,
HPRE_OVERTIME_THRHLD,
HPRE_INVALID_REQ_CNT,
HPRE_DFX_FILE_NUM
};
#define HPRE_DEBUGFS_FILE_NUM (HPRE_DEBUG_FILE_NUM + HPRE_CLUSTERS_NUM - 1)
struct hpre_debugfs_file {
int index;
enum hpre_ctrl_dbgfs_file type;
spinlock_t lock;
struct hpre_debug *debug;
};
struct hpre_dfx {
atomic64_t value;
enum hpre_dfx_dbgfs_file type;
};
/*
* One HPRE controller has one PF and multiple VFs, some global configurations
* which PF has need this structure.
* Just relevant for PF.
*/
struct hpre_debug {
struct hpre_dfx dfx[HPRE_DFX_FILE_NUM];
struct hpre_debugfs_file files[HPRE_DEBUGFS_FILE_NUM];
};
struct hpre {
struct hisi_qm qm;
struct hpre_debug debug;
};
enum hpre_alg_type {
HPRE_ALG_NC_NCRT = 0x0,
HPRE_ALG_NC_CRT = 0x1,
HPRE_ALG_KG_STD = 0x2,
HPRE_ALG_KG_CRT = 0x3,
HPRE_ALG_DH_G2 = 0x4,
HPRE_ALG_DH = 0x5,
};
struct hpre_sqe {
__le32 dw0;
__u8 task_len1;
__u8 task_len2;
__u8 mrttest_num;
__u8 resv1;
__le64 key;
__le64 in;
__le64 out;
__le16 tag;
__le16 resv2;
#define _HPRE_SQE_ALIGN_EXT 7
__le32 rsvd1[_HPRE_SQE_ALIGN_EXT];
};
struct hisi_qp *hpre_create_qp(void);
int hpre_algs_register(void);
void hpre_algs_unregister(void);
#endif

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,564 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/* Copyright (c) 2018-2019 HiSilicon Limited. */
#ifndef HISI_ACC_QM_H
#define HISI_ACC_QM_H
#include <linux/bitfield.h>
#include <linux/dmapool.h>
#include <linux/iopoll.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
#include "../include_linux/acc_compat.h"
#ifdef CONFIG_CRYPTO_QM_UACCE
#include "../include_linux/uacce.h"
#endif
#include "qm_usr_if.h"
#define QNUM_V1 4096
#define QNUM_V2 1024
#define QM_MAX_VFS_NUM_V2 63
/* qm user domain */
#define QM_ARUSER_M_CFG_1 0x100088
#define AXUSER_SNOOP_ENABLE BIT(30)
#define AXUSER_CMD_TYPE GENMASK(14, 12)
#define AXUSER_CMD_SMMU_NORMAL 1
#define AXUSER_NS BIT(6)
#define AXUSER_NO BIT(5)
#define AXUSER_FP BIT(4)
#define AXUSER_SSV BIT(0)
#define AXUSER_BASE (AXUSER_SNOOP_ENABLE | \
FIELD_PREP(AXUSER_CMD_TYPE, \
AXUSER_CMD_SMMU_NORMAL) | \
AXUSER_NS | AXUSER_NO | AXUSER_FP)
#define QM_ARUSER_M_CFG_ENABLE 0x100090
#define ARUSER_M_CFG_ENABLE 0xfffffffe
#define QM_AWUSER_M_CFG_1 0x100098
#define QM_AWUSER_M_CFG_ENABLE 0x1000a0
#define AWUSER_M_CFG_ENABLE 0xfffffffe
#define QM_WUSER_M_CFG_ENABLE 0x1000a8
#define WUSER_M_CFG_ENABLE 0xffffffff
/* qm cache */
#define QM_CACHE_CTL 0x100050
#define SQC_CACHE_ENABLE BIT(0)
#define CQC_CACHE_ENABLE BIT(1)
#define SQC_CACHE_WB_ENABLE BIT(4)
#define SQC_CACHE_WB_THRD GENMASK(10, 5)
#define CQC_CACHE_WB_ENABLE BIT(11)
#define CQC_CACHE_WB_THRD GENMASK(17, 12)
#define QM_AXI_M_CFG 0x1000ac
#define AXI_M_CFG 0xffff
#define QM_AXI_M_CFG_ENABLE 0x1000b0
#define AM_CFG_SINGLE_PORT_MAX_TRANS 0x300014
#define AXI_M_CFG_ENABLE 0xffffffff
#define QM_PEH_AXUSER_CFG 0x1000cc
#define QM_PEH_AXUSER_CFG_ENABLE 0x1000d0
#define PEH_AXUSER_CFG 0x400801
#define PEH_AXUSER_CFG_ENABLE 0xffffffff
#define QM_DFX_MB_CNT_VF 0x104010
#define QM_DFX_DB_CNT_VF 0x104020
#define QM_DFX_SQE_CNT_VF_SQN 0x104030
#define QM_DFX_CQE_CNT_VF_CQN 0x104040
#define QM_AXI_RRESP BIT(0)
#define QM_AXI_BRESP BIT(1)
#define QM_ECC_MBIT BIT(2)
#define QM_ECC_1BIT BIT(3)
#define QM_ACC_GET_TASK_TIMEOUT BIT(4)
#define QM_ACC_DO_TASK_TIMEOUT BIT(5)
#define QM_ACC_WB_NOT_READY_TIMEOUT BIT(6)
#define QM_SQ_CQ_VF_INVALID BIT(7)
#define QM_CQ_VF_INVALID BIT(8)
#define QM_SQ_VF_INVALID BIT(9)
#define QM_DB_TIMEOUT BIT(10)
#define QM_OF_FIFO_OF BIT(11)
#define QM_DB_RANDOM_INVALID BIT(12)
#define QM_BASE_NFE (QM_AXI_RRESP | QM_AXI_BRESP | QM_ECC_MBIT | \
QM_ACC_GET_TASK_TIMEOUT | QM_DB_TIMEOUT | \
QM_OF_FIFO_OF)
#define QM_BASE_CE QM_ECC_1BIT
#define HISI_ACC_SGL_SGE_NR_MAX 255
#define QM_DFX_QN_SHIFT 16
#define CURRENT_FUN_MASK GENMASK(5, 0)
#define CURRENT_Q_MASK GENMASK(31, 16)
#define SQE_ADDR_MASK GENMASK(7, 0)
#define PCI_BAR_2 2
enum qm_stop_reason {
QM_NORMAL,
QM_SOFT_RESET,
QM_FLR,
};
enum qm_state {
QM_INIT = 0,
QM_START,
QM_CLOSE,
QM_STOP,
};
enum qp_state {
QP_INIT = 1,
QP_START,
QP_STOP,
QP_CLOSE,
};
enum qm_hw_ver {
QM_HW_UNKNOWN = -1,
QM_HW_V1 = 0x20,
QM_HW_V2 = 0x21,
};
enum qm_fun_type {
QM_HW_PF,
QM_HW_VF,
};
enum qm_debug_file {
CURRENT_Q,
CLEAR_ENABLE,
QM_STATE,
DEBUG_FILE_NUM,
};
struct qm_dfx {
atomic64_t qm_err_irq_cnt;
atomic64_t aeq_irq_cnt;
atomic64_t abnormal_irq_cnt;
atomic64_t qp_err_cnt;
atomic64_t mb_err_cnt;
};
struct debugfs_file {
enum qm_debug_file index;
struct mutex lock;
struct qm_debug *debug;
};
struct qm_debug {
u32 sqe_mask_len;
u32 sqe_mask_offset;
u32 curr_qm_qp_num;
struct qm_dfx dfx;
struct dentry *debug_root;
struct dentry *qm_d;
struct debugfs_file files[DEBUG_FILE_NUM];
};
struct qm_cqe {
__le32 rsvd0;
__le16 cmd_id;
__le16 rsvd1;
__le16 sq_head;
__le16 sq_num;
__le16 rsvd2;
__le16 w7;
};
struct qm_eqe {
__le32 dw0;
};
struct qm_aeqe {
__le32 dw0;
};
struct qm_sqc {
__le16 head;
__le16 tail;
__le32 base_l;
__le32 base_h;
__le32 dw3;
__le16 w8;
__le16 rsvd0;
__le16 pasid;
__le16 w11;
__le16 cq_num;
__le16 w13;
__le32 rsvd1;
};
struct qm_cqc {
__le16 head;
__le16 tail;
__le32 base_l;
__le32 base_h;
__le32 dw3;
__le16 w8;
__le16 rsvd0;
__le16 pasid;
__le16 w11;
__le32 dw6;
__le32 rsvd1;
};
struct qm_eqc {
__le16 head;
__le16 tail;
__le32 base_l;
__le32 base_h;
__le32 dw3;
__le32 rsvd[2];
__le32 dw6;
};
struct qm_aeqc {
__le16 head;
__le16 tail;
__le32 base_l;
__le32 base_h;
__le32 dw3;
__le32 rsvd[2];
__le32 dw6;
};
struct qm_mailbox {
__le16 w0;
__le16 queue_num;
__le32 base_l;
__le32 base_h;
__le32 rsvd;
};
struct qm_doorbell {
__le16 queue_num;
__le16 cmd;
__le16 index;
__le16 priority;
};
struct qm_dma {
void *va;
dma_addr_t dma;
size_t size;
};
struct hisi_qm_status {
u32 eq_head;
bool eqc_phase;
u32 aeq_head;
bool aeqc_phase;
atomic_t flags;
int stop_reason;
};
struct hisi_qm_hw_error {
u32 int_msk;
const char *msg;
};
struct hisi_qm;
struct hisi_qm_err_info {
char *acpi_rst;
u32 msi_wr_port;
u32 ecc_2bits_mask;
u32 is_qm_ecc_mbit;
u32 is_dev_ecc_mbit;
u32 ce;
u32 nfe;
u32 fe;
u32 msi;
};
struct hisi_qm_err_ini {
u32 (*get_dev_hw_err_status)(struct hisi_qm *qm);
void (*clear_dev_hw_err_status)(struct hisi_qm *qm, u32 err_sts);
void (*hw_err_enable)(struct hisi_qm *qm);
void (*hw_err_disable)(struct hisi_qm *qm);
int (*set_usr_domain_cache)(struct hisi_qm *qm);
void (*log_dev_hw_err)(struct hisi_qm *qm, u32 err_sts);
void (*open_axi_master_ooo)(struct hisi_qm *qm);
void (*close_axi_master_ooo)(struct hisi_qm *qm);
struct hisi_qm_err_info err_info;
};
struct hisi_qm_list {
struct mutex lock;
struct list_head list;
bool (*check)(struct hisi_qm *qm);
};
struct hisi_qm {
enum qm_hw_ver ver;
enum qm_fun_type fun_type;
const char *dev_name;
struct pci_dev *pdev;
void __iomem *io_base;
u32 sqe_size;
u32 qp_base;
u32 qp_num;
u32 ctrl_q_num;
u32 vfs_num;
u32 free_qp_num;
struct list_head list;
struct hisi_qm_list *qm_list;
struct qm_dma qdma;
struct qm_sqc *sqc;
struct qm_cqc *cqc;
struct qm_eqe *eqe;
struct qm_aeqe *aeqe;
dma_addr_t sqc_dma;
dma_addr_t cqc_dma;
dma_addr_t eqe_dma;
dma_addr_t aeqe_dma;
struct hisi_qm_status status;
struct hisi_qm_err_ini err_ini;
struct rw_semaphore qps_lock;
struct idr qp_idr;
struct hisi_qp *qp_array;
struct mutex mailbox_lock;
const struct hisi_qm_hw_ops *ops;
struct qm_debug debug;
u32 error_mask;
u32 msi_mask;
unsigned long hw_status;
bool use_uacce; /* register to uacce */
bool use_sva;
bool is_frozen;
#ifdef CONFIG_CRYPTO_QM_UACCE
resource_size_t phys_base;
resource_size_t size;
struct uacce uacce;
const char *algs;
int uacce_mode;
#endif
struct workqueue_struct *wq;
struct work_struct work;
/* design for module not support aer, such as rde */
int (*abnormal_fix)(struct hisi_qm *qm);
};
struct hisi_qp_status {
atomic_t used;
u16 sq_tail;
u16 sq_head;
u16 cq_head;
bool cqc_phase;
atomic_t flags;
};
struct hisi_qp_ops {
int (*fill_sqe)(void *sqe, void *q_parm, void *d_parm);
};
struct hisi_qp {
u32 qp_id;
u8 alg_type;
u8 req_type;
u8 c_flag;
struct qm_dma qdma;
void *sqe;
struct qm_cqe *cqe;
dma_addr_t sqe_dma;
dma_addr_t cqe_dma;
struct hisi_qp_status qp_status;
struct completion completion;
struct hisi_qp_ops *hw_ops;
void *qp_ctx;
void (*req_cb)(struct hisi_qp *qp, void *data);
void (*event_cb)(struct hisi_qp *qp);
struct hisi_qm *qm;
bool is_resetting;
bool is_in_kernel;
#ifdef CONFIG_CRYPTO_QM_UACCE
u16 pasid;
struct uacce_queue *uacce_q;
#endif
};
static inline int q_num_set(const char *val, const struct kernel_param *kp,
unsigned int device)
{
struct pci_dev *pdev = pci_get_device(PCI_VENDOR_ID_HUAWEI,
device, NULL);
u32 n, q_num;
u8 rev_id;
int ret;
if (!val)
return -EINVAL;
if (!pdev) {
q_num = min_t(u32, QNUM_V1, QNUM_V2);
pr_info("No device found currently, suppose queue number is %d\n",
q_num);
} else {
rev_id = pdev->revision;
switch (rev_id) {
case QM_HW_V1:
q_num = QNUM_V1;
break;
case QM_HW_V2:
q_num = QNUM_V2;
break;
default:
return -EINVAL;
}
}
ret = kstrtou32(val, 10, &n);
if (ret || !n || n > q_num)
return -EINVAL;
return param_set_int(val, kp);
}
static inline int vf_num_set(const char *val, const struct kernel_param *kp)
{
u32 n;
int ret;
if (!val)
return -EINVAL;
ret = kstrtou32(val, 10, &n);
if (ret < 0)
return ret;
if (n > QM_MAX_VFS_NUM_V2)
return -ERANGE;
return param_set_int(val, kp);
}
#ifdef CONFIG_CRYPTO_QM_UACCE
static inline int mode_set(const char *val, const struct kernel_param *kp)
{
u32 n;
int ret;
if (!val)
return -EINVAL;
ret = kstrtou32(val, 10, &n);
if (ret != 0 || (n != UACCE_MODE_NOIOMMU &&
n != UACCE_MODE_NOUACCE))
return -EINVAL;
return param_set_int(val, kp);
}
#endif
static inline void hisi_qm_add_to_list(struct hisi_qm *qm,
struct hisi_qm_list *qm_list)
{
mutex_lock(&qm_list->lock);
list_add_tail(&qm->list, &qm_list->list);
mutex_unlock(&qm_list->lock);
}
static inline void hisi_qm_del_from_list(struct hisi_qm *qm,
struct hisi_qm_list *qm_list)
{
mutex_lock(&qm_list->lock);
list_del(&qm->list);
mutex_unlock(&qm_list->lock);
}
static inline int hisi_qm_pre_init(struct hisi_qm *qm,
u32 pf_q_num, u32 def_q_num)
{
struct pci_dev *pdev = qm->pdev;
switch (pdev->revision) {
case QM_HW_V1:
case QM_HW_V2:
qm->ver = pdev->revision;
break;
default:
pci_err(pdev, "hardware version err!\n");
return -ENODEV;
}
pci_set_drvdata(pdev, qm);
#ifdef CONFIG_CRYPTO_QM_UACCE
switch (qm->uacce_mode) {
case UACCE_MODE_NOUACCE:
qm->use_uacce = false;
break;
case UACCE_MODE_NOIOMMU:
qm->use_uacce = true;
break;
default:
pci_err(pdev, "uacce mode error!\n");
return -EINVAL;
}
#else
qm->use_uacce = false;
#endif
if (qm->fun_type == QM_HW_PF) {
qm->qp_base = def_q_num;
qm->qp_num = pf_q_num;
qm->debug.curr_qm_qp_num = pf_q_num;
}
return 0;
}
void hisi_qm_free_qps(struct hisi_qp **qps, int qp_num);
int hisi_qm_alloc_qps_node(int node, struct hisi_qm_list *qm_list,
struct hisi_qp **qps, int qp_num, u8 alg_type);
int hisi_qm_init(struct hisi_qm *qm);
void hisi_qm_uninit(struct hisi_qm *qm);
void hisi_qm_dev_shutdown(struct pci_dev *pdev);
void hisi_qm_remove_wait_delay(struct hisi_qm *qm,
struct hisi_qm_list *qm_list);
int hisi_qm_start(struct hisi_qm *qm);
int hisi_qm_stop(struct hisi_qm *qm, enum qm_stop_reason r);
struct hisi_qp *hisi_qm_create_qp(struct hisi_qm *qm, u8 alg_type);
int hisi_qm_start_qp(struct hisi_qp *qp, unsigned long arg);
int hisi_qm_stop_qp(struct hisi_qp *qp);
void hisi_qm_release_qp(struct hisi_qp *qp);
int hisi_qp_send(struct hisi_qp *qp, const void *msg);
int hisi_qp_wait(struct hisi_qp *qp);
int hisi_qm_get_free_qp_num(struct hisi_qm *qm);
int hisi_qm_get_vft(struct hisi_qm *qm, u32 *base, u32 *number);
void hisi_qm_debug_regs_clear(struct hisi_qm *qm);
int hisi_qm_debug_init(struct hisi_qm *qm);
int hisi_qm_restart(struct hisi_qm *qm);
int hisi_qm_sriov_enable(struct pci_dev *pdev, int max_vfs);
int hisi_qm_sriov_disable(struct pci_dev *pdev, struct hisi_qm_list *qm_list);
void hisi_qm_dev_err_init(struct hisi_qm *qm);
void hisi_qm_dev_err_uninit(struct hisi_qm *qm);
pci_ers_result_t hisi_qm_dev_err_detected(struct pci_dev *pdev,
pci_channel_state_t state);
pci_ers_result_t hisi_qm_dev_slot_reset(struct pci_dev *pdev);
void hisi_qm_reset_prepare(struct pci_dev *pdev);
void hisi_qm_reset_done(struct pci_dev *pdev);
pci_ers_result_t hisi_qm_process_dev_error(struct pci_dev *pdev);
int hisi_qm_controller_reset(struct hisi_qm *qm);
struct hisi_acc_sgl_pool;
struct hisi_acc_hw_sgl *hisi_acc_sg_buf_map_to_hw_sgl(struct device *dev,
struct scatterlist *sgl, struct hisi_acc_sgl_pool *pool,
u32 index, dma_addr_t *hw_sgl_dma);
void hisi_acc_sg_buf_unmap(struct device *dev, struct scatterlist *sgl,
struct hisi_acc_hw_sgl *hw_sgl);
struct hisi_acc_sgl_pool *hisi_acc_create_sgl_pool(struct device *dev,
u32 count, u32 sge_nr);
void hisi_acc_free_sgl_pool(struct device *dev,
struct hisi_acc_sgl_pool *pool);
#endif

View File

@ -0,0 +1,39 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/* Copyright (c) 2018-2019 HiSilicon Limited. */
#ifndef HISI_QM_USR_IF_H
#define HISI_QM_USR_IF_H
#define QM_CQE_SIZE 16
/* default queue depth for sq/cq/eq */
#define QM_Q_DEPTH 1024
#define QM_EQ_DEPTH (1024 * 2)
/* page number for queue file region */
#define QM_DOORBELL_PAGE_NR 1
#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 {
__u16 id;
__u16 qc_type;
};
#define HISI_QM_API_VER_BASE "hisi_qm_v1"
#define HISI_QM_API_VER2_BASE "hisi_qm_v2"
#define UACCE_CMD_QM_SET_QP_CTX _IOWR('H', 10, struct hisi_qp_ctx)
#endif

View File

@ -0,0 +1,2 @@
obj-$(CONFIG_CRYPTO_DEV_HISI_RDE) += hisi_rde.o
hisi_rde-objs = rde_main.o rde_api.o rde_data.o

View File

@ -0,0 +1,320 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* Copyright (c) 2018-2019 HiSilicon Limited.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
*/
#ifndef __RDE_H__
#define __RDE_H__
#include <linux/list.h>
#include "../qm.h"
#include "rde_usr_if.h"
#include "rde_api.h"
#undef pr_fmt
#define pr_fmt(fmt) "hisi_rde: " fmt
struct hisi_rde_ctrl;
struct hisi_rde {
struct hisi_qm qm;
struct hisi_rde_ctrl *ctrl;
struct work_struct reset_work;
u32 smmu_state;
};
#define RDE_CM_LOAD_ENABLE 1
#define RDE_MPCC_MAX_SRC_NUM 17
#define RDE_FLEXEC_MAX_SRC_NUM 32
#define RDE_MPCC_CMSIZE 2176
#define RDE_FLEXEC_CMSIZE 1024
#define RDE_MEM_SAVE_SHIFT 2
#define RDE_BUF_TYPE_SHIFT 3
#define SGL_DATA_OFFSET_SHIFT 8
#define DIF_GEN_PAD_CTRL_SHIFT 32
#define DIF_GEN_REF_CTRL_SHIFT 35
#define DIF_GEN_APP_CTRL_SHIFT 38
#define DIF_GEN_VER_CTRL_SHIFT 41
#define DIF_GEN_GRD_CTRL_SHIFT 44
#define DIF_APP_TAG_SHIFT 48
#define DIF_VERSION_SHIFT 56
#define RDE_TASK_DONE_STATUS 0x80
#define RDE_CRC16_IV 0x310004
#define RDE_PRP_PAGE_SIZE 0x31022c
#define RDE_SGL_SGE_OFFSET 0x310228
#define RDE_INVLD_REQ_ID (-1)
#define RDE_ALG_TYPE_MSK 0x60
#define RDE_BUF_TYPE_MSK 0x18
#define RDE_MAX_SRC_PLATE_NUM 32
#define RDE_MAX_DST_PLATE_NUM 17
#define SRC_ADDR_TABLE_NUM 48
#define DST_ADDR_TABLE_NUM 26
#define SRC_DIF_TABLE_NUM 20
#define DST_DIF_TABLE_NUM 17
#define RDE_STATUS_MSK 0x7f
#define RDE_DONE_MSK 0x1
#define RDE_DONE_SHIFT 7
#define RDE_PER_SRC_COEF_SIZE 32
#define RDE_PER_SRC_COEF_TIMES 4
#define RDE_TASK_TMOUT_MS 3000
#define RDE_GN_WITH_MODE(column, mode, parity) \
((u8)column + ((ACC_OPT_UPD ^ mode) ? 0 : (0x80 & (parity << 7))))
#define RDE_GN_CNT(i) (((i + 1) % 2 == 0) ? ((i + 1) >> 1) : ((i + 2) >> 1))
#define RDE_GN_FLAG(i) (((i + 1) % 2 == 0) ? 2 : 1)
#define RDE_GN_SHIFT(i) (32 * (i == 1 ? 1 : 0))
#define RDE_CHK_CTRL_CNT(i) ((i / 8) * 5)
#define RDE_LBA_CNT(i) ((i / 8 + 1) + \
((i % 2 == 0) ? (i >> 1) : ((i - 1) >> 1)))
#define RDE_CHK_CTRL_VALUE(grd, ref, i) \
((u64)(grd << 4 | ref) << (8 * (i % 8)))
#define RDE_LBA_SHIFT(i) (32 * ((i % 2) ^ 1))
struct hisi_rde_hw_error {
u8 status;
u32 int_msk;
const char *msg;
};
/* src data addr table, should be 64byte aligned */
struct rde_src_tbl {
u64 content[SRC_ADDR_TABLE_NUM];
};
/* src data dif table, should be 64byte aligned */
struct rde_src_tag_tbl {
u64 content[SRC_DIF_TABLE_NUM];
};
/* dst data addr table, should be 64byte aligned */
struct rde_dst_tbl {
u64 content[DST_ADDR_TABLE_NUM];
};
/* dst data dif table, should be 64byte aligned */
struct rde_dst_tag_tbl {
u64 content[DST_DIF_TABLE_NUM];
};
/* inner msg structure, keep addr info */
struct hisi_rde_msg {
struct rde_src_tbl *src_addr;
dma_addr_t src_dma_addr;
struct rde_dst_tbl *dst_addr;
dma_addr_t dst_dma_addr;
struct rde_src_tag_tbl *src_tag_addr;
dma_addr_t src_tag_dma_addr;
struct rde_dst_tag_tbl *dst_tag_addr;
dma_addr_t dst_tag_dma_addr;
u64 src_record[RDE_MAX_SRC_PLATE_NUM];
u64 dst_record[RDE_MAX_DST_PLATE_NUM];
struct hisi_rde_sqe sqe;
struct raid_ec_ctrl *udata;
struct completion completion;
u32 req_id;
int result;
};
/* rde ctx structure, acc_init api can alloc and init this structure */
struct hisi_rde_ctx {
struct device *dev;
struct hisi_qp *qp;
struct hisi_rde_msg *req_list;
unsigned long *req_bitmap;
spinlock_t req_lock;
u32 smmu_state;
u32 session_num;
u8 addr_type;
};
/* inner structure, to distinguish diffenernt alg and operation */
struct rde_type {
u8 alg_mode;
u8 mem_mode;
u8 buf_mode;
u8 alg_type;
};
/* RDE hardware error status */
enum {
RDE_STATUS_NULL = 0,
RDE_BD_ADDR_NO_ALIGN = 0x2,
RDE_BD_RD_BUS_ERR = 0x3,
RDE_IO_ABORT = 0x4,
RDE_BD_ERR = 0x5,
RDE_ECC_ERR = 0x6,
RDE_SGL_ADDR_ERR = 0x7,
RDE_SGL_PARA_ERR = 0x8,
RDE_DATA_RD_BUS_ERR = 0x1c,
RDE_DATA_WR_BUS_ERR = 0x1d,
RDE_CRC_CHK_ERR = 0x1e,
RDE_REF_CHK_ERR = 0x1f,
RDE_DISK0_VERIFY = 0x20,
RDE_DISK1_VERIFY = 0x21,
RDE_DISK2_VERIFY = 0x22,
RDE_DISK3_VERIFY = 0x23,
RDE_DISK4_VERIFY = 0x24,
RDE_DISK5_VERIFY = 0x25,
RDE_DISK6_VERIFY = 0x26,
RDE_DISK7_VERIFY = 0x27,
RDE_DISK8_VERIFY = 0x28,
RDE_DISK9_VERIFY = 0x29,
RDE_DISK10_VERIFY = 0x2a,
RDE_DISK11_VERIFY = 0x2b,
RDE_DISK12_VERIFY = 0x2c,
RDE_DISK13_VERIFY = 0x2d,
RDE_DISK14_VERIFY = 0x2e,
RDE_DISK15_VERIFY = 0x2f,
RDE_DISK16_VERIFY = 0x30,
RDE_CHAN_TMOUT = 0x31,
};
/* RDE algorithm types */
enum {
MPCC = 0x00, /* EC */
PQ_FLEXEC = 0x40, /* RAID5/RAID6/FlexEC */
XOR = 0x60, /* XOR */
};
/* RDE buffer access types */
enum {
PBUF = 0x00, /* Direct Access */
SGL = 0x08, /* Scatter Gather List */
PRP = 0x10, /* Physical Region Page List */
REVD = 0x18, /* Reserved */
};
/* RDE DIF GRD types */
enum {
NO_GRD = 0, /* no GRD domain */
GRD = 1, /* GRD domain without checking */
GRD_CHECK = 2, /* GRD domain with checking */
};
/* RDE DIF REF types */
enum {
NO_REF = 0, /* no REF domain */
REF = 1, /* REF domain without checking */
REF_CHECK_LBA = 2, /* REF domain checking with lab */
REF_CHECK_PRI = 3, /* REF domain checking with private infoformation */
};
/* RDE IO abort switch */
enum {
NO_ABORT = 0, /* don't abort the io */
ABORT = 1, /* abort the io */
};
/* RDE coefficient matrix load enable */
enum {
NO_CM_LOAD = 0, /* don't load matrix */
CM_LOAD = 1, /* load matrix */
};
/* RDE coefficient matrix types */
enum {
CM_ENCODE = 0, /* encode type */
CM_DECODE = 1, /* decode type */
};
/* RDE algorithms block size */
enum {
ALG_BLK_512B = 0, /* 512 bytes */
ALG_BLK_4K = 1, /* 4K bytes */
};
/* RDE crc iv enable */
enum {
NO_CRCIV = 0, /* default IV is 0 */
CRCIV = 1, /* IV is register's value */
};
/* RDE crc iv switch */
enum {
CRCIV0 = 0, /* select crc16_iv0 of register */
CRCIV1 = 1, /* select crc16_iv1 of register */
};
/* RDE DIF types */
enum {
NO_RDE_DIF = 0, /* without DIF */
RDE_DIF = 1, /* DIF */
};
/* RDE page padding types */
enum {
NO_PAD = 0, /* without padding */
PRE_PAD = 1, /* padding before DIF */
POST_PAD = 2, /* padding after DIF */
};
enum {
QNUM_64 = 64,
QNUM_128 = 128,
QNUM_256 = 256,
QNUM_512 = 512,
QNUM_1024 = 1024,
QNUM_BUTT
};
enum {
QDEPTH_64 = 64,
QDEPTH_128 = 128,
QDEPTH_256 = 256,
QDEPTH_512 = 512,
QDEPTH_1024 = 1024,
QDEPTH_BUTT
};
static inline void rde_bd_dump(struct hisi_rde_sqe *bd)
{
int i;
pr_info_ratelimited("====== BD info start======\n");
for (i = 0; i < sizeof(struct hisi_rde_sqe) / sizeof(u64); i++)
pr_info_ratelimited("sqe-word[%d]: 0x%llx.\n",
i, *((u64 *)bd + i));
pr_info_ratelimited("====== BD info end======\n");
}
static inline void rde_table_dump(const struct hisi_rde_msg *req)
{
int i;
for (i = 0; i < SRC_ADDR_TABLE_NUM; i++) {
if (req->src_addr->content[i])
pr_info_ratelimited("Table0 info[%d] is 0x%llx.\n",
i, req->src_addr->content[i]);
}
for (i = 0; i < SRC_DIF_TABLE_NUM; i++) {
if (req->src_tag_addr->content[i])
pr_info_ratelimited("Table1 info[%d] is 0x%llx.\n",
i, req->src_tag_addr->content[i]);
}
for (i = 0; i < DST_ADDR_TABLE_NUM; i++) {
if (req->dst_addr->content[i])
pr_info_ratelimited("Table2 info[%d] is 0x%llx.\n",
i, req->dst_addr->content[i]);
}
for (i = 0; i < DST_DIF_TABLE_NUM; i++) {
if (req->dst_tag_addr->content[i])
pr_info_ratelimited("Table3 info[%d] is 0x%llx.\n",
i, req->dst_tag_addr->content[i]);
}
}
struct hisi_qp *rde_create_qp(void);
int hisi_rde_abnormal_fix(struct hisi_qm *qm);
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,470 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* Copyright (c) 2018-2019 HiSilicon Limited.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
*/
#ifndef __RDE_API_H__
#define __RDE_API_H__
/**
* @brief dif pad type
*/
enum DIF_PAGE_LAYOUT_PAD_TYPE_E {
DIF_PAGE_LAYOUT_PAD_NONE = 0x0,
DIF_PAGE_LAYOUT_PAD_AHEAD_DIF = 0x1, /* 4096+56+8 */
DIF_PAGE_LAYOUT_PAD_BEHIND_DIF = 0x2, /* 4096+8+56 */
DIF_PAGE_LAYOUT_PAD_BUTT
};
/**
* @brief dif pad gen mode enumeration, rde only support 0,3,5.
*/
enum DIF_PAGE_LAYOUT_PAD_GEN_CTRL_E {
DIF_PAGE_LAYOUT_PAD_GEN_NONE = 0x0,
DIF_PAGE_LAYOUT_PAD_GEN_FROM_ZERO = 0x3,
DIF_PAGE_LAYOUT_PAD_GEN_FROM_SOURCE_DATA = 0x4,
DIF_PAGE_LAYOUT_PAD_GEN_FROM_RAID_OR_EC = 0x5,
DIF_PAGE_LAYOUT_PAD_GEN_BUTT
};
/**
* @brief dif grd gen mode enumeration.
*/
enum DIF_GRD_GEN_CTRL_E {
DIF_GRD_GEN_NONE = 0x0,
DIF_GRD_GEN_FROM_T10CRC = 0x1,
DIF_GRD_GEN_FROM_RAID_OR_EC = 0x5,
DIF_GRD_GEN_BUTT
};
/**
* @brief dif ver gen mode enumeration, rde only support 0 or 1.
*/
enum DIF_VER_GEN_CTRL_E {
DIF_VER_GEN_NONE = 0x0,
DIF_VER_GEN_FROM_INPUT = 0x1,
DIF_VER_GEN_FROM_ZERO = 0x3,
DIF_VER_GEN_FROM_SOURCE_DATA = 0x4,
DIF_VER_GEN_BUTT
};
/**
* @brief dif app gen mode enumeration, rde only support 0,1,5.
*/
enum DIF_APP_GEN_CTRL_E {
DIF_APP_GEN_NONE = 0x0,
DIF_APP_GEN_FROM_INPUT = 0x1,
DIF_APP_GEN_FROM_ZERO = 0x3,
DIF_APP_GEN_FROM_SOURCE_DATA = 0x4,
DIF_APP_GEN_FROM_RAID_OR_EC = 0x5,
DIF_APP_GEN_BUTT
};
/**
* @brief dif ref gen mode enumeration, rde only support 0,1,2,5.
*/
enum DIF_REF_GEN_CTRL_E {
DIF_REF_GEN_NONE = 0x0,
DIF_REF_GEN_FROM_INPUT_LBA = 0x1,
DIF_REF_GEN_FROM_PRIVATE_INFO = 0x2,
DIF_REF_GEN_FROM_ZERO = 0x3,
DIF_REF_GEN_FROM_SOURCE_DATA = 0x4,
DIF_REF_GEN_FROM_RAID_OR_EC = 0x5,
DIF_REF_GEN_BUTT
};
/**
* @brief dif verify mode enumeration, grd: rde only support 0,1,2.
*/
enum DIF_VERIFY_CTRL_E {
DIF_VERIFY_NONE = 0x0,
DIF_VERIFY_DO_NOT_VERIFY = 0x1,
DIF_VERIFY_ALL_BLOCK = 0x2,
DIF_VERIFY_BY_PRIVATE_INFO = 0x3,
DIF_VERIFY_BUTT
};
/**
* @brief data store mode, sdk do not support prp temporarily.
*/
enum ACC_BUF_TYPE_E {
ACC_BUF_TYPE_PBUFFER = 0x0,
ACC_BUF_TYPE_SGL = 0x1,
ACC_BUF_TYPE_PRP = 0x2,
ACC_BUF_TYPE_BUTT
};
/**
* @brief rde operation enumeration.
*/
enum ACC_OPT_RAID_E {
ACC_OPT_GEN = 0x0, /* generate */
ACC_OPT_VLD = 0x1, /* validate */
ACC_OPT_UPD = 0x2, /* update */
ACC_OPT_RCT = 0x3, /* reconstruct */
ACC_OPT_RAID_BUTT
};
/**
* @brief input addr type mode
* @note
* value 0 means input virt addr from
* kzalloc/get_free_pages/dma_alloc_coherent
* value 1 means input phy addr directly without tranform
* value 2 means input virt addr from vmalloc,
* and this addr type only supports pbuf data store mode
* in smmu bypass mode
*/
enum ACC_ADDR_TYPE_E {
VA_FROM_NORMAL_DMA_ZONE = 0x0,
PA_PASS_THROUGH = 0x1,
VA_FROM_HIGHMEM_ZONE = 0x2,
ACC_ADDR_TYPE_BUTT
};
/**
* @brief WRR sched, weights is 1:2:3:4:5:6:7:8:9:10:11:12:13:14:15:16.
*/
enum ACC_PRT_E {
ACC_PRT_WEIGHTS_1 = 0x0,
ACC_PRT_WEIGHTS_2,
ACC_PRT_WEIGHTS_3,
ACC_PRT_WEIGHTS_4,
ACC_PRT_WEIGHTS_5,
ACC_PRT_WEIGHTS_6,
ACC_PRT_WEIGHTS_7,
ACC_PRT_WEIGHTS_8,
ACC_PRT_WEIGHTS_9,
ACC_PRT_WEIGHTS_10,
ACC_PRT_WEIGHTS_11,
ACC_PRT_WEIGHTS_12,
ACC_PRT_WEIGHTS_13,
ACC_PRT_WEIGHTS_14,
ACC_PRT_WEIGHTS_15,
ACC_PRT_WEIGHTS_16,
ACC_PRT_BUTT,
};
/**
* @brief sge structure, should fill buf and len.
* @buf: page data start address, 64bit
* @len: valid data len, Byte
* @note
* usually, just need to fill buf and len
*/
struct sgl_entry_hw {
char *buf;
void *page_ctrl;
uint32_t len;
uint32_t pad;
uint32_t pad0;
uint32_t pad1;
};
/**
* @brief sgl structure.
* @next: next sgl point, to make up chain, 64bit
* @entry_sum_in_chain: sum of entry_sum_in_sgl in sgl chain
* @entry_sum_in_sgl: valid sgl_entry num in this sgl
* @entry_num_in_sgl: sgl_entry num in this sgl
* @entries: sgl_entry point
* @note
* usually, just need to fill next, entry_sum_in_chain,
* entry_sum_in_sgl, entry_num_in_sgl and entry
* entry_sum_in_chain is valid from the first sgl
* entry_sum_in_sgl <= entry_num_in_sgl
* sgl_entry point is determined by entry_sum_in_sgl
*/
struct sgl_hw {
struct sgl_hw *next;
uint16_t entry_sum_in_chain;
uint16_t entry_sum_in_sgl;
uint16_t entry_num_in_sgl;
uint8_t pad0[2];
uint64_t serial_num;
uint32_t flag;
uint32_t cpu_id;
uint8_t pad1[8];
uint8_t reserved[24];
struct sgl_entry_hw entries[0];
};
/**
* @brief sgl structure for rde.
* @ctrl: source and destination data block SGL address
* @buf_offset: offset of per data disk in the SGL chain
* @parity: 0 means data disk, 1 means parity disk
* @column: the index corresponding to src and dst disk
* @note
* parity is just valid in update mode
*/
struct rde_sgl {
struct sgl_hw *ctrl;
uint32_t buf_offset;
uint8_t parity;
uint8_t reserve;
uint16_t column;
};
/**
* @brief pbuf structure for rde.
* @note
* parity is just valid in update mode
*/
struct rde_pbuf {
char *pbuf;
uint32_t reserve1;
uint8_t parity;
uint8_t reserve2;
uint16_t column;
};
/**
* @brief dif data structure.
* @grd: 16bit gurad tag
* @ver: 8bit version
* @app: 8bit application information field
* @ref: 32bit reference tag
*/
struct dif_data {
uint16_t grd;
uint8_t ver;
uint8_t app;
uint32_t ref;
};
/**
* @brief dif gen ctrl structure.
* @page_layout_gen_type: denoted by enum DIF_PAGE_LAYOUT_PAD_GEN_CTRL_E
* @grd_gen_type: denoted by enum DIF_GRD_GEN_CTRL_E
* @ver_gen_type: denoted by enum DIF_VER_GEN_CTRL_E
* @app_gen_type: denoted by enum DIF_APP_GEN_CTRL_E
* @ref_gen_type: denoted by enum DIF_REF_GEN_CTRL_E
* @page_layout_pad_type: denoted by enum DIF_PAGE_LAYOUT_PAD_TYPE_E
*/
struct dif_gen {
uint32_t page_layout_gen_type:4;
uint32_t grd_gen_type:4;
uint32_t ver_gen_type:4;
uint32_t app_gen_type:4;
uint32_t ref_gen_type:4;
uint32_t page_layout_pad_type:2;
uint32_t reserved:10;
};
/**
* @brief dif verify ctrl structure.
* @grd_verify_type: denoted by enum DIF_VERIFY_CTRL_E
* @ref_verify_type: denoted by enum DIF_VERIFY_CTRL_E
* @note
* just need to fill grd_verify_type and ref_verify_type
*/
struct dif_verify {
uint16_t page_layout_pad_type:2;
uint16_t grd_verify_type:4;
uint16_t ref_verify_type:4;
uint16_t reserved:6;
};
/**
* @brief dif ctrl structure.
*/
struct dif_ctrl {
struct dif_gen gen;
struct dif_verify verify;
};
/**
* @brief general dif structure.
* @lba: lba for dif ref field
* @priv: private info for dif ref field
* @ver: 8bit version
* @app: 8bit application information field
* @note
* RDE need not to fill lba
*/
struct acc_dif {
uint64_t lba;
uint32_t priv;
uint8_t ver;
uint8_t app;
struct dif_ctrl ctrl;
};
/**
* @brief ctrl information for per request,
* user should alloc and init this structure.
* @src_data: src data address, reference rde data structure
* @dst_data: dst data address, reference rde data structure
* @src_num: number of source disks
* @dst_num: number of dst disks
* @block_size: support 512,520,4096,4104,4160
* @input_block: number of sector
* @data_len: data len of per disk, block_size (with dif)* input_block
* @buf_type: denoted by ACC_BUF_TYPE_E
* @src_dif: dif information of source disks
* @dst_dif: dif information of dest disks
* @cm_load: coe_matrix reload control, 0: do not load, 1: load
* @cm_len: length of loaded coe_matrix, equal to src_num
* @alg_blk_size: algorithm granularity, 0: 512 gran, 1: 4096 gran
* @mem_saving: mem saving or not, default 0
* @coe_matrix: coe matrix address, should be 64byte aligned
* @priv: design for user
* @note
* only mpcc support mem_saving mode, no mem_saving is 0x0, mem_saving is 0x1
*/
struct raid_ec_ctrl {
void *src_data;
void *dst_data;
uint32_t src_num;
uint32_t dst_num;
uint32_t block_size;
uint32_t input_block;
uint32_t data_len;
uint32_t buf_type;
struct acc_dif src_dif;
struct acc_dif dst_dif;
uint8_t cm_load;
uint8_t cm_len;
uint8_t alg_blk_size;
uint8_t mem_saving;
void *coe_matrix;
void *priv;
};
/**
* @brief acc_callback of user.
* @note
* ctx means struct acc_ctx
* tag means struct raid_ec_ctrl
*/
typedef void (*acc_callback)(void *ctx, void *tag, int status, size_t len);
/**
* @brief acc ctx structure, acc_init api will init this structure
* @inner: reserved for SDK to point to hisi_rde_ctx structure
* @cb: callback function for pool and asynchronously api
* @priority: denoted by ACC_PRT_E
* @addr_type: denoted by ACC_ADDR_TYPE_E
*/
struct acc_ctx {
void *inner;
acc_callback cb;
uint8_t priority;
uint8_t addr_type;
};
/**
* @brief return value.
*/
enum ACC_STATUS_E {
ACC_SUCCESS = 0,
ACC_INVALID_PARAM = (-103), /*!< parameter error */
ACC_RDE_DIF_ERR = (-113), /*!< Input or Output dif check error */
ACC_RDE_DISK_VERIFY_ERR = (-114) /*!< Output data verify error */
};
/**
*
* @brief initialization before you call the other api.
*
* @param [in] ctx is the context which manage the instance.
* @retval 0 is success, else is a negative number that is error code.
*
* @note
* Be sure you will fill para cb and addr_type, then call this function.
*
*/
int acc_init(struct acc_ctx *ctx);
/**
*
* @brief reconfig callback of ctx.
*
* @param [in] ctx is the context which manage the instance.
* @retval 0 is success, else is a negative number that is error code.
*
* @note
*
*/
int acc_setup_callback(struct acc_ctx *ctx, acc_callback cb);
/**
*
* @brief release resource that alloced by acc_init().
*
* @param [in] ctx is the context which manage the instance.
* @retval 0 is success, else is a negative number that is error code.
*
* @note
*
*/
int acc_clear(struct acc_ctx *ctx);
/**
*
* @brief flexec/raid5/raid6 operation asynchronously.
*
* @param [in] ctx is the context which manage the instance.
* @param [in] ctrl is the parameter data of current io.
* @param [in] op_type is from ACC_OPT_RAID_E
* @retval 0 is success, else is a negative number that is error code.
*
* @note
*Multiple concurrent processing is not supported for the same instance.
*/
int acc_do_flexec_asyn(struct acc_ctx *ctx,
struct raid_ec_ctrl *ctrl, uint8_t op_type);
/**
*
* @brief mpcc operation asynchronously.
*
* @param [in] ctx is the context which manage the instance.
* @param [in] ctrl is the parameter data of current io.
* @param [in] op_type is from ACC_OPT_RAID_E
* @retval 0 is success, else is a negative number that is error code.
*
* @note
*Multiple concurrent processing is not supported for the same instance.
*/
int acc_do_mpcc_asyn(struct acc_ctx *ctx,
struct raid_ec_ctrl *ctrl, uint8_t op_type);
/**
*
* @brief flexec/raid5/raid6 operation synchronously.
*
* @param [in] ctx is the context which manage the instance.
* @param [in] ctrl is the parameter data of current io.
* @param [in] op_type is from ACC_OPT_RAID_E
* @retval 0 is success, else is a negative number that is error code.
*
* @note
*Multiple concurrent processing is not supported for the same instance.
*/
int acc_do_flexec(struct acc_ctx *ctx,
struct raid_ec_ctrl *ctrl, uint8_t op_type);
/**
*
* @brief mpcc operation synchronously.
*
* @param [in] ctx is the context which manage the instance.
* @param [in] ctrl is the parameter data of current io.
* @param [in] op_type is from ACC_OPT_RAID_E
* @retval 0 is success, else is a negative number that is error code.
*
* @note
*Multiple concurrent processing is not supported for the same instance.
*/
int acc_do_mpcc(struct acc_ctx *ctx,
struct raid_ec_ctrl *ctrl, uint8_t op_type);
#endif /* __ACC_API_H__ */

View File

@ -0,0 +1,216 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2018-2019 HiSilicon Limited.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*/
#include <linux/slab.h>
#include <linux/gfp.h>
#include <linux/kernel.h>
#include <linux/memory.h>
#include <linux/io.h>
#include <linux/scatterlist.h>
#include <linux/types.h>
#include "rde_data.h"
static inline u32 sgl_addr_cnt(struct sgl_hw *sgl)
{
u32 cnt = 0;
struct sgl_hw *cur_sgl = sgl;
if (!sgl) {
pr_err("[%s] Sgl address is NULL.\n", __func__);
return 0;
}
while (cur_sgl) {
cnt += 1;
cnt += cur_sgl->entry_sum_in_sgl;
cur_sgl = cur_sgl->next;
}
return cnt;
}
int acc_sgl_dump(struct sgl_hw *data)
{
u32 i;
u32 cnt_entries;
struct sgl_hw *cur_sgl;
struct sgl_hw *next_sgl;
struct sgl_entry_hw *entry;
if (unlikely(!data->entry_sum_in_sgl)) {
pr_err("Error! The entrysum of sgl is zero.\n");
return -EINVAL;
}
cnt_entries = sgl_addr_cnt(data);
pr_info("Sgl entries:%d.\n", cnt_entries);
for (cur_sgl = data; cur_sgl; ) {
pr_info("Sgl addr: 0x%pK.\n", cur_sgl);
pr_info("NextSgl: 0x%pK.\n", cur_sgl->next);
pr_info("EntrySumInChain: %u.\n", cur_sgl->entry_sum_in_chain);
pr_info("EntrySumInSgl: %u.\n", cur_sgl->entry_sum_in_sgl);
entry = cur_sgl->entries;
for (i = 0; (i < cur_sgl->entry_sum_in_sgl &&
entry->buf); i++) {
pr_info("Entries[%d]:addr = 0x%pK.\n", i, entry->buf);
entry++;
}
if (cur_sgl->next)
next_sgl = cur_sgl->next;
else
next_sgl = NULL;
cur_sgl = next_sgl;
}
return 0;
}
static void acc_sgl_to_scatterlist(struct pci_dev *pdev, struct sgl_hw *data,
struct scatterlist *sglist, u32 smmu_state)
{
u16 i;
struct sgl_hw *cur_sgl;
struct sgl_hw *next_sgl;
struct sgl_entry_hw *entry;
dma_addr_t pa;
cur_sgl = data;
while (cur_sgl) {
entry = cur_sgl->entries;
for (i = 0; (i < cur_sgl->entry_sum_in_sgl &&
entry->buf); i++) {
sg_set_buf(sglist, (void *)entry->buf, entry->len);
pa = acc_virt_to_phys(pdev, sg_virt(sglist),
(size_t)sglist->length,
smmu_state);
sg_dma_address(sglist) = pa;
sglist++;
entry->buf = (char *)pa;
entry++;
}
if (cur_sgl->next) {
next_sgl = cur_sgl->next;
sg_set_buf(sglist, (void *)next_sgl,
(u32)(sizeof(struct sgl_hw) +
sizeof(struct sgl_entry_hw) *
(next_sgl->entry_sum_in_sgl)));
pa = acc_virt_to_phys(pdev, sg_virt(sglist),
(size_t)sglist->length,
smmu_state);
sg_dma_address(sglist) = pa;
sglist++;
cur_sgl->next = (struct sgl_hw *)pa;
} else {
next_sgl = NULL;
}
cur_sgl = next_sgl;
}
}
int acc_sgl_virt_to_phys(struct pci_dev *pdev, struct sgl_hw *data,
void **sglist_head, u32 smmu_state)
{
u32 addr_cnt;
struct scatterlist *sglist;
if (!data) {
pr_err("[%s] Para sgl_s is NULL.\n", __func__);
return -EINVAL;
}
if (unlikely(!data->entry_sum_in_sgl) ||
data->entry_sum_in_sgl > data->entry_num_in_sgl) {
pr_err("[%s] Para sge num is wrong.\n", __func__);
return -EINVAL;
}
addr_cnt = sgl_addr_cnt(data);
sglist = kcalloc(addr_cnt, sizeof(*sglist), GFP_KERNEL);
if (unlikely(!sglist)) {
pr_err("[%s] Malloc sglist fail.\n", __func__);
return -ENOMEM;
}
*sglist_head = sglist;
sg_init_table(sglist, addr_cnt);
sg_set_buf(sglist, (void *)data, (u32)(sizeof(struct sgl_hw) +
sizeof(struct sgl_entry_hw) * (data->entry_sum_in_sgl)));
sg_dma_address(sglist) = acc_virt_to_phys(pdev, sg_virt(sglist),
(size_t)sglist->length, smmu_state);
sglist++;
acc_sgl_to_scatterlist(pdev, data, sglist, smmu_state);
return 0;
}
int acc_sgl_phys_to_virt(struct pci_dev *pdev, void *sglist_head,
u32 smmu_state)
{
int i;
struct sgl_hw *cur_sgl;
struct sgl_hw *next_sgl;
struct sgl_entry_hw *entry;
struct scatterlist *sglist;
struct scatterlist *sg;
int ret = -EFAULT;
if (!sglist_head) {
pr_err("[%s] Para sglist_head is NULL.\n", __func__);
return -EINVAL;
}
sglist = (struct scatterlist *)sglist_head;
sg = sglist;
cur_sgl = (struct sgl_hw *)sg_virt(sg);
acc_phys_to_virt(pdev, sg_dma_address(sg),
(size_t)sg->length, smmu_state);
while (cur_sgl) {
entry = cur_sgl->entries;
for (i = 0; (i < cur_sgl->entry_sum_in_sgl &&
entry->buf); i++) {
sg = sg_next(sg);
if (unlikely(!sg)) {
pr_err("[%s][%d]Scatterlist happens to be NULL.\n",
__func__, __LINE__);
goto FAIL;
}
entry->buf = (char *)sg_virt(sg);
acc_phys_to_virt(pdev, sg_dma_address(sg),
(size_t)sg->length, smmu_state);
entry++;
}
if (cur_sgl->next) {
sg = sg_next(sg);
if (unlikely(!sg)) {
pr_err("[%s][%d]Scatterlist happens to be NULL.\n",
__func__, __LINE__);
goto FAIL;
}
next_sgl = (struct sgl_hw *)sg_virt(sg);
acc_phys_to_virt(pdev, sg_dma_address(sg),
(size_t)sg->length, smmu_state);
cur_sgl->next = next_sgl;
} else {
next_sgl = NULL;
}
cur_sgl = next_sgl;
}
ret = 0;
FAIL:
kfree(sglist);
return ret;
}

View File

@ -0,0 +1,58 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* Copyright (c) 2018-2019 HiSilicon Limited.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
*/
#ifndef __ACC_DATA_H__
#define __ACC_DATA_H__
#include <linux/pci.h>
#include <linux/mm.h>
#include "rde_api.h"
static inline dma_addr_t acc_virt_to_phys(struct pci_dev *pdev, void *va,
size_t size, u32 smmu_state)
{
dma_addr_t pa;
if (!smmu_state)
pa = (dma_addr_t)virt_to_phys(va);
else
pa = pci_map_single(pdev, va, size, DMA_BIDIRECTIONAL);
return pa;
}
static inline dma_addr_t acc_pfn_to_phys(void *va)
{
unsigned long pfn;
unsigned long off;
unsigned long pa;
off = (uintptr_t)va % PAGE_SIZE;
pfn = vmalloc_to_pfn(va);
pa = (pfn << PAGE_SHIFT) + off;
return pa;
}
static inline void acc_phys_to_virt(struct pci_dev *pdev, dma_addr_t pa,
size_t size, u32 smmu_state)
{
if (smmu_state)
pci_unmap_single(pdev, pa, size, DMA_BIDIRECTIONAL);
}
int acc_sgl_dump(struct sgl_hw *data);
int acc_sgl_virt_to_phys(struct pci_dev *pdev, struct sgl_hw *data,
void **sglist_head, u32 smmu_state);
int acc_sgl_phys_to_virt(struct pci_dev *pdev,
void *sglist_head, u32 smmu_state);
#endif

View File

@ -0,0 +1,875 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (c) 2018-2019 HiSilicon Limited.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*/
#include <linux/acpi.h>
#include <linux/aer.h>
#include <linux/bitops.h>
#include <linux/debugfs.h>
#include <linux/init.h>
#include <linux/iommu.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/seq_file.h>
#include <linux/topology.h>
#include "../../include_linux/uacce.h"
#include "rde.h"
#define HRDE_QUEUE_NUM_V1 4096
#define HRDE_QUEUE_NUM_V2 1024
#define HRDE_PCI_DEVICE_ID 0xa25a
#define HRDE_SQE_SIZE 64
#define HRDE_SQ_SIZE (HRDE_SQE_SIZE * QM_Q_DEPTH)
#define HRDE_PF_DEF_Q_NUM 256
#define HRDE_PF_DEF_Q_BASE 0
#define HRDE_RD_INTVRL_US 10
#define HRDE_RD_TMOUT_US 1000
#define HRDE_RST_TMOUT_MS 400
#define HRDE_ENABLE 1
#define HRDE_DISABLE 0
#define HRDE_PCI_COMMAND_INVALID 0xFFFFFFFF
#define HRDE_RAS_INT_MSK 0x310290
#define HRDE_RAS_CE_MSK BIT(2)
#define HRDE_RAS_NFE_MSK BIT(1)
#define HRDE_RAS_ENABLE BIT(0)
#define HRDE_INT_MSK 0x310314
#define HRDE_INT_ENABLE 0x0
#define HRDE_INT_DISABLE 0x3ffff
#define HRDE_BD_PREFETCH BIT(8)
#define HRDE_INT_SOURCE 0x31030c
#define HRDE_INT_SOURCE_CLEAR GENMASK(17, 0)
#define HRDE_INT_STATUS 0x310318
#define HRDE_DFX_CTRL_0 0x310240
#define HRDE_ECC_ERR 0x310234
#define HRDE_ECC_ERR_CNT 0x310238
#define HRDE_OP_DONE_CNT 0x310250
#define HRDE_OP_ERR_CNT 0x310254
#define HRDE_OP_ABORT_CNT 0x310258
#define HRDE_FIFO_STAT_0 0x310200
#define HRDE_DFX_STAT_7 0x310334
#define HRDE_DFX_STAT_8 0x310338
#define DFX_CTRL0 0x3
#define WRITE_CLEAR_VAL GENMASK(31, 0)
#define HRDE_AWCACHE 0x310154
#define HRDE_ARCACHE 0x31015c
#define AWCACHE 0xff0
#define ARCACHE 0xfff0
#define HRDE_CFG 0x310000
#define CHN_CFG 0x5010101
#define HRDE_AXI_SHUTDOWN_EN BIT(26)
#define HRDE_AXI_SHUTDOWN_DIS 0xFBFFFFFF
#define HRDE_WR_MSI_PORT BIT(0)
#define HRDE_AWUSER_BD_1 0x310104
#define HRDE_ARUSER_BD_1 0x310114
#define HRDE_ARUSER_SGL_1 0x310124
#define HRDE_AWUSER_DAT_1 0x310134
#define HRDE_ARUSER_DAT_1 0x310144
#define HRDE_USER_SMMU 0x40001070
#define HRDE_ERR_CNT 0x310238
#define HRDE_ECC_1BIT_ERR BIT(0)
#define HRDE_ECC_2BIT_ERR BIT(1)
#define HRDE_ECC_1BIT_SHIFT 16
#define HRDE_ECC_2BIT_CNT_MSK GENMASK(15, 0)
#define HRDE_STATE_INT_ERR GENMASK(11, 2)
#define HRDE_AM_CURR_PORT_STS 0x300100
#define HRDE_MASTER_TRANS_RET 0x300150
#define HRDE_FSM_MAX_CNT 0x310280
#define HRDE_QM_IDEL_STATUS 0x1040e4
#define HRDE_QM_PEH_DFX_INFO0 0x1000fc
#define PEH_MSI_MASK_SHIFT 0x90
#define CACHE_CTL 0x1833
#define HRDE_DBGFS_VAL_MAX_LEN 20
#define HRDE_PROBE_ADDR 0x31025c
#define HRDE_PROBE_DATA 0x310260
#define HRDE_PROBE_EN BIT(16)
#define HRDE_PROBE_DATA_EN BIT(17)
#define HRDE_STRB_CS_SHIFT 9
static const char hisi_rde_name[] = "hisi_rde";
static struct dentry *hrde_debugfs_root;
static struct hisi_qm_list rde_devices;
static void hisi_rde_ras_proc(struct work_struct *work);
static const struct hisi_rde_hw_error rde_hw_error[] = {
{.int_msk = BIT(0), .msg = "Rde_ecc_1bitt_err"},
{.int_msk = BIT(1), .msg = "Rde_ecc_2bit_err"},
{.int_msk = BIT(2), .msg = "Rde_stat_mgmt_state_timeout_err"},
{.int_msk = BIT(3), .msg = "Rde_data_wr_state_timeout_err"},
{.int_msk = BIT(4), .msg = "Rde_alg_state_timeout_err"},
{.int_msk = BIT(5), .msg = "Rde_data_ar_state_timeout_err"},
{.int_msk = BIT(6), .msg = "Rde_bd_mgmt_state_timeout_err"},
{.int_msk = BIT(7), .msg = "Rde_list_parse_ar_state_timeout_err"},
{.int_msk = BIT(8), .msg = "Rde_bd_prefetch_state_timeout_err"},
{.int_msk = BIT(9), .msg = "Rde_dst_buf_parse_state_timeout_err"},
{.int_msk = BIT(10), .msg = "Rde_src_buf_parse_state_timeout_err"},
{.int_msk = BIT(11), .msg = "Rde_chn_timeout_err"},
{.int_msk = BIT(12), .msg = "Rde_bd_bresp_err"},
{.int_msk = BIT(13), .msg = "Rde_data_bresp_err"},
{.int_msk = BIT(14), .msg = "Rde_data_rresp_err"},
{.int_msk = BIT(15), .msg = "Rde_sgl_rresp_err"},
{.int_msk = BIT(16), .msg = "Rde_list_rresp_err"},
{.int_msk = BIT(17), .msg = "Rde_bd_rresp_err"},
{ /* sentinel */ }
};
enum ctrl_debug_file_index {
HRDE_CURRENT_FUNCTION,
HRDE_CURRENT_BD,
HRDE_DEBUG_FILE_NUM,
/* RDE not support CNT_CLR_CE config, default enable */
};
static const char *const ctrl_debug_file_name[] = {
[HRDE_CURRENT_FUNCTION] = "current_function_id",
[HRDE_CURRENT_BD] = "current_bd",
};
struct ctrl_debug_file {
enum ctrl_debug_file_index index;
spinlock_t lock;
struct hisi_rde_ctrl *ctrl;
};
/*
* One RDE controller has one PF and multiple VFs, some global configurations
* which PF has need this structure.
* Just relevant for PF.
*/
struct hisi_rde_ctrl {
struct hisi_rde *hisi_rde;
struct ctrl_debug_file files[HRDE_DEBUG_FILE_NUM];
};
static struct debugfs_reg32 hrde_dfx_regs[] = {
{"HRDE_DFX_STAT_0", 0x310220ull},
{"HRDE_DFX_STAT_1", 0x310224ull},
{"HRDE_DFX_STAT_2", 0x310320ull},
{"HRDE_DFX_STAT_3", 0x310324ull},
{"HRDE_DFX_STAT_4", 0x310328ull},
{"HRDE_DFX_STAT_5", 0x31032cull},
{"HRDE_DFX_STAT_6", 0x310330ull},
{"HRDE_DFX_STAT_7", 0x310334ull},
{"HRDE_DFX_STAT_8", 0x310338ull},
{"HRDE_FIFO_STAT_0", 0x310200ull},
{"HRDE_FIFO_STAT_1", 0x310204ull},
{"HRDE_OP_TAG_0", 0x310214ull},
{"HRDE_OP_TAG_1", 0x310218ull},
{"HRDE_OP_TAG_2", 0x31021cull},
{"HRDE_ECC_ERR", 0x310234ull},
{"HRDE_ECC_ERR_CNT", 0x310238ull},
{"HRDE_OP_DONE_CNT", 0x310250ull},
{"HRDE_OP_ERR_CNT", 0x310254ull},
{"HRDE_OP_ABORT_CNT", 0x310258ull},
{"HRDE_TMP_ADDR_HIGH", 0x310270ull},
{"HRDE_TMP_ADDR_LOW", 0x310274ull},
{"HRDE_TMP_LENGTH", 0x310278ull},
{"HRDE_INT_STATUS", 0x310318ull},
};
static struct debugfs_reg32 hrde_ooo_dfx_regs[] = {
{"HRDE_AM_CURR_PORT_STS", 0x300100ull},
{"HRDE_AM_ROB_ECC_ERR_ADDR", 0x30010cull},
{"HRDE_AM_CURR_TRANS_RETURN", 0x300150ull},
{"HRDE_AM_CURR_RD_TXID_STS_0", 0x300160ull},
{"HRDE_AM_CURR_RD_TXID_STS_1", 0x300164ull},
{"HRDE_AM_CURR_RD_TXID_STS_2", 0x300168ull},
{"HRDE_AM_CURR_WR_TXID_STS_0", 0x300170ull},
{"HRDE_AM_CURR_WR_TXID_STS_1", 0x300174ull},
{"HRDE_AM_CURR_WR_TXID_STS_2", 0x300178ull},
};
#ifdef CONFIG_CRYPTO_QM_UACCE
static int uacce_mode_set(const char *val, const struct kernel_param *kp)
{
return mode_set(val, kp);
}
static const struct kernel_param_ops uacce_mode_ops = {
.set = uacce_mode_set,
.get = param_get_int,
};
static int uacce_mode = UACCE_MODE_NOIOMMU;
module_param_cb(uacce_mode, &uacce_mode_ops, &uacce_mode, 0444);
MODULE_PARM_DESC(uacce_mode, "Mode of UACCE can be 0(default), 2");
#endif
static int pf_q_num_set(const char *val, const struct kernel_param *kp)
{
return q_num_set(val, kp, HRDE_PCI_DEVICE_ID);
}
static const struct kernel_param_ops pf_q_num_ops = {
.set = pf_q_num_set,
.get = param_get_int,
};
static u32 pf_q_num = HRDE_PF_DEF_Q_NUM;
module_param_cb(pf_q_num, &pf_q_num_ops, &pf_q_num, 0444);
MODULE_PARM_DESC(pf_q_num, "Number of queues in PF(v1 0-4096, v2 0-1024)");
static const struct pci_device_id hisi_rde_dev_ids[] = {
{PCI_DEVICE(PCI_VENDOR_ID_HUAWEI, HRDE_PCI_DEVICE_ID)},
{0,}
};
MODULE_DEVICE_TABLE(pci, hisi_rde_dev_ids);
struct hisi_qp *rde_create_qp(void)
{
int node = cpu_to_node(smp_processor_id());
struct hisi_qp *qp;
int ret;
ret = hisi_qm_alloc_qps_node(node, &rde_devices, &qp, 1, 0);
if (!ret)
return qp;
return NULL;
}
static int hisi_rde_engine_init(struct hisi_qm *qm)
{
writel(DFX_CTRL0, qm->io_base + HRDE_DFX_CTRL_0);
/* usr domain */
writel(HRDE_USER_SMMU, qm->io_base + HRDE_AWUSER_BD_1);
writel(HRDE_USER_SMMU, qm->io_base + HRDE_ARUSER_BD_1);
writel(HRDE_USER_SMMU, qm->io_base + HRDE_AWUSER_DAT_1);
writel(HRDE_USER_SMMU, qm->io_base + HRDE_ARUSER_DAT_1);
writel(HRDE_USER_SMMU, qm->io_base + HRDE_ARUSER_SGL_1);
/* rde cache */
writel(AWCACHE, qm->io_base + HRDE_AWCACHE);
writel(ARCACHE, qm->io_base + HRDE_ARCACHE);
/* rde chn enable + outstangding config */
writel(CHN_CFG, qm->io_base + HRDE_CFG);
return 0;
}
static int hisi_rde_set_user_domain_and_cache(struct hisi_qm *qm)
{
/* qm user domain */
writel(AXUSER_BASE, qm->io_base + QM_ARUSER_M_CFG_1);
writel(ARUSER_M_CFG_ENABLE, qm->io_base + QM_ARUSER_M_CFG_ENABLE);
writel(AXUSER_BASE, qm->io_base + QM_AWUSER_M_CFG_1);
writel(AWUSER_M_CFG_ENABLE, qm->io_base + QM_AWUSER_M_CFG_ENABLE);
writel(WUSER_M_CFG_ENABLE, qm->io_base + QM_WUSER_M_CFG_ENABLE);
/* qm cache */
writel(AXI_M_CFG, qm->io_base + QM_AXI_M_CFG);
writel(AXI_M_CFG_ENABLE, qm->io_base + QM_AXI_M_CFG_ENABLE);
/* disable BME/PM/SRIOV FLR*/
writel(PEH_AXUSER_CFG, qm->io_base + QM_PEH_AXUSER_CFG);
writel(PEH_AXUSER_CFG_ENABLE, qm->io_base + QM_PEH_AXUSER_CFG_ENABLE);
writel(CACHE_CTL, qm->io_base + QM_CACHE_CTL);
return hisi_rde_engine_init(qm);
}
static void hisi_rde_debug_regs_clear(struct hisi_qm *qm)
{
/* clear rde debug regs */
readl(qm->io_base + HRDE_ECC_ERR);
readl(qm->io_base + HRDE_ECC_ERR_CNT);
readl(qm->io_base + HRDE_OP_DONE_CNT);
readl(qm->io_base + HRDE_OP_ERR_CNT);
readl(qm->io_base + HRDE_OP_ABORT_CNT);
writel(WRITE_CLEAR_VAL, qm->io_base + HRDE_FIFO_STAT_0);
writel(WRITE_CLEAR_VAL, qm->io_base + HRDE_DFX_STAT_7);
writel(WRITE_CLEAR_VAL, qm->io_base + HRDE_DFX_STAT_8);
/* clear current_qm */
writel(0x0, qm->io_base + QM_DFX_MB_CNT_VF);
writel(0x0, qm->io_base + QM_DFX_DB_CNT_VF);
hisi_qm_debug_regs_clear(qm);
}
static void hisi_rde_hw_error_enable(struct hisi_qm *qm)
{
u32 val;
val = readl(qm->io_base + HRDE_CFG);
/* clear RDE hw error source if having */
writel(HRDE_INT_SOURCE_CLEAR, qm->io_base + HRDE_INT_SOURCE);
writel(HRDE_RAS_ENABLE, qm->io_base + HRDE_RAS_INT_MSK);
/* bd prefetch should bd masked to prevent misreport */
writel((HRDE_INT_ENABLE | HRDE_BD_PREFETCH),
qm->io_base + HRDE_INT_MSK);
/* when m-bit error occur, master ooo will close */
val = val | HRDE_AXI_SHUTDOWN_EN;
writel(val, qm->io_base + HRDE_CFG);
}
static void hisi_rde_hw_error_disable(struct hisi_qm *qm)
{
u32 ras_msk = HRDE_RAS_CE_MSK | HRDE_RAS_NFE_MSK;
u32 val;
val = readl(qm->io_base + HRDE_CFG);
writel(ras_msk, qm->io_base + HRDE_RAS_INT_MSK);
writel(HRDE_INT_DISABLE, qm->io_base + HRDE_INT_MSK);
/* when m-bit error occur, master ooo will not close */
val = val & HRDE_AXI_SHUTDOWN_DIS;
writel(val, qm->io_base + HRDE_CFG);
}
static inline struct hisi_qm *file_to_qm(struct ctrl_debug_file *file)
{
struct hisi_rde *hisi_rde = file->ctrl->hisi_rde;
return &hisi_rde->qm;
}
static u32 current_qm_read(struct ctrl_debug_file *file)
{
struct hisi_qm *qm = file_to_qm(file);
return readl(qm->io_base + QM_DFX_MB_CNT_VF);
}
static int current_qm_write(struct ctrl_debug_file *file, u32 val)
{
struct hisi_qm *qm = file_to_qm(file);
u32 tmp;
if (val > 0) {
pr_err("Function id should be smaller than 0.\n");
return -EINVAL;
}
writel(val, qm->io_base + QM_DFX_MB_CNT_VF);
writel(val, qm->io_base + QM_DFX_DB_CNT_VF);
tmp = val |
(readl(qm->io_base + QM_DFX_SQE_CNT_VF_SQN) & CURRENT_Q_MASK);
writel(tmp, qm->io_base + QM_DFX_SQE_CNT_VF_SQN);
tmp = val |
(readl(qm->io_base + QM_DFX_CQE_CNT_VF_CQN) & CURRENT_Q_MASK);
writel(tmp, qm->io_base + QM_DFX_CQE_CNT_VF_CQN);
return 0;
}
static int current_bd_read(struct ctrl_debug_file *file)
{
struct hisi_qm *qm = file_to_qm(file);
return readl(qm->io_base + HRDE_PROBE_DATA);
}
static int current_bd_write(struct ctrl_debug_file *file, u32 val)
{
struct hisi_qm *qm = file_to_qm(file);
u32 tmp = 0;
if (val >= (HRDE_SQE_SIZE / sizeof(u32))) {
pr_err("Width index should be smaller than 16.\n");
return -EINVAL;
}
tmp = HRDE_PROBE_DATA_EN | HRDE_PROBE_EN | (val << HRDE_STRB_CS_SHIFT);
writel(tmp, qm->io_base + HRDE_PROBE_ADDR);
return 0;
}
static ssize_t ctrl_debug_read(struct file *filp, char __user *buf,
size_t count, loff_t *pos)
{
struct ctrl_debug_file *file = filp->private_data;
char tbuf[HRDE_DBGFS_VAL_MAX_LEN];
u32 val;
int ret;
spin_lock_irq(&file->lock);
switch (file->index) {
case HRDE_CURRENT_FUNCTION:
val = current_qm_read(file);
ret = snprintf(tbuf, HRDE_DBGFS_VAL_MAX_LEN, "%u\n", val);
break;
case HRDE_CURRENT_BD:
val = current_bd_read(file);
ret = snprintf(tbuf, HRDE_DBGFS_VAL_MAX_LEN, "%x\n", val);
break;
default:
spin_unlock_irq(&file->lock);
return -EINVAL;
}
spin_unlock_irq(&file->lock);
return simple_read_from_buffer(buf, count, pos, tbuf, ret);
}
static ssize_t ctrl_debug_write(struct file *filp, const char __user *buf,
size_t count, loff_t *pos)
{
struct ctrl_debug_file *file = filp->private_data;
char tbuf[20];
unsigned long val;
int len, ret;
if (*pos != 0)
return 0;
if (count >= HRDE_DBGFS_VAL_MAX_LEN)
return -ENOSPC;
len = simple_write_to_buffer(tbuf, HRDE_DBGFS_VAL_MAX_LEN - 1,
pos, buf, count);
if (len < 0)
return len;
tbuf[len] = '\0';
if (kstrtoul(tbuf, 0, &val))
return -EFAULT;
spin_lock_irq(&file->lock);
switch (file->index) {
case HRDE_CURRENT_FUNCTION:
ret = current_qm_write(file, val);
if (ret)
goto err_input;
break;
case HRDE_CURRENT_BD:
ret = current_bd_write(file, val);
if (ret)
goto err_input;
break;
default:
ret = -EINVAL;
goto err_input;
}
spin_unlock_irq(&file->lock);
return count;
err_input:
spin_unlock_irq(&file->lock);
return ret;
}
static const struct file_operations ctrl_debug_fops = {
.owner = THIS_MODULE,
.open = simple_open,
.read = ctrl_debug_read,
.write = ctrl_debug_write,
};
static int hisi_rde_chn_debug_init(struct hisi_qm *qm)
{
struct device *dev = &qm->pdev->dev;
struct debugfs_regset32 *regset, *regset_ooo;
struct dentry *tmp_d, *tmp;
char buf[HRDE_DBGFS_VAL_MAX_LEN];
int ret;
ret = snprintf(buf, HRDE_DBGFS_VAL_MAX_LEN, "rde_dfx");
if (ret < 0)
return -ENOENT;
tmp_d = debugfs_create_dir(buf, qm->debug.debug_root);
if (!tmp_d)
return -ENOENT;
regset = devm_kzalloc(dev, sizeof(*regset), GFP_KERNEL);
if (!regset)
return -ENOENT;
regset->regs = hrde_dfx_regs;
regset->nregs = ARRAY_SIZE(hrde_dfx_regs);
regset->base = qm->io_base;
tmp = debugfs_create_regset32("chn_regs", 0444, tmp_d, regset);
if (!tmp)
return -ENOENT;
regset_ooo = devm_kzalloc(dev, sizeof(*regset_ooo), GFP_KERNEL);
if (!regset_ooo)
return -ENOENT;
regset_ooo->regs = hrde_ooo_dfx_regs;
regset_ooo->nregs = ARRAY_SIZE(hrde_ooo_dfx_regs);
regset_ooo->base = qm->io_base;
tmp = debugfs_create_regset32("ooo_regs", 0444, tmp_d, regset_ooo);
if (!tmp)
return -ENOENT;
return 0;
}
static int hisi_rde_ctrl_debug_init(struct hisi_qm *qm)
{
struct hisi_rde *hisi_rde = container_of(qm, struct hisi_rde, qm);
struct dentry *tmp;
int i;
for (i = HRDE_CURRENT_FUNCTION; i < HRDE_DEBUG_FILE_NUM; i++) {
spin_lock_init(&hisi_rde->ctrl->files[i].lock);
hisi_rde->ctrl->files[i].ctrl = hisi_rde->ctrl;
hisi_rde->ctrl->files[i].index = i;
tmp = debugfs_create_file(ctrl_debug_file_name[i], 0600,
qm->debug.debug_root,
hisi_rde->ctrl->files + i,
&ctrl_debug_fops);
if (!tmp)
return -ENOENT;
}
return hisi_rde_chn_debug_init(qm);
}
static int hisi_rde_debugfs_init(struct hisi_qm *qm)
{
struct device *dev = &qm->pdev->dev;
struct dentry *dev_d;
int ret;
dev_d = debugfs_create_dir(dev_name(dev), hrde_debugfs_root);
if (!dev_d)
return -ENOENT;
qm->debug.debug_root = dev_d;
ret = hisi_qm_debug_init(qm);
if (ret)
goto failed_to_create;
if (qm->pdev->device == HRDE_PCI_DEVICE_ID) {
ret = hisi_rde_ctrl_debug_init(qm);
if (ret)
goto failed_to_create;
}
return 0;
failed_to_create:
debugfs_remove_recursive(qm->debug.debug_root);
return ret;
}
static void hisi_rde_debugfs_exit(struct hisi_qm *qm)
{
debugfs_remove_recursive(qm->debug.debug_root);
if (qm->fun_type == QM_HW_PF) {
hisi_rde_debug_regs_clear(qm);
qm->debug.curr_qm_qp_num = 0;
}
}
void hisi_rde_hw_error_log(struct hisi_qm *qm, u32 err_sts)
{
const struct hisi_rde_hw_error *err = rde_hw_error;
struct device *dev = &qm->pdev->dev;
u32 err_val;
while (err->msg) {
if (err->int_msk & err_sts)
dev_err_ratelimited(dev,
"[%s] [Error status=0x%x] found.\n",
err->msg, err->int_msk);
err++;
}
if (HRDE_ECC_2BIT_ERR & err_sts) {
err_val = (readl(qm->io_base + HRDE_ERR_CNT) &
HRDE_ECC_2BIT_CNT_MSK);
dev_err_ratelimited(dev,
"Rde ecc 2bit sram num=0x%x.\n", err_val);
}
if (HRDE_STATE_INT_ERR & err_sts) {
err_val = readl(qm->io_base + HRDE_AM_CURR_PORT_STS);
dev_err_ratelimited(dev,
"Rde ooo cur port sts=0x%x.\n", err_val);
err_val = readl(qm->io_base + HRDE_MASTER_TRANS_RET);
dev_err_ratelimited(dev,
"Rde ooo outstanding sts=0x%x.\n", err_val);
}
}
u32 hisi_rde_get_hw_err_status(struct hisi_qm *qm)
{
return readl(qm->io_base + HRDE_INT_STATUS);
}
void hisi_rde_clear_hw_err_status(struct hisi_qm *qm, u32 err_sts)
{
writel(err_sts, qm->io_base + HRDE_INT_SOURCE);
}
static void hisi_rde_open_master_ooo(struct hisi_qm *qm)
{
u32 val;
val = readl(qm->io_base + HRDE_CFG);
writel(val & HRDE_AXI_SHUTDOWN_DIS, qm->io_base + HRDE_CFG);
writel(val | HRDE_AXI_SHUTDOWN_EN, qm->io_base + HRDE_CFG);
}
static int hisi_rde_pf_probe_init(struct hisi_qm *qm)
{
struct hisi_rde *hisi_rde = container_of(qm, struct hisi_rde, qm);
struct hisi_rde_ctrl *ctrl;
int ret;
ctrl = devm_kzalloc(&qm->pdev->dev, sizeof(*ctrl), GFP_KERNEL);
if (!ctrl)
return -ENOMEM;
hisi_rde->ctrl = ctrl;
ctrl->hisi_rde = hisi_rde;
switch (qm->ver) {
case QM_HW_V1:
qm->ctrl_q_num = HRDE_QUEUE_NUM_V1;
break;
case QM_HW_V2:
qm->ctrl_q_num = HRDE_QUEUE_NUM_V2;
break;
default:
return -EINVAL;
}
qm->err_ini.get_dev_hw_err_status = hisi_rde_get_hw_err_status;
qm->err_ini.clear_dev_hw_err_status = hisi_rde_clear_hw_err_status;
qm->err_ini.err_info.ecc_2bits_mask = HRDE_ECC_2BIT_ERR;
qm->err_ini.err_info.ce = QM_BASE_CE;
qm->err_ini.err_info.nfe = QM_BASE_NFE | QM_ACC_DO_TASK_TIMEOUT;
qm->err_ini.err_info.fe = 0;
qm->err_ini.err_info.msi = 0;
qm->err_ini.err_info.acpi_rst = "RRST";
qm->err_ini.hw_err_disable = hisi_rde_hw_error_disable;
qm->err_ini.hw_err_enable = hisi_rde_hw_error_enable;
qm->err_ini.set_usr_domain_cache = hisi_rde_set_user_domain_and_cache;
qm->err_ini.log_dev_hw_err = hisi_rde_hw_error_log;
qm->err_ini.open_axi_master_ooo = hisi_rde_open_master_ooo;
qm->err_ini.err_info.msi_wr_port = HRDE_WR_MSI_PORT;
ret = qm->err_ini.set_usr_domain_cache(qm);
if (ret)
return ret;
hisi_qm_dev_err_init(qm);
qm->err_ini.open_axi_master_ooo(qm);
hisi_rde_debug_regs_clear(qm);
return 0;
}
static int hisi_rde_qm_pre_init(struct hisi_qm *qm, struct pci_dev *pdev)
{
int ret;
#ifdef CONFIG_CRYPTO_QM_UACCE
qm->algs = "ec\n";
qm->uacce_mode = uacce_mode;
#endif
qm->pdev = pdev;
ret = hisi_qm_pre_init(qm, pf_q_num, HRDE_PF_DEF_Q_BASE);
if (ret)
return ret;
qm->qm_list = &rde_devices;
qm->sqe_size = HRDE_SQE_SIZE;
qm->dev_name = hisi_rde_name;
qm->abnormal_fix = hisi_rde_abnormal_fix;
return 0;
}
static u32 hisi_rde_smmu_state(struct device *dev)
{
struct iommu_domain *domain;
domain = iommu_get_domain_for_dev(dev);
if (domain) {
if (domain->type == IOMMU_DOMAIN_DMA)
return true;
else
return false;
} else {
return false;
}
}
static int hisi_rde_probe(struct pci_dev *pdev, const struct pci_device_id *id)
{
struct hisi_rde *hisi_rde;
struct hisi_qm *qm;
int ret;
hisi_rde = devm_kzalloc(&pdev->dev, sizeof(*hisi_rde), GFP_KERNEL);
if (!hisi_rde)
return -ENOMEM;
INIT_WORK(&hisi_rde->reset_work, hisi_rde_ras_proc);
hisi_rde->smmu_state = hisi_rde_smmu_state(&pdev->dev);
qm = &hisi_rde->qm;
qm->fun_type = QM_HW_PF;
ret = hisi_rde_qm_pre_init(qm, pdev);
if (ret) {
pci_err(pdev, "Pre init qm failed!\n");
return ret;
}
ret = hisi_qm_init(qm);
if (ret) {
pci_err(pdev, "Init qm failed!\n");
return ret;
}
ret = hisi_rde_pf_probe_init(qm);
if (ret) {
pci_err(pdev, "Init pf failed!\n");
goto err_qm_uninit;
}
ret = hisi_qm_start(qm);
if (ret) {
pci_err(pdev, "Start qm failed!\n");
goto err_qm_uninit;
}
ret = hisi_rde_debugfs_init(qm);
if (ret)
pci_warn(pdev, "Init debugfs failed!\n");
hisi_qm_add_to_list(qm, &rde_devices);
return 0;
err_qm_uninit:
hisi_qm_uninit(qm);
return ret;
}
static void hisi_rde_remove(struct pci_dev *pdev)
{
struct hisi_qm *qm = pci_get_drvdata(pdev);
struct hisi_rde *hisi_rde = container_of(qm, struct hisi_rde, qm);
hisi_qm_remove_wait_delay(qm, &rde_devices);
qm->abnormal_fix = NULL;
hisi_qm_dev_err_uninit(qm);
cancel_work_sync(&hisi_rde->reset_work);
hisi_qm_del_from_list(qm, &rde_devices);
hisi_rde_debugfs_exit(qm);
hisi_qm_stop(qm, QM_NORMAL);
hisi_qm_uninit(qm);
}
static void hisi_rde_ras_proc(struct work_struct *work)
{
struct pci_dev *pdev;
struct hisi_rde *hisi_rde;
pci_ers_result_t ret;
hisi_rde = container_of(work, struct hisi_rde, reset_work);
pdev = hisi_rde->qm.pdev;
if (!pdev)
return;
ret = hisi_qm_process_dev_error(pdev);
if (ret == PCI_ERS_RESULT_NEED_RESET)
if (hisi_qm_controller_reset(&hisi_rde->qm))
dev_err(&pdev->dev, "Hisi_rde reset fail.\n");
}
int hisi_rde_abnormal_fix(struct hisi_qm *qm)
{
struct hisi_rde *hisi_rde;
if (!qm)
return -EINVAL;
hisi_rde = container_of(qm, struct hisi_rde, qm);
return schedule_work(&hisi_rde->reset_work);
}
static const struct pci_error_handlers hisi_rde_err_handler = {
.reset_prepare = hisi_qm_reset_prepare,
.reset_done = hisi_qm_reset_done,
};
static struct pci_driver hisi_rde_pci_driver = {
.name = "hisi_rde",
.id_table = hisi_rde_dev_ids,
.probe = hisi_rde_probe,
.remove = hisi_rde_remove,
.err_handler = &hisi_rde_err_handler,
.shutdown = hisi_qm_dev_shutdown,
};
static void hisi_rde_register_debugfs(void)
{
if (!debugfs_initialized())
return;
hrde_debugfs_root = debugfs_create_dir("hisi_rde", NULL);
if (IS_ERR_OR_NULL(hrde_debugfs_root))
hrde_debugfs_root = NULL;
}
static void hisi_rde_unregister_debugfs(void)
{
debugfs_remove_recursive(hrde_debugfs_root);
}
static int __init hisi_rde_init(void)
{
int ret;
INIT_LIST_HEAD(&rde_devices.list);
mutex_init(&rde_devices.lock);
rde_devices.check = NULL;
hisi_rde_register_debugfs();
ret = pci_register_driver(&hisi_rde_pci_driver);
if (ret < 0) {
hisi_rde_unregister_debugfs();
pr_err("Register pci driver failed.\n");
}
return ret;
}
static void __exit hisi_rde_exit(void)
{
pci_unregister_driver(&hisi_rde_pci_driver);
hisi_rde_unregister_debugfs();
}
module_init(hisi_rde_init);
module_exit(hisi_rde_exit);
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Yu'an Wang<wangyuan46@huawei.com>");
MODULE_DESCRIPTION("Driver for HiSilicon RDE accelerator");
MODULE_VERSION("1.3.11");

View File

@ -0,0 +1,45 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2019 HiSilicon Limited.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
*/
#ifndef __RDE_USR_IF_H__
#define __RDE_USR_IF_H__
struct hisi_rde_sqe {
__u64 rsvd0: 16;
__u64 op_tag: 16;
__u64 alg_blk_size: 2;
__u64 cm_type: 1;
__u64 cm_le: 1;
__u64 abort: 1;
__u64 src_nblks: 6;
__u64 dst_nblks: 5;
__u64 chk_dst_ref_ctrl: 4;
__u64 chk_dst_grd_ctrl: 4;
__u64 op_type: 8;
__u64 block_size: 16;
__u64 page_pad_type: 2;
__u64 dif_type: 1;
__u64 rsvd1: 3;
__u64 crciv_sel: 1;
__u64 crciv_en: 1;
__u64 status: 8;
__u64 rsvd2: 10;
__u64 cm_len: 6;
__u64 transfer_size: 16;
__u64 coef_matrix_addr;
__u64 src_addr;
__u64 src_tag_addr;
__u64 dst_addr;
__u64 dst_tag_addr;
__u64 dw7;
};
#endif

View File

@ -0,0 +1,2 @@
obj-$(CONFIG_CRYPTO_DEV_HISI_SEC2) += hisi_sec2.o
hisi_sec2-objs = sec_main.o sec_crypto.o

View File

@ -0,0 +1,169 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/* Copyright (c) 2018-2019 HiSilicon Limited. */
#ifndef __HISI_SEC_V2_H
#define __HISI_SEC_V2_H
#include <linux/list.h>
#include "../qm.h"
#include "sec_crypto.h"
/* Algorithm resource per hardware SEC queue */
struct sec_alg_res {
u8 *pbuf;
dma_addr_t pbuf_dma;
u8 *c_ivin;
dma_addr_t c_ivin_dma;
u8 *out_mac;
dma_addr_t out_mac_dma;
};
/* Cipher request of SEC private */
struct sec_cipher_req {
struct hisi_acc_hw_sgl *c_in;
dma_addr_t c_in_dma;
struct hisi_acc_hw_sgl *c_out;
dma_addr_t c_out_dma;
u8 *c_ivin;
dma_addr_t c_ivin_dma;
struct skcipher_request *sk_req;
u32 c_len;
bool encrypt;
};
/* SEC request of Crypto */
struct sec_req {
struct sec_sqe sec_sqe;
struct sec_ctx *ctx;
struct sec_qp_ctx *qp_ctx;
struct sec_cipher_req c_req;
struct list_head backlog_head;
int err_type;
int req_id;
/* Status of the SEC request */
bool fake_busy;
bool use_pbuf;
};
/**
* struct sec_req_op - Operations for SEC request
* @buf_map: DMA map the SGL buffers of the request
* @buf_unmap: DMA unmap the SGL buffers of the request
* @bd_fill: Fill the SEC queue BD
* @bd_send: Send the SEC BD into the hardware queue
* @callback: Call back for the request
* @process: Main processing logic of Skcipher
*/
struct sec_req_op {
int (*buf_map)(struct sec_ctx *ctx, struct sec_req *req);
void (*buf_unmap)(struct sec_ctx *ctx, struct sec_req *req);
void (*do_transfer)(struct sec_ctx *ctx, struct sec_req *req);
int (*bd_fill)(struct sec_ctx *ctx, struct sec_req *req);
int (*bd_send)(struct sec_ctx *ctx, struct sec_req *req);
void (*callback)(struct sec_ctx *ctx, struct sec_req *req, int err);
int (*process)(struct sec_ctx *ctx, struct sec_req *req);
};
/* SEC cipher context which cipher's relatives */
struct sec_cipher_ctx {
u8 *c_key;
dma_addr_t c_key_dma;
sector_t iv_offset;
u32 c_gran_size;
u32 ivsize;
u8 c_mode;
u8 c_alg;
u8 c_key_len;
};
/* SEC queue context which defines queue's relatives */
struct sec_qp_ctx {
struct hisi_qp *qp;
struct sec_req *req_list[QM_Q_DEPTH];
struct idr req_idr;
struct sec_alg_res res[QM_Q_DEPTH];
struct sec_ctx *ctx;
struct mutex req_lock;
struct list_head backlog;
struct hisi_acc_sgl_pool *c_in_pool;
struct hisi_acc_sgl_pool *c_out_pool;
};
enum sec_alg_type {
SEC_SKCIPHER,
SEC_AEAD
};
/* SEC Crypto TFM context which defines queue and cipher .etc relatives */
struct sec_ctx {
struct sec_qp_ctx *qp_ctx;
struct sec_dev *sec;
const struct sec_req_op *req_op;
struct hisi_qp **qps;
/* Half queues for encipher, and half for decipher */
u32 hlf_q_num;
/* Threshold for fake busy, trigger to return -EBUSY to user */
u32 fake_req_limit;
/* Currrent cyclic index to select a queue for encipher */
atomic_t enc_qcyclic;
/* Currrent cyclic index to select a queue for decipher */
atomic_t dec_qcyclic;
enum sec_alg_type alg_type;
bool pbuf_supported;
struct sec_cipher_ctx c_ctx;
};
enum sec_endian {
SEC_LE = 0,
SEC_32BE,
SEC_64BE
};
enum sec_debug_file_index {
SEC_CURRENT_QM,
SEC_CLEAR_ENABLE,
SEC_DEBUG_FILE_NUM,
};
struct sec_debug_file {
enum sec_debug_file_index index;
spinlock_t lock;
struct hisi_qm *qm;
};
struct sec_dfx {
atomic64_t send_cnt;
atomic64_t recv_cnt;
atomic64_t send_busy_cnt;
atomic64_t recv_busy_cnt;
atomic64_t err_bd_cnt;
atomic64_t invalid_req_cnt;
atomic64_t done_flag_cnt;
};
struct sec_debug {
struct sec_dfx dfx;
struct sec_debug_file files[SEC_DEBUG_FILE_NUM];
};
struct sec_dev {
struct hisi_qm qm;
struct sec_debug debug;
u32 ctx_q_num;
bool iommu_used;
};
void sec_destroy_qps(struct hisi_qp **qps, int qp_num);
struct hisi_qp **sec_create_qps(void);
int sec_register_to_crypto(void);
void sec_unregister_from_crypto(void);
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,238 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/* Copyright (c) 2018-2019 HiSilicon Limited. */
#ifndef __HISI_SEC_V2_CRYPTO_H
#define __HISI_SEC_V2_CRYPTO_H
#define SEC_IV_SIZE 24
#define SEC_MAX_KEY_SIZE 64
#define SEC_MAX_AUTH_KEY_SIZE 64
#define SEC_COMM_SCENE 0
enum sec_calg {
SEC_CALG_3DES = 0x1,
SEC_CALG_AES = 0x2,
SEC_CALG_SM4 = 0x3,
};
enum sec_hash_alg {
SEC_A_HMAC_SHA1 = 0x10,
SEC_A_HMAC_SHA256 = 0x11,
SEC_A_HMAC_SHA512 = 0x15,
};
enum sec_mac_len {
SEC_HMAC_SHA1_MAC = 20,
SEC_HMAC_SHA256_MAC = 32,
SEC_HMAC_SHA512_MAC = 64,
};
enum sec_cmode {
SEC_CMODE_ECB = 0x0,
SEC_CMODE_CBC = 0x1,
SEC_CMODE_CTR = 0x4,
SEC_CMODE_XTS = 0x7,
};
enum sec_ckey_type {
SEC_CKEY_128BIT = 0x0,
SEC_CKEY_192BIT = 0x1,
SEC_CKEY_256BIT = 0x2,
SEC_CKEY_3DES_3KEY = 0x1,
SEC_CKEY_3DES_2KEY = 0x3,
};
enum sec_bd_type {
SEC_BD_TYPE1 = 0x1,
SEC_BD_TYPE2 = 0x2,
};
enum sec_auth {
SEC_NO_AUTH = 0x0,
SEC_AUTH_TYPE1 = 0x1,
SEC_AUTH_TYPE2 = 0x2,
};
enum sec_cipher_dir {
SEC_CIPHER_ENC = 0x1,
SEC_CIPHER_DEC = 0x2,
};
enum sec_addr_type {
SEC_PBUF = 0x0,
SEC_SGL = 0x1,
SEC_PRP = 0x2,
};
enum sec_ci_gen {
SEC_CI_GEN_BY_ADDR = 0x0,
SEC_CI_GEN_BY_LBA = 0X3,
};
enum sec_scene {
SEC_SCENE_IPSEC = 0x1,
SEC_SCENE_STORAGE = 0x5,
};
enum sec_work_mode {
SEC_NO_FUSION = 0x0,
SEC_IV_FUSION = 0x1,
SEC_FUSION_BUTT
};
enum sec_req_ops_type {
SEC_OPS_SKCIPHER_ALG = 0x0,
SEC_OPS_DMCRYPT = 0x1,
SEC_OPS_MULTI_IV = 0x2,
SEC_OPS_BUTT
};
struct sec_sqe_type2 {
/*
* mac_len: 0~4 bits
* a_key_len: 5~10 bits
* a_alg: 11~16 bits
*/
__le32 mac_key_alg;
/*
* c_icv_len: 0~5 bits
* c_width: 6~8 bits
* c_key_len: 9~11 bits
* c_mode: 12~15 bits
*/
__le16 icvw_kmode;
/* c_alg: 0~3 bits */
__u8 c_alg;
__u8 rsvd4;
/*
* a_len: 0~23 bits
* iv_offset_l: 24~31 bits
*/
__le32 alen_ivllen;
/*
* c_len: 0~23 bits
* iv_offset_h: 24~31 bits
*/
__le32 clen_ivhlen;
__le16 auth_src_offset;
__le16 cipher_src_offset;
__le16 cs_ip_header_offset;
__le16 cs_udp_header_offset;
__le16 pass_word_len;
__le16 dk_len;
__u8 salt3;
__u8 salt2;
__u8 salt1;
__u8 salt0;
__le16 tag;
__le16 rsvd5;
/*
* c_pad_type: 0~3 bits
* c_pad_len: 4~11 bits
* c_pad_data_type: 12~15 bits
*/
__le16 cph_pad;
/* c_pad_len_field: 0~1 bits */
__le16 c_pad_len_field;
__le64 long_a_data_len;
__le64 a_ivin_addr;
__le64 a_key_addr;
__le64 mac_addr;
__le64 c_ivin_addr;
__le64 c_key_addr;
__le64 data_src_addr;
__le64 data_dst_addr;
/*
* done: 0 bit
* icv: 1~3 bits
* csc: 4~6 bits
* flag: 7-10 bits
* dif_check: 11~13 bits
*/
__le16 done_flag;
__u8 error_type;
__u8 warning_type;
__u8 mac_i3;
__u8 mac_i2;
__u8 mac_i1;
__u8 mac_i0;
__le16 check_sum_i;
__u8 tls_pad_len_i;
__u8 rsvd12;
__le32 counter;
};
struct sec_sqe {
/*
* type: 0~3 bits
* cipher: 4~5 bits
* auth: 6~7 bit s
*/
__u8 type_cipher_auth;
/*
* seq: 0 bit
* de: 1~2 bits
* scene: 3~6 bits
* src_addr_type: ~7 bit, with sdm_addr_type 0-1 bits
*/
__u8 sds_sa_type;
/*
* src_addr_type: 0~1 bits, not used now,
* if support PRP, set this field, or set zero.
* dst_addr_type: 2~4 bits
* mac_addr_type: 5~7 bits
*/
__u8 sdm_addr_type;
__u8 rsvd0;
/*
* nonce_len(type2): 0~3 bits
* huk(type2): 4 bit
* key_s(type2): 5 bit
* ci_gen: 6~7 bits
*/
__u8 huk_key_ci;
/*
* ai_gen: 0~1 bits
* a_pad(type2): 2~3 bits
* c_s(type2): 4~5 bits
*/
__u8 ai_apd_cs;
/*
* rhf(type2): 0 bit
* c_key_type: 1~2 bits
* a_key_type: 3~4 bits
* write_frame_len(type2): 5~7 bits
*/
__u8 rca_key_frm;
/*
* cal_iv_addr_en(type2): 0 bit
* tls_up(type2): 1 bit
* inveld: 7 bit
*/
__u8 iv_tls_ld;
struct sec_sqe_type2 type2;
};
int sec_register_to_crypto(void);
void sec_unregister_from_crypto(void);
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,272 @@
// SPDX-License-Identifier: GPL-2.0
/* Copyright (c) 2019 HiSilicon Limited. */
#include <linux/dma-mapping.h>
#include <linux/module.h>
#include <linux/slab.h>
#include "qm.h"
#define HISI_ACC_SGL_SGE_NR_MIN 1
#define HISI_ACC_SGL_NR_MAX 256
#define HISI_ACC_SGL_ALIGN_SIZE 64
#define HISI_ACC_MEM_BLOCK_NR 5
struct acc_hw_sge {
dma_addr_t buf;
void *page_ctrl;
__le32 len;
__le32 pad;
__le32 pad0;
__le32 pad1;
};
/* use default sgl head size 64B */
struct hisi_acc_hw_sgl {
dma_addr_t next_dma;
__le16 entry_sum_in_chain;
__le16 entry_sum_in_sgl;
__le16 entry_length_in_sgl;
__le16 pad0;
__le64 pad1[5];
struct hisi_acc_hw_sgl *next;
struct acc_hw_sge sge_entries[];
} __aligned(1);
struct hisi_acc_sgl_pool {
struct mem_block {
struct hisi_acc_hw_sgl *sgl;
dma_addr_t sgl_dma;
size_t size;
} mem_block[HISI_ACC_MEM_BLOCK_NR];
u32 sgl_num_per_block;
u32 block_num;
u32 count;
u32 sge_nr;
size_t sgl_size;
};
/**
* hisi_acc_create_sgl_pool() - Create a hw sgl pool.
* @dev: The device which hw sgl pool belongs to.
* @count: Count of hisi_acc_hw_sgl in pool.
* @sge_nr: The count of sge in hw_sgl
*
* This function creates a hw sgl pool, after this user can get hw sgl memory
* from it.
*/
struct hisi_acc_sgl_pool *hisi_acc_create_sgl_pool(struct device *dev,
u32 count, u32 sge_nr)
{
u32 sgl_size, block_size, sgl_num_per_block, block_num, remain_sgl;
struct hisi_acc_sgl_pool *pool;
struct mem_block *block;
u32 i, j;
if (!dev || !count || !sge_nr || sge_nr > HISI_ACC_SGL_SGE_NR_MAX)
return ERR_PTR(-EINVAL);
sgl_size = sizeof(struct acc_hw_sge) * sge_nr +
sizeof(struct hisi_acc_hw_sgl);
block_size = PAGE_SIZE * (1 << (MAX_ORDER - 1));
sgl_num_per_block = block_size / sgl_size;
block_num = count / sgl_num_per_block;
remain_sgl = count % sgl_num_per_block;
if ((!remain_sgl && block_num > HISI_ACC_MEM_BLOCK_NR) ||
(remain_sgl > 0 && block_num > HISI_ACC_MEM_BLOCK_NR - 1))
return ERR_PTR(-EINVAL);
pool = kzalloc(sizeof(*pool), GFP_KERNEL);
if (!pool)
return ERR_PTR(-ENOMEM);
block = pool->mem_block;
for (i = 0; i < block_num; i++) {
block[i].sgl = dma_alloc_coherent(dev, block_size,
&block[i].sgl_dma,
GFP_KERNEL);
if (!block[i].sgl) {
dev_err(dev, "Fail to allocate hw SG buffer!\n");
goto err_free_mem;
}
block[i].size = block_size;
}
if (remain_sgl > 0) {
block[i].sgl = dma_alloc_coherent(dev, remain_sgl * sgl_size,
&block[i].sgl_dma,
GFP_KERNEL);
if (!block[i].sgl) {
dev_err(dev, "Fail to allocate remained hw SG buffer!\n");
goto err_free_mem;
}
block[i].size = remain_sgl * sgl_size;
}
pool->sgl_num_per_block = sgl_num_per_block;
pool->block_num = remain_sgl ? block_num + 1 : block_num;
pool->count = count;
pool->sgl_size = sgl_size;
pool->sge_nr = sge_nr;
return pool;
err_free_mem:
for (j = 0; j < i; j++) {
dma_free_coherent(dev, block_size, block[j].sgl,
block[j].sgl_dma);
memset(block + j, 0, sizeof(*block));
}
kfree(pool);
return ERR_PTR(-ENOMEM);
}
EXPORT_SYMBOL_GPL(hisi_acc_create_sgl_pool);
/**
* hisi_acc_free_sgl_pool() - Free a hw sgl pool.
* @dev: The device which hw sgl pool belongs to.
* @pool: Pointer of pool.
*
* This function frees memory of a hw sgl pool.
*/
void hisi_acc_free_sgl_pool(struct device *dev, struct hisi_acc_sgl_pool *pool)
{
struct mem_block *block;
int i;
if (!dev || !pool)
return;
block = pool->mem_block;
for (i = 0; i < pool->block_num; i++)
dma_free_coherent(dev, block[i].size, block[i].sgl,
block[i].sgl_dma);
kfree(pool);
}
EXPORT_SYMBOL_GPL(hisi_acc_free_sgl_pool);
static struct hisi_acc_hw_sgl *acc_get_sgl(struct hisi_acc_sgl_pool *pool,
u32 index, dma_addr_t *hw_sgl_dma)
{
struct mem_block *block;
u32 block_index, offset;
if (!pool || !hw_sgl_dma || index >= pool->count)
return ERR_PTR(-EINVAL);
block = pool->mem_block;
block_index = index / pool->sgl_num_per_block;
offset = index % pool->sgl_num_per_block;
*hw_sgl_dma = block[block_index].sgl_dma + pool->sgl_size * offset;
return (void *)block[block_index].sgl + pool->sgl_size * offset;
}
static void sg_map_to_hw_sg(struct scatterlist *sgl,
struct acc_hw_sge *hw_sge)
{
hw_sge->buf = sg_dma_address(sgl);
hw_sge->len = cpu_to_le32(sg_dma_len(sgl));
}
static void inc_hw_sgl_sge(struct hisi_acc_hw_sgl *hw_sgl)
{
u16 var = le16_to_cpu(hw_sgl->entry_sum_in_sgl);
var++;
hw_sgl->entry_sum_in_sgl = cpu_to_le16(var);
}
static void update_hw_sgl_sum_sge(struct hisi_acc_hw_sgl *hw_sgl, u16 sum)
{
hw_sgl->entry_sum_in_chain = cpu_to_le16(sum);
}
/**
* hisi_acc_sg_buf_map_to_hw_sgl - Map a scatterlist to a hw sgl.
* @dev: The device which hw sgl belongs to.
* @sgl: Scatterlist which will be mapped to hw sgl.
* @pool: Pool which hw sgl memory will be allocated in.
* @index: Index of hisi_acc_hw_sgl in pool.
* @hw_sgl_dma: The dma address of allocated hw sgl.
*
* This function builds hw sgl according input sgl, user can use hw_sgl_dma
* as src/dst in its BD. Only support single hw sgl currently.
*/
struct hisi_acc_hw_sgl *
hisi_acc_sg_buf_map_to_hw_sgl(struct device *dev,
struct scatterlist *sgl,
struct hisi_acc_sgl_pool *pool,
u32 index, dma_addr_t *hw_sgl_dma)
{
struct hisi_acc_hw_sgl *curr_hw_sgl;
dma_addr_t curr_sgl_dma = 0;
struct acc_hw_sge *curr_hw_sge;
struct scatterlist *sg;
int i, sg_n, sg_n_mapped;
if (!dev || !sgl || !pool || !hw_sgl_dma)
return ERR_PTR(-EINVAL);
sg_n = sg_nents(sgl);
sg_n_mapped = dma_map_sg(dev, sgl, sg_n, DMA_BIDIRECTIONAL);
if (!sg_n_mapped) {
dev_err(dev, "DMA mapping for SG error!\n");
return ERR_PTR(-EINVAL);
}
if (sg_n_mapped > pool->sge_nr) {
dev_err(dev, "the number of entries in input scatterlist is bigger than SGL pool setting.\n");
return ERR_PTR(-EINVAL);
}
curr_hw_sgl = acc_get_sgl(pool, index, &curr_sgl_dma);
if (IS_ERR(curr_hw_sgl)) {
dev_err(dev, "Get SGL error!\n");
dma_unmap_sg(dev, sgl, sg_n, DMA_BIDIRECTIONAL);
return ERR_PTR(-ENOMEM);
}
curr_hw_sgl->entry_length_in_sgl = cpu_to_le16(pool->sge_nr);
curr_hw_sge = curr_hw_sgl->sge_entries;
for_each_sg(sgl, sg, sg_n_mapped, i) {
sg_map_to_hw_sg(sg, curr_hw_sge);
inc_hw_sgl_sge(curr_hw_sgl);
curr_hw_sge++;
}
update_hw_sgl_sum_sge(curr_hw_sgl, pool->sge_nr);
*hw_sgl_dma = curr_sgl_dma;
return curr_hw_sgl;
}
EXPORT_SYMBOL_GPL(hisi_acc_sg_buf_map_to_hw_sgl);
/**
* hisi_acc_sg_buf_unmap() - Unmap allocated hw sgl.
* @dev: The device which hw sgl belongs to.
* @sgl: Related scatterlist.
* @hw_sgl: Virtual address of hw sgl.
* @hw_sgl_dma: DMA address of hw sgl.
* @pool: Pool which hw sgl is allocated in.
*
* This function unmaps allocated hw sgl.
*/
void hisi_acc_sg_buf_unmap(struct device *dev, struct scatterlist *sgl,
struct hisi_acc_hw_sgl *hw_sgl)
{
if (!dev || !sgl || !hw_sgl)
return;
dma_unmap_sg(dev, sgl, sg_nents(sgl), DMA_BIDIRECTIONAL);
hw_sgl->entry_sum_in_chain = 0;
hw_sgl->entry_sum_in_sgl = 0;
hw_sgl->entry_length_in_sgl = 0;
}
EXPORT_SYMBOL_GPL(hisi_acc_sg_buf_unmap);
MODULE_VERSION("1.3.11");

View File

@ -0,0 +1,37 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/* Copyright (c) 2019 HiSilicon Limited. */
#ifndef HISI_ZIP_H
#define HISI_ZIP_H
#include <linux/list.h>
#include "../qm.h"
#include "zip_usr_if.h"
#undef pr_fmt
#define pr_fmt(fmt) "hisi_zip: " fmt
#define ZIP_WAIT_DELAY 1000
enum hisi_zip_error_type {
/* negative compression */
HZIP_NC_ERR = 0x0d,
};
struct zip_dfx {
atomic64_t send_cnt;
atomic64_t recv_cnt;
atomic64_t send_busy_cnt;
atomic64_t err_bd_cnt;
};
struct hisi_zip_ctrl;
struct hisi_zip {
struct hisi_qm qm;
struct hisi_zip_ctrl *ctrl;
struct zip_dfx dfx;
};
int zip_create_qps(struct hisi_qp **qps, int ctx_num);
int hisi_zip_register_to_crypto(void);
void hisi_zip_unregister_from_crypto(void);
#endif

View File

@ -6,8 +6,19 @@
#include <linux/scatterlist.h>
#include "zip.h"
#define HZIP_ZLIB_HEAD_SIZE 2
#define HZIP_GZIP_HEAD_SIZE 10
/* hisi_zip_sqe dw3 */
#define HZIP_BD_STATUS_M GENMASK(7, 0)
/* hisi_zip_sqe dw7 */
#define HZIP_IN_SGE_DATA_OFFSET_M GENMASK(23, 0)
/* hisi_zip_sqe dw8 */
#define HZIP_OUT_SGE_DATA_OFFSET_M GENMASK(23, 0)
/* hisi_zip_sqe dw9 */
#define HZIP_REQ_TYPE_M GENMASK(7, 0)
#define HZIP_ALG_TYPE_ZLIB 0x02
#define HZIP_ALG_TYPE_GZIP 0x03
#define HZIP_BUF_TYPE_M GENMASK(11, 8)
#define HZIP_PBUFFER 0x0
#define HZIP_SGL 0x1
#define GZIP_HEAD_FHCRC_BIT BIT(1)
#define GZIP_HEAD_FEXTRA_BIT BIT(2)
@ -16,21 +27,32 @@
#define GZIP_HEAD_FLG_SHIFT 3
#define GZIP_HEAD_FEXTRA_SHIFT 10
#define GZIP_HEAD_FEXTRA_XLEN 2
#define GZIP_HEAD_FEXTRA_XLEN 2UL
#define GZIP_HEAD_FHCRC_SIZE 2
#define HZIP_CTX_Q_NUM 2
#define HZIP_ZLIB_HEAD_SIZE 2
#define HZIP_GZIP_HEAD_SIZE 10
#define HZIP_GZIP_HEAD_BUF 256
#define HZIP_ALG_PRIORITY 300
#define HZIP_SGL_SGE_NR 10
#define HZIP_SGL_SGE_MAX 255
static const u8 zlib_head[HZIP_ZLIB_HEAD_SIZE] = {0x78, 0x9c};
static const u8 gzip_head[HZIP_GZIP_HEAD_SIZE] = {0x1f, 0x8b, 0x08, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x03};
static const u8 gzip_head[HZIP_GZIP_HEAD_SIZE] = {
0x1f, 0x8b, 0x08, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x03
};
enum hisi_zip_alg_type {
HZIP_ALG_TYPE_COMP = 0,
HZIP_ALG_TYPE_DECOMP = 1,
};
enum {
QPC_COMP,
QPC_DECOMP,
HZIP_CTX_Q_NUM
};
#define COMP_NAME_TO_TYPE(alg_name) \
(!strcmp((alg_name), "zlib-deflate") ? HZIP_ALG_TYPE_ZLIB : \
!strcmp((alg_name), "gzip") ? HZIP_ALG_TYPE_GZIP : 0) \
@ -41,17 +63,17 @@ enum hisi_zip_alg_type {
#define TO_HEAD(req_type) \
(((req_type) == HZIP_ALG_TYPE_ZLIB) ? zlib_head : \
((req_type) == HZIP_ALG_TYPE_GZIP) ? gzip_head : 0) \
((req_type) == HZIP_ALG_TYPE_GZIP) ? gzip_head : NULL) \
struct hisi_zip_req {
struct acomp_req *req;
int sskip;
int dskip;
u32 sskip;
u32 dskip;
struct hisi_acc_hw_sgl *hw_src;
struct hisi_acc_hw_sgl *hw_dst;
dma_addr_t dma_src;
dma_addr_t dma_dst;
int req_id;
u16 req_id;
};
struct hisi_zip_req_q {
@ -65,17 +87,41 @@ struct hisi_zip_qp_ctx {
struct hisi_qp *qp;
struct hisi_zip_sqe zip_sqe;
struct hisi_zip_req_q req_q;
struct hisi_acc_sgl_pool sgl_pool;
struct hisi_acc_sgl_pool *sgl_pool;
struct hisi_zip *zip_dev;
struct hisi_zip_ctx *ctx;
};
struct hisi_zip_ctx {
#define QPC_COMP 0
#define QPC_DECOMP 1
struct hisi_zip_qp_ctx qp_ctx[HZIP_CTX_Q_NUM];
};
static int sgl_sge_nr_set(const char *val, const struct kernel_param *kp)
{
int ret;
u16 n;
if (!val)
return -EINVAL;
ret = kstrtou16(val, 10, &n);
if (ret || n == 0 || n > HZIP_SGL_SGE_MAX)
return -EINVAL;
return param_set_int(val, kp);
}
static const struct kernel_param_ops sgl_sge_nr_ops = {
.set = sgl_sge_nr_set,
.get = param_get_int,
};
static u16 sgl_sge_nr = HZIP_SGL_SGE_NR;
module_param_cb(sgl_sge_nr, &sgl_sge_nr_ops, &sgl_sge_nr, 0444);
MODULE_PARM_DESC(sgl_sge_nr, "Number of sge in sgl(1-255)");
static DEFINE_MUTEX(hisi_zip_alg_lock);
static unsigned int hisi_zip_active_devs;
static void hisi_zip_config_buf_type(struct hisi_zip_sqe *sqe, u8 buf_type)
{
u32 val;
@ -92,7 +138,7 @@ static void hisi_zip_config_tag(struct hisi_zip_sqe *sqe, u32 tag)
static void hisi_zip_fill_sqe(struct hisi_zip_sqe *sqe, u8 req_type,
dma_addr_t s_addr, dma_addr_t d_addr, u32 slen,
u32 dlen, int sskip, int dskip)
u32 dlen, u32 sskip, u32 dskip)
{
memset(sqe, 0, sizeof(struct hisi_zip_sqe));
@ -107,29 +153,24 @@ static void hisi_zip_fill_sqe(struct hisi_zip_sqe *sqe, u8 req_type,
sqe->dest_addr_h = upper_32_bits(d_addr);
}
static int hisi_zip_create_qp(struct hisi_qm *qm, struct hisi_zip_qp_ctx *ctx,
static int hisi_zip_start_qp(struct hisi_qp *qp, struct hisi_zip_qp_ctx *ctx,
int alg_type, int req_type)
{
struct hisi_qp *qp;
struct device *dev = &qp->qm->pdev->dev;
int ret;
qp = hisi_qm_create_qp(qm, alg_type);
if (IS_ERR(qp))
return PTR_ERR(qp);
qp->req_type = req_type;
qp->alg_type = alg_type;
qp->qp_ctx = ctx;
ctx->qp = qp;
ret = hisi_qm_start_qp(qp, 0);
if (ret < 0)
goto err_release_qp;
if (ret < 0) {
dev_err(dev, "start qp failed!\n");
return ret;
}
ctx->qp = qp;
return 0;
err_release_qp:
hisi_qm_release_qp(qp);
return ret;
}
static void hisi_zip_release_qp(struct hisi_zip_qp_ctx *ctx)
@ -140,34 +181,34 @@ static void hisi_zip_release_qp(struct hisi_zip_qp_ctx *ctx)
static int hisi_zip_ctx_init(struct hisi_zip_ctx *hisi_zip_ctx, u8 req_type)
{
struct hisi_qp *qps[HZIP_CTX_Q_NUM] = { NULL };
struct hisi_zip *hisi_zip;
struct hisi_qm *qm;
int ret, i, j;
/* find the proper zip device */
hisi_zip = find_zip_device(cpu_to_node(smp_processor_id()));
if (!hisi_zip) {
pr_err("Failed to find a proper ZIP device!\n");
ret = zip_create_qps(qps, HZIP_CTX_Q_NUM);
if (ret) {
pr_err("Can not create zip qps!\n");
return -ENODEV;
}
qm = &hisi_zip->qm;
hisi_zip = container_of(qps[0]->qm, struct hisi_zip, qm);
for (i = 0; i < HZIP_CTX_Q_NUM; i++) {
/* alg_type = 0 for compress, 1 for decompress in hw sqe */
ret = hisi_zip_create_qp(qm, &hisi_zip_ctx->qp_ctx[i], i,
ret = hisi_zip_start_qp(qps[i], &hisi_zip_ctx->qp_ctx[i], i,
req_type);
if (ret)
goto err;
if (ret) {
for (j = i - 1; j >= 0; j--)
hisi_qm_stop_qp(hisi_zip_ctx->qp_ctx[j].qp);
hisi_qm_free_qps(qps, HZIP_CTX_Q_NUM);
return ret;
}
hisi_zip_ctx->qp_ctx[i].zip_dev = hisi_zip;
}
return 0;
err:
for (j = i - 1; j >= 0; j--)
hisi_zip_release_qp(&hisi_zip_ctx->qp_ctx[j]);
return ret;
}
static void hisi_zip_ctx_exit(struct hisi_zip_ctx *hisi_zip_ctx)
@ -265,14 +306,15 @@ static void hisi_zip_release_req_q(struct hisi_zip_ctx *ctx)
static int hisi_zip_create_sgl_pool(struct hisi_zip_ctx *ctx)
{
struct hisi_zip_qp_ctx *tmp;
int i, ret;
struct device *dev;
int i;
for (i = 0; i < HZIP_CTX_Q_NUM; i++) {
tmp = &ctx->qp_ctx[i];
ret = hisi_acc_create_sgl_pool(&tmp->qp->qm->pdev->dev,
&tmp->sgl_pool,
QM_Q_DEPTH << 1);
if (ret < 0) {
dev = &tmp->qp->qm->pdev->dev;
tmp->sgl_pool = hisi_acc_create_sgl_pool(dev, QM_Q_DEPTH << 1,
sgl_sge_nr);
if (IS_ERR(tmp->sgl_pool)) {
if (i == 1)
goto err_free_sgl_pool0;
return -ENOMEM;
@ -283,7 +325,7 @@ static int hisi_zip_create_sgl_pool(struct hisi_zip_ctx *ctx)
err_free_sgl_pool0:
hisi_acc_free_sgl_pool(&ctx->qp_ctx[QPC_COMP].qp->qm->pdev->dev,
&ctx->qp_ctx[QPC_COMP].sgl_pool);
ctx->qp_ctx[QPC_COMP].sgl_pool);
return -ENOMEM;
}
@ -293,7 +335,7 @@ static void hisi_zip_release_sgl_pool(struct hisi_zip_ctx *ctx)
for (i = 0; i < HZIP_CTX_Q_NUM; i++)
hisi_acc_free_sgl_pool(&ctx->qp_ctx[i].qp->qm->pdev->dev,
&ctx->qp_ctx[i].sgl_pool);
ctx->qp_ctx[i].sgl_pool);
}
static void hisi_zip_remove_req(struct hisi_zip_qp_ctx *qp_ctx,
@ -311,6 +353,7 @@ static void hisi_zip_acomp_cb(struct hisi_qp *qp, void *data)
{
struct hisi_zip_sqe *sqe = data;
struct hisi_zip_qp_ctx *qp_ctx = qp->qp_ctx;
struct zip_dfx *dfx = &qp_ctx->zip_dev->dfx;
struct hisi_zip_req_q *req_q = &qp_ctx->req_q;
struct hisi_zip_req *req = req_q->q + sqe->tag;
struct acomp_req *acomp_req = req->req;
@ -318,12 +361,13 @@ static void hisi_zip_acomp_cb(struct hisi_qp *qp, void *data)
u32 status, dlen, head_size;
int err = 0;
atomic64_inc(&dfx->recv_cnt);
status = sqe->dw3 & HZIP_BD_STATUS_M;
if (status != 0 && status != HZIP_NC_ERR) {
dev_err(dev, "%scompress fail in qp%u: %u, output: %u\n",
(qp->alg_type == 0) ? "" : "de", qp->qp_id, status,
sqe->produced);
atomic64_inc(&dfx->err_bd_cnt);
err = -EIO;
}
dlen = sqe->produced;
@ -353,19 +397,27 @@ static int hisi_zip_acomp_init(struct crypto_acomp *tfm)
{
const char *alg_name = crypto_tfm_alg_name(&tfm->base);
struct hisi_zip_ctx *ctx = crypto_tfm_ctx(&tfm->base);
struct device *dev;
int ret;
ret = hisi_zip_ctx_init(ctx, COMP_NAME_TO_TYPE(alg_name));
if (ret)
if (ret) {
pr_err("Init ctx failed!\n");
return ret;
}
dev = &ctx->qp_ctx[0].qp->qm->pdev->dev;
ret = hisi_zip_create_req_q(ctx);
if (ret)
if (ret) {
dev_err(dev, "Create request queue failed!\n ");
goto err_ctx_exit;
}
ret = hisi_zip_create_sgl_pool(ctx);
if (ret)
if (ret) {
dev_err(dev, "Create sgl pool failed!\n ");
goto err_release_req_q;
}
hisi_zip_set_acomp_cb(ctx, hisi_zip_acomp_cb);
@ -395,13 +447,15 @@ static int add_comp_head(struct scatterlist *dst, u8 req_type)
int ret;
ret = sg_copy_from_buffer(dst, sg_nents(dst), head, head_size);
if (ret != head_size)
if (ret != head_size) {
pr_err("The head size of buffer is wrong!\n");
return -ENOMEM;
}
return head_size;
}
static size_t get_gzip_head_size(struct scatterlist *sgl)
static size_t __maybe_unused get_gzip_head_size(struct scatterlist *sgl)
{
char buf[HZIP_GZIP_HEAD_BUF];
@ -410,13 +464,20 @@ static size_t get_gzip_head_size(struct scatterlist *sgl)
return __get_gzip_head_size(buf);
}
static size_t get_comp_head_size(struct scatterlist *src, u8 req_type)
static int get_comp_head_size(struct acomp_req *acomp_req, u8 req_type)
{
if (!acomp_req->src || !acomp_req->slen)
return -EINVAL;
if ((req_type == HZIP_ALG_TYPE_GZIP) &&
(acomp_req->slen < GZIP_HEAD_FEXTRA_SHIFT))
return -EINVAL;
switch (req_type) {
case HZIP_ALG_TYPE_ZLIB:
return TO_HEAD_SIZE(HZIP_ALG_TYPE_ZLIB);
case HZIP_ALG_TYPE_GZIP:
return get_gzip_head_size(src);
return TO_HEAD_SIZE(HZIP_ALG_TYPE_GZIP);
default:
pr_err("request type does not support!\n");
return -EINVAL;
@ -438,7 +499,7 @@ static struct hisi_zip_req *hisi_zip_create_req(struct acomp_req *req,
if (req_id >= req_q->size) {
write_unlock(&req_q->req_lock);
dev_dbg(&qp_ctx->qp->qm->pdev->dev, "req cache is full!\n");
return ERR_PTR(-EBUSY);
return ERR_PTR(-EPERM);
}
set_bit(req_id, req_q->req_bitmap);
@ -466,7 +527,8 @@ static int hisi_zip_do_work(struct hisi_zip_req *req,
struct acomp_req *a_req = req->req;
struct hisi_qp *qp = qp_ctx->qp;
struct device *dev = &qp->qm->pdev->dev;
struct hisi_acc_sgl_pool *pool = &qp_ctx->sgl_pool;
struct hisi_acc_sgl_pool *pool = qp_ctx->sgl_pool;
struct zip_dfx *dfx = &qp_ctx->zip_dev->dfx;
dma_addr_t input;
dma_addr_t output;
int ret;
@ -476,14 +538,17 @@ static int hisi_zip_do_work(struct hisi_zip_req *req,
req->hw_src = hisi_acc_sg_buf_map_to_hw_sgl(dev, a_req->src, pool,
req->req_id << 1, &input);
if (IS_ERR(req->hw_src))
if (IS_ERR(req->hw_src)) {
dev_err(dev, "the src map to hw SGL failed!\n");
return PTR_ERR(req->hw_src);
}
req->dma_src = input;
req->hw_dst = hisi_acc_sg_buf_map_to_hw_sgl(dev, a_req->dst, pool,
(req->req_id << 1) + 1,
&output);
if (IS_ERR(req->hw_dst)) {
dev_err(dev, "the dst map to hw SGL failed!\n");
ret = PTR_ERR(req->hw_dst);
goto err_unmap_input;
}
@ -495,9 +560,14 @@ static int hisi_zip_do_work(struct hisi_zip_req *req,
hisi_zip_config_tag(zip_sqe, req->req_id);
/* send command to start a task */
atomic64_inc(&dfx->send_cnt);
ret = hisi_qp_send(qp, zip_sqe);
if (ret < 0)
if (ret < 0) {
atomic64_inc(&dfx->send_busy_cnt);
ret = -EPERM;
dev_dbg_ratelimited(dev, "send task message failed!\n");
goto err_unmap_output;
}
return -EINPROGRESS;
@ -512,6 +582,7 @@ static int hisi_zip_acompress(struct acomp_req *acomp_req)
{
struct hisi_zip_ctx *ctx = crypto_tfm_ctx(acomp_req->base.tfm);
struct hisi_zip_qp_ctx *qp_ctx = &ctx->qp_ctx[QPC_COMP];
struct device *dev = &qp_ctx->qp->qm->pdev->dev;
struct hisi_zip_req *req;
int head_size;
int ret;
@ -521,13 +592,17 @@ static int hisi_zip_acompress(struct acomp_req *acomp_req)
if (head_size < 0)
return -ENOMEM;
req = hisi_zip_create_req(acomp_req, qp_ctx, (size_t)head_size, true);
if (IS_ERR(req))
req = hisi_zip_create_req(acomp_req, qp_ctx, head_size, true);
if (IS_ERR(req)) {
dev_err_ratelimited(dev, "create request before compress failed!\n");
return PTR_ERR(req);
}
ret = hisi_zip_do_work(req, qp_ctx);
if (ret != -EINPROGRESS)
if (ret != -EINPROGRESS) {
dev_err_ratelimited(dev, "do compress work failed!\n");
hisi_zip_remove_req(qp_ctx, req);
}
return ret;
}
@ -536,19 +611,26 @@ static int hisi_zip_adecompress(struct acomp_req *acomp_req)
{
struct hisi_zip_ctx *ctx = crypto_tfm_ctx(acomp_req->base.tfm);
struct hisi_zip_qp_ctx *qp_ctx = &ctx->qp_ctx[QPC_DECOMP];
struct device *dev = &qp_ctx->qp->qm->pdev->dev;
struct hisi_zip_req *req;
size_t head_size;
int head_size;
int ret;
head_size = get_comp_head_size(acomp_req->src, qp_ctx->qp->req_type);
head_size = get_comp_head_size(acomp_req, qp_ctx->qp->req_type);
if (head_size < 0)
return -ENOMEM;
req = hisi_zip_create_req(acomp_req, qp_ctx, head_size, false);
if (IS_ERR(req))
if (IS_ERR(req)) {
dev_err_ratelimited(dev, "create request before decompress failed!\n");
return PTR_ERR(req);
}
ret = hisi_zip_do_work(req, qp_ctx);
if (ret != -EINPROGRESS)
if (ret != -EINPROGRESS) {
dev_err_ratelimited(dev, "do decompress work failed!\n");
hisi_zip_remove_req(qp_ctx, req);
}
return ret;
}
@ -585,23 +667,32 @@ int hisi_zip_register_to_crypto(void)
{
int ret = 0;
ret = crypto_register_acomp(&hisi_zip_acomp_zlib);
if (ret) {
pr_err("Zlib acomp algorithm registration failed\n");
return ret;
}
ret = crypto_register_acomp(&hisi_zip_acomp_gzip);
if (ret) {
pr_err("Gzip acomp algorithm registration failed\n");
crypto_unregister_acomp(&hisi_zip_acomp_zlib);
mutex_lock(&hisi_zip_alg_lock);
if (++hisi_zip_active_devs == 1) {
ret = crypto_register_acomp(&hisi_zip_acomp_zlib);
if (ret) {
pr_err("Zlib acomp algorithm registration failed\n");
goto err_unlock;
}
ret = crypto_register_acomp(&hisi_zip_acomp_gzip);
if (ret) {
pr_err("Gzip acomp algorithm registration failed\n");
crypto_unregister_acomp(&hisi_zip_acomp_zlib);
}
}
err_unlock:
mutex_unlock(&hisi_zip_alg_lock);
return ret;
}
void hisi_zip_unregister_from_crypto(void)
{
crypto_unregister_acomp(&hisi_zip_acomp_gzip);
crypto_unregister_acomp(&hisi_zip_acomp_zlib);
mutex_lock(&hisi_zip_alg_lock);
if (--hisi_zip_active_devs == 0) {
crypto_unregister_acomp(&hisi_zip_acomp_gzip);
crypto_unregister_acomp(&hisi_zip_acomp_zlib);
}
mutex_unlock(&hisi_zip_alg_lock);
}

View File

@ -0,0 +1,47 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* Copyright (c) 2018-2019 HiSilicon Limited.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
*/
#ifndef HISI_ZIP_USR_IF_H
#define HISI_ZIP_USR_IF_H
struct hisi_zip_sqe {
__u32 consumed;
__u32 produced;
__u32 comp_data_length;
__u32 dw3;
__u32 input_data_length;
__u32 lba_l;
__u32 lba_h;
__u32 dw7;
__u32 dw8;
__u32 dw9;
__u32 dw10;
__u32 priv_info;
__u32 dw12;
__u32 tag;
__u32 dest_avail_out;
__u32 rsvd0;
__u32 comp_head_addr_l;
__u32 comp_head_addr_h;
__u32 source_addr_l;
__u32 source_addr_h;
__u32 dest_addr_l;
__u32 dest_addr_h;
__u32 stream_ctx_addr_l;
__u32 stream_ctx_addr_h;
__u32 cipher_key1_addr_l;
__u32 cipher_key1_addr_h;
__u32 cipher_key2_addr_l;
__u32 cipher_key2_addr_h;
__u32 rsvd1[4];
};
#endif

View File

@ -0,0 +1,25 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/* Copyright (c) 2018-2019 HiSilicon Limited. */
#ifndef __ACC_COMPAT_H
#define __ACC_COMPAT_H
#include <linux/pci-dma-compat.h>
#define CONFIG_CRYPTO_QM_UACCE 1
#ifndef pci_emerg
#define pci_emerg(pdev, fmt, arg...) dev_emerg(&(pdev)->dev, fmt, ##arg)
#endif
#ifndef pci_err
#define pci_err(pdev, fmt, arg...) dev_err(&(pdev)->dev, fmt, ##arg)
#endif
#ifndef pci_warn
#define pci_warn(pdev, fmt, arg...) dev_warn(&(pdev)->dev, fmt, ##arg)
#endif
#ifndef pci_info
#define pci_info(pdev, fmt, arg...) dev_info(&(pdev)->dev, fmt, ##arg)
#endif
#endif

View File

@ -0,0 +1,135 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/* Copyright (c) 2018-2019 HiSilicon Limited. */
#ifndef __UACCE_H
#define __UACCE_H
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/fs.h>
#include <linux/list.h>
#include <linux/iommu.h>
#include "../include_uapi_linux/uacce.h"
struct uacce_queue;
struct uacce;
#define UACCE_QFRF_MMAP BIT(0) /* map to user space */
#define UACCE_QFRF_DMA BIT(1) /* use dma api for the region */
#define UACCE_QFRF_SELFMT BIT(2) /* self maintained qfr */
struct uacce_hw_err {
struct list_head list;
unsigned long long tick_stamp;
};
struct uacce_err_isolate {
struct list_head hw_errs;
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 */
u32 size; /* Size of this dma slice */
u32 total_num; /* Total slices in this dma list */
};
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;
};
/**
* struct uacce_ops - WD device operations
* @get_queue: get a queue from the device according to algorithm
* @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 WD device
* @reset_queue: reset the queue
* @ioctl: ioctl for user space users of the queue
*/
struct uacce_ops {
int (*get_available_instances)(struct uacce *uacce);
int (*get_queue)(struct uacce *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 *uacce);
int (*reset_queue)(struct uacce_queue *q);
long (*ioctl)(struct uacce_queue *q, unsigned int cmd,
unsigned long arg);
enum uacce_dev_state (*get_dev_state)(struct uacce *uacce);
};
enum uacce_dev_state {
UACCE_DEV_ERR = -1,
UACCE_DEV_NORMAL,
};
enum uacce_q_state {
UACCE_Q_INIT,
UACCE_Q_STARTED,
UACCE_Q_ZOMBIE,
UACCE_Q_CLOSED,
};
struct uacce_queue {
struct uacce *uacce;
__u32 flags;
atomic_t status;
void *priv;
wait_queue_head_t wait;
int pasid;
struct list_head list; /* as list for as->qs */
struct mm_struct *mm;
struct uacce_qfile_region *qfrs[UACCE_QFRT_MAX];
struct fasync_struct *async_queue;
struct file *filep;
enum uacce_q_state state;
};
struct uacce {
const char *name;
const char *drv_name;
const char *algs;
const char *api_ver;
unsigned long qf_pg_start[UACCE_QFRT_MAX];
int status;
unsigned int flags;
struct uacce_ops *ops;
struct device *pdev;
bool is_vf;
u32 dev_id;
struct cdev cdev;
struct device dev;
void *priv;
atomic_t ref;
int prot;
struct uacce_err_isolate isolate_data;
struct uacce_err_isolate *isolate;
};
int uacce_register(struct uacce *uacce);
int uacce_unregister(struct uacce *uacce);
void uacce_wake_up(struct uacce_queue *q);
const char *uacce_qfrt_str(struct uacce_qfile_region *qfr);
struct uacce *dev_to_uacce(struct device *dev);
int uacce_hw_err_isolate(struct uacce *uacce);
#endif

View File

@ -0,0 +1,57 @@
/* 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"
#define UACCE_DEV_ATTRS "attrs"
#define UACCE_CMD_SHARE_SVAS _IO('W', 0)
#define UACCE_CMD_START _IO('W', 1)
#define UACCE_CMD_GET_SS_DMA _IOR('W', 2, unsigned long)
#define UACCE_CMD_PUT_Q _IO('W', 3)
/**
* UACCE Device Attributes:
*
* NOIOMMU: the device has no IOMMU support
* can do ssva, but no map to the dev
* 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_NOIOMMU (1 << 0)
#define UACCE_DEV_PASID (1 << 1)
#define UACCE_DEV_FAULT_FROM_DEV (1 << 2)
#define UACCE_DEV_SVA (UACCE_DEV_PASID | UACCE_DEV_FAULT_FROM_DEV)
#define UACCE_DEV_SHARE_DOMAIN (0)
/* uacce mode of the driver */
#define UACCE_MODE_NOUACCE 0 /* don't use uacce */
#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 {
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

File diff suppressed because it is too large Load Diff

View File

@ -1,215 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0 */
/* Copyright (c) 2019 HiSilicon Limited. */
#ifndef HISI_ACC_QM_H
#define HISI_ACC_QM_H
#include <linux/bitfield.h>
#include <linux/iopoll.h>
#include <linux/module.h>
#include <linux/pci.h>
/* qm user domain */
#define QM_ARUSER_M_CFG_1 0x100088
#define AXUSER_SNOOP_ENABLE BIT(30)
#define AXUSER_CMD_TYPE GENMASK(14, 12)
#define AXUSER_CMD_SMMU_NORMAL 1
#define AXUSER_NS BIT(6)
#define AXUSER_NO BIT(5)
#define AXUSER_FP BIT(4)
#define AXUSER_SSV BIT(0)
#define AXUSER_BASE (AXUSER_SNOOP_ENABLE | \
FIELD_PREP(AXUSER_CMD_TYPE, \
AXUSER_CMD_SMMU_NORMAL) | \
AXUSER_NS | AXUSER_NO | AXUSER_FP)
#define QM_ARUSER_M_CFG_ENABLE 0x100090
#define ARUSER_M_CFG_ENABLE 0xfffffffe
#define QM_AWUSER_M_CFG_1 0x100098
#define QM_AWUSER_M_CFG_ENABLE 0x1000a0
#define AWUSER_M_CFG_ENABLE 0xfffffffe
#define QM_WUSER_M_CFG_ENABLE 0x1000a8
#define WUSER_M_CFG_ENABLE 0xffffffff
/* qm cache */
#define QM_CACHE_CTL 0x100050
#define SQC_CACHE_ENABLE BIT(0)
#define CQC_CACHE_ENABLE BIT(1)
#define SQC_CACHE_WB_ENABLE BIT(4)
#define SQC_CACHE_WB_THRD GENMASK(10, 5)
#define CQC_CACHE_WB_ENABLE BIT(11)
#define CQC_CACHE_WB_THRD GENMASK(17, 12)
#define QM_AXI_M_CFG 0x1000ac
#define AXI_M_CFG 0xffff
#define QM_AXI_M_CFG_ENABLE 0x1000b0
#define AXI_M_CFG_ENABLE 0xffffffff
#define QM_PEH_AXUSER_CFG 0x1000cc
#define QM_PEH_AXUSER_CFG_ENABLE 0x1000d0
#define PEH_AXUSER_CFG 0x401001
#define PEH_AXUSER_CFG_ENABLE 0xffffffff
#define QM_DFX_MB_CNT_VF 0x104010
#define QM_DFX_DB_CNT_VF 0x104020
#define QM_DFX_SQE_CNT_VF_SQN 0x104030
#define QM_DFX_CQE_CNT_VF_CQN 0x104040
#define QM_DFX_QN_SHIFT 16
#define CURRENT_FUN_MASK GENMASK(5, 0)
#define CURRENT_Q_MASK GENMASK(31, 16)
#define QM_AXI_RRESP BIT(0)
#define QM_AXI_BRESP BIT(1)
#define QM_ECC_MBIT BIT(2)
#define QM_ECC_1BIT BIT(3)
#define QM_ACC_GET_TASK_TIMEOUT BIT(4)
#define QM_ACC_DO_TASK_TIMEOUT BIT(5)
#define QM_ACC_WB_NOT_READY_TIMEOUT BIT(6)
#define QM_SQ_CQ_VF_INVALID BIT(7)
#define QM_CQ_VF_INVALID BIT(8)
#define QM_SQ_VF_INVALID BIT(9)
#define QM_DB_TIMEOUT BIT(10)
#define QM_OF_FIFO_OF BIT(11)
#define QM_DB_RANDOM_INVALID BIT(12)
#define QM_BASE_NFE (QM_AXI_RRESP | QM_AXI_BRESP | QM_ECC_MBIT | \
QM_ACC_GET_TASK_TIMEOUT | QM_DB_TIMEOUT | \
QM_OF_FIFO_OF)
#define QM_BASE_CE QM_ECC_1BIT
#define QM_Q_DEPTH 1024
enum qp_state {
QP_STOP,
};
enum qm_hw_ver {
QM_HW_UNKNOWN = -1,
QM_HW_V1 = 0x20,
QM_HW_V2 = 0x21,
};
enum qm_fun_type {
QM_HW_PF,
QM_HW_VF,
};
enum qm_debug_file {
CURRENT_Q,
CLEAR_ENABLE,
DEBUG_FILE_NUM,
};
struct debugfs_file {
enum qm_debug_file index;
struct mutex lock;
struct qm_debug *debug;
};
struct qm_debug {
u32 curr_qm_qp_num;
struct dentry *debug_root;
struct dentry *qm_d;
struct debugfs_file files[DEBUG_FILE_NUM];
};
struct qm_dma {
void *va;
dma_addr_t dma;
size_t size;
};
struct hisi_qm_status {
u32 eq_head;
bool eqc_phase;
u32 aeq_head;
bool aeqc_phase;
unsigned long flags;
};
struct hisi_qm {
enum qm_hw_ver ver;
enum qm_fun_type fun_type;
const char *dev_name;
struct pci_dev *pdev;
void __iomem *io_base;
u32 sqe_size;
u32 qp_base;
u32 qp_num;
u32 ctrl_qp_num;
struct qm_dma qdma;
struct qm_sqc *sqc;
struct qm_cqc *cqc;
struct qm_eqe *eqe;
struct qm_aeqe *aeqe;
dma_addr_t sqc_dma;
dma_addr_t cqc_dma;
dma_addr_t eqe_dma;
dma_addr_t aeqe_dma;
struct hisi_qm_status status;
rwlock_t qps_lock;
unsigned long *qp_bitmap;
struct hisi_qp **qp_array;
struct mutex mailbox_lock;
const struct hisi_qm_hw_ops *ops;
struct qm_debug debug;
u32 error_mask;
u32 msi_mask;
bool use_dma_api;
};
struct hisi_qp_status {
atomic_t used;
u16 sq_tail;
u16 cq_head;
bool cqc_phase;
unsigned long flags;
};
struct hisi_qp_ops {
int (*fill_sqe)(void *sqe, void *q_parm, void *d_parm);
};
struct hisi_qp {
u32 qp_id;
u8 alg_type;
u8 req_type;
struct qm_dma qdma;
void *sqe;
struct qm_cqe *cqe;
dma_addr_t sqe_dma;
dma_addr_t cqe_dma;
struct hisi_qp_status qp_status;
struct hisi_qp_ops *hw_ops;
void *qp_ctx;
void (*req_cb)(struct hisi_qp *qp, void *data);
struct work_struct work;
struct workqueue_struct *wq;
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);
int hisi_qm_stop(struct hisi_qm *qm);
struct hisi_qp *hisi_qm_create_qp(struct hisi_qm *qm, u8 alg_type);
int hisi_qm_start_qp(struct hisi_qp *qp, unsigned long arg);
int hisi_qm_stop_qp(struct hisi_qp *qp);
void hisi_qm_release_qp(struct hisi_qp *qp);
int hisi_qp_send(struct hisi_qp *qp, const void *msg);
int hisi_qm_get_vft(struct hisi_qm *qm, u32 *base, u32 *number);
int hisi_qm_set_vft(struct hisi_qm *qm, u32 fun_num, u32 base, u32 number);
int hisi_qm_debug_init(struct hisi_qm *qm);
void hisi_qm_hw_error_init(struct hisi_qm *qm, u32 ce, u32 nfe, u32 fe,
u32 msi);
int hisi_qm_hw_error_handle(struct hisi_qm *qm);
enum qm_hw_ver hisi_qm_get_hw_version(struct pci_dev *pdev);
void hisi_qm_debug_regs_clear(struct hisi_qm *qm);
#endif

View File

@ -1,3 +0,0 @@
# SPDX-License-Identifier: GPL-2.0
obj-$(CONFIG_CRYPTO_DEV_HISI_SEC) += hisi_sec.o
hisi_sec-y = sec_algs.o sec_drv.o

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,428 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0 */
/* Copyright (c) 2016-2017 Hisilicon Limited. */
#ifndef _SEC_DRV_H_
#define _SEC_DRV_H_
#include <crypto/algapi.h>
#include <linux/kfifo.h>
#define SEC_MAX_SGE_NUM 64
#define SEC_HW_RING_NUM 3
#define SEC_CMD_RING 0
#define SEC_OUTORDER_RING 1
#define SEC_DBG_RING 2
/* A reasonable length to balance memory use against flexibility */
#define SEC_QUEUE_LEN 512
#define SEC_MAX_SGE_NUM 64
struct sec_bd_info {
#define SEC_BD_W0_T_LEN_M GENMASK(4, 0)
#define SEC_BD_W0_T_LEN_S 0
#define SEC_BD_W0_C_WIDTH_M GENMASK(6, 5)
#define SEC_BD_W0_C_WIDTH_S 5
#define SEC_C_WIDTH_AES_128BIT 0
#define SEC_C_WIDTH_AES_8BIT 1
#define SEC_C_WIDTH_AES_1BIT 2
#define SEC_C_WIDTH_DES_64BIT 0
#define SEC_C_WIDTH_DES_8BIT 1
#define SEC_C_WIDTH_DES_1BIT 2
#define SEC_BD_W0_C_MODE_M GENMASK(9, 7)
#define SEC_BD_W0_C_MODE_S 7
#define SEC_C_MODE_ECB 0
#define SEC_C_MODE_CBC 1
#define SEC_C_MODE_CTR 4
#define SEC_C_MODE_CCM 5
#define SEC_C_MODE_GCM 6
#define SEC_C_MODE_XTS 7
#define SEC_BD_W0_SEQ BIT(10)
#define SEC_BD_W0_DE BIT(11)
#define SEC_BD_W0_DAT_SKIP_M GENMASK(13, 12)
#define SEC_BD_W0_DAT_SKIP_S 12
#define SEC_BD_W0_C_GRAN_SIZE_19_16_M GENMASK(17, 14)
#define SEC_BD_W0_C_GRAN_SIZE_19_16_S 14
#define SEC_BD_W0_CIPHER_M GENMASK(19, 18)
#define SEC_BD_W0_CIPHER_S 18
#define SEC_CIPHER_NULL 0
#define SEC_CIPHER_ENCRYPT 1
#define SEC_CIPHER_DECRYPT 2
#define SEC_BD_W0_AUTH_M GENMASK(21, 20)
#define SEC_BD_W0_AUTH_S 20
#define SEC_AUTH_NULL 0
#define SEC_AUTH_MAC 1
#define SEC_AUTH_VERIF 2
#define SEC_BD_W0_AI_GEN BIT(22)
#define SEC_BD_W0_CI_GEN BIT(23)
#define SEC_BD_W0_NO_HPAD BIT(24)
#define SEC_BD_W0_HM_M GENMASK(26, 25)
#define SEC_BD_W0_HM_S 25
#define SEC_BD_W0_ICV_OR_SKEY_EN_M GENMASK(28, 27)
#define SEC_BD_W0_ICV_OR_SKEY_EN_S 27
/* Multi purpose field - gran size bits for send, flag for recv */
#define SEC_BD_W0_FLAG_M GENMASK(30, 29)
#define SEC_BD_W0_C_GRAN_SIZE_21_20_M GENMASK(30, 29)
#define SEC_BD_W0_FLAG_S 29
#define SEC_BD_W0_C_GRAN_SIZE_21_20_S 29
#define SEC_BD_W0_DONE BIT(31)
u32 w0;
#define SEC_BD_W1_AUTH_GRAN_SIZE_M GENMASK(21, 0)
#define SEC_BD_W1_AUTH_GRAN_SIZE_S 0
#define SEC_BD_W1_M_KEY_EN BIT(22)
#define SEC_BD_W1_BD_INVALID BIT(23)
#define SEC_BD_W1_ADDR_TYPE BIT(24)
#define SEC_BD_W1_A_ALG_M GENMASK(28, 25)
#define SEC_BD_W1_A_ALG_S 25
#define SEC_A_ALG_SHA1 0
#define SEC_A_ALG_SHA256 1
#define SEC_A_ALG_MD5 2
#define SEC_A_ALG_SHA224 3
#define SEC_A_ALG_HMAC_SHA1 8
#define SEC_A_ALG_HMAC_SHA224 10
#define SEC_A_ALG_HMAC_SHA256 11
#define SEC_A_ALG_HMAC_MD5 12
#define SEC_A_ALG_AES_XCBC 13
#define SEC_A_ALG_AES_CMAC 14
#define SEC_BD_W1_C_ALG_M GENMASK(31, 29)
#define SEC_BD_W1_C_ALG_S 29
#define SEC_C_ALG_DES 0
#define SEC_C_ALG_3DES 1
#define SEC_C_ALG_AES 2
u32 w1;
#define SEC_BD_W2_C_GRAN_SIZE_15_0_M GENMASK(15, 0)
#define SEC_BD_W2_C_GRAN_SIZE_15_0_S 0
#define SEC_BD_W2_GRAN_NUM_M GENMASK(31, 16)
#define SEC_BD_W2_GRAN_NUM_S 16
u32 w2;
#define SEC_BD_W3_AUTH_LEN_OFFSET_M GENMASK(9, 0)
#define SEC_BD_W3_AUTH_LEN_OFFSET_S 0
#define SEC_BD_W3_CIPHER_LEN_OFFSET_M GENMASK(19, 10)
#define SEC_BD_W3_CIPHER_LEN_OFFSET_S 10
#define SEC_BD_W3_MAC_LEN_M GENMASK(24, 20)
#define SEC_BD_W3_MAC_LEN_S 20
#define SEC_BD_W3_A_KEY_LEN_M GENMASK(29, 25)
#define SEC_BD_W3_A_KEY_LEN_S 25
#define SEC_BD_W3_C_KEY_LEN_M GENMASK(31, 30)
#define SEC_BD_W3_C_KEY_LEN_S 30
#define SEC_KEY_LEN_AES_128 0
#define SEC_KEY_LEN_AES_192 1
#define SEC_KEY_LEN_AES_256 2
#define SEC_KEY_LEN_DES 1
#define SEC_KEY_LEN_3DES_3_KEY 1
#define SEC_KEY_LEN_3DES_2_KEY 3
u32 w3;
/* W4,5 */
union {
u32 authkey_addr_lo;
u32 authiv_addr_lo;
};
union {
u32 authkey_addr_hi;
u32 authiv_addr_hi;
};
/* W6,7 */
u32 cipher_key_addr_lo;
u32 cipher_key_addr_hi;
/* W8,9 */
u32 cipher_iv_addr_lo;
u32 cipher_iv_addr_hi;
/* W10,11 */
u32 data_addr_lo;
u32 data_addr_hi;
/* W12,13 */
u32 mac_addr_lo;
u32 mac_addr_hi;
/* W14,15 */
u32 cipher_destin_addr_lo;
u32 cipher_destin_addr_hi;
};
enum sec_mem_region {
SEC_COMMON = 0,
SEC_SAA,
SEC_NUM_ADDR_REGIONS
};
#define SEC_NAME_SIZE 64
#define SEC_Q_NUM 16
/**
* struct sec_queue_ring_cmd - store information about a SEC HW cmd ring
* @used: Local counter used to cheaply establish if the ring is empty.
* @lock: Protect against simultaneous adjusting of the read and write pointers.
* @vaddr: Virtual address for the ram pages used for the ring.
* @paddr: Physical address of the dma mapped region of ram used for the ring.
* @callback: Callback function called on a ring element completing.
*/
struct sec_queue_ring_cmd {
atomic_t used;
struct mutex lock;
struct sec_bd_info *vaddr;
dma_addr_t paddr;
void (*callback)(struct sec_bd_info *resp, void *ctx);
};
struct sec_debug_bd_info;
struct sec_queue_ring_db {
struct sec_debug_bd_info *vaddr;
dma_addr_t paddr;
};
struct sec_out_bd_info;
struct sec_queue_ring_cq {
struct sec_out_bd_info *vaddr;
dma_addr_t paddr;
};
struct sec_dev_info;
enum sec_cipher_alg {
SEC_C_DES_ECB_64,
SEC_C_DES_CBC_64,
SEC_C_3DES_ECB_192_3KEY,
SEC_C_3DES_ECB_192_2KEY,
SEC_C_3DES_CBC_192_3KEY,
SEC_C_3DES_CBC_192_2KEY,
SEC_C_AES_ECB_128,
SEC_C_AES_ECB_192,
SEC_C_AES_ECB_256,
SEC_C_AES_CBC_128,
SEC_C_AES_CBC_192,
SEC_C_AES_CBC_256,
SEC_C_AES_CTR_128,
SEC_C_AES_CTR_192,
SEC_C_AES_CTR_256,
SEC_C_AES_XTS_128,
SEC_C_AES_XTS_256,
SEC_C_NULL,
};
/**
* struct sec_alg_tfm_ctx - hardware specific tranformation context
* @cipher_alg: Cipher algorithm enabled include encryption mode.
* @key: Key storage if required.
* @pkey: DMA address for the key storage.
* @req_template: Request template to save time on setup.
* @queue: The hardware queue associated with this tfm context.
* @lock: Protect key and pkey to ensure they are consistent
* @auth_buf: Current context buffer for auth operations.
* @backlog: The backlog queue used for cases where our buffers aren't
* large enough.
*/
struct sec_alg_tfm_ctx {
enum sec_cipher_alg cipher_alg;
u8 *key;
dma_addr_t pkey;
struct sec_bd_info req_template;
struct sec_queue *queue;
struct mutex lock;
u8 *auth_buf;
struct list_head backlog;
};
/**
* struct sec_request - data associate with a single crypto request
* @elements: List of subparts of this request (hardware size restriction)
* @num_elements: The number of subparts (used as an optimization)
* @lock: Protect elements of this structure against concurrent change.
* @tfm_ctx: hardware specific context.
* @len_in: length of in sgl from upper layers
* @len_out: length of out sgl from upper layers
* @dma_iv: initialization vector - phsyical address
* @err: store used to track errors across subelements of this request.
* @req_base: pointer to base element of associate crypto context.
* This is needed to allow shared handling skcipher, ahash etc.
* @cb: completion callback.
* @backlog_head: list head to allow backlog maintenance.
*
* The hardware is limited in the maximum size of data that it can
* process from a single BD. Typically this is fairly large (32MB)
* but still requires the complexity of splitting the incoming
* skreq up into a number of elements complete with appropriate
* iv chaining.
*/
struct sec_request {
struct list_head elements;
int num_elements;
struct mutex lock;
struct sec_alg_tfm_ctx *tfm_ctx;
int len_in;
int len_out;
dma_addr_t dma_iv;
int err;
struct crypto_async_request *req_base;
void (*cb)(struct sec_bd_info *resp, struct crypto_async_request *req);
struct list_head backlog_head;
};
/**
* struct sec_request_el - A subpart of a request.
* @head: allow us to attach this to the list in the sec_request
* @req: hardware block descriptor corresponding to this request subpart
* @in: hardware sgl for input - virtual address
* @dma_in: hardware sgl for input - physical address
* @sgl_in: scatterlist for this request subpart
* @out: hardware sgl for output - virtual address
* @dma_out: hardware sgl for output - physical address
* @sgl_out: scatterlist for this request subpart
* @sec_req: The request which this subpart forms a part of
* @el_length: Number of bytes in this subpart. Needed to locate
* last ivsize chunk for iv chaining.
*/
struct sec_request_el {
struct list_head head;
struct sec_bd_info req;
struct sec_hw_sgl *in;
dma_addr_t dma_in;
struct scatterlist *sgl_in;
struct sec_hw_sgl *out;
dma_addr_t dma_out;
struct scatterlist *sgl_out;
struct sec_request *sec_req;
size_t el_length;
};
/**
* struct sec_queue - All the information about a HW queue
* @dev_info: The parent SEC device to which this queue belongs.
* @task_irq: Completion interrupt for the queue.
* @name: Human readable queue description also used as irq name.
* @ring: The several HW rings associated with one queue.
* @regs: The iomapped device registers
* @queue_id: Index of the queue used for naming and resource selection.
* @in_use: Flag to say if the queue is in use.
* @expected: The next expected element to finish assuming we were in order.
* @uprocessed: A bitmap to track which OoO elements are done but not handled.
* @softqueue: A software queue used when chaining requirements prevent direct
* use of the hardware queues.
* @havesoftqueue: A flag to say we have a queues - as we may need one for the
* current mode.
* @queuelock: Protect the soft queue from concurrent changes to avoid some
* potential loss of data races.
* @shadow: Pointers back to the shadow copy of the hardware ring element
* need because we can't store any context reference in the bd element.
*/
struct sec_queue {
struct sec_dev_info *dev_info;
int task_irq;
char name[SEC_NAME_SIZE];
struct sec_queue_ring_cmd ring_cmd;
struct sec_queue_ring_cq ring_cq;
struct sec_queue_ring_db ring_db;
void __iomem *regs;
u32 queue_id;
bool in_use;
int expected;
DECLARE_BITMAP(unprocessed, SEC_QUEUE_LEN);
DECLARE_KFIFO_PTR(softqueue, typeof(struct sec_request_el *));
bool havesoftqueue;
struct mutex queuelock;
void *shadow[SEC_QUEUE_LEN];
};
/**
* struct sec_hw_sge: Track each of the 64 element SEC HW SGL entries
* @buf: The IOV dma address for this entry.
* @len: Length of this IOV.
* @pad: Reserved space.
*/
struct sec_hw_sge {
dma_addr_t buf;
unsigned int len;
unsigned int pad;
};
/**
* struct sec_hw_sgl: One hardware SGL entry.
* @next_sgl: The next entry if we need to chain dma address. Null if last.
* @entry_sum_in_chain: The full count of SGEs - only matters for first SGL.
* @entry_sum_in_sgl: The number of SGEs in this SGL element.
* @flag: Unused in skciphers.
* @serial_num: Unsued in skciphers.
* @cpuid: Currently unused.
* @data_bytes_in_sgl: Count of bytes from all SGEs in this SGL.
* @next: Virtual address used to stash the next sgl - useful in completion.
* @reserved: A reserved field not currently used.
* @sge_entries: The (up to) 64 Scatter Gather Entries, representing IOVs.
* @node: Currently unused.
*/
struct sec_hw_sgl {
dma_addr_t next_sgl;
u16 entry_sum_in_chain;
u16 entry_sum_in_sgl;
u32 flag;
u64 serial_num;
u32 cpuid;
u32 data_bytes_in_sgl;
struct sec_hw_sgl *next;
u64 reserved;
struct sec_hw_sge sge_entries[SEC_MAX_SGE_NUM];
u8 node[16];
};
struct dma_pool;
/**
* struct sec_dev_info: The full SEC unit comprising queues and processors.
* @sec_id: Index used to track which SEC this is when more than one is present.
* @num_saas: The number of backed processors enabled.
* @regs: iomapped register regions shared by whole SEC unit.
* @dev_lock: Protects concurrent queue allocation / freeing for the SEC.
* @queues: The 16 queues that this SEC instance provides.
* @dev: Device pointer.
* @hw_sgl_pool: DMA pool used to mimise mapping for the scatter gather lists.
*/
struct sec_dev_info {
int sec_id;
int num_saas;
void __iomem *regs[SEC_NUM_ADDR_REGIONS];
struct mutex dev_lock;
int queues_in_use;
struct sec_queue queues[SEC_Q_NUM];
struct device *dev;
struct dma_pool *hw_sgl_pool;
};
int sec_queue_send(struct sec_queue *queue, struct sec_bd_info *msg, void *ctx);
bool sec_queue_can_enqueue(struct sec_queue *queue, int num);
int sec_queue_stop_release(struct sec_queue *queue);
struct sec_queue *sec_queue_alloc_start_safe(void);
bool sec_queue_empty(struct sec_queue *queue);
/* Algorithm specific elements from sec_algs.c */
void sec_alg_callback(struct sec_bd_info *resp, void *ctx);
int sec_algs_register(void);
void sec_algs_unregister(void);
#endif /* _SEC_DRV_H_ */

View File

@ -1,214 +0,0 @@
// SPDX-License-Identifier: GPL-2.0
/* Copyright (c) 2019 HiSilicon Limited. */
#include <linux/dma-mapping.h>
#include <linux/module.h>
#include "./sgl.h"
#define HISI_ACC_SGL_SGE_NR_MIN 1
#define HISI_ACC_SGL_SGE_NR_MAX 255
#define HISI_ACC_SGL_SGE_NR_DEF 10
#define HISI_ACC_SGL_NR_MAX 256
#define HISI_ACC_SGL_ALIGN_SIZE 64
static int acc_sgl_sge_set(const char *val, const struct kernel_param *kp)
{
int ret;
u32 n;
if (!val)
return -EINVAL;
ret = kstrtou32(val, 10, &n);
if (ret != 0 || n > HISI_ACC_SGL_SGE_NR_MAX || n == 0)
return -EINVAL;
return param_set_int(val, kp);
}
static const struct kernel_param_ops acc_sgl_sge_ops = {
.set = acc_sgl_sge_set,
.get = param_get_int,
};
static u32 acc_sgl_sge_nr = HISI_ACC_SGL_SGE_NR_DEF;
module_param_cb(acc_sgl_sge_nr, &acc_sgl_sge_ops, &acc_sgl_sge_nr, 0444);
MODULE_PARM_DESC(acc_sgl_sge_nr, "Number of sge in sgl(1-255)");
struct acc_hw_sge {
dma_addr_t buf;
void *page_ctrl;
__le32 len;
__le32 pad;
__le32 pad0;
__le32 pad1;
};
/* use default sgl head size 64B */
struct hisi_acc_hw_sgl {
dma_addr_t next_dma;
__le16 entry_sum_in_chain;
__le16 entry_sum_in_sgl;
__le16 entry_length_in_sgl;
__le16 pad0;
__le64 pad1[5];
struct hisi_acc_hw_sgl *next;
struct acc_hw_sge sge_entries[];
} __aligned(1);
/**
* hisi_acc_create_sgl_pool() - Create a hw sgl pool.
* @dev: The device which hw sgl pool belongs to.
* @pool: Pointer of pool.
* @count: Count of hisi_acc_hw_sgl in pool.
*
* This function creates a hw sgl pool, after this user can get hw sgl memory
* from it.
*/
int hisi_acc_create_sgl_pool(struct device *dev,
struct hisi_acc_sgl_pool *pool, u32 count)
{
u32 sgl_size;
u32 size;
if (!dev || !pool || !count)
return -EINVAL;
sgl_size = sizeof(struct acc_hw_sge) * acc_sgl_sge_nr +
sizeof(struct hisi_acc_hw_sgl);
size = sgl_size * count;
pool->sgl = dma_alloc_coherent(dev, size, &pool->sgl_dma, GFP_KERNEL);
if (!pool->sgl)
return -ENOMEM;
pool->size = size;
pool->count = count;
pool->sgl_size = sgl_size;
return 0;
}
EXPORT_SYMBOL_GPL(hisi_acc_create_sgl_pool);
/**
* hisi_acc_free_sgl_pool() - Free a hw sgl pool.
* @dev: The device which hw sgl pool belongs to.
* @pool: Pointer of pool.
*
* This function frees memory of a hw sgl pool.
*/
void hisi_acc_free_sgl_pool(struct device *dev, struct hisi_acc_sgl_pool *pool)
{
dma_free_coherent(dev, pool->size, pool->sgl, pool->sgl_dma);
memset(pool, 0, sizeof(struct hisi_acc_sgl_pool));
}
EXPORT_SYMBOL_GPL(hisi_acc_free_sgl_pool);
struct hisi_acc_hw_sgl *acc_get_sgl(struct hisi_acc_sgl_pool *pool, u32 index,
dma_addr_t *hw_sgl_dma)
{
if (!pool || !hw_sgl_dma || index >= pool->count || !pool->sgl)
return ERR_PTR(-EINVAL);
*hw_sgl_dma = pool->sgl_dma + pool->sgl_size * index;
return (void *)pool->sgl + pool->sgl_size * index;
}
void acc_put_sgl(struct hisi_acc_sgl_pool *pool, u32 index) {}
static void sg_map_to_hw_sg(struct scatterlist *sgl,
struct acc_hw_sge *hw_sge)
{
hw_sge->buf = sgl->dma_address;
hw_sge->len = sgl->dma_length;
}
static void inc_hw_sgl_sge(struct hisi_acc_hw_sgl *hw_sgl)
{
hw_sgl->entry_sum_in_sgl++;
}
static void update_hw_sgl_sum_sge(struct hisi_acc_hw_sgl *hw_sgl, u16 sum)
{
hw_sgl->entry_sum_in_chain = sum;
}
/**
* hisi_acc_sg_buf_map_to_hw_sgl - Map a scatterlist to a hw sgl.
* @dev: The device which hw sgl belongs to.
* @sgl: Scatterlist which will be mapped to hw sgl.
* @pool: Pool which hw sgl memory will be allocated in.
* @index: Index of hisi_acc_hw_sgl in pool.
* @hw_sgl_dma: The dma address of allocated hw sgl.
*
* This function builds hw sgl according input sgl, user can use hw_sgl_dma
* as src/dst in its BD. Only support single hw sgl currently.
*/
struct hisi_acc_hw_sgl *
hisi_acc_sg_buf_map_to_hw_sgl(struct device *dev,
struct scatterlist *sgl,
struct hisi_acc_sgl_pool *pool,
u32 index, dma_addr_t *hw_sgl_dma)
{
struct hisi_acc_hw_sgl *curr_hw_sgl;
dma_addr_t curr_sgl_dma = 0;
struct acc_hw_sge *curr_hw_sge;
struct scatterlist *sg;
int sg_n = sg_nents(sgl);
int i, ret;
if (!dev || !sgl || !pool || !hw_sgl_dma || sg_n > acc_sgl_sge_nr)
return ERR_PTR(-EINVAL);
ret = dma_map_sg(dev, sgl, sg_n, DMA_BIDIRECTIONAL);
if (!ret)
return ERR_PTR(-EINVAL);
curr_hw_sgl = acc_get_sgl(pool, index, &curr_sgl_dma);
if (!curr_hw_sgl) {
ret = -ENOMEM;
goto err_unmap_sg;
}
curr_hw_sgl->entry_length_in_sgl = acc_sgl_sge_nr;
curr_hw_sge = curr_hw_sgl->sge_entries;
for_each_sg(sgl, sg, sg_n, i) {
sg_map_to_hw_sg(sg, curr_hw_sge);
inc_hw_sgl_sge(curr_hw_sgl);
curr_hw_sge++;
}
update_hw_sgl_sum_sge(curr_hw_sgl, acc_sgl_sge_nr);
*hw_sgl_dma = curr_sgl_dma;
return curr_hw_sgl;
err_unmap_sg:
dma_unmap_sg(dev, sgl, sg_n, DMA_BIDIRECTIONAL);
return ERR_PTR(ret);
}
EXPORT_SYMBOL_GPL(hisi_acc_sg_buf_map_to_hw_sgl);
/**
* hisi_acc_sg_buf_unmap() - Unmap allocated hw sgl.
* @dev: The device which hw sgl belongs to.
* @sgl: Related scatterlist.
* @hw_sgl: Virtual address of hw sgl.
* @hw_sgl_dma: DMA address of hw sgl.
* @pool: Pool which hw sgl is allocated in.
*
* This function unmaps allocated hw sgl.
*/
void hisi_acc_sg_buf_unmap(struct device *dev, struct scatterlist *sgl,
struct hisi_acc_hw_sgl *hw_sgl)
{
dma_unmap_sg(dev, sgl, sg_nents(sgl), DMA_BIDIRECTIONAL);
hw_sgl->entry_sum_in_chain = 0;
hw_sgl->entry_sum_in_sgl = 0;
hw_sgl->entry_length_in_sgl = 0;
}
EXPORT_SYMBOL_GPL(hisi_acc_sg_buf_unmap);
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Zhou Wang <wangzhou1@hisilicon.com>");
MODULE_DESCRIPTION("HiSilicon Accelerator SGL support");

View File

@ -1,24 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0 */
/* Copyright (c) 2019 HiSilicon Limited. */
#ifndef HISI_ACC_SGL_H
#define HISI_ACC_SGL_H
struct hisi_acc_sgl_pool {
struct hisi_acc_hw_sgl *sgl;
dma_addr_t sgl_dma;
size_t size;
u32 count;
size_t sgl_size;
};
struct hisi_acc_hw_sgl *
hisi_acc_sg_buf_map_to_hw_sgl(struct device *dev,
struct scatterlist *sgl,
struct hisi_acc_sgl_pool *pool,
u32 index, dma_addr_t *hw_sgl_dma);
void hisi_acc_sg_buf_unmap(struct device *dev, struct scatterlist *sgl,
struct hisi_acc_hw_sgl *hw_sgl);
int hisi_acc_create_sgl_pool(struct device *dev, struct hisi_acc_sgl_pool *pool,
u32 count);
void hisi_acc_free_sgl_pool(struct device *dev, struct hisi_acc_sgl_pool *pool);
#endif

View File

@ -0,0 +1,11 @@
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.
See Documentation/warpdrive/warpdrive.rst for more details.
If you don't know what to do here, say N.

View File

@ -0,0 +1,2 @@
# SPDX-License-Identifier: GPL-2.0-or-later
obj-$(CONFIG_UACCE) += uacce.o

File diff suppressed because it is too large Load Diff

View File

@ -1,75 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0 */
/* Copyright (c) 2019 HiSilicon Limited. */
#ifndef HISI_ZIP_H
#define HISI_ZIP_H
#undef pr_fmt
#define pr_fmt(fmt) "hisi_zip: " fmt
#include <linux/list.h>
#include "../qm.h"
#include "../sgl.h"
/* hisi_zip_sqe dw3 */
#define HZIP_BD_STATUS_M GENMASK(7, 0)
/* hisi_zip_sqe dw7 */
#define HZIP_IN_SGE_DATA_OFFSET_M GENMASK(23, 0)
/* hisi_zip_sqe dw8 */
#define HZIP_OUT_SGE_DATA_OFFSET_M GENMASK(23, 0)
/* hisi_zip_sqe dw9 */
#define HZIP_REQ_TYPE_M GENMASK(7, 0)
#define HZIP_ALG_TYPE_ZLIB 0x02
#define HZIP_ALG_TYPE_GZIP 0x03
#define HZIP_BUF_TYPE_M GENMASK(11, 8)
#define HZIP_PBUFFER 0x0
#define HZIP_SGL 0x1
enum hisi_zip_error_type {
/* negative compression */
HZIP_NC_ERR = 0x0d,
};
struct hisi_zip_ctrl;
struct hisi_zip {
struct hisi_qm qm;
struct list_head list;
struct hisi_zip_ctrl *ctrl;
};
struct hisi_zip_sqe {
u32 consumed;
u32 produced;
u32 comp_data_length;
u32 dw3;
u32 input_data_length;
u32 lba_l;
u32 lba_h;
u32 dw7;
u32 dw8;
u32 dw9;
u32 dw10;
u32 priv_info;
u32 dw12;
u32 tag;
u32 dest_avail_out;
u32 rsvd0;
u32 comp_head_addr_l;
u32 comp_head_addr_h;
u32 source_addr_l;
u32 source_addr_h;
u32 dest_addr_l;
u32 dest_addr_h;
u32 stream_ctx_addr_l;
u32 stream_ctx_addr_h;
u32 cipher_key1_addr_l;
u32 cipher_key1_addr_h;
u32 cipher_key2_addr_l;
u32 cipher_key2_addr_h;
u32 rsvd1[4];
};
struct hisi_zip *find_zip_device(int node);
int hisi_zip_register_to_crypto(void);
void hisi_zip_unregister_from_crypto(void);
#endif

View File

@ -5663,8 +5663,13 @@ CONFIG_CRYPTO_DEV_CCP_CRYPTO=m
CONFIG_CRYPTO_DEV_VIRTIO=m
# CONFIG_CRYPTO_DEV_SAFEXCEL is not set
# CONFIG_CRYPTO_DEV_CCREE is not set
# CONFIG_CRYPTO_DEV_HISI_SEC is not set
# CONFIG_CRYPTO_DEV_HISI_ZIP is not set
CONFIG_CRYPTO_DEV_HISI_QM=m
CONFIG_CRYPTO_QM_UACCE=y
CONFIG_CRYPTO_DEV_HISI_ZIP=m
CONFIG_CRYPTO_DEV_HISI_HPRE=m
CONFIG_CRYPTO_DEV_HISI_SEC2=m
CONFIG_CRYPTO_DEV_HISI_RDE=m
CONFIG_UACCE=m
CONFIG_ASYMMETRIC_KEY_TYPE=y
CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE=y
CONFIG_X509_CERTIFICATE_PARSER=y

View File

@ -5745,8 +5745,13 @@ CONFIG_CRYPTO_DEV_CCP_CRYPTO=m
CONFIG_CRYPTO_DEV_VIRTIO=m
# CONFIG_CRYPTO_DEV_SAFEXCEL is not set
# CONFIG_CRYPTO_DEV_CCREE is not set
# CONFIG_CRYPTO_DEV_HISI_SEC is not set
# CONFIG_CRYPTO_DEV_HISI_ZIP is not set
CONFIG_CRYPTO_DEV_HISI_QM=m
CONFIG_CRYPTO_QM_UACCE=y
CONFIG_CRYPTO_DEV_HISI_ZIP=m
CONFIG_CRYPTO_DEV_HISI_HPRE=m
CONFIG_CRYPTO_DEV_HISI_SEC2=m
CONFIG_CRYPTO_DEV_HISI_RDE=m
CONFIG_UACCE=m
CONFIG_ASYMMETRIC_KEY_TYPE=y
CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE=y
CONFIG_X509_CERTIFICATE_PARSER=y