/* Holds rate groups associated with an E-Switch. */
struct mlx5_qos_domain {
+ /* Serializes access to all qos changes in the qos domain. */
+ struct mutex lock;
/* List of all mlx5_esw_rate_groups. */
struct list_head groups;
};
+static void esw_qos_lock(struct mlx5_eswitch *esw)
+{
+ mutex_lock(&esw->qos.domain->lock);
+}
+
+static void esw_qos_unlock(struct mlx5_eswitch *esw)
+{
+ mutex_unlock(&esw->qos.domain->lock);
+}
+
+static void esw_assert_qos_lock_held(struct mlx5_eswitch *esw)
+{
+ lockdep_assert_held(&esw->qos.domain->lock);
+}
+
static struct mlx5_qos_domain *esw_qos_domain_alloc(void)
{
struct mlx5_qos_domain *qos_domain;
if (!qos_domain)
return NULL;
+ mutex_init(&qos_domain->lock);
INIT_LIST_HEAD(&qos_domain->groups);
return qos_domain;
bool min_rate_supported;
int err;
- lockdep_assert_held(&esw->state_lock);
+ esw_assert_qos_lock_held(esw);
fw_max_bw_share = MLX5_CAP_QOS(vport->dev, max_tsar_bw_share);
min_rate_supported = MLX5_CAP_QOS(vport->dev, esw_bw_share) &&
fw_max_bw_share >= MLX5_MIN_BW_SHARE;
bool max_rate_supported;
int err;
- lockdep_assert_held(&esw->state_lock);
+ esw_assert_qos_lock_held(esw);
max_rate_supported = MLX5_CAP_QOS(vport->dev, esw_rate_limit);
if (max_rate && !max_rate_supported)
struct mlx5_esw_rate_group *new_group, *curr_group;
int err;
- if (!vport->enabled)
- return -EINVAL;
-
+ esw_assert_qos_lock_held(esw);
curr_group = vport->qos.group;
new_group = group ?: esw->qos.group0;
if (curr_group == new_group)
struct mlx5_esw_rate_group *group;
int err;
+ esw_assert_qos_lock_held(esw);
if (!MLX5_CAP_QOS(esw->dev, log_esw_max_sched_depth))
return ERR_PTR(-EOPNOTSUPP);
{
int err = 0;
- lockdep_assert_held(&esw->state_lock);
-
+ esw_assert_qos_lock_held(esw);
if (!refcount_inc_not_zero(&esw->qos.refcnt)) {
/* esw_qos_create() set refcount to 1 only on success.
* No need to decrement on failure.
static void esw_qos_put(struct mlx5_eswitch *esw)
{
- lockdep_assert_held(&esw->state_lock);
+ esw_assert_qos_lock_held(esw);
if (refcount_dec_and_test(&esw->qos.refcnt))
esw_qos_destroy(esw);
}
struct mlx5_eswitch *esw = vport->dev->priv.eswitch;
int err;
- lockdep_assert_held(&esw->state_lock);
+ esw_assert_qos_lock_held(esw);
if (vport->qos.enabled)
return 0;
int err;
lockdep_assert_held(&esw->state_lock);
+ esw_qos_lock(esw);
if (!vport->qos.enabled)
- return;
+ goto unlock;
WARN(vport->qos.group != esw->qos.group0,
"Disabling QoS on port before detaching it from group");
trace_mlx5_esw_vport_qos_destroy(dev, vport);
esw_qos_put(esw);
+unlock:
+ esw_qos_unlock(esw);
}
int mlx5_esw_qos_set_vport_rate(struct mlx5_vport *vport, u32 max_rate, u32 min_rate)
struct mlx5_eswitch *esw = vport->dev->priv.eswitch;
int err;
- lockdep_assert_held(&esw->state_lock);
+ esw_qos_lock(esw);
err = esw_qos_vport_enable(vport, 0, 0, NULL);
if (err)
- return err;
+ goto unlock;
err = esw_qos_set_vport_min_rate(vport, min_rate, NULL);
if (!err)
err = esw_qos_set_vport_max_rate(vport, max_rate, NULL);
+unlock:
+ esw_qos_unlock(esw);
return err;
}
+bool mlx5_esw_qos_get_vport_rate(struct mlx5_vport *vport, u32 *max_rate, u32 *min_rate)
+{
+ struct mlx5_eswitch *esw = vport->dev->priv.eswitch;
+ bool enabled;
+
+ esw_qos_lock(esw);
+ enabled = vport->qos.enabled;
+ if (enabled) {
+ *max_rate = vport->qos.max_rate;
+ *min_rate = vport->qos.min_rate;
+ }
+ esw_qos_unlock(esw);
+ return enabled;
+}
+
static u32 mlx5_esw_qos_lag_link_speed_get_locked(struct mlx5_core_dev *mdev)
{
struct ethtool_link_ksettings lksettings;
return err;
}
- mutex_lock(&esw->state_lock);
+ esw_qos_lock(esw);
if (!vport->qos.enabled) {
/* Eswitch QoS wasn't enabled yet. Enable it and vport QoS. */
err = esw_qos_vport_enable(vport, rate_mbps, vport->qos.bw_share, NULL);
vport->qos.esw_sched_elem_ix,
bitmask);
}
- mutex_unlock(&esw->state_lock);
+ esw_qos_unlock(esw);
return err;
}
if (err)
return err;
- mutex_lock(&esw->state_lock);
+ esw_qos_lock(esw);
err = esw_qos_vport_enable(vport, 0, 0, extack);
if (err)
goto unlock;
err = esw_qos_set_vport_min_rate(vport, tx_share, extack);
unlock:
- mutex_unlock(&esw->state_lock);
+ esw_qos_unlock(esw);
return err;
}
if (err)
return err;
- mutex_lock(&esw->state_lock);
+ esw_qos_lock(esw);
err = esw_qos_vport_enable(vport, 0, 0, extack);
if (err)
goto unlock;
err = esw_qos_set_vport_max_rate(vport, tx_max, extack);
unlock:
- mutex_unlock(&esw->state_lock);
+ esw_qos_unlock(esw);
return err;
}
if (err)
return err;
- mutex_lock(&esw->state_lock);
+ esw_qos_lock(esw);
err = esw_qos_set_group_min_rate(group, tx_share, extack);
- mutex_unlock(&esw->state_lock);
+ esw_qos_unlock(esw);
return err;
}
if (err)
return err;
- mutex_lock(&esw->state_lock);
+ esw_qos_lock(esw);
err = esw_qos_set_group_max_rate(group, tx_max, extack);
- mutex_unlock(&esw->state_lock);
+ esw_qos_unlock(esw);
return err;
}
if (IS_ERR(esw))
return PTR_ERR(esw);
- mutex_lock(&esw->state_lock);
+ esw_qos_lock(esw);
if (esw->mode != MLX5_ESWITCH_OFFLOADS) {
NL_SET_ERR_MSG_MOD(extack,
"Rate node creation supported only in switchdev mode");
*priv = group;
unlock:
- mutex_unlock(&esw->state_lock);
+ esw_qos_unlock(esw);
return err;
}
struct mlx5_eswitch *esw = group->esw;
int err;
- mutex_lock(&esw->state_lock);
+ esw_qos_lock(esw);
err = __esw_qos_destroy_rate_group(group, extack);
esw_qos_put(esw);
- mutex_unlock(&esw->state_lock);
+ esw_qos_unlock(esw);
return err;
}
return -EOPNOTSUPP;
}
- mutex_lock(&esw->state_lock);
+ esw_qos_lock(esw);
if (!vport->qos.enabled && !group)
goto unlock;
if (!err)
err = esw_qos_vport_update_group(vport, group, extack);
unlock:
- mutex_unlock(&esw->state_lock);
+ esw_qos_unlock(esw);
return err;
}