12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later 2a40c175bSVivien Didelot /* 3a40c175bSVivien Didelot * Handling of a single switch port 4a40c175bSVivien Didelot * 5a40c175bSVivien Didelot * Copyright (c) 2017 Savoir-faire Linux Inc. 6a40c175bSVivien Didelot * Vivien Didelot <vivien.didelot@savoirfairelinux.com> 7a40c175bSVivien Didelot */ 8a40c175bSVivien Didelot 9a40c175bSVivien Didelot #include <linux/if_bridge.h> 1095f510d0SVladimir Oltean #include <linux/netdevice.h> 11cfbed329SVivien Didelot #include <linux/notifier.h> 1257ab1ca2SVivien Didelot #include <linux/of_mdio.h> 1357ab1ca2SVivien Didelot #include <linux/of_net.h> 14a40c175bSVivien Didelot 15a40c175bSVivien Didelot #include "dsa_priv.h" 16a40c175bSVivien Didelot 17886f8e26SVladimir Oltean /** 18886f8e26SVladimir Oltean * dsa_port_notify - Notify the switching fabric of changes to a port 19886f8e26SVladimir Oltean * @dp: port on which change occurred 20886f8e26SVladimir Oltean * @e: event, must be of type DSA_NOTIFIER_* 21886f8e26SVladimir Oltean * @v: event-specific value. 22886f8e26SVladimir Oltean * 23886f8e26SVladimir Oltean * Notify all switches in the DSA tree that this port's switch belongs to, 24886f8e26SVladimir Oltean * including this switch itself, of an event. Allows the other switches to 25886f8e26SVladimir Oltean * reconfigure themselves for cross-chip operations. Can also be used to 26886f8e26SVladimir Oltean * reconfigure ports without net_devices (CPU ports, DSA links) whenever 27886f8e26SVladimir Oltean * a user port's state changes. 28886f8e26SVladimir Oltean */ 29bb9f6031SAndrew Lunn static int dsa_port_notify(const struct dsa_port *dp, unsigned long e, void *v) 30cfbed329SVivien Didelot { 31886f8e26SVladimir Oltean return dsa_tree_notify(dp->ds->dst, e, v); 32cfbed329SVivien Didelot } 33cfbed329SVivien Didelot 347414af30STobias Waldekranz static void dsa_port_notify_bridge_fdb_flush(const struct dsa_port *dp, u16 vid) 359264e4adSVladimir Oltean { 369264e4adSVladimir Oltean struct net_device *brport_dev = dsa_port_to_bridge_port(dp); 379264e4adSVladimir Oltean struct switchdev_notifier_fdb_info info = { 387414af30STobias Waldekranz .vid = vid, 399264e4adSVladimir Oltean }; 409264e4adSVladimir Oltean 419264e4adSVladimir Oltean /* When the port becomes standalone it has already left the bridge. 429264e4adSVladimir Oltean * Don't notify the bridge in that case. 439264e4adSVladimir Oltean */ 449264e4adSVladimir Oltean if (!brport_dev) 459264e4adSVladimir Oltean return; 469264e4adSVladimir Oltean 479264e4adSVladimir Oltean call_switchdev_notifiers(SWITCHDEV_FDB_FLUSH_TO_BRIDGE, 489264e4adSVladimir Oltean brport_dev, &info.info, NULL); 499264e4adSVladimir Oltean } 509264e4adSVladimir Oltean 51045c45d1SVladimir Oltean static void dsa_port_fast_age(const struct dsa_port *dp) 52045c45d1SVladimir Oltean { 53045c45d1SVladimir Oltean struct dsa_switch *ds = dp->ds; 54045c45d1SVladimir Oltean 55045c45d1SVladimir Oltean if (!ds->ops->port_fast_age) 56045c45d1SVladimir Oltean return; 57045c45d1SVladimir Oltean 58045c45d1SVladimir Oltean ds->ops->port_fast_age(ds, dp->index); 599264e4adSVladimir Oltean 607414af30STobias Waldekranz /* flush all VLANs */ 617414af30STobias Waldekranz dsa_port_notify_bridge_fdb_flush(dp, 0); 627414af30STobias Waldekranz } 637414af30STobias Waldekranz 647414af30STobias Waldekranz static int dsa_port_vlan_fast_age(const struct dsa_port *dp, u16 vid) 657414af30STobias Waldekranz { 667414af30STobias Waldekranz struct dsa_switch *ds = dp->ds; 677414af30STobias Waldekranz int err; 687414af30STobias Waldekranz 697414af30STobias Waldekranz if (!ds->ops->port_vlan_fast_age) 707414af30STobias Waldekranz return -EOPNOTSUPP; 717414af30STobias Waldekranz 727414af30STobias Waldekranz err = ds->ops->port_vlan_fast_age(ds, dp->index, vid); 737414af30STobias Waldekranz 747414af30STobias Waldekranz if (!err) 757414af30STobias Waldekranz dsa_port_notify_bridge_fdb_flush(dp, vid); 767414af30STobias Waldekranz 777414af30STobias Waldekranz return err; 787414af30STobias Waldekranz } 797414af30STobias Waldekranz 807414af30STobias Waldekranz static int dsa_port_msti_fast_age(const struct dsa_port *dp, u16 msti) 817414af30STobias Waldekranz { 827414af30STobias Waldekranz DECLARE_BITMAP(vids, VLAN_N_VID) = { 0 }; 837414af30STobias Waldekranz int err, vid; 847414af30STobias Waldekranz 857414af30STobias Waldekranz err = br_mst_get_info(dsa_port_bridge_dev_get(dp), msti, vids); 867414af30STobias Waldekranz if (err) 877414af30STobias Waldekranz return err; 887414af30STobias Waldekranz 897414af30STobias Waldekranz for_each_set_bit(vid, vids, VLAN_N_VID) { 907414af30STobias Waldekranz err = dsa_port_vlan_fast_age(dp, vid); 917414af30STobias Waldekranz if (err) 927414af30STobias Waldekranz return err; 937414af30STobias Waldekranz } 947414af30STobias Waldekranz 957414af30STobias Waldekranz return 0; 96045c45d1SVladimir Oltean } 97045c45d1SVladimir Oltean 98a4ffe09fSVladimir Oltean static bool dsa_port_can_configure_learning(struct dsa_port *dp) 99a4ffe09fSVladimir Oltean { 100a4ffe09fSVladimir Oltean struct switchdev_brport_flags flags = { 101a4ffe09fSVladimir Oltean .mask = BR_LEARNING, 102a4ffe09fSVladimir Oltean }; 103a4ffe09fSVladimir Oltean struct dsa_switch *ds = dp->ds; 104a4ffe09fSVladimir Oltean int err; 105a4ffe09fSVladimir Oltean 106a4ffe09fSVladimir Oltean if (!ds->ops->port_bridge_flags || !ds->ops->port_pre_bridge_flags) 107a4ffe09fSVladimir Oltean return false; 108a4ffe09fSVladimir Oltean 109a4ffe09fSVladimir Oltean err = ds->ops->port_pre_bridge_flags(ds, dp->index, flags, NULL); 110a4ffe09fSVladimir Oltean return !err; 111a4ffe09fSVladimir Oltean } 112a4ffe09fSVladimir Oltean 11339f32101SVladimir Oltean int dsa_port_set_state(struct dsa_port *dp, u8 state, bool do_fast_age) 114a40c175bSVivien Didelot { 115a40c175bSVivien Didelot struct dsa_switch *ds = dp->ds; 116a40c175bSVivien Didelot int port = dp->index; 117a40c175bSVivien Didelot 118bae33f2bSVladimir Oltean if (!ds->ops->port_stp_state_set) 119bae33f2bSVladimir Oltean return -EOPNOTSUPP; 120a40c175bSVivien Didelot 121a40c175bSVivien Didelot ds->ops->port_stp_state_set(ds, port, state); 122a40c175bSVivien Didelot 123a4ffe09fSVladimir Oltean if (!dsa_port_can_configure_learning(dp) || 124a4ffe09fSVladimir Oltean (do_fast_age && dp->learning)) { 125a40c175bSVivien Didelot /* Fast age FDB entries or flush appropriate forwarding database 126a40c175bSVivien Didelot * for the given port, if we are moving it from Learning or 127a40c175bSVivien Didelot * Forwarding state, to Disabled or Blocking or Listening state. 12839f32101SVladimir Oltean * Ports that were standalone before the STP state change don't 12939f32101SVladimir Oltean * need to fast age the FDB, since address learning is off in 13039f32101SVladimir Oltean * standalone mode. 131a40c175bSVivien Didelot */ 132a40c175bSVivien Didelot 133a40c175bSVivien Didelot if ((dp->stp_state == BR_STATE_LEARNING || 134a40c175bSVivien Didelot dp->stp_state == BR_STATE_FORWARDING) && 135a40c175bSVivien Didelot (state == BR_STATE_DISABLED || 136a40c175bSVivien Didelot state == BR_STATE_BLOCKING || 137a40c175bSVivien Didelot state == BR_STATE_LISTENING)) 138045c45d1SVladimir Oltean dsa_port_fast_age(dp); 139a40c175bSVivien Didelot } 140a40c175bSVivien Didelot 141a40c175bSVivien Didelot dp->stp_state = state; 142a40c175bSVivien Didelot 143a40c175bSVivien Didelot return 0; 144a40c175bSVivien Didelot } 145a40c175bSVivien Didelot 14639f32101SVladimir Oltean static void dsa_port_set_state_now(struct dsa_port *dp, u8 state, 14739f32101SVladimir Oltean bool do_fast_age) 148a40c175bSVivien Didelot { 149211987f3SVladimir Oltean struct dsa_switch *ds = dp->ds; 150a40c175bSVivien Didelot int err; 151a40c175bSVivien Didelot 15239f32101SVladimir Oltean err = dsa_port_set_state(dp, state, do_fast_age); 153211987f3SVladimir Oltean if (err && err != -EOPNOTSUPP) { 154211987f3SVladimir Oltean dev_err(ds->dev, "port %d failed to set STP state %u: %pe\n", 155211987f3SVladimir Oltean dp->index, state, ERR_PTR(err)); 156211987f3SVladimir Oltean } 157a40c175bSVivien Didelot } 158cfbed329SVivien Didelot 1597414af30STobias Waldekranz int dsa_port_set_mst_state(struct dsa_port *dp, 1607414af30STobias Waldekranz const struct switchdev_mst_state *state, 1617414af30STobias Waldekranz struct netlink_ext_ack *extack) 1627414af30STobias Waldekranz { 1637414af30STobias Waldekranz struct dsa_switch *ds = dp->ds; 1647414af30STobias Waldekranz u8 prev_state; 1657414af30STobias Waldekranz int err; 1667414af30STobias Waldekranz 1677414af30STobias Waldekranz if (!ds->ops->port_mst_state_set) 1687414af30STobias Waldekranz return -EOPNOTSUPP; 1697414af30STobias Waldekranz 1707414af30STobias Waldekranz err = br_mst_get_state(dsa_port_to_bridge_port(dp), state->msti, 1717414af30STobias Waldekranz &prev_state); 1727414af30STobias Waldekranz if (err) 1737414af30STobias Waldekranz return err; 1747414af30STobias Waldekranz 1757414af30STobias Waldekranz err = ds->ops->port_mst_state_set(ds, dp->index, state); 1767414af30STobias Waldekranz if (err) 1777414af30STobias Waldekranz return err; 1787414af30STobias Waldekranz 1797414af30STobias Waldekranz if (!(dp->learning && 1807414af30STobias Waldekranz (prev_state == BR_STATE_LEARNING || 1817414af30STobias Waldekranz prev_state == BR_STATE_FORWARDING) && 1827414af30STobias Waldekranz (state->state == BR_STATE_DISABLED || 1837414af30STobias Waldekranz state->state == BR_STATE_BLOCKING || 1847414af30STobias Waldekranz state->state == BR_STATE_LISTENING))) 1857414af30STobias Waldekranz return 0; 1867414af30STobias Waldekranz 1877414af30STobias Waldekranz err = dsa_port_msti_fast_age(dp, state->msti); 1887414af30STobias Waldekranz if (err) 1897414af30STobias Waldekranz NL_SET_ERR_MSG_MOD(extack, 1907414af30STobias Waldekranz "Unable to flush associated VLANs"); 1917414af30STobias Waldekranz 1927414af30STobias Waldekranz return 0; 1937414af30STobias Waldekranz } 1947414af30STobias Waldekranz 1958640f8dcSRussell King int dsa_port_enable_rt(struct dsa_port *dp, struct phy_device *phy) 196fb8a6a2bSVivien Didelot { 197fb8a6a2bSVivien Didelot struct dsa_switch *ds = dp->ds; 198fb8a6a2bSVivien Didelot int port = dp->index; 199fb8a6a2bSVivien Didelot int err; 200fb8a6a2bSVivien Didelot 201fb8a6a2bSVivien Didelot if (ds->ops->port_enable) { 202fb8a6a2bSVivien Didelot err = ds->ops->port_enable(ds, port, phy); 203fb8a6a2bSVivien Didelot if (err) 204fb8a6a2bSVivien Didelot return err; 205fb8a6a2bSVivien Didelot } 206fb8a6a2bSVivien Didelot 207d3eed0e5SVladimir Oltean if (!dp->bridge) 20839f32101SVladimir Oltean dsa_port_set_state_now(dp, BR_STATE_FORWARDING, false); 209fb8a6a2bSVivien Didelot 2108640f8dcSRussell King if (dp->pl) 2118640f8dcSRussell King phylink_start(dp->pl); 2128640f8dcSRussell King 213fb8a6a2bSVivien Didelot return 0; 214fb8a6a2bSVivien Didelot } 215fb8a6a2bSVivien Didelot 2168640f8dcSRussell King int dsa_port_enable(struct dsa_port *dp, struct phy_device *phy) 2178640f8dcSRussell King { 2188640f8dcSRussell King int err; 2198640f8dcSRussell King 2208640f8dcSRussell King rtnl_lock(); 2218640f8dcSRussell King err = dsa_port_enable_rt(dp, phy); 2228640f8dcSRussell King rtnl_unlock(); 2238640f8dcSRussell King 2248640f8dcSRussell King return err; 2258640f8dcSRussell King } 2268640f8dcSRussell King 2278640f8dcSRussell King void dsa_port_disable_rt(struct dsa_port *dp) 228fb8a6a2bSVivien Didelot { 229fb8a6a2bSVivien Didelot struct dsa_switch *ds = dp->ds; 230fb8a6a2bSVivien Didelot int port = dp->index; 231fb8a6a2bSVivien Didelot 2328640f8dcSRussell King if (dp->pl) 2338640f8dcSRussell King phylink_stop(dp->pl); 2348640f8dcSRussell King 235d3eed0e5SVladimir Oltean if (!dp->bridge) 23639f32101SVladimir Oltean dsa_port_set_state_now(dp, BR_STATE_DISABLED, false); 237fb8a6a2bSVivien Didelot 238fb8a6a2bSVivien Didelot if (ds->ops->port_disable) 23975104db0SAndrew Lunn ds->ops->port_disable(ds, port); 240fb8a6a2bSVivien Didelot } 241fb8a6a2bSVivien Didelot 2428640f8dcSRussell King void dsa_port_disable(struct dsa_port *dp) 2438640f8dcSRussell King { 2448640f8dcSRussell King rtnl_lock(); 2458640f8dcSRussell King dsa_port_disable_rt(dp); 2468640f8dcSRussell King rtnl_unlock(); 2478640f8dcSRussell King } 2488640f8dcSRussell King 2498e9e678eSVladimir Oltean static void dsa_port_reset_vlan_filtering(struct dsa_port *dp, 2508e9e678eSVladimir Oltean struct dsa_bridge bridge) 2518e9e678eSVladimir Oltean { 2528e9e678eSVladimir Oltean struct netlink_ext_ack extack = {0}; 2538e9e678eSVladimir Oltean bool change_vlan_filtering = false; 2548e9e678eSVladimir Oltean struct dsa_switch *ds = dp->ds; 2551699b4d5SVladimir Oltean struct dsa_port *other_dp; 2568e9e678eSVladimir Oltean bool vlan_filtering; 2578e9e678eSVladimir Oltean int err; 2588e9e678eSVladimir Oltean 2598e9e678eSVladimir Oltean if (ds->needs_standalone_vlan_filtering && 2608e9e678eSVladimir Oltean !br_vlan_enabled(bridge.dev)) { 2618e9e678eSVladimir Oltean change_vlan_filtering = true; 2628e9e678eSVladimir Oltean vlan_filtering = true; 2638e9e678eSVladimir Oltean } else if (!ds->needs_standalone_vlan_filtering && 2648e9e678eSVladimir Oltean br_vlan_enabled(bridge.dev)) { 2658e9e678eSVladimir Oltean change_vlan_filtering = true; 2668e9e678eSVladimir Oltean vlan_filtering = false; 2678e9e678eSVladimir Oltean } 2688e9e678eSVladimir Oltean 2698e9e678eSVladimir Oltean /* If the bridge was vlan_filtering, the bridge core doesn't trigger an 2708e9e678eSVladimir Oltean * event for changing vlan_filtering setting upon slave ports leaving 2718e9e678eSVladimir Oltean * it. That is a good thing, because that lets us handle it and also 2728e9e678eSVladimir Oltean * handle the case where the switch's vlan_filtering setting is global 2738e9e678eSVladimir Oltean * (not per port). When that happens, the correct moment to trigger the 2748e9e678eSVladimir Oltean * vlan_filtering callback is only when the last port leaves the last 2758e9e678eSVladimir Oltean * VLAN-aware bridge. 2768e9e678eSVladimir Oltean */ 2778e9e678eSVladimir Oltean if (change_vlan_filtering && ds->vlan_filtering_is_global) { 2781699b4d5SVladimir Oltean dsa_switch_for_each_port(other_dp, ds) { 2791699b4d5SVladimir Oltean struct net_device *br = dsa_port_bridge_dev_get(other_dp); 2808e9e678eSVladimir Oltean 2818e9e678eSVladimir Oltean if (br && br_vlan_enabled(br)) { 2828e9e678eSVladimir Oltean change_vlan_filtering = false; 2838e9e678eSVladimir Oltean break; 2848e9e678eSVladimir Oltean } 2858e9e678eSVladimir Oltean } 2868e9e678eSVladimir Oltean } 2878e9e678eSVladimir Oltean 2888e9e678eSVladimir Oltean if (!change_vlan_filtering) 2898e9e678eSVladimir Oltean return; 2908e9e678eSVladimir Oltean 2918e9e678eSVladimir Oltean err = dsa_port_vlan_filtering(dp, vlan_filtering, &extack); 2928e9e678eSVladimir Oltean if (extack._msg) { 2938e9e678eSVladimir Oltean dev_err(ds->dev, "port %d: %s\n", dp->index, 2948e9e678eSVladimir Oltean extack._msg); 2958e9e678eSVladimir Oltean } 2968e9e678eSVladimir Oltean if (err && err != -EOPNOTSUPP) { 2978e9e678eSVladimir Oltean dev_err(ds->dev, 2988e9e678eSVladimir Oltean "port %d failed to reset VLAN filtering to %d: %pe\n", 2998e9e678eSVladimir Oltean dp->index, vlan_filtering, ERR_PTR(err)); 3008e9e678eSVladimir Oltean } 3018e9e678eSVladimir Oltean } 3028e9e678eSVladimir Oltean 3035961d6a1SVladimir Oltean static int dsa_port_inherit_brport_flags(struct dsa_port *dp, 3045961d6a1SVladimir Oltean struct netlink_ext_ack *extack) 3055e38c158SVladimir Oltean { 3065961d6a1SVladimir Oltean const unsigned long mask = BR_LEARNING | BR_FLOOD | BR_MCAST_FLOOD | 307b9e8b58fSHans Schultz BR_BCAST_FLOOD | BR_PORT_LOCKED; 3085961d6a1SVladimir Oltean struct net_device *brport_dev = dsa_port_to_bridge_port(dp); 3095961d6a1SVladimir Oltean int flag, err; 3105e38c158SVladimir Oltean 3115961d6a1SVladimir Oltean for_each_set_bit(flag, &mask, 32) { 3125961d6a1SVladimir Oltean struct switchdev_brport_flags flags = {0}; 3135e38c158SVladimir Oltean 3145961d6a1SVladimir Oltean flags.mask = BIT(flag); 3155e38c158SVladimir Oltean 3165961d6a1SVladimir Oltean if (br_port_flag_is_set(brport_dev, BIT(flag))) 3175961d6a1SVladimir Oltean flags.val = BIT(flag); 318e18f4c18SVladimir Oltean 3195961d6a1SVladimir Oltean err = dsa_port_bridge_flags(dp, flags, extack); 3205961d6a1SVladimir Oltean if (err && err != -EOPNOTSUPP) 3215961d6a1SVladimir Oltean return err; 3225e38c158SVladimir Oltean } 3235961d6a1SVladimir Oltean 3245961d6a1SVladimir Oltean return 0; 3255961d6a1SVladimir Oltean } 3265961d6a1SVladimir Oltean 3275961d6a1SVladimir Oltean static void dsa_port_clear_brport_flags(struct dsa_port *dp) 3285961d6a1SVladimir Oltean { 3295961d6a1SVladimir Oltean const unsigned long val = BR_FLOOD | BR_MCAST_FLOOD | BR_BCAST_FLOOD; 3305961d6a1SVladimir Oltean const unsigned long mask = BR_LEARNING | BR_FLOOD | BR_MCAST_FLOOD | 331b9e8b58fSHans Schultz BR_BCAST_FLOOD | BR_PORT_LOCKED; 3325961d6a1SVladimir Oltean int flag, err; 3335961d6a1SVladimir Oltean 3345961d6a1SVladimir Oltean for_each_set_bit(flag, &mask, 32) { 3355961d6a1SVladimir Oltean struct switchdev_brport_flags flags = {0}; 3365961d6a1SVladimir Oltean 3375961d6a1SVladimir Oltean flags.mask = BIT(flag); 3385961d6a1SVladimir Oltean flags.val = val & BIT(flag); 3395961d6a1SVladimir Oltean 3405961d6a1SVladimir Oltean err = dsa_port_bridge_flags(dp, flags, NULL); 3415961d6a1SVladimir Oltean if (err && err != -EOPNOTSUPP) 3425961d6a1SVladimir Oltean dev_err(dp->ds->dev, 3435961d6a1SVladimir Oltean "failed to clear bridge port flag %lu: %pe\n", 3445961d6a1SVladimir Oltean flags.val, ERR_PTR(err)); 3455961d6a1SVladimir Oltean } 3465961d6a1SVladimir Oltean } 3475961d6a1SVladimir Oltean 3484e51bf44SVladimir Oltean static int dsa_port_switchdev_sync_attrs(struct dsa_port *dp, 3495961d6a1SVladimir Oltean struct netlink_ext_ack *extack) 3505961d6a1SVladimir Oltean { 351010e269fSVladimir Oltean struct net_device *brport_dev = dsa_port_to_bridge_port(dp); 35236cbf39bSVladimir Oltean struct net_device *br = dsa_port_bridge_dev_get(dp); 3535961d6a1SVladimir Oltean int err; 3545961d6a1SVladimir Oltean 3555961d6a1SVladimir Oltean err = dsa_port_inherit_brport_flags(dp, extack); 3565961d6a1SVladimir Oltean if (err) 3575961d6a1SVladimir Oltean return err; 3585961d6a1SVladimir Oltean 35939f32101SVladimir Oltean err = dsa_port_set_state(dp, br_port_get_stp_state(brport_dev), false); 360010e269fSVladimir Oltean if (err && err != -EOPNOTSUPP) 361010e269fSVladimir Oltean return err; 362010e269fSVladimir Oltean 363010e269fSVladimir Oltean err = dsa_port_vlan_filtering(dp, br_vlan_enabled(br), extack); 364010e269fSVladimir Oltean if (err && err != -EOPNOTSUPP) 365010e269fSVladimir Oltean return err; 366010e269fSVladimir Oltean 367010e269fSVladimir Oltean err = dsa_port_ageing_time(dp, br_get_ageing_time(br)); 368010e269fSVladimir Oltean if (err && err != -EOPNOTSUPP) 369010e269fSVladimir Oltean return err; 370010e269fSVladimir Oltean 37174918945SVladimir Oltean return 0; 37274918945SVladimir Oltean } 37374918945SVladimir Oltean 3748e9e678eSVladimir Oltean static void dsa_port_switchdev_unsync_attrs(struct dsa_port *dp, 3758e9e678eSVladimir Oltean struct dsa_bridge bridge) 3765961d6a1SVladimir Oltean { 3775961d6a1SVladimir Oltean /* Configure the port for standalone mode (no address learning, 3785961d6a1SVladimir Oltean * flood everything). 3795961d6a1SVladimir Oltean * The bridge only emits SWITCHDEV_ATTR_ID_PORT_BRIDGE_FLAGS events 3805961d6a1SVladimir Oltean * when the user requests it through netlink or sysfs, but not 3815961d6a1SVladimir Oltean * automatically at port join or leave, so we need to handle resetting 3825961d6a1SVladimir Oltean * the brport flags ourselves. But we even prefer it that way, because 3835961d6a1SVladimir Oltean * otherwise, some setups might never get the notification they need, 3845961d6a1SVladimir Oltean * for example, when a port leaves a LAG that offloads the bridge, 3855961d6a1SVladimir Oltean * it becomes standalone, but as far as the bridge is concerned, no 3865961d6a1SVladimir Oltean * port ever left. 3875961d6a1SVladimir Oltean */ 3885961d6a1SVladimir Oltean dsa_port_clear_brport_flags(dp); 3895961d6a1SVladimir Oltean 3905961d6a1SVladimir Oltean /* Port left the bridge, put in BR_STATE_DISABLED by the bridge layer, 3915961d6a1SVladimir Oltean * so allow it to be in BR_STATE_FORWARDING to be kept functional 3925961d6a1SVladimir Oltean */ 39339f32101SVladimir Oltean dsa_port_set_state_now(dp, BR_STATE_FORWARDING, true); 394010e269fSVladimir Oltean 3958e9e678eSVladimir Oltean dsa_port_reset_vlan_filtering(dp, bridge); 396010e269fSVladimir Oltean 397010e269fSVladimir Oltean /* Ageing time may be global to the switch chip, so don't change it 398010e269fSVladimir Oltean * here because we have no good reason (or value) to change it to. 399010e269fSVladimir Oltean */ 4005e38c158SVladimir Oltean } 4015e38c158SVladimir Oltean 402947c8746SVladimir Oltean static int dsa_port_bridge_create(struct dsa_port *dp, 403947c8746SVladimir Oltean struct net_device *br, 404947c8746SVladimir Oltean struct netlink_ext_ack *extack) 405947c8746SVladimir Oltean { 406947c8746SVladimir Oltean struct dsa_switch *ds = dp->ds; 407d3eed0e5SVladimir Oltean struct dsa_bridge *bridge; 408947c8746SVladimir Oltean 409d3eed0e5SVladimir Oltean bridge = dsa_tree_bridge_find(ds->dst, br); 410d3eed0e5SVladimir Oltean if (bridge) { 411d3eed0e5SVladimir Oltean refcount_inc(&bridge->refcount); 412d3eed0e5SVladimir Oltean dp->bridge = bridge; 413947c8746SVladimir Oltean return 0; 414d3eed0e5SVladimir Oltean } 415947c8746SVladimir Oltean 416d3eed0e5SVladimir Oltean bridge = kzalloc(sizeof(*bridge), GFP_KERNEL); 417d3eed0e5SVladimir Oltean if (!bridge) 418d3eed0e5SVladimir Oltean return -ENOMEM; 419d3eed0e5SVladimir Oltean 420d3eed0e5SVladimir Oltean refcount_set(&bridge->refcount, 1); 421d3eed0e5SVladimir Oltean 422d3eed0e5SVladimir Oltean bridge->dev = br; 423d3eed0e5SVladimir Oltean 424d3eed0e5SVladimir Oltean bridge->num = dsa_bridge_num_get(br, ds->max_num_bridges); 425d3eed0e5SVladimir Oltean if (ds->max_num_bridges && !bridge->num) { 426947c8746SVladimir Oltean NL_SET_ERR_MSG_MOD(extack, 427947c8746SVladimir Oltean "Range of offloadable bridges exceeded"); 428d3eed0e5SVladimir Oltean kfree(bridge); 429947c8746SVladimir Oltean return -EOPNOTSUPP; 430947c8746SVladimir Oltean } 431947c8746SVladimir Oltean 432d3eed0e5SVladimir Oltean dp->bridge = bridge; 433947c8746SVladimir Oltean 434947c8746SVladimir Oltean return 0; 435947c8746SVladimir Oltean } 436947c8746SVladimir Oltean 437947c8746SVladimir Oltean static void dsa_port_bridge_destroy(struct dsa_port *dp, 438947c8746SVladimir Oltean const struct net_device *br) 439947c8746SVladimir Oltean { 440d3eed0e5SVladimir Oltean struct dsa_bridge *bridge = dp->bridge; 441947c8746SVladimir Oltean 442d3eed0e5SVladimir Oltean dp->bridge = NULL; 443947c8746SVladimir Oltean 444d3eed0e5SVladimir Oltean if (!refcount_dec_and_test(&bridge->refcount)) 445d3eed0e5SVladimir Oltean return; 446947c8746SVladimir Oltean 447d3eed0e5SVladimir Oltean if (bridge->num) 448d3eed0e5SVladimir Oltean dsa_bridge_num_put(br, bridge->num); 449d3eed0e5SVladimir Oltean 450d3eed0e5SVladimir Oltean kfree(bridge); 451123abc06SVladimir Oltean } 452123abc06SVladimir Oltean 453332afc4cSTobias Waldekranz static bool dsa_port_supports_mst(struct dsa_port *dp) 454332afc4cSTobias Waldekranz { 4558e6598a7STobias Waldekranz struct dsa_switch *ds = dp->ds; 4568e6598a7STobias Waldekranz 4578e6598a7STobias Waldekranz return ds->ops->vlan_msti_set && 4587414af30STobias Waldekranz ds->ops->port_mst_state_set && 4597414af30STobias Waldekranz ds->ops->port_vlan_fast_age && 4608e6598a7STobias Waldekranz dsa_port_can_configure_learning(dp); 461332afc4cSTobias Waldekranz } 462332afc4cSTobias Waldekranz 4632afc526aSVladimir Oltean int dsa_port_bridge_join(struct dsa_port *dp, struct net_device *br, 4642afc526aSVladimir Oltean struct netlink_ext_ack *extack) 465cfbed329SVivien Didelot { 466cfbed329SVivien Didelot struct dsa_notifier_bridge_info info = { 467726816a1SVladimir Oltean .dp = dp, 46806b9cce4SVladimir Oltean .extack = extack, 469cfbed329SVivien Didelot }; 4702f5dc00fSVladimir Oltean struct net_device *dev = dp->slave; 4712f5dc00fSVladimir Oltean struct net_device *brport_dev; 472cfbed329SVivien Didelot int err; 473cfbed329SVivien Didelot 474332afc4cSTobias Waldekranz if (br_mst_enabled(br) && !dsa_port_supports_mst(dp)) 475332afc4cSTobias Waldekranz return -EOPNOTSUPP; 476332afc4cSTobias Waldekranz 477c1388063SRussell King /* Here the interface is already bridged. Reflect the current 478c1388063SRussell King * configuration so that drivers can program their chips accordingly. 479cfbed329SVivien Didelot */ 480947c8746SVladimir Oltean err = dsa_port_bridge_create(dp, br, extack); 481947c8746SVladimir Oltean if (err) 482947c8746SVladimir Oltean return err; 483cfbed329SVivien Didelot 4842f5dc00fSVladimir Oltean brport_dev = dsa_port_to_bridge_port(dp); 4852f5dc00fSVladimir Oltean 486d3eed0e5SVladimir Oltean info.bridge = *dp->bridge; 487f66a6a69SVladimir Oltean err = dsa_broadcast(DSA_NOTIFIER_BRIDGE_JOIN, &info); 4885961d6a1SVladimir Oltean if (err) 4895961d6a1SVladimir Oltean goto out_rollback; 490cfbed329SVivien Didelot 491857fdd74SVladimir Oltean /* Drivers which support bridge TX forwarding should set this */ 492857fdd74SVladimir Oltean dp->bridge->tx_fwd_offload = info.tx_fwd_offload; 493123abc06SVladimir Oltean 4944e51bf44SVladimir Oltean err = switchdev_bridge_port_offload(brport_dev, dev, dp, 4954e51bf44SVladimir Oltean &dsa_slave_switchdev_notifier, 4964e51bf44SVladimir Oltean &dsa_slave_switchdev_blocking_notifier, 497857fdd74SVladimir Oltean dp->bridge->tx_fwd_offload, extack); 4985961d6a1SVladimir Oltean if (err) 4995961d6a1SVladimir Oltean goto out_rollback_unbridge; 5005961d6a1SVladimir Oltean 5014e51bf44SVladimir Oltean err = dsa_port_switchdev_sync_attrs(dp, extack); 5022f5dc00fSVladimir Oltean if (err) 5032f5dc00fSVladimir Oltean goto out_rollback_unoffload; 5042f5dc00fSVladimir Oltean 5055961d6a1SVladimir Oltean return 0; 5065961d6a1SVladimir Oltean 5072f5dc00fSVladimir Oltean out_rollback_unoffload: 5084e51bf44SVladimir Oltean switchdev_bridge_port_unoffload(brport_dev, dp, 5094e51bf44SVladimir Oltean &dsa_slave_switchdev_notifier, 5104e51bf44SVladimir Oltean &dsa_slave_switchdev_blocking_notifier); 511630fd482SVladimir Oltean dsa_flush_workqueue(); 5125961d6a1SVladimir Oltean out_rollback_unbridge: 5135961d6a1SVladimir Oltean dsa_broadcast(DSA_NOTIFIER_BRIDGE_LEAVE, &info); 5145961d6a1SVladimir Oltean out_rollback: 515947c8746SVladimir Oltean dsa_port_bridge_destroy(dp, br); 516cfbed329SVivien Didelot return err; 517cfbed329SVivien Didelot } 518cfbed329SVivien Didelot 5194e51bf44SVladimir Oltean void dsa_port_pre_bridge_leave(struct dsa_port *dp, struct net_device *br) 52074918945SVladimir Oltean { 5212f5dc00fSVladimir Oltean struct net_device *brport_dev = dsa_port_to_bridge_port(dp); 5222f5dc00fSVladimir Oltean 52309dba21bSVladimir Oltean /* Don't try to unoffload something that is not offloaded */ 52409dba21bSVladimir Oltean if (!brport_dev) 52509dba21bSVladimir Oltean return; 52609dba21bSVladimir Oltean 5274e51bf44SVladimir Oltean switchdev_bridge_port_unoffload(brport_dev, dp, 5284e51bf44SVladimir Oltean &dsa_slave_switchdev_notifier, 5294e51bf44SVladimir Oltean &dsa_slave_switchdev_blocking_notifier); 530d7d0d423SVladimir Oltean 531d7d0d423SVladimir Oltean dsa_flush_workqueue(); 53274918945SVladimir Oltean } 53374918945SVladimir Oltean 534cfbed329SVivien Didelot void dsa_port_bridge_leave(struct dsa_port *dp, struct net_device *br) 535cfbed329SVivien Didelot { 536cfbed329SVivien Didelot struct dsa_notifier_bridge_info info = { 537726816a1SVladimir Oltean .dp = dp, 538cfbed329SVivien Didelot }; 539cfbed329SVivien Didelot int err; 540cfbed329SVivien Didelot 541342b6419SAlvin Šipraga /* If the port could not be offloaded to begin with, then 542342b6419SAlvin Šipraga * there is nothing to do. 543342b6419SAlvin Šipraga */ 544342b6419SAlvin Šipraga if (!dp->bridge) 545342b6419SAlvin Šipraga return; 546342b6419SAlvin Šipraga 547342b6419SAlvin Šipraga info.bridge = *dp->bridge; 548342b6419SAlvin Šipraga 549cfbed329SVivien Didelot /* Here the port is already unbridged. Reflect the current configuration 550cfbed329SVivien Didelot * so that drivers can program their chips accordingly. 551cfbed329SVivien Didelot */ 552947c8746SVladimir Oltean dsa_port_bridge_destroy(dp, br); 553cfbed329SVivien Didelot 554f66a6a69SVladimir Oltean err = dsa_broadcast(DSA_NOTIFIER_BRIDGE_LEAVE, &info); 555cfbed329SVivien Didelot if (err) 556ab97462bSVladimir Oltean dev_err(dp->ds->dev, 557ab97462bSVladimir Oltean "port %d failed to notify DSA_NOTIFIER_BRIDGE_LEAVE: %pe\n", 558ab97462bSVladimir Oltean dp->index, ERR_PTR(err)); 559cfbed329SVivien Didelot 5608e9e678eSVladimir Oltean dsa_port_switchdev_unsync_attrs(dp, info.bridge); 561cfbed329SVivien Didelot } 5624d61d304SVivien Didelot 563058102a6STobias Waldekranz int dsa_port_lag_change(struct dsa_port *dp, 564058102a6STobias Waldekranz struct netdev_lag_lower_state_info *linfo) 565058102a6STobias Waldekranz { 566058102a6STobias Waldekranz struct dsa_notifier_lag_info info = { 567726816a1SVladimir Oltean .dp = dp, 568058102a6STobias Waldekranz }; 569058102a6STobias Waldekranz bool tx_enabled; 570058102a6STobias Waldekranz 571dedd6a00SVladimir Oltean if (!dp->lag) 572058102a6STobias Waldekranz return 0; 573058102a6STobias Waldekranz 574058102a6STobias Waldekranz /* On statically configured aggregates (e.g. loadbalance 575058102a6STobias Waldekranz * without LACP) ports will always be tx_enabled, even if the 576058102a6STobias Waldekranz * link is down. Thus we require both link_up and tx_enabled 577058102a6STobias Waldekranz * in order to include it in the tx set. 578058102a6STobias Waldekranz */ 579058102a6STobias Waldekranz tx_enabled = linfo->link_up && linfo->tx_enabled; 580058102a6STobias Waldekranz 581058102a6STobias Waldekranz if (tx_enabled == dp->lag_tx_enabled) 582058102a6STobias Waldekranz return 0; 583058102a6STobias Waldekranz 584058102a6STobias Waldekranz dp->lag_tx_enabled = tx_enabled; 585058102a6STobias Waldekranz 586058102a6STobias Waldekranz return dsa_port_notify(dp, DSA_NOTIFIER_LAG_CHANGE, &info); 587058102a6STobias Waldekranz } 588058102a6STobias Waldekranz 589dedd6a00SVladimir Oltean static int dsa_port_lag_create(struct dsa_port *dp, 590dedd6a00SVladimir Oltean struct net_device *lag_dev) 591dedd6a00SVladimir Oltean { 592dedd6a00SVladimir Oltean struct dsa_switch *ds = dp->ds; 593dedd6a00SVladimir Oltean struct dsa_lag *lag; 594dedd6a00SVladimir Oltean 595dedd6a00SVladimir Oltean lag = dsa_tree_lag_find(ds->dst, lag_dev); 596dedd6a00SVladimir Oltean if (lag) { 597dedd6a00SVladimir Oltean refcount_inc(&lag->refcount); 598dedd6a00SVladimir Oltean dp->lag = lag; 599dedd6a00SVladimir Oltean return 0; 600dedd6a00SVladimir Oltean } 601dedd6a00SVladimir Oltean 602dedd6a00SVladimir Oltean lag = kzalloc(sizeof(*lag), GFP_KERNEL); 603dedd6a00SVladimir Oltean if (!lag) 604dedd6a00SVladimir Oltean return -ENOMEM; 605dedd6a00SVladimir Oltean 606dedd6a00SVladimir Oltean refcount_set(&lag->refcount, 1); 607e212fa7cSVladimir Oltean mutex_init(&lag->fdb_lock); 608e212fa7cSVladimir Oltean INIT_LIST_HEAD(&lag->fdbs); 609dedd6a00SVladimir Oltean lag->dev = lag_dev; 610dedd6a00SVladimir Oltean dsa_lag_map(ds->dst, lag); 611dedd6a00SVladimir Oltean dp->lag = lag; 612dedd6a00SVladimir Oltean 613dedd6a00SVladimir Oltean return 0; 614dedd6a00SVladimir Oltean } 615dedd6a00SVladimir Oltean 616dedd6a00SVladimir Oltean static void dsa_port_lag_destroy(struct dsa_port *dp) 617dedd6a00SVladimir Oltean { 618dedd6a00SVladimir Oltean struct dsa_lag *lag = dp->lag; 619dedd6a00SVladimir Oltean 620dedd6a00SVladimir Oltean dp->lag = NULL; 621dedd6a00SVladimir Oltean dp->lag_tx_enabled = false; 622dedd6a00SVladimir Oltean 623dedd6a00SVladimir Oltean if (!refcount_dec_and_test(&lag->refcount)) 624dedd6a00SVladimir Oltean return; 625dedd6a00SVladimir Oltean 626e212fa7cSVladimir Oltean WARN_ON(!list_empty(&lag->fdbs)); 627dedd6a00SVladimir Oltean dsa_lag_unmap(dp->ds->dst, lag); 628dedd6a00SVladimir Oltean kfree(lag); 629dedd6a00SVladimir Oltean } 630dedd6a00SVladimir Oltean 63146a76724SVladimir Oltean int dsa_port_lag_join(struct dsa_port *dp, struct net_device *lag_dev, 6322afc526aSVladimir Oltean struct netdev_lag_upper_info *uinfo, 6332afc526aSVladimir Oltean struct netlink_ext_ack *extack) 634058102a6STobias Waldekranz { 635058102a6STobias Waldekranz struct dsa_notifier_lag_info info = { 636726816a1SVladimir Oltean .dp = dp, 637058102a6STobias Waldekranz .info = uinfo, 638*2e359b00SVladimir Oltean .extack = extack, 639058102a6STobias Waldekranz }; 640185c9a76SVladimir Oltean struct net_device *bridge_dev; 641058102a6STobias Waldekranz int err; 642058102a6STobias Waldekranz 643dedd6a00SVladimir Oltean err = dsa_port_lag_create(dp, lag_dev); 644dedd6a00SVladimir Oltean if (err) 645dedd6a00SVladimir Oltean goto err_lag_create; 646058102a6STobias Waldekranz 647dedd6a00SVladimir Oltean info.lag = *dp->lag; 648058102a6STobias Waldekranz err = dsa_port_notify(dp, DSA_NOTIFIER_LAG_JOIN, &info); 649185c9a76SVladimir Oltean if (err) 650185c9a76SVladimir Oltean goto err_lag_join; 651185c9a76SVladimir Oltean 65246a76724SVladimir Oltean bridge_dev = netdev_master_upper_dev_get(lag_dev); 653185c9a76SVladimir Oltean if (!bridge_dev || !netif_is_bridge_master(bridge_dev)) 654185c9a76SVladimir Oltean return 0; 655185c9a76SVladimir Oltean 6562afc526aSVladimir Oltean err = dsa_port_bridge_join(dp, bridge_dev, extack); 657185c9a76SVladimir Oltean if (err) 658185c9a76SVladimir Oltean goto err_bridge_join; 659185c9a76SVladimir Oltean 660185c9a76SVladimir Oltean return 0; 661185c9a76SVladimir Oltean 662185c9a76SVladimir Oltean err_bridge_join: 663185c9a76SVladimir Oltean dsa_port_notify(dp, DSA_NOTIFIER_LAG_LEAVE, &info); 664185c9a76SVladimir Oltean err_lag_join: 665dedd6a00SVladimir Oltean dsa_port_lag_destroy(dp); 666dedd6a00SVladimir Oltean err_lag_create: 667058102a6STobias Waldekranz return err; 668058102a6STobias Waldekranz } 669058102a6STobias Waldekranz 67046a76724SVladimir Oltean void dsa_port_pre_lag_leave(struct dsa_port *dp, struct net_device *lag_dev) 67174918945SVladimir Oltean { 67236cbf39bSVladimir Oltean struct net_device *br = dsa_port_bridge_dev_get(dp); 67336cbf39bSVladimir Oltean 67436cbf39bSVladimir Oltean if (br) 67536cbf39bSVladimir Oltean dsa_port_pre_bridge_leave(dp, br); 67674918945SVladimir Oltean } 67774918945SVladimir Oltean 67846a76724SVladimir Oltean void dsa_port_lag_leave(struct dsa_port *dp, struct net_device *lag_dev) 679058102a6STobias Waldekranz { 68036cbf39bSVladimir Oltean struct net_device *br = dsa_port_bridge_dev_get(dp); 681058102a6STobias Waldekranz struct dsa_notifier_lag_info info = { 682726816a1SVladimir Oltean .dp = dp, 683058102a6STobias Waldekranz }; 684058102a6STobias Waldekranz int err; 685058102a6STobias Waldekranz 686dedd6a00SVladimir Oltean if (!dp->lag) 687058102a6STobias Waldekranz return; 688058102a6STobias Waldekranz 689058102a6STobias Waldekranz /* Port might have been part of a LAG that in turn was 690058102a6STobias Waldekranz * attached to a bridge. 691058102a6STobias Waldekranz */ 69236cbf39bSVladimir Oltean if (br) 69336cbf39bSVladimir Oltean dsa_port_bridge_leave(dp, br); 694058102a6STobias Waldekranz 695dedd6a00SVladimir Oltean info.lag = *dp->lag; 696dedd6a00SVladimir Oltean 697dedd6a00SVladimir Oltean dsa_port_lag_destroy(dp); 698058102a6STobias Waldekranz 699058102a6STobias Waldekranz err = dsa_port_notify(dp, DSA_NOTIFIER_LAG_LEAVE, &info); 700058102a6STobias Waldekranz if (err) 701ab97462bSVladimir Oltean dev_err(dp->ds->dev, 702ab97462bSVladimir Oltean "port %d failed to notify DSA_NOTIFIER_LAG_LEAVE: %pe\n", 703ab97462bSVladimir Oltean dp->index, ERR_PTR(err)); 704058102a6STobias Waldekranz } 705058102a6STobias Waldekranz 706adb256ebSVladimir Oltean /* Must be called under rcu_read_lock() */ 7078f5d16f6SVladimir Oltean static bool dsa_port_can_apply_vlan_filtering(struct dsa_port *dp, 70889153ed6SVladimir Oltean bool vlan_filtering, 70989153ed6SVladimir Oltean struct netlink_ext_ack *extack) 7108f5d16f6SVladimir Oltean { 7118f5d16f6SVladimir Oltean struct dsa_switch *ds = dp->ds; 712d0004a02SVladimir Oltean struct dsa_port *other_dp; 713d0004a02SVladimir Oltean int err; 714adb256ebSVladimir Oltean 715adb256ebSVladimir Oltean /* VLAN awareness was off, so the question is "can we turn it on". 716adb256ebSVladimir Oltean * We may have had 8021q uppers, those need to go. Make sure we don't 717adb256ebSVladimir Oltean * enter an inconsistent state: deny changing the VLAN awareness state 718adb256ebSVladimir Oltean * as long as we have 8021q uppers. 719adb256ebSVladimir Oltean */ 72057d77986SVladimir Oltean if (vlan_filtering && dsa_port_is_user(dp)) { 72136cbf39bSVladimir Oltean struct net_device *br = dsa_port_bridge_dev_get(dp); 722adb256ebSVladimir Oltean struct net_device *upper_dev, *slave = dp->slave; 723adb256ebSVladimir Oltean struct list_head *iter; 724adb256ebSVladimir Oltean 725adb256ebSVladimir Oltean netdev_for_each_upper_dev_rcu(slave, upper_dev, iter) { 726adb256ebSVladimir Oltean struct bridge_vlan_info br_info; 727adb256ebSVladimir Oltean u16 vid; 728adb256ebSVladimir Oltean 729adb256ebSVladimir Oltean if (!is_vlan_dev(upper_dev)) 730adb256ebSVladimir Oltean continue; 731adb256ebSVladimir Oltean 732adb256ebSVladimir Oltean vid = vlan_dev_vlan_id(upper_dev); 733adb256ebSVladimir Oltean 734adb256ebSVladimir Oltean /* br_vlan_get_info() returns -EINVAL or -ENOENT if the 735adb256ebSVladimir Oltean * device, respectively the VID is not found, returning 736adb256ebSVladimir Oltean * 0 means success, which is a failure for us here. 737adb256ebSVladimir Oltean */ 738adb256ebSVladimir Oltean err = br_vlan_get_info(br, vid, &br_info); 739adb256ebSVladimir Oltean if (err == 0) { 74089153ed6SVladimir Oltean NL_SET_ERR_MSG_MOD(extack, 74189153ed6SVladimir Oltean "Must first remove VLAN uppers having VIDs also present in bridge"); 742adb256ebSVladimir Oltean return false; 743adb256ebSVladimir Oltean } 744adb256ebSVladimir Oltean } 745adb256ebSVladimir Oltean } 7468f5d16f6SVladimir Oltean 7478f5d16f6SVladimir Oltean if (!ds->vlan_filtering_is_global) 7488f5d16f6SVladimir Oltean return true; 7498f5d16f6SVladimir Oltean 7508f5d16f6SVladimir Oltean /* For cases where enabling/disabling VLAN awareness is global to the 7518f5d16f6SVladimir Oltean * switch, we need to handle the case where multiple bridges span 7528f5d16f6SVladimir Oltean * different ports of the same switch device and one of them has a 7538f5d16f6SVladimir Oltean * different setting than what is being requested. 7548f5d16f6SVladimir Oltean */ 755d0004a02SVladimir Oltean dsa_switch_for_each_port(other_dp, ds) { 75636cbf39bSVladimir Oltean struct net_device *other_br = dsa_port_bridge_dev_get(other_dp); 7578f5d16f6SVladimir Oltean 7588f5d16f6SVladimir Oltean /* If it's the same bridge, it also has same 7598f5d16f6SVladimir Oltean * vlan_filtering setting => no need to check 7608f5d16f6SVladimir Oltean */ 76136cbf39bSVladimir Oltean if (!other_br || other_br == dsa_port_bridge_dev_get(dp)) 7628f5d16f6SVladimir Oltean continue; 76336cbf39bSVladimir Oltean 76436cbf39bSVladimir Oltean if (br_vlan_enabled(other_br) != vlan_filtering) { 76589153ed6SVladimir Oltean NL_SET_ERR_MSG_MOD(extack, 76689153ed6SVladimir Oltean "VLAN filtering is a global setting"); 7678f5d16f6SVladimir Oltean return false; 7688f5d16f6SVladimir Oltean } 7698f5d16f6SVladimir Oltean } 7708f5d16f6SVladimir Oltean return true; 7718f5d16f6SVladimir Oltean } 7728f5d16f6SVladimir Oltean 77389153ed6SVladimir Oltean int dsa_port_vlan_filtering(struct dsa_port *dp, bool vlan_filtering, 77489153ed6SVladimir Oltean struct netlink_ext_ack *extack) 7754d61d304SVivien Didelot { 77606cfb2dfSVladimir Oltean bool old_vlan_filtering = dsa_port_is_vlan_filtering(dp); 7774d61d304SVivien Didelot struct dsa_switch *ds = dp->ds; 778adb256ebSVladimir Oltean bool apply; 779bae33f2bSVladimir Oltean int err; 780adb256ebSVladimir Oltean 7818f5d16f6SVladimir Oltean if (!ds->ops->port_vlan_filtering) 782707ec383SVladimir Oltean return -EOPNOTSUPP; 7838f5d16f6SVladimir Oltean 784adb256ebSVladimir Oltean /* We are called from dsa_slave_switchdev_blocking_event(), 785adb256ebSVladimir Oltean * which is not under rcu_read_lock(), unlike 786adb256ebSVladimir Oltean * dsa_slave_switchdev_event(). 787adb256ebSVladimir Oltean */ 788adb256ebSVladimir Oltean rcu_read_lock(); 78989153ed6SVladimir Oltean apply = dsa_port_can_apply_vlan_filtering(dp, vlan_filtering, extack); 790adb256ebSVladimir Oltean rcu_read_unlock(); 791adb256ebSVladimir Oltean if (!apply) 7928f5d16f6SVladimir Oltean return -EINVAL; 793707ec383SVladimir Oltean 794ec9121e7SVladimir Oltean if (dsa_port_is_vlan_filtering(dp) == vlan_filtering) 795ec9121e7SVladimir Oltean return 0; 796ec9121e7SVladimir Oltean 79789153ed6SVladimir Oltean err = ds->ops->port_vlan_filtering(ds, dp->index, vlan_filtering, 79889153ed6SVladimir Oltean extack); 79933162e9aSVladimir Oltean if (err) 80033162e9aSVladimir Oltean return err; 8018f5d16f6SVladimir Oltean 80206cfb2dfSVladimir Oltean if (ds->vlan_filtering_is_global) { 803d0004a02SVladimir Oltean struct dsa_port *other_dp; 80406cfb2dfSVladimir Oltean 80514574676SVladimir Oltean ds->vlan_filtering = vlan_filtering; 80606cfb2dfSVladimir Oltean 807d0004a02SVladimir Oltean dsa_switch_for_each_user_port(other_dp, ds) { 8084db2a5efSVladimir Oltean struct net_device *slave = other_dp->slave; 80906cfb2dfSVladimir Oltean 81006cfb2dfSVladimir Oltean /* We might be called in the unbind path, so not 81106cfb2dfSVladimir Oltean * all slave devices might still be registered. 81206cfb2dfSVladimir Oltean */ 81306cfb2dfSVladimir Oltean if (!slave) 81406cfb2dfSVladimir Oltean continue; 81506cfb2dfSVladimir Oltean 81606cfb2dfSVladimir Oltean err = dsa_slave_manage_vlan_filtering(slave, 81706cfb2dfSVladimir Oltean vlan_filtering); 81806cfb2dfSVladimir Oltean if (err) 81906cfb2dfSVladimir Oltean goto restore; 82006cfb2dfSVladimir Oltean } 82106cfb2dfSVladimir Oltean } else { 82233162e9aSVladimir Oltean dp->vlan_filtering = vlan_filtering; 8232e554a7aSVladimir Oltean 82406cfb2dfSVladimir Oltean err = dsa_slave_manage_vlan_filtering(dp->slave, 82506cfb2dfSVladimir Oltean vlan_filtering); 82606cfb2dfSVladimir Oltean if (err) 82706cfb2dfSVladimir Oltean goto restore; 82806cfb2dfSVladimir Oltean } 82906cfb2dfSVladimir Oltean 8304d61d304SVivien Didelot return 0; 83106cfb2dfSVladimir Oltean 83206cfb2dfSVladimir Oltean restore: 83306cfb2dfSVladimir Oltean ds->ops->port_vlan_filtering(ds, dp->index, old_vlan_filtering, NULL); 83406cfb2dfSVladimir Oltean 83506cfb2dfSVladimir Oltean if (ds->vlan_filtering_is_global) 83606cfb2dfSVladimir Oltean ds->vlan_filtering = old_vlan_filtering; 83706cfb2dfSVladimir Oltean else 83806cfb2dfSVladimir Oltean dp->vlan_filtering = old_vlan_filtering; 83906cfb2dfSVladimir Oltean 84006cfb2dfSVladimir Oltean return err; 8414d61d304SVivien Didelot } 842d87bd94eSVivien Didelot 84354a0ed0dSRussell King /* This enforces legacy behavior for switch drivers which assume they can't 84454a0ed0dSRussell King * receive VLAN configuration when enslaved to a bridge with vlan_filtering=0 84554a0ed0dSRussell King */ 84654a0ed0dSRussell King bool dsa_port_skip_vlan_configuration(struct dsa_port *dp) 84754a0ed0dSRussell King { 84836cbf39bSVladimir Oltean struct net_device *br = dsa_port_bridge_dev_get(dp); 84954a0ed0dSRussell King struct dsa_switch *ds = dp->ds; 85054a0ed0dSRussell King 85136cbf39bSVladimir Oltean if (!br) 85254a0ed0dSRussell King return false; 85354a0ed0dSRussell King 85436cbf39bSVladimir Oltean return !ds->configure_vlan_while_not_filtering && !br_vlan_enabled(br); 85554a0ed0dSRussell King } 85654a0ed0dSRussell King 857bae33f2bSVladimir Oltean int dsa_port_ageing_time(struct dsa_port *dp, clock_t ageing_clock) 858d87bd94eSVivien Didelot { 859d87bd94eSVivien Didelot unsigned long ageing_jiffies = clock_t_to_jiffies(ageing_clock); 860d87bd94eSVivien Didelot unsigned int ageing_time = jiffies_to_msecs(ageing_jiffies); 861bae33f2bSVladimir Oltean struct dsa_notifier_ageing_time_info info; 862bae33f2bSVladimir Oltean int err; 863d87bd94eSVivien Didelot 864bae33f2bSVladimir Oltean info.ageing_time = ageing_time; 865bae33f2bSVladimir Oltean 866bae33f2bSVladimir Oltean err = dsa_port_notify(dp, DSA_NOTIFIER_AGEING_TIME, &info); 867bae33f2bSVladimir Oltean if (err) 868bae33f2bSVladimir Oltean return err; 869d87bd94eSVivien Didelot 870d87bd94eSVivien Didelot dp->ageing_time = ageing_time; 871d87bd94eSVivien Didelot 87277b61365SVladimir Oltean return 0; 873d87bd94eSVivien Didelot } 874d1cffff0SVivien Didelot 875332afc4cSTobias Waldekranz int dsa_port_mst_enable(struct dsa_port *dp, bool on, 876332afc4cSTobias Waldekranz struct netlink_ext_ack *extack) 877332afc4cSTobias Waldekranz { 8787414af30STobias Waldekranz if (on && !dsa_port_supports_mst(dp)) { 879332afc4cSTobias Waldekranz NL_SET_ERR_MSG_MOD(extack, "Hardware does not support MST"); 880332afc4cSTobias Waldekranz return -EINVAL; 881332afc4cSTobias Waldekranz } 882332afc4cSTobias Waldekranz 883332afc4cSTobias Waldekranz return 0; 884332afc4cSTobias Waldekranz } 885332afc4cSTobias Waldekranz 886e18f4c18SVladimir Oltean int dsa_port_pre_bridge_flags(const struct dsa_port *dp, 887a8b659e7SVladimir Oltean struct switchdev_brport_flags flags, 888a8b659e7SVladimir Oltean struct netlink_ext_ack *extack) 889ea87005aSFlorian Fainelli { 890ea87005aSFlorian Fainelli struct dsa_switch *ds = dp->ds; 891ea87005aSFlorian Fainelli 892a8b659e7SVladimir Oltean if (!ds->ops->port_pre_bridge_flags) 893ea87005aSFlorian Fainelli return -EINVAL; 894ea87005aSFlorian Fainelli 895a8b659e7SVladimir Oltean return ds->ops->port_pre_bridge_flags(ds, dp->index, flags, extack); 896ea87005aSFlorian Fainelli } 897ea87005aSFlorian Fainelli 898045c45d1SVladimir Oltean int dsa_port_bridge_flags(struct dsa_port *dp, 899a8b659e7SVladimir Oltean struct switchdev_brport_flags flags, 900a8b659e7SVladimir Oltean struct netlink_ext_ack *extack) 90157652796SRussell King { 90257652796SRussell King struct dsa_switch *ds = dp->ds; 903045c45d1SVladimir Oltean int err; 90457652796SRussell King 905a8b659e7SVladimir Oltean if (!ds->ops->port_bridge_flags) 90670a7c484SOleksij Rempel return -EOPNOTSUPP; 90757652796SRussell King 908045c45d1SVladimir Oltean err = ds->ops->port_bridge_flags(ds, dp->index, flags, extack); 909045c45d1SVladimir Oltean if (err) 910045c45d1SVladimir Oltean return err; 911045c45d1SVladimir Oltean 912045c45d1SVladimir Oltean if (flags.mask & BR_LEARNING) { 913045c45d1SVladimir Oltean bool learning = flags.val & BR_LEARNING; 914045c45d1SVladimir Oltean 915045c45d1SVladimir Oltean if (learning == dp->learning) 916045c45d1SVladimir Oltean return 0; 917045c45d1SVladimir Oltean 918bee7c577SVladimir Oltean if ((dp->learning && !learning) && 919bee7c577SVladimir Oltean (dp->stp_state == BR_STATE_LEARNING || 920bee7c577SVladimir Oltean dp->stp_state == BR_STATE_FORWARDING)) 921045c45d1SVladimir Oltean dsa_port_fast_age(dp); 922045c45d1SVladimir Oltean 923045c45d1SVladimir Oltean dp->learning = learning; 924045c45d1SVladimir Oltean } 925045c45d1SVladimir Oltean 926045c45d1SVladimir Oltean return 0; 92757652796SRussell King } 92857652796SRussell King 92972c3b0c7SVladimir Oltean void dsa_port_set_host_flood(struct dsa_port *dp, bool uc, bool mc) 93072c3b0c7SVladimir Oltean { 93172c3b0c7SVladimir Oltean struct dsa_switch *ds = dp->ds; 93272c3b0c7SVladimir Oltean 93372c3b0c7SVladimir Oltean if (ds->ops->port_set_host_flood) 93472c3b0c7SVladimir Oltean ds->ops->port_set_host_flood(ds, dp->index, uc, mc); 93572c3b0c7SVladimir Oltean } 93672c3b0c7SVladimir Oltean 9378e6598a7STobias Waldekranz int dsa_port_vlan_msti(struct dsa_port *dp, 9388e6598a7STobias Waldekranz const struct switchdev_vlan_msti *msti) 9398e6598a7STobias Waldekranz { 9408e6598a7STobias Waldekranz struct dsa_switch *ds = dp->ds; 9418e6598a7STobias Waldekranz 9428e6598a7STobias Waldekranz if (!ds->ops->vlan_msti_set) 9438e6598a7STobias Waldekranz return -EOPNOTSUPP; 9448e6598a7STobias Waldekranz 9458e6598a7STobias Waldekranz return ds->ops->vlan_msti_set(ds, *dp->bridge, msti); 9468e6598a7STobias Waldekranz } 9478e6598a7STobias Waldekranz 948be6ff966SVladimir Oltean int dsa_port_mtu_change(struct dsa_port *dp, int new_mtu) 949bfcb8132SVladimir Oltean { 950bfcb8132SVladimir Oltean struct dsa_notifier_mtu_info info = { 951726816a1SVladimir Oltean .dp = dp, 952bfcb8132SVladimir Oltean .mtu = new_mtu, 953bfcb8132SVladimir Oltean }; 954bfcb8132SVladimir Oltean 955bfcb8132SVladimir Oltean return dsa_port_notify(dp, DSA_NOTIFIER_MTU, &info); 956bfcb8132SVladimir Oltean } 957bfcb8132SVladimir Oltean 9582acf4e6aSArkadi Sharshevsky int dsa_port_fdb_add(struct dsa_port *dp, const unsigned char *addr, 9592acf4e6aSArkadi Sharshevsky u16 vid) 960d1cffff0SVivien Didelot { 961685fb6a4SVivien Didelot struct dsa_notifier_fdb_info info = { 962726816a1SVladimir Oltean .dp = dp, 9632acf4e6aSArkadi Sharshevsky .addr = addr, 9642acf4e6aSArkadi Sharshevsky .vid = vid, 965c2693363SVladimir Oltean .db = { 966c2693363SVladimir Oltean .type = DSA_DB_BRIDGE, 967c2693363SVladimir Oltean .bridge = *dp->bridge, 968c2693363SVladimir Oltean }, 969685fb6a4SVivien Didelot }; 970d1cffff0SVivien Didelot 971c2693363SVladimir Oltean /* Refcounting takes bridge.num as a key, and should be global for all 972c2693363SVladimir Oltean * bridges in the absence of FDB isolation, and per bridge otherwise. 973c2693363SVladimir Oltean * Force the bridge.num to zero here in the absence of FDB isolation. 974c2693363SVladimir Oltean */ 975c2693363SVladimir Oltean if (!dp->ds->fdb_isolation) 976c2693363SVladimir Oltean info.db.bridge.num = 0; 977c2693363SVladimir Oltean 978685fb6a4SVivien Didelot return dsa_port_notify(dp, DSA_NOTIFIER_FDB_ADD, &info); 979d1cffff0SVivien Didelot } 980d1cffff0SVivien Didelot 9812acf4e6aSArkadi Sharshevsky int dsa_port_fdb_del(struct dsa_port *dp, const unsigned char *addr, 9822acf4e6aSArkadi Sharshevsky u16 vid) 983d1cffff0SVivien Didelot { 984685fb6a4SVivien Didelot struct dsa_notifier_fdb_info info = { 985726816a1SVladimir Oltean .dp = dp, 9862acf4e6aSArkadi Sharshevsky .addr = addr, 9872acf4e6aSArkadi Sharshevsky .vid = vid, 988c2693363SVladimir Oltean .db = { 989c2693363SVladimir Oltean .type = DSA_DB_BRIDGE, 990c2693363SVladimir Oltean .bridge = *dp->bridge, 991c2693363SVladimir Oltean }, 992685fb6a4SVivien Didelot }; 993d1cffff0SVivien Didelot 994c2693363SVladimir Oltean if (!dp->ds->fdb_isolation) 995c2693363SVladimir Oltean info.db.bridge.num = 0; 996c2693363SVladimir Oltean 997685fb6a4SVivien Didelot return dsa_port_notify(dp, DSA_NOTIFIER_FDB_DEL, &info); 998d1cffff0SVivien Didelot } 999d1cffff0SVivien Didelot 10005e8a1e03SVladimir Oltean static int dsa_port_host_fdb_add(struct dsa_port *dp, 10015e8a1e03SVladimir Oltean const unsigned char *addr, u16 vid, 10025e8a1e03SVladimir Oltean struct dsa_db db) 10033dc80afcSVladimir Oltean { 10043dc80afcSVladimir Oltean struct dsa_notifier_fdb_info info = { 1005726816a1SVladimir Oltean .dp = dp, 10063dc80afcSVladimir Oltean .addr = addr, 10073dc80afcSVladimir Oltean .vid = vid, 10085e8a1e03SVladimir Oltean .db = db, 10095e8a1e03SVladimir Oltean }; 10105e8a1e03SVladimir Oltean 10115e8a1e03SVladimir Oltean if (!dp->ds->fdb_isolation) 10125e8a1e03SVladimir Oltean info.db.bridge.num = 0; 10135e8a1e03SVladimir Oltean 10145e8a1e03SVladimir Oltean return dsa_port_notify(dp, DSA_NOTIFIER_HOST_FDB_ADD, &info); 10155e8a1e03SVladimir Oltean } 10165e8a1e03SVladimir Oltean 10175e8a1e03SVladimir Oltean int dsa_port_standalone_host_fdb_add(struct dsa_port *dp, 10185e8a1e03SVladimir Oltean const unsigned char *addr, u16 vid) 10195e8a1e03SVladimir Oltean { 10205e8a1e03SVladimir Oltean struct dsa_db db = { 10215e8a1e03SVladimir Oltean .type = DSA_DB_PORT, 10225e8a1e03SVladimir Oltean .dp = dp, 10235e8a1e03SVladimir Oltean }; 10245e8a1e03SVladimir Oltean 10255e8a1e03SVladimir Oltean return dsa_port_host_fdb_add(dp, addr, vid, db); 10265e8a1e03SVladimir Oltean } 10275e8a1e03SVladimir Oltean 10285e8a1e03SVladimir Oltean int dsa_port_bridge_host_fdb_add(struct dsa_port *dp, 10295e8a1e03SVladimir Oltean const unsigned char *addr, u16 vid) 10305e8a1e03SVladimir Oltean { 10318f6a19c0SVladimir Oltean struct net_device *master = dsa_port_to_master(dp); 10325e8a1e03SVladimir Oltean struct dsa_db db = { 1033c2693363SVladimir Oltean .type = DSA_DB_BRIDGE, 1034c2693363SVladimir Oltean .bridge = *dp->bridge, 10353dc80afcSVladimir Oltean }; 103626ee7b06SVladimir Oltean int err; 103726ee7b06SVladimir Oltean 10388940e6b6SVladimir Oltean /* Avoid a call to __dev_set_promiscuity() on the master, which 10398940e6b6SVladimir Oltean * requires rtnl_lock(), since we can't guarantee that is held here, 10408940e6b6SVladimir Oltean * and we can't take it either. 10418940e6b6SVladimir Oltean */ 10428f6a19c0SVladimir Oltean if (master->priv_flags & IFF_UNICAST_FLT) { 10438f6a19c0SVladimir Oltean err = dev_uc_add(master, addr); 104426ee7b06SVladimir Oltean if (err) 104526ee7b06SVladimir Oltean return err; 10468940e6b6SVladimir Oltean } 10473dc80afcSVladimir Oltean 10485e8a1e03SVladimir Oltean return dsa_port_host_fdb_add(dp, addr, vid, db); 10493dc80afcSVladimir Oltean } 10503dc80afcSVladimir Oltean 10515e8a1e03SVladimir Oltean static int dsa_port_host_fdb_del(struct dsa_port *dp, 10525e8a1e03SVladimir Oltean const unsigned char *addr, u16 vid, 10535e8a1e03SVladimir Oltean struct dsa_db db) 10543dc80afcSVladimir Oltean { 10553dc80afcSVladimir Oltean struct dsa_notifier_fdb_info info = { 1056726816a1SVladimir Oltean .dp = dp, 10573dc80afcSVladimir Oltean .addr = addr, 10583dc80afcSVladimir Oltean .vid = vid, 10595e8a1e03SVladimir Oltean .db = db, 10605e8a1e03SVladimir Oltean }; 10615e8a1e03SVladimir Oltean 10625e8a1e03SVladimir Oltean if (!dp->ds->fdb_isolation) 10635e8a1e03SVladimir Oltean info.db.bridge.num = 0; 10645e8a1e03SVladimir Oltean 10655e8a1e03SVladimir Oltean return dsa_port_notify(dp, DSA_NOTIFIER_HOST_FDB_DEL, &info); 10665e8a1e03SVladimir Oltean } 10675e8a1e03SVladimir Oltean 10685e8a1e03SVladimir Oltean int dsa_port_standalone_host_fdb_del(struct dsa_port *dp, 10695e8a1e03SVladimir Oltean const unsigned char *addr, u16 vid) 10705e8a1e03SVladimir Oltean { 10715e8a1e03SVladimir Oltean struct dsa_db db = { 10725e8a1e03SVladimir Oltean .type = DSA_DB_PORT, 10735e8a1e03SVladimir Oltean .dp = dp, 10745e8a1e03SVladimir Oltean }; 10755e8a1e03SVladimir Oltean 10765e8a1e03SVladimir Oltean return dsa_port_host_fdb_del(dp, addr, vid, db); 10775e8a1e03SVladimir Oltean } 10785e8a1e03SVladimir Oltean 10795e8a1e03SVladimir Oltean int dsa_port_bridge_host_fdb_del(struct dsa_port *dp, 10805e8a1e03SVladimir Oltean const unsigned char *addr, u16 vid) 10815e8a1e03SVladimir Oltean { 10828f6a19c0SVladimir Oltean struct net_device *master = dsa_port_to_master(dp); 10835e8a1e03SVladimir Oltean struct dsa_db db = { 1084c2693363SVladimir Oltean .type = DSA_DB_BRIDGE, 1085c2693363SVladimir Oltean .bridge = *dp->bridge, 10863dc80afcSVladimir Oltean }; 108726ee7b06SVladimir Oltean int err; 108826ee7b06SVladimir Oltean 10898f6a19c0SVladimir Oltean if (master->priv_flags & IFF_UNICAST_FLT) { 10908f6a19c0SVladimir Oltean err = dev_uc_del(master, addr); 109126ee7b06SVladimir Oltean if (err) 109226ee7b06SVladimir Oltean return err; 10938940e6b6SVladimir Oltean } 10943dc80afcSVladimir Oltean 10955e8a1e03SVladimir Oltean return dsa_port_host_fdb_del(dp, addr, vid, db); 10963dc80afcSVladimir Oltean } 10973dc80afcSVladimir Oltean 1098e212fa7cSVladimir Oltean int dsa_port_lag_fdb_add(struct dsa_port *dp, const unsigned char *addr, 1099e212fa7cSVladimir Oltean u16 vid) 1100e212fa7cSVladimir Oltean { 1101e212fa7cSVladimir Oltean struct dsa_notifier_lag_fdb_info info = { 1102e212fa7cSVladimir Oltean .lag = dp->lag, 1103e212fa7cSVladimir Oltean .addr = addr, 1104e212fa7cSVladimir Oltean .vid = vid, 1105c2693363SVladimir Oltean .db = { 1106c2693363SVladimir Oltean .type = DSA_DB_BRIDGE, 1107c2693363SVladimir Oltean .bridge = *dp->bridge, 1108c2693363SVladimir Oltean }, 1109e212fa7cSVladimir Oltean }; 1110e212fa7cSVladimir Oltean 1111c2693363SVladimir Oltean if (!dp->ds->fdb_isolation) 1112c2693363SVladimir Oltean info.db.bridge.num = 0; 1113c2693363SVladimir Oltean 1114e212fa7cSVladimir Oltean return dsa_port_notify(dp, DSA_NOTIFIER_LAG_FDB_ADD, &info); 1115e212fa7cSVladimir Oltean } 1116e212fa7cSVladimir Oltean 1117e212fa7cSVladimir Oltean int dsa_port_lag_fdb_del(struct dsa_port *dp, const unsigned char *addr, 1118e212fa7cSVladimir Oltean u16 vid) 1119e212fa7cSVladimir Oltean { 1120e212fa7cSVladimir Oltean struct dsa_notifier_lag_fdb_info info = { 1121e212fa7cSVladimir Oltean .lag = dp->lag, 1122e212fa7cSVladimir Oltean .addr = addr, 1123e212fa7cSVladimir Oltean .vid = vid, 1124c2693363SVladimir Oltean .db = { 1125c2693363SVladimir Oltean .type = DSA_DB_BRIDGE, 1126c2693363SVladimir Oltean .bridge = *dp->bridge, 1127c2693363SVladimir Oltean }, 1128e212fa7cSVladimir Oltean }; 1129e212fa7cSVladimir Oltean 1130c2693363SVladimir Oltean if (!dp->ds->fdb_isolation) 1131c2693363SVladimir Oltean info.db.bridge.num = 0; 1132c2693363SVladimir Oltean 1133e212fa7cSVladimir Oltean return dsa_port_notify(dp, DSA_NOTIFIER_LAG_FDB_DEL, &info); 1134e212fa7cSVladimir Oltean } 1135e212fa7cSVladimir Oltean 1136de40fc5dSVivien Didelot int dsa_port_fdb_dump(struct dsa_port *dp, dsa_fdb_dump_cb_t *cb, void *data) 1137de40fc5dSVivien Didelot { 1138de40fc5dSVivien Didelot struct dsa_switch *ds = dp->ds; 1139de40fc5dSVivien Didelot int port = dp->index; 1140de40fc5dSVivien Didelot 1141de40fc5dSVivien Didelot if (!ds->ops->port_fdb_dump) 1142de40fc5dSVivien Didelot return -EOPNOTSUPP; 1143de40fc5dSVivien Didelot 1144de40fc5dSVivien Didelot return ds->ops->port_fdb_dump(ds, port, cb, data); 1145de40fc5dSVivien Didelot } 1146de40fc5dSVivien Didelot 1147bb9f6031SAndrew Lunn int dsa_port_mdb_add(const struct dsa_port *dp, 1148ffb68fc5SVladimir Oltean const struct switchdev_obj_port_mdb *mdb) 11493a9afea3SVivien Didelot { 11508ae5bcdcSVivien Didelot struct dsa_notifier_mdb_info info = { 1151726816a1SVladimir Oltean .dp = dp, 11528ae5bcdcSVivien Didelot .mdb = mdb, 1153c2693363SVladimir Oltean .db = { 1154c2693363SVladimir Oltean .type = DSA_DB_BRIDGE, 1155c2693363SVladimir Oltean .bridge = *dp->bridge, 1156c2693363SVladimir Oltean }, 11578ae5bcdcSVivien Didelot }; 11583a9afea3SVivien Didelot 1159c2693363SVladimir Oltean if (!dp->ds->fdb_isolation) 1160c2693363SVladimir Oltean info.db.bridge.num = 0; 1161c2693363SVladimir Oltean 11628ae5bcdcSVivien Didelot return dsa_port_notify(dp, DSA_NOTIFIER_MDB_ADD, &info); 11633a9afea3SVivien Didelot } 11643a9afea3SVivien Didelot 1165bb9f6031SAndrew Lunn int dsa_port_mdb_del(const struct dsa_port *dp, 11663a9afea3SVivien Didelot const struct switchdev_obj_port_mdb *mdb) 11673a9afea3SVivien Didelot { 11688ae5bcdcSVivien Didelot struct dsa_notifier_mdb_info info = { 1169726816a1SVladimir Oltean .dp = dp, 11708ae5bcdcSVivien Didelot .mdb = mdb, 1171c2693363SVladimir Oltean .db = { 1172c2693363SVladimir Oltean .type = DSA_DB_BRIDGE, 1173c2693363SVladimir Oltean .bridge = *dp->bridge, 1174c2693363SVladimir Oltean }, 11758ae5bcdcSVivien Didelot }; 11763a9afea3SVivien Didelot 1177c2693363SVladimir Oltean if (!dp->ds->fdb_isolation) 1178c2693363SVladimir Oltean info.db.bridge.num = 0; 1179c2693363SVladimir Oltean 11808ae5bcdcSVivien Didelot return dsa_port_notify(dp, DSA_NOTIFIER_MDB_DEL, &info); 11813a9afea3SVivien Didelot } 11823a9afea3SVivien Didelot 11835e8a1e03SVladimir Oltean static int dsa_port_host_mdb_add(const struct dsa_port *dp, 11845e8a1e03SVladimir Oltean const struct switchdev_obj_port_mdb *mdb, 11855e8a1e03SVladimir Oltean struct dsa_db db) 1186b8e997c4SVladimir Oltean { 1187b8e997c4SVladimir Oltean struct dsa_notifier_mdb_info info = { 1188726816a1SVladimir Oltean .dp = dp, 1189b8e997c4SVladimir Oltean .mdb = mdb, 11905e8a1e03SVladimir Oltean .db = db, 1191b8e997c4SVladimir Oltean }; 1192b8e997c4SVladimir Oltean 1193c2693363SVladimir Oltean if (!dp->ds->fdb_isolation) 1194c2693363SVladimir Oltean info.db.bridge.num = 0; 1195c2693363SVladimir Oltean 1196b8e997c4SVladimir Oltean return dsa_port_notify(dp, DSA_NOTIFIER_HOST_MDB_ADD, &info); 1197b8e997c4SVladimir Oltean } 1198b8e997c4SVladimir Oltean 11995e8a1e03SVladimir Oltean int dsa_port_standalone_host_mdb_add(const struct dsa_port *dp, 1200b8e997c4SVladimir Oltean const struct switchdev_obj_port_mdb *mdb) 1201b8e997c4SVladimir Oltean { 12025e8a1e03SVladimir Oltean struct dsa_db db = { 12035e8a1e03SVladimir Oltean .type = DSA_DB_PORT, 12045e8a1e03SVladimir Oltean .dp = dp, 12055e8a1e03SVladimir Oltean }; 12065e8a1e03SVladimir Oltean 12075e8a1e03SVladimir Oltean return dsa_port_host_mdb_add(dp, mdb, db); 12085e8a1e03SVladimir Oltean } 12095e8a1e03SVladimir Oltean 12105e8a1e03SVladimir Oltean int dsa_port_bridge_host_mdb_add(const struct dsa_port *dp, 12115e8a1e03SVladimir Oltean const struct switchdev_obj_port_mdb *mdb) 12125e8a1e03SVladimir Oltean { 12138f6a19c0SVladimir Oltean struct net_device *master = dsa_port_to_master(dp); 12145e8a1e03SVladimir Oltean struct dsa_db db = { 12155e8a1e03SVladimir Oltean .type = DSA_DB_BRIDGE, 12165e8a1e03SVladimir Oltean .bridge = *dp->bridge, 12175e8a1e03SVladimir Oltean }; 12185e8a1e03SVladimir Oltean int err; 12195e8a1e03SVladimir Oltean 12208f6a19c0SVladimir Oltean err = dev_mc_add(master, mdb->addr); 12215e8a1e03SVladimir Oltean if (err) 12225e8a1e03SVladimir Oltean return err; 12235e8a1e03SVladimir Oltean 12245e8a1e03SVladimir Oltean return dsa_port_host_mdb_add(dp, mdb, db); 12255e8a1e03SVladimir Oltean } 12265e8a1e03SVladimir Oltean 12275e8a1e03SVladimir Oltean static int dsa_port_host_mdb_del(const struct dsa_port *dp, 12285e8a1e03SVladimir Oltean const struct switchdev_obj_port_mdb *mdb, 12295e8a1e03SVladimir Oltean struct dsa_db db) 12305e8a1e03SVladimir Oltean { 1231b8e997c4SVladimir Oltean struct dsa_notifier_mdb_info info = { 1232726816a1SVladimir Oltean .dp = dp, 1233b8e997c4SVladimir Oltean .mdb = mdb, 12345e8a1e03SVladimir Oltean .db = db, 12355e8a1e03SVladimir Oltean }; 12365e8a1e03SVladimir Oltean 12375e8a1e03SVladimir Oltean if (!dp->ds->fdb_isolation) 12385e8a1e03SVladimir Oltean info.db.bridge.num = 0; 12395e8a1e03SVladimir Oltean 12405e8a1e03SVladimir Oltean return dsa_port_notify(dp, DSA_NOTIFIER_HOST_MDB_DEL, &info); 12415e8a1e03SVladimir Oltean } 12425e8a1e03SVladimir Oltean 12435e8a1e03SVladimir Oltean int dsa_port_standalone_host_mdb_del(const struct dsa_port *dp, 12445e8a1e03SVladimir Oltean const struct switchdev_obj_port_mdb *mdb) 12455e8a1e03SVladimir Oltean { 12465e8a1e03SVladimir Oltean struct dsa_db db = { 12475e8a1e03SVladimir Oltean .type = DSA_DB_PORT, 12485e8a1e03SVladimir Oltean .dp = dp, 12495e8a1e03SVladimir Oltean }; 12505e8a1e03SVladimir Oltean 12515e8a1e03SVladimir Oltean return dsa_port_host_mdb_del(dp, mdb, db); 12525e8a1e03SVladimir Oltean } 12535e8a1e03SVladimir Oltean 12545e8a1e03SVladimir Oltean int dsa_port_bridge_host_mdb_del(const struct dsa_port *dp, 12555e8a1e03SVladimir Oltean const struct switchdev_obj_port_mdb *mdb) 12565e8a1e03SVladimir Oltean { 12578f6a19c0SVladimir Oltean struct net_device *master = dsa_port_to_master(dp); 12585e8a1e03SVladimir Oltean struct dsa_db db = { 1259c2693363SVladimir Oltean .type = DSA_DB_BRIDGE, 1260c2693363SVladimir Oltean .bridge = *dp->bridge, 1261b8e997c4SVladimir Oltean }; 126226ee7b06SVladimir Oltean int err; 126326ee7b06SVladimir Oltean 12648f6a19c0SVladimir Oltean err = dev_mc_del(master, mdb->addr); 126526ee7b06SVladimir Oltean if (err) 126626ee7b06SVladimir Oltean return err; 1267b8e997c4SVladimir Oltean 12685e8a1e03SVladimir Oltean return dsa_port_host_mdb_del(dp, mdb, db); 1269b8e997c4SVladimir Oltean } 1270b8e997c4SVladimir Oltean 1271076e7133SVivien Didelot int dsa_port_vlan_add(struct dsa_port *dp, 127231046a5fSVladimir Oltean const struct switchdev_obj_port_vlan *vlan, 127331046a5fSVladimir Oltean struct netlink_ext_ack *extack) 1274076e7133SVivien Didelot { 1275d0c627b8SVivien Didelot struct dsa_notifier_vlan_info info = { 1276726816a1SVladimir Oltean .dp = dp, 1277d0c627b8SVivien Didelot .vlan = vlan, 127831046a5fSVladimir Oltean .extack = extack, 1279d0c627b8SVivien Didelot }; 1280076e7133SVivien Didelot 1281d0c627b8SVivien Didelot return dsa_port_notify(dp, DSA_NOTIFIER_VLAN_ADD, &info); 1282076e7133SVivien Didelot } 1283076e7133SVivien Didelot 1284076e7133SVivien Didelot int dsa_port_vlan_del(struct dsa_port *dp, 1285076e7133SVivien Didelot const struct switchdev_obj_port_vlan *vlan) 1286076e7133SVivien Didelot { 1287d0c627b8SVivien Didelot struct dsa_notifier_vlan_info info = { 1288726816a1SVladimir Oltean .dp = dp, 1289d0c627b8SVivien Didelot .vlan = vlan, 1290d0c627b8SVivien Didelot }; 1291076e7133SVivien Didelot 1292d0c627b8SVivien Didelot return dsa_port_notify(dp, DSA_NOTIFIER_VLAN_DEL, &info); 1293076e7133SVivien Didelot } 129457ab1ca2SVivien Didelot 1295134ef238SVladimir Oltean int dsa_port_host_vlan_add(struct dsa_port *dp, 1296134ef238SVladimir Oltean const struct switchdev_obj_port_vlan *vlan, 1297134ef238SVladimir Oltean struct netlink_ext_ack *extack) 1298134ef238SVladimir Oltean { 12998f6a19c0SVladimir Oltean struct net_device *master = dsa_port_to_master(dp); 1300134ef238SVladimir Oltean struct dsa_notifier_vlan_info info = { 1301726816a1SVladimir Oltean .dp = dp, 1302134ef238SVladimir Oltean .vlan = vlan, 1303134ef238SVladimir Oltean .extack = extack, 1304134ef238SVladimir Oltean }; 1305134ef238SVladimir Oltean int err; 1306134ef238SVladimir Oltean 1307134ef238SVladimir Oltean err = dsa_port_notify(dp, DSA_NOTIFIER_HOST_VLAN_ADD, &info); 1308134ef238SVladimir Oltean if (err && err != -EOPNOTSUPP) 1309134ef238SVladimir Oltean return err; 1310134ef238SVladimir Oltean 13118f6a19c0SVladimir Oltean vlan_vid_add(master, htons(ETH_P_8021Q), vlan->vid); 1312134ef238SVladimir Oltean 1313134ef238SVladimir Oltean return err; 1314134ef238SVladimir Oltean } 1315134ef238SVladimir Oltean 1316134ef238SVladimir Oltean int dsa_port_host_vlan_del(struct dsa_port *dp, 1317134ef238SVladimir Oltean const struct switchdev_obj_port_vlan *vlan) 1318134ef238SVladimir Oltean { 13198f6a19c0SVladimir Oltean struct net_device *master = dsa_port_to_master(dp); 1320134ef238SVladimir Oltean struct dsa_notifier_vlan_info info = { 1321726816a1SVladimir Oltean .dp = dp, 1322134ef238SVladimir Oltean .vlan = vlan, 1323134ef238SVladimir Oltean }; 1324134ef238SVladimir Oltean int err; 1325134ef238SVladimir Oltean 1326134ef238SVladimir Oltean err = dsa_port_notify(dp, DSA_NOTIFIER_HOST_VLAN_DEL, &info); 1327134ef238SVladimir Oltean if (err && err != -EOPNOTSUPP) 1328134ef238SVladimir Oltean return err; 1329134ef238SVladimir Oltean 13308f6a19c0SVladimir Oltean vlan_vid_del(master, htons(ETH_P_8021Q), vlan->vid); 1331134ef238SVladimir Oltean 1332134ef238SVladimir Oltean return err; 1333134ef238SVladimir Oltean } 1334134ef238SVladimir Oltean 1335c595c433SHoratiu Vultur int dsa_port_mrp_add(const struct dsa_port *dp, 1336c595c433SHoratiu Vultur const struct switchdev_obj_mrp *mrp) 1337c595c433SHoratiu Vultur { 1338cad69019SVladimir Oltean struct dsa_switch *ds = dp->ds; 1339c595c433SHoratiu Vultur 1340cad69019SVladimir Oltean if (!ds->ops->port_mrp_add) 1341cad69019SVladimir Oltean return -EOPNOTSUPP; 1342cad69019SVladimir Oltean 1343cad69019SVladimir Oltean return ds->ops->port_mrp_add(ds, dp->index, mrp); 1344c595c433SHoratiu Vultur } 1345c595c433SHoratiu Vultur 1346c595c433SHoratiu Vultur int dsa_port_mrp_del(const struct dsa_port *dp, 1347c595c433SHoratiu Vultur const struct switchdev_obj_mrp *mrp) 1348c595c433SHoratiu Vultur { 1349cad69019SVladimir Oltean struct dsa_switch *ds = dp->ds; 1350c595c433SHoratiu Vultur 1351cad69019SVladimir Oltean if (!ds->ops->port_mrp_del) 1352cad69019SVladimir Oltean return -EOPNOTSUPP; 1353cad69019SVladimir Oltean 1354cad69019SVladimir Oltean return ds->ops->port_mrp_del(ds, dp->index, mrp); 1355c595c433SHoratiu Vultur } 1356c595c433SHoratiu Vultur 1357c595c433SHoratiu Vultur int dsa_port_mrp_add_ring_role(const struct dsa_port *dp, 1358c595c433SHoratiu Vultur const struct switchdev_obj_ring_role_mrp *mrp) 1359c595c433SHoratiu Vultur { 1360cad69019SVladimir Oltean struct dsa_switch *ds = dp->ds; 1361c595c433SHoratiu Vultur 1362cad69019SVladimir Oltean if (!ds->ops->port_mrp_add_ring_role) 1363cad69019SVladimir Oltean return -EOPNOTSUPP; 1364cad69019SVladimir Oltean 1365cad69019SVladimir Oltean return ds->ops->port_mrp_add_ring_role(ds, dp->index, mrp); 1366c595c433SHoratiu Vultur } 1367c595c433SHoratiu Vultur 1368c595c433SHoratiu Vultur int dsa_port_mrp_del_ring_role(const struct dsa_port *dp, 1369c595c433SHoratiu Vultur const struct switchdev_obj_ring_role_mrp *mrp) 1370c595c433SHoratiu Vultur { 1371cad69019SVladimir Oltean struct dsa_switch *ds = dp->ds; 1372c595c433SHoratiu Vultur 1373cad69019SVladimir Oltean if (!ds->ops->port_mrp_del_ring_role) 1374cad69019SVladimir Oltean return -EOPNOTSUPP; 1375cad69019SVladimir Oltean 1376cad69019SVladimir Oltean return ds->ops->port_mrp_del_ring_role(ds, dp->index, mrp); 1377c595c433SHoratiu Vultur } 1378c595c433SHoratiu Vultur 137995f510d0SVladimir Oltean static int dsa_port_assign_master(struct dsa_port *dp, 138095f510d0SVladimir Oltean struct net_device *master, 138195f510d0SVladimir Oltean struct netlink_ext_ack *extack, 138295f510d0SVladimir Oltean bool fail_on_err) 138395f510d0SVladimir Oltean { 138495f510d0SVladimir Oltean struct dsa_switch *ds = dp->ds; 138595f510d0SVladimir Oltean int port = dp->index, err; 138695f510d0SVladimir Oltean 138795f510d0SVladimir Oltean err = ds->ops->port_change_master(ds, port, master, extack); 138895f510d0SVladimir Oltean if (err && !fail_on_err) 138995f510d0SVladimir Oltean dev_err(ds->dev, "port %d failed to assign master %s: %pe\n", 139095f510d0SVladimir Oltean port, master->name, ERR_PTR(err)); 139195f510d0SVladimir Oltean 139295f510d0SVladimir Oltean if (err && fail_on_err) 139395f510d0SVladimir Oltean return err; 139495f510d0SVladimir Oltean 139595f510d0SVladimir Oltean dp->cpu_dp = master->dsa_ptr; 139695f510d0SVladimir Oltean 139795f510d0SVladimir Oltean return 0; 139895f510d0SVladimir Oltean } 139995f510d0SVladimir Oltean 140095f510d0SVladimir Oltean /* Change the dp->cpu_dp affinity for a user port. Note that both cross-chip 140195f510d0SVladimir Oltean * notifiers and drivers have implicit assumptions about user-to-CPU-port 140295f510d0SVladimir Oltean * mappings, so we unfortunately cannot delay the deletion of the objects 140395f510d0SVladimir Oltean * (switchdev, standalone addresses, standalone VLANs) on the old CPU port 140495f510d0SVladimir Oltean * until the new CPU port has been set up. So we need to completely tear down 140595f510d0SVladimir Oltean * the old CPU port before changing it, and restore it on errors during the 140695f510d0SVladimir Oltean * bringup of the new one. 140795f510d0SVladimir Oltean */ 140895f510d0SVladimir Oltean int dsa_port_change_master(struct dsa_port *dp, struct net_device *master, 140995f510d0SVladimir Oltean struct netlink_ext_ack *extack) 141095f510d0SVladimir Oltean { 141195f510d0SVladimir Oltean struct net_device *bridge_dev = dsa_port_bridge_dev_get(dp); 141295f510d0SVladimir Oltean struct net_device *old_master = dsa_port_to_master(dp); 141395f510d0SVladimir Oltean struct net_device *dev = dp->slave; 141495f510d0SVladimir Oltean struct dsa_switch *ds = dp->ds; 141595f510d0SVladimir Oltean bool vlan_filtering; 141695f510d0SVladimir Oltean int err, tmp; 141795f510d0SVladimir Oltean 141895f510d0SVladimir Oltean /* Bridges may hold host FDB, MDB and VLAN objects. These need to be 141995f510d0SVladimir Oltean * migrated, so dynamically unoffload and later reoffload the bridge 142095f510d0SVladimir Oltean * port. 142195f510d0SVladimir Oltean */ 142295f510d0SVladimir Oltean if (bridge_dev) { 142395f510d0SVladimir Oltean dsa_port_pre_bridge_leave(dp, bridge_dev); 142495f510d0SVladimir Oltean dsa_port_bridge_leave(dp, bridge_dev); 142595f510d0SVladimir Oltean } 142695f510d0SVladimir Oltean 142795f510d0SVladimir Oltean /* The port might still be VLAN filtering even if it's no longer 142895f510d0SVladimir Oltean * under a bridge, either due to ds->vlan_filtering_is_global or 142995f510d0SVladimir Oltean * ds->needs_standalone_vlan_filtering. In turn this means VLANs 143095f510d0SVladimir Oltean * on the CPU port. 143195f510d0SVladimir Oltean */ 143295f510d0SVladimir Oltean vlan_filtering = dsa_port_is_vlan_filtering(dp); 143395f510d0SVladimir Oltean if (vlan_filtering) { 143495f510d0SVladimir Oltean err = dsa_slave_manage_vlan_filtering(dev, false); 143595f510d0SVladimir Oltean if (err) { 143695f510d0SVladimir Oltean NL_SET_ERR_MSG_MOD(extack, 143795f510d0SVladimir Oltean "Failed to remove standalone VLANs"); 143895f510d0SVladimir Oltean goto rewind_old_bridge; 143995f510d0SVladimir Oltean } 144095f510d0SVladimir Oltean } 144195f510d0SVladimir Oltean 144295f510d0SVladimir Oltean /* Standalone addresses, and addresses of upper interfaces like 144395f510d0SVladimir Oltean * VLAN, LAG, HSR need to be migrated. 144495f510d0SVladimir Oltean */ 144595f510d0SVladimir Oltean dsa_slave_unsync_ha(dev); 144695f510d0SVladimir Oltean 144795f510d0SVladimir Oltean err = dsa_port_assign_master(dp, master, extack, true); 144895f510d0SVladimir Oltean if (err) 144995f510d0SVladimir Oltean goto rewind_old_addrs; 145095f510d0SVladimir Oltean 145195f510d0SVladimir Oltean dsa_slave_sync_ha(dev); 145295f510d0SVladimir Oltean 145395f510d0SVladimir Oltean if (vlan_filtering) { 145495f510d0SVladimir Oltean err = dsa_slave_manage_vlan_filtering(dev, true); 145595f510d0SVladimir Oltean if (err) { 145695f510d0SVladimir Oltean NL_SET_ERR_MSG_MOD(extack, 145795f510d0SVladimir Oltean "Failed to restore standalone VLANs"); 145895f510d0SVladimir Oltean goto rewind_new_addrs; 145995f510d0SVladimir Oltean } 146095f510d0SVladimir Oltean } 146195f510d0SVladimir Oltean 146295f510d0SVladimir Oltean if (bridge_dev) { 146395f510d0SVladimir Oltean err = dsa_port_bridge_join(dp, bridge_dev, extack); 146495f510d0SVladimir Oltean if (err && err == -EOPNOTSUPP) { 146595f510d0SVladimir Oltean NL_SET_ERR_MSG_MOD(extack, 146695f510d0SVladimir Oltean "Failed to reoffload bridge"); 146795f510d0SVladimir Oltean goto rewind_new_vlan; 146895f510d0SVladimir Oltean } 146995f510d0SVladimir Oltean } 147095f510d0SVladimir Oltean 147195f510d0SVladimir Oltean return 0; 147295f510d0SVladimir Oltean 147395f510d0SVladimir Oltean rewind_new_vlan: 147495f510d0SVladimir Oltean if (vlan_filtering) 147595f510d0SVladimir Oltean dsa_slave_manage_vlan_filtering(dev, false); 147695f510d0SVladimir Oltean 147795f510d0SVladimir Oltean rewind_new_addrs: 147895f510d0SVladimir Oltean dsa_slave_unsync_ha(dev); 147995f510d0SVladimir Oltean 148095f510d0SVladimir Oltean dsa_port_assign_master(dp, old_master, NULL, false); 148195f510d0SVladimir Oltean 148295f510d0SVladimir Oltean /* Restore the objects on the old CPU port */ 148395f510d0SVladimir Oltean rewind_old_addrs: 148495f510d0SVladimir Oltean dsa_slave_sync_ha(dev); 148595f510d0SVladimir Oltean 148695f510d0SVladimir Oltean if (vlan_filtering) { 148795f510d0SVladimir Oltean tmp = dsa_slave_manage_vlan_filtering(dev, true); 148895f510d0SVladimir Oltean if (tmp) { 148995f510d0SVladimir Oltean dev_err(ds->dev, 149095f510d0SVladimir Oltean "port %d failed to restore standalone VLANs: %pe\n", 149195f510d0SVladimir Oltean dp->index, ERR_PTR(tmp)); 149295f510d0SVladimir Oltean } 149395f510d0SVladimir Oltean } 149495f510d0SVladimir Oltean 149595f510d0SVladimir Oltean rewind_old_bridge: 149695f510d0SVladimir Oltean if (bridge_dev) { 149795f510d0SVladimir Oltean tmp = dsa_port_bridge_join(dp, bridge_dev, extack); 149895f510d0SVladimir Oltean if (tmp) { 149995f510d0SVladimir Oltean dev_err(ds->dev, 150095f510d0SVladimir Oltean "port %d failed to rejoin bridge %s: %pe\n", 150195f510d0SVladimir Oltean dp->index, bridge_dev->name, ERR_PTR(tmp)); 150295f510d0SVladimir Oltean } 150395f510d0SVladimir Oltean } 150495f510d0SVladimir Oltean 150595f510d0SVladimir Oltean return err; 150695f510d0SVladimir Oltean } 150795f510d0SVladimir Oltean 150853da0ebaSVladimir Oltean void dsa_port_set_tag_protocol(struct dsa_port *cpu_dp, 150953da0ebaSVladimir Oltean const struct dsa_device_ops *tag_ops) 151053da0ebaSVladimir Oltean { 151153da0ebaSVladimir Oltean cpu_dp->rcv = tag_ops->rcv; 151253da0ebaSVladimir Oltean cpu_dp->tag_ops = tag_ops; 151353da0ebaSVladimir Oltean } 151453da0ebaSVladimir Oltean 15156207a78cSFlorian Fainelli static struct phy_device *dsa_port_get_phy_device(struct dsa_port *dp) 15166207a78cSFlorian Fainelli { 15176207a78cSFlorian Fainelli struct device_node *phy_dn; 15186207a78cSFlorian Fainelli struct phy_device *phydev; 15196207a78cSFlorian Fainelli 15206207a78cSFlorian Fainelli phy_dn = of_parse_phandle(dp->dn, "phy-handle", 0); 15216207a78cSFlorian Fainelli if (!phy_dn) 15226207a78cSFlorian Fainelli return NULL; 15236207a78cSFlorian Fainelli 15246207a78cSFlorian Fainelli phydev = of_phy_find_device(phy_dn); 15256207a78cSFlorian Fainelli if (!phydev) { 15266207a78cSFlorian Fainelli of_node_put(phy_dn); 15276207a78cSFlorian Fainelli return ERR_PTR(-EPROBE_DEFER); 15286207a78cSFlorian Fainelli } 15296207a78cSFlorian Fainelli 15309919a363SWen Yang of_node_put(phy_dn); 15316207a78cSFlorian Fainelli return phydev; 15326207a78cSFlorian Fainelli } 15336207a78cSFlorian Fainelli 15348ae67496SFlorian Fainelli static void dsa_port_phylink_validate(struct phylink_config *config, 153577373d49SIoana Ciornei unsigned long *supported, 153677373d49SIoana Ciornei struct phylink_link_state *state) 153777373d49SIoana Ciornei { 153877373d49SIoana Ciornei struct dsa_port *dp = container_of(config, struct dsa_port, pl_config); 153977373d49SIoana Ciornei struct dsa_switch *ds = dp->ds; 154077373d49SIoana Ciornei 15415938bce4SRussell King (Oracle) if (!ds->ops->phylink_validate) { 15425938bce4SRussell King (Oracle) if (config->mac_capabilities) 15435938bce4SRussell King (Oracle) phylink_generic_validate(config, supported, state); 154477373d49SIoana Ciornei return; 15455938bce4SRussell King (Oracle) } 154677373d49SIoana Ciornei 154777373d49SIoana Ciornei ds->ops->phylink_validate(ds, dp->index, supported, state); 154877373d49SIoana Ciornei } 154977373d49SIoana Ciornei 15508ae67496SFlorian Fainelli static void dsa_port_phylink_mac_pcs_get_state(struct phylink_config *config, 155177373d49SIoana Ciornei struct phylink_link_state *state) 155277373d49SIoana Ciornei { 155377373d49SIoana Ciornei struct dsa_port *dp = container_of(config, struct dsa_port, pl_config); 155477373d49SIoana Ciornei struct dsa_switch *ds = dp->ds; 155587615c96SRussell King int err; 155677373d49SIoana Ciornei 1557d46b7e4fSRussell King /* Only called for inband modes */ 1558d46b7e4fSRussell King if (!ds->ops->phylink_mac_link_state) { 1559d46b7e4fSRussell King state->link = 0; 1560d46b7e4fSRussell King return; 156177373d49SIoana Ciornei } 1562d46b7e4fSRussell King 156387615c96SRussell King err = ds->ops->phylink_mac_link_state(ds, dp->index, state); 156487615c96SRussell King if (err < 0) { 156587615c96SRussell King dev_err(ds->dev, "p%d: phylink_mac_link_state() failed: %d\n", 156687615c96SRussell King dp->index, err); 1567d46b7e4fSRussell King state->link = 0; 1568d46b7e4fSRussell King } 156987615c96SRussell King } 157077373d49SIoana Ciornei 1571bde01822SRussell King (Oracle) static struct phylink_pcs * 1572bde01822SRussell King (Oracle) dsa_port_phylink_mac_select_pcs(struct phylink_config *config, 1573bde01822SRussell King (Oracle) phy_interface_t interface) 1574bde01822SRussell King (Oracle) { 1575bde01822SRussell King (Oracle) struct dsa_port *dp = container_of(config, struct dsa_port, pl_config); 157610544570SRussell King (Oracle) struct phylink_pcs *pcs = ERR_PTR(-EOPNOTSUPP); 1577bde01822SRussell King (Oracle) struct dsa_switch *ds = dp->ds; 1578bde01822SRussell King (Oracle) 1579bde01822SRussell King (Oracle) if (ds->ops->phylink_mac_select_pcs) 1580bde01822SRussell King (Oracle) pcs = ds->ops->phylink_mac_select_pcs(ds, dp->index, interface); 1581bde01822SRussell King (Oracle) 1582bde01822SRussell King (Oracle) return pcs; 1583bde01822SRussell King (Oracle) } 1584bde01822SRussell King (Oracle) 15858ae67496SFlorian Fainelli static void dsa_port_phylink_mac_config(struct phylink_config *config, 158677373d49SIoana Ciornei unsigned int mode, 158777373d49SIoana Ciornei const struct phylink_link_state *state) 158877373d49SIoana Ciornei { 158977373d49SIoana Ciornei struct dsa_port *dp = container_of(config, struct dsa_port, pl_config); 159077373d49SIoana Ciornei struct dsa_switch *ds = dp->ds; 159177373d49SIoana Ciornei 159277373d49SIoana Ciornei if (!ds->ops->phylink_mac_config) 159377373d49SIoana Ciornei return; 159477373d49SIoana Ciornei 159577373d49SIoana Ciornei ds->ops->phylink_mac_config(ds, dp->index, mode, state); 159677373d49SIoana Ciornei } 159777373d49SIoana Ciornei 15988ae67496SFlorian Fainelli static void dsa_port_phylink_mac_an_restart(struct phylink_config *config) 159977373d49SIoana Ciornei { 160077373d49SIoana Ciornei struct dsa_port *dp = container_of(config, struct dsa_port, pl_config); 160177373d49SIoana Ciornei struct dsa_switch *ds = dp->ds; 160277373d49SIoana Ciornei 160377373d49SIoana Ciornei if (!ds->ops->phylink_mac_an_restart) 160477373d49SIoana Ciornei return; 160577373d49SIoana Ciornei 160677373d49SIoana Ciornei ds->ops->phylink_mac_an_restart(ds, dp->index); 160777373d49SIoana Ciornei } 160877373d49SIoana Ciornei 16098ae67496SFlorian Fainelli static void dsa_port_phylink_mac_link_down(struct phylink_config *config, 161077373d49SIoana Ciornei unsigned int mode, 161177373d49SIoana Ciornei phy_interface_t interface) 161277373d49SIoana Ciornei { 161377373d49SIoana Ciornei struct dsa_port *dp = container_of(config, struct dsa_port, pl_config); 16140e279218SIoana Ciornei struct phy_device *phydev = NULL; 161577373d49SIoana Ciornei struct dsa_switch *ds = dp->ds; 161677373d49SIoana Ciornei 161757d77986SVladimir Oltean if (dsa_port_is_user(dp)) 16180e279218SIoana Ciornei phydev = dp->slave->phydev; 16190e279218SIoana Ciornei 162077373d49SIoana Ciornei if (!ds->ops->phylink_mac_link_down) { 16210e279218SIoana Ciornei if (ds->ops->adjust_link && phydev) 16220e279218SIoana Ciornei ds->ops->adjust_link(ds, dp->index, phydev); 162377373d49SIoana Ciornei return; 162477373d49SIoana Ciornei } 162577373d49SIoana Ciornei 162677373d49SIoana Ciornei ds->ops->phylink_mac_link_down(ds, dp->index, mode, interface); 162777373d49SIoana Ciornei } 162877373d49SIoana Ciornei 16298ae67496SFlorian Fainelli static void dsa_port_phylink_mac_link_up(struct phylink_config *config, 163091a208f2SRussell King struct phy_device *phydev, 163177373d49SIoana Ciornei unsigned int mode, 163277373d49SIoana Ciornei phy_interface_t interface, 163391a208f2SRussell King int speed, int duplex, 163491a208f2SRussell King bool tx_pause, bool rx_pause) 163577373d49SIoana Ciornei { 163677373d49SIoana Ciornei struct dsa_port *dp = container_of(config, struct dsa_port, pl_config); 163777373d49SIoana Ciornei struct dsa_switch *ds = dp->ds; 163877373d49SIoana Ciornei 163977373d49SIoana Ciornei if (!ds->ops->phylink_mac_link_up) { 16400e279218SIoana Ciornei if (ds->ops->adjust_link && phydev) 16410e279218SIoana Ciornei ds->ops->adjust_link(ds, dp->index, phydev); 164277373d49SIoana Ciornei return; 164377373d49SIoana Ciornei } 164477373d49SIoana Ciornei 16455b502a7bSRussell King ds->ops->phylink_mac_link_up(ds, dp->index, mode, interface, phydev, 16465b502a7bSRussell King speed, duplex, tx_pause, rx_pause); 164777373d49SIoana Ciornei } 164877373d49SIoana Ciornei 164921bd64bdSRussell King (Oracle) static const struct phylink_mac_ops dsa_port_phylink_mac_ops = { 165077373d49SIoana Ciornei .validate = dsa_port_phylink_validate, 1651bde01822SRussell King (Oracle) .mac_select_pcs = dsa_port_phylink_mac_select_pcs, 1652d46b7e4fSRussell King .mac_pcs_get_state = dsa_port_phylink_mac_pcs_get_state, 165377373d49SIoana Ciornei .mac_config = dsa_port_phylink_mac_config, 165477373d49SIoana Ciornei .mac_an_restart = dsa_port_phylink_mac_an_restart, 165577373d49SIoana Ciornei .mac_link_down = dsa_port_phylink_mac_link_down, 165677373d49SIoana Ciornei .mac_link_up = dsa_port_phylink_mac_link_up, 165777373d49SIoana Ciornei }; 165877373d49SIoana Ciornei 165921bd64bdSRussell King (Oracle) int dsa_port_phylink_create(struct dsa_port *dp) 166021bd64bdSRussell King (Oracle) { 166121bd64bdSRussell King (Oracle) struct dsa_switch *ds = dp->ds; 166221bd64bdSRussell King (Oracle) phy_interface_t mode; 166321bd64bdSRussell King (Oracle) int err; 166421bd64bdSRussell King (Oracle) 166521bd64bdSRussell King (Oracle) err = of_get_phy_mode(dp->dn, &mode); 166621bd64bdSRussell King (Oracle) if (err) 166721bd64bdSRussell King (Oracle) mode = PHY_INTERFACE_MODE_NA; 166821bd64bdSRussell King (Oracle) 16690a9f0794SRussell King (Oracle) /* Presence of phylink_mac_link_state or phylink_mac_an_restart is 16700a9f0794SRussell King (Oracle) * an indicator of a legacy phylink driver. 16710a9f0794SRussell King (Oracle) */ 16720a9f0794SRussell King (Oracle) if (ds->ops->phylink_mac_link_state || 16730a9f0794SRussell King (Oracle) ds->ops->phylink_mac_an_restart) 16740a9f0794SRussell King (Oracle) dp->pl_config.legacy_pre_march2020 = true; 16750a9f0794SRussell King (Oracle) 1676072eea6cSRussell King (Oracle) if (ds->ops->phylink_get_caps) 1677072eea6cSRussell King (Oracle) ds->ops->phylink_get_caps(ds, dp->index, &dp->pl_config); 167821bd64bdSRussell King (Oracle) 167921bd64bdSRussell King (Oracle) dp->pl = phylink_create(&dp->pl_config, of_fwnode_handle(dp->dn), 168021bd64bdSRussell King (Oracle) mode, &dsa_port_phylink_mac_ops); 168121bd64bdSRussell King (Oracle) if (IS_ERR(dp->pl)) { 168221bd64bdSRussell King (Oracle) pr_err("error creating PHYLINK: %ld\n", PTR_ERR(dp->pl)); 168321bd64bdSRussell King (Oracle) return PTR_ERR(dp->pl); 168421bd64bdSRussell King (Oracle) } 168521bd64bdSRussell King (Oracle) 168621bd64bdSRussell King (Oracle) return 0; 168721bd64bdSRussell King (Oracle) } 168821bd64bdSRussell King (Oracle) 1689770375ffSVladimir Oltean static int dsa_shared_port_setup_phy_of(struct dsa_port *dp, bool enable) 169033615367SSebastian Reichel { 169133615367SSebastian Reichel struct dsa_switch *ds = dp->ds; 169233615367SSebastian Reichel struct phy_device *phydev; 169333615367SSebastian Reichel int port = dp->index; 169433615367SSebastian Reichel int err = 0; 169533615367SSebastian Reichel 16966207a78cSFlorian Fainelli phydev = dsa_port_get_phy_device(dp); 16976207a78cSFlorian Fainelli if (!phydev) 169833615367SSebastian Reichel return 0; 169933615367SSebastian Reichel 17006207a78cSFlorian Fainelli if (IS_ERR(phydev)) 17016207a78cSFlorian Fainelli return PTR_ERR(phydev); 170233615367SSebastian Reichel 170333615367SSebastian Reichel if (enable) { 170433615367SSebastian Reichel err = genphy_resume(phydev); 170533615367SSebastian Reichel if (err < 0) 170633615367SSebastian Reichel goto err_put_dev; 170733615367SSebastian Reichel 170833615367SSebastian Reichel err = genphy_read_status(phydev); 170933615367SSebastian Reichel if (err < 0) 171033615367SSebastian Reichel goto err_put_dev; 171133615367SSebastian Reichel } else { 171233615367SSebastian Reichel err = genphy_suspend(phydev); 171333615367SSebastian Reichel if (err < 0) 171433615367SSebastian Reichel goto err_put_dev; 171533615367SSebastian Reichel } 171633615367SSebastian Reichel 171733615367SSebastian Reichel if (ds->ops->adjust_link) 171833615367SSebastian Reichel ds->ops->adjust_link(ds, port, phydev); 171933615367SSebastian Reichel 172033615367SSebastian Reichel dev_dbg(ds->dev, "enabled port's phy: %s", phydev_name(phydev)); 172133615367SSebastian Reichel 172233615367SSebastian Reichel err_put_dev: 172333615367SSebastian Reichel put_device(&phydev->mdio.dev); 172433615367SSebastian Reichel return err; 172533615367SSebastian Reichel } 172633615367SSebastian Reichel 1727770375ffSVladimir Oltean static int dsa_shared_port_fixed_link_register_of(struct dsa_port *dp) 172857ab1ca2SVivien Didelot { 172957ab1ca2SVivien Didelot struct device_node *dn = dp->dn; 173057ab1ca2SVivien Didelot struct dsa_switch *ds = dp->ds; 173157ab1ca2SVivien Didelot struct phy_device *phydev; 173257ab1ca2SVivien Didelot int port = dp->index; 17330c65b2b9SAndrew Lunn phy_interface_t mode; 173457ab1ca2SVivien Didelot int err; 173557ab1ca2SVivien Didelot 173657ab1ca2SVivien Didelot err = of_phy_register_fixed_link(dn); 173757ab1ca2SVivien Didelot if (err) { 173857ab1ca2SVivien Didelot dev_err(ds->dev, 173957ab1ca2SVivien Didelot "failed to register the fixed PHY of port %d\n", 174057ab1ca2SVivien Didelot port); 174157ab1ca2SVivien Didelot return err; 174257ab1ca2SVivien Didelot } 174357ab1ca2SVivien Didelot 174457ab1ca2SVivien Didelot phydev = of_phy_find_device(dn); 174557ab1ca2SVivien Didelot 17460c65b2b9SAndrew Lunn err = of_get_phy_mode(dn, &mode); 17470c65b2b9SAndrew Lunn if (err) 174857ab1ca2SVivien Didelot mode = PHY_INTERFACE_MODE_NA; 174957ab1ca2SVivien Didelot phydev->interface = mode; 175057ab1ca2SVivien Didelot 175157ab1ca2SVivien Didelot genphy_read_status(phydev); 175257ab1ca2SVivien Didelot 175357ab1ca2SVivien Didelot if (ds->ops->adjust_link) 175457ab1ca2SVivien Didelot ds->ops->adjust_link(ds, port, phydev); 175557ab1ca2SVivien Didelot 175657ab1ca2SVivien Didelot put_device(&phydev->mdio.dev); 175757ab1ca2SVivien Didelot 175857ab1ca2SVivien Didelot return 0; 175957ab1ca2SVivien Didelot } 176057ab1ca2SVivien Didelot 1761770375ffSVladimir Oltean static int dsa_shared_port_phylink_register(struct dsa_port *dp) 17620e279218SIoana Ciornei { 17630e279218SIoana Ciornei struct dsa_switch *ds = dp->ds; 17640e279218SIoana Ciornei struct device_node *port_dn = dp->dn; 17650c65b2b9SAndrew Lunn int err; 17660e279218SIoana Ciornei 17670e279218SIoana Ciornei dp->pl_config.dev = ds->dev; 17680e279218SIoana Ciornei dp->pl_config.type = PHYLINK_DEV; 17690e279218SIoana Ciornei 177021bd64bdSRussell King (Oracle) err = dsa_port_phylink_create(dp); 177121bd64bdSRussell King (Oracle) if (err) 177221bd64bdSRussell King (Oracle) return err; 17730e279218SIoana Ciornei 17740e279218SIoana Ciornei err = phylink_of_phy_connect(dp->pl, port_dn, 0); 17752131fba5SFlorian Fainelli if (err && err != -ENODEV) { 17760e279218SIoana Ciornei pr_err("could not attach to PHY: %d\n", err); 17770e279218SIoana Ciornei goto err_phy_connect; 17780e279218SIoana Ciornei } 17790e279218SIoana Ciornei 17800e279218SIoana Ciornei return 0; 17810e279218SIoana Ciornei 17820e279218SIoana Ciornei err_phy_connect: 17830e279218SIoana Ciornei phylink_destroy(dp->pl); 17840e279218SIoana Ciornei return err; 17850e279218SIoana Ciornei } 17860e279218SIoana Ciornei 1787e09e9873SVladimir Oltean /* During the initial DSA driver migration to OF, port nodes were sometimes 1788e09e9873SVladimir Oltean * added to device trees with no indication of how they should operate from a 1789e09e9873SVladimir Oltean * link management perspective (phy-handle, fixed-link, etc). Additionally, the 1790e09e9873SVladimir Oltean * phy-mode may be absent. The interpretation of these port OF nodes depends on 1791e09e9873SVladimir Oltean * their type. 1792e09e9873SVladimir Oltean * 1793e09e9873SVladimir Oltean * User ports with no phy-handle or fixed-link are expected to connect to an 1794e09e9873SVladimir Oltean * internal PHY located on the ds->slave_mii_bus at an MDIO address equal to 1795e09e9873SVladimir Oltean * the port number. This description is still actively supported. 1796e09e9873SVladimir Oltean * 1797e09e9873SVladimir Oltean * Shared (CPU and DSA) ports with no phy-handle or fixed-link are expected to 1798e09e9873SVladimir Oltean * operate at the maximum speed that their phy-mode is capable of. If the 1799e09e9873SVladimir Oltean * phy-mode is absent, they are expected to operate using the phy-mode 1800e09e9873SVladimir Oltean * supported by the port that gives the highest link speed. It is unspecified 1801e09e9873SVladimir Oltean * if the port should use flow control or not, half duplex or full duplex, or 1802e09e9873SVladimir Oltean * if the phy-mode is a SERDES link, whether in-band autoneg is expected to be 1803e09e9873SVladimir Oltean * enabled or not. 1804e09e9873SVladimir Oltean * 1805e09e9873SVladimir Oltean * In the latter case of shared ports, omitting the link management description 1806e09e9873SVladimir Oltean * from the firmware node is deprecated and strongly discouraged. DSA uses 1807e09e9873SVladimir Oltean * phylink, which rejects the firmware nodes of these ports for lacking 1808e09e9873SVladimir Oltean * required properties. 1809e09e9873SVladimir Oltean * 1810e09e9873SVladimir Oltean * For switches in this table, DSA will skip enforcing validation and will 1811e09e9873SVladimir Oltean * later omit registering a phylink instance for the shared ports, if they lack 1812e09e9873SVladimir Oltean * a fixed-link, a phy-handle, or a managed = "in-band-status" property. 1813e09e9873SVladimir Oltean * It becomes the responsibility of the driver to ensure that these ports 1814e09e9873SVladimir Oltean * operate at the maximum speed (whatever this means) and will interoperate 1815e09e9873SVladimir Oltean * with the DSA master or other cascade port, since phylink methods will not be 1816e09e9873SVladimir Oltean * invoked for them. 1817e09e9873SVladimir Oltean * 1818e09e9873SVladimir Oltean * If you are considering expanding this table for newly introduced switches, 1819e09e9873SVladimir Oltean * think again. It is OK to remove switches from this table if there aren't DT 1820e09e9873SVladimir Oltean * blobs in circulation which rely on defaulting the shared ports. 1821e09e9873SVladimir Oltean */ 1822e09e9873SVladimir Oltean static const char * const dsa_switches_apply_workarounds[] = { 1823e09e9873SVladimir Oltean #if IS_ENABLED(CONFIG_NET_DSA_XRS700X) 1824e09e9873SVladimir Oltean "arrow,xrs7003e", 1825e09e9873SVladimir Oltean "arrow,xrs7003f", 1826e09e9873SVladimir Oltean "arrow,xrs7004e", 1827e09e9873SVladimir Oltean "arrow,xrs7004f", 1828e09e9873SVladimir Oltean #endif 1829e09e9873SVladimir Oltean #if IS_ENABLED(CONFIG_B53) 1830e09e9873SVladimir Oltean "brcm,bcm5325", 1831e09e9873SVladimir Oltean "brcm,bcm53115", 1832e09e9873SVladimir Oltean "brcm,bcm53125", 1833e09e9873SVladimir Oltean "brcm,bcm53128", 1834e09e9873SVladimir Oltean "brcm,bcm5365", 1835e09e9873SVladimir Oltean "brcm,bcm5389", 1836e09e9873SVladimir Oltean "brcm,bcm5395", 1837e09e9873SVladimir Oltean "brcm,bcm5397", 1838e09e9873SVladimir Oltean "brcm,bcm5398", 1839e09e9873SVladimir Oltean "brcm,bcm53010-srab", 1840e09e9873SVladimir Oltean "brcm,bcm53011-srab", 1841e09e9873SVladimir Oltean "brcm,bcm53012-srab", 1842e09e9873SVladimir Oltean "brcm,bcm53018-srab", 1843e09e9873SVladimir Oltean "brcm,bcm53019-srab", 1844e09e9873SVladimir Oltean "brcm,bcm5301x-srab", 1845e09e9873SVladimir Oltean "brcm,bcm11360-srab", 1846e09e9873SVladimir Oltean "brcm,bcm58522-srab", 1847e09e9873SVladimir Oltean "brcm,bcm58525-srab", 1848e09e9873SVladimir Oltean "brcm,bcm58535-srab", 1849e09e9873SVladimir Oltean "brcm,bcm58622-srab", 1850e09e9873SVladimir Oltean "brcm,bcm58623-srab", 1851e09e9873SVladimir Oltean "brcm,bcm58625-srab", 1852e09e9873SVladimir Oltean "brcm,bcm88312-srab", 1853e09e9873SVladimir Oltean "brcm,cygnus-srab", 1854e09e9873SVladimir Oltean "brcm,nsp-srab", 1855e09e9873SVladimir Oltean "brcm,omega-srab", 1856e09e9873SVladimir Oltean "brcm,bcm3384-switch", 1857e09e9873SVladimir Oltean "brcm,bcm6328-switch", 1858e09e9873SVladimir Oltean "brcm,bcm6368-switch", 1859e09e9873SVladimir Oltean "brcm,bcm63xx-switch", 1860e09e9873SVladimir Oltean #endif 1861e09e9873SVladimir Oltean #if IS_ENABLED(CONFIG_NET_DSA_BCM_SF2) 1862e09e9873SVladimir Oltean "brcm,bcm7445-switch-v4.0", 1863e09e9873SVladimir Oltean "brcm,bcm7278-switch-v4.0", 1864e09e9873SVladimir Oltean "brcm,bcm7278-switch-v4.8", 1865e09e9873SVladimir Oltean #endif 1866e09e9873SVladimir Oltean #if IS_ENABLED(CONFIG_NET_DSA_LANTIQ_GSWIP) 1867e09e9873SVladimir Oltean "lantiq,xrx200-gswip", 1868e09e9873SVladimir Oltean "lantiq,xrx300-gswip", 1869e09e9873SVladimir Oltean "lantiq,xrx330-gswip", 1870e09e9873SVladimir Oltean #endif 1871e09e9873SVladimir Oltean #if IS_ENABLED(CONFIG_NET_DSA_MV88E6060) 1872e09e9873SVladimir Oltean "marvell,mv88e6060", 1873e09e9873SVladimir Oltean #endif 1874e09e9873SVladimir Oltean #if IS_ENABLED(CONFIG_NET_DSA_MV88E6XXX) 1875e09e9873SVladimir Oltean "marvell,mv88e6085", 1876e09e9873SVladimir Oltean "marvell,mv88e6190", 1877e09e9873SVladimir Oltean "marvell,mv88e6250", 1878e09e9873SVladimir Oltean #endif 1879e09e9873SVladimir Oltean #if IS_ENABLED(CONFIG_NET_DSA_MICROCHIP_KSZ_COMMON) 1880e09e9873SVladimir Oltean "microchip,ksz8765", 1881e09e9873SVladimir Oltean "microchip,ksz8794", 1882e09e9873SVladimir Oltean "microchip,ksz8795", 1883e09e9873SVladimir Oltean "microchip,ksz8863", 1884e09e9873SVladimir Oltean "microchip,ksz8873", 1885e09e9873SVladimir Oltean "microchip,ksz9477", 1886e09e9873SVladimir Oltean "microchip,ksz9897", 1887e09e9873SVladimir Oltean "microchip,ksz9893", 1888e09e9873SVladimir Oltean "microchip,ksz9563", 1889e09e9873SVladimir Oltean "microchip,ksz8563", 1890e09e9873SVladimir Oltean "microchip,ksz9567", 1891e09e9873SVladimir Oltean #endif 1892e09e9873SVladimir Oltean #if IS_ENABLED(CONFIG_NET_DSA_SMSC_LAN9303_MDIO) 1893e09e9873SVladimir Oltean "smsc,lan9303-mdio", 1894e09e9873SVladimir Oltean #endif 1895e09e9873SVladimir Oltean #if IS_ENABLED(CONFIG_NET_DSA_SMSC_LAN9303_I2C) 1896e09e9873SVladimir Oltean "smsc,lan9303-i2c", 1897e09e9873SVladimir Oltean #endif 1898e09e9873SVladimir Oltean NULL, 1899e09e9873SVladimir Oltean }; 1900e09e9873SVladimir Oltean 1901e09e9873SVladimir Oltean static void dsa_shared_port_validate_of(struct dsa_port *dp, 1902e09e9873SVladimir Oltean bool *missing_phy_mode, 1903e09e9873SVladimir Oltean bool *missing_link_description) 1904e09e9873SVladimir Oltean { 1905e09e9873SVladimir Oltean struct device_node *dn = dp->dn, *phy_np; 1906e09e9873SVladimir Oltean struct dsa_switch *ds = dp->ds; 1907e09e9873SVladimir Oltean phy_interface_t mode; 1908e09e9873SVladimir Oltean 1909e09e9873SVladimir Oltean *missing_phy_mode = false; 1910e09e9873SVladimir Oltean *missing_link_description = false; 1911e09e9873SVladimir Oltean 1912e09e9873SVladimir Oltean if (of_get_phy_mode(dn, &mode)) { 1913e09e9873SVladimir Oltean *missing_phy_mode = true; 1914e09e9873SVladimir Oltean dev_err(ds->dev, 1915e09e9873SVladimir Oltean "OF node %pOF of %s port %d lacks the required \"phy-mode\" property\n", 1916e09e9873SVladimir Oltean dn, dsa_port_is_cpu(dp) ? "CPU" : "DSA", dp->index); 1917e09e9873SVladimir Oltean } 1918e09e9873SVladimir Oltean 1919e09e9873SVladimir Oltean /* Note: of_phy_is_fixed_link() also returns true for 1920e09e9873SVladimir Oltean * managed = "in-band-status" 1921e09e9873SVladimir Oltean */ 1922e09e9873SVladimir Oltean if (of_phy_is_fixed_link(dn)) 1923e09e9873SVladimir Oltean return; 1924e09e9873SVladimir Oltean 1925e09e9873SVladimir Oltean phy_np = of_parse_phandle(dn, "phy-handle", 0); 1926e09e9873SVladimir Oltean if (phy_np) { 1927e09e9873SVladimir Oltean of_node_put(phy_np); 1928e09e9873SVladimir Oltean return; 1929e09e9873SVladimir Oltean } 1930e09e9873SVladimir Oltean 1931e09e9873SVladimir Oltean *missing_link_description = true; 1932e09e9873SVladimir Oltean 1933e09e9873SVladimir Oltean dev_err(ds->dev, 1934e09e9873SVladimir Oltean "OF node %pOF of %s port %d lacks the required \"phy-handle\", \"fixed-link\" or \"managed\" properties\n", 1935e09e9873SVladimir Oltean dn, dsa_port_is_cpu(dp) ? "CPU" : "DSA", dp->index); 1936e09e9873SVladimir Oltean } 1937e09e9873SVladimir Oltean 1938770375ffSVladimir Oltean int dsa_shared_port_link_register_of(struct dsa_port *dp) 193957ab1ca2SVivien Didelot { 19400e279218SIoana Ciornei struct dsa_switch *ds = dp->ds; 1941e09e9873SVladimir Oltean bool missing_link_description; 1942e09e9873SVladimir Oltean bool missing_phy_mode; 19433be98b2dSAndrew Lunn int port = dp->index; 19440e279218SIoana Ciornei 1945e09e9873SVladimir Oltean dsa_shared_port_validate_of(dp, &missing_phy_mode, 1946e09e9873SVladimir Oltean &missing_link_description); 1947e09e9873SVladimir Oltean 1948e09e9873SVladimir Oltean if ((missing_phy_mode || missing_link_description) && 1949e09e9873SVladimir Oltean !of_device_compatible_match(ds->dev->of_node, 1950e09e9873SVladimir Oltean dsa_switches_apply_workarounds)) 1951e09e9873SVladimir Oltean return -EINVAL; 1952e09e9873SVladimir Oltean 1953a20f9970SAndrew Lunn if (!ds->ops->adjust_link) { 1954e09e9873SVladimir Oltean if (missing_link_description) { 1955e09e9873SVladimir Oltean dev_warn(ds->dev, 1956e09e9873SVladimir Oltean "Skipping phylink registration for %s port %d\n", 1957e09e9873SVladimir Oltean dsa_port_is_cpu(dp) ? "CPU" : "DSA", dp->index); 1958e09e9873SVladimir Oltean } else { 19593be98b2dSAndrew Lunn if (ds->ops->phylink_mac_link_down) 19603be98b2dSAndrew Lunn ds->ops->phylink_mac_link_down(ds, port, 19613be98b2dSAndrew Lunn MLO_AN_FIXED, PHY_INTERFACE_MODE_NA); 1962e09e9873SVladimir Oltean 1963770375ffSVladimir Oltean return dsa_shared_port_phylink_register(dp); 19643be98b2dSAndrew Lunn } 1965a20f9970SAndrew Lunn return 0; 1966a20f9970SAndrew Lunn } 19670e279218SIoana Ciornei 19680e279218SIoana Ciornei dev_warn(ds->dev, 19690e279218SIoana Ciornei "Using legacy PHYLIB callbacks. Please migrate to PHYLINK!\n"); 19700e279218SIoana Ciornei 197133615367SSebastian Reichel if (of_phy_is_fixed_link(dp->dn)) 1972770375ffSVladimir Oltean return dsa_shared_port_fixed_link_register_of(dp); 197333615367SSebastian Reichel else 1974770375ffSVladimir Oltean return dsa_shared_port_setup_phy_of(dp, true); 197533615367SSebastian Reichel } 197657ab1ca2SVivien Didelot 1977770375ffSVladimir Oltean void dsa_shared_port_link_unregister_of(struct dsa_port *dp) 197833615367SSebastian Reichel { 19790e279218SIoana Ciornei struct dsa_switch *ds = dp->ds; 19800e279218SIoana Ciornei 1981a20f9970SAndrew Lunn if (!ds->ops->adjust_link && dp->pl) { 19820e279218SIoana Ciornei rtnl_lock(); 19830e279218SIoana Ciornei phylink_disconnect_phy(dp->pl); 19840e279218SIoana Ciornei rtnl_unlock(); 19850e279218SIoana Ciornei phylink_destroy(dp->pl); 1986a20f9970SAndrew Lunn dp->pl = NULL; 19870e279218SIoana Ciornei return; 19880e279218SIoana Ciornei } 19890e279218SIoana Ciornei 199033615367SSebastian Reichel if (of_phy_is_fixed_link(dp->dn)) 199133615367SSebastian Reichel of_phy_deregister_fixed_link(dp->dn); 199233615367SSebastian Reichel else 1993770375ffSVladimir Oltean dsa_shared_port_setup_phy_of(dp, false); 199457ab1ca2SVivien Didelot } 1995cf963573SFlorian Fainelli 199618596f50SGeorge McCollister int dsa_port_hsr_join(struct dsa_port *dp, struct net_device *hsr) 199718596f50SGeorge McCollister { 1998a68dc7b9SVladimir Oltean struct dsa_switch *ds = dp->ds; 199918596f50SGeorge McCollister int err; 200018596f50SGeorge McCollister 2001a68dc7b9SVladimir Oltean if (!ds->ops->port_hsr_join) 2002a68dc7b9SVladimir Oltean return -EOPNOTSUPP; 2003a68dc7b9SVladimir Oltean 200418596f50SGeorge McCollister dp->hsr_dev = hsr; 200518596f50SGeorge McCollister 2006a68dc7b9SVladimir Oltean err = ds->ops->port_hsr_join(ds, dp->index, hsr); 200718596f50SGeorge McCollister if (err) 200818596f50SGeorge McCollister dp->hsr_dev = NULL; 200918596f50SGeorge McCollister 201018596f50SGeorge McCollister return err; 201118596f50SGeorge McCollister } 201218596f50SGeorge McCollister 201318596f50SGeorge McCollister void dsa_port_hsr_leave(struct dsa_port *dp, struct net_device *hsr) 201418596f50SGeorge McCollister { 2015a68dc7b9SVladimir Oltean struct dsa_switch *ds = dp->ds; 201618596f50SGeorge McCollister int err; 201718596f50SGeorge McCollister 201818596f50SGeorge McCollister dp->hsr_dev = NULL; 201918596f50SGeorge McCollister 2020a68dc7b9SVladimir Oltean if (ds->ops->port_hsr_leave) { 2021a68dc7b9SVladimir Oltean err = ds->ops->port_hsr_leave(ds, dp->index, hsr); 202218596f50SGeorge McCollister if (err) 2023ab97462bSVladimir Oltean dev_err(dp->ds->dev, 2024a68dc7b9SVladimir Oltean "port %d failed to leave HSR %s: %pe\n", 2025a68dc7b9SVladimir Oltean dp->index, hsr->name, ERR_PTR(err)); 2026a68dc7b9SVladimir Oltean } 202718596f50SGeorge McCollister } 2028c64b9c05SVladimir Oltean 2029724395f4SVladimir Oltean int dsa_port_tag_8021q_vlan_add(struct dsa_port *dp, u16 vid, bool broadcast) 2030c64b9c05SVladimir Oltean { 2031c64b9c05SVladimir Oltean struct dsa_notifier_tag_8021q_vlan_info info = { 2032726816a1SVladimir Oltean .dp = dp, 2033c64b9c05SVladimir Oltean .vid = vid, 2034c64b9c05SVladimir Oltean }; 2035c64b9c05SVladimir Oltean 2036724395f4SVladimir Oltean if (broadcast) 2037c64b9c05SVladimir Oltean return dsa_broadcast(DSA_NOTIFIER_TAG_8021Q_VLAN_ADD, &info); 2038724395f4SVladimir Oltean 2039724395f4SVladimir Oltean return dsa_port_notify(dp, DSA_NOTIFIER_TAG_8021Q_VLAN_ADD, &info); 2040c64b9c05SVladimir Oltean } 2041c64b9c05SVladimir Oltean 2042724395f4SVladimir Oltean void dsa_port_tag_8021q_vlan_del(struct dsa_port *dp, u16 vid, bool broadcast) 2043c64b9c05SVladimir Oltean { 2044c64b9c05SVladimir Oltean struct dsa_notifier_tag_8021q_vlan_info info = { 2045726816a1SVladimir Oltean .dp = dp, 2046c64b9c05SVladimir Oltean .vid = vid, 2047c64b9c05SVladimir Oltean }; 2048c64b9c05SVladimir Oltean int err; 2049c64b9c05SVladimir Oltean 2050724395f4SVladimir Oltean if (broadcast) 2051c64b9c05SVladimir Oltean err = dsa_broadcast(DSA_NOTIFIER_TAG_8021Q_VLAN_DEL, &info); 2052724395f4SVladimir Oltean else 2053724395f4SVladimir Oltean err = dsa_port_notify(dp, DSA_NOTIFIER_TAG_8021Q_VLAN_DEL, &info); 2054c64b9c05SVladimir Oltean if (err) 2055ab97462bSVladimir Oltean dev_err(dp->ds->dev, 2056ab97462bSVladimir Oltean "port %d failed to notify tag_8021q VLAN %d deletion: %pe\n", 2057ab97462bSVladimir Oltean dp->index, vid, ERR_PTR(err)); 2058c64b9c05SVladimir Oltean } 2059