Resguardo inicial

This commit is contained in:
lastdragon
2026-09-06 12:53:21 -06:00
parent 662efe3c2a
commit ad2088d178
94853 changed files with 43200404 additions and 0 deletions
@@ -0,0 +1,77 @@
# SPDX-License-Identifier: GPL-2.0
config CRYPTO_DEV_HISI_SEC
tristate "Support for Hisilicon SEC crypto block cipher accelerator"
select CRYPTO_SKCIPHER
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_SEC2
tristate "Support for HiSilicon SEC2 crypto block cipher accelerator"
select CRYPTO_SKCIPHER
select CRYPTO_ALGAPI
select CRYPTO_LIB_DES
select CRYPTO_DEV_HISI_QM
select CRYPTO_AEAD
select CRYPTO_AUTHENC
select CRYPTO_HMAC
select CRYPTO_SHA1
select CRYPTO_SHA256
select CRYPTO_SHA512
select CRYPTO_SM4_GENERIC
depends on PCI_MSI
depends on UACCE || UACCE=n
depends on ARM64 || (COMPILE_TEST && 64BIT)
depends on ACPI
help
Support for HiSilicon SEC Engine of version 2 in crypto subsystem.
It provides AES, SM4, and 3DES algorithms with ECB
CBC, and XTS cipher mode, and AEAD algorithms.
To compile this as a module, choose M here: the module
will be called hisi_sec2.
config CRYPTO_DEV_HISI_QM
tristate
depends on ARM64 || COMPILE_TEST
depends on PCI_MSI
depends on UACCE || UACCE=n
depends on ACPI
help
HiSilicon accelerator engines use a common queue management
interface. Specific engine driver may use this module.
config CRYPTO_DEV_HISI_ZIP
tristate "Support for HiSilicon ZIP accelerator"
depends on PCI_MSI
depends on ARM64 || (COMPILE_TEST && 64BIT)
depends on !CPU_BIG_ENDIAN || COMPILE_TEST
depends on UACCE || UACCE=n
depends on ACPI
select CRYPTO_DEV_HISI_QM
select CRYPTO_DEFLATE
select CRYPTO_LZ4
help
Support for HiSilicon ZIP Driver
config CRYPTO_DEV_HISI_HPRE
tristate "Support for HISI HPRE accelerator"
depends on PCI_MSI
depends on UACCE || UACCE=n
depends on ARM64 || (COMPILE_TEST && 64BIT)
depends on ACPI
select CRYPTO_DEV_HISI_QM
select CRYPTO_DH
select CRYPTO_RSA
select CRYPTO_ECDH
help
Support for HiSilicon HPRE(High Performance RSA Engine)
accelerator, which can accelerate RSA and DH algorithms.
@@ -0,0 +1,7 @@
# SPDX-License-Identifier: GPL-2.0
obj-$(CONFIG_CRYPTO_DEV_HISI_HPRE) += hpre/
obj-$(CONFIG_CRYPTO_DEV_HISI_SEC) += sec/
obj-$(CONFIG_CRYPTO_DEV_HISI_SEC2) += sec2/
obj-$(CONFIG_CRYPTO_DEV_HISI_QM) += hisi_qm.o
hisi_qm-objs = qm.o sgl.o debugfs.o
obj-$(CONFIG_CRYPTO_DEV_HISI_ZIP) += zip/
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,2 @@
obj-$(CONFIG_CRYPTO_DEV_HISI_HPRE) += hisi_hpre.o
hisi_hpre-objs = hpre_main.o hpre_crypto.o
@@ -0,0 +1,129 @@
/* SPDX-License-Identifier: GPL-2.0 */
/* Copyright (c) 2019 HiSilicon Limited. */
#ifndef __HISI_HPRE_H
#define __HISI_HPRE_H
#include <linux/list.h>
#include <linux/hisi_acc_qm.h>
#define HPRE_SQE_SIZE sizeof(struct hpre_sqe)
#define HPRE_PF_DEF_Q_NUM 64
#define HPRE_PF_DEF_Q_BASE 0
/*
* type used in qm sqc DW6.
* 0 - Algorithm which has been supported in V2, like RSA, DH and so on;
* 1 - ECC algorithm in V3.
*/
#define HPRE_V2_ALG_TYPE 0
#define HPRE_V3_ECC_ALG_TYPE 1
enum {
HPRE_CLUSTER0,
HPRE_CLUSTER1,
HPRE_CLUSTER2,
HPRE_CLUSTER3,
HPRE_CLUSTERS_NUM_MAX
};
enum hpre_ctrl_dbgfs_file {
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_MAX - 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;
unsigned long status;
};
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,
HPRE_ALG_ECC_MUL = 0xD,
/* shared by x25519 and x448, but x448 is not supported now */
HPRE_ALG_CURVE25519_MUL = 0x10,
};
struct hpre_sqe {
__le32 dw0;
__u8 task_len1;
__u8 task_len2;
__u8 mrttest_num;
__u8 resv1;
__le64 key;
__le64 in;
__le64 out;
__le64 tag;
#define _HPRE_SQE_ALIGN_EXT 6
__le32 rsvd1[_HPRE_SQE_ALIGN_EXT];
};
enum hpre_cap_table_type {
QM_RAS_NFE_TYPE = 0x0,
QM_RAS_NFE_RESET,
QM_RAS_CE_TYPE,
HPRE_RAS_NFE_TYPE,
HPRE_RAS_NFE_RESET,
HPRE_RAS_CE_TYPE,
HPRE_CORE_INFO,
HPRE_CORE_EN,
HPRE_DRV_ALG_BITMAP,
HPRE_ALG_BITMAP,
HPRE_CORE1_BITMAP_CAP,
HPRE_CORE2_BITMAP_CAP,
HPRE_CORE3_BITMAP_CAP,
HPRE_CORE4_BITMAP_CAP,
HPRE_CORE5_BITMAP_CAP,
HPRE_CORE6_BITMAP_CAP,
HPRE_CORE7_BITMAP_CAP,
HPRE_CORE8_BITMAP_CAP,
HPRE_CORE9_BITMAP_CAP,
HPRE_CORE10_BITMAP_CAP,
};
struct hisi_qp *hpre_create_qp(u8 type);
int hpre_algs_register(struct hisi_qm *qm);
void hpre_algs_unregister(struct hisi_qm *qm);
bool hpre_check_alg_support(struct hisi_qm *qm, u32 alg);
#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
@@ -0,0 +1,79 @@
/* SPDX-License-Identifier: GPL-2.0 */
/* Copyright (c) 2022 HiSilicon Limited. */
#ifndef QM_COMMON_H
#define QM_COMMON_H
#define QM_DBG_READ_LEN 256
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;
};
int qm_set_and_get_xqc(struct hisi_qm *qm, u8 cmd, void *xqc, u32 qp_id, bool op);
void hisi_qm_show_last_dfx_regs(struct hisi_qm *qm);
void hisi_qm_set_algqos_init(struct hisi_qm *qm);
#endif
@@ -0,0 +1,3 @@
# 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
@@ -0,0 +1,428 @@
/* 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;
spinlock_t 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_ */
@@ -0,0 +1,2 @@
obj-$(CONFIG_CRYPTO_DEV_HISI_SEC2) += hisi_sec2.o
hisi_sec2-objs = sec_main.o sec_crypto.o
@@ -0,0 +1,289 @@
/* SPDX-License-Identifier: GPL-2.0 */
/* Copyright (c) 2019 HiSilicon Limited. */
#ifndef __HISI_SEC_V2_H
#define __HISI_SEC_V2_H
#include <linux/hisi_acc_qm.h>
#include "sec_crypto.h"
#define SEC_PBUF_SZ 512
#define SEC_MAX_MAC_LEN 64
#define SEC_IV_SIZE 24
#define SEC_SGE_NR_NUM 4
#define SEC_SGL_ALIGN_SIZE 64
/* 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 *a_ivin;
dma_addr_t a_ivin_dma;
u8 *out_mac;
dma_addr_t out_mac_dma;
u16 depth;
};
struct sec_hw_sge {
dma_addr_t buf;
void *page_ctrl;
__le32 len;
__le32 pad;
__le32 pad0;
__le32 pad1;
};
struct sec_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 sec_hw_sgl *next;
struct sec_hw_sge sge_entries[SEC_SGE_NR_NUM];
} __aligned(SEC_SGL_ALIGN_SIZE);
struct sec_src_dst_buf {
struct sec_hw_sgl in;
struct sec_hw_sgl out;
};
struct sec_request_buf {
union {
struct sec_src_dst_buf data_buf;
__u8 pbuf[SEC_PBUF_SZ];
};
dma_addr_t in_dma;
dma_addr_t out_dma;
};
/* Cipher request of SEC private */
struct sec_cipher_req {
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;
__u8 c_ivin_buf[SEC_IV_SIZE];
};
struct sec_aead_req {
u8 *out_mac;
dma_addr_t out_mac_dma;
u8 *a_ivin;
dma_addr_t a_ivin_dma;
struct aead_request *aead_req;
__u8 a_ivin_buf[SEC_IV_SIZE];
__u8 out_mac_buf[SEC_MAX_MAC_LEN];
};
/* SEC request of Crypto */
struct sec_req {
union {
struct sec_sqe sec_sqe;
struct sec_sqe3 sec_sqe3;
};
struct sec_ctx *ctx;
struct sec_qp_ctx *qp_ctx;
/**
* Common parameter of the SEC request.
*/
struct hisi_acc_hw_sgl *in;
dma_addr_t in_dma;
struct sec_cipher_req c_req;
struct sec_aead_req aead_req;
struct crypto_async_request *base;
int err_type;
int req_id;
u32 flag;
bool use_pbuf;
struct list_head list;
struct sec_request_buf buf;
};
/**
* 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 auth context */
struct sec_auth_ctx {
dma_addr_t a_key_dma;
u8 *a_key;
u8 a_key_len;
u8 a_alg;
struct crypto_shash *hash_tfm;
struct crypto_aead *fallback_aead_tfm;
};
/* 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;
/* add software support */
bool fallback;
struct crypto_sync_skcipher *fbtfm;
};
/* SEC queue context which defines queue's relatives */
struct sec_qp_ctx {
struct hisi_qp *qp;
struct sec_req **req_list;
struct idr req_idr;
struct sec_alg_res *res;
struct sec_ctx *ctx;
spinlock_t req_lock;
spinlock_t id_lock;
struct hisi_acc_sgl_pool *c_in_pool;
struct hisi_acc_sgl_pool *c_out_pool;
u16 send_head;
};
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;
/* Current cyclic index to select a queue for encipher */
atomic_t enc_qcyclic;
/* Current 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;
struct sec_auth_ctx a_ctx;
u8 type_supported;
struct device *dev;
};
enum sec_debug_file_index {
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;
};
enum sec_cap_type {
SEC_QM_NFE_MASK_CAP = 0x0,
SEC_QM_RESET_MASK_CAP,
SEC_QM_OOO_SHUTDOWN_MASK_CAP,
SEC_QM_CE_MASK_CAP,
SEC_NFE_MASK_CAP,
SEC_RESET_MASK_CAP,
SEC_OOO_SHUTDOWN_MASK_CAP,
SEC_CE_MASK_CAP,
SEC_CLUSTER_NUM_CAP,
SEC_CORE_TYPE_NUM_CAP,
SEC_CORE_NUM_CAP,
SEC_CORES_PER_CLUSTER_NUM_CAP,
SEC_CORE_ENABLE_BITMAP,
SEC_DRV_ALG_BITMAP_LOW,
SEC_DRV_ALG_BITMAP_HIGH,
SEC_DEV_ALG_BITMAP_LOW,
SEC_DEV_ALG_BITMAP_HIGH,
SEC_CORE1_ALG_BITMAP_LOW,
SEC_CORE1_ALG_BITMAP_HIGH,
SEC_CORE2_ALG_BITMAP_LOW,
SEC_CORE2_ALG_BITMAP_HIGH,
SEC_CORE3_ALG_BITMAP_LOW,
SEC_CORE3_ALG_BITMAP_HIGH,
SEC_CORE4_ALG_BITMAP_LOW,
SEC_CORE4_ALG_BITMAP_HIGH,
};
enum sec_cap_table_type {
QM_RAS_NFE_TYPE = 0x0,
QM_RAS_NFE_RESET,
QM_RAS_CE_TYPE,
SEC_RAS_NFE_TYPE,
SEC_RAS_NFE_RESET,
SEC_RAS_CE_TYPE,
SEC_CORE_INFO,
SEC_CORE_EN,
SEC_DRV_ALG_BITMAP_LOW_TB,
SEC_DRV_ALG_BITMAP_HIGH_TB,
SEC_ALG_BITMAP_LOW,
SEC_ALG_BITMAP_HIGH,
SEC_CORE1_BITMAP_LOW,
SEC_CORE1_BITMAP_HIGH,
SEC_CORE2_BITMAP_LOW,
SEC_CORE2_BITMAP_HIGH,
SEC_CORE3_BITMAP_LOW,
SEC_CORE3_BITMAP_HIGH,
SEC_CORE4_BITMAP_LOW,
SEC_CORE4_BITMAP_HIGH,
};
void sec_destroy_qps(struct hisi_qp **qps, int qp_num);
struct hisi_qp **sec_create_qps(void);
u64 sec_get_alg_bitmap(struct hisi_qm *qm, u32 high, u32 low);
#endif
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,397 @@
/* SPDX-License-Identifier: GPL-2.0 */
/* Copyright (c) 2019 HiSilicon Limited. */
#ifndef __HISI_SEC_V2_CRYPTO_H
#define __HISI_SEC_V2_CRYPTO_H
#define SEC_AIV_SIZE 12
#define SEC_IV_SIZE 24
#define SEC_MAX_KEY_SIZE 64
#define SEC_MAX_AKEY_SIZE 128
#define SEC_COMM_SCENE 0
#define SEC_MIN_BLOCK_SZ 1
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_cmode {
SEC_CMODE_ECB = 0x0,
SEC_CMODE_CBC = 0x1,
SEC_CMODE_CTR = 0x4,
SEC_CMODE_CCM = 0x5,
SEC_CMODE_GCM = 0x6,
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,
SEC_BD_TYPE3 = 0x3,
};
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,
};
struct bd_status {
u64 tag;
u8 done;
u8 err_type;
u16 flag;
u16 icv;
};
enum {
AUTHPAD_PAD,
AUTHPAD_NOPAD,
};
enum {
AIGEN_GEN,
AIGEN_NOGEN,
};
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;
/* Just using type2 BD now */
struct sec_sqe_type2 type2;
};
struct bd3_auth_ivin {
__le64 a_ivin_addr;
__le32 rsvd0;
__le32 rsvd1;
} __packed __aligned(4);
struct bd3_skip_data {
__le32 rsvd0;
/*
* gran_num: 0~15 bits
* reserved: 16~31 bits
*/
__le32 gran_num;
/*
* src_skip_data_len: 0~24 bits
* reserved: 25~31 bits
*/
__le32 src_skip_data_len;
/*
* dst_skip_data_len: 0~24 bits
* reserved: 25~31 bits
*/
__le32 dst_skip_data_len;
};
struct bd3_stream_scene {
__le64 c_ivin_addr;
__le64 long_a_data_len;
/*
* auth_pad: 0~1 bits
* stream_protocol: 2~4 bits
* reserved: 5~7 bits
*/
__u8 stream_auth_pad;
__u8 plaintext_type;
__le16 pad_len_1p3;
} __packed __aligned(4);
struct bd3_no_scene {
__le64 c_ivin_addr;
__le32 rsvd0;
__le32 rsvd1;
__le32 rsvd2;
} __packed __aligned(4);
struct bd3_check_sum {
__u8 rsvd0;
__u8 hac_sva_status;
__le16 check_sum_i;
};
struct bd3_tls_type_back {
__u8 tls_1p3_type_back;
__u8 hac_sva_status;
__le16 pad_len_1p3_back;
};
struct sec_sqe3 {
/*
* type: 0~3 bit
* bd_invalid: 4 bit
* scene: 5~8 bit
* de: 9~10 bit
* src_addr_type: 11~13 bit
* dst_addr_type: 14~16 bit
* mac_addr_type: 17~19 bit
* reserved: 20~31 bits
*/
__le32 bd_param;
/*
* cipher: 0~1 bits
* ci_gen: 2~3 bit
* c_icv_len: 4~9 bit
* c_width: 10~12 bits
* c_key_len: 13~15 bits
*/
__le16 c_icv_key;
/*
* c_mode : 0~3 bits
* c_alg : 4~7 bits
*/
__u8 c_mode_alg;
/*
* nonce_len : 0~3 bits
* huk : 4 bits
* cal_iv_addr_en : 5 bits
* seq : 6 bits
* reserved : 7 bits
*/
__u8 huk_iv_seq;
__le64 tag;
__le64 data_src_addr;
__le64 a_key_addr;
union {
struct bd3_auth_ivin auth_ivin;
struct bd3_skip_data skip_data;
};
__le64 c_key_addr;
/*
* auth: 0~1 bits
* ai_gen: 2~3 bits
* mac_len: 4~8 bits
* akey_len: 9~14 bits
* a_alg: 15~20 bits
* key_sel: 21~24 bits
* ctr_count_mode/sm4_xts: 25~26 bits
* sva_prefetch: 27 bits
* key_wrap_num: 28~30 bits
* update_key: 31 bits
*/
__le32 auth_mac_key;
__le32 salt;
__le16 auth_src_offset;
__le16 cipher_src_offset;
/*
* auth_len: 0~23 bit
* auth_key_offset: 24~31 bits
*/
__le32 a_len_key;
/*
* cipher_len: 0~23 bit
* auth_ivin_offset: 24~31 bits
*/
__le32 c_len_ivin;
__le64 data_dst_addr;
__le64 mac_addr;
union {
struct bd3_stream_scene stream_scene;
struct bd3_no_scene no_scene;
};
/*
* done: 0 bit
* icv: 1~3 bit
* csc: 4~6 bit
* flag: 7~10 bit
* reserved: 11~15 bit
*/
__le16 done_flag;
__u8 error_type;
__u8 warning_type;
union {
__le32 mac_i;
__le32 kek_key_addr_l;
};
union {
__le32 kek_key_addr_h;
struct bd3_check_sum check_sum;
struct bd3_tls_type_back tls_type_back;
};
__le32 counter;
} __packed __aligned(4);
int sec_register_to_crypto(struct hisi_qm *qm);
void sec_unregister_from_crypto(struct hisi_qm *qm);
#endif
File diff suppressed because it is too large Load Diff
+290
View File
@@ -0,0 +1,290 @@
// SPDX-License-Identifier: GPL-2.0
/* Copyright (c) 2019 HiSilicon Limited. */
#include <linux/align.h>
#include <linux/dma-mapping.h>
#include <linux/hisi_acc_qm.h>
#include <linux/module.h>
#include <linux/slab.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 = ALIGN(sizeof(struct acc_hw_sge) * sge_nr +
sizeof(struct hisi_acc_hw_sgl),
HISI_ACC_SGL_ALIGN_SIZE);
/*
* the pool may allocate a block of memory of size PAGE_SIZE * 2^MAX_PAGE_ORDER,
* block size may exceed 2^31 on ia64, so the max of block size is 2^31
*/
block_size = 1 << (PAGE_SHIFT + MAX_PAGE_ORDER < 32 ?
PAGE_SHIFT + MAX_PAGE_ORDER : 31);
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_obj(*pool);
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);
kfree_sensitive(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;
u32 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;
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));
hw_sge->page_ctrl = sg_virt(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);
}
static void clear_hw_sgl_sge(struct hisi_acc_hw_sgl *hw_sgl)
{
struct acc_hw_sge *hw_sge = hw_sgl->sge_entries;
u16 entry_sum = le16_to_cpu(hw_sgl->entry_sum_in_sgl);
int i;
for (i = 0; i < entry_sum; i++) {
hw_sge[i].page_ctrl = NULL;
hw_sge[i].buf = 0;
hw_sge[i].len = 0;
}
}
/**
* 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.
* @dir: DMA direction.
*
* 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, enum dma_data_direction dir)
{
struct hisi_acc_hw_sgl *curr_hw_sgl;
unsigned int i, sg_n_mapped;
dma_addr_t curr_sgl_dma = 0;
struct acc_hw_sge *curr_hw_sge;
struct scatterlist *sg;
int sg_n, ret;
if (!dev || !sgl || !pool || !hw_sgl_dma || index >= pool->count)
return ERR_PTR(-EINVAL);
sg_n = sg_nents(sgl);
sg_n_mapped = dma_map_sg(dev, sgl, sg_n, dir);
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");
ret = -EINVAL;
goto err_unmap;
}
curr_hw_sgl = acc_get_sgl(pool, index, &curr_sgl_dma);
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;
err_unmap:
dma_unmap_sg(dev, sgl, sg_n, dir);
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.
* @dir: DMA direction.
*
* 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, enum dma_data_direction dir)
{
if (!dev || !sgl || !hw_sgl)
return;
dma_unmap_sg(dev, sgl, sg_nents(sgl), dir);
clear_hw_sgl_sge(hw_sgl);
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);
@@ -0,0 +1,2 @@
obj-$(CONFIG_CRYPTO_DEV_HISI_ZIP) += hisi_zip.o
hisi_zip-objs = zip_main.o zip_crypto.o dae_main.o
@@ -0,0 +1,277 @@
// SPDX-License-Identifier: GPL-2.0
/* Copyright (c) 2024 HiSilicon Limited. */
#include <linux/bitops.h>
#include <linux/io.h>
#include <linux/uacce.h>
#include "zip.h"
/* memory */
#define DAE_MEM_START_OFFSET 0x331040
#define DAE_MEM_DONE_OFFSET 0x331044
#define DAE_MEM_START_MASK 0x1
#define DAE_MEM_DONE_MASK 0x1
#define DAE_REG_RD_INTVRL_US 10
#define DAE_REG_RD_TMOUT_US USEC_PER_SEC
#define DAE_ALG_NAME "hashagg"
#define DAE_V5_ALG_NAME "hashagg\nudma\nhashjoin\ngather"
/* error */
#define DAE_AXI_CFG_OFFSET 0x331000
#define DAE_AXI_SHUTDOWN_MASK (BIT(0) | BIT(5))
#define DAE_ERR_SOURCE_OFFSET 0x331C84
#define DAE_ERR_STATUS_OFFSET 0x331C88
#define DAE_ERR_CE_OFFSET 0x331CA0
#define DAE_ERR_CE_MASK BIT(3)
#define DAE_ERR_NFE_OFFSET 0x331CA4
#define DAE_ERR_NFE_MASK 0x17
#define DAE_ERR_FE_OFFSET 0x331CA8
#define DAE_ERR_FE_MASK 0
#define DAE_ECC_MBIT_MASK BIT(2)
#define DAE_ECC_INFO_OFFSET 0x33400C
#define DAE_ERR_SHUTDOWN_OFFSET 0x331CAC
#define DAE_ERR_SHUTDOWN_MASK 0x17
#define DAE_ERR_ENABLE_OFFSET 0x331C80
#define DAE_ERR_ENABLE_MASK (DAE_ERR_FE_MASK | DAE_ERR_NFE_MASK | DAE_ERR_CE_MASK)
#define DAE_AM_CTRL_GLOBAL_OFFSET 0x330000
#define DAE_AM_RETURN_OFFSET 0x330150
#define DAE_AM_RETURN_MASK 0x3
#define DAE_AXI_CFG_OFFSET 0x331000
#define DAE_AXI_SHUTDOWN_EN_MASK (BIT(0) | BIT(5))
struct hisi_dae_hw_error {
u32 int_msk;
const char *msg;
};
static const struct hisi_dae_hw_error dae_hw_error[] = {
{ .int_msk = BIT(0), .msg = "dae_axi_bus_err" },
{ .int_msk = BIT(1), .msg = "dae_axi_poison_err" },
{ .int_msk = BIT(2), .msg = "dae_ecc_2bit_err" },
{ .int_msk = BIT(3), .msg = "dae_ecc_1bit_err" },
{ .int_msk = BIT(4), .msg = "dae_fsm_hbeat_err" },
};
static inline bool dae_is_support(struct hisi_qm *qm)
{
if (test_bit(QM_SUPPORT_DAE, &qm->caps))
return true;
return false;
}
int hisi_dae_set_user_domain(struct hisi_qm *qm)
{
u32 val;
int ret;
if (!dae_is_support(qm))
return 0;
val = readl(qm->io_base + DAE_MEM_START_OFFSET);
val |= DAE_MEM_START_MASK;
writel(val, qm->io_base + DAE_MEM_START_OFFSET);
ret = readl_relaxed_poll_timeout(qm->io_base + DAE_MEM_DONE_OFFSET, val,
val & DAE_MEM_DONE_MASK,
DAE_REG_RD_INTVRL_US, DAE_REG_RD_TMOUT_US);
if (ret)
pci_err(qm->pdev, "failed to init dae memory!\n");
return ret;
}
int hisi_dae_set_alg(struct hisi_qm *qm)
{
const char *alg_name;
size_t len;
if (!dae_is_support(qm))
return 0;
if (!qm->uacce)
return 0;
if (qm->ver >= QM_HW_V5)
alg_name = DAE_V5_ALG_NAME;
else
alg_name = DAE_ALG_NAME;
len = strlen(qm->uacce->algs);
/* A line break may be required */
if (len + strlen(alg_name) + 1 >= QM_DEV_ALG_MAX_LEN) {
pci_err(qm->pdev, "algorithm name is too long!\n");
return -EINVAL;
}
if (len)
strcat((char *)qm->uacce->algs, "\n");
strcat((char *)qm->uacce->algs, alg_name);
return 0;
}
static void hisi_dae_master_ooo_ctrl(struct hisi_qm *qm, bool enable)
{
u32 axi_val, err_val;
axi_val = readl(qm->io_base + DAE_AXI_CFG_OFFSET);
if (enable) {
axi_val |= DAE_AXI_SHUTDOWN_MASK;
err_val = DAE_ERR_SHUTDOWN_MASK;
} else {
axi_val &= ~DAE_AXI_SHUTDOWN_MASK;
err_val = 0;
}
writel(axi_val, qm->io_base + DAE_AXI_CFG_OFFSET);
writel(err_val, qm->io_base + DAE_ERR_SHUTDOWN_OFFSET);
}
void hisi_dae_hw_error_enable(struct hisi_qm *qm)
{
if (!dae_is_support(qm))
return;
/* clear dae hw error source if having */
writel(DAE_ERR_ENABLE_MASK, qm->io_base + DAE_ERR_SOURCE_OFFSET);
/* configure error type */
writel(DAE_ERR_CE_MASK, qm->io_base + DAE_ERR_CE_OFFSET);
writel(DAE_ERR_NFE_MASK, qm->io_base + DAE_ERR_NFE_OFFSET);
writel(DAE_ERR_FE_MASK, qm->io_base + DAE_ERR_FE_OFFSET);
hisi_dae_master_ooo_ctrl(qm, true);
/* enable dae hw error interrupts */
writel(DAE_ERR_ENABLE_MASK, qm->io_base + DAE_ERR_ENABLE_OFFSET);
}
void hisi_dae_hw_error_disable(struct hisi_qm *qm)
{
if (!dae_is_support(qm))
return;
writel(0, qm->io_base + DAE_ERR_ENABLE_OFFSET);
hisi_dae_master_ooo_ctrl(qm, false);
}
static u32 hisi_dae_get_hw_err_status(struct hisi_qm *qm)
{
return readl(qm->io_base + DAE_ERR_STATUS_OFFSET);
}
static void hisi_dae_clear_hw_err_status(struct hisi_qm *qm, u32 err_sts)
{
if (!dae_is_support(qm))
return;
writel(err_sts, qm->io_base + DAE_ERR_SOURCE_OFFSET);
}
static void hisi_dae_disable_error_report(struct hisi_qm *qm, u32 err_type)
{
writel(DAE_ERR_NFE_MASK & (~err_type), qm->io_base + DAE_ERR_NFE_OFFSET);
}
static void hisi_dae_enable_error_report(struct hisi_qm *qm)
{
writel(DAE_ERR_CE_MASK, qm->io_base + DAE_ERR_CE_OFFSET);
writel(DAE_ERR_NFE_MASK, qm->io_base + DAE_ERR_NFE_OFFSET);
}
static void hisi_dae_log_hw_error(struct hisi_qm *qm, u32 err_type)
{
const struct hisi_dae_hw_error *err = dae_hw_error;
struct device *dev = &qm->pdev->dev;
u32 ecc_info;
size_t i;
for (i = 0; i < ARRAY_SIZE(dae_hw_error); i++) {
err = &dae_hw_error[i];
if (!(err->int_msk & err_type))
continue;
dev_err(dev, "%s [error status=0x%x] found\n",
err->msg, err->int_msk);
if (err->int_msk & DAE_ECC_MBIT_MASK) {
ecc_info = readl(qm->io_base + DAE_ECC_INFO_OFFSET);
dev_err(dev, "dae multi ecc sram info 0x%x\n", ecc_info);
}
}
}
enum acc_err_result hisi_dae_get_err_result(struct hisi_qm *qm)
{
u32 err_status;
if (!dae_is_support(qm))
return ACC_ERR_NONE;
err_status = hisi_dae_get_hw_err_status(qm);
if (!err_status)
return ACC_ERR_NONE;
hisi_dae_log_hw_error(qm, err_status);
if (err_status & DAE_ERR_NFE_MASK) {
/* Disable the same error reporting until device is recovered. */
hisi_dae_disable_error_report(qm, err_status);
return ACC_ERR_NEED_RESET;
}
hisi_dae_clear_hw_err_status(qm, err_status);
/* Avoid firmware disable error report, re-enable. */
hisi_dae_enable_error_report(qm);
return ACC_ERR_RECOVERED;
}
bool hisi_dae_dev_is_abnormal(struct hisi_qm *qm)
{
u32 err_status;
if (!dae_is_support(qm))
return false;
err_status = hisi_dae_get_hw_err_status(qm);
if (err_status & DAE_ERR_NFE_MASK)
return true;
return false;
}
int hisi_dae_close_axi_master_ooo(struct hisi_qm *qm)
{
u32 val;
int ret;
if (!dae_is_support(qm))
return 0;
val = readl(qm->io_base + DAE_AM_CTRL_GLOBAL_OFFSET);
val |= BIT(0);
writel(val, qm->io_base + DAE_AM_CTRL_GLOBAL_OFFSET);
ret = readl_relaxed_poll_timeout(qm->io_base + DAE_AM_RETURN_OFFSET,
val, (val == DAE_AM_RETURN_MASK),
DAE_REG_RD_INTVRL_US, DAE_REG_RD_TMOUT_US);
if (ret)
dev_err(&qm->pdev->dev, "failed to close dae axi ooo!\n");
return ret;
}
void hisi_dae_open_axi_master_ooo(struct hisi_qm *qm)
{
u32 val;
if (!dae_is_support(qm))
return;
val = readl(qm->io_base + DAE_AXI_CFG_OFFSET);
writel(val & ~DAE_AXI_SHUTDOWN_EN_MASK, qm->io_base + DAE_AXI_CFG_OFFSET);
writel(val | DAE_AXI_SHUTDOWN_EN_MASK, qm->io_base + DAE_AXI_CFG_OFFSET);
}
@@ -0,0 +1,114 @@
/* 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 <linux/hisi_acc_qm.h>
enum hisi_zip_error_type {
/* negative compression */
HZIP_NC_ERR = 0x0d,
};
struct hisi_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 hisi_zip_dfx dfx;
};
struct hisi_zip_sqe {
u32 consumed;
u32 produced;
u32 comp_data_length;
/*
* status: 0~7 bits
* rsvd: 8~31 bits
*/
u32 dw3;
u32 input_data_length;
u32 dw5;
u32 dw6;
/*
* in_sge_data_offset: 0~23 bits
* rsvd: 24~27 bits
* sqe_type: 29~31 bits
*/
u32 dw7;
/*
* out_sge_data_offset: 0~23 bits
* rsvd: 24~31 bits
*/
u32 dw8;
/*
* request_type: 0~7 bits
* buffer_type: 8~11 bits
* rsvd: 13~31 bits
*/
u32 dw9;
u32 dw10;
u32 dw11;
u32 dw12;
/* tag: in sqe type 0 */
u32 dw13;
u32 dest_avail_out;
u32 dw15;
u32 dw16;
u32 dw17;
u32 source_addr_l;
u32 source_addr_h;
u32 dest_addr_l;
u32 dest_addr_h;
u32 dw22;
u32 dw23;
u32 dw24;
u32 dw25;
/* tag: in sqe type 3 */
u32 dw26;
u32 dw27;
u32 rsvd1[4];
};
enum zip_cap_table_type {
QM_RAS_NFE_TYPE,
QM_RAS_NFE_RESET,
QM_RAS_CE_TYPE,
ZIP_RAS_NFE_TYPE,
ZIP_RAS_NFE_RESET,
ZIP_RAS_CE_TYPE,
ZIP_CORE_INFO,
ZIP_CORE_EN,
ZIP_DRV_ALG_BITMAP_TB,
ZIP_ALG_BITMAP,
ZIP_CORE1_BITMAP,
ZIP_CORE2_BITMAP,
ZIP_CORE3_BITMAP,
ZIP_CORE4_BITMAP,
ZIP_CORE5_BITMAP,
};
int zip_create_qps(struct hisi_qp **qps, int qp_num, int node, u8 *alg_type);
int hisi_zip_register_to_crypto(struct hisi_qm *qm);
void hisi_zip_unregister_from_crypto(struct hisi_qm *qm);
bool hisi_zip_alg_support(struct hisi_qm *qm, u32 alg);
int hisi_dae_set_user_domain(struct hisi_qm *qm);
int hisi_dae_set_alg(struct hisi_qm *qm);
void hisi_dae_hw_error_disable(struct hisi_qm *qm);
void hisi_dae_hw_error_enable(struct hisi_qm *qm);
void hisi_dae_open_axi_master_ooo(struct hisi_qm *qm);
int hisi_dae_close_axi_master_ooo(struct hisi_qm *qm);
bool hisi_dae_dev_is_abnormal(struct hisi_qm *qm);
enum acc_err_result hisi_dae_get_err_result(struct hisi_qm *qm);
#endif
@@ -0,0 +1,727 @@
// SPDX-License-Identifier: GPL-2.0
/* Copyright (c) 2019 HiSilicon Limited. */
#include <crypto/internal/acompress.h>
#include <linux/bitfield.h>
#include <linux/bitmap.h>
#include <linux/dma-mapping.h>
#include <linux/scatterlist.h>
#include "zip.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)
#define HZIP_SQE_TYPE_M GENMASK(31, 28)
/* 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_DEFLATE 0x01
#define HZIP_ALG_TYPE_LZ4 0x04
#define HZIP_BUF_TYPE_M GENMASK(11, 8)
#define HZIP_SGL 0x1
#define HZIP_WIN_SIZE_M GENMASK(15, 12)
#define HZIP_16K_WINSZ 0x2
#define HZIP_ALG_PRIORITY 300
#define HZIP_SGL_SGE_NR 10
#define HZIP_ALG_DEFLATE GENMASK(5, 4)
#define HZIP_ALG_LZ4 BIT(8)
static DEFINE_MUTEX(zip_algs_lock);
static unsigned int zip_available_devs;
enum hisi_zip_alg_type {
HZIP_ALG_TYPE_COMP = 0,
HZIP_ALG_TYPE_DECOMP = 1,
};
enum {
HZIP_QPC_COMP,
HZIP_QPC_DECOMP,
HZIP_CTX_Q_NUM
};
#define GET_REQ_FROM_SQE(sqe) ((u64)(sqe)->dw26 | (u64)(sqe)->dw27 << 32)
#define COMP_NAME_TO_TYPE(alg_name) \
(!strcmp((alg_name), "deflate") ? HZIP_ALG_TYPE_DEFLATE : \
(!strcmp((alg_name), "lz4") ? HZIP_ALG_TYPE_LZ4 : 0))
struct hisi_zip_req {
struct acomp_req *req;
struct hisi_acc_hw_sgl *hw_src;
struct hisi_acc_hw_sgl *hw_dst;
dma_addr_t dma_src;
dma_addr_t dma_dst;
struct hisi_zip_qp_ctx *qp_ctx;
u16 req_id;
};
struct hisi_zip_req_q {
struct hisi_zip_req *q;
unsigned long *req_bitmap;
spinlock_t req_lock;
u16 size;
};
struct hisi_zip_qp_ctx {
struct hisi_qp *qp;
struct hisi_zip_req_q req_q;
struct hisi_acc_sgl_pool *sgl_pool;
struct hisi_zip *zip_dev;
struct hisi_zip_ctx *ctx;
u8 req_type;
};
struct hisi_zip_sqe_ops {
u8 sqe_type;
void (*fill_addr)(struct hisi_zip_sqe *sqe, struct hisi_zip_req *req);
void (*fill_buf_size)(struct hisi_zip_sqe *sqe, struct hisi_zip_req *req);
void (*fill_buf_type)(struct hisi_zip_sqe *sqe, u8 buf_type);
void (*fill_req_type)(struct hisi_zip_sqe *sqe, u8 req_type);
void (*fill_win_size)(struct hisi_zip_sqe *sqe, u8 win_size);
void (*fill_tag)(struct hisi_zip_sqe *sqe, struct hisi_zip_req *req);
void (*fill_sqe_type)(struct hisi_zip_sqe *sqe, u8 sqe_type);
u32 (*get_status)(struct hisi_zip_sqe *sqe);
u32 (*get_dstlen)(struct hisi_zip_sqe *sqe);
};
struct hisi_zip_ctx {
struct hisi_zip_qp_ctx qp_ctx[HZIP_CTX_Q_NUM];
const struct hisi_zip_sqe_ops *ops;
bool fallback;
};
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 > HISI_ACC_SGL_SGE_NR_MAX)
return -EINVAL;
return param_set_ushort(val, kp);
}
static const struct kernel_param_ops sgl_sge_nr_ops = {
.set = sgl_sge_nr_set,
.get = param_get_ushort,
};
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 int hisi_zip_fallback_do_work(struct acomp_req *acomp_req, bool is_decompress)
{
ACOMP_FBREQ_ON_STACK(fbreq, acomp_req);
int ret;
if (!is_decompress)
ret = crypto_acomp_compress(fbreq);
else
ret = crypto_acomp_decompress(fbreq);
if (ret) {
pr_err("failed to do fallback work, ret=%d\n", ret);
return ret;
}
acomp_req->dlen = fbreq->dlen;
return ret;
}
static struct hisi_zip_req *hisi_zip_create_req(struct hisi_zip_qp_ctx *qp_ctx,
struct acomp_req *req)
{
struct hisi_zip_req_q *req_q = &qp_ctx->req_q;
struct hisi_zip_req *q = req_q->q;
struct hisi_zip_req *req_cache;
int req_id;
spin_lock(&req_q->req_lock);
req_id = find_first_zero_bit(req_q->req_bitmap, req_q->size);
if (req_id >= req_q->size) {
spin_unlock(&req_q->req_lock);
dev_dbg(&qp_ctx->qp->qm->pdev->dev, "req cache is full!\n");
return ERR_PTR(-EAGAIN);
}
set_bit(req_id, req_q->req_bitmap);
spin_unlock(&req_q->req_lock);
req_cache = q + req_id;
req_cache->req_id = req_id;
req_cache->req = req;
req_cache->qp_ctx = qp_ctx;
return req_cache;
}
static void hisi_zip_remove_req(struct hisi_zip_qp_ctx *qp_ctx,
struct hisi_zip_req *req)
{
struct hisi_zip_req_q *req_q = &qp_ctx->req_q;
spin_lock(&req_q->req_lock);
clear_bit(req->req_id, req_q->req_bitmap);
spin_unlock(&req_q->req_lock);
}
static void hisi_zip_fill_addr(struct hisi_zip_sqe *sqe, struct hisi_zip_req *req)
{
sqe->source_addr_l = lower_32_bits(req->dma_src);
sqe->source_addr_h = upper_32_bits(req->dma_src);
sqe->dest_addr_l = lower_32_bits(req->dma_dst);
sqe->dest_addr_h = upper_32_bits(req->dma_dst);
}
static void hisi_zip_fill_buf_size(struct hisi_zip_sqe *sqe, struct hisi_zip_req *req)
{
struct acomp_req *a_req = req->req;
sqe->input_data_length = a_req->slen;
sqe->dest_avail_out = a_req->dlen;
}
static void hisi_zip_fill_buf_type(struct hisi_zip_sqe *sqe, u8 buf_type)
{
u32 val;
val = sqe->dw9 & ~HZIP_BUF_TYPE_M;
val |= FIELD_PREP(HZIP_BUF_TYPE_M, buf_type);
sqe->dw9 = val;
}
static void hisi_zip_fill_req_type(struct hisi_zip_sqe *sqe, u8 req_type)
{
u32 val;
val = sqe->dw9 & ~HZIP_REQ_TYPE_M;
val |= FIELD_PREP(HZIP_REQ_TYPE_M, req_type);
sqe->dw9 = val;
}
static void hisi_zip_fill_win_size(struct hisi_zip_sqe *sqe, u8 win_size)
{
u32 val;
val = sqe->dw9 & ~HZIP_WIN_SIZE_M;
val |= FIELD_PREP(HZIP_WIN_SIZE_M, win_size);
sqe->dw9 = val;
}
static void hisi_zip_fill_tag(struct hisi_zip_sqe *sqe, struct hisi_zip_req *req)
{
sqe->dw26 = lower_32_bits((u64)req);
sqe->dw27 = upper_32_bits((u64)req);
}
static void hisi_zip_fill_sqe_type(struct hisi_zip_sqe *sqe, u8 sqe_type)
{
u32 val;
val = sqe->dw7 & ~HZIP_SQE_TYPE_M;
val |= FIELD_PREP(HZIP_SQE_TYPE_M, sqe_type);
sqe->dw7 = val;
}
static void hisi_zip_fill_sqe(struct hisi_zip_ctx *ctx, struct hisi_zip_sqe *sqe,
u8 req_type, struct hisi_zip_req *req)
{
const struct hisi_zip_sqe_ops *ops = ctx->ops;
memset(sqe, 0, sizeof(struct hisi_zip_sqe));
ops->fill_addr(sqe, req);
ops->fill_buf_size(sqe, req);
ops->fill_buf_type(sqe, HZIP_SGL);
ops->fill_req_type(sqe, req_type);
ops->fill_win_size(sqe, HZIP_16K_WINSZ);
ops->fill_tag(sqe, req);
ops->fill_sqe_type(sqe, ops->sqe_type);
}
static int hisi_zip_do_work(struct hisi_zip_qp_ctx *qp_ctx,
struct hisi_zip_req *req)
{
struct hisi_acc_sgl_pool *pool = qp_ctx->sgl_pool;
struct hisi_zip_dfx *dfx = &qp_ctx->zip_dev->dfx;
struct acomp_req *a_req = req->req;
struct hisi_qp *qp = qp_ctx->qp;
struct device *dev = &qp->qm->pdev->dev;
struct hisi_zip_sqe zip_sqe;
int ret;
if (unlikely(!a_req->src || !a_req->slen || !a_req->dst || !a_req->dlen))
return -EINVAL;
req->hw_src = hisi_acc_sg_buf_map_to_hw_sgl(dev, a_req->src, pool,
req->req_id << 1, &req->dma_src,
DMA_TO_DEVICE);
if (IS_ERR(req->hw_src)) {
dev_err(dev, "failed to map the src buffer to hw sgl (%ld)!\n",
PTR_ERR(req->hw_src));
return PTR_ERR(req->hw_src);
}
req->hw_dst = hisi_acc_sg_buf_map_to_hw_sgl(dev, a_req->dst, pool,
(req->req_id << 1) + 1,
&req->dma_dst, DMA_FROM_DEVICE);
if (IS_ERR(req->hw_dst)) {
ret = PTR_ERR(req->hw_dst);
dev_err(dev, "failed to map the dst buffer to hw sgl (%d)!\n",
ret);
goto err_unmap_input;
}
hisi_zip_fill_sqe(qp_ctx->ctx, &zip_sqe, qp_ctx->req_type, req);
/* send command to start a task */
atomic64_inc(&dfx->send_cnt);
ret = hisi_qp_send(qp, &zip_sqe);
if (unlikely(ret < 0)) {
atomic64_inc(&dfx->send_busy_cnt);
ret = -EAGAIN;
dev_dbg_ratelimited(dev, "failed to send request!\n");
goto err_unmap_output;
}
return -EINPROGRESS;
err_unmap_output:
hisi_acc_sg_buf_unmap(dev, a_req->dst, req->hw_dst, DMA_FROM_DEVICE);
err_unmap_input:
hisi_acc_sg_buf_unmap(dev, a_req->src, req->hw_src, DMA_TO_DEVICE);
return ret;
}
static u32 hisi_zip_get_status(struct hisi_zip_sqe *sqe)
{
return sqe->dw3 & HZIP_BD_STATUS_M;
}
static u32 hisi_zip_get_dstlen(struct hisi_zip_sqe *sqe)
{
return sqe->produced;
}
static void hisi_zip_acomp_cb(struct hisi_qp *qp, void *data)
{
struct hisi_zip_sqe *sqe = data;
struct hisi_zip_req *req = (struct hisi_zip_req *)GET_REQ_FROM_SQE(sqe);
struct hisi_zip_qp_ctx *qp_ctx = req->qp_ctx;
const struct hisi_zip_sqe_ops *ops = qp_ctx->ctx->ops;
struct hisi_zip_dfx *dfx = &qp_ctx->zip_dev->dfx;
struct device *dev = &qp->qm->pdev->dev;
struct acomp_req *acomp_req = req->req;
int err = 0;
u32 status;
atomic64_inc(&dfx->recv_cnt);
status = ops->get_status(sqe);
if (unlikely(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;
}
hisi_acc_sg_buf_unmap(dev, acomp_req->dst, req->hw_dst, DMA_FROM_DEVICE);
hisi_acc_sg_buf_unmap(dev, acomp_req->src, req->hw_src, DMA_TO_DEVICE);
acomp_req->dlen = ops->get_dstlen(sqe);
if (acomp_req->base.complete)
acomp_request_complete(acomp_req, err);
hisi_zip_remove_req(qp_ctx, req);
}
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[HZIP_QPC_COMP];
struct hisi_zip_req *req;
struct device *dev;
int ret;
if (ctx->fallback)
return hisi_zip_fallback_do_work(acomp_req, 0);
dev = &qp_ctx->qp->qm->pdev->dev;
req = hisi_zip_create_req(qp_ctx, acomp_req);
if (IS_ERR(req))
return PTR_ERR(req);
ret = hisi_zip_do_work(qp_ctx, req);
if (unlikely(ret != -EINPROGRESS)) {
dev_info_ratelimited(dev, "failed to do compress (%d)!\n", ret);
hisi_zip_remove_req(qp_ctx, req);
}
return ret;
}
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[HZIP_QPC_DECOMP];
struct hisi_zip_req *req;
struct device *dev;
int ret;
if (ctx->fallback)
return hisi_zip_fallback_do_work(acomp_req, 1);
dev = &qp_ctx->qp->qm->pdev->dev;
req = hisi_zip_create_req(qp_ctx, acomp_req);
if (IS_ERR(req))
return PTR_ERR(req);
ret = hisi_zip_do_work(qp_ctx, req);
if (unlikely(ret != -EINPROGRESS)) {
dev_info_ratelimited(dev, "failed to do decompress (%d)!\n",
ret);
hisi_zip_remove_req(qp_ctx, req);
}
return ret;
}
static int hisi_zip_decompress(struct acomp_req *acomp_req)
{
return hisi_zip_fallback_do_work(acomp_req, 1);
}
static const struct hisi_zip_sqe_ops hisi_zip_ops = {
.sqe_type = 0x3,
.fill_addr = hisi_zip_fill_addr,
.fill_buf_size = hisi_zip_fill_buf_size,
.fill_buf_type = hisi_zip_fill_buf_type,
.fill_req_type = hisi_zip_fill_req_type,
.fill_win_size = hisi_zip_fill_win_size,
.fill_tag = hisi_zip_fill_tag,
.fill_sqe_type = hisi_zip_fill_sqe_type,
.get_status = hisi_zip_get_status,
.get_dstlen = hisi_zip_get_dstlen,
};
static int hisi_zip_ctx_init(struct hisi_zip_ctx *hisi_zip_ctx, u8 req_type, int node)
{
struct hisi_qp *qps[HZIP_CTX_Q_NUM] = { NULL };
struct hisi_zip_qp_ctx *qp_ctx;
u8 alg_type[HZIP_CTX_Q_NUM];
struct hisi_zip *hisi_zip;
int ret, i;
/* alg_type = 0 for compress, 1 for decompress in hw sqe */
for (i = 0; i < HZIP_CTX_Q_NUM; i++)
alg_type[i] = i;
ret = zip_create_qps(qps, HZIP_CTX_Q_NUM, node, alg_type);
if (ret) {
pr_err("failed to create zip qps (%d)!\n", ret);
return -ENODEV;
}
hisi_zip = container_of(qps[0]->qm, struct hisi_zip, qm);
for (i = 0; i < HZIP_CTX_Q_NUM; i++) {
qp_ctx = &hisi_zip_ctx->qp_ctx[i];
qp_ctx->ctx = hisi_zip_ctx;
qp_ctx->zip_dev = hisi_zip;
qp_ctx->req_type = req_type;
qp_ctx->qp = qps[i];
}
hisi_zip_ctx->ops = &hisi_zip_ops;
return 0;
}
static void hisi_zip_ctx_exit(struct hisi_zip_ctx *hisi_zip_ctx)
{
struct hisi_qp *qps[HZIP_CTX_Q_NUM] = { NULL };
int i;
for (i = 0; i < HZIP_CTX_Q_NUM; i++)
qps[i] = hisi_zip_ctx->qp_ctx[i].qp;
hisi_qm_free_qps(qps, HZIP_CTX_Q_NUM);
}
static int hisi_zip_create_req_q(struct hisi_zip_ctx *ctx)
{
u16 q_depth = ctx->qp_ctx[0].qp->sq_depth;
struct hisi_zip_req_q *req_q;
int i, ret;
for (i = 0; i < HZIP_CTX_Q_NUM; i++) {
req_q = &ctx->qp_ctx[i].req_q;
req_q->size = q_depth;
req_q->req_bitmap = bitmap_zalloc(req_q->size, GFP_KERNEL);
if (!req_q->req_bitmap) {
ret = -ENOMEM;
if (i == 0)
return ret;
goto err_free_comp_q;
}
spin_lock_init(&req_q->req_lock);
req_q->q = kzalloc_objs(struct hisi_zip_req, req_q->size);
if (!req_q->q) {
ret = -ENOMEM;
if (i == 0)
goto err_free_comp_bitmap;
else
goto err_free_decomp_bitmap;
}
}
return 0;
err_free_decomp_bitmap:
bitmap_free(ctx->qp_ctx[HZIP_QPC_DECOMP].req_q.req_bitmap);
err_free_comp_q:
kfree(ctx->qp_ctx[HZIP_QPC_COMP].req_q.q);
err_free_comp_bitmap:
bitmap_free(ctx->qp_ctx[HZIP_QPC_COMP].req_q.req_bitmap);
return ret;
}
static void hisi_zip_release_req_q(struct hisi_zip_ctx *ctx)
{
int i;
for (i = 0; i < HZIP_CTX_Q_NUM; i++) {
kfree(ctx->qp_ctx[i].req_q.q);
bitmap_free(ctx->qp_ctx[i].req_q.req_bitmap);
}
}
static int hisi_zip_create_sgl_pool(struct hisi_zip_ctx *ctx)
{
u16 q_depth = ctx->qp_ctx[0].qp->sq_depth;
struct hisi_zip_qp_ctx *tmp;
struct device *dev;
int i;
for (i = 0; i < HZIP_CTX_Q_NUM; i++) {
tmp = &ctx->qp_ctx[i];
dev = &tmp->qp->qm->pdev->dev;
tmp->sgl_pool = hisi_acc_create_sgl_pool(dev, q_depth << 1,
sgl_sge_nr);
if (IS_ERR(tmp->sgl_pool)) {
if (i == 1)
goto err_free_sgl_pool0;
return -ENOMEM;
}
}
return 0;
err_free_sgl_pool0:
hisi_acc_free_sgl_pool(&ctx->qp_ctx[HZIP_QPC_COMP].qp->qm->pdev->dev,
ctx->qp_ctx[HZIP_QPC_COMP].sgl_pool);
return -ENOMEM;
}
static void hisi_zip_release_sgl_pool(struct hisi_zip_ctx *ctx)
{
int i;
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);
}
static void hisi_zip_set_acomp_cb(struct hisi_zip_ctx *ctx,
void (*fn)(struct hisi_qp *, void *))
{
int i;
for (i = 0; i < HZIP_CTX_Q_NUM; i++)
ctx->qp_ctx[i].qp->req_cb = fn;
}
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), tfm->base.node);
if (ret) {
pr_err("failed to init ctx (%d)!\n", ret);
goto switch_to_soft;
}
dev = &ctx->qp_ctx[0].qp->qm->pdev->dev;
ret = hisi_zip_create_req_q(ctx);
if (ret) {
dev_err(dev, "failed to create request queue (%d)!\n", ret);
goto err_ctx_exit;
}
ret = hisi_zip_create_sgl_pool(ctx);
if (ret) {
dev_err(dev, "failed to create sgl pool (%d)!\n", ret);
goto err_release_req_q;
}
hisi_zip_set_acomp_cb(ctx, hisi_zip_acomp_cb);
return 0;
err_release_req_q:
hisi_zip_release_req_q(ctx);
err_ctx_exit:
hisi_zip_ctx_exit(ctx);
switch_to_soft:
ctx->fallback = true;
return 0;
}
static void hisi_zip_acomp_exit(struct crypto_acomp *tfm)
{
struct hisi_zip_ctx *ctx = crypto_tfm_ctx(&tfm->base);
if (ctx->fallback)
return;
hisi_zip_release_sgl_pool(ctx);
hisi_zip_release_req_q(ctx);
hisi_zip_ctx_exit(ctx);
}
static struct acomp_alg hisi_zip_acomp_deflate = {
.init = hisi_zip_acomp_init,
.exit = hisi_zip_acomp_exit,
.compress = hisi_zip_acompress,
.decompress = hisi_zip_adecompress,
.base = {
.cra_name = "deflate",
.cra_driver_name = "hisi-deflate-acomp",
.cra_flags = CRYPTO_ALG_ASYNC |
CRYPTO_ALG_NEED_FALLBACK,
.cra_module = THIS_MODULE,
.cra_priority = HZIP_ALG_PRIORITY,
.cra_ctxsize = sizeof(struct hisi_zip_ctx),
}
};
static int hisi_zip_register_deflate(struct hisi_qm *qm)
{
int ret;
if (!hisi_zip_alg_support(qm, HZIP_ALG_DEFLATE))
return 0;
ret = crypto_register_acomp(&hisi_zip_acomp_deflate);
if (ret)
dev_err(&qm->pdev->dev, "failed to register to deflate (%d)!\n", ret);
return ret;
}
static void hisi_zip_unregister_deflate(struct hisi_qm *qm)
{
if (!hisi_zip_alg_support(qm, HZIP_ALG_DEFLATE))
return;
crypto_unregister_acomp(&hisi_zip_acomp_deflate);
}
static struct acomp_alg hisi_zip_acomp_lz4 = {
.init = hisi_zip_acomp_init,
.exit = hisi_zip_acomp_exit,
.compress = hisi_zip_acompress,
.decompress = hisi_zip_decompress,
.base = {
.cra_name = "lz4",
.cra_driver_name = "hisi-lz4-acomp",
.cra_flags = CRYPTO_ALG_ASYNC |
CRYPTO_ALG_NEED_FALLBACK,
.cra_module = THIS_MODULE,
.cra_priority = HZIP_ALG_PRIORITY,
.cra_ctxsize = sizeof(struct hisi_zip_ctx),
}
};
static int hisi_zip_register_lz4(struct hisi_qm *qm)
{
int ret;
if (!hisi_zip_alg_support(qm, HZIP_ALG_LZ4))
return 0;
ret = crypto_register_acomp(&hisi_zip_acomp_lz4);
if (ret)
dev_err(&qm->pdev->dev, "failed to register to LZ4 (%d)!\n", ret);
return ret;
}
static void hisi_zip_unregister_lz4(struct hisi_qm *qm)
{
if (!hisi_zip_alg_support(qm, HZIP_ALG_LZ4))
return;
crypto_unregister_acomp(&hisi_zip_acomp_lz4);
}
int hisi_zip_register_to_crypto(struct hisi_qm *qm)
{
int ret = 0;
mutex_lock(&zip_algs_lock);
if (zip_available_devs) {
zip_available_devs++;
goto unlock;
}
ret = hisi_zip_register_deflate(qm);
if (ret)
goto unlock;
ret = hisi_zip_register_lz4(qm);
if (ret)
goto unreg_deflate;
zip_available_devs++;
mutex_unlock(&zip_algs_lock);
return 0;
unreg_deflate:
hisi_zip_unregister_deflate(qm);
unlock:
mutex_unlock(&zip_algs_lock);
return ret;
}
void hisi_zip_unregister_from_crypto(struct hisi_qm *qm)
{
mutex_lock(&zip_algs_lock);
if (--zip_available_devs)
goto unlock;
hisi_zip_unregister_deflate(qm);
hisi_zip_unregister_lz4(qm);
unlock:
mutex_unlock(&zip_algs_lock);
}
File diff suppressed because it is too large Load Diff