Commit 60e453a9 authored by Ming Lei's avatar Ming Lei Committed by David S. Miller

USBNET: fix handling padding packet

Commit 638c5115(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: default avatarDavid Laight <David.Laight@aculab.com>
Acked-by: default avatarOliver Neukum <oliver@neukum.org>
Signed-off-by: default avatarMing Lei <ming.lei@canonical.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 66451615
...@@ -1241,7 +1241,9 @@ static int build_dma_sg(const struct sk_buff *skb, struct urb *urb) ...@@ -1241,7 +1241,9 @@ static int build_dma_sg(const struct sk_buff *skb, struct urb *urb)
if (num_sgs == 1) if (num_sgs == 1)
return 0; 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) if (!urb->sg)
return -ENOMEM; return -ENOMEM;
...@@ -1305,7 +1307,7 @@ netdev_tx_t usbnet_start_xmit (struct sk_buff *skb, ...@@ -1305,7 +1307,7 @@ netdev_tx_t usbnet_start_xmit (struct sk_buff *skb,
if (build_dma_sg(skb, urb) < 0) if (build_dma_sg(skb, urb) < 0)
goto drop; goto drop;
} }
entry->length = length = urb->transfer_buffer_length; length = urb->transfer_buffer_length;
/* don't assume the hardware handles USB_ZERO_PACKET /* don't assume the hardware handles USB_ZERO_PACKET
* NOTE: strictly conforming cdc-ether devices should expect * NOTE: strictly conforming cdc-ether devices should expect
...@@ -1317,15 +1319,18 @@ netdev_tx_t usbnet_start_xmit (struct sk_buff *skb, ...@@ -1317,15 +1319,18 @@ netdev_tx_t usbnet_start_xmit (struct sk_buff *skb,
if (length % dev->maxpacket == 0) { if (length % dev->maxpacket == 0) {
if (!(info->flags & FLAG_SEND_ZLP)) { if (!(info->flags & FLAG_SEND_ZLP)) {
if (!(info->flags & FLAG_MULTI_PACKET)) { if (!(info->flags & FLAG_MULTI_PACKET)) {
urb->transfer_buffer_length++; length++;
if (skb_tailroom(skb)) { if (skb_tailroom(skb) && !urb->num_sgs) {
skb->data[skb->len] = 0; skb->data[skb->len] = 0;
__skb_put(skb, 1); __skb_put(skb, 1);
} } else if (urb->num_sgs)
sg_set_buf(&urb->sg[urb->num_sgs++],
dev->padding_pkt, 1);
} }
} else } else
urb->transfer_flags |= URB_ZERO_PACKET; urb->transfer_flags |= URB_ZERO_PACKET;
} }
entry->length = urb->transfer_buffer_length = length;
spin_lock_irqsave(&dev->txq.lock, flags); spin_lock_irqsave(&dev->txq.lock, flags);
retval = usb_autopm_get_interface_async(dev->intf); retval = usb_autopm_get_interface_async(dev->intf);
...@@ -1509,6 +1514,7 @@ void usbnet_disconnect (struct usb_interface *intf) ...@@ -1509,6 +1514,7 @@ void usbnet_disconnect (struct usb_interface *intf)
usb_kill_urb(dev->interrupt); usb_kill_urb(dev->interrupt);
usb_free_urb(dev->interrupt); usb_free_urb(dev->interrupt);
kfree(dev->padding_pkt);
free_netdev(net); free_netdev(net);
} }
...@@ -1679,9 +1685,16 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod) ...@@ -1679,9 +1685,16 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod)
/* initialize max rx_qlen and tx_qlen */ /* initialize max rx_qlen and tx_qlen */
usbnet_update_max_qlen(dev); 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); status = register_netdev (net);
if (status) if (status)
goto out4; goto out5;
netif_info(dev, probe, dev->net, netif_info(dev, probe, dev->net,
"register '%s' at usb-%s-%s, %s, %pM\n", "register '%s' at usb-%s-%s, %s, %pM\n",
udev->dev.driver->name, udev->dev.driver->name,
...@@ -1699,6 +1712,8 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod) ...@@ -1699,6 +1712,8 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod)
return 0; return 0;
out5:
kfree(dev->padding_pkt);
out4: out4:
usb_free_urb(dev->interrupt); usb_free_urb(dev->interrupt);
out3: out3:
......
...@@ -42,6 +42,7 @@ struct usbnet { ...@@ -42,6 +42,7 @@ struct usbnet {
struct usb_host_endpoint *status; struct usb_host_endpoint *status;
unsigned maxpacket; unsigned maxpacket;
struct timer_list delay; struct timer_list delay;
const char *padding_pkt;
/* protocol/interface state */ /* protocol/interface state */
struct net_device *net; struct net_device *net;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment