summaryrefslogtreecommitdiffstats
path: root/net-at91_ether-Make-mdio-protection-rt-safe.patch
blob: 5e7044614d8f987eb838b2d29ee809fbaabc4472 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
From 18033b350193d8e3517c3446436979ab495cd950 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>
Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com>
---
 drivers/net/arm/at91_ether.c |    5 +++++
 1 files changed, 5 insertions(+), 0 deletions(-)

diff --git a/drivers/net/arm/at91_ether.c b/drivers/net/arm/at91_ether.c
index aed5b54..75146af 100644
--- a/drivers/net/arm/at91_ether.c
+++ b/drivers/net/arm/at91_ether.c
@@ -199,7 +199,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
@@ -241,6 +243,7 @@ static irqreturn_t at91ether_phy_interrupt(int irq, void *dev_id)
 
 done:
 	disable_mdi();
+	spin_unlock_irqrestore(&lp->lock, flags);
 
 	return IRQ_HANDLED;
 }
@@ -397,9 +400,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.0.4