From 4617721c502b2ddaa4e324e86da4997edf738fa5 Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Wed, 2 Sep 2026 09:55:01 -0400 Subject: ftrace: Synchronize the initialization of ftrace_ops There's some internal state that ftrace_ops needs to have set, but since it can be declared outside of the ftrace.c code, it calls ftrace_ops_init() on the ops in every global function. The issue is that if two tasks call it on the same ops at the same time it is possible to have the initialization of one corrupt the initialization of the other call. Create a ops_mutex to use to synchronize every initialization of the ftrace_ops. The mutex is taken within checking the ftrace_ops flag that states it was initializied but the flag is checked again after the mutex has been taken. Checking first outside the mutex allows it to shortcut having to take the mutex. But then the check needs to be done again after the mute is taken in case of races. Cc: stable@vger.kernel.org Link: https://patch.msgid.link/20260902095501.6b59af20@gandalf.local.home Fixes: f04f24fb7e48d ("ftrace, kprobes: Fix a deadlock on ftrace_regex_lock") Reported-by: sashiko-bot@kernel.org Close: https://lore.kernel.org/all/20260829025528.49A831F000E9@smtp.kernel.org/ Signed-off-by: Steven Rostedt --- drivers/net/phy/swphy.c | 175 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 175 insertions(+) create mode 100644 drivers/net/phy/swphy.c (limited to 'drivers/net/phy/swphy.c') diff --git a/drivers/net/phy/swphy.c b/drivers/net/phy/swphy.c new file mode 100644 index 000000000..59f1ba4d4 --- /dev/null +++ b/drivers/net/phy/swphy.c @@ -0,0 +1,175 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Software PHY emulation + * + * Code taken from fixed_phy.c by Russell King. + * + * Author: Vitaly Bordug + * Anton Vorontsov + * + * Copyright (c) 2006-2007 MontaVista Software, Inc. + */ +#include +#include +#include +#include + +#include "swphy.h" + +#define MII_REGS_NUM 29 + +struct swmii_regs { + u16 bmsr; + u16 lpa; + u16 lpagb; + u16 estat; +}; + +enum { + SWMII_SPEED_10 = 0, + SWMII_SPEED_100, + SWMII_SPEED_1000, + SWMII_DUPLEX_HALF = 0, + SWMII_DUPLEX_FULL, +}; + +/* + * These two tables get bitwise-anded together to produce the final result. + * This means the speed table must contain both duplex settings, and the + * duplex table must contain all speed settings. + */ +static const struct swmii_regs speed[] = { + [SWMII_SPEED_10] = { + .lpa = LPA_10FULL | LPA_10HALF, + }, + [SWMII_SPEED_100] = { + .bmsr = BMSR_100FULL | BMSR_100HALF, + .lpa = LPA_100FULL | LPA_100HALF, + }, + [SWMII_SPEED_1000] = { + .bmsr = BMSR_ESTATEN, + .lpagb = LPA_1000FULL | LPA_1000HALF, + .estat = ESTATUS_1000_TFULL | ESTATUS_1000_THALF, + }, +}; + +static const struct swmii_regs duplex[] = { + [SWMII_DUPLEX_HALF] = { + .bmsr = BMSR_ESTATEN | BMSR_100HALF, + .lpa = LPA_10HALF | LPA_100HALF, + .lpagb = LPA_1000HALF, + .estat = ESTATUS_1000_THALF, + }, + [SWMII_DUPLEX_FULL] = { + .bmsr = BMSR_ESTATEN | BMSR_100FULL, + .lpa = LPA_10FULL | LPA_100FULL, + .lpagb = LPA_1000FULL, + .estat = ESTATUS_1000_TFULL, + }, +}; + +static int swphy_decode_speed(int speed) +{ + switch (speed) { + case 1000: + return SWMII_SPEED_1000; + case 100: + return SWMII_SPEED_100; + case 10: + return SWMII_SPEED_10; + default: + return -EINVAL; + } +} + +/** + * swphy_validate_state - validate the software phy status + * @state: software phy status + * + * This checks that we can represent the state stored in @state can be + * represented in the emulated MII registers. Returns 0 if it can, + * otherwise returns -EINVAL. + */ +int swphy_validate_state(const struct fixed_phy_status *state) +{ + int err; + + if (state->link) { + err = swphy_decode_speed(state->speed); + if (err < 0) { + pr_warn("swphy: unknown speed\n"); + return -EINVAL; + } + } + return 0; +} +EXPORT_SYMBOL_GPL(swphy_validate_state); + +/** + * swphy_read_reg - return a MII register from the fixed phy state + * @reg: MII register + * @state: fixed phy status + * + * Return the MII @reg register generated from the fixed phy state @state. + */ +int swphy_read_reg(int reg, const struct fixed_phy_status *state) +{ + int speed_index, duplex_index; + u16 bmsr = BMSR_ANEGCAPABLE; + u16 estat = 0; + u16 lpagb = 0; + u16 lpa = 0; + + if (reg > MII_REGS_NUM) + return -1; + + speed_index = swphy_decode_speed(state->speed); + if (WARN_ON(speed_index < 0)) + return 0; + + duplex_index = state->duplex ? SWMII_DUPLEX_FULL : SWMII_DUPLEX_HALF; + + bmsr |= speed[speed_index].bmsr & duplex[duplex_index].bmsr; + estat |= speed[speed_index].estat & duplex[duplex_index].estat; + + if (state->link) { + bmsr |= BMSR_LSTATUS | BMSR_ANEGCOMPLETE; + + lpa |= speed[speed_index].lpa & duplex[duplex_index].lpa; + lpagb |= speed[speed_index].lpagb & duplex[duplex_index].lpagb; + + if (state->pause) + lpa |= LPA_PAUSE_CAP; + + if (state->asym_pause) + lpa |= LPA_PAUSE_ASYM; + } + + switch (reg) { + case MII_BMCR: + return BMCR_ANENABLE; + case MII_BMSR: + return bmsr; + case MII_PHYSID1: + case MII_PHYSID2: + return 0; + case MII_LPA: + return lpa; + case MII_STAT1000: + return lpagb; + case MII_ESTATUS: + return estat; + + /* + * We do not support emulating Clause 45 over Clause 22 register + * reads. Return an error instead of bogus data. + */ + case MII_MMD_CTRL: + case MII_MMD_DATA: + return -1; + + default: + return 0xffff; + } +} +EXPORT_SYMBOL_GPL(swphy_read_reg); -- cgit v1.3.1