Commit 3bcce5c0 authored by Takashi Iwai's avatar Takashi Iwai

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: default avatarTakashi Iwai <tiwai@suse.de>
parent aa88a355
...@@ -222,8 +222,14 @@ static int codec_exec_verb(struct hda_codec *codec, unsigned int cmd, ...@@ -222,8 +222,14 @@ static int codec_exec_verb(struct hda_codec *codec, unsigned int cmd,
again: again:
snd_hda_power_up(codec); snd_hda_power_up(codec);
mutex_lock(&bus->cmd_mutex); mutex_lock(&bus->cmd_mutex);
trace_hda_send_cmd(codec, cmd); for (;;) {
err = bus->ops.command(bus, cmd); trace_hda_send_cmd(codec, cmd);
err = bus->ops.command(bus, cmd);
if (err != -EAGAIN)
break;
/* process pending verbs */
bus->ops.get_response(bus, codec->addr);
}
if (!err && res) { if (!err && res) {
*res = bus->ops.get_response(bus, codec->addr); *res = bus->ops.get_response(bus, codec->addr);
trace_hda_get_response(codec, *res); trace_hda_get_response(codec, *res);
......
...@@ -797,7 +797,7 @@ static int azx_corb_send_cmd(struct hda_bus *bus, u32 val) ...@@ -797,7 +797,7 @@ static int azx_corb_send_cmd(struct hda_bus *bus, u32 val)
{ {
struct azx *chip = bus->private_data; struct azx *chip = bus->private_data;
unsigned int addr = azx_command_addr(val); unsigned int addr = azx_command_addr(val);
unsigned int wp; unsigned int wp, rp;
spin_lock_irq(&chip->reg_lock); spin_lock_irq(&chip->reg_lock);
...@@ -806,11 +806,18 @@ static int azx_corb_send_cmd(struct hda_bus *bus, u32 val) ...@@ -806,11 +806,18 @@ static int azx_corb_send_cmd(struct hda_bus *bus, u32 val)
if (wp == 0xffff) { if (wp == 0xffff) {
/* something wrong, controller likely turned to D3 */ /* something wrong, controller likely turned to D3 */
spin_unlock_irq(&chip->reg_lock); spin_unlock_irq(&chip->reg_lock);
return -1; return -EIO;
} }
wp++; wp++;
wp %= ICH6_MAX_CORB_ENTRIES; 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->rirb.cmds[addr]++;
chip->corb.buf[wp] = cpu_to_le32(val); chip->corb.buf[wp] = cpu_to_le32(val);
azx_writel(chip, CORBWP, wp); azx_writel(chip, CORBWP, wp);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment