Skip to content

Commit

Permalink
net: dsa: Get information about stacked DSA protocol
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
ffainelli authored and davem330 committed Jan 9, 2020
1 parent 8d2ff12 commit 4d77648
Show file tree
Hide file tree
Showing 20 changed files with 78 additions and 29 deletions.
22 changes: 14 additions & 8 deletions drivers/net/dsa/b53/b53_common.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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;

Expand All @@ -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);

Expand Down
4 changes: 3 additions & 1 deletion drivers/net/dsa/b53/b53_priv.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand Down
3 changes: 2 additions & 1 deletion drivers/net/dsa/dsa_loop.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
3 changes: 2 additions & 1 deletion drivers/net/dsa/lan9303-core.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
3 changes: 2 additions & 1 deletion drivers/net/dsa/lantiq_gswip.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
3 changes: 2 additions & 1 deletion drivers/net/dsa/microchip/ksz8795.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
3 changes: 2 additions & 1 deletion drivers/net/dsa/microchip/ksz9477.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
3 changes: 2 additions & 1 deletion drivers/net/dsa/mt7530.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
3 changes: 2 additions & 1 deletion drivers/net/dsa/mv88e6060.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
3 changes: 2 additions & 1 deletion drivers/net/dsa/mv88e6xxx/chip.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
3 changes: 2 additions & 1 deletion drivers/net/dsa/ocelot/felix.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
3 changes: 2 additions & 1 deletion drivers/net/dsa/qca/ar9331.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
3 changes: 2 additions & 1 deletion drivers/net/dsa/qca8k.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
3 changes: 2 additions & 1 deletion drivers/net/dsa/rtl8366rb.c
Original file line number Diff line number Diff line change
Expand Up @@ -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.
*
Expand Down
3 changes: 2 additions & 1 deletion drivers/net/dsa/sja1105/sja1105_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
3 changes: 2 additions & 1 deletion drivers/net/dsa/vitesse-vsc73xx-core.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
3 changes: 2 additions & 1 deletion include/net/dsa.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
31 changes: 29 additions & 2 deletions net/dsa/dsa2.c
Original file line number Diff line number Diff line change
Expand Up @@ -614,27 +614,54 @@ 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;
struct dsa_switch_tree *dst = ds->dst;
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;
Expand Down
1 change: 1 addition & 0 deletions net/dsa/dsa_priv.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
4 changes: 1 addition & 3 deletions net/dsa/slave.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down Expand Up @@ -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;
}
Expand Down

0 comments on commit 4d77648

Please sign in to comment.