// SPDX-License-Identifier: GPL-2.0-only /* Copyright(c) 2014 - 2022 Intel Corporation */ #include #include #include #include #include #include #include "adf_accel_devices.h" #include "qat_bl.h" #include "qat_crypto.h" void qat_bl_free_bufl(struct adf_accel_dev *accel_dev, struct qat_request_buffs *buf) { struct device *dev = &GET_DEV(accel_dev); struct qat_alg_buf_list *bl = buf->bl; struct qat_alg_buf_list *blout = buf->blout; dma_addr_t blp = buf->blp; dma_addr_t blpout = buf->bloutp; size_t sz = buf->sz; size_t sz_out = buf->sz_out; int bl_dma_dir; int i; bl_dma_dir = blp != blpout ? DMA_TO_DEVICE : DMA_BIDIRECTIONAL; for (i = 0; i < bl->num_bufs; i++) dma_unmap_single(dev, bl->buffers[i].addr, bl->buffers[i].len, bl_dma_dir); dma_unmap_single(dev, blp, sz, DMA_TO_DEVICE); if (!buf->sgl_src_valid) kfree(bl); if (blp != blpout) { for (i = 0; i < blout->num_mapped_bufs; i++) { dma_unmap_single(dev, blout->buffers[i].addr, blout->buffers[i].len, DMA_FROM_DEVICE); } dma_unmap_single(dev, blpout, sz_out, DMA_TO_DEVICE); if (!buf->sgl_dst_valid) kfree(blout); } } static int __qat_bl_sgl_to_bufl(struct adf_accel_dev *accel_dev, struct scatterlist *sgl, struct scatterlist *sglout, struct qat_request_buffs *buf, dma_addr_t extra_dst_buff, size_t sz_extra_dst_buff, unsigned int sskip, unsigned int dskip, gfp_t flags) { struct device *dev = &GET_DEV(accel_dev); int i, sg_nctr = 0; int n = sg_nents(sgl); struct qat_alg_buf_list *bufl; struct qat_alg_buf_list *buflout = NULL; dma_addr_t blp = DMA_MAPPING_ERROR; dma_addr_t bloutp = DMA_MAPPING_ERROR; struct scatterlist *sg; size_t sz_out, sz = struct_size(bufl, buffers, n); int node = dev_to_node(&GET_DEV(accel_dev)); unsigned int left; int bufl_dma_dir; if (unlikely(!n)) return -EINVAL; buf->sgl_src_valid = false; buf->sgl_dst_valid = false; if (n > QAT_MAX_BUFF_DESC) { bufl = kzalloc_node(sz, flags, node); if (unlikely(!bufl)) return -ENOMEM; } else { bufl = &buf->sgl_src.sgl_hdr; memset(bufl, 0, sizeof(struct qat_alg_buf_list)); buf->sgl_src_valid = true; } bufl_dma_dir = sgl != sglout ? DMA_TO_DEVICE : DMA_BIDIRECTIONAL; for (i = 0; i < n; i++) bufl->buffers[i].addr = DMA_MAPPING_ERROR; left = sskip; for_each_sg(sgl, sg, n, i) { int y = sg_nctr; if (!sg->length) continue; if (left >= sg->length) { left -= sg->length; continue; } bufl->buffers[y].addr = dma_map_single(dev, sg_virt(sg) + left, sg->length - left, bufl_dma_dir); bufl->buffers[y].len = sg->length; if (unlikely(dma_mapping_error(dev, bufl->buffers[y].addr))) goto err_in; sg_nctr++; if (left) { bufl->buffers[y].len -= left; left = 0; } } bufl->num_bufs = sg_nctr; blp = dma_map_single(dev, bufl, sz, DMA_TO_DEVICE); if (unlikely(dma_mapping_error(dev, blp))) goto err_in; buf->bl = bufl; buf->blp = blp; buf->sz = sz; /* Handle out of place operation */ if (sgl != sglout) { struct qat_alg_buf *buffers; int extra_buff = extra_dst_buff ? 1 : 0; int n_sglout = sg_nents(sglout); n = n_sglout + extra_buff; sz_out = struct_size(buflout, buffers, n); left = dskip; sg_nctr = 0; if (n > QAT_MAX_BUFF_DESC) { buflout = kzalloc_node(sz_out, flags, node); if (unlikely(!buflout)) goto err_in; } else { buflout = &buf->sgl_dst.sgl_hdr; memset(buflout, 0, sizeof(struct qat_alg_buf_list)); buf->sgl_dst_valid = true; } buffers = buflout->buffers; for (i = 0; i < n; i++) buffers[i].addr = DMA_MAPPING_ERROR; for_each_sg(sglout, sg, n_sglout, i) { int y = sg_nctr; if (!sg->length) continue; if (left >= sg->length) { left -= sg->length; continue; } buffers[y].addr = dma_map_single(dev, sg_virt(sg) + left, sg->length - left, DMA_FROM_DEVICE); if (unlikely(dma_mapping_error(dev, buffers[y].addr))) goto err_out; buffers[y].len = sg->length; sg_nctr++; if (left) { buffers[y].len -= left; left = 0; } } if (extra_buff) { buffers[sg_nctr].addr = extra_dst_buff; buffers[sg_nctr].len = sz_extra_dst_buff; } buflout->num_bufs = sg_nctr; buflout->num_bufs += extra_buff; buflout->num_mapped_bufs = sg_nctr; bloutp = dma_map_single(dev, buflout, sz_out, DMA_TO_DEVICE); if (unlikely(dma_mapping_error(dev, bloutp))) goto err_out; buf->blout = buflout; buf->bloutp = bloutp; buf->sz_out = sz_out; } else { /* Otherwise set the src and dst to the same address */ buf->bloutp = buf->blp; buf->sz_out = 0; } return 0; err_out: if (!dma_mapping_error(dev, bloutp)) dma_unmap_single(dev, bloutp, sz_out, DMA_TO_DEVICE); n = sg_nents(sglout); for (i = 0; i < n; i++) { if (buflout->buffers[i].addr == extra_dst_buff) break; if (!dma_mapping_error(dev, buflout->buffers[i].addr)) dma_unmap_single(dev, buflout->buffers[i].addr, buflout->buffers[i].len, DMA_FROM_DEVICE); } if (!buf->sgl_dst_valid) kfree(buflout); err_in: if (!dma_mapping_error(dev, blp)) dma_unmap_single(dev, blp, sz, DMA_TO_DEVICE); n = sg_nents(sgl); for (i = 0; i < n; i++) if (!dma_mapping_error(dev, bufl->buffers[i].addr)) dma_unmap_single(dev, bufl->buffers[i].addr, bufl->buffers[i].len, bufl_dma_dir); if (!buf->sgl_src_valid) kfree(bufl); dev_err(dev, "Failed to map buf for dma\n"); return -ENOMEM; } int qat_bl_sgl_to_bufl(struct adf_accel_dev *accel_dev, struct scatterlist *sgl, struct scatterlist *sglout, struct qat_request_buffs *buf, struct qat_sgl_to_bufl_params *params, gfp_t flags) { dma_addr_t extra_dst_buff = 0; size_t sz_extra_dst_buff = 0; unsigned int sskip = 0; unsigned int dskip = 0; if (params) { extra_dst_buff = params->extra_dst_buff; sz_extra_dst_buff = params->sz_extra_dst_buff; sskip = params->sskip; dskip = params->dskip; } return __qat_bl_sgl_to_bufl(accel_dev, sgl, sglout, buf, extra_dst_buff, sz_extra_dst_buff, sskip, dskip, flags); } static void qat_bl_sgl_unmap(struct adf_accel_dev *accel_dev, struct qat_alg_buf_list *bl) { struct device *dev = &GET_DEV(accel_dev); int n = bl->num_bufs; int i; for (i = 0; i < n; i++) if (!dma_mapping_error(dev, bl->buffers[i].addr)) dma_unmap_single(dev, bl->buffers[i].addr, bl->buffers[i].len, DMA_FROM_DEVICE); } static int qat_bl_sgl_map(struct adf_accel_dev *accel_dev, struct scatterlist *sgl, struct qat_alg_buf_list **bl) { struct device *dev = &GET_DEV(accel_dev); struct qat_alg_buf_list *bufl; int node = dev_to_node(dev); struct scatterlist *sg; int n, i, sg_nctr; size_t sz; n = sg_nents(sgl); sz = struct_size(bufl, buffers, n); bufl = kzalloc_node(sz, GFP_KERNEL, node); if (unlikely(!bufl)) return -ENOMEM; for (i = 0; i < n; i++) bufl->buffers[i].addr = DMA_MAPPING_ERROR; sg_nctr = 0; for_each_sg(sgl, sg, n, i) { int y = sg_nctr; if (!sg->length) continue; bufl->buffers[y].addr = dma_map_single(dev, sg_virt(sg), sg->length, DMA_FROM_DEVICE); bufl->buffers[y].len = sg->length; if (unlikely(dma_mapping_error(dev, bufl->buffers[y].addr))) goto err_map; sg_nctr++; } bufl->num_bufs = sg_nctr; bufl->num_mapped_bufs = sg_nctr; *bl = bufl; return 0; err_map: for (i = 0; i < n; i++) if (!dma_mapping_error(dev, bufl->buffers[i].addr)) dma_unmap_single(dev, bufl->buffers[i].addr, bufl->buffers[i].len, DMA_FROM_DEVICE); kfree(bufl); *bl = NULL; return -ENOMEM; } static void qat_bl_sgl_free_unmap(struct adf_accel_dev *accel_dev, struct scatterlist *sgl, struct qat_alg_buf_list *bl, bool free_bl) { if (bl) { qat_bl_sgl_unmap(accel_dev, bl); if (free_bl) kfree(bl); } if (sgl) sgl_free(sgl); } static int qat_bl_sgl_alloc_map(struct adf_accel_dev *accel_dev, struct scatterlist **sgl, struct qat_alg_buf_list **bl, unsigned int dlen, gfp_t gfp) { struct scatterlist *dst; int ret; dst = sgl_alloc(dlen, gfp, NULL); if (!dst) { dev_err(&GET_DEV(accel_dev), "sg_alloc failed\n"); return -ENOMEM; } ret = qat_bl_sgl_map(accel_dev, dst, bl); if (ret) goto err; *sgl = dst; return 0; err: sgl_free(dst); *sgl = NULL; return ret; } int qat_bl_realloc_map_new_dst(struct adf_accel_dev *accel_dev, struct scatterlist **sg, unsigned int dlen, struct qat_request_buffs *qat_bufs, gfp_t gfp) { struct device *dev = &GET_DEV(accel_dev); dma_addr_t new_blp = DMA_MAPPING_ERROR; struct qat_alg_buf_list *new_bl; struct scatterlist *new_sg; size_t new_bl_size; int ret; ret = qat_bl_sgl_alloc_map(accel_dev, &new_sg, &new_bl, dlen, gfp); if (ret) return ret; new_bl_size = struct_size(new_bl, buffers, new_bl->num_bufs); /* Map new firmware SGL descriptor */ new_blp = dma_map_single(dev, new_bl, new_bl_size, DMA_TO_DEVICE); if (unlikely(dma_mapping_error(dev, new_blp))) goto err; /* Unmap old firmware SGL descriptor */ dma_unmap_single(dev, qat_bufs->bloutp, qat_bufs->sz_out, DMA_TO_DEVICE); /* Free and unmap old scatterlist */ qat_bl_sgl_free_unmap(accel_dev, *sg, qat_bufs->blout, !qat_bufs->sgl_dst_valid); qat_bufs->sgl_dst_valid = false; qat_bufs->blout = new_bl; qat_bufs->bloutp = new_blp; qat_bufs->sz_out = new_bl_size; *sg = new_sg; return 0; err: qat_bl_sgl_free_unmap(accel_dev, new_sg, new_bl, true); if (!dma_mapping_error(dev, new_blp)) dma_unmap_single(dev, new_blp, new_bl_size, DMA_TO_DEVICE); return -ENOMEM; }