Skip to content

Commit

Permalink
net: dsa: qca: ar9331: make proper initial port defaults
Browse files Browse the repository at this point in the history
Make sure that all external port are actually isolated from each other,
so no packets are leaked.

Fixes: ec6698c ("net: dsa: add support for Atheros AR9331 built-in switch")
Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
olerem authored and davem330 committed Aug 7, 2021
1 parent d992e99 commit 47fac45
Showing 1 changed file with 72 additions and 1 deletion.
73 changes: 72 additions & 1 deletion drivers/net/dsa/qca/ar9331.c
Original file line number Diff line number Diff line change
Expand Up @@ -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))

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

0 comments on commit 47fac45

Please sign in to comment.