| /* SPDX-License-Identifier: GPL-2.0 */ | 
 | /* | 
 |  * Thunderbolt tracing support | 
 |  * | 
 |  * Copyright (C) 2024, Intel Corporation | 
 |  * Author: Mika Westerberg <mika.westerberg@linux.intel.com> | 
 |  *	   Gil Fine <gil.fine@intel.com> | 
 |  */ | 
 |  | 
 | #undef TRACE_SYSTEM | 
 | #define TRACE_SYSTEM thunderbolt | 
 |  | 
 | #if !defined(TB_TRACE_H_) || defined(TRACE_HEADER_MULTI_READ) | 
 | #define TB_TRACE_H_ | 
 |  | 
 | #include <linux/trace_seq.h> | 
 | #include <linux/tracepoint.h> | 
 |  | 
 | #include "tb_msgs.h" | 
 |  | 
 | #define tb_cfg_type_name(type)		{ type, #type } | 
 | #define show_type_name(val)					\ | 
 | 	__print_symbolic(val,					\ | 
 | 		tb_cfg_type_name(TB_CFG_PKG_READ),		\ | 
 | 		tb_cfg_type_name(TB_CFG_PKG_WRITE),		\ | 
 | 		tb_cfg_type_name(TB_CFG_PKG_ERROR),		\ | 
 | 		tb_cfg_type_name(TB_CFG_PKG_NOTIFY_ACK),	\ | 
 | 		tb_cfg_type_name(TB_CFG_PKG_EVENT),		\ | 
 | 		tb_cfg_type_name(TB_CFG_PKG_XDOMAIN_REQ),	\ | 
 | 		tb_cfg_type_name(TB_CFG_PKG_XDOMAIN_RESP),	\ | 
 | 		tb_cfg_type_name(TB_CFG_PKG_OVERRIDE),		\ | 
 | 		tb_cfg_type_name(TB_CFG_PKG_RESET),		\ | 
 | 		tb_cfg_type_name(TB_CFG_PKG_ICM_EVENT),		\ | 
 | 		tb_cfg_type_name(TB_CFG_PKG_ICM_CMD),		\ | 
 | 		tb_cfg_type_name(TB_CFG_PKG_ICM_RESP)) | 
 |  | 
 | #ifndef TB_TRACE_HELPERS | 
 | #define TB_TRACE_HELPERS | 
 | static inline const char *show_data_read_write(struct trace_seq *p, | 
 | 					       const u32 *data) | 
 | { | 
 | 	const struct cfg_read_pkg *msg = (const struct cfg_read_pkg *)data; | 
 | 	const char *ret = trace_seq_buffer_ptr(p); | 
 |  | 
 | 	trace_seq_printf(p, "offset=%#x, len=%u, port=%d, config=%#x, seq=%d, ", | 
 | 			 msg->addr.offset, msg->addr.length, msg->addr.port, | 
 | 			 msg->addr.space, msg->addr.seq); | 
 |  | 
 | 	return ret; | 
 | } | 
 |  | 
 | static inline const char *show_data_error(struct trace_seq *p, const u32 *data) | 
 | { | 
 | 	const struct cfg_error_pkg *msg = (const struct cfg_error_pkg *)data; | 
 | 	const char *ret = trace_seq_buffer_ptr(p); | 
 |  | 
 | 	trace_seq_printf(p, "error=%#x, port=%d, plug=%#x, ", msg->error, | 
 | 			 msg->port, msg->pg); | 
 |  | 
 | 	return ret; | 
 | } | 
 |  | 
 | static inline const char *show_data_event(struct trace_seq *p, const u32 *data) | 
 | { | 
 | 	const struct cfg_event_pkg *msg = (const struct cfg_event_pkg *)data; | 
 | 	const char *ret = trace_seq_buffer_ptr(p); | 
 |  | 
 | 	trace_seq_printf(p, "port=%d, unplug=%#x, ", msg->port, msg->unplug); | 
 |  | 
 | 	return ret; | 
 | } | 
 |  | 
 | static inline const char *show_route(struct trace_seq *p, const u32 *data) | 
 | { | 
 | 	const struct tb_cfg_header *header = (const struct tb_cfg_header *)data; | 
 | 	const char *ret = trace_seq_buffer_ptr(p); | 
 |  | 
 | 	trace_seq_printf(p, "route=%llx, ", tb_cfg_get_route(header)); | 
 |  | 
 | 	return ret; | 
 | } | 
 |  | 
 | static inline const char *show_data(struct trace_seq *p, u8 type, | 
 | 				    const u32 *data, u32 length) | 
 | { | 
 | 	const char *ret = trace_seq_buffer_ptr(p); | 
 | 	const char *prefix = ""; | 
 | 	int i; | 
 |  | 
 | 	switch (type) { | 
 | 	case TB_CFG_PKG_READ: | 
 | 	case TB_CFG_PKG_WRITE: | 
 | 		show_route(p, data); | 
 | 		show_data_read_write(p, data); | 
 | 		break; | 
 |  | 
 | 	case TB_CFG_PKG_ERROR: | 
 | 		show_route(p, data); | 
 | 		show_data_error(p, data); | 
 | 		break; | 
 |  | 
 | 	case TB_CFG_PKG_EVENT: | 
 | 		show_route(p, data); | 
 | 		show_data_event(p, data); | 
 | 		break; | 
 |  | 
 | 	case TB_CFG_PKG_ICM_EVENT: | 
 | 	case TB_CFG_PKG_ICM_CMD: | 
 | 	case TB_CFG_PKG_ICM_RESP: | 
 | 		/* ICM messages always target the host router */ | 
 | 		trace_seq_puts(p, "route=0, "); | 
 | 		break; | 
 |  | 
 | 	default: | 
 | 		show_route(p, data); | 
 | 		break; | 
 | 	} | 
 |  | 
 | 	trace_seq_printf(p, "data=["); | 
 | 	for (i = 0; i < length; i++) { | 
 | 		trace_seq_printf(p, "%s0x%08x", prefix, data[i]); | 
 | 		prefix = ", "; | 
 | 	} | 
 | 	trace_seq_printf(p, "]"); | 
 | 	trace_seq_putc(p, 0); | 
 |  | 
 | 	return ret; | 
 | } | 
 | #endif | 
 |  | 
 | DECLARE_EVENT_CLASS(tb_raw, | 
 | 	TP_PROTO(int index, u8 type, const void *data, size_t size), | 
 | 	TP_ARGS(index, type, data, size), | 
 | 	TP_STRUCT__entry( | 
 | 		__field(int, index) | 
 | 		__field(u8, type) | 
 | 		__field(size_t, size) | 
 | 		__dynamic_array(u32, data, size / 4) | 
 | 	), | 
 | 	TP_fast_assign( | 
 | 		__entry->index = index; | 
 | 		__entry->type = type; | 
 | 		__entry->size = size / 4; | 
 | 		memcpy(__get_dynamic_array(data), data, size); | 
 | 	), | 
 | 	TP_printk("type=%s, size=%zd, domain=%d, %s", | 
 | 		  show_type_name(__entry->type), __entry->size, __entry->index, | 
 | 		  show_data(p, __entry->type, __get_dynamic_array(data), | 
 | 			    __entry->size) | 
 | 	) | 
 | ); | 
 |  | 
 | DEFINE_EVENT(tb_raw, tb_tx, | 
 | 	TP_PROTO(int index, u8 type, const void *data, size_t size), | 
 | 	TP_ARGS(index, type, data, size) | 
 | ); | 
 |  | 
 | DEFINE_EVENT(tb_raw, tb_event, | 
 | 	TP_PROTO(int index, u8 type, const void *data, size_t size), | 
 | 	TP_ARGS(index, type, data, size) | 
 | ); | 
 |  | 
 | TRACE_EVENT(tb_rx, | 
 | 	TP_PROTO(int index, u8 type, const void *data, size_t size, bool dropped), | 
 | 	TP_ARGS(index, type, data, size, dropped), | 
 | 	TP_STRUCT__entry( | 
 | 		__field(int, index) | 
 | 		__field(u8, type) | 
 | 		__field(size_t, size) | 
 | 		__dynamic_array(u32, data, size / 4) | 
 | 		__field(bool, dropped) | 
 | 	), | 
 | 	TP_fast_assign( | 
 | 		__entry->index = index; | 
 | 		__entry->type = type; | 
 | 		__entry->size = size / 4; | 
 | 		memcpy(__get_dynamic_array(data), data, size); | 
 | 		__entry->dropped = dropped; | 
 | 	), | 
 | 	TP_printk("type=%s, dropped=%u, size=%zd, domain=%d, %s", | 
 | 		  show_type_name(__entry->type), __entry->dropped, | 
 | 		  __entry->size, __entry->index, | 
 | 		  show_data(p, __entry->type, __get_dynamic_array(data), | 
 | 			    __entry->size) | 
 | 	) | 
 | ); | 
 |  | 
 | #endif /* TB_TRACE_H_ */ | 
 |  | 
 | #undef TRACE_INCLUDE_PATH | 
 | #define TRACE_INCLUDE_PATH . | 
 |  | 
 | #undef TRACE_INCLUDE_FILE | 
 | #define TRACE_INCLUDE_FILE trace | 
 |  | 
 | /* This part must be outside protection */ | 
 | #include <trace/define_trace.h> |