xref: /openbmc/linux/net/dsa/port.c (revision 14562277)
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 
1547d2ce03SVladimir Oltean #include "dsa.h"
16022bba63SVladimir Oltean #include "port.h"
1709f92341SVladimir Oltean #include "slave.h"
180c603136SVladimir Oltean #include "switch.h"
1919d05ea7SVladimir Oltean #include "tag_8021q.h"
20a40c175bSVivien Didelot 
21886f8e26SVladimir Oltean /**
22886f8e26SVladimir Oltean  * dsa_port_notify - Notify the switching fabric of changes to a port
23886f8e26SVladimir Oltean  * @dp: port on which change occurred
24886f8e26SVladimir Oltean  * @e: event, must be of type DSA_NOTIFIER_*
25886f8e26SVladimir Oltean  * @v: event-specific value.
26886f8e26SVladimir Oltean  *
27886f8e26SVladimir Oltean  * Notify all switches in the DSA tree that this port's switch belongs to,
28886f8e26SVladimir Oltean  * including this switch itself, of an event. Allows the other switches to
29886f8e26SVladimir Oltean  * reconfigure themselves for cross-chip operations. Can also be used to
30886f8e26SVladimir Oltean  * reconfigure ports without net_devices (CPU ports, DSA links) whenever
31886f8e26SVladimir Oltean  * a user port's state changes.
32886f8e26SVladimir Oltean  */
dsa_port_notify(const struct dsa_port * dp,unsigned long e,void * v)33bb9f6031SAndrew Lunn static int dsa_port_notify(const struct dsa_port *dp, unsigned long e, void *v)
34cfbed329SVivien Didelot {
35886f8e26SVladimir Oltean 	return dsa_tree_notify(dp->ds->dst, e, v);
36cfbed329SVivien Didelot }
37cfbed329SVivien Didelot 
dsa_port_notify_bridge_fdb_flush(const struct dsa_port * dp,u16 vid)387414af30STobias Waldekranz static void dsa_port_notify_bridge_fdb_flush(const struct dsa_port *dp, u16 vid)
399264e4adSVladimir Oltean {
409264e4adSVladimir Oltean 	struct net_device *brport_dev = dsa_port_to_bridge_port(dp);
419264e4adSVladimir Oltean 	struct switchdev_notifier_fdb_info info = {
427414af30STobias Waldekranz 		.vid = vid,
439264e4adSVladimir Oltean 	};
449264e4adSVladimir Oltean 
459264e4adSVladimir Oltean 	/* When the port becomes standalone it has already left the bridge.
469264e4adSVladimir Oltean 	 * Don't notify the bridge in that case.
479264e4adSVladimir Oltean 	 */
489264e4adSVladimir Oltean 	if (!brport_dev)
499264e4adSVladimir Oltean 		return;
509264e4adSVladimir Oltean 
519264e4adSVladimir Oltean 	call_switchdev_notifiers(SWITCHDEV_FDB_FLUSH_TO_BRIDGE,
529264e4adSVladimir Oltean 				 brport_dev, &info.info, NULL);
539264e4adSVladimir Oltean }
549264e4adSVladimir Oltean 
dsa_port_fast_age(const struct dsa_port * dp)55045c45d1SVladimir Oltean static void dsa_port_fast_age(const struct dsa_port *dp)
56045c45d1SVladimir Oltean {
57045c45d1SVladimir Oltean 	struct dsa_switch *ds = dp->ds;
58045c45d1SVladimir Oltean 
59045c45d1SVladimir Oltean 	if (!ds->ops->port_fast_age)
60045c45d1SVladimir Oltean 		return;
61045c45d1SVladimir Oltean 
62045c45d1SVladimir Oltean 	ds->ops->port_fast_age(ds, dp->index);
639264e4adSVladimir Oltean 
647414af30STobias Waldekranz 	/* flush all VLANs */
657414af30STobias Waldekranz 	dsa_port_notify_bridge_fdb_flush(dp, 0);
667414af30STobias Waldekranz }
677414af30STobias Waldekranz 
dsa_port_vlan_fast_age(const struct dsa_port * dp,u16 vid)687414af30STobias Waldekranz static int dsa_port_vlan_fast_age(const struct dsa_port *dp, u16 vid)
697414af30STobias Waldekranz {
707414af30STobias Waldekranz 	struct dsa_switch *ds = dp->ds;
717414af30STobias Waldekranz 	int err;
727414af30STobias Waldekranz 
737414af30STobias Waldekranz 	if (!ds->ops->port_vlan_fast_age)
747414af30STobias Waldekranz 		return -EOPNOTSUPP;
757414af30STobias Waldekranz 
767414af30STobias Waldekranz 	err = ds->ops->port_vlan_fast_age(ds, dp->index, vid);
777414af30STobias Waldekranz 
787414af30STobias Waldekranz 	if (!err)
797414af30STobias Waldekranz 		dsa_port_notify_bridge_fdb_flush(dp, vid);
807414af30STobias Waldekranz 
817414af30STobias Waldekranz 	return err;
827414af30STobias Waldekranz }
837414af30STobias Waldekranz 
dsa_port_msti_fast_age(const struct dsa_port * dp,u16 msti)847414af30STobias Waldekranz static int dsa_port_msti_fast_age(const struct dsa_port *dp, u16 msti)
857414af30STobias Waldekranz {
867414af30STobias Waldekranz 	DECLARE_BITMAP(vids, VLAN_N_VID) = { 0 };
877414af30STobias Waldekranz 	int err, vid;
887414af30STobias Waldekranz 
897414af30STobias Waldekranz 	err = br_mst_get_info(dsa_port_bridge_dev_get(dp), msti, vids);
907414af30STobias Waldekranz 	if (err)
917414af30STobias Waldekranz 		return err;
927414af30STobias Waldekranz 
937414af30STobias Waldekranz 	for_each_set_bit(vid, vids, VLAN_N_VID) {
947414af30STobias Waldekranz 		err = dsa_port_vlan_fast_age(dp, vid);
957414af30STobias Waldekranz 		if (err)
967414af30STobias Waldekranz 			return err;
977414af30STobias Waldekranz 	}
987414af30STobias Waldekranz 
997414af30STobias Waldekranz 	return 0;
100045c45d1SVladimir Oltean }
101045c45d1SVladimir Oltean 
dsa_port_can_configure_learning(struct dsa_port * dp)102a4ffe09fSVladimir Oltean static bool dsa_port_can_configure_learning(struct dsa_port *dp)
103a4ffe09fSVladimir Oltean {
104a4ffe09fSVladimir Oltean 	struct switchdev_brport_flags flags = {
105a4ffe09fSVladimir Oltean 		.mask = BR_LEARNING,
106a4ffe09fSVladimir Oltean 	};
107a4ffe09fSVladimir Oltean 	struct dsa_switch *ds = dp->ds;
108a4ffe09fSVladimir Oltean 	int err;
109a4ffe09fSVladimir Oltean 
110a4ffe09fSVladimir Oltean 	if (!ds->ops->port_bridge_flags || !ds->ops->port_pre_bridge_flags)
111a4ffe09fSVladimir Oltean 		return false;
112a4ffe09fSVladimir Oltean 
113a4ffe09fSVladimir Oltean 	err = ds->ops->port_pre_bridge_flags(ds, dp->index, flags, NULL);
114a4ffe09fSVladimir Oltean 	return !err;
115a4ffe09fSVladimir Oltean }
116a4ffe09fSVladimir Oltean 
dsa_port_supports_hwtstamp(struct dsa_port * dp)117ff6ac4d0SVladimir Oltean bool dsa_port_supports_hwtstamp(struct dsa_port *dp)
118ed1fe1beSVladimir Oltean {
119ed1fe1beSVladimir Oltean 	struct dsa_switch *ds = dp->ds;
120ff6ac4d0SVladimir Oltean 	struct ifreq ifr = {};
121ed1fe1beSVladimir Oltean 	int err;
122ed1fe1beSVladimir Oltean 
123ed1fe1beSVladimir Oltean 	if (!ds->ops->port_hwtstamp_get || !ds->ops->port_hwtstamp_set)
124ed1fe1beSVladimir Oltean 		return false;
125ed1fe1beSVladimir Oltean 
126ed1fe1beSVladimir Oltean 	/* "See through" shim implementations of the "get" method.
127ff6ac4d0SVladimir Oltean 	 * Since we can't cook up a complete ioctl request structure, this will
128ff6ac4d0SVladimir Oltean 	 * fail in copy_to_user() with -EFAULT, which hopefully is enough to
129ff6ac4d0SVladimir Oltean 	 * detect a valid implementation.
130ed1fe1beSVladimir Oltean 	 */
131ff6ac4d0SVladimir Oltean 	err = ds->ops->port_hwtstamp_get(ds, dp->index, &ifr);
132ed1fe1beSVladimir Oltean 	return err != -EOPNOTSUPP;
133ed1fe1beSVladimir Oltean }
134ed1fe1beSVladimir Oltean 
dsa_port_set_state(struct dsa_port * dp,u8 state,bool do_fast_age)13539f32101SVladimir Oltean int dsa_port_set_state(struct dsa_port *dp, u8 state, bool do_fast_age)
136a40c175bSVivien Didelot {
137a40c175bSVivien Didelot 	struct dsa_switch *ds = dp->ds;
138a40c175bSVivien Didelot 	int port = dp->index;
139a40c175bSVivien Didelot 
140bae33f2bSVladimir Oltean 	if (!ds->ops->port_stp_state_set)
141bae33f2bSVladimir Oltean 		return -EOPNOTSUPP;
142a40c175bSVivien Didelot 
143a40c175bSVivien Didelot 	ds->ops->port_stp_state_set(ds, port, state);
144a40c175bSVivien Didelot 
145a4ffe09fSVladimir Oltean 	if (!dsa_port_can_configure_learning(dp) ||
146a4ffe09fSVladimir Oltean 	    (do_fast_age && dp->learning)) {
147a40c175bSVivien Didelot 		/* Fast age FDB entries or flush appropriate forwarding database
148a40c175bSVivien Didelot 		 * for the given port, if we are moving it from Learning or
149a40c175bSVivien Didelot 		 * Forwarding state, to Disabled or Blocking or Listening state.
15039f32101SVladimir Oltean 		 * Ports that were standalone before the STP state change don't
15139f32101SVladimir Oltean 		 * need to fast age the FDB, since address learning is off in
15239f32101SVladimir Oltean 		 * standalone mode.
153a40c175bSVivien Didelot 		 */
154a40c175bSVivien Didelot 
155a40c175bSVivien Didelot 		if ((dp->stp_state == BR_STATE_LEARNING ||
156a40c175bSVivien Didelot 		     dp->stp_state == BR_STATE_FORWARDING) &&
157a40c175bSVivien Didelot 		    (state == BR_STATE_DISABLED ||
158a40c175bSVivien Didelot 		     state == BR_STATE_BLOCKING ||
159a40c175bSVivien Didelot 		     state == BR_STATE_LISTENING))
160045c45d1SVladimir Oltean 			dsa_port_fast_age(dp);
161a40c175bSVivien Didelot 	}
162a40c175bSVivien Didelot 
163a40c175bSVivien Didelot 	dp->stp_state = state;
164a40c175bSVivien Didelot 
165a40c175bSVivien Didelot 	return 0;
166a40c175bSVivien Didelot }
167a40c175bSVivien Didelot 
dsa_port_set_state_now(struct dsa_port * dp,u8 state,bool do_fast_age)16839f32101SVladimir Oltean static void dsa_port_set_state_now(struct dsa_port *dp, u8 state,
16939f32101SVladimir Oltean 				   bool do_fast_age)
170a40c175bSVivien Didelot {
171211987f3SVladimir Oltean 	struct dsa_switch *ds = dp->ds;
172a40c175bSVivien Didelot 	int err;
173a40c175bSVivien Didelot 
17439f32101SVladimir Oltean 	err = dsa_port_set_state(dp, state, do_fast_age);
175211987f3SVladimir Oltean 	if (err && err != -EOPNOTSUPP) {
176211987f3SVladimir Oltean 		dev_err(ds->dev, "port %d failed to set STP state %u: %pe\n",
177211987f3SVladimir Oltean 			dp->index, state, ERR_PTR(err));
178211987f3SVladimir Oltean 	}
179a40c175bSVivien Didelot }
180cfbed329SVivien Didelot 
dsa_port_set_mst_state(struct dsa_port * dp,const struct switchdev_mst_state * state,struct netlink_ext_ack * extack)1817414af30STobias Waldekranz int dsa_port_set_mst_state(struct dsa_port *dp,
1827414af30STobias Waldekranz 			   const struct switchdev_mst_state *state,
1837414af30STobias Waldekranz 			   struct netlink_ext_ack *extack)
1847414af30STobias Waldekranz {
1857414af30STobias Waldekranz 	struct dsa_switch *ds = dp->ds;
1867414af30STobias Waldekranz 	u8 prev_state;
1877414af30STobias Waldekranz 	int err;
1887414af30STobias Waldekranz 
1897414af30STobias Waldekranz 	if (!ds->ops->port_mst_state_set)
1907414af30STobias Waldekranz 		return -EOPNOTSUPP;
1917414af30STobias Waldekranz 
1927414af30STobias Waldekranz 	err = br_mst_get_state(dsa_port_to_bridge_port(dp), state->msti,
1937414af30STobias Waldekranz 			       &prev_state);
1947414af30STobias Waldekranz 	if (err)
1957414af30STobias Waldekranz 		return err;
1967414af30STobias Waldekranz 
1977414af30STobias Waldekranz 	err = ds->ops->port_mst_state_set(ds, dp->index, state);
1987414af30STobias Waldekranz 	if (err)
1997414af30STobias Waldekranz 		return err;
2007414af30STobias Waldekranz 
2017414af30STobias Waldekranz 	if (!(dp->learning &&
2027414af30STobias Waldekranz 	      (prev_state == BR_STATE_LEARNING ||
2037414af30STobias Waldekranz 	       prev_state == BR_STATE_FORWARDING) &&
2047414af30STobias Waldekranz 	      (state->state == BR_STATE_DISABLED ||
2057414af30STobias Waldekranz 	       state->state == BR_STATE_BLOCKING ||
2067414af30STobias Waldekranz 	       state->state == BR_STATE_LISTENING)))
2077414af30STobias Waldekranz 		return 0;
2087414af30STobias Waldekranz 
2097414af30STobias Waldekranz 	err = dsa_port_msti_fast_age(dp, state->msti);
2107414af30STobias Waldekranz 	if (err)
2117414af30STobias Waldekranz 		NL_SET_ERR_MSG_MOD(extack,
2127414af30STobias Waldekranz 				   "Unable to flush associated VLANs");
2137414af30STobias Waldekranz 
2147414af30STobias Waldekranz 	return 0;
2157414af30STobias Waldekranz }
2167414af30STobias Waldekranz 
dsa_port_enable_rt(struct dsa_port * dp,struct phy_device * phy)2178640f8dcSRussell King int dsa_port_enable_rt(struct dsa_port *dp, struct phy_device *phy)
218fb8a6a2bSVivien Didelot {
219fb8a6a2bSVivien Didelot 	struct dsa_switch *ds = dp->ds;
220fb8a6a2bSVivien Didelot 	int port = dp->index;
221fb8a6a2bSVivien Didelot 	int err;
222fb8a6a2bSVivien Didelot 
223fb8a6a2bSVivien Didelot 	if (ds->ops->port_enable) {
224fb8a6a2bSVivien Didelot 		err = ds->ops->port_enable(ds, port, phy);
225fb8a6a2bSVivien Didelot 		if (err)
226fb8a6a2bSVivien Didelot 			return err;
227fb8a6a2bSVivien Didelot 	}
228fb8a6a2bSVivien Didelot 
229d3eed0e5SVladimir Oltean 	if (!dp->bridge)
23039f32101SVladimir Oltean 		dsa_port_set_state_now(dp, BR_STATE_FORWARDING, false);
231fb8a6a2bSVivien Didelot 
2328640f8dcSRussell King 	if (dp->pl)
2338640f8dcSRussell King 		phylink_start(dp->pl);
2348640f8dcSRussell King 
235fb8a6a2bSVivien Didelot 	return 0;
236fb8a6a2bSVivien Didelot }
237fb8a6a2bSVivien Didelot 
dsa_port_enable(struct dsa_port * dp,struct phy_device * phy)2388640f8dcSRussell King int dsa_port_enable(struct dsa_port *dp, struct phy_device *phy)
2398640f8dcSRussell King {
2408640f8dcSRussell King 	int err;
2418640f8dcSRussell King 
2428640f8dcSRussell King 	rtnl_lock();
2438640f8dcSRussell King 	err = dsa_port_enable_rt(dp, phy);
2448640f8dcSRussell King 	rtnl_unlock();
2458640f8dcSRussell King 
2468640f8dcSRussell King 	return err;
2478640f8dcSRussell King }
2488640f8dcSRussell King 
dsa_port_disable_rt(struct dsa_port * dp)2498640f8dcSRussell King void dsa_port_disable_rt(struct dsa_port *dp)
250fb8a6a2bSVivien Didelot {
251fb8a6a2bSVivien Didelot 	struct dsa_switch *ds = dp->ds;
252fb8a6a2bSVivien Didelot 	int port = dp->index;
253fb8a6a2bSVivien Didelot 
2548640f8dcSRussell King 	if (dp->pl)
2558640f8dcSRussell King 		phylink_stop(dp->pl);
2568640f8dcSRussell King 
257d3eed0e5SVladimir Oltean 	if (!dp->bridge)
25839f32101SVladimir Oltean 		dsa_port_set_state_now(dp, BR_STATE_DISABLED, false);
259fb8a6a2bSVivien Didelot 
260fb8a6a2bSVivien Didelot 	if (ds->ops->port_disable)
26175104db0SAndrew Lunn 		ds->ops->port_disable(ds, port);
262fb8a6a2bSVivien Didelot }
263fb8a6a2bSVivien Didelot 
dsa_port_disable(struct dsa_port * dp)2648640f8dcSRussell King void dsa_port_disable(struct dsa_port *dp)
2658640f8dcSRussell King {
2668640f8dcSRussell King 	rtnl_lock();
2678640f8dcSRussell King 	dsa_port_disable_rt(dp);
2688640f8dcSRussell King 	rtnl_unlock();
2698640f8dcSRussell King }
2708640f8dcSRussell King 
dsa_port_reset_vlan_filtering(struct dsa_port * dp,struct dsa_bridge bridge)2718e9e678eSVladimir Oltean static void dsa_port_reset_vlan_filtering(struct dsa_port *dp,
2728e9e678eSVladimir Oltean 					  struct dsa_bridge bridge)
2738e9e678eSVladimir Oltean {
2748e9e678eSVladimir Oltean 	struct netlink_ext_ack extack = {0};
2758e9e678eSVladimir Oltean 	bool change_vlan_filtering = false;
2768e9e678eSVladimir Oltean 	struct dsa_switch *ds = dp->ds;
2771699b4d5SVladimir Oltean 	struct dsa_port *other_dp;
2788e9e678eSVladimir Oltean 	bool vlan_filtering;
2798e9e678eSVladimir Oltean 	int err;
2808e9e678eSVladimir Oltean 
2818e9e678eSVladimir Oltean 	if (ds->needs_standalone_vlan_filtering &&
2828e9e678eSVladimir Oltean 	    !br_vlan_enabled(bridge.dev)) {
2838e9e678eSVladimir Oltean 		change_vlan_filtering = true;
2848e9e678eSVladimir Oltean 		vlan_filtering = true;
2858e9e678eSVladimir Oltean 	} else if (!ds->needs_standalone_vlan_filtering &&
2868e9e678eSVladimir Oltean 		   br_vlan_enabled(bridge.dev)) {
2878e9e678eSVladimir Oltean 		change_vlan_filtering = true;
2888e9e678eSVladimir Oltean 		vlan_filtering = false;
2898e9e678eSVladimir Oltean 	}
2908e9e678eSVladimir Oltean 
2918e9e678eSVladimir Oltean 	/* If the bridge was vlan_filtering, the bridge core doesn't trigger an
2928e9e678eSVladimir Oltean 	 * event for changing vlan_filtering setting upon slave ports leaving
2938e9e678eSVladimir Oltean 	 * it. That is a good thing, because that lets us handle it and also
2948e9e678eSVladimir Oltean 	 * handle the case where the switch's vlan_filtering setting is global
2958e9e678eSVladimir Oltean 	 * (not per port). When that happens, the correct moment to trigger the
2968e9e678eSVladimir Oltean 	 * vlan_filtering callback is only when the last port leaves the last
2978e9e678eSVladimir Oltean 	 * VLAN-aware bridge.
2988e9e678eSVladimir Oltean 	 */
2998e9e678eSVladimir Oltean 	if (change_vlan_filtering && ds->vlan_filtering_is_global) {
3001699b4d5SVladimir Oltean 		dsa_switch_for_each_port(other_dp, ds) {
3011699b4d5SVladimir Oltean 			struct net_device *br = dsa_port_bridge_dev_get(other_dp);
3028e9e678eSVladimir Oltean 
3038e9e678eSVladimir Oltean 			if (br && br_vlan_enabled(br)) {
3048e9e678eSVladimir Oltean 				change_vlan_filtering = false;
3058e9e678eSVladimir Oltean 				break;
3068e9e678eSVladimir Oltean 			}
3078e9e678eSVladimir Oltean 		}
3088e9e678eSVladimir Oltean 	}
3098e9e678eSVladimir Oltean 
3108e9e678eSVladimir Oltean 	if (!change_vlan_filtering)
3118e9e678eSVladimir Oltean 		return;
3128e9e678eSVladimir Oltean 
3138e9e678eSVladimir Oltean 	err = dsa_port_vlan_filtering(dp, vlan_filtering, &extack);
3148e9e678eSVladimir Oltean 	if (extack._msg) {
3158e9e678eSVladimir Oltean 		dev_err(ds->dev, "port %d: %s\n", dp->index,
3168e9e678eSVladimir Oltean 			extack._msg);
3178e9e678eSVladimir Oltean 	}
3188e9e678eSVladimir Oltean 	if (err && err != -EOPNOTSUPP) {
3198e9e678eSVladimir Oltean 		dev_err(ds->dev,
3208e9e678eSVladimir Oltean 			"port %d failed to reset VLAN filtering to %d: %pe\n",
3218e9e678eSVladimir Oltean 		       dp->index, vlan_filtering, ERR_PTR(err));
3228e9e678eSVladimir Oltean 	}
3238e9e678eSVladimir Oltean }
3248e9e678eSVladimir Oltean 
dsa_port_inherit_brport_flags(struct dsa_port * dp,struct netlink_ext_ack * extack)3255961d6a1SVladimir Oltean static int dsa_port_inherit_brport_flags(struct dsa_port *dp,
3265961d6a1SVladimir Oltean 					 struct netlink_ext_ack *extack)
3275e38c158SVladimir Oltean {
3285961d6a1SVladimir Oltean 	const unsigned long mask = BR_LEARNING | BR_FLOOD | BR_MCAST_FLOOD |
329b9e8b58fSHans Schultz 				   BR_BCAST_FLOOD | BR_PORT_LOCKED;
3305961d6a1SVladimir Oltean 	struct net_device *brport_dev = dsa_port_to_bridge_port(dp);
3315961d6a1SVladimir Oltean 	int flag, err;
3325e38c158SVladimir Oltean 
3335961d6a1SVladimir Oltean 	for_each_set_bit(flag, &mask, 32) {
3345961d6a1SVladimir Oltean 		struct switchdev_brport_flags flags = {0};
3355e38c158SVladimir Oltean 
3365961d6a1SVladimir Oltean 		flags.mask = BIT(flag);
3375e38c158SVladimir Oltean 
3385961d6a1SVladimir Oltean 		if (br_port_flag_is_set(brport_dev, BIT(flag)))
3395961d6a1SVladimir Oltean 			flags.val = BIT(flag);
340e18f4c18SVladimir Oltean 
3415961d6a1SVladimir Oltean 		err = dsa_port_bridge_flags(dp, flags, extack);
3425961d6a1SVladimir Oltean 		if (err && err != -EOPNOTSUPP)
3435961d6a1SVladimir Oltean 			return err;
3445e38c158SVladimir Oltean 	}
3455961d6a1SVladimir Oltean 
3465961d6a1SVladimir Oltean 	return 0;
3475961d6a1SVladimir Oltean }
3485961d6a1SVladimir Oltean 
dsa_port_clear_brport_flags(struct dsa_port * dp)3495961d6a1SVladimir Oltean static void dsa_port_clear_brport_flags(struct dsa_port *dp)
3505961d6a1SVladimir Oltean {
3515961d6a1SVladimir Oltean 	const unsigned long val = BR_FLOOD | BR_MCAST_FLOOD | BR_BCAST_FLOOD;
3525961d6a1SVladimir Oltean 	const unsigned long mask = BR_LEARNING | BR_FLOOD | BR_MCAST_FLOOD |
353b9e8b58fSHans Schultz 				   BR_BCAST_FLOOD | BR_PORT_LOCKED;
3545961d6a1SVladimir Oltean 	int flag, err;
3555961d6a1SVladimir Oltean 
3565961d6a1SVladimir Oltean 	for_each_set_bit(flag, &mask, 32) {
3575961d6a1SVladimir Oltean 		struct switchdev_brport_flags flags = {0};
3585961d6a1SVladimir Oltean 
3595961d6a1SVladimir Oltean 		flags.mask = BIT(flag);
3605961d6a1SVladimir Oltean 		flags.val = val & BIT(flag);
3615961d6a1SVladimir Oltean 
3625961d6a1SVladimir Oltean 		err = dsa_port_bridge_flags(dp, flags, NULL);
3635961d6a1SVladimir Oltean 		if (err && err != -EOPNOTSUPP)
3645961d6a1SVladimir Oltean 			dev_err(dp->ds->dev,
3655961d6a1SVladimir Oltean 				"failed to clear bridge port flag %lu: %pe\n",
3665961d6a1SVladimir Oltean 				flags.val, ERR_PTR(err));
3675961d6a1SVladimir Oltean 	}
3685961d6a1SVladimir Oltean }
3695961d6a1SVladimir Oltean 
dsa_port_switchdev_sync_attrs(struct dsa_port * dp,struct netlink_ext_ack * extack)3704e51bf44SVladimir Oltean static int dsa_port_switchdev_sync_attrs(struct dsa_port *dp,
3715961d6a1SVladimir Oltean 					 struct netlink_ext_ack *extack)
3725961d6a1SVladimir Oltean {
373010e269fSVladimir Oltean 	struct net_device *brport_dev = dsa_port_to_bridge_port(dp);
37436cbf39bSVladimir Oltean 	struct net_device *br = dsa_port_bridge_dev_get(dp);
3755961d6a1SVladimir Oltean 	int err;
3765961d6a1SVladimir Oltean 
3775961d6a1SVladimir Oltean 	err = dsa_port_inherit_brport_flags(dp, extack);
3785961d6a1SVladimir Oltean 	if (err)
3795961d6a1SVladimir Oltean 		return err;
3805961d6a1SVladimir Oltean 
38139f32101SVladimir Oltean 	err = dsa_port_set_state(dp, br_port_get_stp_state(brport_dev), false);
382010e269fSVladimir Oltean 	if (err && err != -EOPNOTSUPP)
383010e269fSVladimir Oltean 		return err;
384010e269fSVladimir Oltean 
385010e269fSVladimir Oltean 	err = dsa_port_vlan_filtering(dp, br_vlan_enabled(br), extack);
386010e269fSVladimir Oltean 	if (err && err != -EOPNOTSUPP)
387010e269fSVladimir Oltean 		return err;
388010e269fSVladimir Oltean 
389010e269fSVladimir Oltean 	err = dsa_port_ageing_time(dp, br_get_ageing_time(br));
390010e269fSVladimir Oltean 	if (err && err != -EOPNOTSUPP)
391010e269fSVladimir Oltean 		return err;
392010e269fSVladimir Oltean 
39374918945SVladimir Oltean 	return 0;
39474918945SVladimir Oltean }
39574918945SVladimir Oltean 
dsa_port_switchdev_unsync_attrs(struct dsa_port * dp,struct dsa_bridge bridge)3968e9e678eSVladimir Oltean static void dsa_port_switchdev_unsync_attrs(struct dsa_port *dp,
3978e9e678eSVladimir Oltean 					    struct dsa_bridge bridge)
3985961d6a1SVladimir Oltean {
3995961d6a1SVladimir Oltean 	/* Configure the port for standalone mode (no address learning,
4005961d6a1SVladimir Oltean 	 * flood everything).
4015961d6a1SVladimir Oltean 	 * The bridge only emits SWITCHDEV_ATTR_ID_PORT_BRIDGE_FLAGS events
4025961d6a1SVladimir Oltean 	 * when the user requests it through netlink or sysfs, but not
4035961d6a1SVladimir Oltean 	 * automatically at port join or leave, so we need to handle resetting
4045961d6a1SVladimir Oltean 	 * the brport flags ourselves. But we even prefer it that way, because
4055961d6a1SVladimir Oltean 	 * otherwise, some setups might never get the notification they need,
4065961d6a1SVladimir Oltean 	 * for example, when a port leaves a LAG that offloads the bridge,
4075961d6a1SVladimir Oltean 	 * it becomes standalone, but as far as the bridge is concerned, no
4085961d6a1SVladimir Oltean 	 * port ever left.
4095961d6a1SVladimir Oltean 	 */
4105961d6a1SVladimir Oltean 	dsa_port_clear_brport_flags(dp);
4115961d6a1SVladimir Oltean 
4125961d6a1SVladimir Oltean 	/* Port left the bridge, put in BR_STATE_DISABLED by the bridge layer,
4135961d6a1SVladimir Oltean 	 * so allow it to be in BR_STATE_FORWARDING to be kept functional
4145961d6a1SVladimir Oltean 	 */
41539f32101SVladimir Oltean 	dsa_port_set_state_now(dp, BR_STATE_FORWARDING, true);
416010e269fSVladimir Oltean 
4178e9e678eSVladimir Oltean 	dsa_port_reset_vlan_filtering(dp, bridge);
418010e269fSVladimir Oltean 
419010e269fSVladimir Oltean 	/* Ageing time may be global to the switch chip, so don't change it
420010e269fSVladimir Oltean 	 * here because we have no good reason (or value) to change it to.
421010e269fSVladimir Oltean 	 */
4225e38c158SVladimir Oltean }
4235e38c158SVladimir Oltean 
dsa_port_bridge_create(struct dsa_port * dp,struct net_device * br,struct netlink_ext_ack * extack)424947c8746SVladimir Oltean static int dsa_port_bridge_create(struct dsa_port *dp,
425947c8746SVladimir Oltean 				  struct net_device *br,
426947c8746SVladimir Oltean 				  struct netlink_ext_ack *extack)
427947c8746SVladimir Oltean {
428947c8746SVladimir Oltean 	struct dsa_switch *ds = dp->ds;
429d3eed0e5SVladimir Oltean 	struct dsa_bridge *bridge;
430947c8746SVladimir Oltean 
431d3eed0e5SVladimir Oltean 	bridge = dsa_tree_bridge_find(ds->dst, br);
432d3eed0e5SVladimir Oltean 	if (bridge) {
433d3eed0e5SVladimir Oltean 		refcount_inc(&bridge->refcount);
434d3eed0e5SVladimir Oltean 		dp->bridge = bridge;
435947c8746SVladimir Oltean 		return 0;
436d3eed0e5SVladimir Oltean 	}
437947c8746SVladimir Oltean 
438d3eed0e5SVladimir Oltean 	bridge = kzalloc(sizeof(*bridge), GFP_KERNEL);
439d3eed0e5SVladimir Oltean 	if (!bridge)
440d3eed0e5SVladimir Oltean 		return -ENOMEM;
441d3eed0e5SVladimir Oltean 
442d3eed0e5SVladimir Oltean 	refcount_set(&bridge->refcount, 1);
443d3eed0e5SVladimir Oltean 
444d3eed0e5SVladimir Oltean 	bridge->dev = br;
445d3eed0e5SVladimir Oltean 
446d3eed0e5SVladimir Oltean 	bridge->num = dsa_bridge_num_get(br, ds->max_num_bridges);
447d3eed0e5SVladimir Oltean 	if (ds->max_num_bridges && !bridge->num) {
448947c8746SVladimir Oltean 		NL_SET_ERR_MSG_MOD(extack,
449947c8746SVladimir Oltean 				   "Range of offloadable bridges exceeded");
450d3eed0e5SVladimir Oltean 		kfree(bridge);
451947c8746SVladimir Oltean 		return -EOPNOTSUPP;
452947c8746SVladimir Oltean 	}
453947c8746SVladimir Oltean 
454d3eed0e5SVladimir Oltean 	dp->bridge = bridge;
455947c8746SVladimir Oltean 
456947c8746SVladimir Oltean 	return 0;
457947c8746SVladimir Oltean }
458947c8746SVladimir Oltean 
dsa_port_bridge_destroy(struct dsa_port * dp,const struct net_device * br)459947c8746SVladimir Oltean static void dsa_port_bridge_destroy(struct dsa_port *dp,
460947c8746SVladimir Oltean 				    const struct net_device *br)
461947c8746SVladimir Oltean {
462d3eed0e5SVladimir Oltean 	struct dsa_bridge *bridge = dp->bridge;
463947c8746SVladimir Oltean 
464d3eed0e5SVladimir Oltean 	dp->bridge = NULL;
465947c8746SVladimir Oltean 
466d3eed0e5SVladimir Oltean 	if (!refcount_dec_and_test(&bridge->refcount))
467d3eed0e5SVladimir Oltean 		return;
468947c8746SVladimir Oltean 
469d3eed0e5SVladimir Oltean 	if (bridge->num)
470d3eed0e5SVladimir Oltean 		dsa_bridge_num_put(br, bridge->num);
471d3eed0e5SVladimir Oltean 
472d3eed0e5SVladimir Oltean 	kfree(bridge);
473123abc06SVladimir Oltean }
474123abc06SVladimir Oltean 
dsa_port_supports_mst(struct dsa_port * dp)475332afc4cSTobias Waldekranz static bool dsa_port_supports_mst(struct dsa_port *dp)
476332afc4cSTobias Waldekranz {
4778e6598a7STobias Waldekranz 	struct dsa_switch *ds = dp->ds;
4788e6598a7STobias Waldekranz 
4798e6598a7STobias Waldekranz 	return ds->ops->vlan_msti_set &&
4807414af30STobias Waldekranz 		ds->ops->port_mst_state_set &&
4817414af30STobias Waldekranz 		ds->ops->port_vlan_fast_age &&
4828e6598a7STobias Waldekranz 		dsa_port_can_configure_learning(dp);
483332afc4cSTobias Waldekranz }
484332afc4cSTobias Waldekranz 
dsa_port_bridge_join(struct dsa_port * dp,struct net_device * br,struct netlink_ext_ack * extack)4852afc526aSVladimir Oltean int dsa_port_bridge_join(struct dsa_port *dp, struct net_device *br,
4862afc526aSVladimir Oltean 			 struct netlink_ext_ack *extack)
487cfbed329SVivien Didelot {
488cfbed329SVivien Didelot 	struct dsa_notifier_bridge_info info = {
489726816a1SVladimir Oltean 		.dp = dp,
49006b9cce4SVladimir Oltean 		.extack = extack,
491cfbed329SVivien Didelot 	};
4922f5dc00fSVladimir Oltean 	struct net_device *dev = dp->slave;
4932f5dc00fSVladimir Oltean 	struct net_device *brport_dev;
494cfbed329SVivien Didelot 	int err;
495cfbed329SVivien Didelot 
496332afc4cSTobias Waldekranz 	if (br_mst_enabled(br) && !dsa_port_supports_mst(dp))
497332afc4cSTobias Waldekranz 		return -EOPNOTSUPP;
498332afc4cSTobias Waldekranz 
499c1388063SRussell King 	/* Here the interface is already bridged. Reflect the current
500c1388063SRussell King 	 * configuration so that drivers can program their chips accordingly.
501cfbed329SVivien Didelot 	 */
502947c8746SVladimir Oltean 	err = dsa_port_bridge_create(dp, br, extack);
503947c8746SVladimir Oltean 	if (err)
504947c8746SVladimir Oltean 		return err;
505cfbed329SVivien Didelot 
5062f5dc00fSVladimir Oltean 	brport_dev = dsa_port_to_bridge_port(dp);
5072f5dc00fSVladimir Oltean 
508d3eed0e5SVladimir Oltean 	info.bridge = *dp->bridge;
509f66a6a69SVladimir Oltean 	err = dsa_broadcast(DSA_NOTIFIER_BRIDGE_JOIN, &info);
5105961d6a1SVladimir Oltean 	if (err)
5115961d6a1SVladimir Oltean 		goto out_rollback;
512cfbed329SVivien Didelot 
513857fdd74SVladimir Oltean 	/* Drivers which support bridge TX forwarding should set this */
514857fdd74SVladimir Oltean 	dp->bridge->tx_fwd_offload = info.tx_fwd_offload;
515123abc06SVladimir Oltean 
5164e51bf44SVladimir Oltean 	err = switchdev_bridge_port_offload(brport_dev, dev, dp,
5174e51bf44SVladimir Oltean 					    &dsa_slave_switchdev_notifier,
5184e51bf44SVladimir Oltean 					    &dsa_slave_switchdev_blocking_notifier,
519857fdd74SVladimir Oltean 					    dp->bridge->tx_fwd_offload, extack);
5205961d6a1SVladimir Oltean 	if (err)
5215961d6a1SVladimir Oltean 		goto out_rollback_unbridge;
5225961d6a1SVladimir Oltean 
5234e51bf44SVladimir Oltean 	err = dsa_port_switchdev_sync_attrs(dp, extack);
5242f5dc00fSVladimir Oltean 	if (err)
5252f5dc00fSVladimir Oltean 		goto out_rollback_unoffload;
5262f5dc00fSVladimir Oltean 
5275961d6a1SVladimir Oltean 	return 0;
5285961d6a1SVladimir Oltean 
5292f5dc00fSVladimir Oltean out_rollback_unoffload:
5304e51bf44SVladimir Oltean 	switchdev_bridge_port_unoffload(brport_dev, dp,
5314e51bf44SVladimir Oltean 					&dsa_slave_switchdev_notifier,
5324e51bf44SVladimir Oltean 					&dsa_slave_switchdev_blocking_notifier);
533630fd482SVladimir Oltean 	dsa_flush_workqueue();
5345961d6a1SVladimir Oltean out_rollback_unbridge:
5355961d6a1SVladimir Oltean 	dsa_broadcast(DSA_NOTIFIER_BRIDGE_LEAVE, &info);
5365961d6a1SVladimir Oltean out_rollback:
537947c8746SVladimir Oltean 	dsa_port_bridge_destroy(dp, br);
538cfbed329SVivien Didelot 	return err;
539cfbed329SVivien Didelot }
540cfbed329SVivien Didelot 
dsa_port_pre_bridge_leave(struct dsa_port * dp,struct net_device * br)5414e51bf44SVladimir Oltean void dsa_port_pre_bridge_leave(struct dsa_port *dp, struct net_device *br)
54274918945SVladimir Oltean {
5432f5dc00fSVladimir Oltean 	struct net_device *brport_dev = dsa_port_to_bridge_port(dp);
5442f5dc00fSVladimir Oltean 
54509dba21bSVladimir Oltean 	/* Don't try to unoffload something that is not offloaded */
54609dba21bSVladimir Oltean 	if (!brport_dev)
54709dba21bSVladimir Oltean 		return;
54809dba21bSVladimir Oltean 
5494e51bf44SVladimir Oltean 	switchdev_bridge_port_unoffload(brport_dev, dp,
5504e51bf44SVladimir Oltean 					&dsa_slave_switchdev_notifier,
5514e51bf44SVladimir Oltean 					&dsa_slave_switchdev_blocking_notifier);
552d7d0d423SVladimir Oltean 
553d7d0d423SVladimir Oltean 	dsa_flush_workqueue();
55474918945SVladimir Oltean }
55574918945SVladimir Oltean 
dsa_port_bridge_leave(struct dsa_port * dp,struct net_device * br)556cfbed329SVivien Didelot void dsa_port_bridge_leave(struct dsa_port *dp, struct net_device *br)
557cfbed329SVivien Didelot {
558cfbed329SVivien Didelot 	struct dsa_notifier_bridge_info info = {
559726816a1SVladimir Oltean 		.dp = dp,
560cfbed329SVivien Didelot 	};
561cfbed329SVivien Didelot 	int err;
562cfbed329SVivien Didelot 
563342b6419SAlvin Šipraga 	/* If the port could not be offloaded to begin with, then
564342b6419SAlvin Šipraga 	 * there is nothing to do.
565342b6419SAlvin Šipraga 	 */
566342b6419SAlvin Šipraga 	if (!dp->bridge)
567342b6419SAlvin Šipraga 		return;
568342b6419SAlvin Šipraga 
569342b6419SAlvin Šipraga 	info.bridge = *dp->bridge;
570342b6419SAlvin Šipraga 
571cfbed329SVivien Didelot 	/* Here the port is already unbridged. Reflect the current configuration
572cfbed329SVivien Didelot 	 * so that drivers can program their chips accordingly.
573cfbed329SVivien Didelot 	 */
574947c8746SVladimir Oltean 	dsa_port_bridge_destroy(dp, br);
575cfbed329SVivien Didelot 
576f66a6a69SVladimir Oltean 	err = dsa_broadcast(DSA_NOTIFIER_BRIDGE_LEAVE, &info);
577cfbed329SVivien Didelot 	if (err)
578ab97462bSVladimir Oltean 		dev_err(dp->ds->dev,
579ab97462bSVladimir Oltean 			"port %d failed to notify DSA_NOTIFIER_BRIDGE_LEAVE: %pe\n",
580ab97462bSVladimir Oltean 			dp->index, ERR_PTR(err));
581cfbed329SVivien Didelot 
5828e9e678eSVladimir Oltean 	dsa_port_switchdev_unsync_attrs(dp, info.bridge);
583cfbed329SVivien Didelot }
5844d61d304SVivien Didelot 
dsa_port_lag_change(struct dsa_port * dp,struct netdev_lag_lower_state_info * linfo)585058102a6STobias Waldekranz int dsa_port_lag_change(struct dsa_port *dp,
586058102a6STobias Waldekranz 			struct netdev_lag_lower_state_info *linfo)
587058102a6STobias Waldekranz {
588058102a6STobias Waldekranz 	struct dsa_notifier_lag_info info = {
589726816a1SVladimir Oltean 		.dp = dp,
590058102a6STobias Waldekranz 	};
591058102a6STobias Waldekranz 	bool tx_enabled;
592058102a6STobias Waldekranz 
593dedd6a00SVladimir Oltean 	if (!dp->lag)
594058102a6STobias Waldekranz 		return 0;
595058102a6STobias Waldekranz 
596058102a6STobias Waldekranz 	/* On statically configured aggregates (e.g. loadbalance
597058102a6STobias Waldekranz 	 * without LACP) ports will always be tx_enabled, even if the
598058102a6STobias Waldekranz 	 * link is down. Thus we require both link_up and tx_enabled
599058102a6STobias Waldekranz 	 * in order to include it in the tx set.
600058102a6STobias Waldekranz 	 */
601058102a6STobias Waldekranz 	tx_enabled = linfo->link_up && linfo->tx_enabled;
602058102a6STobias Waldekranz 
603058102a6STobias Waldekranz 	if (tx_enabled == dp->lag_tx_enabled)
604058102a6STobias Waldekranz 		return 0;
605058102a6STobias Waldekranz 
606058102a6STobias Waldekranz 	dp->lag_tx_enabled = tx_enabled;
607058102a6STobias Waldekranz 
608058102a6STobias Waldekranz 	return dsa_port_notify(dp, DSA_NOTIFIER_LAG_CHANGE, &info);
609058102a6STobias Waldekranz }
610058102a6STobias Waldekranz 
dsa_port_lag_create(struct dsa_port * dp,struct net_device * lag_dev)611dedd6a00SVladimir Oltean static int dsa_port_lag_create(struct dsa_port *dp,
612dedd6a00SVladimir Oltean 			       struct net_device *lag_dev)
613dedd6a00SVladimir Oltean {
614dedd6a00SVladimir Oltean 	struct dsa_switch *ds = dp->ds;
615dedd6a00SVladimir Oltean 	struct dsa_lag *lag;
616dedd6a00SVladimir Oltean 
617dedd6a00SVladimir Oltean 	lag = dsa_tree_lag_find(ds->dst, lag_dev);
618dedd6a00SVladimir Oltean 	if (lag) {
619dedd6a00SVladimir Oltean 		refcount_inc(&lag->refcount);
620dedd6a00SVladimir Oltean 		dp->lag = lag;
621dedd6a00SVladimir Oltean 		return 0;
622dedd6a00SVladimir Oltean 	}
623dedd6a00SVladimir Oltean 
624dedd6a00SVladimir Oltean 	lag = kzalloc(sizeof(*lag), GFP_KERNEL);
625dedd6a00SVladimir Oltean 	if (!lag)
626dedd6a00SVladimir Oltean 		return -ENOMEM;
627dedd6a00SVladimir Oltean 
628dedd6a00SVladimir Oltean 	refcount_set(&lag->refcount, 1);
629e212fa7cSVladimir Oltean 	mutex_init(&lag->fdb_lock);
630e212fa7cSVladimir Oltean 	INIT_LIST_HEAD(&lag->fdbs);
631dedd6a00SVladimir Oltean 	lag->dev = lag_dev;
632dedd6a00SVladimir Oltean 	dsa_lag_map(ds->dst, lag);
633dedd6a00SVladimir Oltean 	dp->lag = lag;
634dedd6a00SVladimir Oltean 
635dedd6a00SVladimir Oltean 	return 0;
636dedd6a00SVladimir Oltean }
637dedd6a00SVladimir Oltean 
dsa_port_lag_destroy(struct dsa_port * dp)638dedd6a00SVladimir Oltean static void dsa_port_lag_destroy(struct dsa_port *dp)
639dedd6a00SVladimir Oltean {
640dedd6a00SVladimir Oltean 	struct dsa_lag *lag = dp->lag;
641dedd6a00SVladimir Oltean 
642dedd6a00SVladimir Oltean 	dp->lag = NULL;
643dedd6a00SVladimir Oltean 	dp->lag_tx_enabled = false;
644dedd6a00SVladimir Oltean 
645dedd6a00SVladimir Oltean 	if (!refcount_dec_and_test(&lag->refcount))
646dedd6a00SVladimir Oltean 		return;
647dedd6a00SVladimir Oltean 
648e212fa7cSVladimir Oltean 	WARN_ON(!list_empty(&lag->fdbs));
649dedd6a00SVladimir Oltean 	dsa_lag_unmap(dp->ds->dst, lag);
650dedd6a00SVladimir Oltean 	kfree(lag);
651dedd6a00SVladimir Oltean }
652dedd6a00SVladimir Oltean 
dsa_port_lag_join(struct dsa_port * dp,struct net_device * lag_dev,struct netdev_lag_upper_info * uinfo,struct netlink_ext_ack * extack)65346a76724SVladimir Oltean int dsa_port_lag_join(struct dsa_port *dp, struct net_device *lag_dev,
6542afc526aSVladimir Oltean 		      struct netdev_lag_upper_info *uinfo,
6552afc526aSVladimir Oltean 		      struct netlink_ext_ack *extack)
656058102a6STobias Waldekranz {
657058102a6STobias Waldekranz 	struct dsa_notifier_lag_info info = {
658726816a1SVladimir Oltean 		.dp = dp,
659058102a6STobias Waldekranz 		.info = uinfo,
6602e359b00SVladimir Oltean 		.extack = extack,
661058102a6STobias Waldekranz 	};
662185c9a76SVladimir Oltean 	struct net_device *bridge_dev;
663058102a6STobias Waldekranz 	int err;
664058102a6STobias Waldekranz 
665dedd6a00SVladimir Oltean 	err = dsa_port_lag_create(dp, lag_dev);
666dedd6a00SVladimir Oltean 	if (err)
667dedd6a00SVladimir Oltean 		goto err_lag_create;
668058102a6STobias Waldekranz 
669dedd6a00SVladimir Oltean 	info.lag = *dp->lag;
670058102a6STobias Waldekranz 	err = dsa_port_notify(dp, DSA_NOTIFIER_LAG_JOIN, &info);
671185c9a76SVladimir Oltean 	if (err)
672185c9a76SVladimir Oltean 		goto err_lag_join;
673185c9a76SVladimir Oltean 
67446a76724SVladimir Oltean 	bridge_dev = netdev_master_upper_dev_get(lag_dev);
675185c9a76SVladimir Oltean 	if (!bridge_dev || !netif_is_bridge_master(bridge_dev))
676185c9a76SVladimir Oltean 		return 0;
677185c9a76SVladimir Oltean 
6782afc526aSVladimir Oltean 	err = dsa_port_bridge_join(dp, bridge_dev, extack);
679185c9a76SVladimir Oltean 	if (err)
680185c9a76SVladimir Oltean 		goto err_bridge_join;
681185c9a76SVladimir Oltean 
682185c9a76SVladimir Oltean 	return 0;
683185c9a76SVladimir Oltean 
684185c9a76SVladimir Oltean err_bridge_join:
685185c9a76SVladimir Oltean 	dsa_port_notify(dp, DSA_NOTIFIER_LAG_LEAVE, &info);
686185c9a76SVladimir Oltean err_lag_join:
687dedd6a00SVladimir Oltean 	dsa_port_lag_destroy(dp);
688dedd6a00SVladimir Oltean err_lag_create:
689058102a6STobias Waldekranz 	return err;
690058102a6STobias Waldekranz }
691058102a6STobias Waldekranz 
dsa_port_pre_lag_leave(struct dsa_port * dp,struct net_device * lag_dev)69246a76724SVladimir Oltean void dsa_port_pre_lag_leave(struct dsa_port *dp, struct net_device *lag_dev)
69374918945SVladimir Oltean {
69436cbf39bSVladimir Oltean 	struct net_device *br = dsa_port_bridge_dev_get(dp);
69536cbf39bSVladimir Oltean 
69636cbf39bSVladimir Oltean 	if (br)
69736cbf39bSVladimir Oltean 		dsa_port_pre_bridge_leave(dp, br);
69874918945SVladimir Oltean }
69974918945SVladimir Oltean 
dsa_port_lag_leave(struct dsa_port * dp,struct net_device * lag_dev)70046a76724SVladimir Oltean void dsa_port_lag_leave(struct dsa_port *dp, struct net_device *lag_dev)
701058102a6STobias Waldekranz {
70236cbf39bSVladimir Oltean 	struct net_device *br = dsa_port_bridge_dev_get(dp);
703058102a6STobias Waldekranz 	struct dsa_notifier_lag_info info = {
704726816a1SVladimir Oltean 		.dp = dp,
705058102a6STobias Waldekranz 	};
706058102a6STobias Waldekranz 	int err;
707058102a6STobias Waldekranz 
708dedd6a00SVladimir Oltean 	if (!dp->lag)
709058102a6STobias Waldekranz 		return;
710058102a6STobias Waldekranz 
711058102a6STobias Waldekranz 	/* Port might have been part of a LAG that in turn was
712058102a6STobias Waldekranz 	 * attached to a bridge.
713058102a6STobias Waldekranz 	 */
71436cbf39bSVladimir Oltean 	if (br)
71536cbf39bSVladimir Oltean 		dsa_port_bridge_leave(dp, br);
716058102a6STobias Waldekranz 
717dedd6a00SVladimir Oltean 	info.lag = *dp->lag;
718dedd6a00SVladimir Oltean 
719dedd6a00SVladimir Oltean 	dsa_port_lag_destroy(dp);
720058102a6STobias Waldekranz 
721058102a6STobias Waldekranz 	err = dsa_port_notify(dp, DSA_NOTIFIER_LAG_LEAVE, &info);
722058102a6STobias Waldekranz 	if (err)
723ab97462bSVladimir Oltean 		dev_err(dp->ds->dev,
724ab97462bSVladimir Oltean 			"port %d failed to notify DSA_NOTIFIER_LAG_LEAVE: %pe\n",
725ab97462bSVladimir Oltean 			dp->index, ERR_PTR(err));
726058102a6STobias Waldekranz }
727058102a6STobias Waldekranz 
728adb256ebSVladimir Oltean /* Must be called under rcu_read_lock() */
dsa_port_can_apply_vlan_filtering(struct dsa_port * dp,bool vlan_filtering,struct netlink_ext_ack * extack)7298f5d16f6SVladimir Oltean static bool dsa_port_can_apply_vlan_filtering(struct dsa_port *dp,
73089153ed6SVladimir Oltean 					      bool vlan_filtering,
73189153ed6SVladimir Oltean 					      struct netlink_ext_ack *extack)
7328f5d16f6SVladimir Oltean {
7338f5d16f6SVladimir Oltean 	struct dsa_switch *ds = dp->ds;
734d0004a02SVladimir Oltean 	struct dsa_port *other_dp;
735d0004a02SVladimir Oltean 	int err;
736adb256ebSVladimir Oltean 
737adb256ebSVladimir Oltean 	/* VLAN awareness was off, so the question is "can we turn it on".
738adb256ebSVladimir Oltean 	 * We may have had 8021q uppers, those need to go. Make sure we don't
739adb256ebSVladimir Oltean 	 * enter an inconsistent state: deny changing the VLAN awareness state
740adb256ebSVladimir Oltean 	 * as long as we have 8021q uppers.
741adb256ebSVladimir Oltean 	 */
74257d77986SVladimir Oltean 	if (vlan_filtering && dsa_port_is_user(dp)) {
74336cbf39bSVladimir Oltean 		struct net_device *br = dsa_port_bridge_dev_get(dp);
744adb256ebSVladimir Oltean 		struct net_device *upper_dev, *slave = dp->slave;
745adb256ebSVladimir Oltean 		struct list_head *iter;
746adb256ebSVladimir Oltean 
747adb256ebSVladimir Oltean 		netdev_for_each_upper_dev_rcu(slave, upper_dev, iter) {
748adb256ebSVladimir Oltean 			struct bridge_vlan_info br_info;
749adb256ebSVladimir Oltean 			u16 vid;
750adb256ebSVladimir Oltean 
751adb256ebSVladimir Oltean 			if (!is_vlan_dev(upper_dev))
752adb256ebSVladimir Oltean 				continue;
753adb256ebSVladimir Oltean 
754adb256ebSVladimir Oltean 			vid = vlan_dev_vlan_id(upper_dev);
755adb256ebSVladimir Oltean 
756adb256ebSVladimir Oltean 			/* br_vlan_get_info() returns -EINVAL or -ENOENT if the
757adb256ebSVladimir Oltean 			 * device, respectively the VID is not found, returning
758adb256ebSVladimir Oltean 			 * 0 means success, which is a failure for us here.
759adb256ebSVladimir Oltean 			 */
760adb256ebSVladimir Oltean 			err = br_vlan_get_info(br, vid, &br_info);
761adb256ebSVladimir Oltean 			if (err == 0) {
76289153ed6SVladimir Oltean 				NL_SET_ERR_MSG_MOD(extack,
76389153ed6SVladimir Oltean 						   "Must first remove VLAN uppers having VIDs also present in bridge");
764adb256ebSVladimir Oltean 				return false;
765adb256ebSVladimir Oltean 			}
766adb256ebSVladimir Oltean 		}
767adb256ebSVladimir Oltean 	}
7688f5d16f6SVladimir Oltean 
7698f5d16f6SVladimir Oltean 	if (!ds->vlan_filtering_is_global)
7708f5d16f6SVladimir Oltean 		return true;
7718f5d16f6SVladimir Oltean 
7728f5d16f6SVladimir Oltean 	/* For cases where enabling/disabling VLAN awareness is global to the
7738f5d16f6SVladimir Oltean 	 * switch, we need to handle the case where multiple bridges span
7748f5d16f6SVladimir Oltean 	 * different ports of the same switch device and one of them has a
7758f5d16f6SVladimir Oltean 	 * different setting than what is being requested.
7768f5d16f6SVladimir Oltean 	 */
777d0004a02SVladimir Oltean 	dsa_switch_for_each_port(other_dp, ds) {
77836cbf39bSVladimir Oltean 		struct net_device *other_br = dsa_port_bridge_dev_get(other_dp);
7798f5d16f6SVladimir Oltean 
7808f5d16f6SVladimir Oltean 		/* If it's the same bridge, it also has same
7818f5d16f6SVladimir Oltean 		 * vlan_filtering setting => no need to check
7828f5d16f6SVladimir Oltean 		 */
78336cbf39bSVladimir Oltean 		if (!other_br || other_br == dsa_port_bridge_dev_get(dp))
7848f5d16f6SVladimir Oltean 			continue;
78536cbf39bSVladimir Oltean 
78636cbf39bSVladimir Oltean 		if (br_vlan_enabled(other_br) != vlan_filtering) {
78789153ed6SVladimir Oltean 			NL_SET_ERR_MSG_MOD(extack,
78889153ed6SVladimir Oltean 					   "VLAN filtering is a global setting");
7898f5d16f6SVladimir Oltean 			return false;
7908f5d16f6SVladimir Oltean 		}
7918f5d16f6SVladimir Oltean 	}
7928f5d16f6SVladimir Oltean 	return true;
7938f5d16f6SVladimir Oltean }
7948f5d16f6SVladimir Oltean 
dsa_port_vlan_filtering(struct dsa_port * dp,bool vlan_filtering,struct netlink_ext_ack * extack)79589153ed6SVladimir Oltean int dsa_port_vlan_filtering(struct dsa_port *dp, bool vlan_filtering,
79689153ed6SVladimir Oltean 			    struct netlink_ext_ack *extack)
7974d61d304SVivien Didelot {
79806cfb2dfSVladimir Oltean 	bool old_vlan_filtering = dsa_port_is_vlan_filtering(dp);
7994d61d304SVivien Didelot 	struct dsa_switch *ds = dp->ds;
800adb256ebSVladimir Oltean 	bool apply;
801bae33f2bSVladimir Oltean 	int err;
802adb256ebSVladimir Oltean 
8038f5d16f6SVladimir Oltean 	if (!ds->ops->port_vlan_filtering)
804707ec383SVladimir Oltean 		return -EOPNOTSUPP;
8058f5d16f6SVladimir Oltean 
806adb256ebSVladimir Oltean 	/* We are called from dsa_slave_switchdev_blocking_event(),
807adb256ebSVladimir Oltean 	 * which is not under rcu_read_lock(), unlike
808adb256ebSVladimir Oltean 	 * dsa_slave_switchdev_event().
809adb256ebSVladimir Oltean 	 */
810adb256ebSVladimir Oltean 	rcu_read_lock();
81189153ed6SVladimir Oltean 	apply = dsa_port_can_apply_vlan_filtering(dp, vlan_filtering, extack);
812adb256ebSVladimir Oltean 	rcu_read_unlock();
813adb256ebSVladimir Oltean 	if (!apply)
8148f5d16f6SVladimir Oltean 		return -EINVAL;
815707ec383SVladimir Oltean 
816ec9121e7SVladimir Oltean 	if (dsa_port_is_vlan_filtering(dp) == vlan_filtering)
817ec9121e7SVladimir Oltean 		return 0;
818ec9121e7SVladimir Oltean 
81989153ed6SVladimir Oltean 	err = ds->ops->port_vlan_filtering(ds, dp->index, vlan_filtering,
82089153ed6SVladimir Oltean 					   extack);
82133162e9aSVladimir Oltean 	if (err)
82233162e9aSVladimir Oltean 		return err;
8238f5d16f6SVladimir Oltean 
82406cfb2dfSVladimir Oltean 	if (ds->vlan_filtering_is_global) {
825d0004a02SVladimir Oltean 		struct dsa_port *other_dp;
82606cfb2dfSVladimir Oltean 
82714574676SVladimir Oltean 		ds->vlan_filtering = vlan_filtering;
82806cfb2dfSVladimir Oltean 
829d0004a02SVladimir Oltean 		dsa_switch_for_each_user_port(other_dp, ds) {
8304db2a5efSVladimir Oltean 			struct net_device *slave = other_dp->slave;
83106cfb2dfSVladimir Oltean 
83206cfb2dfSVladimir Oltean 			/* We might be called in the unbind path, so not
83306cfb2dfSVladimir Oltean 			 * all slave devices might still be registered.
83406cfb2dfSVladimir Oltean 			 */
83506cfb2dfSVladimir Oltean 			if (!slave)
83606cfb2dfSVladimir Oltean 				continue;
83706cfb2dfSVladimir Oltean 
83806cfb2dfSVladimir Oltean 			err = dsa_slave_manage_vlan_filtering(slave,
83906cfb2dfSVladimir Oltean 							      vlan_filtering);
84006cfb2dfSVladimir Oltean 			if (err)
84106cfb2dfSVladimir Oltean 				goto restore;
84206cfb2dfSVladimir Oltean 		}
84306cfb2dfSVladimir Oltean 	} else {
84433162e9aSVladimir Oltean 		dp->vlan_filtering = vlan_filtering;
8452e554a7aSVladimir Oltean 
84606cfb2dfSVladimir Oltean 		err = dsa_slave_manage_vlan_filtering(dp->slave,
84706cfb2dfSVladimir Oltean 						      vlan_filtering);
84806cfb2dfSVladimir Oltean 		if (err)
84906cfb2dfSVladimir Oltean 			goto restore;
85006cfb2dfSVladimir Oltean 	}
85106cfb2dfSVladimir Oltean 
8524d61d304SVivien Didelot 	return 0;
85306cfb2dfSVladimir Oltean 
85406cfb2dfSVladimir Oltean restore:
85506cfb2dfSVladimir Oltean 	ds->ops->port_vlan_filtering(ds, dp->index, old_vlan_filtering, NULL);
85606cfb2dfSVladimir Oltean 
85706cfb2dfSVladimir Oltean 	if (ds->vlan_filtering_is_global)
85806cfb2dfSVladimir Oltean 		ds->vlan_filtering = old_vlan_filtering;
85906cfb2dfSVladimir Oltean 	else
86006cfb2dfSVladimir Oltean 		dp->vlan_filtering = old_vlan_filtering;
86106cfb2dfSVladimir Oltean 
86206cfb2dfSVladimir Oltean 	return err;
8634d61d304SVivien Didelot }
864d87bd94eSVivien Didelot 
86554a0ed0dSRussell King /* This enforces legacy behavior for switch drivers which assume they can't
86654a0ed0dSRussell King  * receive VLAN configuration when enslaved to a bridge with vlan_filtering=0
86754a0ed0dSRussell King  */
dsa_port_skip_vlan_configuration(struct dsa_port * dp)86854a0ed0dSRussell King bool dsa_port_skip_vlan_configuration(struct dsa_port *dp)
86954a0ed0dSRussell King {
87036cbf39bSVladimir Oltean 	struct net_device *br = dsa_port_bridge_dev_get(dp);
87154a0ed0dSRussell King 	struct dsa_switch *ds = dp->ds;
87254a0ed0dSRussell King 
87336cbf39bSVladimir Oltean 	if (!br)
87454a0ed0dSRussell King 		return false;
87554a0ed0dSRussell King 
87636cbf39bSVladimir Oltean 	return !ds->configure_vlan_while_not_filtering && !br_vlan_enabled(br);
87754a0ed0dSRussell King }
87854a0ed0dSRussell King 
dsa_port_ageing_time(struct dsa_port * dp,clock_t ageing_clock)879bae33f2bSVladimir Oltean int dsa_port_ageing_time(struct dsa_port *dp, clock_t ageing_clock)
880d87bd94eSVivien Didelot {
881d87bd94eSVivien Didelot 	unsigned long ageing_jiffies = clock_t_to_jiffies(ageing_clock);
882d87bd94eSVivien Didelot 	unsigned int ageing_time = jiffies_to_msecs(ageing_jiffies);
883bae33f2bSVladimir Oltean 	struct dsa_notifier_ageing_time_info info;
884bae33f2bSVladimir Oltean 	int err;
885d87bd94eSVivien Didelot 
886bae33f2bSVladimir Oltean 	info.ageing_time = ageing_time;
887bae33f2bSVladimir Oltean 
888bae33f2bSVladimir Oltean 	err = dsa_port_notify(dp, DSA_NOTIFIER_AGEING_TIME, &info);
889bae33f2bSVladimir Oltean 	if (err)
890bae33f2bSVladimir Oltean 		return err;
891d87bd94eSVivien Didelot 
892d87bd94eSVivien Didelot 	dp->ageing_time = ageing_time;
893d87bd94eSVivien Didelot 
89477b61365SVladimir Oltean 	return 0;
895d87bd94eSVivien Didelot }
896d1cffff0SVivien Didelot 
dsa_port_mst_enable(struct dsa_port * dp,bool on,struct netlink_ext_ack * extack)897332afc4cSTobias Waldekranz int dsa_port_mst_enable(struct dsa_port *dp, bool on,
898332afc4cSTobias Waldekranz 			struct netlink_ext_ack *extack)
899332afc4cSTobias Waldekranz {
9007414af30STobias Waldekranz 	if (on && !dsa_port_supports_mst(dp)) {
901332afc4cSTobias Waldekranz 		NL_SET_ERR_MSG_MOD(extack, "Hardware does not support MST");
902332afc4cSTobias Waldekranz 		return -EINVAL;
903332afc4cSTobias Waldekranz 	}
904332afc4cSTobias Waldekranz 
905332afc4cSTobias Waldekranz 	return 0;
906332afc4cSTobias Waldekranz }
907332afc4cSTobias Waldekranz 
dsa_port_pre_bridge_flags(const struct dsa_port * dp,struct switchdev_brport_flags flags,struct netlink_ext_ack * extack)908e18f4c18SVladimir Oltean int dsa_port_pre_bridge_flags(const struct dsa_port *dp,
909a8b659e7SVladimir Oltean 			      struct switchdev_brport_flags flags,
910a8b659e7SVladimir Oltean 			      struct netlink_ext_ack *extack)
911ea87005aSFlorian Fainelli {
912ea87005aSFlorian Fainelli 	struct dsa_switch *ds = dp->ds;
913ea87005aSFlorian Fainelli 
914a8b659e7SVladimir Oltean 	if (!ds->ops->port_pre_bridge_flags)
915ea87005aSFlorian Fainelli 		return -EINVAL;
916ea87005aSFlorian Fainelli 
917a8b659e7SVladimir Oltean 	return ds->ops->port_pre_bridge_flags(ds, dp->index, flags, extack);
918ea87005aSFlorian Fainelli }
919ea87005aSFlorian Fainelli 
dsa_port_bridge_flags(struct dsa_port * dp,struct switchdev_brport_flags flags,struct netlink_ext_ack * extack)920045c45d1SVladimir Oltean int dsa_port_bridge_flags(struct dsa_port *dp,
921a8b659e7SVladimir Oltean 			  struct switchdev_brport_flags flags,
922a8b659e7SVladimir Oltean 			  struct netlink_ext_ack *extack)
92357652796SRussell King {
92457652796SRussell King 	struct dsa_switch *ds = dp->ds;
925045c45d1SVladimir Oltean 	int err;
92657652796SRussell King 
927a8b659e7SVladimir Oltean 	if (!ds->ops->port_bridge_flags)
92870a7c484SOleksij Rempel 		return -EOPNOTSUPP;
92957652796SRussell King 
930045c45d1SVladimir Oltean 	err = ds->ops->port_bridge_flags(ds, dp->index, flags, extack);
931045c45d1SVladimir Oltean 	if (err)
932045c45d1SVladimir Oltean 		return err;
933045c45d1SVladimir Oltean 
934045c45d1SVladimir Oltean 	if (flags.mask & BR_LEARNING) {
935045c45d1SVladimir Oltean 		bool learning = flags.val & BR_LEARNING;
936045c45d1SVladimir Oltean 
937045c45d1SVladimir Oltean 		if (learning == dp->learning)
938045c45d1SVladimir Oltean 			return 0;
939045c45d1SVladimir Oltean 
940bee7c577SVladimir Oltean 		if ((dp->learning && !learning) &&
941bee7c577SVladimir Oltean 		    (dp->stp_state == BR_STATE_LEARNING ||
942bee7c577SVladimir Oltean 		     dp->stp_state == BR_STATE_FORWARDING))
943045c45d1SVladimir Oltean 			dsa_port_fast_age(dp);
944045c45d1SVladimir Oltean 
945045c45d1SVladimir Oltean 		dp->learning = learning;
946045c45d1SVladimir Oltean 	}
947045c45d1SVladimir Oltean 
948045c45d1SVladimir Oltean 	return 0;
94957652796SRussell King }
95057652796SRussell King 
dsa_port_set_host_flood(struct dsa_port * dp,bool uc,bool mc)95172c3b0c7SVladimir Oltean void dsa_port_set_host_flood(struct dsa_port *dp, bool uc, bool mc)
95272c3b0c7SVladimir Oltean {
95372c3b0c7SVladimir Oltean 	struct dsa_switch *ds = dp->ds;
95472c3b0c7SVladimir Oltean 
95572c3b0c7SVladimir Oltean 	if (ds->ops->port_set_host_flood)
95672c3b0c7SVladimir Oltean 		ds->ops->port_set_host_flood(ds, dp->index, uc, mc);
95772c3b0c7SVladimir Oltean }
95872c3b0c7SVladimir Oltean 
dsa_port_vlan_msti(struct dsa_port * dp,const struct switchdev_vlan_msti * msti)9598e6598a7STobias Waldekranz int dsa_port_vlan_msti(struct dsa_port *dp,
9608e6598a7STobias Waldekranz 		       const struct switchdev_vlan_msti *msti)
9618e6598a7STobias Waldekranz {
9628e6598a7STobias Waldekranz 	struct dsa_switch *ds = dp->ds;
9638e6598a7STobias Waldekranz 
9648e6598a7STobias Waldekranz 	if (!ds->ops->vlan_msti_set)
9658e6598a7STobias Waldekranz 		return -EOPNOTSUPP;
9668e6598a7STobias Waldekranz 
9678e6598a7STobias Waldekranz 	return ds->ops->vlan_msti_set(ds, *dp->bridge, msti);
9688e6598a7STobias Waldekranz }
9698e6598a7STobias Waldekranz 
dsa_port_mtu_change(struct dsa_port * dp,int new_mtu)970be6ff966SVladimir Oltean int dsa_port_mtu_change(struct dsa_port *dp, int new_mtu)
971bfcb8132SVladimir Oltean {
972bfcb8132SVladimir Oltean 	struct dsa_notifier_mtu_info info = {
973726816a1SVladimir Oltean 		.dp = dp,
974bfcb8132SVladimir Oltean 		.mtu = new_mtu,
975bfcb8132SVladimir Oltean 	};
976bfcb8132SVladimir Oltean 
977bfcb8132SVladimir Oltean 	return dsa_port_notify(dp, DSA_NOTIFIER_MTU, &info);
978bfcb8132SVladimir Oltean }
979bfcb8132SVladimir Oltean 
dsa_port_fdb_add(struct dsa_port * dp,const unsigned char * addr,u16 vid)9802acf4e6aSArkadi Sharshevsky int dsa_port_fdb_add(struct dsa_port *dp, const unsigned char *addr,
9812acf4e6aSArkadi Sharshevsky 		     u16 vid)
982d1cffff0SVivien Didelot {
983685fb6a4SVivien Didelot 	struct dsa_notifier_fdb_info info = {
984726816a1SVladimir Oltean 		.dp = dp,
9852acf4e6aSArkadi Sharshevsky 		.addr = addr,
9862acf4e6aSArkadi Sharshevsky 		.vid = vid,
987c2693363SVladimir Oltean 		.db = {
988c2693363SVladimir Oltean 			.type = DSA_DB_BRIDGE,
989c2693363SVladimir Oltean 			.bridge = *dp->bridge,
990c2693363SVladimir Oltean 		},
991685fb6a4SVivien Didelot 	};
992d1cffff0SVivien Didelot 
993c2693363SVladimir Oltean 	/* Refcounting takes bridge.num as a key, and should be global for all
994c2693363SVladimir Oltean 	 * bridges in the absence of FDB isolation, and per bridge otherwise.
995c2693363SVladimir Oltean 	 * Force the bridge.num to zero here in the absence of FDB isolation.
996c2693363SVladimir Oltean 	 */
997c2693363SVladimir Oltean 	if (!dp->ds->fdb_isolation)
998c2693363SVladimir Oltean 		info.db.bridge.num = 0;
999c2693363SVladimir Oltean 
1000685fb6a4SVivien Didelot 	return dsa_port_notify(dp, DSA_NOTIFIER_FDB_ADD, &info);
1001d1cffff0SVivien Didelot }
1002d1cffff0SVivien Didelot 
dsa_port_fdb_del(struct dsa_port * dp,const unsigned char * addr,u16 vid)10032acf4e6aSArkadi Sharshevsky int dsa_port_fdb_del(struct dsa_port *dp, const unsigned char *addr,
10042acf4e6aSArkadi Sharshevsky 		     u16 vid)
1005d1cffff0SVivien Didelot {
1006685fb6a4SVivien Didelot 	struct dsa_notifier_fdb_info info = {
1007726816a1SVladimir Oltean 		.dp = dp,
10082acf4e6aSArkadi Sharshevsky 		.addr = addr,
10092acf4e6aSArkadi Sharshevsky 		.vid = vid,
1010c2693363SVladimir Oltean 		.db = {
1011c2693363SVladimir Oltean 			.type = DSA_DB_BRIDGE,
1012c2693363SVladimir Oltean 			.bridge = *dp->bridge,
1013c2693363SVladimir Oltean 		},
1014685fb6a4SVivien Didelot 	};
1015d1cffff0SVivien Didelot 
1016c2693363SVladimir Oltean 	if (!dp->ds->fdb_isolation)
1017c2693363SVladimir Oltean 		info.db.bridge.num = 0;
1018c2693363SVladimir Oltean 
1019685fb6a4SVivien Didelot 	return dsa_port_notify(dp, DSA_NOTIFIER_FDB_DEL, &info);
1020d1cffff0SVivien Didelot }
1021d1cffff0SVivien Didelot 
dsa_port_host_fdb_add(struct dsa_port * dp,const unsigned char * addr,u16 vid,struct dsa_db db)10225e8a1e03SVladimir Oltean static int dsa_port_host_fdb_add(struct dsa_port *dp,
10235e8a1e03SVladimir Oltean 				 const unsigned char *addr, u16 vid,
10245e8a1e03SVladimir Oltean 				 struct dsa_db db)
10253dc80afcSVladimir Oltean {
10263dc80afcSVladimir Oltean 	struct dsa_notifier_fdb_info info = {
1027726816a1SVladimir Oltean 		.dp = dp,
10283dc80afcSVladimir Oltean 		.addr = addr,
10293dc80afcSVladimir Oltean 		.vid = vid,
10305e8a1e03SVladimir Oltean 		.db = db,
10315e8a1e03SVladimir Oltean 	};
10325e8a1e03SVladimir Oltean 
10335e8a1e03SVladimir Oltean 	return dsa_port_notify(dp, DSA_NOTIFIER_HOST_FDB_ADD, &info);
10345e8a1e03SVladimir Oltean }
10355e8a1e03SVladimir Oltean 
dsa_port_standalone_host_fdb_add(struct dsa_port * dp,const unsigned char * addr,u16 vid)10365e8a1e03SVladimir Oltean int dsa_port_standalone_host_fdb_add(struct dsa_port *dp,
10375e8a1e03SVladimir Oltean 				     const unsigned char *addr, u16 vid)
10385e8a1e03SVladimir Oltean {
10395e8a1e03SVladimir Oltean 	struct dsa_db db = {
10405e8a1e03SVladimir Oltean 		.type = DSA_DB_PORT,
10415e8a1e03SVladimir Oltean 		.dp = dp,
10425e8a1e03SVladimir Oltean 	};
10435e8a1e03SVladimir Oltean 
10445e8a1e03SVladimir Oltean 	return dsa_port_host_fdb_add(dp, addr, vid, db);
10455e8a1e03SVladimir Oltean }
10465e8a1e03SVladimir Oltean 
dsa_port_bridge_host_fdb_add(struct dsa_port * dp,const unsigned char * addr,u16 vid)10475e8a1e03SVladimir Oltean int dsa_port_bridge_host_fdb_add(struct dsa_port *dp,
10485e8a1e03SVladimir Oltean 				 const unsigned char *addr, u16 vid)
10495e8a1e03SVladimir Oltean {
10508f6a19c0SVladimir Oltean 	struct net_device *master = dsa_port_to_master(dp);
10515e8a1e03SVladimir Oltean 	struct dsa_db db = {
1052c2693363SVladimir Oltean 		.type = DSA_DB_BRIDGE,
1053c2693363SVladimir Oltean 		.bridge = *dp->bridge,
10543dc80afcSVladimir Oltean 	};
105526ee7b06SVladimir Oltean 	int err;
105626ee7b06SVladimir Oltean 
1057eb1ab765SVladimir Oltean 	if (!dp->ds->fdb_isolation)
1058eb1ab765SVladimir Oltean 		db.bridge.num = 0;
1059eb1ab765SVladimir Oltean 
10608940e6b6SVladimir Oltean 	/* Avoid a call to __dev_set_promiscuity() on the master, which
10618940e6b6SVladimir Oltean 	 * requires rtnl_lock(), since we can't guarantee that is held here,
10628940e6b6SVladimir Oltean 	 * and we can't take it either.
10638940e6b6SVladimir Oltean 	 */
10648f6a19c0SVladimir Oltean 	if (master->priv_flags & IFF_UNICAST_FLT) {
10658f6a19c0SVladimir Oltean 		err = dev_uc_add(master, addr);
106626ee7b06SVladimir Oltean 		if (err)
106726ee7b06SVladimir Oltean 			return err;
10688940e6b6SVladimir Oltean 	}
10693dc80afcSVladimir Oltean 
10705e8a1e03SVladimir Oltean 	return dsa_port_host_fdb_add(dp, addr, vid, db);
10713dc80afcSVladimir Oltean }
10723dc80afcSVladimir Oltean 
dsa_port_host_fdb_del(struct dsa_port * dp,const unsigned char * addr,u16 vid,struct dsa_db db)10735e8a1e03SVladimir Oltean static int dsa_port_host_fdb_del(struct dsa_port *dp,
10745e8a1e03SVladimir Oltean 				 const unsigned char *addr, u16 vid,
10755e8a1e03SVladimir Oltean 				 struct dsa_db db)
10763dc80afcSVladimir Oltean {
10773dc80afcSVladimir Oltean 	struct dsa_notifier_fdb_info info = {
1078726816a1SVladimir Oltean 		.dp = dp,
10793dc80afcSVladimir Oltean 		.addr = addr,
10803dc80afcSVladimir Oltean 		.vid = vid,
10815e8a1e03SVladimir Oltean 		.db = db,
10825e8a1e03SVladimir Oltean 	};
10835e8a1e03SVladimir Oltean 
10845e8a1e03SVladimir Oltean 	return dsa_port_notify(dp, DSA_NOTIFIER_HOST_FDB_DEL, &info);
10855e8a1e03SVladimir Oltean }
10865e8a1e03SVladimir Oltean 
dsa_port_standalone_host_fdb_del(struct dsa_port * dp,const unsigned char * addr,u16 vid)10875e8a1e03SVladimir Oltean int dsa_port_standalone_host_fdb_del(struct dsa_port *dp,
10885e8a1e03SVladimir Oltean 				     const unsigned char *addr, u16 vid)
10895e8a1e03SVladimir Oltean {
10905e8a1e03SVladimir Oltean 	struct dsa_db db = {
10915e8a1e03SVladimir Oltean 		.type = DSA_DB_PORT,
10925e8a1e03SVladimir Oltean 		.dp = dp,
10935e8a1e03SVladimir Oltean 	};
10945e8a1e03SVladimir Oltean 
10955e8a1e03SVladimir Oltean 	return dsa_port_host_fdb_del(dp, addr, vid, db);
10965e8a1e03SVladimir Oltean }
10975e8a1e03SVladimir Oltean 
dsa_port_bridge_host_fdb_del(struct dsa_port * dp,const unsigned char * addr,u16 vid)10985e8a1e03SVladimir Oltean int dsa_port_bridge_host_fdb_del(struct dsa_port *dp,
10995e8a1e03SVladimir Oltean 				 const unsigned char *addr, u16 vid)
11005e8a1e03SVladimir Oltean {
11018f6a19c0SVladimir Oltean 	struct net_device *master = dsa_port_to_master(dp);
11025e8a1e03SVladimir Oltean 	struct dsa_db db = {
1103c2693363SVladimir Oltean 		.type = DSA_DB_BRIDGE,
1104c2693363SVladimir Oltean 		.bridge = *dp->bridge,
11053dc80afcSVladimir Oltean 	};
110626ee7b06SVladimir Oltean 	int err;
110726ee7b06SVladimir Oltean 
1108eb1ab765SVladimir Oltean 	if (!dp->ds->fdb_isolation)
1109eb1ab765SVladimir Oltean 		db.bridge.num = 0;
1110eb1ab765SVladimir Oltean 
11118f6a19c0SVladimir Oltean 	if (master->priv_flags & IFF_UNICAST_FLT) {
11128f6a19c0SVladimir Oltean 		err = dev_uc_del(master, addr);
111326ee7b06SVladimir Oltean 		if (err)
111426ee7b06SVladimir Oltean 			return err;
11158940e6b6SVladimir Oltean 	}
11163dc80afcSVladimir Oltean 
11175e8a1e03SVladimir Oltean 	return dsa_port_host_fdb_del(dp, addr, vid, db);
11183dc80afcSVladimir Oltean }
11193dc80afcSVladimir Oltean 
dsa_port_lag_fdb_add(struct dsa_port * dp,const unsigned char * addr,u16 vid)1120e212fa7cSVladimir Oltean int dsa_port_lag_fdb_add(struct dsa_port *dp, const unsigned char *addr,
1121e212fa7cSVladimir Oltean 			 u16 vid)
1122e212fa7cSVladimir Oltean {
1123e212fa7cSVladimir Oltean 	struct dsa_notifier_lag_fdb_info info = {
1124e212fa7cSVladimir Oltean 		.lag = dp->lag,
1125e212fa7cSVladimir Oltean 		.addr = addr,
1126e212fa7cSVladimir Oltean 		.vid = vid,
1127c2693363SVladimir Oltean 		.db = {
1128c2693363SVladimir Oltean 			.type = DSA_DB_BRIDGE,
1129c2693363SVladimir Oltean 			.bridge = *dp->bridge,
1130c2693363SVladimir Oltean 		},
1131e212fa7cSVladimir Oltean 	};
1132e212fa7cSVladimir Oltean 
1133c2693363SVladimir Oltean 	if (!dp->ds->fdb_isolation)
1134c2693363SVladimir Oltean 		info.db.bridge.num = 0;
1135c2693363SVladimir Oltean 
1136e212fa7cSVladimir Oltean 	return dsa_port_notify(dp, DSA_NOTIFIER_LAG_FDB_ADD, &info);
1137e212fa7cSVladimir Oltean }
1138e212fa7cSVladimir Oltean 
dsa_port_lag_fdb_del(struct dsa_port * dp,const unsigned char * addr,u16 vid)1139e212fa7cSVladimir Oltean int dsa_port_lag_fdb_del(struct dsa_port *dp, const unsigned char *addr,
1140e212fa7cSVladimir Oltean 			 u16 vid)
1141e212fa7cSVladimir Oltean {
1142e212fa7cSVladimir Oltean 	struct dsa_notifier_lag_fdb_info info = {
1143e212fa7cSVladimir Oltean 		.lag = dp->lag,
1144e212fa7cSVladimir Oltean 		.addr = addr,
1145e212fa7cSVladimir Oltean 		.vid = vid,
1146c2693363SVladimir Oltean 		.db = {
1147c2693363SVladimir Oltean 			.type = DSA_DB_BRIDGE,
1148c2693363SVladimir Oltean 			.bridge = *dp->bridge,
1149c2693363SVladimir Oltean 		},
1150e212fa7cSVladimir Oltean 	};
1151e212fa7cSVladimir Oltean 
1152c2693363SVladimir Oltean 	if (!dp->ds->fdb_isolation)
1153c2693363SVladimir Oltean 		info.db.bridge.num = 0;
1154c2693363SVladimir Oltean 
1155e212fa7cSVladimir Oltean 	return dsa_port_notify(dp, DSA_NOTIFIER_LAG_FDB_DEL, &info);
1156e212fa7cSVladimir Oltean }
1157e212fa7cSVladimir Oltean 
dsa_port_fdb_dump(struct dsa_port * dp,dsa_fdb_dump_cb_t * cb,void * data)1158de40fc5dSVivien Didelot int dsa_port_fdb_dump(struct dsa_port *dp, dsa_fdb_dump_cb_t *cb, void *data)
1159de40fc5dSVivien Didelot {
1160de40fc5dSVivien Didelot 	struct dsa_switch *ds = dp->ds;
1161de40fc5dSVivien Didelot 	int port = dp->index;
1162de40fc5dSVivien Didelot 
1163de40fc5dSVivien Didelot 	if (!ds->ops->port_fdb_dump)
1164de40fc5dSVivien Didelot 		return -EOPNOTSUPP;
1165de40fc5dSVivien Didelot 
1166de40fc5dSVivien Didelot 	return ds->ops->port_fdb_dump(ds, port, cb, data);
1167de40fc5dSVivien Didelot }
1168de40fc5dSVivien Didelot 
dsa_port_mdb_add(const struct dsa_port * dp,const struct switchdev_obj_port_mdb * mdb)1169bb9f6031SAndrew Lunn int dsa_port_mdb_add(const struct dsa_port *dp,
1170ffb68fc5SVladimir Oltean 		     const struct switchdev_obj_port_mdb *mdb)
11713a9afea3SVivien Didelot {
11728ae5bcdcSVivien Didelot 	struct dsa_notifier_mdb_info info = {
1173726816a1SVladimir Oltean 		.dp = dp,
11748ae5bcdcSVivien Didelot 		.mdb = mdb,
1175c2693363SVladimir Oltean 		.db = {
1176c2693363SVladimir Oltean 			.type = DSA_DB_BRIDGE,
1177c2693363SVladimir Oltean 			.bridge = *dp->bridge,
1178c2693363SVladimir Oltean 		},
11798ae5bcdcSVivien Didelot 	};
11803a9afea3SVivien Didelot 
1181c2693363SVladimir Oltean 	if (!dp->ds->fdb_isolation)
1182c2693363SVladimir Oltean 		info.db.bridge.num = 0;
1183c2693363SVladimir Oltean 
11848ae5bcdcSVivien Didelot 	return dsa_port_notify(dp, DSA_NOTIFIER_MDB_ADD, &info);
11853a9afea3SVivien Didelot }
11863a9afea3SVivien Didelot 
dsa_port_mdb_del(const struct dsa_port * dp,const struct switchdev_obj_port_mdb * mdb)1187bb9f6031SAndrew Lunn int dsa_port_mdb_del(const struct dsa_port *dp,
11883a9afea3SVivien Didelot 		     const struct switchdev_obj_port_mdb *mdb)
11893a9afea3SVivien Didelot {
11908ae5bcdcSVivien Didelot 	struct dsa_notifier_mdb_info info = {
1191726816a1SVladimir Oltean 		.dp = dp,
11928ae5bcdcSVivien Didelot 		.mdb = mdb,
1193c2693363SVladimir Oltean 		.db = {
1194c2693363SVladimir Oltean 			.type = DSA_DB_BRIDGE,
1195c2693363SVladimir Oltean 			.bridge = *dp->bridge,
1196c2693363SVladimir Oltean 		},
11978ae5bcdcSVivien Didelot 	};
11983a9afea3SVivien Didelot 
1199c2693363SVladimir Oltean 	if (!dp->ds->fdb_isolation)
1200c2693363SVladimir Oltean 		info.db.bridge.num = 0;
1201c2693363SVladimir Oltean 
12028ae5bcdcSVivien Didelot 	return dsa_port_notify(dp, DSA_NOTIFIER_MDB_DEL, &info);
12033a9afea3SVivien Didelot }
12043a9afea3SVivien Didelot 
dsa_port_host_mdb_add(const struct dsa_port * dp,const struct switchdev_obj_port_mdb * mdb,struct dsa_db db)12055e8a1e03SVladimir Oltean static int dsa_port_host_mdb_add(const struct dsa_port *dp,
12065e8a1e03SVladimir Oltean 				 const struct switchdev_obj_port_mdb *mdb,
12075e8a1e03SVladimir Oltean 				 struct dsa_db db)
1208b8e997c4SVladimir Oltean {
1209b8e997c4SVladimir Oltean 	struct dsa_notifier_mdb_info info = {
1210726816a1SVladimir Oltean 		.dp = dp,
1211b8e997c4SVladimir Oltean 		.mdb = mdb,
12125e8a1e03SVladimir Oltean 		.db = db,
1213b8e997c4SVladimir Oltean 	};
1214b8e997c4SVladimir Oltean 
1215b8e997c4SVladimir Oltean 	return dsa_port_notify(dp, DSA_NOTIFIER_HOST_MDB_ADD, &info);
1216b8e997c4SVladimir Oltean }
1217b8e997c4SVladimir Oltean 
dsa_port_standalone_host_mdb_add(const struct dsa_port * dp,const struct switchdev_obj_port_mdb * mdb)12185e8a1e03SVladimir Oltean int dsa_port_standalone_host_mdb_add(const struct dsa_port *dp,
1219b8e997c4SVladimir Oltean 				     const struct switchdev_obj_port_mdb *mdb)
1220b8e997c4SVladimir Oltean {
12215e8a1e03SVladimir Oltean 	struct dsa_db db = {
12225e8a1e03SVladimir Oltean 		.type = DSA_DB_PORT,
12235e8a1e03SVladimir Oltean 		.dp = dp,
12245e8a1e03SVladimir Oltean 	};
12255e8a1e03SVladimir Oltean 
12265e8a1e03SVladimir Oltean 	return dsa_port_host_mdb_add(dp, mdb, db);
12275e8a1e03SVladimir Oltean }
12285e8a1e03SVladimir Oltean 
dsa_port_bridge_host_mdb_add(const struct dsa_port * dp,const struct switchdev_obj_port_mdb * mdb)12295e8a1e03SVladimir Oltean int dsa_port_bridge_host_mdb_add(const struct dsa_port *dp,
12305e8a1e03SVladimir Oltean 				 const struct switchdev_obj_port_mdb *mdb)
12315e8a1e03SVladimir Oltean {
12328f6a19c0SVladimir Oltean 	struct net_device *master = dsa_port_to_master(dp);
12335e8a1e03SVladimir Oltean 	struct dsa_db db = {
12345e8a1e03SVladimir Oltean 		.type = DSA_DB_BRIDGE,
12355e8a1e03SVladimir Oltean 		.bridge = *dp->bridge,
12365e8a1e03SVladimir Oltean 	};
12375e8a1e03SVladimir Oltean 	int err;
12385e8a1e03SVladimir Oltean 
1239eb1ab765SVladimir Oltean 	if (!dp->ds->fdb_isolation)
1240eb1ab765SVladimir Oltean 		db.bridge.num = 0;
1241eb1ab765SVladimir Oltean 
12428f6a19c0SVladimir Oltean 	err = dev_mc_add(master, mdb->addr);
12435e8a1e03SVladimir Oltean 	if (err)
12445e8a1e03SVladimir Oltean 		return err;
12455e8a1e03SVladimir Oltean 
12465e8a1e03SVladimir Oltean 	return dsa_port_host_mdb_add(dp, mdb, db);
12475e8a1e03SVladimir Oltean }
12485e8a1e03SVladimir Oltean 
dsa_port_host_mdb_del(const struct dsa_port * dp,const struct switchdev_obj_port_mdb * mdb,struct dsa_db db)12495e8a1e03SVladimir Oltean static int dsa_port_host_mdb_del(const struct dsa_port *dp,
12505e8a1e03SVladimir Oltean 				 const struct switchdev_obj_port_mdb *mdb,
12515e8a1e03SVladimir Oltean 				 struct dsa_db db)
12525e8a1e03SVladimir Oltean {
1253b8e997c4SVladimir Oltean 	struct dsa_notifier_mdb_info info = {
1254726816a1SVladimir Oltean 		.dp = dp,
1255b8e997c4SVladimir Oltean 		.mdb = mdb,
12565e8a1e03SVladimir Oltean 		.db = db,
12575e8a1e03SVladimir Oltean 	};
12585e8a1e03SVladimir Oltean 
12595e8a1e03SVladimir Oltean 	return dsa_port_notify(dp, DSA_NOTIFIER_HOST_MDB_DEL, &info);
12605e8a1e03SVladimir Oltean }
12615e8a1e03SVladimir Oltean 
dsa_port_standalone_host_mdb_del(const struct dsa_port * dp,const struct switchdev_obj_port_mdb * mdb)12625e8a1e03SVladimir Oltean int dsa_port_standalone_host_mdb_del(const struct dsa_port *dp,
12635e8a1e03SVladimir Oltean 				     const struct switchdev_obj_port_mdb *mdb)
12645e8a1e03SVladimir Oltean {
12655e8a1e03SVladimir Oltean 	struct dsa_db db = {
12665e8a1e03SVladimir Oltean 		.type = DSA_DB_PORT,
12675e8a1e03SVladimir Oltean 		.dp = dp,
12685e8a1e03SVladimir Oltean 	};
12695e8a1e03SVladimir Oltean 
12705e8a1e03SVladimir Oltean 	return dsa_port_host_mdb_del(dp, mdb, db);
12715e8a1e03SVladimir Oltean }
12725e8a1e03SVladimir Oltean 
dsa_port_bridge_host_mdb_del(const struct dsa_port * dp,const struct switchdev_obj_port_mdb * mdb)12735e8a1e03SVladimir Oltean int dsa_port_bridge_host_mdb_del(const struct dsa_port *dp,
12745e8a1e03SVladimir Oltean 				 const struct switchdev_obj_port_mdb *mdb)
12755e8a1e03SVladimir Oltean {
12768f6a19c0SVladimir Oltean 	struct net_device *master = dsa_port_to_master(dp);
12775e8a1e03SVladimir Oltean 	struct dsa_db db = {
1278c2693363SVladimir Oltean 		.type = DSA_DB_BRIDGE,
1279c2693363SVladimir Oltean 		.bridge = *dp->bridge,
1280b8e997c4SVladimir Oltean 	};
128126ee7b06SVladimir Oltean 	int err;
128226ee7b06SVladimir Oltean 
1283eb1ab765SVladimir Oltean 	if (!dp->ds->fdb_isolation)
1284eb1ab765SVladimir Oltean 		db.bridge.num = 0;
1285eb1ab765SVladimir Oltean 
12868f6a19c0SVladimir Oltean 	err = dev_mc_del(master, mdb->addr);
128726ee7b06SVladimir Oltean 	if (err)
128826ee7b06SVladimir Oltean 		return err;
1289b8e997c4SVladimir Oltean 
12905e8a1e03SVladimir Oltean 	return dsa_port_host_mdb_del(dp, mdb, db);
1291b8e997c4SVladimir Oltean }
1292b8e997c4SVladimir Oltean 
dsa_port_vlan_add(struct dsa_port * dp,const struct switchdev_obj_port_vlan * vlan,struct netlink_ext_ack * extack)1293076e7133SVivien Didelot int dsa_port_vlan_add(struct dsa_port *dp,
129431046a5fSVladimir Oltean 		      const struct switchdev_obj_port_vlan *vlan,
129531046a5fSVladimir Oltean 		      struct netlink_ext_ack *extack)
1296076e7133SVivien Didelot {
1297d0c627b8SVivien Didelot 	struct dsa_notifier_vlan_info info = {
1298726816a1SVladimir Oltean 		.dp = dp,
1299d0c627b8SVivien Didelot 		.vlan = vlan,
130031046a5fSVladimir Oltean 		.extack = extack,
1301d0c627b8SVivien Didelot 	};
1302076e7133SVivien Didelot 
1303d0c627b8SVivien Didelot 	return dsa_port_notify(dp, DSA_NOTIFIER_VLAN_ADD, &info);
1304076e7133SVivien Didelot }
1305076e7133SVivien Didelot 
dsa_port_vlan_del(struct dsa_port * dp,const struct switchdev_obj_port_vlan * vlan)1306076e7133SVivien Didelot int dsa_port_vlan_del(struct dsa_port *dp,
1307076e7133SVivien Didelot 		      const struct switchdev_obj_port_vlan *vlan)
1308076e7133SVivien Didelot {
1309d0c627b8SVivien Didelot 	struct dsa_notifier_vlan_info info = {
1310726816a1SVladimir Oltean 		.dp = dp,
1311d0c627b8SVivien Didelot 		.vlan = vlan,
1312d0c627b8SVivien Didelot 	};
1313076e7133SVivien Didelot 
1314d0c627b8SVivien Didelot 	return dsa_port_notify(dp, DSA_NOTIFIER_VLAN_DEL, &info);
1315076e7133SVivien Didelot }
131657ab1ca2SVivien Didelot 
dsa_port_host_vlan_add(struct dsa_port * dp,const struct switchdev_obj_port_vlan * vlan,struct netlink_ext_ack * extack)1317134ef238SVladimir Oltean int dsa_port_host_vlan_add(struct dsa_port *dp,
1318134ef238SVladimir Oltean 			   const struct switchdev_obj_port_vlan *vlan,
1319134ef238SVladimir Oltean 			   struct netlink_ext_ack *extack)
1320134ef238SVladimir Oltean {
13218f6a19c0SVladimir Oltean 	struct net_device *master = dsa_port_to_master(dp);
1322134ef238SVladimir Oltean 	struct dsa_notifier_vlan_info info = {
1323726816a1SVladimir Oltean 		.dp = dp,
1324134ef238SVladimir Oltean 		.vlan = vlan,
1325134ef238SVladimir Oltean 		.extack = extack,
1326134ef238SVladimir Oltean 	};
1327134ef238SVladimir Oltean 	int err;
1328134ef238SVladimir Oltean 
1329134ef238SVladimir Oltean 	err = dsa_port_notify(dp, DSA_NOTIFIER_HOST_VLAN_ADD, &info);
1330134ef238SVladimir Oltean 	if (err && err != -EOPNOTSUPP)
1331134ef238SVladimir Oltean 		return err;
1332134ef238SVladimir Oltean 
13338f6a19c0SVladimir Oltean 	vlan_vid_add(master, htons(ETH_P_8021Q), vlan->vid);
1334134ef238SVladimir Oltean 
1335134ef238SVladimir Oltean 	return err;
1336134ef238SVladimir Oltean }
1337134ef238SVladimir Oltean 
dsa_port_host_vlan_del(struct dsa_port * dp,const struct switchdev_obj_port_vlan * vlan)1338134ef238SVladimir Oltean int dsa_port_host_vlan_del(struct dsa_port *dp,
1339134ef238SVladimir Oltean 			   const struct switchdev_obj_port_vlan *vlan)
1340134ef238SVladimir Oltean {
13418f6a19c0SVladimir Oltean 	struct net_device *master = dsa_port_to_master(dp);
1342134ef238SVladimir Oltean 	struct dsa_notifier_vlan_info info = {
1343726816a1SVladimir Oltean 		.dp = dp,
1344134ef238SVladimir Oltean 		.vlan = vlan,
1345134ef238SVladimir Oltean 	};
1346134ef238SVladimir Oltean 	int err;
1347134ef238SVladimir Oltean 
1348134ef238SVladimir Oltean 	err = dsa_port_notify(dp, DSA_NOTIFIER_HOST_VLAN_DEL, &info);
1349134ef238SVladimir Oltean 	if (err && err != -EOPNOTSUPP)
1350134ef238SVladimir Oltean 		return err;
1351134ef238SVladimir Oltean 
13528f6a19c0SVladimir Oltean 	vlan_vid_del(master, htons(ETH_P_8021Q), vlan->vid);
1353134ef238SVladimir Oltean 
1354134ef238SVladimir Oltean 	return err;
1355134ef238SVladimir Oltean }
1356134ef238SVladimir Oltean 
dsa_port_mrp_add(const struct dsa_port * dp,const struct switchdev_obj_mrp * mrp)1357c595c433SHoratiu Vultur int dsa_port_mrp_add(const struct dsa_port *dp,
1358c595c433SHoratiu Vultur 		     const struct switchdev_obj_mrp *mrp)
1359c595c433SHoratiu Vultur {
1360cad69019SVladimir Oltean 	struct dsa_switch *ds = dp->ds;
1361c595c433SHoratiu Vultur 
1362cad69019SVladimir Oltean 	if (!ds->ops->port_mrp_add)
1363cad69019SVladimir Oltean 		return -EOPNOTSUPP;
1364cad69019SVladimir Oltean 
1365cad69019SVladimir Oltean 	return ds->ops->port_mrp_add(ds, dp->index, mrp);
1366c595c433SHoratiu Vultur }
1367c595c433SHoratiu Vultur 
dsa_port_mrp_del(const struct dsa_port * dp,const struct switchdev_obj_mrp * mrp)1368c595c433SHoratiu Vultur int dsa_port_mrp_del(const struct dsa_port *dp,
1369c595c433SHoratiu Vultur 		     const struct switchdev_obj_mrp *mrp)
1370c595c433SHoratiu Vultur {
1371cad69019SVladimir Oltean 	struct dsa_switch *ds = dp->ds;
1372c595c433SHoratiu Vultur 
1373cad69019SVladimir Oltean 	if (!ds->ops->port_mrp_del)
1374cad69019SVladimir Oltean 		return -EOPNOTSUPP;
1375cad69019SVladimir Oltean 
1376cad69019SVladimir Oltean 	return ds->ops->port_mrp_del(ds, dp->index, mrp);
1377c595c433SHoratiu Vultur }
1378c595c433SHoratiu Vultur 
dsa_port_mrp_add_ring_role(const struct dsa_port * dp,const struct switchdev_obj_ring_role_mrp * mrp)1379c595c433SHoratiu Vultur int dsa_port_mrp_add_ring_role(const struct dsa_port *dp,
1380c595c433SHoratiu Vultur 			       const struct switchdev_obj_ring_role_mrp *mrp)
1381c595c433SHoratiu Vultur {
1382cad69019SVladimir Oltean 	struct dsa_switch *ds = dp->ds;
1383c595c433SHoratiu Vultur 
1384cad69019SVladimir Oltean 	if (!ds->ops->port_mrp_add_ring_role)
1385cad69019SVladimir Oltean 		return -EOPNOTSUPP;
1386cad69019SVladimir Oltean 
1387cad69019SVladimir Oltean 	return ds->ops->port_mrp_add_ring_role(ds, dp->index, mrp);
1388c595c433SHoratiu Vultur }
1389c595c433SHoratiu Vultur 
dsa_port_mrp_del_ring_role(const struct dsa_port * dp,const struct switchdev_obj_ring_role_mrp * mrp)1390c595c433SHoratiu Vultur int dsa_port_mrp_del_ring_role(const struct dsa_port *dp,
1391c595c433SHoratiu Vultur 			       const struct switchdev_obj_ring_role_mrp *mrp)
1392c595c433SHoratiu Vultur {
1393cad69019SVladimir Oltean 	struct dsa_switch *ds = dp->ds;
1394c595c433SHoratiu Vultur 
1395cad69019SVladimir Oltean 	if (!ds->ops->port_mrp_del_ring_role)
1396cad69019SVladimir Oltean 		return -EOPNOTSUPP;
1397cad69019SVladimir Oltean 
1398cad69019SVladimir Oltean 	return ds->ops->port_mrp_del_ring_role(ds, dp->index, mrp);
1399c595c433SHoratiu Vultur }
1400c595c433SHoratiu Vultur 
dsa_port_assign_master(struct dsa_port * dp,struct net_device * master,struct netlink_ext_ack * extack,bool fail_on_err)140195f510d0SVladimir Oltean static int dsa_port_assign_master(struct dsa_port *dp,
140295f510d0SVladimir Oltean 				  struct net_device *master,
140395f510d0SVladimir Oltean 				  struct netlink_ext_ack *extack,
140495f510d0SVladimir Oltean 				  bool fail_on_err)
140595f510d0SVladimir Oltean {
140695f510d0SVladimir Oltean 	struct dsa_switch *ds = dp->ds;
140795f510d0SVladimir Oltean 	int port = dp->index, err;
140895f510d0SVladimir Oltean 
140995f510d0SVladimir Oltean 	err = ds->ops->port_change_master(ds, port, master, extack);
141095f510d0SVladimir Oltean 	if (err && !fail_on_err)
141195f510d0SVladimir Oltean 		dev_err(ds->dev, "port %d failed to assign master %s: %pe\n",
141295f510d0SVladimir Oltean 			port, master->name, ERR_PTR(err));
141395f510d0SVladimir Oltean 
141495f510d0SVladimir Oltean 	if (err && fail_on_err)
141595f510d0SVladimir Oltean 		return err;
141695f510d0SVladimir Oltean 
141795f510d0SVladimir Oltean 	dp->cpu_dp = master->dsa_ptr;
1418acc43b7bSVladimir Oltean 	dp->cpu_port_in_lag = netif_is_lag_master(master);
141995f510d0SVladimir Oltean 
142095f510d0SVladimir Oltean 	return 0;
142195f510d0SVladimir Oltean }
142295f510d0SVladimir Oltean 
142395f510d0SVladimir Oltean /* Change the dp->cpu_dp affinity for a user port. Note that both cross-chip
142495f510d0SVladimir Oltean  * notifiers and drivers have implicit assumptions about user-to-CPU-port
142595f510d0SVladimir Oltean  * mappings, so we unfortunately cannot delay the deletion of the objects
142695f510d0SVladimir Oltean  * (switchdev, standalone addresses, standalone VLANs) on the old CPU port
142795f510d0SVladimir Oltean  * until the new CPU port has been set up. So we need to completely tear down
142895f510d0SVladimir Oltean  * the old CPU port before changing it, and restore it on errors during the
142995f510d0SVladimir Oltean  * bringup of the new one.
143095f510d0SVladimir Oltean  */
dsa_port_change_master(struct dsa_port * dp,struct net_device * master,struct netlink_ext_ack * extack)143195f510d0SVladimir Oltean int dsa_port_change_master(struct dsa_port *dp, struct net_device *master,
143295f510d0SVladimir Oltean 			   struct netlink_ext_ack *extack)
143395f510d0SVladimir Oltean {
143495f510d0SVladimir Oltean 	struct net_device *bridge_dev = dsa_port_bridge_dev_get(dp);
143595f510d0SVladimir Oltean 	struct net_device *old_master = dsa_port_to_master(dp);
143695f510d0SVladimir Oltean 	struct net_device *dev = dp->slave;
143795f510d0SVladimir Oltean 	struct dsa_switch *ds = dp->ds;
143895f510d0SVladimir Oltean 	bool vlan_filtering;
143995f510d0SVladimir Oltean 	int err, tmp;
144095f510d0SVladimir Oltean 
144195f510d0SVladimir Oltean 	/* Bridges may hold host FDB, MDB and VLAN objects. These need to be
144295f510d0SVladimir Oltean 	 * migrated, so dynamically unoffload and later reoffload the bridge
144395f510d0SVladimir Oltean 	 * port.
144495f510d0SVladimir Oltean 	 */
144595f510d0SVladimir Oltean 	if (bridge_dev) {
144695f510d0SVladimir Oltean 		dsa_port_pre_bridge_leave(dp, bridge_dev);
144795f510d0SVladimir Oltean 		dsa_port_bridge_leave(dp, bridge_dev);
144895f510d0SVladimir Oltean 	}
144995f510d0SVladimir Oltean 
145095f510d0SVladimir Oltean 	/* The port might still be VLAN filtering even if it's no longer
145195f510d0SVladimir Oltean 	 * under a bridge, either due to ds->vlan_filtering_is_global or
145295f510d0SVladimir Oltean 	 * ds->needs_standalone_vlan_filtering. In turn this means VLANs
145395f510d0SVladimir Oltean 	 * on the CPU port.
145495f510d0SVladimir Oltean 	 */
145595f510d0SVladimir Oltean 	vlan_filtering = dsa_port_is_vlan_filtering(dp);
145695f510d0SVladimir Oltean 	if (vlan_filtering) {
145795f510d0SVladimir Oltean 		err = dsa_slave_manage_vlan_filtering(dev, false);
145895f510d0SVladimir Oltean 		if (err) {
145995f510d0SVladimir Oltean 			NL_SET_ERR_MSG_MOD(extack,
146095f510d0SVladimir Oltean 					   "Failed to remove standalone VLANs");
146195f510d0SVladimir Oltean 			goto rewind_old_bridge;
146295f510d0SVladimir Oltean 		}
146395f510d0SVladimir Oltean 	}
146495f510d0SVladimir Oltean 
146595f510d0SVladimir Oltean 	/* Standalone addresses, and addresses of upper interfaces like
146695f510d0SVladimir Oltean 	 * VLAN, LAG, HSR need to be migrated.
146795f510d0SVladimir Oltean 	 */
146895f510d0SVladimir Oltean 	dsa_slave_unsync_ha(dev);
146995f510d0SVladimir Oltean 
147095f510d0SVladimir Oltean 	err = dsa_port_assign_master(dp, master, extack, true);
147195f510d0SVladimir Oltean 	if (err)
147295f510d0SVladimir Oltean 		goto rewind_old_addrs;
147395f510d0SVladimir Oltean 
147495f510d0SVladimir Oltean 	dsa_slave_sync_ha(dev);
147595f510d0SVladimir Oltean 
147695f510d0SVladimir Oltean 	if (vlan_filtering) {
147795f510d0SVladimir Oltean 		err = dsa_slave_manage_vlan_filtering(dev, true);
147895f510d0SVladimir Oltean 		if (err) {
147995f510d0SVladimir Oltean 			NL_SET_ERR_MSG_MOD(extack,
148095f510d0SVladimir Oltean 					   "Failed to restore standalone VLANs");
148195f510d0SVladimir Oltean 			goto rewind_new_addrs;
148295f510d0SVladimir Oltean 		}
148395f510d0SVladimir Oltean 	}
148495f510d0SVladimir Oltean 
148595f510d0SVladimir Oltean 	if (bridge_dev) {
148695f510d0SVladimir Oltean 		err = dsa_port_bridge_join(dp, bridge_dev, extack);
148795f510d0SVladimir Oltean 		if (err && err == -EOPNOTSUPP) {
148895f510d0SVladimir Oltean 			NL_SET_ERR_MSG_MOD(extack,
148995f510d0SVladimir Oltean 					   "Failed to reoffload bridge");
149095f510d0SVladimir Oltean 			goto rewind_new_vlan;
149195f510d0SVladimir Oltean 		}
149295f510d0SVladimir Oltean 	}
149395f510d0SVladimir Oltean 
149495f510d0SVladimir Oltean 	return 0;
149595f510d0SVladimir Oltean 
149695f510d0SVladimir Oltean rewind_new_vlan:
149795f510d0SVladimir Oltean 	if (vlan_filtering)
149895f510d0SVladimir Oltean 		dsa_slave_manage_vlan_filtering(dev, false);
149995f510d0SVladimir Oltean 
150095f510d0SVladimir Oltean rewind_new_addrs:
150195f510d0SVladimir Oltean 	dsa_slave_unsync_ha(dev);
150295f510d0SVladimir Oltean 
150395f510d0SVladimir Oltean 	dsa_port_assign_master(dp, old_master, NULL, false);
150495f510d0SVladimir Oltean 
150595f510d0SVladimir Oltean /* Restore the objects on the old CPU port */
150695f510d0SVladimir Oltean rewind_old_addrs:
150795f510d0SVladimir Oltean 	dsa_slave_sync_ha(dev);
150895f510d0SVladimir Oltean 
150995f510d0SVladimir Oltean 	if (vlan_filtering) {
151095f510d0SVladimir Oltean 		tmp = dsa_slave_manage_vlan_filtering(dev, true);
151195f510d0SVladimir Oltean 		if (tmp) {
151295f510d0SVladimir Oltean 			dev_err(ds->dev,
151395f510d0SVladimir Oltean 				"port %d failed to restore standalone VLANs: %pe\n",
151495f510d0SVladimir Oltean 				dp->index, ERR_PTR(tmp));
151595f510d0SVladimir Oltean 		}
151695f510d0SVladimir Oltean 	}
151795f510d0SVladimir Oltean 
151895f510d0SVladimir Oltean rewind_old_bridge:
151995f510d0SVladimir Oltean 	if (bridge_dev) {
152095f510d0SVladimir Oltean 		tmp = dsa_port_bridge_join(dp, bridge_dev, extack);
152195f510d0SVladimir Oltean 		if (tmp) {
152295f510d0SVladimir Oltean 			dev_err(ds->dev,
152395f510d0SVladimir Oltean 				"port %d failed to rejoin bridge %s: %pe\n",
152495f510d0SVladimir Oltean 				dp->index, bridge_dev->name, ERR_PTR(tmp));
152595f510d0SVladimir Oltean 		}
152695f510d0SVladimir Oltean 	}
152795f510d0SVladimir Oltean 
152895f510d0SVladimir Oltean 	return err;
152995f510d0SVladimir Oltean }
153095f510d0SVladimir Oltean 
dsa_port_set_tag_protocol(struct dsa_port * cpu_dp,const struct dsa_device_ops * tag_ops)153153da0ebaSVladimir Oltean void dsa_port_set_tag_protocol(struct dsa_port *cpu_dp,
153253da0ebaSVladimir Oltean 			       const struct dsa_device_ops *tag_ops)
153353da0ebaSVladimir Oltean {
153453da0ebaSVladimir Oltean 	cpu_dp->rcv = tag_ops->rcv;
153553da0ebaSVladimir Oltean 	cpu_dp->tag_ops = tag_ops;
153653da0ebaSVladimir Oltean }
153753da0ebaSVladimir Oltean 
dsa_port_get_phy_device(struct dsa_port * dp)15386207a78cSFlorian Fainelli static struct phy_device *dsa_port_get_phy_device(struct dsa_port *dp)
15396207a78cSFlorian Fainelli {
15406207a78cSFlorian Fainelli 	struct device_node *phy_dn;
15416207a78cSFlorian Fainelli 	struct phy_device *phydev;
15426207a78cSFlorian Fainelli 
15436207a78cSFlorian Fainelli 	phy_dn = of_parse_phandle(dp->dn, "phy-handle", 0);
15446207a78cSFlorian Fainelli 	if (!phy_dn)
15456207a78cSFlorian Fainelli 		return NULL;
15466207a78cSFlorian Fainelli 
15476207a78cSFlorian Fainelli 	phydev = of_phy_find_device(phy_dn);
15486207a78cSFlorian Fainelli 	if (!phydev) {
15496207a78cSFlorian Fainelli 		of_node_put(phy_dn);
15506207a78cSFlorian Fainelli 		return ERR_PTR(-EPROBE_DEFER);
15516207a78cSFlorian Fainelli 	}
15526207a78cSFlorian Fainelli 
15539919a363SWen Yang 	of_node_put(phy_dn);
15546207a78cSFlorian Fainelli 	return phydev;
15556207a78cSFlorian Fainelli }
15566207a78cSFlorian Fainelli 
dsa_port_phylink_validate(struct phylink_config * config,unsigned long * supported,struct phylink_link_state * state)15578ae67496SFlorian Fainelli static void dsa_port_phylink_validate(struct phylink_config *config,
155877373d49SIoana Ciornei 				      unsigned long *supported,
155977373d49SIoana Ciornei 				      struct phylink_link_state *state)
156077373d49SIoana Ciornei {
156153d04b98SVladimir Oltean 	/* Skip call for drivers which don't yet set mac_capabilities,
156253d04b98SVladimir Oltean 	 * since validating in that case would mean their PHY will advertise
156353d04b98SVladimir Oltean 	 * nothing. In turn, skipping validation makes them advertise
156453d04b98SVladimir Oltean 	 * everything that the PHY supports, so those drivers should be
156553d04b98SVladimir Oltean 	 * converted ASAP.
156653d04b98SVladimir Oltean 	 */
15675938bce4SRussell King (Oracle) 	if (config->mac_capabilities)
15685938bce4SRussell King (Oracle) 		phylink_generic_validate(config, supported, state);
156977373d49SIoana Ciornei }
157077373d49SIoana Ciornei 
1571bde01822SRussell King (Oracle) static struct phylink_pcs *
dsa_port_phylink_mac_select_pcs(struct phylink_config * config,phy_interface_t interface)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) 
dsa_port_phylink_mac_prepare(struct phylink_config * config,unsigned int mode,phy_interface_t interface)1585dd805cf3SRussell King (Oracle) static int dsa_port_phylink_mac_prepare(struct phylink_config *config,
1586dd805cf3SRussell King (Oracle) 					unsigned int mode,
1587dd805cf3SRussell King (Oracle) 					phy_interface_t interface)
1588dd805cf3SRussell King (Oracle) {
1589dd805cf3SRussell King (Oracle) 	struct dsa_port *dp = container_of(config, struct dsa_port, pl_config);
1590dd805cf3SRussell King (Oracle) 	struct dsa_switch *ds = dp->ds;
1591dd805cf3SRussell King (Oracle) 	int err = 0;
1592dd805cf3SRussell King (Oracle) 
1593dd805cf3SRussell King (Oracle) 	if (ds->ops->phylink_mac_prepare)
1594dd805cf3SRussell King (Oracle) 		err = ds->ops->phylink_mac_prepare(ds, dp->index, mode,
1595dd805cf3SRussell King (Oracle) 						   interface);
1596dd805cf3SRussell King (Oracle) 
1597dd805cf3SRussell King (Oracle) 	return err;
1598dd805cf3SRussell King (Oracle) }
1599dd805cf3SRussell King (Oracle) 
dsa_port_phylink_mac_config(struct phylink_config * config,unsigned int mode,const struct phylink_link_state * state)16008ae67496SFlorian Fainelli static void dsa_port_phylink_mac_config(struct phylink_config *config,
160177373d49SIoana Ciornei 					unsigned int mode,
160277373d49SIoana Ciornei 					const struct phylink_link_state *state)
160377373d49SIoana Ciornei {
160477373d49SIoana Ciornei 	struct dsa_port *dp = container_of(config, struct dsa_port, pl_config);
160577373d49SIoana Ciornei 	struct dsa_switch *ds = dp->ds;
160677373d49SIoana Ciornei 
160777373d49SIoana Ciornei 	if (!ds->ops->phylink_mac_config)
160877373d49SIoana Ciornei 		return;
160977373d49SIoana Ciornei 
161077373d49SIoana Ciornei 	ds->ops->phylink_mac_config(ds, dp->index, mode, state);
161177373d49SIoana Ciornei }
161277373d49SIoana Ciornei 
dsa_port_phylink_mac_finish(struct phylink_config * config,unsigned int mode,phy_interface_t interface)1613dd805cf3SRussell King (Oracle) static int dsa_port_phylink_mac_finish(struct phylink_config *config,
1614dd805cf3SRussell King (Oracle) 				       unsigned int mode,
1615dd805cf3SRussell King (Oracle) 				       phy_interface_t interface)
1616dd805cf3SRussell King (Oracle) {
1617dd805cf3SRussell King (Oracle) 	struct dsa_port *dp = container_of(config, struct dsa_port, pl_config);
1618dd805cf3SRussell King (Oracle) 	struct dsa_switch *ds = dp->ds;
1619dd805cf3SRussell King (Oracle) 	int err = 0;
1620dd805cf3SRussell King (Oracle) 
1621dd805cf3SRussell King (Oracle) 	if (ds->ops->phylink_mac_finish)
1622dd805cf3SRussell King (Oracle) 		err = ds->ops->phylink_mac_finish(ds, dp->index, mode,
1623dd805cf3SRussell King (Oracle) 						  interface);
1624dd805cf3SRussell King (Oracle) 
1625dd805cf3SRussell King (Oracle) 	return err;
1626dd805cf3SRussell King (Oracle) }
1627dd805cf3SRussell King (Oracle) 
dsa_port_phylink_mac_link_down(struct phylink_config * config,unsigned int mode,phy_interface_t interface)16288ae67496SFlorian Fainelli static void dsa_port_phylink_mac_link_down(struct phylink_config *config,
162977373d49SIoana Ciornei 					   unsigned int mode,
163077373d49SIoana Ciornei 					   phy_interface_t interface)
163177373d49SIoana Ciornei {
163277373d49SIoana Ciornei 	struct dsa_port *dp = container_of(config, struct dsa_port, pl_config);
16330e279218SIoana Ciornei 	struct phy_device *phydev = NULL;
163477373d49SIoana Ciornei 	struct dsa_switch *ds = dp->ds;
163577373d49SIoana Ciornei 
163657d77986SVladimir Oltean 	if (dsa_port_is_user(dp))
16370e279218SIoana Ciornei 		phydev = dp->slave->phydev;
16380e279218SIoana Ciornei 
163977373d49SIoana Ciornei 	if (!ds->ops->phylink_mac_link_down) {
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 
164577373d49SIoana Ciornei 	ds->ops->phylink_mac_link_down(ds, dp->index, mode, interface);
164677373d49SIoana Ciornei }
164777373d49SIoana Ciornei 
dsa_port_phylink_mac_link_up(struct phylink_config * config,struct phy_device * phydev,unsigned int mode,phy_interface_t interface,int speed,int duplex,bool tx_pause,bool rx_pause)16488ae67496SFlorian Fainelli static void dsa_port_phylink_mac_link_up(struct phylink_config *config,
164991a208f2SRussell King 					 struct phy_device *phydev,
165077373d49SIoana Ciornei 					 unsigned int mode,
165177373d49SIoana Ciornei 					 phy_interface_t interface,
165291a208f2SRussell King 					 int speed, int duplex,
165391a208f2SRussell King 					 bool tx_pause, bool rx_pause)
165477373d49SIoana Ciornei {
165577373d49SIoana Ciornei 	struct dsa_port *dp = container_of(config, struct dsa_port, pl_config);
165677373d49SIoana Ciornei 	struct dsa_switch *ds = dp->ds;
165777373d49SIoana Ciornei 
165877373d49SIoana Ciornei 	if (!ds->ops->phylink_mac_link_up) {
16590e279218SIoana Ciornei 		if (ds->ops->adjust_link && phydev)
16600e279218SIoana Ciornei 			ds->ops->adjust_link(ds, dp->index, phydev);
166177373d49SIoana Ciornei 		return;
166277373d49SIoana Ciornei 	}
166377373d49SIoana Ciornei 
16645b502a7bSRussell King 	ds->ops->phylink_mac_link_up(ds, dp->index, mode, interface, phydev,
16655b502a7bSRussell King 				     speed, duplex, tx_pause, rx_pause);
166677373d49SIoana Ciornei }
166777373d49SIoana Ciornei 
166821bd64bdSRussell King (Oracle) static const struct phylink_mac_ops dsa_port_phylink_mac_ops = {
166977373d49SIoana Ciornei 	.validate = dsa_port_phylink_validate,
1670bde01822SRussell King (Oracle) 	.mac_select_pcs = dsa_port_phylink_mac_select_pcs,
1671dd805cf3SRussell King (Oracle) 	.mac_prepare = dsa_port_phylink_mac_prepare,
167277373d49SIoana Ciornei 	.mac_config = dsa_port_phylink_mac_config,
1673dd805cf3SRussell King (Oracle) 	.mac_finish = dsa_port_phylink_mac_finish,
167477373d49SIoana Ciornei 	.mac_link_down = dsa_port_phylink_mac_link_down,
167577373d49SIoana Ciornei 	.mac_link_up = dsa_port_phylink_mac_link_up,
167677373d49SIoana Ciornei };
167777373d49SIoana Ciornei 
dsa_port_phylink_create(struct dsa_port * dp)167821bd64bdSRussell King (Oracle) int dsa_port_phylink_create(struct dsa_port *dp)
167921bd64bdSRussell King (Oracle) {
168021bd64bdSRussell King (Oracle) 	struct dsa_switch *ds = dp->ds;
168121bd64bdSRussell King (Oracle) 	phy_interface_t mode;
1682cf5ca4ddSVladimir Oltean 	struct phylink *pl;
168321bd64bdSRussell King (Oracle) 	int err;
168421bd64bdSRussell King (Oracle) 
168521bd64bdSRussell King (Oracle) 	err = of_get_phy_mode(dp->dn, &mode);
168621bd64bdSRussell King (Oracle) 	if (err)
168721bd64bdSRussell King (Oracle) 		mode = PHY_INTERFACE_MODE_NA;
168821bd64bdSRussell King (Oracle) 
16899945c1fbSRussell King (Oracle) 	if (ds->ops->phylink_get_caps) {
1690072eea6cSRussell King (Oracle) 		ds->ops->phylink_get_caps(ds, dp->index, &dp->pl_config);
16919945c1fbSRussell King (Oracle) 	} else {
16929945c1fbSRussell King (Oracle) 		/* For legacy drivers */
1693*14562277SRussell King (Oracle) 		if (mode != PHY_INTERFACE_MODE_NA) {
1694*14562277SRussell King (Oracle) 			__set_bit(mode, dp->pl_config.supported_interfaces);
1695*14562277SRussell King (Oracle) 		} else {
16969945c1fbSRussell King (Oracle) 			__set_bit(PHY_INTERFACE_MODE_INTERNAL,
16979945c1fbSRussell King (Oracle) 				  dp->pl_config.supported_interfaces);
16989945c1fbSRussell King (Oracle) 			__set_bit(PHY_INTERFACE_MODE_GMII,
16999945c1fbSRussell King (Oracle) 				  dp->pl_config.supported_interfaces);
17009945c1fbSRussell King (Oracle) 		}
1701*14562277SRussell King (Oracle) 	}
170221bd64bdSRussell King (Oracle) 
1703cf5ca4ddSVladimir Oltean 	pl = phylink_create(&dp->pl_config, of_fwnode_handle(dp->dn),
170421bd64bdSRussell King (Oracle) 			    mode, &dsa_port_phylink_mac_ops);
1705cf5ca4ddSVladimir Oltean 	if (IS_ERR(pl)) {
1706557f0501SYang Yingliang 		pr_err("error creating PHYLINK: %ld\n", PTR_ERR(pl));
1707cf5ca4ddSVladimir Oltean 		return PTR_ERR(pl);
170821bd64bdSRussell King (Oracle) 	}
170921bd64bdSRussell King (Oracle) 
1710cf5ca4ddSVladimir Oltean 	dp->pl = pl;
1711cf5ca4ddSVladimir Oltean 
171221bd64bdSRussell King (Oracle) 	return 0;
171321bd64bdSRussell King (Oracle) }
171421bd64bdSRussell King (Oracle) 
dsa_port_phylink_destroy(struct dsa_port * dp)1715cf5ca4ddSVladimir Oltean void dsa_port_phylink_destroy(struct dsa_port *dp)
1716cf5ca4ddSVladimir Oltean {
1717cf5ca4ddSVladimir Oltean 	phylink_destroy(dp->pl);
1718cf5ca4ddSVladimir Oltean 	dp->pl = NULL;
1719cf5ca4ddSVladimir Oltean }
1720cf5ca4ddSVladimir Oltean 
dsa_shared_port_setup_phy_of(struct dsa_port * dp,bool enable)1721770375ffSVladimir Oltean static int dsa_shared_port_setup_phy_of(struct dsa_port *dp, bool enable)
172233615367SSebastian Reichel {
172333615367SSebastian Reichel 	struct dsa_switch *ds = dp->ds;
172433615367SSebastian Reichel 	struct phy_device *phydev;
172533615367SSebastian Reichel 	int port = dp->index;
172633615367SSebastian Reichel 	int err = 0;
172733615367SSebastian Reichel 
17286207a78cSFlorian Fainelli 	phydev = dsa_port_get_phy_device(dp);
17296207a78cSFlorian Fainelli 	if (!phydev)
173033615367SSebastian Reichel 		return 0;
173133615367SSebastian Reichel 
17326207a78cSFlorian Fainelli 	if (IS_ERR(phydev))
17336207a78cSFlorian Fainelli 		return PTR_ERR(phydev);
173433615367SSebastian Reichel 
173533615367SSebastian Reichel 	if (enable) {
173633615367SSebastian Reichel 		err = genphy_resume(phydev);
173733615367SSebastian Reichel 		if (err < 0)
173833615367SSebastian Reichel 			goto err_put_dev;
173933615367SSebastian Reichel 
174033615367SSebastian Reichel 		err = genphy_read_status(phydev);
174133615367SSebastian Reichel 		if (err < 0)
174233615367SSebastian Reichel 			goto err_put_dev;
174333615367SSebastian Reichel 	} else {
174433615367SSebastian Reichel 		err = genphy_suspend(phydev);
174533615367SSebastian Reichel 		if (err < 0)
174633615367SSebastian Reichel 			goto err_put_dev;
174733615367SSebastian Reichel 	}
174833615367SSebastian Reichel 
174933615367SSebastian Reichel 	if (ds->ops->adjust_link)
175033615367SSebastian Reichel 		ds->ops->adjust_link(ds, port, phydev);
175133615367SSebastian Reichel 
175233615367SSebastian Reichel 	dev_dbg(ds->dev, "enabled port's phy: %s", phydev_name(phydev));
175333615367SSebastian Reichel 
175433615367SSebastian Reichel err_put_dev:
175533615367SSebastian Reichel 	put_device(&phydev->mdio.dev);
175633615367SSebastian Reichel 	return err;
175733615367SSebastian Reichel }
175833615367SSebastian Reichel 
dsa_shared_port_fixed_link_register_of(struct dsa_port * dp)1759770375ffSVladimir Oltean static int dsa_shared_port_fixed_link_register_of(struct dsa_port *dp)
176057ab1ca2SVivien Didelot {
176157ab1ca2SVivien Didelot 	struct device_node *dn = dp->dn;
176257ab1ca2SVivien Didelot 	struct dsa_switch *ds = dp->ds;
176357ab1ca2SVivien Didelot 	struct phy_device *phydev;
176457ab1ca2SVivien Didelot 	int port = dp->index;
17650c65b2b9SAndrew Lunn 	phy_interface_t mode;
176657ab1ca2SVivien Didelot 	int err;
176757ab1ca2SVivien Didelot 
176857ab1ca2SVivien Didelot 	err = of_phy_register_fixed_link(dn);
176957ab1ca2SVivien Didelot 	if (err) {
177057ab1ca2SVivien Didelot 		dev_err(ds->dev,
177157ab1ca2SVivien Didelot 			"failed to register the fixed PHY of port %d\n",
177257ab1ca2SVivien Didelot 			port);
177357ab1ca2SVivien Didelot 		return err;
177457ab1ca2SVivien Didelot 	}
177557ab1ca2SVivien Didelot 
177657ab1ca2SVivien Didelot 	phydev = of_phy_find_device(dn);
177757ab1ca2SVivien Didelot 
17780c65b2b9SAndrew Lunn 	err = of_get_phy_mode(dn, &mode);
17790c65b2b9SAndrew Lunn 	if (err)
178057ab1ca2SVivien Didelot 		mode = PHY_INTERFACE_MODE_NA;
178157ab1ca2SVivien Didelot 	phydev->interface = mode;
178257ab1ca2SVivien Didelot 
178357ab1ca2SVivien Didelot 	genphy_read_status(phydev);
178457ab1ca2SVivien Didelot 
178557ab1ca2SVivien Didelot 	if (ds->ops->adjust_link)
178657ab1ca2SVivien Didelot 		ds->ops->adjust_link(ds, port, phydev);
178757ab1ca2SVivien Didelot 
178857ab1ca2SVivien Didelot 	put_device(&phydev->mdio.dev);
178957ab1ca2SVivien Didelot 
179057ab1ca2SVivien Didelot 	return 0;
179157ab1ca2SVivien Didelot }
179257ab1ca2SVivien Didelot 
dsa_shared_port_phylink_register(struct dsa_port * dp)1793770375ffSVladimir Oltean static int dsa_shared_port_phylink_register(struct dsa_port *dp)
17940e279218SIoana Ciornei {
17950e279218SIoana Ciornei 	struct dsa_switch *ds = dp->ds;
17960e279218SIoana Ciornei 	struct device_node *port_dn = dp->dn;
17970c65b2b9SAndrew Lunn 	int err;
17980e279218SIoana Ciornei 
17990e279218SIoana Ciornei 	dp->pl_config.dev = ds->dev;
18000e279218SIoana Ciornei 	dp->pl_config.type = PHYLINK_DEV;
18010e279218SIoana Ciornei 
180221bd64bdSRussell King (Oracle) 	err = dsa_port_phylink_create(dp);
180321bd64bdSRussell King (Oracle) 	if (err)
180421bd64bdSRussell King (Oracle) 		return err;
18050e279218SIoana Ciornei 
18060e279218SIoana Ciornei 	err = phylink_of_phy_connect(dp->pl, port_dn, 0);
18072131fba5SFlorian Fainelli 	if (err && err != -ENODEV) {
18080e279218SIoana Ciornei 		pr_err("could not attach to PHY: %d\n", err);
18090e279218SIoana Ciornei 		goto err_phy_connect;
18100e279218SIoana Ciornei 	}
18110e279218SIoana Ciornei 
18120e279218SIoana Ciornei 	return 0;
18130e279218SIoana Ciornei 
18140e279218SIoana Ciornei err_phy_connect:
1815cf5ca4ddSVladimir Oltean 	dsa_port_phylink_destroy(dp);
18160e279218SIoana Ciornei 	return err;
18170e279218SIoana Ciornei }
18180e279218SIoana Ciornei 
1819e09e9873SVladimir Oltean /* During the initial DSA driver migration to OF, port nodes were sometimes
1820e09e9873SVladimir Oltean  * added to device trees with no indication of how they should operate from a
1821e09e9873SVladimir Oltean  * link management perspective (phy-handle, fixed-link, etc). Additionally, the
1822e09e9873SVladimir Oltean  * phy-mode may be absent. The interpretation of these port OF nodes depends on
1823e09e9873SVladimir Oltean  * their type.
1824e09e9873SVladimir Oltean  *
1825e09e9873SVladimir Oltean  * User ports with no phy-handle or fixed-link are expected to connect to an
1826e09e9873SVladimir Oltean  * internal PHY located on the ds->slave_mii_bus at an MDIO address equal to
1827e09e9873SVladimir Oltean  * the port number. This description is still actively supported.
1828e09e9873SVladimir Oltean  *
1829e09e9873SVladimir Oltean  * Shared (CPU and DSA) ports with no phy-handle or fixed-link are expected to
1830e09e9873SVladimir Oltean  * operate at the maximum speed that their phy-mode is capable of. If the
1831e09e9873SVladimir Oltean  * phy-mode is absent, they are expected to operate using the phy-mode
1832e09e9873SVladimir Oltean  * supported by the port that gives the highest link speed. It is unspecified
1833e09e9873SVladimir Oltean  * if the port should use flow control or not, half duplex or full duplex, or
1834e09e9873SVladimir Oltean  * if the phy-mode is a SERDES link, whether in-band autoneg is expected to be
1835e09e9873SVladimir Oltean  * enabled or not.
1836e09e9873SVladimir Oltean  *
1837e09e9873SVladimir Oltean  * In the latter case of shared ports, omitting the link management description
1838e09e9873SVladimir Oltean  * from the firmware node is deprecated and strongly discouraged. DSA uses
1839e09e9873SVladimir Oltean  * phylink, which rejects the firmware nodes of these ports for lacking
1840e09e9873SVladimir Oltean  * required properties.
1841e09e9873SVladimir Oltean  *
1842e09e9873SVladimir Oltean  * For switches in this table, DSA will skip enforcing validation and will
1843e09e9873SVladimir Oltean  * later omit registering a phylink instance for the shared ports, if they lack
1844e09e9873SVladimir Oltean  * a fixed-link, a phy-handle, or a managed = "in-band-status" property.
1845e09e9873SVladimir Oltean  * It becomes the responsibility of the driver to ensure that these ports
1846e09e9873SVladimir Oltean  * operate at the maximum speed (whatever this means) and will interoperate
1847e09e9873SVladimir Oltean  * with the DSA master or other cascade port, since phylink methods will not be
1848e09e9873SVladimir Oltean  * invoked for them.
1849e09e9873SVladimir Oltean  *
1850e09e9873SVladimir Oltean  * If you are considering expanding this table for newly introduced switches,
1851e09e9873SVladimir Oltean  * think again. It is OK to remove switches from this table if there aren't DT
1852e09e9873SVladimir Oltean  * blobs in circulation which rely on defaulting the shared ports.
1853e09e9873SVladimir Oltean  */
1854e09e9873SVladimir Oltean static const char * const dsa_switches_apply_workarounds[] = {
1855e09e9873SVladimir Oltean #if IS_ENABLED(CONFIG_NET_DSA_XRS700X)
1856e09e9873SVladimir Oltean 	"arrow,xrs7003e",
1857e09e9873SVladimir Oltean 	"arrow,xrs7003f",
1858e09e9873SVladimir Oltean 	"arrow,xrs7004e",
1859e09e9873SVladimir Oltean 	"arrow,xrs7004f",
1860e09e9873SVladimir Oltean #endif
1861e09e9873SVladimir Oltean #if IS_ENABLED(CONFIG_B53)
1862e09e9873SVladimir Oltean 	"brcm,bcm5325",
1863e09e9873SVladimir Oltean 	"brcm,bcm53115",
1864e09e9873SVladimir Oltean 	"brcm,bcm53125",
1865e09e9873SVladimir Oltean 	"brcm,bcm53128",
1866e09e9873SVladimir Oltean 	"brcm,bcm5365",
1867e09e9873SVladimir Oltean 	"brcm,bcm5389",
1868e09e9873SVladimir Oltean 	"brcm,bcm5395",
1869e09e9873SVladimir Oltean 	"brcm,bcm5397",
1870e09e9873SVladimir Oltean 	"brcm,bcm5398",
1871e09e9873SVladimir Oltean 	"brcm,bcm53010-srab",
1872e09e9873SVladimir Oltean 	"brcm,bcm53011-srab",
1873e09e9873SVladimir Oltean 	"brcm,bcm53012-srab",
1874e09e9873SVladimir Oltean 	"brcm,bcm53018-srab",
1875e09e9873SVladimir Oltean 	"brcm,bcm53019-srab",
1876e09e9873SVladimir Oltean 	"brcm,bcm5301x-srab",
1877e09e9873SVladimir Oltean 	"brcm,bcm11360-srab",
1878e09e9873SVladimir Oltean 	"brcm,bcm58522-srab",
1879e09e9873SVladimir Oltean 	"brcm,bcm58525-srab",
1880e09e9873SVladimir Oltean 	"brcm,bcm58535-srab",
1881e09e9873SVladimir Oltean 	"brcm,bcm58622-srab",
1882e09e9873SVladimir Oltean 	"brcm,bcm58623-srab",
1883e09e9873SVladimir Oltean 	"brcm,bcm58625-srab",
1884e09e9873SVladimir Oltean 	"brcm,bcm88312-srab",
1885e09e9873SVladimir Oltean 	"brcm,cygnus-srab",
1886e09e9873SVladimir Oltean 	"brcm,nsp-srab",
1887e09e9873SVladimir Oltean 	"brcm,omega-srab",
1888e09e9873SVladimir Oltean 	"brcm,bcm3384-switch",
1889e09e9873SVladimir Oltean 	"brcm,bcm6328-switch",
1890e09e9873SVladimir Oltean 	"brcm,bcm6368-switch",
1891e09e9873SVladimir Oltean 	"brcm,bcm63xx-switch",
1892e09e9873SVladimir Oltean #endif
1893e09e9873SVladimir Oltean #if IS_ENABLED(CONFIG_NET_DSA_BCM_SF2)
1894e09e9873SVladimir Oltean 	"brcm,bcm7445-switch-v4.0",
1895e09e9873SVladimir Oltean 	"brcm,bcm7278-switch-v4.0",
1896e09e9873SVladimir Oltean 	"brcm,bcm7278-switch-v4.8",
1897e09e9873SVladimir Oltean #endif
1898e09e9873SVladimir Oltean #if IS_ENABLED(CONFIG_NET_DSA_LANTIQ_GSWIP)
1899e09e9873SVladimir Oltean 	"lantiq,xrx200-gswip",
1900e09e9873SVladimir Oltean 	"lantiq,xrx300-gswip",
1901e09e9873SVladimir Oltean 	"lantiq,xrx330-gswip",
1902e09e9873SVladimir Oltean #endif
1903e09e9873SVladimir Oltean #if IS_ENABLED(CONFIG_NET_DSA_MV88E6060)
1904e09e9873SVladimir Oltean 	"marvell,mv88e6060",
1905e09e9873SVladimir Oltean #endif
1906e09e9873SVladimir Oltean #if IS_ENABLED(CONFIG_NET_DSA_MV88E6XXX)
1907e09e9873SVladimir Oltean 	"marvell,mv88e6085",
1908e09e9873SVladimir Oltean 	"marvell,mv88e6190",
1909e09e9873SVladimir Oltean 	"marvell,mv88e6250",
1910e09e9873SVladimir Oltean #endif
1911e09e9873SVladimir Oltean #if IS_ENABLED(CONFIG_NET_DSA_MICROCHIP_KSZ_COMMON)
1912e09e9873SVladimir Oltean 	"microchip,ksz8765",
1913e09e9873SVladimir Oltean 	"microchip,ksz8794",
1914e09e9873SVladimir Oltean 	"microchip,ksz8795",
1915e09e9873SVladimir Oltean 	"microchip,ksz8863",
1916e09e9873SVladimir Oltean 	"microchip,ksz8873",
1917e09e9873SVladimir Oltean 	"microchip,ksz9477",
1918e09e9873SVladimir Oltean 	"microchip,ksz9897",
1919e09e9873SVladimir Oltean 	"microchip,ksz9893",
1920e09e9873SVladimir Oltean 	"microchip,ksz9563",
1921e09e9873SVladimir Oltean 	"microchip,ksz8563",
1922e09e9873SVladimir Oltean 	"microchip,ksz9567",
1923e09e9873SVladimir Oltean #endif
1924e09e9873SVladimir Oltean #if IS_ENABLED(CONFIG_NET_DSA_SMSC_LAN9303_MDIO)
1925e09e9873SVladimir Oltean 	"smsc,lan9303-mdio",
1926e09e9873SVladimir Oltean #endif
1927e09e9873SVladimir Oltean #if IS_ENABLED(CONFIG_NET_DSA_SMSC_LAN9303_I2C)
1928e09e9873SVladimir Oltean 	"smsc,lan9303-i2c",
1929e09e9873SVladimir Oltean #endif
1930e09e9873SVladimir Oltean 	NULL,
1931e09e9873SVladimir Oltean };
1932e09e9873SVladimir Oltean 
dsa_shared_port_validate_of(struct dsa_port * dp,bool * missing_phy_mode,bool * missing_link_description)1933e09e9873SVladimir Oltean static void dsa_shared_port_validate_of(struct dsa_port *dp,
1934e09e9873SVladimir Oltean 					bool *missing_phy_mode,
1935e09e9873SVladimir Oltean 					bool *missing_link_description)
1936e09e9873SVladimir Oltean {
1937e09e9873SVladimir Oltean 	struct device_node *dn = dp->dn, *phy_np;
1938e09e9873SVladimir Oltean 	struct dsa_switch *ds = dp->ds;
1939e09e9873SVladimir Oltean 	phy_interface_t mode;
1940e09e9873SVladimir Oltean 
1941e09e9873SVladimir Oltean 	*missing_phy_mode = false;
1942e09e9873SVladimir Oltean 	*missing_link_description = false;
1943e09e9873SVladimir Oltean 
1944e09e9873SVladimir Oltean 	if (of_get_phy_mode(dn, &mode)) {
1945e09e9873SVladimir Oltean 		*missing_phy_mode = true;
1946e09e9873SVladimir Oltean 		dev_err(ds->dev,
1947e09e9873SVladimir Oltean 			"OF node %pOF of %s port %d lacks the required \"phy-mode\" property\n",
1948e09e9873SVladimir Oltean 			dn, dsa_port_is_cpu(dp) ? "CPU" : "DSA", dp->index);
1949e09e9873SVladimir Oltean 	}
1950e09e9873SVladimir Oltean 
1951e09e9873SVladimir Oltean 	/* Note: of_phy_is_fixed_link() also returns true for
1952e09e9873SVladimir Oltean 	 * managed = "in-band-status"
1953e09e9873SVladimir Oltean 	 */
1954e09e9873SVladimir Oltean 	if (of_phy_is_fixed_link(dn))
1955e09e9873SVladimir Oltean 		return;
1956e09e9873SVladimir Oltean 
1957e09e9873SVladimir Oltean 	phy_np = of_parse_phandle(dn, "phy-handle", 0);
1958e09e9873SVladimir Oltean 	if (phy_np) {
1959e09e9873SVladimir Oltean 		of_node_put(phy_np);
1960e09e9873SVladimir Oltean 		return;
1961e09e9873SVladimir Oltean 	}
1962e09e9873SVladimir Oltean 
1963e09e9873SVladimir Oltean 	*missing_link_description = true;
1964e09e9873SVladimir Oltean 
1965e09e9873SVladimir Oltean 	dev_err(ds->dev,
1966e09e9873SVladimir Oltean 		"OF node %pOF of %s port %d lacks the required \"phy-handle\", \"fixed-link\" or \"managed\" properties\n",
1967e09e9873SVladimir Oltean 		dn, dsa_port_is_cpu(dp) ? "CPU" : "DSA", dp->index);
1968e09e9873SVladimir Oltean }
1969e09e9873SVladimir Oltean 
dsa_shared_port_link_register_of(struct dsa_port * dp)1970770375ffSVladimir Oltean int dsa_shared_port_link_register_of(struct dsa_port *dp)
197157ab1ca2SVivien Didelot {
19720e279218SIoana Ciornei 	struct dsa_switch *ds = dp->ds;
1973e09e9873SVladimir Oltean 	bool missing_link_description;
1974e09e9873SVladimir Oltean 	bool missing_phy_mode;
19753be98b2dSAndrew Lunn 	int port = dp->index;
19760e279218SIoana Ciornei 
1977e09e9873SVladimir Oltean 	dsa_shared_port_validate_of(dp, &missing_phy_mode,
1978e09e9873SVladimir Oltean 				    &missing_link_description);
1979e09e9873SVladimir Oltean 
1980e09e9873SVladimir Oltean 	if ((missing_phy_mode || missing_link_description) &&
1981e09e9873SVladimir Oltean 	    !of_device_compatible_match(ds->dev->of_node,
1982e09e9873SVladimir Oltean 					dsa_switches_apply_workarounds))
1983e09e9873SVladimir Oltean 		return -EINVAL;
1984e09e9873SVladimir Oltean 
1985a20f9970SAndrew Lunn 	if (!ds->ops->adjust_link) {
1986e09e9873SVladimir Oltean 		if (missing_link_description) {
1987e09e9873SVladimir Oltean 			dev_warn(ds->dev,
1988e09e9873SVladimir Oltean 				 "Skipping phylink registration for %s port %d\n",
1989e09e9873SVladimir Oltean 				 dsa_port_is_cpu(dp) ? "CPU" : "DSA", dp->index);
1990e09e9873SVladimir Oltean 		} else {
19913be98b2dSAndrew Lunn 			if (ds->ops->phylink_mac_link_down)
19923be98b2dSAndrew Lunn 				ds->ops->phylink_mac_link_down(ds, port,
19933be98b2dSAndrew Lunn 					MLO_AN_FIXED, PHY_INTERFACE_MODE_NA);
1994e09e9873SVladimir Oltean 
1995770375ffSVladimir Oltean 			return dsa_shared_port_phylink_register(dp);
19963be98b2dSAndrew Lunn 		}
1997a20f9970SAndrew Lunn 		return 0;
1998a20f9970SAndrew Lunn 	}
19990e279218SIoana Ciornei 
20000e279218SIoana Ciornei 	dev_warn(ds->dev,
20010e279218SIoana Ciornei 		 "Using legacy PHYLIB callbacks. Please migrate to PHYLINK!\n");
20020e279218SIoana Ciornei 
200333615367SSebastian Reichel 	if (of_phy_is_fixed_link(dp->dn))
2004770375ffSVladimir Oltean 		return dsa_shared_port_fixed_link_register_of(dp);
200533615367SSebastian Reichel 	else
2006770375ffSVladimir Oltean 		return dsa_shared_port_setup_phy_of(dp, true);
200733615367SSebastian Reichel }
200857ab1ca2SVivien Didelot 
dsa_shared_port_link_unregister_of(struct dsa_port * dp)2009770375ffSVladimir Oltean void dsa_shared_port_link_unregister_of(struct dsa_port *dp)
201033615367SSebastian Reichel {
20110e279218SIoana Ciornei 	struct dsa_switch *ds = dp->ds;
20120e279218SIoana Ciornei 
2013a20f9970SAndrew Lunn 	if (!ds->ops->adjust_link && dp->pl) {
20140e279218SIoana Ciornei 		rtnl_lock();
20150e279218SIoana Ciornei 		phylink_disconnect_phy(dp->pl);
20160e279218SIoana Ciornei 		rtnl_unlock();
2017cf5ca4ddSVladimir Oltean 		dsa_port_phylink_destroy(dp);
20180e279218SIoana Ciornei 		return;
20190e279218SIoana Ciornei 	}
20200e279218SIoana Ciornei 
202133615367SSebastian Reichel 	if (of_phy_is_fixed_link(dp->dn))
202233615367SSebastian Reichel 		of_phy_deregister_fixed_link(dp->dn);
202333615367SSebastian Reichel 	else
2024770375ffSVladimir Oltean 		dsa_shared_port_setup_phy_of(dp, false);
202557ab1ca2SVivien Didelot }
2026cf963573SFlorian Fainelli 
dsa_port_hsr_join(struct dsa_port * dp,struct net_device * hsr)202718596f50SGeorge McCollister int dsa_port_hsr_join(struct dsa_port *dp, struct net_device *hsr)
202818596f50SGeorge McCollister {
2029a68dc7b9SVladimir Oltean 	struct dsa_switch *ds = dp->ds;
203018596f50SGeorge McCollister 	int err;
203118596f50SGeorge McCollister 
2032a68dc7b9SVladimir Oltean 	if (!ds->ops->port_hsr_join)
2033a68dc7b9SVladimir Oltean 		return -EOPNOTSUPP;
2034a68dc7b9SVladimir Oltean 
203518596f50SGeorge McCollister 	dp->hsr_dev = hsr;
203618596f50SGeorge McCollister 
2037a68dc7b9SVladimir Oltean 	err = ds->ops->port_hsr_join(ds, dp->index, hsr);
203818596f50SGeorge McCollister 	if (err)
203918596f50SGeorge McCollister 		dp->hsr_dev = NULL;
204018596f50SGeorge McCollister 
204118596f50SGeorge McCollister 	return err;
204218596f50SGeorge McCollister }
204318596f50SGeorge McCollister 
dsa_port_hsr_leave(struct dsa_port * dp,struct net_device * hsr)204418596f50SGeorge McCollister void dsa_port_hsr_leave(struct dsa_port *dp, struct net_device *hsr)
204518596f50SGeorge McCollister {
2046a68dc7b9SVladimir Oltean 	struct dsa_switch *ds = dp->ds;
204718596f50SGeorge McCollister 	int err;
204818596f50SGeorge McCollister 
204918596f50SGeorge McCollister 	dp->hsr_dev = NULL;
205018596f50SGeorge McCollister 
2051a68dc7b9SVladimir Oltean 	if (ds->ops->port_hsr_leave) {
2052a68dc7b9SVladimir Oltean 		err = ds->ops->port_hsr_leave(ds, dp->index, hsr);
205318596f50SGeorge McCollister 		if (err)
2054ab97462bSVladimir Oltean 			dev_err(dp->ds->dev,
2055a68dc7b9SVladimir Oltean 				"port %d failed to leave HSR %s: %pe\n",
2056a68dc7b9SVladimir Oltean 				dp->index, hsr->name, ERR_PTR(err));
2057a68dc7b9SVladimir Oltean 	}
205818596f50SGeorge McCollister }
2059c64b9c05SVladimir Oltean 
dsa_port_tag_8021q_vlan_add(struct dsa_port * dp,u16 vid,bool broadcast)2060724395f4SVladimir Oltean int dsa_port_tag_8021q_vlan_add(struct dsa_port *dp, u16 vid, bool broadcast)
2061c64b9c05SVladimir Oltean {
2062c64b9c05SVladimir Oltean 	struct dsa_notifier_tag_8021q_vlan_info info = {
2063726816a1SVladimir Oltean 		.dp = dp,
2064c64b9c05SVladimir Oltean 		.vid = vid,
2065c64b9c05SVladimir Oltean 	};
2066c64b9c05SVladimir Oltean 
2067724395f4SVladimir Oltean 	if (broadcast)
2068c64b9c05SVladimir Oltean 		return dsa_broadcast(DSA_NOTIFIER_TAG_8021Q_VLAN_ADD, &info);
2069724395f4SVladimir Oltean 
2070724395f4SVladimir Oltean 	return dsa_port_notify(dp, DSA_NOTIFIER_TAG_8021Q_VLAN_ADD, &info);
2071c64b9c05SVladimir Oltean }
2072c64b9c05SVladimir Oltean 
dsa_port_tag_8021q_vlan_del(struct dsa_port * dp,u16 vid,bool broadcast)2073724395f4SVladimir Oltean void dsa_port_tag_8021q_vlan_del(struct dsa_port *dp, u16 vid, bool broadcast)
2074c64b9c05SVladimir Oltean {
2075c64b9c05SVladimir Oltean 	struct dsa_notifier_tag_8021q_vlan_info info = {
2076726816a1SVladimir Oltean 		.dp = dp,
2077c64b9c05SVladimir Oltean 		.vid = vid,
2078c64b9c05SVladimir Oltean 	};
2079c64b9c05SVladimir Oltean 	int err;
2080c64b9c05SVladimir Oltean 
2081724395f4SVladimir Oltean 	if (broadcast)
2082c64b9c05SVladimir Oltean 		err = dsa_broadcast(DSA_NOTIFIER_TAG_8021Q_VLAN_DEL, &info);
2083724395f4SVladimir Oltean 	else
2084724395f4SVladimir Oltean 		err = dsa_port_notify(dp, DSA_NOTIFIER_TAG_8021Q_VLAN_DEL, &info);
2085c64b9c05SVladimir Oltean 	if (err)
2086ab97462bSVladimir Oltean 		dev_err(dp->ds->dev,
2087ab97462bSVladimir Oltean 			"port %d failed to notify tag_8021q VLAN %d deletion: %pe\n",
2088ab97462bSVladimir Oltean 			dp->index, vid, ERR_PTR(err));
2089c64b9c05SVladimir Oltean }
2090