diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c index 0a88f647f075..825edfe8c088 100644 --- a/drivers/net/usb/r8152.c +++ b/drivers/net/usb/r8152.c @@ -1131,6 +1131,51 @@ r8152_tx_csum(struct r8152 *tp, struct tx_desc *desc, struct sk_buff *skb) } } +static int r8152_tx_agg_fill(struct r8152 *tp, struct tx_agg *agg) +{ + u32 remain; + u8 *tx_data; + + tx_data = agg->head; + agg->skb_num = agg->skb_len = 0; + remain = rx_buf_sz - sizeof(struct tx_desc); + + while (remain >= ETH_ZLEN) { + struct tx_desc *tx_desc; + struct sk_buff *skb; + unsigned int len; + + skb = skb_dequeue(&tp->tx_queue); + if (!skb) + break; + + len = skb->len; + if (remain < len) { + skb_queue_head(&tp->tx_queue, skb); + break; + } + + tx_desc = (struct tx_desc *)tx_data; + tx_data += sizeof(*tx_desc); + + r8152_tx_csum(tp, tx_desc, skb); + memcpy(tx_data, skb->data, len); + agg->skb_num++; + agg->skb_len += len; + dev_kfree_skb_any(skb); + + tx_data = tx_agg_align(tx_data + len); + remain = rx_buf_sz - sizeof(*tx_desc) - + (u32)((void *)tx_data - agg->head); + } + + usb_fill_bulk_urb(agg->urb, tp->udev, usb_sndbulkpipe(tp->udev, 2), + agg->head, (int)(tx_data - (u8 *)agg->head), + (usb_complete_t)write_bulk_callback, agg); + + return usb_submit_urb(agg->urb, GFP_ATOMIC); +} + static void rx_bottom(struct r8152 *tp) { unsigned long flags; @@ -1204,82 +1249,39 @@ submit: static void tx_bottom(struct r8152 *tp) { - struct net_device_stats *stats; - struct net_device *netdev; - struct tx_agg *agg; - unsigned long flags; - u32 remain, total; - u8 *tx_data; int res; - netdev = tp->netdev; + do { + struct tx_agg *agg; -next_agg: - agg = NULL; - if (skb_queue_empty(&tp->tx_queue)) - return; - - agg = r8152_get_tx_agg(tp); - if (!agg) - return; - - tx_data = agg->head; - agg->skb_num = agg->skb_len = 0; - remain = rx_buf_sz - sizeof(struct tx_desc); - total = 0; - - while (remain >= ETH_ZLEN) { - struct tx_desc *tx_desc; - struct sk_buff *skb; - unsigned int len; - - skb = skb_dequeue(&tp->tx_queue); - if (!skb) + if (skb_queue_empty(&tp->tx_queue)) break; - len = skb->len; - if (remain < len) { - skb_queue_head(&tp->tx_queue, skb); + agg = r8152_get_tx_agg(tp); + if (!agg) break; + + res = r8152_tx_agg_fill(tp, agg); + if (res) { + struct net_device_stats *stats; + struct net_device *netdev; + unsigned long flags; + + netdev = tp->netdev; + stats = rtl8152_get_stats(netdev); + + if (res == -ENODEV) { + netif_device_detach(netdev); + } else { + netif_warn(tp, tx_err, netdev, + "failed tx_urb %d\n", res); + stats->tx_dropped += agg->skb_num; + spin_lock_irqsave(&tp->tx_lock, flags); + list_add_tail(&agg->list, &tp->tx_free); + spin_unlock_irqrestore(&tp->tx_lock, flags); + } } - - tx_data = tx_agg_align(tx_data); - tx_desc = (struct tx_desc *)tx_data; - tx_data += sizeof(*tx_desc); - - r8152_tx_csum(tp, tx_desc, skb); - memcpy(tx_data, skb->data, len); - agg->skb_num++; - agg->skb_len += len; - dev_kfree_skb_any(skb); - - tx_data += len; - remain = rx_buf_sz - sizeof(*tx_desc) - - (u32)(tx_agg_align(tx_data) - agg->head); - } - - usb_fill_bulk_urb(agg->urb, tp->udev, usb_sndbulkpipe(tp->udev, 2), - agg->head, (int)(tx_data - (u8 *)agg->head), - (usb_complete_t)write_bulk_callback, agg); - res = usb_submit_urb(agg->urb, GFP_ATOMIC); - - stats = rtl8152_get_stats(netdev); - - if (res) { - /* Can we get/handle EPIPE here? */ - if (res == -ENODEV) { - netif_device_detach(netdev); - } else { - netif_warn(tp, tx_err, netdev, - "failed tx_urb %d\n", res); - stats->tx_dropped += agg->skb_num; - spin_lock_irqsave(&tp->tx_lock, flags); - list_add_tail(&agg->list, &tp->tx_free); - spin_unlock_irqrestore(&tp->tx_lock, flags); - } - return; - } - goto next_agg; + } while (res == 0); } static void bottom_half(unsigned long data)