
If we set the status after successful init call then we get in trouble if stdout (or setderr) is set to netconsole. If we are going to use one of those (lets say printf) during ->init() the following happens: - network is of (state passive) - we switch on netconsole - nc_getc() gets called - in NetLoop() we switch on ethernet via eth_init() - we end up in tsec_init() (inc case we use the tsec driver). Here we call a printf() - That printf() ends up in nc_puts() because netconsole is our default output. - The state is not active yet, so we call eth_init() once again. - and we are again in tsec_init(). Another printf() is waiting. However, due to the recursion check nc_puts() returns early before doing anything. - we return from each function. Sine nc_puts() thinks that it was in charge of enabling the ethernet, it disables it before leaving. - We return now to the top-most eth_init() function. Since everything went fine, it sets the status to active. In reality the network is switched off. - nc_getc() gets called over and over to receive new packets. Sadly the nic is disabled and new network packets won't be noticed.
This patch sets the network status early so nc_puts() does not get confused and disables the network interface in case of a printf() on its way.
Signed-off-by: Sebastian Andrzej Siewior bigeasy@linutronix.de --- net/eth.c | 11 +++++++---- 1 files changed, 7 insertions(+), 4 deletions(-)
diff --git a/net/eth.c b/net/eth.c index 4280d6d..bca405a 100644 --- a/net/eth.c +++ b/net/eth.c @@ -380,14 +380,17 @@ int eth_init(bd_t *bis)
old_current = eth_current; do { + int old_state; + debug("Trying %s\n", eth_current->name);
- if (eth_current->init(eth_current,bis) >= 0) { - eth_current->state = ETH_STATE_ACTIVE; - + old_state = eth_current->state; + eth_current->state = ETH_STATE_ACTIVE; + if (eth_current->init(eth_current,bis) >= 0) return 0; - } + debug("FAIL\n"); + eth_current->state = old_state;
eth_try_another(0); } while (old_current != eth_current);