[PATCH v4 24/24] dmaengine: dw-edma: Add trace support
Koichiro Den <[email protected]> Wed, 29 Jul 2026 23:30:36 +0900
| Newsgroups | org.kernel.vger.dmaengine,org.kernel.vger.linux-kernel |
|---|---|
| Message-ID | <[email protected]> |
From: Frank Li <[email protected]> The circular LL ring has separate producer and consumer positions. Add tracepoints for LL publication, descriptor append and completion, IRQ-paired LL events, and engine recovery. The LL events cover both eDMA and HDMA. The recovery event records configured LL channels before a direction reset. When disabled, static keys leave only a branch at each trace site. Signed-off-by: Frank Li <[email protected]> Co-developed-by: Koichiro Den <[email protected]> Signed-off-by: Koichiro Den <[email protected]> --- Changes in v4: - No changes. drivers/dma/dw-edma/Makefile | 2 + drivers/dma/dw-edma/dw-edma-core.c | 49 ++++++++ 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 | 169 ++++++++++++++++++++++++++++ 5 files changed, 226 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..5f395fa1ede4 100644 --- a/drivers/dma/dw-edma/Makefile +++ b/drivers/dma/dw-edma/Makefile @@ -1,8 +1,10 @@ # SPDX-License-Identifier: GPL-2.0 +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-$(CONFIG_TRACING) += dw-edma-trace.o dw-edma-objs := dw-edma-core.o \ dw-edma-v0-core.o \ dw-hdma-v0-core.o $(dw-edma-y) diff --git a/drivers/dma/dw-edma/dw-edma-core.c b/drivers/dma/dw-edma/dw-edma-core.c index 05b9ceb0b920..a53c5b96886c 100644 --- a/drivers/dma/dw-edma/dw-edma-core.c +++ b/drivers/dma/dw-edma/dw-edma-core.c @@ -421,6 +421,12 @@ static void dw_edma_core_ll_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) { @@ -482,6 +488,7 @@ static int dw_edma_start_transfer(struct dw_edma_chan *chan) if (desc->start_burst == desc->nburst) continue; + trace_edma_append_desc(desc); dw_edma_core_start(desc); ret = 1; } @@ -611,6 +618,7 @@ static bool dw_edma_ll_clean_pending(struct dw_edma_chan *chan, int idx) /* 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); } @@ -945,6 +953,44 @@ dw_edma_engine_recovery_drain_irqs(struct dw_edma_engine_recovery *rec) } } +static void +dw_edma_trace_engine_recovery(struct dw_edma_engine_recovery *rec) +{ + struct dw_edma *dw = rec->dw; + u16 off = rec->dir == EDMA_DIR_WRITE ? 0 : dw->wr_ch_cnt; + u16 cnt = rec->dir == EDMA_DIR_WRITE ? dw->wr_ch_cnt : dw->rd_ch_cnt; + struct dw_edma_chan *chan; + u16 i; + + if (!trace_edma_engine_recovery_enabled()) + return; + + for (i = 0; i < cnt; i++) { + enum dw_edma_request request; + enum dw_edma_status status; + bool configured_ll; + u32 ll_head, ll_done, pending; + + chan = &dw->chan[off + i]; + scoped_guard(spinlock_irqsave, &chan->vc.lock) { + configured_ll = chan->configured && !chan->non_ll; + if (configured_ll) { + request = chan->request; + status = chan->status; + ll_head = chan->ll_head; + ll_done = chan->ll_done; + pending = dw_edma_core_get_used_num(chan); + } + } + if (!configured_ll) + continue; + + trace_edma_engine_recovery(chan, dw_edma_core_ch_status(chan), + request, status, ll_head, ll_done, + pending); + } +} + static void dw_edma_engine_recovery_work(struct work_struct *work) { struct dw_edma_engine_recovery *rec = @@ -1071,6 +1117,8 @@ static void dw_edma_engine_recovery_work(struct work_struct *work) return; } + dw_edma_trace_engine_recovery(rec); + if (!dw->core->engine_reset(dw, rec->dir)) { unsigned long delay = 0; @@ -1693,6 +1741,7 @@ static void dw_edma_ll_interrupt(struct dw_edma_chan *chan) if (!dw_edma_ll_snapshot_take(chan, &snapshot)) return; + trace_edma_irq(chan, &snapshot); if (chan->status == EDMA_ST_PAUSE) return; diff --git a/drivers/dma/dw-edma/dw-edma-core.h b/drivers/dma/dw-edma/dw-edma-core.h index cb3ff23143a2..da2a9ec54adc 100644 --- a/drivers/dma/dw-edma/dw-edma-core.h +++ b/drivers/dma/dw-edma/dw-edma-core.h @@ -204,6 +204,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 *chan, unsigned int events); 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..e5b3eb57df06 --- /dev/null +++ b/drivers/dma/dw-edma/dw-edma-trace.h @@ -0,0 +1,169 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * 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(size_t, nburst) + __field(size_t, start_burst) + __field(dma_cookie_t, cookie) + __field(u32, id) + __field(u8, dir) + ), + TP_fast_assign( + __entry->nburst = desc->nburst; + __entry->start_burst = desc->start_burst; + __entry->id = desc->chan->id; + __entry->dir = desc->chan->dir; + __entry->cookie = desc->vd.tx.cookie; + ), + TP_printk("chan %u%c desc %d nburst %zu start_burst %zu", + __entry->id, + __entry->dir ? 'R' : 'W', + __entry->cookie, + __entry->nburst, + __entry->start_burst) +); + +DEFINE_EVENT(edma_desc_info, edma_append_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) +); + +TRACE_EVENT(edma_irq, + TP_PROTO(struct dw_edma_chan *chan, + const struct dw_edma_ll_snapshot *snapshot), + TP_ARGS(chan, snapshot), + TP_STRUCT__entry( + __field(u32, head) + __field(u32, done) + __field(u32, total) + __field(int, index) + __field(int, event) + __field(dma_cookie_t, completed_cookie) + __field(dma_cookie_t, cookie) + __field(u32, id) + __field(u8, dir) + ), + TP_fast_assign( + __entry->head = chan->ll_head; + __entry->done = chan->ll_done; + __entry->total = chan->ll_max; + __entry->index = snapshot->idx; + __entry->event = snapshot->event; + __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 %u%c event %s head %u done %u total %u idx %d completed %d cookie %d", + __entry->id, + __entry->dir ? 'R' : 'W', + __entry->event == DW_EDMA_LL_EVENT_STOP ? "stop" : "progress", + __entry->head, + __entry->done, + __entry->total, + __entry->index, + __entry->completed_cookie, + __entry->cookie) +); + +TRACE_EVENT(edma_engine_recovery, + TP_PROTO(struct dw_edma_chan *chan, enum dma_status hw_status, + enum dw_edma_request request, enum dw_edma_status status, + u32 ll_head, u32 ll_done, u32 pending), + TP_ARGS(chan, hw_status, request, status, ll_head, ll_done, pending), + TP_STRUCT__entry( + __field(u32, id) + __field(u32, head) + __field(u32, done) + __field(u32, pending) + __field(int, hw_status) + __field(int, request) + __field(int, status) + __field(u8, dir) + ), + TP_fast_assign( + __entry->id = chan->id; + __entry->dir = chan->dir; + __entry->hw_status = hw_status; + __entry->request = request; + __entry->status = status; + __entry->head = ll_head; + __entry->done = ll_done; + __entry->pending = pending; + ), + TP_printk("chan %u%c hw %d request %d status %d head %u done %u pending %u", + __entry->id, + __entry->dir ? 'R' : 'W', + __entry->hw_status, + __entry->request, + __entry->status, + __entry->head, + __entry->done, + __entry->pending) +); + +TRACE_EVENT(edma_fill_ll, + TP_PROTO(struct dw_edma_chan *chan, u32 idx, dma_cookie_t 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(dma_cookie_t, 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 %u%c %d [%u] %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) +); + +#endif + +/* This part must be outside the 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