Acc
Threads by month
- ----- 2026 -----
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2025 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
September 2026
- 2 participants
- 5 discussions
[PATCH 2/4] uadk: unify SEC BD3 paths and fix CE digest/cipher result check
by Chenghai Huang 24 Sep '26
by Chenghai Huang 24 Sep '26
24 Sep '26
From: Wenkai Lin <linwenkai6(a)hisilicon.com>
The SEC module has duplicated BD3 fill/parse paths across cipher,
digest, and aead, a stream mode scene misconfiguration for common
digests, and silently swallowed computation errors in the CE driver.
The following three issues are addressed:
Unify the BD3 fill/parse paths for cipher, digest, and aead on V3+
hardware. Previously each algorithm duplicated udata handling, scene
selection, and DIF detection in the qm_fill/qm_parse entry points.
Route everything through fill_xxx_bd3/parse_xxx_bd3, add DIF and
udata address helpers, select scene (STORAGE/IPSEC/STREAM) by
is_storage, and guard unmap in error paths. BD1/BD2 paths are
retained for V2 hardware.
The common digest (such as SHA/SM3) that is not GMAC supports
streaming hash processing, but SCENE_STREAM was only described for
CTR/GCM streaming encryption in the FS, and the hash function for
streaming mode in FS014/FS017 was ignored. Use SCENE_STREAM for
common digests; GMAC uses SCENE_IPSEC independently.
In sm3_ce_drv_send and isa_ce_cipher_send, the return value of the
software digest/cipher computation is silently overwritten by the
subsequent wd_get_sqe_from_queue call. If the computation fails, the
error is swallowed and the function may return success. Add an early
return on error before calling wd_get_sqe_from_queue.
Signed-off-by: Wenkai Lin <linwenkai6(a)hisilicon.com>
---
drv/isa_ce_sm3.c | 2 +
drv/isa_ce_sm4.c | 2 +
v1/drv/hisi_sec_udrv.c | 465 ++++++++++++++++++++++++++---------------
3 files changed, 298 insertions(+), 171 deletions(-)
diff --git a/drv/isa_ce_sm3.c b/drv/isa_ce_sm3.c
index b41f6c5..117b95e 100644
--- a/drv/isa_ce_sm3.c
+++ b/drv/isa_ce_sm3.c
@@ -374,6 +374,8 @@ static int sm3_ce_drv_send(handle_t ctx, void *digest_msg)
WD_ERR("invalid digest mode!\n");
ret = -WD_EINVAL;
}
+ if (ret)
+ return ret;
ret = wd_get_sqe_from_queue(sfctx, msg->tag);
if (ret)
diff --git a/drv/isa_ce_sm4.c b/drv/isa_ce_sm4.c
index 863b99e..7547c00 100644
--- a/drv/isa_ce_sm4.c
+++ b/drv/isa_ce_sm4.c
@@ -399,6 +399,8 @@ static int isa_ce_cipher_send(handle_t ctx, void *wd_msg)
ret = sm4_xts_encrypt(msg, &rkey);
else
ret = sm4_xts_decrypt(msg, &rkey);
+ if (ret)
+ return ret;
break;
default:
WD_ERR("The current block cipher mode is not supported!\n");
diff --git a/v1/drv/hisi_sec_udrv.c b/v1/drv/hisi_sec_udrv.c
index cf4bcd9..6ad6c57 100644
--- a/v1/drv/hisi_sec_udrv.c
+++ b/v1/drv/hisi_sec_udrv.c
@@ -823,11 +823,6 @@ static int fill_cipher_bd3_alg(struct wcrypto_cipher_msg *msg,
struct hisi_sec_bd3_sqe *sqe)
{
int ret = WD_SUCCESS;
-
- ret = cipher_param_check(msg);
- if (unlikely(ret))
- return ret;
-
__u8 c_key_len = 0;
switch (msg->alg) {
@@ -971,19 +966,72 @@ static int fill_cipher_bd3_mode(struct wcrypto_cipher_msg *msg,
return ret;
}
+static void fill_cipher_bd3_dif(struct hisi_sec_bd3_sqe *sqe,
+ struct wd_sec_udata *udata)
+{
+ sqe->skip_data.gran_num = udata->gran_num;
+ sqe->skip_data.src_skip_data_len = udata->src_offset;
+ sqe->skip_data.dst_skip_data_len = udata->dst_offset;
+
+ sqe->storage_scene.gen_ver_val = udata->dif.ver;
+ sqe->storage_scene.gen_app_val = udata->dif.app;
+ sqe->storage_scene.gen_page_pad_ctrl = udata->dif.ctrl.gen.page_layout_gen_type;
+ sqe->storage_scene.gen_grd_ctrl = udata->dif.ctrl.gen.grd_gen_type;
+ sqe->storage_scene.gen_ver_ctrl = udata->dif.ctrl.gen.ver_gen_type;
+ sqe->storage_scene.gen_app_ctrl = udata->dif.ctrl.gen.app_gen_type;
+ sqe->storage_scene.gen_ref_ctrl = udata->dif.ctrl.gen.ref_gen_type;
+ sqe->storage_scene.page_pad_type = udata->dif.ctrl.gen.page_layout_pad_type;
+ sqe->storage_scene.block_size = udata->block_size;
+ sqe->storage_scene.private_info = udata->dif.priv_info;
+ sqe->storage_scene.chk_grd_ctrl = udata->dif.ctrl.verify.grd_verify_type;
+ sqe->storage_scene.chk_ref_ctrl = udata->dif.ctrl.verify.ref_verify_type;
+ sqe->storage_scene.lba_l = udata->dif.lba & QM_L32BITS_MASK;
+ sqe->storage_scene.lba_h = udata->dif.lba >> QM_HADDR_SHIFT;
+}
+
+static void fill_cipher_bd3_udata_addr(struct wcrypto_cipher_msg *msg,
+ struct hisi_sec_bd3_sqe *sqe, __u8 is_storage)
+{
+ uintptr_t phy;
+
+ phy = (uintptr_t)msg->in;
+ sqe->data_src_addr_l = (__u32)(phy & QM_L32BITS_MASK);
+ sqe->data_src_addr_h = HI_U32(phy);
+ phy = (uintptr_t)msg->out;
+ sqe->data_dst_addr_l = (__u32)(phy & QM_L32BITS_MASK);
+ sqe->data_dst_addr_h = HI_U32(phy);
+ phy = (uintptr_t)msg->key;
+ sqe->c_key_addr_l = (__u32)(phy & QM_L32BITS_MASK);
+ sqe->c_key_addr_h = HI_U32(phy);
+ if (msg->iv_bytes) {
+ phy = (uintptr_t)msg->iv;
+ if (is_storage) {
+ sqe->skip_data.c_iv_a_key_l = (__u32)(phy & QM_L32BITS_MASK);
+ sqe->skip_data.c_iv_a_key_h = HI_U32(phy);
+ } else {
+ sqe->ipsec_scene.c_ivin_addr_l = (__u32)(phy & QM_L32BITS_MASK);
+ sqe->ipsec_scene.c_ivin_addr_h = HI_U32(phy);
+ }
+ }
+}
+
static int fill_cipher_bd3(struct wd_queue *q, struct hisi_sec_bd3_sqe *sqe,
struct wcrypto_cipher_msg *msg, struct wcrypto_cipher_tag *tag)
{
+ struct wd_sec_udata *udata = tag ? tag->priv : NULL;
+ __u8 is_storage = udata && udata->gran_num != 0;
int ret;
+ if (!is_storage) {
+ ret = cipher_param_check(msg);
+ if (unlikely(ret))
+ return ret;
+ }
+
sqe->type = BD_TYPE3;
- sqe->scene = SCENE_IPSEC;
+ sqe->scene = is_storage ? SCENE_STORAGE : SCENE_IPSEC;
sqe->de = DATA_DST_ADDR_ENABLE;
- if (msg->in_bytes > MAX_CIPHER_LENGTH) {
- WD_ERR("input data is too large.\n");
- return -WD_EINVAL;
- }
sqe->c_len = msg->in_bytes;
fill_bd3_addr_type(msg->data_fmt, sqe);
@@ -1000,10 +1048,19 @@ static int fill_cipher_bd3(struct wd_queue *q, struct hisi_sec_bd3_sqe *sqe,
return ret;
}
- ret = fill_cipher_bd3_area(q, msg, sqe);
- if (ret != WD_SUCCESS) {
- WD_ERR("fail to fill_cipher_bd3_addr.\n");
- return ret;
+ if (is_storage && msg->mode == WCRYPTO_CIPHER_XTS)
+ sqe->ci_gen = CI_GEN_BY_LBA;
+
+ if (udata) {
+ fill_cipher_bd3_udata_addr(msg, sqe, is_storage);
+ if (is_storage)
+ fill_cipher_bd3_dif(sqe, udata);
+ } else {
+ ret = fill_cipher_bd3_area(q, msg, sqe);
+ if (ret != WD_SUCCESS) {
+ WD_ERR("fail to fill_cipher_bd3_addr.\n");
+ return ret;
+ }
}
if (tag)
@@ -1129,10 +1186,8 @@ int qm_fill_cipher_bd3_sqe(void *message, struct qm_queue_info *info, __u16 i)
{
struct wcrypto_cipher_msg *msg = message;
struct wcrypto_cipher_tag *tag = (void *)(uintptr_t)msg->usr_data;
- struct wd_sec_udata *udata = tag->priv;
struct wd_queue *q = info->q;
struct hisi_sec_bd3_sqe *sqe3;
- struct hisi_sec_sqe *sqe;
uintptr_t temp;
int ret;
@@ -1144,35 +1199,17 @@ int qm_fill_cipher_bd3_sqe(void *message, struct qm_queue_info *info, __u16 i)
}
temp = (uintptr_t)info->sq_base + i * info->sqe_size;
+ sqe3 = (struct hisi_sec_bd3_sqe *)temp;
+ memset(sqe3, 0, sizeof(struct hisi_sec_bd3_sqe));
- /*
- * For user self-defined data with DIF scence, will fill BD1.
- * For user self-defined data without DIF scence, will fill BD2.
- * For non user self-defined data scence, will fill BD3.
- */
- if (udata) {
- sqe = (struct hisi_sec_sqe *)temp;
- memset(sqe, 0, sizeof(struct hisi_sec_sqe));
- if (udata->gran_num != 0)
- ret = fill_cipher_bd1(q, sqe, msg, tag);
- else
- ret = fill_cipher_bd2(q, sqe, msg, tag);
- } else {
- sqe3 = (struct hisi_sec_bd3_sqe *)temp;
- memset(sqe3, 0, sizeof(struct hisi_sec_bd3_sqe));
- ret = fill_cipher_bd3(q, sqe3, msg, tag);
- }
-
+ ret = fill_cipher_bd3(q, sqe3, msg, tag);
if (ret != WD_SUCCESS)
return ret;
info->req_cache[i] = msg;
#ifdef DEBUG_LOG
- if (udata)
- sec_dump_bd((unsigned char *)sqe, SQE_BYTES_NUMS);
- else
- sec_dump_bd((unsigned char *)sqe3, SQE_BYTES_NUMS);
+ sec_dump_bd((unsigned char *)sqe3, SQE_BYTES_NUMS);
#endif
return ret;
@@ -1707,24 +1744,45 @@ static int digest_param_check_v3(struct wcrypto_digest_msg *msg)
return WD_SUCCESS;
}
-static int fill_digest_bd3(struct wd_queue *q, struct hisi_sec_bd3_sqe *sqe,
- struct wcrypto_digest_msg *msg, struct wcrypto_digest_tag *tag)
+static void fill_digest_bd3_udata_addr(struct wcrypto_digest_msg *msg,
+ struct hisi_sec_bd3_sqe *sqe)
{
uintptr_t phy;
- int ret;
- ret = digest_param_check_v3(msg);
- if (unlikely(ret))
- return ret;
+ phy = (uintptr_t)msg->in;
+ sqe->data_src_addr_l = (__u32)(phy & QM_L32BITS_MASK);
+ sqe->data_src_addr_h = HI_U32(phy);
+ phy = (uintptr_t)msg->out;
+ sqe->mac_addr_l = (__u32)(phy & QM_L32BITS_MASK);
+ sqe->mac_addr_h = HI_U32(phy);
- sqe->type = BD_TYPE3;
- if (msg->alg == WCRYPTO_AES_GMAC)
- sqe->scene = SCENE_IPSEC;
- else
- sqe->scene = SCENE_STREAM;
+ if (msg->mode == WCRYPTO_DIGEST_HMAC) {
+ sqe->a_key_len = msg->key_bytes / SEC_SQE_LEN_RATE;
+ phy = (uintptr_t)msg->key;
+ sqe->auth_key_iv.a_key_addr_l = (__u32)(phy & QM_L32BITS_MASK);
+ sqe->auth_key_iv.a_key_addr_h = HI_U32(phy);
+ }
+}
+
+static void fill_digest_bd3_dif(struct hisi_sec_bd3_sqe *sqe,
+ struct wd_sec_udata *udata)
+{
+ sqe->skip_data.gran_num = udata->gran_num;
+ sqe->skip_data.src_skip_data_len = udata->src_offset;
+ sqe->storage_scene.block_size = udata->block_size;
+ sqe->storage_scene.private_info = udata->dif.priv_info;
+ sqe->storage_scene.chk_grd_ctrl = udata->dif.ctrl.verify.grd_verify_type;
+ sqe->storage_scene.chk_ref_ctrl = udata->dif.ctrl.verify.ref_verify_type;
+ sqe->storage_scene.lba_l = udata->dif.lba & QM_L32BITS_MASK;
+ sqe->storage_scene.lba_h = udata->dif.lba >> QM_HADDR_SHIFT;
+}
+
+static int fill_digest_bd3_map(struct wd_queue *q, struct hisi_sec_bd3_sqe *sqe,
+ struct wcrypto_digest_msg *msg)
+{
+ uintptr_t phy;
+ int ret;
- sqe->auth = AUTH_MAC_CALCULATE;
- sqe->a_len = msg->in_bytes;
phy = (uintptr_t)drv_iova_map(q, msg->in, msg->in_bytes);
if (unlikely(!phy)) {
WD_ERR("Get message in dma address fail!\n");
@@ -1740,33 +1798,84 @@ static int fill_digest_bd3(struct wd_queue *q, struct hisi_sec_bd3_sqe *sqe,
WD_ERR("Get digest bd3 message out dma address fail!\n");
goto map_out_error;
}
+
+ ret = set_hmac_mode_v3(msg, sqe, q);
+ if (unlikely(ret))
+ goto unmap_out;
+
+ return WD_SUCCESS;
+
+unmap_out:
+ unmap_addr(q, msg->out, msg->out_bytes, sqe->mac_addr_l,
+ sqe->mac_addr_h, msg->data_fmt);
+map_out_error:
+ phy = DMA_ADDR(sqe->data_src_addr_h, sqe->data_src_addr_l);
+ drv_iova_unmap(q, msg->in, (void *)(uintptr_t)phy, msg->in_bytes);
+ return ret;
+}
+
+static int fill_digest_bd3(struct wd_queue *q, struct hisi_sec_bd3_sqe *sqe,
+ struct wcrypto_digest_msg *msg, struct wcrypto_digest_tag *tag)
+{
+ struct wd_sec_udata *udata = tag ? tag->priv : NULL;
+ __u8 is_storage = udata && udata->gran_num != 0;
+ uintptr_t phy;
+ int ret;
+
+ ret = digest_param_check_v3(msg);
+ if (unlikely(ret))
+ return ret;
+
+ sqe->type = BD_TYPE3;
+
+ /*
+ * GMAC is an IPSEC-specific auth algo (RFC4543); other digests use
+ * stream scene for long-data hash processing.
+ */
+ if (is_storage)
+ sqe->scene = SCENE_STORAGE;
+ else if (msg->alg == WCRYPTO_AES_GMAC)
+ sqe->scene = SCENE_IPSEC;
+ else
+ sqe->scene = SCENE_STREAM;
+
+ sqe->auth = AUTH_MAC_CALCULATE;
+ sqe->a_len = msg->in_bytes;
+
+ if (udata) {
+ fill_digest_bd3_udata_addr(msg, sqe);
+ if (is_storage)
+ fill_digest_bd3_dif(sqe, udata);
+ } else {
+ ret = fill_digest_bd3_map(q, sqe, msg);
+ if (unlikely(ret))
+ return ret;
+ }
+
sqe->mac_len = msg->out_bytes / WORD_BYTES;
ret = fill_digest_bd3_alg(msg, sqe);
if (ret != WD_SUCCESS) {
WD_ERR("fill_digest_bd3_alg fail!\n");
- goto map_alg_error;
+ goto unmap;
}
ret = qm_fill_digest_long_bd3(msg, sqe);
if (ret)
- goto map_alg_error;
-
- ret = set_hmac_mode_v3(msg, sqe, q);
- if (ret)
- goto map_alg_error;
+ goto unmap;
if (tag)
sqe->tag_l = tag->wcrypto_tag.ctx_id;
return ret;
-map_alg_error:
- unmap_addr(q, msg->out, msg->out_bytes, sqe->mac_addr_l,
- sqe->mac_addr_h, msg->data_fmt);
-map_out_error:
- phy = DMA_ADDR(sqe->data_src_addr_h, sqe->data_src_addr_l);
- drv_iova_unmap(q, msg->in, (void *)(uintptr_t)phy, msg->in_bytes);
+unmap:
+ if (!udata) {
+ unmap_addr(q, msg->out, msg->out_bytes, sqe->mac_addr_l,
+ sqe->mac_addr_h, msg->data_fmt);
+ phy = DMA_ADDR(sqe->data_src_addr_h, sqe->data_src_addr_l);
+ drv_iova_unmap(q, msg->in, (void *)(uintptr_t)phy, msg->in_bytes);
+ }
return ret;
}
@@ -1776,23 +1885,15 @@ int qm_fill_digest_bd3_sqe(void *message, struct qm_queue_info *info, __u16 i)
struct wcrypto_digest_tag *tag = (void *)(uintptr_t)msg->usr_data;
struct wd_queue *q = info->q;
struct hisi_sec_bd3_sqe *sqe;
- struct hisi_sec_sqe *sqe2;
uintptr_t temp;
int ret;
temp = (uintptr_t)info->sq_base + i * info->sqe_size;
+ sqe = (struct hisi_sec_bd3_sqe *)temp;
+ memset(sqe, 0, sizeof(struct hisi_sec_bd3_sqe));
+ fill_bd3_addr_type(msg->data_fmt, sqe);
- if (tag->priv) {
- sqe2 = (struct hisi_sec_sqe *)temp;
- memset(sqe2, 0, sizeof(struct hisi_sec_sqe));
- fill_bd_addr_type(msg->data_fmt, sqe2);
- ret = fill_digest_bd_udata(q, sqe2, msg, tag);
- } else {
- sqe = (struct hisi_sec_bd3_sqe *)temp;
- memset(sqe, 0, sizeof(struct hisi_sec_bd3_sqe));
- fill_bd3_addr_type(msg->data_fmt, sqe);
- ret = fill_digest_bd3(q, sqe, msg, tag);
- }
+ ret = fill_digest_bd3(q, sqe, msg, tag);
if (ret != WD_SUCCESS)
return ret;
@@ -1890,7 +1991,7 @@ static void parse_cipher_bd2(struct wd_queue *q, struct hisi_sec_sqe *sqe,
/* In user self-define data case, may not need addr map, just return */
tag = (void *)(uintptr_t)cipher_msg->usr_data;
- if (tag->priv)
+ if (tag && tag->priv)
return;
dma_addr = DMA_ADDR(sqe->type2.data_src_addr_h,
@@ -1919,16 +2020,24 @@ static void parse_cipher_bd2(struct wd_queue *q, struct hisi_sec_sqe *sqe,
static void parse_cipher_bd3(struct wd_queue *q, struct hisi_sec_bd3_sqe *sqe,
struct wcrypto_cipher_msg *cipher_msg)
{
+ struct wcrypto_cipher_tag *tag;
__u64 dma_addr;
if (sqe->done != SEC_HW_TASK_DONE || sqe->error_type) {
WD_ERR("Fail to parse SEC BD3 %s, done=0x%x, etype=0x%x\n", "cipher",
(__u32)sqe->done, (__u32)sqe->error_type);
cipher_msg->result = WD_IN_EPARA;
+ } else if (sqe->dc == DIF_VERIFY_FAIL) {
+ cipher_msg->result = WD_VERIFY_ERR;
} else {
cipher_msg->result = WD_SUCCESS;
}
+ /* In user self-define data case, may not need addr map, just return */
+ tag = (void *)(uintptr_t)cipher_msg->usr_data;
+ if (tag && tag->priv)
+ return;
+
dma_addr = DMA_ADDR(sqe->data_src_addr_h, sqe->data_src_addr_l);
drv_iova_unmap(q, cipher_msg->in, (void *)(uintptr_t)dma_addr,
cipher_msg->in_bytes);
@@ -1990,36 +2099,15 @@ int qm_parse_cipher_bd3_sqe(void *msg, const struct qm_queue_info *info,
struct wcrypto_cipher_msg *cipher_msg = info->req_cache[i];
struct hisi_sec_bd3_sqe *sqe3 = msg;
struct wd_queue *q = info->q;
- struct hisi_sec_sqe *sqe;
if (unlikely(!cipher_msg)) {
WD_ERR("info->req_cache is null at index:%hu\n", i);
return 0;
}
+ if (unlikely(usr && sqe3->tag_l != usr))
+ return 0;
- switch (sqe3->type) {
- case BD_TYPE3:
- if (unlikely(usr && sqe3->tag_l != usr))
- return 0;
- parse_cipher_bd3(q, sqe3, cipher_msg);
- break;
- case BD_TYPE2:
- sqe = (struct hisi_sec_sqe *)sqe3;
- if (usr && sqe->type2.tag != usr)
- return 0;
- parse_cipher_bd2(q, sqe, cipher_msg);
- break;
- case BD_TYPE1:
- sqe = (struct hisi_sec_sqe *)sqe3;
- if (usr && sqe->type1.tag != usr)
- return 0;
- parse_cipher_bd1(q, sqe, cipher_msg);
- break;
- default:
- WD_ERR("SEC BD Type error\n");
- cipher_msg->result = WD_IN_EPARA;
- break;
- }
+ parse_cipher_bd3(q, sqe3, cipher_msg);
#ifdef DEBUG_LOG
sec_dump_bd((unsigned char *)msg, SQE_BYTES_NUMS);
@@ -2068,7 +2156,7 @@ static void parse_digest_bd2(struct wd_queue *q, struct hisi_sec_sqe *sqe,
digest_msg->result = WD_SUCCESS;
tag = (void *)(uintptr_t)digest_msg->usr_data;
- if (tag->priv)
+ if (tag && tag->priv)
return;
dma_addr = DMA_ADDR(sqe->type2.data_src_addr_h,
@@ -2674,16 +2762,80 @@ out:
return ret;
}
+static int fill_aead_bd3_udata_addr(struct wcrypto_aead_msg *msg,
+ struct hisi_sec_bd3_sqe *sqe, struct wd_aead_udata *udata)
+{
+ uintptr_t phy;
+
+ sqe->auth_src_offset = udata->src_offset;
+ sqe->cipher_src_offset = udata->src_offset + msg->assoc_bytes;
+
+ phy = (uintptr_t)msg->in;
+ sqe->data_src_addr_l = (__u32)(phy & QM_L32BITS_MASK);
+ sqe->data_src_addr_h = HI_U32(phy);
+ phy = (uintptr_t)msg->out;
+ sqe->data_dst_addr_l = (__u32)(phy & QM_L32BITS_MASK);
+ sqe->data_dst_addr_h = HI_U32(phy);
+ phy = (uintptr_t)msg->iv;
+ sqe->ipsec_scene.c_ivin_addr_l = (__u32)(phy & QM_L32BITS_MASK);
+ sqe->ipsec_scene.c_ivin_addr_h = HI_U32(phy);
+
+ phy = (uintptr_t)udata->ckey;
+ sqe->c_key_addr_l = (__u32)(phy & QM_L32BITS_MASK);
+ sqe->c_key_addr_h = HI_U32(phy);
+ phy = (uintptr_t)udata->mac;
+ sqe->mac_addr_l = (__u32)(phy & QM_L32BITS_MASK);
+ sqe->mac_addr_h = HI_U32(phy);
+ if (msg->cmode == WCRYPTO_CIPHER_CCM || msg->cmode == WCRYPTO_CIPHER_GCM) {
+ if (unlikely(!udata->aiv)) {
+ WD_ERR("invalid aead udata: aiv is NULL!\n");
+ return -WD_EINVAL;
+ }
+ phy = (uintptr_t)udata->aiv;
+ sqe->auth_key_iv.a_ivin_addr_l = (__u32)(phy & QM_L32BITS_MASK);
+ sqe->auth_key_iv.a_ivin_addr_h = HI_U32(phy);
+ }
+
+ return WD_SUCCESS;
+}
+
+static int init_msg_with_udata(struct wcrypto_aead_msg *req, struct wd_aead_udata *udata)
+{
+ if (!udata->ckey || !udata->mac) {
+ WD_ERR("invalid udata para!\n");
+ return -WD_EINVAL;
+ }
+
+ if (req->cmode == WCRYPTO_CIPHER_CCM || req->cmode == WCRYPTO_CIPHER_GCM) {
+ req->ckey_bytes = udata->ckey_bytes;
+ req->auth_bytes = udata->mac_bytes;
+ } else {
+ WD_ERR("invalid cmode para!\n");
+ return -WD_EINVAL;
+ }
+
+ return WD_SUCCESS;
+}
+
static int fill_aead_bd3(struct wd_queue *q, struct hisi_sec_bd3_sqe *sqe,
struct wcrypto_aead_msg *msg, struct wcrypto_aead_tag *tag)
{
+ struct wd_aead_udata *udata = tag ? tag->priv : NULL;
int ret;
+ if (udata) {
+ ret = init_msg_with_udata(msg, udata);
+ if (ret != WD_SUCCESS)
+ return ret;
+ }
+
sqe->type = BD_TYPE3;
sqe->scene = SCENE_IPSEC;
sqe->de = DATA_DST_ADDR_ENABLE;
sqe->c_len = msg->in_bytes;
- sqe->cipher_src_offset = msg->assoc_bytes;
+ sqe->cipher_src_offset = udata ? udata->src_offset + msg->assoc_bytes
+ : msg->assoc_bytes;
+ sqe->auth_src_offset = udata ? udata->src_offset : 0;
sqe->a_len = msg->in_bytes + msg->assoc_bytes;
ret = fill_aead_bd3_alg(msg, sqe);
@@ -2698,15 +2850,21 @@ static int fill_aead_bd3(struct wd_queue *q, struct hisi_sec_bd3_sqe *sqe,
return ret;
}
- ret = fill_aead_bd3_addr(q, msg, sqe);
- if (ret != WD_SUCCESS) {
- WD_ERR("fail to fill_aead_bd3_addr!\n");
- return ret;
- }
+ if (udata) {
+ ret = fill_aead_bd3_udata_addr(msg, sqe, udata);
+ if (unlikely(ret))
+ return ret;
+ } else {
+ ret = fill_aead_bd3_addr(q, msg, sqe);
+ if (ret != WD_SUCCESS) {
+ WD_ERR("fail to fill_aead_bd3_addr!\n");
+ return ret;
+ }
- ret = fill_aead_stream_bd3(q, msg, sqe);
- if (unlikely(ret))
- return ret;
+ ret = fill_aead_stream_bd3(q, msg, sqe);
+ if (unlikely(ret))
+ return ret;
+ }
if (tag)
sqe->tag_l = tag->wcrypto_tag.ctx_id;
@@ -2777,7 +2935,6 @@ int qm_fill_aead_bd3_sqe(void *message, struct qm_queue_info *info, __u16 i)
struct wcrypto_aead_tag *tag = (void *)(uintptr_t)msg->usr_data;
struct wd_queue *q = info->q;
struct hisi_sec_bd3_sqe *sqe;
- struct hisi_sec_sqe *sqe2;
uintptr_t temp;
int ret;
@@ -2789,17 +2946,11 @@ int qm_fill_aead_bd3_sqe(void *message, struct qm_queue_info *info, __u16 i)
}
temp = (uintptr_t)info->sq_base + i * info->sqe_size;
- if (tag->priv) {
- sqe2 = (struct hisi_sec_sqe *)temp;
- memset(sqe2, 0, sizeof(struct hisi_sec_sqe));
- fill_bd_addr_type(msg->data_fmt, sqe2);
- ret = fill_aead_bd_udata(q, sqe2, msg, tag);
- } else {
- sqe = (struct hisi_sec_bd3_sqe *)temp;
- memset(sqe, 0, sizeof(struct hisi_sec_bd3_sqe));
- fill_bd3_addr_type(msg->data_fmt, sqe);
- ret = fill_aead_bd3(q, sqe, msg, tag);
- }
+ sqe = (struct hisi_sec_bd3_sqe *)temp;
+ memset(sqe, 0, sizeof(struct hisi_sec_bd3_sqe));
+ fill_bd3_addr_type(msg->data_fmt, sqe);
+
+ ret = fill_aead_bd3(q, sqe, msg, tag);
if (ret != WD_SUCCESS)
return ret;
@@ -2815,6 +2966,7 @@ int qm_fill_aead_bd3_sqe(void *message, struct qm_queue_info *info, __u16 i)
static void parse_aead_bd3(struct wd_queue *q, struct hisi_sec_bd3_sqe *sqe3,
struct wcrypto_aead_msg *msg)
{
+ struct wcrypto_aead_tag *tag;
__u8 mac[AEAD_IV_MAX_BYTES] = { 0 };
__u64 dma_addr;
int ret;
@@ -2828,6 +2980,11 @@ static void parse_aead_bd3(struct wd_queue *q, struct hisi_sec_bd3_sqe *sqe3,
msg->result = WD_SUCCESS;
}
+ /* In user self-define data case, may not need addr map, just return */
+ tag = (void *)(uintptr_t)msg->usr_data;
+ if (tag && tag->priv)
+ return;
+
/*
* We obtain a memory from IV SGL as a temporary address space for MAC,
* After the encryption is completed, copy the data from this temporary
@@ -2883,26 +3040,16 @@ int qm_parse_aead_bd3_sqe(void *msg, const struct qm_queue_info *info,
{
struct wcrypto_aead_msg *aead_msg = info->req_cache[i];
struct hisi_sec_bd3_sqe *sqe = msg;
- struct hisi_sec_sqe *sqe2 = msg;
struct wd_queue *q = info->q;
if (unlikely(!aead_msg)) {
WD_ERR("info->req_cache is null at index:%hu\n", i);
return 0;
}
+ if (unlikely(usr && sqe->tag_l != usr))
+ return 0;
- if (sqe->type == BD_TYPE3) {
- if (usr && sqe->tag_l != usr)
- return 0;
- parse_aead_bd3(q, sqe, aead_msg);
- } else if (sqe->type == BD_TYPE2) {
- if (usr && sqe2->type2.tag != usr)
- return 0;
- parse_aead_bd2(q, sqe2, aead_msg);
- } else {
- WD_ERR("SEC BD Type error\n");
- aead_msg->result = WD_IN_EPARA;
- }
+ parse_aead_bd3(q, sqe, aead_msg);
#ifdef DEBUG_LOG
sec_dump_bd((unsigned char *)msg, SQE_BYTES_NUMS);
@@ -2914,16 +3061,24 @@ int qm_parse_aead_bd3_sqe(void *msg, const struct qm_queue_info *info,
static void parse_digest_bd3(struct wd_queue *q, struct hisi_sec_bd3_sqe *sqe,
struct wcrypto_digest_msg *digest_msg)
{
+ struct wcrypto_digest_tag *tag;
__u64 dma_addr;
if (sqe->done != SEC_HW_TASK_DONE || sqe->error_type) {
WD_ERR("SEC BD3 %s fail!done=0x%x, etype=0x%x\n", "digest",
(__u32)sqe->done, (__u32)sqe->error_type);
digest_msg->result = WD_IN_EPARA;
+ } else if (sqe->dc == DIF_VERIFY_FAIL) {
+ digest_msg->result = WD_VERIFY_ERR;
} else {
digest_msg->result = WD_SUCCESS;
}
+ /* In user self-define data case, may not need addr map, just return */
+ tag = (void *)(uintptr_t)digest_msg->usr_data;
+ if (tag && tag->priv)
+ return;
+
dma_addr = DMA_ADDR(sqe->data_src_addr_h, sqe->data_src_addr_l);
drv_iova_unmap(q, digest_msg->in, (void *)(uintptr_t)dma_addr,
digest_msg->in_bytes);
@@ -2946,30 +3101,16 @@ int qm_parse_digest_bd3_sqe(void *msg, const struct qm_queue_info *info,
{
struct wcrypto_digest_msg *digest_msg = info->req_cache[i];
struct hisi_sec_bd3_sqe *sqe = msg;
- struct hisi_sec_sqe *sqe2 = msg;
struct wd_queue *q = info->q;
if (unlikely(!digest_msg)) {
WD_ERR("info->req_cache is null at index:%hu\n", i);
return 0;
}
+ if (unlikely(usr && sqe->tag_l != usr))
+ return 0;
- if (sqe->type == BD_TYPE3) {
- if (usr && sqe->tag_l != usr)
- return 0;
- parse_digest_bd3(q, sqe, digest_msg);
- } else if (sqe->type == BD_TYPE2) {
- if (usr && sqe2->type2.tag != usr)
- return 0;
- parse_digest_bd2(q, sqe2, digest_msg);
- } else if (sqe->type == BD_TYPE1) {
- if (usr && sqe2->type1.tag != usr)
- return 0;
- parse_digest_bd1(q, sqe2, digest_msg);
- } else {
- WD_ERR("SEC Digest BD Type error\n");
- digest_msg->result = WD_IN_EPARA;
- }
+ parse_digest_bd3(q, sqe, digest_msg);
#ifdef DEBUG_LOG
sec_dump_bd((unsigned char *)msg, SQE_BYTES_NUMS);
@@ -3332,24 +3473,6 @@ static int fill_aead_bd2(struct wd_queue *q, struct hisi_sec_sqe *sqe,
return fill_aead_bd2_addr(q, msg, sqe);
}
-static int init_msg_with_udata(struct wcrypto_aead_msg *req, struct wd_aead_udata *udata)
-{
- if (!udata->ckey || !udata->mac) {
- WD_ERR("invalid udata para!\n");
- return -WD_EINVAL;
- }
-
- if (req->cmode == WCRYPTO_CIPHER_CCM || req->cmode == WCRYPTO_CIPHER_GCM) {
- req->ckey_bytes = udata->ckey_bytes;
- req->auth_bytes = udata->mac_bytes;
- } else {
- WD_ERR("invalid cmode para!\n");
- return -WD_EINVAL;
- }
-
- return WD_SUCCESS;
-}
-
static int fill_aead_bd2_udata(struct wd_queue *q, struct hisi_sec_sqe *sqe,
struct wcrypto_aead_msg *msg, struct wcrypto_aead_tag *tag)
{
@@ -3433,7 +3556,7 @@ static void parse_aead_bd2(struct wd_queue *q, struct hisi_sec_sqe *sqe,
}
tag = (void *)(uintptr_t)msg->usr_data;
- if (tag->priv)
+ if (tag && tag->priv)
return;
/*
--
2.28.0.windows.1
1
0
[PATCH 1/4] uadk: fix scheduler ctx allocation and sched_params initialization
by Chenghai Huang 20 Sep '26
by Chenghai Huang 20 Sep '26
20 Sep '26
The scheduler ctx allocation under SCHED_POLICY_DEV and session
initialization in several modules contain bugs that cause async process
hangs, device starvation, and nondeterministic scheduling behavior.
The following four issues are addressed:
Under SCHED_POLICY_DEV, allocating sync ctxs then async ctxs in two
passes let concurrent contention split them across devices. The DEV
scheduler pins the region to ctxs[0]'s device and forbids cross-region
fallback, so the async domain ended empty: async picks returned idx
65535, sends failed with -22, and the async process hung. Add a DEV-only
path that opens sync/async ctxs interleaved on ONE device, with a
preferred_dev_path field to pin later ctxs of the group. Then simplify
it to a linear two-pass per device: open all sync then all async; any
shortfall rolls back the whole group and tries the next device.
wd_hw_alloc_ctx picked the first device whose wd_request_ctx() succeeded.
When PF and VFs share the same NUMA node, concurrent businesses all bind
to the same leading device, starving the others. Select the device with
the most available contexts (wd_get_avail_ctx) instead, with fallback to
remaining devices if the chosen one fails to open.
wd_agg_alloc_sess, wd_join_gather_alloc_sess and wd_udma_alloc_sess
declared a local struct wd_sched_params without initialization, setting
only alg_name and ctxs before passing it to wd_sched_set_param, which
unconditionally reads pkt_size, data_mode and prio_mode. The
uninitialized stack values caused nondeterministic scheduling behavior.
Initialize the struct with = {0} at declaration.
Signed-off-by: Chenghai Huang <huangchenghai2(a)huawei.com>
Co-developed-by: Wenkai Lin <linwenkai6(a)hisilicon.com>
Signed-off-by: Wenkai Lin <linwenkai6(a)hisilicon.com>
Co-developed-by: Weili Qian <qianweili(a)huawei.com>
Signed-off-by: Weili Qian <qianweili(a)huawei.com>
---
drv/wd_drv.c | 67 ++++++++++--
include/wd_alg.h | 3 +
wd_agg.c | 2 +-
wd_join_gather.c | 2 +-
wd_udma.c | 2 +-
wd_util.c | 279 ++++++++++++++++++++++++++++++++++++++---------
6 files changed, 291 insertions(+), 64 deletions(-)
diff --git a/drv/wd_drv.c b/drv/wd_drv.c
index 381cee1..08014dd 100644
--- a/drv/wd_drv.c
+++ b/drv/wd_drv.c
@@ -181,12 +181,12 @@ int wd_hw_alloc_ctx(char *alg_name, void *params, handle_t *ctx)
{
struct wd_drv_ctx_params *ctx_params = (struct wd_drv_ctx_params *)params;
struct uacce_dev_list *dev_list, *used_list = NULL;
+ struct uacce_dev_list *curr, *best = NULL;
char alg_type[CRYPTO_MAX_ALG_NAME];
- struct uacce_dev_list *curr;
+ int target_numa, best_avail = 0;
struct wd_ctx_h *ctx_h;
- int target_numa;
+ int ret, avail;
handle_t hctx;
- int ret;
if (!params || !ctx) {
WD_ERR("invalid: parameters are NULL!\n");
@@ -220,14 +220,61 @@ int wd_hw_alloc_ctx(char *alg_name, void *params, handle_t *ctx)
goto out;
}
- curr = used_list;
- while (curr) {
- if (curr->dev) {
- hctx = wd_request_ctx(curr->dev);
- if (hctx)
- goto success;
+ /*
+ * Preferred-device binding (SCHED_POLICY_DEV): open exactly this device
+ * and fail strictly if unavailable, so the sync and async ctxs of one
+ * (driver, op_type, numa) stay on the same device. No NUMA fallback.
+ */
+ if (ctx_params->preferred_dev_path) {
+ for (curr = used_list; curr; curr = curr->next) {
+ if (curr->dev && !strcmp(curr->dev->char_dev_path,
+ ctx_params->preferred_dev_path))
+ break;
}
- curr = curr->next;
+
+ if (!curr) {
+ ret = -WD_ENODEV;
+ goto out;
+ }
+
+ hctx = wd_request_ctx(curr->dev);
+ if (!hctx) {
+ ret = -WD_EBUSY;
+ goto out;
+ }
+
+ goto success;
+ }
+
+ /* Pick the device with the most available contexts to balance load. */
+ for (curr = used_list; curr; curr = curr->next) {
+ if (!curr->dev)
+ continue;
+ avail = wd_get_avail_ctx(curr->dev);
+ if (avail > best_avail) {
+ best_avail = avail;
+ best = curr;
+ }
+ }
+
+ if (!best) {
+ WD_ERR("failed to request ctx on NUMA node %d for %s\n",
+ target_numa, alg_name);
+ ret = -WD_EBUSY;
+ goto out;
+ }
+
+ hctx = wd_request_ctx(best->dev);
+ if (hctx)
+ goto success;
+
+ /* Fall back to remaining devices if the best one fails to open */
+ for (curr = used_list; curr; curr = curr->next) {
+ if (curr == best || !curr->dev)
+ continue;
+ hctx = wd_request_ctx(curr->dev);
+ if (hctx)
+ goto success;
}
WD_ERR("failed to request ctx on NUMA node %d for %s\n",
diff --git a/include/wd_alg.h b/include/wd_alg.h
index b256a2f..3cc4e43 100644
--- a/include/wd_alg.h
+++ b/include/wd_alg.h
@@ -96,6 +96,8 @@ enum alg_drv_type {
* @ctx_mode: CTX_MODE_SYNC or CTX_MODE_ASYNC
* @op_type: Operation type
* @bmp: NUMA node bitmask (optional, NULL if not needed)
+ * @preferred_dev_path: Preferred device char_dev_path; NULL/empty = auto-select,
+ * non-empty = open only this device and fail strictly if unavailable
*/
struct wd_drv_ctx_params {
__u8 ctx_mode;
@@ -103,6 +105,7 @@ struct wd_drv_ctx_params {
int numa_id;
bool epoll_en;
struct bitmask *bmp;
+ const char *preferred_dev_path;
};
/**
diff --git a/wd_agg.c b/wd_agg.c
index 95cb869..2c7825d 100644
--- a/wd_agg.c
+++ b/wd_agg.c
@@ -446,7 +446,7 @@ static int wd_agg_uninit_sess_priv(struct wd_agg_sess *sess)
handle_t wd_agg_alloc_sess(struct wd_agg_sess_setup *setup)
{
- struct wd_sched_params params;
+ struct wd_sched_params params = {0};
struct wd_agg_sess *sess;
__u32 out_agg_cols_num = 0;
int ret;
diff --git a/wd_join_gather.c b/wd_join_gather.c
index e43dbf9..27472d3 100644
--- a/wd_join_gather.c
+++ b/wd_join_gather.c
@@ -533,7 +533,7 @@ static int wd_join_gather_init_sess(struct wd_join_gather_sess *sess,
handle_t wd_join_gather_alloc_sess(struct wd_join_gather_sess_setup *setup)
{
- struct wd_sched_params params;
+ struct wd_sched_params params = {0};
struct wd_join_gather_sess *sess;
int ret;
diff --git a/wd_udma.c b/wd_udma.c
index 582c8d1..59841bb 100644
--- a/wd_udma.c
+++ b/wd_udma.c
@@ -78,7 +78,7 @@ void wd_udma_free_sess(handle_t sess)
handle_t wd_udma_alloc_sess(struct wd_udma_sess_setup *setup)
{
- struct wd_sched_params params;
+ struct wd_sched_params params = {0};
struct wd_udma_sess *sess;
int ret;
diff --git a/wd_util.c b/wd_util.c
index 1b4c74e..0d482f9 100644
--- a/wd_util.c
+++ b/wd_util.c
@@ -2613,17 +2613,17 @@ static int wd_alg_sched_instance(struct wd_sched *sched,
return WD_SUCCESS;
}
-static void wd_free_ctxs_batch(struct wd_init_attrs *attrs,
- __u32 allocated_count)
+static void wd_free_ctxs_batch_range(struct wd_init_attrs *attrs,
+ __u32 start_idx, __u32 end_idx)
{
struct wd_ctx_config_internal *internal_config = attrs->ctx_config_internal;
struct wd_alg_driver *drv;
__u32 i;
- if (!internal_config || !internal_config->ctxs || !allocated_count)
+ if (!internal_config || !internal_config->ctxs || start_idx >= end_idx)
return;
- for (i = 0; i < allocated_count; i++) {
+ for (i = start_idx; i < end_idx; i++) {
if (!internal_config->ctxs[i].ctx)
continue;
@@ -2635,21 +2635,76 @@ static void wd_free_ctxs_batch(struct wd_init_attrs *attrs,
}
}
+static void wd_free_ctxs_batch(struct wd_init_attrs *attrs,
+ __u32 allocated_count)
+{
+ wd_free_ctxs_batch_range(attrs, 0, allocated_count);
+}
+
+static void wd_collect_numa_nodes(struct bitmask *bmp, int *numa_nodes,
+ __u8 *numa_count)
+{
+ int max_node, n;
+
+ max_node = numa_max_node() + 1;
+ if (max_node <= 0 || max_node > UADK_MAX_NUMA_NODES)
+ max_node = UADK_MAX_NUMA_NODES;
+
+ *numa_count = 0;
+
+ for (n = 0; n < max_node; n++) {
+ if (numa_bitmask_isbitset(bmp, n))
+ numa_nodes[(*numa_count)++] = n;
+ }
+
+ if (!*numa_count) {
+ numa_nodes[0] = 0;
+ *numa_count = 1;
+ }
+}
+
+static int wd_alloc_one_ctx(struct wd_init_attrs *attrs,
+ struct wd_alg_driver *drv,
+ struct wd_drv_ctx_params *dparams,
+ __u32 *ctx_idx)
+{
+ struct wd_ctx_config_internal *internal_config = attrs->ctx_config_internal;
+ handle_t ctx;
+ int ret;
+
+ ret = drv->alloc_ctx(attrs->alg, dparams, &ctx);
+ if (ret < 0)
+ return ret;
+
+ if (!ctx)
+ return -WD_EINVAL;
+
+ internal_config->ctxs[*ctx_idx].ctx = ctx;
+ internal_config->ctxs[*ctx_idx].op_type = dparams->op_type;
+ internal_config->ctxs[*ctx_idx].ctx_mode = dparams->ctx_mode;
+ internal_config->ctxs[*ctx_idx].ctx_type = drv->calc_type;
+ internal_config->ctxs[*ctx_idx].drv = drv;
+ (*ctx_idx)++;
+ return WD_SUCCESS;
+}
+
static int wd_alloc_single_drv_ctxs(struct wd_init_attrs *attrs,
struct wd_alg_driver *drv,
__u8 ctx_mode, __u8 op_type,
__u32 *ctx_idx)
{
- struct wd_ctx_config_internal *internal_config = attrs->ctx_config_internal;
struct wd_ctx_params *ctx_params = attrs->ctx_params;
- struct wd_drv_ctx_params dparams;
+ struct wd_drv_ctx_params dparams = {0};
int numa_nodes[UADK_MAX_NUMA_NODES];
- __u32 mode_ctx_num, numa_count = 0;
- __u32 numa_idx, j;
- int max_node, n;
- handle_t ctx;
+ __u32 mode_ctx_num, numa_idx, j;
+ __u8 numa_count;
int ret;
+ dparams.ctx_mode = ctx_mode;
+ dparams.op_type = op_type;
+ dparams.bmp = ctx_params->bmp;
+ dparams.epoll_en = false;
+
if (ctx_mode == CTX_MODE_SYNC)
mode_ctx_num = ctx_params->ctx_set_num[op_type].sync_ctx_num;
else
@@ -2661,46 +2716,26 @@ static int wd_alloc_single_drv_ctxs(struct wd_init_attrs *attrs,
attrs->sched_type == SCHED_POLICY_SINGLE) && mode_ctx_num > 1)
mode_ctx_num = 1;
- if (drv->calc_type == UADK_ALG_HW) {
- max_node = numa_max_node() + 1;
- if (max_node <= 0 || max_node > UADK_MAX_NUMA_NODES)
- max_node = UADK_MAX_NUMA_NODES;
- for (n = 0; n < max_node; n++) {
- if (numa_bitmask_isbitset(ctx_params->bmp, n))
- numa_nodes[numa_count++] = n;
- }
- } else {
- numa_nodes[0] = 0;
- numa_count = 1;
- }
- if (!numa_count) {
+ if (drv->calc_type != UADK_ALG_HW) {
numa_nodes[0] = 0;
numa_count = 1;
+ } else {
+ wd_collect_numa_nodes(ctx_params->bmp, numa_nodes, &numa_count);
}
for (numa_idx = 0; numa_idx < numa_count; numa_idx++) {
+ dparams.numa_id = numa_nodes[numa_idx];
+
for (j = 0; j < mode_ctx_num; j++) {
- memset(&dparams, 0, sizeof(dparams));
- dparams.ctx_mode = ctx_mode;
- dparams.op_type = op_type;
- dparams.numa_id = numa_nodes[numa_idx];
- dparams.bmp = ctx_params->bmp;
- dparams.epoll_en = false;
- ret = drv->alloc_ctx(attrs->alg, &dparams, &ctx);
- if (!ctx || ret < 0) {
- if (ret == -WD_ENODEV)
- break;
+ ret = wd_alloc_one_ctx(attrs, drv, &dparams, ctx_idx);
+ if (ret == -WD_ENODEV)
+ break;
+
+ if (ret) {
WD_ERR("failed to alloc ctx %u from driver %s on numa %d!\n",
*ctx_idx, drv->drv_name, numa_nodes[numa_idx]);
return ret;
}
-
- internal_config->ctxs[*ctx_idx].ctx = ctx;
- internal_config->ctxs[*ctx_idx].op_type = dparams.op_type;
- internal_config->ctxs[*ctx_idx].ctx_mode = dparams.ctx_mode;
- internal_config->ctxs[*ctx_idx].ctx_type = drv->calc_type;
- internal_config->ctxs[*ctx_idx].drv = drv;
- (*ctx_idx)++;
}
}
@@ -2749,6 +2784,142 @@ err_ctxs:
return ret;
}
+/*
+ * SCHED_POLICY_DEV: open all sync ctxs then all async ctxs of
+ * (drv, op_type, numa) on ONE device pinned by dparams->preferred_dev_path.
+ * If the device cannot hold the whole group, roll back every ctx opened on
+ * it and return -WD_ENODEV so the caller tries the next device.
+ */
+static int wd_alloc_dev_group(struct wd_init_attrs *attrs,
+ struct wd_alg_driver *drv,
+ struct wd_drv_ctx_params *dparams,
+ __u32 *ctx_idx)
+{
+ struct wd_ctx_nums *nums = &attrs->ctx_params->ctx_set_num[dparams->op_type];
+ __u32 want[2] = {nums->sync_ctx_num, nums->async_ctx_num};
+ __u8 modes[2] = {CTX_MODE_SYNC, CTX_MODE_ASYNC};
+ __u32 group_start = *ctx_idx;
+ __u32 i, j;
+ int ret;
+
+ for (i = 0; i < 2; i++) {
+ dparams->ctx_mode = modes[i];
+ for (j = 0; j < want[i]; j++) {
+ ret = wd_alloc_one_ctx(attrs, drv, dparams, ctx_idx);
+ if (ret) {
+ wd_free_ctxs_batch_range(attrs, group_start, *ctx_idx);
+ *ctx_idx = group_start;
+ if (ret != -WD_EBUSY && ret != -WD_ENODEV)
+ return ret;
+ return -WD_ENODEV;
+ }
+ }
+ }
+ return WD_SUCCESS;
+}
+
+/*
+ * SCHED_POLICY_DEV: per (drv, op_type, numa) open all sync+async ctxs on one
+ * device. Enumerates devices on each numa node and pins each group to one
+ * device via preferred_dev_path, trying the next device if the current one
+ * cannot hold the whole group. All devices exhausted => error out.
+ */
+static int wd_alloc_ctxs_batch_dev(struct wd_init_attrs *attrs, __u32 *start_idx)
+{
+ struct wd_ctx_config_internal *internal_config = attrs->ctx_config_internal;
+ struct wd_ctx_params *ctx_params = attrs->ctx_params;
+ __u32 ctx_idx, drv_idx, start, group_start;
+ struct uacce_dev_list *dev_list = NULL;
+ int numa_nodes[UADK_MAX_NUMA_NODES];
+ char alg_type[CRYPTO_MAX_ALG_NAME];
+ struct wd_drv_ctx_params dparams;
+ struct wd_alg_driver *drv;
+ __u8 op_type, numa_count;
+ struct wd_ctx_nums *nums;
+ struct uacce_dev_list *p;
+ int n, ret;
+
+ memset(&dparams, 0, sizeof(dparams));
+ dparams.bmp = ctx_params->bmp;
+ dparams.epoll_en = false;
+
+ start = *start_idx;
+ ctx_idx = start;
+ for (drv_idx = 0; drv_idx < internal_config->drv_count; drv_idx++) {
+ drv = internal_config->drv_array[drv_idx];
+ if (!drv || !drv->alloc_ctx) {
+ WD_ERR("failed to check driver %s alloc_ctx!\n",
+ drv ? drv->drv_name : "unknown");
+ ret = -WD_EINVAL;
+ goto err_ctxs;
+ }
+ if (drv->calc_type != UADK_ALG_HW)
+ continue;
+
+ ret = wd_get_alg_type(attrs->alg, alg_type);
+ if (ret) {
+ ret = -WD_EINVAL;
+ goto err_ctxs;
+ }
+ if (!strcmp(alg_type, "ecc"))
+ (void)strcpy(alg_type, "sm2");
+ if (!strcmp(alg_type, "comp"))
+ (void)strcpy(alg_type, "zlib");
+
+ dev_list = wd_get_accel_list(alg_type);
+ if (!dev_list)
+ continue;
+
+ wd_collect_numa_nodes(ctx_params->bmp, numa_nodes, &numa_count);
+
+ for (op_type = 0; op_type < ctx_params->op_type_num; op_type++) {
+ nums = &ctx_params->ctx_set_num[op_type];
+ if (!nums->sync_ctx_num && !nums->async_ctx_num)
+ continue;
+
+ dparams.op_type = op_type;
+ group_start = ctx_idx;
+ for (n = 0; n < numa_count; n++) {
+ dparams.numa_id = numa_nodes[n];
+ for (p = dev_list; p; p = p->next) {
+ if (!p->dev || p->dev->numa_id != numa_nodes[n])
+ continue;
+
+ /* Skip devices that cannot hold the whole group */
+ if (wd_get_avail_ctx(p->dev) < (int)(nums->sync_ctx_num +
+ nums->async_ctx_num))
+ continue;
+
+ dparams.preferred_dev_path = p->dev->char_dev_path;
+ ret = wd_alloc_dev_group(attrs, drv,
+ &dparams,
+ &ctx_idx);
+ if (!ret)
+ break;
+ if (ret != -WD_ENODEV)
+ goto err_ctxs;
+ }
+ }
+
+ if (ctx_idx == group_start) {
+ ret = -WD_ENODEV;
+ goto err_ctxs;
+ }
+ }
+ wd_free_list_accels(dev_list);
+ dev_list = NULL;
+ }
+
+ *start_idx = ctx_idx;
+ return ctx_idx == start ? -WD_ENODEV : WD_SUCCESS;
+
+err_ctxs:
+ if (dev_list)
+ wd_free_list_accels(dev_list);
+ wd_free_ctxs_batch(attrs, ctx_idx);
+ return ret;
+}
+
/**
* wd_alg_ctx_uninit() - Release ctxs, scheduler, ctx_config.
*
@@ -2880,18 +3051,24 @@ int wd_alg_ctx_init(struct wd_init_attrs *attrs)
return -WD_EINVAL;
}
- /*
- * Ensure that contexts (ctx) with the same attributes are allocated first,
- * thereby maintaining queue continuity within the contexts.
- */
- ret = wd_alloc_ctxs_batch(attrs, CTX_MODE_SYNC, &ctx_idx);
- if (ret)
- return -WD_EINVAL;
+ if (attrs->sched_type == SCHED_POLICY_DEV) {
+ ret = wd_alloc_ctxs_batch_dev(attrs, &ctx_idx);
+ /* DEV tolerates partial: only a truly empty result fails. */
+ if (ret == -WD_ENODEV)
+ return -WD_EINVAL;
- /* wd_alloc_ctxs_batch already cleaned up via its internal err_ctxs. */
- ret = wd_alloc_ctxs_batch(attrs, CTX_MODE_ASYNC, &ctx_idx);
- if (ret)
- return -WD_EINVAL;
+ if (ret)
+ return ret;
+ } else {
+ ret = wd_alloc_ctxs_batch(attrs, CTX_MODE_SYNC, &ctx_idx);
+ if (ret)
+ return -WD_EINVAL;
+
+ /* wd_alloc_ctxs_batch already cleaned up via its internal err_ctxs. */
+ ret = wd_alloc_ctxs_batch(attrs, CTX_MODE_ASYNC, &ctx_idx);
+ if (ret)
+ return -WD_EINVAL;
+ }
/* Backfill actual allocated count */
internal_config = attrs->ctx_config_internal;
--
2.28.0.windows.1
1
3
Fix several minor issues.
Weili Qian (6):
uadk_engine: fix double-free in AEAD and async init
uadk_engine: use secure BN allocation for signing nonce
uadk_engine: fix uninit read in ECDH derive
uadk_engine: fix memory leaks in error paths
uadk_engine: fix EC key management cleanup and secure allocation
uadk_engine: refactor RSA set0 functions and fix keygen BN allocation
Zhushuai Yin (3):
uadk_provider: fix one-shot cipher padding and stream-mode handling
uadk_provider: fix stream mode ciphertext error on non-aligned
multi-update
uadk_engine: fix stream mode ciphertext error on non-aligned
multi-update
src/uadk_aead.c | 4 +-
src/uadk_async.c | 7 +-
src/uadk_cipher.c | 74 ++++++++++++-----
src/uadk_digest.c | 11 ++-
src/uadk_ec.c | 9 +++
src/uadk_pkey.c | 4 +-
src/uadk_prov_aead.c | 3 +-
src/uadk_prov_cipher.c | 165 ++++++++++++++++++++++++++++++--------
src/uadk_prov_ec_kmgmt.c | 4 +-
src/uadk_prov_ecdh_exch.c | 2 +-
src/uadk_prov_ecx.c | 25 +++---
src/uadk_prov_pkey.c | 4 +-
src/uadk_prov_rsa_kmgmt.c | 128 +++++++++--------------------
src/uadk_prov_rsa_sign.c | 9 ++-
src/uadk_rsa.c | 92 +++++++++++----------
15 files changed, 314 insertions(+), 227 deletions(-)
--
2.43.0
1
9
[PATCH 00/13] uadk_engine/uadk_provider: bug fixes and AEAD GCM enhancements
by Weili Qian 04 Sep '26
by Weili Qian 04 Sep '26
04 Sep '26
From: qianweili <qianweili(a)huawei.com>
This series fixes several bugs in the UADK engine and provider, and
adds non-block-aligned data handling and TLS 1.x GCM record offload to
the provider AES-GCM path.
Engine fixes:
- Correct error log format and a misleading async macro name (01)
- Balance the async recv loop count (02)
- Fix wrong return values and missing NULL checks in error paths (03)
- Securely release DH/ECDH/SM2 private keys and fix an SM2 order
leak (04)
- Fall back to software when digest/cipher session allocation fails
(05)
- Copy md_nid and md_update_status in SM2 ctx copy (06)
Provider fixes:
- Fix wrong parameter order in wd_xxx_init2_ calls (07)
- Split session/key management into the init stage to avoid
per-operation alloc/free overhead (08)
- Handle non-block-aligned GCM data via an AES-CTR tail soft path (09)
- Add TLS 1.x GCM record offload and an IV state machine (10)
- Widen the IV buffer and fall back to software for non-default IV
lengths (11)
- Fix session allocation failure handling in multiple threads (12)
- Fix a double-free in digest cleanup under multiple threads (13)
Weili Qian (9):
uadk_engine: fix error log format coding style and misleading async
macro name
uadk_engine: fix return value checks in error paths
uadk_engine: securely release DH/ECDH/SM2 private key and fix SM2
order leak
uadk_engine: copy md_nid and md_update_status in SM2 ctx copy
uadk_provider: fix wrong parameter order in wd_xxx_init2_ call
uadk_provider: split session/key management into init stage
uadk_provider: handle non-block-aligned data via AES-CTR tail soft
path
uadk_provider: add TLS 1.x GCM record offload and IV state machine
uadk_provider: widen IV buffer and fall back to software for
non-default IV lengths
Wenkai Lin (2):
uadk_engine: fall back to software when digest/cipher session alloc
fails
uadk_provider: fix the double free problem in multiple threads
Zhushuai Yin (1):
uadk_provider: fix the error of allocating sessions in multiple
threads
lizhi (1):
uadk_engine: adjust async recv loop count to balance async mode
behavior
src/uadk.h | 2 +-
src/uadk_cipher.c | 3 +-
src/uadk_dh.c | 8 +-
src/uadk_digest.c | 40 +-
src/uadk_ec.c | 52 +-
src/uadk_ecx.c | 4 +-
src/uadk_prov.h | 2 +-
src/uadk_prov_aead.c | 1337 +++++++++++++++++++++++++------------
src/uadk_prov_cipher.c | 2 +-
src/uadk_prov_dh.c | 6 +-
src/uadk_prov_digest.c | 97 ++-
src/uadk_prov_ecdh_exch.c | 23 +-
src/uadk_prov_ecx.c | 10 +-
src/uadk_prov_hmac.c | 4 +-
src/uadk_prov_pkey.c | 8 +-
src/uadk_prov_rsa_enc.c | 2 +-
src/uadk_prov_sm2_enc.c | 2 +-
src/uadk_prov_sm2_kmgmt.c | 11 +-
src/uadk_prov_sm2_sign.c | 4 +-
src/uadk_sm2.c | 18 +-
20 files changed, 1135 insertions(+), 500 deletions(-)
--
2.53.0.windows.2
1
13
02 Sep '26
From: Junchong Pan <panjunchong(a)h-partners.com>
Initialize ret to 0 in wd_ctx_param_init() to fix -Wmaybe-uninitialized
warning. Change ret type from int to size_t in get_str_attr() to fix
-Wsign-compare warning. Move sched_uninit and set_param to the end of
struct wd_sched to maintain ABI compatibility.
Signed-off-by: Junchong Pan <panjunchong(a)h-partners.com>
---
include/wd_alg_common.h | 4 ++--
wd.c | 2 +-
wd_util.c | 5 +++--
3 files changed, 6 insertions(+), 5 deletions(-)
diff --git a/include/wd_alg_common.h b/include/wd_alg_common.h
index 05cc5c0..f0e13bb 100644
--- a/include/wd_alg_common.h
+++ b/include/wd_alg_common.h
@@ -165,13 +165,13 @@ struct wd_sched {
const char *name;
int sched_policy;
handle_t (*sched_init)(handle_t h_sched_ctx, void *sched_param);
- void (*sched_uninit)(handle_t h_sched_ctx, handle_t h_sched_key);
__u32 (*pick_next_ctx)(handle_t h_sched_ctx,
void *sched_key,
const int sched_mode);
int (*poll_policy)(handle_t h_sched_ctx, __u32 expect, __u32 *count);
- void (*set_param)(handle_t h_sched_ctx, void *sched_key, void *sched_param);
handle_t h_sched_ctx;
+ void (*sched_uninit)(handle_t h_sched_ctx, handle_t h_sched_key);
+ void (*set_param)(handle_t h_sched_ctx, void *sched_key, void *sched_param);
};
typedef int (*wd_alg_init)(struct wd_ctx_config *config, struct wd_sched *sched);
diff --git a/wd.c b/wd.c
index f973c70..1c28bb3 100644
--- a/wd.c
+++ b/wd.c
@@ -203,7 +203,7 @@ static int get_int_attr(struct uacce_dev *dev, const char *attr, int *val)
static int get_str_attr(struct uacce_dev *dev, const char *attr, char *buf,
size_t buf_sz)
{
- int ret;
+ size_t ret;
int size;
size = get_raw_attr(dev->dev_root, attr, buf, buf_sz);
diff --git a/wd_util.c b/wd_util.c
index 1b4c74e..bf6d380 100644
--- a/wd_util.c
+++ b/wd_util.c
@@ -1765,7 +1765,7 @@ static int wd_env_set_ctx_nums(const char *alg_name, const char *name, const cha
{
char *left, *section, *start;
int is_comp;
- int ret;
+ int ret = 0;
/* COMP environment variable's format is different, mark it */
is_comp = strncmp(name, "WD_COMP_CTX_NUM", sizeof("WD_COMP_CTX_NUM") - 1) ? 0 : 1;
@@ -1799,7 +1799,8 @@ int wd_ctx_param_init(struct wd_ctx_params *ctx_params,
{
const char *env_name = wd_env_name[type];
const char *var_s;
- int i, ret;
+ int ret = 0;
+ int i;
ctx_params->bmp = numa_allocate_nodemask();
if (!ctx_params->bmp) {
--
2.43.0
1
0