mirror of
https://github.com/u-boot/u-boot.git
synced 2025-04-23 05:08:24 +00:00
net: eth-uclass: guard against reentrant eth_init()/eth_halt() calls
With netconsole, any log message can result in an eth_init(), possibly causing an reentrant call into eth_init() if a driver's ops print anything: eth_init() -> driver.start() -> printf() -> netconsole -> eth_init() eth_halt() -> driver.stop() -> printf() -> netconsole -> eth_init() Rather than expecting every single Ethernet driver to handle this case, prevent the reentrant calls in eth_init() and eth_halt(). The issue was noticed on an AM62x board, where a bootm after simultaneous netconsole and TFTP would result in a crash. Signed-off-by: Matthias Schiffer <matthias.schiffer@ew.tq-group.com> Link: https://e2e.ti.com/support/processors-group/processors/f/processors-forum/1350550/sk-am62a-lp-am65_cpsw_nuss_port-error-in-u-boot-while-using-netconsole-functionality/
This commit is contained in:
parent
85e2c6900e
commit
ef9d4da6c9
1 changed files with 32 additions and 8 deletions
|
@ -47,6 +47,8 @@ struct eth_uclass_priv {
|
||||||
|
|
||||||
/* eth_errno - This stores the most recent failure code from DM functions */
|
/* eth_errno - This stores the most recent failure code from DM functions */
|
||||||
static int eth_errno;
|
static int eth_errno;
|
||||||
|
/* Are we currently in eth_init() or eth_halt()? */
|
||||||
|
static bool in_init_halt;
|
||||||
|
|
||||||
/* board-specific Ethernet Interface initializations. */
|
/* board-specific Ethernet Interface initializations. */
|
||||||
__weak int board_interface_eth_init(struct udevice *dev,
|
__weak int board_interface_eth_init(struct udevice *dev,
|
||||||
|
@ -284,11 +286,19 @@ U_BOOT_ENV_CALLBACK(ethaddr, on_ethaddr);
|
||||||
|
|
||||||
int eth_init(void)
|
int eth_init(void)
|
||||||
{
|
{
|
||||||
char *ethact = env_get("ethact");
|
|
||||||
char *ethrotate = env_get("ethrotate");
|
|
||||||
struct udevice *current = NULL;
|
struct udevice *current = NULL;
|
||||||
struct udevice *old_current;
|
struct udevice *old_current;
|
||||||
int ret = -ENODEV;
|
int ret = -ENODEV;
|
||||||
|
char *ethrotate;
|
||||||
|
char *ethact;
|
||||||
|
|
||||||
|
if (in_init_halt)
|
||||||
|
return -EBUSY;
|
||||||
|
|
||||||
|
in_init_halt = true;
|
||||||
|
|
||||||
|
ethact = env_get("ethact");
|
||||||
|
ethrotate = env_get("ethrotate");
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* When 'ethrotate' variable is set to 'no' and 'ethact' variable
|
* When 'ethrotate' variable is set to 'no' and 'ethact' variable
|
||||||
|
@ -297,8 +307,10 @@ int eth_init(void)
|
||||||
if ((ethrotate != NULL) && (strcmp(ethrotate, "no") == 0)) {
|
if ((ethrotate != NULL) && (strcmp(ethrotate, "no") == 0)) {
|
||||||
if (ethact) {
|
if (ethact) {
|
||||||
current = eth_get_dev_by_name(ethact);
|
current = eth_get_dev_by_name(ethact);
|
||||||
if (!current)
|
if (!current) {
|
||||||
return -EINVAL;
|
ret = -EINVAL;
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -306,7 +318,8 @@ int eth_init(void)
|
||||||
current = eth_get_dev();
|
current = eth_get_dev();
|
||||||
if (!current) {
|
if (!current) {
|
||||||
log_err("No ethernet found.\n");
|
log_err("No ethernet found.\n");
|
||||||
return -ENODEV;
|
ret = -ENODEV;
|
||||||
|
goto end;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -323,7 +336,8 @@ int eth_init(void)
|
||||||
|
|
||||||
priv->state = ETH_STATE_ACTIVE;
|
priv->state = ETH_STATE_ACTIVE;
|
||||||
priv->running = true;
|
priv->running = true;
|
||||||
return 0;
|
ret = 0;
|
||||||
|
goto end;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
ret = eth_errno;
|
ret = eth_errno;
|
||||||
|
@ -343,6 +357,8 @@ int eth_init(void)
|
||||||
current = eth_get_dev();
|
current = eth_get_dev();
|
||||||
} while (old_current != current);
|
} while (old_current != current);
|
||||||
|
|
||||||
|
end:
|
||||||
|
in_init_halt = false;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -351,17 +367,25 @@ void eth_halt(void)
|
||||||
struct udevice *current;
|
struct udevice *current;
|
||||||
struct eth_device_priv *priv;
|
struct eth_device_priv *priv;
|
||||||
|
|
||||||
|
if (in_init_halt)
|
||||||
|
return;
|
||||||
|
|
||||||
|
in_init_halt = true;
|
||||||
|
|
||||||
current = eth_get_dev();
|
current = eth_get_dev();
|
||||||
if (!current)
|
if (!current)
|
||||||
return;
|
goto end;
|
||||||
|
|
||||||
priv = dev_get_uclass_priv(current);
|
priv = dev_get_uclass_priv(current);
|
||||||
if (!priv || !priv->running)
|
if (!priv || !priv->running)
|
||||||
return;
|
goto end;
|
||||||
|
|
||||||
eth_get_ops(current)->stop(current);
|
eth_get_ops(current)->stop(current);
|
||||||
priv->state = ETH_STATE_PASSIVE;
|
priv->state = ETH_STATE_PASSIVE;
|
||||||
priv->running = false;
|
priv->running = false;
|
||||||
|
|
||||||
|
end:
|
||||||
|
in_init_halt = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
int eth_is_active(struct udevice *dev)
|
int eth_is_active(struct udevice *dev)
|
||||||
|
|
Loading…
Add table
Reference in a new issue