]> git.sur5r.net Git - u-boot/commitdiff
Merge branch 'master' of git://git.denx.de/u-boot-sh
authorWolfgang Denk <wd@denx.de>
Fri, 26 Aug 2011 13:55:03 +0000 (15:55 +0200)
committerWolfgang Denk <wd@denx.de>
Fri, 26 Aug 2011 13:55:03 +0000 (15:55 +0200)
* 'master' of git://git.denx.de/u-boot-sh:
  sh: add calling mmc_initialize in board.c
  sh: sh7757lcr: Add KEEP order to start.o section
  usb: r8a66597: Fix argument mistake of inl
  sh: Clean up rsk7264 board settings
  sh: sh2a: Add sh2a optimize to config.mk
  sh: Fix rsk7203 alignment problem
  sh: Add support for SH2A freestanding build
  sh: Add Renesas rsk7264 board

13 files changed:
board/davinci/common/misc.c
common/usb.c
doc/README.usb
drivers/net/designware.c
drivers/usb/eth/Makefile
drivers/usb/eth/smsc95xx.c [new file with mode: 0644]
drivers/usb/eth/usb_ether.c
fs/ubifs/ubifs.c
include/net.h
include/usb.h
include/usb_ether.h
net/bootp.c
net/eth.c

index 6103339216dd3ef893967220a0df40764254ea29..89ae1115d6078931b6e784d97154e984306966c7 100644 (file)
@@ -101,7 +101,7 @@ void davinci_sync_env_enetaddr(uint8_t *rom_enetaddr)
 {
        uint8_t env_enetaddr[6];
 
-       eth_getenv_enetaddr_by_index(0, env_enetaddr);
+       eth_getenv_enetaddr_by_index("eth", 0, env_enetaddr);
        if (!memcmp(env_enetaddr, "\0\0\0\0\0\0", 6)) {
                /* There is no MAC address in the environment, so we initialize
                 * it from the value in the EEPROM. */
index 4f7c520b344d7676d20a604be5c63d96b672efac..a401c0919878b5801a947c8992b60ae331e799b0 100644 (file)
@@ -957,8 +957,8 @@ void usb_scan_devices(void)
        /* insert "driver" if possible */
 #ifdef CONFIG_USB_KEYBOARD
        drv_usb_kbd_init();
-       USB_PRINTF("scan end\n");
 #endif
+       USB_PRINTF("scan end\n");
 }
 
 
@@ -1166,6 +1166,7 @@ void usb_hub_port_connect_change(struct usb_device *dev, int port)
 
        dev->children[port] = usb;
        usb->parent = dev;
+       usb->portnr = port + 1;
        /* Run it through the hoops (find a driver, etc) */
        if (usb_new_device(usb)) {
                /* Woops, disable the port */
index 9aa4f62ddfae0c738c423beb5fa2a5f90d49ae31..a8a4058de122d6c068d9cb91b218bdc89919c0b8 100644 (file)
@@ -79,4 +79,159 @@ CONFIG_USB_UHCI         defines the lowlevel part.A lowlevel part must be defined
                    if using CONFIG_CMD_USB
 CONFIG_USB_KEYBOARD enables the USB Keyboard
 CONFIG_USB_STORAGE  enables the USB storage devices
-CONFIG_USB_HOST_ETHER  enables USB ethernet dongle support
+CONFIG_USB_HOST_ETHER  enables USB ethernet adapter support
+
+
+USB Host Networking
+===================
+
+If you have a supported USB Ethernet adapter you can use it in U-Boot
+to obtain an IP address and load a kernel from a network server.
+
+Note: USB Host Networking is not the same as making your board act as a USB
+client. In that case your board is pretending to be an Ethernet adapter
+and will appear as a network interface to an attached computer. In that
+case the connection is via a USB cable with the computer acting as the host.
+
+With USB Host Networking, your board is the USB host. It controls the
+Ethernet adapter to which it is directly connected and the connection to
+the outside world is your adapter's Ethernet cable. Your board becomes an
+independent network device, able to connect and perform network operations
+independently of your computer.
+
+
+Device support
+--------------
+
+Currently supported devices are listed in the drivers according to
+their vendor and product IDs. You can check your device by connecting it
+to a Linux machine and typing 'lsusb'. The drivers are in
+drivers/usb/eth.
+
+For example this lsusb output line shows a device with Vendor ID 0x0x95
+and product ID 0x7720:
+
+Bus 002 Device 010: ID 0b95:7720 ASIX Electronics Corp. AX88772
+
+If you look at drivers/usb/eth/asix.c you will see this line within the
+supported device list, so we know this adapter is supported.
+
+        { 0x0b95, 0x7720 },     /* Trendnet TU2-ET100 V3.0R */
+
+If your adapter is not listed there is a still a chance that it will
+work. Try looking up the manufacturer of the chip inside your adapter.
+or take the adapter apart and look for chip markings. Then add a line
+for your vendor/product ID into the table of the appropriate driver,
+build U-Boot and see if it works. If not then there might be differences
+between the chip in your adapter and the driver. You could try to get a
+datasheet for your device and add support for it to U-Boot. This is not
+particularly difficult - you only need to provide support for four basic
+functions: init, halt, send and recv.
+
+
+Enabling USB Host Networking
+----------------------------
+
+The normal U-Boot commands are used with USB networking, but you must
+start USB first. For example:
+
+usb start
+setenv bootfile /tftpboot/uImage
+bootp
+
+
+To enable USB Host Ethernet in U-Boot, your platform must of course
+support USB with CONFIG_CMD_USB enabled and working. You will need to
+add some config settings to your board header file:
+
+#define CONFIG_USB_HOST_ETHER   /* Enable USB Ethernet adapters */
+#define CONFIG_USB_ETHER_ASIX   /* Asix, or whatever driver(s) you want */
+
+As with built-in networking, you will also want to enable some network
+commands, for example:
+
+#define CONFIG_CMD_NET
+#define CONFIG_NET_MULTI
+#define CONFIG_CMD_PING
+#define CONFIG_CMD_DHCP
+
+and some bootp options, which tell your board to obtain its subnet,
+gateway IP, host name and boot path from the bootp/dhcp server. These
+settings should start you off:
+
+#define CONFIG_BOOTP_SUBNETMASK
+#define CONFIG_BOOTP_GATEWAY
+#define CONFIG_BOOTP_HOSTNAME
+#define CONFIG_BOOTP_BOOTPATH
+
+You can also set the default IP address of your board and the server
+as well as the default file to load when a 'bootp' command is issued.
+All of these can be obtained from the bootp server if not set.
+
+#define CONFIG_IPADDR           10.0.0.2  (replace with your value)
+#define CONFIG_SERVERIP         10.0.0.1  (replace with your value)
+#define CONFIG_BOOTFILE         uImage
+
+
+The 'usb start' command should identify the adapter something like this:
+
+CrOS> usb start
+(Re)start USB...
+USB EHCI 1.00
+scanning bus for devices... 3 USB Device(s) found
+       scanning bus for storage devices... 0 Storage Device(s) found
+       scanning bus for ethernet devices... 1 Ethernet Device(s) found
+CrOS> print ethact
+ethact=asx0
+
+You can see that it found an ethernet device and we can print out the
+device name (asx0 in this case).
+
+Then 'bootp' or 'dhcp' should use it to obtain an IP address from DHCP,
+perhaps something like this:
+
+CrOS> bootp
+Waiting for Ethernet connection... done.
+BOOTP broadcast 1
+BOOTP broadcast 2
+DHCP client bound to address 172.22.73.81
+Using asx0 device
+TFTP from server 172.22.72.144; our IP address is 172.22.73.81
+Filename '/tftpboot/uImage-sjg-seaboard-261347'.
+Load address: 0x40c000
+Loading: #################################################################
+         #################################################################
+         #################################################################
+         ################################################
+done
+Bytes transferred = 3557464 (364858 hex)
+CrOS>
+
+
+Another way of doing this is to issue a tftp command, which will cause the
+bootp to happen automatically.
+
+
+MAC Addresses
+-------------
+
+Most Ethernet dongles have a built-in MAC address which is unique in the
+world. This is important so that devices on the network can be
+distinguised from each other. MAC address conflicts are evil and
+generally result in strange and eratic behaviour.
+
+Some boards have USB Ethernet chips on-board, and these sometimes do not
+have an assigned MAC address. In this case it is up to you to assign
+one which is unique. You should obtain a valid MAC address from a range
+assigned to you before you ship the product.
+
+Built-in Ethernet adapters support setting the MAC address by means of
+an ethaddr environment variable for each interface (ethaddr, eth1addr,
+eth2addr). There is similar support on the USB network side, using the
+names usbethaddr, usbeth1addr, etc. They are kept separate since we
+don't want a USB device taking the MAC address of a built-in device or
+vice versa.
+
+So if your USB Ethernet chip doesn't have a MAC address available then
+you must set usbethaddr to a suitable MAC address. At the time of
+writing this functionality is only supported by the SMSC driver.
index bfa43842ac34b582a7f1796192b14fe09ce4ac6f..1e34436772d3018403c7615331b600dc3595e660 100644 (file)
@@ -504,7 +504,7 @@ int designware_initialize(u32 id, ulong base_addr, u32 phy_addr)
        dev->iobase = (int)base_addr;
        dev->priv = priv;
 
-       eth_getenv_enetaddr_by_index(id, &dev->enetaddr[0]);
+       eth_getenv_enetaddr_by_index("eth", id, &dev->enetaddr[0]);
 
        priv->dev = dev;
        priv->mac_regs_p = (struct eth_mac_regs *)base_addr;
index a8e9eff911bfb4a571450fbe6e55dab921e4fda9..51b5b46b07abdff0d31c35d273aa345ebf4921fc 100644 (file)
@@ -28,6 +28,7 @@ COBJS-$(CONFIG_USB_HOST_ETHER) += usb_ether.o
 ifdef CONFIG_USB_ETHER_ASIX
 COBJS-y += asix.o
 endif
+COBJS-$(CONFIG_USB_ETHER_SMSC95XX) += smsc95xx.o
 
 COBJS  := $(COBJS-y)
 SRCS   := $(COBJS:.o=.c)
diff --git a/drivers/usb/eth/smsc95xx.c b/drivers/usb/eth/smsc95xx.c
new file mode 100644 (file)
index 0000000..97f2729
--- /dev/null
@@ -0,0 +1,879 @@
+/*
+ * Copyright (c) 2011 The Chromium OS Authors.
+ * Copyright (C) 2009 NVIDIA, Corporation
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <usb.h>
+#include <linux/mii.h>
+#include "usb_ether.h"
+
+/* SMSC LAN95xx based USB 2.0 Ethernet Devices */
+
+/* Tx command words */
+#define TX_CMD_A_FIRST_SEG_            0x00002000
+#define TX_CMD_A_LAST_SEG_             0x00001000
+
+/* Rx status word */
+#define RX_STS_FL_                     0x3FFF0000      /* Frame Length */
+#define RX_STS_ES_                     0x00008000      /* Error Summary */
+
+/* SCSRs */
+#define ID_REV                         0x00
+
+#define INT_STS                                0x08
+
+#define TX_CFG                         0x10
+#define TX_CFG_ON_                     0x00000004
+
+#define HW_CFG                         0x14
+#define HW_CFG_BIR_                    0x00001000
+#define HW_CFG_RXDOFF_                 0x00000600
+#define HW_CFG_MEF_                    0x00000020
+#define HW_CFG_BCE_                    0x00000002
+#define HW_CFG_LRST_                   0x00000008
+
+#define PM_CTRL                                0x20
+#define PM_CTL_PHY_RST_                        0x00000010
+
+#define AFC_CFG                                0x2C
+
+/*
+ * Hi watermark = 15.5Kb (~10 mtu pkts)
+ * low watermark = 3k (~2 mtu pkts)
+ * backpressure duration = ~ 350us
+ * Apply FC on any frame.
+ */
+#define AFC_CFG_DEFAULT                        0x00F830A1
+
+#define E2P_CMD                                0x30
+#define E2P_CMD_BUSY_                  0x80000000
+#define E2P_CMD_READ_                  0x00000000
+#define E2P_CMD_TIMEOUT_               0x00000400
+#define E2P_CMD_LOADED_                        0x00000200
+#define E2P_CMD_ADDR_                  0x000001FF
+
+#define E2P_DATA                       0x34
+
+#define BURST_CAP                      0x38
+
+#define INT_EP_CTL                     0x68
+#define INT_EP_CTL_PHY_INT_            0x00008000
+
+#define BULK_IN_DLY                    0x6C
+
+/* MAC CSRs */
+#define MAC_CR                         0x100
+#define MAC_CR_MCPAS_                  0x00080000
+#define MAC_CR_PRMS_                   0x00040000
+#define MAC_CR_HPFILT_                 0x00002000
+#define MAC_CR_TXEN_                   0x00000008
+#define MAC_CR_RXEN_                   0x00000004
+
+#define ADDRH                          0x104
+
+#define ADDRL                          0x108
+
+#define MII_ADDR                       0x114
+#define MII_WRITE_                     0x02
+#define MII_BUSY_                      0x01
+#define MII_READ_                      0x00 /* ~of MII Write bit */
+
+#define MII_DATA                       0x118
+
+#define FLOW                           0x11C
+
+#define VLAN1                          0x120
+
+#define COE_CR                         0x130
+#define Tx_COE_EN_                     0x00010000
+#define Rx_COE_EN_                     0x00000001
+
+/* Vendor-specific PHY Definitions */
+#define PHY_INT_SRC                    29
+
+#define PHY_INT_MASK                   30
+#define PHY_INT_MASK_ANEG_COMP_                ((u16)0x0040)
+#define PHY_INT_MASK_LINK_DOWN_                ((u16)0x0010)
+#define PHY_INT_MASK_DEFAULT_          (PHY_INT_MASK_ANEG_COMP_ | \
+                                        PHY_INT_MASK_LINK_DOWN_)
+
+/* USB Vendor Requests */
+#define USB_VENDOR_REQUEST_WRITE_REGISTER      0xA0
+#define USB_VENDOR_REQUEST_READ_REGISTER       0xA1
+
+/* 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)
+#define DEFAULT_BULK_IN_DELAY          0x00002000
+#define MAX_SINGLE_PACKET_SIZE         2048
+#define EEPROM_MAC_OFFSET              0x01
+#define SMSC95XX_INTERNAL_PHY_ID       1
+#define ETH_P_8021Q    0x8100          /* 802.1Q VLAN Extended Header  */
+
+/* local defines */
+#define SMSC95XX_BASE_NAME "sms"
+#define USB_CTRL_SET_TIMEOUT 5000
+#define USB_CTRL_GET_TIMEOUT 5000
+#define USB_BULK_SEND_TIMEOUT 5000
+#define USB_BULK_RECV_TIMEOUT 5000
+
+#define AX_RX_URB_SIZE 2048
+#define PHY_CONNECT_TIMEOUT 5000
+
+#define TURBO_MODE
+
+/* local vars */
+static int curr_eth_dev; /* index for name of next device detected */
+
+
+/*
+ * Smsc95xx infrastructure commands
+ */
+static int smsc95xx_write_reg(struct ueth_data *dev, u32 index, u32 data)
+{
+       int len;
+
+       cpu_to_le32s(&data);
+
+       len = usb_control_msg(dev->pusb_dev, usb_sndctrlpipe(dev->pusb_dev, 0),
+               USB_VENDOR_REQUEST_WRITE_REGISTER,
+               USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+               00, index, &data, sizeof(data), USB_CTRL_SET_TIMEOUT);
+       if (len != sizeof(data)) {
+               debug("smsc95xx_write_reg failed: index=%d, data=%d, len=%d",
+                     index, data, len);
+               return -1;
+       }
+       return 0;
+}
+
+static int smsc95xx_read_reg(struct ueth_data *dev, u32 index, u32 *data)
+{
+       int len;
+
+       len = usb_control_msg(dev->pusb_dev, usb_rcvctrlpipe(dev->pusb_dev, 0),
+               USB_VENDOR_REQUEST_READ_REGISTER,
+               USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+               00, index, data, sizeof(data), USB_CTRL_GET_TIMEOUT);
+       if (len != sizeof(data)) {
+               debug("smsc95xx_read_reg failed: index=%d, len=%d",
+                     index, len);
+               return -1;
+       }
+
+       le32_to_cpus(data);
+       return 0;
+}
+
+/* Loop until the read is completed with timeout */
+static int smsc95xx_phy_wait_not_busy(struct ueth_data *dev)
+{
+       unsigned long start_time = get_timer(0);
+       u32 val;
+
+       do {
+               smsc95xx_read_reg(dev, MII_ADDR, &val);
+               if (!(val & MII_BUSY_))
+                       return 0;
+       } while (get_timer(start_time) < 1 * 1000 * 1000);
+
+       return -1;
+}
+
+static int smsc95xx_mdio_read(struct ueth_data *dev, int phy_id, int idx)
+{
+       u32 val, addr;
+
+       /* confirm MII not busy */
+       if (smsc95xx_phy_wait_not_busy(dev)) {
+               debug("MII is busy in smsc95xx_mdio_read\n");
+               return -1;
+       }
+
+       /* set the address, index & direction (read from PHY) */
+       addr = (phy_id << 11) | (idx << 6) | MII_READ_;
+       smsc95xx_write_reg(dev, MII_ADDR, addr);
+
+       if (smsc95xx_phy_wait_not_busy(dev)) {
+               debug("Timed out reading MII reg %02X\n", idx);
+               return -1;
+       }
+
+       smsc95xx_read_reg(dev, MII_DATA, &val);
+
+       return (u16)(val & 0xFFFF);
+}
+
+static void smsc95xx_mdio_write(struct ueth_data *dev, int phy_id, int idx,
+                               int regval)
+{
+       u32 val, addr;
+
+       /* confirm MII not busy */
+       if (smsc95xx_phy_wait_not_busy(dev)) {
+               debug("MII is busy in smsc95xx_mdio_write\n");
+               return;
+       }
+
+       val = regval;
+       smsc95xx_write_reg(dev, MII_DATA, val);
+
+       /* set the address, index & direction (write to PHY) */
+       addr = (phy_id << 11) | (idx << 6) | MII_WRITE_;
+       smsc95xx_write_reg(dev, MII_ADDR, addr);
+
+       if (smsc95xx_phy_wait_not_busy(dev))
+               debug("Timed out writing MII reg %02X\n", idx);
+}
+
+static int smsc95xx_eeprom_confirm_not_busy(struct ueth_data *dev)
+{
+       unsigned long start_time = get_timer(0);
+       u32 val;
+
+       do {
+               smsc95xx_read_reg(dev, E2P_CMD, &val);
+               if (!(val & E2P_CMD_LOADED_)) {
+                       debug("No EEPROM present\n");
+                       return -1;
+               }
+               if (!(val & E2P_CMD_BUSY_))
+                       return 0;
+               udelay(40);
+       } while (get_timer(start_time) < 1 * 1000 * 1000);
+
+       debug("EEPROM is busy\n");
+       return -1;
+}
+
+static int smsc95xx_wait_eeprom(struct ueth_data *dev)
+{
+       unsigned long start_time = get_timer(0);
+       u32 val;
+
+       do {
+               smsc95xx_read_reg(dev, E2P_CMD, &val);
+               if (!(val & E2P_CMD_BUSY_) || (val & E2P_CMD_TIMEOUT_))
+                       break;
+               udelay(40);
+       } while (get_timer(start_time) < 1 * 1000 * 1000);
+
+       if (val & (E2P_CMD_TIMEOUT_ | E2P_CMD_BUSY_)) {
+               debug("EEPROM read operation timeout\n");
+               return -1;
+       }
+       return 0;
+}
+
+static int smsc95xx_read_eeprom(struct ueth_data *dev, u32 offset, u32 length,
+                               u8 *data)
+{
+       u32 val;
+       int i, ret;
+
+       ret = smsc95xx_eeprom_confirm_not_busy(dev);
+       if (ret)
+               return ret;
+
+       for (i = 0; i < length; i++) {
+               val = E2P_CMD_BUSY_ | E2P_CMD_READ_ | (offset & E2P_CMD_ADDR_);
+               smsc95xx_write_reg(dev, E2P_CMD, val);
+
+               ret = smsc95xx_wait_eeprom(dev);
+               if (ret < 0)
+                       return ret;
+
+               smsc95xx_read_reg(dev, E2P_DATA, &val);
+               data[i] = val & 0xFF;
+               offset++;
+       }
+       return 0;
+}
+
+/*
+ * mii_nway_restart - restart NWay (autonegotiation) for this interface
+ *
+ * Returns 0 on success, negative on error.
+ */
+static int mii_nway_restart(struct ueth_data *dev)
+{
+       int bmcr;
+       int r = -1;
+
+       /* if autoneg is off, it's an error */
+       bmcr = smsc95xx_mdio_read(dev, dev->phy_id, MII_BMCR);
+
+       if (bmcr & BMCR_ANENABLE) {
+               bmcr |= BMCR_ANRESTART;
+               smsc95xx_mdio_write(dev, dev->phy_id, MII_BMCR, bmcr);
+               r = 0;
+       }
+       return r;
+}
+
+static int smsc95xx_phy_initialize(struct ueth_data *dev)
+{
+       smsc95xx_mdio_write(dev, dev->phy_id, MII_BMCR, BMCR_RESET);
+       smsc95xx_mdio_write(dev, dev->phy_id, MII_ADVERTISE,
+               ADVERTISE_ALL | ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP |
+               ADVERTISE_PAUSE_ASYM);
+
+       /* read to clear */
+       smsc95xx_mdio_read(dev, dev->phy_id, PHY_INT_SRC);
+
+       smsc95xx_mdio_write(dev, dev->phy_id, PHY_INT_MASK,
+               PHY_INT_MASK_DEFAULT_);
+       mii_nway_restart(dev);
+
+       debug("phy initialised succesfully\n");
+       return 0;
+}
+
+static int smsc95xx_init_mac_address(struct eth_device *eth,
+               struct ueth_data *dev)
+{
+       /* try reading mac address from EEPROM */
+       if (smsc95xx_read_eeprom(dev, EEPROM_MAC_OFFSET, ETH_ALEN,
+                       eth->enetaddr) == 0) {
+               if (is_valid_ether_addr(eth->enetaddr)) {
+                       /* eeprom values are valid so use them */
+                       debug("MAC address read from EEPROM\n");
+                       return 0;
+               }
+       }
+
+       /*
+        * No eeprom, or eeprom values are invalid. Generating a random MAC
+        * address is not safe. Just return an error.
+        */
+       return -1;
+}
+
+static int smsc95xx_write_hwaddr(struct eth_device *eth)
+{
+       struct ueth_data *dev = (struct ueth_data *)eth->priv;
+       u32 addr_lo, addr_hi;
+       int ret;
+
+       /* set hardware address */
+       debug("** %s()\n", __func__);
+       addr_lo = cpu_to_le32(*((u32 *)eth->enetaddr));
+       addr_hi = cpu_to_le16(*((u16 *)(eth->enetaddr + 4)));
+       ret = smsc95xx_write_reg(dev, ADDRL, addr_lo);
+       if (ret < 0) {
+               debug("Failed to write ADDRL: %d\n", ret);
+               return ret;
+       }
+
+       ret = smsc95xx_write_reg(dev, ADDRH, addr_hi);
+       if (ret < 0)
+               return ret;
+       debug("MAC %02x:%02x:%02x:%02x:%02x:%02x\n",
+               eth->enetaddr[0], eth->enetaddr[1],
+               eth->enetaddr[2], eth->enetaddr[3],
+               eth->enetaddr[4], eth->enetaddr[5]);
+       dev->have_hwaddr = 1;
+       return 0;
+}
+
+/* Enable or disable Tx & Rx checksum offload engines */
+static int smsc95xx_set_csums(struct ueth_data *dev,
+               int use_tx_csum, int use_rx_csum)
+{
+       u32 read_buf;
+       int ret = smsc95xx_read_reg(dev, COE_CR, &read_buf);
+       if (ret < 0)
+               return ret;
+
+       if (use_tx_csum)
+               read_buf |= Tx_COE_EN_;
+       else
+               read_buf &= ~Tx_COE_EN_;
+
+       if (use_rx_csum)
+               read_buf |= Rx_COE_EN_;
+       else
+               read_buf &= ~Rx_COE_EN_;
+
+       ret = smsc95xx_write_reg(dev, COE_CR, read_buf);
+       if (ret < 0)
+               return ret;
+
+       debug("COE_CR = 0x%08x\n", read_buf);
+       return 0;
+}
+
+static void smsc95xx_set_multicast(struct ueth_data *dev)
+{
+       /* No multicast in u-boot */
+       dev->mac_cr &= ~(MAC_CR_PRMS_ | MAC_CR_MCPAS_ | MAC_CR_HPFILT_);
+}
+
+/* starts the TX path */
+static void smsc95xx_start_tx_path(struct ueth_data *dev)
+{
+       u32 reg_val;
+
+       /* Enable Tx at MAC */
+       dev->mac_cr |= MAC_CR_TXEN_;
+
+       smsc95xx_write_reg(dev, MAC_CR, dev->mac_cr);
+
+       /* Enable Tx at SCSRs */
+       reg_val = TX_CFG_ON_;
+       smsc95xx_write_reg(dev, TX_CFG, reg_val);
+}
+
+/* Starts the Receive path */
+static void smsc95xx_start_rx_path(struct ueth_data *dev)
+{
+       dev->mac_cr |= MAC_CR_RXEN_;
+       smsc95xx_write_reg(dev, MAC_CR, dev->mac_cr);
+}
+
+/*
+ * Smsc95xx callbacks
+ */
+static int smsc95xx_init(struct eth_device *eth, bd_t *bd)
+{
+       int ret;
+       u32 write_buf;
+       u32 read_buf;
+       u32 burst_cap;
+       int timeout;
+       struct ueth_data *dev = (struct ueth_data *)eth->priv;
+#define TIMEOUT_RESOLUTION 50  /* ms */
+       int link_detected;
+
+       debug("** %s()\n", __func__);
+       dev->phy_id = SMSC95XX_INTERNAL_PHY_ID; /* fixed phy id */
+
+       write_buf = HW_CFG_LRST_;
+       ret = smsc95xx_write_reg(dev, HW_CFG, write_buf);
+       if (ret < 0)
+               return ret;
+
+       timeout = 0;
+       do {
+               ret = smsc95xx_read_reg(dev, HW_CFG, &read_buf);
+               if (ret < 0)
+                       return ret;
+               udelay(10 * 1000);
+               timeout++;
+       } while ((read_buf & HW_CFG_LRST_) && (timeout < 100));
+
+       if (timeout >= 100) {
+               debug("timeout waiting for completion of Lite Reset\n");
+               return -1;
+       }
+
+       write_buf = PM_CTL_PHY_RST_;
+       ret = smsc95xx_write_reg(dev, PM_CTRL, write_buf);
+       if (ret < 0)
+               return ret;
+
+       timeout = 0;
+       do {
+               ret = smsc95xx_read_reg(dev, PM_CTRL, &read_buf);
+               if (ret < 0)
+                       return ret;
+               udelay(10 * 1000);
+               timeout++;
+       } while ((read_buf & PM_CTL_PHY_RST_) && (timeout < 100));
+       if (timeout >= 100) {
+               debug("timeout waiting for PHY Reset\n");
+               return -1;
+       }
+       if (!dev->have_hwaddr && smsc95xx_init_mac_address(eth, dev) == 0)
+               dev->have_hwaddr = 1;
+       if (!dev->have_hwaddr) {
+               puts("Error: SMSC95xx: No MAC address set - set usbethaddr\n");
+               return -1;
+       }
+       if (smsc95xx_write_hwaddr(eth) < 0)
+               return -1;
+
+       ret = smsc95xx_read_reg(dev, 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(dev, HW_CFG, read_buf);
+       if (ret < 0)
+               return ret;
+
+       ret = smsc95xx_read_reg(dev, 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;
+               dev->rx_urb_size = DEFAULT_HS_BURST_CAP_SIZE;
+       } else {
+               burst_cap = DEFAULT_FS_BURST_CAP_SIZE / FS_USB_PKT_SIZE;
+               dev->rx_urb_size = DEFAULT_FS_BURST_CAP_SIZE;
+       }
+#else
+       burst_cap = 0;
+       dev->rx_urb_size = MAX_SINGLE_PACKET_SIZE;
+#endif
+       debug("rx_urb_size=%ld\n", (ulong)dev->rx_urb_size);
+
+       ret = smsc95xx_write_reg(dev, BURST_CAP, burst_cap);
+       if (ret < 0)
+               return ret;
+
+       ret = smsc95xx_read_reg(dev, BURST_CAP, &read_buf);
+       if (ret < 0)
+               return ret;
+       debug("Read Value from BURST_CAP after writing: 0x%08x\n", read_buf);
+
+       read_buf = DEFAULT_BULK_IN_DELAY;
+       ret = smsc95xx_write_reg(dev, BULK_IN_DLY, read_buf);
+       if (ret < 0)
+               return ret;
+
+       ret = smsc95xx_read_reg(dev, BULK_IN_DLY, &read_buf);
+       if (ret < 0)
+               return ret;
+       debug("Read Value from BULK_IN_DLY after writing: "
+                       "0x%08x\n", read_buf);
+
+       ret = smsc95xx_read_reg(dev, HW_CFG, &read_buf);
+       if (ret < 0)
+               return ret;
+       debug("Read Value from HW_CFG: 0x%08x\n", read_buf);
+
+#ifdef TURBO_MODE
+       read_buf |= (HW_CFG_MEF_ | HW_CFG_BCE_);
+#endif
+       read_buf &= ~HW_CFG_RXDOFF_;
+
+#define NET_IP_ALIGN 0
+       read_buf |= NET_IP_ALIGN << 9;
+
+       ret = smsc95xx_write_reg(dev, HW_CFG, read_buf);
+       if (ret < 0)
+               return ret;
+
+       ret = smsc95xx_read_reg(dev, HW_CFG, &read_buf);
+       if (ret < 0)
+               return ret;
+       debug("Read Value from HW_CFG after writing: 0x%08x\n", read_buf);
+
+       write_buf = 0xFFFFFFFF;
+       ret = smsc95xx_write_reg(dev, INT_STS, write_buf);
+       if (ret < 0)
+               return ret;
+
+       ret = smsc95xx_read_reg(dev, ID_REV, &read_buf);
+       if (ret < 0)
+               return ret;
+       debug("ID_REV = 0x%08x\n", read_buf);
+
+       /* Init Tx */
+       write_buf = 0;
+       ret = smsc95xx_write_reg(dev, FLOW, write_buf);
+       if (ret < 0)
+               return ret;
+
+       read_buf = AFC_CFG_DEFAULT;
+       ret = smsc95xx_write_reg(dev, AFC_CFG, read_buf);
+       if (ret < 0)
+               return ret;
+
+       ret = smsc95xx_read_reg(dev, MAC_CR, &dev->mac_cr);
+       if (ret < 0)
+               return ret;
+
+       /* Init Rx. Set Vlan */
+       write_buf = (u32)ETH_P_8021Q;
+       ret = smsc95xx_write_reg(dev, VLAN1, write_buf);
+       if (ret < 0)
+               return ret;
+
+       /* Disable checksum offload engines */
+       ret = smsc95xx_set_csums(dev, 0, 0);
+       if (ret < 0) {
+               debug("Failed to set csum offload: %d\n", ret);
+               return ret;
+       }
+       smsc95xx_set_multicast(dev);
+
+       if (smsc95xx_phy_initialize(dev) < 0)
+               return -1;
+       ret = smsc95xx_read_reg(dev, INT_EP_CTL, &read_buf);
+       if (ret < 0)
+               return ret;
+
+       /* enable PHY interrupts */
+       read_buf |= INT_EP_CTL_PHY_INT_;
+
+       ret = smsc95xx_write_reg(dev, INT_EP_CTL, read_buf);
+       if (ret < 0)
+               return ret;
+
+       smsc95xx_start_tx_path(dev);
+       smsc95xx_start_rx_path(dev);
+
+       timeout = 0;
+       do {
+               link_detected = smsc95xx_mdio_read(dev, dev->phy_id, MII_BMSR)
+                       & BMSR_LSTATUS;
+               if (!link_detected) {
+                       if (timeout == 0)
+                               printf("Waiting for Ethernet connection... ");
+                       udelay(TIMEOUT_RESOLUTION * 1000);
+                       timeout += TIMEOUT_RESOLUTION;
+               }
+       } while (!link_detected && timeout < PHY_CONNECT_TIMEOUT);
+       if (link_detected) {
+               if (timeout != 0)
+                       printf("done.\n");
+       } else {
+               printf("unable to connect.\n");
+               return -1;
+       }
+       return 0;
+}
+
+static int smsc95xx_send(struct eth_device *eth, volatile void* packet,
+                        int length)
+{
+       struct ueth_data *dev = (struct ueth_data *)eth->priv;
+       int err;
+       int actual_len;
+       u32 tx_cmd_a;
+       u32 tx_cmd_b;
+       unsigned char msg[PKTSIZE + sizeof(tx_cmd_a) + sizeof(tx_cmd_b)];
+
+       debug("** %s(), len %d, buf %#x\n", __func__, length, (int)msg);
+       if (length > PKTSIZE)
+               return -1;
+
+       tx_cmd_a = (u32)length | TX_CMD_A_FIRST_SEG_ | TX_CMD_A_LAST_SEG_;
+       tx_cmd_b = (u32)length;
+       cpu_to_le32s(&tx_cmd_a);
+       cpu_to_le32s(&tx_cmd_b);
+
+       /* prepend cmd_a and cmd_b */
+       memcpy(msg, &tx_cmd_a, sizeof(tx_cmd_a));
+       memcpy(msg + sizeof(tx_cmd_a), &tx_cmd_b, sizeof(tx_cmd_b));
+       memcpy(msg + sizeof(tx_cmd_a) + sizeof(tx_cmd_b), (void *)packet,
+              length);
+       err = usb_bulk_msg(dev->pusb_dev,
+                               usb_sndbulkpipe(dev->pusb_dev, dev->ep_out),
+                               (void *)msg,
+                               length + sizeof(tx_cmd_a) + sizeof(tx_cmd_b),
+                               &actual_len,
+                               USB_BULK_SEND_TIMEOUT);
+       debug("Tx: len = %u, actual = %u, err = %d\n",
+             length + sizeof(tx_cmd_a) + sizeof(tx_cmd_b),
+             actual_len, err);
+       return err;
+}
+
+static int smsc95xx_recv(struct eth_device *eth)
+{
+       struct ueth_data *dev = (struct ueth_data *)eth->priv;
+       static unsigned char  recv_buf[AX_RX_URB_SIZE];
+       unsigned char *buf_ptr;
+       int err;
+       int actual_len;
+       u32 packet_len;
+       int cur_buf_align;
+
+       debug("** %s()\n", __func__);
+       err = usb_bulk_msg(dev->pusb_dev,
+                               usb_rcvbulkpipe(dev->pusb_dev, dev->ep_in),
+                               (void *)recv_buf,
+                               AX_RX_URB_SIZE,
+                               &actual_len,
+                               USB_BULK_RECV_TIMEOUT);
+       debug("Rx: len = %u, actual = %u, err = %d\n", AX_RX_URB_SIZE,
+             actual_len, err);
+       if (err != 0) {
+               debug("Rx: failed to receive\n");
+               return -1;
+       }
+       if (actual_len > AX_RX_URB_SIZE) {
+               debug("Rx: received too many bytes %d\n", actual_len);
+               return -1;
+       }
+
+       buf_ptr = recv_buf;
+       while (actual_len > 0) {
+               /*
+                * 1st 4 bytes contain the length of the actual data plus error
+                * info. Extract data length.
+                */
+               if (actual_len < sizeof(packet_len)) {
+                       debug("Rx: incomplete packet length\n");
+                       return -1;
+               }
+               memcpy(&packet_len, buf_ptr, sizeof(packet_len));
+               le32_to_cpus(&packet_len);
+               if (packet_len & RX_STS_ES_) {
+                       debug("Rx: Error header=%#x", packet_len);
+                       return -1;
+               }
+               packet_len = ((packet_len & RX_STS_FL_) >> 16);
+
+               if (packet_len > actual_len - sizeof(packet_len)) {
+                       debug("Rx: too large packet: %d\n", packet_len);
+                       return -1;
+               }
+
+               /* Notify net stack */
+               NetReceive(buf_ptr + sizeof(packet_len), packet_len - 4);
+
+               /* Adjust for next iteration */
+               actual_len -= sizeof(packet_len) + packet_len;
+               buf_ptr += sizeof(packet_len) + packet_len;
+               cur_buf_align = (int)buf_ptr - (int)recv_buf;
+
+               if (cur_buf_align & 0x03) {
+                       int align = 4 - (cur_buf_align & 0x03);
+
+                       actual_len -= align;
+                       buf_ptr += align;
+               }
+       }
+       return err;
+}
+
+static void smsc95xx_halt(struct eth_device *eth)
+{
+       debug("** %s()\n", __func__);
+}
+
+/*
+ * SMSC probing functions
+ */
+void smsc95xx_eth_before_probe(void)
+{
+       curr_eth_dev = 0;
+}
+
+struct smsc95xx_dongle {
+       unsigned short vendor;
+       unsigned short product;
+};
+
+static const struct smsc95xx_dongle smsc95xx_dongles[] = {
+       { 0x0424, 0xec00 },     /* LAN9512/LAN9514 Ethernet */
+       { 0x0424, 0x9500 },     /* LAN9500 Ethernet */
+       { 0x0000, 0x0000 }      /* END - Do not remove */
+};
+
+/* Probe to see if a new device is actually an SMSC device */
+int smsc95xx_eth_probe(struct usb_device *dev, unsigned int ifnum,
+                     struct ueth_data *ss)
+{
+       struct usb_interface *iface;
+       struct usb_interface_descriptor *iface_desc;
+       int i;
+
+       /* let's examine the device now */
+       iface = &dev->config.if_desc[ifnum];
+       iface_desc = &dev->config.if_desc[ifnum].desc;
+
+       for (i = 0; smsc95xx_dongles[i].vendor != 0; i++) {
+               if (dev->descriptor.idVendor == smsc95xx_dongles[i].vendor &&
+                   dev->descriptor.idProduct == smsc95xx_dongles[i].product)
+                       /* Found a supported dongle */
+                       break;
+       }
+       if (smsc95xx_dongles[i].vendor == 0)
+               return 0;
+
+       /* At this point, we know we've got a live one */
+       debug("\n\nUSB Ethernet device detected\n");
+       memset(ss, '\0', sizeof(struct ueth_data));
+
+       /* Initialize the ueth_data structure with some useful info */
+       ss->ifnum = ifnum;
+       ss->pusb_dev = dev;
+       ss->subclass = iface_desc->bInterfaceSubClass;
+       ss->protocol = iface_desc->bInterfaceProtocol;
+
+       /*
+        * We are expecting a minimum of 3 endpoints - in, out (bulk), and int.
+        * We will ignore any others.
+        */
+       for (i = 0; i < iface_desc->bNumEndpoints; i++) {
+               /* is it an BULK endpoint? */
+               if ((iface->ep_desc[i].bmAttributes &
+                    USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_BULK) {
+                       if (iface->ep_desc[i].bEndpointAddress & USB_DIR_IN)
+                               ss->ep_in =
+                                       iface->ep_desc[i].bEndpointAddress &
+                                       USB_ENDPOINT_NUMBER_MASK;
+                       else
+                               ss->ep_out =
+                                       iface->ep_desc[i].bEndpointAddress &
+                                       USB_ENDPOINT_NUMBER_MASK;
+               }
+
+               /* is it an interrupt endpoint? */
+               if ((iface->ep_desc[i].bmAttributes &
+                   USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT) {
+                       ss->ep_int = iface->ep_desc[i].bEndpointAddress &
+                               USB_ENDPOINT_NUMBER_MASK;
+                       ss->irqinterval = iface->ep_desc[i].bInterval;
+               }
+       }
+       debug("Endpoints In %d Out %d Int %d\n",
+                 ss->ep_in, ss->ep_out, ss->ep_int);
+
+       /* Do some basic sanity checks, and bail if we find a problem */
+       if (usb_set_interface(dev, iface_desc->bInterfaceNumber, 0) ||
+           !ss->ep_in || !ss->ep_out || !ss->ep_int) {
+               debug("Problems with device\n");
+               return 0;
+       }
+       dev->privptr = (void *)ss;
+       return 1;
+}
+
+int smsc95xx_eth_get_info(struct usb_device *dev, struct ueth_data *ss,
+                               struct eth_device *eth)
+{
+       debug("** %s()\n", __func__);
+       if (!eth) {
+               debug("%s: missing parameter.\n", __func__);
+               return 0;
+       }
+       sprintf(eth->name, "%s%d", SMSC95XX_BASE_NAME, curr_eth_dev++);
+       eth->init = smsc95xx_init;
+       eth->send = smsc95xx_send;
+       eth->recv = smsc95xx_recv;
+       eth->halt = smsc95xx_halt;
+       eth->write_hwaddr = smsc95xx_write_hwaddr;
+       eth->priv = ss;
+       return 1;
+}
index 68a08836ec949499a2356e345381d3de8faeee52..6565ea5590b8235834166c99bb083b3cc1debd72 100644 (file)
@@ -44,6 +44,13 @@ static const struct usb_eth_prob_dev prob_dev[] = {
                .probe = asix_eth_probe,
                .get_info = asix_eth_get_info,
        },
+#endif
+#ifdef CONFIG_USB_ETHER_SMSC95XX
+       {
+               .before_probe = smsc95xx_eth_before_probe,
+               .probe = smsc95xx_eth_probe,
+               .get_info = smsc95xx_eth_get_info,
+       },
 #endif
        { },            /* END */
 };
@@ -73,6 +80,7 @@ int is_eth_dev_on_usb_host(void)
  */
 static void probe_valid_drivers(struct usb_device *dev)
 {
+       struct eth_device *eth;
        int j;
 
        for (j = 0; prob_dev[j].probe && prob_dev[j].get_info; j++) {
@@ -81,9 +89,10 @@ static void probe_valid_drivers(struct usb_device *dev)
                /*
                 * ok, it is a supported eth device. Get info and fill it in
                 */
+               eth = &usb_eth[usb_max_eth_dev].eth_dev;
                if (prob_dev[j].get_info(dev,
                        &usb_eth[usb_max_eth_dev],
-                       &usb_eth[usb_max_eth_dev].eth_dev)) {
+                       eth)) {
                        /* found proper driver */
                        /* register with networking stack */
                        usb_max_eth_dev++;
@@ -93,7 +102,10 @@ static void probe_valid_drivers(struct usb_device *dev)
                         * call since eth_current_changed (internally called)
                         * relies on it
                         */
-                       eth_register(&usb_eth[usb_max_eth_dev - 1].eth_dev);
+                       eth_register(eth);
+                       if (eth_write_hwaddr(eth, "usbeth",
+                                       usb_max_eth_dev - 1))
+                               puts("Warning: failed to set MAC address\n");
                        break;
                        }
                }
index 5a5c739b53f5caccf1936efa7bbe93178f11494e..61f70b29604c0a7fcf8e4ff1236286b19959cf7f 100644 (file)
@@ -360,6 +360,8 @@ out:
                return err;
        }
 
+       if (file->private_data)
+               kfree(file->private_data);
        if (file)
                free(file);
        if (dentry)
@@ -367,10 +369,6 @@ out:
        if (dir)
                free(dir);
 
-       if (file->private_data)
-               kfree(file->private_data);
-       file->private_data = NULL;
-       file->f_pos = 2;
        return 0;
 }
 
index 018a74402c8357f55e3c63777cb49be4514ccd78..ce54825085569a29c7242958a06956882b6138d6 100644 (file)
@@ -128,7 +128,18 @@ extern int eth_get_dev_index (void);               /* get the device index */
 extern void eth_parse_enetaddr(const char *addr, uchar *enetaddr);
 extern int eth_getenv_enetaddr(char *name, uchar *enetaddr);
 extern int eth_setenv_enetaddr(char *name, const uchar *enetaddr);
-extern int eth_getenv_enetaddr_by_index(int index, uchar *enetaddr);
+
+/*
+ * Get the hardware address for an ethernet interface .
+ * Args:
+ *     base_name - base name for device (normally "eth")
+ *     index - device index number (0 for first)
+ *     enetaddr - returns 6 byte hardware address
+ * Returns:
+ *     Return true if the address is valid.
+ */
+extern int eth_getenv_enetaddr_by_index(const char *base_name, int index,
+                                       uchar *enetaddr);
 
 extern int usb_eth_initialize(bd_t *bi);
 extern int eth_init(bd_t *bis);                        /* Initialize the device */
@@ -141,6 +152,18 @@ extern int eth_rx(void);                   /* Check for received packets */
 extern void eth_halt(void);                    /* stop SCC */
 extern char *eth_get_name(void);               /* get name of current device */
 
+/*
+ * Set the hardware address for an ethernet interface based on 'eth%daddr'
+ * environment variable (or just 'ethaddr' if eth_number is 0).
+ * Args:
+ *     base_name - base name for device (normally "eth")
+ *     eth_number - value of %d (0 for first device of this type)
+ * Returns:
+ *     0 is success, non-zero is error status from driver.
+ */
+int eth_write_hwaddr(struct eth_device *dev, const char *base_name,
+                    int eth_number);
+
 #ifdef CONFIG_MCAST_TFTP
 int eth_mcast_join( IPaddr_t mcast_addr, u8 join);
 u32 ether_crc (size_t len, unsigned char const *p);
index 53603a5582256bd90ae47f2dbc7cccab5b3d0010..06170cdc5a51a45524badfa39c38adb2ab1956d8 100644 (file)
@@ -46,7 +46,7 @@
  * This is the timeout to allow for submitting an urb in ms. We allow more
  * time for a BULK device to react - some are slow.
  */
-#define USB_TIMEOUT_MS(pipe) (usb_pipebulk(pipe) ? 5000 : 100)
+#define USB_TIMEOUT_MS(pipe) (usb_pipebulk(pipe) ? 5000 : 1000)
 
 /* device request (setup) */
 struct devrequest {
index 825c27518f9931f63c1ce0cdee1c6b156093247b..a7fb26bf7c121a350054839e1824764ff195d304 100644 (file)
@@ -51,6 +51,11 @@ struct ueth_data {
        unsigned char   irqinterval;    /* Intervall for IRQ Pipe */
 
        /* private fields for each driver can go here if needed */
+#ifdef CONFIG_USB_ETHER_SMSC95XX
+       size_t rx_urb_size;  /* maximum USB URB size */
+       u32 mac_cr;  /* MAC control register value */
+       int have_hwaddr;  /* 1 if we have a hardware MAC address */
+#endif
 };
 
 /*
@@ -65,4 +70,12 @@ int asix_eth_get_info(struct usb_device *dev, struct ueth_data *ss,
                      struct eth_device *eth);
 #endif
 
+#ifdef CONFIG_USB_ETHER_SMSC95XX
+void smsc95xx_eth_before_probe(void);
+int smsc95xx_eth_probe(struct usb_device *dev, unsigned int ifnum,
+                       struct ueth_data *ss);
+int smsc95xx_eth_get_info(struct usb_device *dev, struct ueth_data *ss,
+                       struct eth_device *eth);
+#endif
+
 #endif /* __USB_ETHER_H__ */
index 45eaab1e0582c272a075b2adb57e67b9ea0d5926..3db08ea2f31583443ee11581763bac4d1fccb2a8 100644 (file)
@@ -138,6 +138,36 @@ static int truncate_sz (const char *name, int maxlen, int curlen)
        return (curlen);
 }
 
+/*
+ * Check if autoload is enabled. If so, use either NFS or TFTP to download
+ * the boot file.
+ */
+static void auto_load(void)
+{
+       const char *s = getenv("autoload");
+
+       if (s != NULL) {
+               if (*s == 'n') {
+                       /*
+                        * Just use BOOTP to configure system;
+                        * Do not use TFTP to load the bootfile.
+                        */
+                       NetState = NETLOOP_SUCCESS;
+                       return;
+               }
+#if defined(CONFIG_CMD_NFS)
+               if (strcmp(s, "NFS") == 0) {
+                       /*
+                        * Use NFS to load the bootfile.
+                        */
+                       NfsStart();
+                       return;
+               }
+#endif
+       TftpStart();
+       }
+}
+
 #if !defined(CONFIG_CMD_DHCP)
 
 static void BootpVendorFieldProcess (u8 * ext)
@@ -289,6 +319,7 @@ static void BootpVendorProcess (u8 * ext, int size)
                debug("NetNtpServerIP : %pI4\n", &NetNtpServerIP);
 #endif
 }
+
 /*
  *     Handle a BOOTP received packet.
  */
@@ -297,7 +328,6 @@ BootpHandler(uchar *pkt, unsigned dest, IPaddr_t sip, unsigned src,
             unsigned len)
 {
        Bootp_t *bp;
-       char    *s;
 
        debug("got BOOTP packet (src=%d, dst=%d, len=%d want_len=%zu)\n",
                src, dest, len, sizeof (Bootp_t));
@@ -324,26 +354,7 @@ BootpHandler(uchar *pkt, unsigned dest, IPaddr_t sip, unsigned src,
 
        debug("Got good BOOTP\n");
 
-       if ((s = getenv("autoload")) != NULL) {
-               if (*s == 'n') {
-                       /*
-                        * Just use BOOTP to configure system;
-                        * Do not use TFTP to load the bootfile.
-                        */
-                       NetState = NETLOOP_SUCCESS;
-                       return;
-#if defined(CONFIG_CMD_NFS)
-               } else if (strcmp(s, "NFS") == 0) {
-                       /*
-                        * Use NFS to load the bootfile.
-                        */
-                       NfsStart();
-                       return;
-#endif
-               }
-       }
-
-       TftpStart();
+       auto_load();
 }
 #endif
 
@@ -922,34 +933,13 @@ DhcpHandler(uchar *pkt, unsigned dest, IPaddr_t sip, unsigned src,
                debug("DHCP State: REQUESTING\n");
 
                if ( DhcpMessageType((u8 *)bp->bp_vend) == DHCP_ACK ) {
-                       char *s;
-
                        if (NetReadLong((ulong*)&bp->bp_vend[0]) == htonl(BOOTP_VENDOR_MAGIC))
                                DhcpOptionsProcess((u8 *)&bp->bp_vend[4], bp);
                        BootpCopyNetParams(bp); /* Store net params from reply */
                        dhcp_state = BOUND;
                        printf ("DHCP client bound to address %pI4\n", &NetOurIP);
 
-                       /* Obey the 'autoload' setting */
-                       if ((s = getenv("autoload")) != NULL) {
-                               if (*s == 'n') {
-                                       /*
-                                        * Just use BOOTP to configure system;
-                                        * Do not use TFTP to load the bootfile.
-                                        */
-                                       NetState = NETLOOP_SUCCESS;
-                                       return;
-#if defined(CONFIG_CMD_NFS)
-                               } else if (strcmp(s, "NFS") == 0) {
-                                       /*
-                                        * Use NFS to load the bootfile.
-                                        */
-                                       NfsStart();
-                                       return;
-#endif
-                               }
-                       }
-                       TftpStart();
+                       auto_load();
                        return;
                }
                break;
index 3aad71f5d35ba0e59e9b0d25f7db8ea86b637577..a34fe59383f38bc40a830c2628d191960c4396d3 100644 (file)
--- a/net/eth.c
+++ b/net/eth.c
@@ -54,10 +54,11 @@ int eth_setenv_enetaddr(char *name, const uchar *enetaddr)
        return setenv(name, buf);
 }
 
-int eth_getenv_enetaddr_by_index(int index, uchar *enetaddr)
+int eth_getenv_enetaddr_by_index(const char *base_name, int index,
+                                uchar *enetaddr)
 {
        char enetvar[32];
-       sprintf(enetvar, index ? "eth%daddr" : "ethaddr", index);
+       sprintf(enetvar, index ? "%s%daddr" : "%saddr", base_name, index);
        return eth_getenv_enetaddr(enetvar, enetaddr);
 }
 
@@ -188,6 +189,38 @@ static void eth_current_changed(void)
 #endif
 }
 
+int eth_write_hwaddr(struct eth_device *dev, const char *base_name,
+                  int eth_number)
+{
+       unsigned char env_enetaddr[6];
+       int ret = 0;
+
+       if (!eth_getenv_enetaddr_by_index(base_name, eth_number, env_enetaddr))
+               return -1;
+
+       if (memcmp(env_enetaddr, "\0\0\0\0\0\0", 6)) {
+               if (memcmp(dev->enetaddr, "\0\0\0\0\0\0", 6) &&
+                       memcmp(dev->enetaddr, env_enetaddr, 6)) {
+                       printf("\nWarning: %s MAC addresses don't match:\n",
+                               dev->name);
+                       printf("Address in SROM is         %pM\n",
+                               dev->enetaddr);
+                       printf("Address in environment is  %pM\n",
+                               env_enetaddr);
+               }
+
+               memcpy(dev->enetaddr, env_enetaddr, 6);
+       }
+
+       if (dev->write_hwaddr &&
+               !eth_mac_skip(eth_number) &&
+               is_valid_ether_addr(dev->enetaddr)) {
+               ret = dev->write_hwaddr(dev);
+       }
+
+       return ret;
+}
+
 int eth_register(struct eth_device *dev)
 {
        struct eth_device *d;
@@ -208,7 +241,6 @@ int eth_register(struct eth_device *dev)
 
 int eth_initialize(bd_t *bis)
 {
-       unsigned char env_enetaddr[6];
        int eth_number = 0;
 
        eth_devices = NULL;
@@ -264,27 +296,8 @@ int eth_initialize(bd_t *bis)
                        if (strchr(dev->name, ' '))
                                puts("\nWarning: eth device name has a space!\n");
 
-                       eth_getenv_enetaddr_by_index(eth_number, env_enetaddr);
-
-                       if (memcmp(env_enetaddr, "\0\0\0\0\0\0", 6)) {
-                               if (memcmp(dev->enetaddr, "\0\0\0\0\0\0", 6) &&
-                                   memcmp(dev->enetaddr, env_enetaddr, 6))
-                               {
-                                       printf ("\nWarning: %s MAC addresses don't match:\n",
-                                               dev->name);
-                                       printf ("Address in SROM is         %pM\n",
-                                               dev->enetaddr);
-                                       printf ("Address in environment is  %pM\n",
-                                               env_enetaddr);
-                               }
-
-                               memcpy(dev->enetaddr, env_enetaddr, 6);
-                       }
-                       if (dev->write_hwaddr &&
-                               !eth_mac_skip(eth_number) &&
-                               is_valid_ether_addr(dev->enetaddr)) {
-                               dev->write_hwaddr(dev);
-                       }
+                       if (eth_write_hwaddr(dev, NULL, eth_number))
+                               puts("Warning: failed to set MAC address\n");
 
                        eth_number++;
                        dev = dev->next;
@@ -359,7 +372,8 @@ int eth_init(bd_t *bis)
        do {
                uchar env_enetaddr[6];
 
-               if (eth_getenv_enetaddr_by_index(eth_number, env_enetaddr))
+               if (eth_getenv_enetaddr_by_index("eth", eth_number,
+                                                env_enetaddr))
                        memcpy(dev->enetaddr, env_enetaddr, 6);
 
                ++eth_number;