The sysfs dev_usage attribute under /sys/class/uacce/{dev}/ is being removed from the kernel uacce framework. Move the bandwidth utilization read path to debugfs at /sys/kernel/debug/{drv_name}/{pci_bdf}/dev_usage, which is driver-specific and maintained by each HiSilicon QM driver. Add hisi_qm_get_usage_debugfs() in the shared QM layer to resolve the PCI BDF from the uacce sysfs symlink (using dev_name) and read the debugfs dev_usage file. Each hardware driver falls back to this when the MMIO path is unavailable (no qp). Remove sysfs-based parsing from wd.c (wd_read_dev_usage, wd_parse_dev_usage, per-device parse functions, dev_usage_info struct, hpre_ecc_algs/zip_dae_algs arrays). Signed-off-by: Weili Qian <qianweili@huawei.com> --- drv/hisi_comp.c | 36 ++++++---- drv/hisi_dae_common.c | 21 +++--- drv/hisi_hpre.c | 8 ++- drv/hisi_qm_udrv.c | 126 +++++++++++++++++++++++++++++++++ drv/hisi_qm_udrv.h | 2 + drv/hisi_sec.c | 23 ++++--- drv/hisi_udma.c | 21 +++--- include/wd_alg.h | 2 +- wd.c | 144 +------------------------------------- wd_alg.c | 157 +++++++++++++++++++++++++++++++++++++++--- 10 files changed, 337 insertions(+), 203 deletions(-) diff --git a/drv/hisi_comp.c b/drv/hisi_comp.c index c1b83c3..bca5337 100644 --- a/drv/hisi_comp.c +++ b/drv/hisi_comp.c @@ -1828,6 +1828,11 @@ static int hisi_zip_comp_recv(handle_t ctx, void *comp_msg) return 0; } +static const char * const zip_usage_channel_name[] = { + "COMPRESS: ", + "DECOMPRESS: ", +}; + static int hisi_zip_get_usage(void *param) { struct hisi_dev_usage *zip_usage = (struct hisi_dev_usage *)param; @@ -1845,25 +1850,26 @@ static int hisi_zip_get_usage(void *param) } priv = (struct hisi_zip_ctx *)drv->drv_data; - if (!priv) - return -WD_EACCES; - - config = &priv->config; - for (i = 0; i < config->ctx_num; i++) { - ctx_dev_name = wd_ctx_get_dev_name(config->ctxs[i].ctx); - if (!strcmp(zip_usage->dev_name, ctx_dev_name)) { - ctx = config->ctxs[i].ctx; - break; + if (priv) { + config = &priv->config; + for (i = 0; i < config->ctx_num; i++) { + ctx_dev_name = wd_ctx_get_dev_name(config->ctxs[i].ctx); + if (!strcmp(zip_usage->dev_name, ctx_dev_name)) { + ctx = config->ctxs[i].ctx; + break; + } } - } - if (ctx) - qp = (handle_t)wd_ctx_get_priv(ctx); + if (ctx) + qp = (handle_t)wd_ctx_get_priv(ctx); - if (qp) - return hisi_qm_get_usage(qp, zip_usage->alg_op_type); + if (qp) + return hisi_qm_get_usage(qp, zip_usage->alg_op_type); + } - return -WD_EACCES; + /* Fallback to debugfs when no qp is available for this device */ + return hisi_qm_get_usage_debugfs(drv->drv_name, zip_usage->dev_name, + zip_usage_channel_name[zip_usage->alg_op_type]); } #define GEN_ZIP_ALG_DRIVER(zip_alg_name) \ diff --git a/drv/hisi_dae_common.c b/drv/hisi_dae_common.c index 24f6481..f41a5e6 100644 --- a/drv/hisi_dae_common.c +++ b/drv/hisi_dae_common.c @@ -430,17 +430,18 @@ int dae_get_usage(void *param) } dae_ctx = (struct hisi_dae_ctx *)drv->drv_data; - if (!dae_ctx) - return -WD_EACCES; - - for (i = 0; i < dae_ctx->ctx_num; i++) { - ctx_dev_name = wd_ctx_get_dev_name(dae_ctx->ctxs[i]->ctx); - if (!strcmp(dae_usage->dev_name, ctx_dev_name)) { - qp = (handle_t)wd_ctx_get_priv(dae_ctx->ctxs[i]->ctx); - if (qp) - return hisi_qm_get_usage(qp, 0); + if (dae_ctx) { + for (i = 0; i < dae_ctx->ctx_num; i++) { + ctx_dev_name = wd_ctx_get_dev_name(dae_ctx->ctxs[i]->ctx); + if (!strcmp(dae_usage->dev_name, ctx_dev_name)) { + qp = (handle_t)wd_ctx_get_priv(dae_ctx->ctxs[i]->ctx); + if (qp) + return hisi_qm_get_usage(qp, 0); + } } } - return -WD_EACCES; + /* Fallback to debugfs when no qp is available for this device */ + return hisi_qm_get_usage_debugfs(drv->drv_name, dae_usage->dev_name, + "DAE: "); } diff --git a/drv/hisi_hpre.c b/drv/hisi_hpre.c index a4523ab..9a8b58c 100644 --- a/drv/hisi_hpre.c +++ b/drv/hisi_hpre.c @@ -2840,7 +2840,9 @@ static int hpre_ecc_get_usage(void *param) if (qp) return hisi_qm_get_usage(qp, HPRE_HW_V3_ECC_ALG_TYPE); - return -WD_EACCES; + /* Fallback to debugfs when no qp is available for this device */ + return hisi_qm_get_usage_debugfs(drv->drv_name, hpre_usage->dev_name, + "ECC: "); } static int hpre_rsa_get_usage(void *param) @@ -2858,7 +2860,9 @@ static int hpre_rsa_get_usage(void *param) if (qp) return hisi_qm_get_usage(qp, HPRE_HW_V2_ALG_TYPE); - return -WD_EACCES; + /* Fallback to debugfs when no qp is available for this device */ + return hisi_qm_get_usage_debugfs(drv->drv_name, hpre_usage->dev_name, + "RSA: "); } static bool is_valid_hw_type(struct wd_alg_driver *drv) diff --git a/drv/hisi_qm_udrv.c b/drv/hisi_qm_udrv.c index 8617b10..8ecf74a 100644 --- a/drv/hisi_qm_udrv.c +++ b/drv/hisi_qm_udrv.c @@ -5,12 +5,14 @@ #include <limits.h> #include <stdlib.h> #include <string.h> +#include <fcntl.h> #include <sys/mman.h> #include "hisi_qm_udrv.h" #include "wd_util.h" #define QM_DBELL_CMD_SQ 0 +#define DECIMAL_NUMBER 10 #define QM_DBELL_CMD_CQ 1 #define QM_DBELL_OFFSET 0x340 #define QM_DBELL_OFFSET_V2 0x1000 @@ -48,6 +50,11 @@ #define QM_MAX_DEV_USAGE 100 #define QM_DEV_USAGE_RATE 100 +#define DEBUGFS_ROOT "/sys/kernel/debug" +#define UACCE_SYSFS_DIR "/sys/class/uacce" +#define QM_DEV_USAGE_BUF_SIZE 256 +#define QM_PCI_BDF_LEN 32 + struct hisi_qm_type { __u16 qm_ver; int qm_db_offs; @@ -193,6 +200,125 @@ int hisi_qm_get_usage(handle_t h_qp, __u8 type) return usage; } + +static int qm_read_file(const char *path, char *buf, size_t sz) +{ + int saved_errno; + ssize_t rlen; + int fd; + + fd = open(path, O_RDONLY); + if (fd < 0) { + WD_ERR("failed to open %s, errno = %d!\n", path, errno); + return -WD_ENODEV; + } + + rlen = read(fd, buf, sz - 1); + saved_errno = errno; + close(fd); + if (rlen <= 0) { + WD_ERR("failed to read %s, errno = %d!\n", path, saved_errno); + return -WD_EIO; + } + + buf[rlen] = '\0'; + + return 0; +} + +/* + * Resolve the PCI BDF from the uacce sysfs symlink for @dev_name. + * realpath() resolves /sys/class/uacce/{dev} to + * /sys/devices/pciXXX/.../{pci_bdf}/uacce/{dev}; strip the last + * three components to extract the BDF as the last segment. + */ +static int qm_get_pci_bdf(const char *dev_name, char *bdf, size_t sz) +{ + char sysfs_path[PATH_MAX]; + char *resolved, *str; + int ret; + + ret = snprintf(sysfs_path, sizeof(sysfs_path), "%s/%s", + UACCE_SYSFS_DIR, dev_name); + if (ret < 0 || ret >= (int)sizeof(sysfs_path)) + return -WD_EINVAL; + + resolved = realpath(sysfs_path, NULL); + if (!resolved) { + WD_ERR("failed to realpath %s!\n", sysfs_path); + return -WD_ENODEV; + } + + str = strrchr(resolved, '/'); + if (!str) + goto err; + *str = '\0'; + str = strrchr(resolved, '/'); + if (!str) + goto err; + *str = '\0'; + str = strrchr(resolved, '/'); + if (!str) + goto err; + + ret = snprintf(bdf, sz, "%s", str + 1); + if (ret < 0 || ret >= (int)sz) + goto err; + + free(resolved); + return 0; + +err: + free(resolved); + return -WD_EINVAL; +} + +int hisi_qm_get_usage_debugfs(const char *drv_name, const char *dev_name, + const char *channel_name) +{ + char buf[QM_DEV_USAGE_BUF_SIZE]; + char dbg_path[PATH_MAX]; + char bdf[QM_PCI_BDF_LEN]; + long usage; + char *str; + int ret; + + if (!drv_name || !dev_name || !channel_name) { + WD_ERR("invalid: drv_name or dev_name or channel_name is NULL!\n"); + return -WD_EINVAL; + } + + ret = qm_get_pci_bdf(dev_name, bdf, sizeof(bdf)); + if (ret) + return ret; + + ret = snprintf(dbg_path, sizeof(dbg_path), "%s/%s/%s/dev_usage", + DEBUGFS_ROOT, drv_name, bdf); + if (ret < 0 || ret >= (int)sizeof(dbg_path)) { + WD_ERR("failed to snprintf dbg_path!\n"); + return -WD_EINVAL; + } + + ret = qm_read_file(dbg_path, buf, sizeof(buf)); + if (ret) + return ret; + + str = strstr(buf, channel_name); + if (!str) { + WD_ERR("failed to find channel %s!\n", channel_name); + return -WD_EINVAL; + } + + str += strlen(channel_name); + usage = strtol(str, NULL, DECIMAL_NUMBER); + if (usage < 0 || usage > QM_MAX_DEV_USAGE) { + WD_ERR("invalid: usage value %ld!\n", usage); + return -WD_EINVAL; + } + + return (int)usage; +} + static void hisi_qm_fill_sqe(const void *sqe, struct hisi_qm_queue_info *info, __u16 tail, __u16 num) { diff --git a/drv/hisi_qm_udrv.h b/drv/hisi_qm_udrv.h index a7222ce..a442f63 100644 --- a/drv/hisi_qm_udrv.h +++ b/drv/hisi_qm_udrv.h @@ -211,6 +211,8 @@ int hisi_qm_get_free_sqe_num(handle_t h_qp); __u32 hisi_qm_get_list_size(struct wd_datalist *start_node, struct wd_datalist *end_node); int hisi_qm_get_usage(handle_t h_qp, __u8 type); +int hisi_qm_get_usage_debugfs(const char *drv_name, const char *dev_name, + const char *channel_name); #ifdef __cplusplus } diff --git a/drv/hisi_sec.c b/drv/hisi_sec.c index df086d7..f0dffd3 100644 --- a/drv/hisi_sec.c +++ b/drv/hisi_sec.c @@ -615,20 +615,21 @@ static int hisi_sec_get_usage(void *param) } sec_ctx = (struct hisi_sec_ctx *)drv->drv_data; - if (!sec_ctx) - return -WD_EACCES; - - /* Only process the queues used by your own driver. */ - for (i = 0; i < sec_ctx->ctx_num; i++) { - ctx_dev_name = wd_ctx_get_dev_name(sec_ctx->ctxs[i]->ctx); - if (!strcmp(sec_usage->dev_name, ctx_dev_name)) { - qp = (handle_t)wd_ctx_get_priv(sec_ctx->ctxs[i]->ctx); - if (qp) - return hisi_qm_get_usage(qp, 0); + if (sec_ctx) { + /* Only process the queues used by your own driver. */ + for (i = 0; i < sec_ctx->ctx_num; i++) { + ctx_dev_name = wd_ctx_get_dev_name(sec_ctx->ctxs[i]->ctx); + if (!strcmp(sec_usage->dev_name, ctx_dev_name)) { + qp = (handle_t)wd_ctx_get_priv(sec_ctx->ctxs[i]->ctx); + if (qp) + return hisi_qm_get_usage(qp, 0); + } } } - return -WD_EACCES; + /* Fallback to debugfs when no qp is available for this device */ + return hisi_qm_get_usage_debugfs(drv->drv_name, sec_usage->dev_name, + "SEC: "); } static int eops_param_check(struct wd_alg_driver *drv, struct wd_mm_ops *mm_ops) diff --git a/drv/hisi_udma.c b/drv/hisi_udma.c index 2d665e8..631f070 100644 --- a/drv/hisi_udma.c +++ b/drv/hisi_udma.c @@ -563,19 +563,20 @@ static int udma_get_usage(void *param) } uctx = (struct hisi_udma_ctx *)drv->drv_data; - if (!uctx) - return -WD_EACCES; - - for (i = 0; i < uctx->ctx_num; i++) { - ctx_dev_name = wd_ctx_get_dev_name(uctx->ctxs[i]->ctx); - if (!strcmp(udma_usage->dev_name, ctx_dev_name)) { - qp = (handle_t)wd_ctx_get_priv(uctx->ctxs[i]->ctx); - if (qp) - return hisi_qm_get_usage(qp, 0); + if (uctx) { + for (i = 0; i < uctx->ctx_num; i++) { + ctx_dev_name = wd_ctx_get_dev_name(uctx->ctxs[i]->ctx); + if (!strcmp(udma_usage->dev_name, ctx_dev_name)) { + qp = (handle_t)wd_ctx_get_priv(uctx->ctxs[i]->ctx); + if (qp) + return hisi_qm_get_usage(qp, 0); + } } } - return -WD_EACCES; + /* Fallback to debugfs when no qp is available for this device */ + return hisi_qm_get_usage_debugfs(drv->drv_name, udma_usage->dev_name, + "DAE: "); } static struct wd_alg_driver udma_driver = { diff --git a/include/wd_alg.h b/include/wd_alg.h index 3cc4e43..80bb57d 100644 --- a/include/wd_alg.h +++ b/include/wd_alg.h @@ -251,7 +251,7 @@ bool wd_drv_alg_support(const char *alg_name, void *param); */ bool wd_alg_match_drv(struct wd_alg_driver *drv, const char *alg_name); -int wd_alg_get_dev_usage(const char *dev_name, const char *alg_type, __u8 op_type); +int wd_alg_get_dev_usage(const char *dev_name, const char *alg_name, __u8 op_type); int wd_get_alg_type(const char *alg_name, char *alg_type); struct wd_drv_node *wd_get_alg_head(void); diff --git a/wd.c b/wd.c index 13852f7..23ec0e1 100644 --- a/wd.c +++ b/wd.c @@ -24,7 +24,6 @@ #include "wd_bmm.h" #define SYS_CLASS_DIR "/sys/class/uacce" #define FILE_MAX_SIZE (8 << 20) -#define WD_DEV_USAGE_SIZE 256 #define WD_DEFAULT_NUMA_DISTANCE 1024 enum UADK_LOG_LEVEL { @@ -37,27 +36,6 @@ enum UADK_LOG_LEVEL { static int uadk_log_level = WD_LOG_INVALID; -struct dev_usage_info { - const char *dev_name; - __u8 alg_op_type; - int (*usage_parse_fn)(char *buf, const char *alg_name, __u8 alg_op_type); -}; - -static const char * const hpre_ecc_algs[] = { - "sm2", - "ecdh", - "x448", - "x25519", - "ecdsa" -}; - -static const char * const zip_dae_algs[] = { - "udma", - "hashagg", - "hashjoin", - "gather", -}; - /** * Constant-time memory comparison function (primarily used for equality verification) * It only supports equality/inequality results rather than full comparison results, @@ -1044,130 +1022,12 @@ alloc_err: return NULL; } -static int wd_parse_usage_value(char *buf, const char *type_name) -{ - char *str; - int ret; - - str = strstr(buf, type_name); - if (!str) - return -WD_EINVAL; - - str += strlen(type_name); - ret = strtol(str, NULL, 10); - if (ret < 0) - WD_ERR("fail to get device usage value, ret %d!\n", ret); - - return ret; -} - -/* - * The format of the string obtained from sysfs is fixed - * and does not need to consider other scenarios. - */ -static int wd_zip_usage_parse_fn(char *buf, const char *alg_name, __u8 alg_op_type) -{ - size_t size = ARRAY_SIZE(zip_dae_algs); - size_t i; - - for (i = 0; i < size; i++) { - if (!strcmp(alg_name, zip_dae_algs[i])) { - if (alg_op_type != 0) { - WD_ERR("invalid: alg_name %s alg_op_type error!\n", alg_name); - return -WD_EINVAL; - } - return wd_parse_usage_value(buf, "DAE: "); - } - } - - if (alg_op_type == 0) - return wd_parse_usage_value(buf, "COMPRESS: "); - - return wd_parse_usage_value(buf, "DECOMPRESS: "); -} - -static int wd_sec_usage_parse_fn(char *buf, const char *alg_name, __u8 alg_op_type) -{ - return wd_parse_usage_value(buf, "SEC: "); -} - -static int wd_hpre_usage_parse_fn(char *buf, const char *alg_name, __u8 alg_op_type) -{ - size_t size = ARRAY_SIZE(hpre_ecc_algs); - size_t i; - - for (i = 0; i < size; i++) { - if (!strcmp(alg_name, hpre_ecc_algs[i])) - return wd_parse_usage_value(buf, "ECC: "); - } - - return wd_parse_usage_value(buf, "RSA: "); -} - -static const struct dev_usage_info dev_usage_parse[] = { - { - .dev_name = "hisi_zip", - .alg_op_type = 2, - .usage_parse_fn = wd_zip_usage_parse_fn - }, { - .dev_name = "hisi_sec", - .alg_op_type = 1, - .usage_parse_fn = wd_sec_usage_parse_fn - }, { - .dev_name = "hisi_hpre", - .alg_op_type = 1, - .usage_parse_fn = wd_hpre_usage_parse_fn - }, -}; - -static int wd_parse_dev_usage(struct uacce_dev *dev, char *buf, - const char *alg_name, __u8 alg_op_type) -{ - size_t size = ARRAY_SIZE(dev_usage_parse); - size_t i; - - for (i = 0; i < size; i++) { - if (strstr(dev->dev_root, dev_usage_parse[i].dev_name)) - break; - } - - if (i == size) { - WD_ERR("failed to find parse function!\n"); - return -WD_EINVAL; - } - - if (alg_op_type >= dev_usage_parse[i].alg_op_type) { - WD_ERR("invalid: alg_op_type %u is error!\n", alg_op_type); - return -WD_EINVAL; - } - - return dev_usage_parse[i].usage_parse_fn(buf, alg_name, alg_op_type); -} - -static int wd_read_dev_usage(struct uacce_dev *dev, const char *alg_name, __u8 alg_op_type) -{ - char buf[WD_DEV_USAGE_SIZE]; - int ret; - - ret = access_attr(dev->dev_root, "dev_usage", F_OK); - if (ret) { - WD_ERR("failed to access dev_usage!\n"); - return ret; - } - - ret = get_str_attr(dev, "dev_usage", buf, WD_DEV_USAGE_SIZE); - if (ret < 0) - return ret; - - return wd_parse_dev_usage(dev, buf, alg_name, alg_op_type); -} - int wd_get_dev_usage(struct uacce_dev *dev, const char *alg_name, __u8 alg_op_type) { char *dev_name; int ret; - if (!dev || !alg_name || !strlen(dev->algs)) { + if (!dev || !alg_name) { WD_ERR("invalid: dev or alg name is NULL!\n"); return -WD_EINVAL; } @@ -1184,8 +1044,6 @@ int wd_get_dev_usage(struct uacce_dev *dev, const char *alg_name, __u8 alg_op_ty } ret = wd_alg_get_dev_usage(dev_name + 1, alg_name, alg_op_type); - if (ret == -WD_EACCES) - return wd_read_dev_usage(dev, alg_name, alg_op_type); return ret; } diff --git a/wd_alg.c b/wd_alg.c index e288bd0..01f33b9 100644 --- a/wd_alg.c +++ b/wd_alg.c @@ -5,12 +5,16 @@ #define _GNU_SOURCE #include <dirent.h> +#include <dlfcn.h> #include <errno.h> +#include <limits.h> #include <stdio.h> #include <stdbool.h> #include <stdlib.h> +#include <string.h> #include <pthread.h> #include <sys/auxv.h> +#include <sys/stat.h> #include "wd.h" #include "wd_alg_common.h" @@ -554,26 +558,157 @@ struct wd_alg_driver *wd_request_drv(const char *alg_name, int drv_type) return drv; } -int wd_alg_get_dev_usage(const char *dev_name, const char *alg_type, __u8 alg_op_type) +static struct wd_drv_node *wd_alg_find_drv_node(const char *dev_name, + const char *alg_type) { - struct wd_drv_node *node = alg_registry.head->next; - struct hisi_dev_usage dev_usage; - struct wd_alg_driver *drv; - - if (!dev_name || !alg_type) { - WD_ERR("invalid: dev_name or alg_type is NULL!\n"); - return -WD_EINVAL; - } + struct wd_drv_node *node; + pthread_mutex_lock(&alg_registry.mutex); + node = alg_registry.head->next; while (node) { - /* Match dev_name and alg_type at the driver node level */ if (strstr(dev_name, node->drv_name) && !strcmp(alg_type, node->alg_type)) break; - node = node->next; } + pthread_mutex_unlock(&alg_registry.mutex); + return node; +} + +/* + * wd_alg_scan_drv_dir() - dlopen each lib*.so in the uadk driver directory. + * + * Each driver .so uses __attribute__((constructor)) to auto-register its + * wd_alg_driver entries into alg_registry. Stops as soon as a node + * matching @dev_name and @alg_type appears. + */ +static struct wd_drv_node *wd_alg_scan_drv_dir(const char *dev_name, + const char *alg_type) +{ + struct wd_drv_node *node = NULL; + char lib_dir[PATH_MAX]; + struct dirent *ent; + char *resolved, *p; + int len, dir_len; + Dl_info info; + void *handle; + DIR *dir; + + if (!dladdr((void *)wd_alg_scan_drv_dir, &info) || !info.dli_fname) + return NULL; + + resolved = realpath(info.dli_fname, lib_dir); + if (!resolved) + return NULL; + + p = strrchr(lib_dir, '/'); + if (!p) + return NULL; + *p = '\0'; + + len = (int)strlen(lib_dir); + if (len + (int)sizeof("/uadk") >= PATH_MAX) + return NULL; + strcat(lib_dir, "/uadk"); + + dir = opendir(lib_dir); + if (!dir) + return NULL; + + dir_len = (int)strlen(lib_dir); + + while ((ent = readdir(dir)) != NULL) { + size_t namelen = strlen(ent->d_name); + + if (namelen < strlen("lib") + 1 + strlen(".so") || + strncmp(ent->d_name, "lib", strlen("lib")) || + strcmp(ent->d_name + namelen - strlen(".so"), ".so")) + continue; + + if (dir_len + 1 + (int)namelen >= PATH_MAX) + continue; + + lib_dir[dir_len] = '/'; + memcpy(lib_dir + dir_len + 1, ent->d_name, namelen + 1); + + handle = dlopen(lib_dir, RTLD_NODELETE | RTLD_NOW); + if (!handle) { + WD_ERR("failed to dlopen %s: %s\n", lib_dir, dlerror()); + continue; + } + + dlclose(handle); + node = wd_alg_find_drv_node(dev_name, alg_type); + if (node) + break; + } + + closedir(dir); + return node; +} + +/* + * wd_alg_load_drv() - Load driver libraries until the requested driver + * is found. Fallback for paths that query alg_registry without having + * gone through wd_*_init() (e.g. uadk_tool dfx --usage). + */ +static struct wd_drv_node *wd_alg_load_drv(const char *dev_name, + const char *alg_type) +{ + struct wd_drv_node *node; + static bool all_loaded; + static bool loading; + + /* + * dlopen must run outside alg_registry.mutex because driver + * constructors call wd_alg_driver_register which acquires the + * same mutex. + */ + pthread_mutex_lock(&alg_registry.mutex); + if (all_loaded || loading) { + pthread_mutex_unlock(&alg_registry.mutex); + return NULL; + } + loading = true; + pthread_mutex_unlock(&alg_registry.mutex); + + node = wd_alg_scan_drv_dir(dev_name, alg_type); + + pthread_mutex_lock(&alg_registry.mutex); + if (!node) + all_loaded = true; + loading = false; + pthread_mutex_unlock(&alg_registry.mutex); + + return node; +} + +int wd_alg_get_dev_usage(const char *dev_name, const char *alg_name, __u8 alg_op_type) +{ + struct hisi_dev_usage dev_usage = {0}; + struct wd_alg_driver *drv; + char alg_type[ALG_NAME_SIZE]; + struct wd_drv_node *node; + int ret; + + if (!dev_name || !alg_name) { + WD_ERR("invalid: dev_name or alg_name is NULL!\n"); + return -WD_EINVAL; + } + /* + * Convert alg_name to alg_type for driver node matching. + * If alg_name is already a generic alg_type (e.g. "cipher", "digest"), + * wd_get_alg_type fails, fall back to using alg_name directly. + */ + ret = wd_get_alg_type(alg_name, alg_type); + if (ret) + snprintf(alg_type, ALG_NAME_SIZE, "%s", alg_name); + + /* Load driver libraries if target driver node not found. */ + node = wd_alg_find_drv_node(dev_name, alg_type); + if (!node) + node = wd_alg_load_drv(dev_name, alg_type); if (!node) return -WD_EACCES; -- 2.43.0