net: switchdev: remove the transaction structure from port attributes

Since the introduction of the switchdev API, port attributes were
transmitted to drivers for offloading using a two-step transactional
model, with a prepare phase that was supposed to catch all errors, and a
commit phase that was supposed to never fail.

Some classes of failures can never be avoided, like hardware access, or
memory allocation. In the latter case, merely attempting to move the
memory allocation to the preparation phase makes it impossible to avoid
memory leaks, since commit 91cf8eceff ("switchdev: Remove unused
transaction item queue") which has removed the unused mechanism of
passing on the allocated memory between one phase and another.

It is time we admit that separating the preparation from the commit
phase is something that is best left for the driver to decide, and not
something that should be baked into the API, especially since there are
no switchdev callers that depend on this.

This patch removes the struct switchdev_trans member from switchdev port
attribute notifier structures, and converts drivers to not look at this
member.

In part, this patch contains a revert of my previous commit 2e554a7a5d
("net: dsa: propagate switchdev vlan_filtering prepare phase to
drivers").

For the most part, the conversion was trivial except for:
- Rocker's world implementation based on Broadcom OF-DPA had an odd
  implementation of ofdpa_port_attr_bridge_flags_set. The conversion was
  done mechanically, by pasting the implementation twice, then only
  keeping the code that would get executed during prepare phase on top,
  then only keeping the code that gets executed during the commit phase
  on bottom, then simplifying the resulting code until this was obtained.
- DSA's offloading of STP state, bridge flags, VLAN filtering and
  multicast router could be converted right away. But the ageing time
  could not, so a shim was introduced and this was left for a further
  commit.

Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
Acked-by: Linus Walleij <linus.walleij@linaro.org>
Acked-by: Jiri Pirko <jiri@nvidia.com>
Reviewed-by: Kurt Kanzenbach <kurt@linutronix.de> # hellcreek
Reviewed-by: Linus Walleij <linus.walleij@linaro.org> # RTL8366RB
Reviewed-by: Ido Schimmel <idosch@nvidia.com>
Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
Vladimir Oltean 2021-01-09 02:01:50 +02:00 committed by Jakub Kicinski
parent cf6def51ba
commit bae33f2b5a
33 changed files with 162 additions and 424 deletions

View File

@ -1374,14 +1374,10 @@ void b53_phylink_mac_link_up(struct dsa_switch *ds, int port,
} }
EXPORT_SYMBOL(b53_phylink_mac_link_up); 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; struct b53_device *dev = ds->priv;
if (switchdev_trans_ph_prepare(trans))
return 0;
b53_enable_vlan(dev, dev->vlan_enabled, vlan_filtering); b53_enable_vlan(dev, dev->vlan_enabled, vlan_filtering);
return 0; return 0;

View File

@ -348,8 +348,7 @@ void b53_phylink_mac_link_up(struct dsa_switch *ds, int port,
struct phy_device *phydev, struct phy_device *phydev,
int speed, int duplex, int speed, int duplex,
bool tx_pause, bool rx_pause); 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, int b53_vlan_prepare(struct dsa_switch *ds, int port,
const struct switchdev_obj_port_vlan *vlan); const struct switchdev_obj_port_vlan *vlan);
void b53_vlan_add(struct dsa_switch *ds, int port, void b53_vlan_add(struct dsa_switch *ds, int port,

View File

@ -190,8 +190,7 @@ static void dsa_loop_port_stp_state_set(struct dsa_switch *ds, int port,
} }
static int dsa_loop_port_vlan_filtering(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", dev_dbg(ds->dev, "%s: port: %d, vlan_filtering: %d\n",
__func__, port, vlan_filtering); __func__, port, vlan_filtering);

View File

@ -858,14 +858,10 @@ static int hellcreek_fdb_dump(struct dsa_switch *ds, int port,
} }
static int hellcreek_vlan_filtering(struct dsa_switch *ds, int port, static int hellcreek_vlan_filtering(struct dsa_switch *ds, int port,
bool vlan_filtering, bool vlan_filtering)
struct switchdev_trans *trans)
{ {
struct hellcreek *hellcreek = ds->priv; struct hellcreek *hellcreek = ds->priv;
if (switchdev_trans_ph_prepare(trans))
return 0;
dev_dbg(hellcreek->dev, "%s VLAN filtering on port %d\n", dev_dbg(hellcreek->dev, "%s VLAN filtering on port %d\n",
vlan_filtering ? "Enable" : "Disable", port); vlan_filtering ? "Enable" : "Disable", port);

View File

@ -727,23 +727,14 @@ static int gswip_pce_load_microcode(struct gswip_priv *priv)
} }
static int gswip_port_vlan_filtering(struct dsa_switch *ds, int port, static int gswip_port_vlan_filtering(struct dsa_switch *ds, int port,
bool vlan_filtering, bool vlan_filtering)
struct switchdev_trans *trans)
{ {
struct net_device *bridge = dsa_to_port(ds, port)->bridge_dev;
struct gswip_priv *priv = ds->priv; struct gswip_priv *priv = ds->priv;
/* Do not allow changing the VLAN filtering options while in bridge */ /* Do not allow changing the VLAN filtering options while in bridge */
if (switchdev_trans_ph_prepare(trans)) { if (bridge && !!(priv->port_vlan_filter & BIT(port)) != vlan_filtering)
struct net_device *bridge = dsa_to_port(ds, port)->bridge_dev; return -EIO;
if (!bridge)
return 0;
if (!!(priv->port_vlan_filter & BIT(port)) != vlan_filtering)
return -EIO;
return 0;
}
if (vlan_filtering) { if (vlan_filtering) {
/* Use port based VLAN tag */ /* Use port based VLAN tag */
@ -781,15 +772,8 @@ static int gswip_setup(struct dsa_switch *ds)
/* disable port fetch/store dma on all ports */ /* disable port fetch/store dma on all ports */
for (i = 0; i < priv->hw_info->max_ports; i++) { 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_disable(ds, i);
gswip_port_vlan_filtering(ds, i, false, &trans); gswip_port_vlan_filtering(ds, i, false);
} }
/* enable Switch */ /* enable Switch */

View File

@ -783,14 +783,10 @@ static void ksz8795_flush_dyn_mac_table(struct ksz_device *dev, int port)
} }
static int ksz8795_port_vlan_filtering(struct dsa_switch *ds, int port, 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; struct ksz_device *dev = ds->priv;
if (switchdev_trans_ph_prepare(trans))
return 0;
ksz_cfg(dev, S_MIRROR_CTRL, SW_VLAN_ENABLE, flag); ksz_cfg(dev, S_MIRROR_CTRL, SW_VLAN_ENABLE, flag);
return 0; return 0;

View File

@ -493,14 +493,10 @@ static void ksz9477_flush_dyn_mac_table(struct ksz_device *dev, int port)
} }
static int ksz9477_port_vlan_filtering(struct dsa_switch *ds, int port, 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; struct ksz_device *dev = ds->priv;
if (switchdev_trans_ph_prepare(trans))
return 0;
if (flag) { if (flag) {
ksz_port_cfg(dev, port, REG_PORT_LUE_CTRL, ksz_port_cfg(dev, port, REG_PORT_LUE_CTRL,
PORT_VLAN_LOOKUP_VID_0, true); PORT_VLAN_LOOKUP_VID_0, true);

View File

@ -1376,12 +1376,8 @@ mt7530_vlan_cmd(struct mt7530_priv *priv, enum mt7530_vlan_cmd cmd, u16 vid)
static int static int
mt7530_port_vlan_filtering(struct dsa_switch *ds, int port, 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) { if (vlan_filtering) {
/* The port is being kept as VLAN-unaware port when bridge is /* The port is being kept as VLAN-unaware port when bridge is
* set up with vlan_filtering not being set, Otherwise, the * set up with vlan_filtering not being set, Otherwise, the

View File

@ -1583,16 +1583,15 @@ static int mv88e6xxx_port_check_hw_vlan(struct dsa_switch *ds, int port,
} }
static int mv88e6xxx_port_vlan_filtering(struct dsa_switch *ds, int port, 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; struct mv88e6xxx_chip *chip = ds->priv;
u16 mode = vlan_filtering ? MV88E6XXX_PORT_CTL2_8021Q_MODE_SECURE : u16 mode = vlan_filtering ? MV88E6XXX_PORT_CTL2_8021Q_MODE_SECURE :
MV88E6XXX_PORT_CTL2_8021Q_MODE_DISABLED; MV88E6XXX_PORT_CTL2_8021Q_MODE_DISABLED;
int err; int err;
if (switchdev_trans_ph_prepare(trans)) if (!mv88e6xxx_max_vid(chip))
return mv88e6xxx_max_vid(chip) ? 0 : -EOPNOTSUPP; return -EOPNOTSUPP;
mv88e6xxx_reg_lock(chip); mv88e6xxx_reg_lock(chip);
err = mv88e6xxx_port_set_8021q_mode(chip, port, mode); err = mv88e6xxx_port_set_8021q_mode(chip, port, mode);

View File

@ -134,12 +134,11 @@ static int felix_vlan_prepare(struct dsa_switch *ds, int port,
flags & BRIDGE_VLAN_INFO_UNTAGGED); flags & BRIDGE_VLAN_INFO_UNTAGGED);
} }
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; struct ocelot *ocelot = ds->priv;
return ocelot_port_vlan_filtering(ocelot, port, enabled, trans); return ocelot_port_vlan_filtering(ocelot, port, enabled);
} }
static void felix_vlan_add(struct dsa_switch *ds, int port, static void felix_vlan_add(struct dsa_switch *ds, int port,

View File

@ -1294,14 +1294,10 @@ qca8k_port_fdb_dump(struct dsa_switch *ds, int port,
} }
static int 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; struct qca8k_priv *priv = ds->priv;
if (switchdev_trans_ph_prepare(trans))
return 0;
if (vlan_filtering) { if (vlan_filtering) {
qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(port), qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(port),
QCA8K_PORT_LOOKUP_VLAN_MODE, QCA8K_PORT_LOOKUP_VLAN_MODE,

View File

@ -131,8 +131,7 @@ int rtl8366_enable_vlan(struct realtek_smi *smi, bool enable);
int rtl8366_reset_vlan(struct realtek_smi *smi); int rtl8366_reset_vlan(struct realtek_smi *smi);
int rtl8366_init_vlan(struct realtek_smi *smi); int rtl8366_init_vlan(struct realtek_smi *smi);
int rtl8366_vlan_filtering(struct dsa_switch *ds, int port, 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, int rtl8366_vlan_prepare(struct dsa_switch *ds, int port,
const struct switchdev_obj_port_vlan *vlan); const struct switchdev_obj_port_vlan *vlan);
void rtl8366_vlan_add(struct dsa_switch *ds, int port, void rtl8366_vlan_add(struct dsa_switch *ds, int port,

View File

@ -340,20 +340,15 @@ int rtl8366_init_vlan(struct realtek_smi *smi)
} }
EXPORT_SYMBOL_GPL(rtl8366_init_vlan); 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 realtek_smi *smi = ds->priv;
struct rtl8366_vlan_4k vlan4k; struct rtl8366_vlan_4k vlan4k;
int ret; int ret;
/* Use VLAN nr port + 1 since VLAN0 is not valid */ /* Use VLAN nr port + 1 since VLAN0 is not valid */
if (switchdev_trans_ph_prepare(trans)) { if (!smi->ops->is_vlan_valid(smi, port + 1))
if (!smi->ops->is_vlan_valid(smi, port + 1)) return -EINVAL;
return -EINVAL;
return 0;
}
dev_info(smi->dev, "%s filtering on port %d\n", dev_info(smi->dev, "%s filtering on port %d\n",
vlan_filtering ? "enable" : "disable", vlan_filtering ? "enable" : "disable",

View File

@ -245,8 +245,7 @@ enum sja1105_reset_reason {
int sja1105_static_config_reload(struct sja1105_private *priv, int sja1105_static_config_reload(struct sja1105_private *priv,
enum sja1105_reset_reason reason); 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); void sja1105_frame_memory_partitioning(struct sja1105_private *priv);
/* From sja1105_devlink.c */ /* From sja1105_devlink.c */

View File

@ -135,7 +135,6 @@ static int sja1105_best_effort_vlan_filtering_set(struct sja1105_private *priv,
rtnl_lock(); rtnl_lock();
for (port = 0; port < ds->num_ports; port++) { for (port = 0; port < ds->num_ports; port++) {
struct switchdev_trans trans;
struct dsa_port *dp; struct dsa_port *dp;
if (!dsa_is_user_port(ds, port)) if (!dsa_is_user_port(ds, port))
@ -144,13 +143,7 @@ static int sja1105_best_effort_vlan_filtering_set(struct sja1105_private *priv,
dp = dsa_to_port(ds, port); dp = dsa_to_port(ds, port);
vlan_filtering = dsa_port_is_vlan_filtering(dp); vlan_filtering = dsa_port_is_vlan_filtering(dp);
trans.ph_prepare = true; rc = sja1105_vlan_filtering(ds, port, vlan_filtering);
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) if (rc)
break; break;
} }

View File

@ -2631,8 +2631,7 @@ static int sja1105_vlan_prepare(struct dsa_switch *ds, int port,
* which can only be partially reconfigured at runtime (and not the TPID). * which can only be partially reconfigured at runtime (and not the TPID).
* So a switch reset is required. * 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_l2_lookup_params_entry *l2_lookup_params;
struct sja1105_general_params_entry *general_params; struct sja1105_general_params_entry *general_params;
@ -2644,16 +2643,12 @@ int sja1105_vlan_filtering(struct dsa_switch *ds, int port, bool enabled,
u16 tpid, tpid2; u16 tpid, tpid2;
int rc; int rc;
if (switchdev_trans_ph_prepare(trans)) { list_for_each_entry(rule, &priv->flow_block.rules, list) {
list_for_each_entry(rule, &priv->flow_block.rules, list) { if (rule->type == SJA1105_RULE_VL) {
if (rule->type == SJA1105_RULE_VL) { dev_err(ds->dev,
dev_err(ds->dev, "Cannot change VLAN filtering with active VL rules\n");
"Cannot change VLAN filtering with active VL rules\n"); return -EBUSY;
return -EBUSY;
}
} }
return 0;
} }
if (enabled) { if (enabled) {

View File

@ -580,16 +580,12 @@ int prestera_bridge_port_event(struct net_device *dev, unsigned long event,
} }
static int prestera_port_attr_br_flags_set(struct prestera_port *port, static int prestera_port_attr_br_flags_set(struct prestera_port *port,
struct switchdev_trans *trans,
struct net_device *dev, struct net_device *dev,
unsigned long flags) unsigned long flags)
{ {
struct prestera_bridge_port *br_port; struct prestera_bridge_port *br_port;
int err; int err;
if (switchdev_trans_ph_prepare(trans))
return 0;
br_port = prestera_bridge_port_by_dev(port->sw->swdev, dev); br_port = prestera_bridge_port_by_dev(port->sw->swdev, dev);
if (!br_port) if (!br_port)
return 0; return 0;
@ -608,35 +604,26 @@ static int prestera_port_attr_br_flags_set(struct prestera_port *port,
} }
static int prestera_port_attr_br_ageing_set(struct prestera_port *port, static int prestera_port_attr_br_ageing_set(struct prestera_port *port,
struct switchdev_trans *trans,
unsigned long ageing_clock_t) unsigned long ageing_clock_t)
{ {
unsigned long ageing_jiffies = clock_t_to_jiffies(ageing_clock_t); unsigned long ageing_jiffies = clock_t_to_jiffies(ageing_clock_t);
u32 ageing_time_ms = jiffies_to_msecs(ageing_jiffies); u32 ageing_time_ms = jiffies_to_msecs(ageing_jiffies);
struct prestera_switch *sw = port->sw; struct prestera_switch *sw = port->sw;
if (switchdev_trans_ph_prepare(trans)) { if (ageing_time_ms < PRESTERA_MIN_AGEING_TIME_MS ||
if (ageing_time_ms < PRESTERA_MIN_AGEING_TIME_MS || ageing_time_ms > PRESTERA_MAX_AGEING_TIME_MS)
ageing_time_ms > PRESTERA_MAX_AGEING_TIME_MS) return -ERANGE;
return -ERANGE;
else
return 0;
}
return prestera_hw_switch_ageing_set(sw, ageing_time_ms); return prestera_hw_switch_ageing_set(sw, ageing_time_ms);
} }
static int prestera_port_attr_br_vlan_set(struct prestera_port *port, static int prestera_port_attr_br_vlan_set(struct prestera_port *port,
struct switchdev_trans *trans,
struct net_device *dev, struct net_device *dev,
bool vlan_enabled) bool vlan_enabled)
{ {
struct prestera_switch *sw = port->sw; struct prestera_switch *sw = port->sw;
struct prestera_bridge *bridge; struct prestera_bridge *bridge;
if (!switchdev_trans_ph_prepare(trans))
return 0;
bridge = prestera_bridge_by_dev(sw->swdev, dev); bridge = prestera_bridge_by_dev(sw->swdev, dev);
if (WARN_ON(!bridge)) if (WARN_ON(!bridge))
return -EINVAL; return -EINVAL;
@ -666,7 +653,6 @@ static int prestera_port_bridge_vlan_stp_set(struct prestera_port *port,
} }
static int presterar_port_attr_stp_state_set(struct prestera_port *port, static int presterar_port_attr_stp_state_set(struct prestera_port *port,
struct switchdev_trans *trans,
struct net_device *dev, struct net_device *dev,
u8 state) u8 state)
{ {
@ -675,9 +661,6 @@ static int presterar_port_attr_stp_state_set(struct prestera_port *port,
int err; int err;
u16 vid; u16 vid;
if (switchdev_trans_ph_prepare(trans))
return 0;
br_port = prestera_bridge_port_by_dev(port->sw->swdev, dev); br_port = prestera_bridge_port_by_dev(port->sw->swdev, dev);
if (!br_port) if (!br_port)
return 0; return 0;
@ -712,16 +695,14 @@ static int presterar_port_attr_stp_state_set(struct prestera_port *port,
} }
static int prestera_port_obj_attr_set(struct net_device *dev, static int prestera_port_obj_attr_set(struct net_device *dev,
const struct switchdev_attr *attr, const struct switchdev_attr *attr)
struct switchdev_trans *trans)
{ {
struct prestera_port *port = netdev_priv(dev); struct prestera_port *port = netdev_priv(dev);
int err = 0; int err = 0;
switch (attr->id) { switch (attr->id) {
case SWITCHDEV_ATTR_ID_PORT_STP_STATE: case SWITCHDEV_ATTR_ID_PORT_STP_STATE:
err = presterar_port_attr_stp_state_set(port, trans, err = presterar_port_attr_stp_state_set(port, attr->orig_dev,
attr->orig_dev,
attr->u.stp_state); attr->u.stp_state);
break; break;
case SWITCHDEV_ATTR_ID_PORT_PRE_BRIDGE_FLAGS: case SWITCHDEV_ATTR_ID_PORT_PRE_BRIDGE_FLAGS:
@ -730,17 +711,15 @@ static int prestera_port_obj_attr_set(struct net_device *dev,
err = -EINVAL; err = -EINVAL;
break; break;
case SWITCHDEV_ATTR_ID_PORT_BRIDGE_FLAGS: case SWITCHDEV_ATTR_ID_PORT_BRIDGE_FLAGS:
err = prestera_port_attr_br_flags_set(port, trans, err = prestera_port_attr_br_flags_set(port, attr->orig_dev,
attr->orig_dev,
attr->u.brport_flags); attr->u.brport_flags);
break; break;
case SWITCHDEV_ATTR_ID_BRIDGE_AGEING_TIME: case SWITCHDEV_ATTR_ID_BRIDGE_AGEING_TIME:
err = prestera_port_attr_br_ageing_set(port, trans, err = prestera_port_attr_br_ageing_set(port,
attr->u.ageing_time); attr->u.ageing_time);
break; break;
case SWITCHDEV_ATTR_ID_BRIDGE_VLAN_FILTERING: case SWITCHDEV_ATTR_ID_BRIDGE_VLAN_FILTERING:
err = prestera_port_attr_br_vlan_set(port, trans, err = prestera_port_attr_br_vlan_set(port, attr->orig_dev,
attr->orig_dev,
attr->u.vlan_filtering); attr->u.vlan_filtering);
break; break;
default: default:

View File

@ -527,7 +527,6 @@ mlxsw_sp_port_bridge_vlan_stp_set(struct mlxsw_sp_port *mlxsw_sp_port,
} }
static int mlxsw_sp_port_attr_stp_state_set(struct mlxsw_sp_port *mlxsw_sp_port, static int mlxsw_sp_port_attr_stp_state_set(struct mlxsw_sp_port *mlxsw_sp_port,
struct switchdev_trans *trans,
struct net_device *orig_dev, struct net_device *orig_dev,
u8 state) u8 state)
{ {
@ -535,9 +534,6 @@ static int mlxsw_sp_port_attr_stp_state_set(struct mlxsw_sp_port *mlxsw_sp_port,
struct mlxsw_sp_bridge_vlan *bridge_vlan; struct mlxsw_sp_bridge_vlan *bridge_vlan;
int err; int err;
if (switchdev_trans_ph_prepare(trans))
return 0;
/* It's possible we failed to enslave the port, yet this /* It's possible we failed to enslave the port, yet this
* operation is executed due to it being deferred. * operation is executed due to it being deferred.
*/ */
@ -659,7 +655,6 @@ mlxsw_sp_bridge_port_learning_set(struct mlxsw_sp_port *mlxsw_sp_port,
static int mlxsw_sp_port_attr_br_pre_flags_set(struct mlxsw_sp_port static int mlxsw_sp_port_attr_br_pre_flags_set(struct mlxsw_sp_port
*mlxsw_sp_port, *mlxsw_sp_port,
struct switchdev_trans *trans,
unsigned long brport_flags) unsigned long brport_flags)
{ {
if (brport_flags & ~(BR_LEARNING | BR_FLOOD | BR_MCAST_FLOOD)) if (brport_flags & ~(BR_LEARNING | BR_FLOOD | BR_MCAST_FLOOD))
@ -669,16 +664,12 @@ static int mlxsw_sp_port_attr_br_pre_flags_set(struct mlxsw_sp_port
} }
static int mlxsw_sp_port_attr_br_flags_set(struct mlxsw_sp_port *mlxsw_sp_port, static int mlxsw_sp_port_attr_br_flags_set(struct mlxsw_sp_port *mlxsw_sp_port,
struct switchdev_trans *trans,
struct net_device *orig_dev, struct net_device *orig_dev,
unsigned long brport_flags) unsigned long brport_flags)
{ {
struct mlxsw_sp_bridge_port *bridge_port; struct mlxsw_sp_bridge_port *bridge_port;
int err; int err;
if (switchdev_trans_ph_prepare(trans))
return 0;
bridge_port = mlxsw_sp_bridge_port_find(mlxsw_sp_port->mlxsw_sp->bridge, bridge_port = mlxsw_sp_bridge_port_find(mlxsw_sp_port->mlxsw_sp->bridge,
orig_dev); orig_dev);
if (!bridge_port) if (!bridge_port)
@ -724,35 +715,26 @@ static int mlxsw_sp_ageing_set(struct mlxsw_sp *mlxsw_sp, u32 ageing_time)
} }
static int mlxsw_sp_port_attr_br_ageing_set(struct mlxsw_sp_port *mlxsw_sp_port, static int mlxsw_sp_port_attr_br_ageing_set(struct mlxsw_sp_port *mlxsw_sp_port,
struct switchdev_trans *trans,
unsigned long ageing_clock_t) unsigned long ageing_clock_t)
{ {
struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
unsigned long ageing_jiffies = clock_t_to_jiffies(ageing_clock_t); unsigned long ageing_jiffies = clock_t_to_jiffies(ageing_clock_t);
u32 ageing_time = jiffies_to_msecs(ageing_jiffies) / 1000; u32 ageing_time = jiffies_to_msecs(ageing_jiffies) / 1000;
if (switchdev_trans_ph_prepare(trans)) { if (ageing_time < MLXSW_SP_MIN_AGEING_TIME ||
if (ageing_time < MLXSW_SP_MIN_AGEING_TIME || ageing_time > MLXSW_SP_MAX_AGEING_TIME)
ageing_time > MLXSW_SP_MAX_AGEING_TIME) return -ERANGE;
return -ERANGE;
else
return 0;
}
return mlxsw_sp_ageing_set(mlxsw_sp, ageing_time); return mlxsw_sp_ageing_set(mlxsw_sp, ageing_time);
} }
static int mlxsw_sp_port_attr_br_vlan_set(struct mlxsw_sp_port *mlxsw_sp_port, static int mlxsw_sp_port_attr_br_vlan_set(struct mlxsw_sp_port *mlxsw_sp_port,
struct switchdev_trans *trans,
struct net_device *orig_dev, struct net_device *orig_dev,
bool vlan_enabled) bool vlan_enabled)
{ {
struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
struct mlxsw_sp_bridge_device *bridge_device; struct mlxsw_sp_bridge_device *bridge_device;
if (!switchdev_trans_ph_prepare(trans))
return 0;
bridge_device = mlxsw_sp_bridge_device_find(mlxsw_sp->bridge, orig_dev); bridge_device = mlxsw_sp_bridge_device_find(mlxsw_sp->bridge, orig_dev);
if (WARN_ON(!bridge_device)) if (WARN_ON(!bridge_device))
return -EINVAL; return -EINVAL;
@ -765,16 +747,12 @@ static int mlxsw_sp_port_attr_br_vlan_set(struct mlxsw_sp_port *mlxsw_sp_port,
} }
static int mlxsw_sp_port_attr_br_vlan_proto_set(struct mlxsw_sp_port *mlxsw_sp_port, static int mlxsw_sp_port_attr_br_vlan_proto_set(struct mlxsw_sp_port *mlxsw_sp_port,
struct switchdev_trans *trans,
struct net_device *orig_dev, struct net_device *orig_dev,
u16 vlan_proto) u16 vlan_proto)
{ {
struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
struct mlxsw_sp_bridge_device *bridge_device; struct mlxsw_sp_bridge_device *bridge_device;
if (!switchdev_trans_ph_prepare(trans))
return 0;
bridge_device = mlxsw_sp_bridge_device_find(mlxsw_sp->bridge, orig_dev); bridge_device = mlxsw_sp_bridge_device_find(mlxsw_sp->bridge, orig_dev);
if (WARN_ON(!bridge_device)) if (WARN_ON(!bridge_device))
return -EINVAL; return -EINVAL;
@ -784,16 +762,12 @@ static int mlxsw_sp_port_attr_br_vlan_proto_set(struct mlxsw_sp_port *mlxsw_sp_p
} }
static int mlxsw_sp_port_attr_mrouter_set(struct mlxsw_sp_port *mlxsw_sp_port, static int mlxsw_sp_port_attr_mrouter_set(struct mlxsw_sp_port *mlxsw_sp_port,
struct switchdev_trans *trans,
struct net_device *orig_dev, struct net_device *orig_dev,
bool is_port_mrouter) bool is_port_mrouter)
{ {
struct mlxsw_sp_bridge_port *bridge_port; struct mlxsw_sp_bridge_port *bridge_port;
int err; int err;
if (switchdev_trans_ph_prepare(trans))
return 0;
bridge_port = mlxsw_sp_bridge_port_find(mlxsw_sp_port->mlxsw_sp->bridge, bridge_port = mlxsw_sp_bridge_port_find(mlxsw_sp_port->mlxsw_sp->bridge,
orig_dev); orig_dev);
if (!bridge_port) if (!bridge_port)
@ -825,7 +799,6 @@ static bool mlxsw_sp_mc_flood(const struct mlxsw_sp_bridge_port *bridge_port)
} }
static int mlxsw_sp_port_mc_disabled_set(struct mlxsw_sp_port *mlxsw_sp_port, static int mlxsw_sp_port_mc_disabled_set(struct mlxsw_sp_port *mlxsw_sp_port,
struct switchdev_trans *trans,
struct net_device *orig_dev, struct net_device *orig_dev,
bool mc_disabled) bool mc_disabled)
{ {
@ -834,9 +807,6 @@ static int mlxsw_sp_port_mc_disabled_set(struct mlxsw_sp_port *mlxsw_sp_port,
struct mlxsw_sp_bridge_port *bridge_port; struct mlxsw_sp_bridge_port *bridge_port;
int err; int err;
if (switchdev_trans_ph_prepare(trans))
return 0;
/* It's possible we failed to enslave the port, yet this /* It's possible we failed to enslave the port, yet this
* operation is executed due to it being deferred. * operation is executed due to it being deferred.
*/ */
@ -896,16 +866,12 @@ mlxsw_sp_bridge_mrouter_update_mdb(struct mlxsw_sp *mlxsw_sp,
static int static int
mlxsw_sp_port_attr_br_mrouter_set(struct mlxsw_sp_port *mlxsw_sp_port, mlxsw_sp_port_attr_br_mrouter_set(struct mlxsw_sp_port *mlxsw_sp_port,
struct switchdev_trans *trans,
struct net_device *orig_dev, struct net_device *orig_dev,
bool is_mrouter) bool is_mrouter)
{ {
struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
struct mlxsw_sp_bridge_device *bridge_device; struct mlxsw_sp_bridge_device *bridge_device;
if (switchdev_trans_ph_prepare(trans))
return 0;
/* It's possible we failed to enslave the port, yet this /* It's possible we failed to enslave the port, yet this
* operation is executed due to it being deferred. * operation is executed due to it being deferred.
*/ */
@ -921,54 +887,52 @@ mlxsw_sp_port_attr_br_mrouter_set(struct mlxsw_sp_port *mlxsw_sp_port,
} }
static int mlxsw_sp_port_attr_set(struct net_device *dev, static int mlxsw_sp_port_attr_set(struct net_device *dev,
const struct switchdev_attr *attr, const struct switchdev_attr *attr)
struct switchdev_trans *trans)
{ {
struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev); struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
int err; int err;
switch (attr->id) { switch (attr->id) {
case SWITCHDEV_ATTR_ID_PORT_STP_STATE: case SWITCHDEV_ATTR_ID_PORT_STP_STATE:
err = mlxsw_sp_port_attr_stp_state_set(mlxsw_sp_port, trans, err = mlxsw_sp_port_attr_stp_state_set(mlxsw_sp_port,
attr->orig_dev, attr->orig_dev,
attr->u.stp_state); attr->u.stp_state);
break; break;
case SWITCHDEV_ATTR_ID_PORT_PRE_BRIDGE_FLAGS: case SWITCHDEV_ATTR_ID_PORT_PRE_BRIDGE_FLAGS:
err = mlxsw_sp_port_attr_br_pre_flags_set(mlxsw_sp_port, err = mlxsw_sp_port_attr_br_pre_flags_set(mlxsw_sp_port,
trans,
attr->u.brport_flags); attr->u.brport_flags);
break; break;
case SWITCHDEV_ATTR_ID_PORT_BRIDGE_FLAGS: case SWITCHDEV_ATTR_ID_PORT_BRIDGE_FLAGS:
err = mlxsw_sp_port_attr_br_flags_set(mlxsw_sp_port, trans, err = mlxsw_sp_port_attr_br_flags_set(mlxsw_sp_port,
attr->orig_dev, attr->orig_dev,
attr->u.brport_flags); attr->u.brport_flags);
break; break;
case SWITCHDEV_ATTR_ID_BRIDGE_AGEING_TIME: case SWITCHDEV_ATTR_ID_BRIDGE_AGEING_TIME:
err = mlxsw_sp_port_attr_br_ageing_set(mlxsw_sp_port, trans, err = mlxsw_sp_port_attr_br_ageing_set(mlxsw_sp_port,
attr->u.ageing_time); attr->u.ageing_time);
break; break;
case SWITCHDEV_ATTR_ID_BRIDGE_VLAN_FILTERING: case SWITCHDEV_ATTR_ID_BRIDGE_VLAN_FILTERING:
err = mlxsw_sp_port_attr_br_vlan_set(mlxsw_sp_port, trans, err = mlxsw_sp_port_attr_br_vlan_set(mlxsw_sp_port,
attr->orig_dev, attr->orig_dev,
attr->u.vlan_filtering); attr->u.vlan_filtering);
break; break;
case SWITCHDEV_ATTR_ID_BRIDGE_VLAN_PROTOCOL: case SWITCHDEV_ATTR_ID_BRIDGE_VLAN_PROTOCOL:
err = mlxsw_sp_port_attr_br_vlan_proto_set(mlxsw_sp_port, trans, err = mlxsw_sp_port_attr_br_vlan_proto_set(mlxsw_sp_port,
attr->orig_dev, attr->orig_dev,
attr->u.vlan_protocol); attr->u.vlan_protocol);
break; break;
case SWITCHDEV_ATTR_ID_PORT_MROUTER: case SWITCHDEV_ATTR_ID_PORT_MROUTER:
err = mlxsw_sp_port_attr_mrouter_set(mlxsw_sp_port, trans, err = mlxsw_sp_port_attr_mrouter_set(mlxsw_sp_port,
attr->orig_dev, attr->orig_dev,
attr->u.mrouter); attr->u.mrouter);
break; break;
case SWITCHDEV_ATTR_ID_BRIDGE_MC_DISABLED: case SWITCHDEV_ATTR_ID_BRIDGE_MC_DISABLED:
err = mlxsw_sp_port_mc_disabled_set(mlxsw_sp_port, trans, err = mlxsw_sp_port_mc_disabled_set(mlxsw_sp_port,
attr->orig_dev, attr->orig_dev,
attr->u.mc_disabled); attr->u.mc_disabled);
break; break;
case SWITCHDEV_ATTR_ID_BRIDGE_MROUTER: case SWITCHDEV_ATTR_ID_BRIDGE_MROUTER:
err = mlxsw_sp_port_attr_br_mrouter_set(mlxsw_sp_port, trans, err = mlxsw_sp_port_attr_br_mrouter_set(mlxsw_sp_port,
attr->orig_dev, attr->orig_dev,
attr->u.mrouter); attr->u.mrouter);
break; break;
@ -977,8 +941,7 @@ static int mlxsw_sp_port_attr_set(struct net_device *dev,
break; break;
} }
if (switchdev_trans_ph_commit(trans)) mlxsw_sp_span_respin(mlxsw_sp_port->mlxsw_sp);
mlxsw_sp_span_respin(mlxsw_sp_port->mlxsw_sp);
return err; return err;
} }

View File

@ -208,25 +208,20 @@ static void ocelot_port_set_pvid(struct ocelot *ocelot, int port,
} }
int ocelot_port_vlan_filtering(struct ocelot *ocelot, int port, int ocelot_port_vlan_filtering(struct ocelot *ocelot, int port,
bool vlan_aware, struct switchdev_trans *trans) bool vlan_aware)
{ {
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];
struct ocelot_vcap_filter *filter;
u32 val; u32 val;
if (switchdev_trans_ph_prepare(trans)) { list_for_each_entry(filter, &block->rules, list) {
struct ocelot_vcap_block *block = &ocelot->block[VCAP_IS1]; if (filter->ingress_port_mask & BIT(port) &&
struct ocelot_vcap_filter *filter; filter->action.vid_replace_ena) {
dev_err(ocelot->dev,
list_for_each_entry(filter, &block->rules, list) { "Cannot change VLAN state with vlan modify rules active\n");
if (filter->ingress_port_mask & BIT(port) && return -EBUSY;
filter->action.vid_replace_ena) {
dev_err(ocelot->dev,
"Cannot change VLAN state with vlan modify rules active\n");
return -EBUSY;
}
} }
return 0;
} }
ocelot_port->vlan_aware = vlan_aware; ocelot_port->vlan_aware = vlan_aware;
@ -1179,7 +1174,6 @@ int ocelot_port_bridge_leave(struct ocelot *ocelot, int port,
struct net_device *bridge) struct net_device *bridge)
{ {
struct ocelot_vlan pvid = {0}, native_vlan = {0}; struct ocelot_vlan pvid = {0}, native_vlan = {0};
struct switchdev_trans trans;
int ret; int ret;
ocelot->bridge_mask &= ~BIT(port); ocelot->bridge_mask &= ~BIT(port);
@ -1187,13 +1181,7 @@ int ocelot_port_bridge_leave(struct ocelot *ocelot, int port,
if (!ocelot->bridge_mask) if (!ocelot->bridge_mask)
ocelot->hw_bridge_dev = NULL; ocelot->hw_bridge_dev = NULL;
trans.ph_prepare = true; ret = ocelot_port_vlan_filtering(ocelot, port, false);
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) if (ret)
return ret; return ret;

View File

@ -825,12 +825,8 @@ static const struct ethtool_ops ocelot_ethtool_ops = {
}; };
static void ocelot_port_attr_stp_state_set(struct ocelot *ocelot, int port, static void ocelot_port_attr_stp_state_set(struct ocelot *ocelot, int port,
struct switchdev_trans *trans,
u8 state) u8 state)
{ {
if (switchdev_trans_ph_prepare(trans))
return;
ocelot_bridge_stp_state_set(ocelot, port, state); ocelot_bridge_stp_state_set(ocelot, port, state);
} }
@ -858,8 +854,7 @@ static void ocelot_port_attr_mc_set(struct ocelot *ocelot, int port, bool mc)
} }
static int ocelot_port_attr_set(struct net_device *dev, static int ocelot_port_attr_set(struct net_device *dev,
const struct switchdev_attr *attr, const struct switchdev_attr *attr)
struct switchdev_trans *trans)
{ {
struct ocelot_port_private *priv = netdev_priv(dev); struct ocelot_port_private *priv = netdev_priv(dev);
struct ocelot *ocelot = priv->port.ocelot; struct ocelot *ocelot = priv->port.ocelot;
@ -868,15 +863,13 @@ static int ocelot_port_attr_set(struct net_device *dev,
switch (attr->id) { switch (attr->id) {
case SWITCHDEV_ATTR_ID_PORT_STP_STATE: case SWITCHDEV_ATTR_ID_PORT_STP_STATE:
ocelot_port_attr_stp_state_set(ocelot, port, trans, ocelot_port_attr_stp_state_set(ocelot, port, attr->u.stp_state);
attr->u.stp_state);
break; break;
case SWITCHDEV_ATTR_ID_BRIDGE_AGEING_TIME: case SWITCHDEV_ATTR_ID_BRIDGE_AGEING_TIME:
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, ocelot_port_vlan_filtering(ocelot, port, attr->u.vlan_filtering);
attr->u.vlan_filtering, trans);
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);

View File

@ -103,15 +103,13 @@ struct rocker_world_ops {
int (*port_attr_stp_state_set)(struct rocker_port *rocker_port, int (*port_attr_stp_state_set)(struct rocker_port *rocker_port,
u8 state); u8 state);
int (*port_attr_bridge_flags_set)(struct rocker_port *rocker_port, int (*port_attr_bridge_flags_set)(struct rocker_port *rocker_port,
unsigned long brport_flags, unsigned long brport_flags);
struct switchdev_trans *trans);
int (*port_attr_bridge_flags_support_get)(const struct rocker_port * int (*port_attr_bridge_flags_support_get)(const struct rocker_port *
rocker_port, rocker_port,
unsigned long * unsigned long *
p_brport_flags); p_brport_flags);
int (*port_attr_bridge_ageing_time_set)(struct rocker_port *rocker_port, int (*port_attr_bridge_ageing_time_set)(struct rocker_port *rocker_port,
u32 ageing_time, u32 ageing_time);
struct switchdev_trans *trans);
int (*port_obj_vlan_add)(struct rocker_port *rocker_port, int (*port_obj_vlan_add)(struct rocker_port *rocker_port,
const struct switchdev_obj_port_vlan *vlan); const struct switchdev_obj_port_vlan *vlan);
int (*port_obj_vlan_del)(struct rocker_port *rocker_port, int (*port_obj_vlan_del)(struct rocker_port *rocker_port,

View File

@ -1550,17 +1550,13 @@ static void rocker_world_port_stop(struct rocker_port *rocker_port)
} }
static int rocker_world_port_attr_stp_state_set(struct rocker_port *rocker_port, static int rocker_world_port_attr_stp_state_set(struct rocker_port *rocker_port,
u8 state, u8 state)
struct switchdev_trans *trans)
{ {
struct rocker_world_ops *wops = rocker_port->rocker->wops; struct rocker_world_ops *wops = rocker_port->rocker->wops;
if (!wops->port_attr_stp_state_set) if (!wops->port_attr_stp_state_set)
return -EOPNOTSUPP; return -EOPNOTSUPP;
if (switchdev_trans_ph_prepare(trans))
return 0;
return wops->port_attr_stp_state_set(rocker_port, state); return wops->port_attr_stp_state_set(rocker_port, state);
} }
@ -1580,8 +1576,7 @@ rocker_world_port_attr_bridge_flags_support_get(const struct rocker_port *
static int static int
rocker_world_port_attr_pre_bridge_flags_set(struct rocker_port *rocker_port, rocker_world_port_attr_pre_bridge_flags_set(struct rocker_port *rocker_port,
unsigned long brport_flags, unsigned long brport_flags)
struct switchdev_trans *trans)
{ {
struct rocker_world_ops *wops = rocker_port->rocker->wops; struct rocker_world_ops *wops = rocker_port->rocker->wops;
unsigned long brport_flags_s; unsigned long brport_flags_s;
@ -1603,37 +1598,26 @@ rocker_world_port_attr_pre_bridge_flags_set(struct rocker_port *rocker_port,
static int static int
rocker_world_port_attr_bridge_flags_set(struct rocker_port *rocker_port, rocker_world_port_attr_bridge_flags_set(struct rocker_port *rocker_port,
unsigned long brport_flags, unsigned long brport_flags)
struct switchdev_trans *trans)
{ {
struct rocker_world_ops *wops = rocker_port->rocker->wops; struct rocker_world_ops *wops = rocker_port->rocker->wops;
if (!wops->port_attr_bridge_flags_set) if (!wops->port_attr_bridge_flags_set)
return -EOPNOTSUPP; return -EOPNOTSUPP;
if (switchdev_trans_ph_prepare(trans)) return wops->port_attr_bridge_flags_set(rocker_port, brport_flags);
return 0;
return wops->port_attr_bridge_flags_set(rocker_port, brport_flags,
trans);
} }
static int static int
rocker_world_port_attr_bridge_ageing_time_set(struct rocker_port *rocker_port, rocker_world_port_attr_bridge_ageing_time_set(struct rocker_port *rocker_port,
u32 ageing_time, u32 ageing_time)
struct switchdev_trans *trans)
{ {
struct rocker_world_ops *wops = rocker_port->rocker->wops; struct rocker_world_ops *wops = rocker_port->rocker->wops;
if (!wops->port_attr_bridge_ageing_time_set) if (!wops->port_attr_bridge_ageing_time_set)
return -EOPNOTSUPP; return -EOPNOTSUPP;
if (switchdev_trans_ph_prepare(trans)) return wops->port_attr_bridge_ageing_time_set(rocker_port, ageing_time);
return 0;
return wops->port_attr_bridge_ageing_time_set(rocker_port, ageing_time,
trans);
} }
static int static int
@ -2062,8 +2046,7 @@ static const struct net_device_ops rocker_port_netdev_ops = {
********************/ ********************/
static int rocker_port_attr_set(struct net_device *dev, static int rocker_port_attr_set(struct net_device *dev,
const struct switchdev_attr *attr, const struct switchdev_attr *attr)
struct switchdev_trans *trans)
{ {
struct rocker_port *rocker_port = netdev_priv(dev); struct rocker_port *rocker_port = netdev_priv(dev);
int err = 0; int err = 0;
@ -2071,23 +2054,19 @@ static int rocker_port_attr_set(struct net_device *dev,
switch (attr->id) { switch (attr->id) {
case SWITCHDEV_ATTR_ID_PORT_STP_STATE: case SWITCHDEV_ATTR_ID_PORT_STP_STATE:
err = rocker_world_port_attr_stp_state_set(rocker_port, err = rocker_world_port_attr_stp_state_set(rocker_port,
attr->u.stp_state, attr->u.stp_state);
trans);
break; break;
case SWITCHDEV_ATTR_ID_PORT_PRE_BRIDGE_FLAGS: case SWITCHDEV_ATTR_ID_PORT_PRE_BRIDGE_FLAGS:
err = rocker_world_port_attr_pre_bridge_flags_set(rocker_port, err = rocker_world_port_attr_pre_bridge_flags_set(rocker_port,
attr->u.brport_flags, attr->u.brport_flags);
trans);
break; break;
case SWITCHDEV_ATTR_ID_PORT_BRIDGE_FLAGS: case SWITCHDEV_ATTR_ID_PORT_BRIDGE_FLAGS:
err = rocker_world_port_attr_bridge_flags_set(rocker_port, err = rocker_world_port_attr_bridge_flags_set(rocker_port,
attr->u.brport_flags, attr->u.brport_flags);
trans);
break; break;
case SWITCHDEV_ATTR_ID_BRIDGE_AGEING_TIME: case SWITCHDEV_ATTR_ID_BRIDGE_AGEING_TIME:
err = rocker_world_port_attr_bridge_ageing_time_set(rocker_port, err = rocker_world_port_attr_bridge_ageing_time_set(rocker_port,
attr->u.ageing_time, attr->u.ageing_time);
trans);
break; break;
default: default:
err = -EOPNOTSUPP; err = -EOPNOTSUPP;
@ -2719,8 +2698,7 @@ rocker_switchdev_port_attr_set_event(struct net_device *netdev,
{ {
int err; int err;
err = rocker_port_attr_set(netdev, port_attr_info->attr, err = rocker_port_attr_set(netdev, port_attr_info->attr);
port_attr_info->trans);
port_attr_info->handled = true; port_attr_info->handled = true;
return notifier_from_errno(err); return notifier_from_errno(err);

View File

@ -2488,8 +2488,7 @@ static int ofdpa_port_attr_stp_state_set(struct rocker_port *rocker_port,
} }
static int ofdpa_port_attr_bridge_flags_set(struct rocker_port *rocker_port, static int ofdpa_port_attr_bridge_flags_set(struct rocker_port *rocker_port,
unsigned long brport_flags, unsigned long brport_flags)
struct switchdev_trans *trans)
{ {
struct ofdpa_port *ofdpa_port = rocker_port->wpriv; struct ofdpa_port *ofdpa_port = rocker_port->wpriv;
unsigned long orig_flags; unsigned long orig_flags;
@ -2497,14 +2496,11 @@ static int ofdpa_port_attr_bridge_flags_set(struct rocker_port *rocker_port,
orig_flags = ofdpa_port->brport_flags; orig_flags = ofdpa_port->brport_flags;
ofdpa_port->brport_flags = brport_flags; ofdpa_port->brport_flags = brport_flags;
if ((orig_flags ^ ofdpa_port->brport_flags) & BR_LEARNING &&
!switchdev_trans_ph_prepare(trans)) if ((orig_flags ^ ofdpa_port->brport_flags) & BR_LEARNING)
err = rocker_port_set_learning(ofdpa_port->rocker_port, err = rocker_port_set_learning(ofdpa_port->rocker_port,
!!(ofdpa_port->brport_flags & BR_LEARNING)); !!(ofdpa_port->brport_flags & BR_LEARNING));
if (switchdev_trans_ph_prepare(trans))
ofdpa_port->brport_flags = orig_flags;
return err; return err;
} }
@ -2520,18 +2516,15 @@ ofdpa_port_attr_bridge_flags_support_get(const struct rocker_port *
static int static int
ofdpa_port_attr_bridge_ageing_time_set(struct rocker_port *rocker_port, ofdpa_port_attr_bridge_ageing_time_set(struct rocker_port *rocker_port,
u32 ageing_time, u32 ageing_time)
struct switchdev_trans *trans)
{ {
struct ofdpa_port *ofdpa_port = rocker_port->wpriv; struct ofdpa_port *ofdpa_port = rocker_port->wpriv;
struct ofdpa *ofdpa = ofdpa_port->ofdpa; struct ofdpa *ofdpa = ofdpa_port->ofdpa;
if (!switchdev_trans_ph_prepare(trans)) { ofdpa_port->ageing_time = clock_t_to_jiffies(ageing_time);
ofdpa_port->ageing_time = clock_t_to_jiffies(ageing_time); if (ofdpa_port->ageing_time < ofdpa->ageing_time)
if (ofdpa_port->ageing_time < ofdpa->ageing_time) ofdpa->ageing_time = ofdpa_port->ageing_time;
ofdpa->ageing_time = ofdpa_port->ageing_time; mod_timer(&ofdpa_port->ofdpa->fdb_cleanup_timer, jiffies);
mod_timer(&ofdpa_port->ofdpa->fdb_cleanup_timer, jiffies);
}
return 0; return 0;
} }

View File

@ -24,16 +24,12 @@ struct cpsw_switchdev_event_work {
unsigned long event; unsigned long event;
}; };
static int cpsw_port_stp_state_set(struct cpsw_priv *priv, static int cpsw_port_stp_state_set(struct cpsw_priv *priv, u8 state)
struct switchdev_trans *trans, u8 state)
{ {
struct cpsw_common *cpsw = priv->cpsw; struct cpsw_common *cpsw = priv->cpsw;
u8 cpsw_state; u8 cpsw_state;
int ret = 0; int ret = 0;
if (switchdev_trans_ph_prepare(trans))
return 0;
switch (state) { switch (state) {
case BR_STATE_FORWARDING: case BR_STATE_FORWARDING:
cpsw_state = ALE_PORT_STATE_FORWARD; cpsw_state = ALE_PORT_STATE_FORWARD;
@ -60,16 +56,12 @@ static int cpsw_port_stp_state_set(struct cpsw_priv *priv,
} }
static int cpsw_port_attr_br_flags_set(struct cpsw_priv *priv, static int cpsw_port_attr_br_flags_set(struct cpsw_priv *priv,
struct switchdev_trans *trans,
struct net_device *orig_dev, struct net_device *orig_dev,
unsigned long brport_flags) unsigned long brport_flags)
{ {
struct cpsw_common *cpsw = priv->cpsw; struct cpsw_common *cpsw = priv->cpsw;
bool unreg_mcast_add = false; bool unreg_mcast_add = false;
if (switchdev_trans_ph_prepare(trans))
return 0;
if (brport_flags & BR_MCAST_FLOOD) if (brport_flags & BR_MCAST_FLOOD)
unreg_mcast_add = true; unreg_mcast_add = true;
dev_dbg(priv->dev, "BR_MCAST_FLOOD: %d port %u\n", dev_dbg(priv->dev, "BR_MCAST_FLOOD: %d port %u\n",
@ -82,7 +74,6 @@ static int cpsw_port_attr_br_flags_set(struct cpsw_priv *priv,
} }
static int cpsw_port_attr_br_flags_pre_set(struct net_device *netdev, static int cpsw_port_attr_br_flags_pre_set(struct net_device *netdev,
struct switchdev_trans *trans,
unsigned long flags) unsigned long flags)
{ {
if (flags & ~(BR_LEARNING | BR_MCAST_FLOOD)) if (flags & ~(BR_LEARNING | BR_MCAST_FLOOD))
@ -92,8 +83,7 @@ static int cpsw_port_attr_br_flags_pre_set(struct net_device *netdev,
} }
static int cpsw_port_attr_set(struct net_device *ndev, static int cpsw_port_attr_set(struct net_device *ndev,
const struct switchdev_attr *attr, const struct switchdev_attr *attr)
struct switchdev_trans *trans)
{ {
struct cpsw_priv *priv = netdev_priv(ndev); struct cpsw_priv *priv = netdev_priv(ndev);
int ret; int ret;
@ -102,15 +92,15 @@ static int cpsw_port_attr_set(struct net_device *ndev,
switch (attr->id) { switch (attr->id) {
case SWITCHDEV_ATTR_ID_PORT_PRE_BRIDGE_FLAGS: case SWITCHDEV_ATTR_ID_PORT_PRE_BRIDGE_FLAGS:
ret = cpsw_port_attr_br_flags_pre_set(ndev, trans, ret = cpsw_port_attr_br_flags_pre_set(ndev,
attr->u.brport_flags); attr->u.brport_flags);
break; break;
case SWITCHDEV_ATTR_ID_PORT_STP_STATE: case SWITCHDEV_ATTR_ID_PORT_STP_STATE:
ret = cpsw_port_stp_state_set(priv, trans, attr->u.stp_state); ret = cpsw_port_stp_state_set(priv, attr->u.stp_state);
dev_dbg(priv->dev, "stp state: %u\n", attr->u.stp_state); dev_dbg(priv->dev, "stp state: %u\n", attr->u.stp_state);
break; break;
case SWITCHDEV_ATTR_ID_PORT_BRIDGE_FLAGS: case SWITCHDEV_ATTR_ID_PORT_BRIDGE_FLAGS:
ret = cpsw_port_attr_br_flags_set(priv, trans, attr->orig_dev, ret = cpsw_port_attr_br_flags_set(priv, attr->orig_dev,
attr->u.brport_flags); attr->u.brport_flags);
break; break;
default: default:

View File

@ -901,19 +901,14 @@ static void dpaa2_switch_teardown_irqs(struct fsl_mc_device *sw_dev)
} }
static int dpaa2_switch_port_attr_stp_state_set(struct net_device *netdev, static int dpaa2_switch_port_attr_stp_state_set(struct net_device *netdev,
struct switchdev_trans *trans,
u8 state) u8 state)
{ {
struct ethsw_port_priv *port_priv = netdev_priv(netdev); struct ethsw_port_priv *port_priv = netdev_priv(netdev);
if (switchdev_trans_ph_prepare(trans))
return 0;
return dpaa2_switch_port_set_stp_state(port_priv, state); return dpaa2_switch_port_set_stp_state(port_priv, state);
} }
static int dpaa2_switch_port_attr_br_flags_pre_set(struct net_device *netdev, static int dpaa2_switch_port_attr_br_flags_pre_set(struct net_device *netdev,
struct switchdev_trans *trans,
unsigned long flags) unsigned long flags)
{ {
if (flags & ~(BR_LEARNING | BR_FLOOD)) if (flags & ~(BR_LEARNING | BR_FLOOD))
@ -923,15 +918,11 @@ static int dpaa2_switch_port_attr_br_flags_pre_set(struct net_device *netdev,
} }
static int dpaa2_switch_port_attr_br_flags_set(struct net_device *netdev, static int dpaa2_switch_port_attr_br_flags_set(struct net_device *netdev,
struct switchdev_trans *trans,
unsigned long flags) unsigned long flags)
{ {
struct ethsw_port_priv *port_priv = netdev_priv(netdev); struct ethsw_port_priv *port_priv = netdev_priv(netdev);
int err = 0; int err = 0;
if (switchdev_trans_ph_prepare(trans))
return 0;
/* Learning is enabled per switch */ /* Learning is enabled per switch */
err = dpaa2_switch_set_learning(port_priv->ethsw_data, err = dpaa2_switch_set_learning(port_priv->ethsw_data,
!!(flags & BR_LEARNING)); !!(flags & BR_LEARNING));
@ -945,22 +936,21 @@ static int dpaa2_switch_port_attr_br_flags_set(struct net_device *netdev,
} }
static int dpaa2_switch_port_attr_set(struct net_device *netdev, static int dpaa2_switch_port_attr_set(struct net_device *netdev,
const struct switchdev_attr *attr, const struct switchdev_attr *attr)
struct switchdev_trans *trans)
{ {
int err = 0; int err = 0;
switch (attr->id) { switch (attr->id) {
case SWITCHDEV_ATTR_ID_PORT_STP_STATE: case SWITCHDEV_ATTR_ID_PORT_STP_STATE:
err = dpaa2_switch_port_attr_stp_state_set(netdev, trans, err = dpaa2_switch_port_attr_stp_state_set(netdev,
attr->u.stp_state); attr->u.stp_state);
break; break;
case SWITCHDEV_ATTR_ID_PORT_PRE_BRIDGE_FLAGS: case SWITCHDEV_ATTR_ID_PORT_PRE_BRIDGE_FLAGS:
err = dpaa2_switch_port_attr_br_flags_pre_set(netdev, trans, err = dpaa2_switch_port_attr_br_flags_pre_set(netdev,
attr->u.brport_flags); attr->u.brport_flags);
break; break;
case SWITCHDEV_ATTR_ID_PORT_BRIDGE_FLAGS: case SWITCHDEV_ATTR_ID_PORT_BRIDGE_FLAGS:
err = dpaa2_switch_port_attr_br_flags_set(netdev, trans, err = dpaa2_switch_port_attr_br_flags_set(netdev,
attr->u.brport_flags); attr->u.brport_flags);
break; break;
case SWITCHDEV_ATTR_ID_BRIDGE_VLAN_FILTERING: case SWITCHDEV_ATTR_ID_BRIDGE_VLAN_FILTERING:
@ -1197,8 +1187,7 @@ static int dpaa2_switch_port_attr_set_event(struct net_device *netdev,
{ {
int err; int err;
err = dpaa2_switch_port_attr_set(netdev, port_attr_info->attr, err = dpaa2_switch_port_attr_set(netdev, port_attr_info->attr);
port_attr_info->trans);
port_attr_info->handled = true; port_attr_info->handled = true;
return notifier_from_errno(err); return notifier_from_errno(err);

View File

@ -565,8 +565,7 @@ struct dsa_switch_ops {
* VLAN support * VLAN support
*/ */
int (*port_vlan_filtering)(struct dsa_switch *ds, int port, 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, int (*port_vlan_prepare)(struct dsa_switch *ds, int port,
const struct switchdev_obj_port_vlan *vlan); const struct switchdev_obj_port_vlan *vlan);
void (*port_vlan_add)(struct dsa_switch *ds, int port, void (*port_vlan_add)(struct dsa_switch *ds, int port,

View File

@ -239,7 +239,6 @@ struct switchdev_notifier_port_obj_info {
struct switchdev_notifier_port_attr_info { struct switchdev_notifier_port_attr_info {
struct switchdev_notifier_info info; /* must be first */ struct switchdev_notifier_info info; /* must be first */
const struct switchdev_attr *attr; const struct switchdev_attr *attr;
struct switchdev_trans *trans;
bool handled; bool handled;
}; };
@ -298,8 +297,7 @@ int switchdev_handle_port_attr_set(struct net_device *dev,
struct switchdev_notifier_port_attr_info *port_attr_info, struct switchdev_notifier_port_attr_info *port_attr_info,
bool (*check_cb)(const struct net_device *dev), bool (*check_cb)(const struct net_device *dev),
int (*set_cb)(struct net_device *dev, int (*set_cb)(struct net_device *dev,
const struct switchdev_attr *attr, const struct switchdev_attr *attr));
struct switchdev_trans *trans));
#else #else
static inline void switchdev_deferred_process(void) static inline void switchdev_deferred_process(void)
@ -390,8 +388,7 @@ switchdev_handle_port_attr_set(struct net_device *dev,
struct switchdev_notifier_port_attr_info *port_attr_info, struct switchdev_notifier_port_attr_info *port_attr_info,
bool (*check_cb)(const struct net_device *dev), bool (*check_cb)(const struct net_device *dev),
int (*set_cb)(struct net_device *dev, int (*set_cb)(struct net_device *dev,
const struct switchdev_attr *attr, const struct switchdev_attr *attr))
struct switchdev_trans *trans))
{ {
return 0; return 0;
} }

View File

@ -739,8 +739,7 @@ int ocelot_get_ts_info(struct ocelot *ocelot, int port,
void ocelot_set_ageing_time(struct ocelot *ocelot, unsigned int msecs); void ocelot_set_ageing_time(struct ocelot *ocelot, unsigned int msecs);
void ocelot_adjust_link(struct ocelot *ocelot, int port, void ocelot_adjust_link(struct ocelot *ocelot, int port,
struct phy_device *phydev); struct phy_device *phydev);
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 switchdev_trans *trans);
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);
int ocelot_port_bridge_join(struct ocelot *ocelot, int port, int ocelot_port_bridge_join(struct ocelot *ocelot, int port,
struct net_device *bridge); struct net_device *bridge);

View File

@ -128,19 +128,16 @@ static inline struct net_device *dsa_master_find_slave(struct net_device *dev,
} }
/* port.c */ /* port.c */
int dsa_port_set_state(struct dsa_port *dp, u8 state, int dsa_port_set_state(struct dsa_port *dp, u8 state);
struct switchdev_trans *trans);
int dsa_port_enable_rt(struct dsa_port *dp, struct phy_device *phy); int dsa_port_enable_rt(struct dsa_port *dp, struct phy_device *phy);
int dsa_port_enable(struct dsa_port *dp, struct phy_device *phy); int dsa_port_enable(struct dsa_port *dp, struct phy_device *phy);
void dsa_port_disable_rt(struct dsa_port *dp); void dsa_port_disable_rt(struct dsa_port *dp);
void dsa_port_disable(struct dsa_port *dp); void dsa_port_disable(struct dsa_port *dp);
int dsa_port_bridge_join(struct dsa_port *dp, struct net_device *br); int dsa_port_bridge_join(struct dsa_port *dp, struct net_device *br);
void dsa_port_bridge_leave(struct dsa_port *dp, struct net_device *br); void dsa_port_bridge_leave(struct dsa_port *dp, struct net_device *br);
int dsa_port_vlan_filtering(struct dsa_port *dp, bool vlan_filtering, int dsa_port_vlan_filtering(struct dsa_port *dp, bool vlan_filtering);
struct switchdev_trans *trans);
bool dsa_port_skip_vlan_configuration(struct dsa_port *dp); bool dsa_port_skip_vlan_configuration(struct dsa_port *dp);
int dsa_port_ageing_time(struct dsa_port *dp, clock_t ageing_clock, int dsa_port_ageing_time(struct dsa_port *dp, clock_t ageing_clock);
struct switchdev_trans *trans);
int dsa_port_mtu_change(struct dsa_port *dp, int new_mtu, int dsa_port_mtu_change(struct dsa_port *dp, int new_mtu,
bool propagate_upstream); bool propagate_upstream);
int dsa_port_fdb_add(struct dsa_port *dp, const unsigned char *addr, int dsa_port_fdb_add(struct dsa_port *dp, const unsigned char *addr,
@ -152,12 +149,9 @@ int dsa_port_mdb_add(const struct dsa_port *dp,
const struct switchdev_obj_port_mdb *mdb); const struct switchdev_obj_port_mdb *mdb);
int dsa_port_mdb_del(const struct dsa_port *dp, int dsa_port_mdb_del(const struct dsa_port *dp,
const struct switchdev_obj_port_mdb *mdb); const struct switchdev_obj_port_mdb *mdb);
int dsa_port_pre_bridge_flags(const struct dsa_port *dp, unsigned long flags, int dsa_port_pre_bridge_flags(const struct dsa_port *dp, unsigned long flags);
struct switchdev_trans *trans); int dsa_port_bridge_flags(const struct dsa_port *dp, unsigned long flags);
int dsa_port_bridge_flags(const struct dsa_port *dp, unsigned long flags, int dsa_port_mrouter(struct dsa_port *dp, bool mrouter);
struct switchdev_trans *trans);
int dsa_port_mrouter(struct dsa_port *dp, bool mrouter,
struct switchdev_trans *trans);
int dsa_port_vlan_add(struct dsa_port *dp, int dsa_port_vlan_add(struct dsa_port *dp,
const struct switchdev_obj_port_vlan *vlan); const struct switchdev_obj_port_vlan *vlan);
int dsa_port_vlan_del(struct dsa_port *dp, int dsa_port_vlan_del(struct dsa_port *dp,

View File

@ -40,17 +40,15 @@ static int dsa_port_notify(const struct dsa_port *dp, unsigned long e, void *v)
return notifier_to_errno(err); return notifier_to_errno(err);
} }
int dsa_port_set_state(struct dsa_port *dp, u8 state, int dsa_port_set_state(struct dsa_port *dp, u8 state)
struct switchdev_trans *trans)
{ {
struct dsa_switch *ds = dp->ds; struct dsa_switch *ds = dp->ds;
int port = dp->index; int port = dp->index;
if (switchdev_trans_ph_prepare(trans)) if (!ds->ops->port_stp_state_set)
return ds->ops->port_stp_state_set ? 0 : -EOPNOTSUPP; return -EOPNOTSUPP;
if (ds->ops->port_stp_state_set) ds->ops->port_stp_state_set(ds, port, state);
ds->ops->port_stp_state_set(ds, port, state);
if (ds->ops->port_fast_age) { if (ds->ops->port_fast_age) {
/* Fast age FDB entries or flush appropriate forwarding database /* Fast age FDB entries or flush appropriate forwarding database
@ -75,7 +73,7 @@ static void dsa_port_set_state_now(struct dsa_port *dp, u8 state)
{ {
int err; int err;
err = dsa_port_set_state(dp, state, NULL); err = dsa_port_set_state(dp, state);
if (err) if (err)
pr_err("DSA: failed to set STP state %u (%d)\n", state, err); pr_err("DSA: failed to set STP state %u (%d)\n", state, err);
} }
@ -145,7 +143,7 @@ int dsa_port_bridge_join(struct dsa_port *dp, struct net_device *br)
int err; int err;
/* Set the flooding mode before joining the port in the switch */ /* Set the flooding mode before joining the port in the switch */
err = dsa_port_bridge_flags(dp, BR_FLOOD | BR_MCAST_FLOOD, NULL); err = dsa_port_bridge_flags(dp, BR_FLOOD | BR_MCAST_FLOOD);
if (err) if (err)
return err; return err;
@ -158,7 +156,7 @@ int dsa_port_bridge_join(struct dsa_port *dp, struct net_device *br)
/* The bridging is rolled back on error */ /* The bridging is rolled back on error */
if (err) { if (err) {
dsa_port_bridge_flags(dp, 0, NULL); dsa_port_bridge_flags(dp, 0);
dp->bridge_dev = NULL; dp->bridge_dev = NULL;
} }
@ -185,7 +183,7 @@ void dsa_port_bridge_leave(struct dsa_port *dp, struct net_device *br)
pr_err("DSA: failed to notify DSA_NOTIFIER_BRIDGE_LEAVE\n"); pr_err("DSA: failed to notify DSA_NOTIFIER_BRIDGE_LEAVE\n");
/* Port is leaving the bridge, disable flooding */ /* Port is leaving the bridge, disable flooding */
dsa_port_bridge_flags(dp, 0, NULL); dsa_port_bridge_flags(dp, 0);
/* Port left the bridge, put in BR_STATE_DISABLED by the bridge layer, /* Port left the bridge, put in BR_STATE_DISABLED by the bridge layer,
* so allow it to be in BR_STATE_FORWARDING to be kept functional * so allow it to be in BR_STATE_FORWARDING to be kept functional
@ -259,43 +257,36 @@ static bool dsa_port_can_apply_vlan_filtering(struct dsa_port *dp,
return true; return true;
} }
int dsa_port_vlan_filtering(struct dsa_port *dp, bool vlan_filtering, int dsa_port_vlan_filtering(struct dsa_port *dp, bool vlan_filtering)
struct switchdev_trans *trans)
{ {
struct dsa_switch *ds = dp->ds; struct dsa_switch *ds = dp->ds;
bool apply;
int err; int err;
if (switchdev_trans_ph_prepare(trans)) { if (!ds->ops->port_vlan_filtering)
bool apply; return -EOPNOTSUPP;
if (!ds->ops->port_vlan_filtering) /* We are called from dsa_slave_switchdev_blocking_event(),
return -EOPNOTSUPP; * which is not under rcu_read_lock(), unlike
* dsa_slave_switchdev_event().
/* We are called from dsa_slave_switchdev_blocking_event(), */
* which is not under rcu_read_lock(), unlike rcu_read_lock();
* dsa_slave_switchdev_event(). apply = dsa_port_can_apply_vlan_filtering(dp, vlan_filtering);
*/ rcu_read_unlock();
rcu_read_lock(); if (!apply)
apply = dsa_port_can_apply_vlan_filtering(dp, vlan_filtering); return -EINVAL;
rcu_read_unlock();
if (!apply)
return -EINVAL;
}
if (dsa_port_is_vlan_filtering(dp) == vlan_filtering) if (dsa_port_is_vlan_filtering(dp) == vlan_filtering)
return 0; 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) if (err)
return err; return err;
if (switchdev_trans_ph_commit(trans)) { if (ds->vlan_filtering_is_global)
if (ds->vlan_filtering_is_global) ds->vlan_filtering = vlan_filtering;
ds->vlan_filtering = vlan_filtering; else
else dp->vlan_filtering = vlan_filtering;
dp->vlan_filtering = vlan_filtering;
}
return 0; return 0;
} }
@ -314,26 +305,29 @@ bool dsa_port_skip_vlan_configuration(struct dsa_port *dp)
!br_vlan_enabled(dp->bridge_dev)); !br_vlan_enabled(dp->bridge_dev));
} }
int dsa_port_ageing_time(struct dsa_port *dp, clock_t ageing_clock, int dsa_port_ageing_time(struct dsa_port *dp, clock_t ageing_clock)
struct switchdev_trans *trans)
{ {
unsigned long ageing_jiffies = clock_t_to_jiffies(ageing_clock); unsigned long ageing_jiffies = clock_t_to_jiffies(ageing_clock);
unsigned int ageing_time = jiffies_to_msecs(ageing_jiffies); unsigned int ageing_time = jiffies_to_msecs(ageing_jiffies);
struct dsa_notifier_ageing_time_info info = { struct dsa_notifier_ageing_time_info info;
.ageing_time = ageing_time, struct switchdev_trans trans;
.trans = trans, int err;
};
if (switchdev_trans_ph_prepare(trans)) info.ageing_time = ageing_time;
return dsa_port_notify(dp, DSA_NOTIFIER_AGEING_TIME, &info); info.trans = &trans;
trans.ph_prepare = true;
err = dsa_port_notify(dp, DSA_NOTIFIER_AGEING_TIME, &info);
if (err)
return err;
dp->ageing_time = ageing_time; dp->ageing_time = ageing_time;
trans.ph_prepare = false;
return dsa_port_notify(dp, DSA_NOTIFIER_AGEING_TIME, &info); return dsa_port_notify(dp, DSA_NOTIFIER_AGEING_TIME, &info);
} }
int dsa_port_pre_bridge_flags(const struct dsa_port *dp, unsigned long flags, int dsa_port_pre_bridge_flags(const struct dsa_port *dp, unsigned long flags)
struct switchdev_trans *trans)
{ {
struct dsa_switch *ds = dp->ds; struct dsa_switch *ds = dp->ds;
@ -344,16 +338,12 @@ int dsa_port_pre_bridge_flags(const struct dsa_port *dp, unsigned long flags,
return 0; return 0;
} }
int dsa_port_bridge_flags(const struct dsa_port *dp, unsigned long flags, int dsa_port_bridge_flags(const struct dsa_port *dp, unsigned long flags)
struct switchdev_trans *trans)
{ {
struct dsa_switch *ds = dp->ds; struct dsa_switch *ds = dp->ds;
int port = dp->index; int port = dp->index;
int err = 0; int err = 0;
if (switchdev_trans_ph_prepare(trans))
return 0;
if (ds->ops->port_egress_floods) if (ds->ops->port_egress_floods)
err = ds->ops->port_egress_floods(ds, port, flags & BR_FLOOD, err = ds->ops->port_egress_floods(ds, port, flags & BR_FLOOD,
flags & BR_MCAST_FLOOD); flags & BR_MCAST_FLOOD);
@ -361,14 +351,13 @@ int dsa_port_bridge_flags(const struct dsa_port *dp, unsigned long flags,
return err; return err;
} }
int dsa_port_mrouter(struct dsa_port *dp, bool mrouter, int dsa_port_mrouter(struct dsa_port *dp, bool mrouter)
struct switchdev_trans *trans)
{ {
struct dsa_switch *ds = dp->ds; struct dsa_switch *ds = dp->ds;
int port = dp->index; int port = dp->index;
if (switchdev_trans_ph_prepare(trans)) if (!ds->ops->port_egress_floods)
return ds->ops->port_egress_floods ? 0 : -EOPNOTSUPP; return -EOPNOTSUPP;
return ds->ops->port_egress_floods(ds, port, true, mrouter); return ds->ops->port_egress_floods(ds, port, true, mrouter);
} }

View File

@ -268,32 +268,29 @@ static int dsa_slave_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
} }
static int dsa_slave_port_attr_set(struct net_device *dev, static int dsa_slave_port_attr_set(struct net_device *dev,
const struct switchdev_attr *attr, const struct switchdev_attr *attr)
struct switchdev_trans *trans)
{ {
struct dsa_port *dp = dsa_slave_to_port(dev); struct dsa_port *dp = dsa_slave_to_port(dev);
int ret; int ret;
switch (attr->id) { switch (attr->id) {
case SWITCHDEV_ATTR_ID_PORT_STP_STATE: case SWITCHDEV_ATTR_ID_PORT_STP_STATE:
ret = dsa_port_set_state(dp, attr->u.stp_state, trans); ret = dsa_port_set_state(dp, attr->u.stp_state);
break; break;
case SWITCHDEV_ATTR_ID_BRIDGE_VLAN_FILTERING: case SWITCHDEV_ATTR_ID_BRIDGE_VLAN_FILTERING:
ret = dsa_port_vlan_filtering(dp, attr->u.vlan_filtering, ret = dsa_port_vlan_filtering(dp, attr->u.vlan_filtering);
trans);
break; break;
case SWITCHDEV_ATTR_ID_BRIDGE_AGEING_TIME: case SWITCHDEV_ATTR_ID_BRIDGE_AGEING_TIME:
ret = dsa_port_ageing_time(dp, attr->u.ageing_time, trans); ret = dsa_port_ageing_time(dp, attr->u.ageing_time);
break; break;
case SWITCHDEV_ATTR_ID_PORT_PRE_BRIDGE_FLAGS: case SWITCHDEV_ATTR_ID_PORT_PRE_BRIDGE_FLAGS:
ret = dsa_port_pre_bridge_flags(dp, attr->u.brport_flags, ret = dsa_port_pre_bridge_flags(dp, attr->u.brport_flags);
trans);
break; break;
case SWITCHDEV_ATTR_ID_PORT_BRIDGE_FLAGS: case SWITCHDEV_ATTR_ID_PORT_BRIDGE_FLAGS:
ret = dsa_port_bridge_flags(dp, attr->u.brport_flags, trans); ret = dsa_port_bridge_flags(dp, attr->u.brport_flags);
break; break;
case SWITCHDEV_ATTR_ID_BRIDGE_MROUTER: case SWITCHDEV_ATTR_ID_BRIDGE_MROUTER:
ret = dsa_port_mrouter(dp->cpu_dp, attr->u.mrouter, trans); ret = dsa_port_mrouter(dp->cpu_dp, attr->u.mrouter);
break; break;
default: default:
ret = -EOPNOTSUPP; ret = -EOPNOTSUPP;

View File

@ -139,17 +139,8 @@ static int dsa_switch_bridge_leave(struct dsa_switch *ds,
} }
} }
if (unset_vlan_filtering) { if (unset_vlan_filtering) {
struct switchdev_trans trans;
trans.ph_prepare = true;
err = dsa_port_vlan_filtering(dsa_to_port(ds, info->port), err = dsa_port_vlan_filtering(dsa_to_port(ds, info->port),
false, &trans); false);
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) if (err && err != EOPNOTSUPP)
return err; return err;
} }

View File

@ -100,15 +100,13 @@ static int switchdev_deferred_enqueue(struct net_device *dev,
static int switchdev_port_attr_notify(enum switchdev_notifier_type nt, static int switchdev_port_attr_notify(enum switchdev_notifier_type nt,
struct net_device *dev, struct net_device *dev,
const struct switchdev_attr *attr, const struct switchdev_attr *attr)
struct switchdev_trans *trans)
{ {
int err; int err;
int rc; int rc;
struct switchdev_notifier_port_attr_info attr_info = { struct switchdev_notifier_port_attr_info attr_info = {
.attr = attr, .attr = attr,
.trans = trans,
.handled = false, .handled = false,
}; };
@ -129,34 +127,7 @@ static int switchdev_port_attr_notify(enum switchdev_notifier_type nt,
static int switchdev_port_attr_set_now(struct net_device *dev, static int switchdev_port_attr_set_now(struct net_device *dev,
const struct switchdev_attr *attr) const struct switchdev_attr *attr)
{ {
struct switchdev_trans trans; return switchdev_port_attr_notify(SWITCHDEV_PORT_ATTR_SET, dev, attr);
int err;
/* Phase I: prepare for attr set. Driver/device should fail
* here if there are going to be issues in the commit phase,
* such as lack of resources or support. The driver/device
* should reserve resources needed for the commit phase here,
* but should not commit the attr.
*/
trans.ph_prepare = true;
err = switchdev_port_attr_notify(SWITCHDEV_PORT_ATTR_SET, dev, attr,
&trans);
if (err)
return err;
/* Phase II: commit attr set. This cannot fail as a fault
* of driver/device. If it does, it's a bug in the driver/device
* because the driver said everythings was OK in phase I.
*/
trans.ph_prepare = false;
err = switchdev_port_attr_notify(SWITCHDEV_PORT_ATTR_SET, dev, attr,
&trans);
WARN(err, "%s: Commit of attribute (id=%d) failed.\n",
dev->name, attr->id);
return err;
} }
static void switchdev_port_attr_set_deferred(struct net_device *dev, static void switchdev_port_attr_set_deferred(struct net_device *dev,
@ -186,10 +157,6 @@ static int switchdev_port_attr_set_defer(struct net_device *dev,
* @dev: port device * @dev: port device
* @attr: attribute to set * @attr: attribute to set
* *
* Use a 2-phase prepare-commit transaction model to ensure
* system is not left in a partially updated state due to
* failure from driver/device.
*
* rtnl_lock must be held and must not be in atomic section, * rtnl_lock must be held and must not be in atomic section,
* in case SWITCHDEV_F_DEFER flag is not set. * in case SWITCHDEV_F_DEFER flag is not set.
*/ */
@ -519,8 +486,7 @@ static int __switchdev_handle_port_attr_set(struct net_device *dev,
struct switchdev_notifier_port_attr_info *port_attr_info, struct switchdev_notifier_port_attr_info *port_attr_info,
bool (*check_cb)(const struct net_device *dev), bool (*check_cb)(const struct net_device *dev),
int (*set_cb)(struct net_device *dev, int (*set_cb)(struct net_device *dev,
const struct switchdev_attr *attr, const struct switchdev_attr *attr))
struct switchdev_trans *trans))
{ {
struct net_device *lower_dev; struct net_device *lower_dev;
struct list_head *iter; struct list_head *iter;
@ -528,8 +494,7 @@ static int __switchdev_handle_port_attr_set(struct net_device *dev,
if (check_cb(dev)) { if (check_cb(dev)) {
port_attr_info->handled = true; port_attr_info->handled = true;
return set_cb(dev, port_attr_info->attr, return set_cb(dev, port_attr_info->attr);
port_attr_info->trans);
} }
/* Switch ports might be stacked under e.g. a LAG. Ignore the /* Switch ports might be stacked under e.g. a LAG. Ignore the
@ -556,8 +521,7 @@ int switchdev_handle_port_attr_set(struct net_device *dev,
struct switchdev_notifier_port_attr_info *port_attr_info, struct switchdev_notifier_port_attr_info *port_attr_info,
bool (*check_cb)(const struct net_device *dev), bool (*check_cb)(const struct net_device *dev),
int (*set_cb)(struct net_device *dev, int (*set_cb)(struct net_device *dev,
const struct switchdev_attr *attr, const struct switchdev_attr *attr))
struct switchdev_trans *trans))
{ {
int err; int err;