aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/usb/asix.c
diff options
context:
space:
mode:
authorEric Dumazet <eric.dumazet@gmail.com>2012-03-14 16:18:32 -0400
committerDavid S. Miller <davem@davemloft.net>2012-03-16 04:52:13 -0400
commita9e0aca4b37885b5599e52211f098bd7f565e749 (patch)
tree7f4edd4ed8a96bfccca216ef4ce84d29d6049f9d /drivers/net/usb/asix.c
parent1174764e810998e81b334b5ccdfad8a9d059c6a1 (diff)
asix: asix_rx_fixup surgery to reduce skb truesizes
asix_rx_fixup() is complex, and does some unnecessary memory copies (at least on x86 where NET_IP_ALIGN is 0) Also, it tends to provide skbs with a big truesize (4096+256 with MTU=1500) to upper stack, so incoming trafic consume a lot of memory and I noticed early packet drops because we hit socket rcvbuf too fast. Switch to a different strategy, using copybreak so that we provide nice skbs to upper stack (including the NET_SKB_PAD to avoid future head reallocations in some paths) With this patch, I no longer see packets drops or tcp collapses on various tcp workload with a AX88772 adapter. Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com> Cc: Aurelien Jacobs <aurel@gnuage.org> Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Cc: Trond Wuellner <trond@chromium.org> Cc: Grant Grundler <grundler@chromium.org> Cc: Paul Stewart <pstew@chromium.org> Reviewed-by: Grant Grundler <grundler@chromium.org> Reviewed-by: Grant Grundler <grundler@chromium.org> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/usb/asix.c')
-rw-r--r--drivers/net/usb/asix.c88
1 files changed, 20 insertions, 68 deletions
diff --git a/drivers/net/usb/asix.c b/drivers/net/usb/asix.c
index 8e84f5bdd6ca..25fe1838d886 100644
--- a/drivers/net/usb/asix.c
+++ b/drivers/net/usb/asix.c
@@ -305,88 +305,40 @@ asix_write_cmd_async(struct usbnet *dev, u8 cmd, u16 value, u16 index,
305 305
306static int asix_rx_fixup(struct usbnet *dev, struct sk_buff *skb) 306static int asix_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
307{ 307{
308 u8 *head; 308 int offset = 0;
309 u32 header;
310 char *packet;
311 struct sk_buff *ax_skb;
312 u16 size;
313 309
314 head = (u8 *) skb->data; 310 while (offset + sizeof(u32) < skb->len) {
315 memcpy(&header, head, sizeof(header)); 311 struct sk_buff *ax_skb;
316 le32_to_cpus(&header); 312 u16 size;
317 packet = head + sizeof(header); 313 u32 header = get_unaligned_le32(skb->data + offset);
318 314
319 skb_pull(skb, 4); 315 offset += sizeof(u32);
320
321 while (skb->len > 0) {
322 if ((header & 0x07ff) != ((~header >> 16) & 0x07ff))
323 netdev_err(dev->net, "asix_rx_fixup() Bad Header Length\n");
324 316
325 /* get the packet length */ 317 /* get the packet length */
326 size = (u16) (header & 0x000007ff); 318 size = (u16) (header & 0x7ff);
327 319 if (size != ((~header >> 16) & 0x07ff)) {
328 if ((skb->len) - ((size + 1) & 0xfffe) == 0) { 320 netdev_err(dev->net, "asix_rx_fixup() Bad Header Length\n");
329 u8 alignment = (unsigned long)skb->data & 0x3; 321 return 0;
330 if (alignment != 0x2) {
331 /*
332 * not 16bit aligned so use the room provided by
333 * the 32 bit header to align the data
334 *
335 * note we want 16bit alignment as MAC header is
336 * 14bytes thus ip header will be aligned on
337 * 32bit boundary so accessing ipheader elements
338 * using a cast to struct ip header wont cause
339 * an unaligned accesses.
340 */
341 u8 realignment = (alignment + 2) & 0x3;
342 memmove(skb->data - realignment,
343 skb->data,
344 size);
345 skb->data -= realignment;
346 skb_set_tail_pointer(skb, size);
347 }
348 return 2;
349 } 322 }
350 323
351 if (size > dev->net->mtu + ETH_HLEN) { 324 if ((size > dev->net->mtu + ETH_HLEN) ||
325 (size + offset > skb->len)) {
352 netdev_err(dev->net, "asix_rx_fixup() Bad RX Length %d\n", 326 netdev_err(dev->net, "asix_rx_fixup() Bad RX Length %d\n",
353 size); 327 size);
354 return 0; 328 return 0;
355 } 329 }
356 ax_skb = skb_clone(skb, GFP_ATOMIC); 330 ax_skb = netdev_alloc_skb_ip_align(dev->net, size);
357 if (ax_skb) { 331 if (!ax_skb)
358 u8 alignment = (unsigned long)packet & 0x3;
359 ax_skb->len = size;
360
361 if (alignment != 0x2) {
362 /*
363 * not 16bit aligned use the room provided by
364 * the 32 bit header to align the data
365 */
366 u8 realignment = (alignment + 2) & 0x3;
367 memmove(packet - realignment, packet, size);
368 packet -= realignment;
369 }
370 ax_skb->data = packet;
371 skb_set_tail_pointer(ax_skb, size);
372 usbnet_skb_return(dev, ax_skb);
373 } else {
374 return 0; 332 return 0;
375 }
376
377 skb_pull(skb, (size + 1) & 0xfffe);
378 333
379 if (skb->len < sizeof(header)) 334 skb_put(ax_skb, size);
380 break; 335 memcpy(ax_skb->data, skb->data + offset, size);
336 usbnet_skb_return(dev, ax_skb);
381 337
382 head = (u8 *) skb->data; 338 offset += (size + 1) & 0xfffe;
383 memcpy(&header, head, sizeof(header));
384 le32_to_cpus(&header);
385 packet = head + sizeof(header);
386 skb_pull(skb, 4);
387 } 339 }
388 340
389 if (skb->len < 0) { 341 if (skb->len != offset) {
390 netdev_err(dev->net, "asix_rx_fixup() Bad SKB Length %d\n", 342 netdev_err(dev->net, "asix_rx_fixup() Bad SKB Length %d\n",
391 skb->len); 343 skb->len);
392 return 0; 344 return 0;
@@ -1541,7 +1493,7 @@ static const struct driver_info ax88772_info = {
1541 .status = asix_status, 1493 .status = asix_status,
1542 .link_reset = ax88772_link_reset, 1494 .link_reset = ax88772_link_reset,
1543 .reset = ax88772_reset, 1495 .reset = ax88772_reset,
1544 .flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_LINK_INTR, 1496 .flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_LINK_INTR | FLAG_MULTI_PACKET,
1545 .rx_fixup = asix_rx_fixup, 1497 .rx_fixup = asix_rx_fixup,
1546 .tx_fixup = asix_tx_fixup, 1498 .tx_fixup = asix_tx_fixup,
1547}; 1499};