44 */
55#include <linux/bitfield.h>
66#include <linux/ethtool_netlink.h>
7+ #include <linux/jiffies.h>
78#include <linux/kernel.h>
89#include <linux/module.h>
910#include <linux/phy.h>
11+ #include <linux/random.h>
1012
1113#include "open_alliance_helpers.h"
1214
15+ /*
16+ * DP83TG720S_POLL_ACTIVE_LINK - Polling interval in milliseconds when the link
17+ * is active.
18+ * DP83TG720S_POLL_NO_LINK_MIN - Minimum polling interval in milliseconds when
19+ * the link is down.
20+ * DP83TG720S_POLL_NO_LINK_MAX - Maximum polling interval in milliseconds when
21+ * the link is down.
22+ *
23+ * These values are not documented or officially recommended by the vendor but
24+ * were determined through empirical testing. They achieve a good balance in
25+ * minimizing the number of reset retries while ensuring reliable link recovery
26+ * within a reasonable timeframe.
27+ */
28+ #define DP83TG720S_POLL_ACTIVE_LINK 1000
29+ #define DP83TG720S_POLL_NO_LINK_MIN 100
30+ #define DP83TG720S_POLL_NO_LINK_MAX 1000
31+
1332#define DP83TG720S_PHY_ID 0x2000a284
1433
1534/* MDIO_MMD_VEND2 registers */
@@ -371,6 +390,13 @@ static int dp83tg720_read_status(struct phy_device *phydev)
371390 if (ret )
372391 return ret ;
373392
393+ /* Sleep 600ms for PHY stabilization post-reset.
394+ * Empirically chosen value (not documented).
395+ * Helps reduce reset bounces with link partners having similar
396+ * issues.
397+ */
398+ msleep (600 );
399+
374400 /* After HW reset we need to restore master/slave configuration.
375401 * genphy_c45_pma_baset1_read_master_slave() call will be done
376402 * by the dp83tg720_config_aneg() function.
@@ -498,6 +524,57 @@ static int dp83tg720_probe(struct phy_device *phydev)
498524 return 0 ;
499525}
500526
527+ /**
528+ * dp83tg720_get_next_update_time - Determine the next update time for PHY
529+ * state
530+ * @phydev: Pointer to the phy_device structure
531+ *
532+ * This function addresses a limitation of the DP83TG720 PHY, which cannot
533+ * reliably detect or report a stable link state. To recover from such
534+ * scenarios, the PHY must be periodically reset when the link is down. However,
535+ * if the link partner also runs Linux with the same driver, synchronized reset
536+ * intervals can lead to a deadlock where the link never establishes due to
537+ * simultaneous resets on both sides.
538+ *
539+ * To avoid this, the function implements randomized polling intervals when the
540+ * link is down. It ensures that reset intervals are desynchronized by
541+ * introducing a random delay between a configured minimum and maximum range.
542+ * When the link is up, a fixed polling interval is used to minimize overhead.
543+ *
544+ * This mechanism guarantees that the link will reestablish within 10 seconds
545+ * in the worst-case scenario.
546+ *
547+ * Return: Time (in jiffies) until the next update event for the PHY state
548+ * machine.
549+ */
550+ static unsigned int dp83tg720_get_next_update_time (struct phy_device * phydev )
551+ {
552+ unsigned int next_time_jiffies ;
553+
554+ if (phydev -> link ) {
555+ /* When the link is up, use a fixed 1000ms interval
556+ * (in jiffies)
557+ */
558+ next_time_jiffies =
559+ msecs_to_jiffies (DP83TG720S_POLL_ACTIVE_LINK );
560+ } else {
561+ unsigned int min_jiffies , max_jiffies , rand_jiffies ;
562+
563+ /* When the link is down, randomize interval between min/max
564+ * (in jiffies)
565+ */
566+ min_jiffies = msecs_to_jiffies (DP83TG720S_POLL_NO_LINK_MIN );
567+ max_jiffies = msecs_to_jiffies (DP83TG720S_POLL_NO_LINK_MAX );
568+
569+ rand_jiffies = min_jiffies +
570+ get_random_u32_below (max_jiffies - min_jiffies + 1 );
571+ next_time_jiffies = rand_jiffies ;
572+ }
573+
574+ /* Ensure the polling time is at least one jiffy */
575+ return max (next_time_jiffies , 1U );
576+ }
577+
501578static struct phy_driver dp83tg720_driver [] = {
502579{
503580 PHY_ID_MATCH_MODEL (DP83TG720S_PHY_ID ),
@@ -516,6 +593,7 @@ static struct phy_driver dp83tg720_driver[] = {
516593 .get_link_stats = dp83tg720_get_link_stats ,
517594 .get_phy_stats = dp83tg720_get_phy_stats ,
518595 .update_stats = dp83tg720_update_stats ,
596+ .get_next_update_time = dp83tg720_get_next_update_time ,
519597
520598 .suspend = genphy_suspend ,
521599 .resume = genphy_resume ,
0 commit comments