Patchwork [1/1] AX88179_178A: Add FLAG_HW_IPALIGN to determine whether reserving NET_IP_ALIGN bytes for an SKB.

login
register
mail settings
Submitter Freddy Xin
Date Dec. 13, 2013, 9:25 a.m.
Message ID <1386926708-2343-1-git-send-email-freddy@asix.com.tw>
Download mbox | patch
Permalink /patch/300970/
State Changes Requested
Delegated to: David Miller
Headers show

Comments

Freddy Xin - Dec. 13, 2013, 9:25 a.m.
From: Freddy Xin <freddy@asix.com.tw>

The AX88179_178A has a hardware feature that it can insert a
2-bytes pseudo header in front of each received frame by setting
the AX_RX_CTL_IPE bit. This feature is used to let the IP header
be aligned on a doubleword-aligned address, so the rx_submit() of
usbnet.c needn't reserve NET_IP_ALIGN bytes for an SKB in the case.

This patch adds a flag of driver_info "FLAG_HW_IPALIGN" which is
used in rx_submit() of usbnet.c to determine whether reserving
NET_IP_ALIGN bytes for an SKB.

Signed-off-by: Freddy Xin <freddy@asix.com.tw>
---
 drivers/net/usb/ax88179_178a.c | 8 ++++----
 drivers/net/usb/usbnet.c       | 5 ++++-
 include/linux/usb/usbnet.h     | 3 +++
 3 files changed, 11 insertions(+), 5 deletions(-)
David Laight - Dec. 13, 2013, 10:36 a.m.
> From: freddy@asix.com.tw
...
> -	skb = __netdev_alloc_skb_ip_align(dev->net, size, flags);
> +	if (dev->driver_info->flags & FLAG_HW_IPALIGN)
> +		skb = __netdev_alloc_skb(dev->net, size, flags);
> +	else
> +		skb = __netdev_alloc_skb_ip_align(dev->net, size, flags);

Given the definition:
static inline struct sk_buff *__netdev_alloc_skb_ip_align(struct net_device *dev,
                unsigned int length, gfp_t gfp)
{
        struct sk_buff *skb = __netdev_alloc_skb(dev, length + NET_IP_ALIGN, gfp);

        if (NET_IP_ALIGN && skb)
                skb_reserve(skb, NET_IP_ALIGN);
        return skb;
}

It really ought to be possible to code that without an extra conditional.

	David



--
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
Freddy Xin - Dec. 16, 2013, 6:54 a.m.
On 2013年12月13日 18:36, David Laight wrote:
>> From: freddy@asix.com.tw
> ...
>> -	skb = __netdev_alloc_skb_ip_align(dev->net, size, flags);
>> +	if (dev->driver_info->flags & FLAG_HW_IPALIGN)
>> +		skb = __netdev_alloc_skb(dev->net, size, flags);
>> +	else
>> +		skb = __netdev_alloc_skb_ip_align(dev->net, size, flags);
> Given the definition:
> static inline struct sk_buff *__netdev_alloc_skb_ip_align(struct net_device *dev,
>                  unsigned int length, gfp_t gfp)
> {
>          struct sk_buff *skb = __netdev_alloc_skb(dev, length + NET_IP_ALIGN, gfp);
>
>          if (NET_IP_ALIGN && skb)
>                  skb_reserve(skb, NET_IP_ALIGN);
>          return skb;
> }
>
> It really ought to be possible to code that without an extra conditional.
>
> 	David
>
>
>
>
The AX88179_178A driver do need to know the value of NET_IP_ALIGN
to determine whether enabling the feature that makes IP header align
on a dword-aligned address, but according to the comments from David
Miller, I need to consider all situations, not just for the case that
NET_IP_ALIGN is zero, so the condition added in rx_submit is just used to
determine whether reserving NET_IP_ALIGN bytes for each SKB.

Freddy
--
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 Laight - Dec. 16, 2013, 10:09 a.m.
> From: Freddy Xin

> On 2013年12月13日 18:36, David Laight wrote:

> >> From: freddy@asix.com.tw

> > ...

> >> -	skb = __netdev_alloc_skb_ip_align(dev->net, size, flags);

> >> +	if (dev->driver_info->flags & FLAG_HW_IPALIGN)

> >> +		skb = __netdev_alloc_skb(dev->net, size, flags);

> >> +	else

> >> +		skb = __netdev_alloc_skb_ip_align(dev->net, size, flags);

> > Given the definition:

> > static inline struct sk_buff *__netdev_alloc_skb_ip_align(struct net_device *dev,

> >                  unsigned int length, gfp_t gfp)

> > {

> >          struct sk_buff *skb = __netdev_alloc_skb(dev, length + NET_IP_ALIGN, gfp);

> >

> >          if (NET_IP_ALIGN && skb)

> >                  skb_reserve(skb, NET_IP_ALIGN);

> >          return skb;

> > }

> >

> > It really ought to be possible to code that without an extra conditional.

> >

> > 	David

>

> The AX88179_178A driver do need to know the value of NET_IP_ALIGN

> to determine whether enabling the feature that makes IP header align

> on a dword-aligned address, but according to the comments from David

> Miller, I need to consider all situations, not just for the case that

> NET_IP_ALIGN is zero, so the condition added in rx_submit is just used to

> determine whether reserving NET_IP_ALIGN bytes for each SKB.


I was thinking of something like:

	skb = netdev_alloc_skb(dev, length + dev->skb_align, gfp);
	if (NET_IP_ALIGN && skb && !(ev->driver_flags & FLAG_HW_IPALIGN))
		skb_reserve(skb, NET_IP_ALIGN);

It might even be reasonable to remove the length adjustment - provided
that all the later code uses the skb length.

	David
Freddy Xin - Dec. 19, 2013, 3:14 a.m.
On 2013年12月16日 18:09, David Laight wrote:
>> I was thinking of something like: skb = netdev_alloc_skb(dev, length 
>> + dev->skb_align, gfp); if (NET_IP_ALIGN && skb && !(ev->driver_flags 
>> & FLAG_HW_IPALIGN)) skb_reserve(skb, NET_IP_ALIGN); It might even be 
>> reasonable to remove the length adjustment - provided that all the 
>> later code uses the skb length. David 

Thanks for your advice.
In the way you advised, does the dev->skb_align equal
to NET_IP_ALIGN in the case that HW doesn't supoort
IP alignment?
In other words, dev->skb_align should be initialized to
NET_IP_ALIGN in USBNET, and I can change its value to
0 in AX88179_178A driver, right?

     Freddy

--
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 Laight - Dec. 19, 2013, 10:01 a.m.
> From: Freddy Xin

> On 2013年12月16日 18:09, David Laight wrote:

> >> I was thinking of something like: skb = netdev_alloc_skb(dev, length

> >> + dev->skb_align, gfp); if (NET_IP_ALIGN && skb && !(ev->driver_flags

> >> & FLAG_HW_IPALIGN)) skb_reserve(skb, NET_IP_ALIGN); It might even be

> >> reasonable to remove the length adjustment - provided that all the

> >> later code uses the skb length. David

> 

> Thanks for your advice.

> In the way you advised, does the dev->skb_align equal

> to NET_IP_ALIGN in the case that HW doesn't supoort

> IP alignment?


Yes

> In other words, dev->skb_align should be initialized to

> NET_IP_ALIGN in USBNET, and I can change its value to

> 0 in AX88179_178A driver, right?


I'd probably set a flag to request that usbnet set the offset
to the correct value. That makes the initialisation a bit clearer.

	David

Patch

diff --git a/drivers/net/usb/ax88179_178a.c b/drivers/net/usb/ax88179_178a.c
index 8e8d0fc..04a2cc9 100644
--- a/drivers/net/usb/ax88179_178a.c
+++ b/drivers/net/usb/ax88179_178a.c
@@ -1374,7 +1374,7 @@  static const struct driver_info ax88179_info = {
 	.link_reset = ax88179_link_reset,
 	.reset = ax88179_reset,
 	.stop = ax88179_stop,
-	.flags = FLAG_ETHER | FLAG_FRAMING_AX,
+	.flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_HW_IPALIGN,
 	.rx_fixup = ax88179_rx_fixup,
 	.tx_fixup = ax88179_tx_fixup,
 };
@@ -1387,7 +1387,7 @@  static const struct driver_info ax88178a_info = {
 	.link_reset = ax88179_link_reset,
 	.reset = ax88179_reset,
 	.stop = ax88179_stop,
-	.flags = FLAG_ETHER | FLAG_FRAMING_AX,
+	.flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_HW_IPALIGN,
 	.rx_fixup = ax88179_rx_fixup,
 	.tx_fixup = ax88179_tx_fixup,
 };
@@ -1400,7 +1400,7 @@  static const struct driver_info sitecom_info = {
 	.link_reset = ax88179_link_reset,
 	.reset = ax88179_reset,
 	.stop = ax88179_stop,
-	.flags = FLAG_ETHER | FLAG_FRAMING_AX,
+	.flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_HW_IPALIGN,
 	.rx_fixup = ax88179_rx_fixup,
 	.tx_fixup = ax88179_tx_fixup,
 };
@@ -1413,7 +1413,7 @@  static const struct driver_info samsung_info = {
 	.link_reset = ax88179_link_reset,
 	.reset = ax88179_reset,
 	.stop = ax88179_stop,
-	.flags = FLAG_ETHER | FLAG_FRAMING_AX,
+	.flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_HW_IPALIGN,
 	.rx_fixup = ax88179_rx_fixup,
 	.tx_fixup = ax88179_tx_fixup,
 };
diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c
index 8494bb5..8a618b8 100644
--- a/drivers/net/usb/usbnet.c
+++ b/drivers/net/usb/usbnet.c
@@ -473,7 +473,10 @@  static int rx_submit (struct usbnet *dev, struct urb *urb, gfp_t flags)
 		return -ENOLINK;
 	}
 
-	skb = __netdev_alloc_skb_ip_align(dev->net, size, flags);
+	if (dev->driver_info->flags & FLAG_HW_IPALIGN)
+		skb = __netdev_alloc_skb(dev->net, size, flags);
+	else
+		skb = __netdev_alloc_skb_ip_align(dev->net, size, flags);
 	if (!skb) {
 		netif_dbg(dev, rx_err, dev->net, "no rx skb\n");
 		usbnet_defer_kevent (dev, EVENT_RX_MEMORY);
diff --git a/include/linux/usb/usbnet.h b/include/linux/usb/usbnet.h
index e303eef..e4855cf 100644
--- a/include/linux/usb/usbnet.h
+++ b/include/linux/usb/usbnet.h
@@ -116,6 +116,9 @@  struct driver_info {
 #define FLAG_MULTI_PACKET	0x2000
 #define FLAG_RX_ASSEMBLE	0x4000	/* rx packets may span >1 frames */
 #define FLAG_NOARP		0x8000	/* device can't do ARP */
+#define FLAG_HW_IPALIGN		0x10000 /* hardware adds headers to let the
+					 * IP header align on a dword-aligned
+					 * address */
 
 	/* init device ... can sleep, or cause probe() failure */
 	int	(*bind)(struct usbnet *, struct usb_interface *);