Commit 47fac456 authored by Oleksij Rempel's avatar Oleksij Rempel Committed by David S. Miller
Browse files

net: dsa: qca: ar9331: make proper initial port defaults



Make sure that all external port are actually isolated from each other,
so no packets are leaked.

Fixes: ec6698c2 ("net: dsa: add support for Atheros AR9331 built-in switch")
Signed-off-by: default avatarOleksij Rempel <o.rempel@pengutronix.de>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent d992e99b
Loading
Loading
Loading
Loading
+72 −1
Original line number Diff line number Diff line
@@ -101,6 +101,23 @@
	 AR9331_SW_PORT_STATUS_RX_FLOW_EN | AR9331_SW_PORT_STATUS_TX_FLOW_EN | \
	 AR9331_SW_PORT_STATUS_SPEED_M)

#define AR9331_SW_REG_PORT_CTRL(_port)			(0x104 + (_port) * 0x100)
#define AR9331_SW_PORT_CTRL_HEAD_EN			BIT(11)
#define AR9331_SW_PORT_CTRL_PORT_STATE			GENMASK(2, 0)
#define AR9331_SW_PORT_CTRL_PORT_STATE_DISABLED		0
#define AR9331_SW_PORT_CTRL_PORT_STATE_BLOCKING		1
#define AR9331_SW_PORT_CTRL_PORT_STATE_LISTENING	2
#define AR9331_SW_PORT_CTRL_PORT_STATE_LEARNING		3
#define AR9331_SW_PORT_CTRL_PORT_STATE_FORWARD		4

#define AR9331_SW_REG_PORT_VLAN(_port)			(0x108 + (_port) * 0x100)
#define AR9331_SW_PORT_VLAN_8021Q_MODE			GENMASK(31, 30)
#define AR9331_SW_8021Q_MODE_SECURE			3
#define AR9331_SW_8021Q_MODE_CHECK			2
#define AR9331_SW_8021Q_MODE_FALLBACK			1
#define AR9331_SW_8021Q_MODE_NONE			0
#define AR9331_SW_PORT_VLAN_PORT_VID_MEMBER		GENMASK(25, 16)

/* MIB registers */
#define AR9331_MIB_COUNTER(x)			(0x20000 + ((x) * 0x100))

@@ -371,12 +388,60 @@ static int ar9331_sw_mbus_init(struct ar9331_sw_priv *priv)
	return 0;
}

static int ar9331_sw_setup(struct dsa_switch *ds)
static int ar9331_sw_setup_port(struct dsa_switch *ds, int port)
{
	struct ar9331_sw_priv *priv = (struct ar9331_sw_priv *)ds->priv;
	struct regmap *regmap = priv->regmap;
	u32 port_mask, port_ctrl, val;
	int ret;

	/* Generate default port settings */
	port_ctrl = FIELD_PREP(AR9331_SW_PORT_CTRL_PORT_STATE,
			       AR9331_SW_PORT_CTRL_PORT_STATE_FORWARD);

	if (dsa_is_cpu_port(ds, port)) {
		/* CPU port should be allowed to communicate with all user
		 * ports.
		 */
		port_mask = dsa_user_ports(ds);
		/* Enable Atheros header on CPU port. This will allow us
		 * communicate with each port separately
		 */
		port_ctrl |= AR9331_SW_PORT_CTRL_HEAD_EN;
	} else if (dsa_is_user_port(ds, port)) {
		/* User ports should communicate only with the CPU port.
		 */
		port_mask = BIT(dsa_upstream_port(ds, port));
	} else {
		/* Other ports do not need to communicate at all */
		port_mask = 0;
	}

	val = FIELD_PREP(AR9331_SW_PORT_VLAN_8021Q_MODE,
			 AR9331_SW_8021Q_MODE_NONE) |
		FIELD_PREP(AR9331_SW_PORT_VLAN_PORT_VID_MEMBER, port_mask);

	ret = regmap_write(regmap, AR9331_SW_REG_PORT_VLAN(port), val);
	if (ret)
		goto error;

	ret = regmap_write(regmap, AR9331_SW_REG_PORT_CTRL(port), port_ctrl);
	if (ret)
		goto error;

	return 0;
error:
	dev_err(priv->dev, "%s: error: %i\n", __func__, ret);

	return ret;
}

static int ar9331_sw_setup(struct dsa_switch *ds)
{
	struct ar9331_sw_priv *priv = (struct ar9331_sw_priv *)ds->priv;
	struct regmap *regmap = priv->regmap;
	int ret, i;

	ret = ar9331_sw_reset(priv);
	if (ret)
		return ret;
@@ -402,6 +467,12 @@ static int ar9331_sw_setup(struct dsa_switch *ds)
	if (ret)
		goto error;

	for (i = 0; i < ds->num_ports; i++) {
		ret = ar9331_sw_setup_port(ds, i);
		if (ret)
			goto error;
	}

	ds->configure_vlan_while_not_filtering = false;

	return 0;