summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDaniel Hellstrom <daniel@gaisler.com>2017-04-11 10:47:39 +0200
committerDaniel Hellstrom <daniel@gaisler.com>2017-05-14 12:31:58 +0200
commit9855690300d8aa5c8f025811e3cc0bbb2c2d91e9 (patch)
tree8fb42477313fcc9ebe940eb3f14749ce5aac433c
parent3a650d3b2c376ecfb97fa410251991ea82d200f6 (diff)
downloadrtems-9855690300d8aa5c8f025811e3cc0bbb2c2d91e9.tar.bz2
leon, grcan: split hw_stop() into hw and sw stop
this is to avoid owning the spin-lock during semaphore operations.
-rw-r--r--c/src/lib/libbsp/sparc/shared/can/grcan.c13
1 files changed, 13 insertions, 0 deletions
diff --git a/c/src/lib/libbsp/sparc/shared/can/grcan.c b/c/src/lib/libbsp/sparc/shared/can/grcan.c
index 1348d7ab41..10509342ee 100644
--- a/c/src/lib/libbsp/sparc/shared/can/grcan.c
+++ b/c/src/lib/libbsp/sparc/shared/can/grcan.c
@@ -488,7 +488,10 @@ static void grcan_hw_stop(struct grcan_priv *pDev)
/* Disable receiver & transmitter */
pDev->regs->rx0ctrl = 0;
pDev->regs->tx0ctrl = 0;
+}
+static void grcan_sw_stop(struct grcan_priv *pDev)
+{
/* Reset semaphores to the initial state and wakeing
* all threads waiting for an IRQ. The threads that
* get woken up must check for RTEMS_UNSATISFIED in
@@ -1577,6 +1580,7 @@ int grcan_stop(void *d)
{
struct grcan_priv *pDev = d;
SPIN_IRQFLAGS(oldLevel);
+ int do_sw_stop;
FUNCDBG();
@@ -1586,6 +1590,7 @@ int grcan_stop(void *d)
SPIN_LOCK_IRQ(&pDev->devlock, oldLevel);
if (pDev->started == STATE_STARTED) {
grcan_hw_stop(pDev);
+ do_sw_stop = 1;
DBGC(DBG_STATE, "STARTED->STOPPED\n");
} else {
/*
@@ -1593,10 +1598,14 @@ int grcan_stop(void *d)
* might already been called from ISR.
*/
DBGC(DBG_STATE, "[STOPPED|BUSOFF|AHBERR]->STOPPED\n");
+ do_sw_stop = 0;
}
pDev->started = STATE_STOPPED;
SPIN_UNLOCK_IRQ(&pDev->devlock, oldLevel);
+ if (do_sw_stop)
+ grcan_sw_stop(pDev);
+
/* Disable interrupts */
drvmgr_interrupt_unregister(pDev->dev, 0, grcan_interrupt, pDev);
@@ -1932,6 +1941,10 @@ static void grcan_interrupt(void *arg)
* again with grcan_start().
*/
SPIN_UNLOCK(&pDev->devlock, irqflags);
+
+ /* flush semaphores to wake blocked threads */
+ grcan_sw_stop(pDev);
+
/*
* NOTE: Another interrupt may be pending now so ISR could be
* executed one more time aftert this (first) return.