mlx4: Linearize large blocks to avoid dropping packets 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>
diff --git a/kern/drivers/net/mlx4/en_tx.c b/kern/drivers/net/mlx4/en_tx.c index ab51ae1..36db4ab 100644 --- a/kern/drivers/net/mlx4/en_tx.c +++ b/kern/drivers/net/mlx4/en_tx.c
@@ -1299,6 +1299,11 @@ 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); } }