[Sound-open-firmware] [PATCH_V3 1/8] interrupt refinement
The issues for original data structure and algorithm are: (1)it only supports 2 level interrupt architecture. (2)it doesn't support different HW interrupt shares one IRQ value. (3)it doesn't support multi-core.
The refinement is based on the prototype provided by Liam. refine irq data structure to make it support more than 2 level and issue(2). Add multi-core support in interrupt setting
test on CNL & APL & BYT, pass SOF: master c1f2682c210201 kernel: v4.14 d09db67c5a9d6d SOF-tools: master 13b56fa6047c566a
Rander Wang (7): interrupt: refine irq structure and algorithm interrupt: add irq id in IRQ cnl-interrupt: refine interrupt setting for change in irq_desc cnl-dma: remove special dma code for cnl apl-interrupt: refine interrupt code according to interrupt change byt-interrupt: port irq change to byt hsw-interrupt: port irq change to hsw
src/drivers/dw-dma.c | 32 +-- src/include/sof/interrupt-map.h | 17 ++ src/include/sof/interrupt.h | 32 +-- src/lib/interrupt.c | 120 +++++------ .../apollolake/include/platform/interrupt.h | 2 +- src/platform/apollolake/include/platform/memory.h | 4 +- .../apollolake/include/platform/platform.h | 2 + src/platform/apollolake/interrupt.c | 210 ++++++++++++-------- src/platform/baytrail/include/platform/interrupt.h | 2 +- src/platform/cannonlake/dma.c | 2 +- .../cannonlake/include/platform/interrupt.h | 16 +- src/platform/cannonlake/include/platform/memory.h | 2 +- .../cannonlake/include/platform/platform.h | 2 + src/platform/cannonlake/interrupt.c | 220 +++++++++++++-------- src/platform/haswell/include/platform/interrupt.h | 2 +- 15 files changed, 382 insertions(+), 283 deletions(-)
The issue for original data structure and algorithm is that: (1)it only support 2 level interrupt architecture. (2)it doesn't support two HW interrupt triggered by one irq pin.
Unify irq parent and child to irq_desc. Now each irq_desc maybe directly attach to xtensa core or another irq_desc.Each irq_desc may have 32 child list instead of 32 child.
--- V2: check whether memory allocation failed V3: remove useless declaration in interrupt.h
test on CNL & APL & BYT, pass SOF: master c1f2682c210201 kernel: v4.14 d09db67c5a9d6d SOF-tools: master 13b56fa6047c566a
Signed-off-by: Rander Wang rander.wang@linux.intel.com Signed-off-by: Liam Girdwood liam.r.girdwood@linux.intel.com --- src/include/sof/interrupt.h | 29 +++++----- src/lib/interrupt.c | 126 +++++++++++++++++++++++++------------------- 2 files changed, 83 insertions(+), 72 deletions(-)
diff --git a/src/include/sof/interrupt.h b/src/include/sof/interrupt.h index 2dc8954..bbda635 100644 --- a/src/include/sof/interrupt.h +++ b/src/include/sof/interrupt.h @@ -37,27 +37,29 @@ #include <sof/trace.h> #include <sof/debug.h> #include <sof/lock.h> +#include <sof/list.h>
#define trace_irq(__e) trace_event(TRACE_CLASS_IRQ, __e) #define trace_irq_error(__e) trace_error(TRACE_CLASS_IRQ, __e)
-/* child interrupt source */ -struct irq_child { - uint32_t enabled; +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; -};
-/* parent source */ -struct irq_parent { - int num; - void (*handler)(void *arg); - uint32_t enabled_count; + /* 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;
uint32_t num_children; - struct irq_child *child[PLATFORM_IRQ_CHILDREN]; + struct list_item child[PLATFORM_IRQ_CHILDREN]; };
int interrupt_register(uint32_t irq, @@ -86,11 +88,4 @@ static inline void interrupt_global_enable(uint32_t flags) arch_interrupt_global_enable(flags); }
-/* called by platform interrupt ops */ -int irq_register_child(struct irq_parent *parent, int irq, - void (*handler)(void *arg), void *arg); -void irq_unregister_child(struct irq_parent *parent, int irq); -uint32_t irq_enable_child(struct irq_parent *parent, int irq); -uint32_t irq_disable_child(struct irq_parent *parent, int irq); - #endif diff --git a/src/lib/interrupt.c b/src/lib/interrupt.c index e8e2899..a1f22eb 100644 --- a/src/lib/interrupt.c +++ b/src/lib/interrupt.c @@ -38,127 +38,143 @@ #include <stdint.h> #include <stdlib.h>
-int irq_register_child(struct irq_parent *parent, int irq, - void (*handler)(void *arg), void *arg) +static int irq_register_child(struct irq_desc *parent, int irq, + void (*handler)(void *arg), void *arg); +static void irq_unregister_child(struct irq_desc *parent, int irq); +static uint32_t irq_enable_child(struct irq_desc *parent, int irq); +static uint32_t irq_disable_child(struct irq_desc *parent, int irq); + +static int irq_register_child(struct irq_desc *parent, int irq, + void (*handler)(void *arg), void *arg) { int ret = 0; + struct irq_desc *child;
if (parent == NULL) return -EINVAL;
spin_lock(&parent->lock);
- /* does child already exist ? */ - if (parent->child[SOF_IRQ_BIT(irq)]) { - /* already registered, return */ + /* init child */ + child = rzalloc(RZONE_SYS, SOF_MEM_CAPS_RAM, + sizeof(struct irq_desc)); + if (!child) { + ret = -ENOMEM; goto finish; }
- /* init child */ - parent->child[SOF_IRQ_BIT(irq)] = - rzalloc(RZONE_SYS, SOF_MEM_CAPS_RAM, - sizeof(struct irq_child)); - parent->child[SOF_IRQ_BIT(irq)]->enabled = 0; - parent->child[SOF_IRQ_BIT(irq)]->handler = handler; - parent->child[SOF_IRQ_BIT(irq)]->handler_arg = arg; + child->enabled_count = 0; + child->handler = handler; + child->handler_arg = arg; + child->id = SOF_IRQ_ID(irq); + + list_item_append(&child->irq_list, &parent->child[SOF_IRQ_BIT(irq)]);
/* do we need to register parent ? */ if (parent->num_children == 0) { - ret = arch_interrupt_register(parent->num, - parent->handler, parent); + ret = arch_interrupt_register(parent->irq, + parent->handler, parent); }
/* increment number of children */ - parent->num_children += 1; + parent->num_children++;
finish: spin_unlock(&parent->lock); return ret; - }
-void irq_unregister_child(struct irq_parent *parent, int irq) +static void irq_unregister_child(struct irq_desc *parent, int irq) { spin_lock(&parent->lock); + struct irq_desc *child; + struct list_item *clist;
/* does child already exist ? */ - if (!parent->child[SOF_IRQ_BIT(irq)]) + if (list_is_empty(&parent->child[SOF_IRQ_BIT(irq)])) goto finish;
- /* free child */ - parent->num_children -= 1; - rfree(parent->child[SOF_IRQ_BIT(irq)]); - parent->child[SOF_IRQ_BIT(irq)] = NULL; + list_for_item(clist, &parent->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); + rfree(child); + parent->num_children--; + } + }
/* * unregister the root interrupt if the this l2 is * the last registered one. */ if (parent->num_children == 0) - arch_interrupt_unregister(parent->num); + arch_interrupt_unregister(parent->irq);
finish: spin_unlock(&parent->lock); }
-uint32_t irq_enable_child(struct irq_parent *parent, int irq) +static uint32_t irq_enable_child(struct irq_desc *parent, int irq) { - struct irq_child *child; + struct irq_desc *child; + struct list_item *clist;
spin_lock(&parent->lock);
- child = parent->child[SOF_IRQ_BIT(irq)]; - - /* already enabled ? */ - if (child->enabled) - goto finish; - /* enable the parent interrupt */ if (parent->enabled_count == 0) arch_interrupt_enable_mask(1 << SOF_IRQ_NUMBER(irq)); - child->enabled = 1; - parent->enabled_count++;
- /* enable the child interrupt */ - platform_interrupt_unmask(irq, 0); + list_for_item(clist, &parent->child[SOF_IRQ_BIT(irq)]) { + child = container_of(clist, struct irq_desc, irq_list); + + 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, 0); + } + }
-finish: spin_unlock(&parent->lock); return 0;
}
-uint32_t irq_disable_child(struct irq_parent *parent, int irq) +static uint32_t irq_disable_child(struct irq_desc *parent, int irq) { - struct irq_child *child; + struct irq_desc *child; + struct list_item *clist;
spin_lock(&parent->lock);
- child = parent->child[SOF_IRQ_BIT(irq)]; - - /* already disabled ? */ - if (!child->enabled) - goto finish; + list_for_item(clist, &parent->child[SOF_IRQ_BIT(irq)]) { + child = container_of(clist, struct irq_desc, irq_list);
- /* disable the child interrupt */ - platform_interrupt_mask(irq, 0); - child->enabled = 0; + if ((SOF_IRQ_ID(irq) == child->id) && + child->enabled_count) { + child->enabled_count = 0; + parent->enabled_count--; + } + }
- /* disable the parent interrupt */ - parent->enabled_count--; - if (parent->enabled_count == 0) + if (parent->enabled_count == 0) { + /* disable the child interrupt */ + platform_interrupt_mask(irq, 0); arch_interrupt_disable_mask(1 << SOF_IRQ_NUMBER(irq)); + }
-finish: spin_unlock(&parent->lock); return 0; - }
int interrupt_register(uint32_t irq, void (*handler)(void *arg), void *arg) { - struct irq_parent *parent; + struct irq_desc *parent;
/* no parent means we are registering DSP internal IRQ */ parent = platform_irq_get_parent(irq); @@ -170,7 +186,7 @@ int interrupt_register(uint32_t irq,
void interrupt_unregister(uint32_t irq) { - struct irq_parent *parent; + struct irq_desc *parent;
/* no parent means we are unregistering DSP internal IRQ */ parent = platform_irq_get_parent(irq); @@ -182,7 +198,7 @@ void interrupt_unregister(uint32_t irq)
uint32_t interrupt_enable(uint32_t irq) { - struct irq_parent *parent; + struct irq_desc *parent;
/* no parent means we are enabling DSP internal IRQ */ parent = platform_irq_get_parent(irq); @@ -194,7 +210,7 @@ uint32_t interrupt_enable(uint32_t irq)
uint32_t interrupt_disable(uint32_t irq) { - struct irq_parent *parent; + struct irq_desc *parent;
/* no parent means we are disabling DSP internal IRQ */ parent = platform_irq_get_parent(irq);
-----Original Message----- From: sound-open-firmware-bounces@alsa-project.org [mailto:sound-open- firmware-bounces@alsa-project.org] On Behalf Of Rander Wang Sent: Thursday, May 10, 2018 1:32 PM To: sound-open-firmware@alsa-project.org; marcin.maka@linux.intel.com Cc: Liam Girdwood liam.r.girdwood@linux.intel.com; Rander Wang rander.wang@linux.intel.com Subject: [Sound-open-firmware] [PATCH_V3 1/8] interrupt: refine irq structure and algorithm
The issue for original data structure and algorithm is that: (1)it only support 2 level interrupt architecture. (2)it doesn't support two HW interrupt triggered by one irq pin.
Unify irq parent and child to irq_desc. Now each irq_desc maybe directly attach to xtensa core or another irq_desc.Each irq_desc may have 32 child list instead of 32 child.
V2: check whether memory allocation failed V3: remove useless declaration in interrupt.h
test on CNL & APL & BYT, pass SOF: master c1f2682c210201 kernel: v4.14 d09db67c5a9d6d SOF-tools: master 13b56fa6047c566a
Signed-off-by: Rander Wang rander.wang@linux.intel.com Signed-off-by: Liam Girdwood liam.r.girdwood@linux.intel.com
src/include/sof/interrupt.h | 29 +++++----- src/lib/interrupt.c | 126 +++++++++++++++++++++++++------------------- 2 files changed, 83 insertions(+), 72 deletions(-)
diff --git a/src/include/sof/interrupt.h b/src/include/sof/interrupt.h index 2dc8954..bbda635 100644 --- a/src/include/sof/interrupt.h +++ b/src/include/sof/interrupt.h @@ -37,27 +37,29 @@ #include <sof/trace.h> #include <sof/debug.h> #include <sof/lock.h> +#include <sof/list.h>
#define trace_irq(__e) trace_event(TRACE_CLASS_IRQ, __e) #define trace_irq_error(__e) trace_error(TRACE_CLASS_IRQ, __e)
-/* child interrupt source */ -struct irq_child {
- uint32_t enabled;
+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;
-};
-/* parent source */ -struct irq_parent {
- int num;
- void (*handler)(void *arg);
- uint32_t enabled_count;
/* 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;
uint32_t num_children;
- struct irq_child *child[PLATFORM_IRQ_CHILDREN];
- struct list_item child[PLATFORM_IRQ_CHILDREN];
};
int interrupt_register(uint32_t irq, @@ -86,11 +88,4 @@ static inline void interrupt_global_enable(uint32_t flags) arch_interrupt_global_enable(flags); }
-/* called by platform interrupt ops */ -int irq_register_child(struct irq_parent *parent, int irq,
- void (*handler)(void *arg), void *arg);
-void irq_unregister_child(struct irq_parent *parent, int irq); -uint32_t irq_enable_child(struct irq_parent *parent, int irq); -uint32_t irq_disable_child(struct irq_parent *parent, int irq);
#endif diff --git a/src/lib/interrupt.c b/src/lib/interrupt.c index e8e2899..a1f22eb 100644 --- a/src/lib/interrupt.c +++ b/src/lib/interrupt.c @@ -38,127 +38,143 @@ #include <stdint.h> #include <stdlib.h>
-int irq_register_child(struct irq_parent *parent, int irq,
- void (*handler)(void *arg), void *arg)
+static int irq_register_child(struct irq_desc *parent, int irq,
void (*handler)(void *arg), void *arg); static void
+irq_unregister_child(struct irq_desc *parent, int irq); static uint32_t +irq_enable_child(struct irq_desc *parent, int irq); static uint32_t +irq_disable_child(struct irq_desc *parent, int irq);
+static int irq_register_child(struct irq_desc *parent, int irq,
void (*handler)(void *arg), void *arg)
{ int ret = 0;
struct irq_desc *child;
if (parent == NULL) return -EINVAL;
spin_lock(&parent->lock);
- /* does child already exist ? */
- if (parent->child[SOF_IRQ_BIT(irq)]) {
/* already registered, return */
- /* init child */
- child = rzalloc(RZONE_SYS, SOF_MEM_CAPS_RAM,
sizeof(struct irq_desc));
- if (!child) {
goto finish; }ret = -ENOMEM;
- /* init child */
- parent->child[SOF_IRQ_BIT(irq)] =
rzalloc(RZONE_SYS, SOF_MEM_CAPS_RAM,
sizeof(struct irq_child));
- parent->child[SOF_IRQ_BIT(irq)]->enabled = 0;
- parent->child[SOF_IRQ_BIT(irq)]->handler = handler;
- parent->child[SOF_IRQ_BIT(irq)]->handler_arg = arg;
child->enabled_count = 0;
child->handler = handler;
child->handler_arg = arg;
child->id = SOF_IRQ_ID(irq);
list_item_append(&child->irq_list, &parent->child[SOF_IRQ_BIT(irq)]);
/* do we need to register parent ? */ if (parent->num_children == 0) {
ret = arch_interrupt_register(parent->num,
parent->handler, parent);
ret = arch_interrupt_register(parent->irq,
parent->handler, parent);
}
/* increment number of children */
- parent->num_children += 1;
- parent->num_children++;
finish: spin_unlock(&parent->lock); return ret;
}
-void irq_unregister_child(struct irq_parent *parent, int irq) +static void irq_unregister_child(struct irq_desc *parent, int irq) { spin_lock(&parent->lock);
struct irq_desc *child;
struct list_item *clist;
/* does child already exist ? */
- if (!parent->child[SOF_IRQ_BIT(irq)])
- if (list_is_empty(&parent->child[SOF_IRQ_BIT(irq)])) goto finish;
- /* free child */
- parent->num_children -= 1;
- rfree(parent->child[SOF_IRQ_BIT(irq)]);
- parent->child[SOF_IRQ_BIT(irq)] = NULL;
list_for_item(clist, &parent->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);
rfree(child);
parent->num_children--;
}
}
/*
- unregister the root interrupt if the this l2 is
- the last registered one.
*/ if (parent->num_children == 0)
arch_interrupt_unregister(parent->num);
arch_interrupt_unregister(parent->irq);
Is it possible here the parent also has parent? If so, we need a recursive calling here.
finish: spin_unlock(&parent->lock); }
-uint32_t irq_enable_child(struct irq_parent *parent, int irq) +static uint32_t irq_enable_child(struct irq_desc *parent, int irq) {
- struct irq_child *child;
struct irq_desc *child;
struct list_item *clist;
spin_lock(&parent->lock);
child = parent->child[SOF_IRQ_BIT(irq)];
/* already enabled ? */
if (child->enabled)
goto finish;
/* enable the parent interrupt */ if (parent->enabled_count == 0) arch_interrupt_enable_mask(1 << SOF_IRQ_NUMBER(irq));
child->enabled = 1;
parent->enabled_count++;
/* enable the child interrupt */
platform_interrupt_unmask(irq, 0);
- list_for_item(clist, &parent->child[SOF_IRQ_BIT(irq)]) {
child = container_of(clist, struct irq_desc, irq_list);
if ((SOF_IRQ_ID(irq) == child->id) &&
!child->enabled_count) {
child->enabled_count = 1;
Is child here has its child possible?
parent->enabled_count++;
/* enable the child interrupt */
platform_interrupt_unmask(irq, 0);
}
- }
-finish: spin_unlock(&parent->lock); return 0;
}
-uint32_t irq_disable_child(struct irq_parent *parent, int irq) +static uint32_t irq_disable_child(struct irq_desc *parent, int irq) {
- struct irq_child *child;
struct irq_desc *child;
struct list_item *clist;
spin_lock(&parent->lock);
- child = parent->child[SOF_IRQ_BIT(irq)];
- /* already disabled ? */
- if (!child->enabled)
goto finish;
- list_for_item(clist, &parent->child[SOF_IRQ_BIT(irq)]) {
child = container_of(clist, struct irq_desc, irq_list);
- /* disable the child interrupt */
- platform_interrupt_mask(irq, 0);
- child->enabled = 0;
if ((SOF_IRQ_ID(irq) == child->id) &&
child->enabled_count) {
child->enabled_count = 0;
Same question here.
Thanks, ~Keyon
parent->enabled_count--;
}
- }
- /* disable the parent interrupt */
- parent->enabled_count--;
- if (parent->enabled_count == 0)
- if (parent->enabled_count == 0) {
/* disable the child interrupt */
arch_interrupt_disable_mask(1 << SOF_IRQ_NUMBER(irq));platform_interrupt_mask(irq, 0);
- }
-finish: spin_unlock(&parent->lock); return 0;
}
int interrupt_register(uint32_t irq, void (*handler)(void *arg), void *arg) {
- struct irq_parent *parent;
struct irq_desc *parent;
/* no parent means we are registering DSP internal IRQ */ parent = platform_irq_get_parent(irq); @@ -170,7 +186,7 @@ int
interrupt_register(uint32_t irq,
void interrupt_unregister(uint32_t irq) {
- struct irq_parent *parent;
struct irq_desc *parent;
/* no parent means we are unregistering DSP internal IRQ */ parent = platform_irq_get_parent(irq); @@ -182,7 +198,7 @@ void
interrupt_unregister(uint32_t irq)
uint32_t interrupt_enable(uint32_t irq) {
- struct irq_parent *parent;
struct irq_desc *parent;
/* no parent means we are enabling DSP internal IRQ */ parent = platform_irq_get_parent(irq); @@ -194,7 +210,7 @@ uint32_t
interrupt_enable(uint32_t irq)
uint32_t interrupt_disable(uint32_t irq) {
- struct irq_parent *parent;
struct irq_desc *parent;
/* no parent means we are disabling DSP internal IRQ */ parent = platform_irq_get_parent(irq);
-- 2.14.1
Sound-open-firmware mailing list Sound-open-firmware@alsa-project.org http://mailman.alsa-project.org/mailman/listinfo/sound-open-firmware
On 5/10/2018 9:44 PM, Jie, Yang wrote:
-----Original Message----- From: sound-open-firmware-bounces@alsa-project.org [mailto:sound-open- firmware-bounces@alsa-project.org] On Behalf Of Rander Wang Sent: Thursday, May 10, 2018 1:32 PM To: sound-open-firmware@alsa-project.org; marcin.maka@linux.intel.com Cc: Liam Girdwood liam.r.girdwood@linux.intel.com; Rander Wang rander.wang@linux.intel.com Subject: [Sound-open-firmware] [PATCH_V3 1/8] interrupt: refine irq structure and algorithm
The issue for original data structure and algorithm is that: (1)it only support 2 level interrupt architecture. (2)it doesn't support two HW interrupt triggered by one irq pin.
Unify irq parent and child to irq_desc. Now each irq_desc maybe directly attach to xtensa core or another irq_desc.Each irq_desc may have 32 child list instead of 32 child.
V2: check whether memory allocation failed V3: remove useless declaration in interrupt.h
test on CNL & APL & BYT, pass SOF: master c1f2682c210201 kernel: v4.14 d09db67c5a9d6d SOF-tools: master 13b56fa6047c566a
Signed-off-by: Rander Wang rander.wang@linux.intel.com Signed-off-by: Liam Girdwood liam.r.girdwood@linux.intel.com
src/include/sof/interrupt.h | 29 +++++----- src/lib/interrupt.c | 126 +++++++++++++++++++++++++------------------- 2 files changed, 83 insertions(+), 72 deletions(-)
diff --git a/src/include/sof/interrupt.h b/src/include/sof/interrupt.h index 2dc8954..bbda635 100644 --- a/src/include/sof/interrupt.h +++ b/src/include/sof/interrupt.h @@ -37,27 +37,29 @@ #include <sof/trace.h> #include <sof/debug.h> #include <sof/lock.h> +#include <sof/list.h>
#define trace_irq(__e) trace_event(TRACE_CLASS_IRQ, __e) #define trace_irq_error(__e) trace_error(TRACE_CLASS_IRQ, __e)
-/* child interrupt source */ -struct irq_child {
- uint32_t enabled;
+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;
-};
-/* parent source */ -struct irq_parent {
- int num;
- void (*handler)(void *arg);
- uint32_t enabled_count;
/* 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;
uint32_t num_children;
- struct irq_child *child[PLATFORM_IRQ_CHILDREN];
- struct list_item child[PLATFORM_IRQ_CHILDREN];
};
int interrupt_register(uint32_t irq, @@ -86,11 +88,4 @@ static inline void interrupt_global_enable(uint32_t flags) arch_interrupt_global_enable(flags); }
-/* called by platform interrupt ops */ -int irq_register_child(struct irq_parent *parent, int irq,
- void (*handler)(void *arg), void *arg);
-void irq_unregister_child(struct irq_parent *parent, int irq); -uint32_t irq_enable_child(struct irq_parent *parent, int irq); -uint32_t irq_disable_child(struct irq_parent *parent, int irq);
#endif diff --git a/src/lib/interrupt.c b/src/lib/interrupt.c index e8e2899..a1f22eb 100644 --- a/src/lib/interrupt.c +++ b/src/lib/interrupt.c @@ -38,127 +38,143 @@ #include <stdint.h> #include <stdlib.h>
-int irq_register_child(struct irq_parent *parent, int irq,
- void (*handler)(void *arg), void *arg)
+static int irq_register_child(struct irq_desc *parent, int irq,
void (*handler)(void *arg), void *arg); static void
+irq_unregister_child(struct irq_desc *parent, int irq); static uint32_t +irq_enable_child(struct irq_desc *parent, int irq); static uint32_t +irq_disable_child(struct irq_desc *parent, int irq);
+static int irq_register_child(struct irq_desc *parent, int irq,
void (*handler)(void *arg), void *arg)
{ int ret = 0;
struct irq_desc *child;
if (parent == NULL) return -EINVAL;
spin_lock(&parent->lock);
- /* does child already exist ? */
- if (parent->child[SOF_IRQ_BIT(irq)]) {
/* already registered, return */
- /* init child */
- child = rzalloc(RZONE_SYS, SOF_MEM_CAPS_RAM,
sizeof(struct irq_desc));
- if (!child) {
goto finish; }ret = -ENOMEM;
- /* init child */
- parent->child[SOF_IRQ_BIT(irq)] =
rzalloc(RZONE_SYS, SOF_MEM_CAPS_RAM,
sizeof(struct irq_child));
- parent->child[SOF_IRQ_BIT(irq)]->enabled = 0;
- parent->child[SOF_IRQ_BIT(irq)]->handler = handler;
- parent->child[SOF_IRQ_BIT(irq)]->handler_arg = arg;
child->enabled_count = 0;
child->handler = handler;
child->handler_arg = arg;
child->id = SOF_IRQ_ID(irq);
list_item_append(&child->irq_list, &parent->child[SOF_IRQ_BIT(irq)]);
/* do we need to register parent ? */ if (parent->num_children == 0) {
ret = arch_interrupt_register(parent->num,
parent->handler, parent);
ret = arch_interrupt_register(parent->irq,
parent->handler, parent);
}
/* increment number of children */
- parent->num_children += 1;
- parent->num_children++;
finish: spin_unlock(&parent->lock); return ret;
}
-void irq_unregister_child(struct irq_parent *parent, int irq) +static void irq_unregister_child(struct irq_desc *parent, int irq) { spin_lock(&parent->lock);
struct irq_desc *child;
struct list_item *clist;
/* does child already exist ? */
- if (!parent->child[SOF_IRQ_BIT(irq)])
- if (list_is_empty(&parent->child[SOF_IRQ_BIT(irq)])) goto finish;
- /* free child */
- parent->num_children -= 1;
- rfree(parent->child[SOF_IRQ_BIT(irq)]);
- parent->child[SOF_IRQ_BIT(irq)] = NULL;
list_for_item(clist, &parent->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);
rfree(child);
parent->num_children--;
}
}
/*
- unregister the root interrupt if the this l2 is
- the last registered one.
*/ if (parent->num_children == 0)
arch_interrupt_unregister(parent->num);
arch_interrupt_unregister(parent->irq);
Is it possible here the parent also has parent? If so, we need a recursive calling here.
as we have discussed, parent connects to xtensa core, child connects to parent in a link list. only the first
level of irqs is parent which is used to set interrupt in xtensa core. other irqs are all children of corresponding parent,
and they are linked to the parent. you can refer to Linux kernel, all the irqs are linked in a list attached to a root irq,
no recursive level.
finish: spin_unlock(&parent->lock); }
-uint32_t irq_enable_child(struct irq_parent *parent, int irq) +static uint32_t irq_enable_child(struct irq_desc *parent, int irq) {
- struct irq_child *child;
struct irq_desc *child;
struct list_item *clist;
spin_lock(&parent->lock);
child = parent->child[SOF_IRQ_BIT(irq)];
/* already enabled ? */
if (child->enabled)
goto finish;
/* enable the parent interrupt */ if (parent->enabled_count == 0) arch_interrupt_enable_mask(1 << SOF_IRQ_NUMBER(irq));
child->enabled = 1;
parent->enabled_count++;
/* enable the child interrupt */
platform_interrupt_unmask(irq, 0);
- list_for_item(clist, &parent->child[SOF_IRQ_BIT(irq)]) {
child = container_of(clist, struct irq_desc, irq_list);
if ((SOF_IRQ_ID(irq) == child->id) &&
!child->enabled_count) {
child->enabled_count = 1;
Is child here has its child possible?
parent->enabled_count++;
/* enable the child interrupt */
platform_interrupt_unmask(irq, 0);
}
- }
-finish: spin_unlock(&parent->lock); return 0;
}
-uint32_t irq_disable_child(struct irq_parent *parent, int irq) +static uint32_t irq_disable_child(struct irq_desc *parent, int irq) {
- struct irq_child *child;
struct irq_desc *child;
struct list_item *clist;
spin_lock(&parent->lock);
- child = parent->child[SOF_IRQ_BIT(irq)];
- /* already disabled ? */
- if (!child->enabled)
goto finish;
- list_for_item(clist, &parent->child[SOF_IRQ_BIT(irq)]) {
child = container_of(clist, struct irq_desc, irq_list);
- /* disable the child interrupt */
- platform_interrupt_mask(irq, 0);
- child->enabled = 0;
if ((SOF_IRQ_ID(irq) == child->id) &&
child->enabled_count) {
child->enabled_count = 0;
Same question here.
Thanks, ~Keyon
parent->enabled_count--;
}
- }
- /* disable the parent interrupt */
- parent->enabled_count--;
- if (parent->enabled_count == 0)
- if (parent->enabled_count == 0) {
/* disable the child interrupt */
arch_interrupt_disable_mask(1 << SOF_IRQ_NUMBER(irq));platform_interrupt_mask(irq, 0);
- }
-finish: spin_unlock(&parent->lock); return 0;
}
int interrupt_register(uint32_t irq, void (*handler)(void *arg), void *arg) {
- struct irq_parent *parent;
struct irq_desc *parent;
/* no parent means we are registering DSP internal IRQ */ parent = platform_irq_get_parent(irq); @@ -170,7 +186,7 @@ int
interrupt_register(uint32_t irq,
void interrupt_unregister(uint32_t irq) {
- struct irq_parent *parent;
struct irq_desc *parent;
/* no parent means we are unregistering DSP internal IRQ */ parent = platform_irq_get_parent(irq); @@ -182,7 +198,7 @@ void
interrupt_unregister(uint32_t irq)
uint32_t interrupt_enable(uint32_t irq) {
- struct irq_parent *parent;
struct irq_desc *parent;
/* no parent means we are enabling DSP internal IRQ */ parent = platform_irq_get_parent(irq); @@ -194,7 +210,7 @@ uint32_t
interrupt_enable(uint32_t irq)
uint32_t interrupt_disable(uint32_t irq) {
- struct irq_parent *parent;
struct irq_desc *parent;
/* no parent means we are disabling DSP internal IRQ */ parent = platform_irq_get_parent(irq);
-- 2.14.1
Sound-open-firmware mailing list Sound-open-firmware@alsa-project.org http://mailman.alsa-project.org/mailman/listinfo/sound-open-firmware
On Thu, 2018-05-10 at 13:32 +0800, Rander Wang wrote:
The issue for original data structure and algorithm is that: (1)it only support 2 level interrupt architecture. (2)it doesn't support two HW interrupt triggered by one irq pin.
Unify irq parent and child to irq_desc. Now each irq_desc maybe directly attach to xtensa core or another irq_desc.Each irq_desc may have 32 child list instead of 32 child.
V2: check whether memory allocation failed V3: remove useless declaration in interrupt.h
Applied, but squashed to preserve bisection.
Thanks
Liam
For CNL or later chips, a group of HW IP(like GP-DMA) share the same IRQ value. Now add id in IRQ to identify each HW interrupt. If no IRQ shared, call SOF_IRQ to get the IRQ value, and the default id value would be zero. otherwise call SOF_ID_IRQ to record its id in IRQ value.
Signed-off-by: Rander Wang rander.wang@linux.intel.com
--- no version change for this patch
test on CNL & APL & BYT, pass SOF: master c1f2682c210201 kernel: v4.14 d09db67c5a9d6d SOF-tools: master 13b56fa6047c566a
--- src/include/sof/interrupt-map.h | 17 +++++++++++++++++ 1 file changed, 17 insertions(+)
diff --git a/src/include/sof/interrupt-map.h b/src/include/sof/interrupt-map.h index bea567a..cec85df 100644 --- a/src/include/sof/interrupt-map.h +++ b/src/include/sof/interrupt-map.h @@ -33,6 +33,7 @@
#include <config.h>
+#define SOF_IRQ_ID_SHIFT 29 #define SOF_IRQ_BIT_SHIFT 24 #define SOF_IRQ_LEVEL_SHIFT 16 #define SOF_IRQ_CPU_SHIFT 8 @@ -41,6 +42,7 @@ #define SOF_IRQ_LEVEL_MASK 0xff #define SOF_IRQ_BIT_MASK 0x1f #define SOF_IRQ_CPU_MASK 0xff +#define SOF_IRQ_ID_MASK 0x7
#define SOF_IRQ(_bit, _level, _cpu, _number) \ (((_bit) << SOF_IRQ_BIT_SHIFT) \ @@ -48,6 +50,18 @@ | ((_cpu) << SOF_IRQ_CPU_SHIFT) \ | ((_number) << SOF_IRQ_NUM_SHIFT))
+/* + * for chip CNL or later, a group of HW IP(GP-DMA) share + * the same IRQ. So add id in IRQ to identify each HW IP + * for this case, it will be 5 levels + */ +#define SOF_ID_IRQ(_id, _bit, _level, _cpu, _number) \ + (((_id) << SOF_IRQ_ID_SHIFT) \ + | ((_bit) << SOF_IRQ_BIT_SHIFT) \ + | ((_level) << SOF_IRQ_LEVEL_SHIFT) \ + | ((_cpu) << SOF_IRQ_CPU_SHIFT) \ + | ((_number) << SOF_IRQ_NUM_SHIFT)) + #ifdef CONFIG_IRQ_MAP /* * IRQs are mapped on 4 levels. @@ -65,6 +79,8 @@ (((_bit) >> SOF_IRQ_BIT_SHIFT) & SOF_IRQ_BIT_MASK) #define SOF_IRQ_CPU(_cpu) \ (((_cpu) >> SOF_IRQ_CPU_SHIFT) & SOF_IRQ_CPU_MASK) +#define SOF_IRQ_ID(_bit) \ + (((_bit) >> SOF_IRQ_ID_SHIFT) & SOF_IRQ_ID_MASK) #else /* * IRQs are directly mapped onto a single level, bit and level. @@ -73,6 +89,7 @@ #define SOF_IRQ_LEVEL(_level) 0 #define SOF_IRQ_BIT(_bit) 0 #define SOF_IRQ_CPU(_cpu) 0 +#define SOF_IRQ_ID(_bit) 0 #endif
#endif
Signed-off-by: Rander Wang rander.wang@linux.intel.com --- src/arch/xtensa/include/arch/cpu.h | 43 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 src/arch/xtensa/include/arch/cpu.h
diff --git a/src/arch/xtensa/include/arch/cpu.h b/src/arch/xtensa/include/arch/cpu.h new file mode 100644 index 0000000..fecbb71 --- /dev/null +++ b/src/arch/xtensa/include/arch/cpu.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2018, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the Intel Corporation nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * Author: Rander Wang rander.wang@linux.intel.com + * + */ + +#ifndef __INCLUDE_ARCH_CPU__ +#define __INCLUDE_ARCH_CPU__ + +static inline int cpu_get_id(void) +{ + int prid; + + __asm__("rsr.prid %0" : "=a"(prid)); + return prid; +} + +#endif
(1)Add core id check in interrupt register setting. (2)Check child list in interrupt function (3)Extend root irq_desc to support 4 core on cnl. (4)Refine macro for interrupt setting
Signed-off-by: Rander Wang rander.wang@linux.intel.com Signed-off-by: Liam Girdwood liam.r.girdwood@linux.intel.com
--- V2: call cpu_get_id to get core id V3: remove duplication in handler function
test on CNL & APL & BYT, pass SOF: master c1f2682c210201 kernel: v4.14 d09db67c5a9d6d SOF-tools: master 13b56fa6047c566a --- src/platform/cannonlake/dma.c | 2 +- .../cannonlake/include/platform/interrupt.h | 16 +- src/platform/cannonlake/include/platform/memory.h | 2 +- .../cannonlake/include/platform/platform.h | 2 + src/platform/cannonlake/interrupt.c | 258 ++++++++------------- 5 files changed, 108 insertions(+), 172 deletions(-)
diff --git a/src/platform/cannonlake/dma.c b/src/platform/cannonlake/dma.c index b606d1e..3f9d6cb 100644 --- a/src/platform/cannonlake/dma.c +++ b/src/platform/cannonlake/dma.c @@ -125,7 +125,7 @@ static struct dma dma[] = { .id = DMA_GP_LP_DMAC1, .base = LP_GP_DMA_BASE(1), .channels = 8, - .irq = IRQ_EXT_LP_GPDMA0_LVL5(0, 0), + .irq = IRQ_EXT_LP_GPDMA1_LVL5(0, 0), .drv_plat_data = &dmac1, }, .ops = &dw_dma_ops, diff --git a/src/platform/cannonlake/include/platform/interrupt.h b/src/platform/cannonlake/include/platform/interrupt.h index 03857a7..b14cfdf 100644 --- a/src/platform/cannonlake/include/platform/interrupt.h +++ b/src/platform/cannonlake/include/platform/interrupt.h @@ -88,7 +88,7 @@ #define IRQ_BIT_LVL5_DMIC 6 #define IRQ_BIT_LVL5_SSP(x) (0 + x)
-/* Level 2 Peripheral IRQ mappings */ +/* 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) \ @@ -106,7 +106,7 @@ #define IRQ_EXT_SHA256_LVL2(xcpu) \ SOF_IRQ(IRQ_BIT_LVL2_SHA256, 2, xcpu, IRQ_NUM_EXT_LEVEL2)
-/* Level 3 Peripheral IRQ mappings */ +/* 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) \ @@ -114,17 +114,17 @@ #define IRQ_EXT_HOST_DMA_OUT_LVL3(xcpu, channel) \ SOF_IRQ(IRQ_BIT_LVL3_HOST_STREAM_OUT(channel), 3, xcpu, IRQ_NUM_EXT_LEVEL3)
-/* Level 4 Peripheral IRQ mappings */ +/* 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)
-/* Level 5 Peripheral IRQ mappings */ +/* Priority 5 Peripheral IRQ mappings */ #define IRQ_EXT_LP_GPDMA0_LVL5(xcpu, channel) \ - SOF_IRQ(IRQ_BIT_LVL5_LP_GP_DMA0, 5, xcpu, IRQ_NUM_EXT_LEVEL5) -#define IRQ_EXT_LP_GPDMA1_LVL4(xcpu, channel) \ - SOF_IRQ(IRQ_BIT_LVL5_LP_GP_DMA1, 4, xcpu, IRQ_NUM_EXT_LEVEL4) + 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_SSP0_LVL5(xcpu) \ SOF_IRQ(IRQ_BIT_LVL5_SSP(0), 5, xcpu, IRQ_NUM_EXT_LEVEL5) #define IRQ_EXT_SSP1_LVL5(xcpu) \ @@ -161,7 +161,7 @@
void platform_interrupt_init(void);
-struct irq_parent *platform_irq_get_parent(uint32_t irq); +struct irq_desc *platform_irq_get_parent(uint32_t irq); void platform_interrupt_set(int irq); void platform_interrupt_clear(uint32_t irq, uint32_t mask); uint32_t platform_interrupt_get_enabled(void); diff --git a/src/platform/cannonlake/include/platform/memory.h b/src/platform/cannonlake/include/platform/memory.h index c7f4750..67f574a 100644 --- a/src/platform/cannonlake/include/platform/memory.h +++ b/src/platform/cannonlake/include/platform/memory.h @@ -240,7 +240,7 @@ #define SOF_TEXT_SIZE 0x18000
/* initialized data */ -#define SOF_DATA_SIZE 0x18000 +#define SOF_DATA_SIZE 0x19000
/* bss data */ #define SOF_BSS_DATA_SIZE 0x8000 diff --git a/src/platform/cannonlake/include/platform/platform.h b/src/platform/cannonlake/include/platform/platform.h index dc9a963..73d57ec 100644 --- a/src/platform/cannonlake/include/platform/platform.h +++ b/src/platform/cannonlake/include/platform/platform.h @@ -43,6 +43,8 @@ struct sof; #define PLATFORM_SSP_COUNT 3 #define MAX_GPDMA_COUNT 2
+#define MAX_CORE_COUNT 4 + /* Host page size */ #define HOST_PAGE_SIZE 4096 #define PLATFORM_PAGE_TABLE_SIZE 256 diff --git a/src/platform/cannonlake/interrupt.c b/src/platform/cannonlake/interrupt.c index 8c47e14..949b923 100644 --- a/src/platform/cannonlake/interrupt.c +++ b/src/platform/cannonlake/interrupt.c @@ -34,24 +34,31 @@ #include <sof/interrupt.h> #include <sof/interrupt-map.h> #include <arch/interrupt.h> +#include <arch/cpu.h> #include <platform/interrupt.h> #include <platform/shim.h> #include <stdint.h> #include <stdlib.h>
-static void parent_level2_handler(void *data) +static inline void irq_lvl2_handler(void *data, + int level, + uint32_t ilxsd, + uint32_t ilxmsd, + uint32_t ilxmcd) { - struct irq_parent *parent = (struct irq_parent *)data; - struct irq_child * child = NULL; + struct irq_desc *parent = (struct irq_desc *)data; + struct irq_desc *child = NULL; + struct list_item *clist; uint32_t status; uint32_t i = 0; + uint32_t unmask = 0;
/* mask the parent IRQ */ - arch_interrupt_disable_mask(1 << IRQ_NUM_EXT_LEVEL2); + arch_interrupt_disable_mask(1 << level);
/* mask all child interrupts */ - status = irq_read(REG_IRQ_IL2SD(0)); - irq_write(REG_IRQ_IL2MSD(0), status); + status = irq_read(ilxsd); + irq_write(ilxmsd, status);
/* handle each child */ while (status) { @@ -61,175 +68,95 @@ static void parent_level2_handler(void *data) goto next;
/* get child if any and run handler */ - child = parent->child[i]; - if (child && child->handler) { - child->handler(child->handler_arg); - - /* unmask this bit i interrupt */ - irq_write(REG_IRQ_IL2MCD(0), 0x1 << i); - } else { - /* nobody cared ? */ - trace_irq_error("nbc"); + list_for_item(clist, &parent->child[i]) { + child = container_of(clist, struct irq_desc, irq_list); + + if (child && child->handler) { + child->handler(child->handler_arg); + unmask = 1; + } else { + /* nobody cared ? */ + trace_irq_error("nbc"); + } }
+ /* unmask this bit i interrupt */ + if (unmask) + irq_write(ilxmcd, 0x1 << i); + next: status >>= 1; i++; }
/* clear parent and unmask */ - arch_interrupt_clear(IRQ_NUM_EXT_LEVEL2); - arch_interrupt_enable_mask(1 << IRQ_NUM_EXT_LEVEL2); + arch_interrupt_clear(level); + arch_interrupt_enable_mask(1 << level); }
-static void parent_level3_handler(void *data) -{ - struct irq_parent *parent = (struct irq_parent *)data; - struct irq_child * child = NULL; - uint32_t status; - uint32_t i = 0; - - /* mask the parent IRQ */ - arch_interrupt_disable_mask(1 << IRQ_NUM_EXT_LEVEL3); - - /* mask all child interrupts */ - status = irq_read(REG_IRQ_IL3SD(0)); - irq_write(REG_IRQ_IL3MSD(0), status); - - /* handle each child */ - while (status) { - - /* any IRQ for this child bit ? */ - if ((status & 0x1) == 0) - goto next; - - /* get child if any and run handler */ - child = parent->child[i]; - if (child && child->handler) { - child->handler(child->handler_arg); - - /* unmask this bit i interrupt */ - irq_write(REG_IRQ_IL3MCD(0), 0x1 << i); - } else { - /* nobody cared ? */ - trace_irq_error("nbc"); - } - -next: - status >>= 1; - i++; - } +#define IRQ_LVL2_HANDLER(n) int core = cpu_get_id(); \ + 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))
- /* clear parent and unmask */ - arch_interrupt_clear(IRQ_NUM_EXT_LEVEL3); - arch_interrupt_enable_mask(1 << IRQ_NUM_EXT_LEVEL3); +static void irq_lvl2_level2_handler(void *data) +{ + IRQ_LVL2_HANDLER(2); }
-static void parent_level4_handler(void *data) +static void irq_lvl2_level3_handler(void *data) { - struct irq_parent *parent = (struct irq_parent *)data; - struct irq_child * child = NULL; - uint32_t status; - uint32_t i = 0; - - /* mask the parent IRQ */ - arch_interrupt_disable_mask(1 << IRQ_NUM_EXT_LEVEL4); - - /* mask all child interrupts */ - status = irq_read(REG_IRQ_IL4SD(0)); - irq_write(REG_IRQ_IL4MSD(0), status); - - /* handle each child */ - while (status) { - - /* any IRQ for this child bit ? */ - if ((status & 0x1) == 0) - goto next; - - /* get child if any and run handler */ - child = parent->child[i]; - if (child && child->handler) { - child->handler(child->handler_arg); - - /* unmask this bit i interrupt */ - irq_write(REG_IRQ_IL4MCD(0), 0x1 << i); - } else { - /* nobody cared ? */ - trace_irq_error("nbc"); - } - -next: - status >>= 1; - i++; - } - - /* clear parent and unmask */ - arch_interrupt_clear(IRQ_NUM_EXT_LEVEL4); - arch_interrupt_enable_mask(1 << IRQ_NUM_EXT_LEVEL4); + IRQ_LVL2_HANDLER(3); }
-static void parent_level5_handler(void *data) +static void irq_lvl2_level4_handler(void *data) { - struct irq_parent *parent = (struct irq_parent *)data; - struct irq_child * child = NULL; - uint32_t status; - uint32_t i = 0; - - /* mask the parent IRQ */ - arch_interrupt_disable_mask(1 << IRQ_NUM_EXT_LEVEL5); - - /* mask all child interrupts */ - status = irq_read(REG_IRQ_IL5SD(0)); - irq_write(REG_IRQ_IL5MSD(0), status); - - /* handle each child */ - while (status) { - - /* any IRQ for this child bit ? */ - if ((status & 0x1) == 0) - goto next; - - /* get child if any and run handler */ - child = parent->child[i]; - if (child && child->handler) { - child->handler(child->handler_arg); - - /* unmask this bit i interrupt */ - irq_write(REG_IRQ_IL5MCD(0), 0x1 << i); - } else { - /* nobody cared ? */ - trace_irq_error("nbc"); - } - -next: - status >>= 1; - i++; - } + IRQ_LVL2_HANDLER(4); +}
- /* clear parent and unmask */ - arch_interrupt_clear(IRQ_NUM_EXT_LEVEL5); - arch_interrupt_enable_mask(1 << IRQ_NUM_EXT_LEVEL5); +static void irq_lvl2_level5_handler(void *data) +{ + IRQ_LVL2_HANDLER(5); }
/* DSP internal interrupts */ -static struct irq_parent dsp_irq[4] = { - {IRQ_NUM_EXT_LEVEL2, parent_level2_handler, }, - {IRQ_NUM_EXT_LEVEL3, parent_level3_handler, }, - {IRQ_NUM_EXT_LEVEL4, parent_level4_handler, }, - {IRQ_NUM_EXT_LEVEL5, parent_level5_handler, }, +static struct irq_desc dsp_irq[MAX_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, } }, + + {{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, } }, + + {{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, } }, + + {{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, } }, };
-struct irq_parent *platform_irq_get_parent(uint32_t irq) +struct irq_desc *platform_irq_get_parent(uint32_t irq) { + int core = cpu_get_id(); + switch (SOF_IRQ_NUMBER(irq)) { case IRQ_NUM_EXT_LEVEL2: - return &dsp_irq[0]; + return &dsp_irq[core][0]; case IRQ_NUM_EXT_LEVEL3: - return &dsp_irq[1]; + return &dsp_irq[core][1]; case IRQ_NUM_EXT_LEVEL4: - return &dsp_irq[2]; + return &dsp_irq[core][2]; case IRQ_NUM_EXT_LEVEL5: - return &dsp_irq[3]; + return &dsp_irq[core][3]; default: return NULL; } @@ -242,19 +169,21 @@ uint32_t platform_interrupt_get_enabled(void)
void platform_interrupt_mask(uint32_t irq, uint32_t mask) { + int core = cpu_get_id(); + /* mask external interrupt bit */ switch (SOF_IRQ_NUMBER(irq)) { case IRQ_NUM_EXT_LEVEL5: - irq_write(REG_IRQ_IL5MSD(0), 1 << SOF_IRQ_BIT(irq)); + irq_write(REG_IRQ_IL5MSD(core), 1 << SOF_IRQ_BIT(irq)); break; case IRQ_NUM_EXT_LEVEL4: - irq_write(REG_IRQ_IL4MSD(0), 1 << SOF_IRQ_BIT(irq)); + irq_write(REG_IRQ_IL4MSD(core), 1 << SOF_IRQ_BIT(irq)); break; case IRQ_NUM_EXT_LEVEL3: - irq_write(REG_IRQ_IL3MSD(0), 1 << SOF_IRQ_BIT(irq)); + irq_write(REG_IRQ_IL3MSD(core), 1 << SOF_IRQ_BIT(irq)); break; case IRQ_NUM_EXT_LEVEL2: - irq_write(REG_IRQ_IL2MSD(0), 1 << SOF_IRQ_BIT(irq)); + irq_write(REG_IRQ_IL2MSD(core), 1 << SOF_IRQ_BIT(irq)); break; default: break; @@ -264,19 +193,21 @@ void platform_interrupt_mask(uint32_t irq, uint32_t mask)
void platform_interrupt_unmask(uint32_t irq, uint32_t mask) { + int core = cpu_get_id(); + /* unmask external interrupt bit */ switch (SOF_IRQ_NUMBER(irq)) { case IRQ_NUM_EXT_LEVEL5: - irq_write(REG_IRQ_IL5MCD(0), 1 << SOF_IRQ_BIT(irq)); + irq_write(REG_IRQ_IL5MCD(core), 1 << SOF_IRQ_BIT(irq)); break; case IRQ_NUM_EXT_LEVEL4: - irq_write(REG_IRQ_IL4MCD(0), 1 << SOF_IRQ_BIT(irq)); + irq_write(REG_IRQ_IL4MCD(core), 1 << SOF_IRQ_BIT(irq)); break; case IRQ_NUM_EXT_LEVEL3: - irq_write(REG_IRQ_IL3MCD(0), 1 << SOF_IRQ_BIT(irq)); + irq_write(REG_IRQ_IL3MCD(core), 1 << SOF_IRQ_BIT(irq)); break; case IRQ_NUM_EXT_LEVEL2: - irq_write(REG_IRQ_IL2MCD(0), 1 << SOF_IRQ_BIT(irq)); + irq_write(REG_IRQ_IL2MCD(core), 1 << SOF_IRQ_BIT(irq)); break; default: break; @@ -290,15 +221,18 @@ void platform_interrupt_clear(uint32_t irq, uint32_t mask)
void platform_interrupt_init(void) { - int i; + int i, j; + int core = cpu_get_id();
/* mask all external IRQs by default */ - irq_write(REG_IRQ_IL2MSD(0), REG_IRQ_IL2MD_ALL); - irq_write(REG_IRQ_IL3MSD(0), REG_IRQ_IL3MD_ALL); - irq_write(REG_IRQ_IL4MSD(0), REG_IRQ_IL4MD_ALL); - irq_write(REG_IRQ_IL5MSD(0), REG_IRQ_IL5MD_ALL); - - for (i = 0; i < ARRAY_SIZE(dsp_irq); i++) { - spinlock_init(&dsp_irq[i].lock); + irq_write(REG_IRQ_IL2MSD(core), REG_IRQ_IL2MD_ALL); + irq_write(REG_IRQ_IL3MSD(core), REG_IRQ_IL3MD_ALL); + 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]); } }
-----Original Message----- From: sound-open-firmware-bounces@alsa-project.org [mailto:sound-open- firmware-bounces@alsa-project.org] On Behalf Of Rander Wang Sent: Thursday, May 10, 2018 1:32 PM To: sound-open-firmware@alsa-project.org; marcin.maka@linux.intel.com Cc: Liam Girdwood liam.r.girdwood@linux.intel.com; Rander Wang rander.wang@linux.intel.com Subject: [Sound-open-firmware] [PATCH_V3 4/8] cnl-interrupt: refine interrupt setting for change in irq_desc
(1)Add core id check in interrupt register setting. (2)Check child list in interrupt function (3)Extend root irq_desc to support 4 core on cnl. (4)Refine macro for interrupt setting
Signed-off-by: Rander Wang rander.wang@linux.intel.com Signed-off-by: Liam Girdwood liam.r.girdwood@linux.intel.com
V2: call cpu_get_id to get core id V3: remove duplication in handler function
test on CNL & APL & BYT, pass SOF: master c1f2682c210201 kernel: v4.14 d09db67c5a9d6d SOF-tools: master 13b56fa6047c566a
src/platform/cannonlake/dma.c | 2 +- .../cannonlake/include/platform/interrupt.h | 16 +- src/platform/cannonlake/include/platform/memory.h | 2 +- .../cannonlake/include/platform/platform.h | 2 + src/platform/cannonlake/interrupt.c | 258 ++++++++------------- 5 files changed, 108 insertions(+), 172 deletions(-)
diff --git a/src/platform/cannonlake/dma.c b/src/platform/cannonlake/dma.c index b606d1e..3f9d6cb 100644 --- a/src/platform/cannonlake/dma.c +++ b/src/platform/cannonlake/dma.c @@ -125,7 +125,7 @@ static struct dma dma[] = { .id = DMA_GP_LP_DMAC1, .base = LP_GP_DMA_BASE(1), .channels = 8,
.irq = IRQ_EXT_LP_GPDMA0_LVL5(0, 0),
.drv_plat_data = &dmac1, }, .ops = &dw_dma_ops,.irq = IRQ_EXT_LP_GPDMA1_LVL5(0, 0),
diff --git a/src/platform/cannonlake/include/platform/interrupt.h b/src/platform/cannonlake/include/platform/interrupt.h index 03857a7..b14cfdf 100644 --- a/src/platform/cannonlake/include/platform/interrupt.h +++ b/src/platform/cannonlake/include/platform/interrupt.h @@ -88,7 +88,7 @@ #define IRQ_BIT_LVL5_DMIC 6 #define IRQ_BIT_LVL5_SSP(x) (0 + x)
-/* Level 2 Peripheral IRQ mappings */ +/* 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) \ @@ -106,7 +106,7 @@ #define IRQ_EXT_SHA256_LVL2(xcpu) \ SOF_IRQ(IRQ_BIT_LVL2_SHA256, 2, xcpu, IRQ_NUM_EXT_LEVEL2)
-/* Level 3 Peripheral IRQ mappings */ +/* 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) \ @@ -114,17 +114,17 @@ #define IRQ_EXT_HOST_DMA_OUT_LVL3(xcpu, channel) \ SOF_IRQ(IRQ_BIT_LVL3_HOST_STREAM_OUT(channel), 3, xcpu, IRQ_NUM_EXT_LEVEL3)
-/* Level 4 Peripheral IRQ mappings */ +/* 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)
-/* Level 5 Peripheral IRQ mappings */ +/* Priority 5 Peripheral IRQ mappings */ #define IRQ_EXT_LP_GPDMA0_LVL5(xcpu, channel) \
- SOF_IRQ(IRQ_BIT_LVL5_LP_GP_DMA0, 5, xcpu, IRQ_NUM_EXT_LEVEL5)
-#define IRQ_EXT_LP_GPDMA1_LVL4(xcpu, channel) \
- SOF_IRQ(IRQ_BIT_LVL5_LP_GP_DMA1, 4, xcpu, IRQ_NUM_EXT_LEVEL4)
- 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_SSP0_LVL5(xcpu) \ SOF_IRQ(IRQ_BIT_LVL5_SSP(0), 5, xcpu, IRQ_NUM_EXT_LEVEL5) #define IRQ_EXT_SSP1_LVL5(xcpu) \ @@ -161,7 +161,7 @@
void platform_interrupt_init(void);
-struct irq_parent *platform_irq_get_parent(uint32_t irq); +struct irq_desc *platform_irq_get_parent(uint32_t irq); void platform_interrupt_set(int irq); void platform_interrupt_clear(uint32_t irq, uint32_t mask); uint32_t platform_interrupt_get_enabled(void); diff --git a/src/platform/cannonlake/include/platform/memory.h b/src/platform/cannonlake/include/platform/memory.h index c7f4750..67f574a 100644 --- a/src/platform/cannonlake/include/platform/memory.h +++ b/src/platform/cannonlake/include/platform/memory.h @@ -240,7 +240,7 @@ #define SOF_TEXT_SIZE 0x18000
/* initialized data */ -#define SOF_DATA_SIZE 0x18000 +#define SOF_DATA_SIZE 0x19000
/* bss data */ #define SOF_BSS_DATA_SIZE 0x8000 diff --git a/src/platform/cannonlake/include/platform/platform.h b/src/platform/cannonlake/include/platform/platform.h index dc9a963..73d57ec 100644 --- a/src/platform/cannonlake/include/platform/platform.h +++ b/src/platform/cannonlake/include/platform/platform.h @@ -43,6 +43,8 @@ struct sof; #define PLATFORM_SSP_COUNT 3 #define MAX_GPDMA_COUNT 2
+#define MAX_CORE_COUNT 4
/* Host page size */ #define HOST_PAGE_SIZE 4096 #define PLATFORM_PAGE_TABLE_SIZE 256 diff --git a/src/platform/cannonlake/interrupt.c b/src/platform/cannonlake/interrupt.c index 8c47e14..949b923 100644 --- a/src/platform/cannonlake/interrupt.c +++ b/src/platform/cannonlake/interrupt.c @@ -34,24 +34,31 @@ #include <sof/interrupt.h> #include <sof/interrupt-map.h> #include <arch/interrupt.h> +#include <arch/cpu.h> #include <platform/interrupt.h> #include <platform/shim.h> #include <stdint.h> #include <stdlib.h>
-static void parent_level2_handler(void *data) +static inline void irq_lvl2_handler(void *data,
int level,
uint32_t ilxsd,
uint32_t ilxmsd,
uint32_t ilxmcd)
{
- struct irq_parent *parent = (struct irq_parent *)data;
- struct irq_child * child = NULL;
struct irq_desc *parent = (struct irq_desc *)data;
struct irq_desc *child = NULL;
struct list_item *clist; uint32_t status; uint32_t i = 0;
uint32_t unmask = 0;
/* mask the parent IRQ */
- arch_interrupt_disable_mask(1 << IRQ_NUM_EXT_LEVEL2);
arch_interrupt_disable_mask(1 << level);
/* mask all child interrupts */
- status = irq_read(REG_IRQ_IL2SD(0));
- irq_write(REG_IRQ_IL2MSD(0), status);
status = irq_read(ilxsd);
irq_write(ilxmsd, status);
/* handle each child */ while (status) {
@@ -61,175 +68,95 @@ static void parent_level2_handler(void *data) goto next;
/* get child if any and run handler */
child = parent->child[i];
if (child && child->handler) {
child->handler(child->handler_arg);
/* unmask this bit i interrupt */
irq_write(REG_IRQ_IL2MCD(0), 0x1 << i);
} else {
/* nobody cared ? */
trace_irq_error("nbc");
list_for_item(clist, &parent->child[i]) {
child = container_of(clist, struct irq_desc, irq_list);
if (child && child->handler) {
child->handler(child->handler_arg);
unmask = 1;
} else {
/* nobody cared ? */
trace_irq_error("nbc");
}
}
/* unmask this bit i interrupt */
if (unmask)
irq_write(ilxmcd, 0x1 << i);
next: status >>= 1; i++; }
/* clear parent and unmask */
- arch_interrupt_clear(IRQ_NUM_EXT_LEVEL2);
- arch_interrupt_enable_mask(1 << IRQ_NUM_EXT_LEVEL2);
- arch_interrupt_clear(level);
- arch_interrupt_enable_mask(1 << level);
}
-static void parent_level3_handler(void *data) -{
- struct irq_parent *parent = (struct irq_parent *)data;
- struct irq_child * child = NULL;
- uint32_t status;
- uint32_t i = 0;
- /* mask the parent IRQ */
- arch_interrupt_disable_mask(1 << IRQ_NUM_EXT_LEVEL3);
- /* mask all child interrupts */
- status = irq_read(REG_IRQ_IL3SD(0));
- irq_write(REG_IRQ_IL3MSD(0), status);
- /* handle each child */
- while (status) {
/* any IRQ for this child bit ? */
if ((status & 0x1) == 0)
goto next;
/* get child if any and run handler */
child = parent->child[i];
if (child && child->handler) {
child->handler(child->handler_arg);
/* unmask this bit i interrupt */
irq_write(REG_IRQ_IL3MCD(0), 0x1 << i);
} else {
/* nobody cared ? */
trace_irq_error("nbc");
}
-next:
status >>= 1;
i++;
- }
+#define IRQ_LVL2_HANDLER(n) int core = cpu_get_id(); \
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))
- /* clear parent and unmask */
- arch_interrupt_clear(IRQ_NUM_EXT_LEVEL3);
- arch_interrupt_enable_mask(1 << IRQ_NUM_EXT_LEVEL3);
+static void irq_lvl2_level2_handler(void *data) {
- IRQ_LVL2_HANDLER(2);
}
-static void parent_level4_handler(void *data) +static void irq_lvl2_level3_handler(void *data) {
- struct irq_parent *parent = (struct irq_parent *)data;
- struct irq_child * child = NULL;
- uint32_t status;
- uint32_t i = 0;
- /* mask the parent IRQ */
- arch_interrupt_disable_mask(1 << IRQ_NUM_EXT_LEVEL4);
- /* mask all child interrupts */
- status = irq_read(REG_IRQ_IL4SD(0));
- irq_write(REG_IRQ_IL4MSD(0), status);
- /* handle each child */
- while (status) {
/* any IRQ for this child bit ? */
if ((status & 0x1) == 0)
goto next;
/* get child if any and run handler */
child = parent->child[i];
if (child && child->handler) {
child->handler(child->handler_arg);
/* unmask this bit i interrupt */
irq_write(REG_IRQ_IL4MCD(0), 0x1 << i);
} else {
/* nobody cared ? */
trace_irq_error("nbc");
}
-next:
status >>= 1;
i++;
- }
- /* clear parent and unmask */
- arch_interrupt_clear(IRQ_NUM_EXT_LEVEL4);
- arch_interrupt_enable_mask(1 << IRQ_NUM_EXT_LEVEL4);
- IRQ_LVL2_HANDLER(3);
}
-static void parent_level5_handler(void *data) +static void irq_lvl2_level4_handler(void *data) {
- struct irq_parent *parent = (struct irq_parent *)data;
- struct irq_child * child = NULL;
- uint32_t status;
- uint32_t i = 0;
- /* mask the parent IRQ */
- arch_interrupt_disable_mask(1 << IRQ_NUM_EXT_LEVEL5);
- /* mask all child interrupts */
- status = irq_read(REG_IRQ_IL5SD(0));
- irq_write(REG_IRQ_IL5MSD(0), status);
- /* handle each child */
- while (status) {
/* any IRQ for this child bit ? */
if ((status & 0x1) == 0)
goto next;
/* get child if any and run handler */
child = parent->child[i];
if (child && child->handler) {
child->handler(child->handler_arg);
/* unmask this bit i interrupt */
irq_write(REG_IRQ_IL5MCD(0), 0x1 << i);
} else {
/* nobody cared ? */
trace_irq_error("nbc");
}
-next:
status >>= 1;
i++;
- }
- IRQ_LVL2_HANDLER(4);
+}
- /* clear parent and unmask */
- arch_interrupt_clear(IRQ_NUM_EXT_LEVEL5);
- arch_interrupt_enable_mask(1 << IRQ_NUM_EXT_LEVEL5);
+static void irq_lvl2_level5_handler(void *data) {
- IRQ_LVL2_HANDLER(5);
}
/* DSP internal interrupts */ -static struct irq_parent dsp_irq[4] = {
- {IRQ_NUM_EXT_LEVEL2, parent_level2_handler, },
- {IRQ_NUM_EXT_LEVEL3, parent_level3_handler, },
- {IRQ_NUM_EXT_LEVEL4, parent_level4_handler, },
- {IRQ_NUM_EXT_LEVEL5, parent_level5_handler, },
+static struct irq_desc dsp_irq[MAX_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, } },
- {{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, } },
- {{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, } },
- {{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, } },
};
Can we share this irq_desc array among 4 cores? They looks exactly same and are static.
Thanks, ~Keyon
-struct irq_parent *platform_irq_get_parent(uint32_t irq) +struct irq_desc *platform_irq_get_parent(uint32_t irq) {
- int core = cpu_get_id();
- switch (SOF_IRQ_NUMBER(irq)) { case IRQ_NUM_EXT_LEVEL2:
return &dsp_irq[0];
case IRQ_NUM_EXT_LEVEL3:return &dsp_irq[core][0];
return &dsp_irq[1];
case IRQ_NUM_EXT_LEVEL4:return &dsp_irq[core][1];
return &dsp_irq[2];
case IRQ_NUM_EXT_LEVEL5:return &dsp_irq[core][2];
return &dsp_irq[3];
default: return NULL; }return &dsp_irq[core][3];
@@ -242,19 +169,21 @@ uint32_t platform_interrupt_get_enabled(void)
void platform_interrupt_mask(uint32_t irq, uint32_t mask) {
- int core = cpu_get_id();
- /* mask external interrupt bit */ switch (SOF_IRQ_NUMBER(irq)) { case IRQ_NUM_EXT_LEVEL5:
irq_write(REG_IRQ_IL5MSD(0), 1 << SOF_IRQ_BIT(irq));
break; case IRQ_NUM_EXT_LEVEL4:irq_write(REG_IRQ_IL5MSD(core), 1 << SOF_IRQ_BIT(irq));
irq_write(REG_IRQ_IL4MSD(0), 1 << SOF_IRQ_BIT(irq));
break; case IRQ_NUM_EXT_LEVEL3:irq_write(REG_IRQ_IL4MSD(core), 1 << SOF_IRQ_BIT(irq));
irq_write(REG_IRQ_IL3MSD(0), 1 << SOF_IRQ_BIT(irq));
break; case IRQ_NUM_EXT_LEVEL2:irq_write(REG_IRQ_IL3MSD(core), 1 << SOF_IRQ_BIT(irq));
irq_write(REG_IRQ_IL2MSD(0), 1 << SOF_IRQ_BIT(irq));
break; default: break;irq_write(REG_IRQ_IL2MSD(core), 1 << SOF_IRQ_BIT(irq));
@@ -264,19 +193,21 @@ void platform_interrupt_mask(uint32_t irq, uint32_t mask)
void platform_interrupt_unmask(uint32_t irq, uint32_t mask) {
- int core = cpu_get_id();
- /* unmask external interrupt bit */ switch (SOF_IRQ_NUMBER(irq)) { case IRQ_NUM_EXT_LEVEL5:
irq_write(REG_IRQ_IL5MCD(0), 1 << SOF_IRQ_BIT(irq));
break; case IRQ_NUM_EXT_LEVEL4:irq_write(REG_IRQ_IL5MCD(core), 1 << SOF_IRQ_BIT(irq));
irq_write(REG_IRQ_IL4MCD(0), 1 << SOF_IRQ_BIT(irq));
break; case IRQ_NUM_EXT_LEVEL3:irq_write(REG_IRQ_IL4MCD(core), 1 << SOF_IRQ_BIT(irq));
irq_write(REG_IRQ_IL3MCD(0), 1 << SOF_IRQ_BIT(irq));
break; case IRQ_NUM_EXT_LEVEL2:irq_write(REG_IRQ_IL3MCD(core), 1 << SOF_IRQ_BIT(irq));
irq_write(REG_IRQ_IL2MCD(0), 1 << SOF_IRQ_BIT(irq));
break; default: break;irq_write(REG_IRQ_IL2MCD(core), 1 << SOF_IRQ_BIT(irq));
@@ -290,15 +221,18 @@ void platform_interrupt_clear(uint32_t irq, uint32_t mask)
void platform_interrupt_init(void) {
- int i;
int i, j;
int core = cpu_get_id();
/* mask all external IRQs by default */
- irq_write(REG_IRQ_IL2MSD(0), REG_IRQ_IL2MD_ALL);
- irq_write(REG_IRQ_IL3MSD(0), REG_IRQ_IL3MD_ALL);
- irq_write(REG_IRQ_IL4MSD(0), REG_IRQ_IL4MD_ALL);
- irq_write(REG_IRQ_IL5MSD(0), REG_IRQ_IL5MD_ALL);
- for (i = 0; i < ARRAY_SIZE(dsp_irq); i++) {
spinlock_init(&dsp_irq[i].lock);
- irq_write(REG_IRQ_IL2MSD(core), REG_IRQ_IL2MD_ALL);
- irq_write(REG_IRQ_IL3MSD(core), REG_IRQ_IL3MD_ALL);
- 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]);
}
2.14.1
Sound-open-firmware mailing list Sound-open-firmware@alsa-project.org http://mailman.alsa-project.org/mailman/listinfo/sound-open-firmware
On Thu, 2018-05-10 at 14:25 +0000, sound-open-firmware-bounces@alsa-project.org wrote:
/* DSP internal interrupts */ -static struct irq_parent dsp_irq[4] = {
{IRQ_NUM_EXT_LEVEL2, parent_level2_handler, },
{IRQ_NUM_EXT_LEVEL3, parent_level3_handler, },
{IRQ_NUM_EXT_LEVEL4, parent_level4_handler, },
{IRQ_NUM_EXT_LEVEL5, parent_level5_handler, },
+static struct irq_desc dsp_irq[MAX_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, } },
{{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, } },
{{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, } },
{{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, } },
};
Can we share this irq_desc array among 4 cores? They looks exactly same and are static.
This would be the next phase, where we de-duplicate and reuse the same code amongst APL & CNL. i.e. we may create a separate src/platform/intel directory for common code like this.
Liam
On 5/10/2018 10:25 PM, Jie, Yang wrote:
-----Original Message----- From: sound-open-firmware-bounces@alsa-project.org [mailto:sound-open- firmware-bounces@alsa-project.org] On Behalf Of Rander Wang Sent: Thursday, May 10, 2018 1:32 PM To: sound-open-firmware@alsa-project.org; marcin.maka@linux.intel.com Cc: Liam Girdwood liam.r.girdwood@linux.intel.com; Rander Wang rander.wang@linux.intel.com Subject: [Sound-open-firmware] [PATCH_V3 4/8] cnl-interrupt: refine interrupt setting for change in irq_desc
(1)Add core id check in interrupt register setting. (2)Check child list in interrupt function (3)Extend root irq_desc to support 4 core on cnl. (4)Refine macro for interrupt setting
Signed-off-by: Rander Wang rander.wang@linux.intel.com Signed-off-by: Liam Girdwood liam.r.girdwood@linux.intel.com
V2: call cpu_get_id to get core id V3: remove duplication in handler function
test on CNL & APL & BYT, pass SOF: master c1f2682c210201 kernel: v4.14 d09db67c5a9d6d SOF-tools: master 13b56fa6047c566a
src/platform/cannonlake/dma.c | 2 +- .../cannonlake/include/platform/interrupt.h | 16 +- src/platform/cannonlake/include/platform/memory.h | 2 +- .../cannonlake/include/platform/platform.h | 2 + src/platform/cannonlake/interrupt.c | 258 ++++++++------------- 5 files changed, 108 insertions(+), 172 deletions(-)
diff --git a/src/platform/cannonlake/dma.c b/src/platform/cannonlake/dma.c index b606d1e..3f9d6cb 100644 --- a/src/platform/cannonlake/dma.c +++ b/src/platform/cannonlake/dma.c @@ -125,7 +125,7 @@ static struct dma dma[] = { .id = DMA_GP_LP_DMAC1, .base = LP_GP_DMA_BASE(1), .channels = 8,
.irq = IRQ_EXT_LP_GPDMA0_LVL5(0, 0),
.drv_plat_data = &dmac1, }, .ops = &dw_dma_ops,.irq = IRQ_EXT_LP_GPDMA1_LVL5(0, 0),
diff --git a/src/platform/cannonlake/include/platform/interrupt.h b/src/platform/cannonlake/include/platform/interrupt.h index 03857a7..b14cfdf 100644 --- a/src/platform/cannonlake/include/platform/interrupt.h +++ b/src/platform/cannonlake/include/platform/interrupt.h @@ -88,7 +88,7 @@ #define IRQ_BIT_LVL5_DMIC 6 #define IRQ_BIT_LVL5_SSP(x) (0 + x)
-/* Level 2 Peripheral IRQ mappings */ +/* 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) \ @@ -106,7 +106,7 @@ #define IRQ_EXT_SHA256_LVL2(xcpu) \ SOF_IRQ(IRQ_BIT_LVL2_SHA256, 2, xcpu, IRQ_NUM_EXT_LEVEL2)
-/* Level 3 Peripheral IRQ mappings */ +/* 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) \ @@ -114,17 +114,17 @@ #define IRQ_EXT_HOST_DMA_OUT_LVL3(xcpu, channel) \ SOF_IRQ(IRQ_BIT_LVL3_HOST_STREAM_OUT(channel), 3, xcpu, IRQ_NUM_EXT_LEVEL3)
-/* Level 4 Peripheral IRQ mappings */ +/* 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)
-/* Level 5 Peripheral IRQ mappings */ +/* Priority 5 Peripheral IRQ mappings */ #define IRQ_EXT_LP_GPDMA0_LVL5(xcpu, channel) \
- SOF_IRQ(IRQ_BIT_LVL5_LP_GP_DMA0, 5, xcpu, IRQ_NUM_EXT_LEVEL5)
-#define IRQ_EXT_LP_GPDMA1_LVL4(xcpu, channel) \
- SOF_IRQ(IRQ_BIT_LVL5_LP_GP_DMA1, 4, xcpu, IRQ_NUM_EXT_LEVEL4)
- 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_SSP0_LVL5(xcpu) \ SOF_IRQ(IRQ_BIT_LVL5_SSP(0), 5, xcpu, IRQ_NUM_EXT_LEVEL5) #define IRQ_EXT_SSP1_LVL5(xcpu) \ @@ -161,7 +161,7 @@
void platform_interrupt_init(void);
-struct irq_parent *platform_irq_get_parent(uint32_t irq); +struct irq_desc *platform_irq_get_parent(uint32_t irq); void platform_interrupt_set(int irq); void platform_interrupt_clear(uint32_t irq, uint32_t mask); uint32_t platform_interrupt_get_enabled(void); diff --git a/src/platform/cannonlake/include/platform/memory.h b/src/platform/cannonlake/include/platform/memory.h index c7f4750..67f574a 100644 --- a/src/platform/cannonlake/include/platform/memory.h +++ b/src/platform/cannonlake/include/platform/memory.h @@ -240,7 +240,7 @@ #define SOF_TEXT_SIZE 0x18000
/* initialized data */ -#define SOF_DATA_SIZE 0x18000 +#define SOF_DATA_SIZE 0x19000
/* bss data */ #define SOF_BSS_DATA_SIZE 0x8000 diff --git a/src/platform/cannonlake/include/platform/platform.h b/src/platform/cannonlake/include/platform/platform.h index dc9a963..73d57ec 100644 --- a/src/platform/cannonlake/include/platform/platform.h +++ b/src/platform/cannonlake/include/platform/platform.h @@ -43,6 +43,8 @@ struct sof; #define PLATFORM_SSP_COUNT 3 #define MAX_GPDMA_COUNT 2
+#define MAX_CORE_COUNT 4
/* Host page size */ #define HOST_PAGE_SIZE 4096 #define PLATFORM_PAGE_TABLE_SIZE 256 diff --git a/src/platform/cannonlake/interrupt.c b/src/platform/cannonlake/interrupt.c index 8c47e14..949b923 100644 --- a/src/platform/cannonlake/interrupt.c +++ b/src/platform/cannonlake/interrupt.c @@ -34,24 +34,31 @@ #include <sof/interrupt.h> #include <sof/interrupt-map.h> #include <arch/interrupt.h> +#include <arch/cpu.h> #include <platform/interrupt.h> #include <platform/shim.h> #include <stdint.h> #include <stdlib.h>
-static void parent_level2_handler(void *data) +static inline void irq_lvl2_handler(void *data,
int level,
uint32_t ilxsd,
uint32_t ilxmsd,
uint32_t ilxmcd)
{
- struct irq_parent *parent = (struct irq_parent *)data;
- struct irq_child * child = NULL;
struct irq_desc *parent = (struct irq_desc *)data;
struct irq_desc *child = NULL;
struct list_item *clist; uint32_t status; uint32_t i = 0;
uint32_t unmask = 0;
/* mask the parent IRQ */
- arch_interrupt_disable_mask(1 << IRQ_NUM_EXT_LEVEL2);
arch_interrupt_disable_mask(1 << level);
/* mask all child interrupts */
- status = irq_read(REG_IRQ_IL2SD(0));
- irq_write(REG_IRQ_IL2MSD(0), status);
status = irq_read(ilxsd);
irq_write(ilxmsd, status);
/* handle each child */ while (status) {
@@ -61,175 +68,95 @@ static void parent_level2_handler(void *data) goto next;
/* get child if any and run handler */
child = parent->child[i];
if (child && child->handler) {
child->handler(child->handler_arg);
/* unmask this bit i interrupt */
irq_write(REG_IRQ_IL2MCD(0), 0x1 << i);
} else {
/* nobody cared ? */
trace_irq_error("nbc");
list_for_item(clist, &parent->child[i]) {
child = container_of(clist, struct irq_desc, irq_list);
if (child && child->handler) {
child->handler(child->handler_arg);
unmask = 1;
} else {
/* nobody cared ? */
trace_irq_error("nbc");
}
}
/* unmask this bit i interrupt */
if (unmask)
irq_write(ilxmcd, 0x1 << i);
next: status >>= 1; i++; }
/* clear parent and unmask */
- arch_interrupt_clear(IRQ_NUM_EXT_LEVEL2);
- arch_interrupt_enable_mask(1 << IRQ_NUM_EXT_LEVEL2);
- arch_interrupt_clear(level);
- arch_interrupt_enable_mask(1 << level);
}
-static void parent_level3_handler(void *data) -{
- struct irq_parent *parent = (struct irq_parent *)data;
- struct irq_child * child = NULL;
- uint32_t status;
- uint32_t i = 0;
- /* mask the parent IRQ */
- arch_interrupt_disable_mask(1 << IRQ_NUM_EXT_LEVEL3);
- /* mask all child interrupts */
- status = irq_read(REG_IRQ_IL3SD(0));
- irq_write(REG_IRQ_IL3MSD(0), status);
- /* handle each child */
- while (status) {
/* any IRQ for this child bit ? */
if ((status & 0x1) == 0)
goto next;
/* get child if any and run handler */
child = parent->child[i];
if (child && child->handler) {
child->handler(child->handler_arg);
/* unmask this bit i interrupt */
irq_write(REG_IRQ_IL3MCD(0), 0x1 << i);
} else {
/* nobody cared ? */
trace_irq_error("nbc");
}
-next:
status >>= 1;
i++;
- }
+#define IRQ_LVL2_HANDLER(n) int core = cpu_get_id(); \
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))
- /* clear parent and unmask */
- arch_interrupt_clear(IRQ_NUM_EXT_LEVEL3);
- arch_interrupt_enable_mask(1 << IRQ_NUM_EXT_LEVEL3);
+static void irq_lvl2_level2_handler(void *data) {
- IRQ_LVL2_HANDLER(2);
}
-static void parent_level4_handler(void *data) +static void irq_lvl2_level3_handler(void *data) {
- struct irq_parent *parent = (struct irq_parent *)data;
- struct irq_child * child = NULL;
- uint32_t status;
- uint32_t i = 0;
- /* mask the parent IRQ */
- arch_interrupt_disable_mask(1 << IRQ_NUM_EXT_LEVEL4);
- /* mask all child interrupts */
- status = irq_read(REG_IRQ_IL4SD(0));
- irq_write(REG_IRQ_IL4MSD(0), status);
- /* handle each child */
- while (status) {
/* any IRQ for this child bit ? */
if ((status & 0x1) == 0)
goto next;
/* get child if any and run handler */
child = parent->child[i];
if (child && child->handler) {
child->handler(child->handler_arg);
/* unmask this bit i interrupt */
irq_write(REG_IRQ_IL4MCD(0), 0x1 << i);
} else {
/* nobody cared ? */
trace_irq_error("nbc");
}
-next:
status >>= 1;
i++;
- }
- /* clear parent and unmask */
- arch_interrupt_clear(IRQ_NUM_EXT_LEVEL4);
- arch_interrupt_enable_mask(1 << IRQ_NUM_EXT_LEVEL4);
- IRQ_LVL2_HANDLER(3);
}
-static void parent_level5_handler(void *data) +static void irq_lvl2_level4_handler(void *data) {
- struct irq_parent *parent = (struct irq_parent *)data;
- struct irq_child * child = NULL;
- uint32_t status;
- uint32_t i = 0;
- /* mask the parent IRQ */
- arch_interrupt_disable_mask(1 << IRQ_NUM_EXT_LEVEL5);
- /* mask all child interrupts */
- status = irq_read(REG_IRQ_IL5SD(0));
- irq_write(REG_IRQ_IL5MSD(0), status);
- /* handle each child */
- while (status) {
/* any IRQ for this child bit ? */
if ((status & 0x1) == 0)
goto next;
/* get child if any and run handler */
child = parent->child[i];
if (child && child->handler) {
child->handler(child->handler_arg);
/* unmask this bit i interrupt */
irq_write(REG_IRQ_IL5MCD(0), 0x1 << i);
} else {
/* nobody cared ? */
trace_irq_error("nbc");
}
-next:
status >>= 1;
i++;
- }
- IRQ_LVL2_HANDLER(4);
+}
- /* clear parent and unmask */
- arch_interrupt_clear(IRQ_NUM_EXT_LEVEL5);
- arch_interrupt_enable_mask(1 << IRQ_NUM_EXT_LEVEL5);
+static void irq_lvl2_level5_handler(void *data) {
- IRQ_LVL2_HANDLER(5);
}
/* DSP internal interrupts */ -static struct irq_parent dsp_irq[4] = {
- {IRQ_NUM_EXT_LEVEL2, parent_level2_handler, },
- {IRQ_NUM_EXT_LEVEL3, parent_level3_handler, },
- {IRQ_NUM_EXT_LEVEL4, parent_level4_handler, },
- {IRQ_NUM_EXT_LEVEL5, parent_level5_handler, },
+static struct irq_desc dsp_irq[MAX_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, } },
- {{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, } },
- {{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, } },
- {{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, } },
};
Can we share this irq_desc array among 4 cores? They looks exactly same and are static.
Thanks, ~Keyon
Hi Keyon,
they are private irq data for each core. Each core has private data to record irq info like irq registration
irq list, or irq enabling or disabling info.
-struct irq_parent *platform_irq_get_parent(uint32_t irq) +struct irq_desc *platform_irq_get_parent(uint32_t irq) {
- int core = cpu_get_id();
- switch (SOF_IRQ_NUMBER(irq)) { case IRQ_NUM_EXT_LEVEL2:
return &dsp_irq[0];
case IRQ_NUM_EXT_LEVEL3:return &dsp_irq[core][0];
return &dsp_irq[1];
case IRQ_NUM_EXT_LEVEL4:return &dsp_irq[core][1];
return &dsp_irq[2];
case IRQ_NUM_EXT_LEVEL5:return &dsp_irq[core][2];
return &dsp_irq[3];
default: return NULL; }return &dsp_irq[core][3];
@@ -242,19 +169,21 @@ uint32_t platform_interrupt_get_enabled(void)
void platform_interrupt_mask(uint32_t irq, uint32_t mask) {
- int core = cpu_get_id();
- /* mask external interrupt bit */ switch (SOF_IRQ_NUMBER(irq)) { case IRQ_NUM_EXT_LEVEL5:
irq_write(REG_IRQ_IL5MSD(0), 1 << SOF_IRQ_BIT(irq));
break; case IRQ_NUM_EXT_LEVEL4:irq_write(REG_IRQ_IL5MSD(core), 1 << SOF_IRQ_BIT(irq));
irq_write(REG_IRQ_IL4MSD(0), 1 << SOF_IRQ_BIT(irq));
break; case IRQ_NUM_EXT_LEVEL3:irq_write(REG_IRQ_IL4MSD(core), 1 << SOF_IRQ_BIT(irq));
irq_write(REG_IRQ_IL3MSD(0), 1 << SOF_IRQ_BIT(irq));
break; case IRQ_NUM_EXT_LEVEL2:irq_write(REG_IRQ_IL3MSD(core), 1 << SOF_IRQ_BIT(irq));
irq_write(REG_IRQ_IL2MSD(0), 1 << SOF_IRQ_BIT(irq));
break; default: break;irq_write(REG_IRQ_IL2MSD(core), 1 << SOF_IRQ_BIT(irq));
@@ -264,19 +193,21 @@ void platform_interrupt_mask(uint32_t irq, uint32_t mask)
void platform_interrupt_unmask(uint32_t irq, uint32_t mask) {
- int core = cpu_get_id();
- /* unmask external interrupt bit */ switch (SOF_IRQ_NUMBER(irq)) { case IRQ_NUM_EXT_LEVEL5:
irq_write(REG_IRQ_IL5MCD(0), 1 << SOF_IRQ_BIT(irq));
break; case IRQ_NUM_EXT_LEVEL4:irq_write(REG_IRQ_IL5MCD(core), 1 << SOF_IRQ_BIT(irq));
irq_write(REG_IRQ_IL4MCD(0), 1 << SOF_IRQ_BIT(irq));
break; case IRQ_NUM_EXT_LEVEL3:irq_write(REG_IRQ_IL4MCD(core), 1 << SOF_IRQ_BIT(irq));
irq_write(REG_IRQ_IL3MCD(0), 1 << SOF_IRQ_BIT(irq));
break; case IRQ_NUM_EXT_LEVEL2:irq_write(REG_IRQ_IL3MCD(core), 1 << SOF_IRQ_BIT(irq));
irq_write(REG_IRQ_IL2MCD(0), 1 << SOF_IRQ_BIT(irq));
break; default: break;irq_write(REG_IRQ_IL2MCD(core), 1 << SOF_IRQ_BIT(irq));
@@ -290,15 +221,18 @@ void platform_interrupt_clear(uint32_t irq, uint32_t mask)
void platform_interrupt_init(void) {
- int i;
int i, j;
int core = cpu_get_id();
/* mask all external IRQs by default */
- irq_write(REG_IRQ_IL2MSD(0), REG_IRQ_IL2MD_ALL);
- irq_write(REG_IRQ_IL3MSD(0), REG_IRQ_IL3MD_ALL);
- irq_write(REG_IRQ_IL4MSD(0), REG_IRQ_IL4MD_ALL);
- irq_write(REG_IRQ_IL5MSD(0), REG_IRQ_IL5MD_ALL);
- for (i = 0; i < ARRAY_SIZE(dsp_irq); i++) {
spinlock_init(&dsp_irq[i].lock);
- irq_write(REG_IRQ_IL2MSD(core), REG_IRQ_IL2MD_ALL);
- irq_write(REG_IRQ_IL3MSD(core), REG_IRQ_IL3MD_ALL);
- 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]);
}
2.14.1
Sound-open-firmware mailing list Sound-open-firmware@alsa-project.org http://mailman.alsa-project.org/mailman/listinfo/sound-open-firmware
These code is for CNL for it is not supported that two HW IPs share one irq pin. Now it is resolved in new algorithm, so delete it.
Signed-off-by: Rander Wang rander.wang@linux.intel.com --- src/drivers/dw-dma.c | 32 +------------------------------- 1 file changed, 1 insertion(+), 31 deletions(-)
diff --git a/src/drivers/dw-dma.c b/src/drivers/dw-dma.c index e0fbc5f..f16153f 100644 --- a/src/drivers/dw-dma.c +++ b/src/drivers/dw-dma.c @@ -1054,7 +1054,7 @@ static void dw_dma_irq_handler(void *data)
status_intr = dw_read(dma, DW_INTR_STATUS); if (!status_intr) { - trace_dma_error("eI0"); + return; }
tracev_dma("DIr"); @@ -1144,32 +1144,6 @@ static void dw_dma_irq_handler(void *data) } }
-#if defined CONFIG_CANNONLAKE -/*All the dma share the same interrupt on CNL, so check each dma*/ -/*controller when interrupt coming, then do the work */ -static void dw_dma_irq_cnl(void *data) -{ - struct dma *dma; - uint32_t status_intr; - - /*check interrupt status of DMA controller 0*/ - dma = dma_get(DMA_GP_LP_DMAC0); - if (dma) { - status_intr = dw_read(dma, DW_INTR_STATUS); - if (status_intr) - dw_dma_irq_handler(dma); - } - - /*check interrupt status of DMA controller 1*/ - dma = dma_get(DMA_GP_LP_DMAC1); - if (dma) { - status_intr = dw_read(dma, DW_INTR_STATUS); - if (status_intr) - dw_dma_irq_handler(dma); - } -} -#endif - static int dw_dma_probe(struct dma *dma) { struct dma_pdata *dw_pdata; @@ -1192,11 +1166,7 @@ static int dw_dma_probe(struct dma *dma) }
/* register our IRQ handler */ -#if defined CONFIG_CANNONLAKE - interrupt_register(dma_irq(dma), dw_dma_irq_cnl, dma); -#else interrupt_register(dma_irq(dma), dw_dma_irq_handler, dma); -#endif interrupt_enable(dma_irq(dma));
return 0;
Port the change on cnl to apl
Signed-off-by: Rander Wang rander.wang@linux.intel.com
--- V2: call cpu_get_id to get core id V3: remove duplication in irq handler
no version change for this patch
test on CNL & APL & BYT, pass SOF: master c1f2682c210201 kernel: v4.14 d09db67c5a9d6d SOF-tools: master 13b56fa6047c566a
--- .../apollolake/include/platform/interrupt.h | 2 +- src/platform/apollolake/include/platform/memory.h | 4 +- .../apollolake/include/platform/platform.h | 2 + src/platform/apollolake/interrupt.c | 248 +++++++-------------- 4 files changed, 91 insertions(+), 165 deletions(-)
diff --git a/src/platform/apollolake/include/platform/interrupt.h b/src/platform/apollolake/include/platform/interrupt.h index 8e29deb..6778661 100644 --- a/src/platform/apollolake/include/platform/interrupt.h +++ b/src/platform/apollolake/include/platform/interrupt.h @@ -164,7 +164,7 @@
void platform_interrupt_init(void);
-struct irq_parent *platform_irq_get_parent(uint32_t irq); +struct irq_desc *platform_irq_get_parent(uint32_t irq); void platform_interrupt_set(int irq); void platform_interrupt_clear(uint32_t irq, uint32_t mask); uint32_t platform_interrupt_get_enabled(void); diff --git a/src/platform/apollolake/include/platform/memory.h b/src/platform/apollolake/include/platform/memory.h index c71d8c6..6b3f21f 100644 --- a/src/platform/apollolake/include/platform/memory.h +++ b/src/platform/apollolake/include/platform/memory.h @@ -171,7 +171,7 @@ #define SOF_TEXT_SIZE 0x19000
/* initialized data */ -#define SOF_DATA_SIZE 0x18000 +#define SOF_DATA_SIZE 0x19000
/* bss data */ #define SOF_BSS_DATA_SIZE 0x2800 @@ -180,7 +180,7 @@ #define HEAP_SYSTEM_BASE \ (SOF_TEXT_BASE + SOF_TEXT_SIZE +\ SOF_DATA_SIZE + SOF_BSS_DATA_SIZE) -#define HEAP_SYSTEM_SIZE 0x3200 +#define HEAP_SYSTEM_SIZE 0x5000
#define HEAP_RUNTIME_BASE (HEAP_SYSTEM_BASE + HEAP_SYSTEM_SIZE) #define HEAP_RUNTIME_SIZE \ diff --git a/src/platform/apollolake/include/platform/platform.h b/src/platform/apollolake/include/platform/platform.h index d57b880..c9b2757 100644 --- a/src/platform/apollolake/include/platform/platform.h +++ b/src/platform/apollolake/include/platform/platform.h @@ -39,6 +39,8 @@
struct sof;
+#define MAX_CORE_COUNT 2 + /* Host page size */ #define HOST_PAGE_SIZE 4096 #define PLATFORM_PAGE_TABLE_SIZE 256 diff --git a/src/platform/apollolake/interrupt.c b/src/platform/apollolake/interrupt.c index d4af079..7d4d364 100644 --- a/src/platform/apollolake/interrupt.c +++ b/src/platform/apollolake/interrupt.c @@ -33,25 +33,32 @@ #include <sof/sof.h> #include <sof/interrupt.h> #include <sof/interrupt-map.h> +#include <arch/cpu.h> #include <arch/interrupt.h> #include <platform/interrupt.h> #include <platform/shim.h> #include <stdint.h> #include <stdlib.h>
-static void parent_level2_handler(void *data) +static inline void irq_lvl2_handler(void *data, + int level, + uint32_t ilxsd, + uint32_t ilxmsd, + uint32_t ilxmcd) { - struct irq_parent *parent = (struct irq_parent *)data; - struct irq_child * child = NULL; + struct irq_desc *parent = (struct irq_desc *)data; + struct irq_desc *child = NULL; + struct list_item *clist; uint32_t status; uint32_t i = 0; + uint32_t unmask = 0;
/* mask the parent IRQ */ - arch_interrupt_disable_mask(1 << IRQ_NUM_EXT_LEVEL2); + arch_interrupt_disable_mask(1 << level);
/* mask all child interrupts */ - status = irq_read(REG_IRQ_IL2SD(0)); - irq_write(REG_IRQ_IL2MSD(0), status); + status = irq_read(ilxsd); + irq_write(ilxmsd, status);
/* handle each child */ while (status) { @@ -61,175 +68,85 @@ static void parent_level2_handler(void *data) goto next;
/* get child if any and run handler */ - child = parent->child[i]; - if (child && child->handler) { - child->handler(child->handler_arg); - - /* unmask this bit i interrupt */ - irq_write(REG_IRQ_IL2MCD(0), 0x1 << i); - } else { - /* nobody cared ? */ - trace_irq_error("nbc"); + list_for_item(clist, &parent->child[i]) { + child = container_of(clist, struct irq_desc, irq_list); + + if (child && child->handler) { + child->handler(child->handler_arg); + unmask = 1; + } else { + /* nobody cared ? */ + trace_irq_error("nbc"); + } }
+ /* unmask this bit i interrupt */ + if (unmask) + irq_write(ilxmcd, 0x1 << i); + next: status >>= 1; i++; }
/* clear parent and unmask */ - arch_interrupt_clear(IRQ_NUM_EXT_LEVEL2); - arch_interrupt_enable_mask(1 << IRQ_NUM_EXT_LEVEL2); + arch_interrupt_clear(level); + arch_interrupt_enable_mask(1 << level); }
-static void parent_level3_handler(void *data) -{ - struct irq_parent *parent = (struct irq_parent *)data; - struct irq_child * child = NULL; - uint32_t status; - uint32_t i = 0; - - /* mask the parent IRQ */ - arch_interrupt_disable_mask(1 << IRQ_NUM_EXT_LEVEL3); - - /* mask all child interrupts */ - status = irq_read(REG_IRQ_IL3SD(0)); - irq_write(REG_IRQ_IL3MSD(0), status); - - /* handle each child */ - while (status) { - - /* any IRQ for this child bit ? */ - if ((status & 0x1) == 0) - goto next; - - /* get child if any and run handler */ - child = parent->child[i]; - if (child && child->handler) { - child->handler(child->handler_arg); - - /* unmask this bit i interrupt */ - irq_write(REG_IRQ_IL3MCD(0), 0x1 << i); - } else { - /* nobody cared ? */ - trace_irq_error("nbc"); - } - -next: - status >>= 1; - i++; - } +#define IRQ_LVL2_HANDLER(n) int core = cpu_get_id(); \ + 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))
- /* clear parent and unmask */ - arch_interrupt_clear(IRQ_NUM_EXT_LEVEL3); - arch_interrupt_enable_mask(1 << IRQ_NUM_EXT_LEVEL3); +static void irq_lvl2_level2_handler(void *data) +{ + IRQ_LVL2_HANDLER(2); }
-static void parent_level4_handler(void *data) +static void irq_lvl2_level3_handler(void *data) { - struct irq_parent *parent = (struct irq_parent *)data; - struct irq_child * child = NULL; - uint32_t status; - uint32_t i = 0; - - /* mask the parent IRQ */ - arch_interrupt_disable_mask(1 << IRQ_NUM_EXT_LEVEL4); - - /* mask all child interrupts */ - status = irq_read(REG_IRQ_IL4SD(0)); - irq_write(REG_IRQ_IL4MSD(0), status); - - /* handle each child */ - while (status) { - - /* any IRQ for this child bit ? */ - if ((status & 0x1) == 0) - goto next; - - /* get child if any and run handler */ - child = parent->child[i]; - if (child && child->handler) { - child->handler(child->handler_arg); - - /* unmask this bit i interrupt */ - irq_write(REG_IRQ_IL4MCD(0), 0x1 << i); - } else { - /* nobody cared ? */ - trace_irq_error("nbc"); - } - -next: - status >>= 1; - i++; - } - - /* clear parent and unmask */ - arch_interrupt_clear(IRQ_NUM_EXT_LEVEL4); - arch_interrupt_enable_mask(1 << IRQ_NUM_EXT_LEVEL4); + IRQ_LVL2_HANDLER(3); }
-static void parent_level5_handler(void *data) +static void irq_lvl2_level4_handler(void *data) { - struct irq_parent *parent = (struct irq_parent *)data; - struct irq_child * child = NULL; - uint32_t status; - uint32_t i = 0; - - /* mask the parent IRQ */ - arch_interrupt_disable_mask(1 << IRQ_NUM_EXT_LEVEL5); - - /* mask all child interrupts */ - status = irq_read(REG_IRQ_IL5SD(0)); - irq_write(REG_IRQ_IL5MSD(0), status); - - /* handle each child */ - while (status) { - - /* any IRQ for this child bit ? */ - if ((status & 0x1) == 0) - goto next; - - /* get child if any and run handler */ - child = parent->child[i]; - if (child && child->handler) { - child->handler(child->handler_arg); - - /* unmask this bit i interrupt */ - irq_write(REG_IRQ_IL5MCD(0), 0x1 << i); - } else { - /* nobody cared ? */ - trace_irq_error("nbc"); - } - -next: - status >>= 1; - i++; - } + IRQ_LVL2_HANDLER(4); +}
- /* clear parent and unmask */ - arch_interrupt_clear(IRQ_NUM_EXT_LEVEL5); - arch_interrupt_enable_mask(1 << IRQ_NUM_EXT_LEVEL5); +static void irq_lvl2_level5_handler(void *data) +{ + IRQ_LVL2_HANDLER(5); }
/* DSP internal interrupts */ -static struct irq_parent dsp_irq[4] = { - {IRQ_NUM_EXT_LEVEL2, parent_level2_handler, }, - {IRQ_NUM_EXT_LEVEL3, parent_level3_handler, }, - {IRQ_NUM_EXT_LEVEL4, parent_level4_handler, }, - {IRQ_NUM_EXT_LEVEL5, parent_level5_handler, }, +static struct irq_desc dsp_irq[MAX_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, } }, + + {{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, } }, };
-struct irq_parent *platform_irq_get_parent(uint32_t irq) +struct irq_desc *platform_irq_get_parent(uint32_t irq) { + int core = cpu_get_id(); + switch (SOF_IRQ_NUMBER(irq)) { case IRQ_NUM_EXT_LEVEL2: - return &dsp_irq[0]; + return &dsp_irq[core][0]; case IRQ_NUM_EXT_LEVEL3: - return &dsp_irq[1]; + return &dsp_irq[core][1]; case IRQ_NUM_EXT_LEVEL4: - return &dsp_irq[2]; + return &dsp_irq[core][2]; case IRQ_NUM_EXT_LEVEL5: - return &dsp_irq[3]; + return &dsp_irq[core][3]; default: return NULL; } @@ -242,19 +159,21 @@ uint32_t platform_interrupt_get_enabled(void)
void platform_interrupt_mask(uint32_t irq, uint32_t mask) { + int core = cpu_get_id(); + /* mask external interrupt bit */ switch (SOF_IRQ_NUMBER(irq)) { case IRQ_NUM_EXT_LEVEL5: - irq_write(REG_IRQ_IL5MSD(0), 1 << SOF_IRQ_BIT(irq)); + irq_write(REG_IRQ_IL5MSD(core), 1 << SOF_IRQ_BIT(irq)); break; case IRQ_NUM_EXT_LEVEL4: - irq_write(REG_IRQ_IL4MSD(0), 1 << SOF_IRQ_BIT(irq)); + irq_write(REG_IRQ_IL4MSD(core), 1 << SOF_IRQ_BIT(irq)); break; case IRQ_NUM_EXT_LEVEL3: - irq_write(REG_IRQ_IL3MSD(0), 1 << SOF_IRQ_BIT(irq)); + irq_write(REG_IRQ_IL3MSD(core), 1 << SOF_IRQ_BIT(irq)); break; case IRQ_NUM_EXT_LEVEL2: - irq_write(REG_IRQ_IL2MSD(0), 1 << SOF_IRQ_BIT(irq)); + irq_write(REG_IRQ_IL2MSD(core), 1 << SOF_IRQ_BIT(irq)); break; default: break; @@ -264,19 +183,21 @@ void platform_interrupt_mask(uint32_t irq, uint32_t mask)
void platform_interrupt_unmask(uint32_t irq, uint32_t mask) { + int core = cpu_get_id(); + /* unmask external interrupt bit */ switch (SOF_IRQ_NUMBER(irq)) { case IRQ_NUM_EXT_LEVEL5: - irq_write(REG_IRQ_IL5MCD(0), 1 << SOF_IRQ_BIT(irq)); + irq_write(REG_IRQ_IL5MCD(core), 1 << SOF_IRQ_BIT(irq)); break; case IRQ_NUM_EXT_LEVEL4: - irq_write(REG_IRQ_IL4MCD(0), 1 << SOF_IRQ_BIT(irq)); + irq_write(REG_IRQ_IL4MCD(core), 1 << SOF_IRQ_BIT(irq)); break; case IRQ_NUM_EXT_LEVEL3: - irq_write(REG_IRQ_IL3MCD(0), 1 << SOF_IRQ_BIT(irq)); + irq_write(REG_IRQ_IL3MCD(core), 1 << SOF_IRQ_BIT(irq)); break; case IRQ_NUM_EXT_LEVEL2: - irq_write(REG_IRQ_IL2MCD(0), 1 << SOF_IRQ_BIT(irq)); + irq_write(REG_IRQ_IL2MCD(core), 1 << SOF_IRQ_BIT(irq)); break; default: break; @@ -290,15 +211,18 @@ void platform_interrupt_clear(uint32_t irq, uint32_t mask)
void platform_interrupt_init(void) { - int i; + int i, j; + int core = cpu_get_id();
/* mask all external IRQs by default */ - irq_write(REG_IRQ_IL2MSD(0), REG_IRQ_IL2MD_ALL); - irq_write(REG_IRQ_IL3MSD(0), REG_IRQ_IL3MD_ALL); - irq_write(REG_IRQ_IL4MSD(0), REG_IRQ_IL4MD_ALL); - irq_write(REG_IRQ_IL5MSD(0), REG_IRQ_IL5MD_ALL); - - for (i = 0; i < ARRAY_SIZE(dsp_irq); i++) { - spinlock_init(&dsp_irq[i].lock); + irq_write(REG_IRQ_IL2MSD(core), REG_IRQ_IL2MD_ALL); + irq_write(REG_IRQ_IL3MSD(core), REG_IRQ_IL3MD_ALL); + 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]); } }
Almost no change for byt because only one interrupt level on byt.
Signed-off-by: Rander Wang rander.wang@linux.intel.com --- src/platform/baytrail/include/platform/interrupt.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/platform/baytrail/include/platform/interrupt.h b/src/platform/baytrail/include/platform/interrupt.h index 9ea2c42..d0cd17b 100644 --- a/src/platform/baytrail/include/platform/interrupt.h +++ b/src/platform/baytrail/include/platform/interrupt.h @@ -90,7 +90,7 @@
static inline void platform_interrupt_init(void) {}
-static inline struct irq_parent *platform_irq_get_parent(uint32_t irq) +static inline struct irq_desc *platform_irq_get_parent(uint32_t irq) { return NULL; }
Almost no change for hsw because only one interrupt level on hsw.
Signed-off-by: Rander Wang rander.wang@linux.intel.com --- src/platform/haswell/include/platform/interrupt.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/platform/haswell/include/platform/interrupt.h b/src/platform/haswell/include/platform/interrupt.h index 603da5f..14d0e30 100644 --- a/src/platform/haswell/include/platform/interrupt.h +++ b/src/platform/haswell/include/platform/interrupt.h @@ -69,7 +69,7 @@ static inline void platform_interrupt_init(void) {}
/* haswell does not support child IRQs */ -static inline struct irq_parent *platform_irq_get_parent(uint32_t irq) +static inline struct irq_desc *platform_irq_get_parent(uint32_t irq) { return NULL; }
participants (4)
-
Jie, Yang
-
Liam Girdwood
-
Rander Wang
-
rander.wang