Skip to content

Commit

Permalink
net: dsa: mv88e6xxx: check hardware VLAN in use
Browse files Browse the repository at this point in the history
The DSA drivers now have access to the VLAN prepare phase and the bridge
net_device. It is easier to check for overlapping bridges from within
the driver. Thus add such check in mv88e6xxx_port_vlan_prepare.

Signed-off-by: Vivien Didelot <vivien.didelot@savoirfairelinux.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Vivien Didelot authored and David S. Miller committed Feb 23, 2016
1 parent a669275 commit da9c359
Showing 1 changed file with 64 additions and 0 deletions.
64 changes: 64 additions & 0 deletions drivers/net/dsa/mv88e6xxx.c
Original file line number Diff line number Diff line change
Expand Up @@ -1471,14 +1471,78 @@ static int _mv88e6xxx_vlan_init(struct dsa_switch *ds, u16 vid,
return 0;
}

static int mv88e6xxx_port_check_hw_vlan(struct dsa_switch *ds, int port,
u16 vid_begin, u16 vid_end)
{
struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
struct mv88e6xxx_vtu_stu_entry vlan;
int i, err;

if (!vid_begin)
return -EOPNOTSUPP;

mutex_lock(&ps->smi_mutex);

err = _mv88e6xxx_vtu_vid_write(ds, vid_begin - 1);
if (err)
goto unlock;

do {
err = _mv88e6xxx_vtu_getnext(ds, &vlan);
if (err)
goto unlock;

if (!vlan.valid)
break;

if (vlan.vid > vid_end)
break;

for (i = 0; i < ps->num_ports; ++i) {
if (dsa_is_dsa_port(ds, i) || dsa_is_cpu_port(ds, i))
continue;

if (vlan.data[i] ==
GLOBAL_VTU_DATA_MEMBER_TAG_NON_MEMBER)
continue;

if (ps->ports[i].bridge_dev ==
ps->ports[port].bridge_dev)
break; /* same bridge, check next VLAN */

netdev_warn(ds->ports[port],
"hardware VLAN %d already used by %s\n",
vlan.vid,
netdev_name(ps->ports[i].bridge_dev));
err = -EOPNOTSUPP;
goto unlock;
}
} while (vlan.vid < vid_end);

unlock:
mutex_unlock(&ps->smi_mutex);

return err;
}

int mv88e6xxx_port_vlan_prepare(struct dsa_switch *ds, int port,
const struct switchdev_obj_port_vlan *vlan,
struct switchdev_trans *trans)
{
int err;

/* We reserve a few VLANs to isolate unbridged ports */
if (vlan->vid_end >= 4000)
return -EOPNOTSUPP;

/* If the requested port doesn't belong to the same bridge as the VLAN
* members, do not support it (yet) and fallback to software VLAN.
*/
err = mv88e6xxx_port_check_hw_vlan(ds, port, vlan->vid_begin,
vlan->vid_end);
if (err)
return err;

/* We don't need any dynamic resource from the kernel (yet),
* so skip the prepare phase.
*/
Expand Down

0 comments on commit da9c359

Please sign in to comment.