In a future commit we will have to call vsc9959_tas_guard_bands_update()
from ocelot_port_update_active_preemptible_tcs(), and that will be
impossible due to the AB/BA locking dependencies between
ocelot->tas_lock and ocelot->fwd_domain_lock.
Just like we did in commit
3ff468ef987e ("net: mscc: ocelot: remove
struct ocelot_mm_state :: lock"), the only solution is to expand the
scope of ocelot->fwd_domain_lock for it to also serialize changes made
to the Time-Aware Shaper, because those will have to result in a
recalculation of cut-through TCs, which is something that depends on the
forwarding domain.
Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
Message-ID: <
20230705104422.49025-2-vladimir.oltean@nxp.com>
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
ocelot_port_set_maxlen(ocelot, port, new_mtu);
ocelot_port_set_maxlen(ocelot, port, new_mtu);
- mutex_lock(&ocelot->tas_lock);
+ mutex_lock(&ocelot->fwd_domain_lock);
if (ocelot_port->taprio && felix->info->tas_guard_bands_update)
felix->info->tas_guard_bands_update(ocelot, port);
if (ocelot_port->taprio && felix->info->tas_guard_bands_update)
felix->info->tas_guard_bands_update(ocelot, port);
- mutex_unlock(&ocelot->tas_lock);
+ mutex_unlock(&ocelot->fwd_domain_lock);
- lockdep_assert_held(&ocelot->tas_lock);
+ lockdep_assert_held(&ocelot->fwd_domain_lock);
taprio = ocelot_port->taprio;
taprio = ocelot_port->taprio;
vsc9959_tas_min_gate_lengths(taprio, min_gate_len);
vsc9959_tas_min_gate_lengths(taprio, min_gate_len);
- mutex_lock(&ocelot->fwd_domain_lock);
-
for (tc = 0; tc < OCELOT_NUM_TC; tc++) {
u32 requested_max_sdu = vsc9959_tas_tc_max_sdu(taprio, tc);
u64 remaining_gate_len_ps;
for (tc = 0; tc < OCELOT_NUM_TC; tc++) {
u32 requested_max_sdu = vsc9959_tas_tc_max_sdu(taprio, tc);
u64 remaining_gate_len_ps;
ocelot_write_rix(ocelot, maxlen, QSYS_PORT_MAX_SDU, port);
ocelot->ops->cut_through_fwd(ocelot);
ocelot_write_rix(ocelot, maxlen, QSYS_PORT_MAX_SDU, port);
ocelot->ops->cut_through_fwd(ocelot);
-
- mutex_unlock(&ocelot->fwd_domain_lock);
}
static void vsc9959_sched_speed_set(struct ocelot *ocelot, int port,
}
static void vsc9959_sched_speed_set(struct ocelot *ocelot, int port,
- mutex_lock(&ocelot->tas_lock);
+ mutex_lock(&ocelot->fwd_domain_lock);
ocelot_rmw_rix(ocelot,
QSYS_TAG_CONFIG_LINK_SPEED(tas_speed),
ocelot_rmw_rix(ocelot,
QSYS_TAG_CONFIG_LINK_SPEED(tas_speed),
if (ocelot_port->taprio)
vsc9959_tas_guard_bands_update(ocelot, port);
if (ocelot_port->taprio)
vsc9959_tas_guard_bands_update(ocelot, port);
- mutex_unlock(&ocelot->tas_lock);
+ mutex_unlock(&ocelot->fwd_domain_lock);
}
static void vsc9959_new_base_time(struct ocelot *ocelot, ktime_t base_time,
}
static void vsc9959_new_base_time(struct ocelot *ocelot, ktime_t base_time,
- mutex_lock(&ocelot->tas_lock);
+ mutex_lock(&ocelot->fwd_domain_lock);
if (taprio->cmd == TAPRIO_CMD_DESTROY) {
ocelot_port_mqprio(ocelot, port, &taprio->mqprio);
if (taprio->cmd == TAPRIO_CMD_DESTROY) {
ocelot_port_mqprio(ocelot, port, &taprio->mqprio);
vsc9959_tas_guard_bands_update(ocelot, port);
vsc9959_tas_guard_bands_update(ocelot, port);
- mutex_unlock(&ocelot->tas_lock);
+ mutex_unlock(&ocelot->fwd_domain_lock);
return 0;
} else if (taprio->cmd != TAPRIO_CMD_REPLACE) {
ret = -EOPNOTSUPP;
return 0;
} else if (taprio->cmd != TAPRIO_CMD_REPLACE) {
ret = -EOPNOTSUPP;
ocelot_port->taprio = taprio_offload_get(taprio);
vsc9959_tas_guard_bands_update(ocelot, port);
ocelot_port->taprio = taprio_offload_get(taprio);
vsc9959_tas_guard_bands_update(ocelot, port);
- mutex_unlock(&ocelot->tas_lock);
+ mutex_unlock(&ocelot->fwd_domain_lock);
taprio->mqprio.qopt.num_tc = 0;
ocelot_port_mqprio(ocelot, port, &taprio->mqprio);
err_unlock:
taprio->mqprio.qopt.num_tc = 0;
ocelot_port_mqprio(ocelot, port, &taprio->mqprio);
err_unlock:
- mutex_unlock(&ocelot->tas_lock);
+ mutex_unlock(&ocelot->fwd_domain_lock);
- mutex_lock(&ocelot->tas_lock);
+ mutex_lock(&ocelot->fwd_domain_lock);
for (port = 0; port < ocelot->num_phys_ports; port++) {
ocelot_port = ocelot->ports[port];
for (port = 0; port < ocelot->num_phys_ports; port++) {
ocelot_port = ocelot->ports[port];
QSYS_TAG_CONFIG_ENABLE,
QSYS_TAG_CONFIG, port);
}
QSYS_TAG_CONFIG_ENABLE,
QSYS_TAG_CONFIG, port);
}
- mutex_unlock(&ocelot->tas_lock);
+ mutex_unlock(&ocelot->fwd_domain_lock);
}
static int vsc9959_qos_port_cbs_set(struct dsa_switch *ds, int port,
}
static int vsc9959_qos_port_cbs_set(struct dsa_switch *ds, int port,
+static int vsc9959_qos_port_mqprio(struct ocelot *ocelot, int port,
+ struct tc_mqprio_qopt_offload *mqprio)
+{
+ int ret;
+
+ mutex_lock(&ocelot->fwd_domain_lock);
+ ret = ocelot_port_mqprio(ocelot, port, mqprio);
+ mutex_unlock(&ocelot->fwd_domain_lock);
+
+ return ret;
+}
+
static int vsc9959_port_setup_tc(struct dsa_switch *ds, int port,
enum tc_setup_type type,
void *type_data)
static int vsc9959_port_setup_tc(struct dsa_switch *ds, int port,
enum tc_setup_type type,
void *type_data)
case TC_SETUP_QDISC_TAPRIO:
return vsc9959_qos_port_tas_set(ocelot, port, type_data);
case TC_SETUP_QDISC_MQPRIO:
case TC_SETUP_QDISC_TAPRIO:
return vsc9959_qos_port_tas_set(ocelot, port, type_data);
case TC_SETUP_QDISC_MQPRIO:
- return ocelot_port_mqprio(ocelot, port, type_data);
+ return vsc9959_qos_port_mqprio(ocelot, port, type_data);
case TC_SETUP_QDISC_CBS:
return vsc9959_qos_port_cbs_set(ds, port, type_data);
default:
case TC_SETUP_QDISC_CBS:
return vsc9959_qos_port_cbs_set(ds, port, type_data);
default:
mutex_init(&ocelot->mact_lock);
mutex_init(&ocelot->fwd_domain_lock);
mutex_init(&ocelot->mact_lock);
mutex_init(&ocelot->fwd_domain_lock);
- mutex_init(&ocelot->tas_lock);
spin_lock_init(&ocelot->ptp_clock_lock);
spin_lock_init(&ocelot->ts_id_lock);
spin_lock_init(&ocelot->ptp_clock_lock);
spin_lock_init(&ocelot->ts_id_lock);
{
struct ocelot_mm_state *mm = &ocelot->mm[port];
{
struct ocelot_mm_state *mm = &ocelot->mm[port];
- mutex_lock(&ocelot->fwd_domain_lock);
+ lockdep_assert_held(&ocelot->fwd_domain_lock);
if (mm->preemptible_tcs == preemptible_tcs)
if (mm->preemptible_tcs == preemptible_tcs)
mm->preemptible_tcs = preemptible_tcs;
ocelot_port_update_active_preemptible_tcs(ocelot, port);
mm->preemptible_tcs = preemptible_tcs;
ocelot_port_update_active_preemptible_tcs(ocelot, port);
-
-out_unlock:
- mutex_unlock(&ocelot->fwd_domain_lock);
}
static void ocelot_mm_update_port_status(struct ocelot *ocelot, int port)
}
static void ocelot_mm_update_port_status(struct ocelot *ocelot, int port)
struct mutex stat_view_lock;
/* Lock for serializing access to the MAC table */
struct mutex mact_lock;
struct mutex stat_view_lock;
/* Lock for serializing access to the MAC table */
struct mutex mact_lock;
- /* Lock for serializing forwarding domain changes */
+ /* Lock for serializing forwarding domain changes, including the
+ * configuration of the Time-Aware Shaper, MAC Merge layer and
+ * cut-through forwarding, on which it depends
+ */
struct mutex fwd_domain_lock;
struct mutex fwd_domain_lock;
- /* Lock for serializing Time-Aware Shaper changes */
- struct mutex tas_lock;
-
struct workqueue_struct *owq;
u8 ptp:1;
struct workqueue_struct *owq;
u8 ptp:1;