ALSA: hda: Unify get_response handling

Now most of the get_response handling became quite similar between
HDA-core and legacy drivers, and the only differences are:

- the handling of extra-long polling delay for some codecs
- the debug message for the stalled communication

and both are worth to share in the common code.

This patch unifies the code into snd_hdac_bus_get_response(), and use
this from the legacy get_response callback.  It results in a good
amount of code reduction in the end.

Reviewed-by: Kai Vehmanen <kai.vehmanen@linux.intel.com>
Link: https://lore.kernel.org/r/20191212191101.19517-3-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
This commit is contained in:
Takashi Iwai 2019-12-12 20:11:01 +01:00
parent 89698ed5cc
commit 5f2cb361d7
8 changed files with 19 additions and 51 deletions

View File

@ -51,7 +51,6 @@ struct hda_bus {
DECLARE_BITMAP(pcm_dev_bits, SNDRV_PCM_DEVICES); DECLARE_BITMAP(pcm_dev_bits, SNDRV_PCM_DEVICES);
/* misc op flags */ /* misc op flags */
unsigned int needs_damn_long_delay :1;
unsigned int allow_bus_reset:1; /* allow bus reset at fatal error */ unsigned int allow_bus_reset:1; /* allow bus reset at fatal error */
/* status for codec/controller */ /* status for codec/controller */
unsigned int shutdown :1; /* being unloaded */ unsigned int shutdown :1; /* being unloaded */

View File

@ -338,6 +338,7 @@ struct hdac_bus {
bool reverse_assign:1; /* assign devices in reverse order */ bool reverse_assign:1; /* assign devices in reverse order */
bool corbrp_self_clear:1; /* CORBRP clears itself after reset */ bool corbrp_self_clear:1; /* CORBRP clears itself after reset */
bool polling_mode:1; bool polling_mode:1;
bool needs_damn_long_delay:1;
int poll_count; int poll_count;

View File

@ -242,6 +242,7 @@ int snd_hdac_bus_get_response(struct hdac_bus *bus, unsigned int addr,
unsigned long timeout; unsigned long timeout;
unsigned long loopcounter; unsigned long loopcounter;
wait_queue_entry_t wait; wait_queue_entry_t wait;
bool warned = false;
init_wait_entry(&wait, 0); init_wait_entry(&wait, 0);
timeout = jiffies + msecs_to_jiffies(1000); timeout = jiffies + msecs_to_jiffies(1000);
@ -264,9 +265,17 @@ int snd_hdac_bus_get_response(struct hdac_bus *bus, unsigned int addr,
spin_unlock_irq(&bus->reg_lock); spin_unlock_irq(&bus->reg_lock);
if (time_after(jiffies, timeout)) if (time_after(jiffies, timeout))
break; break;
#define LOOP_COUNT_MAX 3000
if (!bus->polling_mode) { if (!bus->polling_mode) {
schedule_timeout(msecs_to_jiffies(2)); schedule_timeout(msecs_to_jiffies(2));
} else if (loopcounter > 3000) { } else if (bus->needs_damn_long_delay ||
loopcounter > LOOP_COUNT_MAX) {
if (loopcounter > LOOP_COUNT_MAX && !warned) {
dev_dbg_ratelimited(bus->dev,
"too slow response, last cmd=%#08x\n",
bus->last_cmd[addr]);
warned = true;
}
msleep(2); /* temporary workaround */ msleep(2); /* temporary workaround */
} else { } else {
udelay(10); udelay(10);

View File

@ -784,53 +784,12 @@ static int azx_rirb_get_response(struct hdac_bus *bus, unsigned int addr,
{ {
struct azx *chip = bus_to_azx(bus); struct azx *chip = bus_to_azx(bus);
struct hda_bus *hbus = &chip->bus; struct hda_bus *hbus = &chip->bus;
unsigned long timeout; int err;
unsigned long loopcounter;
wait_queue_entry_t wait;
bool warned = false;
init_wait_entry(&wait, 0);
again: again:
timeout = jiffies + msecs_to_jiffies(1000); err = snd_hdac_bus_get_response(bus, addr, res);
if (!err)
for (loopcounter = 0;; loopcounter++) { return 0;
spin_lock_irq(&bus->reg_lock);
if (!bus->polling_mode)
prepare_to_wait(&bus->rirb_wq, &wait,
TASK_UNINTERRUPTIBLE);
if (bus->polling_mode)
snd_hdac_bus_update_rirb(bus);
if (!bus->rirb.cmds[addr]) {
if (res)
*res = bus->rirb.res[addr]; /* the last value */
if (!bus->polling_mode)
finish_wait(&bus->rirb_wq, &wait);
spin_unlock_irq(&bus->reg_lock);
return 0;
}
spin_unlock_irq(&bus->reg_lock);
if (time_after(jiffies, timeout))
break;
#define LOOP_COUNT_MAX 3000
if (!bus->polling_mode) {
schedule_timeout(msecs_to_jiffies(2));
} else if (hbus->needs_damn_long_delay ||
loopcounter > LOOP_COUNT_MAX) {
if (loopcounter > LOOP_COUNT_MAX && !warned) {
dev_dbg_ratelimited(chip->card->dev,
"too slow response, last cmd=%#08x\n",
bus->last_cmd[addr]);
warned = true;
}
msleep(2); /* temporary workaround */
} else {
udelay(10);
cond_resched();
}
}
if (!bus->polling_mode)
finish_wait(&bus->rirb_wq, &wait);
if (hbus->no_response_fallback) if (hbus->no_response_fallback)
return -EIO; return -EIO;

View File

@ -1809,7 +1809,7 @@ static int azx_create(struct snd_card *card, struct pci_dev *pci,
if (chip->driver_type == AZX_DRIVER_NVIDIA) { if (chip->driver_type == AZX_DRIVER_NVIDIA) {
dev_dbg(chip->card->dev, "Enable delay in RIRB handling\n"); dev_dbg(chip->card->dev, "Enable delay in RIRB handling\n");
chip->bus.needs_damn_long_delay = 1; chip->bus.core.needs_damn_long_delay = 1;
} }
err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops); err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops);

View File

@ -394,7 +394,7 @@ static int hda_tegra_create(struct snd_card *card,
if (err < 0) if (err < 0)
return err; return err;
chip->bus.needs_damn_long_delay = 1; chip->bus.core.needs_damn_long_delay = 1;
err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops); err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops);
if (err < 0) { if (err < 0) {

View File

@ -53,7 +53,7 @@ static int patch_ca0110(struct hda_codec *codec)
codec->patch_ops = ca0110_patch_ops; codec->patch_ops = ca0110_patch_ops;
spec->multi_cap_vol = 1; spec->multi_cap_vol = 1;
codec->bus->needs_damn_long_delay = 1; codec->bus->core.needs_damn_long_delay = 1;
err = ca0110_parse_auto_config(codec); err = ca0110_parse_auto_config(codec);
if (err < 0) if (err < 0)

View File

@ -4908,7 +4908,7 @@ static int patch_stac927x(struct hda_codec *codec)
* The below flag enables the longer delay (see get_response * The below flag enables the longer delay (see get_response
* in hda_intel.c). * in hda_intel.c).
*/ */
codec->bus->needs_damn_long_delay = 1; codec->bus->core.needs_damn_long_delay = 1;
snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE); snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);