| From oneukum@suse.de Fri Mar 30 04:11:00 2007 |
| From: Oliver Neukum <oneukum@suse.de> |
| Date: Fri, 30 Mar 2007 13:11:00 +0200 |
| Subject: USB: fix catc error handling |
| To: Greg KH <gregkh@suse.de>, linux-usb-devel@lists.sourceforge.net |
| Message-ID: <200703301311.00961.oneukum@suse.de> |
| Content-Disposition: inline |
| |
| |
| this driver ignores errors while starting the transmit queue. It will |
| never be reported stopped as the completion handler won't run |
| and it will never be started again as it will be considered started. |
| This patch adds error handling. |
| |
| Signed-off-by: Oliver Neukum <oneukum@suse.de> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> |
| |
| --- |
| drivers/usb/net/catc.c | 27 +++++++++++++++++++-------- |
| 1 file changed, 19 insertions(+), 8 deletions(-) |
| |
| --- a/drivers/usb/net/catc.c |
| +++ b/drivers/usb/net/catc.c |
| @@ -356,7 +356,7 @@ resubmit: |
| * Transmit routines. |
| */ |
| |
| -static void catc_tx_run(struct catc *catc) |
| +static int catc_tx_run(struct catc *catc) |
| { |
| int status; |
| |
| @@ -374,12 +374,14 @@ static void catc_tx_run(struct catc *cat |
| catc->tx_ptr = 0; |
| |
| catc->netdev->trans_start = jiffies; |
| + return status; |
| } |
| |
| static void catc_tx_done(struct urb *urb) |
| { |
| struct catc *catc = urb->context; |
| unsigned long flags; |
| + int r; |
| |
| if (urb->status == -ECONNRESET) { |
| dbg("Tx Reset."); |
| @@ -398,10 +400,13 @@ static void catc_tx_done(struct urb *urb |
| |
| spin_lock_irqsave(&catc->tx_lock, flags); |
| |
| - if (catc->tx_ptr) |
| - catc_tx_run(catc); |
| - else |
| + if (catc->tx_ptr) { |
| + r = catc_tx_run(catc); |
| + if (unlikely(r < 0)) |
| + clear_bit(TX_RUNNING, &catc->flags); |
| + } else { |
| clear_bit(TX_RUNNING, &catc->flags); |
| + } |
| |
| netif_wake_queue(catc->netdev); |
| |
| @@ -412,6 +417,7 @@ static int catc_hard_start_xmit(struct s |
| { |
| struct catc *catc = netdev_priv(netdev); |
| unsigned long flags; |
| + int r = 0; |
| char *tx_buf; |
| |
| spin_lock_irqsave(&catc->tx_lock, flags); |
| @@ -422,8 +428,11 @@ static int catc_hard_start_xmit(struct s |
| memcpy(tx_buf + 2, skb->data, skb->len); |
| catc->tx_ptr += skb->len + 2; |
| |
| - if (!test_and_set_bit(TX_RUNNING, &catc->flags)) |
| - catc_tx_run(catc); |
| + if (!test_and_set_bit(TX_RUNNING, &catc->flags)) { |
| + r = catc_tx_run(catc); |
| + if (r < 0) |
| + clear_bit(TX_RUNNING, &catc->flags); |
| + } |
| |
| if ((catc->is_f5u011 && catc->tx_ptr) |
| || (catc->tx_ptr >= ((TX_MAX_BURST - 1) * (PKT_SZ + 2)))) |
| @@ -431,8 +440,10 @@ static int catc_hard_start_xmit(struct s |
| |
| spin_unlock_irqrestore(&catc->tx_lock, flags); |
| |
| - catc->stats.tx_bytes += skb->len; |
| - catc->stats.tx_packets++; |
| + if (r >= 0) { |
| + catc->stats.tx_bytes += skb->len; |
| + catc->stats.tx_packets++; |
| + } |
| |
| dev_kfree_skb(skb); |
| |