leon, grspw_pkt: fixed and improved RX/TX wait

This commit is contained in:
Daniel Hellstrom
2016-03-22 16:41:51 +01:00
parent 57e1f4c30b
commit 9cb7e5d80f
2 changed files with 61 additions and 44 deletions

View File

@@ -487,7 +487,7 @@ extern void grspw_dma_tx_count(void *c, int *send, int *sched, int *sent);
#define GRSPW_OP_AND 0 #define GRSPW_OP_AND 0
#define GRSPW_OP_OR 1 #define GRSPW_OP_OR 1
/* Block until ready_cnt or fewer packets are Queued in "Send and Scheduled" Q, /* Block until send_cnt or fewer packets are Queued in "Send and Scheduled" Q,
* op (AND or OR), sent_cnt or more packet "have been sent" (Sent Q) condition * op (AND or OR), sent_cnt or more packet "have been sent" (Sent Q) condition
* is met. * is met.
* If a link error occurs and the Stop on Link error is defined, this function * If a link error occurs and the Stop on Link error is defined, this function
@@ -504,6 +504,7 @@ extern void grspw_dma_tx_count(void *c, int *send, int *sched, int *sent);
* 0 Returing to caller because specified conditions are now fullfilled * 0 Returing to caller because specified conditions are now fullfilled
* 1 DMA stopped * 1 DMA stopped
* 2 Timeout, conditions are not met * 2 Timeout, conditions are not met
* 3 Another task is already waiting. Service is Busy.
*/ */
extern int grspw_dma_tx_wait(void *c, int send_cnt, int op, int sent_cnt, int timeout); extern int grspw_dma_tx_wait(void *c, int send_cnt, int op, int sent_cnt, int timeout);
@@ -565,7 +566,7 @@ extern void grspw_dma_rx_count(void *c, int *ready, int *sched, int *recv);
* the other conditions. If timeout is zero, the function will wait forever * the other conditions. If timeout is zero, the function will wait forever
* until the condition is satisfied. * until the condition is satisfied.
* *
* NOTE: if IRQ of TX descriptors are not enabled conditions are never * NOTE: if IRQ of RX descriptors are not enabled conditions are never
* checked, this may hang infinitely unless a timeout has been specified * checked, this may hang infinitely unless a timeout has been specified
* *
* Return Code * Return Code
@@ -573,6 +574,7 @@ extern void grspw_dma_rx_count(void *c, int *ready, int *sched, int *recv);
* 0 Returing to caller because specified conditions are now fullfilled * 0 Returing to caller because specified conditions are now fullfilled
* 1 DMA stopped * 1 DMA stopped
* 2 Timeout, conditions are not met * 2 Timeout, conditions are not met
* 3 Another task is already waiting. Service is Busy.
*/ */
extern int grspw_dma_rx_wait(void *c, int recv_cnt, int op, int ready_cnt, int timeout); extern int grspw_dma_rx_wait(void *c, int recv_cnt, int op, int ready_cnt, int timeout);

View File

@@ -1926,7 +1926,7 @@ static inline int grspw_tx_wait_eval(struct grspw_dma_priv *dma)
int grspw_dma_tx_wait(void *c, int send_cnt, int op, int sent_cnt, int timeout) int grspw_dma_tx_wait(void *c, int send_cnt, int op, int sent_cnt, int timeout)
{ {
struct grspw_dma_priv *dma = c; struct grspw_dma_priv *dma = c;
int ret, rc; int ret, rc, initialized = 0;
if (timeout == 0) if (timeout == 0)
timeout = RTEMS_NO_TIMEOUT; timeout = RTEMS_NO_TIMEOUT;
@@ -1941,15 +1941,15 @@ check_condition:
/* Check so that no other thread is waiting, this driver only supports /* Check so that no other thread is waiting, this driver only supports
* one waiter at a time. * one waiter at a time.
*/ */
if (dma->tx_wait.waiting) { if (initialized == 0 && dma->tx_wait.waiting) {
ret = -1; ret = 3;
goto out; goto out_release;
} }
/* Stop if link error or similar, abort */ /* Stop if link error or similar (DMA stopped), abort */
if (dma->started == 0) { if (dma->started == 0) {
ret = 1; ret = 1;
goto out; goto out_release;
} }
/* Set up Condition */ /* Set up Condition */
@@ -1959,6 +1959,7 @@ check_condition:
if (grspw_tx_wait_eval(dma) == 0) { if (grspw_tx_wait_eval(dma) == 0) {
/* Prepare Wait */ /* Prepare Wait */
initialized = 1;
dma->tx_wait.waiting = 1; dma->tx_wait.waiting = 1;
/* Release DMA channel lock */ /* Release DMA channel lock */
@@ -1970,27 +1971,34 @@ check_condition:
rc = rtems_semaphore_obtain(dma->tx_wait.sem_wait, RTEMS_WAIT, rc = rtems_semaphore_obtain(dma->tx_wait.sem_wait, RTEMS_WAIT,
timeout); timeout);
if (rc == RTEMS_TIMEOUT) { if (rc == RTEMS_TIMEOUT) {
dma->tx_wait.waiting = 0; ret = 2;
return 2; goto out;
} else if (rc == RTEMS_UNSATISFIED || } else if (rc == RTEMS_UNSATISFIED ||
rc == RTEMS_OBJECT_WAS_DELETED) { rc == RTEMS_OBJECT_WAS_DELETED) {
dma->tx_wait.waiting = 0; ret = 1; /* sem was flushed/deleted, means DMA stop */
return 1; /* sem was flushed/deleted, means DMA stop */ goto out;
} else if (rc != RTEMS_SUCCESSFUL) } else if (rc != RTEMS_SUCCESSFUL) {
return -1; /* Unknown Error */
ret = -1;
goto out;
} else if (dma->started == 0) {
ret = 1;
goto out;
}
/* Check condition once more */ /* Check condition once more */
goto check_condition; goto check_condition;
} else {
/* No Wait needed */
dma->tx_wait.waiting = 0;
} }
ret = 0; ret = 0;
out:
out_release:
/* Unlock DMA channel */ /* Unlock DMA channel */
rtems_semaphore_release(dma->sem_dma); rtems_semaphore_release(dma->sem_dma);
out:
if (initialized)
dma->tx_wait.waiting = 0;
return ret; return ret;
} }
@@ -2132,7 +2140,7 @@ static inline int grspw_rx_wait_eval(struct grspw_dma_priv *dma)
int grspw_dma_rx_wait(void *c, int recv_cnt, int op, int ready_cnt, int timeout) int grspw_dma_rx_wait(void *c, int recv_cnt, int op, int ready_cnt, int timeout)
{ {
struct grspw_dma_priv *dma = c; struct grspw_dma_priv *dma = c;
int ret, rc; int ret, rc, initialized = 0;
if (timeout == 0) if (timeout == 0)
timeout = RTEMS_NO_TIMEOUT; timeout = RTEMS_NO_TIMEOUT;
@@ -2147,15 +2155,15 @@ check_condition:
/* Check so that no other thread is waiting, this driver only supports /* Check so that no other thread is waiting, this driver only supports
* one waiter at a time. * one waiter at a time.
*/ */
if (dma->rx_wait.waiting) { if (initialized == 0 && dma->rx_wait.waiting) {
ret = -1; ret = 3;
goto out; goto out_release;
} }
/* Stop if link error or similar (MDA stopped) */ /* Stop if link error or similar (DMA stopped), abort */
if (dma->started == 0) { if (dma->started == 0) {
ret = 1; ret = 1;
goto out; goto out_release;
} }
/* Set up Condition */ /* Set up Condition */
@@ -2165,6 +2173,7 @@ check_condition:
if (grspw_rx_wait_eval(dma) == 0) { if (grspw_rx_wait_eval(dma) == 0) {
/* Prepare Wait */ /* Prepare Wait */
initialized = 1;
dma->rx_wait.waiting = 1; dma->rx_wait.waiting = 1;
/* Release channel lock */ /* Release channel lock */
@@ -2176,27 +2185,34 @@ check_condition:
rc = rtems_semaphore_obtain(dma->rx_wait.sem_wait, RTEMS_WAIT, rc = rtems_semaphore_obtain(dma->rx_wait.sem_wait, RTEMS_WAIT,
timeout); timeout);
if (rc == RTEMS_TIMEOUT) { if (rc == RTEMS_TIMEOUT) {
dma->rx_wait.waiting = 0; ret = 2;
return 2; goto out;
} else if (rc == RTEMS_UNSATISFIED || } else if (rc == RTEMS_UNSATISFIED ||
rc == RTEMS_OBJECT_WAS_DELETED) { rc == RTEMS_OBJECT_WAS_DELETED) {
dma->rx_wait.waiting = 0; ret = 1; /* sem was flushed/deleted, means DMA stop */
return 1; /* sem was flushed/deleted, means DMA stop */ goto out;
} else if (rc != RTEMS_SUCCESSFUL) } else if (rc != RTEMS_SUCCESSFUL) {
return -1; /* Unknown Error */
ret = -1;
goto out;
} else if (dma->started == 0) {
ret = 1;
goto out;
}
/* Check condition once more */ /* Check condition once more */
goto check_condition; goto check_condition;
} else {
/* No Wait needed */
dma->rx_wait.waiting = 0;
} }
ret = 0; ret = 0;
out: out_release:
/* Unlock DMA channel */ /* Unlock DMA channel */
rtems_semaphore_release(dma->sem_dma); rtems_semaphore_release(dma->sem_dma);
out:
if (initialized)
dma->rx_wait.waiting = 0;
return ret; return ret;
} }
@@ -2398,8 +2414,8 @@ static void grspw_work_shutdown_func(struct grspw_priv *priv)
int i; int i;
/* Link is down for some reason, and the user has configured /* Link is down for some reason, and the user has configured
* that we stop all DMA channels and throw out all blocked * that we stop all (open) DMA channels and throw out all their
* threads. * blocked threads.
*/ */
for (i=0; i<priv->hwsup.ndma_chans; i++) for (i=0; i<priv->hwsup.ndma_chans; i++)
grspw_dma_stop(&priv->dma[i]); grspw_dma_stop(&priv->dma[i]);
@@ -2422,6 +2438,10 @@ static void grspw_work_dma_func(struct grspw_dma_priv *dma)
!= RTEMS_SUCCESSFUL) != RTEMS_SUCCESSFUL)
return; return;
/* If closing DMA channel or just shut down */
if (dma->started == 0)
goto out;
/* Look at cause we were woken up and clear source */ /* Look at cause we were woken up and clear source */
SPIN_LOCK_IRQ(&priv->devlock, irqflags); SPIN_LOCK_IRQ(&priv->devlock, irqflags);
ctrl = REG_READ(&dma->regs->ctrl); ctrl = REG_READ(&dma->regs->ctrl);
@@ -2448,26 +2468,21 @@ static void grspw_work_dma_func(struct grspw_dma_priv *dma)
/* Check to see if condition for waking blocked USER /* Check to see if condition for waking blocked USER
* task is fullfilled. * task is fullfilled.
*/ */
if (dma->rx_wait.waiting) { if (dma->rx_wait.waiting)
rx_cond_true = grspw_rx_wait_eval(dma); rx_cond_true = grspw_rx_wait_eval(dma);
if (rx_cond_true)
dma->rx_wait.waiting = 0;
}
} }
if (ctrl & GRSPW_DMACTRL_PS) { if (ctrl & GRSPW_DMACTRL_PS) {
/* Do TX Work */ /* Do TX Work */
dma->stats.tx_work_cnt++; dma->stats.tx_work_cnt++;
grspw_tx_process_scheduled(dma); grspw_tx_process_scheduled(dma);
dma->stats.tx_work_enabled += grspw_tx_schedule_send(dma); dma->stats.tx_work_enabled += grspw_tx_schedule_send(dma);
if (dma->tx_wait.waiting) { if (dma->tx_wait.waiting)
tx_cond_true = grspw_tx_wait_eval(dma); tx_cond_true = grspw_tx_wait_eval(dma);
if (tx_cond_true)
dma->tx_wait.waiting = 0;
}
} }
} else } else
SPIN_UNLOCK_IRQ(&priv->devlock, irqflags); SPIN_UNLOCK_IRQ(&priv->devlock, irqflags);
out:
/* Release lock */ /* Release lock */
rtems_semaphore_release(dma->sem_dma); rtems_semaphore_release(dma->sem_dma);