diff options
author | Takashi Iwai <tiwai@suse.de> | 2012-12-20 11:17:17 +0100 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2013-01-12 08:33:56 +0100 |
commit | 3bcce5c0d931bf623adc5974200e4d7636b10bef (patch) | |
tree | 0174be815bfcf29033effad302171275756dbab9 /sound/pci/hda/hda_intel.c | |
parent | aa88a3553eebdcc3ce6801aabb4ed0223bfa198e (diff) |
ALSA: hda - Check CORB overflow
Add an overflow check of CORB in HD-audio controller and codec drivers
so that flood of sequential writes would work properly.
In the controller side, add a check of CORB read-pointer to make
returning -EAGAIN when it's full. Meanwhile in the codec side, when
-EAGAIN error is received, it retries the write after flushing the
pending verbs (calling get_response() essentially does it).
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/pci/hda/hda_intel.c')
-rw-r--r-- | sound/pci/hda/hda_intel.c | 11 |
1 files changed, 9 insertions, 2 deletions
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 0b6aebacc56..0430436b003 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -797,7 +797,7 @@ static int azx_corb_send_cmd(struct hda_bus *bus, u32 val) { struct azx *chip = bus->private_data; unsigned int addr = azx_command_addr(val); - unsigned int wp; + unsigned int wp, rp; spin_lock_irq(&chip->reg_lock); @@ -806,11 +806,18 @@ static int azx_corb_send_cmd(struct hda_bus *bus, u32 val) if (wp == 0xffff) { /* something wrong, controller likely turned to D3 */ spin_unlock_irq(&chip->reg_lock); - return -1; + return -EIO; } wp++; wp %= ICH6_MAX_CORB_ENTRIES; + rp = azx_readw(chip, CORBRP); + if (wp == rp) { + /* oops, it's full */ + spin_unlock_irq(&chip->reg_lock); + return -EAGAIN; + } + chip->rirb.cmds[addr]++; chip->corb.buf[wp] = cpu_to_le32(val); azx_writel(chip, CORBWP, wp); |