blob: be5ae1ad135c1b514ea3df9361817afc0a0a1050 [file] [log] [blame]
b.liue9582032025-04-17 19:18:16 +08001From 27aa9f97887f599267c345075e61979de785c770 Mon Sep 17 00:00:00 2001
2From: Peng Ma <peng.ma@nxp.com>
3Date: Thu, 11 Oct 2018 16:49:41 +0800
4Subject: [PATCH] dma: caam: add dma memcpy driver
5MIME-Version: 1.0
6Content-Type: text/plain; charset=UTF-8
7Content-Transfer-Encoding: 8bit
8
9This module introduces a memcpy DMA driver based on the DMA capabilities
10of the CAAM hardware block. CAAM DMA is a platform driver that is only
11probed if the device is defined in the device tree. The driver creates
12a DMA channel for each JR of the CAAM. This introduces a dependency on
13the JR driver. Therefore a defering mechanism was used to ensure that
14the CAAM DMA driver is probed only after the JR driver.
15
16Signed-off-by: Radu Alexe <radu.alexe@nxp.com>
17Signed-off-by: Tudor Ambarus <tudor-dan.ambarus@nxp.com>
18Signed-off-by: Rajiv Vishwakarma <rajiv.vishwakarma@nxp.com>
19Signed-off-by: Horia Geantă <horia.geanta@nxp.com>
20[rebase]
21Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com>
22---
23 drivers/dma/Kconfig | 19 +-
24 drivers/dma/Makefile | 1 +
25 drivers/dma/caam_dma.c | 462 +++++++++++++++++++++++++++++++++++++++++++++++++
26 3 files changed, 481 insertions(+), 1 deletion(-)
27 create mode 100644 drivers/dma/caam_dma.c
28
29--- a/drivers/dma/Kconfig
30+++ b/drivers/dma/Kconfig
31@@ -132,6 +132,24 @@ config COH901318
32 help
33 Enable support for ST-Ericsson COH 901 318 DMA.
34
35+config CRYPTO_DEV_FSL_CAAM_DMA
36+ tristate "CAAM DMA engine support"
37+ depends on CRYPTO_DEV_FSL_CAAM_JR
38+ default n
39+ select DMA_ENGINE
40+ select ASYNC_CORE
41+ select ASYNC_TX_ENABLE_CHANNEL_SWITCH
42+ help
43+ Selecting this will offload the DMA operations for users of
44+ the scatter gather memcopy API to the CAAM via job rings. The
45+ CAAM is a hardware module that provides hardware acceleration to
46+ cryptographic operations. It has a built-in DMA controller that can
47+ be programmed to read/write cryptographic data. This module defines
48+ a DMA driver that uses the DMA capabilities of the CAAM.
49+
50+ To compile this as a module, choose M here: the module
51+ will be called caam_dma.
52+
53 config DMA_BCM2835
54 tristate "BCM2835 DMA engine support"
55 depends on ARCH_BCM2835
56@@ -663,7 +681,6 @@ config ZX_DMA
57 help
58 Support the DMA engine for ZTE ZX family platform devices.
59
60-
61 # driver files
62 source "drivers/dma/bestcomm/Kconfig"
63
64--- a/drivers/dma/Makefile
65+++ b/drivers/dma/Makefile
66@@ -77,6 +77,7 @@ obj-$(CONFIG_XGENE_DMA) += xgene-dma.o
67 obj-$(CONFIG_ZX_DMA) += zx_dma.o
68 obj-$(CONFIG_ST_FDMA) += st_fdma.o
69 obj-$(CONFIG_FSL_DPAA2_QDMA) += fsl-dpaa2-qdma/
70+obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM_DMA) += caam_dma.o
71
72 obj-y += mediatek/
73 obj-y += qcom/
74--- /dev/null
75+++ b/drivers/dma/caam_dma.c
76@@ -0,0 +1,462 @@
77+/*
78+ * caam support for SG DMA
79+ *
80+ * Copyright 2016 Freescale Semiconductor, Inc
81+ * Copyright 2017 NXP
82+ *
83+ * Redistribution and use in source and binary forms, with or without
84+ * modification, are permitted provided that the following conditions are met:
85+ * * Redistributions of source code must retain the above copyright
86+ * notice, this list of conditions and the following disclaimer.
87+ * * Redistributions in binary form must reproduce the above copyright
88+ * notice, this list of conditions and the following disclaimer in the
89+ * documentation and/or other materials provided with the distribution.
90+ * * Neither the names of the above-listed copyright holders nor the
91+ * names of any contributors may be used to endorse or promote products
92+ * derived from this software without specific prior written permission.
93+ *
94+ *
95+ * ALTERNATIVELY, this software may be distributed under the terms of the
96+ * GNU General Public License ("GPL") as published by the Free Software
97+ * Foundation, either version 2 of that License or (at your option) any
98+ * later version.
99+ *
100+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
101+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
102+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
103+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
104+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
105+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
106+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
107+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
108+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
109+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
110+ * POSSIBILITY OF SUCH DAMAGE.
111+ */
112+
113+#include <linux/dma-mapping.h>
114+#include <linux/dmaengine.h>
115+#include <linux/module.h>
116+#include <linux/platform_device.h>
117+#include <linux/slab.h>
118+
119+#include "dmaengine.h"
120+
121+#include "../crypto/caam/regs.h"
122+#include "../crypto/caam/jr.h"
123+#include "../crypto/caam/error.h"
124+#include "../crypto/caam/desc_constr.h"
125+
126+#define DESC_DMA_MEMCPY_LEN ((CAAM_DESC_BYTES_MAX - DESC_JOB_IO_LEN) / \
127+ CAAM_CMD_SZ)
128+
129+/*
130+ * This is max chunk size of a DMA transfer. If a buffer is larger than this
131+ * value it is internally broken into chunks of max CAAM_DMA_CHUNK_SIZE bytes
132+ * and for each chunk a DMA transfer request is issued.
133+ * This value is the largest number on 16 bits that is a multiple of 256 bytes
134+ * (the largest configurable CAAM DMA burst size).
135+ */
136+#define CAAM_DMA_CHUNK_SIZE 65280
137+
138+struct caam_dma_sh_desc {
139+ u32 desc[DESC_DMA_MEMCPY_LEN] ____cacheline_aligned;
140+ dma_addr_t desc_dma;
141+};
142+
143+/* caam dma extended descriptor */
144+struct caam_dma_edesc {
145+ struct dma_async_tx_descriptor async_tx;
146+ struct list_head node;
147+ struct caam_dma_ctx *ctx;
148+ dma_addr_t src_dma;
149+ dma_addr_t dst_dma;
150+ unsigned int src_len;
151+ unsigned int dst_len;
152+ u32 jd[] ____cacheline_aligned;
153+};
154+
155+/*
156+ * caam_dma_ctx - per jr/channel context
157+ * @chan: dma channel used by async_tx API
158+ * @node: list_head used to attach to the global dma_ctx_list
159+ * @jrdev: Job Ring device
160+ * @pending_q: queue of pending (submitted, but not enqueued) jobs
161+ * @done_not_acked: jobs that have been completed by jr, but maybe not acked
162+ * @edesc_lock: protects extended descriptor
163+ */
164+struct caam_dma_ctx {
165+ struct dma_chan chan;
166+ struct list_head node;
167+ struct device *jrdev;
168+ struct list_head pending_q;
169+ struct list_head done_not_acked;
170+ spinlock_t edesc_lock;
171+};
172+
173+static struct dma_device *dma_dev;
174+static struct caam_dma_sh_desc *dma_sh_desc;
175+static LIST_HEAD(dma_ctx_list);
176+
177+static dma_cookie_t caam_dma_tx_submit(struct dma_async_tx_descriptor *tx)
178+{
179+ struct caam_dma_edesc *edesc = NULL;
180+ struct caam_dma_ctx *ctx = NULL;
181+ dma_cookie_t cookie;
182+
183+ edesc = container_of(tx, struct caam_dma_edesc, async_tx);
184+ ctx = container_of(tx->chan, struct caam_dma_ctx, chan);
185+
186+ spin_lock_bh(&ctx->edesc_lock);
187+
188+ cookie = dma_cookie_assign(tx);
189+ list_add_tail(&edesc->node, &ctx->pending_q);
190+
191+ spin_unlock_bh(&ctx->edesc_lock);
192+
193+ return cookie;
194+}
195+
196+static void caam_jr_chan_free_edesc(struct caam_dma_edesc *edesc)
197+{
198+ struct caam_dma_ctx *ctx = edesc->ctx;
199+ struct caam_dma_edesc *_edesc = NULL;
200+
201+ spin_lock_bh(&ctx->edesc_lock);
202+
203+ list_add_tail(&edesc->node, &ctx->done_not_acked);
204+ list_for_each_entry_safe(edesc, _edesc, &ctx->done_not_acked, node) {
205+ if (async_tx_test_ack(&edesc->async_tx)) {
206+ list_del(&edesc->node);
207+ kfree(edesc);
208+ }
209+ }
210+
211+ spin_unlock_bh(&ctx->edesc_lock);
212+}
213+
214+static void caam_dma_done(struct device *dev, u32 *hwdesc, u32 err,
215+ void *context)
216+{
217+ struct caam_dma_edesc *edesc = context;
218+ struct caam_dma_ctx *ctx = edesc->ctx;
219+ dma_async_tx_callback callback;
220+ void *callback_param;
221+
222+ if (err)
223+ caam_jr_strstatus(ctx->jrdev, err);
224+
225+ dma_run_dependencies(&edesc->async_tx);
226+
227+ spin_lock_bh(&ctx->edesc_lock);
228+ dma_cookie_complete(&edesc->async_tx);
229+ spin_unlock_bh(&ctx->edesc_lock);
230+
231+ callback = edesc->async_tx.callback;
232+ callback_param = edesc->async_tx.callback_param;
233+
234+ dma_descriptor_unmap(&edesc->async_tx);
235+
236+ caam_jr_chan_free_edesc(edesc);
237+
238+ if (callback)
239+ callback(callback_param);
240+}
241+
242+static void caam_dma_memcpy_init_job_desc(struct caam_dma_edesc *edesc)
243+{
244+ u32 *jd = edesc->jd;
245+ u32 *sh_desc = dma_sh_desc->desc;
246+ dma_addr_t desc_dma = dma_sh_desc->desc_dma;
247+
248+ /* init the job descriptor */
249+ init_job_desc_shared(jd, desc_dma, desc_len(sh_desc), HDR_REVERSE);
250+
251+ /* set SEQIN PTR */
252+ append_seq_in_ptr(jd, edesc->src_dma, edesc->src_len, 0);
253+
254+ /* set SEQOUT PTR */
255+ append_seq_out_ptr(jd, edesc->dst_dma, edesc->dst_len, 0);
256+
257+ print_hex_dump_debug("caam dma desc@" __stringify(__LINE__) ": ",
258+ DUMP_PREFIX_ADDRESS, 16, 4, jd, desc_bytes(jd), 1);
259+}
260+
261+static struct dma_async_tx_descriptor *
262+caam_dma_prep_memcpy(struct dma_chan *chan, dma_addr_t dst, dma_addr_t src,
263+ size_t len, unsigned long flags)
264+{
265+ struct caam_dma_edesc *edesc;
266+ struct caam_dma_ctx *ctx = container_of(chan, struct caam_dma_ctx,
267+ chan);
268+
269+ edesc = kzalloc(sizeof(*edesc) + DESC_JOB_IO_LEN, GFP_DMA | GFP_NOWAIT);
270+ if (!edesc)
271+ return ERR_PTR(-ENOMEM);
272+
273+ dma_async_tx_descriptor_init(&edesc->async_tx, chan);
274+ edesc->async_tx.tx_submit = caam_dma_tx_submit;
275+ edesc->async_tx.flags = flags;
276+ edesc->async_tx.cookie = -EBUSY;
277+
278+ edesc->src_dma = src;
279+ edesc->src_len = len;
280+ edesc->dst_dma = dst;
281+ edesc->dst_len = len;
282+ edesc->ctx = ctx;
283+
284+ caam_dma_memcpy_init_job_desc(edesc);
285+
286+ return &edesc->async_tx;
287+}
288+
289+/* This function can be called in an interrupt context */
290+static void caam_dma_issue_pending(struct dma_chan *chan)
291+{
292+ struct caam_dma_ctx *ctx = container_of(chan, struct caam_dma_ctx,
293+ chan);
294+ struct caam_dma_edesc *edesc, *_edesc;
295+
296+ spin_lock_bh(&ctx->edesc_lock);
297+ list_for_each_entry_safe(edesc, _edesc, &ctx->pending_q, node) {
298+ if (caam_jr_enqueue(ctx->jrdev, edesc->jd,
299+ caam_dma_done, edesc) < 0)
300+ break;
301+ list_del(&edesc->node);
302+ }
303+ spin_unlock_bh(&ctx->edesc_lock);
304+}
305+
306+static void caam_dma_free_chan_resources(struct dma_chan *chan)
307+{
308+ struct caam_dma_ctx *ctx = container_of(chan, struct caam_dma_ctx,
309+ chan);
310+ struct caam_dma_edesc *edesc, *_edesc;
311+
312+ spin_lock_bh(&ctx->edesc_lock);
313+ list_for_each_entry_safe(edesc, _edesc, &ctx->pending_q, node) {
314+ list_del(&edesc->node);
315+ kfree(edesc);
316+ }
317+ list_for_each_entry_safe(edesc, _edesc, &ctx->done_not_acked, node) {
318+ list_del(&edesc->node);
319+ kfree(edesc);
320+ }
321+ spin_unlock_bh(&ctx->edesc_lock);
322+}
323+
324+static int caam_dma_jr_chan_bind(void)
325+{
326+ struct device *jrdev;
327+ struct caam_dma_ctx *ctx;
328+ int bonds = 0;
329+ int i;
330+
331+ for (i = 0; i < caam_jr_driver_probed(); i++) {
332+ jrdev = caam_jridx_alloc(i);
333+ if (IS_ERR(jrdev)) {
334+ pr_err("job ring device %d allocation failed\n", i);
335+ continue;
336+ }
337+
338+ ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
339+ if (!ctx) {
340+ caam_jr_free(jrdev);
341+ continue;
342+ }
343+
344+ ctx->chan.device = dma_dev;
345+ ctx->chan.private = ctx;
346+
347+ ctx->jrdev = jrdev;
348+
349+ INIT_LIST_HEAD(&ctx->pending_q);
350+ INIT_LIST_HEAD(&ctx->done_not_acked);
351+ INIT_LIST_HEAD(&ctx->node);
352+ spin_lock_init(&ctx->edesc_lock);
353+
354+ dma_cookie_init(&ctx->chan);
355+
356+ /* add the context of this channel to the context list */
357+ list_add_tail(&ctx->node, &dma_ctx_list);
358+
359+ /* add this channel to the device chan list */
360+ list_add_tail(&ctx->chan.device_node, &dma_dev->channels);
361+
362+ bonds++;
363+ }
364+
365+ return bonds;
366+}
367+
368+static inline void caam_jr_dma_free(struct dma_chan *chan)
369+{
370+ struct caam_dma_ctx *ctx = container_of(chan, struct caam_dma_ctx,
371+ chan);
372+
373+ list_del(&ctx->node);
374+ list_del(&chan->device_node);
375+ caam_jr_free(ctx->jrdev);
376+ kfree(ctx);
377+}
378+
379+static void set_caam_dma_desc(u32 *desc)
380+{
381+ u32 *jmp_cmd;
382+
383+ /* dma shared descriptor */
384+ init_sh_desc(desc, HDR_SHARE_NEVER | (1 << HDR_START_IDX_SHIFT));
385+
386+ /* REG1 = CAAM_DMA_CHUNK_SIZE */
387+ append_math_add_imm_u32(desc, REG1, ZERO, IMM, CAAM_DMA_CHUNK_SIZE);
388+
389+ /* REG0 = SEQINLEN - CAAM_DMA_CHUNK_SIZE */
390+ append_math_sub_imm_u32(desc, REG0, SEQINLEN, IMM, CAAM_DMA_CHUNK_SIZE);
391+
392+ /*
393+ * if (REG0 > 0)
394+ * jmp to LABEL1
395+ */
396+ jmp_cmd = append_jump(desc, JUMP_TEST_INVALL | JUMP_COND_MATH_N |
397+ JUMP_COND_MATH_Z);
398+
399+ /* REG1 = SEQINLEN */
400+ append_math_sub(desc, REG1, SEQINLEN, ZERO, CAAM_CMD_SZ);
401+
402+ /* LABEL1 */
403+ set_jump_tgt_here(desc, jmp_cmd);
404+
405+ /* VARSEQINLEN = REG1 */
406+ append_math_add(desc, VARSEQINLEN, REG1, ZERO, CAAM_CMD_SZ);
407+
408+ /* VARSEQOUTLEN = REG1 */
409+ append_math_add(desc, VARSEQOUTLEN, REG1, ZERO, CAAM_CMD_SZ);
410+
411+ /* do FIFO STORE */
412+ append_seq_fifo_store(desc, 0, FIFOST_TYPE_METADATA | LDST_VLF);
413+
414+ /* do FIFO LOAD */
415+ append_seq_fifo_load(desc, 0, FIFOLD_CLASS_CLASS1 |
416+ FIFOLD_TYPE_IFIFO | LDST_VLF);
417+
418+ /*
419+ * if (REG0 > 0)
420+ * jmp 0xF8 (after shared desc header)
421+ */
422+ append_jump(desc, JUMP_TEST_INVALL | JUMP_COND_MATH_N |
423+ JUMP_COND_MATH_Z | 0xF8);
424+
425+ print_hex_dump_debug("caam dma shdesc@" __stringify(__LINE__) ": ",
426+ DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc),
427+ 1);
428+}
429+
430+static int caam_dma_probe(struct platform_device *pdev)
431+{
432+ struct device *dev = &pdev->dev;
433+ struct device *ctrldev = dev->parent;
434+ struct dma_chan *chan, *_chan;
435+ u32 *sh_desc;
436+ int err = -ENOMEM;
437+ int bonds;
438+
439+ if (!caam_jr_driver_probed()) {
440+ dev_info(dev, "Defer probing after JR driver probing\n");
441+ return -EPROBE_DEFER;
442+ }
443+
444+ dma_dev = kzalloc(sizeof(*dma_dev), GFP_KERNEL);
445+ if (!dma_dev)
446+ return -ENOMEM;
447+
448+ dma_sh_desc = kzalloc(sizeof(*dma_sh_desc), GFP_KERNEL | GFP_DMA);
449+ if (!dma_sh_desc)
450+ goto desc_err;
451+
452+ sh_desc = dma_sh_desc->desc;
453+ set_caam_dma_desc(sh_desc);
454+ dma_sh_desc->desc_dma = dma_map_single(ctrldev, sh_desc,
455+ desc_bytes(sh_desc),
456+ DMA_TO_DEVICE);
457+ if (dma_mapping_error(ctrldev, dma_sh_desc->desc_dma)) {
458+ dev_err(dev, "unable to map dma descriptor\n");
459+ goto map_err;
460+ }
461+
462+ INIT_LIST_HEAD(&dma_dev->channels);
463+
464+ bonds = caam_dma_jr_chan_bind();
465+ if (!bonds) {
466+ err = -ENODEV;
467+ goto jr_bind_err;
468+ }
469+
470+ dma_dev->dev = dev;
471+ dma_dev->residue_granularity = DMA_RESIDUE_GRANULARITY_DESCRIPTOR;
472+ dma_cap_set(DMA_MEMCPY, dma_dev->cap_mask);
473+ dma_cap_set(DMA_PRIVATE, dma_dev->cap_mask);
474+ dma_dev->device_tx_status = dma_cookie_status;
475+ dma_dev->device_issue_pending = caam_dma_issue_pending;
476+ dma_dev->device_prep_dma_memcpy = caam_dma_prep_memcpy;
477+ dma_dev->device_free_chan_resources = caam_dma_free_chan_resources;
478+
479+ err = dma_async_device_register(dma_dev);
480+ if (err) {
481+ dev_err(dev, "Failed to register CAAM DMA engine\n");
482+ goto jr_bind_err;
483+ }
484+
485+ dev_info(dev, "caam dma support with %d job rings\n", bonds);
486+
487+ return err;
488+
489+jr_bind_err:
490+ list_for_each_entry_safe(chan, _chan, &dma_dev->channels, device_node)
491+ caam_jr_dma_free(chan);
492+
493+ dma_unmap_single(ctrldev, dma_sh_desc->desc_dma, desc_bytes(sh_desc),
494+ DMA_TO_DEVICE);
495+map_err:
496+ kfree(dma_sh_desc);
497+desc_err:
498+ kfree(dma_dev);
499+ return err;
500+}
501+
502+static int caam_dma_remove(struct platform_device *pdev)
503+{
504+ struct device *dev = &pdev->dev;
505+ struct device *ctrldev = dev->parent;
506+ struct caam_dma_ctx *ctx, *_ctx;
507+
508+ dma_async_device_unregister(dma_dev);
509+
510+ list_for_each_entry_safe(ctx, _ctx, &dma_ctx_list, node) {
511+ list_del(&ctx->node);
512+ caam_jr_free(ctx->jrdev);
513+ kfree(ctx);
514+ }
515+
516+ dma_unmap_single(ctrldev, dma_sh_desc->desc_dma,
517+ desc_bytes(dma_sh_desc->desc), DMA_TO_DEVICE);
518+
519+ kfree(dma_sh_desc);
520+ kfree(dma_dev);
521+
522+ dev_info(dev, "caam dma support disabled\n");
523+ return 0;
524+}
525+
526+static struct platform_driver caam_dma_driver = {
527+ .driver = {
528+ .name = "caam-dma",
529+ },
530+ .probe = caam_dma_probe,
531+ .remove = caam_dma_remove,
532+};
533+module_platform_driver(caam_dma_driver);
534+
535+MODULE_LICENSE("Dual BSD/GPL");
536+MODULE_DESCRIPTION("NXP CAAM support for DMA engine");
537+MODULE_AUTHOR("NXP Semiconductors");
538+MODULE_ALIAS("platform:caam-dma");