Patch "net: phy: aquantia: fix -ETIMEDOUT PHY probe failure when firmware not present" has been added to the 6.11-stable tree

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This is a note to let you know that I've just added the patch titled

    net: phy: aquantia: fix -ETIMEDOUT PHY probe failure when firmware not present

to the 6.11-stable tree which can be found at:
    http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary

The filename of the patch is:
     net-phy-aquantia-fix-etimedout-phy-probe-failure-whe.patch
and it can be found in the queue-6.11 subdirectory.

If you, or anyone else, feels it should not be added to the stable tree,
please let <stable@xxxxxxxxxxxxxxx> know about it.



commit be012476386f57829535259b267d908ad5c35354
Author: Vladimir Oltean <vladimir.oltean@xxxxxxx>
Date:   Fri Sep 13 15:12:30 2024 +0300

    net: phy: aquantia: fix -ETIMEDOUT PHY probe failure when firmware not present
    
    [ Upstream commit 194ef9d0de9021df4a0ba8b112f91e56adaddd22 ]
    
    The author of the blamed commit apparently did not notice something
    about aqr_wait_reset_complete(): it polls the exact same register -
    MDIO_MMD_VEND1:VEND1_GLOBAL_FW_ID - as aqr_firmware_load().
    
    Thus, the entire logic after the introduction of aqr_wait_reset_complete() is
    now completely side-stepped, because if aqr_wait_reset_complete()
    succeeds, MDIO_MMD_VEND1:VEND1_GLOBAL_FW_ID could have only been a
    non-zero value. The handling of the case where the register reads as 0
    is dead code, due to the previous -ETIMEDOUT having stopped execution
    and returning a fatal error to the caller. We never attempt to load
    new firmware if no firmware is present.
    
    Based on static code analysis, I guess we should simply introduce a
    switch/case statement based on the return code from aqr_wait_reset_complete(),
    to determine whether to load firmware or not. I am not intending to
    change the procedure through which the driver determines whether to load
    firmware or not, as I am unaware of alternative possibilities.
    
    At the same time, Russell King suggests that if aqr_wait_reset_complete()
    is expected to return -ETIMEDOUT as part of normal operation and not
    just catastrophic failure, the use of phy_read_mmd_poll_timeout() is
    improper, since that has an embedded print inside. Just open-code a
    call to read_poll_timeout() to avoid printing -ETIMEDOUT, but continue
    printing actual read errors from the MDIO bus.
    
    Fixes: ad649a1fac37 ("net: phy: aquantia: wait for FW reset before checking the vendor ID")
    Reported-by: Clark Wang <xiaoning.wang@xxxxxxx>
    Reported-by: Jon Hunter <jonathanh@xxxxxxxxxx>
    Closes: https://lore.kernel.org/netdev/8ac00a45-ac61-41b4-9f74-d18157b8b6bf@xxxxxxxxxx/
    Reported-by: Hans-Frieder Vogt <hfdevel@xxxxxxx>
    Closes: https://lore.kernel.org/netdev/c7c1a3ae-be97-4929-8d89-04c8aa870209@xxxxxxx/
    Signed-off-by: Vladimir Oltean <vladimir.oltean@xxxxxxx>
    Tested-by: Bartosz Golaszewski <bartosz.golaszewski@xxxxxxxxxx>
    Tested-by: Hans-Frieder Vogt <hfdevel@xxxxxxx>
    Link: https://patch.msgid.link/20240913121230.2620122-1-vladimir.oltean@xxxxxxx
    Signed-off-by: Paolo Abeni <pabeni@xxxxxxxxxx>
    Signed-off-by: Sasha Levin <sashal@xxxxxxxxxx>

diff --git a/drivers/net/phy/aquantia/aquantia_firmware.c b/drivers/net/phy/aquantia/aquantia_firmware.c
index 524627a36c6fc..dac6464b5fe2e 100644
--- a/drivers/net/phy/aquantia/aquantia_firmware.c
+++ b/drivers/net/phy/aquantia/aquantia_firmware.c
@@ -353,26 +353,32 @@ int aqr_firmware_load(struct phy_device *phydev)
 {
 	int ret;
 
-	ret = aqr_wait_reset_complete(phydev);
-	if (ret)
-		return ret;
-
-	/* Check if the firmware is not already loaded by pooling
-	 * the current version returned by the PHY. If 0 is returned,
-	 * no firmware is loaded.
+	/* Check if the firmware is not already loaded by polling
+	 * the current version returned by the PHY.
 	 */
-	ret = phy_read_mmd(phydev, MDIO_MMD_VEND1, VEND1_GLOBAL_FW_ID);
-	if (ret > 0)
-		goto exit;
-
-	ret = aqr_firmware_load_nvmem(phydev);
-	if (!ret)
-		goto exit;
-
-	ret = aqr_firmware_load_fs(phydev);
-	if (ret)
+	ret = aqr_wait_reset_complete(phydev);
+	switch (ret) {
+	case 0:
+		/* Some firmware is loaded => do nothing */
+		return 0;
+	case -ETIMEDOUT:
+		/* VEND1_GLOBAL_FW_ID still reads 0 after 2 seconds of polling.
+		 * We don't have full confidence that no firmware is loaded (in
+		 * theory it might just not have loaded yet), but we will
+		 * assume that, and load a new image.
+		 */
+		ret = aqr_firmware_load_nvmem(phydev);
+		if (!ret)
+			return ret;
+
+		ret = aqr_firmware_load_fs(phydev);
+		if (ret)
+			return ret;
+		break;
+	default:
+		/* PHY read error, propagate it to the caller */
 		return ret;
+	}
 
-exit:
 	return 0;
 }
diff --git a/drivers/net/phy/aquantia/aquantia_main.c b/drivers/net/phy/aquantia/aquantia_main.c
index e982e9ce44a59..57b8b8f400fd4 100644
--- a/drivers/net/phy/aquantia/aquantia_main.c
+++ b/drivers/net/phy/aquantia/aquantia_main.c
@@ -435,6 +435,9 @@ static int aqr107_set_tunable(struct phy_device *phydev,
 	}
 }
 
+#define AQR_FW_WAIT_SLEEP_US	20000
+#define AQR_FW_WAIT_TIMEOUT_US	2000000
+
 /* If we configure settings whilst firmware is still initializing the chip,
  * then these settings may be overwritten. Therefore make sure chip
  * initialization has completed. Use presence of the firmware ID as
@@ -444,11 +447,19 @@ static int aqr107_set_tunable(struct phy_device *phydev,
  */
 int aqr_wait_reset_complete(struct phy_device *phydev)
 {
-	int val;
+	int ret, val;
+
+	ret = read_poll_timeout(phy_read_mmd, val, val != 0,
+				AQR_FW_WAIT_SLEEP_US, AQR_FW_WAIT_TIMEOUT_US,
+				false, phydev, MDIO_MMD_VEND1,
+				VEND1_GLOBAL_FW_ID);
+	if (val < 0) {
+		phydev_err(phydev, "Failed to read VEND1_GLOBAL_FW_ID: %pe\n",
+			   ERR_PTR(val));
+		return val;
+	}
 
-	return phy_read_mmd_poll_timeout(phydev, MDIO_MMD_VEND1,
-					 VEND1_GLOBAL_FW_ID, val, val != 0,
-					 20000, 2000000, false);
+	return ret;
 }
 
 static void aqr107_chip_info(struct phy_device *phydev)




[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Index of Archives]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux