Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

spi: spi-mem: Trace exec_op

The spi subsystem has tracing, which is very convenient when debugging
problems. Add tracing for spi-mem too so that accesses that skip the spi
subsystem can still be seen.

The format is roughly based on the existing spi tracing. We don't bother
tracing the op's address because the tracing happens while the memory is
locked, so there can be no confusion about the matching of start and
stop. The conversion of cmd/addr/dummy to an array is directly analogous
to the conversion in the latter half of spi_mem_exec_op.

Signed-off-by: Sean Anderson <sean.anderson@linux.dev>
Link: https://patch.msgid.link/20251021144702.1582397-1-sean.anderson@linux.dev
Signed-off-by: Mark Brown <broonie@kernel.org>

authored by

Sean Anderson and committed by
Mark Brown
77a58ba7 fd5ef3d6

+112
+1
MAINTAINERS
··· 24226 24226 F: Documentation/devicetree/bindings/spi/ 24227 24227 F: Documentation/spi/ 24228 24228 F: drivers/spi/ 24229 + F: include/trace/events/spi* 24229 24230 F: include/linux/spi/ 24230 24231 F: include/uapi/linux/spi/ 24231 24232 F: tools/spi/
+5
drivers/spi/spi-mem.c
··· 12 12 #include <linux/spi/spi-mem.h> 13 13 #include <linux/sched/task_stack.h> 14 14 15 + #define CREATE_TRACE_POINTS 16 + #include <trace/events/spi-mem.h> 17 + 15 18 #include "internals.h" 16 19 17 20 #define SPI_MEM_MAX_BUSWIDTH 8 ··· 406 403 if (ret) 407 404 return ret; 408 405 406 + trace_spi_mem_start_op(mem, op); 409 407 ret = ctlr->mem_ops->exec_op(mem, op); 408 + trace_spi_mem_stop_op(mem, op); 410 409 411 410 spi_mem_access_end(mem); 412 411
+106
include/trace/events/spi-mem.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + #undef TRACE_SYSTEM 3 + #define TRACE_SYSTEM spi-mem 4 + 5 + #undef TRACE_SYSTEM_VAR 6 + #define TRACE_SYSTEM_VAR spi_mem 7 + 8 + #if !defined(_TRACE_SPI_MEM_H) || defined(TRACE_HEADER_MULTI_READ) 9 + #define _TRACE_SPI_MEM_H 10 + 11 + #include <linux/tracepoint.h> 12 + #include <linux/spi/spi-mem.h> 13 + 14 + #define decode_dtr(dtr) \ 15 + __print_symbolic(dtr, \ 16 + { 0, "S" }, \ 17 + { 1, "D" }) 18 + 19 + TRACE_EVENT(spi_mem_start_op, 20 + TP_PROTO(struct spi_mem *mem, const struct spi_mem_op *op), 21 + TP_ARGS(mem, op), 22 + 23 + TP_STRUCT__entry( 24 + __string(name, mem->name) 25 + __dynamic_array(u8, op, 1 + op->addr.nbytes + op->dummy.nbytes) 26 + __dynamic_array(u8, data, op->data.dir == SPI_MEM_DATA_OUT ? 27 + min(op->data.nbytes, 64) : 0) 28 + __field(u32, data_len) 29 + __field(u32, max_freq) 30 + __field(u8, cmd_buswidth) 31 + __field(bool, cmd_dtr) 32 + __field(u8, addr_buswidth) 33 + __field(bool, addr_dtr) 34 + __field(u8, dummy_nbytes) 35 + __field(u8, data_buswidth) 36 + __field(bool, data_dtr) 37 + ), 38 + 39 + TP_fast_assign( 40 + int i; 41 + 42 + __assign_str(name); 43 + __entry->max_freq = op->max_freq ?: mem->spi->max_speed_hz; 44 + 45 + __entry->cmd_buswidth = op->cmd.buswidth; 46 + __entry->cmd_dtr = op->cmd.dtr; 47 + *((u8 *)__get_dynamic_array(op)) = op->cmd.opcode; 48 + 49 + __entry->addr_buswidth = op->addr.buswidth; 50 + __entry->addr_dtr = op->addr.dtr; 51 + for (i = 0; i < op->addr.nbytes; i++) 52 + ((u8 *)__get_dynamic_array(op))[i + 1] = 53 + op->addr.val >> (8 * (op->addr.nbytes - i - 1)); 54 + 55 + memset(((u8 *)__get_dynamic_array(op)) + op->addr.nbytes + 1, 56 + 0xff, op->dummy.nbytes); 57 + 58 + __entry->data_len = op->data.nbytes; 59 + __entry->data_buswidth = op->data.buswidth; 60 + __entry->data_dtr = op->data.dtr; 61 + if (op->data.dir == SPI_MEM_DATA_OUT) 62 + memcpy(__get_dynamic_array(data), op->data.buf.out, 63 + __get_dynamic_array_len(data)); 64 + ), 65 + 66 + TP_printk("%s %u%s-%u%s-%u%s @%u Hz op=[%*phD] len=%u tx=[%*phD]", 67 + __get_str(name), 68 + __entry->cmd_buswidth, decode_dtr(__entry->cmd_dtr), 69 + __entry->addr_buswidth, decode_dtr(__entry->addr_dtr), 70 + __entry->data_buswidth, decode_dtr(__entry->data_dtr), 71 + __entry->max_freq, 72 + __get_dynamic_array_len(op), __get_dynamic_array(op), 73 + __entry->data_len, 74 + __get_dynamic_array_len(data), __get_dynamic_array(data)) 75 + ); 76 + 77 + TRACE_EVENT(spi_mem_stop_op, 78 + TP_PROTO(struct spi_mem *mem, const struct spi_mem_op *op), 79 + TP_ARGS(mem, op), 80 + 81 + TP_STRUCT__entry( 82 + __string(name, mem->name) 83 + __dynamic_array(u8, data, op->data.dir == SPI_MEM_DATA_IN ? 84 + min(op->data.nbytes, 64) : 0) 85 + __field(u32, data_len) 86 + ), 87 + 88 + TP_fast_assign( 89 + __assign_str(name); 90 + __entry->data_len = op->data.nbytes; 91 + if (op->data.dir == SPI_MEM_DATA_IN) 92 + memcpy(__get_dynamic_array(data), op->data.buf.in, 93 + __get_dynamic_array_len(data)); 94 + ), 95 + 96 + TP_printk("%s len=%u rx=[%*phD]", 97 + __get_str(name), 98 + __entry->data_len, 99 + __get_dynamic_array_len(data), __get_dynamic_array(data)) 100 + ); 101 + 102 + 103 + #endif /* _TRACE_SPI_MEM_H */ 104 + 105 + /* This part must be outside protection */ 106 + #include <trace/define_trace.h>