From nobody Tue Jun 16 19:36:52 2026 Received: from mail-dl1-f42.google.com (mail-dl1-f42.google.com [74.125.82.42]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 2E89C37757D for ; Wed, 29 Apr 2026 18:34:21 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=74.125.82.42 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1777487663; cv=none; b=WadSpE6f7GLNWsKsv6tiqwpsJEadRPUEAr4i8JLlntvKAJKec0DNGnrTSgH3OBaTSUgWLMJWaq1bgYLeA0TdqCvlrynjfda8bH+z63mpFMDh4MNiWphvIaToeTvt4gVPovqWRqlaYfzLvbUxW/ovNAXYDgemAfdIGGagqIlx/Io= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1777487663; c=relaxed/simple; bh=ggB6iqNXAUdCdmuPFrKjyW2XjK/FQ6ji9Jf6A5CZqXY=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:To:Cc; b=ZurwVOX0UYwHK/U4qYYSg0W2ebh1g6cJ34aZEaMRZhftIIFV2tLGi5JFTE7yV0WdVoiE99yzBhswW8mMXqkrqcj/VhVubCP2frvQ04/gqYDMPMOuYsIfI9pYS+o2Y8gJDrDwEBAsGhqeSZfqfBhakmnSglHLrM7fuK+KSg63Dn0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=jE/YGvp2; arc=none smtp.client-ip=74.125.82.42 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="jE/YGvp2" Received: by mail-dl1-f42.google.com with SMTP id a92af1059eb24-12c726ef332so74709c88.1 for ; Wed, 29 Apr 2026 11:34:21 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1777487660; x=1778092460; darn=vger.kernel.org; h=cc:to:message-id:content-transfer-encoding:mime-version:subject :date:from:from:to:cc:subject:date:message-id:reply-to; bh=dWNz7f7Eq6/FoxVuvOcnlGaVoOPITwz8TC8gscczLsw=; b=jE/YGvp2dMK9v0gJT3sGP5/SXyQau2J1qALs6IuPDPUd7JMkZiCpQN8TYcl6fbHFkc 8rq0G/OvZqnga4Z0zyv/HELe1EuPpDUZKTJVkUDJ8eJB3NWNFvv6vBXphCYLZUNZAWZ8 zqTUKu71SE0DwITpBAjq3JHSlkFg9gN/O5L1dorF0zvEnkuEpsRs6m1P3ak8iuAhEU1+ AQ3lVtjoD2ha7duhZQvcmEH6pz059iXZrB5vibKy7WGL4NXxOZBTTPYox3D4DLBPGAEo 3IFnPari7RURgEHZR7v1vvDHABfhy/QWWI1C2dGhLlA8LjO1AKWQTzHr0xcFbbD8+HSU co+Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1777487660; x=1778092460; h=cc:to:message-id:content-transfer-encoding:mime-version:subject :date:from:x-gm-gg:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to; bh=dWNz7f7Eq6/FoxVuvOcnlGaVoOPITwz8TC8gscczLsw=; b=LoRowHl11Y9d62NArXbO7fqY6FcNsnrkM9T0NVo1N1mNrlUYhdOoyQsAQf9yLzY8EW yAhYBroMatY98uSH2AioYFrYyJwnFymmNf1Ze4Ur+IPHycb07BJqTHeJ1mQFAmvNoOJW aqGp3QSiMpropHRPu5EIWAnNCal+VgOCbCNx/U5ipuP9t5gp3p339uCfzbZIa4FFWU8m /3t1xpGp7ZzMtzbgRNExg/+aquVSqRMIJfefsLmjkW6UZXJXG+20UV894JUA/i+XgZ08 ivlDz1FeeVUUMKIWcxyTTRVTsSBziaBq5XO/rrO/JwK4D+/hNpD/MGG8rG+Mn+YplkGj EiwA== X-Forwarded-Encrypted: i=1; AFNElJ/2mpOTXaQ51xXGwYJ0ktMlKxQeBI//4SeYYla7CmRro7Jm2VzzD68jHQl69tKrDttaphYGf1GcgbvWpsU=@vger.kernel.org X-Gm-Message-State: AOJu0YxIlQwYx0wC3olmHRBIj/aFmebHy6osBOqbWiHQT+REpFFy2b07 c8Mnx+jsY6beYNsltvS+/YPoT35pxfn/lSnL5p0Cm87fi+pbxRbkNjjw X-Gm-Gg: AeBDieubDjH5gvE0GRJW8wEO77MaEXR4KMAmm1beT4iV7ic2M226/ezyVCEa7q8uEk+ UmYg0UVFLSFA9aMLSRPboIFTbfNC8HKDUo+l3u5hnfaQKnkXmItqqgXKmG41SkcEkEk9veUIzir +CIQ/LEXpRRc7TQjb3rLMC5XoVq7d0pUuUTQtERjaGe5ny+DkaIZcPeBbK853GiWthaPzsAYJ3H Bwrjh1M8WsjqgT2mp3eV/I4nlA0HcZeizYq0QuIabzVP4sEFfg162wd+6BPGQRqXF2ruffPzVWz GKkuiQ2MUCAYJ9XxP5hzO6OEhGSYMcMh+CG0ErqTxh9+fFepiNE+S9ULmdPfi4JcGevJm3jQX6B 0D+mbIbKMcra5OWDfr9mNRlMH915K92ZqXm/mzx30tWXAeufoZVYpYjbLRLprZNeMFtQTtsMcOX sFv/84EAn0I1SQzP3fGOe63s/kbDlu6zI0TLY5SviPDF8db8trmDkWGdBVLi6xKGtWhmFJRaZKN 0My9xMRNuwI X-Received: by 2002:a05:7300:dc86:b0:2e2:27bb:a4a2 with SMTP id 5a478bee46e88-2ed197ac539mr2258327eec.13.1777487660066; Wed, 29 Apr 2026 11:34:20 -0700 (PDT) Received: from [192.168.1.18] (177-4-161-87.user3p.v-tal.net.br. [177.4.161.87]) by smtp.gmail.com with ESMTPSA id 5a478bee46e88-2ed1c09c6e3sm3136785eec.25.2026.04.29.11.34.15 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 29 Apr 2026 11:34:19 -0700 (PDT) From: =?utf-8?q?C=C3=A1ssio_Gabriel?= Date: Wed, 29 Apr 2026 15:34:05 -0300 Subject: [PATCH] ALSA: hda/cs35l41: Fix firmware load work teardown Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260429-alsa-hda-cs35l41-fw-work-teardown-v1-1-ba82a429fff0@gmail.com> X-B4-Tracking: v=1; b=H4sIAAAAAAAC/yXNQQ6CMBBA0auQWTsJrdWoVzEuhnaQKmnNDFoSw t2punyb/xdQlsgKl2YB4U/UmFOF2TXgB0p3xhiqwbb22DprkEYlHAKh1/1hdAb7giXLEycmCbk kdCcfOjKOzj5A7byE+zj/Htfb3/ruHuynbxjWdQNptUEPhQAAAA== X-Change-ID: 20260421-alsa-hda-cs35l41-fw-work-teardown-48cdba14a9cd To: David Rhodes , Richard Fitzgerald , Takashi Iwai , Stefan Binding , Vitaly Rodionov , Jaroslav Kysela Cc: linux-sound@vger.kernel.org, patches@opensource.cirrus.com, linux-kernel@vger.kernel.org, stable@vger.kernel.org, =?utf-8?q?C=C3=A1ssio_Gabriel?= X-Mailer: b4 0.15.2 X-Developer-Signature: v=1; a=openpgp-sha256; l=5974; i=cassiogabrielcontato@gmail.com; h=from:subject:message-id; bh=ggB6iqNXAUdCdmuPFrKjyW2XjK/FQ6ji9Jf6A5CZqXY=; b=owGbwMvMwCV2IdZeKur/u2bG02pJDJmf/NVFA+crG8ocvMt/dXag3s2vix42PsqU/3vjjfOc7 0uOPPc36ihlYRDjYpAVU2RZnbTIck/Xg6v1cSs8YOawMoEMYeDiFICJpJ9nZDjd5PSpaGL62dpA vonZmxxeVxgyOCl1xzEvbjy5YX4adxTD//gyn+Tzsy+4phytOSfiZ3Xm437RPztOFsy64dt0hFl sAicA X-Developer-Key: i=cassiogabrielcontato@gmail.com; a=openpgp; fpr=AB62A239BC8AE0D57F5EA848D05D3F1A5AFFEE83 cs35l41_hda creates ALSA controls whose private data points at the cs35l41_hda object. The firmware load control can also queue fw_load_work. Those controls are not removed on component unbind, and device remove only cancels fw_load_work through cs35l41_remove_dsp(). That helper is skipped when halo_initialized is false. With firmware_autostart disabled, a firmware load can be requested before the DSP has been initialized. If the component or device is removed before the queued work runs, the worker can run after teardown and dereference driver state that is no longer valid. Track the created controls and remove them on unbind so no new control callback can reach the driver data or queue more work. Then cancel fw_load_work to drain any request that was already queued. Also cancel the work unconditionally during device remove before runtime PM teardown. Fixes: 47ceabd99a28 ("ALSA: hda: cs35l41: Support Firmware switching and re= loading") Fixes: 4c870513fbb0 ("ALSA: hda: cs35l41: Add read-only ALSA control for fo= rced mute") Cc: stable@vger.kernel.org Signed-off-by: C=C3=A1ssio Gabriel --- sound/hda/codecs/side-codecs/cs35l41_hda.c | 77 +++++++++++++++++++++-----= ---- sound/hda/codecs/side-codecs/cs35l41_hda.h | 5 ++ 2 files changed, 60 insertions(+), 22 deletions(-) diff --git a/sound/hda/codecs/side-codecs/cs35l41_hda.c b/sound/hda/codecs/= side-codecs/cs35l41_hda.c index b64890006bb7..7f18be0ccf5a 100644 --- a/sound/hda/codecs/side-codecs/cs35l41_hda.c +++ b/sound/hda/codecs/side-codecs/cs35l41_hda.c @@ -1325,6 +1325,43 @@ static int cs35l41_fw_type_ctl_info(struct snd_kcont= rol *kcontrol, struct snd_ct return snd_ctl_enum_info(uinfo, 1, ARRAY_SIZE(cs35l41_hda_fw_ids), cs35l4= 1_hda_fw_ids); } =20 +static void cs35l41_remove_controls(struct cs35l41_hda *cs35l41) +{ + if (!cs35l41->codec) + return; + + snd_ctl_remove(cs35l41->codec->card, cs35l41->mute_override_ctl); + cs35l41->mute_override_ctl =3D NULL; + + snd_ctl_remove(cs35l41->codec->card, cs35l41->fw_load_ctl); + cs35l41->fw_load_ctl =3D NULL; + + snd_ctl_remove(cs35l41->codec->card, cs35l41->fw_type_ctl); + cs35l41->fw_type_ctl =3D NULL; +} + +static int cs35l41_add_control(struct cs35l41_hda *cs35l41, + struct snd_kcontrol_new *ctl, + struct snd_kcontrol **kctl) +{ + int ret; + + *kctl =3D snd_ctl_new1(ctl, cs35l41); + if (!*kctl) + return -ENOMEM; + + ret =3D snd_ctl_add(cs35l41->codec->card, *kctl); + if (ret) { + dev_err(cs35l41->dev, "Failed to add KControl %s =3D %d\n", ctl->name, r= et); + *kctl =3D NULL; + return ret; + } + + dev_dbg(cs35l41->dev, "Added Control %s\n", ctl->name); + + return 0; +} + static int cs35l41_create_controls(struct cs35l41_hda *cs35l41) { char fw_type_ctl_name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; @@ -1360,32 +1397,23 @@ static int cs35l41_create_controls(struct cs35l41_h= da *cs35l41) scnprintf(mute_override_ctl_name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN, "%s Forc= ed Mute Status", cs35l41->amp_name); =20 - ret =3D snd_ctl_add(cs35l41->codec->card, snd_ctl_new1(&fw_type_ctl, cs35= l41)); - if (ret) { - dev_err(cs35l41->dev, "Failed to add KControl %s =3D %d\n", fw_type_ctl.= name, ret); - return ret; - } - - dev_dbg(cs35l41->dev, "Added Control %s\n", fw_type_ctl.name); - - ret =3D snd_ctl_add(cs35l41->codec->card, snd_ctl_new1(&fw_load_ctl, cs35= l41)); - if (ret) { - dev_err(cs35l41->dev, "Failed to add KControl %s =3D %d\n", fw_load_ctl.= name, ret); - return ret; - } - - dev_dbg(cs35l41->dev, "Added Control %s\n", fw_load_ctl.name); + ret =3D cs35l41_add_control(cs35l41, &fw_type_ctl, &cs35l41->fw_type_ctl); + if (ret) + goto err; =20 - ret =3D snd_ctl_add(cs35l41->codec->card, snd_ctl_new1(&mute_override_ctl= , cs35l41)); - if (ret) { - dev_err(cs35l41->dev, "Failed to add KControl %s =3D %d\n", mute_overrid= e_ctl.name, - ret); - return ret; - } + ret =3D cs35l41_add_control(cs35l41, &fw_load_ctl, &cs35l41->fw_load_ctl); + if (ret) + goto err; =20 - dev_dbg(cs35l41->dev, "Added Control %s\n", mute_override_ctl.name); + ret =3D cs35l41_add_control(cs35l41, &mute_override_ctl, &cs35l41->mute_o= verride_ctl); + if (ret) + goto err; =20 return 0; + +err: + cs35l41_remove_controls(cs35l41); + return ret; } =20 static bool cs35l41_dsm_supported(acpi_handle handle, unsigned int command= s) @@ -1522,6 +1550,10 @@ static void cs35l41_hda_unbind(struct device *dev, s= truct device *master, void * device_link_remove(&cs35l41->codec->core.dev, cs35l41->dev); unlock_system_sleep(sleep_flags); memset(comp, 0, sizeof(*comp)); + + cs35l41_remove_controls(cs35l41); + cancel_work_sync(&cs35l41->fw_load_work); + cs35l41->codec =3D NULL; } } =20 @@ -2058,6 +2090,7 @@ void cs35l41_hda_remove(struct device *dev) struct cs35l41_hda *cs35l41 =3D dev_get_drvdata(dev); =20 component_del(cs35l41->dev, &cs35l41_hda_comp_ops); + cancel_work_sync(&cs35l41->fw_load_work); =20 pm_runtime_get_sync(cs35l41->dev); pm_runtime_dont_use_autosuspend(cs35l41->dev); diff --git a/sound/hda/codecs/side-codecs/cs35l41_hda.h b/sound/hda/codecs/= side-codecs/cs35l41_hda.h index 7d003c598e93..56ec07c0bb74 100644 --- a/sound/hda/codecs/side-codecs/cs35l41_hda.h +++ b/sound/hda/codecs/side-codecs/cs35l41_hda.h @@ -57,6 +57,8 @@ enum control_bus { SPI }; =20 +struct snd_kcontrol; + struct cs35l41_hda { struct device *dev; struct regmap *regmap; @@ -75,6 +77,9 @@ struct cs35l41_hda { int speaker_id; struct mutex fw_mutex; struct work_struct fw_load_work; + struct snd_kcontrol *fw_type_ctl; + struct snd_kcontrol *fw_load_ctl; + struct snd_kcontrol *mute_override_ctl; =20 struct regmap_irq_chip_data *irq_data; bool firmware_running; --- base-commit: 1bc46462f4c09f8d429ae8ec17f92886d604659f change-id: 20260421-alsa-hda-cs35l41-fw-work-teardown-48cdba14a9cd Best regards, -- =20 C=C3=A1ssio Gabriel