From bb14a2f07c5b50fac48f91e68bb692ed7e0f1304 Mon Sep 17 00:00:00 2001
From: juhosg <juhosg@3c298f89-4303-0410-b956-a3cf2f4a3e73>
Date: Sun, 8 May 2011 16:32:53 +0000
Subject: [PATCH] ar71xx: ag71xx: make switch register access atomic

Reading of the PHY registers occasionally returns with bogus values
under heavy load. This misleads the PHY driver and thus causes false
link/speed change notifications which leads to performance loss.

This is easily noticable during an iperf session:

...
[  3] 52.0-53.0 sec  11.3 MBytes  94.4 Mbits/sec
[  3] 53.0-54.0 sec  11.4 MBytes  95.4 Mbits/sec
eth1: link down
br-lan: port 2(eth1) entering forwarding state
eth1: link up (100Mbps/Full duplex)
br-lan: port 2(eth1) entering forwarding state
br-lan: port 2(eth1) entering forwarding state
[  3] 54.0-55.0 sec  6.75 MBytes  56.6 Mbits/sec
[  3] 55.0-56.0 sec  0.00 Bytes  0.00 bits/sec
[  3] 56.0-57.0 sec  10.5 MBytes  88.1 Mbits/sec
...
[  3] 169.0-170.0 sec  11.4 MBytes  95.4 Mbits/sec
[  3] 170.0-171.0 sec  11.4 MBytes  95.4 Mbits/sec
eth1: link up (10Mbps/Half duplex)
[  3] 171.0-172.0 sec  7.63 MBytes  64.0 Mbits/sec
[  3] 172.0-173.0 sec  9.38 MBytes  78.6 Mbits/sec
eth1: link up (100Mbps/Full duplex)
[  3] 173.0-174.0 sec  11.3 MBytes  94.4 Mbits/sec
[  3] 174.0-175.0 sec  11.4 MBytes  95.4 Mbits/sec

git-svn-id: svn://svn.openwrt.org/openwrt/trunk@26856 3c298f89-4303-0410-b956-a3cf2f4a3e73
---
 .../files/drivers/net/ag71xx/ag71xx_ar7240.c       | 14 ++++++++------
 1 file changed, 8 insertions(+), 6 deletions(-)

diff --git a/target/linux/ar71xx/files/drivers/net/ag71xx/ag71xx_ar7240.c b/target/linux/ar71xx/files/drivers/net/ag71xx/ag71xx_ar7240.c
index 0270e6051..1bc7f58c1 100644
--- a/target/linux/ar71xx/files/drivers/net/ag71xx/ag71xx_ar7240.c
+++ b/target/linux/ar71xx/files/drivers/net/ag71xx/ag71xx_ar7240.c
@@ -233,37 +233,39 @@ static inline u16 mk_high_addr(u32 reg)
 
 static u32 __ar7240sw_reg_read(struct mii_bus *mii, u32 reg)
 {
+	unsigned long flags;
 	u16 phy_addr;
 	u16 phy_reg;
 	u32 hi, lo;
 
 	reg = (reg & 0xfffffffc) >> 2;
-
-	ag71xx_mdio_mii_write(mii->priv, 0x1f, 0x10, mk_high_addr(reg));
-
 	phy_addr = mk_phy_addr(reg);
 	phy_reg = mk_phy_reg(reg);
 
+	local_irq_save(flags);
+	ag71xx_mdio_mii_write(mii->priv, 0x1f, 0x10, mk_high_addr(reg));
 	lo = (u32) ag71xx_mdio_mii_read(mii->priv, phy_addr, phy_reg);
 	hi = (u32) ag71xx_mdio_mii_read(mii->priv, phy_addr, phy_reg + 1);
+	local_irq_restore(flags);
 
 	return (hi << 16) | lo;
 }
 
 static void __ar7240sw_reg_write(struct mii_bus *mii, u32 reg, u32 val)
 {
+	unsigned long flags;
 	u16 phy_addr;
 	u16 phy_reg;
 
 	reg = (reg & 0xfffffffc) >> 2;
-
-	ag71xx_mdio_mii_write(mii->priv, 0x1f, 0x10, mk_high_addr(reg));
-
 	phy_addr = mk_phy_addr(reg);
 	phy_reg = mk_phy_reg(reg);
 
+	local_irq_save(flags);
+	ag71xx_mdio_mii_write(mii->priv, 0x1f, 0x10, mk_high_addr(reg));
 	ag71xx_mdio_mii_write(mii->priv, phy_addr, phy_reg + 1, (val >> 16));
 	ag71xx_mdio_mii_write(mii->priv, phy_addr, phy_reg, (val & 0xffff));
+	local_irq_restore(flags);
 }
 
 static u32 ar7240sw_reg_read(struct mii_bus *mii, u32 reg_addr)
-- 
2.20.1