From 79d4ea1f917b91798b5356d35feaa07cca6b2632 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Mon, 11 Feb 2019 16:01:56 +0100 Subject: [PATCH 01/25] interrupt: introduce a separate struct for cascading interrupts Currently each interrupt descriptor has an array of list heads, that can be used to cascade further interrupts to it. But most interrupts are simple decide interrupts, that cannot have children. This patch introduces a separate type for interrupt controllers, that can indeed have children. Signed-off-by: Guennadi Liakhovetski --- src/drivers/intel/cavs/interrupt.c | 46 +++++++++++++++-------------- src/drivers/interrupt.c | 43 ++++++++++++++++----------- src/include/sof/drivers/interrupt.h | 9 +++++- 3 files changed, 58 insertions(+), 40 deletions(-) diff --git a/src/drivers/intel/cavs/interrupt.c b/src/drivers/intel/cavs/interrupt.c index e5186258a2d3..b854a2dfdad6 100644 --- a/src/drivers/intel/cavs/interrupt.c +++ b/src/drivers/intel/cavs/interrupt.c @@ -32,6 +32,8 @@ 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_cascade_desc *cascade = container_of(parent, + struct irq_cascade_desc, desc); struct irq_desc *child = NULL; struct list_item *clist; uint32_t status; @@ -65,7 +67,7 @@ static inline void irq_lvl2_handler(void *data, int level, uint32_t ilxsd, goto next; /* get child if any and run handler */ - list_for_item(clist, &parent->child[i]) { + list_for_item(clist, &cascade->child[i]) { child = container_of(clist, struct irq_desc, irq_list); if (child && child->handler) { @@ -114,28 +116,28 @@ static void irq_lvl2_level5_handler(void *data) } /* DSP internal interrupts */ -static struct irq_desc dsp_irq[PLATFORM_CORE_COUNT][4] = { - {{IRQ_NUM_EXT_LEVEL2, irq_lvl2_level2_handler, }, - {IRQ_NUM_EXT_LEVEL3, irq_lvl2_level3_handler, }, - {IRQ_NUM_EXT_LEVEL4, irq_lvl2_level4_handler, }, - {IRQ_NUM_EXT_LEVEL5, irq_lvl2_level5_handler, } }, +static struct irq_cascade_desc dsp_irq[PLATFORM_CORE_COUNT][4] = { + {{.desc = {IRQ_NUM_EXT_LEVEL2, irq_lvl2_level2_handler, },}, + {.desc = {IRQ_NUM_EXT_LEVEL3, irq_lvl2_level3_handler, },}, + {.desc = {IRQ_NUM_EXT_LEVEL4, irq_lvl2_level4_handler, },}, + {.desc = {IRQ_NUM_EXT_LEVEL5, irq_lvl2_level5_handler, },} }, #if PLATFORM_CORE_COUNT > 1 - {{IRQ_NUM_EXT_LEVEL2, irq_lvl2_level2_handler, }, - {IRQ_NUM_EXT_LEVEL3, irq_lvl2_level3_handler, }, - {IRQ_NUM_EXT_LEVEL4, irq_lvl2_level4_handler, }, - {IRQ_NUM_EXT_LEVEL5, irq_lvl2_level5_handler, } }, + {{.desc = {IRQ_NUM_EXT_LEVEL2, irq_lvl2_level2_handler, },}, + {.desc = {IRQ_NUM_EXT_LEVEL3, irq_lvl2_level3_handler, },}, + {.desc = {IRQ_NUM_EXT_LEVEL4, irq_lvl2_level4_handler, },}, + {.desc = {IRQ_NUM_EXT_LEVEL5, irq_lvl2_level5_handler, },} }, #endif #if PLATFORM_CORE_COUNT > 2 - {{IRQ_NUM_EXT_LEVEL2, irq_lvl2_level2_handler, }, - {IRQ_NUM_EXT_LEVEL3, irq_lvl2_level3_handler, }, - {IRQ_NUM_EXT_LEVEL4, irq_lvl2_level4_handler, }, - {IRQ_NUM_EXT_LEVEL5, irq_lvl2_level5_handler, } }, + {{.desc = {IRQ_NUM_EXT_LEVEL2, irq_lvl2_level2_handler, },}, + {.desc = {IRQ_NUM_EXT_LEVEL3, irq_lvl2_level3_handler, },}, + {.desc = {IRQ_NUM_EXT_LEVEL4, irq_lvl2_level4_handler, },}, + {.desc = {IRQ_NUM_EXT_LEVEL5, irq_lvl2_level5_handler, },} }, #endif #if PLATFORM_CORE_COUNT > 3 - {{IRQ_NUM_EXT_LEVEL2, irq_lvl2_level2_handler, }, - {IRQ_NUM_EXT_LEVEL3, irq_lvl2_level3_handler, }, - {IRQ_NUM_EXT_LEVEL4, irq_lvl2_level4_handler, }, - {IRQ_NUM_EXT_LEVEL5, irq_lvl2_level5_handler, } }, + {{.desc = {IRQ_NUM_EXT_LEVEL2, irq_lvl2_level2_handler, },}, + {.desc = {IRQ_NUM_EXT_LEVEL3, irq_lvl2_level3_handler, },}, + {.desc = {IRQ_NUM_EXT_LEVEL4, irq_lvl2_level4_handler, },}, + {.desc = {IRQ_NUM_EXT_LEVEL5, irq_lvl2_level5_handler, },} }, #endif }; @@ -145,13 +147,13 @@ struct irq_desc *platform_irq_get_parent(uint32_t irq) switch (SOF_IRQ_NUMBER(irq)) { case IRQ_NUM_EXT_LEVEL2: - return &dsp_irq[core][0]; + return &dsp_irq[core][0].desc; case IRQ_NUM_EXT_LEVEL3: - return &dsp_irq[core][1]; + return &dsp_irq[core][1].desc; case IRQ_NUM_EXT_LEVEL4: - return &dsp_irq[core][2]; + return &dsp_irq[core][2].desc; case IRQ_NUM_EXT_LEVEL5: - return &dsp_irq[core][3]; + return &dsp_irq[core][3].desc; default: return NULL; } diff --git a/src/drivers/interrupt.c b/src/drivers/interrupt.c index 4c88dd8a6b9a..274c2182f68d 100644 --- a/src/drivers/interrupt.c +++ b/src/drivers/interrupt.c @@ -21,11 +21,14 @@ static int irq_register_child(struct irq_desc *parent, int irq, int unmask, { int ret = 0; struct irq_desc *child; + struct irq_cascade_desc *cascade; if (parent == NULL) return -EINVAL; - spin_lock(&parent->lock); + cascade = container_of(parent, struct irq_cascade_desc, desc); + + spin_lock(&cascade->lock); /* init child from run-time, may be registered and unregistered * many times at run-time @@ -43,19 +46,19 @@ static int irq_register_child(struct irq_desc *parent, int irq, int unmask, child->id = SOF_IRQ_ID(irq); child->unmask = unmask; - list_item_append(&child->irq_list, &parent->child[SOF_IRQ_BIT(irq)]); + list_item_append(&child->irq_list, &cascade->child[SOF_IRQ_BIT(irq)]); /* do we need to register parent ? */ - if (parent->num_children == 0) { + if (cascade->num_children == 0) { ret = arch_interrupt_register(parent->irq, parent->handler, parent); } /* increment number of children */ - parent->num_children++; + cascade->num_children++; finish: - spin_unlock(&parent->lock); + spin_unlock(&cascade->lock); return ret; } @@ -64,19 +67,21 @@ static void irq_unregister_child(struct irq_desc *parent, int irq) struct irq_desc *child; struct list_item *clist; struct list_item *tlist; + struct irq_cascade_desc *cascade = container_of(parent, + struct irq_cascade_desc, desc); - spin_lock(&parent->lock); + spin_lock(&cascade->lock); /* does child already exist ? */ - if (list_is_empty(&parent->child[SOF_IRQ_BIT(irq)])) + if (list_is_empty(&cascade->child[SOF_IRQ_BIT(irq)])) goto finish; - list_for_item_safe(clist, tlist, &parent->child[SOF_IRQ_BIT(irq)]) { + list_for_item_safe(clist, tlist, &cascade->child[SOF_IRQ_BIT(irq)]) { child = container_of(clist, struct irq_desc, irq_list); if (SOF_IRQ_ID(irq) == child->id) { list_item_del(&child->irq_list); - parent->num_children--; + cascade->num_children--; rfree(child); } } @@ -85,25 +90,27 @@ static void irq_unregister_child(struct irq_desc *parent, int irq) * unregister the root interrupt if the this l2 is * the last registered one. */ - if (parent->num_children == 0) + if (cascade->num_children == 0) arch_interrupt_unregister(parent->irq); finish: - spin_unlock(&parent->lock); + spin_unlock(&cascade->lock); } static uint32_t irq_enable_child(struct irq_desc *parent, int irq) { struct irq_desc *child; struct list_item *clist; + struct irq_cascade_desc *cascade = container_of(parent, + struct irq_cascade_desc, desc); - spin_lock(&parent->lock); + spin_lock(&cascade->lock); /* enable the parent interrupt */ if (parent->enabled_count == 0) arch_interrupt_enable_mask(1 << SOF_IRQ_NUMBER(irq)); - list_for_item(clist, &parent->child[SOF_IRQ_BIT(irq)]) { + list_for_item(clist, &cascade->child[SOF_IRQ_BIT(irq)]) { child = container_of(clist, struct irq_desc, irq_list); if ((SOF_IRQ_ID(irq) == child->id) && @@ -116,7 +123,7 @@ static uint32_t irq_enable_child(struct irq_desc *parent, int irq) } } - spin_unlock(&parent->lock); + spin_unlock(&cascade->lock); return 0; } @@ -125,10 +132,12 @@ static uint32_t irq_disable_child(struct irq_desc *parent, int irq) { struct irq_desc *child; struct list_item *clist; + struct irq_cascade_desc *cascade = container_of(parent, + struct irq_cascade_desc, desc); - spin_lock(&parent->lock); + spin_lock(&cascade->lock); - list_for_item(clist, &parent->child[SOF_IRQ_BIT(irq)]) { + list_for_item(clist, &cascade->child[SOF_IRQ_BIT(irq)]) { child = container_of(clist, struct irq_desc, irq_list); if ((SOF_IRQ_ID(irq) == child->id) && @@ -144,7 +153,7 @@ static uint32_t irq_disable_child(struct irq_desc *parent, int irq) if (parent->enabled_count == 0) arch_interrupt_disable_mask(1 << SOF_IRQ_NUMBER(irq)); - spin_unlock(&parent->lock); + spin_unlock(&cascade->lock); return 0; } diff --git a/src/include/sof/drivers/interrupt.h b/src/include/sof/drivers/interrupt.h index 040faad5ce22..e4e9f076b4b5 100644 --- a/src/include/sof/drivers/interrupt.h +++ b/src/include/sof/drivers/interrupt.h @@ -37,12 +37,19 @@ struct irq_desc { /* to identify interrupt with the same IRQ */ int id; - spinlock_t lock; uint32_t enabled_count; /* to link to other irq_desc */ struct list_item irq_list; +}; +/* A descriptor for cascading interrupt controllers */ +struct irq_cascade_desc { + /* the interrupt, that this controller is generating */ + struct irq_desc desc; + + /* protect child lists in the below array */ + spinlock_t lock; uint32_t num_children; struct list_item child[PLATFORM_IRQ_CHILDREN]; }; From b1306e82c5099b0062706c637f1cfa1dbaeb47f0 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Thu, 14 Feb 2019 12:28:08 +0100 Subject: [PATCH 02/25] interrupt: add a parameter to interrupt_unregister() Sharing interrupts is currently implemented by inserting an interrupt ID field into the interrupt bitmask. We want to get rid of bitmasked interrupt numbers, therefore that method has to be replaced. This patch uses an approach, similar to the Linux kernel: we pass the interrupt handler argument to the interrupt_unregister() function to be compared to the argument, used when registering the interrupt handler. This means, that users must use unique arguments when registering interrupts, but this is anyway the case in most cases. We also add a check for this to interrupt_register(). Signed-off-by: Guennadi Liakhovetski --- src/arch/xtensa/drivers/idc.c | 2 +- src/arch/xtensa/include/arch/drivers/timer.h | 1 + src/arch/xtensa/schedule/task.c | 6 ++--- src/drivers/dw/dma.c | 23 ++++++++++++------ src/drivers/intel/baytrail/timer.c | 4 +++- src/drivers/intel/cavs/dmic.c | 2 +- src/drivers/intel/cavs/timer.c | 19 ++++++++++++--- src/drivers/intel/haswell/timer.c | 4 +++- src/drivers/interrupt.c | 25 +++++++++++++++++--- src/include/sof/drivers/interrupt.h | 2 +- src/schedule/edf_schedule.c | 4 ++-- 11 files changed, 69 insertions(+), 23 deletions(-) diff --git a/src/arch/xtensa/drivers/idc.c b/src/arch/xtensa/drivers/idc.c index 6f5d9d7d0949..b04d0bc8bfb7 100644 --- a/src/arch/xtensa/drivers/idc.c +++ b/src/arch/xtensa/drivers/idc.c @@ -374,7 +374,7 @@ void idc_free(void) /* disable and unregister interrupt */ interrupt_disable(PLATFORM_IDC_INTERRUPT(core)); - interrupt_unregister(PLATFORM_IDC_INTERRUPT(core)); + interrupt_unregister(PLATFORM_IDC_INTERRUPT(core), idc); /* clear BUSY bits */ for (i = 0; i < PLATFORM_CORE_COUNT; i++) { diff --git a/src/arch/xtensa/include/arch/drivers/timer.h b/src/arch/xtensa/include/arch/drivers/timer.h index 51199121d043..20e1defbf182 100644 --- a/src/arch/xtensa/include/arch/drivers/timer.h +++ b/src/arch/xtensa/include/arch/drivers/timer.h @@ -16,6 +16,7 @@ struct timer { uint32_t id; uint32_t irq; + void *irq_arg; void *timer_data; /* used by core */ uint32_t hitime; /* high end of 64bit timer */ uint32_t hitimeout; diff --git a/src/arch/xtensa/schedule/task.c b/src/arch/xtensa/schedule/task.c index e99a59793c74..1c3e3da8e39d 100644 --- a/src/arch/xtensa/schedule/task.c +++ b/src/arch/xtensa/schedule/task.c @@ -223,7 +223,7 @@ void arch_free_tasks(void) spin_lock_irq(&(*low)->lock, flags); interrupt_disable(PLATFORM_IRQ_TASK_LOW); - interrupt_unregister(PLATFORM_IRQ_TASK_LOW); + interrupt_unregister(PLATFORM_IRQ_TASK_LOW, task_irq_low_get()); list_item_del(&(*low)->list); spin_unlock_irq(&(*low)->lock, flags); #endif @@ -234,7 +234,7 @@ void arch_free_tasks(void) spin_lock_irq(&(*med)->lock, flags); interrupt_disable(PLATFORM_IRQ_TASK_MED); - interrupt_unregister(PLATFORM_IRQ_TASK_MED); + interrupt_unregister(PLATFORM_IRQ_TASK_MED, task_irq_med_get()); list_item_del(&(*med)->list); spin_unlock_irq(&(*med)->lock, flags); #endif @@ -244,7 +244,7 @@ void arch_free_tasks(void) spin_lock_irq(&(*high)->lock, flags); interrupt_disable(PLATFORM_IRQ_TASK_HIGH); - interrupt_unregister(PLATFORM_IRQ_TASK_HIGH); + interrupt_unregister(PLATFORM_IRQ_TASK_HIGH, task_irq_high_get()); list_item_del(&(*high)->list); spin_unlock_irq(&(*high)->lock, flags); } diff --git a/src/drivers/dw/dma.c b/src/drivers/dw/dma.c index 76dc4eeabd26..c7d318fe17f7 100644 --- a/src/drivers/dw/dma.c +++ b/src/drivers/dw/dma.c @@ -71,6 +71,8 @@ struct dw_dma_chan_data { void *cb_data; /* callback type */ int cb_type; + + struct dma *dma; }; /* private data for DW DMA engine */ @@ -1050,7 +1052,8 @@ static int dw_dma_copy(struct dma *dma, unsigned int channel, int bytes, /* interrupt handler for DMA */ static void dw_dma_irq_handler(void *data) { - struct dma *dma = data; + struct dw_dma_chan_data *chan = data; + struct dma *dma = chan->dma; struct dma_pdata *p = dma_get_drvdata(dma); uint32_t status_intr; uint32_t status_err; @@ -1110,13 +1113,14 @@ static inline int dw_dma_interrupt_register(struct dma *dma, unsigned int channel) { struct dma_pdata *p = dma_get_drvdata(dma); + struct dw_dma_chan_data *chan = p->chan + channel; uint32_t irq = dma_chan_irq(dma, cpu_get_id(), channel); #if CONFIG_DMA_AGGREGATED_IRQ int cpu = cpu_get_id(); #endif int ret; - if (p->chan[channel].irq_disabled) { + if (chan->irq_disabled) { tracev_dwdma("dw_dma_interrupt_register(): dma %d channel %d " "not working in irq mode", dma->plat_data.id, channel); @@ -1127,7 +1131,7 @@ static inline int dw_dma_interrupt_register(struct dma *dma, if (!p->mask_irq_channels[cpu]) { #endif ret = interrupt_register(irq, IRQ_AUTO_UNMASK, - dw_dma_irq_handler, dma); + dw_dma_irq_handler, chan); if (ret < 0) { trace_dwdma_error("dw_dma_interrupt_register() error: " "dma %d channel %d failed to " @@ -1150,12 +1154,13 @@ static inline void dw_dma_interrupt_unregister(struct dma *dma, unsigned int channel) { struct dma_pdata *p = dma_get_drvdata(dma); + struct dw_dma_chan_data *chan = p->chan + channel; uint32_t irq = dma_chan_irq(dma, cpu_get_id(), channel); #if CONFIG_DMA_AGGREGATED_IRQ int cpu = cpu_get_id(); #endif - if (p->chan[channel].irq_disabled) { + if (chan->irq_disabled) { tracev_dwdma("dw_dma_interrupt_unregister(): dma %d channel %d" " not working in irq mode", dma->plat_data.id, channel); @@ -1168,7 +1173,7 @@ static inline void dw_dma_interrupt_unregister(struct dma *dma, if (!p->mask_irq_channels[cpu]) { #endif interrupt_disable(irq); - interrupt_unregister(irq); + interrupt_unregister(irq, chan); #if CONFIG_DMA_AGGREGATED_IRQ } #endif @@ -1224,6 +1229,7 @@ static int dw_dma_setup(struct dma *dma) static int dw_dma_probe(struct dma *dma) { + struct dw_dma_chan_data *chan; struct dma_pdata *dw_pdata; int ret; int i; @@ -1251,8 +1257,11 @@ static int dw_dma_probe(struct dma *dma) return ret; /* init work */ - for (i = 0; i < dma->plat_data.channels; i++) - dw_pdata->chan[i].status = COMP_STATE_INIT; + for (i = 0, chan = dw_pdata->chan; i < dma->plat_data.channels; + i++, chan++) { + chan->status = COMP_STATE_INIT; + chan->dma = dma; + } /* init number of channels draining */ atomic_init(&dma->num_channels_busy, 0); diff --git a/src/drivers/intel/baytrail/timer.c b/src/drivers/intel/baytrail/timer.c index 599cd7067a3e..9971875194df 100644 --- a/src/drivers/intel/baytrail/timer.c +++ b/src/drivers/intel/baytrail/timer.c @@ -202,6 +202,8 @@ static int platform_timer_register(struct timer *timer, int timer_register(struct timer *timer, void(*handler)(void *arg), void *arg) { + timer->irq_arg = arg; + switch (timer->id) { case TIMER0: case TIMER1: @@ -216,7 +218,7 @@ int timer_register(struct timer *timer, void(*handler)(void *arg), void *arg) void timer_unregister(struct timer *timer) { - interrupt_unregister(timer->irq); + interrupt_unregister(timer->irq, timer->irq_arg); } void timer_enable(struct timer *timer) diff --git a/src/drivers/intel/cavs/dmic.c b/src/drivers/intel/cavs/dmic.c index 122c82664360..6fee0e857a78 100644 --- a/src/drivers/intel/cavs/dmic.c +++ b/src/drivers/intel/cavs/dmic.c @@ -1552,7 +1552,7 @@ static int dmic_remove(struct dai *dai) interrupt_disable(dmic_irq(dai)); platform_interrupt_mask(dmic_irq(dai), 0); - interrupt_unregister(dmic_irq(dai)); + interrupt_unregister(dmic_irq(dai), dai); pm_runtime_put_sync(DMIC_CLK, dai->index); /* Disable DMIC power */ diff --git a/src/drivers/intel/cavs/timer.c b/src/drivers/intel/cavs/timer.c index cbca6f704673..75b075a4506b 100644 --- a/src/drivers/intel/cavs/timer.c +++ b/src/drivers/intel/cavs/timer.c @@ -102,6 +102,8 @@ static int platform_timer_register(struct timer *timer, if (err < 0) return err; + timer->irq_arg = arg; + /* enable timer interrupt */ interrupt_enable(timer->irq); @@ -113,11 +115,22 @@ static int platform_timer_register(struct timer *timer, int timer_register(struct timer *timer, void(*handler)(void *arg), void *arg) { + int ret; + switch (timer->id) { case TIMER0: case TIMER1: case TIMER2: - return arch_timer_register(timer, handler, arg); + ret = arch_timer_register(timer, handler, arg); + /* + * Actually this isn't needed for arch_interrupt_register(), + * since arch_interrupt_unregister() doesn't support interrupt + * sharing and thus doesn't need the handler argument to locate + * the handler, do it just for uniformity + */ + if (!ret) + timer->irq_arg = arg; + return ret; case TIMER3: return platform_timer_register(timer, handler, arg); default: @@ -131,7 +144,7 @@ static void platform_timer_unregister(struct timer *timer) interrupt_disable(timer->irq); /* unregister timer interrupt */ - interrupt_unregister(timer->irq); + interrupt_unregister(timer->irq, timer->irq_arg); } void timer_unregister(struct timer *timer) @@ -140,7 +153,7 @@ void timer_unregister(struct timer *timer) case TIMER0: case TIMER1: case TIMER2: - interrupt_unregister(timer->irq); + interrupt_unregister(timer->irq, timer->irq_arg); break; case TIMER3: platform_timer_unregister(timer); diff --git a/src/drivers/intel/haswell/timer.c b/src/drivers/intel/haswell/timer.c index f66969702ba2..137de301c57a 100644 --- a/src/drivers/intel/haswell/timer.c +++ b/src/drivers/intel/haswell/timer.c @@ -76,6 +76,8 @@ void platform_dai_wallclock(struct comp_dev *dai, uint64_t *wallclock) int timer_register(struct timer *timer, void(*handler)(void *arg), void *arg) { + timer->irq_arg = arg; + switch (timer->id) { case TIMER0: case TIMER1: @@ -88,7 +90,7 @@ int timer_register(struct timer *timer, void(*handler)(void *arg), void *arg) void timer_unregister(struct timer *timer) { - interrupt_unregister(timer->irq); + interrupt_unregister(timer->irq, timer->irq_arg); } void timer_enable(struct timer *timer) diff --git a/src/drivers/interrupt.c b/src/drivers/interrupt.c index 274c2182f68d..3ac7784ef020 100644 --- a/src/drivers/interrupt.c +++ b/src/drivers/interrupt.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -22,6 +23,7 @@ static int irq_register_child(struct irq_desc *parent, int irq, int unmask, int ret = 0; struct irq_desc *child; struct irq_cascade_desc *cascade; + struct list_item *list; if (parent == NULL) return -EINVAL; @@ -30,6 +32,18 @@ static int irq_register_child(struct irq_desc *parent, int irq, int unmask, spin_lock(&cascade->lock); + list_for_item(list, &cascade->child[SOF_IRQ_BIT(irq)]) { + child = container_of(list, struct irq_desc, irq_list); + + if (child->handler_arg == arg) { + trace_error(TRACE_CLASS_IRQ, + "error: IRQ 0x%x handler argument re-used!", + irq); + ret = -EINVAL; + goto finish; + } + } + /* init child from run-time, may be registered and unregistered * many times at run-time */ @@ -62,7 +76,8 @@ static int irq_register_child(struct irq_desc *parent, int irq, int unmask, return ret; } -static void irq_unregister_child(struct irq_desc *parent, int irq) +static void irq_unregister_child(struct irq_desc *parent, int irq, + const void *arg) { struct irq_desc *child; struct list_item *clist; @@ -80,6 +95,10 @@ static void irq_unregister_child(struct irq_desc *parent, int irq) child = container_of(clist, struct irq_desc, irq_list); if (SOF_IRQ_ID(irq) == child->id) { + if (child->handler_arg != arg) + trace_error(TRACE_CLASS_IRQ, + "error: IRQ 0x%x handler argument mismatch!", + irq); list_item_del(&child->irq_list); cascade->num_children--; rfree(child); @@ -170,7 +189,7 @@ int interrupt_register(uint32_t irq, int unmask, void (*handler)(void *arg), return irq_register_child(parent, irq, unmask, handler, arg); } -void interrupt_unregister(uint32_t irq) +void interrupt_unregister(uint32_t irq, const void *arg) { struct irq_desc *parent; @@ -179,7 +198,7 @@ void interrupt_unregister(uint32_t irq) if (parent == NULL) arch_interrupt_unregister(irq); else - irq_unregister_child(parent, irq); + irq_unregister_child(parent, irq, arg); } uint32_t interrupt_enable(uint32_t irq) diff --git a/src/include/sof/drivers/interrupt.h b/src/include/sof/drivers/interrupt.h index e4e9f076b4b5..9d07c64c1695 100644 --- a/src/include/sof/drivers/interrupt.h +++ b/src/include/sof/drivers/interrupt.h @@ -56,7 +56,7 @@ struct irq_cascade_desc { int interrupt_register(uint32_t irq, int unmask, void(*handler)(void *arg), void *arg); -void interrupt_unregister(uint32_t irq); +void interrupt_unregister(uint32_t irq, const void *arg); uint32_t interrupt_enable(uint32_t irq); uint32_t interrupt_disable(uint32_t irq); diff --git a/src/schedule/edf_schedule.c b/src/schedule/edf_schedule.c index 696a2aa15b30..daf68cd7324b 100644 --- a/src/schedule/edf_schedule.c +++ b/src/schedule/edf_schedule.c @@ -429,7 +429,7 @@ static int edf_scheduler_init(void) /* configure scheduler interrupt */ interrupt_register(PLATFORM_SCHEDULE_IRQ, IRQ_AUTO_UNMASK, - edf_scheduler_run, NULL); + edf_scheduler_run, sch); interrupt_enable(PLATFORM_SCHEDULE_IRQ); /* allocate arch tasks */ @@ -449,7 +449,7 @@ static void edf_scheduler_free(void) /* disable and unregister scheduler interrupt */ interrupt_disable(PLATFORM_SCHEDULE_IRQ); - interrupt_unregister(PLATFORM_SCHEDULE_IRQ); + interrupt_unregister(PLATFORM_SCHEDULE_IRQ, sch); /* free arch tasks */ arch_free_tasks(); From 0a4cbc329384d56733cbafac437ddff45a174fdf Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Mon, 18 Feb 2019 11:28:33 +0100 Subject: [PATCH 03/25] xtensa: only enable interrupts after allocating context Enabling interrupts before allocating context for them can at least in theory lead to such an interrupt being triggered and then attempting to access the context. Fix the order for task interrupts. Signed-off-by: Guennadi Liakhovetski --- src/arch/xtensa/include/arch/schedule/task.h | 5 - src/arch/xtensa/init.c | 1 - src/arch/xtensa/schedule/task.c | 132 ++++++++----------- 3 files changed, 53 insertions(+), 85 deletions(-) diff --git a/src/arch/xtensa/include/arch/schedule/task.h b/src/arch/xtensa/include/arch/schedule/task.h index 36cdf32cfd19..ebb1b7a4de15 100644 --- a/src/arch/xtensa/include/arch/schedule/task.h +++ b/src/arch/xtensa/include/arch/schedule/task.h @@ -63,11 +63,6 @@ int arch_allocate_tasks(void); */ void arch_free_tasks(void); -/** - * \brief Assigns IRQ tasks to interrupts. - */ -int arch_assign_tasks(void); - #endif /* __ARCH_SCHEDULE_TASK_H__ */ #else diff --git a/src/arch/xtensa/init.c b/src/arch/xtensa/init.c index cdee7b10b289..6f962f1bf4e0 100644 --- a/src/arch/xtensa/init.c +++ b/src/arch/xtensa/init.c @@ -87,7 +87,6 @@ int arch_init(struct sof *sof) { initialize_pointers_per_core(); register_exceptions(); - arch_assign_tasks(); return 0; } diff --git a/src/arch/xtensa/schedule/task.c b/src/arch/xtensa/schedule/task.c index 1c3e3da8e39d..849ba398c8c4 100644 --- a/src/arch/xtensa/schedule/task.c +++ b/src/arch/xtensa/schedule/task.c @@ -48,29 +48,32 @@ struct irq_task **task_irq_high_get(void) return &ctx->irq_high_task; } -/** - * \brief Retrieves task IRQ level. - * \param[in,out] task Task data. - * \return IRQ level. - */ -static uint32_t task_get_irq(struct task *task) +static struct irq_task *task_get_irq_task(struct task *task) { - uint32_t irq; - switch (task->priority) { +#ifdef CONFIG_TASK_HAVE_PRIORITY_MEDIUM case SOF_TASK_PRI_MED + 1 ... SOF_TASK_PRI_LOW: - irq = PLATFORM_IRQ_TASK_LOW; - break; + return *task_irq_low_get(); case SOF_TASK_PRI_HIGH ... SOF_TASK_PRI_MED - 1: - irq = PLATFORM_IRQ_TASK_HIGH; - break; + return *task_irq_high_get(); case SOF_TASK_PRI_MED: + return *task_irq_med_get(); +#elif CONFIG_TASK_HAVE_PRIORITY_LOW + case SOF_TASK_PRI_MED ... SOF_TASK_PRI_LOW: + return *task_irq_low_get(); + case SOF_TASK_PRI_HIGH ... SOF_TASK_PRI_MED - 1: + return *task_irq_high_get(); +#else + case SOF_TASK_PRI_HIGH ... SOF_TASK_PRI_LOW: + return *task_irq_high_get(); +#endif default: - irq = PLATFORM_IRQ_TASK_MED; - break; + trace_error(TRACE_CLASS_IRQ, + "task_get_irq_task() error: task priority %d", + task->priority); } - return irq; + return NULL; } /** @@ -79,39 +82,12 @@ static uint32_t task_get_irq(struct task *task) */ static int task_set_data(struct task *task) { - struct list_item *dst = NULL; - struct irq_task *irq_task; - uint32_t flags; + struct irq_task *irq_task = task_get_irq_task(task); + struct list_item *dst; + unsigned long flags; - switch (task->priority) { -#if CONFIG_TASK_HAVE_PRIORITY_MEDIUM - case SOF_TASK_PRI_MED + 1 ... SOF_TASK_PRI_LOW: - irq_task = *task_irq_low_get(); - break; - case SOF_TASK_PRI_HIGH ... SOF_TASK_PRI_MED - 1: - irq_task = *task_irq_high_get(); - break; - case SOF_TASK_PRI_MED: - irq_task = *task_irq_med_get(); - break; -#elif CONFIG_TASK_HAVE_PRIORITY_LOW - case SOF_TASK_PRI_MED ... SOF_TASK_PRI_LOW: - irq_task = *task_irq_low_get(); - break; - case SOF_TASK_PRI_HIGH ... SOF_TASK_PRI_MED - 1: - irq_task = *task_irq_high_get(); - break; -#else - case SOF_TASK_PRI_HIGH ... SOF_TASK_PRI_LOW: - irq_task = *task_irq_high_get(); - break; -#endif - default: - trace_error(TRACE_CLASS_IRQ, - "task_set_data() error: task priority %d", - task->priority); + if (!irq_task) return -EINVAL; - } dst = &irq_task->list; spin_lock_irq(&irq_task->lock, flags); @@ -165,22 +141,26 @@ static void _irq_task(void *arg) int arch_run_task(struct task *task) { - uint32_t irq; + struct irq_task *irq_task = task_get_irq_task(task); int ret; + if (!irq_task) + return -EINVAL; + ret = task_set_data(task); if (ret < 0) return ret; - irq = task_get_irq(task); - interrupt_set(irq); + interrupt_set(irq_task->irq); return 0; } int arch_allocate_tasks(void) { + int ret; + #if CONFIG_TASK_HAVE_PRIORITY_LOW /* irq low */ struct irq_task **low = task_irq_low_get(); @@ -189,6 +169,12 @@ int arch_allocate_tasks(void) list_init(&((*low)->list)); spinlock_init(&((*low)->lock)); (*low)->irq = PLATFORM_IRQ_TASK_LOW; + + ret = interrupt_register((*low)->irq, IRQ_AUTO_UNMASK, _irq_task, + task_irq_low_get()); + if (ret < 0) + return ret; + interrupt_enable((*low)->irq); #endif #if CONFIG_TASK_HAVE_PRIORITY_MEDIUM @@ -199,6 +185,12 @@ int arch_allocate_tasks(void) list_init(&((*med)->list)); spinlock_init(&((*med)->lock)); (*med)->irq = PLATFORM_IRQ_TASK_MED; + + ret = interrupt_register((*med)->irq, IRQ_AUTO_UNMASK, _irq_task, + task_irq_med_get()); + if (ret < 0) + return ret; + interrupt_enable((*med)->irq); #endif /* irq high */ @@ -209,6 +201,12 @@ int arch_allocate_tasks(void) spinlock_init(&((*high)->lock)); (*high)->irq = PLATFORM_IRQ_TASK_HIGH; + ret = interrupt_register((*high)->irq, IRQ_AUTO_UNMASK, _irq_task, + task_irq_high_get()); + if (ret < 0) + return ret; + interrupt_enable((*high)->irq); + return 0; } @@ -222,8 +220,8 @@ void arch_free_tasks(void) struct irq_task **low = task_irq_low_get(); spin_lock_irq(&(*low)->lock, flags); - interrupt_disable(PLATFORM_IRQ_TASK_LOW); - interrupt_unregister(PLATFORM_IRQ_TASK_LOW, task_irq_low_get()); + interrupt_disable((*low)->irq); + interrupt_unregister((*low)->irq, task_irq_low_get()); list_item_del(&(*low)->list); spin_unlock_irq(&(*low)->lock, flags); #endif @@ -233,8 +231,8 @@ void arch_free_tasks(void) struct irq_task **med = task_irq_med_get(); spin_lock_irq(&(*med)->lock, flags); - interrupt_disable(PLATFORM_IRQ_TASK_MED); - interrupt_unregister(PLATFORM_IRQ_TASK_MED, task_irq_med_get()); + interrupt_disable((*med)->irq); + interrupt_unregister((*med)->irq, task_irq_med_get()); list_item_del(&(*med)->list); spin_unlock_irq(&(*med)->lock, flags); #endif @@ -243,32 +241,8 @@ void arch_free_tasks(void) struct irq_task **high = task_irq_high_get(); spin_lock_irq(&(*high)->lock, flags); - interrupt_disable(PLATFORM_IRQ_TASK_HIGH); - interrupt_unregister(PLATFORM_IRQ_TASK_HIGH, task_irq_high_get()); + interrupt_disable((*high)->irq); + interrupt_unregister((*high)->irq, task_irq_high_get()); list_item_del(&(*high)->list); spin_unlock_irq(&(*high)->lock, flags); } - -int arch_assign_tasks(void) -{ -#if CONFIG_TASK_HAVE_PRIORITY_LOW - /* irq low */ - interrupt_register(PLATFORM_IRQ_TASK_LOW, IRQ_AUTO_UNMASK, _irq_task, - task_irq_low_get()); - interrupt_enable(PLATFORM_IRQ_TASK_LOW); -#endif - -#if CONFIG_TASK_HAVE_PRIORITY_MEDIUM - /* irq medium */ - interrupt_register(PLATFORM_IRQ_TASK_MED, IRQ_AUTO_UNMASK, _irq_task, - task_irq_med_get()); - interrupt_enable(PLATFORM_IRQ_TASK_MED); -#endif - - /* irq high */ - interrupt_register(PLATFORM_IRQ_TASK_HIGH, IRQ_AUTO_UNMASK, _irq_task, - task_irq_high_get()); - interrupt_enable(PLATFORM_IRQ_TASK_HIGH); - - return 0; -} From d4cd20afdc5905e298d8a1f7f455f89c8eae1fd7 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Tue, 19 Feb 2019 10:49:48 +0100 Subject: [PATCH 04/25] byt, hsw: call arch_interrupt_clear() directly Platform interrupt handling code should call arch_interrupt_clear() directly, no need to use the interrupt_clear() wrapper. Signed-off-by: Guennadi Liakhovetski --- src/drivers/intel/baytrail/interrupt.c | 18 +++++++++--------- src/drivers/intel/haswell/interrupt.c | 2 +- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/drivers/intel/baytrail/interrupt.c b/src/drivers/intel/baytrail/interrupt.c index 304e5a1c66f3..fa17d1535074 100644 --- a/src/drivers/intel/baytrail/interrupt.c +++ b/src/drivers/intel/baytrail/interrupt.c @@ -29,40 +29,40 @@ void platform_interrupt_clear(uint32_t irq, uint32_t mask) switch (irq) { case IRQ_NUM_EXT_SSP0: shim_write(SHIM_PISR, mask << 3); - interrupt_clear(irq); + arch_interrupt_clear(irq); break; case IRQ_NUM_EXT_SSP1: shim_write(SHIM_PISR, mask << 4); - interrupt_clear(irq); + arch_interrupt_clear(irq); break; case IRQ_NUM_EXT_SSP2: shim_write(SHIM_PISR, mask << 5); - interrupt_clear(irq); + arch_interrupt_clear(irq); break; case IRQ_NUM_EXT_DMAC0: shim_write(SHIM_PISR, mask << 16); - interrupt_clear(irq); + arch_interrupt_clear(irq); break; case IRQ_NUM_EXT_DMAC1: shim_write(SHIM_PISR, mask << 24); - interrupt_clear(irq); + arch_interrupt_clear(irq); break; #if defined CONFIG_CHERRYTRAIL case IRQ_NUM_EXT_DMAC2: shim_write(SHIM_PISRH, mask << 0); - interrupt_clear(irq); + arch_interrupt_clear(irq); break; case IRQ_NUM_EXT_SSP3: shim_write(SHIM_PISRH, mask << 8); - interrupt_clear(irq); + arch_interrupt_clear(irq); break; case IRQ_NUM_EXT_SSP4: shim_write(SHIM_PISRH, mask << 9); - interrupt_clear(irq); + arch_interrupt_clear(irq); break; case IRQ_NUM_EXT_SSP5: shim_write(SHIM_PISRH, mask << 10); - interrupt_clear(irq); + arch_interrupt_clear(irq); break; #endif default: diff --git a/src/drivers/intel/haswell/interrupt.c b/src/drivers/intel/haswell/interrupt.c index 3f37fc5ace9a..2a6ef1862877 100644 --- a/src/drivers/intel/haswell/interrupt.c +++ b/src/drivers/intel/haswell/interrupt.c @@ -32,7 +32,7 @@ void platform_interrupt_clear(uint32_t irq, uint32_t mask) case IRQ_NUM_EXT_DMAC1: case IRQ_NUM_EXT_SSP0: case IRQ_NUM_EXT_SSP1: - interrupt_clear(irq); + arch_interrupt_clear(irq); break; default: break; From e8aea53dcf8ee9744f9be4e669edb2d3f6c4e0a6 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Tue, 19 Feb 2019 11:38:32 +0100 Subject: [PATCH 05/25] cavs: don't call known dummy function platform_interrupt_clear() is a dummy function on cAVS platforms, no need to call it in cAVS-specific drivers. Signed-off-by: Guennadi Liakhovetski --- src/drivers/intel/cavs/dmic.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/drivers/intel/cavs/dmic.c b/src/drivers/intel/cavs/dmic.c index 6fee0e857a78..f79319557fe1 100644 --- a/src/drivers/intel/cavs/dmic.c +++ b/src/drivers/intel/cavs/dmic.c @@ -1499,9 +1499,6 @@ static void dmic_irq_handler(void *data) if (val1 & OUTSTAT1_ROR_BIT) trace_dmic_error("dmic_irq_handler() error: " "full fifo B or PDM overrrun"); - - /* clear IRQ */ - platform_interrupt_clear(dmic_irq(dai), 1); } static int dmic_probe(struct dai *dai) From 1fdb3a013b5cb945b24ea360479765cfefcb9638 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Tue, 19 Feb 2019 13:18:37 +0100 Subject: [PATCH 06/25] interrupt: unify interrupt_clear() and interrupt_set() functions Currently the SOF API in addition to interrupt_clear() and interrupt_set() functions also has platform_interrupt_clear() and platform_interrupt_set(). Those functions are partially overlapping and their choice is confusing. Unify them to only use the former variant - without the platform_ prefix. Signed-off-by: Guennadi Liakhovetski --- src/drivers/dw/dma.c | 7 +++---- src/drivers/imx/interrupt.c | 2 +- src/drivers/intel/baytrail/interrupt.c | 10 +++++++++- src/drivers/intel/cavs/interrupt.c | 8 ++++++++ src/drivers/intel/haswell/interrupt.c | 5 ++++- src/include/sof/drivers/interrupt.h | 11 ++++++++--- 6 files changed, 33 insertions(+), 10 deletions(-) diff --git a/src/drivers/dw/dma.c b/src/drivers/dw/dma.c index c7d318fe17f7..e6504ad02bb4 100644 --- a/src/drivers/dw/dma.c +++ b/src/drivers/dw/dma.c @@ -171,8 +171,7 @@ static void dw_dma_interrupt_clear(struct dma *dma, unsigned int channel) dw_write(dma, DW_CLEAR_ERR, DW_CHAN(channel)); /* clear platform interrupt */ - platform_interrupt_clear(dma_irq(dma, cpu_get_id()), - DW_CHAN(channel)); + interrupt_clear_mask(dma_irq(dma, cpu_get_id()), DW_CHAN(channel)); } /* allocate next free DMA channel */ @@ -1094,8 +1093,8 @@ static void dw_dma_irq_handler(void *data) } /* clear platform and DSP interrupt */ - platform_interrupt_clear(dma_irq(dma, cpu_get_id()), - status_src | status_err); + interrupt_clear_mask(dma_irq(dma, cpu_get_id()), + status_src | status_err); for (i = 0; i < dma->plat_data.channels; i++) { /* skip if channel is not running */ diff --git a/src/drivers/imx/interrupt.c b/src/drivers/imx/interrupt.c index 8dbcf2eb4c59..399026773ffd 100644 --- a/src/drivers/imx/interrupt.c +++ b/src/drivers/imx/interrupt.c @@ -15,7 +15,7 @@ struct irq_desc *platform_irq_get_parent(uint32_t irq) return NULL; } -void platform_interrupt_set(int irq) +void platform_interrupt_set(uint32_t irq) { arch_interrupt_set(irq); } diff --git a/src/drivers/intel/baytrail/interrupt.c b/src/drivers/intel/baytrail/interrupt.c index fa17d1535074..b8e13c945020 100644 --- a/src/drivers/intel/baytrail/interrupt.c +++ b/src/drivers/intel/baytrail/interrupt.c @@ -18,7 +18,7 @@ struct irq_desc *platform_irq_get_parent(uint32_t irq) return NULL; } -void platform_interrupt_set(int irq) +void platform_interrupt_set(uint32_t irq) { arch_interrupt_set(irq); } @@ -27,6 +27,14 @@ void platform_interrupt_set(int irq) void platform_interrupt_clear(uint32_t irq, uint32_t mask) { switch (irq) { + case IRQ_NUM_EXT_PMC: + case IRQ_NUM_EXT_IA: + case IRQ_NUM_SOFTWARE2: + case IRQ_NUM_SOFTWARE3: + case IRQ_NUM_SOFTWARE4: + case IRQ_NUM_SOFTWARE5: + arch_interrupt_clear(irq); + break; case IRQ_NUM_EXT_SSP0: shim_write(SHIM_PISR, mask << 3); arch_interrupt_clear(irq); diff --git a/src/drivers/intel/cavs/interrupt.c b/src/drivers/intel/cavs/interrupt.c index b854a2dfdad6..44d08b5a74c7 100644 --- a/src/drivers/intel/cavs/interrupt.c +++ b/src/drivers/intel/cavs/interrupt.c @@ -210,8 +210,16 @@ void platform_interrupt_unmask(uint32_t irq, uint32_t mask) } } +void platform_interrupt_set(uint32_t irq) +{ + if (!platform_irq_get_parent(irq)) + arch_interrupt_set(SOF_IRQ_NUMBER(irq)); +} + void platform_interrupt_clear(uint32_t irq, uint32_t mask) { + if (!platform_irq_get_parent(irq)) + arch_interrupt_clear(SOF_IRQ_NUMBER(irq)); } void platform_interrupt_init(void) diff --git a/src/drivers/intel/haswell/interrupt.c b/src/drivers/intel/haswell/interrupt.c index 2a6ef1862877..091ea749f523 100644 --- a/src/drivers/intel/haswell/interrupt.c +++ b/src/drivers/intel/haswell/interrupt.c @@ -19,7 +19,7 @@ struct irq_desc *platform_irq_get_parent(uint32_t irq) return NULL; } -void platform_interrupt_set(int irq) +void platform_interrupt_set(uint32_t irq) { arch_interrupt_set(irq); } @@ -32,6 +32,9 @@ void platform_interrupt_clear(uint32_t irq, uint32_t mask) case IRQ_NUM_EXT_DMAC1: case IRQ_NUM_EXT_SSP0: case IRQ_NUM_EXT_SSP1: + case IRQ_NUM_EXT_IA: + case IRQ_NUM_SOFTWARE1: + case IRQ_NUM_SOFTWARE2: arch_interrupt_clear(irq); break; default: diff --git a/src/include/sof/drivers/interrupt.h b/src/include/sof/drivers/interrupt.h index 9d07c64c1695..74d2b6b6cbcf 100644 --- a/src/include/sof/drivers/interrupt.h +++ b/src/include/sof/drivers/interrupt.h @@ -63,7 +63,7 @@ uint32_t interrupt_disable(uint32_t irq); void platform_interrupt_init(void); struct irq_desc *platform_irq_get_parent(uint32_t irq); -void platform_interrupt_set(int irq); +void platform_interrupt_set(uint32_t irq); void platform_interrupt_clear(uint32_t irq, uint32_t mask); uint32_t platform_interrupt_get_enabled(void); void platform_interrupt_mask(uint32_t irq, uint32_t mask); @@ -71,12 +71,17 @@ void platform_interrupt_unmask(uint32_t irq, uint32_t mask); static inline void interrupt_set(int irq) { - arch_interrupt_set(SOF_IRQ_NUMBER(irq)); + platform_interrupt_set(irq); +} + +static inline void interrupt_clear_mask(int irq, uint32_t mask) +{ + platform_interrupt_clear(irq, mask); } static inline void interrupt_clear(int irq) { - arch_interrupt_clear(SOF_IRQ_NUMBER(irq)); + interrupt_clear_mask(irq, 1); } static inline uint32_t interrupt_global_disable(void) From 7b2bb575673722fde9865b798d6ad7bab99acdb9 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Thu, 21 Feb 2019 13:13:37 +0100 Subject: [PATCH 07/25] interrupt: remove an unused function parameter platform_interrupt_mask() and platform_interrupt_unmask() have a "mask" parameter, that is actually never used. It is only used on baytrail, but the only use of those functions on that platform is from the ssp.c driver, where mask is fixed to 1. Besides the meaning of that parameter was unclear: it would be logical to assume, that it is a bitmask that has to be applied to a masking register, but often those functions were called with mask=0, which makes no sense. This patch removes that parameter. Signed-off-by: Guennadi Liakhovetski --- src/arch/xtensa/drivers/idc.c | 2 +- src/drivers/imx/interrupt.c | 4 +-- src/drivers/intel/baytrail/interrupt.c | 40 +++++++++++++------------- src/drivers/intel/cavs/dmic.c | 4 +-- src/drivers/intel/cavs/interrupt.c | 4 +-- src/drivers/intel/cavs/timer.c | 4 +-- src/drivers/intel/haswell/interrupt.c | 4 +-- src/drivers/interrupt.c | 4 +-- src/include/sof/drivers/interrupt.h | 4 +-- 9 files changed, 35 insertions(+), 35 deletions(-) diff --git a/src/arch/xtensa/drivers/idc.c b/src/arch/xtensa/drivers/idc.c index b04d0bc8bfb7..36259845e75f 100644 --- a/src/arch/xtensa/drivers/idc.c +++ b/src/arch/xtensa/drivers/idc.c @@ -52,7 +52,7 @@ void idc_enable_interrupts(int target_core, int source_core) { idc_write(IPC_IDCCTL, target_core, IPC_IDCCTL_IDCTBIE(source_core)); - platform_interrupt_unmask(PLATFORM_IDC_INTERRUPT(target_core), 0); + platform_interrupt_unmask(PLATFORM_IDC_INTERRUPT(target_core)); } /** diff --git a/src/drivers/imx/interrupt.c b/src/drivers/imx/interrupt.c index 399026773ffd..035d39b182a8 100644 --- a/src/drivers/imx/interrupt.c +++ b/src/drivers/imx/interrupt.c @@ -30,5 +30,5 @@ uint32_t platform_interrupt_get_enabled(void) return 0; } -void platform_interrupt_mask(uint32_t irq, uint32_t mask) {} -void platform_interrupt_unmask(uint32_t irq, uint32_t mask) {} +void platform_interrupt_mask(uint32_t irq) {} +void platform_interrupt_unmask(uint32_t irq) {} diff --git a/src/drivers/intel/baytrail/interrupt.c b/src/drivers/intel/baytrail/interrupt.c index b8e13c945020..50a6ac79f27b 100644 --- a/src/drivers/intel/baytrail/interrupt.c +++ b/src/drivers/intel/baytrail/interrupt.c @@ -84,36 +84,36 @@ uint32_t platform_interrupt_get_enabled(void) return shim_read(SHIM_PIMR); } -void platform_interrupt_mask(uint32_t irq, uint32_t mask) +void platform_interrupt_mask(uint32_t irq) { switch (irq) { case IRQ_NUM_EXT_SSP0: - shim_write(SHIM_PIMR, mask << 3); + shim_write(SHIM_PIMR, 1 << 3); break; case IRQ_NUM_EXT_SSP1: - shim_write(SHIM_PIMR, mask << 4); + shim_write(SHIM_PIMR, 1 << 4); break; case IRQ_NUM_EXT_SSP2: - shim_write(SHIM_PIMR, mask << 5); + shim_write(SHIM_PIMR, 1 << 5); break; case IRQ_NUM_EXT_DMAC0: - shim_write(SHIM_PIMR, mask << 16); + shim_write(SHIM_PIMR, 1 << 16); break; case IRQ_NUM_EXT_DMAC1: - shim_write(SHIM_PIMR, mask << 24); + shim_write(SHIM_PIMR, 1 << 24); break; #if defined CONFIG_CHERRYTRAIL case IRQ_NUM_EXT_DMAC2: - shim_write(SHIM_PIMRH, mask << 8); + shim_write(SHIM_PIMRH, 1 << 8); break; case IRQ_NUM_EXT_SSP3: - shim_write(SHIM_PIMRH, mask << 0); + shim_write(SHIM_PIMRH, 1 << 0); break; case IRQ_NUM_EXT_SSP4: - shim_write(SHIM_PIMRH, mask << 1); + shim_write(SHIM_PIMRH, 1 << 1); break; case IRQ_NUM_EXT_SSP5: - shim_write(SHIM_PIMRH, mask << 2); + shim_write(SHIM_PIMRH, 1 << 2); break; #endif default: @@ -121,36 +121,36 @@ void platform_interrupt_mask(uint32_t irq, uint32_t mask) } } -void platform_interrupt_unmask(uint32_t irq, uint32_t mask) +void platform_interrupt_unmask(uint32_t irq) { switch (irq) { case IRQ_NUM_EXT_SSP0: - shim_write(SHIM_PIMR, shim_read(SHIM_PIMR) & ~(mask << 3)); + shim_write(SHIM_PIMR, shim_read(SHIM_PIMR) & ~(1 << 3)); break; case IRQ_NUM_EXT_SSP1: - shim_write(SHIM_PIMR, shim_read(SHIM_PIMR) & ~(mask << 4)); + shim_write(SHIM_PIMR, shim_read(SHIM_PIMR) & ~(1 << 4)); break; case IRQ_NUM_EXT_SSP2: - shim_write(SHIM_PIMR, shim_read(SHIM_PIMR) & ~(mask << 5)); + shim_write(SHIM_PIMR, shim_read(SHIM_PIMR) & ~(1 << 5)); break; case IRQ_NUM_EXT_DMAC0: - shim_write(SHIM_PIMR, shim_read(SHIM_PIMR) & ~(mask << 16)); + shim_write(SHIM_PIMR, shim_read(SHIM_PIMR) & ~(1 << 16)); break; case IRQ_NUM_EXT_DMAC1: - shim_write(SHIM_PIMR, shim_read(SHIM_PIMR) & ~(mask << 24)); + shim_write(SHIM_PIMR, shim_read(SHIM_PIMR) & ~(1 << 24)); break; #if defined CONFIG_CHERRYTRAIL case IRQ_NUM_EXT_DMAC2: - shim_write(SHIM_PIMRH, shim_read(SHIM_PIMRH) & ~(mask << 8)); + shim_write(SHIM_PIMRH, shim_read(SHIM_PIMRH) & ~(1 << 8)); break; case IRQ_NUM_EXT_SSP3: - shim_write(SHIM_PIMRH, shim_read(SHIM_PIMRH) & ~(mask << 0)); + shim_write(SHIM_PIMRH, shim_read(SHIM_PIMRH) & ~(1 << 0)); break; case IRQ_NUM_EXT_SSP4: - shim_write(SHIM_PIMRH, shim_read(SHIM_PIMRH) & ~(mask << 1)); + shim_write(SHIM_PIMRH, shim_read(SHIM_PIMRH) & ~(1 << 1)); break; case IRQ_NUM_EXT_SSP5: - shim_write(SHIM_PIMRH, shim_read(SHIM_PIMRH) & ~(mask << 2)); + shim_write(SHIM_PIMRH, shim_read(SHIM_PIMRH) & ~(1 << 2)); break; #endif default: diff --git a/src/drivers/intel/cavs/dmic.c b/src/drivers/intel/cavs/dmic.c index f79319557fe1..fdec691f7ca2 100644 --- a/src/drivers/intel/cavs/dmic.c +++ b/src/drivers/intel/cavs/dmic.c @@ -1537,7 +1537,7 @@ static int dmic_probe(struct dai *dai) /* Disable dynamic clock gating for dmic before touching any reg */ pm_runtime_get_sync(DMIC_CLK, dai->index); - platform_interrupt_unmask(dmic_irq(dai), 1); + platform_interrupt_unmask(dmic_irq(dai)); interrupt_enable(dmic_irq(dai)); return 0; @@ -1548,7 +1548,7 @@ static int dmic_remove(struct dai *dai) int i; interrupt_disable(dmic_irq(dai)); - platform_interrupt_mask(dmic_irq(dai), 0); + platform_interrupt_mask(dmic_irq(dai)); interrupt_unregister(dmic_irq(dai), dai); pm_runtime_put_sync(DMIC_CLK, dai->index); diff --git a/src/drivers/intel/cavs/interrupt.c b/src/drivers/intel/cavs/interrupt.c index 44d08b5a74c7..c9dc8b083f1d 100644 --- a/src/drivers/intel/cavs/interrupt.c +++ b/src/drivers/intel/cavs/interrupt.c @@ -164,7 +164,7 @@ uint32_t platform_interrupt_get_enabled(void) return 0; } -void platform_interrupt_mask(uint32_t irq, uint32_t mask) +void platform_interrupt_mask(uint32_t irq) { int core = SOF_IRQ_CPU(irq); @@ -187,7 +187,7 @@ void platform_interrupt_mask(uint32_t irq, uint32_t mask) } } -void platform_interrupt_unmask(uint32_t irq, uint32_t mask) +void platform_interrupt_unmask(uint32_t irq) { int core = SOF_IRQ_CPU(irq); diff --git a/src/drivers/intel/cavs/timer.c b/src/drivers/intel/cavs/timer.c index 75b075a4506b..3b57f85a93b7 100644 --- a/src/drivers/intel/cavs/timer.c +++ b/src/drivers/intel/cavs/timer.c @@ -170,7 +170,7 @@ void timer_enable(struct timer *timer) interrupt_enable(timer->irq); break; case TIMER3: - platform_interrupt_unmask(timer->irq, 0); + platform_interrupt_unmask(timer->irq); break; } } @@ -184,7 +184,7 @@ void timer_disable(struct timer *timer) interrupt_disable(timer->irq); break; case TIMER3: - platform_interrupt_mask(timer->irq, 0); + platform_interrupt_mask(timer->irq); break; } } diff --git a/src/drivers/intel/haswell/interrupt.c b/src/drivers/intel/haswell/interrupt.c index 091ea749f523..b85e2268b70d 100644 --- a/src/drivers/intel/haswell/interrupt.c +++ b/src/drivers/intel/haswell/interrupt.c @@ -48,7 +48,7 @@ uint32_t platform_interrupt_get_enabled(void) return shim_read(SHIM_IMRD); } -void platform_interrupt_mask(uint32_t irq, uint32_t mask) +void platform_interrupt_mask(uint32_t irq) { switch (irq) { case IRQ_NUM_EXT_SSP0: @@ -68,7 +68,7 @@ void platform_interrupt_mask(uint32_t irq, uint32_t mask) } } -void platform_interrupt_unmask(uint32_t irq, uint32_t mask) +void platform_interrupt_unmask(uint32_t irq) { switch (irq) { case IRQ_NUM_EXT_SSP0: diff --git a/src/drivers/interrupt.c b/src/drivers/interrupt.c index 3ac7784ef020..12a16f956117 100644 --- a/src/drivers/interrupt.c +++ b/src/drivers/interrupt.c @@ -138,7 +138,7 @@ static uint32_t irq_enable_child(struct irq_desc *parent, int irq) parent->enabled_count++; /* enable the child interrupt */ - platform_interrupt_unmask(irq, 0); + platform_interrupt_unmask(irq); } } @@ -165,7 +165,7 @@ static uint32_t irq_disable_child(struct irq_desc *parent, int irq) parent->enabled_count--; /* disable the child interrupt */ - platform_interrupt_mask(irq, 0); + platform_interrupt_mask(irq); } } diff --git a/src/include/sof/drivers/interrupt.h b/src/include/sof/drivers/interrupt.h index 74d2b6b6cbcf..7741a03e2061 100644 --- a/src/include/sof/drivers/interrupt.h +++ b/src/include/sof/drivers/interrupt.h @@ -66,8 +66,8 @@ struct irq_desc *platform_irq_get_parent(uint32_t irq); void platform_interrupt_set(uint32_t irq); void platform_interrupt_clear(uint32_t irq, uint32_t mask); uint32_t platform_interrupt_get_enabled(void); -void platform_interrupt_mask(uint32_t irq, uint32_t mask); -void platform_interrupt_unmask(uint32_t irq, uint32_t mask); +void platform_interrupt_mask(uint32_t irq); +void platform_interrupt_unmask(uint32_t irq); static inline void interrupt_set(int irq) { From 7a29d5e06d7df8ed221ec02059a285dec48c9a52 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Mon, 18 Mar 2019 15:28:22 +0100 Subject: [PATCH 08/25] interrupt: add a macro to distinguish DSP interrupts Until now cavs/interrupt.c used to call interrupt_get_parent() where it had to verify whether an interrupt was a DSP interrupt or a cascaded one. That function is rather heavy - it takes a spin-lock, scans a list of all cascading interrupt controllers and checks their interrupt numbers. Whereas that check can be performed much easier and faster by simply checking the "level" field of the IRQ token. Signed-off-by: Guennadi Liakhovetski --- src/drivers/intel/cavs/interrupt.c | 4 ++-- src/include/sof/drivers/interrupt.h | 6 ++++++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/drivers/intel/cavs/interrupt.c b/src/drivers/intel/cavs/interrupt.c index c9dc8b083f1d..17460f764efc 100644 --- a/src/drivers/intel/cavs/interrupt.c +++ b/src/drivers/intel/cavs/interrupt.c @@ -212,13 +212,13 @@ void platform_interrupt_unmask(uint32_t irq) void platform_interrupt_set(uint32_t irq) { - if (!platform_irq_get_parent(irq)) + if (interrupt_is_dsp_direct(irq)) arch_interrupt_set(SOF_IRQ_NUMBER(irq)); } void platform_interrupt_clear(uint32_t irq, uint32_t mask) { - if (!platform_irq_get_parent(irq)) + if (interrupt_is_dsp_direct(irq)) arch_interrupt_clear(SOF_IRQ_NUMBER(irq)); } diff --git a/src/include/sof/drivers/interrupt.h b/src/include/sof/drivers/interrupt.h index 7741a03e2061..48dc56400821 100644 --- a/src/include/sof/drivers/interrupt.h +++ b/src/include/sof/drivers/interrupt.h @@ -69,6 +69,12 @@ uint32_t platform_interrupt_get_enabled(void); void platform_interrupt_mask(uint32_t irq); void platform_interrupt_unmask(uint32_t irq); +/* + * On platforms, supporting cascading interrupts cascaded interrupt numbers + * have SOF_IRQ_LEVEL(irq) != 0. + */ +#define interrupt_is_dsp_direct(irq) (!SOF_IRQ_LEVEL(irq)) + static inline void interrupt_set(int irq) { platform_interrupt_set(irq); From 6f27cbeeab7aef20209c4076bb591f29090e7ba4 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Thu, 21 Feb 2019 15:36:28 +0100 Subject: [PATCH 09/25] interrupt: introduce a list of interrupt controllers Add a list of interrupt controllers, that will be allocated at run-time from non-cacheable memory, and functions to perform such a registration and to search through the list. Signed-off-by: Guennadi Liakhovetski --- src/drivers/interrupt.c | 83 +++++++++++++++++++++++++++++ src/include/sof/drivers/interrupt.h | 16 ++++++ src/init/init.c | 3 ++ 3 files changed, 102 insertions(+) diff --git a/src/drivers/interrupt.c b/src/drivers/interrupt.c index 12a16f956117..aa430b90342e 100644 --- a/src/drivers/interrupt.c +++ b/src/drivers/interrupt.c @@ -17,6 +17,89 @@ #include #include +static spinlock_t cascade_lock; +static union { + struct irq_cascade_desc *list __aligned(PLATFORM_DCACHE_ALIGN); + uint8_t bytes[PLATFORM_DCACHE_ALIGN]; +} cascade_root; + +int interrupt_cascade_register(const struct irq_cascade_tmpl *tmpl) +{ + struct irq_cascade_desc **cascade; + unsigned long flags; + unsigned int i; + int ret; + + if (!tmpl->name) + return -EINVAL; + + spin_lock_irq(&cascade_lock, flags); + + dcache_invalidate_region(&cascade_root, sizeof(cascade_root)); + + for (cascade = &cascade_root.list; *cascade; + cascade = &(*cascade)->next) { + if (!rstrcmp((*cascade)->name, tmpl->name)) { + ret = -EEXIST; + trace_error(TRACE_CLASS_IRQ, + "error: cascading IRQ controller name duplication!"); + goto unlock; + } + } + + *cascade = rmalloc(RZONE_SYS | RZONE_FLAG_UNCACHED, SOF_MEM_CAPS_RAM, + sizeof(**cascade)); + + spinlock_init(&(*cascade)->lock); + for (i = 0; i < PLATFORM_IRQ_CHILDREN; i++) + list_init(&(*cascade)->child[i]); + + (*cascade)->name = tmpl->name; + (*cascade)->desc.irq = tmpl->irq; + (*cascade)->desc.handler = tmpl->handler; + (*cascade)->desc.handler_arg = &(*cascade)->desc; + + if (cascade == &cascade_root.list) + /* First descriptor */ + dcache_writeback_region(&cascade_root, sizeof(cascade_root)); + + ret = 0; + +unlock: + spin_unlock_irq(&cascade_lock, flags); + + return ret; +} + +struct irq_desc *interrupt_get_parent(uint32_t irq) +{ + struct irq_cascade_desc *cascade; + struct irq_desc *parent = NULL; + unsigned long flags; + + if (irq < PLATFORM_IRQ_CHILDREN) + return NULL; + + spin_lock_irq(&cascade_lock, flags); + + dcache_invalidate_region(&cascade_root, sizeof(cascade_root)); + + for (cascade = cascade_root.list; cascade; cascade = cascade->next) + if (SOF_IRQ_NUMBER(irq) == cascade->desc.irq) { + parent = &cascade->desc; + break; + } + + spin_unlock_irq(&cascade_lock, flags); + + return parent; +} + +void interrupt_init(void) +{ + spinlock_init(&cascade_lock); +} + static int irq_register_child(struct irq_desc *parent, int irq, int unmask, void (*handler)(void *arg), void *arg) { diff --git a/src/include/sof/drivers/interrupt.h b/src/include/sof/drivers/interrupt.h index 48dc56400821..093ea75c55ac 100644 --- a/src/include/sof/drivers/interrupt.h +++ b/src/include/sof/drivers/interrupt.h @@ -45,15 +45,27 @@ struct irq_desc { /* A descriptor for cascading interrupt controllers */ struct irq_cascade_desc { + const char *name; + /* the interrupt, that this controller is generating */ struct irq_desc desc; + /* to link to the global list of interrupt controllers */ + struct irq_cascade_desc *next; + /* protect child lists in the below array */ spinlock_t lock; uint32_t num_children; struct list_item child[PLATFORM_IRQ_CHILDREN]; }; +/* A descriptor for cascading interrupt controller template */ +struct irq_cascade_tmpl { + const char *name; + int irq; + void (*handler)(void *arg); +}; + int interrupt_register(uint32_t irq, int unmask, void(*handler)(void *arg), void *arg); void interrupt_unregister(uint32_t irq, const void *arg); @@ -75,6 +87,10 @@ void platform_interrupt_unmask(uint32_t irq); */ #define interrupt_is_dsp_direct(irq) (!SOF_IRQ_LEVEL(irq)) +void interrupt_init(void); +int interrupt_cascade_register(const struct irq_cascade_tmpl *tmpl); +struct irq_desc *interrupt_get_parent(uint32_t irq); + static inline void interrupt_set(int irq) { platform_interrupt_set(irq); diff --git a/src/init/init.c b/src/init/init.c index b513ae40902a..81dfb5b6c12c 100644 --- a/src/init/init.c +++ b/src/init/init.c @@ -10,6 +10,7 @@ */ #include +#include #include #include #include @@ -29,6 +30,8 @@ int master_core_init(struct sof *sof) { int err; + interrupt_init(); + /* init architecture */ trace_point(TRACE_BOOT_ARCH); err = arch_init(sof); From e7873b62ce45492e15bdc3ff6e68c607e9969c64 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Tue, 26 Feb 2019 18:28:33 +0100 Subject: [PATCH 10/25] cavs: optimise the interrupt handler Instead of checking one bit at a time, use ffs() to only handle set bits in the interrupt status. Also fix the unhandled interrupt detection logic: complain only if no handler has been found for a given interrupt. Signed-off-by: Guennadi Liakhovetski --- src/drivers/intel/cavs/interrupt.c | 70 +++++++++++++++--------------- src/include/sof/common.h | 2 + 2 files changed, 38 insertions(+), 34 deletions(-) diff --git a/src/drivers/intel/cavs/interrupt.c b/src/drivers/intel/cavs/interrupt.c index 17460f764efc..6c2c437a50a3 100644 --- a/src/drivers/intel/cavs/interrupt.c +++ b/src/drivers/intel/cavs/interrupt.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include @@ -31,60 +32,61 @@ 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 *parent = data; struct irq_cascade_desc *cascade = container_of(parent, struct irq_cascade_desc, desc); struct irq_desc *child = NULL; struct list_item *clist; uint32_t status; - uint32_t i = 0; uint32_t tries = LVL2_MAX_TRIES; /* read active interrupt status */ status = irq_read(ilxsd); + if (!status) + return; /* handle each child */ - while (irq_read(ilxsd)) { + for (;;) { + unsigned int bit = ffs(status) - 1; + bool handled = false; - /* are all IRQs serviced from last status ? */ - if (status == 0x0) { - /* yes, so reload the new status and service again */ - status = irq_read(ilxsd); - i = 0; - tries--; - } - - /* any devices continually interrupting / can't be cleared ? */ - if (!tries) { - tries = LVL2_MAX_TRIES; - trace_irq_error("irq_lvl2_handler() error: " - "IRQ storm at level %d status %08X", - level, irq_read(ilxsd)); - } - - /* any IRQ for this child bit ? */ - if ((status & 0x1) == 0) - goto next; + status &= ~(1 << bit); /* get child if any and run handler */ - list_for_item(clist, &cascade->child[i]) { + list_for_item(clist, &cascade->child[bit]) { child = container_of(clist, struct irq_desc, irq_list); - if (child && child->handler) { + if (child->handler) { child->handler(child->handler_arg); - } else { - /* nobody cared ? */ - trace_irq_error("irq_lvl2_handler() error: " - "nobody cared level %d bit %d", - level, i); - /* now mask it */ - irq_write(ilxmcd, 0x1 << i); + handled = true; } } -next: - status >>= 1; - i++; + if (!handled) { + /* nobody cared ? */ + trace_irq_error("irq_lvl2_handler() error: " + "nobody cared level %d bit %d", + level, bit); + /* now mask it */ + irq_write(ilxmcd, 0x1 << bit); + } + + /* are all IRQs serviced from last status ? */ + if (status) + continue; + + /* yes, so reload the new status and service again */ + status = irq_read(ilxsd); + if (!status) + break; + + /* any devices continually interrupting / can't be cleared ? */ + if (!--tries) { + tries = LVL2_MAX_TRIES; + trace_irq_error("irq_lvl2_handler() error: " + "IRQ storm at level %d status %08X", + level, irq_read(ilxsd)); + } } } diff --git a/src/include/sof/common.h b/src/include/sof/common.h index 61fa8ecb80bf..23c59a44bb6e 100644 --- a/src/include/sof/common.h +++ b/src/include/sof/common.h @@ -29,6 +29,8 @@ #define __aligned(x) __attribute__((__aligned__(x))) +#define ffs(i) __builtin_ffs(i) + /* count number of var args */ #define PP_NARG(...) (sizeof((unsigned int[]){0, ##__VA_ARGS__}) \ / sizeof(unsigned int) - 1) From 1a002f8f54e3902361974a0d98d4e5dc3e757f85 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Fri, 12 Jul 2019 13:19:07 +0200 Subject: [PATCH 11/25] cavs: fix wrong interrupt masking To mask an interrupt ILMXSD has to be written, not ILXMCD. Signed-off-by: Guennadi Liakhovetski --- src/drivers/intel/cavs/interrupt.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/drivers/intel/cavs/interrupt.c b/src/drivers/intel/cavs/interrupt.c index 6c2c437a50a3..b65f4cd53eed 100644 --- a/src/drivers/intel/cavs/interrupt.c +++ b/src/drivers/intel/cavs/interrupt.c @@ -30,7 +30,7 @@ * same time then they are serviced in order of ascending status bit. */ static inline void irq_lvl2_handler(void *data, int level, uint32_t ilxsd, - uint32_t ilxmsd, uint32_t ilxmcd) + uint32_t ilxmsd) { struct irq_desc *parent = data; struct irq_cascade_desc *cascade = container_of(parent, @@ -68,7 +68,7 @@ static inline void irq_lvl2_handler(void *data, int level, uint32_t ilxsd, "nobody cared level %d bit %d", level, bit); /* now mask it */ - irq_write(ilxmcd, 0x1 << bit); + irq_write(ilxmsd, 0x1 << bit); } /* are all IRQs serviced from last status ? */ @@ -94,8 +94,7 @@ static inline void irq_lvl2_handler(void *data, int level, uint32_t ilxsd, irq_lvl2_handler(data, \ IRQ_NUM_EXT_LEVEL##n, \ REG_IRQ_IL##n##SD(core), \ - REG_IRQ_IL##n##MSD(core), \ - REG_IRQ_IL##n##MCD(core)) + REG_IRQ_IL##n##MSD(core)) static void irq_lvl2_level2_handler(void *data) { From b6198cd07ec5bb6e5258c34333277af919918525 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Tue, 12 Feb 2019 15:27:12 +0100 Subject: [PATCH 12/25] cavs: eliminate per-core interrupt controller descriptors Currently cascading interrupt controller descriptors are registered per core. This works well with Xtensa's "levelN" IRQ controllers because their child interrupt lines can be masked per core. However generic interrupt controllers do not have such a capability, which makes registering them per core meaningless and error-prone. Switch over to global IRQ descriptors, allocating them from non-cacheable memory to avoid having to manually synchronise them at run-time. Signed-off-by: Guennadi Liakhovetski --- src/drivers/imx/interrupt.c | 6 -- src/drivers/intel/baytrail/interrupt.c | 6 -- src/drivers/intel/cavs/interrupt.c | 90 ++++++++--------- src/drivers/intel/haswell/interrupt.c | 7 -- src/drivers/interrupt.c | 130 ++++++++++++------------- src/include/sof/drivers/interrupt.h | 28 ++++-- 6 files changed, 126 insertions(+), 141 deletions(-) diff --git a/src/drivers/imx/interrupt.c b/src/drivers/imx/interrupt.c index 035d39b182a8..b8c63f99eff6 100644 --- a/src/drivers/imx/interrupt.c +++ b/src/drivers/imx/interrupt.c @@ -5,16 +5,10 @@ // Author: Daniel Baluta #include -#include #include void platform_interrupt_init(void) {} -struct irq_desc *platform_irq_get_parent(uint32_t irq) -{ - return NULL; -} - void platform_interrupt_set(uint32_t irq) { arch_interrupt_set(irq); diff --git a/src/drivers/intel/baytrail/interrupt.c b/src/drivers/intel/baytrail/interrupt.c index 50a6ac79f27b..154d166dc99b 100644 --- a/src/drivers/intel/baytrail/interrupt.c +++ b/src/drivers/intel/baytrail/interrupt.c @@ -8,16 +8,10 @@ #include #include -#include #include void platform_interrupt_init(void) {} -struct irq_desc *platform_irq_get_parent(uint32_t irq) -{ - return NULL; -} - void platform_interrupt_set(uint32_t irq) { arch_interrupt_set(irq); diff --git a/src/drivers/intel/cavs/interrupt.c b/src/drivers/intel/cavs/interrupt.c index b65f4cd53eed..290f897f5a55 100644 --- a/src/drivers/intel/cavs/interrupt.c +++ b/src/drivers/intel/cavs/interrupt.c @@ -24,6 +24,11 @@ */ #define LVL2_MAX_TRIES 1000 +char irq_name_level2[] = "level2"; +char irq_name_level3[] = "level3"; +char irq_name_level4[] = "level4"; +char irq_name_level5[] = "level5"; + /* * The level2 handler attempts to try and fairly service interrupt sources by * servicing on first come first served basis. If two or more IRQs arrive at the @@ -36,6 +41,7 @@ static inline void irq_lvl2_handler(void *data, int level, uint32_t ilxsd, struct irq_cascade_desc *cascade = container_of(parent, struct irq_cascade_desc, desc); struct irq_desc *child = NULL; + int core = cpu_get_id(); struct list_item *clist; uint32_t status; uint32_t tries = LVL2_MAX_TRIES; @@ -52,16 +58,20 @@ static inline void irq_lvl2_handler(void *data, int level, uint32_t ilxsd, status &= ~(1 << bit); + spin_lock(&cascade->lock); + /* get child if any and run handler */ - list_for_item(clist, &cascade->child[bit]) { + list_for_item(clist, &cascade->child[bit].list) { child = container_of(clist, struct irq_desc, irq_list); - if (child->handler) { + if (child->handler && (child->cpu_mask & 1 << core)) { child->handler(child->handler_arg); handled = true; } } + spin_unlock(&cascade->lock); + if (!handled) { /* nobody cared ? */ trace_irq_error("irq_lvl2_handler() error: " @@ -117,49 +127,30 @@ static void irq_lvl2_level5_handler(void *data) } /* DSP internal interrupts */ -static struct irq_cascade_desc dsp_irq[PLATFORM_CORE_COUNT][4] = { - {{.desc = {IRQ_NUM_EXT_LEVEL2, irq_lvl2_level2_handler, },}, - {.desc = {IRQ_NUM_EXT_LEVEL3, irq_lvl2_level3_handler, },}, - {.desc = {IRQ_NUM_EXT_LEVEL4, irq_lvl2_level4_handler, },}, - {.desc = {IRQ_NUM_EXT_LEVEL5, irq_lvl2_level5_handler, },} }, -#if PLATFORM_CORE_COUNT > 1 - {{.desc = {IRQ_NUM_EXT_LEVEL2, irq_lvl2_level2_handler, },}, - {.desc = {IRQ_NUM_EXT_LEVEL3, irq_lvl2_level3_handler, },}, - {.desc = {IRQ_NUM_EXT_LEVEL4, irq_lvl2_level4_handler, },}, - {.desc = {IRQ_NUM_EXT_LEVEL5, irq_lvl2_level5_handler, },} }, -#endif -#if PLATFORM_CORE_COUNT > 2 - {{.desc = {IRQ_NUM_EXT_LEVEL2, irq_lvl2_level2_handler, },}, - {.desc = {IRQ_NUM_EXT_LEVEL3, irq_lvl2_level3_handler, },}, - {.desc = {IRQ_NUM_EXT_LEVEL4, irq_lvl2_level4_handler, },}, - {.desc = {IRQ_NUM_EXT_LEVEL5, irq_lvl2_level5_handler, },} }, -#endif -#if PLATFORM_CORE_COUNT > 3 - {{.desc = {IRQ_NUM_EXT_LEVEL2, irq_lvl2_level2_handler, },}, - {.desc = {IRQ_NUM_EXT_LEVEL3, irq_lvl2_level3_handler, },}, - {.desc = {IRQ_NUM_EXT_LEVEL4, irq_lvl2_level4_handler, },}, - {.desc = {IRQ_NUM_EXT_LEVEL5, irq_lvl2_level5_handler, },} }, -#endif +static const struct irq_cascade_tmpl dsp_irq[] = { + { + .name = irq_name_level2, + .irq = IRQ_NUM_EXT_LEVEL2, + .handler = irq_lvl2_level2_handler, + .global_mask = false, + }, { + .name = irq_name_level3, + .irq = IRQ_NUM_EXT_LEVEL3, + .handler = irq_lvl2_level3_handler, + .global_mask = false, + }, { + .name = irq_name_level4, + .irq = IRQ_NUM_EXT_LEVEL4, + .handler = irq_lvl2_level4_handler, + .global_mask = false, + }, { + .name = irq_name_level5, + .irq = IRQ_NUM_EXT_LEVEL5, + .handler = irq_lvl2_level5_handler, + .global_mask = false, + }, }; -struct irq_desc *platform_irq_get_parent(uint32_t irq) -{ - int core = SOF_IRQ_CPU(irq); - - switch (SOF_IRQ_NUMBER(irq)) { - case IRQ_NUM_EXT_LEVEL2: - return &dsp_irq[core][0].desc; - case IRQ_NUM_EXT_LEVEL3: - return &dsp_irq[core][1].desc; - case IRQ_NUM_EXT_LEVEL4: - return &dsp_irq[core][2].desc; - case IRQ_NUM_EXT_LEVEL5: - return &dsp_irq[core][3].desc; - default: - return NULL; - } -} - uint32_t platform_interrupt_get_enabled(void) { return 0; @@ -223,9 +214,10 @@ void platform_interrupt_clear(uint32_t irq, uint32_t mask) arch_interrupt_clear(SOF_IRQ_NUMBER(irq)); } +/* Called on each core: from platform_init() and from slave_core_init() */ void platform_interrupt_init(void) { - int i, j; + int i; int core = cpu_get_id(); /* mask all external IRQs by default */ @@ -234,9 +226,9 @@ void platform_interrupt_init(void) irq_write(REG_IRQ_IL4MSD(core), REG_IRQ_IL4MD_ALL); irq_write(REG_IRQ_IL5MSD(core), REG_IRQ_IL5MD_ALL); - for (i = 0; i < ARRAY_SIZE(dsp_irq[core]); i++) { - spinlock_init(&dsp_irq[core][i].lock); - for (j = 0; j < PLATFORM_IRQ_CHILDREN; j++) - list_init(&dsp_irq[core][i].child[j]); - } + if (core != PLATFORM_MASTER_CORE_ID) + return; + + for (i = 0; i < ARRAY_SIZE(dsp_irq); i++) + interrupt_cascade_register(dsp_irq + i); } diff --git a/src/drivers/intel/haswell/interrupt.c b/src/drivers/intel/haswell/interrupt.c index b85e2268b70d..5d2ff2ba458f 100644 --- a/src/drivers/intel/haswell/interrupt.c +++ b/src/drivers/intel/haswell/interrupt.c @@ -8,17 +8,10 @@ #include #include -#include #include void platform_interrupt_init(void) {} -/* haswell does not support child IRQs */ -struct irq_desc *platform_irq_get_parent(uint32_t irq) -{ - return NULL; -} - void platform_interrupt_set(uint32_t irq) { arch_interrupt_set(irq); diff --git a/src/drivers/interrupt.c b/src/drivers/interrupt.c index aa430b90342e..bc7c4de939fd 100644 --- a/src/drivers/interrupt.c +++ b/src/drivers/interrupt.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -47,17 +48,19 @@ int interrupt_cascade_register(const struct irq_cascade_tmpl *tmpl) } } - *cascade = rmalloc(RZONE_SYS | RZONE_FLAG_UNCACHED, SOF_MEM_CAPS_RAM, + *cascade = rzalloc(RZONE_SYS | RZONE_FLAG_UNCACHED, SOF_MEM_CAPS_RAM, sizeof(**cascade)); spinlock_init(&(*cascade)->lock); for (i = 0; i < PLATFORM_IRQ_CHILDREN; i++) - list_init(&(*cascade)->child[i]); + list_init(&(*cascade)->child[i].list); (*cascade)->name = tmpl->name; + (*cascade)->global_mask = tmpl->global_mask; (*cascade)->desc.irq = tmpl->irq; (*cascade)->desc.handler = tmpl->handler; (*cascade)->desc.handler_arg = &(*cascade)->desc; + (*cascade)->desc.cpu_mask = 1 << cpu_get_id(); if (cascade == &cascade_root.list) /* First descriptor */ @@ -103,19 +106,21 @@ void interrupt_init(void) static int irq_register_child(struct irq_desc *parent, int irq, int unmask, void (*handler)(void *arg), void *arg) { + unsigned int core = cpu_get_id(); int ret = 0; struct irq_desc *child; struct irq_cascade_desc *cascade; - struct list_item *list; + struct list_item *list, *head; if (parent == NULL) return -EINVAL; cascade = container_of(parent, struct irq_cascade_desc, desc); + head = &cascade->child[SOF_IRQ_BIT(irq)].list; spin_lock(&cascade->lock); - list_for_item(list, &cascade->child[SOF_IRQ_BIT(irq)]) { + list_for_item(list, head) { child = container_of(list, struct irq_desc, irq_list); if (child->handler_arg == arg) { @@ -130,29 +135,28 @@ static int irq_register_child(struct irq_desc *parent, int irq, int unmask, /* init child from run-time, may be registered and unregistered * many times at run-time */ - child = rzalloc(RZONE_SYS_RUNTIME, SOF_MEM_CAPS_RAM, - sizeof(struct irq_desc)); + child = rzalloc(RZONE_SYS_RUNTIME | RZONE_FLAG_UNCACHED, + SOF_MEM_CAPS_RAM, sizeof(struct irq_desc)); if (!child) { ret = -ENOMEM; goto finish; } - child->enabled_count = 0; child->handler = handler; child->handler_arg = arg; - child->id = SOF_IRQ_ID(irq); child->unmask = unmask; + child->cpu_mask = 1 << core; - list_item_append(&child->irq_list, &cascade->child[SOF_IRQ_BIT(irq)]); + list_item_append(&child->irq_list, head); - /* do we need to register parent ? */ - if (cascade->num_children == 0) { + /* do we need to register parent on this CPU? */ + if (!cascade->num_children[core]) ret = arch_interrupt_register(parent->irq, parent->handler, parent); - } /* increment number of children */ - cascade->num_children++; + if (!ret) + cascade->num_children[core]++; finish: spin_unlock(&cascade->lock); @@ -163,99 +167,95 @@ static void irq_unregister_child(struct irq_desc *parent, int irq, const void *arg) { struct irq_desc *child; - struct list_item *clist; - struct list_item *tlist; struct irq_cascade_desc *cascade = container_of(parent, struct irq_cascade_desc, desc); + struct list_item *list, *head = &cascade->child[SOF_IRQ_BIT(irq)].list; + unsigned int core = cpu_get_id(); spin_lock(&cascade->lock); /* does child already exist ? */ - if (list_is_empty(&cascade->child[SOF_IRQ_BIT(irq)])) + if (list_is_empty(head)) goto finish; - list_for_item_safe(clist, tlist, &cascade->child[SOF_IRQ_BIT(irq)]) { - child = container_of(clist, struct irq_desc, irq_list); + list_for_item(list, head) { + child = container_of(list, struct irq_desc, irq_list); - if (SOF_IRQ_ID(irq) == child->id) { - if (child->handler_arg != arg) - trace_error(TRACE_CLASS_IRQ, - "error: IRQ 0x%x handler argument mismatch!", - irq); + if (child->handler_arg == arg) { list_item_del(&child->irq_list); - cascade->num_children--; + cascade->num_children[core]--; rfree(child); + + /* + * unregister the root interrupt if this l2 is the last + * registered child. + */ + if (!cascade->num_children[core]) + arch_interrupt_unregister(parent->irq); + + break; } } - /* - * unregister the root interrupt if the this l2 is - * the last registered one. - */ - if (cascade->num_children == 0) - arch_interrupt_unregister(parent->irq); - finish: spin_unlock(&cascade->lock); } static uint32_t irq_enable_child(struct irq_desc *parent, int irq) { - struct irq_desc *child; - struct list_item *clist; struct irq_cascade_desc *cascade = container_of(parent, struct irq_cascade_desc, desc); + unsigned int core = cpu_get_id(); + struct irq_child *child; + unsigned int child_idx; spin_lock(&cascade->lock); - /* enable the parent interrupt */ - if (parent->enabled_count == 0) - arch_interrupt_enable_mask(1 << SOF_IRQ_NUMBER(irq)); + child = cascade->child + SOF_IRQ_BIT(irq); + child_idx = cascade->global_mask ? 0 : core; - list_for_item(clist, &cascade->child[SOF_IRQ_BIT(irq)]) { - child = container_of(clist, struct irq_desc, irq_list); + if (!child->enable_count[child_idx]++) { + /* enable the parent interrupt */ + if (!cascade->enable_count[core]++) + arch_interrupt_enable_mask(1 << SOF_IRQ_NUMBER(irq)); - if ((SOF_IRQ_ID(irq) == child->id) && - !child->enabled_count) { - child->enabled_count = 1; - parent->enabled_count++; - - /* enable the child interrupt */ - platform_interrupt_unmask(irq); - } + /* enable the child interrupt */ + platform_interrupt_unmask(irq); } spin_unlock(&cascade->lock); - return 0; + return 0; } static uint32_t irq_disable_child(struct irq_desc *parent, int irq) { - struct irq_desc *child; - struct list_item *clist; struct irq_cascade_desc *cascade = container_of(parent, struct irq_cascade_desc, desc); + unsigned int core = cpu_get_id(); + struct irq_child *child; + unsigned int child_idx; spin_lock(&cascade->lock); - list_for_item(clist, &cascade->child[SOF_IRQ_BIT(irq)]) { - child = container_of(clist, struct irq_desc, irq_list); + child = cascade->child + SOF_IRQ_BIT(irq); + child_idx = cascade->global_mask ? 0 : core; - if ((SOF_IRQ_ID(irq) == child->id) && - child->enabled_count) { - child->enabled_count = 0; - parent->enabled_count--; + if (!child->enable_count[child_idx]) { + trace_error(TRACE_CLASS_IRQ, + "error: IRQ %x unbalanced interrupt_disable()", + irq); + } else if (!--child->enable_count[child_idx]) { + /* disable the child interrupt */ + platform_interrupt_mask(irq); - /* disable the child interrupt */ - platform_interrupt_mask(irq); - } + /* disable the parent interrupt */ + if (!--cascade->enable_count[core]) + arch_interrupt_disable_mask(1 << SOF_IRQ_NUMBER(irq)); } - if (parent->enabled_count == 0) - arch_interrupt_disable_mask(1 << SOF_IRQ_NUMBER(irq)); - spin_unlock(&cascade->lock); + return 0; } @@ -265,7 +265,7 @@ int interrupt_register(uint32_t irq, int unmask, void (*handler)(void *arg), struct irq_desc *parent; /* no parent means we are registering DSP internal IRQ */ - parent = platform_irq_get_parent(irq); + parent = interrupt_get_parent(irq); if (parent == NULL) return arch_interrupt_register(irq, handler, arg); else @@ -277,7 +277,7 @@ void interrupt_unregister(uint32_t irq, const void *arg) struct irq_desc *parent; /* no parent means we are unregistering DSP internal IRQ */ - parent = platform_irq_get_parent(irq); + parent = interrupt_get_parent(irq); if (parent == NULL) arch_interrupt_unregister(irq); else @@ -289,7 +289,7 @@ uint32_t interrupt_enable(uint32_t irq) struct irq_desc *parent; /* no parent means we are enabling DSP internal IRQ */ - parent = platform_irq_get_parent(irq); + parent = interrupt_get_parent(irq); if (parent == NULL) return arch_interrupt_enable_mask(1 << irq); else @@ -301,7 +301,7 @@ uint32_t interrupt_disable(uint32_t irq) struct irq_desc *parent; /* no parent means we are disabling DSP internal IRQ */ - parent = platform_irq_get_parent(irq); + parent = interrupt_get_parent(irq); if (parent == NULL) return arch_interrupt_disable_mask(1 << irq); else diff --git a/src/include/sof/drivers/interrupt.h b/src/include/sof/drivers/interrupt.h index 093ea75c55ac..dc962826711e 100644 --- a/src/include/sof/drivers/interrupt.h +++ b/src/include/sof/drivers/interrupt.h @@ -11,10 +11,12 @@ #include #include #include +#include #include #include #include #include +#include #include #define trace_irq(__e) trace_event(TRACE_CLASS_IRQ, __e) @@ -24,20 +26,27 @@ #define IRQ_MANUAL_UNMASK 0 #define IRQ_AUTO_UNMASK 1 +/** + * struct irq_child - child IRQ descriptor for cascading IRQ controllers + * + * @enable_count: IRQ enable counter + * @list: head for IRQ descriptors, sharing this interrupt + */ +struct irq_child { + int enable_count[PLATFORM_CORE_COUNT]; + struct list_item list; +}; + struct irq_desc { - /* irq must be first for constructor */ int irq; /* logical IRQ number */ - /* handler is optional for constructor */ void (*handler)(void *arg); void *handler_arg; /* whether irq should be automatically unmasked */ int unmask; - /* to identify interrupt with the same IRQ */ - int id; - uint32_t enabled_count; + uint32_t cpu_mask; /* to link to other irq_desc */ struct list_item irq_list; @@ -53,10 +62,13 @@ struct irq_cascade_desc { /* to link to the global list of interrupt controllers */ struct irq_cascade_desc *next; + bool global_mask; + /* protect child lists in the below array */ spinlock_t lock; - uint32_t num_children; - struct list_item child[PLATFORM_IRQ_CHILDREN]; + int enable_count[PLATFORM_CORE_COUNT]; + unsigned int num_children[PLATFORM_CORE_COUNT]; + struct irq_child child[PLATFORM_IRQ_CHILDREN]; }; /* A descriptor for cascading interrupt controller template */ @@ -64,6 +76,7 @@ struct irq_cascade_tmpl { const char *name; int irq; void (*handler)(void *arg); + bool global_mask; }; int interrupt_register(uint32_t irq, int unmask, void(*handler)(void *arg), @@ -74,7 +87,6 @@ uint32_t interrupt_disable(uint32_t irq); void platform_interrupt_init(void); -struct irq_desc *platform_irq_get_parent(uint32_t irq); void platform_interrupt_set(uint32_t irq); void platform_interrupt_clear(uint32_t irq, uint32_t mask); uint32_t platform_interrupt_get_enabled(void); From 5aa0cc0cd63581ca8b3feb1d89ab969709015dc9 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Thu, 21 Feb 2019 18:05:37 +0100 Subject: [PATCH 13/25] interrupt: add controller mask and unmask operations Add interrupt controller .mask() and .unmask() operations. Use them instead of platform_interrupt_mask() and platform_interrupt_unmask(). Signed-off-by: Guennadi Liakhovetski --- src/arch/xtensa/drivers/idc.c | 2 +- src/drivers/imx/interrupt.c | 4 +- src/drivers/intel/baytrail/interrupt.c | 4 +- src/drivers/intel/cavs/dmic.c | 4 +- src/drivers/intel/cavs/interrupt.c | 89 ++++++++++++++++---------- src/drivers/intel/cavs/timer.c | 4 +- src/drivers/intel/haswell/interrupt.c | 4 +- src/drivers/interrupt.c | 7 +- src/include/sof/drivers/interrupt.h | 75 +++++++++++++++------- 9 files changed, 122 insertions(+), 71 deletions(-) diff --git a/src/arch/xtensa/drivers/idc.c b/src/arch/xtensa/drivers/idc.c index 36259845e75f..6e53d31a7943 100644 --- a/src/arch/xtensa/drivers/idc.c +++ b/src/arch/xtensa/drivers/idc.c @@ -52,7 +52,7 @@ void idc_enable_interrupts(int target_core, int source_core) { idc_write(IPC_IDCCTL, target_core, IPC_IDCCTL_IDCTBIE(source_core)); - platform_interrupt_unmask(PLATFORM_IDC_INTERRUPT(target_core)); + interrupt_unmask(PLATFORM_IDC_INTERRUPT(target_core)); } /** diff --git a/src/drivers/imx/interrupt.c b/src/drivers/imx/interrupt.c index b8c63f99eff6..c6f6e8947398 100644 --- a/src/drivers/imx/interrupt.c +++ b/src/drivers/imx/interrupt.c @@ -24,5 +24,5 @@ uint32_t platform_interrupt_get_enabled(void) return 0; } -void platform_interrupt_mask(uint32_t irq) {} -void platform_interrupt_unmask(uint32_t irq) {} +void interrupt_mask(uint32_t irq) {} +void interrupt_unmask(uint32_t irq) {} diff --git a/src/drivers/intel/baytrail/interrupt.c b/src/drivers/intel/baytrail/interrupt.c index 154d166dc99b..88ebb4d5c4d5 100644 --- a/src/drivers/intel/baytrail/interrupt.c +++ b/src/drivers/intel/baytrail/interrupt.c @@ -78,7 +78,7 @@ uint32_t platform_interrupt_get_enabled(void) return shim_read(SHIM_PIMR); } -void platform_interrupt_mask(uint32_t irq) +void interrupt_mask(uint32_t irq) { switch (irq) { case IRQ_NUM_EXT_SSP0: @@ -115,7 +115,7 @@ void platform_interrupt_mask(uint32_t irq) } } -void platform_interrupt_unmask(uint32_t irq) +void interrupt_unmask(uint32_t irq) { switch (irq) { case IRQ_NUM_EXT_SSP0: diff --git a/src/drivers/intel/cavs/dmic.c b/src/drivers/intel/cavs/dmic.c index fdec691f7ca2..5aba135a1c9c 100644 --- a/src/drivers/intel/cavs/dmic.c +++ b/src/drivers/intel/cavs/dmic.c @@ -1537,7 +1537,7 @@ static int dmic_probe(struct dai *dai) /* Disable dynamic clock gating for dmic before touching any reg */ pm_runtime_get_sync(DMIC_CLK, dai->index); - platform_interrupt_unmask(dmic_irq(dai)); + interrupt_unmask(dmic_irq(dai)); interrupt_enable(dmic_irq(dai)); return 0; @@ -1548,7 +1548,7 @@ static int dmic_remove(struct dai *dai) int i; interrupt_disable(dmic_irq(dai)); - platform_interrupt_mask(dmic_irq(dai)); + interrupt_mask(dmic_irq(dai)); interrupt_unregister(dmic_irq(dai), dai); pm_runtime_put_sync(DMIC_CLK, dai->index); diff --git a/src/drivers/intel/cavs/interrupt.c b/src/drivers/intel/cavs/interrupt.c index 290f897f5a55..0c137f2d05c8 100644 --- a/src/drivers/intel/cavs/interrupt.c +++ b/src/drivers/intel/cavs/interrupt.c @@ -126,42 +126,35 @@ static void irq_lvl2_level5_handler(void *data) IRQ_LVL2_HANDLER(5); } -/* DSP internal interrupts */ -static const struct irq_cascade_tmpl dsp_irq[] = { - { - .name = irq_name_level2, - .irq = IRQ_NUM_EXT_LEVEL2, - .handler = irq_lvl2_level2_handler, - .global_mask = false, - }, { - .name = irq_name_level3, - .irq = IRQ_NUM_EXT_LEVEL3, - .handler = irq_lvl2_level3_handler, - .global_mask = false, - }, { - .name = irq_name_level4, - .irq = IRQ_NUM_EXT_LEVEL4, - .handler = irq_lvl2_level4_handler, - .global_mask = false, - }, { - .name = irq_name_level5, - .irq = IRQ_NUM_EXT_LEVEL5, - .handler = irq_lvl2_level5_handler, - .global_mask = false, - }, -}; - uint32_t platform_interrupt_get_enabled(void) { return 0; } -void platform_interrupt_mask(uint32_t irq) +void interrupt_mask(uint32_t irq) +{ + struct irq_desc *parent = interrupt_get_parent(irq); + struct irq_cascade_desc *cascade = container_of(parent, + struct irq_cascade_desc, desc); + if (parent && cascade->ops->mask) + cascade->ops->mask(parent, irq); +} + +void interrupt_unmask(uint32_t irq) +{ + struct irq_desc *parent = interrupt_get_parent(irq); + struct irq_cascade_desc *cascade = container_of(parent, + struct irq_cascade_desc, desc); + if (parent && cascade->ops->unmask) + cascade->ops->unmask(parent, irq); +} + +static void irq_mask(struct irq_desc *desc, uint32_t irq) { int core = SOF_IRQ_CPU(irq); /* mask external interrupt bit */ - switch (SOF_IRQ_NUMBER(irq)) { + switch (desc->irq) { case IRQ_NUM_EXT_LEVEL5: irq_write(REG_IRQ_IL5MSD(core), 1 << SOF_IRQ_BIT(irq)); break; @@ -174,17 +167,15 @@ void platform_interrupt_mask(uint32_t irq) case IRQ_NUM_EXT_LEVEL2: irq_write(REG_IRQ_IL2MSD(core), 1 << SOF_IRQ_BIT(irq)); break; - default: - break; } } -void platform_interrupt_unmask(uint32_t irq) +static void irq_unmask(struct irq_desc *desc, uint32_t irq) { int core = SOF_IRQ_CPU(irq); /* unmask external interrupt bit */ - switch (SOF_IRQ_NUMBER(irq)) { + switch (desc->irq) { case IRQ_NUM_EXT_LEVEL5: irq_write(REG_IRQ_IL5MCD(core), 1 << SOF_IRQ_BIT(irq)); break; @@ -197,11 +188,43 @@ void platform_interrupt_unmask(uint32_t irq) case IRQ_NUM_EXT_LEVEL2: irq_write(REG_IRQ_IL2MCD(core), 1 << SOF_IRQ_BIT(irq)); break; - default: - break; } } +static const struct irq_cascade_ops irq_ops = { + .mask = irq_mask, + .unmask = irq_unmask, +}; + +/* DSP internal interrupts */ +static const struct irq_cascade_tmpl dsp_irq[] = { + { + .name = irq_name_level2, + .irq = IRQ_NUM_EXT_LEVEL2, + .handler = irq_lvl2_level2_handler, + .ops = &irq_ops, + .global_mask = false, + }, { + .name = irq_name_level3, + .irq = IRQ_NUM_EXT_LEVEL3, + .handler = irq_lvl2_level3_handler, + .ops = &irq_ops, + .global_mask = false, + }, { + .name = irq_name_level4, + .irq = IRQ_NUM_EXT_LEVEL4, + .handler = irq_lvl2_level4_handler, + .ops = &irq_ops, + .global_mask = false, + }, { + .name = irq_name_level5, + .irq = IRQ_NUM_EXT_LEVEL5, + .handler = irq_lvl2_level5_handler, + .ops = &irq_ops, + .global_mask = false, + }, +}; + void platform_interrupt_set(uint32_t irq) { if (interrupt_is_dsp_direct(irq)) diff --git a/src/drivers/intel/cavs/timer.c b/src/drivers/intel/cavs/timer.c index 3b57f85a93b7..7646099cd806 100644 --- a/src/drivers/intel/cavs/timer.c +++ b/src/drivers/intel/cavs/timer.c @@ -170,7 +170,7 @@ void timer_enable(struct timer *timer) interrupt_enable(timer->irq); break; case TIMER3: - platform_interrupt_unmask(timer->irq); + interrupt_unmask(timer->irq); break; } } @@ -184,7 +184,7 @@ void timer_disable(struct timer *timer) interrupt_disable(timer->irq); break; case TIMER3: - platform_interrupt_mask(timer->irq); + interrupt_mask(timer->irq); break; } } diff --git a/src/drivers/intel/haswell/interrupt.c b/src/drivers/intel/haswell/interrupt.c index 5d2ff2ba458f..96c1dbda1ced 100644 --- a/src/drivers/intel/haswell/interrupt.c +++ b/src/drivers/intel/haswell/interrupt.c @@ -41,7 +41,7 @@ uint32_t platform_interrupt_get_enabled(void) return shim_read(SHIM_IMRD); } -void platform_interrupt_mask(uint32_t irq) +void interrupt_mask(uint32_t irq) { switch (irq) { case IRQ_NUM_EXT_SSP0: @@ -61,7 +61,7 @@ void platform_interrupt_mask(uint32_t irq) } } -void platform_interrupt_unmask(uint32_t irq) +void interrupt_unmask(uint32_t irq) { switch (irq) { case IRQ_NUM_EXT_SSP0: diff --git a/src/drivers/interrupt.c b/src/drivers/interrupt.c index bc7c4de939fd..e9eef00df56f 100644 --- a/src/drivers/interrupt.c +++ b/src/drivers/interrupt.c @@ -31,7 +31,7 @@ int interrupt_cascade_register(const struct irq_cascade_tmpl *tmpl) unsigned int i; int ret; - if (!tmpl->name) + if (!tmpl->name || !tmpl->ops) return -EINVAL; spin_lock_irq(&cascade_lock, flags); @@ -56,6 +56,7 @@ int interrupt_cascade_register(const struct irq_cascade_tmpl *tmpl) list_init(&(*cascade)->child[i].list); (*cascade)->name = tmpl->name; + (*cascade)->ops = tmpl->ops; (*cascade)->global_mask = tmpl->global_mask; (*cascade)->desc.irq = tmpl->irq; (*cascade)->desc.handler = tmpl->handler; @@ -220,7 +221,7 @@ static uint32_t irq_enable_child(struct irq_desc *parent, int irq) arch_interrupt_enable_mask(1 << SOF_IRQ_NUMBER(irq)); /* enable the child interrupt */ - platform_interrupt_unmask(irq); + interrupt_unmask(irq); } spin_unlock(&cascade->lock); @@ -247,7 +248,7 @@ static uint32_t irq_disable_child(struct irq_desc *parent, int irq) irq); } else if (!--child->enable_count[child_idx]) { /* disable the child interrupt */ - platform_interrupt_mask(irq); + interrupt_mask(irq); /* disable the parent interrupt */ if (!--cascade->enable_count[core]) diff --git a/src/include/sof/drivers/interrupt.h b/src/include/sof/drivers/interrupt.h index dc962826711e..71a7608eb41b 100644 --- a/src/include/sof/drivers/interrupt.h +++ b/src/include/sof/drivers/interrupt.h @@ -27,14 +27,13 @@ #define IRQ_AUTO_UNMASK 1 /** - * struct irq_child - child IRQ descriptor for cascading IRQ controllers - * - * @enable_count: IRQ enable counter - * @list: head for IRQ descriptors, sharing this interrupt + * \brief child IRQ descriptor for cascading IRQ controllers. */ struct irq_child { - int enable_count[PLATFORM_CORE_COUNT]; - struct list_item list; + int enable_count[PLATFORM_CORE_COUNT]; /**< IRQ enable counter */ + struct list_item list; /**< head for IRQ descriptors, + * sharing this interrupt + */ }; struct irq_desc { @@ -52,28 +51,56 @@ struct irq_desc { struct list_item irq_list; }; -/* A descriptor for cascading interrupt controllers */ -struct irq_cascade_desc { - const char *name; - - /* the interrupt, that this controller is generating */ - struct irq_desc desc; - - /* to link to the global list of interrupt controllers */ - struct irq_cascade_desc *next; - - bool global_mask; +/** + * \brief cascading IRQ controller operations. + */ +struct irq_cascade_ops { + void (*mask)(struct irq_desc *desc, uint32_t irq); /**< mask */ + void (*unmask)(struct irq_desc *desc, uint32_t irq); /**< unmask */ +}; - /* protect child lists in the below array */ - spinlock_t lock; - int enable_count[PLATFORM_CORE_COUNT]; - unsigned int num_children[PLATFORM_CORE_COUNT]; - struct irq_child child[PLATFORM_IRQ_CHILDREN]; +/** + * \brief cascading interrupt controller descriptor. + */ +struct irq_cascade_desc { + const char *name; /**< name of the + * controller + */ + const struct irq_cascade_ops *ops; /**< cascading interrupt + * controller driver + * operations + */ + struct irq_desc desc; /**< the interrupt, that + * this controller is + * generating + */ + struct irq_cascade_desc *next; /**< link to the global + * list of interrupt + * controllers + */ + bool global_mask; /**< the controller + * cannot mask input + * interrupts per core + */ + spinlock_t lock; /**< protect child + * lists, enable and + * child counters + */ + int enable_count[PLATFORM_CORE_COUNT]; /**< enabled child + * interrupt counter + */ + unsigned int num_children[PLATFORM_CORE_COUNT]; /**< number of children + */ + struct irq_child child[PLATFORM_IRQ_CHILDREN]; /**< array of child + * lists - one per + * multiplexed IRQ + */ }; /* A descriptor for cascading interrupt controller template */ struct irq_cascade_tmpl { const char *name; + const struct irq_cascade_ops *ops; int irq; void (*handler)(void *arg); bool global_mask; @@ -90,8 +117,8 @@ void platform_interrupt_init(void); void platform_interrupt_set(uint32_t irq); void platform_interrupt_clear(uint32_t irq, uint32_t mask); uint32_t platform_interrupt_get_enabled(void); -void platform_interrupt_mask(uint32_t irq); -void platform_interrupt_unmask(uint32_t irq); +void interrupt_mask(uint32_t irq); +void interrupt_unmask(uint32_t irq); /* * On platforms, supporting cascading interrupts cascaded interrupt numbers From 0af63ecc411bf3aad217cccdbf1c67439ac8ed01 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Fri, 22 Feb 2019 10:16:58 +0100 Subject: [PATCH 14/25] interrupt: add a cpu argument to interrupt_(un)mask() Most interrupts in SOF are handled completely locally: they are registered, enabled, disabled, and handled on one and the same core. There is only one case, where interrupts have to be unmasked on a different core: in idc_enable_interrupts(). To make this possible without using the CPU field in the IRQ bitfield we add a "cpu" argument to interrupt_mask() and interrupt_unmask() functions. Signed-off-by: Guennadi Liakhovetski --- src/arch/xtensa/drivers/idc.c | 2 +- src/drivers/imx/interrupt.c | 4 ++-- src/drivers/intel/baytrail/interrupt.c | 4 ++-- src/drivers/intel/cavs/dmic.c | 14 ++++++++------ src/drivers/intel/cavs/interrupt.c | 16 ++++++---------- src/drivers/intel/cavs/timer.c | 4 ++-- src/drivers/intel/haswell/interrupt.c | 4 ++-- src/drivers/interrupt.c | 4 ++-- src/include/sof/drivers/interrupt.h | 10 ++++++---- 9 files changed, 31 insertions(+), 31 deletions(-) diff --git a/src/arch/xtensa/drivers/idc.c b/src/arch/xtensa/drivers/idc.c index 6e53d31a7943..d9c540197138 100644 --- a/src/arch/xtensa/drivers/idc.c +++ b/src/arch/xtensa/drivers/idc.c @@ -52,7 +52,7 @@ void idc_enable_interrupts(int target_core, int source_core) { idc_write(IPC_IDCCTL, target_core, IPC_IDCCTL_IDCTBIE(source_core)); - interrupt_unmask(PLATFORM_IDC_INTERRUPT(target_core)); + interrupt_unmask(PLATFORM_IDC_INTERRUPT(target_core), target_core); } /** diff --git a/src/drivers/imx/interrupt.c b/src/drivers/imx/interrupt.c index c6f6e8947398..023c22e53619 100644 --- a/src/drivers/imx/interrupt.c +++ b/src/drivers/imx/interrupt.c @@ -24,5 +24,5 @@ uint32_t platform_interrupt_get_enabled(void) return 0; } -void interrupt_mask(uint32_t irq) {} -void interrupt_unmask(uint32_t irq) {} +void interrupt_mask(uint32_t irq, unsigned int cpu) {} +void interrupt_unmask(uint32_t irq, unsigned int cpu) {} diff --git a/src/drivers/intel/baytrail/interrupt.c b/src/drivers/intel/baytrail/interrupt.c index 88ebb4d5c4d5..35b433cbdefe 100644 --- a/src/drivers/intel/baytrail/interrupt.c +++ b/src/drivers/intel/baytrail/interrupt.c @@ -78,7 +78,7 @@ uint32_t platform_interrupt_get_enabled(void) return shim_read(SHIM_PIMR); } -void interrupt_mask(uint32_t irq) +void interrupt_mask(uint32_t irq, unsigned int cpu) { switch (irq) { case IRQ_NUM_EXT_SSP0: @@ -115,7 +115,7 @@ void interrupt_mask(uint32_t irq) } } -void interrupt_unmask(uint32_t irq) +void interrupt_unmask(uint32_t irq, unsigned int cpu) { switch (irq) { case IRQ_NUM_EXT_SSP0: diff --git a/src/drivers/intel/cavs/dmic.c b/src/drivers/intel/cavs/dmic.c index 5aba135a1c9c..3a7da9c4c4ea 100644 --- a/src/drivers/intel/cavs/dmic.c +++ b/src/drivers/intel/cavs/dmic.c @@ -1503,6 +1503,7 @@ static void dmic_irq_handler(void *data) static int dmic_probe(struct dai *dai) { + int irq = dmic_irq(dai); struct dmic_pdata *dmic; int ret; @@ -1524,7 +1525,7 @@ static int dmic_probe(struct dai *dai) dmic->state = COMP_STATE_READY; /* register our IRQ handler */ - ret = interrupt_register(dmic_irq(dai), IRQ_AUTO_UNMASK, + ret = interrupt_register(irq, IRQ_AUTO_UNMASK, dmic_irq_handler, dai); if (ret < 0) { trace_dmic_error("dmic failed to allocate IRQ"); @@ -1537,19 +1538,20 @@ static int dmic_probe(struct dai *dai) /* Disable dynamic clock gating for dmic before touching any reg */ pm_runtime_get_sync(DMIC_CLK, dai->index); - interrupt_unmask(dmic_irq(dai)); - interrupt_enable(dmic_irq(dai)); + interrupt_unmask(irq, SOF_IRQ_CPU(irq)); + interrupt_enable(irq); return 0; } static int dmic_remove(struct dai *dai) { + int irq = dmic_irq(dai); int i; - interrupt_disable(dmic_irq(dai)); - interrupt_mask(dmic_irq(dai)); - interrupt_unregister(dmic_irq(dai), dai); + interrupt_disable(irq); + interrupt_mask(irq, SOF_IRQ_CPU(irq)); + interrupt_unregister(irq, dai); pm_runtime_put_sync(DMIC_CLK, dai->index); /* Disable DMIC power */ diff --git a/src/drivers/intel/cavs/interrupt.c b/src/drivers/intel/cavs/interrupt.c index 0c137f2d05c8..55c52b296ebe 100644 --- a/src/drivers/intel/cavs/interrupt.c +++ b/src/drivers/intel/cavs/interrupt.c @@ -131,28 +131,26 @@ uint32_t platform_interrupt_get_enabled(void) return 0; } -void interrupt_mask(uint32_t irq) +void interrupt_mask(uint32_t irq, unsigned int cpu) { struct irq_desc *parent = interrupt_get_parent(irq); struct irq_cascade_desc *cascade = container_of(parent, struct irq_cascade_desc, desc); if (parent && cascade->ops->mask) - cascade->ops->mask(parent, irq); + cascade->ops->mask(parent, irq, cpu); } -void interrupt_unmask(uint32_t irq) +void interrupt_unmask(uint32_t irq, unsigned int cpu) { struct irq_desc *parent = interrupt_get_parent(irq); struct irq_cascade_desc *cascade = container_of(parent, struct irq_cascade_desc, desc); if (parent && cascade->ops->unmask) - cascade->ops->unmask(parent, irq); + cascade->ops->unmask(parent, irq, cpu); } -static void irq_mask(struct irq_desc *desc, uint32_t irq) +static void irq_mask(struct irq_desc *desc, uint32_t irq, unsigned int core) { - int core = SOF_IRQ_CPU(irq); - /* mask external interrupt bit */ switch (desc->irq) { case IRQ_NUM_EXT_LEVEL5: @@ -170,10 +168,8 @@ static void irq_mask(struct irq_desc *desc, uint32_t irq) } } -static void irq_unmask(struct irq_desc *desc, uint32_t irq) +static void irq_unmask(struct irq_desc *desc, uint32_t irq, unsigned int core) { - int core = SOF_IRQ_CPU(irq); - /* unmask external interrupt bit */ switch (desc->irq) { case IRQ_NUM_EXT_LEVEL5: diff --git a/src/drivers/intel/cavs/timer.c b/src/drivers/intel/cavs/timer.c index 7646099cd806..6b18e24f1729 100644 --- a/src/drivers/intel/cavs/timer.c +++ b/src/drivers/intel/cavs/timer.c @@ -170,7 +170,7 @@ void timer_enable(struct timer *timer) interrupt_enable(timer->irq); break; case TIMER3: - interrupt_unmask(timer->irq); + interrupt_unmask(timer->irq, SOF_IRQ_CPU(timer->irq)); break; } } @@ -184,7 +184,7 @@ void timer_disable(struct timer *timer) interrupt_disable(timer->irq); break; case TIMER3: - interrupt_mask(timer->irq); + interrupt_mask(timer->irq, SOF_IRQ_CPU(timer->irq)); break; } } diff --git a/src/drivers/intel/haswell/interrupt.c b/src/drivers/intel/haswell/interrupt.c index 96c1dbda1ced..aa76f5f1721b 100644 --- a/src/drivers/intel/haswell/interrupt.c +++ b/src/drivers/intel/haswell/interrupt.c @@ -41,7 +41,7 @@ uint32_t platform_interrupt_get_enabled(void) return shim_read(SHIM_IMRD); } -void interrupt_mask(uint32_t irq) +void interrupt_mask(uint32_t irq, unsigned int cpu) { switch (irq) { case IRQ_NUM_EXT_SSP0: @@ -61,7 +61,7 @@ void interrupt_mask(uint32_t irq) } } -void interrupt_unmask(uint32_t irq) +void interrupt_unmask(uint32_t irq, unsigned int cpu) { switch (irq) { case IRQ_NUM_EXT_SSP0: diff --git a/src/drivers/interrupt.c b/src/drivers/interrupt.c index e9eef00df56f..f054f9405df7 100644 --- a/src/drivers/interrupt.c +++ b/src/drivers/interrupt.c @@ -221,7 +221,7 @@ static uint32_t irq_enable_child(struct irq_desc *parent, int irq) arch_interrupt_enable_mask(1 << SOF_IRQ_NUMBER(irq)); /* enable the child interrupt */ - interrupt_unmask(irq); + interrupt_unmask(irq, core); } spin_unlock(&cascade->lock); @@ -248,7 +248,7 @@ static uint32_t irq_disable_child(struct irq_desc *parent, int irq) irq); } else if (!--child->enable_count[child_idx]) { /* disable the child interrupt */ - interrupt_mask(irq); + interrupt_mask(irq, core); /* disable the parent interrupt */ if (!--cascade->enable_count[core]) diff --git a/src/include/sof/drivers/interrupt.h b/src/include/sof/drivers/interrupt.h index 71a7608eb41b..db1fc2130f8e 100644 --- a/src/include/sof/drivers/interrupt.h +++ b/src/include/sof/drivers/interrupt.h @@ -55,8 +55,10 @@ struct irq_desc { * \brief cascading IRQ controller operations. */ struct irq_cascade_ops { - void (*mask)(struct irq_desc *desc, uint32_t irq); /**< mask */ - void (*unmask)(struct irq_desc *desc, uint32_t irq); /**< unmask */ + void (*mask)(struct irq_desc *desc, uint32_t irq, + unsigned int cpu); /**< mask */ + void (*unmask)(struct irq_desc *desc, uint32_t irq, + unsigned int cpu); /**< unmask */ }; /** @@ -117,8 +119,8 @@ void platform_interrupt_init(void); void platform_interrupt_set(uint32_t irq); void platform_interrupt_clear(uint32_t irq, uint32_t mask); uint32_t platform_interrupt_get_enabled(void); -void interrupt_mask(uint32_t irq); -void interrupt_unmask(uint32_t irq); +void interrupt_mask(uint32_t irq, unsigned int cpu); +void interrupt_unmask(uint32_t irq, unsigned int cpu); /* * On platforms, supporting cascading interrupts cascaded interrupt numbers From 30c7bf9afe8db62ecd46330add5961f25818d712 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Tue, 30 Apr 2019 11:22:57 +0200 Subject: [PATCH 15/25] interrupt: stop using SOF_IRQ_CPU() The only two uses of SOF_IRQ_CPU() are currently in irq_mask() and irq_unmask() on cAVS. However, those functions are always called after interrupt_get_parent(), which makes sure, that the CPU, encoded into the IRQ is the same as the current one. Therefore we can also just use the current CPU in irq_mask() and irq_unmask(). Signed-off-by: Guennadi Liakhovetski --- src/arch/xtensa/include/arch/drivers/timer.h | 1 + src/drivers/intel/cavs/dmic.c | 4 ++-- src/drivers/intel/cavs/timer.c | 4 ++-- src/platform/intel/cavs/platform.c | 4 ++++ 4 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/arch/xtensa/include/arch/drivers/timer.h b/src/arch/xtensa/include/arch/drivers/timer.h index 20e1defbf182..e4a1f77c95a5 100644 --- a/src/arch/xtensa/include/arch/drivers/timer.h +++ b/src/arch/xtensa/include/arch/drivers/timer.h @@ -16,6 +16,7 @@ struct timer { uint32_t id; uint32_t irq; + uint32_t core; void *irq_arg; void *timer_data; /* used by core */ uint32_t hitime; /* high end of 64bit timer */ diff --git a/src/drivers/intel/cavs/dmic.c b/src/drivers/intel/cavs/dmic.c index 3a7da9c4c4ea..062bb8e16c2d 100644 --- a/src/drivers/intel/cavs/dmic.c +++ b/src/drivers/intel/cavs/dmic.c @@ -1538,7 +1538,7 @@ static int dmic_probe(struct dai *dai) /* Disable dynamic clock gating for dmic before touching any reg */ pm_runtime_get_sync(DMIC_CLK, dai->index); - interrupt_unmask(irq, SOF_IRQ_CPU(irq)); + interrupt_unmask(irq, cpu_get_id()); interrupt_enable(irq); return 0; @@ -1550,7 +1550,7 @@ static int dmic_remove(struct dai *dai) int i; interrupt_disable(irq); - interrupt_mask(irq, SOF_IRQ_CPU(irq)); + interrupt_mask(irq, cpu_get_id()); interrupt_unregister(irq, dai); pm_runtime_put_sync(DMIC_CLK, dai->index); diff --git a/src/drivers/intel/cavs/timer.c b/src/drivers/intel/cavs/timer.c index 6b18e24f1729..b0640437c5ce 100644 --- a/src/drivers/intel/cavs/timer.c +++ b/src/drivers/intel/cavs/timer.c @@ -170,7 +170,7 @@ void timer_enable(struct timer *timer) interrupt_enable(timer->irq); break; case TIMER3: - interrupt_unmask(timer->irq, SOF_IRQ_CPU(timer->irq)); + interrupt_unmask(timer->irq, timer->core); break; } } @@ -184,7 +184,7 @@ void timer_disable(struct timer *timer) interrupt_disable(timer->irq); break; case TIMER3: - interrupt_mask(timer->irq, SOF_IRQ_CPU(timer->irq)); + interrupt_mask(timer->irq, timer->core); break; } } diff --git a/src/platform/intel/cavs/platform.c b/src/platform/intel/cavs/platform.c index 90ba5ea2b031..88d45bfe7c58 100644 --- a/src/platform/intel/cavs/platform.c +++ b/src/platform/intel/cavs/platform.c @@ -131,6 +131,7 @@ struct timesource_data platform_generic_queue[] = { .timer = { .id = TIMER3, /* external timer */ .irq = IRQ_EXT_TSTAMP0_LVL2(0), + .core = 0, }, .clk = CLK_SSP, .notifier = NOTIFIER_ID_SSP_FREQ, @@ -142,6 +143,7 @@ struct timesource_data platform_generic_queue[] = { .timer = { .id = TIMER3, /* external timer */ .irq = IRQ_EXT_TSTAMP0_LVL2(1), + .core = 1, }, .clk = CLK_SSP, .notifier = NOTIFIER_ID_SSP_FREQ, @@ -154,6 +156,7 @@ struct timesource_data platform_generic_queue[] = { .timer = { .id = TIMER3, /* external timer */ .irq = IRQ_EXT_TSTAMP0_LVL2(2), + .core = 2, }, .clk = CLK_SSP, .notifier = NOTIFIER_ID_SSP_FREQ, @@ -165,6 +168,7 @@ struct timesource_data platform_generic_queue[] = { .timer = { .id = TIMER3, /* external timer */ .irq = IRQ_EXT_TSTAMP0_LVL2(3), + .core = 3, }, .clk = CLK_SSP, .notifier = NOTIFIER_ID_SSP_FREQ, From 0468e75bf5a56c4da596462d434a3d27eff31eba Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Fri, 22 Feb 2019 11:09:25 +0100 Subject: [PATCH 16/25] interrupt: SOF_IRQ_NUMBER() for DSP interrupts is not needed DSP interrupts have their own interrupt number in parent interrupt bits, therefore using SOF_IRQ_NUMBER() for them is redundant. Signed-off-by: Guennadi Liakhovetski --- src/drivers/intel/cavs/interrupt.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/drivers/intel/cavs/interrupt.c b/src/drivers/intel/cavs/interrupt.c index 55c52b296ebe..e12ba61d9cda 100644 --- a/src/drivers/intel/cavs/interrupt.c +++ b/src/drivers/intel/cavs/interrupt.c @@ -224,13 +224,13 @@ static const struct irq_cascade_tmpl dsp_irq[] = { void platform_interrupt_set(uint32_t irq) { if (interrupt_is_dsp_direct(irq)) - arch_interrupt_set(SOF_IRQ_NUMBER(irq)); + arch_interrupt_set(irq); } void platform_interrupt_clear(uint32_t irq, uint32_t mask) { if (interrupt_is_dsp_direct(irq)) - arch_interrupt_clear(SOF_IRQ_NUMBER(irq)); + arch_interrupt_clear(irq); } /* Called on each core: from platform_init() and from slave_core_init() */ From 7d00840815109f887af1aacc65587d7eedebaa6b Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Fri, 22 Feb 2019 11:45:42 +0100 Subject: [PATCH 17/25] interrupt: use the parent IRQ instead of SOF_IRQ_NUMBER() Where available, use the IRQ number of the parent instead of extracting it from the child's interrupt, using SOF_IRQ_NUMBER(). Signed-off-by: Guennadi Liakhovetski --- src/drivers/interrupt.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/drivers/interrupt.c b/src/drivers/interrupt.c index f054f9405df7..9e682896cac9 100644 --- a/src/drivers/interrupt.c +++ b/src/drivers/interrupt.c @@ -218,7 +218,7 @@ static uint32_t irq_enable_child(struct irq_desc *parent, int irq) if (!child->enable_count[child_idx]++) { /* enable the parent interrupt */ if (!cascade->enable_count[core]++) - arch_interrupt_enable_mask(1 << SOF_IRQ_NUMBER(irq)); + arch_interrupt_enable_mask(1 << parent->irq); /* enable the child interrupt */ interrupt_unmask(irq, core); @@ -252,7 +252,7 @@ static uint32_t irq_disable_child(struct irq_desc *parent, int irq) /* disable the parent interrupt */ if (!--cascade->enable_count[core]) - arch_interrupt_disable_mask(1 << SOF_IRQ_NUMBER(irq)); + arch_interrupt_disable_mask(1 << parent->irq); } spin_unlock(&cascade->lock); From ef7a83e71f1ef30f3a7c33ab8dbb17f575c386d6 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Fri, 22 Feb 2019 13:04:44 +0100 Subject: [PATCH 18/25] schedule: add an irq private data member Use the platform provided scheduler IRQ number only once and save the number in a private field. Signed-off-by: Guennadi Liakhovetski --- src/schedule/edf_schedule.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/schedule/edf_schedule.c b/src/schedule/edf_schedule.c index daf68cd7324b..07fac9c444ab 100644 --- a/src/schedule/edf_schedule.c +++ b/src/schedule/edf_schedule.c @@ -27,6 +27,7 @@ struct edf_schedule_data { struct list_item list; /* list of tasks in priority queue */ struct list_item idle_list; /* list of queued idle tasks */ uint32_t clock; + int irq; }; #define SLOT_ALIGN_TRIES 10 @@ -172,7 +173,7 @@ static struct task *sch_edf(void) tracev_edf_sch("sch_edf()"); - interrupt_clear(PLATFORM_SCHEDULE_IRQ); + interrupt_clear(sch->irq); while (!list_is_empty(&sch->list)) { spin_lock_irq(&sch->lock, flags); @@ -406,7 +407,7 @@ static void schedule_edf(void) */ /* the scheduler is run in IRQ context */ - interrupt_set(PLATFORM_SCHEDULE_IRQ); + interrupt_set(sch->irq); } /* Initialise the scheduler */ @@ -428,9 +429,9 @@ static int edf_scheduler_init(void) sch->clock = PLATFORM_SCHED_CLOCK; /* configure scheduler interrupt */ - interrupt_register(PLATFORM_SCHEDULE_IRQ, IRQ_AUTO_UNMASK, - edf_scheduler_run, sch); - interrupt_enable(PLATFORM_SCHEDULE_IRQ); + sch->irq = PLATFORM_SCHEDULE_IRQ; + interrupt_register(sch->irq, IRQ_AUTO_UNMASK, edf_scheduler_run, sch); + interrupt_enable(sch->irq); /* allocate arch tasks */ int tasks_result = allocate_tasks(); @@ -448,8 +449,8 @@ static void edf_scheduler_free(void) spin_lock_irq(&sch->lock, flags); /* disable and unregister scheduler interrupt */ - interrupt_disable(PLATFORM_SCHEDULE_IRQ); - interrupt_unregister(PLATFORM_SCHEDULE_IRQ, sch); + interrupt_disable(sch->irq); + interrupt_unregister(sch->irq, sch); /* free arch tasks */ arch_free_tasks(); From aa3255a5df0af774376267908db6d1b140120b2b Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Fri, 22 Feb 2019 14:51:10 +0100 Subject: [PATCH 19/25] idc: add an irq private data member Use the platform provided IDC IRQ number only once and save the number in a private field. This relies on the fact, that the interrupt number is the same on all cores. Signed-off-by: Guennadi Liakhovetski --- src/arch/xtensa/drivers/idc.c | 15 +++++++++------ src/include/sof/drivers/idc.h | 1 + 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/arch/xtensa/drivers/idc.c b/src/arch/xtensa/drivers/idc.c index d9c540197138..16b3831b403d 100644 --- a/src/arch/xtensa/drivers/idc.c +++ b/src/arch/xtensa/drivers/idc.c @@ -50,9 +50,11 @@ static struct idc **idc_get(void) */ void idc_enable_interrupts(int target_core, int source_core) { + struct idc *idc = *idc_get(); + idc_write(IPC_IDCCTL, target_core, IPC_IDCCTL_IDCTBIE(source_core)); - interrupt_unmask(PLATFORM_IDC_INTERRUPT(target_core), target_core); + interrupt_unmask(idc->irq, target_core); } /** @@ -347,11 +349,12 @@ int arch_idc_init(void) SOF_TASK_PRI_IDC, idc_do_cmd, *idc, core, 0); /* configure interrupt */ - ret = interrupt_register(PLATFORM_IDC_INTERRUPT(core), IRQ_AUTO_UNMASK, - idc_irq_handler, *idc); + (*idc)->irq = PLATFORM_IDC_INTERRUPT(core); + ret = interrupt_register((*idc)->irq, IRQ_AUTO_UNMASK, idc_irq_handler, + *idc); if (ret < 0) return ret; - interrupt_enable(PLATFORM_IDC_INTERRUPT(core)); + interrupt_enable((*idc)->irq); /* enable BUSY and DONE (only for master core) interrupts */ idc_write(IPC_IDCCTL, core, @@ -373,8 +376,8 @@ void idc_free(void) trace_idc("idc_free()"); /* disable and unregister interrupt */ - interrupt_disable(PLATFORM_IDC_INTERRUPT(core)); - interrupt_unregister(PLATFORM_IDC_INTERRUPT(core), idc); + interrupt_disable(idc->irq); + interrupt_unregister(idc->irq, idc); /* clear BUSY bits */ for (i = 0; i < PLATFORM_CORE_COUNT; i++) { diff --git a/src/include/sof/drivers/idc.h b/src/include/sof/drivers/idc.h index 995a2f173cad..a5673241776b 100644 --- a/src/include/sof/drivers/idc.h +++ b/src/include/sof/drivers/idc.h @@ -98,6 +98,7 @@ struct idc { uint32_t done_bit_mask; /**< done interrupt mask */ struct idc_msg received_msg; /**< received message */ struct task idc_task; /**< IDC processing task */ + int irq; }; #endif /* __SOF_DRIVERS_IDC_H__ */ From 2af8e799f0726ca55774dbf36cc427efaa70006c Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Tue, 26 Feb 2019 11:23:51 +0100 Subject: [PATCH 20/25] spi: remove the unused irq field The SPI driver only supports the DMA mode, its IRQ line isn't used and the IRQ number in Sue Creek data is wrong. Remove the field completely. Signed-off-by: Guennadi Liakhovetski --- src/include/sof/drivers/spi.h | 1 - src/platform/intel/cavs/platform.c | 1 - 2 files changed, 2 deletions(-) diff --git a/src/include/sof/drivers/spi.h b/src/include/sof/drivers/spi.h index dbf0b52b41cb..1af887100a98 100644 --- a/src/include/sof/drivers/spi.h +++ b/src/include/sof/drivers/spi.h @@ -27,7 +27,6 @@ struct spi_plat_fifo_data { struct spi_platform_data { uint32_t base; - uint32_t irq; struct spi_plat_fifo_data fifo[2]; enum spi_type type; }; diff --git a/src/platform/intel/cavs/platform.c b/src/platform/intel/cavs/platform.c index 88d45bfe7c58..a91c8af49982 100644 --- a/src/platform/intel/cavs/platform.c +++ b/src/platform/intel/cavs/platform.c @@ -292,7 +292,6 @@ struct timer *platform_timer = static struct spi_platform_data spi = { .base = DW_SPI_SLAVE_BASE, - .irq = IRQ_EXT_LP_GPDMA0_LVL5(0, 0), .type = SOF_SPI_INTEL_SLAVE, .fifo[SPI_DIR_RX] = { .handshake = DMA_HANDSHAKE_SSI_RX, From ed1aff4489cd496b65dcf647e0d2f2f57d3d1e9d Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Mon, 25 Feb 2019 18:08:48 +0100 Subject: [PATCH 21/25] interrupt: call the interrupt handler only for enabled descriptors When multiple interrupt handlers share the same interrupt, only those, that enabled the interrupt on a specific CPU, have to be called on that CPU. Signed-off-by: Guennadi Liakhovetski --- src/arch/xtensa/drivers/idc.c | 4 ++-- src/arch/xtensa/schedule/task.c | 24 ++++++++++---------- src/drivers/dw/dma.c | 4 ++-- src/drivers/imx/ipc.c | 4 ++-- src/drivers/imx/timer.c | 7 +++--- src/drivers/intel/baytrail/ipc.c | 5 ++--- src/drivers/intel/baytrail/timer.c | 4 ++-- src/drivers/intel/cavs/dmic.c | 5 +++-- src/drivers/intel/cavs/ipc.c | 4 ++-- src/drivers/intel/cavs/timer.c | 8 +++---- src/drivers/intel/haswell/ipc.c | 5 ++--- src/drivers/intel/haswell/timer.c | 4 ++-- src/drivers/intel/pmc-ipc.c | 5 ++--- src/drivers/interrupt.c | 35 +++++++++++++++++++++++------ src/include/sof/drivers/interrupt.h | 4 ++-- src/schedule/edf_schedule.c | 4 ++-- 16 files changed, 73 insertions(+), 53 deletions(-) diff --git a/src/arch/xtensa/drivers/idc.c b/src/arch/xtensa/drivers/idc.c index 16b3831b403d..491ff3032c2c 100644 --- a/src/arch/xtensa/drivers/idc.c +++ b/src/arch/xtensa/drivers/idc.c @@ -354,7 +354,7 @@ int arch_idc_init(void) *idc); if (ret < 0) return ret; - interrupt_enable((*idc)->irq); + interrupt_enable((*idc)->irq, *idc); /* enable BUSY and DONE (only for master core) interrupts */ idc_write(IPC_IDCCTL, core, @@ -376,7 +376,7 @@ void idc_free(void) trace_idc("idc_free()"); /* disable and unregister interrupt */ - interrupt_disable(idc->irq); + interrupt_disable(idc->irq, idc); interrupt_unregister(idc->irq, idc); /* clear BUSY bits */ diff --git a/src/arch/xtensa/schedule/task.c b/src/arch/xtensa/schedule/task.c index 849ba398c8c4..d2a290c5480b 100644 --- a/src/arch/xtensa/schedule/task.c +++ b/src/arch/xtensa/schedule/task.c @@ -171,10 +171,10 @@ int arch_allocate_tasks(void) (*low)->irq = PLATFORM_IRQ_TASK_LOW; ret = interrupt_register((*low)->irq, IRQ_AUTO_UNMASK, _irq_task, - task_irq_low_get()); + low); if (ret < 0) return ret; - interrupt_enable((*low)->irq); + interrupt_enable((*low)->irq, low); #endif #if CONFIG_TASK_HAVE_PRIORITY_MEDIUM @@ -187,10 +187,10 @@ int arch_allocate_tasks(void) (*med)->irq = PLATFORM_IRQ_TASK_MED; ret = interrupt_register((*med)->irq, IRQ_AUTO_UNMASK, _irq_task, - task_irq_med_get()); + med); if (ret < 0) return ret; - interrupt_enable((*med)->irq); + interrupt_enable((*med)->irq, med); #endif /* irq high */ @@ -202,10 +202,10 @@ int arch_allocate_tasks(void) (*high)->irq = PLATFORM_IRQ_TASK_HIGH; ret = interrupt_register((*high)->irq, IRQ_AUTO_UNMASK, _irq_task, - task_irq_high_get()); + high); if (ret < 0) return ret; - interrupt_enable((*high)->irq); + interrupt_enable((*high)->irq, high); return 0; } @@ -220,8 +220,8 @@ void arch_free_tasks(void) struct irq_task **low = task_irq_low_get(); spin_lock_irq(&(*low)->lock, flags); - interrupt_disable((*low)->irq); - interrupt_unregister((*low)->irq, task_irq_low_get()); + interrupt_disable((*low)->irq, low); + interrupt_unregister((*low)->irq, low); list_item_del(&(*low)->list); spin_unlock_irq(&(*low)->lock, flags); #endif @@ -231,8 +231,8 @@ void arch_free_tasks(void) struct irq_task **med = task_irq_med_get(); spin_lock_irq(&(*med)->lock, flags); - interrupt_disable((*med)->irq); - interrupt_unregister((*med)->irq, task_irq_med_get()); + interrupt_disable((*med)->irq, med); + interrupt_unregister((*med)->irq, med); list_item_del(&(*med)->list); spin_unlock_irq(&(*med)->lock, flags); #endif @@ -241,8 +241,8 @@ void arch_free_tasks(void) struct irq_task **high = task_irq_high_get(); spin_lock_irq(&(*high)->lock, flags); - interrupt_disable((*high)->irq); - interrupt_unregister((*high)->irq, task_irq_high_get()); + interrupt_disable((*high)->irq, high); + interrupt_unregister((*high)->irq, high); list_item_del(&(*high)->list); spin_unlock_irq(&(*high)->lock, flags); } diff --git a/src/drivers/dw/dma.c b/src/drivers/dw/dma.c index e6504ad02bb4..d68f8264a1fe 100644 --- a/src/drivers/dw/dma.c +++ b/src/drivers/dw/dma.c @@ -1139,7 +1139,7 @@ static inline int dw_dma_interrupt_register(struct dma *dma, return ret; } - interrupt_enable(irq); + interrupt_enable(irq, chan); #if CONFIG_DMA_AGGREGATED_IRQ } @@ -1171,7 +1171,7 @@ static inline void dw_dma_interrupt_unregister(struct dma *dma, if (!p->mask_irq_channels[cpu]) { #endif - interrupt_disable(irq); + interrupt_disable(irq, chan); interrupt_unregister(irq, chan); #if CONFIG_DMA_AGGREGATED_IRQ } diff --git a/src/drivers/imx/ipc.c b/src/drivers/imx/ipc.c index 69efe7e615fd..73e03deb0776 100644 --- a/src/drivers/imx/ipc.c +++ b/src/drivers/imx/ipc.c @@ -193,8 +193,8 @@ int platform_ipc_init(struct ipc *ipc) /* configure interrupt */ interrupt_register(PLATFORM_IPC_INTERRUPT, IRQ_AUTO_UNMASK, - irq_handler, NULL); - interrupt_enable(PLATFORM_IPC_INTERRUPT); + irq_handler, _ipc); + interrupt_enable(PLATFORM_IPC_INTERRUPT, _ipc); /* enable GP #0 for Host -> DSP message notification * enable GP #1 for DSP -> Host message notification diff --git a/src/drivers/imx/timer.c b/src/drivers/imx/timer.c index 48edf1930a05..5d89ea9507a9 100644 --- a/src/drivers/imx/timer.c +++ b/src/drivers/imx/timer.c @@ -77,6 +77,7 @@ int timer_register(struct timer *timer, void(*handler)(void *arg), void *arg) switch (timer->id) { case TIMER0: case TIMER1: + timer->irq_arg = arg; return arch_timer_register(timer, handler, arg); default: return -EINVAL; @@ -85,15 +86,15 @@ int timer_register(struct timer *timer, void(*handler)(void *arg), void *arg) void timer_unregister(struct timer *timer) { - interrupt_unregister(timer->irq); + interrupt_unregister(timer->irq, timer->irq_arg); } void timer_enable(struct timer *timer) { - interrupt_enable(timer->irq); + interrupt_enable(timer->irq, timer->irq_arg); } void timer_disable(struct timer *timer) { - interrupt_disable(timer->irq); + interrupt_disable(timer->irq, timer->irq_arg); } diff --git a/src/drivers/intel/baytrail/ipc.c b/src/drivers/intel/baytrail/ipc.c index 01c4bb565174..b23ac4f71e31 100644 --- a/src/drivers/intel/baytrail/ipc.c +++ b/src/drivers/intel/baytrail/ipc.c @@ -18,7 +18,6 @@ #include #include #include -#include #include extern struct ipc *_ipc; @@ -217,8 +216,8 @@ int platform_ipc_init(struct ipc *ipc) /* configure interrupt */ interrupt_register(PLATFORM_IPC_INTERRUPT, IRQ_AUTO_UNMASK, - irq_handler, NULL); - interrupt_enable(PLATFORM_IPC_INTERRUPT); + irq_handler, ipc); + interrupt_enable(PLATFORM_IPC_INTERRUPT, ipc); /* Unmask Busy and Done interrupts */ imrd = shim_read(SHIM_IMRD); diff --git a/src/drivers/intel/baytrail/timer.c b/src/drivers/intel/baytrail/timer.c index 9971875194df..0330198f0f00 100644 --- a/src/drivers/intel/baytrail/timer.c +++ b/src/drivers/intel/baytrail/timer.c @@ -223,10 +223,10 @@ void timer_unregister(struct timer *timer) void timer_enable(struct timer *timer) { - interrupt_enable(timer->irq); + interrupt_enable(timer->irq, timer->irq_arg); } void timer_disable(struct timer *timer) { - interrupt_disable(timer->irq); + interrupt_disable(timer->irq, timer->irq_arg); } diff --git a/src/drivers/intel/cavs/dmic.c b/src/drivers/intel/cavs/dmic.c index 062bb8e16c2d..bac45df1df95 100644 --- a/src/drivers/intel/cavs/dmic.c +++ b/src/drivers/intel/cavs/dmic.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -1539,7 +1540,7 @@ static int dmic_probe(struct dai *dai) pm_runtime_get_sync(DMIC_CLK, dai->index); interrupt_unmask(irq, cpu_get_id()); - interrupt_enable(irq); + interrupt_enable(irq, dai); return 0; } @@ -1549,7 +1550,7 @@ static int dmic_remove(struct dai *dai) int irq = dmic_irq(dai); int i; - interrupt_disable(irq); + interrupt_disable(irq, dai); interrupt_mask(irq, cpu_get_id()); interrupt_unregister(irq, dai); diff --git a/src/drivers/intel/cavs/ipc.c b/src/drivers/intel/cavs/ipc.c index 671935819e36..e151ae135a8d 100644 --- a/src/drivers/intel/cavs/ipc.c +++ b/src/drivers/intel/cavs/ipc.c @@ -241,8 +241,8 @@ int platform_ipc_init(struct ipc *ipc) /* configure interrupt */ interrupt_register(PLATFORM_IPC_INTERRUPT, IRQ_AUTO_UNMASK, - ipc_irq_handler, NULL); - interrupt_enable(PLATFORM_IPC_INTERRUPT); + ipc_irq_handler, ipc); + interrupt_enable(PLATFORM_IPC_INTERRUPT, ipc); /* enable IPC interrupts from host */ ipc_write(IPC_DIPCCTL, IPC_DIPCCTL_IPCIDIE | IPC_DIPCCTL_IPCTBIE); diff --git a/src/drivers/intel/cavs/timer.c b/src/drivers/intel/cavs/timer.c index b0640437c5ce..7c025d732c0e 100644 --- a/src/drivers/intel/cavs/timer.c +++ b/src/drivers/intel/cavs/timer.c @@ -105,7 +105,7 @@ static int platform_timer_register(struct timer *timer, timer->irq_arg = arg; /* enable timer interrupt */ - interrupt_enable(timer->irq); + interrupt_enable(timer->irq, arg); /* disable timer interrupt on core level */ timer_disable(timer); @@ -141,7 +141,7 @@ int timer_register(struct timer *timer, void(*handler)(void *arg), void *arg) static void platform_timer_unregister(struct timer *timer) { /* disable timer interrupt */ - interrupt_disable(timer->irq); + interrupt_disable(timer->irq, timer->irq_arg); /* unregister timer interrupt */ interrupt_unregister(timer->irq, timer->irq_arg); @@ -167,7 +167,7 @@ void timer_enable(struct timer *timer) case TIMER0: case TIMER1: case TIMER2: - interrupt_enable(timer->irq); + interrupt_enable(timer->irq, timer->irq_arg); break; case TIMER3: interrupt_unmask(timer->irq, timer->core); @@ -181,7 +181,7 @@ void timer_disable(struct timer *timer) case TIMER0: case TIMER1: case TIMER2: - interrupt_disable(timer->irq); + interrupt_disable(timer->irq, timer->irq_arg); break; case TIMER3: interrupt_mask(timer->irq, timer->core); diff --git a/src/drivers/intel/haswell/ipc.c b/src/drivers/intel/haswell/ipc.c index 2345c8dd17d8..9d84caa319c0 100644 --- a/src/drivers/intel/haswell/ipc.c +++ b/src/drivers/intel/haswell/ipc.c @@ -18,7 +18,6 @@ #include #include #include -#include #include extern struct ipc *_ipc; @@ -207,8 +206,8 @@ int platform_ipc_init(struct ipc *ipc) /* configure interrupt */ interrupt_register(PLATFORM_IPC_INTERRUPT, IRQ_AUTO_UNMASK, - irq_handler, NULL); - interrupt_enable(PLATFORM_IPC_INTERRUPT); + irq_handler, ipc); + interrupt_enable(PLATFORM_IPC_INTERRUPT, ipc); /* Unmask Busy and Done interrupts */ imrd = shim_read(SHIM_IMRD); diff --git a/src/drivers/intel/haswell/timer.c b/src/drivers/intel/haswell/timer.c index 137de301c57a..b49a3243f2c1 100644 --- a/src/drivers/intel/haswell/timer.c +++ b/src/drivers/intel/haswell/timer.c @@ -95,10 +95,10 @@ void timer_unregister(struct timer *timer) void timer_enable(struct timer *timer) { - interrupt_enable(timer->irq); + interrupt_enable(timer->irq, timer->irq_arg); } void timer_disable(struct timer *timer) { - interrupt_disable(timer->irq); + interrupt_disable(timer->irq, timer->irq_arg); } diff --git a/src/drivers/intel/pmc-ipc.c b/src/drivers/intel/pmc-ipc.c index 9dc2bf85e7a2..ccbbcc557da6 100644 --- a/src/drivers/intel/pmc-ipc.c +++ b/src/drivers/intel/pmc-ipc.c @@ -13,7 +13,6 @@ #include #include #include -#include #include /* private data for IPC */ @@ -139,8 +138,8 @@ int platform_ipc_pmc_init(void) /* configure interrupt */ interrupt_register(IRQ_NUM_EXT_PMC, IRQ_AUTO_UNMASK, irq_handler, - NULL); - interrupt_enable(IRQ_NUM_EXT_PMC); + _pmc); + interrupt_enable(IRQ_NUM_EXT_PMC, _pmc); /* Unmask Busy and Done interrupts */ imrlpesc = shim_read(SHIM_IMRLPESC); diff --git a/src/drivers/interrupt.c b/src/drivers/interrupt.c index 9e682896cac9..2e6dd8b5071e 100644 --- a/src/drivers/interrupt.c +++ b/src/drivers/interrupt.c @@ -146,7 +146,6 @@ static int irq_register_child(struct irq_desc *parent, int irq, int unmask, child->handler = handler; child->handler_arg = arg; child->unmask = unmask; - child->cpu_mask = 1 << core; list_item_append(&child->irq_list, head); @@ -202,19 +201,30 @@ static void irq_unregister_child(struct irq_desc *parent, int irq, spin_unlock(&cascade->lock); } -static uint32_t irq_enable_child(struct irq_desc *parent, int irq) +static uint32_t irq_enable_child(struct irq_desc *parent, int irq, void *arg) { struct irq_cascade_desc *cascade = container_of(parent, struct irq_cascade_desc, desc); unsigned int core = cpu_get_id(); struct irq_child *child; unsigned int child_idx; + struct list_item *list; spin_lock(&cascade->lock); child = cascade->child + SOF_IRQ_BIT(irq); child_idx = cascade->global_mask ? 0 : core; + list_for_item(list, &child->list) { + struct irq_desc *d = container_of(list, + struct irq_desc, irq_list); + + if (d->handler_arg == arg) { + d->cpu_mask |= 1 << core; + break; + } + } + if (!child->enable_count[child_idx]++) { /* enable the parent interrupt */ if (!cascade->enable_count[core]++) @@ -229,19 +239,30 @@ static uint32_t irq_enable_child(struct irq_desc *parent, int irq) return 0; } -static uint32_t irq_disable_child(struct irq_desc *parent, int irq) +static uint32_t irq_disable_child(struct irq_desc *parent, int irq, void *arg) { struct irq_cascade_desc *cascade = container_of(parent, struct irq_cascade_desc, desc); unsigned int core = cpu_get_id(); struct irq_child *child; unsigned int child_idx; + struct list_item *list; spin_lock(&cascade->lock); child = cascade->child + SOF_IRQ_BIT(irq); child_idx = cascade->global_mask ? 0 : core; + list_for_item(list, &child->list) { + struct irq_desc *d = container_of(list, + struct irq_desc, irq_list); + + if (d->handler_arg == arg) { + d->cpu_mask &= ~(1 << core); + break; + } + } + if (!child->enable_count[child_idx]) { trace_error(TRACE_CLASS_IRQ, "error: IRQ %x unbalanced interrupt_disable()", @@ -285,7 +306,7 @@ void interrupt_unregister(uint32_t irq, const void *arg) irq_unregister_child(parent, irq, arg); } -uint32_t interrupt_enable(uint32_t irq) +uint32_t interrupt_enable(uint32_t irq, void *arg) { struct irq_desc *parent; @@ -294,10 +315,10 @@ uint32_t interrupt_enable(uint32_t irq) if (parent == NULL) return arch_interrupt_enable_mask(1 << irq); else - return irq_enable_child(parent, irq); + return irq_enable_child(parent, irq, arg); } -uint32_t interrupt_disable(uint32_t irq) +uint32_t interrupt_disable(uint32_t irq, void *arg) { struct irq_desc *parent; @@ -306,5 +327,5 @@ uint32_t interrupt_disable(uint32_t irq) if (parent == NULL) return arch_interrupt_disable_mask(1 << irq); else - return irq_disable_child(parent, irq); + return irq_disable_child(parent, irq, arg); } diff --git a/src/include/sof/drivers/interrupt.h b/src/include/sof/drivers/interrupt.h index db1fc2130f8e..d4dd21aed062 100644 --- a/src/include/sof/drivers/interrupt.h +++ b/src/include/sof/drivers/interrupt.h @@ -111,8 +111,8 @@ struct irq_cascade_tmpl { int interrupt_register(uint32_t irq, int unmask, void(*handler)(void *arg), void *arg); void interrupt_unregister(uint32_t irq, const void *arg); -uint32_t interrupt_enable(uint32_t irq); -uint32_t interrupt_disable(uint32_t irq); +uint32_t interrupt_enable(uint32_t irq, void *arg); +uint32_t interrupt_disable(uint32_t irq, void *arg); void platform_interrupt_init(void); diff --git a/src/schedule/edf_schedule.c b/src/schedule/edf_schedule.c index 07fac9c444ab..79e319e4b037 100644 --- a/src/schedule/edf_schedule.c +++ b/src/schedule/edf_schedule.c @@ -431,7 +431,7 @@ static int edf_scheduler_init(void) /* configure scheduler interrupt */ sch->irq = PLATFORM_SCHEDULE_IRQ; interrupt_register(sch->irq, IRQ_AUTO_UNMASK, edf_scheduler_run, sch); - interrupt_enable(sch->irq); + interrupt_enable(sch->irq, sch); /* allocate arch tasks */ int tasks_result = allocate_tasks(); @@ -449,7 +449,7 @@ static void edf_scheduler_free(void) spin_lock_irq(&sch->lock, flags); /* disable and unregister scheduler interrupt */ - interrupt_disable(sch->irq); + interrupt_disable(sch->irq, sch); interrupt_unregister(sch->irq, sch); /* free arch tasks */ From a9c4309d5fa17da150ed5e10930bdefab6ba4f9c Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Tue, 26 Feb 2019 11:49:39 +0100 Subject: [PATCH 22/25] interrupt: switch from bitfields to dynamic interrupt mapping Currently on cAVS platforms the two kinds of interrupts are treated differently: the native DSP interrupts and "level" interrupts, multiplexed by cascading interrupt controllers. For the latter bitfields are used with both the parent DSP interrupt and the child multiplexed interrupt numbers encoded in them. This is inflexible and doesn't scale when more cascading interrupt controllers are added. This patch switches over from using those bitfields to dynamically mapping cascaded interrupts into a single plain interrupt number space. Specifically this patch does the following: - For interrupt conttrollers it adds an .irq_base field, which is the base for child interrupts, multiplexed by this controller. - An interrupt mapping function interrupt_get_irq() is added, which uses the name of the cascading interrupt controller and an interrupt number on that controller to create a logical interrupt number. - All uses of SOF_IRQ() and SOF_ID_IRQ() and related bitfield- manipulation macros are removed. Signed-off-by: Guennadi Liakhovetski --- src/arch/xtensa/drivers/idc.c | 5 +- .../xtensa/include/arch/drivers/interrupt.h | 10 +- src/arch/xtensa/include/arch/drivers/timer.h | 12 ++- src/arch/xtensa/include/arch/schedule/task.h | 3 +- src/arch/xtensa/schedule/task.c | 21 +++-- src/drivers/dw/dma.c | 76 +++++++-------- src/drivers/imx/timer.c | 16 +++- src/drivers/intel/baytrail/timer.c | 16 +++- src/drivers/intel/cavs/dmic.c | 21 +++-- src/drivers/intel/cavs/interrupt.c | 21 ++--- src/drivers/intel/cavs/ipc.c | 11 ++- src/drivers/intel/cavs/timer.c | 48 +++++++--- src/drivers/intel/haswell/timer.c | 16 +++- src/drivers/interrupt.c | 93 ++++++++++++++----- src/include/sof/drivers/dmic.h | 5 +- src/include/sof/drivers/interrupt.h | 11 ++- src/include/sof/drivers/timer.h | 2 + src/include/sof/lib/dai.h | 3 +- src/include/sof/lib/dma.h | 10 +- src/include/sof/schedule/ll_schedule.h | 3 - .../include/platform/drivers/interrupt.h | 57 ++++-------- .../include/platform/drivers/timer.h | 4 +- .../apollolake/include/platform/lib/dma.h | 5 +- .../apollolake/include/platform/platform.h | 13 ++- .../baytrail/include/platform/lib/dma.h | 2 +- .../baytrail/include/platform/platform.h | 6 ++ .../include/platform/drivers/interrupt.h | 57 ++++-------- .../include/platform/drivers/timer.h | 4 +- .../cannonlake/include/platform/lib/dma.h | 2 +- .../cannonlake/include/platform/platform.h | 11 ++- .../haswell/include/platform/lib/dma.h | 2 +- .../haswell/include/platform/platform.h | 6 ++ .../include/platform/drivers/interrupt.h | 57 ++++-------- .../icelake/include/platform/drivers/timer.h | 4 +- .../icelake/include/platform/lib/dma.h | 2 +- .../icelake/include/platform/platform.h | 11 ++- src/platform/imx8/include/platform/platform.h | 18 ++-- src/platform/intel/cavs/lib/dai.c | 9 +- src/platform/intel/cavs/lib/dma.c | 31 ++++--- src/platform/intel/cavs/platform.c | 12 ++- .../include/platform/drivers/interrupt.h | 55 ++++------- .../suecreek/include/platform/drivers/timer.h | 4 +- .../suecreek/include/platform/lib/dma.h | 2 +- .../suecreek/include/platform/platform.h | 13 ++- src/schedule/edf_schedule.c | 5 +- src/schedule/ll_schedule.c | 20 +++- 46 files changed, 462 insertions(+), 353 deletions(-) diff --git a/src/arch/xtensa/drivers/idc.c b/src/arch/xtensa/drivers/idc.c index 491ff3032c2c..d9029ccac8e9 100644 --- a/src/arch/xtensa/drivers/idc.c +++ b/src/arch/xtensa/drivers/idc.c @@ -349,7 +349,10 @@ int arch_idc_init(void) SOF_TASK_PRI_IDC, idc_do_cmd, *idc, core, 0); /* configure interrupt */ - (*idc)->irq = PLATFORM_IDC_INTERRUPT(core); + (*idc)->irq = interrupt_get_irq(PLATFORM_IDC_INTERRUPT, + PLATFORM_IDC_INTERRUPT_NAME); + if ((*idc)->irq < 0) + return (*idc)->irq; ret = interrupt_register((*idc)->irq, IRQ_AUTO_UNMASK, idc_irq_handler, *idc); if (ret < 0) diff --git a/src/arch/xtensa/include/arch/drivers/interrupt.h b/src/arch/xtensa/include/arch/drivers/interrupt.h index 9a8240ce30b5..21d950dbcde6 100644 --- a/src/arch/xtensa/include/arch/drivers/interrupt.h +++ b/src/arch/xtensa/include/arch/drivers/interrupt.h @@ -10,16 +10,19 @@ #ifndef __ARCH_DRIVERS_INTERRUPT_H__ #define __ARCH_DRIVERS_INTERRUPT_H__ -#include #include #include #include #include +extern char irq_name_level2[]; +extern char irq_name_level3[]; +extern char irq_name_level4[]; +extern char irq_name_level5[]; + static inline int arch_interrupt_register(int irq, void (*handler)(void *arg), void *arg) { - irq = SOF_IRQ_NUMBER(irq); xthal_set_intclear(0x1 << irq); _xtos_set_interrupt_handler_arg(irq, handler, arg); return 0; @@ -27,7 +30,6 @@ static inline int arch_interrupt_register(int irq, static inline void arch_interrupt_unregister(int irq) { - irq = SOF_IRQ_NUMBER(irq); _xtos_set_interrupt_handler_arg(irq, NULL, NULL); } @@ -53,13 +55,11 @@ static inline uint32_t arch_interrupt_get_level(void) static inline void arch_interrupt_set(int irq) { - irq = SOF_IRQ_NUMBER(irq); xthal_set_intset(0x1 << irq); } static inline void arch_interrupt_clear(int irq) { - irq = SOF_IRQ_NUMBER(irq); xthal_set_intclear(0x1 << irq); } diff --git a/src/arch/xtensa/include/arch/drivers/timer.h b/src/arch/xtensa/include/arch/drivers/timer.h index e4a1f77c95a5..daa9275a6de3 100644 --- a/src/arch/xtensa/include/arch/drivers/timer.h +++ b/src/arch/xtensa/include/arch/drivers/timer.h @@ -13,12 +13,18 @@ #include #include +struct timer_irq { + int logical_irq; + void *irq_arg; +}; + struct timer { uint32_t id; - uint32_t irq; - uint32_t core; - void *irq_arg; + int irq; + const char *irq_name; + unsigned int core; void *timer_data; /* used by core */ + struct timer_irq *tirq; /* dynamic non-cacheable IRQ data */ uint32_t hitime; /* high end of 64bit timer */ uint32_t hitimeout; uint32_t lowtimeout; diff --git a/src/arch/xtensa/include/arch/schedule/task.h b/src/arch/xtensa/include/arch/schedule/task.h index ebb1b7a4de15..9c4e5c26aff6 100644 --- a/src/arch/xtensa/include/arch/schedule/task.h +++ b/src/arch/xtensa/include/arch/schedule/task.h @@ -18,13 +18,12 @@ #include #include -#include /** \brief IRQ task data. */ struct irq_task { spinlock_t lock; /**< lock */ struct list_item list; /**< list of tasks */ - uint32_t irq; /**< IRQ level */ + int irq; /**< IRQ level */ }; struct task; diff --git a/src/arch/xtensa/schedule/task.c b/src/arch/xtensa/schedule/task.c index d2a290c5480b..3176cc1b667e 100644 --- a/src/arch/xtensa/schedule/task.c +++ b/src/arch/xtensa/schedule/task.c @@ -168,10 +168,12 @@ int arch_allocate_tasks(void) list_init(&((*low)->list)); spinlock_init(&((*low)->lock)); - (*low)->irq = PLATFORM_IRQ_TASK_LOW; + (*low)->irq = interrupt_get_irq(PLATFORM_IRQ_TASK_LOW, + PLATFORM_IRQ_TASK_LOW_NAME); + if ((*low)->irq < 0) + return (*low)->irq; - ret = interrupt_register((*low)->irq, IRQ_AUTO_UNMASK, _irq_task, - low); + ret = interrupt_register((*low)->irq, IRQ_AUTO_UNMASK, _irq_task, low); if (ret < 0) return ret; interrupt_enable((*low)->irq, low); @@ -184,10 +186,12 @@ int arch_allocate_tasks(void) list_init(&((*med)->list)); spinlock_init(&((*med)->lock)); - (*med)->irq = PLATFORM_IRQ_TASK_MED; + (*med)->irq = interrupt_get_irq(PLATFORM_IRQ_TASK_MED, + PLATFORM_IRQ_TASK_MED_NAME); + if ((*med)->irq < 0) + return (*med)->irq; - ret = interrupt_register((*med)->irq, IRQ_AUTO_UNMASK, _irq_task, - med); + ret = interrupt_register((*med)->irq, IRQ_AUTO_UNMASK, _irq_task, med); if (ret < 0) return ret; interrupt_enable((*med)->irq, med); @@ -199,7 +203,10 @@ int arch_allocate_tasks(void) list_init(&((*high)->list)); spinlock_init(&((*high)->lock)); - (*high)->irq = PLATFORM_IRQ_TASK_HIGH; + (*high)->irq = interrupt_get_irq(PLATFORM_IRQ_TASK_HIGH, + PLATFORM_IRQ_TASK_HIGH_NAME); + if ((*high)->irq < 0) + return (*high)->irq; ret = interrupt_register((*high)->irq, IRQ_AUTO_UNMASK, _irq_task, high); diff --git a/src/drivers/dw/dma.c b/src/drivers/dw/dma.c index d68f8264a1fe..f9f0aeefc220 100644 --- a/src/drivers/dw/dma.c +++ b/src/drivers/dw/dma.c @@ -61,6 +61,9 @@ struct dw_dma_chan_data { uint32_t cfg_lo; uint32_t cfg_hi; bool irq_disabled; +#if !CONFIG_DMA_AGGREGATED_IRQ + int irq; +#endif /* pointer data */ struct dw_dma_ptr_data ptr_data; @@ -79,8 +82,7 @@ struct dw_dma_chan_data { struct dma_pdata { struct dw_dma_chan_data chan[DW_MAX_CHAN]; #if CONFIG_DMA_AGGREGATED_IRQ - /**< bitmask of channels with registered IRQs per core */ - uint32_t mask_irq_channels[PLATFORM_CORE_COUNT]; + int irq; #endif }; @@ -155,8 +157,9 @@ static void dw_dma_interrupt_unmask(struct dma *dma, unsigned int channel) static void dw_dma_interrupt_clear(struct dma *dma, unsigned int channel) { const struct dma_pdata *p = dma_get_drvdata(dma); + const struct dw_dma_chan_data *chan = p->chan + channel; - if (p->chan[channel].irq_disabled) { + if (chan->irq_disabled) { tracev_dwdma("dw_dma_interrupt_mask(): dma %d channel %d " "not working in irq mode", dma->plat_data.id, channel); @@ -171,7 +174,11 @@ static void dw_dma_interrupt_clear(struct dma *dma, unsigned int channel) dw_write(dma, DW_CLEAR_ERR, DW_CHAN(channel)); /* clear platform interrupt */ - interrupt_clear_mask(dma_irq(dma, cpu_get_id()), DW_CHAN(channel)); +#if CONFIG_DMA_AGGREGATED_IRQ + interrupt_clear_mask(p->irq, DW_CHAN(channel)); +#else + interrupt_clear_mask(chan->irq, DW_CHAN(channel)); +#endif } /* allocate next free DMA channel */ @@ -1072,7 +1079,7 @@ static void dw_dma_irq_handler(void *data) #if CONFIG_HW_LLI #if CONFIG_DMA_AGGREGATED_IRQ /* skip if channel is not registered on this core */ - mask = p->mask_irq_channels[cpu_get_id()]; + mask = BIT(chan - p->chan); #else mask = ~0; #endif @@ -1092,9 +1099,10 @@ static void dw_dma_irq_handler(void *data) dw_write(dma, DW_CLEAR_ERR, status_err); } +#if CONFIG_DMA_AGGREGATED_IRQ /* clear platform and DSP interrupt */ - interrupt_clear_mask(dma_irq(dma, cpu_get_id()), - status_src | status_err); + interrupt_clear_mask(p->irq, status_src | status_err); +#endif for (i = 0; i < dma->plat_data.channels; i++) { /* skip if channel is not running */ @@ -1113,10 +1121,8 @@ static inline int dw_dma_interrupt_register(struct dma *dma, { struct dma_pdata *p = dma_get_drvdata(dma); struct dw_dma_chan_data *chan = p->chan + channel; - uint32_t irq = dma_chan_irq(dma, cpu_get_id(), channel); -#if CONFIG_DMA_AGGREGATED_IRQ - int cpu = cpu_get_id(); -#endif + uint32_t irq = dma_chan_irq(dma, channel); + int logical_irq = interrupt_get_irq(irq, dma_irq_name(dma)); int ret; if (chan->irq_disabled) { @@ -1126,25 +1132,25 @@ static inline int dw_dma_interrupt_register(struct dma *dma, return 0; } -#if CONFIG_DMA_AGGREGATED_IRQ - if (!p->mask_irq_channels[cpu]) { -#endif - ret = interrupt_register(irq, IRQ_AUTO_UNMASK, - dw_dma_irq_handler, chan); - if (ret < 0) { - trace_dwdma_error("dw_dma_interrupt_register() error: " - "dma %d channel %d failed to " - "allocate IRQ", dma->plat_data.id, - channel); - return ret; - } + if (logical_irq < 0) + return logical_irq; - interrupt_enable(irq, chan); #if CONFIG_DMA_AGGREGATED_IRQ + p->irq = logical_irq; +#else + chan->irq = logical_irq; +#endif + ret = interrupt_register(logical_irq, IRQ_AUTO_UNMASK, + dw_dma_irq_handler, chan); + if (ret < 0) { + trace_dwdma_error("dw_dma_interrupt_register() error: " + "dma %d channel %d failed to " + "allocate IRQ", dma->plat_data.id, + channel); + return ret; } - p->mask_irq_channels[cpu] |= BIT(channel); -#endif + interrupt_enable(logical_irq, chan); return 0; } @@ -1154,10 +1160,7 @@ static inline void dw_dma_interrupt_unregister(struct dma *dma, { struct dma_pdata *p = dma_get_drvdata(dma); struct dw_dma_chan_data *chan = p->chan + channel; - uint32_t irq = dma_chan_irq(dma, cpu_get_id(), channel); -#if CONFIG_DMA_AGGREGATED_IRQ - int cpu = cpu_get_id(); -#endif + int logical_irq; if (chan->irq_disabled) { tracev_dwdma("dw_dma_interrupt_unregister(): dma %d channel %d" @@ -1167,15 +1170,12 @@ static inline void dw_dma_interrupt_unregister(struct dma *dma, } #if CONFIG_DMA_AGGREGATED_IRQ - p->mask_irq_channels[cpu] &= ~BIT(channel); - - if (!p->mask_irq_channels[cpu]) { -#endif - interrupt_disable(irq, chan); - interrupt_unregister(irq, chan); -#if CONFIG_DMA_AGGREGATED_IRQ - } + logical_irq = p->irq; +#else + logical_irq = chan->irq; #endif + interrupt_disable(logical_irq, chan); + interrupt_unregister(logical_irq, chan); } static int dw_dma_setup(struct dma *dma) diff --git a/src/drivers/imx/timer.c b/src/drivers/imx/timer.c index 5d89ea9507a9..d9d2cc5a48cb 100644 --- a/src/drivers/imx/timer.c +++ b/src/drivers/imx/timer.c @@ -74,10 +74,12 @@ void platform_dai_wallclock(struct comp_dev *dai, uint64_t *wallclock) int timer_register(struct timer *timer, void(*handler)(void *arg), void *arg) { + struct timer_irq *tirq = timer->tirq; + switch (timer->id) { case TIMER0: case TIMER1: - timer->irq_arg = arg; + tirq->irq_arg = arg; return arch_timer_register(timer, handler, arg); default: return -EINVAL; @@ -86,15 +88,21 @@ int timer_register(struct timer *timer, void(*handler)(void *arg), void *arg) void timer_unregister(struct timer *timer) { - interrupt_unregister(timer->irq, timer->irq_arg); + struct timer_irq *tirq = timer->tirq; + + interrupt_unregister(timer->irq, tirq->irq_arg); } void timer_enable(struct timer *timer) { - interrupt_enable(timer->irq, timer->irq_arg); + struct timer_irq *tirq = timer->tirq; + + interrupt_enable(timer->irq, tirq->irq_arg); } void timer_disable(struct timer *timer) { - interrupt_disable(timer->irq, timer->irq_arg); + struct timer_irq *tirq = timer->tirq; + + interrupt_disable(timer->irq, tirq->irq_arg); } diff --git a/src/drivers/intel/baytrail/timer.c b/src/drivers/intel/baytrail/timer.c index 0330198f0f00..84c2dd607209 100644 --- a/src/drivers/intel/baytrail/timer.c +++ b/src/drivers/intel/baytrail/timer.c @@ -202,7 +202,9 @@ static int platform_timer_register(struct timer *timer, int timer_register(struct timer *timer, void(*handler)(void *arg), void *arg) { - timer->irq_arg = arg; + struct timer_irq *tirq = timer->tirq; + + tirq->irq_arg = arg; switch (timer->id) { case TIMER0: @@ -218,15 +220,21 @@ int timer_register(struct timer *timer, void(*handler)(void *arg), void *arg) void timer_unregister(struct timer *timer) { - interrupt_unregister(timer->irq, timer->irq_arg); + struct timer_irq *tirq = timer->tirq; + + interrupt_unregister(timer->irq, tirq->irq_arg); } void timer_enable(struct timer *timer) { - interrupt_enable(timer->irq, timer->irq_arg); + struct timer_irq *tirq = timer->tirq; + + interrupt_enable(timer->irq, tirq->irq_arg); } void timer_disable(struct timer *timer) { - interrupt_disable(timer->irq, timer->irq_arg); + struct timer_irq *tirq = timer->tirq; + + interrupt_disable(timer->irq, tirq->irq_arg); } diff --git a/src/drivers/intel/cavs/dmic.c b/src/drivers/intel/cavs/dmic.c index bac45df1df95..46d649dc8aa7 100644 --- a/src/drivers/intel/cavs/dmic.c +++ b/src/drivers/intel/cavs/dmic.c @@ -1526,7 +1526,14 @@ static int dmic_probe(struct dai *dai) dmic->state = COMP_STATE_READY; /* register our IRQ handler */ - ret = interrupt_register(irq, IRQ_AUTO_UNMASK, + dmic->irq = interrupt_get_irq(irq, dmic_irq_name(dai)); + if (dmic->irq < 0) { + ret = dmic->irq; + rfree(dmic); + return ret; + } + + ret = interrupt_register(dmic->irq, IRQ_AUTO_UNMASK, dmic_irq_handler, dai); if (ret < 0) { trace_dmic_error("dmic failed to allocate IRQ"); @@ -1539,20 +1546,20 @@ static int dmic_probe(struct dai *dai) /* Disable dynamic clock gating for dmic before touching any reg */ pm_runtime_get_sync(DMIC_CLK, dai->index); - interrupt_unmask(irq, cpu_get_id()); - interrupt_enable(irq, dai); + interrupt_unmask(dmic->irq, cpu_get_id()); + interrupt_enable(dmic->irq, dai); return 0; } static int dmic_remove(struct dai *dai) { - int irq = dmic_irq(dai); + struct dmic_pdata *dmic = dai_get_drvdata(dai); int i; - interrupt_disable(irq, dai); - interrupt_mask(irq, cpu_get_id()); - interrupt_unregister(irq, dai); + interrupt_disable(dmic->irq, dai); + interrupt_mask(dmic->irq, cpu_get_id()); + interrupt_unregister(dmic->irq, dai); pm_runtime_put_sync(DMIC_CLK, dai->index); /* Disable DMIC power */ diff --git a/src/drivers/intel/cavs/interrupt.c b/src/drivers/intel/cavs/interrupt.c index e12ba61d9cda..a31f41259c7d 100644 --- a/src/drivers/intel/cavs/interrupt.c +++ b/src/drivers/intel/cavs/interrupt.c @@ -9,7 +9,6 @@ #include #include -#include #include #include #include @@ -137,7 +136,7 @@ void interrupt_mask(uint32_t irq, unsigned int cpu) struct irq_cascade_desc *cascade = container_of(parent, struct irq_cascade_desc, desc); if (parent && cascade->ops->mask) - cascade->ops->mask(parent, irq, cpu); + cascade->ops->mask(parent, irq - cascade->irq_base, cpu); } void interrupt_unmask(uint32_t irq, unsigned int cpu) @@ -146,7 +145,7 @@ void interrupt_unmask(uint32_t irq, unsigned int cpu) struct irq_cascade_desc *cascade = container_of(parent, struct irq_cascade_desc, desc); if (parent && cascade->ops->unmask) - cascade->ops->unmask(parent, irq, cpu); + cascade->ops->unmask(parent, irq - cascade->irq_base, cpu); } static void irq_mask(struct irq_desc *desc, uint32_t irq, unsigned int core) @@ -154,16 +153,16 @@ static void irq_mask(struct irq_desc *desc, uint32_t irq, unsigned int core) /* mask external interrupt bit */ switch (desc->irq) { case IRQ_NUM_EXT_LEVEL5: - irq_write(REG_IRQ_IL5MSD(core), 1 << SOF_IRQ_BIT(irq)); + irq_write(REG_IRQ_IL5MSD(core), 1 << irq); break; case IRQ_NUM_EXT_LEVEL4: - irq_write(REG_IRQ_IL4MSD(core), 1 << SOF_IRQ_BIT(irq)); + irq_write(REG_IRQ_IL4MSD(core), 1 << irq); break; case IRQ_NUM_EXT_LEVEL3: - irq_write(REG_IRQ_IL3MSD(core), 1 << SOF_IRQ_BIT(irq)); + irq_write(REG_IRQ_IL3MSD(core), 1 << irq); break; case IRQ_NUM_EXT_LEVEL2: - irq_write(REG_IRQ_IL2MSD(core), 1 << SOF_IRQ_BIT(irq)); + irq_write(REG_IRQ_IL2MSD(core), 1 << irq); break; } } @@ -173,16 +172,16 @@ static void irq_unmask(struct irq_desc *desc, uint32_t irq, unsigned int core) /* unmask external interrupt bit */ switch (desc->irq) { case IRQ_NUM_EXT_LEVEL5: - irq_write(REG_IRQ_IL5MCD(core), 1 << SOF_IRQ_BIT(irq)); + irq_write(REG_IRQ_IL5MCD(core), 1 << irq); break; case IRQ_NUM_EXT_LEVEL4: - irq_write(REG_IRQ_IL4MCD(core), 1 << SOF_IRQ_BIT(irq)); + irq_write(REG_IRQ_IL4MCD(core), 1 << irq); break; case IRQ_NUM_EXT_LEVEL3: - irq_write(REG_IRQ_IL3MCD(core), 1 << SOF_IRQ_BIT(irq)); + irq_write(REG_IRQ_IL3MCD(core), 1 << irq); break; case IRQ_NUM_EXT_LEVEL2: - irq_write(REG_IRQ_IL2MCD(core), 1 << SOF_IRQ_BIT(irq)); + irq_write(REG_IRQ_IL2MCD(core), 1 << irq); break; } } diff --git a/src/drivers/intel/cavs/ipc.c b/src/drivers/intel/cavs/ipc.c index e151ae135a8d..75cc5d86a4c1 100644 --- a/src/drivers/intel/cavs/ipc.c +++ b/src/drivers/intel/cavs/ipc.c @@ -231,6 +231,8 @@ void ipc_platform_send_msg(struct ipc *ipc) int platform_ipc_init(struct ipc *ipc) { + int irq; + _ipc = ipc; ipc_set_drvdata(_ipc, NULL); @@ -240,9 +242,12 @@ int platform_ipc_init(struct ipc *ipc) ipc_process_task, _ipc, 0, 0); /* configure interrupt */ - interrupt_register(PLATFORM_IPC_INTERRUPT, IRQ_AUTO_UNMASK, - ipc_irq_handler, ipc); - interrupt_enable(PLATFORM_IPC_INTERRUPT, ipc); + irq = interrupt_get_irq(PLATFORM_IPC_INTERRUPT, + PLATFORM_IPC_INTERRUPT_NAME); + if (irq < 0) + return irq; + interrupt_register(irq, IRQ_AUTO_UNMASK, ipc_irq_handler, ipc); + interrupt_enable(irq, ipc); /* enable IPC interrupts from host */ ipc_write(IPC_DIPCCTL, IPC_DIPCCTL_IPCIDIE | IPC_DIPCCTL_IPCTBIE); diff --git a/src/drivers/intel/cavs/timer.c b/src/drivers/intel/cavs/timer.c index 7c025d732c0e..dd78802704ab 100644 --- a/src/drivers/intel/cavs/timer.c +++ b/src/drivers/intel/cavs/timer.c @@ -95,17 +95,22 @@ 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) { + struct timer_irq *tirq = timer->tirq; int err; /* register timer interrupt */ - err = interrupt_register(timer->irq, IRQ_MANUAL_UNMASK, handler, arg); + tirq->logical_irq = interrupt_get_irq(timer->irq, timer->irq_name); + if (tirq->logical_irq < 0) + return tirq->logical_irq; + err = interrupt_register(tirq->logical_irq, IRQ_MANUAL_UNMASK, handler, + arg); if (err < 0) return err; - timer->irq_arg = arg; + tirq->irq_arg = arg; /* enable timer interrupt */ - interrupt_enable(timer->irq, arg); + interrupt_enable(tirq->logical_irq, arg); /* disable timer interrupt on core level */ timer_disable(timer); @@ -115,6 +120,7 @@ static int platform_timer_register(struct timer *timer, int timer_register(struct timer *timer, void(*handler)(void *arg), void *arg) { + struct timer_irq *tirq = timer->tirq; int ret; switch (timer->id) { @@ -122,38 +128,48 @@ int timer_register(struct timer *timer, void(*handler)(void *arg), void *arg) case TIMER1: case TIMER2: ret = arch_timer_register(timer, handler, arg); + if (ret < 0) + return ret; /* * Actually this isn't needed for arch_interrupt_register(), * since arch_interrupt_unregister() doesn't support interrupt * sharing and thus doesn't need the handler argument to locate * the handler, do it just for uniformity */ - if (!ret) - timer->irq_arg = arg; - return ret; + tirq->irq_arg = arg; + break; case TIMER3: - return platform_timer_register(timer, handler, arg); + ret = platform_timer_register(timer, handler, arg); + if (ret < 0) + return ret; + break; default: return -EINVAL; } + + return ret; } static void platform_timer_unregister(struct timer *timer) { + struct timer_irq *tirq = timer->tirq; + /* disable timer interrupt */ - interrupt_disable(timer->irq, timer->irq_arg); + interrupt_disable(tirq->logical_irq, tirq->irq_arg); /* unregister timer interrupt */ - interrupt_unregister(timer->irq, timer->irq_arg); + interrupt_unregister(tirq->logical_irq, tirq->irq_arg); } void timer_unregister(struct timer *timer) { + struct timer_irq *tirq = timer->tirq; + switch (timer->id) { case TIMER0: case TIMER1: case TIMER2: - interrupt_unregister(timer->irq, timer->irq_arg); + interrupt_unregister(tirq->logical_irq, tirq->irq_arg); break; case TIMER3: platform_timer_unregister(timer); @@ -163,28 +179,32 @@ void timer_unregister(struct timer *timer) void timer_enable(struct timer *timer) { + struct timer_irq *tirq = timer->tirq; + switch (timer->id) { case TIMER0: case TIMER1: case TIMER2: - interrupt_enable(timer->irq, timer->irq_arg); + interrupt_enable(tirq->logical_irq, tirq->irq_arg); break; case TIMER3: - interrupt_unmask(timer->irq, timer->core); + interrupt_unmask(tirq->logical_irq, timer->core); break; } } void timer_disable(struct timer *timer) { + struct timer_irq *tirq = timer->tirq; + switch (timer->id) { case TIMER0: case TIMER1: case TIMER2: - interrupt_disable(timer->irq, timer->irq_arg); + interrupt_disable(tirq->logical_irq, tirq->irq_arg); break; case TIMER3: - interrupt_mask(timer->irq, timer->core); + interrupt_mask(tirq->logical_irq, timer->core); break; } } diff --git a/src/drivers/intel/haswell/timer.c b/src/drivers/intel/haswell/timer.c index b49a3243f2c1..03be80c3d0f5 100644 --- a/src/drivers/intel/haswell/timer.c +++ b/src/drivers/intel/haswell/timer.c @@ -76,7 +76,9 @@ void platform_dai_wallclock(struct comp_dev *dai, uint64_t *wallclock) int timer_register(struct timer *timer, void(*handler)(void *arg), void *arg) { - timer->irq_arg = arg; + struct timer_irq *tirq = timer->tirq; + + tirq->irq_arg = arg; switch (timer->id) { case TIMER0: @@ -90,15 +92,21 @@ int timer_register(struct timer *timer, void(*handler)(void *arg), void *arg) void timer_unregister(struct timer *timer) { - interrupt_unregister(timer->irq, timer->irq_arg); + struct timer_irq *tirq = timer->tirq; + + interrupt_unregister(timer->irq, tirq->irq_arg); } void timer_enable(struct timer *timer) { - interrupt_enable(timer->irq, timer->irq_arg); + struct timer_irq *tirq = timer->tirq; + + interrupt_enable(timer->irq, tirq->irq_arg); } void timer_disable(struct timer *timer) { - interrupt_disable(timer->irq, timer->irq_arg); + struct timer_irq *tirq = timer->tirq; + + interrupt_disable(timer->irq, tirq->irq_arg); } diff --git a/src/drivers/interrupt.c b/src/drivers/interrupt.c index 2e6dd8b5071e..1bbb4cb066da 100644 --- a/src/drivers/interrupt.c +++ b/src/drivers/interrupt.c @@ -7,7 +7,6 @@ #include #include -#include #include #include #include @@ -20,7 +19,10 @@ static spinlock_t cascade_lock; static union { - struct irq_cascade_desc *list __aligned(PLATFORM_DCACHE_ALIGN); + struct { + struct irq_cascade_desc *list; + int last_irq; + } __aligned(PLATFORM_DCACHE_ALIGN); uint8_t bytes[PLATFORM_DCACHE_ALIGN]; } cascade_root; @@ -58,14 +60,14 @@ int interrupt_cascade_register(const struct irq_cascade_tmpl *tmpl) (*cascade)->name = tmpl->name; (*cascade)->ops = tmpl->ops; (*cascade)->global_mask = tmpl->global_mask; + (*cascade)->irq_base = cascade_root.last_irq + 1; (*cascade)->desc.irq = tmpl->irq; (*cascade)->desc.handler = tmpl->handler; (*cascade)->desc.handler_arg = &(*cascade)->desc; (*cascade)->desc.cpu_mask = 1 << cpu_get_id(); - if (cascade == &cascade_root.list) - /* First descriptor */ - dcache_writeback_region(&cascade_root, sizeof(cascade_root)); + cascade_root.last_irq += ARRAY_SIZE((*cascade)->child); + dcache_writeback_region(&cascade_root, sizeof(cascade_root)); ret = 0; @@ -75,6 +77,38 @@ int interrupt_cascade_register(const struct irq_cascade_tmpl *tmpl) return ret; } +int interrupt_get_irq(unsigned int irq, const char *name) +{ + struct irq_cascade_desc *cascade; + unsigned long flags; + int ret = -ENODEV; + + if (!name || name[0] == '\0') + return irq; + + /* If a name is specified, irq must be <= PLATFORM_IRQ_CHILDREN */ + if (irq >= PLATFORM_IRQ_CHILDREN) { + trace_error(TRACE_CLASS_IRQ, + "error: IRQ %d invalid as a child interrupt!"); + return -EINVAL; + } + + spin_lock_irq(&cascade_lock, flags); + + dcache_invalidate_region(&cascade_root, sizeof(cascade_root)); + + for (cascade = cascade_root.list; cascade; cascade = cascade->next) + /* .name is non-volatile */ + if (!rstrcmp(name, cascade->name)) { + ret = cascade->irq_base + irq; + break; + } + + spin_unlock_irq(&cascade_lock, flags); + + return ret; +} + struct irq_desc *interrupt_get_parent(uint32_t irq) { struct irq_cascade_desc *cascade; @@ -89,7 +123,8 @@ struct irq_desc *interrupt_get_parent(uint32_t irq) dcache_invalidate_region(&cascade_root, sizeof(cascade_root)); for (cascade = cascade_root.list; cascade; cascade = cascade->next) - if (SOF_IRQ_NUMBER(irq) == cascade->desc.irq) { + if (irq >= cascade->irq_base && + irq < cascade->irq_base + PLATFORM_IRQ_CHILDREN) { parent = &cascade->desc; break; } @@ -101,6 +136,8 @@ struct irq_desc *interrupt_get_parent(uint32_t irq) void interrupt_init(void) { + cascade_root.last_irq = PLATFORM_IRQ_CHILDREN - 1; + dcache_writeback_region(&cascade_root, sizeof(cascade_root)); spinlock_init(&cascade_lock); } @@ -108,19 +145,27 @@ static int irq_register_child(struct irq_desc *parent, int irq, int unmask, void (*handler)(void *arg), void *arg) { unsigned int core = cpu_get_id(); - int ret = 0; struct irq_desc *child; struct irq_cascade_desc *cascade; struct list_item *list, *head; + int hw_irq, ret = 0; if (parent == NULL) return -EINVAL; cascade = container_of(parent, struct irq_cascade_desc, desc); - head = &cascade->child[SOF_IRQ_BIT(irq)].list; spin_lock(&cascade->lock); + hw_irq = irq - cascade->irq_base; + + if (hw_irq < 0 || cascade->irq_base + PLATFORM_IRQ_CHILDREN <= irq) { + ret = -EINVAL; + goto finish; + } + + head = &cascade->child[hw_irq].list; + list_for_item(list, head) { child = container_of(list, struct irq_desc, irq_list); @@ -128,6 +173,13 @@ static int irq_register_child(struct irq_desc *parent, int irq, int unmask, trace_error(TRACE_CLASS_IRQ, "error: IRQ 0x%x handler argument re-used!", irq); + ret = -EEXIST; + goto finish; + } + + if (child->unmask != unmask) { + trace_error(TRACE_CLASS_IRQ, + "error: IRQ 0x%x flags differ!", irq); ret = -EINVAL; goto finish; } @@ -146,13 +198,14 @@ static int irq_register_child(struct irq_desc *parent, int irq, int unmask, child->handler = handler; child->handler_arg = arg; child->unmask = unmask; + child->irq = irq; list_item_append(&child->irq_list, head); /* do we need to register parent on this CPU? */ if (!cascade->num_children[core]) - ret = arch_interrupt_register(parent->irq, - parent->handler, parent); + ret = interrupt_register(parent->irq, IRQ_AUTO_UNMASK, + parent->handler, parent); /* increment number of children */ if (!ret) @@ -169,15 +222,12 @@ static void irq_unregister_child(struct irq_desc *parent, int irq, struct irq_desc *child; struct irq_cascade_desc *cascade = container_of(parent, struct irq_cascade_desc, desc); - struct list_item *list, *head = &cascade->child[SOF_IRQ_BIT(irq)].list; + int hw_irq = irq - cascade->irq_base; + struct list_item *list, *head = &cascade->child[hw_irq].list; unsigned int core = cpu_get_id(); spin_lock(&cascade->lock); - /* does child already exist ? */ - if (list_is_empty(head)) - goto finish; - list_for_item(list, head) { child = container_of(list, struct irq_desc, irq_list); @@ -191,13 +241,12 @@ static void irq_unregister_child(struct irq_desc *parent, int irq, * registered child. */ if (!cascade->num_children[core]) - arch_interrupt_unregister(parent->irq); + interrupt_unregister(parent->irq, parent); break; } } -finish: spin_unlock(&cascade->lock); } @@ -205,6 +254,7 @@ static uint32_t irq_enable_child(struct irq_desc *parent, int irq, void *arg) { struct irq_cascade_desc *cascade = container_of(parent, struct irq_cascade_desc, desc); + int hw_irq = irq - cascade->irq_base; unsigned int core = cpu_get_id(); struct irq_child *child; unsigned int child_idx; @@ -212,7 +262,7 @@ static uint32_t irq_enable_child(struct irq_desc *parent, int irq, void *arg) spin_lock(&cascade->lock); - child = cascade->child + SOF_IRQ_BIT(irq); + child = cascade->child + hw_irq; child_idx = cascade->global_mask ? 0 : core; list_for_item(list, &child->list) { @@ -228,7 +278,7 @@ static uint32_t irq_enable_child(struct irq_desc *parent, int irq, void *arg) if (!child->enable_count[child_idx]++) { /* enable the parent interrupt */ if (!cascade->enable_count[core]++) - arch_interrupt_enable_mask(1 << parent->irq); + interrupt_enable(parent->irq, parent->handler_arg); /* enable the child interrupt */ interrupt_unmask(irq, core); @@ -243,6 +293,7 @@ static uint32_t irq_disable_child(struct irq_desc *parent, int irq, void *arg) { struct irq_cascade_desc *cascade = container_of(parent, struct irq_cascade_desc, desc); + int hw_irq = irq - cascade->irq_base; unsigned int core = cpu_get_id(); struct irq_child *child; unsigned int child_idx; @@ -250,7 +301,7 @@ static uint32_t irq_disable_child(struct irq_desc *parent, int irq, void *arg) spin_lock(&cascade->lock); - child = cascade->child + SOF_IRQ_BIT(irq); + child = cascade->child + hw_irq; child_idx = cascade->global_mask ? 0 : core; list_for_item(list, &child->list) { @@ -273,7 +324,7 @@ static uint32_t irq_disable_child(struct irq_desc *parent, int irq, void *arg) /* disable the parent interrupt */ if (!--cascade->enable_count[core]) - arch_interrupt_disable_mask(1 << parent->irq); + interrupt_disable(parent->irq, parent->handler_arg); } spin_unlock(&cascade->lock); diff --git a/src/include/sof/drivers/dmic.h b/src/include/sof/drivers/dmic.h index 6328162df3f4..df7e17c836e6 100644 --- a/src/include/sof/drivers/dmic.h +++ b/src/include/sof/drivers/dmic.h @@ -307,8 +307,8 @@ #define FIR_COEF_A(x) SET_BITS(19, 0, x) #define FIR_COEF_B(x) SET_BITS(19, 0, x) -#define dmic_irq(dmic) \ - dmic->plat_data.irq +#define dmic_irq(dmic) dmic->plat_data.irq +#define dmic_irq_name(dmic) dmic->plat_data.irq_name /* DMIC private data */ struct dmic_pdata { @@ -319,6 +319,7 @@ struct dmic_pdata { int32_t startcount; int32_t gain; int32_t gain_coef; + int irq; }; extern const struct dai_driver dmic_driver; diff --git a/src/include/sof/drivers/interrupt.h b/src/include/sof/drivers/interrupt.h index d4dd21aed062..8f086b577afa 100644 --- a/src/include/sof/drivers/interrupt.h +++ b/src/include/sof/drivers/interrupt.h @@ -10,7 +10,6 @@ #include #include -#include #include #include #include @@ -68,6 +67,10 @@ struct irq_cascade_desc { const char *name; /**< name of the * controller */ + int irq_base; /**< first virtual IRQ + * number, assigned to + * this controller + */ const struct irq_cascade_ops *ops; /**< cascading interrupt * controller driver * operations @@ -124,13 +127,15 @@ void interrupt_unmask(uint32_t irq, unsigned int cpu); /* * On platforms, supporting cascading interrupts cascaded interrupt numbers - * have SOF_IRQ_LEVEL(irq) != 0. + * are greater than or equal to PLATFORM_IRQ_CHILDREN */ -#define interrupt_is_dsp_direct(irq) (!SOF_IRQ_LEVEL(irq)) +#define interrupt_is_dsp_direct(irq) (!PLATFORM_IRQ_CHILDREN || \ + irq < PLATFORM_IRQ_CHILDREN) void interrupt_init(void); int interrupt_cascade_register(const struct irq_cascade_tmpl *tmpl); struct irq_desc *interrupt_get_parent(uint32_t irq); +int interrupt_get_irq(unsigned int irq, const char *cascade); static inline void interrupt_set(int irq) { diff --git a/src/include/sof/drivers/timer.h b/src/include/sof/drivers/timer.h index 6194652eb28e..a30a399821f1 100644 --- a/src/include/sof/drivers/timer.h +++ b/src/include/sof/drivers/timer.h @@ -24,6 +24,8 @@ struct timesource_data { uint64_t (*timer_get)(struct timer *t); }; +extern struct timesource_data platform_generic_queue[]; + int timer_register(struct timer *timer, void (*handler)(void *arg), void *arg); void timer_unregister(struct timer *timer); diff --git a/src/include/sof/lib/dai.h b/src/include/sof/lib/dai.h index 88abce42ff26..04376a023a7f 100644 --- a/src/include/sof/lib/dai.h +++ b/src/include/sof/lib/dai.h @@ -100,7 +100,8 @@ struct dai_plat_fifo_data { */ struct dai_plat_data { uint32_t base; - uint32_t irq; + int irq; + const char *irq_name; uint32_t flags; struct dai_plat_fifo_data fifo[2]; }; diff --git a/src/include/sof/lib/dma.h b/src/include/sof/lib/dma.h index 8f4b93f0a4c1..bbc7b5372e43 100644 --- a/src/include/sof/lib/dma.h +++ b/src/include/sof/lib/dma.h @@ -19,7 +19,6 @@ #include #include #include -#include #include #include #include @@ -176,7 +175,8 @@ struct dma_plat_data { uint32_t devs; /* bitmask of supported devs */ uint32_t base; uint32_t channels; - uint32_t irq; + int irq; + const char *irq_name; uint32_t chan_size; void *drv_plat_data; }; @@ -223,8 +223,10 @@ void dma_put(struct dma *dma); dma->private #define dma_base(dma) \ dma->plat_data.base -#define dma_irq(dma, cpu) \ - (dma->plat_data.irq + (cpu << SOF_IRQ_CPU_SHIFT)) +#define dma_irq(dma) \ + dma->plat_data.irq +#define dma_irq_name(dma) \ + dma->plat_data.irq_name #define dma_chan_size(dma) \ dma->plat_data.chan_size #define dma_chan_base(dma, chan) \ diff --git a/src/include/sof/schedule/ll_schedule.h b/src/include/sof/schedule/ll_schedule.h index 94979fba9853..0951cbd00ed2 100644 --- a/src/include/sof/schedule/ll_schedule.h +++ b/src/include/sof/schedule/ll_schedule.h @@ -13,7 +13,6 @@ #ifndef __SOF_SCHEDULE_LL_SCHEDULE_H__ #define __SOF_SCHEDULE_LL_SCHEDULE_H__ -#include #include #include #include @@ -38,6 +37,4 @@ struct ll_task_pdata { uint32_t flags; }; -extern struct timesource_data platform_generic_queue[]; - #endif /* __SOF_SCHEDULE_LL_SCHEDULE_H__ */ diff --git a/src/platform/apollolake/include/platform/drivers/interrupt.h b/src/platform/apollolake/include/platform/drivers/interrupt.h index d75e2a69b00d..7472693e3ffb 100644 --- a/src/platform/apollolake/include/platform/drivers/interrupt.h +++ b/src/platform/apollolake/include/platform/drivers/interrupt.h @@ -11,8 +11,6 @@ #ifndef __PLATFORM_DRIVERS_INTERRUPT_H__ #define __PLATFORM_DRIVERS_INTERRUPT_H__ -#include - #define PLATFORM_IRQ_CHILDREN 32 /* IRQ numbers - wrt Tensilica DSP */ @@ -66,52 +64,31 @@ #define IRQ_BIT_LVL5_SSP(x) (0 + x) /* Level 2 Peripheral IRQ mappings */ -#define IRQ_EXT_HP_GPDMA_LVL2(xcpu) \ - SOF_IRQ(IRQ_BIT_LVL2_HP_GP_DMA0(0), 2, xcpu, IRQ_NUM_EXT_LEVEL2) -#define IRQ_EXT_IDC_LVL2(xcpu) \ - SOF_IRQ(IRQ_BIT_LVL2_IDC, 2, xcpu, IRQ_NUM_EXT_LEVEL2) -#define IRQ_EXT_IPC_LVL2(xcpu) \ - SOF_IRQ(IRQ_BIT_LVL2_HOST_IPC, 2, xcpu, IRQ_NUM_EXT_LEVEL2) -#define IRQ_EXT_TSTAMP1_LVL2(xcpu) \ - SOF_IRQ(IRQ_BIT_LVL2_WALL_CLK1, 2, xcpu, IRQ_NUM_EXT_LEVEL2) -#define IRQ_EXT_TSTAMP0_LVL2(xcpu) \ - SOF_IRQ(IRQ_BIT_LVL2_WALL_CLK0, 2, xcpu, IRQ_NUM_EXT_LEVEL2) -#define IRQ_EXT_MERR_LVL2(xcpu) \ - SOF_IRQ(IRQ_BIT_LVL2_L2_MEMERR, 2, xcpu, IRQ_NUM_EXT_LEVEL2) -#define IRQ_EXT_L2CACHE_LVL2(xcpu) \ - SOF_IRQ(IRQ_BIT_LVL2_L2_CACHE, 2, xcpu, IRQ_NUM_EXT_LEVEL2) -#define IRQ_EXT_SHA256_LVL2(xcpu) \ - SOF_IRQ(IRQ_BIT_LVL2_SHA256, 2, xcpu, IRQ_NUM_EXT_LEVEL2) +#define IRQ_EXT_HP_GPDMA_LVL2 IRQ_BIT_LVL2_HP_GP_DMA0(0) +#define IRQ_EXT_IDC_LVL2 IRQ_BIT_LVL2_IDC +#define IRQ_EXT_IPC_LVL2 IRQ_BIT_LVL2_HOST_IPC +#define IRQ_EXT_TSTAMP1_LVL2 IRQ_BIT_LVL2_WALL_CLK1 +#define IRQ_EXT_TSTAMP0_LVL2 IRQ_BIT_LVL2_WALL_CLK0 +#define IRQ_EXT_MERR_LVL2 IRQ_BIT_LVL2_L2_MEMERR +#define IRQ_EXT_L2CACHE_LVL2 IRQ_BIT_LVL2_L2_CACHE +#define IRQ_EXT_SHA256_LVL2 IRQ_BIT_LVL2_SHA256 /* Level 3 Peripheral IRQ mappings */ -#define IRQ_EXT_CODE_DMA_LVL3(xcpu) \ - SOF_IRQ(IRQ_BIT_LVL3_CODE_LOADER, 3, xcpu, IRQ_NUM_EXT_LEVEL3) -#define IRQ_EXT_HOST_DMA_IN_LVL3(xcpu, channel) \ - SOF_IRQ(IRQ_BIT_LVL3_HOST_STREAM_IN(channel), 3, xcpu, \ - IRQ_NUM_EXT_LEVEL3) -#define IRQ_EXT_HOST_DMA_OUT_LVL3(xcpu, channel) \ - SOF_IRQ(IRQ_BIT_LVL3_HOST_STREAM_OUT(channel), 3, xcpu, \ - IRQ_NUM_EXT_LEVEL3) +#define IRQ_EXT_CODE_DMA_LVL3 IRQ_BIT_LVL3_CODE_LOADER +#define IRQ_EXT_HOST_DMA_IN_LVL3(channel) IRQ_BIT_LVL3_HOST_STREAM_IN(channel) +#define IRQ_EXT_HOST_DMA_OUT_LVL3(channel) IRQ_BIT_LVL3_HOST_STREAM_OUT(channel) /* Level 4 Peripheral IRQ mappings */ -#define IRQ_EXT_LINK_DMA_IN_LVL4(xcpu, channel) \ - SOF_IRQ(IRQ_BIT_LVL4_LINK_STREAM_IN(channel), 4, xcpu, \ - IRQ_NUM_EXT_LEVEL4) -#define IRQ_EXT_LINK_DMA_OUT_LVL4(xcpu, channel) \ - SOF_IRQ(IRQ_BIT_LVL4_LINK_STREAM_OUT(channel), 4, xcpu, \ - IRQ_NUM_EXT_LEVEL4) +#define IRQ_EXT_LINK_DMA_IN_LVL4(channel) IRQ_BIT_LVL4_LINK_STREAM_IN(channel) +#define IRQ_EXT_LINK_DMA_OUT_LVL4(channel) IRQ_BIT_LVL4_LINK_STREAM_OUT(channel) /* Level 5 Peripheral IRQ mappings */ -#define IRQ_EXT_LP_GPDMA0_LVL5(xcpu, channel) \ - SOF_IRQ(IRQ_BIT_LVL5_LP_GP_DMA0(channel), 5, xcpu, IRQ_NUM_EXT_LEVEL5) -#define IRQ_EXT_LP_GPDMA1_LVL5(xcpu, channel) \ - SOF_IRQ(IRQ_BIT_LVL5_LP_GP_DMA1(channel), 5, xcpu, IRQ_NUM_EXT_LEVEL5) +#define IRQ_EXT_LP_GPDMA0_LVL5(channel) IRQ_BIT_LVL5_LP_GP_DMA0(channel) +#define IRQ_EXT_LP_GPDMA1_LVL5(channel) IRQ_BIT_LVL5_LP_GP_DMA1(channel) -#define IRQ_EXT_SSPx_LVL5(x, xcpu) \ - SOF_IRQ(IRQ_BIT_LVL5_SSP(x), 5, xcpu, IRQ_NUM_EXT_LEVEL5) +#define IRQ_EXT_SSPx_LVL5(x) IRQ_BIT_LVL5_SSP(x) -#define IRQ_EXT_DMIC_LVL5(x, xcpu) \ - SOF_IRQ(IRQ_BIT_LVL5_DMIC(x), 5, xcpu, IRQ_NUM_EXT_LEVEL5) +#define IRQ_EXT_DMIC_LVL5(x) IRQ_BIT_LVL5_DMIC(x) /* IRQ Masks */ diff --git a/src/platform/apollolake/include/platform/drivers/timer.h b/src/platform/apollolake/include/platform/drivers/timer.h index ea6a0b0f77b2..09711cc99916 100644 --- a/src/platform/apollolake/include/platform/drivers/timer.h +++ b/src/platform/apollolake/include/platform/drivers/timer.h @@ -19,8 +19,8 @@ #define TIMER0 IRQ_NUM_TIMER1 #define TIMER1 IRQ_NUM_TIMER2 #define TIMER2 IRQ_NUM_TIMER3 -#define TIMER3 IRQ_EXT_TSTAMP0_LVL2(0) -#define TIMER4 IRQ_EXT_TSTAMP1_LVL2(0) +#define TIMER3 IRQ_EXT_TSTAMP0_LVL2 +#define TIMER4 IRQ_EXT_TSTAMP1_LVL2 #endif /* __PLATFORM_DRIVERS_TIMER_H__ */ diff --git a/src/platform/apollolake/include/platform/lib/dma.h b/src/platform/apollolake/include/platform/lib/dma.h index 08c833ea47fd..3c9109b3d8cd 100644 --- a/src/platform/apollolake/include/platform/lib/dma.h +++ b/src/platform/apollolake/include/platform/lib/dma.h @@ -11,8 +11,6 @@ #ifndef __PLATFORM_LIB_DMA_H__ #define __PLATFORM_LIB_DMA_H__ -#include - /* available DMACs */ #define DMA_GP_LP_DMAC0 0 #define DMA_GP_LP_DMAC1 1 @@ -49,8 +47,7 @@ #define DMA_HANDSHAKE_SSP5_TX 12 #define DMA_HANDSHAKE_SSP5_RX 13 -#define dma_chan_irq(dma, cpu, chan) \ - (dma_irq(dma, cpu) + (channel << SOF_IRQ_BIT_SHIFT)) +#define dma_chan_irq(dma, chan) (dma_irq(dma) + channel) int dmac_init(void); diff --git a/src/platform/apollolake/include/platform/platform.h b/src/platform/apollolake/include/platform/platform.h index 2ab8f20193d3..0ec725e285fd 100644 --- a/src/platform/apollolake/include/platform/platform.h +++ b/src/platform/apollolake/include/platform/platform.h @@ -21,6 +21,7 @@ #include #include #include +#include #include struct timer; @@ -39,17 +40,23 @@ struct timer; #define PLATFORM_PAGE_TABLE_SIZE 256 /* IDC Interrupt */ -#define PLATFORM_IDC_INTERRUPT(x) IRQ_EXT_IDC_LVL2(x) +#define PLATFORM_IDC_INTERRUPT IRQ_EXT_IDC_LVL2 +#define PLATFORM_IDC_INTERRUPT_NAME irq_name_level2 /* IPC Interrupt */ -#define PLATFORM_IPC_INTERRUPT IRQ_EXT_IPC_LVL2(0) +#define PLATFORM_IPC_INTERRUPT IRQ_BIT_LVL2_HOST_IPC +#define PLATFORM_IPC_INTERRUPT_NAME irq_name_level2 /* pipeline IRQ */ -#define PLATFORM_SCHEDULE_IRQ IRQ_NUM_SOFTWARE4 +#define PLATFORM_SCHEDULE_IRQ IRQ_NUM_SOFTWARE4 +#define PLATFORM_SCHEDULE_IRQ_NAME NULL #define PLATFORM_IRQ_TASK_HIGH IRQ_NUM_SOFTWARE3 +#define PLATFORM_IRQ_TASK_HIGH_NAME NULL #define PLATFORM_IRQ_TASK_MED IRQ_NUM_SOFTWARE2 +#define PLATFORM_IRQ_TASK_MED_NAME NULL #define PLATFORM_IRQ_TASK_LOW IRQ_NUM_SOFTWARE1 +#define PLATFORM_IRQ_TASK_LOW_NAME NULL #define PLATFORM_SCHEDULE_COST 200 diff --git a/src/platform/baytrail/include/platform/lib/dma.h b/src/platform/baytrail/include/platform/lib/dma.h index ebe16b802c96..b9e8539d5cdd 100644 --- a/src/platform/baytrail/include/platform/lib/dma.h +++ b/src/platform/baytrail/include/platform/lib/dma.h @@ -38,7 +38,7 @@ #define DMA_HANDSHAKE_SSP6_RX 12 #define DMA_HANDSHAKE_SSP6_TX 13 -#define dma_chan_irq(dma, cpu, chan) dma_irq(dma, cpu) +#define dma_chan_irq(dma, chan) dma_irq(dma) int dmac_init(void); diff --git a/src/platform/baytrail/include/platform/platform.h b/src/platform/baytrail/include/platform/platform.h index 65f24cabeb16..d9f8d7f41802 100644 --- a/src/platform/baytrail/include/platform/platform.h +++ b/src/platform/baytrail/include/platform/platform.h @@ -24,6 +24,7 @@ #include #include #include +#include #include struct timer; @@ -44,6 +45,7 @@ struct timer; /* IPC Interrupt */ #define PLATFORM_IPC_INTERRUPT IRQ_NUM_EXT_IA +#define PLATFORM_IPC_INTERRUPT_NAME NULL /* Host page size */ #define HOST_PAGE_SIZE 4096 @@ -51,10 +53,14 @@ struct timer; /* pipeline IRQ */ #define PLATFORM_SCHEDULE_IRQ IRQ_NUM_SOFTWARE5 +#define PLATFORM_SCHEDULE_IRQ_NAME NULL #define PLATFORM_IRQ_TASK_HIGH IRQ_NUM_SOFTWARE4 +#define PLATFORM_IRQ_TASK_HIGH_NAME NULL #define PLATFORM_IRQ_TASK_MED IRQ_NUM_SOFTWARE3 +#define PLATFORM_IRQ_TASK_MED_NAME NULL #define PLATFORM_IRQ_TASK_LOW IRQ_NUM_SOFTWARE2 +#define PLATFORM_IRQ_TASK_LOW_NAME NULL #define PLATFORM_SCHEDULE_COST 200 diff --git a/src/platform/cannonlake/include/platform/drivers/interrupt.h b/src/platform/cannonlake/include/platform/drivers/interrupt.h index 76004e405a0c..262f2b8dd88d 100644 --- a/src/platform/cannonlake/include/platform/drivers/interrupt.h +++ b/src/platform/cannonlake/include/platform/drivers/interrupt.h @@ -12,8 +12,6 @@ #ifndef __PLATFORM_DRIVERS_INTERRUPT_H__ #define __PLATFORM_DRIVERS_INTERRUPT_H__ -#include - #define PLATFORM_IRQ_CHILDREN 32 /* IRQ numbers - wrt Tensilica DSP */ @@ -67,52 +65,31 @@ #define IRQ_BIT_LVL5_SSP(x) (0 + x) /* Priority 2 Peripheral IRQ mappings */ -#define IRQ_EXT_HP_GPDMA_LVL2(xcpu) \ - SOF_IRQ(IRQ_BIT_LVL2_HP_GP_DMA0(0), 2, xcpu, IRQ_NUM_EXT_LEVEL2) -#define IRQ_EXT_IDC_LVL2(xcpu) \ - SOF_IRQ(IRQ_BIT_LVL2_IDC, 2, xcpu, IRQ_NUM_EXT_LEVEL2) -#define IRQ_EXT_IPC_LVL2(xcpu) \ - SOF_IRQ(IRQ_BIT_LVL2_HOST_IPC, 2, xcpu, IRQ_NUM_EXT_LEVEL2) -#define IRQ_EXT_TSTAMP1_LVL2(xcpu) \ - SOF_IRQ(IRQ_BIT_LVL2_WALL_CLK1, 2, xcpu, IRQ_NUM_EXT_LEVEL2) -#define IRQ_EXT_TSTAMP0_LVL2(xcpu) \ - SOF_IRQ(IRQ_BIT_LVL2_WALL_CLK0, 2, xcpu, IRQ_NUM_EXT_LEVEL2) -#define IRQ_EXT_MERR_LVL2(xcpu) \ - SOF_IRQ(IRQ_BIT_LVL2_L2_MEMERR, 2, xcpu, IRQ_NUM_EXT_LEVEL2) -#define IRQ_EXT_L2CACHE_LVL2(xcpu) \ - SOF_IRQ(IRQ_BIT_LVL2_L2_CACHE, 2, xcpu, IRQ_NUM_EXT_LEVEL2) -#define IRQ_EXT_SHA256_LVL2(xcpu) \ - SOF_IRQ(IRQ_BIT_LVL2_SHA256, 2, xcpu, IRQ_NUM_EXT_LEVEL2) +#define IRQ_EXT_HP_GPDMA_LVL2 IRQ_BIT_LVL2_HP_GP_DMA0(0) +#define IRQ_EXT_IDC_LVL2 IRQ_BIT_LVL2_IDC +#define IRQ_EXT_IPC_LVL2 IRQ_BIT_LVL2_HOST_IPC +#define IRQ_EXT_TSTAMP1_LVL2 IRQ_BIT_LVL2_WALL_CLK1 +#define IRQ_EXT_TSTAMP0_LVL2 IRQ_BIT_LVL2_WALL_CLK0 +#define IRQ_EXT_MERR_LVL2 IRQ_BIT_LVL2_L2_MEMERR +#define IRQ_EXT_L2CACHE_LVL2 IRQ_BIT_LVL2_L2_CACHE +#define IRQ_EXT_SHA256_LVL2 IRQ_BIT_LVL2_SHA256 /* Priority 3 Peripheral IRQ mappings */ -#define IRQ_EXT_CODE_DMA_LVL3(xcpu) \ - SOF_IRQ(IRQ_BIT_LVL3_CODE_LOADER, 3, xcpu, IRQ_NUM_EXT_LEVEL3) -#define IRQ_EXT_HOST_DMA_IN_LVL3(xcpu, channel) \ - SOF_IRQ(IRQ_BIT_LVL3_HOST_STREAM_IN(channel), 3, xcpu, \ - IRQ_NUM_EXT_LEVEL3) -#define IRQ_EXT_HOST_DMA_OUT_LVL3(xcpu, channel) \ - SOF_IRQ(IRQ_BIT_LVL3_HOST_STREAM_OUT(channel), 3, xcpu, \ - IRQ_NUM_EXT_LEVEL3) +#define IRQ_EXT_CODE_DMA_LVL3 IRQ_BIT_LVL3_CODE_LOADER +#define IRQ_EXT_HOST_DMA_IN_LVL3(channel) IRQ_BIT_LVL3_HOST_STREAM_IN(channel) +#define IRQ_EXT_HOST_DMA_OUT_LVL3(channel) IRQ_BIT_LVL3_HOST_STREAM_OUT(channel) /* Priority 4 Peripheral IRQ mappings */ -#define IRQ_EXT_LINK_DMA_IN_LVL4(xcpu, channel) \ - SOF_IRQ(IRQ_BIT_LVL4_LINK_STREAM_IN(channel), 4, xcpu, \ - IRQ_NUM_EXT_LEVEL4) -#define IRQ_EXT_LINK_DMA_OUT_LVL4(xcpu, channel) \ - SOF_IRQ(IRQ_BIT_LVL4_LINK_STREAM_OUT(channel), 4, xcpu, \ - IRQ_NUM_EXT_LEVEL4) +#define IRQ_EXT_LINK_DMA_IN_LVL4(channel) IRQ_BIT_LVL4_LINK_STREAM_IN(channel) +#define IRQ_EXT_LINK_DMA_OUT_LVL4(channel) IRQ_BIT_LVL4_LINK_STREAM_OUT(channel) /* Priority 5 Peripheral IRQ mappings */ -#define IRQ_EXT_LP_GPDMA0_LVL5(xcpu, channel) \ - SOF_ID_IRQ(0, IRQ_BIT_LVL5_LP_GP_DMA0, 5, xcpu, IRQ_NUM_EXT_LEVEL5) -#define IRQ_EXT_LP_GPDMA1_LVL5(xcpu, channel) \ - SOF_ID_IRQ(1, IRQ_BIT_LVL5_LP_GP_DMA0, 5, xcpu, IRQ_NUM_EXT_LEVEL5) +#define IRQ_EXT_LP_GPDMA0_LVL5(channel) IRQ_BIT_LVL5_LP_GP_DMA0 +#define IRQ_EXT_LP_GPDMA1_LVL5(channel) IRQ_BIT_LVL5_LP_GP_DMA0 -#define IRQ_EXT_SSPx_LVL5(x, xcpu) \ - SOF_IRQ(IRQ_BIT_LVL5_SSP(x), 5, xcpu, IRQ_NUM_EXT_LEVEL5) +#define IRQ_EXT_SSPx_LVL5(x) IRQ_BIT_LVL5_SSP(x) -#define IRQ_EXT_DMIC_LVL5(x, xcpu) \ - SOF_IRQ(IRQ_BIT_LVL5_DMIC(x), 5, xcpu, IRQ_NUM_EXT_LEVEL5) +#define IRQ_EXT_DMIC_LVL5(x) IRQ_BIT_LVL5_DMIC(x) /* IRQ Masks */ diff --git a/src/platform/cannonlake/include/platform/drivers/timer.h b/src/platform/cannonlake/include/platform/drivers/timer.h index 92a49cebc7ef..cf4ea48174af 100644 --- a/src/platform/cannonlake/include/platform/drivers/timer.h +++ b/src/platform/cannonlake/include/platform/drivers/timer.h @@ -20,8 +20,8 @@ #define TIMER0 IRQ_NUM_TIMER1 #define TIMER1 IRQ_NUM_TIMER2 #define TIMER2 IRQ_NUM_TIMER3 -#define TIMER3 IRQ_EXT_TSTAMP0_LVL2(0) -#define TIMER4 IRQ_EXT_TSTAMP1_LVL2(0) +#define TIMER3 IRQ_EXT_TSTAMP0_LVL2 +#define TIMER4 IRQ_EXT_TSTAMP1_LVL2 #endif /* __PLATFORM_DRIVERS_TIMER_H__ */ diff --git a/src/platform/cannonlake/include/platform/lib/dma.h b/src/platform/cannonlake/include/platform/lib/dma.h index 4e88bdf95bcc..3768296b9b4b 100644 --- a/src/platform/cannonlake/include/platform/lib/dma.h +++ b/src/platform/cannonlake/include/platform/lib/dma.h @@ -48,7 +48,7 @@ #define DMA_HANDSHAKE_SSP5_TX 12 #define DMA_HANDSHAKE_SSP5_RX 13 -#define dma_chan_irq(dma, cpu, chan) dma_irq(dma, cpu) +#define dma_chan_irq(dma, chan) dma_irq(dma) int dmac_init(void); diff --git a/src/platform/cannonlake/include/platform/platform.h b/src/platform/cannonlake/include/platform/platform.h index 5b593f1bf90e..85498857f5f5 100644 --- a/src/platform/cannonlake/include/platform/platform.h +++ b/src/platform/cannonlake/include/platform/platform.h @@ -22,6 +22,7 @@ #include #include #include +#include #include struct timer; @@ -49,17 +50,23 @@ struct timer; #define PLATFORM_PAGE_TABLE_SIZE 256 /* IDC Interrupt */ -#define PLATFORM_IDC_INTERRUPT(x) IRQ_EXT_IDC_LVL2(x) +#define PLATFORM_IDC_INTERRUPT IRQ_EXT_IDC_LVL2 +#define PLATFORM_IDC_INTERRUPT_NAME irq_name_level2 /* IPC Interrupt */ -#define PLATFORM_IPC_INTERRUPT IRQ_EXT_IPC_LVL2(0) +#define PLATFORM_IPC_INTERRUPT IRQ_EXT_IPC_LVL2 +#define PLATFORM_IPC_INTERRUPT_NAME irq_name_level2 /* pipeline IRQ */ #define PLATFORM_SCHEDULE_IRQ IRQ_NUM_SOFTWARE4 +#define PLATFORM_SCHEDULE_IRQ_NAME NULL #define PLATFORM_IRQ_TASK_HIGH IRQ_NUM_SOFTWARE3 +#define PLATFORM_IRQ_TASK_HIGH_NAME NULL #define PLATFORM_IRQ_TASK_MED IRQ_NUM_SOFTWARE2 +#define PLATFORM_IRQ_TASK_MED_NAME NULL #define PLATFORM_IRQ_TASK_LOW IRQ_NUM_SOFTWARE1 +#define PLATFORM_IRQ_TASK_LOW_NAME NULL #define PLATFORM_SCHEDULE_COST 200 diff --git a/src/platform/haswell/include/platform/lib/dma.h b/src/platform/haswell/include/platform/lib/dma.h index 87fad497a44e..526eb9c9bb15 100644 --- a/src/platform/haswell/include/platform/lib/dma.h +++ b/src/platform/haswell/include/platform/lib/dma.h @@ -32,7 +32,7 @@ #define DMA_HANDSHAKE_OBFF_10 14 #define DMA_HANDSHAKE_OBFF_11 15 -#define dma_chan_irq(dma, cpu, chan) dma_irq(dma, cpu) +#define dma_chan_irq(dma, chan) dma_irq(dma) int dmac_init(void); diff --git a/src/platform/haswell/include/platform/platform.h b/src/platform/haswell/include/platform/platform.h index cb1fe58ba860..24bd4bb75a8c 100644 --- a/src/platform/haswell/include/platform/platform.h +++ b/src/platform/haswell/include/platform/platform.h @@ -20,6 +20,7 @@ #include #include #include +#include #include struct timer; @@ -40,6 +41,7 @@ struct timer; /* IPC Interrupt */ #define PLATFORM_IPC_INTERRUPT IRQ_NUM_EXT_IA +#define PLATFORM_IPC_INTERRUPT_NAME NULL /* Host page size */ #define HOST_PAGE_SIZE 4096 @@ -47,10 +49,14 @@ struct timer; /* pipeline IRQ */ #define PLATFORM_SCHEDULE_IRQ IRQ_NUM_SOFTWARE2 +#define PLATFORM_SCHEDULE_IRQ_NAME NULL #define PLATFORM_IRQ_TASK_HIGH IRQ_NUM_SOFTWARE2 +#define PLATFORM_IRQ_TASK_HIGH_NAME NULL #define PLATFORM_IRQ_TASK_MED IRQ_NUM_SOFTWARE1 +#define PLATFORM_IRQ_TASK_MED_NAME NULL #define PLATFORM_IRQ_TASK_LOW IRQ_NUM_SOFTWARE1 +#define PLATFORM_IRQ_TASK_LOW_NAME NULL #define PLATFORM_SCHEDULE_COST 200 diff --git a/src/platform/icelake/include/platform/drivers/interrupt.h b/src/platform/icelake/include/platform/drivers/interrupt.h index 76004e405a0c..262f2b8dd88d 100644 --- a/src/platform/icelake/include/platform/drivers/interrupt.h +++ b/src/platform/icelake/include/platform/drivers/interrupt.h @@ -12,8 +12,6 @@ #ifndef __PLATFORM_DRIVERS_INTERRUPT_H__ #define __PLATFORM_DRIVERS_INTERRUPT_H__ -#include - #define PLATFORM_IRQ_CHILDREN 32 /* IRQ numbers - wrt Tensilica DSP */ @@ -67,52 +65,31 @@ #define IRQ_BIT_LVL5_SSP(x) (0 + x) /* Priority 2 Peripheral IRQ mappings */ -#define IRQ_EXT_HP_GPDMA_LVL2(xcpu) \ - SOF_IRQ(IRQ_BIT_LVL2_HP_GP_DMA0(0), 2, xcpu, IRQ_NUM_EXT_LEVEL2) -#define IRQ_EXT_IDC_LVL2(xcpu) \ - SOF_IRQ(IRQ_BIT_LVL2_IDC, 2, xcpu, IRQ_NUM_EXT_LEVEL2) -#define IRQ_EXT_IPC_LVL2(xcpu) \ - SOF_IRQ(IRQ_BIT_LVL2_HOST_IPC, 2, xcpu, IRQ_NUM_EXT_LEVEL2) -#define IRQ_EXT_TSTAMP1_LVL2(xcpu) \ - SOF_IRQ(IRQ_BIT_LVL2_WALL_CLK1, 2, xcpu, IRQ_NUM_EXT_LEVEL2) -#define IRQ_EXT_TSTAMP0_LVL2(xcpu) \ - SOF_IRQ(IRQ_BIT_LVL2_WALL_CLK0, 2, xcpu, IRQ_NUM_EXT_LEVEL2) -#define IRQ_EXT_MERR_LVL2(xcpu) \ - SOF_IRQ(IRQ_BIT_LVL2_L2_MEMERR, 2, xcpu, IRQ_NUM_EXT_LEVEL2) -#define IRQ_EXT_L2CACHE_LVL2(xcpu) \ - SOF_IRQ(IRQ_BIT_LVL2_L2_CACHE, 2, xcpu, IRQ_NUM_EXT_LEVEL2) -#define IRQ_EXT_SHA256_LVL2(xcpu) \ - SOF_IRQ(IRQ_BIT_LVL2_SHA256, 2, xcpu, IRQ_NUM_EXT_LEVEL2) +#define IRQ_EXT_HP_GPDMA_LVL2 IRQ_BIT_LVL2_HP_GP_DMA0(0) +#define IRQ_EXT_IDC_LVL2 IRQ_BIT_LVL2_IDC +#define IRQ_EXT_IPC_LVL2 IRQ_BIT_LVL2_HOST_IPC +#define IRQ_EXT_TSTAMP1_LVL2 IRQ_BIT_LVL2_WALL_CLK1 +#define IRQ_EXT_TSTAMP0_LVL2 IRQ_BIT_LVL2_WALL_CLK0 +#define IRQ_EXT_MERR_LVL2 IRQ_BIT_LVL2_L2_MEMERR +#define IRQ_EXT_L2CACHE_LVL2 IRQ_BIT_LVL2_L2_CACHE +#define IRQ_EXT_SHA256_LVL2 IRQ_BIT_LVL2_SHA256 /* Priority 3 Peripheral IRQ mappings */ -#define IRQ_EXT_CODE_DMA_LVL3(xcpu) \ - SOF_IRQ(IRQ_BIT_LVL3_CODE_LOADER, 3, xcpu, IRQ_NUM_EXT_LEVEL3) -#define IRQ_EXT_HOST_DMA_IN_LVL3(xcpu, channel) \ - SOF_IRQ(IRQ_BIT_LVL3_HOST_STREAM_IN(channel), 3, xcpu, \ - IRQ_NUM_EXT_LEVEL3) -#define IRQ_EXT_HOST_DMA_OUT_LVL3(xcpu, channel) \ - SOF_IRQ(IRQ_BIT_LVL3_HOST_STREAM_OUT(channel), 3, xcpu, \ - IRQ_NUM_EXT_LEVEL3) +#define IRQ_EXT_CODE_DMA_LVL3 IRQ_BIT_LVL3_CODE_LOADER +#define IRQ_EXT_HOST_DMA_IN_LVL3(channel) IRQ_BIT_LVL3_HOST_STREAM_IN(channel) +#define IRQ_EXT_HOST_DMA_OUT_LVL3(channel) IRQ_BIT_LVL3_HOST_STREAM_OUT(channel) /* Priority 4 Peripheral IRQ mappings */ -#define IRQ_EXT_LINK_DMA_IN_LVL4(xcpu, channel) \ - SOF_IRQ(IRQ_BIT_LVL4_LINK_STREAM_IN(channel), 4, xcpu, \ - IRQ_NUM_EXT_LEVEL4) -#define IRQ_EXT_LINK_DMA_OUT_LVL4(xcpu, channel) \ - SOF_IRQ(IRQ_BIT_LVL4_LINK_STREAM_OUT(channel), 4, xcpu, \ - IRQ_NUM_EXT_LEVEL4) +#define IRQ_EXT_LINK_DMA_IN_LVL4(channel) IRQ_BIT_LVL4_LINK_STREAM_IN(channel) +#define IRQ_EXT_LINK_DMA_OUT_LVL4(channel) IRQ_BIT_LVL4_LINK_STREAM_OUT(channel) /* Priority 5 Peripheral IRQ mappings */ -#define IRQ_EXT_LP_GPDMA0_LVL5(xcpu, channel) \ - SOF_ID_IRQ(0, IRQ_BIT_LVL5_LP_GP_DMA0, 5, xcpu, IRQ_NUM_EXT_LEVEL5) -#define IRQ_EXT_LP_GPDMA1_LVL5(xcpu, channel) \ - SOF_ID_IRQ(1, IRQ_BIT_LVL5_LP_GP_DMA0, 5, xcpu, IRQ_NUM_EXT_LEVEL5) +#define IRQ_EXT_LP_GPDMA0_LVL5(channel) IRQ_BIT_LVL5_LP_GP_DMA0 +#define IRQ_EXT_LP_GPDMA1_LVL5(channel) IRQ_BIT_LVL5_LP_GP_DMA0 -#define IRQ_EXT_SSPx_LVL5(x, xcpu) \ - SOF_IRQ(IRQ_BIT_LVL5_SSP(x), 5, xcpu, IRQ_NUM_EXT_LEVEL5) +#define IRQ_EXT_SSPx_LVL5(x) IRQ_BIT_LVL5_SSP(x) -#define IRQ_EXT_DMIC_LVL5(x, xcpu) \ - SOF_IRQ(IRQ_BIT_LVL5_DMIC(x), 5, xcpu, IRQ_NUM_EXT_LEVEL5) +#define IRQ_EXT_DMIC_LVL5(x) IRQ_BIT_LVL5_DMIC(x) /* IRQ Masks */ diff --git a/src/platform/icelake/include/platform/drivers/timer.h b/src/platform/icelake/include/platform/drivers/timer.h index 92a49cebc7ef..cf4ea48174af 100644 --- a/src/platform/icelake/include/platform/drivers/timer.h +++ b/src/platform/icelake/include/platform/drivers/timer.h @@ -20,8 +20,8 @@ #define TIMER0 IRQ_NUM_TIMER1 #define TIMER1 IRQ_NUM_TIMER2 #define TIMER2 IRQ_NUM_TIMER3 -#define TIMER3 IRQ_EXT_TSTAMP0_LVL2(0) -#define TIMER4 IRQ_EXT_TSTAMP1_LVL2(0) +#define TIMER3 IRQ_EXT_TSTAMP0_LVL2 +#define TIMER4 IRQ_EXT_TSTAMP1_LVL2 #endif /* __PLATFORM_DRIVERS_TIMER_H__ */ diff --git a/src/platform/icelake/include/platform/lib/dma.h b/src/platform/icelake/include/platform/lib/dma.h index 4e88bdf95bcc..3768296b9b4b 100644 --- a/src/platform/icelake/include/platform/lib/dma.h +++ b/src/platform/icelake/include/platform/lib/dma.h @@ -48,7 +48,7 @@ #define DMA_HANDSHAKE_SSP5_TX 12 #define DMA_HANDSHAKE_SSP5_RX 13 -#define dma_chan_irq(dma, cpu, chan) dma_irq(dma, cpu) +#define dma_chan_irq(dma, chan) dma_irq(dma) int dmac_init(void); diff --git a/src/platform/icelake/include/platform/platform.h b/src/platform/icelake/include/platform/platform.h index 0de5514e2ff7..48dbe9a846d4 100644 --- a/src/platform/icelake/include/platform/platform.h +++ b/src/platform/icelake/include/platform/platform.h @@ -22,6 +22,7 @@ #include #include #include +#include #include struct timer; @@ -49,17 +50,23 @@ struct timer; #define PLATFORM_PAGE_TABLE_SIZE 256 /* IDC Interrupt */ -#define PLATFORM_IDC_INTERRUPT(x) IRQ_EXT_IDC_LVL2(x) +#define PLATFORM_IDC_INTERRUPT IRQ_EXT_IDC_LVL2 +#define PLATFORM_IDC_INTERRUPT_NAME irq_name_level2 /* IPC Interrupt */ -#define PLATFORM_IPC_INTERRUPT IRQ_EXT_IPC_LVL2(0) +#define PLATFORM_IPC_INTERRUPT IRQ_EXT_IPC_LVL2 +#define PLATFORM_IPC_INTERRUPT_NAME irq_name_level2 /* pipeline IRQ */ #define PLATFORM_SCHEDULE_IRQ IRQ_NUM_SOFTWARE4 +#define PLATFORM_SCHEDULE_IRQ_NAME NULL #define PLATFORM_IRQ_TASK_HIGH IRQ_NUM_SOFTWARE3 +#define PLATFORM_IRQ_TASK_HIGH_NAME NULL #define PLATFORM_IRQ_TASK_MED IRQ_NUM_SOFTWARE2 +#define PLATFORM_IRQ_TASK_MED_NAME NULL #define PLATFORM_IRQ_TASK_LOW IRQ_NUM_SOFTWARE1 +#define PLATFORM_IRQ_TASK_LOW_NAME NULL #define PLATFORM_SCHEDULE_COST 200 diff --git a/src/platform/imx8/include/platform/platform.h b/src/platform/imx8/include/platform/platform.h index d73b27255051..8470d99a2b9a 100644 --- a/src/platform/imx8/include/platform/platform.h +++ b/src/platform/imx8/include/platform/platform.h @@ -15,6 +15,7 @@ #include #include #include +#include #include struct timer; @@ -25,18 +26,23 @@ struct timer; #define PLATFORM_WORKQ_DEFAULT_TIMEOUT 1000 /* IPC Interrupt */ -#define PLATFORM_IPC_INTERRUPT IRQ_NUM_MU +#define PLATFORM_IPC_INTERRUPT IRQ_NUM_MU +#define PLATFORM_IPC_INTERRUPT_NAME NULL /* Host page size */ #define HOST_PAGE_SIZE 4096 #define PLATFORM_PAGE_TABLE_SIZE 256 /* pipeline IRQ */ -#define PLATFORM_SCHEDULE_IRQ IRQ_NUM_SOFTWARE0 - -#define PLATFORM_IRQ_TASK_HIGH IRQ_NUM_SOFTWARE1 -#define PLATFORM_IRQ_TASK_MED IRQ_NUM_SOFTWARE1 -#define PLATFORM_IRQ_TASK_LOW IRQ_NUM_SOFTWARE1 +#define PLATFORM_SCHEDULE_IRQ IRQ_NUM_SOFTWARE0 +#define PLATFORM_SCHEDULE_IRQ_NAME NULL + +#define PLATFORM_IRQ_TASK_HIGH IRQ_NUM_SOFTWARE1 +#define PLATFORM_IRQ_TASK_HIGH_NAME NULL +#define PLATFORM_IRQ_TASK_MED IRQ_NUM_SOFTWARE1 +#define PLATFORM_IRQ_TASK_MED_NAME NULL +#define PLATFORM_IRQ_TASK_LOW IRQ_NUM_SOFTWARE1 +#define PLATFORM_IRQ_TASK_LOW_NAME NULL #define PLATFORM_SCHEDULE_COST 200 diff --git a/src/platform/intel/cavs/lib/dai.c b/src/platform/intel/cavs/lib/dai.c index 82729b4ae515..de1e56722927 100644 --- a/src/platform/intel/cavs/lib/dai.c +++ b/src/platform/intel/cavs/lib/dai.c @@ -42,7 +42,8 @@ static struct dai dmic[2] = { .index = 0, .plat_data = { .base = DMIC_BASE, - .irq = IRQ_EXT_DMIC_LVL5(0, 0), + .irq = IRQ_EXT_DMIC_LVL5(0), + .irq_name = irq_name_level5, .fifo[SOF_IPC_STREAM_PLAYBACK] = { .offset = 0, /* No playback */ .handshake = 0, @@ -59,7 +60,8 @@ static struct dai dmic[2] = { .index = 1, .plat_data = { .base = DMIC_BASE, - .irq = IRQ_EXT_DMIC_LVL5(1, 0), + .irq = IRQ_EXT_DMIC_LVL5(1), + .irq_name = irq_name_level5, .fifo[SOF_IPC_STREAM_PLAYBACK] = { .offset = 0, /* No playback */ .handshake = 0, @@ -108,7 +110,8 @@ int dai_init(void) ssp[i].index = i; ssp[i].drv = &ssp_driver; ssp[i].plat_data.base = SSP_BASE(i); - ssp[i].plat_data.irq = IRQ_EXT_SSPx_LVL5(i, 0); + ssp[i].plat_data.irq = IRQ_EXT_SSPx_LVL5(i); + ssp[i].plat_data.irq_name = irq_name_level5; ssp[i].plat_data.fifo[SOF_IPC_STREAM_PLAYBACK].offset = SSP_BASE(i) + SSDR; ssp[i].plat_data.fifo[SOF_IPC_STREAM_PLAYBACK].handshake = diff --git a/src/platform/intel/cavs/lib/dma.c b/src/platform/intel/cavs/lib/dma.c index a744d4fb8a0f..49247e77cecf 100644 --- a/src/platform/intel/cavs/lib/dma.c +++ b/src/platform/intel/cavs/lib/dma.c @@ -107,7 +107,7 @@ static struct dw_drv_plat_data dmac1 = { }; #if CONFIG_SUECREEK -struct dma dma[CAVS_PLATFORM_NUM_DMACS] = { +static struct dma dma[CAVS_PLATFORM_NUM_DMACS] = { { /* LP GP DMAC 0 */ .plat_data = { .id = DMA_GP_LP_DMAC0, @@ -117,7 +117,8 @@ struct dma dma[CAVS_PLATFORM_NUM_DMACS] = { .devs = DMA_DEV_SSP | DMA_DEV_SSI | DMA_DEV_DMIC, .base = LP_GP_DMA_BASE(0), .channels = 8, - .irq = IRQ_EXT_LP_GPDMA0_LVL5(0, 0), + .irq = IRQ_EXT_LP_GPDMA0_LVL5(0), + .irq_name = irq_name_level5, .drv_plat_data = &dmac0, }, .ops = &dw_dma_ops, @@ -131,7 +132,8 @@ struct dma dma[CAVS_PLATFORM_NUM_DMACS] = { .devs = DMA_DEV_SSP | DMA_DEV_DMIC, .base = LP_GP_DMA_BASE(1), .channels = 8, - .irq = IRQ_EXT_LP_GPDMA1_LVL5(0, 0), + .irq = IRQ_EXT_LP_GPDMA1_LVL5(0), + .irq_name = irq_name_level5, .drv_plat_data = &dmac1, }, .ops = &dw_dma_ops, @@ -145,7 +147,8 @@ struct dma dma[CAVS_PLATFORM_NUM_DMACS] = { .devs = DMA_DEV_SSP | DMA_DEV_DMIC, .base = LP_GP_DMA_BASE(1), .channels = 8, - .irq = IRQ_EXT_LP_GPDMA1_LVL5(0, 0), + .irq = IRQ_EXT_LP_GPDMA1_LVL5(0), + .irq_name = irq_name_level5, .drv_plat_data = &dmac1, }, .ops = &dw_dma_ops, @@ -153,7 +156,7 @@ struct dma dma[CAVS_PLATFORM_NUM_DMACS] = { }; #else -struct dma dma[CAVS_PLATFORM_NUM_DMACS] = { +static struct dma dma[CAVS_PLATFORM_NUM_DMACS] = { { /* Low Power GP DMAC 0 */ .plat_data = { .id = DMA_GP_LP_DMAC0, @@ -164,7 +167,8 @@ struct dma dma[CAVS_PLATFORM_NUM_DMACS] = { DMA_DEV_SOUNDWIRE, .base = LP_GP_DMA_BASE(0), .channels = 8, - .irq = IRQ_EXT_LP_GPDMA0_LVL5(0, 0), + .irq = IRQ_EXT_LP_GPDMA0_LVL5(0), + .irq_name = irq_name_level5, .drv_plat_data = &dmac0, }, .ops = &dw_dma_ops, @@ -179,7 +183,8 @@ struct dma dma[CAVS_PLATFORM_NUM_DMACS] = { DMA_DEV_SOUNDWIRE, .base = LP_GP_DMA_BASE(1), .channels = 8, - .irq = IRQ_EXT_LP_GPDMA1_LVL5(0, 0), + .irq = IRQ_EXT_LP_GPDMA1_LVL5(0), + .irq_name = irq_name_level5, .drv_plat_data = &dmac1, }, .ops = &dw_dma_ops, @@ -192,7 +197,8 @@ struct dma dma[CAVS_PLATFORM_NUM_DMACS] = { .devs = DMA_DEV_HOST, .base = GTW_HOST_IN_STREAM_BASE(0), .channels = 7, - .irq = IRQ_EXT_HOST_DMA_IN_LVL3(0, 0), + .irq = IRQ_EXT_HOST_DMA_IN_LVL3(0), + .irq_name = irq_name_level3, .chan_size = GTW_HOST_IN_STREAM_SIZE, }, .ops = &hda_host_dma_ops, @@ -205,7 +211,8 @@ struct dma dma[CAVS_PLATFORM_NUM_DMACS] = { .devs = DMA_DEV_HOST, .base = GTW_HOST_OUT_STREAM_BASE(0), .channels = DMAC_HOST_OUT_CHANNELS_COUNT, - .irq = IRQ_EXT_HOST_DMA_OUT_LVL3(0, 0), + .irq = IRQ_EXT_HOST_DMA_OUT_LVL3(0), + .irq_name = irq_name_level3, .chan_size = GTW_HOST_OUT_STREAM_SIZE, }, .ops = &hda_host_dma_ops, @@ -218,7 +225,8 @@ struct dma dma[CAVS_PLATFORM_NUM_DMACS] = { .devs = DMA_DEV_HDA, .base = GTW_LINK_IN_STREAM_BASE(0), .channels = DMAC_LINK_IN_CHANNELS_COUNT, - .irq = IRQ_EXT_LINK_DMA_IN_LVL4(0, 0), + .irq = IRQ_EXT_LINK_DMA_IN_LVL4(0), + .irq_name = irq_name_level4, .chan_size = GTW_LINK_IN_STREAM_SIZE, }, .ops = &hda_link_dma_ops, @@ -231,7 +239,8 @@ struct dma dma[CAVS_PLATFORM_NUM_DMACS] = { .devs = DMA_DEV_HDA, .base = GTW_LINK_OUT_STREAM_BASE(0), .channels = DMAC_LINK_OUT_CHANNELS_COUNT, - .irq = IRQ_EXT_LINK_DMA_OUT_LVL4(0, 0), + .irq = IRQ_EXT_LINK_DMA_OUT_LVL4(0), + .irq_name = irq_name_level4, .chan_size = GTW_LINK_OUT_STREAM_SIZE, }, .ops = &hda_link_dma_ops, diff --git a/src/platform/intel/cavs/platform.c b/src/platform/intel/cavs/platform.c index a91c8af49982..964695770bf6 100644 --- a/src/platform/intel/cavs/platform.c +++ b/src/platform/intel/cavs/platform.c @@ -130,7 +130,8 @@ struct timesource_data platform_generic_queue[] = { { .timer = { .id = TIMER3, /* external timer */ - .irq = IRQ_EXT_TSTAMP0_LVL2(0), + .irq = IRQ_EXT_TSTAMP0_LVL2, + .irq_name = irq_name_level2, .core = 0, }, .clk = CLK_SSP, @@ -142,7 +143,8 @@ struct timesource_data platform_generic_queue[] = { { .timer = { .id = TIMER3, /* external timer */ - .irq = IRQ_EXT_TSTAMP0_LVL2(1), + .irq = IRQ_EXT_TSTAMP0_LVL2, + .irq_name = irq_name_level2, .core = 1, }, .clk = CLK_SSP, @@ -155,7 +157,8 @@ struct timesource_data platform_generic_queue[] = { { .timer = { .id = TIMER3, /* external timer */ - .irq = IRQ_EXT_TSTAMP0_LVL2(2), + .irq = IRQ_EXT_TSTAMP0_LVL2, + .irq_name = irq_name_level2, .core = 2, }, .clk = CLK_SSP, @@ -167,7 +170,8 @@ struct timesource_data platform_generic_queue[] = { { .timer = { .id = TIMER3, /* external timer */ - .irq = IRQ_EXT_TSTAMP0_LVL2(3), + .irq = IRQ_EXT_TSTAMP0_LVL2, + .irq_name = irq_name_level2, .core = 3, }, .clk = CLK_SSP, diff --git a/src/platform/suecreek/include/platform/drivers/interrupt.h b/src/platform/suecreek/include/platform/drivers/interrupt.h index cf865f08e9fb..a89b2d656db5 100644 --- a/src/platform/suecreek/include/platform/drivers/interrupt.h +++ b/src/platform/suecreek/include/platform/drivers/interrupt.h @@ -69,52 +69,31 @@ #define IRQ_BIT_LVL5_SSP(x) (0 + x) /* Priority 2 Peripheral IRQ mappings */ -#define IRQ_EXT_HP_GPDMA_LVL2(xcpu) \ - SOF_IRQ(IRQ_BIT_LVL2_HP_GP_DMA0(0), 2, xcpu, IRQ_NUM_EXT_LEVEL2) -#define IRQ_EXT_IDC_LVL2(xcpu) \ - SOF_IRQ(IRQ_BIT_LVL2_IDC, 2, xcpu, IRQ_NUM_EXT_LEVEL2) -#define IRQ_EXT_IPC_LVL2(xcpu) \ - SOF_IRQ(IRQ_BIT_LVL2_HOST_IPC, 2, xcpu, IRQ_NUM_EXT_LEVEL2) -#define IRQ_EXT_TSTAMP1_LVL2(xcpu) \ - SOF_IRQ(IRQ_BIT_LVL2_WALL_CLK1, 2, xcpu, IRQ_NUM_EXT_LEVEL2) -#define IRQ_EXT_TSTAMP0_LVL2(xcpu) \ - SOF_IRQ(IRQ_BIT_LVL2_WALL_CLK0, 2, xcpu, IRQ_NUM_EXT_LEVEL2) -#define IRQ_EXT_MERR_LVL2(xcpu) \ - SOF_IRQ(IRQ_BIT_LVL2_L2_MEMERR, 2, xcpu, IRQ_NUM_EXT_LEVEL2) -#define IRQ_EXT_L2CACHE_LVL2(xcpu) \ - SOF_IRQ(IRQ_BIT_LVL2_L2_CACHE, 2, xcpu, IRQ_NUM_EXT_LEVEL2) -#define IRQ_EXT_SHA256_LVL2(xcpu) \ - SOF_IRQ(IRQ_BIT_LVL2_SHA256, 2, xcpu, IRQ_NUM_EXT_LEVEL2) +#define IRQ_EXT_HP_GPDMA_LVL2 IRQ_BIT_LVL2_HP_GP_DMA0(0) +#define IRQ_EXT_IDC_LVL2 IRQ_BIT_LVL2_IDC +#define IRQ_EXT_IPC_LVL2 IRQ_BIT_LVL2_HOST_IPC +#define IRQ_EXT_TSTAMP1_LVL2 IRQ_BIT_LVL2_WALL_CLK1 +#define IRQ_EXT_TSTAMP0_LVL2 IRQ_BIT_LVL2_WALL_CLK0 +#define IRQ_EXT_MERR_LVL2 IRQ_BIT_LVL2_L2_MEMERR +#define IRQ_EXT_L2CACHE_LVL2 IRQ_BIT_LVL2_L2_CACHE +#define IRQ_EXT_SHA256_LVL2 IRQ_BIT_LVL2_SHA256 /* Priority 3 Peripheral IRQ mappings */ -#define IRQ_EXT_CODE_DMA_LVL3(xcpu) \ - SOF_IRQ(IRQ_BIT_LVL3_CODE_LOADER, 3, xcpu, IRQ_NUM_EXT_LEVEL3) -#define IRQ_EXT_HOST_DMA_IN_LVL3(xcpu, channel) \ - SOF_IRQ(IRQ_BIT_LVL3_HOST_STREAM_IN(channel), 3, xcpu, \ - IRQ_NUM_EXT_LEVEL3) -#define IRQ_EXT_HOST_DMA_OUT_LVL3(xcpu, channel) \ - SOF_IRQ(IRQ_BIT_LVL3_HOST_STREAM_OUT(channel), 3, xcpu, \ - IRQ_NUM_EXT_LEVEL3) +#define IRQ_EXT_CODE_DMA_LVL3 IRQ_BIT_LVL3_CODE_LOADER +#define IRQ_EXT_HOST_DMA_IN_LVL3(channel) IRQ_BIT_LVL3_HOST_STREAM_IN(channel) +#define IRQ_EXT_HOST_DMA_OUT_LVL3(channel) IRQ_BIT_LVL3_HOST_STREAM_OUT(channel) /* Priority 4 Peripheral IRQ mappings */ -#define IRQ_EXT_LINK_DMA_IN_LVL4(xcpu, channel) \ - SOF_IRQ(IRQ_BIT_LVL4_LINK_STREAM_IN(channel), 4, xcpu, \ - IRQ_NUM_EXT_LEVEL4) -#define IRQ_EXT_LINK_DMA_OUT_LVL4(xcpu, channel) \ - SOF_IRQ(IRQ_BIT_LVL4_LINK_STREAM_OUT(channel), 4, xcpu, \ - IRQ_NUM_EXT_LEVEL4) +#define IRQ_EXT_LINK_DMA_IN_LVL4(channel) IRQ_BIT_LVL4_LINK_STREAM_IN(channel) +#define IRQ_EXT_LINK_DMA_OUT_LVL4(channel) IRQ_BIT_LVL4_LINK_STREAM_OUT(channel) /* Priority 5 Peripheral IRQ mappings */ -#define IRQ_EXT_LP_GPDMA0_LVL5(xcpu, channel) \ - SOF_ID_IRQ(0, IRQ_BIT_LVL5_LP_GP_DMA0, 5, xcpu, IRQ_NUM_EXT_LEVEL5) -#define IRQ_EXT_LP_GPDMA1_LVL5(xcpu, channel) \ - SOF_ID_IRQ(1, IRQ_BIT_LVL5_LP_GP_DMA0, 5, xcpu, IRQ_NUM_EXT_LEVEL5) +#define IRQ_EXT_LP_GPDMA0_LVL5(channel) IRQ_BIT_LVL5_LP_GP_DMA0 +#define IRQ_EXT_LP_GPDMA1_LVL5(channel) IRQ_BIT_LVL5_LP_GP_DMA0 -#define IRQ_EXT_SSPx_LVL5(x, xcpu) \ - SOF_IRQ(IRQ_BIT_LVL5_SSP(x), 5, xcpu, IRQ_NUM_EXT_LEVEL5) +#define IRQ_EXT_SSPx_LVL5(x) IRQ_BIT_LVL5_SSP(x) -#define IRQ_EXT_DMIC_LVL5(x, xcpu) \ - SOF_IRQ(IRQ_BIT_LVL5_DMIC(x), 5, xcpu, IRQ_NUM_EXT_LEVEL5) +#define IRQ_EXT_DMIC_LVL5(x) IRQ_BIT_LVL5_DMIC(x) /* IRQ Masks */ diff --git a/src/platform/suecreek/include/platform/drivers/timer.h b/src/platform/suecreek/include/platform/drivers/timer.h index 92a49cebc7ef..cf4ea48174af 100644 --- a/src/platform/suecreek/include/platform/drivers/timer.h +++ b/src/platform/suecreek/include/platform/drivers/timer.h @@ -20,8 +20,8 @@ #define TIMER0 IRQ_NUM_TIMER1 #define TIMER1 IRQ_NUM_TIMER2 #define TIMER2 IRQ_NUM_TIMER3 -#define TIMER3 IRQ_EXT_TSTAMP0_LVL2(0) -#define TIMER4 IRQ_EXT_TSTAMP1_LVL2(0) +#define TIMER3 IRQ_EXT_TSTAMP0_LVL2 +#define TIMER4 IRQ_EXT_TSTAMP1_LVL2 #endif /* __PLATFORM_DRIVERS_TIMER_H__ */ diff --git a/src/platform/suecreek/include/platform/lib/dma.h b/src/platform/suecreek/include/platform/lib/dma.h index 057a578fe773..b14ab58e6fde 100644 --- a/src/platform/suecreek/include/platform/lib/dma.h +++ b/src/platform/suecreek/include/platform/lib/dma.h @@ -37,7 +37,7 @@ #define DMA_HANDSHAKE_SSI_TX 26 #define DMA_HANDSHAKE_SSI_RX 27 -#define dma_chan_irq(dma, cpu, chan) dma_irq(dma, cpu) +#define dma_chan_irq(dma, chan) dma_irq(dma) int dmac_init(void); diff --git a/src/platform/suecreek/include/platform/platform.h b/src/platform/suecreek/include/platform/platform.h index eb03024be2ad..83c8fa9d1a15 100644 --- a/src/platform/suecreek/include/platform/platform.h +++ b/src/platform/suecreek/include/platform/platform.h @@ -22,6 +22,7 @@ #include #include #include +#include #include struct timer; @@ -49,17 +50,19 @@ struct timer; #define PLATFORM_PAGE_TABLE_SIZE 256 /* IDC Interrupt */ -#define PLATFORM_IDC_INTERRUPT(x) IRQ_EXT_IDC_LVL2(x) - -/* IPC Interrupt */ -#define PLATFORM_IPC_INTERRUPT IRQ_EXT_IPC_LVL2(0) +#define PLATFORM_IDC_INTERRUPT IRQ_EXT_IDC_LVL2 +#define PLATFORM_IDC_INTERRUPT_NAME irq_name_level2 /* pipeline IRQ */ -#define PLATFORM_SCHEDULE_IRQ IRQ_NUM_SOFTWARE4 +#define PLATFORM_SCHEDULE_IRQ IRQ_NUM_SOFTWARE4 +#define PLATFORM_SCHEDULE_IRQ_NAME NULL #define PLATFORM_IRQ_TASK_HIGH IRQ_NUM_SOFTWARE3 +#define PLATFORM_IRQ_TASK_HIGH_NAME NULL #define PLATFORM_IRQ_TASK_MED IRQ_NUM_SOFTWARE2 +#define PLATFORM_IRQ_TASK_MED_NAME NULL #define PLATFORM_IRQ_TASK_LOW IRQ_NUM_SOFTWARE1 +#define PLATFORM_IRQ_TASK_LOW_NAME NULL #define PLATFORM_SCHEDULE_COST 200 diff --git a/src/schedule/edf_schedule.c b/src/schedule/edf_schedule.c index 79e319e4b037..7d335d17c4c6 100644 --- a/src/schedule/edf_schedule.c +++ b/src/schedule/edf_schedule.c @@ -429,7 +429,10 @@ static int edf_scheduler_init(void) sch->clock = PLATFORM_SCHED_CLOCK; /* configure scheduler interrupt */ - sch->irq = PLATFORM_SCHEDULE_IRQ; + sch->irq = interrupt_get_irq(PLATFORM_SCHEDULE_IRQ, + PLATFORM_SCHEDULE_IRQ_NAME); + if (sch->irq < 0) + return sch->irq; interrupt_register(sch->irq, IRQ_AUTO_UNMASK, edf_scheduler_run, sch); interrupt_enable(sch->irq, sch); diff --git a/src/schedule/ll_schedule.c b/src/schedule/ll_schedule.c index 686f6ac45a5e..fdfb4112b5c1 100644 --- a/src/schedule/ll_schedule.c +++ b/src/schedule/ll_schedule.c @@ -58,6 +58,7 @@ struct ll_queue_shared_context { /* registered timers */ struct timer *timers[PLATFORM_CORE_COUNT]; + struct timer_irq tirq[PLATFORM_CORE_COUNT]; }; static struct ll_queue_shared_context *ll_shared_ctx; @@ -527,9 +528,6 @@ static struct ll_schedule_data *work_new_queue(struct timesource_data *ts) queue->notifier.id = ts->notifier; notifier_register(&queue->notifier); - /* register system timer */ - timer_register(&queue->ts->timer, queue_run, queue); - return queue; } @@ -545,14 +543,28 @@ static int ll_scheduler_init(void) sch_data->ll_sch_data = work_new_queue(ts); - if (cpu_get_id() == PLATFORM_MASTER_CORE_ID) { + if (cpu == PLATFORM_MASTER_CORE_ID) { + unsigned int i; + ll_shared_ctx = rzalloc(RZONE_SYS | RZONE_FLAG_UNCACHED, SOF_MEM_CAPS_RAM, sizeof(*ll_shared_ctx)); + + for (i = 0, ts = platform_generic_queue; + i < PLATFORM_CORE_COUNT; i++, ts++) { + ts->timer.tirq = ll_shared_ctx->tirq + i; + dcache_writeback_region(&ts->timer.tirq, + sizeof(ts->timer.tirq)); + } + atomic_init(&ll_shared_ctx->total_num_work, 0); atomic_init(&ll_shared_ctx->timer_clients, 0); } + /* register system timer */ + timer_register(&platform_generic_queue[cpu].timer, queue_run, + sch_data->ll_sch_data); + return ret; } From df67a0eeea6d59e5ee778f47160b4ab1f7b61f91 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Tue, 26 Feb 2019 18:33:33 +0100 Subject: [PATCH 23/25] interrupt: support arbitrary interrupt controller cascading When registering a cascading interrupt controller as a child of another interrupt controller, no new child descriptor has to be allocated, instead the embedded into the cascading interrupt controller object descriptor has to be used. Signed-off-by: Guennadi Liakhovetski --- src/drivers/interrupt.c | 125 ++++++++++++++++++++++++++-------------- 1 file changed, 83 insertions(+), 42 deletions(-) diff --git a/src/drivers/interrupt.c b/src/drivers/interrupt.c index 1bbb4cb066da..e64f13dc7ccf 100644 --- a/src/drivers/interrupt.c +++ b/src/drivers/interrupt.c @@ -26,6 +26,12 @@ static union { uint8_t bytes[PLATFORM_DCACHE_ALIGN]; } cascade_root; +static int interrupt_register_internal(uint32_t irq, int unmask, + void (*handler)(void *arg), + void *arg, struct irq_desc *desc); +static void interrupt_unregister_internal(uint32_t irq, const void *arg, + struct irq_desc *desc); + int interrupt_cascade_register(const struct irq_cascade_tmpl *tmpl) { struct irq_cascade_desc **cascade; @@ -142,7 +148,7 @@ void interrupt_init(void) } static int irq_register_child(struct irq_desc *parent, int irq, int unmask, - void (*handler)(void *arg), void *arg) + void (*handler)(void *arg), void *arg, struct irq_desc *desc) { unsigned int core = cpu_get_id(); struct irq_desc *child; @@ -155,14 +161,10 @@ static int irq_register_child(struct irq_desc *parent, int irq, int unmask, cascade = container_of(parent, struct irq_cascade_desc, desc); - spin_lock(&cascade->lock); - hw_irq = irq - cascade->irq_base; - if (hw_irq < 0 || cascade->irq_base + PLATFORM_IRQ_CHILDREN <= irq) { - ret = -EINVAL; - goto finish; - } + if (hw_irq < 0 || cascade->irq_base + PLATFORM_IRQ_CHILDREN <= irq) + return -EINVAL; head = &cascade->child[hw_irq].list; @@ -173,51 +175,52 @@ static int irq_register_child(struct irq_desc *parent, int irq, int unmask, trace_error(TRACE_CLASS_IRQ, "error: IRQ 0x%x handler argument re-used!", irq); - ret = -EEXIST; - goto finish; + return -EEXIST; } if (child->unmask != unmask) { trace_error(TRACE_CLASS_IRQ, "error: IRQ 0x%x flags differ!", irq); - ret = -EINVAL; - goto finish; + return -EINVAL; } } - /* init child from run-time, may be registered and unregistered - * many times at run-time - */ - child = rzalloc(RZONE_SYS_RUNTIME | RZONE_FLAG_UNCACHED, - SOF_MEM_CAPS_RAM, sizeof(struct irq_desc)); - if (!child) { - ret = -ENOMEM; - goto finish; + if (!desc) { + /* init child from run-time, may be registered and unregistered + * many times at run-time + */ + child = rzalloc(RZONE_SYS_RUNTIME | RZONE_FLAG_UNCACHED, + SOF_MEM_CAPS_RAM, sizeof(struct irq_desc)); + if (!child) + return -ENOMEM; + + child->handler = handler; + child->handler_arg = arg; + child->irq = irq; + } else { + child = desc; + child->cpu_mask = 0; } - child->handler = handler; - child->handler_arg = arg; child->unmask = unmask; - child->irq = irq; list_item_append(&child->irq_list, head); /* do we need to register parent on this CPU? */ if (!cascade->num_children[core]) - ret = interrupt_register(parent->irq, IRQ_AUTO_UNMASK, - parent->handler, parent); + ret = interrupt_register_internal(parent->irq, IRQ_AUTO_UNMASK, + parent->handler, parent, + parent); /* increment number of children */ if (!ret) cascade->num_children[core]++; -finish: - spin_unlock(&cascade->lock); return ret; } static void irq_unregister_child(struct irq_desc *parent, int irq, - const void *arg) + const void *arg, struct irq_desc *desc) { struct irq_desc *child; struct irq_cascade_desc *cascade = container_of(parent, @@ -226,28 +229,26 @@ static void irq_unregister_child(struct irq_desc *parent, int irq, struct list_item *list, *head = &cascade->child[hw_irq].list; unsigned int core = cpu_get_id(); - spin_lock(&cascade->lock); - list_for_item(list, head) { child = container_of(list, struct irq_desc, irq_list); if (child->handler_arg == arg) { list_item_del(&child->irq_list); cascade->num_children[core]--; - rfree(child); + if (!desc) + rfree(child); /* * unregister the root interrupt if this l2 is the last * registered child. */ if (!cascade->num_children[core]) - interrupt_unregister(parent->irq, parent); + interrupt_unregister_internal(parent->irq, + parent, parent); break; } } - - spin_unlock(&cascade->lock); } static uint32_t irq_enable_child(struct irq_desc *parent, int irq, void *arg) @@ -259,8 +260,14 @@ static uint32_t irq_enable_child(struct irq_desc *parent, int irq, void *arg) struct irq_child *child; unsigned int child_idx; struct list_item *list; + unsigned long flags; - spin_lock(&cascade->lock); + /* + * Locking is child to parent: when called recursively we are already + * holding the child's lock and then also taking the parent's lock. The + * same holds for the interrupt_(un)register() paths. + */ + spin_lock_irq(&cascade->lock, flags); child = cascade->child + hw_irq; child_idx = cascade->global_mask ? 0 : core; @@ -284,7 +291,7 @@ static uint32_t irq_enable_child(struct irq_desc *parent, int irq, void *arg) interrupt_unmask(irq, core); } - spin_unlock(&cascade->lock); + spin_unlock_irq(&cascade->lock, flags); return 0; } @@ -298,8 +305,9 @@ static uint32_t irq_disable_child(struct irq_desc *parent, int irq, void *arg) struct irq_child *child; unsigned int child_idx; struct list_item *list; + unsigned long flags; - spin_lock(&cascade->lock); + spin_lock_irq(&cascade->lock, flags); child = cascade->child + hw_irq; child_idx = cascade->global_mask ? 0 : core; @@ -327,7 +335,7 @@ static uint32_t irq_disable_child(struct irq_desc *parent, int irq, void *arg) interrupt_disable(parent->irq, parent->handler_arg); } - spin_unlock(&cascade->lock); + spin_unlock_irq(&cascade->lock, flags); return 0; } @@ -335,26 +343,59 @@ static uint32_t irq_disable_child(struct irq_desc *parent, int irq, void *arg) int interrupt_register(uint32_t irq, int unmask, void (*handler)(void *arg), void *arg) { + return interrupt_register_internal(irq, unmask, handler, arg, NULL); +} + +static int interrupt_register_internal(uint32_t irq, int unmask, + void (*handler)(void *arg), + void *arg, struct irq_desc *desc) +{ + struct irq_cascade_desc *cascade; struct irq_desc *parent; + /* Avoid a bogus compiler warning */ + unsigned long flags = 0; + int ret; /* no parent means we are registering DSP internal IRQ */ parent = interrupt_get_parent(irq); if (parent == NULL) return arch_interrupt_register(irq, handler, arg); - else - return irq_register_child(parent, irq, unmask, handler, arg); + + cascade = container_of(parent, struct irq_cascade_desc, desc); + + spin_lock_irq(&cascade->lock, flags); + ret = irq_register_child(parent, irq, unmask, handler, arg, + desc); + spin_unlock_irq(&cascade->lock, flags); + + return ret; } void interrupt_unregister(uint32_t irq, const void *arg) { + interrupt_unregister_internal(irq, arg, NULL); +} + +static void interrupt_unregister_internal(uint32_t irq, const void *arg, + struct irq_desc *desc) +{ + struct irq_cascade_desc *cascade; struct irq_desc *parent; + /* Avoid a bogus compiler warning */ + unsigned long flags = 0; /* no parent means we are unregistering DSP internal IRQ */ parent = interrupt_get_parent(irq); - if (parent == NULL) + if (!parent) { arch_interrupt_unregister(irq); - else - irq_unregister_child(parent, irq, arg); + return; + } + + cascade = container_of(parent, struct irq_cascade_desc, desc); + + spin_lock_irq(&cascade->lock, flags); + irq_unregister_child(parent, irq, arg, desc); + spin_unlock_irq(&cascade->lock, flags); } uint32_t interrupt_enable(uint32_t irq, void *arg) From 1e3ea0051d30c4ef4cbb6f961c351b2448bf9204 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Wed, 6 Mar 2019 13:19:50 +0100 Subject: [PATCH 24/25] interrupt: reduce the use of the container_of() macro Instead of passing a pointer to the interrupt descriptor, embedded in a cascading interrupt object and then using container_of() to get back to the cascading interrupt, pass a pointer to it directly to functions. Signed-off-by: Guennadi Liakhovetski --- src/drivers/intel/cavs/interrupt.c | 20 +++---- src/drivers/interrupt.c | 87 ++++++++++++----------------- src/include/sof/drivers/interrupt.h | 2 +- 3 files changed, 47 insertions(+), 62 deletions(-) diff --git a/src/drivers/intel/cavs/interrupt.c b/src/drivers/intel/cavs/interrupt.c index a31f41259c7d..61d2d00ebcfc 100644 --- a/src/drivers/intel/cavs/interrupt.c +++ b/src/drivers/intel/cavs/interrupt.c @@ -132,20 +132,20 @@ uint32_t platform_interrupt_get_enabled(void) void interrupt_mask(uint32_t irq, unsigned int cpu) { - struct irq_desc *parent = interrupt_get_parent(irq); - struct irq_cascade_desc *cascade = container_of(parent, - struct irq_cascade_desc, desc); - if (parent && cascade->ops->mask) - cascade->ops->mask(parent, irq - cascade->irq_base, cpu); + struct irq_cascade_desc *cascade = interrupt_get_parent(irq); + + if (cascade && cascade->ops->mask) + cascade->ops->mask(&cascade->desc, irq - cascade->irq_base, + cpu); } void interrupt_unmask(uint32_t irq, unsigned int cpu) { - struct irq_desc *parent = interrupt_get_parent(irq); - struct irq_cascade_desc *cascade = container_of(parent, - struct irq_cascade_desc, desc); - if (parent && cascade->ops->unmask) - cascade->ops->unmask(parent, irq - cascade->irq_base, cpu); + struct irq_cascade_desc *cascade = interrupt_get_parent(irq); + + if (cascade && cascade->ops->unmask) + cascade->ops->unmask(&cascade->desc, irq - cascade->irq_base, + cpu); } static void irq_mask(struct irq_desc *desc, uint32_t irq, unsigned int core) diff --git a/src/drivers/interrupt.c b/src/drivers/interrupt.c index e64f13dc7ccf..a3d67721912a 100644 --- a/src/drivers/interrupt.c +++ b/src/drivers/interrupt.c @@ -115,10 +115,9 @@ int interrupt_get_irq(unsigned int irq, const char *name) return ret; } -struct irq_desc *interrupt_get_parent(uint32_t irq) +struct irq_cascade_desc *interrupt_get_parent(uint32_t irq) { - struct irq_cascade_desc *cascade; - struct irq_desc *parent = NULL; + struct irq_cascade_desc *cascade, *c = NULL; unsigned long flags; if (irq < PLATFORM_IRQ_CHILDREN) @@ -131,13 +130,13 @@ struct irq_desc *interrupt_get_parent(uint32_t irq) for (cascade = cascade_root.list; cascade; cascade = cascade->next) if (irq >= cascade->irq_base && irq < cascade->irq_base + PLATFORM_IRQ_CHILDREN) { - parent = &cascade->desc; + c = cascade; break; } spin_unlock_irq(&cascade_lock, flags); - return parent; + return c; } void interrupt_init(void) @@ -147,20 +146,15 @@ void interrupt_init(void) spinlock_init(&cascade_lock); } -static int irq_register_child(struct irq_desc *parent, int irq, int unmask, - void (*handler)(void *arg), void *arg, struct irq_desc *desc) +static int irq_register_child(struct irq_cascade_desc *cascade, int irq, + int unmask, void (*handler)(void *arg), void *arg, + struct irq_desc *desc) { unsigned int core = cpu_get_id(); - struct irq_desc *child; - struct irq_cascade_desc *cascade; + struct irq_desc *child, *parent = &cascade->desc; struct list_item *list, *head; int hw_irq, ret = 0; - if (parent == NULL) - return -EINVAL; - - cascade = container_of(parent, struct irq_cascade_desc, desc); - hw_irq = irq - cascade->irq_base; if (hw_irq < 0 || cascade->irq_base + PLATFORM_IRQ_CHILDREN <= irq) @@ -219,12 +213,10 @@ static int irq_register_child(struct irq_desc *parent, int irq, int unmask, return ret; } -static void irq_unregister_child(struct irq_desc *parent, int irq, +static void irq_unregister_child(struct irq_cascade_desc *cascade, int irq, const void *arg, struct irq_desc *desc) { - struct irq_desc *child; - struct irq_cascade_desc *cascade = container_of(parent, - struct irq_cascade_desc, desc); + struct irq_desc *child, *parent = &cascade->desc; int hw_irq = irq - cascade->irq_base; struct list_item *list, *head = &cascade->child[hw_irq].list; unsigned int core = cpu_get_id(); @@ -251,10 +243,9 @@ static void irq_unregister_child(struct irq_desc *parent, int irq, } } -static uint32_t irq_enable_child(struct irq_desc *parent, int irq, void *arg) +static uint32_t irq_enable_child(struct irq_cascade_desc *cascade, int irq, + void *arg) { - struct irq_cascade_desc *cascade = container_of(parent, - struct irq_cascade_desc, desc); int hw_irq = irq - cascade->irq_base; unsigned int core = cpu_get_id(); struct irq_child *child; @@ -285,7 +276,8 @@ static uint32_t irq_enable_child(struct irq_desc *parent, int irq, void *arg) if (!child->enable_count[child_idx]++) { /* enable the parent interrupt */ if (!cascade->enable_count[core]++) - interrupt_enable(parent->irq, parent->handler_arg); + interrupt_enable(cascade->desc.irq, + cascade->desc.handler_arg); /* enable the child interrupt */ interrupt_unmask(irq, core); @@ -296,10 +288,9 @@ static uint32_t irq_enable_child(struct irq_desc *parent, int irq, void *arg) return 0; } -static uint32_t irq_disable_child(struct irq_desc *parent, int irq, void *arg) +static uint32_t irq_disable_child(struct irq_cascade_desc *cascade, int irq, + void *arg) { - struct irq_cascade_desc *cascade = container_of(parent, - struct irq_cascade_desc, desc); int hw_irq = irq - cascade->irq_base; unsigned int core = cpu_get_id(); struct irq_child *child; @@ -332,7 +323,8 @@ static uint32_t irq_disable_child(struct irq_desc *parent, int irq, void *arg) /* disable the parent interrupt */ if (!--cascade->enable_count[core]) - interrupt_disable(parent->irq, parent->handler_arg); + interrupt_disable(cascade->desc.irq, + cascade->desc.handler_arg); } spin_unlock_irq(&cascade->lock, flags); @@ -351,21 +343,17 @@ static int interrupt_register_internal(uint32_t irq, int unmask, void *arg, struct irq_desc *desc) { struct irq_cascade_desc *cascade; - struct irq_desc *parent; /* Avoid a bogus compiler warning */ unsigned long flags = 0; int ret; /* no parent means we are registering DSP internal IRQ */ - parent = interrupt_get_parent(irq); - if (parent == NULL) + cascade = interrupt_get_parent(irq); + if (!cascade) return arch_interrupt_register(irq, handler, arg); - cascade = container_of(parent, struct irq_cascade_desc, desc); - spin_lock_irq(&cascade->lock, flags); - ret = irq_register_child(parent, irq, unmask, handler, arg, - desc); + ret = irq_register_child(cascade, irq, unmask, handler, arg, desc); spin_unlock_irq(&cascade->lock, flags); return ret; @@ -380,44 +368,41 @@ static void interrupt_unregister_internal(uint32_t irq, const void *arg, struct irq_desc *desc) { struct irq_cascade_desc *cascade; - struct irq_desc *parent; /* Avoid a bogus compiler warning */ unsigned long flags = 0; /* no parent means we are unregistering DSP internal IRQ */ - parent = interrupt_get_parent(irq); - if (!parent) { + cascade = interrupt_get_parent(irq); + if (!cascade) { arch_interrupt_unregister(irq); return; } - cascade = container_of(parent, struct irq_cascade_desc, desc); - spin_lock_irq(&cascade->lock, flags); - irq_unregister_child(parent, irq, arg, desc); + irq_unregister_child(cascade, irq, arg, desc); spin_unlock_irq(&cascade->lock, flags); } uint32_t interrupt_enable(uint32_t irq, void *arg) { - struct irq_desc *parent; + struct irq_cascade_desc *cascade; /* no parent means we are enabling DSP internal IRQ */ - parent = interrupt_get_parent(irq); - if (parent == NULL) - return arch_interrupt_enable_mask(1 << irq); - else - return irq_enable_child(parent, irq, arg); + cascade = interrupt_get_parent(irq); + if (cascade) + return irq_enable_child(cascade, irq, arg); + + return arch_interrupt_enable_mask(1 << irq); } uint32_t interrupt_disable(uint32_t irq, void *arg) { - struct irq_desc *parent; + struct irq_cascade_desc *cascade; /* no parent means we are disabling DSP internal IRQ */ - parent = interrupt_get_parent(irq); - if (parent == NULL) - return arch_interrupt_disable_mask(1 << irq); - else - return irq_disable_child(parent, irq, arg); + cascade = interrupt_get_parent(irq); + if (cascade) + return irq_disable_child(cascade, irq, arg); + + return arch_interrupt_disable_mask(1 << irq); } diff --git a/src/include/sof/drivers/interrupt.h b/src/include/sof/drivers/interrupt.h index 8f086b577afa..aa48dc00fd07 100644 --- a/src/include/sof/drivers/interrupt.h +++ b/src/include/sof/drivers/interrupt.h @@ -134,7 +134,7 @@ void interrupt_unmask(uint32_t irq, unsigned int cpu); void interrupt_init(void); int interrupt_cascade_register(const struct irq_cascade_tmpl *tmpl); -struct irq_desc *interrupt_get_parent(uint32_t irq); +struct irq_cascade_desc *interrupt_get_parent(uint32_t irq); int interrupt_get_irq(unsigned int irq, const char *cascade); static inline void interrupt_set(int irq) From 01c68184a07e2a368d0bd8bc5147ede748d03167 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Tue, 26 Mar 2019 14:20:42 +0100 Subject: [PATCH 25/25] interrupt: add doxygen documentation for struct irq_desc Other global interrupt-related structs are already documented, add missing documentation to struct irq_desc Signed-off-by: Guennadi Liakhovetski --- src/include/sof/drivers/interrupt.h | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/src/include/sof/drivers/interrupt.h b/src/include/sof/drivers/interrupt.h index aa48dc00fd07..f85cf66b6a73 100644 --- a/src/include/sof/drivers/interrupt.h +++ b/src/include/sof/drivers/interrupt.h @@ -35,19 +35,20 @@ struct irq_child { */ }; +/** + * \brief interrupt client descriptor + */ struct irq_desc { - int irq; /* logical IRQ number */ - - void (*handler)(void *arg); - void *handler_arg; - - /* whether irq should be automatically unmasked */ - int unmask; - - uint32_t cpu_mask; - - /* to link to other irq_desc */ - struct list_item irq_list; + int irq; /**< virtual IRQ number */ + void (*handler)(void *arg); /**< interrupt handler function */ + void *handler_arg; /**< interrupt handler argument */ + int unmask; /**< whether irq should be + * automatically unmasked + */ + uint32_t cpu_mask; /**< a mask of CPUs on which this + * interrupt is enabled + */ + struct list_item irq_list; /**< to link to other irq_desc */ }; /**