aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2009-06-01 19:16:07 -0400
committerTakashi Iwai <tiwai@suse.de>2009-06-01 19:21:23 -0400
commit8dd783304e6d0f7c2830365d63f75f08aa343e10 (patch)
tree1f678835b512020cca26d26f58b7dc18194762bf
parent8871e5b91518a47284b6bc2603b44dbc79c85446 (diff)
ALSA: hda - Add codec bus reset and verb-retry at critical errors
Some machines machine cause a severe CORB/RIRB stall in certain weird conditions, such as PA access at the start up together with fglrx driver. This seems unable to 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>
-rw-r--r--sound/pci/hda/hda_codec.c32
-rw-r--r--sound/pci/hda/hda_codec.h6
-rw-r--r--sound/pci/hda/hda_intel.c40
3 files changed, 55 insertions, 23 deletions
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c
index d1d5fb9d7afb..aa0e1c18b606 100644
--- a/sound/pci/hda/hda_codec.c
+++ b/sound/pci/hda/hda_codec.c
@@ -165,28 +165,29 @@ static int codec_exec_verb(struct hda_codec *codec, unsigned int cmd,
165 unsigned int *res) 165 unsigned int *res)
166{ 166{
167 struct hda_bus *bus = codec->bus; 167 struct hda_bus *bus = codec->bus;
168 int err, repeated = 0; 168 int err;
169 169
170 if (res) 170 if (res)
171 *res = -1; 171 *res = -1;
172 again:
172 snd_hda_power_up(codec); 173 snd_hda_power_up(codec);
173 mutex_lock(&bus->cmd_mutex); 174 mutex_lock(&bus->cmd_mutex);
174 again:
175 err = bus->ops.command(bus, cmd); 175 err = bus->ops.command(bus, cmd);
176 if (!err) { 176 if (!err && res)
177 if (res) { 177 *res = bus->ops.get_response(bus);
178 *res = bus->ops.get_response(bus);
179 if (*res == -1 && bus->rirb_error) {
180 if (repeated++ < 1) {
181 snd_printd(KERN_WARNING "hda_codec: "
182 "Trying verb 0x%08x again\n", cmd);
183 goto again;
184 }
185 }
186 }
187 }
188 mutex_unlock(&bus->cmd_mutex); 178 mutex_unlock(&bus->cmd_mutex);
189 snd_hda_power_down(codec); 179 snd_hda_power_down(codec);
180 if (res && *res == -1 && bus->rirb_error) {
181 if (bus->response_reset) {
182 snd_printd("hda_codec: resetting BUS due to "
183 "fatal communication error\n");
184 bus->ops.bus_reset(bus);
185 }
186 goto again;
187 }
188 /* clear reset-flag when the communication gets recovered */
189 if (!err)
190 bus->response_reset = 0;
190 return err; 191 return err;
191} 192}
192 193
@@ -3894,11 +3895,10 @@ EXPORT_SYMBOL_HDA(auto_pin_cfg_labels);
3894/** 3895/**
3895 * snd_hda_suspend - suspend the codecs 3896 * snd_hda_suspend - suspend the codecs
3896 * @bus: the HDA bus 3897 * @bus: the HDA bus
3897 * @state: suspsend state
3898 * 3898 *
3899 * Returns 0 if successful. 3899 * Returns 0 if successful.
3900 */ 3900 */
3901int snd_hda_suspend(struct hda_bus *bus, pm_message_t state) 3901int snd_hda_suspend(struct hda_bus *bus)
3902{ 3902{
3903 struct hda_codec *codec; 3903 struct hda_codec *codec;
3904 3904
diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h
index c5bd40f77bb9..f5fa5d1f223c 100644
--- a/sound/pci/hda/hda_codec.h
+++ b/sound/pci/hda/hda_codec.h
@@ -574,6 +574,8 @@ struct hda_bus_ops {
574 /* attach a PCM stream */ 574 /* attach a PCM stream */
575 int (*attach_pcm)(struct hda_bus *bus, struct hda_codec *codec, 575 int (*attach_pcm)(struct hda_bus *bus, struct hda_codec *codec,
576 struct hda_pcm *pcm); 576 struct hda_pcm *pcm);
577 /* reset bus for retry verb */
578 void (*bus_reset)(struct hda_bus *bus);
577#ifdef CONFIG_SND_HDA_POWER_SAVE 579#ifdef CONFIG_SND_HDA_POWER_SAVE
578 /* notify power-up/down from codec to controller */ 580 /* notify power-up/down from codec to controller */
579 void (*pm_notify)(struct hda_bus *bus); 581 void (*pm_notify)(struct hda_bus *bus);
@@ -624,6 +626,8 @@ struct hda_bus {
624 unsigned int needs_damn_long_delay :1; 626 unsigned int needs_damn_long_delay :1;
625 unsigned int shutdown :1; /* being unloaded */ 627 unsigned int shutdown :1; /* being unloaded */
626 unsigned int rirb_error:1; /* error in codec communication */ 628 unsigned int rirb_error:1; /* error in codec communication */
629 unsigned int response_reset:1; /* controller was reset */
630 unsigned int in_reset:1; /* during reset operation */
627}; 631};
628 632
629/* 633/*
@@ -907,7 +911,7 @@ void snd_hda_get_codec_name(struct hda_codec *codec, char *name, int namelen);
907 * power management 911 * power management
908 */ 912 */
909#ifdef CONFIG_PM 913#ifdef CONFIG_PM
910int snd_hda_suspend(struct hda_bus *bus, pm_message_t state); 914int snd_hda_suspend(struct hda_bus *bus);
911int snd_hda_resume(struct hda_bus *bus); 915int snd_hda_resume(struct hda_bus *bus);
912#endif 916#endif
913 917
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c
index b063d0e3d325..44f9a0aa20c5 100644
--- a/sound/pci/hda/hda_intel.c
+++ b/sound/pci/hda/hda_intel.c
@@ -661,14 +661,23 @@ static unsigned int azx_rirb_get_response(struct hda_bus *bus)
661 return -1; 661 return -1;
662 } 662 }
663 663
664 snd_printk(KERN_ERR SFX "azx_get_response timeout (ERROR): " 664 /* a fatal communication error; need either to reset or to fallback
665 "last cmd=0x%08x\n", chip->last_cmd); 665 * to the single_cmd mode
666 /* re-initialize CORB/RIRB */ 666 */
667 spin_lock_irq(&chip->reg_lock);
668 bus->rirb_error = 1; 667 bus->rirb_error = 1;
668 if (!bus->response_reset && !bus->in_reset) {
669 bus->response_reset = 1;
670 return -1; /* give a chance to retry */
671 }
672
673 snd_printk(KERN_ERR "hda_intel: azx_get_response timeout, "
674 "switching to single_cmd mode: last cmd=0x%08x\n",
675 chip->last_cmd);
676 chip->single_cmd = 1;
677 bus->response_reset = 0;
678 /* re-initialize CORB/RIRB */
669 azx_free_cmd_io(chip); 679 azx_free_cmd_io(chip);
670 azx_init_cmd_io(chip); 680 azx_init_cmd_io(chip);
671 spin_unlock_irq(&chip->reg_lock);
672 return -1; 681 return -1;
673} 682}
674 683
@@ -709,6 +718,7 @@ static int azx_single_send_cmd(struct hda_bus *bus, u32 val)
709 struct azx *chip = bus->private_data; 718 struct azx *chip = bus->private_data;
710 int timeout = 50; 719 int timeout = 50;
711 720
721 bus->rirb_error = 0;
712 while (timeout--) { 722 while (timeout--) {
713 /* check ICB busy bit */ 723 /* check ICB busy bit */
714 if (!((azx_readw(chip, IRS) & ICH6_IRS_BUSY))) { 724 if (!((azx_readw(chip, IRS) & ICH6_IRS_BUSY))) {
@@ -1247,6 +1257,23 @@ static int azx_attach_pcm_stream(struct hda_bus *bus, struct hda_codec *codec,
1247 struct hda_pcm *cpcm); 1257 struct hda_pcm *cpcm);
1248static void azx_stop_chip(struct azx *chip); 1258static void azx_stop_chip(struct azx *chip);
1249 1259
1260static void azx_bus_reset(struct hda_bus *bus)
1261{
1262 struct azx *chip = bus->private_data;
1263 int i;
1264
1265 bus->in_reset = 1;
1266 azx_stop_chip(chip);
1267 azx_init_chip(chip);
1268 if (chip->initialized) {
1269 for (i = 0; i < AZX_MAX_PCMS; i++)
1270 snd_pcm_suspend_all(chip->pcm[i]);
1271 snd_hda_suspend(chip->bus);
1272 snd_hda_resume(chip->bus);
1273 }
1274 bus->in_reset = 0;
1275}
1276
1250/* 1277/*
1251 * Codec initialization 1278 * Codec initialization
1252 */ 1279 */
@@ -1270,6 +1297,7 @@ static int __devinit azx_codec_create(struct azx *chip, const char *model,
1270 bus_temp.ops.command = azx_send_cmd; 1297 bus_temp.ops.command = azx_send_cmd;
1271 bus_temp.ops.get_response = azx_get_response; 1298 bus_temp.ops.get_response = azx_get_response;
1272 bus_temp.ops.attach_pcm = azx_attach_pcm_stream; 1299 bus_temp.ops.attach_pcm = azx_attach_pcm_stream;
1300 bus_temp.ops.bus_reset = azx_bus_reset;
1273#ifdef CONFIG_SND_HDA_POWER_SAVE 1301#ifdef CONFIG_SND_HDA_POWER_SAVE
1274 bus_temp.power_save = &power_save; 1302 bus_temp.power_save = &power_save;
1275 bus_temp.ops.pm_notify = azx_power_notify; 1303 bus_temp.ops.pm_notify = azx_power_notify;
@@ -1997,7 +2025,7 @@ static int azx_suspend(struct pci_dev *pci, pm_message_t state)
1997 for (i = 0; i < AZX_MAX_PCMS; i++) 2025 for (i = 0; i < AZX_MAX_PCMS; i++)
1998 snd_pcm_suspend_all(chip->pcm[i]); 2026 snd_pcm_suspend_all(chip->pcm[i]);
1999 if (chip->initialized) 2027 if (chip->initialized)
2000 snd_hda_suspend(chip->bus, state); 2028 snd_hda_suspend(chip->bus);
2001 azx_stop_chip(chip); 2029 azx_stop_chip(chip);
2002 if (chip->irq >= 0) { 2030 if (chip->irq >= 0) {
2003 free_irq(chip->irq, chip); 2031 free_irq(chip->irq, chip);