* Re: [PATCH 0/2] drivers/perf: hisi: Updates for HiSilicon uncore PMUs
From: Yushan Wang @ 2026-06-09 13:53 UTC (permalink / raw)
To: Will Deacon
Cc: mark.rutland, robin.murphy, linux-arm-kernel, linux-kernel,
fanghao11, linuxarm, liuyonglong, prime.zeng, wangzhou1
In-Reply-To: <aiCHPe4X4bwAtZ8q@willie-the-truck>
On 6/4/2026 3:57 AM, Will Deacon wrote:
> On Tue, May 19, 2026 at 04:42:32PM +0800, Yushan Wang wrote:
>> Hi all, a gentle ping on this.
>>
>> All comments are welcomed
> Sashiko has a few (some of which are bogus):
>
> https://sashiko.dev/#/patchset/20260423152959.1458563-1-wangyushan12@huawei.com
>
> Will
Thanks for the reminding, I will post newer version this week.
^ permalink raw reply
* [PATCH v2 0/3] arm64: cross-CPU NMI via SDEI
From: Kiryl Shutsemau @ 2026-06-09 13:58 UTC (permalink / raw)
To: Catalin Marinas, Will Deacon, James Morse
Cc: Mark Rutland, Marc Zyngier, Doug Anderson, Petr Mladek,
Thomas Gleixner, Andrew Morton, Baoquan He, Puranjay Mohan,
Usama Arif, Breno Leitao, Julien Thierry, Lecopzer Chen,
Sumit Garg, kernel-team, kexec, linux-arm-kernel, linux-kernel,
Kiryl Shutsemau (Meta)
In-Reply-To: <cover.1780496779.git.kas@kernel.org>
From: "Kiryl Shutsemau (Meta)" <kas@kernel.org>
A class of debug/observability features needs to interrupt a CPU that has
its interrupts locally masked: the all-CPU backtrace behind sysrq-l /
RCU-stall / hung-task / hard-lockup dumps, and crash_smp_send_stop()
capturing a stuck CPU's state into the vmcore. On arm64 these need a
mechanism that reaches a CPU spinning with DAIF masked, which a normal IPI
cannot.
arm64 has two such mechanisms today:
- GICv3 pseudo-NMI (interrupt priority masking). Its cost is on the
interrupt mask/unmask hot path: local_irq_enable() becomes an
ICC_PMR_EL1 write plus a synchronising barrier, and exception
entry/exit save and restore the PMR, paid on every CPU whether or not
an NMI is ever delivered. In our measurements, enabling pseudo-NMI
costs up to ~5% on real workloads, and ~66% on a syscall-in-a-loop
microbenchmark. A fleet-wide ~5% regression is not acceptable, so
these systems run with pseudo-NMI disabled.
- FEAT_NMI (Armv8.8) -- the architectural fix, but absent from deployed
silicon and from most of the fleet for years to come.
For deployments that do not run pseudo-NMI, the backtrace and crash paths
are degraded: a plain IPI can't reach the masked CPU, so the backtrace of
the CPU you care about comes back empty and the kdump is missing the
culprit's registers. The hard-lockup detector on these systems is the
software buddy detector (HARDLOCKUP_DETECTOR_BUDDY): it detects a stall
from a neighbour CPU, but it cannot itself interrupt the wedged CPU, so
its report has no stack for the culprit and (with hardlockup_panic) the
panic runs on the bystander.
This series adds a third delivery backend that costs nothing on the hot
path: SDEI. Firmware delivers an SDEI event into a CPU regardless of its
DAIF state, so interrupt masking stays the cheap PSTATE.DAIF operation and
the firmware round-trip is paid only at the rare moment a CPU must be
interrupted.
It does not add a hard-lockup detector. Detection stays with the buddy
detector (CONFIG_HARDLOCKUP_DETECTOR_PREFER_BUDDY); this series gives the
backtrace and crash-stop paths -- including the buddy detector's
backtrace of the stalled CPU -- a way to actually reach a masked CPU.
Mechanism
=========
It uses the standard SDEI software-signalled event (event 0) and the
SDEI_EVENT_SIGNAL call (DEN0054) -- a spec-defined cross-PE signal, not a
vendor extension. The driver registers a handler for event 0 and pokes a
target CPU with sdei_event_signal(0, target_mpidr); firmware makes event 0
pending on that PE and dispatches the handler NMI-like.
No firmware change is required beyond SDEI being enabled, which
firmware-first RAS (APEI/GHES) deployments already have; the only
SDEI-core addition is a thin sdei_event_signal() wrapper over the standard
call.
Prior SDEI watchdog work
========================
Out-of-tree SDEI hard-lockup watchdogs exist (e.g. in the openEuler and
Anolis kernels). They bind the secure physical timer as an SDEI event, so
firmware delivers a periodic self-CPU tick that drives a detector. That
requires a new SDEI interrupt-binding API, pushes the watchdog period into
firmware, and adds secure-timer EOI handling on the kexec path. This
series instead uses only the standard software-signalled event 0, keeps
all timing in the kernel (the buddy detector), and the same delivery
primitive serves the backtrace and crash-stop users, not just lockup
reporting.
Not included / follow-ups
=========================
- No SDEI hard-lockup-detector backend. v1 had one; it is dropped here.
The buddy detector plus this series' backtrace already cover the
no-pseudo-NMI case, and a dedicated SDEI backend duplicated the
perf-NMI detector it had to compile-exclude. Run PREFER_BUDDY.
- A CPU stopped by the SDEI rung is parked, not powered off via PSCI
CPU_OFF. Reaching and dumping the wedged CPU -- the point of the
series -- works, and this matches ipi_cpu_crash_stop()'s own park
fallback. The consequence is that an SMP crash-capture kernel cannot
re-online such a CPU (it stays "already on"); the capture kernel boots
and runs on the remaining CPUs. Powering the stopped CPU off so a
capture kernel can reclaim it requires completing the SDEI event and
then CPU_OFF, which hit a firmware-specific issue still under
investigation; it is left as a follow-up and does not affect the
dump's contents.
Testing
=======
Developed on QEMU 'virt' (Trusted Firmware-A with SDEI enabled) and
validated on NVIDIA Grace (Neoverse V2) hardware, under
irqchip.gicv3_pseudo_nmi=0 with HARDLOCKUP_DETECTOR_PREFER_BUDDY=y:
- sysrq-l backtrace of an interrupt-masked CPU returns its real stack,
pstate showing DAIF set -- proof SDEI delivered into the masked CPU;
- buddy detector catches a hard lockup (LKDTM) and the wedged CPU's
stack is fetched via the SDEI backtrace;
- reboot/halt and the panic/kdump crash stop reach a wedged CPU via the
SDEI rung ("SMP: retry stop with SDEI NMI for CPUs N"), and the kdump
captures the wedged CPU's registers in the vmcore.
Changes since v1
================
- Dropped the SDEI hard-lockup-detector patch (v1 3/4); use the buddy
detector instead (Doug Anderson).
- Reworked the crash-stop patch (v1 4/4) into a third rung of
smp_send_stop()'s escalation, shared with the IPI stop path and
covering reboot/halt as well as crash; no on-stack cpumask
(Doug Anderson).
- 2/3: split the merged comment in arch_trigger_cpumask_backtrace()
(Doug Anderson).
- Renamed the driver to drivers/firmware/arm_sdei_nmi.c, to sit beside
the SDEI core it builds on (drivers/firmware/arm_sdei.c), and widened
that entry's MAINTAINERS glob (arm_sdei.c -> arm_sdei*) to cover it.
- Picked up Reviewed-by from Doug Anderson on 1/3 and 2/3 (the changes
above are mechanical / comment-only on those two).
v1: https://lore.kernel.org/all/cover.1780496779.git.kas@kernel.org
Also available at:
git://git.kernel.org/pub/scm/linux/kernel/git/kas/linux.git sdei-nmi/v2
Kiryl Shutsemau (Meta) (3):
firmware: arm_sdei: add SDEI_EVENT_SIGNAL support
drivers/firmware: add SDEI cross-CPU NMI service for arm64
arm64: escalate smp_send_stop() to an SDEI NMI as a last resort
MAINTAINERS | 2 +-
arch/arm64/include/asm/nmi.h | 38 ++++++
arch/arm64/kernel/smp.c | 64 ++++++++++
drivers/firmware/Kconfig | 21 +++
drivers/firmware/Makefile | 1 +
drivers/firmware/arm_sdei.c | 12 ++
drivers/firmware/arm_sdei_nmi.c | 220 ++++++++++++++++++++++++++++++++
include/linux/arm_sdei.h | 6 +
include/uapi/linux/arm_sdei.h | 1 +
9 files changed, 364 insertions(+), 1 deletion(-)
create mode 100644 arch/arm64/include/asm/nmi.h
create mode 100644 drivers/firmware/arm_sdei_nmi.c
base-commit: e7ae89a0c97ce2b68b0983cd01eda67cf373517d
--
2.54.0
^ permalink raw reply
* [PATCH v2 1/3] firmware: arm_sdei: add SDEI_EVENT_SIGNAL support
From: Kiryl Shutsemau @ 2026-06-09 13:58 UTC (permalink / raw)
To: Catalin Marinas, Will Deacon, James Morse
Cc: Mark Rutland, Marc Zyngier, Doug Anderson, Petr Mladek,
Thomas Gleixner, Andrew Morton, Baoquan He, Puranjay Mohan,
Usama Arif, Breno Leitao, Julien Thierry, Lecopzer Chen,
Sumit Garg, kernel-team, kexec, linux-arm-kernel, linux-kernel,
Kiryl Shutsemau (Meta)
In-Reply-To: <cover.1781013134.git.kas@kernel.org>
From: "Kiryl Shutsemau (Meta)" <kas@kernel.org>
Add sdei_event_signal(), a thin wrapper over the SDEI_EVENT_SIGNAL call
(DEN0054) that makes the software-signalled event (event 0) pending on a
target PE -- delivered NMI-like even when that PE has interrupts masked.
It takes no locks, so it is safe to call from NMI / crash context.
Signed-off-by: Kiryl Shutsemau (Meta) <kas@kernel.org>
Reviewed-by: Douglas Anderson <dianders@chromium.org>
---
drivers/firmware/arm_sdei.c | 12 ++++++++++++
include/linux/arm_sdei.h | 6 ++++++
include/uapi/linux/arm_sdei.h | 1 +
3 files changed, 19 insertions(+)
diff --git a/drivers/firmware/arm_sdei.c b/drivers/firmware/arm_sdei.c
index f39ed7ba3a38..e3fd604d9894 100644
--- a/drivers/firmware/arm_sdei.c
+++ b/drivers/firmware/arm_sdei.c
@@ -339,6 +339,18 @@ static void _ipi_unmask_cpu(void *ignored)
sdei_unmask_local_cpu();
}
+/*
+ * Signal the software-signalled event (event 0) to @mpidr. Does nothing
+ * but the SMC -- no locks, no event lookup -- so it is safe from NMI /
+ * crash context (e.g. the cross-CPU NMI service).
+ */
+int sdei_event_signal(u32 event_num, u64 mpidr)
+{
+ return invoke_sdei_fn(SDEI_1_0_FN_SDEI_EVENT_SIGNAL, event_num,
+ mpidr, 0, 0, 0, NULL);
+}
+NOKPROBE_SYMBOL(sdei_event_signal);
+
static void _ipi_private_reset(void *ignored)
{
int err;
diff --git a/include/linux/arm_sdei.h b/include/linux/arm_sdei.h
index f652a5028b59..3f3ec01155e8 100644
--- a/include/linux/arm_sdei.h
+++ b/include/linux/arm_sdei.h
@@ -37,6 +37,12 @@ int sdei_event_unregister(u32 event_num);
int sdei_event_enable(u32 event_num);
int sdei_event_disable(u32 event_num);
+/*
+ * Signal the software-signalled event (event 0) to another PE, NMI-like.
+ * @mpidr is the target's MPIDR affinity.
+ */
+int sdei_event_signal(u32 event_num, u64 mpidr);
+
/* GHES register/unregister helpers */
int sdei_register_ghes(struct ghes *ghes, sdei_event_callback *normal_cb,
sdei_event_callback *critical_cb);
diff --git a/include/uapi/linux/arm_sdei.h b/include/uapi/linux/arm_sdei.h
index af0630ba5437..22eb61612673 100644
--- a/include/uapi/linux/arm_sdei.h
+++ b/include/uapi/linux/arm_sdei.h
@@ -22,6 +22,7 @@
#define SDEI_1_0_FN_SDEI_PE_UNMASK SDEI_1_0_FN(0x0C)
#define SDEI_1_0_FN_SDEI_INTERRUPT_BIND SDEI_1_0_FN(0x0D)
#define SDEI_1_0_FN_SDEI_INTERRUPT_RELEASE SDEI_1_0_FN(0x0E)
+#define SDEI_1_0_FN_SDEI_EVENT_SIGNAL SDEI_1_0_FN(0x0F)
#define SDEI_1_0_FN_SDEI_PRIVATE_RESET SDEI_1_0_FN(0x11)
#define SDEI_1_0_FN_SDEI_SHARED_RESET SDEI_1_0_FN(0x12)
--
2.54.0
^ permalink raw reply related
* [PATCH v2 3/3] arm64: escalate smp_send_stop() to an SDEI NMI as a last resort
From: Kiryl Shutsemau @ 2026-06-09 13:58 UTC (permalink / raw)
To: Catalin Marinas, Will Deacon, James Morse
Cc: Mark Rutland, Marc Zyngier, Doug Anderson, Petr Mladek,
Thomas Gleixner, Andrew Morton, Baoquan He, Puranjay Mohan,
Usama Arif, Breno Leitao, Julien Thierry, Lecopzer Chen,
Sumit Garg, kernel-team, kexec, linux-arm-kernel, linux-kernel,
Kiryl Shutsemau (Meta)
In-Reply-To: <cover.1781013134.git.kas@kernel.org>
From: "Kiryl Shutsemau (Meta)" <kas@kernel.org>
A CPU wedged with interrupts masked ignores the stop IPI, and without
pseudo-NMI there is no NMI IPI to escalate to: a reboot proceeds with
the CPU still running, and a kdump misses its registers.
Add a third rung to smp_send_stop()'s escalation: signal SDEI event 0
at whatever is still online after the IPI (and pseudo-NMI IPI, if
enabled) rungs. The handler routes like the IPI handlers do --
crash_stop distinguishes a kdump crash stop (crash_save_cpu() on the
wedged context) from a plain stop -- and the CPU acks by marking
itself offline, which the caller already polls.
arm64_nmi_cpu_stop() lives in smp.c rather than the SDEI provider
because it needs the crash_stop discriminator and shares its shape with
ipi_cpu_crash_stop(); it is exported only so the provider's event-0
handler, which owns the trigger, can route into it.
Two differences against an IPI-stopped CPU: the SDEI event is never
completed, since completing it would resume the wedged context, so EL3
retains the event's dispatch slot until reset; and the CPU parks
instead of trying PSCI CPU_OFF, which must not be called from inside
an unfinished SDEI event.
Signed-off-by: Kiryl Shutsemau (Meta) <kas@kernel.org>
---
arch/arm64/include/asm/nmi.h | 14 +++++++
arch/arm64/kernel/smp.c | 53 ++++++++++++++++++++++++
drivers/firmware/Kconfig | 2 +
drivers/firmware/arm_sdei_nmi.c | 71 +++++++++++++++++++++++++++++++++
4 files changed, 140 insertions(+)
diff --git a/arch/arm64/include/asm/nmi.h b/arch/arm64/include/asm/nmi.h
index 9366be419d18..2a9e6065f7af 100644
--- a/arch/arm64/include/asm/nmi.h
+++ b/arch/arm64/include/asm/nmi.h
@@ -4,21 +4,35 @@
#include <linux/cpumask.h>
+struct pt_regs;
+
/*
* Cross-CPU NMI provider hooks, consulted by the arm64 arch code before
* its regular-IRQ / pseudo-NMI IPI paths. The SDEI provider in
* drivers/firmware/arm_sdei_nmi.c implements them when active; a future
* FEAT_NMI provider could slot in here too. The stubs let callers stay
* unconditional when ARM_SDEI_NMI is off.
+ *
+ * arm64_nmi_cpu_stop() is the reverse direction: the arch entry point
+ * (arch/arm64/kernel/smp.c) that the provider's NMI handler routes a
+ * stop request into.
*/
#ifdef CONFIG_ARM_SDEI_NMI
bool sdei_nmi_trigger_cpumask_backtrace(const cpumask_t *mask, int exclude_cpu);
+bool sdei_nmi_stop_cpus(const cpumask_t *mask);
+
+void __noreturn arm64_nmi_cpu_stop(struct pt_regs *regs);
#else
static inline bool sdei_nmi_trigger_cpumask_backtrace(const cpumask_t *mask,
int exclude_cpu)
{
return false;
}
+
+static inline bool sdei_nmi_stop_cpus(const cpumask_t *mask)
+{
+ return false;
+}
#endif
#endif /* __ASM_NMI_H */
diff --git a/arch/arm64/kernel/smp.c b/arch/arm64/kernel/smp.c
index a670434a8cae..1af7fdae48db 100644
--- a/arch/arm64/kernel/smp.c
+++ b/arch/arm64/kernel/smp.c
@@ -33,6 +33,7 @@
#include <linux/kernel_stat.h>
#include <linux/kexec.h>
#include <linux/kgdb.h>
+#include <linux/kprobes.h>
#include <linux/kvm_host.h>
#include <linux/nmi.h>
@@ -910,6 +911,35 @@ static void __noreturn ipi_cpu_crash_stop(unsigned int cpu, struct pt_regs *regs
#endif
}
+#ifdef CONFIG_ARM_SDEI_NMI
+/*
+ * Stop entry for the SDEI cross-CPU NMI service: its event-0 handler
+ * lands here when this CPU was asked to stop. The bookkeeping mirrors
+ * the IPI_CPU_STOP{,_NMI} handling; the park happens inside the SDEI
+ * event, which is never completed -- completing it would have firmware
+ * resume the interrupted (typically wedged) context. No PSCI CPU_OFF
+ * either: powering off a PE that EL3 still considers mid-event invites
+ * firmware trouble.
+ */
+void __noreturn arm64_nmi_cpu_stop(struct pt_regs *regs)
+{
+ unsigned int cpu = smp_processor_id();
+
+ local_daif_mask();
+
+ if (IS_ENABLED(CONFIG_KEXEC_CORE) && crash_stop)
+ crash_save_cpu(regs, cpu);
+
+ /* the ack the stop requester polls for */
+ set_cpu_online(cpu, false);
+
+ sdei_mask_local_cpu();
+
+ cpu_park_loop();
+}
+NOKPROBE_SYMBOL(arm64_nmi_cpu_stop);
+#endif
+
static void arm64_send_ipi(const cpumask_t *mask, unsigned int nr)
{
unsigned int cpu;
@@ -1263,6 +1293,29 @@ void smp_send_stop(void)
udelay(1);
}
+ /*
+ * If CPUs are *still* online, try the SDEI cross-CPU NMI. Firmware
+ * delivers it regardless of the target's DAIF state, so it reaches
+ * a CPU spinning with interrupts masked, which neither rung above
+ * could (without pseudo-NMI there is no NMI rung at all). Allow
+ * 100ms: a firmware round-trip per CPU, with headroom.
+ */
+ if (num_other_online_cpus()) {
+ /* re-snapshot after the rungs above took CPUs offline */
+ smp_rmb();
+ cpumask_copy(&mask, cpu_online_mask);
+ cpumask_clear_cpu(smp_processor_id(), &mask);
+
+ if (sdei_nmi_stop_cpus(&mask)) {
+ pr_info("SMP: retry stop with SDEI NMI for CPUs %*pbl\n",
+ cpumask_pr_args(&mask));
+
+ timeout = USEC_PER_MSEC * 100;
+ while (num_other_online_cpus() && timeout--)
+ udelay(1);
+ }
+ }
+
if (num_other_online_cpus()) {
smp_rmb();
cpumask_copy(&mask, cpu_online_mask);
diff --git a/drivers/firmware/Kconfig b/drivers/firmware/Kconfig
index 6501087ff90d..ab0ee36d46e7 100644
--- a/drivers/firmware/Kconfig
+++ b/drivers/firmware/Kconfig
@@ -46,6 +46,8 @@ config ARM_SDEI_NMI
- arch_trigger_cpumask_backtrace() (sysrq-l, RCU stalls,
hardlockup_all_cpu_backtrace, soft-lockup secondary dumps,
hung-task auxiliary dumps)
+ - smp_send_stop() escalation (reboot/halt and the
+ panic / kdump crash stop)
The driver registers a handler for the SDEI software-signalled
event (event 0) and reaches a target CPU by signalling it with
diff --git a/drivers/firmware/arm_sdei_nmi.c b/drivers/firmware/arm_sdei_nmi.c
index a82776e7b55a..b34ea42cfe5c 100644
--- a/drivers/firmware/arm_sdei_nmi.c
+++ b/drivers/firmware/arm_sdei_nmi.c
@@ -29,6 +29,11 @@
* hardlockup_all_cpu_backtrace, soft-lockup/hung-task secondary
* dumps all reach interrupt-masked CPUs.
*
+ * - sdei_nmi_stop_cpus() — the last rung of smp_send_stop()'s
+ * escalation (reboot/halt and the panic/kdump crash stop alike),
+ * reaching CPUs that ignored the stop IPIs; on the kdump path the
+ * wedged context is captured into the vmcore before the CPU parks.
+ *
* Delivery uses the standard SDEI software-signalled event (event 0) and
* SDEI_EVENT_SIGNAL. We register a handler for event 0, enable it, and
* poke a target CPU with sdei_event_signal(0, mpidr): firmware makes
@@ -59,8 +64,45 @@ static bool sdei_nmi_available;
#define SDEI_NMI_EVENT 0
+/*
+ * Stop-request dispatch lives on the same SDEI event 0 as everything
+ * else. The requesting CPU sets each target's bit in sdei_nmi_stop_mask
+ * before signalling event 0; the target's handler test-and-clears its
+ * bit and hands the CPU to arm64_nmi_cpu_stop(), which saves crash
+ * state when the stop is a kdump crash-stop, marks the CPU offline
+ * (which is what the requester polls for) and parks it.
+ *
+ * This mirrors the cpumask the framework's nmi_cpu_backtrace() consults
+ * just below, and a shared mask rather than a separate SDEI event avoids
+ * extra registrations from firmware.
+ */
+static cpumask_t sdei_nmi_stop_mask;
+
static int sdei_nmi_handler(u32 event, struct pt_regs *regs, void *arg)
{
+ int cpu = smp_processor_id();
+
+ if (cpumask_test_and_clear_cpu(cpu, &sdei_nmi_stop_mask)) {
+ /*
+ * Never returns, and deliberately never completes the SDEI
+ * event: SDEI_EVENT_COMPLETE has firmware restore the
+ * interrupted context, which would land the CPU back in
+ * the wedged loop (or in do_idle, which BUGs at
+ * cpuhp_report_idle_dead once it sees itself offline).
+ * Returning a modified pt_regs doesn't help --
+ * arch/arm64/kernel/sdei.c::do_sdei_event only honours a PC
+ * override via its IRQ-state heuristic and otherwise hands
+ * EL3 its own saved-context slot back.
+ *
+ * Trade-off: EL3 retains ~one saved-context slot per parked
+ * CPU until the next hardware reset (~hundreds of bytes per
+ * CPU). Recoverability is unchanged versus an IPI-stopped
+ * CPU: neither comes back without a reset.
+ */
+ arm64_nmi_cpu_stop(regs);
+ /* unreachable */
+ }
+
/*
* nmi_cpu_backtrace() no-ops unless this CPU's bit is set in the
* global backtrace mask (driven by nmi_trigger_cpumask_backtrace()),
@@ -115,6 +157,35 @@ bool sdei_nmi_trigger_cpumask_backtrace(const cpumask_t *mask, int exclude_cpu)
return true;
}
+/*
+ * Last rung of the stop escalation in smp_send_stop() (see
+ * arch/arm64/kernel/smp.c). The caller runs the regular stop IPI (and
+ * the pseudo-NMI stop IPI, where available) first; @mask holds whatever
+ * stayed online through those -- typically CPUs wedged with interrupts
+ * masked, unreachable by an IPI. Set each target's stop-request flag and
+ * signal event 0 at it; a target acks by marking itself offline, which
+ * the caller polls for.
+ *
+ * Returns false when SDEI isn't active, so the caller can skip the wait.
+ */
+bool sdei_nmi_stop_cpus(const cpumask_t *mask)
+{
+ unsigned int cpu;
+
+ if (!sdei_nmi_available)
+ return false;
+
+ cpumask_or(&sdei_nmi_stop_mask, &sdei_nmi_stop_mask, mask);
+
+ /* Publish the mask before the SMCs read it on the target side. */
+ smp_wmb();
+
+ for_each_cpu(cpu, mask)
+ sdei_nmi_fire(cpu);
+
+ return true;
+}
+
/*
* device_initcall (after arch_initcall(sdei_init), so the SDEI subsystem
* is up): probe the firmware, register the event, and turn on the
--
2.54.0
^ permalink raw reply related
* [PATCH v2 2/3] drivers/firmware: add SDEI cross-CPU NMI service for arm64
From: Kiryl Shutsemau @ 2026-06-09 13:58 UTC (permalink / raw)
To: Catalin Marinas, Will Deacon, James Morse
Cc: Mark Rutland, Marc Zyngier, Doug Anderson, Petr Mladek,
Thomas Gleixner, Andrew Morton, Baoquan He, Puranjay Mohan,
Usama Arif, Breno Leitao, Julien Thierry, Lecopzer Chen,
Sumit Garg, kernel-team, kexec, linux-arm-kernel, linux-kernel,
Kiryl Shutsemau (Meta)
In-Reply-To: <cover.1781013134.git.kas@kernel.org>
From: "Kiryl Shutsemau (Meta)" <kas@kernel.org>
Deliver an NMI-like event to an interrupt-masked arm64 CPU via the
standard SDEI software-signalled event (event 0), without the pseudo-NMI
hot-path cost: register a handler for event 0 and poke a target with
sdei_event_signal(0, mpidr).
First user is arch_trigger_cpumask_backtrace() (sysrq-l, RCU stalls,
hung-task/soft-lockup dumps), which otherwise rides an IPI that can't
reach a masked CPU. Falls back to the IPI path when SDEI is absent; no
watchdog backend yet, so the stock detector is untouched.
Signed-off-by: Kiryl Shutsemau (Meta) <kas@kernel.org>
Reviewed-by: Douglas Anderson <dianders@chromium.org>
---
MAINTAINERS | 2 +-
arch/arm64/include/asm/nmi.h | 24 +++++
arch/arm64/kernel/smp.c | 11 +++
drivers/firmware/Kconfig | 19 ++++
drivers/firmware/Makefile | 1 +
drivers/firmware/arm_sdei_nmi.c | 149 ++++++++++++++++++++++++++++++++
6 files changed, 205 insertions(+), 1 deletion(-)
create mode 100644 arch/arm64/include/asm/nmi.h
create mode 100644 drivers/firmware/arm_sdei_nmi.c
diff --git a/MAINTAINERS b/MAINTAINERS
index b539be153f6a..c77ce32b9679 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -24794,7 +24794,7 @@ M: James Morse <james.morse@arm.com>
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
S: Maintained
F: Documentation/devicetree/bindings/arm/firmware/sdei.txt
-F: drivers/firmware/arm_sdei.c
+F: drivers/firmware/arm_sdei*
F: include/linux/arm_sdei.h
F: include/uapi/linux/arm_sdei.h
diff --git a/arch/arm64/include/asm/nmi.h b/arch/arm64/include/asm/nmi.h
new file mode 100644
index 000000000000..9366be419d18
--- /dev/null
+++ b/arch/arm64/include/asm/nmi.h
@@ -0,0 +1,24 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __ASM_NMI_H
+#define __ASM_NMI_H
+
+#include <linux/cpumask.h>
+
+/*
+ * Cross-CPU NMI provider hooks, consulted by the arm64 arch code before
+ * its regular-IRQ / pseudo-NMI IPI paths. The SDEI provider in
+ * drivers/firmware/arm_sdei_nmi.c implements them when active; a future
+ * FEAT_NMI provider could slot in here too. The stubs let callers stay
+ * unconditional when ARM_SDEI_NMI is off.
+ */
+#ifdef CONFIG_ARM_SDEI_NMI
+bool sdei_nmi_trigger_cpumask_backtrace(const cpumask_t *mask, int exclude_cpu);
+#else
+static inline bool sdei_nmi_trigger_cpumask_backtrace(const cpumask_t *mask,
+ int exclude_cpu)
+{
+ return false;
+}
+#endif
+
+#endif /* __ASM_NMI_H */
diff --git a/arch/arm64/kernel/smp.c b/arch/arm64/kernel/smp.c
index 1aa324104afb..a670434a8cae 100644
--- a/arch/arm64/kernel/smp.c
+++ b/arch/arm64/kernel/smp.c
@@ -45,6 +45,7 @@
#include <asm/daifflags.h>
#include <asm/kvm_mmu.h>
#include <asm/mmu_context.h>
+#include <asm/nmi.h>
#include <asm/numa.h>
#include <asm/processor.h>
#include <asm/smp_plat.h>
@@ -927,6 +928,16 @@ static void arm64_backtrace_ipi(cpumask_t *mask)
void arch_trigger_cpumask_backtrace(const cpumask_t *mask, int exclude_cpu)
{
+ /*
+ * Prefer the SDEI cross-CPU NMI provider when active: firmware
+ * dispatches the event out of EL3 and reaches CPUs that have
+ * interrupts locally masked, without the per-IRQ-mask cost that
+ * pseudo-NMI pays for the same reach. The plain IPI path below
+ * can't reach such a CPU unless pseudo-NMI is enabled.
+ */
+ if (sdei_nmi_trigger_cpumask_backtrace(mask, exclude_cpu))
+ return;
+
/*
* NOTE: though nmi_trigger_cpumask_backtrace() has "nmi_" in the name,
* nothing about it truly needs to be implemented using an NMI, it's
diff --git a/drivers/firmware/Kconfig b/drivers/firmware/Kconfig
index bbd2155d8483..6501087ff90d 100644
--- a/drivers/firmware/Kconfig
+++ b/drivers/firmware/Kconfig
@@ -36,6 +36,25 @@ config ARM_SDE_INTERFACE
standard for registering callbacks from the platform firmware
into the OS. This is typically used to implement RAS notifications.
+config ARM_SDEI_NMI
+ bool "SDEI-based cross-CPU NMI service (arm64)"
+ depends on ARM64 && ARM_SDE_INTERFACE
+ help
+ Provides SDEI-based cross-CPU NMI delivery for hooks that need
+ to reach interrupt-masked CPUs on silicon that lacks FEAT_NMI:
+
+ - arch_trigger_cpumask_backtrace() (sysrq-l, RCU stalls,
+ hardlockup_all_cpu_backtrace, soft-lockup secondary dumps,
+ hung-task auxiliary dumps)
+
+ The driver registers a handler for the SDEI software-signalled
+ event (event 0) and reaches a target CPU by signalling it with
+ SDEI_EVENT_SIGNAL. Firmware delivers the event out of EL3
+ regardless of the target's PSTATE.DAIF -- forced delivery into a
+ CPU wedged with interrupts locally masked.
+
+ If unsure, say N.
+
config EDD
tristate "BIOS Enhanced Disk Drive calls determine boot disk"
depends on X86
diff --git a/drivers/firmware/Makefile b/drivers/firmware/Makefile
index 4ddec2820c96..be46f1e1dc77 100644
--- a/drivers/firmware/Makefile
+++ b/drivers/firmware/Makefile
@@ -4,6 +4,7 @@
#
obj-$(CONFIG_ARM_SCPI_PROTOCOL) += arm_scpi.o
obj-$(CONFIG_ARM_SDE_INTERFACE) += arm_sdei.o
+obj-$(CONFIG_ARM_SDEI_NMI) += arm_sdei_nmi.o
obj-$(CONFIG_DMI) += dmi_scan.o
obj-$(CONFIG_DMI_SYSFS) += dmi-sysfs.o
obj-$(CONFIG_EDD) += edd.o
diff --git a/drivers/firmware/arm_sdei_nmi.c b/drivers/firmware/arm_sdei_nmi.c
new file mode 100644
index 000000000000..a82776e7b55a
--- /dev/null
+++ b/drivers/firmware/arm_sdei_nmi.c
@@ -0,0 +1,149 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * arm64 SDEI-based cross-CPU NMI service.
+ *
+ * Delivering an "NMI-shaped" event to an EL1 context that has locally
+ * masked interrupts, on silicon without FEAT_NMI, can be done two ways:
+ *
+ * - pseudo-NMI: mask "interrupts" via the GIC priority register
+ * (ICC_PMR_EL1) instead of PSTATE.DAIF, leaving a high-priority band
+ * deliverable. Functionally this works -- but it reimplements every
+ * local_irq_disable()/enable() and exception entry/exit as a PMR
+ * write plus synchronisation, a cost paid on that hot path forever,
+ * whether or not an NMI is ever delivered.
+ *
+ * - SDEI: leave interrupt masking as the cheap PSTATE.DAIF operation
+ * and have the firmware bounce an EL3-routed Group-0 SGI back to
+ * NS-EL1 as an event callback. The cost is a firmware round-trip,
+ * but only at the rare moment delivery is actually needed.
+ *
+ * This driver takes the second path: it keeps the IRQ-mask hot path
+ * free and pays only when it fires, which is what makes cross-CPU NMI
+ * affordable on hardware where the pseudo-NMI tax isn't, until FEAT_NMI
+ * makes NMI masking cheap in the architecture itself.
+ *
+ * Capabilities provided:
+ *
+ * - sdei_nmi_trigger_cpumask_backtrace() — override for arm64's
+ * arch_trigger_cpumask_backtrace(), so sysrq-l, RCU stall dumps,
+ * hardlockup_all_cpu_backtrace, soft-lockup/hung-task secondary
+ * dumps all reach interrupt-masked CPUs.
+ *
+ * Delivery uses the standard SDEI software-signalled event (event 0) and
+ * SDEI_EVENT_SIGNAL. We register a handler for event 0, enable it, and
+ * poke a target CPU with sdei_event_signal(0, mpidr): firmware makes
+ * event 0 pending on that PE and dispatches the handler NMI-like,
+ * regardless of the target's DAIF.
+ * Availability is simply whether event 0 registers and enables -- if SDEI
+ * and its software-signalled event are present we use it, otherwise the
+ * driver stays inert.
+ */
+
+#define pr_fmt(fmt) "sdei_nmi: " fmt
+
+#include <linux/arm_sdei.h>
+#include <linux/cpumask.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/kprobes.h>
+#include <linux/nmi.h>
+#include <linux/printk.h>
+#include <linux/ptrace.h>
+#include <linux/smp.h>
+#include <linux/types.h>
+
+#include <asm/nmi.h>
+#include <asm/smp_plat.h>
+
+static bool sdei_nmi_available;
+
+#define SDEI_NMI_EVENT 0
+
+static int sdei_nmi_handler(u32 event, struct pt_regs *regs, void *arg)
+{
+ /*
+ * nmi_cpu_backtrace() no-ops unless this CPU's bit is set in the
+ * global backtrace mask (driven by nmi_trigger_cpumask_backtrace()),
+ * so a fire that reaches a CPU not being backtraced is harmless.
+ */
+ nmi_cpu_backtrace(regs);
+ return SDEI_EV_HANDLED;
+}
+NOKPROBE_SYMBOL(sdei_nmi_handler);
+
+static void sdei_nmi_fire(unsigned int target_cpu)
+{
+ int err = sdei_event_signal(SDEI_NMI_EVENT, cpu_logical_map(target_cpu));
+
+ if (err)
+ pr_warn("SDEI_EVENT_SIGNAL to CPU %u failed: %d\n",
+ target_cpu, err);
+}
+
+/*
+ * Raise callback for nmi_trigger_cpumask_backtrace(): signal event 0
+ * at every CPU still pending in @mask. The framework excludes the local
+ * CPU from @mask before calling us.
+ */
+static void sdei_nmi_raise_backtrace(cpumask_t *mask)
+{
+ unsigned int cpu;
+
+ for_each_cpu(cpu, mask)
+ sdei_nmi_fire(cpu);
+}
+
+/*
+ * Override hook for arch_trigger_cpumask_backtrace() (see
+ * arch/arm64/kernel/smp.c). Returns true when SDEI handled the request,
+ * which is the case whenever SDEI is active; on a false return the arch
+ * falls back to its regular-IRQ (or pseudo-NMI, if enabled) IPI.
+ *
+ * On a kernel built without paying the pseudo-NMI hot-path cost (the
+ * usual case for this driver's target), the IPI can't reach a CPU that
+ * has interrupts masked -- so the backtrace of the one CPU you care
+ * about comes back empty. SDEI is dispatched out of EL3 and lands
+ * regardless of the target's DAIF, without taxing the IRQ-mask path.
+ */
+bool sdei_nmi_trigger_cpumask_backtrace(const cpumask_t *mask, int exclude_cpu)
+{
+ if (!sdei_nmi_available)
+ return false;
+
+ nmi_trigger_cpumask_backtrace(mask, exclude_cpu,
+ sdei_nmi_raise_backtrace);
+ return true;
+}
+
+/*
+ * device_initcall (after arch_initcall(sdei_init), so the SDEI subsystem
+ * is up): probe the firmware, register the event, and turn on the
+ * cross-CPU service. If the probe fails the driver stays inert and the
+ * override hooks decline, leaving the arch's own paths in place.
+ */
+static int __init sdei_nmi_init(void)
+{
+ int err;
+
+ err = sdei_event_register(SDEI_NMI_EVENT, sdei_nmi_handler, NULL);
+ if (err) {
+ pr_err("sdei_event_register(%u) failed: %d\n",
+ SDEI_NMI_EVENT, err);
+ return 0;
+ }
+
+ err = sdei_event_enable(SDEI_NMI_EVENT);
+ if (err) {
+ pr_err("sdei_event_enable(%u) failed: %d\n",
+ SDEI_NMI_EVENT, err);
+ sdei_event_unregister(SDEI_NMI_EVENT);
+ return 0;
+ }
+
+ sdei_nmi_available = true;
+ pr_info("using SDEI cross-CPU NMI (SDEI_EVENT_SIGNAL, event %u)\n",
+ SDEI_NMI_EVENT);
+
+ return 0;
+}
+device_initcall(sdei_nmi_init);
--
2.54.0
^ permalink raw reply related
* Re: [GIT PULL] Allwinner DT Changes for 7.2
From: Chen-Yu Tsai @ 2026-06-09 14:02 UTC (permalink / raw)
To: Paul Kocialkowski
Cc: Krzysztof Kozlowski, soc, Jernej Skrabec, Samuel Holland,
linux-sunxi, linux-arm-kernel
In-Reply-To: <aigZP9W6AWzde2qo@collins>
On Tue, Jun 9, 2026 at 10:46 PM Paul Kocialkowski <paulk@sys-base.io> wrote:
>
> Hi,
>
> Le Tue 09 Jun 26, 22:26, Chen-Yu Tsai a écrit :
> > On Tue, Jun 9, 2026 at 10:18 PM Krzysztof Kozlowski <krzk@kernel.org> wrote:
> > >
> > > On 09/06/2026 14:38, Chen-Yu Tsai wrote:
> > > > On Tue, Jun 9, 2026 at 8:51 PM Krzysztof Kozlowski <krzk@kernel.org> wrote:
> > > >>
> > > >> On 09/06/2026 13:48, Chen-Yu Tsai wrote:
> > > >>> On Tue, Jun 9, 2026 at 8:43 PM Krzysztof Kozlowski <krzk@kernel.org> wrote:
> > > >>>>
> > > >>>> On Tue, Jun 02, 2026 at 03:09:52AM +0800, Chen-Yu Tsai wrote:
> > > >>>>> The following changes since commit 254f49634ee16a731174d2ae34bc50bd5f45e731:
> > > >>>>>
> > > >>>>> Linux 7.1-rc1 (2026-04-26 14:19:00 -0700)
> > > >>>>>
> > > >>>>> are available in the Git repository at:
> > > >>>>>
> > > >>>>> https://git.kernel.org/pub/scm/linux/kernel/git/sunxi/linux.git tags/sunxi-dt-for-7.2
> > > >>>>>
> > > >>>>> for you to fetch changes up to 44cf19e41c769720750dbb8752aca75c247e565f:
> > > >>>>>
> > > >>>>> arm64: dts: allwinner: a523: add gpadc node (2026-05-25 05:02:58 +0800)
> > > >>>>>
> > > >>>>>
> > > >>>>> As mentioned in the tag, this pull request contains a change that should
> > > >>>>> be shared between the soc and clk trees. However since I don't have any
> > > >>>>> clk changes to send this cycle, I think it can just go through the soc
> > > >>>>> tree without any issues.
> > > >>>>
> > > >>>> But the clock driver change cannot be in the DTS branch. This should go
> > > >>>> via clock tree even if it is one change. And definitely not via DTS
> > > >>>> branch.
> > > >>>
> > > >>> It is a shared change, because it moves two symbols from the driver's
> > > >>> private header to the public DT binding header. I don't see how this
> > > >>> can go through just the clk tree when one of the subsequent patches
> > > >>> uses those new symbols.
> > > >>>
> > > >>> "clk: sunxi-ng: v3s: Export MBUS and DRAM clocks to the public header"
> > > >>> is needed by "ARM: dts: sun8i: v3s: Add mbus node to represent the
> > > >>> interconnect".
> > > >>>
> > > >>> The other way to go about this is to use raw numbers first, then
> > > >>> another patch in the next cycle to switch the numbers to actual
> > > >>> macros. IMHO not worth the churn and headache.
> > > >>
> > > >> You can have a duplicated define.
> > > >
> > > > I honestly did not know that it worked.
> > > >
> > > > However, splitting what is effectively one logical change (*move*
> > > > something) into two patches just to be able to merge them through two
> > > > separate trees still seems wrong to me.
> > >
> > > It is not really one logical change. Defining a new ABI (binding header
> > > define) is considered one change. Merging binding change into driver
> > > commit breaks rule of splitting bindings from implementation.
> > >
> > > Second rule is that DTS branch CANNOT take driver changes. So if you do
> > > not want to adhere to the above rule you still cannot combine it into
> > > DTS branch.
> >
> > Very well. I will drop the two changes and send a revised pull request.
> >
> > Paul, can you redo the clk changes as requested in the next cycle?
>
> Sure, so if I understand correctly, commit:
> clk: sunxi-ng: v3s: Export MBUS and DRAM clocks to the public headersunxi
>
> should be split into two, one adding the definitions to the dt-bindings
> headers first and a second one removing them from the clk driver?
Correct.
> Can it still make it for 7.2?
If you send it out soon, then maybe I can send both in a PR to Stephen.
But the v3s dts patch is not going to make it.
ChenYu
^ permalink raw reply
* Re: [PATCH v6 14/20] dma-direct: return struct page from dma_direct_alloc_from_pool()
From: Jason Gunthorpe @ 2026-06-09 14:15 UTC (permalink / raw)
To: Aneesh Kumar K.V (Arm)
Cc: iommu, linux-arm-kernel, linux-kernel, linux-coco, Robin Murphy,
Marek Szyprowski, Will Deacon, Marc Zyngier, Steven Price,
Suzuki K Poulose, Catalin Marinas, Jiri Pirko, Mostafa Saleh,
Petr Tesarik, Alexey Kardashevskiy, Dan Williams, Xu Yilun,
linuxppc-dev, linux-s390, Madhavan Srinivasan, Michael Ellerman,
Nicholas Piggin, Christophe Leroy (CS GROUP), Alexander Gordeev,
Gerald Schaefer, Heiko Carstens, Vasily Gorbik,
Christian Borntraeger, Sven Schnelle, x86, stable, Michael Kelley
In-Reply-To: <20260604083959.1265923-15-aneesh.kumar@kernel.org>
On Thu, Jun 04, 2026 at 02:09:53PM +0530, Aneesh Kumar K.V (Arm) wrote:
> @@ -270,9 +270,12 @@ void *dma_direct_alloc(struct device *dev, size_t size,
> * the atomic pools instead if we aren't allowed block.
> */
> if ((remap || (attrs & DMA_ATTR_CC_SHARED)) &&
> - dma_direct_use_pool(dev, gfp))
> - return dma_direct_alloc_from_pool(dev, size, dma_handle,
> - gfp, attrs);
> + dma_direct_use_pool(dev, gfp)) {
> + page = dma_direct_alloc_from_pool(dev, size,
> + dma_handle, &cpu_addr,
> + gfp, attrs);
> + return page ? cpu_addr : NULL;
> + }
You should probably put this at the start of the series so it can be
backported
Reviewed-by: Jason Gunthorpe <jgg@nvidia.com>
To Petr's question I think this just shows nobody is really stressing
the PCI dma paths on CC VMs today.
if (force_dma_unencrypted(dev) && dma_direct_use_pool(dev, gfp))
return dma_direct_alloc_from_pool(dev, size, dma_handle, gfp);
For instance the places even calling dma_alloc_pages() don't look like
things people would use in a CC VM.
Jason
^ permalink raw reply
* Re: [PATCH 0/3] i2c: xiic: fix SMBus block read and PEC support
From: Shubhrajyoti Datta @ 2026-06-09 14:26 UTC (permalink / raw)
To: abdurrahman
Cc: Michal Simek, Andi Shyti, linux-arm-kernel, linux-i2c,
linux-kernel
In-Reply-To: <20260427-i2c-xiic-v1-0-e6207f9aa5ad@nexthop.ai>
On Tue, Apr 28, 2026 at 5:48 AM Abdurrahman Hussain via B4 Relay
<devnull+abdurrahman.nexthop.ai@kernel.org> wrote:
>
> This series fixes three independent bugs in the Xilinx AXI IIC driver
> that together make SMBus block reads with PEC return -EBADMSG or -EIO
> on otherwise clean transfers. They only surface when the client has
> I2C_CLIENT_PEC set; non-PEC block reads happen to mask each issue in
> turn.
>
> The problems were uncovered driving an adm1266 PMBus device behind a
> Xilinx AXI IIC FPGA block and reading its 64-byte blackbox record.
>
> Patch 1 stops xiic_smbus_block_read_setup() from truncating rx_msg->len.
> The i2c core appends a byte to msg->len when PEC is enabled, so
> overwriting the length to "block size + 1" silently drops the PEC byte
> and i2c_smbus_check_pec() then reads the last payload byte as the PEC.
>
> Patch 2 raises the RX_FULL threshold so the interrupt only fires once
> every remaining byte (payload plus optional PEC) is already buffered in
> the FIFO. The previous threshold of rxmsg_len - 2 caused the
> bytes_rem == 1 path in xiic_read_rx() to NACK a byte still on the wire.
>
> Patch 3 stops the BNB handler from forcing tx_msg->len = 1 to signal
> completion. tx_msg and rx_msg alias the same i2c_msg during a receive,
> so this also clobbered rx_msg->len; and because tx_pos is already at 2
> in the PEC case, the unsigned subtraction in xiic_tx_space() underflowed
> and the STATE_DONE check fell through to STATE_ERROR. Advancing tx_pos
> up to msg->len drives tx_space to zero without touching the length.
>
> All three patches are pure bug fixes; non-PEC behaviour is unchanged.
> Tested on real hardware -- a Xilinx AXI IIC controller talking to an
> adm1266, where 64-byte PEC-checked block reads now complete cleanly.
>
> Signed-off-by: Abdurrahman Hussain <abdurrahman@nexthop.ai>
LGTM
Reviewed-by: Shubhrajyoti Datta <shubhrajyoti.datta@amd.com>
^ permalink raw reply
* [PATCH v5 0/8] can: flexcan: Add NXP S32N79 SoC support
From: Ciprian Costea @ 2026-06-09 14:29 UTC (permalink / raw)
To: Marc Kleine-Budde, Vincent Mailhol, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Frank Li, Sascha Hauer,
Fabio Estevam
Cc: Pengutronix Kernel Team, linux-can, devicetree, linux-kernel, imx,
linux-arm-kernel, NXP S32 Linux Team, Christophe Lizzi,
Alberto Ruiz, Enric Balletbo, Eric Chanudet,
Ciprian Marian Costea
From: Ciprian Marian Costea <ciprianmarian.costea@oss.nxp.com>
This patch series adds FlexCAN support for the NXP S32N79 SoC.
The S32N79 is an automotive-grade processor from NXP with multiple
FlexCAN instances. The FlexCAN IP integration on S32N79 differs from
other SoCs in the interrupt routing - it uses two separate interrupt
lines:
- one interrupt for mailboxes 0-127
- one interrupt for bus error detection and device state changes
The CAN controllers are connected through an irqsteer interrupt
controller in the RCU (Resource Control Unit) domain.
This series:
1. Splits flexcan_irq() into dedicated handlers for multi-IRQ platforms
2. Adds dt-bindings documentation for S32N79 FlexCAN
3. Introduces FLEXCAN_QUIRK_IRQ_BERR to handle the two-interrupt
configuration
4. Adds S32N79 device data and compatible string to the driver
5. Adds FlexCAN device tree nodes for S32N79 SoC
6. Enables FlexCAN devices on the S32N79-RDB board
Tested on S32N79-RDB board with CAN and CAN FD communication.
v5 -> v4
- Simplified splitting rx/tx masks per mailbox IRQ line
v4 -> v3
- flexcan_chip_interrupts_enable(): disable/enable all IRQ lines
(not just dev->irq) during IMASK register writes
- Split rx/tx masks per mailbox IRQ line (struct flexcan_mb_irq) so
each handler on S32G2 only processes its own MB range
- Added received Acked-by tag on DT bindings patch
v3 -> v2
- Split flexcan_irq() into dedicated handlers (flexcan_irq_mb,
flexcan_irq_boff, flexcan_irq_berr) to fix duplicate event
processing when multiple IRQ lines run concurrently (new patch).
- Added flexcan_irq_esr() handler composing state + berr for S32N79
- Ordered quirks used by s32n devtype data by value.
v2 -> v1
- Renamed FLEXCAN_QUIRK_NR_IRQ_2 to FLEXCAN_QUIRK_IRQ_BERR to better
describe the actual hardware feature
- Appended new quirk at the end
- Switched from platform_get_irq to platform_get_irq_byname usage
- Updated interrupt description in dt-bindings
Ciprian Marian Costea (8):
can: flexcan: use dedicated IRQ handlers for multi-IRQ platforms
can: flexcan: disable all IRQ lines in
flexcan_chip_interrupts_enable()
can: flexcan: split rx/tx masks per mailbox IRQ line
dt-bindings: can: fsl,flexcan: add NXP S32N79 SoC support
can: flexcan: add FLEXCAN_QUIRK_IRQ_BERR quirk
can: flexcan: add NXP S32N79 SoC support
arm64: dts: s32n79: add FlexCAN nodes
arm64: dts: s32n79: enable FlexCAN devices
.../bindings/net/can/fsl,flexcan.yaml | 30 ++-
arch/arm64/boot/dts/freescale/s32n79-rdb.dts | 12 +
arch/arm64/boot/dts/freescale/s32n79.dtsi | 50 ++++
drivers/net/can/flexcan/flexcan-core.c | 227 +++++++++++++++---
drivers/net/can/flexcan/flexcan.h | 2 +
5 files changed, 292 insertions(+), 29 deletions(-)
--
2.43.0
^ permalink raw reply
* [PATCH v5 1/8] can: flexcan: use dedicated IRQ handlers for multi-IRQ platforms
From: Ciprian Costea @ 2026-06-09 14:29 UTC (permalink / raw)
To: Marc Kleine-Budde, Vincent Mailhol, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Frank Li, Sascha Hauer,
Fabio Estevam
Cc: Pengutronix Kernel Team, linux-can, devicetree, linux-kernel, imx,
linux-arm-kernel, NXP S32 Linux Team, Christophe Lizzi,
Alberto Ruiz, Enric Balletbo, Eric Chanudet,
Ciprian Marian Costea, Haibo Chen
In-Reply-To: <20260609142954.1807421-1-ciprianmarian.costea@oss.nxp.com>
From: Ciprian Marian Costea <ciprianmarian.costea@oss.nxp.com>
On platforms with multiple IRQ lines (S32G2, MCF5441X), all lines are
registered to the same flexcan_irq() handler. Since these are distinct IRQ
numbers, they can be dispatched concurrently on different CPUs. Both
instances then read the same iflag and ESR registers unconditionally,
leading to duplicate frame processing.
Fix this by splitting the monolithic handler into focused parts:
- flexcan_do_mb(): processes mailbox events
- flexcan_do_state(): processes device state change events
- flexcan_do_berr(): processes bus error events
Introduce dedicated IRQ handlers for multi-IRQ platforms:
- flexcan_irq_mb(): mailbox-only, used for mb-0, mb-1 IRQ lines
- flexcan_irq_boff(): state-change-only, used for boff/state IRQ line
- flexcan_irq_berr(): bus-error-only, used for berr IRQ line
The combined flexcan_irq() handler is preserved for single-IRQ
platforms with no functional change.
Fixes: d9cead75b1c6 ("can: flexcan: add mcf5441x support")
Signed-off-by: Ciprian Marian Costea <ciprianmarian.costea@oss.nxp.com>
Reviewed-and-tested-by: Haibo Chen <haibo.chen@nxp.com>
Tested-by: Enric Balletbo i Serra <eballetb@redhat.com>
---
drivers/net/can/flexcan/flexcan-core.c | 128 +++++++++++++++++++++----
1 file changed, 111 insertions(+), 17 deletions(-)
diff --git a/drivers/net/can/flexcan/flexcan-core.c b/drivers/net/can/flexcan/flexcan-core.c
index f5d22c61503f..f73ff442d530 100644
--- a/drivers/net/can/flexcan/flexcan-core.c
+++ b/drivers/net/can/flexcan/flexcan-core.c
@@ -1070,16 +1070,14 @@ static struct sk_buff *flexcan_mailbox_read(struct can_rx_offload *offload,
return skb;
}
-static irqreturn_t flexcan_irq(int irq, void *dev_id)
+/* Process mailbox (RX + TX) events */
+static irqreturn_t flexcan_do_mb(struct net_device *dev)
{
- struct net_device *dev = dev_id;
struct net_device_stats *stats = &dev->stats;
struct flexcan_priv *priv = netdev_priv(dev);
struct flexcan_regs __iomem *regs = priv->regs;
irqreturn_t handled = IRQ_NONE;
u64 reg_iflag_tx;
- u32 reg_esr;
- enum can_state last_state = priv->can.state;
/* reception interrupt */
if (priv->devtype_data.quirks & FLEXCAN_QUIRK_USE_RX_MAILBOX) {
@@ -1131,25 +1129,57 @@ static irqreturn_t flexcan_irq(int irq, void *dev_id)
netif_wake_queue(dev);
}
+ return handled;
+}
+
+/* Process bus error events */
+static irqreturn_t flexcan_do_berr(struct net_device *dev)
+{
+ struct flexcan_priv *priv = netdev_priv(dev);
+ struct flexcan_regs __iomem *regs = priv->regs;
+ irqreturn_t handled = IRQ_NONE;
+ u32 reg_esr;
+
reg_esr = priv->read(®s->esr);
- /* ACK all bus error, state change and wake IRQ sources */
- if (reg_esr & (FLEXCAN_ESR_ALL_INT | FLEXCAN_ESR_WAK_INT)) {
+ /* ACK bus error interrupt source */
+ if (reg_esr & FLEXCAN_ESR_ERR_INT) {
handled = IRQ_HANDLED;
- priv->write(reg_esr & (FLEXCAN_ESR_ALL_INT | FLEXCAN_ESR_WAK_INT), ®s->esr);
+ priv->write(FLEXCAN_ESR_ERR_INT, ®s->esr);
}
- /* state change interrupt or broken error state quirk fix is enabled */
- if ((reg_esr & FLEXCAN_ESR_ERR_STATE) ||
- (priv->devtype_data.quirks & (FLEXCAN_QUIRK_BROKEN_WERR_STATE |
- FLEXCAN_QUIRK_BROKEN_PERR_STATE)))
- flexcan_irq_state(dev, reg_esr);
-
/* bus error IRQ - handle if bus error reporting is activated */
if ((reg_esr & FLEXCAN_ESR_ERR_BUS) &&
(priv->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING))
flexcan_irq_bus_err(dev, reg_esr);
+ return handled;
+}
+
+/* Process device state change events */
+static irqreturn_t flexcan_do_state(struct net_device *dev)
+{
+ struct flexcan_priv *priv = netdev_priv(dev);
+ struct flexcan_regs __iomem *regs = priv->regs;
+ irqreturn_t handled = IRQ_NONE;
+ u32 reg_esr;
+ enum can_state last_state = priv->can.state;
+
+ reg_esr = priv->read(®s->esr);
+
+ /* ACK state change and wake IRQ sources */
+ if (reg_esr & (FLEXCAN_ESR_ERR_STATE | FLEXCAN_ESR_WAK_INT)) {
+ handled = IRQ_HANDLED;
+ priv->write(reg_esr & (FLEXCAN_ESR_ERR_STATE | FLEXCAN_ESR_WAK_INT),
+ ®s->esr);
+ }
+
+ /* state change interrupt or broken error state quirk fix is enabled */
+ if ((reg_esr & FLEXCAN_ESR_ERR_STATE) ||
+ (priv->devtype_data.quirks &
+ (FLEXCAN_QUIRK_BROKEN_WERR_STATE | FLEXCAN_QUIRK_BROKEN_PERR_STATE)))
+ flexcan_irq_state(dev, reg_esr);
+
/* availability of error interrupt among state transitions in case
* bus error reporting is de-activated and
* FLEXCAN_QUIRK_BROKEN_PERR_STATE is enabled:
@@ -1188,6 +1218,65 @@ static irqreturn_t flexcan_irq(int irq, void *dev_id)
}
}
+ return handled;
+}
+
+/* Combined IRQ handler for single-IRQ platforms */
+static irqreturn_t flexcan_irq(int irq, void *dev_id)
+{
+ struct net_device *dev = dev_id;
+ struct flexcan_priv *priv = netdev_priv(dev);
+ irqreturn_t handled;
+
+ handled = flexcan_do_mb(dev);
+ handled |= flexcan_do_state(dev);
+ handled |= flexcan_do_berr(dev);
+
+ if (handled)
+ can_rx_offload_irq_finish(&priv->offload);
+
+ return handled;
+}
+
+/* Mailbox IRQ handler for multi-IRQ platforms */
+static irqreturn_t flexcan_irq_mb(int irq, void *dev_id)
+{
+ struct net_device *dev = dev_id;
+ struct flexcan_priv *priv = netdev_priv(dev);
+ irqreturn_t handled;
+
+ handled = flexcan_do_mb(dev);
+
+ if (handled)
+ can_rx_offload_irq_finish(&priv->offload);
+
+ return handled;
+}
+
+/* Bus error IRQ handler for multi-IRQ platforms */
+static irqreturn_t flexcan_irq_berr(int irq, void *dev_id)
+{
+ struct net_device *dev = dev_id;
+ struct flexcan_priv *priv = netdev_priv(dev);
+ irqreturn_t handled;
+
+ handled = flexcan_do_berr(dev);
+
+ if (handled)
+ can_rx_offload_irq_finish(&priv->offload);
+
+ return handled;
+}
+
+/* Device state change IRQ handler for multi-IRQ platforms */
+static irqreturn_t flexcan_irq_boff(int irq, void *dev_id)
+{
+ struct net_device *dev = dev_id;
+ struct flexcan_priv *priv = netdev_priv(dev);
+ irqreturn_t handled;
+
+ handled = flexcan_do_state(dev);
+
if (handled)
can_rx_offload_irq_finish(&priv->offload);
@@ -1761,25 +1850,30 @@ static int flexcan_open(struct net_device *dev)
can_rx_offload_enable(&priv->offload);
- err = request_irq(dev->irq, flexcan_irq, IRQF_SHARED, dev->name, dev);
+ if (priv->devtype_data.quirks & FLEXCAN_QUIRK_NR_IRQ_3)
+ err = request_irq(dev->irq, flexcan_irq_mb,
+ IRQF_SHARED, dev->name, dev);
+ else
+ err = request_irq(dev->irq, flexcan_irq,
+ IRQF_SHARED, dev->name, dev);
if (err)
goto out_can_rx_offload_disable;
if (priv->devtype_data.quirks & FLEXCAN_QUIRK_NR_IRQ_3) {
err = request_irq(priv->irq_boff,
- flexcan_irq, IRQF_SHARED, dev->name, dev);
+ flexcan_irq_boff, IRQF_SHARED, dev->name, dev);
if (err)
goto out_free_irq;
err = request_irq(priv->irq_err,
- flexcan_irq, IRQF_SHARED, dev->name, dev);
+ flexcan_irq_berr, IRQF_SHARED, dev->name, dev);
if (err)
goto out_free_irq_boff;
}
if (priv->devtype_data.quirks & FLEXCAN_QUIRK_SECONDARY_MB_IRQ) {
err = request_irq(priv->irq_secondary_mb,
- flexcan_irq, IRQF_SHARED, dev->name, dev);
+ flexcan_irq_mb, IRQF_SHARED, dev->name, dev);
if (err)
goto out_free_irq_err;
}
--
2.43.0
^ permalink raw reply related
* [PATCH v5 2/8] can: flexcan: disable all IRQ lines in flexcan_chip_interrupts_enable()
From: Ciprian Costea @ 2026-06-09 14:29 UTC (permalink / raw)
To: Marc Kleine-Budde, Vincent Mailhol, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Frank Li, Sascha Hauer,
Fabio Estevam
Cc: Pengutronix Kernel Team, linux-can, devicetree, linux-kernel, imx,
linux-arm-kernel, NXP S32 Linux Team, Christophe Lizzi,
Alberto Ruiz, Enric Balletbo, Eric Chanudet,
Ciprian Marian Costea, Haibo Chen
In-Reply-To: <20260609142954.1807421-1-ciprianmarian.costea@oss.nxp.com>
From: Ciprian Marian Costea <ciprianmarian.costea@oss.nxp.com>
flexcan_chip_interrupts_enable() disables only the primary IRQ line while
writing to the IMASK and CTRL registers.
On multi-IRQ platforms (S32G2, MCF5441X), the additional IRQ lines (boff,
err, secondary-mb) remain active so their handlers can fire while
registers are inconsistent.
Disable all registered IRQ lines around the IMASK/CTRL writes. This
also fixes the resume path, which calls this function.
Signed-off-by: Ciprian Marian Costea <ciprianmarian.costea@oss.nxp.com>
Reviewed-and-tested-by: Haibo Chen <haibo.chen@nxp.com>
Tested-by: Enric Balletbo i Serra <eballetb@redhat.com>
---
drivers/net/can/flexcan/flexcan-core.c | 14 ++++++++++++++
1 file changed, 14 insertions(+)
diff --git a/drivers/net/can/flexcan/flexcan-core.c b/drivers/net/can/flexcan/flexcan-core.c
index f73ff442d530..7dde2e623def 100644
--- a/drivers/net/can/flexcan/flexcan-core.c
+++ b/drivers/net/can/flexcan/flexcan-core.c
@@ -1519,14 +1519,28 @@ static void flexcan_chip_interrupts_enable(const struct net_device *dev)
{
const struct flexcan_priv *priv = netdev_priv(dev);
struct flexcan_regs __iomem *regs = priv->regs;
+ u32 quirks = priv->devtype_data.quirks;
u64 reg_imask;
disable_irq(dev->irq);
+ if (quirks & FLEXCAN_QUIRK_NR_IRQ_3) {
+ disable_irq(priv->irq_boff);
+ disable_irq(priv->irq_err);
+ }
+ if (quirks & FLEXCAN_QUIRK_SECONDARY_MB_IRQ)
+ disable_irq(priv->irq_secondary_mb);
+
priv->write(priv->reg_ctrl_default, ®s->ctrl);
reg_imask = priv->rx_mask | priv->tx_mask;
priv->write(upper_32_bits(reg_imask), ®s->imask2);
priv->write(lower_32_bits(reg_imask), ®s->imask1);
enable_irq(dev->irq);
+ if (quirks & FLEXCAN_QUIRK_SECONDARY_MB_IRQ)
+ enable_irq(priv->irq_secondary_mb);
+ if (quirks & FLEXCAN_QUIRK_NR_IRQ_3) {
+ enable_irq(priv->irq_boff);
+ enable_irq(priv->irq_err);
+ }
}
static void flexcan_chip_interrupts_disable(const struct net_device *dev)
--
2.43.0
^ permalink raw reply related
* [PATCH v5 3/8] can: flexcan: split rx/tx masks per mailbox IRQ line
From: Ciprian Costea @ 2026-06-09 14:29 UTC (permalink / raw)
To: Marc Kleine-Budde, Vincent Mailhol, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Frank Li, Sascha Hauer,
Fabio Estevam
Cc: Pengutronix Kernel Team, linux-can, devicetree, linux-kernel, imx,
linux-arm-kernel, NXP S32 Linux Team, Christophe Lizzi,
Alberto Ruiz, Enric Balletbo, Eric Chanudet,
Ciprian Marian Costea, Haibo Chen
In-Reply-To: <20260609142954.1807421-1-ciprianmarian.costea@oss.nxp.com>
From: Ciprian Marian Costea <ciprianmarian.costea@oss.nxp.com>
On S32G2, which has two mailbox IRQ lines (mb-0 for MBs 0-7, mb-1
for MBs 8-63), both handlers currently process the full rx_mask/tx_mask
range.
Introduce FLEXCAN_SECONDARY_MB_IRQ_MB0_MASK and
FLEXCAN_SECONDARY_MB_IRQ_MB1_MASK to describe the split, and pass
the selected mask to flexcan_do_mb() via a new mb_mask parameter.
In flexcan_irq_mb(), the irq argument selects the correct mask: the
primary MB IRQ uses MB0_MASK and the secondary uses MB1_MASK.
For single-IRQ platforms, mb_mask is ~0ULL with no functional change.
Signed-off-by: Ciprian Marian Costea <ciprianmarian.costea@oss.nxp.com>
Reviewed-and-tested-by: Haibo Chen <haibo.chen@nxp.com>
Tested-by: Enric Balletbo i Serra <eballetb@redhat.com>
---
drivers/net/can/flexcan/flexcan-core.c | 39 ++++++++++++++++++--------
1 file changed, 28 insertions(+), 11 deletions(-)
diff --git a/drivers/net/can/flexcan/flexcan-core.c b/drivers/net/can/flexcan/flexcan-core.c
index 7dde2e623def..0ed838f0719a 100644
--- a/drivers/net/can/flexcan/flexcan-core.c
+++ b/drivers/net/can/flexcan/flexcan-core.c
@@ -182,6 +182,12 @@
#define FLEXCAN_IFLAG_RX_FIFO_WARN BIT(6)
#define FLEXCAN_IFLAG_RX_FIFO_AVAILABLE BIT(5)
+/* On platforms with FLEXCAN_QUIRK_SECONDARY_MB_IRQ, the MB IRQ lines are
+ * split.
+ */
+#define FLEXCAN_SECONDARY_MB_IRQ_MB0_MASK GENMASK_ULL(7, 0)
+#define FLEXCAN_SECONDARY_MB_IRQ_MB1_MASK GENMASK_ULL(63, 8)
+
/* FLEXCAN message buffers */
#define FLEXCAN_MB_CODE_MASK (0xf << 24)
#define FLEXCAN_MB_CODE_RX_BUSY_BIT (0x1 << 24)
@@ -957,14 +963,16 @@ static inline void flexcan_write64(struct flexcan_priv *priv, u64 val, void __io
priv->write(lower_32_bits(val), addr);
}
-static inline u64 flexcan_read_reg_iflag_rx(struct flexcan_priv *priv)
+static inline u64 flexcan_read_reg_iflag_rx(struct flexcan_priv *priv,
+ u64 rx_mask)
{
- return flexcan_read64_mask(priv, &priv->regs->iflag1, priv->rx_mask);
+ return flexcan_read64_mask(priv, &priv->regs->iflag1, rx_mask);
}
-static inline u64 flexcan_read_reg_iflag_tx(struct flexcan_priv *priv)
+static inline u64 flexcan_read_reg_iflag_tx(struct flexcan_priv *priv,
+ u64 tx_mask)
{
- return flexcan_read64_mask(priv, &priv->regs->iflag1, priv->tx_mask);
+ return flexcan_read64_mask(priv, &priv->regs->iflag1, tx_mask);
}
static inline struct flexcan_priv *rx_offload_to_priv(struct can_rx_offload *offload)
@@ -1071,12 +1079,14 @@ static struct sk_buff *flexcan_mailbox_read(struct can_rx_offload *offload,
}
/* Process mailbox (RX + TX) events */
-static irqreturn_t flexcan_do_mb(struct net_device *dev)
+static irqreturn_t flexcan_do_mb(struct net_device *dev, u64 mb_mask)
{
struct net_device_stats *stats = &dev->stats;
struct flexcan_priv *priv = netdev_priv(dev);
struct flexcan_regs __iomem *regs = priv->regs;
irqreturn_t handled = IRQ_NONE;
+ u64 rx_mask = priv->rx_mask & mb_mask;
+ u64 tx_mask = priv->tx_mask & mb_mask;
u64 reg_iflag_tx;
/* reception interrupt */
@@ -1084,7 +1094,8 @@ static irqreturn_t flexcan_do_mb(struct net_device *dev)
u64 reg_iflag_rx;
int ret;
- while ((reg_iflag_rx = flexcan_read_reg_iflag_rx(priv))) {
+ while ((reg_iflag_rx = flexcan_read_reg_iflag_rx(priv,
+ rx_mask))) {
handled = IRQ_HANDLED;
ret = can_rx_offload_irq_offload_timestamp(&priv->offload,
reg_iflag_rx);
@@ -1110,10 +1121,10 @@ static irqreturn_t flexcan_do_mb(struct net_device *dev)
}
}
- reg_iflag_tx = flexcan_read_reg_iflag_tx(priv);
+ reg_iflag_tx = flexcan_read_reg_iflag_tx(priv, tx_mask);
/* transmission complete interrupt */
- if (reg_iflag_tx & priv->tx_mask) {
+ if (reg_iflag_tx & tx_mask) {
u32 reg_ctrl = priv->read(&priv->tx_mb->can_ctrl);
handled = IRQ_HANDLED;
@@ -1125,7 +1136,7 @@ static irqreturn_t flexcan_do_mb(struct net_device *dev)
/* after sending a RTR frame MB is in RX mode */
priv->write(FLEXCAN_MB_CODE_TX_INACTIVE,
&priv->tx_mb->can_ctrl);
- flexcan_write64(priv, priv->tx_mask, ®s->iflag1);
+ flexcan_write64(priv, tx_mask, ®s->iflag1);
netif_wake_queue(dev);
}
@@ -1228,7 +1239,7 @@ static irqreturn_t flexcan_irq(int irq, void *dev_id)
struct flexcan_priv *priv = netdev_priv(dev);
irqreturn_t handled;
- handled = flexcan_do_mb(dev);
+ handled = flexcan_do_mb(dev, ~0ULL);
handled |= flexcan_do_state(dev);
handled |= flexcan_do_berr(dev);
@@ -1244,8 +1255,14 @@ static irqreturn_t flexcan_irq_mb(int irq, void *dev_id)
struct net_device *dev = dev_id;
struct flexcan_priv *priv = netdev_priv(dev);
irqreturn_t handled;
+ u64 mb_mask = ~0ULL;
+
+ if (priv->devtype_data.quirks & FLEXCAN_QUIRK_SECONDARY_MB_IRQ)
+ mb_mask = (irq == priv->irq_secondary_mb) ?
+ FLEXCAN_SECONDARY_MB_IRQ_MB1_MASK :
+ FLEXCAN_SECONDARY_MB_IRQ_MB0_MASK;
- handled = flexcan_do_mb(dev);
+ handled = flexcan_do_mb(dev, mb_mask);
if (handled)
can_rx_offload_irq_finish(&priv->offload);
--
2.43.0
^ permalink raw reply related
* [PATCH v5 4/8] dt-bindings: can: fsl,flexcan: add NXP S32N79 SoC support
From: Ciprian Costea @ 2026-06-09 14:29 UTC (permalink / raw)
To: Marc Kleine-Budde, Vincent Mailhol, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Frank Li, Sascha Hauer,
Fabio Estevam
Cc: Pengutronix Kernel Team, linux-can, devicetree, linux-kernel, imx,
linux-arm-kernel, NXP S32 Linux Team, Christophe Lizzi,
Alberto Ruiz, Enric Balletbo, Eric Chanudet,
Ciprian Marian Costea, Andra-Teodora Ilie, Larisa Grigore,
Conor Dooley, Haibo Chen
In-Reply-To: <20260609142954.1807421-1-ciprianmarian.costea@oss.nxp.com>
From: Ciprian Marian Costea <ciprianmarian.costea@oss.nxp.com>
Add NXP S32N79 SoC compatible string and interrupt properties.
On S32N79, FlexCAN IP is integrated with two interrupt lines:
one for the mailbox interrupts (0-127) and one for signaling
bus errors and device state changes.
Co-developed-by: Andra-Teodora Ilie <andra.ilie@nxp.com>
Signed-off-by: Andra-Teodora Ilie <andra.ilie@nxp.com>
Co-developed-by: Larisa Grigore <larisa.grigore@nxp.com>
Signed-off-by: Larisa Grigore <larisa.grigore@nxp.com>
Signed-off-by: Ciprian Marian Costea <ciprianmarian.costea@oss.nxp.com>
Acked-by: Conor Dooley <conor.dooley@microchip.com>
Reviewed-and-tested-by: Haibo Chen <haibo.chen@nxp.com>
Tested-by: Enric Balletbo i Serra <eballetb@redhat.com>
---
.../bindings/net/can/fsl,flexcan.yaml | 30 ++++++++++++++++++-
1 file changed, 29 insertions(+), 1 deletion(-)
diff --git a/Documentation/devicetree/bindings/net/can/fsl,flexcan.yaml b/Documentation/devicetree/bindings/net/can/fsl,flexcan.yaml
index f81d56f7c12a..d098a44c2b9c 100644
--- a/Documentation/devicetree/bindings/net/can/fsl,flexcan.yaml
+++ b/Documentation/devicetree/bindings/net/can/fsl,flexcan.yaml
@@ -26,6 +26,7 @@ properties:
- fsl,ls1021ar2-flexcan
- fsl,lx2160ar1-flexcan
- nxp,s32g2-flexcan
+ - nxp,s32n79-flexcan
- items:
- enum:
- fsl,imx53-flexcan
@@ -173,11 +174,38 @@ allOf:
- const: mb-1
required:
- interrupt-names
- else:
+ - if:
+ properties:
+ compatible:
+ contains:
+ const: nxp,s32n79-flexcan
+ then:
+ properties:
+ interrupts:
+ items:
+ - description: Message Buffer interrupt for mailboxes 0-127
+ - description: Bus Error and Device state change interrupt
+ interrupt-names:
+ items:
+ - const: mb-0
+ - const: berr
+ required:
+ - interrupt-names
+
+ - if:
+ not:
+ properties:
+ compatible:
+ contains:
+ enum:
+ - nxp,s32g2-flexcan
+ - nxp,s32n79-flexcan
+ then:
properties:
interrupts:
maxItems: 1
interrupt-names: false
+
- if:
required:
- xceiver-supply
--
2.43.0
^ permalink raw reply related
* [PATCH v5 5/8] can: flexcan: add FLEXCAN_QUIRK_IRQ_BERR quirk
From: Ciprian Costea @ 2026-06-09 14:29 UTC (permalink / raw)
To: Marc Kleine-Budde, Vincent Mailhol, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Frank Li, Sascha Hauer,
Fabio Estevam
Cc: Pengutronix Kernel Team, linux-can, devicetree, linux-kernel, imx,
linux-arm-kernel, NXP S32 Linux Team, Christophe Lizzi,
Alberto Ruiz, Enric Balletbo, Eric Chanudet,
Ciprian Marian Costea, Larisa Grigore, Haibo Chen
In-Reply-To: <20260609142954.1807421-1-ciprianmarian.costea@oss.nxp.com>
From: Ciprian Marian Costea <ciprianmarian.costea@oss.nxp.com>
Introduce FLEXCAN_QUIRK_IRQ_BERR quirk to handle hardware integration
where the FlexCAN module has a dedicated interrupt line for signaling
bus errors and device state changes.
This adds the flexcan_irq_esr() handler which composes
flexcan_do_state() and flexcan_do_berr() to handle platforms where
these events share a single IRQ line.
Also extend flexcan_chip_interrupts_enable() to disable/enable the
new IRQ line during IMASK register writes.
This is required for NXP S32N79 SoC support.
Co-developed-by: Larisa Grigore <larisa.grigore@nxp.com>
Signed-off-by: Larisa Grigore <larisa.grigore@nxp.com>
Signed-off-by: Ciprian Marian Costea <ciprianmarian.costea@oss.nxp.com>
Reviewed-and-tested-by: Haibo Chen <haibo.chen@nxp.com>
Tested-by: Enric Balletbo i Serra <eballetb@redhat.com>
---
drivers/net/can/flexcan/flexcan-core.c | 54 +++++++++++++++++++++-----
drivers/net/can/flexcan/flexcan.h | 2 +
2 files changed, 47 insertions(+), 9 deletions(-)
diff --git a/drivers/net/can/flexcan/flexcan-core.c b/drivers/net/can/flexcan/flexcan-core.c
index 0ed838f0719a..adf3af57fb0a 100644
--- a/drivers/net/can/flexcan/flexcan-core.c
+++ b/drivers/net/can/flexcan/flexcan-core.c
@@ -1300,6 +1300,22 @@ static irqreturn_t flexcan_irq_boff(int irq, void *dev_id)
return handled;
}
+/* Combined bus error and state change IRQ handler */
+static irqreturn_t flexcan_irq_esr(int irq, void *dev_id)
+{
+ struct net_device *dev = dev_id;
+ struct flexcan_priv *priv = netdev_priv(dev);
+ irqreturn_t handled;
+
+ handled = flexcan_do_state(dev);
+ handled |= flexcan_do_berr(dev);
+
+ if (handled)
+ can_rx_offload_irq_finish(&priv->offload);
+
+ return handled;
+}
+
static void flexcan_set_bittiming_ctrl(const struct net_device *dev)
{
const struct flexcan_priv *priv = netdev_priv(dev);
@@ -1540,10 +1556,10 @@ static void flexcan_chip_interrupts_enable(const struct net_device *dev)
u64 reg_imask;
disable_irq(dev->irq);
- if (quirks & FLEXCAN_QUIRK_NR_IRQ_3) {
+ if (quirks & FLEXCAN_QUIRK_NR_IRQ_3)
disable_irq(priv->irq_boff);
+ if (quirks & (FLEXCAN_QUIRK_NR_IRQ_3 | FLEXCAN_QUIRK_IRQ_BERR))
disable_irq(priv->irq_err);
- }
if (quirks & FLEXCAN_QUIRK_SECONDARY_MB_IRQ)
disable_irq(priv->irq_secondary_mb);
@@ -1554,10 +1570,10 @@ static void flexcan_chip_interrupts_enable(const struct net_device *dev)
enable_irq(dev->irq);
if (quirks & FLEXCAN_QUIRK_SECONDARY_MB_IRQ)
enable_irq(priv->irq_secondary_mb);
- if (quirks & FLEXCAN_QUIRK_NR_IRQ_3) {
- enable_irq(priv->irq_boff);
+ if (quirks & (FLEXCAN_QUIRK_NR_IRQ_3 | FLEXCAN_QUIRK_IRQ_BERR))
enable_irq(priv->irq_err);
- }
+ if (quirks & FLEXCAN_QUIRK_NR_IRQ_3)
+ enable_irq(priv->irq_boff);
}
static void flexcan_chip_interrupts_disable(const struct net_device *dev)
@@ -1881,7 +1897,8 @@ static int flexcan_open(struct net_device *dev)
can_rx_offload_enable(&priv->offload);
- if (priv->devtype_data.quirks & FLEXCAN_QUIRK_NR_IRQ_3)
+ if (priv->devtype_data.quirks &
+ (FLEXCAN_QUIRK_NR_IRQ_3 | FLEXCAN_QUIRK_IRQ_BERR))
err = request_irq(dev->irq, flexcan_irq_mb,
IRQF_SHARED, dev->name, dev);
else
@@ -1902,6 +1919,13 @@ static int flexcan_open(struct net_device *dev)
goto out_free_irq_boff;
}
+ if (priv->devtype_data.quirks & FLEXCAN_QUIRK_IRQ_BERR) {
+ err = request_irq(priv->irq_err,
+ flexcan_irq_esr, IRQF_SHARED, dev->name, dev);
+ if (err)
+ goto out_free_irq_boff;
+ }
+
if (priv->devtype_data.quirks & FLEXCAN_QUIRK_SECONDARY_MB_IRQ) {
err = request_irq(priv->irq_secondary_mb,
flexcan_irq_mb, IRQF_SHARED, dev->name, dev);
@@ -1916,7 +1940,8 @@ static int flexcan_open(struct net_device *dev)
return 0;
out_free_irq_err:
- if (priv->devtype_data.quirks & FLEXCAN_QUIRK_NR_IRQ_3)
+ if (priv->devtype_data.quirks &
+ (FLEXCAN_QUIRK_IRQ_BERR | FLEXCAN_QUIRK_NR_IRQ_3))
free_irq(priv->irq_err, dev);
out_free_irq_boff:
if (priv->devtype_data.quirks & FLEXCAN_QUIRK_NR_IRQ_3)
@@ -1948,10 +1973,12 @@ static int flexcan_close(struct net_device *dev)
if (priv->devtype_data.quirks & FLEXCAN_QUIRK_SECONDARY_MB_IRQ)
free_irq(priv->irq_secondary_mb, dev);
- if (priv->devtype_data.quirks & FLEXCAN_QUIRK_NR_IRQ_3) {
+ if (priv->devtype_data.quirks &
+ (FLEXCAN_QUIRK_IRQ_BERR | FLEXCAN_QUIRK_NR_IRQ_3))
free_irq(priv->irq_err, dev);
+
+ if (priv->devtype_data.quirks & FLEXCAN_QUIRK_NR_IRQ_3)
free_irq(priv->irq_boff, dev);
- }
free_irq(dev->irq, dev);
can_rx_offload_disable(&priv->offload);
@@ -2338,12 +2365,21 @@ static int flexcan_probe(struct platform_device *pdev)
if (transceiver)
priv->can.bitrate_max = transceiver->attrs.max_link_rate;
+ if (priv->devtype_data.quirks & FLEXCAN_QUIRK_IRQ_BERR) {
+ priv->irq_err = platform_get_irq_byname(pdev, "berr");
+ if (priv->irq_err < 0) {
+ err = priv->irq_err;
+ goto failed_platform_get_irq;
+ }
+ }
+
if (priv->devtype_data.quirks & FLEXCAN_QUIRK_NR_IRQ_3) {
priv->irq_boff = platform_get_irq(pdev, 1);
if (priv->irq_boff < 0) {
err = priv->irq_boff;
goto failed_platform_get_irq;
}
+
priv->irq_err = platform_get_irq(pdev, 2);
if (priv->irq_err < 0) {
err = priv->irq_err;
diff --git a/drivers/net/can/flexcan/flexcan.h b/drivers/net/can/flexcan/flexcan.h
index 16692a2502eb..bbb1a8dd4777 100644
--- a/drivers/net/can/flexcan/flexcan.h
+++ b/drivers/net/can/flexcan/flexcan.h
@@ -74,6 +74,8 @@
* both need to have an interrupt handler registered.
*/
#define FLEXCAN_QUIRK_SECONDARY_MB_IRQ BIT(18)
+/* Setup dedicated bus error and state change IRQ */
+#define FLEXCAN_QUIRK_IRQ_BERR BIT(19)
struct flexcan_devtype_data {
u32 quirks; /* quirks needed for different IP cores */
--
2.43.0
^ permalink raw reply related
* [PATCH v5 6/8] can: flexcan: add NXP S32N79 SoC support
From: Ciprian Costea @ 2026-06-09 14:29 UTC (permalink / raw)
To: Marc Kleine-Budde, Vincent Mailhol, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Frank Li, Sascha Hauer,
Fabio Estevam
Cc: Pengutronix Kernel Team, linux-can, devicetree, linux-kernel, imx,
linux-arm-kernel, NXP S32 Linux Team, Christophe Lizzi,
Alberto Ruiz, Enric Balletbo, Eric Chanudet,
Ciprian Marian Costea, Andra-Teodora Ilie, Larisa Grigore,
Haibo Chen
In-Reply-To: <20260609142954.1807421-1-ciprianmarian.costea@oss.nxp.com>
From: Ciprian Marian Costea <ciprianmarian.costea@oss.nxp.com>
Add device data and compatible string for NXP S32N79 SoC.
FlexCAN IP integration on S32N79 SoC uses two interrupts:
- one for mailboxes 0-127
- one for signaling bus errors and device state changes
Co-developed-by: Andra-Teodora Ilie <andra.ilie@nxp.com>
Signed-off-by: Andra-Teodora Ilie <andra.ilie@nxp.com>
Co-developed-by: Larisa Grigore <larisa.grigore@nxp.com>
Signed-off-by: Larisa Grigore <larisa.grigore@nxp.com>
Signed-off-by: Ciprian Marian Costea <ciprianmarian.costea@oss.nxp.com>
Reviewed-and-tested-by: Haibo Chen <haibo.chen@nxp.com>
Tested-by: Enric Balletbo i Serra <eballetb@redhat.com>
---
drivers/net/can/flexcan/flexcan-core.c | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/drivers/net/can/flexcan/flexcan-core.c b/drivers/net/can/flexcan/flexcan-core.c
index adf3af57fb0a..b43d60fab4b6 100644
--- a/drivers/net/can/flexcan/flexcan-core.c
+++ b/drivers/net/can/flexcan/flexcan-core.c
@@ -403,6 +403,15 @@ static const struct flexcan_devtype_data nxp_s32g2_devtype_data = {
FLEXCAN_QUIRK_SECONDARY_MB_IRQ,
};
+static const struct flexcan_devtype_data nxp_s32n_devtype_data = {
+ .quirks = FLEXCAN_QUIRK_DISABLE_RXFG | FLEXCAN_QUIRK_ENABLE_EACEN_RRS |
+ FLEXCAN_QUIRK_DISABLE_MECR | FLEXCAN_QUIRK_USE_RX_MAILBOX |
+ FLEXCAN_QUIRK_BROKEN_PERR_STATE | FLEXCAN_QUIRK_SUPPORT_FD |
+ FLEXCAN_QUIRK_SUPPORT_ECC | FLEXCAN_QUIRK_SUPPORT_RX_MAILBOX |
+ FLEXCAN_QUIRK_SUPPORT_RX_MAILBOX_RTR |
+ FLEXCAN_QUIRK_IRQ_BERR,
+};
+
static const struct can_bittiming_const flexcan_bittiming_const = {
.name = DRV_NAME,
.tseg1_min = 4,
@@ -2222,6 +2231,7 @@ static const struct of_device_id flexcan_of_match[] = {
{ .compatible = "fsl,ls1021ar2-flexcan", .data = &fsl_ls1021a_r2_devtype_data, },
{ .compatible = "fsl,lx2160ar1-flexcan", .data = &fsl_lx2160a_r1_devtype_data, },
{ .compatible = "nxp,s32g2-flexcan", .data = &nxp_s32g2_devtype_data, },
+ { .compatible = "nxp,s32n79-flexcan", .data = &nxp_s32n_devtype_data, },
{ /* sentinel */ },
};
MODULE_DEVICE_TABLE(of, flexcan_of_match);
--
2.43.0
^ permalink raw reply related
* [PATCH v5 7/8] arm64: dts: s32n79: add FlexCAN nodes
From: Ciprian Costea @ 2026-06-09 14:29 UTC (permalink / raw)
To: Marc Kleine-Budde, Vincent Mailhol, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Frank Li, Sascha Hauer,
Fabio Estevam
Cc: Pengutronix Kernel Team, linux-can, devicetree, linux-kernel, imx,
linux-arm-kernel, NXP S32 Linux Team, Christophe Lizzi,
Alberto Ruiz, Enric Balletbo, Eric Chanudet,
Ciprian Marian Costea, Andra-Teodora Ilie, Haibo Chen
In-Reply-To: <20260609142954.1807421-1-ciprianmarian.costea@oss.nxp.com>
From: Ciprian Marian Costea <ciprianmarian.costea@oss.nxp.com>
The S32N79 integrates multiple FlexCAN instances connected through the RCU
irqsteer interrupt controller.
Co-developed-by: Andra-Teodora Ilie <andra.ilie@nxp.com>
Signed-off-by: Andra-Teodora Ilie <andra.ilie@nxp.com>
Signed-off-by: Ciprian Marian Costea <ciprianmarian.costea@oss.nxp.com>
Reviewed-and-tested-by: Haibo Chen <haibo.chen@nxp.com>
Tested-by: Enric Balletbo i Serra <eballetb@redhat.com>
---
arch/arm64/boot/dts/freescale/s32n79.dtsi | 50 +++++++++++++++++++++++
1 file changed, 50 insertions(+)
diff --git a/arch/arm64/boot/dts/freescale/s32n79.dtsi b/arch/arm64/boot/dts/freescale/s32n79.dtsi
index 94ab58783fdc..c1a4fdead91d 100644
--- a/arch/arm64/boot/dts/freescale/s32n79.dtsi
+++ b/arch/arm64/boot/dts/freescale/s32n79.dtsi
@@ -352,6 +352,56 @@ pmu: pmu {
interrupts = <GIC_PPI 7 IRQ_TYPE_LEVEL_HIGH>;
};
+ rcu-bus {
+ compatible = "simple-bus";
+ ranges = <0x54000000 0x0 0x54000000 0x4000000>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ irqsteer_rcu: interrupt-controller@55101000 {
+ compatible = "nxp,s32n79-irqsteer";
+ reg = <0x55101000 0x1000>;
+ #interrupt-cells = <1>;
+ interrupt-controller;
+ interrupt-parent = <&gic>;
+ interrupts = <GIC_SPI 73 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 74 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 75 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 76 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 77 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 78 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 79 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 80 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&clks 0xf9>;
+ clock-names = "ipg";
+ fsl,channel = <0>;
+ fsl,num-irqs = <512>;
+ status = "disabled";
+ };
+
+ can0: can@55b60000 {
+ compatible = "nxp,s32n79-flexcan";
+ reg = <0x55b60000 0x4000>;
+ interrupt-parent = <&irqsteer_rcu>;
+ interrupts = <0>, <64>;
+ interrupt-names = "mb-0", "berr";
+ clocks = <&clks 0xf9>, <&clks 0xfc>;
+ clock-names = "ipg", "per";
+ status = "disabled";
+ };
+
+ can1: can@55b70000 {
+ compatible = "nxp,s32n79-flexcan";
+ reg = <0x55b70000 0x4000>;
+ interrupt-parent = <&irqsteer_rcu>;
+ interrupts = <1>, <65>;
+ interrupt-names = "mb-0", "berr";
+ clocks = <&clks 0xf9>, <&clks 0xfc>;
+ clock-names = "ipg", "per";
+ status = "disabled";
+ };
+ };
+
timer: timer {
compatible = "arm,armv8-timer";
interrupts = <GIC_PPI 13 IRQ_TYPE_LEVEL_LOW>,
--
2.43.0
^ permalink raw reply related
* [PATCH v5 8/8] arm64: dts: s32n79: enable FlexCAN devices
From: Ciprian Costea @ 2026-06-09 14:29 UTC (permalink / raw)
To: Marc Kleine-Budde, Vincent Mailhol, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Frank Li, Sascha Hauer,
Fabio Estevam
Cc: Pengutronix Kernel Team, linux-can, devicetree, linux-kernel, imx,
linux-arm-kernel, NXP S32 Linux Team, Christophe Lizzi,
Alberto Ruiz, Enric Balletbo, Eric Chanudet,
Ciprian Marian Costea, Haibo Chen
In-Reply-To: <20260609142954.1807421-1-ciprianmarian.costea@oss.nxp.com>
From: Ciprian Marian Costea <ciprianmarian.costea@oss.nxp.com>
Enable FlexCAN controller instances (can0 and can1) and the required RCU
irqsteer interrupt controller on S32N79-RDB board.
Signed-off-by: Ciprian Marian Costea <ciprianmarian.costea@oss.nxp.com>
Reviewed-and-tested-by: Haibo Chen <haibo.chen@nxp.com>
Tested-by: Enric Balletbo i Serra <eballetb@redhat.com>
---
arch/arm64/boot/dts/freescale/s32n79-rdb.dts | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/arch/arm64/boot/dts/freescale/s32n79-rdb.dts b/arch/arm64/boot/dts/freescale/s32n79-rdb.dts
index 1feccd61258e..65a595d7535f 100644
--- a/arch/arm64/boot/dts/freescale/s32n79-rdb.dts
+++ b/arch/arm64/boot/dts/freescale/s32n79-rdb.dts
@@ -43,10 +43,22 @@ memory@80000000 {
};
};
+&can0 {
+ status = "okay";
+};
+
+&can1 {
+ status = "okay";
+};
+
&irqsteer_coss {
status = "okay";
};
+&irqsteer_rcu {
+ status = "okay";
+};
+
&uart0 {
status = "okay";
};
--
2.43.0
^ permalink raw reply related
* Re: [PATCH v6 04/20] dma-pool: track decrypted atomic pools and select them via attrs
From: Jason Gunthorpe @ 2026-06-09 14:32 UTC (permalink / raw)
To: Aneesh Kumar K.V (Arm)
Cc: iommu, linux-arm-kernel, linux-kernel, linux-coco, Robin Murphy,
Marek Szyprowski, Will Deacon, Marc Zyngier, Steven Price,
Suzuki K Poulose, Catalin Marinas, Jiri Pirko, Mostafa Saleh,
Petr Tesarik, Alexey Kardashevskiy, Dan Williams, Xu Yilun,
linuxppc-dev, linux-s390, Madhavan Srinivasan, Michael Ellerman,
Nicholas Piggin, Christophe Leroy (CS GROUP), Alexander Gordeev,
Gerald Schaefer, Heiko Carstens, Vasily Gorbik,
Christian Borntraeger, Sven Schnelle, x86, Jiri Pirko,
Michael Kelley
In-Reply-To: <20260604083959.1265923-5-aneesh.kumar@kernel.org>
On Thu, Jun 04, 2026 at 02:09:43PM +0530, Aneesh Kumar K.V (Arm) wrote:
> struct page *dma_alloc_from_pool(struct device *dev, size_t size,
> - void **cpu_addr, gfp_t gfp,
> + void **cpu_addr, gfp_t gfp, unsigned long attrs,
> bool (*phys_addr_ok)(struct device *, phys_addr_t, size_t))
> {
> - struct gen_pool *pool = NULL;
> + struct dma_gen_pool *dma_pool = NULL;
> struct page *page;
> bool pool_found = false;
>
> - while ((pool = dma_guess_pool(pool, gfp))) {
> + while ((dma_pool = dma_guess_pool(dma_pool, gfp))) {
> +
> + if (dma_pool->unencrypted != !!(attrs & DMA_ATTR_CC_SHARED))
> + continue;
I don't think you should be overloading DMA_ATTR_CC_SHARED like this.
/*
* DMA_ATTR_CC_SHARED is not a caller-visible dma_alloc_*()
* attribute. The direct allocator uses it internally after it has
* decided that the backing pages must be shared/decrypted, so the
* rest of the allocation path can consistently select DMA addresses,
* choose compatible pools and restore encryption on free.
*/
if (attrs & DMA_ATTR_CC_SHARED)
return NULL;
if (force_dma_unencrypted(dev)) {
attrs |= DMA_ATTR_CC_SHARED;
mark_mem_decrypt = true;
}
It is fine to have a bit inside the attrs that is only used by the
internal logic, but it needs to have a clearer name
__DMA_ATTR_REQUIRE_CC_SHARED perhaps.
The sashiko note does look legit though:
if (IS_ENABLED(CONFIG_DMA_DIRECT_REMAP) &&
!gfpflags_allow_blocking(gfp) && !coherent) {
page = dma_alloc_from_pool(dev, PAGE_ALIGN(size), &cpu_addr,
gfp, attrs, NULL);
if (!page)
return NULL;
I don't see anything doing the force_dma_unencrypted test along this
callchain..
I guess it should be done one step up in dma_alloc_attrs() instead of
in dma_direct_alloc()?
Jason
^ permalink raw reply
* Re: [GIT PULL 4/6] firmware: tegra: Changes for v7.2-rc1
From: Arnd Bergmann @ 2026-06-09 14:38 UTC (permalink / raw)
To: Thierry Reding, arm, soc
Cc: Jon Hunter, linux-tegra, linux-arm-kernel, Sasha Levin
In-Reply-To: <20260531060825.1855391-4-thierry.reding@kernel.org>
On Sun, May 31, 2026, at 08:08, Thierry Reding wrote:
> From: Thierry Reding <thierry.reding@gmail.com>
> ----------------------------------------------------------------
> Jon Hunter (2):
> firmware: tegra: bpmp: Propagate debugfs errors
> firmware: tegra: bpmp: Add support for multi-socket platforms
>
> Sasha Levin (1):
> firmware: tegra: Make TEGRA_IVC a hidden Kconfig symbol
I'm merging this, but I would like to point out that the third
patch does not actually solve a real problem and the patch
description is complete nonsense.
Looking through linux-next, I see two more of Sasha's patches
addressing kconfiglint 'K002' warnings. I have not used that
tool and the warning sounds useful in general, but all three
of these patches look like false positives.
Sasha, please try to understand better what the tool is
trying to warn about.
Arnd
^ permalink raw reply
* [RFC PATCH v2 0/3] make persistent huge zero folio read-only
From: Xueyuan Chen @ 2026-06-09 14:37 UTC (permalink / raw)
To: akpm, linux-mm
Cc: linux-kernel, linux-arm-kernel, x86, catalin.marinas, will, tglx,
mingo, bp, dave.hansen, luto, peterz, hpa, david, ljs, liam,
vbabka, rppt, surenb, mhocko, ziy, baolin.wang, npache,
ryan.roberts, dev.jain, baohua, lance.yang, yang, jannh,
Xueyuan Chen
Hi all,
This series makes the persistent huge zero folio read-only in the direct
map where the architecture can support it.
The motivation comes from Jann Horn's read-only zero page work[1] and the
follow-up discussion[2] with Yang Shi. As Jann pointed out, the kernel has
had bugs, including security bugs, where pages taken with read-only
semantics were later written to. For the huge zero folio, making the direct
map read-only turns such writes into faults instead of silently corrupting
shared zero contents.
Patch 1 adds a generic arch_make_pages_readonly() hook and uses it after
the persistent huge zero folio is allocated. Patches 2 and 3 implement the
hook for arm64 and x86.
If the hook is not implemented, or the architecture cannot safely update
the mapping, the existing writable mapping is left in place.
[1] https://lore.kernel.org/linux-mm/20260508-ro-zeropage-v1-1-9808abc20b49@google.com/
[2] https://lore.kernel.org/linux-mm/CAHbLzkrXXe7r3n3jXgDKtwZhRqj=jDx9E6dLOULohnhBguvi9A@mail.gmail.com/
RFC v1 -> RFC v2:
- Patch #01: Drop the READONLY_HUGE_ZERO_FOLIO Kconfig option
(per Dave, thanks!).
- Patch #01: Replace the huge-zero-folio-specific hook with a generic
page-range hook (per David, thanks!)
- Patch #02 and #03: Update the arm64 and x86 implementations for the new
hook.
- https://lore.kernel.org/linux-mm/20260527035607.14919-1-xueyuan.chen21@gmail.com/
Xueyuan Chen (3):
mm/huge_memory: make persistent huge zero folio read-only
arm64/mm: make pages read-only in the linear map
x86/mm: make pages read-only in the direct map
arch/arm64/mm/pageattr.c | 13 +++++++++++++
arch/x86/mm/init.c | 9 +++++++++
include/linux/mm.h | 2 ++
mm/huge_memory.c | 13 ++++++++++++-
4 files changed, 36 insertions(+), 1 deletion(-)
--
2.47.3
^ permalink raw reply
* [RFC PATCH v2 1/3] mm/huge_memory: make persistent huge zero folio read-only
From: Xueyuan Chen @ 2026-06-09 14:37 UTC (permalink / raw)
To: akpm, linux-mm
Cc: linux-kernel, linux-arm-kernel, x86, catalin.marinas, will, tglx,
mingo, bp, dave.hansen, luto, peterz, hpa, david, ljs, liam,
vbabka, rppt, surenb, mhocko, ziy, baolin.wang, npache,
ryan.roberts, dev.jain, baohua, lance.yang, yang, jannh,
Xueyuan Chen, Dave Hansen
In-Reply-To: <20260609143801.7917-1-xueyuan.chen21@gmail.com>
The huge zero folio is shared globally, and its contents should never
change after initialization. As Jann Horn pointed out[1], the kernel has
had bugs, including security bugs, where read-only pages were later written
to. If the persistent huge zero folio is read-only in the direct map, such
writes fault instead of silently corrupting the shared zero contents.
Add arch_make_pages_readonly() so mm code can request read-only direct-map
protection for a page range. Direct-map protection is
architecture-specific, so the generic weak implementation does nothing.
This was inspired by Jann Horn's read-only zero page work[1] and follow-up
discussion[2] with Yang Shi.
[1] https://lore.kernel.org/linux-mm/20260508-ro-zeropage-v1-1-9808abc20b49@google.com/
[2] https://lore.kernel.org/linux-mm/CAHbLzkrXXe7r3n3jXgDKtwZhRqj=jDx9E6dLOULohnhBguvi9A@mail.gmail.com/
Suggested-by: Dave Hansen <dave.hansen@intel.com>
Suggested-by: David Hildenbrand <david@kernel.org>
Co-developed-by: Lance Yang <lance.yang@linux.dev>
Signed-off-by: Lance Yang <lance.yang@linux.dev>
Signed-off-by: Xueyuan Chen <xueyuan.chen21@gmail.com>
---
include/linux/mm.h | 2 ++
mm/huge_memory.c | 13 ++++++++++++-
2 files changed, 14 insertions(+), 1 deletion(-)
diff --git a/include/linux/mm.h b/include/linux/mm.h
index 0f2612a70fb1..02d33cf45b01 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -2936,6 +2936,8 @@ static inline int arch_make_folio_accessible(struct folio *folio)
}
#endif
+bool arch_make_pages_readonly(struct page *page, int nr_pages);
+
/*
* Some inline functions in vmstat.h depend on page_zone()
*/
diff --git a/mm/huge_memory.c b/mm/huge_memory.c
index b81d1ecb434b..2e9d01dc1197 100644
--- a/mm/huge_memory.c
+++ b/mm/huge_memory.c
@@ -308,6 +308,11 @@ static unsigned long shrink_huge_zero_folio_scan(struct shrinker *shrink,
return 0;
}
+bool __weak arch_make_pages_readonly(struct page *page, int nr_pages)
+{
+ return false;
+}
+
static struct shrinker *huge_zero_folio_shrinker;
#ifdef CONFIG_SYSFS
@@ -982,8 +987,14 @@ static int __init thp_shrinker_init(void)
* that get_huge_zero_folio() will most likely not fail as
* thp_shrinker_init() is invoked early on during boot.
*/
- if (!get_huge_zero_folio())
+ if (!get_huge_zero_folio()) {
pr_warn("Allocating persistent huge zero folio failed\n");
+ return 0;
+ }
+
+ arch_make_pages_readonly(folio_page(huge_zero_folio, 0),
+ HPAGE_PMD_NR);
+
return 0;
}
--
2.47.3
^ permalink raw reply related
* [PATCH v3] soc: samsung: exynos-pmu: fix of_node refcount leak in exynos_get_pmu_regmap()
From: Weigang He @ 2026-06-09 14:38 UTC (permalink / raw)
To: Krzysztof Kozlowski
Cc: Alim Akhtar, Marek Szyprowski, Tomasz Figa, linux-arm-kernel,
linux-samsung-soc, linux-kernel, Weigang He
exynos_get_pmu_regmap() obtains a device_node via of_find_matching_node()
and passes it to exynos_get_pmu_regmap_by_phandle(np, NULL). With
propname == NULL the callee uses np directly and does not drop a
reference, so the reference taken by of_find_matching_node() is leaked on
every call -- including on each -EPROBE_DEFER retry of the only in-tree
caller, exynos_retention_init() in the Exynos pinctrl driver.
Annotate np with the __free(device_node) cleanup attribute so the
reference is released when the function returns.
Found by static analysis tool CodeQL.
Fixes: 76640b84bd7a ("soc: samsung: pmu: Provide global function to get PMU regmap")
Signed-off-by: Weigang He <geoffreyhe2@gmail.com>
---
Changes in v3:
- Only annotate the np declaration with __free(device_node); leave the
rest of the function body unchanged (Krzysztof Kozlowski).
Changes in v2:
- Use the __free(device_node) cleanup attribute instead of an explicit
of_node_put() and the helper refactor (Krzysztof Kozlowski); dropped
the former patch 2/2.
v2: https://lore.kernel.org/linux-samsung-soc/20260609133320.1748882-1-geoffreyhe2@gmail.com/
v1: https://lore.kernel.org/linux-samsung-soc/20260609095224.1706036-2-geoffreyhe2@gmail.com>/
drivers/soc/samsung/exynos-pmu.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/soc/samsung/exynos-pmu.c b/drivers/soc/samsung/exynos-pmu.c
index d58376c38179b..f5fcdde9750e2 100644
--- a/drivers/soc/samsung/exynos-pmu.c
+++ b/drivers/soc/samsung/exynos-pmu.c
@@ -167,8 +167,8 @@ static const struct mfd_cell exynos_pmu_devs[] = {
*/
struct regmap *exynos_get_pmu_regmap(void)
{
- struct device_node *np = of_find_matching_node(NULL,
- exynos_pmu_of_device_ids);
+ struct device_node *np __free(device_node) =
+ of_find_matching_node(NULL, exynos_pmu_of_device_ids);
if (np)
return exynos_get_pmu_regmap_by_phandle(np, NULL);
return ERR_PTR(-ENODEV);
base-commit: 0f61b1860cc3f52aef9036d7235ed1f017632193
--
2.43.0
^ permalink raw reply related
* [RFC PATCH v2 2/3] arm64/mm: make pages read-only in the linear map
From: Xueyuan Chen @ 2026-06-09 14:38 UTC (permalink / raw)
To: akpm, linux-mm
Cc: linux-kernel, linux-arm-kernel, x86, catalin.marinas, will, tglx,
mingo, bp, dave.hansen, luto, peterz, hpa, david, ljs, liam,
vbabka, rppt, surenb, mhocko, ziy, baolin.wang, npache,
ryan.roberts, dev.jain, baohua, lance.yang, yang, jannh,
Xueyuan Chen
In-Reply-To: <20260609143801.7917-1-xueyuan.chen21@gmail.com>
Implement arch_make_pages_readonly() for arm64. Make the corresponding
linear-map range read-only so unexpected writes fault instead of
corrupting shared contents.
Respect can_set_direct_map() before touching the linear map. If arm64
cannot safely update the linear map at page granularity, leave the mapping
unchanged.
Co-developed-by: Lance Yang <lance.yang@linux.dev>
Signed-off-by: Lance Yang <lance.yang@linux.dev>
Signed-off-by: Xueyuan Chen <xueyuan.chen21@gmail.com>
---
arch/arm64/mm/pageattr.c | 13 +++++++++++++
1 file changed, 13 insertions(+)
diff --git a/arch/arm64/mm/pageattr.c b/arch/arm64/mm/pageattr.c
index ce035e1b4eaf..da97ec7d5195 100644
--- a/arch/arm64/mm/pageattr.c
+++ b/arch/arm64/mm/pageattr.c
@@ -3,6 +3,7 @@
* Copyright (c) 2014, The Linux Foundation. All rights reserved.
*/
#include <linux/kernel.h>
+#include <linux/init.h>
#include <linux/mm.h>
#include <linux/module.h>
#include <linux/mem_encrypt.h>
@@ -147,6 +148,18 @@ static int __change_memory_common(unsigned long start, unsigned long size,
return ret;
}
+bool arch_make_pages_readonly(struct page *page, int nr_pages)
+{
+ unsigned long addr = (unsigned long)page_address(page);
+
+ if (!can_set_direct_map())
+ return false;
+
+ return !__change_memory_common(addr, PAGE_SIZE * nr_pages,
+ __pgprot(PTE_RDONLY),
+ __pgprot(PTE_WRITE));
+}
+
static int change_memory_common(unsigned long addr, int numpages,
pgprot_t set_mask, pgprot_t clear_mask)
{
--
2.47.3
^ permalink raw reply related
* Re: [PATCH 0/3] i2c: xiic: fix SMBus block read and PEC support
From: Michal Simek @ 2026-06-09 14:39 UTC (permalink / raw)
To: Shubhrajyoti Datta, abdurrahman
Cc: Andi Shyti, linux-arm-kernel, linux-i2c, linux-kernel
In-Reply-To: <CAKfKVtGztJkU_HXZTrb2h3hrTJp0SbRo-sDHM4Sj_1SG8ymOyw@mail.gmail.com>
On 6/9/26 16:26, Shubhrajyoti Datta wrote:
> On Tue, Apr 28, 2026 at 5:48 AM Abdurrahman Hussain via B4 Relay
> <devnull+abdurrahman.nexthop.ai@kernel.org> wrote:
>>
>> This series fixes three independent bugs in the Xilinx AXI IIC driver
>> that together make SMBus block reads with PEC return -EBADMSG or -EIO
>> on otherwise clean transfers. They only surface when the client has
>> I2C_CLIENT_PEC set; non-PEC block reads happen to mask each issue in
>> turn.
>>
>> The problems were uncovered driving an adm1266 PMBus device behind a
>> Xilinx AXI IIC FPGA block and reading its 64-byte blackbox record.
>>
>> Patch 1 stops xiic_smbus_block_read_setup() from truncating rx_msg->len.
>> The i2c core appends a byte to msg->len when PEC is enabled, so
>> overwriting the length to "block size + 1" silently drops the PEC byte
>> and i2c_smbus_check_pec() then reads the last payload byte as the PEC.
>>
>> Patch 2 raises the RX_FULL threshold so the interrupt only fires once
>> every remaining byte (payload plus optional PEC) is already buffered in
>> the FIFO. The previous threshold of rxmsg_len - 2 caused the
>> bytes_rem == 1 path in xiic_read_rx() to NACK a byte still on the wire.
>>
>> Patch 3 stops the BNB handler from forcing tx_msg->len = 1 to signal
>> completion. tx_msg and rx_msg alias the same i2c_msg during a receive,
>> so this also clobbered rx_msg->len; and because tx_pos is already at 2
>> in the PEC case, the unsigned subtraction in xiic_tx_space() underflowed
>> and the STATE_DONE check fell through to STATE_ERROR. Advancing tx_pos
>> up to msg->len drives tx_space to zero without touching the length.
>>
>> All three patches are pure bug fixes; non-PEC behaviour is unchanged.
>> Tested on real hardware -- a Xilinx AXI IIC controller talking to an
>> adm1266, where 64-byte PEC-checked block reads now complete cleanly.
>>
>> Signed-off-by: Abdurrahman Hussain <abdurrahman@nexthop.ai>
>
> LGTM
> Reviewed-by: Shubhrajyoti Datta <shubhrajyoti.datta@amd.com>
Acked-by: Michal Simek <michal.simek@amd.com>
Thanks,
Michal
^ permalink raw reply
* [RFC PATCH v2 3/3] x86/mm: make pages read-only in the direct map
From: Xueyuan Chen @ 2026-06-09 14:38 UTC (permalink / raw)
To: akpm, linux-mm
Cc: linux-kernel, linux-arm-kernel, x86, catalin.marinas, will, tglx,
mingo, bp, dave.hansen, luto, peterz, hpa, david, ljs, liam,
vbabka, rppt, surenb, mhocko, ziy, baolin.wang, npache,
ryan.roberts, dev.jain, baohua, lance.yang, yang, jannh,
Xueyuan Chen
In-Reply-To: <20260609143801.7917-1-xueyuan.chen21@gmail.com>
Implement arch_make_pages_readonly() for x86. Make the corresponding
direct-map range read-only so unexpected writes fault instead of
corrupting shared contents.
Reject highmem pages because they have no permanent direct-map address.
Treat the set_memory_ro() update as best effort. If it fails, leave the
mapping unchanged.
Co-developed-by: Lance Yang <lance.yang@linux.dev>
Signed-off-by: Lance Yang <lance.yang@linux.dev>
Signed-off-by: Xueyuan Chen <xueyuan.chen21@gmail.com>
---
arch/x86/mm/init.c | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/arch/x86/mm/init.c b/arch/x86/mm/init.c
index fb67217fddcd..ff0a7003eaeb 100644
--- a/arch/x86/mm/init.c
+++ b/arch/x86/mm/init.c
@@ -3,6 +3,7 @@
#include <linux/ioport.h>
#include <linux/swap.h>
#include <linux/memblock.h>
+#include <linux/mm.h>
#include <linux/swapfile.h>
#include <linux/swapops.h>
#include <linux/kmemleak.h>
@@ -38,6 +39,14 @@
#include "mm_internal.h"
+bool arch_make_pages_readonly(struct page *page, int nr_pages)
+{
+ if (PageHighMem(page))
+ return false;
+
+ return !set_memory_ro((unsigned long)page_address(page), nr_pages);
+}
+
/*
* Tables translating between page_cache_type_t and pte encoding.
*
--
2.47.3
^ permalink raw reply related
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