mirror of
https://github.com/torvalds/linux.git
synced 2024-11-11 06:31:49 +00:00
ALSA: hda - Delay switching to polling mode if an interrupt was missing
My sound codec seems sometimes (very rarely) to omit interrupts (ALC268) However, interrupt mode still works. Thus if we get timeout, poll the codec once. If we get 3 such polls in a row, then switch to polling mode. This patch is maybe an bandaid, but this might be a workaround for hardware bug. Signed-off-by: Maxim Levitsky <maximlevitsky@gmail.com> Signed-off-by: Takashi Iwai <tiwai@suse.de>
This commit is contained in:
parent
8ce28d6abf
commit
1eb6dc7dab
@ -426,6 +426,7 @@ struct azx {
|
|||||||
|
|
||||||
/* flags */
|
/* flags */
|
||||||
int position_fix;
|
int position_fix;
|
||||||
|
int poll_count;
|
||||||
unsigned int running :1;
|
unsigned int running :1;
|
||||||
unsigned int initialized :1;
|
unsigned int initialized :1;
|
||||||
unsigned int single_cmd :1;
|
unsigned int single_cmd :1;
|
||||||
@ -506,7 +507,7 @@ static char *driver_short_names[] __devinitdata = {
|
|||||||
#define get_azx_dev(substream) (substream->runtime->private_data)
|
#define get_azx_dev(substream) (substream->runtime->private_data)
|
||||||
|
|
||||||
static int azx_acquire_irq(struct azx *chip, int do_disconnect);
|
static int azx_acquire_irq(struct azx *chip, int do_disconnect);
|
||||||
|
static int azx_send_cmd(struct hda_bus *bus, unsigned int val);
|
||||||
/*
|
/*
|
||||||
* Interface for HD codec
|
* Interface for HD codec
|
||||||
*/
|
*/
|
||||||
@ -664,11 +665,12 @@ static unsigned int azx_rirb_get_response(struct hda_bus *bus,
|
|||||||
{
|
{
|
||||||
struct azx *chip = bus->private_data;
|
struct azx *chip = bus->private_data;
|
||||||
unsigned long timeout;
|
unsigned long timeout;
|
||||||
|
int do_poll = 0;
|
||||||
|
|
||||||
again:
|
again:
|
||||||
timeout = jiffies + msecs_to_jiffies(1000);
|
timeout = jiffies + msecs_to_jiffies(1000);
|
||||||
for (;;) {
|
for (;;) {
|
||||||
if (chip->polling_mode) {
|
if (chip->polling_mode || do_poll) {
|
||||||
spin_lock_irq(&chip->reg_lock);
|
spin_lock_irq(&chip->reg_lock);
|
||||||
azx_update_rirb(chip);
|
azx_update_rirb(chip);
|
||||||
spin_unlock_irq(&chip->reg_lock);
|
spin_unlock_irq(&chip->reg_lock);
|
||||||
@ -676,6 +678,9 @@ static unsigned int azx_rirb_get_response(struct hda_bus *bus,
|
|||||||
if (!chip->rirb.cmds[addr]) {
|
if (!chip->rirb.cmds[addr]) {
|
||||||
smp_rmb();
|
smp_rmb();
|
||||||
bus->rirb_error = 0;
|
bus->rirb_error = 0;
|
||||||
|
|
||||||
|
if (!do_poll)
|
||||||
|
chip->poll_count = 0;
|
||||||
return chip->rirb.res[addr]; /* the last value */
|
return chip->rirb.res[addr]; /* the last value */
|
||||||
}
|
}
|
||||||
if (time_after(jiffies, timeout))
|
if (time_after(jiffies, timeout))
|
||||||
@ -688,6 +693,16 @@ static unsigned int azx_rirb_get_response(struct hda_bus *bus,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!chip->polling_mode && chip->poll_count < 2) {
|
||||||
|
snd_printdd(SFX "azx_get_response timeout, "
|
||||||
|
"polling the codec once: last cmd=0x%08x\n",
|
||||||
|
chip->last_cmd[addr]);
|
||||||
|
do_poll = 1;
|
||||||
|
chip->poll_count++;
|
||||||
|
goto again;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
if (!chip->polling_mode) {
|
if (!chip->polling_mode) {
|
||||||
snd_printk(KERN_WARNING SFX "azx_get_response timeout, "
|
snd_printk(KERN_WARNING SFX "azx_get_response timeout, "
|
||||||
"switching to polling mode: last cmd=0x%08x\n",
|
"switching to polling mode: last cmd=0x%08x\n",
|
||||||
|
Loading…
Reference in New Issue
Block a user