From bb907d8d449a32da0f075e188cb22694c89e2281 Mon Sep 17 00:00:00 2001 From: Robert Marko Date: Sun, 11 Feb 2024 18:56:54 +0100 Subject: [PATCH] generic: add fix for AQR113 PMD Global Transmit Disable bit PMD Global Transmit Disable bit should be cleared for normal operation. This should be HW default, however I found that on Asus RT-AX89X that uses AQR113C PHY and firmware 5.4 this bit is set by default. With this bit set the AQR cannot achieve a link with its link-partner and it took me multiple hours of digging through the vendor GPL source to find this out, so lets always clear this bit during .config_init() to avoid a situation like this in the future. aqr107_wait_processor_intensive_op() is moved up because datasheet notes that any changes to this bit are processor intensive. This is a modified version of patch that got merged upstream as AQR113C has a separate config_init() upstream. Link: https://github.com/openwrt/openwrt/pull/15840 Signed-off-by: Robert Marko --- ...-clear-PMD-Global-Transmit-Disable-b.patch | 103 ++++++++++++++++++ ...-clear-PMD-Global-Transmit-Disable-b.patch | 103 ++++++++++++++++++ ...hy-aquantia-enable-AQR112-and-AQR412.patch | 4 +- ...ntia-add-PHY_IDs-for-AQR112-variants.patch | 4 +- ...hy-aquantia-enable-AQR112-and-AQR412.patch | 4 +- ...ntia-add-PHY_IDs-for-AQR112-variants.patch | 4 +- 6 files changed, 214 insertions(+), 8 deletions(-) create mode 100644 target/linux/generic/backport-6.1/839-v6.9-net-phy-aquantia-clear-PMD-Global-Transmit-Disable-b.patch create mode 100644 target/linux/generic/backport-6.6/836-v6.9-net-phy-aquantia-clear-PMD-Global-Transmit-Disable-b.patch diff --git a/target/linux/generic/backport-6.1/839-v6.9-net-phy-aquantia-clear-PMD-Global-Transmit-Disable-b.patch b/target/linux/generic/backport-6.1/839-v6.9-net-phy-aquantia-clear-PMD-Global-Transmit-Disable-b.patch new file mode 100644 index 0000000000..802cf8a128 --- /dev/null +++ b/target/linux/generic/backport-6.1/839-v6.9-net-phy-aquantia-clear-PMD-Global-Transmit-Disable-b.patch @@ -0,0 +1,103 @@ +From cffac22c9215f1883d3848c788f9b03656dced27 Mon Sep 17 00:00:00 2001 +From: Robert Marko +Date: Sun, 11 Feb 2024 18:39:19 +0100 +Subject: [PATCH] net: phy: aquantia: clear PMD Global Transmit Disable bit + during init + +PMD Global Transmit Disable bit should be cleared for normal operation. +This should be HW default, however I found that on Asus RT-AX89X that uses +AQR113C PHY and firmware 5.4 this bit is set by default. + +With this bit set the AQR cannot achieve a link with its link-partner and +it took me multiple hours of digging through the vendor GPL source to find +this out, so lets always clear this bit during .config_init() to avoid a +situation like this in the future. + +aqr107_wait_processor_intensive_op() is moved up because datasheet notes +that any changes to this bit are processor intensive. + +Signed-off-by: Robert Marko +--- + drivers/net/phy/aquantia/aquantia_main.c | 57 ++++++++++++++---------- + 1 file changed, 33 insertions(+), 24 deletions(-) + +--- a/drivers/net/phy/aquantia/aquantia_main.c ++++ b/drivers/net/phy/aquantia/aquantia_main.c +@@ -507,6 +507,30 @@ static void aqr107_chip_info(struct phy_ + fw_major, fw_minor, build_id, prov_id); + } + ++static int aqr107_wait_processor_intensive_op(struct phy_device *phydev) ++{ ++ int val, err; ++ ++ /* The datasheet notes to wait at least 1ms after issuing a ++ * processor intensive operation before checking. ++ * We cannot use the 'sleep_before_read' parameter of read_poll_timeout ++ * because that just determines the maximum time slept, not the minimum. ++ */ ++ usleep_range(1000, 5000); ++ ++ err = phy_read_mmd_poll_timeout(phydev, MDIO_MMD_VEND1, ++ VEND1_GLOBAL_GEN_STAT2, val, ++ !(val & VEND1_GLOBAL_GEN_STAT2_OP_IN_PROG), ++ AQR107_OP_IN_PROG_SLEEP, ++ AQR107_OP_IN_PROG_TIMEOUT, false); ++ if (err) { ++ phydev_err(phydev, "timeout: processor-intensive MDIO operation\n"); ++ return err; ++ } ++ ++ return 0; ++} ++ + static int aqr107_config_init(struct phy_device *phydev) + { + int ret; +@@ -530,6 +554,15 @@ static int aqr107_config_init(struct phy + if (!ret) + aqr107_chip_info(phydev); + ++ ret = phy_clear_bits_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_PMA_TXDIS, ++ MDIO_PMD_TXDIS_GLOBAL); ++ if (ret) ++ return ret; ++ ++ ret = aqr107_wait_processor_intensive_op(phydev); ++ if (ret) ++ return ret; ++ + return aqr107_set_downshift(phydev, MDIO_AN_VEND_PROV_DOWNSHIFT_DFLT); + } + +@@ -600,30 +633,6 @@ static void aqr107_link_change_notify(st + phydev_info(phydev, "Aquantia 1000Base-T2 mode active\n"); + } + +-static int aqr107_wait_processor_intensive_op(struct phy_device *phydev) +-{ +- int val, err; +- +- /* The datasheet notes to wait at least 1ms after issuing a +- * processor intensive operation before checking. +- * We cannot use the 'sleep_before_read' parameter of read_poll_timeout +- * because that just determines the maximum time slept, not the minimum. +- */ +- usleep_range(1000, 5000); +- +- err = phy_read_mmd_poll_timeout(phydev, MDIO_MMD_VEND1, +- VEND1_GLOBAL_GEN_STAT2, val, +- !(val & VEND1_GLOBAL_GEN_STAT2_OP_IN_PROG), +- AQR107_OP_IN_PROG_SLEEP, +- AQR107_OP_IN_PROG_TIMEOUT, false); +- if (err) { +- phydev_err(phydev, "timeout: processor-intensive MDIO operation\n"); +- return err; +- } +- +- return 0; +-} +- + static int aqr107_get_rate_matching(struct phy_device *phydev, + phy_interface_t iface) + { diff --git a/target/linux/generic/backport-6.6/836-v6.9-net-phy-aquantia-clear-PMD-Global-Transmit-Disable-b.patch b/target/linux/generic/backport-6.6/836-v6.9-net-phy-aquantia-clear-PMD-Global-Transmit-Disable-b.patch new file mode 100644 index 0000000000..8b54881ab0 --- /dev/null +++ b/target/linux/generic/backport-6.6/836-v6.9-net-phy-aquantia-clear-PMD-Global-Transmit-Disable-b.patch @@ -0,0 +1,103 @@ +From cffac22c9215f1883d3848c788f9b03656dced27 Mon Sep 17 00:00:00 2001 +From: Robert Marko +Date: Sun, 11 Feb 2024 18:39:19 +0100 +Subject: [PATCH] net: phy: aquantia: clear PMD Global Transmit Disable bit + during init + +PMD Global Transmit Disable bit should be cleared for normal operation. +This should be HW default, however I found that on Asus RT-AX89X that uses +AQR113C PHY and firmware 5.4 this bit is set by default. + +With this bit set the AQR cannot achieve a link with its link-partner and +it took me multiple hours of digging through the vendor GPL source to find +this out, so lets always clear this bit during .config_init() to avoid a +situation like this in the future. + +aqr107_wait_processor_intensive_op() is moved up because datasheet notes +that any changes to this bit are processor intensive. + +Signed-off-by: Robert Marko +--- + drivers/net/phy/aquantia/aquantia_main.c | 57 ++++++++++++++---------- + 1 file changed, 33 insertions(+), 24 deletions(-) + +--- a/drivers/net/phy/aquantia/aquantia_main.c ++++ b/drivers/net/phy/aquantia/aquantia_main.c +@@ -473,6 +473,30 @@ static void aqr107_chip_info(struct phy_ + fw_major, fw_minor, build_id, prov_id); + } + ++static int aqr107_wait_processor_intensive_op(struct phy_device *phydev) ++{ ++ int val, err; ++ ++ /* The datasheet notes to wait at least 1ms after issuing a ++ * processor intensive operation before checking. ++ * We cannot use the 'sleep_before_read' parameter of read_poll_timeout ++ * because that just determines the maximum time slept, not the minimum. ++ */ ++ usleep_range(1000, 5000); ++ ++ err = phy_read_mmd_poll_timeout(phydev, MDIO_MMD_VEND1, ++ VEND1_GLOBAL_GEN_STAT2, val, ++ !(val & VEND1_GLOBAL_GEN_STAT2_OP_IN_PROG), ++ AQR107_OP_IN_PROG_SLEEP, ++ AQR107_OP_IN_PROG_TIMEOUT, false); ++ if (err) { ++ phydev_err(phydev, "timeout: processor-intensive MDIO operation\n"); ++ return err; ++ } ++ ++ return 0; ++} ++ + static int aqr107_config_init(struct phy_device *phydev) + { + struct aqr107_priv *priv = phydev->priv; +@@ -498,6 +522,15 @@ static int aqr107_config_init(struct phy + if (!ret) + aqr107_chip_info(phydev); + ++ ret = phy_clear_bits_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_PMA_TXDIS, ++ MDIO_PMD_TXDIS_GLOBAL); ++ if (ret) ++ return ret; ++ ++ ret = aqr107_wait_processor_intensive_op(phydev); ++ if (ret) ++ return ret; ++ + ret = aqr107_set_downshift(phydev, MDIO_AN_VEND_PROV_DOWNSHIFT_DFLT); + if (ret) + return ret; +@@ -580,30 +613,6 @@ static void aqr107_link_change_notify(st + phydev_info(phydev, "Aquantia 1000Base-T2 mode active\n"); + } + +-static int aqr107_wait_processor_intensive_op(struct phy_device *phydev) +-{ +- int val, err; +- +- /* The datasheet notes to wait at least 1ms after issuing a +- * processor intensive operation before checking. +- * We cannot use the 'sleep_before_read' parameter of read_poll_timeout +- * because that just determines the maximum time slept, not the minimum. +- */ +- usleep_range(1000, 5000); +- +- err = phy_read_mmd_poll_timeout(phydev, MDIO_MMD_VEND1, +- VEND1_GLOBAL_GEN_STAT2, val, +- !(val & VEND1_GLOBAL_GEN_STAT2_OP_IN_PROG), +- AQR107_OP_IN_PROG_SLEEP, +- AQR107_OP_IN_PROG_TIMEOUT, false); +- if (err) { +- phydev_err(phydev, "timeout: processor-intensive MDIO operation\n"); +- return err; +- } +- +- return 0; +-} +- + static int aqr107_get_rate_matching(struct phy_device *phydev, + phy_interface_t iface) + { diff --git a/target/linux/generic/hack-6.1/722-net-phy-aquantia-enable-AQR112-and-AQR412.patch b/target/linux/generic/hack-6.1/722-net-phy-aquantia-enable-AQR112-and-AQR412.patch index faaa40f9bd..42b44d564d 100644 --- a/target/linux/generic/hack-6.1/722-net-phy-aquantia-enable-AQR112-and-AQR412.patch +++ b/target/linux/generic/hack-6.1/722-net-phy-aquantia-enable-AQR112-and-AQR412.patch @@ -106,7 +106,7 @@ Signed-off-by: Alex Marginean static int aqr_config_intr(struct phy_device *phydev) { bool en = phydev->interrupts == PHY_INTERRUPT_ENABLED; -@@ -860,6 +930,30 @@ static struct phy_driver aqr_driver[] = +@@ -869,6 +939,30 @@ static struct phy_driver aqr_driver[] = .get_stats = aqr107_get_stats, .link_change_notify = aqr107_link_change_notify, }, @@ -137,7 +137,7 @@ Signed-off-by: Alex Marginean }; module_phy_driver(aqr_driver); -@@ -877,6 +971,8 @@ static struct mdio_device_id __maybe_unu +@@ -886,6 +980,8 @@ static struct mdio_device_id __maybe_unu { PHY_ID_MATCH_MODEL(PHY_ID_AQR113) }, { PHY_ID_MATCH_MODEL(PHY_ID_AQR113C) }, { PHY_ID_MATCH_MODEL(PHY_ID_AQR813) }, diff --git a/target/linux/generic/hack-6.1/725-net-phy-aquantia-add-PHY_IDs-for-AQR112-variants.patch b/target/linux/generic/hack-6.1/725-net-phy-aquantia-add-PHY_IDs-for-AQR112-variants.patch index d83cc48a33..6d107c3349 100644 --- a/target/linux/generic/hack-6.1/725-net-phy-aquantia-add-PHY_IDs-for-AQR112-variants.patch +++ b/target/linux/generic/hack-6.1/725-net-phy-aquantia-add-PHY_IDs-for-AQR112-variants.patch @@ -21,7 +21,7 @@ Signed-off-by: Daniel Golle #define MDIO_PHYXS_VEND_IF_STATUS 0xe812 #define MDIO_PHYXS_VEND_IF_STATUS_TYPE_MASK GENMASK(7, 3) -@@ -960,6 +962,30 @@ static struct phy_driver aqr_driver[] = +@@ -969,6 +971,30 @@ static struct phy_driver aqr_driver[] = .get_strings = aqr107_get_strings, .get_stats = aqr107_get_stats, }, @@ -52,7 +52,7 @@ Signed-off-by: Daniel Golle }; module_phy_driver(aqr_driver); -@@ -979,6 +1005,8 @@ static struct mdio_device_id __maybe_unu +@@ -988,6 +1014,8 @@ static struct mdio_device_id __maybe_unu { PHY_ID_MATCH_MODEL(PHY_ID_AQR813) }, { PHY_ID_MATCH_MODEL(PHY_ID_AQR112) }, { PHY_ID_MATCH_MODEL(PHY_ID_AQR412) }, diff --git a/target/linux/generic/hack-6.6/722-net-phy-aquantia-enable-AQR112-and-AQR412.patch b/target/linux/generic/hack-6.6/722-net-phy-aquantia-enable-AQR112-and-AQR412.patch index ea5c700702..dee901fbe3 100644 --- a/target/linux/generic/hack-6.6/722-net-phy-aquantia-enable-AQR112-and-AQR412.patch +++ b/target/linux/generic/hack-6.6/722-net-phy-aquantia-enable-AQR112-and-AQR412.patch @@ -97,7 +97,7 @@ Signed-off-by: Alex Marginean static int aqr_config_intr(struct phy_device *phydev) { bool en = phydev->interrupts == PHY_INTERRUPT_ENABLED; -@@ -807,7 +875,7 @@ static struct phy_driver aqr_driver[] = +@@ -816,7 +884,7 @@ static struct phy_driver aqr_driver[] = PHY_ID_MATCH_MODEL(PHY_ID_AQR112), .name = "Aquantia AQR112", .probe = aqr107_probe, @@ -106,7 +106,7 @@ Signed-off-by: Alex Marginean .config_intr = aqr_config_intr, .handle_interrupt = aqr_handle_interrupt, .get_tunable = aqr107_get_tunable, -@@ -830,7 +898,7 @@ static struct phy_driver aqr_driver[] = +@@ -839,7 +907,7 @@ static struct phy_driver aqr_driver[] = PHY_ID_MATCH_MODEL(PHY_ID_AQR412), .name = "Aquantia AQR412", .probe = aqr107_probe, diff --git a/target/linux/generic/hack-6.6/725-net-phy-aquantia-add-PHY_IDs-for-AQR112-variants.patch b/target/linux/generic/hack-6.6/725-net-phy-aquantia-add-PHY_IDs-for-AQR112-variants.patch index 66298b89ed..075b0fc8e2 100644 --- a/target/linux/generic/hack-6.6/725-net-phy-aquantia-add-PHY_IDs-for-AQR112-variants.patch +++ b/target/linux/generic/hack-6.6/725-net-phy-aquantia-add-PHY_IDs-for-AQR112-variants.patch @@ -21,7 +21,7 @@ Signed-off-by: Daniel Golle #define MDIO_PHYXS_VEND_IF_STATUS 0xe812 #define MDIO_PHYXS_VEND_IF_STATUS_TYPE_MASK GENMASK(7, 3) -@@ -1014,6 +1016,30 @@ static struct phy_driver aqr_driver[] = +@@ -1023,6 +1025,30 @@ static struct phy_driver aqr_driver[] = .led_hw_control_get = aqr_phy_led_hw_control_get, .led_polarity_set = aqr_phy_led_polarity_set, }, @@ -52,7 +52,7 @@ Signed-off-by: Daniel Golle }; module_phy_driver(aqr_driver); -@@ -1034,6 +1060,8 @@ static struct mdio_device_id __maybe_unu +@@ -1043,6 +1069,8 @@ static struct mdio_device_id __maybe_unu { PHY_ID_MATCH_MODEL(PHY_ID_AQR113C) }, { PHY_ID_MATCH_MODEL(PHY_ID_AQR114C) }, { PHY_ID_MATCH_MODEL(PHY_ID_AQR813) }, -- 2.30.2