Skip to content

Commit 7ce6cee

Browse files
crojewsk-intelbroonie
authored andcommitted
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>
1 parent 9be5147 commit 7ce6cee

9 files changed

Lines changed: 240 additions & 0 deletions

File tree

sound/soc/intel/avs/apl.c

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,28 @@
88

99
#include <linux/devcoredump.h>
1010
#include <linux/slab.h>
11+
#include <sound/hdaudio_ext.h>
1112
#include "avs.h"
1213
#include "messages.h"
1314
#include "path.h"
1415
#include "topology.h"
1516

17+
static irqreturn_t avs_apl_dsp_interrupt(struct avs_dev *adev)
18+
{
19+
u32 adspis = snd_hdac_adsp_readl(adev, AVS_ADSP_REG_ADSPIS);
20+
irqreturn_t ret = IRQ_NONE;
21+
22+
if (adspis == UINT_MAX)
23+
return ret;
24+
25+
if (adspis & AVS_ADSP_ADSPIS_IPC) {
26+
avs_skl_ipc_interrupt(adev);
27+
ret = IRQ_HANDLED;
28+
}
29+
30+
return ret;
31+
}
32+
1633
#ifdef CONFIG_DEBUG_FS
1734
int avs_apl_enable_logs(struct avs_dev *adev, enum avs_log_enable enable, u32 aging_period,
1835
u32 fifo_full_period, unsigned long resource_mask, u32 *priorities)
@@ -237,6 +254,7 @@ const struct avs_dsp_ops avs_apl_dsp_ops = {
237254
.power = avs_dsp_core_power,
238255
.reset = avs_dsp_core_reset,
239256
.stall = avs_dsp_core_stall,
257+
.dsp_interrupt = avs_apl_dsp_interrupt,
240258
.irq_handler = avs_irq_handler,
241259
.irq_thread = avs_skl_irq_thread,
242260
.int_control = avs_dsp_interrupt_control,

sound/soc/intel/avs/avs.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ struct avs_dsp_ops {
4646
int (* const power)(struct avs_dev *, u32, bool);
4747
int (* const reset)(struct avs_dev *, u32, bool);
4848
int (* const stall)(struct avs_dev *, u32, bool);
49+
irqreturn_t (* const dsp_interrupt)(struct avs_dev *);
4950
irqreturn_t (* const irq_handler)(struct avs_dev *);
5051
irqreturn_t (* const irq_thread)(struct avs_dev *);
5152
void (* const int_control)(struct avs_dev *, bool);
@@ -269,6 +270,8 @@ int avs_dsp_enable_d0ix(struct avs_dev *adev);
269270

270271
irqreturn_t avs_skl_irq_thread(struct avs_dev *adev);
271272
irqreturn_t avs_cnl_irq_thread(struct avs_dev *adev);
273+
void avs_skl_ipc_interrupt(struct avs_dev *adev);
274+
irqreturn_t avs_cnl_dsp_interrupt(struct avs_dev *adev);
272275
int avs_apl_enable_logs(struct avs_dev *adev, enum avs_log_enable enable, u32 aging_period,
273276
u32 fifo_full_period, unsigned long resource_mask, u32 *priorities);
274277
int avs_icl_enable_logs(struct avs_dev *adev, enum avs_log_enable enable, u32 aging_period,

sound/soc/intel/avs/cldma.c

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -270,6 +270,17 @@ static irqreturn_t cldma_irq_handler(int irq, void *dev_id)
270270
return IRQ_HANDLED;
271271
}
272272

273+
void hda_cldma_interrupt(struct hda_cldma *cl)
274+
{
275+
/* disable CLDMA interrupt */
276+
snd_hdac_adsp_updatel(cl, AVS_ADSP_REG_ADSPIC, AVS_ADSP_ADSPIC_CLDMA, 0);
277+
278+
cl->sd_status = snd_hdac_stream_readb(cl, SD_STS);
279+
dev_dbg(cl->dev, "%s sd_status: 0x%08x\n", __func__, cl->sd_status);
280+
281+
complete(&cl->completion);
282+
}
283+
273284
int hda_cldma_init(struct hda_cldma *cl, struct hdac_bus *bus, void __iomem *dsp_ba,
274285
unsigned int buffer_size)
275286
{

sound/soc/intel/avs/cldma.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ int hda_cldma_reset(struct hda_cldma *cl);
2424

2525
void hda_cldma_set_data(struct hda_cldma *cl, void *data, unsigned int size);
2626
void hda_cldma_setup(struct hda_cldma *cl);
27+
void hda_cldma_interrupt(struct hda_cldma *cl);
2728
int hda_cldma_init(struct hda_cldma *cl, struct hdac_bus *bus, void __iomem *dsp_ba,
2829
unsigned int buffer_size);
2930
void hda_cldma_free(struct hda_cldma *cl);

sound/soc/intel/avs/cnl.c

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,10 +42,73 @@ irqreturn_t avs_cnl_irq_thread(struct avs_dev *adev)
4242
return IRQ_HANDLED;
4343
}
4444

45+
static void avs_cnl_ipc_interrupt(struct avs_dev *adev)
46+
{
47+
const struct avs_spec *spec = adev->spec;
48+
u32 hipc_ack, hipc_rsp;
49+
50+
snd_hdac_adsp_updatel(adev, spec->hipc->ctl_offset,
51+
AVS_ADSP_HIPCCTL_DONE | AVS_ADSP_HIPCCTL_BUSY, 0);
52+
53+
hipc_ack = snd_hdac_adsp_readl(adev, spec->hipc->ack_offset);
54+
hipc_rsp = snd_hdac_adsp_readl(adev, spec->hipc->rsp_offset);
55+
56+
/* DSP acked host's request. */
57+
if (hipc_ack & spec->hipc->ack_done_mask) {
58+
complete(&adev->ipc->done_completion);
59+
60+
/* Tell DSP it has our attention. */
61+
snd_hdac_adsp_updatel(adev, spec->hipc->ack_offset, spec->hipc->ack_done_mask,
62+
spec->hipc->ack_done_mask);
63+
}
64+
65+
/* DSP sent new response to process. */
66+
if (hipc_rsp & spec->hipc->rsp_busy_mask) {
67+
union avs_reply_msg msg;
68+
u32 hipctda;
69+
70+
msg.primary = snd_hdac_adsp_readl(adev, CNL_ADSP_REG_HIPCTDR);
71+
msg.ext.val = snd_hdac_adsp_readl(adev, CNL_ADSP_REG_HIPCTDD);
72+
73+
avs_dsp_process_response(adev, msg.val);
74+
75+
/* Tell DSP we accepted its message. */
76+
snd_hdac_adsp_updatel(adev, CNL_ADSP_REG_HIPCTDR,
77+
CNL_ADSP_HIPCTDR_BUSY, CNL_ADSP_HIPCTDR_BUSY);
78+
/* Ack this response. */
79+
snd_hdac_adsp_updatel(adev, CNL_ADSP_REG_HIPCTDA,
80+
CNL_ADSP_HIPCTDA_DONE, CNL_ADSP_HIPCTDA_DONE);
81+
/* HW might have been clock gated, give some time for change to propagate. */
82+
snd_hdac_adsp_readl_poll(adev, CNL_ADSP_REG_HIPCTDA, hipctda,
83+
!(hipctda & CNL_ADSP_HIPCTDA_DONE), 10, 1000);
84+
}
85+
86+
snd_hdac_adsp_updatel(adev, spec->hipc->ctl_offset,
87+
AVS_ADSP_HIPCCTL_DONE | AVS_ADSP_HIPCCTL_BUSY,
88+
AVS_ADSP_HIPCCTL_DONE | AVS_ADSP_HIPCCTL_BUSY);
89+
}
90+
91+
irqreturn_t avs_cnl_dsp_interrupt(struct avs_dev *adev)
92+
{
93+
u32 adspis = snd_hdac_adsp_readl(adev, AVS_ADSP_REG_ADSPIS);
94+
irqreturn_t ret = IRQ_NONE;
95+
96+
if (adspis == UINT_MAX)
97+
return ret;
98+
99+
if (adspis & AVS_ADSP_ADSPIS_IPC) {
100+
avs_cnl_ipc_interrupt(adev);
101+
ret = IRQ_HANDLED;
102+
}
103+
104+
return ret;
105+
}
106+
45107
const struct avs_dsp_ops avs_cnl_dsp_ops = {
46108
.power = avs_dsp_core_power,
47109
.reset = avs_dsp_core_reset,
48110
.stall = avs_dsp_core_stall,
111+
.dsp_interrupt = avs_cnl_dsp_interrupt,
49112
.irq_handler = avs_irq_handler,
50113
.irq_thread = avs_cnl_irq_thread,
51114
.int_control = avs_dsp_interrupt_control,

sound/soc/intel/avs/core.c

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -336,6 +336,86 @@ static irqreturn_t avs_dsp_irq_thread(int irq, void *dev_id)
336336
return avs_dsp_op(adev, irq_thread);
337337
}
338338

339+
static irqreturn_t avs_hda_interrupt(struct hdac_bus *bus)
340+
{
341+
irqreturn_t ret = IRQ_NONE;
342+
u32 status;
343+
344+
status = snd_hdac_chip_readl(bus, INTSTS);
345+
if (snd_hdac_bus_handle_stream_irq(bus, status, hdac_update_stream))
346+
ret = IRQ_HANDLED;
347+
348+
spin_lock_irq(&bus->reg_lock);
349+
/* Clear RIRB interrupt. */
350+
status = snd_hdac_chip_readb(bus, RIRBSTS);
351+
if (status & RIRB_INT_MASK) {
352+
if (status & RIRB_INT_RESPONSE)
353+
snd_hdac_bus_update_rirb(bus);
354+
snd_hdac_chip_writeb(bus, RIRBSTS, RIRB_INT_MASK);
355+
ret = IRQ_HANDLED;
356+
}
357+
358+
spin_unlock_irq(&bus->reg_lock);
359+
return ret;
360+
}
361+
362+
__maybe_unused
363+
static irqreturn_t avs_hda_irq_handler(int irq, void *dev_id)
364+
{
365+
struct hdac_bus *bus = dev_id;
366+
u32 intsts;
367+
368+
intsts = snd_hdac_chip_readl(bus, INTSTS);
369+
if (intsts == UINT_MAX || !(intsts & AZX_INT_GLOBAL_EN))
370+
return IRQ_NONE;
371+
372+
/* Mask GIE, unmasked in irq_thread(). */
373+
snd_hdac_chip_updatel(bus, INTCTL, AZX_INT_GLOBAL_EN, 0);
374+
375+
return IRQ_WAKE_THREAD;
376+
}
377+
378+
__maybe_unused
379+
static irqreturn_t avs_hda_irq_thread(int irq, void *dev_id)
380+
{
381+
struct hdac_bus *bus = dev_id;
382+
u32 status;
383+
384+
status = snd_hdac_chip_readl(bus, INTSTS);
385+
if (status & ~AZX_INT_GLOBAL_EN)
386+
avs_hda_interrupt(bus);
387+
388+
/* Unmask GIE, masked in irq_handler(). */
389+
snd_hdac_chip_updatel(bus, INTCTL, AZX_INT_GLOBAL_EN, AZX_INT_GLOBAL_EN);
390+
391+
return IRQ_HANDLED;
392+
}
393+
394+
__maybe_unused
395+
static irqreturn_t avs_dsp_irq_handler2(int irq, void *dev_id)
396+
{
397+
struct avs_dev *adev = dev_id;
398+
399+
return avs_hda_irq_handler(irq, &adev->base.core);
400+
}
401+
402+
__maybe_unused
403+
static irqreturn_t avs_dsp_irq_thread2(int irq, void *dev_id)
404+
{
405+
struct avs_dev *adev = dev_id;
406+
struct hdac_bus *bus = &adev->base.core;
407+
u32 status;
408+
409+
status = readl(bus->ppcap + AZX_REG_PP_PPSTS);
410+
if (status & AZX_PPCTL_PIE)
411+
avs_dsp_op(adev, dsp_interrupt);
412+
413+
/* Unmask GIE, masked in irq_handler(). */
414+
snd_hdac_chip_updatel(bus, INTCTL, AZX_INT_GLOBAL_EN, AZX_INT_GLOBAL_EN);
415+
416+
return IRQ_HANDLED;
417+
}
418+
339419
static int avs_hdac_acquire_irq(struct avs_dev *adev)
340420
{
341421
struct hdac_bus *bus = &adev->base.core;

sound/soc/intel/avs/icl.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,7 @@ const struct avs_dsp_ops avs_icl_dsp_ops = {
188188
.power = avs_dsp_core_power,
189189
.reset = avs_dsp_core_reset,
190190
.stall = avs_dsp_core_stall,
191+
.dsp_interrupt = avs_cnl_dsp_interrupt,
191192
.irq_handler = avs_irq_handler,
192193
.irq_thread = avs_cnl_irq_thread,
193194
.int_control = avs_dsp_interrupt_control,

sound/soc/intel/avs/skl.c

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include <linux/slab.h>
1111
#include <sound/hdaudio_ext.h>
1212
#include "avs.h"
13+
#include "cldma.h"
1314
#include "messages.h"
1415

1516
irqreturn_t avs_skl_irq_thread(struct avs_dev *adev)
@@ -37,6 +38,66 @@ irqreturn_t avs_skl_irq_thread(struct avs_dev *adev)
3738
return IRQ_HANDLED;
3839
}
3940

41+
void avs_skl_ipc_interrupt(struct avs_dev *adev)
42+
{
43+
const struct avs_spec *spec = adev->spec;
44+
u32 hipc_ack, hipc_rsp;
45+
46+
snd_hdac_adsp_updatel(adev, spec->hipc->ctl_offset,
47+
AVS_ADSP_HIPCCTL_DONE | AVS_ADSP_HIPCCTL_BUSY, 0);
48+
49+
hipc_ack = snd_hdac_adsp_readl(adev, spec->hipc->ack_offset);
50+
hipc_rsp = snd_hdac_adsp_readl(adev, spec->hipc->rsp_offset);
51+
52+
/* DSP acked host's request. */
53+
if (hipc_ack & spec->hipc->ack_done_mask) {
54+
complete(&adev->ipc->done_completion);
55+
56+
/* Tell DSP it has our attention. */
57+
snd_hdac_adsp_updatel(adev, spec->hipc->ack_offset, spec->hipc->ack_done_mask,
58+
spec->hipc->ack_done_mask);
59+
}
60+
61+
/* DSP sent new response to process */
62+
if (hipc_rsp & spec->hipc->rsp_busy_mask) {
63+
union avs_reply_msg msg;
64+
65+
msg.primary = snd_hdac_adsp_readl(adev, SKL_ADSP_REG_HIPCT);
66+
msg.ext.val = snd_hdac_adsp_readl(adev, SKL_ADSP_REG_HIPCTE);
67+
68+
avs_dsp_process_response(adev, msg.val);
69+
70+
/* Tell DSP we accepted its message. */
71+
snd_hdac_adsp_updatel(adev, SKL_ADSP_REG_HIPCT, SKL_ADSP_HIPCT_BUSY,
72+
SKL_ADSP_HIPCT_BUSY);
73+
}
74+
75+
snd_hdac_adsp_updatel(adev, spec->hipc->ctl_offset,
76+
AVS_ADSP_HIPCCTL_DONE | AVS_ADSP_HIPCCTL_BUSY,
77+
AVS_ADSP_HIPCCTL_DONE | AVS_ADSP_HIPCCTL_BUSY);
78+
}
79+
80+
static irqreturn_t avs_skl_dsp_interrupt(struct avs_dev *adev)
81+
{
82+
u32 adspis = snd_hdac_adsp_readl(adev, AVS_ADSP_REG_ADSPIS);
83+
irqreturn_t ret = IRQ_NONE;
84+
85+
if (adspis == UINT_MAX)
86+
return ret;
87+
88+
if (adspis & AVS_ADSP_ADSPIS_CLDMA) {
89+
hda_cldma_interrupt(&code_loader);
90+
ret = IRQ_HANDLED;
91+
}
92+
93+
if (adspis & AVS_ADSP_ADSPIS_IPC) {
94+
avs_skl_ipc_interrupt(adev);
95+
ret = IRQ_HANDLED;
96+
}
97+
98+
return ret;
99+
}
100+
40101
static int __maybe_unused
41102
avs_skl_enable_logs(struct avs_dev *adev, enum avs_log_enable enable, u32 aging_period,
42103
u32 fifo_full_period, unsigned long resource_mask, u32 *priorities)
@@ -128,6 +189,7 @@ const struct avs_dsp_ops avs_skl_dsp_ops = {
128189
.power = avs_dsp_core_power,
129190
.reset = avs_dsp_core_reset,
130191
.stall = avs_dsp_core_stall,
192+
.dsp_interrupt = avs_skl_dsp_interrupt,
131193
.irq_handler = avs_irq_handler,
132194
.irq_thread = avs_skl_irq_thread,
133195
.int_control = avs_dsp_interrupt_control,

sound/soc/intel/avs/tgl.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ const struct avs_dsp_ops avs_tgl_dsp_ops = {
3939
.power = avs_tgl_dsp_core_power,
4040
.reset = avs_tgl_dsp_core_reset,
4141
.stall = avs_tgl_dsp_core_stall,
42+
.dsp_interrupt = avs_cnl_dsp_interrupt,
4243
.irq_handler = avs_irq_handler,
4344
.irq_thread = avs_cnl_irq_thread,
4445
.int_control = avs_dsp_interrupt_control,

0 commit comments

Comments
 (0)