From: Claudiu Manoil Date: Thu, 14 Feb 2013 05:00:07 +0000 (+0000) Subject: gianfar: Fix and cleanup Rx FCB indication X-Git-Url: http://git.lede-project.org./?a=commitdiff_plain;h=ba7797119b486bb5992beda74bdb26be9a291b46;p=openwrt%2Fstaging%2Fblogic.git gianfar: Fix and cleanup Rx FCB indication This fixes a less obvious error on one hand, and prevents futher similar errors by disambiguating and optimizing RxFCB indication, on the other hand. The error consists in NETIF_F_HW_VLAN_TX flag being used as an indication of Rx FCB insertion. This happened as soon gfar_uses_fcb(), which despite its name indicates Rx FCB insertion, started incorporating is_vlan_on(). is_vlan_on(), on the other hand, is also a misleading construct because we need to differentiate b/w hw VLAN extraction/VLEX (marked by VLAN_RX flag) and hw VLAN insertion/VLINS (VLAN_TX flag), which are different mechanisms using different types of FCBs. The hw spec for the RxFCB feature is as follows: In the case of RxBD rings, FCBs (Frame Control Block) are inserted by the eTSEC whenever RCTRL[PRSDEP] is set to a non-zero value. Only one FCB is inserted per frame (in the buffer pointed to by the RxBD with bit F set). TOE acceleration for receive is enabled for all rx frames in this case. This patch introduces priv->uses_rxfcb field to quickly signal RxFCB insertion in accordance with the specification above. The dependency on FSL_GIANFAR_DEV_HAS_TIMER was also eliminated as another source of confusion. The actual dependency is to priv->hwts_rx_en. Upon changing priv->hwts_rx_en via IOCTL, the gfar device is being restarted and on init_mac() the priv->hwts_rx_en flag determines RxFCB insertion, and rctrl is programmed accordingly. The patch takes care of this case too. Though maybe not as self documenting as the inlining version uses_fcb(), priv->uses_rxfcb has the main purpose to quickly signal, on the hot path, that the incoming frame has a *Rx* FCB block inserted which needs to be pulled out before passing the skb to the stack. This is a performance critical operation, it needs to happen fast, that's why uses_rxfcb is placed in the first cacheline of gfar_private. This is also why a cached rctrl cannot be used instead: 1) because we don't have 32 bits available in the first cacheline of gfar_priv (but only 16); 2) bit operations are expensive on the hot path. Signed-off-by: Claudiu Manoil Signed-off-by: David S. Miller --- diff --git a/drivers/net/ethernet/freescale/gianfar.c b/drivers/net/ethernet/freescale/gianfar.c index b2c60772bd96..4b5e8a692481 100644 --- a/drivers/net/ethernet/freescale/gianfar.c +++ b/drivers/net/ethernet/freescale/gianfar.c @@ -344,6 +344,9 @@ static void gfar_init_mac(struct net_device *ndev) /* Configure the coalescing support */ gfar_configure_coalescing(priv, 0xFF, 0xFF); + /* set this when rx hw offload (TOE) functions are being used */ + priv->uses_rxfcb = 0; + if (priv->rx_filer_enable) { rctrl |= RCTRL_FILREN; /* Program the RIR0 reg with the required distribution */ @@ -354,8 +357,10 @@ static void gfar_init_mac(struct net_device *ndev) if (ndev->flags & IFF_PROMISC) rctrl |= RCTRL_PROM; - if (ndev->features & NETIF_F_RXCSUM) + if (ndev->features & NETIF_F_RXCSUM) { rctrl |= RCTRL_CHECKSUMMING; + priv->uses_rxfcb = 1; + } if (priv->extended_hash) { rctrl |= RCTRL_EXTHASH; @@ -377,11 +382,15 @@ static void gfar_init_mac(struct net_device *ndev) } /* Enable HW time stamping if requested from user space */ - if (priv->hwts_rx_en) + if (priv->hwts_rx_en) { rctrl |= RCTRL_PRSDEP_INIT | RCTRL_TS_ENABLE; + priv->uses_rxfcb = 1; + } - if (ndev->features & NETIF_F_HW_VLAN_RX) + if (ndev->features & NETIF_F_HW_VLAN_RX) { rctrl |= RCTRL_VLEX | RCTRL_PRSDEP_INIT; + priv->uses_rxfcb = 1; + } /* Init rctrl based on our settings */ gfar_write(®s->rctrl, rctrl); @@ -500,20 +509,6 @@ void unlock_tx_qs(struct gfar_private *priv) spin_unlock(&priv->tx_queue[i]->txlock); } -static bool gfar_is_vlan_on(struct gfar_private *priv) -{ - return (priv->ndev->features & NETIF_F_HW_VLAN_RX) || - (priv->ndev->features & NETIF_F_HW_VLAN_TX); -} - -/* Returns 1 if incoming frames use an FCB */ -static inline int gfar_uses_fcb(struct gfar_private *priv) -{ - return gfar_is_vlan_on(priv) || - (priv->ndev->features & NETIF_F_RXCSUM) || - (priv->device_flags & FSL_GIANFAR_DEV_HAS_TIMER); -} - static void free_tx_pointers(struct gfar_private *priv) { int i; @@ -2326,10 +2321,13 @@ void gfar_check_rx_parser_mode(struct gfar_private *priv) tempval = gfar_read(®s->rctrl); /* If parse is no longer required, then disable parser */ - if (tempval & RCTRL_REQ_PARSER) + if (tempval & RCTRL_REQ_PARSER) { tempval |= RCTRL_PRSDEP_INIT; - else + priv->uses_rxfcb = 1; + } else { tempval &= ~RCTRL_PRSDEP_INIT; + priv->uses_rxfcb = 0; + } gfar_write(®s->rctrl, tempval); } @@ -2362,6 +2360,7 @@ void gfar_vlan_mode(struct net_device *dev, netdev_features_t features) tempval = gfar_read(®s->rctrl); tempval |= (RCTRL_VLEX | RCTRL_PRSDEP_INIT); gfar_write(®s->rctrl, tempval); + priv->uses_rxfcb = 1; } else { /* Disable VLAN tag extraction */ tempval = gfar_read(®s->rctrl); @@ -2390,7 +2389,7 @@ static int gfar_change_mtu(struct net_device *dev, int new_mtu) return -EINVAL; } - if (gfar_uses_fcb(priv)) + if (priv->uses_rxfcb) frame_size += GMAC_FCB_LEN; frame_size += priv->padding; @@ -2759,7 +2758,7 @@ int gfar_clean_rx_ring(struct gfar_priv_rx_q *rx_queue, int rx_work_limit) bdp = rx_queue->cur_rx; base = rx_queue->rx_bd_base; - amount_pull = (gfar_uses_fcb(priv) ? GMAC_FCB_LEN : 0); + amount_pull = priv->uses_rxfcb ? GMAC_FCB_LEN : 0; while (!((bdp->status & RXBD_EMPTY) || (--rx_work_limit < 0))) { struct sk_buff *newskb; diff --git a/drivers/net/ethernet/freescale/gianfar.h b/drivers/net/ethernet/freescale/gianfar.h index 1e2ce8bfea83..63a28d294e20 100644 --- a/drivers/net/ethernet/freescale/gianfar.h +++ b/drivers/net/ethernet/freescale/gianfar.h @@ -1056,6 +1056,7 @@ struct gfar_private { enum gfar_errata errata; unsigned int rx_buffer_size; + u16 uses_rxfcb; u16 padding; /* HW time stamping enabled flag */