Skip to contentSkip to conversation

Register read/write tracing with dynamic debug and pstore

RFC PATCH In review Sai Prakash Ranjan 4 participants 12 messages Aug 24, 2018 – Sep 6, 2018

Subsystems (7)
lore
Share & tools
lore
#0 lore raw

v2 cover Register read/write tracing with dynamic debug and pstore

Hi,

This patch series adds a new tracing facility for register reads and writes called Register Trace Buffer(RTB).

We also add pstore support through which we can save all register read/write logs into a persistent ram buffer that can be dumped after reboot.

It can be used to determine from where register was read/written before unclocked access or some kind of bus hang or an unexpected reset caused by some buggy driver which happens a lot during initial development stages.

In addition to this, we provide dynamic debug support to filter out unwanted logs and limit trace to only specific files or directories since there can be aweful lot of register events and we will be interested only in specific drivers or subsystems which we will be working on. Last few RTB entries will give us the hint for debugging. With dynamic debug, we are also reducing the overhead of tracing considerably.

Also as a bonus, this tracing can be extended to include IRQ, printk, context switch and lot other things with proper hooks. It can be very helpful for real case debug scenarios.

Below is a simple example of identifying cause for bus hang in qcom mdp tested on db410c. This hang was intentionally introduced just to show the usecase of RTB.
The module used can be found here: https://github.com/saiprakash-ranjan/Bus-Hang which does an unclocked access and will reset db410c and later logs can be viewed through pstore.

Note: I just copied bus_hang.c to drivers/soc/qcom and built it.

1) Set bootargs with dyndbg parameter as below:

# dyndbg="file drivers/soc/qcom/* +p"

2) Bus hang by reading below debugfs entry with bus_hang module.

   # cat /sys/kernel/debug/hang/bus_hang

3) After restart, we can find the cause in last entry i.e. (bus_hang_mdp+0x98/0xb0)

   # cat /sys/fs/pstore/rtb-ramoops-0
   [LOGK_WRITE] ts:1373101930  data:ffff00000cd065a4  <ffff00000867cb44>  qcom_smsm_probe+0x51c/0x668
   [LOGK_WRITE] ts:1373311878  data:ffff00000cd06608  <ffff00000867cb44>  qcom_smsm_probe+0x51c/0x668
   [LOGK_READ ] ts:18177142294  data:ffff00000ab85040 <ffff00000867cdc8>  bus_hang_mdp+0x98/0xb0

4) Offending register access found as below:

# (gdb)
# (gdb) list *(bus_hang_mdp+0x98)
# 0xffff00000867cdc8 is in bus_hang_mdp (drivers/soc/qcom/bus_hang.c:10).
# 5 static int bus_hang_mdp(void *data, u64 *val)
# 6 {
# 7 void *p = ioremap(0x01a01000, SZ_4K);
# 8 unsigned int a;
# 9
# 10 a = __raw_readl((void *)((unsigned long)p + 0x40)); <----
# 11
# 12 *val = a;
# 13
# 14 return 0;
# (gdb)

There will be a lot more real usecases where RTB can be used. Maybe we can test on other boards as well.

This trace module is based on RTB driver in CAF.

Patchwise one line description is given below:

Patch 1 provides the api called uncached_logk which is then called within dynamic_rtb for logging register accesses, i.e. (read/write{b,w,l,q})

Patch 2 adds the pstore support for displaying the logs after reset.

Patch 3 adds dynamic debug support to filter the register read/write{b,w,l,q} access. Also this patch adds asm-generic/io-instrumented.h file for keeping instrumentation away from arch code as suggested by Will Deacon.

v2:
* Addressed Will's comment to keep instrumentation out of arch code and also remove duplicate code
* Addressed Steven's comments regarding code cleanup
* Fixed commit description to be more specific about register accesses i.e., use read/write{b,l,w,q} instead of readl/writel since we will be tracing all

Sai Prakash Ranjan (3):
tracing: Add support for logging data to uncached buffer
pstore: Add register read/write{b,w,l,q} tracing support
dynamic_debug: Add support for dynamic register trace

 .../bindings/reserved-memory/ramoops.txt      |   7 +-
 arch/arm64/include/asm/io.h                   |  26 ++--
 fs/pstore/Kconfig                             |  12 ++
 fs/pstore/Makefile                            |   1 +
 fs/pstore/inode.c                             |  71 ++++++++-
 fs/pstore/internal.h                          |   8 +
 fs/pstore/platform.c                          |   4 +
 fs/pstore/ram.c                               |  42 ++++-
 fs/pstore/rtb.c                               |  45 ++++++
 include/asm-generic/io-instrumented.h         |  32 ++++
 include/linux/dynamic_debug.h                 |  13 ++
 include/linux/pstore.h                        |   2 +
 include/linux/pstore_ram.h                    |   1 +
 include/linux/rtb.h                           |  31 ++++
 kernel/trace/Kconfig                          |   8 +
 kernel/trace/Makefile                         |   2 +
 kernel/trace/trace_rtb.c                      | 146 ++++++++++++++++++
 17 files changed, 430 insertions(+), 21 deletions(-)
 create mode 100644 fs/pstore/rtb.c
 create mode 100644 include/asm-generic/io-instrumented.h
 create mode 100644 include/linux/rtb.h
 create mode 100644 kernel/trace/trace_rtb.c
Signature · 2 lines
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member
of Code Aurora Forum, hosted by The Linux Foundation
#1 lore raw

RFC PATCH v2 1/3 tracing: Add support for logging data to uncached buffer

Add RTB trace support to write data to a small uncached buffer. When a system reset occurs, valuable data may still be remaining in the cache (e.g. last printks) and this data will probably be lost, giving an incomplete picture of what the system was last doing. By logging useful information to this uncached region (e.g. read/write{b,w,l,q}, last printk), a better picture of what the system was last doing can be obtained.

Dummy platform device is created to use dma api to allocate uncached memory. Also initialize dma_mask and coherent_dma_mask after commit 4d8bde883bfb ("OF: Don't set default coherent DMA mask").

We add an additional property called rtb-size in ramoops device tree node for pstore RTB buffer size and use the same in the trace module. DT documentation has been modified to include this.

Information logged in this buffer include log type(read/write{b,w,l,q}), timestamp, extra data from the caller, caller ip and name. This can be extented as needed to include more options(e.g. cpu) for better debugging.

Also RTB panic notifier with high priority is used to make sure that RTB is disabled right after a kernel panic so that log buffer could be prevented from being flooded with some I/O operations.

This is based on RTB driver in CAF. Link below:
* https://source.codeaurora.org/quic/la/kernel/msm-4.9
Modified to support pstore for viewing traces.

---
 .../bindings/reserved-memory/ramoops.txt      |   7 +-
 include/linux/rtb.h                           |  24 +++
 kernel/trace/Kconfig                          |   7 +
 kernel/trace/Makefile                         |   2 +
 kernel/trace/trace_rtb.c                      | 143 ++++++++++++++++++
 5 files changed, 181 insertions(+), 2 deletions(-)
 create mode 100644 include/linux/rtb.h
 create mode 100644 kernel/trace/trace_rtb.c
Documentation/devicetree/bindings/reserved-memory/ramoops.txt +5 -2
index 0eba562fe5c6..f99019d1119b 100644
@@ -14,8 +14,8 @@ Any remaining space will be used for a circular buffer of oops and panic
 records.  These records have a configurable size, with a size of 0 indicating
 that they should be disabled.
 
-At least one of "record-size", "console-size", "ftrace-size", or "pmsg-size"
-must be set non-zero, but are otherwise optional as listed below.
+At least one of "record-size", "console-size", "ftrace-size", "pmsg-size" or
+"rtb-size" must be set non-zero, but are otherwise optional as listed below.
 
 
 Required properties:
@@ -42,6 +42,9 @@ Optional properties:
 - pmsg-size: size in bytes of log buffer reserved for userspace messages
   (defaults to 0: disabled)
 
+- rtb-size: size in bytes of log buffer reserved for RTB buffer traces.
+  (defaults to 0: disabled)
+
 - unbuffered: if present, use unbuffered mappings to map the reserved region
   (defaults to buffered mappings)
 
include/linux/rtb.h new file +24 -0
new file mode 100644
index 000000000000..a969bd020466
@@ -0,0 +1,24 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _RTB_H
+#define _RTB_H
+
+struct rtb_layout {
+	const char *log_type;
+	u32 idx;
+	u64 caller;
+	u64 data;
+	u64 timestamp;
+} __attribute__ ((__packed__));
+
+#if defined(CONFIG_RTB)
+void uncached_logk(const char *log_type, void *data);
+int rtb_init(void);
+void rtb_exit(void);
+#else
+static inline void uncached_logk(const char *log_type,
+				void *data) { }
+static inline int rtb_init(void) { return 0; }
+static inline void rtb_exit(void) { }
+#endif
+
+#endif /* _RTB_H */
kernel/trace/Kconfig +7 -0
index c042a455afc6..fd46c7e0016f 100644
@@ -774,6 +774,13 @@ config TRACING_EVENTS_GPIO
 	help
 	  Enable tracing events for gpio subsystem
 
+config RTB
+	bool "Register Trace Buffer"
+	help
+	  Add support for logging different events to a small uncached
+	  region. This is designed to aid in debugging reset cases where the
+	  caches may not be flushed before the target resets.
+
 endif # FTRACE
 
 endif # TRACING_SUPPORT
kernel/trace/Makefile +2 -0
index 98d53b39a8ee..0b8167124354 100644
@@ -78,4 +78,6 @@ obj-$(CONFIG_UPROBE_EVENTS) += trace_uprobe.o
 
 obj-$(CONFIG_TRACEPOINT_BENCHMARK) += trace_benchmark.o
 
+obj-$(CONFIG_RTB) += trace_rtb.o
+
 libftrace-y := ftrace.o
kernel/trace/trace_rtb.c new file +143 -0

143 lines not on this page · raw message

Signature · 2 lines
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member
of Code Aurora Forum, hosted by The Linux Foundation
#2 lore raw

RFC PATCH v2 2/3 pstore: Add register read/write{b,w,l,q} tracing support

In reply to Sai Prakash Ranjan

read/write{b,w,l,q} are typically used for reading from memory mapped registers, which can cause hangs if accessed unclocked. Tracing these events can help in debugging various issues faced during initial development.

We log this trace information in persistent ram buffer which can be viewed after reset.

We use pstore_rtb_call() to write the RTB log to pstore. RTB buffer size is taken from ramoops dt node with additional property called rtb-size.

For reading the trace after mounting pstore, rtb-ramoops entry can be seen in /sys/fs/pstore/ as in below sample output.

Sample output of tracing register reads/writes in drivers:

 # mount -t pstore pstore /sys/fs/pstore
 # tail /sys/fs/pstore/rtb-ramoops-0
 [LOGK_READ ] ts:36468476204  data:ffff00000800d0fc  <ffff0000084e9ee0>  gic_check_gicv2+0x58/0x60
 [LOGK_WRITE] ts:36468477715  data:ffff00000800d000  <ffff0000084e9fac>  gic_cpu_if_up+0xc4/0x110
 [LOGK_READ ] ts:36468478548  data:ffff00000800d000  <ffff0000084e9fd8>  gic_cpu_if_up+0xf0/0x110
 [LOGK_WRITE] ts:36468480319  data:ffff00000800d000  <ffff0000084e9fac>  gic_cpu_if_up+0xc4/0x110
 [LOGK_READ ] ts:36468481048  data:ffff00000800d00c  <ffff000008081a34>  gic_handle_irq+0xac/0x128
 [LOGK_WRITE] ts:36468482923  data:ffff00000800d010  <ffff000008081aac>  gic_handle_irq+0x124/0x128
 [LOGK_READ ] ts:36468483184  data:ffff00000800d00c  <ffff000008081a34>  gic_handle_irq+0xac/0x128
 [LOGK_WRITE] ts:36468485215  data:ffff00000800d010  <ffff000008081aac>  gic_handle_irq+0x124/0x128
 [LOGK_READ ] ts:36468486309  data:ffff00000800d00c  <ffff000008081a34>  gic_handle_irq+0xac/0x128
 [LOGK_WRITE] ts:36468488236  data:ffff00000800d010  <ffff000008081aac>  gic_handle_irq+0x124/0x128

Output has below 5 fields:

* Log type, Timestamp, Data from caller which is the address of read/write{b,w,l,q}, Caller ip and Caller name.

---
 fs/pstore/Kconfig          | 12 +++++++
 fs/pstore/Makefile         |  1 +
 fs/pstore/inode.c          | 71 +++++++++++++++++++++++++++++++++++++-
 fs/pstore/internal.h       |  8 +++++
 fs/pstore/platform.c       |  4 +++
 fs/pstore/ram.c            | 42 ++++++++++++++++++++--
 fs/pstore/rtb.c            | 45 ++++++++++++++++++++++++
 include/linux/pstore.h     |  2 ++
 include/linux/pstore_ram.h |  1 +
 include/linux/rtb.h        |  7 ++++
 kernel/trace/trace_rtb.c   |  3 ++
 11 files changed, 193 insertions(+), 3 deletions(-)
 create mode 100644 fs/pstore/rtb.c
fs/pstore/Kconfig +12 -0
index 503086f7f7c1..4f1ba1253dfd 100644
@@ -124,6 +124,18 @@ config PSTORE_PMSG
 
 	  If unsure, say N.
 
+config PSTORE_RTB
+	bool "Log register operations like read/write"
+	depends on PSTORE && PSTORE!=m
+	depends on RTB
+	help
+	  When this option is enabled, rtb driver will log all register
+	  reads/writes into a persistent ram buffer that can be decoded
+	  and dumped after reboot through pstore filesystem. It can be used
+	  to debug readl/writel access.
+
+	  If unsure, say N.
+
 config PSTORE_FTRACE
 	bool "Persistent function tracer"
 	depends on PSTORE
fs/pstore/Makefile +1 -0
index 967b5891f325..c772c9420f57 100644
@@ -9,6 +9,7 @@ pstore-objs += inode.o platform.o
 pstore-$(CONFIG_PSTORE_FTRACE)	+= ftrace.o
 
 pstore-$(CONFIG_PSTORE_PMSG)	+= pmsg.o
+pstore-$(CONFIG_PSTORE_RTB)	+= rtb.o
 
 ramoops-objs += ram.o ram_core.o
 obj-$(CONFIG_PSTORE_RAM)	+= ramoops.o
fs/pstore/inode.c +70 -1

107 lines not on this page · raw message

fs/pstore/internal.h +8 -0
index fb767e28aeb2..a5498e8b89d2 100644
@@ -25,6 +25,14 @@ static inline void pstore_register_pmsg(void) {}
 static inline void pstore_unregister_pmsg(void) {}
 #endif
 
+#ifdef CONFIG_PSTORE_RTB
+extern void pstore_register_rtb(void);
+extern void pstore_unregister_rtb(void);
+#else
+static inline void pstore_register_rtb(void) {}
+static inline void pstore_unregister_rtb(void) {}
+#endif
+
 extern struct pstore_info *psinfo;
 
 extern void	pstore_set_kmsg_bytes(int);
fs/pstore/platform.c +4 -0
index 15e99d5a681d..3473a7456585 100644
@@ -589,6 +589,8 @@ int pstore_register(struct pstore_info *psi)
 		pstore_register_ftrace();
 	if (psi->flags & PSTORE_FLAGS_PMSG)
 		pstore_register_pmsg();
+	if (psi->flags & PSTORE_FLAGS_RTB)
+		pstore_register_rtb();
 
 	/* Start watching for new records, if desired. */
 	if (pstore_update_ms >= 0) {
@@ -618,6 +620,8 @@ void pstore_unregister(struct pstore_info *psi)
 	del_timer_sync(&pstore_timer);
 	flush_work(&pstore_work);
 
+	if (psi->flags & PSTORE_FLAGS_RTB)
+		pstore_unregister_rtb();
 	if (psi->flags & PSTORE_FLAGS_PMSG)
 		pstore_unregister_pmsg();
 	if (psi->flags & PSTORE_FLAGS_FTRACE)
fs/pstore/ram.c +40 -2

156 lines not on this page · raw message

fs/pstore/rtb.c new file +45 -0

45 lines not on this page · raw message

include/linux/pstore.h +2 -0
index a15bc4d48752..07ae7afe9d3a 100644
@@ -44,6 +44,7 @@ enum pstore_type_id {
 	PSTORE_TYPE_PPC_COMMON	= 6,
 	PSTORE_TYPE_PMSG	= 7,
 	PSTORE_TYPE_PPC_OPAL	= 8,
+	PSTORE_TYPE_RTB		= 9,
 	PSTORE_TYPE_UNKNOWN	= 255
 };
 
@@ -193,6 +194,7 @@ struct pstore_info {
 #define PSTORE_FLAGS_CONSOLE	(1 << 1)
 #define PSTORE_FLAGS_FTRACE	(1 << 2)
 #define PSTORE_FLAGS_PMSG	(1 << 3)
+#define PSTORE_FLAGS_RTB	(1 << 4)
 
 extern int pstore_register(struct pstore_info *);
 extern void pstore_unregister(struct pstore_info *);
include/linux/pstore_ram.h +1 -0
index e6d226464838..81eee723f2bb 100644
@@ -97,6 +97,7 @@ struct ramoops_platform_data {
 	unsigned long	console_size;
 	unsigned long	ftrace_size;
 	unsigned long	pmsg_size;
+	unsigned long	rtb_size;
 	int		dump_oops;
 	u32		flags;
 	struct persistent_ram_ecc_info ecc_info;
include/linux/rtb.h +7 -0
index a969bd020466..169a77b4a565 100644
@@ -21,4 +21,11 @@ static inline int rtb_init(void) { return 0; }
 static inline void rtb_exit(void) { }
 #endif
 
+#if defined(CONFIG_PSTORE_RTB)
+extern void pstore_rtb_call(struct rtb_layout *start);
+#else
+static inline void pstore_rtb_call(struct rtb_layout *start)
+{ }
+#endif
+
 #endif /* _RTB_H */
kernel/trace/trace_rtb.c +3 -0
index 3e0a85e7b504..26b87b3e6a03 100644
@@ -51,6 +51,9 @@ static void uncached_logk_pc_idx(const char *log_type, u64 caller,
 	start->timestamp = sched_clock();
 	/* Make sure data is written */
 	mb();
+#if defined(CONFIG_PSTORE_RTB)
+	pstore_rtb_call(start);
+#endif
 }
 
 static int rtb_get_idx(void)
Signature · 2 lines
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member
of Code Aurora Forum, hosted by The Linux Foundation
#3 lore raw

Re: [RFC PATCH v2 2/3] pstore: Add register read/write{b,w,l,q} tracing support

Quoted 30 lines · Sai Prakash Ranjan

read/write{b,w,l,q} are typically used for reading from memory mapped registers, which can cause hangs if accessed unclocked. Tracing these events can help in debugging various issues faced during initial development.

We log this trace information in persistent ram buffer which can be viewed after reset.

We use pstore_rtb_call() to write the RTB log to pstore. RTB buffer size is taken from ramoops dt node with additional property called rtb-size.

For reading the trace after mounting pstore, rtb-ramoops entry can be seen in /sys/fs/pstore/ as in below sample output.

Sample output of tracing register reads/writes in drivers:

 # mount -t pstore pstore /sys/fs/pstore
 # tail /sys/fs/pstore/rtb-ramoops-0
 [LOGK_READ ] ts:36468476204  data:ffff00000800d0fc  <ffff0000084e9ee0>  gic_check_gicv2+0x58/0x60
 [LOGK_WRITE] ts:36468477715  data:ffff00000800d000  <ffff0000084e9fac>  gic_cpu_if_up+0xc4/0x110
 [LOGK_READ ] ts:36468478548  data:ffff00000800d000  <ffff0000084e9fd8>  gic_cpu_if_up+0xf0/0x110
 [LOGK_WRITE] ts:36468480319  data:ffff00000800d000  <ffff0000084e9fac>  gic_cpu_if_up+0xc4/0x110
 [LOGK_READ ] ts:36468481048  data:ffff00000800d00c  <ffff000008081a34>  gic_handle_irq+0xac/0x128
 [LOGK_WRITE] ts:36468482923  data:ffff00000800d010  <ffff000008081aac>  gic_handle_irq+0x124/0x128
 [LOGK_READ ] ts:36468483184  data:ffff00000800d00c  <ffff000008081a34>  gic_handle_irq+0xac/0x128
 [LOGK_WRITE] ts:36468485215  data:ffff00000800d010  <ffff000008081aac>  gic_handle_irq+0x124/0x128
 [LOGK_READ ] ts:36468486309  data:ffff00000800d00c  <ffff000008081a34>  gic_handle_irq+0xac/0x128
 [LOGK_WRITE] ts:36468488236  data:ffff00000800d010  <ffff000008081aac>  gic_handle_irq+0x124/0x128
Quoted 6 lines

Output has below 5 fields:

* Log type, Timestamp, Data from caller which is the address of read/write{b,w,l,q}, Caller ip and Caller name.

As this is a tracing-like method, could this instead be added to ftrace? That would mean it could reuse all the ftrace tools and you'd get pstore storage for free.

-Kees

Signature · 2 lines
Kees Cook
Pixel Security
#4 lore raw

Re: [RFC PATCH v2 2/3] pstore: Add register read/write{b,w,l,q} tracing support

Quoted 34 lines · Kees Cook
Quoted 32 lines · Sai Prakash Ranjan

read/write{b,w,l,q} are typically used for reading from memory mapped registers, which can cause hangs if accessed unclocked. Tracing these events can help in debugging various issues faced during initial development.

We log this trace information in persistent ram buffer which can be viewed after reset.

We use pstore_rtb_call() to write the RTB log to pstore. RTB buffer size is taken from ramoops dt node with additional property called rtb-size.

For reading the trace after mounting pstore, rtb-ramoops entry can be seen in /sys/fs/pstore/ as in below sample output.

Sample output of tracing register reads/writes in drivers:

  # mount -t pstore pstore /sys/fs/pstore
  # tail /sys/fs/pstore/rtb-ramoops-0
  [LOGK_READ ] ts:36468476204  data:ffff00000800d0fc  <ffff0000084e9ee0>  gic_check_gicv2+0x58/0x60
  [LOGK_WRITE] ts:36468477715  data:ffff00000800d000  <ffff0000084e9fac>  gic_cpu_if_up+0xc4/0x110
  [LOGK_READ ] ts:36468478548  data:ffff00000800d000  <ffff0000084e9fd8>  gic_cpu_if_up+0xf0/0x110
  [LOGK_WRITE] ts:36468480319  data:ffff00000800d000  <ffff0000084e9fac>  gic_cpu_if_up+0xc4/0x110
  [LOGK_READ ] ts:36468481048  data:ffff00000800d00c  <ffff000008081a34>  gic_handle_irq+0xac/0x128
  [LOGK_WRITE] ts:36468482923  data:ffff00000800d010  <ffff000008081aac>  gic_handle_irq+0x124/0x128
  [LOGK_READ ] ts:36468483184  data:ffff00000800d00c  <ffff000008081a34>  gic_handle_irq+0xac/0x128
  [LOGK_WRITE] ts:36468485215  data:ffff00000800d010  <ffff000008081aac>  gic_handle_irq+0x124/0x128
  [LOGK_READ ] ts:36468486309  data:ffff00000800d00c  <ffff000008081a34>  gic_handle_irq+0xac/0x128
  [LOGK_WRITE] ts:36468488236  data:ffff00000800d010  <ffff000008081aac>  gic_handle_irq+0x124/0x128

Output has below 5 fields:

Quoted 9 lines
Quoted 4 lines

* Log type, Timestamp, Data from caller which is the address of read/write{b,w,l,q}, Caller ip and Caller name.

As this is a tracing-like method, could this instead be added to ftrace? That would mean it could reuse all the ftrace tools and you'd get pstore storage for free.

Ftrace does not trace __raw{read,write}{b,l,w,q}() functions. I am not sure why and how it is filtered out because I do not see any notrace flag in those functions, maybe that whole directory is filtered out. So adding this functionality to ftrace would mean removing the notrace for these functions i.e., something like using __raw{read,write}{b,l,w,q}() as the available filter functions. Also pstore ftrace does not filter functions to trace I suppose?

Coming to the reason as to why it would be good to keep this separate from ftrace would be:
* Ftrace can get ip and parent ip, but suppose we need extra data (field data) as in above sample output we would not be able to get through ftrace.

* Although this patch is for tracing register read/write, we can easily add more functionality since we have dynamic_rtb api which can be hooked to functions and start tracing events(IRQ, Context ID) something similar to tracepoints.
Initially thought of having tracepoints for logging register read/write but I do not know if we can export tracepoint data to pstore since the main usecase is to debug unknown resets and hangs.

* This can be something similar to mmiotrace in x86 and kept seperate from function tracer.

Thanks,
Sai Prakash

maintainer
#5 lore raw

Re: [RFC PATCH v2 2/3] pstore: Add register read/write{b,w,l,q} tracing support

Quoted 7 lines · On Sat, 25 Aug 2018 12:54:07 +0530 Sai Prakash Ranjan…

Ftrace does not trace __raw{read,write}{b,l,w,q}() functions. I am not sure why and how it is filtered out because I do not see any notrace flag in those functions, maybe that whole directory is filtered out. So adding this functionality to ftrace would mean removing the notrace for these functions i.e., something like using __raw{read,write}{b,l,w,q}() as the available filter functions. Also pstore ftrace does not filter functions to trace I suppose?

It's not traced because it is inlined. Simply make the __raw_read function a normal function and it will be traced. And then you could use ftrace to read the function.

If this has to be per arch, you can register your callback with the REGS flags, and pt_regs will be passed to your callback function you attached to __raw_read*() as if you inserted a break point at that location, and you can get any reg data you want there.

Quoted 5 lines

Coming to the reason as to why it would be good to keep this separate from ftrace would be:
* Ftrace can get ip and parent ip, but suppose we need extra data (field data) as in above sample output we would not be able to get through ftrace.

As mentioned above, you can get regs (and ftrace is being expanded now to get parameters of functions).

Quoted 8 lines

* Although this patch is for tracing register read/write, we can easily add more functionality since we have dynamic_rtb api which can be hooked to functions and start tracing events(IRQ, Context ID) something similar to tracepoints.
Initially thought of having tracepoints for logging register read/write but I do not know if we can export tracepoint data to pstore since the main usecase is to debug unknown resets and hangs.

I don't know why not? We have read/write tracepoints for read/write_msr() calls in x86.

Anything can add a hook to the callback of the tracepoints, and use that infrastructure instead of creating yet another dynamic code modification infrastructure.

Quoted 3 lines

* This can be something similar to mmiotrace in x86 and kept seperate from function tracer.

mmiotrace is separate because it faults on writes so that we can capture any reads and writes to the system that a binary driver does.

-- Steve

#6 lore raw

Re: [RFC PATCH v2 2/3] pstore: Add register read/write{b,w,l,q} tracing support

Quoted 12 lines · Steven Rostedt
Quoted 7 lines · On Sat, 25 Aug 2018 12:54:07 +0530 Sai Prakash Ranjan…

Ftrace does not trace __raw{read,write}{b,l,w,q}() functions. I am not sure why and how it is filtered out because I do not see any notrace flag in those functions, maybe that whole directory is filtered out. So adding this functionality to ftrace would mean removing the notrace for these functions i.e., something like using __raw{read,write}{b,l,w,q}() as the available filter functions. Also pstore ftrace does not filter functions to trace I suppose?

Quoted 10 lines

It's not traced because it is inlined. Simply make the __raw_read function a normal function and it will be traced. And then you could use ftrace to read the function.

If this has to be per arch, you can register your callback with the REGS flags, and pt_regs will be passed to your callback function you attached to __raw_read*() as if you inserted a break point at that location, and you can get any reg data you want there.

Thank you very much for the information Steven. Ok so we can get function parameters with pt_regs.

Quoted 9 lines
Quoted 5 lines

Coming to the reason as to why it would be good to keep this separate from ftrace would be:
* Ftrace can get ip and parent ip, but suppose we need extra data (field data) as in above sample output we would not be able to get through ftrace.

As mentioned above, you can get regs (and ftrace is being expanded now to get parameters of functions).

You mean there is another way to get parameters other than regs?

Quoted 9 lines
Quoted 8 lines

* Although this patch is for tracing register read/write, we can easily add more functionality since we have dynamic_rtb api which can be hooked to functions and start tracing events(IRQ, Context ID) something similar to tracepoints.
Initially thought of having tracepoints for logging register read/write but I do not know if we can export tracepoint data to pstore since the main usecase is to debug unknown resets and hangs.

Quoted 7 lines

I don't know why not? We have read/write tracepoints for read/write_msr() calls in x86.

Anything can add a hook to the callback of the tracepoints, and use that infrastructure instead of creating yet another dynamic code modification infrastructure.

Thanks for pointing out to read/write_msr, I checked it and was able to implement something similar for arm64. But still can we export tracepoint data to pstore because we need to debug reset cases and for that pstore is of real importance?. If so then it would be great to have various events logged into pstore which can be a lot of help for debugging.

Also with the current dynamic filtering of read/write(PATCH 3/3), it is a lot easier to filter register read/write since we use dynamic debug framework which provides file, function and line level filtering capacity. Maybe if we can add something like this to trace events it would be better?

- Sai Prakash

maintainer
#7 lore raw

Re: [RFC PATCH v2 2/3] pstore: Add register read/write{b,w,l,q} tracing support

Quoted 24 lines · On Tue, 28 Aug 2018 18:47:33 +0530 Sai Prakash Ranjan…
Quoted 12 lines · Steven Rostedt
Quoted 7 lines · On Sat, 25 Aug 2018 12:54:07 +0530 Sai Prakash Ranjan…

Ftrace does not trace __raw{read,write}{b,l,w,q}() functions. I am not sure why and how it is filtered out because I do not see any notrace flag in those functions, maybe that whole directory is filtered out. So adding this functionality to ftrace would mean removing the notrace for these functions i.e., something like using __raw{read,write}{b,l,w,q}() as the available filter functions. Also pstore ftrace does not filter functions to trace I suppose?

Quoted 10 lines

It's not traced because it is inlined. Simply make the __raw_read function a normal function and it will be traced. And then you could use ftrace to read the function.

If this has to be per arch, you can register your callback with the REGS flags, and pt_regs will be passed to your callback function you attached to __raw_read*() as if you inserted a break point at that location, and you can get any reg data you want there.

Quoted 2 lines

Thank you very much for the information Steven. Ok so we can get function parameters with pt_regs.

Yes.

Quoted 11 lines
Quoted 10 lines
Quoted 6 lines

Coming to the reason as to why it would be good to keep this separate from ftrace would be:
* Ftrace can get ip and parent ip, but suppose we need extra data (field data) as in above sample output we would not be able to get through ftrace.

As mentioned above, you can get regs (and ftrace is being expanded now to get parameters of functions).

You mean there is another way to get parameters other than regs?

No, but you could register a callback function to be called when a function is hit, and the pt_regs are passed to it. We are working on getting parameters from the pt_regs (see this patch:
http://lkml.kernel.org/r/152465885737.26224.2822487520472783854.stgit at devbox)

Quoted 23 lines
Quoted 10 lines
Quoted 9 lines

* Although this patch is for tracing register read/write, we can easily add more functionality since we have dynamic_rtb api which can be hooked to functions and start tracing events(IRQ, Context ID) something similar to tracepoints.
Initially thought of having tracepoints for logging register read/write but I do not know if we can export tracepoint data to pstore since the main usecase is to debug unknown resets and hangs.

Quoted 7 lines

I don't know why not? We have read/write tracepoints for read/write_msr() calls in x86.

Anything can add a hook to the callback of the tracepoints, and use that infrastructure instead of creating yet another dynamic code modification infrastructure.

Thanks for pointing out to read/write_msr, I checked it and was able to implement something similar for arm64. But still can we export tracepoint data to pstore because we need to debug reset cases and for that pstore is of real importance?. If so then it would be great to have various events logged into pstore which can be a lot of help for debugging.

Quoted 5 lines

Also with the current dynamic filtering of read/write(PATCH 3/3), it is a lot easier to filter register read/write since we use dynamic debug framework which provides file, function and line level filtering capacity. Maybe if we can add something like this to trace events it would be better?

I would recommend using the tracepoint infrastructure. Note, tracepoints and trace events are two different things. Trace events use tracepoints, and you use trace events to create tracepoints, thus they are tightly coupled. But once a tracepoint exists, anything can connect to them without needing to use the trace event.

Let's look at the read_msr trace event. Because it is in a header, to avoid "include hell" we open code some of it:

static inline unsigned long long native_read_msr(unsigned int msr)

{
	unsigned long long val;

	val = __rdmsr(msr);

	if (msr_tracepoint_active(__tracepoint_read_msr))
		do_trace_read_msr(msr, val, 0);

	return val;
}

Where:

#ifdef CONFIG_TRACEPOINTS
#define msr_tracepoint_active(t) static_key_false(&(t).key) #else
#define msr_tracepoint_active(t) false
#endif

We have to open code the access to the tracepoint.key because msr.h is used in a lot of critical headers, we couldn't use the normal tracepoint.h header here.

The "static_key_false()" is a jump label that is just a nop. When the static_key is enabled, the nop is converted to a static "jmp" to the code that calls "do_trace_read_msr()". This is a function call to a function defined in msr.c (where we can do proper includes), and all that does is call the tracepoint "trace_read_msr()", which is also a static key that, when enabled, will iterate over a list of functions it should call with the defined parameters (msr, val, failed).

When defining the trace event for "read_msr", it creates the tracepoint "trace_read_msr()" and we place it in this do_trace_read_msr() function. The TRACE_EVENT() macros creates everything that is needed to connect the trace event "read_msr" to the tracepoint "trace_read_msr()", and you can enable this via the tracefs subsystem or via perf.

But you can also add your own hook to that tracepoint. If you have code that does:

register_trace_read_msr(func, data);

The "func" gets called when trace_read_msr() is hit. Thus you could have:

static void my_func(void *data, unsigned msr, u64 val, int failed)

{
	struct my_struct *my_data = data;

	do_something_with(my_data, msr, val, failed);
}
{
	struct my_struct *my_data;

	my_data = kzalloc(sizeof(*my_data)), GFP_KERNEL);

	register_trace_read_msr(my_func, my_data);
}

And then your function "my_func" will be called with any data you registered with it (you may register "NULL" if you don't need to pass in data), and it will also get the parameters passed to trace_read_msr()

If you want to have you "my_func" record into pstore, then it will happen at runtime, and if the system resets, you have your data where you want it.

-- Steve

#8 lore raw

Re: [RFC PATCH v2 2/3] pstore: Add register read/write{b,w,l,q} tracing support

Quoted 42 lines · Steven Rostedt
Quoted 24 lines · On Tue, 28 Aug 2018 18:47:33 +0530 Sai Prakash Ranjan…
Quoted 12 lines · Steven Rostedt
Quoted 7 lines · On Sat, 25 Aug 2018 12:54:07 +0530 Sai Prakash Ranjan…

Ftrace does not trace __raw{read,write}{b,l,w,q}() functions. I am not sure why and how it is filtered out because I do not see any notrace flag in those functions, maybe that whole directory is filtered out. So adding this functionality to ftrace would mean removing the notrace for these functions i.e., something like using __raw{read,write}{b,l,w,q}() as the available filter functions. Also pstore ftrace does not filter functions to trace I suppose?

Quoted 10 lines

It's not traced because it is inlined. Simply make the __raw_read function a normal function and it will be traced. And then you could use ftrace to read the function.

If this has to be per arch, you can register your callback with the REGS flags, and pt_regs will be passed to your callback function you attached to __raw_read*() as if you inserted a break point at that location, and you can get any reg data you want there.

Quoted 2 lines

Thank you very much for the information Steven. Ok so we can get function parameters with pt_regs.

Yes.

Quoted 10 lines
Quoted 10 lines
Quoted 6 lines

Coming to the reason as to why it would be good to keep this separate from ftrace would be:
* Ftrace can get ip and parent ip, but suppose we need extra data (field data) as in above sample output we would not be able to get through ftrace.

As mentioned above, you can get regs (and ftrace is being expanded now to get parameters of functions).

Quoted 7 lines
Quoted 1 line

You mean there is another way to get parameters other than regs?

No, but you could register a callback function to be called when a function is hit, and the pt_regs are passed to it. We are working on getting parameters from the pt_regs (see this patch:
http://lkml.kernel.org/r/152465885737.26224.2822487520472783854.stgit at devbox)

Cool, thanks for the link.

Quoted 101 lines
Quoted 23 lines
Quoted 10 lines
Quoted 9 lines

* Although this patch is for tracing register read/write, we can easily add more functionality since we have dynamic_rtb api which can be hooked to functions and start tracing events(IRQ, Context ID) something similar to tracepoints.
Initially thought of having tracepoints for logging register read/write but I do not know if we can export tracepoint data to pstore since the main usecase is to debug unknown resets and hangs.

Quoted 7 lines

I don't know why not? We have read/write tracepoints for read/write_msr() calls in x86.

Anything can add a hook to the callback of the tracepoints, and use that infrastructure instead of creating yet another dynamic code modification infrastructure.

Thanks for pointing out to read/write_msr, I checked it and was able to implement something similar for arm64. But still can we export tracepoint data to pstore because we need to debug reset cases and for that pstore is of real importance?. If so then it would be great to have various events logged into pstore which can be a lot of help for debugging.

Quoted 5 lines

Also with the current dynamic filtering of read/write(PATCH 3/3), it is a lot easier to filter register read/write since we use dynamic debug framework which provides file, function and line level filtering capacity. Maybe if we can add something like this to trace events it would be better?

I would recommend using the tracepoint infrastructure. Note, tracepoints and trace events are two different things. Trace events use tracepoints, and you use trace events to create tracepoints, thus they are tightly coupled. But once a tracepoint exists, anything can connect to them without needing to use the trace event.

Let's look at the read_msr trace event. Because it is in a header, to avoid "include hell" we open code some of it:

static inline unsigned long long native_read_msr(unsigned int msr)

{
	unsigned long long val;

	val = __rdmsr(msr);

	if (msr_tracepoint_active(__tracepoint_read_msr))
		do_trace_read_msr(msr, val, 0);

	return val;
}

Where:

#ifdef CONFIG_TRACEPOINTS
#define msr_tracepoint_active(t) static_key_false(&(t).key) #else
#define msr_tracepoint_active(t) false
#endif

We have to open code the access to the tracepoint.key because msr.h is used in a lot of critical headers, we couldn't use the normal tracepoint.h header here.

The "static_key_false()" is a jump label that is just a nop. When the static_key is enabled, the nop is converted to a static "jmp" to the code that calls "do_trace_read_msr()". This is a function call to a function defined in msr.c (where we can do proper includes), and all that does is call the tracepoint "trace_read_msr()", which is also a static key that, when enabled, will iterate over a list of functions it should call with the defined parameters (msr, val, failed).

When defining the trace event for "read_msr", it creates the tracepoint "trace_read_msr()" and we place it in this do_trace_read_msr() function. The TRACE_EVENT() macros creates everything that is needed to connect the trace event "read_msr" to the tracepoint "trace_read_msr()", and you can enable this via the tracefs subsystem or via perf.

But you can also add your own hook to that tracepoint. If you have code that does:

register_trace_read_msr(func, data);

The "func" gets called when trace_read_msr() is hit. Thus you could have:

static void my_func(void *data, unsigned msr, u64 val, int failed)

{
	struct my_struct *my_data = data;

	do_something_with(my_data, msr, val, failed);
}
{
	struct my_struct *my_data;

	my_data = kzalloc(sizeof(*my_data)), GFP_KERNEL);

	register_trace_read_msr(my_func, my_data);
}
Quoted 8 lines

And then your function "my_func" will be called with any data you registered with it (you may register "NULL" if you don't need to pass in data), and it will also get the parameters passed to trace_read_msr()

If you want to have you "my_func" record into pstore, then it will happen at runtime, and if the system resets, you have your data where you want it.

Wow, thank you so much for the detailed explanation, it helps a lot. I will try to use this and post next version soon.

- Sai Prakash

#9 lore raw

RFC PATCH v2 3/3 dynamic_debug: Add support for dynamic register trace

In reply to Sai Prakash Ranjan

Introduce dynamic debug filtering mechanism to register tracing as dynamic_rtb() which will reduce a lot of overhead otherwise of tracing all the register reads/writes in all files.

Now we can just specify the file name or any wildcard pattern as any other dynamic debug facility in bootargs and dynamic rtb will just trace them and the output can be seen in pstore.

TODO: Now we use same 'p' flag but will add a separate flag for register trace later.

Also add asm-generic/io-instrumented.h file for instrumentation of IO operations such as read/write{b,w,l,q} as per Will's suggestion to not touch arch code and let core generate instrumentation.
This can be extended to arm as well later for tracing.

Example for tracing all register reads/writes in drivers/soc/qcom/* below:

# dyndbg="file drivers/soc/qcom/* +p" in bootargs

  # reboot -f
  # mount -t pstore pstore /sys/fs/pstore
  # cat /sys/fs/pstore/rtb-ramoops-0
    [LOGK_WRITE] ts:1373030419  data:ffff00000d5065a4  <ffff00000867cb44>  qcom_smsm_probe+0x51c/0x668
    [LOGK_WRITE] ts:1373360576  data:ffff00000d506608  <ffff00000867cb44>  qcom_smsm_probe+0x51c/0x668
---
 arch/arm64/include/asm/io.h           | 26 +++++++++-------------
 include/asm-generic/io-instrumented.h | 32 +++++++++++++++++++++++++++
 include/linux/dynamic_debug.h         | 13 +++++++++++
 kernel/trace/Kconfig                  |  1 +
 4 files changed, 56 insertions(+), 16 deletions(-)
 create mode 100644 include/asm-generic/io-instrumented.h
arch/arm64/include/asm/io.h +10 -16
index 35b2e50f17fb..aafd4b0be9f0 100644
@@ -22,6 +22,7 @@
 #ifdef __KERNEL__
 
 #include <linux/types.h>
+#include <linux/rtb.h>
 
 #include <asm/byteorder.h>
 #include <asm/barrier.h>
@@ -36,32 +37,27 @@
 /*
  * Generic IO read/write.  These perform native-endian accesses.
  */
-#define __raw_writeb __raw_writeb
-static inline void __raw_writeb(u8 val, volatile void __iomem *addr)
+static inline void arch_raw_writeb(u8 val, volatile void __iomem *addr)
 {
 	asm volatile("strb %w0, [%1]" : : "rZ" (val), "r" (addr));
 }
 
-#define __raw_writew __raw_writew
-static inline void __raw_writew(u16 val, volatile void __iomem *addr)
+static inline void arch_raw_writew(u16 val, volatile void __iomem *addr)
 {
 	asm volatile("strh %w0, [%1]" : : "rZ" (val), "r" (addr));
 }
 
-#define __raw_writel __raw_writel
-static inline void __raw_writel(u32 val, volatile void __iomem *addr)
+static inline void arch_raw_writel(u32 val, volatile void __iomem *addr)
 {
 	asm volatile("str %w0, [%1]" : : "rZ" (val), "r" (addr));
 }
 
-#define __raw_writeq __raw_writeq
-static inline void __raw_writeq(u64 val, volatile void __iomem *addr)
+static inline void arch_raw_writeq(u64 val, volatile void __iomem *addr)
 {
 	asm volatile("str %x0, [%1]" : : "rZ" (val), "r" (addr));
 }
 
-#define __raw_readb __raw_readb
-static inline u8 __raw_readb(const volatile void __iomem *addr)
+static inline u8 arch_raw_readb(const volatile void __iomem *addr)
 {
 	u8 val;
 	asm volatile(ALTERNATIVE("ldrb %w0, [%1]",
@@ -71,8 +67,7 @@ static inline u8 __raw_readb(const volatile void __iomem *addr)
 	return val;
 }
 
-#define __raw_readw __raw_readw
-static inline u16 __raw_readw(const volatile void __iomem *addr)
+static inline u16 arch_raw_readw(const volatile void __iomem *addr)
 {
 	u16 val;
 
@@ -83,8 +78,7 @@ static inline u16 __raw_readw(const volatile void __iomem *addr)
 	return val;
 }
 
-#define __raw_readl __raw_readl
-static inline u32 __raw_readl(const volatile void __iomem *addr)
+static inline u32 arch_raw_readl(const volatile void __iomem *addr)
 {
 	u32 val;
 	asm volatile(ALTERNATIVE("ldr %w0, [%1]",
@@ -94,8 +88,7 @@ static inline u32 __raw_readl(const volatile void __iomem *addr)
 	return val;
 }
 
-#define __raw_readq __raw_readq
-static inline u64 __raw_readq(const volatile void __iomem *addr)
+static inline u64 arch_raw_readq(const volatile void __iomem *addr)
 {
 	u64 val;
 	asm volatile(ALTERNATIVE("ldr %0, [%1]",
@@ -193,6 +186,7 @@ extern void __iomem *ioremap_cache(phys_addr_t phys_addr, size_t size);
 #define iowrite32be(v,p)	({ __iowmb(); __raw_writel((__force __u32)cpu_to_be32(v), p); })
 #define iowrite64be(v,p)	({ __iowmb(); __raw_writeq((__force __u64)cpu_to_be64(v), p); })
 
+#include <asm-generic/io-instrumented.h>
 #include <asm-generic/io.h>
 
 /*
include/asm-generic/io-instrumented.h new file +32 -0
new file mode 100644
index 000000000000..ce273742b98c
@@ -0,0 +1,32 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef _ASM_GENERIC_IO_INSTRUMENTED_H
+#define _ASM_GENERIC_IO_INSTRUMENTED_H
+
+#include <linux/dynamic_debug.h>
+
+#define __raw_write(v, a, _t) ({			\
+	volatile void __iomem *_a = (a);		\
+	dynamic_rtb("LOGK_WRITE", (void __force *)(_a));\
+	arch_raw_write##_t((v), _a);			\
+	})
+
+#define __raw_writeb(v, a)	__raw_write((v), a, b)
+#define __raw_writew(v, a)	__raw_write((v), a, w)
+#define __raw_writel(v, a)	__raw_write((v), a, l)
+#define __raw_writeq(v, a)	__raw_write((v), a, q)
+
+#define __raw_read(a, _l, _t)    ({					\
+	_t __a;								\
+	const volatile void __iomem *_a = (const volatile void __iomem *)(a);\
+	dynamic_rtb("LOGK_READ", (void __force *)(_a));			\
+	__a = arch_raw_read##_l(_a);					\
+	__a;								\
+	})
+
+#define __raw_readb(a)	__raw_read((a), b, u8)
+#define __raw_readw(a)	__raw_read((a), w, u16)
+#define __raw_readl(a)	__raw_read((a), l, u32)
+#define __raw_readq(a)	__raw_read((a), q, u64)
+
+#endif
include/linux/dynamic_debug.h +13 -0
index 2fd8006153c3..946b60f48401 100644
@@ -155,6 +155,18 @@ do {								\
 			       buf, len, ascii);		\
 } while (0)
 
+#if defined(CONFIG_RTB)
+#define dynamic_rtb(log_type, data)				\
+do {								\
+	DEFINE_DYNAMIC_DEBUG_METADATA(descriptor,		\
+		__builtin_constant_p(log_type) ? log_type : "rtb");\
+	if (DYNAMIC_DEBUG_BRANCH(descriptor))			\
+		uncached_logk(log_type, data);			\
+} while (0)
+#else
+#define dynamic_rtb(log_type, data)
+#endif
+
 #else
 
 #include <linux/string.h>
@@ -181,6 +193,7 @@ static inline int ddebug_dyndbg_module_param_cb(char *param, char *val,
 	do { if (0) printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__); } while (0)
 #define dynamic_dev_dbg(dev, fmt, ...)					\
 	do { if (0) dev_printk(KERN_DEBUG, dev, fmt, ##__VA_ARGS__); } while (0)
+#define dynamic_rtb(log_type, data)
 #endif
 
 #endif
kernel/trace/Kconfig +1 -0
index fd46c7e0016f..59f01091b5ee 100644
@@ -776,6 +776,7 @@ config TRACING_EVENTS_GPIO
 
 config RTB
 	bool "Register Trace Buffer"
+	depends on DYNAMIC_DEBUG
 	help
 	  Add support for logging different events to a small uncached
 	  region. This is designed to aid in debugging reset cases where the
Signature · 2 lines
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member
of Code Aurora Forum, hosted by The Linux Foundation
#10 lore raw

Re: [RFC PATCH v2 3/3] dynamic_debug: Add support for dynamic register trace

arch/arm64/include/asm/io.h

Quoted 39 lines · Sai Prakash Ranjan

Introduce dynamic debug filtering mechanism to register tracing as dynamic_rtb() which will reduce a lot of overhead otherwise of tracing all the register reads/writes in all files.

Now we can just specify the file name or any wildcard pattern as any other dynamic debug facility in bootargs and dynamic rtb will just trace them and the output can be seen in pstore.

TODO: Now we use same 'p' flag but will add a separate flag for register trace later.

Also add asm-generic/io-instrumented.h file for instrumentation of IO operations such as read/write{b,w,l,q} as per Will's suggestion to not touch arch code and let core generate instrumentation.
This can be extended to arm as well later for tracing.

Example for tracing all register reads/writes in drivers/soc/qcom/* below:

# dyndbg="file drivers/soc/qcom/* +p" in bootargs

  # reboot -f
  # mount -t pstore pstore /sys/fs/pstore
  # cat /sys/fs/pstore/rtb-ramoops-0
    [LOGK_WRITE] ts:1373030419  data:ffff00000d5065a4  <ffff00000867cb44>  qcom_smsm_probe+0x51c/0x668
    [LOGK_WRITE] ts:1373360576  data:ffff00000d506608  <ffff00000867cb44>  qcom_smsm_probe+0x51c/0x668
---
 arch/arm64/include/asm/io.h           | 26 +++++++++-------------
 include/asm-generic/io-instrumented.h | 32 +++++++++++++++++++++++++++
 include/linux/dynamic_debug.h         | 13 +++++++++++
 kernel/trace/Kconfig                  |  1 +
 4 files changed, 56 insertions(+), 16 deletions(-)
 create mode 100644 include/asm-generic/io-instrumented.h
arch/arm64/include/asm/io.h +0 -0
index 35b2e50f17fb..aafd4b0be9f0 100644

The arm64 bits look fine to me, but please can you split them into a separate patch?

Quoted 6 lines
include/asm-generic/io-instrumented.h new file +0 -0
new file mode 100644
index 000000000000..ce273742b98c

include/asm-generic/io-instrumented.h line 9

Quoted 9 lines
include/asm-generic/io-instrumented.h new file +9 -0
@@ -0,0 +1,32 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef _ASM_GENERIC_IO_INSTRUMENTED_H
+#define _ASM_GENERIC_IO_INSTRUMENTED_H
+
+#include <linux/dynamic_debug.h>
+
+#define __raw_write(v, a, _t) ({			\
+	volatile void __iomem *_a = (a);		\

Does this actually need to be volatile?

include/asm-generic/io-instrumented.h line 21

Quoted 12 lines
include/asm-generic/io-instrumented.h new file +12 -0
+	dynamic_rtb("LOGK_WRITE", (void __force *)(_a));\
+	arch_raw_write##_t((v), _a);			\
+	})
+
+#define __raw_writeb(v, a)	__raw_write((v), a, b)
+#define __raw_writew(v, a)	__raw_write((v), a, w)
+#define __raw_writel(v, a)	__raw_write((v), a, l)
+#define __raw_writeq(v, a)	__raw_write((v), a, q)
+
+#define __raw_read(a, _l, _t)    ({					\
+	_t __a;								\
+	const volatile void __iomem *_a = (const volatile void __iomem *)(a);\

Again, can't this just be void __iomem * ?

include/asm-generic/io-instrumented.h line 30

Quoted 9 lines
include/asm-generic/io-instrumented.h new file +9 -0
+	dynamic_rtb("LOGK_READ", (void __force *)(_a));			\
+	__a = arch_raw_read##_l(_a);					\
+	__a;								\
+	})
+
+#define __raw_readb(a)	__raw_read((a), b, u8)
+#define __raw_readw(a)	__raw_read((a), w, u16)
+#define __raw_readl(a)	__raw_read((a), l, u32)
+#define __raw_readq(a)	__raw_read((a), q, u64)

I find the way you've defined the __raw_{read,write} macros quite confusing. They both have an _t parameter, but it's totally unrelated between the two!

Will

#11 lore raw

Re: [RFC PATCH v2 3/3] dynamic_debug: Add support for dynamic register trace

Quoted 36 lines · Will Deacon
Quoted 35 lines · Sai Prakash Ranjan

Introduce dynamic debug filtering mechanism to register tracing as dynamic_rtb() which will reduce a lot of overhead otherwise of tracing all the register reads/writes in all files.

Now we can just specify the file name or any wildcard pattern as any other dynamic debug facility in bootargs and dynamic rtb will just trace them and the output can be seen in pstore.

TODO: Now we use same 'p' flag but will add a separate flag for register trace later.

Also add asm-generic/io-instrumented.h file for instrumentation of IO operations such as read/write{b,w,l,q} as per Will's suggestion to not touch arch code and let core generate instrumentation.
This can be extended to arm as well later for tracing.

Example for tracing all register reads/writes in drivers/soc/qcom/* below:

# dyndbg="file drivers/soc/qcom/* +p" in bootargs

   # reboot -f
   # mount -t pstore pstore /sys/fs/pstore
   # cat /sys/fs/pstore/rtb-ramoops-0
     [LOGK_WRITE] ts:1373030419  data:ffff00000d5065a4  <ffff00000867cb44>  qcom_smsm_probe+0x51c/0x668
     [LOGK_WRITE] ts:1373360576  data:ffff00000d506608  <ffff00000867cb44>  qcom_smsm_probe+0x51c/0x668
---
  arch/arm64/include/asm/io.h           | 26 +++++++++-------------
  include/asm-generic/io-instrumented.h | 32 +++++++++++++++++++++++++++
  include/linux/dynamic_debug.h         | 13 +++++++++++
  kernel/trace/Kconfig                  |  1 +
  4 files changed, 56 insertions(+), 16 deletions(-)

create mode 100644 include/asm-generic/io-instrumented.h

Quoted 8 lines

arch/arm64/include/asm/io.h

Quoted 4 lines
arch/arm64/include/asm/io.h +0 -0
index 35b2e50f17fb..aafd4b0be9f0 100644

The arm64 bits look fine to me, but please can you split them into a separate patch?

Thanks for the review. Sure, I will split them into separate patch in next post. I have got the tracepoints working now as Steven suggested, will upload them soon.

Quoted 9 lines
Quoted 9 lines
include/asm-generic/io-instrumented.h new file +3 -0
new file mode 100644
index 000000000000..ce273742b98c
@@ -0,0 +1,32 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef _ASM_GENERIC_IO_INSTRUMENTED_H
Quoted 9 lines

include/asm-generic/io-instrumented.h line 9

Quoted 6 lines
include/asm-generic/io-instrumented.h new file +6 -0
+#define _ASM_GENERIC_IO_INSTRUMENTED_H
+
+#include <linux/dynamic_debug.h>
+
+#define __raw_write(v, a, _t) ({			\
+	volatile void __iomem *_a = (a);		\

Does this actually need to be volatile?

To avoid 100's of compilation warnings like below. Also wanted the parameters of functions like "iowrite32" to be passed to arch_raw_{read,write}() as is.

./include/asm-generic/io.h: In function ?iowrite32?:
./include/asm-generic/io-instrumented.h:8:21: warning: initialization discards ?volatile? qualifier from pointer target type [-Wdiscarded-qualifiers]

   void __iomem *_a = (a);    \
                      ^
./include/asm-generic/io-instrumented.h:15:28: note: in expansion of 
macro ?__raw_write?
  #define __raw_writel(v, a) __raw_write((v), a, l)
                             ^~~~~~~~~~~

./arch/arm64/include/asm/io.h:118:36: note: in expansion of macro ?__raw_writel?
#define writel_relaxed(v,c) ((void)__raw_writel((__force
u32)cpu_to_le32(v),(c)))

                                     ^~~~~~~~~~~~
./arch/arm64/include/asm/io.h:133:36: note: in expansion of macro 
?writel_relaxed?
  #define writel(v,c)  ({ __iowmb(); writel_relaxed((v),(c)); })
                                     ^~~~~~~~~~~~~~

./include/asm-generic/io.h:745:2: note: in expansion of macro ?writel?
writel(value, addr);
^~~~~~

Quoted 6 lines
Quoted 6 lines
include/asm-generic/io-instrumented.h new file +6 -0
+	dynamic_rtb("LOGK_WRITE", (void __force *)(_a));\
+	arch_raw_write##_t((v), _a);			\
+	})
+
+#define __raw_writeb(v, a)	__raw_write((v), a, b)
+#define __raw_writew(v, a)	__raw_write((v), a, w)
Quoted 9 lines

include/asm-generic/io-instrumented.h line 21

Quoted 6 lines
include/asm-generic/io-instrumented.h new file +6 -0
+#define __raw_writel(v, a)	__raw_write((v), a, l)
+#define __raw_writeq(v, a)	__raw_write((v), a, q)
+
+#define __raw_read(a, _l, _t)    ({					\
+	_t __a;								\
+	const volatile void __iomem *_a = (const volatile void __iomem *)(a);\

Again, can't this just be void __iomem * ?

Same as above.

Quoted 4 lines
Quoted 4 lines
include/asm-generic/io-instrumented.h new file +4 -0
+	dynamic_rtb("LOGK_READ", (void __force *)(_a));			\
+	__a = arch_raw_read##_l(_a);					\
+	__a;								\
+	})
Quoted 9 lines

include/asm-generic/io-instrumented.h line 30

Quoted 5 lines
include/asm-generic/io-instrumented.h new file +5 -0
+
+#define __raw_readb(a)	__raw_read((a), b, u8)
+#define __raw_readw(a)	__raw_read((a), w, u16)
+#define __raw_readl(a)	__raw_read((a), l, u32)
+#define __raw_readq(a)	__raw_read((a), q, u64)

I find the way you've defined the __raw_{read,write} macros quite confusing. They both have an _t parameter, but it's totally unrelated between the two!

Sorry for the confusion, I will fix it and have _l for both _raw_{read,write}.

Thanks,
Sai Prakash