summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/net/dsa/mv88e6xxx.c567
-rw-r--r--drivers/net/dsa/mv88e6xxx.h34
2 files changed, 385 insertions, 216 deletions
diff --git a/drivers/net/dsa/mv88e6xxx.c b/drivers/net/dsa/mv88e6xxx.c
index ee06055444f9..9b116d8d4e23 100644
--- a/drivers/net/dsa/mv88e6xxx.c
+++ b/drivers/net/dsa/mv88e6xxx.c
@@ -21,6 +21,7 @@
#include <linux/list.h>
#include <linux/mdio.h>
#include <linux/module.h>
+#include <linux/of_device.h>
#include <linux/of_mdio.h>
#include <linux/netdevice.h>
#include <linux/gpio/consumer.h>
@@ -29,29 +30,82 @@
#include <net/switchdev.h>
#include "mv88e6xxx.h"
-static void assert_smi_lock(struct mv88e6xxx_priv_state *ps)
+static void assert_reg_lock(struct mv88e6xxx_priv_state *ps)
{
- if (unlikely(!mutex_is_locked(&ps->smi_mutex))) {
- dev_err(ps->dev, "SMI lock not held!\n");
+ if (unlikely(!mutex_is_locked(&ps->reg_lock))) {
+ dev_err(ps->dev, "Switch registers lock not held!\n");
dump_stack();
}
}
-/* 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}
- * pair. If the ADDR[4:0] pins are not strapped to zero, the switch
- * will only respond to SMI transactions to that specific address, and
- * an indirect addressing mechanism needs to be used to access its
- * registers.
+/* The switch ADDR[4:1] configuration pins define the chip SMI device address
+ * (ADDR[0] is always zero, thus only even SMI addresses can be strapped).
+ *
+ * When ADDR is all zero, the chip uses Single-chip Addressing Mode, assuming it
+ * is the only device connected to the SMI master. In this mode it responds to
+ * all 32 possible SMI addresses, and thus maps directly the internal devices.
+ *
+ * When ADDR is non-zero, the chip uses Multi-chip Addressing Mode, allowing
+ * multiple devices to share the SMI interface. In this mode it responds to only
+ * 2 registers, used to indirectly access the internal SMI devices.
*/
-static int mv88e6xxx_reg_wait_ready(struct mii_bus *bus, int sw_addr)
+
+static int mv88e6xxx_smi_read(struct mv88e6xxx_priv_state *ps,
+ int addr, int reg, u16 *val)
+{
+ if (!ps->smi_ops)
+ return -EOPNOTSUPP;
+
+ return ps->smi_ops->read(ps, addr, reg, val);
+}
+
+static int mv88e6xxx_smi_write(struct mv88e6xxx_priv_state *ps,
+ int addr, int reg, u16 val)
+{
+ if (!ps->smi_ops)
+ return -EOPNOTSUPP;
+
+ return ps->smi_ops->write(ps, addr, reg, val);
+}
+
+static int mv88e6xxx_smi_single_chip_read(struct mv88e6xxx_priv_state *ps,
+ int addr, int reg, u16 *val)
+{
+ int ret;
+
+ ret = mdiobus_read_nested(ps->bus, addr, reg);
+ if (ret < 0)
+ return ret;
+
+ *val = ret & 0xffff;
+
+ return 0;
+}
+
+static int mv88e6xxx_smi_single_chip_write(struct mv88e6xxx_priv_state *ps,
+ int addr, int reg, u16 val)
+{
+ int ret;
+
+ ret = mdiobus_write_nested(ps->bus, addr, reg, val);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static const struct mv88e6xxx_ops mv88e6xxx_smi_single_chip_ops = {
+ .read = mv88e6xxx_smi_single_chip_read,
+ .write = mv88e6xxx_smi_single_chip_write,
+};
+
+static int mv88e6xxx_smi_multi_chip_wait(struct mv88e6xxx_priv_state *ps)
{
int ret;
int i;
for (i = 0; i < 16; i++) {
- ret = mdiobus_read_nested(bus, sw_addr, SMI_CMD);
+ ret = mdiobus_read_nested(ps->bus, ps->sw_addr, SMI_CMD);
if (ret < 0)
return ret;
@@ -62,117 +116,144 @@ static int mv88e6xxx_reg_wait_ready(struct mii_bus *bus, int sw_addr)
return -ETIMEDOUT;
}
-static int __mv88e6xxx_reg_read(struct mii_bus *bus, int sw_addr, int addr,
- int reg)
+static int mv88e6xxx_smi_multi_chip_read(struct mv88e6xxx_priv_state *ps,
+ int addr, int reg, u16 *val)
{
int ret;
- if (sw_addr == 0)
- return mdiobus_read_nested(bus, addr, reg);
-
/* Wait for the bus to become free. */
- ret = mv88e6xxx_reg_wait_ready(bus, sw_addr);
+ ret = mv88e6xxx_smi_multi_chip_wait(ps);
if (ret < 0)
return ret;
/* Transmit the read command. */
- ret = mdiobus_write_nested(bus, sw_addr, SMI_CMD,
+ ret = mdiobus_write_nested(ps->bus, ps->sw_addr, SMI_CMD,
SMI_CMD_OP_22_READ | (addr << 5) | reg);
if (ret < 0)
return ret;
/* Wait for the read command to complete. */
- ret = mv88e6xxx_reg_wait_ready(bus, sw_addr);
+ ret = mv88e6xxx_smi_multi_chip_wait(ps);
if (ret < 0)
return ret;
/* Read the data. */
- ret = mdiobus_read_nested(bus, sw_addr, SMI_DATA);
+ ret = mdiobus_read_nested(ps->bus, ps->sw_addr, SMI_DATA);
if (ret < 0)
return ret;
- return ret & 0xffff;
-}
-
-static int _mv88e6xxx_reg_read(struct mv88e6xxx_priv_state *ps,
- int addr, int reg)
-{
- int ret;
-
- assert_smi_lock(ps);
-
- ret = __mv88e6xxx_reg_read(ps->bus, ps->sw_addr, addr, reg);
- if (ret < 0)
- return ret;
-
- dev_dbg(ps->dev, "<- addr: 0x%.2x reg: 0x%.2x val: 0x%.4x\n",
- addr, reg, ret);
-
- return ret;
-}
-
-int mv88e6xxx_reg_read(struct mv88e6xxx_priv_state *ps, int addr, int reg)
-{
- int ret;
+ *val = ret & 0xffff;
- mutex_lock(&ps->smi_mutex);
- ret = _mv88e6xxx_reg_read(ps, addr, reg);
- mutex_unlock(&ps->smi_mutex);
-
- return ret;
+ return 0;
}
-static int __mv88e6xxx_reg_write(struct mii_bus *bus, int sw_addr, int addr,
- int reg, u16 val)
+static int mv88e6xxx_smi_multi_chip_write(struct mv88e6xxx_priv_state *ps,
+ int addr, int reg, u16 val)
{
int ret;
- if (sw_addr == 0)
- return mdiobus_write_nested(bus, addr, reg, val);
-
/* Wait for the bus to become free. */
- ret = mv88e6xxx_reg_wait_ready(bus, sw_addr);
+ ret = mv88e6xxx_smi_multi_chip_wait(ps);
if (ret < 0)
return ret;
/* Transmit the data to write. */
- ret = mdiobus_write_nested(bus, sw_addr, SMI_DATA, val);
+ ret = mdiobus_write_nested(ps->bus, ps->sw_addr, SMI_DATA, val);
if (ret < 0)
return ret;
/* Transmit the write command. */
- ret = mdiobus_write_nested(bus, sw_addr, SMI_CMD,
+ ret = mdiobus_write_nested(ps->bus, ps->sw_addr, SMI_CMD,
SMI_CMD_OP_22_WRITE | (addr << 5) | reg);
if (ret < 0)
return ret;
/* Wait for the write command to complete. */
- ret = mv88e6xxx_reg_wait_ready(bus, sw_addr);
+ ret = mv88e6xxx_smi_multi_chip_wait(ps);
if (ret < 0)
return ret;
return 0;
}
-static int _mv88e6xxx_reg_write(struct mv88e6xxx_priv_state *ps, int addr,
- int reg, u16 val)
+static const struct mv88e6xxx_ops mv88e6xxx_smi_multi_chip_ops = {
+ .read = mv88e6xxx_smi_multi_chip_read,
+ .write = mv88e6xxx_smi_multi_chip_write,
+};
+
+static int mv88e6xxx_read(struct mv88e6xxx_priv_state *ps,
+ int addr, int reg, u16 *val)
{
- assert_smi_lock(ps);
+ int err;
+
+ assert_reg_lock(ps);
+
+ err = mv88e6xxx_smi_read(ps, addr, reg, val);
+ if (err)
+ return err;
+
+ dev_dbg(ps->dev, "<- addr: 0x%.2x reg: 0x%.2x val: 0x%.4x\n",
+ addr, reg, *val);
+
+ return 0;
+}
+
+static int mv88e6xxx_write(struct mv88e6xxx_priv_state *ps,
+ int addr, int reg, u16 val)
+{
+ int err;
+
+ assert_reg_lock(ps);
+
+ err = mv88e6xxx_smi_write(ps, addr, reg, val);
+ if (err)
+ return err;
dev_dbg(ps->dev, "-> addr: 0x%.2x reg: 0x%.2x val: 0x%.4x\n",
addr, reg, val);
- return __mv88e6xxx_reg_write(ps->bus, ps->sw_addr, addr, reg, val);
+ return 0;
+}
+
+static int _mv88e6xxx_reg_read(struct mv88e6xxx_priv_state *ps,
+ int addr, int reg)
+{
+ u16 val;
+ int err;
+
+ err = mv88e6xxx_read(ps, addr, reg, &val);
+ if (err)
+ return err;
+
+ return val;
+}
+
+static int mv88e6xxx_reg_read(struct mv88e6xxx_priv_state *ps, int addr,
+ int reg)
+{
+ int ret;
+
+ mutex_lock(&ps->reg_lock);
+ ret = _mv88e6xxx_reg_read(ps, addr, reg);
+ mutex_unlock(&ps->reg_lock);
+
+ return ret;
}
-int mv88e6xxx_reg_write(struct mv88e6xxx_priv_state *ps, int addr,
- int reg, u16 val)
+static int _mv88e6xxx_reg_write(struct mv88e6xxx_priv_state *ps, int addr,
+ int reg, u16 val)
+{
+ return mv88e6xxx_write(ps, addr, reg, val);
+}
+
+static int mv88e6xxx_reg_write(struct mv88e6xxx_priv_state *ps, int addr,
+ int reg, u16 val)
{
int ret;
- mutex_lock(&ps->smi_mutex);
+ mutex_lock(&ps->reg_lock);
ret = _mv88e6xxx_reg_write(ps, addr, reg, val);
- mutex_unlock(&ps->smi_mutex);
+ mutex_unlock(&ps->reg_lock);
return ret;
}
@@ -229,7 +310,7 @@ static int mv88e6xxx_set_addr_indirect(struct dsa_switch *ds, u8 *addr)
return 0;
}
-int mv88e6xxx_set_addr(struct dsa_switch *ds, u8 *addr)
+static int mv88e6xxx_set_addr(struct dsa_switch *ds, u8 *addr)
{
struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
@@ -319,7 +400,7 @@ static void mv88e6xxx_ppu_reenable_work(struct work_struct *ugly)
ps = container_of(ugly, struct mv88e6xxx_priv_state, ppu_work);
- mutex_lock(&ps->smi_mutex);
+ mutex_lock(&ps->reg_lock);
if (mutex_trylock(&ps->ppu_mutex)) {
if (mv88e6xxx_ppu_enable(ps) == 0)
@@ -327,7 +408,7 @@ static void mv88e6xxx_ppu_reenable_work(struct work_struct *ugly)
mutex_unlock(&ps->ppu_mutex);
}
- mutex_unlock(&ps->smi_mutex);
+ mutex_unlock(&ps->reg_lock);
}
static void mv88e6xxx_ppu_reenable_timer(unsigned long _ps)
@@ -370,7 +451,7 @@ static void mv88e6xxx_ppu_access_put(struct mv88e6xxx_priv_state *ps)
mutex_unlock(&ps->ppu_mutex);
}
-void mv88e6xxx_ppu_state_init(struct mv88e6xxx_priv_state *ps)
+static void mv88e6xxx_ppu_state_init(struct mv88e6xxx_priv_state *ps)
{
mutex_init(&ps->ppu_mutex);
INIT_WORK(&ps->ppu_work, mv88e6xxx_ppu_reenable_work);
@@ -476,7 +557,7 @@ static void mv88e6xxx_adjust_link(struct dsa_switch *ds, int port,
if (!phy_is_pseudo_fixed_link(phydev))
return;
- mutex_lock(&ps->smi_mutex);
+ mutex_lock(&ps->reg_lock);
ret = _mv88e6xxx_reg_read(ps, REG_PORT(port), PORT_PCS_CTRL);
if (ret < 0)
@@ -490,7 +571,7 @@ static void mv88e6xxx_adjust_link(struct dsa_switch *ds, int port,
reg |= PORT_PCS_CTRL_FORCE_LINK;
if (phydev->link)
- reg |= PORT_PCS_CTRL_LINK_UP;
+ reg |= PORT_PCS_CTRL_LINK_UP;
if (mv88e6xxx_6065_family(ps) && phydev->speed > SPEED_100)
goto out;
@@ -527,7 +608,7 @@ static void mv88e6xxx_adjust_link(struct dsa_switch *ds, int port,
_mv88e6xxx_reg_write(ps, REG_PORT(port), PORT_PCS_CTRL, reg);
out:
- mutex_unlock(&ps->smi_mutex);
+ mutex_unlock(&ps->reg_lock);
}
static int _mv88e6xxx_stats_wait(struct mv88e6xxx_priv_state *ps)
@@ -752,11 +833,11 @@ static void mv88e6xxx_get_ethtool_stats(struct dsa_switch *ds, int port,
int ret;
int i, j;
- mutex_lock(&ps->smi_mutex);
+ mutex_lock(&ps->reg_lock);
ret = _mv88e6xxx_stats_snapshot(ps, port);
if (ret < 0) {
- mutex_unlock(&ps->smi_mutex);
+ mutex_unlock(&ps->reg_lock);
return;
}
for (i = 0, j = 0; i < ARRAY_SIZE(mv88e6xxx_hw_stats); i++) {
@@ -767,7 +848,7 @@ static void mv88e6xxx_get_ethtool_stats(struct dsa_switch *ds, int port,
}
}
- mutex_unlock(&ps->smi_mutex);
+ mutex_unlock(&ps->reg_lock);
}
static int mv88e6xxx_get_regs_len(struct dsa_switch *ds, int port)
@@ -786,7 +867,7 @@ static void mv88e6xxx_get_regs(struct dsa_switch *ds, int port,
memset(p, 0xff, 32 * sizeof(u16));
- mutex_lock(&ps->smi_mutex);
+ mutex_lock(&ps->reg_lock);
for (i = 0; i < 32; i++) {
int ret;
@@ -796,7 +877,7 @@ static void mv88e6xxx_get_regs(struct dsa_switch *ds, int port,
p[i] = ret;
}
- mutex_unlock(&ps->smi_mutex);
+ mutex_unlock(&ps->reg_lock);
}
static int _mv88e6xxx_wait(struct mv88e6xxx_priv_state *ps, int reg, int offset,
@@ -823,9 +904,9 @@ static int mv88e6xxx_wait(struct mv88e6xxx_priv_state *ps, int reg,
{
int ret;
- mutex_lock(&ps->smi_mutex);
+ mutex_lock(&ps->reg_lock);
ret = _mv88e6xxx_wait(ps, reg, offset, mask);
- mutex_unlock(&ps->smi_mutex);
+ mutex_unlock(&ps->reg_lock);
return ret;
}
@@ -1122,7 +1203,7 @@ static int mv88e6xxx_get_eee(struct dsa_switch *ds, int port,
if (!mv88e6xxx_has(ps, MV88E6XXX_FLAG_EEE))
return -EOPNOTSUPP;
- mutex_lock(&ps->smi_mutex);
+ mutex_lock(&ps->reg_lock);
reg = mv88e6xxx_mdio_read_indirect(ps, port, 16);
if (reg < 0)
@@ -1139,7 +1220,7 @@ static int mv88e6xxx_get_eee(struct dsa_switch *ds, int port,
reg = 0;
out:
- mutex_unlock(&ps->smi_mutex);
+ mutex_unlock(&ps->reg_lock);
return reg;
}
@@ -1153,7 +1234,7 @@ static int mv88e6xxx_set_eee(struct dsa_switch *ds, int port,
if (!mv88e6xxx_has(ps, MV88E6XXX_FLAG_EEE))
return -EOPNOTSUPP;
- mutex_lock(&ps->smi_mutex);
+ mutex_lock(&ps->reg_lock);
ret = mv88e6xxx_mdio_read_indirect(ps, port, 16);
if (ret < 0)
@@ -1167,7 +1248,7 @@ static int mv88e6xxx_set_eee(struct dsa_switch *ds, int port,
ret = mv88e6xxx_mdio_write_indirect(ps, port, 16, reg);
out:
- mutex_unlock(&ps->smi_mutex);
+ mutex_unlock(&ps->reg_lock);
return ret;
}
@@ -1314,9 +1395,9 @@ static int _mv88e6xxx_port_state(struct mv88e6xxx_priv_state *ps, int port,
* Blocking or Listening state.
*/
if ((oldstate == PORT_CONTROL_STATE_LEARNING ||
- oldstate == PORT_CONTROL_STATE_FORWARDING)
- && (state == PORT_CONTROL_STATE_DISABLED ||
- state == PORT_CONTROL_STATE_BLOCKING)) {
+ oldstate == PORT_CONTROL_STATE_FORWARDING) &&
+ (state == PORT_CONTROL_STATE_DISABLED ||
+ state == PORT_CONTROL_STATE_BLOCKING)) {
ret = _mv88e6xxx_atu_remove(ps, 0, port, false);
if (ret)
return ret;
@@ -1401,9 +1482,9 @@ static void mv88e6xxx_port_stp_state_set(struct dsa_switch *ds, int port,
break;
}
- mutex_lock(&ps->smi_mutex);
+ mutex_lock(&ps->reg_lock);
err = _mv88e6xxx_port_state(ps, port, stp_state);
- mutex_unlock(&ps->smi_mutex);
+ mutex_unlock(&ps->reg_lock);
if (err)
netdev_err(ds->ports[port].netdev,
@@ -1637,7 +1718,7 @@ static int mv88e6xxx_port_vlan_dump(struct dsa_switch *ds, int port,
if (!mv88e6xxx_has(ps, MV88E6XXX_FLAG_VTU))
return -EOPNOTSUPP;
- mutex_lock(&ps->smi_mutex);
+ mutex_lock(&ps->reg_lock);
err = _mv88e6xxx_port_pvid_get(ps, port, &pvid);
if (err)
@@ -1659,7 +1740,8 @@ static int mv88e6xxx_port_vlan_dump(struct dsa_switch *ds, int port,
continue;
/* reinit and dump this VLAN obj */
- vlan->vid_begin = vlan->vid_end = next.vid;
+ vlan->vid_begin = next.vid;
+ vlan->vid_end = next.vid;
vlan->flags = 0;
if (next.data[port] == GLOBAL_VTU_DATA_MEMBER_TAG_UNTAGGED)
@@ -1674,7 +1756,7 @@ static int mv88e6xxx_port_vlan_dump(struct dsa_switch *ds, int port,
} while (next.vid < GLOBAL_VTU_VID_MASK);
unlock:
- mutex_unlock(&ps->smi_mutex);
+ mutex_unlock(&ps->reg_lock);
return err;
}
@@ -2002,7 +2084,7 @@ static int mv88e6xxx_port_check_hw_vlan(struct dsa_switch *ds, int port,
if (!vid_begin)
return -EOPNOTSUPP;
- mutex_lock(&ps->smi_mutex);
+ mutex_lock(&ps->reg_lock);
err = _mv88e6xxx_vtu_vid_write(ps, vid_begin - 1);
if (err)
@@ -2041,7 +2123,7 @@ static int mv88e6xxx_port_check_hw_vlan(struct dsa_switch *ds, int port,
} while (vlan.vid < vid_end);
unlock:
- mutex_unlock(&ps->smi_mutex);
+ mutex_unlock(&ps->reg_lock);
return err;
}
@@ -2064,7 +2146,7 @@ static int mv88e6xxx_port_vlan_filtering(struct dsa_switch *ds, int port,
if (!mv88e6xxx_has(ps, MV88E6XXX_FLAG_VTU))
return -EOPNOTSUPP;
- mutex_lock(&ps->smi_mutex);
+ mutex_lock(&ps->reg_lock);
ret = _mv88e6xxx_reg_read(ps, REG_PORT(port), PORT_CONTROL_2);
if (ret < 0)
@@ -2088,14 +2170,15 @@ static int mv88e6xxx_port_vlan_filtering(struct dsa_switch *ds, int port,
ret = 0;
unlock:
- mutex_unlock(&ps->smi_mutex);
+ mutex_unlock(&ps->reg_lock);
return ret;
}
-static int mv88e6xxx_port_vlan_prepare(struct dsa_switch *ds, int port,
- const struct switchdev_obj_port_vlan *vlan,
- struct switchdev_trans *trans)
+static int
+mv88e6xxx_port_vlan_prepare(struct dsa_switch *ds, int port,
+ const struct switchdev_obj_port_vlan *vlan,
+ struct switchdev_trans *trans)
{
struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
int err;
@@ -2146,7 +2229,7 @@ static void mv88e6xxx_port_vlan_add(struct dsa_switch *ds, int port,
if (!mv88e6xxx_has(ps, MV88E6XXX_FLAG_VTU))
return;
- mutex_lock(&ps->smi_mutex);
+ mutex_lock(&ps->reg_lock);
for (vid = vlan->vid_begin; vid <= vlan->vid_end; ++vid)
if (_mv88e6xxx_port_vlan_add(ps, port, vid, untagged))
@@ -2158,7 +2241,7 @@ static void mv88e6xxx_port_vlan_add(struct dsa_switch *ds, int port,
netdev_err(ds->ports[port].netdev, "failed to set PVID %d\n",
vlan->vid_end);
- mutex_unlock(&ps->smi_mutex);
+ mutex_unlock(&ps->reg_lock);
}
static int _mv88e6xxx_port_vlan_del(struct mv88e6xxx_priv_state *ps,
@@ -2207,7 +2290,7 @@ static int mv88e6xxx_port_vlan_del(struct dsa_switch *ds, int port,
if (!mv88e6xxx_has(ps, MV88E6XXX_FLAG_VTU))
return -EOPNOTSUPP;
- mutex_lock(&ps->smi_mutex);
+ mutex_lock(&ps->reg_lock);
err = _mv88e6xxx_port_pvid_get(ps, port, &pvid);
if (err)
@@ -2226,7 +2309,7 @@ static int mv88e6xxx_port_vlan_del(struct dsa_switch *ds, int port,
}
unlock:
- mutex_unlock(&ps->smi_mutex);
+ mutex_unlock(&ps->reg_lock);
return err;
}
@@ -2338,11 +2421,11 @@ static void mv88e6xxx_port_fdb_add(struct dsa_switch *ds, int port,
if (!mv88e6xxx_has(ps, MV88E6XXX_FLAG_ATU))
return;
- mutex_lock(&ps->smi_mutex);
+ mutex_lock(&ps->reg_lock);
if (_mv88e6xxx_port_fdb_load(ps, port, fdb->addr, fdb->vid, state))
netdev_err(ds->ports[port].netdev,
"failed to load MAC address\n");
- mutex_unlock(&ps->smi_mutex);
+ mutex_unlock(&ps->reg_lock);
}
static int mv88e6xxx_port_fdb_del(struct dsa_switch *ds, int port,
@@ -2354,10 +2437,10 @@ static int mv88e6xxx_port_fdb_del(struct dsa_switch *ds, int port,
if (!mv88e6xxx_has(ps, MV88E6XXX_FLAG_ATU))
return -EOPNOTSUPP;
- mutex_lock(&ps->smi_mutex);
+ mutex_lock(&ps->reg_lock);
ret = _mv88e6xxx_port_fdb_load(ps, port, fdb->addr, fdb->vid,
GLOBAL_ATU_DATA_STATE_UNUSED);
- mutex_unlock(&ps->smi_mutex);
+ mutex_unlock(&ps->reg_lock);
return ret;
}
@@ -2462,7 +2545,7 @@ static int mv88e6xxx_port_fdb_dump(struct dsa_switch *ds, int port,
if (!mv88e6xxx_has(ps, MV88E6XXX_FLAG_ATU))
return -EOPNOTSUPP;
- mutex_lock(&ps->smi_mutex);
+ mutex_lock(&ps->reg_lock);
/* Dump port's default Filtering Information Database (VLAN ID 0) */
err = _mv88e6xxx_port_fid_get(ps, port, &fid);
@@ -2493,7 +2576,7 @@ static int mv88e6xxx_port_fdb_dump(struct dsa_switch *ds, int port,
} while (vlan.vid < GLOBAL_VTU_VID_MASK);
unlock:
- mutex_unlock(&ps->smi_mutex);
+ mutex_unlock(&ps->reg_lock);
return err;
}
@@ -2507,7 +2590,7 @@ static int mv88e6xxx_port_bridge_join(struct dsa_switch *ds, int port,
if (!mv88e6xxx_has(ps, MV88E6XXX_FLAG_VLANTABLE))
return -EOPNOTSUPP;
- mutex_lock(&ps->smi_mutex);
+ mutex_lock(&ps->reg_lock);
/* Assign the bridge and remap each port's VLANTable */
ps->ports[port].bridge_dev = bridge;
@@ -2520,7 +2603,7 @@ static int mv88e6xxx_port_bridge_join(struct dsa_switch *ds, int port,
}
}
- mutex_unlock(&ps->smi_mutex);
+ mutex_unlock(&ps->reg_lock);
return err;
}
@@ -2534,7 +2617,7 @@ static void mv88e6xxx_port_bridge_leave(struct dsa_switch *ds, int port)
if (!mv88e6xxx_has(ps, MV88E6XXX_FLAG_VLANTABLE))
return;
- mutex_lock(&ps->smi_mutex);
+ mutex_lock(&ps->reg_lock);
/* Unassign the bridge and remap each port's VLANTable */
ps->ports[port].bridge_dev = NULL;
@@ -2545,7 +2628,7 @@ static void mv88e6xxx_port_bridge_leave(struct dsa_switch *ds, int port)
netdev_warn(ds->ports[i].netdev,
"failed to remap\n");
- mutex_unlock(&ps->smi_mutex);
+ mutex_unlock(&ps->reg_lock);
}
static int _mv88e6xxx_mdio_page_write(struct mv88e6xxx_priv_state *ps,
@@ -2735,7 +2818,7 @@ static int mv88e6xxx_setup_port(struct mv88e6xxx_priv_state *ps, int port)
mv88e6xxx_6165_family(ps) || mv88e6xxx_6097_family(ps) ||
mv88e6xxx_6095_family(ps) || mv88e6xxx_6065_family(ps) ||
mv88e6xxx_6185_family(ps) || mv88e6xxx_6320_family(ps)) {
- reg |= PORT_CONTROL_EGRESS_ADD_TAG;
+ reg |= PORT_CONTROL_EGRESS_ADD_TAG;
}
}
if (dsa_is_dsa_port(ds, port)) {
@@ -3136,7 +3219,7 @@ static int mv88e6xxx_setup(struct dsa_switch *ds)
if (mv88e6xxx_has(ps, MV88E6XXX_FLAG_EEPROM))
mutex_init(&ps->eeprom_mutex);
- mutex_lock(&ps->smi_mutex);
+ mutex_lock(&ps->reg_lock);
err = mv88e6xxx_switch_reset(ps);
if (err)
@@ -3153,32 +3236,33 @@ static int mv88e6xxx_setup(struct dsa_switch *ds)
}
unlock:
- mutex_unlock(&ps->smi_mutex);
+ mutex_unlock(&ps->reg_lock);
return err;
}
-int mv88e6xxx_mdio_page_read(struct dsa_switch *ds, int port, int page, int reg)
+static int mv88e6xxx_mdio_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->smi_mutex);
+ mutex_lock(&ps->reg_lock);
ret = _mv88e6xxx_mdio_page_read(ps, port, page, reg);
- mutex_unlock(&ps->smi_mutex);
+ mutex_unlock(&ps->reg_lock);
return ret;
}
-int mv88e6xxx_mdio_page_write(struct dsa_switch *ds, int port, int page,
- int reg, int val)
+static int mv88e6xxx_mdio_page_write(struct dsa_switch *ds, int port, int page,
+ int reg, int val)
{
struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
int ret;
- mutex_lock(&ps->smi_mutex);
+ mutex_lock(&ps->reg_lock);
ret = _mv88e6xxx_mdio_page_write(ps, port, page, reg, val);
- mutex_unlock(&ps->smi_mutex);
+ mutex_unlock(&ps->reg_lock);
return ret;
}
@@ -3200,7 +3284,7 @@ static int mv88e6xxx_mdio_read(struct mii_bus *bus, int port, int regnum)
if (addr < 0)
return 0xffff;
- mutex_lock(&ps->smi_mutex);
+ mutex_lock(&ps->reg_lock);
if (mv88e6xxx_has(ps, MV88E6XXX_FLAG_PPU))
ret = mv88e6xxx_mdio_read_ppu(ps, addr, regnum);
@@ -3209,7 +3293,7 @@ static int mv88e6xxx_mdio_read(struct mii_bus *bus, int port, int regnum)
else
ret = mv88e6xxx_mdio_read_direct(ps, addr, regnum);
- mutex_unlock(&ps->smi_mutex);
+ mutex_unlock(&ps->reg_lock);
return ret;
}
@@ -3223,7 +3307,7 @@ static int mv88e6xxx_mdio_write(struct mii_bus *bus, int port, int regnum,
if (addr < 0)
return 0xffff;
- mutex_lock(&ps->smi_mutex);
+ mutex_lock(&ps->reg_lock);
if (mv88e6xxx_has(ps, MV88E6XXX_FLAG_PPU))
ret = mv88e6xxx_mdio_write_ppu(ps, addr, regnum, val);
@@ -3232,7 +3316,7 @@ static int mv88e6xxx_mdio_write(struct mii_bus *bus, int port, int regnum,
else
ret = mv88e6xxx_mdio_write_direct(ps, addr, regnum, val);
- mutex_unlock(&ps->smi_mutex);
+ mutex_unlock(&ps->reg_lock);
return ret;
}
@@ -3306,7 +3390,7 @@ static int mv88e61xx_get_temp(struct dsa_switch *ds, int *temp)
*temp = 0;
- mutex_lock(&ps->smi_mutex);
+ mutex_lock(&ps->reg_lock);
ret = mv88e6xxx_mdio_write_direct(ps, 0x0, 0x16, 0x6);
if (ret < 0)
@@ -3339,7 +3423,7 @@ static int mv88e61xx_get_temp(struct dsa_switch *ds, int *temp)
error:
mv88e6xxx_mdio_write_direct(ps, 0x0, 0x16, 0x0);
- mutex_unlock(&ps->smi_mutex);
+ mutex_unlock(&ps->reg_lock);
return ret;
}
@@ -3438,6 +3522,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
.name = "Marvell 88E6085",
.num_databases = 4096,
.num_ports = 10,
+ .port_base_addr = 0x10,
.flags = MV88E6XXX_FLAGS_FAMILY_6097,
},
@@ -3447,6 +3532,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
.name = "Marvell 88E6095/88E6095F",
.num_databases = 256,
.num_ports = 11,
+ .port_base_addr = 0x10,
.flags = MV88E6XXX_FLAGS_FAMILY_6095,
},
@@ -3456,6 +3542,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
.name = "Marvell 88E6123",
.num_databases = 4096,
.num_ports = 3,
+ .port_base_addr = 0x10,
.flags = MV88E6XXX_FLAGS_FAMILY_6165,
},
@@ -3465,6 +3552,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
.name = "Marvell 88E6131",
.num_databases = 256,
.num_ports = 8,
+ .port_base_addr = 0x10,
.flags = MV88E6XXX_FLAGS_FAMILY_6185,
},
@@ -3474,6 +3562,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
.name = "Marvell 88E6161",
.num_databases = 4096,
.num_ports = 6,
+ .port_base_addr = 0x10,
.flags = MV88E6XXX_FLAGS_FAMILY_6165,
},
@@ -3483,6 +3572,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
.name = "Marvell 88E6165",
.num_databases = 4096,
.num_ports = 6,
+ .port_base_addr = 0x10,
.flags = MV88E6XXX_FLAGS_FAMILY_6165,
},
@@ -3492,6 +3582,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
.name = "Marvell 88E6171",
.num_databases = 4096,
.num_ports = 7,
+ .port_base_addr = 0x10,
.flags = MV88E6XXX_FLAGS_FAMILY_6351,
},
@@ -3501,6 +3592,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
.name = "Marvell 88E6172",
.num_databases = 4096,
.num_ports = 7,
+ .port_base_addr = 0x10,
.flags = MV88E6XXX_FLAGS_FAMILY_6352,
},
@@ -3510,6 +3602,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
.name = "Marvell 88E6175",
.num_databases = 4096,
.num_ports = 7,
+ .port_base_addr = 0x10,
.flags = MV88E6XXX_FLAGS_FAMILY_6351,
},
@@ -3519,6 +3612,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
.name = "Marvell 88E6176",
.num_databases = 4096,
.num_ports = 7,
+ .port_base_addr = 0x10,
.flags = MV88E6XXX_FLAGS_FAMILY_6352,
},
@@ -3528,6 +3622,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
.name = "Marvell 88E6185",
.num_databases = 256,
.num_ports = 10,
+ .port_base_addr = 0x10,
.flags = MV88E6XXX_FLAGS_FAMILY_6185,
},
@@ -3537,6 +3632,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
.name = "Marvell 88E6240",
.num_databases = 4096,
.num_ports = 7,
+ .port_base_addr = 0x10,
.flags = MV88E6XXX_FLAGS_FAMILY_6352,
},
@@ -3546,6 +3642,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
.name = "Marvell 88E6320",
.num_databases = 4096,
.num_ports = 7,
+ .port_base_addr = 0x10,
.flags = MV88E6XXX_FLAGS_FAMILY_6320,
},
@@ -3555,6 +3652,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
.name = "Marvell 88E6321",
.num_databases = 4096,
.num_ports = 7,
+ .port_base_addr = 0x10,
.flags = MV88E6XXX_FLAGS_FAMILY_6320,
},
@@ -3564,6 +3662,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
.name = "Marvell 88E6350",
.num_databases = 4096,
.num_ports = 7,
+ .port_base_addr = 0x10,
.flags = MV88E6XXX_FLAGS_FAMILY_6351,
},
@@ -3573,6 +3672,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
.name = "Marvell 88E6351",
.num_databases = 4096,
.num_ports = 7,
+ .port_base_addr = 0x10,
.flags = MV88E6XXX_FLAGS_FAMILY_6351,
},
@@ -3582,75 +3682,123 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
.name = "Marvell 88E6352",
.num_databases = 4096,
.num_ports = 7,
+ .port_base_addr = 0x10,
.flags = MV88E6XXX_FLAGS_FAMILY_6352,
},
};
-static const struct mv88e6xxx_info *
-mv88e6xxx_lookup_info(unsigned int prod_num, const struct mv88e6xxx_info *table,
- unsigned int num)
+static const struct mv88e6xxx_info *mv88e6xxx_lookup_info(unsigned int prod_num)
{
int i;
- for (i = 0; i < num; ++i)
- if (table[i].prod_num == prod_num)
- return &table[i];
+ for (i = 0; i < ARRAY_SIZE(mv88e6xxx_table); ++i)
+ if (mv88e6xxx_table[i].prod_num == prod_num)
+ return &mv88e6xxx_table[i];
return NULL;
}
-static const char *mv88e6xxx_drv_probe(struct device *dsa_dev,
- struct device *host_dev, int sw_addr,
- void **priv)
+static int mv88e6xxx_detect(struct mv88e6xxx_priv_state *ps)
{
const struct mv88e6xxx_info *info;
- struct mv88e6xxx_priv_state *ps;
- struct mii_bus *bus;
- const char *name;
int id, prod_num, rev;
- int err;
-
- bus = dsa_host_dev_to_mii_bus(host_dev);
- if (!bus)
- return NULL;
- id = __mv88e6xxx_reg_read(bus, sw_addr, REG_PORT(0), PORT_SWITCH_ID);
+ id = mv88e6xxx_reg_read(ps, ps->info->port_base_addr, PORT_SWITCH_ID);
if (id < 0)
- return NULL;
+ return id;
prod_num = (id & 0xfff0) >> 4;
rev = id & 0x000f;
- info = mv88e6xxx_lookup_info(prod_num, mv88e6xxx_table,
- ARRAY_SIZE(mv88e6xxx_table));
+ info = mv88e6xxx_lookup_info(prod_num);
if (!info)
- return NULL;
+ return -ENODEV;
+
+ /* Update the compatible info with the probed one */
+ ps->info = info;
- name = info->name;
+ dev_info(ps->dev, "switch 0x%x detected: %s, revision %u\n",
+ ps->info->prod_num, ps->info->name, rev);
- ps = devm_kzalloc(dsa_dev, sizeof(*ps), GFP_KERNEL);
+ return 0;
+}
+
+static struct mv88e6xxx_priv_state *mv88e6xxx_alloc_chip(struct device *dev)
+{
+ struct mv88e6xxx_priv_state *ps;
+
+ ps = devm_kzalloc(dev, sizeof(*ps), GFP_KERNEL);
if (!ps)
return NULL;
+ ps->dev = dev;
+
+ mutex_init(&ps->reg_lock);
+
+ return ps;
+}
+
+static int mv88e6xxx_smi_init(struct mv88e6xxx_priv_state *ps,
+ struct mii_bus *bus, int sw_addr)
+{
+ /* ADDR[0] pin is unavailable externally and considered zero */
+ if (sw_addr & 0x1)
+ return -EINVAL;
+
+ if (sw_addr == 0)
+ ps->smi_ops = &mv88e6xxx_smi_single_chip_ops;
+ else if (mv88e6xxx_has(ps, MV88E6XXX_FLAG_MULTI_CHIP))
+ ps->smi_ops = &mv88e6xxx_smi_multi_chip_ops;
+ else
+ return -EINVAL;
+
ps->bus = bus;
ps->sw_addr = sw_addr;
- ps->info = info;
- ps->dev = dsa_dev;
- mutex_init(&ps->smi_mutex);
+
+ return 0;
+}
+
+static const char *mv88e6xxx_drv_probe(struct device *dsa_dev,
+ struct device *host_dev, int sw_addr,
+ void **priv)
+{
+ struct mv88e6xxx_priv_state *ps;
+ struct mii_bus *bus;
+ int err;
+
+ bus = dsa_host_dev_to_mii_bus(host_dev);
+ if (!bus)
+ return NULL;
+
+ ps = mv88e6xxx_alloc_chip(dsa_dev);
+ if (!ps)
+ return NULL;
+
+ /* Legacy SMI probing will only support chips similar to 88E6085 */
+ ps->info = &mv88e6xxx_table[MV88E6085];
+
+ err = mv88e6xxx_smi_init(ps, bus, sw_addr);
+ if (err)
+ goto free;
+
+ err = mv88e6xxx_detect(ps);
+ if (err)
+ goto free;
err = mv88e6xxx_mdio_register(ps, NULL);
if (err)
- return NULL;
+ goto free;
*priv = ps;
- dev_info(&ps->bus->dev, "switch 0x%x probed: %s, revision %u\n",
- prod_num, name, rev);
+ return ps->info->name;
+free:
+ devm_kfree(dsa_dev, ps);
- return name;
+ return NULL;
}
-struct dsa_switch_driver mv88e6xxx_switch_driver = {
+static struct dsa_switch_driver mv88e6xxx_switch_driver = {
.tag_protocol = DSA_TAG_PROTO_EDSA,
.probe = mv88e6xxx_drv_probe,
.setup = mv88e6xxx_setup,
@@ -3686,77 +3834,75 @@ struct dsa_switch_driver mv88e6xxx_switch_driver = {
.port_fdb_dump = mv88e6xxx_port_fdb_dump,
};
-int mv88e6xxx_probe(struct mdio_device *mdiodev)
+static int mv88e6xxx_register_switch(struct mv88e6xxx_priv_state *ps,
+ struct device_node *np)
{
- struct device *dev = &mdiodev->dev;
- struct device_node *np = dev->of_node;
- struct mv88e6xxx_priv_state *ps;
- int id, prod_num, rev;
+ struct device *dev = ps->dev;
struct dsa_switch *ds;
- u32 eeprom_len;
- int err;
- ds = devm_kzalloc(dev, sizeof(*ds) + sizeof(*ps), GFP_KERNEL);
+ ds = devm_kzalloc(dev, sizeof(*ds), GFP_KERNEL);
if (!ds)
return -ENOMEM;
- ps = (struct mv88e6xxx_priv_state *)(ds + 1);
- ds->priv = ps;
ds->dev = dev;
- ps->dev = dev;
- ps->ds = ds;
- ps->bus = mdiodev->bus;
- ps->sw_addr = mdiodev->addr;
- mutex_init(&ps->smi_mutex);
+ ds->priv = ps;
+ ds->drv = &mv88e6xxx_switch_driver;
- get_device(&ps->bus->dev);
+ dev_set_drvdata(dev, ds);
- ds->drv = &mv88e6xxx_switch_driver;
+ return dsa_register_switch(ds, np);
+}
- id = mv88e6xxx_reg_read(ps, REG_PORT(0), PORT_SWITCH_ID);
- if (id < 0)
- return id;
+static void mv88e6xxx_unregister_switch(struct mv88e6xxx_priv_state *ps)
+{
+ dsa_unregister_switch(ps->ds);
+}
- prod_num = (id & 0xfff0) >> 4;
- rev = id & 0x000f;
+static int mv88e6xxx_probe(struct mdio_device *mdiodev)
+{
+ struct device *dev = &mdiodev->dev;
+ struct device_node *np = dev->of_node;
+ const struct mv88e6xxx_info *compat_info;
+ struct mv88e6xxx_priv_state *ps;
+ u32 eeprom_len;
+ int err;
- ps->info = mv88e6xxx_lookup_info(prod_num, mv88e6xxx_table,
- ARRAY_SIZE(mv88e6xxx_table));
- if (!ps->info)
- return -ENODEV;
+ compat_info = of_device_get_match_data(dev);
+ if (!compat_info)
+ return -EINVAL;
- ps->reset = devm_gpiod_get(&mdiodev->dev, "reset", GPIOD_ASIS);
- if (IS_ERR(ps->reset)) {
- err = PTR_ERR(ps->reset);
- if (err == -ENOENT) {
- /* Optional, so not an error */
- ps->reset = NULL;
- } else {
- return err;
- }
- }
+ ps = mv88e6xxx_alloc_chip(dev);
+ if (!ps)
+ return -ENOMEM;
+
+ ps->info = compat_info;
+
+ err = mv88e6xxx_smi_init(ps, mdiodev->bus, mdiodev->addr);
+ if (err)
+ return err;
+
+ err = mv88e6xxx_detect(ps);
+ if (err)
+ return err;
+
+ ps->reset = devm_gpiod_get_optional(dev, "reset", GPIOD_ASIS);
+ if (IS_ERR(ps->reset))
+ return PTR_ERR(ps->reset);
if (mv88e6xxx_has(ps, MV88E6XXX_FLAG_EEPROM) &&
!of_property_read_u32(np, "eeprom-length", &eeprom_len))
ps->eeprom_len = eeprom_len;
- err = mv88e6xxx_mdio_register(ps, mdiodev->dev.of_node);
+ err = mv88e6xxx_mdio_register(ps, np);
if (err)
return err;
- ds->slave_mii_bus = ps->mdio_bus;
-
- dev_set_drvdata(dev, ds);
-
- err = dsa_register_switch(ds, mdiodev->dev.of_node);
+ err = mv88e6xxx_register_switch(ps, np);
if (err) {
mv88e6xxx_mdio_unregister(ps);
return err;
}
- dev_info(dev, "switch 0x%x probed: %s, revision %u\n",
- prod_num, ps->info->name, rev);
-
return 0;
}
@@ -3765,14 +3911,15 @@ static void mv88e6xxx_remove(struct mdio_device *mdiodev)
struct dsa_switch *ds = dev_get_drvdata(&mdiodev->dev);
struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
- dsa_unregister_switch(ds);
- put_device(&ps->bus->dev);
-
+ mv88e6xxx_unregister_switch(ps);
mv88e6xxx_mdio_unregister(ps);
}
static const struct of_device_id mv88e6xxx_of_match[] = {
- { .compatible = "marvell,mv88e6085" },
+ {
+ .compatible = "marvell,mv88e6085",
+ .data = &mv88e6xxx_table[MV88E6085],
+ },
{ /* sentinel */ },
};
diff --git a/drivers/net/dsa/mv88e6xxx.h b/drivers/net/dsa/mv88e6xxx.h
index 8221c3c7ec5a..a94acd887929 100644
--- a/drivers/net/dsa/mv88e6xxx.h
+++ b/drivers/net/dsa/mv88e6xxx.h
@@ -387,6 +387,12 @@ enum mv88e6xxx_cap {
*/
MV88E6XXX_CAP_EEPROM,
+ /* Multi-chip Addressing Mode.
+ * Some chips require an indirect SMI access when their SMI device
+ * address is not zero. See SMI_CMD and SMI_DATA.
+ */
+ MV88E6XXX_CAP_MULTI_CHIP,
+
/* Port State Filtering for 802.1D Spanning Tree.
* See PORT_CONTROL_STATE_* values in the PORT_CONTROL register.
*/
@@ -439,6 +445,7 @@ enum mv88e6xxx_cap {
#define MV88E6XXX_FLAG_ATU BIT(MV88E6XXX_CAP_ATU)
#define MV88E6XXX_FLAG_EEE BIT(MV88E6XXX_CAP_EEE)
#define MV88E6XXX_FLAG_EEPROM BIT(MV88E6XXX_CAP_EEPROM)
+#define MV88E6XXX_FLAG_MULTI_CHIP BIT(MV88E6XXX_CAP_MULTI_CHIP)
#define MV88E6XXX_FLAG_PORTSTATE BIT(MV88E6XXX_CAP_PORTSTATE)
#define MV88E6XXX_FLAG_PPU BIT(MV88E6XXX_CAP_PPU)
#define MV88E6XXX_FLAG_PPU_ACTIVE BIT(MV88E6XXX_CAP_PPU_ACTIVE)
@@ -452,25 +459,29 @@ enum mv88e6xxx_cap {
#define MV88E6XXX_FLAGS_FAMILY_6095 \
(MV88E6XXX_FLAG_ATU | \
+ MV88E6XXX_FLAG_MULTI_CHIP | \
MV88E6XXX_FLAG_PPU | \
MV88E6XXX_FLAG_VLANTABLE | \
MV88E6XXX_FLAG_VTU)
#define MV88E6XXX_FLAGS_FAMILY_6097 \
(MV88E6XXX_FLAG_ATU | \
+ MV88E6XXX_FLAG_MULTI_CHIP | \
MV88E6XXX_FLAG_PPU | \
MV88E6XXX_FLAG_STU | \
MV88E6XXX_FLAG_VLANTABLE | \
MV88E6XXX_FLAG_VTU)
#define MV88E6XXX_FLAGS_FAMILY_6165 \
- (MV88E6XXX_FLAG_STU | \
+ (MV88E6XXX_FLAG_MULTI_CHIP | \
+ MV88E6XXX_FLAG_STU | \
MV88E6XXX_FLAG_SWITCH_MAC | \
MV88E6XXX_FLAG_TEMP | \
MV88E6XXX_FLAG_VTU)
#define MV88E6XXX_FLAGS_FAMILY_6185 \
(MV88E6XXX_FLAG_ATU | \
+ MV88E6XXX_FLAG_MULTI_CHIP | \
MV88E6XXX_FLAG_PPU | \
MV88E6XXX_FLAG_VLANTABLE | \
MV88E6XXX_FLAG_VTU)
@@ -479,6 +490,7 @@ enum mv88e6xxx_cap {
(MV88E6XXX_FLAG_ATU | \
MV88E6XXX_FLAG_EEE | \
MV88E6XXX_FLAG_EEPROM | \
+ MV88E6XXX_FLAG_MULTI_CHIP | \
MV88E6XXX_FLAG_PORTSTATE | \
MV88E6XXX_FLAG_PPU_ACTIVE | \
MV88E6XXX_FLAG_SMI_PHY | \
@@ -490,6 +502,7 @@ enum mv88e6xxx_cap {
#define MV88E6XXX_FLAGS_FAMILY_6351 \
(MV88E6XXX_FLAG_ATU | \
+ MV88E6XXX_FLAG_MULTI_CHIP | \
MV88E6XXX_FLAG_PORTSTATE | \
MV88E6XXX_FLAG_PPU_ACTIVE | \
MV88E6XXX_FLAG_SMI_PHY | \
@@ -503,6 +516,7 @@ enum mv88e6xxx_cap {
(MV88E6XXX_FLAG_ATU | \
MV88E6XXX_FLAG_EEE | \
MV88E6XXX_FLAG_EEPROM | \
+ MV88E6XXX_FLAG_MULTI_CHIP | \
MV88E6XXX_FLAG_PORTSTATE | \
MV88E6XXX_FLAG_PPU_ACTIVE | \
MV88E6XXX_FLAG_SMI_PHY | \
@@ -519,6 +533,7 @@ struct mv88e6xxx_info {
const char *name;
unsigned int num_databases;
unsigned int num_ports;
+ unsigned int port_base_addr;
unsigned long flags;
};
@@ -541,6 +556,8 @@ struct mv88e6xxx_vtu_stu_entry {
u8 data[DSA_MAX_PORTS];
};
+struct mv88e6xxx_ops;
+
struct mv88e6xxx_priv_port {
struct net_device *bridge_dev;
};
@@ -554,15 +571,13 @@ struct mv88e6xxx_priv_state {
/* The device this structure is associated to */
struct device *dev;
- /* When using multi-chip addressing, this mutex protects
- * access to the indirect access registers. (In single-chip
- * mode, this mutex is effectively useless.)
- */
- struct mutex smi_mutex;
+ /* This mutex protects the access to the switch registers */
+ struct mutex reg_lock;
/* The MII bus and the address on the bus that is used to
* communication with the switch
*/
+ const struct mv88e6xxx_ops *smi_ops;
struct mii_bus *bus;
int sw_addr;
@@ -608,6 +623,13 @@ struct mv88e6xxx_priv_state {
struct mii_bus *mdio_bus;
};
+struct mv88e6xxx_ops {
+ int (*read)(struct mv88e6xxx_priv_state *ps,
+ int addr, int reg, u16 *val);
+ int (*write)(struct mv88e6xxx_priv_state *ps,
+ int addr, int reg, u16 val);
+};
+
enum stat_type {
BANK0,
BANK1,