Skip to content

Commit

Permalink
net: dsa: microchip: ksz8795: Reject unsupported VLAN configuration
Browse files Browse the repository at this point in the history
commit 8f4f58f upstream.

The switches supported by ksz8795 only have a per-port flag for Tag
Removal.  This means it is not possible to support both tagged and
untagged VLANs on the same port.  Reject attempts to add a VLAN that
requires the flag to be changed, unless there are no VLANs currently
configured.

VID 0 is excluded from this check since it is untagged regardless of
the state of the flag.

On the CPU port we could support tagged and untagged VLANs at the same
time.  This will be enabled by a later patch.

Fixes: e66f840 ("net: dsa: ksz: Add Microchip KSZ8795 DSA driver")
Signed-off-by: Ben Hutchings <[email protected]>
Signed-off-by: David S. Miller <[email protected]>
[bwh: Backport to 5.10:
 - This configuration has to be detected and rejected in the
   port_vlan_prepare operation
 - ksz8795_port_vlan_add() has to check again to decide whether to
   change the Tag Removal flag, so put the common condition in a
   separate function
 - Handle VID ranges]
Signed-off-by: Ben Hutchings <[email protected]>
Signed-off-by: Greg Kroah-Hartman <[email protected]>
  • Loading branch information
bwh-mind authored and gregkh committed Aug 18, 2021
1 parent 60c007b commit 5033d5e
Show file tree
Hide file tree
Showing 2 changed files with 54 additions and 2 deletions.
55 changes: 53 additions & 2 deletions drivers/net/dsa/microchip/ksz8795.c
Original file line number Diff line number Diff line change
Expand Up @@ -801,15 +801,66 @@ static int ksz8795_port_vlan_filtering(struct dsa_switch *ds, int port,
return 0;
}

static bool ksz8795_port_vlan_changes_remove_tag(
struct dsa_switch *ds, int port,
const struct switchdev_obj_port_vlan *vlan)
{
bool untagged = vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED;
struct ksz_device *dev = ds->priv;
struct ksz_port *p = &dev->ports[port];

/* If a VLAN is added with untagged flag different from the
* port's Remove Tag flag, we need to change the latter.
* Ignore VID 0, which is always untagged.
*/
return untagged != p->remove_tag &&
!(vlan->vid_begin == 0 && vlan->vid_end == 0);
}

int ksz8795_port_vlan_prepare(struct dsa_switch *ds, int port,
const struct switchdev_obj_port_vlan *vlan)
{
struct ksz_device *dev = ds->priv;

/* Reject attempts to add a VLAN that requires the Remove Tag
* flag to be changed, unless there are no other VLANs
* currently configured.
*/
if (ksz8795_port_vlan_changes_remove_tag(ds, port, vlan)) {
unsigned int vid;

for (vid = 1; vid < dev->num_vlans; ++vid) {
u8 fid, member, valid;

/* Skip the VIDs we are going to add or reconfigure */
if (vid == vlan->vid_begin) {
vid = vlan->vid_end;
continue;
}

ksz8795_from_vlan(dev->vlan_cache[vid].table[0],
&fid, &member, &valid);
if (valid && (member & BIT(port)))
return -EINVAL;
}
}

return ksz_port_vlan_prepare(ds, port, vlan);
}

static void ksz8795_port_vlan_add(struct dsa_switch *ds, int port,
const struct switchdev_obj_port_vlan *vlan)
{
bool untagged = vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED;
struct ksz_device *dev = ds->priv;
struct ksz_port *p = &dev->ports[port];
u16 data, vid, new_pvid = 0;
u8 fid, member, valid;

ksz_port_cfg(dev, port, P_TAG_CTRL, PORT_REMOVE_TAG, untagged);
if (ksz8795_port_vlan_changes_remove_tag(ds, port, vlan)) {
ksz_port_cfg(dev, port, P_TAG_CTRL, PORT_REMOVE_TAG, untagged);
p->remove_tag = untagged;
}

for (vid = vlan->vid_begin; vid <= vlan->vid_end; vid++) {
ksz8795_r_vlan_table(dev, vid, &data);
Expand Down Expand Up @@ -1128,7 +1179,7 @@ static const struct dsa_switch_ops ksz8795_switch_ops = {
.port_stp_state_set = ksz8795_port_stp_state_set,
.port_fast_age = ksz_port_fast_age,
.port_vlan_filtering = ksz8795_port_vlan_filtering,
.port_vlan_prepare = ksz_port_vlan_prepare,
.port_vlan_prepare = ksz8795_port_vlan_prepare,
.port_vlan_add = ksz8795_port_vlan_add,
.port_vlan_del = ksz8795_port_vlan_del,
.port_fdb_dump = ksz_port_fdb_dump,
Expand Down
1 change: 1 addition & 0 deletions drivers/net/dsa/microchip/ksz_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ struct ksz_port_mib {
struct ksz_port {
u16 member;
u16 vid_member;
bool remove_tag; /* Remove Tag flag set, for ksz8795 only */
int stp_state;
struct phy_device phydev;

Expand Down

0 comments on commit 5033d5e

Please sign in to comment.