Skip to content

Commit

Permalink
USBNET: fix handling padding packet
Browse files Browse the repository at this point in the history
Commit 638c511(USBNET: support DMA SG) introduces DMA SG
if the usb host controller is capable of building packet from
discontinuous buffers, but missed handling padding packet when
building DMA SG.

This patch attachs the pre-allocated padding packet at the
end of the sg list, so padding packet can be sent to device
if drivers require that.

Reported-by: David Laight <David.Laight@aculab.com>
Acked-by: Oliver Neukum <oliver@neukum.org>
Signed-off-by: Ming Lei <ming.lei@canonical.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Ming Lei authored and David S. Miller committed Sep 28, 2013
1 parent 6645161 commit 60e453a
Show file tree
Hide file tree
Showing 2 changed files with 22 additions and 6 deletions.
27 changes: 21 additions & 6 deletions drivers/net/usb/usbnet.c
Original file line number Diff line number Diff line change
Expand Up @@ -1241,7 +1241,9 @@ static int build_dma_sg(const struct sk_buff *skb, struct urb *urb)
if (num_sgs == 1)
return 0;

urb->sg = kmalloc(num_sgs * sizeof(struct scatterlist), GFP_ATOMIC);
/* reserve one for zero packet */
urb->sg = kmalloc((num_sgs + 1) * sizeof(struct scatterlist),
GFP_ATOMIC);
if (!urb->sg)
return -ENOMEM;

Expand Down Expand Up @@ -1305,7 +1307,7 @@ netdev_tx_t usbnet_start_xmit (struct sk_buff *skb,
if (build_dma_sg(skb, urb) < 0)
goto drop;
}
entry->length = length = urb->transfer_buffer_length;
length = urb->transfer_buffer_length;

/* don't assume the hardware handles USB_ZERO_PACKET
* NOTE: strictly conforming cdc-ether devices should expect
Expand All @@ -1317,15 +1319,18 @@ netdev_tx_t usbnet_start_xmit (struct sk_buff *skb,
if (length % dev->maxpacket == 0) {
if (!(info->flags & FLAG_SEND_ZLP)) {
if (!(info->flags & FLAG_MULTI_PACKET)) {
urb->transfer_buffer_length++;
if (skb_tailroom(skb)) {
length++;
if (skb_tailroom(skb) && !urb->num_sgs) {
skb->data[skb->len] = 0;
__skb_put(skb, 1);
}
} else if (urb->num_sgs)
sg_set_buf(&urb->sg[urb->num_sgs++],
dev->padding_pkt, 1);
}
} else
urb->transfer_flags |= URB_ZERO_PACKET;
}
entry->length = urb->transfer_buffer_length = length;

spin_lock_irqsave(&dev->txq.lock, flags);
retval = usb_autopm_get_interface_async(dev->intf);
Expand Down Expand Up @@ -1509,6 +1514,7 @@ void usbnet_disconnect (struct usb_interface *intf)

usb_kill_urb(dev->interrupt);
usb_free_urb(dev->interrupt);
kfree(dev->padding_pkt);

free_netdev(net);
}
Expand Down Expand Up @@ -1679,9 +1685,16 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod)
/* initialize max rx_qlen and tx_qlen */
usbnet_update_max_qlen(dev);

if (dev->can_dma_sg && !(info->flags & FLAG_SEND_ZLP) &&
!(info->flags & FLAG_MULTI_PACKET)) {
dev->padding_pkt = kzalloc(1, GFP_KERNEL);
if (!dev->padding_pkt)
goto out4;
}

status = register_netdev (net);
if (status)
goto out4;
goto out5;
netif_info(dev, probe, dev->net,
"register '%s' at usb-%s-%s, %s, %pM\n",
udev->dev.driver->name,
Expand All @@ -1699,6 +1712,8 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod)

return 0;

out5:
kfree(dev->padding_pkt);
out4:
usb_free_urb(dev->interrupt);
out3:
Expand Down
1 change: 1 addition & 0 deletions include/linux/usb/usbnet.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ struct usbnet {
struct usb_host_endpoint *status;
unsigned maxpacket;
struct timer_list delay;
const char *padding_pkt;

/* protocol/interface state */
struct net_device *net;
Expand Down

0 comments on commit 60e453a

Please sign in to comment.