Merge branch 'topic/hda-ctl-reset' into topic/hda

This commit is contained in:
Takashi Iwai 2009-06-02 12:15:48 +02:00
commit 3c4dbda003
4 changed files with 69 additions and 33 deletions

View File

@ -165,28 +165,29 @@ static int codec_exec_verb(struct hda_codec *codec, unsigned int cmd,
unsigned int *res)
{
struct hda_bus *bus = codec->bus;
int err, repeated = 0;
int err;
if (res)
*res = -1;
again:
snd_hda_power_up(codec);
mutex_lock(&bus->cmd_mutex);
again:
err = bus->ops.command(bus, cmd);
if (!err) {
if (res) {
*res = bus->ops.get_response(bus);
if (*res == -1 && bus->rirb_error) {
if (repeated++ < 1) {
snd_printd(KERN_WARNING "hda_codec: "
"Trying verb 0x%08x again\n", cmd);
goto again;
}
}
}
}
if (!err && res)
*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;
}
/* clear reset-flag when the communication gets recovered */
if (!err)
bus->response_reset = 0;
return err;
}
@ -213,11 +214,6 @@ unsigned int snd_hda_codec_read(struct hda_codec *codec, hda_nid_t nid,
}
EXPORT_SYMBOL_HDA(snd_hda_codec_read);
/* Define the below to send and receive verbs synchronously.
* If you often get any codec communication errors, this is worth to try.
*/
/* #define SND_HDA_SUPPORT_SYNC_WRITE */
/**
* snd_hda_codec_write - send a single command without waiting for response
* @codec: the HDA codec
@ -234,12 +230,9 @@ int snd_hda_codec_write(struct hda_codec *codec, hda_nid_t nid, int direct,
unsigned int verb, unsigned int parm)
{
unsigned int cmd = make_codec_cmd(codec, nid, direct, verb, parm);
#ifdef SND_HDA_SUPPORT_SYNC_WRITE
unsigned int res;
return codec_exec_verb(codec, cmd, &res);
#else
return codec_exec_verb(codec, cmd, NULL);
#endif
return codec_exec_verb(codec, cmd,
codec->bus->sync_write ? &res : NULL);
}
EXPORT_SYMBOL_HDA(snd_hda_codec_write);
@ -3894,11 +3887,10 @@ EXPORT_SYMBOL_HDA(auto_pin_cfg_labels);
/**
* 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;

View File

@ -574,6 +574,8 @@ struct hda_bus_ops {
/* attach a PCM stream */
int (*attach_pcm)(struct hda_bus *bus, struct hda_codec *codec,
struct hda_pcm *pcm);
/* 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);
@ -622,8 +624,13 @@ struct hda_bus {
/* misc op flags */
unsigned int needs_damn_long_delay :1;
unsigned int allow_bus_reset:1; /* allow bus reset at fatal error */
unsigned int sync_write:1; /* sync after verb write */
/* status for codec/controller */
unsigned int shutdown :1; /* being unloaded */
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 */
};
/*
@ -907,7 +914,7 @@ void snd_hda_get_codec_name(struct hda_codec *codec, char *name, int namelen);
* 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

View File

@ -661,14 +661,23 @@ static unsigned int azx_rirb_get_response(struct hda_bus *bus)
return -1;
}
snd_printk(KERN_ERR SFX "azx_get_response timeout (ERROR): "
"last cmd=0x%08x\n", chip->last_cmd);
/* re-initialize CORB/RIRB */
spin_lock_irq(&chip->reg_lock);
/* a fatal communication error; need either to reset or to fallback
* to the single_cmd mode
*/
bus->rirb_error = 1;
if (bus->allow_bus_reset && !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->single_cmd = 1;
bus->response_reset = 0;
/* re-initialize CORB/RIRB */
azx_free_cmd_io(chip);
azx_init_cmd_io(chip);
spin_unlock_irq(&chip->reg_lock);
return -1;
}
@ -709,6 +718,7 @@ static int azx_single_send_cmd(struct hda_bus *bus, u32 val)
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))) {
@ -1247,6 +1257,23 @@ static int azx_attach_pcm_stream(struct hda_bus *bus, struct hda_codec *codec,
struct hda_pcm *cpcm);
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
*/
@ -1270,6 +1297,7 @@ static int __devinit azx_codec_create(struct azx *chip, const char *model,
bus_temp.ops.command = azx_send_cmd;
bus_temp.ops.get_response = azx_get_response;
bus_temp.ops.attach_pcm = azx_attach_pcm_stream;
bus_temp.ops.bus_reset = azx_bus_reset;
#ifdef CONFIG_SND_HDA_POWER_SAVE
bus_temp.power_save = &power_save;
bus_temp.ops.pm_notify = azx_power_notify;
@ -1997,7 +2025,7 @@ static int azx_suspend(struct pci_dev *pci, pm_message_t state)
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);

View File

@ -5375,6 +5375,15 @@ again:
if (get_wcaps(codec, 0xa) & AC_WCAP_IN_AMP)
snd_hda_sequence_write_cache(codec, unmute_init);
/* Some HP machines seem to have unstable codec communications
* especially with ATI fglrx driver. For recovering from the
* CORB/RIRB stall, allow the BUS reset and keep always sync
*/
if (spec->board_config == STAC_HP_DV5) {
codec->bus->sync_write = 1;
codec->bus->allow_bus_reset = 1;
}
spec->aloopback_ctl = stac92hd71bxx_loopback;
spec->aloopback_mask = 0x50;
spec->aloopback_shift = 0;