[PATCH 17/17] dmaengine: dw-edma: Add trace support
From: Koichiro Den
Date: Mon Jun 15 2026 - 11:45:45 EST
From: Frank Li <Frank.Li@xxxxxxx>
Add tracepoints for the linked-list fill, start, interrupt, tx_status(),
and completion paths. These are useful when debugging dynamic
linked-list appends and HDMA watermark progress handling. The LL
progress trace records ll_head, ll_end, and ll_done so it shows both the
descriptor completion boundary and the hardware consumption point.
Signed-off-by: Frank Li <Frank.Li@xxxxxxx>
[den: dropped needless new-lines and unused edma_terminate_all event;
included ll_done in LL progress traces; added trace_edma_irq() in
dw_edma_progress_interrupt; trace descriptor completion before vchan
clears the cookie; fixed minor checkpatch.pl cosmetic issues; updated
commit message]
Signed-off-by: Koichiro Den <den@xxxxxxxxxxxxx>
---
drivers/dma/dw-edma/Makefile | 3 +
drivers/dma/dw-edma/dw-edma-core.c | 13 +++
drivers/dma/dw-edma/dw-edma-core.h | 2 +
drivers/dma/dw-edma/dw-edma-trace.c | 4 +
drivers/dma/dw-edma/dw-edma-trace.h | 150 ++++++++++++++++++++++++++++
5 files changed, 172 insertions(+)
create mode 100644 drivers/dma/dw-edma/dw-edma-trace.c
create mode 100644 drivers/dma/dw-edma/dw-edma-trace.h
diff --git a/drivers/dma/dw-edma/Makefile b/drivers/dma/dw-edma/Makefile
index 83ab58f87760..3e31e7d92f3e 100644
--- a/drivers/dma/dw-edma/Makefile
+++ b/drivers/dma/dw-edma/Makefile
@@ -1,9 +1,12 @@
# SPDX-License-Identifier: GPL-2.0
+dw-edma-trace-$(CONFIG_TRACING) := dw-edma-trace.o
+CFLAGS_dw-edma-trace.o := -I$(src)
obj-$(CONFIG_DW_EDMA) += dw-edma.o
dw-edma-$(CONFIG_DEBUG_FS) := dw-edma-v0-debugfs.o \
dw-hdma-v0-debugfs.o
dw-edma-objs := dw-edma-core.o \
dw-edma-v0-core.o \
+ ${dw-edma-trace-y} \
dw-hdma-v0-core.o $(dw-edma-y)
obj-$(CONFIG_DW_EDMA_PCIE) += dw-edma-pcie.o
diff --git a/drivers/dma/dw-edma/dw-edma-core.c b/drivers/dma/dw-edma/dw-edma-core.c
index acf6cc8147a6..ad7e2a2fd685 100644
--- a/drivers/dma/dw-edma/dw-edma-core.c
+++ b/drivers/dma/dw-edma/dw-edma-core.c
@@ -193,6 +193,12 @@ static void dw_edma_core_start(struct dw_edma_desc *desc)
chan->ll_head, chan->cb,
dw_edma_core_enable_ll_irq(desc, i, free));
+ trace_edma_fill_ll(chan, chan->ll_head,
+ desc->vd.tx.cookie,
+ desc->burst[i].sar,
+ desc->burst[i].dar, desc->burst[i].sz,
+ chan->cb);
+
chan->ll_head++;
if (chan->ll_head == chan->ll_max - 1) {
@@ -228,6 +234,8 @@ static int dw_edma_start_transfer(struct dw_edma_chan *chan)
*/
if (desc->start_burst == desc->nburst)
continue;
+
+ trace_edma_start_desc(desc);
dw_edma_core_start(desc);
ret = 1;
}
@@ -322,6 +330,7 @@ static void dw_edma_ll_clean_pending(struct dw_edma_chan *chan, u32 old_done)
/* Hardware has consumed this descriptor's LL entries. */
dw_hdma_set_callback_result(vd, DMA_TRANS_NOERROR);
list_del(&vd->node);
+ trace_edma_complete_desc(desc);
vchan_cookie_complete(vd);
chan->ll_end = desc->ll_end;
}
@@ -536,6 +545,8 @@ dw_edma_device_tx_status(struct dma_chan *dchan, dma_cookie_t cookie,
dw_edma_core_ch_doorbell_recheck(chan, doorbell);
spin_unlock_irqrestore(&chan->vc.lock, flags);
+ trace_edma_tx_status_info(chan, idx);
+
/* check again because dw_edma_ll_clean_pending() may update cookie */
ret = dma_cookie_status(dchan, cookie, txstate);
if (ret == DMA_COMPLETE)
@@ -797,6 +808,7 @@ static void dw_edma_done_interrupt(struct dw_edma_chan *chan)
spin_lock_irqsave(&chan->vc.lock, flags);
idx = dw_edma_core_ll_cur_idx(chan);
+ trace_edma_irq(chan, idx);
switch (chan->request) {
case EDMA_REQ_NONE:
@@ -852,6 +864,7 @@ static void dw_edma_progress_interrupt(struct dw_edma_chan *chan)
spin_lock_irqsave(&chan->vc.lock, flags);
idx = dw_edma_core_ll_cur_idx(chan);
+ trace_edma_irq(chan, idx);
if (chan->request == EDMA_REQ_NONE && chan->status != EDMA_ST_PAUSE) {
dw_edma_ll_recycle_and_refill(chan, idx);
chan->status = dw_edma_ll_pending(chan) ?
diff --git a/drivers/dma/dw-edma/dw-edma-core.h b/drivers/dma/dw-edma/dw-edma-core.h
index 1bacefb10a3b..a72469c0d262 100644
--- a/drivers/dma/dw-edma/dw-edma-core.h
+++ b/drivers/dma/dw-edma/dw-edma-core.h
@@ -143,6 +143,8 @@ struct dw_edma {
const struct dw_edma_core_ops *core;
};
+#include "dw-edma-trace.h"
+
typedef void (*dw_edma_handler_t)(struct dw_edma_chan *);
struct dw_edma_core_ops {
diff --git a/drivers/dma/dw-edma/dw-edma-trace.c b/drivers/dma/dw-edma/dw-edma-trace.c
new file mode 100644
index 000000000000..2620ad61a943
--- /dev/null
+++ b/drivers/dma/dw-edma/dw-edma-trace.c
@@ -0,0 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#define CREATE_TRACE_POINTS
+#include "dw-edma-core.h"
diff --git a/drivers/dma/dw-edma/dw-edma-trace.h b/drivers/dma/dw-edma/dw-edma-trace.h
new file mode 100644
index 000000000000..a908096156d4
--- /dev/null
+++ b/drivers/dma/dw-edma/dw-edma-trace.h
@@ -0,0 +1,150 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright 2023 NXP.
+ */
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM dw_edma
+
+#if !defined(__LINUX_DW_EDMA_TRACE) || defined(TRACE_HEADER_MULTI_READ)
+#define __LINUX_DW_EDMA_TRACE
+
+#include <linux/types.h>
+#include <linux/tracepoint.h>
+
+DECLARE_EVENT_CLASS(edma_desc_info,
+ TP_PROTO(struct dw_edma_desc *desc),
+ TP_ARGS(desc),
+ TP_STRUCT__entry(
+ __field(u32, nburst)
+ __field(u32, start_burst)
+ __field(u32, ll_end)
+ __field(u32, cookie)
+ __field(u32, id)
+ __field(u8, dir)
+ ),
+ TP_fast_assign(
+ __entry->nburst = desc->nburst,
+ __entry->start_burst = desc->start_burst,
+ __entry->ll_end = desc->ll_end,
+ __entry->id = desc->chan->id,
+ __entry->dir = desc->chan->dir,
+ __entry->cookie = desc->vd.tx.cookie;
+ ),
+ TP_printk("chan %d%c desc %d, nburst %d, start_burst %d, ll_end %d",
+ __entry->id,
+ __entry->dir ? 'R' : 'W',
+ __entry->cookie,
+ __entry->nburst,
+ __entry->start_burst,
+ __entry->ll_end)
+);
+
+DEFINE_EVENT(edma_desc_info, edma_start_desc,
+ TP_PROTO(struct dw_edma_desc *desc),
+ TP_ARGS(desc)
+);
+
+DEFINE_EVENT(edma_desc_info, edma_complete_desc,
+ TP_PROTO(struct dw_edma_desc *desc),
+ TP_ARGS(desc)
+);
+
+DECLARE_EVENT_CLASS(edma_ll_info,
+ TP_PROTO(struct dw_edma_chan *chan, int idx),
+ TP_ARGS(chan, idx),
+ TP_STRUCT__entry(
+ __field(u32, head)
+ __field(u32, end)
+ __field(u32, done)
+ __field(u32, total)
+ __field(u32, index)
+ __field(u32, completed_cookie)
+ __field(u32, cookie)
+ __field(u32, id)
+ __field(u8, dir)
+ ),
+ TP_fast_assign(
+ __entry->head = chan->ll_head,
+ __entry->end = chan->ll_end,
+ __entry->done = chan->ll_done,
+ __entry->total = chan->ll_max,
+ __entry->index = idx,
+ __entry->completed_cookie = chan->vc.chan.completed_cookie,
+ __entry->cookie = chan->vc.chan.cookie,
+ __entry->id = chan->id,
+ __entry->dir = chan->dir;
+ ),
+ TP_printk("chan %d%c head: %d end: %d done: %d: dma cur index: %d, complete cookie: %d, cookie: %d",
+ __entry->id,
+ __entry->dir ? 'R' : 'W',
+ __entry->head,
+ __entry->end,
+ __entry->done,
+ __entry->index,
+ __entry->completed_cookie,
+ __entry->cookie)
+);
+
+DEFINE_EVENT(edma_ll_info, edma_tx_status_info,
+ TP_PROTO(struct dw_edma_chan *chan, int idx),
+ TP_ARGS(chan, idx)
+);
+
+DEFINE_EVENT(edma_ll_info, edma_irq,
+ TP_PROTO(struct dw_edma_chan *chan, int idx),
+ TP_ARGS(chan, idx)
+);
+
+DECLARE_EVENT_CLASS(edma_log_ll,
+ TP_PROTO(struct dw_edma_chan *chan, u32 idx, u32 cookie, u64 src,
+ u64 dest, u32 sz, bool flag),
+ TP_ARGS(chan, idx, cookie, src, dest, sz, flag),
+ TP_STRUCT__entry(
+ __field(u32, idx)
+ __field(u64, src)
+ __field(u64, dest)
+ __field(u32, sz)
+ __field(u32, id)
+ __field(u32, cookie)
+ __field(bool, flag)
+ __field(u8, dir)
+ ),
+ TP_fast_assign(
+ __entry->idx = idx,
+ __entry->src = src,
+ __entry->dest = dest,
+ __entry->sz = sz,
+ __entry->id = chan->id,
+ __entry->dir = chan->dir,
+ __entry->cookie = cookie,
+ __entry->flag = flag;
+ ),
+ TP_printk("chan %d%c %d [%d] %c src: %08llx dest: %08llx sz: %04x",
+ __entry->id,
+ __entry->dir ? 'R' : 'W',
+ __entry->cookie,
+ __entry->idx,
+ __entry->flag ? 'C' : 'c',
+ __entry->src,
+ __entry->dest,
+ __entry->sz)
+);
+
+DEFINE_EVENT(edma_log_ll, edma_fill_ll,
+ TP_PROTO(struct dw_edma_chan *chan, u32 idx, u32 cookie, u64 src,
+ u64 dest, u32 sz, bool flag),
+ TP_ARGS(chan, idx, cookie, src, dest, sz, flag)
+);
+
+#endif
+
+/* this part must be outside header guard */
+
+#undef TRACE_INCLUDE_PATH
+#define TRACE_INCLUDE_PATH .
+
+#undef TRACE_INCLUDE_FILE
+#define TRACE_INCLUDE_FILE dw-edma-trace
+
+#include <trace/define_trace.h>
--
2.51.0