]> git.sur5r.net Git - u-boot/commitdiff
Merge branch 'master' of git://git.denx.de/u-boot-net
authorTom Rini <trini@konsulko.com>
Thu, 29 Oct 2015 20:30:33 +0000 (16:30 -0400)
committerTom Rini <trini@konsulko.com>
Thu, 29 Oct 2015 20:30:33 +0000 (16:30 -0400)
20 files changed:
README
common/miiphyutil.c
configs/bf527-ezkit_defconfig
drivers/core/uclass.c
drivers/net/designware.c
drivers/net/pch_gbe.c
drivers/net/phy/micrel.c
drivers/net/phy/phy.c
drivers/net/rtl8169.c
drivers/usb/eth/smsc95xx.c
include/miiphy.h
include/net.h
net/Kconfig
net/arp.c
net/arp.h
net/bootp.c
net/eth.c
net/net.c
net/tftp.c
test/dm/eth.c

diff --git a/README b/README
index da74513a34ae590422ebb4fc35231ca4b2de9a53..ef8d437fbd46bf350eb6b259eeed3dd0a1810276 100644 (file)
--- 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.
index c88c28adbf4ede84eb62422557cd14c87307acba..e499b588368fd9dcf9f04a6619976923e9d30a53 100644 (file)
@@ -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;
index 2e75225c10c000c67a6bc2972e5f1e9fbfd0e72a..0cc81cc44c1551db343d1d0d00a09f1b045373d7 100644 (file)
@@ -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
index e800c28653f6170c62d9e1aeb23da1ced4ebea7a..1af09472a2cb76cc82b704bb626054ad5093c1da 100644 (file)
@@ -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;
 }
index 6433896eec03b4468b5d83bddc0414b3b7723916..a6c39c39ffaaee82f40f31dbf6c9ada59b3ce745 100644 (file)
@@ -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),
index 004fcf88c207066b3b6aa03e3d9010c38561e07f..dfc01000fc4ca380ea413fcf9373c397acd68760 100644 (file)
@@ -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),
index 49f444ac4c12c57993cb8139ce2fe946978e6d3e..5e49666bbb34e1a12d748db7a8c1107828311f78 100644 (file)
@@ -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);
index a6023f1033ecc879eff43b7719b1ca66cb6f2157..d7364ffc34f2f1774b38153600698451de549d68 100644 (file)
@@ -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);
index ebd46b27e5fdeda6e2e543b2e652802d745cd1ec..19422c4a2ace79892d942be0cab3345b76aa4f69 100644 (file)
@@ -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;
 }
index d4b5ff465a763c7561fa3ea6bd42ea67678cb131..202e48285f9c590b422d85ae7850b1c50528fa1f 100644 (file)
 /* 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
 #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;
index 088797e4c6ca9d4c39a82cd6067de61c4df911a5..af12274c81df2d7febbe257ee940f46be5aaed08 100644 (file)
@@ -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
index 3a787cc4e981da86040f243bee07bef5d6ec9ff0..ebed29ad577e898aecfefcfad784510f7ff6ea28 100644 (file)
@@ -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 */
index 77a2f7e07e012b75bd72f1b48cf1e37a0117f320..a44a783cae239e54cd572149024f8c84743d726c 100644 (file)
@@ -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
index b8655700a828f78439c9499c5fbab5bc90a0c4a6..824d2e9393550ea250f357b2762cf2f465e5fe66 100644 (file)
--- 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)
index 43c6296f7e83f930aac2ca1289646c256ca8175a..a288d618b6849a329a919d0d768f0ab142a46ace 100644 (file)
--- 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__ */
index b2f8ad4ded932ddfdb2aefc86f803e2d4f0d894f..8aeddb08ea83f0bf1094d9cb72938df4357801dc 100644 (file)
@@ -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");
 
index 2e24b55726be8a63846c835b5d3688c7d74bf670..c542f4aa3b3b1e4f2e6fbb5db4c0ea579aefe45e 100644 (file)
--- 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;
index a115ce28927216532179bdcc842d22025e0ee092..2926bceacbad812bbda0956dc905318917f9237e 100644 (file)
--- 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
index 1a5113179ac54862b399593ff2419a6745d8ccf9..f2889fe4c9bda3ab1338b9b0f68aa822947f7c4a 100644 (file)
@@ -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);
index fcfb3e1ece840a5ed896c10cbeddbce6d69139a9..6288ae24abb4467580bb5e1cbd1515c59a6f69b5 100644 (file)
 #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)
 {