From: Praveen Talari praveen.talari@oss.qualcomm.com
[ Upstream commit 1c2e70397b4125022dba80f6111271a37fb36bae ]
Replace disable_irq() with disable_irq_nosync() in msm_pinmux_set_mux() to prevent deadlock when wakeup IRQ is triggered on the same GPIO being reconfigured.
The issue occurs when a wakeup IRQ is triggered on a GPIO and the IRQ handler attempts to reconfigure the same GPIO's pinmux. In this scenario, msm_pinmux_set_mux() calls disable_irq() which waits for the currently running IRQ handler to complete, creating a circular dependency that results in deadlock.
Using disable_irq_nosync() avoids waiting for the IRQ handler to complete, preventing the deadlock condition while still properly disabling the interrupt during pinmux reconfiguration.
Suggested-by: Prasad Sodagudi prasad.sodagudi@oss.qualcomm.com Signed-off-by: Praveen Talari praveen.talari@oss.qualcomm.com Reviewed-by: Bjorn Andersson andersson@kernel.org Signed-off-by: Linus Walleij linus.walleij@linaro.org Signed-off-by: Sasha Levin sashal@kernel.org ---
LLM Generated explanations, may be completely bogus:
## COMPREHENSIVE ANALYSIS
### 1. COMMIT MESSAGE & CODE ANALYSIS
**Problem Identified:** A circular dependency deadlock occurs in the Qualcomm pin control driver (`pinctrl-msm.c`). **Mechanism:** The function `msm_pinmux_set_mux()` is responsible for changing a pin's function. When switching away from a GPIO that has an interrupt enabled, it calls `disable_irq()` to mask the interrupt. **The Deadlock:** `disable_irq()` synchronously waits for any running IRQ handlers to complete. If `msm_pinmux_set_mux()` is called *from within* the handler of the very interrupt being disabled (common in wakeup scenarios where a device wakes up and immediately reconfigures pins), the code waits for itself to finish, resulting in a hard system hang. **The Fix:** The commit replaces `disable_irq()` with `disable_irq_nosync()`. This variant masks the interrupt without waiting for pending handlers, effectively breaking the circular dependency while maintaining the required hardware state safety.
### 2. DEEP CODE RESEARCH
**History and Origin:** - The problematic `disable_irq()` call was introduced in commit `cf9d052aa6005f` ("pinctrl: qcom: Don't clear pending interrupts when enabling"), merged in January 2021 (Linux v5.11). - This means the bug has been present for approximately 4 years and affects multiple Long Term Support (LTS) kernels, including 5.15.y, 6.1.y, and 6.6.y.
**Code Correctness:** - `disable_irq_nosync()` is the specific API designed for this exact use case (disabling an interrupt from within its own handler or call chain). - The change is surgical (one line) and does not alter the logical flow of the driver other than removing the synchronous wait. - The interrupt is properly re-enabled later in the function (if switching back to GPIO), ensuring the logic remains consistent.
### 3. BUG SEVERITY AND USER IMPACT
**Severity:** **CRITICAL**. A deadlock causes a complete system freeze, requiring a hard reset. **Target Users:** This affects devices using Qualcomm SoCs (MSM/QCOM), which includes a vast ecosystem of: - Android smartphones and tablets - Embedded IoT devices - Chromebooks - Automotive IVI systems **Trigger:** The issue is triggered during wakeup events when a GPIO IRQ fires and the handler attempts to reconfigure the pinmux. This is a realistic scenario in power management flows (suspend/resume).
### 4. STABLE KERNEL RULES COMPLIANCE
This commit perfectly fits the criteria for stable backporting: - **Obviously Correct:** It uses the standard kernel API (`_nosync`) to resolve a known deadlock pattern. - **Fixes a Real Bug:** It addresses a system hang/deadlock. - **Small Scope:** Only 1 line changed in 1 file. - **No New Features:** Pure bug fix. - **Low Risk:** The fix relaxes a synchronization constraint that was incorrect for this context; it does not introduce complex new logic.
### 5. BACKPORT FEASIBILITY
Because the surrounding code has been stable since v5.11, this patch should apply cleanly (cherry-pick) to all active stable branches: - v6.12.y - v6.11.y - v6.6.y (LTS) - v6.1.y (LTS) - v5.15.y (LTS)
### CONCLUSION
This is a critical fix for a deadlock that affects widely deployed hardware. The solution is trivial, correct, and low-risk. Despite the lack of a "Cc: stable" tag, the nature of the bug (system hang) makes it a mandatory backport candidate.
**YES**
drivers/pinctrl/qcom/pinctrl-msm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/pinctrl/qcom/pinctrl-msm.c b/drivers/pinctrl/qcom/pinctrl-msm.c index 83eb075b6bfa1..3d6601dc6fcc5 100644 --- a/drivers/pinctrl/qcom/pinctrl-msm.c +++ b/drivers/pinctrl/qcom/pinctrl-msm.c @@ -215,7 +215,7 @@ static int msm_pinmux_set_mux(struct pinctrl_dev *pctldev, */ if (d && i != gpio_func && !test_and_set_bit(d->hwirq, pctrl->disabled_for_mux)) - disable_irq(irq); + disable_irq_nosync(irq);
raw_spin_lock_irqsave(&pctrl->lock, flags);