mlx4: Linearize large blocks to avoid dropping packets
authorBarret Rhoden <brho@cs.berkeley.edu>
Thu, 14 Dec 2017 21:23:59 +0000 (16:23 -0500)
committerBarret Rhoden <brho@cs.berkeley.edu>
Thu, 14 Dec 2017 21:23:59 +0000 (16:23 -0500)
On occasion I would get the "Oversized header or SG list" error.  It might
have been due to having too few TXBB slots for the number of fragments.

Our TCP stack doesn't limit the number of EBDs it sends down the pipe yet.
In lieu of breaking the block into multiple blocks, we can linearize it.  I
had the same issue with r8169.

The longer term fixes:
- Maybe a helper that breaks a block, but it'd need to maintain the
  headers, to include the length fields.
- Peak at the first block in the queue or otherwise block until there is
  enough room.  Need to be careful that we don't get a block that has more
EBDs than the NIC has SG slots.
- Give TCP (and other block producers) a way to know the max number of
  EBDs.
- Just use 16.

I somewhat like the notion of having a limit and then have the helper break
the block at the appropriate layer, since you might not know where a block
is going when you create it.  (Though TCP does - we do this with MSS
already).

Signed-off-by: Barret Rhoden <brho@cs.berkeley.edu>
kern/drivers/net/mlx4/en_tx.c

index ab51ae1..36db4ab 100644 (file)
@@ -1299,6 +1299,11 @@ void __mlx4_xmit_poke(void *args)
                block = qget(edev->oq);
                if (!block)
                        break;
+               /* This estimate might be off a little.  I think the driver is expecting
+                * 16 (Linux's MAX_SKB_FRAGS).  I base that in part on the comment in
+                * mlx4_en.h (grep "Typical TSO"). */
+               if (block->nr_extra_bufs > MAX_SKB_FRAGS)
+                       block = linearizeblock(block);
                mlx4_send_packet(block, priv, ring);
        }
 }