From 9afe23e4c6ac4ca46b93cfe0d3577e6eb5e53e67 Mon Sep 17 00:00:00 2001 From: Libin Yang Date: Wed, 5 Jun 2019 09:20:51 +0800 Subject: [PATCH 1/7] Revert "ASoC: SOF: Intel: hda: switch to use legacy IRQ mode" This reverts commit 0ce706545e8391e4c41077331367ae1e8ba11f8a. --- sound/soc/sof/intel/hda.c | 31 +++++++++++++++++++++---------- 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index d72c6d0bfa70c0..416228730107cd 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -513,17 +513,28 @@ int hda_dsp_probe(struct snd_sof_dev *sdev) /* * register our IRQ - * looks msi has some interrupt missing issues for us, - * let's use legacy interrupt mode before we root casue that. + * let's try to enable msi firstly + * if it fails, use legacy interrupt mode + * TODO: support interrupt mode selection with kernel parameter + * support msi multiple vectors */ - dev_info(sdev->dev, "use legacy interrupt mode\n"); - /* - * use IO-APIC mode, hda->irq and ipc_irq are using the same - * irq number of pci->irq - */ - hdev->irq = pci->irq; - sdev->ipc_irq = pci->irq; - sdev->msi_enabled = 0; + ret = pci_alloc_irq_vectors(pci, 1, 1, PCI_IRQ_MSI); + if (ret < 0) { + dev_info(sdev->dev, "use legacy interrupt mode\n"); + /* + * in IO-APIC mode, hda->irq and ipc_irq are using the same + * irq number of pci->irq + */ + hdev->irq = pci->irq; + sdev->ipc_irq = pci->irq; + sdev->msi_enabled = 0; + } else { + dev_info(sdev->dev, "use msi interrupt mode\n"); + hdev->irq = pci_irq_vector(pci, 0); + /* ipc irq number is the same of hda irq */ + sdev->ipc_irq = hdev->irq; + sdev->msi_enabled = 1; + } dev_dbg(sdev->dev, "using HDA IRQ %d\n", hdev->irq); ret = request_threaded_irq(hdev->irq, hda_dsp_stream_interrupt, From 02dacb68ca81170827069bf6ea8d82f9cb41c4ef Mon Sep 17 00:00:00 2001 From: Libin Yang Date: Wed, 5 Jun 2019 09:57:10 +0800 Subject: [PATCH 2/7] step1 Signed-off-by: Libin Yang --- sound/soc/sof/intel/cnl.c | 86 -------------------------- sound/soc/sof/intel/hda-ipc.c | 113 ++++++++++++++++++++++++++++++++-- sound/soc/sof/intel/hda.c | 4 +- sound/soc/sof/ops.c | 13 +++- sound/soc/sof/ops.h | 6 +- 5 files changed, 125 insertions(+), 97 deletions(-) diff --git a/sound/soc/sof/intel/cnl.c b/sound/soc/sof/intel/cnl.c index 7812f3232a8072..f2a75c4fce96a3 100644 --- a/sound/soc/sof/intel/cnl.c +++ b/sound/soc/sof/intel/cnl.c @@ -29,94 +29,8 @@ static void cnl_ipc_dsp_done(struct snd_sof_dev *sdev); static irqreturn_t cnl_ipc_irq_thread(int irq, void *context) { - struct snd_sof_dev *sdev = context; - u32 hipci; - u32 hipcctl; - u32 hipcida; - u32 hipctdr; - u32 hipctdd; - u32 msg; - u32 msg_ext; irqreturn_t ret = IRQ_NONE; - 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); - - /* reenable IPC interrupt */ - snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, HDA_DSP_REG_ADSPIC, - HDA_DSP_ADSPIC_IPC, HDA_DSP_ADSPIC_IPC); - - /* reply message from DSP */ - if (hipcida & CNL_DSP_REG_HIPCIDA_DONE && - hipcctl & CNL_DSP_REG_HIPCCTL_DONE) { - unsigned long flags; - - hipci = snd_sof_dsp_read(sdev, HDA_DSP_BAR, - CNL_DSP_REG_HIPCIDR); - msg_ext = hipci & CNL_DSP_REG_HIPCIDR_MSG_MASK; - msg = hipcida & CNL_DSP_REG_HIPCIDA_MSG_MASK; - - dev_vdbg(sdev->dev, - "ipc: firmware response, msg:0x%x, msg_ext:0x%x\n", - msg, msg_ext); - - /* mask Done interrupt */ - snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, - CNL_DSP_REG_HIPCCTL, - CNL_DSP_REG_HIPCCTL_DONE, 0); - - spin_lock_irqsave(&sdev->ipc_lock, flags); - - /* handle immediate reply from DSP core */ - hda_dsp_ipc_get_reply(sdev); - snd_sof_ipc_reply(sdev, msg); - - if (sdev->code_loading) { - sdev->code_loading = 0; - wake_up(&sdev->waitq); - } - - cnl_ipc_dsp_done(sdev); - - spin_unlock_irqrestore(&sdev->ipc_lock, flags); - - ret = IRQ_HANDLED; - } - - /* new message from DSP */ - if (hipctdr & CNL_DSP_REG_HIPCTDR_BUSY) { - hipctdd = snd_sof_dsp_read(sdev, HDA_DSP_BAR, - CNL_DSP_REG_HIPCTDD); - msg = hipctdr & CNL_DSP_REG_HIPCTDR_MSG_MASK; - msg_ext = hipctdd & CNL_DSP_REG_HIPCTDD_MSG_MASK; - - dev_vdbg(sdev->dev, - "ipc: firmware initiated, msg:0x%x, msg_ext:0x%x\n", - msg, msg_ext); - - /* handle messages from DSP */ - if ((hipctdr & SOF_IPC_PANIC_MAGIC_MASK) == - SOF_IPC_PANIC_MAGIC) { - snd_sof_dsp_panic(sdev, HDA_DSP_PANIC_OFFSET(msg_ext)); - } else { - snd_sof_ipc_msgs_rx(sdev); - } - - /* - * clear busy interrupt to tell dsp controller this - * interrupt has been accepted, not trigger it again - */ - snd_sof_dsp_update_bits_forced(sdev, HDA_DSP_BAR, - CNL_DSP_REG_HIPCTDR, - CNL_DSP_REG_HIPCTDR_BUSY, - CNL_DSP_REG_HIPCTDR_BUSY); - - cnl_ipc_host_done(sdev); - - ret = IRQ_HANDLED; - } - return ret; } diff --git a/sound/soc/sof/intel/hda-ipc.c b/sound/soc/sof/intel/hda-ipc.c index fc1a1d978b5afe..879174c1367742 100644 --- a/sound/soc/sof/intel/hda-ipc.c +++ b/sound/soc/sof/intel/hda-ipc.c @@ -238,13 +238,53 @@ irqreturn_t hda_dsp_ipc_irq_thread(int irq, void *context) return ret; } +static void cnl_ipc_dsp_done_1(struct snd_sof_dev *sdev) +{ + /* + * set DONE bit - tell DSP we have received the reply msg + * from DSP, and processed it, don't send more reply to host + */ + snd_sof_dsp_update_bits_forced_unlocked(sdev, HDA_DSP_BAR, + CNL_DSP_REG_HIPCIDA, + CNL_DSP_REG_HIPCIDA_DONE, + CNL_DSP_REG_HIPCIDA_DONE); + + /* unmask Done interrupt */ + snd_sof_dsp_update_bits_unlock(sdev, HDA_DSP_BAR, + CNL_DSP_REG_HIPCCTL, + CNL_DSP_REG_HIPCCTL_DONE, + CNL_DSP_REG_HIPCCTL_DONE); +} + +static void cnl_ipc_host_done_1(struct snd_sof_dev *sdev) +{ + /* + * set done bit to ack dsp the msg has been + * processed and send reply msg to dsp + */ + snd_sof_dsp_update_bits_forced_unlocked(sdev, HDA_DSP_BAR, + CNL_DSP_REG_HIPCTDA, + CNL_DSP_REG_HIPCTDA_DONE, + CNL_DSP_REG_HIPCTDA_DONE); +} + /* is this IRQ for ADSP ? - we only care about IPC here */ irqreturn_t hda_dsp_ipc_irq_handler(int irq, void *context) { struct snd_sof_dev *sdev = context; int ret = IRQ_NONE; + u32 hipci; + u32 hipcctl; + u32 hipcida; + u32 hipctdr; + u32 hipctdd; + u32 msg; + u32 msg_ext; u32 irq_status = 0; + 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); spin_lock(&sdev->hw_lock); /* store status */ @@ -256,14 +296,75 @@ irqreturn_t hda_dsp_ipc_irq_handler(int irq, void *context) goto out; /* 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); - ret = IRQ_WAKE_THREAD; + if (!(irq_status & HDA_DSP_ADSPIS_IPC)) + goto out; + + if (hipcida & CNL_DSP_REG_HIPCIDA_DONE && + hipcctl & CNL_DSP_REG_HIPCCTL_DONE) { + hipci = snd_sof_dsp_read(sdev, HDA_DSP_BAR, + CNL_DSP_REG_HIPCIDR); + msg_ext = hipci & CNL_DSP_REG_HIPCIDR_MSG_MASK; + msg = hipcida & CNL_DSP_REG_HIPCIDA_MSG_MASK; + + dev_vdbg(sdev->dev, + "ipc: firmware response, msg:0x%x, msg_ext:0x%x\n", + msg, msg_ext); + + /* mask Done interrupt */ + snd_sof_dsp_update_bits_unlock(sdev, HDA_DSP_BAR, + CNL_DSP_REG_HIPCCTL, + CNL_DSP_REG_HIPCCTL_DONE, 0); + + /* handle immediate reply from DSP core */ + hda_dsp_ipc_get_reply(sdev); + snd_sof_ipc_reply(sdev, msg); + + if (sdev->code_loading) { + sdev->code_loading = 0; + wake_up(&sdev->waitq); + } + + cnl_ipc_dsp_done_1(sdev); + + ret = IRQ_HANDLED; } + /* new message from DSP */ + if (hipctdr & CNL_DSP_REG_HIPCTDR_BUSY) { + hipctdd = snd_sof_dsp_read(sdev, HDA_DSP_BAR, + CNL_DSP_REG_HIPCTDD); + msg = hipctdr & CNL_DSP_REG_HIPCTDR_MSG_MASK; + msg_ext = hipctdd & CNL_DSP_REG_HIPCTDD_MSG_MASK; + + dev_vdbg(sdev->dev, + "ipc: firmware initiated, msg:0x%x, msg_ext:0x%x\n", + msg, msg_ext); + + /* handle messages from DSP */ + if ((hipctdr & SOF_IPC_PANIC_MAGIC_MASK) == + SOF_IPC_PANIC_MAGIC) { + snd_sof_dsp_panic(sdev, HDA_DSP_PANIC_OFFSET(msg_ext)); + } else { + snd_sof_ipc_msgs_rx(sdev); + } + + /* + * clear busy interrupt to tell dsp controller this + * interrupt has been accepted, not trigger it again + */ + snd_sof_dsp_update_bits_forced_unlocked(sdev, HDA_DSP_BAR, + CNL_DSP_REG_HIPCTDR, + CNL_DSP_REG_HIPCTDR_BUSY, + CNL_DSP_REG_HIPCTDR_BUSY); + + cnl_ipc_host_done_1(sdev); + + ret = IRQ_HANDLED; + } + ret = IRQ_HANDLED; + /* /\* reenable IPC interrupt *\/ */ + /* snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, HDA_DSP_REG_ADSPIC, */ + /* HDA_DSP_ADSPIC_IPC, HDA_DSP_ADSPIC_IPC); */ out: spin_unlock(&sdev->hw_lock); return ret; diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index 416228730107cd..afaa0e7396ad22 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -547,8 +547,8 @@ int hda_dsp_probe(struct snd_sof_dev *sdev) } dev_dbg(sdev->dev, "using IPC IRQ %d\n", sdev->ipc_irq); - ret = request_threaded_irq(sdev->ipc_irq, hda_dsp_ipc_irq_handler, - sof_ops(sdev)->irq_thread, IRQF_SHARED, + ret = request_irq(sdev->ipc_irq, hda_dsp_ipc_irq_handler, + IRQF_SHARED, "AudioDSP", sdev); if (ret < 0) { dev_err(sdev->dev, "error: failed to register IPC IRQ %d\n", diff --git a/sound/soc/sof/ops.c b/sound/soc/sof/ops.c index 80f907740b82ce..5b3190d54a1ff6 100644 --- a/sound/soc/sof/ops.c +++ b/sound/soc/sof/ops.c @@ -86,6 +86,17 @@ bool snd_sof_dsp_update_bits64_unlocked(struct snd_sof_dev *sdev, u32 bar, } EXPORT_SYMBOL(snd_sof_dsp_update_bits64_unlocked); +bool snd_sof_dsp_update_bits_unlock(struct snd_sof_dev *sdev, u32 bar, u32 offset, + u32 mask, u32 value) +{ + bool change; + + change = snd_sof_dsp_update_bits_unlocked(sdev, bar, offset, mask, + value); + return change; +} +EXPORT_SYMBOL(snd_sof_dsp_update_bits_unlock); + /* This is for registers bits with attribute RWC */ bool snd_sof_dsp_update_bits(struct snd_sof_dev *sdev, u32 bar, u32 offset, u32 mask, u32 value) @@ -115,7 +126,6 @@ bool snd_sof_dsp_update_bits64(struct snd_sof_dev *sdev, u32 bar, u32 offset, } EXPORT_SYMBOL(snd_sof_dsp_update_bits64); -static void snd_sof_dsp_update_bits_forced_unlocked(struct snd_sof_dev *sdev, u32 bar, u32 offset, u32 mask, u32 value) { @@ -129,6 +139,7 @@ void snd_sof_dsp_update_bits_forced_unlocked(struct snd_sof_dev *sdev, u32 bar, snd_sof_dsp_write(sdev, bar, offset, new); } +EXPORT_SYMBOL(snd_sof_dsp_update_bits_forced_unlocked); /* This is for registers bits with attribute RWC */ void snd_sof_dsp_update_bits_forced(struct snd_sof_dev *sdev, u32 bar, diff --git a/sound/soc/sof/ops.h b/sound/soc/sof/ops.h index 45a3d10911634a..7a2465094f237f 100644 --- a/sound/soc/sof/ops.h +++ b/sound/soc/sof/ops.h @@ -405,7 +405,8 @@ bool snd_sof_dsp_update_bits_unlocked(struct snd_sof_dev *sdev, u32 bar, bool snd_sof_dsp_update_bits64_unlocked(struct snd_sof_dev *sdev, u32 bar, u32 offset, u64 mask, u64 value); - +bool snd_sof_dsp_update_bits_unlock(struct snd_sof_dev *sdev, u32 bar, u32 offset, + u32 mask, u32 value); bool snd_sof_dsp_update_bits(struct snd_sof_dev *sdev, u32 bar, u32 offset, u32 mask, u32 value); @@ -414,7 +415,8 @@ bool snd_sof_dsp_update_bits64(struct snd_sof_dev *sdev, u32 bar, void snd_sof_dsp_update_bits_forced(struct snd_sof_dev *sdev, u32 bar, u32 offset, u32 mask, u32 value); - +void snd_sof_dsp_update_bits_forced_unlocked(struct snd_sof_dev *sdev, u32 bar, + u32 offset, u32 mask, u32 value); int snd_sof_dsp_register_poll(struct snd_sof_dev *sdev, u32 bar, u32 offset, u32 mask, u32 target, u32 timeout_ms, u32 interval_us); From c93242f171a0aec6052c6a119f9a4a5ded468872 Mon Sep 17 00:00:00 2001 From: Libin Yang Date: Tue, 4 Jun 2019 14:55:24 +0800 Subject: [PATCH 3/7] step2 Signed-off-by: Libin Yang --- sound/soc/sof/intel/hda-stream.c | 28 +++++++++++++++++++++++++++- sound/soc/sof/intel/hda.c | 3 +-- 2 files changed, 28 insertions(+), 3 deletions(-) diff --git a/sound/soc/sof/intel/hda-stream.c b/sound/soc/sof/intel/hda-stream.c index 3beb1dc99be0e1..cb120da1da018b 100644 --- a/sound/soc/sof/intel/hda-stream.c +++ b/sound/soc/sof/intel/hda-stream.c @@ -464,6 +464,8 @@ irqreturn_t hda_dsp_stream_interrupt(int irq, void *context) struct sof_intel_hda_dev *sof_hda = bus_to_sof_hda(bus); u32 stream_mask; u32 status; + struct hdac_stream *s; + u32 sd_status; dev_vdbg(bus->dev, "stream irq, INTSTS status: 0x%x\n", snd_hdac_chip_readl(bus, INTSTS)); @@ -492,9 +494,33 @@ irqreturn_t hda_dsp_stream_interrupt(int irq, void *context) } #endif + status = snd_hdac_chip_readl(bus, INTSTS); + /* check streams */ + list_for_each_entry(s, &bus->stream_list, list) { + if (status & (1 << s->index) && s->opened) { + sd_status = snd_hdac_stream_readb(s, SD_STS); + + dev_vdbg(bus->dev, "stream %d status 0x%x\n", + s->index, sd_status); + + snd_hdac_stream_writeb(s, SD_STS, SD_INT_MASK); + + if (!s->substream || + !s->running || + (sd_status & SOF_HDA_CL_DMA_SD_INT_COMPLETE) == 0) + continue; + + /* Inform ALSA only in case not do that with IPC */ + if (sof_hda->no_ipc_position) + snd_pcm_period_elapsed(s->substream); + + } + } + + spin_unlock(&bus->reg_lock); - return snd_hdac_chip_readl(bus, INTSTS) ? IRQ_WAKE_THREAD : IRQ_HANDLED; + return IRQ_HANDLED; } irqreturn_t hda_dsp_stream_threaded_handler(int irq, void *context) diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index afaa0e7396ad22..06beae3f0d802d 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -537,8 +537,7 @@ int hda_dsp_probe(struct snd_sof_dev *sdev) } dev_dbg(sdev->dev, "using HDA IRQ %d\n", hdev->irq); - ret = request_threaded_irq(hdev->irq, hda_dsp_stream_interrupt, - hda_dsp_stream_threaded_handler, + ret = request_irq(hdev->irq, hda_dsp_stream_interrupt, IRQF_SHARED, "AudioHDA", bus); if (ret < 0) { dev_err(sdev->dev, "error: failed to register HDA IRQ %d\n", From 8641f57a823632e50166327e604d07403d8cd1b0 Mon Sep 17 00:00:00 2001 From: Libin Yang Date: Thu, 6 Jun 2019 09:15:53 +0800 Subject: [PATCH 4/7] merge 2 into 1 Signed-off-by: Libin Yang --- sound/soc/sof/intel/hda-ipc.c | 8 +++-- sound/soc/sof/intel/hda-stream.c | 6 ++-- sound/soc/sof/intel/hda.c | 53 ++++++++++++++++++++++---------- sound/soc/sof/sof-priv.h | 1 + 4 files changed, 46 insertions(+), 22 deletions(-) diff --git a/sound/soc/sof/intel/hda-ipc.c b/sound/soc/sof/intel/hda-ipc.c index 879174c1367742..e98f92c40e5c97 100644 --- a/sound/soc/sof/intel/hda-ipc.c +++ b/sound/soc/sof/intel/hda-ipc.c @@ -282,11 +282,12 @@ irqreturn_t hda_dsp_ipc_irq_handler(int irq, void *context) u32 msg_ext; u32 irq_status = 0; + spin_lock(&sdev->hw_lock); + 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); - spin_lock(&sdev->hw_lock); - + sdev->irq_handled = 0; /* store status */ 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); @@ -325,6 +326,7 @@ irqreturn_t hda_dsp_ipc_irq_handler(int irq, void *context) } cnl_ipc_dsp_done_1(sdev); + sdev->irq_handled = 1; ret = IRQ_HANDLED; } @@ -358,10 +360,10 @@ irqreturn_t hda_dsp_ipc_irq_handler(int irq, void *context) CNL_DSP_REG_HIPCTDR_BUSY); cnl_ipc_host_done_1(sdev); + sdev->irq_handled = 1; ret = IRQ_HANDLED; } - ret = IRQ_HANDLED; /* /\* reenable IPC interrupt *\/ */ /* snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, HDA_DSP_REG_ADSPIC, */ /* HDA_DSP_ADSPIC_IPC, HDA_DSP_ADSPIC_IPC); */ diff --git a/sound/soc/sof/intel/hda-stream.c b/sound/soc/sof/intel/hda-stream.c index cb120da1da018b..408d59c0981d94 100644 --- a/sound/soc/sof/intel/hda-stream.c +++ b/sound/soc/sof/intel/hda-stream.c @@ -460,7 +460,8 @@ int hda_dsp_stream_hw_free(struct snd_sof_dev *sdev, irqreturn_t hda_dsp_stream_interrupt(int irq, void *context) { - struct hdac_bus *bus = context; + struct snd_sof_dev *sdev = context; + struct hdac_bus *bus = sof_to_bus(sdev); struct sof_intel_hda_dev *sof_hda = bus_to_sof_hda(bus); u32 stream_mask; u32 status; @@ -470,6 +471,7 @@ irqreturn_t hda_dsp_stream_interrupt(int irq, void *context) dev_vdbg(bus->dev, "stream irq, INTSTS status: 0x%x\n", snd_hdac_chip_readl(bus, INTSTS)); + sdev->irq_handled = 0; if (!pm_runtime_active(bus->dev)) return IRQ_NONE; @@ -519,7 +521,7 @@ irqreturn_t hda_dsp_stream_interrupt(int irq, void *context) spin_unlock(&bus->reg_lock); - + sdev->irq_handled = 1; return IRQ_HANDLED; } diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index 06beae3f0d802d..54193868159c5e 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -416,6 +416,40 @@ static const struct sof_intel_dsp_desc return chip_info; } +irqreturn_t my_irq_handler(int irq, void *context) +{ + struct snd_sof_dev *sdev = context; + //struct hdac_bus *bus; + irqreturn_t ret = IRQ_NONE; + int again = 0; + + //snd_sof_dsp_update_bits_unlocked(sdev, HDA_DSP_BAR, + // HDA_DSP_REG_ADSPIC, + // HDA_DSP_ADSPIC_IPC, 0); +again: + again = 0; + //bus = sof_to_bus(sdev); + hda_dsp_stream_interrupt(irq, context); + if (sdev->irq_handled) { + ret = IRQ_HANDLED; + again = 1; + } + hda_dsp_ipc_irq_handler(irq, context); + if (sdev->irq_handled) { + ret = IRQ_HANDLED; + again = 1; + } + if (again) { + dev_err(sdev->dev, "in %s %d ylb\n", __func__, __LINE__); + goto again; + } + + /* reenable IPC interrupt */ + //snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, HDA_DSP_REG_ADSPIC, + // HDA_DSP_ADSPIC_IPC, HDA_DSP_ADSPIC_IPC); + return ret; +} + int hda_dsp_probe(struct snd_sof_dev *sdev) { struct pci_dev *pci = to_pci_dev(sdev->dev); @@ -537,23 +571,8 @@ int hda_dsp_probe(struct snd_sof_dev *sdev) } dev_dbg(sdev->dev, "using HDA IRQ %d\n", hdev->irq); - ret = request_irq(hdev->irq, hda_dsp_stream_interrupt, - IRQF_SHARED, "AudioHDA", bus); - if (ret < 0) { - dev_err(sdev->dev, "error: failed to register HDA IRQ %d\n", - hdev->irq); - goto free_irq_vector; - } - - dev_dbg(sdev->dev, "using IPC IRQ %d\n", sdev->ipc_irq); - ret = request_irq(sdev->ipc_irq, hda_dsp_ipc_irq_handler, - IRQF_SHARED, - "AudioDSP", sdev); - if (ret < 0) { - dev_err(sdev->dev, "error: failed to register IPC IRQ %d\n", - sdev->ipc_irq); - goto free_hda_irq; - } + ret = request_irq(hdev->irq, my_irq_handler, + IRQF_SHARED, "AudioHDA", sdev); pci_set_master(pci); synchronize_irq(pci->irq); diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index 81eeacb84d2506..6f38c2c8d57b32 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -352,6 +352,7 @@ struct snd_sof_dev { spinlock_t ipc_lock; /* lock for IPC users */ spinlock_t hw_lock; /* lock for HW IO access */ + int irq_handled; /* * ASoC components. plat_drv fields are set dynamically so * can't use const From 04e57634d39cca0431d5d6c36ff8a168a89397d2 Mon Sep 17 00:00:00 2001 From: Libin Yang Date: Thu, 6 Jun 2019 10:00:33 +0800 Subject: [PATCH 5/7] add thread Signed-off-by: Libin Yang --- sound/soc/sof/intel/cnl.c | 19 ++++++++++++++++--- sound/soc/sof/intel/hda-ipc.c | 16 +++++++++------- sound/soc/sof/intel/hda.c | 18 ++++++++++-------- sound/soc/sof/sof-priv.h | 1 + 4 files changed, 36 insertions(+), 18 deletions(-) diff --git a/sound/soc/sof/intel/cnl.c b/sound/soc/sof/intel/cnl.c index f2a75c4fce96a3..458e86fcf281d1 100644 --- a/sound/soc/sof/intel/cnl.c +++ b/sound/soc/sof/intel/cnl.c @@ -29,9 +29,22 @@ static void cnl_ipc_dsp_done(struct snd_sof_dev *sdev); static irqreturn_t cnl_ipc_irq_thread(int irq, void *context) { - irqreturn_t ret = IRQ_NONE; - - return ret; + //irqreturn_t ret = IRQ_NONE; + struct snd_sof_dev *sdev = context; + + + dev_err(sdev->dev, "in %s %d ylb\n", __func__, __LINE__); + if (!sdev->wakeup) + return IRQ_HANDLED; + dev_err(sdev->dev, "in %s %d ylb\n", __func__, __LINE__); + snd_sof_ipc_reply(sdev, 0); + + if (sdev->code_loading) { + sdev->code_loading = 0; + wake_up(&sdev->waitq); + } + sdev->wakeup = 0; + return IRQ_HANDLED; } static void cnl_ipc_host_done(struct snd_sof_dev *sdev) diff --git a/sound/soc/sof/intel/hda-ipc.c b/sound/soc/sof/intel/hda-ipc.c index e98f92c40e5c97..a68ff2cce9cef0 100644 --- a/sound/soc/sof/intel/hda-ipc.c +++ b/sound/soc/sof/intel/hda-ipc.c @@ -318,17 +318,18 @@ irqreturn_t hda_dsp_ipc_irq_handler(int irq, void *context) /* handle immediate reply from DSP core */ hda_dsp_ipc_get_reply(sdev); - snd_sof_ipc_reply(sdev, msg); + sdev->wakeup = 1; + /* snd_sof_ipc_reply(sdev, msg); */ - if (sdev->code_loading) { - sdev->code_loading = 0; - wake_up(&sdev->waitq); - } + /* if (sdev->code_loading) { */ + /* sdev->code_loading = 0; */ + /* wake_up(&sdev->waitq); */ + /* } */ cnl_ipc_dsp_done_1(sdev); sdev->irq_handled = 1; - ret = IRQ_HANDLED; + ret = IRQ_WAKE_THREAD; } /* new message from DSP */ @@ -362,7 +363,8 @@ irqreturn_t hda_dsp_ipc_irq_handler(int irq, void *context) cnl_ipc_host_done_1(sdev); sdev->irq_handled = 1; - ret = IRQ_HANDLED; + if (ret == IRQ_NONE) + ret = IRQ_HANDLED; } /* /\* reenable IPC interrupt *\/ */ /* snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, HDA_DSP_REG_ADSPIC, */ diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index 54193868159c5e..673ae041f3d83d 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -429,25 +429,26 @@ irqreturn_t my_irq_handler(int irq, void *context) again: again = 0; //bus = sof_to_bus(sdev); - hda_dsp_stream_interrupt(irq, context); + ret = hda_dsp_ipc_irq_handler(irq, context); if (sdev->irq_handled) { - ret = IRQ_HANDLED; again = 1; } - hda_dsp_ipc_irq_handler(irq, context); + dev_err(sdev->dev, "in %s %d ylb, ret: %d\n", __func__, __LINE__, ret); + hda_dsp_stream_interrupt(irq, context); if (sdev->irq_handled) { - ret = IRQ_HANDLED; + if (ret == IRQ_NONE) + ret = IRQ_HANDLED; again = 1; } if (again) { - dev_err(sdev->dev, "in %s %d ylb\n", __func__, __LINE__); goto again; } - + dev_err(sdev->dev, "in %s %d ylb, ret: %d\n", __func__, __LINE__, ret); /* reenable IPC interrupt */ //snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, HDA_DSP_REG_ADSPIC, // HDA_DSP_ADSPIC_IPC, HDA_DSP_ADSPIC_IPC); - return ret; + //return IRQ_THREAD; + return IRQ_WAKE_THREAD; } int hda_dsp_probe(struct snd_sof_dev *sdev) @@ -571,7 +572,8 @@ int hda_dsp_probe(struct snd_sof_dev *sdev) } dev_dbg(sdev->dev, "using HDA IRQ %d\n", hdev->irq); - ret = request_irq(hdev->irq, my_irq_handler, + ret = request_threaded_irq(hdev->irq, my_irq_handler, + sof_ops(sdev)->irq_thread, IRQF_SHARED, "AudioHDA", sdev); pci_set_master(pci); diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index 6f38c2c8d57b32..903d865bbfba78 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -353,6 +353,7 @@ struct snd_sof_dev { spinlock_t hw_lock; /* lock for HW IO access */ int irq_handled; + int wakeup; /* * ASoC components. plat_drv fields are set dynamically so * can't use const From 42d1d96c4ace82994d599a2b1b99488e83a5e4ef Mon Sep 17 00:00:00 2001 From: Libin Yang Date: Thu, 6 Jun 2019 12:26:53 +0800 Subject: [PATCH 6/7] tmp Signed-off-by: Libin Yang --- sound/soc/sof/intel/cnl.c | 36 ++++++++++++++++++++++--- sound/soc/sof/intel/hda-stream.c | 46 +++++++++++++++++++------------- sound/soc/sof/sof-priv.h | 1 + 3 files changed, 61 insertions(+), 22 deletions(-) diff --git a/sound/soc/sof/intel/cnl.c b/sound/soc/sof/intel/cnl.c index 458e86fcf281d1..cd0d69940474d0 100644 --- a/sound/soc/sof/intel/cnl.c +++ b/sound/soc/sof/intel/cnl.c @@ -14,7 +14,8 @@ /* * Hardware interface for audio DSP on Cannonlake. */ - +#include +#include #include "../ops.h" #include "hda.h" @@ -31,9 +32,37 @@ static irqreturn_t cnl_ipc_irq_thread(int irq, void *context) { //irqreturn_t ret = IRQ_NONE; struct snd_sof_dev *sdev = context; - + struct hdac_bus *bus = sof_to_bus(sdev); + struct sof_intel_hda_dev *sof_hda = bus_to_sof_hda(bus); + struct hdac_stream *s; + u32 status; + u32 sd_status; + + status = sdev->intsts; + //status = snd_hdac_chip_readl(bus, INTSTS); + dev_err(sdev->dev, "in %s %d ylb, status: %#x\n", __func__, __LINE__, status); + /* check streams */ + list_for_each_entry(s, &bus->stream_list, list) { + if (status & (1 << s->index) && s->opened) { + sd_status = snd_hdac_stream_readb(s, SD_STS); + + dev_vdbg(bus->dev, "stream %d status 0x%x\n", + s->index, sd_status); + + snd_hdac_stream_writeb(s, SD_STS, SD_INT_MASK); + + if (!s->substream || + !s->running || + (sd_status & SOF_HDA_CL_DMA_SD_INT_COMPLETE) == 0) + continue; + + /* Inform ALSA only in case not do that with IPC */ + if (sof_hda->no_ipc_position) + snd_pcm_period_elapsed(s->substream); + + } + } - dev_err(sdev->dev, "in %s %d ylb\n", __func__, __LINE__); if (!sdev->wakeup) return IRQ_HANDLED; dev_err(sdev->dev, "in %s %d ylb\n", __func__, __LINE__); @@ -44,6 +73,7 @@ static irqreturn_t cnl_ipc_irq_thread(int irq, void *context) wake_up(&sdev->waitq); } sdev->wakeup = 0; + sdev->intsts = 0; return IRQ_HANDLED; } diff --git a/sound/soc/sof/intel/hda-stream.c b/sound/soc/sof/intel/hda-stream.c index 408d59c0981d94..b3c68141c20d20 100644 --- a/sound/soc/sof/intel/hda-stream.c +++ b/sound/soc/sof/intel/hda-stream.c @@ -479,7 +479,7 @@ irqreturn_t hda_dsp_stream_interrupt(int irq, void *context) status = snd_hdac_chip_readl(bus, INTSTS); stream_mask = GENMASK(sof_hda->stream_max - 1, 0) | AZX_INT_CTRL_EN; - + dev_err(sdev->dev, "in %s %d ylb status: %#x, intsts: %#x\n", __func__, __LINE__, status, sdev->intsts); /* Not stream interrupt or register inaccessible, ignore it.*/ if (!(status & stream_mask) || status == 0xffffffff) { spin_unlock(&bus->reg_lock); @@ -495,33 +495,41 @@ irqreturn_t hda_dsp_stream_interrupt(int irq, void *context) snd_hdac_chip_writeb(bus, RIRBSTS, RIRB_INT_MASK); } #endif - + dev_err(sdev->dev, "in %s %d ylb\n", __func__, __LINE__); status = snd_hdac_chip_readl(bus, INTSTS); - /* check streams */ - list_for_each_entry(s, &bus->stream_list, list) { - if (status & (1 << s->index) && s->opened) { - sd_status = snd_hdac_stream_readb(s, SD_STS); + dev_err(sdev->dev, "in %s %d ylb status: %#x, intsts: %#x\n", __func__, __LINE__, status, sdev->intsts); + sdev->irq_handled = 1; + if (!sdev->intsts) + sdev->intsts = status; + else + sdev->irq_handled = 0; - dev_vdbg(bus->dev, "stream %d status 0x%x\n", - s->index, sd_status); + + /* /\* check streams *\/ */ + /* list_for_each_entry(s, &bus->stream_list, list) { */ + /* if (status & (1 << s->index) && s->opened) { */ + /* sd_status = snd_hdac_stream_readb(s, SD_STS); */ - snd_hdac_stream_writeb(s, SD_STS, SD_INT_MASK); + /* dev_vdbg(bus->dev, "stream %d status 0x%x\n", */ + /* s->index, sd_status); */ - if (!s->substream || - !s->running || - (sd_status & SOF_HDA_CL_DMA_SD_INT_COMPLETE) == 0) - continue; + /* snd_hdac_stream_writeb(s, SD_STS, SD_INT_MASK); */ - /* Inform ALSA only in case not do that with IPC */ - if (sof_hda->no_ipc_position) - snd_pcm_period_elapsed(s->substream); + /* if (!s->substream || */ + /* !s->running || */ + /* (sd_status & SOF_HDA_CL_DMA_SD_INT_COMPLETE) == 0) */ + /* continue; */ - } - } + /* /\* Inform ALSA only in case not do that with IPC *\/ */ + /* if (sof_hda->no_ipc_position) */ + /* snd_pcm_period_elapsed(s->substream); */ + + /* } */ + /* } */ spin_unlock(&bus->reg_lock); - sdev->irq_handled = 1; + return IRQ_HANDLED; } diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index 903d865bbfba78..273d6e1b6e5002 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -354,6 +354,7 @@ struct snd_sof_dev { int irq_handled; int wakeup; + u32 intsts; /* * ASoC components. plat_drv fields are set dynamically so * can't use const From c19b3c8902a027363c1264e82100307a1b70c436 Mon Sep 17 00:00:00 2001 From: Libin Yang Date: Thu, 6 Jun 2019 13:11:14 +0800 Subject: [PATCH 7/7] works --- sound/soc/sof/intel/cnl.c | 14 ++++++++++++-- sound/soc/sof/intel/hda-stream.c | 2 -- sound/soc/sof/intel/hda.c | 19 ++++++++++++------- 3 files changed, 24 insertions(+), 11 deletions(-) diff --git a/sound/soc/sof/intel/cnl.c b/sound/soc/sof/intel/cnl.c index cd0d69940474d0..8c87f3e7cb956f 100644 --- a/sound/soc/sof/intel/cnl.c +++ b/sound/soc/sof/intel/cnl.c @@ -38,9 +38,19 @@ static irqreturn_t cnl_ipc_irq_thread(int irq, void *context) u32 status; u32 sd_status; - status = sdev->intsts; - //status = snd_hdac_chip_readl(bus, INTSTS); + //status = sdev->intsts; + status = snd_hdac_chip_readl(bus, INTSTS); +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) + /* clear rirb int */ + status = snd_hdac_chip_readb(bus, RIRBSTS); + if (status & RIRB_INT_MASK) { + if (status & RIRB_INT_RESPONSE) + snd_hdac_bus_update_rirb(bus); + snd_hdac_chip_writeb(bus, RIRBSTS, RIRB_INT_MASK); + } +#endif dev_err(sdev->dev, "in %s %d ylb, status: %#x\n", __func__, __LINE__, status); + status = snd_hdac_chip_readl(bus, INTSTS); /* check streams */ list_for_each_entry(s, &bus->stream_list, list) { if (status & (1 << s->index) && s->opened) { diff --git a/sound/soc/sof/intel/hda-stream.c b/sound/soc/sof/intel/hda-stream.c index b3c68141c20d20..fbfff308160b24 100644 --- a/sound/soc/sof/intel/hda-stream.c +++ b/sound/soc/sof/intel/hda-stream.c @@ -501,8 +501,6 @@ irqreturn_t hda_dsp_stream_interrupt(int irq, void *context) sdev->irq_handled = 1; if (!sdev->intsts) sdev->intsts = status; - else - sdev->irq_handled = 0; /* /\* check streams *\/ */ diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index 673ae041f3d83d..7a37a09e699fa4 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -15,6 +15,7 @@ * Hardware interface for generic Intel audio DSP HDA IP */ +#include #include #include #include @@ -419,8 +420,10 @@ static const struct sof_intel_dsp_desc irqreturn_t my_irq_handler(int irq, void *context) { struct snd_sof_dev *sdev = context; + struct hdac_bus *bus = sof_to_bus(sdev); //struct hdac_bus *bus; irqreturn_t ret = IRQ_NONE; + u32 status; int again = 0; //snd_sof_dsp_update_bits_unlocked(sdev, HDA_DSP_BAR, @@ -435,14 +438,16 @@ irqreturn_t my_irq_handler(int irq, void *context) } dev_err(sdev->dev, "in %s %d ylb, ret: %d\n", __func__, __LINE__, ret); hda_dsp_stream_interrupt(irq, context); - if (sdev->irq_handled) { - if (ret == IRQ_NONE) - ret = IRQ_HANDLED; - again = 1; - } - if (again) { + //if (sdev->irq_handled) { + // if (ret == IRQ_NONE) + // ret = IRQ_HANDLED; + // again = 1; + //} + //if (again) + // goto again; + status = snd_hdac_chip_readl(bus, INTSTS); + if (status & AZX_INT_CTRL_EN) goto again; - } dev_err(sdev->dev, "in %s %d ylb, ret: %d\n", __func__, __LINE__, ret); /* reenable IPC interrupt */ //snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, HDA_DSP_REG_ADSPIC,