File Index
Files and directories
Sign in
FILE

dma.c

File preview with syntax highlighting.

linux-6.19.14/drivers/crypto/qce/dma.c C
  1// SPDX-License-Identifier: GPL-2.0-only
  2/*
  3 * Copyright (c) 2012-2014, The Linux Foundation. All rights reserved.
  4 */
  5
  6#include <linux/device.h>
  7#include <linux/dmaengine.h>
  8#include <crypto/scatterwalk.h>
  9
 10#include "dma.h"
 11
 12static void qce_dma_release(void *data)
 13{
 14	struct qce_dma_data *dma = data;
 15
 16	dma_release_channel(dma->txchan);
 17	dma_release_channel(dma->rxchan);
 18	kfree(dma->result_buf);
 19}
 20
 21int devm_qce_dma_request(struct device *dev, struct qce_dma_data *dma)
 22{
 23	int ret;
 24
 25	dma->txchan = dma_request_chan(dev, "tx");
 26	if (IS_ERR(dma->txchan))
 27		return dev_err_probe(dev, PTR_ERR(dma->txchan),
 28				     "Failed to get TX DMA channel\n");
 29
 30	dma->rxchan = dma_request_chan(dev, "rx");
 31	if (IS_ERR(dma->rxchan)) {
 32		ret = dev_err_probe(dev, PTR_ERR(dma->rxchan),
 33				    "Failed to get RX DMA channel\n");
 34		goto error_rx;
 35	}
 36
 37	dma->result_buf = kmalloc(QCE_RESULT_BUF_SZ + QCE_IGNORE_BUF_SZ,
 38				  GFP_KERNEL);
 39	if (!dma->result_buf) {
 40		ret = -ENOMEM;
 41		goto error_nomem;
 42	}
 43
 44	dma->ignore_buf = dma->result_buf + QCE_RESULT_BUF_SZ;
 45
 46	return devm_add_action_or_reset(dev, qce_dma_release, dma);
 47
 48error_nomem:
 49	dma_release_channel(dma->rxchan);
 50error_rx:
 51	dma_release_channel(dma->txchan);
 52	return ret;
 53}
 54
 55struct scatterlist *
 56qce_sgtable_add(struct sg_table *sgt, struct scatterlist *new_sgl,
 57		unsigned int max_len)
 58{
 59	struct scatterlist *sg = sgt->sgl, *sg_last = NULL;
 60	unsigned int new_len;
 61
 62	while (sg) {
 63		if (!sg_page(sg))
 64			break;
 65		sg = sg_next(sg);
 66	}
 67
 68	if (!sg)
 69		return ERR_PTR(-EINVAL);
 70
 71	while (new_sgl && sg && max_len) {
 72		new_len = new_sgl->length > max_len ? max_len : new_sgl->length;
 73		sg_set_page(sg, sg_page(new_sgl), new_len, new_sgl->offset);
 74		sg_last = sg;
 75		sg = sg_next(sg);
 76		new_sgl = sg_next(new_sgl);
 77		max_len -= new_len;
 78	}
 79
 80	return sg_last;
 81}
 82
 83static int qce_dma_prep_sg(struct dma_chan *chan, struct scatterlist *sg,
 84			   int nents, unsigned long flags,
 85			   enum dma_transfer_direction dir,
 86			   dma_async_tx_callback cb, void *cb_param)
 87{
 88	struct dma_async_tx_descriptor *desc;
 89	dma_cookie_t cookie;
 90
 91	if (!sg || !nents)
 92		return -EINVAL;
 93
 94	desc = dmaengine_prep_slave_sg(chan, sg, nents, dir, flags);
 95	if (!desc)
 96		return -EINVAL;
 97
 98	desc->callback = cb;
 99	desc->callback_param = cb_param;
100	cookie = dmaengine_submit(desc);
101
102	return dma_submit_error(cookie);
103}
104
105int qce_dma_prep_sgs(struct qce_dma_data *dma, struct scatterlist *rx_sg,
106		     int rx_nents, struct scatterlist *tx_sg, int tx_nents,
107		     dma_async_tx_callback cb, void *cb_param)
108{
109	struct dma_chan *rxchan = dma->rxchan;
110	struct dma_chan *txchan = dma->txchan;
111	unsigned long flags = DMA_PREP_INTERRUPT | DMA_CTRL_ACK;
112	int ret;
113
114	ret = qce_dma_prep_sg(rxchan, rx_sg, rx_nents, flags, DMA_MEM_TO_DEV,
115			     NULL, NULL);
116	if (ret)
117		return ret;
118
119	return qce_dma_prep_sg(txchan, tx_sg, tx_nents, flags, DMA_DEV_TO_MEM,
120			       cb, cb_param);
121}
122
123void qce_dma_issue_pending(struct qce_dma_data *dma)
124{
125	dma_async_issue_pending(dma->rxchan);
126	dma_async_issue_pending(dma->txchan);
127}
128
129int qce_dma_terminate_all(struct qce_dma_data *dma)
130{
131	int ret;
132
133	ret = dmaengine_terminate_all(dma->rxchan);
134	return ret ?: dmaengine_terminate_all(dma->txchan);
135}
~/ Read-only file preview.