diff mbox

[U-Boot,v2] net: Improve the speed of netconsole

Message ID 1344027548-32373-1-git-send-email-joe.hershberger@ni.com
State Accepted
Delegated to: Joe Hershberger
Headers show

Commit Message

Joe Hershberger Aug. 3, 2012, 8:59 p.m. UTC
Previously u-boot would initialize the network interface for every
network operation and then shut it down again.  This makes sense for
most operations where the network in not known to be needed soon after
the operation is complete.  In the case of netconsole, it will use the
network for every interaction with the shell or every printf.  This
means that the network is being reinitialized very often.  On many
devices, this intialization is very slow.

This patch checks for consecutive netconsole actions and leaves the
ethernet hardware initialized between them.  It will still behave the
same old way for all other network operations and any time another
network operation happens between netconsole operations.

Signed-off-by: Joe Hershberger <joe.hershberger@ni.com>
Cc: Stefano Babic <sbabic@denx.de>
---
 common/cmd_bootm.c       |   17 +++++++++++++++++
 drivers/net/netconsole.c |   22 ++++++++++++++++++----
 include/net.h            |   42 +++++++++++++++++++++++++++++++++++++++++-
 net/eth.c                |    8 ++------
 net/net.c                |   26 ++++++++++++++++++++------
 5 files changed, 98 insertions(+), 17 deletions(-)

Comments

Stefano Babic Aug. 10, 2012, 4:22 p.m. UTC | #1
On 03/08/2012 22:59, Joe Hershberger wrote:
> Previously u-boot would initialize the network interface for every
> network operation and then shut it down again.  This makes sense for
> most operations where the network in not known to be needed soon after
> the operation is complete.  In the case of netconsole, it will use the
> network for every interaction with the shell or every printf.  This
> means that the network is being reinitialized very often.  On many
> devices, this intialization is very slow.
> 
> This patch checks for consecutive netconsole actions and leaves the
> ethernet hardware initialized between them.  It will still behave the
> same old way for all other network operations and any time another
> network operation happens between netconsole operations.
> 

Hi Joe,

> Signed-off-by: Joe Hershberger <joe.hershberger@ni.com>
> Cc: Stefano Babic <sbabic@denx.de>
> ---
>  common/cmd_bootm.c       |   17 +++++++++++++++++
>  drivers/net/netconsole.c |   22 ++++++++++++++++++----
>  include/net.h            |   42 +++++++++++++++++++++++++++++++++++++++++-
>  net/eth.c                |    8 ++------
>  net/net.c                |   26 ++++++++++++++++++++------
>  5 files changed, 98 insertions(+), 17 deletions(-)
> 
> diff --git a/common/cmd_bootm.c b/common/cmd_bootm.c
> index 45e726a..83fa5d7 100644
> --- a/common/cmd_bootm.c
> +++ b/common/cmd_bootm.c
> @@ -564,6 +564,13 @@ int do_bootm_subcommand(cmd_tbl_t *cmdtp, int flag, int argc,
>  			break;
>  		case BOOTM_STATE_OS_GO:
>  			disable_interrupts();
> +#ifdef CONFIG_NETCONSOLE
> +			/*
> +			 * Stop the ethernet stack if NetConsole could have
> +			 * left it up
> +			 */
> +			eth_halt();
> +#endif
>  			arch_preboot_os();
>  			boot_fn(BOOTM_STATE_OS_GO, argc, argv, &images);
>  			break;
> @@ -622,6 +629,11 @@ int do_bootm(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
>  	 */
>  	iflag = disable_interrupts();
>  
> +#ifdef CONFIG_NETCONSOLE
> +	/* Stop the ethernet stack if NetConsole could have left it up */
> +	eth_halt();
> +#endif
> +
>  #if defined(CONFIG_CMD_USB)
>  	/*
>  	 * turn off USB to prevent the host controller from writing to the
> @@ -1599,6 +1611,11 @@ static int do_bootz(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
>  	 */
>  	disable_interrupts();
>  
> +#ifdef CONFIG_NETCONSOLE
> +	/* Stop the ethernet stack if NetConsole could have left it up */
> +	eth_halt();
> +#endif
> +
>  #if defined(CONFIG_CMD_USB)
>  	/*
>  	 * turn off USB to prevent the host controller from writing to the
> diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c
> index 14243b8..069ad87 100644
> --- a/drivers/net/netconsole.c
> +++ b/drivers/net/netconsole.c
> @@ -39,6 +39,11 @@ static IPaddr_t nc_ip; /* server ip */
>  static short nc_port; /* source/target port */
>  static const char *output_packet; /* used by first send udp */
>  static int output_packet_len;
> +/*
> + * Start with a default last protocol.
> + * We are only interested in NETCONS or not.
> + */
> +enum proto_t net_loop_last_protocol = BOOTP;
>  
>  static void nc_wait_arp_handler(uchar *pkt, unsigned dest,
>  				 IPaddr_t sip, unsigned src,
> @@ -131,8 +136,13 @@ static void nc_send_packet(const char *buf, int len)
>  	}
>  
>  	if (eth->state != ETH_STATE_ACTIVE) {
> -		if (eth_init(gd->bd) < 0)
> -			return;
> +		if (eth_is_on_demand_init()) {
> +			if (eth_init(gd->bd) < 0)
> +				return;
> +			eth_set_last_protocol(NETCONS);
> +		} else
> +			eth_init_state_only(gd->bd);
> +
>  		inited = 1;
>  	}
>  	pkt = (uchar *)NetTxPacket + NetEthHdrSize() + IP_UDP_HDR_SIZE;
> @@ -141,8 +151,12 @@ static void nc_send_packet(const char *buf, int len)
>  	ip = nc_ip;
>  	NetSendUDPPacket(ether, ip, nc_port, nc_port, len);
>  
> -	if (inited)
> -		eth_halt();
> +	if (inited) {
> +		if (eth_is_on_demand_init())
> +			eth_halt();
> +		else
> +			eth_halt_state_only();
> +	}
>  }
>  
>  static int nc_start(void)
> diff --git a/include/net.h b/include/net.h
> index 6d2d6cd..e193b7b 100644
> --- a/include/net.h
> +++ b/include/net.h
> @@ -102,7 +102,14 @@ extern int eth_register(struct eth_device* dev);/* Register network device */
>  extern int eth_unregister(struct eth_device *dev);/* Remove network device */
>  extern void eth_try_another(int first_restart);	/* Change the device */
>  extern void eth_set_current(void);		/* set nterface to ethcur var */
> -extern struct eth_device *eth_get_dev(void);	/* get the current device MAC */
> +/* get the current device MAC */
> +static inline __attribute__((always_inline))
> +struct eth_device *eth_get_dev(void)
> +{
> +	extern struct eth_device *eth_current;
> +
> +	return eth_current;
> +}
>  extern struct eth_device *eth_get_dev_by_name(const char *devname);
>  extern struct eth_device *eth_get_dev_by_index(int index); /* get dev @ index */
>  extern int eth_get_dev_index(void);		/* get the device index */
> @@ -151,6 +158,19 @@ extern int eth_rx(void);			/* Check for received packets */
>  extern void eth_halt(void);			/* stop SCC */
>  extern char *eth_get_name(void);		/* get name of current device */
>  
> +/* Set active state */
> +static inline __attribute__((always_inline)) int eth_init_state_only(bd_t *bis)
> +{
> +	eth_get_dev()->state = ETH_STATE_ACTIVE;
> +
> +	return 0;
> +}
> +/* Set passive state */
> +static inline __attribute__((always_inline)) void eth_halt_state_only(void)
> +{
> +	eth_get_dev()->state = ETH_STATE_PASSIVE;
> +}
> +
>  /*
>   * Set the hardware address for an ethernet interface based on 'eth%daddr'
>   * environment variable (or just 'ethaddr' if eth_number is 0).
> @@ -532,6 +552,26 @@ void NcStart(void);
>  int nc_input_packet(uchar *pkt, unsigned dest, unsigned src, unsigned len);
>  #endif
>  
> +static inline __attribute__((always_inline)) int eth_is_on_demand_init(void)
> +{
> +#ifdef CONFIG_NETCONSOLE
> +	extern enum proto_t net_loop_last_protocol;
> +
> +	return net_loop_last_protocol != NETCONS;
> +#else
> +	return 1;
> +#endif
> +}
> +
> +static inline void eth_set_last_protocol(int protocol)
> +{
> +#ifdef CONFIG_NETCONSOLE
> +	extern enum proto_t net_loop_last_protocol;
> +
> +	net_loop_last_protocol = protocol;
> +#endif
> +}
> +
>  /*
>   * Check if autoload is enabled. If so, use either NFS or TFTP to download
>   * the boot file.
> diff --git a/net/eth.c b/net/eth.c
> index 1a11ce1..66295b6 100644
> --- a/net/eth.c
> +++ b/net/eth.c
> @@ -121,12 +121,8 @@ static struct {
>  static unsigned int eth_rcv_current, eth_rcv_last;
>  #endif
>  
> -static struct eth_device *eth_devices, *eth_current;
> -
> -struct eth_device *eth_get_dev(void)
> -{
> -	return eth_current;
> -}
> +static struct eth_device *eth_devices;
> +struct eth_device *eth_current;
>  
>  struct eth_device *eth_get_dev_by_name(const char *devname)
>  {
> diff --git a/net/net.c b/net/net.c
> index e8ff066..f002cda 100644
> --- a/net/net.c
> +++ b/net/net.c
> @@ -315,12 +315,15 @@ int NetLoop(enum proto_t protocol)
>  
>  	bootstage_mark_name(BOOTSTAGE_ID_ETH_START, "eth_start");
>  	net_init();
> -	eth_halt();
> -	eth_set_current();
> -	if (eth_init(bd) < 0) {
> +	if (eth_is_on_demand_init() || protocol != NETCONS) {
>  		eth_halt();
> -		return -1;
> -	}
> +		eth_set_current();
> +		if (eth_init(bd) < 0) {
> +			eth_halt();
> +			return -1;
> +		}
> +	} else
> +		eth_init_state_only(bd);
>  
>  restart:
>  	net_set_state(NETLOOP_CONTINUE);
> @@ -460,6 +463,9 @@ restart:
>  
>  			net_cleanup_loop();
>  			eth_halt();
> +			/* Invalidate the last protocol */
> +			eth_set_last_protocol(BOOTP);
> +
>  			puts("\nAbort\n");
>  			/* include a debug print as well incase the debug
>  			   messages are directed to stderr */
> @@ -517,13 +523,21 @@ restart:
>  				sprintf(buf, "%lX", (unsigned long)load_addr);
>  				setenv("fileaddr", buf);
>  			}
> -			eth_halt();
> +			if (protocol != NETCONS)
> +				eth_halt();
> +			else
> +				eth_halt_state_only();
> +
> +			eth_set_last_protocol(protocol);
> +
>  			ret = NetBootFileXferSize;
>  			debug_cond(DEBUG_INT_STATE, "--- NetLoop Success!\n");
>  			goto done;
>  
>  		case NETLOOP_FAIL:
>  			net_cleanup_loop();
> +			/* Invalidate the last protocol */
> +			eth_set_last_protocol(BOOTP);
>  			debug_cond(DEBUG_INT_STATE, "--- NetLoop Fail!\n");
>  			goto done;
>  
> 

Acked-by: Stefano Babic <sbabic@denx.de>

Best regards,
Stefano
Joe Hershberger Aug. 10, 2012, 7:09 p.m. UTC | #2
Hi Mike,

On Fri, Aug 3, 2012 at 3:59 PM, Joe Hershberger <joe.hershberger@ni.com> wrote:
> Previously u-boot would initialize the network interface for every
> network operation and then shut it down again.  This makes sense for
> most operations where the network in not known to be needed soon after
> the operation is complete.  In the case of netconsole, it will use the
> network for every interaction with the shell or every printf.  This
> means that the network is being reinitialized very often.  On many
> devices, this intialization is very slow.
>
> This patch checks for consecutive netconsole actions and leaves the
> ethernet hardware initialized between them.  It will still behave the
> same old way for all other network operations and any time another
> network operation happens between netconsole operations.
>
> Signed-off-by: Joe Hershberger <joe.hershberger@ni.com>
> Cc: Stefano Babic <sbabic@denx.de>

Sorry I forgot to Cc you on the update... I also forgot the revision notes...

Changes since v1:
 - Halt Ethernet stack before booting Linux
 - Clean up CPP guard noise
 - Reduce overhead of no-re-init case

> ---
>  common/cmd_bootm.c       |   17 +++++++++++++++++
>  drivers/net/netconsole.c |   22 ++++++++++++++++++----
>  include/net.h            |   42 +++++++++++++++++++++++++++++++++++++++++-
>  net/eth.c                |    8 ++------
>  net/net.c                |   26 ++++++++++++++++++++------
>  5 files changed, 98 insertions(+), 17 deletions(-)
>
> diff --git a/common/cmd_bootm.c b/common/cmd_bootm.c
> index 45e726a..83fa5d7 100644
> --- a/common/cmd_bootm.c
> +++ b/common/cmd_bootm.c
> @@ -564,6 +564,13 @@ int do_bootm_subcommand(cmd_tbl_t *cmdtp, int flag, int argc,
>                         break;
>                 case BOOTM_STATE_OS_GO:
>                         disable_interrupts();
> +#ifdef CONFIG_NETCONSOLE
> +                       /*
> +                        * Stop the ethernet stack if NetConsole could have
> +                        * left it up
> +                        */
> +                       eth_halt();
> +#endif
>                         arch_preboot_os();
>                         boot_fn(BOOTM_STATE_OS_GO, argc, argv, &images);
>                         break;
> @@ -622,6 +629,11 @@ int do_bootm(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
>          */
>         iflag = disable_interrupts();
>
> +#ifdef CONFIG_NETCONSOLE
> +       /* Stop the ethernet stack if NetConsole could have left it up */
> +       eth_halt();
> +#endif
> +
>  #if defined(CONFIG_CMD_USB)
>         /*
>          * turn off USB to prevent the host controller from writing to the
> @@ -1599,6 +1611,11 @@ static int do_bootz(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
>          */
>         disable_interrupts();
>
> +#ifdef CONFIG_NETCONSOLE
> +       /* Stop the ethernet stack if NetConsole could have left it up */
> +       eth_halt();
> +#endif
> +
>  #if defined(CONFIG_CMD_USB)
>         /*
>          * turn off USB to prevent the host controller from writing to the
> diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c
> index 14243b8..069ad87 100644
> --- a/drivers/net/netconsole.c
> +++ b/drivers/net/netconsole.c
> @@ -39,6 +39,11 @@ static IPaddr_t nc_ip; /* server ip */
>  static short nc_port; /* source/target port */
>  static const char *output_packet; /* used by first send udp */
>  static int output_packet_len;
> +/*
> + * Start with a default last protocol.
> + * We are only interested in NETCONS or not.
> + */
> +enum proto_t net_loop_last_protocol = BOOTP;
>
>  static void nc_wait_arp_handler(uchar *pkt, unsigned dest,
>                                  IPaddr_t sip, unsigned src,
> @@ -131,8 +136,13 @@ static void nc_send_packet(const char *buf, int len)
>         }
>
>         if (eth->state != ETH_STATE_ACTIVE) {
> -               if (eth_init(gd->bd) < 0)
> -                       return;
> +               if (eth_is_on_demand_init()) {
> +                       if (eth_init(gd->bd) < 0)
> +                               return;
> +                       eth_set_last_protocol(NETCONS);
> +               } else
> +                       eth_init_state_only(gd->bd);
> +
>                 inited = 1;
>         }
>         pkt = (uchar *)NetTxPacket + NetEthHdrSize() + IP_UDP_HDR_SIZE;
> @@ -141,8 +151,12 @@ static void nc_send_packet(const char *buf, int len)
>         ip = nc_ip;
>         NetSendUDPPacket(ether, ip, nc_port, nc_port, len);
>
> -       if (inited)
> -               eth_halt();
> +       if (inited) {
> +               if (eth_is_on_demand_init())
> +                       eth_halt();
> +               else
> +                       eth_halt_state_only();
> +       }
>  }
>
>  static int nc_start(void)
> diff --git a/include/net.h b/include/net.h
> index 6d2d6cd..e193b7b 100644
> --- a/include/net.h
> +++ b/include/net.h
> @@ -102,7 +102,14 @@ extern int eth_register(struct eth_device* dev);/* Register network device */
>  extern int eth_unregister(struct eth_device *dev);/* Remove network device */
>  extern void eth_try_another(int first_restart);        /* Change the device */
>  extern void eth_set_current(void);             /* set nterface to ethcur var */
> -extern struct eth_device *eth_get_dev(void);   /* get the current device MAC */
> +/* get the current device MAC */
> +static inline __attribute__((always_inline))
> +struct eth_device *eth_get_dev(void)
> +{
> +       extern struct eth_device *eth_current;
> +
> +       return eth_current;
> +}
>  extern struct eth_device *eth_get_dev_by_name(const char *devname);
>  extern struct eth_device *eth_get_dev_by_index(int index); /* get dev @ index */
>  extern int eth_get_dev_index(void);            /* get the device index */
> @@ -151,6 +158,19 @@ extern int eth_rx(void);                   /* Check for received packets */
>  extern void eth_halt(void);                    /* stop SCC */
>  extern char *eth_get_name(void);               /* get name of current device */
>
> +/* Set active state */
> +static inline __attribute__((always_inline)) int eth_init_state_only(bd_t *bis)
> +{
> +       eth_get_dev()->state = ETH_STATE_ACTIVE;
> +
> +       return 0;
> +}
> +/* Set passive state */
> +static inline __attribute__((always_inline)) void eth_halt_state_only(void)
> +{
> +       eth_get_dev()->state = ETH_STATE_PASSIVE;
> +}
> +
>  /*
>   * Set the hardware address for an ethernet interface based on 'eth%daddr'
>   * environment variable (or just 'ethaddr' if eth_number is 0).
> @@ -532,6 +552,26 @@ void NcStart(void);
>  int nc_input_packet(uchar *pkt, unsigned dest, unsigned src, unsigned len);
>  #endif
>
> +static inline __attribute__((always_inline)) int eth_is_on_demand_init(void)
> +{
> +#ifdef CONFIG_NETCONSOLE
> +       extern enum proto_t net_loop_last_protocol;
> +
> +       return net_loop_last_protocol != NETCONS;
> +#else
> +       return 1;
> +#endif
> +}
> +
> +static inline void eth_set_last_protocol(int protocol)
> +{
> +#ifdef CONFIG_NETCONSOLE
> +       extern enum proto_t net_loop_last_protocol;
> +
> +       net_loop_last_protocol = protocol;
> +#endif
> +}
> +
>  /*
>   * Check if autoload is enabled. If so, use either NFS or TFTP to download
>   * the boot file.
> diff --git a/net/eth.c b/net/eth.c
> index 1a11ce1..66295b6 100644
> --- a/net/eth.c
> +++ b/net/eth.c
> @@ -121,12 +121,8 @@ static struct {
>  static unsigned int eth_rcv_current, eth_rcv_last;
>  #endif
>
> -static struct eth_device *eth_devices, *eth_current;
> -
> -struct eth_device *eth_get_dev(void)
> -{
> -       return eth_current;
> -}
> +static struct eth_device *eth_devices;
> +struct eth_device *eth_current;
>
>  struct eth_device *eth_get_dev_by_name(const char *devname)
>  {
> diff --git a/net/net.c b/net/net.c
> index e8ff066..f002cda 100644
> --- a/net/net.c
> +++ b/net/net.c
> @@ -315,12 +315,15 @@ int NetLoop(enum proto_t protocol)
>
>         bootstage_mark_name(BOOTSTAGE_ID_ETH_START, "eth_start");
>         net_init();
> -       eth_halt();
> -       eth_set_current();
> -       if (eth_init(bd) < 0) {
> +       if (eth_is_on_demand_init() || protocol != NETCONS) {
>                 eth_halt();
> -               return -1;
> -       }
> +               eth_set_current();
> +               if (eth_init(bd) < 0) {
> +                       eth_halt();
> +                       return -1;
> +               }
> +       } else
> +               eth_init_state_only(bd);
>
>  restart:
>         net_set_state(NETLOOP_CONTINUE);
> @@ -460,6 +463,9 @@ restart:
>
>                         net_cleanup_loop();
>                         eth_halt();
> +                       /* Invalidate the last protocol */
> +                       eth_set_last_protocol(BOOTP);
> +
>                         puts("\nAbort\n");
>                         /* include a debug print as well incase the debug
>                            messages are directed to stderr */
> @@ -517,13 +523,21 @@ restart:
>                                 sprintf(buf, "%lX", (unsigned long)load_addr);
>                                 setenv("fileaddr", buf);
>                         }
> -                       eth_halt();
> +                       if (protocol != NETCONS)
> +                               eth_halt();
> +                       else
> +                               eth_halt_state_only();
> +
> +                       eth_set_last_protocol(protocol);
> +
>                         ret = NetBootFileXferSize;
>                         debug_cond(DEBUG_INT_STATE, "--- NetLoop Success!\n");
>                         goto done;
>
>                 case NETLOOP_FAIL:
>                         net_cleanup_loop();
> +                       /* Invalidate the last protocol */
> +                       eth_set_last_protocol(BOOTP);
>                         debug_cond(DEBUG_INT_STATE, "--- NetLoop Fail!\n");
>                         goto done;
>
> --
> 1.6.0.2
>
> _______________________________________________
> U-Boot mailing list
> U-Boot@lists.denx.de
> http://lists.denx.de/mailman/listinfo/u-boot
diff mbox

Patch

diff --git a/common/cmd_bootm.c b/common/cmd_bootm.c
index 45e726a..83fa5d7 100644
--- a/common/cmd_bootm.c
+++ b/common/cmd_bootm.c
@@ -564,6 +564,13 @@  int do_bootm_subcommand(cmd_tbl_t *cmdtp, int flag, int argc,
 			break;
 		case BOOTM_STATE_OS_GO:
 			disable_interrupts();
+#ifdef CONFIG_NETCONSOLE
+			/*
+			 * Stop the ethernet stack if NetConsole could have
+			 * left it up
+			 */
+			eth_halt();
+#endif
 			arch_preboot_os();
 			boot_fn(BOOTM_STATE_OS_GO, argc, argv, &images);
 			break;
@@ -622,6 +629,11 @@  int do_bootm(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 	 */
 	iflag = disable_interrupts();
 
+#ifdef CONFIG_NETCONSOLE
+	/* Stop the ethernet stack if NetConsole could have left it up */
+	eth_halt();
+#endif
+
 #if defined(CONFIG_CMD_USB)
 	/*
 	 * turn off USB to prevent the host controller from writing to the
@@ -1599,6 +1611,11 @@  static int do_bootz(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 	 */
 	disable_interrupts();
 
+#ifdef CONFIG_NETCONSOLE
+	/* Stop the ethernet stack if NetConsole could have left it up */
+	eth_halt();
+#endif
+
 #if defined(CONFIG_CMD_USB)
 	/*
 	 * turn off USB to prevent the host controller from writing to the
diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c
index 14243b8..069ad87 100644
--- a/drivers/net/netconsole.c
+++ b/drivers/net/netconsole.c
@@ -39,6 +39,11 @@  static IPaddr_t nc_ip; /* server ip */
 static short nc_port; /* source/target port */
 static const char *output_packet; /* used by first send udp */
 static int output_packet_len;
+/*
+ * Start with a default last protocol.
+ * We are only interested in NETCONS or not.
+ */
+enum proto_t net_loop_last_protocol = BOOTP;
 
 static void nc_wait_arp_handler(uchar *pkt, unsigned dest,
 				 IPaddr_t sip, unsigned src,
@@ -131,8 +136,13 @@  static void nc_send_packet(const char *buf, int len)
 	}
 
 	if (eth->state != ETH_STATE_ACTIVE) {
-		if (eth_init(gd->bd) < 0)
-			return;
+		if (eth_is_on_demand_init()) {
+			if (eth_init(gd->bd) < 0)
+				return;
+			eth_set_last_protocol(NETCONS);
+		} else
+			eth_init_state_only(gd->bd);
+
 		inited = 1;
 	}
 	pkt = (uchar *)NetTxPacket + NetEthHdrSize() + IP_UDP_HDR_SIZE;
@@ -141,8 +151,12 @@  static void nc_send_packet(const char *buf, int len)
 	ip = nc_ip;
 	NetSendUDPPacket(ether, ip, nc_port, nc_port, len);
 
-	if (inited)
-		eth_halt();
+	if (inited) {
+		if (eth_is_on_demand_init())
+			eth_halt();
+		else
+			eth_halt_state_only();
+	}
 }
 
 static int nc_start(void)
diff --git a/include/net.h b/include/net.h
index 6d2d6cd..e193b7b 100644
--- a/include/net.h
+++ b/include/net.h
@@ -102,7 +102,14 @@  extern int eth_register(struct eth_device* dev);/* Register network device */
 extern int eth_unregister(struct eth_device *dev);/* Remove network device */
 extern void eth_try_another(int first_restart);	/* Change the device */
 extern void eth_set_current(void);		/* set nterface to ethcur var */
-extern struct eth_device *eth_get_dev(void);	/* get the current device MAC */
+/* get the current device MAC */
+static inline __attribute__((always_inline))
+struct eth_device *eth_get_dev(void)
+{
+	extern struct eth_device *eth_current;
+
+	return eth_current;
+}
 extern struct eth_device *eth_get_dev_by_name(const char *devname);
 extern struct eth_device *eth_get_dev_by_index(int index); /* get dev @ index */
 extern int eth_get_dev_index(void);		/* get the device index */
@@ -151,6 +158,19 @@  extern int eth_rx(void);			/* Check for received packets */
 extern void eth_halt(void);			/* stop SCC */
 extern char *eth_get_name(void);		/* get name of current device */
 
+/* Set active state */
+static inline __attribute__((always_inline)) int eth_init_state_only(bd_t *bis)
+{
+	eth_get_dev()->state = ETH_STATE_ACTIVE;
+
+	return 0;
+}
+/* Set passive state */
+static inline __attribute__((always_inline)) void eth_halt_state_only(void)
+{
+	eth_get_dev()->state = ETH_STATE_PASSIVE;
+}
+
 /*
  * Set the hardware address for an ethernet interface based on 'eth%daddr'
  * environment variable (or just 'ethaddr' if eth_number is 0).
@@ -532,6 +552,26 @@  void NcStart(void);
 int nc_input_packet(uchar *pkt, unsigned dest, unsigned src, unsigned len);
 #endif
 
+static inline __attribute__((always_inline)) int eth_is_on_demand_init(void)
+{
+#ifdef CONFIG_NETCONSOLE
+	extern enum proto_t net_loop_last_protocol;
+
+	return net_loop_last_protocol != NETCONS;
+#else
+	return 1;
+#endif
+}
+
+static inline void eth_set_last_protocol(int protocol)
+{
+#ifdef CONFIG_NETCONSOLE
+	extern enum proto_t net_loop_last_protocol;
+
+	net_loop_last_protocol = protocol;
+#endif
+}
+
 /*
  * Check if autoload is enabled. If so, use either NFS or TFTP to download
  * the boot file.
diff --git a/net/eth.c b/net/eth.c
index 1a11ce1..66295b6 100644
--- a/net/eth.c
+++ b/net/eth.c
@@ -121,12 +121,8 @@  static struct {
 static unsigned int eth_rcv_current, eth_rcv_last;
 #endif
 
-static struct eth_device *eth_devices, *eth_current;
-
-struct eth_device *eth_get_dev(void)
-{
-	return eth_current;
-}
+static struct eth_device *eth_devices;
+struct eth_device *eth_current;
 
 struct eth_device *eth_get_dev_by_name(const char *devname)
 {
diff --git a/net/net.c b/net/net.c
index e8ff066..f002cda 100644
--- a/net/net.c
+++ b/net/net.c
@@ -315,12 +315,15 @@  int NetLoop(enum proto_t protocol)
 
 	bootstage_mark_name(BOOTSTAGE_ID_ETH_START, "eth_start");
 	net_init();
-	eth_halt();
-	eth_set_current();
-	if (eth_init(bd) < 0) {
+	if (eth_is_on_demand_init() || protocol != NETCONS) {
 		eth_halt();
-		return -1;
-	}
+		eth_set_current();
+		if (eth_init(bd) < 0) {
+			eth_halt();
+			return -1;
+		}
+	} else
+		eth_init_state_only(bd);
 
 restart:
 	net_set_state(NETLOOP_CONTINUE);
@@ -460,6 +463,9 @@  restart:
 
 			net_cleanup_loop();
 			eth_halt();
+			/* Invalidate the last protocol */
+			eth_set_last_protocol(BOOTP);
+
 			puts("\nAbort\n");
 			/* include a debug print as well incase the debug
 			   messages are directed to stderr */
@@ -517,13 +523,21 @@  restart:
 				sprintf(buf, "%lX", (unsigned long)load_addr);
 				setenv("fileaddr", buf);
 			}
-			eth_halt();
+			if (protocol != NETCONS)
+				eth_halt();
+			else
+				eth_halt_state_only();
+
+			eth_set_last_protocol(protocol);
+
 			ret = NetBootFileXferSize;
 			debug_cond(DEBUG_INT_STATE, "--- NetLoop Success!\n");
 			goto done;
 
 		case NETLOOP_FAIL:
 			net_cleanup_loop();
+			/* Invalidate the last protocol */
+			eth_set_last_protocol(BOOTP);
 			debug_cond(DEBUG_INT_STATE, "--- NetLoop Fail!\n");
 			goto done;