From 8d6826ff44cee1e7dd2a1d9cc988caf6855e3de7 Mon Sep 17 00:00:00 2001 From: Keyon Jie Date: Wed, 17 Apr 2019 18:31:36 +0800 Subject: [PATCH 1/3] ASoC: SOF: Intel: hda-ipc: simplify handling of IPC IRQ When using a shared IRQ between IPC interrupt and stream IOC interrupt, the interrupt handlers need to check the interrupt source before scheduling their respective IRQ threads. In the case of IPC handler, it should check if it is an IPC interrupt before waking up the IPC IRQ thread. The IPC IRQ thread, once scheduled, does not need to check the IRQ source again. So, remove the superfluous check in the thread. Remove the irq_status field from snd_sof_dev struct also as it is no longer needed. Signed-off-by: Keyon Jie --- sound/soc/sof/intel/cnl.c | 4 ---- sound/soc/sof/intel/hda-ipc.c | 13 +++++-------- sound/soc/sof/sof-priv.h | 1 - 3 files changed, 5 insertions(+), 13 deletions(-) diff --git a/sound/soc/sof/intel/cnl.c b/sound/soc/sof/intel/cnl.c index 3afd96d9c92575..d128839b24504b 100644 --- a/sound/soc/sof/intel/cnl.c +++ b/sound/soc/sof/intel/cnl.c @@ -39,10 +39,6 @@ static irqreturn_t cnl_ipc_irq_thread(int irq, void *context) u32 msg_ext; irqreturn_t ret = IRQ_NONE; - /* here we handle IPC interrupts only */ - if (!(sdev->irq_status & HDA_DSP_ADSPIS_IPC)) - return ret; - hipcida = snd_sof_dsp_read(sdev, HDA_DSP_BAR, CNL_DSP_REG_HIPCIDA); hipcctl = snd_sof_dsp_read(sdev, HDA_DSP_BAR, CNL_DSP_REG_HIPCCTL); hipctdr = snd_sof_dsp_read(sdev, HDA_DSP_BAR, CNL_DSP_REG_HIPCTDR); diff --git a/sound/soc/sof/intel/hda-ipc.c b/sound/soc/sof/intel/hda-ipc.c index a938f568dbb1c3..73ead7070cdefd 100644 --- a/sound/soc/sof/intel/hda-ipc.c +++ b/sound/soc/sof/intel/hda-ipc.c @@ -145,10 +145,6 @@ irqreturn_t hda_dsp_ipc_irq_thread(int irq, void *context) u32 msg; u32 msg_ext; - /* here we handle IPC interrupts only */ - if (!(sdev->irq_status & HDA_DSP_ADSPIS_IPC)) - return IRQ_NONE; - /* read IPC status */ hipcie = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_REG_HIPCIE); @@ -234,19 +230,20 @@ irqreturn_t hda_dsp_ipc_irq_handler(int irq, void *context) { struct snd_sof_dev *sdev = context; int ret = IRQ_NONE; + u32 irq_status; spin_lock(&sdev->hw_lock); /* store status */ - sdev->irq_status = snd_sof_dsp_read(sdev, HDA_DSP_BAR, - HDA_DSP_REG_ADSPIS); + irq_status = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_REG_ADSPIS); + dev_vdbg(sdev->dev, "irq handler: irq_status:0x%x\n", irq_status); /* invalid message ? */ - if (sdev->irq_status == 0xffffffff) + if (irq_status == 0xffffffff) goto out; /* IPC message ? */ - if (sdev->irq_status & HDA_DSP_ADSPIS_IPC) { + if (irq_status & HDA_DSP_ADSPIS_IPC) { /* disable IPC interrupt */ snd_sof_dsp_update_bits_unlocked(sdev, HDA_DSP_BAR, HDA_DSP_REG_ADSPIC, diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index 35e78ffecce2fe..192b8828fd3d06 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -365,7 +365,6 @@ struct snd_sof_dev { struct snd_sof_mailbox host_box; /* Host initiated IPC */ struct snd_sof_mailbox stream_box; /* Stream position update */ struct snd_sof_ipc_msg *msg; - u64 irq_status; int ipc_irq; u32 next_comp_id; /* monotonic - reset during S3 */ From f34858a835582f8ab7e2f1279d80e31d4fdd5ef4 Mon Sep 17 00:00:00 2001 From: Keyon Jie Date: Thu, 18 Apr 2019 17:31:05 +0800 Subject: [PATCH 2/3] ASoC: SOF: Intel: hda-stream: store stream capabilities Add stream_max into struct sof_intel_hda_dev to store the total hda stream number that the platform can support, and initialize it at stream_init. This can be used later e.g. for stream bitmask. Signed-off-by: Keyon Jie --- sound/soc/sof/intel/hda-stream.c | 4 ++++ sound/soc/sof/intel/hda.h | 3 +++ 2 files changed, 7 insertions(+) diff --git a/sound/soc/sof/intel/hda-stream.c b/sound/soc/sof/intel/hda-stream.c index 6290b2df5e621d..3c7e36ae9b7530 100644 --- a/sound/soc/sof/intel/hda-stream.c +++ b/sound/soc/sof/intel/hda-stream.c @@ -500,6 +500,7 @@ int hda_dsp_stream_init(struct snd_sof_dev *sdev) struct hdac_ext_stream *stream; struct hdac_stream *hstream; struct pci_dev *pci = to_pci_dev(sdev->dev); + struct sof_intel_hda_dev *sof_hda = bus_to_sof_hda(bus); int sd_offset; int i, num_playback, num_capture, num_total, ret; u32 gcap; @@ -657,6 +658,9 @@ int hda_dsp_stream_init(struct snd_sof_dev *sdev) list_add_tail(&hstream->list, &bus->stream_list); } + /* store total stream count (playback + capture) from GCAP */ + sof_hda->stream_max = num_total; + return 0; } diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index 7d78110c65a609..59ae6f8a1beaee 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -384,6 +384,9 @@ struct sof_intel_hda_dev { /* if position update IPC needed */ u32 no_ipc_position; + /* the maximum number of streams (playback + capture) supported */ + u32 stream_max; + int irq; /* DMIC device */ From d9f2c03db70dd49579a474fa48b37e02668a4087 Mon Sep 17 00:00:00 2001 From: Keyon Jie Date: Wed, 17 Apr 2019 18:52:20 +0800 Subject: [PATCH 3/3] ASoC: SOF: Intel: hda-stream: handle real stream interrupts only The stream and IPC share the same interrupt. The stream interrupt handler mistakenly uses the ipc interrupt and return IRQ_HANDLED, causing the ipc interrupt to be missed. Make sure the stream interrupt handler only deals with stream-related interrupts. Signed-off-by: Keyon Jie --- sound/soc/sof/intel/hda-stream.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/sound/soc/sof/intel/hda-stream.c b/sound/soc/sof/intel/hda-stream.c index 3c7e36ae9b7530..f9c9a40b2ea991 100644 --- a/sound/soc/sof/intel/hda-stream.c +++ b/sound/soc/sof/intel/hda-stream.c @@ -433,6 +433,8 @@ int hda_dsp_stream_hw_params(struct snd_sof_dev *sdev, irqreturn_t hda_dsp_stream_interrupt(int irq, void *context) { struct hdac_bus *bus = context; + struct sof_intel_hda_dev *sof_hda = bus_to_sof_hda(bus); + u32 stream_mask; u32 status; if (!pm_runtime_active(bus->dev)) @@ -441,7 +443,10 @@ irqreturn_t hda_dsp_stream_interrupt(int irq, void *context) spin_lock(&bus->reg_lock); status = snd_hdac_chip_readl(bus, INTSTS); - if (status == 0 || status == 0xffffffff) { + stream_mask = GENMASK(sof_hda->stream_max - 1, 0) | AZX_INT_CTRL_EN; + + /* Not stream interrupt or register inaccessible, ignore it.*/ + if (!(status & stream_mask) || status == 0xffffffff) { spin_unlock(&bus->reg_lock); return IRQ_NONE; }