diff options
Diffstat (limited to 'net/dsa/dsa.c')
-rw-r--r-- | net/dsa/dsa.c | 80 |
1 files changed, 33 insertions, 47 deletions
diff --git a/net/dsa/dsa.c b/net/dsa/dsa.c index 1eba07feb34a..fa4daba8db55 100644 --- a/net/dsa/dsa.c +++ b/net/dsa/dsa.c | |||
@@ -21,8 +21,10 @@ | |||
21 | #include <linux/of_mdio.h> | 21 | #include <linux/of_mdio.h> |
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/of_gpio.h> | ||
24 | #include <linux/sysfs.h> | 25 | #include <linux/sysfs.h> |
25 | #include <linux/phy_fixed.h> | 26 | #include <linux/phy_fixed.h> |
27 | #include <linux/gpio/consumer.h> | ||
26 | #include "dsa_priv.h" | 28 | #include "dsa_priv.h" |
27 | 29 | ||
28 | char dsa_driver_version[] = "0.1"; | 30 | char dsa_driver_version[] = "0.1"; |
@@ -437,7 +439,7 @@ static void dsa_switch_destroy(struct dsa_switch *ds) | |||
437 | if (of_phy_is_fixed_link(port_dn)) { | 439 | if (of_phy_is_fixed_link(port_dn)) { |
438 | phydev = of_phy_find_device(port_dn); | 440 | phydev = of_phy_find_device(port_dn); |
439 | if (phydev) { | 441 | if (phydev) { |
440 | int addr = phydev->addr; | 442 | int addr = phydev->mdio.addr; |
441 | 443 | ||
442 | phy_device_free(phydev); | 444 | phy_device_free(phydev); |
443 | of_node_put(port_dn); | 445 | of_node_put(port_dn); |
@@ -454,8 +456,7 @@ static void dsa_switch_destroy(struct dsa_switch *ds) | |||
454 | if (!ds->ports[port]) | 456 | if (!ds->ports[port]) |
455 | continue; | 457 | continue; |
456 | 458 | ||
457 | unregister_netdev(ds->ports[port]); | 459 | dsa_slave_destroy(ds->ports[port]); |
458 | free_netdev(ds->ports[port]); | ||
459 | } | 460 | } |
460 | 461 | ||
461 | mdiobus_unregister(ds->slave_mii_bus); | 462 | mdiobus_unregister(ds->slave_mii_bus); |
@@ -506,33 +507,6 @@ static int dsa_switch_resume(struct dsa_switch *ds) | |||
506 | } | 507 | } |
507 | #endif | 508 | #endif |
508 | 509 | ||
509 | |||
510 | /* link polling *************************************************************/ | ||
511 | static void dsa_link_poll_work(struct work_struct *ugly) | ||
512 | { | ||
513 | struct dsa_switch_tree *dst; | ||
514 | int i; | ||
515 | |||
516 | dst = container_of(ugly, struct dsa_switch_tree, link_poll_work); | ||
517 | |||
518 | for (i = 0; i < dst->pd->nr_chips; i++) { | ||
519 | struct dsa_switch *ds = dst->ds[i]; | ||
520 | |||
521 | if (ds != NULL && ds->drv->poll_link != NULL) | ||
522 | ds->drv->poll_link(ds); | ||
523 | } | ||
524 | |||
525 | mod_timer(&dst->link_poll_timer, round_jiffies(jiffies + HZ)); | ||
526 | } | ||
527 | |||
528 | static void dsa_link_poll_timer(unsigned long _dst) | ||
529 | { | ||
530 | struct dsa_switch_tree *dst = (void *)_dst; | ||
531 | |||
532 | schedule_work(&dst->link_poll_work); | ||
533 | } | ||
534 | |||
535 | |||
536 | /* platform driver init and cleanup *****************************************/ | 510 | /* platform driver init and cleanup *****************************************/ |
537 | static int dev_is_class(struct device *dev, void *class) | 511 | static int dev_is_class(struct device *dev, void *class) |
538 | { | 512 | { |
@@ -688,6 +662,9 @@ static int dsa_of_probe(struct device *dev) | |||
688 | const char *port_name; | 662 | const char *port_name; |
689 | int chip_index, port_index; | 663 | int chip_index, port_index; |
690 | const unsigned int *sw_addr, *port_reg; | 664 | const unsigned int *sw_addr, *port_reg; |
665 | int gpio; | ||
666 | enum of_gpio_flags of_flags; | ||
667 | unsigned long flags; | ||
691 | u32 eeprom_len; | 668 | u32 eeprom_len; |
692 | int ret; | 669 | int ret; |
693 | 670 | ||
@@ -766,6 +743,19 @@ static int dsa_of_probe(struct device *dev) | |||
766 | put_device(cd->host_dev); | 743 | put_device(cd->host_dev); |
767 | cd->host_dev = &mdio_bus_switch->dev; | 744 | cd->host_dev = &mdio_bus_switch->dev; |
768 | } | 745 | } |
746 | gpio = of_get_named_gpio_flags(child, "reset-gpios", 0, | ||
747 | &of_flags); | ||
748 | if (gpio_is_valid(gpio)) { | ||
749 | flags = (of_flags == OF_GPIO_ACTIVE_LOW ? | ||
750 | GPIOF_ACTIVE_LOW : 0); | ||
751 | ret = devm_gpio_request_one(dev, gpio, flags, | ||
752 | "switch_reset"); | ||
753 | if (ret) | ||
754 | goto out_free_chip; | ||
755 | |||
756 | cd->reset = gpio_to_desc(gpio); | ||
757 | gpiod_direction_output(cd->reset, 0); | ||
758 | } | ||
769 | 759 | ||
770 | for_each_available_child_of_node(child, port) { | 760 | for_each_available_child_of_node(child, port) { |
771 | port_reg = of_get_property(port, "reg", NULL); | 761 | port_reg = of_get_property(port, "reg", NULL); |
@@ -859,8 +849,6 @@ static int dsa_setup_dst(struct dsa_switch_tree *dst, struct net_device *dev, | |||
859 | } | 849 | } |
860 | 850 | ||
861 | dst->ds[i] = ds; | 851 | dst->ds[i] = ds; |
862 | if (ds->drv->poll_link != NULL) | ||
863 | dst->link_poll_needed = 1; | ||
864 | 852 | ||
865 | ++configured; | 853 | ++configured; |
866 | } | 854 | } |
@@ -879,15 +867,6 @@ static int dsa_setup_dst(struct dsa_switch_tree *dst, struct net_device *dev, | |||
879 | wmb(); | 867 | wmb(); |
880 | dev->dsa_ptr = (void *)dst; | 868 | dev->dsa_ptr = (void *)dst; |
881 | 869 | ||
882 | if (dst->link_poll_needed) { | ||
883 | INIT_WORK(&dst->link_poll_work, dsa_link_poll_work); | ||
884 | init_timer(&dst->link_poll_timer); | ||
885 | dst->link_poll_timer.data = (unsigned long)dst; | ||
886 | dst->link_poll_timer.function = dsa_link_poll_timer; | ||
887 | dst->link_poll_timer.expires = round_jiffies(jiffies + HZ); | ||
888 | add_timer(&dst->link_poll_timer); | ||
889 | } | ||
890 | |||
891 | return 0; | 870 | return 0; |
892 | } | 871 | } |
893 | 872 | ||
@@ -939,8 +918,10 @@ static int dsa_probe(struct platform_device *pdev) | |||
939 | platform_set_drvdata(pdev, dst); | 918 | platform_set_drvdata(pdev, dst); |
940 | 919 | ||
941 | ret = dsa_setup_dst(dst, dev, &pdev->dev, pd); | 920 | ret = dsa_setup_dst(dst, dev, &pdev->dev, pd); |
942 | if (ret) | 921 | if (ret) { |
922 | dev_put(dev); | ||
943 | goto out; | 923 | goto out; |
924 | } | ||
944 | 925 | ||
945 | return 0; | 926 | return 0; |
946 | 927 | ||
@@ -954,17 +935,14 @@ static void dsa_remove_dst(struct dsa_switch_tree *dst) | |||
954 | { | 935 | { |
955 | int i; | 936 | int i; |
956 | 937 | ||
957 | if (dst->link_poll_needed) | ||
958 | del_timer_sync(&dst->link_poll_timer); | ||
959 | |||
960 | flush_work(&dst->link_poll_work); | ||
961 | |||
962 | for (i = 0; i < dst->pd->nr_chips; i++) { | 938 | for (i = 0; i < dst->pd->nr_chips; i++) { |
963 | struct dsa_switch *ds = dst->ds[i]; | 939 | struct dsa_switch *ds = dst->ds[i]; |
964 | 940 | ||
965 | if (ds) | 941 | if (ds) |
966 | dsa_switch_destroy(ds); | 942 | dsa_switch_destroy(ds); |
967 | } | 943 | } |
944 | |||
945 | dev_put(dst->master_netdev); | ||
968 | } | 946 | } |
969 | 947 | ||
970 | static int dsa_remove(struct platform_device *pdev) | 948 | static int dsa_remove(struct platform_device *pdev) |
@@ -1010,6 +988,14 @@ static int dsa_suspend(struct device *d) | |||
1010 | struct dsa_switch_tree *dst = platform_get_drvdata(pdev); | 988 | struct dsa_switch_tree *dst = platform_get_drvdata(pdev); |
1011 | int i, ret = 0; | 989 | int i, ret = 0; |
1012 | 990 | ||
991 | dst->master_netdev->dsa_ptr = NULL; | ||
992 | |||
993 | /* If we used a tagging format that doesn't have an ethertype | ||
994 | * field, make sure that all packets from this point get sent | ||
995 | * without the tag and go through the regular receive path. | ||
996 | */ | ||
997 | wmb(); | ||
998 | |||
1013 | for (i = 0; i < dst->pd->nr_chips; i++) { | 999 | for (i = 0; i < dst->pd->nr_chips; i++) { |
1014 | struct dsa_switch *ds = dst->ds[i]; | 1000 | struct dsa_switch *ds = dst->ds[i]; |
1015 | 1001 | ||