diff mbox series

[v5] arch/x86: port I/O tracing on x86

Message ID cc7fba3b-9da2-b9eb-95c8-7336e1cd4449@gmail.com
State New
Headers show
Series [v5] arch/x86: port I/O tracing on x86 | expand

Commit Message

Dan Raymond Oct. 7, 2023, 5:56 p.m. UTC
Add support for port I/O tracing on x86.  Memory mapped I/O tracing is
available on x86 via CONFIG_MMIOTRACE but that relies on page faults
so it doesn't work with port I/O.  This feature uses tracepoints in a
similar manner as CONFIG_TRACE_MMIO_ACCESS.

Signed-off-by: Dan Raymond <raymod2@gmail.com>
Suggested-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
---
V1 -> V2:
  - create header file for prototypes to silence new compiler warning
  - reduce CPU overhead to 2 instructions (no branching) when tracing disabled
  - fix imprecise IP logging by retrieving the IP off the stack instead of using
    compile time labels

V2 -> V3:
  - restore missing semicolon

V3 -> V4:
  - make GPL licenses consistent
  - change pointer arguments from (long) to (void *)
  - eliminate include guard checks and use -DDISABLE_TRACEPOINTS instead to
    disable tracepoints in arch/x86/boot/*
  - fix compiler warnings due to signed/unsigned mismatch in arch_cmpxchg64()

V4 -> V5:
  - add -DDISABLE_TRACEPOINTS to arch/x86/realmode/rm/Makefile

 arch/x86/boot/Makefile            |  1 +
 arch/x86/boot/compressed/Makefile |  1 +
 arch/x86/include/asm/cmpxchg_32.h | 13 ++++----
 arch/x86/include/asm/shared/io.h  |  9 ++++++
 arch/x86/lib/Makefile             |  1 +
 arch/x86/lib/trace_portio.c       | 21 +++++++++++++
 arch/x86/realmode/rm/Makefile     |  1 +
 include/linux/trace_portio.h      |  6 ++++
 include/linux/tracepoint-defs.h   |  2 +-
 include/trace/events/portio.h     | 49 +++++++++++++++++++++++++++++++
 10 files changed, 98 insertions(+), 6 deletions(-)
 create mode 100644 arch/x86/lib/trace_portio.c
 create mode 100644 include/linux/trace_portio.h
 create mode 100644 include/trace/events/portio.h


base-commit: be8b93b5cc7d533eb8c9b0590cdac055ecafe13a

Comments

Dan Raymond Oct. 11, 2023, 8:22 p.m. UTC | #1
On 10/7/2023 11:56 AM, Dan Raymond wrote:
> Add support for port I/O tracing on x86.  Memory mapped I/O tracing is
> available on x86 via CONFIG_MMIOTRACE but that relies on page faults
> so it doesn't work with port I/O.  This feature uses tracepoints in a
> similar manner as CONFIG_TRACE_MMIO_ACCESS.
> 
> Signed-off-by: Dan Raymond <raymod2@gmail.com>
> Suggested-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
> ---
> V1 -> V2:
>   - create header file for prototypes to silence new compiler warning
>   - reduce CPU overhead to 2 instructions (no branching) when tracing disabled
>   - fix imprecise IP logging by retrieving the IP off the stack instead of using
>     compile time labels
> 
> V2 -> V3:
>   - restore missing semicolon
> 
> V3 -> V4:
>   - make GPL licenses consistent
>   - change pointer arguments from (long) to (void *)
>   - eliminate include guard checks and use -DDISABLE_TRACEPOINTS instead to
>     disable tracepoints in arch/x86/boot/*
>   - fix compiler warnings due to signed/unsigned mismatch in arch_cmpxchg64()
> 
> V4 -> V5:
>   - add -DDISABLE_TRACEPOINTS to arch/x86/realmode/rm/Makefile

Can I get reviews on this please?
Steven Rostedt Oct. 21, 2023, 8:15 p.m. UTC | #2
On Sat, 21 Oct 2023 18:00:38 +0200
Greg KH <gregkh@linuxfoundation.org> wrote:

> On Sat, Oct 07, 2023 at 11:56:53AM -0600, Dan Raymond wrote:
> > Add support for port I/O tracing on x86.  Memory mapped I/O tracing is
> > available on x86 via CONFIG_MMIOTRACE but that relies on page faults
> > so it doesn't work with port I/O.  This feature uses tracepoints in a
> > similar manner as CONFIG_TRACE_MMIO_ACCESS.
> > 
> > Signed-off-by: Dan Raymond <raymod2@gmail.com>
> > Suggested-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>  

BTW, It's usually common practice to send a new revision of a patch as
a new thread and not as a reply to another thread. When I go look for
patches (besides in patchwork), I only look at top level threads. If I
see a patch that has comments against it for a new revision, I might
ignore the rest of the thread to wait for the new revision. If the new
revision is a reply to the existing thread, it may never be seen. 

> 
> This is now outside of my subsystems to review, sorry.  It's going to
> have to go through the x86 tree, so you are going to have to convince
> them that this is something that actually matters and is needed by
> people, as maintaining it over time is going to add to their workload.
> 
> Note, you are keeping tracing from working in a few areas that might not
> be good:
> 
> > --- a/arch/x86/boot/Makefile
> > +++ b/arch/x86/boot/Makefile
> > @@ -70,6 +70,7 @@ KBUILD_CFLAGS	:= $(REALMODE_CFLAGS) -D_SETUP
> >  KBUILD_AFLAGS	:= $(KBUILD_CFLAGS) -D__ASSEMBLY__
> >  KBUILD_CFLAGS	+= $(call cc-option,-fmacro-prefix-map=$(srctree)/=)
> >  KBUILD_CFLAGS	+= -fno-asynchronous-unwind-tables
> > +KBUILD_CFLAGS	+= -DDISABLE_TRACEPOINTS
> >  GCOV_PROFILE := n
> >  UBSAN_SANITIZE := n
> >  
> > diff --git a/arch/x86/boot/compressed/Makefile b/arch/x86/boot/compressed/Makefile
> > index 35ce1a64068b..c368bcc008eb 100644
> > --- a/arch/x86/boot/compressed/Makefile
> > +++ b/arch/x86/boot/compressed/Makefile
> > @@ -51,6 +51,7 @@ KBUILD_CFLAGS += -D__DISABLE_EXPORTS
> >  # Disable relocation relaxation in case the link is not PIE.
> >  KBUILD_CFLAGS += $(call as-option,-Wa$(comma)-mrelax-relocations=no)
> >  KBUILD_CFLAGS += -include $(srctree)/include/linux/hidden.h
> > +KBUILD_CFLAGS += -DDISABLE_TRACEPOINTS
> >  
> >  # sev.c indirectly inludes inat-table.h which is generated during
> >  # compilation and stored in $(objtree). Add the directory to the includes so  
> 
> Now I know why you did that for this patch (i.e. so early boot doesn't
> get the printk mess), but that kind of defeats the use of tracepoints at
> all for this part of the kernel, is that ok?  Are any existing
> tracepoints now removed?

I believe everything in arch/x86/boot is not part of the kernel proper
and not having tracepoints there is fine.

> 
> Some other random comments:
> 
> > --- a/arch/x86/include/asm/cmpxchg_32.h
> > +++ b/arch/x86/include/asm/cmpxchg_32.h
> > @@ -37,13 +37,16 @@ static inline void set_64bit(volatile u64 *ptr, u64 value)
> >  
> >  #ifdef CONFIG_X86_CMPXCHG64
> >  #define arch_cmpxchg64(ptr, o, n)					\
> > -	((__typeof__(*(ptr)))__cmpxchg64((ptr), (unsigned long long)(o), \
> > +	((__typeof__(*(ptr)))__cmpxchg64((unsigned long long *)(ptr),	\
> > +					 (unsigned long long)(o),	\
> >  					 (unsigned long long)(n)))
> > -#define arch_cmpxchg64_local(ptr, o, n)					\
> > -	((__typeof__(*(ptr)))__cmpxchg64_local((ptr), (unsigned long long)(o), \
> > +#define arch_cmpxchg64_local(ptr, o, n)						\
> > +	((__typeof__(*(ptr)))__cmpxchg64_local((unsigned long long *)(ptr),	\
> > +					       (unsigned long long)(o),		\
> >  					       (unsigned long long)(n)))
> > -#define arch_try_cmpxchg64(ptr, po, n)					\
> > -	__try_cmpxchg64((ptr), (unsigned long long *)(po), \
> > +#define arch_try_cmpxchg64(ptr, po, n)			\
> > +	__try_cmpxchg64((unsigned long long *)(ptr),	\
> > +			(unsigned long long *)(po),	\
> >  			(unsigned long long)(n))
> >  #endif
> >    
> 
> Why are these needed to be changed at all?  What code changes with it,
> and it's not mentioned in the changelog, so why is it required?

Agreed, if this has issues, it probably should be a separate patch.

> 
> > diff --git a/arch/x86/include/asm/shared/io.h b/arch/x86/include/asm/shared/io.h
> > index c0ef921c0586..82664956ce41 100644
> > --- a/arch/x86/include/asm/shared/io.h
> > +++ b/arch/x86/include/asm/shared/io.h
> > @@ -2,13 +2,20 @@
> >  #ifndef _ASM_X86_SHARED_IO_H
> >  #define _ASM_X86_SHARED_IO_H
> >  
> > +#include <linux/tracepoint-defs.h>
> > +#include <linux/trace_portio.h>
> >  #include <linux/types.h>
> >  
> > +DECLARE_TRACEPOINT(portio_write);
> > +DECLARE_TRACEPOINT(portio_read);
> > +
> >  #define BUILDIO(bwl, bw, type)						\
> >  static inline void __out##bwl(type value, u16 port)			\
> >  {									\
> >  	asm volatile("out" #bwl " %" #bw "0, %w1"			\
> >  		     : : "a"(value), "Nd"(port));			\
> > +	if (tracepoint_enabled(portio_write))				\
> > +		do_trace_portio_write(value, port, #bwl[0]);		\  
> 
> Your level of indirection here seems deep, why doesn't
> do_trace_portio_write() belong in a .h file here and do the
> tracepoint_enabled() check?
> 
> Is this a by-product of the tracing macros that require this deeper
> callchain to happen?

Yeah. tracepoints cannot be in header files as the macros cause a lot
of side effects. If you need to have them in a header file, then you
need to do this little trick above. That is, use tracepoint_enabled(tp)
and then call a function that will call the tracepoint in a C file.

> 
> >  }									\
> >  									\
> >  static inline type __in##bwl(u16 port)					\
> > @@ -16,6 +23,8 @@ static inline type __in##bwl(u16 port)					\
> >  	type value;							\
> >  	asm volatile("in" #bwl " %w1, %" #bw "0"			\
> >  		     : "=a"(value) : "Nd"(port));			\
> > +	if (tracepoint_enabled(portio_read))				\
> > +		do_trace_portio_read(value, port, #bwl[0]);		\
> >  	return value;							\
> >  }
> >  
> > diff --git a/arch/x86/lib/Makefile b/arch/x86/lib/Makefile
> > index f76747862bd2..254f223c025d 100644
> > --- a/arch/x86/lib/Makefile
> > +++ b/arch/x86/lib/Makefile
> > @@ -40,6 +40,7 @@ $(obj)/inat.o: $(obj)/inat-tables.c
> >  clean-files := inat-tables.c
> >  
> >  obj-$(CONFIG_SMP) += msr-smp.o cache-smp.o
> > +obj-$(CONFIG_TRACEPOINTS) += trace_portio.o  
> 
> So you are always enabling these if any CONFIG_TRACEPOINTS is enabled?
> That seems brave.
> 
> > --- a/arch/x86/realmode/rm/Makefile
> > +++ b/arch/x86/realmode/rm/Makefile
> > @@ -75,5 +75,6 @@ KBUILD_CFLAGS	:= $(REALMODE_CFLAGS) -D_SETUP -D_WAKEUP \
> >  		   -I$(srctree)/arch/x86/boot
> >  KBUILD_AFLAGS	:= $(KBUILD_CFLAGS) -D__ASSEMBLY__
> >  KBUILD_CFLAGS	+= -fno-asynchronous-unwind-tables
> > +KBUILD_CFLAGS	+= -DDISABLE_TRACEPOINTS  
> 
> Again, you prevent any tracepoints from this code chunk, is that going
> to be ok going forward?

I don't know this code very well, but "realmode" sounds like code
that's not going to be "normal" ;-)

> 
> >  GCOV_PROFILE := n
> >  UBSAN_SANITIZE := n
> > diff --git a/include/linux/trace_portio.h b/include/linux/trace_portio.h
> > new file mode 100644
> > index 000000000000..2324d62e6c9e
> > --- /dev/null
> > +++ b/include/linux/trace_portio.h
> > @@ -0,0 +1,6 @@
> > +/* SPDX-License-Identifier: GPL-2.0 */
> > +
> > +#include <linux/types.h>
> > +
> > +extern void do_trace_portio_read(u32 value, u16 port, char width);
> > +extern void do_trace_portio_write(u32 value, u16 port, char width);  
> 
> Nit, "extern" isn't needed in .h files anymore.  Not a big deal, just
> for other work you do going forward.
> 
> > diff --git a/include/linux/tracepoint-defs.h b/include/linux/tracepoint-defs.h
> > index e7c2276be33e..bfe70e17b2aa 100644
> > --- a/include/linux/tracepoint-defs.h
> > +++ b/include/linux/tracepoint-defs.h
> > @@ -80,7 +80,7 @@ struct bpf_raw_event_map {
> >  #define DECLARE_TRACEPOINT(tp) \
> >  	extern struct tracepoint __tracepoint_##tp
> >  
> > -#ifdef CONFIG_TRACEPOINTS
> > +#if defined(CONFIG_TRACEPOINTS) && !defined(DISABLE_TRACEPOINTS)  
> 
> Why this global change?

Yeah, DISABLE_TRACEPOINTS does not currently exist. If this is to be a
new way to disable TRACEPOINTS it needs a separate patch and be able to
disable tracepoints everywhere (maybe include/trace/*.h files also need
to be modified?), and also be documented somewhere in Documentation/trace.

-- Steve
Dan Raymond Oct. 23, 2023, 8:28 p.m. UTC | #3
On 10/21/2023 10:00 AM, Greg KH wrote:> This is now outside of my subsystems to review, sorry.  It's going to> have to go through the x86 tree, so you are going to have to convince
> them that this is something that actually matters and is needed by
> people, as maintaining it over time is going to add to their workload.

Tracing is not needed, per se, but it can be incredibly useful for
debugging certain types of problems.  I think the utility of tracing is
well accepted by the community.  

Quoting Peter Zijlstra:

   "...tracepoints in general are useful"

Quoting Andy Shevchenko:

   "...you may trace any IO on some architectures (at least x86), it's
   called mmiotracer (I have used it like 5 years ago or so to trace UART)"

Similar trace functionality is already present in the kernel today
(CONFIG_MMIOTRACE and CONFIG_TRACE_MMIO_ACCESS) and it does anecdotally
get used.  However, as mentioned in the patch description, those tracing
features don't work with port-based I/O hence the need for this patch.
I don't see how this is going to create a maintenance burden.  It adds
two lines of code to a macro that rarely if ever changes.

>> --- a/arch/x86/boot/Makefile
>> +++ b/arch/x86/boot/Makefile
>
> Note, you are keeping tracing from working in a few areas that might not
> be good...
>> Now I know why you did that for this patch (i.e. so early boot doesn't
> get the printk mess), but that kind of defeats the use of tracepoints at
> all for this part of the kernel, is that ok?  Are any existing
> tracepoints now removed?

Some of the kernel sources (arch/x86/boot/* and arch/x86/realmode/*) are
not part of the kernel proper and they don't have the infrastructure to
support tracepoints.  When these sources include header files that
reference tracepoints it causes compiler errors.  I previously worked
around this issue with include guard checks but you objected to that:

   "I see what you are doing here in trying to see if a .h file has been
   included already, but now you are making an assumption on both the .h
   file ordering, and the #ifdef guard for those .h files, which are
   something that we almost never remember or even consider when dealing
   with .h files files."

Therefore I implemented a more reliable mechanism to disable tracepoints.
I explained this earlier in the thread:

   "What we need is to disable tracepoints altogether in arch/x86/boot/*
   so I added -DDISABLE_TRACEPOINTS to the relevant Makefiles and I added
   a check for that symbol in tracepoint-defs.h.  I will submit a v4
   version of my patch with these changes shortly.

   This resolves the problem with <asm/msr.h> as well.  After applying
   the v4 patch I was able to call rdmsr()/wrmsr() from
   arch/x86/boot/misc.c.  Theoretically we can now remove
   arch/x86/boot/msr.h but I had trouble with that due to compiler
   warnings and errors.  The include files in arch/x86/boot are a mess.
   Maybe this can be cleaned up in another patch."

>> --- a/arch/x86/include/asm/cmpxchg_32.h
>> +++ b/arch/x86/include/asm/cmpxchg_32.h
> 
> Why are these needed to be changed at all?  What code changes with it,
> and it's not mentioned in the changelog, so why is it required?

I did mention these changes in the changelog:

   "fix compiler warnings due to signed/unsigned mismatch in arch_cmpxchg64()"

These warnings appear to be a latent defect which was triggered by the
include file changes in this patch.  I assume that introducing compiler
warnings (even indirectly) is not allowed so I fixed them on this patch.

>> +	if (tracepoint_enabled(portio_write))				\
>> +		do_trace_portio_write(value, port, #bwl[0]);		\
> 
> Your level of indirection here seems deep, why doesn't
> do_trace_portio_write() belong in a .h file here and do the
> tracepoint_enabled() check?
> 
> Is this a by-product of the tracing macros that require this deeper
> callchain to happen?

Please reference Documentation/trace/tracepoints.rst:

   "If you require calling a tracepoint from a header file, it is not
   recommended to call one directly or to use the
   trace_<tracepoint>_enabled() function call, as tracepoints in header
   files can have side effects..."

The tracepoint_enabled() macro is very efficient and causes only one
instruction of overhead (a nop) when tracing is disabled.  I verified
this by disassembling vmlinux.

>> +obj-$(CONFIG_TRACEPOINTS) += trace_portio.o
> 
> So you are always enabling these if any CONFIG_TRACEPOINTS is enabled?
> That seems brave.

This doesn't enable the tracepoints.  It just adds support for portio
tracepoints to the kernel image.  The tracepoints are disabled by default
and must be explicitly enabled by the user at runtime.  The overhead is
very modest when portio tracing is disabled (as I mentioned above).

> Again, you prevent any tracepoints from this code chunk, is that going
> to be ok going forward?

I addressed this question above.

> Nit, "extern" isn't needed in .h files anymore.  Not a big deal, just
> for other work you do going forward.

Noted.

>> -#ifdef CONFIG_TRACEPOINTS
>> +#if defined(CONFIG_TRACEPOINTS) && !defined(DISABLE_TRACEPOINTS)
> 
> Why this global change?

I addressed this question above.  This is how we prevent tracepoint
logic in header files from causing compiler errors in source files that
aren't part of the kernel proper.

> Anyway, it's up to the x86 maintainers now, good luck!
> 
> But personally, I don't see the real need for this at all.  It's a
> debugging thing for what exactly?  Who needs this?  Who will use it?
> When will they use it?  And why?

This comment confuses me.  As you know I originally submitted a patch
that added I/O tracing just to the 8250 serial driver.  The patch was
titled "create debugfs interface for UART register tracing".  You said
this at the time:

   "Anyway, again, cool feature, I like it, but if you can tie it into
   the existing trace framework better (either by using that entirely
   which might be best), or at the least, putting your hook into the
   data path with it, that would be best."

My original patch went through a few revisions before Andy Shevchenko
suggested I should add portio tracing instead in a manner similar to
how CONFIG_TRACE_MMIO_ACCESS works.  You agreed.  Hence I created this
patch.
Dan Raymond Oct. 23, 2023, 9:29 p.m. UTC | #4
On 10/21/2023 2:15 PM, Steven Rostedt wrote:

>> Why are these needed to be changed at all?  What code changes with it,
>> and it's not mentioned in the changelog, so why is it required?
> 
> Agreed, if this has issues, it probably should be a separate patch.

As I mentioned to Greg, this fix is needed to avoid compiler warnings
triggered by this patch.  If I submitted this separately it would have
to be merged first.  Isn't it easier to combine them since this is
not a functional change (it just makes a cast explicit)?

>>> -#ifdef CONFIG_TRACEPOINTS
>>> +#if defined(CONFIG_TRACEPOINTS) && !defined(DISABLE_TRACEPOINTS)  
>>
>> Why this global change?
> 
> Yeah, DISABLE_TRACEPOINTS does not currently exist. If this is to be a
> new way to disable TRACEPOINTS it needs a separate patch and be able to
> disable tracepoints everywhere (maybe include/trace/*.h files also need
> to be modified?), and also be documented somewhere in Documentation/trace.

It's only needed to suppress compiler errors when building arch/x86/boot/*
and arch/x86/realmode/*.  Those source files include various x86 headers
such as <asm/msr.h> and <asm/shared/io.h>.  Those x86 headers include
<linux/tracepoint-defs.h> which references static_key_false() in
<linux/jump_label.h>.  DISABLE_TRACEPOINTS eliminates that reference and
hence suppresses the compiler error.

I didn't intend for this macro to be used by developers adding new
tracepoints so I didn't document it as such.  As far as creating a
separate patch: again this is a requirement for this patch and it doesn't
cause any functional changes so can't we combine them?
Steven Rostedt Oct. 23, 2023, 9:51 p.m. UTC | #5
On Mon, 23 Oct 2023 15:29:53 -0600
Dan Raymond <raymod2@gmail.com> wrote:

> On 10/21/2023 2:15 PM, Steven Rostedt wrote:
> 
> >> Why are these needed to be changed at all?  What code changes with it,
> >> and it's not mentioned in the changelog, so why is it required?  

BTW, trimming is good, but it's still better to leave the code that the
comment was talking about. I had to go back to my sent folder to figure it
out.

Adding back here for reference:


> > --- a/arch/x86/include/asm/cmpxchg_32.h
> > +++ b/arch/x86/include/asm/cmpxchg_32.h
> > @@ -37,13 +37,16 @@ static inline void set_64bit(volatile u64 *ptr, u64 value)
> >  
> >  #ifdef CONFIG_X86_CMPXCHG64
> >  #define arch_cmpxchg64(ptr, o, n)					\
> > -	((__typeof__(*(ptr)))__cmpxchg64((ptr), (unsigned long long)(o), \
> > +	((__typeof__(*(ptr)))__cmpxchg64((unsigned long long *)(ptr),	\
> > +					 (unsigned long long)(o),	\
> >  					 (unsigned long long)(n)))
> > -#define arch_cmpxchg64_local(ptr, o, n)					\
> > -	((__typeof__(*(ptr)))__cmpxchg64_local((ptr), (unsigned long long)(o), \
> > +#define arch_cmpxchg64_local(ptr, o, n)						\
> > +	((__typeof__(*(ptr)))__cmpxchg64_local((unsigned long long *)(ptr),	\
> > +					       (unsigned long long)(o),		\
> >  					       (unsigned long long)(n)))
> > -#define arch_try_cmpxchg64(ptr, po, n)					\
> > -	__try_cmpxchg64((ptr), (unsigned long long *)(po), \
> > +#define arch_try_cmpxchg64(ptr, po, n)			\
> > +	__try_cmpxchg64((unsigned long long *)(ptr),	\
> > +			(unsigned long long *)(po),	\
> >  			(unsigned long long)(n))
> >  #endif

> > 
> > Agreed, if this has issues, it probably should be a separate patch.  
> 
> As I mentioned to Greg, this fix is needed to avoid compiler warnings
> triggered by this patch.  If I submitted this separately it would have
> to be merged first.  Isn't it easier to combine them since this is
> not a functional change (it just makes a cast explicit)?

That's what patch series are for. You make a series of changes where one is
dependent on the other. But each commit should only do one thing. If you
need to fix something to do your one thing, that fix should be a separate
patch, but make it part of a series.

Just a "cast explicit" that's in generic code should be a separate change
with a change log explaining why it is needed, and why it didn't work
without it. Single commits can be just "no functional change".

> 
> >>> -#ifdef CONFIG_TRACEPOINTS
> >>> +#if defined(CONFIG_TRACEPOINTS) && !defined(DISABLE_TRACEPOINTS)    
> >>
> >> Why this global change?  
> > 
> > Yeah, DISABLE_TRACEPOINTS does not currently exist. If this is to be a
> > new way to disable TRACEPOINTS it needs a separate patch and be able to
> > disable tracepoints everywhere (maybe include/trace/*.h files also need
> > to be modified?), and also be documented somewhere in Documentation/trace.  
> 
> It's only needed to suppress compiler errors when building arch/x86/boot/*
> and arch/x86/realmode/*.  Those source files include various x86 headers
> such as <asm/msr.h> and <asm/shared/io.h>.  Those x86 headers include
> <linux/tracepoint-defs.h> which references static_key_false() in
> <linux/jump_label.h>.  DISABLE_TRACEPOINTS eliminates that reference and
> hence suppresses the compiler error.
> 
> I didn't intend for this macro to be used by developers adding new
> tracepoints so I didn't document it as such.  As far as creating a
> separate patch: again this is a requirement for this patch and it doesn't
> cause any functional changes so can't we combine them?

This is touching generic code, and as such, it *will* be used by others. If
generic code needs something like "DISABLE_TRACEPOINTS" for your use case,
it may be needed for someone else's.

For the same reason above, it really needs to be a separate patch with a
change log explaining why it is needed.

If this should only be used by code that is not part of the kernel proper,
then we should probably call it something else.

#ifdef PRE_LINUX_CODE  ?

Or something that more explicitly states that this is included in code
that's not part of the Linux proper. By saying "DISABLE_TRACEPOINTS" it
will look like this is the way to disable it for other use cases. Maybe we
want that, or perhaps we don't.

Either case, it should still be separate with a detailed explanation, for
when another developer sees this code, a git blame will give all the
explanation necessary for why it exists.

-- Steve
diff mbox series

Patch

diff --git a/arch/x86/boot/Makefile b/arch/x86/boot/Makefile
index ffec8bb01ba8..6cec531be03b 100644
--- a/arch/x86/boot/Makefile
+++ b/arch/x86/boot/Makefile
@@ -70,6 +70,7 @@  KBUILD_CFLAGS	:= $(REALMODE_CFLAGS) -D_SETUP
 KBUILD_AFLAGS	:= $(KBUILD_CFLAGS) -D__ASSEMBLY__
 KBUILD_CFLAGS	+= $(call cc-option,-fmacro-prefix-map=$(srctree)/=)
 KBUILD_CFLAGS	+= -fno-asynchronous-unwind-tables
+KBUILD_CFLAGS	+= -DDISABLE_TRACEPOINTS
 GCOV_PROFILE := n
 UBSAN_SANITIZE := n
 
diff --git a/arch/x86/boot/compressed/Makefile b/arch/x86/boot/compressed/Makefile
index 35ce1a64068b..c368bcc008eb 100644
--- a/arch/x86/boot/compressed/Makefile
+++ b/arch/x86/boot/compressed/Makefile
@@ -51,6 +51,7 @@  KBUILD_CFLAGS += -D__DISABLE_EXPORTS
 # Disable relocation relaxation in case the link is not PIE.
 KBUILD_CFLAGS += $(call as-option,-Wa$(comma)-mrelax-relocations=no)
 KBUILD_CFLAGS += -include $(srctree)/include/linux/hidden.h
+KBUILD_CFLAGS += -DDISABLE_TRACEPOINTS
 
 # sev.c indirectly inludes inat-table.h which is generated during
 # compilation and stored in $(objtree). Add the directory to the includes so
diff --git a/arch/x86/include/asm/cmpxchg_32.h b/arch/x86/include/asm/cmpxchg_32.h
index 215f5a65790f..054a2906eefd 100644
--- a/arch/x86/include/asm/cmpxchg_32.h
+++ b/arch/x86/include/asm/cmpxchg_32.h
@@ -37,13 +37,16 @@  static inline void set_64bit(volatile u64 *ptr, u64 value)
 
 #ifdef CONFIG_X86_CMPXCHG64
 #define arch_cmpxchg64(ptr, o, n)					\
-	((__typeof__(*(ptr)))__cmpxchg64((ptr), (unsigned long long)(o), \
+	((__typeof__(*(ptr)))__cmpxchg64((unsigned long long *)(ptr),	\
+					 (unsigned long long)(o),	\
 					 (unsigned long long)(n)))
-#define arch_cmpxchg64_local(ptr, o, n)					\
-	((__typeof__(*(ptr)))__cmpxchg64_local((ptr), (unsigned long long)(o), \
+#define arch_cmpxchg64_local(ptr, o, n)						\
+	((__typeof__(*(ptr)))__cmpxchg64_local((unsigned long long *)(ptr),	\
+					       (unsigned long long)(o),		\
 					       (unsigned long long)(n)))
-#define arch_try_cmpxchg64(ptr, po, n)					\
-	__try_cmpxchg64((ptr), (unsigned long long *)(po), \
+#define arch_try_cmpxchg64(ptr, po, n)			\
+	__try_cmpxchg64((unsigned long long *)(ptr),	\
+			(unsigned long long *)(po),	\
 			(unsigned long long)(n))
 #endif
 
diff --git a/arch/x86/include/asm/shared/io.h b/arch/x86/include/asm/shared/io.h
index c0ef921c0586..82664956ce41 100644
--- a/arch/x86/include/asm/shared/io.h
+++ b/arch/x86/include/asm/shared/io.h
@@ -2,13 +2,20 @@ 
 #ifndef _ASM_X86_SHARED_IO_H
 #define _ASM_X86_SHARED_IO_H
 
+#include <linux/tracepoint-defs.h>
+#include <linux/trace_portio.h>
 #include <linux/types.h>
 
+DECLARE_TRACEPOINT(portio_write);
+DECLARE_TRACEPOINT(portio_read);
+
 #define BUILDIO(bwl, bw, type)						\
 static inline void __out##bwl(type value, u16 port)			\
 {									\
 	asm volatile("out" #bwl " %" #bw "0, %w1"			\
 		     : : "a"(value), "Nd"(port));			\
+	if (tracepoint_enabled(portio_write))				\
+		do_trace_portio_write(value, port, #bwl[0]);		\
 }									\
 									\
 static inline type __in##bwl(u16 port)					\
@@ -16,6 +23,8 @@  static inline type __in##bwl(u16 port)					\
 	type value;							\
 	asm volatile("in" #bwl " %w1, %" #bw "0"			\
 		     : "=a"(value) : "Nd"(port));			\
+	if (tracepoint_enabled(portio_read))				\
+		do_trace_portio_read(value, port, #bwl[0]);		\
 	return value;							\
 }
 
diff --git a/arch/x86/lib/Makefile b/arch/x86/lib/Makefile
index f76747862bd2..254f223c025d 100644
--- a/arch/x86/lib/Makefile
+++ b/arch/x86/lib/Makefile
@@ -40,6 +40,7 @@  $(obj)/inat.o: $(obj)/inat-tables.c
 clean-files := inat-tables.c
 
 obj-$(CONFIG_SMP) += msr-smp.o cache-smp.o
+obj-$(CONFIG_TRACEPOINTS) += trace_portio.o
 
 lib-y := delay.o misc.o cmdline.o cpu.o
 lib-y += usercopy_$(BITS).o usercopy.o getuser.o putuser.o
diff --git a/arch/x86/lib/trace_portio.c b/arch/x86/lib/trace_portio.c
new file mode 100644
index 000000000000..b5f62dfd85a0
--- /dev/null
+++ b/arch/x86/lib/trace_portio.c
@@ -0,0 +1,21 @@ 
+// SPDX-License-Identifier: GPL-2.0
+
+#include <linux/instruction_pointer.h>
+#include <linux/trace_portio.h>
+
+#define CREATE_TRACE_POINTS
+#include <trace/events/portio.h>
+
+void do_trace_portio_read(u32 value, u16 port, char width)
+{
+	trace_portio_read(value, port, width, (void *)_RET_IP_);
+}
+EXPORT_SYMBOL_GPL(do_trace_portio_read);
+EXPORT_TRACEPOINT_SYMBOL_GPL(portio_read);
+
+void do_trace_portio_write(u32 value, u16 port, char width)
+{
+	trace_portio_write(value, port, width, (void *)_RET_IP_);
+}
+EXPORT_SYMBOL_GPL(do_trace_portio_write);
+EXPORT_TRACEPOINT_SYMBOL_GPL(portio_write);
diff --git a/arch/x86/realmode/rm/Makefile b/arch/x86/realmode/rm/Makefile
index 83f1b6a56449..660d3e1ecc03 100644
--- a/arch/x86/realmode/rm/Makefile
+++ b/arch/x86/realmode/rm/Makefile
@@ -75,5 +75,6 @@  KBUILD_CFLAGS	:= $(REALMODE_CFLAGS) -D_SETUP -D_WAKEUP \
 		   -I$(srctree)/arch/x86/boot
 KBUILD_AFLAGS	:= $(KBUILD_CFLAGS) -D__ASSEMBLY__
 KBUILD_CFLAGS	+= -fno-asynchronous-unwind-tables
+KBUILD_CFLAGS	+= -DDISABLE_TRACEPOINTS
 GCOV_PROFILE := n
 UBSAN_SANITIZE := n
diff --git a/include/linux/trace_portio.h b/include/linux/trace_portio.h
new file mode 100644
index 000000000000..2324d62e6c9e
--- /dev/null
+++ b/include/linux/trace_portio.h
@@ -0,0 +1,6 @@ 
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#include <linux/types.h>
+
+extern void do_trace_portio_read(u32 value, u16 port, char width);
+extern void do_trace_portio_write(u32 value, u16 port, char width);
diff --git a/include/linux/tracepoint-defs.h b/include/linux/tracepoint-defs.h
index e7c2276be33e..bfe70e17b2aa 100644
--- a/include/linux/tracepoint-defs.h
+++ b/include/linux/tracepoint-defs.h
@@ -80,7 +80,7 @@  struct bpf_raw_event_map {
 #define DECLARE_TRACEPOINT(tp) \
 	extern struct tracepoint __tracepoint_##tp
 
-#ifdef CONFIG_TRACEPOINTS
+#if defined(CONFIG_TRACEPOINTS) && !defined(DISABLE_TRACEPOINTS)
 # define tracepoint_enabled(tp) \
 	static_key_false(&(__tracepoint_##tp).key)
 #else
diff --git a/include/trace/events/portio.h b/include/trace/events/portio.h
new file mode 100644
index 000000000000..7bac3ed197a8
--- /dev/null
+++ b/include/trace/events/portio.h
@@ -0,0 +1,49 @@ 
+/* SPDX-License-Identifier: GPL-2.0 */
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM portio
+
+#if !defined(_TRACE_PORTIO_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_PORTIO_H
+
+#include <linux/tracepoint.h>
+
+DECLARE_EVENT_CLASS(portio_class,
+	TP_PROTO(u32 value, u16 port, char width, void *ip_addr),
+
+	TP_ARGS(value, port, width, ip_addr),
+
+	TP_STRUCT__entry(
+		__field(u32, value)
+		__field(u16, port)
+		__field(char, width)
+		__field(void *, ip_addr)
+	),
+
+	TP_fast_assign(
+		__entry->value = value;
+		__entry->port = port;
+		__entry->width = width;
+		__entry->ip_addr = ip_addr;
+	),
+
+	TP_printk("port=0x%04x value=0x%0*x %pS",
+		__entry->port,
+		__entry->width == 'b' ? 2 :
+		__entry->width == 'w' ? 4 : 8,
+		__entry->value, __entry->ip_addr)
+);
+
+DEFINE_EVENT(portio_class, portio_read,
+	TP_PROTO(u32 value, u16 port, char width, void *ip_addr),
+	TP_ARGS(value, port, width, ip_addr)
+);
+
+DEFINE_EVENT(portio_class, portio_write,
+	TP_PROTO(u32 value, u16 port, char width, void *ip_addr),
+	TP_ARGS(value, port, width, ip_addr)
+);
+
+#endif /* _TRACE_PORTIO_H */
+
+/* This part must be outside protection */
+#include <trace/define_trace.h>