xref: /openbmc/linux/net/dsa/port.c (revision 2e359b00)
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