diff options
author | Claudiu Manoil <claudiu.manoil@freescale.com> | 2014-02-17 05:53:19 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2014-02-18 15:03:02 -0500 |
commit | 7cca336ae1b27909526987e076388a388f668fe0 (patch) | |
tree | a92907a1923cdce54573d29abcab62c03d097c9a | |
parent | c10650b661b6c43c82c8e91b1d0b9b6adcf7f7dc (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.c | 63 |
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 | ||
47 | extern 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 |
52 | static void gfar_fill_stats(struct net_device *dev, struct ethtool_stats *dummy, | 49 | static 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 | */ |
473 | static int gfar_sringparam(struct net_device *dev, | 468 | static 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 | ||
608 | int gfar_set_features(struct net_device *dev, netdev_features_t features) | 580 | int 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 | ||