summaryrefslogtreecommitdiff
path: root/sound/hda
diff options
context:
space:
mode:
authorJeeja KP <jeeja.kp@intel.com>2016-05-05 11:24:43 +0530
committerTakashi Iwai <tiwai@suse.de>2016-05-08 11:43:36 +0200
commit38b19ed7f81ec930f3ad2066ae088f574970c814 (patch)
treec1bbc901d207c0325d0c6d1692dad6ad644f8afb /sound/hda
parent94e9080ce22d9fb7c0a4361a5890b2c6affc9b1b (diff)
ALSA: hda: fix to wait for RIRB & CORB DMA to set
If the DMAs are not being quiesced properly, it may lead to stability issues, so the recommendation is to wait till DMAs are stopped. After setting the stop bit of RIRB/CORB DMA, we should wait for stop bit to be set. Signed-off-by: Jeeja KP <jeeja.kp@intel.com> Signed-off-by: Vinod Koul <vinod.koul@intel.com> Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/hda')
-rw-r--r--sound/hda/hdac_controller.c17
1 files changed, 17 insertions, 0 deletions
diff --git a/sound/hda/hdac_controller.c b/sound/hda/hdac_controller.c
index 8c486235c905..9fee464e5d49 100644
--- a/sound/hda/hdac_controller.c
+++ b/sound/hda/hdac_controller.c
@@ -80,6 +80,22 @@ void snd_hdac_bus_init_cmd_io(struct hdac_bus *bus)
}
EXPORT_SYMBOL_GPL(snd_hdac_bus_init_cmd_io);
+/* wait for cmd dmas till they are stopped */
+static void hdac_wait_for_cmd_dmas(struct hdac_bus *bus)
+{
+ unsigned long timeout;
+
+ timeout = jiffies + msecs_to_jiffies(100);
+ while ((snd_hdac_chip_readb(bus, RIRBCTL) & AZX_RBCTL_DMA_EN)
+ && time_before(jiffies, timeout))
+ udelay(10);
+
+ timeout = jiffies + msecs_to_jiffies(100);
+ while ((snd_hdac_chip_readb(bus, CORBCTL) & AZX_CORBCTL_RUN)
+ && time_before(jiffies, timeout))
+ udelay(10);
+}
+
/**
* snd_hdac_bus_stop_cmd_io - clean up CORB/RIRB buffers
* @bus: HD-audio core bus
@@ -90,6 +106,7 @@ void snd_hdac_bus_stop_cmd_io(struct hdac_bus *bus)
/* disable ringbuffer DMAs */
snd_hdac_chip_writeb(bus, RIRBCTL, 0);
snd_hdac_chip_writeb(bus, CORBCTL, 0);
+ hdac_wait_for_cmd_dmas(bus);
/* disable unsolicited responses */
snd_hdac_chip_updatel(bus, GCTL, AZX_GCTL_UNSOL, 0);
spin_unlock_irq(&bus->reg_lock);