452 lines
12 KiB
Diff
452 lines
12 KiB
Diff
From 760111f47ef44fc401ded9bd3079ee193cc449bb Mon Sep 17 00:00:00 2001
|
|
From: Longfang Liu <liulongfang@huawei.com>
|
|
Date: Sat, 7 Jan 2023 16:08:56 +0800
|
|
Subject: [PATCH 04/28] uadk: Add driver dynamic loading function
|
|
|
|
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);
|
|
+}
|
|
+
|
|
--
|
|
2.25.1
|
|
|