On Sat, Sep 26, 2026 at 02:21:35AM +0530, Praveen Talari wrote: > Add tracepoint support to the Qualcomm GPI DMA engine driver, giving > structured runtime visibility into GPI DMA behavior without requiring > invasive debug patches. > > The events cover channel/event command dispatch, IRQ type handling, > channel/event control state transitions, error IRQ status, completion > event processing (including the no-pending-descriptor and transfer > result paths), per-event processing in the event ring, ring > allocation/programming details, already-in-state checks for > pause/resume, and TRE queuing and contents. > > Signed-off-by: Praveen Talari <[email protected]> > ---
Reviewed-by: Frank Li <[email protected]> > drivers/dma/qcom/gpi.c | 11 ++ > drivers/dma/qcom/gpi_trace.h | 317 > +++++++++++++++++++++++++++++++++++++++++++ > 2 files changed, 328 insertions(+) > > diff --git a/drivers/dma/qcom/gpi.c b/drivers/dma/qcom/gpi.c > index c41bfac65ddf..fafe6ac848d9 100644 > --- a/drivers/dma/qcom/gpi.c > +++ b/drivers/dma/qcom/gpi.c > @@ -17,6 +17,9 @@ > #include "../dmaengine.h" > #include "../virt-dma.h" > > +#define CREATE_TRACE_POINTS > +#include "gpi_trace.h" > + > #define TRE_TYPE_DMA 0x10 > #define TRE_TYPE_IMMEDIATE_DMA 0x11 > #define TRE_TYPE_GO 0x20 > @@ -683,6 +686,7 @@ static int gpi_send_cmd(struct gpii *gpii, struct gchan > *gchan, > > dev_dbg(gpii->gpi_dev->dev, > "sending cmd: %s:%u\n", TO_GPI_CMD_STR(gpi_cmd), chid); > + trace_gpi_send_cmd(gpii->gpi_dev->dev, chid, gpi_cmd, > TO_GPI_CMD_STR(gpi_cmd)); > > /* send opcode and wait for completion */ > reinit_completion(&gpii->cmd_completion); > @@ -773,6 +777,7 @@ static void gpi_process_ch_ctrl_irq(struct gpii *gpii) > if (gpii->gpi_cmd == GPI_CH_CMD_DE_ALLOC) > state = DEFAULT_CH_STATE; > gchan->ch_state = state; > + trace_gpi_ch_ctrl_irq(gpii->gpi_dev->dev, chid, > gchan->ch_state); > > /* > * Triggering complete all if ch_state is not a stop in process. > @@ -841,6 +846,7 @@ static irqreturn_t gpi_handle_irq(int irq, void *data) > > offset = GPII_n_CNTXT_TYPE_IRQ_OFFS(gpii->gpii_id); > type = gpi_read_reg(gpii, gpii->regs + offset); > + trace_gpi_irq_status(gpii->gpi_dev->dev, gpii_id, type); > > do { > /* global gpii error */ > @@ -968,6 +974,8 @@ static void gpi_process_imed_data_event(struct gchan > *gchan, > smp_wmb(); > > chid = imed_event->chid; > + trace_gpi_ev_process(gpii->gpi_dev->dev, chid, IMMEDIATE_DATA_EV_TYPE, > + imed_event->code, imed_event->status, > imed_event->length); > if (imed_event->code == MSM_GPI_TCE_EOT && gpii->ieob_set) { > if (chid == GPI_RX_CHAN) > goto gpi_free_desc; > @@ -1043,6 +1051,8 @@ static void gpi_process_xfer_compl_event(struct gchan > *gchan, > smp_wmb(); > > chid = compl_event->chid; > + trace_gpi_ev_process(gpii->gpi_dev->dev, chid, XFER_COMPLETE_EV_TYPE, > + compl_event->code, compl_event->status, > compl_event->length); > if (compl_event->code == MSM_GPI_TCE_EOT && gpii->ieob_set) { > if (chid == GPI_RX_CHAN) > goto gpi_free_desc; > @@ -1887,6 +1897,7 @@ static void gpi_issue_pending(struct dma_chan *chan) > } > > gpi_desc = to_gpi_desc(vd); > + trace_gpi_queue_xfer(gpii->gpi_dev->dev, gchan->chid, > gpi_desc->num_tre); > for (i = 0; i < gpi_desc->num_tre; i++) { > tre = &gpi_desc->tre[i]; > gpi_queue_xfer(gpii, gchan, tre, &wp); > diff --git a/drivers/dma/qcom/gpi_trace.h b/drivers/dma/qcom/gpi_trace.h > new file mode 100644 > index 000000000000..f16d156833b9 > --- /dev/null > +++ b/drivers/dma/qcom/gpi_trace.h > @@ -0,0 +1,317 @@ > +/* SPDX-License-Identifier: GPL-2.0 */ > +#undef TRACE_SYSTEM > +#define TRACE_SYSTEM qcom_gpi > + > +#if !defined(_TRACE_QCOM_GPI_H) || defined(TRACE_HEADER_MULTI_READ) > +#define _TRACE_QCOM_GPI_H > + > +#include <linux/tracepoint.h> > + > +TRACE_EVENT(gpi_send_cmd, > + TP_PROTO(struct device *dev, u32 chid, u32 cmd, const char > *cmd_str), > + TP_ARGS(dev, chid, cmd, cmd_str), > + > + TP_STRUCT__entry(__string(name, dev_name(dev)) > + __string(cmd_str, cmd_str) > + __field(u32, chid) > + __field(u32, cmd) > + ), > + > + TP_fast_assign(__assign_str(name); > + __assign_str(cmd_str); > + __entry->chid = chid; > + __entry->cmd = cmd; > + ), > + > + TP_printk("%s: chid=%u cmd=%s(%u)", > + __get_str(name), __entry->chid, __get_str(cmd_str), > + __entry->cmd) > +); > + > +TRACE_EVENT(gpi_irq_status, > + TP_PROTO(struct device *dev, u32 gpii_id, u32 irq_type), > + TP_ARGS(dev, gpii_id, irq_type), > + > + TP_STRUCT__entry(__string(name, dev_name(dev)) > + __field(u32, gpii_id) > + __field(u32, irq_type) > + ), > + > + TP_fast_assign(__assign_str(name); > + __entry->gpii_id = gpii_id; > + __entry->irq_type = irq_type; > + ), > + > + TP_printk("%s: gpii=%u irq_type=0x%08x", > + __get_str(name), __entry->gpii_id, __entry->irq_type) > +); > + > +TRACE_EVENT(gpi_ch_ctrl_irq, > + TP_PROTO(struct device *dev, u32 chid, u32 ch_state), > + TP_ARGS(dev, chid, ch_state), > + > + TP_STRUCT__entry(__string(name, dev_name(dev)) > + __field(u32, chid) > + __field(u32, ch_state) > + ), > + > + TP_fast_assign(__assign_str(name); > + __entry->chid = chid; > + __entry->ch_state = ch_state; > + ), > + > + TP_printk("%s: chid=%u ch_state=%u", > + __get_str(name), __entry->chid, __entry->ch_state) > +); > + > +TRACE_EVENT(gpi_ev_process, > + TP_PROTO(struct device *dev, u32 chid, u32 ev_type, u8 code, > + u16 status, u32 length), > + TP_ARGS(dev, chid, ev_type, code, status, length), > + > + TP_STRUCT__entry(__string(name, dev_name(dev)) > + __field(u32, chid) > + __field(u32, ev_type) > + __field(u32, length) > + __field(u16, status) > + __field(u8, code) > + ), > + > + TP_fast_assign(__assign_str(name); > + __entry->chid = chid; > + __entry->ev_type = ev_type; > + __entry->code = code; > + __entry->status = status; > + __entry->length = length; > + ), > + > + TP_printk("%s: chid=%u ev_type=0x%02x code=%u status=%u length=%u", > + __get_str(name), __entry->chid, __entry->ev_type, > + __entry->code, __entry->status, __entry->length) > +); > + > +TRACE_EVENT(gpi_queue_xfer, > + TP_PROTO(struct device *dev, u32 chid, u32 num_tre), > + TP_ARGS(dev, chid, num_tre), > + > + TP_STRUCT__entry(__string(name, dev_name(dev)) > + __field(u32, chid) > + __field(u32, num_tre) > + ), > + > + TP_fast_assign(__assign_str(name); > + __entry->chid = chid; > + __entry->num_tre = num_tre; > + ), > + > + TP_printk("%s: chid=%u num_tre=%u", > + __get_str(name), __entry->chid, __entry->num_tre) > +); > + > +TRACE_EVENT(gpi_gen_err_irq, > + TP_PROTO(struct device *dev, u32 gpii_id, u32 irq_stts), > + TP_ARGS(dev, gpii_id, irq_stts), > + > + TP_STRUCT__entry(__string(name, dev_name(dev)) > + __field(u32, gpii_id) > + __field(u32, irq_stts) > + ), > + > + TP_fast_assign(__assign_str(name); > + __entry->gpii_id = gpii_id; > + __entry->irq_stts = irq_stts; > + ), > + > + TP_printk("%s: gpii=%u irq_stts=0x%08x", > + __get_str(name), __entry->gpii_id, __entry->irq_stts) > +); > + > +TRACE_EVENT(gpi_ev_ctrl_irq, > + TP_PROTO(struct device *dev, u32 gpii_id, u32 ev_ch_irq, u32 > ev_state), > + TP_ARGS(dev, gpii_id, ev_ch_irq, ev_state), > + > + TP_STRUCT__entry(__string(name, dev_name(dev)) > + __field(u32, gpii_id) > + __field(u32, ev_ch_irq) > + __field(u32, ev_state) > + ), > + > + TP_fast_assign(__assign_str(name); > + __entry->gpii_id = gpii_id; > + __entry->ev_ch_irq = ev_ch_irq; > + __entry->ev_state = ev_state; > + ), > + > + TP_printk("%s: gpii=%u ev_ch_irq=0x%08x ev_state=%u", > + __get_str(name), __entry->gpii_id, __entry->ev_ch_irq, > + __entry->ev_state) > +); > + > +TRACE_EVENT(gpi_ev_no_desc, > + TP_PROTO(struct device *dev, u32 chid, const u32 *ev_dword, > + const u32 *tre_dword), > + TP_ARGS(dev, chid, ev_dword, tre_dword), > + > + TP_STRUCT__entry(__string(name, dev_name(dev)) > + __field(u32, chid) > + __array(u32, ev_dword, 4) > + __array(u32, tre_dword, 4) > + ), > + > + TP_fast_assign(__assign_str(name); > + __entry->chid = chid; > + memcpy(__entry->ev_dword, ev_dword, > sizeof(__entry->ev_dword)); > + memcpy(__entry->tre_dword, tre_dword, > sizeof(__entry->tre_dword)); > + ), > + > + TP_printk("%s: chid=%u event=%08x:%08x:%08x:%08x > pending_tre=%08x:%08x:%08x:%08x", > + __get_str(name), __entry->chid, > + __entry->ev_dword[0], __entry->ev_dword[1], > + __entry->ev_dword[2], __entry->ev_dword[3], > + __entry->tre_dword[0], __entry->tre_dword[1], > + __entry->tre_dword[2], __entry->tre_dword[3]) > +); > + > +TRACE_EVENT(gpi_xfer_result, > + TP_PROTO(struct device *dev, u32 chid, int result, u32 residue), > + TP_ARGS(dev, chid, result, residue), > + > + TP_STRUCT__entry(__string(name, dev_name(dev)) > + __field(u32, chid) > + __field(int, result) > + __field(u32, residue) > + ), > + > + TP_fast_assign(__assign_str(name); > + __entry->chid = chid; > + __entry->result = result; > + __entry->residue = residue; > + ), > + > + TP_printk("%s: chid=%u result=%d residue=%u", > + __get_str(name), __entry->chid, __entry->result, > + __entry->residue) > +); > + > +TRACE_EVENT(gpi_process_event, > + TP_PROTO(struct device *dev, u32 chid, u32 type, const u32 *dword), > + TP_ARGS(dev, chid, type, dword), > + > + TP_STRUCT__entry(__string(name, dev_name(dev)) > + __field(u32, chid) > + __field(u32, type) > + __array(u32, dword, 4) > + ), > + > + TP_fast_assign(__assign_str(name); > + __entry->chid = chid; > + __entry->type = type; > + memcpy(__entry->dword, dword, > sizeof(__entry->dword)); > + ), > + > + TP_printk("%s: chid=%u type=0x%02x %08x:%08x:%08x:%08x", > + __get_str(name), __entry->chid, __entry->type, > + __entry->dword[0], __entry->dword[1], > + __entry->dword[2], __entry->dword[3]) > +); > + > +TRACE_EVENT(gpi_alloc_ring, > + TP_PROTO(struct device *dev, u32 elements, u32 el_size, > + u32 req_len, u64 len, size_t alloc_size), > + TP_ARGS(dev, elements, el_size, req_len, len, alloc_size), > + > + TP_STRUCT__entry(__field(u64, len) > + __field(size_t, alloc_size) > + __string(name, dev_name(dev)) > + __field(u32, elements) > + __field(u32, el_size) > + __field(u32, req_len) > + ), > + > + TP_fast_assign(__assign_str(name); > + __entry->elements = elements; > + __entry->el_size = el_size; > + __entry->req_len = req_len; > + __entry->len = len; > + __entry->alloc_size = alloc_size; > + ), > + > + TP_printk("%s: elements=%u el_size=%u req_len=%u len=%llu > alloc_size=%zu", > + __get_str(name), __entry->elements, __entry->el_size, > + __entry->req_len, __entry->len, __entry->alloc_size) > +); > + > +TRACE_EVENT(gpi_ring_info, > + TP_PROTO(struct device *dev, dma_addr_t dma_handle, phys_addr_t > phys_addr, > + u32 len, u32 el_size, u32 elements), > + TP_ARGS(dev, dma_handle, phys_addr, len, el_size, elements), > + > + TP_STRUCT__entry(__field(u64, dma_handle) > + __field(u64, phys_addr) > + __string(name, dev_name(dev)) > + __field(u32, len) > + __field(u32, el_size) > + __field(u32, elements) > + ), > + > + TP_fast_assign(__assign_str(name); > + __entry->dma_handle = dma_handle; > + __entry->phys_addr = phys_addr; > + __entry->len = len; > + __entry->el_size = el_size; > + __entry->elements = elements; > + ), > + > + TP_printk("%s: dma_handle=%llx phys_addr=%llx len=%u el_size=%u > elements=%u", > + __get_str(name), __entry->dma_handle, __entry->phys_addr, > + __entry->len, __entry->el_size, __entry->elements) > +); > + > +TRACE_EVENT(gpi_already_state, > + TP_PROTO(struct device *dev, u32 gpii_id, u32 pm_state), > + TP_ARGS(dev, gpii_id, pm_state), > + > + TP_STRUCT__entry(__string(name, dev_name(dev)) > + __field(u32, gpii_id) > + __field(u32, pm_state) > + ), > + > + TP_fast_assign(__assign_str(name); > + __entry->gpii_id = gpii_id; > + __entry->pm_state = pm_state; > + ), > + > + TP_printk("%s: gpii=%u already in pm_state=%u", > + __get_str(name), __entry->gpii_id, __entry->pm_state) > +); > + > +TRACE_EVENT(gpi_tre, > + TP_PROTO(struct device *dev, u32 chid, u32 idx, const u32 *dword), > + TP_ARGS(dev, chid, idx, dword), > + > + TP_STRUCT__entry(__string(name, dev_name(dev)) > + __field(u32, chid) > + __field(u32, idx) > + __array(u32, dword, 4) > + ), > + > + TP_fast_assign(__assign_str(name); > + __entry->chid = chid; > + __entry->idx = idx; > + memcpy(__entry->dword, dword, > sizeof(__entry->dword)); > + ), > + > + TP_printk("%s: chid=%u tre[%u]=%08x:%08x:%08x:%08x", > + __get_str(name), __entry->chid, __entry->idx, > + __entry->dword[0], __entry->dword[1], > + __entry->dword[2], __entry->dword[3]) > +); > + > +#endif /* _TRACE_QCOM_GPI_H */ > + > +/* This part must be outside protection */ > +#undef TRACE_INCLUDE_PATH > +#undef TRACE_INCLUDE_FILE > +#define TRACE_INCLUDE_PATH ../../drivers/dma/qcom > +#define TRACE_INCLUDE_FILE gpi_trace > +#include <trace/define_trace.h> > > -- > 2.34.1 >
