diff mbox series

[1/1] ALSA: hda: add fallback to polling to hdac_bus_get_response()

Message ID 20191004143527.5575-2-kai.vehmanen@linux.intel.com (mailing list archive)
State New, archived
Headers show
Series ALSA: hda: add fallback to polling to hdac_bus_get_response() | expand

Commit Message

Kai Vehmanen Oct. 4, 2019, 2:35 p.m. UTC
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 mbox series

Patch

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);