]> git.sur5r.net Git - u-boot/commitdiff
Merge branch 'master' of git://git.denx.de/u-boot-net
authorTom Rini <trini@konsulko.com>
Thu, 28 Jan 2016 23:42:10 +0000 (18:42 -0500)
committerTom Rini <trini@konsulko.com>
Thu, 28 Jan 2016 23:42:10 +0000 (18:42 -0500)
33 files changed:
arch/arm/cpu/armv7/ls102xa/fdt.c
board/freescale/bsc9132qds/bsc9132qds.c
board/freescale/c29xpcie/c29xpcie.c
board/freescale/ls1021atwr/ls1021atwr.c
board/freescale/mpc8548cds/mpc8548cds.c
board/freescale/mpc8572ds/mpc8572ds.c
board/freescale/p1010rdb/p1010rdb.c
cmd/ethsw.c
doc/README.t1040-l2switch
doc/device-tree-bindings/net/fsl-tsec-phy.txt [new file with mode: 0644]
doc/device-tree-bindings/net/micrel-ksz90x1.txt [new file with mode: 0644]
drivers/net/designware.c
drivers/net/designware.h
drivers/net/fsl_mdio.c
drivers/net/phy/cortina.c
drivers/net/phy/micrel.c
drivers/net/phy/phy.c
drivers/net/tsec.c
drivers/net/vsc9953.c
drivers/pci/pci_tegra.c
include/ethsw.h
include/fsl_mdio.h
include/net.h
include/phy.h
include/tsec.h
include/vsc9953.h
net/Makefile
net/bootp.c
net/eth-uclass.c [new file with mode: 0644]
net/eth.c [deleted file]
net/eth_common.c [new file with mode: 0644]
net/eth_internal.h [new file with mode: 0644]
net/eth_legacy.c [new file with mode: 0644]

index 856abed94182ce741643a40bbe286bf613f97977..ae5e794230cd94d31a6eab68f15e85f6847cb61b 100644 (file)
@@ -30,17 +30,13 @@ void ft_fixup_enet_phy_connect_type(void *fdt)
        int phy_node;
        int i = 0;
        uint32_t ph;
+       char *name[3] = { "eTSEC1", "eTSEC2", "eTSEC3" };
 
-       while ((dev = eth_get_dev_by_index(i++)) != NULL) {
-               if (strstr(dev->name, "eTSEC1")) {
-                       strcpy(enet, "ethernet0");
-                       strcpy(phy, "enet0_rgmii_phy");
-               } else if (strstr(dev->name, "eTSEC2")) {
-                       strcpy(enet, "ethernet1");
-                       strcpy(phy, "enet1_rgmii_phy");
-               } else if (strstr(dev->name, "eTSEC3")) {
-                       strcpy(enet, "ethernet2");
-                       strcpy(phy, "enet2_rgmii_phy");
+       for (; i < ARRAY_SIZE(name); i++) {
+               dev = eth_get_dev_by_name(name[i]);
+               if (dev) {
+                       sprintf(enet, "ethernet%d", i);
+                       sprintf(phy, "enet%d_rgmii_phy", i);
                } else {
                        continue;
                }
index 586daccb4a0ba16c5a7b04fae1876d90328b5d66..71a7bb55c48a6e0d8e0c368810de65b9dceb15d6 100644 (file)
@@ -227,9 +227,9 @@ int checkboard(void)
        return 0;
 }
 
-#ifdef CONFIG_TSEC_ENET
 int board_eth_init(bd_t *bis)
 {
+#ifdef CONFIG_TSEC_ENET
        struct fsl_pq_mdio_info mdio_info;
        struct tsec_info_struct tsec_info[4];
        int num = 0;
@@ -250,6 +250,7 @@ int board_eth_init(bd_t *bis)
 
        fsl_pq_mdio_init(bis, &mdio_info);
        tsec_eth_init(bis, tsec_info, num);
+#endif
 
        #ifdef CONFIG_PCI
        pci_eth_init(bis);
@@ -257,7 +258,6 @@ int board_eth_init(bd_t *bis)
 
        return 0;
 }
-#endif
 
 #define USBMUX_SEL_MASK                0xc0
 #define USBMUX_SEL_UART2       0xc0
index f42d373dafbbb5f6fbb57239bec8a073e204c0e4..e325b4db4af9362fbe41dbedb24f07b00348a8af 100644 (file)
@@ -83,9 +83,9 @@ void pci_init_board(void)
 }
 #endif /* ifdef CONFIG_PCI */
 
-#ifdef CONFIG_TSEC_ENET
 int board_eth_init(bd_t *bis)
 {
+#ifdef CONFIG_TSEC_ENET
        struct fsl_pq_mdio_info mdio_info;
        struct tsec_info_struct tsec_info[2];
        int num = 0;
@@ -110,10 +110,10 @@ int board_eth_init(bd_t *bis)
        fsl_pq_mdio_init(bis, &mdio_info);
 
        tsec_eth_init(bis, tsec_info, num);
+#endif
 
        return pci_eth_init(bis);
 }
-#endif
 
 #if defined(CONFIG_OF_BOARD_SETUP)
 void fdt_del_sec(void *blob, int offset)
index b85774c4a4363aeec48095209a81910e218df75e..616e0bfd39c486996a860348122b565998c2318d 100644 (file)
@@ -244,9 +244,9 @@ int board_mmc_init(bd_t *bis)
 }
 #endif
 
-#ifdef CONFIG_TSEC_ENET
 int board_eth_init(bd_t *bis)
 {
+#ifdef CONFIG_TSEC_ENET
        struct fsl_pq_mdio_info mdio_info;
        struct tsec_info_struct tsec_info[4];
        int num = 0;
@@ -281,10 +281,10 @@ int board_eth_init(bd_t *bis)
        fsl_pq_mdio_init(bis, &mdio_info);
 
        tsec_eth_init(bis, tsec_info, num);
+#endif
 
        return pci_eth_init(bis);
 }
-#endif
 
 #if !defined(CONFIG_QSPI_BOOT) && !defined(CONFIG_SD_BOOT_QSPI)
 int config_serdes_mux(void)
index ca9b43c6b621ff3a18fcb8d39b9f9882cb6bf7fd..de76d36174a06a41d7812a4996aeecd1ea014732 100644 (file)
@@ -301,9 +301,9 @@ void configure_rgmii(void)
        return;
 }
 
-#ifdef CONFIG_TSEC_ENET
 int board_eth_init(bd_t *bis)
 {
+#ifdef CONFIG_TSEC_ENET
        struct fsl_pq_mdio_info mdio_info;
        struct tsec_info_struct tsec_info[4];
        int num = 0;
@@ -345,10 +345,10 @@ int board_eth_init(bd_t *bis)
 
        tsec_eth_init(bis, tsec_info, num);
        configure_rgmii();
+#endif
 
        return pci_eth_init(bis);
 }
-#endif
 
 #if defined(CONFIG_OF_BOARD_SETUP)
 void ft_pci_setup(void *blob, bd_t *bd)
index 3f68cf496a45487e3c0888cb5d8f78adf1876c20..ed6836a93027b8035d119d85db692f1e77403778 100644 (file)
@@ -171,9 +171,9 @@ int board_early_init_r(void)
        return 0;
 }
 
-#ifdef CONFIG_TSEC_ENET
 int board_eth_init(bd_t *bis)
 {
+#ifdef CONFIG_TSEC_ENET
        struct fsl_pq_mdio_info mdio_info;
        struct tsec_info_struct tsec_info[4];
        int num = 0;
@@ -226,10 +226,10 @@ int board_eth_init(bd_t *bis)
        fsl_pq_mdio_init(bis, &mdio_info);
 
        tsec_eth_init(bis, tsec_info, num);
+#endif
 
        return pci_eth_init(bis);
 }
-#endif
 
 #if defined(CONFIG_OF_BOARD_SETUP)
 int ft_board_setup(void *blob, bd_t *bd)
index ebffe9a58abca92ec8b0f145130792bbb5abd05e..1ae15407db4e9d4529a77c6fcbf7dc1af9204b8d 100644 (file)
@@ -326,9 +326,9 @@ int checkboard(void)
        return 0;
 }
 
-#ifdef CONFIG_TSEC_ENET
 int board_eth_init(bd_t *bis)
 {
+#ifdef CONFIG_TSEC_ENET
        struct fsl_pq_mdio_info mdio_info;
        struct tsec_info_struct tsec_info[4];
        struct cpu_type *cpu;
@@ -362,10 +362,10 @@ int board_eth_init(bd_t *bis)
        fsl_pq_mdio_init(bis, &mdio_info);
 
        tsec_eth_init(bis, tsec_info, num);
+#endif
 
        return pci_eth_init(bis);
 }
-#endif
 
 #if defined(CONFIG_OF_BOARD_SETUP)
 void fdt_del_flexcan(void *blob)
index 8e452e95be7101c0b1b41db3d719e64a21939b58..491cb8eac385ed8ecf44ab6a2f46ab6bf57a59f9 100644 (file)
@@ -71,7 +71,7 @@ static int ethsw_vlan_help_key_func(struct ethsw_command_def *parsed_cmd)
 
 #define ETHSW_PORT_UNTAG_HELP "ethsw [port <port_no>] untagged " \
 "{ [help] | show | all | none | pvid } " \
-" - set egress tagging mod for a port"
+" - set egress tagging mode for a port"
 
 static int ethsw_port_untag_help_key_func(struct ethsw_command_def *parsed_cmd)
 {
@@ -114,6 +114,17 @@ static int ethsw_ingr_fltr_help_key_func(struct ethsw_command_def *parsed_cmd)
        return CMD_RET_SUCCESS;
 }
 
+#define ETHSW_PORT_AGGR_HELP "ethsw [port <port_no>] aggr" \
+" { [help] | show | <lag_group_no> } " \
+"- get/set LAG group for a port"
+
+static int ethsw_port_aggr_help_key_func(struct ethsw_command_def *parsed_cmd)
+{
+       printf(ETHSW_PORT_AGGR_HELP"\n");
+
+       return CMD_RET_SUCCESS;
+}
+
 static struct keywords_to_function {
        enum ethsw_keyword_id cmd_keyword[ETHSW_MAX_CMD_PARAMS];
        int cmd_func_offset;
@@ -532,6 +543,39 @@ static struct keywords_to_function {
                        .cmd_func_offset = offsetof(struct ethsw_command_func,
                                                    port_ingr_filt_set),
                        .keyword_function = NULL,
+               }, {
+                       .cmd_keyword = {
+                                       ethsw_id_aggr,
+                                       ethsw_id_key_end,
+                       },
+                       .cmd_func_offset = -1,
+                       .keyword_function = &ethsw_port_aggr_help_key_func,
+               }, {
+                       .cmd_keyword = {
+                                       ethsw_id_aggr,
+                                       ethsw_id_help,
+                                       ethsw_id_key_end,
+                       },
+                       .cmd_func_offset = -1,
+                       .keyword_function = &ethsw_port_aggr_help_key_func,
+               }, {
+                       .cmd_keyword = {
+                                       ethsw_id_aggr,
+                                       ethsw_id_show,
+                                       ethsw_id_key_end,
+                       },
+                       .cmd_func_offset = offsetof(struct ethsw_command_func,
+                                                   port_aggr_show),
+                       .keyword_function = NULL,
+               }, {
+                       .cmd_keyword = {
+                                       ethsw_id_aggr,
+                                       ethsw_id_aggr_no,
+                                       ethsw_id_key_end,
+                       },
+                       .cmd_func_offset = offsetof(struct ethsw_command_func,
+                                                   port_aggr_set),
+                       .keyword_function = NULL,
                },
 };
 
@@ -576,6 +620,9 @@ static int keyword_match_pvid(enum ethsw_keyword_id key_id, int argc,
 static int keyword_match_mac_addr(enum ethsw_keyword_id key_id, int argc,
                                  char *const argv[], int *argc_nr,
                                  struct ethsw_command_def *parsed_cmd);
+static int keyword_match_aggr(enum ethsw_keyword_id key_id, int argc,
+                             char *const argv[], int *argc_nr,
+                             struct ethsw_command_def *parsed_cmd);
 
 /*
  * Define properties for each keyword;
@@ -661,6 +708,9 @@ struct keyword_def {
                }, {
                                .keyword_name = "filtering",
                                .match = &keyword_match_gen,
+               }, {
+                               .keyword_name = "aggr",
+                               .match = &keyword_match_aggr,
                },
 };
 
@@ -826,6 +876,28 @@ static int keyword_match_mac_addr(enum ethsw_keyword_id key_id, int argc,
        return 1;
 }
 
+/* Function used to match the command's aggregation number */
+static int keyword_match_aggr(enum ethsw_keyword_id key_id, int argc,
+                             char *const argv[], int *argc_nr,
+                             struct ethsw_command_def *parsed_cmd)
+{
+       unsigned long val;
+
+       if (!keyword_match_gen(key_id, argc, argv, argc_nr, parsed_cmd))
+               return 0;
+
+       if (*argc_nr + 1 >= argc)
+               return 1;
+
+       if (strict_strtoul(argv[*argc_nr + 1], 10, &val) != -EINVAL) {
+               parsed_cmd->aggr_grp = val;
+               (*argc_nr)++;
+               parsed_cmd->cmd_to_keywords[*argc_nr] = ethsw_id_aggr_no;
+       }
+
+       return 1;
+}
+
 /* Finds optional keywords and modifies *argc_va to skip them */
 static void cmd_keywords_opt_check(const struct ethsw_command_def *parsed_cmd,
                                   int *argc_val)
@@ -984,6 +1056,7 @@ static void command_def_init(struct ethsw_command_def *parsed_cmd)
 
        parsed_cmd->port = ETHSW_CMD_PORT_ALL;
        parsed_cmd->vid = ETHSW_CMD_VLAN_ALL;
+       parsed_cmd->aggr_grp = ETHSW_CMD_AGGR_GRP_NONE;
        parsed_cmd->cmd_function = NULL;
 
        /* We initialize the MAC address with the Broadcast address */
@@ -1010,7 +1083,7 @@ static int do_ethsw(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 }
 
 #define ETHSW_PORT_CONF_HELP "[port <port_no>] { enable | disable | show } " \
-"- enable/disable a port; show shows a port's configuration"
+"- enable/disable a port; show a port's configuration"
 
 U_BOOT_CMD(ethsw, ETHSW_MAX_CMD_PARAMS, 0, do_ethsw,
           "Ethernet l2 switch commands",
@@ -1024,4 +1097,5 @@ U_BOOT_CMD(ethsw, ETHSW_MAX_CMD_PARAMS, 0, do_ethsw,
           ETHSW_EGR_VLAN_TAG_HELP"\n"
           ETHSW_VLAN_FDB_HELP"\n"
           ETHSW_PORT_INGR_FLTR_HELP"\n"
+          ETHSW_PORT_AGGR_HELP"\n"
 );
index 14dbf31bf230eecb347120f7bbbbf352c4cd3c8b..6f03de239e6073d11e95858d84b58f0f7c4166ee 100644 (file)
@@ -24,16 +24,31 @@ Switch interfaces:
 Commands Overview:
 =============
 Commands supported
-       - enable/disable a port
-       - check a port's link speed, duplexity and status.
+       - enable/disable a port or show its configuration (speed, duplexity, status, etc.)
+       - port statistics
+       - MAC learning
+       - add/remove FDB entries
+       - Port-based VLAN
+       - Private/Shared VLAN learning
+       - VLAN ingress filtering
+       - Port LAG
 
 Commands syntax
-       ethsw port <port_nr> enable|disable             - enable/disable an l2 switch port
-       ethsw port <port_nr> show                       - show an l2 switch port's configuration
+ethsw [port <port_no>] { enable | disable | show } - enable/disable a port; show a port's configuration
+ethsw [port <port_no>] statistics { [help] | [clear] } - show an l2 switch port's statistics
+ethsw [port <port_no>] learning { [help] | show | auto | disable } - enable/disable/show learning configuration on a port
+ethsw [port <port_no>] [vlan <vid>] fdb { [help] | show | flush | { add | del } <mac> } - add/delete a mac entry in FDB; use show to see FDB entries;
+                                                                                         if [vlan <vid>] is missing, VID 1 will be used
+ethsw [port <port_no>] pvid { [help] | show | <pvid> } - set/show PVID (ingress and egress VLAN tagging) for a port
+ethsw [port <port_no>] vlan { [help] | show | add <vid> | del <vid> } - add a VLAN to a port (VLAN members)
+ethsw [port <port_no>] untagged { [help] | show | all | none | pvid } - set egress tagging mode for a port
+ethsw [port <port_no>] egress tag { [help] | show | pvid | classified } - configure VID source for egress tag.
+                                                                         Tag's VID could be the frame's classified VID or the PVID of the port
+ethsw vlan fdb { [help] | show | shared | private } - make VLAN learning shared or private
+ethsw [port <port_no>] ingress filtering { [help] | show | enable | disable } - enable/disable VLAN ingress filtering on port
+ethsw [port <port_no>] aggr { [help] | show | <lag_group_no> } - get/set LAG group for a port
 
-       port_nr=0..9; use "all" for all ports
-
-=> ethsw port all show
+=> ethsw show
     Port   Status     Link    Speed   Duplex
        0  enabled     down       10     half
        1  enabled     down       10     half
diff --git a/doc/device-tree-bindings/net/fsl-tsec-phy.txt b/doc/device-tree-bindings/net/fsl-tsec-phy.txt
new file mode 100644 (file)
index 0000000..c5bf48c
--- /dev/null
@@ -0,0 +1,64 @@
+* TSEC-compatible ethernet nodes
+
+Properties:
+
+  - compatible : Should be "fsl,tsec"
+  - reg : Offset and length of the register set for the device
+  - phy-handle : See ethernet.txt file in the same directory.
+  - phy-connection-type : See ethernet.txt file in the same directory. This
+    property is only really needed if the connection is of type "rgmii-id",
+    "rgmii-rxid" and "rgmii-txid" as all other connection types are detected
+    by hardware.
+
+Example:
+       ethernet@24000 {
+               compatible = "fsl,tsec";
+               reg = <0x24000 0x1000>;
+               phy-handle = <&phy0>;
+               phy-connection-type = "sgmii";
+       };
+
+Child nodes of the TSEC controller are typically the individual PHY devices
+connected via the MDIO bus (sometimes the MDIO bus controller is separate).
+
+* MDIO IO device
+
+The MDIO is a bus to which the PHY devices are connected.  For each
+device that exists on this bus, a PHY node should be created.
+
+Required properties:
+  - compatible : Should define the compatible device type for the
+    mdio. Currently supported string/device is "fsl,tsec-mdio".
+  - reg : Offset and length of the register set for the device
+
+Example:
+
+       mdio@24520 {
+               compatible = "fsl,tsec-mdio";
+               reg = <0x24520 0x20>;
+
+               ethernet-phy@0 {
+                       reg = <0>;
+               };
+       };
+
+* TBI Internal MDIO bus
+
+As of this writing, every tsec is associated with an internal TBI PHY.
+This PHY is accessed through the local MDIO bus.  These buses are defined
+similarly to the mdio buses.  The TBI PHYs underneath them are similar to
+normal PHYs, but the reg property is considered instructive, rather than
+descriptive.  The reg property should be chosen so it doesn't interfere
+with other PHYs on the bus.  The TBI PHYs are referred to by a "tbi-handle"
+property under the tsec node, which has a similar meaning of "phy-handle".
+
+Example:
+       ethernet@24000 {
+               phy-handle = <&tbi1>;
+       };
+
+       mdio@24520 {
+               tbi1: tbi-phy@1f {
+                       reg = <0x1f>;
+               };
+       };
diff --git a/doc/device-tree-bindings/net/micrel-ksz90x1.txt b/doc/device-tree-bindings/net/micrel-ksz90x1.txt
new file mode 100644 (file)
index 0000000..307f53f
--- /dev/null
@@ -0,0 +1,165 @@
+Micrel KSZ9021/KSZ9031 Gigabit Ethernet PHY
+
+Some boards require special tuning values, particularly when it comes to
+clock delays. You can specify clock delay values by adding
+micrel-specific properties to an Ethernet OF device node.
+
+Note that these settings are applied after any phy-specific fixup from
+phy_fixup_list (see phy_init_hw() from drivers/net/phy/phy_device.c),
+and therefore may overwrite them.
+
+KSZ9021:
+
+  All skew control options are specified in picoseconds. The minimum
+  value is 0, the maximum value is 1800, and it is incremented by 120ps
+  steps.
+
+  Optional properties:
+
+    - rxc-skew-ps : Skew control of RXC pad
+    - rxdv-skew-ps : Skew control of RX CTL pad
+    - txc-skew-ps : Skew control of TXC pad
+    - txen-skew-ps : Skew control of TX CTL pad
+    - rxd0-skew-ps : Skew control of RX data 0 pad
+    - rxd1-skew-ps : Skew control of RX data 1 pad
+    - rxd2-skew-ps : Skew control of RX data 2 pad
+    - rxd3-skew-ps : Skew control of RX data 3 pad
+    - txd0-skew-ps : Skew control of TX data 0 pad
+    - txd1-skew-ps : Skew control of TX data 1 pad
+    - txd2-skew-ps : Skew control of TX data 2 pad
+    - txd3-skew-ps : Skew control of TX data 3 pad
+
+KSZ9031:
+
+  All skew control options are specified in picoseconds. The minimum
+  value is 0, and the maximum is property-dependent. The increment
+  step is 60ps.
+
+  The KSZ9031 hardware supports a range of skew values from negative to
+  positive, where the specific range is property dependent. All values
+  specified in the devicetree are offset by the minimum value so they
+  can be represented as positive integers in the devicetree since it's
+  difficult to represent a negative number in the devictree.
+
+  The following 5-bit values table apply to rxc-skew-ps and txc-skew-ps.
+
+  Pad Skew Value       Delay (ps)      Devicetree Value
+  ------------------------------------------------------
+  0_0000               -900ps          0
+  0_0001               -840ps          60
+  0_0010               -780ps          120
+  0_0011               -720ps          180
+  0_0100               -660ps          240
+  0_0101               -600ps          300
+  0_0110               -540ps          360
+  0_0111               -480ps          420
+  0_1000               -420ps          480
+  0_1001               -360ps          540
+  0_1010               -300ps          600
+  0_1011               -240ps          660
+  0_1100               -180ps          720
+  0_1101               -120ps          780
+  0_1110               -60ps           840
+  0_1111               0ps             900
+  1_0000               60ps            960
+  1_0001               120ps           1020
+  1_0010               180ps           1080
+  1_0011               240ps           1140
+  1_0100               300ps           1200
+  1_0101               360ps           1260
+  1_0110               420ps           1320
+  1_0111               480ps           1380
+  1_1000               540ps           1440
+  1_1001               600ps           1500
+  1_1010               660ps           1560
+  1_1011               720ps           1620
+  1_1100               780ps           1680
+  1_1101               840ps           1740
+  1_1110               900ps           1800
+  1_1111               960ps           1860
+
+  The following 4-bit values table apply to the txdX-skew-ps, rxdX-skew-ps
+  data pads, and the rxdv-skew-ps, txen-skew-ps control pads.
+
+  Pad Skew Value       Delay (ps)      Devicetree Value
+  ------------------------------------------------------
+  0000                 -420ps          0
+  0001                 -360ps          60
+  0010                 -300ps          120
+  0011                 -240ps          180
+  0100                 -180ps          240
+  0101                 -120ps          300
+  0110                 -60ps           360
+  0111                 0ps             420
+  1000                 60ps            480
+  1001                 120ps           540
+  1010                 180ps           600
+  1011                 240ps           660
+  1100                 300ps           720
+  1101                 360ps           780
+  1110                 420ps           840
+  1111                 480ps           900
+
+  Optional properties:
+
+    Maximum value of 1860:
+
+      - rxc-skew-ps : Skew control of RX clock pad
+      - txc-skew-ps : Skew control of TX clock pad
+
+    Maximum value of 900:
+
+      - rxdv-skew-ps : Skew control of RX CTL pad
+      - txen-skew-ps : Skew control of TX CTL pad
+      - rxd0-skew-ps : Skew control of RX data 0 pad
+      - rxd1-skew-ps : Skew control of RX data 1 pad
+      - rxd2-skew-ps : Skew control of RX data 2 pad
+      - rxd3-skew-ps : Skew control of RX data 3 pad
+      - txd0-skew-ps : Skew control of TX data 0 pad
+      - txd1-skew-ps : Skew control of TX data 1 pad
+      - txd2-skew-ps : Skew control of TX data 2 pad
+      - txd3-skew-ps : Skew control of TX data 3 pad
+
+Examples:
+
+       /* Attach to an Ethernet device with autodetected PHY */
+       &enet {
+               rxc-skew-ps = <1800>;
+               rxdv-skew-ps = <0>;
+               txc-skew-ps = <1800>;
+               txen-skew-ps = <0>;
+               status = "okay";
+       };
+
+       /* Attach to an explicitly-specified PHY */
+       mdio {
+               phy0: ethernet-phy@0 {
+                       rxc-skew-ps = <1800>;
+                       rxdv-skew-ps = <0>;
+                       txc-skew-ps = <1800>;
+                       txen-skew-ps = <0>;
+                       reg = <0>;
+               };
+       };
+       ethernet@70000 {
+               status = "okay";
+               phy = <&phy0>;
+               phy-mode = "rgmii-id";
+       };
+
+References
+
+  Micrel ksz9021rl/rn Data Sheet, Revision 1.2. Dated 2/13/2014.
+  http://www.micrel.com/_PDF/Ethernet/datasheets/ksz9021rl-rn_ds.pdf
+
+  Micrel ksz9031rnx Data Sheet, Revision 2.1. Dated 11/20/2014.
+  http://www.micrel.com/_PDF/Ethernet/datasheets/KSZ9031RNX.pdf
+
+Notes:
+
+  Note that a previous version of the Micrel ksz9021rl/rn Data Sheet
+  was missing extended register 106 (transmit data pad skews), and
+  incorrectly specified the ps per step as 200ps/step instead of
+  120ps/step. The latest update to this document reflects the latest
+  revision of the Micrel specification even though usage in the kernel
+  still reflects that incorrect document.
index 68b6548309ef8b6a1a929de0b372f41656962a1f..77b98c94c04df5b0ee5708a14d8798aefff8f908 100644 (file)
@@ -196,6 +196,8 @@ static void dw_adjust_link(struct eth_mac_regs *mac_p,
 
        if (phydev->speed != 1000)
                conf |= MII_PORTSELECT;
+       else
+               conf &= ~MII_PORTSELECT;
 
        if (phydev->speed == 100)
                conf |= FES_100;
@@ -404,7 +406,7 @@ static int _dw_free_pkt(struct dw_eth_dev *priv)
 static int dw_phy_init(struct dw_eth_dev *priv, void *dev)
 {
        struct phy_device *phydev;
-       int mask = 0xffffffff;
+       int mask = 0xffffffff, ret;
 
 #ifdef CONFIG_PHY_ADDR
        mask = 1 << CONFIG_PHY_ADDR;
@@ -417,6 +419,11 @@ static int dw_phy_init(struct dw_eth_dev *priv, void *dev)
        phy_connect_dev(phydev, dev);
 
        phydev->supported &= PHY_GBIT_FEATURES;
+       if (priv->max_speed) {
+               ret = phy_set_supported(phydev, priv->max_speed);
+               if (ret)
+                       return ret;
+       }
        phydev->advertising = phydev->supported;
 
        priv->phydev = phydev;
@@ -599,6 +606,7 @@ static int designware_eth_probe(struct udevice *dev)
        priv->mac_regs_p = (struct eth_mac_regs *)iobase;
        priv->dma_regs_p = (struct eth_dma_regs *)(iobase + DW_DMA_BASE_OFFSET);
        priv->interface = pdata->phy_interface;
+       priv->max_speed = pdata->max_speed;
 
        dw_mdio_init(dev->name, priv->mac_regs_p);
        priv->bus = miiphy_get_dev_by_name(dev->name);
@@ -633,6 +641,7 @@ static int designware_eth_ofdata_to_platdata(struct udevice *dev)
 {
        struct eth_pdata *pdata = dev_get_platdata(dev);
        const char *phy_mode;
+       const fdt32_t *cell;
 
        pdata->iobase = dev_get_addr(dev);
        pdata->phy_interface = -1;
@@ -644,6 +653,11 @@ static int designware_eth_ofdata_to_platdata(struct udevice *dev)
                return -EINVAL;
        }
 
+       pdata->max_speed = 0;
+       cell = fdt_getprop(gd->fdt_blob, dev->of_offset, "max-speed", NULL);
+       if (cell)
+               pdata->max_speed = fdt32_to_cpu(*cell);
+
        return 0;
 }
 
index 4b9ec39cc82a05e0b33ecc85a8b914c85da01777..ed6344cc28f3cfdde713d27476be8abf2f8fb30b 100644 (file)
@@ -223,6 +223,7 @@ struct dw_eth_dev {
        char rxbuffs[RX_TOTAL_BUFSIZE] __aligned(ARCH_DMA_MINALIGN);
 
        u32 interface;
+       u32 max_speed;
        u32 tx_currdescnum;
        u32 rx_currdescnum;
 
index f48bbc312390aaa6846142271f033c25c1f84008..77b9739a244a1a92bd2a61d79ceb3e04850ebb3c 100644 (file)
@@ -5,6 +5,7 @@
  *
  * SPDX-License-Identifier:    GPL-2.0+
  */
+
 #include <common.h>
 #include <miiphy.h>
 #include <phy.h>
@@ -32,8 +33,7 @@ int tsec_local_mdio_read(struct tsec_mii_mng __iomem *phyregs, int port_addr,
        int value;
        int timeout = 1000000;
 
-       /* Put the address of the phy, and the register
-        * number into MIIMADD */
+       /* Put the address of the phy, and the register number into MIIMADD */
        out_be32(&phyregs->miimadd, (port_addr << 8) | (regnum & 0x1f));
 
        /* Clear the command register, and wait */
index 447ecfbeb6dfe9b378d3c7c5789f33a5518b38f9..f975fd82091ff6be3e3cd55d3539f53be49d58fe 100644 (file)
@@ -257,6 +257,12 @@ int cs4340_config(struct phy_device *phydev)
        return 0;
 }
 
+int cs4340_probe(struct phy_device *phydev)
+{
+       phydev->flags = PHY_FLAG_BROKEN_RESET;
+       return 0;
+}
+
 int cs4340_startup(struct phy_device *phydev)
 {
        phydev->link = 1;
@@ -276,6 +282,7 @@ struct phy_driver cs4340_driver = {
                 MDIO_DEVS_PHYXS | MDIO_DEVS_AN |
                 MDIO_DEVS_VEND1 | MDIO_DEVS_VEND2),
        .config = &cs4340_config,
+       .probe  = &cs4340_probe,
        .startup = &cs4340_startup,
        .shutdown = &gen10g_shutdown,
 };
index 19b6bc74727b0d07f0ce769189ca556f38d60ed7..c3da1606dc5e3adb837b2872d745ea820f4ce558 100644 (file)
@@ -27,12 +27,31 @@ static struct phy_driver KSZ804_driver = {
        .shutdown = &genphy_shutdown,
 };
 
+#define MII_KSZPHY_OMSO                0x16
+#define KSZPHY_OMSO_B_CAST_OFF (1 << 9)
+
+static int ksz_genconfig_bcastoff(struct phy_device *phydev)
+{
+       int ret;
+
+       ret = phy_read(phydev, MDIO_DEVAD_NONE, MII_KSZPHY_OMSO);
+       if (ret < 0)
+               return ret;
+
+       ret = phy_write(phydev, MDIO_DEVAD_NONE, MII_KSZPHY_OMSO,
+                       ret | KSZPHY_OMSO_B_CAST_OFF);
+       if (ret < 0)
+               return ret;
+
+       return genphy_config(phydev);
+}
+
 static struct phy_driver KSZ8031_driver = {
        .name = "Micrel KSZ8021/KSZ8031",
        .uid = 0x221550,
        .mask = 0xfffff0,
        .features = PHY_BASIC_FEATURES,
-       .config = &genphy_config,
+       .config = &ksz_genconfig_bcastoff,
        .startup = &genphy_startup,
        .shutdown = &genphy_shutdown,
 };
@@ -70,7 +89,7 @@ static struct phy_driver KSZ8081_driver = {
        .uid = 0x221560,
        .mask = 0xfffff0,
        .features = PHY_BASIC_FEATURES,
-       .config = &genphy_config,
+       .config = &ksz_genconfig_bcastoff,
        .startup = &genphy_startup,
        .shutdown = &genphy_shutdown,
 };
@@ -211,7 +230,7 @@ static int ksz90x1_of_config_group(struct phy_device *phydev,
 {
        struct udevice *dev = phydev->dev;
        struct phy_driver *drv = phydev->drv;
-       const int ps_to_regval = 200;
+       const int ps_to_regval = 60;
        int val[4];
        int i, changed = 0, offset, max;
        u16 regval = 0;
index 51b5746a5a49739c2b71e0a87e115b644f98b6e7..17866a244b3a9d8dbcb38c1f703bfc626f5f2b74 100644 (file)
@@ -38,16 +38,16 @@ DECLARE_GLOBAL_DATA_PTR;
 static int genphy_config_advert(struct phy_device *phydev)
 {
        u32 advertise;
-       int oldadv, adv;
+       int oldadv, adv, bmsr;
        int err, changed = 0;
 
-       /* Only allow advertising what
-        * this PHY supports */
+       /* Only allow advertising what this PHY supports */
        phydev->advertising &= phydev->supported;
        advertise = phydev->advertising;
 
        /* Setup standard advertisement */
-       oldadv = adv = phy_read(phydev, MDIO_DEVAD_NONE, MII_ADVERTISE);
+       adv = phy_read(phydev, MDIO_DEVAD_NONE, MII_ADVERTISE);
+       oldadv = adv;
 
        if (adv < 0)
                return adv;
@@ -79,29 +79,40 @@ static int genphy_config_advert(struct phy_device *phydev)
                changed = 1;
        }
 
+       bmsr = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMSR);
+       if (bmsr < 0)
+               return bmsr;
+
+       /* Per 802.3-2008, Section 22.2.4.2.16 Extended status all
+        * 1000Mbits/sec capable PHYs shall have the BMSR_ESTATEN bit set to a
+        * logical 1.
+        */
+       if (!(bmsr & BMSR_ESTATEN))
+               return changed;
+
        /* Configure gigabit if it's supported */
-       if (phydev->supported & (SUPPORTED_1000baseT_Half |
-                               SUPPORTED_1000baseT_Full)) {
-               oldadv = adv = phy_read(phydev, MDIO_DEVAD_NONE, MII_CTRL1000);
+       adv = phy_read(phydev, MDIO_DEVAD_NONE, MII_CTRL1000);
+       oldadv = adv;
+
+       if (adv < 0)
+               return adv;
 
-               if (adv < 0)
-                       return adv;
+       adv &= ~(ADVERTISE_1000FULL | ADVERTISE_1000HALF);
 
-               adv &= ~(ADVERTISE_1000FULL | ADVERTISE_1000HALF);
+       if (phydev->supported & (SUPPORTED_1000baseT_Half |
+                               SUPPORTED_1000baseT_Full)) {
                if (advertise & SUPPORTED_1000baseT_Half)
                        adv |= ADVERTISE_1000HALF;
                if (advertise & SUPPORTED_1000baseT_Full)
                        adv |= ADVERTISE_1000FULL;
+       }
 
-               if (adv != oldadv) {
-                       err = phy_write(phydev, MDIO_DEVAD_NONE, MII_CTRL1000,
-                                       adv);
+       if (adv != oldadv)
+               changed = 1;
 
-                       if (err < 0)
-                               return err;
-                       changed = 1;
-               }
-       }
+       err = phy_write(phydev, MDIO_DEVAD_NONE, MII_CTRL1000, adv);
+       if (err < 0)
+               return err;
 
        return changed;
 }
@@ -117,7 +128,7 @@ static int genphy_config_advert(struct phy_device *phydev)
 static int genphy_setup_forced(struct phy_device *phydev)
 {
        int err;
-       int ctl = 0;
+       int ctl = BMCR_ANRESTART;
 
        phydev->pause = phydev->asym_pause = 0;
 
@@ -224,7 +235,8 @@ int genphy_update_link(struct phy_device *phydev)
        if (phydev->link && mii_reg & BMSR_LSTATUS)
                return 0;
 
-       if ((mii_reg & BMSR_ANEGCAPABLE) && !(mii_reg & BMSR_ANEGCOMPLETE)) {
+       if ((phydev->autoneg == AUTONEG_ENABLE) &&
+           !(mii_reg & BMSR_ANEGCOMPLETE)) {
                int i = 0;
 
                printf("%s Waiting for PHY auto negotiation to complete",
@@ -280,7 +292,7 @@ int genphy_parse_link(struct phy_device *phydev)
        int mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMSR);
 
        /* We're using autonegotiation */
-       if (phydev->supported & SUPPORTED_Autoneg) {
+       if (phydev->autoneg == AUTONEG_ENABLE) {
                u32 lpa = 0;
                int gblpa = 0;
                u32 estatus = 0;
@@ -371,8 +383,6 @@ int genphy_config(struct phy_device *phydev)
        int val;
        u32 features;
 
-       /* For now, I'll claim that the generic driver supports
-        * all possible port types */
        features = (SUPPORTED_TP | SUPPORTED_MII
                        | SUPPORTED_AUI | SUPPORTED_FIBRE |
                        SUPPORTED_BNC);
@@ -411,8 +421,8 @@ int genphy_config(struct phy_device *phydev)
                        features |= SUPPORTED_1000baseX_Half;
        }
 
-       phydev->supported = features;
-       phydev->advertising = features;
+       phydev->supported &= features;
+       phydev->advertising &= features;
 
        genphy_config_aneg(phydev);
 
@@ -436,7 +446,9 @@ static struct phy_driver genphy_driver = {
        .uid            = 0xffffffff,
        .mask           = 0xffffffff,
        .name           = "Generic PHY",
-       .features       = 0,
+       .features       = PHY_GBIT_FEATURES | SUPPORTED_MII |
+                         SUPPORTED_AUI | SUPPORTED_FIBRE |
+                         SUPPORTED_BNC,
        .config         = genphy_config,
        .startup        = genphy_startup,
        .shutdown       = genphy_shutdown,
@@ -517,6 +529,30 @@ int phy_register(struct phy_driver *drv)
        return 0;
 }
 
+int phy_set_supported(struct phy_device *phydev, u32 max_speed)
+{
+       /* The default values for phydev->supported are provided by the PHY
+        * driver "features" member, we want to reset to sane defaults first
+        * before supporting higher speeds.
+        */
+       phydev->supported &= PHY_DEFAULT_FEATURES;
+
+       switch (max_speed) {
+       default:
+               return -ENOTSUPP;
+       case SPEED_1000:
+               phydev->supported |= PHY_1000BT_FEATURES;
+               /* fall through */
+       case SPEED_100:
+               phydev->supported |= PHY_100BT_FEATURES;
+               /* fall through */
+       case SPEED_10:
+               phydev->supported |= PHY_10BT_FEATURES;
+       }
+
+       return 0;
+}
+
 static int phy_probe(struct phy_device *phydev)
 {
        int err = 0;
@@ -707,6 +743,9 @@ int phy_reset(struct phy_device *phydev)
        int timeout = 500;
        int devad = MDIO_DEVAD_NONE;
 
+       if (phydev->flags & PHY_FLAG_BROKEN_RESET)
+               return 0;
+
 #ifdef CONFIG_PHYLIB_10G
        /* If it's 10G, we need to issue reset through one of the MMDs */
        if (is_10g_interface(phydev->interface)) {
@@ -717,15 +756,7 @@ int phy_reset(struct phy_device *phydev)
        }
 #endif
 
-       reg = phy_read(phydev, devad, MII_BMCR);
-       if (reg < 0) {
-               debug("PHY status read failed\n");
-               return -1;
-       }
-
-       reg |= BMCR_RESET;
-
-       if (phy_write(phydev, devad, MII_BMCR, reg) < 0) {
+       if (phy_write(phydev, devad, MII_BMCR, BMCR_RESET) < 0) {
                debug("PHY reset failed\n");
                return -1;
        }
@@ -738,6 +769,7 @@ int phy_reset(struct phy_device *phydev)
         * auto-clearing).  This should happen within 0.5 seconds per the
         * IEEE spec.
         */
+       reg = phy_read(phydev, devad, MII_BMCR);
        while ((reg & BMCR_RESET) && timeout--) {
                reg = phy_read(phydev, devad, MII_BMCR);
 
index 9b09caf8c8322cce6254c01b4211bf2fe3ea76d2..be0f38288f3dd1806c86dc6f2da87cf676df3dd0 100644 (file)
@@ -1,18 +1,16 @@
 /*
  * Freescale Three Speed Ethernet Controller driver
  *
- * This software may be used and distributed according to the
- * terms of the GNU Public License, Version 2, incorporated
- * herein by reference.
- *
  * Copyright 2004-2011, 2013 Freescale Semiconductor, Inc.
  * (C) Copyright 2003, Motorola, Inc.
  * author Andy Fleming
  *
+ * SPDX-License-Identifier:    GPL-2.0+
  */
 
 #include <config.h>
 #include <common.h>
+#include <dm.h>
 #include <malloc.h>
 #include <net.h>
 #include <command.h>
 
 DECLARE_GLOBAL_DATA_PTR;
 
-#define TX_BUF_CNT             2
-
-static uint rx_idx;            /* index of the current RX buffer */
-static uint tx_idx;            /* index of the current TX buffer */
-
-#ifdef __GNUC__
-static struct txbd8 __iomem txbd[TX_BUF_CNT] __aligned(8);
-static struct rxbd8 __iomem rxbd[PKTBUFSRX] __aligned(8);
-
-#else
-#error "rtx must be 64-bit aligned"
-#endif
-
-static int tsec_send(struct eth_device *dev, void *packet, int length);
-
+#ifndef CONFIG_DM_ETH
 /* Default initializations for TSEC controllers. */
 
 static struct tsec_info_struct tsec_info[] = {
@@ -64,6 +48,7 @@ static struct tsec_info_struct tsec_info[] = {
        STD_TSEC_INFO(4),       /* TSEC4 */
 #endif
 };
+#endif /* CONFIG_DM_ETH */
 
 #define TBIANA_SETTINGS ( \
                TBIANA_ASYMMETRIC_PAUSE \
@@ -84,8 +69,10 @@ static struct tsec_info_struct tsec_info[] = {
 /* Configure the TBI for SGMII operation */
 static void tsec_configure_serdes(struct tsec_private *priv)
 {
-       /* Access TBI PHY registers at given TSEC register offset as opposed
-        * to the register offset used for external PHY accesses */
+       /*
+        * Access TBI PHY registers at given TSEC register offset as opposed
+        * to the register offset used for external PHY accesses
+        */
        tsec_local_mdio_write(priv->phyregs_sgmii, in_be32(&priv->regs->tbipa),
                        0, TBI_ANA, TBIANA_SETTINGS);
        tsec_local_mdio_write(priv->phyregs_sgmii, in_be32(&priv->regs->tbipa),
@@ -100,7 +87,8 @@ static void tsec_configure_serdes(struct tsec_private *priv)
 
 /* Set the appropriate hash bit for the given addr */
 
-/* The algorithm works like so:
+/*
+ * The algorithm works like so:
  * 1) Take the Destination Address (ie the multicast address), and
  * do a CRC on it (little endian), and reverse the bits of the
  * result.
@@ -111,9 +99,13 @@ static void tsec_configure_serdes(struct tsec_private *priv)
  * hash index which gaddr register to use, and the 5 other bits
  * indicate which bit (assuming an IBM numbering scheme, which
  * for PowerPC (tm) is usually the case) in the register holds
- * the entry. */
-static int
-tsec_mcast_addr(struct eth_device *dev, const u8 *mcast_mac, u8 set)
+ * the entry.
+ */
+#ifndef CONFIG_DM_ETH
+static int tsec_mcast_addr(struct eth_device *dev, const u8 *mcast_mac, u8 set)
+#else
+static int tsec_mcast_addr(struct udevice *dev, const u8 *mcast_mac, int set)
+#endif
 {
        struct tsec_private *priv = (struct tsec_private *)dev->priv;
        struct tsec __iomem *regs = priv->regs;
@@ -135,7 +127,8 @@ tsec_mcast_addr(struct eth_device *dev, const u8 *mcast_mac, u8 set)
 }
 #endif /* Multicast TFTP ? */
 
-/* Initialized required registers to appropriate values, zeroing
+/*
+ * Initialized required registers to appropriate values, zeroing
  * those we don't care about (unless zero is bad, in which case,
  * choose a more appropriate value)
  */
@@ -181,7 +174,8 @@ static void init_registers(struct tsec __iomem *regs)
 
 }
 
-/* Configure maccfg2 based on negotiated speed and duplex
+/*
+ * Configure maccfg2 based on negotiated speed and duplex
  * reported by PHY handling code
  */
 static void adjust_link(struct tsec_private *priv, struct phy_device *phydev)
@@ -212,7 +206,8 @@ static void adjust_link(struct tsec_private *priv, struct phy_device *phydev)
        case 10:
                maccfg2 |= MACCFG2_MII;
 
-               /* Set R100 bit in all modes although
+               /*
+                * Set R100 bit in all modes although
                 * it is only used in RGMII mode
                 */
                if (phydev->speed == 100)
@@ -231,15 +226,174 @@ static void adjust_link(struct tsec_private *priv, struct phy_device *phydev)
                        (phydev->port == PORT_FIBRE) ? ", fiber mode" : "");
 }
 
+/*
+ * This returns the status bits of the device. The return value
+ * is never checked, and this is what the 8260 driver did, so we
+ * do the same. Presumably, this would be zero if there were no
+ * errors
+ */
+#ifndef CONFIG_DM_ETH
+static int tsec_send(struct eth_device *dev, void *packet, int length)
+#else
+static int tsec_send(struct udevice *dev, void *packet, int length)
+#endif
+{
+       struct tsec_private *priv = (struct tsec_private *)dev->priv;
+       struct tsec __iomem *regs = priv->regs;
+       uint16_t status;
+       int result = 0;
+       int i;
+
+       /* Find an empty buffer descriptor */
+       for (i = 0;
+            in_be16(&priv->txbd[priv->tx_idx].status) & TXBD_READY;
+            i++) {
+               if (i >= TOUT_LOOP) {
+                       debug("%s: tsec: tx buffers full\n", dev->name);
+                       return result;
+               }
+       }
+
+       out_be32(&priv->txbd[priv->tx_idx].bufptr, (u32)packet);
+       out_be16(&priv->txbd[priv->tx_idx].length, length);
+       status = in_be16(&priv->txbd[priv->tx_idx].status);
+       out_be16(&priv->txbd[priv->tx_idx].status, status |
+               (TXBD_READY | TXBD_LAST | TXBD_CRC | TXBD_INTERRUPT));
+
+       /* Tell the DMA to go */
+       out_be32(&regs->tstat, TSTAT_CLEAR_THALT);
+
+       /* Wait for buffer to be transmitted */
+       for (i = 0;
+            in_be16(&priv->txbd[priv->tx_idx].status) & TXBD_READY;
+            i++) {
+               if (i >= TOUT_LOOP) {
+                       debug("%s: tsec: tx error\n", dev->name);
+                       return result;
+               }
+       }
+
+       priv->tx_idx = (priv->tx_idx + 1) % TX_BUF_CNT;
+       result = in_be16(&priv->txbd[priv->tx_idx].status) & TXBD_STATS;
+
+       return result;
+}
+
+#ifndef CONFIG_DM_ETH
+static int tsec_recv(struct eth_device *dev)
+{
+       struct tsec_private *priv = (struct tsec_private *)dev->priv;
+       struct tsec __iomem *regs = priv->regs;
+
+       while (!(in_be16(&priv->rxbd[priv->rx_idx].status) & RXBD_EMPTY)) {
+               int length = in_be16(&priv->rxbd[priv->rx_idx].length);
+               uint16_t status = in_be16(&priv->rxbd[priv->rx_idx].status);
+               uchar *packet = net_rx_packets[priv->rx_idx];
+
+               /* Send the packet up if there were no errors */
+               if (!(status & RXBD_STATS))
+                       net_process_received_packet(packet, length - 4);
+               else
+                       printf("Got error %x\n", (status & RXBD_STATS));
+
+               out_be16(&priv->rxbd[priv->rx_idx].length, 0);
+
+               status = RXBD_EMPTY;
+               /* Set the wrap bit if this is the last element in the list */
+               if ((priv->rx_idx + 1) == PKTBUFSRX)
+                       status |= RXBD_WRAP;
+               out_be16(&priv->rxbd[priv->rx_idx].status, status);
+
+               priv->rx_idx = (priv->rx_idx + 1) % PKTBUFSRX;
+       }
+
+       if (in_be32(&regs->ievent) & IEVENT_BSY) {
+               out_be32(&regs->ievent, IEVENT_BSY);
+               out_be32(&regs->rstat, RSTAT_CLEAR_RHALT);
+       }
+
+       return -1;
+}
+#else
+static int tsec_recv(struct udevice *dev, int flags, uchar **packetp)
+{
+       struct tsec_private *priv = (struct tsec_private *)dev->priv;
+       struct tsec __iomem *regs = priv->regs;
+       int ret = -1;
+
+       if (!(in_be16(&priv->rxbd[priv->rx_idx].status) & RXBD_EMPTY)) {
+               int length = in_be16(&priv->rxbd[priv->rx_idx].length);
+               uint16_t status = in_be16(&priv->rxbd[priv->rx_idx].status);
+               uint32_t buf;
+
+               /* Send the packet up if there were no errors */
+               if (!(status & RXBD_STATS)) {
+                       buf = in_be32(&priv->rxbd[priv->rx_idx].bufptr);
+                       *packetp = (uchar *)buf;
+                       ret = length - 4;
+               } else {
+                       printf("Got error %x\n", (status & RXBD_STATS));
+               }
+       }
+
+       if (in_be32(&regs->ievent) & IEVENT_BSY) {
+               out_be32(&regs->ievent, IEVENT_BSY);
+               out_be32(&regs->rstat, RSTAT_CLEAR_RHALT);
+       }
+
+       return ret;
+}
+
+static int tsec_free_pkt(struct udevice *dev, uchar *packet, int length)
+{
+       struct tsec_private *priv = (struct tsec_private *)dev->priv;
+       uint16_t status;
+
+       out_be16(&priv->rxbd[priv->rx_idx].length, 0);
+
+       status = RXBD_EMPTY;
+       /* Set the wrap bit if this is the last element in the list */
+       if ((priv->rx_idx + 1) == PKTBUFSRX)
+               status |= RXBD_WRAP;
+       out_be16(&priv->rxbd[priv->rx_idx].status, status);
+
+       priv->rx_idx = (priv->rx_idx + 1) % PKTBUFSRX;
+
+       return 0;
+}
+#endif
+
+/* Stop the interface */
+#ifndef CONFIG_DM_ETH
+static void tsec_halt(struct eth_device *dev)
+#else
+static void tsec_halt(struct udevice *dev)
+#endif
+{
+       struct tsec_private *priv = (struct tsec_private *)dev->priv;
+       struct tsec __iomem *regs = priv->regs;
+
+       clrbits_be32(&regs->dmactrl, DMACTRL_GRS | DMACTRL_GTS);
+       setbits_be32(&regs->dmactrl, DMACTRL_GRS | DMACTRL_GTS);
+
+       while ((in_be32(&regs->ievent) & (IEVENT_GRSC | IEVENT_GTSC))
+                       != (IEVENT_GRSC | IEVENT_GTSC))
+               ;
+
+       clrbits_be32(&regs->maccfg1, MACCFG1_TX_EN | MACCFG1_RX_EN);
+
+       /* Shut down the PHY, as needed */
+       phy_shutdown(priv->phydev);
+}
+
 #ifdef CONFIG_SYS_FSL_ERRATUM_NMG_ETSEC129
 /*
  * When MACCFG1[Rx_EN] is enabled during system boot as part
  * of the eTSEC port initialization sequence,
  * the eTSEC Rx logic may not be properly initialized.
  */
-void redundant_init(struct eth_device *dev)
+void redundant_init(struct tsec_private *priv)
 {
-       struct tsec_private *priv = dev->priv;
        struct tsec __iomem *regs = priv->regs;
        uint t, count = 0;
        int fail = 1;
@@ -274,25 +428,27 @@ void redundant_init(struct eth_device *dev)
 
        do {
                uint16_t status;
-               tsec_send(dev, (void *)pkt, sizeof(pkt));
+               tsec_send(priv->dev, (void *)pkt, sizeof(pkt));
 
                /* Wait for buffer to be received */
-               for (t = 0; in_be16(&rxbd[rx_idx].status) & RXBD_EMPTY; t++) {
+               for (t = 0;
+                    in_be16(&priv->rxbd[priv->rx_idx].status) & RXBD_EMPTY;
+                    t++) {
                        if (t >= 10 * TOUT_LOOP) {
-                               printf("%s: tsec: rx error\n", dev->name);
+                               printf("%s: tsec: rx error\n", priv->dev->name);
                                break;
                        }
                }
 
-               if (!memcmp(pkt, (void *)net_rx_packets[rx_idx], sizeof(pkt)))
+               if (!memcmp(pkt, net_rx_packets[priv->rx_idx], sizeof(pkt)))
                        fail = 0;
 
-               out_be16(&rxbd[rx_idx].length, 0);
+               out_be16(&priv->rxbd[priv->rx_idx].length, 0);
                status = RXBD_EMPTY;
-               if ((rx_idx + 1) == PKTBUFSRX)
+               if ((priv->rx_idx + 1) == PKTBUFSRX)
                        status |= RXBD_WRAP;
-               out_be16(&rxbd[rx_idx].status, status);
-               rx_idx = (rx_idx + 1) % PKTBUFSRX;
+               out_be16(&priv->rxbd[priv->rx_idx].status, status);
+               priv->rx_idx = (priv->rx_idx + 1) % PKTBUFSRX;
 
                if (in_be32(&regs->ievent) & IEVENT_BSY) {
                        out_be32(&regs->ievent, IEVENT_BSY);
@@ -315,49 +471,49 @@ void redundant_init(struct eth_device *dev)
 }
 #endif
 
-/* Set up the buffers and their descriptors, and bring up the
+/*
+ * Set up the buffers and their descriptors, and bring up the
  * interface
  */
-static void startup_tsec(struct eth_device *dev)
+static void startup_tsec(struct tsec_private *priv)
 {
-       struct tsec_private *priv = (struct tsec_private *)dev->priv;
        struct tsec __iomem *regs = priv->regs;
        uint16_t status;
        int i;
 
        /* reset the indices to zero */
-       rx_idx = 0;
-       tx_idx = 0;
+       priv->rx_idx = 0;
+       priv->tx_idx = 0;
 #ifdef CONFIG_SYS_FSL_ERRATUM_NMG_ETSEC129
        uint svr;
 #endif
 
        /* Point to the buffer descriptors */
-       out_be32(&regs->tbase, (u32)&txbd[0]);
-       out_be32(&regs->rbase, (u32)&rxbd[0]);
+       out_be32(&regs->tbase, (u32)&priv->txbd[0]);
+       out_be32(&regs->rbase, (u32)&priv->rxbd[0]);
 
        /* Initialize the Rx Buffer descriptors */
        for (i = 0; i < PKTBUFSRX; i++) {
-               out_be16(&rxbd[i].status, RXBD_EMPTY);
-               out_be16(&rxbd[i].length, 0);
-               out_be32(&rxbd[i].bufptr, (u32)net_rx_packets[i]);
+               out_be16(&priv->rxbd[i].status, RXBD_EMPTY);
+               out_be16(&priv->rxbd[i].length, 0);
+               out_be32(&priv->rxbd[i].bufptr, (u32)net_rx_packets[i]);
        }
-       status = in_be16(&rxbd[PKTBUFSRX - 1].status);
-       out_be16(&rxbd[PKTBUFSRX - 1].status, status | RXBD_WRAP);
+       status = in_be16(&priv->rxbd[PKTBUFSRX - 1].status);
+       out_be16(&priv->rxbd[PKTBUFSRX - 1].status, status | RXBD_WRAP);
 
        /* Initialize the TX Buffer Descriptors */
        for (i = 0; i < TX_BUF_CNT; i++) {
-               out_be16(&txbd[i].status, 0);
-               out_be16(&txbd[i].length, 0);
-               out_be32(&txbd[i].bufptr, 0);
+               out_be16(&priv->txbd[i].status, 0);
+               out_be16(&priv->txbd[i].length, 0);
+               out_be32(&priv->txbd[i].bufptr, 0);
        }
-       status = in_be16(&txbd[TX_BUF_CNT - 1].status);
-       out_be16(&txbd[TX_BUF_CNT - 1].status, status | TXBD_WRAP);
+       status = in_be16(&priv->txbd[TX_BUF_CNT - 1].status);
+       out_be16(&priv->txbd[TX_BUF_CNT - 1].status, status | TXBD_WRAP);
 
 #ifdef CONFIG_SYS_FSL_ERRATUM_NMG_ETSEC129
        svr = get_svr();
        if ((SVR_MAJ(svr) == 1) || IS_SVR_REV(svr, 2, 0))
-               redundant_init(dev);
+               redundant_init(priv);
 #endif
        /* Enable Transmit and Receive */
        setbits_be32(&regs->maccfg1, MACCFG1_RX_EN | MACCFG1_TX_EN);
@@ -369,113 +525,22 @@ static void startup_tsec(struct eth_device *dev)
        clrbits_be32(&regs->dmactrl, DMACTRL_GRS | DMACTRL_GTS);
 }
 
-/* This returns the status bits of the device. The return value
- * is never checked, and this is what the 8260 driver did, so we
- * do the same.         Presumably, this would be zero if there were no
- * errors
- */
-static int tsec_send(struct eth_device *dev, void *packet, int length)
-{
-       struct tsec_private *priv = (struct tsec_private *)dev->priv;
-       struct tsec __iomem *regs = priv->regs;
-       uint16_t status;
-       int result = 0;
-       int i;
-
-       /* Find an empty buffer descriptor */
-       for (i = 0; in_be16(&txbd[tx_idx].status) & TXBD_READY; i++) {
-               if (i >= TOUT_LOOP) {
-                       debug("%s: tsec: tx buffers full\n", dev->name);
-                       return result;
-               }
-       }
-
-       out_be32(&txbd[tx_idx].bufptr, (u32)packet);
-       out_be16(&txbd[tx_idx].length, length);
-       status = in_be16(&txbd[tx_idx].status);
-       out_be16(&txbd[tx_idx].status, status |
-               (TXBD_READY | TXBD_LAST | TXBD_CRC | TXBD_INTERRUPT));
-
-       /* Tell the DMA to go */
-       out_be32(&regs->tstat, TSTAT_CLEAR_THALT);
-
-       /* Wait for buffer to be transmitted */
-       for (i = 0; in_be16(&txbd[tx_idx].status) & TXBD_READY; i++) {
-               if (i >= TOUT_LOOP) {
-                       debug("%s: tsec: tx error\n", dev->name);
-                       return result;
-               }
-       }
-
-       tx_idx = (tx_idx + 1) % TX_BUF_CNT;
-       result = in_be16(&txbd[tx_idx].status) & TXBD_STATS;
-
-       return result;
-}
-
-static int tsec_recv(struct eth_device *dev)
-{
-       struct tsec_private *priv = (struct tsec_private *)dev->priv;
-       struct tsec __iomem *regs = priv->regs;
-
-       while (!(in_be16(&rxbd[rx_idx].status) & RXBD_EMPTY)) {
-               int length = in_be16(&rxbd[rx_idx].length);
-               uint16_t status = in_be16(&rxbd[rx_idx].status);
-
-               /* Send the packet up if there were no errors */
-               if (!(status & RXBD_STATS))
-                       net_process_received_packet(net_rx_packets[rx_idx],
-                                                   length - 4);
-               else
-                       printf("Got error %x\n", (status & RXBD_STATS));
-
-               out_be16(&rxbd[rx_idx].length, 0);
-
-               status = RXBD_EMPTY;
-               /* Set the wrap bit if this is the last element in the list */
-               if ((rx_idx + 1) == PKTBUFSRX)
-                       status |= RXBD_WRAP;
-               out_be16(&rxbd[rx_idx].status, status);
-
-               rx_idx = (rx_idx + 1) % PKTBUFSRX;
-       }
-
-       if (in_be32(&regs->ievent) & IEVENT_BSY) {
-               out_be32(&regs->ievent, IEVENT_BSY);
-               out_be32(&regs->rstat, RSTAT_CLEAR_RHALT);
-       }
-
-       return -1;
-
-}
-
-/* Stop the interface */
-static void tsec_halt(struct eth_device *dev)
-{
-       struct tsec_private *priv = (struct tsec_private *)dev->priv;
-       struct tsec __iomem *regs = priv->regs;
-
-       clrbits_be32(&regs->dmactrl, DMACTRL_GRS | DMACTRL_GTS);
-       setbits_be32(&regs->dmactrl, DMACTRL_GRS | DMACTRL_GTS);
-
-       while ((in_be32(&regs->ievent) & (IEVENT_GRSC | IEVENT_GTSC))
-                       != (IEVENT_GRSC | IEVENT_GTSC))
-               ;
-
-       clrbits_be32(&regs->maccfg1, MACCFG1_TX_EN | MACCFG1_RX_EN);
-
-       /* Shut down the PHY, as needed */
-       phy_shutdown(priv->phydev);
-}
-
-/* Initializes data structures and registers for the controller,
- * and brings the interface up.         Returns the link status, meaning
+/*
+ * Initializes data structures and registers for the controller,
+ * and brings the interface up. Returns the link status, meaning
  * that it returns success if the link is up, failure otherwise.
- * This allows u-boot to find the first active controller.
+ * This allows U-Boot to find the first active controller.
  */
+#ifndef CONFIG_DM_ETH
 static int tsec_init(struct eth_device *dev, bd_t * bd)
+#else
+static int tsec_init(struct udevice *dev)
+#endif
 {
        struct tsec_private *priv = (struct tsec_private *)dev->priv;
+#ifdef CONFIG_DM_ETH
+       struct eth_pdata *pdata = dev_get_platdata(dev);
+#endif
        struct tsec __iomem *regs = priv->regs;
        u32 tempval;
        int ret;
@@ -489,17 +554,27 @@ static int tsec_init(struct eth_device *dev, bd_t * bd)
        /* Init ECNTRL */
        out_be32(&regs->ecntrl, ECNTRL_INIT_SETTINGS);
 
-       /* Copy the station address into the address registers.
+       /*
+        * Copy the station address into the address registers.
         * For a station address of 0x12345678ABCD in transmission
         * order (BE), MACnADDR1 is set to 0xCDAB7856 and
         * MACnADDR2 is set to 0x34120000.
         */
+#ifndef CONFIG_DM_ETH
        tempval = (dev->enetaddr[5] << 24) | (dev->enetaddr[4] << 16) |
                  (dev->enetaddr[3] << 8)  |  dev->enetaddr[2];
+#else
+       tempval = (pdata->enetaddr[5] << 24) | (pdata->enetaddr[4] << 16) |
+                 (pdata->enetaddr[3] << 8)  |  pdata->enetaddr[2];
+#endif
 
        out_be32(&regs->macstnaddr1, tempval);
 
+#ifndef CONFIG_DM_ETH
        tempval = (dev->enetaddr[1] << 24) | (dev->enetaddr[0] << 16);
+#else
+       tempval = (pdata->enetaddr[1] << 24) | (pdata->enetaddr[0] << 16);
+#endif
 
        out_be32(&regs->macstnaddr2, tempval);
 
@@ -507,7 +582,7 @@ static int tsec_init(struct eth_device *dev, bd_t * bd)
        init_registers(regs);
 
        /* Ready the device for tx/rx */
-       startup_tsec(dev);
+       startup_tsec(priv);
 
        /* Start up the PHY */
        ret = phy_startup(priv->phydev);
@@ -551,8 +626,8 @@ static phy_interface_t tsec_get_interface(struct tsec_private *priv)
                         * be set by the platform code.
                         */
                        if ((interface == PHY_INTERFACE_MODE_RGMII_ID) ||
-                                (interface == PHY_INTERFACE_MODE_RGMII_TXID) ||
-                                (interface == PHY_INTERFACE_MODE_RGMII_RXID))
+                           (interface == PHY_INTERFACE_MODE_RGMII_TXID) ||
+                           (interface == PHY_INTERFACE_MODE_RGMII_RXID))
                                return interface;
 
                        return PHY_INTERFACE_MODE_RGMII;
@@ -565,14 +640,13 @@ static phy_interface_t tsec_get_interface(struct tsec_private *priv)
        return PHY_INTERFACE_MODE_MII;
 }
 
-
-/* Discover which PHY is attached to the device, and configure it
+/*
+ * Discover which PHY is attached to the device, and configure it
  * properly.  If the PHY is not recognized, then return 0
  * (failure).  Otherwise, return 1
  */
-static int init_phy(struct eth_device *dev)
+static int init_phy(struct tsec_private *priv)
 {
-       struct tsec_private *priv = (struct tsec_private *)dev->priv;
        struct phy_device *phydev;
        struct tsec __iomem *regs = priv->regs;
        u32 supported = (SUPPORTED_10baseT_Half |
@@ -584,14 +658,15 @@ static int init_phy(struct eth_device *dev)
                supported |= SUPPORTED_1000baseT_Full;
 
        /* Assign a Physical address to the TBI */
-       out_be32(&regs->tbipa, CONFIG_SYS_TBIPA_VALUE);
+       out_be32(&regs->tbipa, priv->tbiaddr);
 
        priv->interface = tsec_get_interface(priv);
 
        if (priv->interface == PHY_INTERFACE_MODE_SGMII)
                tsec_configure_serdes(priv);
 
-       phydev = phy_connect(priv->bus, priv->phyaddr, dev, priv->interface);
+       phydev = phy_connect(priv->bus, priv->phyaddr, priv->dev,
+                            priv->interface);
        if (!phydev)
                return 0;
 
@@ -605,7 +680,9 @@ static int init_phy(struct eth_device *dev)
        return 1;
 }
 
-/* Initialize device structure. Returns success if PHY
+#ifndef CONFIG_DM_ETH
+/*
+ * Initialize device structure. Returns success if PHY
  * initialization succeeded (i.e. if it recognizes the PHY)
  */
 static int tsec_initialize(bd_t *bis, struct tsec_info_struct *tsec_info)
@@ -630,11 +707,13 @@ static int tsec_initialize(bd_t *bis, struct tsec_info_struct *tsec_info)
        priv->phyregs_sgmii = tsec_info->miiregs_sgmii;
 
        priv->phyaddr = tsec_info->phyaddr;
+       priv->tbiaddr = CONFIG_SYS_TBIPA_VALUE;
        priv->flags = tsec_info->flags;
 
        strcpy(dev->name, tsec_info->devname);
        priv->interface = tsec_info->interface;
        priv->bus = miiphy_get_dev_by_name(tsec_info->mii_devname);
+       priv->dev = dev;
        dev->iobase = 0;
        dev->priv = priv;
        dev->init = tsec_init;
@@ -645,7 +724,7 @@ static int tsec_initialize(bd_t *bis, struct tsec_info_struct *tsec_info)
        dev->mcast = tsec_mcast_addr;
 #endif
 
-       /* Tell u-boot to get the addr from the env */
+       /* Tell U-Boot to get the addr from the env */
        for (i = 0; i < 6; i++)
                dev->enetaddr[i] = 0;
 
@@ -657,7 +736,7 @@ static int tsec_initialize(bd_t *bis, struct tsec_info_struct *tsec_info)
        clrbits_be32(&priv->regs->maccfg1, MACCFG1_SOFT_RESET);
 
        /* Try to initialize PHY here, and return */
-       return init_phy(dev);
+       return init_phy(priv);
 }
 
 /*
@@ -690,3 +769,118 @@ int tsec_standard_init(bd_t *bis)
 
        return tsec_eth_init(bis, tsec_info, ARRAY_SIZE(tsec_info));
 }
+#else /* CONFIG_DM_ETH */
+int tsec_probe(struct udevice *dev)
+{
+       struct tsec_private *priv = dev_get_priv(dev);
+       struct eth_pdata *pdata = dev_get_platdata(dev);
+       struct fsl_pq_mdio_info mdio_info;
+       int offset = 0;
+       int reg;
+       const char *phy_mode;
+       int ret;
+
+       pdata->iobase = (phys_addr_t)dev_get_addr(dev);
+       priv->regs = (struct tsec *)pdata->iobase;
+
+       offset = fdtdec_lookup_phandle(gd->fdt_blob, dev->of_offset,
+                                      "phy-handle");
+       if (offset > 0) {
+               reg = fdtdec_get_int(gd->fdt_blob, offset, "reg", 0);
+               priv->phyaddr = reg;
+       } else {
+               debug("phy-handle does not exist under tsec %s\n", dev->name);
+               return -ENOENT;
+       }
+
+       offset = fdt_parent_offset(gd->fdt_blob, offset);
+       if (offset > 0) {
+               reg = fdtdec_get_int(gd->fdt_blob, offset, "reg", 0);
+               priv->phyregs_sgmii = (struct tsec_mii_mng *)(reg + 0x520);
+       } else {
+               debug("No parent node for PHY?\n");
+               return -ENOENT;
+       }
+
+       offset = fdtdec_lookup_phandle(gd->fdt_blob, dev->of_offset,
+                                      "tbi-handle");
+       if (offset > 0) {
+               reg = fdtdec_get_int(gd->fdt_blob, offset, "reg",
+                                    CONFIG_SYS_TBIPA_VALUE);
+               priv->tbiaddr = reg;
+       } else {
+               priv->tbiaddr = CONFIG_SYS_TBIPA_VALUE;
+       }
+
+       phy_mode = fdt_getprop(gd->fdt_blob, dev->of_offset,
+                              "phy-connection-type", NULL);
+       if (phy_mode)
+               pdata->phy_interface = phy_get_interface_by_name(phy_mode);
+       if (pdata->phy_interface == -1) {
+               debug("Invalid PHY interface '%s'\n", phy_mode);
+               return -EINVAL;
+       }
+       priv->interface = pdata->phy_interface;
+
+       /* Initialize flags */
+       priv->flags = TSEC_GIGABIT;
+       if (priv->interface == PHY_INTERFACE_MODE_SGMII)
+               priv->flags |= TSEC_SGMII;
+
+       mdio_info.regs = priv->phyregs_sgmii;
+       mdio_info.name = (char *)dev->name;
+       ret = fsl_pq_mdio_init(NULL, &mdio_info);
+       if (ret)
+               return ret;
+
+       /* Reset the MAC */
+       setbits_be32(&priv->regs->maccfg1, MACCFG1_SOFT_RESET);
+       udelay(2);  /* Soft Reset must be asserted for 3 TX clocks */
+       clrbits_be32(&priv->regs->maccfg1, MACCFG1_SOFT_RESET);
+
+       priv->dev = dev;
+       priv->bus = miiphy_get_dev_by_name(dev->name);
+
+       /* Try to initialize PHY here, and return */
+       return !init_phy(priv);
+}
+
+int tsec_remove(struct udevice *dev)
+{
+       struct tsec_private *priv = dev->priv;
+
+       free(priv->phydev);
+       mdio_unregister(priv->bus);
+       mdio_free(priv->bus);
+
+       return 0;
+}
+
+static const struct eth_ops tsec_ops = {
+       .start = tsec_init,
+       .send = tsec_send,
+       .recv = tsec_recv,
+       .free_pkt = tsec_free_pkt,
+       .stop = tsec_halt,
+#ifdef CONFIG_MCAST_TFTP
+       .mcast = tsec_mcast_addr,
+#endif
+};
+
+static const struct udevice_id tsec_ids[] = {
+       { .compatible = "fsl,tsec" },
+       { }
+};
+
+U_BOOT_DRIVER(eth_tsec) = {
+       .name = "tsec",
+       .id = UCLASS_ETH,
+       .of_match = tsec_ids,
+       .probe = tsec_probe,
+       .remove = tsec_remove,
+       .ops = &tsec_ops,
+       .priv_auto_alloc_size = sizeof(struct tsec_private),
+       .platdata_auto_alloc_size = sizeof(struct eth_pdata),
+       .flags = DM_FLAG_ALLOC_PRIV_DMA,
+};
+#endif /* CONFIG_DM_ETH */
index 7595db1acbd3e368d1a1f0d7a04811350aa3da03..44afe14051566e62800b9cc5f8b70bf9f3bb6494 100644 (file)
@@ -469,6 +469,47 @@ static void vsc9953_vlan_ingr_fltr_learn_drop(int enable)
                clrbits_le32(&l2ana_reg->ana.adv_learn, VSC9953_VLAN_CHK);
 }
 
+enum aggr_code_mode {
+       AGGR_CODE_RAND = 0,
+       AGGR_CODE_ALL,  /* S/D MAC, IPv4 S/D IP, IPv6 Flow Label, S/D PORT */
+};
+
+/* Set aggregation code generation mode */
+static int vsc9953_aggr_code_set(enum aggr_code_mode ac)
+{
+       int rc;
+       struct vsc9953_analyzer *l2ana_reg;
+
+       l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
+                                               VSC9953_ANA_OFFSET);
+
+       switch (ac) {
+       case AGGR_CODE_RAND:
+               clrsetbits_le32(&l2ana_reg->common.aggr_cfg,
+                               VSC9953_AC_DMAC_ENA | VSC9953_AC_SMAC_ENA |
+                               VSC9953_AC_IP6_LBL_ENA |
+                               VSC9953_AC_IP6_TCPUDP_ENA |
+                               VSC9953_AC_IP4_SIPDIP_ENA |
+                               VSC9953_AC_IP4_TCPUDP_ENA, VSC9953_AC_RND_ENA);
+               rc = 0;
+               break;
+       case AGGR_CODE_ALL:
+               clrsetbits_le32(&l2ana_reg->common.aggr_cfg, VSC9953_AC_RND_ENA,
+                               VSC9953_AC_DMAC_ENA | VSC9953_AC_SMAC_ENA |
+                               VSC9953_AC_IP6_LBL_ENA |
+                               VSC9953_AC_IP6_TCPUDP_ENA |
+                               VSC9953_AC_IP4_SIPDIP_ENA |
+                               VSC9953_AC_IP4_TCPUDP_ENA);
+               rc = 0;
+               break;
+       default:
+               /* unknown mode for aggregation code */
+               rc = -EINVAL;
+       }
+
+       return rc;
+}
+
 /* Egress untag modes of a VSC9953 port */
 enum egress_untag_mode {
        EGRESS_UNTAG_ALL = 0,
@@ -593,6 +634,25 @@ static void vsc9953_port_all_vlan_egress_untagged_set(
                vsc9953_port_vlan_egr_untag_set(i, mode);
 }
 
+static int vsc9953_autoage_time_set(int age_period)
+{
+       u32 autoage;
+       struct vsc9953_analyzer *l2ana_reg;
+
+       l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
+                                               VSC9953_ANA_OFFSET);
+
+       if (age_period < 0 || age_period > VSC9953_AUTOAGE_PERIOD_MASK)
+               return -EINVAL;
+
+       autoage = bitfield_replace_by_mask(in_le32(&l2ana_reg->ana.auto_age),
+                                          VSC9953_AUTOAGE_PERIOD_MASK,
+                                          age_period);
+       out_le32(&l2ana_reg->ana.auto_age, autoage);
+
+       return 0;
+}
+
 #ifdef CONFIG_CMD_ETHSW
 
 /* Enable/disable status of a VSC9953 port */
@@ -1474,6 +1534,224 @@ static int vsc9953_port_ingress_filtering_get(int port_no)
        return !!(val & (1 << port_no));
 }
 
+/* Get the aggregation group of a port */
+static int vsc9953_port_aggr_grp_get(int port_no, int *aggr_grp)
+{
+       u32 val;
+       struct vsc9953_analyzer *l2ana_reg;
+
+       if (!VSC9953_PORT_CHECK(port_no))
+               return -EINVAL;
+
+       l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
+                                               VSC9953_ANA_OFFSET);
+
+       val = in_le32(&l2ana_reg->port[port_no].port_cfg);
+       *aggr_grp = bitfield_extract_by_mask(val,
+                                            VSC9953_PORT_CFG_PORTID_MASK);
+
+       return 0;
+}
+
+static void vsc9953_aggr_grp_members_get(int aggr_grp,
+                                        u8 aggr_membr[VSC9953_MAX_PORTS])
+{
+       int port_no;
+       int aggr_membr_grp;
+
+       for (port_no = 0; port_no < VSC9953_MAX_PORTS; port_no++) {
+               aggr_membr[port_no] = 0;
+
+               if (vsc9953_port_aggr_grp_get(port_no, &aggr_membr_grp))
+                       continue;
+
+               if (aggr_grp == aggr_membr_grp)
+                       aggr_membr[port_no] = 1;
+       }
+}
+
+static void vsc9953_update_dest_members_masks(int port_no, u32 membr_bitfld_old,
+                                             u32 membr_bitfld_new)
+{
+       int i;
+       u32 pgid;
+       struct vsc9953_analyzer *l2ana_reg;
+
+       l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
+                                               VSC9953_ANA_OFFSET);
+
+       /*
+        * NOTE: Only the unicast destination masks are updated, since
+        * we do not support for now Layer-2 multicast entries
+        */
+       for (i = 0; i < VSC9953_MAX_PORTS; i++) {
+               if (i == port_no) {
+                       clrsetbits_le32(&l2ana_reg->port_id_tbl.port_grp_id[i],
+                                       VSC9953_PGID_PORT_MASK,
+                                       membr_bitfld_new);
+                       continue;
+               }
+
+               pgid = in_le32(&l2ana_reg->port_id_tbl.port_grp_id[i]);
+               if ((u32)(1 << i) & membr_bitfld_old & VSC9953_PGID_PORT_MASK)
+                       pgid &= ~((u32)(1 << port_no));
+               if ((u32)(1 << i) & membr_bitfld_new & VSC9953_PGID_PORT_MASK)
+                       pgid |= ((u32)(1 << port_no));
+
+               out_le32(&l2ana_reg->port_id_tbl.port_grp_id[i], pgid);
+       }
+}
+
+static void vsc9953_update_source_members_masks(int port_no,
+                                               u32 membr_bitfld_old,
+                                               u32 membr_bitfld_new)
+{
+       int i;
+       int index;
+       u32 pgid;
+       struct vsc9953_analyzer *l2ana_reg;
+
+       l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
+                                               VSC9953_ANA_OFFSET);
+
+       for (i = 0; i < VSC9953_MAX_PORTS + 1; i++) {
+               index = PGID_SRC_START + i;
+               pgid = in_le32(&l2ana_reg->port_id_tbl.port_grp_id[index]);
+               if (i == port_no) {
+                       pgid = (pgid | VSC9953_PGID_PORT_MASK) &
+                              ~membr_bitfld_new;
+                       out_le32(&l2ana_reg->port_id_tbl.port_grp_id[index],
+                                pgid);
+                       continue;
+               }
+
+               if ((u32)(1 << i) & membr_bitfld_old & VSC9953_PGID_PORT_MASK)
+                       pgid |= (u32)(1 << port_no);
+
+               if ((u32)(1 << i) & membr_bitfld_new & VSC9953_PGID_PORT_MASK)
+                       pgid &= ~(u32)(1 << port_no);
+               out_le32(&l2ana_reg->port_id_tbl.port_grp_id[index], pgid);
+       }
+}
+
+static u32 vsc9953_aggr_mask_get_next(u32 aggr_mask, u32 member_bitfield)
+{
+       if (!member_bitfield)
+               return 0;
+
+       if (!(aggr_mask & VSC9953_PGID_PORT_MASK))
+               aggr_mask = 1;
+       else
+               aggr_mask <<= 1;
+
+       while (!(aggr_mask & member_bitfield)) {
+               aggr_mask <<= 1;
+               if (!(aggr_mask & VSC9953_PGID_PORT_MASK))
+                       aggr_mask = 1;
+       }
+
+       return aggr_mask;
+}
+
+static void vsc9953_update_aggr_members_masks(int port_no, u32 membr_bitfld_old,
+                                             u32 membr_bitfld_new)
+{
+       int i;
+       u32 pgid;
+       u32 aggr_mask_old = 0;
+       u32 aggr_mask_new = 0;
+       struct vsc9953_analyzer *l2ana_reg;
+
+       l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
+                                               VSC9953_ANA_OFFSET);
+
+       /* Update all the PGID aggregation masks */
+       for (i = PGID_AGGR_START; i < PGID_SRC_START; i++) {
+               pgid = in_le32(&l2ana_reg->port_id_tbl.port_grp_id[i]);
+
+               aggr_mask_old = vsc9953_aggr_mask_get_next(aggr_mask_old,
+                                                          membr_bitfld_old);
+               pgid = (pgid & ~membr_bitfld_old) | aggr_mask_old;
+
+               aggr_mask_new = vsc9953_aggr_mask_get_next(aggr_mask_new,
+                                                          membr_bitfld_new);
+               pgid = (pgid & ~membr_bitfld_new) | aggr_mask_new;
+
+               out_le32(&l2ana_reg->port_id_tbl.port_grp_id[i], pgid);
+       }
+}
+
+static u32 vsc9953_aggr_membr_bitfield_get(u8 member[VSC9953_MAX_PORTS])
+{
+       int i;
+       u32 member_bitfield = 0;
+
+       for (i = 0; i < VSC9953_MAX_PORTS; i++) {
+               if (member[i])
+                       member_bitfield |= 1 << i;
+       }
+       member_bitfield &= VSC9953_PGID_PORT_MASK;
+
+       return member_bitfield;
+}
+
+static void vsc9953_update_members_masks(int port_no,
+                                        u8 member_old[VSC9953_MAX_PORTS],
+                                        u8 member_new[VSC9953_MAX_PORTS])
+{
+       u32 membr_bitfld_old = vsc9953_aggr_membr_bitfield_get(member_old);
+       u32 membr_bitfld_new = vsc9953_aggr_membr_bitfield_get(member_new);
+
+       vsc9953_update_dest_members_masks(port_no, membr_bitfld_old,
+                                         membr_bitfld_new);
+       vsc9953_update_source_members_masks(port_no, membr_bitfld_old,
+                                           membr_bitfld_new);
+       vsc9953_update_aggr_members_masks(port_no, membr_bitfld_old,
+                                         membr_bitfld_new);
+}
+
+/* Set the aggregation group of a port */
+static int vsc9953_port_aggr_grp_set(int port_no, int aggr_grp)
+{
+       u8 aggr_membr_old[VSC9953_MAX_PORTS];
+       u8 aggr_membr_new[VSC9953_MAX_PORTS];
+       int rc;
+       int aggr_grp_old;
+       u32 val;
+       struct vsc9953_analyzer *l2ana_reg;
+
+       if (!VSC9953_PORT_CHECK(port_no) || !VSC9953_PORT_CHECK(aggr_grp))
+               return -EINVAL;
+
+       l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
+                                               VSC9953_ANA_OFFSET);
+
+       rc = vsc9953_port_aggr_grp_get(port_no, &aggr_grp_old);
+       if (rc)
+               return rc;
+
+       /* get all the members of the old aggregation group */
+       vsc9953_aggr_grp_members_get(aggr_grp_old, aggr_membr_old);
+
+       /* get all the members of the same aggregation group */
+       vsc9953_aggr_grp_members_get(aggr_grp, aggr_membr_new);
+
+       /* add current port as member to the new aggregation group */
+       aggr_membr_old[port_no] = 0;
+       aggr_membr_new[port_no] = 1;
+
+       /* update masks */
+       vsc9953_update_members_masks(port_no, aggr_membr_old, aggr_membr_new);
+
+       /* Change logical port number */
+       val = in_le32(&l2ana_reg->port[port_no].port_cfg);
+       val = bitfield_replace_by_mask(val,
+                                      VSC9953_PORT_CFG_PORTID_MASK, aggr_grp);
+       out_le32(&l2ana_reg->port[port_no].port_cfg, val);
+
+       return 0;
+}
+
 static int vsc9953_port_status_key_func(struct ethsw_command_def *parsed_cmd)
 {
        int i;
@@ -2064,6 +2342,72 @@ static int vsc9953_ingr_fltr_set_key_func(struct ethsw_command_def *parsed_cmd)
        return CMD_RET_SUCCESS;
 }
 
+static int vsc9953_port_aggr_show_key_func(struct ethsw_command_def *parsed_cmd)
+{
+       int i;
+       int aggr_grp;
+
+       if (parsed_cmd->port != ETHSW_CMD_PORT_ALL) {
+               if (!VSC9953_PORT_CHECK(parsed_cmd->port)) {
+                       printf("Invalid port number: %d\n", parsed_cmd->port);
+                       return CMD_RET_FAILURE;
+               }
+
+               if (vsc9953_port_aggr_grp_get(parsed_cmd->port, &aggr_grp))
+                       return CMD_RET_FAILURE;
+               printf("%7s %10s\n", "Port", "Aggr grp");
+               printf("%7d %10d\n", parsed_cmd->port, aggr_grp);
+       } else {
+               printf("%7s %10s\n", "Port", "Aggr grp");
+               for (i = 0; i < VSC9953_MAX_PORTS; i++) {
+                       if (vsc9953_port_aggr_grp_get(i, &aggr_grp))
+                               continue;
+                       printf("%7d %10d\n", i, aggr_grp);
+               }
+       }
+
+       return CMD_RET_SUCCESS;
+}
+
+static int vsc9953_port_aggr_set_key_func(struct ethsw_command_def *parsed_cmd)
+{
+       int i;
+
+       /* Aggregation group number should be set in parsed_cmd->aggr_grp */
+       if (parsed_cmd->aggr_grp == ETHSW_CMD_AGGR_GRP_NONE) {
+               printf("Please set an aggregation group value\n");
+               return CMD_RET_FAILURE;
+       }
+
+       if (!VSC9953_PORT_CHECK(parsed_cmd->aggr_grp)) {
+               printf("Invalid aggregation group number: %d\n",
+                      parsed_cmd->aggr_grp);
+               return CMD_RET_FAILURE;
+       }
+
+       if (parsed_cmd->port != ETHSW_CMD_PORT_ALL) {
+               if (!VSC9953_PORT_CHECK(parsed_cmd->port)) {
+                       printf("Invalid port number: %d\n", parsed_cmd->port);
+                       return CMD_RET_FAILURE;
+               }
+               if (vsc9953_port_aggr_grp_set(parsed_cmd->port,
+                                             parsed_cmd->aggr_grp)) {
+                       printf("Port %d: failed to set aggr group %d\n",
+                              parsed_cmd->port, parsed_cmd->aggr_grp);
+               }
+       } else {
+               for (i = 0; i < VSC9953_MAX_PORTS; i++) {
+                       if (vsc9953_port_aggr_grp_set(i,
+                                                     parsed_cmd->aggr_grp)) {
+                               printf("Port %d: failed to set aggr group %d\n",
+                                      i, parsed_cmd->aggr_grp);
+                       }
+               }
+       }
+
+       return CMD_RET_SUCCESS;
+}
+
 static struct ethsw_command_func vsc9953_cmd_func = {
                .ethsw_name = "L2 Switch VSC9953",
                .port_enable = &vsc9953_port_status_key_func,
@@ -2088,7 +2432,9 @@ static struct ethsw_command_func vsc9953_cmd_func = {
                .vlan_learn_show = &vsc9953_vlan_learn_show_key_func,
                .vlan_learn_set = &vsc9953_vlan_learn_set_key_func,
                .port_ingr_filt_show = &vsc9953_ingr_fltr_show_key_func,
-               .port_ingr_filt_set = &vsc9953_ingr_fltr_set_key_func
+               .port_ingr_filt_set = &vsc9953_ingr_fltr_set_key_func,
+               .port_aggr_show = &vsc9953_port_aggr_show_key_func,
+               .port_aggr_set = &vsc9953_port_aggr_set_key_func,
 };
 
 #endif /* CONFIG_CMD_ETHSW */
@@ -2107,6 +2453,10 @@ void vsc9953_default_configuration(void)
 {
        int i;
 
+       if (vsc9953_autoage_time_set(VSC9953_DEFAULT_AGE_TIME))
+               debug("VSC9953: failed to set AGE time to %d\n",
+                     VSC9953_DEFAULT_AGE_TIME);
+
        for (i = 0; i < VSC9953_MAX_VLAN; i++)
                vsc9953_vlan_table_membership_all_set(i, 0);
        vsc9953_port_all_vlan_aware_set(1);
@@ -2115,6 +2465,8 @@ void vsc9953_default_configuration(void)
        vsc9953_vlan_table_membership_all_set(1, 1);
        vsc9953_vlan_ingr_fltr_learn_drop(1);
        vsc9953_port_all_vlan_egress_untagged_set(EGRESS_UNTAG_PVID_AND_ZERO);
+       if (vsc9953_aggr_code_set(AGGR_CODE_ALL))
+               debug("VSC9953: failed to set default aggregation code mode\n");
 }
 
 void vsc9953_init(bd_t *bis)
index 5a7fefed5e1525e6d942a8e36a9d21b70e4dd3a1..5dadf6fa62a7b4881b2dacdfb5ca02eee26a69ba 100644 (file)
@@ -465,7 +465,11 @@ static int tegra_pcie_parse_dt(const void *fdt, int node, enum tegra_pci_id id,
                return err;
        }
 
-       tegra_pcie_board_init();
+       err = tegra_pcie_board_init();
+       if (err < 0) {
+               error("tegra_pcie_board_init() failed: err=%d", err);
+               return err;
+       }
 
        pcie->phy = tegra_xusb_phy_get(TEGRA_XUSB_PADCTL_PCIE);
        if (pcie->phy) {
index 2d3c12a39e6d9f7909c47e4fcc95de0db06ad926..25f358d128e0c2a8074e82896a1a5d5f64442948 100644 (file)
@@ -12,6 +12,7 @@
 #define ETHSW_MAX_CMD_PARAMS 20
 #define ETHSW_CMD_PORT_ALL -1
 #define ETHSW_CMD_VLAN_ALL -1
+#define ETHSW_CMD_AGGR_GRP_NONE -1
 
 /* IDs used to track keywords in a command */
 enum ethsw_keyword_id {
@@ -41,6 +42,7 @@ enum ethsw_keyword_id {
        ethsw_id_private,
        ethsw_id_ingress,
        ethsw_id_filtering,
+       ethsw_id_aggr,
        ethsw_id_count, /* keep last */
 };
 
@@ -50,6 +52,7 @@ enum ethsw_keyword_opt_id {
        ethsw_id_pvid_no,
        ethsw_id_add_del_no,
        ethsw_id_add_del_mac,
+       ethsw_id_aggr_no,
        ethsw_id_count_all,     /* keep last */
 };
 
@@ -58,6 +61,7 @@ struct ethsw_command_def {
        int cmd_keywords_nr;
        int port;
        int vid;
+       int aggr_grp;
        uchar ethaddr[6];
        int (*cmd_function)(struct ethsw_command_def *parsed_cmd);
 };
@@ -88,6 +92,8 @@ struct ethsw_command_func {
        int (*vlan_learn_set)(struct ethsw_command_def *parsed_cmd);
        int (*port_ingr_filt_show)(struct ethsw_command_def *parsed_cmd);
        int (*port_ingr_filt_set)(struct ethsw_command_def *parsed_cmd);
+       int (*port_aggr_show)(struct ethsw_command_def *parsed_cmd);
+       int (*port_aggr_set)(struct ethsw_command_def *parsed_cmd);
 };
 
 int ethsw_define_functions(const struct ethsw_command_func *cmd_func);
index 2137282df3fd97978ec6cda00530dd4487720b55..25678a9988beb01dd427dda2566104517234fb53 100644 (file)
@@ -5,6 +5,7 @@
  *
  * SPDX-License-Identifier:    GPL-2.0+
  */
+
 #ifndef __FSL_PHY_H__
 #define __FSL_PHY_H__
 
@@ -27,9 +28,9 @@ int fdt_fixup_phy_connection(void *blob, int offset, phy_interface_t phyc);
 #define PHY_EXT_PAGE_ACCESS    0x1f
 
 /* MII Management Configuration Register */
-#define MIIMCFG_RESET_MGMT          0x80000000
-#define MIIMCFG_MGMT_CLOCK_SELECT   0x00000007
-#define MIIMCFG_INIT_VALUE         0x00000003
+#define MIIMCFG_RESET_MGMT             0x80000000
+#define MIIMCFG_MGMT_CLOCK_SELECT      0x00000007
+#define MIIMCFG_INIT_VALUE             0x00000003
 
 /* MII Management Command Register */
 #define MIIMCOM_READ_CYCLE     0x00000001
index ac44d614ca335e390d801e3be50aaac6acccac71..a739f45bbbcea264bbf7ca070a45929c6fd41caf 100644 (file)
@@ -86,11 +86,13 @@ enum eth_state_t {
  * @iobase: The base address of the hardware registers
  * @enetaddr: The Ethernet MAC address that is loaded from EEPROM or env
  * @phy_interface: PHY interface to use - see PHY_INTERFACE_MODE_...
+ * @max_speed: Maximum speed of Ethernet connection supported by MAC
  */
 struct eth_pdata {
        phys_addr_t iobase;
        unsigned char enetaddr[6];
        int phy_interface;
+       int max_speed;
 };
 
 enum eth_recv_flags {
index 66cf61bdfb93954bad76c13d90bccbe736669494..09bbe483a4b120e1642d968692aeaad46ca63a9a 100644 (file)
 
 #define PHY_MAX_ADDR 32
 
-#define PHY_BASIC_FEATURES     (SUPPORTED_10baseT_Half | \
-                                SUPPORTED_10baseT_Full | \
-                                SUPPORTED_100baseT_Half | \
-                                SUPPORTED_100baseT_Full | \
-                                SUPPORTED_Autoneg | \
+#define PHY_FLAG_BROKEN_RESET  (1 << 0) /* soft reset not supported */
+
+#define PHY_DEFAULT_FEATURES   (SUPPORTED_Autoneg | \
                                 SUPPORTED_TP | \
                                 SUPPORTED_MII)
 
-#define PHY_GBIT_FEATURES      (PHY_BASIC_FEATURES | \
-                                SUPPORTED_1000baseT_Half | \
+#define PHY_10BT_FEATURES      (SUPPORTED_10baseT_Half | \
+                                SUPPORTED_10baseT_Full)
+
+#define PHY_100BT_FEATURES     (SUPPORTED_100baseT_Half | \
+                                SUPPORTED_100baseT_Full)
+
+#define PHY_1000BT_FEATURES    (SUPPORTED_1000baseT_Half | \
                                 SUPPORTED_1000baseT_Full)
 
+#define PHY_BASIC_FEATURES     (PHY_10BT_FEATURES | \
+                                PHY_100BT_FEATURES | \
+                                PHY_DEFAULT_FEATURES)
+
+#define PHY_GBIT_FEATURES      (PHY_BASIC_FEATURES | \
+                                PHY_1000BT_FEATURES)
+
 #define PHY_10G_FEATURES       (PHY_GBIT_FEATURES | \
                                SUPPORTED_10000baseT_Full)
 
@@ -226,6 +236,7 @@ int phy_startup(struct phy_device *phydev);
 int phy_config(struct phy_device *phydev);
 int phy_shutdown(struct phy_device *phydev);
 int phy_register(struct phy_driver *drv);
+int phy_set_supported(struct phy_device *phydev, u32 max_speed);
 int genphy_config_aneg(struct phy_device *phydev);
 int genphy_restart_aneg(struct phy_device *phydev);
 int genphy_update_link(struct phy_device *phydev);
index 1119d2cb60be8c4dd3943f383093e9b595f34abb..fb27edf2250d5e40e402fbae58c9629f3fc776d5 100644 (file)
@@ -3,15 +3,12 @@
  *
  *  Driver for the Motorola Triple Speed Ethernet Controller
  *
- *  This software may be used and distributed according to the
- *  terms of the GNU Public License, Version 2, incorporated
- *  herein by reference.
- *
  * Copyright 2004, 2007, 2009, 2011, 2013 Freescale Semiconductor, Inc.
  * (C) Copyright 2003, Motorola, Inc.
  * maintained by Xianghua Xiao (x.xiao@motorola.com)
  * author Andy Fleming
  *
+ * SPDX-License-Identifier:    GPL-2.0+
  */
 
 #ifndef __TSEC_H
@@ -21,6 +18,8 @@
 #include <config.h>
 #include <phy.h>
 
+#ifndef CONFIG_DM_ETH
+
 #ifdef CONFIG_LS102XA
 #define TSEC_SIZE              0x40000
 #define TSEC_MDIO_OFFSET       0x40000
        x.mii_devname = DEFAULT_MII_NAME;\
 }
 
-#define MAC_ADDR_LEN 6
+#endif /* CONFIG_DM_ETH */
+
+#define MAC_ADDR_LEN           6
 
 /* #define TSEC_TIMEOUT        1000000 */
-#define TSEC_TIMEOUT 1000
-#define TOUT_LOOP      1000000
+#define TSEC_TIMEOUT           1000
+#define TOUT_LOOP              1000000
 
 /* TBI register addresses */
 #define TBI_CR                 0x00
@@ -83,8 +84,8 @@
 
 /* TBI MDIO register bit fields*/
 #define TBICON_CLK_SELECT      0x0020
-#define TBIANA_ASYMMETRIC_PAUSE 0x0100
-#define TBIANA_SYMMETRIC_PAUSE  0x0080
+#define TBIANA_ASYMMETRIC_PAUSE        0x0100
+#define TBIANA_SYMMETRIC_PAUSE 0x0080
 #define TBIANA_HALF_DUPLEX     0x0040
 #define TBIANA_FULL_DUPLEX     0x0020
 #define TBICR_PHY_RESET                0x8000
 #define TBICR_FULL_DUPLEX      0x0100
 #define TBICR_SPEED1_SET       0x0040
 
-
 /* MAC register bits */
 #define MACCFG1_SOFT_RESET     0x80000000
 #define MACCFG1_RESET_RX_MC    0x00080000
 #define MACCFG1_RESET_TX_MC    0x00040000
 #define MACCFG1_RESET_RX_FUN   0x00020000
-#define        MACCFG1_RESET_TX_FUN    0x00010000
+#define MACCFG1_RESET_TX_FUN   0x00010000
 #define MACCFG1_LOOPBACK       0x00000100
 #define MACCFG1_RX_FLOW                0x00000020
 #define MACCFG1_TX_FLOW                0x00000010
 #define ECNTRL_SGMII_MODE      0x00000002
 
 #ifndef CONFIG_SYS_TBIPA_VALUE
-    #define CONFIG_SYS_TBIPA_VALUE     0x1f
+# define CONFIG_SYS_TBIPA_VALUE        0x1f
 #endif
 
 #define MRBLR_INIT_SETTINGS    PKTSIZE_ALIGN
 #define TSTAT_CLEAR_THALT      0x80000000
 #define RSTAT_CLEAR_RHALT      0x00800000
 
-
 #define IEVENT_INIT_CLEAR      0xffffffff
 #define IEVENT_BABR            0x80000000
 #define IEVENT_RXC             0x40000000
 #define IMASK_TXFEN            0x00100000
 #define IMASK_RXFEN0           0x00000080
 
-
 /* Default Attribute fields */
-#define ATTR_INIT_SETTINGS     0x000000c0
-#define ATTRELI_INIT_SETTINGS  0x00000000
-
+#define ATTR_INIT_SETTINGS     0x000000c0
+#define ATTRELI_INIT_SETTINGS  0x00000000
 
 /* TxBD status field bits */
 #define TXBD_READY             0x8000
 #define TXBD_HUGEFRAME         0x0080
 #define TXBD_LATECOLLISION     0x0080
 #define TXBD_RETRYLIMIT                0x0040
-#define        TXBD_RETRYCOUNTMASK     0x003c
+#define TXBD_RETRYCOUNTMASK    0x003c
 #define TXBD_UNDERRUN          0x0002
 #define TXBD_STATS             0x03ff
 
 #define RXBD_STATS             0x003f
 
 struct txbd8 {
-       uint16_t     status;         /* Status Fields */
-       uint16_t     length;         /* Buffer length */
-       uint32_t     bufptr;         /* Buffer Pointer */
+       uint16_t status;        /* Status Fields */
+       uint16_t length;        /* Buffer length */
+       uint32_t bufptr;        /* Buffer Pointer */
 };
 
 struct rxbd8 {
-       uint16_t     status;         /* Status Fields */
-       uint16_t     length;         /* Buffer Length */
-       uint32_t     bufptr;         /* Buffer Pointer */
+       uint16_t status;        /* Status Fields */
+       uint16_t length;        /* Buffer Length */
+       uint32_t bufptr;        /* Buffer Pointer */
 };
 
 struct tsec_rmon_mib {
@@ -336,15 +333,15 @@ struct tsec {
        u32     rbdlen;         /* RxBD Data Length */
        u32     res310[4];
        u32     res320;
-       u32     crbptr; /* Current Receive Buffer Pointer */
+       u32     crbptr;         /* Current Receive Buffer Pointer */
        u32     res328[6];
-       u32     mrblr;  /* Maximum Receive Buffer Length */
+       u32     mrblr;          /* Maximum Receive Buffer Length */
        u32     res344[16];
-       u32     rbptr;  /* RxBD Pointer */
+       u32     rbptr;          /* RxBD Pointer */
        u32     res388[30];
        /* (0x2_n400) */
        u32     res400;
-       u32     rbase;  /* RxBD Base Address */
+       u32     rbase;          /* RxBD Base Address */
        u32     res408[62];
 
        /* MAC Registers (0x2_n500) */
@@ -388,21 +385,33 @@ struct tsec {
        u32     resc00[256];
 };
 
-#define TSEC_GIGABIT (1 << 0)
+#define TSEC_GIGABIT   (1 << 0)
 
 /* These flags currently only have meaning if we're using the eTSEC */
 #define TSEC_REDUCED   (1 << 1)        /* MAC-PHY interface uses RGMII */
 #define TSEC_SGMII     (1 << 2)        /* MAC-PHY interface uses SGMII */
 
+#define TX_BUF_CNT     2
+
 struct tsec_private {
+       struct txbd8 __iomem txbd[TX_BUF_CNT];
+       struct rxbd8 __iomem rxbd[PKTBUFSRX];
        struct tsec __iomem *regs;
        struct tsec_mii_mng __iomem *phyregs_sgmii;
        struct phy_device *phydev;
        phy_interface_t interface;
        struct mii_dev *bus;
        uint phyaddr;
+       uint tbiaddr;
        char mii_devname[16];
        u32 flags;
+       uint rx_idx;    /* index of the current RX buffer */
+       uint tx_idx;    /* index of the current TX buffer */
+#ifndef CONFIG_DM_ETH
+       struct eth_device *dev;
+#else
+       struct udevice *dev;
+#endif
 };
 
 struct tsec_info_struct {
@@ -415,7 +424,9 @@ struct tsec_info_struct {
        u32 flags;
 };
 
+#ifndef CONFIG_DM_ETH
 int tsec_standard_init(bd_t *bis);
 int tsec_eth_init(bd_t *bis, struct tsec_info_struct *tsec_info, int num);
+#endif
 
 #endif /* __TSEC_H */
index cd5cfc76b079a0d73977507e4016d56fb625d524..a2d4554c3bbe0b1d8e0d88da2a3b16187be0823b 100644 (file)
 #define VSC9953_PORT_CFG_LEARN_AUTO    0x00000100
 #define VSC9953_PORT_CFG_LEARN_CPU     0x00000200
 #define VSC9953_PORT_CFG_LEARN_DROP    0x00000400
+#define VSC9953_PORT_CFG_PORTID_MASK   0x0000003c
 
 /* Macros for vsc9953_qsys_sys.switch_port_mode register */
 #define VSC9953_PORT_ENA               0x00002000
 /* Macros for vsc9953_ana_ana.adv_learn register */
 #define VSC9953_VLAN_CHK               0x00000400
 
+/* Macros for vsc9953_ana_ana.auto_age register */
+#define VSC9953_AUTOAGE_PERIOD_MASK    0x001ffffe
+
 /* Macros for vsc9953_rew_port.port_tag_cfg register */
 #define VSC9953_TAG_CFG_MASK           0x00000180
 #define VSC9953_TAG_CFG_NONE           0x00000000
 /* Macros for vsc9953_ana_ana_tables.mach_data register */
 #define VSC9953_MACHDATA_VID_MASK      0x1fff0000
 
+/* Macros for vsc9953_ana_common.aggr_cfg register */
+#define VSC9953_AC_RND_ENA             0x00000080
+#define VSC9953_AC_DMAC_ENA            0x00000040
+#define VSC9953_AC_SMAC_ENA            0x00000020
+#define VSC9953_AC_IP6_LBL_ENA         0x00000010
+#define VSC9953_AC_IP6_TCPUDP_ENA      0x00000008
+#define VSC9953_AC_IP4_SIPDIP_ENA      0x00000004
+#define VSC9953_AC_IP4_TCPUDP_ENA      0x00000002
+#define VSC9953_AC_MASK                        0x000000fe
+
+/* Macros for vsc9953_ana_pgid.port_grp_id[] registers */
+#define VSC9953_PGID_PORT_MASK         0x000003ff
+
 #define VSC9953_MAX_PORTS              10
 #define VSC9953_PORT_CHECK(port)       \
        (((port) < 0 || (port) >= VSC9953_MAX_PORTS) ? 0 : 1)
 #define VSC9953_MAX_VLAN               4096
 #define VSC9953_VLAN_CHECK(vid)        \
        (((vid) < 0 || (vid) >= VSC9953_MAX_VLAN) ? 0 : 1)
+#define VSC9953_DEFAULT_AGE_TIME       300
 
 #define DEFAULT_VSC9953_MDIO_NAME      "VSC9953_MDIO0"
 
@@ -235,6 +253,10 @@ struct vsc9953_ana_ana {
        u32     port_mode[12];
 };
 
+#define PGID_DST_START         0
+#define PGID_AGGR_START                64
+#define PGID_SRC_START         80
+
 struct vsc9953_ana_pgid {
        u32     port_grp_id[91];
 };
@@ -269,7 +291,7 @@ struct vsc9953_analyzer {
        struct vsc9953_ana_ana_tables   ana_tables;
        u32     reserved2[14];
        struct vsc9953_ana_ana  ana;
-       u32     reserved3[22];
+       u32     reserved3[21];
        struct vsc9953_ana_pgid port_id_tbl;
        u32     reserved4[549];
        struct vsc9953_ana_pfc  pfc[10];
index e9cc8ada96a783ae18444c9f68a107bede6e0054..f03d6083268f2b085b9277a72f46685d98c30701 100644 (file)
@@ -12,7 +12,12 @@ obj-$(CONFIG_CMD_NET)  += arp.o
 obj-$(CONFIG_CMD_NET)  += bootp.o
 obj-$(CONFIG_CMD_CDP)  += cdp.o
 obj-$(CONFIG_CMD_DNS)  += dns.o
-obj-$(CONFIG_CMD_NET)  += eth.o
+ifdef CONFIG_DM_ETH
+obj-$(CONFIG_CMD_NET)  += eth-uclass.o
+else
+obj-$(CONFIG_CMD_NET)  += eth_legacy.o
+endif
+obj-$(CONFIG_CMD_NET)  += eth_common.o
 obj-$(CONFIG_CMD_LINK_LOCAL) += link_local.o
 obj-$(CONFIG_CMD_NET)  += net.o
 obj-$(CONFIG_CMD_NFS)  += nfs.o
index 8aeddb08ea83f0bf1094d9cb72938df4357801dc..f2978a23ce5aaaa8074ae6bdeac950363edeaca0 100644 (file)
@@ -949,6 +949,7 @@ static void dhcp_send_request_packet(struct bootp_hdr *bp_offer)
        net_write_ip(&bp->bp_giaddr, zero_ip);
 
        memcpy(bp->bp_chaddr, net_ethaddr, 6);
+       copy_filename(bp->bp_file, net_boot_file_name, sizeof(bp->bp_file));
 
        /*
         * ID is the id of the OFFER packet
@@ -995,6 +996,9 @@ static void dhcp_handler(uchar *pkt, unsigned dest, struct in_addr sip,
        debug("DHCPHandler: got DHCP packet: (src=%d, dst=%d, len=%d) state: "
              "%d\n", src, dest, len, dhcp_state);
 
+       if (net_read_ip(&bp->bp_yiaddr).s_addr == 0)
+               return;
+
        switch (dhcp_state) {
        case SELECTING:
                /*
diff --git a/net/eth-uclass.c b/net/eth-uclass.c
new file mode 100644 (file)
index 0000000..a356a08
--- /dev/null
@@ -0,0 +1,549 @@
+/*
+ * (C) Copyright 2001-2015
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ * Joe Hershberger, National Instruments
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <environment.h>
+#include <net.h>
+#include <dm/device-internal.h>
+#include <dm/uclass-internal.h>
+#include "eth_internal.h"
+
+/**
+ * struct eth_device_priv - private structure for each Ethernet device
+ *
+ * @state: The state of the Ethernet MAC driver (defined by enum eth_state_t)
+ */
+struct eth_device_priv {
+       enum eth_state_t state;
+};
+
+/**
+ * struct eth_uclass_priv - The structure attached to the uclass itself
+ *
+ * @current: The Ethernet device that the network functions are using
+ */
+struct eth_uclass_priv {
+       struct udevice *current;
+};
+
+/* eth_errno - This stores the most recent failure code from DM functions */
+static int eth_errno;
+
+static struct eth_uclass_priv *eth_get_uclass_priv(void)
+{
+       struct uclass *uc;
+
+       uclass_get(UCLASS_ETH, &uc);
+       assert(uc);
+       return uc->priv;
+}
+
+void eth_set_current_to_next(void)
+{
+       struct eth_uclass_priv *uc_priv;
+
+       uc_priv = eth_get_uclass_priv();
+       if (uc_priv->current)
+               uclass_next_device(&uc_priv->current);
+       if (!uc_priv->current)
+               uclass_first_device(UCLASS_ETH, &uc_priv->current);
+}
+
+/*
+ * Typically this will simply return the active device.
+ * In the case where the most recent active device was unset, this will attempt
+ * to return the first device. If that device doesn't exist or fails to probe,
+ * this function will return NULL.
+ */
+struct udevice *eth_get_dev(void)
+{
+       struct eth_uclass_priv *uc_priv;
+
+       uc_priv = eth_get_uclass_priv();
+       if (!uc_priv->current)
+               eth_errno = uclass_first_device(UCLASS_ETH,
+                                   &uc_priv->current);
+       return uc_priv->current;
+}
+
+/*
+ * Typically this will just store a device pointer.
+ * In case it was not probed, we will attempt to do so.
+ * dev may be NULL to unset the active device.
+ */
+void eth_set_dev(struct udevice *dev)
+{
+       if (dev && !device_active(dev)) {
+               eth_errno = device_probe(dev);
+               if (eth_errno)
+                       dev = NULL;
+       }
+
+       eth_get_uclass_priv()->current = dev;
+}
+
+/*
+ * Find the udevice that either has the name passed in as devname or has an
+ * alias named devname.
+ */
+struct udevice *eth_get_dev_by_name(const char *devname)
+{
+       int seq = -1;
+       char *endp = NULL;
+       const char *startp = NULL;
+       struct udevice *it;
+       struct uclass *uc;
+       int len = strlen("eth");
+
+       /* Must be longer than 3 to be an alias */
+       if (!strncmp(devname, "eth", len) && strlen(devname) > len) {
+               startp = devname + len;
+               seq = simple_strtoul(startp, &endp, 10);
+       }
+
+       uclass_get(UCLASS_ETH, &uc);
+       uclass_foreach_dev(it, uc) {
+               /*
+                * We need the seq to be valid, so try to probe it.
+                * If the probe fails, the seq will not match since it will be
+                * -1 instead of what we are looking for.
+                * We don't care about errors from probe here. Either they won't
+                * 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().
+                */
+               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;
+       }
+
+       return NULL;
+}
+
+unsigned char *eth_get_ethaddr(void)
+{
+       struct eth_pdata *pdata;
+
+       if (eth_get_dev()) {
+               pdata = eth_get_dev()->platdata;
+               return pdata->enetaddr;
+       }
+
+       return NULL;
+}
+
+/* Set active state without calling start on the driver */
+int eth_init_state_only(void)
+{
+       struct udevice *current;
+       struct eth_device_priv *priv;
+
+       current = eth_get_dev();
+       if (!current || !device_active(current))
+               return -EINVAL;
+
+       priv = current->uclass_priv;
+       priv->state = ETH_STATE_ACTIVE;
+
+       return 0;
+}
+
+/* Set passive state without calling stop on the driver */
+void eth_halt_state_only(void)
+{
+       struct udevice *current;
+       struct eth_device_priv *priv;
+
+       current = eth_get_dev();
+       if (!current || !device_active(current))
+               return;
+
+       priv = current->uclass_priv;
+       priv->state = ETH_STATE_PASSIVE;
+}
+
+int eth_get_dev_index(void)
+{
+       if (eth_get_dev())
+               return eth_get_dev()->seq;
+       return -1;
+}
+
+static int eth_write_hwaddr(struct udevice *dev)
+{
+       struct eth_pdata *pdata = dev->platdata;
+       int ret = 0;
+
+       if (!dev || !device_active(dev))
+               return -EINVAL;
+
+       /* seq is valid since the device is active */
+       if (eth_get_ops(dev)->write_hwaddr && !eth_mac_skip(dev->seq)) {
+               if (!is_valid_ethaddr(pdata->enetaddr)) {
+                       printf("\nError: %s address %pM illegal value\n",
+                              dev->name, pdata->enetaddr);
+                       return -EINVAL;
+               }
+
+               /*
+                * Drivers are allowed to decide not to implement this at
+                * run-time. E.g. Some devices may use it and some may not.
+                */
+               ret = eth_get_ops(dev)->write_hwaddr(dev);
+               if (ret == -ENOSYS)
+                       ret = 0;
+               if (ret)
+                       printf("\nWarning: %s failed to set MAC address\n",
+                              dev->name);
+       }
+
+       return ret;
+}
+
+static int on_ethaddr(const char *name, const char *value, enum env_op op,
+       int flags)
+{
+       int index;
+       int retval;
+       struct udevice *dev;
+
+       /* look for an index after "eth" */
+       index = simple_strtoul(name + 3, NULL, 10);
+
+       retval = uclass_find_device_by_seq(UCLASS_ETH, index, false, &dev);
+       if (!retval) {
+               struct eth_pdata *pdata = dev->platdata;
+               switch (op) {
+               case env_op_create:
+               case env_op_overwrite:
+                       eth_parse_enetaddr(value, pdata->enetaddr);
+                       break;
+               case env_op_delete:
+                       memset(pdata->enetaddr, 0, 6);
+               }
+       }
+
+       return 0;
+}
+U_BOOT_ENV_CALLBACK(ethaddr, on_ethaddr);
+
+int eth_init(void)
+{
+       char *ethact = getenv("ethact");
+       char *ethrotate = getenv("ethrotate");
+       struct udevice *current = NULL;
+       struct udevice *old_current;
+       int ret = -ENODEV;
+
+       /*
+        * When 'ethrotate' variable is set to 'no' and 'ethact' variable
+        * is already set to an ethernet device, we should stick to 'ethact'.
+        */
+       if ((ethrotate != NULL) && (strcmp(ethrotate, "no") == 0)) {
+               if (ethact) {
+                       current = eth_get_dev_by_name(ethact);
+                       if (!current)
+                               return -EINVAL;
+               }
+       }
+
+       if (!current) {
+               current = eth_get_dev();
+               if (!current) {
+                       printf("No ethernet found.\n");
+                       return -ENODEV;
+               }
+       }
+
+       old_current = current;
+       do {
+               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 {
+                       debug("PROBE FAIL\n");
+               }
+
+               /*
+                * If ethrotate is enabled, this will change "current",
+                * otherwise we will drop out of this while loop immediately
+                */
+               eth_try_another(0);
+               /* This will ensure the new "current" attempted to probe */
+               current = eth_get_dev();
+       } while (old_current != current);
+
+       return ret;
+}
+
+void eth_halt(void)
+{
+       struct udevice *current;
+       struct eth_device_priv *priv;
+
+       current = eth_get_dev();
+       if (!current || !device_active(current))
+               return;
+
+       eth_get_ops(current)->stop(current);
+       priv = current->uclass_priv;
+       priv->state = ETH_STATE_PASSIVE;
+}
+
+int eth_is_active(struct udevice *dev)
+{
+       struct eth_device_priv *priv;
+
+       if (!dev || !device_active(dev))
+               return 0;
+
+       priv = dev_get_uclass_priv(dev);
+       return priv->state == ETH_STATE_ACTIVE;
+}
+
+int eth_send(void *packet, int length)
+{
+       struct udevice *current;
+       int ret;
+
+       current = eth_get_dev();
+       if (!current)
+               return -ENODEV;
+
+       if (!device_active(current))
+               return -EINVAL;
+
+       ret = eth_get_ops(current)->send(current, packet, length);
+       if (ret < 0) {
+               /* We cannot completely return the error at present */
+               debug("%s: send() returned error %d\n", __func__, ret);
+       }
+       return ret;
+}
+
+int eth_rx(void)
+{
+       struct udevice *current;
+       uchar *packet;
+       int flags;
+       int ret;
+       int i;
+
+       current = eth_get_dev();
+       if (!current)
+               return -ENODEV;
+
+       if (!device_active(current))
+               return -EINVAL;
+
+       /* Process up to 32 packets at one time */
+       flags = ETH_RECV_CHECK_DEVICE;
+       for (i = 0; i < 32; i++) {
+               ret = eth_get_ops(current)->recv(current, flags, &packet);
+               flags = 0;
+               if (ret > 0)
+                       net_process_received_packet(packet, ret);
+               if (ret >= 0 && eth_get_ops(current)->free_pkt)
+                       eth_get_ops(current)->free_pkt(current, packet, ret);
+               if (ret <= 0)
+                       break;
+       }
+       if (ret == -EAGAIN)
+               ret = 0;
+       if (ret < 0) {
+               /* We cannot completely return the error at present */
+               debug("%s: recv() returned error %d\n", __func__, ret);
+       }
+       return ret;
+}
+
+int eth_initialize(void)
+{
+       int num_devices = 0;
+       struct udevice *dev;
+
+       eth_common_init();
+
+       /*
+        * Devices need to write the hwaddr even if not started so that Linux
+        * will have access to the hwaddr that u-boot stored for the device.
+        * This is accomplished by attempting to probe each device and calling
+        * their write_hwaddr() operation.
+        */
+       uclass_first_device(UCLASS_ETH, &dev);
+       if (!dev) {
+               printf("No ethernet found.\n");
+               bootstage_error(BOOTSTAGE_ID_NET_ETH_START);
+       } else {
+               char *ethprime = getenv("ethprime");
+               struct udevice *prime_dev = NULL;
+
+               if (ethprime)
+                       prime_dev = eth_get_dev_by_name(ethprime);
+               if (prime_dev) {
+                       eth_set_dev(prime_dev);
+                       eth_current_changed();
+               } else {
+                       eth_set_dev(NULL);
+               }
+
+               bootstage_mark(BOOTSTAGE_ID_NET_ETH_INIT);
+               do {
+                       if (num_devices)
+                               printf(", ");
+
+                       printf("eth%d: %s", dev->seq, dev->name);
+
+                       if (ethprime && dev == prime_dev)
+                               printf(" [PRIME]");
+
+                       eth_write_hwaddr(dev);
+
+                       uclass_next_device(&dev);
+                       num_devices++;
+               } while (dev);
+
+               putc('\n');
+       }
+
+       return num_devices;
+}
+
+static int eth_post_bind(struct udevice *dev)
+{
+       if (strchr(dev->name, ' ')) {
+               printf("\nError: eth device name \"%s\" has a space!\n",
+                      dev->name);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int eth_pre_unbind(struct udevice *dev)
+{
+       /* Don't hang onto a pointer that is going away */
+       if (dev == eth_get_uclass_priv()->current)
+               eth_set_dev(NULL);
+
+       return 0;
+}
+
+static int eth_post_probe(struct udevice *dev)
+{
+       struct eth_device_priv *priv = dev->uclass_priv;
+       struct eth_pdata *pdata = dev->platdata;
+       unsigned char env_enetaddr[6];
+
+#if defined(CONFIG_NEEDS_MANUAL_RELOC)
+       struct eth_ops *ops = eth_get_ops(dev);
+       static int reloc_done;
+
+       if (!reloc_done) {
+               if (ops->start)
+                       ops->start += gd->reloc_off;
+               if (ops->send)
+                       ops->send += gd->reloc_off;
+               if (ops->recv)
+                       ops->recv += gd->reloc_off;
+               if (ops->free_pkt)
+                       ops->free_pkt += gd->reloc_off;
+               if (ops->stop)
+                       ops->stop += gd->reloc_off;
+#ifdef CONFIG_MCAST_TFTP
+               if (ops->mcast)
+                       ops->mcast += gd->reloc_off;
+#endif
+               if (ops->write_hwaddr)
+                       ops->write_hwaddr += gd->reloc_off;
+               if (ops->read_rom_hwaddr)
+                       ops->read_rom_hwaddr += gd->reloc_off;
+
+               reloc_done++;
+       }
+#endif
+
+       priv->state = ETH_STATE_INIT;
+
+       /* Check if the device has a MAC address in ROM */
+       if (eth_get_ops(dev)->read_rom_hwaddr)
+               eth_get_ops(dev)->read_rom_hwaddr(dev);
+
+       eth_getenv_enetaddr_by_index("eth", dev->seq, env_enetaddr);
+       if (!is_zero_ethaddr(env_enetaddr)) {
+               if (!is_zero_ethaddr(pdata->enetaddr) &&
+                   memcmp(pdata->enetaddr, env_enetaddr, 6)) {
+                       printf("\nWarning: %s MAC addresses don't match:\n",
+                              dev->name);
+                       printf("Address in SROM is         %pM\n",
+                              pdata->enetaddr);
+                       printf("Address in environment is  %pM\n",
+                              env_enetaddr);
+               }
+
+               /* Override the ROM MAC address */
+               memcpy(pdata->enetaddr, env_enetaddr, 6);
+       } else if (is_valid_ethaddr(pdata->enetaddr)) {
+               eth_setenv_enetaddr_by_index("eth", dev->seq, pdata->enetaddr);
+               printf("\nWarning: %s using MAC address from ROM\n",
+                      dev->name);
+       } else if (is_zero_ethaddr(pdata->enetaddr)) {
+#ifdef CONFIG_NET_RANDOM_ETHADDR
+               net_random_ethaddr(pdata->enetaddr);
+               printf("\nWarning: %s (eth%d) using random MAC address - %pM\n",
+                      dev->name, dev->seq, pdata->enetaddr);
+#else
+               printf("\nError: %s address not set.\n",
+                      dev->name);
+               return -EINVAL;
+#endif
+       }
+
+       return 0;
+}
+
+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;
+}
+
+UCLASS_DRIVER(eth) = {
+       .name           = "eth",
+       .id             = UCLASS_ETH,
+       .post_bind      = eth_post_bind,
+       .pre_unbind     = eth_pre_unbind,
+       .post_probe     = eth_post_probe,
+       .pre_remove     = eth_pre_remove,
+       .priv_auto_alloc_size = sizeof(struct eth_uclass_priv),
+       .per_device_auto_alloc_size = sizeof(struct eth_device_priv),
+       .flags          = DM_UC_FLAG_SEQ_ALIAS,
+};
diff --git a/net/eth.c b/net/eth.c
deleted file mode 100644 (file)
index 45fe6e3..0000000
--- a/net/eth.c
+++ /dev/null
@@ -1,1139 +0,0 @@
-/*
- * (C) Copyright 2001-2015
- * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
- * Joe Hershberger, National Instruments
- *
- * SPDX-License-Identifier:    GPL-2.0+
- */
-
-#include <common.h>
-#include <command.h>
-#include <dm.h>
-#include <environment.h>
-#include <net.h>
-#include <miiphy.h>
-#include <phy.h>
-#include <asm/errno.h>
-#include <dm/device-internal.h>
-#include <dm/uclass-internal.h>
-
-DECLARE_GLOBAL_DATA_PTR;
-
-void eth_parse_enetaddr(const char *addr, uchar *enetaddr)
-{
-       char *end;
-       int i;
-
-       for (i = 0; i < 6; ++i) {
-               enetaddr[i] = addr ? simple_strtoul(addr, &end, 16) : 0;
-               if (addr)
-                       addr = (*end) ? end + 1 : end;
-       }
-}
-
-int eth_getenv_enetaddr(const char *name, uchar *enetaddr)
-{
-       eth_parse_enetaddr(getenv(name), enetaddr);
-       return is_valid_ethaddr(enetaddr);
-}
-
-int eth_setenv_enetaddr(const char *name, const uchar *enetaddr)
-{
-       char buf[20];
-
-       sprintf(buf, "%pM", enetaddr);
-
-       return setenv(name, buf);
-}
-
-int eth_getenv_enetaddr_by_index(const char *base_name, int index,
-                                uchar *enetaddr)
-{
-       char enetvar[32];
-       sprintf(enetvar, index ? "%s%daddr" : "%saddr", base_name, index);
-       return eth_getenv_enetaddr(enetvar, enetaddr);
-}
-
-static inline int eth_setenv_enetaddr_by_index(const char *base_name, int index,
-                                uchar *enetaddr)
-{
-       char enetvar[32];
-       sprintf(enetvar, index ? "%s%daddr" : "%saddr", base_name, index);
-       return eth_setenv_enetaddr(enetvar, enetaddr);
-}
-
-static int eth_mac_skip(int index)
-{
-       char enetvar[15];
-       char *skip_state;
-
-       sprintf(enetvar, index ? "eth%dmacskip" : "ethmacskip", index);
-       skip_state = getenv(enetvar);
-       return skip_state != NULL;
-}
-
-static void eth_current_changed(void);
-
-/*
- * CPU and board-specific Ethernet initializations.  Aliased function
- * signals caller to move on
- */
-static int __def_eth_init(bd_t *bis)
-{
-       return -1;
-}
-int cpu_eth_init(bd_t *bis) __attribute__((weak, alias("__def_eth_init")));
-int board_eth_init(bd_t *bis) __attribute__((weak, alias("__def_eth_init")));
-
-static void eth_common_init(void)
-{
-       bootstage_mark(BOOTSTAGE_ID_NET_ETH_START);
-#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) || defined(CONFIG_PHYLIB)
-       miiphy_init();
-#endif
-
-#ifdef CONFIG_PHYLIB
-       phy_init();
-#endif
-
-       /*
-        * If board-specific initialization exists, call it.
-        * If not, call a CPU-specific one
-        */
-       if (board_eth_init != __def_eth_init) {
-               if (board_eth_init(gd->bd) < 0)
-                       printf("Board Net Initialization Failed\n");
-       } else if (cpu_eth_init != __def_eth_init) {
-               if (cpu_eth_init(gd->bd) < 0)
-                       printf("CPU Net Initialization Failed\n");
-       } else {
-#ifndef CONFIG_DM_ETH
-               printf("Net Initialization Skipped\n");
-#endif
-       }
-}
-
-#ifdef CONFIG_DM_ETH
-/**
- * struct eth_device_priv - private structure for each Ethernet device
- *
- * @state: The state of the Ethernet MAC driver (defined by enum eth_state_t)
- */
-struct eth_device_priv {
-       enum eth_state_t state;
-};
-
-/**
- * struct eth_uclass_priv - The structure attached to the uclass itself
- *
- * @current: The Ethernet device that the network functions are using
- */
-struct eth_uclass_priv {
-       struct udevice *current;
-};
-
-/* eth_errno - This stores the most recent failure code from DM functions */
-static int eth_errno;
-
-static struct eth_uclass_priv *eth_get_uclass_priv(void)
-{
-       struct uclass *uc;
-
-       uclass_get(UCLASS_ETH, &uc);
-       assert(uc);
-       return uc->priv;
-}
-
-static void eth_set_current_to_next(void)
-{
-       struct eth_uclass_priv *uc_priv;
-
-       uc_priv = eth_get_uclass_priv();
-       if (uc_priv->current)
-               uclass_next_device(&uc_priv->current);
-       if (!uc_priv->current)
-               uclass_first_device(UCLASS_ETH, &uc_priv->current);
-}
-
-/*
- * Typically this will simply return the active device.
- * In the case where the most recent active device was unset, this will attempt
- * to return the first device. If that device doesn't exist or fails to probe,
- * this function will return NULL.
- */
-struct udevice *eth_get_dev(void)
-{
-       struct eth_uclass_priv *uc_priv;
-
-       uc_priv = eth_get_uclass_priv();
-       if (!uc_priv->current)
-               eth_errno = uclass_first_device(UCLASS_ETH,
-                                   &uc_priv->current);
-       return uc_priv->current;
-}
-
-/*
- * Typically this will just store a device pointer.
- * In case it was not probed, we will attempt to do so.
- * dev may be NULL to unset the active device.
- */
-static void eth_set_dev(struct udevice *dev)
-{
-       if (dev && !device_active(dev)) {
-               eth_errno = device_probe(dev);
-               if (eth_errno)
-                       dev = NULL;
-       }
-
-       eth_get_uclass_priv()->current = dev;
-}
-
-/*
- * Find the udevice that either has the name passed in as devname or has an
- * alias named devname.
- */
-struct udevice *eth_get_dev_by_name(const char *devname)
-{
-       int seq = -1;
-       char *endp = NULL;
-       const char *startp = NULL;
-       struct udevice *it;
-       struct uclass *uc;
-       int len = strlen("eth");
-
-       /* Must be longer than 3 to be an alias */
-       if (!strncmp(devname, "eth", len) && strlen(devname) > len) {
-               startp = devname + len;
-               seq = simple_strtoul(startp, &endp, 10);
-       }
-
-       uclass_get(UCLASS_ETH, &uc);
-       uclass_foreach_dev(it, uc) {
-               /*
-                * We need the seq to be valid, so try to probe it.
-                * If the probe fails, the seq will not match since it will be
-                * -1 instead of what we are looking for.
-                * We don't care about errors from probe here. Either they won't
-                * 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().
-                */
-               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;
-       }
-
-       return NULL;
-}
-
-unsigned char *eth_get_ethaddr(void)
-{
-       struct eth_pdata *pdata;
-
-       if (eth_get_dev()) {
-               pdata = eth_get_dev()->platdata;
-               return pdata->enetaddr;
-       }
-
-       return NULL;
-}
-
-/* Set active state without calling start on the driver */
-int eth_init_state_only(void)
-{
-       struct udevice *current;
-       struct eth_device_priv *priv;
-
-       current = eth_get_dev();
-       if (!current || !device_active(current))
-               return -EINVAL;
-
-       priv = current->uclass_priv;
-       priv->state = ETH_STATE_ACTIVE;
-
-       return 0;
-}
-
-/* Set passive state without calling stop on the driver */
-void eth_halt_state_only(void)
-{
-       struct udevice *current;
-       struct eth_device_priv *priv;
-
-       current = eth_get_dev();
-       if (!current || !device_active(current))
-               return;
-
-       priv = current->uclass_priv;
-       priv->state = ETH_STATE_PASSIVE;
-}
-
-int eth_get_dev_index(void)
-{
-       if (eth_get_dev())
-               return eth_get_dev()->seq;
-       return -1;
-}
-
-static int eth_write_hwaddr(struct udevice *dev)
-{
-       struct eth_pdata *pdata = dev->platdata;
-       int ret = 0;
-
-       if (!dev || !device_active(dev))
-               return -EINVAL;
-
-       /* seq is valid since the device is active */
-       if (eth_get_ops(dev)->write_hwaddr && !eth_mac_skip(dev->seq)) {
-               if (!is_valid_ethaddr(pdata->enetaddr)) {
-                       printf("\nError: %s address %pM illegal value\n",
-                              dev->name, pdata->enetaddr);
-                       return -EINVAL;
-               }
-
-               /*
-                * Drivers are allowed to decide not to implement this at
-                * run-time. E.g. Some devices may use it and some may not.
-                */
-               ret = eth_get_ops(dev)->write_hwaddr(dev);
-               if (ret == -ENOSYS)
-                       ret = 0;
-               if (ret)
-                       printf("\nWarning: %s failed to set MAC address\n",
-                              dev->name);
-       }
-
-       return ret;
-}
-
-static int on_ethaddr(const char *name, const char *value, enum env_op op,
-       int flags)
-{
-       int index;
-       int retval;
-       struct udevice *dev;
-
-       /* look for an index after "eth" */
-       index = simple_strtoul(name + 3, NULL, 10);
-
-       retval = uclass_find_device_by_seq(UCLASS_ETH, index, false, &dev);
-       if (!retval) {
-               struct eth_pdata *pdata = dev->platdata;
-               switch (op) {
-               case env_op_create:
-               case env_op_overwrite:
-                       eth_parse_enetaddr(value, pdata->enetaddr);
-                       break;
-               case env_op_delete:
-                       memset(pdata->enetaddr, 0, 6);
-               }
-       }
-
-       return 0;
-}
-U_BOOT_ENV_CALLBACK(ethaddr, on_ethaddr);
-
-int eth_init(void)
-{
-       char *ethact = getenv("ethact");
-       char *ethrotate = getenv("ethrotate");
-       struct udevice *current = NULL;
-       struct udevice *old_current;
-       int ret = -ENODEV;
-
-       /*
-        * When 'ethrotate' variable is set to 'no' and 'ethact' variable
-        * is already set to an ethernet device, we should stick to 'ethact'.
-        */
-       if ((ethrotate != NULL) && (strcmp(ethrotate, "no") == 0)) {
-               if (ethact) {
-                       current = eth_get_dev_by_name(ethact);
-                       if (!current)
-                               return -EINVAL;
-               }
-       }
-
-       if (!current) {
-               current = eth_get_dev();
-               if (!current) {
-                       printf("No ethernet found.\n");
-                       return -ENODEV;
-               }
-       }
-
-       old_current = current;
-       do {
-               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 {
-                       debug("PROBE FAIL\n");
-               }
-
-               /*
-                * If ethrotate is enabled, this will change "current",
-                * otherwise we will drop out of this while loop immediately
-                */
-               eth_try_another(0);
-               /* This will ensure the new "current" attempted to probe */
-               current = eth_get_dev();
-       } while (old_current != current);
-
-       return ret;
-}
-
-void eth_halt(void)
-{
-       struct udevice *current;
-       struct eth_device_priv *priv;
-
-       current = eth_get_dev();
-       if (!current || !device_active(current))
-               return;
-
-       eth_get_ops(current)->stop(current);
-       priv = current->uclass_priv;
-       priv->state = ETH_STATE_PASSIVE;
-}
-
-int eth_is_active(struct udevice *dev)
-{
-       struct eth_device_priv *priv;
-
-       if (!dev || !device_active(dev))
-               return 0;
-
-       priv = dev_get_uclass_priv(dev);
-       return priv->state == ETH_STATE_ACTIVE;
-}
-
-int eth_send(void *packet, int length)
-{
-       struct udevice *current;
-       int ret;
-
-       current = eth_get_dev();
-       if (!current)
-               return -ENODEV;
-
-       if (!device_active(current))
-               return -EINVAL;
-
-       ret = eth_get_ops(current)->send(current, packet, length);
-       if (ret < 0) {
-               /* We cannot completely return the error at present */
-               debug("%s: send() returned error %d\n", __func__, ret);
-       }
-       return ret;
-}
-
-int eth_rx(void)
-{
-       struct udevice *current;
-       uchar *packet;
-       int flags;
-       int ret;
-       int i;
-
-       current = eth_get_dev();
-       if (!current)
-               return -ENODEV;
-
-       if (!device_active(current))
-               return -EINVAL;
-
-       /* Process up to 32 packets at one time */
-       flags = ETH_RECV_CHECK_DEVICE;
-       for (i = 0; i < 32; i++) {
-               ret = eth_get_ops(current)->recv(current, flags, &packet);
-               flags = 0;
-               if (ret > 0)
-                       net_process_received_packet(packet, ret);
-               if (ret >= 0 && eth_get_ops(current)->free_pkt)
-                       eth_get_ops(current)->free_pkt(current, packet, ret);
-               if (ret <= 0)
-                       break;
-       }
-       if (ret == -EAGAIN)
-               ret = 0;
-       if (ret < 0) {
-               /* We cannot completely return the error at present */
-               debug("%s: recv() returned error %d\n", __func__, ret);
-       }
-       return ret;
-}
-
-int eth_initialize(void)
-{
-       int num_devices = 0;
-       struct udevice *dev;
-
-       eth_common_init();
-
-       /*
-        * Devices need to write the hwaddr even if not started so that Linux
-        * will have access to the hwaddr that u-boot stored for the device.
-        * This is accomplished by attempting to probe each device and calling
-        * their write_hwaddr() operation.
-        */
-       uclass_first_device(UCLASS_ETH, &dev);
-       if (!dev) {
-               printf("No ethernet found.\n");
-               bootstage_error(BOOTSTAGE_ID_NET_ETH_START);
-       } else {
-               char *ethprime = getenv("ethprime");
-               struct udevice *prime_dev = NULL;
-
-               if (ethprime)
-                       prime_dev = eth_get_dev_by_name(ethprime);
-               if (prime_dev) {
-                       eth_set_dev(prime_dev);
-                       eth_current_changed();
-               } else {
-                       eth_set_dev(NULL);
-               }
-
-               bootstage_mark(BOOTSTAGE_ID_NET_ETH_INIT);
-               do {
-                       if (num_devices)
-                               printf(", ");
-
-                       printf("eth%d: %s", dev->seq, dev->name);
-
-                       if (ethprime && dev == prime_dev)
-                               printf(" [PRIME]");
-
-                       eth_write_hwaddr(dev);
-
-                       uclass_next_device(&dev);
-                       num_devices++;
-               } while (dev);
-
-               putc('\n');
-       }
-
-       return num_devices;
-}
-
-static int eth_post_bind(struct udevice *dev)
-{
-       if (strchr(dev->name, ' ')) {
-               printf("\nError: eth device name \"%s\" has a space!\n",
-                      dev->name);
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
-static int eth_pre_unbind(struct udevice *dev)
-{
-       /* Don't hang onto a pointer that is going away */
-       if (dev == eth_get_uclass_priv()->current)
-               eth_set_dev(NULL);
-
-       return 0;
-}
-
-static int eth_post_probe(struct udevice *dev)
-{
-       struct eth_device_priv *priv = dev->uclass_priv;
-       struct eth_pdata *pdata = dev->platdata;
-       unsigned char env_enetaddr[6];
-
-#if defined(CONFIG_NEEDS_MANUAL_RELOC)
-       struct eth_ops *ops = eth_get_ops(dev);
-       static int reloc_done;
-
-       if (!reloc_done) {
-               if (ops->start)
-                       ops->start += gd->reloc_off;
-               if (ops->send)
-                       ops->send += gd->reloc_off;
-               if (ops->recv)
-                       ops->recv += gd->reloc_off;
-               if (ops->free_pkt)
-                       ops->free_pkt += gd->reloc_off;
-               if (ops->stop)
-                       ops->stop += gd->reloc_off;
-#ifdef CONFIG_MCAST_TFTP
-               if (ops->mcast)
-                       ops->mcast += gd->reloc_off;
-#endif
-               if (ops->write_hwaddr)
-                       ops->write_hwaddr += gd->reloc_off;
-               if (ops->read_rom_hwaddr)
-                       ops->read_rom_hwaddr += gd->reloc_off;
-
-               reloc_done++;
-       }
-#endif
-
-       priv->state = ETH_STATE_INIT;
-
-       /* Check if the device has a MAC address in ROM */
-       if (eth_get_ops(dev)->read_rom_hwaddr)
-               eth_get_ops(dev)->read_rom_hwaddr(dev);
-
-       eth_getenv_enetaddr_by_index("eth", dev->seq, env_enetaddr);
-       if (!is_zero_ethaddr(env_enetaddr)) {
-               if (!is_zero_ethaddr(pdata->enetaddr) &&
-                   memcmp(pdata->enetaddr, env_enetaddr, 6)) {
-                       printf("\nWarning: %s MAC addresses don't match:\n",
-                              dev->name);
-                       printf("Address in SROM is         %pM\n",
-                              pdata->enetaddr);
-                       printf("Address in environment is  %pM\n",
-                              env_enetaddr);
-               }
-
-               /* Override the ROM MAC address */
-               memcpy(pdata->enetaddr, env_enetaddr, 6);
-       } else if (is_valid_ethaddr(pdata->enetaddr)) {
-               eth_setenv_enetaddr_by_index("eth", dev->seq, pdata->enetaddr);
-               printf("\nWarning: %s using MAC address from ROM\n",
-                      dev->name);
-       } else if (is_zero_ethaddr(pdata->enetaddr)) {
-#ifdef CONFIG_NET_RANDOM_ETHADDR
-               net_random_ethaddr(pdata->enetaddr);
-               printf("\nWarning: %s (eth%d) using random MAC address - %pM\n",
-                      dev->name, dev->seq, pdata->enetaddr);
-#else
-               printf("\nError: %s address not set.\n",
-                      dev->name);
-               return -EINVAL;
-#endif
-       }
-
-       return 0;
-}
-
-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;
-}
-
-UCLASS_DRIVER(eth) = {
-       .name           = "eth",
-       .id             = UCLASS_ETH,
-       .post_bind      = eth_post_bind,
-       .pre_unbind     = eth_pre_unbind,
-       .post_probe     = eth_post_probe,
-       .pre_remove     = eth_pre_remove,
-       .priv_auto_alloc_size = sizeof(struct eth_uclass_priv),
-       .per_device_auto_alloc_size = sizeof(struct eth_device_priv),
-       .flags          = DM_UC_FLAG_SEQ_ALIAS,
-};
-#endif /* #ifdef CONFIG_DM_ETH */
-
-#ifndef CONFIG_DM_ETH
-
-#ifdef CONFIG_API
-static struct {
-       uchar data[PKTSIZE];
-       int length;
-} eth_rcv_bufs[PKTBUFSRX];
-
-static unsigned int eth_rcv_current, eth_rcv_last;
-#endif
-
-static struct eth_device *eth_devices;
-struct eth_device *eth_current;
-
-static void eth_set_current_to_next(void)
-{
-       eth_current = eth_current->next;
-}
-
-static void eth_set_dev(struct eth_device *dev)
-{
-       eth_current = dev;
-}
-
-struct eth_device *eth_get_dev_by_name(const char *devname)
-{
-       struct eth_device *dev, *target_dev;
-
-       BUG_ON(devname == NULL);
-
-       if (!eth_devices)
-               return NULL;
-
-       dev = eth_devices;
-       target_dev = NULL;
-       do {
-               if (strcmp(devname, dev->name) == 0) {
-                       target_dev = dev;
-                       break;
-               }
-               dev = dev->next;
-       } while (dev != eth_devices);
-
-       return target_dev;
-}
-
-struct eth_device *eth_get_dev_by_index(int index)
-{
-       struct eth_device *dev, *target_dev;
-
-       if (!eth_devices)
-               return NULL;
-
-       dev = eth_devices;
-       target_dev = NULL;
-       do {
-               if (dev->index == index) {
-                       target_dev = dev;
-                       break;
-               }
-               dev = dev->next;
-       } while (dev != eth_devices);
-
-       return target_dev;
-}
-
-int eth_get_dev_index(void)
-{
-       if (!eth_current)
-               return -1;
-
-       return eth_current->index;
-}
-
-static int on_ethaddr(const char *name, const char *value, enum env_op op,
-       int flags)
-{
-       int index;
-       struct eth_device *dev;
-
-       if (!eth_devices)
-               return 0;
-
-       /* look for an index after "eth" */
-       index = simple_strtoul(name + 3, NULL, 10);
-
-       dev = eth_devices;
-       do {
-               if (dev->index == index) {
-                       switch (op) {
-                       case env_op_create:
-                       case env_op_overwrite:
-                               eth_parse_enetaddr(value, dev->enetaddr);
-                               break;
-                       case env_op_delete:
-                               memset(dev->enetaddr, 0, 6);
-                       }
-               }
-               dev = dev->next;
-       } while (dev != eth_devices);
-
-       return 0;
-}
-U_BOOT_ENV_CALLBACK(ethaddr, on_ethaddr);
-
-int eth_write_hwaddr(struct eth_device *dev, const char *base_name,
-                  int eth_number)
-{
-       unsigned char env_enetaddr[6];
-       int ret = 0;
-
-       eth_getenv_enetaddr_by_index(base_name, eth_number, env_enetaddr);
-
-       if (!is_zero_ethaddr(env_enetaddr)) {
-               if (!is_zero_ethaddr(dev->enetaddr) &&
-                   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);
-       } else if (is_valid_ethaddr(dev->enetaddr)) {
-               eth_setenv_enetaddr_by_index(base_name, eth_number,
-                                            dev->enetaddr);
-       } else if (is_zero_ethaddr(dev->enetaddr)) {
-#ifdef CONFIG_NET_RANDOM_ETHADDR
-               net_random_ethaddr(dev->enetaddr);
-               printf("\nWarning: %s (eth%d) using random MAC address - %pM\n",
-                      dev->name, eth_number, dev->enetaddr);
-#else
-               printf("\nError: %s address not set.\n",
-                      dev->name);
-               return -EINVAL;
-#endif
-       }
-
-       if (dev->write_hwaddr && !eth_mac_skip(eth_number)) {
-               if (!is_valid_ethaddr(dev->enetaddr)) {
-                       printf("\nError: %s address %pM illegal value\n",
-                              dev->name, dev->enetaddr);
-                       return -EINVAL;
-               }
-
-               ret = dev->write_hwaddr(dev);
-               if (ret)
-                       printf("\nWarning: %s failed to set MAC address\n",
-                              dev->name);
-       }
-
-       return ret;
-}
-
-int eth_register(struct eth_device *dev)
-{
-       struct eth_device *d;
-       static int index;
-
-       assert(strlen(dev->name) < sizeof(dev->name));
-
-       if (!eth_devices) {
-               eth_devices = dev;
-               eth_current = dev;
-               eth_current_changed();
-       } else {
-               for (d = eth_devices; d->next != eth_devices; d = d->next)
-                       ;
-               d->next = dev;
-       }
-
-       dev->state = ETH_STATE_INIT;
-       dev->next  = eth_devices;
-       dev->index = index++;
-
-       return 0;
-}
-
-int eth_unregister(struct eth_device *dev)
-{
-       struct eth_device *cur;
-
-       /* No device */
-       if (!eth_devices)
-               return -ENODEV;
-
-       for (cur = eth_devices; cur->next != eth_devices && cur->next != dev;
-            cur = cur->next)
-               ;
-
-       /* Device not found */
-       if (cur->next != dev)
-               return -ENODEV;
-
-       cur->next = dev->next;
-
-       if (eth_devices == dev)
-               eth_devices = dev->next == eth_devices ? NULL : dev->next;
-
-       if (eth_current == dev) {
-               eth_current = eth_devices;
-               eth_current_changed();
-       }
-
-       return 0;
-}
-
-int eth_initialize(void)
-{
-       int num_devices = 0;
-
-       eth_devices = NULL;
-       eth_current = NULL;
-       eth_common_init();
-
-       if (!eth_devices) {
-               puts("No ethernet found.\n");
-               bootstage_error(BOOTSTAGE_ID_NET_ETH_START);
-       } else {
-               struct eth_device *dev = eth_devices;
-               char *ethprime = getenv("ethprime");
-
-               bootstage_mark(BOOTSTAGE_ID_NET_ETH_INIT);
-               do {
-                       if (dev->index)
-                               puts(", ");
-
-                       printf("%s", dev->name);
-
-                       if (ethprime && strcmp(dev->name, ethprime) == 0) {
-                               eth_current = dev;
-                               puts(" [PRIME]");
-                       }
-
-                       if (strchr(dev->name, ' '))
-                               puts("\nWarning: eth device name has a space!"
-                                       "\n");
-
-                       eth_write_hwaddr(dev, "eth", dev->index);
-
-                       dev = dev->next;
-                       num_devices++;
-               } while (dev != eth_devices);
-
-               eth_current_changed();
-               putc('\n');
-       }
-
-       return num_devices;
-}
-
-#ifdef CONFIG_MCAST_TFTP
-/* Multicast.
- * mcast_addr: multicast ipaddr from which multicast Mac is made
- * join: 1=join, 0=leave.
- */
-int eth_mcast_join(struct in_addr mcast_ip, int join)
-{
-       u8 mcast_mac[6];
-       if (!eth_current || !eth_current->mcast)
-               return -1;
-       mcast_mac[5] = htonl(mcast_ip.s_addr) & 0xff;
-       mcast_mac[4] = (htonl(mcast_ip.s_addr)>>8) & 0xff;
-       mcast_mac[3] = (htonl(mcast_ip.s_addr)>>16) & 0x7f;
-       mcast_mac[2] = 0x5e;
-       mcast_mac[1] = 0x0;
-       mcast_mac[0] = 0x1;
-       return eth_current->mcast(eth_current, mcast_mac, join);
-}
-
-/* the 'way' for ethernet-CRC-32. Spliced in from Linux lib/crc32.c
- * and this is the ethernet-crc method needed for TSEC -- and perhaps
- * some other adapter -- hash tables
- */
-#define CRCPOLY_LE 0xedb88320
-u32 ether_crc(size_t len, unsigned char const *p)
-{
-       int i;
-       u32 crc;
-       crc = ~0;
-       while (len--) {
-               crc ^= *p++;
-               for (i = 0; i < 8; i++)
-                       crc = (crc >> 1) ^ ((crc & 1) ? CRCPOLY_LE : 0);
-       }
-       /* an reverse the bits, cuz of way they arrive -- last-first */
-       crc = (crc >> 16) | (crc << 16);
-       crc = (crc >> 8 & 0x00ff00ff) | (crc << 8 & 0xff00ff00);
-       crc = (crc >> 4 & 0x0f0f0f0f) | (crc << 4 & 0xf0f0f0f0);
-       crc = (crc >> 2 & 0x33333333) | (crc << 2 & 0xcccccccc);
-       crc = (crc >> 1 & 0x55555555) | (crc << 1 & 0xaaaaaaaa);
-       return crc;
-}
-
-#endif
-
-
-int eth_init(void)
-{
-       struct eth_device *old_current;
-
-       if (!eth_current) {
-               puts("No ethernet found.\n");
-               return -ENODEV;
-       }
-
-       old_current = eth_current;
-       do {
-               debug("Trying %s\n", eth_current->name);
-
-               if (eth_current->init(eth_current, gd->bd) >= 0) {
-                       eth_current->state = ETH_STATE_ACTIVE;
-
-                       return 0;
-               }
-               debug("FAIL\n");
-
-               eth_try_another(0);
-       } while (old_current != eth_current);
-
-       return -ETIMEDOUT;
-}
-
-void eth_halt(void)
-{
-       if (!eth_current)
-               return;
-
-       eth_current->halt(eth_current);
-
-       eth_current->state = ETH_STATE_PASSIVE;
-}
-
-int eth_is_active(struct eth_device *dev)
-{
-       return dev && dev->state == ETH_STATE_ACTIVE;
-}
-
-int eth_send(void *packet, int length)
-{
-       if (!eth_current)
-               return -ENODEV;
-
-       return eth_current->send(eth_current, packet, length);
-}
-
-int eth_rx(void)
-{
-       if (!eth_current)
-               return -ENODEV;
-
-       return eth_current->recv(eth_current);
-}
-#endif /* ifndef CONFIG_DM_ETH */
-
-#ifdef CONFIG_API
-static void eth_save_packet(void *packet, int length)
-{
-       char *p = packet;
-       int i;
-
-       if ((eth_rcv_last+1) % PKTBUFSRX == eth_rcv_current)
-               return;
-
-       if (PKTSIZE < length)
-               return;
-
-       for (i = 0; i < length; i++)
-               eth_rcv_bufs[eth_rcv_last].data[i] = p[i];
-
-       eth_rcv_bufs[eth_rcv_last].length = length;
-       eth_rcv_last = (eth_rcv_last + 1) % PKTBUFSRX;
-}
-
-int eth_receive(void *packet, int length)
-{
-       char *p = packet;
-       void *pp = push_packet;
-       int i;
-
-       if (eth_rcv_current == eth_rcv_last) {
-               push_packet = eth_save_packet;
-               eth_rx();
-               push_packet = pp;
-
-               if (eth_rcv_current == eth_rcv_last)
-                       return -1;
-       }
-
-       length = min(eth_rcv_bufs[eth_rcv_current].length, length);
-
-       for (i = 0; i < length; i++)
-               p[i] = eth_rcv_bufs[eth_rcv_current].data[i];
-
-       eth_rcv_current = (eth_rcv_current + 1) % PKTBUFSRX;
-       return length;
-}
-#endif /* CONFIG_API */
-
-static void eth_current_changed(void)
-{
-       char *act = getenv("ethact");
-       char *ethrotate;
-
-       /*
-        * The call to eth_get_dev() below has a side effect of rotating
-        * ethernet device if uc_priv->current == NULL. This is not what
-        * we want when 'ethrotate' variable is 'no'.
-        */
-       ethrotate = getenv("ethrotate");
-       if ((ethrotate != NULL) && (strcmp(ethrotate, "no") == 0))
-               return;
-
-       /* update current ethernet name */
-       if (eth_get_dev()) {
-               if (act == NULL || strcmp(act, eth_get_name()) != 0)
-                       setenv("ethact", eth_get_name());
-       }
-       /*
-        * remove the variable completely if there is no active
-        * interface
-        */
-       else if (act != NULL)
-               setenv("ethact", NULL);
-}
-
-void eth_try_another(int first_restart)
-{
-       static void *first_failed;
-       char *ethrotate;
-
-       /*
-        * Do not rotate between network interfaces when
-        * 'ethrotate' variable is set to 'no'.
-        */
-       ethrotate = getenv("ethrotate");
-       if ((ethrotate != NULL) && (strcmp(ethrotate, "no") == 0))
-               return;
-
-       if (!eth_get_dev())
-               return;
-
-       if (first_restart)
-               first_failed = eth_get_dev();
-
-       eth_set_current_to_next();
-
-       eth_current_changed();
-
-       if (first_failed == eth_get_dev())
-               net_restart_wrap = 1;
-}
-
-void eth_set_current(void)
-{
-       static char *act;
-       static int  env_changed_id;
-       int     env_id;
-
-       env_id = get_env_id();
-       if ((act == NULL) || (env_changed_id != env_id)) {
-               act = getenv("ethact");
-               env_changed_id = env_id;
-       }
-
-       if (act == NULL) {
-               char *ethprime = getenv("ethprime");
-               void *dev = NULL;
-
-               if (ethprime)
-                       dev = eth_get_dev_by_name(ethprime);
-               if (dev)
-                       eth_set_dev(dev);
-               else
-                       eth_set_dev(NULL);
-       } else {
-               eth_set_dev(eth_get_dev_by_name(act));
-       }
-
-       eth_current_changed();
-}
-
-const char *eth_get_name(void)
-{
-       return eth_get_dev() ? eth_get_dev()->name : "unknown";
-}
diff --git a/net/eth_common.c b/net/eth_common.c
new file mode 100644 (file)
index 0000000..2880901
--- /dev/null
@@ -0,0 +1,166 @@
+/*
+ * (C) Copyright 2001-2015
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ * Joe Hershberger, National Instruments
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <miiphy.h>
+#include <net.h>
+#include "eth_internal.h"
+
+void eth_parse_enetaddr(const char *addr, uchar *enetaddr)
+{
+       char *end;
+       int i;
+
+       for (i = 0; i < 6; ++i) {
+               enetaddr[i] = addr ? simple_strtoul(addr, &end, 16) : 0;
+               if (addr)
+                       addr = (*end) ? end + 1 : end;
+       }
+}
+
+int eth_getenv_enetaddr(const char *name, uchar *enetaddr)
+{
+       eth_parse_enetaddr(getenv(name), enetaddr);
+       return is_valid_ethaddr(enetaddr);
+}
+
+int eth_setenv_enetaddr(const char *name, const uchar *enetaddr)
+{
+       char buf[20];
+
+       sprintf(buf, "%pM", enetaddr);
+
+       return setenv(name, buf);
+}
+
+int eth_getenv_enetaddr_by_index(const char *base_name, int index,
+                                uchar *enetaddr)
+{
+       char enetvar[32];
+       sprintf(enetvar, index ? "%s%daddr" : "%saddr", base_name, index);
+       return eth_getenv_enetaddr(enetvar, enetaddr);
+}
+
+int eth_setenv_enetaddr_by_index(const char *base_name, int index,
+                                uchar *enetaddr)
+{
+       char enetvar[32];
+       sprintf(enetvar, index ? "%s%daddr" : "%saddr", base_name, index);
+       return eth_setenv_enetaddr(enetvar, enetaddr);
+}
+
+void eth_common_init(void)
+{
+       bootstage_mark(BOOTSTAGE_ID_NET_ETH_START);
+#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) || defined(CONFIG_PHYLIB)
+       miiphy_init();
+#endif
+
+#ifdef CONFIG_PHYLIB
+       phy_init();
+#endif
+}
+
+int eth_mac_skip(int index)
+{
+       char enetvar[15];
+       char *skip_state;
+
+       sprintf(enetvar, index ? "eth%dmacskip" : "ethmacskip", index);
+       skip_state = getenv(enetvar);
+       return skip_state != NULL;
+}
+
+void eth_current_changed(void)
+{
+       char *act = getenv("ethact");
+       char *ethrotate;
+
+       /*
+        * The call to eth_get_dev() below has a side effect of rotating
+        * ethernet device if uc_priv->current == NULL. This is not what
+        * we want when 'ethrotate' variable is 'no'.
+        */
+       ethrotate = getenv("ethrotate");
+       if ((ethrotate != NULL) && (strcmp(ethrotate, "no") == 0))
+               return;
+
+       /* update current ethernet name */
+       if (eth_get_dev()) {
+               if (act == NULL || strcmp(act, eth_get_name()) != 0)
+                       setenv("ethact", eth_get_name());
+       }
+       /*
+        * remove the variable completely if there is no active
+        * interface
+        */
+       else if (act != NULL)
+               setenv("ethact", NULL);
+}
+
+void eth_try_another(int first_restart)
+{
+       static void *first_failed;
+       char *ethrotate;
+
+       /*
+        * Do not rotate between network interfaces when
+        * 'ethrotate' variable is set to 'no'.
+        */
+       ethrotate = getenv("ethrotate");
+       if ((ethrotate != NULL) && (strcmp(ethrotate, "no") == 0))
+               return;
+
+       if (!eth_get_dev())
+               return;
+
+       if (first_restart)
+               first_failed = eth_get_dev();
+
+       eth_set_current_to_next();
+
+       eth_current_changed();
+
+       if (first_failed == eth_get_dev())
+               net_restart_wrap = 1;
+}
+
+void eth_set_current(void)
+{
+       static char *act;
+       static int  env_changed_id;
+       int     env_id;
+
+       env_id = get_env_id();
+       if ((act == NULL) || (env_changed_id != env_id)) {
+               act = getenv("ethact");
+               env_changed_id = env_id;
+       }
+
+       if (act == NULL) {
+               char *ethprime = getenv("ethprime");
+               void *dev = NULL;
+
+               if (ethprime)
+                       dev = eth_get_dev_by_name(ethprime);
+               if (dev)
+                       eth_set_dev(dev);
+               else
+                       eth_set_dev(NULL);
+       } else {
+               eth_set_dev(eth_get_dev_by_name(act));
+       }
+
+       eth_current_changed();
+}
+
+const char *eth_get_name(void)
+{
+       return eth_get_dev() ? eth_get_dev()->name : "unknown";
+}
diff --git a/net/eth_internal.h b/net/eth_internal.h
new file mode 100644 (file)
index 0000000..6e4753c
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * (C) Copyright 2001-2015
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ * Joe Hershberger, National Instruments
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#ifndef __ETH_INTERNAL_H
+#define __ETH_INTERNAL_H
+
+/* Do init that is common to driver model and legacy networking */
+void eth_common_init(void);
+
+/**
+ * eth_setenv_enetaddr_by_index() - set the MAC address envrionment variable
+ *
+ * This sets up an environment variable with the given MAC address (@enetaddr).
+ * The environment variable to be set is defined by <@base_name><@index>addr.
+ * If @index is 0 it is omitted. For common Ethernet this means ethaddr,
+ * eth1addr, etc.
+ *
+ * @base_name: Base name for variable, typically "eth"
+ * @index:     Index of interface being updated (>=0)
+ * @enetaddr:  Pointer to MAC address to put into the variable
+ * @return 0 if OK, other value on error
+ */
+int eth_setenv_enetaddr_by_index(const char *base_name, int index,
+                                uchar *enetaddr);
+
+int eth_mac_skip(int index);
+void eth_current_changed(void);
+#ifdef CONFIG_DM_ETH
+void eth_set_dev(struct udevice *dev);
+#else
+void eth_set_dev(struct eth_device *dev);
+#endif
+void eth_set_current_to_next(void);
+
+#endif
diff --git a/net/eth_legacy.c b/net/eth_legacy.c
new file mode 100644 (file)
index 0000000..bdcd6ea
--- /dev/null
@@ -0,0 +1,439 @@
+/*
+ * (C) Copyright 2001-2015
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ * Joe Hershberger, National Instruments
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#include <common.h>
+#include <command.h>
+#include <environment.h>
+#include <net.h>
+#include <phy.h>
+#include <asm/errno.h>
+#include "eth_internal.h"
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/*
+ * CPU and board-specific Ethernet initializations.  Aliased function
+ * signals caller to move on
+ */
+static int __def_eth_init(bd_t *bis)
+{
+       return -1;
+}
+int cpu_eth_init(bd_t *bis) __attribute__((weak, alias("__def_eth_init")));
+int board_eth_init(bd_t *bis) __attribute__((weak, alias("__def_eth_init")));
+
+#ifdef CONFIG_API
+static struct {
+       uchar data[PKTSIZE];
+       int length;
+} eth_rcv_bufs[PKTBUFSRX];
+
+static unsigned int eth_rcv_current, eth_rcv_last;
+#endif
+
+static struct eth_device *eth_devices;
+struct eth_device *eth_current;
+
+void eth_set_current_to_next(void)
+{
+       eth_current = eth_current->next;
+}
+
+void eth_set_dev(struct eth_device *dev)
+{
+       eth_current = dev;
+}
+
+struct eth_device *eth_get_dev_by_name(const char *devname)
+{
+       struct eth_device *dev, *target_dev;
+
+       BUG_ON(devname == NULL);
+
+       if (!eth_devices)
+               return NULL;
+
+       dev = eth_devices;
+       target_dev = NULL;
+       do {
+               if (strcmp(devname, dev->name) == 0) {
+                       target_dev = dev;
+                       break;
+               }
+               dev = dev->next;
+       } while (dev != eth_devices);
+
+       return target_dev;
+}
+
+struct eth_device *eth_get_dev_by_index(int index)
+{
+       struct eth_device *dev, *target_dev;
+
+       if (!eth_devices)
+               return NULL;
+
+       dev = eth_devices;
+       target_dev = NULL;
+       do {
+               if (dev->index == index) {
+                       target_dev = dev;
+                       break;
+               }
+               dev = dev->next;
+       } while (dev != eth_devices);
+
+       return target_dev;
+}
+
+int eth_get_dev_index(void)
+{
+       if (!eth_current)
+               return -1;
+
+       return eth_current->index;
+}
+
+static int on_ethaddr(const char *name, const char *value, enum env_op op,
+       int flags)
+{
+       int index;
+       struct eth_device *dev;
+
+       if (!eth_devices)
+               return 0;
+
+       /* look for an index after "eth" */
+       index = simple_strtoul(name + 3, NULL, 10);
+
+       dev = eth_devices;
+       do {
+               if (dev->index == index) {
+                       switch (op) {
+                       case env_op_create:
+                       case env_op_overwrite:
+                               eth_parse_enetaddr(value, dev->enetaddr);
+                               break;
+                       case env_op_delete:
+                               memset(dev->enetaddr, 0, 6);
+                       }
+               }
+               dev = dev->next;
+       } while (dev != eth_devices);
+
+       return 0;
+}
+U_BOOT_ENV_CALLBACK(ethaddr, on_ethaddr);
+
+int eth_write_hwaddr(struct eth_device *dev, const char *base_name,
+                  int eth_number)
+{
+       unsigned char env_enetaddr[6];
+       int ret = 0;
+
+       eth_getenv_enetaddr_by_index(base_name, eth_number, env_enetaddr);
+
+       if (!is_zero_ethaddr(env_enetaddr)) {
+               if (!is_zero_ethaddr(dev->enetaddr) &&
+                   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);
+       } else if (is_valid_ethaddr(dev->enetaddr)) {
+               eth_setenv_enetaddr_by_index(base_name, eth_number,
+                                            dev->enetaddr);
+       } else if (is_zero_ethaddr(dev->enetaddr)) {
+#ifdef CONFIG_NET_RANDOM_ETHADDR
+               net_random_ethaddr(dev->enetaddr);
+               printf("\nWarning: %s (eth%d) using random MAC address - %pM\n",
+                      dev->name, eth_number, dev->enetaddr);
+#else
+               printf("\nError: %s address not set.\n",
+                      dev->name);
+               return -EINVAL;
+#endif
+       }
+
+       if (dev->write_hwaddr && !eth_mac_skip(eth_number)) {
+               if (!is_valid_ethaddr(dev->enetaddr)) {
+                       printf("\nError: %s address %pM illegal value\n",
+                              dev->name, dev->enetaddr);
+                       return -EINVAL;
+               }
+
+               ret = dev->write_hwaddr(dev);
+               if (ret)
+                       printf("\nWarning: %s failed to set MAC address\n",
+                              dev->name);
+       }
+
+       return ret;
+}
+
+int eth_register(struct eth_device *dev)
+{
+       struct eth_device *d;
+       static int index;
+
+       assert(strlen(dev->name) < sizeof(dev->name));
+
+       if (!eth_devices) {
+               eth_devices = dev;
+               eth_current = dev;
+               eth_current_changed();
+       } else {
+               for (d = eth_devices; d->next != eth_devices; d = d->next)
+                       ;
+               d->next = dev;
+       }
+
+       dev->state = ETH_STATE_INIT;
+       dev->next  = eth_devices;
+       dev->index = index++;
+
+       return 0;
+}
+
+int eth_unregister(struct eth_device *dev)
+{
+       struct eth_device *cur;
+
+       /* No device */
+       if (!eth_devices)
+               return -ENODEV;
+
+       for (cur = eth_devices; cur->next != eth_devices && cur->next != dev;
+            cur = cur->next)
+               ;
+
+       /* Device not found */
+       if (cur->next != dev)
+               return -ENODEV;
+
+       cur->next = dev->next;
+
+       if (eth_devices == dev)
+               eth_devices = dev->next == eth_devices ? NULL : dev->next;
+
+       if (eth_current == dev) {
+               eth_current = eth_devices;
+               eth_current_changed();
+       }
+
+       return 0;
+}
+
+int eth_initialize(void)
+{
+       int num_devices = 0;
+
+       eth_devices = NULL;
+       eth_current = NULL;
+       eth_common_init();
+       /*
+        * If board-specific initialization exists, call it.
+        * If not, call a CPU-specific one
+        */
+       if (board_eth_init != __def_eth_init) {
+               if (board_eth_init(gd->bd) < 0)
+                       printf("Board Net Initialization Failed\n");
+       } else if (cpu_eth_init != __def_eth_init) {
+               if (cpu_eth_init(gd->bd) < 0)
+                       printf("CPU Net Initialization Failed\n");
+       } else {
+               printf("Net Initialization Skipped\n");
+       }
+
+       if (!eth_devices) {
+               puts("No ethernet found.\n");
+               bootstage_error(BOOTSTAGE_ID_NET_ETH_START);
+       } else {
+               struct eth_device *dev = eth_devices;
+               char *ethprime = getenv("ethprime");
+
+               bootstage_mark(BOOTSTAGE_ID_NET_ETH_INIT);
+               do {
+                       if (dev->index)
+                               puts(", ");
+
+                       printf("%s", dev->name);
+
+                       if (ethprime && strcmp(dev->name, ethprime) == 0) {
+                               eth_current = dev;
+                               puts(" [PRIME]");
+                       }
+
+                       if (strchr(dev->name, ' '))
+                               puts("\nWarning: eth device name has a space!"
+                                       "\n");
+
+                       eth_write_hwaddr(dev, "eth", dev->index);
+
+                       dev = dev->next;
+                       num_devices++;
+               } while (dev != eth_devices);
+
+               eth_current_changed();
+               putc('\n');
+       }
+
+       return num_devices;
+}
+
+#ifdef CONFIG_MCAST_TFTP
+/* Multicast.
+ * mcast_addr: multicast ipaddr from which multicast Mac is made
+ * join: 1=join, 0=leave.
+ */
+int eth_mcast_join(struct in_addr mcast_ip, int join)
+{
+       u8 mcast_mac[6];
+       if (!eth_current || !eth_current->mcast)
+               return -1;
+       mcast_mac[5] = htonl(mcast_ip.s_addr) & 0xff;
+       mcast_mac[4] = (htonl(mcast_ip.s_addr)>>8) & 0xff;
+       mcast_mac[3] = (htonl(mcast_ip.s_addr)>>16) & 0x7f;
+       mcast_mac[2] = 0x5e;
+       mcast_mac[1] = 0x0;
+       mcast_mac[0] = 0x1;
+       return eth_current->mcast(eth_current, mcast_mac, join);
+}
+
+/* the 'way' for ethernet-CRC-32. Spliced in from Linux lib/crc32.c
+ * and this is the ethernet-crc method needed for TSEC -- and perhaps
+ * some other adapter -- hash tables
+ */
+#define CRCPOLY_LE 0xedb88320
+u32 ether_crc(size_t len, unsigned char const *p)
+{
+       int i;
+       u32 crc;
+       crc = ~0;
+       while (len--) {
+               crc ^= *p++;
+               for (i = 0; i < 8; i++)
+                       crc = (crc >> 1) ^ ((crc & 1) ? CRCPOLY_LE : 0);
+       }
+       /* an reverse the bits, cuz of way they arrive -- last-first */
+       crc = (crc >> 16) | (crc << 16);
+       crc = (crc >> 8 & 0x00ff00ff) | (crc << 8 & 0xff00ff00);
+       crc = (crc >> 4 & 0x0f0f0f0f) | (crc << 4 & 0xf0f0f0f0);
+       crc = (crc >> 2 & 0x33333333) | (crc << 2 & 0xcccccccc);
+       crc = (crc >> 1 & 0x55555555) | (crc << 1 & 0xaaaaaaaa);
+       return crc;
+}
+
+#endif
+
+
+int eth_init(void)
+{
+       struct eth_device *old_current;
+
+       if (!eth_current) {
+               puts("No ethernet found.\n");
+               return -ENODEV;
+       }
+
+       old_current = eth_current;
+       do {
+               debug("Trying %s\n", eth_current->name);
+
+               if (eth_current->init(eth_current, gd->bd) >= 0) {
+                       eth_current->state = ETH_STATE_ACTIVE;
+
+                       return 0;
+               }
+               debug("FAIL\n");
+
+               eth_try_another(0);
+       } while (old_current != eth_current);
+
+       return -ETIMEDOUT;
+}
+
+void eth_halt(void)
+{
+       if (!eth_current)
+               return;
+
+       eth_current->halt(eth_current);
+
+       eth_current->state = ETH_STATE_PASSIVE;
+}
+
+int eth_is_active(struct eth_device *dev)
+{
+       return dev && dev->state == ETH_STATE_ACTIVE;
+}
+
+int eth_send(void *packet, int length)
+{
+       if (!eth_current)
+               return -ENODEV;
+
+       return eth_current->send(eth_current, packet, length);
+}
+
+int eth_rx(void)
+{
+       if (!eth_current)
+               return -ENODEV;
+
+       return eth_current->recv(eth_current);
+}
+
+#ifdef CONFIG_API
+static void eth_save_packet(void *packet, int length)
+{
+       char *p = packet;
+       int i;
+
+       if ((eth_rcv_last+1) % PKTBUFSRX == eth_rcv_current)
+               return;
+
+       if (PKTSIZE < length)
+               return;
+
+       for (i = 0; i < length; i++)
+               eth_rcv_bufs[eth_rcv_last].data[i] = p[i];
+
+       eth_rcv_bufs[eth_rcv_last].length = length;
+       eth_rcv_last = (eth_rcv_last + 1) % PKTBUFSRX;
+}
+
+int eth_receive(void *packet, int length)
+{
+       char *p = packet;
+       void *pp = push_packet;
+       int i;
+
+       if (eth_rcv_current == eth_rcv_last) {
+               push_packet = eth_save_packet;
+               eth_rx();
+               push_packet = pp;
+
+               if (eth_rcv_current == eth_rcv_last)
+                       return -1;
+       }
+
+       length = min(eth_rcv_bufs[eth_rcv_current].length, length);
+
+       for (i = 0; i < length; i++)
+               p[i] = eth_rcv_bufs[eth_rcv_current].data[i];
+
+       eth_rcv_current = (eth_rcv_current + 1) % PKTBUFSRX;
+       return length;
+}
+#endif /* CONFIG_API */