Now there are two spinlocks:
- one for HW access like the RX/TX buffer & friends (but the MAC address)
- one for the mii lists.
Theoretically those two spinlocks could become one, but that way it looks
better.
The locks are taken before the first access to the HW (like retrieving the
current pointer to the ring buffer) and released after we finished. This
fixes some races that were covered / fixed by 0a504779d.
Signed-off-by: Sebastian Siewior <bigeasy@linutronix.de>
--- a/drivers/net/fec.c
+++ b/drivers/net/fec.c
@@ -209,7 +209,10 @@ struct fec_enet_private {
cbd_t *cur_rx, *cur_tx; /* The next free ring entry */
cbd_t *dirty_tx; /* The ring entries to be free()ed. */
uint tx_full;
- spinlock_t lock;
+ /* hold while accessing the HW like ringbuffer for tx/rx but not MAC */
+ spinlock_t hw_lock;
+ /* hold while accessing the mii_list_t() elements */
+ spinlock_t mii_lock;
uint phy_id;
uint phy_id_done;
@@ -309,6 +312,7 @@ static int fec_enet_start_xmit(struct sk
volatile fec_t *fecp;
volatile cbd_t *bdp;
unsigned short status;
+ unsigned long flags;
fep = netdev_priv(dev);
fecp = (volatile fec_t *)dev->base_addr;
@@ -318,6 +322,7 @@ static int fec_enet_start_xmit(struct sk
return 1;
}
+ spin_lock_irqsave(&fep->hw_lock, flags);
/* Fill in a Tx ring entry */
bdp = fep->cur_tx;
@@ -328,6 +333,7 @@ static int fec_enet_start_xmit(struct sk
* This should not happen, since dev->tbusy should be set.
*/
printk("%s: tx queue full!.\n", dev->name);
+ spin_unlock_irqrestore(&fep->hw_lock, flags);
return 1;
}
#endif
@@ -367,7 +373,6 @@ static int fec_enet_start_xmit(struct sk
flush_dcache_range((unsigned long)skb->data,
(unsigned long)skb->data + skb->len);
- spin_lock_irq(&fep->lock);
/* Send it on its way. Tell FEC it's ready, interrupt when done,
* it's the last BD of the frame, and to put the CRC on the end.
@@ -397,7 +402,7 @@ static int fec_enet_start_xmit(struct sk
fep->cur_tx = (cbd_t *) bdp;
- spin_unlock_irq(&fep->lock);
+ spin_unlock_irqrestore(&fep->hw_lock, flags);
return 0;
}
@@ -451,19 +456,20 @@ static irqreturn_t fec_enet_interrupt(in
struct net_device *dev = dev_id;
volatile fec_t *fecp;
uint int_events;
- int handled = 0;
+ irqreturn_t ret = IRQ_NONE;
fecp = (volatile fec_t *)dev->base_addr;
/* Get the interrupt events that caused us to be here.
*/
- while ((int_events = fecp->fec_ievent) != 0) {
+ do {
+ int_events = fecp->fec_ievent;
fecp->fec_ievent = int_events;
/* Handle receive event in its own function.
*/
if (int_events & FEC_ENET_RXF) {
- handled = 1;
+ ret = IRQ_HANDLED;
fec_enet_rx(dev);
}
@@ -472,17 +478,18 @@ static irqreturn_t fec_enet_interrupt(in
them as part of the transmit process.
*/
if (int_events & FEC_ENET_TXF) {
- handled = 1;
+ ret = IRQ_HANDLED;
fec_enet_tx(dev);
}
if (int_events & FEC_ENET_MII) {
- handled = 1;
+ ret = IRQ_HANDLED;
fec_enet_mii(dev);
}
- }
- return IRQ_RETVAL(handled);
+ } while (int_events);
+
+ return ret;
}
static void fec_enet_tx(struct net_device *dev)
@@ -493,7 +500,7 @@ static void fec_enet_tx(struct net_devic
struct sk_buff *skb;
fep = netdev_priv(dev);
- spin_lock(&fep->lock);
+ spin_lock_irq(&fep->hw_lock);
bdp = fep->dirty_tx;
while (((status = bdp->cbd_sc) & BD_ENET_TX_READY) == 0) {
@@ -552,7 +559,7 @@ static void fec_enet_tx(struct net_devic
}
}
fep->dirty_tx = (cbd_t *) bdp;
- spin_unlock(&fep->lock);
+ spin_unlock_irq(&fep->hw_lock);
}
/* During a receive, the cur_rx points to the current incoming buffer.
@@ -575,6 +582,7 @@ static void fec_enet_rx(struct net_devic
#endif
fep = netdev_priv(dev);
+ spin_lock_irq(&fep->hw_lock);
fecp = (volatile fec_t *)dev->base_addr;
/* First, grab all of the stats for the incoming packet.
@@ -683,6 +691,7 @@ rx_processing_done:
*/
fecp->fec_r_des_active = 0;
#endif
+ spin_unlock_irq(&fep->hw_lock);
}
/* called from interrupt context */
@@ -695,11 +704,11 @@ static void fec_enet_mii(struct net_devi
mii_func *mii_func = NULL;
fep = netdev_priv(dev);
+ spin_lock_irq(&fep->mii_lock);
+
ep = fep->hwp;
mii_reg = ep->fec_mii_data;
- spin_lock(&fep->lock);
-
if ((mip = mii_head) == NULL) {
printk("MII and no head!\n");
goto unlock;
@@ -716,7 +725,7 @@ static void fec_enet_mii(struct net_devi
ep->fec_mii_data = mip->mii_regval;
unlock:
- spin_unlock(&fep->lock);
+ spin_unlock_irq(&fep->mii_lock);
if (mii_func)
mii_func(mii_reg, dev);
}
@@ -731,12 +740,11 @@ static int mii_queue(struct net_device *
/* Add PHY address to register command.
*/
fep = netdev_priv(dev);
- regval |= fep->phy_addr << 23;
+ spin_lock_irqsave(&fep->mii_lock, flags);
+ regval |= fep->phy_addr << 23;
retval = 0;
- spin_lock_irqsave(&fep->lock, flags);
-
if ((mip = mii_free) != NULL) {
mii_free = mip->mii_next;
mip->mii_regval = regval;
@@ -753,9 +761,8 @@ static int mii_queue(struct net_device *
retval = 1;
}
- spin_unlock_irqrestore(&fep->lock, flags);
-
- return (retval);
+ spin_unlock_irqrestore(&fep->mii_lock, flags);
+ return retval;
}
static void mii_do_cmd(struct net_device *dev, const phy_cmd_t *c)
@@ -2371,6 +2378,8 @@ int __init fec_enet_init(struct net_devi
return -ENOMEM;
}
+ spin_lock_init(&fep->hw_lock);
+ spin_lock_init(&fep->mii_lock);
/* Create an Ethernet device instance.
*/
fecp = (volatile fec_t *)fec_hw[index];
--
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
| Francois Romieu | Re: PROBLEM: 2.6.23-rc "NETDEV WATCHDOG: eth0: transmit timed out" |
| Greg Kroah-Hartman | [PATCH 040/196] kobject: add kobject_add_ng function |
| Dave Airlie | [git pull] drm patches for 2.6.27 final |
| john stultz | [PATCH] correct inconsistent ntp interval/tick_length usage |
| Krzysztof Halasa | Re: [PATCH v2] Re: WAN: new PPP code for generic HDLC |
| David Miller | Re: [PATCH] Expose netdevice dev_id through sysfs |
| Dave Jones | odd RTL8139 quirk. |
| Auke Kok | [PATCH 4/8] e1000e: lower ring minimum size to 64 |
git: | |
| Miklos Vajna | [rfc] git submodules howto |
| Andrew Morton | Untracked working tree files |
| Ben Collins | Re: [kernel.org users] [RFD] On deprecating "git-foo" for builtins |
| Jon Smirl | ! [rejected] master -> master (non-fast forward) |
| rancor | How to copy/pipe console buffert to file? |
| Pieter Verberne | File collision while using pkg_add |
| Greg Thomas | Re: Is it possible to fix a stale NFS hadle without rebooting? |
| Didier Wiroth | win32-codecs, avi and amd64 question |
| Netfilter kernel module | 9 hours ago | Linux kernel |
| serial driver xmit problem | 12 hours ago | Linux kernel |
| Why Windows is better than Linux | 12 hours ago | Linux general |
| How can I see my kernel messages in vt12? | 18 hours ago | Linux kernel |
| Grub | 1 day ago | Linux general |
| vmalloc_fault handling in x86_64 | 1 day ago | Linux kernel |
| epoll_wait()ing on epoll FD | 1 day ago | Linux kernel |
| Framebuffer in x86_64 causes problems to multiseat | 1 day ago | Linux kernel |
| Difference between 2.4 and 2.6 regarding thread creation | 1 day ago | Linux general |
| Compiling gfs2 on kernel 2.6.27 | 2 days ago | Linux kernel |
