diff mbox

[RFC,usbnet.c] - Add packet aggregation capability

Message ID 1244656659.2845.11.camel@localhost.localdomain
State RFC, archived
Delegated to: David Miller
Headers show

Commit Message

David Hollis June 10, 2009, 5:57 p.m. UTC
The ASIX AX88772 and AX88178 devices have the ability to transmit up 16K
worth of packets in a single bulk transfer.  The asix.c driver currently
doesn't support aggregating multiple packets into this buffer so that
packets can be transmitted in a single transfer.  On some systems -
notably ARM - high cpu utilization is experienced when transmitting
large numbers of packets.

The attached set of patches provided by ASIX add this capability to the
usbnet.c driver and add the implementation for the asix.c driver.  

These patches are not yet ready for merging but we are very interested
in any review and comments that can be provided at this time.

One item that I have is how to handle the portion in usbnet_probe() that
sets the hard_start_xmit handler with the change to netdevice_ops:

-	net->hard_start_xmit = usbnet_start_xmit;
+	if (info->tx_gather)
+		net->hard_start_xmit = usbnet_bundle_xmit;
+	else
+		net->hard_start_xmit = usbnet_start_xmit;


Would it be the most appropriate to merge the
usbnet_aggregate_skb_xmit() pieces into the existing usbnet_start_xmit
with appropriate conditionals?

Comments

David Miller June 11, 2009, 12:38 p.m. UTC | #1
From: David Hollis <dhollis@davehollis.com>
Date: Wed, 10 Jun 2009 13:57:39 -0400

> One item that I have is how to handle the portion in usbnet_probe() that
> sets the hard_start_xmit handler with the change to netdevice_ops:
> 
> -	net->hard_start_xmit = usbnet_start_xmit;
> +	if (info->tx_gather)
> +		net->hard_start_xmit = usbnet_bundle_xmit;
> +	else
> +		net->hard_start_xmit = usbnet_start_xmit;
> 
> 
> Would it be the most appropriate to merge the
> usbnet_aggregate_skb_xmit() pieces into the existing usbnet_start_xmit
> with appropriate conditionals?

In the current tree you cannot even make this assignment.

Everything must go through a net_device_ops set of methods,
the pointer of which is const.
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
David Hollis June 11, 2009, 1:30 p.m. UTC | #2
On Thu, 2009-06-11 at 05:38 -0700, David Miller wrote:
> From: David Hollis <dhollis@davehollis.com>
> Date: Wed, 10 Jun 2009 13:57:39 -0400
> 
> > One item that I have is how to handle the portion in usbnet_probe() that
> > sets the hard_start_xmit handler with the change to netdevice_ops:
> > 
> > -	net->hard_start_xmit = usbnet_start_xmit;
> > +	if (info->tx_gather)
> > +		net->hard_start_xmit = usbnet_bundle_xmit;
> > +	else
> > +		net->hard_start_xmit = usbnet_start_xmit;
> > 
> > 
> > Would it be the most appropriate to merge the
> > usbnet_aggregate_skb_xmit() pieces into the existing usbnet_start_xmit
> > with appropriate conditionals?
> 
> In the current tree you cannot even make this assignment.
> 
> Everything must go through a net_device_ops set of methods,
> the pointer of which is const.

So I'd need to have to separate net_device_ops and set
net->hard_start_xmit to the appropriate one based on info->tx_gather
being defined.

Not a problem.


> --
> To unsubscribe from this list: send the line "unsubscribe netdev" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

--- ../../../linux-2.6.29.4/drivers/net/usb/asix.c	2009-05-19 07:52:34.000000000 +0800
+++ asix.c	2009-06-10 10:15:17.000000000 +0800
@@ -354,6 +354,85 @@ 
 	return 1;
 }
 
+static struct sk_buff *
+ax88772_tx_gather (struct usbnet *dev, struct sk_buff_head *q,
+			size_t *actual_len)
+{
+	struct sk_buff		*skb = NULL, *skb_next = NULL;
+	int			pkt_cnt;
+	u16			pkt_size;
+	u32			skb_len = 0;
+
+	u32			packet_hdr;
+	u32			padbytes = 0xffff0000;
+	u8			padneeded = 0;
+	struct driver_info	*info = dev->driver_info;
+
+	pkt_cnt = skb_queue_len (q);
+
+	*actual_len = 0;
+	for (skb_next = q->next; skb_next != (struct sk_buff *) q;
+	     skb_next = skb_next->next){
+		*actual_len += skb_next->len;
+		pkt_size = (skb_next->len + 4 + 1) & 0xFFFE;
+		skb_len += pkt_size;
+	}
+
+	if ((skb_len % 512) == 0) {
+		skb_len += sizeof (padbytes);
+		padneeded = 1;
+	}
+
+	if (pkt_cnt > 1){
+
+		skb = dev_alloc_skb (skb_len); 
+
+		if (!skb){
+
+			while (pkt_cnt--) {
+				skb_next = __skb_dequeue(q);
+				dev_kfree_skb_any (skb_next);
+			}
+
+			devdbg (dev, "skb is NULL, len %d", skb_len);
+			return skb;
+		}
+
+		while (pkt_cnt--) {
+
+			skb_next = __skb_dequeue(q);
+
+			packet_hdr = ((skb_next->len ^ 0x0000ffff) << 16) +
+						skb_next->len;
+
+			le32_to_cpus(&packet_hdr);
+			memcpy (skb_put(skb, 4),  &packet_hdr, 4);
+			memcpy (skb_put(skb, skb_next->len),  skb_next->data,
+						skb_next->len);
+			if (skb->len & 1)
+				skb_put (skb, 1);
+			dev_kfree_skb_any (skb_next);
+		}
+
+		if (padneeded) {
+			memcpy (skb_put(skb, sizeof (padbytes)),
+					&padbytes, sizeof (padbytes));
+		}
+		
+	}else{ //only one packet to send
+		skb = __skb_dequeue(q);
+
+		skb = info->tx_fixup (dev, skb, GFP_ATOMIC);
+		if (!skb) {
+			if (netif_msg_tx_err (dev))
+				devdbg (dev, "can't tx_fixup skb");
+			return skb;
+		}
+	}
+
+	return skb;
+}
+
 static struct sk_buff *asix_tx_fixup(struct usbnet *dev, struct sk_buff *skb,
 					gfp_t flags)
 {
@@ -1011,6 +1090,7 @@ 
 		/* hard_mtu  is still the default - the device does not support
 		   jumbo eth frames */
 		dev->rx_urb_size = 2048;
+		dev->tx_threshold = 16384;
 	}
 	return 0;
 
@@ -1281,6 +1361,7 @@ 
 		/* hard_mtu  is still the default - the device does not support
 		   jumbo eth frames */
 		dev->rx_urb_size = 2048;
+		dev->tx_threshold = 16384;
 	}
 	return 0;
 
@@ -1337,6 +1418,7 @@ 
 	.flags = FLAG_ETHER | FLAG_FRAMING_AX,
 	.rx_fixup = asix_rx_fixup,
 	.tx_fixup = asix_tx_fixup,
+	.tx_gather = ax88772_tx_gather,
 };
 
 static const struct driver_info ax88178_info = {
@@ -1348,6 +1430,7 @@ 
 	.flags = FLAG_ETHER | FLAG_FRAMING_AX,
 	.rx_fixup = asix_rx_fixup,
 	.tx_fixup = asix_tx_fixup,
+	.tx_gather = ax88772_tx_gather,
 };
 
 static const struct usb_device_id	products [] = {