summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--c/src/lib/libbsp/sparc/shared/include/grspw_pkt.h15
-rw-r--r--c/src/lib/libbsp/sparc/shared/spw/grspw_pkt.c48
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 71f45d5283..d14d434217 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 b64a807d99..6b5390fffd 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);
}
}