Merge branch 'topic/hda-ctl-reset' into topic/hda
This commit is contained in:
commit
3c4dbda003
|
@ -165,28 +165,29 @@ static int codec_exec_verb(struct hda_codec *codec, unsigned int cmd,
|
||||||
unsigned int *res)
|
unsigned int *res)
|
||||||
{
|
{
|
||||||
struct hda_bus *bus = codec->bus;
|
struct hda_bus *bus = codec->bus;
|
||||||
int err, repeated = 0;
|
int err;
|
||||||
|
|
||||||
if (res)
|
if (res)
|
||||||
*res = -1;
|
*res = -1;
|
||||||
|
again:
|
||||||
snd_hda_power_up(codec);
|
snd_hda_power_up(codec);
|
||||||
mutex_lock(&bus->cmd_mutex);
|
mutex_lock(&bus->cmd_mutex);
|
||||||
again:
|
|
||||||
err = bus->ops.command(bus, cmd);
|
err = bus->ops.command(bus, cmd);
|
||||||
if (!err) {
|
if (!err && res)
|
||||||
if (res) {
|
*res = bus->ops.get_response(bus);
|
||||||
*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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
mutex_unlock(&bus->cmd_mutex);
|
mutex_unlock(&bus->cmd_mutex);
|
||||||
snd_hda_power_down(codec);
|
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;
|
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);
|
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
|
* snd_hda_codec_write - send a single command without waiting for response
|
||||||
* @codec: the HDA codec
|
* @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 verb, unsigned int parm)
|
||||||
{
|
{
|
||||||
unsigned int cmd = make_codec_cmd(codec, nid, direct, verb, parm);
|
unsigned int cmd = make_codec_cmd(codec, nid, direct, verb, parm);
|
||||||
#ifdef SND_HDA_SUPPORT_SYNC_WRITE
|
|
||||||
unsigned int res;
|
unsigned int res;
|
||||||
return codec_exec_verb(codec, cmd, &res);
|
return codec_exec_verb(codec, cmd,
|
||||||
#else
|
codec->bus->sync_write ? &res : NULL);
|
||||||
return codec_exec_verb(codec, cmd, NULL);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_HDA(snd_hda_codec_write);
|
EXPORT_SYMBOL_HDA(snd_hda_codec_write);
|
||||||
|
|
||||||
|
@ -3894,11 +3887,10 @@ EXPORT_SYMBOL_HDA(auto_pin_cfg_labels);
|
||||||
/**
|
/**
|
||||||
* snd_hda_suspend - suspend the codecs
|
* snd_hda_suspend - suspend the codecs
|
||||||
* @bus: the HDA bus
|
* @bus: the HDA bus
|
||||||
* @state: suspsend state
|
|
||||||
*
|
*
|
||||||
* Returns 0 if successful.
|
* 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;
|
struct hda_codec *codec;
|
||||||
|
|
||||||
|
|
|
@ -574,6 +574,8 @@ struct hda_bus_ops {
|
||||||
/* attach a PCM stream */
|
/* attach a PCM stream */
|
||||||
int (*attach_pcm)(struct hda_bus *bus, struct hda_codec *codec,
|
int (*attach_pcm)(struct hda_bus *bus, struct hda_codec *codec,
|
||||||
struct hda_pcm *pcm);
|
struct hda_pcm *pcm);
|
||||||
|
/* reset bus for retry verb */
|
||||||
|
void (*bus_reset)(struct hda_bus *bus);
|
||||||
#ifdef CONFIG_SND_HDA_POWER_SAVE
|
#ifdef CONFIG_SND_HDA_POWER_SAVE
|
||||||
/* notify power-up/down from codec to controller */
|
/* notify power-up/down from codec to controller */
|
||||||
void (*pm_notify)(struct hda_bus *bus);
|
void (*pm_notify)(struct hda_bus *bus);
|
||||||
|
@ -622,8 +624,13 @@ struct hda_bus {
|
||||||
|
|
||||||
/* misc op flags */
|
/* misc op flags */
|
||||||
unsigned int needs_damn_long_delay :1;
|
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 shutdown :1; /* being unloaded */
|
||||||
unsigned int rirb_error:1; /* error in codec communication */
|
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
|
* power management
|
||||||
*/
|
*/
|
||||||
#ifdef CONFIG_PM
|
#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);
|
int snd_hda_resume(struct hda_bus *bus);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -661,14 +661,23 @@ static unsigned int azx_rirb_get_response(struct hda_bus *bus)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
snd_printk(KERN_ERR SFX "azx_get_response timeout (ERROR): "
|
/* a fatal communication error; need either to reset or to fallback
|
||||||
"last cmd=0x%08x\n", chip->last_cmd);
|
* to the single_cmd mode
|
||||||
/* re-initialize CORB/RIRB */
|
*/
|
||||||
spin_lock_irq(&chip->reg_lock);
|
|
||||||
bus->rirb_error = 1;
|
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_free_cmd_io(chip);
|
||||||
azx_init_cmd_io(chip);
|
azx_init_cmd_io(chip);
|
||||||
spin_unlock_irq(&chip->reg_lock);
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -709,6 +718,7 @@ static int azx_single_send_cmd(struct hda_bus *bus, u32 val)
|
||||||
struct azx *chip = bus->private_data;
|
struct azx *chip = bus->private_data;
|
||||||
int timeout = 50;
|
int timeout = 50;
|
||||||
|
|
||||||
|
bus->rirb_error = 0;
|
||||||
while (timeout--) {
|
while (timeout--) {
|
||||||
/* check ICB busy bit */
|
/* check ICB busy bit */
|
||||||
if (!((azx_readw(chip, IRS) & ICH6_IRS_BUSY))) {
|
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);
|
struct hda_pcm *cpcm);
|
||||||
static void azx_stop_chip(struct azx *chip);
|
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
|
* 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.command = azx_send_cmd;
|
||||||
bus_temp.ops.get_response = azx_get_response;
|
bus_temp.ops.get_response = azx_get_response;
|
||||||
bus_temp.ops.attach_pcm = azx_attach_pcm_stream;
|
bus_temp.ops.attach_pcm = azx_attach_pcm_stream;
|
||||||
|
bus_temp.ops.bus_reset = azx_bus_reset;
|
||||||
#ifdef CONFIG_SND_HDA_POWER_SAVE
|
#ifdef CONFIG_SND_HDA_POWER_SAVE
|
||||||
bus_temp.power_save = &power_save;
|
bus_temp.power_save = &power_save;
|
||||||
bus_temp.ops.pm_notify = azx_power_notify;
|
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++)
|
for (i = 0; i < AZX_MAX_PCMS; i++)
|
||||||
snd_pcm_suspend_all(chip->pcm[i]);
|
snd_pcm_suspend_all(chip->pcm[i]);
|
||||||
if (chip->initialized)
|
if (chip->initialized)
|
||||||
snd_hda_suspend(chip->bus, state);
|
snd_hda_suspend(chip->bus);
|
||||||
azx_stop_chip(chip);
|
azx_stop_chip(chip);
|
||||||
if (chip->irq >= 0) {
|
if (chip->irq >= 0) {
|
||||||
free_irq(chip->irq, chip);
|
free_irq(chip->irq, chip);
|
||||||
|
|
|
@ -5375,6 +5375,15 @@ again:
|
||||||
if (get_wcaps(codec, 0xa) & AC_WCAP_IN_AMP)
|
if (get_wcaps(codec, 0xa) & AC_WCAP_IN_AMP)
|
||||||
snd_hda_sequence_write_cache(codec, unmute_init);
|
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_ctl = stac92hd71bxx_loopback;
|
||||||
spec->aloopback_mask = 0x50;
|
spec->aloopback_mask = 0x50;
|
||||||
spec->aloopback_shift = 0;
|
spec->aloopback_shift = 0;
|
||||||
|
|
Loading…
Reference in New Issue