Commit 36a0bf44 authored by Vladimir Oltean's avatar Vladimir Oltean Committed by Paolo Abeni

net: mscc: ocelot: set up tag_8021q CPU ports independent of user port affinity

This is a partial revert of commit c295f983 ("net: mscc: ocelot:
switch from {,un}set to {,un}assign for tag_8021q CPU ports"), because
as it turns out, this isn't how tag_8021q CPU ports under a LAG are
supposed to work.

Under that scenario, all user ports are "assigned" to the single
tag_8021q CPU port represented by the logical port corresponding to the
bonding interface. So one CPU port in a LAG would have is_dsa_8021q_cpu
set to true (the one whose physical port ID is equal to the logical port
ID), and the other one to false.

In turn, this makes 2 undesirable things happen:

(1) PGID_CPU contains only the first physical CPU port, rather than both
(2) only the first CPU port will be added to the private VLANs used by
    ocelot for VLAN-unaware bridging

To make the driver behave in the same way for both bonded CPU ports, we
need to bring back the old concept of setting up a port as a tag_8021q
CPU port, and this is what deals with VLAN membership and PGID_CPU
updating. But we also need the CPU port "assignment" (the user to CPU
port affinity), and this is what updates the PGID_SRC forwarding rules.

All DSA CPU ports are statically configured for tag_8021q mode when the
tagging protocol is changed to ocelot-8021q. User ports are "assigned"
to one CPU port or the other dynamically (this will be handled by a
future change).
Signed-off-by: default avatarVladimir Oltean <vladimir.oltean@nxp.com>
Signed-off-by: default avatarPaolo Abeni <pabeni@redhat.com>
parent 5dc760d1
...@@ -445,6 +445,9 @@ static int felix_tag_8021q_setup(struct dsa_switch *ds) ...@@ -445,6 +445,9 @@ static int felix_tag_8021q_setup(struct dsa_switch *ds)
if (err) if (err)
return err; return err;
dsa_switch_for_each_cpu_port(dp, ds)
ocelot_port_setup_dsa_8021q_cpu(ocelot, dp->index);
dsa_switch_for_each_user_port(dp, ds) dsa_switch_for_each_user_port(dp, ds)
ocelot_port_assign_dsa_8021q_cpu(ocelot, dp->index, ocelot_port_assign_dsa_8021q_cpu(ocelot, dp->index,
dp->cpu_dp->index); dp->cpu_dp->index);
...@@ -493,6 +496,9 @@ static void felix_tag_8021q_teardown(struct dsa_switch *ds) ...@@ -493,6 +496,9 @@ static void felix_tag_8021q_teardown(struct dsa_switch *ds)
dsa_switch_for_each_user_port(dp, ds) dsa_switch_for_each_user_port(dp, ds)
ocelot_port_unassign_dsa_8021q_cpu(ocelot, dp->index); ocelot_port_unassign_dsa_8021q_cpu(ocelot, dp->index);
dsa_switch_for_each_cpu_port(dp, ds)
ocelot_port_teardown_dsa_8021q_cpu(ocelot, dp->index);
dsa_tag_8021q_unregister(ds); dsa_tag_8021q_unregister(ds);
} }
......
...@@ -2214,61 +2214,61 @@ static void ocelot_update_pgid_cpu(struct ocelot *ocelot) ...@@ -2214,61 +2214,61 @@ static void ocelot_update_pgid_cpu(struct ocelot *ocelot)
ocelot_write_rix(ocelot, pgid_cpu, ANA_PGID_PGID, PGID_CPU); ocelot_write_rix(ocelot, pgid_cpu, ANA_PGID_PGID, PGID_CPU);
} }
void ocelot_port_assign_dsa_8021q_cpu(struct ocelot *ocelot, int port, void ocelot_port_setup_dsa_8021q_cpu(struct ocelot *ocelot, int cpu)
int cpu)
{ {
struct ocelot_port *cpu_port = ocelot->ports[cpu]; struct ocelot_port *cpu_port = ocelot->ports[cpu];
u16 vid; u16 vid;
mutex_lock(&ocelot->fwd_domain_lock); mutex_lock(&ocelot->fwd_domain_lock);
ocelot->ports[port]->dsa_8021q_cpu = cpu_port;
if (!cpu_port->is_dsa_8021q_cpu) {
cpu_port->is_dsa_8021q_cpu = true; cpu_port->is_dsa_8021q_cpu = true;
for (vid = OCELOT_RSV_VLAN_RANGE_START; vid < VLAN_N_VID; vid++) for (vid = OCELOT_RSV_VLAN_RANGE_START; vid < VLAN_N_VID; vid++)
ocelot_vlan_member_add(ocelot, cpu, vid, true); ocelot_vlan_member_add(ocelot, cpu, vid, true);
ocelot_update_pgid_cpu(ocelot); ocelot_update_pgid_cpu(ocelot);
}
ocelot_apply_bridge_fwd_mask(ocelot, true);
mutex_unlock(&ocelot->fwd_domain_lock); mutex_unlock(&ocelot->fwd_domain_lock);
} }
EXPORT_SYMBOL_GPL(ocelot_port_assign_dsa_8021q_cpu); EXPORT_SYMBOL_GPL(ocelot_port_setup_dsa_8021q_cpu);
void ocelot_port_unassign_dsa_8021q_cpu(struct ocelot *ocelot, int port) void ocelot_port_teardown_dsa_8021q_cpu(struct ocelot *ocelot, int cpu)
{ {
struct ocelot_port *cpu_port = ocelot->ports[port]->dsa_8021q_cpu; struct ocelot_port *cpu_port = ocelot->ports[cpu];
bool keep = false;
u16 vid; u16 vid;
int p;
mutex_lock(&ocelot->fwd_domain_lock); mutex_lock(&ocelot->fwd_domain_lock);
ocelot->ports[port]->dsa_8021q_cpu = NULL;
for (p = 0; p < ocelot->num_phys_ports; p++) {
if (!ocelot->ports[p])
continue;
if (ocelot->ports[p]->dsa_8021q_cpu == cpu_port) {
keep = true;
break;
}
}
if (!keep) {
cpu_port->is_dsa_8021q_cpu = false; cpu_port->is_dsa_8021q_cpu = false;
for (vid = OCELOT_RSV_VLAN_RANGE_START; vid < VLAN_N_VID; vid++) for (vid = OCELOT_RSV_VLAN_RANGE_START; vid < VLAN_N_VID; vid++)
ocelot_vlan_member_del(ocelot, cpu_port->index, vid); ocelot_vlan_member_del(ocelot, cpu_port->index, vid);
ocelot_update_pgid_cpu(ocelot); ocelot_update_pgid_cpu(ocelot);
}
mutex_unlock(&ocelot->fwd_domain_lock);
}
EXPORT_SYMBOL_GPL(ocelot_port_teardown_dsa_8021q_cpu);
void ocelot_port_assign_dsa_8021q_cpu(struct ocelot *ocelot, int port,
int cpu)
{
struct ocelot_port *cpu_port = ocelot->ports[cpu];
mutex_lock(&ocelot->fwd_domain_lock);
ocelot->ports[port]->dsa_8021q_cpu = cpu_port;
ocelot_apply_bridge_fwd_mask(ocelot, true);
mutex_unlock(&ocelot->fwd_domain_lock);
}
EXPORT_SYMBOL_GPL(ocelot_port_assign_dsa_8021q_cpu);
void ocelot_port_unassign_dsa_8021q_cpu(struct ocelot *ocelot, int port)
{
mutex_lock(&ocelot->fwd_domain_lock);
ocelot->ports[port]->dsa_8021q_cpu = NULL;
ocelot_apply_bridge_fwd_mask(ocelot, true); ocelot_apply_bridge_fwd_mask(ocelot, true);
mutex_unlock(&ocelot->fwd_domain_lock); mutex_unlock(&ocelot->fwd_domain_lock);
......
...@@ -1024,6 +1024,8 @@ void ocelot_deinit(struct ocelot *ocelot); ...@@ -1024,6 +1024,8 @@ void ocelot_deinit(struct ocelot *ocelot);
void ocelot_init_port(struct ocelot *ocelot, int port); void ocelot_init_port(struct ocelot *ocelot, int port);
void ocelot_deinit_port(struct ocelot *ocelot, int port); void ocelot_deinit_port(struct ocelot *ocelot, int port);
void ocelot_port_setup_dsa_8021q_cpu(struct ocelot *ocelot, int cpu);
void ocelot_port_teardown_dsa_8021q_cpu(struct ocelot *ocelot, int cpu);
void ocelot_port_assign_dsa_8021q_cpu(struct ocelot *ocelot, int port, int cpu); void ocelot_port_assign_dsa_8021q_cpu(struct ocelot *ocelot, int port, int cpu);
void ocelot_port_unassign_dsa_8021q_cpu(struct ocelot *ocelot, int port); void ocelot_port_unassign_dsa_8021q_cpu(struct ocelot *ocelot, int port);
u32 ocelot_port_assigned_dsa_8021q_cpu_mask(struct ocelot *ocelot, int port); u32 ocelot_port_assigned_dsa_8021q_cpu_mask(struct ocelot *ocelot, int port);
......
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