ASoC: Intel: avs: New IRQ handling implementation
The existing code can be both improved and simplified. To make this change easier to manage, first add new implementation and then remove deadcode in a separate patch. Simplification achieved with: - reduce the amount of resources requested by the driver i.e.: IPC and CLDMA request_irq() merged into one - reduce the number of DSP ops from 2 to 1: irq_handler/thread() vs dsp_interrupt() - drop ambiguity around CLDMA interrupt, let skl.c handle that explicitly as it is the only user Signed-off-by: Cezary Rojewski <cezary.rojewski@intel.com> Link: https://lore.kernel.org/r/20240419084857.2719593-2-cezary.rojewski@intel.com Signed-off-by: Mark Brown <broonie@kernel.org>
This commit is contained in:
parent
9be51470d5
commit
7ce6ceeb77
|
@ -8,11 +8,28 @@
|
|||
|
||||
#include <linux/devcoredump.h>
|
||||
#include <linux/slab.h>
|
||||
#include <sound/hdaudio_ext.h>
|
||||
#include "avs.h"
|
||||
#include "messages.h"
|
||||
#include "path.h"
|
||||
#include "topology.h"
|
||||
|
||||
static irqreturn_t avs_apl_dsp_interrupt(struct avs_dev *adev)
|
||||
{
|
||||
u32 adspis = snd_hdac_adsp_readl(adev, AVS_ADSP_REG_ADSPIS);
|
||||
irqreturn_t ret = IRQ_NONE;
|
||||
|
||||
if (adspis == UINT_MAX)
|
||||
return ret;
|
||||
|
||||
if (adspis & AVS_ADSP_ADSPIS_IPC) {
|
||||
avs_skl_ipc_interrupt(adev);
|
||||
ret = IRQ_HANDLED;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
int avs_apl_enable_logs(struct avs_dev *adev, enum avs_log_enable enable, u32 aging_period,
|
||||
u32 fifo_full_period, unsigned long resource_mask, u32 *priorities)
|
||||
|
@ -237,6 +254,7 @@ const struct avs_dsp_ops avs_apl_dsp_ops = {
|
|||
.power = avs_dsp_core_power,
|
||||
.reset = avs_dsp_core_reset,
|
||||
.stall = avs_dsp_core_stall,
|
||||
.dsp_interrupt = avs_apl_dsp_interrupt,
|
||||
.irq_handler = avs_irq_handler,
|
||||
.irq_thread = avs_skl_irq_thread,
|
||||
.int_control = avs_dsp_interrupt_control,
|
||||
|
|
|
@ -46,6 +46,7 @@ struct avs_dsp_ops {
|
|||
int (* const power)(struct avs_dev *, u32, bool);
|
||||
int (* const reset)(struct avs_dev *, u32, bool);
|
||||
int (* const stall)(struct avs_dev *, u32, bool);
|
||||
irqreturn_t (* const dsp_interrupt)(struct avs_dev *);
|
||||
irqreturn_t (* const irq_handler)(struct avs_dev *);
|
||||
irqreturn_t (* const irq_thread)(struct avs_dev *);
|
||||
void (* const int_control)(struct avs_dev *, bool);
|
||||
|
@ -269,6 +270,8 @@ int avs_dsp_enable_d0ix(struct avs_dev *adev);
|
|||
|
||||
irqreturn_t avs_skl_irq_thread(struct avs_dev *adev);
|
||||
irqreturn_t avs_cnl_irq_thread(struct avs_dev *adev);
|
||||
void avs_skl_ipc_interrupt(struct avs_dev *adev);
|
||||
irqreturn_t avs_cnl_dsp_interrupt(struct avs_dev *adev);
|
||||
int avs_apl_enable_logs(struct avs_dev *adev, enum avs_log_enable enable, u32 aging_period,
|
||||
u32 fifo_full_period, unsigned long resource_mask, u32 *priorities);
|
||||
int avs_icl_enable_logs(struct avs_dev *adev, enum avs_log_enable enable, u32 aging_period,
|
||||
|
|
|
@ -270,6 +270,17 @@ static irqreturn_t cldma_irq_handler(int irq, void *dev_id)
|
|||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
void hda_cldma_interrupt(struct hda_cldma *cl)
|
||||
{
|
||||
/* disable CLDMA interrupt */
|
||||
snd_hdac_adsp_updatel(cl, AVS_ADSP_REG_ADSPIC, AVS_ADSP_ADSPIC_CLDMA, 0);
|
||||
|
||||
cl->sd_status = snd_hdac_stream_readb(cl, SD_STS);
|
||||
dev_dbg(cl->dev, "%s sd_status: 0x%08x\n", __func__, cl->sd_status);
|
||||
|
||||
complete(&cl->completion);
|
||||
}
|
||||
|
||||
int hda_cldma_init(struct hda_cldma *cl, struct hdac_bus *bus, void __iomem *dsp_ba,
|
||||
unsigned int buffer_size)
|
||||
{
|
||||
|
|
|
@ -24,6 +24,7 @@ int hda_cldma_reset(struct hda_cldma *cl);
|
|||
|
||||
void hda_cldma_set_data(struct hda_cldma *cl, void *data, unsigned int size);
|
||||
void hda_cldma_setup(struct hda_cldma *cl);
|
||||
void hda_cldma_interrupt(struct hda_cldma *cl);
|
||||
int hda_cldma_init(struct hda_cldma *cl, struct hdac_bus *bus, void __iomem *dsp_ba,
|
||||
unsigned int buffer_size);
|
||||
void hda_cldma_free(struct hda_cldma *cl);
|
||||
|
|
|
@ -42,10 +42,73 @@ irqreturn_t avs_cnl_irq_thread(struct avs_dev *adev)
|
|||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static void avs_cnl_ipc_interrupt(struct avs_dev *adev)
|
||||
{
|
||||
const struct avs_spec *spec = adev->spec;
|
||||
u32 hipc_ack, hipc_rsp;
|
||||
|
||||
snd_hdac_adsp_updatel(adev, spec->hipc->ctl_offset,
|
||||
AVS_ADSP_HIPCCTL_DONE | AVS_ADSP_HIPCCTL_BUSY, 0);
|
||||
|
||||
hipc_ack = snd_hdac_adsp_readl(adev, spec->hipc->ack_offset);
|
||||
hipc_rsp = snd_hdac_adsp_readl(adev, spec->hipc->rsp_offset);
|
||||
|
||||
/* DSP acked host's request. */
|
||||
if (hipc_ack & spec->hipc->ack_done_mask) {
|
||||
complete(&adev->ipc->done_completion);
|
||||
|
||||
/* Tell DSP it has our attention. */
|
||||
snd_hdac_adsp_updatel(adev, spec->hipc->ack_offset, spec->hipc->ack_done_mask,
|
||||
spec->hipc->ack_done_mask);
|
||||
}
|
||||
|
||||
/* DSP sent new response to process. */
|
||||
if (hipc_rsp & spec->hipc->rsp_busy_mask) {
|
||||
union avs_reply_msg msg;
|
||||
u32 hipctda;
|
||||
|
||||
msg.primary = snd_hdac_adsp_readl(adev, CNL_ADSP_REG_HIPCTDR);
|
||||
msg.ext.val = snd_hdac_adsp_readl(adev, CNL_ADSP_REG_HIPCTDD);
|
||||
|
||||
avs_dsp_process_response(adev, msg.val);
|
||||
|
||||
/* Tell DSP we accepted its message. */
|
||||
snd_hdac_adsp_updatel(adev, CNL_ADSP_REG_HIPCTDR,
|
||||
CNL_ADSP_HIPCTDR_BUSY, CNL_ADSP_HIPCTDR_BUSY);
|
||||
/* Ack this response. */
|
||||
snd_hdac_adsp_updatel(adev, CNL_ADSP_REG_HIPCTDA,
|
||||
CNL_ADSP_HIPCTDA_DONE, CNL_ADSP_HIPCTDA_DONE);
|
||||
/* HW might have been clock gated, give some time for change to propagate. */
|
||||
snd_hdac_adsp_readl_poll(adev, CNL_ADSP_REG_HIPCTDA, hipctda,
|
||||
!(hipctda & CNL_ADSP_HIPCTDA_DONE), 10, 1000);
|
||||
}
|
||||
|
||||
snd_hdac_adsp_updatel(adev, spec->hipc->ctl_offset,
|
||||
AVS_ADSP_HIPCCTL_DONE | AVS_ADSP_HIPCCTL_BUSY,
|
||||
AVS_ADSP_HIPCCTL_DONE | AVS_ADSP_HIPCCTL_BUSY);
|
||||
}
|
||||
|
||||
irqreturn_t avs_cnl_dsp_interrupt(struct avs_dev *adev)
|
||||
{
|
||||
u32 adspis = snd_hdac_adsp_readl(adev, AVS_ADSP_REG_ADSPIS);
|
||||
irqreturn_t ret = IRQ_NONE;
|
||||
|
||||
if (adspis == UINT_MAX)
|
||||
return ret;
|
||||
|
||||
if (adspis & AVS_ADSP_ADSPIS_IPC) {
|
||||
avs_cnl_ipc_interrupt(adev);
|
||||
ret = IRQ_HANDLED;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
const struct avs_dsp_ops avs_cnl_dsp_ops = {
|
||||
.power = avs_dsp_core_power,
|
||||
.reset = avs_dsp_core_reset,
|
||||
.stall = avs_dsp_core_stall,
|
||||
.dsp_interrupt = avs_cnl_dsp_interrupt,
|
||||
.irq_handler = avs_irq_handler,
|
||||
.irq_thread = avs_cnl_irq_thread,
|
||||
.int_control = avs_dsp_interrupt_control,
|
||||
|
|
|
@ -336,6 +336,86 @@ static irqreturn_t avs_dsp_irq_thread(int irq, void *dev_id)
|
|||
return avs_dsp_op(adev, irq_thread);
|
||||
}
|
||||
|
||||
static irqreturn_t avs_hda_interrupt(struct hdac_bus *bus)
|
||||
{
|
||||
irqreturn_t ret = IRQ_NONE;
|
||||
u32 status;
|
||||
|
||||
status = snd_hdac_chip_readl(bus, INTSTS);
|
||||
if (snd_hdac_bus_handle_stream_irq(bus, status, hdac_update_stream))
|
||||
ret = IRQ_HANDLED;
|
||||
|
||||
spin_lock_irq(&bus->reg_lock);
|
||||
/* Clear RIRB interrupt. */
|
||||
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);
|
||||
ret = IRQ_HANDLED;
|
||||
}
|
||||
|
||||
spin_unlock_irq(&bus->reg_lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
__maybe_unused
|
||||
static irqreturn_t avs_hda_irq_handler(int irq, void *dev_id)
|
||||
{
|
||||
struct hdac_bus *bus = dev_id;
|
||||
u32 intsts;
|
||||
|
||||
intsts = snd_hdac_chip_readl(bus, INTSTS);
|
||||
if (intsts == UINT_MAX || !(intsts & AZX_INT_GLOBAL_EN))
|
||||
return IRQ_NONE;
|
||||
|
||||
/* Mask GIE, unmasked in irq_thread(). */
|
||||
snd_hdac_chip_updatel(bus, INTCTL, AZX_INT_GLOBAL_EN, 0);
|
||||
|
||||
return IRQ_WAKE_THREAD;
|
||||
}
|
||||
|
||||
__maybe_unused
|
||||
static irqreturn_t avs_hda_irq_thread(int irq, void *dev_id)
|
||||
{
|
||||
struct hdac_bus *bus = dev_id;
|
||||
u32 status;
|
||||
|
||||
status = snd_hdac_chip_readl(bus, INTSTS);
|
||||
if (status & ~AZX_INT_GLOBAL_EN)
|
||||
avs_hda_interrupt(bus);
|
||||
|
||||
/* Unmask GIE, masked in irq_handler(). */
|
||||
snd_hdac_chip_updatel(bus, INTCTL, AZX_INT_GLOBAL_EN, AZX_INT_GLOBAL_EN);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
__maybe_unused
|
||||
static irqreturn_t avs_dsp_irq_handler2(int irq, void *dev_id)
|
||||
{
|
||||
struct avs_dev *adev = dev_id;
|
||||
|
||||
return avs_hda_irq_handler(irq, &adev->base.core);
|
||||
}
|
||||
|
||||
__maybe_unused
|
||||
static irqreturn_t avs_dsp_irq_thread2(int irq, void *dev_id)
|
||||
{
|
||||
struct avs_dev *adev = dev_id;
|
||||
struct hdac_bus *bus = &adev->base.core;
|
||||
u32 status;
|
||||
|
||||
status = readl(bus->ppcap + AZX_REG_PP_PPSTS);
|
||||
if (status & AZX_PPCTL_PIE)
|
||||
avs_dsp_op(adev, dsp_interrupt);
|
||||
|
||||
/* Unmask GIE, masked in irq_handler(). */
|
||||
snd_hdac_chip_updatel(bus, INTCTL, AZX_INT_GLOBAL_EN, AZX_INT_GLOBAL_EN);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int avs_hdac_acquire_irq(struct avs_dev *adev)
|
||||
{
|
||||
struct hdac_bus *bus = &adev->base.core;
|
||||
|
|
|
@ -188,6 +188,7 @@ const struct avs_dsp_ops avs_icl_dsp_ops = {
|
|||
.power = avs_dsp_core_power,
|
||||
.reset = avs_dsp_core_reset,
|
||||
.stall = avs_dsp_core_stall,
|
||||
.dsp_interrupt = avs_cnl_dsp_interrupt,
|
||||
.irq_handler = avs_irq_handler,
|
||||
.irq_thread = avs_cnl_irq_thread,
|
||||
.int_control = avs_dsp_interrupt_control,
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include <linux/slab.h>
|
||||
#include <sound/hdaudio_ext.h>
|
||||
#include "avs.h"
|
||||
#include "cldma.h"
|
||||
#include "messages.h"
|
||||
|
||||
irqreturn_t avs_skl_irq_thread(struct avs_dev *adev)
|
||||
|
@ -37,6 +38,66 @@ irqreturn_t avs_skl_irq_thread(struct avs_dev *adev)
|
|||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
void avs_skl_ipc_interrupt(struct avs_dev *adev)
|
||||
{
|
||||
const struct avs_spec *spec = adev->spec;
|
||||
u32 hipc_ack, hipc_rsp;
|
||||
|
||||
snd_hdac_adsp_updatel(adev, spec->hipc->ctl_offset,
|
||||
AVS_ADSP_HIPCCTL_DONE | AVS_ADSP_HIPCCTL_BUSY, 0);
|
||||
|
||||
hipc_ack = snd_hdac_adsp_readl(adev, spec->hipc->ack_offset);
|
||||
hipc_rsp = snd_hdac_adsp_readl(adev, spec->hipc->rsp_offset);
|
||||
|
||||
/* DSP acked host's request. */
|
||||
if (hipc_ack & spec->hipc->ack_done_mask) {
|
||||
complete(&adev->ipc->done_completion);
|
||||
|
||||
/* Tell DSP it has our attention. */
|
||||
snd_hdac_adsp_updatel(adev, spec->hipc->ack_offset, spec->hipc->ack_done_mask,
|
||||
spec->hipc->ack_done_mask);
|
||||
}
|
||||
|
||||
/* DSP sent new response to process */
|
||||
if (hipc_rsp & spec->hipc->rsp_busy_mask) {
|
||||
union avs_reply_msg msg;
|
||||
|
||||
msg.primary = snd_hdac_adsp_readl(adev, SKL_ADSP_REG_HIPCT);
|
||||
msg.ext.val = snd_hdac_adsp_readl(adev, SKL_ADSP_REG_HIPCTE);
|
||||
|
||||
avs_dsp_process_response(adev, msg.val);
|
||||
|
||||
/* Tell DSP we accepted its message. */
|
||||
snd_hdac_adsp_updatel(adev, SKL_ADSP_REG_HIPCT, SKL_ADSP_HIPCT_BUSY,
|
||||
SKL_ADSP_HIPCT_BUSY);
|
||||
}
|
||||
|
||||
snd_hdac_adsp_updatel(adev, spec->hipc->ctl_offset,
|
||||
AVS_ADSP_HIPCCTL_DONE | AVS_ADSP_HIPCCTL_BUSY,
|
||||
AVS_ADSP_HIPCCTL_DONE | AVS_ADSP_HIPCCTL_BUSY);
|
||||
}
|
||||
|
||||
static irqreturn_t avs_skl_dsp_interrupt(struct avs_dev *adev)
|
||||
{
|
||||
u32 adspis = snd_hdac_adsp_readl(adev, AVS_ADSP_REG_ADSPIS);
|
||||
irqreturn_t ret = IRQ_NONE;
|
||||
|
||||
if (adspis == UINT_MAX)
|
||||
return ret;
|
||||
|
||||
if (adspis & AVS_ADSP_ADSPIS_CLDMA) {
|
||||
hda_cldma_interrupt(&code_loader);
|
||||
ret = IRQ_HANDLED;
|
||||
}
|
||||
|
||||
if (adspis & AVS_ADSP_ADSPIS_IPC) {
|
||||
avs_skl_ipc_interrupt(adev);
|
||||
ret = IRQ_HANDLED;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __maybe_unused
|
||||
avs_skl_enable_logs(struct avs_dev *adev, enum avs_log_enable enable, u32 aging_period,
|
||||
u32 fifo_full_period, unsigned long resource_mask, u32 *priorities)
|
||||
|
@ -128,6 +189,7 @@ const struct avs_dsp_ops avs_skl_dsp_ops = {
|
|||
.power = avs_dsp_core_power,
|
||||
.reset = avs_dsp_core_reset,
|
||||
.stall = avs_dsp_core_stall,
|
||||
.dsp_interrupt = avs_skl_dsp_interrupt,
|
||||
.irq_handler = avs_irq_handler,
|
||||
.irq_thread = avs_skl_irq_thread,
|
||||
.int_control = avs_dsp_interrupt_control,
|
||||
|
|
|
@ -39,6 +39,7 @@ const struct avs_dsp_ops avs_tgl_dsp_ops = {
|
|||
.power = avs_tgl_dsp_core_power,
|
||||
.reset = avs_tgl_dsp_core_reset,
|
||||
.stall = avs_tgl_dsp_core_stall,
|
||||
.dsp_interrupt = avs_cnl_dsp_interrupt,
|
||||
.irq_handler = avs_irq_handler,
|
||||
.irq_thread = avs_cnl_irq_thread,
|
||||
.int_control = avs_dsp_interrupt_control,
|
||||
|
|
Loading…
Reference in New Issue