summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorShaun Ruffell <sruffell@digium.com>2008-12-01 15:59:14 +0000
committerShaun Ruffell <sruffell@digium.com>2008-12-01 15:59:14 +0000
commita6091fa32b6427f4009e8b3e7c508fe20b2b2a1d (patch)
treeba7089a3882ae22c2a569a758adf86cc06616f19
parentdceefa6dcbb0f0d109ae8a54144bd98c2d938646 (diff)
Service the transmit descriptor ring before the receive descriptor ring so
that commands that are still sitting on the transmit descriptor ring are not completed twice. git-svn-id: http://svn.asterisk.org/svn/dahdi/linux/trunk@5413 a0bf4364-ded3-4de4-8d8a-66a801d63aff
-rw-r--r--drivers/dahdi/wctc4xxp/base.c83
1 files changed, 46 insertions, 37 deletions
diff --git a/drivers/dahdi/wctc4xxp/base.c b/drivers/dahdi/wctc4xxp/base.c
index 4814d89..8941cf0 100644
--- a/drivers/dahdi/wctc4xxp/base.c
+++ b/drivers/dahdi/wctc4xxp/base.c
@@ -1818,8 +1818,9 @@ do_rx_response_packet(struct wcdte *wc, struct tcb *cmd)
(listhdr->channel == rxhdr->channel)) {
list_del_init(&pos->node);
pos->flags &= ~(__WAIT_FOR_RESPONSE);
- WARN_ON(pos->response);
pos->response = cmd;
+ WARN_ON(pos->response);
+ WARN_ON(!(pos->flags & TX_COMPLETE));
complete(&pos->complete);
break;
}
@@ -1844,6 +1845,7 @@ do_rx_ack_packet(struct wcdte *wc, struct tcb *cmd)
wc->seq_num = (rxhdr->seq_num + 1) & 0xff;
WARN_ON(!(pos->flags & DO_NOT_AUTO_FREE));
list_del_init(&pos->node);
+ WARN_ON(!(pos->flags & TX_COMPLETE));
complete(&pos->complete);
} else if ((listhdr->seq_num == rxhdr->seq_num) &&
(listhdr->channel == rxhdr->channel)) {
@@ -1853,6 +1855,7 @@ do_rx_ack_packet(struct wcdte *wc, struct tcb *cmd)
list_del_init(&pos->node);
if (pos->flags & DO_NOT_AUTO_FREE) {
+ WARN_ON(!(pos->flags & TX_COMPLETE));
complete(&pos->complete);
} else {
free_cmd(pos);
@@ -1975,49 +1978,17 @@ wctc4xxp_receiveprep(struct wcdte *wc, struct tcb *cmd)
}
}
-static inline void service_dte(struct wcdte *wc)
+static inline void service_tx_ring(struct wcdte *wc)
{
struct tcb *cmd;
-
- /*
- * Process the received packets
- */
- while((cmd = wctc4xxp_retrieve(wc->rxd))) {
- struct tcb *newcmd;
-
- wctc4xxp_net_capture_cmd(wc, cmd);
-
- if(!(newcmd = __alloc_cmd(ALLOC_FLAGS, 0))) {
- DTE_PRINTK(ERR, "Out of memory in %s.\n", __FUNCTION__);
- } else {
- if (newcmd->data_len < MAX_FRAME_SIZE) {
- newcmd->data = kmalloc(MAX_FRAME_SIZE, ALLOC_FLAGS);
- if (!newcmd->data) {
- DTE_PRINTK(ERR, "out of memory in %s " \
- "again.\n", __FUNCTION__);
- }
- newcmd->data_len = MAX_FRAME_SIZE;
- }
- if (wctc4xxp_submit(wc->rxd, newcmd)) {
- DTE_PRINTK(ERR, "Failed submit in %s\n", __FUNCTION__);
- free_cmd(newcmd);
- }
- wctc4xxp_receive_demand_poll(wc);
- }
- wctc4xxp_receiveprep(wc, cmd);
- }
- wctc4xxp_receive_demand_poll(wc);
-
- /*
- * Process the transmit packets
- */
- while((cmd = wctc4xxp_retrieve(wc->txd))) {
+ while ((cmd = wctc4xxp_retrieve(wc->txd))) {
if (!(cmd->flags & (__WAIT_FOR_ACK | __WAIT_FOR_RESPONSE))) {
/* If we're not waiting for an ACK or Response from
* the DTE, this message should not be sitting on any
* lists. */
WARN_ON(!list_empty(&cmd->node));
if (DO_NOT_AUTO_FREE & cmd->flags) {
+ WARN_ON(!(pos->flags & TX_COMPLETE));
complete(&cmd->complete);
} else {
free_cmd(cmd);
@@ -2041,6 +2012,42 @@ static inline void service_dte(struct wcdte *wc)
}
}
+static inline void service_rx_ring(struct wcdte *wc)
+{
+ struct tcb *cmd;
+ while ((cmd = wctc4xxp_retrieve(wc->rxd))) {
+ struct tcb *newcmd;
+
+ wctc4xxp_net_capture_cmd(wc, cmd);
+
+ if(!(newcmd = __alloc_cmd(ALLOC_FLAGS, 0))) {
+ DTE_PRINTK(ERR, "Out of memory in %s.\n", __FUNCTION__);
+ } else {
+ if (newcmd->data_len < MAX_FRAME_SIZE) {
+ newcmd->data = kmalloc(MAX_FRAME_SIZE, ALLOC_FLAGS);
+ if (!newcmd->data) {
+ DTE_PRINTK(ERR, "out of memory in %s " \
+ "again.\n", __FUNCTION__);
+ }
+ newcmd->data_len = MAX_FRAME_SIZE;
+ }
+ if (wctc4xxp_submit(wc->rxd, newcmd)) {
+ DTE_PRINTK(ERR, "Failed submit in %s\n", __FUNCTION__);
+ free_cmd(newcmd);
+ }
+ wctc4xxp_receive_demand_poll(wc);
+ }
+ wctc4xxp_receiveprep(wc, cmd);
+ }
+ wctc4xxp_receive_demand_poll(wc);
+}
+
+static inline void service_dte(struct wcdte *wc)
+{
+ service_tx_ring(wc);
+ service_rx_ring(wc);
+}
+
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
static void deferred_work_func(void *param)
@@ -2832,6 +2839,9 @@ wctc4xxp_watchdog(unsigned long data)
LIST_HEAD(cmds_to_retry);
const int MAX_RETRIES = 5;
+ /* Check for any commands that have completed transmitted. */
+ service_tx_ring(wc);
+
spin_lock(&wc->cmd_list_lock);
/* Go through the list of messages that are waiting for responses from
* the DTE, and complete or retry any that have timed out. */
@@ -2850,7 +2860,6 @@ wctc4xxp_watchdog(unsigned long data)
* received the ACK or the response. */
cmd->flags |= DTE_CMD_TIMEOUT;
list_del_init(&cmd->node);
- complete(&cmd->complete);
} else if (cmd->flags & TX_COMPLETE) {
/* Move this to the local list because we're
* going to resend it once we free the locks */