From: Kenneth Lee <liguo...@hisilicon.com>

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 <xuza...@huawei.com>
Signed-off-by: Kenneth Lee <liguo...@hisilicon.com>
Signed-off-by: Hao Fang <fangha...@huawei.com>
Signed-off-by: Zhou Wang <wangzh...@hisilicon.com>
---
 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 <liguo...@hisilicon.com>
+Zaibo Xu <xuza...@huawei.com>
+Zhou Wang <wangzh...@hisilicon.com>
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], [liguo...@hisilicon.com])
+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

Reply via email to