]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/commitdiff
net: dsa: Get information about stacked DSA protocol
authorFlorian Fainelli <f.fainelli@gmail.com>
Wed, 8 Jan 2020 05:06:05 +0000 (21:06 -0800)
committerDavid S. Miller <davem@davemloft.net>
Thu, 9 Jan 2020 00:01:13 +0000 (16:01 -0800)
It is possible to stack multiple DSA switches in a way that they are not
part of the tree (disjoint) but the DSA master of a switch is a DSA
slave of another. When that happens switch drivers may have to know this
is the case so as to determine whether their tagging protocol has a
remove chance of working.

This is useful for specific switch drivers such as b53 where devices
have been known to be stacked in the wild without the Broadcom tag
protocol supporting that feature. This allows b53 to continue supporting
those devices by forcing the disabling of Broadcom tags on the outermost
switches if necessary.

The get_tag_protocol() function is therefore updated to gain an
additional enum dsa_tag_protocol argument which denotes the current
tagging protocol used by the DSA master we are attached to, else
DSA_TAG_PROTO_NONE for the top of the dsa_switch_tree.

Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
20 files changed:
drivers/net/dsa/b53/b53_common.c
drivers/net/dsa/b53/b53_priv.h
drivers/net/dsa/dsa_loop.c
drivers/net/dsa/lan9303-core.c
drivers/net/dsa/lantiq_gswip.c
drivers/net/dsa/microchip/ksz8795.c
drivers/net/dsa/microchip/ksz9477.c
drivers/net/dsa/mt7530.c
drivers/net/dsa/mv88e6060.c
drivers/net/dsa/mv88e6xxx/chip.c
drivers/net/dsa/ocelot/felix.c
drivers/net/dsa/qca/ar9331.c
drivers/net/dsa/qca8k.c
drivers/net/dsa/rtl8366rb.c
drivers/net/dsa/sja1105/sja1105_main.c
drivers/net/dsa/vitesse-vsc73xx-core.c
include/net/dsa.h
net/dsa/dsa2.c
net/dsa/dsa_priv.h
net/dsa/slave.c

index edacacfc9365ebfae88cb29f71a9c59002393a5f..2b530a31ef0fdafc524514d68e9272d363ba7bd3 100644 (file)
@@ -573,9 +573,8 @@ EXPORT_SYMBOL(b53_disable_port);
 
 void b53_brcm_hdr_setup(struct dsa_switch *ds, int port)
 {
-       bool tag_en = !(ds->ops->get_tag_protocol(ds, port) ==
-                        DSA_TAG_PROTO_NONE);
        struct b53_device *dev = ds->priv;
+       bool tag_en = !(dev->tag_protocol == DSA_TAG_PROTO_NONE);
        u8 hdr_ctl, val;
        u16 reg;
 
@@ -1876,7 +1875,8 @@ static bool b53_can_enable_brcm_tags(struct dsa_switch *ds, int port)
        return ret;
 }
 
-enum dsa_tag_protocol b53_get_tag_protocol(struct dsa_switch *ds, int port)
+enum dsa_tag_protocol b53_get_tag_protocol(struct dsa_switch *ds, int port,
+                                          enum dsa_tag_protocol mprot)
 {
        struct b53_device *dev = ds->priv;
 
@@ -1886,16 +1886,22 @@ enum dsa_tag_protocol b53_get_tag_protocol(struct dsa_switch *ds, int port)
         * misses on multicast addresses (TBD).
         */
        if (is5325(dev) || is5365(dev) || is539x(dev) || is531x5(dev) ||
-           !b53_can_enable_brcm_tags(ds, port))
-               return DSA_TAG_PROTO_NONE;
+           !b53_can_enable_brcm_tags(ds, port)) {
+               dev->tag_protocol = DSA_TAG_PROTO_NONE;
+               goto out;
+       }
 
        /* Broadcom BCM58xx chips have a flow accelerator on Port 8
         * which requires us to use the prepended Broadcom tag type
         */
-       if (dev->chip_id == BCM58XX_DEVICE_ID && port == B53_CPU_PORT)
-               return DSA_TAG_PROTO_BRCM_PREPEND;
+       if (dev->chip_id == BCM58XX_DEVICE_ID && port == B53_CPU_PORT) {
+               dev->tag_protocol = DSA_TAG_PROTO_BRCM_PREPEND;
+               goto out;
+       }
 
-       return DSA_TAG_PROTO_BRCM;
+       dev->tag_protocol = DSA_TAG_PROTO_BRCM;
+out:
+       return dev->tag_protocol;
 }
 EXPORT_SYMBOL(b53_get_tag_protocol);
 
index 1877acf05081fd5865438278a7fb27f88247f1a4..3c30f3a7eb29833f59a548d22d4df3f11187194f 100644 (file)
@@ -118,6 +118,7 @@ struct b53_device {
        u8 jumbo_size_reg;
        int reset_gpio;
        u8 num_arl_entries;
+       enum dsa_tag_protocol tag_protocol;
 
        /* used ports mask */
        u16 enabled_ports;
@@ -359,7 +360,8 @@ int b53_mdb_del(struct dsa_switch *ds, int port,
                const struct switchdev_obj_port_mdb *mdb);
 int b53_mirror_add(struct dsa_switch *ds, int port,
                   struct dsa_mall_mirror_tc_entry *mirror, bool ingress);
-enum dsa_tag_protocol b53_get_tag_protocol(struct dsa_switch *ds, int port);
+enum dsa_tag_protocol b53_get_tag_protocol(struct dsa_switch *ds, int port,
+                                          enum dsa_tag_protocol mprot);
 void b53_mirror_del(struct dsa_switch *ds, int port,
                    struct dsa_mall_mirror_tc_entry *mirror);
 int b53_enable_port(struct dsa_switch *ds, int port, struct phy_device *phy);
index c8d7ef27fd72eb8c93fbf2d0d1c3c02ec0137ecd..fdcb70b9f0e4d908af502a14924ace21c26279b8 100644 (file)
@@ -61,7 +61,8 @@ struct dsa_loop_priv {
 static struct phy_device *phydevs[PHY_MAX_ADDR];
 
 static enum dsa_tag_protocol dsa_loop_get_protocol(struct dsa_switch *ds,
-                                                  int port)
+                                                  int port,
+                                                  enum dsa_tag_protocol mp)
 {
        dev_dbg(ds->dev, "%s: port: %d\n", __func__, port);
 
index e3c333a8f45da29fd445a2f50f2d05138e414d6e..cc17a44dd3a8d916a07ec6e320665f376e01424a 100644 (file)
@@ -883,7 +883,8 @@ static int lan9303_check_device(struct lan9303 *chip)
 /* ---------------------------- DSA -----------------------------------*/
 
 static enum dsa_tag_protocol lan9303_get_tag_protocol(struct dsa_switch *ds,
-                                                     int port)
+                                                     int port,
+                                                     enum dsa_tag_protocol mp)
 {
        return DSA_TAG_PROTO_LAN9303;
 }
index 955324968b7447c5011e6fac2108a24fd5c975e8..0369c22fe3e11a62914e2221a3edd985de554a29 100644 (file)
@@ -841,7 +841,8 @@ static int gswip_setup(struct dsa_switch *ds)
 }
 
 static enum dsa_tag_protocol gswip_get_tag_protocol(struct dsa_switch *ds,
-                                                   int port)
+                                                   int port,
+                                                   enum dsa_tag_protocol mp)
 {
        return DSA_TAG_PROTO_GSWIP;
 }
index 24a5e99f7fd5b5ee66252ca7b41963f24d090d81..47d65b77caf77415b730f0ce3ca3b62332e0b2e0 100644 (file)
@@ -645,7 +645,8 @@ static void ksz8795_w_phy(struct ksz_device *dev, u16 phy, u16 reg, u16 val)
 }
 
 static enum dsa_tag_protocol ksz8795_get_tag_protocol(struct dsa_switch *ds,
-                                                     int port)
+                                                     int port,
+                                                     enum dsa_tag_protocol mp)
 {
        return DSA_TAG_PROTO_KSZ8795;
 }
index 50ffc63d623199e0684c5fb6a81d91a0950ac472..9a51b8a4de5d1432a58537dcda4654932e7cc2dc 100644 (file)
@@ -295,7 +295,8 @@ static void ksz9477_port_init_cnt(struct ksz_device *dev, int port)
 }
 
 static enum dsa_tag_protocol ksz9477_get_tag_protocol(struct dsa_switch *ds,
-                                                     int port)
+                                                     int port,
+                                                     enum dsa_tag_protocol mp)
 {
        enum dsa_tag_protocol proto = DSA_TAG_PROTO_KSZ9477;
        struct ksz_device *dev = ds->priv;
index ed1ec10ec62b294d9652fff417fcb1ac407979dc..022466ca1c1964d0005b5554d6f30b6113d11032 100644 (file)
@@ -1223,7 +1223,8 @@ mt7530_port_vlan_del(struct dsa_switch *ds, int port,
 }
 
 static enum dsa_tag_protocol
-mtk_get_tag_protocol(struct dsa_switch *ds, int port)
+mtk_get_tag_protocol(struct dsa_switch *ds, int port,
+                    enum dsa_tag_protocol mp)
 {
        struct mt7530_priv *priv = ds->priv;
 
index a5a37f47b32086301c3c3aeef8c944a7616b3e8d..24b8219fd607781d5fb042a8c24f8902b204ff0c 100644 (file)
@@ -43,7 +43,8 @@ static const char *mv88e6060_get_name(struct mii_bus *bus, int sw_addr)
 }
 
 static enum dsa_tag_protocol mv88e6060_get_tag_protocol(struct dsa_switch *ds,
-                                                       int port)
+                                                       int port,
+                                                       enum dsa_tag_protocol m)
 {
        return DSA_TAG_PROTO_TRAILER;
 }
index 99816ca9e5e46b52fa139f0da2440d43b2aa6659..04ef4d00f1349ac098738181e8a489f36ed8a4bc 100644 (file)
@@ -5217,7 +5217,8 @@ static struct mv88e6xxx_chip *mv88e6xxx_alloc_chip(struct device *dev)
 }
 
 static enum dsa_tag_protocol mv88e6xxx_get_tag_protocol(struct dsa_switch *ds,
-                                                       int port)
+                                                       int port,
+                                                       enum dsa_tag_protocol m)
 {
        struct mv88e6xxx_chip *chip = ds->priv;
 
index f072dd75cea2d0857e902a9979765158fcdb53ec..feccb6201660add2e3ff843d3c6e9179e4322340 100644 (file)
@@ -16,7 +16,8 @@
 #include "felix.h"
 
 static enum dsa_tag_protocol felix_get_tag_protocol(struct dsa_switch *ds,
-                                                   int port)
+                                                   int port,
+                                                   enum dsa_tag_protocol mp)
 {
        return DSA_TAG_PROTO_OCELOT;
 }
index da3bece75e21773280e7997f94445b9ada4d3667..de25f99e995ada04c75b34c9d2ebb9dbc7fd48c7 100644 (file)
@@ -347,7 +347,8 @@ static void ar9331_sw_port_disable(struct dsa_switch *ds, int port)
 }
 
 static enum dsa_tag_protocol ar9331_sw_get_tag_protocol(struct dsa_switch *ds,
-                                                       int port)
+                                                       int port,
+                                                       enum dsa_tag_protocol m)
 {
        return DSA_TAG_PROTO_AR9331;
 }
index e548289df31eec11cff3b95c87e37a4c755280d1..9f4205b4439b46b385cadfd3047578a17c37ac74 100644 (file)
@@ -1017,7 +1017,8 @@ qca8k_port_fdb_dump(struct dsa_switch *ds, int port,
 }
 
 static enum dsa_tag_protocol
-qca8k_get_tag_protocol(struct dsa_switch *ds, int port)
+qca8k_get_tag_protocol(struct dsa_switch *ds, int port,
+                      enum dsa_tag_protocol mp)
 {
        return DSA_TAG_PROTO_QCA;
 }
index f5cc8b0a7c74cfdfa4fe0b0f4e171f457de3f006..fd1977590cb4b4f4dc174bef357c63e716b0dc82 100644 (file)
@@ -964,7 +964,8 @@ static int rtl8366rb_setup(struct dsa_switch *ds)
 }
 
 static enum dsa_tag_protocol rtl8366_get_tag_protocol(struct dsa_switch *ds,
-                                                     int port)
+                                                     int port,
+                                                     enum dsa_tag_protocol mp)
 {
        /* For now, the RTL switches are handled without any custom tags.
         *
index 61795833c8f55ddbf2fdcaefe3915d5897966108..784e6b8166a095330e67f78d832419699cce9573 100644 (file)
@@ -1534,7 +1534,8 @@ static int sja1105_setup_8021q_tagging(struct dsa_switch *ds, bool enabled)
 }
 
 static enum dsa_tag_protocol
-sja1105_get_tag_protocol(struct dsa_switch *ds, int port)
+sja1105_get_tag_protocol(struct dsa_switch *ds, int port,
+                        enum dsa_tag_protocol mp)
 {
        return DSA_TAG_PROTO_SJA1105;
 }
index 69fc0110ce04438b7026b80922f00a81e3bfa215..6e21a2a5cf016db81f300b04766d960907a7d131 100644 (file)
@@ -542,7 +542,8 @@ static int vsc73xx_phy_write(struct dsa_switch *ds, int phy, int regnum,
 }
 
 static enum dsa_tag_protocol vsc73xx_get_tag_protocol(struct dsa_switch *ds,
-                                                     int port)
+                                                     int port,
+                                                     enum dsa_tag_protocol mp)
 {
        /* The switch internally uses a 8 byte header with length,
         * source port, tag, LPA and priority. This is supposedly
index 0c39fed8cd993984897999c6165c847dd8c05ff3..63495e3443acd6add41368e56adbf4208102fce7 100644 (file)
@@ -380,7 +380,8 @@ typedef int dsa_fdb_dump_cb_t(const unsigned char *addr, u16 vid,
                              bool is_static, void *data);
 struct dsa_switch_ops {
        enum dsa_tag_protocol (*get_tag_protocol)(struct dsa_switch *ds,
-                                                 int port);
+                                                 int port,
+                                                 enum dsa_tag_protocol mprot);
 
        int     (*setup)(struct dsa_switch *ds);
        void    (*teardown)(struct dsa_switch *ds);
index c66abbed4daf21f650f86e4d073c51657854d9b7..c6d81f2baf4e6ac0cf9b8757e0bd93507b89ca28 100644 (file)
@@ -614,6 +614,32 @@ static int dsa_port_parse_dsa(struct dsa_port *dp)
        return 0;
 }
 
+static enum dsa_tag_protocol dsa_get_tag_protocol(struct dsa_port *dp,
+                                                 struct net_device *master)
+{
+       enum dsa_tag_protocol tag_protocol = DSA_TAG_PROTO_NONE;
+       struct dsa_switch *mds, *ds = dp->ds;
+       unsigned int mdp_upstream;
+       struct dsa_port *mdp;
+
+       /* It is possible to stack DSA switches onto one another when that
+        * happens the switch driver may want to know if its tagging protocol
+        * is going to work in such a configuration.
+        */
+       if (dsa_slave_dev_check(master)) {
+               mdp = dsa_slave_to_port(master);
+               mds = mdp->ds;
+               mdp_upstream = dsa_upstream_port(mds, mdp->index);
+               tag_protocol = mds->ops->get_tag_protocol(mds, mdp_upstream,
+                                                         DSA_TAG_PROTO_NONE);
+       }
+
+       /* If the master device is not itself a DSA slave in a disjoint DSA
+        * tree, then return immediately.
+        */
+       return ds->ops->get_tag_protocol(ds, dp->index, tag_protocol);
+}
+
 static int dsa_port_parse_cpu(struct dsa_port *dp, struct net_device *master)
 {
        struct dsa_switch *ds = dp->ds;
@@ -621,20 +647,21 @@ static int dsa_port_parse_cpu(struct dsa_port *dp, struct net_device *master)
        const struct dsa_device_ops *tag_ops;
        enum dsa_tag_protocol tag_protocol;
 
-       tag_protocol = ds->ops->get_tag_protocol(ds, dp->index);
+       tag_protocol = dsa_get_tag_protocol(dp, master);
        tag_ops = dsa_tag_driver_get(tag_protocol);
        if (IS_ERR(tag_ops)) {
                if (PTR_ERR(tag_ops) == -ENOPROTOOPT)
                        return -EPROBE_DEFER;
                dev_warn(ds->dev, "No tagger for this switch\n");
+               dp->master = NULL;
                return PTR_ERR(tag_ops);
        }
 
+       dp->master = master;
        dp->type = DSA_PORT_TYPE_CPU;
        dp->filter = tag_ops->filter;
        dp->rcv = tag_ops->rcv;
        dp->tag_ops = tag_ops;
-       dp->master = master;
        dp->dst = dst;
 
        return 0;
index 8a162605b861bb819626463790cbaa142531d5fd..a7662e7a691d385d3f493d9e7814560e51a2b76a 100644 (file)
@@ -157,6 +157,7 @@ extern const struct dsa_device_ops notag_netdev_ops;
 void dsa_slave_mii_bus_init(struct dsa_switch *ds);
 int dsa_slave_create(struct dsa_port *dp);
 void dsa_slave_destroy(struct net_device *slave_dev);
+bool dsa_slave_dev_check(const struct net_device *dev);
 int dsa_slave_suspend(struct net_device *slave_dev);
 int dsa_slave_resume(struct net_device *slave_dev);
 int dsa_slave_register_notifier(void);
index c1828bdc79dccc8f8c4bdabf5a5ddf5dc9d0f99b..088c886e609ee78d15aa139aad469471b833e057 100644 (file)
@@ -22,8 +22,6 @@
 
 #include "dsa_priv.h"
 
-static bool dsa_slave_dev_check(const struct net_device *dev);
-
 /* slave mii_bus handling ***************************************************/
 static int dsa_slave_phy_read(struct mii_bus *bus, int addr, int reg)
 {
@@ -1473,7 +1471,7 @@ void dsa_slave_destroy(struct net_device *slave_dev)
        free_netdev(slave_dev);
 }
 
-static bool dsa_slave_dev_check(const struct net_device *dev)
+bool dsa_slave_dev_check(const struct net_device *dev)
 {
        return dev->netdev_ops == &dsa_slave_netdev_ops;
 }