Hi all,
I still have the phy stability problem even after adding properties to the device tree that enable the GPIO controlled PHY reset. I understand there are two nodes where the GPIO line is controlled. I apologize if my terminology (node, properties, channel…) is not accurate.
- At the MDIO node. This node has the properties reset-gpios, reset-delay-us and reset-post-delay-us. The MDIO driver will use these properties to control the GPIO before probing for device on the MDIO channel. The GPIO line will reset all devices on the associated MDIO channel.
- At the PHY node. This node has the properties reset-gpios, reset-assert-us and reset-deassert-us. The PHY driver will use these properties to control the GPIO before probing for the associated PHY. If you have multiple PHYs, each with a dedicated GPIO line, you can control the reset of PHY.
My custom board has one GPIO line connected to the nRST of two PHYs. The MDIO channel only has these two PHYs devices. I added the PHY node properties to phy0 (zero). The GPIO line pulsed before probing for phy0 and did not pulse before probing for phy1. I was concerned about the possibility that phy1 could be probed before phy0. I also noticed that the reset-assert-us value entered is not the same as what an oscilloscope pulse width shows. A value of 300 is actually longer. Since both my phy’s nRST are connected to one GPIO, I removed the PHY node properties and added the MDIO node properties. As expected the GPIO line pulsed before the MDIO driver attempted to probe for the devices on the MDIO channel. I again noticed that the gpio-delay-us value did not match what the oscope pulse width showed.
To check if the MDIO node GPIO reset fixed the unstable PHY problem, I setup another GPIO line to control an external delay timer that interrupts the power supplied to the custom board for 10 seconds. I created a script that runs after kernel startup that checks for the existence of devices at /sys/bus/mdio_bus/devices/4a101000.mdio:00 and 4a101000.mdio:01. If they both exist then the script will toggle the GPIO controlling the power supply and reboot the board. If one device (or both) does not exist, the script would not turn the power off so that I can see the failure. After approx 300 reboots, I got a device is missing failure. The test is repeatable. One of the PHYs is broken even with the kernel controlling the GPIO reset line.
#!/bin/sh
if [ -e /sys/bus/mdio_bus/devices/4a101000.mdio:00 -a -e /sys/bus/mdio_bus/devices/4a101000.mdio:01 ]
then
# PHY devices exist
echo "No problem, rebooting..."
echo 36 > /sys/class/gpio/export
echo high > /sys/class/gpio/gpio36/direction
echo 0 > /sys/class/gpio/gpio36/value
else
# PHY device(s) do not exist, so problem occurred. Don't reboot
echo "PROBLEM FOUND!"
fi
I thought then to use a script to control the GPIO line instead of the kernel. I removed the MDIO node properties (the PHY node properties were previously removed). I found that I could unbind the MDIO driver from the MDIO device, then use /sys/class/gpio/gpioxx/value to pulse the GPIO PHY reset line and then rebind the MDIO driver. I found that the MDIO driver re-probes for the PHYs. I don’t understand how/why the MDIO unbind/bind causes the driver to re-probe the PHYs, just that it does. The script then checks again for the existence of the devices. I have rebooted 10K+ times. The script has fixed the missing PHY each time. The oscope pulse width matches the usleep value. It may not be an elegant solution but it is working for me.
resetphy script
#!/bin/sh
echo "Begin resetphy script"
logger -t "resetphy" "Attempting a GPIO controlled ethernet PHY reset"
echo "unbind"
echo 4a100000.ethernet > /sys/bus/platform/drivers/cpsw/unbind
usleep 100
echo "GPIO export"
echo 28 > /sys/class/gpio/export
echo "GPIO set direction"
echo high > /sys/class/gpio/gpio28/direction
echo "GPIO assert"
echo 0 > /sys/class/gpio/gpio28/value
usleep 100000
echo "GPIO deassert"
echo 1 > /sys/class/gpio/gpio28/value
usleep 100
echo "bind"
echo 4a100000.ethernet > /sys/bus/platform/drivers/cpsw/bind
usleep 100
echo "run S10 script"
/home/wmi/sysext.d/S10network
echo "Done resetphy script"
checkmdio script
#!/bin/sh
# 20260617 initial release
# phyxx_is_missing: 0=phy is not missing, 1=phy is missing after reboot, 2=phy is still missing after GPIO reset
phy00_is_missing=0
phy01_is_missing=0
if [ ! -e /sys/bus/mdio_bus/devices/4a101000.mdio:00 ]
then
phy00_is_missing=1
echo "checkmdio: ethernet PHY:00 device is missing"
logger -t "checkmdio" "PHY:00 device is missing"
fi
if [ ! -e /sys/bus/mdio_bus/devices/4a101000.mdio:01 ]
then
phy01_is_missing=1
echo "checkmdio: ethernet PHY:01 device is missing"
logger -t "checkmdio" "PHY:01 device is missing"
fi
if [ $phy00_is_missing = 0 -a $phy01_is_missing = 0 ]
then
echo ""
echo "checkmdio: ethernet PHY:00 and PHY:01 devices exist, continuing..."
logger -t "checkmdio" "ethernet PHY devices exist, continuing..."
else
# at least one PHY device is missing after reboot. attempt GPIO controlled reset of PHYs
resetphy
if [ ! -e /sys/bus/mdio_bus/devices/4a101000.mdio:00 ]
then
phy00_is_missing=2
echo "checkmdio: ethernet PHY:00 device is still missing"
logger -t "checkmdio" "PHY:00 device is still missing"
fi
if [ ! -e /sys/bus/mdio_bus/devices/4a101000.mdio:01 ]
then
phy01_is_missing=2
echo "checkmdio: ethernet PHY:01 device is still missing"
logger -t "checkmdio" "PHY:01 device is still missing"
fi
if [ $phy00_is_missing = 2 -o $phy01_is_missing = 2 ]
then
echo "checkmdio: ethernet PHY reset FAILED, continuing..."
logger -t "checkmdio" "ethernet PHY reset failed!"
else
echo "checkmdio: ethernet PHY reset successful, continuing..."
logger -t "checkmdio" "ethernet PHY reset successful"
fi
fi
I would like to know command line command to trigger the MDIO driver to re-probe the channel for devices without using unbind/bind.
Thank you,