diff options
| -rw-r--r-- | drivers/net/dsa/yt921x.c | 115 | ||||
| -rw-r--r-- | drivers/net/dsa/yt921x.h | 35 |
2 files changed, 137 insertions, 13 deletions
diff --git a/drivers/net/dsa/yt921x.c b/drivers/net/dsa/yt921x.c index d5fb17d2b6e0..12e1bd5a1061 100644 --- a/drivers/net/dsa/yt921x.c +++ b/drivers/net/dsa/yt921x.c @@ -2098,6 +2098,117 @@ yt921x_dsa_port_bridge_join(struct dsa_switch *ds, int port, return res; } +static int +yt921x_dsa_port_mst_state_set(struct dsa_switch *ds, int port, + const struct switchdev_mst_state *st) +{ + struct yt921x_priv *priv = to_yt921x_priv(ds); + u32 mask; + u32 ctrl; + int res; + + mask = YT921X_STP_PORTn_M(port); + switch (st->state) { + case BR_STATE_DISABLED: + ctrl = YT921X_STP_PORTn_DISABLED(port); + break; + case BR_STATE_LISTENING: + case BR_STATE_LEARNING: + ctrl = YT921X_STP_PORTn_LEARNING(port); + break; + case BR_STATE_FORWARDING: + default: + ctrl = YT921X_STP_PORTn_FORWARD(port); + break; + case BR_STATE_BLOCKING: + ctrl = YT921X_STP_PORTn_BLOCKING(port); + break; + } + + mutex_lock(&priv->reg_lock); + res = yt921x_reg_update_bits(priv, YT921X_STPn(st->msti), mask, ctrl); + mutex_unlock(&priv->reg_lock); + + return res; +} + +static int +yt921x_dsa_vlan_msti_set(struct dsa_switch *ds, struct dsa_bridge bridge, + const struct switchdev_vlan_msti *msti) +{ + struct yt921x_priv *priv = to_yt921x_priv(ds); + u64 mask64; + u64 ctrl64; + int res; + + if (!msti->vid) + return -EINVAL; + if (!msti->msti || msti->msti >= YT921X_MSTI_NUM) + return -EINVAL; + + mask64 = YT921X_VLAN_CTRL_STP_ID_M; + ctrl64 = YT921X_VLAN_CTRL_STP_ID(msti->msti); + + mutex_lock(&priv->reg_lock); + res = yt921x_reg64_update_bits(priv, YT921X_VLANn_CTRL(msti->vid), + mask64, ctrl64); + mutex_unlock(&priv->reg_lock); + + return res; +} + +static void +yt921x_dsa_port_stp_state_set(struct dsa_switch *ds, int port, u8 state) +{ + struct yt921x_priv *priv = to_yt921x_priv(ds); + struct dsa_port *dp = dsa_to_port(ds, port); + struct device *dev = to_device(priv); + bool learning; + u32 mask; + u32 ctrl; + int res; + + mask = YT921X_STP_PORTn_M(port); + learning = false; + switch (state) { + case BR_STATE_DISABLED: + ctrl = YT921X_STP_PORTn_DISABLED(port); + break; + case BR_STATE_LISTENING: + ctrl = YT921X_STP_PORTn_LEARNING(port); + break; + case BR_STATE_LEARNING: + ctrl = YT921X_STP_PORTn_LEARNING(port); + learning = dp->learning; + break; + case BR_STATE_FORWARDING: + default: + ctrl = YT921X_STP_PORTn_FORWARD(port); + learning = dp->learning; + break; + case BR_STATE_BLOCKING: + ctrl = YT921X_STP_PORTn_BLOCKING(port); + break; + } + + mutex_lock(&priv->reg_lock); + do { + res = yt921x_reg_update_bits(priv, YT921X_STPn(0), mask, ctrl); + if (res) + break; + + mask = YT921X_PORT_LEARN_DIS; + ctrl = !learning ? YT921X_PORT_LEARN_DIS : 0; + res = yt921x_reg_update_bits(priv, YT921X_PORTn_LEARN(port), + mask, ctrl); + } while (0); + mutex_unlock(&priv->reg_lock); + + if (res) + dev_err(dev, "Failed to %s port %d: %i\n", "set STP state for", + port, res); +} + static int yt921x_port_down(struct yt921x_priv *priv, int port) { u32 mask; @@ -2783,6 +2894,10 @@ static const struct dsa_switch_ops yt921x_dsa_switch_ops = { .port_bridge_flags = yt921x_dsa_port_bridge_flags, .port_bridge_leave = yt921x_dsa_port_bridge_leave, .port_bridge_join = yt921x_dsa_port_bridge_join, + /* mst */ + .port_mst_state_set = yt921x_dsa_port_mst_state_set, + .vlan_msti_set = yt921x_dsa_vlan_msti_set, + .port_stp_state_set = yt921x_dsa_port_stp_state_set, /* port */ .get_tag_protocol = yt921x_dsa_get_tag_protocol, .phylink_get_caps = yt921x_dsa_phylink_get_caps, diff --git a/drivers/net/dsa/yt921x.h b/drivers/net/dsa/yt921x.h index 44719d841d40..61bb0ab3b09a 100644 --- a/drivers/net/dsa/yt921x.h +++ b/drivers/net/dsa/yt921x.h @@ -274,6 +274,13 @@ #define YT921X_VLAN_IGR_FILTER_PORTn(port) BIT(port) #define YT921X_PORTn_ISOLATION(port) (0x180294 + 4 * (port)) #define YT921X_PORT_ISOLATION_BLOCKn(port) BIT(port) +#define YT921X_STPn(n) (0x18038c + 4 * (n)) +#define YT921X_STP_PORTn_M(port) GENMASK(2 * (port) + 1, 2 * (port)) +#define YT921X_STP_PORTn(port, x) ((x) << (2 * (port))) +#define YT921X_STP_PORTn_DISABLED(port) YT921X_STP_PORTn(port, 0) +#define YT921X_STP_PORTn_LEARNING(port) YT921X_STP_PORTn(port, 1) +#define YT921X_STP_PORTn_BLOCKING(port) YT921X_STP_PORTn(port, 2) +#define YT921X_STP_PORTn_FORWARD(port) YT921X_STP_PORTn(port, 3) #define YT921X_PORTn_LEARN(port) (0x1803d0 + 4 * (port)) #define YT921X_PORT_LEARN_VID_LEARN_MULTI_EN BIT(22) #define YT921X_PORT_LEARN_VID_LEARN_MODE BIT(21) @@ -382,23 +389,23 @@ #define YT921X_FDB_HW_FLUSH_ON_LINKDOWN BIT(0) #define YT921X_VLANn_CTRL(vlan) (0x188000 + 8 * (vlan)) -#define YT921X_VLAN_CTRL_UNTAG_PORTS_M GENMASK(50, 40) +#define YT921X_VLAN_CTRL_UNTAG_PORTS_M GENMASK_ULL(50, 40) #define YT921X_VLAN_CTRL_UNTAG_PORTS(x) FIELD_PREP(YT921X_VLAN_CTRL_UNTAG_PORTS_M, (x)) -#define YT921X_VLAN_CTRL_UNTAG_PORTn(port) BIT((port) + 40) -#define YT921X_VLAN_CTRL_STP_ID_M GENMASK(39, 36) +#define YT921X_VLAN_CTRL_UNTAG_PORTn(port) BIT_ULL((port) + 40) +#define YT921X_VLAN_CTRL_STP_ID_M GENMASK_ULL(39, 36) #define YT921X_VLAN_CTRL_STP_ID(x) FIELD_PREP(YT921X_VLAN_CTRL_STP_ID_M, (x)) -#define YT921X_VLAN_CTRL_SVLAN_EN BIT(35) -#define YT921X_VLAN_CTRL_FID_M GENMASK(34, 23) +#define YT921X_VLAN_CTRL_SVLAN_EN BIT_ULL(35) +#define YT921X_VLAN_CTRL_FID_M GENMASK_ULL(34, 23) #define YT921X_VLAN_CTRL_FID(x) FIELD_PREP(YT921X_VLAN_CTRL_FID_M, (x)) -#define YT921X_VLAN_CTRL_LEARN_DIS BIT(22) -#define YT921X_VLAN_CTRL_INT_PRI_EN BIT(21) -#define YT921X_VLAN_CTRL_INT_PRI_M GENMASK(20, 18) -#define YT921X_VLAN_CTRL_PORTS_M GENMASK(17, 7) +#define YT921X_VLAN_CTRL_LEARN_DIS BIT_ULL(22) +#define YT921X_VLAN_CTRL_INT_PRI_EN BIT_ULL(21) +#define YT921X_VLAN_CTRL_INT_PRI_M GENMASK_ULL(20, 18) +#define YT921X_VLAN_CTRL_PORTS_M GENMASK_ULL(17, 7) #define YT921X_VLAN_CTRL_PORTS(x) FIELD_PREP(YT921X_VLAN_CTRL_PORTS_M, (x)) -#define YT921X_VLAN_CTRL_PORTn(port) BIT((port) + 7) -#define YT921X_VLAN_CTRL_BYPASS_1X_AC BIT(6) -#define YT921X_VLAN_CTRL_METER_EN BIT(5) -#define YT921X_VLAN_CTRL_METER_ID_M GENMASK(4, 0) +#define YT921X_VLAN_CTRL_PORTn(port) BIT_ULL((port) + 7) +#define YT921X_VLAN_CTRL_BYPASS_1X_AC BIT_ULL(6) +#define YT921X_VLAN_CTRL_METER_EN BIT_ULL(5) +#define YT921X_VLAN_CTRL_METER_ID_M GENMASK_ULL(4, 0) #define YT921X_TPID_IGRn(x) (0x210000 + 4 * (x)) /* [0, 3] */ #define YT921X_TPID_IGR_TPID_M GENMASK(15, 0) @@ -449,6 +456,8 @@ enum yt921x_fdb_entry_status { YT921X_FDB_ENTRY_STATUS_STATIC = 7, }; +#define YT921X_MSTI_NUM 16 + #define YT9215_MAJOR 0x9002 #define YT9218_MAJOR 0x9001 |
