diff options
author | Daniel Hellstrom <daniel@gaisler.com> | 2016-03-23 10:45:26 +0100 |
---|---|---|
committer | Daniel Hellstrom <daniel@gaisler.com> | 2017-03-06 07:54:55 +0100 |
commit | eb5a42f6e000b1e3c0d8bc75c68855028e77eca0 (patch) | |
tree | b76efa0153e4d47eb2b976be73fabcb743e87b2f /c/src/lib/libbsp/sparc/shared/spw/grspw_pkt.c | |
parent | leon, grspw_pkt: coding style fixups (diff) | |
download | rtems-eb5a42f6e000b1e3c0d8bc75c68855028e77eca0.tar.bz2 |
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.
Diffstat (limited to 'c/src/lib/libbsp/sparc/shared/spw/grspw_pkt.c')
-rw-r--r-- | c/src/lib/libbsp/sparc/shared/spw/grspw_pkt.c | 44 |
1 files changed, 31 insertions, 13 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 359b1ac04f..066d30fb72 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++; |