From 41ee4a283cc74f7c2c7f10261adbacf1df2082e0 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sat, 2 Apr 2011 00:47:29 +0000 Subject: [PATCH] ar71xx: only allow internal access to the ar7240 switch, export the MDIO bus behind the switch instead SVN-Revision: 26393 --- .../ar71xx/files/drivers/net/ag71xx/ag71xx.h | 8 + .../files/drivers/net/ag71xx/ag71xx_ar7240.c | 162 ++++++++++-------- .../files/drivers/net/ag71xx/ag71xx_mdio.c | 15 +- 3 files changed, 109 insertions(+), 76 deletions(-) diff --git a/target/linux/ar71xx/files/drivers/net/ag71xx/ag71xx.h b/target/linux/ar71xx/files/drivers/net/ag71xx/ag71xx.h index 8a2913f219..bb4cb5ba9f 100644 --- a/target/linux/ar71xx/files/drivers/net/ag71xx/ag71xx.h +++ b/target/linux/ar71xx/files/drivers/net/ag71xx/ag71xx.h @@ -503,4 +503,12 @@ void ag71xx_ar7240_stop(struct ag71xx *ag); int ag71xx_ar7240_init(struct ag71xx *ag); void ag71xx_ar7240_cleanup(struct ag71xx *ag); +int ag71xx_mdio_mii_read(struct ag71xx_mdio *am, int addr, int reg); +void ag71xx_mdio_mii_write(struct ag71xx_mdio *am, int addr, int reg, u16 val); + +u16 ar7240sw_phy_read(struct mii_bus *mii, unsigned phy_addr, + unsigned reg_addr); +int ar7240sw_phy_write(struct mii_bus *mii, unsigned phy_addr, + unsigned reg_addr, u16 reg_val); + #endif /* _AG71XX_H */ 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 408fa664a9..3ce2f0a5db 100644 --- a/target/linux/ar71xx/files/drivers/net/ag71xx/ag71xx_ar7240.c +++ b/target/linux/ar71xx/files/drivers/net/ag71xx/ag71xx_ar7240.c @@ -195,7 +195,6 @@ struct ar7240sw { struct mii_bus *mii_bus; - struct mutex reg_mutex; struct switch_dev swdev; bool vlan; u16 vlan_id[AR7240_MAX_VLANS]; @@ -210,11 +209,11 @@ struct ar7240sw_hw_stat { int reg; }; +static DEFINE_MUTEX(reg_mutex); static inline void ar7240sw_init(struct ar7240sw *as, struct mii_bus *mii) { as->mii_bus = mii; - mutex_init(&as->reg_mutex); } static inline u16 mk_phy_addr(u32 reg) @@ -232,95 +231,93 @@ static inline u16 mk_high_addr(u32 reg) return (reg >> 7) & 0x1ff; } -static u32 __ar7240sw_reg_read(struct ar7240sw *as, u32 reg) +static u32 __ar7240sw_reg_read(struct mii_bus *mii, u32 reg) { - struct mii_bus *mii = as->mii_bus; u16 phy_addr; u16 phy_reg; u32 hi, lo; reg = (reg & 0xfffffffc) >> 2; - mdiobus_write(mii, 0x1f, 0x10, mk_high_addr(reg)); + ag71xx_mdio_mii_write(mii->priv, 0x1f, 0x10, mk_high_addr(reg)); phy_addr = mk_phy_addr(reg); phy_reg = mk_phy_reg(reg); - lo = (u32) mdiobus_read(mii, phy_addr, phy_reg); - hi = (u32) mdiobus_read(mii, phy_addr, phy_reg + 1); + 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); return (hi << 16) | lo; } -static void __ar7240sw_reg_write(struct ar7240sw *as, u32 reg, u32 val) +static void __ar7240sw_reg_write(struct mii_bus *mii, u32 reg, u32 val) { - struct mii_bus *mii = as->mii_bus; u16 phy_addr; u16 phy_reg; reg = (reg & 0xfffffffc) >> 2; - mdiobus_write(mii, 0x1f, 0x10, mk_high_addr(reg)); + ag71xx_mdio_mii_write(mii->priv, 0x1f, 0x10, mk_high_addr(reg)); phy_addr = mk_phy_addr(reg); phy_reg = mk_phy_reg(reg); - mdiobus_write(mii, phy_addr, phy_reg + 1, (val >> 16)); - mdiobus_write(mii, phy_addr, phy_reg, (val & 0xffff)); + 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)); } -static u32 ar7240sw_reg_read(struct ar7240sw *as, u32 reg_addr) +static u32 ar7240sw_reg_read(struct mii_bus *mii, u32 reg_addr) { u32 ret; - mutex_lock(&as->reg_mutex); - ret = __ar7240sw_reg_read(as, reg_addr); - mutex_unlock(&as->reg_mutex); + mutex_lock(®_mutex); + ret = __ar7240sw_reg_read(mii, reg_addr); + mutex_unlock(®_mutex); return ret; } -static void ar7240sw_reg_write(struct ar7240sw *as, u32 reg_addr, u32 reg_val) +static void ar7240sw_reg_write(struct mii_bus *mii, u32 reg_addr, u32 reg_val) { - mutex_lock(&as->reg_mutex); - __ar7240sw_reg_write(as, reg_addr, reg_val); - mutex_unlock(&as->reg_mutex); + mutex_lock(®_mutex); + __ar7240sw_reg_write(mii, reg_addr, reg_val); + mutex_unlock(®_mutex); } -static u32 ar7240sw_reg_rmw(struct ar7240sw *as, u32 reg, u32 mask, u32 val) +static u32 ar7240sw_reg_rmw(struct mii_bus *mii, u32 reg, u32 mask, u32 val) { u32 t; - mutex_lock(&as->reg_mutex); - t = __ar7240sw_reg_read(as, reg); + mutex_lock(®_mutex); + t = __ar7240sw_reg_read(mii, reg); t &= ~mask; t |= val; - __ar7240sw_reg_write(as, reg, t); - mutex_unlock(&as->reg_mutex); + __ar7240sw_reg_write(mii, reg, t); + mutex_unlock(®_mutex); return t; } -static void ar7240sw_reg_set(struct ar7240sw *as, u32 reg, u32 val) +static void ar7240sw_reg_set(struct mii_bus *mii, u32 reg, u32 val) { u32 t; - mutex_lock(&as->reg_mutex); - t = __ar7240sw_reg_read(as, reg); + mutex_lock(®_mutex); + t = __ar7240sw_reg_read(mii, reg); t |= val; - __ar7240sw_reg_write(as, reg, t); - mutex_unlock(&as->reg_mutex); + __ar7240sw_reg_write(mii, reg, t); + mutex_unlock(®_mutex); } -static int ar7240sw_reg_wait(struct ar7240sw *as, u32 reg, u32 mask, u32 val, - unsigned timeout) +static int __ar7240sw_reg_wait(struct mii_bus *mii, u32 reg, u32 mask, u32 val, + unsigned timeout) { int i; for (i = 0; i < timeout; i++) { u32 t; - t = ar7240sw_reg_read(as, reg); + t = __ar7240sw_reg_read(mii, reg); if ((t & mask) == val) return 0; @@ -330,33 +327,45 @@ static int ar7240sw_reg_wait(struct ar7240sw *as, u32 reg, u32 mask, u32 val, return -ETIMEDOUT; } -static u16 ar7240sw_phy_read(struct ar7240sw *as, unsigned phy_addr, - unsigned reg_addr) +static int ar7240sw_reg_wait(struct mii_bus *mii, u32 reg, u32 mask, u32 val, + unsigned timeout) { - u32 t; + int ret; + + mutex_lock(®_mutex); + ret = __ar7240sw_reg_wait(mii, reg, mask, val, timeout); + mutex_unlock(®_mutex); + return ret; +} + +u16 ar7240sw_phy_read(struct mii_bus *mii, unsigned phy_addr, + unsigned reg_addr) +{ + u32 t, val = 0xffff; int err; if (phy_addr >= AR7240_NUM_PHYS) return 0xffff; + mutex_lock(®_mutex); t = (reg_addr << AR7240_MDIO_CTRL_REG_ADDR_S) | (phy_addr << AR7240_MDIO_CTRL_PHY_ADDR_S) | AR7240_MDIO_CTRL_MASTER_EN | AR7240_MDIO_CTRL_BUSY | AR7240_MDIO_CTRL_CMD_READ; - ar7240sw_reg_write(as, AR7240_REG_MDIO_CTRL, t); - err = ar7240sw_reg_wait(as, AR7240_REG_MDIO_CTRL, - AR7240_MDIO_CTRL_BUSY, 0, 5); - if (err) - return 0xffff; + __ar7240sw_reg_write(mii, AR7240_REG_MDIO_CTRL, t); + err = __ar7240sw_reg_wait(mii, AR7240_REG_MDIO_CTRL, + AR7240_MDIO_CTRL_BUSY, 0, 5); + if (!err) + val = __ar7240sw_reg_read(mii, AR7240_REG_MDIO_CTRL); + mutex_unlock(®_mutex); - t = ar7240sw_reg_read(as, AR7240_REG_MDIO_CTRL); - return t & AR7240_MDIO_CTRL_DATA_M; + return val & AR7240_MDIO_CTRL_DATA_M; } -static int ar7240sw_phy_write(struct ar7240sw *as, unsigned phy_addr, - unsigned reg_addr, u16 reg_val) +int ar7240sw_phy_write(struct mii_bus *mii, unsigned phy_addr, + unsigned reg_addr, u16 reg_val) { u32 t; int ret; @@ -364,6 +373,7 @@ static int ar7240sw_phy_write(struct ar7240sw *as, unsigned phy_addr, if (phy_addr >= AR7240_NUM_PHYS) return -EINVAL; + mutex_lock(®_mutex); t = (phy_addr << AR7240_MDIO_CTRL_PHY_ADDR_S) | (reg_addr << AR7240_MDIO_CTRL_REG_ADDR_S) | AR7240_MDIO_CTRL_MASTER_EN | @@ -371,34 +381,38 @@ static int ar7240sw_phy_write(struct ar7240sw *as, unsigned phy_addr, AR7240_MDIO_CTRL_CMD_WRITE | reg_val; - ar7240sw_reg_write(as, AR7240_REG_MDIO_CTRL, t); - ret = ar7240sw_reg_wait(as, AR7240_REG_MDIO_CTRL, - AR7240_MDIO_CTRL_BUSY, 0, 5); + __ar7240sw_reg_write(mii, AR7240_REG_MDIO_CTRL, t); + ret = __ar7240sw_reg_wait(mii, AR7240_REG_MDIO_CTRL, + AR7240_MDIO_CTRL_BUSY, 0, 5); + mutex_unlock(®_mutex); + return ret; } static int ar7240sw_capture_stats(struct ar7240sw *as) { + struct mii_bus *mii = as->mii_bus; int ret; /* Capture the hardware statistics for all ports */ - ar7240sw_reg_write(as, AR7240_REG_MIB_FUNCTION0, + ar7240sw_reg_write(mii, AR7240_REG_MIB_FUNCTION0, (AR7240_MIB_FUNC_CAPTURE << AR7240_MIB_FUNC_S)); /* Wait for the capturing to complete. */ - ret = ar7240sw_reg_wait(as, AR7240_REG_MIB_FUNCTION0, + ret = ar7240sw_reg_wait(mii, AR7240_REG_MIB_FUNCTION0, AR7240_MIB_BUSY, 0, 10); return ret; } static void ar7240sw_disable_port(struct ar7240sw *as, unsigned port) { - ar7240sw_reg_write(as, AR7240_REG_PORT_CTRL(port), + ar7240sw_reg_write(as->mii_bus, AR7240_REG_PORT_CTRL(port), AR7240_PORT_CTRL_STATE_DISABLED); } static int ar7240sw_reset(struct ar7240sw *as) { + struct mii_bus *mii = as->mii_bus; int ret; int i; @@ -410,41 +424,44 @@ static int ar7240sw_reset(struct ar7240sw *as) msleep(2); /* Reset the switch. */ - ar7240sw_reg_write(as, AR7240_REG_MASK_CTRL, + ar7240sw_reg_write(mii, AR7240_REG_MASK_CTRL, AR7240_MASK_CTRL_SOFT_RESET); - ret = ar7240sw_reg_wait(as, AR7240_REG_MASK_CTRL, + ret = ar7240sw_reg_wait(mii, AR7240_REG_MASK_CTRL, AR7240_MASK_CTRL_SOFT_RESET, 0, 1000); return ret; } static void ar7240sw_setup(struct ar7240sw *as) { + struct mii_bus *mii = as->mii_bus; + /* Enable CPU port, and disable mirror port */ - ar7240sw_reg_write(as, AR7240_REG_CPU_PORT, + ar7240sw_reg_write(mii, AR7240_REG_CPU_PORT, AR7240_CPU_PORT_EN | (15 << AR7240_MIRROR_PORT_S)); /* Setup TAG priority mapping */ - ar7240sw_reg_write(as, AR7240_REG_TAG_PRIORITY, 0xfa50); + ar7240sw_reg_write(mii, AR7240_REG_TAG_PRIORITY, 0xfa50); /* Enable ARP frame acknowledge */ - ar7240sw_reg_set(as, AR7240_REG_AT_CTRL, AR7240_AT_CTRL_ARP_EN); + ar7240sw_reg_set(mii, AR7240_REG_AT_CTRL, AR7240_AT_CTRL_ARP_EN); /* Enable Broadcast frames transmitted to the CPU */ - ar7240sw_reg_set(as, AR7240_REG_FLOOD_MASK, + ar7240sw_reg_set(mii, AR7240_REG_FLOOD_MASK, AR7240_FLOOD_MASK_BROAD_TO_CPU); /* setup MTU */ - ar7240sw_reg_rmw(as, AR7240_REG_GLOBAL_CTRL, AR7240_GLOBAL_CTRL_MTU_M, + ar7240sw_reg_rmw(mii, AR7240_REG_GLOBAL_CTRL, AR7240_GLOBAL_CTRL_MTU_M, 1536); /* setup Service TAG */ - ar7240sw_reg_rmw(as, AR7240_REG_SERVICE_TAG, AR7240_SERVICE_TAG_M, 0); + ar7240sw_reg_rmw(mii, AR7240_REG_SERVICE_TAG, AR7240_SERVICE_TAG_M, 0); } static void ar7240sw_setup_port(struct ar7240sw *as, unsigned port, u8 portmask) { + struct mii_bus *mii = as->mii_bus; u32 ctrl; u32 dest_ports; u32 vlan; @@ -453,7 +470,7 @@ static void ar7240sw_setup_port(struct ar7240sw *as, unsigned port, u8 portmask) AR7240_PORT_CTRL_SINGLE_VLAN; if (port == AR7240_PORT_CPU) { - ar7240sw_reg_write(as, AR7240_REG_PORT_STATUS(port), + ar7240sw_reg_write(mii, AR7240_REG_PORT_STATUS(port), AR7240_PORT_STATUS_SPEED_1000 | AR7240_PORT_STATUS_TXFLOW | AR7240_PORT_STATUS_RXFLOW | @@ -461,7 +478,7 @@ static void ar7240sw_setup_port(struct ar7240sw *as, unsigned port, u8 portmask) AR7240_PORT_STATUS_RXMAC | AR7240_PORT_STATUS_DUPLEX); } else { - ar7240sw_reg_write(as, AR7240_REG_PORT_STATUS(port), + ar7240sw_reg_write(mii, AR7240_REG_PORT_STATUS(port), AR7240_PORT_STATUS_LINK_AUTO); } @@ -499,19 +516,20 @@ static void ar7240sw_setup_port(struct ar7240sw *as, unsigned port, u8 portmask) /* set default VID and and destination ports for this VLAN */ vlan |= (portmask << AR7240_PORT_VLAN_DEST_PORTS_S); - ar7240sw_reg_write(as, AR7240_REG_PORT_CTRL(port), ctrl); - ar7240sw_reg_write(as, AR7240_REG_PORT_VLAN(port), vlan); + ar7240sw_reg_write(mii, AR7240_REG_PORT_CTRL(port), ctrl); + ar7240sw_reg_write(mii, AR7240_REG_PORT_VLAN(port), vlan); } static int ar7240_set_addr(struct ar7240sw *as, u8 *addr) { + struct mii_bus *mii = as->mii_bus; u32 t; t = (addr[4] << 8) | addr[5]; - ar7240sw_reg_write(as, AR7240_REG_MAC_ADDR0, t); + ar7240sw_reg_write(mii, AR7240_REG_MAC_ADDR0, t); t = (addr[0] << 24) | (addr[1] << 16) | (addr[2] << 8) | addr[3]; - ar7240sw_reg_write(as, AR7240_REG_MAC_ADDR1, t); + ar7240sw_reg_write(mii, AR7240_REG_MAC_ADDR1, t); return 0; } @@ -633,16 +651,18 @@ ar7240_get_vlan(struct switch_dev *dev, const struct switch_attr *attr, static void ar7240_vtu_op(struct ar7240sw *as, u32 op, u32 val) { - if (ar7240sw_reg_wait(as, AR7240_REG_VTU, AR7240_VTU_ACTIVE, 0, 5)) + struct mii_bus *mii = as->mii_bus; + + if (ar7240sw_reg_wait(mii, AR7240_REG_VTU, AR7240_VTU_ACTIVE, 0, 5)) return; if ((op & AR7240_VTU_OP) == AR7240_VTU_OP_LOAD) { val &= AR7240_VTUDATA_MEMBER; val |= AR7240_VTUDATA_VALID; - ar7240sw_reg_write(as, AR7240_REG_VTU_DATA, val); + ar7240sw_reg_write(mii, AR7240_REG_VTU_DATA, val); } op |= AR7240_VTU_ACTIVE; - ar7240sw_reg_write(as, AR7240_REG_VTU, op); + ar7240sw_reg_write(mii, AR7240_REG_VTU, op); } static int @@ -766,7 +786,7 @@ static struct ar7240sw *ar7240_probe(struct ag71xx *ag) ar7240sw_init(as, mii); - ctrl = ar7240sw_reg_read(as, AR7240_REG_MASK_CTRL); + ctrl = ar7240sw_reg_read(mii, AR7240_REG_MASK_CTRL); ver = (ctrl >> AR7240_MASK_CTRL_VERSION_S) & AR7240_MASK_CTRL_VERSION_M; if (ver != 1) { @@ -775,8 +795,8 @@ static struct ar7240sw *ar7240_probe(struct ag71xx *ag) return NULL; } - phy_id1 = ar7240sw_phy_read(as, 0, MII_PHYSID1); - phy_id2 = ar7240sw_phy_read(as, 0, MII_PHYSID2); + phy_id1 = ar7240sw_phy_read(mii, 0, MII_PHYSID1); + phy_id2 = ar7240sw_phy_read(mii, 0, MII_PHYSID2); if (phy_id1 != AR7240_PHY_ID1 || phy_id2 != AR7240_PHY_ID2) { pr_err("%s: unknown phy id '%04x:%04x'\n", ag->dev->name, phy_id1, phy_id2); diff --git a/target/linux/ar71xx/files/drivers/net/ag71xx/ag71xx_mdio.c b/target/linux/ar71xx/files/drivers/net/ag71xx/ag71xx_mdio.c index 2664429e76..b2460d726e 100644 --- a/target/linux/ar71xx/files/drivers/net/ag71xx/ag71xx_mdio.c +++ b/target/linux/ar71xx/files/drivers/net/ag71xx/ag71xx_mdio.c @@ -47,7 +47,7 @@ static void ag71xx_mdio_dump_regs(struct ag71xx_mdio *am) ag71xx_mdio_rr(am, AG71XX_REG_MII_IND)); } -static int ag71xx_mdio_mii_read(struct ag71xx_mdio *am, int addr, int reg) +int ag71xx_mdio_mii_read(struct ag71xx_mdio *am, int addr, int reg) { int ret; int i; @@ -77,8 +77,7 @@ out: return ret; } -static void ag71xx_mdio_mii_write(struct ag71xx_mdio *am, - int addr, int reg, u16 val) +void ag71xx_mdio_mii_write(struct ag71xx_mdio *am, int addr, int reg, u16 val) { int i; @@ -122,14 +121,20 @@ static int ag71xx_mdio_read(struct mii_bus *bus, int addr, int reg) { struct ag71xx_mdio *am = bus->priv; - return ag71xx_mdio_mii_read(am, addr, reg); + if (am->pdata->is_ar7240) + return ar7240sw_phy_read(bus, addr, reg); + else + return ag71xx_mdio_mii_read(am, addr, reg); } static int ag71xx_mdio_write(struct mii_bus *bus, int addr, int reg, u16 val) { struct ag71xx_mdio *am = bus->priv; - ag71xx_mdio_mii_write(am, addr, reg, val); + if (am->pdata->is_ar7240) + ar7240sw_phy_write(bus, addr, reg, val); + else + ag71xx_mdio_mii_write(am, addr, reg, val); return 0; } -- 2.30.2