Commit 78b6d073 authored by David S. Miller's avatar David S. Miller

Merge branch 'Broadcom-tags-support-for-531x5-539x-families'

Florian Fainelli says:

====================
Broadcom tags support for 531x5/539x families

This patch series finally allows us to enable Broadcom tags on the
BCM531x5/BCM539x switch series which are very often cascaded onto
another on-chip Broadcom switch. Because of that we need to be able to
detect that Broadcom tags are already enabled on our DSA master which
happens to be a DSA slave in that case since they are not part of the
same DSA switch tree, the protocol does not support that.

Due to the way DSA works, get_tag_protocol() is called prior to
ds->ops->setup and we do not have all data structures set-up (in
particular dsa_port::cpu_dp is not filed yet) so doing this at the time
get_tag_protocol() is called and without exporting a helper function is
desirable to limit our footprint into the framework.

Having the core (net/dsa/dsa2.c) return and enforce DSA_TAG_PROTO_NONE
was considered and done initially but this leaves the driver outside of
the decision to force/fallback to a particular protocol, instead of
letting it in control. Also there is no reason to suspect that all
tagging protocols are problematic, e.g.: "inner" Marvell EDSA with
"outer" Broadcom tag may work just fine, and vice versa.

This was tested on:

- Lamobo R1 which now has working Broadcom tags for its external BCM53125 switch
- BCM7445 which has a BCM53125 hanging off one of its internal switch
  port, the BCM53125 still works with DSA_TAG_PROTO_NONE
- BCM7278 which has a peculiar dual CPU port set-up (so dual IMP mode
  needs to be enabled)
- Northstar Plus with DSA_TAG_PROTO_BRCM_PREPEND and no external
  switches hanging off the internal switch
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 8d2ff126 8fab459e
...@@ -371,8 +371,6 @@ static void b53_enable_vlan(struct b53_device *dev, bool enable, ...@@ -371,8 +371,6 @@ static void b53_enable_vlan(struct b53_device *dev, bool enable,
b53_read8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL5, &vc5); b53_read8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL5, &vc5);
} }
mgmt &= ~SM_SW_FWD_MODE;
if (enable) { if (enable) {
vc0 |= VC0_VLAN_EN | VC0_VID_CHK_EN | VC0_VID_HASH_VID; vc0 |= VC0_VLAN_EN | VC0_VID_CHK_EN | VC0_VID_HASH_VID;
vc1 |= VC1_RX_MCST_UNTAG_EN | VC1_RX_MCST_FWD_EN; vc1 |= VC1_RX_MCST_UNTAG_EN | VC1_RX_MCST_FWD_EN;
...@@ -573,9 +571,8 @@ EXPORT_SYMBOL(b53_disable_port); ...@@ -573,9 +571,8 @@ EXPORT_SYMBOL(b53_disable_port);
void b53_brcm_hdr_setup(struct dsa_switch *ds, int 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; struct b53_device *dev = ds->priv;
bool tag_en = !(dev->tag_protocol == DSA_TAG_PROTO_NONE);
u8 hdr_ctl, val; u8 hdr_ctl, val;
u16 reg; u16 reg;
...@@ -595,6 +592,22 @@ void b53_brcm_hdr_setup(struct dsa_switch *ds, int port) ...@@ -595,6 +592,22 @@ void b53_brcm_hdr_setup(struct dsa_switch *ds, int port)
break; break;
} }
/* Enable management mode if tagging is requested */
b53_read8(dev, B53_CTRL_PAGE, B53_SWITCH_MODE, &hdr_ctl);
if (tag_en)
hdr_ctl |= SM_SW_FWD_MODE;
else
hdr_ctl &= ~SM_SW_FWD_MODE;
b53_write8(dev, B53_CTRL_PAGE, B53_SWITCH_MODE, hdr_ctl);
/* Configure the appropriate IMP port */
b53_read8(dev, B53_MGMT_PAGE, B53_GLOBAL_CONFIG, &hdr_ctl);
if (port == 8)
hdr_ctl |= GC_FRM_MGMT_PORT_MII;
else if (port == 5)
hdr_ctl |= GC_FRM_MGMT_PORT_M;
b53_write8(dev, B53_MGMT_PAGE, B53_GLOBAL_CONFIG, hdr_ctl);
/* Enable Broadcom tags for IMP port */ /* Enable Broadcom tags for IMP port */
b53_read8(dev, B53_MGMT_PAGE, B53_BRCM_HDR, &hdr_ctl); b53_read8(dev, B53_MGMT_PAGE, B53_BRCM_HDR, &hdr_ctl);
if (tag_en) if (tag_en)
...@@ -1866,36 +1879,57 @@ static bool b53_possible_cpu_port(struct dsa_switch *ds, int port) ...@@ -1866,36 +1879,57 @@ static bool b53_possible_cpu_port(struct dsa_switch *ds, int port)
return false; return false;
} }
static bool b53_can_enable_brcm_tags(struct dsa_switch *ds, int port) static bool b53_can_enable_brcm_tags(struct dsa_switch *ds, int port,
enum dsa_tag_protocol tag_protocol)
{ {
bool ret = b53_possible_cpu_port(ds, port); bool ret = b53_possible_cpu_port(ds, port);
if (!ret) if (!ret) {
dev_warn(ds->dev, "Port %d is not Broadcom tag capable\n", dev_warn(ds->dev, "Port %d is not Broadcom tag capable\n",
port); port);
return ret;
}
switch (tag_protocol) {
case DSA_TAG_PROTO_BRCM:
case DSA_TAG_PROTO_BRCM_PREPEND:
dev_warn(ds->dev,
"Port %d is stacked to Broadcom tag switch\n", port);
ret = false;
break;
default:
ret = true;
break;
}
return ret; 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; struct b53_device *dev = ds->priv;
/* Older models (5325, 5365) support a different tag format that we do /* Older models (5325, 5365) support a different tag format that we do
* not support in net/dsa/tag_brcm.c yet. 539x and 531x5 require managed * not support in net/dsa/tag_brcm.c yet.
* mode to be turned on which means we need to specifically manage ARL
* misses on multicast addresses (TBD).
*/ */
if (is5325(dev) || is5365(dev) || is539x(dev) || is531x5(dev) || if (is5325(dev) || is5365(dev) ||
!b53_can_enable_brcm_tags(ds, port)) !b53_can_enable_brcm_tags(ds, port, mprot)) {
return DSA_TAG_PROTO_NONE; dev->tag_protocol = DSA_TAG_PROTO_NONE;
goto out;
}
/* Broadcom BCM58xx chips have a flow accelerator on Port 8 /* Broadcom BCM58xx chips have a flow accelerator on Port 8
* which requires us to use the prepended Broadcom tag type * which requires us to use the prepended Broadcom tag type
*/ */
if (dev->chip_id == BCM58XX_DEVICE_ID && port == B53_CPU_PORT) if (dev->chip_id == BCM58XX_DEVICE_ID && port == B53_CPU_PORT) {
return DSA_TAG_PROTO_BRCM_PREPEND; 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); EXPORT_SYMBOL(b53_get_tag_protocol);
......
...@@ -118,6 +118,7 @@ struct b53_device { ...@@ -118,6 +118,7 @@ struct b53_device {
u8 jumbo_size_reg; u8 jumbo_size_reg;
int reset_gpio; int reset_gpio;
u8 num_arl_entries; u8 num_arl_entries;
enum dsa_tag_protocol tag_protocol;
/* used ports mask */ /* used ports mask */
u16 enabled_ports; u16 enabled_ports;
...@@ -359,7 +360,8 @@ int b53_mdb_del(struct dsa_switch *ds, int port, ...@@ -359,7 +360,8 @@ int b53_mdb_del(struct dsa_switch *ds, int port,
const struct switchdev_obj_port_mdb *mdb); const struct switchdev_obj_port_mdb *mdb);
int b53_mirror_add(struct dsa_switch *ds, int port, int b53_mirror_add(struct dsa_switch *ds, int port,
struct dsa_mall_mirror_tc_entry *mirror, bool ingress); 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, void b53_mirror_del(struct dsa_switch *ds, int port,
struct dsa_mall_mirror_tc_entry *mirror); struct dsa_mall_mirror_tc_entry *mirror);
int b53_enable_port(struct dsa_switch *ds, int port, struct phy_device *phy); int b53_enable_port(struct dsa_switch *ds, int port, struct phy_device *phy);
......
...@@ -61,7 +61,8 @@ struct dsa_loop_priv { ...@@ -61,7 +61,8 @@ struct dsa_loop_priv {
static struct phy_device *phydevs[PHY_MAX_ADDR]; static struct phy_device *phydevs[PHY_MAX_ADDR];
static enum dsa_tag_protocol dsa_loop_get_protocol(struct dsa_switch *ds, 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); dev_dbg(ds->dev, "%s: port: %d\n", __func__, port);
......
...@@ -883,7 +883,8 @@ static int lan9303_check_device(struct lan9303 *chip) ...@@ -883,7 +883,8 @@ static int lan9303_check_device(struct lan9303 *chip)
/* ---------------------------- DSA -----------------------------------*/ /* ---------------------------- DSA -----------------------------------*/
static enum dsa_tag_protocol lan9303_get_tag_protocol(struct dsa_switch *ds, 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; return DSA_TAG_PROTO_LAN9303;
} }
......
...@@ -841,7 +841,8 @@ static int gswip_setup(struct dsa_switch *ds) ...@@ -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, 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; return DSA_TAG_PROTO_GSWIP;
} }
......
...@@ -645,7 +645,8 @@ static void ksz8795_w_phy(struct ksz_device *dev, u16 phy, u16 reg, u16 val) ...@@ -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, 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; return DSA_TAG_PROTO_KSZ8795;
} }
......
...@@ -295,7 +295,8 @@ static void ksz9477_port_init_cnt(struct ksz_device *dev, int port) ...@@ -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, 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; enum dsa_tag_protocol proto = DSA_TAG_PROTO_KSZ9477;
struct ksz_device *dev = ds->priv; struct ksz_device *dev = ds->priv;
......
...@@ -1223,7 +1223,8 @@ mt7530_port_vlan_del(struct dsa_switch *ds, int port, ...@@ -1223,7 +1223,8 @@ mt7530_port_vlan_del(struct dsa_switch *ds, int port,
} }
static enum dsa_tag_protocol 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; struct mt7530_priv *priv = ds->priv;
......
...@@ -43,7 +43,8 @@ static const char *mv88e6060_get_name(struct mii_bus *bus, int sw_addr) ...@@ -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, 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; return DSA_TAG_PROTO_TRAILER;
} }
......
...@@ -5217,7 +5217,8 @@ static struct mv88e6xxx_chip *mv88e6xxx_alloc_chip(struct device *dev) ...@@ -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, 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; struct mv88e6xxx_chip *chip = ds->priv;
......
...@@ -16,7 +16,8 @@ ...@@ -16,7 +16,8 @@
#include "felix.h" #include "felix.h"
static enum dsa_tag_protocol felix_get_tag_protocol(struct dsa_switch *ds, 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; return DSA_TAG_PROTO_OCELOT;
} }
......
...@@ -347,7 +347,8 @@ static void ar9331_sw_port_disable(struct dsa_switch *ds, int port) ...@@ -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, 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; return DSA_TAG_PROTO_AR9331;
} }
......
...@@ -1017,7 +1017,8 @@ qca8k_port_fdb_dump(struct dsa_switch *ds, int port, ...@@ -1017,7 +1017,8 @@ qca8k_port_fdb_dump(struct dsa_switch *ds, int port,
} }
static enum dsa_tag_protocol 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; return DSA_TAG_PROTO_QCA;
} }
......
...@@ -964,7 +964,8 @@ static int rtl8366rb_setup(struct dsa_switch *ds) ...@@ -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, 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. /* For now, the RTL switches are handled without any custom tags.
* *
......
...@@ -1534,7 +1534,8 @@ static int sja1105_setup_8021q_tagging(struct dsa_switch *ds, bool enabled) ...@@ -1534,7 +1534,8 @@ static int sja1105_setup_8021q_tagging(struct dsa_switch *ds, bool enabled)
} }
static enum dsa_tag_protocol 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; return DSA_TAG_PROTO_SJA1105;
} }
......
...@@ -542,7 +542,8 @@ static int vsc73xx_phy_write(struct dsa_switch *ds, int phy, int regnum, ...@@ -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, 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, /* The switch internally uses a 8 byte header with length,
* source port, tag, LPA and priority. This is supposedly * source port, tag, LPA and priority. This is supposedly
......
...@@ -380,7 +380,8 @@ typedef int dsa_fdb_dump_cb_t(const unsigned char *addr, u16 vid, ...@@ -380,7 +380,8 @@ typedef int dsa_fdb_dump_cb_t(const unsigned char *addr, u16 vid,
bool is_static, void *data); bool is_static, void *data);
struct dsa_switch_ops { struct dsa_switch_ops {
enum dsa_tag_protocol (*get_tag_protocol)(struct dsa_switch *ds, 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); int (*setup)(struct dsa_switch *ds);
void (*teardown)(struct dsa_switch *ds); void (*teardown)(struct dsa_switch *ds);
......
...@@ -614,6 +614,32 @@ static int dsa_port_parse_dsa(struct dsa_port *dp) ...@@ -614,6 +614,32 @@ static int dsa_port_parse_dsa(struct dsa_port *dp)
return 0; 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) static int dsa_port_parse_cpu(struct dsa_port *dp, struct net_device *master)
{ {
struct dsa_switch *ds = dp->ds; struct dsa_switch *ds = dp->ds;
...@@ -621,20 +647,21 @@ static int dsa_port_parse_cpu(struct dsa_port *dp, struct net_device *master) ...@@ -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; const struct dsa_device_ops *tag_ops;
enum dsa_tag_protocol tag_protocol; 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); tag_ops = dsa_tag_driver_get(tag_protocol);
if (IS_ERR(tag_ops)) { if (IS_ERR(tag_ops)) {
if (PTR_ERR(tag_ops) == -ENOPROTOOPT) if (PTR_ERR(tag_ops) == -ENOPROTOOPT)
return -EPROBE_DEFER; return -EPROBE_DEFER;
dev_warn(ds->dev, "No tagger for this switch\n"); dev_warn(ds->dev, "No tagger for this switch\n");
dp->master = NULL;
return PTR_ERR(tag_ops); return PTR_ERR(tag_ops);
} }
dp->master = master;
dp->type = DSA_PORT_TYPE_CPU; dp->type = DSA_PORT_TYPE_CPU;
dp->filter = tag_ops->filter; dp->filter = tag_ops->filter;
dp->rcv = tag_ops->rcv; dp->rcv = tag_ops->rcv;
dp->tag_ops = tag_ops; dp->tag_ops = tag_ops;
dp->master = master;
dp->dst = dst; dp->dst = dst;
return 0; return 0;
......
...@@ -157,6 +157,7 @@ extern const struct dsa_device_ops notag_netdev_ops; ...@@ -157,6 +157,7 @@ extern const struct dsa_device_ops notag_netdev_ops;
void dsa_slave_mii_bus_init(struct dsa_switch *ds); void dsa_slave_mii_bus_init(struct dsa_switch *ds);
int dsa_slave_create(struct dsa_port *dp); int dsa_slave_create(struct dsa_port *dp);
void dsa_slave_destroy(struct net_device *slave_dev); 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_suspend(struct net_device *slave_dev);
int dsa_slave_resume(struct net_device *slave_dev); int dsa_slave_resume(struct net_device *slave_dev);
int dsa_slave_register_notifier(void); int dsa_slave_register_notifier(void);
......
...@@ -22,8 +22,6 @@ ...@@ -22,8 +22,6 @@
#include "dsa_priv.h" #include "dsa_priv.h"
static bool dsa_slave_dev_check(const struct net_device *dev);
/* slave mii_bus handling ***************************************************/ /* slave mii_bus handling ***************************************************/
static int dsa_slave_phy_read(struct mii_bus *bus, int addr, int reg) 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) ...@@ -1473,7 +1471,7 @@ void dsa_slave_destroy(struct net_device *slave_dev)
free_netdev(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; return dev->netdev_ops == &dsa_slave_netdev_ops;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment