From a6091fa32b6427f4009e8b3e7c508fe20b2b2a1d Mon Sep 17 00:00:00 2001 From: Shaun Ruffell Date: Mon, 1 Dec 2008 15:59:14 +0000 Subject: 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 --- drivers/dahdi/wctc4xxp/base.c | 83 ++++++++++++++++++++++++------------------- 1 file changed, 46 insertions(+), 37 deletions(-) (limited to 'drivers/dahdi/wctc4xxp') 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 */ -- cgit v1.2.3