162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (c) 2012-2014, The Linux Foundation. All rights reserved.
462306a36Sopenharmony_ci */
562306a36Sopenharmony_ci
662306a36Sopenharmony_ci#include <linux/dmaengine.h>
762306a36Sopenharmony_ci#include <crypto/scatterwalk.h>
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#include "dma.h"
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ciint qce_dma_request(struct device *dev, struct qce_dma_data *dma)
1262306a36Sopenharmony_ci{
1362306a36Sopenharmony_ci	int ret;
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ci	dma->txchan = dma_request_chan(dev, "tx");
1662306a36Sopenharmony_ci	if (IS_ERR(dma->txchan))
1762306a36Sopenharmony_ci		return PTR_ERR(dma->txchan);
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ci	dma->rxchan = dma_request_chan(dev, "rx");
2062306a36Sopenharmony_ci	if (IS_ERR(dma->rxchan)) {
2162306a36Sopenharmony_ci		ret = PTR_ERR(dma->rxchan);
2262306a36Sopenharmony_ci		goto error_rx;
2362306a36Sopenharmony_ci	}
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci	dma->result_buf = kmalloc(QCE_RESULT_BUF_SZ + QCE_IGNORE_BUF_SZ,
2662306a36Sopenharmony_ci				  GFP_KERNEL);
2762306a36Sopenharmony_ci	if (!dma->result_buf) {
2862306a36Sopenharmony_ci		ret = -ENOMEM;
2962306a36Sopenharmony_ci		goto error_nomem;
3062306a36Sopenharmony_ci	}
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci	dma->ignore_buf = dma->result_buf + QCE_RESULT_BUF_SZ;
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci	return 0;
3562306a36Sopenharmony_cierror_nomem:
3662306a36Sopenharmony_ci	dma_release_channel(dma->rxchan);
3762306a36Sopenharmony_cierror_rx:
3862306a36Sopenharmony_ci	dma_release_channel(dma->txchan);
3962306a36Sopenharmony_ci	return ret;
4062306a36Sopenharmony_ci}
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_civoid qce_dma_release(struct qce_dma_data *dma)
4362306a36Sopenharmony_ci{
4462306a36Sopenharmony_ci	dma_release_channel(dma->txchan);
4562306a36Sopenharmony_ci	dma_release_channel(dma->rxchan);
4662306a36Sopenharmony_ci	kfree(dma->result_buf);
4762306a36Sopenharmony_ci}
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_cistruct scatterlist *
5062306a36Sopenharmony_ciqce_sgtable_add(struct sg_table *sgt, struct scatterlist *new_sgl,
5162306a36Sopenharmony_ci		unsigned int max_len)
5262306a36Sopenharmony_ci{
5362306a36Sopenharmony_ci	struct scatterlist *sg = sgt->sgl, *sg_last = NULL;
5462306a36Sopenharmony_ci	unsigned int new_len;
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ci	while (sg) {
5762306a36Sopenharmony_ci		if (!sg_page(sg))
5862306a36Sopenharmony_ci			break;
5962306a36Sopenharmony_ci		sg = sg_next(sg);
6062306a36Sopenharmony_ci	}
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ci	if (!sg)
6362306a36Sopenharmony_ci		return ERR_PTR(-EINVAL);
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_ci	while (new_sgl && sg && max_len) {
6662306a36Sopenharmony_ci		new_len = new_sgl->length > max_len ? max_len : new_sgl->length;
6762306a36Sopenharmony_ci		sg_set_page(sg, sg_page(new_sgl), new_len, new_sgl->offset);
6862306a36Sopenharmony_ci		sg_last = sg;
6962306a36Sopenharmony_ci		sg = sg_next(sg);
7062306a36Sopenharmony_ci		new_sgl = sg_next(new_sgl);
7162306a36Sopenharmony_ci		max_len -= new_len;
7262306a36Sopenharmony_ci	}
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ci	return sg_last;
7562306a36Sopenharmony_ci}
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_cistatic int qce_dma_prep_sg(struct dma_chan *chan, struct scatterlist *sg,
7862306a36Sopenharmony_ci			   int nents, unsigned long flags,
7962306a36Sopenharmony_ci			   enum dma_transfer_direction dir,
8062306a36Sopenharmony_ci			   dma_async_tx_callback cb, void *cb_param)
8162306a36Sopenharmony_ci{
8262306a36Sopenharmony_ci	struct dma_async_tx_descriptor *desc;
8362306a36Sopenharmony_ci	dma_cookie_t cookie;
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci	if (!sg || !nents)
8662306a36Sopenharmony_ci		return -EINVAL;
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci	desc = dmaengine_prep_slave_sg(chan, sg, nents, dir, flags);
8962306a36Sopenharmony_ci	if (!desc)
9062306a36Sopenharmony_ci		return -EINVAL;
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ci	desc->callback = cb;
9362306a36Sopenharmony_ci	desc->callback_param = cb_param;
9462306a36Sopenharmony_ci	cookie = dmaengine_submit(desc);
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ci	return dma_submit_error(cookie);
9762306a36Sopenharmony_ci}
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_ciint qce_dma_prep_sgs(struct qce_dma_data *dma, struct scatterlist *rx_sg,
10062306a36Sopenharmony_ci		     int rx_nents, struct scatterlist *tx_sg, int tx_nents,
10162306a36Sopenharmony_ci		     dma_async_tx_callback cb, void *cb_param)
10262306a36Sopenharmony_ci{
10362306a36Sopenharmony_ci	struct dma_chan *rxchan = dma->rxchan;
10462306a36Sopenharmony_ci	struct dma_chan *txchan = dma->txchan;
10562306a36Sopenharmony_ci	unsigned long flags = DMA_PREP_INTERRUPT | DMA_CTRL_ACK;
10662306a36Sopenharmony_ci	int ret;
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci	ret = qce_dma_prep_sg(rxchan, rx_sg, rx_nents, flags, DMA_MEM_TO_DEV,
10962306a36Sopenharmony_ci			     NULL, NULL);
11062306a36Sopenharmony_ci	if (ret)
11162306a36Sopenharmony_ci		return ret;
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_ci	return qce_dma_prep_sg(txchan, tx_sg, tx_nents, flags, DMA_DEV_TO_MEM,
11462306a36Sopenharmony_ci			       cb, cb_param);
11562306a36Sopenharmony_ci}
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_civoid qce_dma_issue_pending(struct qce_dma_data *dma)
11862306a36Sopenharmony_ci{
11962306a36Sopenharmony_ci	dma_async_issue_pending(dma->rxchan);
12062306a36Sopenharmony_ci	dma_async_issue_pending(dma->txchan);
12162306a36Sopenharmony_ci}
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_ciint qce_dma_terminate_all(struct qce_dma_data *dma)
12462306a36Sopenharmony_ci{
12562306a36Sopenharmony_ci	int ret;
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_ci	ret = dmaengine_terminate_all(dma->rxchan);
12862306a36Sopenharmony_ci	return ret ?: dmaengine_terminate_all(dma->txchan);
12962306a36Sopenharmony_ci}
130