[PATCH AUTOSEL 6.19-5.10] clocksource/drivers/sh_tmu: Always leave device running after probe

Sasha Levin posted 1 patch 3 hours ago
drivers/clocksource/sh_tmu.c | 18 ------------------
1 file changed, 18 deletions(-)
[PATCH AUTOSEL 6.19-5.10] clocksource/drivers/sh_tmu: Always leave device running after probe
Posted by Sasha Levin 3 hours ago
From: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>

[ Upstream commit b1278972b08e480990e2789bdc6a7c918bc349be ]

The TMU device can be used as both a clocksource and a clockevent
provider. The driver tries to be smart and power itself on and off, as
well as enabling and disabling its clock when it's not in operation.
This behavior is slightly altered if the TMU is used as an early
platform device in which case the device is left powered on after probe,
but the clock is still enabled and disabled at runtime.

This has worked for a long time, but recent improvements in PREEMPT_RT
and PROVE_LOCKING have highlighted an issue. As the TMU registers itself
as a clockevent provider, clockevents_register_device(), it needs to use
raw spinlocks internally as this is the context of which the clockevent
framework interacts with the TMU driver. However in the context of
holding a raw spinlock the TMU driver can't really manage its power
state or clock with calls to pm_runtime_*() and clk_*() as these calls
end up in other platform drivers using regular spinlocks to control
power and clocks.

This mix of spinlock contexts trips a lockdep warning.

    =============================
    [ BUG: Invalid wait context ]
    6.18.0-arm64-renesas-09926-gee959e7c5e34 #1 Not tainted
    -----------------------------
    swapper/0/0 is trying to lock:
    ffff000008c9e180 (&dev->power.lock){-...}-{3:3}, at: __pm_runtime_resume+0x38/0x88
    other info that might help us debug this:
    context-{5:5}
    1 lock held by swapper/0/0:
    ccree e6601000.crypto: ARM CryptoCell 630P Driver: HW version 0xAF400001/0xDCC63000, Driver version 5.0
     #0: ffff8000817ec298
    ccree e6601000.crypto: ARM ccree device initialized
     (tick_broadcast_lock){-...}-{2:2}, at: __tick_broadcast_oneshot_control+0xa4/0x3a8
    stack backtrace:
    CPU: 0 UID: 0 PID: 0 Comm: swapper/0 Not tainted 6.18.0-arm64-renesas-09926-gee959e7c5e34 #1 PREEMPT
    Hardware name: Renesas Salvator-X 2nd version board based on r8a77965 (DT)
    Call trace:
     show_stack+0x14/0x1c (C)
     dump_stack_lvl+0x6c/0x90
     dump_stack+0x14/0x1c
     __lock_acquire+0x904/0x1584
     lock_acquire+0x220/0x34c
     _raw_spin_lock_irqsave+0x58/0x80
     __pm_runtime_resume+0x38/0x88
     sh_tmu_clock_event_set_oneshot+0x84/0xd4
     clockevents_switch_state+0xfc/0x13c
     tick_broadcast_set_event+0x30/0xa4
     __tick_broadcast_oneshot_control+0x1e0/0x3a8
     tick_broadcast_oneshot_control+0x30/0x40
     cpuidle_enter_state+0x40c/0x680
     cpuidle_enter+0x30/0x40
     do_idle+0x1f4/0x280
     cpu_startup_entry+0x34/0x40
     kernel_init+0x0/0x130
     do_one_initcall+0x0/0x230
     __primary_switched+0x88/0x90

For non-PREEMPT_RT builds this is not really an issue, but for
PREEMPT_RT builds where normal spinlocks can sleep this might be an
issue. Be cautious and always leave the power and clock running after
probe.

Signed-off-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
Tested-by: Geert Uytterhoeven <geert+renesas@glider.be>
Link: https://patch.msgid.link/20251202221341.1856773-1-niklas.soderlund+renesas@ragnatech.se
Signed-off-by: Sasha Levin <sashal@kernel.org>
---

LLM Generated explanations, may be completely bogus:

Now I have a complete picture. Let me compile my thorough analysis.

---

## Detailed Analysis

### 1. COMMIT MESSAGE ANALYSIS

The commit message is thorough and well-written. It clearly describes:
- **The problem**: An invalid wait context lockdep warning (`[ BUG:
  Invalid wait context ]`) on PREEMPT_RT kernels
- **The root cause**: The TMU driver tries to manage PM runtime
  (`pm_runtime_get_sync`/`pm_runtime_put`) and clock state
  (`clk_enable`/`clk_disable`) at runtime, but these calls happen within
  a raw spinlock context from the clockevent framework
- **The fix strategy**: Leave the device and clock always running after
  probe
- **Full stack trace**: Reproduced on real hardware (Renesas Salvator-X
  board with r8a77965 SoC)
- **Tested-by**: Geert Uytterhoeven, a very well-known Renesas platform
  maintainer
- **Signed off by**: Daniel Lezcano, the clocksource subsystem
  maintainer

### 2. CODE CHANGE ANALYSIS - THE BUG MECHANISM

The bug is a **lock ordering / invalid wait context** issue. The precise
call chain is:

1. `cpuidle_enter_state` → `__tick_broadcast_oneshot_control` acquires
   `tick_broadcast_lock` (a **raw spinlock**, lock class `{-...}-{2:2}`)
2. Inside the raw spinlock, `clockevents_switch_state` →
   `sh_tmu_clock_event_set_oneshot` → `sh_tmu_clock_event_set_state` →
   `sh_tmu_enable`
3. `sh_tmu_enable` calls `pm_runtime_get_sync(&ch->tmu->pdev->dev)`
   which tries to acquire `dev->power.lock` (a **regular spinlock**,
   lock class `{-...}-{3:3}`)

I verified this call chain through the code:
- `___tick_broadcast_oneshot_control` (line 796 of `tick-broadcast.c`)
  does `raw_spin_lock(&tick_broadcast_lock)` at the top, then at line
  889 calls `clockevents_switch_state(dev, CLOCK_EVT_STATE_ONESHOT)`
- Similarly, `broadcast_shutdown_local` calls
  `clockevents_switch_state(dev, CLOCK_EVT_STATE_SHUTDOWN)` while
  tick_broadcast_lock is held
- `tick_broadcast_set_event` also calls `clockevents_switch_state`
  within the lock

On **PREEMPT_RT**, regular spinlocks are sleeping locks (they can
schedule). Acquiring a sleeping lock while holding a raw spinlock is
**illegal** - it can cause sleeping in atomic context or deadlock. The
lockdep annotation `{-...}-{2:2}` vs `{-...}-{3:3}` in the stack trace
confirms the context mismatch.

### 3. THE FIX

The patch is a **pure deletion** (18 lines removed, 0 added):

1. **`__sh_tmu_enable()`**: Removes `clk_enable()` call (clock stays
   enabled from probe)
2. **`sh_tmu_enable()`**: Removes `pm_runtime_get_sync()` call (PM
   runtime stays active from probe)
3. **`__sh_tmu_disable()`**: Removes `clk_disable()` call (clock never
   disabled)
4. **`sh_tmu_disable()`**: Removes `pm_runtime_put()` call (PM runtime
   never released)
5. **`sh_tmu_setup()`**: Removes `clk_disable()` after rate measurement
   (clock stays enabled)
6. **`sh_tmu_probe()`**: Removes `pm_runtime_idle()` else branch (PM
   runtime stays active)

The trade-off is slightly higher power consumption (the TMU hardware
stays powered/clocked when not actively timing), but this is acceptable
given the alternative is a hard bug.

### 4. SUSPEND/RESUME SAFETY

I verified the suspend/resume paths still work correctly:
- `sh_tmu_clocksource_suspend` calls `__sh_tmu_disable` (still stops the
  channel) + `dev_pm_genpd_suspend` (handles power domain)
- `sh_tmu_clocksource_resume` calls `dev_pm_genpd_resume` +
  `__sh_tmu_enable` (still restores registers)
- Since `clk_enable` count stays at 1 (never disabled), the clock
  framework correctly restores hardware state after genpd resume

### 5. SCOPE AND RISK

- **Files affected**: 1 file (`drivers/clocksource/sh_tmu.c`)
- **Lines changed**: 18 deletions, 0 additions
- **Risk**: Very low - only removes code that dynamically toggles
  power/clock; the conservative approach (always-on) is simpler and
  safer
- **Regression potential**: The only downside is marginally higher power
  consumption on Renesas platforms using TMU, which is negligible
- **Self-contained**: No dependencies on other patches; the companion
  sh_cmt fix (`62524f285c11`) is for a different driver

### 6. APPLICABILITY TO STABLE TREES

I verified the file is **identical** in stable trees 5.15, 6.1, 6.6,
6.12, and the current HEAD (6.19). The patch will apply cleanly to all
active stable trees without any modification.

### 7. USER IMPACT

- **Who is affected**: Users running PREEMPT_RT kernels on Renesas ARM64
  platforms with TMU timers
- **Severity without fix**: Invalid wait context → potential sleeping in
  atomic context → system instability/hang on PREEMPT_RT
- **PREEMPT_RT relevance**: PREEMPT_RT has been merged into mainline and
  is supported in stable trees (verified PREEMPT_RT fixes exist in
  6.12.y stable). This is increasingly used in embedded/industrial
  systems.

### 8. CLASSIFICATION

This is a **locking/synchronization bug fix**:
- Fixes invalid wait context (raw spinlock → regular spinlock
  acquisition)
- Prevents potential sleeping in atomic context on PREEMPT_RT
- Reproducible with lockdep enabled (PROVE_LOCKING)
- Real-world impact on PREEMPT_RT builds (not theoretical)
- Small, surgical, single-driver fix
- Tested on real hardware
- Reviewed and signed off by subsystem maintainer

**YES** signals:
- Fixes a real lockdep BUG warning (potential deadlock/sleep-in-atomic)
- Small, contained fix (18 line deletions in one file)
- Tested-by experienced maintainer
- Applies cleanly to all stable trees
- No dependencies
- Conservative approach (remove complexity, not add it)

**NO** signals: None identified.

**YES**

 drivers/clocksource/sh_tmu.c | 18 ------------------
 1 file changed, 18 deletions(-)

diff --git a/drivers/clocksource/sh_tmu.c b/drivers/clocksource/sh_tmu.c
index beffff81c00f3..3fc6ed9b56300 100644
--- a/drivers/clocksource/sh_tmu.c
+++ b/drivers/clocksource/sh_tmu.c
@@ -143,16 +143,6 @@ static void sh_tmu_start_stop_ch(struct sh_tmu_channel *ch, int start)
 
 static int __sh_tmu_enable(struct sh_tmu_channel *ch)
 {
-	int ret;
-
-	/* enable clock */
-	ret = clk_enable(ch->tmu->clk);
-	if (ret) {
-		dev_err(&ch->tmu->pdev->dev, "ch%u: cannot enable clock\n",
-			ch->index);
-		return ret;
-	}
-
 	/* make sure channel is disabled */
 	sh_tmu_start_stop_ch(ch, 0);
 
@@ -174,7 +164,6 @@ static int sh_tmu_enable(struct sh_tmu_channel *ch)
 	if (ch->enable_count++ > 0)
 		return 0;
 
-	pm_runtime_get_sync(&ch->tmu->pdev->dev);
 	dev_pm_syscore_device(&ch->tmu->pdev->dev, true);
 
 	return __sh_tmu_enable(ch);
@@ -187,9 +176,6 @@ static void __sh_tmu_disable(struct sh_tmu_channel *ch)
 
 	/* disable interrupts in TMU block */
 	sh_tmu_write(ch, TCR, TCR_TPSC_CLK4);
-
-	/* stop clock */
-	clk_disable(ch->tmu->clk);
 }
 
 static void sh_tmu_disable(struct sh_tmu_channel *ch)
@@ -203,7 +189,6 @@ static void sh_tmu_disable(struct sh_tmu_channel *ch)
 	__sh_tmu_disable(ch);
 
 	dev_pm_syscore_device(&ch->tmu->pdev->dev, false);
-	pm_runtime_put(&ch->tmu->pdev->dev);
 }
 
 static void sh_tmu_set_next(struct sh_tmu_channel *ch, unsigned long delta,
@@ -552,7 +537,6 @@ static int sh_tmu_setup(struct sh_tmu_device *tmu, struct platform_device *pdev)
 		goto err_clk_unprepare;
 
 	tmu->rate = clk_get_rate(tmu->clk) / 4;
-	clk_disable(tmu->clk);
 
 	/* Map the memory resource. */
 	ret = sh_tmu_map_memory(tmu);
@@ -626,8 +610,6 @@ static int sh_tmu_probe(struct platform_device *pdev)
  out:
 	if (tmu->has_clockevent || tmu->has_clocksource)
 		pm_runtime_irq_safe(&pdev->dev);
-	else
-		pm_runtime_idle(&pdev->dev);
 
 	return 0;
 }
-- 
2.51.0

[PATCH AUTOSEL 6.19-6.18] irqchip/riscv-imsic: Add a CPU pm notifier to restore the IMSIC on exit
Posted by Sasha Levin 3 hours ago
From: Nick Hu <nick.hu@sifive.com>

[ Upstream commit f48b4bd0915bf61ac12b8c65c7939ebd03bc8abf ]

The IMSIC might be reset when the system enters a low power state, but on
exit nothing restores the registers, which prevents interrupt delivery.

Solve this by registering a CPU power management notifier, which restores
the IMSIC on exit.

Signed-off-by: Nick Hu <nick.hu@sifive.com>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Reviewed-by: Yong-Xuan Wang <yongxuan.wang@sifive.com>
Reviewed-by: Cyan Yang <cyan.yang@sifive.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
Reviewed-by: Nutty Liu <liujingqi@lanxincomputing.com>
Link: https://patch.msgid.link/20251202-preserve-aplic-imsic-v3-1-1844fbf1fe92@sifive.com
Signed-off-by: Sasha Levin <sashal@kernel.org>
---

LLM Generated explanations, may be completely bogus:

Now I have a comprehensive understanding. Let me summarize the analysis.

---

## Detailed Analysis

### 1. Commit Message Analysis

The commit message is clear and directly describes a **bug fix**: "The
IMSIC might be reset when the system enters a low power state, but on
exit nothing restores the registers, which prevents interrupt delivery."
This is unambiguous — without the fix, **interrupt delivery is broken**
after returning from a low power state.

The patch is from Nick Hu at SiFive (a major RISC-V silicon vendor),
signed-off by Thomas Gleixner (the overall irqchip maintainer), and
reviewed by:
- Anup Patel (original IMSIC driver author/maintainer at Ventana Micro)
- Yong-Xuan Wang, Cyan Yang (SiFive reviewers)
- Nutty Liu (Lanxin Computing)

This level of review by domain experts demonstrates the fix is well-
vetted.

### 2. Code Change Analysis

The change is minimal (31 lines added, 8 removed, single file) and
consists of three logical parts:

**a) Refactoring — extracting `imsic_hw_states_init()`:**

The existing code from `imsic_starting_cpu()` that handles hardware
register initialization is moved into a new helper:

```126:147:drivers/irqchip/irq-riscv-imsic-early.c
static int imsic_starting_cpu(unsigned int cpu)
{
        /* Mark per-CPU IMSIC state as online */
        imsic_state_online();

        /* Enable per-CPU parent interrupt */
        enable_percpu_irq(imsic_parent_irq,
irq_get_trigger_type(imsic_parent_irq));

        /* Setup IPIs */
        imsic_ipi_starting_cpu();

        /*
  - Interrupts identities might have been enabled/disabled while
  - this CPU was not running so sync-up local enable/disable state.
         */
        imsic_local_sync_all(true);

        /* Enable local interrupt delivery */
        imsic_local_delivery(true);

        return 0;
}
```

The three operations (`imsic_ipi_starting_cpu()`,
`imsic_local_sync_all(true)`, `imsic_local_delivery(true)`) are
extracted into `imsic_hw_states_init()`, which is then called from both
`imsic_starting_cpu()` and the new PM notifier.

**b) Adding the CPU PM notifier:**

A new `imsic_pm_notifier` function handles `CPU_PM_EXIT` by calling
`imsic_hw_states_init()`. This is the **exact same pattern** used by
GICv3 (`irq-gic-v3.c:1482`) and GIC (`irq-gic.c`), which have been
stable for years.

**c) Registering the notifier:**

The `imsic_early_probe()` return is changed from `return 0` to `return
cpu_pm_register_notifier(&imsic_pm_notifier_block)`.

### 3. Bug Mechanism and Severity

**The bug**: On RISC-V systems with SBI-based cpuidle (the standard CPU
idle mechanism), when a CPU enters a deep idle state, the SBI firmware
may power down the IMSIC. The `cpuidle-riscv-sbi.c` driver calls
`cpu_pm_enter()` before and `cpu_pm_exit()` after the idle transition.
`cpu_pm_exit()` fires `CPU_PM_EXIT` notifications to all registered
handlers. Without this patch, no handler exists for IMSIC, so:

1. `imsic_local_delivery` — the EIDELIVERY/EITHRESHOLD CSRs may be
   reset, disabling all interrupt delivery
2. `imsic_local_sync_all` — individual interrupt enable bits may be
   reset, leaving all interrupt sources disabled
3. `imsic_ipi_starting_cpu` — the IPI enable bit may be reset, breaking
   inter-processor interrupts

**Impact**: The CPU effectively becomes deaf to all interrupts — IPIs,
device interrupts, timer interrupts routed through IMSIC — after
returning from a deep idle state. This can cause:
- System hangs (no timer interrupts)
- IPI failures (scheduler hangs, RCU stalls)
- Device interrupt loss (I/O failures, network timeouts)

This bug affects any RISC-V system using IMSIC with cpuidle deep states
— which includes SiFive boards and other production RISC-V hardware.

### 4. Dependency Check

The patch is **self-contained**. It depends only on:
- `imsic_ipi_starting_cpu()` — exists in all stable trees with IMSIC
  (6.12.y+)
- `imsic_local_sync_all()` — exists in all stable trees with IMSIC
  (6.12.y+)
- `imsic_local_delivery()` — exists in all stable trees with IMSIC
  (6.12.y+)
- `cpu_pm_register_notifier()` — exists in all kernel versions (core
  kernel PM API)
- `cpuidle-riscv-sbi.c` — exists in all stable trees with IMSIC, and
  calls `cpu_pm_enter()`/`cpu_pm_exit()`

The companion APLIC patch (95a8ddde36601) touches a different driver
entirely and is not a dependency.

### 5. Backport Applicability

- **IMSIC driver exists**: 6.12.y through 6.19.y (added in v6.10)
- **Clean backport**: The `imsic_starting_cpu` function is byte-
  identical between the mainline pre-image and 6.12.y. Only minor
  context conflict in the `#include` section (6.12.y lacks
  `<linux/export.h>` that mainline has), trivially resolved.
- **Bug triggerable**: The cpuidle-riscv-sbi driver in 6.12.y already
  calls `cpu_pm_enter()`/`cpu_pm_exit()`, meaning the IMSIC registers
  get reset with no restoration.

### 6. Risk Assessment

**Very low risk**:
- The refactored code (`imsic_hw_states_init`) performs exactly the same
  operations as before — just from an additional call site
- The GICv3 driver has used this exact pattern (CPU PM notifier
  restoring interrupt controller state) for over a decade
- No behavior changes to the existing CPU hotplug path
- Well-reviewed by all key stakeholders

### 7. Conclusion

This is a clear-cut bug fix for a critical issue: **complete loss of
interrupt delivery** after RISC-V CPUs return from deep idle states. The
fix is:
- Small and surgical (31 lines added to a single file)
- Based on a well-established pattern (identical to GICv3/GIC CPU PM
  handling)
- Thoroughly reviewed by domain experts
- Self-contained with no dependencies on other patches
- Cleanly backportable to all stable trees containing IMSIC (6.12.y+)

**YES**

 drivers/irqchip/irq-riscv-imsic-early.c | 39 ++++++++++++++++++++-----
 1 file changed, 31 insertions(+), 8 deletions(-)

diff --git a/drivers/irqchip/irq-riscv-imsic-early.c b/drivers/irqchip/irq-riscv-imsic-early.c
index 6bac67cc0b6d9..ba903fa689bd5 100644
--- a/drivers/irqchip/irq-riscv-imsic-early.c
+++ b/drivers/irqchip/irq-riscv-imsic-early.c
@@ -7,6 +7,7 @@
 #define pr_fmt(fmt) "riscv-imsic: " fmt
 #include <linux/acpi.h>
 #include <linux/cpu.h>
+#include <linux/cpu_pm.h>
 #include <linux/export.h>
 #include <linux/interrupt.h>
 #include <linux/init.h>
@@ -123,14 +124,8 @@ static void imsic_handle_irq(struct irq_desc *desc)
 	chained_irq_exit(chip, desc);
 }
 
-static int imsic_starting_cpu(unsigned int cpu)
+static void imsic_hw_states_init(void)
 {
-	/* Mark per-CPU IMSIC state as online */
-	imsic_state_online();
-
-	/* Enable per-CPU parent interrupt */
-	enable_percpu_irq(imsic_parent_irq, irq_get_trigger_type(imsic_parent_irq));
-
 	/* Setup IPIs */
 	imsic_ipi_starting_cpu();
 
@@ -142,6 +137,18 @@ static int imsic_starting_cpu(unsigned int cpu)
 
 	/* Enable local interrupt delivery */
 	imsic_local_delivery(true);
+}
+
+static int imsic_starting_cpu(unsigned int cpu)
+{
+	/* Mark per-CPU IMSIC state as online */
+	imsic_state_online();
+
+	/* Enable per-CPU parent interrupt */
+	enable_percpu_irq(imsic_parent_irq, irq_get_trigger_type(imsic_parent_irq));
+
+	/* Initialize the IMSIC registers to enable the interrupt delivery */
+	imsic_hw_states_init();
 
 	return 0;
 }
@@ -157,6 +164,22 @@ static int imsic_dying_cpu(unsigned int cpu)
 	return 0;
 }
 
+static int imsic_pm_notifier(struct notifier_block *self, unsigned long cmd, void *v)
+{
+	switch (cmd) {
+	case CPU_PM_EXIT:
+		/* Initialize the IMSIC registers to enable the interrupt delivery */
+		imsic_hw_states_init();
+		break;
+	}
+
+	return NOTIFY_OK;
+}
+
+static struct notifier_block imsic_pm_notifier_block = {
+	.notifier_call = imsic_pm_notifier,
+};
+
 static int __init imsic_early_probe(struct fwnode_handle *fwnode)
 {
 	struct irq_domain *domain;
@@ -194,7 +217,7 @@ static int __init imsic_early_probe(struct fwnode_handle *fwnode)
 	cpuhp_setup_state(CPUHP_AP_IRQ_RISCV_IMSIC_STARTING, "irqchip/riscv/imsic:starting",
 			  imsic_starting_cpu, imsic_dying_cpu);
 
-	return 0;
+	return cpu_pm_register_notifier(&imsic_pm_notifier_block);
 }
 
 static int __init imsic_early_dt_init(struct device_node *node, struct device_node *parent)
-- 
2.51.0

[PATCH AUTOSEL 6.19-6.18] arm64/ftrace,bpf: Fix partial regs after bpf_prog_run
Posted by Sasha Levin 3 hours ago
From: Jiri Olsa <jolsa@kernel.org>

[ Upstream commit 276f3b6daf6024ae2742afd161e7418a5584a660 ]

Mahe reported issue with bpf_override_return helper not working when
executed from kprobe.multi bpf program on arm.

The problem is that on arm we use alternate storage for pt_regs object
that is passed to bpf_prog_run and if any register is changed (which
is the case of bpf_override_return) it's not propagated back to actual
pt_regs object.

Fixing this by introducing and calling ftrace_partial_regs_update function
to propagate the values of changed registers (ip and stack).

Reported-by: Mahe Tardy <mahe.tardy@gmail.com>
Signed-off-by: Jiri Olsa <jolsa@kernel.org>
Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
Reviewed-by: Steven Rostedt (Google) <rostedt@goodmis.org>
Acked-by: Will Deacon <will@kernel.org>
Link: https://lore.kernel.org/bpf/20260112121157.854473-1-jolsa@kernel.org
Signed-off-by: Sasha Levin <sashal@kernel.org>
---

LLM Generated explanations, may be completely bogus:

Now I have a complete picture. Let me provide the full analysis.

---

## Comprehensive Analysis

### 1. COMMIT MESSAGE ANALYSIS

The commit message is clear: `bpf_override_return` helper does not work
when executed from a **kprobe.multi** BPF program on arm64. This was
**reported by a real user** (Mahe Tardy), which indicates it's a real-
world bug affecting actual users. The fix has been **reviewed by Steven
Rostedt** (ftrace maintainer) and **acked by Will Deacon** (arm64
maintainer), two highly authoritative figures.

### 2. THE BUG MECHANISM (Detailed)

On arm64, the `ftrace_regs` structure (`struct __arch_ftrace_regs` in
`arch/arm64/include/asm/ftrace.h`) is **NOT** a wrapper around `pt_regs`
- it's a separate, smaller structure containing only x0-x8, fp, lr, sp,
pc. Arm64 defines `HAVE_ARCH_FTRACE_REGS`.

When `kprobe_multi_link_prog_run()` is called (in
`kernel/trace/bpf_trace.c`):

1. `ftrace_partial_regs(fregs, bpf_kprobe_multi_pt_regs_ptr())` copies
   data **from** `ftrace_regs` **to** a per-CPU `pt_regs` buffer. On
   arm64, this creates a **separate copy**.
2. `bpf_prog_run(link->link.prog, regs)` passes this `pt_regs` copy to
   the BPF program.
3. When `bpf_override_return` is called inside the BPF program, it
   modifies the `pt_regs` copy:
   - `regs_set_return_value(regs, rc)` - sets the return value
   - `override_function_with_return(regs)` - sets `regs->pc = regs->lr`
     (on arm64), redirecting execution to skip the probed function
4. **THE BUG**: After `bpf_prog_run()` returns, the modified `pt_regs`
   copy is simply discarded. The changes are **never propagated back**
   to the original `ftrace_regs`, so the instruction pointer override
   and return value changes are lost.

On x86_64 (and s390, powerpc, loongarch), this bug does NOT manifest
because they define `CONFIG_HAVE_FTRACE_REGS_HAVING_PT_REGS`, meaning
`ftrace_partial_regs()` returns a pointer directly into the
`ftrace_regs` structure — changes to the `pt_regs` automatically update
the `ftrace_regs`.

### 3. THE FIX

The fix introduces a new function `ftrace_partial_regs_update()` with
two variants:

- **For architectures without `HAVE_ARCH_FTRACE_REGS`** (x86, etc.):
  Empty no-op, because `pt_regs` is embedded in `ftrace_regs` directly.
- **For architectures with `HAVE_ARCH_FTRACE_REGS`** (arm64, riscv):
  Copies the instruction pointer and return value back from the separate
  `pt_regs` to the `ftrace_regs`:

```c
ftrace_regs_set_instruction_pointer(fregs, instruction_pointer(regs));
ftrace_regs_set_return_value(fregs, regs_return_value(regs));
```

And in `bpf_trace.c`, the fix calls this function after
`bpf_prog_run()`:
```c
ftrace_partial_regs_update(fregs, bpf_kprobe_multi_pt_regs_ptr());
```

### 4. SCOPE AND RISK ASSESSMENT

- **Files changed**: 2 files
- **Lines added**: ~25 (mostly documentation)
- **Lines removed**: 0
- **Actual code changes**: ~5 lines of actual logic
- **Risk**: Very LOW. The no-op version for non-arm64 architectures
  means zero impact on x86. The arm64 version just copies two values
  back.

### 5. DEPENDENCY CHECK - CRITICAL ISSUE

This is where the analysis gets complex. The affected code —
`kprobe_multi_link_prog_run()` using `ftrace_regs` and
`ftrace_partial_regs()` — was introduced as part of a massive fprobe
rewrite in the **v6.14 merge window**:

- `b9b55c8912ce1` (v6.14): `tracing: Add ftrace_partial_regs() for
  converting ftrace_regs to pt_regs`
- `46bc082388560` (v6.14): `fprobe: Use ftrace_regs in fprobe entry
  handler`
- `8e2759da9378` (v6.14): `bpf: Enable kprobe_multi feature if
  CONFIG_FPROBE is enabled`
- `4346ba1604093` (v6.14): `fprobe: Rewrite fprobe on function-graph
  tracer`

In **v6.13 and earlier** (6.12 LTS, 6.6 LTS, 6.1 LTS, 5.15 LTS),
`kprobe_multi_link_prog_run()` takes `struct pt_regs *regs` directly —
there is no `ftrace_regs` / `ftrace_partial_regs()` indirection. **The
bug simply does not exist in those older stable trees.**

The bug exists in: **v6.14, v6.15, v6.18** stable trees (all currently
maintained).

### 6. BACKPORT FEASIBILITY

The patch should apply cleanly to:
- **v6.14.y**: The code at `bpf_trace.c` is very similar (just needs
  adjustment for `migrate_disable/enable` which was still present in
  v6.14)
- **v6.15.y**: Very similar to HEAD
- **v6.18.y**: Identical to HEAD (`include/linux/ftrace_regs.h`
  unchanged since v6.14)

The `include/linux/ftrace_regs.h` change should apply cleanly to all
three. The `bpf_trace.c` change might need minor adjustment for v6.14
(which still has `migrate_disable()` calls), but the relevant line is
the same.

### 7. USER IMPACT

This bug makes `bpf_override_return` completely non-functional on arm64
when used from kprobe.multi programs. This is a significant feature
regression:
- `bpf_override_return` is used by BPF-based error injection frameworks
- arm64 is a major platform (server, embedded, Android)
- The bug was reported by an actual user

### 8. CLASSIFICATION

This is a **clear bug fix** for a **functional regression** introduced
in v6.14. It:
- Fixes a real, user-reported bug
- Is small and surgical (~5 lines of actual logic)
- Has been reviewed by the ftrace maintainer (Rostedt) and arm64
  maintainer (Will Deacon)
- Has clear scope and low regression risk
- Only affects arm64 and riscv (no impact on x86)

The fix meets all stable kernel criteria:
1. Obviously correct and tested (reviewed/acked by subsystem
   maintainers)
2. Fixes a real bug (user-reported, bpf_override_return completely
   broken on arm64)
3. Important issue (complete feature breakage on a major architecture)
4. Small and contained (2 files, ~5 lines of logic)
5. Does not introduce new features (just propagates existing register
   values back)

**YES**

 include/linux/ftrace_regs.h | 25 +++++++++++++++++++++++++
 kernel/trace/bpf_trace.c    |  1 +
 2 files changed, 26 insertions(+)

diff --git a/include/linux/ftrace_regs.h b/include/linux/ftrace_regs.h
index 15627ceea9bcc..386fa48c4a957 100644
--- a/include/linux/ftrace_regs.h
+++ b/include/linux/ftrace_regs.h
@@ -33,6 +33,31 @@ struct ftrace_regs;
 #define ftrace_regs_get_frame_pointer(fregs) \
 	frame_pointer(&arch_ftrace_regs(fregs)->regs)
 
+static __always_inline void
+ftrace_partial_regs_update(struct ftrace_regs *fregs, struct pt_regs *regs) { }
+
+#else
+
+/*
+ * ftrace_partial_regs_update - update the original ftrace_regs from regs
+ * @fregs: The ftrace_regs to update from @regs
+ * @regs: The partial regs from ftrace_partial_regs() that was updated
+ *
+ * Some architectures have the partial regs living in the ftrace_regs
+ * structure, whereas other architectures need to make a different copy
+ * of the @regs. If a partial @regs is retrieved by ftrace_partial_regs() and
+ * if the code using @regs updates a field (like the instruction pointer or
+ * stack pointer) it may need to propagate that change to the original @fregs
+ * it retrieved the partial @regs from. Use this function to guarantee that
+ * update happens.
+ */
+static __always_inline void
+ftrace_partial_regs_update(struct ftrace_regs *fregs, struct pt_regs *regs)
+{
+	ftrace_regs_set_instruction_pointer(fregs, instruction_pointer(regs));
+	ftrace_regs_set_return_value(fregs, regs_return_value(regs));
+}
+
 #endif /* HAVE_ARCH_FTRACE_REGS */
 
 /* This can be overridden by the architectures */
diff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c
index fe28d86f7c357..2a5dabda8b5c2 100644
--- a/kernel/trace/bpf_trace.c
+++ b/kernel/trace/bpf_trace.c
@@ -2564,6 +2564,7 @@ kprobe_multi_link_prog_run(struct bpf_kprobe_multi_link *link,
 	old_run_ctx = bpf_set_run_ctx(&run_ctx.session_ctx.run_ctx);
 	err = bpf_prog_run(link->link.prog, regs);
 	bpf_reset_run_ctx(old_run_ctx);
+	ftrace_partial_regs_update(fregs, bpf_kprobe_multi_pt_regs_ptr());
 	rcu_read_unlock();
 
  out:
-- 
2.51.0

[PATCH AUTOSEL 6.19-6.12] perf/x86/msr: Add Airmont NP
Posted by Sasha Levin 3 hours ago
From: Martin Schiller <ms@dev.tdt.de>

[ Upstream commit 63dbadcafc1f4d1da796a8e2c0aea1e561f79ece ]

Like Airmont, the Airmont NP (aka Intel / MaxLinear Lightning Mountain)
supports SMI_COUNT MSR.

Signed-off-by: Martin Schiller <ms@dev.tdt.de>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Reviewed-by: Dapeng Mi <dapeng1.mi@linux.intel.com>
Link: https://patch.msgid.link/20251124074846.9653-2-ms@dev.tdt.de
Signed-off-by: Sasha Levin <sashal@kernel.org>
---

LLM Generated explanations, may be completely bogus:

Here is my complete analysis:

---

## Analysis: perf/x86/msr: Add Airmont NP

### 1. Commit Message Analysis

The commit adds support for the Intel Airmont NP (aka Lightning Mountain
/ MaxLinear Lightning Mountain) CPU to the MSR perf driver. The commit
message explicitly states that "Like Airmont, the Airmont NP supports
SMI_COUNT MSR." This is a simple CPU model ID addition to an existing
driver/feature.

The commit was:
- Authored by Martin Schiller (ms@dev.tdt.de), who maintains patches for
  the Lightning Mountain SoC
- Signed off by Peter Zijlstra (Intel), the perf subsystem maintainer
- Reviewed by Dapeng Mi (Intel), an x86 perf developer

### 2. Code Change Analysis

The change is exactly **1 line** in a single file
(`arch/x86/events/msr.c`). It adds:

```c
case INTEL_ATOM_AIRMONT_NP:
```

right after the existing `case INTEL_ATOM_AIRMONT:` line in the
`test_intel()` function. This is a switch-case fall-through that enables
the `PERF_MSR_SMI` counter (which reads `MSR_SMI_COUNT`) for the Airmont
NP CPU model.

Without this patch, on Airmont NP systems:
- `test_intel()` returns `false` for `PERF_MSR_SMI`
- `perf_msr_probe()` skips the SMI counter
- The SMI perf counter is unavailable even though the hardware supports
  it
- Users cannot monitor SMI (System Management Interrupt) counts via perf
  on this CPU

### 3. Classification: CPU Model ID Addition

This falls squarely into the **"NEW DEVICE IDs"** exception category for
stable backports:
- It adds a CPU model ID to an **existing driver** (the MSR perf PMU)
- The driver already exists in all stable trees
- Only the CPU ID is new in the context of this driver
- The `INTEL_ATOM_AIRMONT_NP` / `INTEL_FAM6_ATOM_AIRMONT_NP` define has
  existed since kernel v5.4 (added September 2019 in commit
  `855fa1f362ca`)
- The CPU is already recognized in numerous other kernel subsystems
  (`common.c`, `intel.c`, `tsc_msr.c`, `intel_tcc.c`)

### 4. Scope and Risk Assessment

- **Lines changed**: 1 (absolute minimum)
- **Files touched**: 1
- **Complexity**: Trivially simple - adding a case label to an existing
  switch fall-through group
- **Risk of regression**: Essentially zero. The change only affects
  systems running on the Airmont NP CPU (model 0x75). For all other
  CPUs, behavior is completely unchanged. The added case falls through
  to the same `if (idx == PERF_MSR_SMI) return true;` that all other
  Atom variants in that group use.
- **Subsystem maturity**: The perf MSR driver is mature and stable; this
  same pattern of adding CPU model IDs has been repeated over a dozen
  times in the file's history.

### 5. User Impact

The Intel Airmont NP (Lightning Mountain) is a real SoC used in embedded
networking equipment (routers, CPE devices). Martin Schiller works for
TDT, which produces networking hardware using this SoC. Without this
patch, users of Lightning Mountain-based systems cannot use `perf` to
monitor SMI counts, which is useful for diagnosing system latency and
firmware issues.

The impact is:
- **Who**: Users of Intel Lightning Mountain / Airmont NP embedded
  systems
- **Severity**: Functionality gap - a hardware capability is not exposed
- **Real-world**: The patch author works with the hardware and submitted
  this based on actual need

### 6. Backport Feasibility

- **v6.12 and later**: Patch applies cleanly as-is (uses
  `INTEL_ATOM_AIRMONT_NP` and `x86_vfm`)
- **v6.6, v6.1, v5.15**: Requires trivial name adaptation
  (`INTEL_FAM6_ATOM_AIRMONT_NP` instead of `INTEL_ATOM_AIRMONT_NP`, and
  `x86_model` switch). The `INTEL_FAM6_ATOM_AIRMONT_NP` define exists in
  all these trees.
- **Dependencies**: None. This is a completely standalone one-line
  addition.

### 7. Precedent

The `arch/x86/events/msr.c` file has a long history of similar CPU model
ID additions (Tremont, Tiger Lake, Ice Lake, Comet Lake, Rocket Lake,
Alder Lake, Raptor Lake, Sapphire Rapids, Emerald Rapids, Meteor Lake,
Granite Rapids), all following the exact same pattern. These additions
are the textbook example of the "device ID addition" exception to stable
kernel rules.

### Conclusion

This is a textbook example of a CPU model ID addition to an existing
driver - one of the explicitly allowed exception categories for stable
backports. The change is:
- 1 line, 1 file
- Zero risk of regression to any other hardware
- Enables existing functionality on real hardware that real users depend
  on
- Completely standalone with no dependencies
- The required CPU ID defines exist in all active stable trees
- Following an established pattern seen many times in this exact file

**YES**

 arch/x86/events/msr.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/arch/x86/events/msr.c b/arch/x86/events/msr.c
index 7f5007a4752a1..8052596b85036 100644
--- a/arch/x86/events/msr.c
+++ b/arch/x86/events/msr.c
@@ -78,6 +78,7 @@ static bool test_intel(int idx, void *data)
 	case INTEL_ATOM_SILVERMONT:
 	case INTEL_ATOM_SILVERMONT_D:
 	case INTEL_ATOM_AIRMONT:
+	case INTEL_ATOM_AIRMONT_NP:
 
 	case INTEL_ATOM_GOLDMONT:
 	case INTEL_ATOM_GOLDMONT_D:
-- 
2.51.0
[PATCH AUTOSEL 6.19-6.18] genirq/cpuhotplug: Notify about affinity changes breaking the affinity mask
Posted by Sasha Levin 3 hours ago
From: Imran Khan <imran.f.khan@oracle.com>

[ Upstream commit dd9f6d30c64001ca4dde973ac04d8d155e856743 ]

During CPU offlining the interrupts affined to that CPU are moved to other
online CPUs, which might break the original affinity mask if the outgoing
CPU was the last online CPU in that mask. This change is not propagated to
irq_desc::affinity_notify(), which leaves users of the affinity notifier
mechanism with stale information.

Avoid this by scheduling affinity change notification work for interrupts
that were affined to the CPU being offlined, if the new target CPU is not
part of the original affinity mask.

Since irq_set_affinity_locked() uses the same logic to schedule affinity
change notification work, split out this logic into a dedicated function
and use that at both places.

[ tglx: Removed the EXPORT(), removed the !SMP stub, moved the prototype,
  	added a lockdep assert instead of a comment, fixed up coding style
  	and name space. Polished and clarified the change log ]

Signed-off-by: Imran Khan <imran.f.khan@oracle.com>
Signed-off-by: Thomas Gleixner <tglx@kernel.org>
Link: https://patch.msgid.link/20260113143727.1041265-1-imran.f.khan@oracle.com
Signed-off-by: Sasha Levin <sashal@kernel.org>
---

LLM Generated explanations, may be completely bogus:

Now I have all the information needed for a comprehensive analysis. Let
me compile my findings.

---

## Detailed Analysis

### 1. COMMIT MESSAGE ANALYSIS

The commit subject and body describe a clear, concrete bug: during CPU
offlining, interrupts are migrated away from the offlined CPU. When the
new target CPU is **not** part of the original affinity mask (i.e., the
affinity was "broken"), the `irq_desc::affinity_notify` mechanism is NOT
triggered. This leaves users of the affinity notifier (network drivers,
RFS/RPS, IB HFI1, etc.) with **stale CPU affinity information**.

Key details:
- Author: Imran Khan (Oracle), a recognized contributor
- Signed-off-by and edited by Thomas Gleixner (IRQ subsystem
  maintainer), who personally polished the changelog and code
- The `[tglx: ...]` notes show significant maintainer review and
  modification

### 2. CODE CHANGE ANALYSIS

The patch makes three changes across three files:

**a) `kernel/irq/manage.c` - Refactoring + bug fix enablement**

The inline notification logic in `irq_set_affinity_locked()`:

```350:381:kernel/irq/manage.c
int irq_set_affinity_locked(struct irq_data *data, const struct cpumask
*mask,
                            bool force)
{
        // ... elided ...
        if (desc->affinity_notify) {
                kref_get(&desc->affinity_notify->kref);
                if (!schedule_work(&desc->affinity_notify->work)) {
                        /* Work was already scheduled, drop our extra
ref */
                        kref_put(&desc->affinity_notify->kref,
                                 desc->affinity_notify->release);
                }
        }
```

is extracted into a new function `irq_affinity_schedule_notify_work()`,
and the original site is replaced by a call to this new function. This
is a pure refactoring at this call site -- no behavioral change.

The new function:

```python
void irq_affinity_schedule_notify_work(struct irq_desc *desc)
{
    lockdep_assert_held(&desc->lock);
    kref_get(&desc->affinity_notify->kref);
    if (!schedule_work(&desc->affinity_notify->work)) {
        kref_put(&desc->affinity_notify->kref,
desc->affinity_notify->release);
    }
}
```

This is identical logic to what was inline, plus a
`lockdep_assert_held()` for safety.

**b) `kernel/irq/cpuhotplug.c` - The actual bug fix**

In `irq_migrate_all_off_this_cpu()`, the patch adds:

```python
scoped_guard(raw_spinlock, &desc->lock) {
    affinity_broken = migrate_one_irq(desc);
    if (affinity_broken && desc->affinity_notify)
        irq_affinity_schedule_notify_work(desc);
}
```

This is the core fix: when `migrate_one_irq()` returns `true` (affinity
was broken), and the descriptor has an affinity notifier registered,
**schedule the notification work**. This is done inside the lock scope,
which is correct since `irq_affinity_schedule_notify_work` asserts
`desc->lock` is held.

**c) `kernel/irq/internals.h` - Declaration**

Adds `extern void irq_affinity_schedule_notify_work(struct irq_desc
*desc);` to the internal header.

### 3. BUG MECHANISM AND IMPACT

**Root cause:** The CPU hotplug IRQ migration path
(`irq_migrate_all_off_this_cpu` -> `migrate_one_irq` ->
`irq_do_set_affinity`) bypasses `irq_set_affinity_locked()` and calls
the lower-level `irq_do_set_affinity()` directly. The notification logic
was only in `irq_set_affinity_locked()`, so CPU hotplug IRQ migrations
**never** triggered affinity notifications.

**Who is affected:**

1. **`irq_cpu_rmap` (lib/cpu_rmap.c)** - Used by major network drivers
   (bnxt, sfc, mlx5, mlx4, hns3, i40e, qede, enic) for Receive Flow
   Steering (RFS). When CPU hotplug migrates IRQs, the rmap becomes
   stale, causing incorrect RFS steering decisions. This has existed
   since `cpuhotplug.c` was created in 2015.

2. **NAPI affinity tracking** (net/core/dev.c `netif_napi_irq_notify`) -
   Newer mechanism (v6.15+) where NAPI tracks IRQ CPU affinity. Stale
   data here means incorrect CPU affinity tracking after CPU offlining.

3. **InfiniBand HFI1 driver** (drivers/infiniband/hw/hfi1/affinity.c) -
   Uses affinity notifiers for SDMA engine management.

4. **Various other network drivers** (ionic, i40e, funeth, bnxt,
   qla2xxx, qedf) that directly use `irq_set_affinity_notifier()`.

**Real-world impact:** On systems doing CPU hotplug (common in cloud/VM
environments, power management, CPU isolation), network performance
degrades because RFS steering becomes incorrect. The CPU rmap points to
offline CPUs or wrong CPUs, causing suboptimal packet delivery.

### 4. CLASSIFICATION

This is a **real bug fix** -- not a feature, not cleanup. It fixes a
missing notification that causes stale data in multiple critical
subsystems (networking RFS, NAPI, InfiniBand).

### 5. SCOPE AND RISK ASSESSMENT

- **Lines changed:** ~30 lines (very small)
- **Files touched:** 3, all in `kernel/irq/` (contained)
- **Complexity:** Low. The new function is a direct extraction of
  existing inline code. The new call site is a straightforward
  conditional.
- **Risk of regression:** Very low. The notification work was already
  being scheduled from `irq_set_affinity_locked()` using the identical
  logic. Adding it to the CPU hotplug path uses the same proven
  mechanism.
- **Subsystem:** `kernel/irq/` - core infrastructure, but the change is
  very surgical

### 6. DEPENDENCY ANALYSIS

**Critical concern:** The patch as written uses
`scoped_guard(raw_spinlock, &desc->lock)` syntax, which was introduced
by commit `88a4df117ad66` ("genirq/cpuhotplug: Convert to lock guards")
merged in v6.16. Older stable trees (6.15 and below) use
`raw_spin_lock()`/`raw_spin_unlock()` directly, so **this patch would
not apply cleanly to those trees**.

For stable trees <= 6.15, a backport would need adaptation to use the
old locking style:

```c
raw_spin_lock(&desc->lock);
affinity_broken = migrate_one_irq(desc);
if (affinity_broken && desc->affinity_notify)
    irq_affinity_schedule_notify_work(desc);
raw_spin_unlock(&desc->lock);
```

This adaptation is trivial and mechanically straightforward.

### 7. STABILITY AND TESTING

- Thomas Gleixner (IRQ subsystem maintainer) personally reviewed,
  edited, and applied this patch
- The logic reuses proven existing code (the kref_get + schedule_work +
  kref_put pattern)
- The `lockdep_assert_held()` adds runtime verification in debug builds

### 8. CONCLUSION

This fixes a **real, longstanding bug** (since 2015) that causes stale
IRQ affinity information in the CPU hotplug path, affecting network
drivers using RFS (bnxt, sfc, mlx5, mlx4, hns3, i40e, qede, enic), NAPI
affinity tracking, and InfiniBand HFI1. The impact is concrete:
incorrect receive flow steering and CPU affinity tracking when CPUs go
offline, which is common in cloud, VM, and power-managed environments.

The fix is:
- Small and surgical (~30 lines)
- Obviously correct (reuses existing proven notification logic)
- Well-reviewed (Thomas Gleixner personally edited it)
- Low risk of regression
- Self-contained (no part of a series)
- Fixes a real user-visible issue (stale CPU affinity data)

The only concern is that it requires a trivial backport adaptation for
stable trees <= 6.15 due to the lock guard conversion. This is a
mechanical change.

**YES**

 kernel/irq/cpuhotplug.c |  6 ++++--
 kernel/irq/internals.h  |  2 +-
 kernel/irq/manage.c     | 26 ++++++++++++++++++--------
 3 files changed, 23 insertions(+), 11 deletions(-)

diff --git a/kernel/irq/cpuhotplug.c b/kernel/irq/cpuhotplug.c
index 755346ea98196..cd5689e383b00 100644
--- a/kernel/irq/cpuhotplug.c
+++ b/kernel/irq/cpuhotplug.c
@@ -177,9 +177,11 @@ void irq_migrate_all_off_this_cpu(void)
 		bool affinity_broken;
 
 		desc = irq_to_desc(irq);
-		scoped_guard(raw_spinlock, &desc->lock)
+		scoped_guard(raw_spinlock, &desc->lock) {
 			affinity_broken = migrate_one_irq(desc);
-
+			if (affinity_broken && desc->affinity_notify)
+				irq_affinity_schedule_notify_work(desc);
+		}
 		if (affinity_broken) {
 			pr_debug_ratelimited("IRQ %u: no longer affine to CPU%u\n",
 					    irq, smp_processor_id());
diff --git a/kernel/irq/internals.h b/kernel/irq/internals.h
index 0164ca48da59e..5568ed3a8b852 100644
--- a/kernel/irq/internals.h
+++ b/kernel/irq/internals.h
@@ -135,6 +135,7 @@ extern bool irq_can_set_affinity_usr(unsigned int irq);
 
 extern int irq_do_set_affinity(struct irq_data *data,
 			       const struct cpumask *dest, bool force);
+extern void irq_affinity_schedule_notify_work(struct irq_desc *desc);
 
 #ifdef CONFIG_SMP
 extern int irq_setup_affinity(struct irq_desc *desc);
@@ -142,7 +143,6 @@ extern int irq_setup_affinity(struct irq_desc *desc);
 static inline int irq_setup_affinity(struct irq_desc *desc) { return 0; }
 #endif
 
-
 #define for_each_action_of_desc(desc, act)			\
 	for (act = desc->action; act; act = act->next)
 
diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c
index 349ae7979da0e..4873b0f73df96 100644
--- a/kernel/irq/manage.c
+++ b/kernel/irq/manage.c
@@ -347,6 +347,21 @@ static bool irq_set_affinity_deactivated(struct irq_data *data,
 	return true;
 }
 
+/**
+ * irq_affinity_schedule_notify_work - Schedule work to notify about affinity change
+ * @desc:  Interrupt descriptor whose affinity changed
+ */
+void irq_affinity_schedule_notify_work(struct irq_desc *desc)
+{
+	lockdep_assert_held(&desc->lock);
+
+	kref_get(&desc->affinity_notify->kref);
+	if (!schedule_work(&desc->affinity_notify->work)) {
+		/* Work was already scheduled, drop our extra ref */
+		kref_put(&desc->affinity_notify->kref, desc->affinity_notify->release);
+	}
+}
+
 int irq_set_affinity_locked(struct irq_data *data, const struct cpumask *mask,
 			    bool force)
 {
@@ -367,14 +382,9 @@ int irq_set_affinity_locked(struct irq_data *data, const struct cpumask *mask,
 		irq_copy_pending(desc, mask);
 	}
 
-	if (desc->affinity_notify) {
-		kref_get(&desc->affinity_notify->kref);
-		if (!schedule_work(&desc->affinity_notify->work)) {
-			/* Work was already scheduled, drop our extra ref */
-			kref_put(&desc->affinity_notify->kref,
-				 desc->affinity_notify->release);
-		}
-	}
+	if (desc->affinity_notify)
+		irq_affinity_schedule_notify_work(desc);
+
 	irqd_set(data, IRQD_AFFINITY_SET);
 
 	return ret;
-- 
2.51.0
[PATCH AUTOSEL 6.19-6.12] sched/debug: Fix updating of ppos on server write ops
Posted by Sasha Levin 3 hours ago
From: Joel Fernandes <joelagnelf@nvidia.com>

[ Upstream commit 6080fb211672aec6ce8f2f5a2e0b4eae736f2027 ]

Updating "ppos" on error conditions does not make much sense. The pattern
is to return the error code directly without modifying the position, or
modify the position on success and return the number of bytes written.

Since on success, the return value of apply is 0, there is no point in
modifying ppos either. Fix it by removing all this and just returning
error code or number of bytes written on success.

Signed-off-by: Joel Fernandes <joelagnelf@nvidia.com>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Reviewed-by: Juri Lelli <juri.lelli@redhat.com>
Reviewed-by: Andrea Righi <arighi@nvidia.com>
Acked-by: Tejun Heo <tj@kernel.org>
Tested-by: Christian Loehle <christian.loehle@arm.com>
Link: https://patch.msgid.link/20260126100050.3854740-3-arighi@nvidia.com
Signed-off-by: Sasha Levin <sashal@kernel.org>
---

LLM Generated explanations, may be completely bogus:

The code is identical in 6.18 stable and the commit's parent. The patch
would apply cleanly to 6.18.y and 6.17.y.

Now I have all the information needed for a thorough analysis.

---

## Detailed Analysis

### 1. Commit Message Analysis

The commit is titled "sched/debug: Fix updating of ppos on server write
ops" — clearly labeled as a **fix**. The commit message describes
incorrect handling of the file position pointer (`ppos`) when
`dl_server_apply_params()` returns an error. The message has strong
review/test coverage:
- **Signed-off-by**: Joel Fernandes (NVIDIA), Peter Zijlstra (Intel
  scheduler maintainer)
- **Reviewed-by**: Juri Lelli (Red Hat), Andrea Righi (NVIDIA)
- **Acked-by**: Tejun Heo (well-known kernel developer)
- **Tested-by**: Christian Loehle (ARM)

### 2. Code Change Analysis — The Bug

The buggy code in `sched_fair_server_write()` (present since the fair
server was introduced in v6.12-rc1 via `d741f297bceaf`):

```c
retval = dl_server_apply_params(&rq->fair_server, runtime, period, 0);
if (retval)
    cnt = retval;       // cnt is size_t (unsigned), retval is int
(-EBUSY = -16)
                        // cnt becomes (size_t)-16 = 0xFFFFFFFFFFFFFFF0

// ... after scoped_guard ends ...
*ppos += cnt;           // ppos gets corrupted: advanced by ~18 exabytes
return cnt;             // returns (ssize_t)(size_t)(-16) = -16 = -EBUSY
(by accident)
```

When `dl_server_apply_params()` fails with `-EBUSY` (bandwidth
overflow), two problems occur:

**Problem 1 — `*ppos` corruption**: The negative error code `-16` is
assigned to `cnt` (type `size_t`, unsigned), producing
`0xFFFFFFFFFFFFFFF0` on 64-bit. This massive value is then added to
`*ppos`, corrupting the file position. While this "accidentally" works
for returning the error code (due to 2's complement), the file position
becomes garbage. Subsequent writes to the same file descriptor will
operate at a corrupt offset.

**Problem 2 — Type-unsafe error propagation**: The error code is passed
through `size_t` (unsigned) and back to `ssize_t` (signed). While this
works by coincidence on 2's complement architectures, it's semantically
incorrect and relies on implementation-defined behavior.

The fix is clean:
1. Initialize `retval = 0`
2. Remove the `if (retval) cnt = retval;` hack
3. After the server restart, check `if (retval < 0) return retval;` —
   properly returning the error code without modifying `ppos`
4. On success, `*ppos += cnt; return cnt;` works correctly as before

### 3. Classification

This is a **real bug fix** for incorrect error handling in a debugfs
write interface. It's not a feature, not a cleanup — the commit fixes
actual incorrect behavior (ppos corruption on error).

### 4. Scope and Risk Assessment

- **Lines changed**: 7 (4 insertions, 3 deletions) — extremely small
- **Files touched**: 1 (`kernel/sched/debug.c`)
- **Risk**: Minimal. The change is purely about error path handling. The
  success path is unchanged.
- **Self-contained**: Yes, no dependencies on other commits in the
  series

### 5. User Impact

- **Who is affected**: Any user writing to
  `/sys/kernel/debug/sched/fair_server/cpuN/{runtime,period}` when
  `dl_server_apply_params()` fails (returns `-EBUSY` due to bandwidth
  overflow)
- **Severity**: Low-to-moderate. Debugfs is root-only, and the `-EBUSY`
  error path is somewhat uncommon. However, when triggered, it corrupts
  the file position, which could confuse tools writing to this interface
- **Affected versions**: All kernels 6.12+ (since the fair server
  interface was introduced)

### 6. Stability and Clean Backport

- The bug exists identically in all stable trees from 6.12.y through
  6.18.y
- The fix applies cleanly to 6.17.y and 6.18.y (identical code)
- For 6.12.y through 6.16.y, minor context adaptation may be needed
  (different `dl_server_stop` conditional, `h_nr_running` vs
  `h_nr_queued`), but the core fix is the same
- Well-tested: Tested-by, multiple Reviewed-by tags from respected
  developers
- Signed off by the scheduler maintainer (Peter Zijlstra)

### 7. Dependency Check

- The commit does NOT depend on patch 2 in the series (which only
  touches `deadline.c`)
- It does NOT depend on the `kstrtoull_from_user` conversion (that
  conversion affected `sched_scaling_write`, not the fair server write)
- The affected code exists in all stable trees from 6.12 onward

### Decision

This commit fixes a real bug (file position corruption on error path) in
the scheduler's debugfs interface. It is:
- Small and surgical (7 lines)
- Obviously correct
- Well-reviewed and tested by multiple kernel developers including the
  scheduler maintainer
- Self-contained with no dependencies
- Applicable to all stable trees 6.12+

The severity is on the lower end (debugfs, root-only, uncommon error
path), but the fix is low-risk and clearly beneficial. The code was
incorrect from day one.

**YES**

 kernel/sched/debug.c | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/kernel/sched/debug.c b/kernel/sched/debug.c
index 41caa22e0680a..93f009e1076d8 100644
--- a/kernel/sched/debug.c
+++ b/kernel/sched/debug.c
@@ -345,8 +345,8 @@ static ssize_t sched_fair_server_write(struct file *filp, const char __user *ubu
 	long cpu = (long) ((struct seq_file *) filp->private_data)->private;
 	struct rq *rq = cpu_rq(cpu);
 	u64 runtime, period;
+	int retval = 0;
 	size_t err;
-	int retval;
 	u64 value;
 
 	err = kstrtoull_from_user(ubuf, cnt, 10, &value);
@@ -380,8 +380,6 @@ static ssize_t sched_fair_server_write(struct file *filp, const char __user *ubu
 		dl_server_stop(&rq->fair_server);
 
 		retval = dl_server_apply_params(&rq->fair_server, runtime, period, 0);
-		if (retval)
-			cnt = retval;
 
 		if (!runtime)
 			printk_deferred("Fair server disabled in CPU %d, system may crash due to starvation.\n",
@@ -389,6 +387,9 @@ static ssize_t sched_fair_server_write(struct file *filp, const char __user *ubu
 
 		if (rq->cfs.h_nr_queued)
 			dl_server_start(&rq->fair_server);
+
+		if (retval < 0)
+			return retval;
 	}
 
 	*ppos += cnt;
-- 
2.51.0

[PATCH AUTOSEL 6.19-6.18] perf/x86/intel: Add Airmont NP
Posted by Sasha Levin 3 hours ago
From: Martin Schiller <ms@dev.tdt.de>

[ Upstream commit a08340fd291671c54d379d285b2325490ce90ddd ]

The Intel / MaxLinear Airmont NP (aka Lightning Mountain) supports the
same architectual and non-architecural events as Airmont.

Signed-off-by: Martin Schiller <ms@dev.tdt.de>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Reviewed-by: Dapeng Mi <dapeng1.mi@linux.intel.com>
Link: https://patch.msgid.link/20251124074846.9653-3-ms@dev.tdt.de
Signed-off-by: Sasha Levin <sashal@kernel.org>
---

LLM Generated explanations, may be completely bogus:

This confirms the commit under review only touches `core.c`, and other
files in the perf events subsystem also lack Airmont NP support (which
may be handled by other patches in the series, but this commit is
standalone).

---

## Comprehensive Analysis

### 1. COMMIT MESSAGE ANALYSIS

**Subject:** `perf/x86/intel: Add Airmont NP`

The commit adds the `INTEL_ATOM_AIRMONT_NP` (Lightning Mountain SoC, CPU
model 0x75) case label to the Silvermont/Airmont PMU initialization
block in `intel_pmu_init()`. The commit message states this CPU supports
the same architectural and non-architectural events as Airmont, so it
should share the same event tables.

The commit was reviewed by `Dapeng Mi <dapeng1.mi@linux.intel.com>` (an
Intel PMU engineer) and merged by Peter Zijlstra. The patch link
`20251124074846.9653-3-ms@dev.tdt.de` indicates this is patch 3 of a
series, but the change itself is self-contained.

### 2. CODE CHANGE ANALYSIS

The diff shows a **single-line addition**:

```7407:7408:arch/x86/events/intel/core.c
        case INTEL_ATOM_AIRMONT:
        case INTEL_ATOM_AIRMONT_NP:
```

This adds `case INTEL_ATOM_AIRMONT_NP:` to an existing `switch
(boot_cpu_data.x86_vfm)` case block that groups Silvermont and Airmont
CPUs together. The block configures:
- Cache event IDs (`slm_hw_cache_event_ids`)
- Cache extra regs (`slm_hw_cache_extra_regs`)
- LBR initialization (`intel_pmu_lbr_init_slm()`)
- Event constraints (`intel_slm_event_constraints`)
- PEBS constraints (`intel_slm_pebs_event_constraints`)
- Extra registers (`intel_slm_extra_regs`)
- TopDown and format attributes

**Without this patch:** On Airmont NP (Lightning Mountain) systems,
`intel_pmu_init()` falls through to the `default:` case, which only
provides generic architectural perfmon support (using the version-based
sub-switch). Users would get:
- No Silvermont-specific hardware cache event support
- No LBR (Last Branch Record) support
- Generic event constraints instead of Silvermont-tuned ones
- No PEBS (Processor Event-Based Sampling) support appropriate for the
  microarchitecture
- No TopDown or extra format attributes

This significantly degrades perf monitoring capability on real hardware.

### 3. CLASSIFICATION

This is a **device ID addition to an existing driver**, which is one of
the explicitly enumerated exceptions allowed in stable:

> "NEW DEVICE IDs (Very Common): Adding PCI IDs, USB IDs, ACPI IDs, etc.
to existing drivers. These are trivial one-line additions that enable
hardware support. Rule: The driver must already exist in stable; only
the ID is new."

The `INTEL_ATOM_AIRMONT_NP` define (model `IFM(6, 0x75)`) has existed in
`arch/x86/include/asm/intel-family.h` since kernel v5.4 (commit
`855fa1f362ca`, September 2019). This means it is available in **all
currently maintained stable trees** (5.4, 5.10, 5.15, 6.1, 6.6, 6.12).
The Silvermont/Airmont event tables and LBR code all predate v5.4 as
well.

The CPU model is already handled in multiple other subsystems:
- `arch/x86/kernel/cpu/common.c` - vulnerability whitelist
- `arch/x86/kernel/cpu/intel.c` - TSC features
- `arch/x86/kernel/tsc_msr.c` - TSC frequency
- `drivers/thermal/intel/intel_tcc.c` - thermal management

The perf events subsystem was simply missed when the CPU ID was first
added.

### 4. SCOPE AND RISK ASSESSMENT

- **Lines changed:** 1 (single `case` label addition)
- **Files touched:** 1 (`arch/x86/events/intel/core.c`)
- **Risk:** Extremely low - this is a fall-through case label addition
  to an existing switch block. It only affects systems with CPUID family
  6 model 0x75. No other CPU model is affected.
- **Dependencies:** None. `INTEL_ATOM_AIRMONT_NP` is already defined in
  `intel-family.h` in all stable trees. The Silvermont event tables all
  exist in stable.

### 5. USER IMPACT

The Lightning Mountain (Airmont NP) SoC is used in Intel/MaxLinear
network gateway devices. The author Martin Schiller is from TDT GmbH, a
networking equipment company, and has several commits related to
Lantiq/Intel LGM networking platforms. This is a real embedded platform
with real users who need proper perf support.

Without this patch, `perf stat`, `perf record`, and other perf tools
provide only basic generic counter support, missing the Silvermont-
specific events, PEBS, LBR, and proper event constraints.

### 6. STABILITY INDICATORS

- **Reviewed-by:** Dapeng Mi (Intel PMU engineer)
- **Merged by:** Peter Zijlstra (perf subsystem maintainer)
- **Pattern:** This is a well-established pattern - the switch statement
  in `intel_pmu_init()` has dozens of similar case additions over the
  years
- **No possible regression:** Only affects one specific CPU model

### 7. DEPENDENCY CHECK

The commit is fully self-contained. The `INTEL_ATOM_AIRMONT_NP` macro
exists in all stable trees since v5.4. The Silvermont event tables and
LBR code it hooks into have existed since well before v5.4. No other
patches from the series are required for this change to be correct and
useful.

### Conclusion

This is a textbook example of a device ID addition to an existing driver
- a single `case` label adding CPU model support to the perf PMU
initialization switch statement. The CPU model define has existed in the
kernel since v5.4. The change is trivially correct (confirmed by Intel
PMU engineer review), zero-risk (only affects one specific CPU model),
and enables proper perf monitoring on real embedded hardware. It matches
the explicit stable exception for device ID additions perfectly.

**YES**

 arch/x86/events/intel/core.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/arch/x86/events/intel/core.c b/arch/x86/events/intel/core.c
index bdf3f0d0fe216..d85df652334fb 100644
--- a/arch/x86/events/intel/core.c
+++ b/arch/x86/events/intel/core.c
@@ -7405,6 +7405,7 @@ __init int intel_pmu_init(void)
 	case INTEL_ATOM_SILVERMONT_D:
 	case INTEL_ATOM_SILVERMONT_MID:
 	case INTEL_ATOM_AIRMONT:
+	case INTEL_ATOM_AIRMONT_NP:
 	case INTEL_ATOM_SILVERMONT_MID2:
 		memcpy(hw_cache_event_ids, slm_hw_cache_event_ids,
 			sizeof(hw_cache_event_ids));
-- 
2.51.0
[PATCH AUTOSEL 6.19-5.10] mailbox: bcm-ferxrm-mailbox: Use default primary handler
Posted by Sasha Levin 3 hours ago
From: Sebastian Andrzej Siewior <bigeasy@linutronix.de>

[ Upstream commit 03843d95a4a4e0ba22ad4fcda65ccf21822b104c ]

request_threaded_irq() is invoked with a primary and a secondary handler
and no flags are passed. The primary handler is the same as
irq_default_primary_handler() so there is no need to have an identical
copy.

The lack of the IRQF_ONESHOT flag can be dangerous because the interrupt
source is not masked while the threaded handler is active. This means,
especially on LEVEL typed interrupt lines, the interrupt can fire again
before the threaded handler had a chance to run.

Use the default primary interrupt handler by specifying NULL and set
IRQF_ONESHOT so the interrupt source is masked until the secondary handler
is done.

Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
Signed-off-by: Thomas Gleixner <tglx@kernel.org>
Link: https://patch.msgid.link/20260128095540.863589-5-bigeasy@linutronix.de
Signed-off-by: Sasha Levin <sashal@kernel.org>
---

LLM Generated explanations, may be completely bogus:

## Complete Analysis

### 1. COMMIT MESSAGE ANALYSIS

The subject says "Use default primary handler" which sounds like a
cleanup, but the commit body reveals a real bug:

> "The lack of the IRQF_ONESHOT flag can be dangerous because the
interrupt source is not masked while the threaded handler is active.
This means, especially on LEVEL typed interrupt lines, the interrupt can
fire again before the threaded handler had a chance to run."

The authors are Sebastian Andrzej Siewior (bigeasy, a core IRQ/RT
developer) and Thomas Gleixner (the IRQ subsystem maintainer and co-
author of the `__setup_irq` protection). This is coming from the very
people who understand threaded IRQ semantics best.

### 2. CODE CHANGE ANALYSIS

The change is small and surgical — two distinct modifications:

**A) Remove the redundant `flexrm_irq_event` primary handler:**

```1176:1182:drivers/mailbox/bcm-flexrm-mailbox.c
static irqreturn_t flexrm_irq_event(int irq, void *dev_id)
{
        /* We only have MSI for completions so just wakeup IRQ thread */
        /* Ring related errors will be informed via completion
descriptors */

        return IRQ_WAKE_THREAD;
}
```

This function is **identical** in behavior to
`irq_default_primary_handler()` in `kernel/irq/manage.c`:

```976:979:kernel/irq/manage.c
static irqreturn_t irq_default_primary_handler(int irq, void *dev_id)
{
        return IRQ_WAKE_THREAD;
}
```

Both simply return `IRQ_WAKE_THREAD`. There's zero functional
difference.

**B) Change the `request_threaded_irq()` call:**

Old code:
```
request_threaded_irq(ring->irq, flexrm_irq_event, flexrm_irq_thread, 0,
...)
```

New code:
```
request_threaded_irq(ring->irq, NULL, flexrm_irq_thread, IRQF_ONESHOT,
...)
```

### 3. THE BUG MECHANISM

This is a real bug with two dimensions:

**Dimension 1: Missing IRQF_ONESHOT on non-ONESHOT_SAFE interrupts**

The bcm-flexrm-mailbox driver uses **platform MSI** (via
`platform_device_msi_init_and_alloc_irqs()`), NOT PCI MSI. I verified
that while PCI MSI irqchips have `IRQCHIP_ONESHOT_SAFE` set (in
`drivers/pci/msi/irqdomain.c`), platform MSI does NOT. This means the
IRQ subsystem's safety net — automatically stripping `IRQF_ONESHOT` for
chips that don't need it — does not apply here.

Without `IRQF_ONESHOT`, the interrupt line is **not masked** while the
threaded handler (`flexrm_irq_thread`) runs. On a **level-triggered**
interrupt line, this creates an interrupt storm:
1. Interrupt fires → primary handler returns `IRQ_WAKE_THREAD`
2. Interrupt line is re-enabled immediately (no masking)
3. Device still has the line asserted → interrupt fires again
   immediately
4. Goto 1 — the thread never gets to run, the system is stuck in hard
   IRQ context

The commit message explicitly describes this: "especially on LEVEL typed
interrupt lines, the interrupt can fire again before the threaded
handler had a chance to run."

**Dimension 2: Forced threading bypass**

The old code provided an explicit primary handler (`flexrm_irq_event`),
even though it's functionally identical to
`irq_default_primary_handler`. This is problematic because
`irq_setup_forced_threading()` has a special check:

```1302:1303:kernel/irq/manage.c
        if (new->handler == irq_default_primary_handler)
                return 0;
```

When `handler != irq_default_primary_handler` (i.e., it's the driver's
custom `flexrm_irq_event`), forced threading proceeds and creates a
**secondary action** with the original thread handler, and converts the
primary handler to run in a thread too. This is wasteful and changes the
behavior on PREEMPT_RT kernels — instead of a simple wake-and-handle
flow, it creates an unnecessary secondary handler chain. But more
critically, with the old code and forced threading, the check at line
1295:

```1295:1296:kernel/irq/manage.c
        if (new->flags & (IRQF_NO_THREAD | IRQF_PERCPU | IRQF_ONESHOT))
                return 0;
```

Since flags=0 (no IRQF_ONESHOT), forced threading continues and sets
`IRQF_ONESHOT` at line 1305. But without forced threading (normal
kernels), IRQF_ONESHOT is never set, and the interrupt runs without
masking.

**Why the old code doesn't hit the __setup_irq safety check:**

The `__setup_irq` code at line 1664-1684 rejects `handler==NULL` without
`IRQF_ONESHOT` by checking `new->handler ==
irq_default_primary_handler`. But since the old code passes
`flexrm_irq_event` (a different function pointer that does the same
thing), this safety check is **bypassed**. The driver sneaks past the
protection that Thomas Gleixner himself added in commit 1c6c69525b40e
("genirq: Reject bogus threaded irq requests").

### 4. CLASSIFICATION

This is a **bug fix** — specifically fixing a potential interrupt storm
/ system hang on level-triggered interrupt configurations. It's
disguised as cleanup but addresses a real correctness issue.

### 5. SCOPE AND RISK ASSESSMENT

- **Lines changed:** ~10 lines removed, ~2 lines changed — extremely
  small
- **Files touched:** 1 file (`drivers/mailbox/bcm-flexrm-mailbox.c`)
- **Risk:** Very low. The change is:
  - Removing dead code (a function identical to
    `irq_default_primary_handler`)
  - Passing `NULL` + `IRQF_ONESHOT` instead of a custom handler +
    flags=0
  - This is the canonical correct way to request a threaded IRQ with no
    real primary handler
- **Could it break something?** No. The behavior with `IRQF_ONESHOT` is
  strictly safer — the interrupt is masked during threaded handler
  execution. The primary handler behavior is identical
  (`IRQ_WAKE_THREAD`).

### 6. USER IMPACT

- This driver is used on Broadcom iProc SoCs (embedded ARM) for FlexRM
  offload engine mailbox operations
- The bug manifests as an **interrupt storm causing system hang** on
  level-triggered interrupt configurations
- Even on edge-triggered (MSI) configurations, the missing
  `IRQF_ONESHOT` creates a window where the interrupt can re-fire before
  the thread handler runs, potentially causing lost completions or
  spurious interrupt warnings

### 7. STABILITY INDICATORS

- **Author:** Sebastian Andrzej Siewior — a core kernel developer,
  especially for PREEMPT_RT and IRQ subsystem
- **Acked by:** Thomas Gleixner — the IRQ subsystem maintainer and
  creator of the `__setup_irq` safety checks
- The fix follows a well-established pattern used across many drivers
- The patch is self-contained with no dependencies

### 8. DEPENDENCY CHECK

The code being modified exists in all stable trees that have this
driver. The driver `bcm-flexrm-mailbox.c` has been in the kernel since
at least v4.14. The `request_threaded_irq()` with `NULL` +
`IRQF_ONESHOT` pattern has been supported since the genirq safety check
was added in 2012 (commit 1c6c69525b40e). This patch applies cleanly to
any stable tree.

### CONCLUSION

This commit fixes a real bug: a missing `IRQF_ONESHOT` flag that can
cause an interrupt storm and system hang on level-triggered interrupt
lines. The old code also inadvertently bypassed the kernel's own safety
check for this exact scenario (by providing a custom handler identical
to the default one). The fix is small (net -10 lines), self-contained,
authored by core IRQ subsystem developers, and follows the canonical
pattern for threaded interrupts. It has zero risk of regression —
`IRQF_ONESHOT` is strictly correct and the removed handler was
functionally identical to the default.

**YES**

 drivers/mailbox/bcm-flexrm-mailbox.c | 14 ++------------
 1 file changed, 2 insertions(+), 12 deletions(-)

diff --git a/drivers/mailbox/bcm-flexrm-mailbox.c b/drivers/mailbox/bcm-flexrm-mailbox.c
index 41f79e51d9e5a..4255fefc3a5a0 100644
--- a/drivers/mailbox/bcm-flexrm-mailbox.c
+++ b/drivers/mailbox/bcm-flexrm-mailbox.c
@@ -1173,14 +1173,6 @@ static int flexrm_debugfs_stats_show(struct seq_file *file, void *offset)
 
 /* ====== FlexRM interrupt handler ===== */
 
-static irqreturn_t flexrm_irq_event(int irq, void *dev_id)
-{
-	/* We only have MSI for completions so just wakeup IRQ thread */
-	/* Ring related errors will be informed via completion descriptors */
-
-	return IRQ_WAKE_THREAD;
-}
-
 static irqreturn_t flexrm_irq_thread(int irq, void *dev_id)
 {
 	flexrm_process_completions(dev_id);
@@ -1271,10 +1263,8 @@ static int flexrm_startup(struct mbox_chan *chan)
 		ret = -ENODEV;
 		goto fail_free_cmpl_memory;
 	}
-	ret = request_threaded_irq(ring->irq,
-				   flexrm_irq_event,
-				   flexrm_irq_thread,
-				   0, dev_name(ring->mbox->dev), ring);
+	ret = request_threaded_irq(ring->irq, NULL, flexrm_irq_thread,
+				   IRQF_ONESHOT, dev_name(ring->mbox->dev), ring);
 	if (ret) {
 		dev_err(ring->mbox->dev,
 			"failed to request ring%d IRQ\n", ring->num);
-- 
2.51.0

[PATCH AUTOSEL 6.19-6.12] perf/x86/cstate: Add Airmont NP
Posted by Sasha Levin 3 hours ago
From: Martin Schiller <ms@dev.tdt.de>

[ Upstream commit 3006911f284d769b0f66c12b39da130325ef1440 ]

From the perspective of Intel cstate residency counters, the Airmont NP
(aka Lightning Mountain) is identical to the Airmont.

Signed-off-by: Martin Schiller <ms@dev.tdt.de>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Reviewed-by: Dapeng Mi <dapeng1.mi@linux.intel.com>
Link: https://patch.msgid.link/20251124074846.9653-4-ms@dev.tdt.de
Signed-off-by: Sasha Levin <sashal@kernel.org>
---

LLM Generated explanations, may be completely bogus:

Now I have a complete picture. Here is my analysis:

---

## Detailed Analysis of "perf/x86/cstate: Add Airmont NP"

### 1. COMMIT MESSAGE ANALYSIS

The commit adds a single CPU model ID entry for Intel Airmont NP (also
known as Lightning Mountain, CPU model 0x75) to the perf cstate
residency counter driver's match table. The author, Martin Schiller from
TDT (a networking hardware company), states that from the perspective of
cstate residency counters, Airmont NP is identical to regular Airmont.
The patch was reviewed by Dapeng Mi (Intel) and signed off by Peter
Zijlstra (Intel), the perf maintainer.

The message ID `20251124074846.9653-4-ms@dev.tdt.de` indicates this is
patch 4 of a multi-patch series, which likely adds Airmont NP support to
several Intel subsystems simultaneously.

### 2. CODE CHANGE ANALYSIS

The change is a single line addition:

```c
X86_MATCH_VFM(INTEL_ATOM_AIRMONT_NP,    &slm_cstates),
```

This maps CPU model `INTEL_ATOM_AIRMONT_NP` (IFM(6, 0x75)) to the
`slm_cstates` configuration, which provides:
- **Core events**: C1 and C6 residency counters
- **Package events**: C6 residency counter (using the C7 MSR quirk)

This is the exact same cstate model used by Silvermont
(`INTEL_ATOM_SILVERMONT`), Silvermont-D (`INTEL_ATOM_SILVERMONT_D`), and
regular Airmont (`INTEL_ATOM_AIRMONT`). The Airmont NP is
architecturally an Airmont-based SoC, so sharing the same cstate
configuration is technically correct and expected.

### 3. CLASSIFICATION: NEW DEVICE ID

This falls squarely into the **"New Device ID"** exception category for
stable backports:
- The driver (`arch/x86/events/intel/cstate.c`) already exists in all
  stable trees back to v5.4
- The `slm_cstates` model structure already exists unchanged in all
  stable trees
- The `INTEL_ATOM_AIRMONT_NP` (or `INTEL_FAM6_ATOM_AIRMONT_NP`) macro
  has been defined since v5.4 (commit 855fa1f362ca from September 2019)
- Only the ID-to-model mapping is new

### 4. SCOPE AND RISK ASSESSMENT

- **Lines changed**: 1 addition
- **Files touched**: 1 (`arch/x86/events/intel/cstate.c`)
- **Complexity**: Trivial - a single entry in a match table
- **Risk of regression**: Essentially zero. The new line only activates
  when running on an Airmont NP CPU (model 0x75). It cannot affect any
  other CPU or any other code path.

### 5. USER IMPACT

Without this patch, users running Linux on the Intel Lightning Mountain
SoC (used in networking/embedded equipment like DSL/fiber routers from
companies such as TDT) cannot access perf cstate residency counters.
These counters are used by power management monitoring tools like `perf`
and `turbostat` to measure CPU power states. While not a crash or data
corruption bug, this is a hardware support gap for real users on real
hardware.

The Lightning Mountain SoC vulnerability whitelist entry already exists
in `arch/x86/kernel/cpu/common.c` (since earlier kernels), and
`arch/x86/kernel/tsc_msr.c` already has Airmont NP support. The cstate
driver was simply overlooked.

### 6. BACKPORTABILITY TO STABLE TREES

The change requires trivial adaptation for different stable trees due to
macro naming:

- **v6.12+**: Uses `X86_MATCH_VFM(INTEL_ATOM_AIRMONT_NP, &slm_cstates)`
  - applies as-is
- **v6.1, v6.6**: Uses `X86_MATCH_INTEL_FAM6_MODEL(ATOM_AIRMONT_NP,
  &slm_cstates)` - trivial macro name change
- **v5.4, v5.10, v5.15**: Uses
  `X86_CSTATES_MODEL(INTEL_FAM6_ATOM_AIRMONT_NP, slm_cstates)` (v5.4) or
  `X86_MATCH_INTEL_FAM6_MODEL` variant - trivial adaptation

All prerequisites (`slm_cstates` struct, the `AIRMONT_NP` macro) exist
in every supported stable tree.

### 7. DEPENDENCY CHECK

This commit is self-contained. While it's part of a series (patch 4/N),
each patch in such a series independently adds a CPU ID to a different
driver's match table. No other commits are needed for this one to
function correctly.

### 8. STABILITY INDICATORS

- **Reviewed-by**: Dapeng Mi (Intel) - domain expert
- **Signed-off-by**: Peter Zijlstra (Intel) - perf subsystem maintainer
- The pattern is well-established: every other Atom variant (Silvermont,
  Silvermont-D, Airmont, Goldmont, Tremont, etc.) follows the exact same
  pattern in this driver

---

## Summary

This is a textbook CPU ID addition to an existing driver - the exact
type of change that stable kernel rules explicitly permit as an
exception. It's a single-line, zero-risk change that enables hardware
monitoring on real embedded/networking hardware (Intel Lightning
Mountain SoC). The driver infrastructure, cstate model, and CPU ID
definitions are all already present in every supported stable tree. The
patch was reviewed by an Intel engineer and accepted by the perf
maintainer.

**YES**

 arch/x86/events/intel/cstate.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/arch/x86/events/intel/cstate.c b/arch/x86/events/intel/cstate.c
index fa67fda6e45b4..c1e318bdaa397 100644
--- a/arch/x86/events/intel/cstate.c
+++ b/arch/x86/events/intel/cstate.c
@@ -599,6 +599,7 @@ static const struct x86_cpu_id intel_cstates_match[] __initconst = {
 	X86_MATCH_VFM(INTEL_ATOM_SILVERMONT,	&slm_cstates),
 	X86_MATCH_VFM(INTEL_ATOM_SILVERMONT_D,	&slm_cstates),
 	X86_MATCH_VFM(INTEL_ATOM_AIRMONT,	&slm_cstates),
+	X86_MATCH_VFM(INTEL_ATOM_AIRMONT_NP,	&slm_cstates),
 
 	X86_MATCH_VFM(INTEL_BROADWELL,		&snb_cstates),
 	X86_MATCH_VFM(INTEL_BROADWELL_D,	&snb_cstates),
-- 
2.51.0
[PATCH AUTOSEL 6.19-5.10] clocksource/drivers/timer-integrator-ap: Add missing Kconfig dependency on OF
Posted by Sasha Levin 3 hours ago
From: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>

[ Upstream commit 2246464821e2820572e6feefca2029f17629cc50 ]

This driver accesses the of_aliases global variable declared in
linux/of.h and defined in drivers/base/of.c. It requires OF support or
will cause a link failure. Add the missing Kconfig dependency.

Closes: https://lore.kernel.org/oe-kbuild-all/202601152233.og6LdeUo-lkp@intel.com/
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
Link: https://patch.msgid.link/20260116111723.10585-1-bartosz.golaszewski@oss.qualcomm.com
Signed-off-by: Sasha Levin <sashal@kernel.org>
---

LLM Generated explanations, may be completely bogus:

The key observation is that the `extern` declarations for `of_root`,
`of_chosen`, `of_aliases`, `of_stdout` at lines 141-144 are **outside
any `#ifdef CONFIG_OF`** guard. They are visible regardless of
CONFIG_OF. But the actual definition of `of_aliases` only exists in
`drivers/of/base.c` which is only compiled when `CONFIG_OF=y`.

This means:
1. When `CONFIG_OF=n` and `CONFIG_COMPILE_TEST=y`, the
   `INTEGRATOR_AP_TIMER` config can be enabled
2. The driver compiles fine (the extern declaration is visible)
3. But at link time, there is no definition for `of_aliases` → **linker
   error**

## Summary of Analysis

**Commit:** Adds `depends on OF` to `INTEGRATOR_AP_TIMER` Kconfig
option.

### 1. What Problem Does It Fix?

This is a **build fix** — it prevents a **link failure** when
`CONFIG_INTEGRATOR_AP_TIMER=y` with `CONFIG_COMPILE_TEST=y` but
`CONFIG_OF=n`. The driver `timer-integrator-ap.c` directly references
the global variable `of_aliases` (at lines 181 and 201), which is
defined in `drivers/of/base.c`. That file is only compiled when
`CONFIG_OF=y` (per `drivers/Makefile`: `obj-$(CONFIG_OF) += of/`).
Without `depends on OF`, the Kconfig allows enabling the driver in
configurations where OF is disabled, causing an unresolved symbol at
link time.

This was reported by Intel's kbuild test robot (automated build
testing), confirming it's a real, reproducible build failure.

### 2. Stable Kernel Rules Assessment

- **Obviously correct and tested**: Yes. It's a one-line Kconfig
  dependency addition. The driver uses `of_aliases` and multiple OF APIs
  (`of_io_request_and_map`, `of_clk_get`, `of_property_read_string`,
  `of_find_node_by_path`, `of_node_put`, `irq_of_parse_and_map`,
  `TIMER_OF_DECLARE`). It clearly requires `CONFIG_OF`.
- **Fixes a real bug**: Yes — a link failure preventing kernel
  compilation in certain configurations.
- **Fixes an important issue**: Build fixes are explicitly listed as
  backport-worthy in the stable rules. A link error prevents anyone from
  building the kernel with that configuration.
- **Small and contained**: Yes — single line addition to a Kconfig file.
  Zero risk of runtime regression.
- **No new features**: Correct — this only adds a constraint on when the
  driver can be selected.

### 3. Risk vs Benefit

- **Risk**: Essentially zero. Adding a Kconfig `depends on OF` only
  narrows the set of configurations where this driver can be enabled.
  Since the driver fundamentally requires OF to work (it uses OF APIs
  throughout), this is purely corrective. No runtime behavior changes.
- **Benefit**: Fixes a real build failure that prevents kernel
  compilation.

### 4. Scope

- **One line changed** in `drivers/clocksource/Kconfig`
- **One file affected**
- No code logic changes, no runtime impact

### 5. Affected Versions

The bug has existed since commit `568c0342e494` (June 2016, v4.8 cycle)
when `COMPILE_TEST` was added to `INTEGRATOR_AP_TIMER`. All current
stable trees (5.4.y through 6.12.y) are affected and the patch applies
cleanly since the surrounding Kconfig hasn't changed.

### 6. Dependencies

None. This is completely self-contained.

### 7. Classification

This is a **build fix** — one of the explicitly listed categories for
stable backporting. Build fixes are critical because they affect anyone
who needs to compile the kernel with a particular configuration. Even
though this specific configuration (COMPILE_TEST=y, OF=n) may not be
common for production kernels (since the Integrator/AP platform always
has OF), it matters for:
- Automated build testing infrastructure (like Intel's kbuild)
- Distributions running `make allmodconfig` / `make allyesconfig`
  testing
- Developers using COMPILE_TEST for coverage

The fix is small, surgical, zero-risk, and meets all stable kernel
criteria perfectly.

**YES**

 drivers/clocksource/Kconfig | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
index aa59e5b133510..fd91127065454 100644
--- a/drivers/clocksource/Kconfig
+++ b/drivers/clocksource/Kconfig
@@ -254,6 +254,7 @@ config KEYSTONE_TIMER
 
 config INTEGRATOR_AP_TIMER
 	bool "Integrator-AP timer driver" if COMPILE_TEST
+	depends on OF
 	select CLKSRC_MMIO
 	help
 	  Enables support for the Integrator-AP timer.
-- 
2.51.0

[PATCH AUTOSEL 6.19-6.18] perf/core: Fix slow perf_event_task_exit() with LBR callstacks
Posted by Sasha Levin 3 hours ago
From: Namhyung Kim <namhyung@kernel.org>

[ Upstream commit 4960626f956d63dce57f099016c2ecbe637a8229 ]

I got a report that a task is stuck in perf_event_exit_task() waiting
for global_ctx_data_rwsem.  On large systems with lots threads, it'd
have performance issues when it grabs the lock to iterate all threads
in the system to allocate the context data.

And it'd block task exit path which is problematic especially under
memory pressure.

  perf_event_open
    perf_event_alloc
      attach_perf_ctx_data
        attach_global_ctx_data
          percpu_down_write (global_ctx_data_rwsem)
            for_each_process_thread
              alloc_task_ctx_data
                                               do_exit
                                                 perf_event_exit_task
                                                   percpu_down_read (global_ctx_data_rwsem)

It should not hold the global_ctx_data_rwsem on the exit path.  Let's
skip allocation for exiting tasks and free the data carefully.

Reported-by: Rosalie Fang <rosaliefang@google.com>
Suggested-by: Peter Zijlstra <peterz@infradead.org>
Signed-off-by: Namhyung Kim <namhyung@kernel.org>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Link: https://patch.msgid.link/20260112165157.1919624-1-namhyung@kernel.org
Signed-off-by: Sasha Levin <sashal@kernel.org>
---

LLM Generated explanations, may be completely bogus:

---

## Comprehensive Analysis

### 1. COMMIT MESSAGE ANALYSIS

**Subject**: "perf/core: Fix slow perf_event_task_exit() with LBR
callstacks"

The commit message clearly describes a **performance regression / system
hang** scenario. Key indicators:
- **"I got a report that a task is stuck"** - real-world report from a
  Google engineer (Rosalie Fang)
- **"On large systems with lots threads, it'd have performance issues"**
  - reproducible on production systems
- **"it'd block task exit path which is problematic especially under
  memory pressure"** - can escalate to system unresponsiveness
- **Reported-by: Rosalie Fang <rosaliefang@google.com>** - actual user
  report
- **Suggested-by: Peter Zijlstra** and **Signed-off-by: Peter Zijlstra**
  - the perf subsystem maintainer suggested and approved the fix

The commit message illustrates the exact deadlock scenario:
1. `perf_event_open` -> `attach_global_ctx_data` takes
   `global_ctx_data_rwsem` as a **writer** and iterates all threads to
   allocate context data
2. Simultaneously, a task calling `do_exit` -> `perf_event_exit_task`
   tries to take `global_ctx_data_rwsem` as a **reader**
3. On large systems with many threads, the write lock is held for a long
   time during the `for_each_process_thread` loop, blocking ALL task
   exits

This is effectively a **priority inversion / livelock** scenario where
task exit (a critical path) is blocked by a potentially very long
operation (iterating and allocating for all threads in the system).

### 2. CODE CHANGE ANALYSIS

The patch makes three coordinated changes:

#### Change 1: Skip exiting tasks in `attach_global_ctx_data()` (lines
5483-5484 in the diff)

```c
for_each_process_thread(g, p) {
    if (p->flags & PF_EXITING)
        continue;
```

This adds a check to skip tasks that are already exiting during the
global iteration. No point allocating context data for a task that's
about to die.

#### Change 2: Detect and undo allocation for exiting tasks in
`attach_task_ctx_data()` (lines 5427-5434 in the diff)

After successfully attaching via `try_cmpxchg`, the code now checks:
```c
if (task->flags & PF_EXITING) {
    /* detach_task_ctx_data() may free it already */
    if (try_cmpxchg(&task->perf_ctx_data, &cd, NULL))
        perf_free_ctx_data_rcu(cd);
}
```

This handles the race where `attach_global_ctx_data()` allocates for a
task that starts exiting between the `PF_EXITING` check and the
`try_cmpxchg`. If we detect the task is exiting, we undo our allocation.

The key insight: The `try_cmpxchg()` in `attach_task_ctx_data()` pairs
with the `try_cmpxchg()` in `detach_task_ctx_data()` to provide total
ordering. If `attach_task_ctx_data()` succeeds the cmpxchg first, it
will see `PF_EXITING` and undo the allocation. If
`detach_task_ctx_data()` (called from `perf_event_exit_task`) succeeds
first, the undo cmpxchg will fail (because `cd` is no longer at
`task->perf_ctx_data`), which is fine.

#### Change 3: Remove lock from `perf_event_exit_task()` (lines
14558-14603 in the diff)

The critical change:
```c
// BEFORE:
guard(percpu_read)(&global_ctx_data_rwsem);
detach_task_ctx_data(task);

// AFTER (no lock):
detach_task_ctx_data(task);
```

The comment explains the correctness:
> Done without holding global_ctx_data_rwsem; typically
attach_global_ctx_data() will skip over this task, but otherwise
attach_task_ctx_data() will observe PF_EXITING.

**Correctness argument**:
- `PF_EXITING` is set in `exit_signals()` (line 913 of exit.c)
  **before** `perf_event_exit_task()` is called (line 951)
- The `try_cmpxchg()` operations provide atomic visibility of
  `task->perf_ctx_data` changes
- If `attach_global_ctx_data()` races with exit: either it sees
  `PF_EXITING` and skips, or if it allocates, `attach_task_ctx_data()`
  sees `PF_EXITING` after the cmpxchg and undoes the allocation
- `detach_task_ctx_data()` uses `try_cmpxchg` to atomically clear the
  pointer, so concurrent operations are safe

### 3. BUG CLASSIFICATION

This is a **performance regression / system hang** fix. The
`global_ctx_data_rwsem` write lock blocks ALL readers (task exits) while
iterating ALL threads. On systems with thousands of threads:
- Opening a perf event with LBR callstacks causes the write lock to be
  held for a long time
- Every task trying to exit during this period blocks on the read lock
- Under memory pressure, blocked task exits compound the problem (tasks
  holding memory can't release it)
- This can effectively hang the system

### 4. SCOPE AND RISK ASSESSMENT

**Lines changed**: ~25 lines added/changed in a single file
(`kernel/events/core.c`)
**Files touched**: 1
**Complexity**: Moderate - the synchronization relies on cmpxchg +
PF_EXITING flag ordering
**Risk**: LOW-MEDIUM
  - The fix is self-contained within the perf subsystem
  - The cmpxchg-based synchronization replaces a lock-based approach,
    which is more lockless but well-reasoned
  - Peter Zijlstra (the maintainer) both suggested and signed off on the
    approach
  - The worst case if the fix has a subtle race: a small memory leak of
    one `perf_ctx_data` allocation (not a crash)

### 5. USER IMPACT

**Who is affected**: Anyone using perf with LBR callstacks (Intel) in
system-wide mode on systems with many threads. This is common on:
- Large servers doing production profiling
- CI/CD systems running perf monitoring
- Google's production fleet (where the bug was reported)

**Severity**: HIGH - can block the task exit path, which is critical.
Under memory pressure this can effectively hang the system.

### 6. STABILITY & TRUST INDICATORS

- **Reported-by**: Rosalie Fang from Google - real production issue
- **Suggested-by**: Peter Zijlstra (perf maintainer) - expert-designed
  solution
- **Signed-off-by**: Both Namhyung Kim (author) and Peter Zijlstra
  (maintainer)
- **Link**: Has a patch.msgid.link reference showing proper mailing list
  review

### 7. DEPENDENCY CHECK

The affected code was introduced in:
- `cb43691293390` "perf: Save PMU specific data in task_struct"
  (v6.15-rc1)
- `506e64e710ff9` "perf: attach/detach PMU specific data" (v6.15-rc1)

**Applicable stable trees**: 6.15.y, 6.16.y, 6.17.y, 6.18.y
**NOT applicable**: 6.14.y and earlier (code doesn't exist)

The patch is self-contained - it doesn't depend on any other commits. It
modifies only the code introduced by the above commits and the logic is
self-sufficient.

### 8. MINOR CLEANUP CONCERN

The patch also removes a `(struct perf_ctx_data **)` cast from one
`try_cmpxchg` call in `attach_task_ctx_data()`. This is a minor
whitespace/type-correctness issue and doesn't affect functionality -
`try_cmpxchg` on an `__rcu` pointer works the same way.

### CONCLUSION

This commit fixes a real, reported, production-impacting performance bug
that can cause task exit to hang on systems with many threads when LBR
callstack profiling is active. The fix is:

1. **Obviously correct**: The synchronization relies on the well-
   established pattern of `PF_EXITING` flag + atomic cmpxchg operations,
   with clear ordering guarantees
2. **Fixes a real bug**: Reported by a Google engineer on production
   systems
3. **Important**: Can cause system hangs, especially under memory
   pressure
4. **Small and contained**: ~25 lines in a single file, touching only
   the perf subsystem
5. **No new features**: Just removes unnecessary lock contention
6. **Expert-reviewed**: Suggested by Peter Zijlstra, the perf subsystem
   maintainer

The fix should be backported to all stable trees containing the affected
code (6.15.y through 6.18.y).

**YES**

 kernel/events/core.c | 20 ++++++++++++++++++--
 1 file changed, 18 insertions(+), 2 deletions(-)

diff --git a/kernel/events/core.c b/kernel/events/core.c
index 8cca800946248..69c56cad88a89 100644
--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -5280,9 +5280,20 @@ attach_task_ctx_data(struct task_struct *task, struct kmem_cache *ctx_cache,
 		return -ENOMEM;
 
 	for (;;) {
-		if (try_cmpxchg((struct perf_ctx_data **)&task->perf_ctx_data, &old, cd)) {
+		if (try_cmpxchg(&task->perf_ctx_data, &old, cd)) {
 			if (old)
 				perf_free_ctx_data_rcu(old);
+			/*
+			 * Above try_cmpxchg() pairs with try_cmpxchg() from
+			 * detach_task_ctx_data() such that
+			 * if we race with perf_event_exit_task(), we must
+			 * observe PF_EXITING.
+			 */
+			if (task->flags & PF_EXITING) {
+				/* detach_task_ctx_data() may free it already */
+				if (try_cmpxchg(&task->perf_ctx_data, &cd, NULL))
+					perf_free_ctx_data_rcu(cd);
+			}
 			return 0;
 		}
 
@@ -5328,6 +5339,8 @@ attach_global_ctx_data(struct kmem_cache *ctx_cache)
 	/* Allocate everything */
 	scoped_guard (rcu) {
 		for_each_process_thread(g, p) {
+			if (p->flags & PF_EXITING)
+				continue;
 			cd = rcu_dereference(p->perf_ctx_data);
 			if (cd && !cd->global) {
 				cd->global = 1;
@@ -14294,8 +14307,11 @@ void perf_event_exit_task(struct task_struct *task)
 
 	/*
 	 * Detach the perf_ctx_data for the system-wide event.
+	 *
+	 * Done without holding global_ctx_data_rwsem; typically
+	 * attach_global_ctx_data() will skip over this task, but otherwise
+	 * attach_task_ctx_data() will observe PF_EXITING.
 	 */
-	guard(percpu_read)(&global_ctx_data_rwsem);
 	detach_task_ctx_data(task);
 }
 
-- 
2.51.0