port.c 16.9 KB
Newer Older
1
// SPDX-License-Identifier: GPL-2.0-or-later
2 3 4 5 6 7 8 9
/*
 * Handling of a single switch port
 *
 * Copyright (c) 2017 Savoir-faire Linux Inc.
 *	Vivien Didelot <vivien.didelot@savoirfairelinux.com>
 */

#include <linux/if_bridge.h>
10
#include <linux/notifier.h>
11 12
#include <linux/of_mdio.h>
#include <linux/of_net.h>
13 14 15

#include "dsa_priv.h"

A
Andrew Lunn 已提交
16
static int dsa_port_notify(const struct dsa_port *dp, unsigned long e, void *v)
17 18 19 20 21 22 23 24 25
{
	struct raw_notifier_head *nh = &dp->ds->dst->nh;
	int err;

	err = raw_notifier_call_chain(nh, e, v);

	return notifier_to_errno(err);
}

26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
int dsa_port_set_state(struct dsa_port *dp, u8 state,
		       struct switchdev_trans *trans)
{
	struct dsa_switch *ds = dp->ds;
	int port = dp->index;

	if (switchdev_trans_ph_prepare(trans))
		return ds->ops->port_stp_state_set ? 0 : -EOPNOTSUPP;

	if (ds->ops->port_stp_state_set)
		ds->ops->port_stp_state_set(ds, port, state);

	if (ds->ops->port_fast_age) {
		/* Fast age FDB entries or flush appropriate forwarding database
		 * for the given port, if we are moving it from Learning or
		 * Forwarding state, to Disabled or Blocking or Listening state.
		 */

		if ((dp->stp_state == BR_STATE_LEARNING ||
		     dp->stp_state == BR_STATE_FORWARDING) &&
		    (state == BR_STATE_DISABLED ||
		     state == BR_STATE_BLOCKING ||
		     state == BR_STATE_LISTENING))
			ds->ops->port_fast_age(ds, port);
	}

	dp->stp_state = state;

	return 0;
}

57
static void dsa_port_set_state_now(struct dsa_port *dp, u8 state)
58 59 60 61 62 63 64
{
	int err;

	err = dsa_port_set_state(dp, state, NULL);
	if (err)
		pr_err("DSA: failed to set STP state %u (%d)\n", state, err);
}
65

66
int dsa_port_enable_rt(struct dsa_port *dp, struct phy_device *phy)
67 68 69 70 71 72 73 74 75 76 77
{
	struct dsa_switch *ds = dp->ds;
	int port = dp->index;
	int err;

	if (ds->ops->port_enable) {
		err = ds->ops->port_enable(ds, port, phy);
		if (err)
			return err;
	}

78 79
	if (!dp->bridge_dev)
		dsa_port_set_state_now(dp, BR_STATE_FORWARDING);
80

81 82 83
	if (dp->pl)
		phylink_start(dp->pl);

84 85 86
	return 0;
}

87 88 89 90 91 92 93 94 95 96 97 98
int dsa_port_enable(struct dsa_port *dp, struct phy_device *phy)
{
	int err;

	rtnl_lock();
	err = dsa_port_enable_rt(dp, phy);
	rtnl_unlock();

	return err;
}

void dsa_port_disable_rt(struct dsa_port *dp)
99 100 101 102
{
	struct dsa_switch *ds = dp->ds;
	int port = dp->index;

103 104 105
	if (dp->pl)
		phylink_stop(dp->pl);

106 107
	if (!dp->bridge_dev)
		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
}

113 114 115 116 117 118 119
void dsa_port_disable(struct dsa_port *dp)
{
	rtnl_lock();
	dsa_port_disable_rt(dp);
	rtnl_unlock();
}

120 121 122 123 124 125 126 127 128
int dsa_port_bridge_join(struct dsa_port *dp, struct net_device *br)
{
	struct dsa_notifier_bridge_info info = {
		.sw_index = dp->ds->index,
		.port = dp->index,
		.br = br,
	};
	int err;

129 130 131 132 133 134 135
	/* Set the flooding mode before joining the port in the switch */
	err = dsa_port_bridge_flags(dp, BR_FLOOD | BR_MCAST_FLOOD, NULL);
	if (err)
		return err;

	/* Here the interface is already bridged. Reflect the current
	 * configuration so that drivers can program their chips accordingly.
136 137 138 139 140 141
	 */
	dp->bridge_dev = br;

	err = dsa_port_notify(dp, DSA_NOTIFIER_BRIDGE_JOIN, &info);

	/* The bridging is rolled back on error */
142 143
	if (err) {
		dsa_port_bridge_flags(dp, 0, NULL);
144
		dp->bridge_dev = NULL;
145
	}
146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167

	return err;
}

void dsa_port_bridge_leave(struct dsa_port *dp, struct net_device *br)
{
	struct dsa_notifier_bridge_info info = {
		.sw_index = dp->ds->index,
		.port = dp->index,
		.br = br,
	};
	int err;

	/* Here the port is already unbridged. Reflect the current configuration
	 * so that drivers can program their chips accordingly.
	 */
	dp->bridge_dev = NULL;

	err = dsa_port_notify(dp, DSA_NOTIFIER_BRIDGE_LEAVE, &info);
	if (err)
		pr_err("DSA: failed to notify DSA_NOTIFIER_BRIDGE_LEAVE\n");

168 169 170
	/* Port is leaving the bridge, disable flooding */
	dsa_port_bridge_flags(dp, 0, NULL);

171 172 173 174 175
	/* Port left the bridge, put in BR_STATE_DISABLED by the bridge layer,
	 * so allow it to be in BR_STATE_FORWARDING to be kept functional
	 */
	dsa_port_set_state_now(dp, BR_STATE_FORWARDING);
}
176

177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209
static bool dsa_port_can_apply_vlan_filtering(struct dsa_port *dp,
					      bool vlan_filtering)
{
	struct dsa_switch *ds = dp->ds;
	int i;

	if (!ds->vlan_filtering_is_global)
		return true;

	/* For cases where enabling/disabling VLAN awareness is global to the
	 * switch, we need to handle the case where multiple bridges span
	 * different ports of the same switch device and one of them has a
	 * different setting than what is being requested.
	 */
	for (i = 0; i < ds->num_ports; i++) {
		struct net_device *other_bridge;

		other_bridge = dsa_to_port(ds, i)->bridge_dev;
		if (!other_bridge)
			continue;
		/* If it's the same bridge, it also has same
		 * vlan_filtering setting => no need to check
		 */
		if (other_bridge == dp->bridge_dev)
			continue;
		if (br_vlan_enabled(other_bridge) != vlan_filtering) {
			dev_err(ds->dev, "VLAN filtering is a global setting\n");
			return false;
		}
	}
	return true;
}

210 211 212 213
int dsa_port_vlan_filtering(struct dsa_port *dp, bool vlan_filtering,
			    struct switchdev_trans *trans)
{
	struct dsa_switch *ds = dp->ds;
214
	int err;
215 216 217 218 219

	/* bridge skips -EOPNOTSUPP, so skip the prepare phase */
	if (switchdev_trans_ph_prepare(trans))
		return 0;

220 221 222 223 224 225
	if (!ds->ops->port_vlan_filtering)
		return 0;

	if (!dsa_port_can_apply_vlan_filtering(dp, vlan_filtering))
		return -EINVAL;

226 227 228
	if (dsa_port_is_vlan_filtering(dp) == vlan_filtering)
		return 0;

229 230 231 232 233
	err = ds->ops->port_vlan_filtering(ds, dp->index,
					   vlan_filtering);
	if (err)
		return err;

234 235 236 237
	if (ds->vlan_filtering_is_global)
		ds->vlan_filtering = vlan_filtering;
	else
		dp->vlan_filtering = vlan_filtering;
238 239
	return 0;
}
240 241 242 243 244 245

int dsa_port_ageing_time(struct dsa_port *dp, clock_t ageing_clock,
			 struct switchdev_trans *trans)
{
	unsigned long ageing_jiffies = clock_t_to_jiffies(ageing_clock);
	unsigned int ageing_time = jiffies_to_msecs(ageing_jiffies);
246 247 248 249
	struct dsa_notifier_ageing_time_info info = {
		.ageing_time = ageing_time,
		.trans = trans,
	};
250

251 252
	if (switchdev_trans_ph_prepare(trans))
		return dsa_port_notify(dp, DSA_NOTIFIER_AGEING_TIME, &info);
253 254 255

	dp->ageing_time = ageing_time;

256
	return dsa_port_notify(dp, DSA_NOTIFIER_AGEING_TIME, &info);
257
}
V
Vivien Didelot 已提交
258

259 260 261 262 263 264 265 266 267 268 269 270
int dsa_port_pre_bridge_flags(const struct dsa_port *dp, unsigned long flags,
			      struct switchdev_trans *trans)
{
	struct dsa_switch *ds = dp->ds;

	if (!ds->ops->port_egress_floods ||
	    (flags & ~(BR_FLOOD | BR_MCAST_FLOOD)))
		return -EINVAL;

	return 0;
}

271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287
int dsa_port_bridge_flags(const struct dsa_port *dp, unsigned long flags,
			  struct switchdev_trans *trans)
{
	struct dsa_switch *ds = dp->ds;
	int port = dp->index;
	int err = 0;

	if (switchdev_trans_ph_prepare(trans))
		return 0;

	if (ds->ops->port_egress_floods)
		err = ds->ops->port_egress_floods(ds, port, flags & BR_FLOOD,
						  flags & BR_MCAST_FLOOD);

	return err;
}

288 289 290 291 292 293 294 295 296 297 298 299
int dsa_port_mrouter(struct dsa_port *dp, bool mrouter,
		     struct switchdev_trans *trans)
{
	struct dsa_switch *ds = dp->ds;
	int port = dp->index;

	if (switchdev_trans_ph_prepare(trans))
		return ds->ops->port_egress_floods ? 0 : -EOPNOTSUPP;

	return ds->ops->port_egress_floods(ds, port, true, mrouter);
}

300 301
int dsa_port_fdb_add(struct dsa_port *dp, const unsigned char *addr,
		     u16 vid)
V
Vivien Didelot 已提交
302
{
V
Vivien Didelot 已提交
303 304 305
	struct dsa_notifier_fdb_info info = {
		.sw_index = dp->ds->index,
		.port = dp->index,
306 307
		.addr = addr,
		.vid = vid,
V
Vivien Didelot 已提交
308
	};
V
Vivien Didelot 已提交
309

V
Vivien Didelot 已提交
310
	return dsa_port_notify(dp, DSA_NOTIFIER_FDB_ADD, &info);
V
Vivien Didelot 已提交
311 312
}

313 314
int dsa_port_fdb_del(struct dsa_port *dp, const unsigned char *addr,
		     u16 vid)
V
Vivien Didelot 已提交
315
{
V
Vivien Didelot 已提交
316 317 318
	struct dsa_notifier_fdb_info info = {
		.sw_index = dp->ds->index,
		.port = dp->index,
319 320 321
		.addr = addr,
		.vid = vid,

V
Vivien Didelot 已提交
322
	};
V
Vivien Didelot 已提交
323

V
Vivien Didelot 已提交
324
	return dsa_port_notify(dp, DSA_NOTIFIER_FDB_DEL, &info);
V
Vivien Didelot 已提交
325 326
}

V
Vivien Didelot 已提交
327 328 329 330 331 332 333 334 335 336 337
int dsa_port_fdb_dump(struct dsa_port *dp, dsa_fdb_dump_cb_t *cb, void *data)
{
	struct dsa_switch *ds = dp->ds;
	int port = dp->index;

	if (!ds->ops->port_fdb_dump)
		return -EOPNOTSUPP;

	return ds->ops->port_fdb_dump(ds, port, cb, data);
}

A
Andrew Lunn 已提交
338
int dsa_port_mdb_add(const struct dsa_port *dp,
V
Vivien Didelot 已提交
339 340 341
		     const struct switchdev_obj_port_mdb *mdb,
		     struct switchdev_trans *trans)
{
V
Vivien Didelot 已提交
342 343 344 345 346 347
	struct dsa_notifier_mdb_info info = {
		.sw_index = dp->ds->index,
		.port = dp->index,
		.trans = trans,
		.mdb = mdb,
	};
V
Vivien Didelot 已提交
348

V
Vivien Didelot 已提交
349
	return dsa_port_notify(dp, DSA_NOTIFIER_MDB_ADD, &info);
V
Vivien Didelot 已提交
350 351
}

A
Andrew Lunn 已提交
352
int dsa_port_mdb_del(const struct dsa_port *dp,
V
Vivien Didelot 已提交
353 354
		     const struct switchdev_obj_port_mdb *mdb)
{
V
Vivien Didelot 已提交
355 356 357 358 359
	struct dsa_notifier_mdb_info info = {
		.sw_index = dp->ds->index,
		.port = dp->index,
		.mdb = mdb,
	};
V
Vivien Didelot 已提交
360

V
Vivien Didelot 已提交
361
	return dsa_port_notify(dp, DSA_NOTIFIER_MDB_DEL, &info);
V
Vivien Didelot 已提交
362 363
}

V
Vivien Didelot 已提交
364 365 366 367
int dsa_port_vlan_add(struct dsa_port *dp,
		      const struct switchdev_obj_port_vlan *vlan,
		      struct switchdev_trans *trans)
{
V
Vivien Didelot 已提交
368 369 370 371 372 373
	struct dsa_notifier_vlan_info info = {
		.sw_index = dp->ds->index,
		.port = dp->index,
		.trans = trans,
		.vlan = vlan,
	};
V
Vivien Didelot 已提交
374

375
	return dsa_port_notify(dp, DSA_NOTIFIER_VLAN_ADD, &info);
V
Vivien Didelot 已提交
376 377 378 379 380
}

int dsa_port_vlan_del(struct dsa_port *dp,
		      const struct switchdev_obj_port_vlan *vlan)
{
V
Vivien Didelot 已提交
381 382 383 384 385
	struct dsa_notifier_vlan_info info = {
		.sw_index = dp->ds->index,
		.port = dp->index,
		.vlan = vlan,
	};
V
Vivien Didelot 已提交
386

387
	return dsa_port_notify(dp, DSA_NOTIFIER_VLAN_DEL, &info);
V
Vivien Didelot 已提交
388
}
389

390 391 392 393 394 395 396 397 398 399 400 401 402
int dsa_port_vid_add(struct dsa_port *dp, u16 vid, u16 flags)
{
	struct switchdev_obj_port_vlan vlan = {
		.obj.id = SWITCHDEV_OBJ_ID_PORT_VLAN,
		.flags = flags,
		.vid_begin = vid,
		.vid_end = vid,
	};
	struct switchdev_trans trans;
	int err;

	trans.ph_prepare = true;
	err = dsa_port_vlan_add(dp, &vlan, &trans);
403 404
	if (err)
		return err;
405 406 407 408

	trans.ph_prepare = false;
	return dsa_port_vlan_add(dp, &vlan, &trans);
}
409
EXPORT_SYMBOL(dsa_port_vid_add);
410 411 412 413 414 415 416 417 418 419 420

int dsa_port_vid_del(struct dsa_port *dp, u16 vid)
{
	struct switchdev_obj_port_vlan vlan = {
		.obj.id = SWITCHDEV_OBJ_ID_PORT_VLAN,
		.vid_begin = vid,
		.vid_end = vid,
	};

	return dsa_port_vlan_del(dp, &vlan);
}
421
EXPORT_SYMBOL(dsa_port_vid_del);
422

423
static struct phy_device *dsa_port_get_phy_device(struct dsa_port *dp)
424 425 426 427
{
	struct device_node *phy_dn;
	struct phy_device *phydev;

428
	phy_dn = of_parse_phandle(dp->dn, "phy-handle", 0);
429
	if (!phy_dn)
430
		return NULL;
431 432 433

	phydev = of_phy_find_device(phy_dn);
	if (!phydev) {
434 435
		of_node_put(phy_dn);
		return ERR_PTR(-EPROBE_DEFER);
436 437
	}

438
	of_node_put(phy_dn);
439 440 441
	return phydev;
}

442 443 444
static void dsa_port_phylink_validate(struct phylink_config *config,
				      unsigned long *supported,
				      struct phylink_link_state *state)
445 446 447 448 449 450 451 452 453 454
{
	struct dsa_port *dp = container_of(config, struct dsa_port, pl_config);
	struct dsa_switch *ds = dp->ds;

	if (!ds->ops->phylink_validate)
		return;

	ds->ops->phylink_validate(ds, dp->index, supported, state);
}

455 456
static void dsa_port_phylink_mac_pcs_get_state(struct phylink_config *config,
					       struct phylink_link_state *state)
457 458 459 460
{
	struct dsa_port *dp = container_of(config, struct dsa_port, pl_config);
	struct dsa_switch *ds = dp->ds;

461 462 463 464 465
	/* Only called for inband modes */
	if (!ds->ops->phylink_mac_link_state) {
		state->link = 0;
		return;
	}
466

467 468
	if (ds->ops->phylink_mac_link_state(ds, dp->index, state) < 0)
		state->link = 0;
469 470
}

471 472 473
static void dsa_port_phylink_mac_config(struct phylink_config *config,
					unsigned int mode,
					const struct phylink_link_state *state)
474 475 476 477 478 479 480 481 482 483
{
	struct dsa_port *dp = container_of(config, struct dsa_port, pl_config);
	struct dsa_switch *ds = dp->ds;

	if (!ds->ops->phylink_mac_config)
		return;

	ds->ops->phylink_mac_config(ds, dp->index, mode, state);
}

484
static void dsa_port_phylink_mac_an_restart(struct phylink_config *config)
485 486 487 488 489 490 491 492 493 494
{
	struct dsa_port *dp = container_of(config, struct dsa_port, pl_config);
	struct dsa_switch *ds = dp->ds;

	if (!ds->ops->phylink_mac_an_restart)
		return;

	ds->ops->phylink_mac_an_restart(ds, dp->index);
}

495 496 497
static void dsa_port_phylink_mac_link_down(struct phylink_config *config,
					   unsigned int mode,
					   phy_interface_t interface)
498 499
{
	struct dsa_port *dp = container_of(config, struct dsa_port, pl_config);
500
	struct phy_device *phydev = NULL;
501 502
	struct dsa_switch *ds = dp->ds;

503 504 505
	if (dsa_is_user_port(ds, dp->index))
		phydev = dp->slave->phydev;

506
	if (!ds->ops->phylink_mac_link_down) {
507 508
		if (ds->ops->adjust_link && phydev)
			ds->ops->adjust_link(ds, dp->index, phydev);
509 510 511 512 513 514
		return;
	}

	ds->ops->phylink_mac_link_down(ds, dp->index, mode, interface);
}

515 516 517 518
static void dsa_port_phylink_mac_link_up(struct phylink_config *config,
					 unsigned int mode,
					 phy_interface_t interface,
					 struct phy_device *phydev)
519 520 521 522 523
{
	struct dsa_port *dp = container_of(config, struct dsa_port, pl_config);
	struct dsa_switch *ds = dp->ds;

	if (!ds->ops->phylink_mac_link_up) {
524 525
		if (ds->ops->adjust_link && phydev)
			ds->ops->adjust_link(ds, dp->index, phydev);
526 527 528 529 530 531 532 533
		return;
	}

	ds->ops->phylink_mac_link_up(ds, dp->index, mode, interface, phydev);
}

const struct phylink_mac_ops dsa_port_phylink_mac_ops = {
	.validate = dsa_port_phylink_validate,
534
	.mac_pcs_get_state = dsa_port_phylink_mac_pcs_get_state,
535 536 537 538 539 540
	.mac_config = dsa_port_phylink_mac_config,
	.mac_an_restart = dsa_port_phylink_mac_an_restart,
	.mac_link_down = dsa_port_phylink_mac_link_down,
	.mac_link_up = dsa_port_phylink_mac_link_up,
};

541 542 543 544 545 546 547 548 549 550 551 552 553 554
static int dsa_port_setup_phy_of(struct dsa_port *dp, bool enable)
{
	struct dsa_switch *ds = dp->ds;
	struct phy_device *phydev;
	int port = dp->index;
	int err = 0;

	phydev = dsa_port_get_phy_device(dp);
	if (!phydev)
		return 0;

	if (IS_ERR(phydev))
		return PTR_ERR(phydev);

555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579
	if (enable) {
		err = genphy_resume(phydev);
		if (err < 0)
			goto err_put_dev;

		err = genphy_read_status(phydev);
		if (err < 0)
			goto err_put_dev;
	} else {
		err = genphy_suspend(phydev);
		if (err < 0)
			goto err_put_dev;
	}

	if (ds->ops->adjust_link)
		ds->ops->adjust_link(ds, port, phydev);

	dev_dbg(ds->dev, "enabled port's phy: %s", phydev_name(phydev));

err_put_dev:
	put_device(&phydev->mdio.dev);
	return err;
}

static int dsa_port_fixed_link_register_of(struct dsa_port *dp)
580 581 582 583 584
{
	struct device_node *dn = dp->dn;
	struct dsa_switch *ds = dp->ds;
	struct phy_device *phydev;
	int port = dp->index;
585
	phy_interface_t mode;
586 587
	int err;

588 589 590 591 592 593 594
	err = of_phy_register_fixed_link(dn);
	if (err) {
		dev_err(ds->dev,
			"failed to register the fixed PHY of port %d\n",
			port);
		return err;
	}
595

596
	phydev = of_phy_find_device(dn);
597

598 599
	err = of_get_phy_mode(dn, &mode);
	if (err)
600 601
		mode = PHY_INTERFACE_MODE_NA;
	phydev->interface = mode;
602

603
	genphy_read_status(phydev);
604

605 606
	if (ds->ops->adjust_link)
		ds->ops->adjust_link(ds, port, phydev);
607

608
	put_device(&phydev->mdio.dev);
609 610 611 612

	return 0;
}

613 614 615 616
static int dsa_port_phylink_register(struct dsa_port *dp)
{
	struct dsa_switch *ds = dp->ds;
	struct device_node *port_dn = dp->dn;
617 618
	phy_interface_t mode;
	int err;
619

620 621
	err = of_get_phy_mode(port_dn, &mode);
	if (err)
622 623 624 625
		mode = PHY_INTERFACE_MODE_NA;

	dp->pl_config.dev = ds->dev;
	dp->pl_config.type = PHYLINK_DEV;
626
	dp->pl_config.pcs_poll = ds->pcs_poll;
627 628 629 630 631 632 633 634 635

	dp->pl = phylink_create(&dp->pl_config, of_fwnode_handle(port_dn),
				mode, &dsa_port_phylink_mac_ops);
	if (IS_ERR(dp->pl)) {
		pr_err("error creating PHYLINK: %ld\n", PTR_ERR(dp->pl));
		return PTR_ERR(dp->pl);
	}

	err = phylink_of_phy_connect(dp->pl, port_dn, 0);
636
	if (err && err != -ENODEV) {
637 638 639 640 641 642 643 644 645 646 647
		pr_err("could not attach to PHY: %d\n", err);
		goto err_phy_connect;
	}

	return 0;

err_phy_connect:
	phylink_destroy(dp->pl);
	return err;
}

648
int dsa_port_link_register_of(struct dsa_port *dp)
649
{
650
	struct dsa_switch *ds = dp->ds;
651
	struct device_node *phy_np;
652

653 654 655 656 657 658
	if (!ds->ops->adjust_link) {
		phy_np = of_parse_phandle(dp->dn, "phy-handle", 0);
		if (of_phy_is_fixed_link(dp->dn) || phy_np)
			return dsa_port_phylink_register(dp);
		return 0;
	}
659 660 661 662

	dev_warn(ds->dev,
		 "Using legacy PHYLIB callbacks. Please migrate to PHYLINK!\n");

663 664 665 666 667
	if (of_phy_is_fixed_link(dp->dn))
		return dsa_port_fixed_link_register_of(dp);
	else
		return dsa_port_setup_phy_of(dp, true);
}
668

669 670
void dsa_port_link_unregister_of(struct dsa_port *dp)
{
671 672
	struct dsa_switch *ds = dp->ds;

673
	if (!ds->ops->adjust_link && dp->pl) {
674 675 676 677
		rtnl_lock();
		phylink_disconnect_phy(dp->pl);
		rtnl_unlock();
		phylink_destroy(dp->pl);
678
		dp->pl = NULL;
679 680 681
		return;
	}

682 683 684 685
	if (of_phy_is_fixed_link(dp->dn))
		of_phy_deregister_fixed_link(dp->dn);
	else
		dsa_port_setup_phy_of(dp, false);
686
}
687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743

int dsa_port_get_phy_strings(struct dsa_port *dp, uint8_t *data)
{
	struct phy_device *phydev;
	int ret = -EOPNOTSUPP;

	if (of_phy_is_fixed_link(dp->dn))
		return ret;

	phydev = dsa_port_get_phy_device(dp);
	if (IS_ERR_OR_NULL(phydev))
		return ret;

	ret = phy_ethtool_get_strings(phydev, data);
	put_device(&phydev->mdio.dev);

	return ret;
}
EXPORT_SYMBOL_GPL(dsa_port_get_phy_strings);

int dsa_port_get_ethtool_phy_stats(struct dsa_port *dp, uint64_t *data)
{
	struct phy_device *phydev;
	int ret = -EOPNOTSUPP;

	if (of_phy_is_fixed_link(dp->dn))
		return ret;

	phydev = dsa_port_get_phy_device(dp);
	if (IS_ERR_OR_NULL(phydev))
		return ret;

	ret = phy_ethtool_get_stats(phydev, NULL, data);
	put_device(&phydev->mdio.dev);

	return ret;
}
EXPORT_SYMBOL_GPL(dsa_port_get_ethtool_phy_stats);

int dsa_port_get_phy_sset_count(struct dsa_port *dp)
{
	struct phy_device *phydev;
	int ret = -EOPNOTSUPP;

	if (of_phy_is_fixed_link(dp->dn))
		return ret;

	phydev = dsa_port_get_phy_device(dp);
	if (IS_ERR_OR_NULL(phydev))
		return ret;

	ret = phy_ethtool_get_sset_count(phydev);
	put_device(&phydev->mdio.dev);

	return ret;
}
EXPORT_SYMBOL_GPL(dsa_port_get_phy_sset_count);