UADK wrapper for zlib.
Signed-off-by: Yang Shen shenyang39@huawei.com --- Makefile.am | 2 +- wd_zlibwrapper.c | 472 +++++++++++++++++++++++++++++++++++++++++++++++ wd_zlibwrapper.h | 87 +++++++++ 3 files changed, 560 insertions(+), 1 deletion(-) create mode 100644 wd_zlibwrapper.c create mode 100644 wd_zlibwrapper.h
diff --git a/Makefile.am b/Makefile.am index 9b27706..43c18c7 100644 --- a/Makefile.am +++ b/Makefile.am @@ -57,7 +57,7 @@ libwd_la_SOURCES=wd.c wd_mempool.c wd.h \ v1/drv/hisi_rng_udrv.c v1/drv/hisi_rng_udrv.h
libwd_comp_la_SOURCES=wd_comp.c wd_comp.h wd_comp_drv.h wd_util.c wd_util.h \ - wd_sched.c wd_sched.h + wd_sched.c wd_sched.h wd_zlibwrapper.c wd_zlibwrapper.h
libhisi_zip_la_SOURCES=drv/hisi_comp.c hisi_comp.h drv/hisi_qm_udrv.c \ hisi_qm_udrv.h wd_comp_drv.h diff --git a/wd_zlibwrapper.c b/wd_zlibwrapper.c new file mode 100644 index 0000000..3505e7c --- /dev/null +++ b/wd_zlibwrapper.c @@ -0,0 +1,472 @@ +/* SPDX-License-Identifier: Apache-2.0 */ +/* + * Copyright 2020-2021 Huawei Technologies Co.,Ltd. All rights reserved. + */ + +/* === Dependencies === */ +#define _GNU_SOURCE + +#include <errno.h> +#include <stdlib.h> +#include <stdio.h> +#include <stdatomic.h> +#include <sched.h> +#include <numa.h> +#include <sched.h> + +#include "wd.h" +#include "wd_comp.h" +#include "wd_sched.h" +#include "wd_util.h" +#include "wd_zlibwrapper.h" +#include "drv/wd_comp_drv.h" + +/* Allowed flush values; the same as zlib library */ +#define Z_NO_FLUSH 0 +#define Z_PARTIAL_FLUSH 1 +#define Z_SYNC_FLUSH 2 +#define Z_FULL_FLUSH 3 +#define Z_FINISH 4 + +/* + * Return codes for the compression/decompression functions. Negative values + * are errors, positive values are used for special but normal events. + */ +#define Z_OK 0 +#define Z_STREAM_END 1 +#define Z_NEED_DICT 2 +#define Z_ERRNO (-1) +#define Z_STREAM_ERROR (-2) +#define Z_DATA_ERROR (-3) +#define Z_MEM_ERROR (-4) +#define Z_BUF_ERROR (-5) +#define Z_VERSION_ERROR (-6) + +#define Z_DEFLATED 0 +#define MAX_WBITS 0 +#define DEF_MEM_LEVEL 0 +#define Z_DEFAULT_STRATEGY 0 + +#define CTX_SET_NUM 2 +#define CTX_SET_SIZE 32 + +#define max(a, b) ((a) > (b) ? (a) : (b)) + +enum uadk_init_status { + WD_UNINIT, + WD_UNINITING, + WD_INIT, + WD_INITING, +}; + +struct wd_zlibwrapper_config { + struct uacce_dev dev; + struct wd_ctx_config config; + struct wd_sched sched; + int numa_node; + int cpuid; + atomic_int count; + atomic_int status; +}; + +static struct wd_zlibwrapper_config zlib_config = {0}; + +static int wd_zlib_get_dev(void) +{ + struct uacce_dev_list *p, *list; + struct uacce_dev *dev; + int flag = 0; + int dev_ctx; + + list = wd_get_accel_list("zlib"); + if (!list) { + WD_ERR("failed to get devices!\n"); + return Z_STREAM_ERROR; + } + + p = list; + while (p) { + dev = p->dev; + if (dev->numa_id == zlib_config.numa_node) { + dev_ctx = wd_get_avail_ctx(dev); + if (dev_ctx >= CTX_SET_NUM * CTX_SET_SIZE) { + memcpy(&zlib_config.dev, dev, sizeof(*dev)); + flag = 1; + break; + } + } + p = p->next; + } + + wd_free_list_accels(list); + + return flag ? Z_OK : Z_STREAM_ERROR; +} + +static int wd_zlib_request_ctx(struct wd_ctx_config *config) +{ + int ret, i, j; + + ret = wd_zlib_get_dev(); + if (ret < 0) + return ret; + + config->ctx_num = CTX_SET_NUM * CTX_SET_SIZE; + config->ctxs = calloc(CTX_SET_NUM * CTX_SET_SIZE, sizeof(*config->ctxs)); + if (!config->ctxs) { + WD_ERR("failed to alloc ctxs!\n"); + return Z_MEM_ERROR; + } + + for (i = 0; i < CTX_SET_NUM; i++) { + for (j = i * CTX_SET_SIZE; j < (i + 1) * CTX_SET_SIZE; j++) { + config->ctxs[j].ctx = wd_request_ctx(&zlib_config.dev); + if (!config->ctxs[j].ctx) { + WD_ERR("failed to request context #%d!\n", i); + ret = Z_STREAM_ERROR; + goto err_free_ctx; + } + config->ctxs[j].ctx_mode = 1; + config->ctxs[j].op_type = i >> 1; + } + } + + return Z_OK; + +err_free_ctx: + for (i = 0; i < config->ctx_num; i++) + wd_release_ctx(config->ctxs[i].ctx); + free(config->ctxs); + return ret; +} + +static void wd_zlib_release_ctx(struct wd_ctx_config *config) +{ + int i; + + for (i = 0; i < config->ctx_num; i++) + wd_release_ctx(config->ctxs[i].ctx); + free(config->ctxs); +} + +static int wd_zlib_poll_func(__u32 pos, __u32 expect, __u32 *count) +{ + int ret; + + ret = wd_comp_poll_ctx(pos, expect, count); + if (ret < 0) + return ret; + + return Z_OK; +} + +static int wd_zlib_sched_init(struct wd_sched *sched) +{ + struct sched_params param; + int i, ret; + + sched = wd_sched_rr_alloc(SCHED_POLICY_RR, 2, 2, wd_zlib_poll_func); + if (!sched) { + WD_ERR("failed to alloc sched!\n"); + return Z_STREAM_ERROR; + } + + sched->name = "sched_rr"; + + for (i = 0; i < CTX_SET_NUM; i++) { + param.numa_id = zlib_config.numa_node; + param.type = i; + param.begin = i * CTX_SET_SIZE; + param.end = (i + 1) * CTX_SET_SIZE - 1; + ret = wd_sched_rr_instance(sched, ¶m); + if (ret < 0) { + WD_ERR("failed to fill sched region!\n"); + goto err_free_sched; + } + } + + return Z_OK; + +err_free_sched: + wd_sched_rr_release(sched); + return Z_STREAM_ERROR; +} + +static void wd_zlib_sched_uninit(struct wd_sched *sched) +{ + wd_sched_rr_release(sched); +} + +static int wd_zlib_init(void) +{ + struct wd_ctx_config *config = &zlib_config.config; + struct wd_sched *sched = &zlib_config.sched; + atomic_int expect = WD_UNINIT; + int ret, status; + + while ((status = atomic_load(&zlib_config.status)) != WD_INIT) { + if (status == WD_INITING || status == WD_UNINITING) + continue; + if (atomic_compare_exchange_weak(&zlib_config.status, + &expect, WD_INITING)) + goto init; + else + atomic_store(&expect, WD_UNINIT); + } + + return Z_OK; + +init: + ret = sched_getcpu(); + if (ret < 0) { + WD_ERR("failed to get cpu(%d)!\n", ret); + return Z_STREAM_ERROR; + } + zlib_config.cpuid = ret; + + ret = numa_node_of_cpu(zlib_config.cpuid); + if (ret < 0) { + WD_ERR("failed to get numa node(%d)!\n", ret); + return Z_STREAM_ERROR; + } + zlib_config.numa_node = ret; + + ret = wd_zlib_request_ctx(config); + if (ret < 0) + return ret; + + ret = wd_zlib_sched_init(sched); + if (ret < 0) + goto err_free_ctx; + + ret = wd_comp_init(config, sched); + if (ret < 0) { + ret = Z_STREAM_ERROR; + goto err_sched_uninit; + } + + atomic_store(&zlib_config.status, WD_INIT); + + return ret; + +err_sched_uninit: + wd_zlib_sched_uninit(sched); +err_free_ctx: + wd_zlib_release_ctx(config); + atomic_store(&zlib_config.status, WD_UNINIT); + return ret; +} + +static void wd_zlib_uninit(void) +{ + atomic_store(&zlib_config.status, WD_UNINITING); + wd_comp_uninit(); + wd_zlib_sched_uninit(&zlib_config.sched); + wd_zlib_release_ctx(&zlib_config.config); + atomic_store(&zlib_config.status, WD_UNINIT); +} + +static int wd_zlib_analy_alg(int windowbits, int *alg, int *windowsize) +{ + static const int ZLIB_MAX_WBITS = 15; + static const int ZLIB_MIN_WBITS = 8; + static const int GZIP_MAX_WBITS = 31; + static const int GZIP_MIN_WBITS = 24; + static const int DEFLATE_MAX_WBITS = -8; + static const int DEFLATE_MIN_WBITS = -15; + static const int WBINS_ZLIB_4K = 12; + static const int WBINS_GZIP_4K = 27; + static const int WBINS_DEFLATE_4K = -12; + int ret = Z_STREAM_ERROR; + + if ((windowbits >= ZLIB_MIN_WBITS) && (windowbits <= ZLIB_MAX_WBITS)) { + *alg = WD_ZLIB; + *windowsize = max(windowbits - WBINS_ZLIB_4K, WD_COMP_WS_4K); + ret = Z_OK; + } else if ((windowbits >= GZIP_MIN_WBITS) && (windowbits <= GZIP_MAX_WBITS)) { + *alg = WD_GZIP; + *windowsize = max(windowbits - WBINS_GZIP_4K, WD_COMP_WS_4K); + ret = Z_OK; + } else if ((windowbits >= DEFLATE_MIN_WBITS) && (windowbits <= DEFLATE_MAX_WBITS)) { + *alg = WD_DEFLATE; + *windowsize = max(windowbits - WBINS_DEFLATE_4K, WD_COMP_WS_4K); + ret = Z_OK; + } + + return ret; +} + +static int wd_zlib_alloc_sess(z_streamp strm, int level, int windowbits, + enum wd_comp_op_type type) +{ + struct wd_comp_sess_setup setup = {0}; + struct sched_params param = {0}; + int windowsize, alg, ret; + handle_t h_sess; + + ret = wd_zlib_analy_alg(windowbits, &alg, &windowsize); + if (ret < 0) { + WD_ERR("invalid: windowbits is %d!\n", windowbits); + return ret; + } + + setup.comp_lv = level; + setup.alg_type = alg; + setup.win_sz = windowsize; + setup.op_type = type; + param.type = type; + param.numa_id = zlib_config.numa_node; + setup.sched_param = ¶m; + + h_sess = wd_comp_alloc_sess(&setup); + if (!h_sess) { + WD_ERR("failed to alloc comp sess!\n"); + return Z_STREAM_ERROR; + } + strm->reserved = (__u64)h_sess; + + return h_sess; +} + +static void wd_zlib_free_sess(z_streamp strm) +{ + wd_comp_free_sess((handle_t)strm->reserved); +} + +static int wd_zlib_do_request(z_streamp strm, int flush, enum wd_comp_op_type type) +{ + handle_t h_sess = strm->reserved; + struct wd_comp_req req = {0}; + int src_len = strm->avail_in; + int ret; + + if (unlikely(flush != Z_SYNC_FLUSH || flush != Z_FINISH)) + return Z_STREAM_ERROR; + + req.src = (void *)strm->next_in; + req.src_len = strm->avail_in; + req.dst = (void *)strm->next_out; + req.dst_len = strm->avail_out; + req.op_type = type; + req.data_fmt = WD_FLAT_BUF; + req.last = (flush == Z_FINISH) ? 1 : 0; + + ret = wd_do_comp_strm(h_sess, &req); + if (unlikely(ret)) { + WD_ERR("failed to do compress(%d)!\n", ret); + return Z_STREAM_ERROR; + } + + if (flush == Z_FINISH && req.src_len == src_len) + ret = Z_STREAM_END; + + return ret; +} + +/* === Compression === */ +int deflateInit_ (z_streamp strm, int level, const char *version, int stream_size) + +{ + return deflateInit2_(strm, level, Z_DEFLATED, MAX_WBITS, DEF_MEM_LEVEL, + Z_DEFAULT_STRATEGY, version, stream_size); +} + +int deflateInit2_ (z_streamp strm, int level, int method, int windowBits, + int memLevel, int strategy, const char *version, int stream_size) +{ + int ret; + + atomic_fetch_add(&zlib_config.count, 1); + + ret = wd_zlib_init(); + if (unlikely(ret < 0)) { + atomic_fetch_sub(&zlib_config.count, 1); + return ret; + } + + ret = wd_zlib_alloc_sess(strm, level, windowBits, WD_DIR_COMPRESS); + if (unlikely(ret < 0)) + wd_zlib_uninit(); + + return ret; +} + +int deflate (z_streamp strm, int flush) +{ + return wd_zlib_do_request(strm, flush, WD_DIR_COMPRESS); +} + +int deflateReset (z_streamp strm) +{ + wd_comp_reset_sess((handle_t)strm->reserved); + + return Z_OK; +} + +int deflateEnd (z_streamp strm) +{ + int ret, status; + + wd_zlib_free_sess(strm); + + ret = atomic_fetch_sub(&zlib_config.count, 1); + if (ret != 0) + return Z_OK; + + wd_zlib_uninit(); + + return Z_OK; +} + +/* === Decompression === */ +int inflateInit_ (z_streamp strm, const char *version, int stream_size) +{ + return inflateInit2_(strm, MAX_WBITS, version, stream_size); +} + +int inflateInit2_ (z_streamp strm, int windowBits, + const char *version, int stream_size) +{ + int ret; + + atomic_fetch_add(&zlib_config.count, 1); + + ret = wd_zlib_init(); + if (unlikely(ret < 0)) { + atomic_fetch_sub(&zlib_config.count, 1); + return ret; + } + + ret = wd_zlib_alloc_sess(strm, 0, windowBits, WD_DIR_DECOMPRESS); + if (unlikely(ret < 0)) + wd_zlib_uninit(); + + return ret; +} + +int inflate (z_streamp strm, int flush) +{ + return wd_zlib_do_request(strm, flush, WD_DIR_DECOMPRESS); +} + +int inflateReset (z_streamp strm) +{ + wd_comp_reset_sess((handle_t)strm->reserved); + + return Z_OK; +} + +int inflateEnd (z_streamp strm) +{ + int ret, status; + + wd_zlib_free_sess(strm); + + ret = atomic_fetch_sub(&zlib_config.count, 1); + if (ret != 0) + return Z_OK; + + wd_zlib_uninit(); + + return Z_OK; +} diff --git a/wd_zlibwrapper.h b/wd_zlibwrapper.h new file mode 100644 index 0000000..91cc6e1 --- /dev/null +++ b/wd_zlibwrapper.h @@ -0,0 +1,87 @@ +/* SPDX-License-Identifier: Apache-2.0 */ +/* + * Copyright 2020-2021 Huawei Technologies Co.,Ltd. All rights reserved. + */ + +#ifndef UADK_ZLIBWRAPPER_H +#define UADK_ZLIBWRAPPER_H + +#if defined (__cplusplus) +extern "C" { +#endif + +#define ZLIB_VERSION "1.2.11" + +struct internal_state {}; + +typedef void (*alloc_func) (void *opaque, __u32 items, __u32 size); +typedef void (*free_func) (void *opaque, void *address); + +typedef struct z_stream_s { + /* next input byte */ + const __u8 *next_in; + /* number of bytes available at next_in */ + __u32 avail_in; + /* total number of input bytes read so far */ + __u64 total_in; + + /* next output byte will go here */ + __u8 *next_out; + /* remaining free space at next_out */ + __u32 avail_out; + /* total number of bytes output so far */ + __u64 total_out; + + /* last error message, NULL if no error */ + const char *msg; + /* not visible by applications */ + struct internal_state *state; + + /* used to allocate the internal state */ + alloc_func zalloc; + /* used to free the internal state */ + free_func zfree; + /* private data object passed to zalloc and zfree */ + void *opaque; + + /* + * Best guess about the data type: binary or text + * for deflate, or the decoding state for inflate. + */ + int data_type; + /* Adler-32 or CRC-32 value of the uncompressed data */ + __u64 adler; + /* reserved for future use */ + __u64 reserved; +} z_stream; + +typedef z_stream *z_streamp; + +int deflateInit_ (z_streamp strm, int level, const char *version, int stream_size); +int deflateInit2_ (z_streamp strm, int level, int method, int windowBits, + int memLevel, int strategy, const char *version, int stream_size); +int deflate (z_streamp strm, int flush); +int deflateReset (z_streamp strm); +int deflateEnd (z_streamp strm); + +int inflateInit_ (z_streamp strm, const char *version, int stream_size); +int inflateInit2_ (z_streamp strm, int windowBits, + const char *version, int stream_size); +int inflate (z_streamp strm, int flush); +int inflateReset (z_streamp strm); +int inflateEnd (z_streamp strm); + +#define deflateInit(strm, level) \ + deflateInit_((strm), (level), ZLIB_VERSION, (int)sizeof(z_stream)) + +#define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \ + deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\ + (strategy), ZLIB_VERSION, (int)sizeof(z_stream)) + +#define inflateInit(strm) \ + inflateInit_((strm), ZLIB_VERSION, (int)sizeof(z_stream)) + +#define inflateInit2(strm, windowBits) \ + inflateInit2_((strm), (windowBits), ZLIB_VERSION, (int)sizeof(z_stream)) + +#endif /* UADK_ZLIBWRAPPER_H */