Commit | Line | Data |
---|---|---|
56051948 | 1 | // SPDX-License-Identifier: GPL-2.0 |
3c9cfb52 | 2 | /* Copyright 2019-2021 NXP |
375e1314 VO |
3 | * |
4 | * This is an umbrella module for all network switches that are | |
5 | * register-compatible with Ocelot and that perform I/O to their host CPU | |
6 | * through an NPI (Node Processor Interface) Ethernet port. | |
56051948 VO |
7 | */ |
8 | #include <uapi/linux/if_bridge.h> | |
07d985ee | 9 | #include <soc/mscc/ocelot_vcap.h> |
bdeced75 VO |
10 | #include <soc/mscc/ocelot_qsys.h> |
11 | #include <soc/mscc/ocelot_sys.h> | |
12 | #include <soc/mscc/ocelot_dev.h> | |
13 | #include <soc/mscc/ocelot_ana.h> | |
2b49d128 | 14 | #include <soc/mscc/ocelot_ptp.h> |
56051948 | 15 | #include <soc/mscc/ocelot.h> |
e21268ef | 16 | #include <linux/dsa/8021q.h> |
40d3f295 | 17 | #include <linux/dsa/ocelot.h> |
84705fc1 | 18 | #include <linux/platform_device.h> |
0a6f17c6 | 19 | #include <linux/ptp_classify.h> |
56051948 | 20 | #include <linux/module.h> |
bdeced75 | 21 | #include <linux/of_net.h> |
56051948 VO |
22 | #include <linux/pci.h> |
23 | #include <linux/of.h> | |
fc411eaa | 24 | #include <net/pkt_sched.h> |
56051948 VO |
25 | #include <net/dsa.h> |
26 | #include "felix.h" | |
27 | ||
f9cef64f VO |
28 | /* Translate the DSA database API into the ocelot switch library API, |
29 | * which uses VID 0 for all ports that aren't part of a bridge, | |
30 | * and expects the bridge_dev to be NULL in that case. | |
31 | */ | |
32 | static struct net_device *felix_classify_db(struct dsa_db db) | |
33 | { | |
34 | switch (db.type) { | |
35 | case DSA_DB_PORT: | |
36 | case DSA_DB_LAG: | |
37 | return NULL; | |
38 | case DSA_DB_BRIDGE: | |
39 | return db.bridge.dev; | |
40 | default: | |
41 | return ERR_PTR(-EOPNOTSUPP); | |
42 | } | |
43 | } | |
44 | ||
6ca80638 FF |
45 | static int felix_cpu_port_for_conduit(struct dsa_switch *ds, |
46 | struct net_device *conduit) | |
eca70102 VO |
47 | { |
48 | struct ocelot *ocelot = ds->priv; | |
49 | struct dsa_port *cpu_dp; | |
50 | int lag; | |
51 | ||
6ca80638 | 52 | if (netif_is_lag_master(conduit)) { |
eca70102 | 53 | mutex_lock(&ocelot->fwd_domain_lock); |
6ca80638 | 54 | lag = ocelot_bond_get_id(ocelot, conduit); |
eca70102 VO |
55 | mutex_unlock(&ocelot->fwd_domain_lock); |
56 | ||
57 | return lag; | |
58 | } | |
59 | ||
6ca80638 | 60 | cpu_dp = conduit->dsa_ptr; |
eca70102 VO |
61 | return cpu_dp->index; |
62 | } | |
63 | ||
04b67e18 VO |
64 | /* Set up VCAP ES0 rules for pushing a tag_8021q VLAN towards the CPU such that |
65 | * the tagger can perform RX source port identification. | |
66 | */ | |
a4e044dc VO |
67 | static int felix_tag_8021q_vlan_add_rx(struct dsa_switch *ds, int port, |
68 | int upstream, u16 vid) | |
e21268ef VO |
69 | { |
70 | struct ocelot_vcap_filter *outer_tagging_rule; | |
a4e044dc VO |
71 | struct ocelot *ocelot = ds->priv; |
72 | unsigned long cookie; | |
73 | int key_length, err; | |
e21268ef | 74 | |
e21268ef | 75 | key_length = ocelot->vcap[VCAP_ES0].keys[VCAP_ES0_IGR_PORT].length; |
e21268ef VO |
76 | |
77 | outer_tagging_rule = kzalloc(sizeof(struct ocelot_vcap_filter), | |
78 | GFP_KERNEL); | |
79 | if (!outer_tagging_rule) | |
80 | return -ENOMEM; | |
81 | ||
a4e044dc VO |
82 | cookie = OCELOT_VCAP_ES0_TAG_8021Q_RXVLAN(ocelot, port, upstream); |
83 | ||
e21268ef VO |
84 | outer_tagging_rule->key_type = OCELOT_VCAP_KEY_ANY; |
85 | outer_tagging_rule->prio = 1; | |
a4e044dc | 86 | outer_tagging_rule->id.cookie = cookie; |
e21268ef VO |
87 | outer_tagging_rule->id.tc_offload = false; |
88 | outer_tagging_rule->block_id = VCAP_ES0; | |
89 | outer_tagging_rule->type = OCELOT_VCAP_FILTER_OFFLOAD; | |
90 | outer_tagging_rule->lookup = 0; | |
91 | outer_tagging_rule->ingress_port.value = port; | |
92 | outer_tagging_rule->ingress_port.mask = GENMASK(key_length - 1, 0); | |
93 | outer_tagging_rule->egress_port.value = upstream; | |
94 | outer_tagging_rule->egress_port.mask = GENMASK(key_length - 1, 0); | |
95 | outer_tagging_rule->action.push_outer_tag = OCELOT_ES0_TAG; | |
96 | outer_tagging_rule->action.tag_a_tpid_sel = OCELOT_TAG_TPID_SEL_8021AD; | |
97 | outer_tagging_rule->action.tag_a_vid_sel = 1; | |
98 | outer_tagging_rule->action.vid_a_val = vid; | |
99 | ||
100 | err = ocelot_vcap_filter_add(ocelot, outer_tagging_rule, NULL); | |
101 | if (err) | |
102 | kfree(outer_tagging_rule); | |
103 | ||
104 | return err; | |
105 | } | |
106 | ||
a4e044dc VO |
107 | static int felix_tag_8021q_vlan_del_rx(struct dsa_switch *ds, int port, |
108 | int upstream, u16 vid) | |
04b67e18 VO |
109 | { |
110 | struct ocelot_vcap_filter *outer_tagging_rule; | |
111 | struct ocelot_vcap_block *block_vcap_es0; | |
a4e044dc VO |
112 | struct ocelot *ocelot = ds->priv; |
113 | unsigned long cookie; | |
04b67e18 VO |
114 | |
115 | block_vcap_es0 = &ocelot->block[VCAP_ES0]; | |
a4e044dc | 116 | cookie = OCELOT_VCAP_ES0_TAG_8021Q_RXVLAN(ocelot, port, upstream); |
04b67e18 VO |
117 | |
118 | outer_tagging_rule = ocelot_vcap_block_find_filter_by_id(block_vcap_es0, | |
a4e044dc | 119 | cookie, false); |
04b67e18 VO |
120 | if (!outer_tagging_rule) |
121 | return -ENOENT; | |
122 | ||
123 | return ocelot_vcap_filter_del(ocelot, outer_tagging_rule); | |
124 | } | |
125 | ||
126 | /* Set up VCAP IS1 rules for stripping the tag_8021q VLAN on TX and VCAP IS2 | |
127 | * rules for steering those tagged packets towards the correct destination port | |
128 | */ | |
a4e044dc VO |
129 | static int felix_tag_8021q_vlan_add_tx(struct dsa_switch *ds, int port, |
130 | u16 vid) | |
e21268ef VO |
131 | { |
132 | struct ocelot_vcap_filter *untagging_rule, *redirect_rule; | |
a4e044dc VO |
133 | unsigned long cpu_ports = dsa_cpu_ports(ds); |
134 | struct ocelot *ocelot = ds->priv; | |
135 | unsigned long cookie; | |
136 | int err; | |
e21268ef | 137 | |
e21268ef VO |
138 | untagging_rule = kzalloc(sizeof(struct ocelot_vcap_filter), GFP_KERNEL); |
139 | if (!untagging_rule) | |
140 | return -ENOMEM; | |
141 | ||
142 | redirect_rule = kzalloc(sizeof(struct ocelot_vcap_filter), GFP_KERNEL); | |
143 | if (!redirect_rule) { | |
144 | kfree(untagging_rule); | |
145 | return -ENOMEM; | |
146 | } | |
147 | ||
a4e044dc | 148 | cookie = OCELOT_VCAP_IS1_TAG_8021Q_TXVLAN(ocelot, port); |
e21268ef VO |
149 | |
150 | untagging_rule->key_type = OCELOT_VCAP_KEY_ANY; | |
a4e044dc | 151 | untagging_rule->ingress_port_mask = cpu_ports; |
e21268ef VO |
152 | untagging_rule->vlan.vid.value = vid; |
153 | untagging_rule->vlan.vid.mask = VLAN_VID_MASK; | |
154 | untagging_rule->prio = 1; | |
a4e044dc | 155 | untagging_rule->id.cookie = cookie; |
e21268ef VO |
156 | untagging_rule->id.tc_offload = false; |
157 | untagging_rule->block_id = VCAP_IS1; | |
158 | untagging_rule->type = OCELOT_VCAP_FILTER_OFFLOAD; | |
159 | untagging_rule->lookup = 0; | |
160 | untagging_rule->action.vlan_pop_cnt_ena = true; | |
161 | untagging_rule->action.vlan_pop_cnt = 1; | |
162 | untagging_rule->action.pag_override_mask = 0xff; | |
163 | untagging_rule->action.pag_val = port; | |
164 | ||
165 | err = ocelot_vcap_filter_add(ocelot, untagging_rule, NULL); | |
166 | if (err) { | |
167 | kfree(untagging_rule); | |
168 | kfree(redirect_rule); | |
169 | return err; | |
170 | } | |
171 | ||
a4e044dc VO |
172 | cookie = OCELOT_VCAP_IS2_TAG_8021Q_TXVLAN(ocelot, port); |
173 | ||
e21268ef | 174 | redirect_rule->key_type = OCELOT_VCAP_KEY_ANY; |
a4e044dc | 175 | redirect_rule->ingress_port_mask = cpu_ports; |
e21268ef VO |
176 | redirect_rule->pag = port; |
177 | redirect_rule->prio = 1; | |
a4e044dc | 178 | redirect_rule->id.cookie = cookie; |
e21268ef VO |
179 | redirect_rule->id.tc_offload = false; |
180 | redirect_rule->block_id = VCAP_IS2; | |
181 | redirect_rule->type = OCELOT_VCAP_FILTER_OFFLOAD; | |
182 | redirect_rule->lookup = 0; | |
183 | redirect_rule->action.mask_mode = OCELOT_MASK_MODE_REDIRECT; | |
184 | redirect_rule->action.port_mask = BIT(port); | |
185 | ||
186 | err = ocelot_vcap_filter_add(ocelot, redirect_rule, NULL); | |
187 | if (err) { | |
188 | ocelot_vcap_filter_del(ocelot, untagging_rule); | |
189 | kfree(redirect_rule); | |
190 | return err; | |
191 | } | |
192 | ||
193 | return 0; | |
194 | } | |
195 | ||
a4e044dc | 196 | static int felix_tag_8021q_vlan_del_tx(struct dsa_switch *ds, int port, u16 vid) |
e21268ef VO |
197 | { |
198 | struct ocelot_vcap_filter *untagging_rule, *redirect_rule; | |
199 | struct ocelot_vcap_block *block_vcap_is1; | |
200 | struct ocelot_vcap_block *block_vcap_is2; | |
a4e044dc VO |
201 | struct ocelot *ocelot = ds->priv; |
202 | unsigned long cookie; | |
e21268ef VO |
203 | int err; |
204 | ||
e21268ef VO |
205 | block_vcap_is1 = &ocelot->block[VCAP_IS1]; |
206 | block_vcap_is2 = &ocelot->block[VCAP_IS2]; | |
207 | ||
a4e044dc | 208 | cookie = OCELOT_VCAP_IS1_TAG_8021Q_TXVLAN(ocelot, port); |
e21268ef | 209 | untagging_rule = ocelot_vcap_block_find_filter_by_id(block_vcap_is1, |
a4e044dc | 210 | cookie, false); |
e21268ef | 211 | if (!untagging_rule) |
08f44db3 | 212 | return -ENOENT; |
e21268ef VO |
213 | |
214 | err = ocelot_vcap_filter_del(ocelot, untagging_rule); | |
215 | if (err) | |
216 | return err; | |
217 | ||
a4e044dc | 218 | cookie = OCELOT_VCAP_IS2_TAG_8021Q_TXVLAN(ocelot, port); |
e21268ef | 219 | redirect_rule = ocelot_vcap_block_find_filter_by_id(block_vcap_is2, |
a4e044dc | 220 | cookie, false); |
e21268ef | 221 | if (!redirect_rule) |
04b67e18 | 222 | return -ENOENT; |
e21268ef VO |
223 | |
224 | return ocelot_vcap_filter_del(ocelot, redirect_rule); | |
225 | } | |
226 | ||
04b67e18 VO |
227 | static int felix_tag_8021q_vlan_add(struct dsa_switch *ds, int port, u16 vid, |
228 | u16 flags) | |
229 | { | |
a4e044dc | 230 | struct dsa_port *cpu_dp; |
04b67e18 VO |
231 | int err; |
232 | ||
233 | /* tag_8021q.c assumes we are implementing this via port VLAN | |
234 | * membership, which we aren't. So we don't need to add any VCAP filter | |
235 | * for the CPU port. | |
236 | */ | |
237 | if (!dsa_is_user_port(ds, port)) | |
238 | return 0; | |
239 | ||
a4e044dc VO |
240 | dsa_switch_for_each_cpu_port(cpu_dp, ds) { |
241 | err = felix_tag_8021q_vlan_add_rx(ds, port, cpu_dp->index, vid); | |
242 | if (err) | |
243 | return err; | |
04b67e18 VO |
244 | } |
245 | ||
a4e044dc VO |
246 | err = felix_tag_8021q_vlan_add_tx(ds, port, vid); |
247 | if (err) | |
248 | goto add_tx_failed; | |
249 | ||
04b67e18 | 250 | return 0; |
a4e044dc VO |
251 | |
252 | add_tx_failed: | |
253 | dsa_switch_for_each_cpu_port(cpu_dp, ds) | |
254 | felix_tag_8021q_vlan_del_rx(ds, port, cpu_dp->index, vid); | |
255 | ||
256 | return err; | |
04b67e18 VO |
257 | } |
258 | ||
e21268ef VO |
259 | static int felix_tag_8021q_vlan_del(struct dsa_switch *ds, int port, u16 vid) |
260 | { | |
a4e044dc | 261 | struct dsa_port *cpu_dp; |
04b67e18 VO |
262 | int err; |
263 | ||
264 | if (!dsa_is_user_port(ds, port)) | |
265 | return 0; | |
e21268ef | 266 | |
a4e044dc VO |
267 | dsa_switch_for_each_cpu_port(cpu_dp, ds) { |
268 | err = felix_tag_8021q_vlan_del_rx(ds, port, cpu_dp->index, vid); | |
269 | if (err) | |
270 | return err; | |
04b67e18 | 271 | } |
e21268ef | 272 | |
a4e044dc VO |
273 | err = felix_tag_8021q_vlan_del_tx(ds, port, vid); |
274 | if (err) | |
275 | goto del_tx_failed; | |
276 | ||
e21268ef | 277 | return 0; |
a4e044dc VO |
278 | |
279 | del_tx_failed: | |
280 | dsa_switch_for_each_cpu_port(cpu_dp, ds) | |
281 | felix_tag_8021q_vlan_add_rx(ds, port, cpu_dp->index, vid); | |
282 | ||
283 | return err; | |
e21268ef VO |
284 | } |
285 | ||
c352e5e8 VO |
286 | static int felix_trap_get_cpu_port(struct dsa_switch *ds, |
287 | const struct ocelot_vcap_filter *trap) | |
288 | { | |
289 | struct dsa_port *dp; | |
290 | int first_port; | |
291 | ||
292 | if (WARN_ON(!trap->ingress_port_mask)) | |
293 | return -1; | |
294 | ||
295 | first_port = __ffs(trap->ingress_port_mask); | |
296 | dp = dsa_to_port(ds, first_port); | |
297 | ||
298 | return dp->cpu_dp->index; | |
299 | } | |
300 | ||
99348004 VO |
301 | /* On switches with no extraction IRQ wired, trapped packets need to be |
302 | * replicated over Ethernet as well, otherwise we'd get no notification of | |
303 | * their arrival when using the ocelot-8021q tagging protocol. | |
c8c0ba4f | 304 | */ |
99348004 VO |
305 | static int felix_update_trapping_destinations(struct dsa_switch *ds, |
306 | bool using_tag_8021q) | |
c8c0ba4f | 307 | { |
99348004 VO |
308 | struct ocelot *ocelot = ds->priv; |
309 | struct felix *felix = ocelot_to_felix(ocelot); | |
e1846cff | 310 | struct ocelot_vcap_block *block_vcap_is2; |
99348004 VO |
311 | struct ocelot_vcap_filter *trap; |
312 | enum ocelot_mask_mode mask_mode; | |
313 | unsigned long port_mask; | |
99348004 | 314 | bool cpu_copy_ena; |
c352e5e8 | 315 | int err; |
c8c0ba4f | 316 | |
99348004 VO |
317 | if (!felix->info->quirk_no_xtr_irq) |
318 | return 0; | |
c8c0ba4f | 319 | |
d78637a8 VO |
320 | /* We are sure that "cpu" was found, otherwise |
321 | * dsa_tree_setup_default_cpu() would have failed earlier. | |
322 | */ | |
e1846cff | 323 | block_vcap_is2 = &ocelot->block[VCAP_IS2]; |
8d5f7954 | 324 | |
99348004 | 325 | /* Make sure all traps are set up for that destination */ |
e1846cff VO |
326 | list_for_each_entry(trap, &block_vcap_is2->rules, list) { |
327 | if (!trap->is_trap) | |
328 | continue; | |
329 | ||
99348004 VO |
330 | /* Figure out the current trapping destination */ |
331 | if (using_tag_8021q) { | |
332 | /* Redirect to the tag_8021q CPU port. If timestamps | |
333 | * are necessary, also copy trapped packets to the CPU | |
334 | * port module. | |
335 | */ | |
336 | mask_mode = OCELOT_MASK_MODE_REDIRECT; | |
c352e5e8 | 337 | port_mask = BIT(felix_trap_get_cpu_port(ds, trap)); |
99348004 VO |
338 | cpu_copy_ena = !!trap->take_ts; |
339 | } else { | |
340 | /* Trap packets only to the CPU port module, which is | |
341 | * redirected to the NPI port (the DSA CPU port) | |
342 | */ | |
343 | mask_mode = OCELOT_MASK_MODE_PERMIT_DENY; | |
344 | port_mask = 0; | |
345 | cpu_copy_ena = true; | |
346 | } | |
c8c0ba4f | 347 | |
99348004 VO |
348 | if (trap->action.mask_mode == mask_mode && |
349 | trap->action.port_mask == port_mask && | |
350 | trap->action.cpu_copy_ena == cpu_copy_ena) | |
351 | continue; | |
c8c0ba4f | 352 | |
99348004 VO |
353 | trap->action.mask_mode = mask_mode; |
354 | trap->action.port_mask = port_mask; | |
355 | trap->action.cpu_copy_ena = cpu_copy_ena; | |
c8c0ba4f | 356 | |
99348004 VO |
357 | err = ocelot_vcap_filter_replace(ocelot, trap); |
358 | if (err) | |
359 | return err; | |
360 | } | |
0a6f17c6 | 361 | |
c8c0ba4f VO |
362 | return 0; |
363 | } | |
364 | ||
7a29d220 VO |
365 | /* The CPU port module is connected to the Node Processor Interface (NPI). This |
366 | * is the mode through which frames can be injected from and extracted to an | |
367 | * external CPU, over Ethernet. In NXP SoCs, the "external CPU" is the ARM CPU | |
368 | * running Linux, and this forms a DSA setup together with the enetc or fman | |
6ca80638 | 369 | * DSA conduit. |
7a29d220 VO |
370 | */ |
371 | static void felix_npi_port_init(struct ocelot *ocelot, int port) | |
372 | { | |
373 | ocelot->npi = port; | |
374 | ||
375 | ocelot_write(ocelot, QSYS_EXT_CPU_CFG_EXT_CPUQ_MSK_M | | |
376 | QSYS_EXT_CPU_CFG_EXT_CPU_PORT(port), | |
377 | QSYS_EXT_CPU_CFG); | |
378 | ||
379 | /* NPI port Injection/Extraction configuration */ | |
380 | ocelot_fields_write(ocelot, port, SYS_PORT_MODE_INCL_XTR_HDR, | |
381 | ocelot->npi_xtr_prefix); | |
382 | ocelot_fields_write(ocelot, port, SYS_PORT_MODE_INCL_INJ_HDR, | |
383 | ocelot->npi_inj_prefix); | |
384 | ||
385 | /* Disable transmission of pause frames */ | |
386 | ocelot_fields_write(ocelot, port, SYS_PAUSE_CFG_PAUSE_ENA, 0); | |
387 | } | |
388 | ||
389 | static void felix_npi_port_deinit(struct ocelot *ocelot, int port) | |
e21268ef | 390 | { |
7a29d220 VO |
391 | /* Restore hardware defaults */ |
392 | int unused_port = ocelot->num_phys_ports + 2; | |
393 | ||
394 | ocelot->npi = -1; | |
395 | ||
396 | ocelot_write(ocelot, QSYS_EXT_CPU_CFG_EXT_CPU_PORT(unused_port), | |
397 | QSYS_EXT_CPU_CFG); | |
398 | ||
399 | ocelot_fields_write(ocelot, port, SYS_PORT_MODE_INCL_XTR_HDR, | |
400 | OCELOT_TAG_PREFIX_DISABLED); | |
401 | ocelot_fields_write(ocelot, port, SYS_PORT_MODE_INCL_INJ_HDR, | |
402 | OCELOT_TAG_PREFIX_DISABLED); | |
403 | ||
404 | /* Enable transmission of pause frames */ | |
405 | ocelot_fields_write(ocelot, port, SYS_PAUSE_CFG_PAUSE_ENA, 1); | |
406 | } | |
407 | ||
408 | static int felix_tag_npi_setup(struct dsa_switch *ds) | |
409 | { | |
410 | struct dsa_port *dp, *first_cpu_dp = NULL; | |
e21268ef | 411 | struct ocelot *ocelot = ds->priv; |
7a29d220 VO |
412 | |
413 | dsa_switch_for_each_user_port(dp, ds) { | |
414 | if (first_cpu_dp && dp->cpu_dp != first_cpu_dp) { | |
415 | dev_err(ds->dev, "Multiple NPI ports not supported\n"); | |
416 | return -EINVAL; | |
417 | } | |
418 | ||
419 | first_cpu_dp = dp->cpu_dp; | |
420 | } | |
421 | ||
422 | if (!first_cpu_dp) | |
423 | return -EINVAL; | |
424 | ||
425 | felix_npi_port_init(ocelot, first_cpu_dp->index); | |
426 | ||
427 | return 0; | |
428 | } | |
429 | ||
430 | static void felix_tag_npi_teardown(struct dsa_switch *ds) | |
431 | { | |
432 | struct ocelot *ocelot = ds->priv; | |
433 | ||
434 | felix_npi_port_deinit(ocelot, ocelot->npi); | |
435 | } | |
436 | ||
437 | static unsigned long felix_tag_npi_get_host_fwd_mask(struct dsa_switch *ds) | |
438 | { | |
439 | struct ocelot *ocelot = ds->priv; | |
440 | ||
441 | return BIT(ocelot->num_phys_ports); | |
442 | } | |
443 | ||
6ca80638 FF |
444 | static int felix_tag_npi_change_conduit(struct dsa_switch *ds, int port, |
445 | struct net_device *conduit, | |
446 | struct netlink_ext_ack *extack) | |
eca70102 VO |
447 | { |
448 | struct dsa_port *dp = dsa_to_port(ds, port), *other_dp; | |
449 | struct ocelot *ocelot = ds->priv; | |
450 | ||
6ca80638 | 451 | if (netif_is_lag_master(conduit)) { |
eca70102 | 452 | NL_SET_ERR_MSG_MOD(extack, |
6ca80638 | 453 | "LAG DSA conduit only supported using ocelot-8021q"); |
eca70102 VO |
454 | return -EOPNOTSUPP; |
455 | } | |
456 | ||
457 | /* Changing the NPI port breaks user ports still assigned to the old | |
458 | * one, so only allow it while they're down, and don't allow them to | |
459 | * come back up until they're all changed to the new one. | |
460 | */ | |
461 | dsa_switch_for_each_user_port(other_dp, ds) { | |
6ca80638 | 462 | struct net_device *user = other_dp->user; |
eca70102 | 463 | |
6ca80638 FF |
464 | if (other_dp != dp && (user->flags & IFF_UP) && |
465 | dsa_port_to_conduit(other_dp) != conduit) { | |
eca70102 | 466 | NL_SET_ERR_MSG_MOD(extack, |
6ca80638 | 467 | "Cannot change while old conduit still has users"); |
eca70102 VO |
468 | return -EOPNOTSUPP; |
469 | } | |
470 | } | |
471 | ||
472 | felix_npi_port_deinit(ocelot, ocelot->npi); | |
6ca80638 | 473 | felix_npi_port_init(ocelot, felix_cpu_port_for_conduit(ds, conduit)); |
eca70102 VO |
474 | |
475 | return 0; | |
476 | } | |
477 | ||
8c166acb | 478 | /* Alternatively to using the NPI functionality, that same hardware MAC |
6ca80638 | 479 | * connected internally to the enetc or fman DSA conduit can be configured to |
8c166acb VO |
480 | * use the software-defined tag_8021q frame format. As far as the hardware is |
481 | * concerned, it thinks it is a "dumb switch" - the queues of the CPU port | |
482 | * module are now disconnected from it, but can still be accessed through | |
483 | * register-based MMIO. | |
484 | */ | |
7a29d220 VO |
485 | static const struct felix_tag_proto_ops felix_tag_npi_proto_ops = { |
486 | .setup = felix_tag_npi_setup, | |
487 | .teardown = felix_tag_npi_teardown, | |
488 | .get_host_fwd_mask = felix_tag_npi_get_host_fwd_mask, | |
6ca80638 | 489 | .change_conduit = felix_tag_npi_change_conduit, |
7a29d220 VO |
490 | }; |
491 | ||
492 | static int felix_tag_8021q_setup(struct dsa_switch *ds) | |
493 | { | |
494 | struct ocelot *ocelot = ds->priv; | |
c295f983 | 495 | struct dsa_port *dp; |
2960bb14 | 496 | int err; |
e21268ef | 497 | |
7a29d220 VO |
498 | err = dsa_tag_8021q_register(ds, htons(ETH_P_8021AD)); |
499 | if (err) | |
500 | return err; | |
501 | ||
36a0bf44 VO |
502 | dsa_switch_for_each_cpu_port(dp, ds) |
503 | ocelot_port_setup_dsa_8021q_cpu(ocelot, dp->index); | |
504 | ||
c295f983 VO |
505 | dsa_switch_for_each_user_port(dp, ds) |
506 | ocelot_port_assign_dsa_8021q_cpu(ocelot, dp->index, | |
507 | dp->cpu_dp->index); | |
e21268ef | 508 | |
c295f983 | 509 | dsa_switch_for_each_available_port(dp, ds) |
e21268ef VO |
510 | /* This overwrites ocelot_init(): |
511 | * Do not forward BPDU frames to the CPU port module, | |
512 | * for 2 reasons: | |
513 | * - When these packets are injected from the tag_8021q | |
514 | * CPU port, we want them to go out, not loop back | |
515 | * into the system. | |
516 | * - STP traffic ingressing on a user port should go to | |
517 | * the tag_8021q CPU port, not to the hardware CPU | |
518 | * port module. | |
519 | */ | |
520 | ocelot_write_gix(ocelot, | |
521 | ANA_PORT_CPU_FWD_BPDU_CFG_BPDU_REDIR_ENA(0), | |
2960bb14 | 522 | ANA_PORT_CPU_FWD_BPDU_CFG, dp->index); |
e21268ef | 523 | |
99348004 VO |
524 | /* The ownership of the CPU port module's queues might have just been |
525 | * transferred to the tag_8021q tagger from the NPI-based tagger. | |
526 | * So there might still be all sorts of crap in the queues. On the | |
527 | * other hand, the MMIO-based matching of PTP frames is very brittle, | |
528 | * so we need to be careful that there are no extra frames to be | |
529 | * dequeued over MMIO, since we would never know to discard them. | |
530 | */ | |
531 | ocelot_drain_cpu_queue(ocelot, 0); | |
532 | ||
e21268ef | 533 | return 0; |
e21268ef VO |
534 | } |
535 | ||
7a29d220 | 536 | static void felix_tag_8021q_teardown(struct dsa_switch *ds) |
e21268ef VO |
537 | { |
538 | struct ocelot *ocelot = ds->priv; | |
c295f983 | 539 | struct dsa_port *dp; |
e21268ef | 540 | |
c295f983 | 541 | dsa_switch_for_each_available_port(dp, ds) |
e21268ef VO |
542 | /* Restore the logic from ocelot_init: |
543 | * do not forward BPDU frames to the front ports. | |
544 | */ | |
545 | ocelot_write_gix(ocelot, | |
546 | ANA_PORT_CPU_FWD_BPDU_CFG_BPDU_REDIR_ENA(0xffff), | |
547 | ANA_PORT_CPU_FWD_BPDU_CFG, | |
2960bb14 | 548 | dp->index); |
e21268ef | 549 | |
c295f983 VO |
550 | dsa_switch_for_each_user_port(dp, ds) |
551 | ocelot_port_unassign_dsa_8021q_cpu(ocelot, dp->index); | |
adb3dccf | 552 | |
36a0bf44 VO |
553 | dsa_switch_for_each_cpu_port(dp, ds) |
554 | ocelot_port_teardown_dsa_8021q_cpu(ocelot, dp->index); | |
555 | ||
7a29d220 | 556 | dsa_tag_8021q_unregister(ds); |
adb3dccf VO |
557 | } |
558 | ||
7a29d220 | 559 | static unsigned long felix_tag_8021q_get_host_fwd_mask(struct dsa_switch *ds) |
adb3dccf | 560 | { |
7a29d220 VO |
561 | return dsa_cpu_ports(ds); |
562 | } | |
adb3dccf | 563 | |
6ca80638 FF |
564 | static int felix_tag_8021q_change_conduit(struct dsa_switch *ds, int port, |
565 | struct net_device *conduit, | |
566 | struct netlink_ext_ack *extack) | |
eca70102 | 567 | { |
6ca80638 | 568 | int cpu = felix_cpu_port_for_conduit(ds, conduit); |
eca70102 VO |
569 | struct ocelot *ocelot = ds->priv; |
570 | ||
571 | ocelot_port_unassign_dsa_8021q_cpu(ocelot, port); | |
572 | ocelot_port_assign_dsa_8021q_cpu(ocelot, port, cpu); | |
573 | ||
574 | return felix_update_trapping_destinations(ds, true); | |
575 | } | |
576 | ||
7a29d220 VO |
577 | static const struct felix_tag_proto_ops felix_tag_8021q_proto_ops = { |
578 | .setup = felix_tag_8021q_setup, | |
579 | .teardown = felix_tag_8021q_teardown, | |
580 | .get_host_fwd_mask = felix_tag_8021q_get_host_fwd_mask, | |
6ca80638 | 581 | .change_conduit = felix_tag_8021q_change_conduit, |
7a29d220 | 582 | }; |
adb3dccf | 583 | |
7a29d220 VO |
584 | static void felix_set_host_flood(struct dsa_switch *ds, unsigned long mask, |
585 | bool uc, bool mc, bool bc) | |
586 | { | |
587 | struct ocelot *ocelot = ds->priv; | |
588 | unsigned long val; | |
adb3dccf | 589 | |
7a29d220 VO |
590 | val = uc ? mask : 0; |
591 | ocelot_rmw_rix(ocelot, val, mask, ANA_PGID_PGID, PGID_UC); | |
adb3dccf | 592 | |
7a29d220 VO |
593 | val = mc ? mask : 0; |
594 | ocelot_rmw_rix(ocelot, val, mask, ANA_PGID_PGID, PGID_MC); | |
595 | ocelot_rmw_rix(ocelot, val, mask, ANA_PGID_PGID, PGID_MCIPV4); | |
596 | ocelot_rmw_rix(ocelot, val, mask, ANA_PGID_PGID, PGID_MCIPV6); | |
129b7532 VO |
597 | |
598 | val = bc ? mask : 0; | |
599 | ocelot_rmw_rix(ocelot, val, mask, ANA_PGID_PGID, PGID_BC); | |
adb3dccf VO |
600 | } |
601 | ||
7a29d220 VO |
602 | static void |
603 | felix_migrate_host_flood(struct dsa_switch *ds, | |
604 | const struct felix_tag_proto_ops *proto_ops, | |
605 | const struct felix_tag_proto_ops *old_proto_ops) | |
adb3dccf VO |
606 | { |
607 | struct ocelot *ocelot = ds->priv; | |
7a29d220 VO |
608 | struct felix *felix = ocelot_to_felix(ocelot); |
609 | unsigned long mask; | |
adb3dccf | 610 | |
7a29d220 VO |
611 | if (old_proto_ops) { |
612 | mask = old_proto_ops->get_host_fwd_mask(ds); | |
613 | felix_set_host_flood(ds, mask, false, false, false); | |
614 | } | |
adb3dccf | 615 | |
7a29d220 VO |
616 | mask = proto_ops->get_host_fwd_mask(ds); |
617 | felix_set_host_flood(ds, mask, !!felix->host_flood_uc_mask, | |
618 | !!felix->host_flood_mc_mask, true); | |
adb3dccf VO |
619 | } |
620 | ||
7a29d220 VO |
621 | static int felix_migrate_mdbs(struct dsa_switch *ds, |
622 | const struct felix_tag_proto_ops *proto_ops, | |
623 | const struct felix_tag_proto_ops *old_proto_ops) | |
adb3dccf VO |
624 | { |
625 | struct ocelot *ocelot = ds->priv; | |
7a29d220 VO |
626 | unsigned long from, to; |
627 | ||
628 | if (!old_proto_ops) | |
629 | return 0; | |
630 | ||
631 | from = old_proto_ops->get_host_fwd_mask(ds); | |
632 | to = proto_ops->get_host_fwd_mask(ds); | |
adb3dccf | 633 | |
7a29d220 | 634 | return ocelot_migrate_mdbs(ocelot, from, to); |
adb3dccf VO |
635 | } |
636 | ||
7a29d220 VO |
637 | /* Configure the shared hardware resources for a transition between |
638 | * @old_proto_ops and @proto_ops. | |
639 | * Manual migration is needed because as far as DSA is concerned, no change of | |
640 | * the CPU port is taking place here, just of the tagging protocol. | |
641 | */ | |
642 | static int | |
643 | felix_tag_proto_setup_shared(struct dsa_switch *ds, | |
644 | const struct felix_tag_proto_ops *proto_ops, | |
645 | const struct felix_tag_proto_ops *old_proto_ops) | |
adb3dccf | 646 | { |
7a29d220 | 647 | bool using_tag_8021q = (proto_ops == &felix_tag_8021q_proto_ops); |
adb3dccf VO |
648 | int err; |
649 | ||
7a29d220 VO |
650 | err = felix_migrate_mdbs(ds, proto_ops, old_proto_ops); |
651 | if (err) | |
652 | return err; | |
adb3dccf | 653 | |
7a29d220 | 654 | felix_update_trapping_destinations(ds, using_tag_8021q); |
adb3dccf | 655 | |
7a29d220 VO |
656 | felix_migrate_host_flood(ds, proto_ops, old_proto_ops); |
657 | ||
658 | return 0; | |
adb3dccf VO |
659 | } |
660 | ||
e21268ef VO |
661 | /* This always leaves the switch in a consistent state, because although the |
662 | * tag_8021q setup can fail, the NPI setup can't. So either the change is made, | |
663 | * or the restoration is guaranteed to work. | |
664 | */ | |
bacf93b0 | 665 | static int felix_change_tag_protocol(struct dsa_switch *ds, |
adb3dccf VO |
666 | enum dsa_tag_protocol proto) |
667 | { | |
7a29d220 | 668 | const struct felix_tag_proto_ops *old_proto_ops, *proto_ops; |
adb3dccf VO |
669 | struct ocelot *ocelot = ds->priv; |
670 | struct felix *felix = ocelot_to_felix(ocelot); | |
adb3dccf VO |
671 | int err; |
672 | ||
7a29d220 VO |
673 | switch (proto) { |
674 | case DSA_TAG_PROTO_SEVILLE: | |
675 | case DSA_TAG_PROTO_OCELOT: | |
676 | proto_ops = &felix_tag_npi_proto_ops; | |
677 | break; | |
678 | case DSA_TAG_PROTO_OCELOT_8021Q: | |
679 | proto_ops = &felix_tag_8021q_proto_ops; | |
680 | break; | |
681 | default: | |
adb3dccf | 682 | return -EPROTONOSUPPORT; |
7a29d220 | 683 | } |
adb3dccf | 684 | |
7a29d220 | 685 | old_proto_ops = felix->tag_proto_ops; |
00fa91bc | 686 | |
4c46bb49 VO |
687 | if (proto_ops == old_proto_ops) |
688 | return 0; | |
689 | ||
7a29d220 VO |
690 | err = proto_ops->setup(ds); |
691 | if (err) | |
692 | goto setup_failed; | |
adb3dccf | 693 | |
7a29d220 VO |
694 | err = felix_tag_proto_setup_shared(ds, proto_ops, old_proto_ops); |
695 | if (err) | |
696 | goto setup_shared_failed; | |
adb3dccf | 697 | |
7a29d220 VO |
698 | if (old_proto_ops) |
699 | old_proto_ops->teardown(ds); | |
700 | ||
701 | felix->tag_proto_ops = proto_ops; | |
adb3dccf VO |
702 | felix->tag_proto = proto; |
703 | ||
704 | return 0; | |
7a29d220 VO |
705 | |
706 | setup_shared_failed: | |
707 | proto_ops->teardown(ds); | |
708 | setup_failed: | |
709 | return err; | |
adb3dccf VO |
710 | } |
711 | ||
56051948 | 712 | static enum dsa_tag_protocol felix_get_tag_protocol(struct dsa_switch *ds, |
4d776482 FF |
713 | int port, |
714 | enum dsa_tag_protocol mp) | |
56051948 | 715 | { |
adb3dccf VO |
716 | struct ocelot *ocelot = ds->priv; |
717 | struct felix *felix = ocelot_to_felix(ocelot); | |
718 | ||
719 | return felix->tag_proto; | |
56051948 VO |
720 | } |
721 | ||
72c3b0c7 VO |
722 | static void felix_port_set_host_flood(struct dsa_switch *ds, int port, |
723 | bool uc, bool mc) | |
724 | { | |
725 | struct ocelot *ocelot = ds->priv; | |
726 | struct felix *felix = ocelot_to_felix(ocelot); | |
7a29d220 | 727 | unsigned long mask; |
72c3b0c7 VO |
728 | |
729 | if (uc) | |
730 | felix->host_flood_uc_mask |= BIT(port); | |
731 | else | |
732 | felix->host_flood_uc_mask &= ~BIT(port); | |
733 | ||
734 | if (mc) | |
735 | felix->host_flood_mc_mask |= BIT(port); | |
736 | else | |
737 | felix->host_flood_mc_mask &= ~BIT(port); | |
738 | ||
7a29d220 VO |
739 | mask = felix->tag_proto_ops->get_host_fwd_mask(ds); |
740 | felix_set_host_flood(ds, mask, !!felix->host_flood_uc_mask, | |
741 | !!felix->host_flood_mc_mask, true); | |
72c3b0c7 VO |
742 | } |
743 | ||
6ca80638 FF |
744 | static int felix_port_change_conduit(struct dsa_switch *ds, int port, |
745 | struct net_device *conduit, | |
746 | struct netlink_ext_ack *extack) | |
eca70102 VO |
747 | { |
748 | struct ocelot *ocelot = ds->priv; | |
749 | struct felix *felix = ocelot_to_felix(ocelot); | |
750 | ||
6ca80638 | 751 | return felix->tag_proto_ops->change_conduit(ds, port, conduit, extack); |
eca70102 VO |
752 | } |
753 | ||
56051948 VO |
754 | static int felix_set_ageing_time(struct dsa_switch *ds, |
755 | unsigned int ageing_time) | |
756 | { | |
757 | struct ocelot *ocelot = ds->priv; | |
758 | ||
759 | ocelot_set_ageing_time(ocelot, ageing_time); | |
760 | ||
761 | return 0; | |
762 | } | |
763 | ||
5cad43a5 VO |
764 | static void felix_port_fast_age(struct dsa_switch *ds, int port) |
765 | { | |
766 | struct ocelot *ocelot = ds->priv; | |
767 | int err; | |
768 | ||
769 | err = ocelot_mact_flush(ocelot, port); | |
770 | if (err) | |
771 | dev_err(ds->dev, "Flushing MAC table on port %d returned %pe\n", | |
772 | port, ERR_PTR(err)); | |
773 | } | |
774 | ||
56051948 VO |
775 | static int felix_fdb_dump(struct dsa_switch *ds, int port, |
776 | dsa_fdb_dump_cb_t *cb, void *data) | |
777 | { | |
778 | struct ocelot *ocelot = ds->priv; | |
779 | ||
780 | return ocelot_fdb_dump(ocelot, port, cb, data); | |
781 | } | |
782 | ||
783 | static int felix_fdb_add(struct dsa_switch *ds, int port, | |
c2693363 VO |
784 | const unsigned char *addr, u16 vid, |
785 | struct dsa_db db) | |
56051948 | 786 | { |
54c31984 | 787 | struct net_device *bridge_dev = felix_classify_db(db); |
e9b3ba43 | 788 | struct dsa_port *dp = dsa_to_port(ds, port); |
56051948 | 789 | struct ocelot *ocelot = ds->priv; |
56051948 | 790 | |
54c31984 VO |
791 | if (IS_ERR(bridge_dev)) |
792 | return PTR_ERR(bridge_dev); | |
793 | ||
e9b3ba43 | 794 | if (dsa_port_is_cpu(dp) && !bridge_dev && |
7e580490 VO |
795 | dsa_fdb_present_in_other_db(ds, port, addr, vid, db)) |
796 | return 0; | |
797 | ||
e9b3ba43 VO |
798 | if (dsa_port_is_cpu(dp)) |
799 | port = PGID_CPU; | |
800 | ||
54c31984 | 801 | return ocelot_fdb_add(ocelot, port, addr, vid, bridge_dev); |
56051948 VO |
802 | } |
803 | ||
804 | static int felix_fdb_del(struct dsa_switch *ds, int port, | |
c2693363 VO |
805 | const unsigned char *addr, u16 vid, |
806 | struct dsa_db db) | |
56051948 | 807 | { |
54c31984 | 808 | struct net_device *bridge_dev = felix_classify_db(db); |
e9b3ba43 | 809 | struct dsa_port *dp = dsa_to_port(ds, port); |
56051948 VO |
810 | struct ocelot *ocelot = ds->priv; |
811 | ||
54c31984 VO |
812 | if (IS_ERR(bridge_dev)) |
813 | return PTR_ERR(bridge_dev); | |
814 | ||
e9b3ba43 | 815 | if (dsa_port_is_cpu(dp) && !bridge_dev && |
7e580490 VO |
816 | dsa_fdb_present_in_other_db(ds, port, addr, vid, db)) |
817 | return 0; | |
818 | ||
e9b3ba43 VO |
819 | if (dsa_port_is_cpu(dp)) |
820 | port = PGID_CPU; | |
821 | ||
54c31984 | 822 | return ocelot_fdb_del(ocelot, port, addr, vid, bridge_dev); |
56051948 VO |
823 | } |
824 | ||
961d8b69 | 825 | static int felix_lag_fdb_add(struct dsa_switch *ds, struct dsa_lag lag, |
c2693363 VO |
826 | const unsigned char *addr, u16 vid, |
827 | struct dsa_db db) | |
961d8b69 | 828 | { |
54c31984 | 829 | struct net_device *bridge_dev = felix_classify_db(db); |
961d8b69 VO |
830 | struct ocelot *ocelot = ds->priv; |
831 | ||
54c31984 VO |
832 | if (IS_ERR(bridge_dev)) |
833 | return PTR_ERR(bridge_dev); | |
834 | ||
835 | return ocelot_lag_fdb_add(ocelot, lag.dev, addr, vid, bridge_dev); | |
961d8b69 VO |
836 | } |
837 | ||
838 | static int felix_lag_fdb_del(struct dsa_switch *ds, struct dsa_lag lag, | |
c2693363 VO |
839 | const unsigned char *addr, u16 vid, |
840 | struct dsa_db db) | |
961d8b69 | 841 | { |
54c31984 | 842 | struct net_device *bridge_dev = felix_classify_db(db); |
961d8b69 VO |
843 | struct ocelot *ocelot = ds->priv; |
844 | ||
54c31984 VO |
845 | if (IS_ERR(bridge_dev)) |
846 | return PTR_ERR(bridge_dev); | |
847 | ||
848 | return ocelot_lag_fdb_del(ocelot, lag.dev, addr, vid, bridge_dev); | |
961d8b69 VO |
849 | } |
850 | ||
a52b2da7 | 851 | static int felix_mdb_add(struct dsa_switch *ds, int port, |
c2693363 VO |
852 | const struct switchdev_obj_port_mdb *mdb, |
853 | struct dsa_db db) | |
209edf95 | 854 | { |
54c31984 | 855 | struct net_device *bridge_dev = felix_classify_db(db); |
209edf95 VO |
856 | struct ocelot *ocelot = ds->priv; |
857 | ||
54c31984 VO |
858 | if (IS_ERR(bridge_dev)) |
859 | return PTR_ERR(bridge_dev); | |
860 | ||
7e580490 VO |
861 | if (dsa_is_cpu_port(ds, port) && !bridge_dev && |
862 | dsa_mdb_present_in_other_db(ds, port, mdb, db)) | |
863 | return 0; | |
864 | ||
0ddf83cd VO |
865 | if (port == ocelot->npi) |
866 | port = ocelot->num_phys_ports; | |
867 | ||
54c31984 | 868 | return ocelot_port_mdb_add(ocelot, port, mdb, bridge_dev); |
209edf95 VO |
869 | } |
870 | ||
871 | static int felix_mdb_del(struct dsa_switch *ds, int port, | |
c2693363 VO |
872 | const struct switchdev_obj_port_mdb *mdb, |
873 | struct dsa_db db) | |
209edf95 | 874 | { |
54c31984 | 875 | struct net_device *bridge_dev = felix_classify_db(db); |
209edf95 VO |
876 | struct ocelot *ocelot = ds->priv; |
877 | ||
54c31984 VO |
878 | if (IS_ERR(bridge_dev)) |
879 | return PTR_ERR(bridge_dev); | |
880 | ||
7e580490 VO |
881 | if (dsa_is_cpu_port(ds, port) && !bridge_dev && |
882 | dsa_mdb_present_in_other_db(ds, port, mdb, db)) | |
883 | return 0; | |
884 | ||
0ddf83cd VO |
885 | if (port == ocelot->npi) |
886 | port = ocelot->num_phys_ports; | |
887 | ||
54c31984 | 888 | return ocelot_port_mdb_del(ocelot, port, mdb, bridge_dev); |
209edf95 VO |
889 | } |
890 | ||
56051948 VO |
891 | static void felix_bridge_stp_state_set(struct dsa_switch *ds, int port, |
892 | u8 state) | |
893 | { | |
894 | struct ocelot *ocelot = ds->priv; | |
895 | ||
896 | return ocelot_bridge_stp_state_set(ocelot, port, state); | |
897 | } | |
898 | ||
421741ea VO |
899 | static int felix_pre_bridge_flags(struct dsa_switch *ds, int port, |
900 | struct switchdev_brport_flags val, | |
901 | struct netlink_ext_ack *extack) | |
902 | { | |
903 | struct ocelot *ocelot = ds->priv; | |
904 | ||
905 | return ocelot_port_pre_bridge_flags(ocelot, port, val); | |
906 | } | |
907 | ||
908 | static int felix_bridge_flags(struct dsa_switch *ds, int port, | |
909 | struct switchdev_brport_flags val, | |
910 | struct netlink_ext_ack *extack) | |
911 | { | |
912 | struct ocelot *ocelot = ds->priv; | |
913 | ||
910ee6cc VO |
914 | if (port == ocelot->npi) |
915 | port = ocelot->num_phys_ports; | |
916 | ||
421741ea VO |
917 | ocelot_port_bridge_flags(ocelot, port, val); |
918 | ||
919 | return 0; | |
920 | } | |
921 | ||
56051948 | 922 | static int felix_bridge_join(struct dsa_switch *ds, int port, |
06b9cce4 VO |
923 | struct dsa_bridge bridge, bool *tx_fwd_offload, |
924 | struct netlink_ext_ack *extack) | |
56051948 VO |
925 | { |
926 | struct ocelot *ocelot = ds->priv; | |
927 | ||
54c31984 VO |
928 | return ocelot_port_bridge_join(ocelot, port, bridge.dev, bridge.num, |
929 | extack); | |
56051948 VO |
930 | } |
931 | ||
932 | static void felix_bridge_leave(struct dsa_switch *ds, int port, | |
d3eed0e5 | 933 | struct dsa_bridge bridge) |
56051948 VO |
934 | { |
935 | struct ocelot *ocelot = ds->priv; | |
936 | ||
d3eed0e5 | 937 | ocelot_port_bridge_leave(ocelot, port, bridge.dev); |
56051948 VO |
938 | } |
939 | ||
8fe6832e | 940 | static int felix_lag_join(struct dsa_switch *ds, int port, |
dedd6a00 | 941 | struct dsa_lag lag, |
2e359b00 VO |
942 | struct netdev_lag_upper_info *info, |
943 | struct netlink_ext_ack *extack) | |
8fe6832e VO |
944 | { |
945 | struct ocelot *ocelot = ds->priv; | |
eca70102 | 946 | int err; |
8fe6832e | 947 | |
eca70102 VO |
948 | err = ocelot_port_lag_join(ocelot, port, lag.dev, info, extack); |
949 | if (err) | |
950 | return err; | |
951 | ||
952 | /* Update the logical LAG port that serves as tag_8021q CPU port */ | |
953 | if (!dsa_is_cpu_port(ds, port)) | |
954 | return 0; | |
955 | ||
6ca80638 | 956 | return felix_port_change_conduit(ds, port, lag.dev, extack); |
8fe6832e VO |
957 | } |
958 | ||
959 | static int felix_lag_leave(struct dsa_switch *ds, int port, | |
dedd6a00 | 960 | struct dsa_lag lag) |
8fe6832e VO |
961 | { |
962 | struct ocelot *ocelot = ds->priv; | |
963 | ||
dedd6a00 | 964 | ocelot_port_lag_leave(ocelot, port, lag.dev); |
8fe6832e | 965 | |
eca70102 VO |
966 | /* Update the logical LAG port that serves as tag_8021q CPU port */ |
967 | if (!dsa_is_cpu_port(ds, port)) | |
968 | return 0; | |
969 | ||
6ca80638 | 970 | return felix_port_change_conduit(ds, port, lag.dev, NULL); |
8fe6832e VO |
971 | } |
972 | ||
973 | static int felix_lag_change(struct dsa_switch *ds, int port) | |
974 | { | |
975 | struct dsa_port *dp = dsa_to_port(ds, port); | |
976 | struct ocelot *ocelot = ds->priv; | |
977 | ||
978 | ocelot_port_lag_change(ocelot, port, dp->lag_tx_enabled); | |
979 | ||
980 | return 0; | |
981 | } | |
982 | ||
56051948 | 983 | static int felix_vlan_prepare(struct dsa_switch *ds, int port, |
01af940e VO |
984 | const struct switchdev_obj_port_vlan *vlan, |
985 | struct netlink_ext_ack *extack) | |
56051948 | 986 | { |
2f0402fe | 987 | struct ocelot *ocelot = ds->priv; |
b7a9e0da | 988 | u16 flags = vlan->flags; |
2f0402fe | 989 | |
9a720680 VO |
990 | /* Ocelot switches copy frames as-is to the CPU, so the flags: |
991 | * egress-untagged or not, pvid or not, make no difference. This | |
992 | * behavior is already better than what DSA just tries to approximate | |
993 | * when it installs the VLAN with the same flags on the CPU port. | |
994 | * Just accept any configuration, and don't let ocelot deny installing | |
995 | * multiple native VLANs on the NPI port, because the switch doesn't | |
996 | * look at the port tag settings towards the NPI interface anyway. | |
997 | */ | |
998 | if (port == ocelot->npi) | |
999 | return 0; | |
1000 | ||
b7a9e0da VO |
1001 | return ocelot_vlan_prepare(ocelot, port, vlan->vid, |
1002 | flags & BRIDGE_VLAN_INFO_PVID, | |
01af940e VO |
1003 | flags & BRIDGE_VLAN_INFO_UNTAGGED, |
1004 | extack); | |
56051948 VO |
1005 | } |
1006 | ||
89153ed6 VO |
1007 | static int felix_vlan_filtering(struct dsa_switch *ds, int port, bool enabled, |
1008 | struct netlink_ext_ack *extack) | |
56051948 VO |
1009 | { |
1010 | struct ocelot *ocelot = ds->priv; | |
1011 | ||
3b95d1b2 | 1012 | return ocelot_port_vlan_filtering(ocelot, port, enabled, extack); |
56051948 VO |
1013 | } |
1014 | ||
1958d581 | 1015 | static int felix_vlan_add(struct dsa_switch *ds, int port, |
31046a5f VO |
1016 | const struct switchdev_obj_port_vlan *vlan, |
1017 | struct netlink_ext_ack *extack) | |
56051948 VO |
1018 | { |
1019 | struct ocelot *ocelot = ds->priv; | |
183be6f9 | 1020 | u16 flags = vlan->flags; |
1958d581 VO |
1021 | int err; |
1022 | ||
01af940e | 1023 | err = felix_vlan_prepare(ds, port, vlan, extack); |
1958d581 VO |
1024 | if (err) |
1025 | return err; | |
56051948 | 1026 | |
1958d581 VO |
1027 | return ocelot_vlan_add(ocelot, port, vlan->vid, |
1028 | flags & BRIDGE_VLAN_INFO_PVID, | |
1029 | flags & BRIDGE_VLAN_INFO_UNTAGGED); | |
56051948 VO |
1030 | } |
1031 | ||
1032 | static int felix_vlan_del(struct dsa_switch *ds, int port, | |
1033 | const struct switchdev_obj_port_vlan *vlan) | |
1034 | { | |
1035 | struct ocelot *ocelot = ds->priv; | |
b7a9e0da VO |
1036 | |
1037 | return ocelot_vlan_del(ocelot, port, vlan->vid); | |
56051948 VO |
1038 | } |
1039 | ||
79fda660 RKO |
1040 | static void felix_phylink_get_caps(struct dsa_switch *ds, int port, |
1041 | struct phylink_config *config) | |
1042 | { | |
1043 | struct ocelot *ocelot = ds->priv; | |
1044 | ||
3e7e7832 VO |
1045 | config->mac_capabilities = MAC_ASYM_PAUSE | MAC_SYM_PAUSE | |
1046 | MAC_10 | MAC_100 | MAC_1000FD | | |
1047 | MAC_2500FD; | |
1048 | ||
79fda660 RKO |
1049 | __set_bit(ocelot->ports[port]->phy_mode, |
1050 | config->supported_interfaces); | |
1051 | } | |
1052 | ||
544435c9 CF |
1053 | static void felix_phylink_mac_config(struct dsa_switch *ds, int port, |
1054 | unsigned int mode, | |
1055 | const struct phylink_link_state *state) | |
1056 | { | |
1057 | struct ocelot *ocelot = ds->priv; | |
1058 | struct felix *felix = ocelot_to_felix(ocelot); | |
1059 | ||
1060 | if (felix->info->phylink_mac_config) | |
1061 | felix->info->phylink_mac_config(ocelot, port, mode, state); | |
1062 | } | |
1063 | ||
864ba485 RKO |
1064 | static struct phylink_pcs *felix_phylink_mac_select_pcs(struct dsa_switch *ds, |
1065 | int port, | |
1066 | phy_interface_t iface) | |
7e14a2dc VO |
1067 | { |
1068 | struct ocelot *ocelot = ds->priv; | |
1069 | struct felix *felix = ocelot_to_felix(ocelot); | |
864ba485 | 1070 | struct phylink_pcs *pcs = NULL; |
7e14a2dc | 1071 | |
49af6a76 | 1072 | if (felix->pcs && felix->pcs[port]) |
864ba485 RKO |
1073 | pcs = felix->pcs[port]; |
1074 | ||
1075 | return pcs; | |
7e14a2dc VO |
1076 | } |
1077 | ||
1078 | static void felix_phylink_mac_link_down(struct dsa_switch *ds, int port, | |
1079 | unsigned int link_an_mode, | |
1080 | phy_interface_t interface) | |
1081 | { | |
1082 | struct ocelot *ocelot = ds->priv; | |
1dc6a2a0 CF |
1083 | struct felix *felix; |
1084 | ||
1085 | felix = ocelot_to_felix(ocelot); | |
eb4733d7 | 1086 | |
e6e12df6 | 1087 | ocelot_phylink_mac_link_down(ocelot, port, link_an_mode, interface, |
1dc6a2a0 | 1088 | felix->info->quirks); |
7e14a2dc VO |
1089 | } |
1090 | ||
1091 | static void felix_phylink_mac_link_up(struct dsa_switch *ds, int port, | |
1092 | unsigned int link_an_mode, | |
1093 | phy_interface_t interface, | |
1094 | struct phy_device *phydev, | |
1095 | int speed, int duplex, | |
1096 | bool tx_pause, bool rx_pause) | |
bdeced75 VO |
1097 | { |
1098 | struct ocelot *ocelot = ds->priv; | |
bdeced75 | 1099 | struct felix *felix = ocelot_to_felix(ocelot); |
bdeced75 | 1100 | |
e6e12df6 VO |
1101 | ocelot_phylink_mac_link_up(ocelot, port, phydev, link_an_mode, |
1102 | interface, speed, duplex, tx_pause, rx_pause, | |
1dc6a2a0 | 1103 | felix->info->quirks); |
7e14a2dc | 1104 | |
7e14a2dc VO |
1105 | if (felix->info->port_sched_speed_set) |
1106 | felix->info->port_sched_speed_set(ocelot, port, speed); | |
bdeced75 VO |
1107 | } |
1108 | ||
eca70102 VO |
1109 | static int felix_port_enable(struct dsa_switch *ds, int port, |
1110 | struct phy_device *phydev) | |
1111 | { | |
1112 | struct dsa_port *dp = dsa_to_port(ds, port); | |
1113 | struct ocelot *ocelot = ds->priv; | |
1114 | ||
1115 | if (!dsa_port_is_user(dp)) | |
1116 | return 0; | |
1117 | ||
1118 | if (ocelot->npi >= 0) { | |
6ca80638 | 1119 | struct net_device *conduit = dsa_port_to_conduit(dp); |
eca70102 | 1120 | |
6ca80638 FF |
1121 | if (felix_cpu_port_for_conduit(ds, conduit) != ocelot->npi) { |
1122 | dev_err(ds->dev, "Multiple conduits are not allowed\n"); | |
eca70102 VO |
1123 | return -EINVAL; |
1124 | } | |
1125 | } | |
1126 | ||
1127 | return 0; | |
1128 | } | |
1129 | ||
bd2b3161 XY |
1130 | static void felix_port_qos_map_init(struct ocelot *ocelot, int port) |
1131 | { | |
1132 | int i; | |
1133 | ||
1134 | ocelot_rmw_gix(ocelot, | |
1135 | ANA_PORT_QOS_CFG_QOS_PCP_ENA, | |
1136 | ANA_PORT_QOS_CFG_QOS_PCP_ENA, | |
1137 | ANA_PORT_QOS_CFG, | |
1138 | port); | |
1139 | ||
70d39a6e | 1140 | for (i = 0; i < OCELOT_NUM_TC * 2; i++) { |
bd2b3161 XY |
1141 | ocelot_rmw_ix(ocelot, |
1142 | (ANA_PORT_PCP_DEI_MAP_DP_PCP_DEI_VAL & i) | | |
1143 | ANA_PORT_PCP_DEI_MAP_QOS_PCP_DEI_VAL(i), | |
1144 | ANA_PORT_PCP_DEI_MAP_DP_PCP_DEI_VAL | | |
1145 | ANA_PORT_PCP_DEI_MAP_QOS_PCP_DEI_VAL_M, | |
1146 | ANA_PORT_PCP_DEI_MAP, | |
1147 | port, i); | |
1148 | } | |
1149 | } | |
1150 | ||
776b71e5 VO |
1151 | static void felix_get_stats64(struct dsa_switch *ds, int port, |
1152 | struct rtnl_link_stats64 *stats) | |
1153 | { | |
1154 | struct ocelot *ocelot = ds->priv; | |
1155 | ||
1156 | ocelot_port_get_stats64(ocelot, port, stats); | |
1157 | } | |
1158 | ||
e32036e1 VO |
1159 | static void felix_get_pause_stats(struct dsa_switch *ds, int port, |
1160 | struct ethtool_pause_stats *pause_stats) | |
1161 | { | |
1162 | struct ocelot *ocelot = ds->priv; | |
1163 | ||
1164 | ocelot_port_get_pause_stats(ocelot, port, pause_stats); | |
1165 | } | |
1166 | ||
1167 | static void felix_get_rmon_stats(struct dsa_switch *ds, int port, | |
1168 | struct ethtool_rmon_stats *rmon_stats, | |
1169 | const struct ethtool_rmon_hist_range **ranges) | |
1170 | { | |
1171 | struct ocelot *ocelot = ds->priv; | |
1172 | ||
1173 | ocelot_port_get_rmon_stats(ocelot, port, rmon_stats, ranges); | |
1174 | } | |
1175 | ||
1176 | static void felix_get_eth_ctrl_stats(struct dsa_switch *ds, int port, | |
1177 | struct ethtool_eth_ctrl_stats *ctrl_stats) | |
1178 | { | |
1179 | struct ocelot *ocelot = ds->priv; | |
1180 | ||
1181 | ocelot_port_get_eth_ctrl_stats(ocelot, port, ctrl_stats); | |
1182 | } | |
1183 | ||
1184 | static void felix_get_eth_mac_stats(struct dsa_switch *ds, int port, | |
1185 | struct ethtool_eth_mac_stats *mac_stats) | |
1186 | { | |
1187 | struct ocelot *ocelot = ds->priv; | |
1188 | ||
1189 | ocelot_port_get_eth_mac_stats(ocelot, port, mac_stats); | |
1190 | } | |
1191 | ||
1192 | static void felix_get_eth_phy_stats(struct dsa_switch *ds, int port, | |
1193 | struct ethtool_eth_phy_stats *phy_stats) | |
1194 | { | |
1195 | struct ocelot *ocelot = ds->priv; | |
1196 | ||
1197 | ocelot_port_get_eth_phy_stats(ocelot, port, phy_stats); | |
1198 | } | |
1199 | ||
56051948 VO |
1200 | static void felix_get_strings(struct dsa_switch *ds, int port, |
1201 | u32 stringset, u8 *data) | |
1202 | { | |
1203 | struct ocelot *ocelot = ds->priv; | |
1204 | ||
1205 | return ocelot_get_strings(ocelot, port, stringset, data); | |
1206 | } | |
1207 | ||
1208 | static void felix_get_ethtool_stats(struct dsa_switch *ds, int port, u64 *data) | |
1209 | { | |
1210 | struct ocelot *ocelot = ds->priv; | |
1211 | ||
1212 | ocelot_get_ethtool_stats(ocelot, port, data); | |
1213 | } | |
1214 | ||
1215 | static int felix_get_sset_count(struct dsa_switch *ds, int port, int sset) | |
1216 | { | |
1217 | struct ocelot *ocelot = ds->priv; | |
1218 | ||
1219 | return ocelot_get_sset_count(ocelot, port, sset); | |
1220 | } | |
1221 | ||
1222 | static int felix_get_ts_info(struct dsa_switch *ds, int port, | |
1223 | struct ethtool_ts_info *info) | |
1224 | { | |
1225 | struct ocelot *ocelot = ds->priv; | |
1226 | ||
1227 | return ocelot_get_ts_info(ocelot, port, info); | |
1228 | } | |
1229 | ||
acf242fc CF |
1230 | static const u32 felix_phy_match_table[PHY_INTERFACE_MODE_MAX] = { |
1231 | [PHY_INTERFACE_MODE_INTERNAL] = OCELOT_PORT_MODE_INTERNAL, | |
1232 | [PHY_INTERFACE_MODE_SGMII] = OCELOT_PORT_MODE_SGMII, | |
1233 | [PHY_INTERFACE_MODE_QSGMII] = OCELOT_PORT_MODE_QSGMII, | |
1234 | [PHY_INTERFACE_MODE_USXGMII] = OCELOT_PORT_MODE_USXGMII, | |
11ecf341 | 1235 | [PHY_INTERFACE_MODE_1000BASEX] = OCELOT_PORT_MODE_1000BASEX, |
acf242fc CF |
1236 | [PHY_INTERFACE_MODE_2500BASEX] = OCELOT_PORT_MODE_2500BASEX, |
1237 | }; | |
1238 | ||
1239 | static int felix_validate_phy_mode(struct felix *felix, int port, | |
1240 | phy_interface_t phy_mode) | |
1241 | { | |
1242 | u32 modes = felix->info->port_modes[port]; | |
1243 | ||
1244 | if (felix_phy_match_table[phy_mode] & modes) | |
1245 | return 0; | |
1246 | return -EOPNOTSUPP; | |
1247 | } | |
1248 | ||
bdeced75 VO |
1249 | static int felix_parse_ports_node(struct felix *felix, |
1250 | struct device_node *ports_node, | |
1251 | phy_interface_t *port_phy_modes) | |
1252 | { | |
bdeced75 VO |
1253 | struct device *dev = felix->ocelot.dev; |
1254 | struct device_node *child; | |
1255 | ||
37fe45ad | 1256 | for_each_available_child_of_node(ports_node, child) { |
bdeced75 VO |
1257 | phy_interface_t phy_mode; |
1258 | u32 port; | |
1259 | int err; | |
1260 | ||
1261 | /* Get switch port number from DT */ | |
1262 | if (of_property_read_u32(child, "reg", &port) < 0) { | |
1263 | dev_err(dev, "Port number not defined in device tree " | |
1264 | "(property \"reg\")\n"); | |
1265 | of_node_put(child); | |
1266 | return -ENODEV; | |
1267 | } | |
1268 | ||
1269 | /* Get PHY mode from DT */ | |
1270 | err = of_get_phy_mode(child, &phy_mode); | |
1271 | if (err) { | |
1272 | dev_err(dev, "Failed to read phy-mode or " | |
1273 | "phy-interface-type property for port %d\n", | |
1274 | port); | |
1275 | of_node_put(child); | |
1276 | return -ENODEV; | |
1277 | } | |
1278 | ||
acf242fc | 1279 | err = felix_validate_phy_mode(felix, port, phy_mode); |
bdeced75 | 1280 | if (err < 0) { |
de879a01 CF |
1281 | dev_info(dev, "Unsupported PHY mode %s on port %d\n", |
1282 | phy_modes(phy_mode), port); | |
de879a01 CF |
1283 | |
1284 | /* Leave port_phy_modes[port] = 0, which is also | |
1285 | * PHY_INTERFACE_MODE_NA. This will perform a | |
1286 | * best-effort to bring up as many ports as possible. | |
1287 | */ | |
1288 | continue; | |
bdeced75 VO |
1289 | } |
1290 | ||
1291 | port_phy_modes[port] = phy_mode; | |
1292 | } | |
1293 | ||
1294 | return 0; | |
1295 | } | |
1296 | ||
1297 | static int felix_parse_dt(struct felix *felix, phy_interface_t *port_phy_modes) | |
1298 | { | |
1299 | struct device *dev = felix->ocelot.dev; | |
1300 | struct device_node *switch_node; | |
1301 | struct device_node *ports_node; | |
1302 | int err; | |
1303 | ||
1304 | switch_node = dev->of_node; | |
1305 | ||
1306 | ports_node = of_get_child_by_name(switch_node, "ports"); | |
abecbfcd VO |
1307 | if (!ports_node) |
1308 | ports_node = of_get_child_by_name(switch_node, "ethernet-ports"); | |
bdeced75 | 1309 | if (!ports_node) { |
abecbfcd | 1310 | dev_err(dev, "Incorrect bindings: absent \"ports\" or \"ethernet-ports\" node\n"); |
bdeced75 VO |
1311 | return -ENODEV; |
1312 | } | |
1313 | ||
1314 | err = felix_parse_ports_node(felix, ports_node, port_phy_modes); | |
1315 | of_node_put(ports_node); | |
1316 | ||
1317 | return err; | |
1318 | } | |
1319 | ||
1109b97b VO |
1320 | static struct regmap *felix_request_regmap_by_name(struct felix *felix, |
1321 | const char *resource_name) | |
1322 | { | |
1323 | struct ocelot *ocelot = &felix->ocelot; | |
1324 | struct resource res; | |
1325 | int i; | |
1326 | ||
dc454fa4 CF |
1327 | /* In an MFD configuration, regmaps are registered directly to the |
1328 | * parent device before the child devices are probed, so there is no | |
1329 | * need to initialize a new one. | |
1330 | */ | |
1331 | if (!felix->info->resources) | |
1332 | return dev_get_regmap(ocelot->dev->parent, resource_name); | |
1333 | ||
1109b97b VO |
1334 | for (i = 0; i < felix->info->num_resources; i++) { |
1335 | if (strcmp(resource_name, felix->info->resources[i].name)) | |
1336 | continue; | |
1337 | ||
1338 | memcpy(&res, &felix->info->resources[i], sizeof(res)); | |
1339 | res.start += felix->switch_base; | |
1340 | res.end += felix->switch_base; | |
1341 | ||
1342 | return ocelot_regmap_init(ocelot, &res); | |
1343 | } | |
1344 | ||
1345 | return ERR_PTR(-ENOENT); | |
1346 | } | |
1347 | ||
1348 | static struct regmap *felix_request_regmap(struct felix *felix, | |
1349 | enum ocelot_target target) | |
1350 | { | |
1351 | const char *resource_name = felix->info->resource_names[target]; | |
1352 | ||
1353 | /* If the driver didn't provide a resource name for the target, | |
1354 | * the resource is optional. | |
1355 | */ | |
1356 | if (!resource_name) | |
1357 | return NULL; | |
1358 | ||
1359 | return felix_request_regmap_by_name(felix, resource_name); | |
1360 | } | |
1361 | ||
1362 | static struct regmap *felix_request_port_regmap(struct felix *felix, int port) | |
1363 | { | |
1364 | char resource_name[32]; | |
1365 | ||
1366 | sprintf(resource_name, "port%d", port); | |
1367 | ||
1368 | return felix_request_regmap_by_name(felix, resource_name); | |
1369 | } | |
1370 | ||
56051948 VO |
1371 | static int felix_init_structs(struct felix *felix, int num_phys_ports) |
1372 | { | |
1373 | struct ocelot *ocelot = &felix->ocelot; | |
bdeced75 | 1374 | phy_interface_t *port_phy_modes; |
1109b97b | 1375 | struct regmap *target; |
56051948 VO |
1376 | int port, i, err; |
1377 | ||
1378 | ocelot->num_phys_ports = num_phys_ports; | |
1379 | ocelot->ports = devm_kcalloc(ocelot->dev, num_phys_ports, | |
1380 | sizeof(struct ocelot_port *), GFP_KERNEL); | |
1381 | if (!ocelot->ports) | |
1382 | return -ENOMEM; | |
1383 | ||
1384 | ocelot->map = felix->info->map; | |
21ce7f3e | 1385 | ocelot->num_mact_rows = felix->info->num_mact_rows; |
07d985ee | 1386 | ocelot->vcap = felix->info->vcap; |
77043c37 XY |
1387 | ocelot->vcap_pol.base = felix->info->vcap_pol_base; |
1388 | ocelot->vcap_pol.max = felix->info->vcap_pol_max; | |
1389 | ocelot->vcap_pol.base2 = felix->info->vcap_pol_base2; | |
1390 | ocelot->vcap_pol.max2 = felix->info->vcap_pol_max2; | |
56051948 | 1391 | ocelot->ops = felix->info->ops; |
cacea62f VO |
1392 | ocelot->npi_inj_prefix = OCELOT_TAG_PREFIX_SHORT; |
1393 | ocelot->npi_xtr_prefix = OCELOT_TAG_PREFIX_SHORT; | |
f59fd9ca | 1394 | ocelot->devlink = felix->ds->devlink; |
56051948 | 1395 | |
bdeced75 VO |
1396 | port_phy_modes = kcalloc(num_phys_ports, sizeof(phy_interface_t), |
1397 | GFP_KERNEL); | |
1398 | if (!port_phy_modes) | |
1399 | return -ENOMEM; | |
1400 | ||
1401 | err = felix_parse_dt(felix, port_phy_modes); | |
1402 | if (err) { | |
1403 | kfree(port_phy_modes); | |
1404 | return err; | |
1405 | } | |
1406 | ||
56051948 | 1407 | for (i = 0; i < TARGET_MAX; i++) { |
1109b97b | 1408 | target = felix_request_regmap(felix, i); |
56051948 VO |
1409 | if (IS_ERR(target)) { |
1410 | dev_err(ocelot->dev, | |
1109b97b VO |
1411 | "Failed to map device memory space: %pe\n", |
1412 | target); | |
bdeced75 | 1413 | kfree(port_phy_modes); |
56051948 VO |
1414 | return PTR_ERR(target); |
1415 | } | |
1416 | ||
1417 | ocelot->targets[i] = target; | |
1418 | } | |
1419 | ||
1420 | err = ocelot_regfields_init(ocelot, felix->info->regfields); | |
1421 | if (err) { | |
1422 | dev_err(ocelot->dev, "failed to init reg fields map\n"); | |
bdeced75 | 1423 | kfree(port_phy_modes); |
56051948 VO |
1424 | return err; |
1425 | } | |
1426 | ||
1427 | for (port = 0; port < num_phys_ports; port++) { | |
1428 | struct ocelot_port *ocelot_port; | |
56051948 VO |
1429 | |
1430 | ocelot_port = devm_kzalloc(ocelot->dev, | |
1431 | sizeof(struct ocelot_port), | |
1432 | GFP_KERNEL); | |
1433 | if (!ocelot_port) { | |
1434 | dev_err(ocelot->dev, | |
1435 | "failed to allocate port memory\n"); | |
bdeced75 | 1436 | kfree(port_phy_modes); |
56051948 VO |
1437 | return -ENOMEM; |
1438 | } | |
1439 | ||
1109b97b | 1440 | target = felix_request_port_regmap(felix, port); |
91c724cf | 1441 | if (IS_ERR(target)) { |
56051948 | 1442 | dev_err(ocelot->dev, |
1109b97b VO |
1443 | "Failed to map memory space for port %d: %pe\n", |
1444 | port, target); | |
bdeced75 | 1445 | kfree(port_phy_modes); |
91c724cf | 1446 | return PTR_ERR(target); |
56051948 VO |
1447 | } |
1448 | ||
bdeced75 | 1449 | ocelot_port->phy_mode = port_phy_modes[port]; |
56051948 | 1450 | ocelot_port->ocelot = ocelot; |
91c724cf | 1451 | ocelot_port->target = target; |
7e708760 | 1452 | ocelot_port->index = port; |
56051948 VO |
1453 | ocelot->ports[port] = ocelot_port; |
1454 | } | |
1455 | ||
bdeced75 VO |
1456 | kfree(port_phy_modes); |
1457 | ||
1458 | if (felix->info->mdio_bus_alloc) { | |
1459 | err = felix->info->mdio_bus_alloc(ocelot); | |
1460 | if (err < 0) | |
1461 | return err; | |
1462 | } | |
1463 | ||
56051948 VO |
1464 | return 0; |
1465 | } | |
1466 | ||
1328a883 VO |
1467 | static void ocelot_port_purge_txtstamp_skb(struct ocelot *ocelot, int port, |
1468 | struct sk_buff *skb) | |
1469 | { | |
1470 | struct ocelot_port *ocelot_port = ocelot->ports[port]; | |
1471 | struct sk_buff *clone = OCELOT_SKB_CB(skb)->clone; | |
1472 | struct sk_buff *skb_match = NULL, *skb_tmp; | |
1473 | unsigned long flags; | |
1474 | ||
1475 | if (!clone) | |
1476 | return; | |
1477 | ||
1478 | spin_lock_irqsave(&ocelot_port->tx_skbs.lock, flags); | |
1479 | ||
1480 | skb_queue_walk_safe(&ocelot_port->tx_skbs, skb, skb_tmp) { | |
1481 | if (skb != clone) | |
1482 | continue; | |
1483 | __skb_unlink(skb, &ocelot_port->tx_skbs); | |
1484 | skb_match = skb; | |
1485 | break; | |
1486 | } | |
1487 | ||
1488 | spin_unlock_irqrestore(&ocelot_port->tx_skbs.lock, flags); | |
1489 | ||
1490 | WARN_ONCE(!skb_match, | |
1491 | "Could not find skb clone in TX timestamping list\n"); | |
1492 | } | |
1493 | ||
49f885b2 VO |
1494 | #define work_to_xmit_work(w) \ |
1495 | container_of((w), struct felix_deferred_xmit_work, work) | |
1496 | ||
1497 | static void felix_port_deferred_xmit(struct kthread_work *work) | |
1498 | { | |
1499 | struct felix_deferred_xmit_work *xmit_work = work_to_xmit_work(work); | |
1500 | struct dsa_switch *ds = xmit_work->dp->ds; | |
1501 | struct sk_buff *skb = xmit_work->skb; | |
1502 | u32 rew_op = ocelot_ptp_rew_op(skb); | |
1503 | struct ocelot *ocelot = ds->priv; | |
1504 | int port = xmit_work->dp->index; | |
1505 | int retries = 10; | |
1506 | ||
1507 | do { | |
1508 | if (ocelot_can_inject(ocelot, 0)) | |
1509 | break; | |
1510 | ||
1511 | cpu_relax(); | |
1512 | } while (--retries); | |
1513 | ||
1514 | if (!retries) { | |
1515 | dev_err(ocelot->dev, "port %d failed to inject skb\n", | |
1516 | port); | |
1328a883 | 1517 | ocelot_port_purge_txtstamp_skb(ocelot, port, skb); |
49f885b2 VO |
1518 | kfree_skb(skb); |
1519 | return; | |
1520 | } | |
1521 | ||
1522 | ocelot_port_inject_frame(ocelot, port, 0, rew_op, skb); | |
1523 | ||
1524 | consume_skb(skb); | |
1525 | kfree(xmit_work); | |
1526 | } | |
1527 | ||
35d97680 VO |
1528 | static int felix_connect_tag_protocol(struct dsa_switch *ds, |
1529 | enum dsa_tag_protocol proto) | |
49f885b2 | 1530 | { |
35d97680 | 1531 | struct ocelot_8021q_tagger_data *tagger_data; |
49f885b2 | 1532 | |
35d97680 VO |
1533 | switch (proto) { |
1534 | case DSA_TAG_PROTO_OCELOT_8021Q: | |
1535 | tagger_data = ocelot_8021q_tagger_data(ds); | |
1536 | tagger_data->xmit_work_fn = felix_port_deferred_xmit; | |
49f885b2 | 1537 | return 0; |
35d97680 VO |
1538 | case DSA_TAG_PROTO_OCELOT: |
1539 | case DSA_TAG_PROTO_SEVILLE: | |
1540 | return 0; | |
1541 | default: | |
1542 | return -EPROTONOSUPPORT; | |
1543 | } | |
49f885b2 VO |
1544 | } |
1545 | ||
56051948 VO |
1546 | static int felix_setup(struct dsa_switch *ds) |
1547 | { | |
1548 | struct ocelot *ocelot = ds->priv; | |
1549 | struct felix *felix = ocelot_to_felix(ocelot); | |
2960bb14 VO |
1550 | struct dsa_port *dp; |
1551 | int err; | |
56051948 VO |
1552 | |
1553 | err = felix_init_structs(felix, ds->num_ports); | |
1554 | if (err) | |
1555 | return err; | |
1556 | ||
3821fd01 CF |
1557 | if (ocelot->targets[HSIO]) |
1558 | ocelot_pll5_init(ocelot); | |
1559 | ||
d1cc0e93 VO |
1560 | err = ocelot_init(ocelot); |
1561 | if (err) | |
6b73b7c9 | 1562 | goto out_mdiobus_free; |
d1cc0e93 | 1563 | |
2b49d128 | 1564 | if (ocelot->ptp) { |
2ac7c6c5 | 1565 | err = ocelot_init_timestamp(ocelot, felix->info->ptp_caps); |
2b49d128 YL |
1566 | if (err) { |
1567 | dev_err(ocelot->dev, | |
1568 | "Timestamp initialization failed\n"); | |
1569 | ocelot->ptp = 0; | |
1570 | } | |
1571 | } | |
56051948 | 1572 | |
2960bb14 VO |
1573 | dsa_switch_for_each_available_port(dp, ds) { |
1574 | ocelot_init_port(ocelot, dp->index); | |
bd2b3161 | 1575 | |
6865ecee CF |
1576 | if (felix->info->configure_serdes) |
1577 | felix->info->configure_serdes(ocelot, dp->index, | |
1578 | dp->dn); | |
1579 | ||
bd2b3161 XY |
1580 | /* Set the default QoS Classification based on PCP and DEI |
1581 | * bits of vlan tag. | |
1582 | */ | |
2960bb14 | 1583 | felix_port_qos_map_init(ocelot, dp->index); |
56051948 VO |
1584 | } |
1585 | ||
f59fd9ca VO |
1586 | err = ocelot_devlink_sb_register(ocelot); |
1587 | if (err) | |
6b73b7c9 | 1588 | goto out_deinit_ports; |
f59fd9ca | 1589 | |
7a29d220 VO |
1590 | /* The initial tag protocol is NPI which won't fail during initial |
1591 | * setup, there's no real point in checking for errors. | |
1592 | */ | |
1593 | felix_change_tag_protocol(ds, felix->tag_proto); | |
1cf3299b | 1594 | |
0b912fc9 | 1595 | ds->mtu_enforcement_ingress = true; |
c54913c1 | 1596 | ds->assisted_learning_on_cpu_port = true; |
54c31984 VO |
1597 | ds->fdb_isolation = true; |
1598 | ds->max_num_bridges = ds->num_ports; | |
bdeced75 | 1599 | |
56051948 | 1600 | return 0; |
6b73b7c9 VO |
1601 | |
1602 | out_deinit_ports: | |
2960bb14 VO |
1603 | dsa_switch_for_each_available_port(dp, ds) |
1604 | ocelot_deinit_port(ocelot, dp->index); | |
6b73b7c9 VO |
1605 | |
1606 | ocelot_deinit_timestamp(ocelot); | |
1607 | ocelot_deinit(ocelot); | |
1608 | ||
1609 | out_mdiobus_free: | |
1610 | if (felix->info->mdio_bus_free) | |
1611 | felix->info->mdio_bus_free(ocelot); | |
1612 | ||
1613 | return err; | |
56051948 VO |
1614 | } |
1615 | ||
1616 | static void felix_teardown(struct dsa_switch *ds) | |
1617 | { | |
1618 | struct ocelot *ocelot = ds->priv; | |
bdeced75 | 1619 | struct felix *felix = ocelot_to_felix(ocelot); |
2960bb14 | 1620 | struct dsa_port *dp; |
bdeced75 | 1621 | |
a94c16a2 | 1622 | rtnl_lock(); |
7a29d220 VO |
1623 | if (felix->tag_proto_ops) |
1624 | felix->tag_proto_ops->teardown(ds); | |
a94c16a2 | 1625 | rtnl_unlock(); |
adb3dccf | 1626 | |
2960bb14 VO |
1627 | dsa_switch_for_each_available_port(dp, ds) |
1628 | ocelot_deinit_port(ocelot, dp->index); | |
d19741b0 | 1629 | |
49f885b2 VO |
1630 | ocelot_devlink_sb_unregister(ocelot); |
1631 | ocelot_deinit_timestamp(ocelot); | |
1632 | ocelot_deinit(ocelot); | |
1633 | ||
d19741b0 VO |
1634 | if (felix->info->mdio_bus_free) |
1635 | felix->info->mdio_bus_free(ocelot); | |
56051948 VO |
1636 | } |
1637 | ||
c0bcf537 YL |
1638 | static int felix_hwtstamp_get(struct dsa_switch *ds, int port, |
1639 | struct ifreq *ifr) | |
1640 | { | |
1641 | struct ocelot *ocelot = ds->priv; | |
1642 | ||
1643 | return ocelot_hwstamp_get(ocelot, port, ifr); | |
1644 | } | |
1645 | ||
1646 | static int felix_hwtstamp_set(struct dsa_switch *ds, int port, | |
1647 | struct ifreq *ifr) | |
1648 | { | |
1649 | struct ocelot *ocelot = ds->priv; | |
99348004 VO |
1650 | struct felix *felix = ocelot_to_felix(ocelot); |
1651 | bool using_tag_8021q; | |
1652 | int err; | |
c0bcf537 | 1653 | |
99348004 VO |
1654 | err = ocelot_hwstamp_set(ocelot, port, ifr); |
1655 | if (err) | |
1656 | return err; | |
1657 | ||
1658 | using_tag_8021q = felix->tag_proto == DSA_TAG_PROTO_OCELOT_8021Q; | |
1659 | ||
1660 | return felix_update_trapping_destinations(ds, using_tag_8021q); | |
c0bcf537 YL |
1661 | } |
1662 | ||
d219b4b6 | 1663 | static bool felix_check_xtr_pkt(struct ocelot *ocelot) |
0a6f17c6 VO |
1664 | { |
1665 | struct felix *felix = ocelot_to_felix(ocelot); | |
dbd03285 | 1666 | int err = 0, grp = 0; |
0a6f17c6 VO |
1667 | |
1668 | if (felix->tag_proto != DSA_TAG_PROTO_OCELOT_8021Q) | |
1669 | return false; | |
1670 | ||
1671 | if (!felix->info->quirk_no_xtr_irq) | |
1672 | return false; | |
1673 | ||
0a6f17c6 VO |
1674 | while (ocelot_read(ocelot, QS_XTR_DATA_PRESENT) & BIT(grp)) { |
1675 | struct sk_buff *skb; | |
1676 | unsigned int type; | |
1677 | ||
1678 | err = ocelot_xtr_poll_frame(ocelot, grp, &skb); | |
1679 | if (err) | |
1680 | goto out; | |
1681 | ||
1682 | /* We trap to the CPU port module all PTP frames, but | |
1683 | * felix_rxtstamp() only gets called for event frames. | |
1684 | * So we need to avoid sending duplicate general | |
1685 | * message frames by running a second BPF classifier | |
1686 | * here and dropping those. | |
1687 | */ | |
1688 | __skb_push(skb, ETH_HLEN); | |
1689 | ||
1690 | type = ptp_classify_raw(skb); | |
1691 | ||
1692 | __skb_pull(skb, ETH_HLEN); | |
1693 | ||
1694 | if (type == PTP_CLASS_NONE) { | |
1695 | kfree_skb(skb); | |
1696 | continue; | |
1697 | } | |
1698 | ||
1699 | netif_rx(skb); | |
1700 | } | |
1701 | ||
1702 | out: | |
5d3bb7dd VO |
1703 | if (err < 0) { |
1704 | dev_err_ratelimited(ocelot->dev, | |
1705 | "Error during packet extraction: %pe\n", | |
1706 | ERR_PTR(err)); | |
0a6f17c6 | 1707 | ocelot_drain_cpu_queue(ocelot, 0); |
5d3bb7dd | 1708 | } |
0a6f17c6 VO |
1709 | |
1710 | return true; | |
1711 | } | |
1712 | ||
c0bcf537 YL |
1713 | static bool felix_rxtstamp(struct dsa_switch *ds, int port, |
1714 | struct sk_buff *skb, unsigned int type) | |
1715 | { | |
92f62485 | 1716 | u32 tstamp_lo = OCELOT_SKB_CB(skb)->tstamp_lo; |
c0bcf537 YL |
1717 | struct skb_shared_hwtstamps *shhwtstamps; |
1718 | struct ocelot *ocelot = ds->priv; | |
c0bcf537 | 1719 | struct timespec64 ts; |
92f62485 VO |
1720 | u32 tstamp_hi; |
1721 | u64 tstamp; | |
c0bcf537 | 1722 | |
2edcfcbb VO |
1723 | switch (type & PTP_CLASS_PMASK) { |
1724 | case PTP_CLASS_L2: | |
1725 | if (!(ocelot->ports[port]->trap_proto & OCELOT_PROTO_PTP_L2)) | |
1726 | return false; | |
1727 | break; | |
1728 | case PTP_CLASS_IPV4: | |
1729 | case PTP_CLASS_IPV6: | |
1730 | if (!(ocelot->ports[port]->trap_proto & OCELOT_PROTO_PTP_L4)) | |
1731 | return false; | |
1732 | break; | |
1733 | } | |
1734 | ||
0a6f17c6 VO |
1735 | /* If the "no XTR IRQ" workaround is in use, tell DSA to defer this skb |
1736 | * for RX timestamping. Then free it, and poll for its copy through | |
1737 | * MMIO in the CPU port module, and inject that into the stack from | |
1738 | * ocelot_xtr_poll(). | |
1739 | */ | |
d219b4b6 | 1740 | if (felix_check_xtr_pkt(ocelot)) { |
0a6f17c6 VO |
1741 | kfree_skb(skb); |
1742 | return true; | |
1743 | } | |
1744 | ||
c0bcf537 YL |
1745 | ocelot_ptp_gettime64(&ocelot->ptp_info, &ts); |
1746 | tstamp = ktime_set(ts.tv_sec, ts.tv_nsec); | |
1747 | ||
c0bcf537 YL |
1748 | tstamp_hi = tstamp >> 32; |
1749 | if ((tstamp & 0xffffffff) < tstamp_lo) | |
1750 | tstamp_hi--; | |
1751 | ||
1752 | tstamp = ((u64)tstamp_hi << 32) | tstamp_lo; | |
1753 | ||
1754 | shhwtstamps = skb_hwtstamps(skb); | |
1755 | memset(shhwtstamps, 0, sizeof(struct skb_shared_hwtstamps)); | |
1756 | shhwtstamps->hwtstamp = tstamp; | |
1757 | return false; | |
1758 | } | |
1759 | ||
5c5416f5 YL |
1760 | static void felix_txtstamp(struct dsa_switch *ds, int port, |
1761 | struct sk_buff *skb) | |
c0bcf537 YL |
1762 | { |
1763 | struct ocelot *ocelot = ds->priv; | |
682eaad9 | 1764 | struct sk_buff *clone = NULL; |
c0bcf537 | 1765 | |
682eaad9 YL |
1766 | if (!ocelot->ptp) |
1767 | return; | |
5c5416f5 | 1768 | |
52849bcf VO |
1769 | if (ocelot_port_txtstamp_request(ocelot, port, skb, &clone)) { |
1770 | dev_err_ratelimited(ds->dev, | |
1771 | "port %d delivering skb without TX timestamp\n", | |
1772 | port); | |
682eaad9 | 1773 | return; |
52849bcf | 1774 | } |
682eaad9 YL |
1775 | |
1776 | if (clone) | |
c4b364ce | 1777 | OCELOT_SKB_CB(skb)->clone = clone; |
c0bcf537 YL |
1778 | } |
1779 | ||
0b912fc9 VO |
1780 | static int felix_change_mtu(struct dsa_switch *ds, int port, int new_mtu) |
1781 | { | |
1782 | struct ocelot *ocelot = ds->priv; | |
55a515b1 | 1783 | struct ocelot_port *ocelot_port = ocelot->ports[port]; |
0b912fc9 VO |
1784 | |
1785 | ocelot_port_set_maxlen(ocelot, port, new_mtu); | |
1786 | ||
009d30f1 | 1787 | mutex_lock(&ocelot->fwd_domain_lock); |
55a515b1 | 1788 | |
c6081914 VO |
1789 | if (ocelot_port->taprio && ocelot->ops->tas_guard_bands_update) |
1790 | ocelot->ops->tas_guard_bands_update(ocelot, port); | |
55a515b1 | 1791 | |
009d30f1 | 1792 | mutex_unlock(&ocelot->fwd_domain_lock); |
55a515b1 | 1793 | |
0b912fc9 VO |
1794 | return 0; |
1795 | } | |
1796 | ||
1797 | static int felix_get_max_mtu(struct dsa_switch *ds, int port) | |
1798 | { | |
1799 | struct ocelot *ocelot = ds->priv; | |
1800 | ||
1801 | return ocelot_get_max_mtu(ocelot, port); | |
1802 | } | |
1803 | ||
07d985ee VO |
1804 | static int felix_cls_flower_add(struct dsa_switch *ds, int port, |
1805 | struct flow_cls_offload *cls, bool ingress) | |
1806 | { | |
1807 | struct ocelot *ocelot = ds->priv; | |
99348004 VO |
1808 | struct felix *felix = ocelot_to_felix(ocelot); |
1809 | bool using_tag_8021q; | |
1810 | int err; | |
1811 | ||
1812 | err = ocelot_cls_flower_replace(ocelot, port, cls, ingress); | |
1813 | if (err) | |
1814 | return err; | |
1815 | ||
1816 | using_tag_8021q = felix->tag_proto == DSA_TAG_PROTO_OCELOT_8021Q; | |
07d985ee | 1817 | |
99348004 | 1818 | return felix_update_trapping_destinations(ds, using_tag_8021q); |
07d985ee VO |
1819 | } |
1820 | ||
1821 | static int felix_cls_flower_del(struct dsa_switch *ds, int port, | |
1822 | struct flow_cls_offload *cls, bool ingress) | |
1823 | { | |
1824 | struct ocelot *ocelot = ds->priv; | |
1825 | ||
1826 | return ocelot_cls_flower_destroy(ocelot, port, cls, ingress); | |
1827 | } | |
1828 | ||
1829 | static int felix_cls_flower_stats(struct dsa_switch *ds, int port, | |
1830 | struct flow_cls_offload *cls, bool ingress) | |
1831 | { | |
1832 | struct ocelot *ocelot = ds->priv; | |
1833 | ||
1834 | return ocelot_cls_flower_stats(ocelot, port, cls, ingress); | |
1835 | } | |
1836 | ||
fc411eaa VO |
1837 | static int felix_port_policer_add(struct dsa_switch *ds, int port, |
1838 | struct dsa_mall_policer_tc_entry *policer) | |
1839 | { | |
1840 | struct ocelot *ocelot = ds->priv; | |
1841 | struct ocelot_policer pol = { | |
1842 | .rate = div_u64(policer->rate_bytes_per_sec, 1000) * 8, | |
5f035af7 | 1843 | .burst = policer->burst, |
fc411eaa VO |
1844 | }; |
1845 | ||
1846 | return ocelot_port_policer_add(ocelot, port, &pol); | |
1847 | } | |
1848 | ||
1849 | static void felix_port_policer_del(struct dsa_switch *ds, int port) | |
1850 | { | |
1851 | struct ocelot *ocelot = ds->priv; | |
1852 | ||
1853 | ocelot_port_policer_del(ocelot, port); | |
1854 | } | |
1855 | ||
5e497497 VO |
1856 | static int felix_port_mirror_add(struct dsa_switch *ds, int port, |
1857 | struct dsa_mall_mirror_tc_entry *mirror, | |
1858 | bool ingress, struct netlink_ext_ack *extack) | |
1859 | { | |
1860 | struct ocelot *ocelot = ds->priv; | |
1861 | ||
1862 | return ocelot_port_mirror_add(ocelot, port, mirror->to_local_port, | |
1863 | ingress, extack); | |
1864 | } | |
1865 | ||
1866 | static void felix_port_mirror_del(struct dsa_switch *ds, int port, | |
1867 | struct dsa_mall_mirror_tc_entry *mirror) | |
1868 | { | |
1869 | struct ocelot *ocelot = ds->priv; | |
1870 | ||
1871 | ocelot_port_mirror_del(ocelot, port, mirror->ingress); | |
1872 | } | |
1873 | ||
de143c0e XY |
1874 | static int felix_port_setup_tc(struct dsa_switch *ds, int port, |
1875 | enum tc_setup_type type, | |
1876 | void *type_data) | |
1877 | { | |
1878 | struct ocelot *ocelot = ds->priv; | |
1879 | struct felix *felix = ocelot_to_felix(ocelot); | |
1880 | ||
1881 | if (felix->info->port_setup_tc) | |
1882 | return felix->info->port_setup_tc(ds, port, type, type_data); | |
1883 | else | |
1884 | return -EOPNOTSUPP; | |
1885 | } | |
1886 | ||
f59fd9ca VO |
1887 | static int felix_sb_pool_get(struct dsa_switch *ds, unsigned int sb_index, |
1888 | u16 pool_index, | |
1889 | struct devlink_sb_pool_info *pool_info) | |
1890 | { | |
1891 | struct ocelot *ocelot = ds->priv; | |
1892 | ||
1893 | return ocelot_sb_pool_get(ocelot, sb_index, pool_index, pool_info); | |
1894 | } | |
1895 | ||
1896 | static int felix_sb_pool_set(struct dsa_switch *ds, unsigned int sb_index, | |
1897 | u16 pool_index, u32 size, | |
1898 | enum devlink_sb_threshold_type threshold_type, | |
1899 | struct netlink_ext_ack *extack) | |
1900 | { | |
1901 | struct ocelot *ocelot = ds->priv; | |
1902 | ||
1903 | return ocelot_sb_pool_set(ocelot, sb_index, pool_index, size, | |
1904 | threshold_type, extack); | |
1905 | } | |
1906 | ||
1907 | static int felix_sb_port_pool_get(struct dsa_switch *ds, int port, | |
1908 | unsigned int sb_index, u16 pool_index, | |
1909 | u32 *p_threshold) | |
1910 | { | |
1911 | struct ocelot *ocelot = ds->priv; | |
1912 | ||
1913 | return ocelot_sb_port_pool_get(ocelot, port, sb_index, pool_index, | |
1914 | p_threshold); | |
1915 | } | |
1916 | ||
1917 | static int felix_sb_port_pool_set(struct dsa_switch *ds, int port, | |
1918 | unsigned int sb_index, u16 pool_index, | |
1919 | u32 threshold, struct netlink_ext_ack *extack) | |
1920 | { | |
1921 | struct ocelot *ocelot = ds->priv; | |
1922 | ||
1923 | return ocelot_sb_port_pool_set(ocelot, port, sb_index, pool_index, | |
1924 | threshold, extack); | |
1925 | } | |
1926 | ||
1927 | static int felix_sb_tc_pool_bind_get(struct dsa_switch *ds, int port, | |
1928 | unsigned int sb_index, u16 tc_index, | |
1929 | enum devlink_sb_pool_type pool_type, | |
1930 | u16 *p_pool_index, u32 *p_threshold) | |
1931 | { | |
1932 | struct ocelot *ocelot = ds->priv; | |
1933 | ||
1934 | return ocelot_sb_tc_pool_bind_get(ocelot, port, sb_index, tc_index, | |
1935 | pool_type, p_pool_index, | |
1936 | p_threshold); | |
1937 | } | |
1938 | ||
1939 | static int felix_sb_tc_pool_bind_set(struct dsa_switch *ds, int port, | |
1940 | unsigned int sb_index, u16 tc_index, | |
1941 | enum devlink_sb_pool_type pool_type, | |
1942 | u16 pool_index, u32 threshold, | |
1943 | struct netlink_ext_ack *extack) | |
1944 | { | |
1945 | struct ocelot *ocelot = ds->priv; | |
1946 | ||
1947 | return ocelot_sb_tc_pool_bind_set(ocelot, port, sb_index, tc_index, | |
1948 | pool_type, pool_index, threshold, | |
1949 | extack); | |
1950 | } | |
1951 | ||
1952 | static int felix_sb_occ_snapshot(struct dsa_switch *ds, | |
1953 | unsigned int sb_index) | |
1954 | { | |
1955 | struct ocelot *ocelot = ds->priv; | |
1956 | ||
1957 | return ocelot_sb_occ_snapshot(ocelot, sb_index); | |
1958 | } | |
1959 | ||
1960 | static int felix_sb_occ_max_clear(struct dsa_switch *ds, | |
1961 | unsigned int sb_index) | |
1962 | { | |
1963 | struct ocelot *ocelot = ds->priv; | |
1964 | ||
1965 | return ocelot_sb_occ_max_clear(ocelot, sb_index); | |
1966 | } | |
1967 | ||
1968 | static int felix_sb_occ_port_pool_get(struct dsa_switch *ds, int port, | |
1969 | unsigned int sb_index, u16 pool_index, | |
1970 | u32 *p_cur, u32 *p_max) | |
1971 | { | |
1972 | struct ocelot *ocelot = ds->priv; | |
1973 | ||
1974 | return ocelot_sb_occ_port_pool_get(ocelot, port, sb_index, pool_index, | |
1975 | p_cur, p_max); | |
1976 | } | |
1977 | ||
1978 | static int felix_sb_occ_tc_port_bind_get(struct dsa_switch *ds, int port, | |
1979 | unsigned int sb_index, u16 tc_index, | |
1980 | enum devlink_sb_pool_type pool_type, | |
1981 | u32 *p_cur, u32 *p_max) | |
1982 | { | |
1983 | struct ocelot *ocelot = ds->priv; | |
1984 | ||
1985 | return ocelot_sb_occ_tc_port_bind_get(ocelot, port, sb_index, tc_index, | |
1986 | pool_type, p_cur, p_max); | |
1987 | } | |
1988 | ||
a026c50b HV |
1989 | static int felix_mrp_add(struct dsa_switch *ds, int port, |
1990 | const struct switchdev_obj_mrp *mrp) | |
1991 | { | |
1992 | struct ocelot *ocelot = ds->priv; | |
1993 | ||
1994 | return ocelot_mrp_add(ocelot, port, mrp); | |
1995 | } | |
1996 | ||
1997 | static int felix_mrp_del(struct dsa_switch *ds, int port, | |
1998 | const struct switchdev_obj_mrp *mrp) | |
1999 | { | |
2000 | struct ocelot *ocelot = ds->priv; | |
2001 | ||
2002 | return ocelot_mrp_add(ocelot, port, mrp); | |
2003 | } | |
2004 | ||
2005 | static int | |
2006 | felix_mrp_add_ring_role(struct dsa_switch *ds, int port, | |
2007 | const struct switchdev_obj_ring_role_mrp *mrp) | |
2008 | { | |
2009 | struct ocelot *ocelot = ds->priv; | |
2010 | ||
2011 | return ocelot_mrp_add_ring_role(ocelot, port, mrp); | |
2012 | } | |
2013 | ||
2014 | static int | |
2015 | felix_mrp_del_ring_role(struct dsa_switch *ds, int port, | |
2016 | const struct switchdev_obj_ring_role_mrp *mrp) | |
2017 | { | |
2018 | struct ocelot *ocelot = ds->priv; | |
2019 | ||
2020 | return ocelot_mrp_del_ring_role(ocelot, port, mrp); | |
2021 | } | |
2022 | ||
978777d0 VO |
2023 | static int felix_port_get_default_prio(struct dsa_switch *ds, int port) |
2024 | { | |
2025 | struct ocelot *ocelot = ds->priv; | |
2026 | ||
2027 | return ocelot_port_get_default_prio(ocelot, port); | |
2028 | } | |
2029 | ||
2030 | static int felix_port_set_default_prio(struct dsa_switch *ds, int port, | |
2031 | u8 prio) | |
2032 | { | |
2033 | struct ocelot *ocelot = ds->priv; | |
2034 | ||
2035 | return ocelot_port_set_default_prio(ocelot, port, prio); | |
2036 | } | |
2037 | ||
2038 | static int felix_port_get_dscp_prio(struct dsa_switch *ds, int port, u8 dscp) | |
2039 | { | |
2040 | struct ocelot *ocelot = ds->priv; | |
2041 | ||
2042 | return ocelot_port_get_dscp_prio(ocelot, port, dscp); | |
2043 | } | |
2044 | ||
2045 | static int felix_port_add_dscp_prio(struct dsa_switch *ds, int port, u8 dscp, | |
2046 | u8 prio) | |
2047 | { | |
2048 | struct ocelot *ocelot = ds->priv; | |
2049 | ||
2050 | return ocelot_port_add_dscp_prio(ocelot, port, dscp, prio); | |
2051 | } | |
2052 | ||
2053 | static int felix_port_del_dscp_prio(struct dsa_switch *ds, int port, u8 dscp, | |
2054 | u8 prio) | |
2055 | { | |
2056 | struct ocelot *ocelot = ds->priv; | |
2057 | ||
2058 | return ocelot_port_del_dscp_prio(ocelot, port, dscp, prio); | |
2059 | } | |
2060 | ||
6505b680 VO |
2061 | static int felix_get_mm(struct dsa_switch *ds, int port, |
2062 | struct ethtool_mm_state *state) | |
2063 | { | |
2064 | struct ocelot *ocelot = ds->priv; | |
2065 | ||
2066 | return ocelot_port_get_mm(ocelot, port, state); | |
2067 | } | |
2068 | ||
2069 | static int felix_set_mm(struct dsa_switch *ds, int port, | |
2070 | struct ethtool_mm_cfg *cfg, | |
2071 | struct netlink_ext_ack *extack) | |
2072 | { | |
2073 | struct ocelot *ocelot = ds->priv; | |
2074 | ||
2075 | return ocelot_port_set_mm(ocelot, port, cfg, extack); | |
2076 | } | |
2077 | ||
ab3f97a9 VO |
2078 | static void felix_get_mm_stats(struct dsa_switch *ds, int port, |
2079 | struct ethtool_mm_stats *stats) | |
2080 | { | |
2081 | struct ocelot *ocelot = ds->priv; | |
2082 | ||
2083 | ocelot_port_get_mm_stats(ocelot, port, stats); | |
2084 | } | |
2085 | ||
375e1314 | 2086 | const struct dsa_switch_ops felix_switch_ops = { |
a7096915 | 2087 | .get_tag_protocol = felix_get_tag_protocol, |
adb3dccf | 2088 | .change_tag_protocol = felix_change_tag_protocol, |
35d97680 | 2089 | .connect_tag_protocol = felix_connect_tag_protocol, |
a7096915 VO |
2090 | .setup = felix_setup, |
2091 | .teardown = felix_teardown, | |
2092 | .set_ageing_time = felix_set_ageing_time, | |
6505b680 VO |
2093 | .get_mm = felix_get_mm, |
2094 | .set_mm = felix_set_mm, | |
ab3f97a9 | 2095 | .get_mm_stats = felix_get_mm_stats, |
776b71e5 | 2096 | .get_stats64 = felix_get_stats64, |
e32036e1 VO |
2097 | .get_pause_stats = felix_get_pause_stats, |
2098 | .get_rmon_stats = felix_get_rmon_stats, | |
2099 | .get_eth_ctrl_stats = felix_get_eth_ctrl_stats, | |
2100 | .get_eth_mac_stats = felix_get_eth_mac_stats, | |
2101 | .get_eth_phy_stats = felix_get_eth_phy_stats, | |
a7096915 VO |
2102 | .get_strings = felix_get_strings, |
2103 | .get_ethtool_stats = felix_get_ethtool_stats, | |
2104 | .get_sset_count = felix_get_sset_count, | |
2105 | .get_ts_info = felix_get_ts_info, | |
79fda660 | 2106 | .phylink_get_caps = felix_phylink_get_caps, |
544435c9 | 2107 | .phylink_mac_config = felix_phylink_mac_config, |
864ba485 | 2108 | .phylink_mac_select_pcs = felix_phylink_mac_select_pcs, |
a7096915 VO |
2109 | .phylink_mac_link_down = felix_phylink_mac_link_down, |
2110 | .phylink_mac_link_up = felix_phylink_mac_link_up, | |
eca70102 | 2111 | .port_enable = felix_port_enable, |
5cad43a5 | 2112 | .port_fast_age = felix_port_fast_age, |
a7096915 VO |
2113 | .port_fdb_dump = felix_fdb_dump, |
2114 | .port_fdb_add = felix_fdb_add, | |
2115 | .port_fdb_del = felix_fdb_del, | |
961d8b69 VO |
2116 | .lag_fdb_add = felix_lag_fdb_add, |
2117 | .lag_fdb_del = felix_lag_fdb_del, | |
a7096915 VO |
2118 | .port_mdb_add = felix_mdb_add, |
2119 | .port_mdb_del = felix_mdb_del, | |
421741ea VO |
2120 | .port_pre_bridge_flags = felix_pre_bridge_flags, |
2121 | .port_bridge_flags = felix_bridge_flags, | |
a7096915 VO |
2122 | .port_bridge_join = felix_bridge_join, |
2123 | .port_bridge_leave = felix_bridge_leave, | |
8fe6832e VO |
2124 | .port_lag_join = felix_lag_join, |
2125 | .port_lag_leave = felix_lag_leave, | |
2126 | .port_lag_change = felix_lag_change, | |
a7096915 VO |
2127 | .port_stp_state_set = felix_bridge_stp_state_set, |
2128 | .port_vlan_filtering = felix_vlan_filtering, | |
2129 | .port_vlan_add = felix_vlan_add, | |
2130 | .port_vlan_del = felix_vlan_del, | |
2131 | .port_hwtstamp_get = felix_hwtstamp_get, | |
2132 | .port_hwtstamp_set = felix_hwtstamp_set, | |
2133 | .port_rxtstamp = felix_rxtstamp, | |
2134 | .port_txtstamp = felix_txtstamp, | |
2135 | .port_change_mtu = felix_change_mtu, | |
2136 | .port_max_mtu = felix_get_max_mtu, | |
2137 | .port_policer_add = felix_port_policer_add, | |
2138 | .port_policer_del = felix_port_policer_del, | |
5e497497 VO |
2139 | .port_mirror_add = felix_port_mirror_add, |
2140 | .port_mirror_del = felix_port_mirror_del, | |
a7096915 VO |
2141 | .cls_flower_add = felix_cls_flower_add, |
2142 | .cls_flower_del = felix_cls_flower_del, | |
2143 | .cls_flower_stats = felix_cls_flower_stats, | |
2144 | .port_setup_tc = felix_port_setup_tc, | |
f59fd9ca VO |
2145 | .devlink_sb_pool_get = felix_sb_pool_get, |
2146 | .devlink_sb_pool_set = felix_sb_pool_set, | |
2147 | .devlink_sb_port_pool_get = felix_sb_port_pool_get, | |
2148 | .devlink_sb_port_pool_set = felix_sb_port_pool_set, | |
2149 | .devlink_sb_tc_pool_bind_get = felix_sb_tc_pool_bind_get, | |
2150 | .devlink_sb_tc_pool_bind_set = felix_sb_tc_pool_bind_set, | |
2151 | .devlink_sb_occ_snapshot = felix_sb_occ_snapshot, | |
2152 | .devlink_sb_occ_max_clear = felix_sb_occ_max_clear, | |
2153 | .devlink_sb_occ_port_pool_get = felix_sb_occ_port_pool_get, | |
2154 | .devlink_sb_occ_tc_port_bind_get= felix_sb_occ_tc_port_bind_get, | |
a026c50b HV |
2155 | .port_mrp_add = felix_mrp_add, |
2156 | .port_mrp_del = felix_mrp_del, | |
2157 | .port_mrp_add_ring_role = felix_mrp_add_ring_role, | |
2158 | .port_mrp_del_ring_role = felix_mrp_del_ring_role, | |
5da11eb4 VO |
2159 | .tag_8021q_vlan_add = felix_tag_8021q_vlan_add, |
2160 | .tag_8021q_vlan_del = felix_tag_8021q_vlan_del, | |
978777d0 VO |
2161 | .port_get_default_prio = felix_port_get_default_prio, |
2162 | .port_set_default_prio = felix_port_set_default_prio, | |
2163 | .port_get_dscp_prio = felix_port_get_dscp_prio, | |
2164 | .port_add_dscp_prio = felix_port_add_dscp_prio, | |
2165 | .port_del_dscp_prio = felix_port_del_dscp_prio, | |
72c3b0c7 | 2166 | .port_set_host_flood = felix_port_set_host_flood, |
6ca80638 | 2167 | .port_change_conduit = felix_port_change_conduit, |
56051948 | 2168 | }; |
c8005511 | 2169 | EXPORT_SYMBOL_GPL(felix_switch_ops); |
319e4dd1 VO |
2170 | |
2171 | struct net_device *felix_port_to_netdev(struct ocelot *ocelot, int port) | |
2172 | { | |
2173 | struct felix *felix = ocelot_to_felix(ocelot); | |
2174 | struct dsa_switch *ds = felix->ds; | |
2175 | ||
2176 | if (!dsa_is_user_port(ds, port)) | |
2177 | return NULL; | |
2178 | ||
6ca80638 | 2179 | return dsa_to_port(ds, port)->user; |
319e4dd1 | 2180 | } |
c8005511 | 2181 | EXPORT_SYMBOL_GPL(felix_port_to_netdev); |
319e4dd1 VO |
2182 | |
2183 | int felix_netdev_to_port(struct net_device *dev) | |
2184 | { | |
2185 | struct dsa_port *dp; | |
2186 | ||
2187 | dp = dsa_port_from_netdev(dev); | |
2188 | if (IS_ERR(dp)) | |
2189 | return -EINVAL; | |
2190 | ||
2191 | return dp->index; | |
2192 | } | |
c8005511 VO |
2193 | EXPORT_SYMBOL_GPL(felix_netdev_to_port); |
2194 | ||
2195 | MODULE_DESCRIPTION("Felix DSA library"); | |
2196 | MODULE_LICENSE("GPL"); |