The USB ethernet driver in linux-2.5.8-pre1/drivers/usb/rtl8150.c
unnecessarily copies all transmitted and received packets. The following
patch eliminates copying of both transmitted and received packets.
I am running the resulting driver now and it seems to be fine.
A couple of hours ago, I sent an earlier patch just to do
the elimination of the copying from transmitted packets. Please ignore
that patch and use this one against pristine linux-2.5.8-pre1. That
patch had a minor error in it, where it called dev_kfree_skb in a place
where it should have called dev_kfree_skb_irq, resulting in a bunch of
warning messages. I have put "(v2)" in the subject line of this
message to avoid confusion about which is the latest patch.
--
Adam J. Richter __ ______________ 4880 Stevens Creek Blvd, Suite 104
[EMAIL PROTECTED] \ / San Jose, California 95129-1034
+1 408 261-6630 | g g d r a s i l United States of America
fax +1 408 261-6631 "Free Software For The Rest Of Us."
--- linux-2.5.8-pre1/drivers/usb/rtl8150.c Wed Apr 3 23:38:31 2002
+++ linux/drivers/usb/rtl8150.c Fri Apr 5 05:07:29 2002
@@ -90,11 +90,11 @@
struct net_device_stats stats;
struct net_device *netdev;
struct urb *rx_urb, *tx_urb, *intr_urb, *ctrl_urb;
+ struct sk_buff *tx_skb;
+ struct sk_buff *rx_skb;
struct usb_ctrlrequest dr;
int intr_interval;
u16 rx_creg;
- u8 rx_buff[RTL8150_MAX_MTU];
- u8 tx_buff[RTL8150_MAX_MTU];
u8 intr_buff[8];
u8 phy;
};
@@ -302,12 +302,11 @@
usb_unlink_urb(dev->ctrl_urb);
}
-
static void read_bulk_callback(struct urb *urb)
{
rtl8150_t *dev;
unsigned pkt_len, res;
- struct sk_buff *skb;
+ struct sk_buff *new_skb;
struct net_device *netdev;
u16 rx_stat;
@@ -335,22 +334,25 @@
}
res = urb->actual_length;
- rx_stat = le16_to_cpu(*(short*)(dev->rx_buff + res - 4));
+ rx_stat = le16_to_cpu(*(short*)(urb->transfer_buffer + res - 4));
pkt_len = res - 4;
- if (!(skb = dev_alloc_skb(pkt_len + 2)))
+ if (!(new_skb = dev_alloc_skb(RTL8150_MAX_MTU + 4)))
goto goon;
- skb->dev = netdev;
- skb_reserve(skb, 2);
- eth_copy_and_sum(skb, dev->rx_buff, pkt_len, 0);
- skb_put(skb, pkt_len);
- skb->protocol = eth_type_trans(skb, netdev);
- netif_rx(skb);
+
+ skb_put(dev->rx_skb, pkt_len);
+ dev->rx_skb->protocol = eth_type_trans(dev->rx_skb, netdev);
+ netif_rx(dev->rx_skb);
+
+ new_skb->dev = netdev;
+ skb_reserve(new_skb, 2);
+ dev->rx_skb = new_skb;
dev->stats.rx_packets++;
dev->stats.rx_bytes += pkt_len;
goon:
FILL_BULK_URB(dev->rx_urb, dev->udev, usb_rcvbulkpipe(dev->udev,1),
- dev->rx_buff, RTL8150_MAX_MTU, read_bulk_callback, dev);
+ dev->rx_skb->data, RTL8150_MAX_MTU + 4,
+ read_bulk_callback, dev);
if ((res=usb_submit_urb(dev->rx_urb, GFP_ATOMIC)))
warn("%s: Rx urb submission failed %d", netdev->name, res);
}
@@ -363,6 +365,7 @@
dev = urb->context;
if (!dev)
return;
+ dev_kfree_skb_irq(dev->tx_skb);
if (!netif_device_present(dev->netdev))
return;
if (urb->status)
@@ -479,10 +482,9 @@
dev = netdev->priv;
count = (skb->len < 60) ? 60 : skb->len;
count = (count & 0x3f) ? count : count + 1;
- memcpy(dev->tx_buff, skb->data, skb->len);
+ dev->tx_skb = skb;
FILL_BULK_URB(dev->tx_urb, dev->udev, usb_sndbulkpipe(dev->udev,2),
- dev->tx_buff, RTL8150_MAX_MTU, write_bulk_callback, dev);
- dev->tx_urb->transfer_buffer_length = count;
+ skb->data, count, write_bulk_callback, dev);
if ((res = usb_submit_urb(dev->tx_urb, GFP_KERNEL))) {
warn("failed tx_urb %d\n", res);
@@ -493,7 +495,6 @@
dev->stats.tx_bytes += skb->len;
netdev->trans_start = jiffies;
}
- dev_kfree_skb(skb);
return 0;
}
@@ -510,10 +511,13 @@
}
down(&dev->sem);
+
FILL_BULK_URB(dev->rx_urb, dev->udev, usb_rcvbulkpipe(dev->udev,1),
- dev->rx_buff, RTL8150_MAX_MTU, read_bulk_callback, dev);
+ dev->rx_skb->data, RTL8150_MAX_MTU + 4,
+ read_bulk_callback, dev);
if ((res=usb_submit_urb(dev->rx_urb, GFP_KERNEL)))
warn("%s: rx_urb submit failed: %d", __FUNCTION__, res);
+
FILL_INT_URB(dev->intr_urb, dev->udev, usb_rcvintpipe(dev->udev,3),
dev->intr_buff, sizeof(dev->intr_buff), intr_callback,
dev, dev->intr_interval);
@@ -708,15 +712,20 @@
netdev->mtu = RTL8150_MTU;
dev->intr_interval = 100; /* 100ms */
- if (rtl8150_reset(dev) || !alloc_all_urbs(dev)) {
+ if ((dev->rx_skb = dev_alloc_skb(RTL8150_MAX_MTU + 2)) == NULL ||
+ rtl8150_reset(dev) || !alloc_all_urbs(dev)) {
err("couldn't reset the device");
free_all_urbs(dev);
+ if (dev->rx_skb != NULL)
+ dev_kfree_skb(dev->rx_skb);
unregister_netdev(dev->netdev);
kfree(netdev);
kfree(dev);
dev = NULL;
goto exit;
}
+ dev->rx_skb->dev = netdev;
+ skb_reserve(dev->rx_skb, 2);
set_ethernet_addr(dev);
info("%s: rtl8150 is detected", netdev->name);
@@ -734,6 +743,7 @@
unregister_netdev(dev->netdev);
unlink_all_urbs(dev);
free_all_urbs(dev);
+ dev_kfree_skb(dev->rx_skb);
kfree(dev->netdev);
kfree(dev);
dev->netdev = NULL;