diff options
4 files changed, 0 insertions, 1113 deletions
diff --git a/target/linux/realtek/patches-5.15/007-5.16-gpio-realtek-realtek-otto-fix-gpio-line-irq-offset.patch b/target/linux/realtek/patches-5.15/007-5.16-gpio-realtek-realtek-otto-fix-gpio-line-irq-offset.patch deleted file mode 100644 index 9935c57257..0000000000 --- a/target/linux/realtek/patches-5.15/007-5.16-gpio-realtek-realtek-otto-fix-gpio-line-irq-offset.patch +++ /dev/null @@ -1,22 +0,0 @@ -From: Sander Vanheule <sander@svanheule.net> -Subject: gpio: realtek-otto: fix GPIO line IRQ offset - -The irqchip uses one domain for all GPIO lines, so th line offset should be -determined w.r.t. the first line of the first port, not the first line of the -triggered port. - -Fixes: 0d82fb1127fb ("gpio: Add Realtek Otto GPIO support") -Signed-off-by: Sander Vanheule <sander@svanheule.net> -Link: https://lore.kernel.org/linux-gpio/20211028085243.34360-1-sander@svanheule.net/ - ---- a/drivers/gpio/gpio-realtek-otto.c -+++ b/drivers/gpio/gpio-realtek-otto.c -@@ -206,7 +206,7 @@ static void realtek_gpio_irq_handler(str - status = realtek_gpio_read_isr(ctrl, lines_done / 8); - port_pin_count = min(gc->ngpio - lines_done, 8U); - for_each_set_bit(offset, &status, port_pin_count) { -- irq = irq_find_mapping(gc->irq.domain, offset); -+ irq = irq_find_mapping(gc->irq.domain, offset + lines_done); - generic_handle_irq(irq); - } - } diff --git a/target/linux/realtek/patches-5.15/708-brflood-api.patch b/target/linux/realtek/patches-5.15/708-brflood-api.patch deleted file mode 100644 index 2716933ae7..0000000000 --- a/target/linux/realtek/patches-5.15/708-brflood-api.patch +++ /dev/null @@ -1,162 +0,0 @@ -From afa3ab54c03d5126b14651f367b38165fab5b3cc Mon Sep 17 00:00:00 2001 -From: Birger Koblitz <git@birger-koblitz.de> -Date: Tue, 18 Jan 2022 17:18:43 +0100 -Subject: net: brflood API - -Adds the DSA API for bridge configuration (flooding, L2 learning, -and aging) offload as found in Linux 5.12 so that we can implement -it in our drivver. - -Submitted-by: Sebastian Gottschall <s.gottschall@dd-wrt.com> -Submitted-by: Birger Koblitz <git@birger-koblitz.de> ---- - include/net/dsa.h | 6 +++++++-- - net/dsa/dsa_priv.h | 6 +++--- - net/dsa/port.c | 28 ++++++++---- - net/dsa/slave.c | 6 +++--- - 4 file changed, 29 insertions(+), 13 deletions(-) - ---- a/include/net/dsa.h -+++ b/include/net/dsa.h -@@ -552,8 +552,14 @@ struct dsa_switch_ops { - void (*port_stp_state_set)(struct dsa_switch *ds, int port, - u8 state); - void (*port_fast_age)(struct dsa_switch *ds, int port); -- int (*port_egress_floods)(struct dsa_switch *ds, int port, -- bool unicast, bool multicast); -+ int (*port_pre_bridge_flags)(struct dsa_switch *ds, int port, -+ unsigned long flags, -+ struct netlink_ext_ack *extack); -+ int (*port_bridge_flags)(struct dsa_switch *ds, int port, -+ unsigned long flags, -+ struct netlink_ext_ack *extack); -+ int (*port_set_mrouter)(struct dsa_switch *ds, int port, bool mrouter, -+ struct netlink_ext_ack *extack); - - /* - * VLAN support ---- a/net/dsa/dsa_priv.h -+++ b/net/dsa/dsa_priv.h -@@ -167,11 +167,11 @@ int dsa_port_mdb_add(const struct dsa_po - int dsa_port_mdb_del(const struct dsa_port *dp, - const struct switchdev_obj_port_mdb *mdb); - int dsa_port_pre_bridge_flags(const struct dsa_port *dp, unsigned long flags, -- struct switchdev_trans *trans); -+ struct switchdev_trans *trans, struct netlink_ext_ack *extack); - int dsa_port_bridge_flags(const struct dsa_port *dp, unsigned long flags, -- struct switchdev_trans *trans); -+ struct switchdev_trans *trans, struct netlink_ext_ack *extack); - int dsa_port_mrouter(struct dsa_port *dp, bool mrouter, -- struct switchdev_trans *trans); -+ struct switchdev_trans *trans, struct netlink_ext_ack *extack); - int dsa_port_vlan_add(struct dsa_port *dp, - const struct switchdev_obj_port_vlan *vlan, - struct switchdev_trans *trans); ---- a/net/dsa/port.c -+++ b/net/dsa/port.c -@@ -145,7 +145,7 @@ int dsa_port_bridge_join(struct dsa_port - int err; - - /* Set the flooding mode before joining the port in the switch */ -- err = dsa_port_bridge_flags(dp, BR_FLOOD | BR_MCAST_FLOOD, NULL); -+ err = dsa_port_bridge_flags(dp, BR_FLOOD | BR_MCAST_FLOOD, NULL, NULL); - if (err) - return err; - -@@ -158,7 +158,7 @@ int dsa_port_bridge_join(struct dsa_port - - /* The bridging is rolled back on error */ - if (err) { -- dsa_port_bridge_flags(dp, 0, NULL); -+ dsa_port_bridge_flags(dp, 0, NULL, NULL); - dp->bridge_dev = NULL; - } - -@@ -185,7 +185,7 @@ void dsa_port_bridge_leave(struct dsa_po - pr_err("DSA: failed to notify DSA_NOTIFIER_BRIDGE_LEAVE\n"); - - /* Port is leaving the bridge, disable flooding */ -- dsa_port_bridge_flags(dp, 0, NULL); -+ dsa_port_bridge_flags(dp, 0, NULL, NULL); - - /* Port left the bridge, put in BR_STATE_DISABLED by the bridge layer, - * so allow it to be in BR_STATE_FORWARDING to be kept functional -@@ -333,44 +333,44 @@ int dsa_port_ageing_time(struct dsa_port - } - - int dsa_port_pre_bridge_flags(const struct dsa_port *dp, unsigned long flags, -- struct switchdev_trans *trans) -+ struct switchdev_trans *trans, struct netlink_ext_ack *extack) - { - struct dsa_switch *ds = dp->ds; - -- if (!ds->ops->port_egress_floods || -- (flags & ~(BR_FLOOD | BR_MCAST_FLOOD))) -+ if (!ds->ops->port_pre_bridge_flags) - return -EINVAL; - -- return 0; -+ return ds->ops->port_pre_bridge_flags(ds, dp->index, flags, extack); - } - - int dsa_port_bridge_flags(const struct dsa_port *dp, unsigned long flags, -- struct switchdev_trans *trans) -+ struct switchdev_trans *trans, struct netlink_ext_ack *extack) - { - struct dsa_switch *ds = dp->ds; -- int port = dp->index; -- int err = 0; - - if (switchdev_trans_ph_prepare(trans)) - return 0; - -- if (ds->ops->port_egress_floods) -- err = ds->ops->port_egress_floods(ds, port, flags & BR_FLOOD, -- flags & BR_MCAST_FLOOD); -+ if (!ds->ops->port_bridge_flags) -+ return -EINVAL; -+ -+ return ds->ops->port_bridge_flags(ds, dp->index, flags, extack); - -- return err; - } - - int dsa_port_mrouter(struct dsa_port *dp, bool mrouter, -- struct switchdev_trans *trans) -+ struct switchdev_trans *trans, -+ struct netlink_ext_ack *extack) - { - struct dsa_switch *ds = dp->ds; -- int port = dp->index; - - if (switchdev_trans_ph_prepare(trans)) -- return ds->ops->port_egress_floods ? 0 : -EOPNOTSUPP; -+ return ds->ops->port_set_mrouter ? 0 : -EOPNOTSUPP; -+ -+ if (!ds->ops->port_set_mrouter) -+ return -EOPNOTSUPP; - -- return ds->ops->port_egress_floods(ds, port, true, mrouter); -+ return ds->ops->port_set_mrouter(ds, dp->index, mrouter, extack); - } - - int dsa_port_mtu_change(struct dsa_port *dp, int new_mtu, ---- a/net/dsa/slave.c -+++ b/net/dsa/slave.c -@@ -290,13 +290,13 @@ static int dsa_slave_port_attr_set(struc - break; - case SWITCHDEV_ATTR_ID_PORT_PRE_BRIDGE_FLAGS: - ret = dsa_port_pre_bridge_flags(dp, attr->u.brport_flags, -- trans); -+ trans, NULL); - break; - case SWITCHDEV_ATTR_ID_PORT_BRIDGE_FLAGS: -- ret = dsa_port_bridge_flags(dp, attr->u.brport_flags, trans); -+ ret = dsa_port_bridge_flags(dp, attr->u.brport_flags, trans, NULL); - break; - case SWITCHDEV_ATTR_ID_BRIDGE_MROUTER: -- ret = dsa_port_mrouter(dp->cpu_dp, attr->u.mrouter, trans); -+ ret = dsa_port_mrouter(dp->cpu_dp, attr->u.mrouter, trans, NULL); - break; - default: - ret = -EOPNOTSUPP; diff --git a/target/linux/realtek/patches-5.15/709-lag-offloading.patch b/target/linux/realtek/patches-5.15/709-lag-offloading.patch deleted file mode 100644 index f84687ff4a..0000000000 --- a/target/linux/realtek/patches-5.15/709-lag-offloading.patch +++ /dev/null @@ -1,781 +0,0 @@ -From afa3ab54c03d5126b14651f367b38165fab5b3cc Mon Sep 17 00:00:00 2001 -From: Birger Koblitz <git@birger-koblitz.de> -Date: Tue, 18 Jan 2022 17:18:43 +0100 -Subject: [PATCH] realtek: Backport bridge configuration for DSA - -Adds the DSA API for bridge configuration (flooding, L2 learning, -and aging) offload as found in Linux 5.12 so that we can implement -it in our drivver. - -Submitted-by: Sebastian Gottschall <s.gottschall@dd-wrt.com> -Submitted-by: Birger Koblitz <git@birger-koblitz.de> ---- - drivers/net/bonding/bond_main.c | 2 ++ - include/net/dsa.h | 79 ++++++++++++++++- - net/dsa/dsa2.c | 88 +++++++++++++++++++ - net/dsa/dsa_priv.h | 74 ++++++++++++++ - net/dsa/port.c | 92 ++++++++++++++++++++ - net/dsa/slave.c | 88 ++++++++++++++++--- - net/dsa/switch.c | 49 ++++++++++ - net/sda/tag_dsa.c | 13 +++++- - 8 file changed, 460 insertions(+), 25 deletions(-) - ---- a/drivers/net/bonding/bond_main.c -+++ b/drivers/net/bonding/bond_main.c -@@ -2045,6 +2045,8 @@ int bond_enslave(struct net_device *bond - goto err_unregister; - } - -+ bond_lower_state_changed(new_slave); -+ - res = bond_sysfs_slave_add(new_slave); - if (res) { - slave_dbg(bond_dev, slave_dev, "Error %d calling bond_sysfs_slave_add\n", res); ---- a/include/net/dsa.h -+++ b/include/net/dsa.h -@@ -149,8 +149,41 @@ struct dsa_switch_tree { - - /* List of DSA links composing the routing table */ - struct list_head rtable; -+ -+ /* Maps offloaded LAG netdevs to a zero-based linear ID for -+ * drivers that need it. -+ */ -+ struct net_device **lags; -+ unsigned int lags_len; - }; - -+#define dsa_lags_foreach_id(_id, _dst) \ -+ for ((_id) = 0; (_id) < (_dst)->lags_len; (_id)++) \ -+ if ((_dst)->lags[(_id)]) -+ -+#define dsa_lag_foreach_port(_dp, _dst, _lag) \ -+ list_for_each_entry((_dp), &(_dst)->ports, list) \ -+ if ((_dp)->lag_dev == (_lag)) -+ -+static inline struct net_device *dsa_lag_dev(struct dsa_switch_tree *dst, -+ unsigned int id) -+{ -+ return dst->lags[id]; -+} -+ -+static inline int dsa_lag_id(struct dsa_switch_tree *dst, -+ struct net_device *lag) -+{ -+ unsigned int id; -+ -+ dsa_lags_foreach_id(id, dst) { -+ if (dsa_lag_dev(dst, id) == lag) -+ return id; -+ } -+ -+ return -ENODEV; -+} -+ - /* TC matchall action types */ - enum dsa_port_mall_action_type { - DSA_PORT_MALL_MIRROR, -@@ -220,6 +253,8 @@ struct dsa_port { - bool devlink_port_setup; - struct phylink *pl; - struct phylink_config pl_config; -+ struct net_device *lag_dev; -+ bool lag_tx_enabled; - - struct list_head list; - -@@ -340,6 +375,14 @@ struct dsa_switch { - */ - bool mtu_enforcement_ingress; - -+ /* Drivers that benefit from having an ID associated with each -+ * offloaded LAG should set this to the maximum number of -+ * supported IDs. DSA will then maintain a mapping of _at -+ * least_ these many IDs, accessible to drivers via -+ * dsa_lag_id(). -+ */ -+ unsigned int num_lag_ids; -+ - size_t num_ports; - }; - -@@ -432,6 +475,18 @@ static inline bool dsa_port_is_vlan_filt - return dp->vlan_filtering; - } - -+static inline -+struct net_device *dsa_port_to_bridge_port(const struct dsa_port *dp) -+{ -+ if (!dp->bridge_dev) -+ return NULL; -+ -+ if (dp->lag_dev) -+ return dp->lag_dev; -+ -+ return dp->slave; -+} -+ - typedef int dsa_fdb_dump_cb_t(const unsigned char *addr, u16 vid, - bool is_static, void *data); - struct dsa_switch_ops { -@@ -629,6 +684,13 @@ struct dsa_switch_ops { - void (*crosschip_bridge_leave)(struct dsa_switch *ds, int tree_index, - int sw_index, int port, - struct net_device *br); -+ int (*crosschip_lag_change)(struct dsa_switch *ds, int sw_index, -+ int port); -+ int (*crosschip_lag_join)(struct dsa_switch *ds, int sw_index, -+ int port, struct net_device *lag, -+ struct netdev_lag_upper_info *info); -+ int (*crosschip_lag_leave)(struct dsa_switch *ds, int sw_index, -+ int port, struct net_device *lag); - - /* - * PTP functionality -@@ -660,6 +722,16 @@ struct dsa_switch_ops { - int (*port_change_mtu)(struct dsa_switch *ds, int port, - int new_mtu); - int (*port_max_mtu)(struct dsa_switch *ds, int port); -+ -+ /* -+ * LAG integration -+ */ -+ int (*port_lag_change)(struct dsa_switch *ds, int port); -+ int (*port_lag_join)(struct dsa_switch *ds, int port, -+ struct net_device *lag, -+ struct netdev_lag_upper_info *info); -+ int (*port_lag_leave)(struct dsa_switch *ds, int port, -+ struct net_device *lag); - }; - - #define DSA_DEVLINK_PARAM_DRIVER(_id, _name, _type, _cmodes) \ ---- a/net/dsa/dsa.c -+++ b/net/dsa/dsa.c -@@ -220,11 +220,21 @@ static int dsa_switch_rcv(struct sk_buff - } - - skb = nskb; -- p = netdev_priv(skb->dev); - skb_push(skb, ETH_HLEN); - skb->pkt_type = PACKET_HOST; - skb->protocol = eth_type_trans(skb, skb->dev); - -+ if (unlikely(!dsa_slave_dev_check(skb->dev))) { -+ /* Packet is to be injected directly on an upper -+ * device, e.g. a team/bond, so skip all DSA-port -+ * specific actions. -+ */ -+ netif_rx(skb); -+ return 0; -+ } -+ -+ p = netdev_priv(skb->dev); -+ - if (unlikely(cpu_dp->ds->untag_bridge_pvid)) { - nskb = dsa_untag_bridge_pvid(skb); - if (!nskb) { ---- a/net/dsa/dsa2.c -+++ b/net/dsa/dsa2.c -@@ -21,6 +21,65 @@ - static DEFINE_MUTEX(dsa2_mutex); - LIST_HEAD(dsa_tree_list); - -+/** -+ * dsa_lag_map() - Map LAG netdev to a linear LAG ID -+ * @dst: Tree in which to record the mapping. -+ * @lag: Netdev that is to be mapped to an ID. -+ * -+ * dsa_lag_id/dsa_lag_dev can then be used to translate between the -+ * two spaces. The size of the mapping space is determined by the -+ * driver by setting ds->num_lag_ids. It is perfectly legal to leave -+ * it unset if it is not needed, in which case these functions become -+ * no-ops. -+ */ -+void dsa_lag_map(struct dsa_switch_tree *dst, struct net_device *lag) -+{ -+ unsigned int id; -+ -+ if (dsa_lag_id(dst, lag) >= 0) -+ /* Already mapped */ -+ return; -+ -+ for (id = 0; id < dst->lags_len; id++) { -+ if (!dsa_lag_dev(dst, id)) { -+ dst->lags[id] = lag; -+ return; -+ } -+ } -+ -+ /* No IDs left, which is OK. Some drivers do not need it. The -+ * ones that do, e.g. mv88e6xxx, will discover that dsa_lag_id -+ * returns an error for this device when joining the LAG. The -+ * driver can then return -EOPNOTSUPP back to DSA, which will -+ * fall back to a software LAG. -+ */ -+} -+ -+/** -+ * dsa_lag_unmap() - Remove a LAG ID mapping -+ * @dst: Tree in which the mapping is recorded. -+ * @lag: Netdev that was mapped. -+ * -+ * As there may be multiple users of the mapping, it is only removed -+ * if there are no other references to it. -+ */ -+void dsa_lag_unmap(struct dsa_switch_tree *dst, struct net_device *lag) -+{ -+ struct dsa_port *dp; -+ unsigned int id; -+ -+ dsa_lag_foreach_port(dp, dst, lag) -+ /* There are remaining users of this mapping */ -+ return; -+ -+ dsa_lags_foreach_id(id, dst) { -+ if (dsa_lag_dev(dst, id) == lag) { -+ dst->lags[id] = NULL; -+ break; -+ } -+ } -+} -+ - struct dsa_switch *dsa_switch_find(int tree_index, int sw_index) - { - struct dsa_switch_tree *dst; -@@ -597,6 +656,32 @@ static void dsa_tree_teardown_master(str - dsa_master_teardown(dp->master); - } - -+static int dsa_tree_setup_lags(struct dsa_switch_tree *dst) -+{ -+ unsigned int len = 0; -+ struct dsa_port *dp; -+ -+ list_for_each_entry(dp, &dst->ports, list) { -+ if (dp->ds->num_lag_ids > len) -+ len = dp->ds->num_lag_ids; -+ } -+ -+ if (!len) -+ return 0; -+ -+ dst->lags = kcalloc(len, sizeof(*dst->lags), GFP_KERNEL); -+ if (!dst->lags) -+ return -ENOMEM; -+ -+ dst->lags_len = len; -+ return 0; -+} -+ -+static void dsa_tree_teardown_lags(struct dsa_switch_tree *dst) -+{ -+ kfree(dst->lags); -+} -+ - static int dsa_tree_setup(struct dsa_switch_tree *dst) - { - bool complete; -@@ -624,12 +709,18 @@ static int dsa_tree_setup(struct dsa_swi - if (err) - goto teardown_switches; - -+ err = dsa_tree_setup_lags(dst); -+ if (err) -+ goto teardown_master; -+ - dst->setup = true; - - pr_info("DSA: tree %d setup\n", dst->index); - - return 0; - -+teardown_master: -+ dsa_tree_teardown_master(dst); - teardown_switches: - dsa_tree_teardown_switches(dst); - teardown_default_cpu: -@@ -645,6 +736,8 @@ static void dsa_tree_teardown(struct dsa - if (!dst->setup) - return; - -+ dsa_tree_teardown_lags(dst); -+ - dsa_tree_teardown_master(dst); - - dsa_tree_teardown_switches(dst); ---- a/net/dsa/dsa_priv.h -+++ b/net/dsa/dsa_priv.h -@@ -20,6 +20,9 @@ enum { - DSA_NOTIFIER_BRIDGE_LEAVE, - DSA_NOTIFIER_FDB_ADD, - DSA_NOTIFIER_FDB_DEL, -+ DSA_NOTIFIER_LAG_CHANGE, -+ DSA_NOTIFIER_LAG_JOIN, -+ DSA_NOTIFIER_LAG_LEAVE, - DSA_NOTIFIER_MDB_ADD, - DSA_NOTIFIER_MDB_DEL, - DSA_NOTIFIER_VLAN_ADD, -@@ -57,6 +60,15 @@ struct dsa_notifier_mdb_info { - int port; - }; - -+/* DSA_NOTIFIER_LAG_* */ -+struct dsa_notifier_lag_info { -+ struct net_device *lag; -+ int sw_index; -+ int port; -+ -+ struct netdev_lag_upper_info *info; -+}; -+ - /* DSA_NOTIFIER_VLAN_* */ - struct dsa_notifier_vlan_info { - const struct switchdev_obj_port_vlan *vlan; -@@ -149,6 +161,11 @@ void dsa_port_disable_rt(struct dsa_port - void dsa_port_disable(struct dsa_port *dp); - int dsa_port_bridge_join(struct dsa_port *dp, struct net_device *br); - void dsa_port_bridge_leave(struct dsa_port *dp, struct net_device *br); -+int dsa_port_lag_change(struct dsa_port *dp, -+ struct netdev_lag_lower_state_info *linfo); -+int dsa_port_lag_join(struct dsa_port *dp, struct net_device *lag_dev, -+ struct netdev_lag_upper_info *uinfo); -+void dsa_port_lag_leave(struct dsa_port *dp, struct net_device *lag_dev); - int dsa_port_vlan_filtering(struct dsa_port *dp, bool vlan_filtering, - struct switchdev_trans *trans); - bool dsa_port_skip_vlan_configuration(struct dsa_port *dp); -@@ -181,6 +198,71 @@ int dsa_port_link_register_of(struct dsa - void dsa_port_link_unregister_of(struct dsa_port *dp); - extern const struct phylink_mac_ops dsa_port_phylink_mac_ops; - -+static inline bool dsa_port_offloads_netdev(struct dsa_port *dp, -+ struct net_device *dev) -+{ -+ /* Switchdev offloading can be configured on: */ -+ -+ if (dev == dp->slave) -+ /* DSA ports directly connected to a bridge, and event -+ * was emitted for the ports themselves. -+ */ -+ return true; -+ -+ if (dp->bridge_dev == dev) -+ /* DSA ports connected to a bridge, and event was emitted -+ * for the bridge. -+ */ -+ return true; -+ -+ if (dp->lag_dev == dev) -+ /* DSA ports connected to a bridge via a LAG */ -+ return true; -+ -+ return false; -+} -+ -+static inline bool dsa_port_offloads_bridge_port(struct dsa_port *dp, -+ struct net_device *dev) -+{ -+ return dsa_port_to_bridge_port(dp) == dev; -+} -+ -+static inline bool dsa_port_offloads_bridge(struct dsa_port *dp, -+ struct net_device *bridge_dev) -+{ -+ /* DSA ports connected to a bridge, and event was emitted -+ * for the bridge. -+ */ -+ return dp->bridge_dev == bridge_dev; -+} -+ -+/* Returns true if any port of this tree offloads the given net_device */ -+static inline bool dsa_tree_offloads_bridge_port(struct dsa_switch_tree *dst, -+ struct net_device *dev) -+{ -+ struct dsa_port *dp; -+ -+ list_for_each_entry(dp, &dst->ports, list) -+ if (dsa_port_offloads_bridge_port(dp, dev)) -+ return true; -+ -+ return false; -+} -+ -+/* Returns true if any port of this tree offloads the given net_device */ -+static inline bool dsa_tree_offloads_netdev(struct dsa_switch_tree *dst, -+ struct net_device *dev) -+{ -+ struct dsa_port *dp; -+ -+ list_for_each_entry(dp, &dst->ports, list) -+ if (dsa_port_offloads_netdev(dp, dev)) -+ return true; -+ -+ return false; -+} -+ - /* slave.c */ - extern const struct dsa_device_ops notag_netdev_ops; - void dsa_slave_mii_bus_init(struct dsa_switch *ds); -@@ -285,6 +367,9 @@ int dsa_switch_register_notifier(struct - void dsa_switch_unregister_notifier(struct dsa_switch *ds); - - /* dsa2.c */ -+void dsa_lag_map(struct dsa_switch_tree *dst, struct net_device *lag); -+void dsa_lag_unmap(struct dsa_switch_tree *dst, struct net_device *lag); -+ - extern struct list_head dsa_tree_list; - - #endif ---- a/net/dsa/port.c -+++ b/net/dsa/port.c -@@ -193,6 +193,99 @@ void dsa_port_bridge_leave(struct dsa_po - dsa_port_set_state_now(dp, BR_STATE_FORWARDING); - } - -+int dsa_port_lag_change(struct dsa_port *dp, -+ struct netdev_lag_lower_state_info *linfo) -+{ -+ struct dsa_notifier_lag_info info = { -+ .sw_index = dp->ds->index, -+ .port = dp->index, -+ }; -+ bool tx_enabled; -+ -+ if (!dp->lag_dev) -+ return 0; -+ -+ /* On statically configured aggregates (e.g. loadbalance -+ * without LACP) ports will always be tx_enabled, even if the -+ * link is down. Thus we require both link_up and tx_enabled -+ * in order to include it in the tx set. -+ */ -+ tx_enabled = linfo->link_up && linfo->tx_enabled; -+ -+ if (tx_enabled == dp->lag_tx_enabled) -+ return 0; -+ -+ dp->lag_tx_enabled = tx_enabled; -+ -+ return dsa_port_notify(dp, DSA_NOTIFIER_LAG_CHANGE, &info); -+} -+ -+int dsa_port_lag_join(struct dsa_port *dp, struct net_device *lag, -+ struct netdev_lag_upper_info *uinfo) -+{ -+ struct dsa_notifier_lag_info info = { -+ .sw_index = dp->ds->index, -+ .port = dp->index, -+ .lag = lag, -+ .info = uinfo, -+ }; -+ struct net_device *bridge_dev; -+ int err; -+ -+ dsa_lag_map(dp->ds->dst, lag); -+ dp->lag_dev = lag; -+ -+ err = dsa_port_notify(dp, DSA_NOTIFIER_LAG_JOIN, &info); -+ if (err) -+ goto err_lag_join; -+ -+ bridge_dev = netdev_master_upper_dev_get(lag); -+ if (!bridge_dev || !netif_is_bridge_master(bridge_dev)) -+ return 0; -+ -+ err = dsa_port_bridge_join(dp, bridge_dev); -+ if (err) -+ goto err_bridge_join; -+ -+ return 0; -+ -+err_bridge_join: -+ dsa_port_notify(dp, DSA_NOTIFIER_LAG_LEAVE, &info); -+err_lag_join: -+ dp->lag_dev = NULL; -+ dsa_lag_unmap(dp->ds->dst, lag); -+ return err; -+} -+ -+void dsa_port_lag_leave(struct dsa_port *dp, struct net_device *lag) -+{ -+ struct dsa_notifier_lag_info info = { -+ .sw_index = dp->ds->index, -+ .port = dp->index, -+ .lag = lag, -+ }; -+ int err; -+ -+ if (!dp->lag_dev) -+ return; -+ -+ /* Port might have been part of a LAG that in turn was -+ * attached to a bridge. -+ */ -+ if (dp->bridge_dev) -+ dsa_port_bridge_leave(dp, dp->bridge_dev); -+ -+ dp->lag_tx_enabled = false; -+ dp->lag_dev = NULL; -+ -+ err = dsa_port_notify(dp, DSA_NOTIFIER_LAG_LEAVE, &info); -+ if (err) -+ pr_err("DSA: failed to notify DSA_NOTIFIER_LAG_LEAVE: %d\n", -+ err); -+ -+ dsa_lag_unmap(dp->ds->dst, lag); -+} -+ - /* Must be called under rcu_read_lock() */ - static bool dsa_port_can_apply_vlan_filtering(struct dsa_port *dp, - bool vlan_filtering) ---- a/net/dsa/slave.c -+++ b/net/dsa/slave.c -@@ -337,9 +337,6 @@ static int dsa_slave_vlan_add(struct net - struct switchdev_obj_port_vlan vlan; - int vid, err; - -- if (obj->orig_dev != dev) -- return -EOPNOTSUPP; -- - if (dsa_port_skip_vlan_configuration(dp)) - return 0; - -@@ -394,11 +391,13 @@ static int dsa_slave_port_obj_add(struct - - switch (obj->id) { - case SWITCHDEV_OBJ_ID_PORT_MDB: -- if (obj->orig_dev != dev) -+ if (!dsa_port_offloads_bridge_port(dp, obj->orig_dev)) - return -EOPNOTSUPP; - err = dsa_port_mdb_add(dp, SWITCHDEV_OBJ_PORT_MDB(obj), trans); - break; - case SWITCHDEV_OBJ_ID_HOST_MDB: -+ if (!dsa_port_offloads_bridge(dp, obj->orig_dev)) -+ return -EOPNOTSUPP; - /* DSA can directly translate this to a normal MDB add, - * but on the CPU port. - */ -@@ -406,6 +405,9 @@ static int dsa_slave_port_obj_add(struct - trans); - break; - case SWITCHDEV_OBJ_ID_PORT_VLAN: -+ if (!dsa_port_offloads_bridge_port(dp, obj->orig_dev)) -+ return -EOPNOTSUPP; -+ - err = dsa_slave_vlan_add(dev, obj, trans); - break; - default: -@@ -424,9 +426,6 @@ static int dsa_slave_vlan_del(struct net - struct switchdev_obj_port_vlan *vlan; - int vid, err; - -- if (obj->orig_dev != dev) -- return -EOPNOTSUPP; -- - if (dsa_port_skip_vlan_configuration(dp)) - return 0; - -@@ -453,17 +452,22 @@ static int dsa_slave_port_obj_del(struct - - switch (obj->id) { - case SWITCHDEV_OBJ_ID_PORT_MDB: -- if (obj->orig_dev != dev) -+ if (!dsa_port_offloads_bridge_port(dp, obj->orig_dev)) - return -EOPNOTSUPP; - err = dsa_port_mdb_del(dp, SWITCHDEV_OBJ_PORT_MDB(obj)); - break; - case SWITCHDEV_OBJ_ID_HOST_MDB: -+ if (!dsa_port_offloads_bridge(dp, obj->orig_dev)) -+ return -EOPNOTSUPP; - /* DSA can directly translate this to a normal MDB add, - * but on the CPU port. - */ - err = dsa_port_mdb_del(dp->cpu_dp, SWITCHDEV_OBJ_PORT_MDB(obj)); - break; - case SWITCHDEV_OBJ_ID_PORT_VLAN: -+ if (!dsa_port_offloads_bridge_port(dp, obj->orig_dev)) -+ return -EOPNOTSUPP; -+ - err = dsa_slave_vlan_del(dev, obj); - break; - default: -@@ -1993,6 +1997,46 @@ static int dsa_slave_changeupper(struct - dsa_port_bridge_leave(dp, info->upper_dev); - err = NOTIFY_OK; - } -+ } else if (netif_is_lag_master(info->upper_dev)) { -+ if (info->linking) { -+ err = dsa_port_lag_join(dp, info->upper_dev, -+ info->upper_info); -+ if (err == -EOPNOTSUPP) { -+ NL_SET_ERR_MSG_MOD(info->info.extack, -+ "Offloading not supported"); -+ err = 0; -+ } -+ err = notifier_from_errno(err); -+ } else { -+ dsa_port_lag_leave(dp, info->upper_dev); -+ err = NOTIFY_OK; -+ } -+ } -+ -+ return err; -+} -+ -+static int -+dsa_slave_lag_changeupper(struct net_device *dev, -+ struct netdev_notifier_changeupper_info *info) -+{ -+ struct net_device *lower; -+ struct list_head *iter; -+ int err = NOTIFY_DONE; -+ struct dsa_port *dp; -+ -+ netdev_for_each_lower_dev(dev, lower, iter) { -+ if (!dsa_slave_dev_check(lower)) -+ continue; -+ -+ dp = dsa_slave_to_port(lower); -+ if (!dp->lag_dev) -+ /* Software LAG */ -+ continue; -+ -+ err = dsa_slave_changeupper(lower, info); -+ if (notifier_to_errno(err)) -+ break; - } - - return err; -@@ -2078,10 +2122,26 @@ static int dsa_slave_netdevice_event(str - break; - } - case NETDEV_CHANGEUPPER: -+ if (dsa_slave_dev_check(dev)) -+ return dsa_slave_changeupper(dev, ptr); -+ -+ if (netif_is_lag_master(dev)) -+ return dsa_slave_lag_changeupper(dev, ptr); -+ -+ break; -+ case NETDEV_CHANGELOWERSTATE: { -+ struct netdev_notifier_changelowerstate_info *info = ptr; -+ struct dsa_port *dp; -+ int err; -+ - if (!dsa_slave_dev_check(dev)) -- return NOTIFY_DONE; -+ break; - -- return dsa_slave_changeupper(dev, ptr); -+ dp = dsa_slave_to_port(dev); -+ -+ err = dsa_port_lag_change(dp, info->lower_state_info); -+ return notifier_from_errno(err); -+ } - } - - return NOTIFY_DONE; -@@ -2229,6 +2289,15 @@ static int dsa_slave_switchdev_event(str - if (!fdb_info->added_by_user && - !dp->ds->assisted_learning_on_cpu_port) - return NOTIFY_DONE; -+ -+ /* When the bridge learns an address on an offloaded -+ * LAG we don't want to send traffic to the CPU, the -+ * other ports bridged with the LAG should be able to -+ * autonomously forward towards it. -+ */ -+ if (dsa_tree_offloads_netdev(dp->ds->dst, dev)) -+ return NOTIFY_DONE; -+ - } - - if (!dp->ds->ops->port_fdb_add || !dp->ds->ops->port_fdb_del) ---- a/net/dsa/switch.c -+++ b/net/dsa/switch.c -@@ -193,6 +193,47 @@ static int dsa_switch_fdb_del(struct dsa - return ds->ops->port_fdb_del(ds, port, info->addr, info->vid); - } - -+static int dsa_switch_lag_change(struct dsa_switch *ds, -+ struct dsa_notifier_lag_info *info) -+{ -+ if (ds->index == info->sw_index && ds->ops->port_lag_change) -+ return ds->ops->port_lag_change(ds, info->port); -+ -+ if (ds->index != info->sw_index && ds->ops->crosschip_lag_change) -+ return ds->ops->crosschip_lag_change(ds, info->sw_index, -+ info->port); -+ -+ return 0; -+} -+ -+static int dsa_switch_lag_join(struct dsa_switch *ds, -+ struct dsa_notifier_lag_info *info) -+{ -+ if (ds->index == info->sw_index && ds->ops->port_lag_join) -+ return ds->ops->port_lag_join(ds, info->port, info->lag, -+ info->info); -+ -+ if (ds->index != info->sw_index && ds->ops->crosschip_lag_join) -+ return ds->ops->crosschip_lag_join(ds, info->sw_index, -+ info->port, info->lag, -+ info->info); -+ -+ return -EOPNOTSUPP; -+} -+ -+static int dsa_switch_lag_leave(struct dsa_switch *ds, -+ struct dsa_notifier_lag_info *info) -+{ -+ if (ds->index == info->sw_index && ds->ops->port_lag_leave) -+ return ds->ops->port_lag_leave(ds, info->port, info->lag); -+ -+ if (ds->index != info->sw_index && ds->ops->crosschip_lag_leave) -+ return ds->ops->crosschip_lag_leave(ds, info->sw_index, -+ info->port, info->lag); -+ -+ return -EOPNOTSUPP; -+} -+ - static bool dsa_switch_mdb_match(struct dsa_switch *ds, int port, - struct dsa_notifier_mdb_info *info) - { -@@ -340,6 +381,15 @@ static int dsa_switch_event(struct notif - case DSA_NOTIFIER_FDB_DEL: - err = dsa_switch_fdb_del(ds, info); - break; -+ case DSA_NOTIFIER_LAG_CHANGE: -+ err = dsa_switch_lag_change(ds, info); -+ break; -+ case DSA_NOTIFIER_LAG_JOIN: -+ err = dsa_switch_lag_join(ds, info); -+ break; -+ case DSA_NOTIFIER_LAG_LEAVE: -+ err = dsa_switch_lag_leave(ds, info); -+ break; - case DSA_NOTIFIER_MDB_ADD: - err = dsa_switch_mdb_add(ds, info); - break; ---- a/net/dsa/tag_dsa.c -+++ b/net/dsa/tag_dsa.c -@@ -82,7 +82,19 @@ static struct sk_buff *dsa_rcv(struct sk - source_device = dsa_header[0] & 0x1f; - source_port = (dsa_header[1] >> 3) & 0x1f; - -- skb->dev = dsa_master_find_slave(dev, source_device, source_port); -+ if (trunk) { -+ struct dsa_port *cpu_dp = dev->dsa_ptr; -+ -+ /* The exact source port is not available in the tag, -+ * so we inject the frame directly on the upper -+ * team/bond. -+ */ -+ skb->dev = dsa_lag_dev(cpu_dp->dst, source_port); -+ } else { -+ skb->dev = dsa_master_find_slave(dev, source_device, -+ source_port); -+ } -+ - if (!skb->dev) - return NULL; - diff --git a/target/linux/realtek/patches-5.15/713-v5.12-net-dsa-configure-better-brport-flags-when-ports-lea.patch b/target/linux/realtek/patches-5.15/713-v5.12-net-dsa-configure-better-brport-flags-when-ports-lea.patch deleted file mode 100644 index a3bfec59ab..0000000000 --- a/target/linux/realtek/patches-5.15/713-v5.12-net-dsa-configure-better-brport-flags-when-ports-lea.patch +++ /dev/null @@ -1,148 +0,0 @@ -From: Vladimir Oltean <vladimir.oltean@nxp.com> -Date: Fri, 12 Feb 2021 17:15:54 +0200 -Subject: [PATCH] net: dsa: configure better brport flags when ports leave the - bridge - -Bugfixed version of upstream commit 5e38c15856e9 ("net: dsa: configure -better brport flags when ports leave the bridge") - -For a DSA switch port operating in standalone mode, address learning -doesn't make much sense since that is a bridge function. In fact, -address learning even breaks setups such as this one: - - +---------------------------------------------+ - | | - | +-------------------+ | - | | br0 | send receive | - | +--------+-+--------+ +--------+ +--------+ | - | | | | | | | | | | - | | swp0 | | swp1 | | swp2 | | swp3 | | - | | | | | | | | | | - +-+--------+-+--------+-+--------+-+--------+-+ - | ^ | ^ - | | | | - | +-----------+ | - | | - +--------------------------------+ - -because if the switch has a single FDB (can offload a single bridge) -then source address learning on swp3 can "steal" the source MAC address -of swp2 from br0's FDB, because learning frames coming from swp2 will be -done twice: first on the swp1 ingress port, second on the swp3 ingress -port. So the hardware FDB will become out of sync with the software -bridge, and when swp2 tries to send one more packet towards swp1, the -ASIC will attempt to short-circuit the forwarding path and send it -directly to swp3 (since that's the last port it learned that address on), -which it obviously can't, because swp3 operates in standalone mode. - -So DSA drivers operating in standalone mode should still configure a -list of bridge port flags even when they are standalone. Currently DSA -attempts to call dsa_port_bridge_flags with 0, which disables egress -flooding of unknown unicast and multicast, something which doesn't make -much sense. For the switches that implement .port_egress_floods - b53 -and mv88e6xxx, it probably doesn't matter too much either, since they -can possibly inject traffic from the CPU into a standalone port, -regardless of MAC DA, even if egress flooding is turned off for that -port, but certainly not all DSA switches can do that - sja1105, for -example, can't. So it makes sense to use a better common default there, -such as "flood everything". - -It should also be noted that what DSA calls "dsa_port_bridge_flags()" -is a degenerate name for just calling .port_egress_floods(), since -nothing else is implemented - not learning, in particular. But disabling -address learning, something that this driver is also coding up for, will -be supported by individual drivers once .port_egress_floods is replaced -with a more generic .port_bridge_flags. - -Previous attempts to code up this logic have been in the common bridge -layer, but as pointed out by Ido Schimmel, there are corner cases that -are missed when doing that: -https://patchwork.kernel.org/project/netdevbpf/patch/20210209151936.97382-5-olteanv@gmail.com/ - -So, at least for now, let's leave DSA in charge of setting port flags -before and after the bridge join and leave. - -Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com> -Reviewed-by: Florian Fainelli <f.fainelli@gmail.com> -Signed-off-by: David S. Miller <davem@davemloft.net> -[ backport and bugfix: break dsa_port_bridge_flags() out of loop ] -Signed-off-by: Bjørn Mork <bjorn@mork.no> ---- - net/dsa/port.c | 45 ++++++++++++++++++++++++++++++++++++++------- - 1 file changed, 38 insertions(+), 7 deletions(-) - ---- a/net/dsa/port.c -+++ b/net/dsa/port.c -@@ -134,6 +134,27 @@ void dsa_port_disable(struct dsa_port *d - rtnl_unlock(); - } - -+static void dsa_port_change_brport_flags(struct dsa_port *dp, -+ bool bridge_offload) -+{ -+ unsigned long mask, flags; -+ int flag, err; -+ -+ mask = BR_LEARNING | BR_FLOOD | BR_MCAST_FLOOD | BR_BCAST_FLOOD; -+ if (bridge_offload) -+ flags = mask; -+ else -+ flags = mask & ~BR_LEARNING; -+ -+ for_each_set_bit(flag, &mask, 32) { -+ err = dsa_port_pre_bridge_flags(dp, BIT(flag), NULL, NULL); -+ if (err) -+ flags &= ~BIT(flag); -+ } -+ -+ dsa_port_bridge_flags(dp, flags, NULL, NULL); -+} -+ - int dsa_port_bridge_join(struct dsa_port *dp, struct net_device *br) - { - struct dsa_notifier_bridge_info info = { -@@ -144,10 +165,10 @@ int dsa_port_bridge_join(struct dsa_port - }; - int err; - -- /* Set the flooding mode before joining the port in the switch */ -- err = dsa_port_bridge_flags(dp, BR_FLOOD | BR_MCAST_FLOOD, NULL, NULL); -- if (err) -- return err; -+ /* Notify the port driver to set its configurable flags in a way that -+ * matches the initial settings of a bridge port. -+ */ -+ dsa_port_change_brport_flags(dp, true); - - /* Here the interface is already bridged. Reflect the current - * configuration so that drivers can program their chips accordingly. -@@ -158,7 +179,7 @@ int dsa_port_bridge_join(struct dsa_port - - /* The bridging is rolled back on error */ - if (err) { -- dsa_port_bridge_flags(dp, 0, NULL, NULL); -+ dsa_port_change_brport_flags(dp, false); - dp->bridge_dev = NULL; - } - -@@ -184,8 +205,18 @@ void dsa_port_bridge_leave(struct dsa_po - if (err) - pr_err("DSA: failed to notify DSA_NOTIFIER_BRIDGE_LEAVE\n"); - -- /* Port is leaving the bridge, disable flooding */ -- dsa_port_bridge_flags(dp, 0, NULL, NULL); -+ /* Configure the port for standalone mode (no address learning, -+ * flood everything). -+ * The bridge only emits SWITCHDEV_ATTR_ID_PORT_BRIDGE_FLAGS events -+ * when the user requests it through netlink or sysfs, but not -+ * automatically at port join or leave, so we need to handle resetting -+ * the brport flags ourselves. But we even prefer it that way, because -+ * otherwise, some setups might never get the notification they need, -+ * for example, when a port leaves a LAG that offloads the bridge, -+ * it becomes standalone, but as far as the bridge is concerned, no -+ * port ever left. -+ */ -+ dsa_port_change_brport_flags(dp, false); - - /* Port left the bridge, put in BR_STATE_DISABLED by the bridge layer, - * so allow it to be in BR_STATE_FORWARDING to be kept functional |