blob: 14872a92285e17877f97cae3bd758f322eea0317 [file] [log] [blame]
b.liue9582032025-04-17 19:18:16 +08001// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * Handling of a single switch port
4 *
5 * Copyright (c) 2017 Savoir-faire Linux Inc.
6 * Vivien Didelot <vivien.didelot@savoirfairelinux.com>
7 */
8
9#include <linux/if_bridge.h>
10#include <linux/notifier.h>
11#include <linux/of_mdio.h>
12#include <linux/of_net.h>
13
14#include "dsa_priv.h"
15
16static int dsa_port_notify(const struct dsa_port *dp, unsigned long e, void *v)
17{
18 struct raw_notifier_head *nh = &dp->ds->dst->nh;
19 int err;
20
21 err = raw_notifier_call_chain(nh, e, v);
22
23 return notifier_to_errno(err);
24}
25
26int dsa_port_set_state(struct dsa_port *dp, u8 state,
27 struct switchdev_trans *trans)
28{
29 struct dsa_switch *ds = dp->ds;
30 int port = dp->index;
31
32 if (switchdev_trans_ph_prepare(trans))
33 return ds->ops->port_stp_state_set ? 0 : -EOPNOTSUPP;
34
35 if (ds->ops->port_stp_state_set)
36 ds->ops->port_stp_state_set(ds, port, state);
37
38 if (ds->ops->port_fast_age) {
39 /* Fast age FDB entries or flush appropriate forwarding database
40 * for the given port, if we are moving it from Learning or
41 * Forwarding state, to Disabled or Blocking or Listening state.
42 */
43
44 if ((dp->stp_state == BR_STATE_LEARNING ||
45 dp->stp_state == BR_STATE_FORWARDING) &&
46 (state == BR_STATE_DISABLED ||
47 state == BR_STATE_BLOCKING ||
48 state == BR_STATE_LISTENING))
49 ds->ops->port_fast_age(ds, port);
50 }
51
52 dp->stp_state = state;
53
54 return 0;
55}
56
57static void dsa_port_set_state_now(struct dsa_port *dp, u8 state)
58{
59 int err;
60
61 err = dsa_port_set_state(dp, state, NULL);
62 if (err)
63 pr_err("DSA: failed to set STP state %u (%d)\n", state, err);
64}
65
66int dsa_port_enable_rt(struct dsa_port *dp, struct phy_device *phy)
67{
68 struct dsa_switch *ds = dp->ds;
69 int port = dp->index;
70 int err;
71
72 if (ds->ops->port_enable) {
73 err = ds->ops->port_enable(ds, port, phy);
74 if (err)
75 return err;
76 }
77
78 if (!dp->bridge_dev)
79 dsa_port_set_state_now(dp, BR_STATE_FORWARDING);
80
81 if (dp->pl)
82 phylink_start(dp->pl);
83
84 return 0;
85}
86
87int dsa_port_enable(struct dsa_port *dp, struct phy_device *phy)
88{
89 int err;
90
91 rtnl_lock();
92 err = dsa_port_enable_rt(dp, phy);
93 rtnl_unlock();
94
95 return err;
96}
97
98void dsa_port_disable_rt(struct dsa_port *dp)
99{
100 struct dsa_switch *ds = dp->ds;
101 int port = dp->index;
102
103 if (dp->pl)
104 phylink_stop(dp->pl);
105
106 if (!dp->bridge_dev)
107 dsa_port_set_state_now(dp, BR_STATE_DISABLED);
108
109 if (ds->ops->port_disable)
110 ds->ops->port_disable(ds, port);
111}
112
113void dsa_port_disable(struct dsa_port *dp)
114{
115 rtnl_lock();
116 dsa_port_disable_rt(dp);
117 rtnl_unlock();
118}
119
120int dsa_port_bridge_join(struct dsa_port *dp, struct net_device *br)
121{
122 struct dsa_notifier_bridge_info info = {
123 .sw_index = dp->ds->index,
124 .port = dp->index,
125 .br = br,
126 };
127 int err;
128
129 /* Set the flooding mode before joining the port in the switch */
130 err = dsa_port_bridge_flags(dp, BR_FLOOD | BR_MCAST_FLOOD, NULL);
131 if (err)
132 return err;
133
134 /* Here the interface is already bridged. Reflect the current
135 * configuration so that drivers can program their chips accordingly.
136 */
137 dp->bridge_dev = br;
138
139 err = dsa_port_notify(dp, DSA_NOTIFIER_BRIDGE_JOIN, &info);
140
141 /* The bridging is rolled back on error */
142 if (err) {
143 dsa_port_bridge_flags(dp, 0, NULL);
144 dp->bridge_dev = NULL;
145 }
146
147 return err;
148}
149
150void dsa_port_bridge_leave(struct dsa_port *dp, struct net_device *br)
151{
152 struct dsa_notifier_bridge_info info = {
153 .sw_index = dp->ds->index,
154 .port = dp->index,
155 .br = br,
156 };
157 int err;
158
159 /* Here the port is already unbridged. Reflect the current configuration
160 * so that drivers can program their chips accordingly.
161 */
162 dp->bridge_dev = NULL;
163
164 err = dsa_port_notify(dp, DSA_NOTIFIER_BRIDGE_LEAVE, &info);
165 if (err)
166 pr_err("DSA: failed to notify DSA_NOTIFIER_BRIDGE_LEAVE\n");
167
168 /* Port is leaving the bridge, disable flooding */
169 dsa_port_bridge_flags(dp, 0, NULL);
170
171 /* Port left the bridge, put in BR_STATE_DISABLED by the bridge layer,
172 * so allow it to be in BR_STATE_FORWARDING to be kept functional
173 */
174 dsa_port_set_state_now(dp, BR_STATE_FORWARDING);
175}
176
177static bool dsa_port_can_apply_vlan_filtering(struct dsa_port *dp,
178 bool vlan_filtering)
179{
180 struct dsa_switch *ds = dp->ds;
181 int i;
182
183 if (!ds->vlan_filtering_is_global)
184 return true;
185
186 /* For cases where enabling/disabling VLAN awareness is global to the
187 * switch, we need to handle the case where multiple bridges span
188 * different ports of the same switch device and one of them has a
189 * different setting than what is being requested.
190 */
191 for (i = 0; i < ds->num_ports; i++) {
192 struct net_device *other_bridge;
193
194 other_bridge = dsa_to_port(ds, i)->bridge_dev;
195 if (!other_bridge)
196 continue;
197 /* If it's the same bridge, it also has same
198 * vlan_filtering setting => no need to check
199 */
200 if (other_bridge == dp->bridge_dev)
201 continue;
202 if (br_vlan_enabled(other_bridge) != vlan_filtering) {
203 dev_err(ds->dev, "VLAN filtering is a global setting\n");
204 return false;
205 }
206 }
207 return true;
208}
209
210int dsa_port_vlan_filtering(struct dsa_port *dp, bool vlan_filtering,
211 struct switchdev_trans *trans)
212{
213 struct dsa_switch *ds = dp->ds;
214 int err;
215
216 /* bridge skips -EOPNOTSUPP, so skip the prepare phase */
217 if (switchdev_trans_ph_prepare(trans))
218 return 0;
219
220 if (!ds->ops->port_vlan_filtering)
221 return 0;
222
223 if (!dsa_port_can_apply_vlan_filtering(dp, vlan_filtering))
224 return -EINVAL;
225
226 if (dsa_port_is_vlan_filtering(dp) == vlan_filtering)
227 return 0;
228
229 err = ds->ops->port_vlan_filtering(ds, dp->index,
230 vlan_filtering);
231 if (err)
232 return err;
233
234 if (ds->vlan_filtering_is_global)
235 ds->vlan_filtering = vlan_filtering;
236 else
237 dp->vlan_filtering = vlan_filtering;
238 return 0;
239}
240
241/* This enforces legacy behavior for switch drivers which assume they can't
242 * receive VLAN configuration when enslaved to a bridge with vlan_filtering=0
243 */
244bool dsa_port_skip_vlan_configuration(struct dsa_port *dp)
245{
246 struct dsa_switch *ds = dp->ds;
247
248 if (!dp->bridge_dev)
249 return false;
250
251 return (!ds->configure_vlan_while_not_filtering &&
252 !br_vlan_enabled(dp->bridge_dev));
253}
254
255int dsa_port_ageing_time(struct dsa_port *dp, clock_t ageing_clock,
256 struct switchdev_trans *trans)
257{
258 unsigned long ageing_jiffies = clock_t_to_jiffies(ageing_clock);
259 unsigned int ageing_time = jiffies_to_msecs(ageing_jiffies);
260 struct dsa_notifier_ageing_time_info info = {
261 .ageing_time = ageing_time,
262 .trans = trans,
263 };
264
265 if (switchdev_trans_ph_prepare(trans))
266 return dsa_port_notify(dp, DSA_NOTIFIER_AGEING_TIME, &info);
267
268 dp->ageing_time = ageing_time;
269
270 return dsa_port_notify(dp, DSA_NOTIFIER_AGEING_TIME, &info);
271}
272
273int dsa_port_pre_bridge_flags(const struct dsa_port *dp, unsigned long flags,
274 struct switchdev_trans *trans)
275{
276 struct dsa_switch *ds = dp->ds;
277
278 if (!ds->ops->port_egress_floods ||
279 (flags & ~(BR_FLOOD | BR_MCAST_FLOOD)))
280 return -EINVAL;
281
282 return 0;
283}
284
285int dsa_port_bridge_flags(const struct dsa_port *dp, unsigned long flags,
286 struct switchdev_trans *trans)
287{
288 struct dsa_switch *ds = dp->ds;
289 int port = dp->index;
290 int err = 0;
291
292 if (switchdev_trans_ph_prepare(trans))
293 return 0;
294
295 if (ds->ops->port_egress_floods)
296 err = ds->ops->port_egress_floods(ds, port, flags & BR_FLOOD,
297 flags & BR_MCAST_FLOOD);
298
299 return err;
300}
301
302int dsa_port_mrouter(struct dsa_port *dp, bool mrouter,
303 struct switchdev_trans *trans)
304{
305 struct dsa_switch *ds = dp->ds;
306 int port = dp->index;
307
308 if (switchdev_trans_ph_prepare(trans))
309 return ds->ops->port_egress_floods ? 0 : -EOPNOTSUPP;
310
311 return ds->ops->port_egress_floods(ds, port, true, mrouter);
312}
313
314int dsa_port_fdb_add(struct dsa_port *dp, const unsigned char *addr,
315 u16 vid)
316{
317 struct dsa_notifier_fdb_info info = {
318 .sw_index = dp->ds->index,
319 .port = dp->index,
320 .addr = addr,
321 .vid = vid,
322 };
323
324 return dsa_port_notify(dp, DSA_NOTIFIER_FDB_ADD, &info);
325}
326
327int dsa_port_fdb_del(struct dsa_port *dp, const unsigned char *addr,
328 u16 vid)
329{
330 struct dsa_notifier_fdb_info info = {
331 .sw_index = dp->ds->index,
332 .port = dp->index,
333 .addr = addr,
334 .vid = vid,
335
336 };
337
338 return dsa_port_notify(dp, DSA_NOTIFIER_FDB_DEL, &info);
339}
340
341int dsa_port_fdb_dump(struct dsa_port *dp, dsa_fdb_dump_cb_t *cb, void *data)
342{
343 struct dsa_switch *ds = dp->ds;
344 int port = dp->index;
345
346 if (!ds->ops->port_fdb_dump)
347 return -EOPNOTSUPP;
348
349 return ds->ops->port_fdb_dump(ds, port, cb, data);
350}
351
352int dsa_port_mdb_add(const struct dsa_port *dp,
353 const struct switchdev_obj_port_mdb *mdb,
354 struct switchdev_trans *trans)
355{
356 struct dsa_notifier_mdb_info info = {
357 .sw_index = dp->ds->index,
358 .port = dp->index,
359 .trans = trans,
360 .mdb = mdb,
361 };
362
363 return dsa_port_notify(dp, DSA_NOTIFIER_MDB_ADD, &info);
364}
365
366int dsa_port_mdb_del(const struct dsa_port *dp,
367 const struct switchdev_obj_port_mdb *mdb)
368{
369 struct dsa_notifier_mdb_info info = {
370 .sw_index = dp->ds->index,
371 .port = dp->index,
372 .mdb = mdb,
373 };
374
375 return dsa_port_notify(dp, DSA_NOTIFIER_MDB_DEL, &info);
376}
377
378int dsa_port_vlan_add(struct dsa_port *dp,
379 const struct switchdev_obj_port_vlan *vlan,
380 struct switchdev_trans *trans)
381{
382 struct dsa_notifier_vlan_info info = {
383 .sw_index = dp->ds->index,
384 .port = dp->index,
385 .trans = trans,
386 .vlan = vlan,
387 };
388
389 return dsa_port_notify(dp, DSA_NOTIFIER_VLAN_ADD, &info);
390}
391
392int dsa_port_vlan_del(struct dsa_port *dp,
393 const struct switchdev_obj_port_vlan *vlan)
394{
395 struct dsa_notifier_vlan_info info = {
396 .sw_index = dp->ds->index,
397 .port = dp->index,
398 .vlan = vlan,
399 };
400
401 return dsa_port_notify(dp, DSA_NOTIFIER_VLAN_DEL, &info);
402}
403
404int dsa_port_vid_add(struct dsa_port *dp, u16 vid, u16 flags)
405{
406 struct switchdev_obj_port_vlan vlan = {
407 .obj.id = SWITCHDEV_OBJ_ID_PORT_VLAN,
408 .flags = flags,
409 .vid_begin = vid,
410 .vid_end = vid,
411 };
412 struct switchdev_trans trans;
413 int err;
414
415 trans.ph_prepare = true;
416 err = dsa_port_vlan_add(dp, &vlan, &trans);
417 if (err)
418 return err;
419
420 trans.ph_prepare = false;
421 return dsa_port_vlan_add(dp, &vlan, &trans);
422}
423EXPORT_SYMBOL(dsa_port_vid_add);
424
425int dsa_port_vid_del(struct dsa_port *dp, u16 vid)
426{
427 struct switchdev_obj_port_vlan vlan = {
428 .obj.id = SWITCHDEV_OBJ_ID_PORT_VLAN,
429 .vid_begin = vid,
430 .vid_end = vid,
431 };
432
433 return dsa_port_vlan_del(dp, &vlan);
434}
435EXPORT_SYMBOL(dsa_port_vid_del);
436
437static struct phy_device *dsa_port_get_phy_device(struct dsa_port *dp)
438{
439 struct device_node *phy_dn;
440 struct phy_device *phydev;
441
442 phy_dn = of_parse_phandle(dp->dn, "phy-handle", 0);
443 if (!phy_dn)
444 return NULL;
445
446 phydev = of_phy_find_device(phy_dn);
447 if (!phydev) {
448 of_node_put(phy_dn);
449 return ERR_PTR(-EPROBE_DEFER);
450 }
451
452 of_node_put(phy_dn);
453 return phydev;
454}
455
456void dsa_port_phylink_validate(struct phylink_config *config,
457 unsigned long *supported,
458 struct phylink_link_state *state)
459{
460 struct dsa_port *dp = container_of(config, struct dsa_port, pl_config);
461 struct dsa_switch *ds = dp->ds;
462
463 if (!ds->ops->phylink_validate)
464 return;
465
466 ds->ops->phylink_validate(ds, dp->index, supported, state);
467}
468EXPORT_SYMBOL_GPL(dsa_port_phylink_validate);
469
470int dsa_port_phylink_mac_link_state(struct phylink_config *config,
471 struct phylink_link_state *state)
472{
473 struct dsa_port *dp = container_of(config, struct dsa_port, pl_config);
474 struct dsa_switch *ds = dp->ds;
475
476 /* Only called for SGMII and 802.3z */
477 if (!ds->ops->phylink_mac_link_state)
478 return -EOPNOTSUPP;
479
480 return ds->ops->phylink_mac_link_state(ds, dp->index, state);
481}
482EXPORT_SYMBOL_GPL(dsa_port_phylink_mac_link_state);
483
484void dsa_port_phylink_mac_config(struct phylink_config *config,
485 unsigned int mode,
486 const struct phylink_link_state *state)
487{
488 struct dsa_port *dp = container_of(config, struct dsa_port, pl_config);
489 struct dsa_switch *ds = dp->ds;
490
491 if (!ds->ops->phylink_mac_config)
492 return;
493
494 ds->ops->phylink_mac_config(ds, dp->index, mode, state);
495}
496EXPORT_SYMBOL_GPL(dsa_port_phylink_mac_config);
497
498void dsa_port_phylink_mac_an_restart(struct phylink_config *config)
499{
500 struct dsa_port *dp = container_of(config, struct dsa_port, pl_config);
501 struct dsa_switch *ds = dp->ds;
502
503 if (!ds->ops->phylink_mac_an_restart)
504 return;
505
506 ds->ops->phylink_mac_an_restart(ds, dp->index);
507}
508EXPORT_SYMBOL_GPL(dsa_port_phylink_mac_an_restart);
509
510void dsa_port_phylink_mac_link_down(struct phylink_config *config,
511 unsigned int mode,
512 phy_interface_t interface)
513{
514 struct dsa_port *dp = container_of(config, struct dsa_port, pl_config);
515 struct phy_device *phydev = NULL;
516 struct dsa_switch *ds = dp->ds;
517
518 if (dsa_is_user_port(ds, dp->index))
519 phydev = dp->slave->phydev;
520
521 if (!ds->ops->phylink_mac_link_down) {
522 if (ds->ops->adjust_link && phydev)
523 ds->ops->adjust_link(ds, dp->index, phydev);
524 return;
525 }
526
527 ds->ops->phylink_mac_link_down(ds, dp->index, mode, interface);
528}
529EXPORT_SYMBOL_GPL(dsa_port_phylink_mac_link_down);
530
531void dsa_port_phylink_mac_link_up(struct phylink_config *config,
532 unsigned int mode,
533 phy_interface_t interface,
534 struct phy_device *phydev)
535{
536 struct dsa_port *dp = container_of(config, struct dsa_port, pl_config);
537 struct dsa_switch *ds = dp->ds;
538
539 if (!ds->ops->phylink_mac_link_up) {
540 if (ds->ops->adjust_link && phydev)
541 ds->ops->adjust_link(ds, dp->index, phydev);
542 return;
543 }
544
545 ds->ops->phylink_mac_link_up(ds, dp->index, mode, interface, phydev);
546}
547EXPORT_SYMBOL_GPL(dsa_port_phylink_mac_link_up);
548
549const struct phylink_mac_ops dsa_port_phylink_mac_ops = {
550 .validate = dsa_port_phylink_validate,
551 .mac_link_state = dsa_port_phylink_mac_link_state,
552 .mac_config = dsa_port_phylink_mac_config,
553 .mac_an_restart = dsa_port_phylink_mac_an_restart,
554 .mac_link_down = dsa_port_phylink_mac_link_down,
555 .mac_link_up = dsa_port_phylink_mac_link_up,
556};
557
558static int dsa_port_setup_phy_of(struct dsa_port *dp, bool enable)
559{
560 struct dsa_switch *ds = dp->ds;
561 struct phy_device *phydev;
562 int port = dp->index;
563 int err = 0;
564
565 phydev = dsa_port_get_phy_device(dp);
566 if (!phydev)
567 return 0;
568
569 if (IS_ERR(phydev))
570 return PTR_ERR(phydev);
571
572 if (enable) {
573 err = genphy_resume(phydev);
574 if (err < 0)
575 goto err_put_dev;
576
577 err = genphy_read_status(phydev);
578 if (err < 0)
579 goto err_put_dev;
580 } else {
581 err = genphy_suspend(phydev);
582 if (err < 0)
583 goto err_put_dev;
584 }
585
586 if (ds->ops->adjust_link)
587 ds->ops->adjust_link(ds, port, phydev);
588
589 dev_dbg(ds->dev, "enabled port's phy: %s", phydev_name(phydev));
590
591err_put_dev:
592 put_device(&phydev->mdio.dev);
593 return err;
594}
595
596static int dsa_port_fixed_link_register_of(struct dsa_port *dp)
597{
598 struct device_node *dn = dp->dn;
599 struct dsa_switch *ds = dp->ds;
600 struct phy_device *phydev;
601 int port = dp->index;
602 int mode;
603 int err;
604
605 err = of_phy_register_fixed_link(dn);
606 if (err) {
607 dev_err(ds->dev,
608 "failed to register the fixed PHY of port %d\n",
609 port);
610 return err;
611 }
612
613 phydev = of_phy_find_device(dn);
614
615 mode = of_get_phy_mode(dn);
616 if (mode < 0)
617 mode = PHY_INTERFACE_MODE_NA;
618 phydev->interface = mode;
619
620 genphy_read_status(phydev);
621
622 if (ds->ops->adjust_link)
623 ds->ops->adjust_link(ds, port, phydev);
624
625 put_device(&phydev->mdio.dev);
626
627 return 0;
628}
629
630static int dsa_port_phylink_register(struct dsa_port *dp)
631{
632 struct dsa_switch *ds = dp->ds;
633 struct device_node *port_dn = dp->dn;
634 int mode, err;
635
636 mode = of_get_phy_mode(port_dn);
637 if (mode < 0)
638 mode = PHY_INTERFACE_MODE_NA;
639
640 dp->pl_config.dev = ds->dev;
641 dp->pl_config.type = PHYLINK_DEV;
642
643 dp->pl = phylink_create(&dp->pl_config, of_fwnode_handle(port_dn),
644 mode, &dsa_port_phylink_mac_ops);
645 if (IS_ERR(dp->pl)) {
646 pr_err("error creating PHYLINK: %ld\n", PTR_ERR(dp->pl));
647 return PTR_ERR(dp->pl);
648 }
649
650 err = phylink_of_phy_connect(dp->pl, port_dn, 0);
651 if (err && err != -ENODEV) {
652 pr_err("could not attach to PHY: %d\n", err);
653 goto err_phy_connect;
654 }
655
656 return 0;
657
658err_phy_connect:
659 phylink_destroy(dp->pl);
660 return err;
661}
662
663int dsa_port_link_register_of(struct dsa_port *dp)
664{
665 struct dsa_switch *ds = dp->ds;
666 struct device_node *phy_np;
667
668 if (!ds->ops->adjust_link) {
669 phy_np = of_parse_phandle(dp->dn, "phy-handle", 0);
670 if (of_phy_is_fixed_link(dp->dn) || phy_np)
671 return dsa_port_phylink_register(dp);
672 return 0;
673 }
674
675 dev_warn(ds->dev,
676 "Using legacy PHYLIB callbacks. Please migrate to PHYLINK!\n");
677
678 if (of_phy_is_fixed_link(dp->dn))
679 return dsa_port_fixed_link_register_of(dp);
680 else
681 return dsa_port_setup_phy_of(dp, true);
682}
683
684void dsa_port_link_unregister_of(struct dsa_port *dp)
685{
686 struct dsa_switch *ds = dp->ds;
687
688 if (!ds->ops->adjust_link && dp->pl) {
689 rtnl_lock();
690 phylink_disconnect_phy(dp->pl);
691 rtnl_unlock();
692 phylink_destroy(dp->pl);
693 dp->pl = NULL;
694 return;
695 }
696
697 if (of_phy_is_fixed_link(dp->dn))
698 of_phy_deregister_fixed_link(dp->dn);
699 else
700 dsa_port_setup_phy_of(dp, false);
701}
702
703int dsa_port_get_phy_strings(struct dsa_port *dp, uint8_t *data)
704{
705 struct phy_device *phydev;
706 int ret = -EOPNOTSUPP;
707
708 if (of_phy_is_fixed_link(dp->dn))
709 return ret;
710
711 phydev = dsa_port_get_phy_device(dp);
712 if (IS_ERR_OR_NULL(phydev))
713 return ret;
714
715 ret = phy_ethtool_get_strings(phydev, data);
716 put_device(&phydev->mdio.dev);
717
718 return ret;
719}
720EXPORT_SYMBOL_GPL(dsa_port_get_phy_strings);
721
722int dsa_port_get_ethtool_phy_stats(struct dsa_port *dp, uint64_t *data)
723{
724 struct phy_device *phydev;
725 int ret = -EOPNOTSUPP;
726
727 if (of_phy_is_fixed_link(dp->dn))
728 return ret;
729
730 phydev = dsa_port_get_phy_device(dp);
731 if (IS_ERR_OR_NULL(phydev))
732 return ret;
733
734 ret = phy_ethtool_get_stats(phydev, NULL, data);
735 put_device(&phydev->mdio.dev);
736
737 return ret;
738}
739EXPORT_SYMBOL_GPL(dsa_port_get_ethtool_phy_stats);
740
741int dsa_port_get_phy_sset_count(struct dsa_port *dp)
742{
743 struct phy_device *phydev;
744 int ret = -EOPNOTSUPP;
745
746 if (of_phy_is_fixed_link(dp->dn))
747 return ret;
748
749 phydev = dsa_port_get_phy_device(dp);
750 if (IS_ERR_OR_NULL(phydev))
751 return ret;
752
753 ret = phy_ethtool_get_sset_count(phydev);
754 put_device(&phydev->mdio.dev);
755
756 return ret;
757}
758EXPORT_SYMBOL_GPL(dsa_port_get_phy_sset_count);