diff options
Diffstat (limited to 'net/dsa/dsa.c')
-rw-r--r-- | net/dsa/dsa.c | 111 |
1 files changed, 93 insertions, 18 deletions
diff --git a/net/dsa/dsa.c b/net/dsa/dsa.c index 76e3800765f8..adb5325f4934 100644 --- a/net/dsa/dsa.c +++ b/net/dsa/dsa.c | |||
@@ -22,6 +22,7 @@ | |||
22 | #include <linux/of_platform.h> | 22 | #include <linux/of_platform.h> |
23 | #include <linux/of_net.h> | 23 | #include <linux/of_net.h> |
24 | #include <linux/sysfs.h> | 24 | #include <linux/sysfs.h> |
25 | #include <linux/phy_fixed.h> | ||
25 | #include "dsa_priv.h" | 26 | #include "dsa_priv.h" |
26 | 27 | ||
27 | char dsa_driver_version[] = "0.1"; | 28 | char dsa_driver_version[] = "0.1"; |
@@ -305,7 +306,7 @@ static int dsa_switch_setup_one(struct dsa_switch *ds, struct device *parent) | |||
305 | if (ret < 0) | 306 | if (ret < 0) |
306 | goto out; | 307 | goto out; |
307 | 308 | ||
308 | ds->slave_mii_bus = mdiobus_alloc(); | 309 | ds->slave_mii_bus = devm_mdiobus_alloc(parent); |
309 | if (ds->slave_mii_bus == NULL) { | 310 | if (ds->slave_mii_bus == NULL) { |
310 | ret = -ENOMEM; | 311 | ret = -ENOMEM; |
311 | goto out; | 312 | goto out; |
@@ -314,7 +315,7 @@ static int dsa_switch_setup_one(struct dsa_switch *ds, struct device *parent) | |||
314 | 315 | ||
315 | ret = mdiobus_register(ds->slave_mii_bus); | 316 | ret = mdiobus_register(ds->slave_mii_bus); |
316 | if (ret < 0) | 317 | if (ret < 0) |
317 | goto out_free; | 318 | goto out; |
318 | 319 | ||
319 | 320 | ||
320 | /* | 321 | /* |
@@ -367,10 +368,7 @@ static int dsa_switch_setup_one(struct dsa_switch *ds, struct device *parent) | |||
367 | 368 | ||
368 | return ret; | 369 | return ret; |
369 | 370 | ||
370 | out_free: | ||
371 | mdiobus_free(ds->slave_mii_bus); | ||
372 | out: | 371 | out: |
373 | kfree(ds); | ||
374 | return ret; | 372 | return ret; |
375 | } | 373 | } |
376 | 374 | ||
@@ -400,7 +398,7 @@ dsa_switch_setup(struct dsa_switch_tree *dst, int index, | |||
400 | /* | 398 | /* |
401 | * Allocate and initialise switch state. | 399 | * Allocate and initialise switch state. |
402 | */ | 400 | */ |
403 | ds = kzalloc(sizeof(*ds) + drv->priv_size, GFP_KERNEL); | 401 | ds = devm_kzalloc(parent, sizeof(*ds) + drv->priv_size, GFP_KERNEL); |
404 | if (ds == NULL) | 402 | if (ds == NULL) |
405 | return ERR_PTR(-ENOMEM); | 403 | return ERR_PTR(-ENOMEM); |
406 | 404 | ||
@@ -420,10 +418,47 @@ dsa_switch_setup(struct dsa_switch_tree *dst, int index, | |||
420 | 418 | ||
421 | static void dsa_switch_destroy(struct dsa_switch *ds) | 419 | static void dsa_switch_destroy(struct dsa_switch *ds) |
422 | { | 420 | { |
421 | struct device_node *port_dn; | ||
422 | struct phy_device *phydev; | ||
423 | struct dsa_chip_data *cd = ds->pd; | ||
424 | int port; | ||
425 | |||
423 | #ifdef CONFIG_NET_DSA_HWMON | 426 | #ifdef CONFIG_NET_DSA_HWMON |
424 | if (ds->hwmon_dev) | 427 | if (ds->hwmon_dev) |
425 | hwmon_device_unregister(ds->hwmon_dev); | 428 | hwmon_device_unregister(ds->hwmon_dev); |
426 | #endif | 429 | #endif |
430 | |||
431 | /* Disable configuration of the CPU and DSA ports */ | ||
432 | for (port = 0; port < DSA_MAX_PORTS; port++) { | ||
433 | if (!(dsa_is_cpu_port(ds, port) || dsa_is_dsa_port(ds, port))) | ||
434 | continue; | ||
435 | |||
436 | port_dn = cd->port_dn[port]; | ||
437 | if (of_phy_is_fixed_link(port_dn)) { | ||
438 | phydev = of_phy_find_device(port_dn); | ||
439 | if (phydev) { | ||
440 | int addr = phydev->addr; | ||
441 | |||
442 | phy_device_free(phydev); | ||
443 | of_node_put(port_dn); | ||
444 | fixed_phy_del(addr); | ||
445 | } | ||
446 | } | ||
447 | } | ||
448 | |||
449 | /* Destroy network devices for physical switch ports. */ | ||
450 | for (port = 0; port < DSA_MAX_PORTS; port++) { | ||
451 | if (!(ds->phys_port_mask & (1 << port))) | ||
452 | continue; | ||
453 | |||
454 | if (!ds->ports[port]) | ||
455 | continue; | ||
456 | |||
457 | unregister_netdev(ds->ports[port]); | ||
458 | free_netdev(ds->ports[port]); | ||
459 | } | ||
460 | |||
461 | mdiobus_unregister(ds->slave_mii_bus); | ||
427 | } | 462 | } |
428 | 463 | ||
429 | #ifdef CONFIG_PM_SLEEP | 464 | #ifdef CONFIG_PM_SLEEP |
@@ -634,6 +669,10 @@ static void dsa_of_free_platform_data(struct dsa_platform_data *pd) | |||
634 | port_index++; | 669 | port_index++; |
635 | } | 670 | } |
636 | kfree(pd->chip[i].rtable); | 671 | kfree(pd->chip[i].rtable); |
672 | |||
673 | /* Drop our reference to the MDIO bus device */ | ||
674 | if (pd->chip[i].host_dev) | ||
675 | put_device(pd->chip[i].host_dev); | ||
637 | } | 676 | } |
638 | kfree(pd->chip); | 677 | kfree(pd->chip); |
639 | } | 678 | } |
@@ -661,16 +700,22 @@ static int dsa_of_probe(struct device *dev) | |||
661 | return -EPROBE_DEFER; | 700 | return -EPROBE_DEFER; |
662 | 701 | ||
663 | ethernet = of_parse_phandle(np, "dsa,ethernet", 0); | 702 | ethernet = of_parse_phandle(np, "dsa,ethernet", 0); |
664 | if (!ethernet) | 703 | if (!ethernet) { |
665 | return -EINVAL; | 704 | ret = -EINVAL; |
705 | goto out_put_mdio; | ||
706 | } | ||
666 | 707 | ||
667 | ethernet_dev = of_find_net_device_by_node(ethernet); | 708 | ethernet_dev = of_find_net_device_by_node(ethernet); |
668 | if (!ethernet_dev) | 709 | if (!ethernet_dev) { |
669 | return -EPROBE_DEFER; | 710 | ret = -EPROBE_DEFER; |
711 | goto out_put_mdio; | ||
712 | } | ||
670 | 713 | ||
671 | pd = kzalloc(sizeof(*pd), GFP_KERNEL); | 714 | pd = kzalloc(sizeof(*pd), GFP_KERNEL); |
672 | if (!pd) | 715 | if (!pd) { |
673 | return -ENOMEM; | 716 | ret = -ENOMEM; |
717 | goto out_put_ethernet; | ||
718 | } | ||
674 | 719 | ||
675 | dev->platform_data = pd; | 720 | dev->platform_data = pd; |
676 | pd->of_netdev = ethernet_dev; | 721 | pd->of_netdev = ethernet_dev; |
@@ -691,7 +736,9 @@ static int dsa_of_probe(struct device *dev) | |||
691 | cd = &pd->chip[chip_index]; | 736 | cd = &pd->chip[chip_index]; |
692 | 737 | ||
693 | cd->of_node = child; | 738 | cd->of_node = child; |
694 | cd->host_dev = &mdio_bus->dev; | 739 | |
740 | /* When assigning the host device, increment its refcount */ | ||
741 | cd->host_dev = get_device(&mdio_bus->dev); | ||
695 | 742 | ||
696 | sw_addr = of_get_property(child, "reg", NULL); | 743 | sw_addr = of_get_property(child, "reg", NULL); |
697 | if (!sw_addr) | 744 | if (!sw_addr) |
@@ -711,6 +758,12 @@ static int dsa_of_probe(struct device *dev) | |||
711 | ret = -EPROBE_DEFER; | 758 | ret = -EPROBE_DEFER; |
712 | goto out_free_chip; | 759 | goto out_free_chip; |
713 | } | 760 | } |
761 | |||
762 | /* Drop the mdio_bus device ref, replacing the host | ||
763 | * device with the mdio_bus_switch device, keeping | ||
764 | * the refcount from of_mdio_find_bus() above. | ||
765 | */ | ||
766 | put_device(cd->host_dev); | ||
714 | cd->host_dev = &mdio_bus_switch->dev; | 767 | cd->host_dev = &mdio_bus_switch->dev; |
715 | } | 768 | } |
716 | 769 | ||
@@ -744,6 +797,10 @@ static int dsa_of_probe(struct device *dev) | |||
744 | } | 797 | } |
745 | } | 798 | } |
746 | 799 | ||
800 | /* The individual chips hold their own refcount on the mdio bus, | ||
801 | * so drop ours */ | ||
802 | put_device(&mdio_bus->dev); | ||
803 | |||
747 | return 0; | 804 | return 0; |
748 | 805 | ||
749 | out_free_chip: | 806 | out_free_chip: |
@@ -751,6 +808,10 @@ out_free_chip: | |||
751 | out_free: | 808 | out_free: |
752 | kfree(pd); | 809 | kfree(pd); |
753 | dev->platform_data = NULL; | 810 | dev->platform_data = NULL; |
811 | out_put_ethernet: | ||
812 | put_device(ðernet_dev->dev); | ||
813 | out_put_mdio: | ||
814 | put_device(&mdio_bus->dev); | ||
754 | return ret; | 815 | return ret; |
755 | } | 816 | } |
756 | 817 | ||
@@ -762,6 +823,7 @@ static void dsa_of_remove(struct device *dev) | |||
762 | return; | 823 | return; |
763 | 824 | ||
764 | dsa_of_free_platform_data(pd); | 825 | dsa_of_free_platform_data(pd); |
826 | put_device(&pd->of_netdev->dev); | ||
765 | kfree(pd); | 827 | kfree(pd); |
766 | } | 828 | } |
767 | #else | 829 | #else |
@@ -775,10 +837,11 @@ static inline void dsa_of_remove(struct device *dev) | |||
775 | } | 837 | } |
776 | #endif | 838 | #endif |
777 | 839 | ||
778 | static void dsa_setup_dst(struct dsa_switch_tree *dst, struct net_device *dev, | 840 | static int dsa_setup_dst(struct dsa_switch_tree *dst, struct net_device *dev, |
779 | struct device *parent, struct dsa_platform_data *pd) | 841 | struct device *parent, struct dsa_platform_data *pd) |
780 | { | 842 | { |
781 | int i; | 843 | int i; |
844 | unsigned configured = 0; | ||
782 | 845 | ||
783 | dst->pd = pd; | 846 | dst->pd = pd; |
784 | dst->master_netdev = dev; | 847 | dst->master_netdev = dev; |
@@ -798,9 +861,17 @@ static void dsa_setup_dst(struct dsa_switch_tree *dst, struct net_device *dev, | |||
798 | dst->ds[i] = ds; | 861 | dst->ds[i] = ds; |
799 | if (ds->drv->poll_link != NULL) | 862 | if (ds->drv->poll_link != NULL) |
800 | dst->link_poll_needed = 1; | 863 | dst->link_poll_needed = 1; |
864 | |||
865 | ++configured; | ||
801 | } | 866 | } |
802 | 867 | ||
803 | /* | 868 | /* |
869 | * If no switch was found, exit cleanly | ||
870 | */ | ||
871 | if (!configured) | ||
872 | return -EPROBE_DEFER; | ||
873 | |||
874 | /* | ||
804 | * If we use a tagging format that doesn't have an ethertype | 875 | * If we use a tagging format that doesn't have an ethertype |
805 | * field, make sure that all packets from this point on get | 876 | * field, make sure that all packets from this point on get |
806 | * sent to the tag format's receive function. | 877 | * sent to the tag format's receive function. |
@@ -816,6 +887,8 @@ static void dsa_setup_dst(struct dsa_switch_tree *dst, struct net_device *dev, | |||
816 | dst->link_poll_timer.expires = round_jiffies(jiffies + HZ); | 887 | dst->link_poll_timer.expires = round_jiffies(jiffies + HZ); |
817 | add_timer(&dst->link_poll_timer); | 888 | add_timer(&dst->link_poll_timer); |
818 | } | 889 | } |
890 | |||
891 | return 0; | ||
819 | } | 892 | } |
820 | 893 | ||
821 | static int dsa_probe(struct platform_device *pdev) | 894 | static int dsa_probe(struct platform_device *pdev) |
@@ -856,7 +929,7 @@ static int dsa_probe(struct platform_device *pdev) | |||
856 | goto out; | 929 | goto out; |
857 | } | 930 | } |
858 | 931 | ||
859 | dst = kzalloc(sizeof(*dst), GFP_KERNEL); | 932 | dst = devm_kzalloc(&pdev->dev, sizeof(*dst), GFP_KERNEL); |
860 | if (dst == NULL) { | 933 | if (dst == NULL) { |
861 | dev_put(dev); | 934 | dev_put(dev); |
862 | ret = -ENOMEM; | 935 | ret = -ENOMEM; |
@@ -865,7 +938,9 @@ static int dsa_probe(struct platform_device *pdev) | |||
865 | 938 | ||
866 | platform_set_drvdata(pdev, dst); | 939 | platform_set_drvdata(pdev, dst); |
867 | 940 | ||
868 | dsa_setup_dst(dst, dev, &pdev->dev, pd); | 941 | ret = dsa_setup_dst(dst, dev, &pdev->dev, pd); |
942 | if (ret) | ||
943 | goto out; | ||
869 | 944 | ||
870 | return 0; | 945 | return 0; |
871 | 946 | ||
@@ -887,7 +962,7 @@ static void dsa_remove_dst(struct dsa_switch_tree *dst) | |||
887 | for (i = 0; i < dst->pd->nr_chips; i++) { | 962 | for (i = 0; i < dst->pd->nr_chips; i++) { |
888 | struct dsa_switch *ds = dst->ds[i]; | 963 | struct dsa_switch *ds = dst->ds[i]; |
889 | 964 | ||
890 | if (ds != NULL) | 965 | if (ds) |
891 | dsa_switch_destroy(ds); | 966 | dsa_switch_destroy(ds); |
892 | } | 967 | } |
893 | } | 968 | } |