Lines Matching +full:ethernet +full:- +full:ports
1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * net/dsa/dsa2.c - Hardware switch handling, binding version 2
4 * Copyright (c) 2008-2009 Marvell Semiconductor
30 if (dst->index != tree_index) in dsa_switch_find()
33 list_for_each_entry(dp, &dst->ports, list) { in dsa_switch_find()
34 if (dp->ds->index != sw_index) in dsa_switch_find()
37 return dp->ds; in dsa_switch_find()
50 if (dst->index == index) in dsa_tree_find()
64 dst->index = index; in dsa_tree_alloc()
66 INIT_LIST_HEAD(&dst->rtable); in dsa_tree_alloc()
68 INIT_LIST_HEAD(&dst->ports); in dsa_tree_alloc()
70 INIT_LIST_HEAD(&dst->list); in dsa_tree_alloc()
71 list_add_tail(&dst->list, &dsa_tree_list); in dsa_tree_alloc()
73 kref_init(&dst->refcount); in dsa_tree_alloc()
80 list_del(&dst->list); in dsa_tree_free()
87 kref_get(&dst->refcount); in dsa_tree_get()
115 kref_put(&dst->refcount, dsa_tree_release); in dsa_tree_put()
120 return port->type == DSA_PORT_TYPE_DSA; in dsa_port_is_dsa()
125 return port->type == DSA_PORT_TYPE_CPU; in dsa_port_is_cpu()
130 return dp->type == DSA_PORT_TYPE_USER; in dsa_port_is_user()
138 list_for_each_entry(dp, &dst->ports, list) in dsa_tree_find_port_by_node()
139 if (dp->dn == dn) in dsa_tree_find_port_by_node()
148 struct dsa_switch *ds = dp->ds; in dsa_link_touch()
152 dst = ds->dst; in dsa_link_touch()
154 list_for_each_entry(dl, &dst->rtable, list) in dsa_link_touch()
155 if (dl->dp == dp && dl->link_dp == link_dp) in dsa_link_touch()
162 dl->dp = dp; in dsa_link_touch()
163 dl->link_dp = link_dp; in dsa_link_touch()
165 INIT_LIST_HEAD(&dl->list); in dsa_link_touch()
166 list_add_tail(&dl->list, &dst->rtable); in dsa_link_touch()
173 struct dsa_switch *ds = dp->ds; in dsa_port_setup_routing_table()
174 struct dsa_switch_tree *dst = ds->dst; in dsa_port_setup_routing_table()
175 struct device_node *dn = dp->dn; in dsa_port_setup_routing_table()
203 list_for_each_entry(dp, &dst->ports, list) { in dsa_tree_setup_routing_table()
218 list_for_each_entry(dp, &dst->ports, list) in dsa_tree_find_first_cpu()
231 pr_err("DSA: tree %d has no CPU port\n", dst->index); in dsa_tree_setup_default_cpu()
232 return -EINVAL; in dsa_tree_setup_default_cpu()
235 /* Assign the default CPU port to all ports of the fabric */ in dsa_tree_setup_default_cpu()
236 list_for_each_entry(dp, &dst->ports, list) in dsa_tree_setup_default_cpu()
238 dp->cpu_dp = cpu_dp; in dsa_tree_setup_default_cpu()
247 list_for_each_entry(dp, &dst->ports, list) in dsa_tree_teardown_default_cpu()
249 dp->cpu_dp = NULL; in dsa_tree_teardown_default_cpu()
254 struct devlink_port *dlp = &dp->devlink_port; in dsa_port_setup()
259 if (dp->setup) in dsa_port_setup()
262 switch (dp->type) { in dsa_port_setup()
291 dp->mac = of_get_mac_address(dp->dn); in dsa_port_setup()
296 devlink_port_type_eth_set(dlp, dp->slave); in dsa_port_setup()
307 dp->setup = true; in dsa_port_setup()
314 struct devlink_port *dlp = &dp->devlink_port; in dsa_port_devlink_setup()
315 struct dsa_switch_tree *dst = dp->ds->dst; in dsa_port_devlink_setup()
317 struct devlink *dl = dp->ds->devlink; in dsa_port_devlink_setup()
322 id = (const unsigned char *)&dst->index; in dsa_port_devlink_setup()
323 len = sizeof(dst->index); in dsa_port_devlink_setup()
325 attrs.phys.port_number = dp->index; in dsa_port_devlink_setup()
330 switch (dp->type) { in dsa_port_devlink_setup()
346 err = devlink_port_register(dl, dlp, dp->index); in dsa_port_devlink_setup()
349 dp->devlink_port_setup = true; in dsa_port_devlink_setup()
356 if (!dp->setup) in dsa_port_teardown()
359 switch (dp->type) { in dsa_port_teardown()
364 dsa_tag_driver_put(dp->tag_ops); in dsa_port_teardown()
372 if (dp->slave) { in dsa_port_teardown()
373 dsa_slave_destroy(dp->slave); in dsa_port_teardown()
374 dp->slave = NULL; in dsa_port_teardown()
379 dp->setup = false; in dsa_port_teardown()
384 struct devlink_port *dlp = &dp->devlink_port; in dsa_port_devlink_teardown()
386 if (dp->devlink_port_setup) in dsa_port_devlink_teardown()
388 dp->devlink_port_setup = false; in dsa_port_devlink_teardown()
397 if (ds->ops->devlink_info_get) in dsa_devlink_info_get()
398 return ds->ops->devlink_info_get(ds, req, extack); in dsa_devlink_info_get()
400 return -EOPNOTSUPP; in dsa_devlink_info_get()
413 if (ds->setup) in dsa_switch_setup()
416 /* Initialize ds->phys_mii_mask before registering the slave MDIO bus in dsa_switch_setup()
417 * driver and before ops->setup() has run, since the switch drivers and in dsa_switch_setup()
421 ds->phys_mii_mask |= dsa_user_ports(ds); in dsa_switch_setup()
426 ds->devlink = devlink_alloc(&dsa_devlink_ops, sizeof(*dl_priv)); in dsa_switch_setup()
427 if (!ds->devlink) in dsa_switch_setup()
428 return -ENOMEM; in dsa_switch_setup()
429 dl_priv = devlink_priv(ds->devlink); in dsa_switch_setup()
430 dl_priv->ds = ds; in dsa_switch_setup()
432 err = devlink_register(ds->devlink, ds->dev); in dsa_switch_setup()
437 * setup() can register regions etc, against the ports in dsa_switch_setup()
439 list_for_each_entry(dp, &ds->dst->ports, list) { in dsa_switch_setup()
440 if (dp->ds == ds) { in dsa_switch_setup()
451 err = ds->ops->setup(ds); in dsa_switch_setup()
455 devlink_params_publish(ds->devlink); in dsa_switch_setup()
457 if (!ds->slave_mii_bus && ds->ops->phy_read) { in dsa_switch_setup()
458 ds->slave_mii_bus = devm_mdiobus_alloc(ds->dev); in dsa_switch_setup()
459 if (!ds->slave_mii_bus) { in dsa_switch_setup()
460 err = -ENOMEM; in dsa_switch_setup()
466 err = mdiobus_register(ds->slave_mii_bus); in dsa_switch_setup()
471 ds->setup = true; in dsa_switch_setup()
478 list_for_each_entry(dp, &ds->dst->ports, list) in dsa_switch_setup()
479 if (dp->ds == ds) in dsa_switch_setup()
481 devlink_unregister(ds->devlink); in dsa_switch_setup()
483 devlink_free(ds->devlink); in dsa_switch_setup()
484 ds->devlink = NULL; in dsa_switch_setup()
493 if (!ds->setup) in dsa_switch_teardown()
496 if (ds->slave_mii_bus && ds->ops->phy_read) in dsa_switch_teardown()
497 mdiobus_unregister(ds->slave_mii_bus); in dsa_switch_teardown()
501 if (ds->ops->teardown) in dsa_switch_teardown()
502 ds->ops->teardown(ds); in dsa_switch_teardown()
504 if (ds->devlink) { in dsa_switch_teardown()
505 list_for_each_entry(dp, &ds->dst->ports, list) in dsa_switch_teardown()
506 if (dp->ds == ds) in dsa_switch_teardown()
508 devlink_unregister(ds->devlink); in dsa_switch_teardown()
509 devlink_free(ds->devlink); in dsa_switch_teardown()
510 ds->devlink = NULL; in dsa_switch_teardown()
513 ds->setup = false; in dsa_switch_teardown()
521 list_for_each_entry(dp, &dst->ports, list) { in dsa_tree_setup_switches()
522 err = dsa_switch_setup(dp->ds); in dsa_tree_setup_switches()
527 list_for_each_entry(dp, &dst->ports, list) { in dsa_tree_setup_switches()
536 list_for_each_entry(dp, &dst->ports, list) in dsa_tree_setup_switches()
539 list_for_each_entry(dp, &dst->ports, list) in dsa_tree_setup_switches()
540 dsa_switch_teardown(dp->ds); in dsa_tree_setup_switches()
549 list_for_each_entry(dp, &dst->ports, list) in dsa_tree_teardown_switches()
552 list_for_each_entry(dp, &dst->ports, list) in dsa_tree_teardown_switches()
553 dsa_switch_teardown(dp->ds); in dsa_tree_teardown_switches()
561 list_for_each_entry(dp, &dst->ports, list) { in dsa_tree_setup_master()
563 err = dsa_master_setup(dp->master, dp); in dsa_tree_setup_master()
576 list_for_each_entry(dp, &dst->ports, list) in dsa_tree_teardown_master()
578 dsa_master_teardown(dp->master); in dsa_tree_teardown_master()
586 if (dst->setup) { in dsa_tree_setup()
588 dst->index); in dsa_tree_setup()
589 return -EEXIST; in dsa_tree_setup()
608 dst->setup = true; in dsa_tree_setup()
610 pr_info("DSA: tree %d setup\n", dst->index); in dsa_tree_setup()
626 if (!dst->setup) in dsa_tree_teardown()
635 list_for_each_entry_safe(dl, next, &dst->rtable, list) { in dsa_tree_teardown()
636 list_del(&dl->list); in dsa_tree_teardown()
640 pr_info("DSA: tree %d torn down\n", dst->index); in dsa_tree_teardown()
642 dst->setup = false; in dsa_tree_teardown()
647 struct dsa_switch_tree *dst = ds->dst; in dsa_port_touch()
650 list_for_each_entry(dp, &dst->ports, list) in dsa_port_touch()
651 if (dp->ds == ds && dp->index == index) in dsa_port_touch()
658 dp->ds = ds; in dsa_port_touch()
659 dp->index = index; in dsa_port_touch()
661 INIT_LIST_HEAD(&dp->list); in dsa_port_touch()
662 list_add_tail(&dp->list, &dst->ports); in dsa_port_touch()
672 dp->type = DSA_PORT_TYPE_USER; in dsa_port_parse_user()
673 dp->name = name; in dsa_port_parse_user()
680 dp->type = DSA_PORT_TYPE_DSA; in dsa_port_parse_dsa()
689 struct dsa_switch *mds, *ds = dp->ds; in dsa_get_tag_protocol()
699 mds = mdp->ds; in dsa_get_tag_protocol()
700 mdp_upstream = dsa_upstream_port(mds, mdp->index); in dsa_get_tag_protocol()
701 tag_protocol = mds->ops->get_tag_protocol(mds, mdp_upstream, in dsa_get_tag_protocol()
708 return ds->ops->get_tag_protocol(ds, dp->index, tag_protocol); in dsa_get_tag_protocol()
713 struct dsa_switch *ds = dp->ds; in dsa_port_parse_cpu()
714 struct dsa_switch_tree *dst = ds->dst; in dsa_port_parse_cpu()
721 if (PTR_ERR(tag_ops) == -ENOPROTOOPT) in dsa_port_parse_cpu()
722 return -EPROBE_DEFER; in dsa_port_parse_cpu()
723 dev_warn(ds->dev, "No tagger for this switch\n"); in dsa_port_parse_cpu()
724 dp->master = NULL; in dsa_port_parse_cpu()
728 dp->master = master; in dsa_port_parse_cpu()
729 dp->type = DSA_PORT_TYPE_CPU; in dsa_port_parse_cpu()
730 dp->filter = tag_ops->filter; in dsa_port_parse_cpu()
731 dp->rcv = tag_ops->rcv; in dsa_port_parse_cpu()
732 dp->tag_ops = tag_ops; in dsa_port_parse_cpu()
733 dp->dst = dst; in dsa_port_parse_cpu()
740 struct device_node *ethernet = of_parse_phandle(dn, "ethernet", 0); in dsa_port_parse_of() local
744 dp->dn = dn; in dsa_port_parse_of()
746 if (ethernet) { in dsa_port_parse_of()
749 master = of_find_net_device_by_node(ethernet); in dsa_port_parse_of()
751 return -EPROBE_DEFER; in dsa_port_parse_of()
765 struct device_node *ports, *port; in dsa_switch_parse_ports_of() local
770 ports = of_get_child_by_name(dn, "ports"); in dsa_switch_parse_ports_of()
771 if (!ports) { in dsa_switch_parse_ports_of()
772 /* The second possibility is "ethernet-ports" */ in dsa_switch_parse_ports_of()
773 ports = of_get_child_by_name(dn, "ethernet-ports"); in dsa_switch_parse_ports_of()
774 if (!ports) { in dsa_switch_parse_ports_of()
775 dev_err(ds->dev, "no ports child node found\n"); in dsa_switch_parse_ports_of()
776 return -EINVAL; in dsa_switch_parse_ports_of()
780 for_each_available_child_of_node(ports, port) { in dsa_switch_parse_ports_of()
785 if (reg >= ds->num_ports) { in dsa_switch_parse_ports_of()
786 err = -EINVAL; in dsa_switch_parse_ports_of()
798 of_node_put(ports); in dsa_switch_parse_ports_of()
810 if (sz < 0 && sz != -EINVAL) in dsa_switch_parse_member_of()
813 ds->index = m[1]; in dsa_switch_parse_member_of()
815 ds->dst = dsa_tree_touch(m[0]); in dsa_switch_parse_member_of()
816 if (!ds->dst) in dsa_switch_parse_member_of()
817 return -ENOMEM; in dsa_switch_parse_member_of()
827 for (port = 0; port < ds->num_ports; port++) { in dsa_switch_touch_ports()
830 return -ENOMEM; in dsa_switch_touch_ports()
859 return -EPROBE_DEFER; in dsa_port_parse()
883 name = cd->port_names[i]; in dsa_switch_parse_ports()
884 dev = cd->netdev[i]; in dsa_switch_parse_ports()
898 return -EINVAL; in dsa_switch_parse_ports()
907 ds->cd = cd; in dsa_switch_parse()
912 ds->index = 0; in dsa_switch_parse()
913 ds->dst = dsa_tree_touch(0); in dsa_switch_parse()
914 if (!ds->dst) in dsa_switch_parse()
915 return -ENOMEM; in dsa_switch_parse()
926 struct dsa_switch_tree *dst = ds->dst; in dsa_switch_release_ports()
929 list_for_each_entry_safe(dp, next, &dst->ports, list) { in dsa_switch_release_ports()
930 if (dp->ds != ds) in dsa_switch_release_ports()
932 list_del(&dp->list); in dsa_switch_release_ports()
944 if (!ds->dev) in dsa_switch_probe()
945 return -ENODEV; in dsa_switch_probe()
947 pdata = ds->dev->platform_data; in dsa_switch_probe()
948 np = ds->dev->of_node; in dsa_switch_probe()
950 if (!ds->num_ports) in dsa_switch_probe()
951 return -EINVAL; in dsa_switch_probe()
962 err = -ENODEV; in dsa_switch_probe()
968 dst = ds->dst; in dsa_switch_probe()
985 dsa_tree_put(ds->dst); in dsa_register_switch()
994 struct dsa_switch_tree *dst = ds->dst; in dsa_switch_remove()