Commit 6505782c authored by David S. Miller's avatar David S. Miller

Merge branch 'ocelot-vlan'

Vladimir Oltean says:

====================
Small ocelot VLAN improvements

This small series propagates some VLAN restrictions via netlink extack
and creates some helper functions instead of open-coding VLAN table
manipulations from multiple places.

This is split from the larger "DSA FDB isolation" series, hence the v2
tag:
https://patchwork.kernel.org/project/netdevbpf/cover/20210818120150.892647-1-vladimir.oltean@nxp.com/
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents f2aea90d bbf6a2d9
...@@ -742,7 +742,8 @@ static int felix_lag_change(struct dsa_switch *ds, int port) ...@@ -742,7 +742,8 @@ static int felix_lag_change(struct dsa_switch *ds, int port)
} }
static int felix_vlan_prepare(struct dsa_switch *ds, int port, static int felix_vlan_prepare(struct dsa_switch *ds, int port,
const struct switchdev_obj_port_vlan *vlan) const struct switchdev_obj_port_vlan *vlan,
struct netlink_ext_ack *extack)
{ {
struct ocelot *ocelot = ds->priv; struct ocelot *ocelot = ds->priv;
u16 flags = vlan->flags; u16 flags = vlan->flags;
...@@ -760,7 +761,8 @@ static int felix_vlan_prepare(struct dsa_switch *ds, int port, ...@@ -760,7 +761,8 @@ static int felix_vlan_prepare(struct dsa_switch *ds, int port,
return ocelot_vlan_prepare(ocelot, port, vlan->vid, return ocelot_vlan_prepare(ocelot, port, vlan->vid,
flags & BRIDGE_VLAN_INFO_PVID, flags & BRIDGE_VLAN_INFO_PVID,
flags & BRIDGE_VLAN_INFO_UNTAGGED); flags & BRIDGE_VLAN_INFO_UNTAGGED,
extack);
} }
static int felix_vlan_filtering(struct dsa_switch *ds, int port, bool enabled, static int felix_vlan_filtering(struct dsa_switch *ds, int port, bool enabled,
...@@ -768,7 +770,7 @@ static int felix_vlan_filtering(struct dsa_switch *ds, int port, bool enabled, ...@@ -768,7 +770,7 @@ static int felix_vlan_filtering(struct dsa_switch *ds, int port, bool enabled,
{ {
struct ocelot *ocelot = ds->priv; struct ocelot *ocelot = ds->priv;
return ocelot_port_vlan_filtering(ocelot, port, enabled); return ocelot_port_vlan_filtering(ocelot, port, enabled, extack);
} }
static int felix_vlan_add(struct dsa_switch *ds, int port, static int felix_vlan_add(struct dsa_switch *ds, int port,
...@@ -779,7 +781,7 @@ static int felix_vlan_add(struct dsa_switch *ds, int port, ...@@ -779,7 +781,7 @@ static int felix_vlan_add(struct dsa_switch *ds, int port,
u16 flags = vlan->flags; u16 flags = vlan->flags;
int err; int err;
err = felix_vlan_prepare(ds, port, vlan); err = felix_vlan_prepare(ds, port, vlan, extack);
if (err) if (err)
return err; return err;
......
...@@ -222,8 +222,35 @@ static void ocelot_port_set_pvid(struct ocelot *ocelot, int port, ...@@ -222,8 +222,35 @@ static void ocelot_port_set_pvid(struct ocelot *ocelot, int port,
ANA_PORT_DROP_CFG, port); ANA_PORT_DROP_CFG, port);
} }
static int ocelot_vlan_member_set(struct ocelot *ocelot, u32 vlan_mask, u16 vid)
{
int err;
err = ocelot_vlant_set_mask(ocelot, vid, vlan_mask);
if (err)
return err;
ocelot->vlan_mask[vid] = vlan_mask;
return 0;
}
static int ocelot_vlan_member_add(struct ocelot *ocelot, int port, u16 vid)
{
return ocelot_vlan_member_set(ocelot,
ocelot->vlan_mask[vid] | BIT(port),
vid);
}
static int ocelot_vlan_member_del(struct ocelot *ocelot, int port, u16 vid)
{
return ocelot_vlan_member_set(ocelot,
ocelot->vlan_mask[vid] & ~BIT(port),
vid);
}
int ocelot_port_vlan_filtering(struct ocelot *ocelot, int port, int ocelot_port_vlan_filtering(struct ocelot *ocelot, int port,
bool vlan_aware) bool vlan_aware, struct netlink_ext_ack *extack)
{ {
struct ocelot_vcap_block *block = &ocelot->block[VCAP_IS1]; struct ocelot_vcap_block *block = &ocelot->block[VCAP_IS1];
struct ocelot_port *ocelot_port = ocelot->ports[port]; struct ocelot_port *ocelot_port = ocelot->ports[port];
...@@ -233,8 +260,8 @@ int ocelot_port_vlan_filtering(struct ocelot *ocelot, int port, ...@@ -233,8 +260,8 @@ int ocelot_port_vlan_filtering(struct ocelot *ocelot, int port,
list_for_each_entry(filter, &block->rules, list) { list_for_each_entry(filter, &block->rules, list) {
if (filter->ingress_port_mask & BIT(port) && if (filter->ingress_port_mask & BIT(port) &&
filter->action.vid_replace_ena) { filter->action.vid_replace_ena) {
dev_err(ocelot->dev, NL_SET_ERR_MSG_MOD(extack,
"Cannot change VLAN state with vlan modify rules active\n"); "Cannot change VLAN state with vlan modify rules active");
return -EBUSY; return -EBUSY;
} }
} }
...@@ -259,16 +286,15 @@ int ocelot_port_vlan_filtering(struct ocelot *ocelot, int port, ...@@ -259,16 +286,15 @@ int ocelot_port_vlan_filtering(struct ocelot *ocelot, int port,
EXPORT_SYMBOL(ocelot_port_vlan_filtering); EXPORT_SYMBOL(ocelot_port_vlan_filtering);
int ocelot_vlan_prepare(struct ocelot *ocelot, int port, u16 vid, bool pvid, int ocelot_vlan_prepare(struct ocelot *ocelot, int port, u16 vid, bool pvid,
bool untagged) bool untagged, struct netlink_ext_ack *extack)
{ {
struct ocelot_port *ocelot_port = ocelot->ports[port]; struct ocelot_port *ocelot_port = ocelot->ports[port];
/* Deny changing the native VLAN, but always permit deleting it */ /* Deny changing the native VLAN, but always permit deleting it */
if (untagged && ocelot_port->native_vlan.vid != vid && if (untagged && ocelot_port->native_vlan.vid != vid &&
ocelot_port->native_vlan.valid) { ocelot_port->native_vlan.valid) {
dev_err(ocelot->dev, NL_SET_ERR_MSG_MOD(extack,
"Port already has a native VLAN: %d\n", "Port already has a native VLAN");
ocelot_port->native_vlan.vid);
return -EBUSY; return -EBUSY;
} }
...@@ -279,13 +305,11 @@ EXPORT_SYMBOL(ocelot_vlan_prepare); ...@@ -279,13 +305,11 @@ EXPORT_SYMBOL(ocelot_vlan_prepare);
int ocelot_vlan_add(struct ocelot *ocelot, int port, u16 vid, bool pvid, int ocelot_vlan_add(struct ocelot *ocelot, int port, u16 vid, bool pvid,
bool untagged) bool untagged)
{ {
int ret; int err;
/* Make the port a member of the VLAN */ err = ocelot_vlan_member_add(ocelot, port, vid);
ocelot->vlan_mask[vid] |= BIT(port); if (err)
ret = ocelot_vlant_set_mask(ocelot, vid, ocelot->vlan_mask[vid]); return err;
if (ret)
return ret;
/* Default ingress vlan classification */ /* Default ingress vlan classification */
if (pvid) { if (pvid) {
...@@ -312,13 +336,11 @@ EXPORT_SYMBOL(ocelot_vlan_add); ...@@ -312,13 +336,11 @@ EXPORT_SYMBOL(ocelot_vlan_add);
int ocelot_vlan_del(struct ocelot *ocelot, int port, u16 vid) int ocelot_vlan_del(struct ocelot *ocelot, int port, u16 vid)
{ {
struct ocelot_port *ocelot_port = ocelot->ports[port]; struct ocelot_port *ocelot_port = ocelot->ports[port];
int ret; int err;
/* Stop the port from being a member of the vlan */ err = ocelot_vlan_member_del(ocelot, port, vid);
ocelot->vlan_mask[vid] &= ~BIT(port); if (err)
ret = ocelot_vlant_set_mask(ocelot, vid, ocelot->vlan_mask[vid]); return err;
if (ret)
return ret;
/* Ingress */ /* Ingress */
if (ocelot_port->pvid_vlan.vid == vid) { if (ocelot_port->pvid_vlan.vid == vid) {
...@@ -340,6 +362,7 @@ EXPORT_SYMBOL(ocelot_vlan_del); ...@@ -340,6 +362,7 @@ EXPORT_SYMBOL(ocelot_vlan_del);
static void ocelot_vlan_init(struct ocelot *ocelot) static void ocelot_vlan_init(struct ocelot *ocelot)
{ {
unsigned long all_ports = GENMASK(ocelot->num_phys_ports - 1, 0);
u16 port, vid; u16 port, vid;
/* Clear VLAN table, by default all ports are members of all VLANs */ /* Clear VLAN table, by default all ports are members of all VLANs */
...@@ -348,23 +371,19 @@ static void ocelot_vlan_init(struct ocelot *ocelot) ...@@ -348,23 +371,19 @@ static void ocelot_vlan_init(struct ocelot *ocelot)
ocelot_vlant_wait_for_completion(ocelot); ocelot_vlant_wait_for_completion(ocelot);
/* Configure the port VLAN memberships */ /* Configure the port VLAN memberships */
for (vid = 1; vid < VLAN_N_VID; vid++) { for (vid = 1; vid < VLAN_N_VID; vid++)
ocelot->vlan_mask[vid] = 0; ocelot_vlan_member_set(ocelot, 0, vid);
ocelot_vlant_set_mask(ocelot, vid, ocelot->vlan_mask[vid]);
}
/* Because VLAN filtering is enabled, we need VID 0 to get untagged /* Because VLAN filtering is enabled, we need VID 0 to get untagged
* traffic. It is added automatically if 8021q module is loaded, but * traffic. It is added automatically if 8021q module is loaded, but
* we can't rely on it since module may be not loaded. * we can't rely on it since module may be not loaded.
*/ */
ocelot->vlan_mask[0] = GENMASK(ocelot->num_phys_ports - 1, 0); ocelot_vlan_member_set(ocelot, all_ports, 0);
ocelot_vlant_set_mask(ocelot, 0, ocelot->vlan_mask[0]);
/* Set vlan ingress filter mask to all ports but the CPU port by /* Set vlan ingress filter mask to all ports but the CPU port by
* default. * default.
*/ */
ocelot_write(ocelot, GENMASK(ocelot->num_phys_ports - 1, 0), ocelot_write(ocelot, all_ports, ANA_VLANMASK);
ANA_VLANMASK);
for (port = 0; port < ocelot->num_phys_ports; port++) { for (port = 0; port < ocelot->num_phys_ports; port++) {
ocelot_write_gix(ocelot, 0, REW_PORT_VLAN_CFG, port); ocelot_write_gix(ocelot, 0, REW_PORT_VLAN_CFG, port);
......
...@@ -386,17 +386,6 @@ static int ocelot_setup_tc(struct net_device *dev, enum tc_setup_type type, ...@@ -386,17 +386,6 @@ static int ocelot_setup_tc(struct net_device *dev, enum tc_setup_type type,
return 0; return 0;
} }
static int ocelot_vlan_vid_prepare(struct net_device *dev, u16 vid, bool pvid,
bool untagged)
{
struct ocelot_port_private *priv = netdev_priv(dev);
struct ocelot_port *ocelot_port = &priv->port;
struct ocelot *ocelot = ocelot_port->ocelot;
int port = priv->chip_port;
return ocelot_vlan_prepare(ocelot, port, vid, pvid, untagged);
}
static int ocelot_vlan_vid_add(struct net_device *dev, u16 vid, bool pvid, static int ocelot_vlan_vid_add(struct net_device *dev, u16 vid, bool pvid,
bool untagged) bool untagged)
{ {
...@@ -924,7 +913,8 @@ static int ocelot_port_attr_set(struct net_device *dev, const void *ctx, ...@@ -924,7 +913,8 @@ static int ocelot_port_attr_set(struct net_device *dev, const void *ctx,
ocelot_port_attr_ageing_set(ocelot, port, attr->u.ageing_time); ocelot_port_attr_ageing_set(ocelot, port, attr->u.ageing_time);
break; break;
case SWITCHDEV_ATTR_ID_BRIDGE_VLAN_FILTERING: case SWITCHDEV_ATTR_ID_BRIDGE_VLAN_FILTERING:
ocelot_port_vlan_filtering(ocelot, port, attr->u.vlan_filtering); ocelot_port_vlan_filtering(ocelot, port, attr->u.vlan_filtering,
extack);
break; break;
case SWITCHDEV_ATTR_ID_BRIDGE_MC_DISABLED: case SWITCHDEV_ATTR_ID_BRIDGE_MC_DISABLED:
ocelot_port_attr_mc_set(ocelot, port, !attr->u.mc_disabled); ocelot_port_attr_mc_set(ocelot, port, !attr->u.mc_disabled);
...@@ -944,14 +934,26 @@ static int ocelot_port_attr_set(struct net_device *dev, const void *ctx, ...@@ -944,14 +934,26 @@ static int ocelot_port_attr_set(struct net_device *dev, const void *ctx,
return err; return err;
} }
static int ocelot_vlan_vid_prepare(struct net_device *dev, u16 vid, bool pvid,
bool untagged, struct netlink_ext_ack *extack)
{
struct ocelot_port_private *priv = netdev_priv(dev);
struct ocelot_port *ocelot_port = &priv->port;
struct ocelot *ocelot = ocelot_port->ocelot;
int port = priv->chip_port;
return ocelot_vlan_prepare(ocelot, port, vid, pvid, untagged, extack);
}
static int ocelot_port_obj_add_vlan(struct net_device *dev, static int ocelot_port_obj_add_vlan(struct net_device *dev,
const struct switchdev_obj_port_vlan *vlan) const struct switchdev_obj_port_vlan *vlan,
struct netlink_ext_ack *extack)
{ {
bool untagged = vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED; bool untagged = vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED;
bool pvid = vlan->flags & BRIDGE_VLAN_INFO_PVID; bool pvid = vlan->flags & BRIDGE_VLAN_INFO_PVID;
int ret; int ret;
ret = ocelot_vlan_vid_prepare(dev, vlan->vid, pvid, untagged); ret = ocelot_vlan_vid_prepare(dev, vlan->vid, pvid, untagged, extack);
if (ret) if (ret)
return ret; return ret;
...@@ -1039,7 +1041,8 @@ static int ocelot_port_obj_add(struct net_device *dev, const void *ctx, ...@@ -1039,7 +1041,8 @@ static int ocelot_port_obj_add(struct net_device *dev, const void *ctx,
switch (obj->id) { switch (obj->id) {
case SWITCHDEV_OBJ_ID_PORT_VLAN: case SWITCHDEV_OBJ_ID_PORT_VLAN:
ret = ocelot_port_obj_add_vlan(dev, ret = ocelot_port_obj_add_vlan(dev,
SWITCHDEV_OBJ_PORT_VLAN(obj)); SWITCHDEV_OBJ_PORT_VLAN(obj),
extack);
break; break;
case SWITCHDEV_OBJ_ID_PORT_MDB: case SWITCHDEV_OBJ_ID_PORT_MDB:
ret = ocelot_port_obj_add_mdb(dev, SWITCHDEV_OBJ_PORT_MDB(obj)); ret = ocelot_port_obj_add_mdb(dev, SWITCHDEV_OBJ_PORT_MDB(obj));
...@@ -1131,14 +1134,15 @@ static int ocelot_switchdev_sync(struct ocelot *ocelot, int port, ...@@ -1131,14 +1134,15 @@ static int ocelot_switchdev_sync(struct ocelot *ocelot, int port,
ocelot_port_attr_ageing_set(ocelot, port, ageing_time); ocelot_port_attr_ageing_set(ocelot, port, ageing_time);
return ocelot_port_vlan_filtering(ocelot, port, return ocelot_port_vlan_filtering(ocelot, port,
br_vlan_enabled(bridge_dev)); br_vlan_enabled(bridge_dev),
extack);
} }
static int ocelot_switchdev_unsync(struct ocelot *ocelot, int port) static int ocelot_switchdev_unsync(struct ocelot *ocelot, int port)
{ {
int err; int err;
err = ocelot_port_vlan_filtering(ocelot, port, false); err = ocelot_port_vlan_filtering(ocelot, port, false, NULL);
if (err) if (err)
return err; return err;
......
...@@ -807,7 +807,8 @@ int ocelot_get_sset_count(struct ocelot *ocelot, int port, int sset); ...@@ -807,7 +807,8 @@ int ocelot_get_sset_count(struct ocelot *ocelot, int port, int sset);
int ocelot_get_ts_info(struct ocelot *ocelot, int port, int ocelot_get_ts_info(struct ocelot *ocelot, int port,
struct ethtool_ts_info *info); struct ethtool_ts_info *info);
void ocelot_set_ageing_time(struct ocelot *ocelot, unsigned int msecs); void ocelot_set_ageing_time(struct ocelot *ocelot, unsigned int msecs);
int ocelot_port_vlan_filtering(struct ocelot *ocelot, int port, bool enabled); int ocelot_port_vlan_filtering(struct ocelot *ocelot, int port, bool enabled,
struct netlink_ext_ack *extack);
void ocelot_bridge_stp_state_set(struct ocelot *ocelot, int port, u8 state); void ocelot_bridge_stp_state_set(struct ocelot *ocelot, int port, u8 state);
void ocelot_apply_bridge_fwd_mask(struct ocelot *ocelot); void ocelot_apply_bridge_fwd_mask(struct ocelot *ocelot);
int ocelot_port_pre_bridge_flags(struct ocelot *ocelot, int port, int ocelot_port_pre_bridge_flags(struct ocelot *ocelot, int port,
...@@ -825,7 +826,7 @@ int ocelot_fdb_add(struct ocelot *ocelot, int port, ...@@ -825,7 +826,7 @@ int ocelot_fdb_add(struct ocelot *ocelot, int port,
int ocelot_fdb_del(struct ocelot *ocelot, int port, int ocelot_fdb_del(struct ocelot *ocelot, int port,
const unsigned char *addr, u16 vid); const unsigned char *addr, u16 vid);
int ocelot_vlan_prepare(struct ocelot *ocelot, int port, u16 vid, bool pvid, int ocelot_vlan_prepare(struct ocelot *ocelot, int port, u16 vid, bool pvid,
bool untagged); bool untagged, struct netlink_ext_ack *extack);
int ocelot_vlan_add(struct ocelot *ocelot, int port, u16 vid, bool pvid, int ocelot_vlan_add(struct ocelot *ocelot, int port, u16 vid, bool pvid,
bool untagged); bool untagged);
int ocelot_vlan_del(struct ocelot *ocelot, int port, u16 vid); int ocelot_vlan_del(struct ocelot *ocelot, int port, u16 vid);
......
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