From 0d31dccdee517ca07339877231e94025bf2eb45f Mon Sep 17 00:00:00 2001 From: Daniel Hellstrom Date: Thu, 7 Apr 2016 10:02:55 +0200 Subject: leon, grspw_pkt: split DMA sem into RX and TX sem By introducing a spearate RX and TX DMA channel semaphore RX operations and TX operations does not block each other. Stopping a DMA channel needs now to take both RX and TX semaphores to block out both RX and TX tasks. --- c/src/lib/libbsp/sparc/shared/spw/grspw_pkt.c | 148 ++++++++++++++++---------- 1 file changed, 94 insertions(+), 54 deletions(-) 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 ddde100807..60aa68f936 100644 --- a/c/src/lib/libbsp/sparc/shared/spw/grspw_pkt.c +++ b/c/src/lib/libbsp/sparc/shared/spw/grspw_pkt.c @@ -376,7 +376,8 @@ struct grspw_dma_priv { int index; /* DMA Channel Index @ GRSPW core */ int open; /* DMA Channel opened by user */ int started; /* DMA Channel activity (start|stop) */ - rtems_id sem_dma; /* DMA Channel Semaphore */ + rtems_id sem_rxdma; /* DMA Channel RX Semaphore */ + rtems_id sem_txdma; /* DMA Channel TX Semaphore */ struct grspw_dma_stats stats; /* DMA Channel Statistics */ struct grspw_dma_config cfg; /* DMA Channel Configuration */ @@ -1657,18 +1658,27 @@ void *grspw_dma_open(void *d, int chan_no) dma->cfg.flags = DMAFLAG_NO_SPILL; /* set to NULL so that error exit works correctly */ - dma->sem_dma = RTEMS_ID_NONE; + dma->sem_rxdma = RTEMS_ID_NONE; + dma->sem_txdma = RTEMS_ID_NONE; dma->rx_wait.sem_wait = RTEMS_ID_NONE; dma->tx_wait.sem_wait = RTEMS_ID_NONE; dma->rx_ring_base = NULL; /* DMA Channel Semaphore created with count = 1 */ if (rtems_semaphore_create( - rtems_build_name('S', 'D', '0' + priv->index, '0' + chan_no), 1, + rtems_build_name('S', 'D', '0' + priv->index, '0' + chan_no*2), 1, RTEMS_FIFO | RTEMS_SIMPLE_BINARY_SEMAPHORE | \ RTEMS_NO_INHERIT_PRIORITY | RTEMS_LOCAL | \ - RTEMS_NO_PRIORITY_CEILING, 0, &dma->sem_dma) != RTEMS_SUCCESSFUL) { - dma->sem_dma = RTEMS_ID_NONE; + RTEMS_NO_PRIORITY_CEILING, 0, &dma->sem_rxdma) != RTEMS_SUCCESSFUL) { + dma->sem_rxdma = RTEMS_ID_NONE; + goto err; + } + if (rtems_semaphore_create( + rtems_build_name('S', 'D', '0' + priv->index, '0' + chan_no*2+1), 1, + RTEMS_FIFO | RTEMS_SIMPLE_BINARY_SEMAPHORE | \ + RTEMS_NO_INHERIT_PRIORITY | RTEMS_LOCAL | \ + RTEMS_NO_PRIORITY_CEILING, 0, &dma->sem_txdma) != RTEMS_SUCCESSFUL) { + dma->sem_txdma = RTEMS_ID_NONE; goto err; } @@ -1710,8 +1720,10 @@ out: /* initialization error happended */ err: - if (dma->sem_dma != RTEMS_ID_NONE) - rtems_semaphore_delete(dma->sem_dma); + if (dma->sem_rxdma != RTEMS_ID_NONE) + rtems_semaphore_delete(dma->sem_rxdma); + if (dma->sem_txdma != RTEMS_ID_NONE) + rtems_semaphore_delete(dma->sem_txdma); if (dma->rx_wait.sem_wait != RTEMS_ID_NONE) rtems_semaphore_delete(dma->rx_wait.sem_wait); if (dma->tx_wait.sem_wait != RTEMS_ID_NONE) @@ -1764,15 +1776,21 @@ int grspw_dma_close(void *c) return 0; /* Take device lock - Wait until we get semaphore */ - if (rtems_semaphore_obtain(dma->sem_dma, RTEMS_WAIT, RTEMS_NO_TIMEOUT) + if (rtems_semaphore_obtain(dma->sem_rxdma, RTEMS_WAIT, RTEMS_NO_TIMEOUT) != RTEMS_SUCCESSFUL) return -1; + if (rtems_semaphore_obtain(dma->sem_txdma, RTEMS_WAIT, RTEMS_NO_TIMEOUT) + != RTEMS_SUCCESSFUL) { + rtems_semaphore_release(dma->sem_rxdma); + return -1; + } /* Can not close active DMA channel. User must stop DMA and make sure * no threads are active/blocked within driver. */ if (dma->started || dma->rx_wait.waiting || dma->tx_wait.waiting) { - rtems_semaphore_release(dma->sem_dma); + rtems_semaphore_release(dma->sem_txdma); + rtems_semaphore_release(dma->sem_rxdma); return 1; } @@ -1780,8 +1798,10 @@ int grspw_dma_close(void *c) rtems_semaphore_delete(dma->rx_wait.sem_wait); rtems_semaphore_delete(dma->tx_wait.sem_wait); /* Release and delete lock. Operations requiring lock will fail */ - rtems_semaphore_delete(dma->sem_dma); - dma->sem_dma = RTEMS_ID_NONE; + rtems_semaphore_delete(dma->sem_txdma); + rtems_semaphore_delete(dma->sem_rxdma); + dma->sem_txdma = RTEMS_ID_NONE; + dma->sem_rxdma = RTEMS_ID_NONE; /* Free memory */ if (dma->rx_ring_base) @@ -1806,7 +1826,7 @@ int grspw_dma_tx_send(void *c, int opts, struct grspw_list *pkts, int count) int ret; /* Take DMA channel lock */ - if (rtems_semaphore_obtain(dma->sem_dma, RTEMS_WAIT, RTEMS_NO_TIMEOUT) + if (rtems_semaphore_obtain(dma->sem_txdma, RTEMS_WAIT, RTEMS_NO_TIMEOUT) != RTEMS_SUCCESSFUL) return -1; @@ -1834,7 +1854,7 @@ int grspw_dma_tx_send(void *c, int opts, struct grspw_list *pkts, int count) out: /* Unlock DMA channel */ - rtems_semaphore_release(dma->sem_dma); + rtems_semaphore_release(dma->sem_txdma); return ret; } @@ -1846,7 +1866,7 @@ int grspw_dma_tx_reclaim(void *c, int opts, struct grspw_list *pkts, int *count) int cnt, started; /* Take DMA channel lock */ - if (rtems_semaphore_obtain(dma->sem_dma, RTEMS_WAIT, RTEMS_NO_TIMEOUT) + if (rtems_semaphore_obtain(dma->sem_txdma, RTEMS_WAIT, RTEMS_NO_TIMEOUT) != RTEMS_SUCCESSFUL) return -1; @@ -1891,7 +1911,7 @@ int grspw_dma_tx_reclaim(void *c, int opts, struct grspw_list *pkts, int *count) grspw_tx_schedule_send(dma); /* Unlock DMA channel */ - rtems_semaphore_release(dma->sem_dma); + rtems_semaphore_release(dma->sem_txdma); return (~started) & 1; /* signal DMA has been stopped */ } @@ -1908,7 +1928,7 @@ void grspw_dma_tx_count(void *c, int *send, int *sched, int *sent, int *hw) * and that DMA descriptor table and tx_ring_tail is not being updated * during HW counter processing in this function. */ - if (rtems_semaphore_obtain(dma->sem_dma, RTEMS_WAIT, RTEMS_NO_TIMEOUT) + if (rtems_semaphore_obtain(dma->sem_txdma, RTEMS_WAIT, RTEMS_NO_TIMEOUT) != RTEMS_SUCCESSFUL) return; @@ -1938,7 +1958,7 @@ void grspw_dma_tx_count(void *c, int *send, int *sched, int *sent, int *hw) } /* Unlock DMA channel */ - rtems_semaphore_release(dma->sem_dma); + rtems_semaphore_release(dma->sem_txdma); } static inline int grspw_tx_wait_eval(struct grspw_dma_priv *dma) @@ -1979,7 +1999,7 @@ int grspw_dma_tx_wait(void *c, int send_cnt, int op, int sent_cnt, int timeout) check_condition: /* Take DMA channel lock */ - if (rtems_semaphore_obtain(dma->sem_dma, RTEMS_WAIT, RTEMS_NO_TIMEOUT) + if (rtems_semaphore_obtain(dma->sem_txdma, RTEMS_WAIT, RTEMS_NO_TIMEOUT) != RTEMS_SUCCESSFUL) return -1; @@ -2008,7 +2028,7 @@ check_condition: dma->tx_wait.waiting = 1; /* Release DMA channel lock */ - rtems_semaphore_release(dma->sem_dma); + rtems_semaphore_release(dma->sem_txdma); /* Try to take Wait lock, if this fail link may have gone down * or user stopped this DMA channel @@ -2039,7 +2059,7 @@ check_condition: out_release: /* Unlock DMA channel */ - rtems_semaphore_release(dma->sem_dma); + rtems_semaphore_release(dma->sem_txdma); out: if (initialized) @@ -2054,7 +2074,7 @@ int grspw_dma_rx_recv(void *c, int opts, struct grspw_list *pkts, int *count) int cnt, started; /* Take DMA channel lock */ - if (rtems_semaphore_obtain(dma->sem_dma, RTEMS_WAIT, RTEMS_NO_TIMEOUT) + if (rtems_semaphore_obtain(dma->sem_rxdma, RTEMS_WAIT, RTEMS_NO_TIMEOUT) != RTEMS_SUCCESSFUL) return -1; @@ -2099,7 +2119,7 @@ int grspw_dma_rx_recv(void *c, int opts, struct grspw_list *pkts, int *count) grspw_rx_schedule_ready(dma); /* Unlock DMA channel */ - rtems_semaphore_release(dma->sem_dma); + rtems_semaphore_release(dma->sem_rxdma); return (~started) & 1; } @@ -2110,7 +2130,7 @@ int grspw_dma_rx_prepare(void *c, int opts, struct grspw_list *pkts, int count) int ret; /* Take DMA channel lock */ - if (rtems_semaphore_obtain(dma->sem_dma, RTEMS_WAIT, RTEMS_NO_TIMEOUT) + if (rtems_semaphore_obtain(dma->sem_rxdma, RTEMS_WAIT, RTEMS_NO_TIMEOUT) != RTEMS_SUCCESSFUL) return -1; @@ -2138,7 +2158,7 @@ int grspw_dma_rx_prepare(void *c, int opts, struct grspw_list *pkts, int count) ret = 0; out: /* Unlock DMA channel */ - rtems_semaphore_release(dma->sem_dma); + rtems_semaphore_release(dma->sem_rxdma); return ret; } @@ -2155,7 +2175,7 @@ void grspw_dma_rx_count(void *c, int *ready, int *sched, int *recv, int *hw) * and that DMA descriptor table and rx_ring_tail is not being updated * during HW counter processing in this function. */ - if (rtems_semaphore_obtain(dma->sem_dma, RTEMS_WAIT, RTEMS_NO_TIMEOUT) + if (rtems_semaphore_obtain(dma->sem_rxdma, RTEMS_WAIT, RTEMS_NO_TIMEOUT) != RTEMS_SUCCESSFUL) return; @@ -2185,7 +2205,7 @@ void grspw_dma_rx_count(void *c, int *ready, int *sched, int *recv, int *hw) } /* Unlock DMA channel */ - rtems_semaphore_release(dma->sem_dma); + rtems_semaphore_release(dma->sem_rxdma); } static inline int grspw_rx_wait_eval(struct grspw_dma_priv *dma) @@ -2226,7 +2246,7 @@ int grspw_dma_rx_wait(void *c, int recv_cnt, int op, int ready_cnt, int timeout) check_condition: /* Take DMA channel lock */ - if (rtems_semaphore_obtain(dma->sem_dma, RTEMS_WAIT, RTEMS_NO_TIMEOUT) + if (rtems_semaphore_obtain(dma->sem_rxdma, RTEMS_WAIT, RTEMS_NO_TIMEOUT) != RTEMS_SUCCESSFUL) return -1; @@ -2255,7 +2275,7 @@ check_condition: dma->rx_wait.waiting = 1; /* Release channel lock */ - rtems_semaphore_release(dma->sem_dma); + rtems_semaphore_release(dma->sem_rxdma); /* Try to take Wait lock, if this fail link may have gone down * or user stopped this DMA channel @@ -2286,7 +2306,7 @@ check_condition: out_release: /* Unlock DMA channel */ - rtems_semaphore_release(dma->sem_dma); + rtems_semaphore_release(dma->sem_rxdma); out: if (initialized) @@ -2481,13 +2501,19 @@ void grspw_dma_stop(void *c) return; /* Take DMA Channel lock */ - if (rtems_semaphore_obtain(dma->sem_dma, RTEMS_WAIT, RTEMS_NO_TIMEOUT) + if (rtems_semaphore_obtain(dma->sem_rxdma, RTEMS_WAIT, RTEMS_NO_TIMEOUT) != RTEMS_SUCCESSFUL) return; + if (rtems_semaphore_obtain(dma->sem_txdma, RTEMS_WAIT, RTEMS_NO_TIMEOUT) + != RTEMS_SUCCESSFUL) { + rtems_semaphore_release(dma->sem_rxdma); + return; + } grspw_dma_stop_locked(dma); - rtems_semaphore_release(dma->sem_dma); + rtems_semaphore_release(dma->sem_txdma); + rtems_semaphore_release(dma->sem_rxdma); } /* Do general work, invoked indirectly from ISR */ @@ -2519,24 +2545,19 @@ static void grspw_work_dma_func(struct grspw_dma_priv *dma) tx_cond_true = 0; dma->stats.irq_cnt++; - /* Take DMA channel lock */ - if (rtems_semaphore_obtain(dma->sem_dma, RTEMS_WAIT, RTEMS_NO_TIMEOUT) - != RTEMS_SUCCESSFUL) - return; - - /* If closing DMA channel or just shut down */ - if (dma->started == 0) - goto out; - /* 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); + return; + } ctrl = REG_READ(&dma->regs->ctrl); /* Read/Write DMA error ? */ if (ctrl & GRSPW_DMA_STATUS_ERROR) { /* DMA error -> Stop DMA channel (both RX and TX) */ SPIN_UNLOCK_IRQ(&priv->devlock, irqflags); - grspw_dma_stop_locked(dma); + grspw_dma_stop(dma); } else if (ctrl & (GRSPW_DMACTRL_PR | GRSPW_DMACTRL_PS)) { /* DMA has finished a TX/RX packet */ ctrl &= ~GRSPW_DMACTRL_AT; @@ -2550,30 +2571,49 @@ static void grspw_work_dma_func(struct grspw_dma_priv *dma) SPIN_UNLOCK_IRQ(&priv->devlock, irqflags); if (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); - 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 (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); } if (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); - dma->stats.tx_work_enabled += grspw_tx_schedule_send(dma); - if (dma->tx_wait.waiting) - tx_cond_true = grspw_tx_wait_eval(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); } } else SPIN_UNLOCK_IRQ(&priv->devlock, irqflags); -out: - /* Release lock */ - rtems_semaphore_release(dma->sem_dma); - if (rx_cond_true) rtems_semaphore_release(dma->rx_wait.sem_wait); -- cgit v1.2.3