diff options
author | Tom Rini <trini@konsulko.com> | 2015-10-29 16:30:33 -0400 |
---|---|---|
committer | Tom Rini <trini@konsulko.com> | 2015-10-29 16:30:33 -0400 |
commit | 0eb4cf9c14315e1976a116de75da6f420ac0e8dd (patch) | |
tree | 3933d354a6be71cbe66d583fec3f5b2479e596ee | |
parent | 446d37c1acc76680770400fd90e6c502e49d72df (diff) | |
parent | ac1d31380618f3f68bf7f05b73b6ab0cdeab0e9f (diff) | |
download | u-boot-imx-0eb4cf9c14315e1976a116de75da6f420ac0e8dd.zip u-boot-imx-0eb4cf9c14315e1976a116de75da6f420ac0e8dd.tar.gz u-boot-imx-0eb4cf9c14315e1976a116de75da6f420ac0e8dd.tar.bz2 |
Merge branch 'master' of git://git.denx.de/u-boot-net
-rw-r--r-- | README | 12 | ||||
-rw-r--r-- | common/miiphyutil.c | 19 | ||||
-rw-r--r-- | configs/bf527-ezkit_defconfig | 1 | ||||
-rw-r--r-- | drivers/core/uclass.c | 7 | ||||
-rw-r--r-- | drivers/net/designware.c | 12 | ||||
-rw-r--r-- | drivers/net/pch_gbe.c | 12 | ||||
-rw-r--r-- | drivers/net/phy/micrel.c | 40 | ||||
-rw-r--r-- | drivers/net/phy/phy.c | 14 | ||||
-rw-r--r-- | drivers/net/rtl8169.c | 10 | ||||
-rw-r--r-- | drivers/usb/eth/smsc95xx.c | 23 | ||||
-rw-r--r-- | include/miiphy.h | 2 | ||||
-rw-r--r-- | include/net.h | 6 | ||||
-rw-r--r-- | net/Kconfig | 10 | ||||
-rw-r--r-- | net/arp.c | 7 | ||||
-rw-r--r-- | net/arp.h | 2 | ||||
-rw-r--r-- | net/bootp.c | 123 | ||||
-rw-r--r-- | net/eth.c | 53 | ||||
-rw-r--r-- | net/net.c | 6 | ||||
-rw-r--r-- | net/tftp.c | 17 | ||||
-rw-r--r-- | test/dm/eth.c | 64 |
20 files changed, 326 insertions, 114 deletions
@@ -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 c88c28a..e499b58 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 2e75225..0cc81cc 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 e800c28..1af0947 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 6433896..a6c39c3 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 004fcf8..dfc0100 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 49f444a..5e49666 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 a6023f1..d7364ff 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 ebd46b2..19422c4 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 d4b5ff4..202e482 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 088797e..af12274 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 3a787cc..ebed29a 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 77a2f7e..a44a783 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 @@ -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) @@ -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 b2f8ad4..8aeddb0 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"); @@ -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; @@ -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 @@ -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 fcfb3e1..6288ae2 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) { |