diff mbox series

[PATCHv9,5/5] asm-generic/io: Add logging support for MMIO accessors

Message ID 9d7bf0462a140c1425e304c1e709f82e9132253d.1642482334.git.quic_saipraka@quicinc.com (mailing list archive)
State New, archived
Headers show
Series lib/rwmmio/arm64: Add support to trace register reads/writes | expand

Commit Message

Sai Prakash Ranjan Jan. 24, 2022, 6:33 a.m. UTC
Add logging support for MMIO high level accessors such as read{b,w,l,q}
and their relaxed versions to aid in debugging unexpected crashes/hangs
caused by the corresponding MMIO operation. Also add a generic flag
(__DISABLE_TRACE_MMIO__) which is used to disable MMIO tracing in nVHE KVM
and if required can be used to disable MMIO tracing for specific drivers.

Signed-off-by: Sai Prakash Ranjan <quic_saipraka@quicinc.com>
---
 arch/arm64/kvm/hyp/nvhe/Makefile |  7 ++-
 include/asm-generic/io.h         | 82 ++++++++++++++++++++++++++++++--
 2 files changed, 84 insertions(+), 5 deletions(-)

Comments

Sai Prakash Ranjan Feb. 14, 2022, 3:40 a.m. UTC | #1
Hi Arnd,

On 1/24/2022 12:03 PM, Sai Prakash Ranjan wrote:
> Add logging support for MMIO high level accessors such as read{b,w,l,q}
> and their relaxed versions to aid in debugging unexpected crashes/hangs
> caused by the corresponding MMIO operation. Also add a generic flag
> (__DISABLE_TRACE_MMIO__) which is used to disable MMIO tracing in nVHE KVM
> and if required can be used to disable MMIO tracing for specific drivers.
>
> Signed-off-by: Sai Prakash Ranjan <quic_saipraka@quicinc.com>
> ---
>   arch/arm64/kvm/hyp/nvhe/Makefile |  7 ++-
>   include/asm-generic/io.h         | 82 ++++++++++++++++++++++++++++++--
>   2 files changed, 84 insertions(+), 5 deletions(-)
>
> diff --git a/arch/arm64/kvm/hyp/nvhe/Makefile b/arch/arm64/kvm/hyp/nvhe/Makefile
> index 24b2c2425b38..228d1f8921c3 100644
> --- a/arch/arm64/kvm/hyp/nvhe/Makefile
> +++ b/arch/arm64/kvm/hyp/nvhe/Makefile
> @@ -4,7 +4,12 @@
>   #
>   
>   asflags-y := -D__KVM_NVHE_HYPERVISOR__ -D__DISABLE_EXPORTS
> -ccflags-y := -D__KVM_NVHE_HYPERVISOR__ -D__DISABLE_EXPORTS
> +
> +# Tracepoint and MMIO logging symbols should not be visible at nVHE KVM as
> +# there is no way to execute them and any such MMIO access from nVHE KVM
> +# will explode instantly (Words of Marc Zyngier). So introduce a generic flag
> +# __DISABLE_TRACE_MMIO__ to disable MMIO tracing for nVHE KVM.
> +ccflags-y := -D__KVM_NVHE_HYPERVISOR__ -D__DISABLE_EXPORTS -D__DISABLE_TRACE_MMIO__
>   
>   hostprogs := gen-hyprel
>   HOST_EXTRACFLAGS += -I$(objtree)/include
> diff --git a/include/asm-generic/io.h b/include/asm-generic/io.h
> index 7ce93aaf69f8..c9b428657760 100644
> --- a/include/asm-generic/io.h
> +++ b/include/asm-generic/io.h
> @@ -10,6 +10,7 @@
>   #include <asm/page.h> /* I/O is all done through memory accesses */
>   #include <linux/string.h> /* for memset() and memcpy() */
>   #include <linux/types.h>
> +#include <linux/instruction_pointer.h>
>   
>   #ifdef CONFIG_GENERIC_IOMAP
>   #include <asm-generic/iomap.h>
> @@ -61,6 +62,35 @@
>   #define __io_par(v)     __io_ar(v)
>   #endif
>   
> +#if IS_ENABLED(CONFIG_TRACE_MMIO_ACCESS) && !(defined(__DISABLE_TRACE_MMIO__))
> +#include <linux/tracepoint-defs.h>
> +
> +DECLARE_TRACEPOINT(rwmmio_write);
> +DECLARE_TRACEPOINT(rwmmio_post_write);
> +DECLARE_TRACEPOINT(rwmmio_read);
> +DECLARE_TRACEPOINT(rwmmio_post_read);
> +
> +void log_write_mmio(u64 val, u8 width, volatile void __iomem *addr,
> +		    unsigned long caller_addr);
> +void log_post_write_mmio(u64 val, u8 width, volatile void __iomem *addr,
> +			 unsigned long caller_addr);
> +void log_read_mmio(u8 width, const volatile void __iomem *addr,
> +		   unsigned long caller_addr);
> +void log_post_read_mmio(u64 val, u8 width, const volatile void __iomem *addr,
> +			unsigned long caller_addr);
> +
> +#else
> +
> +static inline void log_write_mmio(u64 val, u8 width, volatile void __iomem *addr,
> +				  unsigned long caller_addr) {}
> +static inline void log_post_write_mmio(u64 val, u8 width, volatile void __iomem *addr,
> +				       unsigned long caller_addr) {}
> +static inline void log_read_mmio(u8 width, const volatile void __iomem *addr,
> +				 unsigned long caller_addr) {}
> +static inline void log_post_read_mmio(u64 val, u8 width, const volatile void __iomem *addr,
> +				      unsigned long caller_addr) {}
> +
> +#endif /* CONFIG_TRACE_MMIO_ACCESS */
>   
>   /*
>    * __raw_{read,write}{b,w,l,q}() access memory in native endianness.
> @@ -149,9 +179,11 @@ static inline u8 readb(const volatile void __iomem *addr)
>   {
>   	u8 val;
>   
> +	log_read_mmio(8, addr, _THIS_IP_);
>   	__io_br();
>   	val = __raw_readb(addr);
>   	__io_ar(val);
> +	log_post_read_mmio(val, 8, addr, _THIS_IP_);
>   	return val;
>   }
>   #endif
> @@ -162,9 +194,11 @@ static inline u16 readw(const volatile void __iomem *addr)
>   {
>   	u16 val;
>   
> +	log_read_mmio(16, addr, _THIS_IP_);
>   	__io_br();
>   	val = __le16_to_cpu((__le16 __force)__raw_readw(addr));
>   	__io_ar(val);
> +	log_post_read_mmio(val, 16, addr, _THIS_IP_);
>   	return val;
>   }
>   #endif
> @@ -175,9 +209,11 @@ static inline u32 readl(const volatile void __iomem *addr)
>   {
>   	u32 val;
>   
> +	log_read_mmio(32, addr, _THIS_IP_);
>   	__io_br();
>   	val = __le32_to_cpu((__le32 __force)__raw_readl(addr));
>   	__io_ar(val);
> +	log_post_read_mmio(val, 32, addr, _THIS_IP_);
>   	return val;
>   }
>   #endif
> @@ -189,9 +225,11 @@ static inline u64 readq(const volatile void __iomem *addr)
>   {
>   	u64 val;
>   
> +	log_read_mmio(64, addr, _THIS_IP_);
>   	__io_br();
>   	val = __le64_to_cpu(__raw_readq(addr));
>   	__io_ar(val);
> +	log_post_read_mmio(val, 64, addr, _THIS_IP_);
>   	return val;
>   }
>   #endif
> @@ -201,9 +239,11 @@ static inline u64 readq(const volatile void __iomem *addr)
>   #define writeb writeb
>   static inline void writeb(u8 value, volatile void __iomem *addr)
>   {
> +	log_write_mmio(value, 8, addr, _THIS_IP_);
>   	__io_bw();
>   	__raw_writeb(value, addr);
>   	__io_aw();
> +	log_post_write_mmio(value, 8, addr, _THIS_IP_);
>   }
>   #endif
>   
> @@ -211,9 +251,11 @@ static inline void writeb(u8 value, volatile void __iomem *addr)
>   #define writew writew
>   static inline void writew(u16 value, volatile void __iomem *addr)
>   {
> +	log_write_mmio(value, 16, addr, _THIS_IP_);
>   	__io_bw();
>   	__raw_writew((u16 __force)cpu_to_le16(value), addr);
>   	__io_aw();
> +	log_post_write_mmio(value, 16, addr, _THIS_IP_);
>   }
>   #endif
>   
> @@ -221,9 +263,11 @@ static inline void writew(u16 value, volatile void __iomem *addr)
>   #define writel writel
>   static inline void writel(u32 value, volatile void __iomem *addr)
>   {
> +	log_write_mmio(value, 32, addr, _THIS_IP_);
>   	__io_bw();
>   	__raw_writel((u32 __force)__cpu_to_le32(value), addr);
>   	__io_aw();
> +	log_post_write_mmio(value, 32, addr, _THIS_IP_);
>   }
>   #endif
>   
> @@ -232,9 +276,11 @@ static inline void writel(u32 value, volatile void __iomem *addr)
>   #define writeq writeq
>   static inline void writeq(u64 value, volatile void __iomem *addr)
>   {
> +	log_write_mmio(value, 64, addr, _THIS_IP_);
>   	__io_bw();
>   	__raw_writeq(__cpu_to_le64(value), addr);
>   	__io_aw();
> +	log_post_write_mmio(value, 64, addr, _THIS_IP_);
>   }
>   #endif
>   #endif /* CONFIG_64BIT */
> @@ -248,7 +294,12 @@ static inline void writeq(u64 value, volatile void __iomem *addr)
>   #define readb_relaxed readb_relaxed
>   static inline u8 readb_relaxed(const volatile void __iomem *addr)
>   {
> -	return __raw_readb(addr);
> +	u8 val;
> +
> +	log_read_mmio(8, addr, _THIS_IP_);
> +	val = __raw_readb(addr);
> +	log_post_read_mmio(val, 8, addr, _THIS_IP_);
> +	return val;
>   }
>   #endif
>   
> @@ -256,7 +307,12 @@ static inline u8 readb_relaxed(const volatile void __iomem *addr)
>   #define readw_relaxed readw_relaxed
>   static inline u16 readw_relaxed(const volatile void __iomem *addr)
>   {
> -	return __le16_to_cpu(__raw_readw(addr));
> +	u16 val;
> +
> +	log_read_mmio(16, addr, _THIS_IP_);
> +	val = __le16_to_cpu(__raw_readw(addr));
> +	log_post_read_mmio(val, 16, addr, _THIS_IP_);
> +	return val;
>   }
>   #endif
>   
> @@ -264,7 +320,12 @@ static inline u16 readw_relaxed(const volatile void __iomem *addr)
>   #define readl_relaxed readl_relaxed
>   static inline u32 readl_relaxed(const volatile void __iomem *addr)
>   {
> -	return __le32_to_cpu(__raw_readl(addr));
> +	u32 val;
> +
> +	log_read_mmio(32, addr, _THIS_IP_);
> +	val = __le32_to_cpu(__raw_readl(addr));
> +	log_post_read_mmio(val, 32, addr, _THIS_IP_);
> +	return val;
>   }
>   #endif
>   
> @@ -272,7 +333,12 @@ static inline u32 readl_relaxed(const volatile void __iomem *addr)
>   #define readq_relaxed readq_relaxed
>   static inline u64 readq_relaxed(const volatile void __iomem *addr)
>   {
> -	return __le64_to_cpu(__raw_readq(addr));
> +	u64 val;
> +
> +	log_read_mmio(64, addr, _THIS_IP_);
> +	val =__le64_to_cpu(__raw_readq(addr));
> +	log_post_read_mmio(val, 64, addr, _THIS_IP_);
> +	return val;
>   }
>   #endif
>   
> @@ -280,7 +346,9 @@ static inline u64 readq_relaxed(const volatile void __iomem *addr)
>   #define writeb_relaxed writeb_relaxed
>   static inline void writeb_relaxed(u8 value, volatile void __iomem *addr)
>   {
> +	log_write_mmio(value, 8, addr, _THIS_IP_);
>   	__raw_writeb(value, addr);
> +	log_post_write_mmio(value, 8, addr, _THIS_IP_);
>   }
>   #endif
>   
> @@ -288,7 +356,9 @@ static inline void writeb_relaxed(u8 value, volatile void __iomem *addr)
>   #define writew_relaxed writew_relaxed
>   static inline void writew_relaxed(u16 value, volatile void __iomem *addr)
>   {
> +	log_write_mmio(value, 16, addr, _THIS_IP_);
>   	__raw_writew(cpu_to_le16(value), addr);
> +	log_post_write_mmio(value, 16, addr, _THIS_IP_);
>   }
>   #endif
>   
> @@ -296,7 +366,9 @@ static inline void writew_relaxed(u16 value, volatile void __iomem *addr)
>   #define writel_relaxed writel_relaxed
>   static inline void writel_relaxed(u32 value, volatile void __iomem *addr)
>   {
> +	log_write_mmio(value, 32, addr, _THIS_IP_);
>   	__raw_writel(__cpu_to_le32(value), addr);
> +	log_post_write_mmio(value, 32, addr, _THIS_IP_);
>   }
>   #endif
>   
> @@ -304,7 +376,9 @@ static inline void writel_relaxed(u32 value, volatile void __iomem *addr)
>   #define writeq_relaxed writeq_relaxed
>   static inline void writeq_relaxed(u64 value, volatile void __iomem *addr)
>   {
> +	log_write_mmio(value, 64, addr, _THIS_IP_);
>   	__raw_writeq(__cpu_to_le64(value), addr);
> +	log_post_write_mmio(value, 64, addr, _THIS_IP_);
>   }
>   #endif
>   

Does this version look good to you? I would rather this series spend 
more time in some testing branch
than on the list.

Thanks,
Sai
diff mbox series

Patch

diff --git a/arch/arm64/kvm/hyp/nvhe/Makefile b/arch/arm64/kvm/hyp/nvhe/Makefile
index 24b2c2425b38..228d1f8921c3 100644
--- a/arch/arm64/kvm/hyp/nvhe/Makefile
+++ b/arch/arm64/kvm/hyp/nvhe/Makefile
@@ -4,7 +4,12 @@ 
 #
 
 asflags-y := -D__KVM_NVHE_HYPERVISOR__ -D__DISABLE_EXPORTS
-ccflags-y := -D__KVM_NVHE_HYPERVISOR__ -D__DISABLE_EXPORTS
+
+# Tracepoint and MMIO logging symbols should not be visible at nVHE KVM as
+# there is no way to execute them and any such MMIO access from nVHE KVM
+# will explode instantly (Words of Marc Zyngier). So introduce a generic flag
+# __DISABLE_TRACE_MMIO__ to disable MMIO tracing for nVHE KVM.
+ccflags-y := -D__KVM_NVHE_HYPERVISOR__ -D__DISABLE_EXPORTS -D__DISABLE_TRACE_MMIO__
 
 hostprogs := gen-hyprel
 HOST_EXTRACFLAGS += -I$(objtree)/include
diff --git a/include/asm-generic/io.h b/include/asm-generic/io.h
index 7ce93aaf69f8..c9b428657760 100644
--- a/include/asm-generic/io.h
+++ b/include/asm-generic/io.h
@@ -10,6 +10,7 @@ 
 #include <asm/page.h> /* I/O is all done through memory accesses */
 #include <linux/string.h> /* for memset() and memcpy() */
 #include <linux/types.h>
+#include <linux/instruction_pointer.h>
 
 #ifdef CONFIG_GENERIC_IOMAP
 #include <asm-generic/iomap.h>
@@ -61,6 +62,35 @@ 
 #define __io_par(v)     __io_ar(v)
 #endif
 
+#if IS_ENABLED(CONFIG_TRACE_MMIO_ACCESS) && !(defined(__DISABLE_TRACE_MMIO__))
+#include <linux/tracepoint-defs.h>
+
+DECLARE_TRACEPOINT(rwmmio_write);
+DECLARE_TRACEPOINT(rwmmio_post_write);
+DECLARE_TRACEPOINT(rwmmio_read);
+DECLARE_TRACEPOINT(rwmmio_post_read);
+
+void log_write_mmio(u64 val, u8 width, volatile void __iomem *addr,
+		    unsigned long caller_addr);
+void log_post_write_mmio(u64 val, u8 width, volatile void __iomem *addr,
+			 unsigned long caller_addr);
+void log_read_mmio(u8 width, const volatile void __iomem *addr,
+		   unsigned long caller_addr);
+void log_post_read_mmio(u64 val, u8 width, const volatile void __iomem *addr,
+			unsigned long caller_addr);
+
+#else
+
+static inline void log_write_mmio(u64 val, u8 width, volatile void __iomem *addr,
+				  unsigned long caller_addr) {}
+static inline void log_post_write_mmio(u64 val, u8 width, volatile void __iomem *addr,
+				       unsigned long caller_addr) {}
+static inline void log_read_mmio(u8 width, const volatile void __iomem *addr,
+				 unsigned long caller_addr) {}
+static inline void log_post_read_mmio(u64 val, u8 width, const volatile void __iomem *addr,
+				      unsigned long caller_addr) {}
+
+#endif /* CONFIG_TRACE_MMIO_ACCESS */
 
 /*
  * __raw_{read,write}{b,w,l,q}() access memory in native endianness.
@@ -149,9 +179,11 @@  static inline u8 readb(const volatile void __iomem *addr)
 {
 	u8 val;
 
+	log_read_mmio(8, addr, _THIS_IP_);
 	__io_br();
 	val = __raw_readb(addr);
 	__io_ar(val);
+	log_post_read_mmio(val, 8, addr, _THIS_IP_);
 	return val;
 }
 #endif
@@ -162,9 +194,11 @@  static inline u16 readw(const volatile void __iomem *addr)
 {
 	u16 val;
 
+	log_read_mmio(16, addr, _THIS_IP_);
 	__io_br();
 	val = __le16_to_cpu((__le16 __force)__raw_readw(addr));
 	__io_ar(val);
+	log_post_read_mmio(val, 16, addr, _THIS_IP_);
 	return val;
 }
 #endif
@@ -175,9 +209,11 @@  static inline u32 readl(const volatile void __iomem *addr)
 {
 	u32 val;
 
+	log_read_mmio(32, addr, _THIS_IP_);
 	__io_br();
 	val = __le32_to_cpu((__le32 __force)__raw_readl(addr));
 	__io_ar(val);
+	log_post_read_mmio(val, 32, addr, _THIS_IP_);
 	return val;
 }
 #endif
@@ -189,9 +225,11 @@  static inline u64 readq(const volatile void __iomem *addr)
 {
 	u64 val;
 
+	log_read_mmio(64, addr, _THIS_IP_);
 	__io_br();
 	val = __le64_to_cpu(__raw_readq(addr));
 	__io_ar(val);
+	log_post_read_mmio(val, 64, addr, _THIS_IP_);
 	return val;
 }
 #endif
@@ -201,9 +239,11 @@  static inline u64 readq(const volatile void __iomem *addr)
 #define writeb writeb
 static inline void writeb(u8 value, volatile void __iomem *addr)
 {
+	log_write_mmio(value, 8, addr, _THIS_IP_);
 	__io_bw();
 	__raw_writeb(value, addr);
 	__io_aw();
+	log_post_write_mmio(value, 8, addr, _THIS_IP_);
 }
 #endif
 
@@ -211,9 +251,11 @@  static inline void writeb(u8 value, volatile void __iomem *addr)
 #define writew writew
 static inline void writew(u16 value, volatile void __iomem *addr)
 {
+	log_write_mmio(value, 16, addr, _THIS_IP_);
 	__io_bw();
 	__raw_writew((u16 __force)cpu_to_le16(value), addr);
 	__io_aw();
+	log_post_write_mmio(value, 16, addr, _THIS_IP_);
 }
 #endif
 
@@ -221,9 +263,11 @@  static inline void writew(u16 value, volatile void __iomem *addr)
 #define writel writel
 static inline void writel(u32 value, volatile void __iomem *addr)
 {
+	log_write_mmio(value, 32, addr, _THIS_IP_);
 	__io_bw();
 	__raw_writel((u32 __force)__cpu_to_le32(value), addr);
 	__io_aw();
+	log_post_write_mmio(value, 32, addr, _THIS_IP_);
 }
 #endif
 
@@ -232,9 +276,11 @@  static inline void writel(u32 value, volatile void __iomem *addr)
 #define writeq writeq
 static inline void writeq(u64 value, volatile void __iomem *addr)
 {
+	log_write_mmio(value, 64, addr, _THIS_IP_);
 	__io_bw();
 	__raw_writeq(__cpu_to_le64(value), addr);
 	__io_aw();
+	log_post_write_mmio(value, 64, addr, _THIS_IP_);
 }
 #endif
 #endif /* CONFIG_64BIT */
@@ -248,7 +294,12 @@  static inline void writeq(u64 value, volatile void __iomem *addr)
 #define readb_relaxed readb_relaxed
 static inline u8 readb_relaxed(const volatile void __iomem *addr)
 {
-	return __raw_readb(addr);
+	u8 val;
+
+	log_read_mmio(8, addr, _THIS_IP_);
+	val = __raw_readb(addr);
+	log_post_read_mmio(val, 8, addr, _THIS_IP_);
+	return val;
 }
 #endif
 
@@ -256,7 +307,12 @@  static inline u8 readb_relaxed(const volatile void __iomem *addr)
 #define readw_relaxed readw_relaxed
 static inline u16 readw_relaxed(const volatile void __iomem *addr)
 {
-	return __le16_to_cpu(__raw_readw(addr));
+	u16 val;
+
+	log_read_mmio(16, addr, _THIS_IP_);
+	val = __le16_to_cpu(__raw_readw(addr));
+	log_post_read_mmio(val, 16, addr, _THIS_IP_);
+	return val;
 }
 #endif
 
@@ -264,7 +320,12 @@  static inline u16 readw_relaxed(const volatile void __iomem *addr)
 #define readl_relaxed readl_relaxed
 static inline u32 readl_relaxed(const volatile void __iomem *addr)
 {
-	return __le32_to_cpu(__raw_readl(addr));
+	u32 val;
+
+	log_read_mmio(32, addr, _THIS_IP_);
+	val = __le32_to_cpu(__raw_readl(addr));
+	log_post_read_mmio(val, 32, addr, _THIS_IP_);
+	return val;
 }
 #endif
 
@@ -272,7 +333,12 @@  static inline u32 readl_relaxed(const volatile void __iomem *addr)
 #define readq_relaxed readq_relaxed
 static inline u64 readq_relaxed(const volatile void __iomem *addr)
 {
-	return __le64_to_cpu(__raw_readq(addr));
+	u64 val;
+
+	log_read_mmio(64, addr, _THIS_IP_);
+	val =__le64_to_cpu(__raw_readq(addr));
+	log_post_read_mmio(val, 64, addr, _THIS_IP_);
+	return val;
 }
 #endif
 
@@ -280,7 +346,9 @@  static inline u64 readq_relaxed(const volatile void __iomem *addr)
 #define writeb_relaxed writeb_relaxed
 static inline void writeb_relaxed(u8 value, volatile void __iomem *addr)
 {
+	log_write_mmio(value, 8, addr, _THIS_IP_);
 	__raw_writeb(value, addr);
+	log_post_write_mmio(value, 8, addr, _THIS_IP_);
 }
 #endif
 
@@ -288,7 +356,9 @@  static inline void writeb_relaxed(u8 value, volatile void __iomem *addr)
 #define writew_relaxed writew_relaxed
 static inline void writew_relaxed(u16 value, volatile void __iomem *addr)
 {
+	log_write_mmio(value, 16, addr, _THIS_IP_);
 	__raw_writew(cpu_to_le16(value), addr);
+	log_post_write_mmio(value, 16, addr, _THIS_IP_);
 }
 #endif
 
@@ -296,7 +366,9 @@  static inline void writew_relaxed(u16 value, volatile void __iomem *addr)
 #define writel_relaxed writel_relaxed
 static inline void writel_relaxed(u32 value, volatile void __iomem *addr)
 {
+	log_write_mmio(value, 32, addr, _THIS_IP_);
 	__raw_writel(__cpu_to_le32(value), addr);
+	log_post_write_mmio(value, 32, addr, _THIS_IP_);
 }
 #endif
 
@@ -304,7 +376,9 @@  static inline void writel_relaxed(u32 value, volatile void __iomem *addr)
 #define writeq_relaxed writeq_relaxed
 static inline void writeq_relaxed(u64 value, volatile void __iomem *addr)
 {
+	log_write_mmio(value, 64, addr, _THIS_IP_);
 	__raw_writeq(__cpu_to_le64(value), addr);
+	log_post_write_mmio(value, 64, addr, _THIS_IP_);
 }
 #endif