[PATCH] Fix locking in gianfar

This patch fixes several bugs in the gianfar driver, including a major one
where spinlocks were horribly broken:

* Split gianfar locks into two types: TX and RX
* Made it so gfar_start() now clears RHALT
* Fixed a bug where calling gfar_start_xmit() with interrupts off would
corrupt the interrupt state
* Fixed a bug where a frame could potentially arrive, and never be handled
(if no more frames arrived
* Fixed a bug where the rx_work_limit would never be observed by the rx
completion code
* Fixed a bug where the interrupt handlers were not actually protected by
their spinlocks

Signed-off-by: Andy Fleming <afleming@freescale.com>
Signed-off-by: Jeff Garzik <jeff@garzik.org>
This commit is contained in:
Andy Fleming
2006-04-20 16:44:29 -05:00
committed by Jeff Garzik
parent f18b95c3e2
commit fef6108d45
4 changed files with 100 additions and 67 deletions

View File

@@ -455,10 +455,14 @@ static int gfar_sringparam(struct net_device *dev, struct ethtool_ringparam *rva
/* Halt TX and RX, and process the frames which
* have already been received */
spin_lock_irqsave(&priv->lock, flags);
spin_lock_irqsave(&priv->txlock, flags);
spin_lock(&priv->rxlock);
gfar_halt(dev);
gfar_clean_rx_ring(dev, priv->rx_ring_size);
spin_unlock_irqrestore(&priv->lock, flags);
spin_unlock(&priv->rxlock);
spin_unlock_irqrestore(&priv->txlock, flags);
/* Now we take down the rings to rebuild them */
stop_gfar(dev);
@@ -488,10 +492,14 @@ static int gfar_set_rx_csum(struct net_device *dev, uint32_t data)
/* Halt TX and RX, and process the frames which
* have already been received */
spin_lock_irqsave(&priv->lock, flags);
spin_lock_irqsave(&priv->txlock, flags);
spin_lock(&priv->rxlock);
gfar_halt(dev);
gfar_clean_rx_ring(dev, priv->rx_ring_size);
spin_unlock_irqrestore(&priv->lock, flags);
spin_unlock(&priv->rxlock);
spin_unlock_irqrestore(&priv->txlock, flags);
/* Now we take down the rings to rebuild them */
stop_gfar(dev);
@@ -523,7 +531,7 @@ static int gfar_set_tx_csum(struct net_device *dev, uint32_t data)
if (!(priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_CSUM))
return -EOPNOTSUPP;
spin_lock_irqsave(&priv->lock, flags);
spin_lock_irqsave(&priv->txlock, flags);
gfar_halt(dev);
if (data)
@@ -532,7 +540,7 @@ static int gfar_set_tx_csum(struct net_device *dev, uint32_t data)
dev->features &= ~NETIF_F_IP_CSUM;
gfar_start(dev);
spin_unlock_irqrestore(&priv->lock, flags);
spin_unlock_irqrestore(&priv->txlock, flags);
return 0;
}