mirror of https://gitee.com/openkylin/linux.git
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>
This commit is contained in:
parent
c10650b661
commit
7cca336ae1
|
@ -44,9 +44,6 @@
|
||||||
|
|
||||||
#include "gianfar.h"
|
#include "gianfar.h"
|
||||||
|
|
||||||
extern int gfar_clean_rx_ring(struct gfar_priv_rx_q *rx_queue,
|
|
||||||
int rx_work_limit);
|
|
||||||
|
|
||||||
#define GFAR_MAX_COAL_USECS 0xffff
|
#define GFAR_MAX_COAL_USECS 0xffff
|
||||||
#define GFAR_MAX_COAL_FRAMES 0xff
|
#define GFAR_MAX_COAL_FRAMES 0xff
|
||||||
static void gfar_fill_stats(struct net_device *dev, struct ethtool_stats *dummy,
|
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,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Change the current ring parameters, stopping the controller if
|
/* Change the current ring parameters, stopping the controller if
|
||||||
* necessary so that we don't mess things up while we're in
|
* necessary so that we don't mess things up while we're in motion.
|
||||||
* motion. We wait for the ring to be clean before reallocating
|
|
||||||
* the rings.
|
|
||||||
*/
|
*/
|
||||||
static int gfar_sringparam(struct net_device *dev,
|
static int gfar_sringparam(struct net_device *dev,
|
||||||
struct ethtool_ringparam *rvals)
|
struct ethtool_ringparam *rvals)
|
||||||
{
|
{
|
||||||
struct gfar_private *priv = netdev_priv(dev);
|
struct gfar_private *priv = netdev_priv(dev);
|
||||||
int err = 0, i = 0;
|
int err = 0, i;
|
||||||
|
|
||||||
if (rvals->rx_pending > GFAR_RX_MAX_RING_SIZE)
|
if (rvals->rx_pending > GFAR_RX_MAX_RING_SIZE)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
@ -492,38 +487,15 @@ static int gfar_sringparam(struct net_device *dev,
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (dev->flags & IFF_UP)
|
||||||
if (dev->flags & IFF_UP) {
|
|
||||||
unsigned long flags;
|
|
||||||
|
|
||||||
/* Halt TX and RX, and process the frames which
|
|
||||||
* have already been received
|
|
||||||
*/
|
|
||||||
local_irq_save(flags);
|
|
||||||
lock_tx_qs(priv);
|
|
||||||
lock_rx_qs(priv);
|
|
||||||
|
|
||||||
gfar_halt(priv);
|
|
||||||
|
|
||||||
unlock_rx_qs(priv);
|
|
||||||
unlock_tx_qs(priv);
|
|
||||||
local_irq_restore(flags);
|
|
||||||
|
|
||||||
for (i = 0; i < priv->num_rx_queues; i++)
|
|
||||||
gfar_clean_rx_ring(priv->rx_queue[i],
|
|
||||||
priv->rx_queue[i]->rx_ring_size);
|
|
||||||
|
|
||||||
/* Now we take down the rings to rebuild them */
|
|
||||||
stop_gfar(dev);
|
stop_gfar(dev);
|
||||||
}
|
|
||||||
|
|
||||||
/* Change the size */
|
/* Change the sizes */
|
||||||
for (i = 0; i < priv->num_rx_queues; i++) {
|
for (i = 0; i < priv->num_rx_queues; i++)
|
||||||
priv->rx_queue[i]->rx_ring_size = rvals->rx_pending;
|
priv->rx_queue[i]->rx_ring_size = rvals->rx_pending;
|
||||||
|
|
||||||
|
for (i = 0; i < priv->num_tx_queues; i++)
|
||||||
priv->tx_queue[i]->tx_ring_size = rvals->tx_pending;
|
priv->tx_queue[i]->tx_ring_size = rvals->tx_pending;
|
||||||
priv->tx_queue[i]->num_txbdfree =
|
|
||||||
priv->tx_queue[i]->tx_ring_size;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Rebuild the rings with the new size */
|
/* Rebuild the rings with the new size */
|
||||||
if (dev->flags & IFF_UP) {
|
if (dev->flags & IFF_UP) {
|
||||||
|
@ -607,10 +579,8 @@ static int gfar_spauseparam(struct net_device *dev,
|
||||||
|
|
||||||
int gfar_set_features(struct net_device *dev, netdev_features_t features)
|
int gfar_set_features(struct net_device *dev, netdev_features_t features)
|
||||||
{
|
{
|
||||||
struct gfar_private *priv = netdev_priv(dev);
|
|
||||||
unsigned long flags;
|
|
||||||
int err = 0, i = 0;
|
|
||||||
netdev_features_t changed = dev->features ^ features;
|
netdev_features_t changed = dev->features ^ features;
|
||||||
|
int err = 0;
|
||||||
|
|
||||||
if (changed & (NETIF_F_HW_VLAN_CTAG_TX|NETIF_F_HW_VLAN_CTAG_RX))
|
if (changed & (NETIF_F_HW_VLAN_CTAG_TX|NETIF_F_HW_VLAN_CTAG_RX))
|
||||||
gfar_vlan_mode(dev, features);
|
gfar_vlan_mode(dev, features);
|
||||||
|
@ -619,23 +589,6 @@ int gfar_set_features(struct net_device *dev, netdev_features_t features)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (dev->flags & IFF_UP) {
|
if (dev->flags & IFF_UP) {
|
||||||
/* Halt TX and RX, and process the frames which
|
|
||||||
* have already been received
|
|
||||||
*/
|
|
||||||
local_irq_save(flags);
|
|
||||||
lock_tx_qs(priv);
|
|
||||||
lock_rx_qs(priv);
|
|
||||||
|
|
||||||
gfar_halt(priv);
|
|
||||||
|
|
||||||
unlock_tx_qs(priv);
|
|
||||||
unlock_rx_qs(priv);
|
|
||||||
local_irq_restore(flags);
|
|
||||||
|
|
||||||
for (i = 0; i < priv->num_rx_queues; i++)
|
|
||||||
gfar_clean_rx_ring(priv->rx_queue[i],
|
|
||||||
priv->rx_queue[i]->rx_ring_size);
|
|
||||||
|
|
||||||
/* Now we take down the rings to rebuild them */
|
/* Now we take down the rings to rebuild them */
|
||||||
stop_gfar(dev);
|
stop_gfar(dev);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue