xref: /kernel/linux/linux-5.10/drivers/crypto/qce/dma.c (revision 8c2ecf20)
18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright (c) 2012-2014, The Linux Foundation. All rights reserved.
48c2ecf20Sopenharmony_ci */
58c2ecf20Sopenharmony_ci
68c2ecf20Sopenharmony_ci#include <linux/dmaengine.h>
78c2ecf20Sopenharmony_ci#include <crypto/scatterwalk.h>
88c2ecf20Sopenharmony_ci
98c2ecf20Sopenharmony_ci#include "dma.h"
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_ciint qce_dma_request(struct device *dev, struct qce_dma_data *dma)
128c2ecf20Sopenharmony_ci{
138c2ecf20Sopenharmony_ci	int ret;
148c2ecf20Sopenharmony_ci
158c2ecf20Sopenharmony_ci	dma->txchan = dma_request_chan(dev, "tx");
168c2ecf20Sopenharmony_ci	if (IS_ERR(dma->txchan))
178c2ecf20Sopenharmony_ci		return PTR_ERR(dma->txchan);
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ci	dma->rxchan = dma_request_chan(dev, "rx");
208c2ecf20Sopenharmony_ci	if (IS_ERR(dma->rxchan)) {
218c2ecf20Sopenharmony_ci		ret = PTR_ERR(dma->rxchan);
228c2ecf20Sopenharmony_ci		goto error_rx;
238c2ecf20Sopenharmony_ci	}
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_ci	dma->result_buf = kmalloc(QCE_RESULT_BUF_SZ + QCE_IGNORE_BUF_SZ,
268c2ecf20Sopenharmony_ci				  GFP_KERNEL);
278c2ecf20Sopenharmony_ci	if (!dma->result_buf) {
288c2ecf20Sopenharmony_ci		ret = -ENOMEM;
298c2ecf20Sopenharmony_ci		goto error_nomem;
308c2ecf20Sopenharmony_ci	}
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_ci	dma->ignore_buf = dma->result_buf + QCE_RESULT_BUF_SZ;
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_ci	return 0;
358c2ecf20Sopenharmony_cierror_nomem:
368c2ecf20Sopenharmony_ci	dma_release_channel(dma->rxchan);
378c2ecf20Sopenharmony_cierror_rx:
388c2ecf20Sopenharmony_ci	dma_release_channel(dma->txchan);
398c2ecf20Sopenharmony_ci	return ret;
408c2ecf20Sopenharmony_ci}
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_civoid qce_dma_release(struct qce_dma_data *dma)
438c2ecf20Sopenharmony_ci{
448c2ecf20Sopenharmony_ci	dma_release_channel(dma->txchan);
458c2ecf20Sopenharmony_ci	dma_release_channel(dma->rxchan);
468c2ecf20Sopenharmony_ci	kfree(dma->result_buf);
478c2ecf20Sopenharmony_ci}
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_cistruct scatterlist *
508c2ecf20Sopenharmony_ciqce_sgtable_add(struct sg_table *sgt, struct scatterlist *new_sgl,
518c2ecf20Sopenharmony_ci		unsigned int max_len)
528c2ecf20Sopenharmony_ci{
538c2ecf20Sopenharmony_ci	struct scatterlist *sg = sgt->sgl, *sg_last = NULL;
548c2ecf20Sopenharmony_ci	unsigned int new_len;
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_ci	while (sg) {
578c2ecf20Sopenharmony_ci		if (!sg_page(sg))
588c2ecf20Sopenharmony_ci			break;
598c2ecf20Sopenharmony_ci		sg = sg_next(sg);
608c2ecf20Sopenharmony_ci	}
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_ci	if (!sg)
638c2ecf20Sopenharmony_ci		return ERR_PTR(-EINVAL);
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_ci	while (new_sgl && sg && max_len) {
668c2ecf20Sopenharmony_ci		new_len = new_sgl->length > max_len ? max_len : new_sgl->length;
678c2ecf20Sopenharmony_ci		sg_set_page(sg, sg_page(new_sgl), new_len, new_sgl->offset);
688c2ecf20Sopenharmony_ci		sg_last = sg;
698c2ecf20Sopenharmony_ci		sg = sg_next(sg);
708c2ecf20Sopenharmony_ci		new_sgl = sg_next(new_sgl);
718c2ecf20Sopenharmony_ci		max_len -= new_len;
728c2ecf20Sopenharmony_ci	}
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_ci	return sg_last;
758c2ecf20Sopenharmony_ci}
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_cistatic int qce_dma_prep_sg(struct dma_chan *chan, struct scatterlist *sg,
788c2ecf20Sopenharmony_ci			   int nents, unsigned long flags,
798c2ecf20Sopenharmony_ci			   enum dma_transfer_direction dir,
808c2ecf20Sopenharmony_ci			   dma_async_tx_callback cb, void *cb_param)
818c2ecf20Sopenharmony_ci{
828c2ecf20Sopenharmony_ci	struct dma_async_tx_descriptor *desc;
838c2ecf20Sopenharmony_ci	dma_cookie_t cookie;
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_ci	if (!sg || !nents)
868c2ecf20Sopenharmony_ci		return -EINVAL;
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_ci	desc = dmaengine_prep_slave_sg(chan, sg, nents, dir, flags);
898c2ecf20Sopenharmony_ci	if (!desc)
908c2ecf20Sopenharmony_ci		return -EINVAL;
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_ci	desc->callback = cb;
938c2ecf20Sopenharmony_ci	desc->callback_param = cb_param;
948c2ecf20Sopenharmony_ci	cookie = dmaengine_submit(desc);
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_ci	return dma_submit_error(cookie);
978c2ecf20Sopenharmony_ci}
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_ciint qce_dma_prep_sgs(struct qce_dma_data *dma, struct scatterlist *rx_sg,
1008c2ecf20Sopenharmony_ci		     int rx_nents, struct scatterlist *tx_sg, int tx_nents,
1018c2ecf20Sopenharmony_ci		     dma_async_tx_callback cb, void *cb_param)
1028c2ecf20Sopenharmony_ci{
1038c2ecf20Sopenharmony_ci	struct dma_chan *rxchan = dma->rxchan;
1048c2ecf20Sopenharmony_ci	struct dma_chan *txchan = dma->txchan;
1058c2ecf20Sopenharmony_ci	unsigned long flags = DMA_PREP_INTERRUPT | DMA_CTRL_ACK;
1068c2ecf20Sopenharmony_ci	int ret;
1078c2ecf20Sopenharmony_ci
1088c2ecf20Sopenharmony_ci	ret = qce_dma_prep_sg(rxchan, rx_sg, rx_nents, flags, DMA_MEM_TO_DEV,
1098c2ecf20Sopenharmony_ci			     NULL, NULL);
1108c2ecf20Sopenharmony_ci	if (ret)
1118c2ecf20Sopenharmony_ci		return ret;
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_ci	return qce_dma_prep_sg(txchan, tx_sg, tx_nents, flags, DMA_DEV_TO_MEM,
1148c2ecf20Sopenharmony_ci			       cb, cb_param);
1158c2ecf20Sopenharmony_ci}
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_civoid qce_dma_issue_pending(struct qce_dma_data *dma)
1188c2ecf20Sopenharmony_ci{
1198c2ecf20Sopenharmony_ci	dma_async_issue_pending(dma->rxchan);
1208c2ecf20Sopenharmony_ci	dma_async_issue_pending(dma->txchan);
1218c2ecf20Sopenharmony_ci}
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_ciint qce_dma_terminate_all(struct qce_dma_data *dma)
1248c2ecf20Sopenharmony_ci{
1258c2ecf20Sopenharmony_ci	int ret;
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_ci	ret = dmaengine_terminate_all(dma->rxchan);
1288c2ecf20Sopenharmony_ci	return ret ?: dmaengine_terminate_all(dma->txchan);
1298c2ecf20Sopenharmony_ci}
130