/* SPDX-License-Identifier: GPL-2.0-or-later */1/*2* Asynchronous Compression operations3*4* Copyright (c) 2016, Intel Corporation5* Authors: Weigang Li <[email protected]>6* Giovanni Cabiddu <[email protected]>7*/8#ifndef _CRYPTO_ACOMP_H9#define _CRYPTO_ACOMP_H1011#include <linux/atomic.h>12#include <linux/args.h>13#include <linux/compiler_types.h>14#include <linux/container_of.h>15#include <linux/crypto.h>16#include <linux/err.h>17#include <linux/scatterlist.h>18#include <linux/slab.h>19#include <linux/spinlock_types.h>20#include <linux/types.h>2122/* Set this bit if source is virtual address instead of SG list. */23#define CRYPTO_ACOMP_REQ_SRC_VIRT 0x000000022425/* Set this bit for if virtual address source cannot be used for DMA. */26#define CRYPTO_ACOMP_REQ_SRC_NONDMA 0x000000042728/* Set this bit if destination is virtual address instead of SG list. */29#define CRYPTO_ACOMP_REQ_DST_VIRT 0x000000083031/* Set this bit for if virtual address destination cannot be used for DMA. */32#define CRYPTO_ACOMP_REQ_DST_NONDMA 0x000000103334/* Private flags that should not be touched by the user. */35#define CRYPTO_ACOMP_REQ_PRIVATE \36(CRYPTO_ACOMP_REQ_SRC_VIRT | CRYPTO_ACOMP_REQ_SRC_NONDMA | \37CRYPTO_ACOMP_REQ_DST_VIRT | CRYPTO_ACOMP_REQ_DST_NONDMA)3839#define CRYPTO_ACOMP_DST_MAX 1310724041#define MAX_SYNC_COMP_REQSIZE 04243#define ACOMP_REQUEST_ON_STACK(name, tfm) \44char __##name##_req[sizeof(struct acomp_req) + \45MAX_SYNC_COMP_REQSIZE] CRYPTO_MINALIGN_ATTR; \46struct acomp_req *name = acomp_request_on_stack_init( \47__##name##_req, (tfm))4849#define ACOMP_REQUEST_CLONE(name, gfp) \50acomp_request_clone(name, sizeof(__##name##_req), gfp)5152struct acomp_req;53struct folio;5455struct acomp_req_chain {56crypto_completion_t compl;57void *data;58struct scatterlist ssg;59struct scatterlist dsg;60union {61const u8 *src;62struct folio *sfolio;63};64union {65u8 *dst;66struct folio *dfolio;67};68u32 flags;69};7071/**72* struct acomp_req - asynchronous (de)compression request73*74* @base: Common attributes for asynchronous crypto requests75* @src: Source scatterlist76* @dst: Destination scatterlist77* @svirt: Source virtual address78* @dvirt: Destination virtual address79* @slen: Size of the input buffer80* @dlen: Size of the output buffer and number of bytes produced81* @chain: Private API code data, do not use82* @__ctx: Start of private context data83*/84struct acomp_req {85struct crypto_async_request base;86union {87struct scatterlist *src;88const u8 *svirt;89};90union {91struct scatterlist *dst;92u8 *dvirt;93};94unsigned int slen;95unsigned int dlen;9697struct acomp_req_chain chain;9899void *__ctx[] CRYPTO_MINALIGN_ATTR;100};101102/**103* struct crypto_acomp - user-instantiated objects which encapsulate104* algorithms and core processing logic105*106* @compress: Function performs a compress operation107* @decompress: Function performs a de-compress operation108* @reqsize: Context size for (de)compression requests109* @fb: Synchronous fallback tfm110* @base: Common crypto API algorithm data structure111*/112struct crypto_acomp {113int (*compress)(struct acomp_req *req);114int (*decompress)(struct acomp_req *req);115unsigned int reqsize;116struct crypto_tfm base;117};118119#define COMP_ALG_COMMON { \120struct crypto_alg base; \121}122struct comp_alg_common COMP_ALG_COMMON;123124/**125* DOC: Asynchronous Compression API126*127* The Asynchronous Compression API is used with the algorithms of type128* CRYPTO_ALG_TYPE_ACOMPRESS (listed as type "acomp" in /proc/crypto)129*/130131/**132* crypto_alloc_acomp() -- allocate ACOMPRESS tfm handle133* @alg_name: is the cra_name / name or cra_driver_name / driver name of the134* compression algorithm e.g. "deflate"135* @type: specifies the type of the algorithm136* @mask: specifies the mask for the algorithm137*138* Allocate a handle for a compression algorithm. The returned struct139* crypto_acomp is the handle that is required for any subsequent140* API invocation for the compression operations.141*142* Return: allocated handle in case of success; IS_ERR() is true in case143* of an error, PTR_ERR() returns the error code.144*/145struct crypto_acomp *crypto_alloc_acomp(const char *alg_name, u32 type,146u32 mask);147/**148* crypto_alloc_acomp_node() -- allocate ACOMPRESS tfm handle with desired NUMA node149* @alg_name: is the cra_name / name or cra_driver_name / driver name of the150* compression algorithm e.g. "deflate"151* @type: specifies the type of the algorithm152* @mask: specifies the mask for the algorithm153* @node: specifies the NUMA node the ZIP hardware belongs to154*155* Allocate a handle for a compression algorithm. Drivers should try to use156* (de)compressors on the specified NUMA node.157* The returned struct crypto_acomp is the handle that is required for any158* subsequent API invocation for the compression operations.159*160* Return: allocated handle in case of success; IS_ERR() is true in case161* of an error, PTR_ERR() returns the error code.162*/163struct crypto_acomp *crypto_alloc_acomp_node(const char *alg_name, u32 type,164u32 mask, int node);165166static inline struct crypto_tfm *crypto_acomp_tfm(struct crypto_acomp *tfm)167{168return &tfm->base;169}170171static inline struct comp_alg_common *__crypto_comp_alg_common(172struct crypto_alg *alg)173{174return container_of(alg, struct comp_alg_common, base);175}176177static inline struct crypto_acomp *__crypto_acomp_tfm(struct crypto_tfm *tfm)178{179return container_of(tfm, struct crypto_acomp, base);180}181182static inline struct comp_alg_common *crypto_comp_alg_common(183struct crypto_acomp *tfm)184{185return __crypto_comp_alg_common(crypto_acomp_tfm(tfm)->__crt_alg);186}187188static inline unsigned int crypto_acomp_reqsize(struct crypto_acomp *tfm)189{190return tfm->reqsize;191}192193static inline void acomp_request_set_tfm(struct acomp_req *req,194struct crypto_acomp *tfm)195{196crypto_request_set_tfm(&req->base, crypto_acomp_tfm(tfm));197}198199static inline bool acomp_is_async(struct crypto_acomp *tfm)200{201return crypto_comp_alg_common(tfm)->base.cra_flags &202CRYPTO_ALG_ASYNC;203}204205static inline struct crypto_acomp *crypto_acomp_reqtfm(struct acomp_req *req)206{207return __crypto_acomp_tfm(req->base.tfm);208}209210/**211* crypto_free_acomp() -- free ACOMPRESS tfm handle212*213* @tfm: ACOMPRESS tfm handle allocated with crypto_alloc_acomp()214*215* If @tfm is a NULL or error pointer, this function does nothing.216*/217static inline void crypto_free_acomp(struct crypto_acomp *tfm)218{219crypto_destroy_tfm(tfm, crypto_acomp_tfm(tfm));220}221222static inline int crypto_has_acomp(const char *alg_name, u32 type, u32 mask)223{224type &= ~CRYPTO_ALG_TYPE_MASK;225type |= CRYPTO_ALG_TYPE_ACOMPRESS;226mask |= CRYPTO_ALG_TYPE_ACOMPRESS_MASK;227228return crypto_has_alg(alg_name, type, mask);229}230231static inline const char *crypto_acomp_alg_name(struct crypto_acomp *tfm)232{233return crypto_tfm_alg_name(crypto_acomp_tfm(tfm));234}235236static inline const char *crypto_acomp_driver_name(struct crypto_acomp *tfm)237{238return crypto_tfm_alg_driver_name(crypto_acomp_tfm(tfm));239}240241/**242* acomp_request_alloc() -- allocates asynchronous (de)compression request243*244* @tfm: ACOMPRESS tfm handle allocated with crypto_alloc_acomp()245* @gfp: gfp to pass to kzalloc (defaults to GFP_KERNEL)246*247* Return: allocated handle in case of success or NULL in case of an error248*/249static inline struct acomp_req *acomp_request_alloc_extra_noprof(250struct crypto_acomp *tfm, size_t extra, gfp_t gfp)251{252struct acomp_req *req;253size_t len;254255len = ALIGN(sizeof(*req) + crypto_acomp_reqsize(tfm), CRYPTO_MINALIGN);256if (check_add_overflow(len, extra, &len))257return NULL;258259req = kzalloc_noprof(len, gfp);260if (likely(req))261acomp_request_set_tfm(req, tfm);262return req;263}264#define acomp_request_alloc_noprof(tfm, ...) \265CONCATENATE(acomp_request_alloc_noprof_, COUNT_ARGS(__VA_ARGS__))( \266tfm, ##__VA_ARGS__)267#define acomp_request_alloc_noprof_0(tfm) \268acomp_request_alloc_noprof_1(tfm, GFP_KERNEL)269#define acomp_request_alloc_noprof_1(tfm, gfp) \270acomp_request_alloc_extra_noprof(tfm, 0, gfp)271#define acomp_request_alloc(...) alloc_hooks(acomp_request_alloc_noprof(__VA_ARGS__))272273/**274* acomp_request_alloc_extra() -- allocate acomp request with extra memory275*276* @tfm: ACOMPRESS tfm handle allocated with crypto_alloc_acomp()277* @extra: amount of extra memory278* @gfp: gfp to pass to kzalloc279*280* Return: allocated handle in case of success or NULL in case of an error281*/282#define acomp_request_alloc_extra(...) alloc_hooks(acomp_request_alloc_extra_noprof(__VA_ARGS__))283284static inline void *acomp_request_extra(struct acomp_req *req)285{286struct crypto_acomp *tfm = crypto_acomp_reqtfm(req);287size_t len;288289len = ALIGN(sizeof(*req) + crypto_acomp_reqsize(tfm), CRYPTO_MINALIGN);290return (void *)((char *)req + len);291}292293static inline bool acomp_req_on_stack(struct acomp_req *req)294{295return crypto_req_on_stack(&req->base);296}297298/**299* acomp_request_free() -- zeroize and free asynchronous (de)compression300* request as well as the output buffer if allocated301* inside the algorithm302*303* @req: request to free304*/305static inline void acomp_request_free(struct acomp_req *req)306{307if (!req || acomp_req_on_stack(req))308return;309kfree_sensitive(req);310}311312/**313* acomp_request_set_callback() -- Sets an asynchronous callback314*315* Callback will be called when an asynchronous operation on a given316* request is finished.317*318* @req: request that the callback will be set for319* @flgs: specify for instance if the operation may backlog320* @cmlp: callback which will be called321* @data: private data used by the caller322*/323static inline void acomp_request_set_callback(struct acomp_req *req,324u32 flgs,325crypto_completion_t cmpl,326void *data)327{328flgs &= ~CRYPTO_ACOMP_REQ_PRIVATE;329flgs |= req->base.flags & CRYPTO_ACOMP_REQ_PRIVATE;330crypto_request_set_callback(&req->base, flgs, cmpl, data);331}332333/**334* acomp_request_set_params() -- Sets request parameters335*336* Sets parameters required by an acomp operation337*338* @req: asynchronous compress request339* @src: pointer to input buffer scatterlist340* @dst: pointer to output buffer scatterlist. If this is NULL, the341* acomp layer will allocate the output memory342* @slen: size of the input buffer343* @dlen: size of the output buffer. If dst is NULL, this can be used by344* the user to specify the maximum amount of memory to allocate345*/346static inline void acomp_request_set_params(struct acomp_req *req,347struct scatterlist *src,348struct scatterlist *dst,349unsigned int slen,350unsigned int dlen)351{352req->src = src;353req->dst = dst;354req->slen = slen;355req->dlen = dlen;356357req->base.flags &= ~(CRYPTO_ACOMP_REQ_SRC_VIRT |358CRYPTO_ACOMP_REQ_SRC_NONDMA |359CRYPTO_ACOMP_REQ_DST_VIRT |360CRYPTO_ACOMP_REQ_DST_NONDMA);361}362363/**364* acomp_request_set_src_sg() -- Sets source scatterlist365*366* Sets source scatterlist required by an acomp operation.367*368* @req: asynchronous compress request369* @src: pointer to input buffer scatterlist370* @slen: size of the input buffer371*/372static inline void acomp_request_set_src_sg(struct acomp_req *req,373struct scatterlist *src,374unsigned int slen)375{376req->src = src;377req->slen = slen;378379req->base.flags &= ~CRYPTO_ACOMP_REQ_SRC_NONDMA;380req->base.flags &= ~CRYPTO_ACOMP_REQ_SRC_VIRT;381}382383/**384* acomp_request_set_src_dma() -- Sets DMA source virtual address385*386* Sets source virtual address required by an acomp operation.387* The address must be usable for DMA.388*389* @req: asynchronous compress request390* @src: virtual address pointer to input buffer391* @slen: size of the input buffer392*/393static inline void acomp_request_set_src_dma(struct acomp_req *req,394const u8 *src, unsigned int slen)395{396req->svirt = src;397req->slen = slen;398399req->base.flags &= ~CRYPTO_ACOMP_REQ_SRC_NONDMA;400req->base.flags |= CRYPTO_ACOMP_REQ_SRC_VIRT;401}402403/**404* acomp_request_set_src_nondma() -- Sets non-DMA source virtual address405*406* Sets source virtual address required by an acomp operation.407* The address can not be used for DMA.408*409* @req: asynchronous compress request410* @src: virtual address pointer to input buffer411* @slen: size of the input buffer412*/413static inline void acomp_request_set_src_nondma(struct acomp_req *req,414const u8 *src,415unsigned int slen)416{417req->svirt = src;418req->slen = slen;419420req->base.flags |= CRYPTO_ACOMP_REQ_SRC_NONDMA;421req->base.flags |= CRYPTO_ACOMP_REQ_SRC_VIRT;422}423424/**425* acomp_request_set_src_folio() -- Sets source folio426*427* Sets source folio required by an acomp operation.428*429* @req: asynchronous compress request430* @folio: pointer to input folio431* @off: input folio offset432* @len: size of the input buffer433*/434static inline void acomp_request_set_src_folio(struct acomp_req *req,435struct folio *folio, size_t off,436unsigned int len)437{438sg_init_table(&req->chain.ssg, 1);439sg_set_folio(&req->chain.ssg, folio, len, off);440acomp_request_set_src_sg(req, &req->chain.ssg, len);441}442443/**444* acomp_request_set_dst_sg() -- Sets destination scatterlist445*446* Sets destination scatterlist required by an acomp operation.447*448* @req: asynchronous compress request449* @dst: pointer to output buffer scatterlist450* @dlen: size of the output buffer451*/452static inline void acomp_request_set_dst_sg(struct acomp_req *req,453struct scatterlist *dst,454unsigned int dlen)455{456req->dst = dst;457req->dlen = dlen;458459req->base.flags &= ~CRYPTO_ACOMP_REQ_DST_NONDMA;460req->base.flags &= ~CRYPTO_ACOMP_REQ_DST_VIRT;461}462463/**464* acomp_request_set_dst_dma() -- Sets DMA destination virtual address465*466* Sets destination virtual address required by an acomp operation.467* The address must be usable for DMA.468*469* @req: asynchronous compress request470* @dst: virtual address pointer to output buffer471* @dlen: size of the output buffer472*/473static inline void acomp_request_set_dst_dma(struct acomp_req *req,474u8 *dst, unsigned int dlen)475{476req->dvirt = dst;477req->dlen = dlen;478479req->base.flags &= ~CRYPTO_ACOMP_REQ_DST_NONDMA;480req->base.flags |= CRYPTO_ACOMP_REQ_DST_VIRT;481}482483/**484* acomp_request_set_dst_nondma() -- Sets non-DMA destination virtual address485*486* Sets destination virtual address required by an acomp operation.487* The address can not be used for DMA.488*489* @req: asynchronous compress request490* @dst: virtual address pointer to output buffer491* @dlen: size of the output buffer492*/493static inline void acomp_request_set_dst_nondma(struct acomp_req *req,494u8 *dst, unsigned int dlen)495{496req->dvirt = dst;497req->dlen = dlen;498499req->base.flags |= CRYPTO_ACOMP_REQ_DST_NONDMA;500req->base.flags |= CRYPTO_ACOMP_REQ_DST_VIRT;501}502503/**504* acomp_request_set_dst_folio() -- Sets destination folio505*506* Sets destination folio required by an acomp operation.507*508* @req: asynchronous compress request509* @folio: pointer to input folio510* @off: input folio offset511* @len: size of the input buffer512*/513static inline void acomp_request_set_dst_folio(struct acomp_req *req,514struct folio *folio, size_t off,515unsigned int len)516{517sg_init_table(&req->chain.dsg, 1);518sg_set_folio(&req->chain.dsg, folio, len, off);519acomp_request_set_dst_sg(req, &req->chain.dsg, len);520}521522/**523* crypto_acomp_compress() -- Invoke asynchronous compress operation524*525* Function invokes the asynchronous compress operation526*527* @req: asynchronous compress request528*529* Return: zero on success; error code in case of error530*/531int crypto_acomp_compress(struct acomp_req *req);532533/**534* crypto_acomp_decompress() -- Invoke asynchronous decompress operation535*536* Function invokes the asynchronous decompress operation537*538* @req: asynchronous compress request539*540* Return: zero on success; error code in case of error541*/542int crypto_acomp_decompress(struct acomp_req *req);543544static inline struct acomp_req *acomp_request_on_stack_init(545char *buf, struct crypto_acomp *tfm)546{547struct acomp_req *req = (void *)buf;548549crypto_stack_request_init(&req->base, crypto_acomp_tfm(tfm));550return req;551}552553struct acomp_req *acomp_request_clone(struct acomp_req *req,554size_t total, gfp_t gfp);555556#endif557558559