|
@@ -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;
|
|
|
-
|
|
|
-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)
|