xref: /linux/drivers/net/dsa/ocelot/felix.c (revision 9410645520e9b820069761f3450ef6661418e279)
156051948SVladimir Oltean // SPDX-License-Identifier: GPL-2.0
23c9cfb52SVladimir Oltean /* Copyright 2019-2021 NXP
3375e1314SVladimir Oltean  *
4375e1314SVladimir Oltean  * This is an umbrella module for all network switches that are
5375e1314SVladimir Oltean  * register-compatible with Ocelot and that perform I/O to their host CPU
6375e1314SVladimir Oltean  * through an NPI (Node Processor Interface) Ethernet port.
756051948SVladimir Oltean  */
856051948SVladimir Oltean #include <uapi/linux/if_bridge.h>
907d985eeSVladimir Oltean #include <soc/mscc/ocelot_vcap.h>
10bdeced75SVladimir Oltean #include <soc/mscc/ocelot_qsys.h>
11bdeced75SVladimir Oltean #include <soc/mscc/ocelot_sys.h>
12bdeced75SVladimir Oltean #include <soc/mscc/ocelot_dev.h>
13bdeced75SVladimir Oltean #include <soc/mscc/ocelot_ana.h>
142b49d128SYangbo Lu #include <soc/mscc/ocelot_ptp.h>
1556051948SVladimir Oltean #include <soc/mscc/ocelot.h>
16e21268efSVladimir Oltean #include <linux/dsa/8021q.h>
1740d3f295SVladimir Oltean #include <linux/dsa/ocelot.h>
1884705fc1SMaxim Kochetkov #include <linux/platform_device.h>
190a6f17c6SVladimir Oltean #include <linux/ptp_classify.h>
2056051948SVladimir Oltean #include <linux/module.h>
21bdeced75SVladimir Oltean #include <linux/of_net.h>
2256051948SVladimir Oltean #include <linux/pci.h>
2356051948SVladimir Oltean #include <linux/of.h>
24fc411eaaSVladimir Oltean #include <net/pkt_sched.h>
2556051948SVladimir Oltean #include <net/dsa.h>
2656051948SVladimir Oltean #include "felix.h"
2756051948SVladimir Oltean 
28f9cef64fSVladimir Oltean /* Translate the DSA database API into the ocelot switch library API,
29f9cef64fSVladimir Oltean  * which uses VID 0 for all ports that aren't part of a bridge,
30f9cef64fSVladimir Oltean  * and expects the bridge_dev to be NULL in that case.
31f9cef64fSVladimir Oltean  */
felix_classify_db(struct dsa_db db)32f9cef64fSVladimir Oltean static struct net_device *felix_classify_db(struct dsa_db db)
33f9cef64fSVladimir Oltean {
34f9cef64fSVladimir Oltean 	switch (db.type) {
35f9cef64fSVladimir Oltean 	case DSA_DB_PORT:
36f9cef64fSVladimir Oltean 	case DSA_DB_LAG:
37f9cef64fSVladimir Oltean 		return NULL;
38f9cef64fSVladimir Oltean 	case DSA_DB_BRIDGE:
39f9cef64fSVladimir Oltean 		return db.bridge.dev;
40f9cef64fSVladimir Oltean 	default:
41f9cef64fSVladimir Oltean 		return ERR_PTR(-EOPNOTSUPP);
42f9cef64fSVladimir Oltean 	}
43f9cef64fSVladimir Oltean }
44f9cef64fSVladimir Oltean 
felix_cpu_port_for_conduit(struct dsa_switch * ds,struct net_device * conduit)456ca80638SFlorian Fainelli static int felix_cpu_port_for_conduit(struct dsa_switch *ds,
466ca80638SFlorian Fainelli 				      struct net_device *conduit)
47eca70102SVladimir Oltean {
48eca70102SVladimir Oltean 	struct ocelot *ocelot = ds->priv;
49eca70102SVladimir Oltean 	struct dsa_port *cpu_dp;
50eca70102SVladimir Oltean 	int lag;
51eca70102SVladimir Oltean 
526ca80638SFlorian Fainelli 	if (netif_is_lag_master(conduit)) {
53eca70102SVladimir Oltean 		mutex_lock(&ocelot->fwd_domain_lock);
546ca80638SFlorian Fainelli 		lag = ocelot_bond_get_id(ocelot, conduit);
55eca70102SVladimir Oltean 		mutex_unlock(&ocelot->fwd_domain_lock);
56eca70102SVladimir Oltean 
57eca70102SVladimir Oltean 		return lag;
58eca70102SVladimir Oltean 	}
59eca70102SVladimir Oltean 
606ca80638SFlorian Fainelli 	cpu_dp = conduit->dsa_ptr;
61eca70102SVladimir Oltean 	return cpu_dp->index;
62eca70102SVladimir Oltean }
63eca70102SVladimir Oltean 
64f1288fd7SVladimir Oltean /**
65f1288fd7SVladimir Oltean  * felix_update_tag_8021q_rx_rule - Update VCAP ES0 tag_8021q rule after
66f1288fd7SVladimir Oltean  *				    vlan_filtering change
67f1288fd7SVladimir Oltean  * @outer_tagging_rule: Pointer to VCAP filter on which the update is performed
68f1288fd7SVladimir Oltean  * @vlan_filtering: Current bridge VLAN filtering setting
69f1288fd7SVladimir Oltean  *
70f1288fd7SVladimir Oltean  * Source port identification for tag_8021q is done using VCAP ES0 rules on the
71f1288fd7SVladimir Oltean  * CPU port(s). The ES0 tag B (inner tag from the packet) can be configured as
72f1288fd7SVladimir Oltean  * either:
73f1288fd7SVladimir Oltean  * - push_inner_tag=0: the inner tag is never pushed into the frame
74f1288fd7SVladimir Oltean  *		       (and we lose info about the classified VLAN). This is
75f1288fd7SVladimir Oltean  *		       good when the classified VLAN is a discardable quantity
76f1288fd7SVladimir Oltean  *		       for the software RX path: it is either set to
77f1288fd7SVladimir Oltean  *		       OCELOT_STANDALONE_PVID, or to
78f1288fd7SVladimir Oltean  *		       ocelot_vlan_unaware_pvid(bridge).
79f1288fd7SVladimir Oltean  * - push_inner_tag=1: the inner tag is always pushed. This is good when the
80f1288fd7SVladimir Oltean  *		       classified VLAN is not a discardable quantity (the port
81f1288fd7SVladimir Oltean  *		       is under a VLAN-aware bridge, and software needs to
82f1288fd7SVladimir Oltean  *		       continue processing the packet in the same VLAN as the
83f1288fd7SVladimir Oltean  *		       hardware).
84f1288fd7SVladimir Oltean  * The point is that what is good for a VLAN-unaware port is not good for a
85f1288fd7SVladimir Oltean  * VLAN-aware port, and vice versa. Thus, the RX tagging rules must be kept in
86f1288fd7SVladimir Oltean  * sync with the VLAN filtering state of the port.
87f1288fd7SVladimir Oltean  */
88f1288fd7SVladimir Oltean static void
felix_update_tag_8021q_rx_rule(struct ocelot_vcap_filter * outer_tagging_rule,bool vlan_filtering)89f1288fd7SVladimir Oltean felix_update_tag_8021q_rx_rule(struct ocelot_vcap_filter *outer_tagging_rule,
90f1288fd7SVladimir Oltean 			       bool vlan_filtering)
91f1288fd7SVladimir Oltean {
92f1288fd7SVladimir Oltean 	if (vlan_filtering)
93f1288fd7SVladimir Oltean 		outer_tagging_rule->action.push_inner_tag = OCELOT_ES0_TAG;
94f1288fd7SVladimir Oltean 	else
95f1288fd7SVladimir Oltean 		outer_tagging_rule->action.push_inner_tag = OCELOT_NO_ES0_TAG;
96f1288fd7SVladimir Oltean }
97f1288fd7SVladimir Oltean 
9804b67e18SVladimir Oltean /* Set up VCAP ES0 rules for pushing a tag_8021q VLAN towards the CPU such that
9904b67e18SVladimir Oltean  * the tagger can perform RX source port identification.
10004b67e18SVladimir Oltean  */
felix_tag_8021q_vlan_add_rx(struct dsa_switch * ds,int port,int upstream,u16 vid,bool vlan_filtering)101a4e044dcSVladimir Oltean static int felix_tag_8021q_vlan_add_rx(struct dsa_switch *ds, int port,
102f1288fd7SVladimir Oltean 				       int upstream, u16 vid,
103f1288fd7SVladimir Oltean 				       bool vlan_filtering)
104e21268efSVladimir Oltean {
105e21268efSVladimir Oltean 	struct ocelot_vcap_filter *outer_tagging_rule;
106a4e044dcSVladimir Oltean 	struct ocelot *ocelot = ds->priv;
107a4e044dcSVladimir Oltean 	unsigned long cookie;
108a4e044dcSVladimir Oltean 	int key_length, err;
109e21268efSVladimir Oltean 
110e21268efSVladimir Oltean 	key_length = ocelot->vcap[VCAP_ES0].keys[VCAP_ES0_IGR_PORT].length;
111e21268efSVladimir Oltean 
112e21268efSVladimir Oltean 	outer_tagging_rule = kzalloc(sizeof(struct ocelot_vcap_filter),
113e21268efSVladimir Oltean 				     GFP_KERNEL);
114e21268efSVladimir Oltean 	if (!outer_tagging_rule)
115e21268efSVladimir Oltean 		return -ENOMEM;
116e21268efSVladimir Oltean 
117a4e044dcSVladimir Oltean 	cookie = OCELOT_VCAP_ES0_TAG_8021Q_RXVLAN(ocelot, port, upstream);
118a4e044dcSVladimir Oltean 
119e21268efSVladimir Oltean 	outer_tagging_rule->key_type = OCELOT_VCAP_KEY_ANY;
120e21268efSVladimir Oltean 	outer_tagging_rule->prio = 1;
121a4e044dcSVladimir Oltean 	outer_tagging_rule->id.cookie = cookie;
122e21268efSVladimir Oltean 	outer_tagging_rule->id.tc_offload = false;
123e21268efSVladimir Oltean 	outer_tagging_rule->block_id = VCAP_ES0;
124e21268efSVladimir Oltean 	outer_tagging_rule->type = OCELOT_VCAP_FILTER_OFFLOAD;
125e21268efSVladimir Oltean 	outer_tagging_rule->lookup = 0;
126e21268efSVladimir Oltean 	outer_tagging_rule->ingress_port.value = port;
127e21268efSVladimir Oltean 	outer_tagging_rule->ingress_port.mask = GENMASK(key_length - 1, 0);
128e21268efSVladimir Oltean 	outer_tagging_rule->egress_port.value = upstream;
129e21268efSVladimir Oltean 	outer_tagging_rule->egress_port.mask = GENMASK(key_length - 1, 0);
130e21268efSVladimir Oltean 	outer_tagging_rule->action.push_outer_tag = OCELOT_ES0_TAG;
131e21268efSVladimir Oltean 	outer_tagging_rule->action.tag_a_tpid_sel = OCELOT_TAG_TPID_SEL_8021AD;
132e21268efSVladimir Oltean 	outer_tagging_rule->action.tag_a_vid_sel = 1;
133e21268efSVladimir Oltean 	outer_tagging_rule->action.vid_a_val = vid;
134f1288fd7SVladimir Oltean 	felix_update_tag_8021q_rx_rule(outer_tagging_rule, vlan_filtering);
135f1288fd7SVladimir Oltean 	outer_tagging_rule->action.tag_b_tpid_sel = OCELOT_TAG_TPID_SEL_8021Q;
136f1288fd7SVladimir Oltean 	/* Leave TAG_B_VID_SEL at 0 (Classified VID + VID_B_VAL). Since we also
137f1288fd7SVladimir Oltean 	 * leave VID_B_VAL at 0, this makes ES0 tag B (the inner tag) equal to
138f1288fd7SVladimir Oltean 	 * the classified VID, which we need to see in the DSA tagger's receive
139f1288fd7SVladimir Oltean 	 * path. Note: the inner tag is only visible in the packet when pushed
140f1288fd7SVladimir Oltean 	 * (push_inner_tag == OCELOT_ES0_TAG).
141f1288fd7SVladimir Oltean 	 */
142e21268efSVladimir Oltean 
143e21268efSVladimir Oltean 	err = ocelot_vcap_filter_add(ocelot, outer_tagging_rule, NULL);
144e21268efSVladimir Oltean 	if (err)
145e21268efSVladimir Oltean 		kfree(outer_tagging_rule);
146e21268efSVladimir Oltean 
147e21268efSVladimir Oltean 	return err;
148e21268efSVladimir Oltean }
149e21268efSVladimir Oltean 
felix_tag_8021q_vlan_del_rx(struct dsa_switch * ds,int port,int upstream,u16 vid)150a4e044dcSVladimir Oltean static int felix_tag_8021q_vlan_del_rx(struct dsa_switch *ds, int port,
151a4e044dcSVladimir Oltean 				       int upstream, u16 vid)
15204b67e18SVladimir Oltean {
15304b67e18SVladimir Oltean 	struct ocelot_vcap_filter *outer_tagging_rule;
15404b67e18SVladimir Oltean 	struct ocelot_vcap_block *block_vcap_es0;
155a4e044dcSVladimir Oltean 	struct ocelot *ocelot = ds->priv;
156a4e044dcSVladimir Oltean 	unsigned long cookie;
15704b67e18SVladimir Oltean 
15804b67e18SVladimir Oltean 	block_vcap_es0 = &ocelot->block[VCAP_ES0];
159a4e044dcSVladimir Oltean 	cookie = OCELOT_VCAP_ES0_TAG_8021Q_RXVLAN(ocelot, port, upstream);
16004b67e18SVladimir Oltean 
16104b67e18SVladimir Oltean 	outer_tagging_rule = ocelot_vcap_block_find_filter_by_id(block_vcap_es0,
162a4e044dcSVladimir Oltean 								 cookie, false);
16304b67e18SVladimir Oltean 	if (!outer_tagging_rule)
16404b67e18SVladimir Oltean 		return -ENOENT;
16504b67e18SVladimir Oltean 
16604b67e18SVladimir Oltean 	return ocelot_vcap_filter_del(ocelot, outer_tagging_rule);
16704b67e18SVladimir Oltean }
16804b67e18SVladimir Oltean 
16904b67e18SVladimir Oltean /* Set up VCAP IS1 rules for stripping the tag_8021q VLAN on TX and VCAP IS2
17004b67e18SVladimir Oltean  * rules for steering those tagged packets towards the correct destination port
17104b67e18SVladimir Oltean  */
felix_tag_8021q_vlan_add_tx(struct dsa_switch * ds,int port,u16 vid)172a4e044dcSVladimir Oltean static int felix_tag_8021q_vlan_add_tx(struct dsa_switch *ds, int port,
173a4e044dcSVladimir Oltean 				       u16 vid)
174e21268efSVladimir Oltean {
175e21268efSVladimir Oltean 	struct ocelot_vcap_filter *untagging_rule, *redirect_rule;
176a4e044dcSVladimir Oltean 	unsigned long cpu_ports = dsa_cpu_ports(ds);
177a4e044dcSVladimir Oltean 	struct ocelot *ocelot = ds->priv;
178a4e044dcSVladimir Oltean 	unsigned long cookie;
179a4e044dcSVladimir Oltean 	int err;
180e21268efSVladimir Oltean 
181e21268efSVladimir Oltean 	untagging_rule = kzalloc(sizeof(struct ocelot_vcap_filter), GFP_KERNEL);
182e21268efSVladimir Oltean 	if (!untagging_rule)
183e21268efSVladimir Oltean 		return -ENOMEM;
184e21268efSVladimir Oltean 
185e21268efSVladimir Oltean 	redirect_rule = kzalloc(sizeof(struct ocelot_vcap_filter), GFP_KERNEL);
186e21268efSVladimir Oltean 	if (!redirect_rule) {
187e21268efSVladimir Oltean 		kfree(untagging_rule);
188e21268efSVladimir Oltean 		return -ENOMEM;
189e21268efSVladimir Oltean 	}
190e21268efSVladimir Oltean 
191a4e044dcSVladimir Oltean 	cookie = OCELOT_VCAP_IS1_TAG_8021Q_TXVLAN(ocelot, port);
192e21268efSVladimir Oltean 
193e21268efSVladimir Oltean 	untagging_rule->key_type = OCELOT_VCAP_KEY_ANY;
194a4e044dcSVladimir Oltean 	untagging_rule->ingress_port_mask = cpu_ports;
195e21268efSVladimir Oltean 	untagging_rule->vlan.vid.value = vid;
196e21268efSVladimir Oltean 	untagging_rule->vlan.vid.mask = VLAN_VID_MASK;
197e21268efSVladimir Oltean 	untagging_rule->prio = 1;
198a4e044dcSVladimir Oltean 	untagging_rule->id.cookie = cookie;
199e21268efSVladimir Oltean 	untagging_rule->id.tc_offload = false;
200e21268efSVladimir Oltean 	untagging_rule->block_id = VCAP_IS1;
201e21268efSVladimir Oltean 	untagging_rule->type = OCELOT_VCAP_FILTER_OFFLOAD;
202e21268efSVladimir Oltean 	untagging_rule->lookup = 0;
203e21268efSVladimir Oltean 	untagging_rule->action.vlan_pop_cnt_ena = true;
204e21268efSVladimir Oltean 	untagging_rule->action.vlan_pop_cnt = 1;
205e21268efSVladimir Oltean 	untagging_rule->action.pag_override_mask = 0xff;
206e21268efSVladimir Oltean 	untagging_rule->action.pag_val = port;
207e21268efSVladimir Oltean 
208e21268efSVladimir Oltean 	err = ocelot_vcap_filter_add(ocelot, untagging_rule, NULL);
209e21268efSVladimir Oltean 	if (err) {
210e21268efSVladimir Oltean 		kfree(untagging_rule);
211e21268efSVladimir Oltean 		kfree(redirect_rule);
212e21268efSVladimir Oltean 		return err;
213e21268efSVladimir Oltean 	}
214e21268efSVladimir Oltean 
215a4e044dcSVladimir Oltean 	cookie = OCELOT_VCAP_IS2_TAG_8021Q_TXVLAN(ocelot, port);
216a4e044dcSVladimir Oltean 
217e21268efSVladimir Oltean 	redirect_rule->key_type = OCELOT_VCAP_KEY_ANY;
218a4e044dcSVladimir Oltean 	redirect_rule->ingress_port_mask = cpu_ports;
219e21268efSVladimir Oltean 	redirect_rule->pag = port;
220e21268efSVladimir Oltean 	redirect_rule->prio = 1;
221a4e044dcSVladimir Oltean 	redirect_rule->id.cookie = cookie;
222e21268efSVladimir Oltean 	redirect_rule->id.tc_offload = false;
223e21268efSVladimir Oltean 	redirect_rule->block_id = VCAP_IS2;
224e21268efSVladimir Oltean 	redirect_rule->type = OCELOT_VCAP_FILTER_OFFLOAD;
225e21268efSVladimir Oltean 	redirect_rule->lookup = 0;
226e21268efSVladimir Oltean 	redirect_rule->action.mask_mode = OCELOT_MASK_MODE_REDIRECT;
227e21268efSVladimir Oltean 	redirect_rule->action.port_mask = BIT(port);
228e21268efSVladimir Oltean 
229e21268efSVladimir Oltean 	err = ocelot_vcap_filter_add(ocelot, redirect_rule, NULL);
230e21268efSVladimir Oltean 	if (err) {
231e21268efSVladimir Oltean 		ocelot_vcap_filter_del(ocelot, untagging_rule);
232e21268efSVladimir Oltean 		kfree(redirect_rule);
233e21268efSVladimir Oltean 		return err;
234e21268efSVladimir Oltean 	}
235e21268efSVladimir Oltean 
236e21268efSVladimir Oltean 	return 0;
237e21268efSVladimir Oltean }
238e21268efSVladimir Oltean 
felix_tag_8021q_vlan_del_tx(struct dsa_switch * ds,int port,u16 vid)239a4e044dcSVladimir Oltean static int felix_tag_8021q_vlan_del_tx(struct dsa_switch *ds, int port, u16 vid)
240e21268efSVladimir Oltean {
241e21268efSVladimir Oltean 	struct ocelot_vcap_filter *untagging_rule, *redirect_rule;
242e21268efSVladimir Oltean 	struct ocelot_vcap_block *block_vcap_is1;
243e21268efSVladimir Oltean 	struct ocelot_vcap_block *block_vcap_is2;
244a4e044dcSVladimir Oltean 	struct ocelot *ocelot = ds->priv;
245a4e044dcSVladimir Oltean 	unsigned long cookie;
246e21268efSVladimir Oltean 	int err;
247e21268efSVladimir Oltean 
248e21268efSVladimir Oltean 	block_vcap_is1 = &ocelot->block[VCAP_IS1];
249e21268efSVladimir Oltean 	block_vcap_is2 = &ocelot->block[VCAP_IS2];
250e21268efSVladimir Oltean 
251a4e044dcSVladimir Oltean 	cookie = OCELOT_VCAP_IS1_TAG_8021Q_TXVLAN(ocelot, port);
252e21268efSVladimir Oltean 	untagging_rule = ocelot_vcap_block_find_filter_by_id(block_vcap_is1,
253a4e044dcSVladimir Oltean 							     cookie, false);
254e21268efSVladimir Oltean 	if (!untagging_rule)
25508f44db3SVladimir Oltean 		return -ENOENT;
256e21268efSVladimir Oltean 
257e21268efSVladimir Oltean 	err = ocelot_vcap_filter_del(ocelot, untagging_rule);
258e21268efSVladimir Oltean 	if (err)
259e21268efSVladimir Oltean 		return err;
260e21268efSVladimir Oltean 
261a4e044dcSVladimir Oltean 	cookie = OCELOT_VCAP_IS2_TAG_8021Q_TXVLAN(ocelot, port);
262e21268efSVladimir Oltean 	redirect_rule = ocelot_vcap_block_find_filter_by_id(block_vcap_is2,
263a4e044dcSVladimir Oltean 							    cookie, false);
264e21268efSVladimir Oltean 	if (!redirect_rule)
26504b67e18SVladimir Oltean 		return -ENOENT;
266e21268efSVladimir Oltean 
267e21268efSVladimir Oltean 	return ocelot_vcap_filter_del(ocelot, redirect_rule);
268e21268efSVladimir Oltean }
269e21268efSVladimir Oltean 
felix_tag_8021q_vlan_add(struct dsa_switch * ds,int port,u16 vid,u16 flags)27004b67e18SVladimir Oltean static int felix_tag_8021q_vlan_add(struct dsa_switch *ds, int port, u16 vid,
27104b67e18SVladimir Oltean 				    u16 flags)
27204b67e18SVladimir Oltean {
273f1288fd7SVladimir Oltean 	struct dsa_port *dp = dsa_to_port(ds, port);
274a4e044dcSVladimir Oltean 	struct dsa_port *cpu_dp;
27504b67e18SVladimir Oltean 	int err;
27604b67e18SVladimir Oltean 
27704b67e18SVladimir Oltean 	/* tag_8021q.c assumes we are implementing this via port VLAN
27804b67e18SVladimir Oltean 	 * membership, which we aren't. So we don't need to add any VCAP filter
27904b67e18SVladimir Oltean 	 * for the CPU port.
28004b67e18SVladimir Oltean 	 */
281f1288fd7SVladimir Oltean 	if (!dsa_port_is_user(dp))
28204b67e18SVladimir Oltean 		return 0;
28304b67e18SVladimir Oltean 
284a4e044dcSVladimir Oltean 	dsa_switch_for_each_cpu_port(cpu_dp, ds) {
285f1288fd7SVladimir Oltean 		err = felix_tag_8021q_vlan_add_rx(ds, port, cpu_dp->index, vid,
286f1288fd7SVladimir Oltean 						  dsa_port_is_vlan_filtering(dp));
28704b67e18SVladimir Oltean 		if (err)
28804b67e18SVladimir Oltean 			return err;
28904b67e18SVladimir Oltean 	}
29004b67e18SVladimir Oltean 
291a4e044dcSVladimir Oltean 	err = felix_tag_8021q_vlan_add_tx(ds, port, vid);
292a4e044dcSVladimir Oltean 	if (err)
293a4e044dcSVladimir Oltean 		goto add_tx_failed;
294a4e044dcSVladimir Oltean 
29504b67e18SVladimir Oltean 	return 0;
296a4e044dcSVladimir Oltean 
297a4e044dcSVladimir Oltean add_tx_failed:
298a4e044dcSVladimir Oltean 	dsa_switch_for_each_cpu_port(cpu_dp, ds)
299a4e044dcSVladimir Oltean 		felix_tag_8021q_vlan_del_rx(ds, port, cpu_dp->index, vid);
300a4e044dcSVladimir Oltean 
301a4e044dcSVladimir Oltean 	return err;
30204b67e18SVladimir Oltean }
30304b67e18SVladimir Oltean 
felix_tag_8021q_vlan_del(struct dsa_switch * ds,int port,u16 vid)304e21268efSVladimir Oltean static int felix_tag_8021q_vlan_del(struct dsa_switch *ds, int port, u16 vid)
305e21268efSVladimir Oltean {
306f1288fd7SVladimir Oltean 	struct dsa_port *dp = dsa_to_port(ds, port);
307a4e044dcSVladimir Oltean 	struct dsa_port *cpu_dp;
30804b67e18SVladimir Oltean 	int err;
309e21268efSVladimir Oltean 
310f1288fd7SVladimir Oltean 	if (!dsa_port_is_user(dp))
31104b67e18SVladimir Oltean 		return 0;
312e21268efSVladimir Oltean 
313a4e044dcSVladimir Oltean 	dsa_switch_for_each_cpu_port(cpu_dp, ds) {
314a4e044dcSVladimir Oltean 		err = felix_tag_8021q_vlan_del_rx(ds, port, cpu_dp->index, vid);
31504b67e18SVladimir Oltean 		if (err)
31604b67e18SVladimir Oltean 			return err;
31704b67e18SVladimir Oltean 	}
318e21268efSVladimir Oltean 
319a4e044dcSVladimir Oltean 	err = felix_tag_8021q_vlan_del_tx(ds, port, vid);
320a4e044dcSVladimir Oltean 	if (err)
321a4e044dcSVladimir Oltean 		goto del_tx_failed;
322a4e044dcSVladimir Oltean 
323e21268efSVladimir Oltean 	return 0;
324a4e044dcSVladimir Oltean 
325a4e044dcSVladimir Oltean del_tx_failed:
326a4e044dcSVladimir Oltean 	dsa_switch_for_each_cpu_port(cpu_dp, ds)
327f1288fd7SVladimir Oltean 		felix_tag_8021q_vlan_add_rx(ds, port, cpu_dp->index, vid,
328f1288fd7SVladimir Oltean 					    dsa_port_is_vlan_filtering(dp));
329a4e044dcSVladimir Oltean 
330a4e044dcSVladimir Oltean 	return err;
331e21268efSVladimir Oltean }
332e21268efSVladimir Oltean 
felix_update_tag_8021q_rx_rules(struct dsa_switch * ds,int port,bool vlan_filtering)333f1288fd7SVladimir Oltean static int felix_update_tag_8021q_rx_rules(struct dsa_switch *ds, int port,
334f1288fd7SVladimir Oltean 					   bool vlan_filtering)
335f1288fd7SVladimir Oltean {
336f1288fd7SVladimir Oltean 	struct ocelot_vcap_filter *outer_tagging_rule;
337f1288fd7SVladimir Oltean 	struct ocelot_vcap_block *block_vcap_es0;
338f1288fd7SVladimir Oltean 	struct ocelot *ocelot = ds->priv;
339f1288fd7SVladimir Oltean 	struct dsa_port *cpu_dp;
340f1288fd7SVladimir Oltean 	unsigned long cookie;
341f1288fd7SVladimir Oltean 	int err;
342f1288fd7SVladimir Oltean 
343f1288fd7SVladimir Oltean 	block_vcap_es0 = &ocelot->block[VCAP_ES0];
344f1288fd7SVladimir Oltean 
345f1288fd7SVladimir Oltean 	dsa_switch_for_each_cpu_port(cpu_dp, ds) {
346f1288fd7SVladimir Oltean 		cookie = OCELOT_VCAP_ES0_TAG_8021Q_RXVLAN(ocelot, port,
347f1288fd7SVladimir Oltean 							  cpu_dp->index);
348f1288fd7SVladimir Oltean 
349f1288fd7SVladimir Oltean 		outer_tagging_rule = ocelot_vcap_block_find_filter_by_id(block_vcap_es0,
350f1288fd7SVladimir Oltean 									 cookie, false);
351f1288fd7SVladimir Oltean 
352f1288fd7SVladimir Oltean 		felix_update_tag_8021q_rx_rule(outer_tagging_rule, vlan_filtering);
353f1288fd7SVladimir Oltean 
354f1288fd7SVladimir Oltean 		err = ocelot_vcap_filter_replace(ocelot, outer_tagging_rule);
355f1288fd7SVladimir Oltean 		if (err)
356f1288fd7SVladimir Oltean 			return err;
357f1288fd7SVladimir Oltean 	}
358f1288fd7SVladimir Oltean 
359f1288fd7SVladimir Oltean 	return 0;
360f1288fd7SVladimir Oltean }
361f1288fd7SVladimir Oltean 
felix_trap_get_cpu_port(struct dsa_switch * ds,const struct ocelot_vcap_filter * trap)362c352e5e8SVladimir Oltean static int felix_trap_get_cpu_port(struct dsa_switch *ds,
363c352e5e8SVladimir Oltean 				   const struct ocelot_vcap_filter *trap)
364c352e5e8SVladimir Oltean {
365c352e5e8SVladimir Oltean 	struct dsa_port *dp;
366c352e5e8SVladimir Oltean 	int first_port;
367c352e5e8SVladimir Oltean 
368c352e5e8SVladimir Oltean 	if (WARN_ON(!trap->ingress_port_mask))
369c352e5e8SVladimir Oltean 		return -1;
370c352e5e8SVladimir Oltean 
371c352e5e8SVladimir Oltean 	first_port = __ffs(trap->ingress_port_mask);
372c352e5e8SVladimir Oltean 	dp = dsa_to_port(ds, first_port);
373c352e5e8SVladimir Oltean 
374c352e5e8SVladimir Oltean 	return dp->cpu_dp->index;
375c352e5e8SVladimir Oltean }
376c352e5e8SVladimir Oltean 
37799348004SVladimir Oltean /* On switches with no extraction IRQ wired, trapped packets need to be
37899348004SVladimir Oltean  * replicated over Ethernet as well, otherwise we'd get no notification of
37999348004SVladimir Oltean  * their arrival when using the ocelot-8021q tagging protocol.
380c8c0ba4fSVladimir Oltean  */
felix_update_trapping_destinations(struct dsa_switch * ds,bool using_tag_8021q)38199348004SVladimir Oltean static int felix_update_trapping_destinations(struct dsa_switch *ds,
38299348004SVladimir Oltean 					      bool using_tag_8021q)
383c8c0ba4fSVladimir Oltean {
38499348004SVladimir Oltean 	struct ocelot *ocelot = ds->priv;
38599348004SVladimir Oltean 	struct felix *felix = ocelot_to_felix(ocelot);
386e1846cffSVladimir Oltean 	struct ocelot_vcap_block *block_vcap_is2;
38799348004SVladimir Oltean 	struct ocelot_vcap_filter *trap;
38899348004SVladimir Oltean 	enum ocelot_mask_mode mask_mode;
38999348004SVladimir Oltean 	unsigned long port_mask;
39099348004SVladimir Oltean 	bool cpu_copy_ena;
391c352e5e8SVladimir Oltean 	int err;
392c8c0ba4fSVladimir Oltean 
39399348004SVladimir Oltean 	if (!felix->info->quirk_no_xtr_irq)
39499348004SVladimir Oltean 		return 0;
395c8c0ba4fSVladimir Oltean 
396d78637a8SVladimir Oltean 	/* We are sure that "cpu" was found, otherwise
397d78637a8SVladimir Oltean 	 * dsa_tree_setup_default_cpu() would have failed earlier.
398d78637a8SVladimir Oltean 	 */
399e1846cffSVladimir Oltean 	block_vcap_is2 = &ocelot->block[VCAP_IS2];
400c8c0ba4fSVladimir Oltean 
40199348004SVladimir Oltean 	/* Make sure all traps are set up for that destination */
402e1846cffSVladimir Oltean 	list_for_each_entry(trap, &block_vcap_is2->rules, list) {
403e1846cffSVladimir Oltean 		if (!trap->is_trap)
404e1846cffSVladimir Oltean 			continue;
405e1846cffSVladimir Oltean 
40699348004SVladimir Oltean 		/* Figure out the current trapping destination */
40799348004SVladimir Oltean 		if (using_tag_8021q) {
40899348004SVladimir Oltean 			/* Redirect to the tag_8021q CPU port. If timestamps
40999348004SVladimir Oltean 			 * are necessary, also copy trapped packets to the CPU
41099348004SVladimir Oltean 			 * port module.
411c8c0ba4fSVladimir Oltean 			 */
41299348004SVladimir Oltean 			mask_mode = OCELOT_MASK_MODE_REDIRECT;
413c352e5e8SVladimir Oltean 			port_mask = BIT(felix_trap_get_cpu_port(ds, trap));
41499348004SVladimir Oltean 			cpu_copy_ena = !!trap->take_ts;
415c8c0ba4fSVladimir Oltean 		} else {
41699348004SVladimir Oltean 			/* Trap packets only to the CPU port module, which is
41799348004SVladimir Oltean 			 * redirected to the NPI port (the DSA CPU port)
418c8c0ba4fSVladimir Oltean 			 */
41999348004SVladimir Oltean 			mask_mode = OCELOT_MASK_MODE_PERMIT_DENY;
42099348004SVladimir Oltean 			port_mask = 0;
42199348004SVladimir Oltean 			cpu_copy_ena = true;
422c8c0ba4fSVladimir Oltean 		}
423c8c0ba4fSVladimir Oltean 
42499348004SVladimir Oltean 		if (trap->action.mask_mode == mask_mode &&
42599348004SVladimir Oltean 		    trap->action.port_mask == port_mask &&
42699348004SVladimir Oltean 		    trap->action.cpu_copy_ena == cpu_copy_ena)
42799348004SVladimir Oltean 			continue;
428c8c0ba4fSVladimir Oltean 
42999348004SVladimir Oltean 		trap->action.mask_mode = mask_mode;
43099348004SVladimir Oltean 		trap->action.port_mask = port_mask;
43199348004SVladimir Oltean 		trap->action.cpu_copy_ena = cpu_copy_ena;
4320a6f17c6SVladimir Oltean 
43399348004SVladimir Oltean 		err = ocelot_vcap_filter_replace(ocelot, trap);
434c8c0ba4fSVladimir Oltean 		if (err)
435c8c0ba4fSVladimir Oltean 			return err;
43699348004SVladimir Oltean 	}
437c8c0ba4fSVladimir Oltean 
43899348004SVladimir Oltean 	return 0;
439c8c0ba4fSVladimir Oltean }
440c8c0ba4fSVladimir Oltean 
441adb3dccfSVladimir Oltean /* The CPU port module is connected to the Node Processor Interface (NPI). This
442adb3dccfSVladimir Oltean  * is the mode through which frames can be injected from and extracted to an
443adb3dccfSVladimir Oltean  * external CPU, over Ethernet. In NXP SoCs, the "external CPU" is the ARM CPU
444adb3dccfSVladimir Oltean  * running Linux, and this forms a DSA setup together with the enetc or fman
4456ca80638SFlorian Fainelli  * DSA conduit.
446adb3dccfSVladimir Oltean  */
felix_npi_port_init(struct ocelot * ocelot,int port)447adb3dccfSVladimir Oltean static void felix_npi_port_init(struct ocelot *ocelot, int port)
448adb3dccfSVladimir Oltean {
449adb3dccfSVladimir Oltean 	ocelot->npi = port;
450adb3dccfSVladimir Oltean 
451adb3dccfSVladimir Oltean 	ocelot_write(ocelot, QSYS_EXT_CPU_CFG_EXT_CPUQ_MSK_M |
452adb3dccfSVladimir Oltean 		     QSYS_EXT_CPU_CFG_EXT_CPU_PORT(port),
453adb3dccfSVladimir Oltean 		     QSYS_EXT_CPU_CFG);
454adb3dccfSVladimir Oltean 
455adb3dccfSVladimir Oltean 	/* NPI port Injection/Extraction configuration */
456adb3dccfSVladimir Oltean 	ocelot_fields_write(ocelot, port, SYS_PORT_MODE_INCL_XTR_HDR,
457adb3dccfSVladimir Oltean 			    ocelot->npi_xtr_prefix);
458adb3dccfSVladimir Oltean 	ocelot_fields_write(ocelot, port, SYS_PORT_MODE_INCL_INJ_HDR,
459adb3dccfSVladimir Oltean 			    ocelot->npi_inj_prefix);
460adb3dccfSVladimir Oltean 
461adb3dccfSVladimir Oltean 	/* Disable transmission of pause frames */
462adb3dccfSVladimir Oltean 	ocelot_fields_write(ocelot, port, SYS_PAUSE_CFG_PAUSE_ENA, 0);
463adb3dccfSVladimir Oltean }
464adb3dccfSVladimir Oltean 
felix_npi_port_deinit(struct ocelot * ocelot,int port)465adb3dccfSVladimir Oltean static void felix_npi_port_deinit(struct ocelot *ocelot, int port)
466adb3dccfSVladimir Oltean {
467adb3dccfSVladimir Oltean 	/* Restore hardware defaults */
468adb3dccfSVladimir Oltean 	int unused_port = ocelot->num_phys_ports + 2;
469adb3dccfSVladimir Oltean 
470adb3dccfSVladimir Oltean 	ocelot->npi = -1;
471adb3dccfSVladimir Oltean 
472adb3dccfSVladimir Oltean 	ocelot_write(ocelot, QSYS_EXT_CPU_CFG_EXT_CPU_PORT(unused_port),
473adb3dccfSVladimir Oltean 		     QSYS_EXT_CPU_CFG);
474adb3dccfSVladimir Oltean 
475adb3dccfSVladimir Oltean 	ocelot_fields_write(ocelot, port, SYS_PORT_MODE_INCL_XTR_HDR,
476adb3dccfSVladimir Oltean 			    OCELOT_TAG_PREFIX_DISABLED);
477adb3dccfSVladimir Oltean 	ocelot_fields_write(ocelot, port, SYS_PORT_MODE_INCL_INJ_HDR,
478adb3dccfSVladimir Oltean 			    OCELOT_TAG_PREFIX_DISABLED);
479adb3dccfSVladimir Oltean 
480adb3dccfSVladimir Oltean 	/* Enable transmission of pause frames */
481adb3dccfSVladimir Oltean 	ocelot_fields_write(ocelot, port, SYS_PAUSE_CFG_PAUSE_ENA, 1);
482adb3dccfSVladimir Oltean }
483adb3dccfSVladimir Oltean 
felix_tag_npi_setup(struct dsa_switch * ds)4847a29d220SVladimir Oltean static int felix_tag_npi_setup(struct dsa_switch *ds)
485adb3dccfSVladimir Oltean {
4867a29d220SVladimir Oltean 	struct dsa_port *dp, *first_cpu_dp = NULL;
487adb3dccfSVladimir Oltean 	struct ocelot *ocelot = ds->priv;
488f9cef64fSVladimir Oltean 
4897a29d220SVladimir Oltean 	dsa_switch_for_each_user_port(dp, ds) {
4907a29d220SVladimir Oltean 		if (first_cpu_dp && dp->cpu_dp != first_cpu_dp) {
4917a29d220SVladimir Oltean 			dev_err(ds->dev, "Multiple NPI ports not supported\n");
4927a29d220SVladimir Oltean 			return -EINVAL;
4937a29d220SVladimir Oltean 		}
494b903a6bdSVladimir Oltean 
4957a29d220SVladimir Oltean 		first_cpu_dp = dp->cpu_dp;
4967a29d220SVladimir Oltean 	}
497adb3dccfSVladimir Oltean 
4987a29d220SVladimir Oltean 	if (!first_cpu_dp)
4997a29d220SVladimir Oltean 		return -EINVAL;
5007a29d220SVladimir Oltean 
5017a29d220SVladimir Oltean 	felix_npi_port_init(ocelot, first_cpu_dp->index);
502adb3dccfSVladimir Oltean 
503adb3dccfSVladimir Oltean 	return 0;
504adb3dccfSVladimir Oltean }
505adb3dccfSVladimir Oltean 
felix_tag_npi_teardown(struct dsa_switch * ds)5067a29d220SVladimir Oltean static void felix_tag_npi_teardown(struct dsa_switch *ds)
507adb3dccfSVladimir Oltean {
508adb3dccfSVladimir Oltean 	struct ocelot *ocelot = ds->priv;
509adb3dccfSVladimir Oltean 
5107a29d220SVladimir Oltean 	felix_npi_port_deinit(ocelot, ocelot->npi);
511adb3dccfSVladimir Oltean }
512adb3dccfSVladimir Oltean 
felix_tag_npi_get_host_fwd_mask(struct dsa_switch * ds)5137a29d220SVladimir Oltean static unsigned long felix_tag_npi_get_host_fwd_mask(struct dsa_switch *ds)
514adb3dccfSVladimir Oltean {
5157a29d220SVladimir Oltean 	struct ocelot *ocelot = ds->priv;
5167a29d220SVladimir Oltean 
5177a29d220SVladimir Oltean 	return BIT(ocelot->num_phys_ports);
5187a29d220SVladimir Oltean }
5197a29d220SVladimir Oltean 
felix_tag_npi_change_conduit(struct dsa_switch * ds,int port,struct net_device * conduit,struct netlink_ext_ack * extack)5206ca80638SFlorian Fainelli static int felix_tag_npi_change_conduit(struct dsa_switch *ds, int port,
5216ca80638SFlorian Fainelli 					struct net_device *conduit,
522eca70102SVladimir Oltean 					struct netlink_ext_ack *extack)
523eca70102SVladimir Oltean {
524eca70102SVladimir Oltean 	struct dsa_port *dp = dsa_to_port(ds, port), *other_dp;
525eca70102SVladimir Oltean 	struct ocelot *ocelot = ds->priv;
526eca70102SVladimir Oltean 
5276ca80638SFlorian Fainelli 	if (netif_is_lag_master(conduit)) {
528eca70102SVladimir Oltean 		NL_SET_ERR_MSG_MOD(extack,
5296ca80638SFlorian Fainelli 				   "LAG DSA conduit only supported using ocelot-8021q");
530eca70102SVladimir Oltean 		return -EOPNOTSUPP;
531eca70102SVladimir Oltean 	}
532eca70102SVladimir Oltean 
533eca70102SVladimir Oltean 	/* Changing the NPI port breaks user ports still assigned to the old
534eca70102SVladimir Oltean 	 * one, so only allow it while they're down, and don't allow them to
535eca70102SVladimir Oltean 	 * come back up until they're all changed to the new one.
536eca70102SVladimir Oltean 	 */
537eca70102SVladimir Oltean 	dsa_switch_for_each_user_port(other_dp, ds) {
5386ca80638SFlorian Fainelli 		struct net_device *user = other_dp->user;
539eca70102SVladimir Oltean 
5406ca80638SFlorian Fainelli 		if (other_dp != dp && (user->flags & IFF_UP) &&
5416ca80638SFlorian Fainelli 		    dsa_port_to_conduit(other_dp) != conduit) {
542eca70102SVladimir Oltean 			NL_SET_ERR_MSG_MOD(extack,
5436ca80638SFlorian Fainelli 					   "Cannot change while old conduit still has users");
544eca70102SVladimir Oltean 			return -EOPNOTSUPP;
545eca70102SVladimir Oltean 		}
546eca70102SVladimir Oltean 	}
547eca70102SVladimir Oltean 
548eca70102SVladimir Oltean 	felix_npi_port_deinit(ocelot, ocelot->npi);
5496ca80638SFlorian Fainelli 	felix_npi_port_init(ocelot, felix_cpu_port_for_conduit(ds, conduit));
550eca70102SVladimir Oltean 
551eca70102SVladimir Oltean 	return 0;
552eca70102SVladimir Oltean }
553eca70102SVladimir Oltean 
5548c166acbSVladimir Oltean /* Alternatively to using the NPI functionality, that same hardware MAC
5556ca80638SFlorian Fainelli  * connected internally to the enetc or fman DSA conduit can be configured to
5568c166acbSVladimir Oltean  * use the software-defined tag_8021q frame format. As far as the hardware is
5578c166acbSVladimir Oltean  * concerned, it thinks it is a "dumb switch" - the queues of the CPU port
5588c166acbSVladimir Oltean  * module are now disconnected from it, but can still be accessed through
5598c166acbSVladimir Oltean  * register-based MMIO.
5608c166acbSVladimir Oltean  */
5617a29d220SVladimir Oltean static const struct felix_tag_proto_ops felix_tag_npi_proto_ops = {
5627a29d220SVladimir Oltean 	.setup			= felix_tag_npi_setup,
5637a29d220SVladimir Oltean 	.teardown		= felix_tag_npi_teardown,
5647a29d220SVladimir Oltean 	.get_host_fwd_mask	= felix_tag_npi_get_host_fwd_mask,
5656ca80638SFlorian Fainelli 	.change_conduit		= felix_tag_npi_change_conduit,
5667a29d220SVladimir Oltean };
5677a29d220SVladimir Oltean 
felix_tag_8021q_setup(struct dsa_switch * ds)5687a29d220SVladimir Oltean static int felix_tag_8021q_setup(struct dsa_switch *ds)
5697a29d220SVladimir Oltean {
5707a29d220SVladimir Oltean 	struct ocelot *ocelot = ds->priv;
571c295f983SVladimir Oltean 	struct dsa_port *dp;
572adb3dccfSVladimir Oltean 	int err;
573adb3dccfSVladimir Oltean 
5747a29d220SVladimir Oltean 	err = dsa_tag_8021q_register(ds, htons(ETH_P_8021AD));
5757a29d220SVladimir Oltean 	if (err)
576adb3dccfSVladimir Oltean 		return err;
5777a29d220SVladimir Oltean 
57836a0bf44SVladimir Oltean 	dsa_switch_for_each_cpu_port(dp, ds)
57936a0bf44SVladimir Oltean 		ocelot_port_setup_dsa_8021q_cpu(ocelot, dp->index);
58036a0bf44SVladimir Oltean 
581c295f983SVladimir Oltean 	dsa_switch_for_each_user_port(dp, ds)
582c295f983SVladimir Oltean 		ocelot_port_assign_dsa_8021q_cpu(ocelot, dp->index,
583c295f983SVladimir Oltean 						 dp->cpu_dp->index);
5847a29d220SVladimir Oltean 
585c295f983SVladimir Oltean 	dsa_switch_for_each_available_port(dp, ds)
5867a29d220SVladimir Oltean 		/* This overwrites ocelot_init():
5877a29d220SVladimir Oltean 		 * Do not forward BPDU frames to the CPU port module,
5887a29d220SVladimir Oltean 		 * for 2 reasons:
5897a29d220SVladimir Oltean 		 * - When these packets are injected from the tag_8021q
5907a29d220SVladimir Oltean 		 *   CPU port, we want them to go out, not loop back
5917a29d220SVladimir Oltean 		 *   into the system.
5927a29d220SVladimir Oltean 		 * - STP traffic ingressing on a user port should go to
5937a29d220SVladimir Oltean 		 *   the tag_8021q CPU port, not to the hardware CPU
5947a29d220SVladimir Oltean 		 *   port module.
5957a29d220SVladimir Oltean 		 */
5967a29d220SVladimir Oltean 		ocelot_write_gix(ocelot,
5977a29d220SVladimir Oltean 				 ANA_PORT_CPU_FWD_BPDU_CFG_BPDU_REDIR_ENA(0),
5987a29d220SVladimir Oltean 				 ANA_PORT_CPU_FWD_BPDU_CFG, dp->index);
5997a29d220SVladimir Oltean 
6007a29d220SVladimir Oltean 	/* The ownership of the CPU port module's queues might have just been
6017a29d220SVladimir Oltean 	 * transferred to the tag_8021q tagger from the NPI-based tagger.
6027a29d220SVladimir Oltean 	 * So there might still be all sorts of crap in the queues. On the
6037a29d220SVladimir Oltean 	 * other hand, the MMIO-based matching of PTP frames is very brittle,
6047a29d220SVladimir Oltean 	 * so we need to be careful that there are no extra frames to be
6057a29d220SVladimir Oltean 	 * dequeued over MMIO, since we would never know to discard them.
6067a29d220SVladimir Oltean 	 */
607c5e12ac3SVladimir Oltean 	ocelot_lock_xtr_grp_bh(ocelot, 0);
6087a29d220SVladimir Oltean 	ocelot_drain_cpu_queue(ocelot, 0);
609c5e12ac3SVladimir Oltean 	ocelot_unlock_xtr_grp_bh(ocelot, 0);
6107a29d220SVladimir Oltean 
611f1288fd7SVladimir Oltean 	/* Problem: when using push_inner_tag=1 for ES0 tag B, we lose info
612f1288fd7SVladimir Oltean 	 * about whether the received packets were VLAN-tagged on the wire,
613f1288fd7SVladimir Oltean 	 * since they are always tagged on egress towards the CPU port.
614f1288fd7SVladimir Oltean 	 *
615f1288fd7SVladimir Oltean 	 * Since using push_inner_tag=1 is unavoidable for VLAN-aware bridges,
616f1288fd7SVladimir Oltean 	 * we must work around the fallout by untagging in software to make
617f1288fd7SVladimir Oltean 	 * untagged reception work more or less as expected.
618f1288fd7SVladimir Oltean 	 */
619f1288fd7SVladimir Oltean 	ds->untag_vlan_aware_bridge_pvid = true;
6207a29d220SVladimir Oltean 
6217a29d220SVladimir Oltean 	return 0;
6227a29d220SVladimir Oltean }
6237a29d220SVladimir Oltean 
felix_tag_8021q_teardown(struct dsa_switch * ds)6247a29d220SVladimir Oltean static void felix_tag_8021q_teardown(struct dsa_switch *ds)
625adb3dccfSVladimir Oltean {
6267a29d220SVladimir Oltean 	struct ocelot *ocelot = ds->priv;
627c295f983SVladimir Oltean 	struct dsa_port *dp;
6287a29d220SVladimir Oltean 
629c295f983SVladimir Oltean 	dsa_switch_for_each_available_port(dp, ds)
6307a29d220SVladimir Oltean 		/* Restore the logic from ocelot_init:
6317a29d220SVladimir Oltean 		 * do not forward BPDU frames to the front ports.
6327a29d220SVladimir Oltean 		 */
6337a29d220SVladimir Oltean 		ocelot_write_gix(ocelot,
6347a29d220SVladimir Oltean 				 ANA_PORT_CPU_FWD_BPDU_CFG_BPDU_REDIR_ENA(0xffff),
6357a29d220SVladimir Oltean 				 ANA_PORT_CPU_FWD_BPDU_CFG,
6367a29d220SVladimir Oltean 				 dp->index);
6377a29d220SVladimir Oltean 
638c295f983SVladimir Oltean 	dsa_switch_for_each_user_port(dp, ds)
639c295f983SVladimir Oltean 		ocelot_port_unassign_dsa_8021q_cpu(ocelot, dp->index);
6407a29d220SVladimir Oltean 
64136a0bf44SVladimir Oltean 	dsa_switch_for_each_cpu_port(dp, ds)
64236a0bf44SVladimir Oltean 		ocelot_port_teardown_dsa_8021q_cpu(ocelot, dp->index);
64336a0bf44SVladimir Oltean 
6447a29d220SVladimir Oltean 	dsa_tag_8021q_unregister(ds);
645f1288fd7SVladimir Oltean 
646f1288fd7SVladimir Oltean 	ds->untag_vlan_aware_bridge_pvid = false;
6477a29d220SVladimir Oltean }
6487a29d220SVladimir Oltean 
felix_tag_8021q_get_host_fwd_mask(struct dsa_switch * ds)6497a29d220SVladimir Oltean static unsigned long felix_tag_8021q_get_host_fwd_mask(struct dsa_switch *ds)
6507a29d220SVladimir Oltean {
6517a29d220SVladimir Oltean 	return dsa_cpu_ports(ds);
6527a29d220SVladimir Oltean }
6537a29d220SVladimir Oltean 
felix_tag_8021q_change_conduit(struct dsa_switch * ds,int port,struct net_device * conduit,struct netlink_ext_ack * extack)6546ca80638SFlorian Fainelli static int felix_tag_8021q_change_conduit(struct dsa_switch *ds, int port,
6556ca80638SFlorian Fainelli 					  struct net_device *conduit,
656eca70102SVladimir Oltean 					  struct netlink_ext_ack *extack)
657eca70102SVladimir Oltean {
6586ca80638SFlorian Fainelli 	int cpu = felix_cpu_port_for_conduit(ds, conduit);
659eca70102SVladimir Oltean 	struct ocelot *ocelot = ds->priv;
660eca70102SVladimir Oltean 
661eca70102SVladimir Oltean 	ocelot_port_unassign_dsa_8021q_cpu(ocelot, port);
662eca70102SVladimir Oltean 	ocelot_port_assign_dsa_8021q_cpu(ocelot, port, cpu);
663eca70102SVladimir Oltean 
664eca70102SVladimir Oltean 	return felix_update_trapping_destinations(ds, true);
665eca70102SVladimir Oltean }
666eca70102SVladimir Oltean 
6677a29d220SVladimir Oltean static const struct felix_tag_proto_ops felix_tag_8021q_proto_ops = {
6687a29d220SVladimir Oltean 	.setup			= felix_tag_8021q_setup,
6697a29d220SVladimir Oltean 	.teardown		= felix_tag_8021q_teardown,
6707a29d220SVladimir Oltean 	.get_host_fwd_mask	= felix_tag_8021q_get_host_fwd_mask,
6716ca80638SFlorian Fainelli 	.change_conduit		= felix_tag_8021q_change_conduit,
6727a29d220SVladimir Oltean };
6737a29d220SVladimir Oltean 
felix_set_host_flood(struct dsa_switch * ds,unsigned long mask,bool uc,bool mc,bool bc)6747a29d220SVladimir Oltean static void felix_set_host_flood(struct dsa_switch *ds, unsigned long mask,
6757a29d220SVladimir Oltean 				 bool uc, bool mc, bool bc)
6767a29d220SVladimir Oltean {
6777a29d220SVladimir Oltean 	struct ocelot *ocelot = ds->priv;
6787a29d220SVladimir Oltean 	unsigned long val;
6797a29d220SVladimir Oltean 
6807a29d220SVladimir Oltean 	val = uc ? mask : 0;
6817a29d220SVladimir Oltean 	ocelot_rmw_rix(ocelot, val, mask, ANA_PGID_PGID, PGID_UC);
6827a29d220SVladimir Oltean 
6837a29d220SVladimir Oltean 	val = mc ? mask : 0;
6847a29d220SVladimir Oltean 	ocelot_rmw_rix(ocelot, val, mask, ANA_PGID_PGID, PGID_MC);
6857a29d220SVladimir Oltean 	ocelot_rmw_rix(ocelot, val, mask, ANA_PGID_PGID, PGID_MCIPV4);
6867a29d220SVladimir Oltean 	ocelot_rmw_rix(ocelot, val, mask, ANA_PGID_PGID, PGID_MCIPV6);
687129b7532SVladimir Oltean 
688129b7532SVladimir Oltean 	val = bc ? mask : 0;
689129b7532SVladimir Oltean 	ocelot_rmw_rix(ocelot, val, mask, ANA_PGID_PGID, PGID_BC);
6907a29d220SVladimir Oltean }
6917a29d220SVladimir Oltean 
6927a29d220SVladimir Oltean static void
felix_migrate_host_flood(struct dsa_switch * ds,const struct felix_tag_proto_ops * proto_ops,const struct felix_tag_proto_ops * old_proto_ops)6937a29d220SVladimir Oltean felix_migrate_host_flood(struct dsa_switch *ds,
6947a29d220SVladimir Oltean 			 const struct felix_tag_proto_ops *proto_ops,
6957a29d220SVladimir Oltean 			 const struct felix_tag_proto_ops *old_proto_ops)
6967a29d220SVladimir Oltean {
6977a29d220SVladimir Oltean 	struct ocelot *ocelot = ds->priv;
6987a29d220SVladimir Oltean 	struct felix *felix = ocelot_to_felix(ocelot);
6997a29d220SVladimir Oltean 	unsigned long mask;
7007a29d220SVladimir Oltean 
7017a29d220SVladimir Oltean 	if (old_proto_ops) {
7027a29d220SVladimir Oltean 		mask = old_proto_ops->get_host_fwd_mask(ds);
7037a29d220SVladimir Oltean 		felix_set_host_flood(ds, mask, false, false, false);
7047a29d220SVladimir Oltean 	}
7057a29d220SVladimir Oltean 
7067a29d220SVladimir Oltean 	mask = proto_ops->get_host_fwd_mask(ds);
7077a29d220SVladimir Oltean 	felix_set_host_flood(ds, mask, !!felix->host_flood_uc_mask,
7087a29d220SVladimir Oltean 			     !!felix->host_flood_mc_mask, true);
7097a29d220SVladimir Oltean }
7107a29d220SVladimir Oltean 
felix_migrate_mdbs(struct dsa_switch * ds,const struct felix_tag_proto_ops * proto_ops,const struct felix_tag_proto_ops * old_proto_ops)7117a29d220SVladimir Oltean static int felix_migrate_mdbs(struct dsa_switch *ds,
7127a29d220SVladimir Oltean 			      const struct felix_tag_proto_ops *proto_ops,
7137a29d220SVladimir Oltean 			      const struct felix_tag_proto_ops *old_proto_ops)
7147a29d220SVladimir Oltean {
7157a29d220SVladimir Oltean 	struct ocelot *ocelot = ds->priv;
7167a29d220SVladimir Oltean 	unsigned long from, to;
7177a29d220SVladimir Oltean 
7187a29d220SVladimir Oltean 	if (!old_proto_ops)
7197a29d220SVladimir Oltean 		return 0;
7207a29d220SVladimir Oltean 
7217a29d220SVladimir Oltean 	from = old_proto_ops->get_host_fwd_mask(ds);
7227a29d220SVladimir Oltean 	to = proto_ops->get_host_fwd_mask(ds);
7237a29d220SVladimir Oltean 
7247a29d220SVladimir Oltean 	return ocelot_migrate_mdbs(ocelot, from, to);
7257a29d220SVladimir Oltean }
7267a29d220SVladimir Oltean 
7277a29d220SVladimir Oltean /* Configure the shared hardware resources for a transition between
7287a29d220SVladimir Oltean  * @old_proto_ops and @proto_ops.
7297a29d220SVladimir Oltean  * Manual migration is needed because as far as DSA is concerned, no change of
7307a29d220SVladimir Oltean  * the CPU port is taking place here, just of the tagging protocol.
7317a29d220SVladimir Oltean  */
7327a29d220SVladimir Oltean static int
felix_tag_proto_setup_shared(struct dsa_switch * ds,const struct felix_tag_proto_ops * proto_ops,const struct felix_tag_proto_ops * old_proto_ops)7337a29d220SVladimir Oltean felix_tag_proto_setup_shared(struct dsa_switch *ds,
7347a29d220SVladimir Oltean 			     const struct felix_tag_proto_ops *proto_ops,
7357a29d220SVladimir Oltean 			     const struct felix_tag_proto_ops *old_proto_ops)
7367a29d220SVladimir Oltean {
7377a29d220SVladimir Oltean 	bool using_tag_8021q = (proto_ops == &felix_tag_8021q_proto_ops);
7387a29d220SVladimir Oltean 	int err;
7397a29d220SVladimir Oltean 
7407a29d220SVladimir Oltean 	err = felix_migrate_mdbs(ds, proto_ops, old_proto_ops);
7417a29d220SVladimir Oltean 	if (err)
7427a29d220SVladimir Oltean 		return err;
7437a29d220SVladimir Oltean 
7447a29d220SVladimir Oltean 	felix_update_trapping_destinations(ds, using_tag_8021q);
7457a29d220SVladimir Oltean 
7467a29d220SVladimir Oltean 	felix_migrate_host_flood(ds, proto_ops, old_proto_ops);
7477a29d220SVladimir Oltean 
7487a29d220SVladimir Oltean 	return 0;
749adb3dccfSVladimir Oltean }
750adb3dccfSVladimir Oltean 
751e21268efSVladimir Oltean /* This always leaves the switch in a consistent state, because although the
752e21268efSVladimir Oltean  * tag_8021q setup can fail, the NPI setup can't. So either the change is made,
753e21268efSVladimir Oltean  * or the restoration is guaranteed to work.
754e21268efSVladimir Oltean  */
felix_change_tag_protocol(struct dsa_switch * ds,enum dsa_tag_protocol proto)755bacf93b0SVladimir Oltean static int felix_change_tag_protocol(struct dsa_switch *ds,
756adb3dccfSVladimir Oltean 				     enum dsa_tag_protocol proto)
757adb3dccfSVladimir Oltean {
7587a29d220SVladimir Oltean 	const struct felix_tag_proto_ops *old_proto_ops, *proto_ops;
759adb3dccfSVladimir Oltean 	struct ocelot *ocelot = ds->priv;
760adb3dccfSVladimir Oltean 	struct felix *felix = ocelot_to_felix(ocelot);
761adb3dccfSVladimir Oltean 	int err;
762adb3dccfSVladimir Oltean 
7637a29d220SVladimir Oltean 	switch (proto) {
7647a29d220SVladimir Oltean 	case DSA_TAG_PROTO_SEVILLE:
7657a29d220SVladimir Oltean 	case DSA_TAG_PROTO_OCELOT:
7667a29d220SVladimir Oltean 		proto_ops = &felix_tag_npi_proto_ops;
767bacf93b0SVladimir Oltean 		break;
7687a29d220SVladimir Oltean 	case DSA_TAG_PROTO_OCELOT_8021Q:
7697a29d220SVladimir Oltean 		proto_ops = &felix_tag_8021q_proto_ops;
7707a29d220SVladimir Oltean 		break;
7717a29d220SVladimir Oltean 	default:
7727a29d220SVladimir Oltean 		return -EPROTONOSUPPORT;
773bacf93b0SVladimir Oltean 	}
774bacf93b0SVladimir Oltean 
7757a29d220SVladimir Oltean 	old_proto_ops = felix->tag_proto_ops;
7767a29d220SVladimir Oltean 
7774c46bb49SVladimir Oltean 	if (proto_ops == old_proto_ops)
7784c46bb49SVladimir Oltean 		return 0;
7794c46bb49SVladimir Oltean 
7807a29d220SVladimir Oltean 	err = proto_ops->setup(ds);
7817a29d220SVladimir Oltean 	if (err)
7827a29d220SVladimir Oltean 		goto setup_failed;
7837a29d220SVladimir Oltean 
7847a29d220SVladimir Oltean 	err = felix_tag_proto_setup_shared(ds, proto_ops, old_proto_ops);
7857a29d220SVladimir Oltean 	if (err)
7867a29d220SVladimir Oltean 		goto setup_shared_failed;
7877a29d220SVladimir Oltean 
7887a29d220SVladimir Oltean 	if (old_proto_ops)
7897a29d220SVladimir Oltean 		old_proto_ops->teardown(ds);
7907a29d220SVladimir Oltean 
7917a29d220SVladimir Oltean 	felix->tag_proto_ops = proto_ops;
792adb3dccfSVladimir Oltean 	felix->tag_proto = proto;
793adb3dccfSVladimir Oltean 
794adb3dccfSVladimir Oltean 	return 0;
7957a29d220SVladimir Oltean 
7967a29d220SVladimir Oltean setup_shared_failed:
7977a29d220SVladimir Oltean 	proto_ops->teardown(ds);
7987a29d220SVladimir Oltean setup_failed:
7997a29d220SVladimir Oltean 	return err;
800adb3dccfSVladimir Oltean }
801adb3dccfSVladimir Oltean 
felix_get_tag_protocol(struct dsa_switch * ds,int port,enum dsa_tag_protocol mp)80256051948SVladimir Oltean static enum dsa_tag_protocol felix_get_tag_protocol(struct dsa_switch *ds,
8034d776482SFlorian Fainelli 						    int port,
8044d776482SFlorian Fainelli 						    enum dsa_tag_protocol mp)
80556051948SVladimir Oltean {
806adb3dccfSVladimir Oltean 	struct ocelot *ocelot = ds->priv;
807adb3dccfSVladimir Oltean 	struct felix *felix = ocelot_to_felix(ocelot);
808adb3dccfSVladimir Oltean 
809adb3dccfSVladimir Oltean 	return felix->tag_proto;
81056051948SVladimir Oltean }
81156051948SVladimir Oltean 
felix_port_set_host_flood(struct dsa_switch * ds,int port,bool uc,bool mc)81272c3b0c7SVladimir Oltean static void felix_port_set_host_flood(struct dsa_switch *ds, int port,
81372c3b0c7SVladimir Oltean 				      bool uc, bool mc)
81472c3b0c7SVladimir Oltean {
81572c3b0c7SVladimir Oltean 	struct ocelot *ocelot = ds->priv;
81672c3b0c7SVladimir Oltean 	struct felix *felix = ocelot_to_felix(ocelot);
8177a29d220SVladimir Oltean 	unsigned long mask;
81872c3b0c7SVladimir Oltean 
81972c3b0c7SVladimir Oltean 	if (uc)
82072c3b0c7SVladimir Oltean 		felix->host_flood_uc_mask |= BIT(port);
82172c3b0c7SVladimir Oltean 	else
82272c3b0c7SVladimir Oltean 		felix->host_flood_uc_mask &= ~BIT(port);
82372c3b0c7SVladimir Oltean 
82472c3b0c7SVladimir Oltean 	if (mc)
82572c3b0c7SVladimir Oltean 		felix->host_flood_mc_mask |= BIT(port);
82672c3b0c7SVladimir Oltean 	else
82772c3b0c7SVladimir Oltean 		felix->host_flood_mc_mask &= ~BIT(port);
82872c3b0c7SVladimir Oltean 
8297a29d220SVladimir Oltean 	mask = felix->tag_proto_ops->get_host_fwd_mask(ds);
8307a29d220SVladimir Oltean 	felix_set_host_flood(ds, mask, !!felix->host_flood_uc_mask,
8317a29d220SVladimir Oltean 			     !!felix->host_flood_mc_mask, true);
83272c3b0c7SVladimir Oltean }
83372c3b0c7SVladimir Oltean 
felix_port_change_conduit(struct dsa_switch * ds,int port,struct net_device * conduit,struct netlink_ext_ack * extack)8346ca80638SFlorian Fainelli static int felix_port_change_conduit(struct dsa_switch *ds, int port,
8356ca80638SFlorian Fainelli 				     struct net_device *conduit,
836eca70102SVladimir Oltean 				     struct netlink_ext_ack *extack)
837eca70102SVladimir Oltean {
838eca70102SVladimir Oltean 	struct ocelot *ocelot = ds->priv;
839eca70102SVladimir Oltean 	struct felix *felix = ocelot_to_felix(ocelot);
840eca70102SVladimir Oltean 
8416ca80638SFlorian Fainelli 	return felix->tag_proto_ops->change_conduit(ds, port, conduit, extack);
842eca70102SVladimir Oltean }
843eca70102SVladimir Oltean 
felix_set_ageing_time(struct dsa_switch * ds,unsigned int ageing_time)84456051948SVladimir Oltean static int felix_set_ageing_time(struct dsa_switch *ds,
84556051948SVladimir Oltean 				 unsigned int ageing_time)
84656051948SVladimir Oltean {
84756051948SVladimir Oltean 	struct ocelot *ocelot = ds->priv;
84856051948SVladimir Oltean 
84956051948SVladimir Oltean 	ocelot_set_ageing_time(ocelot, ageing_time);
85056051948SVladimir Oltean 
85156051948SVladimir Oltean 	return 0;
85256051948SVladimir Oltean }
85356051948SVladimir Oltean 
felix_port_fast_age(struct dsa_switch * ds,int port)8545cad43a5SVladimir Oltean static void felix_port_fast_age(struct dsa_switch *ds, int port)
8555cad43a5SVladimir Oltean {
8565cad43a5SVladimir Oltean 	struct ocelot *ocelot = ds->priv;
8575cad43a5SVladimir Oltean 	int err;
8585cad43a5SVladimir Oltean 
8595cad43a5SVladimir Oltean 	err = ocelot_mact_flush(ocelot, port);
8605cad43a5SVladimir Oltean 	if (err)
8615cad43a5SVladimir Oltean 		dev_err(ds->dev, "Flushing MAC table on port %d returned %pe\n",
8625cad43a5SVladimir Oltean 			port, ERR_PTR(err));
8635cad43a5SVladimir Oltean }
8645cad43a5SVladimir Oltean 
felix_fdb_dump(struct dsa_switch * ds,int port,dsa_fdb_dump_cb_t * cb,void * data)86556051948SVladimir Oltean static int felix_fdb_dump(struct dsa_switch *ds, int port,
86656051948SVladimir Oltean 			  dsa_fdb_dump_cb_t *cb, void *data)
86756051948SVladimir Oltean {
86856051948SVladimir Oltean 	struct ocelot *ocelot = ds->priv;
86956051948SVladimir Oltean 
87056051948SVladimir Oltean 	return ocelot_fdb_dump(ocelot, port, cb, data);
87156051948SVladimir Oltean }
87256051948SVladimir Oltean 
felix_fdb_add(struct dsa_switch * ds,int port,const unsigned char * addr,u16 vid,struct dsa_db db)87356051948SVladimir Oltean static int felix_fdb_add(struct dsa_switch *ds, int port,
874c2693363SVladimir Oltean 			 const unsigned char *addr, u16 vid,
875c2693363SVladimir Oltean 			 struct dsa_db db)
87656051948SVladimir Oltean {
87754c31984SVladimir Oltean 	struct net_device *bridge_dev = felix_classify_db(db);
878e9b3ba43SVladimir Oltean 	struct dsa_port *dp = dsa_to_port(ds, port);
87956051948SVladimir Oltean 	struct ocelot *ocelot = ds->priv;
88056051948SVladimir Oltean 
88154c31984SVladimir Oltean 	if (IS_ERR(bridge_dev))
88254c31984SVladimir Oltean 		return PTR_ERR(bridge_dev);
88354c31984SVladimir Oltean 
884e9b3ba43SVladimir Oltean 	if (dsa_port_is_cpu(dp) && !bridge_dev &&
8857e580490SVladimir Oltean 	    dsa_fdb_present_in_other_db(ds, port, addr, vid, db))
8867e580490SVladimir Oltean 		return 0;
8877e580490SVladimir Oltean 
888e9b3ba43SVladimir Oltean 	if (dsa_port_is_cpu(dp))
889e9b3ba43SVladimir Oltean 		port = PGID_CPU;
890e9b3ba43SVladimir Oltean 
89154c31984SVladimir Oltean 	return ocelot_fdb_add(ocelot, port, addr, vid, bridge_dev);
89256051948SVladimir Oltean }
89356051948SVladimir Oltean 
felix_fdb_del(struct dsa_switch * ds,int port,const unsigned char * addr,u16 vid,struct dsa_db db)89456051948SVladimir Oltean static int felix_fdb_del(struct dsa_switch *ds, int port,
895c2693363SVladimir Oltean 			 const unsigned char *addr, u16 vid,
896c2693363SVladimir Oltean 			 struct dsa_db db)
89756051948SVladimir Oltean {
89854c31984SVladimir Oltean 	struct net_device *bridge_dev = felix_classify_db(db);
899e9b3ba43SVladimir Oltean 	struct dsa_port *dp = dsa_to_port(ds, port);
90056051948SVladimir Oltean 	struct ocelot *ocelot = ds->priv;
90156051948SVladimir Oltean 
90254c31984SVladimir Oltean 	if (IS_ERR(bridge_dev))
90354c31984SVladimir Oltean 		return PTR_ERR(bridge_dev);
90454c31984SVladimir Oltean 
905e9b3ba43SVladimir Oltean 	if (dsa_port_is_cpu(dp) && !bridge_dev &&
9067e580490SVladimir Oltean 	    dsa_fdb_present_in_other_db(ds, port, addr, vid, db))
9077e580490SVladimir Oltean 		return 0;
9087e580490SVladimir Oltean 
909e9b3ba43SVladimir Oltean 	if (dsa_port_is_cpu(dp))
910e9b3ba43SVladimir Oltean 		port = PGID_CPU;
911e9b3ba43SVladimir Oltean 
91254c31984SVladimir Oltean 	return ocelot_fdb_del(ocelot, port, addr, vid, bridge_dev);
91356051948SVladimir Oltean }
91456051948SVladimir Oltean 
felix_lag_fdb_add(struct dsa_switch * ds,struct dsa_lag lag,const unsigned char * addr,u16 vid,struct dsa_db db)915961d8b69SVladimir Oltean static int felix_lag_fdb_add(struct dsa_switch *ds, struct dsa_lag lag,
916c2693363SVladimir Oltean 			     const unsigned char *addr, u16 vid,
917c2693363SVladimir Oltean 			     struct dsa_db db)
918961d8b69SVladimir Oltean {
91954c31984SVladimir Oltean 	struct net_device *bridge_dev = felix_classify_db(db);
920961d8b69SVladimir Oltean 	struct ocelot *ocelot = ds->priv;
921961d8b69SVladimir Oltean 
92254c31984SVladimir Oltean 	if (IS_ERR(bridge_dev))
92354c31984SVladimir Oltean 		return PTR_ERR(bridge_dev);
92454c31984SVladimir Oltean 
92554c31984SVladimir Oltean 	return ocelot_lag_fdb_add(ocelot, lag.dev, addr, vid, bridge_dev);
926961d8b69SVladimir Oltean }
927961d8b69SVladimir Oltean 
felix_lag_fdb_del(struct dsa_switch * ds,struct dsa_lag lag,const unsigned char * addr,u16 vid,struct dsa_db db)928961d8b69SVladimir Oltean static int felix_lag_fdb_del(struct dsa_switch *ds, struct dsa_lag lag,
929c2693363SVladimir Oltean 			     const unsigned char *addr, u16 vid,
930c2693363SVladimir Oltean 			     struct dsa_db db)
931961d8b69SVladimir Oltean {
93254c31984SVladimir Oltean 	struct net_device *bridge_dev = felix_classify_db(db);
933961d8b69SVladimir Oltean 	struct ocelot *ocelot = ds->priv;
934961d8b69SVladimir Oltean 
93554c31984SVladimir Oltean 	if (IS_ERR(bridge_dev))
93654c31984SVladimir Oltean 		return PTR_ERR(bridge_dev);
93754c31984SVladimir Oltean 
93854c31984SVladimir Oltean 	return ocelot_lag_fdb_del(ocelot, lag.dev, addr, vid, bridge_dev);
939961d8b69SVladimir Oltean }
940961d8b69SVladimir Oltean 
felix_mdb_add(struct dsa_switch * ds,int port,const struct switchdev_obj_port_mdb * mdb,struct dsa_db db)941a52b2da7SVladimir Oltean static int felix_mdb_add(struct dsa_switch *ds, int port,
942c2693363SVladimir Oltean 			 const struct switchdev_obj_port_mdb *mdb,
943c2693363SVladimir Oltean 			 struct dsa_db db)
944209edf95SVladimir Oltean {
94554c31984SVladimir Oltean 	struct net_device *bridge_dev = felix_classify_db(db);
946209edf95SVladimir Oltean 	struct ocelot *ocelot = ds->priv;
947209edf95SVladimir Oltean 
94854c31984SVladimir Oltean 	if (IS_ERR(bridge_dev))
94954c31984SVladimir Oltean 		return PTR_ERR(bridge_dev);
95054c31984SVladimir Oltean 
9517e580490SVladimir Oltean 	if (dsa_is_cpu_port(ds, port) && !bridge_dev &&
9527e580490SVladimir Oltean 	    dsa_mdb_present_in_other_db(ds, port, mdb, db))
9537e580490SVladimir Oltean 		return 0;
9547e580490SVladimir Oltean 
9550ddf83cdSVladimir Oltean 	if (port == ocelot->npi)
9560ddf83cdSVladimir Oltean 		port = ocelot->num_phys_ports;
9570ddf83cdSVladimir Oltean 
95854c31984SVladimir Oltean 	return ocelot_port_mdb_add(ocelot, port, mdb, bridge_dev);
959209edf95SVladimir Oltean }
960209edf95SVladimir Oltean 
felix_mdb_del(struct dsa_switch * ds,int port,const struct switchdev_obj_port_mdb * mdb,struct dsa_db db)961209edf95SVladimir Oltean static int felix_mdb_del(struct dsa_switch *ds, int port,
962c2693363SVladimir Oltean 			 const struct switchdev_obj_port_mdb *mdb,
963c2693363SVladimir Oltean 			 struct dsa_db db)
964209edf95SVladimir Oltean {
96554c31984SVladimir Oltean 	struct net_device *bridge_dev = felix_classify_db(db);
966209edf95SVladimir Oltean 	struct ocelot *ocelot = ds->priv;
967209edf95SVladimir Oltean 
96854c31984SVladimir Oltean 	if (IS_ERR(bridge_dev))
96954c31984SVladimir Oltean 		return PTR_ERR(bridge_dev);
97054c31984SVladimir Oltean 
9717e580490SVladimir Oltean 	if (dsa_is_cpu_port(ds, port) && !bridge_dev &&
9727e580490SVladimir Oltean 	    dsa_mdb_present_in_other_db(ds, port, mdb, db))
9737e580490SVladimir Oltean 		return 0;
9747e580490SVladimir Oltean 
9750ddf83cdSVladimir Oltean 	if (port == ocelot->npi)
9760ddf83cdSVladimir Oltean 		port = ocelot->num_phys_ports;
9770ddf83cdSVladimir Oltean 
97854c31984SVladimir Oltean 	return ocelot_port_mdb_del(ocelot, port, mdb, bridge_dev);
979209edf95SVladimir Oltean }
980209edf95SVladimir Oltean 
felix_bridge_stp_state_set(struct dsa_switch * ds,int port,u8 state)98156051948SVladimir Oltean static void felix_bridge_stp_state_set(struct dsa_switch *ds, int port,
98256051948SVladimir Oltean 				       u8 state)
98356051948SVladimir Oltean {
98456051948SVladimir Oltean 	struct ocelot *ocelot = ds->priv;
98556051948SVladimir Oltean 
98656051948SVladimir Oltean 	return ocelot_bridge_stp_state_set(ocelot, port, state);
98756051948SVladimir Oltean }
98856051948SVladimir Oltean 
felix_pre_bridge_flags(struct dsa_switch * ds,int port,struct switchdev_brport_flags val,struct netlink_ext_ack * extack)989421741eaSVladimir Oltean static int felix_pre_bridge_flags(struct dsa_switch *ds, int port,
990421741eaSVladimir Oltean 				  struct switchdev_brport_flags val,
991421741eaSVladimir Oltean 				  struct netlink_ext_ack *extack)
992421741eaSVladimir Oltean {
993421741eaSVladimir Oltean 	struct ocelot *ocelot = ds->priv;
994421741eaSVladimir Oltean 
995421741eaSVladimir Oltean 	return ocelot_port_pre_bridge_flags(ocelot, port, val);
996421741eaSVladimir Oltean }
997421741eaSVladimir Oltean 
felix_bridge_flags(struct dsa_switch * ds,int port,struct switchdev_brport_flags val,struct netlink_ext_ack * extack)998421741eaSVladimir Oltean static int felix_bridge_flags(struct dsa_switch *ds, int port,
999421741eaSVladimir Oltean 			      struct switchdev_brport_flags val,
1000421741eaSVladimir Oltean 			      struct netlink_ext_ack *extack)
1001421741eaSVladimir Oltean {
1002421741eaSVladimir Oltean 	struct ocelot *ocelot = ds->priv;
1003421741eaSVladimir Oltean 
1004910ee6ccSVladimir Oltean 	if (port == ocelot->npi)
1005910ee6ccSVladimir Oltean 		port = ocelot->num_phys_ports;
1006910ee6ccSVladimir Oltean 
1007421741eaSVladimir Oltean 	ocelot_port_bridge_flags(ocelot, port, val);
1008421741eaSVladimir Oltean 
1009421741eaSVladimir Oltean 	return 0;
1010421741eaSVladimir Oltean }
1011421741eaSVladimir Oltean 
felix_bridge_join(struct dsa_switch * ds,int port,struct dsa_bridge bridge,bool * tx_fwd_offload,struct netlink_ext_ack * extack)101256051948SVladimir Oltean static int felix_bridge_join(struct dsa_switch *ds, int port,
101306b9cce4SVladimir Oltean 			     struct dsa_bridge bridge, bool *tx_fwd_offload,
101406b9cce4SVladimir Oltean 			     struct netlink_ext_ack *extack)
101556051948SVladimir Oltean {
101656051948SVladimir Oltean 	struct ocelot *ocelot = ds->priv;
101756051948SVladimir Oltean 
101854c31984SVladimir Oltean 	return ocelot_port_bridge_join(ocelot, port, bridge.dev, bridge.num,
101954c31984SVladimir Oltean 				       extack);
102056051948SVladimir Oltean }
102156051948SVladimir Oltean 
felix_bridge_leave(struct dsa_switch * ds,int port,struct dsa_bridge bridge)102256051948SVladimir Oltean static void felix_bridge_leave(struct dsa_switch *ds, int port,
1023d3eed0e5SVladimir Oltean 			       struct dsa_bridge bridge)
102456051948SVladimir Oltean {
102556051948SVladimir Oltean 	struct ocelot *ocelot = ds->priv;
102656051948SVladimir Oltean 
1027d3eed0e5SVladimir Oltean 	ocelot_port_bridge_leave(ocelot, port, bridge.dev);
102856051948SVladimir Oltean }
102956051948SVladimir Oltean 
felix_lag_join(struct dsa_switch * ds,int port,struct dsa_lag lag,struct netdev_lag_upper_info * info,struct netlink_ext_ack * extack)10308fe6832eSVladimir Oltean static int felix_lag_join(struct dsa_switch *ds, int port,
1031dedd6a00SVladimir Oltean 			  struct dsa_lag lag,
10322e359b00SVladimir Oltean 			  struct netdev_lag_upper_info *info,
10332e359b00SVladimir Oltean 			  struct netlink_ext_ack *extack)
10348fe6832eSVladimir Oltean {
10358fe6832eSVladimir Oltean 	struct ocelot *ocelot = ds->priv;
1036eca70102SVladimir Oltean 	int err;
10378fe6832eSVladimir Oltean 
1038eca70102SVladimir Oltean 	err = ocelot_port_lag_join(ocelot, port, lag.dev, info, extack);
1039eca70102SVladimir Oltean 	if (err)
1040eca70102SVladimir Oltean 		return err;
1041eca70102SVladimir Oltean 
1042eca70102SVladimir Oltean 	/* Update the logical LAG port that serves as tag_8021q CPU port */
1043eca70102SVladimir Oltean 	if (!dsa_is_cpu_port(ds, port))
1044eca70102SVladimir Oltean 		return 0;
1045eca70102SVladimir Oltean 
10466ca80638SFlorian Fainelli 	return felix_port_change_conduit(ds, port, lag.dev, extack);
10478fe6832eSVladimir Oltean }
10488fe6832eSVladimir Oltean 
felix_lag_leave(struct dsa_switch * ds,int port,struct dsa_lag lag)10498fe6832eSVladimir Oltean static int felix_lag_leave(struct dsa_switch *ds, int port,
1050dedd6a00SVladimir Oltean 			   struct dsa_lag lag)
10518fe6832eSVladimir Oltean {
10528fe6832eSVladimir Oltean 	struct ocelot *ocelot = ds->priv;
10538fe6832eSVladimir Oltean 
1054dedd6a00SVladimir Oltean 	ocelot_port_lag_leave(ocelot, port, lag.dev);
10558fe6832eSVladimir Oltean 
1056eca70102SVladimir Oltean 	/* Update the logical LAG port that serves as tag_8021q CPU port */
1057eca70102SVladimir Oltean 	if (!dsa_is_cpu_port(ds, port))
10588fe6832eSVladimir Oltean 		return 0;
1059eca70102SVladimir Oltean 
10606ca80638SFlorian Fainelli 	return felix_port_change_conduit(ds, port, lag.dev, NULL);
10618fe6832eSVladimir Oltean }
10628fe6832eSVladimir Oltean 
felix_lag_change(struct dsa_switch * ds,int port)10638fe6832eSVladimir Oltean static int felix_lag_change(struct dsa_switch *ds, int port)
10648fe6832eSVladimir Oltean {
10658fe6832eSVladimir Oltean 	struct dsa_port *dp = dsa_to_port(ds, port);
10668fe6832eSVladimir Oltean 	struct ocelot *ocelot = ds->priv;
10678fe6832eSVladimir Oltean 
10688fe6832eSVladimir Oltean 	ocelot_port_lag_change(ocelot, port, dp->lag_tx_enabled);
10698fe6832eSVladimir Oltean 
10708fe6832eSVladimir Oltean 	return 0;
10718fe6832eSVladimir Oltean }
10728fe6832eSVladimir Oltean 
felix_vlan_prepare(struct dsa_switch * ds,int port,const struct switchdev_obj_port_vlan * vlan,struct netlink_ext_ack * extack)107356051948SVladimir Oltean static int felix_vlan_prepare(struct dsa_switch *ds, int port,
107401af940eSVladimir Oltean 			      const struct switchdev_obj_port_vlan *vlan,
107501af940eSVladimir Oltean 			      struct netlink_ext_ack *extack)
107656051948SVladimir Oltean {
10772f0402feSVladimir Oltean 	struct ocelot *ocelot = ds->priv;
1078b7a9e0daSVladimir Oltean 	u16 flags = vlan->flags;
10792f0402feSVladimir Oltean 
10809a720680SVladimir Oltean 	/* Ocelot switches copy frames as-is to the CPU, so the flags:
10819a720680SVladimir Oltean 	 * egress-untagged or not, pvid or not, make no difference. This
10829a720680SVladimir Oltean 	 * behavior is already better than what DSA just tries to approximate
10839a720680SVladimir Oltean 	 * when it installs the VLAN with the same flags on the CPU port.
10849a720680SVladimir Oltean 	 * Just accept any configuration, and don't let ocelot deny installing
10859a720680SVladimir Oltean 	 * multiple native VLANs on the NPI port, because the switch doesn't
10869a720680SVladimir Oltean 	 * look at the port tag settings towards the NPI interface anyway.
10879a720680SVladimir Oltean 	 */
10889a720680SVladimir Oltean 	if (port == ocelot->npi)
10899a720680SVladimir Oltean 		return 0;
10909a720680SVladimir Oltean 
1091b7a9e0daSVladimir Oltean 	return ocelot_vlan_prepare(ocelot, port, vlan->vid,
10922f0402feSVladimir Oltean 				   flags & BRIDGE_VLAN_INFO_PVID,
109301af940eSVladimir Oltean 				   flags & BRIDGE_VLAN_INFO_UNTAGGED,
109401af940eSVladimir Oltean 				   extack);
109556051948SVladimir Oltean }
109656051948SVladimir Oltean 
felix_vlan_filtering(struct dsa_switch * ds,int port,bool enabled,struct netlink_ext_ack * extack)109789153ed6SVladimir Oltean static int felix_vlan_filtering(struct dsa_switch *ds, int port, bool enabled,
109889153ed6SVladimir Oltean 				struct netlink_ext_ack *extack)
109956051948SVladimir Oltean {
110056051948SVladimir Oltean 	struct ocelot *ocelot = ds->priv;
1101f1288fd7SVladimir Oltean 	bool using_tag_8021q;
1102f1288fd7SVladimir Oltean 	struct felix *felix;
1103f1288fd7SVladimir Oltean 	int err;
110456051948SVladimir Oltean 
1105f1288fd7SVladimir Oltean 	err = ocelot_port_vlan_filtering(ocelot, port, enabled, extack);
1106f1288fd7SVladimir Oltean 	if (err)
1107f1288fd7SVladimir Oltean 		return err;
1108f1288fd7SVladimir Oltean 
1109f1288fd7SVladimir Oltean 	felix = ocelot_to_felix(ocelot);
1110f1288fd7SVladimir Oltean 	using_tag_8021q = felix->tag_proto == DSA_TAG_PROTO_OCELOT_8021Q;
1111f1288fd7SVladimir Oltean 	if (using_tag_8021q) {
1112f1288fd7SVladimir Oltean 		err = felix_update_tag_8021q_rx_rules(ds, port, enabled);
1113f1288fd7SVladimir Oltean 		if (err)
1114f1288fd7SVladimir Oltean 			return err;
1115f1288fd7SVladimir Oltean 	}
1116f1288fd7SVladimir Oltean 
1117f1288fd7SVladimir Oltean 	return 0;
111856051948SVladimir Oltean }
111956051948SVladimir Oltean 
felix_vlan_add(struct dsa_switch * ds,int port,const struct switchdev_obj_port_vlan * vlan,struct netlink_ext_ack * extack)11201958d581SVladimir Oltean static int felix_vlan_add(struct dsa_switch *ds, int port,
112131046a5fSVladimir Oltean 			  const struct switchdev_obj_port_vlan *vlan,
112231046a5fSVladimir Oltean 			  struct netlink_ext_ack *extack)
112356051948SVladimir Oltean {
112456051948SVladimir Oltean 	struct ocelot *ocelot = ds->priv;
1125183be6f9SVladimir Oltean 	u16 flags = vlan->flags;
11261958d581SVladimir Oltean 	int err;
112756051948SVladimir Oltean 
112801af940eSVladimir Oltean 	err = felix_vlan_prepare(ds, port, vlan, extack);
11291958d581SVladimir Oltean 	if (err)
11301958d581SVladimir Oltean 		return err;
11311958d581SVladimir Oltean 
11321958d581SVladimir Oltean 	return ocelot_vlan_add(ocelot, port, vlan->vid,
1133183be6f9SVladimir Oltean 			       flags & BRIDGE_VLAN_INFO_PVID,
1134183be6f9SVladimir Oltean 			       flags & BRIDGE_VLAN_INFO_UNTAGGED);
113556051948SVladimir Oltean }
113656051948SVladimir Oltean 
felix_vlan_del(struct dsa_switch * ds,int port,const struct switchdev_obj_port_vlan * vlan)113756051948SVladimir Oltean static int felix_vlan_del(struct dsa_switch *ds, int port,
113856051948SVladimir Oltean 			  const struct switchdev_obj_port_vlan *vlan)
113956051948SVladimir Oltean {
114056051948SVladimir Oltean 	struct ocelot *ocelot = ds->priv;
114156051948SVladimir Oltean 
1142b7a9e0daSVladimir Oltean 	return ocelot_vlan_del(ocelot, port, vlan->vid);
114356051948SVladimir Oltean }
114456051948SVladimir Oltean 
felix_phylink_get_caps(struct dsa_switch * ds,int port,struct phylink_config * config)114579fda660SRussell King (Oracle) static void felix_phylink_get_caps(struct dsa_switch *ds, int port,
114679fda660SRussell King (Oracle) 				   struct phylink_config *config)
114779fda660SRussell King (Oracle) {
114879fda660SRussell King (Oracle) 	struct ocelot *ocelot = ds->priv;
114979fda660SRussell King (Oracle) 
11503e7e7832SVladimir Oltean 	config->mac_capabilities = MAC_ASYM_PAUSE | MAC_SYM_PAUSE |
11513e7e7832SVladimir Oltean 				   MAC_10 | MAC_100 | MAC_1000FD |
11523e7e7832SVladimir Oltean 				   MAC_2500FD;
11533e7e7832SVladimir Oltean 
115479fda660SRussell King (Oracle) 	__set_bit(ocelot->ports[port]->phy_mode,
115579fda660SRussell King (Oracle) 		  config->supported_interfaces);
115679fda660SRussell King (Oracle) }
115779fda660SRussell King (Oracle) 
felix_phylink_mac_config(struct phylink_config * config,unsigned int mode,const struct phylink_link_state * state)1158ef0e51dcSRussell King (Oracle) static void felix_phylink_mac_config(struct phylink_config *config,
1159544435c9SColin Foster 				     unsigned int mode,
1160544435c9SColin Foster 				     const struct phylink_link_state *state)
1161544435c9SColin Foster {
1162ef0e51dcSRussell King (Oracle) 	struct dsa_port *dp = dsa_phylink_to_port(config);
1163ef0e51dcSRussell King (Oracle) 	struct ocelot *ocelot = dp->ds->priv;
1164ef0e51dcSRussell King (Oracle) 	int port = dp->index;
1165ef0e51dcSRussell King (Oracle) 	struct felix *felix;
1166ef0e51dcSRussell King (Oracle) 
1167ef0e51dcSRussell King (Oracle) 	felix = ocelot_to_felix(ocelot);
1168544435c9SColin Foster 
1169544435c9SColin Foster 	if (felix->info->phylink_mac_config)
1170544435c9SColin Foster 		felix->info->phylink_mac_config(ocelot, port, mode, state);
1171544435c9SColin Foster }
1172544435c9SColin Foster 
1173ef0e51dcSRussell King (Oracle) static struct phylink_pcs *
felix_phylink_mac_select_pcs(struct phylink_config * config,phy_interface_t iface)1174ef0e51dcSRussell King (Oracle) felix_phylink_mac_select_pcs(struct phylink_config *config,
1175864ba485SRussell King (Oracle) 			     phy_interface_t iface)
1176bdeced75SVladimir Oltean {
1177ef0e51dcSRussell King (Oracle) 	struct dsa_port *dp = dsa_phylink_to_port(config);
1178ef0e51dcSRussell King (Oracle) 	struct ocelot *ocelot = dp->ds->priv;
1179864ba485SRussell King (Oracle) 	struct phylink_pcs *pcs = NULL;
1180ef0e51dcSRussell King (Oracle) 	int port = dp->index;
1181ef0e51dcSRussell King (Oracle) 	struct felix *felix;
1182ef0e51dcSRussell King (Oracle) 
1183ef0e51dcSRussell King (Oracle) 	felix = ocelot_to_felix(ocelot);
1184bdeced75SVladimir Oltean 
118549af6a76SColin Foster 	if (felix->pcs && felix->pcs[port])
1186864ba485SRussell King (Oracle) 		pcs = felix->pcs[port];
1187864ba485SRussell King (Oracle) 
1188864ba485SRussell King (Oracle) 	return pcs;
1189bdeced75SVladimir Oltean }
1190bdeced75SVladimir Oltean 
felix_phylink_mac_link_down(struct phylink_config * config,unsigned int link_an_mode,phy_interface_t interface)1191ef0e51dcSRussell King (Oracle) static void felix_phylink_mac_link_down(struct phylink_config *config,
1192bdeced75SVladimir Oltean 					unsigned int link_an_mode,
1193bdeced75SVladimir Oltean 					phy_interface_t interface)
1194bdeced75SVladimir Oltean {
1195ef0e51dcSRussell King (Oracle) 	struct dsa_port *dp = dsa_phylink_to_port(config);
1196ef0e51dcSRussell King (Oracle) 	struct ocelot *ocelot = dp->ds->priv;
1197ef0e51dcSRussell King (Oracle) 	int port = dp->index;
11981dc6a2a0SColin Foster 	struct felix *felix;
11991dc6a2a0SColin Foster 
12001dc6a2a0SColin Foster 	felix = ocelot_to_felix(ocelot);
1201bdeced75SVladimir Oltean 
1202e6e12df6SVladimir Oltean 	ocelot_phylink_mac_link_down(ocelot, port, link_an_mode, interface,
12031dc6a2a0SColin Foster 				     felix->info->quirks);
1204bdeced75SVladimir Oltean }
1205bdeced75SVladimir Oltean 
felix_phylink_mac_link_up(struct phylink_config * config,struct phy_device * phydev,unsigned int link_an_mode,phy_interface_t interface,int speed,int duplex,bool tx_pause,bool rx_pause)1206ef0e51dcSRussell King (Oracle) static void felix_phylink_mac_link_up(struct phylink_config *config,
1207ef0e51dcSRussell King (Oracle) 				      struct phy_device *phydev,
1208bdeced75SVladimir Oltean 				      unsigned int link_an_mode,
1209bdeced75SVladimir Oltean 				      phy_interface_t interface,
12105b502a7bSRussell King 				      int speed, int duplex,
12115b502a7bSRussell King 				      bool tx_pause, bool rx_pause)
1212bdeced75SVladimir Oltean {
1213ef0e51dcSRussell King (Oracle) 	struct dsa_port *dp = dsa_phylink_to_port(config);
1214ef0e51dcSRussell King (Oracle) 	struct ocelot *ocelot = dp->ds->priv;
1215ef0e51dcSRussell King (Oracle) 	int port = dp->index;
1216ef0e51dcSRussell King (Oracle) 	struct felix *felix;
1217ef0e51dcSRussell King (Oracle) 
1218ef0e51dcSRussell King (Oracle) 	felix = ocelot_to_felix(ocelot);
1219bdeced75SVladimir Oltean 
1220e6e12df6SVladimir Oltean 	ocelot_phylink_mac_link_up(ocelot, port, phydev, link_an_mode,
1221e6e12df6SVladimir Oltean 				   interface, speed, duplex, tx_pause, rx_pause,
12221dc6a2a0SColin Foster 				   felix->info->quirks);
12237e14a2dcSVladimir Oltean 
12247e14a2dcSVladimir Oltean 	if (felix->info->port_sched_speed_set)
12257e14a2dcSVladimir Oltean 		felix->info->port_sched_speed_set(ocelot, port, speed);
1226bdeced75SVladimir Oltean }
1227bdeced75SVladimir Oltean 
felix_port_enable(struct dsa_switch * ds,int port,struct phy_device * phydev)1228eca70102SVladimir Oltean static int felix_port_enable(struct dsa_switch *ds, int port,
1229eca70102SVladimir Oltean 			     struct phy_device *phydev)
1230eca70102SVladimir Oltean {
1231eca70102SVladimir Oltean 	struct dsa_port *dp = dsa_to_port(ds, port);
1232eca70102SVladimir Oltean 	struct ocelot *ocelot = ds->priv;
1233eca70102SVladimir Oltean 
1234eca70102SVladimir Oltean 	if (!dsa_port_is_user(dp))
1235eca70102SVladimir Oltean 		return 0;
1236eca70102SVladimir Oltean 
1237eca70102SVladimir Oltean 	if (ocelot->npi >= 0) {
12386ca80638SFlorian Fainelli 		struct net_device *conduit = dsa_port_to_conduit(dp);
1239eca70102SVladimir Oltean 
12406ca80638SFlorian Fainelli 		if (felix_cpu_port_for_conduit(ds, conduit) != ocelot->npi) {
12416ca80638SFlorian Fainelli 			dev_err(ds->dev, "Multiple conduits are not allowed\n");
1242eca70102SVladimir Oltean 			return -EINVAL;
1243eca70102SVladimir Oltean 		}
1244eca70102SVladimir Oltean 	}
1245eca70102SVladimir Oltean 
1246eca70102SVladimir Oltean 	return 0;
1247eca70102SVladimir Oltean }
1248eca70102SVladimir Oltean 
felix_port_qos_map_init(struct ocelot * ocelot,int port)1249bd2b3161SXiaoliang Yang static void felix_port_qos_map_init(struct ocelot *ocelot, int port)
1250bd2b3161SXiaoliang Yang {
1251bd2b3161SXiaoliang Yang 	int i;
1252bd2b3161SXiaoliang Yang 
1253bd2b3161SXiaoliang Yang 	ocelot_rmw_gix(ocelot,
1254bd2b3161SXiaoliang Yang 		       ANA_PORT_QOS_CFG_QOS_PCP_ENA,
1255bd2b3161SXiaoliang Yang 		       ANA_PORT_QOS_CFG_QOS_PCP_ENA,
1256bd2b3161SXiaoliang Yang 		       ANA_PORT_QOS_CFG,
1257bd2b3161SXiaoliang Yang 		       port);
1258bd2b3161SXiaoliang Yang 
125970d39a6eSVladimir Oltean 	for (i = 0; i < OCELOT_NUM_TC * 2; i++) {
1260bd2b3161SXiaoliang Yang 		ocelot_rmw_ix(ocelot,
1261bd2b3161SXiaoliang Yang 			      (ANA_PORT_PCP_DEI_MAP_DP_PCP_DEI_VAL & i) |
1262bd2b3161SXiaoliang Yang 			      ANA_PORT_PCP_DEI_MAP_QOS_PCP_DEI_VAL(i),
1263bd2b3161SXiaoliang Yang 			      ANA_PORT_PCP_DEI_MAP_DP_PCP_DEI_VAL |
1264bd2b3161SXiaoliang Yang 			      ANA_PORT_PCP_DEI_MAP_QOS_PCP_DEI_VAL_M,
1265bd2b3161SXiaoliang Yang 			      ANA_PORT_PCP_DEI_MAP,
1266bd2b3161SXiaoliang Yang 			      port, i);
1267bd2b3161SXiaoliang Yang 	}
1268bd2b3161SXiaoliang Yang }
1269bd2b3161SXiaoliang Yang 
felix_get_stats64(struct dsa_switch * ds,int port,struct rtnl_link_stats64 * stats)1270776b71e5SVladimir Oltean static void felix_get_stats64(struct dsa_switch *ds, int port,
1271776b71e5SVladimir Oltean 			      struct rtnl_link_stats64 *stats)
1272776b71e5SVladimir Oltean {
1273776b71e5SVladimir Oltean 	struct ocelot *ocelot = ds->priv;
1274776b71e5SVladimir Oltean 
1275776b71e5SVladimir Oltean 	ocelot_port_get_stats64(ocelot, port, stats);
1276776b71e5SVladimir Oltean }
1277776b71e5SVladimir Oltean 
felix_get_pause_stats(struct dsa_switch * ds,int port,struct ethtool_pause_stats * pause_stats)1278e32036e1SVladimir Oltean static void felix_get_pause_stats(struct dsa_switch *ds, int port,
1279e32036e1SVladimir Oltean 				  struct ethtool_pause_stats *pause_stats)
1280e32036e1SVladimir Oltean {
1281e32036e1SVladimir Oltean 	struct ocelot *ocelot = ds->priv;
1282e32036e1SVladimir Oltean 
1283e32036e1SVladimir Oltean 	ocelot_port_get_pause_stats(ocelot, port, pause_stats);
1284e32036e1SVladimir Oltean }
1285e32036e1SVladimir Oltean 
felix_get_rmon_stats(struct dsa_switch * ds,int port,struct ethtool_rmon_stats * rmon_stats,const struct ethtool_rmon_hist_range ** ranges)1286e32036e1SVladimir Oltean static void felix_get_rmon_stats(struct dsa_switch *ds, int port,
1287e32036e1SVladimir Oltean 				 struct ethtool_rmon_stats *rmon_stats,
1288e32036e1SVladimir Oltean 				 const struct ethtool_rmon_hist_range **ranges)
1289e32036e1SVladimir Oltean {
1290e32036e1SVladimir Oltean 	struct ocelot *ocelot = ds->priv;
1291e32036e1SVladimir Oltean 
1292e32036e1SVladimir Oltean 	ocelot_port_get_rmon_stats(ocelot, port, rmon_stats, ranges);
1293e32036e1SVladimir Oltean }
1294e32036e1SVladimir Oltean 
felix_get_eth_ctrl_stats(struct dsa_switch * ds,int port,struct ethtool_eth_ctrl_stats * ctrl_stats)1295e32036e1SVladimir Oltean static void felix_get_eth_ctrl_stats(struct dsa_switch *ds, int port,
1296e32036e1SVladimir Oltean 				     struct ethtool_eth_ctrl_stats *ctrl_stats)
1297e32036e1SVladimir Oltean {
1298e32036e1SVladimir Oltean 	struct ocelot *ocelot = ds->priv;
1299e32036e1SVladimir Oltean 
1300e32036e1SVladimir Oltean 	ocelot_port_get_eth_ctrl_stats(ocelot, port, ctrl_stats);
1301e32036e1SVladimir Oltean }
1302e32036e1SVladimir Oltean 
felix_get_eth_mac_stats(struct dsa_switch * ds,int port,struct ethtool_eth_mac_stats * mac_stats)1303e32036e1SVladimir Oltean static void felix_get_eth_mac_stats(struct dsa_switch *ds, int port,
1304e32036e1SVladimir Oltean 				    struct ethtool_eth_mac_stats *mac_stats)
1305e32036e1SVladimir Oltean {
1306e32036e1SVladimir Oltean 	struct ocelot *ocelot = ds->priv;
1307e32036e1SVladimir Oltean 
1308e32036e1SVladimir Oltean 	ocelot_port_get_eth_mac_stats(ocelot, port, mac_stats);
1309e32036e1SVladimir Oltean }
1310e32036e1SVladimir Oltean 
felix_get_eth_phy_stats(struct dsa_switch * ds,int port,struct ethtool_eth_phy_stats * phy_stats)1311e32036e1SVladimir Oltean static void felix_get_eth_phy_stats(struct dsa_switch *ds, int port,
1312e32036e1SVladimir Oltean 				    struct ethtool_eth_phy_stats *phy_stats)
1313e32036e1SVladimir Oltean {
1314e32036e1SVladimir Oltean 	struct ocelot *ocelot = ds->priv;
1315e32036e1SVladimir Oltean 
1316e32036e1SVladimir Oltean 	ocelot_port_get_eth_phy_stats(ocelot, port, phy_stats);
1317e32036e1SVladimir Oltean }
1318e32036e1SVladimir Oltean 
felix_get_strings(struct dsa_switch * ds,int port,u32 stringset,u8 * data)131956051948SVladimir Oltean static void felix_get_strings(struct dsa_switch *ds, int port,
132056051948SVladimir Oltean 			      u32 stringset, u8 *data)
132156051948SVladimir Oltean {
132256051948SVladimir Oltean 	struct ocelot *ocelot = ds->priv;
132356051948SVladimir Oltean 
132456051948SVladimir Oltean 	return ocelot_get_strings(ocelot, port, stringset, data);
132556051948SVladimir Oltean }
132656051948SVladimir Oltean 
felix_get_ethtool_stats(struct dsa_switch * ds,int port,u64 * data)132756051948SVladimir Oltean static void felix_get_ethtool_stats(struct dsa_switch *ds, int port, u64 *data)
132856051948SVladimir Oltean {
132956051948SVladimir Oltean 	struct ocelot *ocelot = ds->priv;
133056051948SVladimir Oltean 
133156051948SVladimir Oltean 	ocelot_get_ethtool_stats(ocelot, port, data);
133256051948SVladimir Oltean }
133356051948SVladimir Oltean 
felix_get_sset_count(struct dsa_switch * ds,int port,int sset)133456051948SVladimir Oltean static int felix_get_sset_count(struct dsa_switch *ds, int port, int sset)
133556051948SVladimir Oltean {
133656051948SVladimir Oltean 	struct ocelot *ocelot = ds->priv;
133756051948SVladimir Oltean 
133856051948SVladimir Oltean 	return ocelot_get_sset_count(ocelot, port, sset);
133956051948SVladimir Oltean }
134056051948SVladimir Oltean 
felix_get_ts_info(struct dsa_switch * ds,int port,struct kernel_ethtool_ts_info * info)134156051948SVladimir Oltean static int felix_get_ts_info(struct dsa_switch *ds, int port,
13422111375bSKory Maincent 			     struct kernel_ethtool_ts_info *info)
134356051948SVladimir Oltean {
134456051948SVladimir Oltean 	struct ocelot *ocelot = ds->priv;
134556051948SVladimir Oltean 
134656051948SVladimir Oltean 	return ocelot_get_ts_info(ocelot, port, info);
134756051948SVladimir Oltean }
134856051948SVladimir Oltean 
1349acf242fcSColin Foster static const u32 felix_phy_match_table[PHY_INTERFACE_MODE_MAX] = {
1350acf242fcSColin Foster 	[PHY_INTERFACE_MODE_INTERNAL] = OCELOT_PORT_MODE_INTERNAL,
1351acf242fcSColin Foster 	[PHY_INTERFACE_MODE_SGMII] = OCELOT_PORT_MODE_SGMII,
1352acf242fcSColin Foster 	[PHY_INTERFACE_MODE_QSGMII] = OCELOT_PORT_MODE_QSGMII,
1353acf242fcSColin Foster 	[PHY_INTERFACE_MODE_USXGMII] = OCELOT_PORT_MODE_USXGMII,
135411ecf341SVladimir Oltean 	[PHY_INTERFACE_MODE_1000BASEX] = OCELOT_PORT_MODE_1000BASEX,
1355acf242fcSColin Foster 	[PHY_INTERFACE_MODE_2500BASEX] = OCELOT_PORT_MODE_2500BASEX,
1356acf242fcSColin Foster };
1357acf242fcSColin Foster 
felix_validate_phy_mode(struct felix * felix,int port,phy_interface_t phy_mode)1358acf242fcSColin Foster static int felix_validate_phy_mode(struct felix *felix, int port,
1359acf242fcSColin Foster 				   phy_interface_t phy_mode)
1360acf242fcSColin Foster {
1361acf242fcSColin Foster 	u32 modes = felix->info->port_modes[port];
1362acf242fcSColin Foster 
1363acf242fcSColin Foster 	if (felix_phy_match_table[phy_mode] & modes)
1364acf242fcSColin Foster 		return 0;
1365acf242fcSColin Foster 	return -EOPNOTSUPP;
1366acf242fcSColin Foster }
1367acf242fcSColin Foster 
felix_parse_ports_node(struct felix * felix,struct device_node * ports_node,phy_interface_t * port_phy_modes)1368bdeced75SVladimir Oltean static int felix_parse_ports_node(struct felix *felix,
1369bdeced75SVladimir Oltean 				  struct device_node *ports_node,
1370bdeced75SVladimir Oltean 				  phy_interface_t *port_phy_modes)
1371bdeced75SVladimir Oltean {
1372bdeced75SVladimir Oltean 	struct device *dev = felix->ocelot.dev;
1373bdeced75SVladimir Oltean 
1374*e58c3f3dSJinjie Ruan 	for_each_available_child_of_node_scoped(ports_node, child) {
1375bdeced75SVladimir Oltean 		phy_interface_t phy_mode;
1376bdeced75SVladimir Oltean 		u32 port;
1377bdeced75SVladimir Oltean 		int err;
1378bdeced75SVladimir Oltean 
1379bdeced75SVladimir Oltean 		/* Get switch port number from DT */
1380bdeced75SVladimir Oltean 		if (of_property_read_u32(child, "reg", &port) < 0) {
1381bdeced75SVladimir Oltean 			dev_err(dev, "Port number not defined in device tree "
1382bdeced75SVladimir Oltean 				"(property \"reg\")\n");
1383bdeced75SVladimir Oltean 			return -ENODEV;
1384bdeced75SVladimir Oltean 		}
1385bdeced75SVladimir Oltean 
1386bdeced75SVladimir Oltean 		/* Get PHY mode from DT */
1387bdeced75SVladimir Oltean 		err = of_get_phy_mode(child, &phy_mode);
1388bdeced75SVladimir Oltean 		if (err) {
1389bdeced75SVladimir Oltean 			dev_err(dev, "Failed to read phy-mode or "
1390bdeced75SVladimir Oltean 				"phy-interface-type property for port %d\n",
1391bdeced75SVladimir Oltean 				port);
1392bdeced75SVladimir Oltean 			return -ENODEV;
1393bdeced75SVladimir Oltean 		}
1394bdeced75SVladimir Oltean 
1395acf242fcSColin Foster 		err = felix_validate_phy_mode(felix, port, phy_mode);
1396bdeced75SVladimir Oltean 		if (err < 0) {
1397de879a01SColin Foster 			dev_info(dev, "Unsupported PHY mode %s on port %d\n",
1398bdeced75SVladimir Oltean 				 phy_modes(phy_mode), port);
1399de879a01SColin Foster 
1400de879a01SColin Foster 			/* Leave port_phy_modes[port] = 0, which is also
1401de879a01SColin Foster 			 * PHY_INTERFACE_MODE_NA. This will perform a
1402de879a01SColin Foster 			 * best-effort to bring up as many ports as possible.
1403de879a01SColin Foster 			 */
1404de879a01SColin Foster 			continue;
1405bdeced75SVladimir Oltean 		}
1406bdeced75SVladimir Oltean 
1407bdeced75SVladimir Oltean 		port_phy_modes[port] = phy_mode;
1408bdeced75SVladimir Oltean 	}
1409bdeced75SVladimir Oltean 
1410bdeced75SVladimir Oltean 	return 0;
1411bdeced75SVladimir Oltean }
1412bdeced75SVladimir Oltean 
felix_parse_dt(struct felix * felix,phy_interface_t * port_phy_modes)1413bdeced75SVladimir Oltean static int felix_parse_dt(struct felix *felix, phy_interface_t *port_phy_modes)
1414bdeced75SVladimir Oltean {
1415bdeced75SVladimir Oltean 	struct device *dev = felix->ocelot.dev;
1416bdeced75SVladimir Oltean 	struct device_node *switch_node;
1417bdeced75SVladimir Oltean 	struct device_node *ports_node;
1418bdeced75SVladimir Oltean 	int err;
1419bdeced75SVladimir Oltean 
1420bdeced75SVladimir Oltean 	switch_node = dev->of_node;
1421bdeced75SVladimir Oltean 
1422bdeced75SVladimir Oltean 	ports_node = of_get_child_by_name(switch_node, "ports");
1423abecbfcdSVladimir Oltean 	if (!ports_node)
1424abecbfcdSVladimir Oltean 		ports_node = of_get_child_by_name(switch_node, "ethernet-ports");
1425bdeced75SVladimir Oltean 	if (!ports_node) {
1426abecbfcdSVladimir Oltean 		dev_err(dev, "Incorrect bindings: absent \"ports\" or \"ethernet-ports\" node\n");
1427bdeced75SVladimir Oltean 		return -ENODEV;
1428bdeced75SVladimir Oltean 	}
1429bdeced75SVladimir Oltean 
1430bdeced75SVladimir Oltean 	err = felix_parse_ports_node(felix, ports_node, port_phy_modes);
1431bdeced75SVladimir Oltean 	of_node_put(ports_node);
1432bdeced75SVladimir Oltean 
1433bdeced75SVladimir Oltean 	return err;
1434bdeced75SVladimir Oltean }
1435bdeced75SVladimir Oltean 
felix_request_regmap_by_name(struct felix * felix,const char * resource_name)14361109b97bSVladimir Oltean static struct regmap *felix_request_regmap_by_name(struct felix *felix,
14371109b97bSVladimir Oltean 						   const char *resource_name)
14381109b97bSVladimir Oltean {
14391109b97bSVladimir Oltean 	struct ocelot *ocelot = &felix->ocelot;
14401109b97bSVladimir Oltean 	struct resource res;
14411109b97bSVladimir Oltean 	int i;
14421109b97bSVladimir Oltean 
1443dc454fa4SColin Foster 	/* In an MFD configuration, regmaps are registered directly to the
1444dc454fa4SColin Foster 	 * parent device before the child devices are probed, so there is no
1445dc454fa4SColin Foster 	 * need to initialize a new one.
1446dc454fa4SColin Foster 	 */
1447dc454fa4SColin Foster 	if (!felix->info->resources)
1448dc454fa4SColin Foster 		return dev_get_regmap(ocelot->dev->parent, resource_name);
1449dc454fa4SColin Foster 
14501109b97bSVladimir Oltean 	for (i = 0; i < felix->info->num_resources; i++) {
14511109b97bSVladimir Oltean 		if (strcmp(resource_name, felix->info->resources[i].name))
14521109b97bSVladimir Oltean 			continue;
14531109b97bSVladimir Oltean 
14541109b97bSVladimir Oltean 		memcpy(&res, &felix->info->resources[i], sizeof(res));
14551109b97bSVladimir Oltean 		res.start += felix->switch_base;
14561109b97bSVladimir Oltean 		res.end += felix->switch_base;
14571109b97bSVladimir Oltean 
14581109b97bSVladimir Oltean 		return ocelot_regmap_init(ocelot, &res);
14591109b97bSVladimir Oltean 	}
14601109b97bSVladimir Oltean 
14611109b97bSVladimir Oltean 	return ERR_PTR(-ENOENT);
14621109b97bSVladimir Oltean }
14631109b97bSVladimir Oltean 
felix_request_regmap(struct felix * felix,enum ocelot_target target)14641109b97bSVladimir Oltean static struct regmap *felix_request_regmap(struct felix *felix,
14651109b97bSVladimir Oltean 					   enum ocelot_target target)
14661109b97bSVladimir Oltean {
14671109b97bSVladimir Oltean 	const char *resource_name = felix->info->resource_names[target];
14681109b97bSVladimir Oltean 
14691109b97bSVladimir Oltean 	/* If the driver didn't provide a resource name for the target,
14701109b97bSVladimir Oltean 	 * the resource is optional.
14711109b97bSVladimir Oltean 	 */
14721109b97bSVladimir Oltean 	if (!resource_name)
14731109b97bSVladimir Oltean 		return NULL;
14741109b97bSVladimir Oltean 
14751109b97bSVladimir Oltean 	return felix_request_regmap_by_name(felix, resource_name);
14761109b97bSVladimir Oltean }
14771109b97bSVladimir Oltean 
felix_request_port_regmap(struct felix * felix,int port)14781109b97bSVladimir Oltean static struct regmap *felix_request_port_regmap(struct felix *felix, int port)
14791109b97bSVladimir Oltean {
14801109b97bSVladimir Oltean 	char resource_name[32];
14811109b97bSVladimir Oltean 
14821109b97bSVladimir Oltean 	sprintf(resource_name, "port%d", port);
14831109b97bSVladimir Oltean 
14841109b97bSVladimir Oltean 	return felix_request_regmap_by_name(felix, resource_name);
14851109b97bSVladimir Oltean }
14861109b97bSVladimir Oltean 
felix_init_structs(struct felix * felix,int num_phys_ports)148756051948SVladimir Oltean static int felix_init_structs(struct felix *felix, int num_phys_ports)
148856051948SVladimir Oltean {
148956051948SVladimir Oltean 	struct ocelot *ocelot = &felix->ocelot;
1490bdeced75SVladimir Oltean 	phy_interface_t *port_phy_modes;
14911109b97bSVladimir Oltean 	struct regmap *target;
149256051948SVladimir Oltean 	int port, i, err;
149356051948SVladimir Oltean 
149456051948SVladimir Oltean 	ocelot->num_phys_ports = num_phys_ports;
149556051948SVladimir Oltean 	ocelot->ports = devm_kcalloc(ocelot->dev, num_phys_ports,
149656051948SVladimir Oltean 				     sizeof(struct ocelot_port *), GFP_KERNEL);
149756051948SVladimir Oltean 	if (!ocelot->ports)
149856051948SVladimir Oltean 		return -ENOMEM;
149956051948SVladimir Oltean 
150056051948SVladimir Oltean 	ocelot->map		= felix->info->map;
150121ce7f3eSVladimir Oltean 	ocelot->num_mact_rows	= felix->info->num_mact_rows;
150207d985eeSVladimir Oltean 	ocelot->vcap		= felix->info->vcap;
150377043c37SXiaoliang Yang 	ocelot->vcap_pol.base	= felix->info->vcap_pol_base;
150477043c37SXiaoliang Yang 	ocelot->vcap_pol.max	= felix->info->vcap_pol_max;
150577043c37SXiaoliang Yang 	ocelot->vcap_pol.base2	= felix->info->vcap_pol_base2;
150677043c37SXiaoliang Yang 	ocelot->vcap_pol.max2	= felix->info->vcap_pol_max2;
150756051948SVladimir Oltean 	ocelot->ops		= felix->info->ops;
1508cacea62fSVladimir Oltean 	ocelot->npi_inj_prefix	= OCELOT_TAG_PREFIX_SHORT;
1509cacea62fSVladimir Oltean 	ocelot->npi_xtr_prefix	= OCELOT_TAG_PREFIX_SHORT;
1510f59fd9caSVladimir Oltean 	ocelot->devlink		= felix->ds->devlink;
151156051948SVladimir Oltean 
1512bdeced75SVladimir Oltean 	port_phy_modes = kcalloc(num_phys_ports, sizeof(phy_interface_t),
1513bdeced75SVladimir Oltean 				 GFP_KERNEL);
1514bdeced75SVladimir Oltean 	if (!port_phy_modes)
1515bdeced75SVladimir Oltean 		return -ENOMEM;
1516bdeced75SVladimir Oltean 
1517bdeced75SVladimir Oltean 	err = felix_parse_dt(felix, port_phy_modes);
1518bdeced75SVladimir Oltean 	if (err) {
1519bdeced75SVladimir Oltean 		kfree(port_phy_modes);
1520bdeced75SVladimir Oltean 		return err;
1521bdeced75SVladimir Oltean 	}
1522bdeced75SVladimir Oltean 
152356051948SVladimir Oltean 	for (i = 0; i < TARGET_MAX; i++) {
15241109b97bSVladimir Oltean 		target = felix_request_regmap(felix, i);
152556051948SVladimir Oltean 		if (IS_ERR(target)) {
152656051948SVladimir Oltean 			dev_err(ocelot->dev,
15271109b97bSVladimir Oltean 				"Failed to map device memory space: %pe\n",
15281109b97bSVladimir Oltean 				target);
1529bdeced75SVladimir Oltean 			kfree(port_phy_modes);
153056051948SVladimir Oltean 			return PTR_ERR(target);
153156051948SVladimir Oltean 		}
153256051948SVladimir Oltean 
153356051948SVladimir Oltean 		ocelot->targets[i] = target;
153456051948SVladimir Oltean 	}
153556051948SVladimir Oltean 
153656051948SVladimir Oltean 	err = ocelot_regfields_init(ocelot, felix->info->regfields);
153756051948SVladimir Oltean 	if (err) {
153856051948SVladimir Oltean 		dev_err(ocelot->dev, "failed to init reg fields map\n");
1539bdeced75SVladimir Oltean 		kfree(port_phy_modes);
154056051948SVladimir Oltean 		return err;
154156051948SVladimir Oltean 	}
154256051948SVladimir Oltean 
154356051948SVladimir Oltean 	for (port = 0; port < num_phys_ports; port++) {
154456051948SVladimir Oltean 		struct ocelot_port *ocelot_port;
154556051948SVladimir Oltean 
154656051948SVladimir Oltean 		ocelot_port = devm_kzalloc(ocelot->dev,
154756051948SVladimir Oltean 					   sizeof(struct ocelot_port),
154856051948SVladimir Oltean 					   GFP_KERNEL);
154956051948SVladimir Oltean 		if (!ocelot_port) {
155056051948SVladimir Oltean 			dev_err(ocelot->dev,
155156051948SVladimir Oltean 				"failed to allocate port memory\n");
1552bdeced75SVladimir Oltean 			kfree(port_phy_modes);
155356051948SVladimir Oltean 			return -ENOMEM;
155456051948SVladimir Oltean 		}
155556051948SVladimir Oltean 
15561109b97bSVladimir Oltean 		target = felix_request_port_regmap(felix, port);
155791c724cfSVladimir Oltean 		if (IS_ERR(target)) {
155856051948SVladimir Oltean 			dev_err(ocelot->dev,
15591109b97bSVladimir Oltean 				"Failed to map memory space for port %d: %pe\n",
15601109b97bSVladimir Oltean 				port, target);
1561bdeced75SVladimir Oltean 			kfree(port_phy_modes);
156291c724cfSVladimir Oltean 			return PTR_ERR(target);
156356051948SVladimir Oltean 		}
156456051948SVladimir Oltean 
1565bdeced75SVladimir Oltean 		ocelot_port->phy_mode = port_phy_modes[port];
156656051948SVladimir Oltean 		ocelot_port->ocelot = ocelot;
156791c724cfSVladimir Oltean 		ocelot_port->target = target;
15687e708760SVladimir Oltean 		ocelot_port->index = port;
156956051948SVladimir Oltean 		ocelot->ports[port] = ocelot_port;
157056051948SVladimir Oltean 	}
157156051948SVladimir Oltean 
1572bdeced75SVladimir Oltean 	kfree(port_phy_modes);
1573bdeced75SVladimir Oltean 
1574bdeced75SVladimir Oltean 	if (felix->info->mdio_bus_alloc) {
1575bdeced75SVladimir Oltean 		err = felix->info->mdio_bus_alloc(ocelot);
1576bdeced75SVladimir Oltean 		if (err < 0)
1577bdeced75SVladimir Oltean 			return err;
1578bdeced75SVladimir Oltean 	}
1579bdeced75SVladimir Oltean 
158056051948SVladimir Oltean 	return 0;
158156051948SVladimir Oltean }
158256051948SVladimir Oltean 
ocelot_port_purge_txtstamp_skb(struct ocelot * ocelot,int port,struct sk_buff * skb)15831328a883SVladimir Oltean static void ocelot_port_purge_txtstamp_skb(struct ocelot *ocelot, int port,
15841328a883SVladimir Oltean 					   struct sk_buff *skb)
15851328a883SVladimir Oltean {
15861328a883SVladimir Oltean 	struct ocelot_port *ocelot_port = ocelot->ports[port];
15871328a883SVladimir Oltean 	struct sk_buff *clone = OCELOT_SKB_CB(skb)->clone;
15881328a883SVladimir Oltean 	struct sk_buff *skb_match = NULL, *skb_tmp;
15891328a883SVladimir Oltean 	unsigned long flags;
15901328a883SVladimir Oltean 
15911328a883SVladimir Oltean 	if (!clone)
15921328a883SVladimir Oltean 		return;
15931328a883SVladimir Oltean 
15941328a883SVladimir Oltean 	spin_lock_irqsave(&ocelot_port->tx_skbs.lock, flags);
15951328a883SVladimir Oltean 
15961328a883SVladimir Oltean 	skb_queue_walk_safe(&ocelot_port->tx_skbs, skb, skb_tmp) {
15971328a883SVladimir Oltean 		if (skb != clone)
15981328a883SVladimir Oltean 			continue;
15991328a883SVladimir Oltean 		__skb_unlink(skb, &ocelot_port->tx_skbs);
16001328a883SVladimir Oltean 		skb_match = skb;
16011328a883SVladimir Oltean 		break;
16021328a883SVladimir Oltean 	}
16031328a883SVladimir Oltean 
16041328a883SVladimir Oltean 	spin_unlock_irqrestore(&ocelot_port->tx_skbs.lock, flags);
16051328a883SVladimir Oltean 
16061328a883SVladimir Oltean 	WARN_ONCE(!skb_match,
16071328a883SVladimir Oltean 		  "Could not find skb clone in TX timestamping list\n");
16081328a883SVladimir Oltean }
16091328a883SVladimir Oltean 
161049f885b2SVladimir Oltean #define work_to_xmit_work(w) \
161149f885b2SVladimir Oltean 		container_of((w), struct felix_deferred_xmit_work, work)
161249f885b2SVladimir Oltean 
felix_port_deferred_xmit(struct kthread_work * work)161349f885b2SVladimir Oltean static void felix_port_deferred_xmit(struct kthread_work *work)
161449f885b2SVladimir Oltean {
161549f885b2SVladimir Oltean 	struct felix_deferred_xmit_work *xmit_work = work_to_xmit_work(work);
161649f885b2SVladimir Oltean 	struct dsa_switch *ds = xmit_work->dp->ds;
161749f885b2SVladimir Oltean 	struct sk_buff *skb = xmit_work->skb;
161849f885b2SVladimir Oltean 	u32 rew_op = ocelot_ptp_rew_op(skb);
161949f885b2SVladimir Oltean 	struct ocelot *ocelot = ds->priv;
162049f885b2SVladimir Oltean 	int port = xmit_work->dp->index;
162149f885b2SVladimir Oltean 	int retries = 10;
162249f885b2SVladimir Oltean 
1623c5e12ac3SVladimir Oltean 	ocelot_lock_inj_grp(ocelot, 0);
1624c5e12ac3SVladimir Oltean 
162549f885b2SVladimir Oltean 	do {
162649f885b2SVladimir Oltean 		if (ocelot_can_inject(ocelot, 0))
162749f885b2SVladimir Oltean 			break;
162849f885b2SVladimir Oltean 
162949f885b2SVladimir Oltean 		cpu_relax();
163049f885b2SVladimir Oltean 	} while (--retries);
163149f885b2SVladimir Oltean 
163249f885b2SVladimir Oltean 	if (!retries) {
1633c5e12ac3SVladimir Oltean 		ocelot_unlock_inj_grp(ocelot, 0);
163449f885b2SVladimir Oltean 		dev_err(ocelot->dev, "port %d failed to inject skb\n",
163549f885b2SVladimir Oltean 			port);
16361328a883SVladimir Oltean 		ocelot_port_purge_txtstamp_skb(ocelot, port, skb);
163749f885b2SVladimir Oltean 		kfree_skb(skb);
163849f885b2SVladimir Oltean 		return;
163949f885b2SVladimir Oltean 	}
164049f885b2SVladimir Oltean 
164149f885b2SVladimir Oltean 	ocelot_port_inject_frame(ocelot, port, 0, rew_op, skb);
164249f885b2SVladimir Oltean 
1643c5e12ac3SVladimir Oltean 	ocelot_unlock_inj_grp(ocelot, 0);
1644c5e12ac3SVladimir Oltean 
164549f885b2SVladimir Oltean 	consume_skb(skb);
164649f885b2SVladimir Oltean 	kfree(xmit_work);
164749f885b2SVladimir Oltean }
164849f885b2SVladimir Oltean 
felix_connect_tag_protocol(struct dsa_switch * ds,enum dsa_tag_protocol proto)164935d97680SVladimir Oltean static int felix_connect_tag_protocol(struct dsa_switch *ds,
165035d97680SVladimir Oltean 				      enum dsa_tag_protocol proto)
165149f885b2SVladimir Oltean {
165235d97680SVladimir Oltean 	struct ocelot_8021q_tagger_data *tagger_data;
165349f885b2SVladimir Oltean 
165435d97680SVladimir Oltean 	switch (proto) {
165535d97680SVladimir Oltean 	case DSA_TAG_PROTO_OCELOT_8021Q:
165635d97680SVladimir Oltean 		tagger_data = ocelot_8021q_tagger_data(ds);
165735d97680SVladimir Oltean 		tagger_data->xmit_work_fn = felix_port_deferred_xmit;
165849f885b2SVladimir Oltean 		return 0;
165935d97680SVladimir Oltean 	case DSA_TAG_PROTO_OCELOT:
166035d97680SVladimir Oltean 	case DSA_TAG_PROTO_SEVILLE:
166149f885b2SVladimir Oltean 		return 0;
166235d97680SVladimir Oltean 	default:
166335d97680SVladimir Oltean 		return -EPROTONOSUPPORT;
166449f885b2SVladimir Oltean 	}
166549f885b2SVladimir Oltean }
166649f885b2SVladimir Oltean 
felix_setup(struct dsa_switch * ds)166756051948SVladimir Oltean static int felix_setup(struct dsa_switch *ds)
166856051948SVladimir Oltean {
166956051948SVladimir Oltean 	struct ocelot *ocelot = ds->priv;
167056051948SVladimir Oltean 	struct felix *felix = ocelot_to_felix(ocelot);
16712960bb14SVladimir Oltean 	struct dsa_port *dp;
16722960bb14SVladimir Oltean 	int err;
167356051948SVladimir Oltean 
167456051948SVladimir Oltean 	err = felix_init_structs(felix, ds->num_ports);
167556051948SVladimir Oltean 	if (err)
167656051948SVladimir Oltean 		return err;
167756051948SVladimir Oltean 
16783821fd01SColin Foster 	if (ocelot->targets[HSIO])
16793821fd01SColin Foster 		ocelot_pll5_init(ocelot);
16803821fd01SColin Foster 
1681d1cc0e93SVladimir Oltean 	err = ocelot_init(ocelot);
1682d1cc0e93SVladimir Oltean 	if (err)
16836b73b7c9SVladimir Oltean 		goto out_mdiobus_free;
1684d1cc0e93SVladimir Oltean 
16852b49d128SYangbo Lu 	if (ocelot->ptp) {
16862ac7c6c5SVladimir Oltean 		err = ocelot_init_timestamp(ocelot, felix->info->ptp_caps);
16872b49d128SYangbo Lu 		if (err) {
16882b49d128SYangbo Lu 			dev_err(ocelot->dev,
16892b49d128SYangbo Lu 				"Timestamp initialization failed\n");
16902b49d128SYangbo Lu 			ocelot->ptp = 0;
16912b49d128SYangbo Lu 		}
16922b49d128SYangbo Lu 	}
169356051948SVladimir Oltean 
16942960bb14SVladimir Oltean 	dsa_switch_for_each_available_port(dp, ds) {
16952960bb14SVladimir Oltean 		ocelot_init_port(ocelot, dp->index);
1696bd2b3161SXiaoliang Yang 
16976865eceeSColin Foster 		if (felix->info->configure_serdes)
16986865eceeSColin Foster 			felix->info->configure_serdes(ocelot, dp->index,
16996865eceeSColin Foster 						      dp->dn);
17006865eceeSColin Foster 
1701bd2b3161SXiaoliang Yang 		/* Set the default QoS Classification based on PCP and DEI
1702bd2b3161SXiaoliang Yang 		 * bits of vlan tag.
1703bd2b3161SXiaoliang Yang 		 */
17042960bb14SVladimir Oltean 		felix_port_qos_map_init(ocelot, dp->index);
170556051948SVladimir Oltean 	}
170656051948SVladimir Oltean 
17070367a177SVladimir Oltean 	if (felix->info->request_irq) {
17080367a177SVladimir Oltean 		err = felix->info->request_irq(ocelot);
17090367a177SVladimir Oltean 		if (err) {
17100367a177SVladimir Oltean 			dev_err(ocelot->dev, "Failed to request IRQ: %pe\n",
17110367a177SVladimir Oltean 				ERR_PTR(err));
17120367a177SVladimir Oltean 			goto out_deinit_ports;
17130367a177SVladimir Oltean 		}
17140367a177SVladimir Oltean 	}
17150367a177SVladimir Oltean 
1716f59fd9caSVladimir Oltean 	err = ocelot_devlink_sb_register(ocelot);
1717f59fd9caSVladimir Oltean 	if (err)
17186b73b7c9SVladimir Oltean 		goto out_deinit_ports;
1719f59fd9caSVladimir Oltean 
17207a29d220SVladimir Oltean 	/* The initial tag protocol is NPI which won't fail during initial
17217a29d220SVladimir Oltean 	 * setup, there's no real point in checking for errors.
17221cf3299bSVladimir Oltean 	 */
17237a29d220SVladimir Oltean 	felix_change_tag_protocol(ds, felix->tag_proto);
17241cf3299bSVladimir Oltean 
17250b912fc9SVladimir Oltean 	ds->mtu_enforcement_ingress = true;
1726c54913c1SVladimir Oltean 	ds->assisted_learning_on_cpu_port = true;
172754c31984SVladimir Oltean 	ds->fdb_isolation = true;
172854c31984SVladimir Oltean 	ds->max_num_bridges = ds->num_ports;
1729bdeced75SVladimir Oltean 
173056051948SVladimir Oltean 	return 0;
17316b73b7c9SVladimir Oltean 
17326b73b7c9SVladimir Oltean out_deinit_ports:
17332960bb14SVladimir Oltean 	dsa_switch_for_each_available_port(dp, ds)
17342960bb14SVladimir Oltean 		ocelot_deinit_port(ocelot, dp->index);
17356b73b7c9SVladimir Oltean 
17366b73b7c9SVladimir Oltean 	ocelot_deinit_timestamp(ocelot);
17376b73b7c9SVladimir Oltean 	ocelot_deinit(ocelot);
17386b73b7c9SVladimir Oltean 
17396b73b7c9SVladimir Oltean out_mdiobus_free:
17406b73b7c9SVladimir Oltean 	if (felix->info->mdio_bus_free)
17416b73b7c9SVladimir Oltean 		felix->info->mdio_bus_free(ocelot);
17426b73b7c9SVladimir Oltean 
17436b73b7c9SVladimir Oltean 	return err;
174456051948SVladimir Oltean }
174556051948SVladimir Oltean 
felix_teardown(struct dsa_switch * ds)174656051948SVladimir Oltean static void felix_teardown(struct dsa_switch *ds)
174756051948SVladimir Oltean {
174856051948SVladimir Oltean 	struct ocelot *ocelot = ds->priv;
1749bdeced75SVladimir Oltean 	struct felix *felix = ocelot_to_felix(ocelot);
17502960bb14SVladimir Oltean 	struct dsa_port *dp;
1751bdeced75SVladimir Oltean 
1752a94c16a2SVladimir Oltean 	rtnl_lock();
17537a29d220SVladimir Oltean 	if (felix->tag_proto_ops)
17547a29d220SVladimir Oltean 		felix->tag_proto_ops->teardown(ds);
1755a94c16a2SVladimir Oltean 	rtnl_unlock();
1756adb3dccfSVladimir Oltean 
17572960bb14SVladimir Oltean 	dsa_switch_for_each_available_port(dp, ds)
17582960bb14SVladimir Oltean 		ocelot_deinit_port(ocelot, dp->index);
1759d19741b0SVladimir Oltean 
176049f885b2SVladimir Oltean 	ocelot_devlink_sb_unregister(ocelot);
176149f885b2SVladimir Oltean 	ocelot_deinit_timestamp(ocelot);
176249f885b2SVladimir Oltean 	ocelot_deinit(ocelot);
176349f885b2SVladimir Oltean 
1764d19741b0SVladimir Oltean 	if (felix->info->mdio_bus_free)
1765d19741b0SVladimir Oltean 		felix->info->mdio_bus_free(ocelot);
176656051948SVladimir Oltean }
176756051948SVladimir Oltean 
felix_hwtstamp_get(struct dsa_switch * ds,int port,struct ifreq * ifr)1768c0bcf537SYangbo Lu static int felix_hwtstamp_get(struct dsa_switch *ds, int port,
1769c0bcf537SYangbo Lu 			      struct ifreq *ifr)
1770c0bcf537SYangbo Lu {
1771c0bcf537SYangbo Lu 	struct ocelot *ocelot = ds->priv;
1772c0bcf537SYangbo Lu 
1773c0bcf537SYangbo Lu 	return ocelot_hwstamp_get(ocelot, port, ifr);
1774c0bcf537SYangbo Lu }
1775c0bcf537SYangbo Lu 
felix_hwtstamp_set(struct dsa_switch * ds,int port,struct ifreq * ifr)1776c0bcf537SYangbo Lu static int felix_hwtstamp_set(struct dsa_switch *ds, int port,
1777c0bcf537SYangbo Lu 			      struct ifreq *ifr)
1778c0bcf537SYangbo Lu {
1779c0bcf537SYangbo Lu 	struct ocelot *ocelot = ds->priv;
178099348004SVladimir Oltean 	struct felix *felix = ocelot_to_felix(ocelot);
178199348004SVladimir Oltean 	bool using_tag_8021q;
178299348004SVladimir Oltean 	int err;
1783c0bcf537SYangbo Lu 
178499348004SVladimir Oltean 	err = ocelot_hwstamp_set(ocelot, port, ifr);
178599348004SVladimir Oltean 	if (err)
178699348004SVladimir Oltean 		return err;
178799348004SVladimir Oltean 
178899348004SVladimir Oltean 	using_tag_8021q = felix->tag_proto == DSA_TAG_PROTO_OCELOT_8021Q;
178999348004SVladimir Oltean 
179099348004SVladimir Oltean 	return felix_update_trapping_destinations(ds, using_tag_8021q);
1791c0bcf537SYangbo Lu }
1792c0bcf537SYangbo Lu 
felix_check_xtr_pkt(struct ocelot * ocelot)1793d219b4b6SVladimir Oltean static bool felix_check_xtr_pkt(struct ocelot *ocelot)
17940a6f17c6SVladimir Oltean {
17950a6f17c6SVladimir Oltean 	struct felix *felix = ocelot_to_felix(ocelot);
1796dbd03285SVladimir Oltean 	int err = 0, grp = 0;
17970a6f17c6SVladimir Oltean 
17980a6f17c6SVladimir Oltean 	if (felix->tag_proto != DSA_TAG_PROTO_OCELOT_8021Q)
17990a6f17c6SVladimir Oltean 		return false;
18000a6f17c6SVladimir Oltean 
18010a6f17c6SVladimir Oltean 	if (!felix->info->quirk_no_xtr_irq)
18020a6f17c6SVladimir Oltean 		return false;
18030a6f17c6SVladimir Oltean 
1804c5e12ac3SVladimir Oltean 	ocelot_lock_xtr_grp(ocelot, grp);
1805c5e12ac3SVladimir Oltean 
18060a6f17c6SVladimir Oltean 	while (ocelot_read(ocelot, QS_XTR_DATA_PRESENT) & BIT(grp)) {
18070a6f17c6SVladimir Oltean 		struct sk_buff *skb;
18080a6f17c6SVladimir Oltean 		unsigned int type;
18090a6f17c6SVladimir Oltean 
18100a6f17c6SVladimir Oltean 		err = ocelot_xtr_poll_frame(ocelot, grp, &skb);
18110a6f17c6SVladimir Oltean 		if (err)
18120a6f17c6SVladimir Oltean 			goto out;
18130a6f17c6SVladimir Oltean 
18140a6f17c6SVladimir Oltean 		/* We trap to the CPU port module all PTP frames, but
18150a6f17c6SVladimir Oltean 		 * felix_rxtstamp() only gets called for event frames.
18160a6f17c6SVladimir Oltean 		 * So we need to avoid sending duplicate general
18170a6f17c6SVladimir Oltean 		 * message frames by running a second BPF classifier
18180a6f17c6SVladimir Oltean 		 * here and dropping those.
18190a6f17c6SVladimir Oltean 		 */
18200a6f17c6SVladimir Oltean 		__skb_push(skb, ETH_HLEN);
18210a6f17c6SVladimir Oltean 
18220a6f17c6SVladimir Oltean 		type = ptp_classify_raw(skb);
18230a6f17c6SVladimir Oltean 
18240a6f17c6SVladimir Oltean 		__skb_pull(skb, ETH_HLEN);
18250a6f17c6SVladimir Oltean 
18260a6f17c6SVladimir Oltean 		if (type == PTP_CLASS_NONE) {
18270a6f17c6SVladimir Oltean 			kfree_skb(skb);
18280a6f17c6SVladimir Oltean 			continue;
18290a6f17c6SVladimir Oltean 		}
18300a6f17c6SVladimir Oltean 
18310a6f17c6SVladimir Oltean 		netif_rx(skb);
18320a6f17c6SVladimir Oltean 	}
18330a6f17c6SVladimir Oltean 
18340a6f17c6SVladimir Oltean out:
18355d3bb7ddSVladimir Oltean 	if (err < 0) {
18365d3bb7ddSVladimir Oltean 		dev_err_ratelimited(ocelot->dev,
18375d3bb7ddSVladimir Oltean 				    "Error during packet extraction: %pe\n",
18385d3bb7ddSVladimir Oltean 				    ERR_PTR(err));
18390a6f17c6SVladimir Oltean 		ocelot_drain_cpu_queue(ocelot, 0);
18405d3bb7ddSVladimir Oltean 	}
18410a6f17c6SVladimir Oltean 
1842c5e12ac3SVladimir Oltean 	ocelot_unlock_xtr_grp(ocelot, grp);
1843c5e12ac3SVladimir Oltean 
18440a6f17c6SVladimir Oltean 	return true;
18450a6f17c6SVladimir Oltean }
18460a6f17c6SVladimir Oltean 
felix_rxtstamp(struct dsa_switch * ds,int port,struct sk_buff * skb,unsigned int type)1847c0bcf537SYangbo Lu static bool felix_rxtstamp(struct dsa_switch *ds, int port,
1848c0bcf537SYangbo Lu 			   struct sk_buff *skb, unsigned int type)
1849c0bcf537SYangbo Lu {
185092f62485SVladimir Oltean 	u32 tstamp_lo = OCELOT_SKB_CB(skb)->tstamp_lo;
1851c0bcf537SYangbo Lu 	struct skb_shared_hwtstamps *shhwtstamps;
1852c0bcf537SYangbo Lu 	struct ocelot *ocelot = ds->priv;
1853c0bcf537SYangbo Lu 	struct timespec64 ts;
185492f62485SVladimir Oltean 	u32 tstamp_hi;
185592f62485SVladimir Oltean 	u64 tstamp;
1856c0bcf537SYangbo Lu 
18572edcfcbbSVladimir Oltean 	switch (type & PTP_CLASS_PMASK) {
18582edcfcbbSVladimir Oltean 	case PTP_CLASS_L2:
18592edcfcbbSVladimir Oltean 		if (!(ocelot->ports[port]->trap_proto & OCELOT_PROTO_PTP_L2))
18602edcfcbbSVladimir Oltean 			return false;
18612edcfcbbSVladimir Oltean 		break;
18622edcfcbbSVladimir Oltean 	case PTP_CLASS_IPV4:
18632edcfcbbSVladimir Oltean 	case PTP_CLASS_IPV6:
18642edcfcbbSVladimir Oltean 		if (!(ocelot->ports[port]->trap_proto & OCELOT_PROTO_PTP_L4))
18652edcfcbbSVladimir Oltean 			return false;
18662edcfcbbSVladimir Oltean 		break;
18672edcfcbbSVladimir Oltean 	}
18682edcfcbbSVladimir Oltean 
18690a6f17c6SVladimir Oltean 	/* If the "no XTR IRQ" workaround is in use, tell DSA to defer this skb
18700a6f17c6SVladimir Oltean 	 * for RX timestamping. Then free it, and poll for its copy through
18710a6f17c6SVladimir Oltean 	 * MMIO in the CPU port module, and inject that into the stack from
18720a6f17c6SVladimir Oltean 	 * ocelot_xtr_poll().
18730a6f17c6SVladimir Oltean 	 */
1874d219b4b6SVladimir Oltean 	if (felix_check_xtr_pkt(ocelot)) {
18750a6f17c6SVladimir Oltean 		kfree_skb(skb);
18760a6f17c6SVladimir Oltean 		return true;
18770a6f17c6SVladimir Oltean 	}
18780a6f17c6SVladimir Oltean 
1879c0bcf537SYangbo Lu 	ocelot_ptp_gettime64(&ocelot->ptp_info, &ts);
1880c0bcf537SYangbo Lu 	tstamp = ktime_set(ts.tv_sec, ts.tv_nsec);
1881c0bcf537SYangbo Lu 
1882c0bcf537SYangbo Lu 	tstamp_hi = tstamp >> 32;
1883c0bcf537SYangbo Lu 	if ((tstamp & 0xffffffff) < tstamp_lo)
1884c0bcf537SYangbo Lu 		tstamp_hi--;
1885c0bcf537SYangbo Lu 
1886c0bcf537SYangbo Lu 	tstamp = ((u64)tstamp_hi << 32) | tstamp_lo;
1887c0bcf537SYangbo Lu 
1888c0bcf537SYangbo Lu 	shhwtstamps = skb_hwtstamps(skb);
1889c0bcf537SYangbo Lu 	memset(shhwtstamps, 0, sizeof(struct skb_shared_hwtstamps));
1890c0bcf537SYangbo Lu 	shhwtstamps->hwtstamp = tstamp;
1891c0bcf537SYangbo Lu 	return false;
1892c0bcf537SYangbo Lu }
1893c0bcf537SYangbo Lu 
felix_txtstamp(struct dsa_switch * ds,int port,struct sk_buff * skb)18945c5416f5SYangbo Lu static void felix_txtstamp(struct dsa_switch *ds, int port,
18955c5416f5SYangbo Lu 			   struct sk_buff *skb)
1896c0bcf537SYangbo Lu {
1897c0bcf537SYangbo Lu 	struct ocelot *ocelot = ds->priv;
1898682eaad9SYangbo Lu 	struct sk_buff *clone = NULL;
1899c0bcf537SYangbo Lu 
1900682eaad9SYangbo Lu 	if (!ocelot->ptp)
19015c5416f5SYangbo Lu 		return;
1902c0bcf537SYangbo Lu 
190352849bcfSVladimir Oltean 	if (ocelot_port_txtstamp_request(ocelot, port, skb, &clone)) {
190452849bcfSVladimir Oltean 		dev_err_ratelimited(ds->dev,
190552849bcfSVladimir Oltean 				    "port %d delivering skb without TX timestamp\n",
190652849bcfSVladimir Oltean 				    port);
1907682eaad9SYangbo Lu 		return;
190852849bcfSVladimir Oltean 	}
1909682eaad9SYangbo Lu 
1910682eaad9SYangbo Lu 	if (clone)
1911c4b364ceSYangbo Lu 		OCELOT_SKB_CB(skb)->clone = clone;
19125c5416f5SYangbo Lu }
1913c0bcf537SYangbo Lu 
felix_change_mtu(struct dsa_switch * ds,int port,int new_mtu)19140b912fc9SVladimir Oltean static int felix_change_mtu(struct dsa_switch *ds, int port, int new_mtu)
19150b912fc9SVladimir Oltean {
19160b912fc9SVladimir Oltean 	struct ocelot *ocelot = ds->priv;
191755a515b1SVladimir Oltean 	struct ocelot_port *ocelot_port = ocelot->ports[port];
19180b912fc9SVladimir Oltean 
19190b912fc9SVladimir Oltean 	ocelot_port_set_maxlen(ocelot, port, new_mtu);
19200b912fc9SVladimir Oltean 
1921009d30f1SVladimir Oltean 	mutex_lock(&ocelot->fwd_domain_lock);
192255a515b1SVladimir Oltean 
1923c6081914SVladimir Oltean 	if (ocelot_port->taprio && ocelot->ops->tas_guard_bands_update)
1924c6081914SVladimir Oltean 		ocelot->ops->tas_guard_bands_update(ocelot, port);
192555a515b1SVladimir Oltean 
1926009d30f1SVladimir Oltean 	mutex_unlock(&ocelot->fwd_domain_lock);
192755a515b1SVladimir Oltean 
19280b912fc9SVladimir Oltean 	return 0;
19290b912fc9SVladimir Oltean }
19300b912fc9SVladimir Oltean 
felix_get_max_mtu(struct dsa_switch * ds,int port)19310b912fc9SVladimir Oltean static int felix_get_max_mtu(struct dsa_switch *ds, int port)
19320b912fc9SVladimir Oltean {
19330b912fc9SVladimir Oltean 	struct ocelot *ocelot = ds->priv;
19340b912fc9SVladimir Oltean 
19350b912fc9SVladimir Oltean 	return ocelot_get_max_mtu(ocelot, port);
19360b912fc9SVladimir Oltean }
19370b912fc9SVladimir Oltean 
felix_cls_flower_add(struct dsa_switch * ds,int port,struct flow_cls_offload * cls,bool ingress)193807d985eeSVladimir Oltean static int felix_cls_flower_add(struct dsa_switch *ds, int port,
193907d985eeSVladimir Oltean 				struct flow_cls_offload *cls, bool ingress)
194007d985eeSVladimir Oltean {
194107d985eeSVladimir Oltean 	struct ocelot *ocelot = ds->priv;
194299348004SVladimir Oltean 	struct felix *felix = ocelot_to_felix(ocelot);
194399348004SVladimir Oltean 	bool using_tag_8021q;
194499348004SVladimir Oltean 	int err;
194507d985eeSVladimir Oltean 
194699348004SVladimir Oltean 	err = ocelot_cls_flower_replace(ocelot, port, cls, ingress);
194799348004SVladimir Oltean 	if (err)
194899348004SVladimir Oltean 		return err;
194999348004SVladimir Oltean 
195099348004SVladimir Oltean 	using_tag_8021q = felix->tag_proto == DSA_TAG_PROTO_OCELOT_8021Q;
195199348004SVladimir Oltean 
195299348004SVladimir Oltean 	return felix_update_trapping_destinations(ds, using_tag_8021q);
195307d985eeSVladimir Oltean }
195407d985eeSVladimir Oltean 
felix_cls_flower_del(struct dsa_switch * ds,int port,struct flow_cls_offload * cls,bool ingress)195507d985eeSVladimir Oltean static int felix_cls_flower_del(struct dsa_switch *ds, int port,
195607d985eeSVladimir Oltean 				struct flow_cls_offload *cls, bool ingress)
195707d985eeSVladimir Oltean {
195807d985eeSVladimir Oltean 	struct ocelot *ocelot = ds->priv;
195907d985eeSVladimir Oltean 
196007d985eeSVladimir Oltean 	return ocelot_cls_flower_destroy(ocelot, port, cls, ingress);
196107d985eeSVladimir Oltean }
196207d985eeSVladimir Oltean 
felix_cls_flower_stats(struct dsa_switch * ds,int port,struct flow_cls_offload * cls,bool ingress)196307d985eeSVladimir Oltean static int felix_cls_flower_stats(struct dsa_switch *ds, int port,
196407d985eeSVladimir Oltean 				  struct flow_cls_offload *cls, bool ingress)
196507d985eeSVladimir Oltean {
196607d985eeSVladimir Oltean 	struct ocelot *ocelot = ds->priv;
196707d985eeSVladimir Oltean 
196807d985eeSVladimir Oltean 	return ocelot_cls_flower_stats(ocelot, port, cls, ingress);
196907d985eeSVladimir Oltean }
197007d985eeSVladimir Oltean 
felix_port_policer_add(struct dsa_switch * ds,int port,struct dsa_mall_policer_tc_entry * policer)1971fc411eaaSVladimir Oltean static int felix_port_policer_add(struct dsa_switch *ds, int port,
1972fc411eaaSVladimir Oltean 				  struct dsa_mall_policer_tc_entry *policer)
1973fc411eaaSVladimir Oltean {
1974fc411eaaSVladimir Oltean 	struct ocelot *ocelot = ds->priv;
1975fc411eaaSVladimir Oltean 	struct ocelot_policer pol = {
1976fc411eaaSVladimir Oltean 		.rate = div_u64(policer->rate_bytes_per_sec, 1000) * 8,
19775f035af7SPo Liu 		.burst = policer->burst,
1978fc411eaaSVladimir Oltean 	};
1979fc411eaaSVladimir Oltean 
1980fc411eaaSVladimir Oltean 	return ocelot_port_policer_add(ocelot, port, &pol);
1981fc411eaaSVladimir Oltean }
1982fc411eaaSVladimir Oltean 
felix_port_policer_del(struct dsa_switch * ds,int port)1983fc411eaaSVladimir Oltean static void felix_port_policer_del(struct dsa_switch *ds, int port)
1984fc411eaaSVladimir Oltean {
1985fc411eaaSVladimir Oltean 	struct ocelot *ocelot = ds->priv;
1986fc411eaaSVladimir Oltean 
1987fc411eaaSVladimir Oltean 	ocelot_port_policer_del(ocelot, port);
1988fc411eaaSVladimir Oltean }
1989fc411eaaSVladimir Oltean 
felix_port_mirror_add(struct dsa_switch * ds,int port,struct dsa_mall_mirror_tc_entry * mirror,bool ingress,struct netlink_ext_ack * extack)19905e497497SVladimir Oltean static int felix_port_mirror_add(struct dsa_switch *ds, int port,
19915e497497SVladimir Oltean 				 struct dsa_mall_mirror_tc_entry *mirror,
19925e497497SVladimir Oltean 				 bool ingress, struct netlink_ext_ack *extack)
19935e497497SVladimir Oltean {
19945e497497SVladimir Oltean 	struct ocelot *ocelot = ds->priv;
19955e497497SVladimir Oltean 
19965e497497SVladimir Oltean 	return ocelot_port_mirror_add(ocelot, port, mirror->to_local_port,
19975e497497SVladimir Oltean 				      ingress, extack);
19985e497497SVladimir Oltean }
19995e497497SVladimir Oltean 
felix_port_mirror_del(struct dsa_switch * ds,int port,struct dsa_mall_mirror_tc_entry * mirror)20005e497497SVladimir Oltean static void felix_port_mirror_del(struct dsa_switch *ds, int port,
20015e497497SVladimir Oltean 				  struct dsa_mall_mirror_tc_entry *mirror)
20025e497497SVladimir Oltean {
20035e497497SVladimir Oltean 	struct ocelot *ocelot = ds->priv;
20045e497497SVladimir Oltean 
20055e497497SVladimir Oltean 	ocelot_port_mirror_del(ocelot, port, mirror->ingress);
20065e497497SVladimir Oltean }
20075e497497SVladimir Oltean 
felix_port_setup_tc(struct dsa_switch * ds,int port,enum tc_setup_type type,void * type_data)2008de143c0eSXiaoliang Yang static int felix_port_setup_tc(struct dsa_switch *ds, int port,
2009de143c0eSXiaoliang Yang 			       enum tc_setup_type type,
2010de143c0eSXiaoliang Yang 			       void *type_data)
2011de143c0eSXiaoliang Yang {
2012de143c0eSXiaoliang Yang 	struct ocelot *ocelot = ds->priv;
2013de143c0eSXiaoliang Yang 	struct felix *felix = ocelot_to_felix(ocelot);
2014de143c0eSXiaoliang Yang 
2015de143c0eSXiaoliang Yang 	if (felix->info->port_setup_tc)
2016de143c0eSXiaoliang Yang 		return felix->info->port_setup_tc(ds, port, type, type_data);
2017de143c0eSXiaoliang Yang 	else
2018de143c0eSXiaoliang Yang 		return -EOPNOTSUPP;
2019de143c0eSXiaoliang Yang }
2020de143c0eSXiaoliang Yang 
felix_sb_pool_get(struct dsa_switch * ds,unsigned int sb_index,u16 pool_index,struct devlink_sb_pool_info * pool_info)2021f59fd9caSVladimir Oltean static int felix_sb_pool_get(struct dsa_switch *ds, unsigned int sb_index,
2022f59fd9caSVladimir Oltean 			     u16 pool_index,
2023f59fd9caSVladimir Oltean 			     struct devlink_sb_pool_info *pool_info)
2024f59fd9caSVladimir Oltean {
2025f59fd9caSVladimir Oltean 	struct ocelot *ocelot = ds->priv;
2026f59fd9caSVladimir Oltean 
2027f59fd9caSVladimir Oltean 	return ocelot_sb_pool_get(ocelot, sb_index, pool_index, pool_info);
2028f59fd9caSVladimir Oltean }
2029f59fd9caSVladimir Oltean 
felix_sb_pool_set(struct dsa_switch * ds,unsigned int sb_index,u16 pool_index,u32 size,enum devlink_sb_threshold_type threshold_type,struct netlink_ext_ack * extack)2030f59fd9caSVladimir Oltean static int felix_sb_pool_set(struct dsa_switch *ds, unsigned int sb_index,
2031f59fd9caSVladimir Oltean 			     u16 pool_index, u32 size,
2032f59fd9caSVladimir Oltean 			     enum devlink_sb_threshold_type threshold_type,
2033f59fd9caSVladimir Oltean 			     struct netlink_ext_ack *extack)
2034f59fd9caSVladimir Oltean {
2035f59fd9caSVladimir Oltean 	struct ocelot *ocelot = ds->priv;
2036f59fd9caSVladimir Oltean 
2037f59fd9caSVladimir Oltean 	return ocelot_sb_pool_set(ocelot, sb_index, pool_index, size,
2038f59fd9caSVladimir Oltean 				  threshold_type, extack);
2039f59fd9caSVladimir Oltean }
2040f59fd9caSVladimir Oltean 
felix_sb_port_pool_get(struct dsa_switch * ds,int port,unsigned int sb_index,u16 pool_index,u32 * p_threshold)2041f59fd9caSVladimir Oltean static int felix_sb_port_pool_get(struct dsa_switch *ds, int port,
2042f59fd9caSVladimir Oltean 				  unsigned int sb_index, u16 pool_index,
2043f59fd9caSVladimir Oltean 				  u32 *p_threshold)
2044f59fd9caSVladimir Oltean {
2045f59fd9caSVladimir Oltean 	struct ocelot *ocelot = ds->priv;
2046f59fd9caSVladimir Oltean 
2047f59fd9caSVladimir Oltean 	return ocelot_sb_port_pool_get(ocelot, port, sb_index, pool_index,
2048f59fd9caSVladimir Oltean 				       p_threshold);
2049f59fd9caSVladimir Oltean }
2050f59fd9caSVladimir Oltean 
felix_sb_port_pool_set(struct dsa_switch * ds,int port,unsigned int sb_index,u16 pool_index,u32 threshold,struct netlink_ext_ack * extack)2051f59fd9caSVladimir Oltean static int felix_sb_port_pool_set(struct dsa_switch *ds, int port,
2052f59fd9caSVladimir Oltean 				  unsigned int sb_index, u16 pool_index,
2053f59fd9caSVladimir Oltean 				  u32 threshold, struct netlink_ext_ack *extack)
2054f59fd9caSVladimir Oltean {
2055f59fd9caSVladimir Oltean 	struct ocelot *ocelot = ds->priv;
2056f59fd9caSVladimir Oltean 
2057f59fd9caSVladimir Oltean 	return ocelot_sb_port_pool_set(ocelot, port, sb_index, pool_index,
2058f59fd9caSVladimir Oltean 				       threshold, extack);
2059f59fd9caSVladimir Oltean }
2060f59fd9caSVladimir Oltean 
felix_sb_tc_pool_bind_get(struct dsa_switch * ds,int port,unsigned int sb_index,u16 tc_index,enum devlink_sb_pool_type pool_type,u16 * p_pool_index,u32 * p_threshold)2061f59fd9caSVladimir Oltean static int felix_sb_tc_pool_bind_get(struct dsa_switch *ds, int port,
2062f59fd9caSVladimir Oltean 				     unsigned int sb_index, u16 tc_index,
2063f59fd9caSVladimir Oltean 				     enum devlink_sb_pool_type pool_type,
2064f59fd9caSVladimir Oltean 				     u16 *p_pool_index, u32 *p_threshold)
2065f59fd9caSVladimir Oltean {
2066f59fd9caSVladimir Oltean 	struct ocelot *ocelot = ds->priv;
2067f59fd9caSVladimir Oltean 
2068f59fd9caSVladimir Oltean 	return ocelot_sb_tc_pool_bind_get(ocelot, port, sb_index, tc_index,
2069f59fd9caSVladimir Oltean 					  pool_type, p_pool_index,
2070f59fd9caSVladimir Oltean 					  p_threshold);
2071f59fd9caSVladimir Oltean }
2072f59fd9caSVladimir Oltean 
felix_sb_tc_pool_bind_set(struct dsa_switch * ds,int port,unsigned int sb_index,u16 tc_index,enum devlink_sb_pool_type pool_type,u16 pool_index,u32 threshold,struct netlink_ext_ack * extack)2073f59fd9caSVladimir Oltean static int felix_sb_tc_pool_bind_set(struct dsa_switch *ds, int port,
2074f59fd9caSVladimir Oltean 				     unsigned int sb_index, u16 tc_index,
2075f59fd9caSVladimir Oltean 				     enum devlink_sb_pool_type pool_type,
2076f59fd9caSVladimir Oltean 				     u16 pool_index, u32 threshold,
2077f59fd9caSVladimir Oltean 				     struct netlink_ext_ack *extack)
2078f59fd9caSVladimir Oltean {
2079f59fd9caSVladimir Oltean 	struct ocelot *ocelot = ds->priv;
2080f59fd9caSVladimir Oltean 
2081f59fd9caSVladimir Oltean 	return ocelot_sb_tc_pool_bind_set(ocelot, port, sb_index, tc_index,
2082f59fd9caSVladimir Oltean 					  pool_type, pool_index, threshold,
2083f59fd9caSVladimir Oltean 					  extack);
2084f59fd9caSVladimir Oltean }
2085f59fd9caSVladimir Oltean 
felix_sb_occ_snapshot(struct dsa_switch * ds,unsigned int sb_index)2086f59fd9caSVladimir Oltean static int felix_sb_occ_snapshot(struct dsa_switch *ds,
2087f59fd9caSVladimir Oltean 				 unsigned int sb_index)
2088f59fd9caSVladimir Oltean {
2089f59fd9caSVladimir Oltean 	struct ocelot *ocelot = ds->priv;
2090f59fd9caSVladimir Oltean 
2091f59fd9caSVladimir Oltean 	return ocelot_sb_occ_snapshot(ocelot, sb_index);
2092f59fd9caSVladimir Oltean }
2093f59fd9caSVladimir Oltean 
felix_sb_occ_max_clear(struct dsa_switch * ds,unsigned int sb_index)2094f59fd9caSVladimir Oltean static int felix_sb_occ_max_clear(struct dsa_switch *ds,
2095f59fd9caSVladimir Oltean 				  unsigned int sb_index)
2096f59fd9caSVladimir Oltean {
2097f59fd9caSVladimir Oltean 	struct ocelot *ocelot = ds->priv;
2098f59fd9caSVladimir Oltean 
2099f59fd9caSVladimir Oltean 	return ocelot_sb_occ_max_clear(ocelot, sb_index);
2100f59fd9caSVladimir Oltean }
2101f59fd9caSVladimir Oltean 
felix_sb_occ_port_pool_get(struct dsa_switch * ds,int port,unsigned int sb_index,u16 pool_index,u32 * p_cur,u32 * p_max)2102f59fd9caSVladimir Oltean static int felix_sb_occ_port_pool_get(struct dsa_switch *ds, int port,
2103f59fd9caSVladimir Oltean 				      unsigned int sb_index, u16 pool_index,
2104f59fd9caSVladimir Oltean 				      u32 *p_cur, u32 *p_max)
2105f59fd9caSVladimir Oltean {
2106f59fd9caSVladimir Oltean 	struct ocelot *ocelot = ds->priv;
2107f59fd9caSVladimir Oltean 
2108f59fd9caSVladimir Oltean 	return ocelot_sb_occ_port_pool_get(ocelot, port, sb_index, pool_index,
2109f59fd9caSVladimir Oltean 					   p_cur, p_max);
2110f59fd9caSVladimir Oltean }
2111f59fd9caSVladimir Oltean 
felix_sb_occ_tc_port_bind_get(struct dsa_switch * ds,int port,unsigned int sb_index,u16 tc_index,enum devlink_sb_pool_type pool_type,u32 * p_cur,u32 * p_max)2112f59fd9caSVladimir Oltean static int felix_sb_occ_tc_port_bind_get(struct dsa_switch *ds, int port,
2113f59fd9caSVladimir Oltean 					 unsigned int sb_index, u16 tc_index,
2114f59fd9caSVladimir Oltean 					 enum devlink_sb_pool_type pool_type,
2115f59fd9caSVladimir Oltean 					 u32 *p_cur, u32 *p_max)
2116f59fd9caSVladimir Oltean {
2117f59fd9caSVladimir Oltean 	struct ocelot *ocelot = ds->priv;
2118f59fd9caSVladimir Oltean 
2119f59fd9caSVladimir Oltean 	return ocelot_sb_occ_tc_port_bind_get(ocelot, port, sb_index, tc_index,
2120f59fd9caSVladimir Oltean 					      pool_type, p_cur, p_max);
2121f59fd9caSVladimir Oltean }
2122f59fd9caSVladimir Oltean 
felix_mrp_add(struct dsa_switch * ds,int port,const struct switchdev_obj_mrp * mrp)2123a026c50bSHoratiu Vultur static int felix_mrp_add(struct dsa_switch *ds, int port,
2124a026c50bSHoratiu Vultur 			 const struct switchdev_obj_mrp *mrp)
2125a026c50bSHoratiu Vultur {
2126a026c50bSHoratiu Vultur 	struct ocelot *ocelot = ds->priv;
2127a026c50bSHoratiu Vultur 
2128a026c50bSHoratiu Vultur 	return ocelot_mrp_add(ocelot, port, mrp);
2129a026c50bSHoratiu Vultur }
2130a026c50bSHoratiu Vultur 
felix_mrp_del(struct dsa_switch * ds,int port,const struct switchdev_obj_mrp * mrp)2131a026c50bSHoratiu Vultur static int felix_mrp_del(struct dsa_switch *ds, int port,
2132a026c50bSHoratiu Vultur 			 const struct switchdev_obj_mrp *mrp)
2133a026c50bSHoratiu Vultur {
2134a026c50bSHoratiu Vultur 	struct ocelot *ocelot = ds->priv;
2135a026c50bSHoratiu Vultur 
2136a026c50bSHoratiu Vultur 	return ocelot_mrp_add(ocelot, port, mrp);
2137a026c50bSHoratiu Vultur }
2138a026c50bSHoratiu Vultur 
2139a026c50bSHoratiu Vultur static int
felix_mrp_add_ring_role(struct dsa_switch * ds,int port,const struct switchdev_obj_ring_role_mrp * mrp)2140a026c50bSHoratiu Vultur felix_mrp_add_ring_role(struct dsa_switch *ds, int port,
2141a026c50bSHoratiu Vultur 			const struct switchdev_obj_ring_role_mrp *mrp)
2142a026c50bSHoratiu Vultur {
2143a026c50bSHoratiu Vultur 	struct ocelot *ocelot = ds->priv;
2144a026c50bSHoratiu Vultur 
2145a026c50bSHoratiu Vultur 	return ocelot_mrp_add_ring_role(ocelot, port, mrp);
2146a026c50bSHoratiu Vultur }
2147a026c50bSHoratiu Vultur 
2148a026c50bSHoratiu Vultur static int
felix_mrp_del_ring_role(struct dsa_switch * ds,int port,const struct switchdev_obj_ring_role_mrp * mrp)2149a026c50bSHoratiu Vultur felix_mrp_del_ring_role(struct dsa_switch *ds, int port,
2150a026c50bSHoratiu Vultur 			const struct switchdev_obj_ring_role_mrp *mrp)
2151a026c50bSHoratiu Vultur {
2152a026c50bSHoratiu Vultur 	struct ocelot *ocelot = ds->priv;
2153a026c50bSHoratiu Vultur 
2154a026c50bSHoratiu Vultur 	return ocelot_mrp_del_ring_role(ocelot, port, mrp);
2155a026c50bSHoratiu Vultur }
2156a026c50bSHoratiu Vultur 
felix_port_get_default_prio(struct dsa_switch * ds,int port)2157978777d0SVladimir Oltean static int felix_port_get_default_prio(struct dsa_switch *ds, int port)
2158978777d0SVladimir Oltean {
2159978777d0SVladimir Oltean 	struct ocelot *ocelot = ds->priv;
2160978777d0SVladimir Oltean 
2161978777d0SVladimir Oltean 	return ocelot_port_get_default_prio(ocelot, port);
2162978777d0SVladimir Oltean }
2163978777d0SVladimir Oltean 
felix_port_set_default_prio(struct dsa_switch * ds,int port,u8 prio)2164978777d0SVladimir Oltean static int felix_port_set_default_prio(struct dsa_switch *ds, int port,
2165978777d0SVladimir Oltean 				       u8 prio)
2166978777d0SVladimir Oltean {
2167978777d0SVladimir Oltean 	struct ocelot *ocelot = ds->priv;
2168978777d0SVladimir Oltean 
2169978777d0SVladimir Oltean 	return ocelot_port_set_default_prio(ocelot, port, prio);
2170978777d0SVladimir Oltean }
2171978777d0SVladimir Oltean 
felix_port_get_dscp_prio(struct dsa_switch * ds,int port,u8 dscp)2172978777d0SVladimir Oltean static int felix_port_get_dscp_prio(struct dsa_switch *ds, int port, u8 dscp)
2173978777d0SVladimir Oltean {
2174978777d0SVladimir Oltean 	struct ocelot *ocelot = ds->priv;
2175978777d0SVladimir Oltean 
2176978777d0SVladimir Oltean 	return ocelot_port_get_dscp_prio(ocelot, port, dscp);
2177978777d0SVladimir Oltean }
2178978777d0SVladimir Oltean 
felix_port_add_dscp_prio(struct dsa_switch * ds,int port,u8 dscp,u8 prio)2179978777d0SVladimir Oltean static int felix_port_add_dscp_prio(struct dsa_switch *ds, int port, u8 dscp,
2180978777d0SVladimir Oltean 				    u8 prio)
2181978777d0SVladimir Oltean {
2182978777d0SVladimir Oltean 	struct ocelot *ocelot = ds->priv;
2183978777d0SVladimir Oltean 
2184978777d0SVladimir Oltean 	return ocelot_port_add_dscp_prio(ocelot, port, dscp, prio);
2185978777d0SVladimir Oltean }
2186978777d0SVladimir Oltean 
felix_port_del_dscp_prio(struct dsa_switch * ds,int port,u8 dscp,u8 prio)2187978777d0SVladimir Oltean static int felix_port_del_dscp_prio(struct dsa_switch *ds, int port, u8 dscp,
2188978777d0SVladimir Oltean 				    u8 prio)
2189978777d0SVladimir Oltean {
2190978777d0SVladimir Oltean 	struct ocelot *ocelot = ds->priv;
2191978777d0SVladimir Oltean 
2192978777d0SVladimir Oltean 	return ocelot_port_del_dscp_prio(ocelot, port, dscp, prio);
2193978777d0SVladimir Oltean }
2194978777d0SVladimir Oltean 
felix_get_mm(struct dsa_switch * ds,int port,struct ethtool_mm_state * state)21956505b680SVladimir Oltean static int felix_get_mm(struct dsa_switch *ds, int port,
21966505b680SVladimir Oltean 			struct ethtool_mm_state *state)
21976505b680SVladimir Oltean {
21986505b680SVladimir Oltean 	struct ocelot *ocelot = ds->priv;
21996505b680SVladimir Oltean 
22006505b680SVladimir Oltean 	return ocelot_port_get_mm(ocelot, port, state);
22016505b680SVladimir Oltean }
22026505b680SVladimir Oltean 
felix_set_mm(struct dsa_switch * ds,int port,struct ethtool_mm_cfg * cfg,struct netlink_ext_ack * extack)22036505b680SVladimir Oltean static int felix_set_mm(struct dsa_switch *ds, int port,
22046505b680SVladimir Oltean 			struct ethtool_mm_cfg *cfg,
22056505b680SVladimir Oltean 			struct netlink_ext_ack *extack)
22066505b680SVladimir Oltean {
22076505b680SVladimir Oltean 	struct ocelot *ocelot = ds->priv;
22086505b680SVladimir Oltean 
22096505b680SVladimir Oltean 	return ocelot_port_set_mm(ocelot, port, cfg, extack);
22106505b680SVladimir Oltean }
22116505b680SVladimir Oltean 
felix_get_mm_stats(struct dsa_switch * ds,int port,struct ethtool_mm_stats * stats)2212ab3f97a9SVladimir Oltean static void felix_get_mm_stats(struct dsa_switch *ds, int port,
2213ab3f97a9SVladimir Oltean 			       struct ethtool_mm_stats *stats)
2214ab3f97a9SVladimir Oltean {
2215ab3f97a9SVladimir Oltean 	struct ocelot *ocelot = ds->priv;
2216ab3f97a9SVladimir Oltean 
2217ab3f97a9SVladimir Oltean 	ocelot_port_get_mm_stats(ocelot, port, stats);
2218ab3f97a9SVladimir Oltean }
2219ab3f97a9SVladimir Oltean 
2220a4303941SVladimir Oltean static const struct phylink_mac_ops felix_phylink_mac_ops = {
2221ef0e51dcSRussell King (Oracle) 	.mac_select_pcs		= felix_phylink_mac_select_pcs,
2222ef0e51dcSRussell King (Oracle) 	.mac_config		= felix_phylink_mac_config,
2223ef0e51dcSRussell King (Oracle) 	.mac_link_down		= felix_phylink_mac_link_down,
2224ef0e51dcSRussell King (Oracle) 	.mac_link_up		= felix_phylink_mac_link_up,
2225ef0e51dcSRussell King (Oracle) };
2226ef0e51dcSRussell King (Oracle) 
2227a4303941SVladimir Oltean static const struct dsa_switch_ops felix_switch_ops = {
222856051948SVladimir Oltean 	.get_tag_protocol		= felix_get_tag_protocol,
2229adb3dccfSVladimir Oltean 	.change_tag_protocol		= felix_change_tag_protocol,
223035d97680SVladimir Oltean 	.connect_tag_protocol		= felix_connect_tag_protocol,
223156051948SVladimir Oltean 	.setup				= felix_setup,
223256051948SVladimir Oltean 	.teardown			= felix_teardown,
223356051948SVladimir Oltean 	.set_ageing_time		= felix_set_ageing_time,
22346505b680SVladimir Oltean 	.get_mm				= felix_get_mm,
22356505b680SVladimir Oltean 	.set_mm				= felix_set_mm,
2236ab3f97a9SVladimir Oltean 	.get_mm_stats			= felix_get_mm_stats,
2237776b71e5SVladimir Oltean 	.get_stats64			= felix_get_stats64,
2238e32036e1SVladimir Oltean 	.get_pause_stats		= felix_get_pause_stats,
2239e32036e1SVladimir Oltean 	.get_rmon_stats			= felix_get_rmon_stats,
2240e32036e1SVladimir Oltean 	.get_eth_ctrl_stats		= felix_get_eth_ctrl_stats,
2241e32036e1SVladimir Oltean 	.get_eth_mac_stats		= felix_get_eth_mac_stats,
2242e32036e1SVladimir Oltean 	.get_eth_phy_stats		= felix_get_eth_phy_stats,
224356051948SVladimir Oltean 	.get_strings			= felix_get_strings,
224456051948SVladimir Oltean 	.get_ethtool_stats		= felix_get_ethtool_stats,
224556051948SVladimir Oltean 	.get_sset_count			= felix_get_sset_count,
224656051948SVladimir Oltean 	.get_ts_info			= felix_get_ts_info,
224779fda660SRussell King (Oracle) 	.phylink_get_caps		= felix_phylink_get_caps,
2248eca70102SVladimir Oltean 	.port_enable			= felix_port_enable,
22495cad43a5SVladimir Oltean 	.port_fast_age			= felix_port_fast_age,
225056051948SVladimir Oltean 	.port_fdb_dump			= felix_fdb_dump,
225156051948SVladimir Oltean 	.port_fdb_add			= felix_fdb_add,
225256051948SVladimir Oltean 	.port_fdb_del			= felix_fdb_del,
2253961d8b69SVladimir Oltean 	.lag_fdb_add			= felix_lag_fdb_add,
2254961d8b69SVladimir Oltean 	.lag_fdb_del			= felix_lag_fdb_del,
2255209edf95SVladimir Oltean 	.port_mdb_add			= felix_mdb_add,
2256209edf95SVladimir Oltean 	.port_mdb_del			= felix_mdb_del,
2257421741eaSVladimir Oltean 	.port_pre_bridge_flags		= felix_pre_bridge_flags,
2258421741eaSVladimir Oltean 	.port_bridge_flags		= felix_bridge_flags,
225956051948SVladimir Oltean 	.port_bridge_join		= felix_bridge_join,
226056051948SVladimir Oltean 	.port_bridge_leave		= felix_bridge_leave,
22618fe6832eSVladimir Oltean 	.port_lag_join			= felix_lag_join,
22628fe6832eSVladimir Oltean 	.port_lag_leave			= felix_lag_leave,
22638fe6832eSVladimir Oltean 	.port_lag_change		= felix_lag_change,
226456051948SVladimir Oltean 	.port_stp_state_set		= felix_bridge_stp_state_set,
226556051948SVladimir Oltean 	.port_vlan_filtering		= felix_vlan_filtering,
226656051948SVladimir Oltean 	.port_vlan_add			= felix_vlan_add,
226756051948SVladimir Oltean 	.port_vlan_del			= felix_vlan_del,
2268c0bcf537SYangbo Lu 	.port_hwtstamp_get		= felix_hwtstamp_get,
2269c0bcf537SYangbo Lu 	.port_hwtstamp_set		= felix_hwtstamp_set,
2270c0bcf537SYangbo Lu 	.port_rxtstamp			= felix_rxtstamp,
2271c0bcf537SYangbo Lu 	.port_txtstamp			= felix_txtstamp,
22720b912fc9SVladimir Oltean 	.port_change_mtu		= felix_change_mtu,
22730b912fc9SVladimir Oltean 	.port_max_mtu			= felix_get_max_mtu,
2274fc411eaaSVladimir Oltean 	.port_policer_add		= felix_port_policer_add,
2275fc411eaaSVladimir Oltean 	.port_policer_del		= felix_port_policer_del,
22765e497497SVladimir Oltean 	.port_mirror_add		= felix_port_mirror_add,
22775e497497SVladimir Oltean 	.port_mirror_del		= felix_port_mirror_del,
227807d985eeSVladimir Oltean 	.cls_flower_add			= felix_cls_flower_add,
227907d985eeSVladimir Oltean 	.cls_flower_del			= felix_cls_flower_del,
228007d985eeSVladimir Oltean 	.cls_flower_stats		= felix_cls_flower_stats,
2281de143c0eSXiaoliang Yang 	.port_setup_tc			= felix_port_setup_tc,
2282f59fd9caSVladimir Oltean 	.devlink_sb_pool_get		= felix_sb_pool_get,
2283f59fd9caSVladimir Oltean 	.devlink_sb_pool_set		= felix_sb_pool_set,
2284f59fd9caSVladimir Oltean 	.devlink_sb_port_pool_get	= felix_sb_port_pool_get,
2285f59fd9caSVladimir Oltean 	.devlink_sb_port_pool_set	= felix_sb_port_pool_set,
2286f59fd9caSVladimir Oltean 	.devlink_sb_tc_pool_bind_get	= felix_sb_tc_pool_bind_get,
2287f59fd9caSVladimir Oltean 	.devlink_sb_tc_pool_bind_set	= felix_sb_tc_pool_bind_set,
2288f59fd9caSVladimir Oltean 	.devlink_sb_occ_snapshot	= felix_sb_occ_snapshot,
2289f59fd9caSVladimir Oltean 	.devlink_sb_occ_max_clear	= felix_sb_occ_max_clear,
2290f59fd9caSVladimir Oltean 	.devlink_sb_occ_port_pool_get	= felix_sb_occ_port_pool_get,
2291f59fd9caSVladimir Oltean 	.devlink_sb_occ_tc_port_bind_get= felix_sb_occ_tc_port_bind_get,
2292a026c50bSHoratiu Vultur 	.port_mrp_add			= felix_mrp_add,
2293a026c50bSHoratiu Vultur 	.port_mrp_del			= felix_mrp_del,
2294a026c50bSHoratiu Vultur 	.port_mrp_add_ring_role		= felix_mrp_add_ring_role,
2295a026c50bSHoratiu Vultur 	.port_mrp_del_ring_role		= felix_mrp_del_ring_role,
22965da11eb4SVladimir Oltean 	.tag_8021q_vlan_add		= felix_tag_8021q_vlan_add,
22975da11eb4SVladimir Oltean 	.tag_8021q_vlan_del		= felix_tag_8021q_vlan_del,
2298978777d0SVladimir Oltean 	.port_get_default_prio		= felix_port_get_default_prio,
2299978777d0SVladimir Oltean 	.port_set_default_prio		= felix_port_set_default_prio,
2300978777d0SVladimir Oltean 	.port_get_dscp_prio		= felix_port_get_dscp_prio,
2301978777d0SVladimir Oltean 	.port_add_dscp_prio		= felix_port_add_dscp_prio,
2302978777d0SVladimir Oltean 	.port_del_dscp_prio		= felix_port_del_dscp_prio,
230372c3b0c7SVladimir Oltean 	.port_set_host_flood		= felix_port_set_host_flood,
23046ca80638SFlorian Fainelli 	.port_change_conduit		= felix_port_change_conduit,
230556051948SVladimir Oltean };
2306319e4dd1SVladimir Oltean 
felix_register_switch(struct device * dev,resource_size_t switch_base,int num_flooding_pgids,bool ptp,bool mm_supported,enum dsa_tag_protocol init_tag_proto,const struct felix_info * info)2307efdbee7dSVladimir Oltean int felix_register_switch(struct device *dev, resource_size_t switch_base,
2308efdbee7dSVladimir Oltean 			  int num_flooding_pgids, bool ptp,
2309efdbee7dSVladimir Oltean 			  bool mm_supported,
2310efdbee7dSVladimir Oltean 			  enum dsa_tag_protocol init_tag_proto,
2311efdbee7dSVladimir Oltean 			  const struct felix_info *info)
2312efdbee7dSVladimir Oltean {
2313efdbee7dSVladimir Oltean 	struct dsa_switch *ds;
2314efdbee7dSVladimir Oltean 	struct ocelot *ocelot;
2315efdbee7dSVladimir Oltean 	struct felix *felix;
2316efdbee7dSVladimir Oltean 	int err;
2317efdbee7dSVladimir Oltean 
2318efdbee7dSVladimir Oltean 	felix = devm_kzalloc(dev, sizeof(*felix), GFP_KERNEL);
2319efdbee7dSVladimir Oltean 	if (!felix)
2320efdbee7dSVladimir Oltean 		return -ENOMEM;
2321efdbee7dSVladimir Oltean 
2322efdbee7dSVladimir Oltean 	ds = devm_kzalloc(dev, sizeof(*ds), GFP_KERNEL);
2323efdbee7dSVladimir Oltean 	if (!ds)
2324efdbee7dSVladimir Oltean 		return -ENOMEM;
2325efdbee7dSVladimir Oltean 
2326efdbee7dSVladimir Oltean 	dev_set_drvdata(dev, felix);
2327efdbee7dSVladimir Oltean 
2328efdbee7dSVladimir Oltean 	ocelot = &felix->ocelot;
2329efdbee7dSVladimir Oltean 	ocelot->dev = dev;
2330efdbee7dSVladimir Oltean 	ocelot->num_flooding_pgids = num_flooding_pgids;
2331efdbee7dSVladimir Oltean 	ocelot->ptp = ptp;
2332efdbee7dSVladimir Oltean 	ocelot->mm_supported = mm_supported;
2333efdbee7dSVladimir Oltean 
2334efdbee7dSVladimir Oltean 	felix->info = info;
2335efdbee7dSVladimir Oltean 	felix->switch_base = switch_base;
2336efdbee7dSVladimir Oltean 	felix->ds = ds;
2337efdbee7dSVladimir Oltean 	felix->tag_proto = init_tag_proto;
2338efdbee7dSVladimir Oltean 
2339efdbee7dSVladimir Oltean 	ds->dev = dev;
2340efdbee7dSVladimir Oltean 	ds->num_ports = info->num_ports;
2341efdbee7dSVladimir Oltean 	ds->num_tx_queues = OCELOT_NUM_TC;
2342efdbee7dSVladimir Oltean 	ds->ops = &felix_switch_ops;
2343efdbee7dSVladimir Oltean 	ds->phylink_mac_ops = &felix_phylink_mac_ops;
2344efdbee7dSVladimir Oltean 	ds->priv = ocelot;
2345efdbee7dSVladimir Oltean 
2346efdbee7dSVladimir Oltean 	err = dsa_register_switch(ds);
2347efdbee7dSVladimir Oltean 	if (err)
2348efdbee7dSVladimir Oltean 		dev_err_probe(dev, err, "Failed to register DSA switch\n");
2349efdbee7dSVladimir Oltean 
2350efdbee7dSVladimir Oltean 	return err;
2351efdbee7dSVladimir Oltean }
2352efdbee7dSVladimir Oltean EXPORT_SYMBOL_GPL(felix_register_switch);
2353efdbee7dSVladimir Oltean 
felix_port_to_netdev(struct ocelot * ocelot,int port)2354319e4dd1SVladimir Oltean struct net_device *felix_port_to_netdev(struct ocelot *ocelot, int port)
2355319e4dd1SVladimir Oltean {
2356319e4dd1SVladimir Oltean 	struct felix *felix = ocelot_to_felix(ocelot);
2357319e4dd1SVladimir Oltean 	struct dsa_switch *ds = felix->ds;
2358319e4dd1SVladimir Oltean 
2359319e4dd1SVladimir Oltean 	if (!dsa_is_user_port(ds, port))
2360319e4dd1SVladimir Oltean 		return NULL;
2361319e4dd1SVladimir Oltean 
23626ca80638SFlorian Fainelli 	return dsa_to_port(ds, port)->user;
2363319e4dd1SVladimir Oltean }
2364c8005511SVladimir Oltean EXPORT_SYMBOL_GPL(felix_port_to_netdev);
2365319e4dd1SVladimir Oltean 
felix_netdev_to_port(struct net_device * dev)2366319e4dd1SVladimir Oltean int felix_netdev_to_port(struct net_device *dev)
2367319e4dd1SVladimir Oltean {
2368319e4dd1SVladimir Oltean 	struct dsa_port *dp;
2369319e4dd1SVladimir Oltean 
2370319e4dd1SVladimir Oltean 	dp = dsa_port_from_netdev(dev);
2371319e4dd1SVladimir Oltean 	if (IS_ERR(dp))
2372319e4dd1SVladimir Oltean 		return -EINVAL;
2373319e4dd1SVladimir Oltean 
2374319e4dd1SVladimir Oltean 	return dp->index;
2375319e4dd1SVladimir Oltean }
2376c8005511SVladimir Oltean EXPORT_SYMBOL_GPL(felix_netdev_to_port);
2377c8005511SVladimir Oltean 
2378c8005511SVladimir Oltean MODULE_DESCRIPTION("Felix DSA library");
2379c8005511SVladimir Oltean MODULE_LICENSE("GPL");
2380