[PATCH 17/44] leon, grspw_pkt: fixed device/dma closing

Daniel Hellstrom daniel at gaisler.com
Fri Mar 3 14:56:50 UTC 2017


The user is now responsible to stop and close the DMA channels
before closing the device. To prevent complicated situations and
blocking the caller of grspw_close and grspw_dma_close a return
code was added to indicate to the user that the DMA may not have
been stopped or that blocked tasks are still active within the
driver for the specified device.
---
 c/src/lib/libbsp/sparc/shared/include/grspw_pkt.h |  4 +--
 c/src/lib/libbsp/sparc/shared/spw/grspw_pkt.c     | 44 ++++++++++++++++-------
 2 files changed, 33 insertions(+), 15 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 83d5c9c..9a2a440 100644
--- a/c/src/lib/libbsp/sparc/shared/include/grspw_pkt.h
+++ b/c/src/lib/libbsp/sparc/shared/include/grspw_pkt.h
@@ -312,7 +312,7 @@ extern void grspw_initialize_user(
 	);
 extern int grspw_dev_count(void);
 extern void *grspw_open(int dev_no);
-extern void grspw_close(void *d);
+extern int grspw_close(void *d);
 extern void grspw_hw_support(void *d, struct grspw_hw_sup *hw);
 extern void grspw_stats_read(void *d, struct grspw_core_stats *sts);
 extern void grspw_stats_clr(void *d);
@@ -422,7 +422,7 @@ extern int grspw_port_active(void *d);
 
 /*** DMA Interface ***/
 extern void *grspw_dma_open(void *d, int chan_no);
-extern void grspw_dma_close(void *c);
+extern int grspw_dma_close(void *c);
 
 extern int grspw_dma_start(void *c);
 extern void grspw_dma_stop(void *c);
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 359b1ac..066d30f 100644
--- a/c/src/lib/libbsp/sparc/shared/spw/grspw_pkt.c
+++ b/c/src/lib/libbsp/sparc/shared/spw/grspw_pkt.c
@@ -623,7 +623,7 @@ out:
 	return priv;
 }
 
-void grspw_close(void *d)
+int grspw_close(void *d)
 {
 	struct grspw_priv *priv = d;
 	int i;
@@ -631,21 +631,24 @@ void grspw_close(void *d)
 	/* Take GRSPW lock - Wait until we get semaphore */
 	if (rtems_semaphore_obtain(grspw_sem, RTEMS_WAIT, RTEMS_NO_TIMEOUT)
 	    != RTEMS_SUCCESSFUL)
-		return;
+		return -1;
 
-	/* Stop Hardware from doing DMA, put HW into "startup-state",
-	 * Stop hardware from generating IRQ.
+	/* Check that user has stopped and closed all DMA channels
+	 * appropriately. At this point the Hardware shall not be doing DMA
+	 * or generating Interrupts. We want HW in a "startup-state".
 	 */
-	for (i=0; i<priv->hwsup.ndma_chans; i++)
-		grspw_dma_close(&priv->dma[i]);
+	for (i=0; i<priv->hwsup.ndma_chans; i++) {
+		if (priv->dma[i].open) {
+			rtems_semaphore_release(grspw_sem);
+			return 1;
+		}
+	}
 	grspw_hw_stop(priv);
 
 	/* Mark not open */
 	priv->open = 0;
-
 	rtems_semaphore_release(grspw_sem);
-
-	/* Check that all threads are out? */
+	return 0;
 }
 
 void grspw_hw_support(void *d, struct grspw_hw_sup *hw)
@@ -1751,19 +1754,25 @@ STATIC void grspw_dma_reset(struct grspw_dma_priv *dma)
 	grspw_dma_stats_clr(dma);
 }
 
-void grspw_dma_close(void *c)
+int grspw_dma_close(void *c)
 {
 	struct grspw_dma_priv *dma = c;
 
 	if (!dma->open)
-		return;
+		return 0;
 
 	/* Take device lock - Wait until we get semaphore */
 	if (rtems_semaphore_obtain(dma->sem_dma, RTEMS_WAIT, RTEMS_NO_TIMEOUT)
 	    != RTEMS_SUCCESSFUL)
-		return;
+		return -1;
 
-	grspw_dma_stop_locked(dma);
+	/* 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);
+		return 1;
+	}
 
 	/* Free resources */
 	rtems_semaphore_delete(dma->rx_wait.sem_wait);
@@ -1779,6 +1788,7 @@ void grspw_dma_close(void *c)
 	dma->tx_ring_base = NULL;
 
 	dma->open = 0;
+	return 0;
 }
 
 /* Schedule List of packets for transmission at some point in
@@ -2398,6 +2408,10 @@ void grspw_dma_stop(void *c)
 {
 	struct grspw_dma_priv *dma = c;
 
+	/* If DMA channel is closed we should not access the semaphore */
+	if (!dma->open)
+		return;
+
 	/* Take DMA Channel lock */
 	if (rtems_semaphore_obtain(dma->sem_dma, RTEMS_WAIT, RTEMS_NO_TIMEOUT)
 	    != RTEMS_SUCCESSFUL)
@@ -2429,6 +2443,10 @@ static void grspw_work_dma_func(struct grspw_dma_priv *dma)
 	unsigned int ctrl;
 	IRQFLAGS_TYPE irqflags;
 
+	/* 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++;
-- 
2.7.4



More information about the devel mailing list