Added new function: * grspw_dma_ctrlsts() - Read value of DMA CTRL/STS reg. * grspw_dma_enable_int() - re-enable interrupt, used when implementing a custom work-task. --- c/src/lib/libbsp/sparc/shared/include/grspw_pkt.h | 6 + c/src/lib/libbsp/sparc/shared/spw/grspw_pkt.c | 189 +++++++++++++--------- 2 files changed, 119 insertions(+), 76 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 5b3a606..71f45d5 100644 --- a/c/src/lib/libbsp/sparc/shared/include/grspw_pkt.h +++ b/c/src/lib/libbsp/sparc/shared/include/grspw_pkt.h @@ -535,6 +535,12 @@ extern int grspw_dma_close(void *c); extern int grspw_dma_start(void *c); extern void grspw_dma_stop(void *c); +/* Enable interrupt manually */ +extern unsigned int grspw_dma_enable_int(void *c, int rxtx, int force); + +/* Return Current DMA Control & Status Register */ +extern unsigned int grspw_dma_ctrlsts(void *c); + /* Schedule List of packets for transmission at some point in * future. * 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 8853a36..e445c2a 100644 --- a/c/src/lib/libbsp/sparc/shared/spw/grspw_pkt.c +++ b/c/src/lib/libbsp/sparc/shared/spw/grspw_pkt.c @@ -730,6 +730,14 @@ void grspw_addr_ctrl(void *d, struct grspw_addr_config *cfg) } } +/* Return Current DMA CTRL/Status Register */ +unsigned int grspw_dma_ctrlsts(void *c) +{ + struct grspw_dma_priv *dma = c; + + return REG_READ(&dma->regs->ctrl); +} + /* Return Current Status Register */ unsigned int grspw_link_status(void *d) { @@ -1822,6 +1830,52 @@ int grspw_dma_close(void *c) return 0; } +unsigned int grspw_dma_enable_int(void *c, int rxtx, int force) +{ + struct grspw_dma_priv *dma = c; + int rc = 0; + unsigned int ctrl, ctrl_old; + IRQFLAGS_TYPE irqflags; + + SPIN_LOCK_IRQ(&dma->core->devlock, irqflags); + if (dma->started == 0) { + rc = 1; /* DMA stopped */ + goto out; + } + ctrl = REG_READ(&dma->regs->ctrl); + ctrl_old = ctrl; + + /* Read/Write DMA error ? */ + if (ctrl & GRSPW_DMA_STATUS_ERROR) { + rc = 2; /* DMA error */ + goto out; + } + + /* DMA has finished a TX/RX packet and user wants work-task to + * take care of DMA table processing. + */ + ctrl &= ~GRSPW_DMACTRL_AT; + + if ((rxtx & 1) == 0) + ctrl &= ~GRSPW_DMACTRL_PR; + else if (force || ((dma->cfg.rx_irq_en_cnt != 0) || + (dma->cfg.flags & DMAFLAG2_RXIE))) + ctrl |= GRSPW_DMACTRL_RI; + + if ((rxtx & 2) == 0) + ctrl &= ~GRSPW_DMACTRL_PS; + else if (force || ((dma->cfg.tx_irq_en_cnt != 0) || + (dma->cfg.flags & DMAFLAG2_TXIE))) + ctrl |= GRSPW_DMACTRL_TI; + + REG_WRITE(&dma->regs->ctrl, ctrl); + /* Re-enabled interrupts previously enabled */ + rc = ctrl_old & (GRSPW_DMACTRL_PR | GRSPW_DMACTRL_PS); +out: + SPIN_UNLOCK_IRQ(&dma->core->devlock, irqflags); + return rc; +} + /* Schedule List of packets for transmission at some point in * future. * @@ -2542,99 +2596,82 @@ static void grspw_work_shutdown_func(struct grspw_priv *priv) /* Do DMA work on one channel, invoked indirectly from ISR */ static void grspw_work_dma_func(struct grspw_dma_priv *dma, unsigned int msg) { - int tx_cond_true, rx_cond_true; - unsigned int ctrl; - IRQFLAGS_TYPE irqflags; + int tx_cond_true, rx_cond_true, rxtx; /* If DMA channel is closed we should not access the semaphore */ if (dma->open == 0) return; - rx_cond_true = 0; - tx_cond_true = 0; dma->stats.irq_cnt++; /* Look at cause we were woken up and clear source */ - SPIN_LOCK_IRQ(&priv->devlock, irqflags); - if (dma->started == 0) { - SPIN_UNLOCK_IRQ(&priv->devlock, irqflags); + rxtx = 0; + if (msg & WORK_DMA_RX_MASK) + rxtx |= 1; + if (msg & WORK_DMA_TX_MASK) + rxtx |= 2; + switch (grspw_dma_enable_int(dma, rxtx, 0)) { + case 1: + /* DMA stopped */ return; - } - ctrl = REG_READ(&dma->regs->ctrl); - - /* Read/Write DMA error ? */ - if (ctrl & GRSPW_DMA_STATUS_ERROR) { + case 2: /* DMA error -> Stop DMA channel (both RX and TX) */ - SPIN_UNLOCK_IRQ(&priv->devlock, irqflags); if (msg & WORK_DMA_ER_MASK) { /* DMA error and user wants work-task to handle error */ grspw_dma_stop(dma); grspw_work_event(WORKTASK_EV_DMA_STOP, msg); } - } else if (((msg & WORK_DMA_RX_MASK) && (ctrl & GRSPW_DMACTRL_PR)) || - ((msg & WORK_DMA_TX_MASK) && (ctrl & GRSPW_DMACTRL_PS))) { - /* DMA has finished a TX/RX packet and user wants work-task to - * take care of DMA table processing. - */ - ctrl &= ~GRSPW_DMACTRL_AT; - - if ((msg & WORK_DMA_RX_MASK) == 0) - ctrl &= ~GRSPW_DMACTRL_PR; - else if (dma->cfg.rx_irq_en_cnt != 0 || - (dma->cfg.flags & DMAFLAG2_RXIE)) - ctrl |= GRSPW_DMACTRL_RI; - if ((msg & WORK_DMA_TX_MASK) == 0) - ctrl &= ~GRSPW_DMACTRL_PS; - else if ((dma->cfg.tx_irq_en_cnt != 0 || - (dma->cfg.flags & DMAFLAG2_TXIE))) - ctrl |= GRSPW_DMACTRL_TI; - - REG_WRITE(&dma->regs->ctrl, ctrl); - SPIN_UNLOCK_IRQ(&priv->devlock, irqflags); - if ((msg & WORK_DMA_RX_MASK) && (ctrl & GRSPW_DMACTRL_PR)) { - /* Do RX Work */ - - /* Take DMA channel RX lock */ - if (rtems_semaphore_obtain(dma->sem_rxdma, RTEMS_WAIT, RTEMS_NO_TIMEOUT) - != RTEMS_SUCCESSFUL) - return; - - dma->stats.rx_work_cnt++; - grspw_rx_process_scheduled(dma); - if (dma->started) { - dma->stats.rx_work_enabled += - grspw_rx_schedule_ready(dma); - /* Check to see if condition for waking blocked - * USER task is fullfilled. - */ - if (dma->rx_wait.waiting) - rx_cond_true = grspw_rx_wait_eval(dma); - } - rtems_semaphore_release(dma->sem_rxdma); + return; + default: + break; + } + + rx_cond_true = 0; + tx_cond_true = 0; + + if (msg & WORK_DMA_RX_MASK) { + /* Do RX Work */ + + /* Take DMA channel RX lock */ + if (rtems_semaphore_obtain(dma->sem_rxdma, RTEMS_WAIT, RTEMS_NO_TIMEOUT) + != RTEMS_SUCCESSFUL) + return; + + dma->stats.rx_work_cnt++; + grspw_rx_process_scheduled(dma); + if (dma->started) { + dma->stats.rx_work_enabled += + grspw_rx_schedule_ready(dma); + /* Check to see if condition for waking blocked + * USER task is fullfilled. + */ + if (dma->rx_wait.waiting) + rx_cond_true = grspw_rx_wait_eval(dma); } - if ((msg & WORK_DMA_TX_MASK) && (ctrl & GRSPW_DMACTRL_PS)) { - /* Do TX Work */ - - /* Take DMA channel TX lock */ - if (rtems_semaphore_obtain(dma->sem_txdma, RTEMS_WAIT, RTEMS_NO_TIMEOUT) - != RTEMS_SUCCESSFUL) - return; - - dma->stats.tx_work_cnt++; - grspw_tx_process_scheduled(dma); - if (dma->started) { - dma->stats.tx_work_enabled += - grspw_tx_schedule_send(dma); - /* Check to see if condition for waking blocked - * USER task is fullfilled. - */ - if (dma->tx_wait.waiting) - tx_cond_true = grspw_tx_wait_eval(dma); - } - rtems_semaphore_release(dma->sem_txdma); + rtems_semaphore_release(dma->sem_rxdma); + } + + if (msg & WORK_DMA_TX_MASK) { + /* Do TX Work */ + + /* Take DMA channel TX lock */ + if (rtems_semaphore_obtain(dma->sem_txdma, RTEMS_WAIT, RTEMS_NO_TIMEOUT) + != RTEMS_SUCCESSFUL) + return; + + dma->stats.tx_work_cnt++; + grspw_tx_process_scheduled(dma); + if (dma->started) { + dma->stats.tx_work_enabled += + grspw_tx_schedule_send(dma); + /* Check to see if condition for waking blocked + * USER task is fullfilled. + */ + if (dma->tx_wait.waiting) + tx_cond_true = grspw_tx_wait_eval(dma); } - } else - SPIN_UNLOCK_IRQ(&priv->devlock, irqflags); + rtems_semaphore_release(dma->sem_txdma); + } if (rx_cond_true) rtems_semaphore_release(dma->rx_wait.sem_wait); -- 2.7.4 _______________________________________________ devel mailing list devel@rtems.org http://lists.rtems.org/mailman/listinfo/devel