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