net: dsa: let switches specify their tagging protocol
[firefly-linux-kernel-4.4.55.git] / net / dsa / dsa.c
index 2173402d87e0f56f255d0b378f06fc51aa2d3fed..4cc995664fdf679c22b2df051d1da50d5fb7cf20 100644 (file)
@@ -175,43 +175,14 @@ __ATTRIBUTE_GROUPS(dsa_hwmon);
 #endif /* CONFIG_NET_DSA_HWMON */
 
 /* basic switch operations **************************************************/
-static struct dsa_switch *
-dsa_switch_setup(struct dsa_switch_tree *dst, int index,
-                struct device *parent, struct device *host_dev)
+static int dsa_switch_setup_one(struct dsa_switch *ds, struct device *parent)
 {
-       struct dsa_chip_data *pd = dst->pd->chip + index;
-       struct dsa_switch_driver *drv;
-       struct dsa_switch *ds;
-       int ret;
-       char *name;
-       int i;
+       struct dsa_switch_driver *drv = ds->drv;
+       struct dsa_switch_tree *dst = ds->dst;
+       struct dsa_chip_data *pd = ds->pd;
        bool valid_name_found = false;
-
-       /*
-        * Probe for switch model.
-        */
-       drv = dsa_switch_probe(host_dev, pd->sw_addr, &name);
-       if (drv == NULL) {
-               netdev_err(dst->master_netdev, "[%d]: could not detect attached switch\n",
-                          index);
-               return ERR_PTR(-EINVAL);
-       }
-       netdev_info(dst->master_netdev, "[%d]: detected a %s switch\n",
-                   index, name);
-
-
-       /*
-        * Allocate and initialise switch state.
-        */
-       ds = kzalloc(sizeof(*ds) + drv->priv_size, GFP_KERNEL);
-       if (ds == NULL)
-               return ERR_PTR(-ENOMEM);
-
-       ds->dst = dst;
-       ds->index = index;
-       ds->pd = dst->pd->chip + index;
-       ds->drv = drv;
-       ds->master_dev = host_dev;
+       int index = ds->index;
+       int i, ret;
 
        /*
         * Validate supplied switch configuration.
@@ -256,7 +227,7 @@ dsa_switch_setup(struct dsa_switch_tree *dst, int index,
         * switch.
         */
        if (dst->cpu_switch == index) {
-               switch (drv->tag_protocol) {
+               switch (ds->tag_protocol) {
 #ifdef CONFIG_NET_DSA_TAG_DSA
                case DSA_TAG_PROTO_DSA:
                        dst->rcv = dsa_netdev_ops.rcv;
@@ -284,7 +255,7 @@ dsa_switch_setup(struct dsa_switch_tree *dst, int index,
                        goto out;
                }
 
-               dst->tag_protocol = drv->tag_protocol;
+               dst->tag_protocol = ds->tag_protocol;
        }
 
        /*
@@ -314,19 +285,15 @@ dsa_switch_setup(struct dsa_switch_tree *dst, int index,
         * Create network devices for physical switch ports.
         */
        for (i = 0; i < DSA_MAX_PORTS; i++) {
-               struct net_device *slave_dev;
-
                if (!(ds->phys_port_mask & (1 << i)))
                        continue;
 
-               slave_dev = dsa_slave_create(ds, parent, i, pd->port_names[i]);
-               if (slave_dev == NULL) {
+               ret = dsa_slave_create(ds, parent, i, pd->port_names[i]);
+               if (ret < 0) {
                        netdev_err(dst->master_netdev, "[%d]: can't create dsa slave device for port %d(%s)\n",
                                   index, i, pd->port_names[i]);
-                       continue;
+                       ret = 0;
                }
-
-               ds->ports[i] = slave_dev;
        }
 
 #ifdef CONFIG_NET_DSA_HWMON
@@ -354,13 +321,57 @@ dsa_switch_setup(struct dsa_switch_tree *dst, int index,
        }
 #endif /* CONFIG_NET_DSA_HWMON */
 
-       return ds;
+       return ret;
 
 out_free:
        mdiobus_free(ds->slave_mii_bus);
 out:
        kfree(ds);
-       return ERR_PTR(ret);
+       return ret;
+}
+
+static struct dsa_switch *
+dsa_switch_setup(struct dsa_switch_tree *dst, int index,
+                struct device *parent, struct device *host_dev)
+{
+       struct dsa_chip_data *pd = dst->pd->chip + index;
+       struct dsa_switch_driver *drv;
+       struct dsa_switch *ds;
+       int ret;
+       char *name;
+
+       /*
+        * Probe for switch model.
+        */
+       drv = dsa_switch_probe(host_dev, pd->sw_addr, &name);
+       if (drv == NULL) {
+               netdev_err(dst->master_netdev, "[%d]: could not detect attached switch\n",
+                          index);
+               return ERR_PTR(-EINVAL);
+       }
+       netdev_info(dst->master_netdev, "[%d]: detected a %s switch\n",
+                   index, name);
+
+
+       /*
+        * Allocate and initialise switch state.
+        */
+       ds = kzalloc(sizeof(*ds) + drv->priv_size, GFP_KERNEL);
+       if (ds == NULL)
+               return NULL;
+
+       ds->dst = dst;
+       ds->index = index;
+       ds->pd = pd;
+       ds->drv = drv;
+       ds->tag_protocol = drv->tag_protocol;
+       ds->master_dev = host_dev;
+
+       ret = dsa_switch_setup_one(ds, parent);
+       if (ret)
+               return NULL;
+
+       return ds;
 }
 
 static void dsa_switch_destroy(struct dsa_switch *ds)
@@ -378,7 +389,7 @@ static int dsa_switch_suspend(struct dsa_switch *ds)
 
        /* Suspend slave network devices */
        for (i = 0; i < DSA_MAX_PORTS; i++) {
-               if (!(ds->phys_port_mask & (1 << i)))
+               if (!dsa_is_port_initialized(ds, i))
                        continue;
 
                ret = dsa_slave_suspend(ds->ports[i]);
@@ -404,7 +415,7 @@ static int dsa_switch_resume(struct dsa_switch *ds)
 
        /* Resume slave network devices */
        for (i = 0; i < DSA_MAX_PORTS; i++) {
-               if (!(ds->phys_port_mask & (1 << i)))
+               if (!dsa_is_port_initialized(ds, i))
                        continue;
 
                ret = dsa_slave_resume(ds->ports[i]);
@@ -567,9 +578,9 @@ static void dsa_of_free_platform_data(struct dsa_platform_data *pd)
        kfree(pd->chip);
 }
 
-static int dsa_of_probe(struct platform_device *pdev)
+static int dsa_of_probe(struct device *dev)
 {
-       struct device_node *np = pdev->dev.of_node;
+       struct device_node *np = dev->of_node;
        struct device_node *child, *mdio, *ethernet, *port, *link;
        struct mii_bus *mdio_bus;
        struct platform_device *ethernet_dev;
@@ -587,7 +598,7 @@ static int dsa_of_probe(struct platform_device *pdev)
 
        mdio_bus = of_mdio_find_bus(mdio);
        if (!mdio_bus)
-               return -EINVAL;
+               return -EPROBE_DEFER;
 
        ethernet = of_parse_phandle(np, "dsa,ethernet", 0);
        if (!ethernet)
@@ -595,13 +606,13 @@ static int dsa_of_probe(struct platform_device *pdev)
 
        ethernet_dev = of_find_device_by_node(ethernet);
        if (!ethernet_dev)
-               return -ENODEV;
+               return -EPROBE_DEFER;
 
        pd = kzalloc(sizeof(*pd), GFP_KERNEL);
        if (!pd)
                return -ENOMEM;
 
-       pdev->dev.platform_data = pd;
+       dev->platform_data = pd;
        pd->netdev = &ethernet_dev->dev;
        pd->nr_chips = of_get_available_child_count(np);
        if (pd->nr_chips > DSA_MAX_SWITCHES)
@@ -674,27 +685,27 @@ out_free_chip:
        dsa_of_free_platform_data(pd);
 out_free:
        kfree(pd);
-       pdev->dev.platform_data = NULL;
+       dev->platform_data = NULL;
        return ret;
 }
 
-static void dsa_of_remove(struct platform_device *pdev)
+static void dsa_of_remove(struct device *dev)
 {
-       struct dsa_platform_data *pd = pdev->dev.platform_data;
+       struct dsa_platform_data *pd = dev->platform_data;
 
-       if (!pdev->dev.of_node)
+       if (!dev->of_node)
                return;
 
        dsa_of_free_platform_data(pd);
        kfree(pd);
 }
 #else
-static inline int dsa_of_probe(struct platform_device *pdev)
+static inline int dsa_of_probe(struct device *dev)
 {
        return 0;
 }
 
-static inline void dsa_of_remove(struct platform_device *pdev)
+static inline void dsa_of_remove(struct device *dev)
 {
 }
 #endif
@@ -710,7 +721,7 @@ static int dsa_probe(struct platform_device *pdev)
                       dsa_driver_version);
 
        if (pdev->dev.of_node) {
-               ret = dsa_of_probe(pdev);
+               ret = dsa_of_probe(&pdev->dev);
                if (ret)
                        return ret;
 
@@ -722,7 +733,7 @@ static int dsa_probe(struct platform_device *pdev)
 
        dev = dev_to_net_device(pd->netdev);
        if (dev == NULL) {
-               ret = -EINVAL;
+               ret = -EPROBE_DEFER;
                goto out;
        }
 
@@ -781,7 +792,7 @@ static int dsa_probe(struct platform_device *pdev)
        return 0;
 
 out:
-       dsa_of_remove(pdev);
+       dsa_of_remove(&pdev->dev);
 
        return ret;
 }
@@ -803,7 +814,7 @@ static int dsa_remove(struct platform_device *pdev)
                        dsa_switch_destroy(ds);
        }
 
-       dsa_of_remove(pdev);
+       dsa_of_remove(&pdev->dev);
 
        return 0;
 }
@@ -830,6 +841,10 @@ static struct packet_type dsa_pack_type __read_mostly = {
        .func   = dsa_switch_rcv,
 };
 
+static struct notifier_block dsa_netdevice_nb __read_mostly = {
+       .notifier_call  = dsa_slave_netdevice_event,
+};
+
 #ifdef CONFIG_PM_SLEEP
 static int dsa_suspend(struct device *d)
 {
@@ -888,6 +903,8 @@ static int __init dsa_init_module(void)
 {
        int rc;
 
+       register_netdevice_notifier(&dsa_netdevice_nb);
+
        rc = platform_driver_register(&dsa_driver);
        if (rc)
                return rc;
@@ -900,6 +917,7 @@ module_init(dsa_init_module);
 
 static void __exit dsa_cleanup_module(void)
 {
+       unregister_netdevice_notifier(&dsa_netdevice_nb);
        dev_remove_pack(&dsa_pack_type);
        platform_driver_unregister(&dsa_driver);
 }