ar71xx: rb493g: fix gpio-mdio accesses under load

It seems that there are maximum timings for mdio accesses that can be
hit when the system is under load and the thread is scheduled during
a read or write access. Since there is no way of knowing if this
happens as there is not even a parity bit, try to work around it
by disabling interrupts during any gpio-mdio accesses.

Performance impact seems to be neglectable, as mdio accesses are not
that often.

Hopefully fixes #19500.

Signed-off-by: Jonas Gorski <jogo@openwrt.org>

Backport of r46012.

git-svn-id: svn://svn.openwrt.org/openwrt/branches/chaos_calmer@46016 3c298f89-4303-0410-b956-a3cf2f4a3e73
zsun
jogo 2015-06-17 10:22:06 +00:00
parent e1cdd3e753
commit 27ebbd9389
1 changed files with 61 additions and 0 deletions

View File

@ -0,0 +1,61 @@
From 66e584435ac0de6e0abeb6d7166fe4fe25d6bb73 Mon Sep 17 00:00:00 2001
From: Jonas Gorski <jogo@openwrt.org>
Date: Tue, 16 Jun 2015 13:15:08 +0200
Subject: [PATCH] phy/mdio-bitbang: prevent rescheduling during command
It seems some phys have some maximum timings for accessing the MDIO line,
resulting in bit errors under cpu stress. Prevent this from happening by
disabling interrupts when sending commands.
Signed-off-by: Jonas Gorski <jogo@openwrt.org>
---
drivers/net/phy/mdio-bitbang.c | 9 +++++++++
1 file changed, 9 insertions(+)
--- a/drivers/net/phy/mdio-bitbang.c
+++ b/drivers/net/phy/mdio-bitbang.c
@@ -17,6 +17,7 @@
* kind, whether express or implied.
*/
+#include <linux/irqflags.h>
#include <linux/module.h>
#include <linux/mdio-bitbang.h>
#include <linux/types.h>
@@ -156,7 +157,9 @@ static int mdiobb_read(struct mii_bus *b
{
struct mdiobb_ctrl *ctrl = bus->priv;
int ret, i;
+ long flags;
+ local_irq_save(flags);
if (reg & MII_ADDR_C45) {
reg = mdiobb_cmd_addr(ctrl, phy, reg);
mdiobb_cmd(ctrl, MDIO_C45_READ, phy, reg);
@@ -169,13 +172,17 @@ static int mdiobb_read(struct mii_bus *b
ret = mdiobb_get_num(ctrl, 16);
mdiobb_get_bit(ctrl);
+ local_irq_restore(flags);
+
return ret;
}
static int mdiobb_write(struct mii_bus *bus, int phy, int reg, u16 val)
{
struct mdiobb_ctrl *ctrl = bus->priv;
+ long flags;
+ local_irq_save(flags);
if (reg & MII_ADDR_C45) {
reg = mdiobb_cmd_addr(ctrl, phy, reg);
mdiobb_cmd(ctrl, MDIO_C45_WRITE, phy, reg);
@@ -190,6 +197,8 @@ static int mdiobb_write(struct mii_bus *
ctrl->ops->set_mdio_dir(ctrl, 0);
mdiobb_get_bit(ctrl);
+ local_irq_restore(flags);
+
return 0;
}