summaryrefslogtreecommitdiff
path: root/sound/soc/sof/intel/hda-stream.c
diff options
context:
space:
mode:
authorBard Liao <yung-chuan.liao@linux.intel.com>2019-12-04 15:28:59 -0600
committerMark Brown <broonie@kernel.org>2019-12-09 18:35:56 +0000
commit7c11af9fcdc425b80f140a218d4fef9f17734bfc (patch)
tree1316234b4cecc9854d2493dd02840a035e400534 /sound/soc/sof/intel/hda-stream.c
parent253f584a0699d12a90bde9d524d499a921cc7827 (diff)
ASoC: SOF: Intel: hda: solve MSI issues by merging ipc and stream irq handlers
The existing code uses two handlers for a shared edge-based MSI interrupts. In corner cases, interrupts are lost, leading to IPC timeouts. Those timeouts do not appear in legacy mode. This patch merges the two handlers and threads into a single one, and simplifies the mask/unmask operations by using a single top-level mask (Global Interrupt Enable). The handler only checks for interrupt sources using the Global Interrupt Status (GIS) field, and all the actual work happens in the thread. This also enables us to remove the use of spin locks. Stream events are prioritized over IPC ones. This patch was tested with HDaudio and SoundWire platforms, and all known IPC timeout issues are solved in MSI mode. The SoundWire-specific patches will be provided in follow-up patches, where the SoundWire interrupts are handled in the same thread as IPC and stream interrupts. Signed-off-by: Bard Liao <yung-chuan.liao@linux.intel.com> Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com> Link: https://lore.kernel.org/r/20191204212859.13239-1-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown <broonie@kernel.org>
Diffstat (limited to 'sound/soc/sof/intel/hda-stream.c')
-rw-r--r--sound/soc/sof/intel/hda-stream.c20
1 files changed, 11 insertions, 9 deletions
diff --git a/sound/soc/sof/intel/hda-stream.c b/sound/soc/sof/intel/hda-stream.c
index 29ab43281670..927a36f92c24 100644
--- a/sound/soc/sof/intel/hda-stream.c
+++ b/sound/soc/sof/intel/hda-stream.c
@@ -549,22 +549,23 @@ int hda_dsp_stream_hw_free(struct snd_sof_dev *sdev,
return 0;
}
-irqreturn_t hda_dsp_stream_interrupt(int irq, void *context)
+bool hda_dsp_check_stream_irq(struct snd_sof_dev *sdev)
{
- struct hdac_bus *bus = context;
- int ret = IRQ_WAKE_THREAD;
+ struct hdac_bus *bus = sof_to_bus(sdev);
+ bool ret = false;
u32 status;
- spin_lock(&bus->reg_lock);
+ /* The function can be called at irq thread, so use spin_lock_irq */
+ spin_lock_irq(&bus->reg_lock);
status = snd_hdac_chip_readl(bus, INTSTS);
dev_vdbg(bus->dev, "stream irq, INTSTS status: 0x%x\n", status);
- /* Register inaccessible, ignore it.*/
- if (status == 0xffffffff)
- ret = IRQ_NONE;
+ /* if Register inaccessible, ignore it.*/
+ if (status != 0xffffffff)
+ ret = true;
- spin_unlock(&bus->reg_lock);
+ spin_unlock_irq(&bus->reg_lock);
return ret;
}
@@ -602,7 +603,8 @@ static bool hda_dsp_stream_check(struct hdac_bus *bus, u32 status)
irqreturn_t hda_dsp_stream_threaded_handler(int irq, void *context)
{
- struct hdac_bus *bus = context;
+ struct snd_sof_dev *sdev = context;
+ struct hdac_bus *bus = sof_to_bus(sdev);
#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
u32 rirb_status;
#endif