Loading Documentation/arm/msm/msm_ipc_logging.txt 0 → 100644 +361 −0 Original line number Diff line number Diff line Introduction ============ This module will be used to log the events by any module/driver which enables Inter Processor Communication (IPC). Some of the IPC drivers such as Message Routers, Multiplexers etc. which act as a passive pipe need some mechanism to log their events. Since all such IPC drivers handle a large amount of traffic/events, using kernel logs renders kernel logs unusable by other drivers and also degrades the performance of IPC drivers. This new module will help in logging such high frequency IPC driver events while keeping the standard kernel logging mechanism intact. Hardware description ==================== This module does not drive any hardware resource and will only use the kernel memory-space to log the events. Software description ==================== Design Goals ------------ This module is designed to * support logging for drivers handling large amount of traffic/events * define & differentiate events/logs from different drivers * support both id-based and stream-based logging * support extracting the logs from both live target & memory dump IPC Log Context ---------------- This module will support logging by multiple drivers. To differentiate between the multiple drivers that are using this logging mechanism, each driver will be assigned a unique context by this module. Associated with each context is the logging space, dynamically allocated from the kernel memory-space, specific to that context so that the events logged using that context will not interfere with other contexts. Event Logging -------------- Every event will be logged as a <Type: Size: Value> combination. Type field identifies the type of the event that is logged. Size field represents the size of the log information. Value field represents the actual information being logged. This approach will support both id-based logging and stream-based logging. This approach will also support logging sub-events of an event. This module will provide helper routines to encode/decode the logs to/from this format. Encode Context --------------- Encode context is a temporary storage space that will be used by the client drivers to log the events in <Type: Size: Value> format. The client drivers will perform an encode start operation to initialize the encode context data structure. Then the client drivers will log their events into the encode context. Upon completion of event logging, the client drivers will perform an encode end operation to finalize the encode context data structure to be logged. Then this updated encode context data structure will be written into the client driver's IPC Log Context. The maximum event log size will be defined as 256 bytes. Log Space ---------- Each context (Figure 1) has an associated log space, which is dynamically allocated from the kernel memory-space. The log space is organized as a list of 1 or more kernel memory pages. Each page (Figure 2) contains header information which is used to differentiate the log kernel page from the other kernel pages. 0 --------------------------------- | magic_no = 0x25874452 | --------------------------------- | nmagic_no = 0x52784425 | --------------------------------- | version | --------------------------------- | user_version | --------------------------------- | log_id | --------------------------------- | header_size | --------------------------------- | | | | | name [20 chars] | | | | | --------------------------------- | run-time data structures | --------------------------------- Figure 1 - Log Context Structure 31 0 0 --------------------------------- | magic_no = 0x52784425 | --------------------------------- | nmagic_no = 0xAD87BBDA | --------------------------------- |1| page_num | --------------------------------- | read_offset | write_offset | --------------------------------- | log_id | --------------------------------- | start_time low word | | start_time high word | --------------------------------- | end_time low word | | end_time high word | --------------------------------- | context offset | --------------------------------- | run-time data structures | . . . . . --------------------------------- | | | Log Data | . . . . . . | | --------------------------------- PAGE_SIZE - 1 Figure 2 - Log Page Structure In addition to extracting logs at runtime through DebugFS, IPC Logging has been designed to allow extraction of logs from a memory dump. The magic numbers, timestamps, and context offset are all added to support the memory-dump extraction use case. Design ====== Alternate solutions discussed include using kernel & SMEM logs which are limited in size and hence using them render them unusable by other drivers. Also kernel logging into serial console is slowing down the performance of the drivers by multiple times and sometimes lead to APPs watchdog bite. Power Management ================ Not-Applicable SMP/multi-core ============== This module uses spinlocks & mutexes to handle multi-core safety. Security ======== Not-Applicable Performance =========== This logging mechanism, based on experimental data, is not expected to cause a significant performance degradation. Under worst case, it can cause 1 - 2 percent degradation in the throughput of the IPC Drivers. Interface ========= Exported Data Structures ------------------------ struct encode_context { struct tsv_header hdr; char buff[MAX_MSG_SIZE]; int offset; }; struct decode_context { int output_format; char *buff; int size; }; Kernel-Space Interface APIs ---------------------------- /* * ipc_log_context_create: Create a ipc log context * * @max_num_pages: Number of pages of logging space required (max. 10) * @mod_name : Name of the directory entry under DEBUGFS * @user_version : Version number of user-defined message formats * * returns reference to context on success, NULL on failure */ void *ipc_log_context_create(int max_num_pages, const char *mod_name, uint16_t user_version); /* * msg_encode_start: Start encoding a log message * * @ectxt: Temporary storage to hold the encoded message * @type: Root event type defined by the module which is logging */ void msg_encode_start(struct encode_context *ectxt, uint32_t type); /* * msg_encode_end: Complete the message encode process * * @ectxt: Temporary storage which holds the encoded message */ void msg_encode_end(struct encode_context *ectxt); /* * tsv_timestamp_write: Writes the current timestamp count * * @ectxt: Context initialized by calling msg_encode_start() * * Returns 0 on success, -ve error code on failure */ int tsv_timestamp_write(struct encode_context *ectxt); /* * tsv_pointer_write: Writes a data pointer * * @ectxt: Context initialized by calling msg_encode_start() * @pointer: Pointer value to write * * Returns 0 on success, -ve error code on failure */ int tsv_pointer_write(struct encode_context *ectxt, void *pointer); /* * tsv_int32_write: Writes a 32-bit integer value * * @ectxt: Context initialized by calling msg_encode_start() * @n: Integer to write * * Returns 0 on success, -ve error code on failure */ int tsv_int32_write(struct encode_context *ectxt, int32_t n); /* * tsv_byte_array_write: Writes a byte array * * @ectxt: Context initialized by calling msg_encode_start() * @data: Location of data * @data_size: Size of data to be written * * Returns 0 on success, -ve error code on failure */ int tsv_byte_array_write(struct encode_context *ectxt, void *data, int data_size); /* * ipc_log_write: Write the encoded message into the log space * * @ctxt: IPC log context where the message has to be logged into * @ectxt: Temporary storage containing the encoded message */ void ipc_log_write(unsigned long ctxt, struct encode_context *ectxt); /* * ipc_log_string: Helper function to log a string * * @dlctxt: IPC Log Context created using ipc_log_context_create() * @fmt: Data specified using format specifiers */ int ipc_log_string(unsigned long dlctxt, const char *fmt, ...); /* * tsv_timestamp_read: Reads a timestamp * * @ectxt: Context retrieved by reading from log space * @dctxt: Temporary storage to hold the decoded message * @format: Output format while dumping through DEBUGFS */ void tsv_timestamp_read(struct encode_context *ectxt, struct decode_context *dctxt, const char *format); /* * tsv_pointer_read: Reads a data pointer * * @ectxt: Context retrieved by reading from log space * @dctxt: Temporary storage to hold the decoded message * @format: Output format while dumping through DEBUGFS */ void tsv_pointer_read(struct encode_context *ectxt, struct decode_context *dctxt, const char *format); /* * tsv_int32_read: Reads a 32-bit integer value * * @ectxt: Context retrieved by reading from log space * @dctxt: Temporary storage to hold the decoded message * @format: Output format while dumping through DEBUGFS */ void tsv_int32_read(struct encode_context *ectxt, struct decode_context *dctxt, const char *format); /* * tsv_byte_array_read: Reads a byte array/string * * @ectxt: Context retrieved by reading from log space * @dctxt: Temporary storage to hold the decoded message * @format: Output format while dumping through DEBUGFS */ void tsv_byte_array_read(struct encode_context *ectxt, struct decode_context *dctxt, const char *format); /* * add_deserialization_func: Register a deserialization function to * to unpack the subevents of a main event * * @ctxt: IPC log context to which the deserialization function has * to be registered * @type: Main/Root event, defined by the module which is logging, to * which this deserialization function has to be registered. * @dfune: Deserialization function to be registered * * return 0 on success, -ve value on FAILURE */ int add_deserialization_func(unsigned long ctxt, int type, void (*dfunc)(struct encode_context *, struct decode_context *)); Driver parameters ================= Not-Applicable Config options ============== Not-Applicable Dependencies ============ This module will partially depend on CONFIG_DEBUGFS, in order to dump the logs through debugfs. If CONFIG_DEBUGFS is disabled, the above mentioned helper functions will perform no operation and return appropriate error code if the return value is non void. Under such circumstances the logs can only be extracted through the memory dump. User space utilities ==================== DEBUGFS Other ===== Not-Applicable Known issues ============ None To do ===== None include/linux/ipc_logging.h 0 → 100644 +285 −0 Original line number Diff line number Diff line /* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2012-2015,2017 The Linux Foundation. All rights reserved. */ #ifndef _IPC_LOGGING_H #define _IPC_LOGGING_H #include <linux/types.h> #define MAX_MSG_SIZE 255 enum { TSV_TYPE_MSG_START = 1, TSV_TYPE_SKB = TSV_TYPE_MSG_START, TSV_TYPE_STRING, TSV_TYPE_MSG_END = TSV_TYPE_STRING, }; struct tsv_header { unsigned char type; unsigned char size; /* size of data field */ }; struct encode_context { struct tsv_header hdr; char buff[MAX_MSG_SIZE]; int offset; }; struct decode_context { int output_format; /* 0 = debugfs */ char *buff; /* output buffer */ int size; /* size of output buffer */ }; #if defined(CONFIG_IPC_LOGGING) /* * ipc_log_context_create: Create a debug log context * Should not be called from atomic context * * @max_num_pages: Number of pages of logging space required (max. 10) * @mod_name : Name of the directory entry under DEBUGFS * @user_version : Version number of user-defined message formats * * returns context id on success, NULL on failure */ void *ipc_log_context_create(int max_num_pages, const char *modname, uint16_t user_version); /* * msg_encode_start: Start encoding a log message * * @ectxt: Temporary storage to hold the encoded message * @type: Root event type defined by the module which is logging */ void msg_encode_start(struct encode_context *ectxt, uint32_t type); /* * tsv_timestamp_write: Writes the current timestamp count * * @ectxt: Context initialized by calling msg_encode_start() */ int tsv_timestamp_write(struct encode_context *ectxt); /* * tsv_qtimer_write: Writes the current QTimer timestamp count * * @ectxt: Context initialized by calling msg_encode_start() */ int tsv_qtimer_write(struct encode_context *ectxt); /* * tsv_pointer_write: Writes a data pointer * * @ectxt: Context initialized by calling msg_encode_start() * @pointer: Pointer value to write */ int tsv_pointer_write(struct encode_context *ectxt, void *pointer); /* * tsv_int32_write: Writes a 32-bit integer value * * @ectxt: Context initialized by calling msg_encode_start() * @n: Integer to write */ int tsv_int32_write(struct encode_context *ectxt, int32_t n); /* * tsv_byte_array_write: Writes a byte array * * @ectxt: Context initialized by calling msg_encode_start() * @data: Pointer to byte array * @data_size: Size of byte array */ int tsv_byte_array_write(struct encode_context *ectxt, void *data, int data_size); /* * msg_encode_end: Complete the message encode process * * @ectxt: Temporary storage which holds the encoded message */ void msg_encode_end(struct encode_context *ectxt); /* * ipc_log_write: Commits message to logging ring buffer * * @ctxt: Logging context * @ectxt: Temporary storage which holds the encoded message */ void ipc_log_write(void *ctxt, struct encode_context *ectxt); /* * ipc_log_string: Helper function to log a string * * @ilctxt: Debug Log Context created using ipc_log_context_create() * @fmt: Data specified using format specifiers */ int ipc_log_string(void *ilctxt, const char *fmt, ...) __printf(2, 3); /** * ipc_log_extract - Reads and deserializes log * * @ilctxt: logging context * @buff: buffer to receive the data * @size: size of the buffer * @returns: 0 if no data read; >0 number of bytes read; < 0 error * * If no data is available to be read, then the ilctxt::read_avail * completion is reinitialized. This allows clients to block * until new log data is save. */ int ipc_log_extract(void *ilctxt, char *buff, int size); /* * Print a string to decode context. * @dctxt Decode context * @args printf args */ #define IPC_SPRINTF_DECODE(dctxt, args...) \ do { \ int i; \ i = scnprintf(dctxt->buff, dctxt->size, args); \ dctxt->buff += i; \ dctxt->size -= i; \ } while (0) /* * tsv_timestamp_read: Reads a timestamp * * @ectxt: Context retrieved by reading from log space * @dctxt: Temporary storage to hold the decoded message * @format: Output format while dumping through DEBUGFS */ void tsv_timestamp_read(struct encode_context *ectxt, struct decode_context *dctxt, const char *format); /* * tsv_qtimer_read: Reads a QTimer timestamp * * @ectxt: Context retrieved by reading from log space * @dctxt: Temporary storage to hold the decoded message * @format: Output format while dumping through DEBUGFS */ void tsv_qtimer_read(struct encode_context *ectxt, struct decode_context *dctxt, const char *format); /* * tsv_pointer_read: Reads a data pointer * * @ectxt: Context retrieved by reading from log space * @dctxt: Temporary storage to hold the decoded message * @format: Output format while dumping through DEBUGFS */ void tsv_pointer_read(struct encode_context *ectxt, struct decode_context *dctxt, const char *format); /* * tsv_int32_read: Reads a 32-bit integer value * * @ectxt: Context retrieved by reading from log space * @dctxt: Temporary storage to hold the decoded message * @format: Output format while dumping through DEBUGFS */ int32_t tsv_int32_read(struct encode_context *ectxt, struct decode_context *dctxt, const char *format); /* * tsv_byte_array_read: Reads a byte array * * @ectxt: Context retrieved by reading from log space * @dctxt: Temporary storage to hold the decoded message * @format: Output format while dumping through DEBUGFS */ void tsv_byte_array_read(struct encode_context *ectxt, struct decode_context *dctxt, const char *format); /* * add_deserialization_func: Register a deserialization function to * to unpack the subevents of a main event * * @ctxt: Debug log context to which the deserialization function has * to be registered * @type: Main/Root event, defined by the module which is logging, to * which this deserialization function has to be registered. * @dfune: Deserialization function to be registered * * return 0 on success, -ve value on FAILURE */ int add_deserialization_func(void *ctxt, int type, void (*dfunc)(struct encode_context *, struct decode_context *)); /* * ipc_log_context_destroy: Destroy debug log context * * @ctxt: debug log context created by calling ipc_log_context_create API. */ int ipc_log_context_destroy(void *ctxt); #else static inline void *ipc_log_context_create(int max_num_pages, const char *modname, uint16_t user_version) { return NULL; } static inline void msg_encode_start(struct encode_context *ectxt, uint32_t type) { } static inline int tsv_timestamp_write(struct encode_context *ectxt) { return -EINVAL; } static inline int tsv_qtimer_write(struct encode_context *ectxt) { return -EINVAL; } static inline int tsv_pointer_write(struct encode_context *ectxt, void *pointer) { return -EINVAL; } static inline int tsv_int32_write(struct encode_context *ectxt, int32_t n) { return -EINVAL; } static inline int tsv_byte_array_write(struct encode_context *ectxt, void *data, int data_size) { return -EINVAL; } static inline void msg_encode_end(struct encode_context *ectxt) { } static inline void ipc_log_write(void *ctxt, struct encode_context *ectxt) { } static inline int ipc_log_string(void *ilctxt, const char *fmt, ...) { return -EINVAL; } static inline int ipc_log_extract(void *ilctxt, char *buff, int size) { return -EINVAL; } #define IPC_SPRINTF_DECODE(dctxt, args...) do { } while (0) static inline void tsv_timestamp_read(struct encode_context *ectxt, struct decode_context *dctxt, const char *format) { } static inline void tsv_qtimer_read(struct encode_context *ectxt, struct decode_context *dctxt, const char *format) { } static inline void tsv_pointer_read(struct encode_context *ectxt, struct decode_context *dctxt, const char *format) { } static inline int32_t tsv_int32_read(struct encode_context *ectxt, struct decode_context *dctxt, const char *format) { return 0; } static inline void tsv_byte_array_read(struct encode_context *ectxt, struct decode_context *dctxt, const char *format) { } static inline int add_deserialization_func(void *ctxt, int type, void (*dfunc)(struct encode_context *, struct decode_context *)) { return 0; } static inline int ipc_log_context_destroy(void *ctxt) { return 0; } #endif #endif kernel/trace/Kconfig +11 −0 Original line number Diff line number Diff line Loading @@ -88,6 +88,17 @@ config RING_BUFFER_ALLOW_SWAP Allow the use of ring_buffer_swap_cpu. Adds a very slight overhead to tracing when enabled. config IPC_LOGGING bool "Debug Logging for IPC Drivers" select GENERIC_TRACER help IPC Logging driver provides a logging option for IPC Drivers. This provides a cyclic buffer based logging support in a driver specific context. This driver also provides a debugfs interface to dump the logs in a live fashion. If in doubt, say no. config PREEMPTIRQ_TRACEPOINTS bool depends on TRACE_PREEMPT_TOGGLE || TRACE_IRQFLAGS Loading kernel/trace/Makefile +4 −0 Original line number Diff line number Diff line Loading @@ -85,4 +85,8 @@ obj-$(CONFIG_UPROBE_EVENTS) += trace_uprobe.o obj-$(CONFIG_TRACEPOINT_BENCHMARK) += trace_benchmark.o obj-$(CONFIG_IPC_LOGGING) += ipc_logging.o ifdef CONFIG_DEBUG_FS obj-$(CONFIG_IPC_LOGGING) += ipc_logging_debug.o endif libftrace-y := ftrace.o Loading
Documentation/arm/msm/msm_ipc_logging.txt 0 → 100644 +361 −0 Original line number Diff line number Diff line Introduction ============ This module will be used to log the events by any module/driver which enables Inter Processor Communication (IPC). Some of the IPC drivers such as Message Routers, Multiplexers etc. which act as a passive pipe need some mechanism to log their events. Since all such IPC drivers handle a large amount of traffic/events, using kernel logs renders kernel logs unusable by other drivers and also degrades the performance of IPC drivers. This new module will help in logging such high frequency IPC driver events while keeping the standard kernel logging mechanism intact. Hardware description ==================== This module does not drive any hardware resource and will only use the kernel memory-space to log the events. Software description ==================== Design Goals ------------ This module is designed to * support logging for drivers handling large amount of traffic/events * define & differentiate events/logs from different drivers * support both id-based and stream-based logging * support extracting the logs from both live target & memory dump IPC Log Context ---------------- This module will support logging by multiple drivers. To differentiate between the multiple drivers that are using this logging mechanism, each driver will be assigned a unique context by this module. Associated with each context is the logging space, dynamically allocated from the kernel memory-space, specific to that context so that the events logged using that context will not interfere with other contexts. Event Logging -------------- Every event will be logged as a <Type: Size: Value> combination. Type field identifies the type of the event that is logged. Size field represents the size of the log information. Value field represents the actual information being logged. This approach will support both id-based logging and stream-based logging. This approach will also support logging sub-events of an event. This module will provide helper routines to encode/decode the logs to/from this format. Encode Context --------------- Encode context is a temporary storage space that will be used by the client drivers to log the events in <Type: Size: Value> format. The client drivers will perform an encode start operation to initialize the encode context data structure. Then the client drivers will log their events into the encode context. Upon completion of event logging, the client drivers will perform an encode end operation to finalize the encode context data structure to be logged. Then this updated encode context data structure will be written into the client driver's IPC Log Context. The maximum event log size will be defined as 256 bytes. Log Space ---------- Each context (Figure 1) has an associated log space, which is dynamically allocated from the kernel memory-space. The log space is organized as a list of 1 or more kernel memory pages. Each page (Figure 2) contains header information which is used to differentiate the log kernel page from the other kernel pages. 0 --------------------------------- | magic_no = 0x25874452 | --------------------------------- | nmagic_no = 0x52784425 | --------------------------------- | version | --------------------------------- | user_version | --------------------------------- | log_id | --------------------------------- | header_size | --------------------------------- | | | | | name [20 chars] | | | | | --------------------------------- | run-time data structures | --------------------------------- Figure 1 - Log Context Structure 31 0 0 --------------------------------- | magic_no = 0x52784425 | --------------------------------- | nmagic_no = 0xAD87BBDA | --------------------------------- |1| page_num | --------------------------------- | read_offset | write_offset | --------------------------------- | log_id | --------------------------------- | start_time low word | | start_time high word | --------------------------------- | end_time low word | | end_time high word | --------------------------------- | context offset | --------------------------------- | run-time data structures | . . . . . --------------------------------- | | | Log Data | . . . . . . | | --------------------------------- PAGE_SIZE - 1 Figure 2 - Log Page Structure In addition to extracting logs at runtime through DebugFS, IPC Logging has been designed to allow extraction of logs from a memory dump. The magic numbers, timestamps, and context offset are all added to support the memory-dump extraction use case. Design ====== Alternate solutions discussed include using kernel & SMEM logs which are limited in size and hence using them render them unusable by other drivers. Also kernel logging into serial console is slowing down the performance of the drivers by multiple times and sometimes lead to APPs watchdog bite. Power Management ================ Not-Applicable SMP/multi-core ============== This module uses spinlocks & mutexes to handle multi-core safety. Security ======== Not-Applicable Performance =========== This logging mechanism, based on experimental data, is not expected to cause a significant performance degradation. Under worst case, it can cause 1 - 2 percent degradation in the throughput of the IPC Drivers. Interface ========= Exported Data Structures ------------------------ struct encode_context { struct tsv_header hdr; char buff[MAX_MSG_SIZE]; int offset; }; struct decode_context { int output_format; char *buff; int size; }; Kernel-Space Interface APIs ---------------------------- /* * ipc_log_context_create: Create a ipc log context * * @max_num_pages: Number of pages of logging space required (max. 10) * @mod_name : Name of the directory entry under DEBUGFS * @user_version : Version number of user-defined message formats * * returns reference to context on success, NULL on failure */ void *ipc_log_context_create(int max_num_pages, const char *mod_name, uint16_t user_version); /* * msg_encode_start: Start encoding a log message * * @ectxt: Temporary storage to hold the encoded message * @type: Root event type defined by the module which is logging */ void msg_encode_start(struct encode_context *ectxt, uint32_t type); /* * msg_encode_end: Complete the message encode process * * @ectxt: Temporary storage which holds the encoded message */ void msg_encode_end(struct encode_context *ectxt); /* * tsv_timestamp_write: Writes the current timestamp count * * @ectxt: Context initialized by calling msg_encode_start() * * Returns 0 on success, -ve error code on failure */ int tsv_timestamp_write(struct encode_context *ectxt); /* * tsv_pointer_write: Writes a data pointer * * @ectxt: Context initialized by calling msg_encode_start() * @pointer: Pointer value to write * * Returns 0 on success, -ve error code on failure */ int tsv_pointer_write(struct encode_context *ectxt, void *pointer); /* * tsv_int32_write: Writes a 32-bit integer value * * @ectxt: Context initialized by calling msg_encode_start() * @n: Integer to write * * Returns 0 on success, -ve error code on failure */ int tsv_int32_write(struct encode_context *ectxt, int32_t n); /* * tsv_byte_array_write: Writes a byte array * * @ectxt: Context initialized by calling msg_encode_start() * @data: Location of data * @data_size: Size of data to be written * * Returns 0 on success, -ve error code on failure */ int tsv_byte_array_write(struct encode_context *ectxt, void *data, int data_size); /* * ipc_log_write: Write the encoded message into the log space * * @ctxt: IPC log context where the message has to be logged into * @ectxt: Temporary storage containing the encoded message */ void ipc_log_write(unsigned long ctxt, struct encode_context *ectxt); /* * ipc_log_string: Helper function to log a string * * @dlctxt: IPC Log Context created using ipc_log_context_create() * @fmt: Data specified using format specifiers */ int ipc_log_string(unsigned long dlctxt, const char *fmt, ...); /* * tsv_timestamp_read: Reads a timestamp * * @ectxt: Context retrieved by reading from log space * @dctxt: Temporary storage to hold the decoded message * @format: Output format while dumping through DEBUGFS */ void tsv_timestamp_read(struct encode_context *ectxt, struct decode_context *dctxt, const char *format); /* * tsv_pointer_read: Reads a data pointer * * @ectxt: Context retrieved by reading from log space * @dctxt: Temporary storage to hold the decoded message * @format: Output format while dumping through DEBUGFS */ void tsv_pointer_read(struct encode_context *ectxt, struct decode_context *dctxt, const char *format); /* * tsv_int32_read: Reads a 32-bit integer value * * @ectxt: Context retrieved by reading from log space * @dctxt: Temporary storage to hold the decoded message * @format: Output format while dumping through DEBUGFS */ void tsv_int32_read(struct encode_context *ectxt, struct decode_context *dctxt, const char *format); /* * tsv_byte_array_read: Reads a byte array/string * * @ectxt: Context retrieved by reading from log space * @dctxt: Temporary storage to hold the decoded message * @format: Output format while dumping through DEBUGFS */ void tsv_byte_array_read(struct encode_context *ectxt, struct decode_context *dctxt, const char *format); /* * add_deserialization_func: Register a deserialization function to * to unpack the subevents of a main event * * @ctxt: IPC log context to which the deserialization function has * to be registered * @type: Main/Root event, defined by the module which is logging, to * which this deserialization function has to be registered. * @dfune: Deserialization function to be registered * * return 0 on success, -ve value on FAILURE */ int add_deserialization_func(unsigned long ctxt, int type, void (*dfunc)(struct encode_context *, struct decode_context *)); Driver parameters ================= Not-Applicable Config options ============== Not-Applicable Dependencies ============ This module will partially depend on CONFIG_DEBUGFS, in order to dump the logs through debugfs. If CONFIG_DEBUGFS is disabled, the above mentioned helper functions will perform no operation and return appropriate error code if the return value is non void. Under such circumstances the logs can only be extracted through the memory dump. User space utilities ==================== DEBUGFS Other ===== Not-Applicable Known issues ============ None To do ===== None
include/linux/ipc_logging.h 0 → 100644 +285 −0 Original line number Diff line number Diff line /* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2012-2015,2017 The Linux Foundation. All rights reserved. */ #ifndef _IPC_LOGGING_H #define _IPC_LOGGING_H #include <linux/types.h> #define MAX_MSG_SIZE 255 enum { TSV_TYPE_MSG_START = 1, TSV_TYPE_SKB = TSV_TYPE_MSG_START, TSV_TYPE_STRING, TSV_TYPE_MSG_END = TSV_TYPE_STRING, }; struct tsv_header { unsigned char type; unsigned char size; /* size of data field */ }; struct encode_context { struct tsv_header hdr; char buff[MAX_MSG_SIZE]; int offset; }; struct decode_context { int output_format; /* 0 = debugfs */ char *buff; /* output buffer */ int size; /* size of output buffer */ }; #if defined(CONFIG_IPC_LOGGING) /* * ipc_log_context_create: Create a debug log context * Should not be called from atomic context * * @max_num_pages: Number of pages of logging space required (max. 10) * @mod_name : Name of the directory entry under DEBUGFS * @user_version : Version number of user-defined message formats * * returns context id on success, NULL on failure */ void *ipc_log_context_create(int max_num_pages, const char *modname, uint16_t user_version); /* * msg_encode_start: Start encoding a log message * * @ectxt: Temporary storage to hold the encoded message * @type: Root event type defined by the module which is logging */ void msg_encode_start(struct encode_context *ectxt, uint32_t type); /* * tsv_timestamp_write: Writes the current timestamp count * * @ectxt: Context initialized by calling msg_encode_start() */ int tsv_timestamp_write(struct encode_context *ectxt); /* * tsv_qtimer_write: Writes the current QTimer timestamp count * * @ectxt: Context initialized by calling msg_encode_start() */ int tsv_qtimer_write(struct encode_context *ectxt); /* * tsv_pointer_write: Writes a data pointer * * @ectxt: Context initialized by calling msg_encode_start() * @pointer: Pointer value to write */ int tsv_pointer_write(struct encode_context *ectxt, void *pointer); /* * tsv_int32_write: Writes a 32-bit integer value * * @ectxt: Context initialized by calling msg_encode_start() * @n: Integer to write */ int tsv_int32_write(struct encode_context *ectxt, int32_t n); /* * tsv_byte_array_write: Writes a byte array * * @ectxt: Context initialized by calling msg_encode_start() * @data: Pointer to byte array * @data_size: Size of byte array */ int tsv_byte_array_write(struct encode_context *ectxt, void *data, int data_size); /* * msg_encode_end: Complete the message encode process * * @ectxt: Temporary storage which holds the encoded message */ void msg_encode_end(struct encode_context *ectxt); /* * ipc_log_write: Commits message to logging ring buffer * * @ctxt: Logging context * @ectxt: Temporary storage which holds the encoded message */ void ipc_log_write(void *ctxt, struct encode_context *ectxt); /* * ipc_log_string: Helper function to log a string * * @ilctxt: Debug Log Context created using ipc_log_context_create() * @fmt: Data specified using format specifiers */ int ipc_log_string(void *ilctxt, const char *fmt, ...) __printf(2, 3); /** * ipc_log_extract - Reads and deserializes log * * @ilctxt: logging context * @buff: buffer to receive the data * @size: size of the buffer * @returns: 0 if no data read; >0 number of bytes read; < 0 error * * If no data is available to be read, then the ilctxt::read_avail * completion is reinitialized. This allows clients to block * until new log data is save. */ int ipc_log_extract(void *ilctxt, char *buff, int size); /* * Print a string to decode context. * @dctxt Decode context * @args printf args */ #define IPC_SPRINTF_DECODE(dctxt, args...) \ do { \ int i; \ i = scnprintf(dctxt->buff, dctxt->size, args); \ dctxt->buff += i; \ dctxt->size -= i; \ } while (0) /* * tsv_timestamp_read: Reads a timestamp * * @ectxt: Context retrieved by reading from log space * @dctxt: Temporary storage to hold the decoded message * @format: Output format while dumping through DEBUGFS */ void tsv_timestamp_read(struct encode_context *ectxt, struct decode_context *dctxt, const char *format); /* * tsv_qtimer_read: Reads a QTimer timestamp * * @ectxt: Context retrieved by reading from log space * @dctxt: Temporary storage to hold the decoded message * @format: Output format while dumping through DEBUGFS */ void tsv_qtimer_read(struct encode_context *ectxt, struct decode_context *dctxt, const char *format); /* * tsv_pointer_read: Reads a data pointer * * @ectxt: Context retrieved by reading from log space * @dctxt: Temporary storage to hold the decoded message * @format: Output format while dumping through DEBUGFS */ void tsv_pointer_read(struct encode_context *ectxt, struct decode_context *dctxt, const char *format); /* * tsv_int32_read: Reads a 32-bit integer value * * @ectxt: Context retrieved by reading from log space * @dctxt: Temporary storage to hold the decoded message * @format: Output format while dumping through DEBUGFS */ int32_t tsv_int32_read(struct encode_context *ectxt, struct decode_context *dctxt, const char *format); /* * tsv_byte_array_read: Reads a byte array * * @ectxt: Context retrieved by reading from log space * @dctxt: Temporary storage to hold the decoded message * @format: Output format while dumping through DEBUGFS */ void tsv_byte_array_read(struct encode_context *ectxt, struct decode_context *dctxt, const char *format); /* * add_deserialization_func: Register a deserialization function to * to unpack the subevents of a main event * * @ctxt: Debug log context to which the deserialization function has * to be registered * @type: Main/Root event, defined by the module which is logging, to * which this deserialization function has to be registered. * @dfune: Deserialization function to be registered * * return 0 on success, -ve value on FAILURE */ int add_deserialization_func(void *ctxt, int type, void (*dfunc)(struct encode_context *, struct decode_context *)); /* * ipc_log_context_destroy: Destroy debug log context * * @ctxt: debug log context created by calling ipc_log_context_create API. */ int ipc_log_context_destroy(void *ctxt); #else static inline void *ipc_log_context_create(int max_num_pages, const char *modname, uint16_t user_version) { return NULL; } static inline void msg_encode_start(struct encode_context *ectxt, uint32_t type) { } static inline int tsv_timestamp_write(struct encode_context *ectxt) { return -EINVAL; } static inline int tsv_qtimer_write(struct encode_context *ectxt) { return -EINVAL; } static inline int tsv_pointer_write(struct encode_context *ectxt, void *pointer) { return -EINVAL; } static inline int tsv_int32_write(struct encode_context *ectxt, int32_t n) { return -EINVAL; } static inline int tsv_byte_array_write(struct encode_context *ectxt, void *data, int data_size) { return -EINVAL; } static inline void msg_encode_end(struct encode_context *ectxt) { } static inline void ipc_log_write(void *ctxt, struct encode_context *ectxt) { } static inline int ipc_log_string(void *ilctxt, const char *fmt, ...) { return -EINVAL; } static inline int ipc_log_extract(void *ilctxt, char *buff, int size) { return -EINVAL; } #define IPC_SPRINTF_DECODE(dctxt, args...) do { } while (0) static inline void tsv_timestamp_read(struct encode_context *ectxt, struct decode_context *dctxt, const char *format) { } static inline void tsv_qtimer_read(struct encode_context *ectxt, struct decode_context *dctxt, const char *format) { } static inline void tsv_pointer_read(struct encode_context *ectxt, struct decode_context *dctxt, const char *format) { } static inline int32_t tsv_int32_read(struct encode_context *ectxt, struct decode_context *dctxt, const char *format) { return 0; } static inline void tsv_byte_array_read(struct encode_context *ectxt, struct decode_context *dctxt, const char *format) { } static inline int add_deserialization_func(void *ctxt, int type, void (*dfunc)(struct encode_context *, struct decode_context *)) { return 0; } static inline int ipc_log_context_destroy(void *ctxt) { return 0; } #endif #endif
kernel/trace/Kconfig +11 −0 Original line number Diff line number Diff line Loading @@ -88,6 +88,17 @@ config RING_BUFFER_ALLOW_SWAP Allow the use of ring_buffer_swap_cpu. Adds a very slight overhead to tracing when enabled. config IPC_LOGGING bool "Debug Logging for IPC Drivers" select GENERIC_TRACER help IPC Logging driver provides a logging option for IPC Drivers. This provides a cyclic buffer based logging support in a driver specific context. This driver also provides a debugfs interface to dump the logs in a live fashion. If in doubt, say no. config PREEMPTIRQ_TRACEPOINTS bool depends on TRACE_PREEMPT_TOGGLE || TRACE_IRQFLAGS Loading
kernel/trace/Makefile +4 −0 Original line number Diff line number Diff line Loading @@ -85,4 +85,8 @@ obj-$(CONFIG_UPROBE_EVENTS) += trace_uprobe.o obj-$(CONFIG_TRACEPOINT_BENCHMARK) += trace_benchmark.o obj-$(CONFIG_IPC_LOGGING) += ipc_logging.o ifdef CONFIG_DEBUG_FS obj-$(CONFIG_IPC_LOGGING) += ipc_logging_debug.o endif libftrace-y := ftrace.o