}
}
+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;
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;
-
-next_agg:
- agg = NULL;
- if (skb_queue_empty(&tp->tx_queue))
- return;
+ do {
+ struct tx_agg *agg;
- 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;
- }
-
- 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);
+ res = r8152_tx_agg_fill(tp, agg);
+ if (res) {
+ struct net_device_stats *stats;
+ struct net_device *netdev;
+ unsigned long flags;
- stats = rtl8152_get_stats(netdev);
+ netdev = tp->netdev;
+ 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);
+ 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)