| From 51af17335eb28fac0d218a47304e6889c028998d Mon Sep 17 00:00:00 2001 |
| From: Thomas Gleixner <tglx@linutronix.de> |
| Date: Tue, 17 Nov 2009 12:02:43 +0100 |
| Subject: [PATCH] net: at91_ether: Make mdio protection -rt safe |
| |
| commit 05d5f5080a2e3fbbc0f762875b66721588f5e251 in tip. |
| |
| Neither the phy interrupt nor the timer callback which updates the |
| link status in absense of a phy interrupt are taking lp->lock which |
| serializes the MDIO access. This works on mainline as at91 is an UP |
| machine. On preempt-rt the timer callback can run even in the |
| spin_lock_irq(&lp->lock) protected code pathes because spin_lock_irq |
| is neither disabling interrupts nor disabling preemption. |
| |
| Fix this by adding proper locking to at91ether_phy_interrupt() and |
| at91_check_ether() which serializes the access on -rt. |
| |
| Signed-off-by: Thomas Gleixner <tglx@linutronix.de> |
| |
| diff --git a/drivers/net/arm/at91_ether.c b/drivers/net/arm/at91_ether.c |
| index c8bc60a..42230fc 100644 |
| --- a/drivers/net/arm/at91_ether.c |
| +++ b/drivers/net/arm/at91_ether.c |
| @@ -198,7 +198,9 @@ static irqreturn_t at91ether_phy_interrupt(int irq, void *dev_id) |
| struct net_device *dev = (struct net_device *) dev_id; |
| struct at91_private *lp = netdev_priv(dev); |
| unsigned int phy; |
| + unsigned long flags; |
| |
| + spin_lock_irqsave(&lp->lock, flags); |
| /* |
| * This hander is triggered on both edges, but the PHY chips expect |
| * level-triggering. We therefore have to check if the PHY actually has |
| @@ -240,6 +242,7 @@ static irqreturn_t at91ether_phy_interrupt(int irq, void *dev_id) |
| |
| done: |
| disable_mdi(); |
| + spin_unlock_irqrestore(&lp->lock, flags); |
| |
| return IRQ_HANDLED; |
| } |
| @@ -396,9 +399,11 @@ static void at91ether_check_link(unsigned long dev_id) |
| struct net_device *dev = (struct net_device *) dev_id; |
| struct at91_private *lp = netdev_priv(dev); |
| |
| + spin_lock_irq(&lp->lock); |
| enable_mdi(); |
| update_linkspeed(dev, 1); |
| disable_mdi(); |
| + spin_unlock_irq(&lp->lock); |
| |
| mod_timer(&lp->check_timer, jiffies + LINK_POLL_INTERVAL); |
| } |
| -- |
| 1.7.1.1 |
| |