Commit 6c8607eb authored by David S. Miller's avatar David S. Miller

Merge branch 'dsa-add-cross-chip-VLAN-support'

Vivien Didelot says:

====================
net: dsa: add cross-chip VLAN support

The current code in DSA does not support cross-chip VLAN. This means
that in a multi-chip environment such as this one (similar to ZII Rev B)

         [CPU].................... (mdio)
    (eth0) |   :       :          :
          _|_____    _______    _______
         [__sw0__]--[__sw1__]--[__sw2__]
          |  |  |    |  |  |    |  |  |
          v  v  v    v  v  v    v  v  v
          p1 p2 p3   p4 p5 p6   p7 p8 p9

adding a VLAN to p9 won't be enough to reach the CPU, until at least one
port of sw0 and sw1 join the VLAN as well and become aware of the VID.

This patchset makes the DSA core program the VLAN on the CPU and DSA
links itself, which brings seamlessly cross-chip VLAN support to DSA.

With this series applied*, the hardware VLAN tables of a 3-switch setup
look like this after adding a VLAN to only one port of the end switch:

    # cat /sys/class/net/br0/bridge/default_pvid
    42
    # cat /sys/kernel/debug/mv88e6xxx/sw{0,1,2}/vtu
    # ip link set up master br0 dev lan6
    # cat /sys/kernel/debug/mv88e6xxx/sw{0,1,2}/vtu
     VID  FID  SID  0  1  2  3  4  5  6
      42    1    0  x  x  x  x  x  =  =
     VID  FID  SID  0  1  2  3  4  5  6
      42    1    0  x  x  x  x  x  =  =
     VID  FID  SID  0  1  2  3  4  5  6  7  8  9
      42    1    0  u  x  x  x  x  x  x  x  x  =

('x' is excluded, 'u' is untagged, '=' is unmodified DSA and CPU ports.)

Completely removing a VLAN entry (which is currently the responsibility
of drivers anyway) is not supported yet since it requires some caching.

(*) the output is shown from this out-of-tree debugfs patch:
https://github.com/vivien/linux/commit/7b61a684b9d6b6a499135a587c7f62a1fddceb8b.patch

Changes in v2:
  - canonical incrementation (port++ instead of ++port)
  - check CPU and DSA ports before purging a VLAN
  - add Reviewed-by tags
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 7eca9cc5 adc3a9ce
......@@ -1159,11 +1159,10 @@ static int mv88e6xxx_vtu_get(struct mv88e6xxx_chip *chip, u16 vid,
entry->valid = true;
entry->vid = vid;
/* Include only CPU and DSA ports */
/* Exclude all ports */
for (i = 0; i < mv88e6xxx_num_ports(chip); ++i)
entry->member[i] = dsa_is_normal_port(chip->ds, i) ?
GLOBAL_VTU_DATA_MEMBER_TAG_NON_MEMBER :
GLOBAL_VTU_DATA_MEMBER_TAG_UNMODIFIED;
entry->member[i] =
GLOBAL_VTU_DATA_MEMBER_TAG_NON_MEMBER;
return mv88e6xxx_atu_new(chip, &entry->fid);
}
......@@ -1274,7 +1273,7 @@ mv88e6xxx_port_vlan_prepare(struct dsa_switch *ds, int port,
}
static int _mv88e6xxx_port_vlan_add(struct mv88e6xxx_chip *chip, int port,
u16 vid, bool untagged)
u16 vid, u8 member)
{
struct mv88e6xxx_vtu_entry vlan;
int err;
......@@ -1283,9 +1282,7 @@ static int _mv88e6xxx_port_vlan_add(struct mv88e6xxx_chip *chip, int port,
if (err)
return err;
vlan.member[port] = untagged ?
GLOBAL_VTU_DATA_MEMBER_TAG_UNTAGGED :
GLOBAL_VTU_DATA_MEMBER_TAG_TAGGED;
vlan.member[port] = member;
return mv88e6xxx_vtu_loadpurge(chip, &vlan);
}
......@@ -1297,15 +1294,23 @@ static void mv88e6xxx_port_vlan_add(struct dsa_switch *ds, int port,
struct mv88e6xxx_chip *chip = ds->priv;
bool untagged = vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED;
bool pvid = vlan->flags & BRIDGE_VLAN_INFO_PVID;
u8 member;
u16 vid;
if (!chip->info->max_vid)
return;
if (dsa_is_dsa_port(ds, port) || dsa_is_cpu_port(ds, port))
member = GLOBAL_VTU_DATA_MEMBER_TAG_UNMODIFIED;
else if (untagged)
member = GLOBAL_VTU_DATA_MEMBER_TAG_UNTAGGED;
else
member = GLOBAL_VTU_DATA_MEMBER_TAG_TAGGED;
mutex_lock(&chip->reg_lock);
for (vid = vlan->vid_begin; vid <= vlan->vid_end; ++vid)
if (_mv88e6xxx_port_vlan_add(chip, port, vid, untagged))
if (_mv88e6xxx_port_vlan_add(chip, port, vid, member))
netdev_err(ds->ports[port].netdev,
"failed to add VLAN %d%c\n",
vid, untagged ? 'u' : 't');
......@@ -1320,7 +1325,6 @@ static void mv88e6xxx_port_vlan_add(struct dsa_switch *ds, int port,
static int _mv88e6xxx_port_vlan_del(struct mv88e6xxx_chip *chip,
int port, u16 vid)
{
struct dsa_switch *ds = chip->ds;
struct mv88e6xxx_vtu_entry vlan;
int i, err;
......@@ -1337,9 +1341,6 @@ static int _mv88e6xxx_port_vlan_del(struct mv88e6xxx_chip *chip,
/* keep the VLAN unless all ports are excluded */
vlan.valid = false;
for (i = 0; i < mv88e6xxx_num_ports(chip); ++i) {
if (dsa_is_cpu_port(ds, i) || dsa_is_dsa_port(ds, i))
continue;
if (vlan.member[i] != GLOBAL_VTU_DATA_MEMBER_TAG_NON_MEMBER) {
vlan.valid = true;
break;
......
......@@ -159,19 +159,30 @@ static int dsa_switch_vlan_add(struct dsa_switch *ds,
{
const struct switchdev_obj_port_vlan *vlan = info->vlan;
struct switchdev_trans *trans = info->trans;
DECLARE_BITMAP(members, ds->num_ports);
int port, err;
/* Do not care yet about other switch chips of the fabric */
if (ds->index != info->sw_index)
return 0;
/* Build a mask of VLAN members */
bitmap_zero(members, ds->num_ports);
if (ds->index == info->sw_index)
set_bit(info->port, members);
for (port = 0; port < ds->num_ports; port++)
if (dsa_is_cpu_port(ds, port) || dsa_is_dsa_port(ds, port))
set_bit(port, members);
if (switchdev_trans_ph_prepare(trans)) {
if (!ds->ops->port_vlan_prepare || !ds->ops->port_vlan_add)
return -EOPNOTSUPP;
return ds->ops->port_vlan_prepare(ds, info->port, vlan, trans);
for_each_set_bit(port, members, ds->num_ports) {
err = ds->ops->port_vlan_prepare(ds, port, vlan, trans);
if (err)
return err;
}
}
ds->ops->port_vlan_add(ds, info->port, vlan, trans);
for_each_set_bit(port, members, ds->num_ports)
ds->ops->port_vlan_add(ds, port, vlan, trans);
return 0;
}
......@@ -181,14 +192,13 @@ static int dsa_switch_vlan_del(struct dsa_switch *ds,
{
const struct switchdev_obj_port_vlan *vlan = info->vlan;
/* Do not care yet about other switch chips of the fabric */
if (ds->index != info->sw_index)
return 0;
if (!ds->ops->port_vlan_del)
return -EOPNOTSUPP;
return ds->ops->port_vlan_del(ds, info->port, vlan);
if (ds->index == info->sw_index)
return ds->ops->port_vlan_del(ds, info->port, vlan);
return 0;
}
static int dsa_switch_event(struct notifier_block *nb,
......
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