]> git.ipfire.org Git - ipfire-2.x.git/blobdiff - src/patches/suse-2.6.27.31/patches.drivers/alsa-post-ga-hda-codec-verb-retry
Move xen patchset to new version's subdir.
[ipfire-2.x.git] / src / patches / suse-2.6.27.31 / patches.drivers / alsa-post-ga-hda-codec-verb-retry
diff --git a/src/patches/suse-2.6.27.31/patches.drivers/alsa-post-ga-hda-codec-verb-retry b/src/patches/suse-2.6.27.31/patches.drivers/alsa-post-ga-hda-codec-verb-retry
new file mode 100644 (file)
index 0000000..3318b09
--- /dev/null
@@ -0,0 +1,175 @@
+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);