Skip to content

Commit 6c389fc

Browse files
zefir-kurtisidavem330
authored andcommitted
gianfar: fix size of scatter-gathered frames
The current scatter-gather logic in gianfar is flawed, since it does not consider the eTSEC's RxBD 'Data Length' field is context depening: for the last fragment it contains the full frame size, while fragments contain the fragment size, which equals the value written to register MRBLR. This causes data corruption as soon as the hardware starts to fragment receiving frames. As a result, the size of fragmented frames is increased by (nr_frags - 1) * MRBLR We first noticed this issue working with DSA, where an ICMP request sized 1472 bytes causes the scatter-gather logic to kick in. The full Ethernet frame (1518) gets increased by DSA (4), GMAC_FCB_LEN (8), and FSL_GIANFAR_DEV_HAS_TIMER (priv->padding=8) to a total of 1538 octets, which is fragmented by the hardware and reconstructed by the driver to a 3074 octet frame. This patch fixes the problem by adjusting the size of the last fragment. It was tested by setting MRBLR to different multiples of 64, proving correct scatter-gather operation on frames with up to 9000 octets in size. Signed-off-by: Zefir Kurtisi <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent b323431 commit 6c389fc

File tree

1 file changed

+14
-6
lines changed

1 file changed

+14
-6
lines changed

drivers/net/ethernet/freescale/gianfar.c

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2922,17 +2922,25 @@ static bool gfar_add_rx_frag(struct gfar_rx_buff *rxb, u32 lstatus,
29222922
{
29232923
unsigned int size = lstatus & BD_LENGTH_MASK;
29242924
struct page *page = rxb->page;
2925+
bool last = !!(lstatus & BD_LFLAG(RXBD_LAST));
29252926

29262927
/* Remove the FCS from the packet length */
2927-
if (likely(lstatus & BD_LFLAG(RXBD_LAST)))
2928+
if (last)
29282929
size -= ETH_FCS_LEN;
29292930

2930-
if (likely(first))
2931+
if (likely(first)) {
29312932
skb_put(skb, size);
2932-
else
2933-
skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags, page,
2934-
rxb->page_offset + RXBUF_ALIGNMENT,
2935-
size, GFAR_RXB_TRUESIZE);
2933+
} else {
2934+
/* the last fragments' length contains the full frame length */
2935+
if (last)
2936+
size -= skb->len;
2937+
2938+
/* in case the last fragment consisted only of the FCS */
2939+
if (size > 0)
2940+
skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags, page,
2941+
rxb->page_offset + RXBUF_ALIGNMENT,
2942+
size, GFAR_RXB_TRUESIZE);
2943+
}
29362944

29372945
/* try reuse page */
29382946
if (unlikely(page_count(page) != 1))

0 commit comments

Comments
 (0)