lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20230717021203.3541437-1-rex.zhang@intel.com>
Date:   Mon, 17 Jul 2023 10:12:03 +0800
From:   Rex Zhang <rex.zhang@...el.com>
To:     tom.zanussi@...ux.intel.com
Cc:     dave.jiang@...el.com, davem@...emloft.net,
        dmaengine@...r.kernel.org, fenghua.yu@...el.com,
        giovanni.cabiddu@...el.com, herbert@...dor.apana.org.au,
        james.guilford@...el.com, kanchana.p.sridhar@...el.com,
        linux-crypto@...r.kernel.org, linux-kernel@...r.kernel.org,
        tony.luck@...el.com, vinodh.gopal@...el.com, vkoul@...nel.org,
        wajdi.k.feghali@...el.com, rex.zhang@...el.com
Subject: Re: [PATCH v7 12/14] crypto: iaa - Add support for deflate-iaa compression algorithm

Hi, Tom,

On 2023-07-10 at 14:06:52 -0500, Tom Zanussi wrote:
> This patch registers the deflate-iaa deflate compression algorithm and
> hooks it up to the IAA hardware using the 'fixed' compression mode
> introduced in the previous patch.
> 
> Because the IAA hardware has a 4k history-window limitation, only
> buffers <= 4k, or that have been compressed using a <= 4k history
> window, are technically compliant with the deflate spec, which allows
> for a window of up to 32k.  Because of this limitation, the IAA fixed
> mode deflate algorithm is given its own algorithm name, 'deflate-iaa'.
> 
> With this change, the deflate-iaa crypto algorithm is registered and
> operational, and compression and decompression operations are fully
> enabled following the successful binding of the first IAA workqueue
> to the iaa_crypto sub-driver.
> 
> when there are no IAA workqueues bound to the driver, the IAA crypto
> algorithm can be unregistered by removing the module.
> 
> A new iaa_crypto 'verify_compress' driver attribute is also added,
> allowing the user to toggle compression verification.  If set, each
> compress will be internally decompressed and the contents verified,
> returning error codes if unsuccessful.  This can be toggled with 0/1:
> 
>   echo 0 > /sys/bus/dsa/drivers/crypto/verify_compress
> 
> The default setting is '1' - verify all compresses.
> 
> The verify_compress value setting at the time the algorithm is
> registered is captured in the algorithm's crypto_ctx and used for all
> compresses when using the algorithm.
> 
> [ Based on work originally by George Powley, Jing Lin and Kyung Min
> Park ]
> 
> Signed-off-by: Tom Zanussi <tom.zanussi@...ux.intel.com>
> ---
>  crypto/testmgr.c                           |  10 +
>  drivers/crypto/intel/iaa/iaa_crypto.h      |  36 +
>  drivers/crypto/intel/iaa/iaa_crypto_main.c | 921 ++++++++++++++++++++-
>  3 files changed, 950 insertions(+), 17 deletions(-)
> 
> diff --git a/crypto/testmgr.c b/crypto/testmgr.c
> index 216878c8bc3d..b6d924e0ff59 100644
> --- a/crypto/testmgr.c
> +++ b/crypto/testmgr.c
> @@ -4819,6 +4819,16 @@ static const struct alg_test_desc alg_test_descs[] = {
>  				.decomp = __VECS(deflate_decomp_tv_template)
>  			}
>  		}
> +	}, {
> +		.alg = "deflate-iaa",
> +		.test = alg_test_comp,
> +		.fips_allowed = 1,
> +		.suite = {
> +			.comp = {
> +				.comp = __VECS(deflate_comp_tv_template),
> +				.decomp = __VECS(deflate_decomp_tv_template)
> +			}
> +		}
>  	}, {
>  		.alg = "dh",
>  		.test = alg_test_kpp,
> diff --git a/drivers/crypto/intel/iaa/iaa_crypto.h b/drivers/crypto/intel/iaa/iaa_crypto.h
> index 33e68f9d3d02..4c6b0f5a6b50 100644
> --- a/drivers/crypto/intel/iaa/iaa_crypto.h
> +++ b/drivers/crypto/intel/iaa/iaa_crypto.h
> @@ -10,15 +10,42 @@
>  
>  #define IDXD_SUBDRIVER_NAME		"crypto"
>  
> +#define IAA_DECOMP_ENABLE		BIT(0)
> +#define IAA_DECOMP_FLUSH_OUTPUT		BIT(1)
> +#define IAA_DECOMP_CHECK_FOR_EOB	BIT(2)
> +#define IAA_DECOMP_STOP_ON_EOB		BIT(3)
> +#define IAA_DECOMP_SUPPRESS_OUTPUT	BIT(9)
> +
> +#define IAA_COMP_FLUSH_OUTPUT		BIT(1)
> +#define IAA_COMP_APPEND_EOB		BIT(2)
> +
> +#define IAA_COMPLETION_TIMEOUT		1000000
> +
> +#define IAA_ANALYTICS_ERROR		0x0a
> +#define IAA_ERROR_DECOMP_BUF_OVERFLOW	0x0b
> +#define IAA_ERROR_COMP_BUF_OVERFLOW	0x19
> +#define IAA_ERROR_WATCHDOG_EXPIRED	0x24
> +
>  #define IAA_COMP_MODES_MAX		2
>  
>  #define FIXED_HDR			0x2
>  #define FIXED_HDR_SIZE			3
>  
> +#define IAA_COMP_FLAGS			(IAA_COMP_FLUSH_OUTPUT | \
> +					 IAA_COMP_APPEND_EOB)
> +
> +#define IAA_DECOMP_FLAGS		(IAA_DECOMP_ENABLE |	   \
> +					 IAA_DECOMP_FLUSH_OUTPUT | \
> +					 IAA_DECOMP_CHECK_FOR_EOB | \
> +					 IAA_DECOMP_STOP_ON_EOB)
> +
>  /* Representation of IAA workqueue */
>  struct iaa_wq {
>  	struct list_head	list;
> +
>  	struct idxd_wq		*wq;
> +	int			ref;
> +	bool			remove;
>  
>  	struct iaa_device	*iaa_device;
>  };
> @@ -119,4 +146,13 @@ int add_iaa_compression_mode(const char *name,
>  
>  void remove_iaa_compression_mode(const char *name);
>  
> +enum iaa_mode {
> +	IAA_MODE_FIXED,
> +};
> +
> +struct iaa_compression_ctx {
> +	enum iaa_mode	mode;
> +	bool		verify_compress;
> +};
> +
>  #endif
> diff --git a/drivers/crypto/intel/iaa/iaa_crypto_main.c b/drivers/crypto/intel/iaa/iaa_crypto_main.c
> index 0c59332456f0..9b4acc343582 100644
> --- a/drivers/crypto/intel/iaa/iaa_crypto_main.c
> +++ b/drivers/crypto/intel/iaa/iaa_crypto_main.c
> @@ -10,6 +10,7 @@
>  #include <uapi/linux/idxd.h>
>  #include <linux/highmem.h>
>  #include <linux/sched/smt.h>
> +#include <crypto/internal/acompress.h>
>  
>  #include "idxd.h"
>  #include "iaa_crypto.h"
> @@ -32,6 +33,20 @@ static unsigned int cpus_per_iaa;
>  /* Per-cpu lookup table for balanced wqs */
>  static struct wq_table_entry __percpu *wq_table;
>  
> +static struct idxd_wq *wq_table_next_wq(int cpu)
> +{
> +	struct wq_table_entry *entry = per_cpu_ptr(wq_table, cpu);
> +
> +	if (++entry->cur_wq >= entry->n_wqs)
> +		entry->cur_wq = 0;
> +
> +	pr_debug("%s: returning wq at idx %d (iaa wq %d.%d) from cpu %d\n", __func__,
> +		 entry->cur_wq, entry->wqs[entry->cur_wq]->idxd->id,
> +		 entry->wqs[entry->cur_wq]->id, cpu);
> +
> +	return entry->wqs[entry->cur_wq];
> +}
> +
>  static void wq_table_add(int cpu, struct idxd_wq *wq)
>  {
>  	struct wq_table_entry *entry = per_cpu_ptr(wq_table, cpu);
> @@ -66,6 +81,40 @@ static void wq_table_clear_entry(int cpu)
>  static LIST_HEAD(iaa_devices);
>  static DEFINE_MUTEX(iaa_devices_lock);
>  
> +/* If enabled, IAA hw crypto algos are registered, unavailable otherwise */
> +static bool iaa_crypto_enabled;
> +static bool iaa_crypto_registered;
> +
> +/* Verify results of IAA compress or not */
> +static bool iaa_verify_compress = true;
> +
> +static ssize_t verify_compress_show(struct device_driver *driver, char *buf)
> +{
> +	return sprintf(buf, "%d\n", iaa_verify_compress);
> +}
> +
> +static ssize_t verify_compress_store(struct device_driver *driver,
> +				     const char *buf, size_t count)
> +{
> +	int ret = -EBUSY;
> +
> +	mutex_lock(&iaa_devices_lock);
> +
> +	if (iaa_crypto_enabled)
> +		goto out;
> +
> +	ret = kstrtobool(buf, &iaa_verify_compress);
> +	if (ret)
> +		goto out;
> +
> +	ret = count;
> +out:
> +	mutex_unlock(&iaa_devices_lock);
> +
> +	return ret;
> +}
> +static DRIVER_ATTR_RW(verify_compress);
> +
>  static struct iaa_compression_mode *iaa_compression_modes[IAA_COMP_MODES_MAX];
>  
>  static int find_empty_iaa_compression_mode(void)
> @@ -250,6 +299,12 @@ int add_iaa_compression_mode(const char *name,
>  }
>  EXPORT_SYMBOL_GPL(add_iaa_compression_mode);
>  
> +static struct iaa_device_compression_mode *
> +get_iaa_device_compression_mode(struct iaa_device *iaa_device, int idx)
> +{
> +	return iaa_device->compression_modes[idx];
> +}
> +
>  static void free_device_compression_mode(struct iaa_device *iaa_device,
>  					 struct iaa_device_compression_mode *device_mode)
>  {
> @@ -268,6 +323,86 @@ static void free_device_compression_mode(struct iaa_device *iaa_device,
>  	kfree(device_mode);
>  }
>  
> +#define IDXD_OP_FLAG_AECS_RW_TGLS       0x400000
> +#define IAX_AECS_DEFAULT_FLAG (IDXD_OP_FLAG_CRAV | IDXD_OP_FLAG_RCR | IDXD_OP_FLAG_CC)
> +#define IAX_AECS_COMPRESS_FLAG	(IAX_AECS_DEFAULT_FLAG | IDXD_OP_FLAG_RD_SRC2_AECS)
> +#define IAX_AECS_DECOMPRESS_FLAG (IAX_AECS_DEFAULT_FLAG | IDXD_OP_FLAG_RD_SRC2_AECS)
> +#define IAX_AECS_GEN_FLAG (IAX_AECS_DEFAULT_FLAG | \
> +						IDXD_OP_FLAG_WR_SRC2_AECS_COMP | \
> +						IDXD_OP_FLAG_AECS_RW_TGLS)
> +
> +static int check_completion(struct device *dev,
> +			    struct iax_completion_record *comp,
> +			    bool compress,
> +			    bool only_once);
> +
> +static int decompress_header(struct iaa_device_compression_mode *device_mode,
> +			     struct iaa_compression_mode *mode,
> +			     struct idxd_wq *wq)
> +{
> +	dma_addr_t src_addr, src2_addr;
> +	struct idxd_desc *idxd_desc;
> +	struct iax_hw_desc *desc;
> +	struct device *dev;
> +	int ret = 0;
> +
> +	idxd_desc = idxd_alloc_desc(wq, IDXD_OP_BLOCK);
> +	if (IS_ERR(idxd_desc))
> +		return PTR_ERR(idxd_desc);
> +
> +	desc = idxd_desc->iax_hw;
> +
> +	dev = &wq->idxd->pdev->dev;
> +
> +	src_addr = dma_map_single(dev, (void *)mode->header_table,
> +				  mode->header_table_size, DMA_TO_DEVICE);
> +	dev_dbg(dev, "%s: mode->name %s, src_addr %llx, dev %p, src %p, slen %d\n",
> +		__func__, mode->name, src_addr,	dev,
> +		mode->header_table, mode->header_table_size);
> +	if (unlikely(dma_mapping_error(dev, src_addr))) {
> +		dev_dbg(dev, "dma_map_single err, exiting\n");
> +		ret = -ENOMEM;
> +		return ret;
> +	}
> +
> +	desc->flags = IAX_AECS_GEN_FLAG;
> +	desc->opcode = IAX_OPCODE_DECOMPRESS;
> +
> +	desc->src1_addr = (u64)src_addr;
> +	desc->src1_size = mode->header_table_size;
> +
> +	src2_addr = device_mode->aecs_decomp_table_dma_addr;
> +	desc->src2_addr = (u64)src2_addr;
> +	desc->src2_size = 1088;
> +	dev_dbg(dev, "%s: mode->name %s, src2_addr %llx, dev %p, src2_size %d\n",
> +		__func__, mode->name, desc->src2_addr, dev, desc->src2_size);
> +	desc->max_dst_size = 0; // suppressed output
> +
> +	desc->decompr_flags = mode->gen_decomp_table_flags;
> +
> +	desc->priv = 1;
> +
> +	desc->completion_addr = idxd_desc->compl_dma;
> +
> +	ret = idxd_submit_desc(wq, idxd_desc);
> +	if (ret) {
> +		pr_err("%s: submit_desc failed ret=0x%x\n", __func__, ret);
> +		goto out;
> +	}
> +
> +	ret = check_completion(dev, idxd_desc->iax_completion, false, false);
> +	if (ret)
> +		dev_dbg(dev, "%s: mode->name %s check_completion failed ret=%d\n",
> +			__func__, mode->name, ret);
> +	else
> +		dev_dbg(dev, "%s: mode->name %s succeeded\n", __func__,
> +			mode->name);
> +out:
> +	dma_unmap_single(dev, src_addr, 1088, DMA_TO_DEVICE);
> +
> +	return ret;
> +}
> +
>  static int init_device_compression_mode(struct iaa_device *iaa_device,
>  					struct iaa_compression_mode *mode,
>  					int idx, struct idxd_wq *wq)
> @@ -300,6 +435,14 @@ static int init_device_compression_mode(struct iaa_device *iaa_device,
>  	memcpy(device_mode->aecs_comp_table->ll_sym, mode->ll_table, mode->ll_table_size);
>  	memcpy(device_mode->aecs_comp_table->d_sym, mode->d_table, mode->d_table_size);
>  
> +	if (mode->header_table) {
> +		ret = decompress_header(device_mode, mode, wq);
> +		if (ret) {
> +			pr_debug("iaa header decompression failed: ret=%d\n", ret);
> +			goto free;
> +		}
> +	}
> +
>  	if (mode->init) {
>  		ret = mode->init(device_mode);
>  		if (ret)
> @@ -372,18 +515,6 @@ static struct iaa_device *iaa_device_alloc(void)
>  	return iaa_device;
>  }
>  
> -static void iaa_device_free(struct iaa_device *iaa_device)
> -{
> -	struct iaa_wq *iaa_wq, *next;
> -
> -	list_for_each_entry_safe(iaa_wq, next, &iaa_device->wqs, list) {
> -		list_del(&iaa_wq->list);
> -		kfree(iaa_wq);
> -	}
> -
> -	kfree(iaa_device);
> -}
> -
>  static bool iaa_has_wq(struct iaa_device *iaa_device, struct idxd_wq *wq)
>  {
>  	struct iaa_wq *iaa_wq;
> @@ -426,12 +557,8 @@ static int init_iaa_device(struct iaa_device *iaa_device, struct iaa_wq *iaa_wq)
>  
>  static void del_iaa_device(struct iaa_device *iaa_device)
>  {
> -	remove_device_compression_modes(iaa_device);
> -
>  	list_del(&iaa_device->list);
>  
> -	iaa_device_free(iaa_device);
> -
>  	nr_iaa--;
>  }
>  
> @@ -497,6 +624,82 @@ static void clear_wq_table(void)
>  	pr_debug("cleared wq table\n");
>  }
>  
> +static void free_iaa_device(struct iaa_device *iaa_device)
> +{
> +	if (!iaa_device)
> +		return;
> +
> +	remove_device_compression_modes(iaa_device);
> +	kfree(iaa_device);
> +}
> +
> +static void __free_iaa_wq(struct iaa_wq *iaa_wq)
> +{
> +	struct iaa_device *iaa_device;
> +
> +	if (!iaa_wq)
> +		return;
> +
> +	iaa_device = iaa_wq->iaa_device;
> +	if (iaa_device->n_wq == 0)
> +		free_iaa_device(iaa_wq->iaa_device);
> +}
> +
> +static void free_iaa_wq(struct iaa_wq *iaa_wq)
> +{
> +	struct idxd_wq *wq;
> +
> +	__free_iaa_wq(iaa_wq);
> +
> +	wq = iaa_wq->wq;
> +
> +	kfree(iaa_wq);
> +	idxd_wq_set_private(wq, NULL);
> +}
> +
> +static int iaa_wq_get(struct idxd_wq *wq)
> +{
> +	struct idxd_device *idxd = wq->idxd;
> +	struct iaa_wq *iaa_wq;
> +	int ret = 0;
> +
> +	spin_lock(&idxd->dev_lock);
> +	iaa_wq = idxd_wq_get_private(wq);
> +	if (iaa_wq && !iaa_wq->remove)
> +		iaa_wq->ref++;
> +	else
> +		ret = -ENODEV;
> +	spin_unlock(&idxd->dev_lock);
> +
> +	return ret;
> +}
> +
> +static int iaa_wq_put(struct idxd_wq *wq)
> +{
> +	struct idxd_device *idxd = wq->idxd;
> +	struct iaa_wq *iaa_wq;
> +	bool free = false;
> +	int ret = 0;
> +
> +	spin_lock(&idxd->dev_lock);
> +	iaa_wq = idxd_wq_get_private(wq);
> +	if (iaa_wq) {
> +		iaa_wq->ref--;
> +		if (iaa_wq->ref == 0 && iaa_wq->remove) {
> +			__free_iaa_wq(iaa_wq);
> +			idxd_wq_set_private(wq, NULL);
> +			free = true;
> +		}
> +	} else {
> +		ret = -ENODEV;
> +	}
> +	spin_unlock(&idxd->dev_lock);
> +	if (free)
> +		kfree(iaa_wq);
> +
> +	return ret;
> +}
> +
>  static void free_wq_table(void)
>  {
>  	int cpu;
> @@ -580,6 +783,7 @@ static int save_iaa_wq(struct idxd_wq *wq)
>  		ret = add_iaa_wq(new_device, wq, &new_wq);
>  		if (ret) {
>  			del_iaa_device(new_device);
> +			free_iaa_device(new_device);
>  			goto out;
>  		}
>  
> @@ -587,6 +791,7 @@ static int save_iaa_wq(struct idxd_wq *wq)
>  		if (ret) {
>  			del_iaa_wq(new_device, new_wq->wq);
>  			del_iaa_device(new_device);
> +			free_iaa_wq(new_wq);
>  			goto out;
>  		}
>  	}
> @@ -724,6 +929,624 @@ static void rebalance_wq_table(void)
>  	}
>  }
>  
> +static inline int check_completion(struct device *dev,
> +				   struct iax_completion_record *comp,
> +				   bool compress,
> +				   bool only_once)
> +{
> +	char *op_str = compress ? "compress" : "decompress";
> +	int ret = 0;
> +
> +	while (!comp->status) {
> +		if (only_once)
> +			return -EAGAIN;
> +		cpu_relax();
> +	}
> +
> +	if (comp->status != IAX_COMP_SUCCESS) {
> +		if (comp->status == IAA_ERROR_WATCHDOG_EXPIRED) {
> +			ret = -ETIMEDOUT;
> +			dev_dbg(dev, "%s timed out, size=0x%x\n",
> +				op_str, comp->output_size);
> +			goto out;
> +		}
> +
> +		if (comp->status == IAA_ANALYTICS_ERROR &&
> +		    comp->error_code == IAA_ERROR_COMP_BUF_OVERFLOW && compress) {
> +			ret = -E2BIG;
> +			dev_dbg(dev, "compressed > uncompressed size,"
> +				" not compressing, size=0x%x\n",
> +				comp->output_size);
> +			goto out;
> +		}
> +
> +		if (comp->status == IAA_ERROR_DECOMP_BUF_OVERFLOW) {
> +			ret = -EOVERFLOW;
> +			goto out;
> +		}
> +
> +		ret = -EINVAL;
> +		dev_dbg(dev, "iaa %s status=0x%x, error=0x%x, size=0x%x\n",
> +			op_str, comp->status, comp->error_code, comp->output_size);
> +		print_hex_dump(KERN_INFO, "cmp-rec: ", DUMP_PREFIX_OFFSET, 8, 1, comp, 64, 0);
> +
> +		goto out;
> +	}
> +out:
> +	return ret;
> +}
> +
> +static int iaa_compress(struct crypto_tfm *tfm,	struct acomp_req *req,
> +			struct idxd_wq *wq,
> +			dma_addr_t src_addr, unsigned int slen,
> +			dma_addr_t dst_addr, unsigned int *dlen,
> +			u32 *compression_crc,
> +			bool disable_async)
> +{
> +	struct iaa_device_compression_mode *active_compression_mode;
> +	struct iaa_compression_ctx *ctx = crypto_tfm_ctx(tfm);
> +	struct iaa_device *iaa_device;
> +	struct idxd_desc *idxd_desc;
> +	struct iax_hw_desc *desc;
> +	struct idxd_device *idxd;
> +	struct iaa_wq *iaa_wq;
> +	struct pci_dev *pdev;
> +	struct device *dev;
> +	int ret = 0;
> +
> +	iaa_wq = idxd_wq_get_private(wq);
> +	iaa_device = iaa_wq->iaa_device;
> +	idxd = iaa_device->idxd;
> +	pdev = idxd->pdev;
> +	dev = &pdev->dev;
> +
> +	active_compression_mode = get_iaa_device_compression_mode(iaa_device, ctx->mode);
> +
> +	idxd_desc = idxd_alloc_desc(wq, IDXD_OP_BLOCK);
> +	if (IS_ERR(idxd_desc)) {
> +		dev_dbg(dev, "idxd descriptor allocation failed\n");
> +		dev_dbg(dev, "iaa compress failed: ret=%ld\n", PTR_ERR(idxd_desc));
> +		return PTR_ERR(idxd_desc);
> +	}
> +	desc = idxd_desc->iax_hw;
> +
> +	desc->flags = IDXD_OP_FLAG_CRAV | IDXD_OP_FLAG_RCR |
> +		IDXD_OP_FLAG_RD_SRC2_AECS | IDXD_OP_FLAG_CC;
> +	desc->opcode = IAX_OPCODE_COMPRESS;
> +	desc->compr_flags = IAA_COMP_FLAGS;
> +	desc->priv = 1;
> +
> +	desc->src1_addr = (u64)src_addr;
> +	desc->src1_size = slen;
> +	desc->dst_addr = (u64)dst_addr;
> +	desc->max_dst_size = *dlen;
> +	desc->src2_addr = active_compression_mode->aecs_comp_table_dma_addr;
> +	desc->src2_size = sizeof(struct aecs_comp_table_record);
> +	desc->completion_addr = idxd_desc->compl_dma;
> +
> +	dev_dbg(dev, "%s: compression mode %s,"
> +		" desc->src1_addr %llx, desc->src1_size %d,"
> +		" desc->dst_addr %llx, desc->max_dst_size %d,"
> +		" desc->src2_addr %llx, desc->src2_size %d\n", __func__,
> +		active_compression_mode->name,
> +		desc->src1_addr, desc->src1_size, desc->dst_addr,
> +		desc->max_dst_size, desc->src2_addr, desc->src2_size);
> +
> +	ret = idxd_submit_desc(wq, idxd_desc);
> +	if (ret) {
> +		dev_dbg(dev, "submit_desc failed ret=%d\n", ret);
> +		goto err;
> +	}
> +
> +	ret = check_completion(dev, idxd_desc->iax_completion, true, false);
> +	if (ret) {
> +		dev_dbg(dev, "check_completion failed ret=%d\n", ret);
> +		goto err;
> +	}
> +
> +	*dlen = idxd_desc->iax_completion->output_size;
> +
> +	*compression_crc = idxd_desc->iax_completion->crc;
> +
> +	idxd_free_desc(wq, idxd_desc);
> +out:
> +	return ret;
> +err:
> +	idxd_free_desc(wq, idxd_desc);
> +	dev_dbg(dev, "iaa compress failed: ret=%d\n", ret);
> +
> +	goto out;
> +}
> +
> +static int iaa_compress_verify(struct crypto_tfm *tfm, struct acomp_req *req,
> +			       struct idxd_wq *wq,
> +			       dma_addr_t src_addr, unsigned int slen,
> +			       dma_addr_t dst_addr, unsigned int *dlen,
> +			       u32 compression_crc)
> +{
> +	struct iaa_device_compression_mode *active_compression_mode;
> +	struct iaa_compression_ctx *ctx = crypto_tfm_ctx(tfm);
> +	struct iaa_device *iaa_device;
> +	struct idxd_desc *idxd_desc;
> +	struct iax_hw_desc *desc;
> +	struct idxd_device *idxd;
> +	struct iaa_wq *iaa_wq;
> +	struct pci_dev *pdev;
> +	struct device *dev;
> +	int ret = 0;
> +
> +	iaa_wq = idxd_wq_get_private(wq);
> +	iaa_device = iaa_wq->iaa_device;
> +	idxd = iaa_device->idxd;
> +	pdev = idxd->pdev;
> +	dev = &pdev->dev;
> +
> +	active_compression_mode = get_iaa_device_compression_mode(iaa_device, ctx->mode);
> +
> +	idxd_desc = idxd_alloc_desc(wq, IDXD_OP_BLOCK);
> +	if (IS_ERR(idxd_desc)) {
> +		dev_dbg(dev, "idxd descriptor allocation failed\n");
> +		dev_dbg(dev, "iaa compress failed: ret=%ld\n",
> +			PTR_ERR(idxd_desc));
> +		return PTR_ERR(idxd_desc);
> +	}
> +	desc = idxd_desc->iax_hw;
> +
> +	/* Verify (optional) - decompress and check crc, suppress dest write */
> +
> +	desc->flags = IDXD_OP_FLAG_CRAV | IDXD_OP_FLAG_RCR | IDXD_OP_FLAG_CC;
> +	desc->opcode = IAX_OPCODE_DECOMPRESS;
> +	desc->decompr_flags = IAA_DECOMP_FLAGS | IAA_DECOMP_SUPPRESS_OUTPUT;
> +	desc->priv = 1;
> +
> +	desc->src1_addr = (u64)dst_addr;
> +	desc->src1_size = *dlen;
> +	desc->dst_addr = (u64)src_addr;
> +	desc->max_dst_size = slen;
> +	desc->completion_addr = idxd_desc->compl_dma;
> +
> +	dev_dbg(dev, "(verify) compression mode %s,"
> +		" desc->src1_addr %llx, desc->src1_size %d,"
> +		" desc->dst_addr %llx, desc->max_dst_size %d,"
> +		" desc->src2_addr %llx, desc->src2_size %d\n",
> +		active_compression_mode->name,
> +		desc->src1_addr, desc->src1_size, desc->dst_addr,
> +		desc->max_dst_size, desc->src2_addr, desc->src2_size);
> +
> +	ret = idxd_submit_desc(wq, idxd_desc);
> +	if (ret) {
> +		dev_dbg(dev, "submit_desc (verify) failed ret=%d\n", ret);
> +		goto err;
> +	}
> +
> +	ret = check_completion(dev, idxd_desc->iax_completion, false, false);
> +	if (ret) {
> +		dev_dbg(dev, "(verify) check_completion failed ret=%d\n", ret);
> +		goto err;
> +	}
> +
> +	if (compression_crc != idxd_desc->iax_completion->crc) {
> +		ret = -EINVAL;
> +		dev_dbg(dev, "(verify) iaa comp/decomp crc mismatch:"
> +			" comp=0x%x, decomp=0x%x\n", compression_crc,
> +			idxd_desc->iax_completion->crc);
> +		print_hex_dump(KERN_INFO, "cmp-rec: ", DUMP_PREFIX_OFFSET,
> +			       8, 1, idxd_desc->iax_completion, 64, 0);
> +		goto err;
> +	}
> +
> +	idxd_free_desc(wq, idxd_desc);
> +out:
> +	return ret;
> +err:
> +	idxd_free_desc(wq, idxd_desc);
> +	dev_dbg(dev, "iaa compress failed: ret=%d\n", ret);
> +
> +	goto out;
> +}
> +
> +static int iaa_decompress(struct crypto_tfm *tfm, struct acomp_req *req,
> +			  struct idxd_wq *wq,
> +			  dma_addr_t src_addr, unsigned int slen,
> +			  dma_addr_t dst_addr, unsigned int *dlen,
> +			  bool disable_async)
> +{
> +	struct iaa_device_compression_mode *active_compression_mode;
> +	struct iaa_compression_ctx *ctx = crypto_tfm_ctx(tfm);
> +	struct iaa_device *iaa_device;
> +	struct idxd_desc *idxd_desc;
> +	struct iax_hw_desc *desc;
> +	struct idxd_device *idxd;
> +	struct iaa_wq *iaa_wq;
> +	struct pci_dev *pdev;
> +	struct device *dev;
> +	int ret = 0;
> +
> +	iaa_wq = idxd_wq_get_private(wq);
> +	iaa_device = iaa_wq->iaa_device;
> +	idxd = iaa_device->idxd;
> +	pdev = idxd->pdev;
> +	dev = &pdev->dev;
> +
> +	active_compression_mode = get_iaa_device_compression_mode(iaa_device, ctx->mode);
> +
> +	idxd_desc = idxd_alloc_desc(wq, IDXD_OP_BLOCK);
> +	if (IS_ERR(idxd_desc)) {
> +		dev_dbg(dev, "idxd descriptor allocation failed\n");
> +		dev_dbg(dev, "iaa decompress failed: ret=%ld\n",
> +			PTR_ERR(idxd_desc));
> +		return PTR_ERR(idxd_desc);
> +	}
> +	desc = idxd_desc->iax_hw;
> +
> +	desc->flags = IDXD_OP_FLAG_CRAV | IDXD_OP_FLAG_RCR | IDXD_OP_FLAG_CC;
> +	desc->opcode = IAX_OPCODE_DECOMPRESS;
> +	desc->max_dst_size = PAGE_SIZE;
> +	desc->decompr_flags = IAA_DECOMP_FLAGS;
> +	desc->priv = 1;
> +
> +	desc->src1_addr = (u64)src_addr;
> +	desc->dst_addr = (u64)dst_addr;
> +	desc->max_dst_size = *dlen;
> +	desc->src1_size = slen;
> +	desc->completion_addr = idxd_desc->compl_dma;
> +
> +	dev_dbg(dev, "%s: decompression mode %s,"
> +		" desc->src1_addr %llx, desc->src1_size %d,"
> +		" desc->dst_addr %llx, desc->max_dst_size %d,"
> +		" desc->src2_addr %llx, desc->src2_size %d\n", __func__,
> +		active_compression_mode->name,
> +		desc->src1_addr, desc->src1_size, desc->dst_addr,
> +		desc->max_dst_size, desc->src2_addr, desc->src2_size);
> +
> +	ret = idxd_submit_desc(wq, idxd_desc);
> +	if (ret) {
> +		dev_dbg(dev, "submit_desc failed ret=%d\n", ret);
> +		goto err;
> +	}
> +
> +	ret = check_completion(dev, idxd_desc->iax_completion, false, false);
> +	if (ret) {
> +		dev_dbg(dev, "check_completion failed ret=%d\n", ret);
> +		goto err;
> +	}
> +
> +	*dlen = idxd_desc->iax_completion->output_size;
> +
> +	idxd_free_desc(wq, idxd_desc);
> +out:
> +	return ret;
> +err:
> +	idxd_free_desc(wq, idxd_desc);
> +	dev_dbg(dev, "iaa decompress failed: ret=%d\n", ret);
> +
> +	goto out;
> +}
> +
> +static int iaa_comp_acompress(struct acomp_req *req)
> +{
> +	struct iaa_compression_ctx *compression_ctx;
> +	struct crypto_tfm *tfm = req->base.tfm;
> +	dma_addr_t src_addr, dst_addr;
> +	int nr_sgs, cpu, ret = 0;
> +	struct iaa_wq *iaa_wq;
> +	u32 compression_crc;
> +	struct idxd_wq *wq;
> +	struct device *dev;
> +
> +	compression_ctx = crypto_tfm_ctx(tfm);
> +
> +	if (!iaa_crypto_enabled) {
> +		pr_debug("iaa_crypto disabled, not compressing\n");
> +		return -ENODEV;
> +	}
> +
> +	if (!req->src || !req->slen) {
> +		pr_debug("invalid src, not compressing\n");
> +		return -EINVAL;
> +	}
> +
> +	cpu = get_cpu();
> +	wq = wq_table_next_wq(cpu);
> +	put_cpu();
> +	if (!wq) {
> +		pr_debug("no wq configured for cpu=%d\n", cpu);
> +		return -ENODEV;
> +	}
> +
> +	ret = iaa_wq_get(wq);
> +	if (ret) {
> +		pr_debug("no wq available for cpu=%d\n", cpu);
> +		return -ENODEV;
> +	}
> +
> +	iaa_wq = idxd_wq_get_private(wq);
> +
> +	if (!req->dst) {
> +		gfp_t flags = req->flags & CRYPTO_TFM_REQ_MAY_SLEEP ? GFP_KERNEL : GFP_ATOMIC;
> +		/* incompressible data will always be < 2 * slen */
> +		req->dlen = 2 * req->slen;
2 * req->slen is an estimated size for dst buf. When slen is greater
than 2048 bytes, dlen is greater than 4096 bytes.
> +		req->dst = sgl_alloc(req->dlen, flags, NULL);
> +		if (!req->dst) {
> +			ret = -ENOMEM;
> +			goto out;
> +		}
> +	}
> +
> +	dev = &wq->idxd->pdev->dev;
> +
> +	nr_sgs = dma_map_sg(dev, req->src, sg_nents(req->src), DMA_TO_DEVICE);
> +	if (nr_sgs <= 0 || nr_sgs > 1) {
> +		dev_dbg(dev, "couldn't map src sg for iaa device %d,"
> +			" wq %d: ret=%d\n", iaa_wq->iaa_device->idxd->id,
> +			iaa_wq->wq->id, ret);
> +		ret = -EIO;
> +		goto out;
> +	}
> +	src_addr = sg_dma_address(req->src);
> +	dev_dbg(dev, "dma_map_sg, src_addr %llx, nr_sgs %d, req->src %p,"
> +		" req->slen %d, sg_dma_len(sg) %d\n", src_addr, nr_sgs,
> +		req->src, req->slen, sg_dma_len(req->src));
> +
> +	nr_sgs = dma_map_sg(dev, req->dst, sg_nents(req->dst), DMA_FROM_DEVICE);
> +	if (nr_sgs <= 0 || nr_sgs > 1) {
when dlen is greater than 4096 bytes, nr_sgs maybe greater than 1,
but the actual output size maybe less than 4096 bytes.
In other words, the condition nr_sgs > 1 may block a case which could
have been done.
> +		dev_dbg(dev, "couldn't map dst sg for iaa device %d,"
> +			" wq %d: ret=%d\n", iaa_wq->iaa_device->idxd->id,
> +			iaa_wq->wq->id, ret);
> +		ret = -EIO;
> +		goto err_map_dst;
> +	}
> +	dst_addr = sg_dma_address(req->dst);
> +	dev_dbg(dev, "dma_map_sg, dst_addr %llx, nr_sgs %d, req->dst %p,"
> +		" req->dlen %d, sg_dma_len(sg) %d\n", dst_addr, nr_sgs,
> +		req->dst, req->dlen, sg_dma_len(req->dst));
> +
> +	ret = iaa_compress(tfm, req, wq, src_addr, req->slen, dst_addr,
> +			   &req->dlen, &compression_crc, false);
> +	if (ret == -EINPROGRESS)
> +		return ret;
> +
> +	if (!ret && compression_ctx->verify_compress) {
> +		dma_sync_sg_for_device(dev, req->dst, 1, DMA_FROM_DEVICE);
> +		dma_sync_sg_for_device(dev, req->src, 1, DMA_TO_DEVICE);
> +		ret = iaa_compress_verify(tfm, req, wq, src_addr, req->slen,
> +					  dst_addr, &req->dlen, compression_crc);
> +	}
> +
> +	if (ret)
> +		dev_dbg(dev, "asynchronous compress failed ret=%d\n", ret);
> +
> +	dma_unmap_sg(dev, req->dst, sg_nents(req->dst), DMA_FROM_DEVICE);
> +err_map_dst:
> +	dma_unmap_sg(dev, req->src, sg_nents(req->src), DMA_TO_DEVICE);
> +out:
> +	iaa_wq_put(wq);
> +
> +	return ret;
> +}
> +
> +static int iaa_comp_adecompress_alloc_dest(struct acomp_req *req)
> +{
> +	gfp_t flags = req->flags & CRYPTO_TFM_REQ_MAY_SLEEP ?
> +		GFP_KERNEL : GFP_ATOMIC;
> +	struct crypto_tfm *tfm = req->base.tfm;
> +	dma_addr_t src_addr, dst_addr;
> +	int nr_sgs, cpu, ret = 0;
> +	struct iaa_wq *iaa_wq;
> +	struct device *dev;
> +	struct idxd_wq *wq;
> +
> +	cpu = get_cpu();
> +	wq = wq_table_next_wq(cpu);
> +	put_cpu();
> +	if (!wq) {
> +		pr_debug("no wq configured for cpu=%d\n", cpu);
> +		return -ENODEV;
> +	}
> +
> +	ret = iaa_wq_get(wq);
> +	if (ret) {
> +		pr_debug("no wq available for cpu=%d\n", cpu);
> +		return -ENODEV;
> +	}
> +
> +	iaa_wq = idxd_wq_get_private(wq);
> +
> +	dev = &wq->idxd->pdev->dev;
> +
> +	nr_sgs = dma_map_sg(dev, req->src, sg_nents(req->src), DMA_TO_DEVICE);
> +	if (nr_sgs <= 0 || nr_sgs > 1) {
> +		dev_dbg(dev, "couldn't map src sg for iaa device %d,"
> +			" wq %d: ret=%d\n", iaa_wq->iaa_device->idxd->id,
> +			iaa_wq->wq->id, ret);
> +		ret = -EIO;
> +		goto out;
> +	}
> +	src_addr = sg_dma_address(req->src);
> +	dev_dbg(dev, "dma_map_sg, src_addr %llx, nr_sgs %d, req->src %p,"
> +		" req->slen %d, sg_dma_len(sg) %d\n", src_addr, nr_sgs,
> +		req->src, req->slen, sg_dma_len(req->src));
> +
> +	req->dlen = 4 * req->slen; /* start with ~avg comp rato */
4 * req->slen is an estimated size for dst buf. When slen is greater
than 1024 bytes, dlen is greater than 4096 bytes.
> +alloc_dest:
> +	req->dst = sgl_alloc(req->dlen, flags, NULL);
> +	if (!req->dst) {
> +		ret = -ENOMEM;
> +		goto out;
> +	}
> +
> +	nr_sgs = dma_map_sg(dev, req->dst, sg_nents(req->dst), DMA_FROM_DEVICE);
> +	if (nr_sgs <= 0 || nr_sgs > 1) {
When dlen is greater than 4096 bytes, nr_sgs maybe greater than 1,
it may cause the src data compressed by iaa crypto can't be
decompressed by iaa crypto.
> +		dev_dbg(dev, "couldn't map dst sg for iaa device %d,"
> +			" wq %d: ret=%d\n", iaa_wq->iaa_device->idxd->id,
> +			iaa_wq->wq->id, ret);
> +		ret = -EIO;
> +		goto err_map_dst;
> +	}
> +
> +	dst_addr = sg_dma_address(req->dst);
> +	dev_dbg(dev, "dma_map_sg, dst_addr %llx, nr_sgs %d, req->dst %p,"
> +		" req->dlen %d, sg_dma_len(sg) %d\n", dst_addr, nr_sgs,
> +		req->dst, req->dlen, sg_dma_len(req->dst));
> +	ret = iaa_decompress(tfm, req, wq, src_addr, req->slen,
> +			     dst_addr, &req->dlen, true);
> +	if (ret == -EOVERFLOW) {
> +		dma_unmap_sg(dev, req->dst, sg_nents(req->dst), DMA_FROM_DEVICE);
> +		sgl_free(req->dst);
> +		req->dlen *= 2;
> +		if (req->dlen > CRYPTO_ACOMP_DST_MAX)
> +			goto err_map_dst;
> +		goto alloc_dest;
> +	}
> +
> +	if (ret != 0)
> +		dev_dbg(dev, "asynchronous decompress failed ret=%d\n", ret);
> +
> +	dma_unmap_sg(dev, req->dst, sg_nents(req->dst), DMA_FROM_DEVICE);
> +err_map_dst:
> +	dma_unmap_sg(dev, req->src, sg_nents(req->src), DMA_TO_DEVICE);
> +out:
> +	iaa_wq_put(wq);
> +
> +	return ret;
> +}
> +
> +static int iaa_comp_adecompress(struct acomp_req *req)
> +{
> +	struct crypto_tfm *tfm = req->base.tfm;
> +	dma_addr_t src_addr, dst_addr;
> +	int nr_sgs, cpu, ret = 0;
> +	struct iaa_wq *iaa_wq;
> +	struct device *dev;
> +	struct idxd_wq *wq;
> +
> +	if (!iaa_crypto_enabled) {
> +		pr_debug("iaa_crypto disabled, not decompressing\n");
> +		return -ENODEV;
> +	}
> +
> +	if (!req->src || !req->slen) {
> +		pr_debug("invalid src, not decompressing\n");
> +		return -EINVAL;
> +	}
> +
> +	if (!req->dst)
> +		return iaa_comp_adecompress_alloc_dest(req);
> +
> +	cpu = get_cpu();
> +	wq = wq_table_next_wq(cpu);
> +	put_cpu();
> +	if (!wq) {
> +		pr_debug("no wq configured for cpu=%d\n", cpu);
> +		return -ENODEV;
> +	}
> +
> +	ret = iaa_wq_get(wq);
> +	if (ret) {
> +		pr_debug("no wq available for cpu=%d\n", cpu);
> +		return -ENODEV;
> +	}
> +
> +	iaa_wq = idxd_wq_get_private(wq);
> +
> +	dev = &wq->idxd->pdev->dev;
> +
> +	nr_sgs = dma_map_sg(dev, req->src, sg_nents(req->src), DMA_TO_DEVICE);
> +	if (nr_sgs <= 0 || nr_sgs > 1) {
> +		dev_dbg(dev, "couldn't map src sg for iaa device %d,"
> +			" wq %d: ret=%d\n", iaa_wq->iaa_device->idxd->id,
> +			iaa_wq->wq->id, ret);
> +		ret = -EIO;
> +		goto out;
> +	}
> +	src_addr = sg_dma_address(req->src);
> +	dev_dbg(dev, "dma_map_sg, src_addr %llx, nr_sgs %d, req->src %p,"
> +		" req->slen %d, sg_dma_len(sg) %d\n", src_addr, nr_sgs,
> +		req->src, req->slen, sg_dma_len(req->src));
> +
> +	nr_sgs = dma_map_sg(dev, req->dst, sg_nents(req->dst), DMA_FROM_DEVICE);
> +	if (nr_sgs <= 0 || nr_sgs > 1) {
> +		dev_dbg(dev, "couldn't map dst sg for iaa device %d,"
> +			" wq %d: ret=%d\n", iaa_wq->iaa_device->idxd->id,
> +			iaa_wq->wq->id, ret);
> +		ret = -EIO;
> +		goto err_map_dst;
> +	}
> +	dst_addr = sg_dma_address(req->dst);
> +	dev_dbg(dev, "dma_map_sg, dst_addr %llx, nr_sgs %d, req->dst %p,"
> +		" req->dlen %d, sg_dma_len(sg) %d\n", dst_addr, nr_sgs,
> +		req->dst, req->dlen, sg_dma_len(req->dst));
> +
> +	ret = iaa_decompress(tfm, req, wq, src_addr, req->slen,
> +			     dst_addr, &req->dlen, false);
> +	if (ret == -EINPROGRESS)
> +		return ret;
> +
> +	if (ret != 0)
> +		dev_dbg(dev, "asynchronous decompress failed ret=%d\n", ret);
> +
> +	dma_unmap_sg(dev, req->dst, sg_nents(req->dst), DMA_FROM_DEVICE);
> +err_map_dst:
> +	dma_unmap_sg(dev, req->src, sg_nents(req->src), DMA_TO_DEVICE);
> +out:
> +	iaa_wq_put(wq);
> +
> +	return ret;
> +}
> +
> +static void compression_ctx_init(struct iaa_compression_ctx *ctx)
> +{
> +	ctx->verify_compress = iaa_verify_compress;
> +}
> +
> +static int iaa_comp_init_fixed(struct crypto_acomp *acomp_tfm)
> +{
> +	struct crypto_tfm *tfm = crypto_acomp_tfm(acomp_tfm);
> +	struct iaa_compression_ctx *ctx = crypto_tfm_ctx(tfm);
> +
> +	compression_ctx_init(ctx);
> +
> +	ctx->mode = IAA_MODE_FIXED;
> +
> +	return 0;
> +}
> +
> +static struct acomp_alg iaa_acomp_fixed_deflate = {
> +	.init			= iaa_comp_init_fixed,
> +	.compress		= iaa_comp_acompress,
> +	.decompress		= iaa_comp_adecompress,
> +	.dst_free		= sgl_free,
> +	.base			= {
> +		.cra_name		= "deflate-iaa",
> +		.cra_driver_name	= "deflate_iaa",
> +		.cra_ctxsize		= sizeof(struct iaa_compression_ctx),
> +		.cra_module		= THIS_MODULE,
> +	}
> +};
> +
> +static int iaa_register_compression_device(void)
> +{
> +	int ret;
> +
> +	ret = crypto_register_acomp(&iaa_acomp_fixed_deflate);
> +	if (ret) {
> +		pr_err("deflate algorithm acomp fixed registration failed (%d)\n", ret);
> +		goto out;
> +	}
> +
> +	iaa_crypto_registered = true;
> +out:
> +	return ret;
> +}
> +
> +static int iaa_unregister_compression_device(void)
> +{
> +	if (iaa_crypto_registered)
> +		crypto_unregister_acomp(&iaa_acomp_fixed_deflate);
> +
> +	return 0;
> +}
> +
>  static int iaa_crypto_probe(struct idxd_dev *idxd_dev)
>  {
>  	struct idxd_wq *wq = idxd_dev_to_wq(idxd_dev);
> @@ -741,6 +1564,11 @@ static int iaa_crypto_probe(struct idxd_dev *idxd_dev)
>  
>  	mutex_lock(&wq->wq_lock);
>  
> +	if (idxd_wq_get_private(wq)) {
> +		mutex_unlock(&wq->wq_lock);
> +		return -EBUSY;
> +	}
> +
>  	if (!idxd_wq_driver_name_match(wq, dev)) {
>  		dev_dbg(dev, "wq %d.%d driver_name match failed: wq driver_name %s, dev driver name %s\n",
>  			idxd->id, wq->id, wq->driver_name, dev->driver->name);
> @@ -774,12 +1602,28 @@ static int iaa_crypto_probe(struct idxd_dev *idxd_dev)
>  
>  	rebalance_wq_table();
>  
> +	if (first_wq) {
> +		iaa_crypto_enabled = true;
> +		ret = iaa_register_compression_device();
> +		if (ret != 0) {
> +			iaa_crypto_enabled = false;
> +			dev_dbg(dev, "IAA compression device registration failed\n");
> +			goto err_register;
> +		}
> +		try_module_get(THIS_MODULE);
> +
> +		pr_info("iaa_crypto now ENABLED\n");
> +	}
> +
>  	mutex_unlock(&iaa_devices_lock);
>  out:
>  	mutex_unlock(&wq->wq_lock);
>  
>  	return ret;
>  
> +err_register:
> +	remove_iaa_wq(wq);
> +	free_iaa_wq(idxd_wq_get_private(wq));
>  err_save:
>  	if (first_wq)
>  		free_wq_table();
> @@ -795,6 +1639,9 @@ static int iaa_crypto_probe(struct idxd_dev *idxd_dev)
>  static void iaa_crypto_remove(struct idxd_dev *idxd_dev)
>  {
>  	struct idxd_wq *wq = idxd_dev_to_wq(idxd_dev);
> +	struct idxd_device *idxd = wq->idxd;
> +	struct iaa_wq *iaa_wq;
> +	bool free = false;
>  
>  	idxd_wq_quiesce(wq);
>  
> @@ -802,11 +1649,37 @@ static void iaa_crypto_remove(struct idxd_dev *idxd_dev)
>  	mutex_lock(&iaa_devices_lock);
>  
>  	remove_iaa_wq(wq);
> +
> +	spin_lock(&idxd->dev_lock);
> +	iaa_wq = idxd_wq_get_private(wq);
> +	if (!iaa_wq) {
> +		pr_err("%s: no iaa_wq available to remove\n", __func__);
> +		return;
> +	}
> +
> +	if (iaa_wq->ref) {
> +		iaa_wq->remove = true;
> +	} else {
> +		wq = iaa_wq->wq;
> +		__free_iaa_wq(iaa_wq);
> +		idxd_wq_set_private(wq, NULL);
> +		free = true;
> +	}
> +	spin_unlock(&idxd->dev_lock);
> +
> +	if (free)
> +		kfree(iaa_wq);
> +
>  	drv_disable_wq(wq);
>  	rebalance_wq_table();
>  
> -	if (nr_iaa == 0)
> +	if (nr_iaa == 0) {
> +		iaa_crypto_enabled = false;
>  		free_wq_table();
> +		module_put(THIS_MODULE);
> +
> +		pr_info("iaa_crypto now DISABLED\n");
> +	}
>  
>  	mutex_unlock(&iaa_devices_lock);
>  	mutex_unlock(&wq->wq_lock);
> @@ -844,10 +1717,19 @@ static int __init iaa_crypto_init_module(void)
>  		goto err_driver_reg;
>  	}
>  
> +	ret = driver_create_file(&iaa_crypto_driver.drv,
> +				 &driver_attr_verify_compress);
> +	if (ret) {
> +		pr_debug("IAA verify_compress attr creation failed\n");
> +		goto err_verify_attr_create;
> +	}
> +
>  	pr_debug("initialized\n");
>  out:
>  	return ret;
>  
> +err_verify_attr_create:
> +	idxd_driver_unregister(&iaa_crypto_driver);
>  err_driver_reg:
>  	iaa_aecs_cleanup_fixed();
>  
> @@ -856,6 +1738,11 @@ static int __init iaa_crypto_init_module(void)
>  
>  static void __exit iaa_crypto_cleanup_module(void)
>  {
> +	if (iaa_unregister_compression_device())
> +		pr_debug("IAA compression device unregister failed\n");
> +
> +	driver_remove_file(&iaa_crypto_driver.drv,
> +			   &driver_attr_verify_compress);
>  	idxd_driver_unregister(&iaa_crypto_driver);
>  	iaa_aecs_cleanup_fixed();
>  
> -- 
> 2.34.1
> 

Thanks.
Rex Zhang

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ