Skip to content

Commit df16c1c

Browse files
ahalaneykuba-moo
authored andcommitted
net: phy: mdio_device: Reset device only when necessary
Currently the phy reset sequence is as shown below for a devicetree described mdio phy on boot: 1. Assert the phy_device's reset as part of registering 2. Deassert the phy_device's reset as part of registering 3. Deassert the phy_device's reset as part of phy_probe 4. Deassert the phy_device's reset as part of phy_hw_init The extra two deasserts include waiting the deassert delay afterwards, which is adding unnecessary delay. This applies to both possible types of resets (reset controller reference and a reset gpio) that can be used. Here's some snipped tracing output using the following command line params "trace_event=gpio:* trace_options=stacktrace" illustrating the reset handling and where its coming from: /* Assert */ systemd-udevd-283 [002] ..... 6.780434: gpio_value: 544 set 0 systemd-udevd-283 [002] ..... 6.783849: <stack trace> => gpiod_set_raw_value_commit => gpiod_set_value_nocheck => gpiod_set_value_cansleep => mdio_device_reset => mdiobus_register_device => phy_device_register => fwnode_mdiobus_phy_device_register => fwnode_mdiobus_register_phy => __of_mdiobus_register => stmmac_mdio_register => stmmac_dvr_probe => stmmac_pltfr_probe => devm_stmmac_pltfr_probe => qcom_ethqos_probe => platform_probe /* Deassert */ systemd-udevd-283 [002] ..... 6.802480: gpio_value: 544 set 1 systemd-udevd-283 [002] ..... 6.805886: <stack trace> => gpiod_set_raw_value_commit => gpiod_set_value_nocheck => gpiod_set_value_cansleep => mdio_device_reset => phy_device_register => fwnode_mdiobus_phy_device_register => fwnode_mdiobus_register_phy => __of_mdiobus_register => stmmac_mdio_register => stmmac_dvr_probe => stmmac_pltfr_probe => devm_stmmac_pltfr_probe => qcom_ethqos_probe => platform_probe /* Deassert */ systemd-udevd-283 [002] ..... 6.882601: gpio_value: 544 set 1 systemd-udevd-283 [002] ..... 6.886014: <stack trace> => gpiod_set_raw_value_commit => gpiod_set_value_nocheck => gpiod_set_value_cansleep => mdio_device_reset => phy_probe => really_probe => __driver_probe_device => driver_probe_device => __device_attach_driver => bus_for_each_drv => __device_attach => device_initial_probe => bus_probe_device => device_add => phy_device_register => fwnode_mdiobus_phy_device_register => fwnode_mdiobus_register_phy => __of_mdiobus_register => stmmac_mdio_register => stmmac_dvr_probe => stmmac_pltfr_probe => devm_stmmac_pltfr_probe => qcom_ethqos_probe => platform_probe /* Deassert */ NetworkManager-477 [000] ..... 7.023144: gpio_value: 544 set 1 NetworkManager-477 [000] ..... 7.026596: <stack trace> => gpiod_set_raw_value_commit => gpiod_set_value_nocheck => gpiod_set_value_cansleep => mdio_device_reset => phy_init_hw => phy_attach_direct => phylink_fwnode_phy_connect => __stmmac_open => stmmac_open There's a lot of paths where the device is getting its reset asserted and deasserted. Let's track the state and only actually do the assert/deassert when it changes. Reported-by: Sagar Cheluvegowda <[email protected]> Signed-off-by: Andrew Halaney <[email protected]> Reviewed-by: Andrew Lunn <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Jakub Kicinski <[email protected]>
1 parent 753c860 commit df16c1c

File tree

3 files changed

+8
-0
lines changed

3 files changed

+8
-0
lines changed

drivers/net/phy/mdio_device.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ struct mdio_device *mdio_device_create(struct mii_bus *bus, int addr)
6262
mdiodev->device_remove = mdio_device_remove;
6363
mdiodev->bus = bus;
6464
mdiodev->addr = addr;
65+
mdiodev->reset_state = -1;
6566

6667
dev_set_name(&mdiodev->dev, PHY_ID_FMT, bus->id, addr);
6768

@@ -122,6 +123,9 @@ void mdio_device_reset(struct mdio_device *mdiodev, int value)
122123
if (!mdiodev->reset_gpio && !mdiodev->reset_ctrl)
123124
return;
124125

126+
if (mdiodev->reset_state == value)
127+
return;
128+
125129
if (mdiodev->reset_gpio)
126130
gpiod_set_value_cansleep(mdiodev->reset_gpio, value);
127131

@@ -135,6 +139,8 @@ void mdio_device_reset(struct mdio_device *mdiodev, int value)
135139
d = value ? mdiodev->reset_assert_delay : mdiodev->reset_deassert_delay;
136140
if (d)
137141
fsleep(d);
142+
143+
mdiodev->reset_state = value;
138144
}
139145
EXPORT_SYMBOL(mdio_device_reset);
140146

drivers/net/phy/phy_device.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -654,6 +654,7 @@ struct phy_device *phy_device_create(struct mii_bus *bus, int addr, u32 phy_id,
654654
mdiodev->flags = MDIO_DEVICE_FLAG_PHY;
655655
mdiodev->device_free = phy_mdio_device_free;
656656
mdiodev->device_remove = phy_mdio_device_remove;
657+
mdiodev->reset_state = -1;
657658

658659
dev->speed = SPEED_UNKNOWN;
659660
dev->duplex = DUPLEX_UNKNOWN;

include/linux/mdio.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ struct mdio_device {
3838
/* Bus address of the MDIO device (0-31) */
3939
int addr;
4040
int flags;
41+
int reset_state;
4142
struct gpio_desc *reset_gpio;
4243
struct reset_control *reset_ctrl;
4344
unsigned int reset_assert_delay;

0 commit comments

Comments
 (0)