According to the logical layering of UADK, the device driver has been updated from the previous fixed binding HiSilicon accelerator to the dynamic registration method through the algorithm linked list method.
After the update, it can support the use of instruction acceleration and third-party device drivers.
Signed-off-by: Longfang Liu liulongfang@huawei.com --- Makefile.am | 4 +- include/wd_alg.h | 95 ++++++++++++++ include/wd_alg_common.h | 1 + libwd.map | 8 ++ wd_alg.c | 265 ++++++++++++++++++++++++++++++++++++++++ 5 files changed, 371 insertions(+), 2 deletions(-) create mode 100644 include/wd_alg.h create mode 100644 wd_alg.c
diff --git a/Makefile.am b/Makefile.am index ee8454b..1ea6d6b 100644 --- a/Makefile.am +++ b/Makefile.am @@ -33,7 +33,7 @@ AM_CFLAGS+= -DUADK_RELEASED_TIME=""Released ${MONTH} ${DAY}, ${YEAR}"" pkginclude_HEADERS = include/wd.h include/wd_cipher.h include/wd_aead.h \ include/wd_comp.h include/wd_dh.h include/wd_digest.h \ include/wd_rsa.h include/uacce.h include/wd_alg_common.h \ - include/wd_ecc.h include/wd_sched.h + include/wd_ecc.h include/wd_sched.h include/wd_alg.h
nobase_pkginclude_HEADERS = v1/wd.h v1/wd_cipher.h v1/wd_aead.h v1/uacce.h v1/wd_dh.h \ v1/wd_digest.h v1/wd_rsa.h v1/wd_bmm.h @@ -41,7 +41,7 @@ nobase_pkginclude_HEADERS = v1/wd.h v1/wd_cipher.h v1/wd_aead.h v1/uacce.h v1/wd lib_LTLIBRARIES=libwd.la libwd_comp.la libwd_crypto.la libhisi_zip.la \ libhisi_hpre.la libhisi_sec.la
-libwd_la_SOURCES=wd.c wd_mempool.c wd.h \ +libwd_la_SOURCES=wd.c wd_mempool.c wd.h wd_alg.c wd_alg.h \ v1/wd.c v1/wd.h v1/wd_adapter.c v1/wd_adapter.h \ v1/wd_rng.c v1/wd_rng.h \ v1/wd_rsa.c v1/wd_rsa.h \ diff --git a/include/wd_alg.h b/include/wd_alg.h new file mode 100644 index 0000000..e25e191 --- /dev/null +++ b/include/wd_alg.h @@ -0,0 +1,95 @@ +// SPDX-License-Identifier: Apache-2.0 +/* + * Copyright 2023 Huawei Technologies Co.,Ltd. All rights reserved. + */ + +#ifndef __WD_ALG_H +#define __WD_ALG_H +#include <errno.h> +#include <fcntl.h> +#include <stdbool.h> +#include <stdint.h> +#include <stdio.h> +#include <string.h> +#include <syslog.h> +#include <unistd.h> +#include <asm/types.h> + +#ifdef __cplusplus +extern "C" { +#endif + +#define handle_t uintptr_t +enum alg_priority { + UADK_ALG_SOFT = 0x0, + UADK_ALG_CE_INSTR = 0x1, + UADK_ALG_SVE_INSTR = 0x2, + UADK_ALG_HW = 0x3 +}; + +/** + * @drv_name: name of the current device driver + * @alg_name: name of the algorithm supported by the driver + * @priority: priority of the type of algorithm supported by the driver + * @queue_num: number of device queues required by the device to + * execute the algorithm task + * @op_type_num: number of modes in which the device executes the + * algorithm business and requires queues to be executed separately + * @priv_size: parameter memory size passed between the internal + * interfaces of the driver + * @fallback: soft calculation driver handle when performing soft + * calculation supplement + * @init: callback interface for initializing device drivers + * @exit: callback interface for destroying device drivers + * @send: callback interface used to send task packets to + * hardware devices. + * @recv: callback interface used to retrieve the calculation + * result of the task packets from the hardware device. + * @get_usage: callback interface used to obtain the + * utilization rate of devices. + */ +struct wd_alg_driver { + const char *drv_name; + const char *alg_name; + int priority; + int queue_num; + int op_type_num; + int priv_size; + handle_t fallback; + + int (*init)(void *conf, void *priv); + void (*exit)(void *priv); + int (*send)(handle_t ctx, void *drv_msg); + int (*recv)(handle_t ctx, void *drv_msg); + int (*get_usage)(void *param); +}; + +int wd_alg_driver_register(struct wd_alg_driver *drv); +void wd_alg_driver_unregister(struct wd_alg_driver *drv); + +struct wd_alg_list { + const char *alg_name; + const char *drv_name; + bool available; + int priority; + int refcnt; + + struct wd_alg_driver *drv; + struct wd_alg_list *next; +}; + +struct wd_alg_driver *wd_request_drv(const char *alg_name, bool hw_mask); +void wd_release_drv(struct wd_alg_driver *drv); + +bool wd_drv_alg_support(const char *alg_name, + struct wd_alg_driver *drv); +void wd_enable_drv(struct wd_alg_driver *drv); +void wd_disable_drv(struct wd_alg_driver *drv); + +struct wd_alg_list *wd_get_alg_head(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/wd_alg_common.h b/include/wd_alg_common.h index 56539cc..d04b046 100644 --- a/include/wd_alg_common.h +++ b/include/wd_alg_common.h @@ -10,6 +10,7 @@ #include <pthread.h> #include <stdbool.h> #include "wd.h" +#include "wd_alg.h"
#ifdef __cplusplus extern "C" { diff --git a/libwd.map b/libwd.map index 459f9ba..5522ec0 100644 --- a/libwd.map +++ b/libwd.map @@ -41,5 +41,13 @@ global: wd_add_dev_to_list; wd_find_dev_by_numa;
+ wd_alg_driver_register; + wd_alg_driver_unregister; + wd_request_drv; + wd_release_drv; + wd_drv_alg_support; + wd_enable_drv; + wd_disable_drv; + wd_get_alg_head; local: *; }; diff --git a/wd_alg.c b/wd_alg.c new file mode 100644 index 0000000..5e4edaf --- /dev/null +++ b/wd_alg.c @@ -0,0 +1,265 @@ +/* SPDX-License-Identifier: Apache-2.0 */ +/* + * Copyright 2023 Huawei Technologies Co.,Ltd. All rights reserved. + */ + +#define _GNU_SOURCE +#include <ctype.h> +#include <dirent.h> +#include <errno.h> +#include <stdbool.h> +#include <stdlib.h> +#include <string.h> +#include <pthread.h> + +#include "wd.h" +#include "wd_alg.h" + +#define SYS_CLASS_DIR "/sys/class/uacce" +static struct wd_alg_list alg_list_head; +static struct wd_alg_list *alg_list_tail = &alg_list_head; + +static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; + +static bool wd_check_accel_dev(const char *dev_name) +{ + struct dirent *dev_dir; + DIR *wd_class; + + wd_class = opendir(SYS_CLASS_DIR); + if (!wd_class) { + WD_ERR("UADK framework isn't enabled in system!\n"); + return false; + } + + while ((dev_dir = readdir(wd_class)) != NULL) { + if (!strncmp(dev_dir->d_name, ".", LINUX_CRTDIR_SIZE) || + !strncmp(dev_dir->d_name, "..", LINUX_PRTDIR_SIZE)) + continue; + + if (!strncmp(dev_dir->d_name, dev_name, strlen(dev_name))) { + closedir(wd_class); + return true; + } + } + closedir(wd_class); + + return false; +} + +int wd_alg_driver_register(struct wd_alg_driver *drv) +{ + struct wd_alg_list *new_alg; + + if (!drv) { + WD_ERR("invalid: register drv is NULL!\n"); + return -WD_EINVAL; + } + + new_alg = calloc(1, sizeof(struct wd_alg_list)); + if (!new_alg) { + WD_ERR("failed to alloc alg driver memory!\n"); + return -WD_ENOMEM; + } + + new_alg->alg_name = drv->alg_name; + new_alg->drv_name = drv->drv_name; + new_alg->priority = drv->priority; + new_alg->drv = drv; + new_alg->refcnt = 0; + new_alg->next = NULL; + + if (drv->priority == UADK_ALG_HW) { + /* If not find dev, remove this driver node */ + new_alg->available = wd_check_accel_dev(drv->drv_name); + if (!new_alg->available) { + free(new_alg); + WD_ERR("failed to find alg driver's device!\n"); + return -WD_ENODEV; + } + } else { + /* Should find the CPU if not support SVE or CE */ + new_alg->available = true; + } + + pthread_mutex_lock(&mutex); + alg_list_tail->next = new_alg; + alg_list_tail = new_alg; + pthread_mutex_unlock(&mutex); + + return 0; +} + +void wd_alg_driver_unregister(struct wd_alg_driver *drv) +{ + struct wd_alg_list *npre = &alg_list_head; + struct wd_alg_list *pnext = npre->next; + + /* Alg driver list has no drivers */ + if (!pnext || !drv) + return; + + pthread_mutex_lock(&mutex); + while (pnext) { + if (!strcmp(drv->alg_name, pnext->alg_name) && + !strcmp(drv->drv_name, pnext->drv_name) && + drv->priority == pnext->priority) { + break; + } + npre = pnext; + pnext = pnext->next; + } + + /* The current algorithm is not registered */ + if (!pnext) { + pthread_mutex_unlock(&mutex); + return; + } + + /* Used to locate the problem and ensure symmetrical use driver */ + if (pnext->refcnt > 0) + WD_ERR("driver<%s> still in used: %d\n", pnext->drv_name, pnext->refcnt); + + if (pnext == alg_list_tail) + alg_list_tail = npre; + + npre->next = pnext->next; + free(pnext); + pthread_mutex_unlock(&mutex); +} + +struct wd_alg_list *wd_get_alg_head(void) +{ + return &alg_list_head; +} + +bool wd_drv_alg_support(const char *alg_name, + struct wd_alg_driver *drv) +{ + struct wd_alg_list *head = &alg_list_head; + struct wd_alg_list *pnext = head->next; + + while (pnext) { + if (!strcmp(alg_name, pnext->alg_name) && + !strcmp(drv->drv_name, pnext->drv_name)) { + return true; + } + pnext = pnext->next; + } + + return false; +} + +void wd_enable_drv(struct wd_alg_driver *drv) +{ + struct wd_alg_list *head = &alg_list_head; + struct wd_alg_list *pnext = head->next; + + if (!pnext || !drv) + return; + + pthread_mutex_lock(&mutex); + while (pnext) { + if (!strcmp(drv->alg_name, pnext->alg_name) && + !strcmp(drv->drv_name, pnext->drv_name) && + drv->priority == pnext->priority) { + break; + } + pnext = pnext->next; + } + + if (drv->priority == UADK_ALG_HW) { + /* If not find dev, remove this driver node */ + pnext->available = wd_check_accel_dev(drv->drv_name); + } else { + /* Should find the CPU if not support SVE or CE */ + pnext->available = true; + } + pthread_mutex_unlock(&mutex); +} + +void wd_disable_drv(struct wd_alg_driver *drv) +{ + struct wd_alg_list *head = &alg_list_head; + struct wd_alg_list *pnext = head->next; + + if (!pnext || !drv) + return; + + pthread_mutex_lock(&mutex); + while (pnext) { + if (!strcmp(drv->alg_name, pnext->alg_name) && + !strcmp(drv->drv_name, pnext->drv_name) && + drv->priority == pnext->priority) { + break; + } + pnext = pnext->next; + } + + pnext->available = false; + pthread_mutex_unlock(&mutex); +} + +struct wd_alg_driver *wd_request_drv(const char *alg_name, bool hw_mask) +{ + struct wd_alg_list *head = &alg_list_head; + struct wd_alg_list *pnext = head->next; + struct wd_alg_list *select_node = NULL; + struct wd_alg_driver *drv = NULL; + int tmp_priority = -1; + + if (!pnext || !alg_name) { + WD_ERR("invalid: request alg param is error!\n"); + return NULL; + } + + /* Check the list to get an best driver */ + pthread_mutex_lock(&mutex); + while (pnext) { + /* hw_mask true mean not to used hardware dev */ + if (hw_mask && pnext->drv->priority == UADK_ALG_HW) { + pnext = pnext->next; + continue; + } + + if (!strcmp(alg_name, pnext->alg_name) && pnext->available && + pnext->drv->priority > tmp_priority) { + tmp_priority = pnext->drv->priority; + select_node = pnext; + drv = pnext->drv; + } + pnext = pnext->next; + } + + if (select_node) + select_node->refcnt++; + pthread_mutex_unlock(&mutex); + + return drv; +} + +void wd_release_drv(struct wd_alg_driver *drv) +{ + struct wd_alg_list *head = &alg_list_head; + struct wd_alg_list *pnext = head->next; + struct wd_alg_list *select_node = NULL; + + if (!pnext || !drv) + return; + + pthread_mutex_lock(&mutex); + while (pnext) { + if (!strcmp(drv->alg_name, pnext->alg_name) && + !strcmp(drv->drv_name, pnext->drv_name) && + drv->priority == pnext->priority) { + select_node = pnext; + break; + } + pnext = pnext->next; + } + + if (select_node && select_node->refcnt > 0) + select_node->refcnt--; + pthread_mutex_unlock(&mutex); +} +