}
EXPORT_SYMBOL(b53_phylink_mac_link_up);
-int b53_vlan_filtering(struct dsa_switch *ds, int port, bool vlan_filtering)
+int b53_vlan_filtering(struct dsa_switch *ds, int port, bool vlan_filtering,
+ struct switchdev_trans *trans)
{
struct b53_device *dev = ds->priv;
+ if (switchdev_trans_ph_prepare(trans))
+ return 0;
+
b53_enable_vlan(dev, dev->vlan_enabled, vlan_filtering);
return 0;
struct phy_device *phydev,
int speed, int duplex,
bool tx_pause, bool rx_pause);
-int b53_vlan_filtering(struct dsa_switch *ds, int port, bool vlan_filtering);
+int b53_vlan_filtering(struct dsa_switch *ds, int port, bool vlan_filtering,
+ struct switchdev_trans *trans);
int b53_vlan_prepare(struct dsa_switch *ds, int port,
const struct switchdev_obj_port_vlan *vlan);
void b53_vlan_add(struct dsa_switch *ds, int port,
}
static int dsa_loop_port_vlan_filtering(struct dsa_switch *ds, int port,
- bool vlan_filtering)
+ bool vlan_filtering,
+ struct switchdev_trans *trans)
{
dev_dbg(ds->dev, "%s: port: %d, vlan_filtering: %d\n",
__func__, port, vlan_filtering);
}
static int gswip_port_vlan_filtering(struct dsa_switch *ds, int port,
- bool vlan_filtering)
+ bool vlan_filtering,
+ struct switchdev_trans *trans)
{
struct gswip_priv *priv = ds->priv;
- struct net_device *bridge = dsa_to_port(ds, port)->bridge_dev;
/* Do not allow changing the VLAN filtering options while in bridge */
- if (!!(priv->port_vlan_filter & BIT(port)) != vlan_filtering && bridge)
- return -EIO;
+ if (switchdev_trans_ph_prepare(trans)) {
+ struct net_device *bridge = dsa_to_port(ds, port)->bridge_dev;
+
+ if (!bridge)
+ return 0;
+
+ if (!!(priv->port_vlan_filter & BIT(port)) != vlan_filtering)
+ return -EIO;
+
+ return 0;
+ }
if (vlan_filtering) {
/* Use port based VLAN tag */
/* disable port fetch/store dma on all ports */
for (i = 0; i < priv->hw_info->max_ports; i++) {
+ struct switchdev_trans trans;
+
+ /* Skip the prepare phase, this shouldn't return an error
+ * during setup.
+ */
+ trans.ph_prepare = false;
+
gswip_port_disable(ds, i);
- gswip_port_vlan_filtering(ds, i, false);
+ gswip_port_vlan_filtering(ds, i, false, &trans);
}
/* enable Switch */
}
static int ksz8795_port_vlan_filtering(struct dsa_switch *ds, int port,
- bool flag)
+ bool flag,
+ struct switchdev_trans *trans)
{
struct ksz_device *dev = ds->priv;
+ if (switchdev_trans_ph_prepare(trans))
+ return 0;
+
ksz_cfg(dev, S_MIRROR_CTRL, SW_VLAN_ENABLE, flag);
return 0;
}
static int ksz9477_port_vlan_filtering(struct dsa_switch *ds, int port,
- bool flag)
+ bool flag,
+ struct switchdev_trans *trans)
{
struct ksz_device *dev = ds->priv;
+ if (switchdev_trans_ph_prepare(trans))
+ return 0;
+
if (flag) {
ksz_port_cfg(dev, port, REG_PORT_LUE_CTRL,
PORT_VLAN_LOOKUP_VID_0, true);
static int
mt7530_port_vlan_filtering(struct dsa_switch *ds, int port,
- bool vlan_filtering)
+ bool vlan_filtering,
+ struct switchdev_trans *trans)
{
+ if (switchdev_trans_ph_prepare(trans))
+ return 0;
+
if (vlan_filtering) {
/* The port is being kept as VLAN-unaware port when bridge is
* set up with vlan_filtering not being set, Otherwise, the
}
static int mv88e6xxx_port_vlan_filtering(struct dsa_switch *ds, int port,
- bool vlan_filtering)
+ bool vlan_filtering,
+ struct switchdev_trans *trans)
{
struct mv88e6xxx_chip *chip = ds->priv;
u16 mode = vlan_filtering ? MV88E6XXX_PORT_CTL2_8021Q_MODE_SECURE :
MV88E6XXX_PORT_CTL2_8021Q_MODE_DISABLED;
int err;
- if (!chip->info->max_vid)
- return -EOPNOTSUPP;
+ if (switchdev_trans_ph_prepare(trans))
+ return chip->info->max_vid ? 0 : -EOPNOTSUPP;
mv88e6xxx_reg_lock(chip);
err = mv88e6xxx_port_set_8021q_mode(chip, port, mode);
return 0;
}
-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,
+ struct switchdev_trans *trans)
{
struct ocelot *ocelot = ds->priv;
- ocelot_port_vlan_filtering(ocelot, port, enabled);
-
- return 0;
+ return ocelot_port_vlan_filtering(ocelot, port, enabled, trans);
}
static void felix_vlan_add(struct dsa_switch *ds, int port,
}
static int
-qca8k_port_vlan_filtering(struct dsa_switch *ds, int port, bool vlan_filtering)
+qca8k_port_vlan_filtering(struct dsa_switch *ds, int port, bool vlan_filtering,
+ struct switchdev_trans *trans)
{
struct qca8k_priv *priv = ds->priv;
+ if (switchdev_trans_ph_prepare(trans))
+ return 0;
+
if (vlan_filtering) {
qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(port),
QCA8K_PORT_LOOKUP_VLAN_MODE,
int rtl8366_reset_vlan(struct realtek_smi *smi);
int rtl8366_init_vlan(struct realtek_smi *smi);
int rtl8366_vlan_filtering(struct dsa_switch *ds, int port,
- bool vlan_filtering);
+ bool vlan_filtering,
+ struct switchdev_trans *trans);
int rtl8366_vlan_prepare(struct dsa_switch *ds, int port,
const struct switchdev_obj_port_vlan *vlan);
void rtl8366_vlan_add(struct dsa_switch *ds, int port,
}
EXPORT_SYMBOL_GPL(rtl8366_init_vlan);
-int rtl8366_vlan_filtering(struct dsa_switch *ds, int port, bool vlan_filtering)
+int rtl8366_vlan_filtering(struct dsa_switch *ds, int port, bool vlan_filtering,
+ struct switchdev_trans *trans)
{
struct realtek_smi *smi = ds->priv;
struct rtl8366_vlan_4k vlan4k;
int ret;
/* Use VLAN nr port + 1 since VLAN0 is not valid */
- if (!smi->ops->is_vlan_valid(smi, port + 1))
- return -EINVAL;
+ if (switchdev_trans_ph_prepare(trans)) {
+ if (!smi->ops->is_vlan_valid(smi, port + 1))
+ return -EINVAL;
+
+ return 0;
+ }
dev_info(smi->dev, "%s filtering on port %d\n",
vlan_filtering ? "enable" : "disable",
int sja1105_static_config_reload(struct sja1105_private *priv,
enum sja1105_reset_reason reason);
-int sja1105_vlan_filtering(struct dsa_switch *ds, int port, bool enabled);
+int sja1105_vlan_filtering(struct dsa_switch *ds, int port, bool enabled,
+ struct switchdev_trans *trans);
void sja1105_frame_memory_partitioning(struct sja1105_private *priv);
/* From sja1105_devlink.c */
rtnl_lock();
for (port = 0; port < ds->num_ports; port++) {
+ struct switchdev_trans trans;
struct dsa_port *dp;
if (!dsa_is_user_port(ds, port))
dp = dsa_to_port(ds, port);
vlan_filtering = dsa_port_is_vlan_filtering(dp);
- rc = sja1105_vlan_filtering(ds, port, vlan_filtering);
+ trans.ph_prepare = true;
+ rc = sja1105_vlan_filtering(ds, port, vlan_filtering, &trans);
+ if (rc)
+ break;
+
+ trans.ph_prepare = false;
+ rc = sja1105_vlan_filtering(ds, port, vlan_filtering, &trans);
if (rc)
break;
}
* which can only be partially reconfigured at runtime (and not the TPID).
* So a switch reset is required.
*/
-int sja1105_vlan_filtering(struct dsa_switch *ds, int port, bool enabled)
+int sja1105_vlan_filtering(struct dsa_switch *ds, int port, bool enabled,
+ struct switchdev_trans *trans)
{
struct sja1105_l2_lookup_params_entry *l2_lookup_params;
struct sja1105_general_params_entry *general_params;
u16 tpid, tpid2;
int rc;
- list_for_each_entry(rule, &priv->flow_block.rules, list) {
- if (rule->type == SJA1105_RULE_VL) {
- dev_err(ds->dev,
- "Cannot change VLAN filtering state while VL rules are active\n");
- return -EBUSY;
+ if (switchdev_trans_ph_prepare(trans)) {
+ list_for_each_entry(rule, &priv->flow_block.rules, list) {
+ if (rule->type == SJA1105_RULE_VL) {
+ dev_err(ds->dev,
+ "Cannot change VLAN filtering with active VL rules\n");
+ return -EBUSY;
+ }
}
+
+ return 0;
}
if (enabled) {
return 0;
}
-void ocelot_port_vlan_filtering(struct ocelot *ocelot, int port,
- bool vlan_aware)
+int ocelot_port_vlan_filtering(struct ocelot *ocelot, int port,
+ bool vlan_aware, struct switchdev_trans *trans)
{
struct ocelot_port *ocelot_port = ocelot->ports[port];
u32 val;
+ if (switchdev_trans_ph_prepare(trans))
+ return 0;
+
ocelot_port->vlan_aware = vlan_aware;
if (vlan_aware)
ANA_PORT_VLAN_CFG, port);
ocelot_port_set_native_vlan(ocelot, port, ocelot_port->vid);
+
+ return 0;
}
EXPORT_SYMBOL(ocelot_port_vlan_filtering);
int ocelot_port_bridge_leave(struct ocelot *ocelot, int port,
struct net_device *bridge)
{
+ struct switchdev_trans trans;
+ int ret;
+
ocelot->bridge_mask &= ~BIT(port);
if (!ocelot->bridge_mask)
ocelot->hw_bridge_dev = NULL;
- ocelot_port_vlan_filtering(ocelot, port, 0);
+ trans.ph_prepare = true;
+ ret = ocelot_port_vlan_filtering(ocelot, port, false, &trans);
+ if (ret)
+ return ret;
+
+ trans.ph_prepare = false;
+ ret = ocelot_port_vlan_filtering(ocelot, port, false, &trans);
+ if (ret)
+ return ret;
+
ocelot_port_set_pvid(ocelot, port, 0);
return ocelot_port_set_native_vlan(ocelot, port, 0);
}
break;
case SWITCHDEV_ATTR_ID_BRIDGE_VLAN_FILTERING:
ocelot_port_vlan_filtering(ocelot, port,
- attr->u.vlan_filtering);
+ attr->u.vlan_filtering, trans);
break;
case SWITCHDEV_ATTR_ID_BRIDGE_MC_DISABLED:
ocelot_port_attr_mc_set(ocelot, port, !attr->u.mc_disabled);
* VLAN support
*/
int (*port_vlan_filtering)(struct dsa_switch *ds, int port,
- bool vlan_filtering);
+ bool vlan_filtering,
+ struct switchdev_trans *trans);
int (*port_vlan_prepare)(struct dsa_switch *ds, int port,
const struct switchdev_obj_port_vlan *vlan);
void (*port_vlan_add)(struct dsa_switch *ds, int port,
void ocelot_set_ageing_time(struct ocelot *ocelot, unsigned int msecs);
void ocelot_adjust_link(struct ocelot *ocelot, int port,
struct phy_device *phydev);
-void ocelot_port_vlan_filtering(struct ocelot *ocelot, int port,
- bool vlan_aware);
+int ocelot_port_vlan_filtering(struct ocelot *ocelot, int port, bool enabled,
+ struct switchdev_trans *trans);
void ocelot_bridge_stp_state_set(struct ocelot *ocelot, int port, u8 state);
int ocelot_port_bridge_join(struct ocelot *ocelot, int port,
struct net_device *bridge);
rcu_read_unlock();
if (!apply)
return -EINVAL;
-
- return 0;
}
if (dsa_port_is_vlan_filtering(dp) == vlan_filtering)
return 0;
- err = ds->ops->port_vlan_filtering(ds, dp->index,
- vlan_filtering);
+ err = ds->ops->port_vlan_filtering(ds, dp->index, vlan_filtering,
+ trans);
if (err)
return err;
- if (ds->vlan_filtering_is_global)
- ds->vlan_filtering = vlan_filtering;
- else
- dp->vlan_filtering = vlan_filtering;
+ if (switchdev_trans_ph_commit(trans)) {
+ if (ds->vlan_filtering_is_global)
+ ds->vlan_filtering = vlan_filtering;
+ else
+ dp->vlan_filtering = vlan_filtering;
+ }
+
return 0;
}
}
}
if (unset_vlan_filtering) {
- struct switchdev_trans trans = {0};
+ struct switchdev_trans trans;
+ trans.ph_prepare = true;
+ err = dsa_port_vlan_filtering(dsa_to_port(ds, info->port),
+ false, &trans);
+ if (err && err != EOPNOTSUPP)
+ return err;
+
+ trans.ph_prepare = false;
err = dsa_port_vlan_filtering(dsa_to_port(ds, info->port),
false, &trans);
if (err && err != EOPNOTSUPP)