summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2026-04-15 16:55:22 +0300
committerTakashi Iwai <tiwai@suse.de>2026-04-16 11:33:06 +0300
commiteb90ae3cca783ebec65704597027811431465de4 (patch)
tree5fe91338c59d2f9983b4a9f04e77f259a2404ec8
parentd9448dca423543c6c0a9890d3ff53a5d51895318 (diff)
downloadlinux-eb90ae3cca783ebec65704597027811431465de4.tar.xz
ALSA: hda/intel: Move firmware loading into the probe work
The hda-intel driver uses request_firmware_nowait() for loading its patch, and tries to continue the probe directly from the fw loader callback. This works in principle, but it has a few drawbacks: - The driver may be released before the firmware callback completes - Having two ways of async probe makes the code flow unnecessarily complex The former issue is more severe, as it may potentially lead to a UAF, and there is no explicit way to cancel the pending firmware worker for now. This patch changes the firmware loading to be performed rather in the common probe work without *_nowait(). Then the pending work can be easily canceled, and the code becomes more straightforward. A nice bonus is that, by moving into the probe work, the firmware doesn't need any longer to be cached, hence we can get rid of struct azx.fw field, and release the firmware immediately after parsing it, too. Fixes: 5cb543dba986 ("ALSA: hda - Deferred probing with request_firmware_nowait()") Link: https://patch.msgid.link/20260415135526.1813126-1-tiwai@suse.de Signed-off-by: Takashi Iwai <tiwai@suse.de>
-rw-r--r--sound/hda/common/hda_controller.h4
-rw-r--r--sound/hda/controllers/intel.c58
2 files changed, 15 insertions, 47 deletions
diff --git a/sound/hda/common/hda_controller.h b/sound/hda/common/hda_controller.h
index c2d0109866e6..7434f38038a0 100644
--- a/sound/hda/common/hda_controller.h
+++ b/sound/hda/common/hda_controller.h
@@ -127,10 +127,6 @@ struct azx {
unsigned int beep_mode;
bool ctl_dev_id;
-#ifdef CONFIG_SND_HDA_PATCH_LOADER
- const struct firmware *fw;
-#endif
-
/* flags */
int bdl_pos_adj;
unsigned int running:1;
diff --git a/sound/hda/controllers/intel.c b/sound/hda/controllers/intel.c
index 257c498c3260..c87d75dbd8aa 100644
--- a/sound/hda/controllers/intel.c
+++ b/sound/hda/controllers/intel.c
@@ -1385,9 +1385,6 @@ static void azx_free(struct azx *chip)
azx_free_streams(chip);
snd_hdac_bus_exit(bus);
-#ifdef CONFIG_SND_HDA_PATCH_LOADER
- release_firmware(chip->fw);
-#endif
display_power(chip, false);
if (chip->driver_caps & AZX_DCAPS_I915_COMPONENT)
@@ -2037,24 +2034,6 @@ static int azx_first_init(struct azx *chip)
return 0;
}
-#ifdef CONFIG_SND_HDA_PATCH_LOADER
-/* callback from request_firmware_nowait() */
-static void azx_firmware_cb(const struct firmware *fw, void *context)
-{
- struct snd_card *card = context;
- struct azx *chip = card->private_data;
-
- if (fw)
- chip->fw = fw;
- else
- dev_err(card->dev, "Cannot load firmware, continue without patching\n");
- if (!chip->disabled) {
- /* continue probing */
- azx_probe_continue(chip);
- }
-}
-#endif
-
static int disable_msi_reset_irq(struct azx *chip)
{
struct hdac_bus *bus = azx_bus(chip);
@@ -2131,7 +2110,6 @@ static int azx_probe(struct pci_dev *pci,
struct snd_card *card;
struct hda_intel *hda;
struct azx *chip;
- bool schedule_probe;
int dev;
int err;
@@ -2227,22 +2205,7 @@ static int azx_probe(struct pci_dev *pci,
chip->disabled = true;
}
- schedule_probe = !chip->disabled;
-
-#ifdef CONFIG_SND_HDA_PATCH_LOADER
- if (patch[dev] && *patch[dev]) {
- dev_info(card->dev, "Applying patch firmware '%s'\n",
- patch[dev]);
- err = request_firmware_nowait(THIS_MODULE, true, patch[dev],
- &pci->dev, GFP_KERNEL, card,
- azx_firmware_cb);
- if (err < 0)
- goto out_free;
- schedule_probe = false; /* continued in azx_firmware_cb() */
- }
-#endif /* CONFIG_SND_HDA_PATCH_LOADER */
-
- if (schedule_probe)
+ if (!chip->disabled)
schedule_delayed_work(&hda->probe_work, 0);
set_bit(dev, probed_devs);
@@ -2371,11 +2334,20 @@ static int azx_probe_continue(struct azx *chip)
}
#ifdef CONFIG_SND_HDA_PATCH_LOADER
- if (chip->fw) {
- err = snd_hda_load_patch(&chip->bus, chip->fw->size,
- chip->fw->data);
- if (err < 0)
- goto out_free;
+ if (patch[dev] && *patch[dev]) {
+ const struct firmware *fw = NULL;
+
+ dev_info(&pci->dev, "Applying patch firmware '%s'\n",
+ patch[dev]);
+ if (request_firmware(&fw, patch[dev], &pci->dev) < 0) {
+ dev_err(&pci->dev,
+ "Cannot load firmware, continue without patching\n");
+ } else {
+ err = snd_hda_load_patch(&chip->bus, fw->size, fw->data);
+ release_firmware(fw);
+ if (err < 0)
+ goto out_free;
+ }
}
#endif