aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/ethernet/freescale
diff options
context:
space:
mode:
authorClaudiu Manoil <claudiu.manoil@freescale.com>2013-08-05 10:20:09 -0400
committerDavid S. Miller <davem@davemloft.net>2013-08-05 15:29:15 -0400
commit02d88fb4fb6a580b0224b3bf07bbfd9d4806f6fb (patch)
tree671f9df5f8e59adcc3f6f2944e0b9f63501b885e /drivers/net/ethernet/freescale
parent7864a1adf7291993d74923fdd0a45459ce9da27e (diff)
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: Claudiu Manoil <claudiu.manoil@freescale.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/ethernet/freescale')
-rw-r--r--drivers/net/ethernet/freescale/gianfar.c44
1 files changed, 25 insertions, 19 deletions
diff --git a/drivers/net/ethernet/freescale/gianfar.c b/drivers/net/ethernet/freescale/gianfar.c
index dbb34f7ce448..352035e440d8 100644
--- a/drivers/net/ethernet/freescale/gianfar.c
+++ b/drivers/net/ethernet/freescale/gianfar.c
@@ -2051,6 +2051,24 @@ static inline struct txbd8 *next_txbd(struct txbd8 *bdp, struct txbd8 *base,
2051 return skip_txbd(bdp, 1, base, ring_size); 2051 return skip_txbd(bdp, 1, base, ring_size);
2052} 2052}
2053 2053
2054/* eTSEC12: csum generation not supported for some fcb offsets */
2055static inline bool gfar_csum_errata_12(struct gfar_private *priv,
2056 unsigned long fcb_addr)
2057{
2058 return (gfar_has_errata(priv, GFAR_ERRATA_12) &&
2059 (fcb_addr % 0x20) > 0x18);
2060}
2061
2062/* eTSEC76: csum generation for frames larger than 2500 may
2063 * cause excess delays before start of transmission
2064 */
2065static inline bool gfar_csum_errata_76(struct gfar_private *priv,
2066 unsigned int len)
2067{
2068 return (gfar_has_errata(priv, GFAR_ERRATA_76) &&
2069 (len > 2500));
2070}
2071
2054/* This is called by the kernel when a frame is ready for transmission. 2072/* This is called by the kernel when a frame is ready for transmission.
2055 * It is pointed to by the dev->hard_start_xmit function pointer 2073 * It is pointed to by the dev->hard_start_xmit function pointer
2056 */ 2074 */
@@ -2068,19 +2086,6 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev)
2068 unsigned long flags; 2086 unsigned long flags;
2069 unsigned int nr_frags, nr_txbds, length, fcb_length = GMAC_FCB_LEN; 2087 unsigned int nr_frags, nr_txbds, length, fcb_length = GMAC_FCB_LEN;
2070 2088
2071 /* TOE=1 frames larger than 2500 bytes may see excess delays
2072 * before start of transmission.
2073 */
2074 if (unlikely(gfar_has_errata(priv, GFAR_ERRATA_76) &&
2075 skb->ip_summed == CHECKSUM_PARTIAL &&
2076 skb->len > 2500)) {
2077 int ret;
2078
2079 ret = skb_checksum_help(skb);
2080 if (ret)
2081 return ret;
2082 }
2083
2084 rq = skb->queue_mapping; 2089 rq = skb->queue_mapping;
2085 tx_queue = priv->tx_queue[rq]; 2090 tx_queue = priv->tx_queue[rq];
2086 txq = netdev_get_tx_queue(dev, rq); 2091 txq = netdev_get_tx_queue(dev, rq);
@@ -2187,14 +2192,15 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev)
2187 /* Set up checksumming */ 2192 /* Set up checksumming */
2188 if (CHECKSUM_PARTIAL == skb->ip_summed) { 2193 if (CHECKSUM_PARTIAL == skb->ip_summed) {
2189 fcb = gfar_add_fcb(skb); 2194 fcb = gfar_add_fcb(skb);
2190 /* as specified by errata */ 2195 lstatus |= BD_LFLAG(TXBD_TOE);
2191 if (unlikely(gfar_has_errata(priv, GFAR_ERRATA_12) && 2196 gfar_tx_checksum(skb, fcb, fcb_length);
2192 ((unsigned long)fcb % 0x20) > 0x18)) { 2197
2198 if (unlikely(gfar_csum_errata_12(priv, (unsigned long)fcb)) ||
2199 unlikely(gfar_csum_errata_76(priv, skb->len))) {
2193 __skb_pull(skb, GMAC_FCB_LEN); 2200 __skb_pull(skb, GMAC_FCB_LEN);
2194 skb_checksum_help(skb); 2201 skb_checksum_help(skb);
2195 } else { 2202 lstatus &= ~(BD_LFLAG(TXBD_TOE));
2196 lstatus |= BD_LFLAG(TXBD_TOE); 2203 fcb = NULL;
2197 gfar_tx_checksum(skb, fcb, fcb_length);
2198 } 2204 }
2199 } 2205 }
2200 2206