[Sound-open-firmware] [PATCH_V2 3/7] cnl-interrupt: refine interrupt setting for change in irq_desc

Rander Wang rander.wang at linux.intel.com
Tue May 8 08:23:44 CEST 2018


(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 at linux.intel.com>
Signed-off-by: Liam Girdwood <liam.r.girdwood at linux.intel.com>

---
V2: get core id in a generic way

test on CNL & APL & BYT, pass
SOF: master 85ae8e74181f
kernel: v4.14 2cd03d26b66f8fee2
SOF-tools: master 56e26dd528b6c77
---
 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         |  10 +
 src/platform/cannonlake/interrupt.c                | 220 +++++++++++++--------
 5 files changed, 158 insertions(+), 92 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..d157daa 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
@@ -126,6 +128,14 @@ struct sof;
 
 extern struct timer *platform_timer;
 
+static inline int platform_get_core_id(void)
+{
+	int prid;
+
+	__asm__("rsr.prid %0" : "=a"(prid));
+	return prid;
+}
+
 /*
  * APIs declared here are defined for every platform and IPC mechanism.
  */
diff --git a/src/platform/cannonlake/interrupt.c b/src/platform/cannonlake/interrupt.c
index 8c47e14..250e631 100644
--- a/src/platform/cannonlake/interrupt.c
+++ b/src/platform/cannonlake/interrupt.c
@@ -39,19 +39,22 @@
 #include <stdint.h>
 #include <stdlib.h>
 
-static void parent_level2_handler(void *data)
+static void irq_lvl2_level2_handler(void *data)
 {
-	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;
+	int core = platform_get_core_id();
 
 	/* mask the parent IRQ */
 	arch_interrupt_disable_mask(1 << IRQ_NUM_EXT_LEVEL2);
 
 	/* mask all child interrupts */
-	status = irq_read(REG_IRQ_IL2SD(0));
-	irq_write(REG_IRQ_IL2MSD(0), status);
+	status = irq_read(REG_IRQ_IL2SD(core));
+	irq_write(REG_IRQ_IL2MSD(core), status);
 
 	/* handle each child */
 	while (status) {
@@ -61,17 +64,22 @@ 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(REG_IRQ_IL2MCD(core), 0x1 << i);
+
 next:
 		status >>= 1;
 		i++;
@@ -82,19 +90,22 @@ next:
 	arch_interrupt_enable_mask(1 << IRQ_NUM_EXT_LEVEL2);
 }
 
-static void parent_level3_handler(void *data)
+static void irq_lvl2_level3_handler(void *data)
 {
-	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;
+	int core = platform_get_core_id();
 
 	/* 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);
+	status = irq_read(REG_IRQ_IL3SD(core));
+	irq_write(REG_IRQ_IL3MSD(core), status);
 
 	/* handle each child */
 	while (status) {
@@ -104,17 +115,22 @@ static void parent_level3_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_IL3MCD(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(REG_IRQ_IL3MCD(core), 0x1 << i);
+
 next:
 		status >>= 1;
 		i++;
@@ -125,19 +141,22 @@ next:
 	arch_interrupt_enable_mask(1 << IRQ_NUM_EXT_LEVEL3);
 }
 
-static void parent_level4_handler(void *data)
+static void irq_lvl2_level4_handler(void *data)
 {
-	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;
+	int core = platform_get_core_id();
 
 	/* 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);
+	status = irq_read(REG_IRQ_IL4SD(core));
+	irq_write(REG_IRQ_IL4MSD(core), status);
 
 	/* handle each child */
 	while (status) {
@@ -147,17 +166,22 @@ static void parent_level4_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_IL4MCD(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(REG_IRQ_IL4MCD(core), 0x1 << i);
+
 next:
 		status >>= 1;
 		i++;
@@ -168,19 +192,22 @@ next:
 	arch_interrupt_enable_mask(1 << IRQ_NUM_EXT_LEVEL4);
 }
 
-static void parent_level5_handler(void *data)
+static void irq_lvl2_level5_handler(void *data)
 {
-	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;
+	int core = platform_get_core_id();
 
 	/* 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);
+	status = irq_read(REG_IRQ_IL5SD(core));
+	irq_write(REG_IRQ_IL5MSD(core), status);
 
 	/* handle each child */
 	while (status) {
@@ -190,17 +217,22 @@ static void parent_level5_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_IL5MCD(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(REG_IRQ_IL5MCD(core), 0x1 << i);
+
 next:
 		status >>= 1;
 		i++;
@@ -212,24 +244,41 @@ next:
 }
 
 /* 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 = platform_get_core_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 +291,21 @@ uint32_t platform_interrupt_get_enabled(void)
 
 void platform_interrupt_mask(uint32_t irq, uint32_t mask)
 {
+	int core = platform_get_core_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 +315,21 @@ void platform_interrupt_mask(uint32_t irq, uint32_t mask)
 
 void platform_interrupt_unmask(uint32_t irq, uint32_t mask)
 {
+	int core = platform_get_core_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 +343,18 @@ void platform_interrupt_clear(uint32_t irq, uint32_t mask)
 
 void platform_interrupt_init(void)
 {
-	int i;
+	int i, j;
+	int core = platform_get_core_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



More information about the Sound-open-firmware mailing list