[PATCH 37/44] leon, grspw_pkt: ISR RX/TX DMA interrupt source disable configurable

Daniel Hellstrom daniel at gaisler.com
Fri Mar 3 14:57:10 UTC 2017


This patch introduces some new options to let the user control when
    the ISR shall disable DMA RX/TX interrupt. The ISR can be set in three
    modes when a RX/TX DMA interrupt is asserted:
     1) ISR will always clear both RX/TX DMA interrupt enable. (DEFAULT).
     2) ISR will never never RX or TX DMA interrupt enable, ISR will
        leave RX/TX DMA interrupt enable untouched.
     3) ISR will clear the interrupt enable(s) causing the interrupt,
        this allows separate RX and TX IRQ handling.

    This patch is backwards compatible since default mode 1) is activated
    when the grspw_dma_config.flags DMAFLAGS2_IRQD field is 0.
---
 c/src/lib/libbsp/sparc/shared/include/grspw_pkt.h | 15 ++++++-
 c/src/lib/libbsp/sparc/shared/spw/grspw_pkt.c     | 48 +++++++++++++++++------
 2 files changed, 51 insertions(+), 12 deletions(-)

diff --git a/c/src/lib/libbsp/sparc/shared/include/grspw_pkt.h b/c/src/lib/libbsp/sparc/shared/include/grspw_pkt.h
index 71f45d5..d14d434 100644
--- a/c/src/lib/libbsp/sparc/shared/include/grspw_pkt.h
+++ b/c/src/lib/libbsp/sparc/shared/include/grspw_pkt.h
@@ -270,7 +270,20 @@ struct grspw_core_stats {
 					 * Used to enable RX DMA interrupt
 					 * when rx_irq_en_cnt=0.
 					 */
-#define DMAFLAG2_MASK	(DMAFLAG2_TXIE | DMAFLAG2_RXIE)
+/* Defines how the ISR will disable RX/TX DMA interrupt source when a DMA RX/TX
+ * interrupt has happended. DMA Error Interrupt always disables both RX/TX DMA
+ * interrupt. By default both RX/TX IRQs are disabled when either a RX, TX or
+ * both RX/TX DMA interrupt has been requested. The work-task, custom
+ * application handler or custom ISR handler is responsible to re-enable
+ * DMA interrupts.
+ */
+#define DMAFLAG2_IRQD_SRC  0x01000000	/* Disable triggering RX/TX source */
+#define DMAFLAG2_IRQD_NONE 0x00c00000	/* Never disable RX/TX IRQ in ISR */
+#define DMAFLAG2_IRQD_BOTH 0x00000000	/* Always disable both RX/TX sources */
+#define DMAFLAG2_IRQD_MASK 0x01c00000	/* Mask of options */
+#define DMAFLAG2_IRQD_BIT  22
+
+#define DMAFLAG2_MASK	(DMAFLAG2_TXIE | DMAFLAG2_RXIE | DMAFLAG2_IRQD_MASK)
 
 struct grspw_dma_config {
 	int flags;		/* DMA config flags, see DMAFLAG1&2_* options */
diff --git a/c/src/lib/libbsp/sparc/shared/spw/grspw_pkt.c b/c/src/lib/libbsp/sparc/shared/spw/grspw_pkt.c
index b64a807..6b5390f 100644
--- a/c/src/lib/libbsp/sparc/shared/spw/grspw_pkt.c
+++ b/c/src/lib/libbsp/sparc/shared/spw/grspw_pkt.c
@@ -2625,10 +2625,21 @@ static void grspw_work_dma_func(struct grspw_dma_priv *dma, unsigned int msg)
 	default:
 		break;
 	}
+	if (msg == 0)
+		return;
 
 	rx_cond_true = 0;
 	tx_cond_true = 0;
 
+	if ((dma->cfg.flags & DMAFLAG2_IRQD_MASK) == DMAFLAG2_IRQD_BOTH) {
+		/* In case both interrupt sources are disabled simultaneously
+		 * by the ISR the re-enabling of the interrupt source must also
+		 * do so to avoid missing interrupts. Both RX and TX process
+		 * will be forced.
+		 */
+		msg |= WORK_DMA_RX_MASK | WORK_DMA_TX_MASK;
+	}
+
 	if (msg & WORK_DMA_RX_MASK) {
 		/* Do RX Work */
 
@@ -2726,7 +2737,7 @@ STATIC void grspw_isr(void *data)
 	unsigned int dma_stat, stat, stat_clrmsk, ctrl, icctrl, timecode, irqs;
 	unsigned int rxirq, rxack, intto;
 	int i, handled = 0, call_user_int_isr;
-	unsigned int message = WORK_NONE;
+	unsigned int message = WORK_NONE, dma_en;
 #ifdef RTEMS_HAS_SMP
 	IRQFLAGS_TYPE irqflags;
 #endif
@@ -2839,26 +2850,41 @@ STATIC void grspw_isr(void *data)
 		if (!irqs)
 			continue;
 
-		/* Disable Further IRQs (until enabled again)
-		 * from this DMA channel. Let the status
-		 * bit remain so that they can be handled by
-		 * work function.
-		 */
-		REG_WRITE(&priv->regs->dma[i].ctrl, dma_stat & 
-			~(GRSPW_DMACTRL_RI|GRSPW_DMACTRL_TI|
-			GRSPW_DMACTRL_PR|GRSPW_DMACTRL_PS|
-			GRSPW_DMACTRL_RA|GRSPW_DMACTRL_TA|
-			GRSPW_DMACTRL_AT));
 		handled = 1;
 
 		/* DMA error has priority, if error happens it is assumed that
 		 * the common work-queue stops the DMA operation for that
 		 * channel and makes the DMA tasks exit from their waiting
 		 * functions (both RX and TX tasks).
+		 * 
+		 * Disable Further IRQs (until enabled again)
+		 * from this DMA channel. Let the status
+		 * bit remain so that they can be handled by
+		 * work function.
 		 */
 		if (irqs & GRSPW_DMA_STATUS_ERROR) {
+			REG_WRITE(&priv->regs->dma[i].ctrl, dma_stat & 
+				~(GRSPW_DMACTRL_RI | GRSPW_DMACTRL_TI |
+				  GRSPW_DMACTRL_PR | GRSPW_DMACTRL_PS |
+				  GRSPW_DMACTRL_RA | GRSPW_DMACTRL_TA |
+				  GRSPW_DMACTRL_AT));
 			message |= WORK_DMA_ER(i);
 		} else {
+			/* determine if RX/TX interrupt source(s) shall remain
+			 * enabled.
+			 */
+			if (priv->dma[i].cfg.flags & DMAFLAG2_IRQD_SRC) {
+				dma_en = ~irqs >> 3;
+			} else {
+				dma_en = priv->dma[i].cfg.flags >>
+				 (DMAFLAG2_IRQD_BIT - GRSPW_DMACTRL_TI_BIT);
+			}
+			dma_en &= (GRSPW_DMACTRL_RI | GRSPW_DMACTRL_TI);
+			REG_WRITE(&priv->regs->dma[i].ctrl, dma_stat &
+				(~(GRSPW_DMACTRL_RI | GRSPW_DMACTRL_TI |
+				   GRSPW_DMACTRL_PR | GRSPW_DMACTRL_PS |
+				   GRSPW_DMACTRL_RA | GRSPW_DMACTRL_TA |
+				   GRSPW_DMACTRL_AT) | dma_en));
 			message |= WORK_DMA(i, irqs >> GRSPW_DMACTRL_PS_BIT);
 		}
 	}
-- 
2.7.4



More information about the devel mailing list