diff --git a/src/arch/xtensa/include/arch/task.h b/src/arch/xtensa/include/arch/task.h index 5b0548d94..a0b66e940 100644 --- a/src/arch/xtensa/include/arch/task.h +++ b/src/arch/xtensa/include/arch/task.h @@ -244,17 +244,17 @@ static inline void arch_free_tasks(void) static inline int arch_assign_tasks(void) { /* irq low */ - interrupt_register(PLATFORM_IRQ_TASK_LOW, _irq_task, + interrupt_register(PLATFORM_IRQ_TASK_LOW, IRQ_AUTO_UNMASK, _irq_task, task_irq_low_get()); interrupt_enable(PLATFORM_IRQ_TASK_LOW); /* irq medium */ - interrupt_register(PLATFORM_IRQ_TASK_MED, _irq_task, + interrupt_register(PLATFORM_IRQ_TASK_MED, IRQ_AUTO_UNMASK, _irq_task, task_irq_med_get()); interrupt_enable(PLATFORM_IRQ_TASK_MED); /* irq high */ - interrupt_register(PLATFORM_IRQ_TASK_HIGH, _irq_task, + interrupt_register(PLATFORM_IRQ_TASK_HIGH, IRQ_AUTO_UNMASK, _irq_task, task_irq_high_get()); interrupt_enable(PLATFORM_IRQ_TASK_HIGH); diff --git a/src/arch/xtensa/smp/include/arch/idc.h b/src/arch/xtensa/smp/include/arch/idc.h index cd964db8f..9d6bbc3cc 100644 --- a/src/arch/xtensa/smp/include/arch/idc.h +++ b/src/arch/xtensa/smp/include/arch/idc.h @@ -307,7 +307,7 @@ static inline void arch_idc_init(void) (*idc)->done_bit_mask = idc_get_done_bit_mask(core); /* configure interrupt */ - interrupt_register(PLATFORM_IDC_INTERRUPT(core), + interrupt_register(PLATFORM_IDC_INTERRUPT(core), IRQ_AUTO_UNMASK, idc_irq_handler, *idc); interrupt_enable(PLATFORM_IDC_INTERRUPT(core)); diff --git a/src/drivers/intel/baytrail/ssp.c b/src/drivers/intel/baytrail/ssp.c index e46188345..6cd50eaed 100644 --- a/src/drivers/intel/baytrail/ssp.c +++ b/src/drivers/intel/baytrail/ssp.c @@ -617,12 +617,14 @@ static int ssp_probe(struct dai *dai) */ if (ssp_irq(dai) >= IRQ_CHT_SSP_OFFSET) interrupt_register(ssp_irq(dai) - IRQ_CHT_SSP_OFFSET, - ssp_irq_handler, dai); + IRQ_AUTO_UNMASK, ssp_irq_handler, dai); else - interrupt_register(ssp_irq(dai), ssp_irq_handler, dai); + interrupt_register(ssp_irq(dai), IRQ_AUTO_UNMASK, + ssp_irq_handler, dai); #else /* register our IRQ handler */ - interrupt_register(ssp_irq(dai), ssp_irq_handler, dai); + interrupt_register(ssp_irq(dai), IRQ_AUTO_UNMASK, ssp_irq_handler, + dai); #endif platform_interrupt_unmask(ssp_irq(dai), 1); interrupt_enable(ssp_irq(dai)); diff --git a/src/drivers/intel/cavs/dmic.c b/src/drivers/intel/cavs/dmic.c index b8ddf8fef..2afa5423b 100644 --- a/src/drivers/intel/cavs/dmic.c +++ b/src/drivers/intel/cavs/dmic.c @@ -1460,7 +1460,8 @@ static int dmic_probe(struct dai *dai) dmic->state = COMP_STATE_READY; /* register our IRQ handler */ - interrupt_register(dmic_irq(dai), dmic_irq_handler, dai); + interrupt_register(dmic_irq(dai), IRQ_AUTO_UNMASK, dmic_irq_handler, + dai); platform_interrupt_unmask(dmic_irq(dai), 1); interrupt_enable(dmic_irq(dai)); diff --git a/src/drivers/intel/cavs/interrupt.c b/src/drivers/intel/cavs/interrupt.c index 9b2393290..c85c8e4ff 100644 --- a/src/drivers/intel/cavs/interrupt.c +++ b/src/drivers/intel/cavs/interrupt.c @@ -43,11 +43,8 @@ #include #include -static inline void irq_lvl2_handler(void *data, - int level, - uint32_t ilxsd, - uint32_t ilxmsd, - uint32_t ilxmcd) +static inline void irq_lvl2_handler(void *data, int level, uint32_t ilxsd, + uint32_t ilxmsd, uint32_t ilxmcd) { struct irq_desc *parent = (struct irq_desc *)data; struct irq_desc *child = NULL; @@ -75,7 +72,7 @@ static inline void irq_lvl2_handler(void *data, if (child && child->handler) { child->handler(child->handler_arg); - unmask = 1; + unmask = child->unmask; } else { /* nobody cared ? */ trace_irq_error("nbc"); diff --git a/src/drivers/intel/cavs/ssp.c b/src/drivers/intel/cavs/ssp.c index 7b0ac5eb5..479c76c83 100644 --- a/src/drivers/intel/cavs/ssp.c +++ b/src/drivers/intel/cavs/ssp.c @@ -881,7 +881,8 @@ static int ssp_probe(struct dai *dai) ssp->state[DAI_DIR_CAPTURE] = COMP_STATE_READY; /* register our IRQ handler */ - interrupt_register(ssp_irq(dai), ssp_irq_handler, dai); + interrupt_register(ssp_irq(dai), IRQ_AUTO_UNMASK, ssp_irq_handler, + dai); platform_interrupt_unmask(ssp_irq(dai), 1); interrupt_enable(ssp_irq(dai)); diff --git a/src/drivers/intel/cavs/timer.c b/src/drivers/intel/cavs/timer.c index 89ab4f669..7bb45ef8b 100644 --- a/src/drivers/intel/cavs/timer.c +++ b/src/drivers/intel/cavs/timer.c @@ -118,7 +118,7 @@ void platform_dai_wallclock(struct comp_dev *dai, uint64_t *wallclock) static int platform_timer_register(struct timer *timer, void (*handler)(void *arg), void *arg) { - return interrupt_register(timer->irq, handler, arg); + return interrupt_register(timer->irq, IRQ_AUTO_UNMASK, handler, arg); } int timer_register(struct timer *timer, void(*handler)(void *arg), void *arg) diff --git a/src/drivers/intel/dw-dma.c b/src/drivers/intel/dw-dma.c index d42e7d67f..8f3c6ca9b 100644 --- a/src/drivers/intel/dw-dma.c +++ b/src/drivers/intel/dw-dma.c @@ -1139,7 +1139,8 @@ static inline void dw_dma_interrupt_register(struct dma *dma, int channel) uint32_t irq = dma_irq(dma, cpu_get_id()) + (channel << SOF_IRQ_BIT_SHIFT); - interrupt_register(irq, dw_dma_irq_handler, &p->chan[channel].id); + interrupt_register(irq, IRQ_AUTO_UNMASK, dw_dma_irq_handler, + &p->chan[channel].id); interrupt_enable(irq); } @@ -1307,7 +1308,7 @@ static inline void dw_dma_interrupt_register(struct dma *dma, int channel) { uint32_t irq = dma_irq(dma, cpu_get_id()); - interrupt_register(irq, dw_dma_irq_handler, dma); + interrupt_register(irq, IRQ_AUTO_UNMASK, dw_dma_irq_handler, dma); interrupt_enable(irq); } diff --git a/src/drivers/intel/haswell/ssp.c b/src/drivers/intel/haswell/ssp.c index 479ae27f0..3e885c7b0 100644 --- a/src/drivers/intel/haswell/ssp.c +++ b/src/drivers/intel/haswell/ssp.c @@ -510,7 +510,8 @@ static int ssp_probe(struct dai *dai) /* register our IRQ handler */ - interrupt_register(ssp_irq(dai), ssp_irq_handler, dai); + interrupt_register(ssp_irq(dai), IRQ_AUTO_UNMASK, ssp_irq_handler, + dai); platform_interrupt_unmask(ssp_irq(dai), 1); interrupt_enable(ssp_irq(dai)); diff --git a/src/include/sof/interrupt.h b/src/include/sof/interrupt.h index 082299534..c2f692729 100644 --- a/src/include/sof/interrupt.h +++ b/src/include/sof/interrupt.h @@ -43,6 +43,9 @@ #define trace_irq(__e) trace_event(TRACE_CLASS_IRQ, __e) #define trace_irq_error(__e) trace_error(TRACE_CLASS_IRQ, __e) +#define IRQ_MANUAL_UNMASK 0 +#define IRQ_AUTO_UNMASK 1 + struct irq_desc { /* irq must be first for constructor */ int irq; /* logical IRQ number */ @@ -51,6 +54,9 @@ struct irq_desc { void (*handler)(void *arg); void *handler_arg; + /* whether irq should be automatically unmasked */ + int unmask; + /* to identify interrupt with the same IRQ */ int id; spinlock_t lock; @@ -63,8 +69,8 @@ struct irq_desc { struct list_item child[PLATFORM_IRQ_CHILDREN]; }; -int interrupt_register(uint32_t irq, - void(*handler)(void *arg), void *arg); +int interrupt_register(uint32_t irq, int unmask, void(*handler)(void *arg), + void *arg); void interrupt_unregister(uint32_t irq); uint32_t interrupt_enable(uint32_t irq); uint32_t interrupt_disable(uint32_t irq); diff --git a/src/ipc/apl-ipc.c b/src/ipc/apl-ipc.c index 58814a0b8..d39295f65 100644 --- a/src/ipc/apl-ipc.c +++ b/src/ipc/apl-ipc.c @@ -215,7 +215,8 @@ int platform_ipc_init(struct ipc *ipc) iipc->pm_prepare_D3 = 0; /* configure interrupt */ - interrupt_register(PLATFORM_IPC_INTERRUPT, irq_handler, NULL); + interrupt_register(PLATFORM_IPC_INTERRUPT, IRQ_AUTO_UNMASK, + irq_handler, NULL); interrupt_enable(PLATFORM_IPC_INTERRUPT); /* enable IPC interrupts from host */ diff --git a/src/ipc/byt-ipc.c b/src/ipc/byt-ipc.c index b97c04086..46e5006d1 100644 --- a/src/ipc/byt-ipc.c +++ b/src/ipc/byt-ipc.c @@ -237,7 +237,8 @@ int platform_ipc_init(struct ipc *ipc) iipc->pm_prepare_D3 = 0; /* configure interrupt */ - interrupt_register(PLATFORM_IPC_INTERRUPT, irq_handler, NULL); + interrupt_register(PLATFORM_IPC_INTERRUPT, IRQ_AUTO_UNMASK, + irq_handler, NULL); interrupt_enable(PLATFORM_IPC_INTERRUPT); /* Unmask Busy and Done interrupts */ diff --git a/src/ipc/cnl-ipc.c b/src/ipc/cnl-ipc.c index 2db555af0..eed9b3a94 100644 --- a/src/ipc/cnl-ipc.c +++ b/src/ipc/cnl-ipc.c @@ -216,7 +216,8 @@ int platform_ipc_init(struct ipc *ipc) iipc->pm_prepare_D3 = 0; /* configure interrupt */ - interrupt_register(PLATFORM_IPC_INTERRUPT, irq_handler, NULL); + interrupt_register(PLATFORM_IPC_INTERRUPT, IRQ_AUTO_UNMASK, + irq_handler, NULL); interrupt_enable(PLATFORM_IPC_INTERRUPT); /* enable IPC interrupts from host */ diff --git a/src/ipc/hsw-ipc.c b/src/ipc/hsw-ipc.c index e25597fff..c245632e9 100644 --- a/src/ipc/hsw-ipc.c +++ b/src/ipc/hsw-ipc.c @@ -232,7 +232,8 @@ int platform_ipc_init(struct ipc *ipc) iipc->pm_prepare_D3 = 0; /* configure interrupt */ - interrupt_register(PLATFORM_IPC_INTERRUPT, irq_handler, NULL); + interrupt_register(PLATFORM_IPC_INTERRUPT, IRQ_AUTO_UNMASK, + irq_handler, NULL); interrupt_enable(PLATFORM_IPC_INTERRUPT); /* Unmask Busy and Done interrupts */ diff --git a/src/ipc/pmc-ipc.c b/src/ipc/pmc-ipc.c index 8c2602b00..47c649981 100644 --- a/src/ipc/pmc-ipc.c +++ b/src/ipc/pmc-ipc.c @@ -173,7 +173,8 @@ int platform_ipc_pmc_init(void) sizeof(struct intel_ipc_pmc_data)); /* configure interrupt */ - interrupt_register(IRQ_NUM_EXT_PMC, irq_handler, NULL); + interrupt_register(IRQ_NUM_EXT_PMC, IRQ_AUTO_UNMASK, irq_handler, + NULL); interrupt_enable(IRQ_NUM_EXT_PMC); /* Unmask Busy and Done interrupts */ diff --git a/src/lib/interrupt.c b/src/lib/interrupt.c index 49b00ef94..3e83502e5 100644 --- a/src/lib/interrupt.c +++ b/src/lib/interrupt.c @@ -38,13 +38,13 @@ #include #include -static int irq_register_child(struct irq_desc *parent, int irq, +static int irq_register_child(struct irq_desc *parent, int irq, int unmask, void (*handler)(void *arg), void *arg); static void irq_unregister_child(struct irq_desc *parent, int irq); static uint32_t irq_enable_child(struct irq_desc *parent, int irq); static uint32_t irq_disable_child(struct irq_desc *parent, int irq); -static int irq_register_child(struct irq_desc *parent, int irq, +static int irq_register_child(struct irq_desc *parent, int irq, int unmask, void (*handler)(void *arg), void *arg) { int ret = 0; @@ -67,6 +67,7 @@ static int irq_register_child(struct irq_desc *parent, int irq, child->handler = handler; child->handler_arg = arg; child->id = SOF_IRQ_ID(irq); + child->unmask = unmask; list_item_append(&child->irq_list, &parent->child[SOF_IRQ_BIT(irq)]); @@ -171,8 +172,8 @@ static uint32_t irq_disable_child(struct irq_desc *parent, int irq) return 0; } -int interrupt_register(uint32_t irq, - void (*handler)(void *arg), void *arg) +int interrupt_register(uint32_t irq, int unmask, void (*handler)(void *arg), + void *arg) { struct irq_desc *parent; @@ -181,7 +182,7 @@ int interrupt_register(uint32_t irq, if (parent == NULL) return arch_interrupt_register(irq, handler, arg); else - return irq_register_child(parent, irq, handler, arg); + return irq_register_child(parent, irq, unmask, handler, arg); } void interrupt_unregister(uint32_t irq) diff --git a/src/lib/schedule.c b/src/lib/schedule.c index df0658bd2..e293a3617 100644 --- a/src/lib/schedule.c +++ b/src/lib/schedule.c @@ -409,7 +409,8 @@ int scheduler_init(struct sof *sof) work_init(&((*sch)->work), sch_work, *sch, WORK_ASYNC); /* configure scheduler interrupt */ - interrupt_register(PLATFORM_SCHEDULE_IRQ, scheduler_run, NULL); + interrupt_register(PLATFORM_SCHEDULE_IRQ, IRQ_AUTO_UNMASK, + scheduler_run, NULL); interrupt_enable(PLATFORM_SCHEDULE_IRQ); /* allocate arch tasks */