summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Hellstrom <daniel@gaisler.com>2016-03-23 10:45:26 +0100
committerDaniel Hellstrom <daniel@gaisler.com>2016-03-29 16:05:33 +0200
commit9d4af50e00bec09dd1d6d385a76ec24e26b85822 (patch)
tree0ebab71eaea6de9ec5f3831906caa36d1ed763a3
parent8773af750cd209deb6ded35b8e4d39846f119502 (diff)
leon, grspw_pkt: fixed device/dma closing
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.
-rw-r--r--c/src/lib/libbsp/sparc/shared/include/grspw_pkt.h4
-rw-r--r--c/src/lib/libbsp/sparc/shared/spw/grspw_pkt.c44
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 f62e3bf0c8..9b4a313947 100644
--- a/c/src/lib/libbsp/sparc/shared/include/grspw_pkt.h
+++ b/c/src/lib/libbsp/sparc/shared/include/grspw_pkt.h
@@ -313,7 +313,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);
@@ -423,7 +423,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 3bbfc84194..9f2f9bd055 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++;