diff options
author | Claudiu Manoil <claudiu.manoil@freescale.com> | 2013-02-14 00:00:07 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2013-02-14 13:32:25 -0500 |
commit | ba7797119b486bb5992beda74bdb26be9a291b46 (patch) | |
tree | b694530d4f62a4e28d60313b57e1c98bfa24bf56 /drivers/net/ethernet/freescale | |
parent | 13f228da40cacdb3c4c23c8e1272c2ad37d1e4c0 (diff) |
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 <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.c | 41 | ||||
-rw-r--r-- | drivers/net/ethernet/freescale/gianfar.h | 1 |
2 files changed, 21 insertions, 21 deletions
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) | |||
344 | /* Configure the coalescing support */ | 344 | /* Configure the coalescing support */ |
345 | gfar_configure_coalescing(priv, 0xFF, 0xFF); | 345 | gfar_configure_coalescing(priv, 0xFF, 0xFF); |
346 | 346 | ||
347 | /* set this when rx hw offload (TOE) functions are being used */ | ||
348 | priv->uses_rxfcb = 0; | ||
349 | |||
347 | if (priv->rx_filer_enable) { | 350 | if (priv->rx_filer_enable) { |
348 | rctrl |= RCTRL_FILREN; | 351 | rctrl |= RCTRL_FILREN; |
349 | /* Program the RIR0 reg with the required distribution */ | 352 | /* Program the RIR0 reg with the required distribution */ |
@@ -354,8 +357,10 @@ static void gfar_init_mac(struct net_device *ndev) | |||
354 | if (ndev->flags & IFF_PROMISC) | 357 | if (ndev->flags & IFF_PROMISC) |
355 | rctrl |= RCTRL_PROM; | 358 | rctrl |= RCTRL_PROM; |
356 | 359 | ||
357 | if (ndev->features & NETIF_F_RXCSUM) | 360 | if (ndev->features & NETIF_F_RXCSUM) { |
358 | rctrl |= RCTRL_CHECKSUMMING; | 361 | rctrl |= RCTRL_CHECKSUMMING; |
362 | priv->uses_rxfcb = 1; | ||
363 | } | ||
359 | 364 | ||
360 | if (priv->extended_hash) { | 365 | if (priv->extended_hash) { |
361 | rctrl |= RCTRL_EXTHASH; | 366 | rctrl |= RCTRL_EXTHASH; |
@@ -377,11 +382,15 @@ static void gfar_init_mac(struct net_device *ndev) | |||
377 | } | 382 | } |
378 | 383 | ||
379 | /* Enable HW time stamping if requested from user space */ | 384 | /* Enable HW time stamping if requested from user space */ |
380 | if (priv->hwts_rx_en) | 385 | if (priv->hwts_rx_en) { |
381 | rctrl |= RCTRL_PRSDEP_INIT | RCTRL_TS_ENABLE; | 386 | rctrl |= RCTRL_PRSDEP_INIT | RCTRL_TS_ENABLE; |
387 | priv->uses_rxfcb = 1; | ||
388 | } | ||
382 | 389 | ||
383 | if (ndev->features & NETIF_F_HW_VLAN_RX) | 390 | if (ndev->features & NETIF_F_HW_VLAN_RX) { |
384 | rctrl |= RCTRL_VLEX | RCTRL_PRSDEP_INIT; | 391 | rctrl |= RCTRL_VLEX | RCTRL_PRSDEP_INIT; |
392 | priv->uses_rxfcb = 1; | ||
393 | } | ||
385 | 394 | ||
386 | /* Init rctrl based on our settings */ | 395 | /* Init rctrl based on our settings */ |
387 | gfar_write(®s->rctrl, rctrl); | 396 | gfar_write(®s->rctrl, rctrl); |
@@ -500,20 +509,6 @@ void unlock_tx_qs(struct gfar_private *priv) | |||
500 | spin_unlock(&priv->tx_queue[i]->txlock); | 509 | spin_unlock(&priv->tx_queue[i]->txlock); |
501 | } | 510 | } |
502 | 511 | ||
503 | static bool gfar_is_vlan_on(struct gfar_private *priv) | ||
504 | { | ||
505 | return (priv->ndev->features & NETIF_F_HW_VLAN_RX) || | ||
506 | (priv->ndev->features & NETIF_F_HW_VLAN_TX); | ||
507 | } | ||
508 | |||
509 | /* Returns 1 if incoming frames use an FCB */ | ||
510 | static inline int gfar_uses_fcb(struct gfar_private *priv) | ||
511 | { | ||
512 | return gfar_is_vlan_on(priv) || | ||
513 | (priv->ndev->features & NETIF_F_RXCSUM) || | ||
514 | (priv->device_flags & FSL_GIANFAR_DEV_HAS_TIMER); | ||
515 | } | ||
516 | |||
517 | static void free_tx_pointers(struct gfar_private *priv) | 512 | static void free_tx_pointers(struct gfar_private *priv) |
518 | { | 513 | { |
519 | int i; | 514 | int i; |
@@ -2326,10 +2321,13 @@ void gfar_check_rx_parser_mode(struct gfar_private *priv) | |||
2326 | 2321 | ||
2327 | tempval = gfar_read(®s->rctrl); | 2322 | tempval = gfar_read(®s->rctrl); |
2328 | /* If parse is no longer required, then disable parser */ | 2323 | /* If parse is no longer required, then disable parser */ |
2329 | if (tempval & RCTRL_REQ_PARSER) | 2324 | if (tempval & RCTRL_REQ_PARSER) { |
2330 | tempval |= RCTRL_PRSDEP_INIT; | 2325 | tempval |= RCTRL_PRSDEP_INIT; |
2331 | else | 2326 | priv->uses_rxfcb = 1; |
2327 | } else { | ||
2332 | tempval &= ~RCTRL_PRSDEP_INIT; | 2328 | tempval &= ~RCTRL_PRSDEP_INIT; |
2329 | priv->uses_rxfcb = 0; | ||
2330 | } | ||
2333 | gfar_write(®s->rctrl, tempval); | 2331 | gfar_write(®s->rctrl, tempval); |
2334 | } | 2332 | } |
2335 | 2333 | ||
@@ -2362,6 +2360,7 @@ void gfar_vlan_mode(struct net_device *dev, netdev_features_t features) | |||
2362 | tempval = gfar_read(®s->rctrl); | 2360 | tempval = gfar_read(®s->rctrl); |
2363 | tempval |= (RCTRL_VLEX | RCTRL_PRSDEP_INIT); | 2361 | tempval |= (RCTRL_VLEX | RCTRL_PRSDEP_INIT); |
2364 | gfar_write(®s->rctrl, tempval); | 2362 | gfar_write(®s->rctrl, tempval); |
2363 | priv->uses_rxfcb = 1; | ||
2365 | } else { | 2364 | } else { |
2366 | /* Disable VLAN tag extraction */ | 2365 | /* Disable VLAN tag extraction */ |
2367 | tempval = gfar_read(®s->rctrl); | 2366 | tempval = gfar_read(®s->rctrl); |
@@ -2390,7 +2389,7 @@ static int gfar_change_mtu(struct net_device *dev, int new_mtu) | |||
2390 | return -EINVAL; | 2389 | return -EINVAL; |
2391 | } | 2390 | } |
2392 | 2391 | ||
2393 | if (gfar_uses_fcb(priv)) | 2392 | if (priv->uses_rxfcb) |
2394 | frame_size += GMAC_FCB_LEN; | 2393 | frame_size += GMAC_FCB_LEN; |
2395 | 2394 | ||
2396 | frame_size += priv->padding; | 2395 | frame_size += priv->padding; |
@@ -2759,7 +2758,7 @@ int gfar_clean_rx_ring(struct gfar_priv_rx_q *rx_queue, int rx_work_limit) | |||
2759 | bdp = rx_queue->cur_rx; | 2758 | bdp = rx_queue->cur_rx; |
2760 | base = rx_queue->rx_bd_base; | 2759 | base = rx_queue->rx_bd_base; |
2761 | 2760 | ||
2762 | amount_pull = (gfar_uses_fcb(priv) ? GMAC_FCB_LEN : 0); | 2761 | amount_pull = priv->uses_rxfcb ? GMAC_FCB_LEN : 0; |
2763 | 2762 | ||
2764 | while (!((bdp->status & RXBD_EMPTY) || (--rx_work_limit < 0))) { | 2763 | while (!((bdp->status & RXBD_EMPTY) || (--rx_work_limit < 0))) { |
2765 | struct sk_buff *newskb; | 2764 | 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 { | |||
1056 | enum gfar_errata errata; | 1056 | enum gfar_errata errata; |
1057 | unsigned int rx_buffer_size; | 1057 | unsigned int rx_buffer_size; |
1058 | 1058 | ||
1059 | u16 uses_rxfcb; | ||
1059 | u16 padding; | 1060 | u16 padding; |
1060 | 1061 | ||
1061 | /* HW time stamping enabled flag */ | 1062 | /* HW time stamping enabled flag */ |