Re: [PATCH v3 2/2] net: asix: handle packets crossing URB boundaries

2013-01-18 Thread David Miller
From: Lucas Stach d...@lynxeye.de
Date: Wed, 16 Jan 2013 15:24:07 +0100

 ASIX AX88772B started to pack data even more tightly. Packets and the ASIX 
 packet
 header may now cross URB boundaries. To handle this we have to introduce
 some state between individual calls to asix_rx_fixup().
 
 Signed-off-by: Lucas Stach d...@lynxeye.de

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


[PATCH v3 2/2] net: asix: handle packets crossing URB boundaries

2013-01-16 Thread Lucas Stach
ASIX AX88772B started to pack data even more tightly. Packets and the ASIX 
packet
header may now cross URB boundaries. To handle this we have to introduce
some state between individual calls to asix_rx_fixup().

Signed-off-by: Lucas Stach d...@lynxeye.de
---
I've running this patch for some weeks already now and it gets rid of all
the commonly seen rx failures with AX88772B.

v2: don't forget to free driver_private
v3: don't break ax88172a. Generates a bit churn, but cleaner than the
alternative of playing pointer casting tricks.
---
 drivers/net/usb/asix.h | 15 ++-
 drivers/net/usb/asix_common.c  | 90 ++
 drivers/net/usb/asix_devices.c | 23 +--
 drivers/net/usb/ax88172a.c | 11 +-
 4 files changed, 109 insertions(+), 30 deletions(-)

diff --git a/drivers/net/usb/asix.h b/drivers/net/usb/asix.h
index 7afe8ac..346c032 100644
--- a/drivers/net/usb/asix.h
+++ b/drivers/net/usb/asix.h
@@ -167,6 +167,17 @@ struct asix_data {
u8 res;
 };
 
+struct asix_rx_fixup_info {
+   struct sk_buff *ax_skb;
+   u32 header;
+   u16 size;
+   bool split_head;
+};
+
+struct asix_common_private {
+   struct asix_rx_fixup_info rx_fixup_info;
+};
+
 /* ASIX specific flags */
 #define FLAG_EEPROM_MAC(1UL  0)  /* init device MAC from 
eeprom */
 
@@ -179,7 +190,9 @@ int asix_write_cmd(struct usbnet *dev, u8 cmd, u16 value, 
u16 index,
 void asix_write_cmd_async(struct usbnet *dev, u8 cmd, u16 value,
  u16 index, u16 size, void *data);
 
-int asix_rx_fixup(struct usbnet *dev, struct sk_buff *skb);
+int asix_rx_fixup_internal(struct usbnet *dev, struct sk_buff *skb,
+  struct asix_rx_fixup_info *rx);
+int asix_rx_fixup_common(struct usbnet *dev, struct sk_buff *skb);
 
 struct sk_buff *asix_tx_fixup(struct usbnet *dev, struct sk_buff *skb,
  gfp_t flags);
diff --git a/drivers/net/usb/asix_common.c b/drivers/net/usb/asix_common.c
index 50d1673..15450dc 100644
--- a/drivers/net/usb/asix_common.c
+++ b/drivers/net/usb/asix_common.c
@@ -51,49 +51,89 @@ void asix_write_cmd_async(struct usbnet *dev, u8 cmd, u16 
value, u16 index,
   value, index, data, size);
 }
 
-int asix_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
+int asix_rx_fixup_internal(struct usbnet *dev, struct sk_buff *skb,
+  struct asix_rx_fixup_info *rx)
 {
int offset = 0;
 
-   while (offset + sizeof(u32)  skb-len) {
-   struct sk_buff *ax_skb;
-   u16 size;
-   u32 header = get_unaligned_le32(skb-data + offset);
-
-   offset += sizeof(u32);
-
-   /* get the packet length */
-   size = (u16) (header  0x7ff);
-   if (size != ((~header  16)  0x07ff)) {
-   netdev_err(dev-net, asix_rx_fixup() Bad Header 
Length\n);
-   return 0;
+   while (offset + sizeof(u16) = skb-len) {
+   u16 remaining = 0;
+   unsigned char *data;
+
+   if (!rx-size) {
+   if ((skb-len - offset == sizeof(u16)) ||
+   rx-split_head) {
+   if(!rx-split_head) {
+   rx-header = get_unaligned_le16(
+   skb-data + offset);
+   rx-split_head = true;
+   offset += sizeof(u16);
+   break;
+   } else {
+   rx-header |= (get_unaligned_le16(
+   skb-data + offset)
+16);
+   rx-split_head = false;
+   offset += sizeof(u16);
+   }
+   } else {
+   rx-header = get_unaligned_le32(skb-data +
+   offset);
+   offset += sizeof(u32);
+   }
+
+   /* get the packet length */
+   rx-size = (u16) (rx-header  0x7ff);
+   if (rx-size != ((~rx-header  16)  0x7ff)) {
+   netdev_err(dev-net, asix_rx_fixup() Bad 
Header Length 0x%x, offset %d\n,
+  rx-header, offset);
+   rx-size = 0;
+   return 0;
+   }
+   rx-ax_skb = netdev_alloc_skb_ip_align(dev-net,
+  rx-size);
+   if (!rx-ax_skb)
+   return 0;