* Re: [RESEND,v2 1/2] dt-bindings: memory-controllers: mtk-smi: Add support for mt8189
From: Krzysztof Kozlowski @ 2026-04-28 6:26 UTC (permalink / raw)
To: mtk20898
Cc: Yong Wu, Rob Herring, Conor Dooley, Matthias Brugger,
AngeloGioacchino Del Regno, linux-mediatek, linux-kernel,
devicetree, linux-arm-kernel,
Project_Global_Chrome_Upstream_Group
In-Reply-To: <20260427070444.20247-2-zhengnan.chen@mediatek.com>
On Mon, Apr 27, 2026 at 03:04:28PM +0800, mtk20898 wrote:
> properties:
> compatible:
> oneOf:
> @@ -40,6 +55,8 @@ properties:
> - mediatek,mt8186-smi-common
> - mediatek,mt8188-smi-common-vdo
> - mediatek,mt8188-smi-common-vpp
> + - mediatek,mt8189-smi-common
> + - mediatek,mt8189-smi-sub-common
> - mediatek,mt8192-smi-common
> - mediatek,mt8195-smi-common-vdo
> - mediatek,mt8195-smi-common-vpp
> @@ -108,19 +125,23 @@ allOf:
> compatible:
> contains:
> enum:
> + - mediatek,mt8189-smi-sub-common
> - mediatek,mt8195-smi-sub-common
> then:
> required:
> - mediatek,smi
> properties:
> clocks:
> - minItems: 3
> + minItems: 2
Same problem as v2 before resend.
Please explain me how mt8195 requires three clocks. You can prove it by
trying a malformed DTS (past here the snippet/diff) and pasting here the
validation error.
Best regards,
Krzysztof
^ permalink raw reply
* Re: [REGRESSION] rseq: refactoring in v6.19 broke everyone on arm64 and tcmalloc everywhere
From: Dmitry Vyukov @ 2026-04-28 6:11 UTC (permalink / raw)
To: Thomas Gleixner
Cc: Peter Zijlstra, Mathias Stearn, Jinjie Ruan, linux-man,
Mark Rutland, Mathieu Desnoyers, Catalin Marinas, Will Deacon,
Boqun Feng, Paul E. McKenney, Chris Kennelly, regressions,
linux-kernel, linux-arm-kernel, Ingo Molnar, Blake Oler,
Florian Weimer, Rich Felker, Matthew Wilcox, Greg Kroah-Hartman,
Linus Torvalds
In-Reply-To: <87jyttz8cf.ffs@tglx>
On Mon, 27 Apr 2026 at 00:04, Thomas Gleixner <tglx@kernel.org> wrote:
>
> On Fri, Apr 24 2026 at 21:44, Thomas Gleixner wrote:
> > On Fri, Apr 24 2026 at 17:03, Peter Zijlstra wrote:
> >> On Fri, Apr 24, 2026 at 04:16:08PM +0200, Thomas Gleixner wrote:
> >>> > I was really hoping that we would only need to do the "redundant"
> >>> > cpu_id_start writes would only be needed on membarrier_rseq IPIs where
> >>> > it really is a pay-for-what-you-use functionality,
> >>>
> >>> That's fine and can be solved without adding this sequence overhead into
> >>> the scheduler hotpath.
> >>
> >> Something like so? (probably needs help for !GENERIC bits)
> >
> > Yes and yes :)
> >
> > Let me stare at that !generic tif bits case.
>
> I stared at it and finally gave up because all of this is in a
> completely FUBAR'ed state and ends up in a horrible pile of hacks and
> duct tape with a way larger than zero probability that we chase the
> nasty corner cases for quite some time just to add more duct tape and
> hacks.
>
> Contrary to that it's rather trivial to cleanly separate the behavioral
> cases and guarantees without a masssive runtime overhead and without a
> pile of hard to maintain TCMalloc specific hacks.
>
> All required code is already available to support the architectures
> which do not utilize the generic entry code and therefore can't neither
> use the optimized mode nor time slice extensions. So instead of letting
> the compiler optimize that code out for the generic entry code users, we
> can keep it around and utilize one or the other depending on the
> requested mode. I managed to get the required run-time conditionals down
> to a minimum so that they are in the noise when analysing it with perf.
>
> The real question is how to differentiate between the legacy and the
> optimized mode. I have two working variants to achieve that:
>
> 1) The fully safe option requires a new flag for RSEQ
> registration. It obviously requires a glibc update. (Suggested by
> PeterZ)
>
> 2) Determine the requirements of the registering task via the size of
> the registered RSEQ area.
>
> The original implementation, which TCMalloc depends on, registers
> a 32 byte region (ORIG_RSEG_SIZE). This region has 32 byte
> alignment requirement.
>
> The extension safe newer variant exposes the kernel RSEQ feature
> size via getauxval(AT_RSEQ_FEATURE_SIZE) and the alignment
> requirement via getauxval(AT_RSEQ_ALIGN). The alignment
> requirement is that the registered rseq region is aligned to the
> next power of two of the feature size. The kernel currently has a
> feature size of 33 bytes, which means the alignment requirement is
> 64 bytes.
>
> The TCMalloc RSEQ region is embedded into a cache line aligned
> data structure starting at offset 32 bytes so that bytes 28-31 and
> the cpu_id_start field at bytes 32-35 form a 64-bit little endian
> pointer with the top-most bit (63 set) to check whether the kernel
> has overwritten cpu_id_start with an actual CPU id value, which is
> guaranteed to not have the top most bit set.
>
> As this is part of their performance tuned magic, it's a pretty
> safe assumption, that TCMalloc won't use a larger RSEQ size, which
> allows to select optimized mode for registrations with a size
> greater than 32 bytes.
>
> That does not require any changes to glibc and works out of the
> box. (Suggested by Mathieu)
>
> In both cases the legacy non-optimized mode exposes the original
> behaviour up to the mm_cid field and does not provide support for time
> slice extensions. Optimized mode restores the performance gains and
> enables support for time slice extensions.
>
> I have no strong preference either way and have working code for both
> variants. Though obviously avoiding to update the libc world has a
> charme. If that unexpectedly would turn out to be not sufficient, then
> disabling that would be a trivial one-liner and as a consequence require
> to add the flag and update the libc world.
>
> Combo patch for the auto-detection based on the registered size below as
> that allows to immediately test without glibc dependencies. It applies
> cleanly on Linus tree and 7.0. 6.19 would need some fixups, but I
> learned today that it's already EOL.
>
> In the final version that's three separate patches plus a set of
> selftest changes which validate legacy behaviour and run the full param
> test suite in both legacy and optimized mode.
>
> Thoughts, preferences?
I like this! This does not create fires, and allows incremental transition.
I've tested the patch with membarrier doing TIF_RSEQ_FORCE_RESTART,
and it did not work with unmodified tcmalloc for subtle reasons
anyway. Tcmalloc can be made to work with that approach with minor
changes, but if the goal is to keep old binaries working, that won't
work.
I've tested this patch with unmodified tcmalloc tests, and it almost works.
I think the recent rseq changes introduced 2 more regressions/bugs.
They are caught by tcmalloc tests, but I think they equally affect
optimized v2 mode.
1. This seems to be broken after rseq unregistration:
"cpu_id_start Optimistic cache of the CPU number on which the
registered thread is running. Its value is guaranteed to always be a
possible CPU number, even when rseq is not registered."
Old kernels used to put cpu_id_start = 0:
https://elixir.bootlin.com/linux/v6.7/source/kernel/rseq.c#L119
But now kernel uses this function which puts cpu_id_start =
RSEQ_CPU_ID_UNINITIALIZED:
https://elixir.bootlin.com/linux/v7.0.1/source/include/linux/rseq_entry.h#L503
2. There are spurious SIGSEGV kills on rseq unregistration (thread exit).
Stress tests that unregister rseq and use membarrier sometimes killed
with SIGSEGV inside of rseq(UNREGISTER) syscall. I suspect there is
some race between ipi_rseq and rseq(UNREGISTER). I saw the same when
tested the
TIF_RSEQ_FORCE_RESTART patch -- kernel tried to update user-space rseq
when the pointer was NULL.
rseq_reset uses memset to clear t->rseq:
memset(&t->rseq, 0, sizeof(t->rseq));
If that uses byte writes, then it will clear sched_switch/ids_changed,
then at this point ipi_rseq still sees has_rseq=1 and sets
sched_switch/ids_changed, which cause update on return from
rseq(UNREGISTER).
Not sure if that's it, or there is something else.
This did not happen on older kernels which used rseq_preempt in ipi_rseq:
https://elixir.bootlin.com/linux/v6.7/source/kernel/sched/membarrier.c#L197
> Thanks,
>
> tglx
> ---
> Documentation/userspace-api/rseq.rst | 77 ++++++++++++++
> include/linux/rseq.h | 20 +++
> include/linux/rseq_entry.h | 110 ++++++++++-----------
> include/linux/rseq_types.h | 3
> kernel/rseq.c | 183 ++++++++++++++++++++++-------------
> kernel/sched/membarrier.c | 11 +-
> 6 files changed, 280 insertions(+), 124 deletions(-)
> ---
> --- a/include/linux/rseq.h
> +++ b/include/linux/rseq.h
> @@ -9,6 +9,11 @@
>
> void __rseq_handle_slowpath(struct pt_regs *regs);
>
> +static __always_inline bool rseq_optimized(struct task_struct *t)
> +{
> + return IS_ENABLED(CONFIG_GENERIC_IRQ_ENTRY) && likely(t->rseq.event.optimized);
> +}
> +
> /* Invoked from resume_user_mode_work() */
> static inline void rseq_handle_slowpath(struct pt_regs *regs)
> {
> @@ -30,7 +35,7 @@ void __rseq_signal_deliver(int sig, stru
> */
> static inline void rseq_signal_deliver(struct ksignal *ksig, struct pt_regs *regs)
> {
> - if (IS_ENABLED(CONFIG_GENERIC_IRQ_ENTRY)) {
> + if (IS_ENABLED(CONFIG_GENERIC_IRQ_ENTRY) && rseq_optimized(current)) {
Just rseq_optimized(t), it already includes the other check.
> /* '&' is intentional to spare one conditional branch */
> if (current->rseq.event.has_rseq & current->rseq.event.user_irq)
> __rseq_signal_deliver(ksig->sig, regs);
> @@ -50,15 +55,21 @@ static __always_inline void rseq_sched_s
> {
> struct rseq_event *ev = &t->rseq.event;
>
> - if (IS_ENABLED(CONFIG_GENERIC_IRQ_ENTRY)) {
> + /*
> + * Only apply the user_irq optimization for RSEQ ABI V2
> + * registrations. Legacy users like TCMalloc rely on the historical ABI
> + * V1 behaviour which updates IDs on every context swtich.
> + */
> + if (IS_ENABLED(CONFIG_GENERIC_IRQ_ENTRY) && rseq_optimized(t)) {
Just rseq_optimized(t), it already includes the other check.
> /*
> * Avoid a boat load of conditionals by using simple logic
> * to determine whether NOTIFY_RESUME needs to be raised.
> *
> * It's required when the CPU or MM CID has changed or
> - * the entry was from user space.
> + * the entry was from user space. ev->has_rseq does not
> + * have to be evaluated because optimized implies has_rseq.
> */
> - bool raise = (ev->user_irq | ev->ids_changed) & ev->has_rseq;
> + bool raise = ev->user_irq | ev->ids_changed;
>
> if (raise) {
> ev->sched_switch = true;
> @@ -66,6 +77,7 @@ static __always_inline void rseq_sched_s
> }
> } else {
> if (ev->has_rseq) {
> + t->rseq.event.ids_changed = true;
> t->rseq.event.sched_switch = true;
> rseq_raise_notify_resume(t);
> }
> --- a/include/linux/rseq_entry.h
> +++ b/include/linux/rseq_entry.h
> @@ -111,6 +111,20 @@ static __always_inline void rseq_slice_c
> t->rseq.slice.state.granted = false;
> }
>
> +/*
> + * Open coded, so it can be invoked within a user access region.
> + *
> + * This clears the user space state of the time slice extensions field only when
> + * the task has registered the optimized RSEQ_ABI V2. Some legacy registrations,
> + * e.g. TCMalloc, have conflicting non-ABI fields in struct RSEQ, which would be
> + * overwritten by an unconditional write.
> + */
> +#define rseq_slice_clear_user(rseq, efault) \
> +do { \
> + if (rseq_slice_extension_enabled()) \
> + unsafe_put_user(0U, &rseq->slice_ctrl.all, efault); \
> +} while (0)
> +
> static __always_inline bool __rseq_grant_slice_extension(bool work_pending)
> {
> struct task_struct *curr = current;
> @@ -230,10 +244,10 @@ static __always_inline bool rseq_slice_e
> static __always_inline bool rseq_arm_slice_extension_timer(void) { return false; }
> static __always_inline void rseq_slice_clear_grant(struct task_struct *t) { }
> static __always_inline bool rseq_grant_slice_extension(unsigned long ti_work, unsigned long mask) { return false; }
> +#define rseq_slice_clear_user(rseq, efault) do { } while (0)
> #endif /* !CONFIG_RSEQ_SLICE_EXTENSION */
>
> bool rseq_debug_update_user_cs(struct task_struct *t, struct pt_regs *regs, unsigned long csaddr);
> -bool rseq_debug_validate_ids(struct task_struct *t);
>
> static __always_inline void rseq_note_user_irq_entry(void)
> {
> @@ -353,43 +367,6 @@ bool rseq_debug_update_user_cs(struct ta
> return false;
> }
>
> -/*
> - * On debug kernels validate that user space did not mess with it if the
> - * debug branch is enabled.
> - */
> -bool rseq_debug_validate_ids(struct task_struct *t)
> -{
> - struct rseq __user *rseq = t->rseq.usrptr;
> - u32 cpu_id, uval, node_id;
> -
> - /*
> - * On the first exit after registering the rseq region CPU ID is
> - * RSEQ_CPU_ID_UNINITIALIZED and node_id in user space is 0!
> - */
> - node_id = t->rseq.ids.cpu_id != RSEQ_CPU_ID_UNINITIALIZED ?
> - cpu_to_node(t->rseq.ids.cpu_id) : 0;
> -
> - scoped_user_read_access(rseq, efault) {
> - unsafe_get_user(cpu_id, &rseq->cpu_id_start, efault);
> - if (cpu_id != t->rseq.ids.cpu_id)
> - goto die;
> - unsafe_get_user(uval, &rseq->cpu_id, efault);
> - if (uval != cpu_id)
> - goto die;
> - unsafe_get_user(uval, &rseq->node_id, efault);
> - if (uval != node_id)
> - goto die;
> - unsafe_get_user(uval, &rseq->mm_cid, efault);
> - if (uval != t->rseq.ids.mm_cid)
> - goto die;
> - }
> - return true;
> -die:
> - t->rseq.event.fatal = true;
> -efault:
> - return false;
> -}
> -
> #endif /* RSEQ_BUILD_SLOW_PATH */
>
> /*
> @@ -504,12 +481,32 @@ bool rseq_set_ids_get_csaddr(struct task
> {
> struct rseq __user *rseq = t->rseq.usrptr;
>
> - if (static_branch_unlikely(&rseq_debug_enabled)) {
> - if (!rseq_debug_validate_ids(t))
> - return false;
> - }
> -
> scoped_user_rw_access(rseq, efault) {
> + /* Validate the R/O fields for debug and optimized mode */
> + if (static_branch_unlikely(&rseq_debug_enabled) || rseq_optimized(t)) {
> + u32 cpu_id, uval, node_id;
> +
> + /*
> + * On the first exit after registering the rseq region CPU ID is
> + * RSEQ_CPU_ID_UNINITIALIZED and node_id in user space is 0!
> + */
> + node_id = t->rseq.ids.cpu_id != RSEQ_CPU_ID_UNINITIALIZED ?
> + cpu_to_node(t->rseq.ids.cpu_id) : 0;
> +
> + unsafe_get_user(cpu_id, &rseq->cpu_id_start, efault);
> + if (cpu_id != t->rseq.ids.cpu_id)
> + goto die;
> + unsafe_get_user(uval, &rseq->cpu_id, efault);
> + if (uval != cpu_id)
> + goto die;
> + unsafe_get_user(uval, &rseq->node_id, efault);
> + if (uval != node_id)
> + goto die;
> + unsafe_get_user(uval, &rseq->mm_cid, efault);
> + if (uval != t->rseq.ids.mm_cid)
> + goto die;
> + }
> +
> unsafe_put_user(ids->cpu_id, &rseq->cpu_id_start, efault);
> unsafe_put_user(ids->cpu_id, &rseq->cpu_id, efault);
> unsafe_put_user(node_id, &rseq->node_id, efault);
> @@ -517,11 +514,9 @@ bool rseq_set_ids_get_csaddr(struct task
> if (csaddr)
> unsafe_get_user(*csaddr, &rseq->rseq_cs, efault);
>
> - /* Open coded, so it's in the same user access region */
> - if (rseq_slice_extension_enabled()) {
> - /* Unconditionally clear it, no point in conditionals */
> - unsafe_put_user(0U, &rseq->slice_ctrl.all, efault);
> - }
> + /* RSEQ ABI V2 only operations */
> + if (rseq_optimized(t))
> + rseq_slice_clear_user(rseq, efault);
> }
>
> rseq_slice_clear_grant(t);
> @@ -530,6 +525,9 @@ bool rseq_set_ids_get_csaddr(struct task
> rseq_stat_inc(rseq_stats.ids);
> rseq_trace_update(t, ids);
> return true;
> +
> +die:
> + t->rseq.event.fatal = true;
> efault:
> return false;
> }
> @@ -612,6 +610,14 @@ static __always_inline bool rseq_exit_us
> * interrupts disabled
> */
> guard(pagefault)();
> + /*
> + * This optimization is only valid when the task registered for the
> + * optimized RSEQ_ABI_V2 variant. Some legacy users rely on the original
> + * RSEQ implementation behaviour which unconditionally updated the IDs.
> + * rseq_sched_switch_event() ensures that legacy registrations always
> + * have both sched_switch and ids_changed set, which is compatible with
> + * the historical TIF_NOTIFY_RESUME behaviour.
> + */
> if (likely(!t->rseq.event.ids_changed)) {
> struct rseq __user *rseq = t->rseq.usrptr;
> /*
> @@ -623,11 +629,9 @@ static __always_inline bool rseq_exit_us
> scoped_user_rw_access(rseq, efault) {
> unsafe_get_user(csaddr, &rseq->rseq_cs, efault);
>
> - /* Open coded, so it's in the same user access region */
> - if (rseq_slice_extension_enabled()) {
> - /* Unconditionally clear it, no point in conditionals */
> - unsafe_put_user(0U, &rseq->slice_ctrl.all, efault);
> - }
> + /* RSEQ ABI V2 only operations */
> + if (rseq_optimized(t))
> + rseq_slice_clear_user(rseq, efault);
> }
>
> rseq_slice_clear_grant(t);
> --- a/include/linux/rseq_types.h
> +++ b/include/linux/rseq_types.h
> @@ -18,6 +18,7 @@ struct rseq;
> * @ids_changed: Indicator that IDs need to be updated
> * @user_irq: True on interrupt entry from user mode
> * @has_rseq: True if the task has a rseq pointer installed
> + * @optimized: RSEQ ABI V2 optimized mode
> * @error: Compound error code for the slow path to analyze
> * @fatal: User space data corrupted or invalid
> * @slowpath: Indicator that slow path processing via TIF_NOTIFY_RESUME
> @@ -41,7 +42,7 @@ struct rseq_event {
> };
>
> u8 has_rseq;
> - u8 __pad;
> + u8 optimized;
> union {
> u16 error;
> struct {
> --- a/kernel/rseq.c
> +++ b/kernel/rseq.c
> @@ -258,11 +258,15 @@ static bool rseq_handle_cs(struct task_s
> static void rseq_slowpath_update_usr(struct pt_regs *regs)
> {
> /*
> - * Preserve rseq state and user_irq state. The generic entry code
> - * clears user_irq on the way out, the non-generic entry
> - * architectures are not having user_irq.
> - */
> - const struct rseq_event evt_mask = { .has_rseq = true, .user_irq = true, };
> + * Preserve has_rseq, optimized and user_irq state. The generic entry
> + * code clears user_irq on the way out, the non-generic entry
> + * architectures are not setting user_irq.
> + */
> + const struct rseq_event evt_mask = {
> + .has_rseq = true,
> + .user_irq = true,
> + .optimized = true,
> + };
> struct task_struct *t = current;
> struct rseq_ids ids;
> u32 node_id;
> @@ -335,8 +339,9 @@ void __rseq_handle_slowpath(struct pt_re
> void __rseq_signal_deliver(int sig, struct pt_regs *regs)
> {
> rseq_stat_inc(rseq_stats.signal);
> +
> /*
> - * Don't update IDs, they are handled on exit to user if
> + * Don't update IDs yet, they are handled on exit to user if
> * necessary. The important thing is to abort a critical section of
> * the interrupted context as after this point the instruction
> * pointer in @regs points to the signal handler.
> @@ -349,6 +354,13 @@ void __rseq_signal_deliver(int sig, stru
> current->rseq.event.error = 0;
> force_sigsegv(sig);
> }
> +
> + /*
> + * In legacy mode, force the update of IDs before returning to user
> + * space to stay compatible.
> + */
> + if (!rseq_optimized(current))
> + rseq_force_update();
> }
>
> /*
> @@ -404,66 +416,19 @@ static bool rseq_reset_ids(void)
> /* The original rseq structure size (including padding) is 32 bytes. */
> #define ORIG_RSEQ_SIZE 32
>
> -/*
> - * sys_rseq - setup restartable sequences for caller thread.
> - */
> -SYSCALL_DEFINE4(rseq, struct rseq __user *, rseq, u32, rseq_len, int, flags, u32, sig)
> +static long rseq_register(struct rseq __user * rseq, u32 rseq_len, int flags, u32 sig)
> {
> + bool optimized = IS_ENABLED(CONFIG_GENERIC_IRQ_ENTRY) && rseq_len > ORIG_RSEQ_SIZE;
> u32 rseqfl = 0;
>
> - if (flags & RSEQ_FLAG_UNREGISTER) {
> - if (flags & ~RSEQ_FLAG_UNREGISTER)
> - return -EINVAL;
> - /* Unregister rseq for current thread. */
> - if (current->rseq.usrptr != rseq || !current->rseq.usrptr)
> - return -EINVAL;
> - if (rseq_len != current->rseq.len)
> - return -EINVAL;
> - if (current->rseq.sig != sig)
> - return -EPERM;
> - if (!rseq_reset_ids())
> - return -EFAULT;
> - rseq_reset(current);
> - return 0;
> - }
> -
> - if (unlikely(flags & ~(RSEQ_FLAG_SLICE_EXT_DEFAULT_ON)))
> - return -EINVAL;
> -
> - if (current->rseq.usrptr) {
> - /*
> - * If rseq is already registered, check whether
> - * the provided address differs from the prior
> - * one.
> - */
> - if (current->rseq.usrptr != rseq || rseq_len != current->rseq.len)
> - return -EINVAL;
> - if (current->rseq.sig != sig)
> - return -EPERM;
> - /* Already registered. */
> - return -EBUSY;
> - }
> -
> - /*
> - * If there was no rseq previously registered, ensure the provided rseq
> - * is properly aligned, as communcated to user-space through the ELF
> - * auxiliary vector AT_RSEQ_ALIGN. If rseq_len is the original rseq
> - * size, the required alignment is the original struct rseq alignment.
> - *
> - * The rseq_len is required to be greater or equal to the original rseq
> - * size. In order to be valid, rseq_len is either the original rseq size,
> - * or large enough to contain all supported fields, as communicated to
> - * user-space through the ELF auxiliary vector AT_RSEQ_FEATURE_SIZE.
> - */
> - if (rseq_len < ORIG_RSEQ_SIZE ||
> - (rseq_len == ORIG_RSEQ_SIZE && !IS_ALIGNED((unsigned long)rseq, ORIG_RSEQ_SIZE)) ||
> - (rseq_len != ORIG_RSEQ_SIZE && (!IS_ALIGNED((unsigned long)rseq, rseq_alloc_align()) ||
> - rseq_len < offsetof(struct rseq, end))))
> - return -EINVAL;
> if (!access_ok(rseq, rseq_len))
> return -EFAULT;
>
> - if (IS_ENABLED(CONFIG_RSEQ_SLICE_EXTENSION)) {
> + /*
> + * The optimized check disables time slice extensions for legacy
> + * registrations.
> + */
> + if (IS_ENABLED(CONFIG_RSEQ_SLICE_EXTENSION) && optimized) {
> rseqfl |= RSEQ_CS_FLAG_SLICE_EXT_AVAILABLE;
> if (rseq_slice_extension_enabled() &&
> (flags & RSEQ_FLAG_SLICE_EXT_DEFAULT_ON))
> @@ -485,7 +450,15 @@ SYSCALL_DEFINE4(rseq, struct rseq __user
> unsafe_put_user(RSEQ_CPU_ID_UNINITIALIZED, &rseq->cpu_id, efault);
> unsafe_put_user(0U, &rseq->node_id, efault);
> unsafe_put_user(0U, &rseq->mm_cid, efault);
> - unsafe_put_user(0U, &rseq->slice_ctrl.all, efault);
> +
> + /*
> + * All fields past mm_cid are only valid for non-legacy registrations
> + * which register with rseq_len > ORIG_RSEQ_SIZE.
> + */
> + if (optimized) {
> + if (IS_ENABLED(CONFIG_RSEQ_SLICE_EXTENSION))
> + unsafe_put_user(0U, &rseq->slice_ctrl.all, efault);
> + }
> }
>
> /*
> @@ -501,11 +474,11 @@ SYSCALL_DEFINE4(rseq, struct rseq __user
> #endif
>
> /*
> - * If rseq was previously inactive, and has just been
> - * registered, ensure the cpu_id_start and cpu_id fields
> - * are updated before returning to user-space.
> + * Ensure the cpu_id_start and cpu_id fields are updated before
> + * returning to user-space.
> */
> current->rseq.event.has_rseq = true;
> + current->rseq.event.optimized = optimized;
> rseq_force_update();
> return 0;
>
> @@ -513,6 +486,86 @@ SYSCALL_DEFINE4(rseq, struct rseq __user
> return -EFAULT;
> }
>
> +static long rseq_unregister(struct rseq __user * rseq, u32 rseq_len, int flags, u32 sig)
> +{
> + if (flags & ~RSEQ_FLAG_UNREGISTER)
> + return -EINVAL;
> + if (current->rseq.usrptr != rseq || !current->rseq.usrptr)
> + return -EINVAL;
> + if (rseq_len != current->rseq.len)
> + return -EINVAL;
> + if (current->rseq.sig != sig)
> + return -EPERM;
> + if (!rseq_reset_ids())
> + return -EFAULT;
> + rseq_reset(current);
> + return 0;
> +}
> +
> +static long rseq_reregister(struct rseq __user * rseq, u32 rseq_len, u32 sig)
> +{
> + /*
> + * If rseq is already registered, check whether the provided address
> + * differs from the prior one.
> + */
> + if (current->rseq.usrptr != rseq || rseq_len != current->rseq.len)
> + return -EINVAL;
> + if (current->rseq.sig != sig)
> + return -EPERM;
> + /* Already registered. */
> + return -EBUSY;
> +}
> +
> +static bool rseq_length_valid(struct rseq __user *rseq, unsigned int rseq_len)
> +{
> + if (rseq_len < ORIG_RSEQ_SIZE)
> + return false;
> +
> + /*
> + * Ensure the provided rseq is properly aligned, as communicated to
> + * user-space through the ELF auxiliary vector AT_RSEQ_ALIGN. If
> + * rseq_len is the original rseq size, the required alignment is the
> + * original struct rseq alignment.
> + *
> + * The rseq_len is required to be greater or equal than the original
> + * rseq size.
> + *
> + * In order to be valid, rseq_len is either the original rseq size, or
> + * large enough to contain all supported fields, as communicated to
> + * user-space through the ELF auxiliary vector AT_RSEQ_FEATURE_SIZE.
> + */
> + if (rseq_len < ORIG_RSEQ_SIZE)
> + return false;
> +
> + if (rseq_len == ORIG_RSEQ_SIZE)
> + return IS_ALIGNED((unsigned long)rseq, ORIG_RSEQ_SIZE);
> +
> + return IS_ALIGNED((unsigned long)rseq, rseq_alloc_align()) &&
> + rseq_len >= offsetof(struct rseq, end);
> +}
> +
> +#define RSEQ_FLAGS_SUPPORTED (RSEQ_FLAG_SLICE_EXT_DEFAULT_ON)
> +
> +/*
> + * sys_rseq - Register or unregister restartable sequences for the caller thread.
> + */
> +SYSCALL_DEFINE4(rseq, struct rseq __user *, rseq, u32, rseq_len, int, flags, u32, sig)
> +{
> + if (flags & RSEQ_FLAG_UNREGISTER)
> + return rseq_unregister(rseq, rseq_len, flags, sig);
> +
> + if (unlikely(flags & ~RSEQ_FLAGS_SUPPORTED))
> + return -EINVAL;
> +
> + if (current->rseq.usrptr)
> + return rseq_reregister(rseq, rseq_len, sig);
> +
> + if (!rseq_length_valid(rseq, rseq_len))
> + return -EINVAL;
> +
> + return rseq_register(rseq, rseq_len, flags, sig);
> +}
> +
> #ifdef CONFIG_RSEQ_SLICE_EXTENSION
> struct slice_timer {
> struct hrtimer timer;
> @@ -713,6 +766,8 @@ int rseq_slice_extension_prctl(unsigned
> return -ENOTSUPP;
> if (!current->rseq.usrptr)
> return -ENXIO;
> + if (!current->rseq.event.optimized)
> + return -ENOTSUPP;
>
> /* No change? */
> if (enable == !!current->rseq.slice.state.enabled)
> --- a/kernel/sched/membarrier.c
> +++ b/kernel/sched/membarrier.c
> @@ -199,7 +199,16 @@ static void ipi_rseq(void *info)
> * is negligible.
> */
> smp_mb();
> - rseq_sched_switch_event(current);
> + /*
> + * Legacy mode requires that IDs are written and the critical section is
> + * evaluated. Optimized mode handles the critical section and IDs are
> + * only updated if they change as a consequence of preemption after
> + * return from this IPI.
> + */
> + if (rseq_optimized(current))
> + rseq_sched_switch_event(current);
> + else
> + rseq_force_update();
> }
>
> static void ipi_sync_rq_state(void *info)
> --- a/Documentation/userspace-api/rseq.rst
> +++ b/Documentation/userspace-api/rseq.rst
> @@ -24,6 +24,80 @@ Quick access to CPU number, node ID
> Allows to implement per CPU data efficiently. Documentation is in code and
> selftests. :(
>
> +Optimized RSEQ V2
> +-----------------
> +
> +On architectures which utilize the generic entry code and generic TIF bits
> +the kernel supports runtime optimizations for RSEQ, which also enable
> +enhanced features like scheduler time slice extensions.
> +
> +To enable them a task has to register the RSEQ region with at least the
> +length advertised by getauxval(AT_RSEQ_FEATURE_SIZE).
> +
> +If existing binaries register with RSEQ_ORIG_SIZE (32 bytes), the kernel
> +keeps the legacy low performance mode enabled to fulfil the expectations
> +existing users regarding the original RSEQ implementation behaviour.
> +
> +The following table documents the ABI and behavioral guarantees of the
> +legacy and the optimized V2 mode.
> +
> +.. list-table:: RSEQ modes
> + :header-rows: 1
> +
> + * - Nr
> + - What
> + - Legacy
> + - Optimized V2
> + * - 1
> + - The cpu_id_start, cpu_id, node_id and mm_cid fields (User mode read
> + only)
> + - Updated by the kernel unconditionally after each context switch and
> + before signal delivery
> + - Updated by the kernel if and only if they change, i.e. if the task
> + is migrated or mm_cid changes
> + * - 2
> + - The rseq_cs critical section field
> + - Evaluated and handled unconditionally after each context switch and
> + before signal delivery
> + - Evaluated and handled conditionally only when user space was
> + interrupted. Either after being preempted or before signal delivery
> + in the interrupted context.
> + * - 3
> + - Read only fields
> + - No strict enforcement except in debug mode
> + - Strict enforcement
> + * - 4
> + - membarrier(...RSEQ)
> + - All running threads of the process are interrupted and the ID fields
> + are rewritten and eventually active critical sections are aborted
> + before they return to user space. All threads which are scheduled
> + out whether voluntary or not are covered by #1/#2 above.
> + - All running threads of the process are interrupted and eventually
> + active critical sections are aborted before these threads return to
> + user space. The ID fields are only updated if changed as a
> + consequence of the interrupt. All threads which are scheduled out
> + whether voluntary not are covered by #1/#2 above.
> + * - 5
> + - Time slice extensions
> + - Not supported
> + - Supported
> +
> +The legacy mode is obviously less performant as it does unconditional
> +updates and critical section checks even if not strictly required by the
> +ABI contract. That can't be changed anymore as some users depend on that
> +observed behavior, which in turn enables them to violate the ABI and
> +overwrite the cpu_id_start field for their own purposes. This is obviously
> +discouraged as it renders RSEQ incompatible with the intended usage and
> +breaks the expectation of other libraries in the same application.
> +
> +The ABI compliant optimized mode, which respects the read only fields, does
> +not require unconditional updates and therefore is way more performant. The
> +kernel validates the read only fields for compliance. If user space
> +modifies them, the process is killed. Compliant usage allows multiple
> +libraries in the same application to benefit from the RSEQ functionality
> +without disturbing each other.
> +
> +
> Scheduler time slice extensions
> -------------------------------
>
> @@ -37,7 +111,8 @@ scheduled out inside of the critical sec
>
> * Enabled at boot time (default is enabled)
>
> - * A rseq userspace pointer has been registered for the thread
> + * A rseq userspace pointer has been registered for the thread in
> + optimized V2 mode
>
> The thread has to enable the functionality via prctl(2)::
>
^ permalink raw reply
* Re: [PATCH] crypto: atmel-sha204a - drop hwrng quality reduction for ATSHA204A
From: Ard Biesheuvel @ 2026-04-28 5:58 UTC (permalink / raw)
To: Thorsten Blum, Herbert Xu, David S. Miller, Nicolas Ferre,
Alexandre Belloni, Claudiu Beznea, Marek Behún,
Linus Walleij
Cc: stable, linux-crypto, linux-arm-kernel, linux-kernel
In-Reply-To: <20260427124030.315590-3-thorsten.blum@linux.dev>
Hi Thorsten,
On Mon, 27 Apr 2026, at 14:40, Thorsten Blum wrote:
> Commit 8006aff15516 ("crypto: atmel-sha204a - Set hwrng quality to
> lowest possible") reduced the hwrng quality to 1 based on a review by
> Bill Cox [1]. However, despite its title, the review only tested the
> ATSHA204, not the ATSHA204A.
>
> In the same thread, Atmel engineer Landon Cox wrote "this behavior has
> been eliminated entirely"[2] in the ATSHA204A and "this problem does not
> affect the ATECC108 or the ATECC108A (or the ATSHA204A)"[3].
>
> According to the official ATSHA204A datasheet [4], the device contains a
> high-quality hardware RNG that combines its output with an internal seed
> value stored in EEPROM or SRAM to generate random numbers. The device
> also implements all security functions using SHA-256, and the driver
> uses the chip's Random command in seed-update mode.
>
> Keep 'quality = 1' for ATSHA204, but drop the explicit hwrng quality
> reduction for ATSHA204A and fall back to the hwrng core default.
>
Interesting! Thanks for digging this up.
> [1]
> https://www.metzdowd.com/pipermail/cryptography/2014-December/023858.html
> [2]
> https://www.metzdowd.com/pipermail/cryptography/2014-December/023852.html
> [3]
> https://www.metzdowd.com/pipermail/cryptography/2014-December/023886.html
> [4]
> https://ww1.microchip.com/downloads/en/DeviceDoc/ATSHA204A-Data-Sheet-40002025A.pdf
>
> Fixes: 8006aff15516 ("crypto: atmel-sha204a - Set hwrng quality to
> lowest possible")
> Cc: stable@vger.kernel.org
> Signed-off-by: Thorsten Blum <thorsten.blum@linux.dev>
> ---
> drivers/crypto/atmel-sha204a.c | 40 ++++++++++++++++++----------------
> 1 file changed, 21 insertions(+), 19 deletions(-)
>
> diff --git a/drivers/crypto/atmel-sha204a.c b/drivers/crypto/atmel-sha204a.c
> index dbb39ed0cea1..df69fb190e52 100644
> --- a/drivers/crypto/atmel-sha204a.c
> +++ b/drivers/crypto/atmel-sha204a.c
> @@ -19,6 +19,25 @@
> #include <linux/workqueue.h>
> #include "atmel-i2c.h"
>
> +enum atmel_sha204a_variant {
> + ATSHA204 = 1,
> + ATSHA204A,
> +};
> +
I agree that setting quality to '1' is only appropriate for the ATSHA204
but this looks a bit clunky to me.
Can we retain the comment here that you deleted below, and add
something like
static const unsigned short atsha204_quality = 1;
> +static const struct of_device_id atmel_sha204a_dt_ids[] __maybe_unused = {
> + { .compatible = "atmel,atsha204", .data = (void *)ATSHA204 },
> + { .compatible = "atmel,atsha204a", .data = (void *)ATSHA204A },
> + { /* sentinel */ }
> +};
> +MODULE_DEVICE_TABLE(of, atmel_sha204a_dt_ids);
> +
> +static const struct i2c_device_id atmel_sha204a_id[] = {
> + { .name = "atsha204", .driver_data = ATSHA204 },
> + { .name = "atsha204a", .driver_data = ATSHA204A },
> + { /* sentinel */ }
> +};
> +MODULE_DEVICE_TABLE(i2c, atmel_sha204a_id);
> +
Then, move these back to the old location, and point .data /
.driver_data to &atsha204_quality for atsha204 only.
> static void atmel_sha204a_rng_done(struct atmel_i2c_work_data *work_data,
> void *areq, int status)
> {
> @@ -171,11 +190,8 @@ static int atmel_sha204a_probe(struct i2c_client *client)
> i2c_priv->hwrng.name = dev_name(&client->dev);
> i2c_priv->hwrng.read = atmel_sha204a_rng_read;
>
> - /*
> - * According to review by Bill Cox [1], this HWRNG has very low
> entropy.
> - * [1]
> https://www.metzdowd.com/pipermail/cryptography/2014-December/023858.html
> - */
> - i2c_priv->hwrng.quality = 1;
> + if ((uintptr_t)i2c_get_match_data(client) == ATSHA204)
> + i2c_priv->hwrng.quality = 1;
>
Here you can override the field by dereferencing the match data if it
is non-NULL.
Alternatively, you could store the quality in the device_id structs
directly, but I think this is slightly more idiomatic.
> ret = devm_hwrng_register(&client->dev, &i2c_priv->hwrng);
> if (ret)
> @@ -202,20 +218,6 @@ static void atmel_sha204a_remove(struct i2c_client *client)
> kfree((void *)i2c_priv->hwrng.priv);
> }
>
> -static const struct of_device_id atmel_sha204a_dt_ids[] __maybe_unused = {
> - { .compatible = "atmel,atsha204", },
> - { .compatible = "atmel,atsha204a", },
> - { /* sentinel */ }
> -};
> -MODULE_DEVICE_TABLE(of, atmel_sha204a_dt_ids);
> -
> -static const struct i2c_device_id atmel_sha204a_id[] = {
> - { "atsha204" },
> - { "atsha204a" },
> - { /* sentinel */ }
> -};
> -MODULE_DEVICE_TABLE(i2c, atmel_sha204a_id);
> -
> static struct i2c_driver atmel_sha204a_driver = {
> .probe = atmel_sha204a_probe,
> .remove = atmel_sha204a_remove,
^ permalink raw reply
* [PATCH net-next] net: airoha: Rename get_src_port_id callback in get_sport
From: Lorenzo Bianconi @ 2026-04-28 5:23 UTC (permalink / raw)
To: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni
Cc: Simon Horman, linux-arm-kernel, linux-mediatek, netdev,
Lorenzo Bianconi
For code consistency, rename get_src_port_id callback in get_sport.
Please note this patch does not introduce any logical change and it is
just a cosmetic patch.
Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
---
drivers/net/ethernet/airoha/airoha_eth.c | 10 +++++-----
drivers/net/ethernet/airoha/airoha_eth.h | 2 +-
2 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/drivers/net/ethernet/airoha/airoha_eth.c b/drivers/net/ethernet/airoha/airoha_eth.c
index 2bb0a3ff9810..56441b99448a 100644
--- a/drivers/net/ethernet/airoha/airoha_eth.c
+++ b/drivers/net/ethernet/airoha/airoha_eth.c
@@ -1813,7 +1813,7 @@ static int airoha_set_gdm2_loopback(struct airoha_gdm_port *port)
airoha_fe_clear(eth, REG_FE_VIP_PORT_EN, BIT(AIROHA_GDM2_IDX));
airoha_fe_clear(eth, REG_FE_IFC_PORT_EN, BIT(AIROHA_GDM2_IDX));
- src_port = eth->soc->ops.get_src_port_id(port, port->nbq);
+ src_port = eth->soc->ops.get_sport(port, port->nbq);
if (src_port < 0)
return src_port;
@@ -3187,7 +3187,7 @@ static const char * const en7581_xsi_rsts_names[] = {
"xfp-mac",
};
-static int airoha_en7581_get_src_port_id(struct airoha_gdm_port *port, int nbq)
+static int airoha_en7581_get_sport(struct airoha_gdm_port *port, int nbq)
{
switch (port->id) {
case AIROHA_GDM3_IDX:
@@ -3240,7 +3240,7 @@ static const char * const an7583_xsi_rsts_names[] = {
"xfp-mac",
};
-static int airoha_an7583_get_src_port_id(struct airoha_gdm_port *port, int nbq)
+static int airoha_an7583_get_sport(struct airoha_gdm_port *port, int nbq)
{
switch (port->id) {
case AIROHA_GDM3_IDX:
@@ -3288,7 +3288,7 @@ static const struct airoha_eth_soc_data en7581_soc_data = {
.num_xsi_rsts = ARRAY_SIZE(en7581_xsi_rsts_names),
.num_ppe = 2,
.ops = {
- .get_src_port_id = airoha_en7581_get_src_port_id,
+ .get_sport = airoha_en7581_get_sport,
.get_vip_port = airoha_en7581_get_vip_port,
},
};
@@ -3299,7 +3299,7 @@ static const struct airoha_eth_soc_data an7583_soc_data = {
.num_xsi_rsts = ARRAY_SIZE(an7583_xsi_rsts_names),
.num_ppe = 1,
.ops = {
- .get_src_port_id = airoha_an7583_get_src_port_id,
+ .get_sport = airoha_an7583_get_sport,
.get_vip_port = airoha_an7583_get_vip_port,
},
};
diff --git a/drivers/net/ethernet/airoha/airoha_eth.h b/drivers/net/ethernet/airoha/airoha_eth.h
index e389d2fe3b86..1a052b898816 100644
--- a/drivers/net/ethernet/airoha/airoha_eth.h
+++ b/drivers/net/ethernet/airoha/airoha_eth.h
@@ -578,7 +578,7 @@ struct airoha_eth_soc_data {
int num_xsi_rsts;
int num_ppe;
struct {
- int (*get_src_port_id)(struct airoha_gdm_port *port, int nbq);
+ int (*get_sport)(struct airoha_gdm_port *port, int nbq);
u32 (*get_vip_port)(struct airoha_gdm_port *port, int nbq);
} ops;
};
---
base-commit: 790ead9394860e7d70c5e0e50a35b243e909a618
change-id: 20260428-airoha-get_src_port_id-callback-6526e82ba957
Best regards,
--
Lorenzo Bianconi <lorenzo@kernel.org>
^ permalink raw reply related
* [PATCH net-next] net: airoha: Introduce airoha_fe_get()/airoha_qdma_get() register read helpers
From: Lorenzo Bianconi @ 2026-04-28 5:10 UTC (permalink / raw)
To: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni
Cc: Simon Horman, linux-arm-kernel, linux-mediatek, netdev,
Lorenzo Bianconi
Add airoha_fe_get() and airoha_qdma_get() as utility routines for reading
a masked field from a specified register.
This is a non-functional refactor, no logical changes are introduced to
the existing codebase.
Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
---
drivers/net/ethernet/airoha/airoha_eth.c | 13 ++++---------
drivers/net/ethernet/airoha/airoha_eth.h | 4 ++++
drivers/net/ethernet/airoha/airoha_ppe.c | 5 ++---
3 files changed, 10 insertions(+), 12 deletions(-)
diff --git a/drivers/net/ethernet/airoha/airoha_eth.c b/drivers/net/ethernet/airoha/airoha_eth.c
index 2bb0a3ff9810..40b7a00c7d95 100644
--- a/drivers/net/ethernet/airoha/airoha_eth.c
+++ b/drivers/net/ethernet/airoha/airoha_eth.c
@@ -201,15 +201,13 @@ static void airoha_fe_vip_setup(struct airoha_eth *eth)
static u32 airoha_fe_get_pse_queue_rsv_pages(struct airoha_eth *eth,
u32 port, u32 queue)
{
- u32 val;
-
airoha_fe_rmw(eth, REG_FE_PSE_QUEUE_CFG_WR,
PSE_CFG_PORT_ID_MASK | PSE_CFG_QUEUE_ID_MASK,
FIELD_PREP(PSE_CFG_PORT_ID_MASK, port) |
FIELD_PREP(PSE_CFG_QUEUE_ID_MASK, queue));
- val = airoha_fe_rr(eth, REG_FE_PSE_QUEUE_CFG_VAL);
- return FIELD_GET(PSE_CFG_OQ_RSV_MASK, val);
+ return airoha_fe_get(eth, REG_FE_PSE_QUEUE_CFG_VAL,
+ PSE_CFG_OQ_RSV_MASK);
}
static void airoha_fe_set_pse_queue_rsv_pages(struct airoha_eth *eth,
@@ -227,9 +225,7 @@ static void airoha_fe_set_pse_queue_rsv_pages(struct airoha_eth *eth,
static u32 airoha_fe_get_pse_all_rsv(struct airoha_eth *eth)
{
- u32 val = airoha_fe_rr(eth, REG_FE_PSE_BUF_SET);
-
- return FIELD_GET(PSE_ALLRSV_MASK, val);
+ return airoha_fe_get(eth, REG_FE_PSE_BUF_SET, PSE_ALLRSV_MASK);
}
static int airoha_fe_set_pse_oq_rsv(struct airoha_eth *eth,
@@ -247,8 +243,7 @@ static int airoha_fe_set_pse_oq_rsv(struct airoha_eth *eth,
FIELD_PREP(PSE_ALLRSV_MASK, all_rsv));
/* modify hthd */
- tmp = airoha_fe_rr(eth, PSE_FQ_CFG);
- fq_limit = FIELD_GET(PSE_FQ_LIMIT_MASK, tmp);
+ fq_limit = airoha_fe_get(eth, PSE_FQ_CFG, PSE_FQ_LIMIT_MASK);
tmp = fq_limit - all_rsv - 0x20;
airoha_fe_rmw(eth, REG_PSE_SHARE_USED_THD,
PSE_SHARE_USED_HTHD_MASK,
diff --git a/drivers/net/ethernet/airoha/airoha_eth.h b/drivers/net/ethernet/airoha/airoha_eth.h
index e389d2fe3b86..c81433d44e3e 100644
--- a/drivers/net/ethernet/airoha/airoha_eth.h
+++ b/drivers/net/ethernet/airoha/airoha_eth.h
@@ -619,6 +619,8 @@ u32 airoha_rmw(void __iomem *base, u32 offset, u32 mask, u32 val);
airoha_rmw((eth)->fe_regs, (offset), 0, (val))
#define airoha_fe_clear(eth, offset, val) \
airoha_rmw((eth)->fe_regs, (offset), (val), 0)
+#define airoha_fe_get(eth, offset, mask) \
+ FIELD_GET((mask), airoha_fe_rr((eth), (offset)))
#define airoha_qdma_rr(qdma, offset) \
airoha_rr((qdma)->regs, (offset))
@@ -630,6 +632,8 @@ u32 airoha_rmw(void __iomem *base, u32 offset, u32 mask, u32 val);
airoha_rmw((qdma)->regs, (offset), 0, (val))
#define airoha_qdma_clear(qdma, offset, val) \
airoha_rmw((qdma)->regs, (offset), (val), 0)
+#define airoha_qdma_get(eth, offset, mask) \
+ FIELD_GET((mask), airoha_qdma_rr((eth), (offset)))
static inline bool airoha_is_lan_gdm_port(struct airoha_gdm_port *port)
{
diff --git a/drivers/net/ethernet/airoha/airoha_ppe.c b/drivers/net/ethernet/airoha/airoha_ppe.c
index 5c9dff6bccd1..697af6fdd4c3 100644
--- a/drivers/net/ethernet/airoha/airoha_ppe.c
+++ b/drivers/net/ethernet/airoha/airoha_ppe.c
@@ -80,9 +80,8 @@ bool airoha_ppe_is_enabled(struct airoha_eth *eth, int index)
static u32 airoha_ppe_get_timestamp(struct airoha_ppe *ppe)
{
- u16 timestamp = airoha_fe_rr(ppe->eth, REG_FE_FOE_TS);
-
- return FIELD_GET(AIROHA_FOE_IB1_BIND_TIMESTAMP, timestamp);
+ return airoha_fe_get(ppe->eth, REG_FE_FOE_TS,
+ AIROHA_FOE_IB1_BIND_TIMESTAMP);
}
void airoha_ppe_set_cpu_port(struct airoha_gdm_port *port, u8 ppe_id, u8 fport)
---
base-commit: 790ead9394860e7d70c5e0e50a35b243e909a618
change-id: 20260428-airoha_fe_get-airoha_qdma_get-7a087a23aef4
Best regards,
--
Lorenzo Bianconi <lorenzo@kernel.org>
^ permalink raw reply related
* Re: [PATCH net] net: airoha: Do not read uninitialized fragment address in airoha_dev_xmit()
From: Lorenzo Bianconi @ 2026-04-28 5:06 UTC (permalink / raw)
To: Jakub Kicinski
Cc: Andrew Lunn, David S. Miller, Eric Dumazet, Paolo Abeni,
Simon Horman, linux-arm-kernel, linux-mediatek, netdev
In-Reply-To: <20260427173935.6a1e36ee@kernel.org>
[-- Attachment #1: Type: text/plain, Size: 1072 bytes --]
> On Sat, 25 Apr 2026 16:10:51 +0200 Lorenzo Bianconi wrote:
> > - Does the TSO checksum calculation earlier in this function ensure the
> > TCP header is in the linear portion of the SKB?
> > This issue is not related to the current patch. Moreover, can we have a TSO
> > packet where the tcp header is not in the linear area of the skb?
>
> Don't think so.
>
> > - If dma_map_single() fails partway through a multi-fragment packet and
> > triggers this goto error_unmap, will it break the Tx ring contiguity?
> > This issue is not related to the current patch. Moreover, I guess the hw is
> > capable of managing out-of-order descriptors.
> >
> > - Is it safe to map fragment data using dma_map_single() instead of
> > skb_frag_dma_map()?
> > This issue is not related to the current patch. I will post a dedicated patch
> > for it.
>
> I don't think it's an issue. Unless you support DMABUF zero-copy
> the skb_frag helper is just for convenience. I wouldn't bother.
ack, let's skip it for the moment.
Regards,
Lorenzo
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]
^ permalink raw reply
* Re: Re: [PATCH v8 next 00/10] arm_mpam: Introduce Narrow-PARTID feature
From: Shaopeng Tan (Fujitsu) @ 2026-04-28 4:20 UTC (permalink / raw)
To: ben.horgan@arm.com, Dave.Martin@arm.com, james.morse@arm.com,
reinette.chatre@intel.com, fenghuay@nvidia.com, tglx@kernel.org,
will@kernel.org, hpa@zytor.com, bp@alien8.de, babu.moger@amd.com,
dave.hansen@linux.intel.com, mingo@redhat.com,
tony.luck@intel.com, gshan@redhat.com, catalin.marinas@arm.com,
TY4PR01MB16930EB1ACB3A3356A92169BC8B232@TY4PR01MB16930.jpnprd01.prod.outlook.com,
Zeng Heng
Cc: linux-arm-kernel@lists.infradead.org, x86@kernel.org,
linux-kernel@vger.kernel.org, wangkefeng.wang@huawei.com
In-Reply-To: <1d9cee5a-38be-7115-51ef-b7109aa4ab5e@huawei.com>
Hello Zeng Heng,
I hope this email finds you well.
>As indicated in the patch series tags, this patch set applies to the
>linux-next repository, specifically the master branch at:
>https://kernel.googlesource.com/pub/scm/linux/kernel/git/next/linux-next.git
This patch series could not be applied correctly to the master branch.
>Keep me in the mail list for follow-up responses if you want my feedback
>in time. I was accidentally dropped from the mail list in a previous
>thread (see
>https://lore.kernel.org/all/TY4PR01MB16930EB1ACB3A3356A92169BC8B232@TY4PR01MB16930.jpnprd01.prod.outlook.com/).
I've confirmed that your email address was correctly in the recipient field, and the email was sent successfully on my end.
Also, it seems that I sometimes don't receive your emails.
I'm not entirely sure why this is happening, as my email settings appear to be configured correctly.
Best regards,
Shaopeng TAN
^ permalink raw reply
* Re: [RFC PATCH 0/8] mm/vmalloc: Speed up ioremap, vmalloc and vmap with contiguous memory
From: Dev Jain @ 2026-04-28 4:14 UTC (permalink / raw)
To: Barry Song
Cc: linux-mm, linux-arm-kernel, catalin.marinas, will, akpm, urezki,
linux-kernel, anshuman.khandual, ryan.roberts, ajd, rppt, david,
Xueyuan.chen21, jiangwenxiaomi
In-Reply-To: <CAGsJ_4zwrsrKt5NiuN-rYCqJiyjNdv=UssLuf8VCu8xZ+5sohA@mail.gmail.com>
On 28/04/26 8:46 am, Barry Song wrote:
> On Mon, Apr 27, 2026 at 11:05 PM Dev Jain <dev.jain@arm.com> wrote:
>>
>>
>>
>> On 08/04/26 8:21 am, Barry Song (Xiaomi) wrote:
> [...]
>>>
>>> Barry Song (Xiaomi) (8):
>>> arm64/hugetlb: Extend batching of multiple CONT_PTE in a single PTE
>>> setup
>>> arm64/vmalloc: Allow arch_vmap_pte_range_map_size to batch multiple
>>> CONT_PTE
>>> mm/vmalloc: Extend vmap_small_pages_range_noflush() to support larger
>>> page_shift sizes
>>> mm/vmalloc: Eliminate page table zigzag for huge vmalloc mappings
>>> mm/vmalloc: map contiguous pages in batches for vmap() if possible
>>> mm/vmalloc: align vm_area so vmap() can batch mappings
>>> mm/vmalloc: Coalesce same page_shift mappings in vmap to avoid pgtable
>>> zigzag
>>> mm/vmalloc: Stop scanning for compound pages after encountering small
>>> pages in vmap
>>>
>>> arch/arm64/include/asm/vmalloc.h | 6 +-
>>> arch/arm64/mm/hugetlbpage.c | 10 ++
>>> mm/vmalloc.c | 178 +++++++++++++++++++++++++------
>>> 3 files changed, 161 insertions(+), 33 deletions(-)
>>>
>>
>> Hi Barry, have you got the chance to work on v2?
>
> Hi Dev, thanks for the ping.
>
> Yes, I’m getting Wen Jiang (cc’d) to send v2 within the next few days.
> The patchset is basically ready, but still under testing.
Thanks!
^ permalink raw reply
* Re: [PATCH 5/5] fpga: m10bmc-sec: switch show_canceled_csk() to using sysfs_emit()
From: Xu Yilun @ 2026-04-28 3:33 UTC (permalink / raw)
To: Yury Norov
Cc: linux-kernel, Christophe Leroy (CS GROUP), Peter Zijlstra (Intel),
Rafael J. Wysocki, Alexander Shishkin, Daniel Lezcano,
Ingo Molnar, James Clark, Kees Cook, Lukasz Luba,
Madhavan Srinivasan, Michael Ellerman, Mike Leach, Moritz Fischer,
Nicholas Piggin, Russ Weight, Shrikanth Hegde, Suki K Poulose,
Tom Rix, Thomas Weißschuh, Xu Yilun, Yury Norov, Zhang Rui,
coresight, linux-arm-kernel, linux-fpga, linux-pm, linuxppc-dev,
Jakub Kicinski
In-Reply-To: <afAh1hq_mkRN3q2t@yury>
On Mon, Apr 27, 2026 at 10:56:22PM -0400, Yury Norov wrote:
> On Wed, Mar 25, 2026 at 03:25:48PM +0800, Xu Yilun wrote:
> > On Tue, Mar 24, 2026 at 02:38:04PM -0400, Yury Norov wrote:
> > > On Tue, Mar 24, 2026 at 05:15:33PM +0800, Xu Yilun wrote:
> > > > On Tue, Mar 03, 2026 at 03:08:41PM -0500, Yury Norov wrote:
> > > > > Switch show_canceled_csk() to use the proper sysfs_emit("%*pbl").
> > > > >
> > > > > Reviewed-by: Russ Weight <russ.weight@linux.dev>
> > > > > Suggested-by: Thomas Weißschuh <linux@weissschuh.net>
> > > > > Signed-off-by: Yury Norov <ynorov@nvidia.com>
> > > > > ---
> > > > > drivers/fpga/intel-m10-bmc-sec-update.c | 3 ++-
> > > > > 1 file changed, 2 insertions(+), 1 deletion(-)
> > > > >
> > > > > diff --git a/drivers/fpga/intel-m10-bmc-sec-update.c b/drivers/fpga/intel-m10-bmc-sec-update.c
> > > > > index 10f678b9ed36..ae364c6636eb 100644
> > > > > --- a/drivers/fpga/intel-m10-bmc-sec-update.c
> > > > > +++ b/drivers/fpga/intel-m10-bmc-sec-update.c
> > > > > @@ -10,6 +10,7 @@
> > > > > #include <linux/firmware.h>
> > > > > #include <linux/mfd/intel-m10-bmc.h>
> > > > > #include <linux/mod_devicetable.h>
> > > > > +#include <linux/mm.h>
> > > >
> > > > Why add this header file?
> > >
> > > When I was preparing the series, I had build issues without this. But
> > > now I checked it against -rc5, and it's clean. Would you like me to
> > > resend?
> >
> > No need. Given that I'll pick this patch alone to fpga for-next with the
> > fix.
> >
> > Reviewed-by: Xu Yilun <yilun.xu@intel.com>
>
> Hi Xu,
>
> This patch is still not applied. This is the last non-lib user of
I see it is already in v7.1-rc1, what's your expectation?
> the bitmap_print_to_pagebuf(), and it blocks me from removing the
> function.
>
> Are you still going to pick it yourself? I can move the patch with
> bitmap-for-next if you prefer.
>
> Thanks,
> Yury
^ permalink raw reply
* Re: [PATCH] spi: axiado: replace usleep_range() with udelay() in IRQ path
From: Mark Brown @ 2026-04-27 23:36 UTC (permalink / raw)
To: Vladimir Moravcevic, Tzu-Hao Wei, Swark Yang, Prasad Bolisetty,
Harshit Shah, Felix Gu
Cc: linux-spi, linux-arm-kernel, linux-kernel
In-Reply-To: <20260428-axiado-v1-1-cd767500af72@gmail.com>
On Tue, 28 Apr 2026 00:33:04 +0800, Felix Gu wrote:
> spi: axiado: replace usleep_range() with udelay() in IRQ path
Applied to
https://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi.git for-7.1
Thanks!
[1/1] spi: axiado: replace usleep_range() with udelay() in IRQ path
https://git.kernel.org/broonie/spi/c/f5c6a272b699
All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.
You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.
If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.
Please add any relevant lists and maintainers to the CCs when replying
to this mail.
Thanks,
Mark
^ permalink raw reply
* Re: [RFC PATCH 0/8] mm/vmalloc: Speed up ioremap, vmalloc and vmap with contiguous memory
From: Barry Song @ 2026-04-28 3:16 UTC (permalink / raw)
To: Dev Jain
Cc: linux-mm, linux-arm-kernel, catalin.marinas, will, akpm, urezki,
linux-kernel, anshuman.khandual, ryan.roberts, ajd, rppt, david,
Xueyuan.chen21, jiangwenxiaomi
In-Reply-To: <fb022a6f-0faf-4742-8934-8a7ffae806f6@arm.com>
On Mon, Apr 27, 2026 at 11:05 PM Dev Jain <dev.jain@arm.com> wrote:
>
>
>
> On 08/04/26 8:21 am, Barry Song (Xiaomi) wrote:
[...]
> >
> > Barry Song (Xiaomi) (8):
> > arm64/hugetlb: Extend batching of multiple CONT_PTE in a single PTE
> > setup
> > arm64/vmalloc: Allow arch_vmap_pte_range_map_size to batch multiple
> > CONT_PTE
> > mm/vmalloc: Extend vmap_small_pages_range_noflush() to support larger
> > page_shift sizes
> > mm/vmalloc: Eliminate page table zigzag for huge vmalloc mappings
> > mm/vmalloc: map contiguous pages in batches for vmap() if possible
> > mm/vmalloc: align vm_area so vmap() can batch mappings
> > mm/vmalloc: Coalesce same page_shift mappings in vmap to avoid pgtable
> > zigzag
> > mm/vmalloc: Stop scanning for compound pages after encountering small
> > pages in vmap
> >
> > arch/arm64/include/asm/vmalloc.h | 6 +-
> > arch/arm64/mm/hugetlbpage.c | 10 ++
> > mm/vmalloc.c | 178 +++++++++++++++++++++++++------
> > 3 files changed, 161 insertions(+), 33 deletions(-)
> >
>
> Hi Barry, have you got the chance to work on v2?
Hi Dev, thanks for the ping.
Yes, I’m getting Wen Jiang (cc’d) to send v2 within the next few days.
The patchset is basically ready, but still under testing.
^ permalink raw reply
* Re: [PATCH 5/5] fpga: m10bmc-sec: switch show_canceled_csk() to using sysfs_emit()
From: Yury Norov @ 2026-04-28 2:56 UTC (permalink / raw)
To: Xu Yilun
Cc: linux-kernel, Christophe Leroy (CS GROUP), Peter Zijlstra (Intel),
Rafael J. Wysocki, Alexander Shishkin, Daniel Lezcano,
Ingo Molnar, James Clark, Kees Cook, Lukasz Luba,
Madhavan Srinivasan, Michael Ellerman, Mike Leach, Moritz Fischer,
Nicholas Piggin, Russ Weight, Shrikanth Hegde, Suki K Poulose,
Tom Rix, Thomas Weißschuh, Xu Yilun, Yury Norov, Zhang Rui,
coresight, linux-arm-kernel, linux-fpga, linux-pm, linuxppc-dev,
Jakub Kicinski
In-Reply-To: <acON/EU/GFvxRO1e@yilunxu-OptiPlex-7050>
On Wed, Mar 25, 2026 at 03:25:48PM +0800, Xu Yilun wrote:
> On Tue, Mar 24, 2026 at 02:38:04PM -0400, Yury Norov wrote:
> > On Tue, Mar 24, 2026 at 05:15:33PM +0800, Xu Yilun wrote:
> > > On Tue, Mar 03, 2026 at 03:08:41PM -0500, Yury Norov wrote:
> > > > Switch show_canceled_csk() to use the proper sysfs_emit("%*pbl").
> > > >
> > > > Reviewed-by: Russ Weight <russ.weight@linux.dev>
> > > > Suggested-by: Thomas Weißschuh <linux@weissschuh.net>
> > > > Signed-off-by: Yury Norov <ynorov@nvidia.com>
> > > > ---
> > > > drivers/fpga/intel-m10-bmc-sec-update.c | 3 ++-
> > > > 1 file changed, 2 insertions(+), 1 deletion(-)
> > > >
> > > > diff --git a/drivers/fpga/intel-m10-bmc-sec-update.c b/drivers/fpga/intel-m10-bmc-sec-update.c
> > > > index 10f678b9ed36..ae364c6636eb 100644
> > > > --- a/drivers/fpga/intel-m10-bmc-sec-update.c
> > > > +++ b/drivers/fpga/intel-m10-bmc-sec-update.c
> > > > @@ -10,6 +10,7 @@
> > > > #include <linux/firmware.h>
> > > > #include <linux/mfd/intel-m10-bmc.h>
> > > > #include <linux/mod_devicetable.h>
> > > > +#include <linux/mm.h>
> > >
> > > Why add this header file?
> >
> > When I was preparing the series, I had build issues without this. But
> > now I checked it against -rc5, and it's clean. Would you like me to
> > resend?
>
> No need. Given that I'll pick this patch alone to fpga for-next with the
> fix.
>
> Reviewed-by: Xu Yilun <yilun.xu@intel.com>
Hi Xu,
This patch is still not applied. This is the last non-lib user of
the bitmap_print_to_pagebuf(), and it blocks me from removing the
function.
Are you still going to pick it yourself? I can move the patch with
bitmap-for-next if you prefer.
Thanks,
Yury
^ permalink raw reply
* [PATCH] mailbox: mtk-adsp: fix UAF during device teardown
From: Sergey Senozhatsky @ 2026-04-28 2:55 UTC (permalink / raw)
To: Jassi Brar, Matthias Brugger, AngeloGioacchino Del Regno,
Allen-KH Cheng, YC Hung
Cc: Tzung-Bi Shih, linux-kernel, linux-arm-kernel, linux-mediatek,
Sergey Senozhatsky
When the SOF audio driver fails to initialize (e.g. firmware boot
timeout), its devres unwind frees the snd_sof_dev object that the
mailbox client (mtk-adsp-ipc) reaches via chan->cl->rx_callback.
The mtk-adsp-mailbox shutdown clears the mailbox command registers
but leaves the IRQ line unmasked, so a late interrupt can still
queue a threaded handler after mbox_free_channel() had cleared
chan->cl, and mbox_chan_received_data() would then trigger UAF:
BUG: KASAN: slab-use-after-free in sof_ipc3_validate_fw_version
sof_ipc3_validate_fw_version
sof_ipc3_do_rx_work
sof_ipc3_rx_msg
mt8196_dsp_handle_request
mtk_adsp_ipc_recv
mbox_chan_received_data
mtk_adsp_mbox_isr
irq_thread_fn
Freed by task ...:
kfree
devres_release_all
really_probe
... (sof-audio-of-mt8196 probe failure)
The crash was observed roughly three seconds after the failed probe.
disable_irq() in shutdown and enable_irq() in startup. disable_irq()
also waits for any in-flight interrupts, so by the time
mbox_free_channel() proceeds to clear chan->cl no rx_callback can run.
In addition, request the IRQ with IRQF_NO_AUTOEN so it stays masked
between probe and the first client bind — otherwise an early interrupt
can crash on chan->cl == NULL in mbox_chan_received_data().
Fixes: af2dfa96c52d ("mailbox: mediatek: add support for adsp mailbox controller")
Signed-off-by: Sergey Senozhatsky <senozhatsky@chromium.org>
---
drivers/mailbox/mtk-adsp-mailbox.c | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/drivers/mailbox/mtk-adsp-mailbox.c b/drivers/mailbox/mtk-adsp-mailbox.c
index 91487aa4d7da..8bcecddee0eb 100644
--- a/drivers/mailbox/mtk-adsp-mailbox.c
+++ b/drivers/mailbox/mtk-adsp-mailbox.c
@@ -19,6 +19,7 @@ struct mtk_adsp_mbox_priv {
struct mbox_controller mbox;
void __iomem *va_mboxreg;
const struct mtk_adsp_mbox_cfg *cfg;
+ int irq;
};
struct mtk_adsp_mbox_cfg {
@@ -67,6 +68,8 @@ static int mtk_adsp_mbox_startup(struct mbox_chan *chan)
writel(0xFFFFFFFF, priv->va_mboxreg + priv->cfg->clr_in);
writel(0xFFFFFFFF, priv->va_mboxreg + priv->cfg->clr_out);
+ enable_irq(priv->irq);
+
return 0;
}
@@ -74,6 +77,8 @@ static void mtk_adsp_mbox_shutdown(struct mbox_chan *chan)
{
struct mtk_adsp_mbox_priv *priv = get_mtk_adsp_mbox_priv(chan->mbox);
+ disable_irq(priv->irq);
+
/* Clear ADSP mbox command */
writel(0xFFFFFFFF, priv->va_mboxreg + priv->cfg->clr_in);
writel(0xFFFFFFFF, priv->va_mboxreg + priv->cfg->clr_out);
@@ -139,8 +144,10 @@ static int mtk_adsp_mbox_probe(struct platform_device *pdev)
if (irq < 0)
return irq;
+ priv->irq = irq;
ret = devm_request_threaded_irq(dev, irq, mtk_adsp_mbox_irq,
- mtk_adsp_mbox_isr, IRQF_TRIGGER_NONE,
+ mtk_adsp_mbox_isr,
+ IRQF_TRIGGER_NONE | IRQF_NO_AUTOEN,
dev_name(dev), mbox->chans);
if (ret < 0)
return ret;
--
2.54.0.545.g6539524ca2-goog
^ permalink raw reply related
* Re: [PATCH v8 1/4] coresight: cti: Convert trigger usage fields to dynamic bitmaps and arrays
From: Yingchao Deng (Consultant) @ 2026-04-28 2:25 UTC (permalink / raw)
To: Leo Yan, Yingchao Deng
Cc: Suzuki K Poulose, Mike Leach, James Clark, Alexander Shishkin,
coresight, linux-arm-kernel, linux-kernel, linux-arm-msm,
Jinlong Mao, Tingwei Zhang, Jie Gan
In-Reply-To: <20260427165913.GA16537@e132581.arm.com>
On 4/28/2026 12:59 AM, Leo Yan wrote:
> On Sun, Apr 26, 2026 at 05:44:38PM +0800, Yingchao Deng wrote:
>
> [...]
>
>> @@ -316,23 +316,33 @@ static int cti_plat_process_filter_sigs(struct cti_drvdata *drvdata,
>> {
>> struct cti_trig_grp *tg = NULL;
>> int err = 0, nr_filter_sigs;
>> + int nr_trigs = drvdata->config.nr_trig_max;
>>
>> nr_filter_sigs = cti_plat_count_sig_elements(fwnode,
>> CTI_DT_FILTER_OUT_SIGS);
>> if (nr_filter_sigs == 0)
>> return 0;
>>
>> - if (nr_filter_sigs > drvdata->config.nr_trig_max)
>> + if (nr_filter_sigs > nr_trigs)
>> return -EINVAL;
>>
>> tg = kzalloc_obj(*tg);
>> if (!tg)
>> return -ENOMEM;
>>
>> + tg->used_mask = bitmap_zalloc(nr_trigs, GFP_KERNEL);
> Here would be:
>
> tg->used_mask = bitmap_zalloc(nr_filter_sigs, GFP_KERNEL);
"nr_filter_sigs" is the count of entries in the DT property array, if
the DT property is:
arm,trig-filters = <22 23>;
Here nr_filter_sigs=2, so bitmap_zalloc(2) allocates only 1 unsigned long
(64 bits). set_bit(22/23, used_mask) still fits, but it's logically an
OOB, and any index >=64 would
write past the end.
>> + if (!tg->used_mask) {
>> + kfree(tg);
>> + return -ENOMEM;
>> + }
>> +
> It is likely this will have merge conflict with the new patch [1].
>
> You might need to rebase this patch on the top of [1]. We need to
> give [1] priority as it is a fix.
>
> [1] https://lore.kernel.org/linux-arm-kernel/20260426-nr_sigs-v1-1-3b9df99dab97@oss.qualcomm.com/
>
> Otherwise, LGTM:
>
> Reviewed-by: Leo Yan <leo.yan@arm.com>
Will update.
Thanks,
Yingchao
^ permalink raw reply
* RE: [PATCH] PCI: imx6: Keep Root Port MSI capability also for i.MX6Q
From: Hongxing Zhu @ 2026-04-28 2:19 UTC (permalink / raw)
To: Soeren Moch
Cc: stable@vger.kernel.org, Manivannan Sadhasivam, Lucas Stach,
Bjorn Helgaas, Frank Li, Fabio Estevam, linux-pci@vger.kernel.org,
linux-arm-kernel@lists.infradead.org, imx@lists.linux.dev,
linux-kernel@vger.kernel.org
In-Reply-To: <20260427115804.134231-1-smoch@web.de>
> -----Original Message-----
> From: Soeren Moch <smoch@web.de>
> Sent: Monday, April 27, 2026 7:58 PM
> To: Hongxing Zhu <hongxing.zhu@nxp.com>
> Cc: Soeren Moch <smoch@web.de>; stable@vger.kernel.org; Manivannan
> Sadhasivam <mani@kernel.org>; Lucas Stach <l.stach@pengutronix.de>; Bjorn
> Helgaas <bhelgaas@google.com>; Frank Li <frank.li@nxp.com>; Fabio Estevam
> <festevam@gmail.com>; linux-pci@vger.kernel.org; linux-arm-
> kernel@lists.infradead.org; imx@lists.linux.dev; linux-kernel@vger.kernel.org
> Subject: [PATCH] PCI: imx6: Keep Root Port MSI capability also for i.MX6Q
>
> [You don't often get email from smoch@web.de. Learn why this is important at
> https://aka.ms/LearnAboutSenderIdentification ]
>
> Also on the NXP i.MX6Q chipset MSIs from the endpoints won't be received by
> the iMSI-RX MSI controller if the Root Port MSI capability is disabled.
>
> Even though the Root Port MSIs won't be received by the iMSI-RX controller due
> to design, this chipset has some weird hardware bug that prevents the endpoint
> MSIs from reaching when the Root Port MSI capability is disabled.
>
> Hence, always keep the Root Port MSI capability for this chipset.
>
> Note that by keeping Root Port MSI capability, Root Port MSIs such as AER, PME
> and others won't be received by default. So users need to use workarounds such
> as passing 'pcie_pme=nomsi' cmdline param.
>
> Fixes: 3a4e8302e72f ("PCI: imx6: Keep Root Port MSI capability with iMSI-RX to
> work around hardware bug")
> Cc: <stable@vger.kernel.org> # 7.0.x
> Signed-off-by: Soeren Moch <smoch@web.de>
Acked-by: Richard Zhu <hongxing.zhu@nxp.com>
Best Regards
Richard Zhu
> ---
> Cc: Manivannan Sadhasivam <mani@kernel.org>
> Cc: Richard Zhu <hongxing.zhu@nxp.com>
> Cc: Lucas Stach <l.stach@pengutronix.de>
> Cc: Bjorn Helgaas <bhelgaas@google.com>
> Cc: Frank Li <Frank.Li@nxp.com>
> Cc: Fabio Estevam <festevam@gmail.com>
> Cc: linux-pci@vger.kernel.org
> Cc: linux-arm-kernel@lists.infradead.org
> Cc: imx@lists.linux.dev
> Cc: linux-kernel@vger.kernel.org
>
> Tested on a tbs2910 board [1]
> [1] arch/arm/boot/dts/nxp/imx/imx6q-tbs2910.dts
> ---
> drivers/pci/controller/dwc/pci-imx6.c | 3 ++-
> 1 file changed, 2 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/pci/controller/dwc/pci-imx6.c
> b/drivers/pci/controller/dwc/pci-imx6.c
> index 6d6a1688e7eb..3d461bdef967 100644
> --- a/drivers/pci/controller/dwc/pci-imx6.c
> +++ b/drivers/pci/controller/dwc/pci-imx6.c
> @@ -1865,7 +1865,8 @@ static const struct imx_pcie_drvdata drvdata[] = {
> .flags = IMX_PCIE_FLAG_IMX_PHY |
> IMX_PCIE_FLAG_SPEED_CHANGE_WORKAROUND |
> IMX_PCIE_FLAG_BROKEN_SUSPEND |
> - IMX_PCIE_FLAG_SUPPORTS_SUSPEND,
> + IMX_PCIE_FLAG_SUPPORTS_SUSPEND |
> + IMX_PCIE_FLAG_KEEP_MSI_CAP,
> .dbi_length = 0x200,
> .gpr = "fsl,imx6q-iomuxc-gpr",
> .ltssm_off = IOMUXC_GPR12,
> --
> 2.43.0
^ permalink raw reply
* Re: [PATCH v8 4/4] coresight: cti: expose banked sysfs registers for Qualcomm extended CTI
From: Yingchao Deng (Consultant) @ 2026-04-28 2:18 UTC (permalink / raw)
To: Leo Yan, Yingchao Deng
Cc: Suzuki K Poulose, Mike Leach, James Clark, Alexander Shishkin,
coresight, linux-arm-kernel, linux-kernel, linux-arm-msm,
Jinlong Mao, Tingwei Zhang, Jie Gan, Yingchao Deng
In-Reply-To: <20260427181557.GC16537@e132581.arm.com>
On 4/28/2026 2:15 AM, Leo Yan wrote:
> On Sun, Apr 26, 2026 at 05:44:41PM +0800, Yingchao Deng wrote:
>> Qualcomm extended CTI implements banked trigger status and integration
>> registers, where each bank covers 32 triggers. Multiple instances of
>> these registers are required to expose the full trigger space.
>>
>> Add static sysfs entries for the banked CTI registers and control their
>> visibility based on the underlying hardware configuration. Numbered
>> sysfs nodes are hidden on standard ARM CTIs, preserving the existing ABI.
>> On Qualcomm CTIs, only banked registers backed by hardware are exposed,
>> with the number of visible banks derived from nr_trig_max.
>>
>> This ensures that userspace only sees registers that are actually
>> implemented, while maintaining compatibility with existing CTI tooling.
>>
>> Signed-off-by: Yingchao Deng <yingchao.deng@oss.qualcomm.com>
>> ---
>> drivers/hwtracing/coresight/coresight-cti-sysfs.c | 58 +++++++++++++++++++++++
>> 1 file changed, 58 insertions(+)
>>
>> diff --git a/drivers/hwtracing/coresight/coresight-cti-sysfs.c b/drivers/hwtracing/coresight/coresight-cti-sysfs.c
>> index 8b70e7e38ea3..046757e4e9b6 100644
>> --- a/drivers/hwtracing/coresight/coresight-cti-sysfs.c
>> +++ b/drivers/hwtracing/coresight/coresight-cti-sysfs.c
>> @@ -512,18 +512,36 @@ static struct attribute *coresight_cti_regs_attrs[] = {
>> &dev_attr_appclear.attr,
>> &dev_attr_apppulse.attr,
>> coresight_cti_reg(triginstatus, CTITRIGINSTATUS),
>> + coresight_cti_reg(triginstatus1, CTI_REG_SET_NR_CONST(CTITRIGINSTATUS, 1)),
> How about extend the cs_off_attribute struct:
>
> struct cs_off_attribute {
> struct device_attribute attr;
> u32 off;
> u32 index;
> };
>
> // by default, the index is 0
> #define coresight_cti_reg(name, offset) \
> (&((struct cs_off_attribute[]) { \
> { \
> __ATTR(name, 0444, coresight_cti_reg_show, NULL), \
> offset \
> 0 \
> } \
> })[0].attr.attr)
>
> // For the register with index
> #define coresight_cti_reg_index(name, offset, index) \
> (&((struct cs_off_attribute[]) { \
> { \
> __ATTR(name, 0444, coresight_cti_reg_show, NULL), \
> offset \
> index \
> } \
> })[0].attr.attr)
>
> coresight_cti_reg_index(triginstatus1, CTITRIGINSTATUS, 1),
>
>> + coresight_cti_reg(triginstatus2, CTI_REG_SET_NR_CONST(CTITRIGINSTATUS, 2)),
>> + coresight_cti_reg(triginstatus3, CTI_REG_SET_NR_CONST(CTITRIGINSTATUS, 3)),
>> coresight_cti_reg(trigoutstatus, CTITRIGOUTSTATUS),
>> + coresight_cti_reg(trigoutstatus1, CTI_REG_SET_NR_CONST(CTITRIGOUTSTATUS, 1)),
>> + coresight_cti_reg(trigoutstatus2, CTI_REG_SET_NR_CONST(CTITRIGOUTSTATUS, 2)),
>> + coresight_cti_reg(trigoutstatus3, CTI_REG_SET_NR_CONST(CTITRIGOUTSTATUS, 3)),
>> coresight_cti_reg(chinstatus, CTICHINSTATUS),
>> coresight_cti_reg(choutstatus, CTICHOUTSTATUS),
>> #ifdef CONFIG_CORESIGHT_CTI_INTEGRATION_REGS
>> coresight_cti_reg_rw(itctrl, CORESIGHT_ITCTRL),
>> coresight_cti_reg(ittrigin, ITTRIGIN),
>> + coresight_cti_reg(ittrigin1, CTI_REG_SET_NR_CONST(ITTRIGIN, 1)),
>> + coresight_cti_reg(ittrigin2, CTI_REG_SET_NR_CONST(ITTRIGIN, 2)),
>> + coresight_cti_reg(ittrigin3, CTI_REG_SET_NR_CONST(ITTRIGIN, 3)),
>> coresight_cti_reg(itchin, ITCHIN),
>> coresight_cti_reg_rw(ittrigout, ITTRIGOUT),
>> + coresight_cti_reg_rw(ittrigout1, CTI_REG_SET_NR_CONST(ITTRIGOUT, 1)),
>> + coresight_cti_reg_rw(ittrigout2, CTI_REG_SET_NR_CONST(ITTRIGOUT, 2)),
>> + coresight_cti_reg_rw(ittrigout3, CTI_REG_SET_NR_CONST(ITTRIGOUT, 3)),
>> coresight_cti_reg_rw(itchout, ITCHOUT),
>> coresight_cti_reg(itchoutack, ITCHOUTACK),
>> coresight_cti_reg(ittrigoutack, ITTRIGOUTACK),
>> + coresight_cti_reg(ittrigoutack1, CTI_REG_SET_NR_CONST(ITTRIGOUTACK, 1)),
>> + coresight_cti_reg(ittrigoutack2, CTI_REG_SET_NR_CONST(ITTRIGOUTACK, 2)),
>> + coresight_cti_reg(ittrigoutack3, CTI_REG_SET_NR_CONST(ITTRIGOUTACK, 3)),
>> coresight_cti_reg_wo(ittriginack, ITTRIGINACK),
>> + coresight_cti_reg_wo(ittriginack1, CTI_REG_SET_NR_CONST(ITTRIGINACK, 1)),
>> + coresight_cti_reg_wo(ittriginack2, CTI_REG_SET_NR_CONST(ITTRIGINACK, 2)),
>> + coresight_cti_reg_wo(ittriginack3, CTI_REG_SET_NR_CONST(ITTRIGINACK, 3)),
>> coresight_cti_reg_wo(itchinack, ITCHINACK),
>> #endif
>> NULL,
>> @@ -534,10 +552,50 @@ static umode_t coresight_cti_regs_is_visible(struct kobject *kobj,
>> {
>> struct device *dev = kobj_to_dev(kobj);
>> struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
>> + static const char * const qcom_suffix_registers[] = {
>> + "triginstatus",
>> + "trigoutstatus",
>> +#ifdef CONFIG_CORESIGHT_CTI_INTEGRATION_REGS
>> + "ittrigin",
>> + "ittrigout",
>> + "ittriginack",
>> + "ittrigoutack",
>> +#endif
>> + };
>> + int i, nr, max_bank;
>> + size_t len;
>>
>> if (attr == &dev_attr_asicctl.attr && !drvdata->config.asicctl_impl)
>> return 0;
>>
>> + /*
>> + * Banked regs are exposed as <qcom_suffix_registers><nr> (nr = 1..3).
>> + * - Hide them on standard CTIs.
>> + * - On QCOM CTIs, hide suffixes beyond the number of banks implied
>> + * by nr_trig_max (32 triggers per bank).
>> + */
>> + for (i = 0; i < ARRAY_SIZE(qcom_suffix_registers); i++) {
> This can be general for a register with index? Like:
>
> for (i = 0; i < ARRAY_SIZE(registers_with_index); i++) {
>
>> + len = strlen(qcom_suffix_registers[i]);
>> +
>> + if (strncmp(attr->name, qcom_suffix_registers[i], len))
>> + continue;
>> +
>> + if (kstrtoint(attr->name + len, 10, &nr))
>> + continue;
>> +
>> + if (!drvdata->is_qcom_cti)
>> + return 0;
>> +
>> + if (nr < 1 || nr > 3)
>> + return 0;
>> +
>> + max_bank = DIV_ROUND_UP(drvdata->config.nr_trig_max, 32) - 1;
>> + if (nr > max_bank)
>> + return 0;
> Directly check the attr's index here?
>
> struct cs_off_attribute *cti_attr =
> container_of(attr, struct cs_off_attribute, attr);
>
> max_bank = DIV_ROUND_UP(drvdata->config.nr_trig_max, 32);
> if (cti_attr->index >= max_bank)
> return 0;
>
> Thanks,
> Leo
Will update.
Thanks,
Yingchao
^ permalink raw reply
* Re: [PATCH v8 2/4] coresight: cti: encode trigger register index in register offsets
From: Yingchao Deng (Consultant) @ 2026-04-28 2:16 UTC (permalink / raw)
To: Leo Yan, Yingchao Deng
Cc: Suzuki K Poulose, Mike Leach, James Clark, Alexander Shishkin,
coresight, linux-arm-kernel, linux-kernel, linux-arm-msm,
Jinlong Mao, Tingwei Zhang, Jie Gan, Yingchao Deng
In-Reply-To: <20260427174800.GB16537@e132581.arm.com>
On 4/28/2026 1:48 AM, Leo Yan wrote:
> On Sun, Apr 26, 2026 at 05:44:39PM +0800, Yingchao Deng wrote:
>> Introduce a small encoding to carry the register index together with the
>> base offset in a single u32, and use a common helper to compute the final
>> MMIO address. This refactors register access to be based on the encoded
>> (reg, nr) pair, reducing duplicated arithmetic and making it easier to
>> support variants that bank or relocate trigger-indexed registers.
>>
>> Signed-off-by: Yingchao Deng <yingchao.deng@oss.qualcomm.com>
>> ---
>> drivers/hwtracing/coresight/coresight-cti-core.c | 31 +++++++++++++++--------
>> drivers/hwtracing/coresight/coresight-cti-sysfs.c | 4 +--
>> drivers/hwtracing/coresight/coresight-cti.h | 16 ++++++++++--
>> 3 files changed, 36 insertions(+), 15 deletions(-)
>>
>> diff --git a/drivers/hwtracing/coresight/coresight-cti-core.c b/drivers/hwtracing/coresight/coresight-cti-core.c
>> index 4e7d12bd2d3e..c4cbeb64365b 100644
>> --- a/drivers/hwtracing/coresight/coresight-cti-core.c
>> +++ b/drivers/hwtracing/coresight/coresight-cti-core.c
>> @@ -42,6 +42,14 @@ static DEFINE_MUTEX(ect_mutex);
>> #define csdev_to_cti_drvdata(csdev) \
>> dev_get_drvdata(csdev->dev.parent)
>>
>> +static void __iomem *cti_reg_addr(struct cti_drvdata *drvdata, int reg)
>> +{
>> + u32 offset = CTI_REG_CLR_NR(reg);
>> + u32 nr = CTI_REG_GET_NR(reg);
>> +
>> + return drvdata->base + offset + sizeof(u32) * nr;
>> +}
> Could you try below change, which is more straightforward?
>
> static void __iomem *__reg_addr(struct cti_drvdata *drvdata, int off,
> int index)
> {
> return drvdata->base + offset + sizeof(u32) * index;
> }
>
> #define reg_addr(drvdata, off) \
> __reg_addr((drvdata), (off), 0)
>
> #define reg_index_addr(drvdata, off, i) \
> __reg_addr((drvdata), (off), (i))
>
>> +
>> /* write set of regs to hardware - call with spinlock claimed */
>> void cti_write_all_hw_regs(struct cti_drvdata *drvdata)
>> {
>> @@ -55,16 +63,17 @@ void cti_write_all_hw_regs(struct cti_drvdata *drvdata)
>>
>> /* write the CTI trigger registers */
>> for (i = 0; i < config->nr_trig_max; i++) {
>> - writel_relaxed(config->ctiinen[i], drvdata->base + CTIINEN(i));
>> + writel_relaxed(config->ctiinen[i],
>> + cti_reg_addr(drvdata, CTI_REG_SET_NR(CTIINEN, i)));
> writel_relaxed(config->ctiinen[i],
> reg_index_addr(drvdata, CTIINEN, i));
>
>> writel_relaxed(config->ctiouten[i],
>> - drvdata->base + CTIOUTEN(i));
>> + cti_reg_addr(drvdata, CTI_REG_SET_NR(CTIOUTEN, i)));
> writel_relaxed(config->ctiouten[i],
> reg_index_addr(drvdata, CTIOUTEN, i));
>
> [...]
Will try.
Thanks,
Yingchao
>> +/*
>> + * Encode CTI register offset and register index in one u32:
>> + * - bits[0:11] : base register offset (0x000 to 0xFFF)
>> + * - bits[24:31] : register index (nr)
>> + */
>> +#define CTI_REG_NR_MASK GENMASK(31, 24)
>> +#define CTI_REG_GET_NR(reg) FIELD_GET(CTI_REG_NR_MASK, (reg))
>> +#define CTI_REG_SET_NR_CONST(reg, nr) ((reg) | FIELD_PREP_CONST(CTI_REG_NR_MASK, (nr)))
>> +#define CTI_REG_SET_NR(reg, nr) ((reg) | FIELD_PREP(CTI_REG_NR_MASK, (nr)))
>> +#define CTI_REG_CLR_NR(reg) ((reg) & (~CTI_REG_NR_MASK))
> I know this might come from my suggestion, and it is also will be
> heavily used in patch 04. We can have strightforward way to
> implement this, please drop these macros.
>
> I will reply in patch 04 separately. Sorry my review might cause
> extra effort.
>
> Thanks,
> Leo
^ permalink raw reply
* Re: [PATCH net v3] net: dsa: mt7530: fix .get_stats64 sleeping in atomic context
From: Jakub Kicinski @ 2026-04-28 1:59 UTC (permalink / raw)
To: daniel
Cc: Jakub Kicinski, chester.a.unal, andrew, olteanv, davem, edumazet,
pabeni, matthias.bgg, angelogioacchino.delregno, linux,
ansuelsmth, netdev, linux-kernel, linux-arm-kernel,
linux-mediatek
In-Reply-To: <8c407b36d8a597c1449ff9335dfdc250d76311c3.1777034225.git.daniel@makrotopia.org>
This is an AI-generated review of your patch. The human sending this
email has considered the AI review valid, or at least plausible.
---
net: dsa: mt7530: fix .get_stats64 sleeping in atomic context
This change converts MDIO-connected mt7530 switches to poll MIB counters
via a delayed workqueue and have .get_stats64 return cached values under
a spinlock, avoiding a sleeping-in-atomic-context issue. MMIO-connected
variants continue to read directly.
> diff --git a/drivers/net/dsa/mt7530.c b/drivers/net/dsa/mt7530.c
> index b9423389c2ef..9733ff9fc322 100644
> --- a/drivers/net/dsa/mt7530.c
> +++ b/drivers/net/dsa/mt7530.c
[ ... ]
> +static void mt7530_stats_poll(struct work_struct *work)
> +{
> + struct mt7530_priv *priv = container_of(work, struct mt7530_priv,
> + stats_work.work);
> + struct rtnl_link_stats64 stats = {};
> + struct dsa_port *dp;
> + int port;
> +
> + dsa_switch_for_each_user_port(dp, priv->ds) {
> + port = dp->index;
> +
> + mt7530_read_port_stats64(priv, port, &stats);
> +
> + spin_lock_bh(&priv->stats_lock);
> + priv->ports[port].stats = stats;
> + priv->stats_last = jiffies;
> + spin_unlock_bh(&priv->stats_lock);
> + }
> +
> + schedule_delayed_work(&priv->stats_work,
> + MT7530_STATS_POLL_INTERVAL);
> +}
> +
> +static void mt7530_get_stats64(struct dsa_switch *ds, int port,
> + struct rtnl_link_stats64 *storage)
> +{
> + struct mt7530_priv *priv = ds->priv;
> + bool refresh;
> +
> + if (priv->bus) {
> + spin_lock_bh(&priv->stats_lock);
> + *storage = priv->ports[port].stats;
> + refresh = time_after(jiffies, priv->stats_last +
> + MT7530_STATS_RATE_LIMIT);
> + spin_unlock_bh(&priv->stats_lock);
> + if (refresh)
> + mod_delayed_work(system_wq, &priv->stats_work, 0);
^^^^^^^^^
Is the target workqueue here intentional? The re-arm path at the end of
mt7530_stats_poll() and the initial arming in mt753x_setup() both go
through schedule_delayed_work(), which expands to:
queue_delayed_work(system_percpu_wq, dwork, delay)
whereas this site passes system_wq. Those are two distinct workqueue
allocations in kernel/workqueue.c, so each on-demand refresh moves the
delayed_work between the two queues.
include/linux/workqueue.h also marks system_wq as deprecated:
/* Please use system_percpu_wq, this will be removed */
extern struct workqueue_struct *system_wq;
Should this call use system_percpu_wq (or mod_delayed_work on the same
queue that schedule_delayed_work() targets) to keep the work on a single
workqueue and avoid the deprecated symbol?
> + } else {
> + mt7530_read_port_stats64(priv, port, storage);
> + }
> +}
> +
[ ... ]
> @@ -3137,9 +3181,24 @@ mt753x_setup(struct dsa_switch *ds)
> if (ret && priv->irq_domain)
> mt7530_free_mdio_irq(priv);
>
> + if (!ret && priv->bus) {
> + spin_lock_init(&priv->stats_lock);
> + INIT_DELAYED_WORK(&priv->stats_work, mt7530_stats_poll);
> + schedule_delayed_work(&priv->stats_work,
> + MT7530_STATS_POLL_INTERVAL);
> + }
> +
> return ret;
> }
How does .get_stats64 behave during the first MT7530_STATS_POLL_INTERVAL
(1 * HZ) after setup?
priv->ports[port].stats and priv->stats_last come from the devm_kzalloc
allocation in mt7530_probe_common(), so both are zero. The first poll
is scheduled with a delay of MT7530_STATS_POLL_INTERVAL, so any reader
during that first second sees:
spin_lock_bh(&priv->stats_lock);
*storage = priv->ports[port].stats; /* all zero */
refresh = time_after(jiffies, priv->stats_last +
MT7530_STATS_RATE_LIMIT);
spin_unlock_bh(&priv->stats_lock);
Can the on-demand refresh path help here? time_after() is defined as:
#define time_after(a,b) \
(typecheck(unsigned long, a) && \
typecheck(unsigned long, b) && \
((long)((b) - (a)) < 0))
On 32-bit, jiffies starts at INITIAL_JIFFIES = (unsigned long)(unsigned
int)(-300*HZ), which is close to ULONG_MAX. With stats_last == 0, the
signed difference check can evaluate to false for a long time, so the
mod_delayed_work() refresh is suppressed until the first scheduled poll
updates stats_last.
Would seeding priv->stats_last = jiffies at init, and either populating
the cache synchronously in mt753x_setup() or scheduling the first poll
with delay 0, avoid returning zeroed counters and the suppressed
on-demand refresh during the initial window?
--
pw-bot: cr
^ permalink raw reply
* Re: [PATCH v5 10/10] drm/rockchip: dw_hdmi_qp: Restrict HPD event to the affected connector
From: Dmitry Baryshkov @ 2026-04-28 1:53 UTC (permalink / raw)
To: Cristian Ciocaltea
Cc: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, David Airlie, Simona Vetter, Sandy Huang,
Heiko Stübner, Andy Yan, kernel, dri-devel, linux-kernel,
linux-arm-kernel, linux-rockchip, Diederik de Haas,
Maud Spierings
In-Reply-To: <20260426-dw-hdmi-qp-scramb-v5-10-d778e70c317b@collabora.com>
On Sun, Apr 26, 2026 at 03:20:22AM +0300, Cristian Ciocaltea wrote:
> Switch from drm_helper_hpd_irq_event(), which polls all connectors, to
> drm_connector_helper_hpd_irq_event(), which runs the detect cycle only
> on the affected connector.
>
> This avoids unnecessary work and redundant detect calls on unrelated
> connectors.
This also doesn't feel correct. The dw_hdmi_qp is a bridge. As such it
should be using drm_bridge_hpd_notify() rather than any of the mentioned
functions. Would it be better to add the a corresponding wrapper to the
dw_hdmi_qp API and call one there? Also consider implementing the
.hpd_enable() and .hpd_disable() callbacks for the bridge, which would
remove the necessity to call enable the IRQ in the bind function.
>
> Tested-by: Diederik de Haas <diederik@cknow-tech.com>
> Tested-by: Maud Spierings <maud_spierings@hotmail.com>
> Reviewed-by: Heiko Stuebner <heiko@sntech.de>
> Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
> ---
> drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c | 21 +++++++++++----------
> 1 file changed, 11 insertions(+), 10 deletions(-)
>
--
With best wishes
Dmitry
^ permalink raw reply
* Re: [PATCH v5 09/10] drm/rockchip: dw_hdmi_qp: Register HPD IRQ after connector setup
From: Dmitry Baryshkov @ 2026-04-28 1:41 UTC (permalink / raw)
To: Cristian Ciocaltea
Cc: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, David Airlie, Simona Vetter, Sandy Huang,
Heiko Stübner, Andy Yan, kernel, dri-devel, linux-kernel,
linux-arm-kernel, linux-rockchip, Diederik de Haas,
Maud Spierings
In-Reply-To: <20260426-dw-hdmi-qp-scramb-v5-9-d778e70c317b@collabora.com>
On Sun, Apr 26, 2026 at 03:20:21AM +0300, Cristian Ciocaltea wrote:
> Move devm_request_threaded_irq() to the end of bind(), after
> drm_bridge_connector_init() and drm_connector_attach_encoder(), to
> ensure all DRM resources are ready before HPD interrupts can fire.
>
> While at it, add error handling for drm_connector_attach_encoder().
>
> Tested-by: Diederik de Haas <diederik@cknow-tech.com>
> Tested-by: Maud Spierings <maud_spierings@hotmail.com>
> Reviewed-by: Heiko Stuebner <heiko@sntech.de>
> Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
> ---
> drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c | 18 +++++++++---------
> 1 file changed, 9 insertions(+), 9 deletions(-)
>
> diff --git a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
> index 618d2aaa5c7d..fbbe26f8730c 100644
> --- a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
> +++ b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
> @@ -577,14 +577,6 @@ static int dw_hdmi_qp_rockchip_bind(struct device *dev, struct device *master,
> if (irq < 0)
> return irq;
>
> - ret = devm_request_threaded_irq(dev, irq,
> - cfg->ctrl_ops->hardirq_callback,
> - cfg->ctrl_ops->irq_callback,
> - IRQF_SHARED, "dw-hdmi-qp-hpd",
> - hdmi);
> - if (ret)
> - return ret;
> -
> drm_encoder_helper_add(encoder, &dw_hdmi_qp_rockchip_encoder_helper_funcs);
> ret = drmm_encoder_init(drm, encoder, NULL, DRM_MODE_ENCODER_TMDS, NULL);
> if (ret)
> @@ -602,7 +594,15 @@ static int dw_hdmi_qp_rockchip_bind(struct device *dev, struct device *master,
> return dev_err_probe(dev, PTR_ERR(connector),
> "Failed to init bridge connector\n");
>
> - return drm_connector_attach_encoder(connector, encoder);
> + ret = drm_connector_attach_encoder(connector, encoder);
> + if (ret)
> + return dev_err_probe(dev, ret, "Failed to attach connector\n");
> +
> + return devm_request_threaded_irq(dev, irq,
> + cfg->ctrl_ops->hardirq_callback,
> + cfg->ctrl_ops->irq_callback,
> + IRQF_SHARED, "dw-hdmi-qp-hpd",
> + hdmi);
And if requesting of the IRQ fails, you have a lot to unwind. It might
be better to request IRQ early enough with the IRQF_NO_AUTOEN flag and
then enable_irq() here.
> }
>
> static void dw_hdmi_qp_rockchip_unbind(struct device *dev,
>
> --
> 2.53.0
>
>
> _______________________________________________
> Linux-rockchip mailing list
> Linux-rockchip@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-rockchip
--
With best wishes
Dmitry
^ permalink raw reply
* Re: [PATCH v5 07/10] drm/rockchip: dw_hdmi_qp: Add missing newlines in dev_err_probe() messages
From: Dmitry Baryshkov @ 2026-04-28 1:40 UTC (permalink / raw)
To: Cristian Ciocaltea
Cc: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, David Airlie, Simona Vetter, Sandy Huang,
Heiko Stübner, Andy Yan, kernel, dri-devel, linux-kernel,
linux-arm-kernel, linux-rockchip
In-Reply-To: <20260426-dw-hdmi-qp-scramb-v5-7-d778e70c317b@collabora.com>
On Sun, Apr 26, 2026 at 03:20:19AM +0300, Cristian Ciocaltea wrote:
> Add the missing trailing newlines to a couple of dev_err_probe() calls
> in dw_hdmi_qp_rockchip_bind().
>
> Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
> ---
> drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c | 4 ++--
> 1 file changed, 2 insertions(+), 2 deletions(-)
Missing Fixes tag.
>
> diff --git a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
> index c78db7f8ab6c..d9333ad8996b 100644
> --- a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
> +++ b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
> @@ -589,14 +589,14 @@ static int dw_hdmi_qp_rockchip_bind(struct device *dev, struct device *master,
> drm_encoder_helper_add(encoder, &dw_hdmi_qp_rockchip_encoder_helper_funcs);
> ret = drmm_encoder_init(drm, encoder, NULL, DRM_MODE_ENCODER_TMDS, NULL);
> if (ret)
> - return dev_err_probe(hdmi->dev, ret, "Failed to init encoder");
> + return dev_err_probe(hdmi->dev, ret, "Failed to init encoder\n");
>
> platform_set_drvdata(pdev, hdmi);
>
> hdmi->hdmi = dw_hdmi_qp_bind(pdev, encoder, &plat_data);
> if (IS_ERR(hdmi->hdmi))
> return dev_err_probe(hdmi->dev, PTR_ERR(hdmi->hdmi),
> - "Failed to bind dw-hdmi-qp");
> + "Failed to bind dw-hdmi-qp\n");
>
> connector = drm_bridge_connector_init(drm, encoder);
> if (IS_ERR(connector))
>
> --
> 2.53.0
>
--
With best wishes
Dmitry
^ permalink raw reply
* Re: [PATCH] arm64/entry: Fix arm64-specific rseq brokenness
From: Jinjie Ruan @ 2026-04-28 1:39 UTC (permalink / raw)
To: Mark Rutland, Mathias Stearn, Linus Torvalds, Catalin Marinas,
Will Deacon, Thomas Gleixner, Mathieu Desnoyers, Peter Zijlstra
Cc: Boqun Feng, Paul E. McKenney, Chris Kennelly, Dmitry Vyukov,
regressions, linux-kernel, linux-arm-kernel, Ingo Molnar,
Blake Oler
In-Reply-To: <aeueE1I1OuVkOcEZ@J2N7QTR9R3>
On 4/25/2026 12:45 AM, Mark Rutland wrote:
> Patch for the arm64-specific issue below. This doesn't fix the generic
> cpu_id_start issue, but it brings arm64 into line with everyone else,
> and it's the shape we'll need going forwards for other stuff anyway.
>
> I've given it light testing with Mathias's reproducer and the
> kselftests, which all pass.
>
> I've also pushed it to my arm64/rseq branch:
>
> https://git.kernel.org/pub/scm/linux/kernel/git/mark/linux.git/log/?h=arm64/rseq
>
> Mark.
>
> ---->8----
> From 79b65cbbfa20aa2cb0bc248591fab5459cdc101b Mon Sep 17 00:00:00 2001
> From: Mark Rutland <mark.rutland@arm.com>
> Date: Thu, 23 Apr 2026 16:51:12 +0100
> Subject: [PATCH] arm64/entry: Fix arm64-specific rseq brokenness
>
> Mathias Stearn reports that since v6.19, there are two big issues
> affecting rseq:
>
> (1) On arm64 specifically, rseq critical sections aren't aborted when
> they should be.
>
> (2) The 'cpu_id_start' field is no longer written by the kernel in all
> cases it used to be, including some cases where TCMalloc depends on
> the kernel clobbering the field.
>
> This patch fixes issue #1. This patch DOES NOT fix issue #2, which will
> need to be addressed by other patches.
>
> The arm64-specific brokenness is a result of commits:
>
> 2fc0e4b4126c ("rseq: Record interrupt from user space")
> 39a167560a61 ("rseq: Optimize event setting")
>
> The first commit failed to add a call to rseq_note_user_irq_entry() on
> arm64. Thus arm64 never sets rseq_event::user_irq to record that it may
> be necessary to abort an active rseq critical section upon return to
> userspace. On its own, this commit had no functional impact as the value
> of rseq_event::user_irq was not consumed.
>
> The second commit relied upon rseq_event::user_irq to determine whether
> or not to bother to perform rseq work when returning to userspace. As
> rseq_event::user_irq wasn't set on arm64, this work would be skipped,
> and consequently an active rseq critical section would not be aborted.
>
> Fix this by giving arm64 syscall-specific entry/exit paths, and
> performing the relevant logic in syscall and non-syscall paths,
> including calling rseq_note_user_irq_entry() for non-syscall entry.
>
> Currently arm64 cannot use syscall_enter_from_user_mode(),
> syscall_exit_to_user_mode(), and irqentry_exit_to_user_mode(), due to
> ordering constraints with exception masking, and risk of ABI breakage
> for syscall tracing/audit/etc. For the moment the entry/exit logic is
> left as arm64-specific, but mirroring the generic code.
>
> I intend to follow up with refactoring/cleanup, as we did for kernel
> mode entry paths in commit:
>
> 041aa7a85390 ("entry: Split preemption from irqentry_exit_to_kernel_mode()")
>
> ... which will allow arm64 to use the GENERIC_IRQ_ENTRY functions directly.
>
> Fixes: 39a167560a61 ("rseq: Optimize event setting")
> Reported-by: Mathias Stearn <mathias@mongodb.com>
> Link: https://lore.kernel.org/regressions/CAHnCjA25b+nO2n5CeifknSKHssJpPrjnf+dtr7UgzRw4Zgu=oA@mail.gmail.com/
> Signed-off-by: Mark Rutland <mark.rutland@arm.com>
> Cc: Catalin Marinas <catalin.marinas@arm.com>
> Cc: Chris Kennelly <ckennelly@google.com>
> Cc: Dmitry Vyukov <dvyukov@google.com>
> Cc: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
> Cc: Peter Zijlstra <peterz@infradead.org>
> Cc: Thomas Gleixner <tglx@linutronix.de>
> Cc: Will Deacon <will@kernel.org>
> ---
> arch/arm64/kernel/entry-common.c | 29 ++++++++++++++++++++++-------
> include/linux/irq-entry-common.h | 8 --------
> include/linux/rseq_entry.h | 19 -------------------
> 3 files changed, 22 insertions(+), 34 deletions(-)
>
> diff --git a/arch/arm64/kernel/entry-common.c b/arch/arm64/kernel/entry-common.c
> index cb54335465f66..65ade1f1544f6 100644
> --- a/arch/arm64/kernel/entry-common.c
> +++ b/arch/arm64/kernel/entry-common.c
> @@ -62,6 +62,12 @@ static void noinstr arm64_exit_to_kernel_mode(struct pt_regs *regs,
> irqentry_exit_to_kernel_mode_after_preempt(regs, state);
> }
>
> +static __always_inline void arm64_syscall_enter_from_user_mode(struct pt_regs *regs)
> +{
> + enter_from_user_mode(regs);
> + mte_disable_tco_entry(current);
Did we skip sme_enter/exit_from_user_mode() on the syscall path on
purpose? Not very familiar with ARM64 SME.
> +}
> +
> /*
> * Handle IRQ/context state management when entering from user mode.
> * Before this function is called it is not safe to call regular kernel code,
> @@ -70,20 +76,29 @@ static void noinstr arm64_exit_to_kernel_mode(struct pt_regs *regs,
> static __always_inline void arm64_enter_from_user_mode(struct pt_regs *regs)
> {
> enter_from_user_mode(regs);
> + rseq_note_user_irq_entry();
Can we just use irqentry_enter_from_user_mode() instead?
> mte_disable_tco_entry(current);
> sme_enter_from_user_mode();
> }
>
> +static __always_inline void arm64_syscall_exit_to_user_mode(struct pt_regs *regs)
> +{
> + local_irq_disable();
> + syscall_exit_to_user_mode_prepare(regs);
> + local_daif_mask();
> + mte_check_tfsr_exit();
> + exit_to_user_mode();
> +}
> +
> /*
> * Handle IRQ/context state management when exiting to user mode.
> * After this function returns it is not safe to call regular kernel code,
> * instrumentable code, or any code which may trigger an exception.
> */
> -
> static __always_inline void arm64_exit_to_user_mode(struct pt_regs *regs)
> {
> local_irq_disable();
> - exit_to_user_mode_prepare_legacy(regs);
> + irqentry_exit_to_user_mode_prepare(regs);
> local_daif_mask();
> sme_exit_to_user_mode();
> mte_check_tfsr_exit();
> @@ -92,7 +107,7 @@ static __always_inline void arm64_exit_to_user_mode(struct pt_regs *regs)
>
> asmlinkage void noinstr asm_exit_to_user_mode(struct pt_regs *regs)
> {
> - arm64_exit_to_user_mode(regs);
> + arm64_syscall_exit_to_user_mode(regs);
> }
>
> /*
> @@ -716,12 +731,12 @@ static void noinstr el0_brk64(struct pt_regs *regs, unsigned long esr)
>
> static void noinstr el0_svc(struct pt_regs *regs)
> {
> - arm64_enter_from_user_mode(regs);
> + arm64_syscall_enter_from_user_mode(regs);
> cortex_a76_erratum_1463225_svc_handler();
> fpsimd_syscall_enter();
> local_daif_restore(DAIF_PROCCTX);
> do_el0_svc(regs);
> - arm64_exit_to_user_mode(regs);
> + arm64_syscall_exit_to_user_mode(regs);
> fpsimd_syscall_exit();
> }
>
> @@ -868,11 +883,11 @@ static void noinstr el0_cp15(struct pt_regs *regs, unsigned long esr)
>
> static void noinstr el0_svc_compat(struct pt_regs *regs)
> {
> - arm64_enter_from_user_mode(regs);
> + arm64_syscall_enter_from_user_mode(regs);
> cortex_a76_erratum_1463225_svc_handler();
> local_daif_restore(DAIF_PROCCTX);
> do_el0_svc_compat(regs);
> - arm64_exit_to_user_mode(regs);
> + arm64_syscall_exit_to_user_mode(regs);
> }
Otherwise, looks fine to me.
>
> static void noinstr el0_bkpt32(struct pt_regs *regs, unsigned long esr)
> diff --git a/include/linux/irq-entry-common.h b/include/linux/irq-entry-common.h
> index 167fba7dbf043..1fabf0f5ea8e7 100644
> --- a/include/linux/irq-entry-common.h
> +++ b/include/linux/irq-entry-common.h
> @@ -218,14 +218,6 @@ static __always_inline void __exit_to_user_mode_validate(void)
> lockdep_sys_exit();
> }
>
> -/* Temporary workaround to keep ARM64 alive */
> -static __always_inline void exit_to_user_mode_prepare_legacy(struct pt_regs *regs)
> -{
> - __exit_to_user_mode_prepare(regs, EXIT_TO_USER_MODE_WORK);
> - rseq_exit_to_user_mode_legacy();
> - __exit_to_user_mode_validate();
> -}
> -
> /**
> * syscall_exit_to_user_mode_prepare - call exit_to_user_mode_loop() if required
> * @regs: Pointer to pt_regs on entry stack
> diff --git a/include/linux/rseq_entry.h b/include/linux/rseq_entry.h
> index f11ebd34f8b95..a3762410c4ab6 100644
> --- a/include/linux/rseq_entry.h
> +++ b/include/linux/rseq_entry.h
> @@ -753,24 +753,6 @@ static __always_inline void rseq_irqentry_exit_to_user_mode(void)
> ev->events = 0;
> }
>
> -/* Required to keep ARM64 working */
> -static __always_inline void rseq_exit_to_user_mode_legacy(void)
> -{
> - struct rseq_event *ev = ¤t->rseq.event;
> -
> - rseq_stat_inc(rseq_stats.exit);
> -
> - if (static_branch_unlikely(&rseq_debug_enabled))
> - WARN_ON_ONCE(ev->sched_switch);
> -
> - /*
> - * Ensure that event (especially user_irq) is cleared when the
> - * interrupt did not result in a schedule and therefore the
> - * rseq processing did not clear it.
> - */
> - ev->events = 0;
> -}
> -
> void __rseq_debug_syscall_return(struct pt_regs *regs);
>
> static __always_inline void rseq_debug_syscall_return(struct pt_regs *regs)
> @@ -786,7 +768,6 @@ static inline bool rseq_exit_to_user_mode_restart(struct pt_regs *regs, unsigned
> }
> static inline void rseq_syscall_exit_to_user_mode(void) { }
> static inline void rseq_irqentry_exit_to_user_mode(void) { }
> -static inline void rseq_exit_to_user_mode_legacy(void) { }
> static inline void rseq_debug_syscall_return(struct pt_regs *regs) { }
> static inline bool rseq_grant_slice_extension(unsigned long ti_work, unsigned long mask) { return false; }
> #endif /* !CONFIG_RSEQ */
^ permalink raw reply
* Re: [PATCH v5 05/10] drm/bridge: dw-hdmi-qp: Add HDMI 2.0 SCDC scrambling and high TMDS clock ratio support
From: Dmitry Baryshkov @ 2026-04-28 1:38 UTC (permalink / raw)
To: Cristian Ciocaltea
Cc: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, David Airlie, Simona Vetter, Sandy Huang,
Heiko Stübner, Andy Yan, kernel, dri-devel, linux-kernel,
linux-arm-kernel, linux-rockchip, Diederik de Haas,
Maud Spierings
In-Reply-To: <20260426-dw-hdmi-qp-scramb-v5-5-d778e70c317b@collabora.com>
On Sun, Apr 26, 2026 at 03:20:17AM +0300, Cristian Ciocaltea wrote:
> Enable HDMI 2.0 display modes (e.g. 4K@60Hz) by adding SCDC management
> for the high TMDS clock ratio and scrambling, required when the TMDS
> character rate exceeds the 340 MHz HDMI 1.4b limit.
>
> A periodic work item monitors the sink's scrambling status to recover
> from sink-side resets. On hotplug detect, if SCDC scrambling state is
> out of sync with the driver, trigger a CRTC reset to re-establish the
> link.
>
> Reject modes requiring TMDS rates above 600 MHz, as those fall in the
> HDMI 2.1 FRL domain which is not supported. In no_hpd configurations,
> further restrict to 340 MHz since SCDC requires a connected sink.
>
> Tested-by: Diederik de Haas <diederik@cknow-tech.com>
> Tested-by: Maud Spierings <maud_spierings@hotmail.com>
> Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
> ---
> drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c | 188 ++++++++++++++++++++++++---
> 1 file changed, 172 insertions(+), 16 deletions(-)
My main issue with this patch (sorry) is that this adds yet another copy
of SCDC-related helpers into the driver which already OP_HDMI and other
helpers.
> @@ -39,7 +42,9 @@
> #define DDC_SEGMENT_ADDR 0x30
>
> #define HDMI14_MAX_TMDSCLK 340000000
> +#define HDMI20_MAX_TMDSRATE 600000000
>
> +#define SCDC_MAX_SOURCE_VERSION 0x1
> #define SCRAMB_POLL_DELAY_MS 3000
>
> /*
> @@ -164,6 +169,11 @@ struct dw_hdmi_qp {
> } phy;
>
> unsigned long ref_clk_rate;
> +
> + struct drm_connector *curr_conn;
> + struct delayed_work scramb_work;
> + bool scramb_enabled;
s/scramb/scrambler/
Can we move those two to the drm_connector_hdmi
> +
> struct regmap *regm;
> int main_irq;
>
> @@ -749,28 +759,124 @@ static struct i2c_adapter *dw_hdmi_qp_i2c_adapter(struct dw_hdmi_qp *hdmi)
> return adap;
> }
>
> +static bool dw_hdmi_qp_supports_scrambling(struct drm_display_info *display)
> +{
> + if (!display->is_hdmi)
> + return false;
> +
> + return display->hdmi.scdc.supported &&
> + display->hdmi.scdc.scrambling.supported;
> +}
> +
> +static int dw_hdmi_qp_set_scramb(struct dw_hdmi_qp *hdmi)
> +{
> + bool done;
> +
> + dev_dbg(hdmi->dev, "set scrambling\n");
> +
> + done = drm_scdc_set_high_tmds_clock_ratio(hdmi->curr_conn, true);
> + if (!done)
> + return -EIO;
> +
> + done = drm_scdc_set_scrambling(hdmi->curr_conn, true);
> + if (!done) {
> + drm_scdc_set_high_tmds_clock_ratio(hdmi->curr_conn, false);
> + return -EIO;
> + }
> +
> + schedule_delayed_work(&hdmi->scramb_work,
> + msecs_to_jiffies(SCRAMB_POLL_DELAY_MS));
> + return 0;
> +}
> +
> +static void dw_hdmi_qp_scramb_work(struct work_struct *work)
> +{
> + struct dw_hdmi_qp *hdmi = container_of(to_delayed_work(work),
> + struct dw_hdmi_qp,
> + scramb_work);
> + if (READ_ONCE(hdmi->scramb_enabled) &&
> + !drm_scdc_get_scrambling_status(hdmi->curr_conn))
> + dw_hdmi_qp_set_scramb(hdmi);
> +}
> +
> +static void dw_hdmi_qp_enable_scramb(struct dw_hdmi_qp *hdmi)
> +{
> + int ret;
> + u8 ver;
> +
> + if (!dw_hdmi_qp_supports_scrambling(&hdmi->curr_conn->display_info))
> + return;
> +
> + ret = drm_scdc_readb(hdmi->bridge.ddc, SCDC_SINK_VERSION, &ver);
> + if (ret) {
> + dev_err(hdmi->dev, "Failed to read SCDC_SINK_VERSION: %d\n", ret);
> + return;
> + }
> +
> + ret = drm_scdc_writeb(hdmi->bridge.ddc, SCDC_SOURCE_VERSION,
> + min_t(u8, ver, SCDC_MAX_SOURCE_VERSION));
> + if (ret) {
> + dev_err(hdmi->dev, "Failed to write SCDC_SOURCE_VERSION: %d\n", ret);
> + return;
> + }
> +
> + WRITE_ONCE(hdmi->scramb_enabled, true);
> +
> + ret = dw_hdmi_qp_set_scramb(hdmi);
> + if (ret) {
> + hdmi->scramb_enabled = false;
> + return;
> + }
> +
> + dw_hdmi_qp_write(hdmi, 1, SCRAMB_CONFIG0);
> +
> + /* Wait at least 1 ms before resuming TMDS transmission */
> + usleep_range(1000, 5000);
> +}
> +
> +static void dw_hdmi_qp_disable_scramb(struct dw_hdmi_qp *hdmi)
> +{
> + if (!hdmi->scramb_enabled)
> + return;
> +
> + dev_dbg(hdmi->dev, "disable scrambling\n");
> +
> + WRITE_ONCE(hdmi->scramb_enabled, false);
> + cancel_delayed_work_sync(&hdmi->scramb_work);
> +
> + dw_hdmi_qp_write(hdmi, 0, SCRAMB_CONFIG0);
> +
> + if (hdmi->curr_conn->status == connector_status_connected) {
> + drm_scdc_set_scrambling(hdmi->curr_conn, false);
> + drm_scdc_set_high_tmds_clock_ratio(hdmi->curr_conn, false);
> + }
> +}
All of these feel like generic helpers.
> +
> static void dw_hdmi_qp_bridge_atomic_enable(struct drm_bridge *bridge,
> struct drm_atomic_state *state)
> {
> struct dw_hdmi_qp *hdmi = bridge->driver_private;
> struct drm_connector_state *conn_state;
> - struct drm_connector *connector;
> unsigned int op_mode;
>
> - connector = drm_atomic_get_new_connector_for_encoder(state, bridge->encoder);
> - if (WARN_ON(!connector))
> + hdmi->curr_conn = drm_atomic_get_new_connector_for_encoder(state,
> + bridge->encoder);
> + if (WARN_ON(!hdmi->curr_conn))
> return;
>
> - conn_state = drm_atomic_get_new_connector_state(state, connector);
> + conn_state = drm_atomic_get_new_connector_state(state, hdmi->curr_conn);
> if (WARN_ON(!conn_state))
> return;
>
> - if (connector->display_info.is_hdmi) {
> + if (hdmi->curr_conn->display_info.is_hdmi) {
> dev_dbg(hdmi->dev, "%s mode=HDMI %s rate=%llu bpc=%u\n", __func__,
> drm_hdmi_connector_get_output_format_name(conn_state->hdmi.output_format),
> conn_state->hdmi.tmds_char_rate, conn_state->hdmi.output_bpc);
> op_mode = 0;
> hdmi->tmds_char_rate = conn_state->hdmi.tmds_char_rate;
> +
> + if (conn_state->hdmi.tmds_char_rate > HDMI14_MAX_TMDSCLK)
> + dw_hdmi_qp_enable_scramb(hdmi);
> } else {
> dev_dbg(hdmi->dev, "%s mode=DVI\n", __func__);
> op_mode = OPMODE_DVI;
> @@ -781,7 +887,7 @@ static void dw_hdmi_qp_bridge_atomic_enable(struct drm_bridge *bridge,
> dw_hdmi_qp_mod(hdmi, HDCP2_BYPASS, HDCP2_BYPASS, HDCP2LOGIC_CONFIG0);
> dw_hdmi_qp_mod(hdmi, op_mode, OPMODE_DVI, LINK_CONFIG0);
>
> - drm_atomic_helper_connector_hdmi_update_infoframes(connector, state);
> + drm_atomic_helper_connector_hdmi_update_infoframes(hdmi->curr_conn, state);
> }
>
> static void dw_hdmi_qp_bridge_atomic_disable(struct drm_bridge *bridge,
> @@ -791,14 +897,49 @@ static void dw_hdmi_qp_bridge_atomic_disable(struct drm_bridge *bridge,
>
> hdmi->tmds_char_rate = 0;
>
> + dw_hdmi_qp_disable_scramb(hdmi);
> +
> + hdmi->curr_conn = NULL;
> hdmi->phy.ops->disable(hdmi, hdmi->phy.data);
> }
>
> -static enum drm_connector_status
> -dw_hdmi_qp_bridge_detect(struct drm_bridge *bridge, struct drm_connector *connector)
> +static int dw_hdmi_qp_reset_crtc(struct dw_hdmi_qp *hdmi,
> + struct drm_connector *connector,
> + struct drm_modeset_acquire_ctx *ctx)
> +{
> + u8 config;
> + int ret;
> +
> + ret = drm_scdc_readb(hdmi->bridge.ddc, SCDC_TMDS_CONFIG, &config);
> + if (ret < 0) {
> + dev_err(hdmi->dev, "Failed to read TMDS config: %d\n", ret);
> + return ret;
> + }
> +
> + if (!!(config & SCDC_SCRAMBLING_ENABLE) == hdmi->scramb_enabled)
> + return 0;
Also please check the high TMDS clock ration bit.
> +
> + drm_atomic_helper_connector_hdmi_hotplug(connector,
> + connector_status_connected);
I don't see a forced hotplug event in the existing drivers. Why is it
necessary? This function is being called from the detect() path.
> + /*
> + * Conform to HDMI 2.0 spec by ensuring scrambled data is not sent
> + * before configuring the sink scrambling, as well as suspending any
> + * TMDS transmission while changing the TMDS clock rate in the sink.
> + */
> +
> + dev_dbg(hdmi->dev, "resetting crtc\n");
> +
> + return drm_bridge_helper_reset_crtc(&hdmi->bridge, ctx);
> +}
> +
> +static int dw_hdmi_qp_bridge_detect_ctx(struct drm_bridge *bridge,
> + struct drm_connector *connector,
> + struct drm_modeset_acquire_ctx *ctx)
> {
> struct dw_hdmi_qp *hdmi = bridge->driver_private;
> + enum drm_connector_status status;
> const struct drm_edid *drm_edid;
> + int ret;
>
> if (hdmi->no_hpd) {
> drm_edid = drm_edid_read_ddc(connector, bridge->ddc);
> @@ -808,7 +949,20 @@ dw_hdmi_qp_bridge_detect(struct drm_bridge *bridge, struct drm_connector *connec
> return connector_status_disconnected;
> }
>
> - return hdmi->phy.ops->read_hpd(hdmi, hdmi->phy.data);
> + status = hdmi->phy.ops->read_hpd(hdmi, hdmi->phy.data);
> +
> + dev_dbg(hdmi->dev, "%s status=%d scramb=%d\n", __func__,
> + status, hdmi->scramb_enabled);
> +
> + if (status == connector_status_connected && hdmi->scramb_enabled) {
> + ret = dw_hdmi_qp_reset_crtc(hdmi, connector, ctx);
> + if (ret == -EDEADLK)
> + return ret;
> + if (ret < 0)
> + status = connector_status_unknown;
Ideally this should go to the drm_atomic_helper_connector_hdmi_update().
And once it goes, I don't think we'd need the detect_ctx() callback for
bridges.
> + }
> +
> + return status;
> }
>
> static const struct drm_edid *
> @@ -832,12 +986,12 @@ dw_hdmi_qp_bridge_tmds_char_rate_valid(const struct drm_bridge *bridge,
> {
> struct dw_hdmi_qp *hdmi = bridge->driver_private;
>
> - /*
> - * TODO: when hdmi->no_hpd is 1 we must not support modes that
> - * require scrambling, including every mode with a clock above
> - * HDMI14_MAX_TMDSCLK.
> - */
> - if (rate > HDMI14_MAX_TMDSCLK) {
> + if (hdmi->no_hpd && rate > HDMI14_MAX_TMDSCLK) {
> + dev_dbg(hdmi->dev, "Unsupported TMDS char rate in no_hpd mode: %lld\n", rate);
> + return MODE_CLOCK_HIGH;
> + }
> +
> + if (rate > HDMI20_MAX_TMDSRATE) {
> dev_dbg(hdmi->dev, "Unsupported TMDS char rate: %lld\n", rate);
> return MODE_CLOCK_HIGH;
> }
> @@ -1197,7 +1351,7 @@ static const struct drm_bridge_funcs dw_hdmi_qp_bridge_funcs = {
> .atomic_reset = drm_atomic_helper_bridge_reset,
> .atomic_enable = dw_hdmi_qp_bridge_atomic_enable,
> .atomic_disable = dw_hdmi_qp_bridge_atomic_disable,
> - .detect = dw_hdmi_qp_bridge_detect,
> + .detect_ctx = dw_hdmi_qp_bridge_detect_ctx,
> .edid_read = dw_hdmi_qp_bridge_edid_read,
> .hdmi_tmds_char_rate_valid = dw_hdmi_qp_bridge_tmds_char_rate_valid,
> .hdmi_clear_avi_infoframe = dw_hdmi_qp_bridge_clear_avi_infoframe,
> @@ -1287,6 +1441,8 @@ struct dw_hdmi_qp *dw_hdmi_qp_bind(struct platform_device *pdev,
> if (IS_ERR(hdmi))
> return ERR_CAST(hdmi);
>
> + INIT_DELAYED_WORK(&hdmi->scramb_work, dw_hdmi_qp_scramb_work);
> +
> hdmi->dev = dev;
>
> regs = devm_platform_ioremap_resource(pdev, 0);
>
> --
> 2.53.0
>
--
With best wishes
Dmitry
^ permalink raw reply
* Re: [PATCH 1/2] pmdomain/rockchip: skip QoS operations for idle-only domains
From: Daniel Bozeman @ 2026-04-28 1:32 UTC (permalink / raw)
To: shawn.lin, finley.xiao, jonas, ulf.hansson, heiko, linux-pm,
linux-arm-kernel, linux-rockchip, linux-kernel
In-Reply-To: <adRH235mv00OdOsb@claude-dev>
Hi Jonas,
Just following up — I have the NanoPi Zero2 on my bench and am
happy to run any tests if that would be helpful.
I can confirm the EPROBE_DEFER teardown crash is still
reproducible on your next-20260403-rk3528 branch (7.0-rc6)
with your conditional NO_STAY_ON fix applied. If you'd like
me to test a different approach or gather additional debug
output, just let me know.
Thanks,
Daniel
^ permalink raw reply
* Re: [RFC PATCH v2 1/4] security: ima: call ima_init() again at late_initcall_sync for defered TPM
From: Paul Moore @ 2026-04-28 1:31 UTC (permalink / raw)
To: Yeoreum Yun
Cc: Mimi Zohar, roberto.sassu, Jonathan McDowell,
linux-security-module, linux-kernel, linux-integrity,
linux-arm-kernel, kvmarm, jmorris, serge, dmitry.kasatkin,
eric.snowberg, jarkko, jgg, sudeep.holla, maz, oupton, joey.gouly,
suzuki.poulose, yuzenghui, catalin.marinas, will, noodles,
sebastianene
In-Reply-To: <aexIwJpno3iPIdRD@e129823.arm.com>
On Sat, Apr 25, 2026 at 12:53 AM Yeoreum Yun <yeoreum.yun@arm.com> wrote:
> > > I understand the need to ensure that the TPM is available, but if it
> > > isn't safe to wait to initialize IMA at late_initcall_sync() then it
> > > would seem like this is a bad option and we need another mechanism to
> > > synchronize IMA with TPM devices. If it is safe to initalize IMA in
> > > late_initcall_sync(), just do that and be done with it.
> >
> > Within the same initcall level there is no way of ordering the initialization.
> > Yeorum attempted to address the ordering issue in commit 0e0546eabcd6
> > ("firmware: arm_ffa: Change initcall level of ffa_init() to rootfs_initcall"),
> > which is being reverted in this patch set.
> >
> > Ordering within an initcall level needs to be fixed, but for now retrying at
> > late_initcall_sync works for some, hopefully most, cases.
>
> Ordering within an initcall level is not good idea.
Agreed. That's why we have the different initcall levels.
--
paul-moore.com
^ 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;
as well as URLs for NNTP newsgroup(s).