[PATCH 35/44] leon, grspw_pkt: functions to support custom work-task

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


    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




More information about the devel mailing list