mirror of
https://github.com/torvalds/linux.git
synced 2026-06-05 04:56:13 +02:00
ASoC: SOF: Intel: hda: use global interrupt enable/disable
We have a Global Interrupt Enable (GIE) flag, which can be used to mask all possible interrupts instead of disabling each possible source of interrupts. Since we have a shared interrupt, the proposal is to use a single mask, merge all handlers together and test the sources of interrupts without any racy behavior. Credits to Bard Liao for most of the ideas, I just experimented with the GIE flag. Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
This commit is contained in:
parent
74dd135590
commit
c642382958
|
|
@ -107,10 +107,6 @@ static irqreturn_t cnl_ipc_irq_thread(int irq, void *context)
|
|||
"nothing to do in IPC IRQ thread\n");
|
||||
}
|
||||
|
||||
/* re-enable IPC interrupt */
|
||||
snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, HDA_DSP_REG_ADSPIC,
|
||||
HDA_DSP_ADSPIC_IPC, HDA_DSP_ADSPIC_IPC);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -230,14 +230,10 @@ irqreturn_t hda_dsp_ipc_irq_thread(int irq, void *context)
|
|||
"nothing to do in IPC IRQ thread\n");
|
||||
}
|
||||
|
||||
/* re-enable IPC interrupt */
|
||||
snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, HDA_DSP_REG_ADSPIC,
|
||||
HDA_DSP_ADSPIC_IPC, HDA_DSP_ADSPIC_IPC);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
/* Check if it is an IPC and disable IPC interrupt if yes */
|
||||
/* Check if an IPC IRQ occurred */
|
||||
bool hda_dsp_check_ipc_irq(struct snd_sof_dev *sdev)
|
||||
{
|
||||
bool ret = false;
|
||||
|
|
@ -256,10 +252,7 @@ bool hda_dsp_check_ipc_irq(struct snd_sof_dev *sdev)
|
|||
|
||||
/* IPC message ? */
|
||||
if (irq_status & HDA_DSP_ADSPIS_IPC) {
|
||||
/* disable IPC interrupt */
|
||||
snd_sof_dsp_update_bits_unlocked(sdev, HDA_DSP_BAR,
|
||||
HDA_DSP_REG_ADSPIC,
|
||||
HDA_DSP_ADSPIC_IPC, 0);
|
||||
sdev->irq_event |= SOF_HDA_IRQ_IPC;
|
||||
ret = true;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -553,7 +553,7 @@ int hda_dsp_stream_hw_free(struct snd_sof_dev *sdev,
|
|||
bool hda_dsp_check_stream_irq(struct snd_sof_dev *sdev)
|
||||
{
|
||||
struct hdac_bus *bus = sof_to_bus(sdev);
|
||||
bool ret = true;
|
||||
bool ret = false;
|
||||
u32 status;
|
||||
|
||||
/* The function can be called at irq thread, so use spin_lock_irq */
|
||||
|
|
@ -562,9 +562,11 @@ bool hda_dsp_check_stream_irq(struct snd_sof_dev *sdev)
|
|||
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 = false;
|
||||
/* if Register inaccessible, ignore it.*/
|
||||
if (status != 0xffffffff) {
|
||||
sdev->irq_event |= SOF_HDA_IRQ_STREAM;
|
||||
ret = true;
|
||||
}
|
||||
|
||||
spin_unlock_irq(&bus->reg_lock);
|
||||
|
||||
|
|
|
|||
|
|
@ -406,9 +406,20 @@ static irqreturn_t hda_dsp_interrupt_handler(int irq, void *context)
|
|||
{
|
||||
struct snd_sof_dev *sdev = context;
|
||||
|
||||
if (hda_dsp_check_ipc_irq(sdev) ||
|
||||
hda_dsp_check_stream_irq(sdev))
|
||||
/* clear flags for interrupt sources */
|
||||
sdev->irq_event = 0;
|
||||
|
||||
if (hda_dsp_check_stream_irq(sdev) ||
|
||||
hda_dsp_check_ipc_irq(sdev)) {
|
||||
|
||||
/* disable GIE interrupt */
|
||||
snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR,
|
||||
SOF_HDA_INTCTL,
|
||||
SOF_HDA_INT_GLOBAL_EN,
|
||||
0);
|
||||
|
||||
return IRQ_WAKE_THREAD;
|
||||
}
|
||||
|
||||
return IRQ_NONE;
|
||||
}
|
||||
|
|
@ -417,11 +428,21 @@ static irqreturn_t hda_dsp_interrupt_thread(int irq, void *context)
|
|||
{
|
||||
struct snd_sof_dev *sdev = context;
|
||||
|
||||
if (hda_dsp_check_ipc_irq(sdev))
|
||||
sof_ops(sdev)->irq_thread(irq, sdev);
|
||||
if (hda_dsp_check_stream_irq(sdev))
|
||||
/* deal with streams and controller first */
|
||||
if (sdev->irq_event & SOF_HDA_IRQ_STREAM ||
|
||||
hda_dsp_check_stream_irq(sdev))
|
||||
hda_dsp_stream_threaded_handler(irq, sdev);
|
||||
|
||||
if (sdev->irq_event & SOF_HDA_IRQ_IPC ||
|
||||
hda_dsp_check_ipc_irq(sdev))
|
||||
sof_ops(sdev)->irq_thread(irq, sdev);
|
||||
|
||||
/* enable GIE interrupt */
|
||||
snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR,
|
||||
SOF_HDA_INTCTL,
|
||||
SOF_HDA_INT_GLOBAL_EN,
|
||||
SOF_HDA_INT_GLOBAL_EN);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -389,6 +389,11 @@ struct sof_intel_dsp_bdl {
|
|||
#define SOF_HDA_PLAYBACK 0
|
||||
#define SOF_HDA_CAPTURE 1
|
||||
|
||||
/* flags to memorize IPC source (not hardware-defined) */
|
||||
#define SOF_HDA_IRQ_IPC BIT(0)
|
||||
#define SOF_HDA_IRQ_STREAM BIT(1)
|
||||
#define SOF_HDA_IRQ_SDW BIT(2)
|
||||
|
||||
/* represents DSP HDA controller frontend - i.e. host facing control */
|
||||
struct sof_intel_hda_dev {
|
||||
|
||||
|
|
|
|||
|
|
@ -387,6 +387,7 @@ struct snd_sof_dev {
|
|||
u32 dtrace_draining;
|
||||
|
||||
bool msi_enabled;
|
||||
u32 irq_event;
|
||||
|
||||
void *private; /* core does not touch this */
|
||||
};
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user