mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-08-30 07:39:12 -04:00
Merge branch 'net-dsa-realtek-rtl8366rb-use-generic-rtl83xx-code'
Linus Walleij says: ==================== net: dsa: realtek: rtl8366rb: Use generic RTL83xx code As a follow-up to Luiz's and Alvin's series improvining the generic handling of the Realtek DSA switches, this small series brings the RTL8366RB closer to the way things are done in the RTL8365MB driver. This patch series switches over to using the generic helpers for: - Bridge joining and leaving (isolation) - STP handling - Learning enable/disable It would be appreciated if this doesn't lead to AI-automated request to fix the entire universe (hi Sashiko, I'm looking at you but I bet you will do you compulsive C3P0-style review anyway) since I'm just moving code around so some helper functions come before their new users. The code itself is pretty straight-forward. Signed-off-by: Linus Walleij <linusw@kernel.org> ==================== Link: https://patch.msgid.link/20260630-rtl8366rb-improvements-v2-0-05eb9d6a37f5@kernel.org Signed-off-by: Paolo Abeni <pabeni@redhat.com>
This commit is contained in:
@@ -791,11 +791,87 @@ static int rtl8366rb_setup_all_leds_off(struct realtek_priv *priv)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int rtl8366rb_port_set_isolation(struct realtek_priv *priv, int port,
|
||||
u32 mask)
|
||||
{
|
||||
/* Bit 0 enables isolation so set this if we enable isolation
|
||||
* any of the ports an clear it if we disable on all of them.
|
||||
*/
|
||||
if (mask)
|
||||
mask = RTL8366RB_PORT_ISO_PORTS(mask) | RTL8366RB_PORT_ISO_EN;
|
||||
|
||||
return regmap_write(priv->map, RTL8366RB_PORT_ISO(port),
|
||||
mask);
|
||||
}
|
||||
|
||||
static int rtl8366rb_port_add_isolation(struct realtek_priv *priv, int port,
|
||||
u32 mask)
|
||||
{
|
||||
/* We assume isolation bit is on */
|
||||
return regmap_update_bits(priv->map, RTL8366RB_PORT_ISO(port),
|
||||
RTL8366RB_PORT_ISO_PORTS(mask),
|
||||
RTL8366RB_PORT_ISO_PORTS(mask));
|
||||
}
|
||||
|
||||
static int rtl8366rb_port_remove_isolation(struct realtek_priv *priv, int port,
|
||||
u32 mask)
|
||||
{
|
||||
return regmap_update_bits(priv->map, RTL8366RB_PORT_ISO(port),
|
||||
RTL8366RB_PORT_ISO_PORTS(mask), 0);
|
||||
}
|
||||
|
||||
static void
|
||||
rtl8366rb_port_stp_state_set(struct dsa_switch *ds, int port, u8 state)
|
||||
{
|
||||
struct realtek_priv *priv = ds->priv;
|
||||
u32 val;
|
||||
int i;
|
||||
|
||||
switch (state) {
|
||||
case BR_STATE_DISABLED:
|
||||
val = RTL8366RB_STP_STATE_DISABLED;
|
||||
break;
|
||||
case BR_STATE_BLOCKING:
|
||||
case BR_STATE_LISTENING:
|
||||
val = RTL8366RB_STP_STATE_BLOCKING;
|
||||
break;
|
||||
case BR_STATE_LEARNING:
|
||||
val = RTL8366RB_STP_STATE_LEARNING;
|
||||
break;
|
||||
case BR_STATE_FORWARDING:
|
||||
val = RTL8366RB_STP_STATE_FORWARDING;
|
||||
break;
|
||||
default:
|
||||
dev_err(priv->dev, "unknown bridge state requested\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Set the same status for the port on all the FIDs */
|
||||
for (i = 0; i < RTL8366RB_NUM_FIDS; i++) {
|
||||
regmap_update_bits(priv->map, RTL8366RB_STP_STATE_BASE + i,
|
||||
RTL8366RB_STP_STATE_MASK(port),
|
||||
RTL8366RB_STP_STATE(port, val));
|
||||
}
|
||||
}
|
||||
|
||||
static int rtl8366rb_port_set_learning(struct realtek_priv *priv, int port,
|
||||
bool enable)
|
||||
{
|
||||
/* Notice inverted semantics in this register: setting a bit disables
|
||||
* learning instead of enabling it.
|
||||
*/
|
||||
return regmap_update_bits(priv->map, RTL8366RB_PORT_LEARNDIS_CTRL,
|
||||
BIT(port), enable ? 0 : BIT(port));
|
||||
}
|
||||
|
||||
static int rtl8366rb_setup(struct dsa_switch *ds)
|
||||
{
|
||||
struct realtek_priv *priv = ds->priv;
|
||||
const struct rtl8366rb_jam_tbl_entry *jam_table;
|
||||
u32 downports_mask = 0;
|
||||
struct rtl8366rb *rb;
|
||||
u32 upports_mask = 0;
|
||||
struct dsa_port *dp;
|
||||
u32 chip_ver = 0;
|
||||
u32 chip_id = 0;
|
||||
int jam_size;
|
||||
@@ -866,20 +942,58 @@ static int rtl8366rb_setup(struct dsa_switch *ds)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Isolate all user ports so they can only send packets to itself and the CPU port */
|
||||
for (i = 0; i < RTL8366RB_PORT_NUM_CPU; i++) {
|
||||
ret = regmap_write(priv->map, RTL8366RB_PORT_ISO(i),
|
||||
RTL8366RB_PORT_ISO_PORTS(BIT(RTL8366RB_PORT_NUM_CPU)) |
|
||||
RTL8366RB_PORT_ISO_EN);
|
||||
/* Start with all ports blocked, including unused ports */
|
||||
dsa_switch_for_each_port(dp, ds) {
|
||||
/* Set the initial STP state of all ports to DISABLED, otherwise
|
||||
* ports will still forward frames to the CPU despite being
|
||||
* administratively down by default.
|
||||
*/
|
||||
rtl8366rb_port_stp_state_set(ds, dp->index, BR_STATE_DISABLED);
|
||||
|
||||
/* Start with all ports completely isolated */
|
||||
ret = rtl8366rb_port_set_isolation(priv, dp->index, 0);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Disable learning */
|
||||
ret = rtl8366rb_port_set_learning(priv, dp->index, false);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Collect CPU ports. If we support cascade switches, it should
|
||||
* also include the upstream DSA ports.
|
||||
*/
|
||||
if (!dsa_port_is_cpu(dp))
|
||||
continue;
|
||||
|
||||
upports_mask |= BIT(dp->index);
|
||||
}
|
||||
|
||||
/* Configure user ports */
|
||||
dsa_switch_for_each_port(dp, ds) {
|
||||
if (!dsa_port_is_user(dp))
|
||||
continue;
|
||||
|
||||
/* Forward only to the CPU */
|
||||
ret = rtl8366rb_port_set_isolation(priv, dp->index, upports_mask);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* If we support cascade switches, it should also include the
|
||||
* downstream DSA ports.
|
||||
*/
|
||||
downports_mask |= BIT(dp->index);
|
||||
}
|
||||
|
||||
/* Configure CPU ports. If we support cascade switches, this will also
|
||||
* include DSA ports.
|
||||
*/
|
||||
dsa_switch_for_each_cpu_port(dp, ds) {
|
||||
/* Forward to all user ports */
|
||||
ret = rtl8366rb_port_set_isolation(priv, dp->index, downports_mask);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
/* CPU port can send packets to all ports */
|
||||
ret = regmap_write(priv->map, RTL8366RB_PORT_ISO(RTL8366RB_PORT_NUM_CPU),
|
||||
RTL8366RB_PORT_ISO_PORTS(dsa_user_ports(ds)) |
|
||||
RTL8366RB_PORT_ISO_EN);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Set up the "green ethernet" feature */
|
||||
ret = rtl8366rb_jam_table(rtl8366rb_green_jam,
|
||||
@@ -938,12 +1052,6 @@ static int rtl8366rb_setup(struct dsa_switch *ds)
|
||||
rb->max_mtu[i] = ETH_DATA_LEN;
|
||||
}
|
||||
|
||||
/* Disable learning for all ports */
|
||||
ret = regmap_write(priv->map, RTL8366RB_PORT_LEARNDIS_CTRL,
|
||||
RTL8366RB_PORT_ALL);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Enable auto ageing for all ports */
|
||||
ret = regmap_write(priv->map, RTL8366RB_SECURITY_CTRL, 0);
|
||||
if (ret)
|
||||
@@ -1184,70 +1292,6 @@ rtl8366rb_port_disable(struct dsa_switch *ds, int port)
|
||||
return;
|
||||
}
|
||||
|
||||
static int
|
||||
rtl8366rb_port_bridge_join(struct dsa_switch *ds, int port,
|
||||
struct dsa_bridge bridge,
|
||||
bool *tx_fwd_offload,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
struct realtek_priv *priv = ds->priv;
|
||||
unsigned int port_bitmap = 0;
|
||||
int ret, i;
|
||||
|
||||
/* Loop over all other ports than the current one */
|
||||
for (i = 0; i < RTL8366RB_PORT_NUM_CPU; i++) {
|
||||
/* Current port handled last */
|
||||
if (i == port)
|
||||
continue;
|
||||
/* Not on this bridge */
|
||||
if (!dsa_port_offloads_bridge(dsa_to_port(ds, i), &bridge))
|
||||
continue;
|
||||
/* Join this port to each other port on the bridge */
|
||||
ret = regmap_update_bits(priv->map, RTL8366RB_PORT_ISO(i),
|
||||
RTL8366RB_PORT_ISO_PORTS(BIT(port)),
|
||||
RTL8366RB_PORT_ISO_PORTS(BIT(port)));
|
||||
if (ret)
|
||||
dev_err(priv->dev, "failed to join port %d\n", port);
|
||||
|
||||
port_bitmap |= BIT(i);
|
||||
}
|
||||
|
||||
/* Set the bits for the ports we can access */
|
||||
return regmap_update_bits(priv->map, RTL8366RB_PORT_ISO(port),
|
||||
RTL8366RB_PORT_ISO_PORTS(port_bitmap),
|
||||
RTL8366RB_PORT_ISO_PORTS(port_bitmap));
|
||||
}
|
||||
|
||||
static void
|
||||
rtl8366rb_port_bridge_leave(struct dsa_switch *ds, int port,
|
||||
struct dsa_bridge bridge)
|
||||
{
|
||||
struct realtek_priv *priv = ds->priv;
|
||||
unsigned int port_bitmap = 0;
|
||||
int ret, i;
|
||||
|
||||
/* Loop over all other ports than this one */
|
||||
for (i = 0; i < RTL8366RB_PORT_NUM_CPU; i++) {
|
||||
/* Current port handled last */
|
||||
if (i == port)
|
||||
continue;
|
||||
/* Not on this bridge */
|
||||
if (!dsa_port_offloads_bridge(dsa_to_port(ds, i), &bridge))
|
||||
continue;
|
||||
/* Remove this port from any other port on the bridge */
|
||||
ret = regmap_update_bits(priv->map, RTL8366RB_PORT_ISO(i),
|
||||
RTL8366RB_PORT_ISO_PORTS(BIT(port)), 0);
|
||||
if (ret)
|
||||
dev_err(priv->dev, "failed to leave port %d\n", port);
|
||||
|
||||
port_bitmap |= BIT(i);
|
||||
}
|
||||
|
||||
/* Clear the bits for the ports we can not access, leave ourselves */
|
||||
regmap_update_bits(priv->map, RTL8366RB_PORT_ISO(port),
|
||||
RTL8366RB_PORT_ISO_PORTS(port_bitmap), 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* rtl8366rb_drop_untagged() - make the switch drop untagged and C-tagged frames
|
||||
* @priv: SMI state container
|
||||
@@ -1306,59 +1350,6 @@ rtl8366rb_port_pre_bridge_flags(struct dsa_switch *ds, int port,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
rtl8366rb_port_bridge_flags(struct dsa_switch *ds, int port,
|
||||
struct switchdev_brport_flags flags,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
struct realtek_priv *priv = ds->priv;
|
||||
int ret;
|
||||
|
||||
if (flags.mask & BR_LEARNING) {
|
||||
ret = regmap_update_bits(priv->map, RTL8366RB_PORT_LEARNDIS_CTRL,
|
||||
BIT(port),
|
||||
(flags.val & BR_LEARNING) ? 0 : BIT(port));
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
rtl8366rb_port_stp_state_set(struct dsa_switch *ds, int port, u8 state)
|
||||
{
|
||||
struct realtek_priv *priv = ds->priv;
|
||||
u32 val;
|
||||
int i;
|
||||
|
||||
switch (state) {
|
||||
case BR_STATE_DISABLED:
|
||||
val = RTL8366RB_STP_STATE_DISABLED;
|
||||
break;
|
||||
case BR_STATE_BLOCKING:
|
||||
case BR_STATE_LISTENING:
|
||||
val = RTL8366RB_STP_STATE_BLOCKING;
|
||||
break;
|
||||
case BR_STATE_LEARNING:
|
||||
val = RTL8366RB_STP_STATE_LEARNING;
|
||||
break;
|
||||
case BR_STATE_FORWARDING:
|
||||
val = RTL8366RB_STP_STATE_FORWARDING;
|
||||
break;
|
||||
default:
|
||||
dev_err(priv->dev, "unknown bridge state requested\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Set the same status for the port on all the FIDs */
|
||||
for (i = 0; i < RTL8366RB_NUM_FIDS; i++) {
|
||||
regmap_update_bits(priv->map, RTL8366RB_STP_STATE_BASE + i,
|
||||
RTL8366RB_STP_STATE_MASK(port),
|
||||
RTL8366RB_STP_STATE(port, val));
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
rtl8366rb_port_fast_age(struct dsa_switch *ds, int port)
|
||||
{
|
||||
@@ -1801,15 +1792,15 @@ static const struct dsa_switch_ops rtl8366rb_switch_ops = {
|
||||
.get_strings = rtl8366_get_strings,
|
||||
.get_ethtool_stats = rtl8366_get_ethtool_stats,
|
||||
.get_sset_count = rtl8366_get_sset_count,
|
||||
.port_bridge_join = rtl8366rb_port_bridge_join,
|
||||
.port_bridge_leave = rtl8366rb_port_bridge_leave,
|
||||
.port_bridge_join = rtl83xx_port_bridge_join,
|
||||
.port_bridge_leave = rtl83xx_port_bridge_leave,
|
||||
.port_vlan_filtering = rtl8366rb_vlan_filtering,
|
||||
.port_vlan_add = rtl8366_vlan_add,
|
||||
.port_vlan_del = rtl8366_vlan_del,
|
||||
.port_enable = rtl8366rb_port_enable,
|
||||
.port_disable = rtl8366rb_port_disable,
|
||||
.port_pre_bridge_flags = rtl8366rb_port_pre_bridge_flags,
|
||||
.port_bridge_flags = rtl8366rb_port_bridge_flags,
|
||||
.port_bridge_flags = rtl83xx_port_bridge_flags,
|
||||
.port_stp_state_set = rtl8366rb_port_stp_state_set,
|
||||
.port_fast_age = rtl8366rb_port_fast_age,
|
||||
.port_change_mtu = rtl8366rb_change_mtu,
|
||||
@@ -1830,6 +1821,9 @@ static const struct realtek_ops rtl8366rb_ops = {
|
||||
.is_vlan_valid = rtl8366rb_is_vlan_valid,
|
||||
.enable_vlan = rtl8366rb_enable_vlan,
|
||||
.enable_vlan4k = rtl8366rb_enable_vlan4k,
|
||||
.port_add_isolation = rtl8366rb_port_add_isolation,
|
||||
.port_remove_isolation = rtl8366rb_port_remove_isolation,
|
||||
.port_set_learning = rtl8366rb_port_set_learning,
|
||||
.phy_read = rtl8366rb_phy_read,
|
||||
.phy_write = rtl8366rb_phy_write,
|
||||
};
|
||||
|
||||
@@ -356,9 +356,6 @@ int rtl83xx_port_bridge_join(struct dsa_switch *ds, int port,
|
||||
if (!priv->ops->port_add_isolation)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (!priv->ops->port_set_learning)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
dev_dbg(priv->dev, "bridge %d join port %d\n", bridge.num, port);
|
||||
|
||||
/* Add this port to the isolation group of every other port
|
||||
@@ -396,9 +393,11 @@ int rtl83xx_port_bridge_join(struct dsa_switch *ds, int port,
|
||||
goto undo_self_isolation;
|
||||
}
|
||||
|
||||
ret = priv->ops->port_set_learning(priv, port, true);
|
||||
if (ret)
|
||||
goto undo_efid;
|
||||
if (priv->ops->port_set_learning) {
|
||||
ret = priv->ops->port_set_learning(priv, port, true);
|
||||
if (ret)
|
||||
goto undo_efid;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -443,9 +442,6 @@ void rtl83xx_port_bridge_leave(struct dsa_switch *ds, int port,
|
||||
if (!priv->ops->port_remove_isolation)
|
||||
return;
|
||||
|
||||
if (!priv->ops->port_set_learning)
|
||||
return;
|
||||
|
||||
dev_dbg(priv->dev, "bridge %d leave port %d\n", bridge.num, port);
|
||||
|
||||
/* Remove this port from the isolation group of every other
|
||||
@@ -474,11 +470,13 @@ void rtl83xx_port_bridge_leave(struct dsa_switch *ds, int port,
|
||||
* downstream DSA ports from the isolation group.
|
||||
*/
|
||||
|
||||
ret = priv->ops->port_set_learning(priv, port, false);
|
||||
if (ret)
|
||||
dev_err(priv->dev,
|
||||
"failed to disable learning on port %d: %pe\n",
|
||||
port, ERR_PTR(ret));
|
||||
if (priv->ops->port_set_learning) {
|
||||
ret = priv->ops->port_set_learning(priv, port, false);
|
||||
if (ret)
|
||||
dev_err(priv->dev,
|
||||
"failed to disable learning on port %d: %pe\n",
|
||||
port, ERR_PTR(ret));
|
||||
}
|
||||
|
||||
/* Remove those ports from the isolation group of this port */
|
||||
ret = priv->ops->port_remove_isolation(priv, port, mask);
|
||||
|
||||
Reference in New Issue
Block a user