Skip to content

Commit 194ef9d

Browse files
vladimirolteanPaolo Abeni
authored andcommitted
net: phy: aquantia: fix -ETIMEDOUT PHY probe failure when firmware not present
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: ad649a1 ("net: phy: aquantia: wait for FW reset before checking the vendor ID") Reported-by: Clark Wang <[email protected]> Reported-by: Jon Hunter <[email protected]> Closes: https://lore.kernel.org/netdev/[email protected]/ Reported-by: Hans-Frieder Vogt <[email protected]> Closes: https://lore.kernel.org/netdev/[email protected]/ Signed-off-by: Vladimir Oltean <[email protected]> Tested-by: Bartosz Golaszewski <[email protected]> Tested-by: Hans-Frieder Vogt <[email protected]> Link: https://patch.msgid.link/[email protected] Signed-off-by: Paolo Abeni <[email protected]>
1 parent 9410645 commit 194ef9d

File tree

2 files changed

+39
-22
lines changed

2 files changed

+39
-22
lines changed

drivers/net/phy/aquantia/aquantia_firmware.c

Lines changed: 24 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -353,26 +353,32 @@ int aqr_firmware_load(struct phy_device *phydev)
353353
{
354354
int ret;
355355

356-
ret = aqr_wait_reset_complete(phydev);
357-
if (ret)
358-
return ret;
359-
360-
/* Check if the firmware is not already loaded by pooling
361-
* the current version returned by the PHY. If 0 is returned,
362-
* no firmware is loaded.
356+
/* Check if the firmware is not already loaded by polling
357+
* the current version returned by the PHY.
363358
*/
364-
ret = phy_read_mmd(phydev, MDIO_MMD_VEND1, VEND1_GLOBAL_FW_ID);
365-
if (ret > 0)
366-
goto exit;
367-
368-
ret = aqr_firmware_load_nvmem(phydev);
369-
if (!ret)
370-
goto exit;
371-
372-
ret = aqr_firmware_load_fs(phydev);
373-
if (ret)
359+
ret = aqr_wait_reset_complete(phydev);
360+
switch (ret) {
361+
case 0:
362+
/* Some firmware is loaded => do nothing */
363+
return 0;
364+
case -ETIMEDOUT:
365+
/* VEND1_GLOBAL_FW_ID still reads 0 after 2 seconds of polling.
366+
* We don't have full confidence that no firmware is loaded (in
367+
* theory it might just not have loaded yet), but we will
368+
* assume that, and load a new image.
369+
*/
370+
ret = aqr_firmware_load_nvmem(phydev);
371+
if (!ret)
372+
return ret;
373+
374+
ret = aqr_firmware_load_fs(phydev);
375+
if (ret)
376+
return ret;
377+
break;
378+
default:
379+
/* PHY read error, propagate it to the caller */
374380
return ret;
381+
}
375382

376-
exit:
377383
return 0;
378384
}

drivers/net/phy/aquantia/aquantia_main.c

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -435,6 +435,9 @@ static int aqr107_set_tunable(struct phy_device *phydev,
435435
}
436436
}
437437

438+
#define AQR_FW_WAIT_SLEEP_US 20000
439+
#define AQR_FW_WAIT_TIMEOUT_US 2000000
440+
438441
/* If we configure settings whilst firmware is still initializing the chip,
439442
* then these settings may be overwritten. Therefore make sure chip
440443
* initialization has completed. Use presence of the firmware ID as
@@ -444,11 +447,19 @@ static int aqr107_set_tunable(struct phy_device *phydev,
444447
*/
445448
int aqr_wait_reset_complete(struct phy_device *phydev)
446449
{
447-
int val;
450+
int ret, val;
451+
452+
ret = read_poll_timeout(phy_read_mmd, val, val != 0,
453+
AQR_FW_WAIT_SLEEP_US, AQR_FW_WAIT_TIMEOUT_US,
454+
false, phydev, MDIO_MMD_VEND1,
455+
VEND1_GLOBAL_FW_ID);
456+
if (val < 0) {
457+
phydev_err(phydev, "Failed to read VEND1_GLOBAL_FW_ID: %pe\n",
458+
ERR_PTR(val));
459+
return val;
460+
}
448461

449-
return phy_read_mmd_poll_timeout(phydev, MDIO_MMD_VEND1,
450-
VEND1_GLOBAL_FW_ID, val, val != 0,
451-
20000, 2000000, false);
462+
return ret;
452463
}
453464

454465
static void aqr107_chip_info(struct phy_device *phydev)

0 commit comments

Comments
 (0)