summaryrefslogtreecommitdiff
path: root/net
diff options
context:
space:
mode:
authorMatthias Schiffer <matthias.schiffer@ew.tq-group.com>2020-11-04 16:45:14 +0300
committerTom Rini <trini@konsulko.com>2021-01-19 17:06:15 +0300
commitfa795f452541ce07b33be603de36cac3c5d7dfcf (patch)
tree7830e3f9612e2f2d2fa0e9e1c5d52e37a5257457 /net
parentdb0dd72e27ce62c5b28f07595b91ed00d0565819 (diff)
downloadu-boot-fa795f452541ce07b33be603de36cac3c5d7dfcf.tar.xz
net: eth-uclass: avoid running start() twice without stop()
Running the start() handler twice without a stop() inbetween completely breaks communication for some ethernet drivers like fec_mxc. eth_halt() is called before each eth_init(). Due to the switch to eth_is_active() in commit 68acb51f442f ("net: Only call halt on a driver that has been init'ed"), this is not sufficient anymore when netconsole is active: eth_init_state_only()/eth_halt_state_only() manipulate the state check that is performed by eth_is_active() without actually calling into the driver. The issue can be triggered by starting a network operation (e.g. ping or tftp) while netconsole is active. Add an additional "running" flag that reflects the actual state of the driver and use it to ensure that eth_halt() actually stops the device as it is supposed to. Fixes: 68acb51f442f ("net: Only call halt on a driver that has been init'ed") Signed-off-by: Matthias Schiffer <matthias.schiffer@ew.tq-group.com>
Diffstat (limited to 'net')
-rw-r--r--net/eth-uclass.c14
1 files changed, 10 insertions, 4 deletions
diff --git a/net/eth-uclass.c b/net/eth-uclass.c
index 0156324032..7c2454f5ae 100644
--- a/net/eth-uclass.c
+++ b/net/eth-uclass.c
@@ -26,6 +26,7 @@ DECLARE_GLOBAL_DATA_PTR;
*/
struct eth_device_priv {
enum eth_state_t state;
+ bool running;
};
/**
@@ -290,6 +291,7 @@ int eth_init(void)
dev_get_uclass_priv(current);
priv->state = ETH_STATE_ACTIVE;
+ priv->running = true;
return 0;
}
} else {
@@ -319,13 +321,16 @@ void eth_halt(void)
struct eth_device_priv *priv;
current = eth_get_dev();
- if (!current || !eth_is_active(current))
+ if (!current)
return;
- eth_get_ops(current)->stop(current);
priv = dev_get_uclass_priv(current);
- if (priv)
- priv->state = ETH_STATE_PASSIVE;
+ if (!priv || !priv->running)
+ return;
+
+ eth_get_ops(current)->stop(current);
+ priv->state = ETH_STATE_PASSIVE;
+ priv->running = false;
}
int eth_is_active(struct udevice *dev)
@@ -534,6 +539,7 @@ static int eth_post_probe(struct udevice *dev)
#endif
priv->state = ETH_STATE_INIT;
+ priv->running = false;
/* Check if the device has a valid MAC address in device tree */
if (!eth_dev_get_mac_address(dev, pdata->enetaddr) ||