1
0
Fork 0
mirror of synced 2025-03-06 20:59:54 +01:00
linux/drivers/net/dsa/mv88e6xxx
Vladimir Oltean a7d82367da net: dsa: mv88e6xxx: avoid reg_lock deadlock in mv88e6xxx_setup_port()
In the blamed commit, it was not noticed that one implementation of
chip->info->ops->phylink_get_caps(), called by mv88e6xxx_get_caps(),
may access hardware registers, and in doing so, it takes the
mv88e6xxx_reg_lock(). Namely, this is mv88e6352_phylink_get_caps().

This is a problem because mv88e6xxx_get_caps(), apart from being
a top-level function (method invoked by dsa_switch_ops), is now also
directly called from mv88e6xxx_setup_port(), which runs under the
mv88e6xxx_reg_lock() taken by mv88e6xxx_setup(). Therefore, when running
on mv88e6352, the reg_lock would be acquired a second time and the
system would deadlock on driver probe.

The things that mv88e6xxx_setup() can compete with in terms of register
access with are the IRQ handlers and MDIO bus operations registered by
mv88e6xxx_probe(). So there is a real need to acquire the register lock.

The register lock can, in principle, be dropped and re-acquired pretty
much at will within the driver, as long as no operations that involve
waiting for indirect access to complete (essentially, callers of
mv88e6xxx_smi_direct_wait() and mv88e6xxx_wait_mask()) are interrupted
with the lock released. However, I would guess that in mv88e6xxx_setup(),
the critical section is kept open for such a long time just in order to
optimize away multiple lock/unlock operations on the registers.

We could, in principle, drop the reg_lock right before the
mv88e6xxx_setup_port() -> mv88e6xxx_get_caps() call, and
re-acquire it immediately afterwards. But this would look ugly, because
mv88e6xxx_setup_port() would release a lock which it didn't acquire, but
the caller did.

A cleaner solution to this issue comes from the observation that struct
mv88e6xxxx_ops methods generally assume they are called with the
reg_lock already acquired. Whereas mv88e6352_phylink_get_caps() is more
the exception rather than the norm, in that it acquires the lock itself.

Let's enforce the same locking pattern/convention for
chip->info->ops->phylink_get_caps() as well, and make
mv88e6xxx_get_caps(), the top-level function, acquire the register lock
explicitly, for this one implementation that will access registers for
port 4 to work properly.

This means that mv88e6xxx_setup_port() will no longer call the top-level
function, but the low-level mv88e6xxx_ops method which expects the
correct calling context (register lock held).

Compared to chip->info->ops->phylink_get_caps(), mv88e6xxx_get_caps()
also fixes up the supported_interfaces bitmap for internal ports, since
that can be done generically and does not require per-switch knowledge.
That's code which will no longer execute, however mv88e6xxx_setup_port()
doesn't need that. It just needs to look at the mac_capabilities bitmap.

Fixes: cc1049ccee ("net: dsa: mv88e6xxx: fix speed setting for CPU/DSA ports")
Reported-by: Maksim Kiselev <bigunclemax@gmail.com>
Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
Tested-by: Maksim Kiselev <bigunclemax@gmail.com>
Link: https://lore.kernel.org/r/20221214110120.3368472-1-vladimir.oltean@nxp.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
2022-12-15 15:42:23 +01:00
..
chip.c net: dsa: mv88e6xxx: avoid reg_lock deadlock in mv88e6xxx_setup_port() 2022-12-15 15:42:23 +01:00
chip.h net: dsa: mv88e6xxx: get rid of SPEED_MAX setting 2022-06-23 20:26:41 -07:00
devlink.c net: devlink: let the core report the driver name instead of the drivers 2022-11-30 21:49:38 -08:00
devlink.h net: dsa: tear down devlink port regions when tearing down the devlink port on error 2021-09-19 13:05:44 +01:00
global1.c dsa: mv88e6xxx: Fix MTU definition 2021-09-27 13:31:10 +01:00
global1.h net: dsa: mv88e6xxx: Disentangle STU from VTU 2022-03-17 16:49:59 -07:00
global1_atu.c net: dsa: mv88e6xxx: replace ATU violation prints with trace points 2022-12-12 15:01:18 -08:00
global1_vtu.c net: dsa: mv88e6xxx: replace VTU violation prints with trace points 2022-12-12 15:01:18 -08:00
global2.c net: dsa: mv88e6xxx: Export cross-chip PVT as devlink region 2021-04-21 10:25:09 -07:00
global2.h net: dsa: mv88e6xxx: Allow external SMI if serial 2022-08-26 19:25:37 -07:00
global2_avb.c
global2_scratch.c net: dsa: mv88e6xxx: add mv88e6352_g2_scratch_port_has_serdes() 2022-02-03 14:10:35 +00:00
hwtstamp.c net: dsa: Use netif_rx(). 2022-03-04 12:02:19 +00:00
hwtstamp.h net: dsa: no longer clone skb in core driver 2021-04-27 14:10:15 -07:00
Kconfig ethernet: fix PTP_1588_CLOCK dependencies 2021-08-13 17:49:05 -07:00
Makefile net: dsa: mv88e6xxx: replace ATU violation prints with trace points 2022-12-12 15:01:18 -08:00
phy.c
phy.h
port.c net: dsa: mv88e6xxx: Add RGMII delay to 88E6320 2022-10-31 20:00:20 -07:00
port.h net: dsa: mv88e6xxx: Add RGMII delay to 88E6320 2022-10-31 20:00:20 -07:00
port_hidden.c net: dsa: mv88e6xxx: Fix port_hidden_wait to account for port_base_addr 2022-04-26 12:03:58 +02:00
ptp.c
ptp.h
serdes.c net: dsa: mv88e6xxx: correctly report serdes link failure 2022-06-08 20:58:30 -07:00
serdes.h dsa: mv88e6xxx: make serdes SGMII/Fiber tx amplitude configurable 2022-02-11 11:21:34 +00:00
smi.c net: dsa: mv88e6xxx: Improve indirect addressing performance 2022-01-31 11:29:12 +00:00
smi.h
trace.c net: dsa: mv88e6xxx: replace ATU violation prints with trace points 2022-12-12 15:01:18 -08:00
trace.h net: dsa: mv88e6xxx: replace VTU violation prints with trace points 2022-12-12 15:01:18 -08:00