+++ /dev/null
-From: Takashi Iwai <tiwai@suse.de>
-Subject: ALSA: Add codec bus reset and verb-retry at critical errors
-Patch-mainline:
-References: bnc#502903
-
-The Volna machine causes a severe CORB/RIRB stall when PA is started
-together with fglrx. This cannot be recovered without the controller
-reset.
-
-This patch allows the bus controller reset at critical errors so
-that the communication gets recovered again.
-
-Signed-off-by: Takashi Iwai <tiwai@suse.de>
-
----
- sound/pci/hda/hda_codec.c | 13 +++++++++++--
- sound/pci/hda/hda_codec.h | 7 ++++++-
- sound/pci/hda/hda_intel.c | 37 +++++++++++++++++++++++++++++++++----
- 3 files changed, 50 insertions(+), 7 deletions(-)
-
---- a/sound/pci/hda/hda_codec.h
-+++ b/sound/pci/hda/hda_codec.h
-@@ -541,6 +541,8 @@
- unsigned int (*get_response)(struct hda_bus *bus);
- /* free the private data */
- void (*private_free)(struct hda_bus *);
-+ /* reset bus for retry verb */
-+ void (*bus_reset)(struct hda_bus *bus);
- #ifdef CONFIG_SND_HDA_POWER_SAVE
- /* notify power-up/down from codec to controller */
- void (*pm_notify)(struct hda_bus *bus);
-@@ -586,6 +588,9 @@
-
- /* misc op flags */
- unsigned int needs_damn_long_delay :1;
-+ unsigned int rirb_error:1; /* error in codec communication */
-+ unsigned int response_reset:1; /* controller was reset */
-+ unsigned int in_reset:1; /* during reset operation */
- };
-
- /*
-@@ -827,7 +832,7 @@
- * power management
- */
- #ifdef CONFIG_PM
--int snd_hda_suspend(struct hda_bus *bus, pm_message_t state);
-+int snd_hda_suspend(struct hda_bus *bus);
- int snd_hda_resume(struct hda_bus *bus);
- #endif
-
---- a/sound/pci/hda/hda_codec.c
-+++ b/sound/pci/hda/hda_codec.c
-@@ -187,6 +187,7 @@
-
- if (res)
- *res = -1;
-+ again:
- snd_hda_power_up(codec);
- mutex_lock(&bus->cmd_mutex);
- err = bus->ops.command(bus, cmd);
-@@ -194,6 +195,15 @@
- *res = bus->ops.get_response(bus);
- mutex_unlock(&bus->cmd_mutex);
- snd_hda_power_down(codec);
-+ if (res && *res == -1 && bus->rirb_error) {
-+ if (bus->response_reset) {
-+ snd_printd("hda_codec: resetting BUS due to "
-+ "fatal communication error\n");
-+ bus->ops.bus_reset(bus);
-+ }
-+ goto again;
-+ }
-+ bus->response_reset = 0;
- return err;
- }
-
-@@ -3279,11 +3289,10 @@
- /**
- * snd_hda_suspend - suspend the codecs
- * @bus: the HDA bus
-- * @state: suspsend state
- *
- * Returns 0 if successful.
- */
--int snd_hda_suspend(struct hda_bus *bus, pm_message_t state)
-+int snd_hda_suspend(struct hda_bus *bus)
- {
- struct hda_codec *codec;
-
---- a/sound/pci/hda/hda_intel.c
-+++ b/sound/pci/hda/hda_intel.c
-@@ -600,6 +600,7 @@
- }
- if (!chip->rirb.cmds) {
- smp_rmb();
-+ bus->rirb_error = 0;
- return chip->rirb.res; /* the last value */
- }
- if (time_after(jiffies, timeout))
-@@ -640,14 +641,23 @@
- return -1;
- }
-
-+ /* a fatal communication error; need either to reset or to fallback
-+ * to the single_cmd mode
-+ */
-+ bus->rirb_error = 1;
-+ if (!bus->response_reset && !bus->in_reset) {
-+ bus->response_reset = 1;
-+ return -1; /* give a chance to retry */
-+ }
-+
- snd_printk(KERN_ERR "hda_intel: azx_get_response timeout, "
- "switching to single_cmd mode: last cmd=0x%08x\n",
- chip->last_cmd);
-- chip->rirb.rp = azx_readb(chip, RIRBWP);
-- chip->rirb.cmds = 0;
-- /* switch to single_cmd mode */
- chip->single_cmd = 1;
-+ bus->response_reset = 0;
-+ /* re-initialize CORB/RIRB */
- azx_free_cmd_io(chip);
-+ azx_init_cmd_io(chip);
- return -1;
- }
-
-@@ -688,6 +698,7 @@
- struct azx *chip = bus->private_data;
- int timeout = 50;
-
-+ bus->rirb_error = 0;
- while (timeout--) {
- /* check ICB busy bit */
- if (!((azx_readw(chip, IRS) & ICH6_IRS_BUSY))) {
-@@ -1227,6 +1238,23 @@
-
- static void azx_stop_chip(struct azx *chip);
-
-+static void azx_bus_reset(struct hda_bus *bus)
-+{
-+ struct azx *chip = bus->private_data;
-+ int i;
-+
-+ bus->in_reset = 1;
-+ azx_stop_chip(chip);
-+ azx_init_chip(chip);
-+ if (chip->initialized) {
-+ for (i = 0; i < AZX_MAX_PCMS; i++)
-+ snd_pcm_suspend_all(chip->pcm[i]);
-+ snd_hda_suspend(chip->bus);
-+ snd_hda_resume(chip->bus);
-+ }
-+ bus->in_reset = 0;
-+}
-+
- /*
- * Codec initialization
- */
-@@ -1248,6 +1276,7 @@
- bus_temp.pci = chip->pci;
- bus_temp.ops.command = azx_send_cmd;
- bus_temp.ops.get_response = azx_get_response;
-+ bus_temp.ops.bus_reset = azx_bus_reset;
- #ifdef CONFIG_SND_HDA_POWER_SAVE
- bus_temp.ops.pm_notify = azx_power_notify;
- #endif
-@@ -2013,7 +2042,7 @@
- for (i = 0; i < AZX_MAX_PCMS; i++)
- snd_pcm_suspend_all(chip->pcm[i]);
- if (chip->initialized)
-- snd_hda_suspend(chip->bus, state);
-+ snd_hda_suspend(chip->bus);
- azx_stop_chip(chip);
- if (chip->irq >= 0) {
- free_irq(chip->irq, chip);