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

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
Loading
Loading
Loading
Loading
+50 −16
Original line number Diff line number Diff line
@@ -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);
	}

	mgmt &= ~SM_SW_FWD_MODE;

	if (enable) {
		vc0 |= VC0_VLAN_EN | VC0_VID_CHK_EN | VC0_VID_HASH_VID;
		vc1 |= VC1_RX_MCST_UNTAG_EN | VC1_RX_MCST_FWD_EN;
@@ -573,9 +571,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;

@@ -595,6 +592,22 @@ void b53_brcm_hdr_setup(struct dsa_switch *ds, int port)
		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 */
	b53_read8(dev, B53_MGMT_PAGE, B53_BRCM_HDR, &hdr_ctl);
	if (tag_en)
@@ -1866,36 +1879,57 @@ static bool b53_possible_cpu_port(struct dsa_switch *ds, int port)
	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);

	if (!ret)
	if (!ret) {
		dev_warn(ds->dev, "Port %d is not Broadcom tag capable\n",
			 port);
		return ret;
	}

enum dsa_tag_protocol b53_get_tag_protocol(struct dsa_switch *ds, int port)
	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;
}

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;

	/* 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
	 * mode to be turned on which means we need to specifically manage ARL
	 * misses on multicast addresses (TBD).
	 * not support in net/dsa/tag_brcm.c yet.
	 */
	if (is5325(dev) || is5365(dev) || is539x(dev) || is531x5(dev) ||
	    !b53_can_enable_brcm_tags(ds, port))
		return DSA_TAG_PROTO_NONE;
	if (is5325(dev) || is5365(dev) ||
	    !b53_can_enable_brcm_tags(ds, port, mprot)) {
		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);

+3 −1
Original line number Diff line number Diff line
@@ -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);
+2 −1
Original line number Diff line number Diff line
@@ -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);

+2 −1
Original line number Diff line number Diff line
@@ -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;
}
+2 −1
Original line number Diff line number Diff line
@@ -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;
}
Loading