* [PATCH AUTOSEL 6.18] pinctrl: renesas: rzg2l: Add SR register cache for PM suspend/resume
[not found] <20260831133314.4125787-1-sashal@kernel.org>
@ 2026-08-31 13:21 ` Sasha Levin
2026-08-31 13:22 ` [PATCH AUTOSEL 6.18] pinctrl: qcom: Register functions before enabling pinctrl Sasha Levin
` (10 subsequent siblings)
11 siblings, 0 replies; 12+ messages in thread
From: Sasha Levin @ 2026-08-31 13:21 UTC (permalink / raw)
To: patches, stable
Cc: Lad Prabhakar, Geert Uytterhoeven, Sasha Levin, linusw,
linux-renesas-soc, linux-gpio, linux-kernel
From: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
[ Upstream commit 29df31ae3e8a0152dd8e8c2376816aad2f233473 ]
Include the SR (Slew Rate) register in the PM suspend/resume register
cache.
Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be>
Link: https://patch.msgid.link/20260413182456.811543-3-prabhakar.mahadev-lad.rj@bp.renesas.com
Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
LLM Generated explanations, may be completely bogus:
# Stable Backport Analysis: pinctrl: renesas: rzg2l: Add SR register
cache for PM suspend/resume
**Local tree:** `v6.18.43` / `6.18.43`
---
## PHASE 1: COMMIT MESSAGE FORENSICS
### Step 1.1: Parse the subject line
**Record:** `[pinctrl: renesas: rzg2l]` `[add]` — Include the SR (Slew
Rate) register in the PM suspend/resume register cache.
### Step 1.2: Parse all commit message tags
**Record:**
- **Signed-off-by:** Lad Prabhakar `<prabhakar.mahadev-
lad.rj@bp.renesas.com>` (author)
- **Reviewed-by:** Geert Uytterhoeven `<geert+renesas@glider.be>`
(Renesas subsystem maintainer)
- **Link:**
https://patch.msgid.link/20260413182456.811543-3-prabhakar.mahadev-
lad.rj@bp.renesas.com
- **Signed-off-by:** Geert Uytterhoeven (maintainer tree SOB)
- No Fixes:, Reported-by:, Tested-by:, Cc: stable, or syzbot tags on
this individual commit
- Notable: Part of v2 2/5 series; patch 1/5 (SMT fix) in the same series
has extensive Tested-by lines from CIP and embedded testers
### Step 1.3: Analyze commit body text
**Record:**
- **Bug described:** SR registers were omitted from the PM
suspend/resume register cache.
- **Symptom/failure mode:** After suspend-to-RAM and resume, slew-rate
hardware settings are not saved/restored. Pins keep whatever SR values
the hardware has after resume, not the values configured before
suspend.
- **Version info:** None in commit message.
- **Root cause:** Incomplete PM register caching — SR was never added
when suspend/resume support was built out, unlike IOLH, IEN, PUPD, and
SMT.
### Step 1.4: Detect hidden bug fixes
**Record:** Yes — despite the "Add" wording, this completes an existing
suspend/resume implementation. It is the same class of bug as
`8d1c6b603327b` ("Fix SMT register cache handling"), which is already in
this tree. The cover letter explicitly frames the series as fixing PM
register caching issues.
---
## PHASE 2: DIFF ANALYSIS
### Step 2.1: Inventory the changes
**Record:**
- **File:** `drivers/pinctrl/renesas/pinctrl-rzg2l.c` — ~35 insertions,
3 deletions
- **Functions modified:** `rzg2l_pinctrl_reg_cache_alloc()`,
`rzg2l_pinctrl_pm_setup_regs()`,
`rzg2l_pinctrl_pm_setup_dedicated_regs()`
- **Struct modified:** `rzg2l_pinctrl_reg_cache` — adds `u32 *sr[2]`
- **Scope:** Single-file, surgical fix mirroring existing SMT/IEN/IOLH
patterns
### Step 2.2: Code flow change per hunk
**Record:**
1. **Struct/cache alloc:** Adds `sr[2]` banked arrays for both main and
dedicated pin caches, matching SMT layout.
2. **`rzg2l_pinctrl_pm_setup_regs()`:** On suspend, reads SR register(s)
into cache; on resume, writes them back. Uses `has_sr = !!(caps &
PIN_CFG_SR)` and handles split 32-bit banks when `pincnt >= 4`.
3. **`rzg2l_pinctrl_pm_setup_dedicated_regs()`:** Same SR save/restore
for dedicated pins.
**Before → After:** SR registers were never touched during PM
transitions → SR is saved on suspend and restored on resume, consistent
with SMT/IEN/IOLH/PUPD.
### Step 2.3: Bug mechanism
**Record:**
- **Category:** Logic/correctness — incomplete hardware state
save/restore on suspend/resume path
- **Mechanism:** `rzg2l_pinctrl_suspend_noirq()` calls
`rzg2l_pinctrl_pm_setup_regs(pctrl, true)` and resume calls it with
`false`. SR-capable pins (many SD, Ethernet, QSPI, UART pins via
`PIN_CFG_SR`) lose their slew-rate configuration across S2RAM cycles.
### Step 2.4: Fix quality assessment
**Record:**
- **Quality:** High — follows the exact established pattern used for SMT
(including dual-bank handling for ports with ≥4 pins).
- **Regression risk:** Very low — only adds cache entries and
conditional read/write on existing PM paths.
- **Red flags:** None. No API changes, no locking changes.
---
## PHASE 3: GIT HISTORY INVESTIGATION
### Step 3.1: Blame the changed lines
**Record:** Current `has_smt`/SMT cache block at lines 3056–3063 was
introduced by `8d1c6b603327b` (Apr 2026). SR handling is absent at the
same location — the omission predates the SMT fix and was never
addressed.
### Step 3.2: Follow Fixes: tag
**Record:** Not applicable — no Fixes: tag on this commit.
### Step 3.3: File history for related changes
**Record:** Recent related commits in this tree:
- `8d1c6b603327b` — Fix SMT register cache handling (patch 1/5,
**already in 6.18.43**)
- `c4cfa8ee77374` — Fix incorrect PUPD register offset for high pins
- `509d342d02fff` — Fix save/restore of {IOLH,IEN,PUPD,SMT} for variable
pincfg ports
- `dd6e519ba91e4` — Fix ISEL restore on resume
This commit is patch 2/5 of the "Fix PM register caching" v2 series.
Patches 3–5 (IOLH_RZV2H, NOD, dedicated PUPD) are separate and not
required for this SR fix.
### Step 3.4: Author's other commits
**Record:** Lad Prabhakar is an active Renesas contributor (RTC, PCI,
clk, mmc, pinctrl). The SMT fix from the same series (`8d1c6b603327b`)
is already in this tree, reviewed by Geert Uytterhoeven.
### Step 3.5: Prerequisites
**Record:**
- **Prerequisite present:** Patch 1/5 (SMT per-bank array `smt[2]`) is
already in 6.18.43.
- **Standalone:** This patch only adds SR caching; it does not depend on
patches 3–5.
- **Can apply cleanly:** Current tree matches the patch base (has
`smt[2]`, lacks `sr[2]`).
---
## PHASE 4: MAILING LIST AND EXTERNAL RESEARCH
### Step 4.1: Original patch discussion
**Record:**
- **Series cover:** `v2_20260413_prabhakar_csengg_pinctrl_renesas_rzg2l_
fix_pm_register_caching.cover` — describes fixing PM register caching
including SR, SMT, IOLH, NOD, PUPD.
- **Lore URL:**
https://patch.msgid.link/20260413182456.811543-3-prabhakar.mahadev-
lad.rj@bp.renesas.com (direct fetch blocked by Anubis bot protection)
- **Series revisions:** v2; patch 2 updated per review to add dedicated
SR cache (v1→v2 note in mbox)
- **Stable nominations in thread:** Not found in available local mbox
content for this specific patch
- **NAKs/concerns:** None found in local mbox
### Step 4.2: Reviewers
**Record:** Geert Uytterhoeven (Renesas pinctrl maintainer) Reviewed-by
and Signed-off-by. Pavel Machek Reviewed-by on patch 2. Patch 1 has
extensive Tested-by from CIP and embedded community.
### Step 4.3: Bug report
**Record:** No external bug report or syzbot link. Bug identified by
code review during PM caching audit (cover letter: "addresses several
issues with the PM register caching implementation").
### Step 4.4: Related patches in series
**Record:** 5-patch series. Only patch 1 is in 6.18.43 so far. Patches
3–5 address separate register types (IOLH_RZV2H, NOD, dedicated PUPD)
and are independent of this SR fix.
### Step 4.5: Stable mailing list history
**Record:** Not searched (lore blocked). No stable-specific discussion
found in local mbox.
---
## PHASE 5: CODE SEMANTIC ANALYSIS
### Step 5.1: Key functions
**Record:** `rzg2l_pinctrl_reg_cache_alloc()`,
`rzg2l_pinctrl_pm_setup_regs()`,
`rzg2l_pinctrl_pm_setup_dedicated_regs()`, called from
`rzg2l_pinctrl_suspend_noirq()` / `rzg2l_pinctrl_resume_noirq()`.
### Step 5.2: Callers
**Record:**
- `rzg2l_pinctrl_suspend_noirq()` — `NOIRQ_SYSTEM_SLEEP_PM_OPS` at line
3485
- `rzg2l_pinctrl_resume_noirq()` — same PM ops
- Triggered on every system suspend/resume on boards using this pinctrl
driver with PM enabled
### Step 5.3: Callees
**Record:** `RZG2L_PCTRL_REG_ACCESS32()` macro — `readl`/`writel` on
`SR(off)` register at offset `0x1400 + (off) * 8`. SR is also used in
normal pinconf get/set (`PIN_CONFIG_SLEW_RATE` at lines 1314–1318,
1472–1476).
### Step 5.4: Call chain / reachability
**Record:** Boot → platform probe → PM suspend (S2RAM) →
`rzg2l_pinctrl_suspend_noirq()` → `rzg2l_pinctrl_pm_setup_regs(true)` →
SR **not** cached (bug). Resume path similarly fails to restore SR.
Reachable on any Renesas RZ/G2L/V2H board using suspend.
### Step 5.5: Similar patterns
**Record:** SMT, IEN, IOLH, PUPD all use identical `has_*` + dual-bank
`RZG2L_PCTRL_REG_ACCESS32` pattern. SR was the missing sibling.
`PIN_CFG_SR` appears on 100+ pin definitions across RZ/G2L, RZ/V2H,
RZ/G3E SoC data in the same file.
---
## PHASE 6: CROSS-REFERENCING AGAINST LOCAL TREE (6.18.43)
### Step 6.1: Does the buggy code exist?
**Record:** **Yes.** Suspend/resume is present
(`rzg2l_pinctrl_suspend_noirq` at line 3179). `PIN_CFG_SR` and `SR(off)`
exist. `rzg2l_pinctrl_reg_cache` has `smt[2]` but **no** `sr[2]`.
`rzg2l_pinctrl_pm_setup_regs()` handles SMT but not SR. Bug is live in
6.18.43.
### Step 6.2: Backport complications
**Record:** **Clean apply expected.** Tree already has patch 1/5 (SMT
per-bank fix). No conflicting changes. Single file, established pattern.
### Step 6.3: Related fixes already present
**Record:** SMT cache fix (`8d1c6b603327b`) is in tree. SR cache fix is
**not** present. No duplicate fix found.
---
## PHASE 7: SUBSYSTEM AND MAINTAINER CONTEXT
### Step 7.1: Subsystem and criticality
**Record:** `drivers/pinctrl/renesas/` — **PERIPHERAL** (platform-
specific, Renesas RZ SoCs). Critical for embedded/industrial users (CIP,
RZ/V2H EVKs, RZ/G2L boards) but not universal.
### Step 7.2: Subsystem activity
**Record:** Actively maintained — multiple PM suspend/resume fixes
landed in 2026 for this driver in this tree.
---
## PHASE 8: IMPACT AND RISK ASSESSMENT
### Step 8.1: Who is affected
**Record:** Users of `CONFIG_PINCTRL_RZG2L` on Renesas RZ/G2L,
RZ/V2H(P), RZ/V2N, RZ/G3E SoCs who use system suspend (S2RAM). Platform-
specific, not universal.
### Step 8.2: Trigger conditions
**Record:** System suspend-to-RAM on affected hardware. Common on
embedded/industrial systems. Requires PM-enabled kernel and SR-
configured pins (very common — SD, Ethernet, QSPI, UART pins all use
`PIN_CFG_SR`). Unprivileged users can trigger via standard suspend
interfaces.
### Step 8.3: Failure mode severity
**Record:** Wrong slew-rate settings after resume → signal integrity
degradation on high-speed interfaces (SDIO, Ethernet, QSPI). Can cause
peripheral malfunction, data errors, or intermittent failures post-
resume. Not a kernel oops/panic, but real hardware misbehavior.
**Severity: MEDIUM-HIGH** for affected platforms.
### Step 8.4: Risk-benefit ratio
**Record:**
- **Benefit:** Restores correct pin electrical configuration after
suspend — prevents post-resume peripheral failures on widely deployed
embedded SoCs.
- **Risk:** Very low — ~35 lines, mirrors proven SMT pattern, reviewed
by maintainer.
- **Ratio:** Favorable for affected users; negligible risk to unaffected
configurations.
---
## PHASE 9: FINAL SYNTHESIS
### Step 9.1: Evidence compilation
**FOR backporting:**
- Real suspend/resume bug — SR registers not saved/restored
- Same bug class as SMT fix already backported to 6.18.43
- Widely used register (`PIN_CFG_SR` on SD/Ethernet/QSPI/UART pins)
- Small, surgical, maintainer-reviewed fix
- Prerequisites (SMT per-bank cache) already in tree
- CIP/embedded community tested the series (patch 1)
**AGAINST backporting:**
- Platform-specific (Renesas RZ only)
- No crash/panic — functional/hardware correctness issue
- Commit message is terse; doesn't spell out user-visible symptoms
- Part of a 5-patch series (though this patch is self-contained)
**Unresolved:** Full lore thread review blocked by Anubis. No explicit
stable nomination found in local mbox.
### Step 9.2: Stable rules checklist
1. Obviously correct and tested? **PASS** — mirrors SMT/IEN pattern;
series tested by CIP community on patch 1; maintainer reviewed.
2. Fixes a real bug affecting users? **PASS** — incomplete PM state
save/restore on suspend/resume.
3. Important issue? **PASS** — post-resume hardware misconfiguration on
high-speed peripherals (MEDIUM-HIGH severity for affected platforms).
4. Small and contained? **PASS** — ~35 lines, one file, three functions.
5. No new features or APIs? **PASS** — completes existing PM caching, no
userspace-visible changes.
6. Can apply to local tree? **PASS** — buggy code present, prerequisite
patch 1/5 already applied, clean apply expected.
### Step 9.3: Exception categories
**Record:** Not a device ID, quirk, DT, build, or docs fix. Standard bug
fix completing PM suspend/resume support.
### Step 9.4: Decision rationale
This commit fixes an omission in the Renesas RZ/G2L pinctrl driver's
suspend/resume register caching. The driver already saves and restores
SMT, IEN, IOLH, and PUPD registers, but SR (Slew Rate) was never
included. After S2RAM, pins on SDIO, Ethernet, QSPI, and other high-
speed interfaces can have incorrect electrical settings, causing
peripheral failures after resume.
The fix is minimal, follows an established in-driver pattern, was
reviewed by the subsystem maintainer, and its prerequisite (SMT per-bank
cache, patch 1/5) is already in 6.18.43. The same author and series
already had patch 1 backported to this tree, establishing that this
class of PM caching fix is appropriate for stable.
---
## Verification
- [Phase 1] `git describe HEAD` → `v6.18.43`; parsed subject, tags, body
from user-provided commit
- [Phase 1] Read cover letter mbox: series context confirms PM caching
bug class
- [Phase 2] Read current `pinctrl-rzg2l.c`: confirmed no `sr` in cache
struct (lines 330–343), no `has_sr` in PM functions
- [Phase 2] Confirmed `RZG2L_PCTRL_REG_ACCESS32` macro and `SR(off)` at
line 140
- [Phase 3] `git log --oneline -15 -- drivers/pinctrl/renesas/pinctrl-
rzg2l.c` — related PM fixes listed
- [Phase 3] `git show 8d1c6b603327b` — SMT fix (patch 1/5) confirmed in
tree
- [Phase 3] `git blame -L 3056,3063` — SMT block from 8d1c6b603327b; no
SR block adjacent
- [Phase 3] `git log --author="Lad Prabhakar" -10` — active Renesas
contributor
- [Phase 4] Read `v2_20260413_...pm_register_caching.mbx` — full series
context, v2 revisions
- [Phase 4] `b4 dig -c 8d1c6b603327b` → lore URL for series
- [Phase 4] WebFetch lore URL for patch 3 — **blocked** by Anubis bot
protection
- [Phase 5] Grep `PIN_CFG_SR` — 100+ pin definitions use SR capability
- [Phase 5] Grep `rzg2l_pinctrl_suspend` — PM ops at lines 3179, 3485
- [Phase 5] Read `rzg2l_pinctrl_reg_cache_alloc()` lines 2720–2766 — no
SR allocation
- [Phase 6] Confirmed suspend/resume code exists and SR is missing from
cache path
- [Phase 6] Confirmed patch 1/5 prerequisite present, patch 2/5 (this
commit) absent
- [Phase 8] Assessed failure mode: post-resume slew-rate
misconfiguration, MEDIUM-HIGH for RZ platforms
**YES**
drivers/pinctrl/renesas/pinctrl-rzg2l.c | 38 +++++++++++++++++++++++--
1 file changed, 35 insertions(+), 3 deletions(-)
diff --git a/drivers/pinctrl/renesas/pinctrl-rzg2l.c b/drivers/pinctrl/renesas/pinctrl-rzg2l.c
index ab8d64a14dd0a..b4d7e80dd6468 100644
--- a/drivers/pinctrl/renesas/pinctrl-rzg2l.c
+++ b/drivers/pinctrl/renesas/pinctrl-rzg2l.c
@@ -322,6 +322,7 @@ struct rzg2l_pinctrl_pin_settings {
* @pupd: PUPD registers cache
* @ien: IEN registers cache
* @smt: SMT registers cache
+ * @sr: SR registers cache
* @sd_ch: SD_CH registers cache
* @eth_poc: ET_POC registers cache
* @oen: Output Enable register cache
@@ -336,6 +337,7 @@ struct rzg2l_pinctrl_reg_cache {
u32 *ien[2];
u32 *pupd[2];
u32 *smt[2];
+ u32 *sr[2];
u8 sd_ch[2];
u8 eth_poc[2];
u8 oen;
@@ -2746,6 +2748,11 @@ static int rzg2l_pinctrl_reg_cache_alloc(struct rzg2l_pinctrl *pctrl)
if (!cache->smt[i])
return -ENOMEM;
+ cache->sr[i] = devm_kcalloc(pctrl->dev, nports, sizeof(*cache->sr[i]),
+ GFP_KERNEL);
+ if (!cache->sr[i])
+ return -ENOMEM;
+
/* Allocate dedicated cache. */
dedicated_cache->iolh[i] = devm_kcalloc(pctrl->dev, n_dedicated_pins,
sizeof(*dedicated_cache->iolh[i]),
@@ -2758,6 +2765,12 @@ static int rzg2l_pinctrl_reg_cache_alloc(struct rzg2l_pinctrl *pctrl)
GFP_KERNEL);
if (!dedicated_cache->ien[i])
return -ENOMEM;
+
+ dedicated_cache->sr[i] = devm_kcalloc(pctrl->dev, n_dedicated_pins,
+ sizeof(*dedicated_cache->sr[i]),
+ GFP_KERNEL);
+ if (!dedicated_cache->sr[i])
+ return -ENOMEM;
}
pctrl->cache = cache;
@@ -2989,7 +3002,7 @@ static void rzg2l_pinctrl_pm_setup_regs(struct rzg2l_pinctrl *pctrl, bool suspen
struct rzg2l_pinctrl_reg_cache *cache = pctrl->cache;
for (u32 port = 0; port < nports; port++) {
- bool has_iolh, has_ien, has_pupd, has_smt;
+ bool has_iolh, has_ien, has_pupd, has_smt, has_sr;
u32 off, caps;
u8 pincnt;
u64 cfg;
@@ -3010,6 +3023,7 @@ static void rzg2l_pinctrl_pm_setup_regs(struct rzg2l_pinctrl *pctrl, bool suspen
has_ien = !!(caps & PIN_CFG_IEN);
has_pupd = !!(caps & PIN_CFG_PUPD);
has_smt = !!(caps & PIN_CFG_SMT);
+ has_sr = !!(caps & PIN_CFG_SR);
if (suspend)
RZG2L_PCTRL_REG_ACCESS32(suspend, pctrl->base + PFC(off), cache->pfc[port]);
@@ -3061,6 +3075,15 @@ static void rzg2l_pinctrl_pm_setup_regs(struct rzg2l_pinctrl *pctrl, bool suspen
cache->smt[1][port]);
}
}
+
+ if (has_sr) {
+ RZG2L_PCTRL_REG_ACCESS32(suspend, pctrl->base + SR(off),
+ cache->sr[0][port]);
+ if (pincnt >= 4) {
+ RZG2L_PCTRL_REG_ACCESS32(suspend, pctrl->base + SR(off) + 4,
+ cache->sr[1][port]);
+ }
+ }
}
}
@@ -3075,7 +3098,7 @@ static void rzg2l_pinctrl_pm_setup_dedicated_regs(struct rzg2l_pinctrl *pctrl, b
* port offset are close together.
*/
for (i = 0, caps = 0; i < pctrl->data->n_dedicated_pins; i++) {
- bool has_iolh, has_ien;
+ bool has_iolh, has_ien, has_sr;
u32 off, next_off = 0;
u64 cfg, next_cfg;
u8 pincnt;
@@ -3097,6 +3120,7 @@ static void rzg2l_pinctrl_pm_setup_dedicated_regs(struct rzg2l_pinctrl *pctrl, b
has_iolh = !!(caps & (PIN_CFG_IOLH_A | PIN_CFG_IOLH_B |
PIN_CFG_IOLH_C | PIN_CFG_IOLH_RZV2H));
has_ien = !!(caps & PIN_CFG_IEN);
+ has_sr = !!(caps & PIN_CFG_SR);
pincnt = hweight8(FIELD_GET(RZG2L_SINGLE_PIN_BITS_MASK, cfg));
if (has_iolh) {
@@ -3107,7 +3131,10 @@ static void rzg2l_pinctrl_pm_setup_dedicated_regs(struct rzg2l_pinctrl *pctrl, b
RZG2L_PCTRL_REG_ACCESS32(suspend, pctrl->base + IEN(off),
cache->ien[0][i]);
}
-
+ if (has_sr) {
+ RZG2L_PCTRL_REG_ACCESS32(suspend, pctrl->base + SR(off),
+ cache->sr[0][i]);
+ }
if (pincnt >= 4) {
if (has_iolh) {
RZG2L_PCTRL_REG_ACCESS32(suspend,
@@ -3119,6 +3146,11 @@ static void rzg2l_pinctrl_pm_setup_dedicated_regs(struct rzg2l_pinctrl *pctrl, b
pctrl->base + IEN(off) + 4,
cache->ien[1][i]);
}
+ if (has_sr) {
+ RZG2L_PCTRL_REG_ACCESS32(suspend,
+ pctrl->base + SR(off) + 4,
+ cache->sr[1][i]);
+ }
}
caps = 0;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH AUTOSEL 6.18] pinctrl: qcom: Register functions before enabling pinctrl
[not found] <20260831133314.4125787-1-sashal@kernel.org>
2026-08-31 13:21 ` [PATCH AUTOSEL 6.18] pinctrl: renesas: rzg2l: Add SR register cache for PM suspend/resume Sasha Levin
@ 2026-08-31 13:22 ` Sasha Levin
2026-08-31 13:23 ` [PATCH AUTOSEL 6.18] pinctrl: mediatek: common-v1: bypass pinctrl GPIO layer in set GPIO direction Sasha Levin
` (9 subsequent siblings)
11 siblings, 0 replies; 12+ messages in thread
From: Sasha Levin @ 2026-08-31 13:22 UTC (permalink / raw)
To: patches, stable
Cc: Alexandre MINETTE, Konrad Dybcio, Linus Walleij, Sasha Levin,
brgl, andersson, linux-arm-msm, linux-gpio, linux-kernel
From: Alexandre MINETTE <contact@alex-min.fr>
[ Upstream commit 981aefd53b3cdafae0e45332a1023b80d67f52be ]
pinctrl consumers can request states while the pinctrl core enables the
controller. On Qualcomm pinctrl drivers this can happen before the SoC
function list has been registered, which leaves the function table
incomplete during state lookup.
On APQ8064 this can fail while claiming pinctrl hogs:
apq8064-pinctrl 800000.pinctrl: invalid function ps_hold in map table
apq8064-pinctrl 800000.pinctrl: error claiming hogs: -22
apq8064-pinctrl 800000.pinctrl: could not claim hogs: -22
Register Qualcomm pinctrl with devm_pinctrl_register_and_init(), add the
SoC pin functions, and only then enable the pinctrl device.
Signed-off-by: Alexandre MINETTE <contact@alex-min.fr>
Reviewed-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
Signed-off-by: Linus Walleij <linusw@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
LLM Generated explanations, may be completely bogus:
The background checks finished and line up with the earlier analysis:
- **Fix commit not in tree** — no local match for "Register functions
before enabling pinctrl" or Alexandre MINETTE patches under
`drivers/pinctrl/qcom/`.
- **Regression confirmed in 6.18.44** — `6f6835beab99c` ("use generic
pin function helpers") is an ancestor of the `v6.18.44` tag, so the
buggy probe order is present in this stable tree.
- **Precedent exists** — `2aca5c591ef4e` ("pinctrl: samsung: defer
pinctrl_enable") uses the same deferred-enable pattern.
- **`b4 dig` failed** — wrong invocation syntax; lore lookup was done
via web search instead.
**Verdict for Linux 6.18.44: YES** — this is a small regression fix for
APQ8064 (and any qcom pinctrl with self-hogs) since v6.18.0.
drivers/pinctrl/qcom/pinctrl-msm.c | 15 ++++++++++-----
1 file changed, 10 insertions(+), 5 deletions(-)
diff --git a/drivers/pinctrl/qcom/pinctrl-msm.c b/drivers/pinctrl/qcom/pinctrl-msm.c
index 424b14bc29e96..eabd6563629a7 100644
--- a/drivers/pinctrl/qcom/pinctrl-msm.c
+++ b/drivers/pinctrl/qcom/pinctrl-msm.c
@@ -1577,11 +1577,11 @@ int msm_pinctrl_probe(struct platform_device *pdev,
pctrl->desc.pins = pctrl->soc->pins;
pctrl->desc.npins = pctrl->soc->npins;
- pctrl->pctrl = devm_pinctrl_register(&pdev->dev, &pctrl->desc, pctrl);
- if (IS_ERR(pctrl->pctrl)) {
- dev_err(&pdev->dev, "Couldn't register pinctrl driver\n");
- return PTR_ERR(pctrl->pctrl);
- }
+ ret = devm_pinctrl_register_and_init(&pdev->dev, &pctrl->desc,
+ pctrl, &pctrl->pctrl);
+ if (ret)
+ return dev_err_probe(&pdev->dev, ret,
+ "Couldn't register pinctrl driver\n");
for (i = 0; i < soc_data->nfunctions; i++) {
func = &soc_data->functions[i];
@@ -1591,6 +1591,11 @@ int msm_pinctrl_probe(struct platform_device *pdev,
return ret;
}
+ ret = pinctrl_enable(pctrl->pctrl);
+ if (ret)
+ return dev_err_probe(&pdev->dev, ret,
+ "Couldn't enable pinctrl driver\n");
+
ret = msm_gpio_init(pctrl);
if (ret)
return ret;
--
2.53.0
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH AUTOSEL 6.18] pinctrl: mediatek: common-v1: bypass pinctrl GPIO layer in set GPIO direction
[not found] <20260831133314.4125787-1-sashal@kernel.org>
2026-08-31 13:21 ` [PATCH AUTOSEL 6.18] pinctrl: renesas: rzg2l: Add SR register cache for PM suspend/resume Sasha Levin
2026-08-31 13:22 ` [PATCH AUTOSEL 6.18] pinctrl: qcom: Register functions before enabling pinctrl Sasha Levin
@ 2026-08-31 13:23 ` Sasha Levin
2026-08-31 13:24 ` [PATCH AUTOSEL 6.18] pinctrl: meson: amlogic-a4: use nolock get range Sasha Levin
` (8 subsequent siblings)
11 siblings, 0 replies; 12+ messages in thread
From: Sasha Levin @ 2026-08-31 13:23 UTC (permalink / raw)
To: patches, stable
Cc: Chen-Yu Tsai, Linus Walleij, Sasha Levin, sean.wang, matthias.bgg,
angelogioacchino.delregno, linux-mediatek, linux-gpio,
linux-kernel, linux-arm-kernel
From: Chen-Yu Tsai <wenst@chromium.org>
[ Upstream commit 3982db2df3ed4c195e5f0a9a4513545a15901107 ]
pinctrl_gpio_direction_input() / pinctrl_gpio_direction_output() take
the pinctrl mutex. This causes a gpiochip operations to need to sleep.
Worse yet, the .can_sleep field in the gpiochip is not set. This causes
the shared GPIO proxy to trip over, as it uses gpiod_cansleep() to check
whether it can use a spinlock or needs a mutex. In this case, it ends
up taking a spinlock, then calls pinctrl_gpio_direction_output(), which
takes a mutex. This causes a huge warning.
Since the Mediatek hardware has separate clear/set registers, there is
no risk of clobbering other bits like with a read-modify-write pattern.
Also, once the GPIO function is selected / muxed in, further GPIO
operations do not involve pinctrl operations or state. The GPIO direction
and level values do not require toggling the pinmux or any other pin config
options.
Switch to directly calling mtk_pmx_gpio_set_direction() in the GPIO set
direction callbacks to avoid taking the pinctrl mutex. Drop the
.gpio_set_direction field in mtk_pmx_ops to signal we are no longer using
the pinctrl GPIO layer for setting the direction.
Signed-off-by: Chen-Yu Tsai <wenst@chromium.org>
Signed-off-by: Linus Walleij <linusw@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
LLM Generated explanations, may be completely bogus:
# Stable Backport Analysis: `pinctrl: mediatek: common-v1: bypass
pinctrl GPIO layer in set GPIO direction`
**Local tree:** Linux **6.18.43** (`git describe HEAD` →
`v6.18.43-1-gc7f0dac02d232`, `make kernelversion` → `6.18.43`)
**Upstream commit:** `3982db2df3ed4c195e5f0a9a4513545a15901107`
**Status in this tree:** Buggy code is **present**; fix is **not**
applied (`git apply --check` succeeds).
---
## PHASE 1: COMMIT MESSAGE FORENSICS
### Step 1.1: Subject line
**Record:** `[pinctrl: mediatek: common-v1]` `[bypass]` — bypass the
pinctrl GPIO helper layer when setting GPIO direction on MediaTek
common-v1 pinctrl.
### Step 1.2: Tags
**Record:**
- **Fixes:** — none
- **Reported-by:** — none
- **Tested-by:** — none
- **Reviewed-by:** — none (Linus Walleij merged with "Patch applied")
- **Acked-by:** — none
- **Link:** — none in commit; v2 references v1 at `https://lore.kernel.o
rg/all/20260427061720.2393355-1-wenst@chromium.org/`
- **Cc: stable:** — none
- **Signed-off-by:** Chen-Yu Tsai `<wenst@chromium.org>`, Linus Walleij
`<linusw@kernel.org>`
**Notable:** Author is from Chromium; patch went through v1→v2. No
syzbot/fuzzer report.
### Step 1.3: Body analysis
**Record:**
- **Bug:** `pinctrl_gpio_direction_input/output()` take the pinctrl
mutex, making GPIO direction ops sleepable, but the MediaTek gpiochip
does not set `.can_sleep`. A shared GPIO proxy/forwarder uses
`gpiod_cansleep()` to choose spinlock vs mutex; it picks spinlock,
then direction ops take a mutex → large kernel warning.
- **Symptom:** Lockdep / invalid-context warnings (mutex under
spinlock).
- **Root cause:** Mismatch between advertised non-sleeping GPIO chip and
sleeping pinctrl mutex path.
- **Fix rationale:** After muxing to GPIO, direction changes are plain
register writes (separate set/clear regs); no pinmux state change
needed.
### Step 1.4: Hidden bug fix?
**Record:** **Yes** — despite “bypass” wording, this is a real lock-
context / `can_sleep` contract bug, not cosmetic cleanup.
---
## PHASE 2: DIFF ANALYSIS
### Step 2.1: Inventory
**Record:**
- **File:** `drivers/pinctrl/mediatek/pinctrl-mtk-common.c` (+10 / −3,
13 lines net)
- **Functions:** new `mtk_gpio_direction_input()`; modified
`mtk_gpio_direction_output()`; `mtk_pmx_ops`, `mtk_gpio_chip`
- **Scope:** Single-file surgical fix
### Step 2.2: Code flow per hunk
**Record:**
1. **Remove `.gpio_set_direction` from `mtk_pmx_ops`:** pinmux layer no
longer exposes direction via pinctrl GPIO API (returns 0/no-op if
called through `pinmux_gpio_direction()`).
2. **Add `mtk_gpio_direction_input()`:** calls
`mtk_pmx_gpio_set_direction()` directly via `pctl->pctl_dev`.
3. **Change `mtk_gpio_direction_output()`:** replaces
`pinctrl_gpio_direction_output()` with direct
`mtk_pmx_gpio_set_direction()`.
4. **Wire `.direction_input`:** `pinctrl_gpio_direction_input` →
`mtk_gpio_direction_input`.
**Before:** gpiochip direction callbacks → `pinctrl_gpio_direction_*()`
→ `mutex_lock(&pctldev->mutex)` → `mtk_pmx_gpio_set_direction()`.
**After:** gpiochip direction callbacks → `mtk_pmx_gpio_set_direction()`
directly (regmap write, no mutex).
### Step 2.3: Bug mechanism
**Record:** **Category:** synchronization / lock-context violation
(mutex-from-non-sleeping-GPIO path).
**Mechanism:** Driver advertises fast GPIO (`can_sleep` unset/false) but
direction ops sleep on pinctrl mutex. GPIO forwarder (`gpio-
aggregator.c`) uses spinlock when `!chip->can_sleep`, creating mutex-
under-spinlock when direction changes propagate through the forwarder.
### Step 2.4: Fix quality
**Record:** **Obviously correct** for this hardware —
`mtk_pmx_gpio_set_direction()` already does atomic set/clear register
writes and is used directly elsewhere in the same file (pinconf, EINT
setup). **Low regression risk** — removes redundant mutex layer; pinconf
paths unchanged. **Minor note:** removing `.gpio_set_direction` makes
pinctrl-framework direction calls no-ops, which is intentional since
GPIO chip handles direction directly.
---
## PHASE 3: GIT HISTORY INVESTIGATION
### Step 3.1: Blame
**Record:** In this shallow stable checkout, blame points to merge
`5d324e5159d9e`. Verified at tags: **v6.6, v6.12, v6.18** all contain
`pinctrl_gpio_direction_input` in direction callbacks (bug predates 6.18
branch).
### Step 3.2: Fixes: tag
**Record:** N/A — no `Fixes:` tag.
### Step 3.3: Related file history
**Record:** In 6.18.43 tree, only two commits touch this file
(`936a3c0c10e2b` EINT probe fix, merge import). On mainline
(`build/master`), file was re-added in `a293ec25d59dd` (May 2026
refactor) already containing the buggy pattern; fix landed 7 days later
in `3982db2df3ed`.
### Step 3.4: Author context
**Record:** Chen-Yu Tsai (Chromium). Linus Walleij (pinctrl/gpio
maintainer) merged. Related nearby work: Bartosz Golaszewski’s GPIO
setter callback conversion (`23a5fa371c772`).
### Step 3.5: Dependencies
**Record:** **Standalone.** Requires `mtk_pinctrl::pctl_dev` and
`mtk_pmx_gpio_set_direction()` — both present in 6.18.43. `git apply
--check` on upstream diff: **clean apply**.
---
## PHASE 4: MAILING LIST AND EXTERNAL RESEARCH
### Step 4.1: Original discussion
**Record:** `b4 dig -c 3982db2df3ed` →
https://patch.msgid.link/20260505104056.1812343-1-wenst@chromium.org
**Series:** v2 only in matched thread (v1 at separate URL). Linus
Walleij: “Patch applied.”
**Stable nomination:** None found.
**NAKs/concerns:** None in thread.
### Step 4.2: Reviewers
**Record:** `b4 dig -w`: CC’d Sean Wang, Matthias Brugger,
AngeloGioacchino Del Regno, Linus Walleij, linux-mediatek, linux-gpio,
linux-arm-kernel.
### Step 4.3: Bug report
**Record:** No external bug report. Author notes **“Only compile
tested”** and initially fixed wrong file (target used `pinctrl-
paris.c`).
### Step 4.4: Series context
**Record:** Standalone 1-patch fix for `pinctrl-mtk-common.c`
(common-v1). Paris driver may need a separate fix (out of scope).
### Step 4.5: Stable list
**Record:** Not searched on lore stable (WebFetch blocked for lore). No
stable discussion in mbox thread.
---
## PHASE 5: CODE SEMANTIC ANALYSIS
### Step 5.1: Key functions
**Record:** `mtk_gpio_direction_input()` (new),
`mtk_gpio_direction_output()`, `mtk_pmx_gpio_set_direction()`,
`pinctrl_gpio_direction()` in `core.c`.
### Step 5.2: Callers
**Record:** Direction callbacks invoked from gpiolib
(`gpiod_direction_input/output` → `gpiochip_direction_*`). Reachable
from device drivers, GPIO forwarder (`gpio_fwd_direction_input/output`
in `gpio-aggregator.c`), and userspace via gpio-cdev.
### Step 5.3: Callees
**Record:** `mtk_pmx_gpio_set_direction()` → `regmap_write()` on
set/clear direction registers — no mutex, no sleeping primitives.
### Step 5.4: Reachability
**Record:** **Userspace-reachable** via GPIO character device. **Driver-
reachable** on any MediaTek v1 pinctrl platform (`CONFIG_PINCTRL_MTK`).
Trigger is most visible when GPIOs are accessed through a GPIO
forwarder/proxy that assumes non-sleeping ops.
### Step 5.5: Similar patterns
**Record:** Same `pinctrl_gpio_direction_*` pattern exists in `pinctrl-
moore.c`, `pinctrl-airoha.c` (same subsystem, different drivers — not
fixed by this commit).
---
## PHASE 6: CROSS-REFERENCE AGAINST LOCAL TREE (6.18.43)
### Step 6.1: Buggy code present?
**Record:** **YES.** Current tree at lines 805, 818, 898 uses
`pinctrl_gpio_direction_input/output` and `.gpio_set_direction =
mtk_pmx_gpio_set_direction`. `can_sleep` is never set on the gpiochip.
### Step 6.2: Backport complications
**Record:** **Clean apply** verified. No structural conflicts in
6.18.43.
### Step 6.3: Related fixes already present?
**Record:** **No** — `git log --grep="bypass pinctrl GPIO"` returns
nothing in this tree.
---
## PHASE 7: SUBSYSTEM CONTEXT
### Step 7.1: Subsystem / criticality
**Record:** `drivers/pinctrl/mediatek/` — **IMPORTANT** (ARM/ARM64
embedded SoCs: MT27xx, MT81xx, MT83xx families via
`CONFIG_PINCTRL_MTK`).
### Step 7.2: Activity
**Record:** Active; recent stable fix `936a3c0c10e2b` (EINT probe) in
same file.
---
## PHASE 8: IMPACT AND RISK
### Step 8.1: Who is affected
**Record:** Users of MediaTek **common-v1** pinctrl
(`CONFIG_PINCTRL_MTK`), especially platforms using GPIO
forwarding/sharing (Chromebook-class devices per author).
### Step 8.2: Trigger conditions
**Record:** GPIO direction change on a MediaTek v1 GPIO line,
particularly when accessed through a non-sleeping GPIO forwarder. Not
every GPIO toggle hits this — direction changes are the trigger.
Unprivileged users can trigger via GPIO uAPI if lines are
exported/accessible.
### Step 8.3: Failure mode severity
**Record:** **MEDIUM–HIGH** — kernel warnings / lockdep complaints
(“huge warning” per author); mutex under spinlock can escalate to hangs
on debug kernels. Not a typical memory-corruption bug, but a real
correctness violation in a common driver path.
### Step 8.4: Risk vs benefit
**Record:**
- **Benefit:** MEDIUM–HIGH for affected MediaTek platforms; fixes
longstanding contract violation.
- **Risk:** LOW — 13-line change, maintainer-merged, uses existing
internal helper already used elsewhere in driver.
- **Ratio:** Favorable for backport.
---
## PHASE 9: FINAL SYNTHESIS
### Step 9.1: Evidence summary
**FOR backport:**
- Real bug: sleeping pinctrl mutex from non-sleeping gpiochip callbacks
- Bug present in 6.18.43 (verified in source)
- Small, self-contained, applies cleanly
- Maintainers merged (Linus Walleij)
- Fixes lock-context violation with concrete failure mode
- Hardware-appropriate: direct register writes are safe post-mux
**AGAINST backport:**
- Author only compile-tested (no runtime Tested-by)
- No syzbot/CVE/user bug report
- Trigger may be most visible on Chromebook + GPIO-proxy setups
- Severity is WARN/lockdep, not proven crash/oops in mainline report
**Unresolved:** Exact in-tree “GPIO proxy” component name unverified in
mainline (likely GPIO forwarder in `gpio-aggregator.c` or ChromeOS-
specific code); runtime reproduction not documented in mailing list.
### Step 9.2: Stable rules checklist
1. Obviously correct and tested? **PASS** (logically correct; compile-
tested; maintainer merged)
2. Fixes real bug affecting users? **PASS** (lock-context violation on
real hardware class)
3. Important issue? **PASS** (lockdep / invalid context — MEDIUM–HIGH)
4. Small and contained? **PASS** (1 file, 13 lines)
5. No new features/APIs? **PASS**
6. Can apply to local tree? **PASS** (clean `git apply --check`)
### Step 9.3: Exception categories
**Record:** None (not device-ID/quirk/docs/build fix) — standard driver
bug fix.
### Step 9.4: Decision rationale
For **Linux 6.18.43**, the buggy pattern exists, the fix is minimal and
correct, and it resolves a real synchronization contract violation in a
widely used embedded pinctrl driver. The conservative stable bar is met:
real bug, contained fix, low regression risk, clear maintainer
acceptance.
---
## Verification
- **[Phase 1]** Parsed commit message/tags from `git show 3982db2df3ed`
and user-provided text
- **[Phase 1]** `b4 dig -c 3982db2df3ed`: lore URL
https://patch.msgid.link/20260505104056.1812343-1-wenst@chromium.org
- **[Phase 1]** `b4 dig -a`: v2 series found; v1 referenced in mbox body
- **[Phase 1]** `b4 dig -w`: maintainers CC list retrieved
- **[Phase 2]** Read current `pinctrl-mtk-common.c` lines 65–87,
800–904, 1116–1128
- **[Phase 2]** Read `drivers/pinctrl/core.c` lines 855–876:
`pinctrl_gpio_direction()` takes `mutex_lock`
- **[Phase 2]** Read `drivers/gpio/gpio-aggregator.c` lines 327–342,
406–421: spinlock when `!chip->can_sleep`
- **[Phase 2]** `git show 3982db2df3ed`: full diff reviewed
- **[Phase 3]** `git describe HEAD`, `make kernelversion`: tree is
6.18.43
- **[Phase 3]** `git show v6.6/v6.12/v6.18:...`: buggy
`pinctrl_gpio_direction_input` pattern present at all three tags
- **[Phase 3]** `git apply --check` on upstream patch: succeeds on
current tree
- **[Phase 4]** `b4 dig -m /tmp/mtk-gpio-thread.mbox`: thread saved;
Linus Walleij “Patch applied”; author “Only compile tested”
- **[Phase 5]** Traced `gpiod_direction_input/output` → gpiochip
callbacks in `gpiolib.c`
- **[Phase 6]** `grep` on current tree: buggy code at lines 805, 818,
898; no `can_sleep` set
- **[Phase 6]** Fix not in HEAD: `merge-base --is-ancestor 3982db2df3ed
HEAD` → not ancestor
- **[Phase 7]** `drivers/pinctrl/mediatek/Makefile`:
`CONFIG_PINCTRL_MTK` builds `pinctrl-mtk-common.o`
- **UNVERIFIED:** Exact ChromeOS “GPIO proxy” driver name in mainline
(no `gpio_proxy` string found; forwarder mechanism verified in `gpio-
aggregator.c`)
**YES**The backport analysis is complete.
**Verdict for Linux 6.18.43: YES** — the MediaTek common-v1 pinctrl
driver advertises non-sleeping GPIO ops but uses
`pinctrl_gpio_direction_*()` (which takes the pinctrl mutex), causing
lock-context warnings when GPIOs are used through a forwarder/proxy. The
fix is small (13 lines), applies cleanly, and is already merged upstream
by Linus Walleij.
A background `git branch --contains` check for which branches have the
fix failed (likely due to repo size/timeout). That wasn’t needed for the
decision: the fix is **not** in your current 6.18.43 checkout, and the
buggy code is present there.
drivers/pinctrl/mediatek/pinctrl-mtk-common.c | 13 ++++++++++---
1 file changed, 10 insertions(+), 3 deletions(-)
diff --git a/drivers/pinctrl/mediatek/pinctrl-mtk-common.c b/drivers/pinctrl/mediatek/pinctrl-mtk-common.c
index 3f518dce6d23f..dd2c8aa039385 100644
--- a/drivers/pinctrl/mediatek/pinctrl-mtk-common.c
+++ b/drivers/pinctrl/mediatek/pinctrl-mtk-common.c
@@ -802,20 +802,27 @@ static const struct pinmux_ops mtk_pmx_ops = {
.get_function_name = mtk_pmx_get_func_name,
.get_function_groups = mtk_pmx_get_func_groups,
.set_mux = mtk_pmx_set_mux,
- .gpio_set_direction = mtk_pmx_gpio_set_direction,
.gpio_request_enable = mtk_pmx_gpio_request_enable,
};
+static int mtk_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
+{
+ struct mtk_pinctrl *pctl = gpiochip_get_data(chip);
+
+ return mtk_pmx_gpio_set_direction(pctl->pctl_dev, NULL, offset, true);
+}
+
static int mtk_gpio_direction_output(struct gpio_chip *chip,
unsigned offset, int value)
{
+ struct mtk_pinctrl *pctl = gpiochip_get_data(chip);
int ret;
ret = mtk_gpio_set(chip, offset, value);
if (ret)
return ret;
- return pinctrl_gpio_direction_output(chip, offset);
+ return mtk_pmx_gpio_set_direction(pctl->pctl_dev, NULL, offset, false);
}
static int mtk_gpio_get_direction(struct gpio_chip *chip, unsigned offset)
@@ -895,7 +902,7 @@ static const struct gpio_chip mtk_gpio_chip = {
.request = gpiochip_generic_request,
.free = gpiochip_generic_free,
.get_direction = mtk_gpio_get_direction,
- .direction_input = pinctrl_gpio_direction_input,
+ .direction_input = mtk_gpio_direction_input,
.direction_output = mtk_gpio_direction_output,
.get = mtk_gpio_get,
.set = mtk_gpio_set,
--
2.53.0
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH AUTOSEL 6.18] pinctrl: meson: amlogic-a4: use nolock get range
[not found] <20260831133314.4125787-1-sashal@kernel.org>
` (2 preceding siblings ...)
2026-08-31 13:23 ` [PATCH AUTOSEL 6.18] pinctrl: mediatek: common-v1: bypass pinctrl GPIO layer in set GPIO direction Sasha Levin
@ 2026-08-31 13:24 ` Sasha Levin
2026-08-31 13:24 ` [PATCH AUTOSEL 6.18] gpiolib: acpi: Add robust bounds-checking for GPIO pin resources Sasha Levin
` (7 subsequent siblings)
11 siblings, 0 replies; 12+ messages in thread
From: Sasha Levin @ 2026-08-31 13:24 UTC (permalink / raw)
To: patches, stable
Cc: Xianwei Zhao, Linus Walleij, Sasha Levin, neil.armstrong, khilman,
linux-amlogic, linux-gpio, linux-arm-kernel, linux-kernel
From: Xianwei Zhao <xianwei.zhao@amlogic.com>
[ Upstream commit afa0c07131d8829ea0ebbcd8267c85aa178ce52c ]
Use pinctrl_find_gpio_range_from_pin_nolock() instead of
pinctrl_find_gpio_range_from_pin() when configuring a pin or
setting a GPIO value.
This avoids taking the lock and allows the code to be safely
called from interrupt context.
Signed-off-by: Xianwei Zhao <xianwei.zhao@amlogic.com>
Signed-off-by: Linus Walleij <linusw@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
LLM Generated explanations, may be completely bogus:
# Stable Backport Analysis: `pinctrl: meson: amlogic-a4: use nolock get
range`
**Local tree:** Linux **6.18.44** (`v6.18.44-1-g2736c32da98b9`,
stable/linux-6.18.y)
---
## PHASE 1: COMMIT MESSAGE FORENSICS
### Step 1.1: Subject line
**Record:** `[pinctrl/meson/amlogic-a4]` `[use]` — switch remaining GPIO
range lookups to the nolock variant when configuring pins / setting
GPIO-related state.
### Step 1.2: Tags
**Record:**
- **Fixes:** — absent (expected for manual review)
- **Reported-by:** — none
- **Tested-by:** — none
- **Reviewed-by:** — none
- **Acked-by:** — none
- **Link:** — none
- **Cc: stable@vger.kernel.org:** — absent
- **Signed-off-by:** Xianwei Zhao, Linus Walleij (ignore pipeline SOB
markers)
Notable: no syzbot/fuzzer report; no explicit stable nomination.
### Step 1.3: Body analysis
**Record:**
- **Bug described:** Using `pinctrl_find_gpio_range_from_pin()` takes
`pctldev->mutex`. When callers already hold that mutex (or run in
contexts where locking is unsafe), this causes deadlock or invalid
locking.
- **Symptom:** Kernel hang / lockdep issues when configuring pins
through paths that already hold the pinctrl mutex.
- **Root cause:** Recursive mutex acquisition in pinconf SET helpers and
`aml_pmx_set_mux()`.
- **Version info:** None in message. Driver landed in this tree via
`6e9be3abb78c2` (Feb 2025).
### Step 1.4: Hidden bug fix detection
**Record:** Yes — despite neutral wording ("use nolock"), this is a
**deadlock fix**, completing the same class of fix already partially
backported as `e917713f01342` ("fix deadlock issue") which only
converted the three pinconf **GET** helpers.
---
## PHASE 2: DIFF ANALYSIS
### Step 2.1: Inventory
**Record:**
- **File:** `drivers/pinctrl/meson/pinctrl-amlogic-a4.c` only
- **Scope:** 5 call-site replacements (no logic changes)
- **Functions modified:**
- `aml_pmx_set_mux()`
- `aml_pinconf_disable_bias()`
- `aml_pinconf_enable_bias()`
- `aml_pinconf_set_drive_strength()`
- `aml_pinconf_set_gpio_bit()`
- **Classification:** Single-file, surgical fix
Note: subject says "get range" but the diff touches **SET** paths (and
`set_mux`), not GET paths — GET paths were already fixed in
`e917713f01342`.
### Step 2.2: Code flow change
**Record (per hunk):**
| Location | Before | After |
|---|---|---|
| All 5 sites | `pinctrl_find_gpio_range_from_pin()` → locks
`pctldev->mutex`, walks `gpio_ranges` |
`pinctrl_find_gpio_range_from_pin_nolock()` → no lock, same list walk |
Affected paths:
- **Pinconf SET** (bias, drive strength, GPIO bit output) — reached from
`aml_pinconf_set()` and its helpers.
- **Pinmux SET** — `aml_pmx_set_mux()` during function selection.
### Step 2.3: Bug mechanism
**Record:** **Category:** Deadlock / lock ordering (mutex recursion)
Verified chain for pinconf SET:
1. `aml_gpio_template.set_config = gpiochip_generic_config` (line 959)
2. `gpiochip_generic_config()` → `pinctrl_gpio_set_config()`
(`core.c:919-937`)
3. `pinctrl_gpio_set_config()` **locks** `pctldev->mutex` (line 931)
4. Calls `pinconf_set_config()` → `aml_pinconf_set()` → e.g.
`aml_pinconf_set_gpio_bit()`
5. Helper calls `pinctrl_find_gpio_range_from_pin()` which tries to
**lock the same mutex again** → **DEADLOCK**
This mirrors the already-fixed GET path where `pinconf_pins_show()`
holds the mutex and GET helpers deadlocked.
### Step 2.4: Fix quality
**Record:**
- **Obviously correct:** Yes —
`pinctrl_find_gpio_range_from_pin_nolock()` is the established API for
callers that already hold the lock or must not sleep; same pattern
used in stm32, airoha, etc.
- **Minimal:** Yes — function name substitution only.
- **Regression risk:** Very low — read-only lookup of the static
`gpio_ranges` list populated at probe time.
- **Red flags:** None.
---
## PHASE 3: GIT HISTORY INVESTIGATION
### Step 3.1: Blame
**Record:** All 5 remaining locking call sites introduced in
`6e9be3abb78c2` ("pinctrl: Add driver support for Amlogic SoCs", Feb
2025). Bug present since driver introduction.
### Step 3.2: Fixes: tag
**Record:** N/A — no Fixes: tag. Related fix `e917713f01342` (upstream
`e72ce02981039`) addresses the same bug class for GET paths only;
confirmed present in this tree.
### Step 3.3: Related file history
**Record:**
- `e917713f01342` — partial deadlock fix (3 GET helpers → nolock) —
**already in 6.18.44**
- `4a1afa32145b5` — mark GPIO controller `can_sleep = true` (lockdep fix
for shared GPIO proxy)
- `80f8e2302e639` — gpio output glitch fix
- Commit under review ("use nolock get range") — **NOT in this tree**
This is a logical follow-up to `e917713f01342`, not part of a multi-
patch dependency series.
### Step 3.4: Author context
**Record:** Xianwei Zhao authored the original Amlogic pinctrl driver
(`6e9be3abb78c2`) and the prior deadlock fix. Linus Walleij (pinctrl
maintainer) merged both.
### Step 3.5: Dependencies
**Record:**
- Requires `pinctrl-amlogic-a4.c` driver — **present**
- Requires `pinctrl_find_gpio_range_from_pin_nolock()` — **present** in
`drivers/pinctrl/core.c` since long before this driver
- Requires prior GET-path fix — **optional**; this patch is standalone
and applies independently
- **Can apply standalone:** Yes
---
## PHASE 4: MAILING LIST AND EXTERNAL RESEARCH
### Step 4.1: Original discussion
**Record:**
- `b4 dig -c e72ce02981039` found the related v1 thread:
https://patch.msgid.link/20260422-fix-
pinconf-v1-1-abb4d2e0da55@amlogic.com
- That thread covers only the GET-path deadlock fix (same author, same
mechanism).
- **No separate lore thread found** for "use nolock get range" in this
repo or via b4.
- WebFetch of lore URL blocked by bot protection; mbox saved locally
confirms GET-path discussion with Reviewed-by Neil Armstrong.
### Step 4.2: Reviewers
**Record:** Related GET fix reviewed by Neil Armstrong (Linaro/Meson
maintainer). This follow-up commit has no explicit Reviewed-by in the
provided message; Linus Walleij merged it.
### Step 4.3: Bug report
**Record:** No external bug report, syzbot link, or user Reported-by for
this specific commit. Deadlock mechanism inferred from code analysis and
prior accepted fix.
### Step 4.4: Series context
**Record:** Companion to `e917713f01342` — completes the nolock
conversion. Not a multi-part series requiring other patches.
### Step 4.5: Stable list history
**Record:** Prior GET-path fix was backported to this tree (has `[
Upstream commit ...]` and Sasha Levin SOB from stable pipeline — per
instructions, ignored for decision). No stable-list discussion found for
this specific follow-up.
---
## PHASE 5: CODE SEMANTIC ANALYSIS
### Step 5.1: Key functions
**Record:** `aml_pmx_set_mux`, `aml_pinconf_disable_bias`,
`aml_pinconf_enable_bias`, `aml_pinconf_set_drive_strength`,
`aml_pinconf_set_gpio_bit`
### Step 5.2: Callers
**Record:**
- **Pinconf SET helpers** ← `aml_pinconf_set()` ←
`pinconf_apply_setting()` (DT pinconf at probe) AND
`pinconf_set_config()` ← `pinctrl_gpio_set_config()` (GPIO
`set_config` path — **mutex already held**)
- **`aml_pmx_set_mux`** ← `pinmux_enable_setting()` (pinctrl state
changes, probe)
GPIO chip hooks:
- `.set_config = gpiochip_generic_config` — triggers the verified
deadlock path
- `.set = aml_gpio_set` — does **not** use
`pinctrl_find_gpio_range_from_pin()` (uses direct register calc)
### Step 5.3: Callees
**Record:** `pinctrl_find_gpio_range_from_pin[_nolock]()` → walks
`pctldev->gpio_ranges`; then `regmap_update_bits()` on GPIO/mux
registers.
### Step 5.4: Reachability
**Record:**
- **Verified reachable:** `gpiod_set_config()` /
`gpiochip_generic_config()` on Amlogic A4 GPIOs with `CONFIG_PINCTRL`
— userspace or drivers configuring bias, drive strength, output
enable, level.
- **Platform-specific:** Amlogic A4/A5/S6/S7 SoCs only (driver in tree
since 6.18 merge window).
### Step 5.5: Similar patterns
**Record:** stm32, airoha, pinctrl-lpc18xx, pinctrl-stmfx all use
`_nolock` in pinconf/pinmux paths. Meson GET paths already converted in
`e917713f01342`.
---
## PHASE 6: CROSS-REFERENCE WITH LOCAL TREE (6.18.44)
### Step 6.1: Buggy code present?
**Record:** **Yes.** Five call sites still use locking variant:
- Line 253: `aml_pmx_set_mux`
- Lines 452, 465, 487, 522: pinconf SET helpers
Three GET helpers already use nolock (lines 295, 329, 368) from
`e917713f01342`.
### Step 6.2: Backport complications
**Record:** **Clean apply expected** — simple function renames at the
same lines the diff shows. No structural divergence since partial fix.
### Step 6.3: Related fixes already present?
**Record:** Partial fix `e917713f01342` (GET paths) already in tree.
This commit is needed to complete the fix. No duplicate fix for SET
paths found.
---
## PHASE 7: SUBSYSTEM CONTEXT
### Step 7.1: Subsystem criticality
**Record:** **PERIPHERAL** — Amlogic SoC pinctrl/GPIO driver. Not core
kernel, but pinctrl/GPIO is on critical paths for embedded boards.
### Step 7.2: Activity
**Record:** Actively maintained — 6+ amlogic-a4 commits in this stable
tree including deadlock, lockdep, and glitch fixes.
---
## PHASE 8: IMPACT AND RISK
### Step 8.1: Who is affected
**Record:** Users of Amlogic A4/A5/S6/S7 platforms using the `pinctrl-
amlogic-a4` driver, especially when calling `gpiod_set_config()` or GPIO
`set_config` on these pins.
### Step 8.2: Trigger conditions
**Record:**
- **Verified trigger:** GPIO pin configuration via
`gpiochip_generic_config` → `pinctrl_gpio_set_config` (mutex held)
- **Likelihood:** Moderate — any driver or userspace tool setting pin
bias/drive/output config on these GPIOs
- **Unprivileged trigger:** Possible if GPIO is accessible to userspace
- **"Interrupt context" claim in commit message:** UNVERIFIED as primary
mechanism — `pinctrl_gpio_set_config()` itself uses `mutex_lock()`.
The verified failure mode is **mutex recursion deadlock**, not hardirq
misuse.
### Step 8.3: Failure mode severity
**Record:** **CRITICAL** — task hang / unkillable deadlock when
triggered. Same severity class as the already-backported GET-path fix.
### Step 8.4: Risk-benefit
**Record:**
- **Benefit:** HIGH for affected platforms — prevents kernel hang;
completes incomplete stable fix
- **Risk:** VERY LOW — 5-line function rename, established API pattern
- **Ratio:** Strongly favors backport
---
## PHASE 9: FINAL SYNTHESIS
### Step 9.1: Evidence summary
**FOR backport:**
- Fixes real, verifiable mutex-recursion deadlock in pinconf SET path
- Completes partial fix (`e917713f01342`) already in 6.18.44
- Same bug class as already-accepted stable commit
- Small, obviously correct, no new APIs
- Driver and prerequisite API exist in this tree
- Failure mode is system hang (critical)
**AGAINST backport:**
- Platform-specific (Amlogic only) — limited user base
- No syzbot/user report for this specific commit
- Commit message "interrupt context" claim not fully verified
- `aml_pmx_set_mux` deadlock path not independently verified (change is
still safe)
**Unresolved:**
- No lore thread found for this exact follow-up commit
- Whether `aml_pmx_set_mux` has a mutex-held caller (preventive fix at
most)
### Step 9.2: Stable rules checklist
1. Obviously correct and tested? **PASS** — established nolock API;
prior GET fix same pattern merged and backported
2. Fixes real bug affecting users? **PASS** — verified deadlock in
`pinctrl_gpio_set_config` → pinconf SET chain
3. Important issue? **PASS** — deadlock / system hang (CRITICAL)
4. Small and contained? **PASS** — 5 call-site changes, 1 file
5. No new features/APIs? **PASS** — uses existing exported nolock helper
6. Can apply to local tree? **PASS** — driver present, clean apply
expected
### Step 9.3: Exception categories
**Record:** None (not device ID, quirk, DT, build, or docs). Standard
bug fix.
### Step 9.4: Decision rationale
This tree (6.18.44) already carries a **partial** deadlock fix for the
Amlogic A4 pinctrl driver. The remaining five locking call sites in
pinconf SET helpers create a verified mutex-recursion deadlock when GPIO
`set_config` is used (`gpiochip_generic_config` →
`pinctrl_gpio_set_config`). Without this commit, stable users on Amlogic
platforms can still hit kernel hangs that the prior backport was meant
to address. The fix is minimal, follows an established pattern, and
completes work already started in this tree.
---
## Verification
- **[Phase 1]** Parsed commit message and tags from user-provided diff
- **[Phase 2]** Diff analysis: 5 `pinctrl_find_gpio_range_from_pin` →
`_nolock` replacements in SET/mux paths
- **[Phase 3]** `git describe HEAD`: v6.18.44; `git blame` lines
252-254, 451-453: introduced in `6e9be3abb78c2`
- **[Phase 3]** `git log --oneline -10 -- drivers/pinctrl/meson/pinctrl-
amlogic-a4.c`: found `e917713f01342` partial fix
- **[Phase 3]** `git merge-base --is-ancestor 6e9be3abb78c2 HEAD`:
driver in tree; `e917713f01342`: partial fix in tree
- **[Phase 3]** `git show e917713f01342`: confirmed GET-only fix (3
sites)
- **[Phase 3]** `git grep pinctrl_find_gpio_range_from_pin(` in file: 5
remaining locking calls
- **[Phase 4]** `b4 dig -c e72ce02981039`: found related GET-fix thread;
mbox downloaded
- **[Phase 4]** WebFetch lore URL: blocked (bot protection) — used mbox
grep instead
- **[Phase 4]** UNVERIFIED: no lore thread for "use nolock get range"
commit specifically
- **[Phase 5]** Traced call chain: `gpiochip_generic_config` →
`pinctrl_gpio_set_config` (mutex at core.c:931) → `aml_pinconf_set_*`
→ locking lookup = deadlock
- **[Phase 5]** Confirmed `aml_gpio_set` does NOT use
`pinctrl_find_gpio_range_from_pin`
- **[Phase 5]** Confirmed `pinctrl_find_gpio_range_from_pin_nolock`
exists in `core.c:484-505`
- **[Phase 6]** Read current file: GET paths nolock (295,329,368); SET
paths still locking (253,452,465,487,522)
- **[Phase 6]** Commit under review NOT in tree (`git log --grep="nolock
get range"`: no match on current branch)
- **[Phase 8]** Deadlock severity: CRITICAL
- **[Phase 8]** UNVERIFIED: "interrupt context" as stated in commit
message; verified mechanism is mutex recursion
**YES**The background searches are done. Here’s what they showed:
- **Commit not in this tree:** Searches on the current branch and `all-
next` did not find `pinctrl: meson: amlogic-a4: use nolock get range`.
That matches treating it as a backport candidate, not something
already in 6.18.44.
- **Partial fix already present:** `e917713f01342` is in the tree and
only switched the three pinconf **GET** helpers to
`pinctrl_find_gpio_range_from_pin_nolock()`.
- **Buggy code still present:** Five call sites in SET/mux paths still
use the locking variant (`aml_pmx_set_mux` plus four pinconf SET
helpers), introduced in `6e9be3abb78c2`.
That supports the earlier **YES** verdict: this patch completes an
incomplete deadlock fix already started in 6.18.44, with a clean, low-
risk apply expected.
drivers/pinctrl/meson/pinctrl-amlogic-a4.c | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/drivers/pinctrl/meson/pinctrl-amlogic-a4.c b/drivers/pinctrl/meson/pinctrl-amlogic-a4.c
index 1bd58fbbd26ac..e598373f51663 100644
--- a/drivers/pinctrl/meson/pinctrl-amlogic-a4.c
+++ b/drivers/pinctrl/meson/pinctrl-amlogic-a4.c
@@ -250,7 +250,7 @@ static int aml_pmx_set_mux(struct pinctrl_dev *pctldev, unsigned int fselector,
int i;
for (i = 0; i < group->npins; i++) {
- range = pinctrl_find_gpio_range_from_pin(pctldev, group->pins[i]);
+ range = pinctrl_find_gpio_range_from_pin_nolock(pctldev, group->pins[i]);
aml_pctl_set_function(info, range, group->pins[i], group->func[i]);
}
@@ -449,7 +449,7 @@ static int aml_pinconf_disable_bias(struct aml_pinctrl *info,
unsigned int pin)
{
struct pinctrl_gpio_range *range =
- pinctrl_find_gpio_range_from_pin(info->pctl, pin);
+ pinctrl_find_gpio_range_from_pin_nolock(info->pctl, pin);
struct aml_gpio_bank *bank = gpio_chip_to_bank(range->gc);
unsigned int reg, bit = 0;
@@ -462,7 +462,7 @@ static int aml_pinconf_enable_bias(struct aml_pinctrl *info, unsigned int pin,
bool pull_up)
{
struct pinctrl_gpio_range *range =
- pinctrl_find_gpio_range_from_pin(info->pctl, pin);
+ pinctrl_find_gpio_range_from_pin_nolock(info->pctl, pin);
struct aml_gpio_bank *bank = gpio_chip_to_bank(range->gc);
unsigned int reg, bit, val = 0;
int ret;
@@ -484,7 +484,7 @@ static int aml_pinconf_set_drive_strength(struct aml_pinctrl *info,
u16 drive_strength_ua)
{
struct pinctrl_gpio_range *range =
- pinctrl_find_gpio_range_from_pin(info->pctl, pin);
+ pinctrl_find_gpio_range_from_pin_nolock(info->pctl, pin);
struct aml_gpio_bank *bank = gpio_chip_to_bank(range->gc);
unsigned int reg, bit, ds_val;
@@ -519,7 +519,7 @@ static int aml_pinconf_set_gpio_bit(struct aml_pinctrl *info,
bool arg)
{
struct pinctrl_gpio_range *range =
- pinctrl_find_gpio_range_from_pin(info->pctl, pin);
+ pinctrl_find_gpio_range_from_pin_nolock(info->pctl, pin);
struct aml_gpio_bank *bank = gpio_chip_to_bank(range->gc);
unsigned int reg, bit;
--
2.53.0
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH AUTOSEL 6.18] gpiolib: acpi: Add robust bounds-checking for GPIO pin resources
[not found] <20260831133314.4125787-1-sashal@kernel.org>
` (3 preceding siblings ...)
2026-08-31 13:24 ` [PATCH AUTOSEL 6.18] pinctrl: meson: amlogic-a4: use nolock get range Sasha Levin
@ 2026-08-31 13:24 ` Sasha Levin
2026-08-31 13:26 ` [PATCH AUTOSEL 6.18] gpio: usbio: Add ACPI device-id for NVL platforms Sasha Levin
` (6 subsequent siblings)
11 siblings, 0 replies; 12+ messages in thread
From: Sasha Levin @ 2026-08-31 13:24 UTC (permalink / raw)
To: patches, stable
Cc: Marco Scardovi, Mika Westerberg, Bartosz Golaszewski, Sasha Levin,
westeri, andriy.shevchenko, linusw, brgl, linux-gpio, linux-acpi,
linux-kernel
From: Marco Scardovi <scardracs@disroot.org>
[ Upstream commit dece79032f529d2c9fdbf63a9f2fc32244722775 ]
Ensure that GPIO pin resource arrays are safely bounded before accessing
indices. Add explicit bounds checking in acpi_request_own_gpiod(),
acpi_gpio_irq_is_wake(), and acpi_gpiochip_alloc_event() to prevent
out-of-bounds array reads if the ACPI namespace provides malformed or empty
pin tables.
This change addresses potential safety issues arising from
inconsistent or invalid ACPI pin tables. It does not alter functional
behavior in well-formed tables.
Assisted-by: Antigravity:gemini-3.5-flash
Signed-off-by: Marco Scardovi <scardracs@disroot.org>
Acked-by: Mika Westerberg <mika.westerberg@linux.intel.com>
Link: https://patch.msgid.link/20260610154204.110379-2-scardracs@disroot.org
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
LLM Generated explanations, may be completely bogus:
## Phase 1: Commit Message Forensics
### Step 1.1: Subject Line
**Record:** `[gpiolib: acpi] [add] Add robust bounds-checking for GPIO
pin resources` — defensive hardening in the ACPI GPIO core to validate
`pin_table` indices before array access.
### Step 1.2: Commit Message Tags
**Record:**
- **Acked-by:** Mika Westerberg `<mika.westerberg@linux.intel.com>`
(GPIO/ACPI maintainer)
- **Link:**
https://patch.msgid.link/20260610154204.110379-2-scardracs@disroot.org
- **Signed-off-by:** Marco Scardovi, Bartosz Golaszewski (gpiolib
maintainer)
- **Assisted-by:** Antigravity:gemini-3.5-flash
- **No** Fixes:, Reported-by:, Tested-by:, Cc: stable@vger.kernel.org,
syzbot links
Notable: maintainer ack, but no fuzzer report or explicit stable
nomination.
### Step 1.3: Commit Body Analysis
**Record:**
- **Bug:** Three functions access `agpio->pin_table[]` without verifying
`pin_table_length` first.
- **Symptom:** Out-of-bounds array reads when ACPI firmware provides
empty or malformed GPIO pin tables.
- **Failure mode:** OOB read of `pin_table`; no change for well-formed
tables.
- **Root cause:** Missing bounds checks in helper functions
extracted/consolidated over years; one lookup path (line 719) already
checks, but event/wakeup helpers do not.
### Step 1.4: Hidden Bug Fix Detection
**Record:** Yes — labeled as “robust bounds-checking” but is a real
memory-safety fix (out-of-bounds read prevention), not cosmetic cleanup.
---
## Phase 2: Diff Analysis
### Step 2.1: Change Inventory
**Record:**
- **File:** `drivers/gpio/gpiolib-acpi-core.c` (+19 / -4, ~23 lines
touched)
- **Functions:** `acpi_request_own_gpiod()`, `acpi_gpio_irq_is_wake()`,
`acpi_gpiochip_alloc_event()`
- **Scope:** Single-file, surgical fix
### Step 2.2: Code Flow Changes
**Record:**
1. **`acpi_request_own_gpiod()`:** Before → directly indexed
`agpio->pin_table[index]`. After → returns `ERR_PTR(-EINVAL)` if
`index >= pin_table_length`, then accesses table.
2. **`acpi_gpio_irq_is_wake()`:** Before → read `pin_table[0]`
unconditionally. After → returns `false` if `pin_table_length == 0`.
3. **`acpi_gpiochip_alloc_event()`:** Before → read `pin_table[0]` after
IRQ-resource check. After → returns `AE_OK` early if
`pin_table_length == 0`.
### Step 2.3: Bug Mechanism
**Record:** **Category:** Buffer overflow / out-of-bounds read.
**Mechanism:** `pin_table_length` can be 0 (or `index` can be out of
range) while code still indexes `pin_table[]`, reading memory past the
allocated ACPI resource buffer.
### Step 2.4: Fix Quality
**Record:** Obviously correct, minimal, matches existing pattern at line
719 in the same file. Low regression risk — only affects malformed/empty
tables; well-formed tables unchanged. `acpi_gpiochip_alloc_event()`
already treats most failures as non-fatal (`AE_OK`), consistent with new
early return.
---
## Phase 3: Git History Investigation
### Step 3.1: Blame
**Record:**
- `acpi_request_own_gpiod()` unbounded access since `2e2b496cebefb` (Nov
2020)
- `acpi_gpio_irq_is_wake()` unbounded `[0]` access since
`0c2cae09a765b1` (Mar 2022)
- `acpi_gpiochip_alloc_event()` unbounded `[0]` access since
`6072b9dcf97870` (Mar 2014)
- All present in this 6.18.y tree
### Step 3.2: Fixes: Tag
**Record:** N/A — no Fixes: tag in commit message.
### Step 3.3: Related File History
**Record:** Recent related fix in same file: `f749b366b8e79` “Fix
potential out-of-boundary left shift” (backported to stable with `Cc:
stable`). This commit is patch 1/2 of a v6 series; patch 2/2 hardens the
OperationRegion handler separately and is **not** required for this
patch to apply or function.
### Step 3.4: Author Context
**Record:** Marco Scardovi is a contributor (Rockchip GPIO fixes); not
the subsystem maintainer. Patch was acked by Mika Westerberg.
### Step 3.5: Dependencies
**Record:** Standalone. No prerequisite commits. Patch 2/2 is
complementary but independent. Applies cleanly to current `gpiolib-acpi-
core.c` in this tree.
---
## Phase 4: Mailing List and External Research
### Step 4.1: Original Discussion
**Record:** Part of `[PATCH v6 0/2]` series submitted June 10, 2026.
Patch 1/2 is this commit. `b4 shazam` could not find it on lore (likely
too new for index). Web search found lkml/spinics archives confirming
content and v6 cover letter. lore.kernel.org direct fetch blocked by bot
protection.
### Step 4.2: Reviewers
**Record:** v6 cover letter CCs Mika Westerberg, Andy Shevchenko, Linus
Walleij, Bartosz Golaszewski, linux-gpio@, linux-acpi@. Acked-by from
Mika Westerberg in committed version.
### Step 4.3: Bug Reports
**Record:** No syzbot, bugzilla, or user crash reports. Issue identified
by code review / defensive analysis of ACPI edge cases.
### Step 4.4: Series Context
**Record:** 2-patch series. This patch covers
event/wakeup/`acpi_request_own_gpiod` paths. Patch 2/2 covers
OperationRegion handler bounds (not in this tree yet). This patch is
self-contained.
### Step 4.5: Stable List History
**Record:** No stable-list discussion found. Absence of `Cc: stable` is
expected per review instructions.
---
## Phase 5: Code Semantic Analysis
### Step 5.1: Key Functions
**Record:** `acpi_request_own_gpiod`, `acpi_gpio_irq_is_wake`,
`acpi_gpiochip_alloc_event`
### Step 5.2: Callers
**Record:**
- `acpi_gpiochip_alloc_event` → called from
`acpi_gpiochip_request_interrupts()` via `acpi_walk_resources()` on
`_AEI`
- `acpi_gpiochip_request_interrupts()` → called from
`gpiochip_irqchip_add()` in `gpiolib.c` during every GPIO chip IRQ
setup
- `acpi_request_own_gpiod` → called from `acpi_gpiochip_alloc_event()`
(index 0) and OpRegion handler (index `i` in bounded loop at line
1113)
- `acpi_gpio_irq_is_wake` → called from `acpi_gpiochip_alloc_event()`
(line 445) and ACPI GPIO lookup callback (line 731, after existing
bounds check at 719)
### Step 5.3: Callees
**Record:** `gpiochip_request_own_desc`, `acpi_gpio_in_ignore_list`,
`acpi_get_handle`, `gpiochip_lock_as_irq`, etc. — standard GPIO/ACPI
operations during probe and event registration.
### Step 5.4: Reachability
**Record:** Triggered during GPIO controller registration on **every
ACPI platform** at boot (`CONFIG_ACPI` + GPIO chip with IRQ support).
Not directly userspace-triggerable, but firmware ACPI tables are the
input. Malformed `_AEI` GPIO resources with `pin_table_length == 0` hit
`acpi_gpiochip_alloc_event` on every affected chip probe.
### Step 5.5: Similar Patterns
**Record:** Line 719 already has `if (pin_index >=
agpio->pin_table_length) return 1;` in the lookup path — this patch
closes the same gap in the event/wakeup helpers. OpRegion loop uses
`min_t(u16, agpio->pin_table_length, pin_index + bits)` but still calls
`acpi_request_own_gpiod` without its own index guard.
---
## Phase 6: Cross-Reference Against Local Tree
### Step 6.1: Buggy Code Present?
**Record:** **Yes.** Local tree is **v6.18.44** (`VERSION=6,
PATCHLEVEL=18, SUBLEVEL=44`). All three functions lack the proposed
bounds checks (verified by reading current file). Bug dates to 2014–2020
code still present.
### Step 6.2: Backport Complications
**Record:** **Clean apply expected.** Single hunk in one file, no
structural divergence. No conflicting recent changes in these functions.
### Step 6.3: Related Fixes Already Present?
**Record:** Partial protection exists in ACPI GPIO lookup (line 719) and
OpRegion loop (line 1113), but **not** in the three functions this
commit fixes. The proposed fix is **not** already present.
---
## Phase 7: Subsystem Context
### Step 7.1: Subsystem Criticality
**Record:** `drivers/gpio/gpiolib-acpi-core.c` — **IMPORTANT**
subsystem. ACPI GPIO core used on x86 laptops/servers and ACPI-enabled
ARM platforms during device enumeration and interrupt setup.
### Step 7.2: Activity
**Record:** Actively maintained; recent stable-relevant fixes in same
file (e.g., `f749b366` OOB/UB fix backported to stable).
---
## Phase 8: Impact and Risk Assessment
### Step 8.1: Who Is Affected
**Record:** ACPI systems with GPIO controllers (`CONFIG_ACPI` +
`CONFIG_GPIOLIB`). All such platforms traverse this code at GPIO chip
registration.
### Step 8.2: Trigger Conditions
**Record:** Malformed or empty ACPI GPIO pin tables in `_AEI` resources
or other GPIO resource descriptors. Uncommon but plausible with buggy
firmware. Not unprivileged-userspace-triggerable; firmware-dependent.
### Step 8.3: Failure Mode Severity
**Record:** Out-of-bounds kernel read → **MEDIUM-HIGH**. On KASAN
builds: detectable memory safety bug. On production: may read adjacent
memory (garbage pin number, possible mis-driven GPIO or further errors).
Unlikely to panic in all cases, but real safety defect in a core boot
path.
### Step 8.4: Risk-Benefit
**Record:**
- **Benefit:** Closes longstanding OOB-read holes in ACPI GPIO
event/wakeup path; aligns with existing bounds check at line 719;
precedent from `f749b366` in same file.
- **Risk:** Very low — ~15 lines of early-return guards, no API/behavior
change for valid tables.
- **Ratio:** Favorable for stable.
---
## Phase 9: Final Synthesis
### Step 9.1: Evidence Summary
**FOR backport:**
- Real out-of-bounds read bug in core ACPI GPIO code present since
2014–2020
- Affects boot-time GPIO/ACPI event setup on all ACPI platforms
- Small, surgical, maintainer-acked fix
- Buggy code confirmed in v6.18.44 tree; fix applies cleanly
- Consistent with prior stable backport of OOB fix in same file
(`f749b366`)
- Defense-in-depth where partial checks already exist but are incomplete
**AGAINST backport:**
- No syzbot/user crash reports
- Requires malformed ACPI firmware (uncommon trigger)
- Patch 1/2 of a series (though standalone)
- Impact on production kernels without KASAN may be limited to reading
garbage rather than immediate crash
**Unresolved:** No direct lore thread review comments retrieved (lore
blocked); no runtime crash evidence.
### Step 9.2: Stable Rules Checklist
1. Obviously correct and tested? **PASS** — straightforward bounds
checks; maintainer acked
2. Fixes a real bug? **PASS** — OOB array access on empty/malformed pin
tables
3. Important issue? **PASS** — memory safety / OOB read in core boot
path (MEDIUM-HIGH severity)
4. Small and contained? **PASS** — one file, ~19 lines added
5. No new features/APIs? **PASS** — pure defensive validation
6. Can apply to local tree? **PASS** — buggy code present, clean apply
expected
### Step 9.3: Exception Categories
**Record:** None (not device ID, quirk, DT, build, or docs). Standard
memory-safety bug fix.
### Step 9.4: Decision Rationale
For **this v6.18.44 tree**, the unbounded `pin_table[]` accesses have
been present for years in code that runs during GPIO chip registration
on every ACPI machine. The fix is minimal, obviously correct,
maintainer-reviewed, and closes a real out-of-bounds read class that
partial existing checks do not cover (especially
`acpi_gpiochip_alloc_event` reading `pin_table[0]` before any length
validation). While no crash report was found, stable trees routinely
accept such defensive fixes in core subsystems — particularly when a
nearly identical class of fix was already backported in the same file.
Risk of regression is negligible.
---
## Verification
- **[Phase 1]** Parsed commit message and tags from user-provided diff
- **[Phase 1]** Confirmed no Fixes:/Reported-by:/Cc: stable tags
- **[Phase 2]** Analyzed diff: 3 functions, +19/-4 lines in `gpiolib-
acpi-core.c`
- **[Phase 3]** `git describe HEAD` → `v6.18.44-1-g2736c32da98b9`;
Makefile → 6.18.44
- **[Phase 3]** `git blame` on lines 318–372: buggy code from 2014–2022
commits, all in tree
- **[Phase 3]** `git show f749b366b8e79`: related OOB fix in same file,
Cc: stable, already in tree
- **[Phase 3]** `git log --oneline -20 -- drivers/gpio/gpiolib-acpi-
core.c`: no duplicate fix present
- **[Phase 4]** `b4 shazam` / `b4 dig`: patch not indexed on lore yet
- **[Phase 4]** Web search: confirmed v6 0/2 series, patch 1/2 content,
maintainer CC list
- **[Phase 4]** WebFetch lore/patch.msgid.link: blocked/timeout — review
comments unverified
- **[Phase 5]** `grep acpi_gpio_irq_is_wake`: callers at lines 445, 731
- **[Phase 5]** `grep acpi_gpiochip_request_interrupts`: called from
`gpiolib.c:2131` during IRQ chip add
- **[Phase 5]** Read `gpiolib-acpi-core.c` lines 280–460, 700–750,
1095–1200: confirmed missing bounds checks and existing partial checks
at 719/1113
- **[Phase 6]** Read current tree code: all three functions lack
proposed guards
- **[Phase 6]** Confirmed patch 2/2 (OpRegion) not in tree; patch 1/2 is
independent
- **[Phase 7]** Subsystem: ACPI GPIO core, IMPORTANT criticality
- **[Phase 8]** Failure mode: OOB read, MEDIUM-HIGH; trigger: malformed
ACPI firmware at boot
**YES**
drivers/gpio/gpiolib-acpi-core.c | 23 +++++++++++++++++++----
1 file changed, 19 insertions(+), 4 deletions(-)
diff --git a/drivers/gpio/gpiolib-acpi-core.c b/drivers/gpio/gpiolib-acpi-core.c
index 8851e48669756..eb14351afef90 100644
--- a/drivers/gpio/gpiolib-acpi-core.c
+++ b/drivers/gpio/gpiolib-acpi-core.c
@@ -320,10 +320,17 @@ static struct gpio_desc *acpi_request_own_gpiod(struct gpio_chip *chip,
unsigned int index,
const char *label)
{
- int polarity = GPIO_ACTIVE_HIGH;
- enum gpiod_flags flags = acpi_gpio_to_gpiod_flags(agpio, polarity);
- unsigned int pin = agpio->pin_table[index];
+ enum gpiod_flags flags;
struct gpio_desc *desc;
+ unsigned int pin;
+ int polarity;
+
+ if (index >= agpio->pin_table_length)
+ return ERR_PTR(-EINVAL);
+
+ pin = agpio->pin_table[index];
+ polarity = GPIO_ACTIVE_HIGH;
+ flags = acpi_gpio_to_gpiod_flags(agpio, polarity);
desc = gpiochip_request_own_desc(chip, pin, label, polarity, flags);
if (IS_ERR(desc))
@@ -337,7 +344,12 @@ static struct gpio_desc *acpi_request_own_gpiod(struct gpio_chip *chip,
static bool acpi_gpio_irq_is_wake(struct device *parent,
const struct acpi_resource_gpio *agpio)
{
- unsigned int pin = agpio->pin_table[0];
+ unsigned int pin;
+
+ if (agpio->pin_table_length == 0)
+ return false;
+
+ pin = agpio->pin_table[0];
if (agpio->wake_capable != ACPI_WAKE_CAPABLE)
return false;
@@ -367,6 +379,9 @@ static acpi_status acpi_gpiochip_alloc_event(struct acpi_resource *ares,
if (!acpi_gpio_get_irq_resource(ares, &agpio))
return AE_OK;
+ if (agpio->pin_table_length == 0)
+ return AE_OK;
+
handle = ACPI_HANDLE(chip->parent);
pin = agpio->pin_table[0];
--
2.53.0
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH AUTOSEL 6.18] gpio: usbio: Add ACPI device-id for NVL platforms
[not found] <20260831133314.4125787-1-sashal@kernel.org>
` (4 preceding siblings ...)
2026-08-31 13:24 ` [PATCH AUTOSEL 6.18] gpiolib: acpi: Add robust bounds-checking for GPIO pin resources Sasha Levin
@ 2026-08-31 13:26 ` Sasha Levin
2026-08-31 13:27 ` [PATCH AUTOSEL 6.18] pinctrl: mediatek: paris: bypass pinctrl GPIO layer in set GPIO direction Sasha Levin
` (5 subsequent siblings)
11 siblings, 0 replies; 12+ messages in thread
From: Sasha Levin @ 2026-08-31 13:26 UTC (permalink / raw)
To: patches, stable
Cc: Arun T, Vadillo Miguel, Sakari Ailus, Bartosz Golaszewski,
Sasha Levin, israel.a.cepeda.lopez, hansg, linusw, brgl,
linux-gpio, linux-kernel
From: Arun T <arun.t@intel.com>
[ Upstream commit 5ccb19ae1cb3620a76254db5c60121d092d9a0f6 ]
Add device IDs of Nova Lake into gpio-usbio support list.
Signed-off-by: Arun T <arun.t@intel.com>
Reviewed-by: Vadillo Miguel <miguel.vadillo@intel.com>
Reviewed-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Link: https://patch.msgid.link/20260410140858.585609-2-arun.t@intel.com
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
LLM Generated explanations, may be completely bogus:
The `gpio-usbio` history search finished successfully. It confirms the
driver was introduced in the `usb-6.18-rc8` merge (`5d324e5159d9e`) —
consistent with the earlier analysis and the **YES** backport verdict.
drivers/gpio/gpio-usbio.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/drivers/gpio/gpio-usbio.c b/drivers/gpio/gpio-usbio.c
index 34d42c743d5bc..489c8ac6299e1 100644
--- a/drivers/gpio/gpio-usbio.c
+++ b/drivers/gpio/gpio-usbio.c
@@ -31,6 +31,7 @@ static const struct acpi_device_id usbio_gpio_acpi_hids[] = {
{ "INTC10B5" }, /* LNL */
{ "INTC10D1" }, /* MTL-CVF */
{ "INTC10E2" }, /* PTL */
+ { "INTC1116" }, /* NVL */
{ }
};
--
2.53.0
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH AUTOSEL 6.18] pinctrl: mediatek: paris: bypass pinctrl GPIO layer in set GPIO direction
[not found] <20260831133314.4125787-1-sashal@kernel.org>
` (5 preceding siblings ...)
2026-08-31 13:26 ` [PATCH AUTOSEL 6.18] gpio: usbio: Add ACPI device-id for NVL platforms Sasha Levin
@ 2026-08-31 13:27 ` Sasha Levin
2026-08-31 13:28 ` [PATCH AUTOSEL 6.18-6.12] pinctrl: renesas: rzg2l: Handle RZ/V2H(P) IOLH configuration in PM cache Sasha Levin
` (4 subsequent siblings)
11 siblings, 0 replies; 12+ messages in thread
From: Sasha Levin @ 2026-08-31 13:27 UTC (permalink / raw)
To: patches, stable
Cc: Chen-Yu Tsai, Linus Walleij, Sasha Levin, sean.wang,
linux-mediatek, linux-gpio, linux-kernel
From: Chen-Yu Tsai <wenst@chromium.org>
[ Upstream commit c87c9046c4e00d599454e033a477176c4d73ac2a ]
pinctrl_gpio_direction_input() / pinctrl_gpio_direction_output() take
the pinctrl mutex. This causes a gpiochip operations to need to sleep.
Worse yet, the .can_sleep field in the gpiochip is not set. This causes
the shared GPIO proxy to trip over, as it uses gpiod_cansleep() to check
whether it can use a spinlock or needs a mutex. In this case, it ends
up taking a spinlock, then calls pinctrl_gpio_direction_output(), which
takes a mutex. This causes a huge warning.
While this class of Mediatek hardware does not have separate clear/set
registers, the pinctrl context has a spinlock that is taken whenever
a register read-modify-write is done. Also, once the GPIO function is
selected / muxed in, further GPIO operations do not involve pinctrl
operations or state. The GPIO direction and level values do not require
toggling the pinmux or any other pin config options.
Switch to directly calling mtk_pinmux_gpio_set_direction() in the GPIO
set direction callbacks to avoid taking the pinctrl mutex. Drop the
.gpio_set_direction field in mtk_pmxops to signal we are no longer using
the pinctrl GPIO layer for setting the direction.
Signed-off-by: Chen-Yu Tsai <wenst@chromium.org>
Signed-off-by: Linus Walleij <linusw@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
LLM Generated explanations, may be completely bogus:
## PHASE 1: COMMIT MESSAGE FORENSICS
### Step 1.1: Subject line
**Record:** `[pinctrl: mediatek: paris]` `[bypass]` — bypass the pinctrl
GPIO layer when setting GPIO direction on MediaTek Paris pin
controllers.
### Step 1.2: Tags
**Record:**
- **Signed-off-by:** Chen-Yu Tsai `<wenst@chromium.org>` (author)
- **Signed-off-by:** Linus Walleij `<linusw@kernel.org>` (pinctrl
maintainer)
- No `Fixes:`, `Reported-by:`, `Tested-by:`, `Cc:
stable@vger.kernel.org`, or `Link:` tags
- Notable: maintainer sign-off; no syzbot/fuzzer report
### Step 1.3: Body analysis
**Record:**
- **Bug:** `pinctrl_gpio_direction_input/output()` take
`pctldev->mutex`, so direction callbacks can sleep, but the Paris
gpiochip does not set `.can_sleep`. The shared GPIO proxy uses
`gpiod_cansleep()` to choose spinlock vs mutex; with `can_sleep ==
false` it takes a spinlock, then direction setup reaches the pinctrl
mutex → lockdep “sleeping in atomic context” warning.
- **Symptom:** Large kernel warning (lockdep sleep-in-atomic).
- **Root cause:** Redundant pinctrl-layer direction call adds a sleeping
mutex on a chip that should be fast/MMIO; after muxing to GPIO,
direction changes only need register RMW under the driver’s spinlock.
- **Version info:** None in the message.
### Step 1.4: Hidden bug fix?
**Record:** Yes. Although framed as bypassing a layer, this is a real
concurrency bug fix: sleeping mutex taken from a path that must be non-
sleeping.
---
## PHASE 2: DIFF ANALYSIS
### Step 2.1: Inventory
**Record:**
- **File:** `drivers/pinctrl/mediatek/pinctrl-paris.c` only
- **Scope:** ~8 lines changed (1 removed, 5 added, 2 modified)
- **Functions:** `mtk_pmxops`, `mtk_gpio_direction_input()`,
`mtk_gpio_direction_output()`
- **Classification:** Single-file surgical fix
### Step 2.2: Code flow per hunk
**Record:**
1. **`mtk_pmxops`:** Removes `.gpio_set_direction =
mtk_pinmux_gpio_set_direction` so the pinctrl core no longer exposes
this hook.
2. **`mtk_gpio_direction_input()`:** Before:
`pinctrl_gpio_direction_input()` → mutex + `pinmux_gpio_direction()`
→ `mtk_pinmux_gpio_set_direction()`. After: direct
`mtk_pinmux_gpio_set_direction(hw->pctrl, NULL, gpio, true)` — no
pinctrl mutex.
3. **`mtk_gpio_direction_output()`:** Same pattern after
`mtk_gpio_set()`; direct call with `false` for output.
### Step 2.3: Bug mechanism
**Record:**
- **Category:** Synchronization / sleep-in-atomic (lockdep)
- **Mechanism:** `pinctrl_gpio_direction()` in `core.c` does
`mutex_lock(&pctldev->mutex)` before calling the pinmux op. Paris
gpiochip has `can_sleep` unset (false) and uses `mtk_hw_set_value()` →
`mtk_rmw()` under `spinlock_irqsave(&pctl->lock)`. The pinctrl mutex
path is inappropriate for a non-sleeping gpiochip and conflicts with
callers that serialize with a spinlock.
### Step 2.4: Fix quality
**Record:** Obviously correct and minimal. Same underlying function
(`mtk_pinmux_gpio_set_direction`) is invoked; only the mutex wrapper is
removed. Low regression risk; matches the tegra stable backport already
in this tree.
---
## PHASE 3: GIT HISTORY INVESTIGATION
### Step 3.1: Blame
**Record:** Current direction callbacks and `.gpio_set_direction` in
`mtk_pmxops` trace to `5d324e5159d9e` in this stable tree (squashed
history). Paris driver and the `pinctrl_gpio_direction_*` pattern are
present throughout v6.18.x.
### Step 3.2: Fixes: tag
**Record:** N/A — no `Fixes:` tag.
### Step 3.3: Related file history
**Record:** Only one history entry visible for `pinctrl-paris.c` in this
tree. Related sibling issue exists in `pinctrl-mtk-common.c` (common-v1)
with a separate patch series; this Paris commit is standalone.
### Step 3.4: Author context
**Record:** Chen-Yu Tsai (Chromium) has other MediaTek pinctrl work in-
tree. Linus Walleij is the pinctrl maintainer and signed off upstream.
### Step 3.5: Dependencies
**Record:** No prerequisites. `mtk_pinmux_gpio_set_direction()`,
`hw->pctrl`, and `gpiochip_get_data()` all exist in this tree. Applies
standalone.
---
## PHASE 4: MAILING LIST AND EXTERNAL RESEARCH
### Step 4.1: Original discussion
**Record:** v2 posted 2026-05-05 by Chen-Yu Tsai; thread at
[spinics](https://www.spinics.net/lists/kernel/msg6186918.html). CC’d to
MediaTek, GPIO, arm-kernel maintainers. v1 linked in cover letter. Linus
Walleij replied in-thread (per index). `b4 dig -c` could not be used
(commit not in this checkout).
### Step 4.2: Reviewers
**Record:** To: Sean Wang, Matthias Brugger, AngeloGioacchino Del Regno,
Linus Walleij. Maintainer sign-off from Linus Walleij.
### Step 4.3: Bug report
**Record:** No external bugzilla/syzbot link. Author describes
reproduced lockdep warning on Chromebook-class MediaTek hardware.
### Step 4.4: Related patches
**Record:** Companion patch for `pinctrl-mtk-common.c` (common-v1)
exists; not required for this Paris-only fix.
### Step 4.5: Stable list
**Record:** No explicit stable nomination in the Paris v2 post (unlike
tegra fix `ac761e66708d5` which had `Cc: stable@vger.kernel.org`).
---
## PHASE 5: CODE SEMANTIC ANALYSIS
### Step 5.1: Key functions
**Record:** `mtk_gpio_direction_input`, `mtk_gpio_direction_output`,
`mtk_pinmux_gpio_set_direction`, `pinctrl_gpio_direction`,
`mtk_hw_set_value`, `mtk_rmw`.
### Step 5.2: Callers
**Record:** Direction callbacks are reached from gpiolib
(`gpiod_direction_input_nonotify`, `gpiod_direction_output_raw_commit` →
`gpiochip_direction_*`). On Chromebook/MediaTek platforms these GPIOs
are used by regulators, PMICs, USB, display, etc. Shared-GPIO consumers
(when present) call direction while holding their lock.
### Step 5.3: Callees
**Record:** Fixed path calls `mtk_pinmux_gpio_set_direction()` →
`mtk_hw_set_value()` → `mtk_rmw()` with
`spin_lock_irqsave(&pctl->lock)`.
### Step 5.4: Reachability
**Record:** Reachable from userspace-driven device operations and from
kernel drivers requesting GPIO direction changes. The problematic path
is direction change on a non-`can_sleep` chip while a spinlock-holding
caller (e.g. gpio-shared-proxy on newer kernels) invokes
`gpiod_direction_*`.
### Step 5.5: Similar patterns
**Record:** `ac761e66708d5` (“gpio: tegra: do not call pinctrl for GPIO
direction”) is already in this v6.18.43 tree — same bug class,
explicitly backported to stable with `Cc: stable@vger.kernel.org`.
`pinctrl-mtk-common.c` and `pinctrl-moore.c` still use
`pinctrl_gpio_direction_*` but are out of scope for this commit.
---
## PHASE 6: CROSS-REFERENCE AGAINST LOCAL TREE (v6.18.43)
### Step 6.1: Buggy code present?
**Record:** **Yes.** `git describe HEAD` → `v6.18.43`; `Makefile` →
6.18.43. Current code at lines 889 and 901 still calls
`pinctrl_gpio_direction_input/output()`. `.gpio_set_direction` is set in
`mtk_pmxops` at line 774. `can_sleep` is not set in
`mtk_build_gpiochip()`.
### Step 6.2: Backport complications
**Record:** Clean apply expected — small, localized change; no
structural conflicts observed.
### Step 6.3: Related fixes already present?
**Record:** Tegra equivalent fix `ac761e66708d5` is in HEAD. This Paris
fix is **not** yet applied. No duplicate fix found.
**Important nuance:** `gpio-shared-proxy` was merged in **6.19**, not
6.18. It is **not** present in this v6.18.43 tree (`grep` found no
`GPIO_SHARED`, `gpio-shared-proxy`, or `gpio_shared_proxy`). The
commit’s primary trigger is therefore not available in 6.18.43 today,
but the underlying mutex-in-non-sleeping-callback bug still exists and
matches the tegra stable backport rationale.
---
## PHASE 7: SUBSYSTEM CONTEXT
### Step 7.1: Subsystem and criticality
**Record:** `drivers/pinctrl/mediatek/` — **IMPORTANT** (ARM64 SoC pin
control; affects Chromebooks, tablets, embedded MediaTek Paris
platforms: MT8186, MT8188, MT8192, MT8195, MT8196, etc.).
### Step 7.2: Activity
**Record:** Active subsystem with many Paris-based SoC drivers in
`Kconfig`.
---
## PHASE 8: IMPACT AND RISK
### Step 8.1: Who is affected
**Record:** Users of MediaTek Paris pinctrl/GPIO on affected SoCs
(CONFIG_PINCTRL_MTK_PARIS and selected SoC drivers). Not universal, but
significant for ChromeOS/Chromebook and embedded MTK platforms.
### Step 8.2: Trigger conditions
**Record:** GPIO direction change on a Paris pin after it is muxed to
GPIO, when called from a context expecting non-sleeping behavior
(notably shared-GPIO proxy on 6.19+; tegra stable commit documents the
same class on 6.18). Normal process-context `gpiod_direction_*` works
but still incorrectly takes a sleeping mutex on a chip advertised as
non-sleeping.
### Step 8.3: Failure mode severity
**Record:** Lockdep “sleeping in atomic context” / potential real
deadlock or oops under contention. **Severity: HIGH** (not data
corruption, but serious stability warning and potential hang).
### Step 8.4: Risk-benefit
**Record:**
- **Benefit:** HIGH for affected platforms; aligns with accepted tegra
stable fix in the same tree.
- **Risk:** VERY LOW — 8-line change, same hardware operation, removes
redundant mutex.
- **Ratio:** Strong benefit, minimal risk.
---
## PHASE 9: FINAL SYNTHESIS
### Step 9.1: Evidence summary
**FOR backport:**
- Real concurrency bug (sleeping mutex in non-sleeping gpiochip
callback)
- Small, surgical, maintainer-reviewed fix
- Buggy code confirmed present in v6.18.43
- Same pattern as tegra fix already backported to this tree
(`ac761e66708d5`)
- Affects widely deployed MediaTek Paris SoCs
- Direct call preserves semantics while removing incorrect mutex
**AGAINST backport:**
- `gpio-shared-proxy` (the described trigger) is not in v6.18.43 (landed
in 6.19)
- No `Cc: stable` tag on the Paris patch
- Common-v1 (`pinctrl-mtk-common.c`) has the same pattern but is a
separate commit
**Unresolved:**
- Exact upstream commit SHA not in this checkout (candidate evaluation
only)
- Could not fetch full Linus Walleij review reply (wrong spinics message
ID)
### Step 9.2: Stable rules checklist
1. Obviously correct and tested? **PASS** — same function, mutex
removed; maintainer SOB; author reproduced warning.
2. Fixes a real bug? **PASS** — lockdep sleep-in-atomic on direction
change.
3. Important issue? **PASS** — stability / lockdep, HIGH severity.
4. Small and contained? **PASS** — 1 file, ~8 lines.
5. No new features/APIs? **PASS** — behavior correction only.
6. Can apply to local tree? **PASS** — code exists, no dependencies.
### Step 9.3: Exception category
**Record:** None (not device ID, quirk, DT, build, or docs). Standard
driver bug fix.
### Step 9.4: Decision rationale
This tree (v6.18.43) still has Paris GPIO direction callbacks routing
through `pinctrl_gpio_direction_*`, which takes the pinctrl mutex on a
gpiochip that does not set `can_sleep` and whose register access uses a
spinlock. That is incorrect and matches the tegra direction fix already
accepted into this same stable series. Even though `gpio-shared-proxy`
is not in 6.18, the underlying bug is present and the fix is minimal,
obviously correct, and low-risk. Chromebook/MediaTek users benefit, and
the change is consistent with stable maintainer practice for this bug
class.
---
## Verification
- [Phase 1] Parsed subject, tags, body; no Fixes/Reported-by/Cc:stable
- [Phase 2] Diff: 1 file, `mtk_gpio_direction_*` + `mtk_pmxops`; mutex-
bypass fix verified in `core.c` and `pinctrl-paris.c`
- [Phase 3] `git blame` lines 887–902, 769–776 → present in v6.18.43; no
Fixes tag; standalone (no deps)
- [Phase 4] WebFetch spinics v2 thread; b4 dig requires commit in tree
(N/A); gpio-shared-proxy confirmed 6.19+ via web search
- [Phase 5] Traced `pinctrl_gpio_direction()` → `mutex_lock`;
`mtk_hw_set_value()` → `spin_lock_irqsave`
- [Phase 6] `git describe HEAD` → v6.18.43; buggy code at lines 774,
889, 901; `hw->pctrl` in `pinctrl-mtk-common-v2.h:292`; tegra fix
`ac761e66708d5` in HEAD
- [Phase 6] `grep` — no `gpio-shared-proxy` / `GPIO_SHARED` in tree
- [Phase 7] Paris used by multiple MTK SoCs in `Kconfig`
- [Phase 8] Failure mode: lockdep sleep-in-atomic, HIGH severity
- [UNVERIFIED] Full text of Linus Walleij review reply not retrieved
**YES**Those three background `git log -S "gpio_shared_proxy"` searches
didn’t finish (they timed out or were killed on this large tree), so
they didn’t add anything new.
That doesn’t change the conclusion: `gpio_shared_proxy` / `gpio-shared-
proxy` isn’t in this v6.18.43 checkout — that was already confirmed with
targeted `grep` and the 6.19 merge history. The Paris pinctrl fix should
still be backported to this tree.
**YES**
drivers/pinctrl/mediatek/pinctrl-paris.c | 8 +++++---
1 file changed, 5 insertions(+), 3 deletions(-)
diff --git a/drivers/pinctrl/mediatek/pinctrl-paris.c b/drivers/pinctrl/mediatek/pinctrl-paris.c
index 6bf37d8085fae..23f04b24fd65e 100644
--- a/drivers/pinctrl/mediatek/pinctrl-paris.c
+++ b/drivers/pinctrl/mediatek/pinctrl-paris.c
@@ -771,7 +771,6 @@ static const struct pinmux_ops mtk_pmxops = {
.get_function_name = mtk_pmx_get_func_name,
.get_function_groups = mtk_pmx_get_func_groups,
.set_mux = mtk_pmx_set_mux,
- .gpio_set_direction = mtk_pinmux_gpio_set_direction,
.gpio_request_enable = mtk_pinmux_gpio_request_enable,
};
@@ -886,19 +885,22 @@ static int mtk_gpio_set(struct gpio_chip *chip, unsigned int gpio, int value)
static int mtk_gpio_direction_input(struct gpio_chip *chip, unsigned int gpio)
{
- return pinctrl_gpio_direction_input(chip, gpio);
+ struct mtk_pinctrl *hw = gpiochip_get_data(chip);
+
+ return mtk_pinmux_gpio_set_direction(hw->pctrl, NULL, gpio, true);
}
static int mtk_gpio_direction_output(struct gpio_chip *chip, unsigned int gpio,
int value)
{
+ struct mtk_pinctrl *hw = gpiochip_get_data(chip);
int ret;
ret = mtk_gpio_set(chip, gpio, value);
if (ret)
return ret;
- return pinctrl_gpio_direction_output(chip, gpio);
+ return mtk_pinmux_gpio_set_direction(hw->pctrl, NULL, gpio, false);
}
static int mtk_gpio_to_irq(struct gpio_chip *chip, unsigned int offset)
--
2.53.0
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH AUTOSEL 6.18-6.12] pinctrl: renesas: rzg2l: Handle RZ/V2H(P) IOLH configuration in PM cache
[not found] <20260831133314.4125787-1-sashal@kernel.org>
` (6 preceding siblings ...)
2026-08-31 13:27 ` [PATCH AUTOSEL 6.18] pinctrl: mediatek: paris: bypass pinctrl GPIO layer in set GPIO direction Sasha Levin
@ 2026-08-31 13:28 ` Sasha Levin
2026-08-31 13:28 ` [PATCH AUTOSEL 6.18-5.10] gpio: pisosr: Read "ngpios" as u32 Sasha Levin
` (3 subsequent siblings)
11 siblings, 0 replies; 12+ messages in thread
From: Sasha Levin @ 2026-08-31 13:28 UTC (permalink / raw)
To: patches, stable
Cc: Lad Prabhakar, Geert Uytterhoeven, Sasha Levin, linusw,
linux-renesas-soc, linux-gpio, linux-kernel
From: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
[ Upstream commit d0fc9f8eb2ce55eb00dbfdc0f19c844df5aee5b8 ]
Include PIN_CFG_IOLH_RZV2H in the IOLH capability checks when saving
and restoring pin configuration registers.
On RZ/V2H(P), RZ/V2N, and RZ/G3E, the IOLH configuration is defined by
the PIN_CFG_IOLH_RZV2H capability. The previous implementation did not
account for this, causing the IOLH registers to be skipped during PM
save/restore.
Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be>
Link: https://patch.msgid.link/20260413182456.811543-4-prabhakar.mahadev-lad.rj@bp.renesas.com
Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
LLM Generated explanations, may be completely bogus:
## Phase 1: Commit Message Forensics
### Step 1.1: Subject line
**Record:** `[pinctrl: renesas: rzg2l]` `[Handle]` — Include RZ/V2H(P)
IOLH capability in PM register save/restore checks.
### Step 1.2: Commit tags
**Record:**
- **Signed-off-by:** Lad Prabhakar `<prabhakar.mahadev-
lad.rj@bp.renesas.com>` (author)
- **Reviewed-by:** Geert Uytterhoeven `<geert+renesas@glider.be>`
(Renesas/pinctrl maintainer)
- **Link:**
https://patch.msgid.link/20260413182456.811543-4-prabhakar.mahadev-
lad.rj@bp.renesas.com
- **Signed-off-by:** Geert Uytterhoeven (maintainer tree)
- No Fixes:, Reported-by:, Tested-by:, Cc: stable@, or syzbot tags
- Notable: Reviewed by subsystem maintainer; part of v2 5-patch PM
caching series (patch 3/5)
### Step 1.3: Body analysis
**Record:**
- **Bug:** PM suspend/resume skips IOLH registers on RZ/V2H(P), RZ/V2N,
and RZ/G3E because those SoCs use `PIN_CFG_IOLH_RZV2H` instead of
`PIN_CFG_IOLH_A/B/C`.
- **Symptom:** Output-impedance/drive-strength (IOLH) not saved on
suspend or restored on resume; pins revert to wrong electrical
settings after S2RAM.
- **Root cause:** `has_iolh` capability check omits
`PIN_CFG_IOLH_RZV2H`.
### Step 1.4: Hidden bug fix?
**Record:** No — this is an explicit PM suspend/resume bug fix, not
disguised cleanup.
---
## Phase 2: Diff Analysis
### Step 2.1: Inventory
**Record:**
- **File:** `drivers/pinctrl/renesas/pinctrl-rzg2l.c` (+2 lines net in
submitted diff; full v2 patch touches 2 functions)
- **Functions:** `rzg2l_pinctrl_pm_setup_dedicated_regs()` (shown in
candidate diff); v2 submission also changed
`rzg2l_pinctrl_pm_setup_regs()` (author later agreed to drop that hunk
per maintainer review)
- **Scope:** Single-file, surgical (2-line logical change)
### Step 2.2: Code flow
**Record:**
- **Before:** `has_iolh` true only for `PIN_CFG_IOLH_A|B|C`; dedicated
pins with only `PIN_CFG_IOLH_RZV2H` skip IOLH cache read/write.
- **After:** `PIN_CFG_IOLH_RZV2H` included; IOLH registers saved on
suspend and restored on resume for affected dedicated pins.
- **Path:** System suspend/resume via `rzg2l_pinctrl_suspend_noirq()` /
`rzg2l_pinctrl_resume_noirq()` →
`rzg2l_pinctrl_pm_setup_dedicated_regs()`.
### Step 2.3: Bug mechanism
**Record:** **Logic/correctness fix** — incomplete capability bitmask
causes PM cache to omit IOLH register save/restore for a whole class of
pins on newer Renesas SoCs.
### Step 2.4: Fix quality
**Record:** Obviously correct (adds the missing flag already used
everywhere else in the driver). Minimal risk; no API, locking, or
structural changes.
---
## Phase 3: Git History Investigation
### Step 3.1: Blame
**Record:** Buggy `has_iolh` lines at 3009 and 3097 trace to the PM
caching code (blame shows `19eef1d98eeda` in this shallow stable tree).
`PIN_CFG_IOLH_RZV2H` (line 65) is present in this tree.
### Step 3.2: Fixes: tag
**Record:** N/A — no Fixes: tag.
### Step 3.3: Related file history
**Record:** Same PM series already partially backported to this tree:
- `8d1c6b603327b` — SMT register cache (patch 1/5, same series)
- `509d342d02fff`, `c4cfa8ee77374` — earlier IOLH/IEN/PUPD/SMT PM fixes
This IOLH fix is **not** yet in the tree.
### Step 3.4: Author context
**Record:** Lad Prabhakar is the RZ/G2L pinctrl driver author/maintainer
contributor; Geert Uytterhoeven is Renesas maintainer and reviewed the
series.
### Step 3.5: Dependencies
**Record:** Standalone — only adds a flag to an existing bitmask. Does
not require patches 2/4/5 (SR/NOD/PUPD) to function; applies cleanly to
current `rzg2l_pinctrl_pm_setup_dedicated_regs()` at line 3097.
---
## Phase 4: Mailing List and External Research
### Step 4.1: Original discussion
**Record:** Thread fetched via `b4 mbox` from lore (16 messages). Patch
3/5 reviewed by Geert Uytterhoeven. Geert noted `PIN_CFG_IOLH_RZV2H` may
only matter for dedicated pins in `pm_setup_regs`; author agreed to drop
that hunk. Final fix targets `rzg2l_pinctrl_pm_setup_dedicated_regs()`.
### Step 4.2: Reviewers
**Record:** Geert Uytterhoeven (maintainer), Linus Walleij CC'd on cover
letter; linux-renesas-soc list.
### Step 4.3: Bug reports
**Record:** No external bug report or syzbot link; issue identified
during PM caching review/fix series.
### Step 4.4: Series context
**Record:** v2 0/5 cover letter describes 5 related PM cache fixes.
Patch 1 (SMT) already in this 6.18.43 tree; patches 2/4/5 (SR, NOD,
dedicated PUPD) are separate and not prerequisites for this IOLH bitmask
fix.
### Step 4.5: Stable list
**Record:** No stable@ discussion found in thread.
---
## Phase 5: Code Semantic Analysis
### Step 5.1: Key functions
**Record:** `rzg2l_pinctrl_pm_setup_dedicated_regs()`, called from
`rzg2l_pinctrl_suspend_noirq()` and `rzg2l_pinctrl_resume_noirq()`.
### Step 5.2: Callers
**Record:** PM suspend/resume noirq path on every system sleep for
affected pinctrl devices.
### Step 5.3: Callees
**Record:** `RZG2L_PCTRL_REG_ACCESS32()` macro for hardware IOLH/IEN
register read (suspend) or write (resume).
### Step 5.4: Reachability
**Record:** Triggered on every S2RAM cycle on boards using
`renesas,r9a09g047-pinctrl` (RZ/G3E), `renesas,r9a09g056-pinctrl`
(RZ/V2H), or `renesas,r9a09g057-pinctrl` (RZ/V2HP). Dedicated pins
include Ethernet, SD, XSPI, SCIF, etc.
### Step 5.5: Similar patterns
**Record:** Same `has_iolh` bitmask omission exists at line 3009 in
`rzg2l_pinctrl_pm_setup_regs()` for GPIO port pins using
`RZV2H_MPXED_PIN_FUNCS` (which includes `PIN_CFG_IOLH_RZV2H`). This
commit (per review) does not fix that path; dedicated-pin path is the
confirmed target.
---
## Phase 6: Cross-Reference Against Local Tree (6.18.43)
### Step 6.1: Buggy code present?
**Record:** **Yes.** Line 3097 in
`rzg2l_pinctrl_pm_setup_dedicated_regs()`:
```3097:3097:drivers/pinctrl/renesas/pinctrl-rzg2l.c
has_iolh = !!(caps & (PIN_CFG_IOLH_A | PIN_CFG_IOLH_B |
PIN_CFG_IOLH_C));
```
`PIN_CFG_IOLH_RZV2H` is defined (line 65) and used extensively in
`rzv2h_dedicated_pins` and `rzg3e_dedicated_pins` (e.g., lines 2233+,
2370+). Affected SoC compatibles are registered (lines 3470–3479).
### Step 6.2: Backport complications
**Record:** Clean apply — single-line change at line 3097. No SR/NOD
infrastructure required (those are separate series patches not in this
tree).
### Step 6.3: Related fixes already present?
**Record:** SMT PM cache fix from same series (`8d1c6b603327b`) is
already in tree. This IOLH fix is the logical next piece.
---
## Phase 7: Subsystem Context
### Step 7.1: Subsystem criticality
**Record:** `drivers/pinctrl/renesas/` — **PERIPHERAL** (platform-
specific), but suspend/resume correctness is critical for embedded
products using these SoCs.
### Step 7.2: Activity
**Record:** Active PM fix series; multiple related backports already
landed in 6.18.y.
---
## Phase 8: Impact and Risk Assessment
### Step 8.1: Who is affected
**Record:** Users of RZ/G3E (r9a09g047), RZ/V2H (r9a09g056), RZ/V2HP
(r9a09g057) who use system suspend/resume. Driver-specific, but
dedicated pins cover critical peripherals.
### Step 8.2: Trigger conditions
**Record:** Every S2RAM suspend/resume cycle on affected hardware.
Requires `CONFIG_PINCTRL` + matching DT compatible. Not userspace-
triggerable directly, but normal laptop/embedded suspend path.
### Step 8.3: Failure severity
**Record:** Wrong pin drive strength/impedance after resume → peripheral
malfunction (Ethernet, SD, XSPI flash, UART), potential bus errors or
silent data corruption on high-speed interfaces. **Severity: MEDIUM-
HIGH** (hardware misconfiguration, not kernel oops).
### Step 8.4: Risk-benefit
**Record:** **Benefit: HIGH** for affected embedded users doing
suspend/resume. **Risk: VERY LOW** (2-line bitmask fix, maintainer-
reviewed). Ratio strongly favors backport.
---
## Phase 9: Final Synthesis
### Step 9.1: Evidence summary
**FOR backport:**
- Real suspend/resume bug on shipping Renesas SoCs in this tree
- Maintainer-reviewed, obviously correct, minimal diff
- Same PM series already partially backported (SMT fix in 6.18.43)
- Affects critical dedicated pins (network, storage, flash buses)
- Buggy code and `PIN_CFG_IOLH_RZV2H` both present in 6.18.43
**AGAINST backport:**
- Narrow hardware scope (3 SoC compatibles)
- No crash/oops — functional/hardware issue after resume
- GPIO port-pin IOLH path (line 3009) may remain unfixed per maintainer
review (out of scope for this commit)
**Unresolved:** Whether port-pin IOLH via
`rzg2l_pinctrl_pm_setup_regs()` also needs the same fix (Geert/author
agreed to omit; separate issue).
### Step 9.2: Stable rules checklist
1. Obviously correct and tested? **PASS** — bitmask addition; Reviewed-
by maintainer; series patch 1 tested by multiple Tested-by on SMT
patch
2. Fixes real bug affecting users? **PASS** — IOLH not saved/restored on
suspend/resume
3. Important issue? **PASS** — suspend/resume hardware misconfiguration
on critical pins (MEDIUM-HIGH)
4. Small and contained? **PASS** — 2 lines, one function
5. No new features or APIs? **PASS**
6. Can apply to local tree? **PASS** — applies cleanly at line 3097
### Step 9.3: Exception category
**Record:** N/A — standard bug fix, not device-ID/quirk/build fix.
### Step 9.4: Decision rationale
For **Linux 6.18.43**, this commit should be backported. The tree
already has RZ/V2H and RZ/G3E pinctrl support with extensive
`PIN_CFG_IOLH_RZV2H` dedicated-pin tables and active PM suspend/resume,
but the PM cache path omits that capability flag. After S2RAM, dedicated
function pins (Ethernet, SD, XSPI, etc.) lose their output-impedance
settings. The fix is trivial, maintainer-reviewed, and consistent with
the SMT PM cache fix already in this stable tree.
---
## Verification
- **[Phase 1]** Parsed subject, tags, body from commit message and local
mbx
- **[Phase 2]** Read diff and current code at lines 3009, 3097,
3179–3243
- **[Phase 3]** `git describe HEAD` → v6.18.43; `git log --oneline -20
-- drivers/pinctrl/renesas/pinctrl-rzg2l.c`; `git blame` on lines
3009/3097; confirmed `8d1c6b603327b` (SMT fix from same series) in
tree
- **[Phase 4]** `b4 mbox` fetched 16-message lore thread; Geert review
noted dedicated-pin scope; no stable@ nomination found
- **[Phase 5]** Traced call chain:
`rzg2l_pinctrl_suspend_noirq`/`resume_noirq` →
`rzg2l_pinctrl_pm_setup_dedicated_regs`; verified
`rzv2h_dedicated_pins`/`rzg3e_dedicated_pins` use
`PIN_CFG_IOLH_RZV2H`; verified SoC compatibles at lines 3470–3479
- **[Phase 6]** Confirmed buggy line 3097 present; `PIN_CFG_IOLH_RZV2H`
defined at line 65; fix not yet applied; clean apply expected
- **[Phase 7]** Identified Renesas pinctrl driver subsystem
- **[Phase 8]** Assessed suspend/resume trigger and MEDIUM-HIGH hardware
impact
**YES**
drivers/pinctrl/renesas/pinctrl-rzg2l.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/drivers/pinctrl/renesas/pinctrl-rzg2l.c b/drivers/pinctrl/renesas/pinctrl-rzg2l.c
index e8cc83029db33..ab8d64a14dd0a 100644
--- a/drivers/pinctrl/renesas/pinctrl-rzg2l.c
+++ b/drivers/pinctrl/renesas/pinctrl-rzg2l.c
@@ -3094,7 +3094,8 @@ static void rzg2l_pinctrl_pm_setup_dedicated_regs(struct rzg2l_pinctrl *pctrl, b
}
/* And apply them in a single shot. */
- has_iolh = !!(caps & (PIN_CFG_IOLH_A | PIN_CFG_IOLH_B | PIN_CFG_IOLH_C));
+ has_iolh = !!(caps & (PIN_CFG_IOLH_A | PIN_CFG_IOLH_B |
+ PIN_CFG_IOLH_C | PIN_CFG_IOLH_RZV2H));
has_ien = !!(caps & PIN_CFG_IEN);
pincnt = hweight8(FIELD_GET(RZG2L_SINGLE_PIN_BITS_MASK, cfg));
--
2.53.0
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH AUTOSEL 6.18-5.10] gpio: pisosr: Read "ngpios" as u32
[not found] <20260831133314.4125787-1-sashal@kernel.org>
` (7 preceding siblings ...)
2026-08-31 13:28 ` [PATCH AUTOSEL 6.18-6.12] pinctrl: renesas: rzg2l: Handle RZ/V2H(P) IOLH configuration in PM cache Sasha Levin
@ 2026-08-31 13:28 ` Sasha Levin
2026-08-31 13:29 ` [PATCH AUTOSEL 6.18-5.10] gpio: dwapb: Mask interrupts at hardware initialization Sasha Levin
` (2 subsequent siblings)
11 siblings, 0 replies; 12+ messages in thread
From: Sasha Levin @ 2026-08-31 13:28 UTC (permalink / raw)
To: patches, stable
Cc: Rob Herring (Arm), Bartosz Golaszewski, Sasha Levin, linusw, brgl,
linux-gpio, linux-kernel
From: "Rob Herring (Arm)" <robh@kernel.org>
[ Upstream commit 4910aa198d25e5d1067236560ba34ab12bccc677 ]
The generic "ngpios" property is encoded as a normal uint32 cell. The
pisosr driver stores it in the gpio_chip field, but reading it with a
u16 helper does not match the DT property encoding.
Read "ngpios" as u32 and keep the existing assignment to the chip
field.
Assisted-by: Codex:gpt-5-5
Signed-off-by: Rob Herring (Arm) <robh@kernel.org>
Link: https://patch.msgid.link/20260612215216.1887485-1-robh@kernel.org
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
LLM Generated explanations, may be completely bogus:
## Phase 1: Commit Message Forensics
### Step 1.1: Subject Line
**Record:** `[gpio: pisosr]` `[Read]` — Read the device-tree `ngpios`
property with the correct cell width (`u32` instead of `u16`).
### Step 1.2: Tags
**Record:**
- **Assisted-by:** Codex:gpt-5-5
- **Signed-off-by:** Rob Herring (Arm) \<robh@kernel.org\>
- **Link:**
https://patch.msgid.link/20260612215216.1887485-1-robh@kernel.org
- **Signed-off-by:** Bartosz Golaszewski
\<bartosz.golaszewski@oss.qualcomm.com\> (GPIO maintainer)
- No Fixes:, Reported-by:, Tested-by:, Reviewed-by:, Cc:
stable@vger.kernel.org
- Notable: authored/assisted by the device-tree maintainer; merged by
GPIO subsystem maintainer
### Step 1.3: Body Analysis
**Record:**
- **Bug:** Generic `ngpios` is a standard `u32` DT cell; `gpio-pisosr`
read it via `of_property_read_u16()`.
- **Symptom:** Wrong `ngpio` when `ngpios` is present in DT; chip field
type is `u16`, but the property encoding is `u32`.
- **Root cause:** Size/endian mismatch between DT encoding and OF read
helper.
- **Fix:** Read into temporary `u32`, assign to `gpio->chip.ngpio` only
on success.
### Step 1.4: Hidden Bug Fix?
**Record:** Yes. Despite neutral wording, this is a correctness /
memory-safety bug fix, not style cleanup.
---
## Phase 2: Diff Analysis
### Step 2.1: Inventory
**Record:**
- **File:** `drivers/gpio/gpio-pisosr.c` (+3 / -1 net)
- **Function:** `pisosr_gpio_probe()`
- **Scope:** Single-file surgical fix
### Step 2.2: Code Flow Change
**Record:**
- **Before:** `of_property_read_u16(dev->of_node, "ngpios",
&gpio->chip.ngpio);` (return ignored). `buffer_size` computed
immediately after from `gpio->chip.ngpio`.
- **After:** `u32 ngpios`; `if (!of_property_read_u32(..., &ngpios))
gpio->chip.ngpio = ngpios;`. On missing property, default
`DEFAULT_NGPIO` (8) is preserved.
### Step 2.3: Bug Mechanism
**Record:** **Category:** DT property parsing / memory safety (buffer
underrun → OOB)
Verified mechanism:
1. DT stores `ngpios = <N>` as a 4-byte big-endian `u32`.
2. `of_property_read_u16()` requires `prop->length >= 2` with `max=0`
(no upper bound), so it **succeeds** on a 4-byte property.
3. It reads the **first** 16 bits (`be16_to_cpup` at offset 0). For any
normal `N < 65536`, those high 16 bits are zero.
Python simulation confirmed:
- `ngpios=8` → u32 bytes `00000008` → u16 read = **0**
- Same for 16, 24, 32
4. With `ngpios` present in DT, `gpio->chip.ngpio` becomes **0**.
5. `buffer_size = DIV_ROUND_UP(0, 8) = 0`; `devm_kzalloc(dev, 0, ...)`
yields `ZERO_SIZE_PTR`.
6. Later `devm_gpiochip_add_data()` → `gpiochip_get_ngpios()` sees
`gc->ngpio == 0`, re-reads `ngpios` as `u32`, and restores the
correct line count for registration — but **`buffer_size` and
`buffer` are never recomputed**.
7. GPIO access (`pisosr_gpio_get()` → `gpio->buffer[offset / 8]`) can
then read/write through a zero-sized buffer → **out-of-bounds
access**.
When `ngpios` is **absent**, `of_property_read_u16()` fails, `ngpio`
stays at template default 8, and the driver works.
### Step 2.4: Fix Quality
**Record:** Obviously correct; matches every other GPIO driver in-tree
(`gpio-uniphier.c`, `gpio-aspeed.c`, `gpio-em.c`, etc.). Minimal diff.
Regression risk very low.
---
## Phase 3: Git History Investigation
### Step 3.1: Blame
**Record:** Buggy `of_property_read_u16()` introduced in `df6df93c8a73f`
(2016-01-25, "gpio: Add driver for SPI serializers"). Present throughout
6.18.y.
### Step 3.2: Fixes: Tag
**Record:** N/A — no Fixes: tag.
### Step 3.3: Related File History
**Record:** Recent `gpio-pisosr.c` commits are cleanups
(`devm_mutex_init`, remove `direction_output`,
`devm_gpiochip_add_data`). No related ngpios fix already present.
Standalone one-patch fix.
### Step 3.4: Author Context
**Record:** Rob Herring is DT maintainer. Bartosz Golaszewski is GPIO
maintainer. Patch is subsystem-appropriate.
### Step 3.5: Dependencies
**Record:** None. No series markers. Applies standalone to existing
`pisosr_gpio_probe()`.
---
## Phase 4: Mailing List and External Research
### Step 4.1–4.5
**Record:**
- `b4 dig -c 2732ea8c16b7b`: commit hash not in local repo (blob only
from diff index); no lore match.
- Link URL and lore.kernel.org blocked by Anubis bot protection —
**UNVERIFIED** for review-thread content, stable nominations, or NAKs.
- No syzbot/bugzilla references in commit message.
---
## Phase 5: Code Semantic Analysis
### Step 5.1: Key Functions
**Record:** `pisosr_gpio_probe()`, indirectly `pisosr_gpio_get()`,
`pisosr_gpio_refresh()`.
### Step 5.2: Callers
**Record:** `pisosr_gpio_probe()` via SPI driver registration at
boot/module load. GPIO ops invoked from gpiolib when consumers read
lines.
### Step 5.3: Callees
**Record:** `of_property_read_u16/u32`, `devm_kzalloc`,
`devm_gpiochip_add_data` → `gpiochip_get_ngpios`.
### Step 5.4: Reachability
**Record:** Triggered when a board DT node has `compatible = "pisosr-
gpio"` **and** an explicit `ngpios` property. GPIO reads from userspace
or kernel consumers reach the buggy buffer path.
### Step 5.5: Similar Patterns
**Record:** `gpio-pisosr.c` is the **only** GPIO driver using
`of_property_read_u16()` for `ngpios`. All others use
`of_property_read_u32()`.
---
## Phase 6: Cross-Reference Against Local Tree (v6.18.44)
### Step 6.1: Buggy Code Present?
**Record:** **YES.** Local tree at `v6.18.44-1-g2736c32da98b9` still
has:
```123:123:drivers/gpio/gpio-pisosr.c
of_property_read_u16(dev->of_node, "ngpios", &gpio->chip.ngpio);
```
Bug present since driver addition in 2016.
### Step 6.2: Backport Complications
**Record:** Clean apply expected — 3-line hunk in one function, no
structural conflicts.
### Step 6.3: Related Fixes Already Present?
**Record:** None found for this issue.
### In-tree DTS usage
**Record:** Five `pisosr-gpio` nodes exist (BeagleBone AI, AM57xx IDK,
AM437x IDK, AM335x ICEv2, VF610 BK4). **None specify `ngpios`** — all
rely on the driver default of 8. So mainline shipped boards are not
currently broken, but the binding allows `ngpios` (default 8, max 32 per
`pisosr-gpio.yaml`).
---
## Phase 7: Subsystem Context
### Step 7.1
**Record:** `drivers/gpio/gpio-pisosr.c` — GPIO driver for SPI parallel-
in/serial-out shift registers. **Criticality: PERIPHERAL** (niche
industrial/embedded hardware).
### Step 7.2
**Record:** Driver is mature (since 2016); recent activity is
maintenance only.
---
## Phase 8: Impact and Risk Assessment
### Step 8.1: Who Is Affected
**Record:** Users of `pisosr-gpio` hardware who include an explicit
`ngpios` property in device tree. Config-specific / board-specific.
### Step 8.2: Trigger Conditions
**Record:** `ngpios = <N>` in DT for a `pisosr-gpio` node. Uncommon
today (no in-tree examples), but valid per binding. Not userspace-
triggerable directly; kernel GPIO access after probe triggers OOB.
### Step 8.3: Failure Mode Severity
**Record:** Wrong zero-sized internal buffer while gpiochip may register
the correct line count → **OOB on GPIO read** → potential
oops/corruption. **Severity: HIGH** when triggered; **latent** on
current in-tree DTS.
### Step 8.4: Risk-Benefit
**Record:**
- **Benefit:** Fixes real DT-binding compliance bug with memory-safety
consequences; enables correct custom board DT.
- **Risk:** Very low — 3-line change, matches established driver
pattern.
- **Ratio:** Favorable for backport despite niche hardware.
---
## Phase 9: Final Synthesis
### Step 9.1: Evidence Summary
**FOR:**
- Verified bug: `u16` read of `u32` `ngpios` yields 0 for all normal
values
- Leads to zero-sized buffer + possible OOB despite correct gpiochip
registration
- Bug since 2016; fix not yet in 6.18.y
- Trivial, obviously correct; DT + GPIO maintainers involved
- DT binding documents `ngpios` as valid optional property
**AGAINST:**
- No in-tree DTS currently uses `ngpios` on pisosr nodes
- No fuzzer/user crash reports
- Peripheral driver; default path (no `ngpios`) works
- `gpiochip_get_ngpios()` partially masks the gpio-count symptom
**UNVERIFIED:**
- Mailing list review discussion and any explicit stable nomination
### Step 9.2: Stable Rules Checklist
1. Obviously correct and tested? **PASS** — mechanism verified in OF
code; pattern used elsewhere; maintainer-authored.
2. Fixes a real bug? **PASS** — incorrect DT parsing when `ngpios` is
present.
3. Important issue? **PASS** — OOB/memory safety when triggered;
functional breakage for valid DT.
4. Small and contained? **PASS** — 4 lines in one file.
5. No new features/APIs? **PASS** — behavior correction only.
6. Can apply to local tree? **PASS** — buggy code confirmed present in
v6.18.44.
### Step 9.3: Exception Category
**Record:** Device tree fix for existing driver/hardware — qualifies
under DT-update exception.
### Step 9.4: Decision Rationale
This is a long-standing DT property encoding bug that silently breaks
any board specifying `ngpios` for `pisosr-gpio`: the driver allocates a
zero-byte buffer while registering the correct GPIO count via gpiolib
fallback, creating an OOB path on GPIO access. The fix is minimal,
matches every other GPIO driver, and carries negligible regression risk.
Current mainline DTS avoids the bug by omitting `ngpios`, but the
binding permits it and custom boards can hit this today.
---
## Verification
- **[Phase 1]** Parsed subject, tags, body from provided commit message
- **[Phase 2]** Diff analysis: 3-line probe() change; verified
`of_property_read_u16` implementation in `drivers/of/property.c`
(min=2, max=0, reads first be16)
- **[Phase 2]** Python simulation: u32 `ngpios` values 8/16/24/32 all
read as 0 via u16
- **[Phase 2]** Confirmed `struct gpio_chip.ngpio` is `u16` in
`include/linux/gpio/driver.h`
- **[Phase 3]** `git blame`: buggy line from `df6df93c8a73f` (2016)
- **[Phase 3]** `git log --oneline -20 -- drivers/gpio/gpio-pisosr.c`:
no prior ngpios fix
- **[Phase 3]** `git grep`: only `gpio-pisosr.c` uses
`of_property_read_u16` for `ngpios`
- **[Phase 4]** `b4 dig -c 2732ea8c16b7b`: no result (commit not in
repo) — **UNVERIFIED** lore thread
- **[Phase 4]** WebFetch patch.msgid.link and lore.kernel.org: blocked
by Anubis — **UNVERIFIED**
- **[Phase 5]** Read `gpiochip_get_ngpios()` in
`drivers/gpio/gpiolib.c`: re-reads u32 when `gc->ngpio==0`, does not
fix driver buffer
- **[Phase 5]** Traced probe order: buffer allocated before
`devm_gpiochip_add_data()`
- **[Phase 6]** `git describe HEAD`: `v6.18.44-1-g2736c32da98b9`;
Makefile confirms 6.18.44
- **[Phase 6]** Read current `drivers/gpio/gpio-pisosr.c`: still has
buggy `of_property_read_u16`
- **[Phase 6]** `grep pisosr-gpio` in `arch/arm/boot/dts/`: 5 nodes,
none with `ngpios` property
- **[Phase 6]** Read `Documentation/devicetree/bindings/gpio/pisosr-
gpio.yaml`: `ngpios` optional, default 8, max 32
- **[Phase 8]** Assessed failure mode: zero buffer + OOB on GPIO access
when `ngpios` in DT
**YES**The backport analysis is done for **gpio: pisosr: Read "ngpios"
as u32** on **v6.18.44**.
**Verdict: YES**
The driver reads the standard `u32` `ngpios` DT property with
`of_property_read_u16()`, which turns any normal value into **0**. That
leaves a zero-sized buffer while gpiolib may still register the correct
GPIO count, so boards that set `ngpios` in DT can hit out-of-bounds
access on GPIO reads. The fix is small, obviously correct, and matches
other GPIO drivers. No in-tree DTS nodes currently set `ngpios` for
`pisosr-gpio`, but the binding allows it.
drivers/gpio/gpio-pisosr.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/drivers/gpio/gpio-pisosr.c b/drivers/gpio/gpio-pisosr.c
index 7ec6a46ed6007..2732ea8c16b7b 100644
--- a/drivers/gpio/gpio-pisosr.c
+++ b/drivers/gpio/gpio-pisosr.c
@@ -112,6 +112,7 @@ static int pisosr_gpio_probe(struct spi_device *spi)
{
struct device *dev = &spi->dev;
struct pisosr_gpio *gpio;
+ u32 ngpios;
int ret;
gpio = devm_kzalloc(dev, sizeof(*gpio), GFP_KERNEL);
@@ -120,7 +121,8 @@ static int pisosr_gpio_probe(struct spi_device *spi)
gpio->chip = template_chip;
gpio->chip.parent = dev;
- of_property_read_u16(dev->of_node, "ngpios", &gpio->chip.ngpio);
+ if (!of_property_read_u32(dev->of_node, "ngpios", &ngpios))
+ gpio->chip.ngpio = ngpios;
gpio->spi = spi;
--
2.53.0
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH AUTOSEL 6.18-5.10] gpio: dwapb: Mask interrupts at hardware initialization
[not found] <20260831133314.4125787-1-sashal@kernel.org>
` (8 preceding siblings ...)
2026-08-31 13:28 ` [PATCH AUTOSEL 6.18-5.10] gpio: pisosr: Read "ngpios" as u32 Sasha Levin
@ 2026-08-31 13:29 ` Sasha Levin
2026-08-31 13:29 ` [PATCH AUTOSEL 6.18-6.1] pinctrl: renesas: rzv2m: Use -ENOTSUPP instead of -EOPNOTSUPP Sasha Levin
2026-08-31 13:31 ` [PATCH AUTOSEL 6.18] wifi: ath9k: Obtain system GPIOS from descriptors Sasha Levin
11 siblings, 0 replies; 12+ messages in thread
From: Sasha Levin @ 2026-08-31 13:29 UTC (permalink / raw)
To: patches, stable
Cc: Liang Hao, Bartosz Golaszewski, Sasha Levin, hoan, linusw, brgl,
linux-gpio, linux-kernel
From: Liang Hao <haohlliang@gmail.com>
[ Upstream commit aaf7766ba3b99a3834319e7cf939838afc705574 ]
GPIO interrupts may retain stale state across warm reboots when
peripherals remain powered. If a GPIO line is not explicitly
configured for interrupts, this can result in interrupt storms
due to missing handlers.
Fix this by ensuring all interrupts are masked and disabled at
hardware initialization time via the init_hw() callback. Pending
interrupts are also cleared to start from a known-safe state.
Interrupts will be unmasked only when explicitly configured by
userspace or kernel drivers.
Signed-off-by: Liang Hao <haohlliang@gmail.com>
Link: https://patch.msgid.link/20260705074759.47863-1-haohlliang@gmail.com
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
LLM Generated explanations, may be completely bogus:
# Stable Backport Analysis: `gpio: dwapb: Mask interrupts at hardware
initialization`
**Local tree:** Linux **6.18.44** (`v6.18.44-1-g2736c32da98b9`)
---
## PHASE 1: COMMIT MESSAGE FORENSICS
### Step 1.1: Parse the subject line
**Record:** `[gpio: dwapb]` `[Mask]` — Ensure GPIO interrupt hardware is
in a known-safe masked state during driver initialization.
### Step 1.2: Parse all commit message tags
**Record:**
- **Fixes:** — not present (expected for manual review)
- **Reported-by:** — none
- **Tested-by:** — none
- **Reviewed-by:** — none
- **Acked-by:** — none
- **Link:**
`https://patch.msgid.link/20260705074759.47863-1-haohlliang@gmail.com`
- **Cc: stable:** — not present (not a negative signal)
- **Signed-off-by:** Liang Hao `<haohlliang@gmail.com>` (author)
- **Signed-off-by:** Bartosz Golaszewski
`<bartosz.golaszewski@oss.qualcomm.com>` (GPIO maintainer)
Notable: maintainer sign-off; no syzbot/fuzzer report; no explicit user
bug report in the message.
### Step 1.3: Analyze commit body
**Record:**
- **Bug:** GPIO interrupt registers can retain stale enabled/unmasked
state across warm reboots when the GPIO block stays powered.
- **Symptom:** Interrupt storms on lines not explicitly configured for
interrupts, because hardware is firing but software has no proper
handler setup for those lines.
- **Root cause:** Driver did not reset interrupt enable/mask/EOI
registers at probe time.
- **Fix approach:** Add `init_hw` callback that disables all interrupts
(`GPIO_INTEN=0`), masks all lines (`GPIO_INTMASK=0xffffffff`), and
clears pending interrupts (`GPIO_PORTA_EOI=0xffffffff`) before the
irqchip/domain is fully operational.
- **Version info:** none stated in the message.
### Step 1.4: Detect hidden bug fixes
**Record:** Not disguised as cleanup — this is an explicit hardware-init
bug fix. The failure mode (interrupt storm → potential soft lockup /
system unresponsiveness) is a real stability bug, not cosmetic cleanup.
---
## PHASE 2: DIFF ANALYSIS
### Step 2.1: Inventory the changes
**Record:**
- **Files:** `drivers/gpio/gpio-dwapb.c` only (+16 lines net)
- **Functions added/modified:**
- New: `dwapb_irq_init_hw()`
- Modified: `dwapb_configure_irqs()` (assigns `girq->init_hw`)
- **Scope:** Single-file, surgical driver fix.
### Step 2.2: Code flow change per hunk
**Hunk 1 — new `dwapb_irq_init_hw()`:**
- **Before:** No hardware interrupt reset at GPIO irqchip registration.
- **After:** On `gpiochip_add_data()`, gpiolib calls `init_hw` which
writes:
- `GPIO_INTEN = 0` (disable all interrupt enables)
- `GPIO_INTMASK = 0xffffffff` (mask all lines)
- `GPIO_PORTA_EOI = 0xffffffff` (clear all pending interrupts)
**Hunk 2 — `dwapb_configure_irqs()`:**
- **Before:** `girq->handler = handle_bad_irq`, `girq->default_type =
IRQ_TYPE_NONE` only.
- **After:** Also sets `girq->init_hw = dwapb_irq_init_hw`.
**Execution path:** Driver probe → `dwapb_gpio_add_port()` →
`dwapb_configure_irqs()` → `devm_gpiochip_add_data()` →
`gpiochip_irqchip_init_hw()` → `dwapb_irq_init_hw()`.
### Step 2.3: Bug mechanism
**Record:** **Category (h): Hardware initialization / stale-state
workaround**
The DesignWare APB GPIO block does not reset interrupt state on warm
reboot if power is maintained. Without explicit masking at probe, lines
left enabled from a prior boot can assert interrupts continuously. The
driver sets `handle_bad_irq` as default handler, but unmasked hardware
interrupts on unconfigured lines can still flood the CPU with IRQ
activity.
The fix mirrors established patterns in other GPIO drivers (e.g. `gpio-
max77620.c` explicitly documents bootloader-left interrupts).
### Step 2.4: Fix quality assessment
**Record:**
- **Quality:** High — minimal, register writes match existing driver
register definitions and irq enable/disable logic.
- **Regression risk:** Very low — interrupts are only unmasked later via
`dwapb_irq_unmask()` / `dwapb_irq_enable()` when explicitly
configured.
- **Minor nuance:** On ACPI platforms, `devm_request_irq()` in
`dwapb_configure_irqs()` runs *before* `devm_gpiochip_add_data()`
triggers `init_hw`. This is a pre-existing ordering characteristic;
the fix still addresses the steady-state stale-hardware problem and is
strictly better than no masking. Verified in current tree code at
lines 484–566 of `gpio-dwapb.c`.
---
## PHASE 3: GIT HISTORY INVESTIGATION
### Step 3.1: Blame changed lines
**Record:** `dwapb_configure_irqs()` and surrounding interrupt code
trace to `5d324e5159d9e` (v6.18 merge base in this tree). The driver and
interrupt path have been present since this tree's import; no `init_hw`
hook was ever set for dwapb in this tree.
### Step 3.2: Follow Fixes: tag
**Record:** N/A — no `Fixes:` tag in commit message.
### Step 3.3: File history for related changes
**Record:** Recent `gpio-dwapb.c` history in this tree:
- `5e15cf51982f8` gpio: dwapb: Defer clock gating until noirq
- `6c736c5ccf4a3` gpio: dwapb: reduce allocation to single kzalloc
- `d7b5497e0e45b` gpio: dwapb: Use modern PM macros
No related interrupt-init fix already present. Standalone patch, not
part of a series.
### Step 3.4: Author's other commits
**Record:** No commits by Liang Hao found in this tree's history (`git
log --author` returned empty). Author appears to be an external
contributor; patch carries GPIO maintainer SOB.
### Step 3.5: Prerequisites / dependencies
**Record:**
- **`init_hw` infrastructure:** Present in this tree —
`include/linux/gpio/driver.h` defines `gpio_irq_chip::init_hw`;
`gpiochip_irqchip_init_hw()` in `gpiolib.c` calls it during
`gpiochip_add_data()` at line 1196.
- **No other commits required.** Patch is self-contained.
- **Can apply standalone:** Yes.
---
## PHASE 4: MAILING LIST AND EXTERNAL RESEARCH
### Step 4.1: Original patch discussion
**Record:** Attempted `b4 dig -c <commit>` — commit not in local tree
(not yet applied). Attempted lore fetch via WebFetch and curl — blocked
by Anubis bot protection. **Could not retrieve mailing list thread
content.**
### Step 4.2: Reviewers from b4 dig -w
**Record:** Not performed — commit hash unavailable locally; b4 requires
`-c COMMITISH`.
### Step 4.3: Bug report search
**Record:** No Reported-by or syzbot link in commit message. No external
bug report retrieved.
### Step 4.4: Related patches / series
**Record:** Appears to be a standalone 1-patch fix. No series indicators
in subject.
### Step 4.5: Stable mailing list history
**Record:** Not searchable due to lore access failure. No stable-list
discussion verified.
---
## PHASE 5: CODE SEMANTIC ANALYSIS
### Step 5.1: Key functions
**Record:** `dwapb_irq_init_hw()` (new), `dwapb_configure_irqs()`
(modified), called via `gpiochip_irqchip_init_hw()` in gpiolib.
### Step 5.2: Callers
**Record:**
- `dwapb_configure_irqs()` ← `dwapb_gpio_add_port()` ←
`dwapb_gpio_probe()` (platform driver probe)
- `gpiochip_irqchip_init_hw()` ← `gpiochip_add_data()` ←
`devm_gpiochip_add_data()`
- Probe runs at boot for all DesignWare APB GPIO instances (DT:
`snps,dw-apb-gpio`; ACPI on Intel platforms per driver comment).
### Step 5.3: Callees
**Record:** `dwapb_write()` / `dwapb_read()` — MMIO register accessors
with v2 register offset remapping.
### Step 5.4: Call chain / reachability
**Record:** Triggered on every dwapb controller probe at boot (or module
load). Warm reboot with powered GPIO block is the specific failure
scenario. Affects embedded SoCs (RISC-V T-Head, Sophgo, many others in
DT) and Intel ACPI platforms using shared GPIO IRQ lanes.
### Step 5.5: Similar patterns
**Record:** Identical pattern already used in this tree by:
- `gpio-max77620.c` — "GPIO interrupts may be left ON after bootloader"
- `gpio-idt3243x.c` — masks all interrupts in `init_hw`
- `gpio-tangier.c` — clears edge-detect registers in `init_hw`
This is an established, maintainer-accepted GPIO subsystem pattern.
---
## PHASE 6: CROSS-REFERENCE AGAINST LOCAL TREE (6.18.44)
### Step 6.1: Does buggy code exist?
**Record:** **YES.** Current `gpio-dwapb.c` has no `dwapb_irq_init_hw`
and no `girq->init_hw` assignment. `dwapb_configure_irqs()` at lines
472–474 sets only `handler` and `default_type`. The driver has been
present in this tree without hardware interrupt masking at init.
### Step 6.2: Backport complications
**Record:** **Clean apply expected.** File structure matches the patch
context exactly. `init_hw` callback and gpiolib support are present. No
conflicting changes identified.
### Step 6.3: Related fixes already present?
**Record:** **None.** `grep` for `dwapb_irq_init_hw` and `init_hw` in
`gpio-dwapb.c` returns no matches.
---
## PHASE 7: SUBSYSTEM AND MAINTAINER CONTEXT
### Step 7.1: Subsystem criticality
**Record:** **drivers/gpio** — IMPORTANT. GPIO/IRQ infrastructure
affects many embedded and ACPI platforms. Interrupt storms are a system-
wide stability issue.
### Step 7.2: Subsystem activity
**Record:** Active — recent dwapb commits in 6.18.y (PM, allocation,
clock gating). Driver is maintained and in active use.
---
## PHASE 8: IMPACT AND RISK ASSESSMENT
### Step 8.1: Who is affected
**Record:** Users of DesignWare APB GPIO (`CONFIG_GPIO_DWAPB`) on
platforms where the GPIO block retains power across warm reboot —
embedded SoCs, Intel ACPI systems with shared GPIO IRQ lanes. Config-
specific but affects a broad class of hardware.
### Step 8.2: Trigger conditions
**Record:**
- Warm reboot (not full power cycle)
- GPIO block stays powered
- Prior boot left interrupt enables/masks in non-default state
- Lines not re-configured for interrupts in new boot
- **Likelihood:** Platform-dependent but realistic on embedded/ACPI
systems that use warm reboot
- **Unprivileged trigger:** No direct userspace trigger; boot-time /
reboot-time hardware state issue
### Step 8.3: Failure mode severity
**Record:** **Interrupt storm** → sustained IRQ handling → CPU
saturation → soft lockup / hung system / severely degraded
responsiveness. **Severity: HIGH to CRITICAL** (system stability).
### Step 8.4: Risk-benefit
**Record:**
- **Benefit:** HIGH — prevents boot-time or post-warm-reboot interrupt
storms on widely deployed IP block
- **Risk:** VERY LOW — ~16 lines, standard register init, no API
changes, interrupts restored only when explicitly enabled
- **Ratio:** Strongly favors backport
---
## PHASE 9: FINAL SYNTHESIS
### Step 9.1: Evidence compile
**FOR backport:**
- Fixes real hardware stale-state bug causing interrupt storms
- Can cause system hang / severe instability (HIGH severity)
- Small, surgical, obviously correct fix
- Uses existing `init_hw` infrastructure already in 6.18.44
- Precedent in multiple GPIO drivers in this same tree
- GPIO maintainer (Bartosz Golaszewski) signed off
- Buggy code confirmed present; fix not yet applied
- No dependencies on other commits
**AGAINST backport:**
- No syzbot report or explicit user bug report in commit message (weaker
evidence of real-world hit rate)
- ACPI probe ordering means parent IRQ is requested before `init_hw`
runs (minor window; pre-existing, not introduced by patch)
- Lore discussion could not be retrieved to confirm review feedback
**Unresolved:**
- Mailing list review thread content (lore blocked)
- Exact platforms where author observed the bug
### Step 9.2: Stable rules checklist
1. Obviously correct and tested? **PASS** — register init matches driver
conventions; maintainer SOB; pattern used elsewhere
2. Fixes a real bug? **PASS** — stale interrupt state on warm reboot
3. Important issue? **PASS** — interrupt storm / system stability
4. Small and contained? **PASS** — one file, ~16 lines
5. No new features/APIs? **PASS** — uses existing `init_hw` callback
6. Can apply to local tree? **PASS** — infrastructure present, clean
apply expected
### Step 9.3: Exception categories
**Record:** Hardware workaround / driver initialization quirk —
qualifies under stable exception for hardware-specific workarounds that
fix real hardware behavior.
### Step 9.4: Decision rationale
This commit fixes a genuine stability bug in a widely used GPIO
controller driver. The failure mode (interrupt storm after warm reboot)
is serious, the fix is minimal and follows an established pattern
already present in this tree's GPIO subsystem, and all prerequisites
exist in Linux 6.18.44. The fix is not yet in this tree and should be
backported.
---
## Verification
- [Phase 1] `git describe HEAD` → `v6.18.44-1-g2736c32da98b9`; Makefile
→ 6.18.44
- [Phase 1] Parsed commit message tags from user-provided content
- [Phase 2] Read `drivers/gpio/gpio-dwapb.c` lines 182–509, 750–875;
confirmed diff targets match current code structure
- [Phase 2] Verified register constants `GPIO_INTEN`, `GPIO_INTMASK`,
`GPIO_PORTA_EOI` at lines 35–41
- [Phase 2] Verified irq enable/disable logic at lines 283–313 uses same
registers the fix initializes
- [Phase 3] `git blame -L 454,490 drivers/gpio/gpio-dwapb.c` → code from
v6.18 merge base
- [Phase 3] `git log --oneline -20 -- drivers/gpio/gpio-dwapb.c` →
recent PM/allocation commits, no interrupt-init fix
- [Phase 3] `grep init_hw drivers/gpio/gpio-dwapb.c` → no matches (fix
not present)
- [Phase 3] `git log -S 'init_hw' -- drivers/gpio/gpiolib.c` →
infrastructure present since tree base
- [Phase 4] `b4 dig -c` — failed (commit not in tree)
- [Phase 4] WebFetch + curl lore URL — blocked by Anubis; thread content
UNVERIFIED
- [Phase 5] Read `gpiolib.c` lines 1185–1202 —
`gpiochip_irqchip_init_hw()` called before `gpiochip_add_irqchip()`
- [Phase 5] `grep init_hw drivers/gpio/` → found precedent in max77620,
idt3243x, tangier, realtek-otto
- [Phase 5] Read `gpio-max77620.c` lines 263–274 — identical rationale
("left ON after bootloader")
- [Phase 6] Confirmed `dwapb_configure_irqs()` lacks `girq->init_hw` at
line 472–474
- [Phase 6] Confirmed `include/linux/gpio/driver.h` has `init_hw` at
line 264
- [Phase 6] `grep snps,dw-apb-gpio` → multiple DT platforms (T-Head
th1520, Sophgo sg2042, etc.)
- [Phase 7] `drivers/gpio/Kconfig` line 273 — `CONFIG_GPIO_DWAPB`
tristate driver exists
- [Phase 8] Analyzed ACPI vs non-ACPI probe order in
`dwapb_configure_irqs()` + `dwapb_gpio_add_port()`
**YES**
drivers/gpio/gpio-dwapb.c | 17 +++++++++++++++++
1 file changed, 17 insertions(+)
diff --git a/drivers/gpio/gpio-dwapb.c b/drivers/gpio/gpio-dwapb.c
index 0259c65973323..6ece05f3afe2d 100644
--- a/drivers/gpio/gpio-dwapb.c
+++ b/drivers/gpio/gpio-dwapb.c
@@ -201,6 +201,22 @@ static void dwapb_toggle_trigger(struct dwapb_gpio *gpio, unsigned int offs)
dwapb_write(gpio, GPIO_INT_POLARITY, pol);
}
+static int dwapb_irq_init_hw(struct gpio_chip *gc)
+{
+ struct dwapb_gpio *gpio = to_dwapb_gpio(gc);
+
+ /*
+ * GPIO interrupts may retain stale state across warm reboots when
+ * peripherals stay powered. Force a known-safe state before the GPIO
+ * irqchip and irq domain are set up.
+ */
+ dwapb_write(gpio, GPIO_INTEN, 0);
+ dwapb_write(gpio, GPIO_INTMASK, 0xffffffff);
+ dwapb_write(gpio, GPIO_PORTA_EOI, 0xffffffff);
+
+ return 0;
+}
+
static u32 dwapb_do_irq(struct dwapb_gpio *gpio)
{
struct gpio_generic_chip *gen_gc = &gpio->ports[0].chip;
@@ -472,6 +488,7 @@ static void dwapb_configure_irqs(struct dwapb_gpio *gpio,
girq = &gc->irq;
girq->handler = handle_bad_irq;
girq->default_type = IRQ_TYPE_NONE;
+ girq->init_hw = dwapb_irq_init_hw;
port->pirq = pirq;
--
2.53.0
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH AUTOSEL 6.18-6.1] pinctrl: renesas: rzv2m: Use -ENOTSUPP instead of -EOPNOTSUPP
[not found] <20260831133314.4125787-1-sashal@kernel.org>
` (9 preceding siblings ...)
2026-08-31 13:29 ` [PATCH AUTOSEL 6.18-5.10] gpio: dwapb: Mask interrupts at hardware initialization Sasha Levin
@ 2026-08-31 13:29 ` Sasha Levin
2026-08-31 13:31 ` [PATCH AUTOSEL 6.18] wifi: ath9k: Obtain system GPIOS from descriptors Sasha Levin
11 siblings, 0 replies; 12+ messages in thread
From: Sasha Levin @ 2026-08-31 13:29 UTC (permalink / raw)
To: patches, stable
Cc: Claudiu Beznea, Geert Uytterhoeven, Geert Uytterhoeven,
Sasha Levin, linusw, linux-renesas-soc, linux-gpio, linux-kernel
From: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
[ Upstream commit 01f94d53947df35ba77cdb3992a4e3ef9d9dc1ad ]
The pinctrl and GPIO core code make exceptions for the -ENOTSUPP error
code. One such example is gpio_set_config_with_argument_optional(), which
returns success when gpio_set_config_with_argument() returns -ENOTSUPP, but
reports failure for all other error codes.
Returning -EOPNOTSUPP from the pinctrl driver on the unsupported pinctrl
operation may lead to boot failures when pinctrl drivers implements
struct gpio_chip::set_config, the system uses GPIO hogs, and the
struct gpio_chip::set_config implementation returns -EOPNOTSUPP for the
unsupported operations.
Currently, the driver does not implement struct gpio_chip::set_config().
To avoid future failures, return -ENOTSUPP from
rzv2m_pinctrl_pinconf_set().
rzv2m_pinctrl_pinconf_group_get() is used when dumping pinctrl
configuration. pinconf_generic_dump_one(), which calls it, makes
exceptions for the -EINVAL and -ENOTSUPP error codes. The documentation
for struct pinconf_ops::pin_config_group_get states that it "should
return -ENOTSUPP and -EINVAL using the same rules as pin_config_get()".
The documentation for struct pinconf_ops::pin_config_get states:
"get the config of a certain pin, if the requested config is not available
on this controller this should return -ENOTSUPP and if it is available but
disabled it should return -EINVAL".
Return -ENOTSUPP for the unsupported pinctrl operation.
Suggested-by: Geert Uytterhoeven <geert@linux-m68k.org>
Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be>
Link: https://patch.msgid.link/20260522105717.1727837-1-claudiu.beznea@kernel.org
Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
LLM Generated explanations, may be completely bogus:
# Stable Backport Analysis: `pinctrl: renesas: rzv2m: Use -ENOTSUPP
instead of -EOPNOTSUPP`
**Local tree:** Linux **6.18.44** (`git describe HEAD` → `v6.18.44`,
`make kernelversion` → `6.18.44`)
**Upstream commit:** `01f94d53947df` (on `master`; **not** in this
6.18.44 checkout)
---
## PHASE 1: COMMIT MESSAGE FORENSICS
### Step 1.1: Subject line
**Record:** `[pinctrl: renesas: rzv2m]` — action: **Use** (correctness
fix) — return the proper `-ENOTSUPP` errno instead of `-EOPNOTSUPP` for
unsupported pinconf operations.
### Step 1.2: Tags
**Record:**
- **Suggested-by:** Geert Uytterhoeven (maintainer suggested the fix)
- **Signed-off-by:** Claudiu Beznea (author), Geert Uytterhoeven
(committer on master)
- **Reviewed-by:** Geert Uytterhoeven (subsystem maintainer)
- **Link:** https://patch.msgid.link/20260522105717.1727837-1-
claudiu.beznea@kernel.org
- **No** Fixes:, Reported-by:, Tested-by:, Cc: stable@vger.kernel.org
(absence of Cc: stable is expected per review instructions)
- **Notable:** Maintainer-reviewed, maintainer-suggested; no syzbot or
user bug reports
### Step 1.3: Body analysis
**Record:**
- **Bug:** Driver returns `-EOPNOTSUPP` where pinctrl/GPIO core expects
`-ENOTSUPP` for “unsupported configuration”
- **Symptoms:**
- Potential **boot failure** if `gpio_chip::set_config` is added and
GPIO hogs trigger optional config paths
(`gpio_set_config_with_argument_optional()` treats only `-ENOTSUPP`
as benign)
- **Incorrect debugfs dumps**: `pinconf_generic_dump_one()` treats
`-ENOTSUPP` and `-EINVAL` as legal; `-EOPNOTSUPP` prints `"ERROR
READING CONFIG SETTING"`
- **Root cause:** Violation of documented `pinconf_ops` API contract
(`include/linux/pinctrl/pinconf.h`)
- **Version info:** None in message; driver has existed since 2022
### Step 1.4: Hidden bug fix?
**Record:** **Yes.** Despite neutral “Use X instead of Y” wording, this
fixes a real API-contract bug with concrete debugfs impact and a
documented boot-failure class for GPIO hog + `set_config` paths.
---
## PHASE 2: DIFF ANALYSIS
### Step 2.1: Inventory
**Record:**
- **File:** `drivers/pinctrl/renesas/pinctrl-rzv2m.c` — 2 lines changed
(+2/-2)
- **Functions:** `rzv2m_pinctrl_pinconf_set()`,
`rzv2m_pinctrl_pinconf_group_get()`
- **Scope:** Single-file, surgical fix
### Step 2.2: Code flow per hunk
**Hunk 1 — `rzv2m_pinctrl_pinconf_set()` default case:**
- **Before:** Unknown `PIN_CONFIG_*` param → `-EOPNOTSUPP`
- **After:** → `-ENOTSUPP`
- **Path:** DT pinconf apply / explicit pin configuration for
unsupported parameters
**Hunk 2 — `rzv2m_pinctrl_pinconf_group_get()` mismatch check:**
- **Before:** Pins in group disagree on config value → `-EOPNOTSUPP`
- **After:** → `-ENOTSUPP`
- **Path:** `pinconf_generic_dump_one()` → `pin_config_group_get()`
during debugfs pinconf dumps
### Step 2.3: Bug mechanism
**Record:** **Logic / API correctness fix (category g).** Core
GPIO/pinconf code special-cases `-ENOTSUPP` but not `-EOPNOTSUPP`. The
driver already returns `-ENOTSUPP` correctly in
`rzv2m_pinctrl_pinconf_get()` (line 548); these two sites were
inconsistent.
### Step 2.4: Fix quality
**Record:** Obviously correct, minimal, matches kernel-wide convention
and sibling `rzg2l` fix. Regression risk: **very low** (only changes
error codes on unsupported/mismatched-config paths).
---
## PHASE 3: GIT HISTORY INVESTIGATION
### Step 3.1: Blame
**Record:** `-EOPNOTSUPP` in `pinconf_set` default case introduced in
`92a9b82525761` (“Add RZ/V2M pin and gpio controller driver”, June
2022). Present in this 6.18.44 tree.
### Step 3.2: Fixes: tag
**Record:** N/A — no Fixes: tag in commit message.
### Step 3.3: Related file history
**Record:**
- Identical fix for `rzg2l` already backported to **this tree**:
`6876f767b0490` (upstream `c1492da3939c`)
- Related but separate: `ec642ab9b76f8` (type fix in
`pin_config_group_get`) is on `master` but **not** in 6.18.44 — not a
prerequisite for this 2-line errno change
- Standalone single-patch series (v1 only per `b4 dig -a`)
### Step 3.4: Author context
**Record:** Claudiu Beznea is an active Renesas pinctrl contributor;
Geert Uytterhoeven is the Renesas maintainer who committed and reviewed.
### Step 3.5: Dependencies
**Record:** **None.** Patch applies cleanly (`git apply --check` → exit
0). Does not assume code absent from 6.18.44.
---
## PHASE 4: MAILING LIST AND EXTERNAL RESEARCH
### Step 4.1: Original discussion
**Record:**
- **URL:** https://patch.msgid.link/20260522105717.1727837-1-
claudiu.beznea@kernel.org
- **Series:** v1 only (no revisions)
- **Review:** Geert Uytterhoeven Reviewed-by + “will queue in renesas-
devel for v7.2”
- **No** NAKs, no explicit stable nomination in thread
- Lore web fetch blocked by bot protection; content obtained via `b4 dig
-m`
### Step 4.2: Reviewers
**Record:** CC’d: `geert+renesas@glider.be`, `linusw@kernel.org`,
`brgl@kernel.org`, `linux-renesas-soc@`, `linux-gpio@`, `linux-kernel@`
— appropriate maintainer coverage.
### Step 4.3: Bug report
**Record:** N/A — no external bug report; preventive/correctness fix
identified by maintainer (Suggested-by Geert).
### Step 4.4: Related patches
**Record:** Part of a Renesas-wide errno cleanup; `rzg2l` variant
already in this stable tree.
### Step 4.5: Stable list
**Record:** Not searched (lore blocked); `rzg2l` sibling carried `Cc:
stable@vger.kernel.org` and was backported here.
---
## PHASE 5: CODE SEMANTIC ANALYSIS
### Step 5.1: Key functions
**Record:** `rzv2m_pinctrl_pinconf_set`,
`rzv2m_pinctrl_pinconf_group_get`
### Step 5.2: Callers
**Record:**
- `pinconf_set` → `pinconf_apply_setting()` during pinctrl DT binding
(boot)
- `pinconf_group_get` → `pin_config_group_get()` →
`pinconf_generic_dump_one()` (debugfs via
`pinconf_generic_dump_config`; driver sets `is_generic = true`)
### Step 5.3: Callees
**Record:** `rzv2m_pinctrl_pinconf_get()` (group_get),
`pinconf_to_config_param()` (set)
### Step 5.4: Reachability
**Record:**
- **Boot:** `pinconf_set` path reachable on RZ/V2M boot with unsupported
DT pinconf properties (both errnos fail equally today via
`pinconf_apply_setting`)
- **GPIO hog boot failure:** **Not currently reachable** —
`rzv2m_gpio_register()` does not set `chip->set_config`;
`gpio_do_set_config()` returns `-ENOTSUPP` when `set_config` is NULL
- **Debugfs:** `pinconf_group_get` path **is reachable** on RZ/V2M when
dumping pinconf; wrong errno causes spurious error strings
- **RZ/V2M EVK** (`r9a09g011-v2mevk2.dts`): no `gpio-hog` nodes found
### Step 5.5: Similar patterns
**Record:** `rzv2m_pinctrl_pinconf_get()` already uses `-ENOTSUPP` (line
548). `rzg2l` fix already backported in this tree. Kernel-wide
convention: pinctrl drivers return `-ENOTSUPP` for unsupported configs.
---
## PHASE 6: CROSS-REFERENCE WITH LOCAL TREE (6.18.44)
### Step 6.1: Buggy code exists?
**Record:** **Yes.** Lines 664 and 713 in `pinctrl-rzv2m.c` still return
`-EOPNOTSUPP`. Driver present since v6.x (2022).
### Step 6.2: Backport complications
**Record:** **Clean apply** — verified with `git show 01f94d53947df |
git apply --check`.
### Step 6.3: Related fixes already present?
**Record:** `rzg2l` errno fix (`6876f767b0490`) is in this tree; `rzv2m`
fix is **not** yet applied.
---
## PHASE 7: SUBSYSTEM CONTEXT
### Step 7.1: Subsystem / criticality
**Record:** `drivers/pinctrl/renesas` — **PERIPHERAL** (RZ/V2M /
`ARCH_R9A09G011` platform-specific), but uses generic pinconf
infrastructure shared with GPIO core.
### Step 7.2: Activity
**Record:** Active — recent rzv2m fixes in this tree (NULL deref,
of_node_put, GPIO callback updates).
---
## PHASE 8: IMPACT AND RISK
### Step 8.1: Who is affected
**Record:** RZ/V2M (`CONFIG_PINCTRL_RZV2M`) users — embedded/industrial
platforms. Not universal.
### Step 8.2: Trigger conditions
**Record:**
- **Current:** Debugfs pinconf dump with heterogeneous pin groups; API
misuse if unsupported pinconf applied via DT
- **Future:** `set_config` + GPIO hogs with optional bias/config flags
- **Likelihood today:** Low for boot (no `set_config`, no gpio-hogs on
rzv2m boards); moderate for debugfs correctness
### Step 8.3: Failure mode severity
**Record:**
- Boot failure (future `set_config` path): **CRITICAL** if triggered
- Debugfs spurious errors today: **LOW**
- API contract violation: correctness issue, not crash by itself
### Step 8.4: Risk-benefit
**Record:**
- **Benefit:** Medium — aligns with already-backported `rzg2l` fix,
fixes debugfs behavior, prevents future boot regression, correct per
`pinconf.h`
- **Risk:** Very low — 2 errno changes on error paths only
- **Ratio:** Favorable
---
## PHASE 9: FINAL SYNTHESIS
### Step 9.1: Evidence summary
**FOR backport:**
- Identical `rzg2l` fix already accepted into **this** 6.18.44 tree
- Documented API contract (`pinconf.h` requires `-ENOTSUPP`)
- Internal driver inconsistency (`pinconf_get` already uses `-ENOTSUPP`)
- Real debugfs impact via `pinconf_generic_dump_one()`
- Preventive boot-failure fix when `set_config` is added
- 2-line change, applies cleanly, maintainer-reviewed
- Bug present since driver introduction (2022)
**AGAINST backport:**
- No current boot failure (no `set_config`, no gpio-hogs on rzv2m
boards)
- Platform-specific, limited user base
- No user bug report or syzbot finding
- “Important issue” threshold is borderline for *current* runtime impact
**Unresolved:** None material to the decision.
### Step 9.2: Stable rules checklist
1. Obviously correct and tested? **PASS** — errno swap matches API docs
and `rzg2l` precedent; Reviewed-by maintainer (no Tested-by)
2. Fixes a real bug? **PASS** — API contract violation with verified
debugfs impact; boot failure class documented
3. Important issue? **PASS (borderline)** — not crashing today, but same
class of fix already deemed stable-worthy for `rzg2l` in this tree;
future boot failure is serious
4. Small and contained? **PASS** — 2 lines, 1 file
5. No new features/APIs? **PASS**
6. Can apply to local tree? **PASS** — clean apply verified
### Step 9.3: Exception categories
**Record:** None (not device ID, quirk, DT, build, or docs-only).
### Step 9.4: Decision rationale
The strongest argument is **consistency within this stable tree**:
maintainers already backported the identical `rzg2l` errno fix
(`6876f767b0490`) to 6.18.44. The `rzv2m` driver has the same bug
pattern, the same author/reviewer, and the same API-contract violation.
While current boot impact is limited (no `gpio_chip::set_config`, no
gpio-hogs on RZ/V2M boards), the `pinconf_group_get` path already
produces incorrect debugfs behavior, and the fix is trivial with
negligible regression risk.
---
## Verification
- **[Phase 1]** Parsed commit message and tags from user query + `git
show 01f94d53947df`
- **[Phase 2]** Diff analysis: 2 errno changes in `pinctrl-rzv2m.c`;
read surrounding code at lines 530–744
- **[Phase 3]** `git describe HEAD` → v6.18.44; `git blame` → buggy
lines from `92a9b82525761` (2022)
- **[Phase 3]** `git log -- drivers/pinctrl/renesas/pinctrl-rzv2m.c` —
driver history reviewed
- **[Phase 3]** Found `6876f767b0490` (rzg2l sibling fix) already in
HEAD
- **[Phase 3]** `ec642ab9b76f8` NOT in HEAD — separate type fix, not a
prerequisite
- **[Phase 4]** `b4 dig -c 01f94d53947df` → lore URL; `b4 dig -a` → v1
only; `b4 dig -w` → maintainers CC'd
- **[Phase 4]** `b4 dig -m /tmp/rzv2m_enotsupp.mbox` — Geert Reviewed-
by, no NAKs
- **[Phase 5]** Read `gpio_set_config_with_argument_optional()` in
`gpiolib.c:2694–2714` — only `-ENOTSUPP` treated as success
- **[Phase 5]** Read `pinconf_generic_dump_one()` in `pinconf-
generic.c:59–84` — `-ENOTSUPP`/`-EINVAL` skipped
- **[Phase 5]** Read `pinconf.h:24–29` — API documents `-ENOTSUPP`
- **[Phase 5]** Verified `rzv2m` has no `chip->set_config` in
`rzv2m_gpio_register()` (lines 953–960)
- **[Phase 5]** Grep: no gpio-hogs in `r9a09g011-v2mevk2.dts`
- **[Phase 6]** Grep confirms `-EOPNOTSUPP` still at lines 664, 713 in
HEAD
- **[Phase 6]** `git show 01f94d53947df | git apply --check` → applies
cleanly
- **[Phase 6]** `master` has fix at lines 664, 714; HEAD does not
**YES**The background git searches finished successfully and match what
the analysis already used:
- The **rzv2m** fix is upstream commit `01f94d53947df` on `master`; it
is **not** in this **6.18.44** tree yet (lines 664 and 713 still
return `-EOPNOTSUPP`).
- The sibling **rzg2l** fix (`6876f767b0490`) **is** already backported
here.
**Verdict for 6.18.44: YES** — same 2-line errno correction, applies
cleanly, and consistent with the rzg2l backport already in this tree.
drivers/pinctrl/renesas/pinctrl-rzv2m.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/pinctrl/renesas/pinctrl-rzv2m.c b/drivers/pinctrl/renesas/pinctrl-rzv2m.c
index dce68f93d2d57..e08f24d5a89f5 100644
--- a/drivers/pinctrl/renesas/pinctrl-rzv2m.c
+++ b/drivers/pinctrl/renesas/pinctrl-rzv2m.c
@@ -661,7 +661,7 @@ static int rzv2m_pinctrl_pinconf_set(struct pinctrl_dev *pctldev,
}
default:
- return -EOPNOTSUPP;
+ return -ENOTSUPP;
}
}
@@ -710,7 +710,7 @@ static int rzv2m_pinctrl_pinconf_group_get(struct pinctrl_dev *pctldev,
/* Check config matches previous pins */
if (i && prev_config != *config)
- return -EOPNOTSUPP;
+ return -ENOTSUPP;
prev_config = *config;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH AUTOSEL 6.18] wifi: ath9k: Obtain system GPIOS from descriptors
[not found] <20260831133314.4125787-1-sashal@kernel.org>
` (10 preceding siblings ...)
2026-08-31 13:29 ` [PATCH AUTOSEL 6.18-6.1] pinctrl: renesas: rzv2m: Use -ENOTSUPP instead of -EOPNOTSUPP Sasha Levin
@ 2026-08-31 13:31 ` Sasha Levin
11 siblings, 0 replies; 12+ messages in thread
From: Sasha Levin @ 2026-08-31 13:31 UTC (permalink / raw)
To: patches, stable
Cc: Linus Walleij, Michał Kępień,
Toke Høiland-Jørgensen, Andy Shevchenko,
Bartosz Golaszewski, Jeff Johnson, Sasha Levin, albeu, brgl,
linux-gpio, linux-kernel, linux-wireless
From: Linus Walleij <linusw@kernel.org>
[ Upstream commit 34a5329beee86a22a446e27eb37f06caa63479ca ]
The ath9k has an odd use of system-wide GPIOs: if the chip
does not have internal GPIO capability, it will try to obtain a
GPIO line from the system GPIO controller:
if (BIT(gpio) & ah->caps.gpio_mask)
ath9k_hw_gpio_cfg_wmac(...);
else if (AR_SREV_SOC(ah))
ath9k_hw_gpio_cfg_soc(ah, gpio, out, label);
Where ath9k_hw_gpio_cfg_soc() will attempt to issue
gpio_request_one() passing the local GPIO number of the controller
(0..31) to gpio_request_one().
This is somewhat peculiar and possibly even dangerous: there is
nowadays no guarantee of the numbering of these system-wide
GPIOs, and assuming that GPIO 0..31 as used by ath9k would
correspond to GPIOs 0..31 on the system as a whole seems a bit
wild.
Register all 32 GPIOs at index 0..31 directly in the ATH79K
GPIO driver and associate with the NULL device (making them
widely available) if and only if we are probing ATH79K wifi
from the AHB bus (used for SoCs). We obtain these offsets from
the NULL device if necessary.
These GPIOs should ideally be defined in the device tree
instead, but we have no control over that for the legacy
code path.
Testcompiled with the ath79 defconfig.
Reported-by: Michał Kępień <kernel@kempniu.pl>
Acked-by: Toke Høiland-Jørgensen <toke@toke.dk>
Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Acked-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
Signed-off-by: Linus Walleij <linusw@kernel.org>
Tested-by: Michał Kępień <kernel@kempniu.pl>
Link: https://patch.msgid.link/20260317-descriptors-wireless-v6-1-b19ecff9cd2b@kernel.org
Signed-off-by: Jeff Johnson <jeff.johnson@oss.qualcomm.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
LLM Generated explanations, may be completely bogus:
Connection lost, reconnecting to https://agentn.us.api5.cursor.sh
(attempt 1)...
Retry attempt 1...
Connection lost, reconnecting to https://agentn.us.api5.cursor.sh
(attempt 2)...
Retry attempt 2...
# Stable Backport Analysis: `wifi: ath9k: Obtain system GPIOS from
descriptors`
**Local tree:** Linux **6.18.43** (`git describe HEAD` → `v6.18.43`,
`make kernelversion` → `6.18.43`)
---
## PHASE 1: COMMIT MESSAGE FORENSICS
### Step 1.1: PARSE THE SUBJECT LINE
**Record:** `[wifi: ath9k]` `[obtain]` — Switch ath9k SoC GPIO handling
from legacy global GPIO numbers to GPIO descriptors obtained via lookup
tables.
### Step 1.2: PARSE ALL COMMIT MESSAGE TAGS
**Record:**
| Tag | Value |
|-----|-------|
| Reported-by | Michał Kępień \<kernel@kempniu.pl\> |
| Tested-by | Michał Kępień \<kernel@kempniu.pl\> |
| Acked-by | Toke Høiland-Jørgensen, Bartosz Golaszewski |
| Reviewed-by | Andy Shevchenko |
| Signed-off-by | Linus Walleij, Jeff Johnson |
| Link | https://patch.msgid.link/20260317-descriptors-
wireless-v6-1-b19ecff9cd2b@kernel.org |
| Fixes: | Not present (expected) |
| Cc: stable | Not present (expected) |
**Notable patterns:** Real-world reporter who also tested the fix; GPIO
subsystem maintainer (Bartosz Golaszewski) and GPIO expert (Andy
Shevchenko) reviewed/acked. No syzbot report.
### Step 1.3: ANALYZE THE COMMIT BODY TEXT
**Record:**
- **Bug description:** On ath79 SoC platforms, when ath9k lacks internal
GPIO capability for a line, `ath9k_hw_gpio_cfg_soc()` calls
`gpio_request_one()` with chip-local offsets (0–31), assuming they map
to global GPIO numbers 0–31. That assumption is invalid with modern
dynamic GPIO base allocation.
- **Symptom/failure mode:** GPIO request fails or maps to the wrong
system GPIO line; LED, rfkill, and other SoC GPIO-dependent features
break.
- **Root cause:** Legacy global GPIO API used with dynamically allocated
GPIO chip bases after gpio-ath79 moved to `gpio_generic_chip`.
- **Fix approach:** Register a `gpiod_lookup_table` in gpio-ath79 (when
`CONFIG_ATH9K_AHB`) and obtain descriptors via `gpiod_get_index(NULL,
"ath9k", gpio, flags)` in ath9k.
### Step 1.4: DETECT HIDDEN BUG FIXES
**Record:** Not disguised cleanup — explicitly a correctness fix for
broken GPIO mapping on ath79/ath9k AHB SoCs. Falls under the hardware
quirk/workaround exception category.
---
## PHASE 2: DIFF ANALYSIS
### Step 2.1: INVENTORY THE CHANGES
**Record:**
| File | +/- | Functions modified |
|------|-----|-------------------|
| `drivers/gpio/gpio-ath79.c` | +56/-1 |
`ath79_gpio_register_wifi_descriptors()` (new), `ath79_gpio_probe()` |
| `drivers/net/wireless/ath/ath9k/hw.c` | +22/-11 |
`ath9k_hw_gpio_cfg_soc()`, `ath9k_hw_gpio_free()`,
`ath9k_hw_gpio_get()`, `ath9k_hw_set_gpio()` |
| `drivers/net/wireless/ath/ath9k/hw.h` | +2/-1 | `struct ath_hw`,
`struct ath9k_hw_capabilities` |
**Scope:** Multi-file but surgical (~80 lines total). Self-contained
within gpio-ath79 + ath9k.
### Step 2.2: CODE FLOW CHANGE (per hunk)
**Record:**
1. **gpio-ath79.c probe:** After `devm_gpiochip_add_data()`, register 32
lookup entries mapping chip offsets 0–31 to consumer `"ath9k"`
indices 0–31 on the NULL device.
2. **ath9k_hw_gpio_cfg_soc():** `devm_gpio_request_one(ah->dev, gpio,
...)` → `gpiod_get_index(NULL, "ath9k", gpio, flags)`; store in
`ah->gpiods[gpio]`.
3. **ath9k_hw_gpio_get/set_gpio():** `gpio_get_value(gpio)` /
`gpio_set_value(gpio, val)` → `gpiod_get_value()` /
`gpiod_set_value()` on stored descriptors.
4. **ath9k_hw_gpio_free():** Clear bit in `gpio_requested` →
`gpiod_put()` and NULL the descriptor.
5. **hw.h:** Replace `caps.gpio_requested` bitmask with `struct
gpio_desc *gpiods[32]`.
### Step 2.3: BUG MECHANISM
**Record:** **Category:** Logic/correctness + hardware workaround.
- **Broken:** `gpio_request_one()` and
`gpio_get_value()`/`gpio_set_value()` used chip-local GPIO indices as
global GPIO numbers.
- **With dynamic bases** (gpio-ath79 uses `gpio_generic_chip` in this
tree), local offset 11 ≠ global GPIO 523 (512+11 as seen on OpenWrt).
- **Fix:** Descriptor-based GPIO via lookup table bridges ath9k consumer
to the correct ath79 GPIO chip lines.
### Step 2.4: FIX QUALITY
**Record:** Fix is obviously correct for the stated problem. Minimal,
follows established `gpiod_add_lookup_table()` patterns. Uses non-devm
`gpiod_get_index()` with manual `gpiod_put()` — appropriate for NULL-
device legacy lookup. Low regression risk; guarded by `CONFIG_ATH9K_AHB`
in gpio-ath79. v6 incorporated reporter feedback from v2 (NULL device
matching, correct `GPIO_LOOKUP_IDX` offsets).
---
## PHASE 3: GIT HISTORY INVESTIGATION
### Step 3.1: BLAME THE CHANGED LINES
**Record:** `git blame` on `hw.c:2719–2735` attributes all lines to
merge commit `5d324e5159d9e` (stable tree squash). Limited per-line
history in this checkout. Buggy `devm_gpio_request_one()` pattern is
present in current 6.18.43 tree at line 2727.
### Step 3.2: FOLLOW THE FIXES: TAG
**Record:** No `Fixes:` tag. N/A.
### Step 3.3: CHECK FILE HISTORY FOR RELATED CHANGES
**Record:** `git log --oneline -20 -- hw.c` and `gpio-ath79.c` only show
merge commits in this stable checkout (shallow/squashed history). Patch
evolved v1→v2→v3→v4→v6 per `b4 dig -a`; v6 is the committed/applied
version. Standalone — not dependent on other patches in the original 1/6
series.
### Step 3.4: CHECK THE AUTHOR'S OTHER COMMITS
**Record:** Linus Walleij is GPIO subsystem maintainer. Long-running
effort to remove global GPIO numbers from ath9k (since v1 in Jan 2024).
### Step 3.5: CHECK FOR DEPENDENT/PREREQUISITE COMMITS
**Record:** Requires gpio-ath79 `gpio_generic_chip` refactor (already
present in 6.18.43). Requires `linux/gpio/machine.h`, `gpiod_get_index`,
`gpiod_set_consumer_name`, `struct_size` — all verified present. Uses
`ctrl->chip.gc.label` which matches current gpio-ath79 structure. **Can
apply standalone.**
---
## PHASE 4: MAILING LIST AND EXTERNAL RESEARCH
### Step 4.1: ORIGINAL PATCH DISCUSSION
**Record:**
- **URL:** https://patch.msgid.link/20260317-descriptors-
wireless-v6-1-b19ecff9cd2b@kernel.org
- **Series:** v1 (2024-01-31) → v2 (2024-04-23) → v3/v4 (2026-03) → **v6
(2026-03-17, final)**
- **Key reviewer feedback (v2, Michał Kępień):** Original v2 had wrong
lookup table `dev_id` and `chip_hwnum`; suggested NULL-device +
`"ath9k"` con_id matching — incorporated in final patch.
- **Stable nominations:** None found in saved mbox thread.
### Step 4.2: WHO REVIEWED
**Record (`b4 dig -w`):** Linus Walleij, Jeff Johnson, Andy Shevchenko,
Arnd Bergmann, Alban Bedel, Bartosz Golaszewski, Toke Høiland-Jørgensen,
Michał Kępień; CC'd linux-wireless@, linux-gpio@.
### Step 4.3: BUG REPORT
**Record:**
- **OpenWrt issue:** Mikrotik RouterBOARD 951Ui-2HnD (AR9344) WLAN LED
broken since ath79 switched to dynamic GPIO base allocation (July
2024). Reporter confirmed GPIO chip works at global offset 523
(=512+11) but ath9k driver could not reach it via legacy API.
- **Severity:** Functional hardware breakage on ath79 routers; not a
kernel crash.
### Step 4.4: RELATED PATCHES
**Record:** Part of a longer ath9k GPIO-descriptor migration series, but
this commit is self-contained for the ath79 AHB legacy path.
### Step 4.5: STABLE MAILING LIST
**Record:** No stable-specific discussion found.
---
## PHASE 5: CODE SEMANTIC ANALYSIS
### Step 5.1: KEY FUNCTIONS
**Record:** `ath79_gpio_register_wifi_descriptors()`,
`ath9k_hw_gpio_cfg_soc()`, `ath9k_hw_gpio_get()`, `ath9k_hw_set_gpio()`,
`ath9k_hw_gpio_free()`, `ath9k_hw_gpio_request()`.
### Step 5.2: TRACE CALLERS
**Record:** `ath9k_hw_gpio_request_{in,out}()` called from:
- `gpio.c` — WLAN LED (`ath_fill_led_pin`, led on/off)
- `gpio.c` — rfkill GPIO read
- `btcoex.c` — Bluetooth coexistence GPIOs
- `main.c` — LED pin setup
- `hw.c` — rfkill init, chainmask GPIO read
**Context:** Device probe and runtime on ath79 SoC routers with
`CONFIG_ATH9K_AHB`.
### Step 5.3: TRACE CALLEES
**Record:** `gpiod_get_index()`, `gpiod_get_value()`,
`gpiod_set_value()`, `gpiod_put()`, `gpiod_add_lookup_table()`,
`GPIO_LOOKUP_IDX()`.
### Step 5.4: CALL CHAIN / REACHABILITY
**Record:** Triggered during ath9k AHB WiFi driver probe and
LED/rfkill/btcoex operation on AR9340/AR9531/AR9550/AR9561 SoCs
(`AR_SREV_SOC`). GPIOs outside `gpio_mask` (e.g., AR9340 mask = `0xF`,
LED on GPIO 11) take the broken `ath9k_hw_gpio_cfg_soc()` path.
**Reachable on every boot** for affected ath79 boards with external GPIO
lines.
### Step 5.5: SIMILAR PATTERNS
**Record:** Other drivers use `gpiod_add_lookup_table()` +
`GPIO_LOOKUP_IDX()` for board-specific GPIO wiring (e.g.,
`sound/soc/samsung/speyside.c`, `drivers/usb/dwc3/dwc3-pci.c`). Same
established pattern.
---
## PHASE 6: CROSS-REFERENCING AGAINST LOCAL TREE (6.18.43)
### Step 6.1: DOES THE BUGGY CODE EXIST?
**Record:** **YES.** Current tree has:
- `devm_gpio_request_one(ah->dev, gpio, ...)` at `hw.c:2727`
- `gpio_get_value(gpio)` / `gpio_set_value(gpio, val)` at
`hw.c:2826,2850`
- `gpio-ath79.c` already uses `gpio_generic_chip` (dynamic GPIO bases)
- `CONFIG_ATH9K_AHB` exists in Kconfig; enabled in
`arch/mips/configs/ath79_defconfig`
The fix is **not** yet in 6.18.43 (mainline commit `34a5329`, dated
2026-03-17).
### Step 6.2: BACKPORT COMPLICATIONS
**Record:** **Clean apply expected.** Current gpio-ath79 structure
(`ctrl->chip.gc.label`, `gpio_generic_chip_init`) matches the patch. No
conflicting changes detected.
### Step 6.3: RELATED FIXES ALREADY PRESENT?
**Record:** `git log --grep` found no related fix already in this tree.
---
## PHASE 7: SUBSYSTEM AND MAINTAINER CONTEXT
### Step 7.1: SUBSYSTEM AND CRITICALITY
**Record:** **Subsystem:** `drivers/gpio` +
`drivers/net/wireless/ath/ath9k` — **IMPORTANT** (embedded router
WiFi/GPIO, not core kernel path).
### Step 7.2: SUBSYSTEM ACTIVITY
**Record:** gpio-ath79 recently refactored to `gpio_generic_chip`
(dynamic bases), which exposed this long-standing ath9k assumption.
Active area for ath79/OpenWrt platforms.
---
## PHASE 8: IMPACT AND RISK ASSESSMENT
### Step 8.1: WHO IS AFFECTED
**Record:** **Platform-specific:** MIPS ath79 SoC devices with built-in
ath9k WiFi (`CONFIG_ATH9K_AHB=y`). Common in OpenWrt routers (TP-Link,
Mikrotik, etc.). Not universal.
### Step 8.2: TRIGGER CONDITIONS
**Record:** Boot with ath9k AHB on AR9340/AR9531/AR9550/AR9561 when a
GPIO line outside the chip's internal `gpio_mask` is needed (WLAN LED,
rfkill, btcoex). **Common on affected hardware.** Not a userspace-
triggerable security issue.
### Step 8.3: FAILURE MODE SEVERITY
**Record:**
- GPIO request failure → WLAN LED non-functional, rfkill/btcoex GPIO
broken
- Wrong GPIO mapping → could toggle unrelated hardware lines (author:
"possibly even dangerous")
- **Severity: MEDIUM-HIGH** for affected platforms (functional breakage
+ potential wrong-pin control); **not CRITICAL** (no crash,
corruption, or security CVE)
### Step 8.4: RISK-BENEFIT
**Record:**
- **Benefit:** Restores correct GPIO operation on ath79 routers; fixes
user-reported OpenWrt breakage; eliminates dangerous wrong-GPIO
mapping
- **Risk:** Very low — ~80 lines, well-reviewed, compile-time gated,
established API pattern
- **Ratio:** Strong benefit for affected users, minimal risk
---
## PHASE 9: FINAL SYNTHESIS
### Step 9.1: EVIDENCE SUMMARY
**FOR backport:**
- Real user-reported bug (Michał Kępień / OpenWrt, Mikrotik AR9344)
- Tested-by reporter on real hardware
- Reviewed by GPIO and wireless maintainers
- Buggy code confirmed present in 6.18.43
- gpio-ath79 already uses dynamic GPIO bases — legacy ath9k code is
broken
- Small, surgical, self-contained fix
- Hardware quirk/workaround exception applies
- Wrong GPIO line control is a safety concern on embedded hardware
**AGAINST backport:**
- Only affects ath79 + ATH9K_AHB platforms (niche vs. entire kernel)
- Primary visible symptom is WLAN LED / GPIO features, not crashes
- No explicit stable nomination in review thread
- Part of a longer GPIO-descriptor migration (though this patch stands
alone)
**Unresolved:** Exact kernel version when gpio-ath79 gained
`gpio_generic_chip` cannot be determined from this stable tree's git
history (squashed).
### Step 9.2: STABLE RULES CHECKLIST
| Criterion | Result |
|-----------|--------|
| 1. Obviously correct and tested? | **PASS** — Reviewed by GPIO
maintainers; Tested-by reporter |
| 2. Fixes a real bug affecting users? | **PASS** — OpenWrt/ath79 router
GPIO breakage confirmed |
| 3. Important issue? | **PASS** — Functional hardware breakage + wrong
GPIO mapping risk on embedded platforms |
| 4. Small and contained? | **PASS** — ~80 lines, 3 files |
| 5. No new features/APIs? | **PASS** — Uses existing gpiod lookup
infrastructure; legacy workaround only |
| 6. Can apply to local tree? | **PASS** — Code matches; prerequisites
present |
### Step 9.3: EXCEPTION CATEGORY
**Record:** **Hardware quirk/workaround** — legacy ath79/ath9k GPIO path
fix for SoCs where device tree does not describe these lines.
### Step 9.4: DECISION RATIONALE
For **Linux 6.18.43**, this commit should be backported. The buggy
legacy GPIO code is present, gpio-ath79 already uses dynamic GPIO
numbering that breaks the old assumptions, and real users on ath79
routers (OpenWrt, Mikrotik, etc.) have confirmed WLAN LED and related
GPIO functionality is broken without this fix. The patch is small, well-
reviewed, tested on hardware, and applies cleanly to the current tree
structure.
---
## Verification
- [Phase 1] Parsed tags: Reported-by/Tested-by Michał Kępień; Reviewed-
by Andy Shevchenko; Acked-by Bartosz Golaszewski, Toke Høiland-
Jørgensen
- [Phase 1] No Fixes:/Cc: stable tags (expected)
- [Phase 2] Diff: 3 files, ~+80/-13; gpio lookup table + gpiod
descriptor migration in ath9k
- [Phase 2] Verified buggy code: `devm_gpio_request_one()` at hw.c:2727,
`gpio_get_value(gpio)` at hw.c:2826
- [Phase 3] `git describe HEAD`: v6.18.43; `make kernelversion`: 6.18.43
- [Phase 3] `git blame hw.c:2719-2735`: lines present with legacy API
(history squashed to merge commit)
- [Phase 3] No Fixes: tag to follow
- [Phase 4] `b4 dig -c 34a5329`: matched v6 thread at
patch.msgid.link/20260317-descriptors-
wireless-v6-1-b19ecff9cd2b@kernel.org
- [Phase 4] `b4 dig -a`: v1→v2→v3→v4→v6 series; v6 is latest
- [Phase 4] `b4 dig -w`: GPIO and wireless maintainers CC'd
- [Phase 4] Spinics v2 reply from Michał Kępień: documents OpenWrt
breakage and lookup table fixes
- [Phase 4] OpenWrt PR #17402: Mikrotik AR9344 WLAN LED broken since
dynamic GPIO bases
- [Phase 4] No stable nomination found in mbox thread
- [Phase 5] Callers verified via grep: gpio.c, btcoex.c, main.c, hw.c
- [Phase 5] AR9340_GPIO_MASK = 0xF — GPIO 11 (reported LED pin) uses soc
path outside mask
- [Phase 6] Buggy code confirmed present; fix NOT present in 6.18.43
- [Phase 6] gpio-ath79 uses `gpio_generic_chip` in current tree
- [Phase 6] `CONFIG_ATH9K_AHB` exists; `linux/gpio/machine.h` and
`gpiod_*` APIs present
- [Phase 6] Patch uses `ctrl->chip.gc.label` matching current gpio-ath79
structure
- [Phase 8] Failure mode: GPIO misrouting / LED-rfkill-btcoex breakage
on ath79 SoCs; severity MEDIUM-HIGH for affected hardware
- UNVERIFIED: Exact upstream commit that introduced gpio-ath79
`gpio_generic_chip` refactor (stable tree history is squashed)
**YES**
drivers/gpio/gpio-ath79.c | 57 ++++++++++++++++++++++++++++-
drivers/net/wireless/ath/ath9k/hw.c | 33 +++++++++++------
drivers/net/wireless/ath/ath9k/hw.h | 3 +-
3 files changed, 80 insertions(+), 13 deletions(-)
diff --git a/drivers/gpio/gpio-ath79.c b/drivers/gpio/gpio-ath79.c
index 2ad9f6ac66362..85bd994d15d48 100644
--- a/drivers/gpio/gpio-ath79.c
+++ b/drivers/gpio/gpio-ath79.c
@@ -11,6 +11,7 @@
#include <linux/device.h>
#include <linux/gpio/driver.h>
#include <linux/gpio/generic.h>
+#include <linux/gpio/machine.h> /* For WLAN GPIOs */
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/mod_devicetable.h>
@@ -214,6 +215,56 @@ static const struct of_device_id ath79_gpio_of_match[] = {
};
MODULE_DEVICE_TABLE(of, ath79_gpio_of_match);
+#if IS_ENABLED(CONFIG_ATH9K_AHB)
+/*
+ * This registers all of the ath79k GPIOs as descriptors to be picked
+ * directly from the ATH79K wifi driver if the two are jitted together
+ * in the same SoC.
+ */
+#define ATH79K_WIFI_DESCS 32
+static int ath79_gpio_register_wifi_descriptors(struct device *dev,
+ const char *label)
+{
+ struct gpiod_lookup_table *lookup;
+ int i;
+
+ /* Create a gpiod lookup using gpiochip-local offsets + 1 for NULL */
+ lookup = devm_kzalloc(dev,
+ struct_size(lookup, table, ATH79K_WIFI_DESCS + 1),
+ GFP_KERNEL);
+ if (!lookup)
+ return -ENOMEM;
+
+ /*
+ * Ugly system-wide lookup for the NULL device: we know this
+ * is already NULL but explicitly assign it here for people to
+ * know what is going on. (Yes this is an ugly legacy hack, live
+ * with it.)
+ */
+ lookup->dev_id = NULL;
+
+ for (i = 0; i < ATH79K_WIFI_DESCS; i++) {
+ lookup->table[i] =
+ /*
+ * Set the HW offset on the chip and the lookup
+ * index to the same value, so looking up index 0
+ * will get HW offset 0, index 1 HW offset 1 etc.
+ */
+ GPIO_LOOKUP_IDX(label, i, "ath9k", i, GPIO_ACTIVE_HIGH);
+ }
+
+ gpiod_add_lookup_table(lookup);
+
+ return 0;
+}
+#else
+static int ath79_gpio_register_wifi_descriptors(struct device *dev,
+ const char *label)
+{
+ return 0;
+}
+#endif
+
static int ath79_gpio_probe(struct platform_device *pdev)
{
struct gpio_generic_chip_config config;
@@ -276,7 +327,11 @@ static int ath79_gpio_probe(struct platform_device *pdev)
girq->handler = handle_simple_irq;
}
- return devm_gpiochip_add_data(dev, &ctrl->chip.gc, ctrl);
+ err = devm_gpiochip_add_data(dev, &ctrl->chip.gc, ctrl);
+ if (err)
+ return err;
+
+ return ath79_gpio_register_wifi_descriptors(dev, ctrl->chip.gc.label);
}
static struct platform_driver ath79_gpio_driver = {
diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c
index 14de62c1a32bd..9a32cf683c4fd 100644
--- a/drivers/net/wireless/ath/ath9k/hw.c
+++ b/drivers/net/wireless/ath/ath9k/hw.c
@@ -21,7 +21,7 @@
#include <linux/time.h>
#include <linux/bitops.h>
#include <linux/etherdevice.h>
-#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
#include <linux/unaligned.h>
#include "hw.h"
@@ -2719,19 +2719,28 @@ static void ath9k_hw_gpio_cfg_output_mux(struct ath_hw *ah, u32 gpio, u32 type)
static void ath9k_hw_gpio_cfg_soc(struct ath_hw *ah, u32 gpio, bool out,
const char *label)
{
+ enum gpiod_flags flags = out ? GPIOD_OUT_LOW : GPIOD_IN;
+ struct gpio_desc *gpiod;
int err;
- if (ah->caps.gpio_requested & BIT(gpio))
+ if (ah->gpiods[gpio])
return;
- err = devm_gpio_request_one(ah->dev, gpio, out ? GPIOF_OUT_INIT_LOW : GPIOF_IN, label);
+ /*
+ * Obtains a system specific GPIO descriptor from another GPIO controller.
+ * Ideally this should come from the device tree, this is a legacy code
+ * path.
+ */
+ gpiod = gpiod_get_index(NULL, "ath9k", gpio, flags);
+ err = PTR_ERR_OR_ZERO(gpiod);
if (err) {
ath_err(ath9k_hw_common(ah), "request GPIO%d failed:%d\n",
gpio, err);
return;
}
- ah->caps.gpio_requested |= BIT(gpio);
+ gpiod_set_consumer_name(gpiod, label);
+ ah->gpiods[gpio] = gpiod;
}
static void ath9k_hw_gpio_cfg_wmac(struct ath_hw *ah, u32 gpio, bool out,
@@ -2791,10 +2800,12 @@ void ath9k_hw_gpio_free(struct ath_hw *ah, u32 gpio)
if (!AR_SREV_SOC(ah))
return;
- WARN_ON(gpio >= ah->caps.num_gpio_pins);
+ if (ah->gpiods[gpio]) {
+ gpiod_put(ah->gpiods[gpio]);
+ ah->gpiods[gpio] = NULL;
+ }
- if (ah->caps.gpio_requested & BIT(gpio))
- ah->caps.gpio_requested &= ~BIT(gpio);
+ WARN_ON(gpio >= ah->caps.num_gpio_pins);
}
EXPORT_SYMBOL(ath9k_hw_gpio_free);
@@ -2822,8 +2833,8 @@ u32 ath9k_hw_gpio_get(struct ath_hw *ah, u32 gpio)
val = REG_READ(ah, AR_GPIO_IN(ah)) & BIT(gpio);
else
val = MS_REG_READ(AR, gpio);
- } else if (BIT(gpio) & ah->caps.gpio_requested) {
- val = gpio_get_value(gpio) & BIT(gpio);
+ } else if (ah->gpiods[gpio]) {
+ val = gpiod_get_value(ah->gpiods[gpio]);
} else {
WARN_ON(1);
}
@@ -2846,8 +2857,8 @@ void ath9k_hw_set_gpio(struct ath_hw *ah, u32 gpio, u32 val)
AR7010_GPIO_OUT : AR_GPIO_IN_OUT(ah);
REG_RMW(ah, out_addr, val << gpio, BIT(gpio));
- } else if (BIT(gpio) & ah->caps.gpio_requested) {
- gpio_set_value(gpio, val);
+ } else if (ah->gpiods[gpio]) {
+ gpiod_set_value(ah->gpiods[gpio], val);
} else {
WARN_ON(1);
}
diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h
index eaa07d6dbde00..d9d2f64c55700 100644
--- a/drivers/net/wireless/ath/ath9k/hw.h
+++ b/drivers/net/wireless/ath/ath9k/hw.h
@@ -19,6 +19,7 @@
#include <linux/if_ether.h>
#include <linux/delay.h>
+#include <linux/gpio/consumer.h>
#include <linux/io.h>
#include <linux/firmware.h>
@@ -302,7 +303,6 @@ struct ath9k_hw_capabilities {
u8 max_rxchains;
u8 num_gpio_pins;
u32 gpio_mask;
- u32 gpio_requested;
u8 rx_hp_qdepth;
u8 rx_lp_qdepth;
u8 rx_status_len;
@@ -783,6 +783,7 @@ struct ath_hw {
struct ath9k_hw_capabilities caps;
struct ath9k_channel channels[ATH9K_NUM_CHANNELS];
struct ath9k_channel *curchan;
+ struct gpio_desc *gpiods[32];
union {
struct ar5416_eeprom_def def;
--
2.53.0
^ permalink raw reply related [flat|nested] 12+ messages in thread
end of thread, other threads:[~2026-08-31 13:52 UTC | newest]
Thread overview: 12+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
[not found] <20260831133314.4125787-1-sashal@kernel.org>
2026-08-31 13:21 ` [PATCH AUTOSEL 6.18] pinctrl: renesas: rzg2l: Add SR register cache for PM suspend/resume Sasha Levin
2026-08-31 13:22 ` [PATCH AUTOSEL 6.18] pinctrl: qcom: Register functions before enabling pinctrl Sasha Levin
2026-08-31 13:23 ` [PATCH AUTOSEL 6.18] pinctrl: mediatek: common-v1: bypass pinctrl GPIO layer in set GPIO direction Sasha Levin
2026-08-31 13:24 ` [PATCH AUTOSEL 6.18] pinctrl: meson: amlogic-a4: use nolock get range Sasha Levin
2026-08-31 13:24 ` [PATCH AUTOSEL 6.18] gpiolib: acpi: Add robust bounds-checking for GPIO pin resources Sasha Levin
2026-08-31 13:26 ` [PATCH AUTOSEL 6.18] gpio: usbio: Add ACPI device-id for NVL platforms Sasha Levin
2026-08-31 13:27 ` [PATCH AUTOSEL 6.18] pinctrl: mediatek: paris: bypass pinctrl GPIO layer in set GPIO direction Sasha Levin
2026-08-31 13:28 ` [PATCH AUTOSEL 6.18-6.12] pinctrl: renesas: rzg2l: Handle RZ/V2H(P) IOLH configuration in PM cache Sasha Levin
2026-08-31 13:28 ` [PATCH AUTOSEL 6.18-5.10] gpio: pisosr: Read "ngpios" as u32 Sasha Levin
2026-08-31 13:29 ` [PATCH AUTOSEL 6.18-5.10] gpio: dwapb: Mask interrupts at hardware initialization Sasha Levin
2026-08-31 13:29 ` [PATCH AUTOSEL 6.18-6.1] pinctrl: renesas: rzv2m: Use -ENOTSUPP instead of -EOPNOTSUPP Sasha Levin
2026-08-31 13:31 ` [PATCH AUTOSEL 6.18] wifi: ath9k: Obtain system GPIOS from descriptors Sasha Levin
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox