diff options
Diffstat (limited to 'drivers/net/dsa/mv88e6xxx.c')
-rw-r--r-- | drivers/net/dsa/mv88e6xxx.c | 980 |
1 files changed, 848 insertions, 132 deletions
diff --git a/drivers/net/dsa/mv88e6xxx.c b/drivers/net/dsa/mv88e6xxx.c index cf309aa92802..fd8547c2b79d 100644 --- a/drivers/net/dsa/mv88e6xxx.c +++ b/drivers/net/dsa/mv88e6xxx.c @@ -8,6 +8,7 @@ * (at your option) any later version. */ +#include <linux/debugfs.h> #include <linux/delay.h> #include <linux/etherdevice.h> #include <linux/if_bridge.h> @@ -16,9 +17,38 @@ #include <linux/module.h> #include <linux/netdevice.h> #include <linux/phy.h> +#include <linux/seq_file.h> #include <net/dsa.h> #include "mv88e6xxx.h" +/* MDIO bus access can be nested in the case of PHYs connected to the + * internal MDIO bus of the switch, which is accessed via MDIO bus of + * the Ethernet interface. Avoid lockdep false positives by using + * mutex_lock_nested(). + */ +static int mv88e6xxx_mdiobus_read(struct mii_bus *bus, int addr, u32 regnum) +{ + int ret; + + mutex_lock_nested(&bus->mdio_lock, SINGLE_DEPTH_NESTING); + ret = bus->read(bus, addr, regnum); + mutex_unlock(&bus->mdio_lock); + + return ret; +} + +static int mv88e6xxx_mdiobus_write(struct mii_bus *bus, int addr, u32 regnum, + u16 val) +{ + int ret; + + mutex_lock_nested(&bus->mdio_lock, SINGLE_DEPTH_NESTING); + ret = bus->write(bus, addr, regnum, val); + mutex_unlock(&bus->mdio_lock); + + return ret; +} + /* If the switch's ADDR[4:0] strap pins are strapped to zero, it will * use all 32 SMI bus addresses on its SMI bus, and all switch registers * will be directly accessible on some {device address,register address} @@ -33,7 +63,7 @@ static int mv88e6xxx_reg_wait_ready(struct mii_bus *bus, int sw_addr) int i; for (i = 0; i < 16; i++) { - ret = mdiobus_read(bus, sw_addr, SMI_CMD); + ret = mv88e6xxx_mdiobus_read(bus, sw_addr, SMI_CMD); if (ret < 0) return ret; @@ -49,7 +79,7 @@ int __mv88e6xxx_reg_read(struct mii_bus *bus, int sw_addr, int addr, int reg) int ret; if (sw_addr == 0) - return mdiobus_read(bus, addr, reg); + return mv88e6xxx_mdiobus_read(bus, addr, reg); /* Wait for the bus to become free. */ ret = mv88e6xxx_reg_wait_ready(bus, sw_addr); @@ -57,8 +87,8 @@ int __mv88e6xxx_reg_read(struct mii_bus *bus, int sw_addr, int addr, int reg) return ret; /* Transmit the read command. */ - ret = mdiobus_write(bus, sw_addr, SMI_CMD, - SMI_CMD_OP_22_READ | (addr << 5) | reg); + ret = mv88e6xxx_mdiobus_write(bus, sw_addr, SMI_CMD, + SMI_CMD_OP_22_READ | (addr << 5) | reg); if (ret < 0) return ret; @@ -68,7 +98,7 @@ int __mv88e6xxx_reg_read(struct mii_bus *bus, int sw_addr, int addr, int reg) return ret; /* Read the data. */ - ret = mdiobus_read(bus, sw_addr, SMI_DATA); + ret = mv88e6xxx_mdiobus_read(bus, sw_addr, SMI_DATA); if (ret < 0) return ret; @@ -112,7 +142,7 @@ int __mv88e6xxx_reg_write(struct mii_bus *bus, int sw_addr, int addr, int ret; if (sw_addr == 0) - return mdiobus_write(bus, addr, reg, val); + return mv88e6xxx_mdiobus_write(bus, addr, reg, val); /* Wait for the bus to become free. */ ret = mv88e6xxx_reg_wait_ready(bus, sw_addr); @@ -120,13 +150,13 @@ int __mv88e6xxx_reg_write(struct mii_bus *bus, int sw_addr, int addr, return ret; /* Transmit the data to write. */ - ret = mdiobus_write(bus, sw_addr, SMI_DATA, val); + ret = mv88e6xxx_mdiobus_write(bus, sw_addr, SMI_DATA, val); if (ret < 0) return ret; /* Transmit the write command. */ - ret = mdiobus_write(bus, sw_addr, SMI_CMD, - SMI_CMD_OP_22_WRITE | (addr << 5) | reg); + ret = mv88e6xxx_mdiobus_write(bus, sw_addr, SMI_CMD, + SMI_CMD_OP_22_WRITE | (addr << 5) | reg); if (ret < 0) return ret; @@ -165,24 +195,6 @@ int mv88e6xxx_reg_write(struct dsa_switch *ds, int addr, int reg, u16 val) return ret; } -int mv88e6xxx_config_prio(struct dsa_switch *ds) -{ - /* Configure the IP ToS mapping registers. */ - REG_WRITE(REG_GLOBAL, GLOBAL_IP_PRI_0, 0x0000); - REG_WRITE(REG_GLOBAL, GLOBAL_IP_PRI_1, 0x0000); - REG_WRITE(REG_GLOBAL, GLOBAL_IP_PRI_2, 0x5555); - REG_WRITE(REG_GLOBAL, GLOBAL_IP_PRI_3, 0x5555); - REG_WRITE(REG_GLOBAL, GLOBAL_IP_PRI_4, 0xaaaa); - REG_WRITE(REG_GLOBAL, GLOBAL_IP_PRI_5, 0xaaaa); - REG_WRITE(REG_GLOBAL, GLOBAL_IP_PRI_6, 0xffff); - REG_WRITE(REG_GLOBAL, GLOBAL_IP_PRI_7, 0xffff); - - /* Configure the IEEE 802.1p priority mapping register. */ - REG_WRITE(REG_GLOBAL, GLOBAL_IEEE_PRI, 0xfa41); - - return 0; -} - int mv88e6xxx_set_addr_direct(struct dsa_switch *ds, u8 *addr) { REG_WRITE(REG_GLOBAL, GLOBAL_MAC_01, (addr[0] << 8) | addr[1]); @@ -217,20 +229,20 @@ int mv88e6xxx_set_addr_indirect(struct dsa_switch *ds, u8 *addr) return 0; } -/* Must be called with phy mutex held */ +/* Must be called with SMI mutex held */ static int _mv88e6xxx_phy_read(struct dsa_switch *ds, int addr, int regnum) { if (addr >= 0) - return mv88e6xxx_reg_read(ds, addr, regnum); + return _mv88e6xxx_reg_read(ds, addr, regnum); return 0xffff; } -/* Must be called with phy mutex held */ +/* Must be called with SMI mutex held */ static int _mv88e6xxx_phy_write(struct dsa_switch *ds, int addr, int regnum, u16 val) { if (addr >= 0) - return mv88e6xxx_reg_write(ds, addr, regnum, val); + return _mv88e6xxx_reg_write(ds, addr, regnum, val); return 0; } @@ -434,26 +446,113 @@ void mv88e6xxx_poll_link(struct dsa_switch *ds) } } +static bool mv88e6xxx_6065_family(struct dsa_switch *ds) +{ + struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); + + switch (ps->id) { + case PORT_SWITCH_ID_6031: + case PORT_SWITCH_ID_6061: + case PORT_SWITCH_ID_6035: + case PORT_SWITCH_ID_6065: + return true; + } + return false; +} + +static bool mv88e6xxx_6095_family(struct dsa_switch *ds) +{ + struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); + + switch (ps->id) { + case PORT_SWITCH_ID_6092: + case PORT_SWITCH_ID_6095: + return true; + } + return false; +} + +static bool mv88e6xxx_6097_family(struct dsa_switch *ds) +{ + struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); + + switch (ps->id) { + case PORT_SWITCH_ID_6046: + case PORT_SWITCH_ID_6085: + case PORT_SWITCH_ID_6096: + case PORT_SWITCH_ID_6097: + return true; + } + return false; +} + +static bool mv88e6xxx_6165_family(struct dsa_switch *ds) +{ + struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); + + switch (ps->id) { + case PORT_SWITCH_ID_6123: + case PORT_SWITCH_ID_6161: + case PORT_SWITCH_ID_6165: + return true; + } + return false; +} + +static bool mv88e6xxx_6185_family(struct dsa_switch *ds) +{ + struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); + + switch (ps->id) { + case PORT_SWITCH_ID_6121: + case PORT_SWITCH_ID_6122: + case PORT_SWITCH_ID_6152: + case PORT_SWITCH_ID_6155: + case PORT_SWITCH_ID_6182: + case PORT_SWITCH_ID_6185: + case PORT_SWITCH_ID_6108: + case PORT_SWITCH_ID_6131: + return true; + } + return false; +} + +static bool mv88e6xxx_6351_family(struct dsa_switch *ds) +{ + struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); + + switch (ps->id) { + case PORT_SWITCH_ID_6171: + case PORT_SWITCH_ID_6175: + case PORT_SWITCH_ID_6350: + case PORT_SWITCH_ID_6351: + return true; + } + return false; +} + static bool mv88e6xxx_6352_family(struct dsa_switch *ds) { struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); switch (ps->id) { - case PORT_SWITCH_ID_6352: case PORT_SWITCH_ID_6172: case PORT_SWITCH_ID_6176: + case PORT_SWITCH_ID_6240: + case PORT_SWITCH_ID_6352: return true; } return false; } -static int mv88e6xxx_stats_wait(struct dsa_switch *ds) +/* Must be called with SMI mutex held */ +static int _mv88e6xxx_stats_wait(struct dsa_switch *ds) { int ret; int i; for (i = 0; i < 10; i++) { - ret = REG_READ(REG_GLOBAL, GLOBAL_STATS_OP); + ret = _mv88e6xxx_reg_read(ds, REG_GLOBAL, GLOBAL_STATS_OP); if ((ret & GLOBAL_STATS_OP_BUSY) == 0) return 0; } @@ -461,7 +560,8 @@ static int mv88e6xxx_stats_wait(struct dsa_switch *ds) return -ETIMEDOUT; } -static int mv88e6xxx_stats_snapshot(struct dsa_switch *ds, int port) +/* Must be called with SMI mutex held */ +static int _mv88e6xxx_stats_snapshot(struct dsa_switch *ds, int port) { int ret; @@ -469,42 +569,45 @@ static int mv88e6xxx_stats_snapshot(struct dsa_switch *ds, int port) port = (port + 1) << 5; /* Snapshot the hardware statistics counters for this port. */ - REG_WRITE(REG_GLOBAL, GLOBAL_STATS_OP, - GLOBAL_STATS_OP_CAPTURE_PORT | - GLOBAL_STATS_OP_HIST_RX_TX | port); + ret = _mv88e6xxx_reg_write(ds, REG_GLOBAL, GLOBAL_STATS_OP, + GLOBAL_STATS_OP_CAPTURE_PORT | + GLOBAL_STATS_OP_HIST_RX_TX | port); + if (ret < 0) + return ret; /* Wait for the snapshotting to complete. */ - ret = mv88e6xxx_stats_wait(ds); + ret = _mv88e6xxx_stats_wait(ds); if (ret < 0) return ret; return 0; } -static void mv88e6xxx_stats_read(struct dsa_switch *ds, int stat, u32 *val) +/* Must be called with SMI mutex held */ +static void _mv88e6xxx_stats_read(struct dsa_switch *ds, int stat, u32 *val) { u32 _val; int ret; *val = 0; - ret = mv88e6xxx_reg_write(ds, REG_GLOBAL, GLOBAL_STATS_OP, - GLOBAL_STATS_OP_READ_CAPTURED | - GLOBAL_STATS_OP_HIST_RX_TX | stat); + ret = _mv88e6xxx_reg_write(ds, REG_GLOBAL, GLOBAL_STATS_OP, + GLOBAL_STATS_OP_READ_CAPTURED | + GLOBAL_STATS_OP_HIST_RX_TX | stat); if (ret < 0) return; - ret = mv88e6xxx_stats_wait(ds); + ret = _mv88e6xxx_stats_wait(ds); if (ret < 0) return; - ret = mv88e6xxx_reg_read(ds, REG_GLOBAL, GLOBAL_STATS_COUNTER_32); + ret = _mv88e6xxx_reg_read(ds, REG_GLOBAL, GLOBAL_STATS_COUNTER_32); if (ret < 0) return; _val = ret << 16; - ret = mv88e6xxx_reg_read(ds, REG_GLOBAL, GLOBAL_STATS_COUNTER_01); + ret = _mv88e6xxx_reg_read(ds, REG_GLOBAL, GLOBAL_STATS_COUNTER_01); if (ret < 0) return; @@ -578,6 +681,40 @@ static void _mv88e6xxx_get_strings(struct dsa_switch *ds, } } +static uint64_t _mv88e6xxx_get_ethtool_stat(struct dsa_switch *ds, + int stat, + struct mv88e6xxx_hw_stat *stats, + int port) +{ + struct mv88e6xxx_hw_stat *s = stats + stat; + u32 low; + u32 high = 0; + int ret; + u64 value; + + if (s->reg >= 0x100) { + ret = _mv88e6xxx_reg_read(ds, REG_PORT(port), + s->reg - 0x100); + if (ret < 0) + return UINT64_MAX; + + low = ret; + if (s->sizeof_stat == 4) { + ret = _mv88e6xxx_reg_read(ds, REG_PORT(port), + s->reg - 0x100 + 1); + if (ret < 0) + return UINT64_MAX; + high = ret; + } + } else { + _mv88e6xxx_stats_read(ds, s->reg, &low); + if (s->sizeof_stat == 8) + _mv88e6xxx_stats_read(ds, s->reg + 1, &high); + } + value = (((u64)high) << 16) | low; + return value; +} + static void _mv88e6xxx_get_ethtool_stats(struct dsa_switch *ds, int nr_stats, struct mv88e6xxx_hw_stat *stats, @@ -587,44 +724,19 @@ static void _mv88e6xxx_get_ethtool_stats(struct dsa_switch *ds, int ret; int i; - mutex_lock(&ps->stats_mutex); + mutex_lock(&ps->smi_mutex); - ret = mv88e6xxx_stats_snapshot(ds, port); + ret = _mv88e6xxx_stats_snapshot(ds, port); if (ret < 0) { - mutex_unlock(&ps->stats_mutex); + mutex_unlock(&ps->smi_mutex); return; } /* Read each of the counters. */ - for (i = 0; i < nr_stats; i++) { - struct mv88e6xxx_hw_stat *s = stats + i; - u32 low; - u32 high = 0; + for (i = 0; i < nr_stats; i++) + data[i] = _mv88e6xxx_get_ethtool_stat(ds, i, stats, port); - if (s->reg >= 0x100) { - ret = mv88e6xxx_reg_read(ds, REG_PORT(port), - s->reg - 0x100); - if (ret < 0) - goto error; - low = ret; - if (s->sizeof_stat == 4) { - ret = mv88e6xxx_reg_read(ds, REG_PORT(port), - s->reg - 0x100 + 1); - if (ret < 0) - goto error; - high = ret; - } - data[i] = (((u64)high) << 16) | low; - continue; - } - mv88e6xxx_stats_read(ds, s->reg, &low); - if (s->sizeof_stat == 8) - mv88e6xxx_stats_read(ds, s->reg + 1, &high); - - data[i] = (((u64)high) << 32) | low; - } -error: - mutex_unlock(&ps->stats_mutex); + mutex_unlock(&ps->smi_mutex); } /* All the statistics in the table */ @@ -694,7 +806,7 @@ int mv88e6xxx_get_temp(struct dsa_switch *ds, int *temp) *temp = 0; - mutex_lock(&ps->phy_mutex); + mutex_lock(&ps->smi_mutex); ret = _mv88e6xxx_phy_write(ds, 0x0, 0x16, 0x6); if (ret < 0) @@ -727,19 +839,23 @@ int mv88e6xxx_get_temp(struct dsa_switch *ds, int *temp) error: _mv88e6xxx_phy_write(ds, 0x0, 0x16, 0x0); - mutex_unlock(&ps->phy_mutex); + mutex_unlock(&ps->smi_mutex); return ret; } #endif /* CONFIG_NET_DSA_HWMON */ -static int mv88e6xxx_wait(struct dsa_switch *ds, int reg, int offset, u16 mask) +/* Must be called with SMI lock held */ +static int _mv88e6xxx_wait(struct dsa_switch *ds, int reg, int offset, + u16 mask) { unsigned long timeout = jiffies + HZ / 10; while (time_before(jiffies, timeout)) { int ret; - ret = REG_READ(reg, offset); + ret = _mv88e6xxx_reg_read(ds, reg, offset); + if (ret < 0) + return ret; if (!(ret & mask)) return 0; @@ -748,10 +864,22 @@ static int mv88e6xxx_wait(struct dsa_switch *ds, int reg, int offset, u16 mask) return -ETIMEDOUT; } -int mv88e6xxx_phy_wait(struct dsa_switch *ds) +static int mv88e6xxx_wait(struct dsa_switch *ds, int reg, int offset, u16 mask) { - return mv88e6xxx_wait(ds, REG_GLOBAL2, GLOBAL2_SMI_OP, - GLOBAL2_SMI_OP_BUSY); + struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); + int ret; + + mutex_lock(&ps->smi_mutex); + ret = _mv88e6xxx_wait(ds, reg, offset, mask); + mutex_unlock(&ps->smi_mutex); + + return ret; +} + +static int _mv88e6xxx_phy_wait(struct dsa_switch *ds) +{ + return _mv88e6xxx_wait(ds, REG_GLOBAL2, GLOBAL2_SMI_OP, + GLOBAL2_SMI_OP_BUSY); } int mv88e6xxx_eeprom_load_wait(struct dsa_switch *ds) @@ -767,56 +895,53 @@ int mv88e6xxx_eeprom_busy_wait(struct dsa_switch *ds) } /* Must be called with SMI lock held */ -static int _mv88e6xxx_wait(struct dsa_switch *ds, int reg, int offset, u16 mask) +static int _mv88e6xxx_atu_wait(struct dsa_switch *ds) { - unsigned long timeout = jiffies + HZ / 10; - - while (time_before(jiffies, timeout)) { - int ret; - - ret = _mv88e6xxx_reg_read(ds, reg, offset); - if (ret < 0) - return ret; - if (!(ret & mask)) - return 0; - - usleep_range(1000, 2000); - } - return -ETIMEDOUT; + return _mv88e6xxx_wait(ds, REG_GLOBAL, GLOBAL_ATU_OP, + GLOBAL_ATU_OP_BUSY); } /* Must be called with SMI lock held */ -static int _mv88e6xxx_atu_wait(struct dsa_switch *ds) +static int _mv88e6xxx_scratch_wait(struct dsa_switch *ds) { - return _mv88e6xxx_wait(ds, REG_GLOBAL, GLOBAL_ATU_OP, - GLOBAL_ATU_OP_BUSY); + return _mv88e6xxx_wait(ds, REG_GLOBAL2, GLOBAL2_SCRATCH_MISC, + GLOBAL2_SCRATCH_BUSY); } -/* Must be called with phy mutex held */ +/* Must be called with SMI mutex held */ static int _mv88e6xxx_phy_read_indirect(struct dsa_switch *ds, int addr, int regnum) { int ret; - REG_WRITE(REG_GLOBAL2, GLOBAL2_SMI_OP, - GLOBAL2_SMI_OP_22_READ | (addr << 5) | regnum); + ret = _mv88e6xxx_reg_write(ds, REG_GLOBAL2, GLOBAL2_SMI_OP, + GLOBAL2_SMI_OP_22_READ | (addr << 5) | + regnum); + if (ret < 0) + return ret; - ret = mv88e6xxx_phy_wait(ds); + ret = _mv88e6xxx_phy_wait(ds); if (ret < 0) return ret; - return REG_READ(REG_GLOBAL2, GLOBAL2_SMI_DATA); + return _mv88e6xxx_reg_read(ds, REG_GLOBAL2, GLOBAL2_SMI_DATA); } -/* Must be called with phy mutex held */ +/* Must be called with SMI mutex held */ static int _mv88e6xxx_phy_write_indirect(struct dsa_switch *ds, int addr, int regnum, u16 val) { - REG_WRITE(REG_GLOBAL2, GLOBAL2_SMI_DATA, val); - REG_WRITE(REG_GLOBAL2, GLOBAL2_SMI_OP, - GLOBAL2_SMI_OP_22_WRITE | (addr << 5) | regnum); + int ret; - return mv88e6xxx_phy_wait(ds); + ret = _mv88e6xxx_reg_write(ds, REG_GLOBAL2, GLOBAL2_SMI_DATA, val); + if (ret < 0) + return ret; + + ret = _mv88e6xxx_reg_write(ds, REG_GLOBAL2, GLOBAL2_SMI_OP, + GLOBAL2_SMI_OP_22_WRITE | (addr << 5) | + regnum); + + return _mv88e6xxx_phy_wait(ds); } int mv88e6xxx_get_eee(struct dsa_switch *ds, int port, struct ethtool_eee *e) @@ -824,7 +949,7 @@ int mv88e6xxx_get_eee(struct dsa_switch *ds, int port, struct ethtool_eee *e) struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); int reg; - mutex_lock(&ps->phy_mutex); + mutex_lock(&ps->smi_mutex); reg = _mv88e6xxx_phy_read_indirect(ds, port, 16); if (reg < 0) @@ -833,7 +958,7 @@ int mv88e6xxx_get_eee(struct dsa_switch *ds, int port, struct ethtool_eee *e) e->eee_enabled = !!(reg & 0x0200); e->tx_lpi_enabled = !!(reg & 0x0100); - reg = mv88e6xxx_reg_read(ds, REG_PORT(port), PORT_STATUS); + reg = _mv88e6xxx_reg_read(ds, REG_PORT(port), PORT_STATUS); if (reg < 0) goto out; @@ -841,7 +966,7 @@ int mv88e6xxx_get_eee(struct dsa_switch *ds, int port, struct ethtool_eee *e) reg = 0; out: - mutex_unlock(&ps->phy_mutex); + mutex_unlock(&ps->smi_mutex); return reg; } @@ -852,7 +977,7 @@ int mv88e6xxx_set_eee(struct dsa_switch *ds, int port, int reg; int ret; - mutex_lock(&ps->phy_mutex); + mutex_lock(&ps->smi_mutex); ret = _mv88e6xxx_phy_read_indirect(ds, port, 16); if (ret < 0) @@ -866,7 +991,7 @@ int mv88e6xxx_set_eee(struct dsa_switch *ds, int port, ret = _mv88e6xxx_phy_write_indirect(ds, port, 16, reg); out: - mutex_unlock(&ps->phy_mutex); + mutex_unlock(&ps->smi_mutex); return ret; } @@ -1241,13 +1366,212 @@ static void mv88e6xxx_bridge_work(struct work_struct *work) } } -int mv88e6xxx_setup_port_common(struct dsa_switch *ds, int port) +static int mv88e6xxx_setup_port(struct dsa_switch *ds, int port) { struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); int ret, fid; + u16 reg; mutex_lock(&ps->smi_mutex); + if (mv88e6xxx_6352_family(ds) || mv88e6xxx_6351_family(ds) || + mv88e6xxx_6165_family(ds) || mv88e6xxx_6097_family(ds) || + mv88e6xxx_6185_family(ds) || mv88e6xxx_6095_family(ds) || + mv88e6xxx_6065_family(ds)) { + /* MAC Forcing register: don't force link, speed, + * duplex or flow control state to any particular + * values on physical ports, but force the CPU port + * and all DSA ports to their maximum bandwidth and + * full duplex. + */ + reg = _mv88e6xxx_reg_read(ds, REG_PORT(port), PORT_PCS_CTRL); + if (dsa_is_cpu_port(ds, port) || + ds->dsa_port_mask & (1 << port)) { + reg |= PORT_PCS_CTRL_FORCE_LINK | + PORT_PCS_CTRL_LINK_UP | + PORT_PCS_CTRL_DUPLEX_FULL | + PORT_PCS_CTRL_FORCE_DUPLEX; + if (mv88e6xxx_6065_family(ds)) + reg |= PORT_PCS_CTRL_100; + else + reg |= PORT_PCS_CTRL_1000; + } else { + reg |= PORT_PCS_CTRL_UNFORCED; + } + + ret = _mv88e6xxx_reg_write(ds, REG_PORT(port), + PORT_PCS_CTRL, reg); + if (ret) + goto abort; + } + + /* Port Control: disable Drop-on-Unlock, disable Drop-on-Lock, + * disable Header mode, enable IGMP/MLD snooping, disable VLAN + * tunneling, determine priority by looking at 802.1p and IP + * priority fields (IP prio has precedence), and set STP state + * to Forwarding. + * + * If this is the CPU link, use DSA or EDSA tagging depending + * on which tagging mode was configured. + * + * If this is a link to another switch, use DSA tagging mode. + * + * If this is the upstream port for this switch, enable + * forwarding of unknown unicasts and multicasts. + */ + reg = 0; + if (mv88e6xxx_6352_family(ds) || mv88e6xxx_6351_family(ds) || + mv88e6xxx_6165_family(ds) || mv88e6xxx_6097_family(ds) || + mv88e6xxx_6095_family(ds) || mv88e6xxx_6065_family(ds) || + mv88e6xxx_6185_family(ds)) + reg = PORT_CONTROL_IGMP_MLD_SNOOP | + PORT_CONTROL_USE_TAG | PORT_CONTROL_USE_IP | + PORT_CONTROL_STATE_FORWARDING; + if (dsa_is_cpu_port(ds, port)) { + if (mv88e6xxx_6095_family(ds) || mv88e6xxx_6185_family(ds)) + reg |= PORT_CONTROL_DSA_TAG; + if (mv88e6xxx_6352_family(ds) || mv88e6xxx_6351_family(ds) || + mv88e6xxx_6165_family(ds) || mv88e6xxx_6097_family(ds)) { + if (ds->dst->tag_protocol == DSA_TAG_PROTO_EDSA) + reg |= PORT_CONTROL_FRAME_ETHER_TYPE_DSA; + else + reg |= PORT_CONTROL_FRAME_MODE_DSA; + } + + if (mv88e6xxx_6352_family(ds) || mv88e6xxx_6351_family(ds) || + mv88e6xxx_6165_family(ds) || mv88e6xxx_6097_family(ds) || + mv88e6xxx_6095_family(ds) || mv88e6xxx_6065_family(ds) || + mv88e6xxx_6185_family(ds)) { + if (ds->dst->tag_protocol == DSA_TAG_PROTO_EDSA) + reg |= PORT_CONTROL_EGRESS_ADD_TAG; + } + } + if (mv88e6xxx_6352_family(ds) || mv88e6xxx_6351_family(ds) || + mv88e6xxx_6165_family(ds) || mv88e6xxx_6097_family(ds) || + mv88e6xxx_6095_family(ds) || mv88e6xxx_6065_family(ds)) { + if (ds->dsa_port_mask & (1 << port)) + reg |= PORT_CONTROL_FRAME_MODE_DSA; + if (port == dsa_upstream_port(ds)) + reg |= PORT_CONTROL_FORWARD_UNKNOWN | + PORT_CONTROL_FORWARD_UNKNOWN_MC; + } + if (reg) { + ret = _mv88e6xxx_reg_write(ds, REG_PORT(port), + PORT_CONTROL, reg); + if (ret) + goto abort; + } + + /* Port Control 2: don't force a good FCS, set the maximum + * frame size to 10240 bytes, don't let the switch add or + * strip 802.1q tags, don't discard tagged or untagged frames + * on this port, do a destination address lookup on all + * received packets as usual, disable ARP mirroring and don't + * send a copy of all transmitted/received frames on this port + * to the CPU. + */ + reg = 0; + if (mv88e6xxx_6352_family(ds) || mv88e6xxx_6351_family(ds) || + mv88e6xxx_6165_family(ds) || mv88e6xxx_6097_family(ds) || + mv88e6xxx_6095_family(ds)) + reg = PORT_CONTROL_2_MAP_DA; + + if (mv88e6xxx_6352_family(ds) || mv88e6xxx_6351_family(ds) || + mv88e6xxx_6165_family(ds)) + reg |= PORT_CONTROL_2_JUMBO_10240; + + if (mv88e6xxx_6095_family(ds) || mv88e6xxx_6185_family(ds)) { + /* Set the upstream port this port should use */ + reg |= dsa_upstream_port(ds); + /* enable forwarding of unknown multicast addresses to + * the upstream port + */ + if (port == dsa_upstream_port(ds)) + reg |= PORT_CONTROL_2_FORWARD_UNKNOWN; + } + + if (reg) { + ret = _mv88e6xxx_reg_write(ds, REG_PORT(port), + PORT_CONTROL_2, reg); + if (ret) + goto abort; + } + + /* Port Association Vector: when learning source addresses + * of packets, add the address to the address database using + * a port bitmap that has only the bit for this port set and + * the other bits clear. + */ + ret = _mv88e6xxx_reg_write(ds, REG_PORT(port), PORT_ASSOC_VECTOR, + 1 << port); + if (ret) + goto abort; + + /* Egress rate control 2: disable egress rate control. */ + ret = _mv88e6xxx_reg_write(ds, REG_PORT(port), PORT_RATE_CONTROL_2, + 0x0000); + if (ret) + goto abort; + + if (mv88e6xxx_6352_family(ds) || mv88e6xxx_6351_family(ds) || + mv88e6xxx_6165_family(ds) || mv88e6xxx_6097_family(ds)) { + /* Do not limit the period of time that this port can + * be paused for by the remote end or the period of + * time that this port can pause the remote end. + */ + ret = _mv88e6xxx_reg_write(ds, REG_PORT(port), + PORT_PAUSE_CTRL, 0x0000); + if (ret) + goto abort; + + /* Port ATU control: disable limiting the number of + * address database entries that this port is allowed + * to use. + */ + ret = _mv88e6xxx_reg_write(ds, REG_PORT(port), + PORT_ATU_CONTROL, 0x0000); + /* Priority Override: disable DA, SA and VTU priority + * override. + */ + ret = _mv88e6xxx_reg_write(ds, REG_PORT(port), + PORT_PRI_OVERRIDE, 0x0000); + if (ret) + goto abort; + + /* Port Ethertype: use the Ethertype DSA Ethertype + * value. + */ + ret = _mv88e6xxx_reg_write(ds, REG_PORT(port), + PORT_ETH_TYPE, ETH_P_EDSA); + if (ret) + goto abort; + /* Tag Remap: use an identity 802.1p prio -> switch + * prio mapping. + */ + ret = _mv88e6xxx_reg_write(ds, REG_PORT(port), + PORT_TAG_REGMAP_0123, 0x3210); + if (ret) + goto abort; + + /* Tag Remap 2: use an identity 802.1p prio -> switch + * prio mapping. + */ + ret = _mv88e6xxx_reg_write(ds, REG_PORT(port), + PORT_TAG_REGMAP_4567, 0x7654); + if (ret) + goto abort; + } + + if (mv88e6xxx_6352_family(ds) || mv88e6xxx_6351_family(ds) || + mv88e6xxx_6165_family(ds) || mv88e6xxx_6097_family(ds) || + mv88e6xxx_6185_family(ds) || mv88e6xxx_6095_family(ds)) { + /* Rate Control: disable ingress rate limiting. */ + ret = _mv88e6xxx_reg_write(ds, REG_PORT(port), + PORT_RATE_CONTROL, 0x0001); + if (ret) + goto abort; + } + /* Port Control 1: disable trunking, disable sending * learning messages to this port. */ @@ -1281,13 +1605,283 @@ abort: return ret; } +int mv88e6xxx_setup_ports(struct dsa_switch *ds) +{ + struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); + int ret; + int i; + + for (i = 0; i < ps->num_ports; i++) { + ret = mv88e6xxx_setup_port(ds, i); + if (ret < 0) + return ret; + } + return 0; +} + +static int mv88e6xxx_regs_show(struct seq_file *s, void *p) +{ + struct dsa_switch *ds = s->private; + + struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); + int reg, port; + + seq_puts(s, " GLOBAL GLOBAL2 "); + for (port = 0 ; port < ps->num_ports; port++) + seq_printf(s, " %2d ", port); + seq_puts(s, "\n"); + + for (reg = 0; reg < 32; reg++) { + seq_printf(s, "%2x: ", reg); + seq_printf(s, " %4x %4x ", + mv88e6xxx_reg_read(ds, REG_GLOBAL, reg), + mv88e6xxx_reg_read(ds, REG_GLOBAL2, reg)); + + for (port = 0 ; port < ps->num_ports; port++) + seq_printf(s, "%4x ", + mv88e6xxx_reg_read(ds, REG_PORT(port), reg)); + seq_puts(s, "\n"); + } + + return 0; +} + +static int mv88e6xxx_regs_open(struct inode *inode, struct file *file) +{ + return single_open(file, mv88e6xxx_regs_show, inode->i_private); +} + +static const struct file_operations mv88e6xxx_regs_fops = { + .open = mv88e6xxx_regs_open, + .read = seq_read, + .llseek = no_llseek, + .release = single_release, + .owner = THIS_MODULE, +}; + +static void mv88e6xxx_atu_show_header(struct seq_file *s) +{ + seq_puts(s, "DB T/P Vec State Addr\n"); +} + +static void mv88e6xxx_atu_show_entry(struct seq_file *s, int dbnum, + unsigned char *addr, int data) +{ + bool trunk = !!(data & GLOBAL_ATU_DATA_TRUNK); + int portvec = ((data & GLOBAL_ATU_DATA_PORT_VECTOR_MASK) >> + GLOBAL_ATU_DATA_PORT_VECTOR_SHIFT); + int state = data & GLOBAL_ATU_DATA_STATE_MASK; + + seq_printf(s, "%03x %5s %10pb %x %pM\n", + dbnum, (trunk ? "Trunk" : "Port"), &portvec, state, addr); +} + +static int mv88e6xxx_atu_show_db(struct seq_file *s, struct dsa_switch *ds, + int dbnum) +{ + unsigned char bcast[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; + unsigned char addr[6]; + int ret, data, state; + + ret = __mv88e6xxx_write_addr(ds, bcast); + if (ret < 0) + return ret; + + do { + ret = _mv88e6xxx_atu_cmd(ds, dbnum, GLOBAL_ATU_OP_GET_NEXT_DB); + if (ret < 0) + return ret; + data = _mv88e6xxx_reg_read(ds, REG_GLOBAL, GLOBAL_ATU_DATA); + if (data < 0) + return data; + + state = data & GLOBAL_ATU_DATA_STATE_MASK; + if (state == GLOBAL_ATU_DATA_STATE_UNUSED) + break; + ret = __mv88e6xxx_read_addr(ds, addr); + if (ret < 0) + return ret; + mv88e6xxx_atu_show_entry(s, dbnum, addr, data); + } while (state != GLOBAL_ATU_DATA_STATE_UNUSED); + + return 0; +} + +static int mv88e6xxx_atu_show(struct seq_file *s, void *p) +{ + struct dsa_switch *ds = s->private; + struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); + int dbnum; + + mv88e6xxx_atu_show_header(s); + + for (dbnum = 0; dbnum < 255; dbnum++) { + mutex_lock(&ps->smi_mutex); + mv88e6xxx_atu_show_db(s, ds, dbnum); + mutex_unlock(&ps->smi_mutex); + } + + return 0; +} + +static int mv88e6xxx_atu_open(struct inode *inode, struct file *file) +{ + return single_open(file, mv88e6xxx_atu_show, inode->i_private); +} + +static const struct file_operations mv88e6xxx_atu_fops = { + .open = mv88e6xxx_atu_open, + .read = seq_read, + .llseek = no_llseek, + .release = single_release, + .owner = THIS_MODULE, +}; + +static void mv88e6xxx_stats_show_header(struct seq_file *s, + struct mv88e6xxx_priv_state *ps) +{ + int port; + + seq_puts(s, " Statistic "); + for (port = 0 ; port < ps->num_ports; port++) + seq_printf(s, "Port %2d ", port); + seq_puts(s, "\n"); +} + +static int mv88e6xxx_stats_show(struct seq_file *s, void *p) +{ + struct dsa_switch *ds = s->private; + struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); + struct mv88e6xxx_hw_stat *stats = mv88e6xxx_hw_stats; + int port, stat, max_stats; + uint64_t value; + + if (have_sw_in_discards(ds)) + max_stats = ARRAY_SIZE(mv88e6xxx_hw_stats); + else + max_stats = ARRAY_SIZE(mv88e6xxx_hw_stats) - 3; + + mv88e6xxx_stats_show_header(s, ps); + + mutex_lock(&ps->smi_mutex); + + for (stat = 0; stat < max_stats; stat++) { + seq_printf(s, "%19s: ", stats[stat].string); + for (port = 0 ; port < ps->num_ports; port++) { + _mv88e6xxx_stats_snapshot(ds, port); + value = _mv88e6xxx_get_ethtool_stat(ds, stat, stats, + port); + seq_printf(s, "%8llu ", value); + } + seq_puts(s, "\n"); + } + mutex_unlock(&ps->smi_mutex); + + return 0; +} + +static int mv88e6xxx_stats_open(struct inode *inode, struct file *file) +{ + return single_open(file, mv88e6xxx_stats_show, inode->i_private); +} + +static const struct file_operations mv88e6xxx_stats_fops = { + .open = mv88e6xxx_stats_open, + .read = seq_read, + .llseek = no_llseek, + .release = single_release, + .owner = THIS_MODULE, +}; + +static int mv88e6xxx_device_map_show(struct seq_file *s, void *p) +{ + struct dsa_switch *ds = s->private; + struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); + int target, ret; + + seq_puts(s, "Target Port\n"); + + mutex_lock(&ps->smi_mutex); + for (target = 0; target < 32; target++) { + ret = _mv88e6xxx_reg_write( + ds, REG_GLOBAL2, GLOBAL2_DEVICE_MAPPING, + target << GLOBAL2_DEVICE_MAPPING_TARGET_SHIFT); + if (ret < 0) + goto out; + ret = _mv88e6xxx_reg_read(ds, REG_GLOBAL2, + GLOBAL2_DEVICE_MAPPING); + seq_printf(s, " %2d %2d\n", target, + ret & GLOBAL2_DEVICE_MAPPING_PORT_MASK); + } +out: + mutex_unlock(&ps->smi_mutex); + + return 0; +} + +static int mv88e6xxx_device_map_open(struct inode *inode, struct file *file) +{ + return single_open(file, mv88e6xxx_device_map_show, inode->i_private); +} + +static const struct file_operations mv88e6xxx_device_map_fops = { + .open = mv88e6xxx_device_map_open, + .read = seq_read, + .llseek = no_llseek, + .release = single_release, + .owner = THIS_MODULE, +}; + +static int mv88e6xxx_scratch_show(struct seq_file *s, void *p) +{ + struct dsa_switch *ds = s->private; + struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); + int reg, ret; + + seq_puts(s, "Register Value\n"); + + mutex_lock(&ps->smi_mutex); + for (reg = 0; reg < 0x80; reg++) { + ret = _mv88e6xxx_reg_write( + ds, REG_GLOBAL2, GLOBAL2_SCRATCH_MISC, + reg << GLOBAL2_SCRATCH_REGISTER_SHIFT); + if (ret < 0) + goto out; + + ret = _mv88e6xxx_scratch_wait(ds); + if (ret < 0) + goto out; + + ret = _mv88e6xxx_reg_read(ds, REG_GLOBAL2, + GLOBAL2_SCRATCH_MISC); + seq_printf(s, " %2x %2x\n", reg, + ret & GLOBAL2_SCRATCH_VALUE_MASK); + } +out: + mutex_unlock(&ps->smi_mutex); + + return 0; +} + +static int mv88e6xxx_scratch_open(struct inode *inode, struct file *file) +{ + return single_open(file, mv88e6xxx_scratch_show, inode->i_private); +} + +static const struct file_operations mv88e6xxx_scratch_fops = { + .open = mv88e6xxx_scratch_open, + .read = seq_read, + .llseek = no_llseek, + .release = single_release, + .owner = THIS_MODULE, +}; + int mv88e6xxx_setup_common(struct dsa_switch *ds) { struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); + char *name; mutex_init(&ps->smi_mutex); - mutex_init(&ps->stats_mutex); - mutex_init(&ps->phy_mutex); ps->id = REG_READ(REG_PORT(0), PORT_SWITCH_ID) & 0xfff0; @@ -1295,6 +1889,128 @@ int mv88e6xxx_setup_common(struct dsa_switch *ds) INIT_WORK(&ps->bridge_work, mv88e6xxx_bridge_work); + name = kasprintf(GFP_KERNEL, "dsa%d", ds->index); + ps->dbgfs = debugfs_create_dir(name, NULL); + kfree(name); + + debugfs_create_file("regs", S_IRUGO, ps->dbgfs, ds, + &mv88e6xxx_regs_fops); + + debugfs_create_file("atu", S_IRUGO, ps->dbgfs, ds, + &mv88e6xxx_atu_fops); + + debugfs_create_file("stats", S_IRUGO, ps->dbgfs, ds, + &mv88e6xxx_stats_fops); + + debugfs_create_file("device_map", S_IRUGO, ps->dbgfs, ds, + &mv88e6xxx_device_map_fops); + + debugfs_create_file("scratch", S_IRUGO, ps->dbgfs, ds, + &mv88e6xxx_scratch_fops); + return 0; +} + +int mv88e6xxx_setup_global(struct dsa_switch *ds) +{ + struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); + int i; + + /* Set the default address aging time to 5 minutes, and + * enable address learn messages to be sent to all message + * ports. + */ + REG_WRITE(REG_GLOBAL, GLOBAL_ATU_CONTROL, + 0x0140 | GLOBAL_ATU_CONTROL_LEARN2ALL); + + /* Configure the IP ToS mapping registers. */ + REG_WRITE(REG_GLOBAL, GLOBAL_IP_PRI_0, 0x0000); + REG_WRITE(REG_GLOBAL, GLOBAL_IP_PRI_1, 0x0000); + REG_WRITE(REG_GLOBAL, GLOBAL_IP_PRI_2, 0x5555); + REG_WRITE(REG_GLOBAL, GLOBAL_IP_PRI_3, 0x5555); + REG_WRITE(REG_GLOBAL, GLOBAL_IP_PRI_4, 0xaaaa); + REG_WRITE(REG_GLOBAL, GLOBAL_IP_PRI_5, 0xaaaa); + REG_WRITE(REG_GLOBAL, GLOBAL_IP_PRI_6, 0xffff); + REG_WRITE(REG_GLOBAL, GLOBAL_IP_PRI_7, 0xffff); + + /* Configure the IEEE 802.1p priority mapping register. */ + REG_WRITE(REG_GLOBAL, GLOBAL_IEEE_PRI, 0xfa41); + + /* Send all frames with destination addresses matching + * 01:80:c2:00:00:0x to the CPU port. + */ + REG_WRITE(REG_GLOBAL2, GLOBAL2_MGMT_EN_0X, 0xffff); + + /* Ignore removed tag data on doubly tagged packets, disable + * flow control messages, force flow control priority to the + * highest, and send all special multicast frames to the CPU + * port at the highest priority. + */ + REG_WRITE(REG_GLOBAL2, GLOBAL2_SWITCH_MGMT, + 0x7 | GLOBAL2_SWITCH_MGMT_RSVD2CPU | 0x70 | + GLOBAL2_SWITCH_MGMT_FORCE_FLOW_CTRL_PRI); + + /* Program the DSA routing table. */ + for (i = 0; i < 32; i++) { + int nexthop = 0x1f; + + if (ds->pd->rtable && + i != ds->index && i < ds->dst->pd->nr_chips) + nexthop = ds->pd->rtable[i] & 0x1f; + + REG_WRITE(REG_GLOBAL2, GLOBAL2_DEVICE_MAPPING, + GLOBAL2_DEVICE_MAPPING_UPDATE | + (i << GLOBAL2_DEVICE_MAPPING_TARGET_SHIFT) | + nexthop); + } + + /* Clear all trunk masks. */ + for (i = 0; i < 8; i++) + REG_WRITE(REG_GLOBAL2, GLOBAL2_TRUNK_MASK, + 0x8000 | (i << GLOBAL2_TRUNK_MASK_NUM_SHIFT) | + ((1 << ps->num_ports) - 1)); + + /* Clear all trunk mappings. */ + for (i = 0; i < 16; i++) + REG_WRITE(REG_GLOBAL2, GLOBAL2_TRUNK_MAPPING, + GLOBAL2_TRUNK_MAPPING_UPDATE | + (i << GLOBAL2_TRUNK_MAPPING_ID_SHIFT)); + + if (mv88e6xxx_6352_family(ds) || mv88e6xxx_6351_family(ds) || + mv88e6xxx_6165_family(ds) || mv88e6xxx_6097_family(ds)) { + /* Send all frames with destination addresses matching + * 01:80:c2:00:00:2x to the CPU port. + */ + REG_WRITE(REG_GLOBAL2, GLOBAL2_MGMT_EN_2X, 0xffff); + + /* Initialise cross-chip port VLAN table to reset + * defaults. + */ + REG_WRITE(REG_GLOBAL2, GLOBAL2_PVT_ADDR, 0x9000); + + /* Clear the priority override table. */ + for (i = 0; i < 16; i++) + REG_WRITE(REG_GLOBAL2, GLOBAL2_PRIO_OVERRIDE, + 0x8000 | (i << 8)); + } + + if (mv88e6xxx_6352_family(ds) || mv88e6xxx_6351_family(ds) || + mv88e6xxx_6165_family(ds) || mv88e6xxx_6097_family(ds) || + mv88e6xxx_6185_family(ds) || mv88e6xxx_6095_family(ds)) { + /* Disable ingress rate limiting by resetting all + * ingress rate limit registers to their initial + * state. + */ + for (i = 0; i < ps->num_ports; i++) + REG_WRITE(REG_GLOBAL2, GLOBAL2_INGRESS_OP, + 0x9000 | (i << 8)); + } + + /* Clear the statistics counters for all ports */ + REG_WRITE(REG_GLOBAL, GLOBAL_STATS_OP, GLOBAL_STATS_OP_FLUSH_ALL); + + /* Wait for the flush to complete. */ + _mv88e6xxx_stats_wait(ds); + return 0; } @@ -1343,14 +2059,14 @@ int mv88e6xxx_phy_page_read(struct dsa_switch *ds, int port, int page, int reg) struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); int ret; - mutex_lock(&ps->phy_mutex); + mutex_lock(&ps->smi_mutex); ret = _mv88e6xxx_phy_write_indirect(ds, port, 0x16, page); if (ret < 0) goto error; ret = _mv88e6xxx_phy_read_indirect(ds, port, reg); error: _mv88e6xxx_phy_write_indirect(ds, port, 0x16, 0x0); - mutex_unlock(&ps->phy_mutex); + mutex_unlock(&ps->smi_mutex); return ret; } @@ -1360,7 +2076,7 @@ int mv88e6xxx_phy_page_write(struct dsa_switch *ds, int port, int page, struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); int ret; - mutex_lock(&ps->phy_mutex); + mutex_lock(&ps->smi_mutex); ret = _mv88e6xxx_phy_write_indirect(ds, port, 0x16, page); if (ret < 0) goto error; @@ -1368,7 +2084,7 @@ int mv88e6xxx_phy_page_write(struct dsa_switch *ds, int port, int page, ret = _mv88e6xxx_phy_write_indirect(ds, port, reg, val); error: _mv88e6xxx_phy_write_indirect(ds, port, 0x16, 0x0); - mutex_unlock(&ps->phy_mutex); + mutex_unlock(&ps->smi_mutex); return ret; } @@ -1391,9 +2107,9 @@ mv88e6xxx_phy_read(struct dsa_switch *ds, int port, int regnum) if (addr < 0) return addr; - mutex_lock(&ps->phy_mutex); + mutex_lock(&ps->smi_mutex); ret = _mv88e6xxx_phy_read(ds, addr, regnum); - mutex_unlock(&ps->phy_mutex); + mutex_unlock(&ps->smi_mutex); return ret; } @@ -1407,9 +2123,9 @@ mv88e6xxx_phy_write(struct dsa_switch *ds, int port, int regnum, u16 val) if (addr < 0) return addr; - mutex_lock(&ps->phy_mutex); + mutex_lock(&ps->smi_mutex); ret = _mv88e6xxx_phy_write(ds, addr, regnum, val); - mutex_unlock(&ps->phy_mutex); + mutex_unlock(&ps->smi_mutex); return ret; } @@ -1423,9 +2139,9 @@ mv88e6xxx_phy_read_indirect(struct dsa_switch *ds, int port, int regnum) if (addr < 0) return addr; - mutex_lock(&ps->phy_mutex); + mutex_lock(&ps->smi_mutex); ret = _mv88e6xxx_phy_read_indirect(ds, addr, regnum); - mutex_unlock(&ps->phy_mutex); + mutex_unlock(&ps->smi_mutex); return ret; } @@ -1440,9 +2156,9 @@ mv88e6xxx_phy_write_indirect(struct dsa_switch *ds, int port, int regnum, if (addr < 0) return addr; - mutex_lock(&ps->phy_mutex); + mutex_lock(&ps->smi_mutex); ret = _mv88e6xxx_phy_write_indirect(ds, addr, regnum, val); - mutex_unlock(&ps->phy_mutex); + mutex_unlock(&ps->smi_mutex); return ret; } |