|
@@ -19,6 +19,34 @@
|
|
|
#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 +61,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 +77,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 +85,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 +96,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 +140,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 +148,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 +193,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 +227,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 +444,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 +558,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 +567,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;
|
|
|
|
|
@@ -587,11 +688,11 @@ 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;
|
|
|
}
|
|
|
|
|
@@ -608,8 +709,8 @@ static void _mv88e6xxx_get_ethtool_stats(struct dsa_switch *ds,
|
|
|
goto error;
|
|
|
low = ret;
|
|
|
if (s->sizeof_stat == 4) {
|
|
|
- ret = mv88e6xxx_reg_read(ds, REG_PORT(port),
|
|
|
- s->reg - 0x100 + 1);
|
|
|
+ ret = _mv88e6xxx_reg_read(ds, REG_PORT(port),
|
|
|
+ s->reg - 0x100 + 1);
|
|
|
if (ret < 0)
|
|
|
goto error;
|
|
|
high = ret;
|
|
@@ -617,14 +718,14 @@ static void _mv88e6xxx_get_ethtool_stats(struct dsa_switch *ds,
|
|
|
data[i] = (((u64)high) << 16) | low;
|
|
|
continue;
|
|
|
}
|
|
|
- mv88e6xxx_stats_read(ds, s->reg, &low);
|
|
|
+ _mv88e6xxx_stats_read(ds, s->reg, &low);
|
|
|
if (s->sizeof_stat == 8)
|
|
|
- mv88e6xxx_stats_read(ds, s->reg + 1, &high);
|
|
|
+ _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 +795,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 +828,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 +853,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)
|
|
|
+{
|
|
|
+ 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);
|
|
|
+ return _mv88e6xxx_wait(ds, REG_GLOBAL2, GLOBAL2_SMI_OP,
|
|
|
+ GLOBAL2_SMI_OP_BUSY);
|
|
|
}
|
|
|
|
|
|
int mv88e6xxx_eeprom_load_wait(struct dsa_switch *ds)
|
|
@@ -766,25 +883,6 @@ int mv88e6xxx_eeprom_busy_wait(struct dsa_switch *ds)
|
|
|
GLOBAL2_EEPROM_OP_BUSY);
|
|
|
}
|
|
|
|
|
|
-/* 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 = _mv88e6xxx_reg_read(ds, reg, offset);
|
|
|
- if (ret < 0)
|
|
|
- return ret;
|
|
|
- if (!(ret & mask))
|
|
|
- return 0;
|
|
|
-
|
|
|
- usleep_range(1000, 2000);
|
|
|
- }
|
|
|
- return -ETIMEDOUT;
|
|
|
-}
|
|
|
-
|
|
|
/* Must be called with SMI lock held */
|
|
|
static int _mv88e6xxx_atu_wait(struct dsa_switch *ds)
|
|
|
{
|
|
@@ -792,31 +890,40 @@ static int _mv88e6xxx_atu_wait(struct dsa_switch *ds)
|
|
|
GLOBAL_ATU_OP_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 +931,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 +940,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 +948,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 +959,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 +973,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 +1348,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 +1587,25 @@ 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;
|
|
|
+}
|
|
|
+
|
|
|
int mv88e6xxx_setup_common(struct dsa_switch *ds)
|
|
|
{
|
|
|
struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
|
|
|
|
|
|
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;
|
|
|
|
|
@@ -1298,6 +1616,104 @@ int mv88e6xxx_setup_common(struct dsa_switch *ds)
|
|
|
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));
|
|
|
+ }
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
int mv88e6xxx_switch_reset(struct dsa_switch *ds, bool ppu_active)
|
|
|
{
|
|
|
struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
|
|
@@ -1343,14 +1759,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 +1776,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 +1784,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 +1807,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 +1823,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 +1839,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 +1856,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;
|
|
|
}
|
|
|
|