aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorClaudiu Manoil <claudiu.manoil@freescale.com>2014-02-17 05:53:19 -0500
committerDavid S. Miller <davem@davemloft.net>2014-02-18 15:03:02 -0500
commit7cca336ae1b27909526987e076388a388f668fe0 (patch)
treea92907a1923cdce54573d29abcab62c03d097c9a
parentc10650b661b6c43c82c8e91b1d0b9b6adcf7f7dc (diff)
gianfar: Remove clean_rx_ring race from gfar_ethtool
gfar_clean_rx_ring() was designed to be called from napi (rx softirq) context to do the Rx processing. Calling it from a process context like this is a bug as it will clearly race with the napi Rx processing. There's also no point in initializing num_txbdfree since startup_gfar() already does that, when bringing the device up again (after reset). Changing num_txbdfree "on-the-fly" like this is also subject to race conditions. num_txbdfree is handled by the Tx processing path and the device reset procedure. Also, don't assume that num_rx_queues is always equal to num_tx_queues. Signed-off-by: Claudiu Manoil <claudiu.manoil@freescale.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/ethernet/freescale/gianfar_ethtool.c63
1 files changed, 8 insertions, 55 deletions
diff --git a/drivers/net/ethernet/freescale/gianfar_ethtool.c b/drivers/net/ethernet/freescale/gianfar_ethtool.c
index 69fab72b8a8d..19557ec31f33 100644
--- a/drivers/net/ethernet/freescale/gianfar_ethtool.c
+++ b/drivers/net/ethernet/freescale/gianfar_ethtool.c
@@ -44,9 +44,6 @@
44 44
45#include "gianfar.h" 45#include "gianfar.h"
46 46
47extern int gfar_clean_rx_ring(struct gfar_priv_rx_q *rx_queue,
48 int rx_work_limit);
49
50#define GFAR_MAX_COAL_USECS 0xffff 47#define GFAR_MAX_COAL_USECS 0xffff
51#define GFAR_MAX_COAL_FRAMES 0xff 48#define GFAR_MAX_COAL_FRAMES 0xff
52static void gfar_fill_stats(struct net_device *dev, struct ethtool_stats *dummy, 49static void gfar_fill_stats(struct net_device *dev, struct ethtool_stats *dummy,
@@ -466,15 +463,13 @@ static void gfar_gringparam(struct net_device *dev,
466} 463}
467 464
468/* Change the current ring parameters, stopping the controller if 465/* Change the current ring parameters, stopping the controller if
469 * necessary so that we don't mess things up while we're in 466 * necessary so that we don't mess things up while we're in motion.
470 * motion. We wait for the ring to be clean before reallocating
471 * the rings.
472 */ 467 */
473static int gfar_sringparam(struct net_device *dev, 468static int gfar_sringparam(struct net_device *dev,
474 struct ethtool_ringparam *rvals) 469 struct ethtool_ringparam *rvals)
475{ 470{
476 struct gfar_private *priv = netdev_priv(dev); 471 struct gfar_private *priv = netdev_priv(dev);
477 int err = 0, i = 0; 472 int err = 0, i;
478 473
479 if (rvals->rx_pending > GFAR_RX_MAX_RING_SIZE) 474 if (rvals->rx_pending > GFAR_RX_MAX_RING_SIZE)
480 return -EINVAL; 475 return -EINVAL;
@@ -492,38 +487,15 @@ static int gfar_sringparam(struct net_device *dev,
492 return -EINVAL; 487 return -EINVAL;
493 } 488 }
494 489
495 490 if (dev->flags & IFF_UP)
496 if (dev->flags & IFF_UP) {
497 unsigned long flags;
498
499 /* Halt TX and RX, and process the frames which
500 * have already been received
501 */
502 local_irq_save(flags);
503 lock_tx_qs(priv);
504 lock_rx_qs(priv);
505
506 gfar_halt(priv);
507
508 unlock_rx_qs(priv);
509 unlock_tx_qs(priv);
510 local_irq_restore(flags);
511
512 for (i = 0; i < priv->num_rx_queues; i++)
513 gfar_clean_rx_ring(priv->rx_queue[i],
514 priv->rx_queue[i]->rx_ring_size);
515
516 /* Now we take down the rings to rebuild them */
517 stop_gfar(dev); 491 stop_gfar(dev);
518 }
519 492
520 /* Change the size */ 493 /* Change the sizes */
521 for (i = 0; i < priv->num_rx_queues; i++) { 494 for (i = 0; i < priv->num_rx_queues; i++)
522 priv->rx_queue[i]->rx_ring_size = rvals->rx_pending; 495 priv->rx_queue[i]->rx_ring_size = rvals->rx_pending;
496
497 for (i = 0; i < priv->num_tx_queues; i++)
523 priv->tx_queue[i]->tx_ring_size = rvals->tx_pending; 498 priv->tx_queue[i]->tx_ring_size = rvals->tx_pending;
524 priv->tx_queue[i]->num_txbdfree =
525 priv->tx_queue[i]->tx_ring_size;
526 }
527 499
528 /* Rebuild the rings with the new size */ 500 /* Rebuild the rings with the new size */
529 if (dev->flags & IFF_UP) { 501 if (dev->flags & IFF_UP) {
@@ -607,10 +579,8 @@ static int gfar_spauseparam(struct net_device *dev,
607 579
608int gfar_set_features(struct net_device *dev, netdev_features_t features) 580int gfar_set_features(struct net_device *dev, netdev_features_t features)
609{ 581{
610 struct gfar_private *priv = netdev_priv(dev);
611 unsigned long flags;
612 int err = 0, i = 0;
613 netdev_features_t changed = dev->features ^ features; 582 netdev_features_t changed = dev->features ^ features;
583 int err = 0;
614 584
615 if (changed & (NETIF_F_HW_VLAN_CTAG_TX|NETIF_F_HW_VLAN_CTAG_RX)) 585 if (changed & (NETIF_F_HW_VLAN_CTAG_TX|NETIF_F_HW_VLAN_CTAG_RX))
616 gfar_vlan_mode(dev, features); 586 gfar_vlan_mode(dev, features);
@@ -619,23 +589,6 @@ int gfar_set_features(struct net_device *dev, netdev_features_t features)
619 return 0; 589 return 0;
620 590
621 if (dev->flags & IFF_UP) { 591 if (dev->flags & IFF_UP) {
622 /* Halt TX and RX, and process the frames which
623 * have already been received
624 */
625 local_irq_save(flags);
626 lock_tx_qs(priv);
627 lock_rx_qs(priv);
628
629 gfar_halt(priv);
630
631 unlock_tx_qs(priv);
632 unlock_rx_qs(priv);
633 local_irq_restore(flags);
634
635 for (i = 0; i < priv->num_rx_queues; i++)
636 gfar_clean_rx_ring(priv->rx_queue[i],
637 priv->rx_queue[i]->rx_ring_size);
638
639 /* Now we take down the rings to rebuild them */ 592 /* Now we take down the rings to rebuild them */
640 stop_gfar(dev); 593 stop_gfar(dev);
641 594