dsa: Replace mii_bus with a generic host device
[firefly-linux-kernel-4.4.55.git] / net / dsa / dsa.c
index 0a49632fac478f1ac17b3f0159cbdf748fe25110..b34d6978d7734dd992655e6e9bfa81282d86d64b 100644 (file)
@@ -10,7 +10,6 @@
  */
 
 #include <linux/list.h>
-#include <linux/netdevice.h>
 #include <linux/platform_device.h>
 #include <linux/slab.h>
 #include <linux/module.h>
@@ -44,7 +43,7 @@ void unregister_switch_driver(struct dsa_switch_driver *drv)
 EXPORT_SYMBOL_GPL(unregister_switch_driver);
 
 static struct dsa_switch_driver *
-dsa_switch_probe(struct mii_bus *bus, int sw_addr, char **_name)
+dsa_switch_probe(struct device *host_dev, int sw_addr, char **_name)
 {
        struct dsa_switch_driver *ret;
        struct list_head *list;
@@ -59,7 +58,7 @@ dsa_switch_probe(struct mii_bus *bus, int sw_addr, char **_name)
 
                drv = list_entry(list, struct dsa_switch_driver, list);
 
-               name = drv->probe(bus, sw_addr);
+               name = drv->probe(host_dev, sw_addr);
                if (name != NULL) {
                        ret = drv;
                        break;
@@ -76,7 +75,7 @@ dsa_switch_probe(struct mii_bus *bus, int sw_addr, char **_name)
 /* basic switch operations **************************************************/
 static struct dsa_switch *
 dsa_switch_setup(struct dsa_switch_tree *dst, int index,
-                struct device *parent, struct mii_bus *bus)
+                struct device *parent, struct device *host_dev)
 {
        struct dsa_chip_data *pd = dst->pd->chip + index;
        struct dsa_switch_driver *drv;
@@ -89,7 +88,7 @@ dsa_switch_setup(struct dsa_switch_tree *dst, int index,
        /*
         * Probe for switch model.
         */
-       drv = dsa_switch_probe(bus, pd->sw_addr, &name);
+       drv = dsa_switch_probe(host_dev, pd->sw_addr, &name);
        if (drv == NULL) {
                printk(KERN_ERR "%s[%d]: could not detect attached switch\n",
                       dst->master_netdev->name, index);
@@ -110,8 +109,7 @@ dsa_switch_setup(struct dsa_switch_tree *dst, int index,
        ds->index = index;
        ds->pd = dst->pd->chip + index;
        ds->drv = drv;
-       ds->master_mii_bus = bus;
-
+       ds->master_dev = host_dev;
 
        /*
         * Validate supplied switch configuration.
@@ -144,14 +142,44 @@ dsa_switch_setup(struct dsa_switch_tree *dst, int index,
                goto out;
        }
 
+       /* Make the built-in MII bus mask match the number of ports,
+        * switch drivers can override this later
+        */
+       ds->phys_mii_mask = ds->phys_port_mask;
+
        /*
         * If the CPU connects to this switch, set the switch tree
         * tagging protocol to the preferred tagging format of this
         * switch.
         */
-       if (ds->dst->cpu_switch == index)
-               ds->dst->tag_protocol = drv->tag_protocol;
+       if (dst->cpu_switch == index) {
+               switch (drv->tag_protocol) {
+#ifdef CONFIG_NET_DSA_TAG_DSA
+               case DSA_TAG_PROTO_DSA:
+                       dst->rcv = dsa_netdev_ops.rcv;
+                       break;
+#endif
+#ifdef CONFIG_NET_DSA_TAG_EDSA
+               case DSA_TAG_PROTO_EDSA:
+                       dst->rcv = edsa_netdev_ops.rcv;
+                       break;
+#endif
+#ifdef CONFIG_NET_DSA_TAG_TRAILER
+               case DSA_TAG_PROTO_TRAILER:
+                       dst->rcv = trailer_netdev_ops.rcv;
+                       break;
+#endif
+#ifdef CONFIG_NET_DSA_TAG_BRCM
+               case DSA_TAG_PROTO_BRCM:
+                       dst->rcv = brcm_netdev_ops.rcv;
+                       break;
+#endif
+               default:
+                       break;
+               }
 
+               dst->tag_protocol = drv->tag_protocol;
+       }
 
        /*
         * Do basic register setup.
@@ -256,7 +284,7 @@ static struct device *dev_find_class(struct device *parent, char *class)
        return device_find_child(parent, class, dev_is_class);
 }
 
-static struct mii_bus *dev_to_mii_bus(struct device *dev)
+struct mii_bus *dsa_host_dev_to_mii_bus(struct device *dev)
 {
        struct device *d;
 
@@ -272,6 +300,7 @@ static struct mii_bus *dev_to_mii_bus(struct device *dev)
 
        return NULL;
 }
+EXPORT_SYMBOL_GPL(dsa_host_dev_to_mii_bus);
 
 static struct net_device *dev_to_net_device(struct device *dev)
 {
@@ -410,6 +439,7 @@ static int dsa_of_probe(struct platform_device *pdev)
                chip_index++;
                cd = &pd->chip[chip_index];
 
+               cd->of_node = child;
                cd->mii_bus = &mdio_bus->dev;
 
                sw_addr = of_get_property(child, "reg", NULL);
@@ -431,6 +461,8 @@ static int dsa_of_probe(struct platform_device *pdev)
                        if (!port_name)
                                continue;
 
+                       cd->port_dn[port_index] = port;
+
                        cd->port_names[port_index] = kstrdup(port_name,
                                        GFP_KERNEL);
                        if (!cd->port_names[port_index]) {
@@ -534,17 +566,9 @@ static int dsa_probe(struct platform_device *pdev)
        dst->cpu_port = -1;
 
        for (i = 0; i < pd->nr_chips; i++) {
-               struct mii_bus *bus;
                struct dsa_switch *ds;
 
-               bus = dev_to_mii_bus(pd->chip[i].mii_bus);
-               if (bus == NULL) {
-                       printk(KERN_ERR "%s[%d]: no mii bus found for "
-                               "dsa switch\n", dev->name, i);
-                       continue;
-               }
-
-               ds = dsa_switch_setup(dst, i, &pdev->dev, bus);
+               ds = dsa_switch_setup(dst, i, &pdev->dev, pd->chip[i].host_dev);
                if (IS_ERR(ds)) {
                        printk(KERN_ERR "%s[%d]: couldn't create dsa switch "
                                "instance (error %ld)\n", dev->name, i,
@@ -608,7 +632,26 @@ static void dsa_shutdown(struct platform_device *pdev)
 {
 }
 
+static int dsa_switch_rcv(struct sk_buff *skb, struct net_device *dev,
+                         struct packet_type *pt, struct net_device *orig_dev)
+{
+       struct dsa_switch_tree *dst = dev->dsa_ptr;
+
+       if (unlikely(dst == NULL)) {
+               kfree_skb(skb);
+               return 0;
+       }
+
+       return dst->rcv(skb, dev, pt, orig_dev);
+}
+
+static struct packet_type dsa_pack_type __read_mostly = {
+       .type   = cpu_to_be16(ETH_P_XDSA),
+       .func   = dsa_switch_rcv,
+};
+
 static const struct of_device_id dsa_of_match_table[] = {
+       { .compatible = "brcm,bcm7445-switch-v4.0" },
        { .compatible = "marvell,dsa", },
        {}
 };
@@ -633,30 +676,15 @@ static int __init dsa_init_module(void)
        if (rc)
                return rc;
 
-#ifdef CONFIG_NET_DSA_TAG_DSA
-       dev_add_pack(&dsa_packet_type);
-#endif
-#ifdef CONFIG_NET_DSA_TAG_EDSA
-       dev_add_pack(&edsa_packet_type);
-#endif
-#ifdef CONFIG_NET_DSA_TAG_TRAILER
-       dev_add_pack(&trailer_packet_type);
-#endif
+       dev_add_pack(&dsa_pack_type);
+
        return 0;
 }
 module_init(dsa_init_module);
 
 static void __exit dsa_cleanup_module(void)
 {
-#ifdef CONFIG_NET_DSA_TAG_TRAILER
-       dev_remove_pack(&trailer_packet_type);
-#endif
-#ifdef CONFIG_NET_DSA_TAG_EDSA
-       dev_remove_pack(&edsa_packet_type);
-#endif
-#ifdef CONFIG_NET_DSA_TAG_DSA
-       dev_remove_pack(&dsa_packet_type);
-#endif
+       dev_remove_pack(&dsa_pack_type);
        platform_driver_unregister(&dsa_driver);
 }
 module_exit(dsa_cleanup_module);