From: Kenneth Lee <liguozhu@xxxxxxxxxxxxx> This is the sample code to demostrate how WarpDrive user application should be. (Uacce is the kernel component for WarpDrive.) It contains: 1. wd.[ch]: the common library to provide WrapDrive interface. 2. wd_adaptor.[ch]: the adaptor for wd to call different user drivers 3. drv/*: the user driver to access the hardware space 4. test/*, the test application The Hisilicon HIP08 ZIP accelerator is used in this sample. Signed-off-by: Zaibo Xu <xuzaibo@xxxxxxxxxx> Signed-off-by: Kenneth Lee <liguozhu@xxxxxxxxxxxxx> Signed-off-by: Hao Fang <fanghao11@xxxxxxxxxx> Signed-off-by: Zhou Wang <wangzhou1@xxxxxxxxxxxxx> --- samples/warpdrive/AUTHORS | 3 + samples/warpdrive/ChangeLog | 1 + samples/warpdrive/Makefile.am | 9 + samples/warpdrive/NEWS | 1 + samples/warpdrive/README | 32 ++++ samples/warpdrive/autogen.sh | 3 + samples/warpdrive/cleanup.sh | 13 ++ samples/warpdrive/conf.sh | 4 + samples/warpdrive/configure.ac | 52 ++++++ samples/warpdrive/drv/hisi_qm_udrv.c | 228 +++++++++++++++++++++++++ samples/warpdrive/drv/hisi_qm_udrv.h | 57 +++++++ samples/warpdrive/drv/wd_drv.h | 19 +++ samples/warpdrive/test/Makefile.am | 7 + samples/warpdrive/test/test_hisi_zip.c | 150 ++++++++++++++++ samples/warpdrive/wd.c | 96 +++++++++++ samples/warpdrive/wd.h | 97 +++++++++++ samples/warpdrive/wd_adapter.c | 71 ++++++++ samples/warpdrive/wd_adapter.h | 36 ++++ 18 files changed, 879 insertions(+) create mode 100644 samples/warpdrive/AUTHORS create mode 100644 samples/warpdrive/ChangeLog create mode 100644 samples/warpdrive/Makefile.am create mode 100644 samples/warpdrive/NEWS create mode 100644 samples/warpdrive/README create mode 100755 samples/warpdrive/autogen.sh create mode 100755 samples/warpdrive/cleanup.sh create mode 100755 samples/warpdrive/conf.sh create mode 100644 samples/warpdrive/configure.ac create mode 100644 samples/warpdrive/drv/hisi_qm_udrv.c create mode 100644 samples/warpdrive/drv/hisi_qm_udrv.h create mode 100644 samples/warpdrive/drv/wd_drv.h create mode 100644 samples/warpdrive/test/Makefile.am create mode 100644 samples/warpdrive/test/test_hisi_zip.c create mode 100644 samples/warpdrive/wd.c create mode 100644 samples/warpdrive/wd.h create mode 100644 samples/warpdrive/wd_adapter.c create mode 100644 samples/warpdrive/wd_adapter.h diff --git a/samples/warpdrive/AUTHORS b/samples/warpdrive/AUTHORS new file mode 100644 index 000000000000..bb55d2769147 --- /dev/null +++ b/samples/warpdrive/AUTHORS @@ -0,0 +1,3 @@ +Kenneth Lee <liguozhu@xxxxxxxxxxxxx> +Zaibo Xu <xuzaibo@xxxxxxxxxx> +Zhou Wang <wangzhou1@xxxxxxxxxxxxx> diff --git a/samples/warpdrive/ChangeLog b/samples/warpdrive/ChangeLog new file mode 100644 index 000000000000..b1b716105590 --- /dev/null +++ b/samples/warpdrive/ChangeLog @@ -0,0 +1 @@ +init diff --git a/samples/warpdrive/Makefile.am b/samples/warpdrive/Makefile.am new file mode 100644 index 000000000000..41154a880a97 --- /dev/null +++ b/samples/warpdrive/Makefile.am @@ -0,0 +1,9 @@ +ACLOCAL_AMFLAGS = -I m4 +AUTOMAKE_OPTIONS = foreign subdir-objects +AM_CFLAGS=-Wall -O0 -fno-strict-aliasing + +lib_LTLIBRARIES=libwd.la +libwd_la_SOURCES=wd.c wd_adapter.c wd.h wd_adapter.h \ + drv/hisi_qm_udrv.c drv/hisi_qm_udrv.h + +SUBDIRS=. test diff --git a/samples/warpdrive/NEWS b/samples/warpdrive/NEWS new file mode 100644 index 000000000000..b1b716105590 --- /dev/null +++ b/samples/warpdrive/NEWS @@ -0,0 +1 @@ +init diff --git a/samples/warpdrive/README b/samples/warpdrive/README new file mode 100644 index 000000000000..3adf66b112fc --- /dev/null +++ b/samples/warpdrive/README @@ -0,0 +1,32 @@ +WD User Land Demonstration +========================== + +This directory contains some applications and libraries to demonstrate how a + +WrapDrive application can be constructed. + + +As a demo, we try to make it simple and clear for understanding. It is not + +supposed to be used in business scenario. + + +The directory contains the following elements: + +wd.[ch] + A demonstration WrapDrive fundamental library which wraps the basic + operations to the WrapDrive-ed device. + +wd_adapter.[ch] + User driver adaptor for wd.[ch] + +wd_utils.[ch] + Some utitlities function used by WD and its drivers + +drv/* + User drivers. It helps to fulfill the semantic of wd.[ch] for + particular hardware + +test/* + Test applications to use the wrapdrive library + diff --git a/samples/warpdrive/autogen.sh b/samples/warpdrive/autogen.sh new file mode 100755 index 000000000000..58deaf49de2a --- /dev/null +++ b/samples/warpdrive/autogen.sh @@ -0,0 +1,3 @@ +#!/bin/sh -x + +autoreconf -i -f -v diff --git a/samples/warpdrive/cleanup.sh b/samples/warpdrive/cleanup.sh new file mode 100755 index 000000000000..c5f3d21e5dc1 --- /dev/null +++ b/samples/warpdrive/cleanup.sh @@ -0,0 +1,13 @@ +#!/bin/sh + +if [ -r Makefile ]; then + make distclean +fi + +FILES="aclocal.m4 autom4te.cache compile config.guess config.h.in config.log \ + config.status config.sub configure cscope.out depcomp install-sh \ + libsrc/Makefile libsrc/Makefile.in libtool ltmain.sh Makefile \ + ar-lib m4 \ + Makefile.in missing src/Makefile src/Makefile.in test/Makefile.in" + +rm -vRf $FILES diff --git a/samples/warpdrive/conf.sh b/samples/warpdrive/conf.sh new file mode 100755 index 000000000000..2af8a54c5126 --- /dev/null +++ b/samples/warpdrive/conf.sh @@ -0,0 +1,4 @@ +ac_cv_func_malloc_0_nonnull=yes ac_cv_func_realloc_0_nonnull=yes ./configure \ + --host aarch64-linux-gnu \ + --target aarch64-linux-gnu \ + --program-prefix aarch64-linux-gnu- diff --git a/samples/warpdrive/configure.ac b/samples/warpdrive/configure.ac new file mode 100644 index 000000000000..53262f3197c2 --- /dev/null +++ b/samples/warpdrive/configure.ac @@ -0,0 +1,52 @@ +AC_PREREQ([2.69]) +AC_INIT([wrapdrive], [0.1], [liguozhu@xxxxxxxxxxxxx]) +AC_CONFIG_SRCDIR([wd.c]) +AM_INIT_AUTOMAKE([1.10 no-define]) + +AC_CONFIG_MACRO_DIR([m4]) +AC_CONFIG_HEADERS([config.h]) + +# Checks for programs. +AC_PROG_CXX +AC_PROG_AWK +AC_PROG_CC +AC_PROG_CPP +AC_PROG_INSTALL +AC_PROG_LN_S +AC_PROG_MAKE_SET +AC_PROG_RANLIB + +AM_PROG_AR +AC_PROG_LIBTOOL +AM_PROG_LIBTOOL +LT_INIT +AM_PROG_CC_C_O + +AC_DEFINE([HAVE_SVA], [0], [enable SVA support]) +AC_ARG_ENABLE([sva], + [ --enable-sva enable to support sva feature], + AC_DEFINE([HAVE_SVA], [1])) + +# Checks for libraries. + +# Checks for header files. +AC_CHECK_HEADERS([fcntl.h stdint.h stdlib.h string.h sys/ioctl.h sys/time.h unistd.h]) + +# Checks for typedefs, structures, and compiler characteristics. +AC_CHECK_HEADER_STDBOOL +AC_C_INLINE +AC_TYPE_OFF_T +AC_TYPE_SIZE_T +AC_TYPE_UINT16_T +AC_TYPE_UINT32_T +AC_TYPE_UINT64_T +AC_TYPE_UINT8_T + +# Checks for library functions. +AC_FUNC_MALLOC +AC_FUNC_MMAP +AC_CHECK_FUNCS([memset munmap]) + +AC_CONFIG_FILES([Makefile + test/Makefile]) +AC_OUTPUT diff --git a/samples/warpdrive/drv/hisi_qm_udrv.c b/samples/warpdrive/drv/hisi_qm_udrv.c new file mode 100644 index 000000000000..5e623f31e2cb --- /dev/null +++ b/samples/warpdrive/drv/hisi_qm_udrv.c @@ -0,0 +1,228 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#include <stdlib.h> +#include <unistd.h> +#include <stdio.h> +#include <sys/mman.h> +#include <assert.h> +#include <string.h> +#include <stdint.h> +#include <fcntl.h> +#include <sys/stat.h> +#include <sys/ioctl.h> +#include <sys/epoll.h> +#include <sys/eventfd.h> + +#include "wd_drv.h" +#include "hisi_qm_udrv.h" + +#define QM_SQE_SIZE 128 /* todo: get it from sysfs */ +#define QM_CQE_SIZE 16 + +#define DOORBELL_CMD_SQ 0 +#define DOORBELL_CMD_CQ 1 + +/* cqe shift */ +#define CQE_PHASE(cq) (((*((__u32 *)(cq) + 3)) >> 16) & 0x1) +#define CQE_SQ_NUM(cq) ((*((__u32 *)(cq) + 2)) >> 16) +#define CQE_SQ_HEAD_INDEX(cq) ((*((__u32 *)(cq) + 2)) & 0xffff) + +struct hisi_acc_qm_sqc { + __u16 sqn; +}; + +struct hisi_qm_queue_info { + void *sq_base; + void *cq_base; + void *doorbell_base; + void *dko_base; + __u16 sq_tail_index; + __u16 sq_head_index; + __u16 cq_head_index; + __u16 sqn; + bool cqc_phase; + void *req_cache[QM_Q_DEPTH]; + int is_sq_full; +}; + +int hacc_db(struct hisi_qm_queue_info *q, __u8 cmd, __u16 index, __u8 priority) +{ + void *base = q->doorbell_base; + __u16 sqn = q->sqn; + __u64 doorbell = 0; + + doorbell = (__u64)sqn | ((__u64)cmd << 16); + doorbell |= ((__u64)index | ((__u64)priority << 16)) << 32; + + *((__u64 *)base) = doorbell; + + return 0; +} + +static int hisi_qm_fill_sqe(void *msg, struct hisi_qm_queue_info *info, __u16 i) +{ + struct hisi_qm_msg *sqe = (struct hisi_qm_msg *)info->sq_base + i; + + memcpy((void *)sqe, msg, sizeof(struct hisi_qm_msg)); + assert(!info->req_cache[i]); + info->req_cache[i] = msg; + + return 0; +} + +static int hisi_qm_recv_sqe(struct hisi_qm_msg *sqe, + struct hisi_qm_queue_info *info, __u16 i) +{ + __u32 status = sqe->dw3 & 0xff; + __u32 type = sqe->dw9 & 0xff; + + if (status != 0 && status != 0x0d) { + fprintf(stderr, "bad status (s=%d, t=%d)\n", status, type); + return -EIO; + } + + assert(info->req_cache[i]); + memcpy((void *)info->req_cache[i], sqe, sizeof(struct hisi_qm_msg)); + return 0; +} + +int hisi_qm_set_queue_dio(struct wd_queue *q) +{ + struct hisi_qm_queue_info *info; + void *vaddr; + int ret; + + alloc_obj(info); + if (!info) + return -1; + + q->priv = info; + + vaddr = wd_drv_mmap(q, QM_DUS_SIZE, QM_DUS_START); + if (vaddr <= 0) { + ret = (intptr_t)vaddr; + goto err_with_info; + } + info->sq_base = vaddr; + info->cq_base = vaddr + QM_SQE_SIZE * QM_Q_DEPTH; + + vaddr = wd_drv_mmap(q, QM_DOORBELL_SIZE, QM_DOORBELL_START); + if (vaddr <= 0) { + ret = (intptr_t)vaddr; + goto err_with_dus; + } + info->doorbell_base = vaddr + QM_DOORBELL_OFFSET; + info->sq_tail_index = 0; + info->sq_head_index = 0; + info->cq_head_index = 0; + info->cqc_phase = 1; + info->is_sq_full = 0; + + vaddr = wd_drv_mmap(q, QM_DKO_SIZE, QM_DKO_START); + if (vaddr <= 0) { + ret = (intptr_t)vaddr; + goto err_with_db; + } + info->dko_base = vaddr; + + return 0; + +err_with_db: + munmap(info->doorbell_base - QM_DOORBELL_OFFSET, QM_DOORBELL_SIZE); +err_with_dus: + munmap(info->sq_base, QM_DUS_SIZE); +err_with_info: + free(info); + return ret; +} + +void hisi_qm_unset_queue_dio(struct wd_queue *q) +{ + struct hisi_qm_queue_info *info = (struct hisi_qm_queue_info *)q->priv; + + munmap(info->dko_base, QM_DKO_SIZE); + munmap(info->doorbell_base - QM_DOORBELL_OFFSET, QM_DOORBELL_SIZE); + munmap(info->sq_base, QM_DUS_SIZE); + free(info); + q->priv = NULL; +} + +int hisi_qm_add_to_dio_q(struct wd_queue *q, void *req) +{ + struct hisi_qm_queue_info *info = (struct hisi_qm_queue_info *)q->priv; + __u16 i; + + if (info->is_sq_full) + return -EBUSY; + + i = info->sq_tail_index; + + hisi_qm_fill_sqe(req, q->priv, i); + + mb(); /* make sure the request is all in memory before doorbell*/ + fprintf(stderr, "fill sqe\n"); + + if (i == (QM_Q_DEPTH - 1)) + i = 0; + else + i++; + + hacc_db(info, DOORBELL_CMD_SQ, i, 0); + fprintf(stderr, "db\n"); + + info->sq_tail_index = i; + + if (i == info->sq_head_index) + info->is_sq_full = 1; + + return 0; +} + +int hisi_qm_get_from_dio_q(struct wd_queue *q, void **resp) +{ + struct hisi_qm_queue_info *info = (struct hisi_qm_queue_info *)q->priv; + __u16 i = info->cq_head_index; + struct cqe *cq_base = info->cq_base; + struct hisi_qm_msg *sq_base = info->sq_base; + struct cqe *cqe = cq_base + i; + struct hisi_qm_msg *sqe; + int ret; + + if (info->cqc_phase == CQE_PHASE(cqe)) { + sqe = sq_base + CQE_SQ_HEAD_INDEX(cqe); + ret = hisi_qm_recv_sqe(sqe, info, i); + if (ret < 0) + return -EIO; + + if (info->is_sq_full) + info->is_sq_full = 0; + } else { + return -EAGAIN; + } + + *resp = info->req_cache[i]; + info->req_cache[i] = NULL; + + if (i == (QM_Q_DEPTH - 1)) { + info->cqc_phase = !(info->cqc_phase); + i = 0; + } else + i++; + + hacc_db(info, DOORBELL_CMD_CQ, i, 0); + + info->cq_head_index = i; + info->sq_head_index = i; + + + return ret; +} + +void *hisi_qm_preserve_mem(struct wd_queue *q, size_t size) +{ + void *mem = wd_drv_mmap(q, size, QM_SS_START); + + if (mem == MAP_FAILED) + return NULL; + else + return mem; +} diff --git a/samples/warpdrive/drv/hisi_qm_udrv.h b/samples/warpdrive/drv/hisi_qm_udrv.h new file mode 100644 index 000000000000..694eb4dd65de --- /dev/null +++ b/samples/warpdrive/drv/hisi_qm_udrv.h @@ -0,0 +1,57 @@ +// SPDX-License-Identifier: GPL-2.0 +#ifndef __HZIP_DRV_H__ +#define __HZIP_DRV_H__ + +#include <linux/types.h> +#include "../wd.h" +#include "../../drivers/crypto/hisilicon/qm_usr_if.h" + +/* this is unnecessary big, the hardware should optimize it */ +struct hisi_qm_msg { + __u32 consumed; + __u32 produced; + __u32 comp_date_length; + __u32 dw3; + __u32 input_date_length; + __u32 lba_l; + __u32 lba_h; + __u32 dw7; + __u32 dw8; + __u32 dw9; + __u32 dw10; + __u32 priv_info; + __u32 dw12; + __u32 tag; + __u32 dest_avail_out; + __u32 rsvd0; + __u32 comp_head_addr_l; + __u32 comp_head_addr_h; + __u32 source_addr_l; + __u32 source_addr_h; + __u32 dest_addr_l; + __u32 dest_addr_h; + __u32 stream_ctx_addr_l; + __u32 stream_ctx_addr_h; + __u32 cipher_key1_addr_l; + __u32 cipher_key1_addr_h; + __u32 cipher_key2_addr_l; + __u32 cipher_key2_addr_h; + __u32 rsvd1[4]; +}; + +int hisi_qm_set_queue_dio(struct wd_queue *q); +void hisi_qm_unset_queue_dio(struct wd_queue *q); +int hisi_qm_add_to_dio_q(struct wd_queue *q, void *req); +int hisi_qm_get_from_dio_q(struct wd_queue *q, void **resp); +void *hisi_qm_preserve_mem(struct wd_queue *q, size_t size); + +#define QM_DOORBELL_SIZE (QM_DOORBELL_PAGE_NR * PAGE_SIZE) +#define QM_DKO_SIZE (QM_DKO_PAGE_NR * PAGE_SIZE) +#define QM_DUS_SIZE (QM_DUS_PAGE_NR * PAGE_SIZE) + +#define QM_DOORBELL_START 0 +#define QM_DKO_START (QM_DOORBELL_START + QM_DOORBELL_SIZE) +#define QM_DUS_START (QM_DKO_START + QM_DKO_SIZE) +#define QM_SS_START (QM_DUS_START + QM_DUS_SIZE) + +#endif diff --git a/samples/warpdrive/drv/wd_drv.h b/samples/warpdrive/drv/wd_drv.h new file mode 100644 index 000000000000..66fa8d889e70 --- /dev/null +++ b/samples/warpdrive/drv/wd_drv.h @@ -0,0 +1,19 @@ +#ifndef __WD_DRV_H +#define __WD_DRV_H + +#include "wd.h" + +#ifndef PAGE_SHIFT +#define PAGE_SHIFT 12 +#endif + +#ifndef PAGE_SIZE +#define PAGE_SIZE (1 << PAGE_SHIFT) +#endif + +static inline void *wd_drv_mmap(struct wd_queue *q, size_t size, size_t off) +{ + return mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, q->fd, off); +} + +#endif diff --git a/samples/warpdrive/test/Makefile.am b/samples/warpdrive/test/Makefile.am new file mode 100644 index 000000000000..ad80e80a47d7 --- /dev/null +++ b/samples/warpdrive/test/Makefile.am @@ -0,0 +1,7 @@ +AM_CFLAGS=-Wall -O0 -fno-strict-aliasing + +bin_PROGRAMS=test_hisi_zip + +test_hisi_zip_SOURCES=test_hisi_zip.c + +test_hisi_zip_LDADD=../.libs/libwd.a diff --git a/samples/warpdrive/test/test_hisi_zip.c b/samples/warpdrive/test/test_hisi_zip.c new file mode 100644 index 000000000000..5e636482d318 --- /dev/null +++ b/samples/warpdrive/test/test_hisi_zip.c @@ -0,0 +1,150 @@ +// SPDX-License-Identifier: GPL-2.0+ +#include <stdio.h> +#include <string.h> +#include <sys/mman.h> +#include <sys/time.h> +#include <unistd.h> +#include "../wd.h" +#include "../drv/hisi_qm_udrv.h" + +#if defined(MSDOS) || defined(OS2) || defined(WIN32) || defined(__CYGWIN__) +# include <fcntl.h> +# include <io.h> +# define SET_BINARY_MODE(file) setmode(fileno(file), O_BINARY) +#else +# define SET_BINARY_MODE(file) +#endif + +#define SYS_ERR_COND(cond, msg) \ +do { \ + if (cond) { \ + perror(msg); \ + exit(EXIT_FAILURE); \ + } \ +} while (0) + +#define ZLIB 0 +#define GZIP 1 + +int hizip_deflate(FILE *source, FILE *dest, int type) +{ + struct hisi_qm_msg *msg, *recv_msg; + struct wd_queue q; + __u64 in, out; + void *a; + char *src, *dst; + int ret, total_len, output_num, fd; + size_t sz; + + q.dev_path = "/dev/ua1"; + strncpy(q.hw_type, "hisi_qm_v1", PATH_STR_SIZE); + ret = wd_request_queue(&q); + SYS_ERR_COND(ret, "wd_request_queue"); + + fd = fileno(source); + struct stat s; + + if (fstat(fd, &s) < 0) + SYS_ERR_COND(-1, "fstat"); + total_len = s.st_size; + + SYS_ERR_COND(!total_len, "input file length zero"); + + SYS_ERR_COND(total_len > 16 * 1024 * 1024, + "totoal_len > 16MB)!"); + + a = wd_reserve_memory(&q, total_len * 2); + SYS_ERR_COND(!a, "memory reserved!"); + + fprintf(stderr, "a=%lx\n", (unsigned long)a); + memset(a, 0, total_len * 2); + + src = (char *)a; + dst = (char *)a + total_len; + + sz = fread(src, 1, total_len, source); + SYS_ERR_COND(sz != total_len, "read fail"); + + msg = malloc(sizeof(*msg)); + SYS_ERR_COND(!msg, "alloc msg"); + memset((void *)msg, 0, sizeof(*msg)); + msg->input_date_length = total_len; + if (type == ZLIB) + msg->dw9 = 2; + else + msg->dw9 = 3; + msg->dest_avail_out = 0x800000; + + in = (__u64)src; + out = (__u64)dst; + + msg->source_addr_l = in & 0xffffffff; + msg->source_addr_h = in >> 32; + msg->dest_addr_l = out & 0xffffffff; + msg->dest_addr_h = out >> 32; + + ret = wd_send(&q, msg); + if (ret == -EBUSY) { + usleep(1); + goto recv_again; + } + SYS_ERR_COND(ret, "send"); + +recv_again: + ret = wd_recv(&q, (void **)&recv_msg); + SYS_ERR_COND(ret == -EIO, "wd_recv"); + + if (ret == -EAGAIN) + goto recv_again; + + output_num = recv_msg->produced; + /* add zlib compress head and write head + compressed date to a file */ + char zip_head[2] = {0x78, 0x9c}; + + fwrite(zip_head, 1, 2, dest); + fwrite((char *)out, 1, output_num, dest); + fclose(dest); + free(msg); + wd_release_queue(&q); + return 0; +} + +int main(int argc, char *argv[]) +{ + int alg_type = 0; + + /* avoid end-of-line conversions */ + SET_BINARY_MODE(stdin); + SET_BINARY_MODE(stdout); + + if (!argv[1]) { + fputs("<<use ./test_hisi_zip -h get more details>>\n", stderr); + goto EXIT; + } + + if (!strcmp(argv[1], "-z")) + alg_type = ZLIB; + else if (!strcmp(argv[1], "-g")) { + alg_type = GZIP; + } else if (!strcmp(argv[1], "-h")) { + fputs("[version]:1.0.2\n", stderr); + fputs("[usage]: ./test_hisi_zip [type] <src_file> dest_file\n", + stderr); + fputs(" [type]:\n", stderr); + fputs(" -z = zlib\n", stderr); + fputs(" -g = gzip\n", stderr); + fputs(" -h = usage\n", stderr); + fputs("Example:\n", stderr); + fputs("./test_hisi_zip -z < test.data > out.data\n", stderr); + goto EXIT; + } else { + fputs("Unknown option\n", stderr); + fputs("<<use ./test_comp_iommu -h get more details>>\n", + stderr); + goto EXIT; + } + + hizip_deflate(stdin, stdout, alg_type); +EXIT: + return EXIT_SUCCESS; +} diff --git a/samples/warpdrive/wd.c b/samples/warpdrive/wd.c new file mode 100644 index 000000000000..559314a13e38 --- /dev/null +++ b/samples/warpdrive/wd.c @@ -0,0 +1,96 @@ +// SPDX-License-Identifier: GPL-2.0 +#include "config.h" +#include <stdlib.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/queue.h> +#include <fcntl.h> +#include <sys/ioctl.h> +#include <errno.h> +#include <sys/mman.h> +#include <string.h> +#include <assert.h> +#include <dirent.h> +#include <sys/poll.h> +#include "wd.h" +#include "wd_adapter.h" + +int wd_request_queue(struct wd_queue *q) +{ + int ret; + + q->fd = open(q->dev_path, O_RDWR | O_CLOEXEC); + if (q->fd == -1) + return -ENODEV; + + ret = drv_open(q); + if (ret) + goto err_with_fd; + + return 0; + +err_with_fd: + close(q->fd); + return ret; +} + +void wd_release_queue(struct wd_queue *q) +{ + drv_close(q); + close(q->fd); +} + +int wd_send(struct wd_queue *q, void *req) +{ + return drv_send(q, req); +} + +int wd_recv(struct wd_queue *q, void **resp) +{ + return drv_recv(q, resp); +} + +static int wd_wait(struct wd_queue *q, __u16 ms) +{ + struct pollfd fds[1]; + int ret; + + fds[0].fd = q->fd; + fds[0].events = POLLIN; + ret = poll(fds, 1, ms); + if (ret == -1) + return -errno; + + return 0; +} + +int wd_recv_sync(struct wd_queue *q, void **resp, __u16 ms) +{ + int ret; + + while (1) { + ret = wd_recv(q, resp); + if (ret == -EBUSY) { + ret = wd_wait(q, ms); + if (ret) + return ret; + } else + return ret; + } +} + +void wd_flush(struct wd_queue *q) +{ + drv_flush(q); +} + +void *wd_reserve_memory(struct wd_queue *q, size_t size) +{ + return drv_reserve_mem(q, size); +} + +int wd_share_preserved_memory(struct wd_queue *q, struct wd_queue *target_q) +{ + return ioctl(q->fd, UACCE_CMD_SHARE_SVAS, target_q->fd); +} diff --git a/samples/warpdrive/wd.h b/samples/warpdrive/wd.h new file mode 100644 index 000000000000..4c0ecfebdf14 --- /dev/null +++ b/samples/warpdrive/wd.h @@ -0,0 +1,97 @@ +// SPDX-License-Identifier: GPL-2.0 +#ifndef __WD_H +#define __WD_H +#include <stdlib.h> +#include <errno.h> +#include <stdio.h> +#include <string.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <stdint.h> +#include <unistd.h> +#include <limits.h> +#include "../../include/uapi/linux/uacce.h" + +#define SYS_VAL_SIZE 16 +#define PATH_STR_SIZE 256 +#define WD_NAME_SIZE 64 + +typedef int bool; + +#ifndef true +#define true 1 +#endif + +#ifndef false +#define false 0 +#endif + +#ifndef WD_ERR +#define WD_ERR(format, args...) fprintf(stderr, format, ##args) +#endif + +#if defined(__AARCH64_CMODEL_SMALL__) && __AARCH64_CMODEL_SMALL__ + +#define dsb(opt) asm volatile("dsb " #opt : : : "memory") +#define rmb() dsb(ld) +#define wmb() dsb(st) +#define mb() dsb(sy) + +#else + +#define rmb() +#define wmb() +#define mb() +#error "no platform mb, define one before compiling" + +#endif + +static inline void wd_reg_write(void *reg_addr, uint32_t value) +{ + *((volatile uint32_t *)reg_addr) = value; + wmb(); +} + +static inline uint32_t wd_reg_read(void *reg_addr) +{ + uint32_t temp; + + temp = *((volatile uint32_t *)reg_addr); + rmb(); + + return temp; +} + +#define WD_CAPA_PRIV_DATA_SIZE 64 + +#define alloc_obj(objp) do { \ + objp = malloc(sizeof(*objp)); \ + memset(objp, 0, sizeof(*objp)); \ +} while (0) + +#define free_obj(objp) do { \ + if (objp) \ + free(objp); \ +} while (0) + +struct wd_queue { + char hw_type[PATH_STR_SIZE]; + int hw_type_id; + void *priv; /* private data used by the drv layer */ + int fd; + int iommu_type; + char *dev_path; +}; + +extern int wd_request_queue(struct wd_queue *q); +extern void wd_release_queue(struct wd_queue *q); +extern int wd_send(struct wd_queue *q, void *req); +extern int wd_recv(struct wd_queue *q, void **resp); +extern void wd_flush(struct wd_queue *q); +extern int wd_recv_sync(struct wd_queue *q, void **resp, __u16 ms); +extern void *wd_reserve_memory(struct wd_queue *q, size_t size); +extern int wd_share_reserved_memory(struct wd_queue *q, + struct wd_queue *target_q); + +#endif diff --git a/samples/warpdrive/wd_adapter.c b/samples/warpdrive/wd_adapter.c new file mode 100644 index 000000000000..5af7254c37a4 --- /dev/null +++ b/samples/warpdrive/wd_adapter.c @@ -0,0 +1,71 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#include <stdio.h> +#include <string.h> +#include <dirent.h> + + +#include "wd_adapter.h" +#include "./drv/hisi_qm_udrv.h" +#include "./drv/wd_drv.h" + +static struct wd_drv_dio_if hw_dio_tbl[] = { { + .hw_type = "hisi_qm_v1", + .ss_offset = QM_SS_START, + .open = hisi_qm_set_queue_dio, + .close = hisi_qm_unset_queue_dio, + .send = hisi_qm_add_to_dio_q, + .recv = hisi_qm_get_from_dio_q, + }, + /* Add other drivers direct IO operations here */ +}; + +/* todo: there should be some stable way to match the device and the driver */ +#define MAX_HW_TYPE (sizeof(hw_dio_tbl) / sizeof(hw_dio_tbl[0])) + +int drv_open(struct wd_queue *q) +{ + int i; + + //todo: try to find another dev if the user driver is not available + for (i = 0; i < MAX_HW_TYPE; i++) { + if (!strcmp(q->hw_type, + hw_dio_tbl[i].hw_type)) { + q->hw_type_id = i; + return hw_dio_tbl[q->hw_type_id].open(q); + } + } + WD_ERR("No matching driver to use!\n"); + errno = ENODEV; + return -ENODEV; +} + +void drv_close(struct wd_queue *q) +{ + hw_dio_tbl[q->hw_type_id].close(q); +} + +int drv_send(struct wd_queue *q, void *req) +{ + return hw_dio_tbl[q->hw_type_id].send(q, req); +} + +int drv_recv(struct wd_queue *q, void **req) +{ + return hw_dio_tbl[q->hw_type_id].recv(q, req); +} + +void drv_flush(struct wd_queue *q) +{ + if (hw_dio_tbl[q->hw_type_id].flush) + hw_dio_tbl[q->hw_type_id].flush(q); +} + +void *drv_reserve_mem(struct wd_queue *q, size_t size) +{ + void *mem = wd_drv_mmap(q, size, hw_dio_tbl[q->hw_type_id].ss_offset); + + if (mem == MAP_FAILED) + return NULL; + + return mem; +} diff --git a/samples/warpdrive/wd_adapter.h b/samples/warpdrive/wd_adapter.h new file mode 100644 index 000000000000..914cba86198c --- /dev/null +++ b/samples/warpdrive/wd_adapter.h @@ -0,0 +1,36 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* the common drv header define the unified interface for wd */ +#ifndef __WD_ADAPTER_H__ +#define __WD_ADAPTER_H__ + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <stdint.h> +#include <unistd.h> +#include <fcntl.h> +#include <sys/stat.h> +#include <sys/ioctl.h> +#include <sys/mman.h> + + +#include "wd.h" + +struct wd_drv_dio_if { + char *hw_type; + size_t ss_offset; + int (*open)(struct wd_queue *q); + void (*close)(struct wd_queue *q); + int (*send)(struct wd_queue *q, void *req); + int (*recv)(struct wd_queue *q, void **req); + void (*flush)(struct wd_queue *q); +}; + +extern int drv_open(struct wd_queue *q); +extern void drv_close(struct wd_queue *q); +extern int drv_send(struct wd_queue *q, void *req); +extern int drv_recv(struct wd_queue *q, void **req); +extern void drv_flush(struct wd_queue *q); +extern void *drv_reserve_mem(struct wd_queue *q, size_t size); + +#endif -- 2.17.1