xref: /openbmc/linux/drivers/net/dsa/ocelot/felix.c (revision adb3dccf090bc53ce177cd30bbe5b985336a6f66)
156051948SVladimir Oltean // SPDX-License-Identifier: GPL-2.0
2*adb3dccfSVladimir Oltean /* Copyright 2019-2021 NXP Semiconductors
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>
1684705fc1SMaxim Kochetkov #include <linux/platform_device.h>
17c0bcf537SYangbo Lu #include <linux/packing.h>
1856051948SVladimir Oltean #include <linux/module.h>
19bdeced75SVladimir Oltean #include <linux/of_net.h>
2056051948SVladimir Oltean #include <linux/pci.h>
2156051948SVladimir Oltean #include <linux/of.h>
22588d0550SIoana Ciornei #include <linux/pcs-lynx.h>
23fc411eaaSVladimir Oltean #include <net/pkt_sched.h>
2456051948SVladimir Oltean #include <net/dsa.h>
2556051948SVladimir Oltean #include "felix.h"
2656051948SVladimir Oltean 
27*adb3dccfSVladimir Oltean /* The CPU port module is connected to the Node Processor Interface (NPI). This
28*adb3dccfSVladimir Oltean  * is the mode through which frames can be injected from and extracted to an
29*adb3dccfSVladimir Oltean  * external CPU, over Ethernet. In NXP SoCs, the "external CPU" is the ARM CPU
30*adb3dccfSVladimir Oltean  * running Linux, and this forms a DSA setup together with the enetc or fman
31*adb3dccfSVladimir Oltean  * DSA master.
32*adb3dccfSVladimir Oltean  */
33*adb3dccfSVladimir Oltean static void felix_npi_port_init(struct ocelot *ocelot, int port)
34*adb3dccfSVladimir Oltean {
35*adb3dccfSVladimir Oltean 	ocelot->npi = port;
36*adb3dccfSVladimir Oltean 
37*adb3dccfSVladimir Oltean 	ocelot_write(ocelot, QSYS_EXT_CPU_CFG_EXT_CPUQ_MSK_M |
38*adb3dccfSVladimir Oltean 		     QSYS_EXT_CPU_CFG_EXT_CPU_PORT(port),
39*adb3dccfSVladimir Oltean 		     QSYS_EXT_CPU_CFG);
40*adb3dccfSVladimir Oltean 
41*adb3dccfSVladimir Oltean 	/* NPI port Injection/Extraction configuration */
42*adb3dccfSVladimir Oltean 	ocelot_fields_write(ocelot, port, SYS_PORT_MODE_INCL_XTR_HDR,
43*adb3dccfSVladimir Oltean 			    ocelot->npi_xtr_prefix);
44*adb3dccfSVladimir Oltean 	ocelot_fields_write(ocelot, port, SYS_PORT_MODE_INCL_INJ_HDR,
45*adb3dccfSVladimir Oltean 			    ocelot->npi_inj_prefix);
46*adb3dccfSVladimir Oltean 
47*adb3dccfSVladimir Oltean 	/* Disable transmission of pause frames */
48*adb3dccfSVladimir Oltean 	ocelot_fields_write(ocelot, port, SYS_PAUSE_CFG_PAUSE_ENA, 0);
49*adb3dccfSVladimir Oltean }
50*adb3dccfSVladimir Oltean 
51*adb3dccfSVladimir Oltean static void felix_npi_port_deinit(struct ocelot *ocelot, int port)
52*adb3dccfSVladimir Oltean {
53*adb3dccfSVladimir Oltean 	/* Restore hardware defaults */
54*adb3dccfSVladimir Oltean 	int unused_port = ocelot->num_phys_ports + 2;
55*adb3dccfSVladimir Oltean 
56*adb3dccfSVladimir Oltean 	ocelot->npi = -1;
57*adb3dccfSVladimir Oltean 
58*adb3dccfSVladimir Oltean 	ocelot_write(ocelot, QSYS_EXT_CPU_CFG_EXT_CPU_PORT(unused_port),
59*adb3dccfSVladimir Oltean 		     QSYS_EXT_CPU_CFG);
60*adb3dccfSVladimir Oltean 
61*adb3dccfSVladimir Oltean 	ocelot_fields_write(ocelot, port, SYS_PORT_MODE_INCL_XTR_HDR,
62*adb3dccfSVladimir Oltean 			    OCELOT_TAG_PREFIX_DISABLED);
63*adb3dccfSVladimir Oltean 	ocelot_fields_write(ocelot, port, SYS_PORT_MODE_INCL_INJ_HDR,
64*adb3dccfSVladimir Oltean 			    OCELOT_TAG_PREFIX_DISABLED);
65*adb3dccfSVladimir Oltean 
66*adb3dccfSVladimir Oltean 	/* Enable transmission of pause frames */
67*adb3dccfSVladimir Oltean 	ocelot_fields_write(ocelot, port, SYS_PAUSE_CFG_PAUSE_ENA, 1);
68*adb3dccfSVladimir Oltean }
69*adb3dccfSVladimir Oltean 
70*adb3dccfSVladimir Oltean static int felix_setup_tag_npi(struct dsa_switch *ds, int cpu)
71*adb3dccfSVladimir Oltean {
72*adb3dccfSVladimir Oltean 	struct ocelot *ocelot = ds->priv;
73*adb3dccfSVladimir Oltean 	unsigned long cpu_flood;
74*adb3dccfSVladimir Oltean 
75*adb3dccfSVladimir Oltean 	felix_npi_port_init(ocelot, cpu);
76*adb3dccfSVladimir Oltean 
77*adb3dccfSVladimir Oltean 	/* Include the CPU port module (and indirectly, the NPI port)
78*adb3dccfSVladimir Oltean 	 * in the forwarding mask for unknown unicast - the hardware
79*adb3dccfSVladimir Oltean 	 * default value for ANA_FLOODING_FLD_UNICAST excludes
80*adb3dccfSVladimir Oltean 	 * BIT(ocelot->num_phys_ports), and so does ocelot_init,
81*adb3dccfSVladimir Oltean 	 * since Ocelot relies on whitelisting MAC addresses towards
82*adb3dccfSVladimir Oltean 	 * PGID_CPU.
83*adb3dccfSVladimir Oltean 	 * We do this because DSA does not yet perform RX filtering,
84*adb3dccfSVladimir Oltean 	 * and the NPI port does not perform source address learning,
85*adb3dccfSVladimir Oltean 	 * so traffic sent to Linux is effectively unknown from the
86*adb3dccfSVladimir Oltean 	 * switch's perspective.
87*adb3dccfSVladimir Oltean 	 */
88*adb3dccfSVladimir Oltean 	cpu_flood = ANA_PGID_PGID_PGID(BIT(ocelot->num_phys_ports));
89*adb3dccfSVladimir Oltean 	ocelot_rmw_rix(ocelot, cpu_flood, cpu_flood, ANA_PGID_PGID, PGID_UC);
90*adb3dccfSVladimir Oltean 
91*adb3dccfSVladimir Oltean 	return 0;
92*adb3dccfSVladimir Oltean }
93*adb3dccfSVladimir Oltean 
94*adb3dccfSVladimir Oltean static void felix_teardown_tag_npi(struct dsa_switch *ds, int cpu)
95*adb3dccfSVladimir Oltean {
96*adb3dccfSVladimir Oltean 	struct ocelot *ocelot = ds->priv;
97*adb3dccfSVladimir Oltean 
98*adb3dccfSVladimir Oltean 	felix_npi_port_deinit(ocelot, cpu);
99*adb3dccfSVladimir Oltean }
100*adb3dccfSVladimir Oltean 
101*adb3dccfSVladimir Oltean static int felix_set_tag_protocol(struct dsa_switch *ds, int cpu,
102*adb3dccfSVladimir Oltean 				  enum dsa_tag_protocol proto)
103*adb3dccfSVladimir Oltean {
104*adb3dccfSVladimir Oltean 	int err;
105*adb3dccfSVladimir Oltean 
106*adb3dccfSVladimir Oltean 	switch (proto) {
107*adb3dccfSVladimir Oltean 	case DSA_TAG_PROTO_OCELOT:
108*adb3dccfSVladimir Oltean 		err = felix_setup_tag_npi(ds, cpu);
109*adb3dccfSVladimir Oltean 		break;
110*adb3dccfSVladimir Oltean 	default:
111*adb3dccfSVladimir Oltean 		err = -EPROTONOSUPPORT;
112*adb3dccfSVladimir Oltean 	}
113*adb3dccfSVladimir Oltean 
114*adb3dccfSVladimir Oltean 	return err;
115*adb3dccfSVladimir Oltean }
116*adb3dccfSVladimir Oltean 
117*adb3dccfSVladimir Oltean static void felix_del_tag_protocol(struct dsa_switch *ds, int cpu,
118*adb3dccfSVladimir Oltean 				   enum dsa_tag_protocol proto)
119*adb3dccfSVladimir Oltean {
120*adb3dccfSVladimir Oltean 	switch (proto) {
121*adb3dccfSVladimir Oltean 	case DSA_TAG_PROTO_OCELOT:
122*adb3dccfSVladimir Oltean 		felix_teardown_tag_npi(ds, cpu);
123*adb3dccfSVladimir Oltean 		break;
124*adb3dccfSVladimir Oltean 	default:
125*adb3dccfSVladimir Oltean 		break;
126*adb3dccfSVladimir Oltean 	}
127*adb3dccfSVladimir Oltean }
128*adb3dccfSVladimir Oltean 
129*adb3dccfSVladimir Oltean static int felix_change_tag_protocol(struct dsa_switch *ds, int cpu,
130*adb3dccfSVladimir Oltean 				     enum dsa_tag_protocol proto)
131*adb3dccfSVladimir Oltean {
132*adb3dccfSVladimir Oltean 	struct ocelot *ocelot = ds->priv;
133*adb3dccfSVladimir Oltean 	struct felix *felix = ocelot_to_felix(ocelot);
134*adb3dccfSVladimir Oltean 	enum dsa_tag_protocol old_proto = felix->tag_proto;
135*adb3dccfSVladimir Oltean 	int err;
136*adb3dccfSVladimir Oltean 
137*adb3dccfSVladimir Oltean 	if (proto != DSA_TAG_PROTO_OCELOT)
138*adb3dccfSVladimir Oltean 		return -EPROTONOSUPPORT;
139*adb3dccfSVladimir Oltean 
140*adb3dccfSVladimir Oltean 	felix_del_tag_protocol(ds, cpu, old_proto);
141*adb3dccfSVladimir Oltean 
142*adb3dccfSVladimir Oltean 	err = felix_set_tag_protocol(ds, cpu, proto);
143*adb3dccfSVladimir Oltean 	if (err) {
144*adb3dccfSVladimir Oltean 		felix_set_tag_protocol(ds, cpu, old_proto);
145*adb3dccfSVladimir Oltean 		return err;
146*adb3dccfSVladimir Oltean 	}
147*adb3dccfSVladimir Oltean 
148*adb3dccfSVladimir Oltean 	felix->tag_proto = proto;
149*adb3dccfSVladimir Oltean 
150*adb3dccfSVladimir Oltean 	return 0;
151*adb3dccfSVladimir Oltean }
152*adb3dccfSVladimir Oltean 
15356051948SVladimir Oltean static enum dsa_tag_protocol felix_get_tag_protocol(struct dsa_switch *ds,
1544d776482SFlorian Fainelli 						    int port,
1554d776482SFlorian Fainelli 						    enum dsa_tag_protocol mp)
15656051948SVladimir Oltean {
157*adb3dccfSVladimir Oltean 	struct ocelot *ocelot = ds->priv;
158*adb3dccfSVladimir Oltean 	struct felix *felix = ocelot_to_felix(ocelot);
159*adb3dccfSVladimir Oltean 
160*adb3dccfSVladimir Oltean 	return felix->tag_proto;
16156051948SVladimir Oltean }
16256051948SVladimir Oltean 
16356051948SVladimir Oltean static int felix_set_ageing_time(struct dsa_switch *ds,
16456051948SVladimir Oltean 				 unsigned int ageing_time)
16556051948SVladimir Oltean {
16656051948SVladimir Oltean 	struct ocelot *ocelot = ds->priv;
16756051948SVladimir Oltean 
16856051948SVladimir Oltean 	ocelot_set_ageing_time(ocelot, ageing_time);
16956051948SVladimir Oltean 
17056051948SVladimir Oltean 	return 0;
17156051948SVladimir Oltean }
17256051948SVladimir Oltean 
17356051948SVladimir Oltean static int felix_fdb_dump(struct dsa_switch *ds, int port,
17456051948SVladimir Oltean 			  dsa_fdb_dump_cb_t *cb, void *data)
17556051948SVladimir Oltean {
17656051948SVladimir Oltean 	struct ocelot *ocelot = ds->priv;
17756051948SVladimir Oltean 
17856051948SVladimir Oltean 	return ocelot_fdb_dump(ocelot, port, cb, data);
17956051948SVladimir Oltean }
18056051948SVladimir Oltean 
18156051948SVladimir Oltean static int felix_fdb_add(struct dsa_switch *ds, int port,
18256051948SVladimir Oltean 			 const unsigned char *addr, u16 vid)
18356051948SVladimir Oltean {
18456051948SVladimir Oltean 	struct ocelot *ocelot = ds->priv;
18556051948SVladimir Oltean 
18687b0f983SVladimir Oltean 	return ocelot_fdb_add(ocelot, port, addr, vid);
18756051948SVladimir Oltean }
18856051948SVladimir Oltean 
18956051948SVladimir Oltean static int felix_fdb_del(struct dsa_switch *ds, int port,
19056051948SVladimir Oltean 			 const unsigned char *addr, u16 vid)
19156051948SVladimir Oltean {
19256051948SVladimir Oltean 	struct ocelot *ocelot = ds->priv;
19356051948SVladimir Oltean 
19456051948SVladimir Oltean 	return ocelot_fdb_del(ocelot, port, addr, vid);
19556051948SVladimir Oltean }
19656051948SVladimir Oltean 
197a52b2da7SVladimir Oltean static int felix_mdb_add(struct dsa_switch *ds, int port,
198209edf95SVladimir Oltean 			 const struct switchdev_obj_port_mdb *mdb)
199209edf95SVladimir Oltean {
200209edf95SVladimir Oltean 	struct ocelot *ocelot = ds->priv;
201209edf95SVladimir Oltean 
202a52b2da7SVladimir Oltean 	return ocelot_port_mdb_add(ocelot, port, mdb);
203209edf95SVladimir Oltean }
204209edf95SVladimir Oltean 
205209edf95SVladimir Oltean static int felix_mdb_del(struct dsa_switch *ds, int port,
206209edf95SVladimir Oltean 			 const struct switchdev_obj_port_mdb *mdb)
207209edf95SVladimir Oltean {
208209edf95SVladimir Oltean 	struct ocelot *ocelot = ds->priv;
209209edf95SVladimir Oltean 
210209edf95SVladimir Oltean 	return ocelot_port_mdb_del(ocelot, port, mdb);
211209edf95SVladimir Oltean }
212209edf95SVladimir Oltean 
21356051948SVladimir Oltean static void felix_bridge_stp_state_set(struct dsa_switch *ds, int port,
21456051948SVladimir Oltean 				       u8 state)
21556051948SVladimir Oltean {
21656051948SVladimir Oltean 	struct ocelot *ocelot = ds->priv;
21756051948SVladimir Oltean 
21856051948SVladimir Oltean 	return ocelot_bridge_stp_state_set(ocelot, port, state);
21956051948SVladimir Oltean }
22056051948SVladimir Oltean 
22156051948SVladimir Oltean static int felix_bridge_join(struct dsa_switch *ds, int port,
22256051948SVladimir Oltean 			     struct net_device *br)
22356051948SVladimir Oltean {
22456051948SVladimir Oltean 	struct ocelot *ocelot = ds->priv;
22556051948SVladimir Oltean 
22656051948SVladimir Oltean 	return ocelot_port_bridge_join(ocelot, port, br);
22756051948SVladimir Oltean }
22856051948SVladimir Oltean 
22956051948SVladimir Oltean static void felix_bridge_leave(struct dsa_switch *ds, int port,
23056051948SVladimir Oltean 			       struct net_device *br)
23156051948SVladimir Oltean {
23256051948SVladimir Oltean 	struct ocelot *ocelot = ds->priv;
23356051948SVladimir Oltean 
23456051948SVladimir Oltean 	ocelot_port_bridge_leave(ocelot, port, br);
23556051948SVladimir Oltean }
23656051948SVladimir Oltean 
23756051948SVladimir Oltean static int felix_vlan_prepare(struct dsa_switch *ds, int port,
23856051948SVladimir Oltean 			      const struct switchdev_obj_port_vlan *vlan)
23956051948SVladimir Oltean {
2402f0402feSVladimir Oltean 	struct ocelot *ocelot = ds->priv;
241b7a9e0daSVladimir Oltean 	u16 flags = vlan->flags;
2422f0402feSVladimir Oltean 
2439a720680SVladimir Oltean 	/* Ocelot switches copy frames as-is to the CPU, so the flags:
2449a720680SVladimir Oltean 	 * egress-untagged or not, pvid or not, make no difference. This
2459a720680SVladimir Oltean 	 * behavior is already better than what DSA just tries to approximate
2469a720680SVladimir Oltean 	 * when it installs the VLAN with the same flags on the CPU port.
2479a720680SVladimir Oltean 	 * Just accept any configuration, and don't let ocelot deny installing
2489a720680SVladimir Oltean 	 * multiple native VLANs on the NPI port, because the switch doesn't
2499a720680SVladimir Oltean 	 * look at the port tag settings towards the NPI interface anyway.
2509a720680SVladimir Oltean 	 */
2519a720680SVladimir Oltean 	if (port == ocelot->npi)
2529a720680SVladimir Oltean 		return 0;
2539a720680SVladimir Oltean 
254b7a9e0daSVladimir Oltean 	return ocelot_vlan_prepare(ocelot, port, vlan->vid,
2552f0402feSVladimir Oltean 				   flags & BRIDGE_VLAN_INFO_PVID,
2562f0402feSVladimir Oltean 				   flags & BRIDGE_VLAN_INFO_UNTAGGED);
25756051948SVladimir Oltean }
25856051948SVladimir Oltean 
259bae33f2bSVladimir Oltean static int felix_vlan_filtering(struct dsa_switch *ds, int port, bool enabled)
26056051948SVladimir Oltean {
26156051948SVladimir Oltean 	struct ocelot *ocelot = ds->priv;
26256051948SVladimir Oltean 
263bae33f2bSVladimir Oltean 	return ocelot_port_vlan_filtering(ocelot, port, enabled);
26456051948SVladimir Oltean }
26556051948SVladimir Oltean 
2661958d581SVladimir Oltean static int felix_vlan_add(struct dsa_switch *ds, int port,
26756051948SVladimir Oltean 			  const struct switchdev_obj_port_vlan *vlan)
26856051948SVladimir Oltean {
26956051948SVladimir Oltean 	struct ocelot *ocelot = ds->priv;
270183be6f9SVladimir Oltean 	u16 flags = vlan->flags;
2711958d581SVladimir Oltean 	int err;
27256051948SVladimir Oltean 
2731958d581SVladimir Oltean 	err = felix_vlan_prepare(ds, port, vlan);
2741958d581SVladimir Oltean 	if (err)
2751958d581SVladimir Oltean 		return err;
2761958d581SVladimir Oltean 
2771958d581SVladimir Oltean 	return ocelot_vlan_add(ocelot, port, vlan->vid,
278183be6f9SVladimir Oltean 			       flags & BRIDGE_VLAN_INFO_PVID,
279183be6f9SVladimir Oltean 			       flags & BRIDGE_VLAN_INFO_UNTAGGED);
28056051948SVladimir Oltean }
28156051948SVladimir Oltean 
28256051948SVladimir Oltean static int felix_vlan_del(struct dsa_switch *ds, int port,
28356051948SVladimir Oltean 			  const struct switchdev_obj_port_vlan *vlan)
28456051948SVladimir Oltean {
28556051948SVladimir Oltean 	struct ocelot *ocelot = ds->priv;
28656051948SVladimir Oltean 
287b7a9e0daSVladimir Oltean 	return ocelot_vlan_del(ocelot, port, vlan->vid);
28856051948SVladimir Oltean }
28956051948SVladimir Oltean 
29056051948SVladimir Oltean static int felix_port_enable(struct dsa_switch *ds, int port,
29156051948SVladimir Oltean 			     struct phy_device *phy)
29256051948SVladimir Oltean {
29356051948SVladimir Oltean 	struct ocelot *ocelot = ds->priv;
29456051948SVladimir Oltean 
29556051948SVladimir Oltean 	ocelot_port_enable(ocelot, port, phy);
29656051948SVladimir Oltean 
29756051948SVladimir Oltean 	return 0;
29856051948SVladimir Oltean }
29956051948SVladimir Oltean 
30056051948SVladimir Oltean static void felix_port_disable(struct dsa_switch *ds, int port)
30156051948SVladimir Oltean {
30256051948SVladimir Oltean 	struct ocelot *ocelot = ds->priv;
30356051948SVladimir Oltean 
30456051948SVladimir Oltean 	return ocelot_port_disable(ocelot, port);
30556051948SVladimir Oltean }
30656051948SVladimir Oltean 
307bdeced75SVladimir Oltean static void felix_phylink_validate(struct dsa_switch *ds, int port,
308bdeced75SVladimir Oltean 				   unsigned long *supported,
309bdeced75SVladimir Oltean 				   struct phylink_link_state *state)
310bdeced75SVladimir Oltean {
311bdeced75SVladimir Oltean 	struct ocelot *ocelot = ds->priv;
312375e1314SVladimir Oltean 	struct felix *felix = ocelot_to_felix(ocelot);
313bdeced75SVladimir Oltean 
314375e1314SVladimir Oltean 	if (felix->info->phylink_validate)
315375e1314SVladimir Oltean 		felix->info->phylink_validate(ocelot, port, supported, state);
316bdeced75SVladimir Oltean }
317bdeced75SVladimir Oltean 
318bdeced75SVladimir Oltean static void felix_phylink_mac_config(struct dsa_switch *ds, int port,
319bdeced75SVladimir Oltean 				     unsigned int link_an_mode,
320bdeced75SVladimir Oltean 				     const struct phylink_link_state *state)
321bdeced75SVladimir Oltean {
322bdeced75SVladimir Oltean 	struct ocelot *ocelot = ds->priv;
323bdeced75SVladimir Oltean 	struct felix *felix = ocelot_to_felix(ocelot);
324588d0550SIoana Ciornei 	struct dsa_port *dp = dsa_to_port(ds, port);
325bdeced75SVladimir Oltean 
326588d0550SIoana Ciornei 	if (felix->pcs[port])
327588d0550SIoana Ciornei 		phylink_set_pcs(dp->pl, &felix->pcs[port]->pcs);
328bdeced75SVladimir Oltean }
329bdeced75SVladimir Oltean 
330bdeced75SVladimir Oltean static void felix_phylink_mac_link_down(struct dsa_switch *ds, int port,
331bdeced75SVladimir Oltean 					unsigned int link_an_mode,
332bdeced75SVladimir Oltean 					phy_interface_t interface)
333bdeced75SVladimir Oltean {
334bdeced75SVladimir Oltean 	struct ocelot *ocelot = ds->priv;
335bdeced75SVladimir Oltean 	struct ocelot_port *ocelot_port = ocelot->ports[port];
336bdeced75SVladimir Oltean 
337bdeced75SVladimir Oltean 	ocelot_port_writel(ocelot_port, 0, DEV_MAC_ENA_CFG);
338886e1387SVladimir Oltean 	ocelot_fields_write(ocelot, port, QSYS_SWITCH_PORT_MODE_PORT_ENA, 0);
339bdeced75SVladimir Oltean }
340bdeced75SVladimir Oltean 
341bdeced75SVladimir Oltean static void felix_phylink_mac_link_up(struct dsa_switch *ds, int port,
342bdeced75SVladimir Oltean 				      unsigned int link_an_mode,
343bdeced75SVladimir Oltean 				      phy_interface_t interface,
3445b502a7bSRussell King 				      struct phy_device *phydev,
3455b502a7bSRussell King 				      int speed, int duplex,
3465b502a7bSRussell King 				      bool tx_pause, bool rx_pause)
347bdeced75SVladimir Oltean {
348bdeced75SVladimir Oltean 	struct ocelot *ocelot = ds->priv;
349bdeced75SVladimir Oltean 	struct ocelot_port *ocelot_port = ocelot->ports[port];
3507e14a2dcSVladimir Oltean 	struct felix *felix = ocelot_to_felix(ocelot);
3517e14a2dcSVladimir Oltean 	u32 mac_fc_cfg;
352bdeced75SVladimir Oltean 
3537e14a2dcSVladimir Oltean 	/* Take port out of reset by clearing the MAC_TX_RST, MAC_RX_RST and
3547e14a2dcSVladimir Oltean 	 * PORT_RST bits in DEV_CLOCK_CFG. Note that the way this system is
3557e14a2dcSVladimir Oltean 	 * integrated is that the MAC speed is fixed and it's the PCS who is
3567e14a2dcSVladimir Oltean 	 * performing the rate adaptation, so we have to write "1000Mbps" into
3577e14a2dcSVladimir Oltean 	 * the LINK_SPEED field of DEV_CLOCK_CFG (which is also its default
3587e14a2dcSVladimir Oltean 	 * value).
3597e14a2dcSVladimir Oltean 	 */
3607e14a2dcSVladimir Oltean 	ocelot_port_writel(ocelot_port,
3617e14a2dcSVladimir Oltean 			   DEV_CLOCK_CFG_LINK_SPEED(OCELOT_SPEED_1000),
3627e14a2dcSVladimir Oltean 			   DEV_CLOCK_CFG);
3637e14a2dcSVladimir Oltean 
3647e14a2dcSVladimir Oltean 	switch (speed) {
3657e14a2dcSVladimir Oltean 	case SPEED_10:
3667e14a2dcSVladimir Oltean 		mac_fc_cfg = SYS_MAC_FC_CFG_FC_LINK_SPEED(3);
3677e14a2dcSVladimir Oltean 		break;
3687e14a2dcSVladimir Oltean 	case SPEED_100:
3697e14a2dcSVladimir Oltean 		mac_fc_cfg = SYS_MAC_FC_CFG_FC_LINK_SPEED(2);
3707e14a2dcSVladimir Oltean 		break;
3717e14a2dcSVladimir Oltean 	case SPEED_1000:
3727e14a2dcSVladimir Oltean 	case SPEED_2500:
3737e14a2dcSVladimir Oltean 		mac_fc_cfg = SYS_MAC_FC_CFG_FC_LINK_SPEED(1);
3747e14a2dcSVladimir Oltean 		break;
3757e14a2dcSVladimir Oltean 	default:
3767e14a2dcSVladimir Oltean 		dev_err(ocelot->dev, "Unsupported speed on port %d: %d\n",
3777e14a2dcSVladimir Oltean 			port, speed);
3787e14a2dcSVladimir Oltean 		return;
3797e14a2dcSVladimir Oltean 	}
3807e14a2dcSVladimir Oltean 
3817e14a2dcSVladimir Oltean 	/* handle Rx pause in all cases, with 2500base-X this is used for rate
3827e14a2dcSVladimir Oltean 	 * adaptation.
3837e14a2dcSVladimir Oltean 	 */
3847e14a2dcSVladimir Oltean 	mac_fc_cfg |= SYS_MAC_FC_CFG_RX_FC_ENA;
3857e14a2dcSVladimir Oltean 
3867e14a2dcSVladimir Oltean 	if (tx_pause)
3877e14a2dcSVladimir Oltean 		mac_fc_cfg |= SYS_MAC_FC_CFG_TX_FC_ENA |
3887e14a2dcSVladimir Oltean 			      SYS_MAC_FC_CFG_PAUSE_VAL_CFG(0xffff) |
3897e14a2dcSVladimir Oltean 			      SYS_MAC_FC_CFG_FC_LATENCY_CFG(0x7) |
3907e14a2dcSVladimir Oltean 			      SYS_MAC_FC_CFG_ZERO_PAUSE_ENA;
3917e14a2dcSVladimir Oltean 
3927e14a2dcSVladimir Oltean 	/* Flow control. Link speed is only used here to evaluate the time
3937e14a2dcSVladimir Oltean 	 * specification in incoming pause frames.
3947e14a2dcSVladimir Oltean 	 */
3957e14a2dcSVladimir Oltean 	ocelot_write_rix(ocelot, mac_fc_cfg, SYS_MAC_FC_CFG, port);
3967e14a2dcSVladimir Oltean 
3977e14a2dcSVladimir Oltean 	ocelot_write_rix(ocelot, 0, ANA_POL_FLOWC, port);
3987e14a2dcSVladimir Oltean 
3997e14a2dcSVladimir Oltean 	/* Undo the effects of felix_phylink_mac_link_down:
4007e14a2dcSVladimir Oltean 	 * enable MAC module
4017e14a2dcSVladimir Oltean 	 */
402bdeced75SVladimir Oltean 	ocelot_port_writel(ocelot_port, DEV_MAC_ENA_CFG_RX_ENA |
403bdeced75SVladimir Oltean 			   DEV_MAC_ENA_CFG_TX_ENA, DEV_MAC_ENA_CFG);
404bdeced75SVladimir Oltean 
405bdeced75SVladimir Oltean 	/* Enable receiving frames on the port, and activate auto-learning of
406bdeced75SVladimir Oltean 	 * MAC addresses.
407bdeced75SVladimir Oltean 	 */
408bdeced75SVladimir Oltean 	ocelot_write_gix(ocelot, ANA_PORT_PORT_CFG_LEARNAUTO |
409bdeced75SVladimir Oltean 			 ANA_PORT_PORT_CFG_RECV_ENA |
410bdeced75SVladimir Oltean 			 ANA_PORT_PORT_CFG_PORTID_VAL(port),
411bdeced75SVladimir Oltean 			 ANA_PORT_PORT_CFG, port);
412bdeced75SVladimir Oltean 
413bdeced75SVladimir Oltean 	/* Core: Enable port for frame transfer */
414886e1387SVladimir Oltean 	ocelot_fields_write(ocelot, port,
415886e1387SVladimir Oltean 			    QSYS_SWITCH_PORT_MODE_PORT_ENA, 1);
4167e14a2dcSVladimir Oltean 
4177e14a2dcSVladimir Oltean 	if (felix->info->port_sched_speed_set)
4187e14a2dcSVladimir Oltean 		felix->info->port_sched_speed_set(ocelot, port, speed);
419bdeced75SVladimir Oltean }
420bdeced75SVladimir Oltean 
421bd2b3161SXiaoliang Yang static void felix_port_qos_map_init(struct ocelot *ocelot, int port)
422bd2b3161SXiaoliang Yang {
423bd2b3161SXiaoliang Yang 	int i;
424bd2b3161SXiaoliang Yang 
425bd2b3161SXiaoliang Yang 	ocelot_rmw_gix(ocelot,
426bd2b3161SXiaoliang Yang 		       ANA_PORT_QOS_CFG_QOS_PCP_ENA,
427bd2b3161SXiaoliang Yang 		       ANA_PORT_QOS_CFG_QOS_PCP_ENA,
428bd2b3161SXiaoliang Yang 		       ANA_PORT_QOS_CFG,
429bd2b3161SXiaoliang Yang 		       port);
430bd2b3161SXiaoliang Yang 
43170d39a6eSVladimir Oltean 	for (i = 0; i < OCELOT_NUM_TC * 2; i++) {
432bd2b3161SXiaoliang Yang 		ocelot_rmw_ix(ocelot,
433bd2b3161SXiaoliang Yang 			      (ANA_PORT_PCP_DEI_MAP_DP_PCP_DEI_VAL & i) |
434bd2b3161SXiaoliang Yang 			      ANA_PORT_PCP_DEI_MAP_QOS_PCP_DEI_VAL(i),
435bd2b3161SXiaoliang Yang 			      ANA_PORT_PCP_DEI_MAP_DP_PCP_DEI_VAL |
436bd2b3161SXiaoliang Yang 			      ANA_PORT_PCP_DEI_MAP_QOS_PCP_DEI_VAL_M,
437bd2b3161SXiaoliang Yang 			      ANA_PORT_PCP_DEI_MAP,
438bd2b3161SXiaoliang Yang 			      port, i);
439bd2b3161SXiaoliang Yang 	}
440bd2b3161SXiaoliang Yang }
441bd2b3161SXiaoliang Yang 
44256051948SVladimir Oltean static void felix_get_strings(struct dsa_switch *ds, int port,
44356051948SVladimir Oltean 			      u32 stringset, u8 *data)
44456051948SVladimir Oltean {
44556051948SVladimir Oltean 	struct ocelot *ocelot = ds->priv;
44656051948SVladimir Oltean 
44756051948SVladimir Oltean 	return ocelot_get_strings(ocelot, port, stringset, data);
44856051948SVladimir Oltean }
44956051948SVladimir Oltean 
45056051948SVladimir Oltean static void felix_get_ethtool_stats(struct dsa_switch *ds, int port, u64 *data)
45156051948SVladimir Oltean {
45256051948SVladimir Oltean 	struct ocelot *ocelot = ds->priv;
45356051948SVladimir Oltean 
45456051948SVladimir Oltean 	ocelot_get_ethtool_stats(ocelot, port, data);
45556051948SVladimir Oltean }
45656051948SVladimir Oltean 
45756051948SVladimir Oltean static int felix_get_sset_count(struct dsa_switch *ds, int port, int sset)
45856051948SVladimir Oltean {
45956051948SVladimir Oltean 	struct ocelot *ocelot = ds->priv;
46056051948SVladimir Oltean 
46156051948SVladimir Oltean 	return ocelot_get_sset_count(ocelot, port, sset);
46256051948SVladimir Oltean }
46356051948SVladimir Oltean 
46456051948SVladimir Oltean static int felix_get_ts_info(struct dsa_switch *ds, int port,
46556051948SVladimir Oltean 			     struct ethtool_ts_info *info)
46656051948SVladimir Oltean {
46756051948SVladimir Oltean 	struct ocelot *ocelot = ds->priv;
46856051948SVladimir Oltean 
46956051948SVladimir Oltean 	return ocelot_get_ts_info(ocelot, port, info);
47056051948SVladimir Oltean }
47156051948SVladimir Oltean 
472bdeced75SVladimir Oltean static int felix_parse_ports_node(struct felix *felix,
473bdeced75SVladimir Oltean 				  struct device_node *ports_node,
474bdeced75SVladimir Oltean 				  phy_interface_t *port_phy_modes)
475bdeced75SVladimir Oltean {
476bdeced75SVladimir Oltean 	struct ocelot *ocelot = &felix->ocelot;
477bdeced75SVladimir Oltean 	struct device *dev = felix->ocelot.dev;
478bdeced75SVladimir Oltean 	struct device_node *child;
479bdeced75SVladimir Oltean 
48037fe45adSVladimir Oltean 	for_each_available_child_of_node(ports_node, child) {
481bdeced75SVladimir Oltean 		phy_interface_t phy_mode;
482bdeced75SVladimir Oltean 		u32 port;
483bdeced75SVladimir Oltean 		int err;
484bdeced75SVladimir Oltean 
485bdeced75SVladimir Oltean 		/* Get switch port number from DT */
486bdeced75SVladimir Oltean 		if (of_property_read_u32(child, "reg", &port) < 0) {
487bdeced75SVladimir Oltean 			dev_err(dev, "Port number not defined in device tree "
488bdeced75SVladimir Oltean 				"(property \"reg\")\n");
489bdeced75SVladimir Oltean 			of_node_put(child);
490bdeced75SVladimir Oltean 			return -ENODEV;
491bdeced75SVladimir Oltean 		}
492bdeced75SVladimir Oltean 
493bdeced75SVladimir Oltean 		/* Get PHY mode from DT */
494bdeced75SVladimir Oltean 		err = of_get_phy_mode(child, &phy_mode);
495bdeced75SVladimir Oltean 		if (err) {
496bdeced75SVladimir Oltean 			dev_err(dev, "Failed to read phy-mode or "
497bdeced75SVladimir Oltean 				"phy-interface-type property for port %d\n",
498bdeced75SVladimir Oltean 				port);
499bdeced75SVladimir Oltean 			of_node_put(child);
500bdeced75SVladimir Oltean 			return -ENODEV;
501bdeced75SVladimir Oltean 		}
502bdeced75SVladimir Oltean 
503bdeced75SVladimir Oltean 		err = felix->info->prevalidate_phy_mode(ocelot, port, phy_mode);
504bdeced75SVladimir Oltean 		if (err < 0) {
505bdeced75SVladimir Oltean 			dev_err(dev, "Unsupported PHY mode %s on port %d\n",
506bdeced75SVladimir Oltean 				phy_modes(phy_mode), port);
50759ebb430SSumera Priyadarsini 			of_node_put(child);
508bdeced75SVladimir Oltean 			return err;
509bdeced75SVladimir Oltean 		}
510bdeced75SVladimir Oltean 
511bdeced75SVladimir Oltean 		port_phy_modes[port] = phy_mode;
512bdeced75SVladimir Oltean 	}
513bdeced75SVladimir Oltean 
514bdeced75SVladimir Oltean 	return 0;
515bdeced75SVladimir Oltean }
516bdeced75SVladimir Oltean 
517bdeced75SVladimir Oltean static int felix_parse_dt(struct felix *felix, phy_interface_t *port_phy_modes)
518bdeced75SVladimir Oltean {
519bdeced75SVladimir Oltean 	struct device *dev = felix->ocelot.dev;
520bdeced75SVladimir Oltean 	struct device_node *switch_node;
521bdeced75SVladimir Oltean 	struct device_node *ports_node;
522bdeced75SVladimir Oltean 	int err;
523bdeced75SVladimir Oltean 
524bdeced75SVladimir Oltean 	switch_node = dev->of_node;
525bdeced75SVladimir Oltean 
526bdeced75SVladimir Oltean 	ports_node = of_get_child_by_name(switch_node, "ports");
527bdeced75SVladimir Oltean 	if (!ports_node) {
528bdeced75SVladimir Oltean 		dev_err(dev, "Incorrect bindings: absent \"ports\" node\n");
529bdeced75SVladimir Oltean 		return -ENODEV;
530bdeced75SVladimir Oltean 	}
531bdeced75SVladimir Oltean 
532bdeced75SVladimir Oltean 	err = felix_parse_ports_node(felix, ports_node, port_phy_modes);
533bdeced75SVladimir Oltean 	of_node_put(ports_node);
534bdeced75SVladimir Oltean 
535bdeced75SVladimir Oltean 	return err;
536bdeced75SVladimir Oltean }
537bdeced75SVladimir Oltean 
53856051948SVladimir Oltean static int felix_init_structs(struct felix *felix, int num_phys_ports)
53956051948SVladimir Oltean {
54056051948SVladimir Oltean 	struct ocelot *ocelot = &felix->ocelot;
541bdeced75SVladimir Oltean 	phy_interface_t *port_phy_modes;
542b4024c9eSClaudiu Manoil 	struct resource res;
54356051948SVladimir Oltean 	int port, i, err;
54456051948SVladimir Oltean 
54556051948SVladimir Oltean 	ocelot->num_phys_ports = num_phys_ports;
54656051948SVladimir Oltean 	ocelot->ports = devm_kcalloc(ocelot->dev, num_phys_ports,
54756051948SVladimir Oltean 				     sizeof(struct ocelot_port *), GFP_KERNEL);
54856051948SVladimir Oltean 	if (!ocelot->ports)
54956051948SVladimir Oltean 		return -ENOMEM;
55056051948SVladimir Oltean 
55156051948SVladimir Oltean 	ocelot->map		= felix->info->map;
55256051948SVladimir Oltean 	ocelot->stats_layout	= felix->info->stats_layout;
55356051948SVladimir Oltean 	ocelot->num_stats	= felix->info->num_stats;
55421ce7f3eSVladimir Oltean 	ocelot->num_mact_rows	= felix->info->num_mact_rows;
55507d985eeSVladimir Oltean 	ocelot->vcap		= felix->info->vcap;
55656051948SVladimir Oltean 	ocelot->ops		= felix->info->ops;
557cacea62fSVladimir Oltean 	ocelot->npi_inj_prefix	= OCELOT_TAG_PREFIX_SHORT;
558cacea62fSVladimir Oltean 	ocelot->npi_xtr_prefix	= OCELOT_TAG_PREFIX_SHORT;
559f59fd9caSVladimir Oltean 	ocelot->devlink		= felix->ds->devlink;
56056051948SVladimir Oltean 
561bdeced75SVladimir Oltean 	port_phy_modes = kcalloc(num_phys_ports, sizeof(phy_interface_t),
562bdeced75SVladimir Oltean 				 GFP_KERNEL);
563bdeced75SVladimir Oltean 	if (!port_phy_modes)
564bdeced75SVladimir Oltean 		return -ENOMEM;
565bdeced75SVladimir Oltean 
566bdeced75SVladimir Oltean 	err = felix_parse_dt(felix, port_phy_modes);
567bdeced75SVladimir Oltean 	if (err) {
568bdeced75SVladimir Oltean 		kfree(port_phy_modes);
569bdeced75SVladimir Oltean 		return err;
570bdeced75SVladimir Oltean 	}
571bdeced75SVladimir Oltean 
57256051948SVladimir Oltean 	for (i = 0; i < TARGET_MAX; i++) {
57356051948SVladimir Oltean 		struct regmap *target;
57456051948SVladimir Oltean 
57556051948SVladimir Oltean 		if (!felix->info->target_io_res[i].name)
57656051948SVladimir Oltean 			continue;
57756051948SVladimir Oltean 
578b4024c9eSClaudiu Manoil 		memcpy(&res, &felix->info->target_io_res[i], sizeof(res));
579b4024c9eSClaudiu Manoil 		res.flags = IORESOURCE_MEM;
580375e1314SVladimir Oltean 		res.start += felix->switch_base;
581375e1314SVladimir Oltean 		res.end += felix->switch_base;
58256051948SVladimir Oltean 
583b4024c9eSClaudiu Manoil 		target = ocelot_regmap_init(ocelot, &res);
58456051948SVladimir Oltean 		if (IS_ERR(target)) {
58556051948SVladimir Oltean 			dev_err(ocelot->dev,
58656051948SVladimir Oltean 				"Failed to map device memory space\n");
587bdeced75SVladimir Oltean 			kfree(port_phy_modes);
58856051948SVladimir Oltean 			return PTR_ERR(target);
58956051948SVladimir Oltean 		}
59056051948SVladimir Oltean 
59156051948SVladimir Oltean 		ocelot->targets[i] = target;
59256051948SVladimir Oltean 	}
59356051948SVladimir Oltean 
59456051948SVladimir Oltean 	err = ocelot_regfields_init(ocelot, felix->info->regfields);
59556051948SVladimir Oltean 	if (err) {
59656051948SVladimir Oltean 		dev_err(ocelot->dev, "failed to init reg fields map\n");
597bdeced75SVladimir Oltean 		kfree(port_phy_modes);
59856051948SVladimir Oltean 		return err;
59956051948SVladimir Oltean 	}
60056051948SVladimir Oltean 
60156051948SVladimir Oltean 	for (port = 0; port < num_phys_ports; port++) {
60256051948SVladimir Oltean 		struct ocelot_port *ocelot_port;
60391c724cfSVladimir Oltean 		struct regmap *target;
60467c24049SVladimir Oltean 		u8 *template;
60556051948SVladimir Oltean 
60656051948SVladimir Oltean 		ocelot_port = devm_kzalloc(ocelot->dev,
60756051948SVladimir Oltean 					   sizeof(struct ocelot_port),
60856051948SVladimir Oltean 					   GFP_KERNEL);
60956051948SVladimir Oltean 		if (!ocelot_port) {
61056051948SVladimir Oltean 			dev_err(ocelot->dev,
61156051948SVladimir Oltean 				"failed to allocate port memory\n");
612bdeced75SVladimir Oltean 			kfree(port_phy_modes);
61356051948SVladimir Oltean 			return -ENOMEM;
61456051948SVladimir Oltean 		}
61556051948SVladimir Oltean 
616b4024c9eSClaudiu Manoil 		memcpy(&res, &felix->info->port_io_res[port], sizeof(res));
617b4024c9eSClaudiu Manoil 		res.flags = IORESOURCE_MEM;
618375e1314SVladimir Oltean 		res.start += felix->switch_base;
619375e1314SVladimir Oltean 		res.end += felix->switch_base;
62056051948SVladimir Oltean 
62191c724cfSVladimir Oltean 		target = ocelot_regmap_init(ocelot, &res);
62291c724cfSVladimir Oltean 		if (IS_ERR(target)) {
62356051948SVladimir Oltean 			dev_err(ocelot->dev,
62491c724cfSVladimir Oltean 				"Failed to map memory space for port %d\n",
62591c724cfSVladimir Oltean 				port);
626bdeced75SVladimir Oltean 			kfree(port_phy_modes);
62791c724cfSVladimir Oltean 			return PTR_ERR(target);
62856051948SVladimir Oltean 		}
62956051948SVladimir Oltean 
6305124197cSVladimir Oltean 		template = devm_kzalloc(ocelot->dev, OCELOT_TOTAL_TAG_LEN,
63167c24049SVladimir Oltean 					GFP_KERNEL);
63267c24049SVladimir Oltean 		if (!template) {
63367c24049SVladimir Oltean 			dev_err(ocelot->dev,
63467c24049SVladimir Oltean 				"Failed to allocate memory for DSA tag\n");
63567c24049SVladimir Oltean 			kfree(port_phy_modes);
63667c24049SVladimir Oltean 			return -ENOMEM;
63767c24049SVladimir Oltean 		}
63867c24049SVladimir Oltean 
639bdeced75SVladimir Oltean 		ocelot_port->phy_mode = port_phy_modes[port];
64056051948SVladimir Oltean 		ocelot_port->ocelot = ocelot;
64191c724cfSVladimir Oltean 		ocelot_port->target = target;
64267c24049SVladimir Oltean 		ocelot_port->xmit_template = template;
64356051948SVladimir Oltean 		ocelot->ports[port] = ocelot_port;
64467c24049SVladimir Oltean 
64567c24049SVladimir Oltean 		felix->info->xmit_template_populate(ocelot, port);
64656051948SVladimir Oltean 	}
64756051948SVladimir Oltean 
648bdeced75SVladimir Oltean 	kfree(port_phy_modes);
649bdeced75SVladimir Oltean 
650bdeced75SVladimir Oltean 	if (felix->info->mdio_bus_alloc) {
651bdeced75SVladimir Oltean 		err = felix->info->mdio_bus_alloc(ocelot);
652bdeced75SVladimir Oltean 		if (err < 0)
653bdeced75SVladimir Oltean 			return err;
654bdeced75SVladimir Oltean 	}
655bdeced75SVladimir Oltean 
65656051948SVladimir Oltean 	return 0;
65756051948SVladimir Oltean }
65856051948SVladimir Oltean 
65956051948SVladimir Oltean /* Hardware initialization done here so that we can allocate structures with
66056051948SVladimir Oltean  * devm without fear of dsa_register_switch returning -EPROBE_DEFER and causing
66156051948SVladimir Oltean  * us to allocate structures twice (leak memory) and map PCI memory twice
66256051948SVladimir Oltean  * (which will not work).
66356051948SVladimir Oltean  */
66456051948SVladimir Oltean static int felix_setup(struct dsa_switch *ds)
66556051948SVladimir Oltean {
66656051948SVladimir Oltean 	struct ocelot *ocelot = ds->priv;
66756051948SVladimir Oltean 	struct felix *felix = ocelot_to_felix(ocelot);
66856051948SVladimir Oltean 	int port, err;
66956051948SVladimir Oltean 
67056051948SVladimir Oltean 	err = felix_init_structs(felix, ds->num_ports);
67156051948SVladimir Oltean 	if (err)
67256051948SVladimir Oltean 		return err;
67356051948SVladimir Oltean 
674d1cc0e93SVladimir Oltean 	err = ocelot_init(ocelot);
675d1cc0e93SVladimir Oltean 	if (err)
676d1cc0e93SVladimir Oltean 		return err;
677d1cc0e93SVladimir Oltean 
6782b49d128SYangbo Lu 	if (ocelot->ptp) {
6792ac7c6c5SVladimir Oltean 		err = ocelot_init_timestamp(ocelot, felix->info->ptp_caps);
6802b49d128SYangbo Lu 		if (err) {
6812b49d128SYangbo Lu 			dev_err(ocelot->dev,
6822b49d128SYangbo Lu 				"Timestamp initialization failed\n");
6832b49d128SYangbo Lu 			ocelot->ptp = 0;
6842b49d128SYangbo Lu 		}
6852b49d128SYangbo Lu 	}
68656051948SVladimir Oltean 
68756051948SVladimir Oltean 	for (port = 0; port < ds->num_ports; port++) {
688*adb3dccfSVladimir Oltean 		if (dsa_is_unused_port(ds, port))
689*adb3dccfSVladimir Oltean 			continue;
69056051948SVladimir Oltean 
691*adb3dccfSVladimir Oltean 		ocelot_init_port(ocelot, port);
692bd2b3161SXiaoliang Yang 
693bd2b3161SXiaoliang Yang 		/* Set the default QoS Classification based on PCP and DEI
694bd2b3161SXiaoliang Yang 		 * bits of vlan tag.
695bd2b3161SXiaoliang Yang 		 */
696bd2b3161SXiaoliang Yang 		felix_port_qos_map_init(ocelot, port);
69756051948SVladimir Oltean 	}
69856051948SVladimir Oltean 
699f59fd9caSVladimir Oltean 	err = ocelot_devlink_sb_register(ocelot);
700f59fd9caSVladimir Oltean 	if (err)
701f59fd9caSVladimir Oltean 		return err;
702f59fd9caSVladimir Oltean 
703*adb3dccfSVladimir Oltean 	for (port = 0; port < ds->num_ports; port++) {
704*adb3dccfSVladimir Oltean 		if (!dsa_is_cpu_port(ds, port))
705*adb3dccfSVladimir Oltean 			continue;
706*adb3dccfSVladimir Oltean 
707*adb3dccfSVladimir Oltean 		/* The initial tag protocol is NPI which always returns 0, so
708*adb3dccfSVladimir Oltean 		 * there's no real point in checking for errors.
7091cf3299bSVladimir Oltean 		 */
710*adb3dccfSVladimir Oltean 		felix_set_tag_protocol(ds, port, felix->tag_proto);
711*adb3dccfSVladimir Oltean 	}
7121cf3299bSVladimir Oltean 
7130b912fc9SVladimir Oltean 	ds->mtu_enforcement_ingress = true;
714c54913c1SVladimir Oltean 	ds->assisted_learning_on_cpu_port = true;
715bdeced75SVladimir Oltean 
71656051948SVladimir Oltean 	return 0;
71756051948SVladimir Oltean }
71856051948SVladimir Oltean 
71956051948SVladimir Oltean static void felix_teardown(struct dsa_switch *ds)
72056051948SVladimir Oltean {
72156051948SVladimir Oltean 	struct ocelot *ocelot = ds->priv;
722bdeced75SVladimir Oltean 	struct felix *felix = ocelot_to_felix(ocelot);
723e5fb512dSVladimir Oltean 	int port;
724bdeced75SVladimir Oltean 
725*adb3dccfSVladimir Oltean 	for (port = 0; port < ds->num_ports; port++) {
726*adb3dccfSVladimir Oltean 		if (!dsa_is_cpu_port(ds, port))
727*adb3dccfSVladimir Oltean 			continue;
728*adb3dccfSVladimir Oltean 
729*adb3dccfSVladimir Oltean 		felix_del_tag_protocol(ds, port, felix->tag_proto);
730*adb3dccfSVladimir Oltean 	}
731*adb3dccfSVladimir Oltean 
732f59fd9caSVladimir Oltean 	ocelot_devlink_sb_unregister(ocelot);
733d19741b0SVladimir Oltean 	ocelot_deinit_timestamp(ocelot);
734d19741b0SVladimir Oltean 	ocelot_deinit(ocelot);
73556051948SVladimir Oltean 
736e5fb512dSVladimir Oltean 	for (port = 0; port < ocelot->num_phys_ports; port++)
737e5fb512dSVladimir Oltean 		ocelot_deinit_port(ocelot, port);
738d19741b0SVladimir Oltean 
739d19741b0SVladimir Oltean 	if (felix->info->mdio_bus_free)
740d19741b0SVladimir Oltean 		felix->info->mdio_bus_free(ocelot);
74156051948SVladimir Oltean }
74256051948SVladimir Oltean 
743c0bcf537SYangbo Lu static int felix_hwtstamp_get(struct dsa_switch *ds, int port,
744c0bcf537SYangbo Lu 			      struct ifreq *ifr)
745c0bcf537SYangbo Lu {
746c0bcf537SYangbo Lu 	struct ocelot *ocelot = ds->priv;
747c0bcf537SYangbo Lu 
748c0bcf537SYangbo Lu 	return ocelot_hwstamp_get(ocelot, port, ifr);
749c0bcf537SYangbo Lu }
750c0bcf537SYangbo Lu 
751c0bcf537SYangbo Lu static int felix_hwtstamp_set(struct dsa_switch *ds, int port,
752c0bcf537SYangbo Lu 			      struct ifreq *ifr)
753c0bcf537SYangbo Lu {
754c0bcf537SYangbo Lu 	struct ocelot *ocelot = ds->priv;
755c0bcf537SYangbo Lu 
756c0bcf537SYangbo Lu 	return ocelot_hwstamp_set(ocelot, port, ifr);
757c0bcf537SYangbo Lu }
758c0bcf537SYangbo Lu 
759c0bcf537SYangbo Lu static bool felix_rxtstamp(struct dsa_switch *ds, int port,
760c0bcf537SYangbo Lu 			   struct sk_buff *skb, unsigned int type)
761c0bcf537SYangbo Lu {
762c0bcf537SYangbo Lu 	struct skb_shared_hwtstamps *shhwtstamps;
763c0bcf537SYangbo Lu 	struct ocelot *ocelot = ds->priv;
764c0bcf537SYangbo Lu 	u8 *extraction = skb->data - ETH_HLEN - OCELOT_TAG_LEN;
765c0bcf537SYangbo Lu 	u32 tstamp_lo, tstamp_hi;
766c0bcf537SYangbo Lu 	struct timespec64 ts;
767c0bcf537SYangbo Lu 	u64 tstamp, val;
768c0bcf537SYangbo Lu 
769c0bcf537SYangbo Lu 	ocelot_ptp_gettime64(&ocelot->ptp_info, &ts);
770c0bcf537SYangbo Lu 	tstamp = ktime_set(ts.tv_sec, ts.tv_nsec);
771c0bcf537SYangbo Lu 
772c0bcf537SYangbo Lu 	packing(extraction, &val,  116, 85, OCELOT_TAG_LEN, UNPACK, 0);
773c0bcf537SYangbo Lu 	tstamp_lo = (u32)val;
774c0bcf537SYangbo Lu 
775c0bcf537SYangbo Lu 	tstamp_hi = tstamp >> 32;
776c0bcf537SYangbo Lu 	if ((tstamp & 0xffffffff) < tstamp_lo)
777c0bcf537SYangbo Lu 		tstamp_hi--;
778c0bcf537SYangbo Lu 
779c0bcf537SYangbo Lu 	tstamp = ((u64)tstamp_hi << 32) | tstamp_lo;
780c0bcf537SYangbo Lu 
781c0bcf537SYangbo Lu 	shhwtstamps = skb_hwtstamps(skb);
782c0bcf537SYangbo Lu 	memset(shhwtstamps, 0, sizeof(struct skb_shared_hwtstamps));
783c0bcf537SYangbo Lu 	shhwtstamps->hwtstamp = tstamp;
784c0bcf537SYangbo Lu 	return false;
785c0bcf537SYangbo Lu }
786c0bcf537SYangbo Lu 
7873243e04aSChen Wandun static bool felix_txtstamp(struct dsa_switch *ds, int port,
788c0bcf537SYangbo Lu 			   struct sk_buff *clone, unsigned int type)
789c0bcf537SYangbo Lu {
790c0bcf537SYangbo Lu 	struct ocelot *ocelot = ds->priv;
791c0bcf537SYangbo Lu 	struct ocelot_port *ocelot_port = ocelot->ports[port];
792c0bcf537SYangbo Lu 
793e2f9a8feSVladimir Oltean 	if (ocelot->ptp && (skb_shinfo(clone)->tx_flags & SKBTX_HW_TSTAMP) &&
794e2f9a8feSVladimir Oltean 	    ocelot_port->ptp_cmd == IFH_REW_OP_TWO_STEP_PTP) {
795e2f9a8feSVladimir Oltean 		ocelot_port_add_txtstamp_skb(ocelot, port, clone);
796c0bcf537SYangbo Lu 		return true;
797e2f9a8feSVladimir Oltean 	}
798c0bcf537SYangbo Lu 
799c0bcf537SYangbo Lu 	return false;
800c0bcf537SYangbo Lu }
801c0bcf537SYangbo Lu 
8020b912fc9SVladimir Oltean static int felix_change_mtu(struct dsa_switch *ds, int port, int new_mtu)
8030b912fc9SVladimir Oltean {
8040b912fc9SVladimir Oltean 	struct ocelot *ocelot = ds->priv;
8050b912fc9SVladimir Oltean 
8060b912fc9SVladimir Oltean 	ocelot_port_set_maxlen(ocelot, port, new_mtu);
8070b912fc9SVladimir Oltean 
8080b912fc9SVladimir Oltean 	return 0;
8090b912fc9SVladimir Oltean }
8100b912fc9SVladimir Oltean 
8110b912fc9SVladimir Oltean static int felix_get_max_mtu(struct dsa_switch *ds, int port)
8120b912fc9SVladimir Oltean {
8130b912fc9SVladimir Oltean 	struct ocelot *ocelot = ds->priv;
8140b912fc9SVladimir Oltean 
8150b912fc9SVladimir Oltean 	return ocelot_get_max_mtu(ocelot, port);
8160b912fc9SVladimir Oltean }
8170b912fc9SVladimir Oltean 
81807d985eeSVladimir Oltean static int felix_cls_flower_add(struct dsa_switch *ds, int port,
81907d985eeSVladimir Oltean 				struct flow_cls_offload *cls, bool ingress)
82007d985eeSVladimir Oltean {
82107d985eeSVladimir Oltean 	struct ocelot *ocelot = ds->priv;
82207d985eeSVladimir Oltean 
82307d985eeSVladimir Oltean 	return ocelot_cls_flower_replace(ocelot, port, cls, ingress);
82407d985eeSVladimir Oltean }
82507d985eeSVladimir Oltean 
82607d985eeSVladimir Oltean static int felix_cls_flower_del(struct dsa_switch *ds, int port,
82707d985eeSVladimir Oltean 				struct flow_cls_offload *cls, bool ingress)
82807d985eeSVladimir Oltean {
82907d985eeSVladimir Oltean 	struct ocelot *ocelot = ds->priv;
83007d985eeSVladimir Oltean 
83107d985eeSVladimir Oltean 	return ocelot_cls_flower_destroy(ocelot, port, cls, ingress);
83207d985eeSVladimir Oltean }
83307d985eeSVladimir Oltean 
83407d985eeSVladimir Oltean static int felix_cls_flower_stats(struct dsa_switch *ds, int port,
83507d985eeSVladimir Oltean 				  struct flow_cls_offload *cls, bool ingress)
83607d985eeSVladimir Oltean {
83707d985eeSVladimir Oltean 	struct ocelot *ocelot = ds->priv;
83807d985eeSVladimir Oltean 
83907d985eeSVladimir Oltean 	return ocelot_cls_flower_stats(ocelot, port, cls, ingress);
84007d985eeSVladimir Oltean }
84107d985eeSVladimir Oltean 
842fc411eaaSVladimir Oltean static int felix_port_policer_add(struct dsa_switch *ds, int port,
843fc411eaaSVladimir Oltean 				  struct dsa_mall_policer_tc_entry *policer)
844fc411eaaSVladimir Oltean {
845fc411eaaSVladimir Oltean 	struct ocelot *ocelot = ds->priv;
846fc411eaaSVladimir Oltean 	struct ocelot_policer pol = {
847fc411eaaSVladimir Oltean 		.rate = div_u64(policer->rate_bytes_per_sec, 1000) * 8,
8485f035af7SPo Liu 		.burst = policer->burst,
849fc411eaaSVladimir Oltean 	};
850fc411eaaSVladimir Oltean 
851fc411eaaSVladimir Oltean 	return ocelot_port_policer_add(ocelot, port, &pol);
852fc411eaaSVladimir Oltean }
853fc411eaaSVladimir Oltean 
854fc411eaaSVladimir Oltean static void felix_port_policer_del(struct dsa_switch *ds, int port)
855fc411eaaSVladimir Oltean {
856fc411eaaSVladimir Oltean 	struct ocelot *ocelot = ds->priv;
857fc411eaaSVladimir Oltean 
858fc411eaaSVladimir Oltean 	ocelot_port_policer_del(ocelot, port);
859fc411eaaSVladimir Oltean }
860fc411eaaSVladimir Oltean 
861de143c0eSXiaoliang Yang static int felix_port_setup_tc(struct dsa_switch *ds, int port,
862de143c0eSXiaoliang Yang 			       enum tc_setup_type type,
863de143c0eSXiaoliang Yang 			       void *type_data)
864de143c0eSXiaoliang Yang {
865de143c0eSXiaoliang Yang 	struct ocelot *ocelot = ds->priv;
866de143c0eSXiaoliang Yang 	struct felix *felix = ocelot_to_felix(ocelot);
867de143c0eSXiaoliang Yang 
868de143c0eSXiaoliang Yang 	if (felix->info->port_setup_tc)
869de143c0eSXiaoliang Yang 		return felix->info->port_setup_tc(ds, port, type, type_data);
870de143c0eSXiaoliang Yang 	else
871de143c0eSXiaoliang Yang 		return -EOPNOTSUPP;
872de143c0eSXiaoliang Yang }
873de143c0eSXiaoliang Yang 
874f59fd9caSVladimir Oltean static int felix_sb_pool_get(struct dsa_switch *ds, unsigned int sb_index,
875f59fd9caSVladimir Oltean 			     u16 pool_index,
876f59fd9caSVladimir Oltean 			     struct devlink_sb_pool_info *pool_info)
877f59fd9caSVladimir Oltean {
878f59fd9caSVladimir Oltean 	struct ocelot *ocelot = ds->priv;
879f59fd9caSVladimir Oltean 
880f59fd9caSVladimir Oltean 	return ocelot_sb_pool_get(ocelot, sb_index, pool_index, pool_info);
881f59fd9caSVladimir Oltean }
882f59fd9caSVladimir Oltean 
883f59fd9caSVladimir Oltean static int felix_sb_pool_set(struct dsa_switch *ds, unsigned int sb_index,
884f59fd9caSVladimir Oltean 			     u16 pool_index, u32 size,
885f59fd9caSVladimir Oltean 			     enum devlink_sb_threshold_type threshold_type,
886f59fd9caSVladimir Oltean 			     struct netlink_ext_ack *extack)
887f59fd9caSVladimir Oltean {
888f59fd9caSVladimir Oltean 	struct ocelot *ocelot = ds->priv;
889f59fd9caSVladimir Oltean 
890f59fd9caSVladimir Oltean 	return ocelot_sb_pool_set(ocelot, sb_index, pool_index, size,
891f59fd9caSVladimir Oltean 				  threshold_type, extack);
892f59fd9caSVladimir Oltean }
893f59fd9caSVladimir Oltean 
894f59fd9caSVladimir Oltean static int felix_sb_port_pool_get(struct dsa_switch *ds, int port,
895f59fd9caSVladimir Oltean 				  unsigned int sb_index, u16 pool_index,
896f59fd9caSVladimir Oltean 				  u32 *p_threshold)
897f59fd9caSVladimir Oltean {
898f59fd9caSVladimir Oltean 	struct ocelot *ocelot = ds->priv;
899f59fd9caSVladimir Oltean 
900f59fd9caSVladimir Oltean 	return ocelot_sb_port_pool_get(ocelot, port, sb_index, pool_index,
901f59fd9caSVladimir Oltean 				       p_threshold);
902f59fd9caSVladimir Oltean }
903f59fd9caSVladimir Oltean 
904f59fd9caSVladimir Oltean static int felix_sb_port_pool_set(struct dsa_switch *ds, int port,
905f59fd9caSVladimir Oltean 				  unsigned int sb_index, u16 pool_index,
906f59fd9caSVladimir Oltean 				  u32 threshold, struct netlink_ext_ack *extack)
907f59fd9caSVladimir Oltean {
908f59fd9caSVladimir Oltean 	struct ocelot *ocelot = ds->priv;
909f59fd9caSVladimir Oltean 
910f59fd9caSVladimir Oltean 	return ocelot_sb_port_pool_set(ocelot, port, sb_index, pool_index,
911f59fd9caSVladimir Oltean 				       threshold, extack);
912f59fd9caSVladimir Oltean }
913f59fd9caSVladimir Oltean 
914f59fd9caSVladimir Oltean static int felix_sb_tc_pool_bind_get(struct dsa_switch *ds, int port,
915f59fd9caSVladimir Oltean 				     unsigned int sb_index, u16 tc_index,
916f59fd9caSVladimir Oltean 				     enum devlink_sb_pool_type pool_type,
917f59fd9caSVladimir Oltean 				     u16 *p_pool_index, u32 *p_threshold)
918f59fd9caSVladimir Oltean {
919f59fd9caSVladimir Oltean 	struct ocelot *ocelot = ds->priv;
920f59fd9caSVladimir Oltean 
921f59fd9caSVladimir Oltean 	return ocelot_sb_tc_pool_bind_get(ocelot, port, sb_index, tc_index,
922f59fd9caSVladimir Oltean 					  pool_type, p_pool_index,
923f59fd9caSVladimir Oltean 					  p_threshold);
924f59fd9caSVladimir Oltean }
925f59fd9caSVladimir Oltean 
926f59fd9caSVladimir Oltean static int felix_sb_tc_pool_bind_set(struct dsa_switch *ds, int port,
927f59fd9caSVladimir Oltean 				     unsigned int sb_index, u16 tc_index,
928f59fd9caSVladimir Oltean 				     enum devlink_sb_pool_type pool_type,
929f59fd9caSVladimir Oltean 				     u16 pool_index, u32 threshold,
930f59fd9caSVladimir Oltean 				     struct netlink_ext_ack *extack)
931f59fd9caSVladimir Oltean {
932f59fd9caSVladimir Oltean 	struct ocelot *ocelot = ds->priv;
933f59fd9caSVladimir Oltean 
934f59fd9caSVladimir Oltean 	return ocelot_sb_tc_pool_bind_set(ocelot, port, sb_index, tc_index,
935f59fd9caSVladimir Oltean 					  pool_type, pool_index, threshold,
936f59fd9caSVladimir Oltean 					  extack);
937f59fd9caSVladimir Oltean }
938f59fd9caSVladimir Oltean 
939f59fd9caSVladimir Oltean static int felix_sb_occ_snapshot(struct dsa_switch *ds,
940f59fd9caSVladimir Oltean 				 unsigned int sb_index)
941f59fd9caSVladimir Oltean {
942f59fd9caSVladimir Oltean 	struct ocelot *ocelot = ds->priv;
943f59fd9caSVladimir Oltean 
944f59fd9caSVladimir Oltean 	return ocelot_sb_occ_snapshot(ocelot, sb_index);
945f59fd9caSVladimir Oltean }
946f59fd9caSVladimir Oltean 
947f59fd9caSVladimir Oltean static int felix_sb_occ_max_clear(struct dsa_switch *ds,
948f59fd9caSVladimir Oltean 				  unsigned int sb_index)
949f59fd9caSVladimir Oltean {
950f59fd9caSVladimir Oltean 	struct ocelot *ocelot = ds->priv;
951f59fd9caSVladimir Oltean 
952f59fd9caSVladimir Oltean 	return ocelot_sb_occ_max_clear(ocelot, sb_index);
953f59fd9caSVladimir Oltean }
954f59fd9caSVladimir Oltean 
955f59fd9caSVladimir Oltean static int felix_sb_occ_port_pool_get(struct dsa_switch *ds, int port,
956f59fd9caSVladimir Oltean 				      unsigned int sb_index, u16 pool_index,
957f59fd9caSVladimir Oltean 				      u32 *p_cur, u32 *p_max)
958f59fd9caSVladimir Oltean {
959f59fd9caSVladimir Oltean 	struct ocelot *ocelot = ds->priv;
960f59fd9caSVladimir Oltean 
961f59fd9caSVladimir Oltean 	return ocelot_sb_occ_port_pool_get(ocelot, port, sb_index, pool_index,
962f59fd9caSVladimir Oltean 					   p_cur, p_max);
963f59fd9caSVladimir Oltean }
964f59fd9caSVladimir Oltean 
965f59fd9caSVladimir Oltean static int felix_sb_occ_tc_port_bind_get(struct dsa_switch *ds, int port,
966f59fd9caSVladimir Oltean 					 unsigned int sb_index, u16 tc_index,
967f59fd9caSVladimir Oltean 					 enum devlink_sb_pool_type pool_type,
968f59fd9caSVladimir Oltean 					 u32 *p_cur, u32 *p_max)
969f59fd9caSVladimir Oltean {
970f59fd9caSVladimir Oltean 	struct ocelot *ocelot = ds->priv;
971f59fd9caSVladimir Oltean 
972f59fd9caSVladimir Oltean 	return ocelot_sb_occ_tc_port_bind_get(ocelot, port, sb_index, tc_index,
973f59fd9caSVladimir Oltean 					      pool_type, p_cur, p_max);
974f59fd9caSVladimir Oltean }
975f59fd9caSVladimir Oltean 
976375e1314SVladimir Oltean const struct dsa_switch_ops felix_switch_ops = {
97756051948SVladimir Oltean 	.get_tag_protocol		= felix_get_tag_protocol,
978*adb3dccfSVladimir Oltean 	.change_tag_protocol		= felix_change_tag_protocol,
97956051948SVladimir Oltean 	.setup				= felix_setup,
98056051948SVladimir Oltean 	.teardown			= felix_teardown,
98156051948SVladimir Oltean 	.set_ageing_time		= felix_set_ageing_time,
98256051948SVladimir Oltean 	.get_strings			= felix_get_strings,
98356051948SVladimir Oltean 	.get_ethtool_stats		= felix_get_ethtool_stats,
98456051948SVladimir Oltean 	.get_sset_count			= felix_get_sset_count,
98556051948SVladimir Oltean 	.get_ts_info			= felix_get_ts_info,
986bdeced75SVladimir Oltean 	.phylink_validate		= felix_phylink_validate,
987bdeced75SVladimir Oltean 	.phylink_mac_config		= felix_phylink_mac_config,
988bdeced75SVladimir Oltean 	.phylink_mac_link_down		= felix_phylink_mac_link_down,
989bdeced75SVladimir Oltean 	.phylink_mac_link_up		= felix_phylink_mac_link_up,
99056051948SVladimir Oltean 	.port_enable			= felix_port_enable,
99156051948SVladimir Oltean 	.port_disable			= felix_port_disable,
99256051948SVladimir Oltean 	.port_fdb_dump			= felix_fdb_dump,
99356051948SVladimir Oltean 	.port_fdb_add			= felix_fdb_add,
99456051948SVladimir Oltean 	.port_fdb_del			= felix_fdb_del,
995209edf95SVladimir Oltean 	.port_mdb_add			= felix_mdb_add,
996209edf95SVladimir Oltean 	.port_mdb_del			= felix_mdb_del,
99756051948SVladimir Oltean 	.port_bridge_join		= felix_bridge_join,
99856051948SVladimir Oltean 	.port_bridge_leave		= felix_bridge_leave,
99956051948SVladimir Oltean 	.port_stp_state_set		= felix_bridge_stp_state_set,
100056051948SVladimir Oltean 	.port_vlan_filtering		= felix_vlan_filtering,
100156051948SVladimir Oltean 	.port_vlan_add			= felix_vlan_add,
100256051948SVladimir Oltean 	.port_vlan_del			= felix_vlan_del,
1003c0bcf537SYangbo Lu 	.port_hwtstamp_get		= felix_hwtstamp_get,
1004c0bcf537SYangbo Lu 	.port_hwtstamp_set		= felix_hwtstamp_set,
1005c0bcf537SYangbo Lu 	.port_rxtstamp			= felix_rxtstamp,
1006c0bcf537SYangbo Lu 	.port_txtstamp			= felix_txtstamp,
10070b912fc9SVladimir Oltean 	.port_change_mtu		= felix_change_mtu,
10080b912fc9SVladimir Oltean 	.port_max_mtu			= felix_get_max_mtu,
1009fc411eaaSVladimir Oltean 	.port_policer_add		= felix_port_policer_add,
1010fc411eaaSVladimir Oltean 	.port_policer_del		= felix_port_policer_del,
101107d985eeSVladimir Oltean 	.cls_flower_add			= felix_cls_flower_add,
101207d985eeSVladimir Oltean 	.cls_flower_del			= felix_cls_flower_del,
101307d985eeSVladimir Oltean 	.cls_flower_stats		= felix_cls_flower_stats,
1014de143c0eSXiaoliang Yang 	.port_setup_tc			= felix_port_setup_tc,
1015f59fd9caSVladimir Oltean 	.devlink_sb_pool_get		= felix_sb_pool_get,
1016f59fd9caSVladimir Oltean 	.devlink_sb_pool_set		= felix_sb_pool_set,
1017f59fd9caSVladimir Oltean 	.devlink_sb_port_pool_get	= felix_sb_port_pool_get,
1018f59fd9caSVladimir Oltean 	.devlink_sb_port_pool_set	= felix_sb_port_pool_set,
1019f59fd9caSVladimir Oltean 	.devlink_sb_tc_pool_bind_get	= felix_sb_tc_pool_bind_get,
1020f59fd9caSVladimir Oltean 	.devlink_sb_tc_pool_bind_set	= felix_sb_tc_pool_bind_set,
1021f59fd9caSVladimir Oltean 	.devlink_sb_occ_snapshot	= felix_sb_occ_snapshot,
1022f59fd9caSVladimir Oltean 	.devlink_sb_occ_max_clear	= felix_sb_occ_max_clear,
1023f59fd9caSVladimir Oltean 	.devlink_sb_occ_port_pool_get	= felix_sb_occ_port_pool_get,
1024f59fd9caSVladimir Oltean 	.devlink_sb_occ_tc_port_bind_get= felix_sb_occ_tc_port_bind_get,
102556051948SVladimir Oltean };
1026319e4dd1SVladimir Oltean 
1027319e4dd1SVladimir Oltean struct net_device *felix_port_to_netdev(struct ocelot *ocelot, int port)
1028319e4dd1SVladimir Oltean {
1029319e4dd1SVladimir Oltean 	struct felix *felix = ocelot_to_felix(ocelot);
1030319e4dd1SVladimir Oltean 	struct dsa_switch *ds = felix->ds;
1031319e4dd1SVladimir Oltean 
1032319e4dd1SVladimir Oltean 	if (!dsa_is_user_port(ds, port))
1033319e4dd1SVladimir Oltean 		return NULL;
1034319e4dd1SVladimir Oltean 
1035319e4dd1SVladimir Oltean 	return dsa_to_port(ds, port)->slave;
1036319e4dd1SVladimir Oltean }
1037319e4dd1SVladimir Oltean 
1038319e4dd1SVladimir Oltean int felix_netdev_to_port(struct net_device *dev)
1039319e4dd1SVladimir Oltean {
1040319e4dd1SVladimir Oltean 	struct dsa_port *dp;
1041319e4dd1SVladimir Oltean 
1042319e4dd1SVladimir Oltean 	dp = dsa_port_from_netdev(dev);
1043319e4dd1SVladimir Oltean 	if (IS_ERR(dp))
1044319e4dd1SVladimir Oltean 		return -EINVAL;
1045319e4dd1SVladimir Oltean 
1046319e4dd1SVladimir Oltean 	return dp->index;
1047319e4dd1SVladimir Oltean }
1048