mirror of
https://github.com/AuxXxilium/linux_dsm_epyc7002.git
synced 2024-12-28 03:05:21 +07:00
Merge branch 'mv88e6131-hw-bridging-6185'
Vivien Didelot says: ==================== net: dsa: mv88e6131: HW bridging support for 6185 All packets passing through a switch of the 6185 family are currently all directed to the CPU port. This means that port bridging is software driven. To enable hardware bridging for this switch family, we need to implement the port mapping operations, the FDB operations, and optionally the VLAN operations (for 802.1Q and VLAN filtering aware systems). However this family only has 256 FDBs indexed by 8-bit identifiers, opposed to 4096 FDBs with 12-bit identifiers for other families such as 6352. It also doesn't have dedicated FID registers for ATU and VTU operations. This patchset fixes these differences, and enable hardware bridging for 6185. Changes v1 -> v2: - Describe the different numbers of databases and prefer a feature-based logic over the current ID/family-based logic. ==================== Tested-by: Andrew Lunn <andrew@lunn.ch> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
6e3380488a
@ -169,6 +169,17 @@ struct dsa_switch_driver mv88e6131_switch_driver = {
|
||||
.get_ethtool_stats = mv88e6xxx_get_ethtool_stats,
|
||||
.get_sset_count = mv88e6xxx_get_sset_count,
|
||||
.adjust_link = mv88e6xxx_adjust_link,
|
||||
.port_bridge_join = mv88e6xxx_port_bridge_join,
|
||||
.port_bridge_leave = mv88e6xxx_port_bridge_leave,
|
||||
.port_vlan_filtering = mv88e6xxx_port_vlan_filtering,
|
||||
.port_vlan_prepare = mv88e6xxx_port_vlan_prepare,
|
||||
.port_vlan_add = mv88e6xxx_port_vlan_add,
|
||||
.port_vlan_del = mv88e6xxx_port_vlan_del,
|
||||
.port_vlan_dump = mv88e6xxx_port_vlan_dump,
|
||||
.port_fdb_prepare = mv88e6xxx_port_fdb_prepare,
|
||||
.port_fdb_add = mv88e6xxx_port_fdb_add,
|
||||
.port_fdb_del = mv88e6xxx_port_fdb_del,
|
||||
.port_fdb_dump = mv88e6xxx_port_fdb_dump,
|
||||
};
|
||||
|
||||
MODULE_ALIAS("platform:mv88e6085");
|
||||
|
@ -482,6 +482,50 @@ static bool mv88e6xxx_6352_family(struct dsa_switch *ds)
|
||||
return false;
|
||||
}
|
||||
|
||||
static unsigned int mv88e6xxx_num_databases(struct dsa_switch *ds)
|
||||
{
|
||||
struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
|
||||
|
||||
/* The following devices have 4-bit identifiers for 16 databases */
|
||||
if (ps->id == PORT_SWITCH_ID_6061)
|
||||
return 16;
|
||||
|
||||
/* The following devices have 6-bit identifiers for 64 databases */
|
||||
if (ps->id == PORT_SWITCH_ID_6065)
|
||||
return 64;
|
||||
|
||||
/* The following devices have 8-bit identifiers for 256 databases */
|
||||
if (mv88e6xxx_6095_family(ds) || mv88e6xxx_6185_family(ds))
|
||||
return 256;
|
||||
|
||||
/* The following devices have 12-bit identifiers for 4096 databases */
|
||||
if (mv88e6xxx_6097_family(ds) || mv88e6xxx_6165_family(ds) ||
|
||||
mv88e6xxx_6351_family(ds) || mv88e6xxx_6352_family(ds))
|
||||
return 4096;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool mv88e6xxx_has_fid_reg(struct dsa_switch *ds)
|
||||
{
|
||||
/* Does the device have dedicated FID registers for ATU and VTU ops? */
|
||||
if (mv88e6xxx_6097_family(ds) || mv88e6xxx_6165_family(ds) ||
|
||||
mv88e6xxx_6351_family(ds) || mv88e6xxx_6352_family(ds))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool mv88e6xxx_has_stu(struct dsa_switch *ds)
|
||||
{
|
||||
/* Does the device have STU and dedicated SID registers for VTU ops? */
|
||||
if (mv88e6xxx_6097_family(ds) || mv88e6xxx_6165_family(ds) ||
|
||||
mv88e6xxx_6351_family(ds) || mv88e6xxx_6352_family(ds))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/* We expect the switch to perform auto negotiation if there is a real
|
||||
* phy. However, in the case of a fixed link phy, we force the port
|
||||
* settings from the fixed link settings.
|
||||
@ -951,10 +995,30 @@ int mv88e6xxx_set_eee(struct dsa_switch *ds, int port,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int _mv88e6xxx_atu_cmd(struct dsa_switch *ds, u16 cmd)
|
||||
static int _mv88e6xxx_atu_cmd(struct dsa_switch *ds, u16 fid, u16 cmd)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (mv88e6xxx_has_fid_reg(ds)) {
|
||||
ret = _mv88e6xxx_reg_write(ds, REG_GLOBAL, GLOBAL_ATU_FID, fid);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
} else if (mv88e6xxx_num_databases(ds) == 256) {
|
||||
/* ATU DBNum[7:4] are located in ATU Control 15:12 */
|
||||
ret = _mv88e6xxx_reg_read(ds, REG_GLOBAL, GLOBAL_ATU_CONTROL);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = _mv88e6xxx_reg_write(ds, REG_GLOBAL, GLOBAL_ATU_CONTROL,
|
||||
(ret & 0xfff) |
|
||||
((fid << 8) & 0xf000));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* ATU DBNum[3:0] are located in ATU Operation 3:0 */
|
||||
cmd |= fid & 0xf;
|
||||
}
|
||||
|
||||
ret = _mv88e6xxx_reg_write(ds, REG_GLOBAL, GLOBAL_ATU_OP, cmd);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
@ -1001,11 +1065,6 @@ static int _mv88e6xxx_atu_flush_move(struct dsa_switch *ds,
|
||||
return err;
|
||||
|
||||
if (entry->fid) {
|
||||
err = _mv88e6xxx_reg_write(ds, REG_GLOBAL, GLOBAL_ATU_FID,
|
||||
entry->fid);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
op = static_too ? GLOBAL_ATU_OP_FLUSH_MOVE_ALL_DB :
|
||||
GLOBAL_ATU_OP_FLUSH_MOVE_NON_STATIC_DB;
|
||||
} else {
|
||||
@ -1013,7 +1072,7 @@ static int _mv88e6xxx_atu_flush_move(struct dsa_switch *ds,
|
||||
GLOBAL_ATU_OP_FLUSH_MOVE_NON_STATIC;
|
||||
}
|
||||
|
||||
return _mv88e6xxx_atu_cmd(ds, op);
|
||||
return _mv88e6xxx_atu_cmd(ds, entry->fid, op);
|
||||
}
|
||||
|
||||
static int _mv88e6xxx_atu_flush(struct dsa_switch *ds, u16 fid, bool static_too)
|
||||
@ -1321,15 +1380,27 @@ static int _mv88e6xxx_vtu_getnext(struct dsa_switch *ds,
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (mv88e6xxx_6097_family(ds) || mv88e6xxx_6165_family(ds) ||
|
||||
mv88e6xxx_6351_family(ds) || mv88e6xxx_6352_family(ds)) {
|
||||
if (mv88e6xxx_has_fid_reg(ds)) {
|
||||
ret = _mv88e6xxx_reg_read(ds, REG_GLOBAL,
|
||||
GLOBAL_VTU_FID);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
next.fid = ret & GLOBAL_VTU_FID_MASK;
|
||||
} else if (mv88e6xxx_num_databases(ds) == 256) {
|
||||
/* VTU DBNum[7:4] are located in VTU Operation 11:8, and
|
||||
* VTU DBNum[3:0] are located in VTU Operation 3:0
|
||||
*/
|
||||
ret = _mv88e6xxx_reg_read(ds, REG_GLOBAL,
|
||||
GLOBAL_VTU_OP);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
next.fid = (ret & 0xf00) >> 4;
|
||||
next.fid |= ret & 0xf;
|
||||
}
|
||||
|
||||
if (mv88e6xxx_has_stu(ds)) {
|
||||
ret = _mv88e6xxx_reg_read(ds, REG_GLOBAL,
|
||||
GLOBAL_VTU_SID);
|
||||
if (ret < 0)
|
||||
@ -1397,6 +1468,7 @@ int mv88e6xxx_port_vlan_dump(struct dsa_switch *ds, int port,
|
||||
static int _mv88e6xxx_vtu_loadpurge(struct dsa_switch *ds,
|
||||
struct mv88e6xxx_vtu_stu_entry *entry)
|
||||
{
|
||||
u16 op = GLOBAL_VTU_OP_VTU_LOAD_PURGE;
|
||||
u16 reg = 0;
|
||||
int ret;
|
||||
|
||||
@ -1412,17 +1484,24 @@ static int _mv88e6xxx_vtu_loadpurge(struct dsa_switch *ds,
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (mv88e6xxx_6097_family(ds) || mv88e6xxx_6165_family(ds) ||
|
||||
mv88e6xxx_6351_family(ds) || mv88e6xxx_6352_family(ds)) {
|
||||
if (mv88e6xxx_has_stu(ds)) {
|
||||
reg = entry->sid & GLOBAL_VTU_SID_MASK;
|
||||
ret = _mv88e6xxx_reg_write(ds, REG_GLOBAL, GLOBAL_VTU_SID, reg);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (mv88e6xxx_has_fid_reg(ds)) {
|
||||
reg = entry->fid & GLOBAL_VTU_FID_MASK;
|
||||
ret = _mv88e6xxx_reg_write(ds, REG_GLOBAL, GLOBAL_VTU_FID, reg);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
} else if (mv88e6xxx_num_databases(ds) == 256) {
|
||||
/* VTU DBNum[7:4] are located in VTU Operation 11:8, and
|
||||
* VTU DBNum[3:0] are located in VTU Operation 3:0
|
||||
*/
|
||||
op |= (entry->fid & 0xf0) << 8;
|
||||
op |= entry->fid & 0xf;
|
||||
}
|
||||
|
||||
reg = GLOBAL_VTU_VID_VALID;
|
||||
@ -1432,7 +1511,7 @@ static int _mv88e6xxx_vtu_loadpurge(struct dsa_switch *ds,
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return _mv88e6xxx_vtu_cmd(ds, GLOBAL_VTU_OP_VTU_LOAD_PURGE);
|
||||
return _mv88e6xxx_vtu_cmd(ds, op);
|
||||
}
|
||||
|
||||
static int _mv88e6xxx_stu_getnext(struct dsa_switch *ds, u8 sid,
|
||||
@ -1511,9 +1590,17 @@ static int _mv88e6xxx_stu_loadpurge(struct dsa_switch *ds,
|
||||
static int _mv88e6xxx_port_fid(struct dsa_switch *ds, int port, u16 *new,
|
||||
u16 *old)
|
||||
{
|
||||
u16 upper_mask;
|
||||
u16 fid;
|
||||
int ret;
|
||||
|
||||
if (mv88e6xxx_num_databases(ds) == 4096)
|
||||
upper_mask = 0xff;
|
||||
else if (mv88e6xxx_num_databases(ds) == 256)
|
||||
upper_mask = 0xf;
|
||||
else
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
/* Port's default FID bits 3:0 are located in reg 0x06, offset 12 */
|
||||
ret = _mv88e6xxx_reg_read(ds, REG_PORT(port), PORT_BASE_VLAN);
|
||||
if (ret < 0)
|
||||
@ -1536,11 +1623,11 @@ static int _mv88e6xxx_port_fid(struct dsa_switch *ds, int port, u16 *new,
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
fid |= (ret & PORT_CONTROL_1_FID_11_4_MASK) << 4;
|
||||
fid |= (ret & upper_mask) << 4;
|
||||
|
||||
if (new) {
|
||||
ret &= ~PORT_CONTROL_1_FID_11_4_MASK;
|
||||
ret |= (*new >> 4) & PORT_CONTROL_1_FID_11_4_MASK;
|
||||
ret &= ~upper_mask;
|
||||
ret |= (*new >> 4) & upper_mask;
|
||||
|
||||
ret = _mv88e6xxx_reg_write(ds, REG_PORT(port), PORT_CONTROL_1,
|
||||
ret);
|
||||
@ -1604,7 +1691,7 @@ static int _mv88e6xxx_fid_new(struct dsa_switch *ds, u16 *fid)
|
||||
* databases are not needed. Return the next positive available.
|
||||
*/
|
||||
*fid = find_next_zero_bit(fid_bitmap, MV88E6XXX_N_FID, 1);
|
||||
if (unlikely(*fid == MV88E6XXX_N_FID))
|
||||
if (unlikely(*fid >= mv88e6xxx_num_databases(ds)))
|
||||
return -ENOSPC;
|
||||
|
||||
/* Clear the database */
|
||||
@ -1965,11 +2052,7 @@ static int _mv88e6xxx_atu_load(struct dsa_switch *ds,
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = _mv88e6xxx_reg_write(ds, REG_GLOBAL, GLOBAL_ATU_FID, entry->fid);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return _mv88e6xxx_atu_cmd(ds, GLOBAL_ATU_OP_LOAD_DB);
|
||||
return _mv88e6xxx_atu_cmd(ds, entry->fid, GLOBAL_ATU_OP_LOAD_DB);
|
||||
}
|
||||
|
||||
static int _mv88e6xxx_port_fdb_load(struct dsa_switch *ds, int port,
|
||||
@ -2052,11 +2135,7 @@ static int _mv88e6xxx_atu_getnext(struct dsa_switch *ds, u16 fid,
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = _mv88e6xxx_reg_write(ds, REG_GLOBAL, GLOBAL_ATU_FID, fid);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = _mv88e6xxx_atu_cmd(ds, GLOBAL_ATU_OP_GET_NEXT_DB);
|
||||
ret = _mv88e6xxx_atu_cmd(ds, fid, GLOBAL_ATU_OP_GET_NEXT_DB);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
@ -2444,7 +2523,8 @@ static int mv88e6xxx_setup_port(struct dsa_switch *ds, int port)
|
||||
reg = 0;
|
||||
if (mv88e6xxx_6352_family(ds) || mv88e6xxx_6351_family(ds) ||
|
||||
mv88e6xxx_6165_family(ds) || mv88e6xxx_6097_family(ds) ||
|
||||
mv88e6xxx_6095_family(ds) || mv88e6xxx_6320_family(ds))
|
||||
mv88e6xxx_6095_family(ds) || mv88e6xxx_6320_family(ds) ||
|
||||
mv88e6xxx_6185_family(ds))
|
||||
reg = PORT_CONTROL_2_MAP_DA;
|
||||
|
||||
if (mv88e6xxx_6352_family(ds) || mv88e6xxx_6351_family(ds) ||
|
||||
|
Loading…
Reference in New Issue
Block a user