[PATCH 5.16 0826/1017] ALSA: hda: Fix driver index handling at re-binding

From: Greg Kroah-Hartman
Date: Tue Apr 05 2022 - 09:42:35 EST

From: Takashi Iwai <tiwai@xxxxxxx>

[ Upstream commit 69458e2c27800da7697c87ed908b65323ef3f3bd ]

HD-audio driver handles the multiple instances and keeps the static
index that is incremented at each probe. This becomes a problem when
user tries to re-bind the device via sysfs multiple times; as the
device index isn't cleared unlike rmmod case, it points to the next
element at re-binding, and eventually later you can't probe any more
when it reaches to SNDRV_CARDS_MAX (usually 32).

This patch is an attempt to improve the handling at rebinding.
Instead of a static device index, now we keep a bitmap and assigns to
the first zero bit position. At the driver remove, in return, the
bitmap slot is cleared again, so that it'll be available for the next

Reported-by: Alexander Sergeyev <sergeev917@xxxxxxxxx>
Link: https://lore.kernel.org/r/20220209081912.20687-1-tiwai@xxxxxxx
Signed-off-by: Takashi Iwai <tiwai@xxxxxxx>
Signed-off-by: Sasha Levin <sashal@xxxxxxxxxx>
sound/pci/hda/hda_intel.c | 10 +++++++---
1 file changed, 7 insertions(+), 3 deletions(-)

diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c
index 3b6f2aacda45..1ffd96fbf230 100644
--- a/sound/pci/hda/hda_intel.c
+++ b/sound/pci/hda/hda_intel.c
@@ -2061,14 +2061,16 @@ static const struct hda_controller_ops pci_hda_ops = {
.position_check = azx_position_check,

+static DECLARE_BITMAP(probed_devs, SNDRV_CARDS);
static int azx_probe(struct pci_dev *pci,
const struct pci_device_id *pci_id)
- static int dev;
struct snd_card *card;
struct hda_intel *hda;
struct azx *chip;
bool schedule_probe;
+ int dev;
int err;

if (pci_match_id(driver_denylist, pci)) {
@@ -2076,10 +2078,11 @@ static int azx_probe(struct pci_dev *pci,
return -ENODEV;

+ dev = find_first_zero_bit(probed_devs, SNDRV_CARDS);
if (dev >= SNDRV_CARDS)
return -ENODEV;
if (!enable[dev]) {
- dev++;
+ set_bit(dev, probed_devs);
return -ENOENT;

@@ -2146,7 +2149,7 @@ static int azx_probe(struct pci_dev *pci,
if (schedule_probe)
schedule_delayed_work(&hda->probe_work, 0);

- dev++;
+ set_bit(dev, probed_devs);
if (chip->disabled)
return 0;
@@ -2369,6 +2372,7 @@ static void azx_remove(struct pci_dev *pci)

+ clear_bit(chip->dev_index, probed_devs);
pci_set_drvdata(pci, NULL);