|
@@ -1214,29 +1214,74 @@ static int _mv88e6xxx_atu_mac_read(struct dsa_switch *ds, unsigned char *addr)
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
-static int __mv88e6xxx_port_fdb_cmd(struct dsa_switch *ds, int port,
|
|
|
|
- const unsigned char *addr, int state)
|
|
|
|
|
|
+static int _mv88e6xxx_atu_load(struct dsa_switch *ds,
|
|
|
|
+ struct mv88e6xxx_atu_entry *entry)
|
|
{
|
|
{
|
|
- struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
|
|
|
|
- u8 fid = ps->fid[port];
|
|
|
|
|
|
+ u16 reg = 0;
|
|
int ret;
|
|
int ret;
|
|
|
|
|
|
ret = _mv88e6xxx_atu_wait(ds);
|
|
ret = _mv88e6xxx_atu_wait(ds);
|
|
if (ret < 0)
|
|
if (ret < 0)
|
|
return ret;
|
|
return ret;
|
|
|
|
|
|
- ret = _mv88e6xxx_atu_mac_write(ds, addr);
|
|
|
|
|
|
+ ret = _mv88e6xxx_atu_mac_write(ds, entry->mac);
|
|
if (ret < 0)
|
|
if (ret < 0)
|
|
return ret;
|
|
return ret;
|
|
|
|
|
|
- ret = _mv88e6xxx_reg_write(ds, REG_GLOBAL, GLOBAL_ATU_DATA,
|
|
|
|
- (0x10 << port) | state);
|
|
|
|
- if (ret)
|
|
|
|
|
|
+ if (entry->state != GLOBAL_ATU_DATA_STATE_UNUSED) {
|
|
|
|
+ unsigned int mask, shift;
|
|
|
|
+
|
|
|
|
+ if (entry->trunk) {
|
|
|
|
+ reg |= GLOBAL_ATU_DATA_TRUNK;
|
|
|
|
+ mask = GLOBAL_ATU_DATA_TRUNK_ID_MASK;
|
|
|
|
+ shift = GLOBAL_ATU_DATA_TRUNK_ID_SHIFT;
|
|
|
|
+ } else {
|
|
|
|
+ mask = GLOBAL_ATU_DATA_PORT_VECTOR_MASK;
|
|
|
|
+ shift = GLOBAL_ATU_DATA_PORT_VECTOR_SHIFT;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ reg |= (entry->portv_trunkid << shift) & mask;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ reg |= entry->state & GLOBAL_ATU_DATA_STATE_MASK;
|
|
|
|
+
|
|
|
|
+ ret = _mv88e6xxx_reg_write(ds, REG_GLOBAL, GLOBAL_ATU_DATA, reg);
|
|
|
|
+ if (ret < 0)
|
|
return ret;
|
|
return ret;
|
|
|
|
|
|
- ret = _mv88e6xxx_atu_cmd(ds, fid, GLOBAL_ATU_OP_LOAD_DB);
|
|
|
|
|
|
+ return _mv88e6xxx_atu_cmd(ds, entry->fid, GLOBAL_ATU_OP_LOAD_DB);
|
|
|
|
+}
|
|
|
|
|
|
- return ret;
|
|
|
|
|
|
+static int _mv88e6xxx_port_vid_to_fid(struct dsa_switch *ds, int port, u16 vid)
|
|
|
|
+{
|
|
|
|
+ struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
|
|
|
|
+
|
|
|
|
+ if (vid == 0)
|
|
|
|
+ return ps->fid[port];
|
|
|
|
+
|
|
|
|
+ return -ENOENT;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static int _mv88e6xxx_port_fdb_load(struct dsa_switch *ds, int port,
|
|
|
|
+ const unsigned char *addr, u16 vid,
|
|
|
|
+ u8 state)
|
|
|
|
+{
|
|
|
|
+ struct mv88e6xxx_atu_entry entry = { 0 };
|
|
|
|
+ int ret;
|
|
|
|
+
|
|
|
|
+ ret = _mv88e6xxx_port_vid_to_fid(ds, port, vid);
|
|
|
|
+ if (ret < 0)
|
|
|
|
+ return ret;
|
|
|
|
+
|
|
|
|
+ entry.fid = ret;
|
|
|
|
+ entry.state = state;
|
|
|
|
+ ether_addr_copy(entry.mac, addr);
|
|
|
|
+ if (state != GLOBAL_ATU_DATA_STATE_UNUSED) {
|
|
|
|
+ entry.trunk = false;
|
|
|
|
+ entry.portv_trunkid = BIT(port);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return _mv88e6xxx_atu_load(ds, &entry);
|
|
}
|
|
}
|
|
|
|
|
|
int mv88e6xxx_port_fdb_add(struct dsa_switch *ds, int port,
|
|
int mv88e6xxx_port_fdb_add(struct dsa_switch *ds, int port,
|
|
@@ -1249,7 +1294,7 @@ int mv88e6xxx_port_fdb_add(struct dsa_switch *ds, int port,
|
|
int ret;
|
|
int ret;
|
|
|
|
|
|
mutex_lock(&ps->smi_mutex);
|
|
mutex_lock(&ps->smi_mutex);
|
|
- ret = __mv88e6xxx_port_fdb_cmd(ds, port, addr, state);
|
|
|
|
|
|
+ ret = _mv88e6xxx_port_fdb_load(ds, port, addr, vid, state);
|
|
mutex_unlock(&ps->smi_mutex);
|
|
mutex_unlock(&ps->smi_mutex);
|
|
|
|
|
|
return ret;
|
|
return ret;
|
|
@@ -1262,7 +1307,7 @@ int mv88e6xxx_port_fdb_del(struct dsa_switch *ds, int port,
|
|
int ret;
|
|
int ret;
|
|
|
|
|
|
mutex_lock(&ps->smi_mutex);
|
|
mutex_lock(&ps->smi_mutex);
|
|
- ret = __mv88e6xxx_port_fdb_cmd(ds, port, addr,
|
|
|
|
|
|
+ ret = _mv88e6xxx_port_fdb_load(ds, port, addr, vid,
|
|
GLOBAL_ATU_DATA_STATE_UNUSED);
|
|
GLOBAL_ATU_DATA_STATE_UNUSED);
|
|
mutex_unlock(&ps->smi_mutex);
|
|
mutex_unlock(&ps->smi_mutex);
|
|
|
|
|