mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-09-18 23:09:29 +02:00
This is another run of the Coccinelle script for converting kmalloc() family of allocations to kmalloc_obj() via the existing rules in scripts/coccinelle/api/kmalloc_objs.cocci This catches both the set of kmalloc() uses added since the first kmalloc_obj() conversions in v7.0 and adds a large group missed in the first pass due to Coccinelle not interacting well with the cleanup.h scoped_...() family of macros[1]. I worked around this with spatch's "--macro-file" argument to a file with all the scoped_...() macros mapped to Coccinelle's YACFE_ITERATOR[2] as that was the closest viable control flow indicator I could find. Build tested allmodconfig on x86, arm64, arm, loongarch, mips, powerpc, riscv, and s390 with no new warnings. Link: https://lore.kernel.org/lkml/202609021314.8A9C0B8@keescook/ [1] Link: https://github.com/coccinelle/coccinelle/blob/master/standard.h [2] Signed-off-by: Kees Cook <kees+treewide@kernel.org>
759 lines
19 KiB
C
759 lines
19 KiB
C
// SPDX-License-Identifier: GPL-2.0-only
|
|
/* Copyright(c) 2022 Intel Corporation */
|
|
#include <linux/crypto.h>
|
|
#include <crypto/acompress.h>
|
|
#include <crypto/internal/acompress.h>
|
|
#include <crypto/scatterwalk.h>
|
|
#include <linux/dma-mapping.h>
|
|
#include <linux/workqueue.h>
|
|
#include <linux/zstd.h>
|
|
#include "adf_accel_devices.h"
|
|
#include "adf_common_drv.h"
|
|
#include "adf_dc.h"
|
|
#include "qat_bl.h"
|
|
#include "qat_comp_req.h"
|
|
#include "qat_compression.h"
|
|
#include "qat_algs_send.h"
|
|
#include "qat_comp_zstd_utils.h"
|
|
|
|
#define QAT_ZSTD_SCRATCH_SIZE 524288
|
|
#define QAT_ZSTD_MAX_BLOCK_SIZE 65535
|
|
#define QAT_ZSTD_MAX_CONTENT_SIZE 4096
|
|
#define QAT_LZ4S_MIN_INPUT_SIZE 8192
|
|
#define QAT_LZ4S_MAX_OUTPUT_SIZE QAT_ZSTD_SCRATCH_SIZE
|
|
#define QAT_MAX_SEQUENCES (128 * 1024)
|
|
|
|
static DEFINE_MUTEX(algs_lock);
|
|
static unsigned int active_devs_deflate;
|
|
static unsigned int active_devs_lz4s;
|
|
static unsigned int active_devs_zstd;
|
|
|
|
struct qat_zstd_scratch {
|
|
size_t cctx_buffer_size;
|
|
void *lz4s;
|
|
void *literals;
|
|
void *out_seqs;
|
|
void *workspace;
|
|
ZSTD_CCtx *ctx;
|
|
};
|
|
|
|
static void *qat_zstd_alloc_scratch(void)
|
|
{
|
|
struct qat_zstd_scratch *scratch;
|
|
ZSTD_parameters params;
|
|
size_t cctx_size;
|
|
ZSTD_CCtx *ctx;
|
|
size_t zret;
|
|
int ret;
|
|
|
|
ret = -ENOMEM;
|
|
scratch = kzalloc_obj(*scratch);
|
|
if (!scratch)
|
|
return ERR_PTR(ret);
|
|
|
|
scratch->lz4s = kvmalloc(QAT_ZSTD_SCRATCH_SIZE, GFP_KERNEL);
|
|
if (!scratch->lz4s)
|
|
goto error;
|
|
|
|
scratch->literals = kvmalloc(QAT_ZSTD_SCRATCH_SIZE, GFP_KERNEL);
|
|
if (!scratch->literals)
|
|
goto error;
|
|
|
|
scratch->out_seqs = kvzalloc_objs(ZSTD_Sequence, QAT_MAX_SEQUENCES);
|
|
if (!scratch->out_seqs)
|
|
goto error;
|
|
|
|
params = zstd_get_params(zstd_max_clevel(), QAT_ZSTD_SCRATCH_SIZE);
|
|
cctx_size = zstd_cctx_workspace_bound(¶ms.cParams);
|
|
|
|
scratch->workspace = kvmalloc(cctx_size, GFP_KERNEL | __GFP_ZERO);
|
|
if (!scratch->workspace)
|
|
goto error;
|
|
|
|
ret = -EINVAL;
|
|
ctx = zstd_init_cctx(scratch->workspace, cctx_size);
|
|
if (!ctx)
|
|
goto error;
|
|
|
|
scratch->ctx = ctx;
|
|
scratch->cctx_buffer_size = cctx_size;
|
|
|
|
zret = zstd_cctx_set_param(ctx, ZSTD_c_blockDelimiters, ZSTD_sf_explicitBlockDelimiters);
|
|
if (zstd_is_error(zret))
|
|
goto error;
|
|
|
|
return scratch;
|
|
|
|
error:
|
|
kvfree(scratch->lz4s);
|
|
kvfree(scratch->literals);
|
|
kvfree(scratch->out_seqs);
|
|
kvfree(scratch->workspace);
|
|
kfree(scratch);
|
|
return ERR_PTR(ret);
|
|
}
|
|
|
|
static void qat_zstd_free_scratch(void *ctx)
|
|
{
|
|
struct qat_zstd_scratch *scratch = ctx;
|
|
|
|
if (!scratch)
|
|
return;
|
|
|
|
kvfree(scratch->lz4s);
|
|
kvfree(scratch->literals);
|
|
kvfree(scratch->out_seqs);
|
|
kvfree(scratch->workspace);
|
|
kfree(scratch);
|
|
}
|
|
|
|
static struct crypto_acomp_streams qat_zstd_streams = {
|
|
.alloc_ctx = qat_zstd_alloc_scratch,
|
|
.free_ctx = qat_zstd_free_scratch,
|
|
};
|
|
|
|
enum direction {
|
|
DECOMPRESSION = 0,
|
|
COMPRESSION = 1,
|
|
};
|
|
|
|
struct qat_compression_req;
|
|
|
|
struct qat_callback_params {
|
|
unsigned int produced;
|
|
unsigned int dlen;
|
|
bool plain;
|
|
};
|
|
|
|
struct qat_compression_ctx {
|
|
u8 comp_ctx[QAT_COMP_CTX_SIZE];
|
|
struct qat_compression_instance *inst;
|
|
int (*qat_comp_callback)(struct qat_compression_req *qat_req, void *resp,
|
|
struct qat_callback_params *params);
|
|
struct crypto_acomp *ftfm;
|
|
};
|
|
|
|
struct qat_compression_req {
|
|
u8 req[QAT_COMP_REQ_SIZE];
|
|
struct qat_compression_ctx *qat_compression_ctx;
|
|
struct acomp_req *acompress_req;
|
|
struct qat_request_buffs buf;
|
|
enum direction dir;
|
|
int actual_dlen;
|
|
struct qat_alg_req alg_req;
|
|
};
|
|
|
|
static int qat_alg_send_dc_message(struct qat_compression_req *qat_req,
|
|
struct qat_compression_instance *inst,
|
|
struct crypto_async_request *base)
|
|
{
|
|
struct qat_alg_req *alg_req = &qat_req->alg_req;
|
|
|
|
alg_req->fw_req = (u32 *)&qat_req->req;
|
|
alg_req->tx_ring = inst->dc_tx;
|
|
alg_req->base = base;
|
|
alg_req->backlog = &inst->backlog;
|
|
|
|
return qat_alg_send_message(alg_req);
|
|
}
|
|
|
|
static void qat_comp_generic_callback(struct qat_compression_req *qat_req,
|
|
void *resp)
|
|
{
|
|
struct acomp_req *areq = qat_req->acompress_req;
|
|
struct qat_compression_ctx *ctx = qat_req->qat_compression_ctx;
|
|
struct adf_accel_dev *accel_dev = ctx->inst->accel_dev;
|
|
struct crypto_acomp *tfm = crypto_acomp_reqtfm(areq);
|
|
struct qat_compression_instance *inst = ctx->inst;
|
|
struct qat_callback_params params = { };
|
|
int consumed, produced;
|
|
s8 cmp_err, xlt_err;
|
|
int res = -EBADMSG;
|
|
int status;
|
|
u8 cnv;
|
|
|
|
status = qat_comp_get_cmp_status(resp);
|
|
status |= qat_comp_get_xlt_status(resp);
|
|
cmp_err = qat_comp_get_cmp_err(resp);
|
|
xlt_err = qat_comp_get_xlt_err(resp);
|
|
|
|
consumed = qat_comp_get_consumed_ctr(resp);
|
|
produced = qat_comp_get_produced_ctr(resp);
|
|
|
|
/* Cache parameters for algorithm specific callback */
|
|
params.produced = produced;
|
|
params.dlen = areq->dlen;
|
|
|
|
dev_dbg(&GET_DEV(accel_dev),
|
|
"[%s][%s][%s] slen = %8d dlen = %8d consumed = %8d produced = %8d cmp_err = %3d xlt_err = %3d",
|
|
crypto_tfm_alg_driver_name(crypto_acomp_tfm(tfm)),
|
|
qat_req->dir == COMPRESSION ? "comp " : "decomp",
|
|
status ? "ERR" : "OK ",
|
|
areq->slen, areq->dlen, consumed, produced, cmp_err, xlt_err);
|
|
|
|
if (unlikely(status != ICP_QAT_FW_COMN_STATUS_FLAG_OK)) {
|
|
if (cmp_err == ERR_CODE_OVERFLOW_ERROR || xlt_err == ERR_CODE_OVERFLOW_ERROR)
|
|
res = -E2BIG;
|
|
|
|
areq->dlen = 0;
|
|
goto end;
|
|
}
|
|
|
|
if (qat_req->dir == COMPRESSION) {
|
|
cnv = qat_comp_get_cmp_cnv_flag(resp);
|
|
if (unlikely(!cnv)) {
|
|
dev_err(&GET_DEV(accel_dev),
|
|
"Verified compression not supported\n");
|
|
areq->dlen = 0;
|
|
goto end;
|
|
}
|
|
|
|
if (unlikely(produced > qat_req->actual_dlen)) {
|
|
memset(inst->dc_data->ovf_buff, 0,
|
|
inst->dc_data->ovf_buff_sz);
|
|
dev_dbg(&GET_DEV(accel_dev),
|
|
"Actual buffer overflow: produced=%d, dlen=%d\n",
|
|
produced, qat_req->actual_dlen);
|
|
|
|
res = -E2BIG;
|
|
areq->dlen = 0;
|
|
goto end;
|
|
}
|
|
|
|
params.plain = !!qat_comp_get_cmp_uncomp_flag(resp);
|
|
}
|
|
|
|
res = 0;
|
|
areq->dlen = produced;
|
|
|
|
if (ctx->qat_comp_callback)
|
|
res = ctx->qat_comp_callback(qat_req, resp, ¶ms);
|
|
|
|
end:
|
|
qat_bl_free_bufl(accel_dev, &qat_req->buf);
|
|
acomp_request_complete(areq, res);
|
|
qat_alg_send_backlog(qat_req->alg_req.backlog);
|
|
}
|
|
|
|
void qat_comp_alg_callback(void *resp)
|
|
{
|
|
struct qat_compression_req *qat_req =
|
|
(void *)(__force long)qat_comp_get_opaque(resp);
|
|
|
|
qat_comp_generic_callback(qat_req, resp);
|
|
}
|
|
|
|
static int qat_comp_alg_init_tfm(struct crypto_acomp *acomp_tfm, int alg)
|
|
{
|
|
struct qat_compression_ctx *ctx = acomp_tfm_ctx(acomp_tfm);
|
|
struct crypto_tfm *tfm = crypto_acomp_tfm(acomp_tfm);
|
|
struct qat_compression_instance *inst;
|
|
int node, ret;
|
|
|
|
if (tfm->node == NUMA_NO_NODE)
|
|
node = numa_node_id();
|
|
else
|
|
node = tfm->node;
|
|
|
|
memset(ctx, 0, sizeof(*ctx));
|
|
inst = qat_compression_get_instance_node(node, alg);
|
|
if (!inst)
|
|
return -EINVAL;
|
|
ctx->inst = inst;
|
|
|
|
ret = qat_comp_build_ctx(inst->accel_dev, ctx->comp_ctx, alg);
|
|
if (ret) {
|
|
qat_compression_put_instance(inst);
|
|
memset(ctx, 0, sizeof(*ctx));
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int qat_comp_alg_deflate_init_tfm(struct crypto_acomp *acomp_tfm)
|
|
{
|
|
return qat_comp_alg_init_tfm(acomp_tfm, QAT_DEFLATE);
|
|
}
|
|
|
|
static void qat_comp_alg_exit_tfm(struct crypto_acomp *acomp_tfm)
|
|
{
|
|
struct qat_compression_ctx *ctx = acomp_tfm_ctx(acomp_tfm);
|
|
|
|
qat_compression_put_instance(ctx->inst);
|
|
memset(ctx, 0, sizeof(*ctx));
|
|
}
|
|
|
|
static int qat_comp_alg_compress_decompress(struct acomp_req *areq, enum direction dir,
|
|
unsigned int shdr, unsigned int sftr,
|
|
unsigned int dhdr, unsigned int dftr)
|
|
{
|
|
struct qat_compression_req *qat_req = acomp_request_ctx(areq);
|
|
struct crypto_acomp *acomp_tfm = crypto_acomp_reqtfm(areq);
|
|
struct qat_compression_ctx *ctx = acomp_tfm_ctx(acomp_tfm);
|
|
struct qat_compression_instance *inst = ctx->inst;
|
|
gfp_t f = qat_algs_alloc_flags(&areq->base);
|
|
struct qat_sgl_to_bufl_params params = {0};
|
|
int slen = areq->slen - shdr - sftr;
|
|
int dlen = areq->dlen - dhdr - dftr;
|
|
dma_addr_t sfbuf, dfbuf;
|
|
u8 *req = qat_req->req;
|
|
size_t ovf_buff_sz;
|
|
int ret;
|
|
|
|
params.sskip = shdr;
|
|
params.dskip = dhdr;
|
|
|
|
if (!areq->src || !slen)
|
|
return -EINVAL;
|
|
|
|
if (!areq->dst || !dlen)
|
|
return -EINVAL;
|
|
|
|
if (dir == COMPRESSION) {
|
|
params.extra_dst_buff = inst->dc_data->ovf_buff_p;
|
|
ovf_buff_sz = inst->dc_data->ovf_buff_sz;
|
|
params.sz_extra_dst_buff = ovf_buff_sz;
|
|
}
|
|
|
|
ret = qat_bl_sgl_to_bufl(ctx->inst->accel_dev, areq->src, areq->dst,
|
|
&qat_req->buf, ¶ms, f);
|
|
if (unlikely(ret))
|
|
return ret;
|
|
|
|
sfbuf = qat_req->buf.blp;
|
|
dfbuf = qat_req->buf.bloutp;
|
|
qat_req->qat_compression_ctx = ctx;
|
|
qat_req->acompress_req = areq;
|
|
qat_req->dir = dir;
|
|
|
|
if (dir == COMPRESSION) {
|
|
qat_req->actual_dlen = dlen;
|
|
dlen += ovf_buff_sz;
|
|
qat_comp_create_compression_req(ctx->comp_ctx, req,
|
|
(u64)(__force long)sfbuf, slen,
|
|
(u64)(__force long)dfbuf, dlen,
|
|
(u64)(__force long)qat_req);
|
|
} else {
|
|
qat_comp_create_decompression_req(ctx->comp_ctx, req,
|
|
(u64)(__force long)sfbuf, slen,
|
|
(u64)(__force long)dfbuf, dlen,
|
|
(u64)(__force long)qat_req);
|
|
}
|
|
|
|
ret = qat_alg_send_dc_message(qat_req, inst, &areq->base);
|
|
if (ret == -ENOSPC)
|
|
qat_bl_free_bufl(inst->accel_dev, &qat_req->buf);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int qat_comp_alg_compress(struct acomp_req *req)
|
|
{
|
|
return qat_comp_alg_compress_decompress(req, COMPRESSION, 0, 0, 0, 0);
|
|
}
|
|
|
|
static int qat_comp_alg_decompress(struct acomp_req *req)
|
|
{
|
|
return qat_comp_alg_compress_decompress(req, DECOMPRESSION, 0, 0, 0, 0);
|
|
}
|
|
|
|
static int qat_comp_alg_zstd_decompress(struct acomp_req *req)
|
|
{
|
|
struct crypto_acomp *acomp_tfm = crypto_acomp_reqtfm(req);
|
|
struct qat_compression_ctx *ctx = acomp_tfm_ctx(acomp_tfm);
|
|
struct acomp_req *nreq = acomp_request_ctx(req);
|
|
zstd_frame_header header;
|
|
void *buffer;
|
|
size_t zret;
|
|
int ret;
|
|
|
|
buffer = kmap_local_page(sg_page(req->src)) + req->src->offset;
|
|
zret = zstd_get_frame_header(&header, buffer, req->src->length);
|
|
kunmap_local(buffer);
|
|
if (zret) {
|
|
dev_err(&GET_DEV(ctx->inst->accel_dev),
|
|
"ZSTD-compressed data has an incomplete frame header\n");
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (header.windowSize > QAT_ZSTD_MAX_BLOCK_SIZE ||
|
|
header.frameContentSize >= QAT_ZSTD_MAX_CONTENT_SIZE) {
|
|
dev_dbg(&GET_DEV(ctx->inst->accel_dev), "Window size=0x%llx\n",
|
|
header.windowSize);
|
|
|
|
memcpy(nreq, req, sizeof(*req));
|
|
acomp_request_set_tfm(nreq, ctx->ftfm);
|
|
|
|
ret = crypto_acomp_decompress(nreq);
|
|
req->dlen = nreq->dlen;
|
|
|
|
return ret;
|
|
}
|
|
|
|
return qat_comp_alg_compress_decompress(req, DECOMPRESSION, 0, 0, 0, 0);
|
|
}
|
|
|
|
static int qat_comp_lz4s_zstd_callback(struct qat_compression_req *qat_req, void *resp,
|
|
struct qat_callback_params *params)
|
|
{
|
|
struct qat_compression_ctx *qat_ctx = qat_req->qat_compression_ctx;
|
|
struct acomp_req *areq = qat_req->acompress_req;
|
|
struct qat_zstd_scratch *scratch;
|
|
struct crypto_acomp_stream *s;
|
|
unsigned int lit_len = 0;
|
|
ZSTD_Sequence *out_seqs;
|
|
void *lz4s, *zstd;
|
|
size_t comp_size;
|
|
ZSTD_CCtx *ctx;
|
|
void *literals;
|
|
int seq_count;
|
|
int ret = 0;
|
|
|
|
if (params->produced + QAT_ZSTD_LIT_COPY_LEN > QAT_ZSTD_SCRATCH_SIZE) {
|
|
dev_dbg(&GET_DEV(qat_ctx->inst->accel_dev),
|
|
"LZ4s-ZSTD: produced size (%u) + COPY_SIZE > QAT_ZSTD_SCRATCH_SIZE (%u)\n",
|
|
params->produced, QAT_ZSTD_SCRATCH_SIZE);
|
|
areq->dlen = 0;
|
|
return -E2BIG;
|
|
}
|
|
|
|
s = crypto_acomp_lock_stream_bh(&qat_zstd_streams);
|
|
scratch = s->ctx;
|
|
|
|
lz4s = scratch->lz4s;
|
|
zstd = lz4s; /* Output buffer is same as lz4s */
|
|
out_seqs = scratch->out_seqs;
|
|
ctx = scratch->ctx;
|
|
literals = scratch->literals;
|
|
|
|
if (likely(!params->plain)) {
|
|
if (likely(sg_nents(areq->dst) == 1)) {
|
|
zstd = sg_virt(areq->dst);
|
|
lz4s = zstd;
|
|
} else {
|
|
memcpy_from_sglist(lz4s, areq->dst, 0, params->produced);
|
|
}
|
|
|
|
seq_count = qat_alg_dec_lz4s(out_seqs, QAT_MAX_SEQUENCES, lz4s,
|
|
params->produced, literals, &lit_len);
|
|
if (seq_count < 0) {
|
|
ret = seq_count;
|
|
comp_size = 0;
|
|
goto out;
|
|
}
|
|
} else {
|
|
out_seqs[0].litLength = areq->slen;
|
|
out_seqs[0].offset = 0;
|
|
out_seqs[0].matchLength = 0;
|
|
|
|
seq_count = 1;
|
|
}
|
|
|
|
comp_size = zstd_compress_sequences_and_literals(ctx, zstd, params->dlen,
|
|
out_seqs, seq_count,
|
|
literals, lit_len,
|
|
QAT_ZSTD_SCRATCH_SIZE,
|
|
areq->slen);
|
|
if (zstd_is_error(comp_size)) {
|
|
if (comp_size == ZSTD_error_cannotProduce_uncompressedBlock)
|
|
ret = -E2BIG;
|
|
else
|
|
ret = -EOPNOTSUPP;
|
|
|
|
comp_size = 0;
|
|
goto out;
|
|
}
|
|
|
|
if (comp_size > params->dlen) {
|
|
dev_dbg(&GET_DEV(qat_ctx->inst->accel_dev),
|
|
"LZ4s-ZSTD: compressed_size (%u) > output buffer size (%u)\n",
|
|
(unsigned int)comp_size, params->dlen);
|
|
ret = -EOVERFLOW;
|
|
goto out;
|
|
}
|
|
|
|
if (unlikely(sg_nents(areq->dst) != 1))
|
|
memcpy_to_sglist(areq->dst, 0, zstd, comp_size);
|
|
|
|
out:
|
|
areq->dlen = comp_size;
|
|
crypto_acomp_unlock_stream_bh(s);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int qat_comp_alg_lz4s_zstd_init_tfm(struct crypto_acomp *acomp_tfm)
|
|
{
|
|
struct qat_compression_ctx *ctx = acomp_tfm_ctx(acomp_tfm);
|
|
struct crypto_tfm *tfm = crypto_acomp_tfm(acomp_tfm);
|
|
int reqsize;
|
|
int ret;
|
|
|
|
/* qat_comp_alg_init_tfm() wipes out the ctx */
|
|
ret = qat_comp_alg_init_tfm(acomp_tfm, QAT_LZ4S);
|
|
if (ret)
|
|
return ret;
|
|
|
|
ctx->ftfm = crypto_alloc_acomp_node("zstd", 0, CRYPTO_ALG_NEED_FALLBACK,
|
|
tfm->node);
|
|
if (IS_ERR(ctx->ftfm)) {
|
|
qat_comp_alg_exit_tfm(acomp_tfm);
|
|
return PTR_ERR(ctx->ftfm);
|
|
}
|
|
|
|
reqsize = max(sizeof(struct qat_compression_req),
|
|
sizeof(struct acomp_req) + crypto_acomp_reqsize(ctx->ftfm));
|
|
|
|
acomp_tfm->reqsize = reqsize;
|
|
|
|
ctx->qat_comp_callback = qat_comp_lz4s_zstd_callback;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int qat_comp_alg_zstd_init_tfm(struct crypto_acomp *acomp_tfm)
|
|
{
|
|
struct qat_compression_ctx *ctx = acomp_tfm_ctx(acomp_tfm);
|
|
struct crypto_tfm *tfm = crypto_acomp_tfm(acomp_tfm);
|
|
int reqsize;
|
|
int ret;
|
|
|
|
/* qat_comp_alg_init_tfm() wipes out the ctx */
|
|
ret = qat_comp_alg_init_tfm(acomp_tfm, QAT_ZSTD);
|
|
if (ret)
|
|
return ret;
|
|
|
|
ctx->ftfm = crypto_alloc_acomp_node("zstd", 0, CRYPTO_ALG_NEED_FALLBACK,
|
|
tfm->node);
|
|
if (IS_ERR(ctx->ftfm)) {
|
|
qat_comp_alg_exit_tfm(acomp_tfm);
|
|
return PTR_ERR(ctx->ftfm);
|
|
}
|
|
|
|
reqsize = max(sizeof(struct qat_compression_req),
|
|
sizeof(struct acomp_req) + crypto_acomp_reqsize(ctx->ftfm));
|
|
|
|
acomp_tfm->reqsize = reqsize;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void qat_comp_alg_zstd_exit_tfm(struct crypto_acomp *acomp_tfm)
|
|
{
|
|
struct qat_compression_ctx *ctx = acomp_tfm_ctx(acomp_tfm);
|
|
|
|
if (ctx->ftfm)
|
|
crypto_free_acomp(ctx->ftfm);
|
|
|
|
qat_comp_alg_exit_tfm(acomp_tfm);
|
|
}
|
|
|
|
static int qat_comp_alg_lz4s_zstd_compress(struct acomp_req *req)
|
|
{
|
|
struct crypto_acomp *acomp_tfm = crypto_acomp_reqtfm(req);
|
|
struct qat_compression_ctx *ctx = acomp_tfm_ctx(acomp_tfm);
|
|
struct acomp_req *nreq = acomp_request_ctx(req);
|
|
int ret;
|
|
|
|
if (req->slen >= QAT_LZ4S_MIN_INPUT_SIZE && req->dlen >= QAT_LZ4S_MIN_INPUT_SIZE &&
|
|
req->slen <= QAT_LZ4S_MAX_OUTPUT_SIZE && req->dlen <= QAT_LZ4S_MAX_OUTPUT_SIZE)
|
|
return qat_comp_alg_compress(req);
|
|
|
|
memcpy(nreq, req, sizeof(*req));
|
|
acomp_request_set_tfm(nreq, ctx->ftfm);
|
|
|
|
ret = crypto_acomp_compress(nreq);
|
|
req->dlen = nreq->dlen;
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int qat_comp_alg_sw_decompress(struct acomp_req *req)
|
|
{
|
|
struct crypto_acomp *acomp_tfm = crypto_acomp_reqtfm(req);
|
|
struct qat_compression_ctx *ctx = acomp_tfm_ctx(acomp_tfm);
|
|
struct acomp_req *nreq = acomp_request_ctx(req);
|
|
int ret;
|
|
|
|
memcpy(nreq, req, sizeof(*req));
|
|
acomp_request_set_tfm(nreq, ctx->ftfm);
|
|
|
|
ret = crypto_acomp_decompress(nreq);
|
|
req->dlen = nreq->dlen;
|
|
|
|
return ret;
|
|
}
|
|
|
|
static struct acomp_alg qat_acomp_deflate[] = { {
|
|
.base = {
|
|
.cra_name = "deflate",
|
|
.cra_driver_name = "qat_deflate",
|
|
.cra_priority = 4001,
|
|
.cra_flags = CRYPTO_ALG_ASYNC | CRYPTO_ALG_ALLOCATES_MEMORY,
|
|
.cra_ctxsize = sizeof(struct qat_compression_ctx),
|
|
.cra_reqsize = sizeof(struct qat_compression_req),
|
|
.cra_module = THIS_MODULE,
|
|
},
|
|
.init = qat_comp_alg_deflate_init_tfm,
|
|
.exit = qat_comp_alg_exit_tfm,
|
|
.compress = qat_comp_alg_compress,
|
|
.decompress = qat_comp_alg_decompress,
|
|
}};
|
|
|
|
static struct acomp_alg qat_acomp_zstd_lz4s = {
|
|
.base = {
|
|
.cra_name = "zstd",
|
|
.cra_driver_name = "qat_zstd",
|
|
.cra_priority = 4001,
|
|
.cra_flags = CRYPTO_ALG_ASYNC | CRYPTO_ALG_ALLOCATES_MEMORY |
|
|
CRYPTO_ALG_NEED_FALLBACK,
|
|
.cra_reqsize = sizeof(struct qat_compression_req),
|
|
.cra_ctxsize = sizeof(struct qat_compression_ctx),
|
|
.cra_module = THIS_MODULE,
|
|
},
|
|
.init = qat_comp_alg_lz4s_zstd_init_tfm,
|
|
.exit = qat_comp_alg_zstd_exit_tfm,
|
|
.compress = qat_comp_alg_lz4s_zstd_compress,
|
|
.decompress = qat_comp_alg_sw_decompress,
|
|
};
|
|
|
|
static struct acomp_alg qat_acomp_zstd_native = {
|
|
.base = {
|
|
.cra_name = "zstd",
|
|
.cra_driver_name = "qat_zstd",
|
|
.cra_priority = 4001,
|
|
.cra_flags = CRYPTO_ALG_ASYNC | CRYPTO_ALG_ALLOCATES_MEMORY |
|
|
CRYPTO_ALG_NEED_FALLBACK,
|
|
.cra_reqsize = sizeof(struct qat_compression_req),
|
|
.cra_ctxsize = sizeof(struct qat_compression_ctx),
|
|
.cra_module = THIS_MODULE,
|
|
},
|
|
.init = qat_comp_alg_zstd_init_tfm,
|
|
.exit = qat_comp_alg_zstd_exit_tfm,
|
|
.compress = qat_comp_alg_compress,
|
|
.decompress = qat_comp_alg_zstd_decompress,
|
|
};
|
|
|
|
static int qat_comp_algs_register_deflate(void)
|
|
{
|
|
int ret = 0;
|
|
|
|
mutex_lock(&algs_lock);
|
|
if (++active_devs_deflate == 1) {
|
|
ret = crypto_register_acomps(qat_acomp_deflate,
|
|
ARRAY_SIZE(qat_acomp_deflate));
|
|
if (ret)
|
|
active_devs_deflate--;
|
|
}
|
|
mutex_unlock(&algs_lock);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static void qat_comp_algs_unregister_deflate(void)
|
|
{
|
|
mutex_lock(&algs_lock);
|
|
if (--active_devs_deflate == 0)
|
|
crypto_unregister_acomps(qat_acomp_deflate, ARRAY_SIZE(qat_acomp_deflate));
|
|
mutex_unlock(&algs_lock);
|
|
}
|
|
|
|
static int qat_comp_algs_register_lz4s(void)
|
|
{
|
|
int ret = 0;
|
|
|
|
mutex_lock(&algs_lock);
|
|
if (++active_devs_lz4s == 1) {
|
|
ret = crypto_acomp_alloc_streams(&qat_zstd_streams);
|
|
if (ret) {
|
|
active_devs_lz4s--;
|
|
goto unlock;
|
|
}
|
|
|
|
ret = crypto_register_acomp(&qat_acomp_zstd_lz4s);
|
|
if (ret) {
|
|
crypto_acomp_free_streams(&qat_zstd_streams);
|
|
active_devs_lz4s--;
|
|
}
|
|
}
|
|
unlock:
|
|
mutex_unlock(&algs_lock);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static void qat_comp_algs_unregister_lz4s(void)
|
|
{
|
|
mutex_lock(&algs_lock);
|
|
if (--active_devs_lz4s == 0) {
|
|
crypto_unregister_acomp(&qat_acomp_zstd_lz4s);
|
|
crypto_acomp_free_streams(&qat_zstd_streams);
|
|
}
|
|
mutex_unlock(&algs_lock);
|
|
}
|
|
|
|
static int qat_comp_algs_register_zstd(void)
|
|
{
|
|
int ret = 0;
|
|
|
|
mutex_lock(&algs_lock);
|
|
if (++active_devs_zstd == 1) {
|
|
ret = crypto_register_acomp(&qat_acomp_zstd_native);
|
|
if (ret)
|
|
active_devs_zstd--;
|
|
}
|
|
mutex_unlock(&algs_lock);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static void qat_comp_algs_unregister_zstd(void)
|
|
{
|
|
mutex_lock(&algs_lock);
|
|
if (--active_devs_zstd == 0)
|
|
crypto_unregister_acomp(&qat_acomp_zstd_native);
|
|
mutex_unlock(&algs_lock);
|
|
}
|
|
|
|
int qat_comp_algs_register(u32 caps)
|
|
{
|
|
int ret;
|
|
|
|
ret = qat_comp_algs_register_deflate();
|
|
if (ret)
|
|
return ret;
|
|
|
|
if (caps & ADF_ACCEL_CAPABILITIES_EXT_ZSTD_LZ4S) {
|
|
ret = qat_comp_algs_register_lz4s();
|
|
if (ret)
|
|
goto err_unregister_deflate;
|
|
}
|
|
|
|
if (caps & ADF_ACCEL_CAPABILITIES_EXT_ZSTD) {
|
|
ret = qat_comp_algs_register_zstd();
|
|
if (ret)
|
|
goto err_unregister_lz4s;
|
|
}
|
|
|
|
return ret;
|
|
|
|
err_unregister_lz4s:
|
|
if (caps & ADF_ACCEL_CAPABILITIES_EXT_ZSTD_LZ4S)
|
|
qat_comp_algs_unregister_lz4s();
|
|
err_unregister_deflate:
|
|
qat_comp_algs_unregister_deflate();
|
|
|
|
return ret;
|
|
}
|
|
|
|
void qat_comp_algs_unregister(u32 caps)
|
|
{
|
|
qat_comp_algs_unregister_deflate();
|
|
|
|
if (caps & ADF_ACCEL_CAPABILITIES_EXT_ZSTD_LZ4S)
|
|
qat_comp_algs_unregister_lz4s();
|
|
|
|
if (caps & ADF_ACCEL_CAPABILITIES_EXT_ZSTD)
|
|
qat_comp_algs_unregister_zstd();
|
|
}
|