1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * net/dsa/dsa2.c - Hardware switch handling, binding version 2 4 * Copyright (c) 2008-2009 Marvell Semiconductor 5 * Copyright (c) 2013 Florian Fainelli <florian@openwrt.org> 6 * Copyright (c) 2016 Andrew Lunn <andrew@lunn.ch> 7 */ 8 9 #include <linux/device.h> 10 #include <linux/err.h> 11 #include <linux/list.h> 12 #include <linux/netdevice.h> 13 #include <linux/slab.h> 14 #include <linux/rtnetlink.h> 15 #include <linux/of.h> 16 #include <linux/of_net.h> 17 #include <net/devlink.h> 18 19 #include "dsa_priv.h" 20 21 static LIST_HEAD(dsa_tree_list); 22 static DEFINE_MUTEX(dsa2_mutex); 23 24 static const struct devlink_ops dsa_devlink_ops = { 25 }; 26 27 static struct dsa_switch_tree *dsa_tree_find(int index) 28 { 29 struct dsa_switch_tree *dst; 30 31 list_for_each_entry(dst, &dsa_tree_list, list) 32 if (dst->index == index) 33 return dst; 34 35 return NULL; 36 } 37 38 static struct dsa_switch_tree *dsa_tree_alloc(int index) 39 { 40 struct dsa_switch_tree *dst; 41 42 dst = kzalloc(sizeof(*dst), GFP_KERNEL); 43 if (!dst) 44 return NULL; 45 46 dst->index = index; 47 48 INIT_LIST_HEAD(&dst->list); 49 list_add_tail(&dst->list, &dsa_tree_list); 50 51 kref_init(&dst->refcount); 52 53 return dst; 54 } 55 56 static void dsa_tree_free(struct dsa_switch_tree *dst) 57 { 58 list_del(&dst->list); 59 kfree(dst); 60 } 61 62 static struct dsa_switch_tree *dsa_tree_get(struct dsa_switch_tree *dst) 63 { 64 if (dst) 65 kref_get(&dst->refcount); 66 67 return dst; 68 } 69 70 static struct dsa_switch_tree *dsa_tree_touch(int index) 71 { 72 struct dsa_switch_tree *dst; 73 74 dst = dsa_tree_find(index); 75 if (dst) 76 return dsa_tree_get(dst); 77 else 78 return dsa_tree_alloc(index); 79 } 80 81 static void dsa_tree_release(struct kref *ref) 82 { 83 struct dsa_switch_tree *dst; 84 85 dst = container_of(ref, struct dsa_switch_tree, refcount); 86 87 dsa_tree_free(dst); 88 } 89 90 static void dsa_tree_put(struct dsa_switch_tree *dst) 91 { 92 if (dst) 93 kref_put(&dst->refcount, dsa_tree_release); 94 } 95 96 static bool dsa_port_is_dsa(struct dsa_port *port) 97 { 98 return port->type == DSA_PORT_TYPE_DSA; 99 } 100 101 static bool dsa_port_is_cpu(struct dsa_port *port) 102 { 103 return port->type == DSA_PORT_TYPE_CPU; 104 } 105 106 static bool dsa_port_is_user(struct dsa_port *dp) 107 { 108 return dp->type == DSA_PORT_TYPE_USER; 109 } 110 111 static struct dsa_port *dsa_tree_find_port_by_node(struct dsa_switch_tree *dst, 112 struct device_node *dn) 113 { 114 struct dsa_switch *ds; 115 struct dsa_port *dp; 116 int device, port; 117 118 for (device = 0; device < DSA_MAX_SWITCHES; device++) { 119 ds = dst->ds[device]; 120 if (!ds) 121 continue; 122 123 for (port = 0; port < ds->num_ports; port++) { 124 dp = &ds->ports[port]; 125 126 if (dp->dn == dn) 127 return dp; 128 } 129 } 130 131 return NULL; 132 } 133 134 static bool dsa_port_setup_routing_table(struct dsa_port *dp) 135 { 136 struct dsa_switch *ds = dp->ds; 137 struct dsa_switch_tree *dst = ds->dst; 138 struct device_node *dn = dp->dn; 139 struct of_phandle_iterator it; 140 struct dsa_port *link_dp; 141 int err; 142 143 of_for_each_phandle(&it, err, dn, "link", NULL, 0) { 144 link_dp = dsa_tree_find_port_by_node(dst, it.node); 145 if (!link_dp) { 146 of_node_put(it.node); 147 return false; 148 } 149 150 ds->rtable[link_dp->ds->index] = dp->index; 151 } 152 153 return true; 154 } 155 156 static bool dsa_switch_setup_routing_table(struct dsa_switch *ds) 157 { 158 bool complete = true; 159 struct dsa_port *dp; 160 int i; 161 162 for (i = 0; i < DSA_MAX_SWITCHES; i++) 163 ds->rtable[i] = DSA_RTABLE_NONE; 164 165 for (i = 0; i < ds->num_ports; i++) { 166 dp = &ds->ports[i]; 167 168 if (dsa_port_is_dsa(dp)) { 169 complete = dsa_port_setup_routing_table(dp); 170 if (!complete) 171 break; 172 } 173 } 174 175 return complete; 176 } 177 178 static bool dsa_tree_setup_routing_table(struct dsa_switch_tree *dst) 179 { 180 struct dsa_switch *ds; 181 bool complete = true; 182 int device; 183 184 for (device = 0; device < DSA_MAX_SWITCHES; device++) { 185 ds = dst->ds[device]; 186 if (!ds) 187 continue; 188 189 complete = dsa_switch_setup_routing_table(ds); 190 if (!complete) 191 break; 192 } 193 194 return complete; 195 } 196 197 static struct dsa_port *dsa_tree_find_first_cpu(struct dsa_switch_tree *dst) 198 { 199 struct dsa_switch *ds; 200 struct dsa_port *dp; 201 int device, port; 202 203 for (device = 0; device < DSA_MAX_SWITCHES; device++) { 204 ds = dst->ds[device]; 205 if (!ds) 206 continue; 207 208 for (port = 0; port < ds->num_ports; port++) { 209 dp = &ds->ports[port]; 210 211 if (dsa_port_is_cpu(dp)) 212 return dp; 213 } 214 } 215 216 return NULL; 217 } 218 219 static int dsa_tree_setup_default_cpu(struct dsa_switch_tree *dst) 220 { 221 struct dsa_switch *ds; 222 struct dsa_port *dp; 223 int device, port; 224 225 /* DSA currently only supports a single CPU port */ 226 dst->cpu_dp = dsa_tree_find_first_cpu(dst); 227 if (!dst->cpu_dp) { 228 pr_warn("Tree has no master device\n"); 229 return -EINVAL; 230 } 231 232 /* Assign the default CPU port to all ports of the fabric */ 233 for (device = 0; device < DSA_MAX_SWITCHES; device++) { 234 ds = dst->ds[device]; 235 if (!ds) 236 continue; 237 238 for (port = 0; port < ds->num_ports; port++) { 239 dp = &ds->ports[port]; 240 241 if (dsa_port_is_user(dp) || dsa_port_is_dsa(dp)) 242 dp->cpu_dp = dst->cpu_dp; 243 } 244 } 245 246 return 0; 247 } 248 249 static void dsa_tree_teardown_default_cpu(struct dsa_switch_tree *dst) 250 { 251 /* DSA currently only supports a single CPU port */ 252 dst->cpu_dp = NULL; 253 } 254 255 static int dsa_port_setup(struct dsa_port *dp) 256 { 257 enum devlink_port_flavour flavour; 258 struct dsa_switch *ds = dp->ds; 259 struct dsa_switch_tree *dst = ds->dst; 260 int err = 0; 261 262 if (dp->type == DSA_PORT_TYPE_UNUSED) 263 return 0; 264 265 memset(&dp->devlink_port, 0, sizeof(dp->devlink_port)); 266 dp->mac = of_get_mac_address(dp->dn); 267 268 switch (dp->type) { 269 case DSA_PORT_TYPE_CPU: 270 flavour = DEVLINK_PORT_FLAVOUR_CPU; 271 break; 272 case DSA_PORT_TYPE_DSA: 273 flavour = DEVLINK_PORT_FLAVOUR_DSA; 274 break; 275 case DSA_PORT_TYPE_USER: /* fall-through */ 276 default: 277 flavour = DEVLINK_PORT_FLAVOUR_PHYSICAL; 278 break; 279 } 280 281 /* dp->index is used now as port_number. However 282 * CPU and DSA ports should have separate numbering 283 * independent from front panel port numbers. 284 */ 285 devlink_port_attrs_set(&dp->devlink_port, flavour, 286 dp->index, false, 0, 287 (const char *) &dst->index, sizeof(dst->index)); 288 err = devlink_port_register(ds->devlink, &dp->devlink_port, 289 dp->index); 290 if (err) 291 return err; 292 293 switch (dp->type) { 294 case DSA_PORT_TYPE_UNUSED: 295 break; 296 case DSA_PORT_TYPE_CPU: 297 err = dsa_port_link_register_of(dp); 298 if (err) 299 dev_err(ds->dev, "failed to setup link for port %d.%d\n", 300 ds->index, dp->index); 301 break; 302 case DSA_PORT_TYPE_DSA: 303 err = dsa_port_link_register_of(dp); 304 if (err) 305 dev_err(ds->dev, "failed to setup link for port %d.%d\n", 306 ds->index, dp->index); 307 break; 308 case DSA_PORT_TYPE_USER: 309 err = dsa_slave_create(dp); 310 if (err) 311 dev_err(ds->dev, "failed to create slave for port %d.%d\n", 312 ds->index, dp->index); 313 else 314 devlink_port_type_eth_set(&dp->devlink_port, dp->slave); 315 break; 316 } 317 318 if (err) 319 devlink_port_unregister(&dp->devlink_port); 320 321 return err; 322 } 323 324 static void dsa_port_teardown(struct dsa_port *dp) 325 { 326 if (dp->type != DSA_PORT_TYPE_UNUSED) 327 devlink_port_unregister(&dp->devlink_port); 328 329 switch (dp->type) { 330 case DSA_PORT_TYPE_UNUSED: 331 break; 332 case DSA_PORT_TYPE_CPU: 333 dsa_tag_driver_put(dp->tag_ops); 334 /* fall-through */ 335 case DSA_PORT_TYPE_DSA: 336 dsa_port_link_unregister_of(dp); 337 break; 338 case DSA_PORT_TYPE_USER: 339 if (dp->slave) { 340 dsa_slave_destroy(dp->slave); 341 dp->slave = NULL; 342 } 343 break; 344 } 345 } 346 347 static int dsa_switch_setup(struct dsa_switch *ds) 348 { 349 int err = 0; 350 351 /* Initialize ds->phys_mii_mask before registering the slave MDIO bus 352 * driver and before ops->setup() has run, since the switch drivers and 353 * the slave MDIO bus driver rely on these values for probing PHY 354 * devices or not 355 */ 356 ds->phys_mii_mask |= dsa_user_ports(ds); 357 358 /* Add the switch to devlink before calling setup, so that setup can 359 * add dpipe tables 360 */ 361 ds->devlink = devlink_alloc(&dsa_devlink_ops, 0); 362 if (!ds->devlink) 363 return -ENOMEM; 364 365 err = devlink_register(ds->devlink, ds->dev); 366 if (err) 367 goto free_devlink; 368 369 err = dsa_switch_register_notifier(ds); 370 if (err) 371 goto unregister_devlink; 372 373 err = ds->ops->setup(ds); 374 if (err < 0) 375 goto unregister_notifier; 376 377 if (!ds->slave_mii_bus && ds->ops->phy_read) { 378 ds->slave_mii_bus = devm_mdiobus_alloc(ds->dev); 379 if (!ds->slave_mii_bus) { 380 err = -ENOMEM; 381 goto unregister_notifier; 382 } 383 384 dsa_slave_mii_bus_init(ds); 385 386 err = mdiobus_register(ds->slave_mii_bus); 387 if (err < 0) 388 goto unregister_notifier; 389 } 390 391 return 0; 392 393 unregister_notifier: 394 dsa_switch_unregister_notifier(ds); 395 unregister_devlink: 396 devlink_unregister(ds->devlink); 397 free_devlink: 398 devlink_free(ds->devlink); 399 ds->devlink = NULL; 400 401 return err; 402 } 403 404 static void dsa_switch_teardown(struct dsa_switch *ds) 405 { 406 if (ds->slave_mii_bus && ds->ops->phy_read) 407 mdiobus_unregister(ds->slave_mii_bus); 408 409 dsa_switch_unregister_notifier(ds); 410 411 if (ds->ops->teardown) 412 ds->ops->teardown(ds); 413 414 if (ds->devlink) { 415 devlink_unregister(ds->devlink); 416 devlink_free(ds->devlink); 417 ds->devlink = NULL; 418 } 419 420 } 421 422 static int dsa_tree_setup_switches(struct dsa_switch_tree *dst) 423 { 424 struct dsa_switch *ds; 425 struct dsa_port *dp; 426 int device, port, i; 427 int err = 0; 428 429 for (device = 0; device < DSA_MAX_SWITCHES; device++) { 430 ds = dst->ds[device]; 431 if (!ds) 432 continue; 433 434 err = dsa_switch_setup(ds); 435 if (err) 436 goto switch_teardown; 437 438 for (port = 0; port < ds->num_ports; port++) { 439 dp = &ds->ports[port]; 440 441 err = dsa_port_setup(dp); 442 if (err) 443 goto ports_teardown; 444 } 445 } 446 447 return 0; 448 449 ports_teardown: 450 for (i = 0; i < port; i++) 451 dsa_port_teardown(&ds->ports[i]); 452 453 dsa_switch_teardown(ds); 454 455 switch_teardown: 456 for (i = 0; i < device; i++) { 457 ds = dst->ds[i]; 458 if (!ds) 459 continue; 460 461 for (port = 0; port < ds->num_ports; port++) { 462 dp = &ds->ports[port]; 463 464 dsa_port_teardown(dp); 465 } 466 467 dsa_switch_teardown(ds); 468 } 469 470 return err; 471 } 472 473 static void dsa_tree_teardown_switches(struct dsa_switch_tree *dst) 474 { 475 struct dsa_switch *ds; 476 struct dsa_port *dp; 477 int device, port; 478 479 for (device = 0; device < DSA_MAX_SWITCHES; device++) { 480 ds = dst->ds[device]; 481 if (!ds) 482 continue; 483 484 for (port = 0; port < ds->num_ports; port++) { 485 dp = &ds->ports[port]; 486 487 dsa_port_teardown(dp); 488 } 489 490 dsa_switch_teardown(ds); 491 } 492 } 493 494 static int dsa_tree_setup_master(struct dsa_switch_tree *dst) 495 { 496 struct dsa_port *cpu_dp = dst->cpu_dp; 497 struct net_device *master = cpu_dp->master; 498 499 /* DSA currently supports a single pair of CPU port and master device */ 500 return dsa_master_setup(master, cpu_dp); 501 } 502 503 static void dsa_tree_teardown_master(struct dsa_switch_tree *dst) 504 { 505 struct dsa_port *cpu_dp = dst->cpu_dp; 506 struct net_device *master = cpu_dp->master; 507 508 return dsa_master_teardown(master); 509 } 510 511 static int dsa_tree_setup(struct dsa_switch_tree *dst) 512 { 513 bool complete; 514 int err; 515 516 if (dst->setup) { 517 pr_err("DSA: tree %d already setup! Disjoint trees?\n", 518 dst->index); 519 return -EEXIST; 520 } 521 522 complete = dsa_tree_setup_routing_table(dst); 523 if (!complete) 524 return 0; 525 526 err = dsa_tree_setup_default_cpu(dst); 527 if (err) 528 return err; 529 530 err = dsa_tree_setup_switches(dst); 531 if (err) 532 goto teardown_default_cpu; 533 534 err = dsa_tree_setup_master(dst); 535 if (err) 536 goto teardown_switches; 537 538 dst->setup = true; 539 540 pr_info("DSA: tree %d setup\n", dst->index); 541 542 return 0; 543 544 teardown_switches: 545 dsa_tree_teardown_switches(dst); 546 teardown_default_cpu: 547 dsa_tree_teardown_default_cpu(dst); 548 549 return err; 550 } 551 552 static void dsa_tree_teardown(struct dsa_switch_tree *dst) 553 { 554 if (!dst->setup) 555 return; 556 557 dsa_tree_teardown_master(dst); 558 559 dsa_tree_teardown_switches(dst); 560 561 dsa_tree_teardown_default_cpu(dst); 562 563 pr_info("DSA: tree %d torn down\n", dst->index); 564 565 dst->setup = false; 566 } 567 568 static void dsa_tree_remove_switch(struct dsa_switch_tree *dst, 569 unsigned int index) 570 { 571 dsa_tree_teardown(dst); 572 573 dst->ds[index] = NULL; 574 dsa_tree_put(dst); 575 } 576 577 static int dsa_tree_add_switch(struct dsa_switch_tree *dst, 578 struct dsa_switch *ds) 579 { 580 unsigned int index = ds->index; 581 int err; 582 583 if (dst->ds[index]) 584 return -EBUSY; 585 586 dsa_tree_get(dst); 587 dst->ds[index] = ds; 588 589 err = dsa_tree_setup(dst); 590 if (err) { 591 dst->ds[index] = NULL; 592 dsa_tree_put(dst); 593 } 594 595 return err; 596 } 597 598 static int dsa_port_parse_user(struct dsa_port *dp, const char *name) 599 { 600 if (!name) 601 name = "eth%d"; 602 603 dp->type = DSA_PORT_TYPE_USER; 604 dp->name = name; 605 606 return 0; 607 } 608 609 static int dsa_port_parse_dsa(struct dsa_port *dp) 610 { 611 dp->type = DSA_PORT_TYPE_DSA; 612 613 return 0; 614 } 615 616 static int dsa_port_parse_cpu(struct dsa_port *dp, struct net_device *master) 617 { 618 struct dsa_switch *ds = dp->ds; 619 struct dsa_switch_tree *dst = ds->dst; 620 const struct dsa_device_ops *tag_ops; 621 enum dsa_tag_protocol tag_protocol; 622 623 tag_protocol = ds->ops->get_tag_protocol(ds, dp->index); 624 tag_ops = dsa_tag_driver_get(tag_protocol); 625 if (IS_ERR(tag_ops)) { 626 if (PTR_ERR(tag_ops) == -ENOPROTOOPT) 627 return -EPROBE_DEFER; 628 dev_warn(ds->dev, "No tagger for this switch\n"); 629 return PTR_ERR(tag_ops); 630 } 631 632 dp->type = DSA_PORT_TYPE_CPU; 633 dp->filter = tag_ops->filter; 634 dp->rcv = tag_ops->rcv; 635 dp->tag_ops = tag_ops; 636 dp->master = master; 637 dp->dst = dst; 638 639 return 0; 640 } 641 642 static int dsa_port_parse_of(struct dsa_port *dp, struct device_node *dn) 643 { 644 struct device_node *ethernet = of_parse_phandle(dn, "ethernet", 0); 645 const char *name = of_get_property(dn, "label", NULL); 646 bool link = of_property_read_bool(dn, "link"); 647 648 dp->dn = dn; 649 650 if (ethernet) { 651 struct net_device *master; 652 653 master = of_find_net_device_by_node(ethernet); 654 if (!master) 655 return -EPROBE_DEFER; 656 657 return dsa_port_parse_cpu(dp, master); 658 } 659 660 if (link) 661 return dsa_port_parse_dsa(dp); 662 663 return dsa_port_parse_user(dp, name); 664 } 665 666 static int dsa_switch_parse_ports_of(struct dsa_switch *ds, 667 struct device_node *dn) 668 { 669 struct device_node *ports, *port; 670 struct dsa_port *dp; 671 int err = 0; 672 u32 reg; 673 674 ports = of_get_child_by_name(dn, "ports"); 675 if (!ports) { 676 dev_err(ds->dev, "no ports child node found\n"); 677 return -EINVAL; 678 } 679 680 for_each_available_child_of_node(ports, port) { 681 err = of_property_read_u32(port, "reg", ®); 682 if (err) 683 goto out_put_node; 684 685 if (reg >= ds->num_ports) { 686 err = -EINVAL; 687 goto out_put_node; 688 } 689 690 dp = &ds->ports[reg]; 691 692 err = dsa_port_parse_of(dp, port); 693 if (err) 694 goto out_put_node; 695 } 696 697 out_put_node: 698 of_node_put(ports); 699 return err; 700 } 701 702 static int dsa_switch_parse_member_of(struct dsa_switch *ds, 703 struct device_node *dn) 704 { 705 u32 m[2] = { 0, 0 }; 706 int sz; 707 708 /* Don't error out if this optional property isn't found */ 709 sz = of_property_read_variable_u32_array(dn, "dsa,member", m, 2, 2); 710 if (sz < 0 && sz != -EINVAL) 711 return sz; 712 713 ds->index = m[1]; 714 if (ds->index >= DSA_MAX_SWITCHES) 715 return -EINVAL; 716 717 ds->dst = dsa_tree_touch(m[0]); 718 if (!ds->dst) 719 return -ENOMEM; 720 721 return 0; 722 } 723 724 static int dsa_switch_parse_of(struct dsa_switch *ds, struct device_node *dn) 725 { 726 int err; 727 728 err = dsa_switch_parse_member_of(ds, dn); 729 if (err) 730 return err; 731 732 return dsa_switch_parse_ports_of(ds, dn); 733 } 734 735 static int dsa_port_parse(struct dsa_port *dp, const char *name, 736 struct device *dev) 737 { 738 if (!strcmp(name, "cpu")) { 739 struct net_device *master; 740 741 master = dsa_dev_to_net_device(dev); 742 if (!master) 743 return -EPROBE_DEFER; 744 745 dev_put(master); 746 747 return dsa_port_parse_cpu(dp, master); 748 } 749 750 if (!strcmp(name, "dsa")) 751 return dsa_port_parse_dsa(dp); 752 753 return dsa_port_parse_user(dp, name); 754 } 755 756 static int dsa_switch_parse_ports(struct dsa_switch *ds, 757 struct dsa_chip_data *cd) 758 { 759 bool valid_name_found = false; 760 struct dsa_port *dp; 761 struct device *dev; 762 const char *name; 763 unsigned int i; 764 int err; 765 766 for (i = 0; i < DSA_MAX_PORTS; i++) { 767 name = cd->port_names[i]; 768 dev = cd->netdev[i]; 769 dp = &ds->ports[i]; 770 771 if (!name) 772 continue; 773 774 err = dsa_port_parse(dp, name, dev); 775 if (err) 776 return err; 777 778 valid_name_found = true; 779 } 780 781 if (!valid_name_found && i == DSA_MAX_PORTS) 782 return -EINVAL; 783 784 return 0; 785 } 786 787 static int dsa_switch_parse(struct dsa_switch *ds, struct dsa_chip_data *cd) 788 { 789 ds->cd = cd; 790 791 /* We don't support interconnected switches nor multiple trees via 792 * platform data, so this is the unique switch of the tree. 793 */ 794 ds->index = 0; 795 ds->dst = dsa_tree_touch(0); 796 if (!ds->dst) 797 return -ENOMEM; 798 799 return dsa_switch_parse_ports(ds, cd); 800 } 801 802 static int dsa_switch_add(struct dsa_switch *ds) 803 { 804 struct dsa_switch_tree *dst = ds->dst; 805 806 return dsa_tree_add_switch(dst, ds); 807 } 808 809 static int dsa_switch_probe(struct dsa_switch *ds) 810 { 811 struct dsa_chip_data *pdata = ds->dev->platform_data; 812 struct device_node *np = ds->dev->of_node; 813 int err; 814 815 if (np) 816 err = dsa_switch_parse_of(ds, np); 817 else if (pdata) 818 err = dsa_switch_parse(ds, pdata); 819 else 820 err = -ENODEV; 821 822 if (err) 823 return err; 824 825 return dsa_switch_add(ds); 826 } 827 828 struct dsa_switch *dsa_switch_alloc(struct device *dev, size_t n) 829 { 830 struct dsa_switch *ds; 831 int i; 832 833 ds = devm_kzalloc(dev, struct_size(ds, ports, n), GFP_KERNEL); 834 if (!ds) 835 return NULL; 836 837 /* We avoid allocating memory outside dsa_switch 838 * if it is not needed. 839 */ 840 if (n <= sizeof(ds->_bitmap) * 8) { 841 ds->bitmap = &ds->_bitmap; 842 } else { 843 ds->bitmap = devm_kcalloc(dev, 844 BITS_TO_LONGS(n), 845 sizeof(unsigned long), 846 GFP_KERNEL); 847 if (unlikely(!ds->bitmap)) 848 return NULL; 849 } 850 851 ds->dev = dev; 852 ds->num_ports = n; 853 854 for (i = 0; i < ds->num_ports; ++i) { 855 ds->ports[i].index = i; 856 ds->ports[i].ds = ds; 857 } 858 859 return ds; 860 } 861 EXPORT_SYMBOL_GPL(dsa_switch_alloc); 862 863 int dsa_register_switch(struct dsa_switch *ds) 864 { 865 int err; 866 867 mutex_lock(&dsa2_mutex); 868 err = dsa_switch_probe(ds); 869 dsa_tree_put(ds->dst); 870 mutex_unlock(&dsa2_mutex); 871 872 return err; 873 } 874 EXPORT_SYMBOL_GPL(dsa_register_switch); 875 876 static void dsa_switch_remove(struct dsa_switch *ds) 877 { 878 struct dsa_switch_tree *dst = ds->dst; 879 unsigned int index = ds->index; 880 881 dsa_tree_remove_switch(dst, index); 882 } 883 884 void dsa_unregister_switch(struct dsa_switch *ds) 885 { 886 mutex_lock(&dsa2_mutex); 887 dsa_switch_remove(ds); 888 mutex_unlock(&dsa2_mutex); 889 } 890 EXPORT_SYMBOL_GPL(dsa_unregister_switch); 891
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.