patches.lists.linux.dev archive mirror
 help / color / mirror / Atom feed
From: Sasha Levin <sashal@kernel.org>
To: patches@lists.linux.dev, stable@vger.kernel.org
Cc: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>,
	Mark Brown <broonie@kernel.org>, Sasha Levin <sashal@kernel.org>,
	alexander.deucher@amd.com, alexandre.f.demers@gmail.com
Subject: [PATCH AUTOSEL 6.17] ASoC: nau8821: Avoid unnecessary blocking in IRQ handler
Date: Mon, 27 Oct 2025 20:38:53 -0400	[thread overview]
Message-ID: <20251028003940.884625-9-sashal@kernel.org> (raw)
In-Reply-To: <20251028003940.884625-1-sashal@kernel.org>

From: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>

[ Upstream commit ee70bacef1c6050e4836409927294d744dbcfa72 ]

The interrupt handler offloads the microphone detection logic to
nau8821_jdet_work(), which implies a sleep operation.  However, before
being able to process any subsequent hotplug event, the interrupt
handler needs to wait for any prior scheduled work to complete.

Move the sleep out of jdet_work by converting it to a delayed work.
This eliminates the undesired blocking in the interrupt handler when
attempting to cancel a recently scheduled work item and should help
reducing transient input reports that might confuse user-space.

Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
Link: https://patch.msgid.link/20251003-nau8821-jdet-fixes-v1-5-f7b0e2543f09@collabora.com
Signed-off-by: Mark Brown <broonie@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---

LLM Generated explanations, may be completely bogus:

Based on my analysis using semantic code analysis tools and repository
examination, here is my assessment:

## **Backport Status: YES**

## Detailed Analysis:

### 1. Semantic Analysis Tools Used:

- **mcp__semcode__find_function**: Located the three affected functions
  (`nau8821_jdet_work`, `nau8821_interrupt`,
  `nau8821_enable_jack_detect`)
- **mcp__semcode__find_callers**: Identified that
  `nau8821_enable_jack_detect` is called by 2 AMD machine drivers
  (acp5x_8821_init, acp_8821_init)
- **mcp__semcode__find_type**: Examined the `struct nau8821` definition
  to understand the data structure change
- **Grep**: Analyzed all `cancel_work_sync` calls and `msleep` usage
  patterns in the driver
- **Git analysis**: Verified no follow-up fixes or reverts exist for
  this commit

### 2. Code Analysis - What Changed:

The commit addresses a **kernel programming anti-pattern: blocking in an
interrupt handler**.

**Before (problematic code):**
- `nau8821_jdet_work` (work handler) contains `msleep(20)` at
  sound/soc/codecs/nau8821.c:1115
- IRQ handler calls `cancel_work_sync()` at lines 1208 and 1222, which
  blocks waiting for work completion
- If work is sleeping, IRQ handler blocks for 20ms+ (unacceptable
  latency)

**After (fixed code):**
- Converted `struct work_struct` → `struct delayed_work`
- Removed `msleep(20)` from work handler
- Moved MICBIAS enable to IRQ handler, schedule delayed work with
  `msecs_to_jiffies(20)`
- Changed to `cancel_delayed_work_sync()` - won't block on sleeping work

### 3. Impact Scope Assessment:

**Call Graph Analysis:**
- Affects NAU8821 audio codec driver (used on AMD Vangogh platforms)
- 2 machine drivers call this code (AMD ACP platforms)
- User-triggerable via hardware jack insertion/ejection events
- Affects real consumer hardware (likely Steam Deck and similar AMD
  devices)

**Exposure:**
- Hardware interrupt path → directly user-facing
- Bug causes measurable interrupt latency (20ms blocking)
- Commit message states it helps "reducing transient input reports that
  might confuse user-space"

### 4. Complexity and Risk Analysis:

**Change Complexity: LOW**
- Only 2 files modified: nau8821.c (22 lines) and nau8821.h (2 lines)
- Simple type conversion: `work_struct` → `delayed_work`
- No API changes, no new dependencies
- Logic remains functionally equivalent (same 20ms delay, just
  implemented differently)

**Regression Risk: VERY LOW**
- Standard kernel pattern (delayed_work is designed exactly for this use
  case)
- Similar fix exists in WM8350 codec: "Use delayed work to debounce
  WM8350 jack IRQs"
- No follow-up fixes found in git history (ee70bacef1c60..HEAD shows no
  corrections)
- 4 subsequent commits to driver are unrelated (DMI quirks, interrupt
  clearing)

### 5. Backport Suitability Criteria:

| Criterion | Assessment | Details |
|-----------|------------|---------|
| Fixes important bug? | ✅ YES | Blocking in IRQ handler violates kernel
design |
| Small and contained? | ✅ YES | 24 lines changed, single subsystem |
| No new features? | ✅ YES | Pure bug fix |
| No architectural changes? | ✅ YES | Just work→delayed_work conversion
|
| Low regression risk? | ✅ YES | Standard pattern, no follow-up fixes |
| User impact? | ✅ YES | Improves latency, reduces spurious events |
| Has stable tag? | ❌ NO | No "Cc: stable" or "Fixes:" tag |

### 6. Why Backport Despite No Stable Tag:

1. **Correctness Issue**: Blocking in IRQ handlers is a documented
   kernel anti-pattern that can cause system-wide latency issues
2. **Real Hardware Impact**: Affects consumer devices with NAU8821 codec
   (AMD platforms)
3. **Safe Fix**: Uses standard kernel pattern (delayed_work), minimal
   code change
4. **Proven Stable**: Already in v6.18-rc2 with no reported issues or
   fixes
5. **User-Visible Benefit**: Reduces interrupt latency and spurious jack
   detection events

### Recommendation:

**This commit should be backported** to stable kernels that support the
affected hardware. It fixes a legitimate kernel programming bug
(blocking in IRQ context) with a small, safe, well-tested change. The
absence of an explicit stable tag appears to be an oversight rather than
intentional exclusion, given that the fix addresses a clear correctness
issue following established kernel patterns.

 sound/soc/codecs/nau8821.c | 22 ++++++++++++----------
 sound/soc/codecs/nau8821.h |  2 +-
 2 files changed, 13 insertions(+), 11 deletions(-)

diff --git a/sound/soc/codecs/nau8821.c b/sound/soc/codecs/nau8821.c
index a8ff2ce70be9a..4fa9a785513e5 100644
--- a/sound/soc/codecs/nau8821.c
+++ b/sound/soc/codecs/nau8821.c
@@ -1104,16 +1104,12 @@ static void nau8821_eject_jack(struct nau8821 *nau8821)
 static void nau8821_jdet_work(struct work_struct *work)
 {
 	struct nau8821 *nau8821 =
-		container_of(work, struct nau8821, jdet_work);
+		container_of(work, struct nau8821, jdet_work.work);
 	struct snd_soc_dapm_context *dapm = nau8821->dapm;
 	struct snd_soc_component *component = snd_soc_dapm_to_component(dapm);
 	struct regmap *regmap = nau8821->regmap;
 	int jack_status_reg, mic_detected, event = 0, event_mask = 0;
 
-	snd_soc_component_force_enable_pin(component, "MICBIAS");
-	snd_soc_dapm_sync(dapm);
-	msleep(20);
-
 	regmap_read(regmap, NAU8821_R58_I2C_DEVICE_ID, &jack_status_reg);
 	mic_detected = !(jack_status_reg & NAU8821_KEYDET);
 	if (mic_detected) {
@@ -1146,6 +1142,7 @@ static void nau8821_jdet_work(struct work_struct *work)
 		snd_soc_component_disable_pin(component, "MICBIAS");
 		snd_soc_dapm_sync(dapm);
 	}
+
 	event_mask |= SND_JACK_HEADSET;
 	snd_soc_jack_report(nau8821->jack, event, event_mask);
 }
@@ -1194,6 +1191,7 @@ static irqreturn_t nau8821_interrupt(int irq, void *data)
 {
 	struct nau8821 *nau8821 = (struct nau8821 *)data;
 	struct regmap *regmap = nau8821->regmap;
+	struct snd_soc_component *component;
 	int active_irq, event = 0, event_mask = 0;
 
 	if (regmap_read(regmap, NAU8821_R10_IRQ_STATUS, &active_irq)) {
@@ -1205,7 +1203,7 @@ static irqreturn_t nau8821_interrupt(int irq, void *data)
 
 	if ((active_irq & NAU8821_JACK_EJECT_IRQ_MASK) ==
 		NAU8821_JACK_EJECT_DETECTED) {
-		cancel_work_sync(&nau8821->jdet_work);
+		cancel_delayed_work_sync(&nau8821->jdet_work);
 		regmap_update_bits(regmap, NAU8821_R71_ANALOG_ADC_1,
 			NAU8821_MICDET_MASK, NAU8821_MICDET_DIS);
 		nau8821_eject_jack(nau8821);
@@ -1219,12 +1217,15 @@ static irqreturn_t nau8821_interrupt(int irq, void *data)
 		nau8821_irq_status_clear(regmap, NAU8821_KEY_RELEASE_IRQ);
 	} else if ((active_irq & NAU8821_JACK_INSERT_IRQ_MASK) ==
 		NAU8821_JACK_INSERT_DETECTED) {
-		cancel_work_sync(&nau8821->jdet_work);
+		cancel_delayed_work_sync(&nau8821->jdet_work);
 		regmap_update_bits(regmap, NAU8821_R71_ANALOG_ADC_1,
 			NAU8821_MICDET_MASK, NAU8821_MICDET_EN);
 		if (nau8821_is_jack_inserted(regmap)) {
-			/* detect microphone and jack type */
-			schedule_work(&nau8821->jdet_work);
+			/* Detect microphone and jack type */
+			component = snd_soc_dapm_to_component(nau8821->dapm);
+			snd_soc_component_force_enable_pin(component, "MICBIAS");
+			snd_soc_dapm_sync(nau8821->dapm);
+			schedule_delayed_work(&nau8821->jdet_work, msecs_to_jiffies(20));
 			/* Turn off insertion interruption at manual mode */
 			nau8821_setup_inserted_irq(nau8821);
 		} else {
@@ -1661,7 +1662,8 @@ int nau8821_enable_jack_detect(struct snd_soc_component *component,
 
 	nau8821->jack = jack;
 	/* Initiate jack detection work queue */
-	INIT_WORK(&nau8821->jdet_work, nau8821_jdet_work);
+	INIT_DELAYED_WORK(&nau8821->jdet_work, nau8821_jdet_work);
+
 	ret = devm_request_threaded_irq(nau8821->dev, nau8821->irq, NULL,
 		nau8821_interrupt, IRQF_TRIGGER_LOW | IRQF_ONESHOT,
 		"nau8821", nau8821);
diff --git a/sound/soc/codecs/nau8821.h b/sound/soc/codecs/nau8821.h
index f0935ffafcbec..88602923780d8 100644
--- a/sound/soc/codecs/nau8821.h
+++ b/sound/soc/codecs/nau8821.h
@@ -561,7 +561,7 @@ struct nau8821 {
 	struct regmap *regmap;
 	struct snd_soc_dapm_context *dapm;
 	struct snd_soc_jack *jack;
-	struct work_struct jdet_work;
+	struct delayed_work jdet_work;
 	int irq;
 	int clk_id;
 	int micbias_voltage;
-- 
2.51.0


  parent reply	other threads:[~2025-10-28  0:40 UTC|newest]

Thread overview: 26+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-10-28  0:38 [PATCH AUTOSEL 6.17-6.1] smb/server: fix possible memory leak in smb2_read() Sasha Levin
2025-10-28  0:38 ` [PATCH AUTOSEL 6.17-5.4] NFS4: Fix state renewals missing after boot Sasha Levin
2025-10-28  0:38 ` [PATCH AUTOSEL 6.17-6.12] drm/amdgpu: remove two invalid BUG_ON()s Sasha Levin
2025-10-28  0:38 ` [PATCH AUTOSEL 6.17-5.15] NFS: check if suid/sgid was cleared after a write as needed Sasha Levin
2025-10-28  0:38 ` [PATCH AUTOSEL 6.17-6.12] HID: logitech-hidpp: Add HIDPP_QUIRK_RESET_HI_RES_SCROLL Sasha Levin
2025-10-28  0:38 ` [PATCH AUTOSEL 6.17-5.4] ASoC: max98090/91: fixed max98091 ALSA widget powering up/down Sasha Levin
2025-10-28  0:38 ` [PATCH AUTOSEL 6.17] ALSA: hda/realtek: Fix mute led for HP Omen 17-cb0xxx Sasha Levin
2025-10-28  0:38 ` [PATCH AUTOSEL 6.17-5.10] RISC-V: clear hot-unplugged cores from all task mm_cpumasks to avoid rfence errors Sasha Levin
2025-10-28  0:38 ` Sasha Levin [this message]
2025-10-28  0:38 ` [PATCH AUTOSEL 6.17-5.4] HID: quirks: avoid Cooler Master MM712 dongle wakeup bug Sasha Levin
2025-10-28  0:38 ` [PATCH AUTOSEL 6.17] drm/amdkfd: fix suspend/resume all calls in mes based eviction path Sasha Levin
2025-10-28  0:38 ` [PATCH AUTOSEL 6.17-6.12] exfat: fix improper check of dentry.stream.valid_size Sasha Levin
2025-10-28  0:38 ` [PATCH AUTOSEL 6.17] io_uring: fix unexpected placement on same size resizing Sasha Levin
2025-10-28  0:38 ` [PATCH AUTOSEL 6.17] drm/amd: Disable ASPM on SI Sasha Levin
2025-10-28  0:38 ` [PATCH AUTOSEL 6.17-6.6] riscv: acpi: avoid errors caused by probing DT devices when ACPI is used Sasha Levin
2025-10-28  0:39 ` [PATCH AUTOSEL 6.17-6.1] drm/amd/pm: Disable MCLK switching on SI at high pixel clocks Sasha Levin
2025-10-28  0:39 ` [PATCH AUTOSEL 6.17-6.12] drm/amdgpu: hide VRAM sysfs attributes on GPUs without VRAM Sasha Levin
2025-10-28  0:39 ` [PATCH AUTOSEL 6.17] fs: return EOPNOTSUPP from file_setattr/file_getattr syscalls Sasha Levin
2025-10-28  0:39 ` [PATCH AUTOSEL 6.17-6.12] NFS4: Apply delay_retrans to async operations Sasha Levin
2025-10-28  0:39 ` [PATCH AUTOSEL 6.17-6.1] drm/amdgpu: Fix NULL pointer dereference in VRAM logic for APU devices Sasha Levin
2025-10-28  0:39 ` [PATCH AUTOSEL 6.17] ixgbe: handle IXGBE_VF_FEATURES_NEGOTIATE mbox cmd Sasha Levin
2025-10-28  0:39 ` [PATCH AUTOSEL 6.17] ixgbe: handle IXGBE_VF_GET_PF_LINK_STATE mailbox operation Sasha Levin
2025-10-28  0:39 ` [PATCH AUTOSEL 6.17-6.6] HID: quirks: Add ALWAYS_POLL quirk for VRS R295 steering wheel Sasha Levin
2025-10-28  0:39 ` [PATCH AUTOSEL 6.17] HID: intel-thc-hid: intel-quickspi: Add ARL PCI Device Id's Sasha Levin
2025-10-28  0:39 ` [PATCH AUTOSEL 6.17-6.12] HID: nintendo: Wait longer for initial probe Sasha Levin
2025-10-28  0:39 ` [PATCH AUTOSEL 6.17-6.1] smb/server: fix possible refcount leak in smb2_sess_setup() Sasha Levin

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20251028003940.884625-9-sashal@kernel.org \
    --to=sashal@kernel.org \
    --cc=alexander.deucher@amd.com \
    --cc=alexandre.f.demers@gmail.com \
    --cc=broonie@kernel.org \
    --cc=cristian.ciocaltea@collabora.com \
    --cc=patches@lists.linux.dev \
    --cc=stable@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).