From 94fb377bd92c7c0fbbfe76e60c513959e6e32f2d Mon Sep 17 00:00:00 2001 From: Daniel Hellstrom Date: Sun, 22 Jan 2017 15:58:18 +0100 Subject: leon, grspw_pkt: ISR RX/TX DMA interrupt source disable configurable 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 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); } } -- cgit v1.2.3