diff mbox series

[net,v3] net: dsa: lan9303: ensure chip reset and wait for READY status

Message ID 20241004090332.3252564-1-alexander.sverdlin@siemens.com (mailing list archive)
State Superseded
Delegated to: Netdev Maintainers
Headers show
Series [net,v3] net: dsa: lan9303: ensure chip reset and wait for READY status | expand

Checks

Context Check Description
netdev/series_format success Single patches do not need cover letters
netdev/tree_selection success Clearly marked for net
netdev/ynl success Generated files up to date; no warnings/errors; no diff in generated;
netdev/fixes_present fail Series targets non-next tree, but doesn't contain any Fixes tags
netdev/header_inline success No static functions without inline keyword in header files
netdev/build_32bit success Errors and warnings before: 6 this patch: 6
netdev/build_tools success No tools touched, skip
netdev/cc_maintainers warning 3 maintainers not CCed: pabeni@redhat.com kuba@kernel.org edumazet@google.com
netdev/build_clang success Errors and warnings before: 6 this patch: 6
netdev/verify_signedoff success Signed-off-by tag matches author and committer
netdev/deprecated_api success None detected
netdev/check_selftest success No net selftest shell script
netdev/verify_fixes success No Fixes tag
netdev/build_allmodconfig_warn success Errors and warnings before: 5 this patch: 5
netdev/checkpatch success total: 0 errors, 0 warnings, 0 checks, 45 lines checked
netdev/build_clang_rust success No Rust files in patch. Skipping build
netdev/kdoc success Errors and warnings before: 0 this patch: 0
netdev/source_inline success Was 0 now: 0

Commit Message

Sverdlin, Alexander Oct. 4, 2024, 9:03 a.m. UTC
From: Anatolij Gustschin <agust@denx.de>

Accessing device registers seems to be not reliable, the chip
revision is sometimes detected wrongly (0 instead of expected 1).

Ensure that the chip reset is performed via reset GPIO and then
wait for 'Device Ready' status in HW_CFG register before doing
any register initializations.

Signed-off-by: Anatolij Gustschin <agust@denx.de>
[alex: reworked using read_poll_timeout()]
Signed-off-by: Alexander Sverdlin <alexander.sverdlin@siemens.com>
---
Changelog:
v3: comment style, use "!ret" in stop condition, user-readable error code
v2: use read_poll_timeout()

 drivers/net/dsa/lan9303-core.c | 27 +++++++++++++++++++++++++++
 1 file changed, 27 insertions(+)

Comments

Vladimir Oltean Oct. 4, 2024, 10:18 a.m. UTC | #1
On Fri, Oct 04, 2024 at 11:03:31AM +0200, A. Sverdlin wrote:
> From: Anatolij Gustschin <agust@denx.de>
> 
> Accessing device registers seems to be not reliable, the chip
> revision is sometimes detected wrongly (0 instead of expected 1).
> 
> Ensure that the chip reset is performed via reset GPIO and then
> wait for 'Device Ready' status in HW_CFG register before doing
> any register initializations.
> 
> Signed-off-by: Anatolij Gustschin <agust@denx.de>
> [alex: reworked using read_poll_timeout()]
> Signed-off-by: Alexander Sverdlin <alexander.sverdlin@siemens.com>
> ---
> Changelog:
> v3: comment style, use "!ret" in stop condition, user-readable error code
> v2: use read_poll_timeout()
> 
>  drivers/net/dsa/lan9303-core.c | 27 +++++++++++++++++++++++++++
>  1 file changed, 27 insertions(+)
> 
> diff --git a/drivers/net/dsa/lan9303-core.c b/drivers/net/dsa/lan9303-core.c
> index 268949939636a..f478b55d4d297 100644
> --- a/drivers/net/dsa/lan9303-core.c
> +++ b/drivers/net/dsa/lan9303-core.c
> @@ -6,6 +6,7 @@
>  #include <linux/module.h>
>  #include <linux/gpio/consumer.h>
>  #include <linux/regmap.h>
> +#include <linux/iopoll.h>
>  #include <linux/mutex.h>
>  #include <linux/mii.h>
>  #include <linux/of.h>
> @@ -839,6 +840,8 @@ static void lan9303_handle_reset(struct lan9303 *chip)
>  	if (!chip->reset_gpio)
>  		return;
>  
> +	gpiod_set_value_cansleep(chip->reset_gpio, 1);
> +
>  	if (chip->reset_duration != 0)
>  		msleep(chip->reset_duration);
>  
> @@ -866,6 +869,30 @@ static int lan9303_check_device(struct lan9303 *chip)
>  	int ret;
>  	u32 reg;
>  
> +	/* In I2C-managed configurations this polling loop will clash with
> +	 * switch's reading of EEPROM right after reset and this behaviour is
> +	 * not configurable. While lan9303_read() already has quite long retry
> +	 * timeout, seems not all cases are being detected as arbitration error.
> +	 *
> +	 * According to datasheet, EEPROM loader has 30ms timeout (in case of
> +	 * missing EEPROM).
> +	 *
> +	 * Loading of the largest supported EEPROM is expected to take at least
> +	 * 5.9s.
> +	 */
> +	if (read_poll_timeout(lan9303_read, ret,
> +			      !ret && reg & LAN9303_HW_CFG_READY,
> +			      20000, 6000000, false,
> +			      chip->regmap, LAN9303_HW_CFG, &reg)) {
> +		dev_err(chip->dev, "HW_CFG not ready: 0x%08x\n", reg);
> +		return -ETIMEDOUT;

Please:

	int ret, err;

	err = read_poll_timeout();
	if (err)
		ret = err;
	if (ret) {
		dev_err(chip->dev, "failed to read HW_CFG reg: %pe\n",
			ERR_PTR(ret));
		return ret;
	}

No hardcoding of -ETIMEDOUT either.

> +	}
> +	if (ret) {
> +		dev_err(chip->dev, "failed to read HW_CFG reg: %pe\n",
> +			ERR_PTR(ret));
> +		return ret;
> +	}
> +
>  	ret = lan9303_read(chip->regmap, LAN9303_CHIP_REV, &reg);
>  	if (ret) {
>  		dev_err(chip->dev, "failed to read chip revision register: %d\n",
> -- 
> 2.46.2
>
Sverdlin, Alexander Oct. 4, 2024, 11:42 a.m. UTC | #2
Hi Vladimir!

On Fri, 2024-10-04 at 13:18 +0300, Vladimir Oltean wrote:
> > +	if (read_poll_timeout(lan9303_read, ret,
> > +			      !ret && reg & LAN9303_HW_CFG_READY,
> > +			      20000, 6000000, false,
> > +			      chip->regmap, LAN9303_HW_CFG, &reg)) {
> > +		dev_err(chip->dev, "HW_CFG not ready: 0x%08x\n", reg);
> > +		return -ETIMEDOUT;
> 
> Please:
> 
> 	int ret, err;
> 
> 	err = read_poll_timeout();
> 	if (err)
> 		ret = err;
> 	if (ret) {
> 		dev_err(chip->dev, "failed to read HW_CFG reg: %pe\n",
> 			ERR_PTR(ret));
> 		return ret;
> 	}
> 
> No hardcoding of -ETIMEDOUT either.

I've removed the hardcoded -ETIMEDOUT in the v4, but retained different
error messages, because I believe, individual read errors could be more
informative than generic -ETIMEDOUT, including, maybe even the actual
register value.
diff mbox series

Patch

diff --git a/drivers/net/dsa/lan9303-core.c b/drivers/net/dsa/lan9303-core.c
index 268949939636a..f478b55d4d297 100644
--- a/drivers/net/dsa/lan9303-core.c
+++ b/drivers/net/dsa/lan9303-core.c
@@ -6,6 +6,7 @@ 
 #include <linux/module.h>
 #include <linux/gpio/consumer.h>
 #include <linux/regmap.h>
+#include <linux/iopoll.h>
 #include <linux/mutex.h>
 #include <linux/mii.h>
 #include <linux/of.h>
@@ -839,6 +840,8 @@  static void lan9303_handle_reset(struct lan9303 *chip)
 	if (!chip->reset_gpio)
 		return;
 
+	gpiod_set_value_cansleep(chip->reset_gpio, 1);
+
 	if (chip->reset_duration != 0)
 		msleep(chip->reset_duration);
 
@@ -866,6 +869,30 @@  static int lan9303_check_device(struct lan9303 *chip)
 	int ret;
 	u32 reg;
 
+	/* In I2C-managed configurations this polling loop will clash with
+	 * switch's reading of EEPROM right after reset and this behaviour is
+	 * not configurable. While lan9303_read() already has quite long retry
+	 * timeout, seems not all cases are being detected as arbitration error.
+	 *
+	 * According to datasheet, EEPROM loader has 30ms timeout (in case of
+	 * missing EEPROM).
+	 *
+	 * Loading of the largest supported EEPROM is expected to take at least
+	 * 5.9s.
+	 */
+	if (read_poll_timeout(lan9303_read, ret,
+			      !ret && reg & LAN9303_HW_CFG_READY,
+			      20000, 6000000, false,
+			      chip->regmap, LAN9303_HW_CFG, &reg)) {
+		dev_err(chip->dev, "HW_CFG not ready: 0x%08x\n", reg);
+		return -ETIMEDOUT;
+	}
+	if (ret) {
+		dev_err(chip->dev, "failed to read HW_CFG reg: %pe\n",
+			ERR_PTR(ret));
+		return ret;
+	}
+
 	ret = lan9303_read(chip->regmap, LAN9303_CHIP_REV, &reg);
 	if (ret) {
 		dev_err(chip->dev, "failed to read chip revision register: %d\n",