|
@@ -1197,6 +1197,37 @@ EXPORT_SYMBOL_GPL(usbnet_tx_timeout);
|
|
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
|
|
|
|
+static int build_dma_sg(const struct sk_buff *skb, struct urb *urb)
|
|
|
+{
|
|
|
+ unsigned num_sgs, total_len = 0;
|
|
|
+ int i, s = 0;
|
|
|
+
|
|
|
+ num_sgs = skb_shinfo(skb)->nr_frags + 1;
|
|
|
+ if (num_sgs == 1)
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ urb->sg = kmalloc(num_sgs * sizeof(struct scatterlist), GFP_ATOMIC);
|
|
|
+ if (!urb->sg)
|
|
|
+ return -ENOMEM;
|
|
|
+
|
|
|
+ urb->num_sgs = num_sgs;
|
|
|
+ sg_init_table(urb->sg, urb->num_sgs);
|
|
|
+
|
|
|
+ sg_set_buf(&urb->sg[s++], skb->data, skb_headlen(skb));
|
|
|
+ total_len += skb_headlen(skb);
|
|
|
+
|
|
|
+ for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
|
|
|
+ struct skb_frag_struct *f = &skb_shinfo(skb)->frags[i];
|
|
|
+
|
|
|
+ total_len += skb_frag_size(f);
|
|
|
+ sg_set_page(&urb->sg[i + s], f->page.p, f->size,
|
|
|
+ f->page_offset);
|
|
|
+ }
|
|
|
+ urb->transfer_buffer_length = total_len;
|
|
|
+
|
|
|
+ return 1;
|
|
|
+}
|
|
|
+
|
|
|
netdev_tx_t usbnet_start_xmit (struct sk_buff *skb,
|
|
|
struct net_device *net)
|
|
|
{
|
|
@@ -1223,7 +1254,6 @@ netdev_tx_t usbnet_start_xmit (struct sk_buff *skb,
|
|
|
goto drop;
|
|
|
}
|
|
|
}
|
|
|
- length = skb->len;
|
|
|
|
|
|
if (!(urb = usb_alloc_urb (0, GFP_ATOMIC))) {
|
|
|
netif_dbg(dev, tx_err, dev->net, "no urb\n");
|
|
@@ -1233,10 +1263,14 @@ netdev_tx_t usbnet_start_xmit (struct sk_buff *skb,
|
|
|
entry = (struct skb_data *) skb->cb;
|
|
|
entry->urb = urb;
|
|
|
entry->dev = dev;
|
|
|
- entry->length = length;
|
|
|
|
|
|
usb_fill_bulk_urb (urb, dev->udev, dev->out,
|
|
|
skb->data, skb->len, tx_complete, skb);
|
|
|
+ if (dev->can_dma_sg) {
|
|
|
+ if (build_dma_sg(skb, urb) < 0)
|
|
|
+ goto drop;
|
|
|
+ }
|
|
|
+ entry->length = length = urb->transfer_buffer_length;
|
|
|
|
|
|
/* don't assume the hardware handles USB_ZERO_PACKET
|
|
|
* NOTE: strictly conforming cdc-ether devices should expect
|
|
@@ -1305,7 +1339,10 @@ drop:
|
|
|
not_drop:
|
|
|
if (skb)
|
|
|
dev_kfree_skb_any (skb);
|
|
|
- usb_free_urb (urb);
|
|
|
+ if (urb) {
|
|
|
+ kfree(urb->sg);
|
|
|
+ usb_free_urb(urb);
|
|
|
+ }
|
|
|
} else
|
|
|
netif_dbg(dev, tx_queued, dev->net,
|
|
|
"> tx, len %d, type 0x%x\n", length, skb->protocol);
|
|
@@ -1356,6 +1393,7 @@ static void usbnet_bh (unsigned long param)
|
|
|
rx_process (dev, skb);
|
|
|
continue;
|
|
|
case tx_done:
|
|
|
+ kfree(entry->urb->sg);
|
|
|
case rx_cleanup:
|
|
|
usb_free_urb (entry->urb);
|
|
|
dev_kfree_skb (skb);
|
|
@@ -1689,6 +1727,7 @@ int usbnet_resume (struct usb_interface *intf)
|
|
|
retval = usb_submit_urb(res, GFP_ATOMIC);
|
|
|
if (retval < 0) {
|
|
|
dev_kfree_skb_any(skb);
|
|
|
+ kfree(res->sg);
|
|
|
usb_free_urb(res);
|
|
|
usb_autopm_put_interface_async(dev->intf);
|
|
|
} else {
|