|
|
@@ -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;
|