Commit 02d88fb4 authored by Claudiu Manoil's avatar Claudiu Manoil Committed by David S. Miller
Browse files

gianfar: Fix Tx csum generation errata handling

Both [eTSEC76] and [eTSEC12] errata relate to Tx checksum generation
(for some MPC83xx and MCP8548 older revisions). They require the same
workaround: manual checksum computation and insertion, and disabling
the H/W Tx csum acceleration feature (per frame) through Tx FCB
(Frame Control Block) csum offload settings.

The workaround for [eTSEC76] needs to be fixed because it currently
fails to disable H/W Tx csum insertion via FCB. This patch fixes it
and provides a common workaround implementation for both Tx csum errata.
Signed-off-by: default avatarClaudiu Manoil <>
Signed-off-by: default avatarDavid S. Miller <>
parent 7864a1ad
......@@ -2051,6 +2051,24 @@ static inline struct txbd8 *next_txbd(struct txbd8 *bdp, struct txbd8 *base,
return skip_txbd(bdp, 1, base, ring_size);
/* eTSEC12: csum generation not supported for some fcb offsets */
static inline bool gfar_csum_errata_12(struct gfar_private *priv,
unsigned long fcb_addr)
return (gfar_has_errata(priv, GFAR_ERRATA_12) &&
(fcb_addr % 0x20) > 0x18);
/* eTSEC76: csum generation for frames larger than 2500 may
* cause excess delays before start of transmission
static inline bool gfar_csum_errata_76(struct gfar_private *priv,
unsigned int len)
return (gfar_has_errata(priv, GFAR_ERRATA_76) &&
(len > 2500));
/* This is called by the kernel when a frame is ready for transmission.
* It is pointed to by the dev->hard_start_xmit function pointer
......@@ -2068,19 +2086,6 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev)
unsigned long flags;
unsigned int nr_frags, nr_txbds, length, fcb_length = GMAC_FCB_LEN;
/* TOE=1 frames larger than 2500 bytes may see excess delays
* before start of transmission.
if (unlikely(gfar_has_errata(priv, GFAR_ERRATA_76) &&
skb->ip_summed == CHECKSUM_PARTIAL &&
skb->len > 2500)) {
int ret;
ret = skb_checksum_help(skb);
if (ret)
return ret;
rq = skb->queue_mapping;
tx_queue = priv->tx_queue[rq];
txq = netdev_get_tx_queue(dev, rq);
......@@ -2187,14 +2192,15 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev)
/* Set up checksumming */
if (CHECKSUM_PARTIAL == skb->ip_summed) {
fcb = gfar_add_fcb(skb);
/* as specified by errata */
if (unlikely(gfar_has_errata(priv, GFAR_ERRATA_12) &&
((unsigned long)fcb % 0x20) > 0x18)) {
__skb_pull(skb, GMAC_FCB_LEN);
} else {
lstatus |= BD_LFLAG(TXBD_TOE);
gfar_tx_checksum(skb, fcb, fcb_length);
if (unlikely(gfar_csum_errata_12(priv, (unsigned long)fcb)) ||
unlikely(gfar_csum_errata_76(priv, skb->len))) {
__skb_pull(skb, GMAC_FCB_LEN);
lstatus &= ~(BD_LFLAG(TXBD_TOE));
fcb = NULL;
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment