diff --git a/README b/README
index da74513a34ae590422ebb4fc35231ca4b2de9a53..ef8d437fbd46bf350eb6b259eeed3dd0a1810276 100644
--- a/README
+++ b/README
@@ -5454,10 +5454,10 @@ List of environment variables (most likely not complete):
 		  unset, then it will be made silent if the U-Boot console
 		  is silent.
 
-  tftpsrcport	- If this is set, the value is used for TFTP's
+  tftpsrcp	- If this is set, the value is used for TFTP's
 		  UDP source port.
 
-  tftpdstport	- If this is set, the value is used for TFTP's UDP
+  tftpdstp	- If this is set, the value is used for TFTP's UDP
 		  destination port instead of the Well Know Port 69.
 
   tftpblocksize - Block size to use for TFTP transfers; if not set,
@@ -5471,6 +5471,14 @@ List of environment variables (most likely not complete):
 		  faster in networks with high packet loss rates or
 		  with unreliable TFTP servers.
 
+  tftptimeoutcountmax	- maximum count of TFTP timeouts (no
+		  unit, minimum value = 0). Defines how many timeouts
+		  can happen during a single file transfer before that
+		  transfer is aborted. The default is 10, and 0 means
+		  'no timeouts allowed'. Increasing this value may help
+		  downloads succeed with high packet loss rates, or with
+		  unreliable TFTP servers or client hardware.
+
   vlan		- When set to a value < 4095 the traffic over
 		  Ethernet is encapsulated/received over 802.1q
 		  VLAN tagged frames.
diff --git a/common/miiphyutil.c b/common/miiphyutil.c
index c88c28adbf4ede84eb62422557cd14c87307acba..e499b588368fd9dcf9f04a6619976923e9d30a53 100644
--- a/common/miiphyutil.c
+++ b/common/miiphyutil.c
@@ -152,6 +152,11 @@ struct mii_dev *mdio_alloc(void)
 	return bus;
 }
 
+void mdio_free(struct mii_dev *bus)
+{
+	free(bus);
+}
+
 int mdio_register(struct mii_dev *bus)
 {
 	if (!bus || !bus->name || !bus->read || !bus->write)
@@ -173,6 +178,20 @@ int mdio_register(struct mii_dev *bus)
 	return 0;
 }
 
+int mdio_unregister(struct mii_dev *bus)
+{
+	if (!bus)
+		return 0;
+
+	/* delete it from the list */
+	list_del(&bus->link);
+
+	if (current_mii == bus)
+		current_mii = NULL;
+
+	return 0;
+}
+
 void mdio_list_devices(void)
 {
 	struct list_head *entry;
diff --git a/configs/bf527-ezkit_defconfig b/configs/bf527-ezkit_defconfig
index 2e75225c10c000c67a6bc2972e5f1e9fbfd0e72a..0cc81cc44c1551db343d1d0d00a09f1b045373d7 100644
--- a/configs/bf527-ezkit_defconfig
+++ b/configs/bf527-ezkit_defconfig
@@ -4,3 +4,4 @@ CONFIG_TARGET_BF527_EZKIT=y
 CONFIG_NET_RANDOM_ETHADDR=y
 CONFIG_SPI_FLASH=y
 CONFIG_CC_OPTIMIZE_LIBS_FOR_SPEED=y
+CONFIG_NET_TFTP_VARS=n
diff --git a/drivers/core/uclass.c b/drivers/core/uclass.c
index e800c28653f6170c62d9e1aeb23da1ced4ebea7a..1af09472a2cb76cc82b704bb626054ad5093c1da 100644
--- a/drivers/core/uclass.c
+++ b/drivers/core/uclass.c
@@ -523,22 +523,15 @@ int uclass_post_probe_device(struct udevice *dev)
 #if CONFIG_IS_ENABLED(DM_DEVICE_REMOVE)
 int uclass_pre_remove_device(struct udevice *dev)
 {
-	struct uclass_driver *uc_drv;
 	struct uclass *uc;
 	int ret;
 
 	uc = dev->uclass;
-	uc_drv = uc->uc_drv;
 	if (uc->uc_drv->pre_remove) {
 		ret = uc->uc_drv->pre_remove(dev);
 		if (ret)
 			return ret;
 	}
-	if (uc_drv->per_device_auto_alloc_size) {
-		free(dev->uclass_priv);
-		dev->uclass_priv = NULL;
-	}
-	dev->seq = -1;
 
 	return 0;
 }
diff --git a/drivers/net/designware.c b/drivers/net/designware.c
index 6433896eec03b4468b5d83bddc0414b3b7723916..a6c39c39ffaaee82f40f31dbf6c9ada59b3ce745 100644
--- a/drivers/net/designware.c
+++ b/drivers/net/designware.c
@@ -613,6 +613,17 @@ static int designware_eth_probe(struct udevice *dev)
 	return ret;
 }
 
+static int designware_eth_remove(struct udevice *dev)
+{
+	struct dw_eth_dev *priv = dev_get_priv(dev);
+
+	free(priv->phydev);
+	mdio_unregister(priv->bus);
+	mdio_free(priv->bus);
+
+	return 0;
+}
+
 static const struct eth_ops designware_eth_ops = {
 	.start			= designware_eth_start,
 	.send			= designware_eth_send,
@@ -653,6 +664,7 @@ U_BOOT_DRIVER(eth_designware) = {
 	.ofdata_to_platdata = designware_eth_ofdata_to_platdata,
 	.bind	= designware_eth_bind,
 	.probe	= designware_eth_probe,
+	.remove	= designware_eth_remove,
 	.ops	= &designware_eth_ops,
 	.priv_auto_alloc_size = sizeof(struct dw_eth_dev),
 	.platdata_auto_alloc_size = sizeof(struct eth_pdata),
diff --git a/drivers/net/pch_gbe.c b/drivers/net/pch_gbe.c
index 004fcf88c207066b3b6aa03e3d9010c38561e07f..dfc01000fc4ca380ea413fcf9373c397acd68760 100644
--- a/drivers/net/pch_gbe.c
+++ b/drivers/net/pch_gbe.c
@@ -452,6 +452,17 @@ int pch_gbe_probe(struct udevice *dev)
 	return pch_gbe_phy_init(dev);
 }
 
+int pch_gbe_remove(struct udevice *dev)
+{
+	struct pch_gbe_priv *priv = dev_get_priv(dev);
+
+	free(priv->phydev);
+	mdio_unregister(priv->bus);
+	mdio_free(priv->bus);
+
+	return 0;
+}
+
 static const struct eth_ops pch_gbe_ops = {
 	.start = pch_gbe_start,
 	.send = pch_gbe_send,
@@ -470,6 +481,7 @@ U_BOOT_DRIVER(eth_pch_gbe) = {
 	.id = UCLASS_ETH,
 	.of_match = pch_gbe_ids,
 	.probe = pch_gbe_probe,
+	.remove = pch_gbe_remove,
 	.ops = &pch_gbe_ops,
 	.priv_auto_alloc_size = sizeof(struct pch_gbe_priv),
 	.platdata_auto_alloc_size = sizeof(struct eth_pdata),
diff --git a/drivers/net/phy/micrel.c b/drivers/net/phy/micrel.c
index 49f444ac4c12c57993cb8139ce2fe946978e6d3e..5e49666bbb34e1a12d748db7a8c1107828311f78 100644
--- a/drivers/net/phy/micrel.c
+++ b/drivers/net/phy/micrel.c
@@ -22,6 +22,44 @@ static struct phy_driver KSZ804_driver = {
 	.shutdown = &genphy_shutdown,
 };
 
+static struct phy_driver KSZ8031_driver = {
+	.name = "Micrel KSZ8021/KSZ8031",
+	.uid = 0x221550,
+	.mask = 0xfffff0,
+	.features = PHY_BASIC_FEATURES,
+	.config = &genphy_config,
+	.startup = &genphy_startup,
+	.shutdown = &genphy_shutdown,
+};
+
+/**
+ * KSZ8051
+ */
+#define MII_KSZ8051_PHY_OMSO			0x16
+#define MII_KSZ8051_PHY_OMSO_NAND_TREE_ON	(1 << 5)
+
+static int ksz8051_config(struct phy_device *phydev)
+{
+	unsigned val;
+
+	/* Disable NAND-tree */
+	val = phy_read(phydev, MDIO_DEVAD_NONE, MII_KSZ8051_PHY_OMSO);
+	val &= ~MII_KSZ8051_PHY_OMSO_NAND_TREE_ON;
+	phy_write(phydev, MDIO_DEVAD_NONE, MII_KSZ8051_PHY_OMSO, val);
+
+	return genphy_config(phydev);
+}
+
+static struct phy_driver KSZ8051_driver = {
+	.name = "Micrel KSZ8051",
+	.uid = 0x221550,
+	.mask = 0xfffff0,
+	.features = PHY_BASIC_FEATURES,
+	.config = &ksz8051_config,
+	.startup = &genphy_startup,
+	.shutdown = &genphy_shutdown,
+};
+
 static struct phy_driver KSZ8081_driver = {
 	.name = "Micrel KSZ8081",
 	.uid = 0x221560,
@@ -282,6 +320,8 @@ static struct phy_driver ksz9031_driver = {
 int phy_micrel_init(void)
 {
 	phy_register(&KSZ804_driver);
+	phy_register(&KSZ8031_driver);
+	phy_register(&KSZ8051_driver);
 	phy_register(&KSZ8081_driver);
 #ifdef CONFIG_PHY_MICREL_KSZ9021
 	phy_register(&ksz9021_driver);
diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c
index a6023f1033ecc879eff43b7719b1ca66cb6f2157..d7364ffc34f2f1774b38153600698451de549d68 100644
--- a/drivers/net/phy/phy.c
+++ b/drivers/net/phy/phy.c
@@ -671,8 +671,16 @@ static struct phy_device *get_phy_device_by_mask(struct mii_dev *bus,
 		if (phydev)
 			return phydev;
 	}
-	printf("Phy %d not found\n", ffs(phy_mask) - 1);
-	return phy_device_create(bus, ffs(phy_mask) - 1, 0xffffffff, interface);
+
+	debug("\n%s PHY: ", bus->name);
+	while (phy_mask) {
+		int addr = ffs(phy_mask) - 1;
+		debug("%d ", addr);
+		phy_mask &= ~(1 << addr);
+	}
+	debug("not found\n");
+
+	return NULL;
 }
 
 /**
@@ -781,7 +789,7 @@ void phy_connect_dev(struct phy_device *phydev, struct eth_device *dev)
 {
 	/* Soft Reset the PHY */
 	phy_reset(phydev);
-	if (phydev->dev) {
+	if (phydev->dev && phydev->dev != dev) {
 		printf("%s:%d is connected to %s.  Reconnecting to %s\n",
 				phydev->bus->name, phydev->addr,
 				phydev->dev->name, dev->name);
diff --git a/drivers/net/rtl8169.c b/drivers/net/rtl8169.c
index ebd46b27e5fdeda6e2e543b2e652802d745cd1ec..19422c4a2ace79892d942be0cab3345b76aa4f69 100644
--- a/drivers/net/rtl8169.c
+++ b/drivers/net/rtl8169.c
@@ -581,7 +581,8 @@ int rtl8169_eth_recv(struct udevice *dev, int flags, uchar **packetp)
 #else
 static int rtl_recv(struct eth_device *dev)
 {
-	return rtl_recv_common((pci_dev_t)dev->priv, dev->iobase, NULL);
+	return rtl_recv_common((pci_dev_t)(unsigned long)dev->priv,
+			       dev->iobase, NULL);
 }
 #endif /* nCONFIG_DM_ETH */
 
@@ -666,8 +667,8 @@ int rtl8169_eth_send(struct udevice *dev, void *packet, int length)
 #else
 static int rtl_send(struct eth_device *dev, void *packet, int length)
 {
-	return rtl_send_common((pci_dev_t)dev->priv, dev->iobase, packet,
-			       length);
+	return rtl_send_common((pci_dev_t)(unsigned long)dev->priv,
+			       dev->iobase, packet, length);
 }
 #endif
 
@@ -846,7 +847,8 @@ RESET - Finish setting up the ethernet interface
 ***************************************************************************/
 static int rtl_reset(struct eth_device *dev, bd_t *bis)
 {
-	rtl8169_common_start((pci_dev_t)dev->priv, dev->enetaddr);
+	rtl8169_common_start((pci_dev_t)(unsigned long)dev->priv,
+			     dev->enetaddr);
 
 	return 0;
 }
diff --git a/drivers/usb/eth/smsc95xx.c b/drivers/usb/eth/smsc95xx.c
index d4b5ff465a763c7561fa3ea6bd42ea67678cb131..202e48285f9c590b422d85ae7850b1c50528fa1f 100644
--- a/drivers/usb/eth/smsc95xx.c
+++ b/drivers/usb/eth/smsc95xx.c
@@ -120,8 +120,9 @@
 /* Some extra defines */
 #define HS_USB_PKT_SIZE			512
 #define FS_USB_PKT_SIZE			64
-#define DEFAULT_HS_BURST_CAP_SIZE	(16 * 1024 + 5 * HS_USB_PKT_SIZE)
-#define DEFAULT_FS_BURST_CAP_SIZE	(6 * 1024 + 33 * FS_USB_PKT_SIZE)
+/* 5/33 is lower limit for BURST_CAP to work */
+#define DEFAULT_HS_BURST_CAP_SIZE	(5 * HS_USB_PKT_SIZE)
+#define DEFAULT_FS_BURST_CAP_SIZE	(33 * FS_USB_PKT_SIZE)
 #define DEFAULT_BULK_IN_DELAY		0x00002000
 #define MAX_SINGLE_PACKET_SIZE		2048
 #define EEPROM_MAC_OFFSET		0x01
@@ -135,7 +136,7 @@
 #define USB_BULK_SEND_TIMEOUT 5000
 #define USB_BULK_RECV_TIMEOUT 5000
 
-#define RX_URB_SIZE 2048
+#define RX_URB_SIZE DEFAULT_HS_BURST_CAP_SIZE
 #define PHY_CONNECT_TIMEOUT 5000
 
 #define TURBO_MODE
@@ -529,22 +530,6 @@ static int smsc95xx_init_common(struct usb_device *udev, struct ueth_data *dev,
 	if (ret < 0)
 		return ret;
 
-	ret = smsc95xx_read_reg(udev, HW_CFG, &read_buf);
-	if (ret < 0)
-		return ret;
-	debug("Read Value from HW_CFG : 0x%08x\n", read_buf);
-
-	read_buf |= HW_CFG_BIR_;
-	ret = smsc95xx_write_reg(udev, HW_CFG, read_buf);
-	if (ret < 0)
-		return ret;
-
-	ret = smsc95xx_read_reg(udev, HW_CFG, &read_buf);
-	if (ret < 0)
-		return ret;
-	debug("Read Value from HW_CFG after writing "
-		"HW_CFG_BIR_: 0x%08x\n", read_buf);
-
 #ifdef TURBO_MODE
 	if (dev->pusb_dev->speed == USB_SPEED_HIGH) {
 		burst_cap = DEFAULT_HS_BURST_CAP_SIZE / HS_USB_PKT_SIZE;
diff --git a/include/miiphy.h b/include/miiphy.h
index 088797e4c6ca9d4c39a82cd6067de61c4df911a5..af12274c81df2d7febbe257ee940f46be5aaed08 100644
--- a/include/miiphy.h
+++ b/include/miiphy.h
@@ -59,7 +59,9 @@ struct phy_device *mdio_phydev_for_ethname(const char *devname);
 void miiphy_listdev(void);
 
 struct mii_dev *mdio_alloc(void);
+void mdio_free(struct mii_dev *bus);
 int mdio_register(struct mii_dev *bus);
+int mdio_unregister(struct mii_dev *bus);
 void mdio_list_devices(void);
 
 #ifdef CONFIG_BITBANGMII
diff --git a/include/net.h b/include/net.h
index 3a787cc4e981da86040f243bee07bef5d6ec9ff0..ebed29ad577e898aecfefcfad784510f7ff6ea28 100644
--- a/include/net.h
+++ b/include/net.h
@@ -233,8 +233,8 @@ void eth_set_current(void);		/* set nterface to ethcur var */
 
 int eth_get_dev_index(void);		/* get the device index */
 void eth_parse_enetaddr(const char *addr, uchar *enetaddr);
-int eth_getenv_enetaddr(char *name, uchar *enetaddr);
-int eth_setenv_enetaddr(char *name, const uchar *enetaddr);
+int eth_getenv_enetaddr(const char *name, uchar *enetaddr);
+int eth_setenv_enetaddr(const char *name, const uchar *enetaddr);
 
 /*
  * Get the hardware address for an ethernet interface .
@@ -516,7 +516,7 @@ enum proto_t {
 	TFTPSRV, TFTPPUT, LINKLOCAL
 };
 
-extern char	net_boot_file_name[128];/* Boot File name */
+extern char	net_boot_file_name[1024];/* Boot File name */
 /* The actual transferred size of the bootfile (in bytes) */
 extern u32	net_boot_file_size;
 /* Boot file size in blocks as reported by the DHCP server */
diff --git a/net/Kconfig b/net/Kconfig
index 77a2f7e07e012b75bd72f1b48cf1e37a0117f320..a44a783cae239e54cd572149024f8c84743d726c 100644
--- a/net/Kconfig
+++ b/net/Kconfig
@@ -22,4 +22,14 @@ config NETCONSOLE
 	  Support the 'nc' input/output device for networked console.
 	  See README.NetConsole for details.
 
+config NET_TFTP_VARS
+	bool "Control TFTP timeout and count through environment"
+	default y
+	help
+	  If set, allows controlling the TFTP timeout through the
+	  environment variable tftptimeout, and the TFTP maximum
+	  timeout count through the variable tftptimeoutcountmax.
+	  If unset, timeout and maximum are hard-defined as 1 second
+	  and 10 timouts per TFTP transfer.
+
 endif   # if NET
diff --git a/net/arp.c b/net/arp.c
index b8655700a828f78439c9499c5fbab5bc90a0c4a6..824d2e9393550ea250f357b2762cf2f465e5fe66 100644
--- a/net/arp.c
+++ b/net/arp.c
@@ -96,12 +96,12 @@ void arp_request(void)
 	arp_raw_request(net_ip, net_null_ethaddr, net_arp_wait_reply_ip);
 }
 
-void arp_timeout_check(void)
+int arp_timeout_check(void)
 {
 	ulong t;
 
 	if (!net_arp_wait_packet_ip.s_addr)
-		return;
+		return 0;
 
 	t = get_timer(0);
 
@@ -112,12 +112,13 @@ void arp_timeout_check(void)
 		if (arp_wait_try >= ARP_TIMEOUT_COUNT) {
 			puts("\nARP Retry count exceeded; starting again\n");
 			arp_wait_try = 0;
-			net_start_again();
+			net_set_state(NETLOOP_FAIL);
 		} else {
 			arp_wait_timer_start = t;
 			arp_request();
 		}
 	}
+	return 1;
 }
 
 void arp_receive(struct ethernet_hdr *et, struct ip_udp_hdr *ip, int len)
diff --git a/net/arp.h b/net/arp.h
index 43c6296f7e83f930aac2ca1289646c256ca8175a..a288d618b6849a329a919d0d768f0ab142a46ace 100644
--- a/net/arp.h
+++ b/net/arp.h
@@ -25,7 +25,7 @@ void arp_init(void);
 void arp_request(void);
 void arp_raw_request(struct in_addr source_ip, const uchar *targetEther,
 	struct in_addr target_ip);
-void arp_timeout_check(void);
+int arp_timeout_check(void);
 void arp_receive(struct ethernet_hdr *et, struct ip_udp_hdr *ip, int len);
 
 #endif /* __ARP_H__ */
diff --git a/net/bootp.c b/net/bootp.c
index b2f8ad4ded932ddfdb2aefc86f803e2d4f0d894f..8aeddb08ea83f0bf1094d9cb72938df4357801dc 100644
--- a/net/bootp.c
+++ b/net/bootp.c
@@ -64,6 +64,9 @@ char net_root_path[64] = {0,}; /* Our bootpath */
 static dhcp_state_t dhcp_state = INIT;
 static u32 dhcp_leasetime;
 static struct in_addr dhcp_server_ip;
+static u8 dhcp_option_overload;
+#define OVERLOAD_FILE 1
+#define OVERLOAD_SNAME 2
 static void dhcp_handler(uchar *pkt, unsigned dest, struct in_addr sip,
 			unsigned src, unsigned len);
 
@@ -109,7 +112,8 @@ static bool bootp_match_id(ulong id)
 	return false;
 }
 
-static int check_packet(uchar *pkt, unsigned dest, unsigned src, unsigned len)
+static int check_reply_packet(uchar *pkt, unsigned dest, unsigned src,
+			      unsigned len)
 {
 	struct bootp_hdr *bp = (struct bootp_hdr *)pkt;
 	int retval = 0;
@@ -118,11 +122,7 @@ static int check_packet(uchar *pkt, unsigned dest, unsigned src, unsigned len)
 		retval = -1;
 	else if (len < sizeof(struct bootp_hdr) - OPT_FIELD_SIZE)
 		retval = -2;
-	else if (bp->bp_op != OP_BOOTREQUEST &&
-			bp->bp_op != OP_BOOTREPLY &&
-			bp->bp_op != DHCP_OFFER &&
-			bp->bp_op != DHCP_ACK &&
-			bp->bp_op != DHCP_NAK)
+	else if (bp->bp_op != OP_BOOTREPLY)
 		retval = -3;
 	else if (bp->bp_htype != HWT_ETHER)
 		retval = -4;
@@ -149,9 +149,14 @@ static void store_net_params(struct bootp_hdr *bp)
 		net_copy_ip(&net_server_ip, &bp->bp_siaddr);
 	memcpy(net_server_ethaddr,
 	       ((struct ethernet_hdr *)net_rx_packet)->et_src, 6);
-	if (strlen(bp->bp_file) > 0)
+	if (
+#if defined(CONFIG_CMD_DHCP)
+	    !(dhcp_option_overload & OVERLOAD_FILE) &&
+#endif
+	    (strlen(bp->bp_file) > 0)) {
 		copy_filename(net_boot_file_name, bp->bp_file,
 			      sizeof(net_boot_file_name));
+	}
 
 	debug("net_boot_file_name: %s\n", net_boot_file_name);
 
@@ -343,13 +348,13 @@ static void bootp_handler(uchar *pkt, unsigned dest, struct in_addr sip,
 	bp = (struct bootp_hdr *)pkt;
 
 	/* Filter out pkts we don't want */
-	if (check_packet(pkt, dest, src, len))
+	if (check_reply_packet(pkt, dest, src, len))
 		return;
 
 	/*
 	 *	Got a good BOOTP reply.	 Copy the data into our variables.
 	 */
-#ifdef CONFIG_STATUS_LED
+#if defined(CONFIG_STATUS_LED) && defined(STATUS_LED_BOOT)
 	status_led_set(STATUS_LED_BOOT, STATUS_LED_OFF);
 #endif
 
@@ -498,7 +503,9 @@ static int dhcp_extended(u8 *e, int message_type, struct in_addr server_ip,
 	}
 #endif
 
-#ifdef CONFIG_BOOTP_VCI_STRING
+#if defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_NET_VCI_STRING)
+	put_vci(e, CONFIG_SPL_NET_VCI_STRING);
+#elif defined(CONFIG_BOOTP_VCI_STRING)
 	put_vci(e, CONFIG_BOOTP_VCI_STRING);
 #endif
 
@@ -712,7 +719,11 @@ void bootp_request(void)
 	bp->bp_htype = HWT_ETHER;
 	bp->bp_hlen = HWL_ETHER;
 	bp->bp_hops = 0;
-	bp->bp_secs = htons(get_timer(0) / 1000);
+	/*
+	 * according to RFC1542, should be 0 on first request, secs since
+	 * first request otherwise
+	 */
+	bp->bp_secs = htons(get_timer(bootp_start) / 1000);
 	zero_ip.s_addr = 0;
 	net_write_ip(&bp->bp_ciaddr, zero_ip);
 	net_write_ip(&bp->bp_yiaddr, zero_ip);
@@ -762,9 +773,8 @@ void bootp_request(void)
 }
 
 #if defined(CONFIG_CMD_DHCP)
-static void dhcp_process_options(uchar *popt, struct bootp_hdr *bp)
+static void dhcp_process_options(uchar *popt, uchar *end)
 {
-	uchar *end = popt + BOOTP_HDR_SIZE;
 	int oplen, size;
 #if defined(CONFIG_CMD_SNTP) && defined(CONFIG_BOOTP_TIMEOFFSET)
 	int *to_ptr;
@@ -773,6 +783,9 @@ static void dhcp_process_options(uchar *popt, struct bootp_hdr *bp)
 	while (popt < end && *popt != 0xff) {
 		oplen = *(popt + 1);
 		switch (*popt) {
+		case 0:
+			oplen = -1; /* Pad omits len byte */
+			break;
 		case 1:
 			net_copy_ip(&net_netmask, (popt + 2));
 			break;
@@ -817,6 +830,9 @@ static void dhcp_process_options(uchar *popt, struct bootp_hdr *bp)
 		case 51:
 			net_copy_u32(&dhcp_leasetime, (u32 *)(popt + 2));
 			break;
+		case 52:
+			dhcp_option_overload = popt[2];
+			break;
 		case 53:	/* Ignore Message Type Option */
 			break;
 		case 54:
@@ -828,31 +844,11 @@ static void dhcp_process_options(uchar *popt, struct bootp_hdr *bp)
 			break;
 		case 66:	/* Ignore TFTP server name */
 			break;
-		case 67:	/* vendor opt bootfile */
-			/*
-			 * I can't use dhcp_vendorex_proc here because I need
-			 * to write into the bootp packet - even then I had to
-			 * pass the bootp packet pointer into here as the
-			 * second arg
-			 */
-			size = truncate_sz("Opt Boot File",
-					    sizeof(bp->bp_file),
-					    oplen);
-			if (bp->bp_file[0] == '\0' && size > 0) {
-				/*
-				 * only use vendor boot file if we didn't
-				 * receive a boot file in the main non-vendor
-				 * part of the packet - god only knows why
-				 * some vendors chose not to use this perfectly
-				 * good spot to store the boot file (join on
-				 * Tru64 Unix) it seems mind bogglingly crazy
-				 * to me
-				 */
-				printf("*** WARNING: using vendor "
-				       "optional boot file\n");
-				memcpy(bp->bp_file, popt + 2, size);
-				bp->bp_file[size] = '\0';
-			}
+		case 67:	/* Bootfile option */
+			size = truncate_sz("Bootfile",
+					   sizeof(net_boot_file_name), oplen);
+			memcpy(&net_boot_file_name, popt + 2, size);
+			net_boot_file_name[size] = 0;
 			break;
 		default:
 #if defined(CONFIG_BOOTP_VENDOREX)
@@ -867,6 +863,35 @@ static void dhcp_process_options(uchar *popt, struct bootp_hdr *bp)
 	}
 }
 
+static void dhcp_packet_process_options(struct bootp_hdr *bp)
+{
+	uchar *popt = (uchar *)&bp->bp_vend[4];
+	uchar *end = popt + BOOTP_HDR_SIZE;
+
+	if (net_read_u32((u32 *)&bp->bp_vend[0]) != htonl(BOOTP_VENDOR_MAGIC))
+		return;
+
+	dhcp_option_overload = 0;
+
+	/*
+	 * The 'options' field MUST be interpreted first, 'file' next,
+	 * 'sname' last.
+	 */
+	dhcp_process_options(popt, end);
+
+	if (dhcp_option_overload & OVERLOAD_FILE) {
+		popt = (uchar *)bp->bp_file;
+		end = popt + sizeof(bp->bp_file);
+		dhcp_process_options(popt, end);
+	}
+
+	if (dhcp_option_overload & OVERLOAD_SNAME) {
+		popt = (uchar *)bp->bp_sname;
+		end = popt + sizeof(bp->bp_sname);
+		dhcp_process_options(popt, end);
+	}
+}
+
 static int dhcp_message_type(unsigned char *popt)
 {
 	if (net_read_u32((u32 *)popt) != htonl(BOOTP_VENDOR_MAGIC))
@@ -876,7 +901,13 @@ static int dhcp_message_type(unsigned char *popt)
 	while (*popt != 0xff) {
 		if (*popt == 53)	/* DHCP Message Type */
 			return *(popt + 2);
-		popt += *(popt + 1) + 2;	/* Scan through all options */
+		if (*popt == 0)	{
+			/* Pad */
+			popt += 1;
+		} else {
+			/* Scan through all options */
+			popt += *(popt + 1) + 2;
+		}
 	}
 	return -1;
 }
@@ -906,7 +937,7 @@ static void dhcp_send_request_packet(struct bootp_hdr *bp_offer)
 	bp->bp_htype = HWT_ETHER;
 	bp->bp_hlen = HWL_ETHER;
 	bp->bp_hops = 0;
-	bp->bp_secs = htons(get_timer(0) / 1000);
+	bp->bp_secs = htons(get_timer(bootp_start) / 1000);
 	/* Do not set the client IP, your IP, or server IP yet, since it
 	 * hasn't been ACK'ed by the server yet */
 
@@ -958,7 +989,7 @@ static void dhcp_handler(uchar *pkt, unsigned dest, struct in_addr sip,
 	      src, dest, len, dhcp_state);
 
 	/* Filter out pkts we don't want */
-	if (check_packet(pkt, dest, src, len))
+	if (check_reply_packet(pkt, dest, src, len))
 		return;
 
 	debug("DHCPHandler: got DHCP packet: (src=%d, dst=%d, len=%d) state: "
@@ -978,14 +1009,11 @@ static void dhcp_handler(uchar *pkt, unsigned dest, struct in_addr sip,
 			    CONFIG_SYS_BOOTFILE_PREFIX,
 			    strlen(CONFIG_SYS_BOOTFILE_PREFIX)) == 0) {
 #endif	/* CONFIG_SYS_BOOTFILE_PREFIX */
+			dhcp_packet_process_options(bp);
 
 			debug("TRANSITIONING TO REQUESTING STATE\n");
 			dhcp_state = REQUESTING;
 
-			if (net_read_u32((u32 *)&bp->bp_vend[0]) ==
-						htonl(BOOTP_VENDOR_MAGIC))
-				dhcp_process_options((u8 *)&bp->bp_vend[4], bp);
-
 			net_set_timeout_handler(5000, bootp_timeout_handler);
 			dhcp_send_request_packet(bp);
 #ifdef CONFIG_SYS_BOOTFILE_PREFIX
@@ -998,14 +1026,13 @@ static void dhcp_handler(uchar *pkt, unsigned dest, struct in_addr sip,
 		debug("DHCP State: REQUESTING\n");
 
 		if (dhcp_message_type((u8 *)bp->bp_vend) == DHCP_ACK) {
-			if (net_read_u32((u32 *)&bp->bp_vend[0]) ==
-						htonl(BOOTP_VENDOR_MAGIC))
-				dhcp_process_options((u8 *)&bp->bp_vend[4], bp);
+			dhcp_packet_process_options(bp);
 			/* Store net params from reply */
 			store_net_params(bp);
 			dhcp_state = BOUND;
 			printf("DHCP client bound to address %pI4 (%lu ms)\n",
 			       &net_ip, get_timer(bootp_start));
+			net_set_timeout_handler(0, (thand_f *)0);
 			bootstage_mark_name(BOOTSTAGE_ID_BOOTP_STOP,
 					    "bootp_stop");
 
diff --git a/net/eth.c b/net/eth.c
index 2e24b55726be8a63846c835b5d3688c7d74bf670..c542f4aa3b3b1e4f2e6fbb5db4c0ea579aefe45e 100644
--- a/net/eth.c
+++ b/net/eth.c
@@ -31,13 +31,13 @@ void eth_parse_enetaddr(const char *addr, uchar *enetaddr)
 	}
 }
 
-int eth_getenv_enetaddr(char *name, uchar *enetaddr)
+int eth_getenv_enetaddr(const char *name, uchar *enetaddr)
 {
 	eth_parse_enetaddr(getenv(name), enetaddr);
 	return is_valid_ethaddr(enetaddr);
 }
 
-int eth_setenv_enetaddr(char *name, const uchar *enetaddr)
+int eth_setenv_enetaddr(const char *name, const uchar *enetaddr)
 {
 	char buf[20];
 
@@ -179,8 +179,12 @@ struct udevice *eth_get_dev(void)
  */
 static void eth_set_dev(struct udevice *dev)
 {
-	if (dev && !device_active(dev))
+	if (dev && !device_active(dev)) {
 		eth_errno = device_probe(dev);
+		if (eth_errno)
+			dev = NULL;
+	}
+
 	eth_get_uclass_priv()->current = dev;
 }
 
@@ -213,10 +217,9 @@ struct udevice *eth_get_dev_by_name(const char *devname)
 		 * match an alias or it will match a literal name and we'll pick
 		 * up the error when we try to probe again in eth_set_dev().
 		 */
-		device_probe(it);
-		/*
-		 * Check for the name or the sequence number to match
-		 */
+		if (device_probe(it))
+			continue;
+		/* Check for the name or the sequence number to match */
 		if (strcmp(it->name, devname) == 0 ||
 		    (endp > startp && it->seq == seq))
 			return it;
@@ -346,23 +349,27 @@ int eth_init(void)
 
 	old_current = current;
 	do {
-		debug("Trying %s\n", current->name);
-
-		if (device_active(current)) {
-			ret = eth_get_ops(current)->start(current);
-			if (ret >= 0) {
-				struct eth_device_priv *priv =
-					current->uclass_priv;
-
-				priv->state = ETH_STATE_ACTIVE;
-				return 0;
+		if (current) {
+			debug("Trying %s\n", current->name);
+
+			if (device_active(current)) {
+				ret = eth_get_ops(current)->start(current);
+				if (ret >= 0) {
+					struct eth_device_priv *priv =
+						current->uclass_priv;
+
+					priv->state = ETH_STATE_ACTIVE;
+					return 0;
+				}
+			} else {
+				ret = eth_errno;
 			}
+
+			debug("FAIL\n");
 		} else {
-			ret = eth_errno;
+			debug("PROBE FAIL\n");
 		}
 
-		debug("FAIL\n");
-
 		/*
 		 * If ethrotate is enabled, this will change "current",
 		 * otherwise we will drop out of this while loop immediately
@@ -575,8 +582,13 @@ static int eth_post_probe(struct udevice *dev)
 
 static int eth_pre_remove(struct udevice *dev)
 {
+	struct eth_pdata *pdata = dev->platdata;
+
 	eth_get_ops(dev)->stop(dev);
 
+	/* clear the MAC address */
+	memset(pdata->enetaddr, 0, 6);
+
 	return 0;
 }
 
@@ -691,6 +703,7 @@ static int on_ethaddr(const char *name, const char *value, enum env_op op,
 				memset(dev->enetaddr, 0, 6);
 			}
 		}
+		dev = dev->next;
 	} while (dev != eth_devices);
 
 	return 0;
diff --git a/net/net.c b/net/net.c
index a115ce28927216532179bdcc842d22025e0ee092..2926bceacbad812bbda0956dc905318917f9237e 100644
--- a/net/net.c
+++ b/net/net.c
@@ -164,7 +164,7 @@ ushort		net_our_vlan = 0xFFFF;
 ushort		net_native_vlan = 0xFFFF;
 
 /* Boot File name */
-char net_boot_file_name[128];
+char net_boot_file_name[1024];
 /* The actual transferred size of the bootfile (in bytes) */
 u32 net_boot_file_size;
 /* Boot file size in blocks as reported by the DHCP server */
@@ -569,7 +569,9 @@ restart:
 			goto done;
 		}
 
-		arp_timeout_check();
+		if (arp_timeout_check() > 0) {
+		    time_start = get_timer(0);
+		}
 
 		/*
 		 *	Check for a timeout, and run the timeout handler
diff --git a/net/tftp.c b/net/tftp.c
index 1a5113179ac54862b399593ff2419a6745d8ccf9..f2889fe4c9bda3ab1338b9b0f68aa822947f7c4a 100644
--- a/net/tftp.c
+++ b/net/tftp.c
@@ -602,7 +602,7 @@ static void tftp_handler(uchar *pkt, unsigned dest, struct in_addr sip,
 		}
 
 		tftp_prev_block = tftp_cur_block;
-		timeout_count_max = TIMEOUT_COUNT;
+		timeout_count_max = tftp_timeout_count_max;
 		net_set_timeout_handler(timeout_ms, tftp_timeout_handler);
 
 		store_block(tftp_cur_block - 1, pkt + 2, len);
@@ -697,12 +697,14 @@ static void tftp_timeout_handler(void)
 
 void tftp_start(enum proto_t protocol)
 {
+#if CONFIG_NET_TFTP_VARS
 	char *ep;             /* Environment pointer */
 
 	/*
 	 * Allow the user to choose TFTP blocksize and timeout.
 	 * TFTP protocol has a minimal timeout of 1 second.
 	 */
+
 	ep = getenv("tftpblocksize");
 	if (ep != NULL)
 		tftp_block_size_option = simple_strtol(ep, NULL, 10);
@@ -717,6 +719,17 @@ void tftp_start(enum proto_t protocol)
 		timeout_ms = 1000;
 	}
 
+	ep = getenv("tftptimeoutcountmax");
+	if (ep != NULL)
+		tftp_timeout_count_max = simple_strtol(ep, NULL, 10);
+
+	if (tftp_timeout_count_max < 0) {
+		printf("TFTP timeout count max (%d ms) negative, set to 0\n",
+		       tftp_timeout_count_max);
+		tftp_timeout_count_max = 0;
+	}
+#endif
+
 	debug("TFTP blocksize = %i, timeout = %ld ms\n",
 	      tftp_block_size_option, timeout_ms);
 
@@ -842,7 +855,7 @@ void tftp_start_server(void)
 
 	puts("Loading: *\b");
 
-	timeout_count_max = TIMEOUT_COUNT;
+	timeout_count_max = tftp_timeout_count_max;
 	timeout_count = 0;
 	timeout_ms = TIMEOUT;
 	net_set_timeout_handler(timeout_ms, tftp_timeout_handler);
diff --git a/test/dm/eth.c b/test/dm/eth.c
index fcfb3e1ece840a5ed896c10cbeddbce6d69139a9..6288ae24abb4467580bb5e1cbd1515c59a6f69b5 100644
--- a/test/dm/eth.c
+++ b/test/dm/eth.c
@@ -13,11 +13,15 @@
 #include <malloc.h>
 #include <net.h>
 #include <dm/test.h>
+#include <dm/device-internal.h>
+#include <dm/uclass-internal.h>
 #include <asm/eth.h>
 #include <test/ut.h>
 
 DECLARE_GLOBAL_DATA_PTR;
 
+#define DM_TEST_ETH_NUM		4
+
 static int dm_test_eth(struct unit_test_state *uts)
 {
 	net_ping_ip = string_to_ip("1.1.2.2");
@@ -82,6 +86,66 @@ static int dm_test_eth_prime(struct unit_test_state *uts)
 }
 DM_TEST(dm_test_eth_prime, DM_TESTF_SCAN_FDT);
 
+/**
+ * This test case is trying to test the following scenario:
+ *	- All ethernet devices are not probed
+ *	- "ethaddr" for all ethernet devices are not set
+ *	- "ethact" is set to a valid ethernet device name
+ *
+ * With Sandbox default test configuration, all ethernet devices are
+ * probed after power-up, so we have to manually create such scenario:
+ *	- Remove all ethernet devices
+ *	- Remove all "ethaddr" environment variables
+ *	- Set "ethact" to the first ethernet device
+ *
+ * Do a ping test to see if anything goes wrong.
+ */
+static int dm_test_eth_act(struct unit_test_state *uts)
+{
+	struct udevice *dev[DM_TEST_ETH_NUM];
+	const char *ethname[DM_TEST_ETH_NUM] = {"eth@10002000", "eth@10003000",
+						"sbe5", "eth@10004000"};
+	const char *addrname[DM_TEST_ETH_NUM] = {"ethaddr", "eth5addr",
+						 "eth3addr", "eth1addr"};
+	char ethaddr[DM_TEST_ETH_NUM][18];
+	int i;
+
+	net_ping_ip = string_to_ip("1.1.2.2");
+
+	/* Prepare the test scenario */
+	for (i = 0; i < DM_TEST_ETH_NUM; i++) {
+		ut_assertok(uclass_find_device_by_name(UCLASS_ETH,
+						       ethname[i], &dev[i]));
+		ut_assertok(device_remove(dev[i]));
+
+		/* Invalidate MAC address */
+		strcpy(ethaddr[i], getenv(addrname[i]));
+		/* Must disable access protection for ethaddr before clearing */
+		setenv(".flags", addrname[i]);
+		setenv(addrname[i], NULL);
+	}
+
+	/* Set ethact to "eth@10002000" */
+	setenv("ethact", ethname[0]);
+
+	/* Segment fault might happen if something is wrong */
+	ut_asserteq(-ENODEV, net_loop(PING));
+
+	for (i = 0; i < DM_TEST_ETH_NUM; i++) {
+		/* Restore the env */
+		setenv(".flags", addrname[i]);
+		setenv(addrname[i], ethaddr[i]);
+
+		/* Probe the device again */
+		ut_assertok(device_probe(dev[i]));
+	}
+	setenv(".flags", NULL);
+	setenv("ethact", NULL);
+
+	return 0;
+}
+DM_TEST(dm_test_eth_act, DM_TESTF_SCAN_FDT);
+
 /* The asserts include a return on fail; cleanup in the caller */
 static int _dm_test_eth_rotate1(struct unit_test_state *uts)
 {