generic: ar8216: add optimized rmw operation
authorGabor Juhos <juhosg@openwrt.org>
Mon, 20 Jan 2014 10:22:54 +0000 (10:22 +0000)
committerGabor Juhos <juhosg@openwrt.org>
Mon, 20 Jan 2014 10:22:54 +0000 (10:22 +0000)
Signed-off-by: Gabor Juhos <juhosg@openwrt.org>
SVN-Revision: 39336

target/linux/generic/files/drivers/net/phy/ar8216.c

index 952dee27ecd66fd9de9c42b0fea724c3ce6c0ea6..884b3199c125fda78655e6a37c09a26661fac622 100644 (file)
@@ -92,6 +92,7 @@ struct ar8xxx_priv {
 
        u32 (*read)(struct ar8xxx_priv *priv, int reg);
        void (*write)(struct ar8xxx_priv *priv, int reg, u32 val);
+       u32 (*rmw)(struct ar8xxx_priv *priv, int reg, u32 mask, u32 val);
 
        int (*get_port_link)(unsigned port);
 
@@ -326,6 +327,45 @@ ar8xxx_mii_write(struct ar8xxx_priv *priv, int reg, u32 val)
        mutex_unlock(&bus->mdio_lock);
 }
 
+static u32
+ar8xxx_mii_rmw(struct ar8xxx_priv *priv, int reg, u32 mask, u32 val)
+{
+       struct mii_bus *bus = priv->mii_bus;
+       u16 r1, r2, page;
+       u16 lo, hi;
+       u32 ret;
+
+       split_addr((u32) reg, &r1, &r2, &page);
+
+       mutex_lock(&bus->mdio_lock);
+
+       bus->write(bus, 0x18, 0, page);
+       usleep_range(1000, 2000); /* wait for the page switch to propagate */
+
+       lo = bus->read(bus, 0x10 | r2, r1);
+       hi = bus->read(bus, 0x10 | r2, r1 + 1);
+
+       ret = hi << 16 | lo;
+       ret &= ~mask;
+       ret |= val;
+
+       lo = ret & 0xffff;
+       hi = (u16) (ret >> 16);
+
+       if (priv->mii_lo_first) {
+               bus->write(bus, 0x10 | r2, r1, lo);
+               bus->write(bus, 0x10 | r2, r1 + 1, hi);
+       } else {
+               bus->write(bus, 0x10 | r2, r1 + 1, hi);
+               bus->write(bus, 0x10 | r2, r1, lo);
+       }
+
+       mutex_unlock(&bus->mdio_lock);
+
+       return ret;
+}
+
+
 static void
 ar8xxx_phy_dbg_write(struct ar8xxx_priv *priv, int phy_addr,
                     u16 dbg_addr, u16 dbg_data)
@@ -349,31 +389,16 @@ ar8xxx_phy_mmd_write(struct ar8xxx_priv *priv, int phy_addr, u16 addr, u16 data)
        mutex_unlock(&bus->mdio_lock);
 }
 
-static u32
+static inline u32
 ar8xxx_rmw(struct ar8xxx_priv *priv, int reg, u32 mask, u32 val)
 {
-       u32 v;
-
-       lockdep_assert_held(&priv->reg_mutex);
-
-       v = priv->read(priv, reg);
-       v &= ~mask;
-       v |= val;
-       priv->write(priv, reg, v);
-
-       return v;
+       return priv->rmw(priv, reg, mask, val);
 }
 
 static inline void
 ar8xxx_reg_set(struct ar8xxx_priv *priv, int reg, u32 val)
 {
-       u32 v;
-
-       lockdep_assert_held(&priv->reg_mutex);
-
-       v = priv->read(priv, reg);
-       v |= val;
-       priv->write(priv, reg, v);
+       priv->rmw(priv, reg, 0, val);
 }
 
 static int
@@ -408,10 +433,8 @@ ar8xxx_mib_op(struct ar8xxx_priv *priv, u32 op)
        else
                mib_func = AR8216_REG_MIB_FUNC;
 
-       mutex_lock(&priv->reg_mutex);
        /* Capture the hardware statistics for all ports */
        ar8xxx_rmw(priv, mib_func, AR8216_MIB_FUNC, (op << AR8216_MIB_FUNC_S));
-       mutex_unlock(&priv->reg_mutex);
 
        /* Wait for the capturing to complete. */
        ret = ar8xxx_reg_wait(priv, mib_func, AR8216_MIB_BUSY, 0, 10);
@@ -2225,6 +2248,7 @@ ar8xxx_create_mii(struct mii_bus *bus)
                priv->mii_bus = bus;
                priv->read = ar8xxx_mii_read;
                priv->write = ar8xxx_mii_write;
+               priv->rmw = ar8xxx_mii_rmw;
        }
 
        return priv;