* Re: [PATCH V4 2/2] mm/khugepaged: retry with sync writeback for MADV_COLLAPSE
From: David Hildenbrand (Red Hat) @ 2026-01-09 14:46 UTC (permalink / raw)
To: Shivank Garg, Andrew Morton, Lorenzo Stoakes
Cc: Zi Yan, Baolin Wang, Liam R . Howlett, Nico Pache, Ryan Roberts,
Dev Jain, Barry Song, Lance Yang, Steven Rostedt,
Masami Hiramatsu, Mathieu Desnoyers, Zach O'Keefe, linux-mm,
linux-kernel, linux-trace-kernel, Branden Moore
In-Reply-To: <20251215084615.5283-7-shivankg@amd.com>
On 12/15/25 09:46, Shivank Garg wrote:
> When MADV_COLLAPSE is called on file-backed mappings (e.g., executable
> text sections), the pages may still be dirty from recent writes.
> collapse_file() will trigger async writeback and fail with
> SCAN_PAGE_DIRTY_OR_WRITEBACK (-EAGAIN).
>
> MADV_COLLAPSE is a synchronous operation where userspace expects
> immediate results. If the collapse fails due to dirty pages, perform
> synchronous writeback on the specific range and retry once.
>
> This avoids spurious failures for freshly written executables while
> avoiding unnecessary synchronous I/O for mappings that are already clean.
>
> Reported-by: Branden Moore <Branden.Moore@amd.com>
> Closes: https://lore.kernel.org/all/4e26fe5e-7374-467c-a333-9dd48f85d7cc@amd.com
> Fixes: 34488399fa08 ("mm/madvise: add file and shmem support to MADV_COLLAPSE")
> Suggested-by: David Hildenbrand <david@kernel.org>
> Tested-by: Lance Yang <lance.yang@linux.dev>
> Signed-off-by: Shivank Garg <shivankg@amd.com>
> ---
> mm/khugepaged.c | 40 ++++++++++++++++++++++++++++++++++++++++
> 1 file changed, 40 insertions(+)
>
> diff --git a/mm/khugepaged.c b/mm/khugepaged.c
> index 219dfa2e523c..6c8c35d3e0c9 100644
> --- a/mm/khugepaged.c
> +++ b/mm/khugepaged.c
> @@ -22,6 +22,7 @@
> #include <linux/dax.h>
> #include <linux/ksm.h>
> #include <linux/pgalloc.h>
> +#include <linux/backing-dev.h>
>
> #include <asm/tlb.h>
> #include "internal.h"
> @@ -2787,9 +2788,11 @@ int madvise_collapse(struct vm_area_struct *vma, unsigned long start,
> hend = end & HPAGE_PMD_MASK;
>
> for (addr = hstart; addr < hend; addr += HPAGE_PMD_SIZE) {
> + bool retried = false;
> int result = SCAN_FAIL;
>
> if (!mmap_locked) {
> +retry:
Jumping into an if block is nasty :)
> cond_resched();
> mmap_read_lock(mm);
> mmap_locked = true;
> @@ -2819,6 +2822,43 @@ int madvise_collapse(struct vm_area_struct *vma, unsigned long start,
> if (!mmap_locked)
> *lock_dropped = true;
>
> + /*
> + * If the file-backed VMA has dirty pages, the scan triggers
> + * async writeback and returns SCAN_PAGE_DIRTY_OR_WRITEBACK.
> + * Since MADV_COLLAPSE is sync, we force sync writeback and
> + * retry once.
> + */
> + if (result == SCAN_PAGE_DIRTY_OR_WRITEBACK && !retried) {
> + /*
> + * File scan drops the lock. We must re-acquire it to
> + * safely inspect the VMA and hold the file reference.
> + */
> + if (!mmap_locked) {
> + cond_resched();
> + mmap_read_lock(mm);
> + mmap_locked = true;
> + result = hugepage_vma_revalidate(mm, addr, false, &vma, cc);
> + if (result != SCAN_SUCCEED)
> + goto handle_result;
> + }
> +
> + if (!vma_is_anonymous(vma) && vma->vm_file &&
> + mapping_can_writeback(vma->vm_file->f_mapping)) {
> + struct file *file = get_file(vma->vm_file);
> + pgoff_t pgoff = linear_page_index(vma, addr);
> + loff_t lstart = (loff_t)pgoff << PAGE_SHIFT;
> + loff_t lend = lstart + HPAGE_PMD_SIZE - 1;
> +
> + mmap_read_unlock(mm);
> + mmap_locked = false;
> + *lock_dropped = true;
> + filemap_write_and_wait_range(file->f_mapping, lstart, lend);
> + fput(file);
> + retried = true;
> + goto retry;
> + }
> + }
> +
This looks a bit complicated. Can't we move that handing up, where we have most of that
information already? Or am I missing something important?
diff --git a/mm/khugepaged.c b/mm/khugepaged.c
index 97d1b2824386f..c7271877c5220 100644
--- a/mm/khugepaged.c
+++ b/mm/khugepaged.c
@@ -22,6 +22,7 @@
#include <linux/dax.h>
#include <linux/ksm.h>
#include <linux/pgalloc.h>
+#include <linux/backing-dev.h>
#include <asm/tlb.h>
#include "internal.h"
@@ -2786,7 +2787,9 @@ int madvise_collapse(struct vm_area_struct *vma, unsigned long start,
for (addr = hstart; addr < hend; addr += HPAGE_PMD_SIZE) {
int result = SCAN_FAIL;
+ bool triggered_wb = false;
+retry:
if (!mmap_locked) {
cond_resched();
mmap_read_lock(mm);
@@ -2809,6 +2812,16 @@ int madvise_collapse(struct vm_area_struct *vma, unsigned long start,
mmap_locked = false;
result = hpage_collapse_scan_file(mm, addr, file, pgoff,
cc);
+
+ if (result == SCAN_PAGE_DIRTY_OR_WRITEBACK && !triggered_wb &&
+ mapping_can_writeback(file->f_mapping)) {
+ loff_t lstart = (loff_t)pgoff << PAGE_SHIFT;
+ loff_t lend = lstart + HPAGE_PMD_SIZE - 1;
+
+ filemap_write_and_wait_range(file->f_mapping, lstart, lend);
+ triggered_wb = true;
+ goto retry;
+ }
fput(file);
} else {
result = hpage_collapse_scan_pmd(mm, vma, addr,
--
Cheers
David
^ permalink raw reply related
* Re: [PATCH v5] tracing: Guard __DECLARE_TRACE() use of __DO_TRACE_CALL() with SRCU-fast
From: Mathieu Desnoyers @ 2026-01-09 14:40 UTC (permalink / raw)
To: Steven Rostedt, LKML, Linux trace kernel, bpf
Cc: Masami Hiramatsu, Paul E. McKenney, Sebastian Andrzej Siewior,
Thomas Gleixner
In-Reply-To: <20260108220550.2f6638f3@fedora>
On 2026-01-08 22:05, Steven Rostedt wrote:
> From: "Paul E. McKenney" <paulmck@kernel.org>
[...]
I disagree with many elements of the proposed approach.
On one end we have BPF wanting to hook on arbitrary tracepoints without
adding significant latency to PREEMPT RT kernels.
One the other hand, we have high-speed tracers which execute very short
critical sections to serialize trace data into ring buffers.
All of those users register to the tracepoint API.
We also have to consider that migrate disable is *not* cheap at all
compared to preempt disable.
So I'm wondering why all tracepoint users need to pay the migrate
disable runtime overhead on preempt RT kernels for the sake of BPF ?
Using SRCU-fast to protect tracepoint callback iteration makes sense
for preempt-rt, but I'd recommend moving the migrate disable guard
within the bpf callback code rather than slowing down other tracers
which execute within a short amount of time. Other tracers can then
choose to disable preemption rather than migration if that's a better
fit for their needs.
> diff --git a/include/linux/trace_events.h b/include/linux/trace_events.h
> index 3690221ba3d8..a2704c35eda8 100644
> --- a/include/linux/trace_events.h
> +++ b/include/linux/trace_events.h
> @@ -222,6 +222,26 @@ static inline unsigned int tracing_gen_ctx_dec(void)
> return trace_ctx;
> }
>
> +/*
> + * When PREEMPT_RT is enabled, trace events are called with disabled
> + * migration. The trace events need to know if the tracepoint disabled
> + * migration or not so that what is recorded to the ring buffer shows
> + * the state of when the trace event triggered, and not the state caused
> + * by the trace event.
> + */
> +#ifdef CONFIG_PREEMPT_RT
> +static inline unsigned int tracing_gen_ctx_dec_cond(void)
> +{
> + unsigned int trace_ctx;
> +
> + trace_ctx = tracing_gen_ctx_dec();
> + /* The migration counter starts at bit 4 */
> + return trace_ctx - (1 << 4);
We should turn this hardcoded "4" value into an enum label or a
define. That define should be exposed by tracepoint.h. We should
not hardcode expectations about the implementation of distinct APIs
across the tracing subsystem.
[...]
> --- a/include/linux/tracepoint.h
> +++ b/include/linux/tracepoint.h
> @@ -100,6 +100,25 @@ void for_each_tracepoint_in_module(struct module *mod,
> }
> #endif /* CONFIG_MODULES */
>
> +/*
> + * BPF programs can attach to the tracepoint callbacks. But if the
> + * callbacks are called with preemption disabled, the BPF programs
> + * can cause quite a bit of latency. When PREEMPT_RT is enabled,
> + * instead of disabling preemption, use srcu_fast_notrace() for
> + * synchronization. As BPF programs that are attached to tracepoints
> + * expect to stay on the same CPU, also disable migration.
> + */
> +#ifdef CONFIG_PREEMPT_RT
> +extern struct srcu_struct tracepoint_srcu;
> +# define tracepoint_sync() synchronize_srcu(&tracepoint_srcu);
> +# define tracepoint_guard() \
> + guard(srcu_fast_notrace)(&tracepoint_srcu); \
> + guard(migrate)()
> +#else
> +# define tracepoint_sync() synchronize_rcu();
> +# define tracepoint_guard() guard(preempt_notrace)()
> +#endif
Doing migrate disable on PREEMPT RT for BPF vs preempt disable in other
tracers should come in a separate preparation patch. It belongs to the
tracers, not to tracepoints.
[...]
\
> diff --git a/include/trace/perf.h b/include/trace/perf.h
> index a1754b73a8f5..348ad1d9b556 100644
> --- a/include/trace/perf.h
> +++ b/include/trace/perf.h
> @@ -71,6 +71,7 @@ perf_trace_##call(void *__data, proto) \
> u64 __count __attribute__((unused)); \
> struct task_struct *__task __attribute__((unused)); \
> \
> + guard(preempt_notrace)(); \
> do_perf_trace_##call(__data, args); \
> }
>
> @@ -85,9 +86,8 @@ perf_trace_##call(void *__data, proto) \
> struct task_struct *__task __attribute__((unused)); \
> \
> might_fault(); \
> - preempt_disable_notrace(); \
> + guard(preempt_notrace)(); \
> do_perf_trace_##call(__data, args); \
> - preempt_enable_notrace();
Move this to a perf-specific preparation patch. \
> }
>
> /*
> diff --git a/include/trace/trace_events.h b/include/trace/trace_events.h
> index 4f22136fd465..6fb58387e9f1 100644
> --- a/include/trace/trace_events.h
> +++ b/include/trace/trace_events.h
> @@ -429,6 +429,22 @@ do_trace_event_raw_event_##call(void *__data, proto) \
> trace_event_buffer_commit(&fbuffer); \
> }
>
> +/*
> + * When PREEMPT_RT is enabled, the tracepoint does not disable preemption
> + * but instead disables migration. The callbacks for the trace events
> + * need to have a consistent state so that it can reflect the proper
> + * preempt_disabled counter.
Having those defines within trace_events.h is poking holes within any
hope of abstraction we can have from the tracepoint.h API. This adds
strong coupling between tracepoint and trace_event.h.
Rather than hardcoding preempt counter expectations across tracepoint
and trace-events, we should expose a #define in tracepoint.h which
will make the preempt counter nesting level available to other
parts of the kernel such as trace_events.h. This way we keep everything
in one place and we don't add cross-references about subtle preempt
counter nesting level details.
> + */
> +#ifdef CONFIG_PREEMPT_RT
> +/* disable preemption for RT so that the counters still match */
> +# define trace_event_guard() guard(preempt_notrace)()
> +/* Have syscalls up the migrate disable counter to emulate non-syscalls */
> +# define trace_syscall_event_guard() guard(migrate)()
> +#else
> +# define trace_event_guard()
> +# define trace_syscall_event_guard()
> +#endif
This should be moved to separate tracer-specific prep patches.
[...]
> + * The @trace_file is the desrciptor with information about the status
descriptor
[...]
> + *
> + * Returns a pointer to the data on the ring buffer or NULL if the
> + * event was not reserved (event was filtered, too big, or the buffer
> + * simply was disabled for write).
odd spaces here.
[...]
>
> +#ifdef CONFIG_PREEMPT_RT
> +static void srcu_free_old_probes(struct rcu_head *head)
> +{
> + kfree(container_of(head, struct tp_probes, rcu));
> +}
> +
> +static void rcu_free_old_probes(struct rcu_head *head)
> +{
> + call_srcu(&tracepoint_srcu, head, srcu_free_old_probes);
> +}
> +#else
> static void rcu_free_old_probes(struct rcu_head *head)
> {
> kfree(container_of(head, struct tp_probes, rcu));
> }
> +#endif
>
> static inline void release_probes(struct tracepoint *tp, struct tracepoint_func *old)
> {
> @@ -112,6 +149,13 @@ static inline void release_probes(struct tracepoint *tp, struct tracepoint_func
> struct tp_probes *tp_probes = container_of(old,
> struct tp_probes, probes[0]);
>
> + /*
> + * Tracepoint probes are protected by either RCU or
> + * Tasks Trace RCU and also by SRCU. By calling the SRCU
I'm confused.
My understanding is that in !RT we have:
- RCU (!tracepoint_is_faultable(tp))
- RCU tasks trace (tracepoint_is_faultable(tp))
And for RT:
- SRCU-fast (!tracepoint_is_faultable(tp))
- RCU tasks trace (tracepoint_is_faultable(tp))
So I don't understand this comment, and also I don't understand why we
need to chain the callbacks rather than just call the appropriate
call_rcu based on the tracepoint "is_faultable" state.
What am I missing ?
> + * callback in the [Tasks Trace] RCU callback we cover
> + * both cases. So let us chain the SRCU and [Tasks Trace]
> + * RCU callbacks to wait for both grace periods.
> + */
> if (tracepoint_is_faultable(tp))
> call_rcu_tasks_trace(&tp_probes->rcu, rcu_free_old_probes);
> else
Thanks,
Mathieu
--
Mathieu Desnoyers
EfficiOS Inc.
https://www.efficios.com
^ permalink raw reply
* Re: [PATCH V4 1/2] mm/khugepaged: map dirty/writeback pages failures to EAGAIN
From: David Hildenbrand (Red Hat) @ 2026-01-09 14:30 UTC (permalink / raw)
To: Shivank Garg, Andrew Morton, Lorenzo Stoakes
Cc: Zi Yan, Baolin Wang, Liam R . Howlett, Nico Pache, Ryan Roberts,
Dev Jain, Barry Song, Lance Yang, Steven Rostedt,
Masami Hiramatsu, Mathieu Desnoyers, Zach O'Keefe, linux-mm,
linux-kernel, linux-trace-kernel, Branden Moore, wang lian
In-Reply-To: <20251215084615.5283-5-shivankg@amd.com>
On 12/15/25 09:46, Shivank Garg wrote:
> When collapse_file encounters dirty or writeback pages in file-backed
> mappings, it currently returns SCAN_FAIL which maps to -EINVAL. This is
> misleading as EINVAL suggests invalid arguments, whereas dirty/writeback
> pages represent transient conditions that may resolve on retry.
>
> Introduce SCAN_PAGE_DIRTY_OR_WRITEBACK to cover both dirty and writeback
> states, mapping it to -EAGAIN. For MADV_COLLAPSE, this provides userspace
> with a clear signal that retry may succeed after writeback completes.
> For khugepaged, this is harmless as it will naturally revisit the range
> during periodic scans after async writeback completes.
>
> Reported-by: Branden Moore <Branden.Moore@amd.com>
> Closes: https://lore.kernel.org/all/4e26fe5e-7374-467c-a333-9dd48f85d7cc@amd.com
> Fixes: 34488399fa08 ("mm/madvise: add file and shmem support to MADV_COLLAPSE")
> Reviewed-by: Dev Jain <dev.jain@arm.com>
> Reviewed-by: Lance Yang <lance.yang@linux.dev>
> Reviewed-by: Baolin Wang <baolin.wang@linux.alibaba.com>
> Reviewed-by: wang lian <lianux.mm@gmail.com>
> Signed-off-by: Shivank Garg <shivankg@amd.com>
Acked-by: David Hildenbrand (Red Hat) <david@kernel.org>
--
Cheers
David
^ permalink raw reply
* Re: [PATCH v13 mm-new 00/16] khugepaged: mTHP support
From: Lorenzo Stoakes @ 2026-01-09 13:59 UTC (permalink / raw)
To: David Hildenbrand (Red Hat)
Cc: Nico Pache, linux-kernel, linux-trace-kernel, linux-mm, linux-doc,
ziy, baolin.wang, Liam.Howlett, ryan.roberts, dev.jain, corbet,
rostedt, mhiramat, mathieu.desnoyers, akpm, baohua, willy, peterx,
wangkefeng.wang, usamaarif642, sunnanyong, vishal.moola,
thomas.hellstrom, yang, kas, aarcange, raquini, anshuman.khandual,
catalin.marinas, tiwai, will, dave.hansen, jack, cl, jglisse,
surenb, zokeefe, hannes, rientjes, mhocko, rdunlap, hughd,
richard.weiyang, lance.yang, vbabka, rppt, jannh, pfalcato
In-Reply-To: <4cfb49a2-f0fc-4796-83a6-91db3a0f2a97@kernel.org>
On Fri, Jan 09, 2026 at 02:57:16PM +0100, David Hildenbrand (Red Hat) wrote:
> On 1/8/26 18:19, Lorenzo Stoakes wrote:
> > (Sorry for multiple mails replying to same, lei/lore are broken again so my
> > setup isn't working properly).
> >
> > I tried to fixup the conflicts here to run tests locally but there's too many
> > and I messed it up.
> >
> > Could you please resend this series rebased on mm-unstable please?
>
>
> And maybe send out the two cleanups that can be applied earlier separately?
Yeah sounds sensible.
>
> --
> Cheers
>
> David
Cheers, Lorenzo
^ permalink raw reply
* Re: [PATCH v13 mm-new 00/16] khugepaged: mTHP support
From: David Hildenbrand (Red Hat) @ 2026-01-09 13:57 UTC (permalink / raw)
To: Lorenzo Stoakes, Nico Pache
Cc: linux-kernel, linux-trace-kernel, linux-mm, linux-doc, ziy,
baolin.wang, Liam.Howlett, ryan.roberts, dev.jain, corbet,
rostedt, mhiramat, mathieu.desnoyers, akpm, baohua, willy, peterx,
wangkefeng.wang, usamaarif642, sunnanyong, vishal.moola,
thomas.hellstrom, yang, kas, aarcange, raquini, anshuman.khandual,
catalin.marinas, tiwai, will, dave.hansen, jack, cl, jglisse,
surenb, zokeefe, hannes, rientjes, mhocko, rdunlap, hughd,
richard.weiyang, lance.yang, vbabka, rppt, jannh, pfalcato
In-Reply-To: <e54b6ade-e2a0-4a68-93c4-23af85479567@lucifer.local>
On 1/8/26 18:19, Lorenzo Stoakes wrote:
> (Sorry for multiple mails replying to same, lei/lore are broken again so my
> setup isn't working properly).
>
> I tried to fixup the conflicts here to run tests locally but there's too many
> and I messed it up.
>
> Could you please resend this series rebased on mm-unstable please?
And maybe send out the two cleanups that can be applied earlier separately?
--
Cheers
David
^ permalink raw reply
* Re: [PATCH 1/3] powerpc64: make clang cross-build friendly
From: Naveen N Rao @ 2026-01-09 13:50 UTC (permalink / raw)
To: Hari Bathini
Cc: linuxppc-dev, Madhavan Srinivasan, Christophe Leroy,
Michael Ellerman, linux-trace-kernel, Mark Rutland,
Steven Rostedt, Masami Hiramatsu, llvm, Maryam Moghadas
In-Reply-To: <8141c6eb-f2b7-4a19-b637-af699bb8d5c4@linux.ibm.com>
On Mon, Dec 08, 2025 at 09:32:06PM +0530, Hari Bathini wrote:
> Thanks for the review, Naveen.
>
> On 24/11/25 11:19 am, Naveen N Rao wrote:
> > On Sun, Nov 09, 2025 at 02:34:03AM +0530, Hari Bathini wrote:
> > > ARCH_USING_PATCHABLE_FUNCTION_ENTRY depends on toolchain support for
> > > -fpatchable-function-entry option. The current script that checks
> > > for this support only handles GCC. Rename the script and extend it
> > > to detect support for -fpatchable-function-entry with Clang as well,
> > > allowing clean cross-compilation with Clang toolchains.
> > >
> > > Signed-off-by: Hari Bathini <hbathini@linux.ibm.com>
> > > ---
> > > arch/powerpc/Kconfig | 5 +++--
> > > ...-function-entry.sh => check-fpatchable-function-entry.sh} | 0
> > > 2 files changed, 3 insertions(+), 2 deletions(-)
> > > rename arch/powerpc/tools/{gcc-check-fpatchable-function-entry.sh => check-fpatchable-function-entry.sh} (100%)
> > >
> > > diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
> > > index 325c1171894d..dfb62e211c92 100644
> > > --- a/arch/powerpc/Kconfig
> > > +++ b/arch/powerpc/Kconfig
> > > @@ -568,8 +568,9 @@ config ARCH_USING_PATCHABLE_FUNCTION_ENTRY
> > > depends on FUNCTION_TRACER && (PPC32 || PPC64_ELF_ABI_V2)
> > > depends on $(cc-option,-fpatchable-function-entry=2)
> > > def_bool y if PPC32
> > > - def_bool $(success,$(srctree)/arch/powerpc/tools/gcc-check-fpatchable-function-entry.sh $(CC) -mlittle-endian) if PPC64 && CPU_LITTLE_ENDIAN
> > > - def_bool $(success,$(srctree)/arch/powerpc/tools/gcc-check-fpatchable-function-entry.sh $(CC) -mbig-endian) if PPC64 && CPU_BIG_ENDIAN
> > > + def_bool $(success,$(srctree)/arch/powerpc/tools/check-fpatchable-function-entry.sh $(CC) -mlittle-endian) if PPC64 && CPU_LITTLE_ENDIAN && CC_IS_GCC
> > > + def_bool $(success,$(srctree)/arch/powerpc/tools/check-fpatchable-function-entry.sh $(CC) -target ppc64le -mlittle-endian) if PPC64 && CPU_LITTLE_ENDIAN && CC_IS_CLANG
> >
> > Can you instead pass $(CLANG_FLAGS) to retain the same command across
> > gcc/clang?
>
> Should work, I guess.
> But do I need to test for any additional clang flags that
> may interfere with what we are trying to check here?
From what I can tell, $(CLANG_FLAGS) includes a fairly static set of
flags which will be included alongside other $CFLAGS. So, I don't think
anything special should be needed there.
- Naveen
^ permalink raw reply
* Re: [PATCH] powerpc64/bpf: support direct_call on livepatch function
From: Naveen N Rao @ 2026-01-09 13:48 UTC (permalink / raw)
To: Hari Bathini
Cc: Madhavan Srinivasan, linuxppc-dev, Christophe Leroy,
Michael Ellerman, Nicholas Piggin, bpf, Alexei Starovoitov,
Daniel Borkmann, Andrii Nakryiko, Song Liu, Jiri Olsa,
Viktor Malik, live-patching, Josh Poimboeuf, Joe Lawrence,
Jiri Kosina, linux-trace-kernel, Steven Rostedt, Masami Hiramatsu,
Mark Rutland, Shung-Hsi Yu
In-Reply-To: <e34ddd05-d926-4eb4-b861-4bf8fd5635bb@linux.ibm.com>
On Mon, Dec 08, 2025 at 10:05:44PM +0530, Hari Bathini wrote:
> >
> > One of the other thoughts I had was if we could stuff the function
> > address into the ftrace OOL stub. I had considered this back when I
> > implemented the OOL stubs, but didn't do it due to the extra memory
> > requirement. However, given the dance we're having to do, I'm now
> > thinking that may make sense and can simplify the code. If we can also
> > hook into livepatch, then we should be able to update the function
> > address in the stub to point to the new address and the trampoline
> > should then "just work" since it already saves/restores the TOC [We may
> > additionally have to update the function IP in _R12, but that would be a
> > minor change overall]
> >
> > We will still need a way to restore livepatch TOC if the BPF trampoline
> > doesn't itself call into the function, but we may be able to handle that
> > if we change the return address to jump to a stub that restores the TOC
> > from the livepatch stack.
>
> Sounds doable. Looking into a couple of other things at the moment
> though. Will try out this suggestion and get back post that.
> Having said that, your thoughts on whether the current approach
> is a viable option if bpf_get_func_ip() can be fixed somehow?
Oh, that's fine -- feel free to go with whatever approach you think
works best.
- Naveen
^ permalink raw reply
* Re: [PATCHv2 bpf-next 1/2] arm64/ftrace,bpf: Fix partial regs after bpf_prog_run
From: Will Deacon @ 2026-01-09 13:47 UTC (permalink / raw)
To: Jiri Olsa
Cc: Masami Hiramatsu, Steven Rostedt, Mahe Tardy, Peter Zijlstra, bpf,
linux-trace-kernel, linux-arm-kernel, x86, Yonghong Song,
Song Liu, Andrii Nakryiko, Mark Rutland
In-Reply-To: <20260109093454.389295-1-jolsa@kernel.org>
On Fri, Jan 09, 2026 at 10:34:53AM +0100, Jiri Olsa wrote:
> Mahe reported issue with bpf_override_return helper not working when
> executed from kprobe.multi bpf program on arm.
>
> The problem is that on arm we use alternate storage for pt_regs object
> that is passed to bpf_prog_run and if any register is changed (which
> is the case of bpf_override_return) it's not propagated back to actual
> pt_regs object.
>
> Fixing this by introducing and calling ftrace_partial_regs_update function
> to propagate the values of changed registers (ip and stack).
>
> Reported-by: Mahe Tardy <mahe.tardy@gmail.com>
> Signed-off-by: Jiri Olsa <jolsa@kernel.org>
> ---
> v2 changes:
> - moved ftrace_partial_regs_update to generic code [Will]
>
> include/linux/ftrace_regs.h | 25 +++++++++++++++++++++++++
> kernel/trace/bpf_trace.c | 1 +
> 2 files changed, 26 insertions(+)
>
> diff --git a/include/linux/ftrace_regs.h b/include/linux/ftrace_regs.h
> index 15627ceea9bc..f9a7c009cdae 100644
> --- a/include/linux/ftrace_regs.h
> +++ b/include/linux/ftrace_regs.h
> @@ -33,6 +33,31 @@ struct ftrace_regs;
> #define ftrace_regs_get_frame_pointer(fregs) \
> frame_pointer(&arch_ftrace_regs(fregs)->regs)
>
> +static __always_inline void
> +ftrace_partial_regs_update(const struct ftrace_regs *fregs, struct pt_regs *regs) { }
> +
> +#else
> +
> +/*
> + * ftrace_partial_regs_update - update the original ftrace_regs from regs
> + * @fregs: The ftrace_regs to update from @regs
> + * @regs: The partial regs from ftrace_partial_regs() that was updated
> + *
> + * Some architectures have the partial regs living in the ftrace_regs
> + * structure, whereas other architectures need to make a different copy
> + * of the @regs. If a partial @regs is retrieved by ftrace_partial_regs() and
> + * if the code using @regs updates a field (like the instruction pointer or
> + * stack pointer) it may need to propagate that change to the original @fregs
> + * it retrieved the partial @regs from. Use this function to guarantee that
> + * update happens.
> + */
> +static __always_inline void
> +ftrace_partial_regs_update(const struct ftrace_regs *fregs, struct pt_regs *regs)
> +{
> + ftrace_regs_set_instruction_pointer(fregs, instruction_pointer(regs));
> + ftrace_regs_set_return_value(fregs, regs_return_value(regs));
> +}
I think the AI thingy is right about dropping the const qualifier here
but overall I prefer this to the previous revisions. Thanks for sticking
with it!
Acked-by: Will Deacon <will@kernel.org>
Will
^ permalink raw reply
* [PATCH v13] dma-buf: add some tracepoints to debug.
From: Xiang Gao @ 2026-01-09 11:54 UTC (permalink / raw)
To: sumit.semwal, christian.koenig, rostedt, mhiramat
Cc: linux-media, dri-devel, linux-kernel, mathieu.desnoyers, dhowells,
kuba, brauner, akpm, linux-trace-kernel, gaoxiang17
In-Reply-To: <7e126504-1966-4c63-8db5-dfe57e206169@amd.com/>
From: gaoxiang17 <gaoxiang17@xiaomi.com>
Since we can only inspect dmabuf by iterating over process FDs or the
dmabuf_list, we need to add our own tracepoints to track its status in
real time in production.
For example:
binder:3016_1-3102 [006] ...1. 255.126521: dma_buf_export: exp_name=qcom,system size=12685312 ino=2738
binder:3016_1-3102 [006] ...1. 255.126528: dma_buf_fd: exp_name=qcom,system size=12685312 ino=2738 fd=8
binder:3016_1-3102 [006] ...1. 255.126642: dma_buf_mmap_internal: exp_name=qcom,system size=28672 ino=2739
kworker/6:1-86 [006] ...1. 255.127194: dma_buf_put: exp_name=qcom,system size=12685312 ino=2738
RenderThread-9293 [006] ...1. 316.618179: dma_buf_get: exp_name=qcom,system size=12771328 ino=2762 fd=176
RenderThread-9293 [006] ...1. 316.618195: dma_buf_dynamic_attach: exp_name=qcom,system size=12771328 ino=2762 attachment:ffffff880a18dd00 is_dynamic=0 dev_name=kgsl-3d0
RenderThread-9293 [006] ...1. 318.878220: dma_buf_detach: exp_name=qcom,system size=12771328 ino=2762 attachment:ffffff880a18dd00 is_dynamic=0 dev_name=kgsl-3d0
Signed-off-by: Xiang Gao <gaoxiang17@xiaomi.com>
---
Changes since v12: https://lore.kernel.org/all/20251229031547.59272-1-gxxa03070307@gmail.com/
- list history changes
Changes since v11: https://lore.kernel.org/all/20251225121119.2194228-1-gxxa03070307@gmail.com/
- Lined up the backslashes nicely for the macro DMA_BUF_TRACE.
- Used DEFINE_EVENT_CONDITION() to move the condition branch into the tracepoint.
Changes since v10: https://lore.kernel.org/all/20251224013455.1649879-1-gxxa03070307@gmail.com/
- Always expose dmabuf->name_lock if lockdep is enabled.
Changes since v9: https://lore.kernel.org/all/20251223032749.1371913-1-gxxa03070307@gmail.com/
- Fixed some whitespace issues with the macro DMA_BUF_TRACE again.
Changes since v8: https://lore.kernel.org/all/20251218062853.819744-1-gxxa03070307@gmail.com/
- Expose dmabuf->name_lock when lockdep is enabled but trace event is not.
Changes since v7: https://lore.kernel.org/all/20251217105132.643300-1-gxxa03070307@gmail.com/
- Fixed some whitespace issues with the macro DMA_BUF_TRACE.
Changes since v6: https://lore.kernel.org/all/20251216063952.516364-1-gxxa03070307@gmail.com/
- Add a comment for the macro DMA_BUF_TRACE.
Changes since v5: https://lore.kernel.org/all/20251201112148.843572-1-gxxa03070307@gmail.com/
- Add the macro DMA_BUF_TRACE.
- Modify the commit message.
Changes since v4: https://lore.kernel.org/all/20251128085215.550100-1-gxxa03070307@gmail.com/
- Remove the tracepoints exporting.
- Remove the file refcount for the trace.
- Print the dev_name last.
- Add the parameter of whether dma_buf attachment is dynamic.
Changes since v3: https://lore.kernel.org/all/20251127004352.376307-1-gxxa03070307@gmail.com/
- Take the dmabuf->name_lock around the tracepoint call itself.
- Used DECLARE_EVENT_CLASS() and a DEFINE_EVENT().
Changes since v2: https://lore.kernel.org/all/20251125162949.220488-1-gxxa03070307@gmail.com/
- Add more explanation to the commit message.
drivers/dma-buf/dma-buf.c | 9 ++----
include/trace/events/dma_buf.h | 50 ++++++++++++++++++----------------
2 files changed, 29 insertions(+), 30 deletions(-)
diff --git a/drivers/dma-buf/dma-buf.c b/drivers/dma-buf/dma-buf.c
index a4d8f2ff94e4..ac4238063ec1 100644
--- a/drivers/dma-buf/dma-buf.c
+++ b/drivers/dma-buf/dma-buf.c
@@ -48,12 +48,10 @@
*/
#define DMA_BUF_TRACE(FUNC, ...) \
do { \
- if (FUNC##_enabled()) { \
+ /* Always expose lock if lockdep is enabled */ \
+ if (IS_ENABLED(CONFIG_LOCKDEP) || FUNC##_enabled()) { \
guard(spinlock)(&dmabuf->name_lock); \
FUNC(__VA_ARGS__); \
- } else if (IS_ENABLED(CONFIG_LOCKDEP)) { \
- /* Expose this lock when lockdep is enabled */ \
- guard(spinlock)(&dmabuf->name_lock); \
} \
} while (0)
@@ -806,8 +804,7 @@ int dma_buf_fd(struct dma_buf *dmabuf, int flags)
return -EINVAL;
fd = FD_ADD(flags, dmabuf->file);
- if (fd >= 0)
- DMA_BUF_TRACE(trace_dma_buf_fd, dmabuf, fd);
+ DMA_BUF_TRACE(trace_dma_buf_fd, dmabuf, fd);
return fd;
}
diff --git a/include/trace/events/dma_buf.h b/include/trace/events/dma_buf.h
index 35f8140095f4..3bb88d05bcc8 100644
--- a/include/trace/events/dma_buf.h
+++ b/include/trace/events/dma_buf.h
@@ -15,15 +15,15 @@ DECLARE_EVENT_CLASS(dma_buf,
TP_ARGS(dmabuf),
TP_STRUCT__entry(
- __string(exp_name, dmabuf->exp_name)
- __field(size_t, size)
- __field(ino_t, ino)
+ __string( exp_name, dmabuf->exp_name)
+ __field( size_t, size)
+ __field( ino_t, ino)
),
TP_fast_assign(
__assign_str(exp_name);
- __entry->size = dmabuf->size;
- __entry->ino = dmabuf->file->f_inode->i_ino;
+ __entry->size = dmabuf->size;
+ __entry->ino = dmabuf->file->f_inode->i_ino;
),
TP_printk("exp_name=%s size=%zu ino=%lu",
@@ -40,21 +40,21 @@ DECLARE_EVENT_CLASS(dma_buf_attach_dev,
TP_ARGS(dmabuf, attach, is_dynamic, dev),
TP_STRUCT__entry(
- __string(dev_name, dev_name(dev))
- __string(exp_name, dmabuf->exp_name)
- __field(size_t, size)
- __field(ino_t, ino)
- __field(struct dma_buf_attachment *, attach)
- __field(bool, is_dynamic)
+ __string( dev_name, dev_name(dev))
+ __string( exp_name, dmabuf->exp_name)
+ __field( size_t, size)
+ __field( ino_t, ino)
+ __field( struct dma_buf_attachment *, attach)
+ __field( bool, is_dynamic)
),
TP_fast_assign(
__assign_str(dev_name);
__assign_str(exp_name);
- __entry->size = dmabuf->size;
- __entry->ino = dmabuf->file->f_inode->i_ino;
- __entry->is_dynamic = is_dynamic;
- __entry->attach = attach;
+ __entry->size = dmabuf->size;
+ __entry->ino = dmabuf->file->f_inode->i_ino;
+ __entry->is_dynamic = is_dynamic;
+ __entry->attach = attach;
),
TP_printk("exp_name=%s size=%zu ino=%lu attachment:%p is_dynamic=%d dev_name=%s",
@@ -73,17 +73,17 @@ DECLARE_EVENT_CLASS(dma_buf_fd,
TP_ARGS(dmabuf, fd),
TP_STRUCT__entry(
- __string(exp_name, dmabuf->exp_name)
- __field(size_t, size)
- __field(ino_t, ino)
- __field(int, fd)
+ __string( exp_name, dmabuf->exp_name)
+ __field( size_t, size)
+ __field( ino_t, ino)
+ __field( int, fd)
),
TP_fast_assign(
__assign_str(exp_name);
- __entry->size = dmabuf->size;
- __entry->ino = dmabuf->file->f_inode->i_ino;
- __entry->fd = fd;
+ __entry->size = dmabuf->size;
+ __entry->ino = dmabuf->file->f_inode->i_ino;
+ __entry->fd = fd;
),
TP_printk("exp_name=%s size=%zu ino=%lu fd=%d",
@@ -137,11 +137,13 @@ DEFINE_EVENT(dma_buf_attach_dev, dma_buf_detach,
TP_ARGS(dmabuf, attach, is_dynamic, dev)
);
-DEFINE_EVENT(dma_buf_fd, dma_buf_fd,
+DEFINE_EVENT_CONDITION(dma_buf_fd, dma_buf_fd,
TP_PROTO(struct dma_buf *dmabuf, int fd),
- TP_ARGS(dmabuf, fd)
+ TP_ARGS(dmabuf, fd),
+
+ TP_CONDITION(fd >= 0)
);
DEFINE_EVENT(dma_buf_fd, dma_buf_get,
--
2.34.1
^ permalink raw reply related
* Re: [PATCHv2 bpf-next 1/2] arm64/ftrace,bpf: Fix partial regs after bpf_prog_run
From: bot+bpf-ci @ 2026-01-09 10:00 UTC (permalink / raw)
To: jolsa, mhiramat, rostedt, will
Cc: mahe.tardy, peterz, bpf, linux-trace-kernel, linux-arm-kernel,
x86, yhs, songliubraving, andrii, mark.rutland, ast, andrii,
daniel, martin.lau, eddyz87, yonghong.song, clm, ihor.solodrai
In-Reply-To: <20260109093454.389295-1-jolsa@kernel.org>
[-- Attachment #1: Type: text/plain, Size: 1539 bytes --]
> diff --git a/include/linux/ftrace_regs.h b/include/linux/ftrace_regs.h
> index 15627ceea9bc..f9a7c009cdae 100644
> --- a/include/linux/ftrace_regs.h
> +++ b/include/linux/ftrace_regs.h
> @@ -33,6 +33,31 @@ struct ftrace_regs;
[ ... ]
> +#else
> +
> +/*
> + * ftrace_partial_regs_update - update the original ftrace_regs from regs
> + * @fregs: The ftrace_regs to update from @regs
> + * @regs: The partial regs from ftrace_partial_regs() that was updated
[ ... ]
> + */
> +static __always_inline void
> +ftrace_partial_regs_update(const struct ftrace_regs *fregs, struct pt_regs *regs)
> +{
> + ftrace_regs_set_instruction_pointer(fregs, instruction_pointer(regs));
> + ftrace_regs_set_return_value(fregs, regs_return_value(regs));
^^^^^
Should the fregs parameter be non-const here? On architectures with
HAVE_ARCH_FTRACE_REGS (arm64, riscv), the setter functions expect a
non-const pointer:
ftrace_regs_set_instruction_pointer(struct ftrace_regs *fregs, ...)
ftrace_regs_set_return_value(struct ftrace_regs *fregs, ...)
Passing the const-qualified fregs to these functions discards the const
qualifier, which may cause compiler warnings with -Werror or undefined
behavior since the setters do modify the ftrace_regs structure.
> +}
> +
[ ... ]
---
AI reviewed your patch. Please fix the bug or email reply why it's not a bug.
See: https://github.com/kernel-patches/vmtest/blob/master/ci/claude/README.md
CI run summary: https://github.com/kernel-patches/bpf/actions/runs/20847954035
^ permalink raw reply
* [PATCHv2 bpf-next 2/2] selftests/bpf: Add test for bpf_override_return helper
From: Jiri Olsa @ 2026-01-09 9:34 UTC (permalink / raw)
To: Masami Hiramatsu, Steven Rostedt, Will Deacon
Cc: Song Liu, Peter Zijlstra, bpf, linux-trace-kernel,
linux-arm-kernel, x86, Yonghong Song, Song Liu, Andrii Nakryiko,
Mark Rutland, Mahe Tardy
In-Reply-To: <20260109093454.389295-1-jolsa@kernel.org>
We do not actually test the bpf_override_return helper functionality
itself at the moment, only the bpf program being able to attach it.
Adding test that override prctl syscall return value on top of
kprobe and kprobe.multi.
Acked-by: Song Liu <song@kernel.org>
Signed-off-by: Jiri Olsa <jolsa@kernel.org>
---
.../bpf/prog_tests/kprobe_multi_test.c | 44 +++++++++++++++++++
.../bpf/progs/kprobe_multi_override.c | 15 +++++++
tools/testing/selftests/bpf/trace_helpers.h | 12 +++++
3 files changed, 71 insertions(+)
diff --git a/tools/testing/selftests/bpf/prog_tests/kprobe_multi_test.c b/tools/testing/selftests/bpf/prog_tests/kprobe_multi_test.c
index 6cfaa978bc9a..9caef222e528 100644
--- a/tools/testing/selftests/bpf/prog_tests/kprobe_multi_test.c
+++ b/tools/testing/selftests/bpf/prog_tests/kprobe_multi_test.c
@@ -1,4 +1,6 @@
// SPDX-License-Identifier: GPL-2.0
+#include <errno.h>
+#include <sys/prctl.h>
#include <test_progs.h>
#include "kprobe_multi.skel.h"
#include "trace_helpers.h"
@@ -540,6 +542,46 @@ static void test_attach_override(void)
kprobe_multi_override__destroy(skel);
}
+static void test_override(void)
+{
+ struct kprobe_multi_override *skel = NULL;
+ int err;
+
+ skel = kprobe_multi_override__open_and_load();
+ if (!ASSERT_OK_PTR(skel, "kprobe_multi_empty__open_and_load"))
+ goto cleanup;
+
+ skel->bss->pid = getpid();
+
+ /* no override */
+ err = prctl(0xffff, 0);
+ ASSERT_EQ(err, -1, "err");
+
+ /* kprobe.multi override */
+ skel->links.test_override = bpf_program__attach_kprobe_multi_opts(skel->progs.test_override,
+ SYS_PREFIX "sys_prctl", NULL);
+ if (!ASSERT_OK_PTR(skel->links.test_override, "bpf_program__attach_kprobe_multi_opts"))
+ goto cleanup;
+
+ err = prctl(0xffff, 0);
+ ASSERT_EQ(err, 123, "err");
+
+ bpf_link__destroy(skel->links.test_override);
+ skel->links.test_override = NULL;
+
+ /* kprobe override */
+ skel->links.test_kprobe_override = bpf_program__attach_kprobe(skel->progs.test_kprobe_override,
+ false, SYS_PREFIX "sys_prctl");
+ if (!ASSERT_OK_PTR(skel->links.test_kprobe_override, "bpf_program__attach_kprobe"))
+ goto cleanup;
+
+ err = prctl(0xffff, 0);
+ ASSERT_EQ(err, 123, "err");
+
+cleanup:
+ kprobe_multi_override__destroy(skel);
+}
+
#ifdef __x86_64__
static void test_attach_write_ctx(void)
{
@@ -597,6 +639,8 @@ void test_kprobe_multi_test(void)
test_attach_api_fails();
if (test__start_subtest("attach_override"))
test_attach_override();
+ if (test__start_subtest("override"))
+ test_override();
if (test__start_subtest("session"))
test_session_skel_api();
if (test__start_subtest("session_cookie"))
diff --git a/tools/testing/selftests/bpf/progs/kprobe_multi_override.c b/tools/testing/selftests/bpf/progs/kprobe_multi_override.c
index 28f8487c9059..14f39fa6d515 100644
--- a/tools/testing/selftests/bpf/progs/kprobe_multi_override.c
+++ b/tools/testing/selftests/bpf/progs/kprobe_multi_override.c
@@ -5,9 +5,24 @@
char _license[] SEC("license") = "GPL";
+int pid = 0;
+
SEC("kprobe.multi")
int test_override(struct pt_regs *ctx)
{
+ if (bpf_get_current_pid_tgid() >> 32 != pid)
+ return 0;
+
+ bpf_override_return(ctx, 123);
+ return 0;
+}
+
+SEC("kprobe")
+int test_kprobe_override(struct pt_regs *ctx)
+{
+ if (bpf_get_current_pid_tgid() >> 32 != pid)
+ return 0;
+
bpf_override_return(ctx, 123);
return 0;
}
diff --git a/tools/testing/selftests/bpf/trace_helpers.h b/tools/testing/selftests/bpf/trace_helpers.h
index 9437bdd4afa5..a5576b2dfc26 100644
--- a/tools/testing/selftests/bpf/trace_helpers.h
+++ b/tools/testing/selftests/bpf/trace_helpers.h
@@ -4,6 +4,18 @@
#include <bpf/libbpf.h>
+#ifdef __x86_64__
+#define SYS_PREFIX "__x64_"
+#elif defined(__s390x__)
+#define SYS_PREFIX "__s390x_"
+#elif defined(__aarch64__)
+#define SYS_PREFIX "__arm64_"
+#elif defined(__riscv)
+#define SYS_PREFIX "__riscv_"
+#else
+#define SYS_PREFIX ""
+#endif
+
#define __ALIGN_MASK(x, mask) (((x)+(mask))&~(mask))
#define ALIGN(x, a) __ALIGN_MASK(x, (typeof(x))(a)-1)
--
2.52.0
^ permalink raw reply related
* [PATCHv2 bpf-next 1/2] arm64/ftrace,bpf: Fix partial regs after bpf_prog_run
From: Jiri Olsa @ 2026-01-09 9:34 UTC (permalink / raw)
To: Masami Hiramatsu, Steven Rostedt, Will Deacon
Cc: Mahe Tardy, Peter Zijlstra, bpf, linux-trace-kernel,
linux-arm-kernel, x86, Yonghong Song, Song Liu, Andrii Nakryiko,
Mark Rutland
Mahe reported issue with bpf_override_return helper not working when
executed from kprobe.multi bpf program on arm.
The problem is that on arm we use alternate storage for pt_regs object
that is passed to bpf_prog_run and if any register is changed (which
is the case of bpf_override_return) it's not propagated back to actual
pt_regs object.
Fixing this by introducing and calling ftrace_partial_regs_update function
to propagate the values of changed registers (ip and stack).
Reported-by: Mahe Tardy <mahe.tardy@gmail.com>
Signed-off-by: Jiri Olsa <jolsa@kernel.org>
---
v2 changes:
- moved ftrace_partial_regs_update to generic code [Will]
include/linux/ftrace_regs.h | 25 +++++++++++++++++++++++++
kernel/trace/bpf_trace.c | 1 +
2 files changed, 26 insertions(+)
diff --git a/include/linux/ftrace_regs.h b/include/linux/ftrace_regs.h
index 15627ceea9bc..f9a7c009cdae 100644
--- a/include/linux/ftrace_regs.h
+++ b/include/linux/ftrace_regs.h
@@ -33,6 +33,31 @@ struct ftrace_regs;
#define ftrace_regs_get_frame_pointer(fregs) \
frame_pointer(&arch_ftrace_regs(fregs)->regs)
+static __always_inline void
+ftrace_partial_regs_update(const struct ftrace_regs *fregs, struct pt_regs *regs) { }
+
+#else
+
+/*
+ * ftrace_partial_regs_update - update the original ftrace_regs from regs
+ * @fregs: The ftrace_regs to update from @regs
+ * @regs: The partial regs from ftrace_partial_regs() that was updated
+ *
+ * Some architectures have the partial regs living in the ftrace_regs
+ * structure, whereas other architectures need to make a different copy
+ * of the @regs. If a partial @regs is retrieved by ftrace_partial_regs() and
+ * if the code using @regs updates a field (like the instruction pointer or
+ * stack pointer) it may need to propagate that change to the original @fregs
+ * it retrieved the partial @regs from. Use this function to guarantee that
+ * update happens.
+ */
+static __always_inline void
+ftrace_partial_regs_update(const struct ftrace_regs *fregs, struct pt_regs *regs)
+{
+ ftrace_regs_set_instruction_pointer(fregs, instruction_pointer(regs));
+ ftrace_regs_set_return_value(fregs, regs_return_value(regs));
+}
+
#endif /* HAVE_ARCH_FTRACE_REGS */
/* This can be overridden by the architectures */
diff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c
index 6e076485bf70..3a17f79b20c2 100644
--- a/kernel/trace/bpf_trace.c
+++ b/kernel/trace/bpf_trace.c
@@ -2564,6 +2564,7 @@ kprobe_multi_link_prog_run(struct bpf_kprobe_multi_link *link,
old_run_ctx = bpf_set_run_ctx(&run_ctx.session_ctx.run_ctx);
err = bpf_prog_run(link->link.prog, regs);
bpf_reset_run_ctx(old_run_ctx);
+ ftrace_partial_regs_update(fregs, bpf_kprobe_multi_pt_regs_ptr());
rcu_read_unlock();
out:
--
2.52.0
^ permalink raw reply related
* [PATCH v2 3/3] PCI: dw-rockchip: Add pcie_ltssm_state_transition trace support
From: Shawn Lin @ 2026-01-09 3:29 UTC (permalink / raw)
To: Manivannan Sadhasivam, Bjorn Helgaas
Cc: linux-rockchip, linux-pci, linux-trace-kernel, linux-doc,
Steven Rostedt, Masami Hiramatsu, Shawn Lin
In-Reply-To: <1767929389-143957-1-git-send-email-shawn.lin@rock-chips.com>
Rockchip platforms provide a 64x4 bytes debug FIFO to trace the
LTSSM history. Any LTSSM change will be recorded. It's userful
for debug purpose, for example link failure, etc.
Signed-off-by: Shawn Lin <shawn.lin@rock-chips.com>
---
Changes in v2:
- use tracepoint
drivers/pci/controller/dwc/pcie-dw-rockchip.c | 92 +++++++++++++++++++++++++++
1 file changed, 92 insertions(+)
diff --git a/drivers/pci/controller/dwc/pcie-dw-rockchip.c b/drivers/pci/controller/dwc/pcie-dw-rockchip.c
index 352f513..be9639aa 100644
--- a/drivers/pci/controller/dwc/pcie-dw-rockchip.c
+++ b/drivers/pci/controller/dwc/pcie-dw-rockchip.c
@@ -22,6 +22,8 @@
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/reset.h>
+#include <linux/workqueue.h>
+#include <trace/events/pci_controller.h>
#include "../../pci.h"
#include "pcie-designware.h"
@@ -73,6 +75,18 @@
#define PCIE_CLIENT_CDM_RASDES_TBA_L1_1 BIT(4)
#define PCIE_CLIENT_CDM_RASDES_TBA_L1_2 BIT(5)
+/* Debug FIFO information */
+#define PCIE_CLIENT_DBG_FIFO_MODE_CON 0x310
+#define PCIE_CLIENT_DBG_EN 0xffff0007
+#define PCIE_CLIENT_DBG_DIS 0xffff0000
+#define PCIE_CLIENT_DBG_FIFO_PTN_HIT_D0 0x320
+#define PCIE_CLIENT_DBG_FIFO_PTN_HIT_D1 0x324
+#define PCIE_CLIENT_DBG_FIFO_TRN_HIT_D0 0x328
+#define PCIE_CLIENT_DBG_FIFO_TRN_HIT_D1 0x32c
+#define PCIE_CLIENT_DBG_TRANSITION_DATA 0xffff0000
+#define PCIE_CLIENT_DBG_FIFO_STATUS 0x350
+#define PCIE_DBG_LTSSM_HISTORY_CNT 64
+
/* Hot Reset Control Register */
#define PCIE_CLIENT_HOT_RESET_CTRL 0x180
#define PCIE_LTSSM_APP_DLY2_EN BIT(1)
@@ -96,6 +110,7 @@ struct rockchip_pcie {
struct irq_domain *irq_domain;
const struct rockchip_pcie_of_data *data;
bool supports_clkreq;
+ struct delayed_work trace_work;
};
struct rockchip_pcie_of_data {
@@ -206,6 +221,79 @@ static enum dw_pcie_ltssm rockchip_pcie_get_ltssm(struct dw_pcie *pci)
return rockchip_pcie_get_ltssm_reg(rockchip) & PCIE_LTSSM_STATUS_MASK;
}
+#ifdef CONFIG_TRACING
+static void rockchip_pcie_ltssm_trace_work(struct work_struct *work)
+{
+ struct rockchip_pcie *rockchip = container_of(work, struct rockchip_pcie,
+ trace_work.work);
+ struct dw_pcie *pci = &rockchip->pci;
+ enum dw_pcie_ltssm state;
+ u32 val, rate, l1ss, loop, prev_val = DW_PCIE_LTSSM_UNKNOWN;
+
+ for (loop = 0; loop < PCIE_DBG_LTSSM_HISTORY_CNT; loop++) {
+ val = rockchip_pcie_readl_apb(rockchip, PCIE_CLIENT_DBG_FIFO_STATUS);
+ rate = (val & GENMASK(22, 20)) >> 20;
+ l1ss = (val & GENMASK(10, 8)) >> 8;
+ val &= PCIE_LTSSM_STATUS_MASK;
+
+ /* Two consecutive identical LTSSM means invalid subsequent data */
+ if ((loop > 0 && val == prev_val) || val > DW_PCIE_LTSSM_RCVRY_EQ3)
+ break;
+
+ state = prev_val = val;
+ if (val == DW_PCIE_LTSSM_L1_IDLE) {
+ if (l1ss == 2)
+ state = DW_PCIE_LTSSM_L1_2;
+ else if (l1ss == 1)
+ state = DW_PCIE_LTSSM_L1_1;
+ }
+
+ trace_pcie_ltssm_state_transition(dev_name(pci->dev),
+ dw_pcie_ltssm_status_string(state),
+ ((rate + 1) > pci->max_link_speed) ?
+ PCI_SPEED_UNKNOWN : PCIE_SPEED_2_5GT + rate);
+ }
+
+ schedule_delayed_work(&rockchip->trace_work, msecs_to_jiffies(5000));
+}
+
+static void rockchip_pcie_ltssm_trace(struct rockchip_pcie *rockchip,
+ bool en)
+{
+ if (en) {
+ rockchip_pcie_writel_apb(rockchip,
+ PCIE_CLIENT_DBG_TRANSITION_DATA,
+ PCIE_CLIENT_DBG_FIFO_PTN_HIT_D0);
+ rockchip_pcie_writel_apb(rockchip,
+ PCIE_CLIENT_DBG_TRANSITION_DATA,
+ PCIE_CLIENT_DBG_FIFO_PTN_HIT_D1);
+ rockchip_pcie_writel_apb(rockchip,
+ PCIE_CLIENT_DBG_TRANSITION_DATA,
+ PCIE_CLIENT_DBG_FIFO_TRN_HIT_D0);
+ rockchip_pcie_writel_apb(rockchip,
+ PCIE_CLIENT_DBG_TRANSITION_DATA,
+ PCIE_CLIENT_DBG_FIFO_TRN_HIT_D1);
+ rockchip_pcie_writel_apb(rockchip,
+ PCIE_CLIENT_DBG_EN,
+ PCIE_CLIENT_DBG_FIFO_MODE_CON);
+
+ INIT_DELAYED_WORK(&rockchip->trace_work,
+ rockchip_pcie_ltssm_trace_work);
+ schedule_delayed_work(&rockchip->trace_work, 0);
+ } else {
+ rockchip_pcie_writel_apb(rockchip,
+ PCIE_CLIENT_DBG_DIS,
+ PCIE_CLIENT_DBG_FIFO_MODE_CON);
+ cancel_delayed_work_sync(&rockchip->trace_work);
+ }
+}
+#else
+static void rockchip_pcie_ltssm_trace(struct rockchip_pcie *rockchip,
+ bool en)
+{
+}
+#endif
+
static void rockchip_pcie_enable_ltssm(struct rockchip_pcie *rockchip)
{
rockchip_pcie_writel_apb(rockchip, PCIE_CLIENT_ENABLE_LTSSM,
@@ -289,6 +377,9 @@ static int rockchip_pcie_start_link(struct dw_pcie *pci)
* 100us as we don't know how long should the device need to reset.
*/
msleep(PCIE_T_PVPERL_MS);
+
+ rockchip_pcie_ltssm_trace(rockchip, true);
+
gpiod_set_value_cansleep(rockchip->rst_gpio, 1);
return 0;
@@ -299,6 +390,7 @@ static void rockchip_pcie_stop_link(struct dw_pcie *pci)
struct rockchip_pcie *rockchip = to_rockchip_pcie(pci);
rockchip_pcie_disable_ltssm(rockchip);
+ rockchip_pcie_ltssm_trace(rockchip, false);
}
static int rockchip_pcie_host_init(struct dw_pcie_rp *pp)
--
2.7.4
^ permalink raw reply related
* Re: [PATCH] ring-buffer: Use a housekeeping CPU to wake up waiters
From: Petr Tesarik @ 2026-01-09 8:57 UTC (permalink / raw)
To: Steven Rostedt
Cc: Masami Hiramatsu, Mathieu Desnoyers, Sebastian Andrzej Siewior,
Clark Williams, linux-kernel, linux-trace-kernel, linux-rt-devel
In-Reply-To: <20260108115800.7a7fc8a7@gandalf.local.home>
On Thu, 8 Jan 2026 11:58:00 -0500
Steven Rostedt <rostedt@goodmis.org> wrote:
> On Thu, 8 Jan 2026 09:39:32 +0100
> Petr Tesarik <ptesarik@suse.com> wrote:
>
> > > > Or we simply change it to:
> > > >
> > > > static inline void
> > >
> > > Actually, the above should be noinline, as it's in a slower path, and
> > > should not be adding logic into the cache of the fast path.
> >
> > However, to be honest, I'm surprized this is considered slow path. My
> > use case is to record a few selected trace events with "trace-cmd
> > record", which spends most time polling trace_pipe_raw. Consequently,
> > there is almost always a pending waiter that requires a wakeup.
> >
> > In short, irq_work_queue() is the hot path for me.
> >
> > OTOH I don't mind making it noinline, because on recent Intel and AMD
> > systems, a function call (noinline) is often cheaper than an increase
> > in L1 cache footprint (caused by inlining). But I'm confused. I have
> > always thought most people use tracing same way as I do.
>
> The call to rb_wakeups() is a fast path, but the wakeup itself is a slow
> path. This is the case even when you have user space in a loop that is just
> waiting on data.
>
> User space tool:
>
> ring_buffer_wait() {
> wake_event_interruptible(.., rb_wait_cond(..));
> }
>
> Writer:
>
> rb_wakeups() {
> if (!full_hit())
> return;
> }
>
> The full_hit() is the watermark check. If you look at the tracefs
> directory, you'll see a "buffer_percent" file, which is default set to 50.
> That means that full_hit() will not return true until the ring buffer is
> around 50 percent full. This function is called thousands of times before
> the first wakeup happens.
>
> Let's look at even a waiter that isn't using the buffer percent. This means
> it will be woken up on any event in the buffer.
>
> rb_wakeups() {
> if (buffer->irq_work.waiters_pending) {
> buffer->irq_work.waiters_pending = false;
> /* irq_work_queue() supplies it's own memory barriers */
> irq_work_queue(&buffer->irq_work.work);
>
>
> So it clears the waiters_pending flag and wakes up the waiter. Now the
> waiter wakes up and starts reading the ring buffer. While the ring buffer
> has content, it will continue to read and doesn't block again until the
> ring buffer is empty. This means that thousands of events are being
> recorded with no waiters to wake up.
>
> See why this is a slow path?
Thank you for the detailed explanation. So, yeah, most people use it
differently from me, generating trace events fast enough that the
reader does not consume the previous event before the next one arrives.
I have removed both "inline" and "noinline" in v2, leaving it at the
discretion of the compiler. If you believe it deserves a "noinline",
feel free to add it. FWIW on x86-64, I didn't observe any measurable
diference either in latency or instruction cache footprint.
Petr T
^ permalink raw reply
* Re: [PATCH v2 3/3] PCI: dw-rockchip: Add pcie_ltssm_state_transition trace support
From: Manivannan Sadhasivam @ 2026-01-09 7:33 UTC (permalink / raw)
To: Shawn Lin
Cc: Bjorn Helgaas, linux-rockchip, linux-pci, linux-trace-kernel,
linux-doc, Steven Rostedt, Masami Hiramatsu
In-Reply-To: <dddbcb37-68d4-4ccb-9897-b1e5a4b41be7@rock-chips.com>
On Fri, Jan 09, 2026 at 02:22:10PM +0800, Shawn Lin wrote:
> 在 2026/01/09 星期五 13:55, Manivannan Sadhasivam 写道:
> > On Fri, Jan 09, 2026 at 11:29:49AM +0800, Shawn Lin wrote:
> > > Rockchip platforms provide a 64x4 bytes debug FIFO to trace the
> > > LTSSM history. Any LTSSM change will be recorded. It's userful
> > > for debug purpose, for example link failure, etc.
> > >
> > > Signed-off-by: Shawn Lin <shawn.lin@rock-chips.com>
> > > ---
> > >
> > > Changes in v2:
> > > - use tracepoint
> > >
> > > drivers/pci/controller/dwc/pcie-dw-rockchip.c | 92 +++++++++++++++++++++++++++
> > > 1 file changed, 92 insertions(+)
> > >
> > > diff --git a/drivers/pci/controller/dwc/pcie-dw-rockchip.c b/drivers/pci/controller/dwc/pcie-dw-rockchip.c
> > > index 352f513..be9639aa 100644
> > > --- a/drivers/pci/controller/dwc/pcie-dw-rockchip.c
> > > +++ b/drivers/pci/controller/dwc/pcie-dw-rockchip.c
> > > @@ -22,6 +22,8 @@
> > > #include <linux/platform_device.h>
> > > #include <linux/regmap.h>
> > > #include <linux/reset.h>
> > > +#include <linux/workqueue.h>
> > > +#include <trace/events/pci_controller.h>
> > > #include "../../pci.h"
> > > #include "pcie-designware.h"
> > > @@ -73,6 +75,18 @@
> > > #define PCIE_CLIENT_CDM_RASDES_TBA_L1_1 BIT(4)
> > > #define PCIE_CLIENT_CDM_RASDES_TBA_L1_2 BIT(5)
> > > +/* Debug FIFO information */
> > > +#define PCIE_CLIENT_DBG_FIFO_MODE_CON 0x310
> > > +#define PCIE_CLIENT_DBG_EN 0xffff0007
> > > +#define PCIE_CLIENT_DBG_DIS 0xffff0000
> > > +#define PCIE_CLIENT_DBG_FIFO_PTN_HIT_D0 0x320
> > > +#define PCIE_CLIENT_DBG_FIFO_PTN_HIT_D1 0x324
> > > +#define PCIE_CLIENT_DBG_FIFO_TRN_HIT_D0 0x328
> > > +#define PCIE_CLIENT_DBG_FIFO_TRN_HIT_D1 0x32c
> > > +#define PCIE_CLIENT_DBG_TRANSITION_DATA 0xffff0000
> > > +#define PCIE_CLIENT_DBG_FIFO_STATUS 0x350
> > > +#define PCIE_DBG_LTSSM_HISTORY_CNT 64
> > > +
> > > /* Hot Reset Control Register */
> > > #define PCIE_CLIENT_HOT_RESET_CTRL 0x180
> > > #define PCIE_LTSSM_APP_DLY2_EN BIT(1)
> > > @@ -96,6 +110,7 @@ struct rockchip_pcie {
> > > struct irq_domain *irq_domain;
> > > const struct rockchip_pcie_of_data *data;
> > > bool supports_clkreq;
> > > + struct delayed_work trace_work;
> > > };
> > > struct rockchip_pcie_of_data {
> > > @@ -206,6 +221,79 @@ static enum dw_pcie_ltssm rockchip_pcie_get_ltssm(struct dw_pcie *pci)
> > > return rockchip_pcie_get_ltssm_reg(rockchip) & PCIE_LTSSM_STATUS_MASK;
> > > }
> > > +#ifdef CONFIG_TRACING
> > > +static void rockchip_pcie_ltssm_trace_work(struct work_struct *work)
> > > +{
> > > + struct rockchip_pcie *rockchip = container_of(work, struct rockchip_pcie,
> > > + trace_work.work);
> > > + struct dw_pcie *pci = &rockchip->pci;
> > > + enum dw_pcie_ltssm state;
> > > + u32 val, rate, l1ss, loop, prev_val = DW_PCIE_LTSSM_UNKNOWN;
> >
> > Reverse Xmas order please.
> >
> > > +
> > > + for (loop = 0; loop < PCIE_DBG_LTSSM_HISTORY_CNT; loop++) {
> >
> > s/loop/i?
> >
> > > + val = rockchip_pcie_readl_apb(rockchip, PCIE_CLIENT_DBG_FIFO_STATUS);
> > > + rate = (val & GENMASK(22, 20)) >> 20;
> > > + l1ss = (val & GENMASK(10, 8)) >> 8;
> > > + val &= PCIE_LTSSM_STATUS_MASK;
> >
> > Can you use FIELD_ macros here?
> >
> > > +
> > > + /* Two consecutive identical LTSSM means invalid subsequent data */
> >
> > Interesting. Does the hardware maintain a counter to track the reads? So once
> > you break out of the loop and read it after 5s, you'll start from where you left
> > i.e., the duplicate entry or from the start of the counter again?
> >
>
> Yes, the ring FIFO maintains counters for recording both of last-read-point
> for user to continue to read, and last-valid-point for HW to
> continue to update transition state. So we could start from where we
> left.
>
Ok. Thanks for clarification. It'd be worth to add it to the existing comment.
> > > + if ((loop > 0 && val == prev_val) || val > DW_PCIE_LTSSM_RCVRY_EQ3)
> > > + break;
> > > +
> > > + state = prev_val = val;
> > > + if (val == DW_PCIE_LTSSM_L1_IDLE) {
> > > + if (l1ss == 2)
> > > + state = DW_PCIE_LTSSM_L1_2;
> > > + else if (l1ss == 1)
> > > + state = DW_PCIE_LTSSM_L1_1;
> >
> > I believe L1.0 is not supported.
> >
>
> I'm not sure I follow this comment. state is DW_PCIE_LTSSM_L1_IDLE
> (L1.0) if l1ss is neither 1 nor 2.
>
Ah ok. It was not clear that L1_IDLE is L1.0
- Mani
--
மணிவண்ணன் சதாசிவம்
^ permalink raw reply
* Re: [PATCH v2 3/3] PCI: dw-rockchip: Add pcie_ltssm_state_transition trace support
From: Shawn Lin @ 2026-01-09 6:22 UTC (permalink / raw)
To: Manivannan Sadhasivam
Cc: shawn.lin, Bjorn Helgaas, linux-rockchip, linux-pci,
linux-trace-kernel, linux-doc, Steven Rostedt, Masami Hiramatsu
In-Reply-To: <uev63wla4msmmhww4j3t2jim7lhvxjikvujwpxiblg5mz7jwwa@2jucxkbtcsfm>
在 2026/01/09 星期五 13:55, Manivannan Sadhasivam 写道:
> On Fri, Jan 09, 2026 at 11:29:49AM +0800, Shawn Lin wrote:
>> Rockchip platforms provide a 64x4 bytes debug FIFO to trace the
>> LTSSM history. Any LTSSM change will be recorded. It's userful
>> for debug purpose, for example link failure, etc.
>>
>> Signed-off-by: Shawn Lin <shawn.lin@rock-chips.com>
>> ---
>>
>> Changes in v2:
>> - use tracepoint
>>
>> drivers/pci/controller/dwc/pcie-dw-rockchip.c | 92 +++++++++++++++++++++++++++
>> 1 file changed, 92 insertions(+)
>>
>> diff --git a/drivers/pci/controller/dwc/pcie-dw-rockchip.c b/drivers/pci/controller/dwc/pcie-dw-rockchip.c
>> index 352f513..be9639aa 100644
>> --- a/drivers/pci/controller/dwc/pcie-dw-rockchip.c
>> +++ b/drivers/pci/controller/dwc/pcie-dw-rockchip.c
>> @@ -22,6 +22,8 @@
>> #include <linux/platform_device.h>
>> #include <linux/regmap.h>
>> #include <linux/reset.h>
>> +#include <linux/workqueue.h>
>> +#include <trace/events/pci_controller.h>
>>
>> #include "../../pci.h"
>> #include "pcie-designware.h"
>> @@ -73,6 +75,18 @@
>> #define PCIE_CLIENT_CDM_RASDES_TBA_L1_1 BIT(4)
>> #define PCIE_CLIENT_CDM_RASDES_TBA_L1_2 BIT(5)
>>
>> +/* Debug FIFO information */
>> +#define PCIE_CLIENT_DBG_FIFO_MODE_CON 0x310
>> +#define PCIE_CLIENT_DBG_EN 0xffff0007
>> +#define PCIE_CLIENT_DBG_DIS 0xffff0000
>> +#define PCIE_CLIENT_DBG_FIFO_PTN_HIT_D0 0x320
>> +#define PCIE_CLIENT_DBG_FIFO_PTN_HIT_D1 0x324
>> +#define PCIE_CLIENT_DBG_FIFO_TRN_HIT_D0 0x328
>> +#define PCIE_CLIENT_DBG_FIFO_TRN_HIT_D1 0x32c
>> +#define PCIE_CLIENT_DBG_TRANSITION_DATA 0xffff0000
>> +#define PCIE_CLIENT_DBG_FIFO_STATUS 0x350
>> +#define PCIE_DBG_LTSSM_HISTORY_CNT 64
>> +
>> /* Hot Reset Control Register */
>> #define PCIE_CLIENT_HOT_RESET_CTRL 0x180
>> #define PCIE_LTSSM_APP_DLY2_EN BIT(1)
>> @@ -96,6 +110,7 @@ struct rockchip_pcie {
>> struct irq_domain *irq_domain;
>> const struct rockchip_pcie_of_data *data;
>> bool supports_clkreq;
>> + struct delayed_work trace_work;
>> };
>>
>> struct rockchip_pcie_of_data {
>> @@ -206,6 +221,79 @@ static enum dw_pcie_ltssm rockchip_pcie_get_ltssm(struct dw_pcie *pci)
>> return rockchip_pcie_get_ltssm_reg(rockchip) & PCIE_LTSSM_STATUS_MASK;
>> }
>>
>> +#ifdef CONFIG_TRACING
>> +static void rockchip_pcie_ltssm_trace_work(struct work_struct *work)
>> +{
>> + struct rockchip_pcie *rockchip = container_of(work, struct rockchip_pcie,
>> + trace_work.work);
>> + struct dw_pcie *pci = &rockchip->pci;
>> + enum dw_pcie_ltssm state;
>> + u32 val, rate, l1ss, loop, prev_val = DW_PCIE_LTSSM_UNKNOWN;
>
> Reverse Xmas order please.
>
>> +
>> + for (loop = 0; loop < PCIE_DBG_LTSSM_HISTORY_CNT; loop++) {
>
> s/loop/i?
>
>> + val = rockchip_pcie_readl_apb(rockchip, PCIE_CLIENT_DBG_FIFO_STATUS);
>> + rate = (val & GENMASK(22, 20)) >> 20;
>> + l1ss = (val & GENMASK(10, 8)) >> 8;
>> + val &= PCIE_LTSSM_STATUS_MASK;
>
> Can you use FIELD_ macros here?
>
>> +
>> + /* Two consecutive identical LTSSM means invalid subsequent data */
>
> Interesting. Does the hardware maintain a counter to track the reads? So once
> you break out of the loop and read it after 5s, you'll start from where you left
> i.e., the duplicate entry or from the start of the counter again?
>
Yes, the ring FIFO maintains counters for recording both of
last-read-point for user to continue to read, and last-valid-point for
HW to
continue to update transition state. So we could start from where we
left.
>> + if ((loop > 0 && val == prev_val) || val > DW_PCIE_LTSSM_RCVRY_EQ3)
>> + break;
>> +
>> + state = prev_val = val;
>> + if (val == DW_PCIE_LTSSM_L1_IDLE) {
>> + if (l1ss == 2)
>> + state = DW_PCIE_LTSSM_L1_2;
>> + else if (l1ss == 1)
>> + state = DW_PCIE_LTSSM_L1_1;
>
> I believe L1.0 is not supported.
>
I'm not sure I follow this comment. state is DW_PCIE_LTSSM_L1_IDLE
(L1.0) if l1ss is neither 1 nor 2.
>> + }
>> +
>> + trace_pcie_ltssm_state_transition(dev_name(pci->dev),
>> + dw_pcie_ltssm_status_string(state),
>> + ((rate + 1) > pci->max_link_speed) ?
>> + PCI_SPEED_UNKNOWN : PCIE_SPEED_2_5GT + rate);
>> + }
>> +
>> + schedule_delayed_work(&rockchip->trace_work, msecs_to_jiffies(5000));
>> +}
>> +
>> +static void rockchip_pcie_ltssm_trace(struct rockchip_pcie *rockchip,
>> + bool en)
>
> s/en/enable
>
> - Mani
>
^ permalink raw reply
* Re: [PATCH v2 3/3] PCI: dw-rockchip: Add pcie_ltssm_state_transition trace support
From: Manivannan Sadhasivam @ 2026-01-09 5:55 UTC (permalink / raw)
To: Shawn Lin
Cc: Bjorn Helgaas, linux-rockchip, linux-pci, linux-trace-kernel,
linux-doc, Steven Rostedt, Masami Hiramatsu
In-Reply-To: <1767929389-143957-4-git-send-email-shawn.lin@rock-chips.com>
On Fri, Jan 09, 2026 at 11:29:49AM +0800, Shawn Lin wrote:
> Rockchip platforms provide a 64x4 bytes debug FIFO to trace the
> LTSSM history. Any LTSSM change will be recorded. It's userful
> for debug purpose, for example link failure, etc.
>
> Signed-off-by: Shawn Lin <shawn.lin@rock-chips.com>
> ---
>
> Changes in v2:
> - use tracepoint
>
> drivers/pci/controller/dwc/pcie-dw-rockchip.c | 92 +++++++++++++++++++++++++++
> 1 file changed, 92 insertions(+)
>
> diff --git a/drivers/pci/controller/dwc/pcie-dw-rockchip.c b/drivers/pci/controller/dwc/pcie-dw-rockchip.c
> index 352f513..be9639aa 100644
> --- a/drivers/pci/controller/dwc/pcie-dw-rockchip.c
> +++ b/drivers/pci/controller/dwc/pcie-dw-rockchip.c
> @@ -22,6 +22,8 @@
> #include <linux/platform_device.h>
> #include <linux/regmap.h>
> #include <linux/reset.h>
> +#include <linux/workqueue.h>
> +#include <trace/events/pci_controller.h>
>
> #include "../../pci.h"
> #include "pcie-designware.h"
> @@ -73,6 +75,18 @@
> #define PCIE_CLIENT_CDM_RASDES_TBA_L1_1 BIT(4)
> #define PCIE_CLIENT_CDM_RASDES_TBA_L1_2 BIT(5)
>
> +/* Debug FIFO information */
> +#define PCIE_CLIENT_DBG_FIFO_MODE_CON 0x310
> +#define PCIE_CLIENT_DBG_EN 0xffff0007
> +#define PCIE_CLIENT_DBG_DIS 0xffff0000
> +#define PCIE_CLIENT_DBG_FIFO_PTN_HIT_D0 0x320
> +#define PCIE_CLIENT_DBG_FIFO_PTN_HIT_D1 0x324
> +#define PCIE_CLIENT_DBG_FIFO_TRN_HIT_D0 0x328
> +#define PCIE_CLIENT_DBG_FIFO_TRN_HIT_D1 0x32c
> +#define PCIE_CLIENT_DBG_TRANSITION_DATA 0xffff0000
> +#define PCIE_CLIENT_DBG_FIFO_STATUS 0x350
> +#define PCIE_DBG_LTSSM_HISTORY_CNT 64
> +
> /* Hot Reset Control Register */
> #define PCIE_CLIENT_HOT_RESET_CTRL 0x180
> #define PCIE_LTSSM_APP_DLY2_EN BIT(1)
> @@ -96,6 +110,7 @@ struct rockchip_pcie {
> struct irq_domain *irq_domain;
> const struct rockchip_pcie_of_data *data;
> bool supports_clkreq;
> + struct delayed_work trace_work;
> };
>
> struct rockchip_pcie_of_data {
> @@ -206,6 +221,79 @@ static enum dw_pcie_ltssm rockchip_pcie_get_ltssm(struct dw_pcie *pci)
> return rockchip_pcie_get_ltssm_reg(rockchip) & PCIE_LTSSM_STATUS_MASK;
> }
>
> +#ifdef CONFIG_TRACING
> +static void rockchip_pcie_ltssm_trace_work(struct work_struct *work)
> +{
> + struct rockchip_pcie *rockchip = container_of(work, struct rockchip_pcie,
> + trace_work.work);
> + struct dw_pcie *pci = &rockchip->pci;
> + enum dw_pcie_ltssm state;
> + u32 val, rate, l1ss, loop, prev_val = DW_PCIE_LTSSM_UNKNOWN;
Reverse Xmas order please.
> +
> + for (loop = 0; loop < PCIE_DBG_LTSSM_HISTORY_CNT; loop++) {
s/loop/i?
> + val = rockchip_pcie_readl_apb(rockchip, PCIE_CLIENT_DBG_FIFO_STATUS);
> + rate = (val & GENMASK(22, 20)) >> 20;
> + l1ss = (val & GENMASK(10, 8)) >> 8;
> + val &= PCIE_LTSSM_STATUS_MASK;
Can you use FIELD_ macros here?
> +
> + /* Two consecutive identical LTSSM means invalid subsequent data */
Interesting. Does the hardware maintain a counter to track the reads? So once
you break out of the loop and read it after 5s, you'll start from where you left
i.e., the duplicate entry or from the start of the counter again?
> + if ((loop > 0 && val == prev_val) || val > DW_PCIE_LTSSM_RCVRY_EQ3)
> + break;
> +
> + state = prev_val = val;
> + if (val == DW_PCIE_LTSSM_L1_IDLE) {
> + if (l1ss == 2)
> + state = DW_PCIE_LTSSM_L1_2;
> + else if (l1ss == 1)
> + state = DW_PCIE_LTSSM_L1_1;
I believe L1.0 is not supported.
> + }
> +
> + trace_pcie_ltssm_state_transition(dev_name(pci->dev),
> + dw_pcie_ltssm_status_string(state),
> + ((rate + 1) > pci->max_link_speed) ?
> + PCI_SPEED_UNKNOWN : PCIE_SPEED_2_5GT + rate);
> + }
> +
> + schedule_delayed_work(&rockchip->trace_work, msecs_to_jiffies(5000));
> +}
> +
> +static void rockchip_pcie_ltssm_trace(struct rockchip_pcie *rockchip,
> + bool en)
s/en/enable
- Mani
--
மணிவண்ணன் சதாசிவம்
^ permalink raw reply
* Re: [PATCH v2 2/3] Documentation: tracing: Add PCI controller event documentation
From: Manivannan Sadhasivam @ 2026-01-09 5:19 UTC (permalink / raw)
To: Shawn Lin
Cc: Bjorn Helgaas, linux-rockchip, linux-pci, linux-trace-kernel,
linux-doc, Steven Rostedt, Masami Hiramatsu
In-Reply-To: <1767929389-143957-3-git-send-email-shawn.lin@rock-chips.com>
On Fri, Jan 09, 2026 at 11:29:48AM +0800, Shawn Lin wrote:
> The available tracepoint, pcie_ltssm_state_transition, monitors the LTSSM state
> transistion for debugging purpose. Add description about it.
>
> Signed-off-by: Shawn Lin <shawn.lin@rock-chips.com>
> ---
>
> Changes in v2: None
>
> Documentation/trace/events-pci-conotroller.rst | 41 ++++++++++++++++++++++++++
> 1 file changed, 41 insertions(+)
> create mode 100644 Documentation/trace/events-pci-conotroller.rst
>
> diff --git a/Documentation/trace/events-pci-conotroller.rst b/Documentation/trace/events-pci-conotroller.rst
> new file mode 100644
> index 0000000..8253d00
> --- /dev/null
> +++ b/Documentation/trace/events-pci-conotroller.rst
> @@ -0,0 +1,41 @@
> +.. SPDX-License-Identifier: GPL-2.0
> +
> +======================================
> +Subsystem Trace Points: PCI Controller
> +======================================
> +
> +Overview
> +========
> +The PCI controller tracing system provides tracepoints to monitor controller level
> +information for debugging purpose. The events normally show up here:
> +up here:
> +
> + /sys/kernel/tracing/events/pci_controller
> +
> +Cf. include/trace/events/pci_controller.h for the events definitions.
> +
> +Available Tracepoints
> +=====================
> +
> +pcie_ltssm_state_transition
> +-----------------------
> +
> +Monitors PCIe LTSSM state transition including state and rate information
> +::
> +
> + pcie_ltssm_state_transition "dev: %s state: %s rate: %s\n"
> +
> +**Parameters**:
> +
> +* ``dev`` - PCIe root port name
'PCIe controller instance'
> +* ``state`` - PCIe LTSSM state
> +* ``rate`` - PCIe bus speed
'PCIe data rate'
> +
> +**Example Usage**:
> +
> + # Enable the tracepoint
> + echo 1 > /sys/kernel/debug/tracing/events/pci/pcie_ltssm_state_transition/enable
/sys/kernel/debug/tracing/events/pci_controller/pcie_ltssm_state_transition/enable
- Mani
--
மணிவண்ணன் சதாசிவம்
^ permalink raw reply
* Re: [PATCH v2 2/3] Documentation: tracing: Add PCI controller event documentation
From: Bagas Sanjaya @ 2026-01-09 3:53 UTC (permalink / raw)
To: Shawn Lin, Manivannan Sadhasivam, Bjorn Helgaas
Cc: linux-rockchip, linux-pci, linux-trace-kernel, linux-doc,
Steven Rostedt, Masami Hiramatsu
In-Reply-To: <1767929389-143957-3-git-send-email-shawn.lin@rock-chips.com>
[-- Attachment #1: Type: text/plain, Size: 938 bytes --]
On Fri, Jan 09, 2026 at 11:29:48AM +0800, Shawn Lin wrote:
> Documentation/trace/events-pci-conotroller.rst | 41 ++++++++++++++++++++++++++
Missing toctree entry in Documentation/trace/index.rst.
> +Available Tracepoints
> +=====================
> +
> +pcie_ltssm_state_transition
> +-----------------------
Please match section underline length.
> +**Example Usage**:
> +
> + # Enable the tracepoint
> + echo 1 > /sys/kernel/debug/tracing/events/pci/pcie_ltssm_state_transition/enable
> +
> + # Monitor events (the following output is generated when a device is linking)
> + cat /sys/kernel/debug/tracing/trace_pipe
> + kworker/0:0-9 [000] ..... 5.600221: pcie_ltssm_state_transition: dev: a40000000.pcie state: RCVRY_EQ2 rate: 8.0 GT/s
Wrap above example snippets in literal code block (use double colon).
Thanks.
--
An old man doll... just what I always wanted! - Clara
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]
^ permalink raw reply
* Re: [PATCH v2 1/3] PCI: trace: Add PCI controller LTSSM transition tracepoint
From: Steven Rostedt @ 2026-01-09 3:42 UTC (permalink / raw)
To: Shawn Lin
Cc: Manivannan Sadhasivam, Bjorn Helgaas, linux-rockchip, linux-pci,
linux-trace-kernel, linux-doc, Masami Hiramatsu
In-Reply-To: <1767929389-143957-2-git-send-email-shawn.lin@rock-chips.com>
On Fri, 9 Jan 2026 11:29:47 +0800
Shawn Lin <shawn.lin@rock-chips.com> wrote:
> + TP_printk("dev: %s state: %s rate: %s",
> + __get_str(dev_name), __get_str(state),
> + __print_symbolic(__entry->rate,
> + { PCIE_SPEED_2_5GT, "2.5 GT/s" },
> + { PCIE_SPEED_5_0GT, "5.0 GT/s" },
> + { PCIE_SPEED_8_0GT, "8.0 GT/s" },
> + { PCIE_SPEED_16_0GT, "16.0 GT/s" },
> + { PCIE_SPEED_32_0GT, "32.0 GT/s" },
> + { PCIE_SPEED_64_0GT, "64.0 GT/s" },
> + { PCI_SPEED_UNKNOWN, "Unknown" }
As these values are all enums, you may want to add in this file:
TRACE_DEFINE_ENUM(PCIE_SPEED_2_5GT);
TRACE_DEFINE_ENUM(PCIE_SPEED_5_0GT);
[..]
TRACE_DEFINE_ENUM(PCIE_SPEED_UNKNOWN);
So that this can be parsed by user space tooling such as trace-cmd and
perf.
-- Steve
> + )
> + )
> +);
> +
^ permalink raw reply
* [PATCH v3] selftests/tracing: Fix test_multiple_writes stall
From: Fushuai Wang @ 2026-01-09 3:36 UTC (permalink / raw)
To: rostedt, mhiramat, mathieu.desnoyers, shuah, wangfushuai
Cc: skhan, linux-kernel, linux-trace-kernel, linux-kselftest
From: Fushuai Wang <wangfushuai@baidu.com>
When /sys/kernel/tracing/buffer_size_kb is less than 12KB,
the test_multiple_writes test will stall and wait for more
input due to insufficient buffer space.
Check current buffer_size_kb value before the test. If it is
less than 12KB, it temporarily increase the buffer to 12KB,
and restore the original value after the tests are completed.
Fixes: 37f46601383a ("selftests/tracing: Add basic test for trace_marker_raw file")
Suggested-by: Steven Rostedt <rostedt@goodmis.org>
Signed-off-by: Fushuai Wang <wangfushuai@baidu.com>
Acked-by: Steven Rostedt (Google) <rostedt@goodmis.org>
---
V2 -> V3: Make the From and SoB match.
V1 -> V2: Restore buffer_size_kb outside of awk script.
.../ftrace/test.d/00basic/trace_marker_raw.tc | 18 +++++++++++++++++-
1 file changed, 17 insertions(+), 1 deletion(-)
diff --git a/tools/testing/selftests/ftrace/test.d/00basic/trace_marker_raw.tc b/tools/testing/selftests/ftrace/test.d/00basic/trace_marker_raw.tc
index 7daf7292209e..a2c42e13f614 100644
--- a/tools/testing/selftests/ftrace/test.d/00basic/trace_marker_raw.tc
+++ b/tools/testing/selftests/ftrace/test.d/00basic/trace_marker_raw.tc
@@ -89,6 +89,7 @@ test_buffer() {
# The id must be four bytes, test that 3 bytes fails a write
if echo -n abc > ./trace_marker_raw ; then
echo "Too small of write expected to fail but did not"
+ echo ${ORIG} > buffer_size_kb
exit_fail
fi
@@ -99,9 +100,24 @@ test_buffer() {
if write_buffer 0xdeadbeef $size ; then
echo "Too big of write expected to fail but did not"
+ echo ${ORIG} > buffer_size_kb
exit_fail
fi
}
+ORIG=`cat buffer_size_kb`
+
+# test_multiple_writes test needs at least 12KB buffer
+NEW_SIZE=12
+
+if [ ${ORIG} -lt ${NEW_SIZE} ]; then
+ echo ${NEW_SIZE} > buffer_size_kb
+fi
+
test_buffer
-test_multiple_writes
+if ! test_multiple_writes; then
+ echo ${ORIG} > buffer_size_kb
+ exit_fail
+fi
+
+echo ${ORIG} > buffer_size_kb
--
2.36.1
^ permalink raw reply related
* [PATCH v2 1/3] PCI: trace: Add PCI controller LTSSM transition tracepoint
From: Shawn Lin @ 2026-01-09 3:29 UTC (permalink / raw)
To: Manivannan Sadhasivam, Bjorn Helgaas
Cc: linux-rockchip, linux-pci, linux-trace-kernel, linux-doc,
Steven Rostedt, Masami Hiramatsu, Shawn Lin
In-Reply-To: <1767929389-143957-1-git-send-email-shawn.lin@rock-chips.com>
Some platforms may provide LTSSM trace functionality, recording historical
LTSSM state transition information. This is very useful for debugging, such
as when certain devices cannot be recognized or link broken during test.
Implement the pci controller tracepoint for recording LTSSM and rate.
Signed-off-by: Shawn Lin <shawn.lin@rock-chips.com>
---
Changes in v2: None
drivers/pci/trace.c | 1 +
include/trace/events/pci_controller.h | 44 +++++++++++++++++++++++++++++++++++
2 files changed, 45 insertions(+)
create mode 100644 include/trace/events/pci_controller.h
diff --git a/drivers/pci/trace.c b/drivers/pci/trace.c
index cf11abc..c1da9d3 100644
--- a/drivers/pci/trace.c
+++ b/drivers/pci/trace.c
@@ -9,3 +9,4 @@
#define CREATE_TRACE_POINTS
#include <trace/events/pci.h>
+#include <trace/events/pci_controller.h>
diff --git a/include/trace/events/pci_controller.h b/include/trace/events/pci_controller.h
new file mode 100644
index 0000000..47d54c6
--- /dev/null
+++ b/include/trace/events/pci_controller.h
@@ -0,0 +1,44 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM pci_controller
+
+#if !defined(_TRACE_HW_EVENT_PCI_CONTROLLER_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_HW_EVENT_PCI_CONTROLLER_H
+
+#include <uapi/linux/pci_regs.h>
+#include <linux/tracepoint.h>
+
+TRACE_EVENT(pcie_ltssm_state_transition,
+ TP_PROTO(const char *dev_name, const char *state, u32 rate),
+ TP_ARGS(dev_name, state, rate),
+
+ TP_STRUCT__entry(
+ __string(dev_name, dev_name)
+ __string(state, state)
+ __field(u32, rate)
+ ),
+
+ TP_fast_assign(
+ __assign_str(dev_name);
+ __assign_str(state);
+ __entry->rate = rate;
+ ),
+
+ TP_printk("dev: %s state: %s rate: %s",
+ __get_str(dev_name), __get_str(state),
+ __print_symbolic(__entry->rate,
+ { PCIE_SPEED_2_5GT, "2.5 GT/s" },
+ { PCIE_SPEED_5_0GT, "5.0 GT/s" },
+ { PCIE_SPEED_8_0GT, "8.0 GT/s" },
+ { PCIE_SPEED_16_0GT, "16.0 GT/s" },
+ { PCIE_SPEED_32_0GT, "32.0 GT/s" },
+ { PCIE_SPEED_64_0GT, "64.0 GT/s" },
+ { PCI_SPEED_UNKNOWN, "Unknown" }
+ )
+ )
+);
+
+#endif /* _TRACE_HW_EVENT_PCI_CONTROLLER_H */
+
+/* This part must be outside protection */
+#include <trace/define_trace.h>
--
2.7.4
^ permalink raw reply related
* [PATCH v2 0/3] PCI Controller event and LTSSM tracepoint support
From: Shawn Lin @ 2026-01-09 3:29 UTC (permalink / raw)
To: Manivannan Sadhasivam, Bjorn Helgaas
Cc: linux-rockchip, linux-pci, linux-trace-kernel, linux-doc,
Steven Rostedt, Masami Hiramatsu, Shawn Lin
This patch-set adds new pci controller event and LTSSM tracepoint used by host drivers
which provide LTSSM trace functionality. The first user is pcie-dw-rockchip with a 256
Bytes FIFO for recording LTSSM transition.
Dependency
======
Need to apply on top of Mani's rework of error handling of dw_pcie_wait_for_link()
API in order to show the proper LTSSM name for dwc-based controller[1].
[1] https://lore.kernel.org/linux-pci/20260107-pci-dwc-suspend-rework-v4-0-9b5f3c72df0a@oss.qualcomm.com/T/#mfc5885b2afdeef4db1322597eaee61967558821e
Testing
=======
This series was tested on RK3588/RK3588s EVB1 with NVMe SSD connected to PCIe3 and PCIe2
root ports.
echo 1 > /sys/kernel/debug/tracing/events/pci_controller/pcie_ltssm_state_transition/enable
cat /sys/kernel/debug/tracing/trace_pipe
# tracer: nop
#
# entries-in-buffer/entries-written: 64/64 #P:8
#
# _-----=> irqs-off/BH-disabled
# / _----=> need-resched
# | / _---=> hardirq/softirq
# || / _--=> preempt-depth
# ||| / _-=> migrate-disable
# |||| / delay
# TASK-PID CPU# ||||| TIMESTAMP FUNCTION
# | | | ||||| | |
kworker/0:0-9 [000] ..... 5.600194: pcie_ltssm_state_transition: dev: a40000000.pcie state: DETECT_ACT rate: Unknown
kworker/0:0-9 [000] ..... 5.600198: pcie_ltssm_state_transition: dev: a40000000.pcie state: DETECT_WAIT rate: Unknown
kworker/0:0-9 [000] ..... 5.600199: pcie_ltssm_state_transition: dev: a40000000.pcie state: DETECT_ACT rate: Unknown
kworker/0:0-9 [000] ..... 5.600201: pcie_ltssm_state_transition: dev: a40000000.pcie state: POLL_ACTIVE rate: Unknown
kworker/0:0-9 [000] ..... 5.600202: pcie_ltssm_state_transition: dev: a40000000.pcie state: POLL_CONFIG rate: Unknown
kworker/0:0-9 [000] ..... 5.600204: pcie_ltssm_state_transition: dev: a40000000.pcie state: CFG_LINKWD_START rate: Unknown
kworker/0:0-9 [000] ..... 5.600206: pcie_ltssm_state_transition: dev: a40000000.pcie state: CFG_LINKWD_ACEPT rate: Unknown
kworker/0:0-9 [000] ..... 5.600207: pcie_ltssm_state_transition: dev: a40000000.pcie state: CFG_LANENUM_WAI rate: Unknown
kworker/0:0-9 [000] ..... 5.600208: pcie_ltssm_state_transition: dev: a40000000.pcie state: CFG_LANENUM_ACEPT rate: Unknown
kworker/0:0-9 [000] ..... 5.600210: pcie_ltssm_state_transition: dev: a40000000.pcie state: CFG_COMPLETE rate: Unknown
kworker/0:0-9 [000] ..... 5.600212: pcie_ltssm_state_transition: dev: a40000000.pcie state: CFG_IDLE rate: Unknown
kworker/0:0-9 [000] ..... 5.600213: pcie_ltssm_state_transition: dev: a40000000.pcie state: L0 rate: 2.5 GT/s
kworker/0:0-9 [000] ..... 5.600214: pcie_ltssm_state_transition: dev: a40000000.pcie state: RCVRY_LOCK rate: Unknown
kworker/0:0-9 [000] ..... 5.600216: pcie_ltssm_state_transition: dev: a40000000.pcie state: RCVRY_RCVRCFG rate: Unknown
kworker/0:0-9 [000] ..... 5.600217: pcie_ltssm_state_transition: dev: a40000000.pcie state: RCVRY_SPEED rate: Unknown
kworker/0:0-9 [000] ..... 5.600218: pcie_ltssm_state_transition: dev: a40000000.pcie state: RCVRY_LOCK rate: Unknown
kworker/0:0-9 [000] ..... 5.600220: pcie_ltssm_state_transition: dev: a40000000.pcie state: RCVRY_EQ1 rate: Unknown
kworker/0:0-9 [000] ..... 5.600221: pcie_ltssm_state_transition: dev: a40000000.pcie state: RCVRY_EQ2 rate: 8.0 GT/s
kworker/0:0-9 [000] ..... 5.600222: pcie_ltssm_state_transition: dev: a40000000.pcie state: RCVRY_EQ3 rate: 8.0 GT/s
kworker/0:0-9 [000] ..... 5.600224: pcie_ltssm_state_transition: dev: a40000000.pcie state: RCVRY_LOCK rate: 8.0 GT/s
kworker/0:0-9 [000] ..... 5.600225: pcie_ltssm_state_transition: dev: a40000000.pcie state: RCVRY_RCVRCFG rate: 8.0 GT/s
kworker/0:0-9 [000] ..... 5.600226: pcie_ltssm_state_transition: dev: a40000000.pcie state: RCVRY_IDLE rate: 8.0 GT/s
kworker/0:0-9 [000] ..... 5.600227: pcie_ltssm_state_transition: dev: a40000000.pcie state: L0 rate: 8.0 GT/s
kworker/0:0-9 [000] ..... 5.600228: pcie_ltssm_state_transition: dev: a40000000.pcie state: RCVRY_LOCK rate: 8.0 GT/s
kworker/0:0-9 [000] ..... 5.600229: pcie_ltssm_state_transition: dev: a40000000.pcie state: RCVRY_RCVRCFG rate: 8.0 GT/s
kworker/0:0-9 [000] ..... 5.600231: pcie_ltssm_state_transition: dev: a40000000.pcie state: RCVRY_IDLE rate: 8.0 GT/s
kworker/0:0-9 [000] ..... 5.600232: pcie_ltssm_state_transition: dev: a40000000.pcie state: L0 rate: 8.0 GT/s
kworker/0:0-9 [000] ..... 5.600233: pcie_ltssm_state_transition: dev: a40000000.pcie state: L123_SEND_EIDLE rate: 8.0 GT/s
kworker/0:0-9 [000] ..... 5.600234: pcie_ltssm_state_transition: dev: a40000000.pcie state: L1_IDLE rate: 8.0 GT/s
kworker/0:0-9 [000] ..... 5.600236: pcie_ltssm_state_transition: dev: a40000000.pcie state: RCVRY_LOCK rate: 8.0 GT/s
kworker/0:0-9 [000] ..... 5.600237: pcie_ltssm_state_transition: dev: a40000000.pcie state: RCVRY_RCVRCFG rate: 8.0 GT/s
kworker/0:0-9 [000] ..... 5.600238: pcie_ltssm_state_transition: dev: a40000000.pcie state: RCVRY_IDLE rate: 8.0 GT/s
kworker/0:0-9 [000] ..... 5.600239: pcie_ltssm_state_transition: dev: a40000000.pcie state: L0 rate: 8.0 GT/s
Changes in v2:
- create PCI controller tracepoint instead of debugfs(Mani)
- Link to v1: https://lore.kernel.org/linux-pci/ym435w3ltwc7vln7g6j3ijswsarubwjazux65ttcqtrbr3i5fu@gig3qlzdkopf/T/#t
Shawn Lin (3):
PCI: trace: Add pci-controller LTSSM transition tracepoint
Documentation: tracing: Add PCI controller event documentation
PCI: dw-rockchip: Add pcie_ltssm_state_transition trace support
Documentation/trace/events-pci-conotroller.rst | 41 ++++++++++++
drivers/pci/controller/dwc/pcie-dw-rockchip.c | 92 ++++++++++++++++++++++++++
drivers/pci/trace.c | 1 +
include/trace/events/pci_controller.h | 44 ++++++++++++
4 files changed, 178 insertions(+)
create mode 100644 Documentation/trace/events-pci-conotroller.rst
create mode 100644 include/trace/events/pci_controller.h
--
2.7.4
^ permalink raw reply
* [PATCH v2 2/3] Documentation: tracing: Add PCI controller event documentation
From: Shawn Lin @ 2026-01-09 3:29 UTC (permalink / raw)
To: Manivannan Sadhasivam, Bjorn Helgaas
Cc: linux-rockchip, linux-pci, linux-trace-kernel, linux-doc,
Steven Rostedt, Masami Hiramatsu, Shawn Lin
In-Reply-To: <1767929389-143957-1-git-send-email-shawn.lin@rock-chips.com>
The available tracepoint, pcie_ltssm_state_transition, monitors the LTSSM state
transistion for debugging purpose. Add description about it.
Signed-off-by: Shawn Lin <shawn.lin@rock-chips.com>
---
Changes in v2: None
Documentation/trace/events-pci-conotroller.rst | 41 ++++++++++++++++++++++++++
1 file changed, 41 insertions(+)
create mode 100644 Documentation/trace/events-pci-conotroller.rst
diff --git a/Documentation/trace/events-pci-conotroller.rst b/Documentation/trace/events-pci-conotroller.rst
new file mode 100644
index 0000000..8253d00
--- /dev/null
+++ b/Documentation/trace/events-pci-conotroller.rst
@@ -0,0 +1,41 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+======================================
+Subsystem Trace Points: PCI Controller
+======================================
+
+Overview
+========
+The PCI controller tracing system provides tracepoints to monitor controller level
+information for debugging purpose. The events normally show up here:
+up here:
+
+ /sys/kernel/tracing/events/pci_controller
+
+Cf. include/trace/events/pci_controller.h for the events definitions.
+
+Available Tracepoints
+=====================
+
+pcie_ltssm_state_transition
+-----------------------
+
+Monitors PCIe LTSSM state transition including state and rate information
+::
+
+ pcie_ltssm_state_transition "dev: %s state: %s rate: %s\n"
+
+**Parameters**:
+
+* ``dev`` - PCIe root port name
+* ``state`` - PCIe LTSSM state
+* ``rate`` - PCIe bus speed
+
+**Example Usage**:
+
+ # Enable the tracepoint
+ echo 1 > /sys/kernel/debug/tracing/events/pci/pcie_ltssm_state_transition/enable
+
+ # Monitor events (the following output is generated when a device is linking)
+ cat /sys/kernel/debug/tracing/trace_pipe
+ kworker/0:0-9 [000] ..... 5.600221: pcie_ltssm_state_transition: dev: a40000000.pcie state: RCVRY_EQ2 rate: 8.0 GT/s
--
2.7.4
^ permalink raw reply related
* Re: [PATCH v2] selftests/tracing: Fix test_multiple_writes stall
From: Fushuai Wang @ 2026-01-09 3:27 UTC (permalink / raw)
To: rostedt
Cc: fushuai.wang, linux-kernel, linux-kselftest, linux-trace-kernel,
mathieu.desnoyers, mhiramat, shuah, skhan, wangfushuai
In-Reply-To: <20260108165247.3ae2f21a@gandalf.local.home>
> Anyway, Fushuai, you can add to the top of your commit:
>
> From: Fushuai Wang <wangfushuai@baidu.com>
>
> and that will make the From and SoB match without having to change your
> mail client. I usually have that. Because Linus doesn't like my patches
> having my company name in it for the "author" but I have it in the SoB to
> give credit to the one paying me to do the work.
Thanks!
I will send a v3 shortly.
---
Regards,
WANG
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox