From: lizhi <lizhi206@huawei.com> 1. Add max timeout control and adaptive backoff to prevent long usleep delays on device failure 2. Implement exponential backoff to reduce context switching overhead under high load. Signed-off-by: lizhi <lizhi206@huawei.com> --- v1/wd_dh.c | 12 +++++++----- v1/wd_ecc.c | 12 +++++++----- v1/wd_rsa.c | 14 ++++++++------ v1/wd_util.c | 31 +++++++++++++++++++++++++++++++ v1/wd_util.h | 2 ++ 5 files changed, 55 insertions(+), 16 deletions(-) diff --git a/v1/wd_dh.c b/v1/wd_dh.c index 12f7b19..e8ecf5d 100644 --- a/v1/wd_dh.c +++ b/v1/wd_dh.c @@ -363,6 +363,8 @@ int wcrypto_do_dh(void *ctx, struct wcrypto_dh_op_data *opdata, void *tag) struct wcrypto_dh_cookie *cookie; struct wcrypto_dh_msg *req; uint32_t rx_cnt = 0; + __u64 slept = 0; + bool is_timeout; int ret; ret = do_dh_prepare(opdata, &cookie, ctxt, &req, tag); @@ -383,14 +385,14 @@ int wcrypto_do_dh(void *ctx, struct wcrypto_dh_op_data *opdata, void *tag) if (ret > 0) { break; } else if (!ret) { - if (unlikely(rx_cnt++ >= DH_RECV_MAX_CNT)) { - WD_ERR("failed to receive: timeout!\n"); + is_timeout = wd_adaptive_backoff_sleep(balance, DH_BALANCE_THRHD, + rx_cnt, &slept); + if (unlikely(rx_cnt++ >= DH_RECV_MAX_CNT || is_timeout)) { + WD_ERR("dh recv timeout: rx_cnt = %u, slept = %llu us\n", + rx_cnt, slept); ret = -WD_ETIMEDOUT; goto fail_with_cookie; } - - if (balance > DH_BALANCE_THRHD) - usleep(1); } else { WD_ERR("do dh wd_recv err!\n"); goto fail_with_cookie; diff --git a/v1/wd_ecc.c b/v1/wd_ecc.c index bb65dfb..aec13e8 100644 --- a/v1/wd_ecc.c +++ b/v1/wd_ecc.c @@ -1558,6 +1558,8 @@ static int ecc_sync_recv(struct wcrypto_ecc_ctx *ctx, { struct wcrypto_ecc_msg *resp; __u32 rx_cnt = 0; + __u64 slept = 0; + bool is_timeout; int ret; resp = (void *)(uintptr_t)ctx->ctx_id; @@ -1567,13 +1569,13 @@ static int ecc_sync_recv(struct wcrypto_ecc_ctx *ctx, if (ret > 0) { break; } else if (!ret) { - if (rx_cnt++ >= ECC_RECV_MAX_CNT) { - WD_ERR("failed to recv: timeout!\n"); + is_timeout = wd_adaptive_backoff_sleep(balance, ECC_BALANCE_THRHD, + rx_cnt, &slept); + if (unlikely(rx_cnt++ >= ECC_RECV_MAX_CNT || is_timeout)) { + WD_ERR("ecc recv timeout: rx_cnt = %u, slept = %llu us\n", + rx_cnt, slept); return -WD_ETIMEDOUT; } - - if (balance > ECC_BALANCE_THRHD) - usleep(1); } else { WD_ERR("failed to recv: error = %d!\n", ret); return ret; diff --git a/v1/wd_rsa.c b/v1/wd_rsa.c index 1703dd3..08e6151 100644 --- a/v1/wd_rsa.c +++ b/v1/wd_rsa.c @@ -1031,7 +1031,9 @@ int wcrypto_do_rsa(void *ctx, struct wcrypto_rsa_op_data *opdata, void *tag) struct wcrypto_rsa_ctx *ctxt = ctx; struct wcrypto_rsa_cookie *cookie; struct wcrypto_rsa_msg *req; - uint32_t rx_cnt = 0; + __u32 rx_cnt = 0; + __u64 slept = 0; + bool is_timeout; int ret; ret = do_rsa_prepare(ctxt, opdata, &cookie, &req, tag); @@ -1051,14 +1053,14 @@ int wcrypto_do_rsa(void *ctx, struct wcrypto_rsa_op_data *opdata, void *tag) if (ret > 0) { break; } else if (!ret) { - if (unlikely(rx_cnt++ >= RSA_RECV_MAX_CNT)) { - WD_ERR("failed to recv: timeout!\n"); + is_timeout = wd_adaptive_backoff_sleep(balance, RSA_BALANCE_THRHD, + rx_cnt, &slept); + if (unlikely(rx_cnt++ >= RSA_RECV_MAX_CNT || is_timeout)) { + WD_ERR("rsa recv timeout: rx_cnt = %u, slept = %llu us\n", + rx_cnt, slept); ret = -WD_ETIMEDOUT; goto fail_with_cookie; } - - if (balance > RSA_BALANCE_THRHD) - usleep(1); } else { WD_ERR("do rsa wd_recv err!\n"); goto fail_with_cookie; diff --git a/v1/wd_util.c b/v1/wd_util.c index 0bc9d04..eae148b 100644 --- a/v1/wd_util.c +++ b/v1/wd_util.c @@ -24,6 +24,37 @@ #define BYTE_TO_BIT 8 #define LOCK_TRY_CNT (0x800000000U) +#define MAX_SLEEP_SINGLE_US 1000000u +#define MAX_SLEEP_TOTAL_US 60000000u + +#define EXPONENTIAL_BASE 1u +#define BACKOFF_DIV_SHIFT 3 +#define MAX_SHIFT_LIMIT 15 + +bool wd_adaptive_backoff_sleep(int balance, int threshold, + __u32 cnt, __u64 *slept) +{ + __u32 shift; + __u32 delay; + + if (likely(balance <= threshold)) + return false; + + shift = cnt >> BACKOFF_DIV_SHIFT; + if (unlikely(shift >= MAX_SHIFT_LIMIT)) + delay = MAX_SLEEP_SINGLE_US; + else + delay = EXPONENTIAL_BASE << shift; + + if (unlikely(*slept + delay > MAX_SLEEP_TOTAL_US)) + return true; + + usleep(delay); + *slept += delay; + + return false; +} + void wd_spinlock(struct wd_lock *lock) { int val = 0; diff --git a/v1/wd_util.h b/v1/wd_util.h index 9767be4..efe2ed9 100644 --- a/v1/wd_util.h +++ b/v1/wd_util.h @@ -395,6 +395,8 @@ static inline uint32_t wd_reg_read(void *reg_addr) return *((uint32_t *)reg_addr); } +bool wd_adaptive_backoff_sleep(int balance, int threshold, + __u32 cnt, __u64 *slept); void wd_spinlock(struct wd_lock *lock); void wd_unspinlock(struct wd_lock *lock); void wd_fair_init(struct wd_fair_lock *lock); -- 2.33.0