From f3c5e7ddcc365f66f9b21f3332a95d281a101303 Mon Sep 17 00:00:00 2001 From: Birger Koblitz Date: Tue, 18 Jan 2022 17:20:30 +0100 Subject: realted: Add DSA bridge offload configuration Add functionality to enable or disable L2 learning offload and port flooding for RTL83XX. Signed-off-by: Sebastian Gottschall Signed-off-by: Birger Koblitz --- .../files-5.10/drivers/net/dsa/rtl83xx/dsa.c | 44 +++++++++++++++++++++ .../files-5.10/drivers/net/dsa/rtl83xx/rtl838x.c | 44 +++++++++++++++++++++ .../files-5.10/drivers/net/dsa/rtl83xx/rtl838x.h | 7 +++- .../files-5.10/drivers/net/dsa/rtl83xx/rtl839x.c | 45 ++++++++++++++++++++++ 4 files changed, 139 insertions(+), 1 deletion(-) diff --git a/target/linux/realtek/files-5.10/drivers/net/dsa/rtl83xx/dsa.c b/target/linux/realtek/files-5.10/drivers/net/dsa/rtl83xx/dsa.c index c71396efab..863d36cd36 100644 --- a/target/linux/realtek/files-5.10/drivers/net/dsa/rtl83xx/dsa.c +++ b/target/linux/realtek/files-5.10/drivers/net/dsa/rtl83xx/dsa.c @@ -1927,6 +1927,45 @@ static void rtl83xx_port_mirror_del(struct dsa_switch *ds, int port, mutex_unlock(&priv->reg_mutex); } +static int rtl83xx_port_pre_bridge_flags(struct dsa_switch *ds, int port, unsigned long flags, struct netlink_ext_ack *extack) +{ + struct rtl838x_switch_priv *priv = ds->priv; + unsigned long features = 0; + pr_debug("%s: %d %lX\n", __func__, port, flags); + if (priv->r->enable_learning) + features |= BR_LEARNING; + if (priv->r->enable_flood) + features |= BR_FLOOD; + if (priv->r->enable_mcast_flood) + features |= BR_MCAST_FLOOD; + if (priv->r->enable_bcast_flood) + features |= BR_BCAST_FLOOD; + if (flags & ~(features)) + return -EINVAL; + + return 0; +} + +static int rtl83xx_port_bridge_flags(struct dsa_switch *ds, int port, unsigned long flags, struct netlink_ext_ack *extack) +{ + struct rtl838x_switch_priv *priv = ds->priv; + + pr_debug("%s: %d %lX\n", __func__, port, flags); + if (priv->r->enable_learning) + priv->r->enable_learning(port, !!(flags & BR_LEARNING)); + + if (priv->r->enable_flood) + priv->r->enable_flood(port, !!(flags & BR_FLOOD)); + + if (priv->r->enable_mcast_flood) + priv->r->enable_mcast_flood(port, !!(flags & BR_MCAST_FLOOD)); + + if (priv->r->enable_bcast_flood) + priv->r->enable_bcast_flood(port, !!(flags & BR_BCAST_FLOOD)); + + return 0; +} + static bool rtl83xx_lag_can_offload(struct dsa_switch *ds, struct net_device *lag, struct netdev_lag_upper_info *info) @@ -2123,6 +2162,9 @@ const struct dsa_switch_ops rtl83xx_switch_ops = { .port_lag_change = rtl83xx_port_lag_change, .port_lag_join = rtl83xx_port_lag_join, .port_lag_leave = rtl83xx_port_lag_leave, + + .port_pre_bridge_flags = rtl83xx_port_pre_bridge_flags, + .port_bridge_flags = rtl83xx_port_bridge_flags, }; const struct dsa_switch_ops rtl930x_switch_ops = { @@ -2171,4 +2213,6 @@ const struct dsa_switch_ops rtl930x_switch_ops = { .port_lag_join = rtl83xx_port_lag_join, .port_lag_leave = rtl83xx_port_lag_leave, + .port_pre_bridge_flags = rtl83xx_port_pre_bridge_flags, + .port_bridge_flags = rtl83xx_port_bridge_flags, }; diff --git a/target/linux/realtek/files-5.10/drivers/net/dsa/rtl83xx/rtl838x.c b/target/linux/realtek/files-5.10/drivers/net/dsa/rtl83xx/rtl838x.c index 85e8c85a7f..b130750b16 100644 --- a/target/linux/realtek/files-5.10/drivers/net/dsa/rtl83xx/rtl838x.c +++ b/target/linux/realtek/files-5.10/drivers/net/dsa/rtl83xx/rtl838x.c @@ -512,6 +512,46 @@ static void rtl838x_l2_learning_setup(void) sw_w32(0, RTL838X_SPCL_TRAP_ARP_CTRL); } +static void rtl838x_enable_learning(int port, bool enable) +{ + // Limit learning to maximum: 32k entries, after that just flood (bits 0-1) + + if (enable) { + // flood after 32k entries + sw_w32((0x3fff << 2) | 0, RTL838X_L2_PORT_LRN_CONSTRT + (port << 2)); + } else { + // just forward + sw_w32(0, RTL838X_L2_PORT_LRN_CONSTRT + (port << 2)); + } +} + +static void rtl838x_enable_flood(int port, bool enable) +{ + u32 flood_mask = sw_r32(RTL838X_L2_PORT_LRN_CONSTRT + (port << 2)); + + if (enable) { + // flood + flood_mask &= ~3; + flood_mask |= 0; + sw_w32(flood_mask, RTL838X_L2_PORT_LRN_CONSTRT + (port << 2)); + } else { + // drop (bit 1) + flood_mask &= ~3; + flood_mask |= 1; + sw_w32(flood_mask, RTL838X_L2_PORT_LRN_CONSTRT + (port << 2)); + } +} + +static void rtl838x_enable_mcast_flood(int port, bool enable) +{ + +} + +static void rtl838x_enable_bcast_flood(int port, bool enable) +{ + +} + static void rtl838x_stp_get(struct rtl838x_switch_priv *priv, u16 msti, u32 port_state[]) { int i; @@ -1653,6 +1693,10 @@ const struct rtl838x_reg rtl838x_reg = { .vlan_fwd_on_inner = rtl838x_vlan_fwd_on_inner, .set_vlan_igr_filter = rtl838x_set_igr_filter, .set_vlan_egr_filter = rtl838x_set_egr_filter, + .enable_learning = rtl838x_enable_learning, + .enable_flood = rtl838x_enable_flood, + .enable_mcast_flood = rtl838x_enable_mcast_flood, + .enable_bcast_flood = rtl838x_enable_bcast_flood, .stp_get = rtl838x_stp_get, .stp_set = rtl838x_stp_set, .mac_port_ctrl = rtl838x_mac_port_ctrl, diff --git a/target/linux/realtek/files-5.10/drivers/net/dsa/rtl83xx/rtl838x.h b/target/linux/realtek/files-5.10/drivers/net/dsa/rtl83xx/rtl838x.h index 660efc8cad..b875f545f3 100644 --- a/target/linux/realtek/files-5.10/drivers/net/dsa/rtl83xx/rtl838x.h +++ b/target/linux/realtek/files-5.10/drivers/net/dsa/rtl83xx/rtl838x.h @@ -228,6 +228,8 @@ #define RTL930X_L2_BC_FLD_PMSK (0x9068) #define RTL930X_L2_UNKN_UC_FLD_PMSK (0x9064) #define RTL838X_L2_LRN_CONSTRT_EN (0x3368) +#define RTL838X_L2_PORT_LRN_CONSTRT (0x32A0) +#define RTL839X_L2_PORT_LRN_CONSTRT (0x3914) #define RTL838X_L2_PORT_NEW_SALRN(p) (0x328c + (((p >> 4) << 2))) #define RTL839X_L2_PORT_NEW_SALRN(p) (0x38F0 + (((p >> 4) << 2))) @@ -868,6 +870,10 @@ struct rtl838x_reg { void (*vlan_port_pvid_set)(int port, enum pbvlan_type type, int pvid); void (*set_vlan_igr_filter)(int port, enum igr_filter state); void (*set_vlan_egr_filter)(int port, enum egr_filter state); + void (*enable_learning)(int port, bool enable); + void (*enable_flood)(int port, bool enable); + void (*enable_mcast_flood)(int port, bool enable); + void (*enable_bcast_flood)(int port, bool enable); void (*stp_get)(struct rtl838x_switch_priv *priv, u16 msti, u32 port_state[]); void (*stp_set)(struct rtl838x_switch_priv *priv, u16 msti, u32 port_state[]); int (*mac_force_mode_ctrl)(int port); @@ -922,7 +928,6 @@ struct rtl838x_reg { void (*set_l3_router_mac)(u32 idx, struct rtl93xx_rt_mac *m); void (*set_l3_egress_intf)(int idx, struct rtl838x_l3_intf *intf); void (*set_distribution_algorithm)(int group, int algoidx, u32 algomask); - }; struct rtl838x_switch_priv { diff --git a/target/linux/realtek/files-5.10/drivers/net/dsa/rtl83xx/rtl839x.c b/target/linux/realtek/files-5.10/drivers/net/dsa/rtl83xx/rtl839x.c index 0d1f3e0382..8ae174bd9e 100644 --- a/target/linux/realtek/files-5.10/drivers/net/dsa/rtl83xx/rtl839x.c +++ b/target/linux/realtek/files-5.10/drivers/net/dsa/rtl83xx/rtl839x.c @@ -558,6 +558,47 @@ static void rtl839x_l2_learning_setup(void) sw_w32(0, RTL839X_SPCL_TRAP_ARP_CTRL); } +static void rtl839x_enable_learning(int port, bool enable) +{ + // Limit learning to maximum: 32k entries, after that just flood (bits 0-1) + + if (enable) { + // flood after 32k entries + sw_w32((0x7fff << 2) | 0, RTL839X_L2_PORT_LRN_CONSTRT + (port << 2)); + } else { + // just forward + sw_w32(0, RTL839X_L2_PORT_LRN_CONSTRT + (port << 2)); + } + +} + +static void rtl839x_enable_flood(int port, bool enable) +{ + u32 flood_mask = sw_r32(RTL839X_L2_PORT_LRN_CONSTRT + (port << 2)); + + if (enable) { + // flood + flood_mask &= ~3; + flood_mask |= 0; + sw_w32(flood_mask, RTL839X_L2_PORT_LRN_CONSTRT + (port << 2)); + } else { + // drop (bit 1) + flood_mask &= ~3; + flood_mask |= 1; + sw_w32(flood_mask, RTL839X_L2_PORT_LRN_CONSTRT + (port << 2)); + } + +} + +static void rtl839x_enable_mcast_flood(int port, bool enable) +{ + +} + +static void rtl839x_enable_bcast_flood(int port, bool enable) +{ + +} irqreturn_t rtl839x_switch_irq(int irq, void *dev_id) { struct dsa_switch *ds = dev_id; @@ -1777,6 +1818,10 @@ const struct rtl838x_reg rtl839x_reg = { .vlan_port_pvid_set = rtl839x_vlan_port_pvid_set, .set_vlan_igr_filter = rtl839x_set_igr_filter, .set_vlan_egr_filter = rtl839x_set_egr_filter, + .enable_learning = rtl839x_enable_learning, + .enable_flood = rtl839x_enable_flood, + .enable_mcast_flood = rtl839x_enable_mcast_flood, + .enable_bcast_flood = rtl839x_enable_bcast_flood, .stp_get = rtl839x_stp_get, .stp_set = rtl839x_stp_set, .mac_force_mode_ctrl = rtl839x_mac_force_mode_ctrl, -- cgit v1.2.3