USBNET: fix handling padding packet
Commit 638c5115a7949(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>
This commit is contained in:
Родитель
6645161513
Коммит
60e453a940
|
@ -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;
|
||||
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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:
|
||||
|
|
|
@ -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;
|
||||
|
|
Загрузка…
Ссылка в новой задаче