The AZX controller implementation in azx_rirb_get_response() implements logic to fallback to polling in case interrupt is not received from HDA codec.
Port over this same logic to the generic snd_hdac_bus_get_response() function, which is used by other HDAC clients such as SOF.
Without this fix, failures are observed in module reload stress tests with the SOF driver, while test passes on same hardware with the snd_hda_intel driver. Considering the AZX implementation has been much more widely used and there can be exceptions with other systems (and codecs), it is best to align the implementation and use the time-proven logic in all drivers.
Signed-off-by: Kai Vehmanen kai.vehmanen@linux.intel.com --- sound/hda/hdac_controller.c | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-)
diff --git a/sound/hda/hdac_controller.c b/sound/hda/hdac_controller.c index d3999e7b0705..994c1dd2eb2e 100644 --- a/sound/hda/hdac_controller.c +++ b/sound/hda/hdac_controller.c @@ -238,14 +238,18 @@ int snd_hdac_bus_get_response(struct hdac_bus *bus, unsigned int addr, { unsigned long timeout; unsigned long loopcounter; + int do_poll = 0;
+ again: timeout = jiffies + msecs_to_jiffies(1000);
for (loopcounter = 0;; loopcounter++) { spin_lock_irq(&bus->reg_lock); - if (bus->polling_mode) + if (bus->polling_mode || do_poll) snd_hdac_bus_update_rirb(bus); if (!bus->rirb.cmds[addr]) { + if (!do_poll) + bus->poll_count = 0; if (res) *res = bus->rirb.res[addr]; /* the last value */ spin_unlock_irq(&bus->reg_lock); @@ -262,6 +266,23 @@ int snd_hdac_bus_get_response(struct hdac_bus *bus, unsigned int addr, } }
+ if (!bus->polling_mode && bus->poll_count < 2) { + dev_dbg(bus->dev, + "response timeout, polling the codec once: last cmd=0x%08x\n", + bus->last_cmd[addr]); + do_poll = 1; + bus->poll_count++; + goto again; + } + + if (!bus->polling_mode) { + dev_warn(bus->dev, + "response timeout, switching to polling mode: last cmd=0x%08x\n", + bus->last_cmd[addr]); + bus->polling_mode = 1; + goto again; + } + return -EIO; } EXPORT_SYMBOL_GPL(snd_hdac_bus_get_response);