[linux-yocto] [PATCH 14/65] ethernet: add owl 10/100M ethernet driver

Jiang Lu lu.jiang at windriver.com
Wed Dec 21 01:16:15 PST 2016


From: wurui <wurui at actions-semi.com>

commit f71183b7ae78e06172a3b4ad6bb7ffa47bc8fdd1 from
https://github.com/xapp-le/kernel.git

Change-Id: I63d01e6e52d7f2a9fdab60c1a0481522ab18cb09
---
 drivers/net/ethernet/Kconfig               |    5 +-
 drivers/net/ethernet/Makefile              |    2 +
 drivers/net/ethernet/acts/Kconfig          |   20 +
 drivers/net/ethernet/acts/Makefile         |    9 +
 drivers/net/ethernet/acts/config.h         | 2001 +++++++++++++++
 drivers/net/ethernet/acts/des.c            | 1063 ++++++++
 drivers/net/ethernet/acts/des.h            |  307 +++
 drivers/net/ethernet/acts/ec_ethtool.c     |  497 ++++
 drivers/net/ethernet/acts/ec_hardware.h    |  416 +++
 drivers/net/ethernet/acts/ec_phy.c         |  863 +++++++
 drivers/net/ethernet/acts/ethctrl.c        | 3664 +++++++++++++++++++++++++++
 drivers/net/ethernet/acts/ethctrl.h        |  248 ++
 drivers/net/ethernet/sg8201g/Kconfig       |    5 +
 drivers/net/ethernet/sg8201g/Makefile      |    9 +
 drivers/net/ethernet/sg8201g/ec_ethtool.c  |  592 +++++
 drivers/net/ethernet/sg8201g/ec_hardware.h |  382 +++
 drivers/net/ethernet/sg8201g/ec_phy.c      |  887 +++++++
 drivers/net/ethernet/sg8201g/ethctrl.c     | 3749 ++++++++++++++++++++++++++++
 drivers/net/ethernet/sg8201g/ethctrl.h     |  240 ++
 19 files changed, 14957 insertions(+), 2 deletions(-)
 mode change 100644 => 100755 drivers/net/ethernet/Kconfig
 mode change 100644 => 100755 drivers/net/ethernet/Makefile
 create mode 100755 drivers/net/ethernet/acts/Kconfig
 create mode 100755 drivers/net/ethernet/acts/Makefile
 create mode 100755 drivers/net/ethernet/acts/config.h
 create mode 100755 drivers/net/ethernet/acts/des.c
 create mode 100755 drivers/net/ethernet/acts/des.h
 create mode 100755 drivers/net/ethernet/acts/ec_ethtool.c
 create mode 100755 drivers/net/ethernet/acts/ec_hardware.h
 create mode 100755 drivers/net/ethernet/acts/ec_phy.c
 create mode 100755 drivers/net/ethernet/acts/ethctrl.c
 create mode 100755 drivers/net/ethernet/acts/ethctrl.h
 create mode 100755 drivers/net/ethernet/sg8201g/Kconfig
 create mode 100755 drivers/net/ethernet/sg8201g/Makefile
 create mode 100755 drivers/net/ethernet/sg8201g/ec_ethtool.c
 create mode 100755 drivers/net/ethernet/sg8201g/ec_hardware.h
 create mode 100755 drivers/net/ethernet/sg8201g/ec_phy.c
 create mode 100755 drivers/net/ethernet/sg8201g/ethctrl.c
 create mode 100755 drivers/net/ethernet/sg8201g/ethctrl.h

diff --git a/drivers/net/ethernet/Kconfig b/drivers/net/ethernet/Kconfig
old mode 100644
new mode 100755
index eadcb05..9ead146
--- a/drivers/net/ethernet/Kconfig
+++ b/drivers/net/ethernet/Kconfig
@@ -51,7 +51,8 @@ config CX_ECAT
 	  will be called ec_bhf.
 
 source "drivers/net/ethernet/davicom/Kconfig"
-
+source "drivers/net/ethernet/acts/Kconfig"
+source "drivers/net/ethernet/sg8201g/Kconfig"
 config DNET
 	tristate "Dave ethernet support (DNET)"
 	depends on HAS_IOMEM
@@ -77,7 +78,7 @@ source "drivers/net/ethernet/intel/Kconfig"
 source "drivers/net/ethernet/i825xx/Kconfig"
 source "drivers/net/ethernet/xscale/Kconfig"
 source "drivers/net/ethernet/icplus/Kconfig"
-
+source "drivers/net/ethernet/sg8201g/Kconfig"
 config JME
 	tristate "JMicron(R) PCI-Express Gigabit Ethernet support"
 	depends on PCI
diff --git a/drivers/net/ethernet/Makefile b/drivers/net/ethernet/Makefile
old mode 100644
new mode 100755
index 1367afc..3f39790
--- a/drivers/net/ethernet/Makefile
+++ b/drivers/net/ethernet/Makefile
@@ -84,3 +84,5 @@ obj-$(CONFIG_NET_VENDOR_VIA) += via/
 obj-$(CONFIG_NET_VENDOR_WIZNET) += wiznet/
 obj-$(CONFIG_NET_VENDOR_XILINX) += xilinx/
 obj-$(CONFIG_NET_VENDOR_XIRCOM) += xircom/
+obj-$(CONFIG_NET_VENDOR_ACTS) += acts/
+obj-$(CONFIG_NET_VENDOR_SG8201G) += sg8201g/
diff --git a/drivers/net/ethernet/acts/Kconfig b/drivers/net/ethernet/acts/Kconfig
new file mode 100755
index 0000000..ff65f2b
--- /dev/null
+++ b/drivers/net/ethernet/acts/Kconfig
@@ -0,0 +1,20 @@
+config NET_VENDOR_ACTS
+	tristate "Actions Ethernet driver"
+	default m
+	---help---
+		enable Actions Semi 520X ethernet driver
+config POLL_PHY_STATE
+	tristate "Phy state check"
+	default n
+	---help---
+		poll the phy's sate
+config PHY_REALTEK_RTL8201
+	tristate "phy type"
+	default n
+	---help---
+		use the phy as realtek rtl8201
+config PHY_CORECHIP_SR8201G
+	tristate "phy type"
+	default n
+	---help---
+		use the phy as corechip sg8201g
diff --git a/drivers/net/ethernet/acts/Makefile b/drivers/net/ethernet/acts/Makefile
new file mode 100755
index 0000000..6e4214e
--- /dev/null
+++ b/drivers/net/ethernet/acts/Makefile
@@ -0,0 +1,9 @@
+
+EXTRA_CFLAGS += -DDEF_LINUX 
+
+ifeq ($(CONFIG_MII),y)
+EXTRA_CFLAGS += -DMII
+endif
+obj-$(CONFIG_NET_VENDOR_ACTS)	+= ethernet.o
+ethernet-objs := ec_ethtool.o ec_phy.o des.o ethctrl.o
+
diff --git a/drivers/net/ethernet/acts/config.h b/drivers/net/ethernet/acts/config.h
new file mode 100755
index 0000000..ec5337e
--- /dev/null
+++ b/drivers/net/ethernet/acts/config.h
@@ -0,0 +1,2001 @@
+/**
+ * \file config.h
+ *
+ * \brief Configuration options (set of defines)
+ *
+ *  Copyright (C) 2006-2013, Brainspark B.V.
+ *
+ *  This file is part of PolarSSL (http://www.polarssl.org)
+ *  Lead Maintainer: Paul Bakker <polarssl_maintainer at polarssl.org>
+ *
+ *  All rights reserved.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * This set of compile-time options may be used to enable
+ * or disable features selectively, and reduce the global
+ * memory footprint.
+ */
+#ifndef POLARSSL_CONFIG_H
+#define POLARSSL_CONFIG_H
+
+#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_DEPRECATE)
+#define _CRT_SECURE_NO_DEPRECATE 1
+#endif
+
+/**
+ * \name SECTION: System support
+ *
+ * This section sets system specific settings.
+ * \{
+ */
+
+/**
+ * \def POLARSSL_HAVE_INT8
+ *
+ * The system uses 8-bit wide native integers.
+ *
+ * Uncomment if native integers are 8-bit wide.
+ */
+//#define POLARSSL_HAVE_INT8
+
+/**
+ * \def POLARSSL_HAVE_INT16
+ *
+ * The system uses 16-bit wide native integers.
+ *
+ * Uncomment if native integers are 16-bit wide.
+ */
+//#define POLARSSL_HAVE_INT16
+
+/**
+ * \def POLARSSL_HAVE_LONGLONG
+ *
+ * The compiler supports the 'long long' type.
+ * (Only used on 32-bit platforms)
+ */
+#define POLARSSL_HAVE_LONGLONG
+
+/**
+ * \def POLARSSL_HAVE_ASM
+ *
+ * The compiler has support for asm().
+ *
+ * Requires support for asm() in compiler.
+ *
+ * Used in:
+ *      library/timing.c
+ *      library/padlock.c
+ *      include/polarssl/bn_mul.h
+ *
+ * Comment to disable the use of assembly code.
+ */
+#define POLARSSL_HAVE_ASM
+
+/**
+ * \def POLARSSL_HAVE_SSE2
+ *
+ * CPU supports SSE2 instruction set.
+ *
+ * Uncomment if the CPU supports SSE2 (IA-32 specific).
+ */
+//#define POLARSSL_HAVE_SSE2
+
+/**
+ * \def POLARSSL_HAVE_READDIR_R
+ *
+ * (Non Windows) System has readdir_r().
+ *
+ * Required for x509_crt_parse_path() in non-Windows systems.
+ *
+ * Comment if your system does not have support.
+ */
+// #define POLARSSL_HAVE_READDIR_R
+
+/**
+ * \def POLARSSL_HAVE_TIME
+ *
+ * System has time.h and time() / localtime()  / gettimeofday().
+ *
+ * Comment if your system does not support time functions
+ */
+// #define POLARSSL_HAVE_TIME
+/* \} name SECTION: System support */
+
+/**
+ * \name SECTION: PolarSSL feature support
+ *
+ * This section sets support for features that are or are not needed
+ * within the modules that are enabled.
+ * \{
+ */
+
+/**
+ * \def POLARSSL_XXX_ALT
+ *
+ * Uncomment a macro to let PolarSSL use your alternate core implementation of
+ * a symmetric or hash algorithm (e.g. platform specific assembly optimized
+ * implementations). Keep in mind that the function prototypes should remain
+ * the same.
+ *
+ * Example: In case you uncomment POLARSSL_AES_ALT, PolarSSL will no longer
+ * provide the "struct aes_context" definition and omit the base function
+ * declarations and implementations. "aes_alt.h" will be included from
+ * "aes.h" to include the new function definitions.
+ *
+ * Uncomment a macro to enable alternate implementation for core algorithm
+ * functions
+ */
+//#define POLARSSL_AES_ALT
+//#define POLARSSL_ARC4_ALT
+//#define POLARSSL_BLOWFISH_ALT
+//#define POLARSSL_CAMELLIA_ALT
+//#define POLARSSL_DES_ALT
+//#define POLARSSL_XTEA_ALT
+//#define POLARSSL_MD2_ALT
+//#define POLARSSL_MD4_ALT
+//#define POLARSSL_MD5_ALT
+//#define POLARSSL_SHA1_ALT
+//#define POLARSSL_SHA256_ALT
+//#define POLARSSL_SHA512_ALT
+
+/**
+ * \def POLARSSL_AES_ROM_TABLES
+ *
+ * Store the AES tables in ROM.
+ *
+ * Uncomment this macro to store the AES tables in ROM.
+ *
+ */
+//#define POLARSSL_AES_ROM_TABLES
+
+/**
+ * \def POLARSSL_CIPHER_MODE_CBC
+ *
+ * Enable Cipher Block Chaining mode (CBC) for symmetric ciphers.
+ */
+#define POLARSSL_CIPHER_MODE_CBC
+
+/**
+ * \def POLARSSL_CIPHER_MODE_CFB
+ *
+ * Enable Cipher Feedback mode (CFB) for symmetric ciphers.
+ */
+#define POLARSSL_CIPHER_MODE_CFB
+
+/**
+ * \def POLARSSL_CIPHER_MODE_CTR
+ *
+ * Enable Counter Block Cipher mode (CTR) for symmetric ciphers.
+ */
+#define POLARSSL_CIPHER_MODE_CTR
+
+/**
+ * \def POLARSSL_CIPHER_NULL_CIPHER
+ *
+ * Enable NULL cipher.
+ * Warning: Only do so when you know what you are doing. This allows for
+ * encryption or channels without any security!
+ *
+ * Requires POLARSSL_ENABLE_WEAK_CIPHERSUITES as well to enable
+ * the following ciphersuites:
+ *      TLS_ECDHE_ECDSA_WITH_NULL_SHA
+ *      TLS_ECDHE_RSA_WITH_NULL_SHA
+ *      TLS_ECDHE_PSK_WITH_NULL_SHA384
+ *      TLS_ECDHE_PSK_WITH_NULL_SHA256
+ *      TLS_ECDHE_PSK_WITH_NULL_SHA
+ *      TLS_DHE_PSK_WITH_NULL_SHA384
+ *      TLS_DHE_PSK_WITH_NULL_SHA256
+ *      TLS_DHE_PSK_WITH_NULL_SHA
+ *      TLS_RSA_WITH_NULL_SHA256
+ *      TLS_RSA_WITH_NULL_SHA
+ *      TLS_RSA_WITH_NULL_MD5
+ *      TLS_RSA_PSK_WITH_NULL_SHA384
+ *      TLS_RSA_PSK_WITH_NULL_SHA256
+ *      TLS_RSA_PSK_WITH_NULL_SHA
+ *      TLS_PSK_WITH_NULL_SHA384
+ *      TLS_PSK_WITH_NULL_SHA256
+ *      TLS_PSK_WITH_NULL_SHA
+ *
+ * Uncomment this macro to enable the NULL cipher and ciphersuites
+#define POLARSSL_CIPHER_NULL_CIPHER
+ */
+
+/**
+ * \def POLARSSL_CIPHER_PADDING_XXX
+ *
+ * Uncomment or comment macros to add support for specific padding modes
+ * in the cipher layer with cipher modes that support padding (e.g. CBC)
+ *
+ * If you disable all padding modes, only full blocks can be used with CBC.
+ *
+ * Enable padding modes in the cipher layer.
+ */
+#define POLARSSL_CIPHER_PADDING_PKCS7
+#define POLARSSL_CIPHER_PADDING_ONE_AND_ZEROS
+#define POLARSSL_CIPHER_PADDING_ZEROS_AND_LEN
+#define POLARSSL_CIPHER_PADDING_ZEROS
+
+/**
+ * \def POLARSSL_ENABLE_WEAK_CIPHERSUITES
+ *
+ * Enable weak ciphersuites in SSL / TLS.
+ * Warning: Only do so when you know what you are doing. This allows for
+ * channels with virtually no security at all!
+ *
+ * This enables the following ciphersuites:
+ *      TLS_RSA_WITH_DES_CBC_SHA
+ *      TLS_DHE_RSA_WITH_DES_CBC_SHA
+ *
+ * Uncomment this macro to enable weak ciphersuites
+#define POLARSSL_ENABLE_WEAK_CIPHERSUITES
+ */
+
+/**
+ * \def POLARSSL_ECP_XXXX_ENABLED
+ *
+ * Enables specific curves within the Elliptic Curve module.
+ * By default all supported curves are enabled.
+ *
+ * Comment macros to disable the curve and functions for it
+
+#define POLARSSL_ECP_DP_SECP192R1_ENABLED
+#define POLARSSL_ECP_DP_SECP224R1_ENABLED
+#define POLARSSL_ECP_DP_SECP256R1_ENABLED
+#define POLARSSL_ECP_DP_SECP384R1_ENABLED
+#define POLARSSL_ECP_DP_SECP521R1_ENABLED
+#define POLARSSL_ECP_DP_BP256R1_ENABLED
+#define POLARSSL_ECP_DP_BP384R1_ENABLED
+#define POLARSSL_ECP_DP_BP512R1_ENABLED
+*/
+
+/**
+ * \def POLARSSL_ECP_NIST_OPTIM
+ *
+ * Enable specific 'modulo p' routines for each NIST prime.
+ * Depending on the prime and architecture, makes operations 4 to 8 times
+ * faster on the corresponding curve.
+ *
+ * Comment this macro to disable NIST curves optimisation.
+
+#define POLARSSL_ECP_NIST_OPTIM
+*/
+
+/**
+ * \def POLARSSL_KEY_EXCHANGE_PSK_ENABLED
+ *
+ * Enable the PSK based ciphersuite modes in SSL / TLS.
+ *
+ * This enables the following ciphersuites (if other requisites are
+ * enabled as well):
+ *      TLS_PSK_WITH_AES_256_GCM_SHA384
+ *      TLS_PSK_WITH_AES_256_CBC_SHA384
+ *      TLS_PSK_WITH_AES_256_CBC_SHA
+ *      TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384
+ *      TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384
+ *      TLS_PSK_WITH_AES_128_GCM_SHA256
+ *      TLS_PSK_WITH_AES_128_CBC_SHA256
+ *      TLS_PSK_WITH_AES_128_CBC_SHA
+ *      TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256
+ *      TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256
+ *      TLS_PSK_WITH_3DES_EDE_CBC_SHA
+ *      TLS_PSK_WITH_RC4_128_SHA
+#define POLARSSL_KEY_EXCHANGE_PSK_ENABLED
+ */
+
+/**
+ * \def POLARSSL_KEY_EXCHANGE_DHE_PSK_ENABLED
+ *
+ * Enable the DHE-PSK based ciphersuite modes in SSL / TLS.
+ *
+ * Requires: POLARSSL_DHM_C
+ *
+ * This enables the following ciphersuites (if other requisites are
+ * enabled as well):
+ *      TLS_DHE_PSK_WITH_AES_256_GCM_SHA384
+ *      TLS_DHE_PSK_WITH_AES_256_CBC_SHA384
+ *      TLS_DHE_PSK_WITH_AES_256_CBC_SHA
+ *      TLS_DHE_PSK_WITH_CAMELLIA_256_GCM_SHA384
+ *      TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384
+ *      TLS_DHE_PSK_WITH_AES_128_GCM_SHA256
+ *      TLS_DHE_PSK_WITH_AES_128_CBC_SHA256
+ *      TLS_DHE_PSK_WITH_AES_128_CBC_SHA
+ *      TLS_DHE_PSK_WITH_CAMELLIA_128_GCM_SHA256
+ *      TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256
+ *      TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA
+ *      TLS_DHE_PSK_WITH_RC4_128_SHA
+#define POLARSSL_KEY_EXCHANGE_DHE_PSK_ENABLED
+ */
+
+/**
+ * \def POLARSSL_KEY_EXCHANGE_ECDHE_PSK_ENABLED
+ *
+ * Enable the ECDHE-PSK based ciphersuite modes in SSL / TLS.
+ *
+ * Requires: POLARSSL_ECDH_C
+ *
+ * This enables the following ciphersuites (if other requisites are
+ * enabled as well):
+ *      TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384
+ *      TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA
+ *      TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384
+ *      TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256
+ *      TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA
+ *      TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256
+ *      TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA
+ *      TLS_ECDHE_PSK_WITH_RC4_128_SHA
+#define POLARSSL_KEY_EXCHANGE_ECDHE_PSK_ENABLED
+ */
+
+/**
+ * \def POLARSSL_KEY_EXCHANGE_RSA_PSK_ENABLED
+ *
+ * Enable the RSA-PSK based ciphersuite modes in SSL / TLS.
+ *
+ * Requires: POLARSSL_RSA_C, POLARSSL_PKCS1_V15,
+ *           POLARSSL_X509_CRT_PARSE_C
+ *
+ * This enables the following ciphersuites (if other requisites are
+ * enabled as well):
+ *      TLS_RSA_PSK_WITH_AES_256_GCM_SHA384
+ *      TLS_RSA_PSK_WITH_AES_256_CBC_SHA384
+ *      TLS_RSA_PSK_WITH_AES_256_CBC_SHA
+ *      TLS_RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384
+ *      TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384
+ *      TLS_RSA_PSK_WITH_AES_128_GCM_SHA256
+ *      TLS_RSA_PSK_WITH_AES_128_CBC_SHA256
+ *      TLS_RSA_PSK_WITH_AES_128_CBC_SHA
+ *      TLS_RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256
+ *      TLS_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256
+ *      TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA
+ *      TLS_RSA_PSK_WITH_RC4_128_SHA
+#define POLARSSL_KEY_EXCHANGE_RSA_PSK_ENABLED
+ */
+
+/**
+ * \def POLARSSL_KEY_EXCHANGE_RSA_ENABLED
+ *
+ * Enable the RSA-only based ciphersuite modes in SSL / TLS.
+ *
+ * Requires: POLARSSL_RSA_C, POLARSSL_PKCS1_V15,
+ *           POLARSSL_X509_CRT_PARSE_C
+ *
+ * This enables the following ciphersuites (if other requisites are
+ * enabled as well):
+ *      TLS_RSA_WITH_AES_256_GCM_SHA384
+ *      TLS_RSA_WITH_AES_256_CBC_SHA256
+ *      TLS_RSA_WITH_AES_256_CBC_SHA
+ *      TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384
+ *      TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256
+ *      TLS_RSA_WITH_CAMELLIA_256_CBC_SHA
+ *      TLS_RSA_WITH_AES_128_GCM_SHA256
+ *      TLS_RSA_WITH_AES_128_CBC_SHA256
+ *      TLS_RSA_WITH_AES_128_CBC_SHA
+ *      TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256
+ *      TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256
+ *      TLS_RSA_WITH_CAMELLIA_128_CBC_SHA
+ *      TLS_RSA_WITH_3DES_EDE_CBC_SHA
+ *      TLS_RSA_WITH_RC4_128_SHA
+ *      TLS_RSA_WITH_RC4_128_MD5
+#define POLARSSL_KEY_EXCHANGE_RSA_ENABLED
+ */
+
+/**
+ * \def POLARSSL_KEY_EXCHANGE_DHE_RSA_ENABLED
+ *
+ * Enable the DHE-RSA based ciphersuite modes in SSL / TLS.
+ *
+ * Requires: POLARSSL_DHM_C, POLARSSL_RSA_C, POLARSSL_PKCS1_V15,
+ *           POLARSSL_X509_CRT_PARSE_C
+ *
+ * This enables the following ciphersuites (if other requisites are
+ * enabled as well):
+ *      TLS_DHE_RSA_WITH_AES_256_GCM_SHA384
+ *      TLS_DHE_RSA_WITH_AES_256_CBC_SHA256
+ *      TLS_DHE_RSA_WITH_AES_256_CBC_SHA
+ *      TLS_DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384
+ *      TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256
+ *      TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA
+ *      TLS_DHE_RSA_WITH_AES_128_GCM_SHA256
+ *      TLS_DHE_RSA_WITH_AES_128_CBC_SHA256
+ *      TLS_DHE_RSA_WITH_AES_128_CBC_SHA
+ *      TLS_DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256
+ *      TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256
+ *      TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA
+ *      TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA
+#define POLARSSL_KEY_EXCHANGE_DHE_RSA_ENABLED
+ */
+
+/**
+ * \def POLARSSL_KEY_EXCHANGE_ECDHE_RSA_ENABLED
+ *
+ * Enable the ECDHE-RSA based ciphersuite modes in SSL / TLS.
+ *
+ * Requires: POLARSSL_ECDH_C, POLARSSL_RSA_C, POLARSSL_PKCS1_V15,
+ *           POLARSSL_X509_CRT_PARSE_C
+ *
+ * This enables the following ciphersuites (if other requisites are
+ * enabled as well):
+ *      TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
+ *      TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384
+ *      TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA
+ *      TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384
+ *      TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384
+ *      TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
+ *      TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256
+ *      TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA
+ *      TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256
+ *      TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256
+ *      TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA
+ *      TLS_ECDHE_RSA_WITH_RC4_128_SHA
+#define POLARSSL_KEY_EXCHANGE_ECDHE_RSA_ENABLED
+ */
+
+/**
+ * \def POLARSSL_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED
+ *
+ * Enable the ECDHE-ECDSA based ciphersuite modes in SSL / TLS.
+ *
+ * Requires: POLARSSL_ECDH_C, POLARSSL_ECDSA_C, POLARSSL_X509_CRT_PARSE_C,
+ *
+ * This enables the following ciphersuites (if other requisites are
+ * enabled as well):
+ *      TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
+ *      TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384
+ *      TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA
+ *      TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384
+ *      TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384
+ *      TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
+ *      TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256
+ *      TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA
+ *      TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256
+ *      TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256
+ *      TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA
+ *      TLS_ECDHE_ECDSA_WITH_RC4_128_SHA
+#define POLARSSL_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED
+ */
+
+/**
+ * \def POLARSSL_ERROR_STRERROR_BC
+ *
+ * Make available the backward compatible error_strerror() next to the
+ * current polarssl_strerror().
+ *
+ * Disable if you run into name conflicts and want to really remove the
+ * error_strerror()
+ */
+// #define POLARSSL_ERROR_STRERROR_BC
+
+/**
+ * \def POLARSSL_ERROR_STRERROR_DUMMY
+ *
+ * Enable a dummy error function to make use of polarssl_strerror() in
+ * third party libraries easier.
+ *
+ * Disable if you run into name conflicts and want to really remove the
+ * polarssl_strerror()
+ */
+#define POLARSSL_ERROR_STRERROR_DUMMY
+
+/**
+ * \def POLARSSL_GENPRIME
+ *
+ * Enable the prime-number generation code.
+ *
+ * Requires: POLARSSL_BIGNUM_C
+ */
+#define POLARSSL_GENPRIME
+
+/**
+ * \def POLARSSL_FS_IO
+ *
+ * Enable functions that use the filesystem.
+ */
+#define POLARSSL_FS_IO
+
+/**
+ * \def POLARSSL_NO_DEFAULT_ENTROPY_SOURCES
+ *
+ * Do not add default entropy sources. These are the platform specific,
+ * hardclock and HAVEGE based poll functions.
+ *
+ * This is useful to have more control over the added entropy sources in an 
+ * application.
+ *
+ * Uncomment this macro to prevent loading of default entropy functions.
+ */
+//#define POLARSSL_NO_DEFAULT_ENTROPY_SOURCES
+
+/**
+ * \def POLARSSL_NO_PLATFORM_ENTROPY
+ *
+ * Do not use built-in platform entropy functions.
+ * This is useful if your platform does not support
+ * standards like the /dev/urandom or Windows CryptoAPI.
+ *
+ * Uncomment this macro to disable the built-in platform entropy functions.
+ */
+//#define POLARSSL_NO_PLATFORM_ENTROPY
+
+/**
+ * \def POLARSSL_MEMORY_DEBUG
+ *
+ * Enable debugging of buffer allocator memory issues. Automatically prints
+ * (to stderr) all (fatal) messages on memory allocation issues. Enables
+ * function for 'debug output' of allocated memory.
+ *
+ * Requires: POLARSSL_MEMORY_BUFFER_ALLOC_C
+ *           fprintf()
+ *
+ * Uncomment this macro to let the buffer allocator print out error messages.
+ */
+// #define POLARSSL_MEMORY_DEBUG
+
+/**
+ * \def POLARSSL_MEMORY_BACKTRACE
+ *
+ * Include backtrace information with each allocated block.
+ *
+ * Requires: POLARSSL_MEMORY_BUFFER_ALLOC_C
+ *           GLIBC-compatible backtrace() an backtrace_symbols() support
+ *
+ * Uncomment this macro to include backtrace information
+ */
+//#define POLARSSL_MEMORY_BACKTRACE
+
+/**
+ * \def POLARSSL_PKCS1_V15
+ *
+ * Enable support for PKCS#1 v1.5 encoding.
+ *
+ * Requires: POLARSSL_RSA_C
+ *
+ * This enables support for PKCS#1 v1.5 operations.
+ */
+#define POLARSSL_PKCS1_V15
+
+/**
+ * \def POLARSSL_PKCS1_V21
+ *
+ * Enable support for PKCS#1 v2.1 encoding.
+ *
+ * Requires: POLARSSL_MD_C, POLARSSL_RSA_C
+ *
+ * This enables support for RSAES-OAEP and RSASSA-PSS operations.
+#define POLARSSL_PKCS1_V21
+ */
+/**
+ * \def POLARSSL_RSA_NO_CRT
+ *
+ * Do not use the Chinese Remainder Theorem for the RSA private operation.
+ *
+ * Uncomment this macro to disable the use of CRT in RSA.
+ *
+ */
+//#define POLARSSL_RSA_NO_CRT
+
+/**
+ * \def POLARSSL_SELF_TEST
+ *
+ * Enable the checkup functions (*_self_test).
+ */
+#define POLARSSL_SELF_TEST
+
+/**
+ * \def POLARSSL_SSL_ALL_ALERT_MESSAGES
+ *
+ * Enable sending of alert messages in case of encountered errors as per RFC.
+ * If you choose not to send the alert messages, PolarSSL can still communicate
+ * with other servers, only debugging of failures is harder.
+ *
+ * The advantage of not sending alert messages, is that no information is given
+ * about reasons for failures thus preventing adversaries of gaining intel.
+ *
+ * Enable sending of all alert messages
+ */
+// #define POLARSSL_SSL_ALERT_MESSAGES
+
+/**
+ * \def POLARSSL_SSL_DEBUG_ALL
+ *
+ * Enable the debug messages in SSL module for all issues.
+ * Debug messages have been disabled in some places to prevent timing
+ * attacks due to (unbalanced) debugging function calls.
+ *
+ * If you need all error reporting you should enable this during debugging,
+ * but remove this for production servers that should log as well.
+ *
+ * Uncomment this macro to report all debug messages on errors introducing
+ * a timing side-channel.
+ *
+ */
+//#define POLARSSL_SSL_DEBUG_ALL
+
+/**
+ * \def POLARSSL_SSL_HW_RECORD_ACCEL
+ *
+ * Enable hooking functions in SSL module for hardware acceleration of
+ * individual records.
+ *
+ * Uncomment this macro to enable hooking functions.
+ */
+//#define POLARSSL_SSL_HW_RECORD_ACCEL
+
+/**
+ * \def POLARSSL_SSL_SRV_SUPPORT_SSLV2_CLIENT_HELLO
+ *
+ * Enable support for receiving and parsing SSLv2 Client Hello messages for the
+ * SSL Server module (POLARSSL_SSL_SRV_C).
+ *
+ * Comment this macro to disable support for SSLv2 Client Hello messages.
+ */
+// #define POLARSSL_SSL_SRV_SUPPORT_SSLV2_CLIENT_HELLO
+
+/**
+ * \def POLARSSL_SSL_MAX_FRAGMENT_LENGTH
+ *
+ * Enable support for RFC 6066 max_fragment_length extension in SSL.
+ *
+ * Comment this macro to disable support for the max_fragment_length extension
+ */
+// #define POLARSSL_SSL_MAX_FRAGMENT_LENGTH
+
+/**
+ * \def POLARSSL_SSL_PROTO_SSL3
+ *
+ * Enable support for SSL 3.0.
+ *
+ * Requires: POLARSSL_MD5_C
+ *           POLARSSL_SHA1_C
+ *
+ * Comment this macro to disable support for SSL 3.0
+#define POLARSSL_SSL_PROTO_SSL3
+ */
+
+/**
+ * \def POLARSSL_SSL_PROTO_TLS1
+ *
+ * Enable support for TLS 1.0.
+ *
+ * Requires: POLARSSL_MD5_C
+ *           POLARSSL_SHA1_C
+ *
+ * Comment this macro to disable support for TLS 1.0
+ */
+//#define POLARSSL_SSL_PROTO_TLS1
+
+/**
+ * \def POLARSSL_SSL_PROTO_TLS1_1
+ *
+ * Enable support for TLS 1.1.
+ *
+ * Requires: POLARSSL_MD5_C
+ *           POLARSSL_SHA1_C
+ *
+ * Comment this macro to disable support for TLS 1.1
+ */
+//#define POLARSSL_SSL_PROTO_TLS1_1
+
+/**
+ * \def POLARSSL_SSL_PROTO_TLS1_2
+ *
+ * Enable support for TLS 1.2.
+ *
+ * Requires: POLARSSL_SHA1_C or POLARSSL_SHA256_C or POLARSSL_SHA512_C
+ *           (Depends on ciphersuites)
+ *
+ * Comment this macro to disable support for TLS 1.2
+ */
+// #define POLARSSL_SSL_PROTO_TLS1_2
+
+/**
+ * \def POLARSSL_SSL_SESSION_TICKETS
+ *
+ * Enable support for RFC 5077 session tickets in SSL.
+ *
+ * Requires: POLARSSL_AES_C
+ *           POLARSSL_SHA256_C
+ *           POLARSSL_CIPHER_MODE_CBC
+ *
+ * Comment this macro to disable support for SSL session tickets
+ */
+// #define POLARSSL_SSL_SESSION_TICKETS
+
+/**
+ * \def POLARSSL_SSL_SERVER_NAME_INDICATION
+ *
+ * Enable support for RFC 6066 server name indication (SNI) in SSL.
+ *
+ * Comment this macro to disable support for server name indication in SSL
+ */
+// #define POLARSSL_SSL_SERVER_NAME_INDICATION
+
+/**
+ * \def POLARSSL_SSL_TRUNCATED_HMAC
+ *
+ * Enable support for RFC 6066 truncated HMAC in SSL.
+ *
+ * Comment this macro to disable support for truncated HMAC in SSL
+ */
+// #define POLARSSL_SSL_TRUNCATED_HMAC
+
+/**
+ * \def POLARSSL_THREADING_ALT
+ *
+ * Provide your own alternate threading implementation.
+ *
+ * Requires: POLARSSL_THREADING_C
+ *
+ * Uncomment this to allow your own alternate threading implementation.
+ */
+//#define POLARSSL_THREADING_ALT
+
+/**
+ * \def POLARSSL_THREADING_DUMMY
+ *
+ * Provide a dummy threading implementation.
+ * Warning: If you use this, all claims of thread-safety in the documentation
+ *          are void!
+ *
+ * Requires: POLARSSL_THREADING_C
+ *
+ * Uncomment this to enable code to compile like with threading enabled
+ */
+//#define POLARSSL_THREADING_DUMMY
+
+/**
+ * \def POLARSSL_THREADING_PTHREAD
+ *
+ * Enable the pthread wrapper layer for the threading layer.
+ *
+ * Requires: POLARSSL_THREADING_C
+ *
+ * Uncomment this to enable pthread mutexes.
+ */
+//#define POLARSSL_THREADING_PTHREAD
+
+/**
+ * \def POLARSSL_X509_ALLOW_EXTENSIONS_NON_V3
+ *
+ * If set, the X509 parser will not break-off when parsing an X509 certificate
+ * and encountering an extension in a v1 or v2 certificate.
+ *
+ * Uncomment to prevent an error.
+ */
+//#define POLARSSL_X509_ALLOW_EXTENSIONS_NON_V3
+
+/**
+ * \def POLARSSL_X509_ALLOW_UNSUPPORTED_CRITICAL_EXTENSION
+ *
+ * If set, the X509 parser will not break-off when parsing an X509 certificate
+ * and encountering an unknown critical extension.
+ *
+ * Uncomment to prevent an error.
+ */
+//#define POLARSSL_X509_ALLOW_UNSUPPORTED_CRITICAL_EXTENSION
+
+/**
+ * \def POLARSSL_ZLIB_SUPPORT
+ *
+ * If set, the SSL/TLS module uses ZLIB to support compression and
+ * decompression of packet data.
+ *
+ * Used in: library/ssl_tls.c
+ *          library/ssl_cli.c
+ *          library/ssl_srv.c
+ *
+ * This feature requires zlib library and headers to be present.
+ *
+ * Uncomment to enable use of ZLIB
+ */
+//#define POLARSSL_ZLIB_SUPPORT
+/* \} name SECTION: PolarSSL feature support */
+
+/**
+ * \name SECTION: PolarSSL modules
+ *
+ * This section enables or disables entire modules in PolarSSL
+ * \{
+ */
+
+/**
+ * \def POLARSSL_AES_C
+ *
+ * Enable the AES block cipher.
+ *
+ * Module:  library/aes.c
+ * Caller:  library/ssl_tls.c
+ *          library/pem.c
+ *          library/ctr_drbg.c
+ *
+ * This module enables the following ciphersuites (if other requisites are
+ * enabled as well):
+ *      TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
+ *      TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
+ *      TLS_DHE_RSA_WITH_AES_256_GCM_SHA384
+ *      TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384
+ *      TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384
+ *      TLS_DHE_RSA_WITH_AES_256_CBC_SHA256
+ *      TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA
+ *      TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA
+ *      TLS_DHE_RSA_WITH_AES_256_CBC_SHA
+ *      TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
+ *      TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
+ *      TLS_DHE_RSA_WITH_AES_128_GCM_SHA256
+ *      TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256
+ *      TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256
+ *      TLS_DHE_RSA_WITH_AES_128_CBC_SHA256
+ *      TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA
+ *      TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA
+ *      TLS_DHE_RSA_WITH_AES_128_CBC_SHA
+ *      TLS_DHE_PSK_WITH_AES_256_GCM_SHA384
+ *      TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384
+ *      TLS_DHE_PSK_WITH_AES_256_CBC_SHA384
+ *      TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA
+ *      TLS_DHE_PSK_WITH_AES_256_CBC_SHA
+ *      TLS_DHE_PSK_WITH_AES_128_GCM_SHA256
+ *      TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256
+ *      TLS_DHE_PSK_WITH_AES_128_CBC_SHA256
+ *      TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA
+ *      TLS_DHE_PSK_WITH_AES_128_CBC_SHA
+ *      TLS_RSA_WITH_AES_256_GCM_SHA384
+ *      TLS_RSA_WITH_AES_256_CBC_SHA256
+ *      TLS_RSA_WITH_AES_256_CBC_SHA
+ *      TLS_RSA_WITH_AES_128_GCM_SHA256
+ *      TLS_RSA_WITH_AES_128_CBC_SHA256
+ *      TLS_RSA_WITH_AES_128_CBC_SHA
+ *      TLS_RSA_PSK_WITH_AES_256_GCM_SHA384
+ *      TLS_RSA_PSK_WITH_AES_256_CBC_SHA384
+ *      TLS_RSA_PSK_WITH_AES_256_CBC_SHA
+ *      TLS_RSA_PSK_WITH_AES_128_GCM_SHA256
+ *      TLS_RSA_PSK_WITH_AES_128_CBC_SHA256
+ *      TLS_RSA_PSK_WITH_AES_128_CBC_SHA
+ *      TLS_PSK_WITH_AES_256_GCM_SHA384
+ *      TLS_PSK_WITH_AES_256_CBC_SHA384
+ *      TLS_PSK_WITH_AES_256_CBC_SHA
+ *      TLS_PSK_WITH_AES_128_GCM_SHA256
+ *      TLS_PSK_WITH_AES_128_CBC_SHA256
+ *      TLS_PSK_WITH_AES_128_CBC_SHA
+ *
+ * PEM_PARSE uses AES for decrypting encrypted keys.
+ */
+#define POLARSSL_AES_C
+
+/**
+ * \def POLARSSL_ARC4_C
+ *
+ * Enable the ARCFOUR stream cipher.
+ *
+ * Module:  library/arc4.c
+ * Caller:  library/ssl_tls.c
+ *
+ * This module enables the following ciphersuites (if other requisites are
+ * enabled as well):
+ *      TLS_ECDHE_ECDSA_WITH_RC4_128_SHA
+ *      TLS_ECDHE_RSA_WITH_RC4_128_SHA
+ *      TLS_ECDHE_PSK_WITH_RC4_128_SHA
+ *      TLS_DHE_PSK_WITH_RC4_128_SHA
+ *      TLS_RSA_WITH_RC4_128_SHA
+ *      TLS_RSA_WITH_RC4_128_MD5
+ *      TLS_RSA_PSK_WITH_RC4_128_SHA
+ *      TLS_PSK_WITH_RC4_128_SHA
+#define POLARSSL_ARC4_C
+ */
+/**
+ * \def POLARSSL_ASN1_PARSE_C
+ *
+ * Enable the generic ASN1 parser.
+ *
+ * Module:  library/asn1.c
+ * Caller:  library/x509.c
+ *          library/dhm.c
+ *          library/pkcs12.c
+ *          library/pkcs5.c
+ *          library/pkparse.c
+ */
+// #define POLARSSL_ASN1_PARSE_C
+
+/**
+ * \def POLARSSL_ASN1_WRITE_C
+ *
+ * Enable the generic ASN1 writer.
+ *
+ * Module:  library/asn1write.c
+ * Caller:  library/ecdsa.c
+ *          library/pkwrite.c
+ *          library/x509_create.c
+ *          library/x509write_crt.c
+ *          library/x509write_csr.c
+ */
+// #define POLARSSL_ASN1_WRITE_C
+
+/**
+ * \def POLARSSL_BASE64_C
+ *
+ * Enable the Base64 module.
+ *
+ * Module:  library/base64.c
+ * Caller:  library/pem.c
+ *
+ * This module is required for PEM support (required by X.509).
+#define POLARSSL_BASE64_C
+ */
+/**
+ * \def POLARSSL_BIGNUM_C
+ *
+ * Enable the multi-precision integer library.
+ *
+ * Module:  library/bignum.c
+ * Caller:  library/dhm.c
+ *          library/ecp.c
+ *          library/rsa.c
+ *          library/ssl_tls.c
+ *
+ * This module is required for RSA and DHM support.
+ */
+#define POLARSSL_BIGNUM_C
+
+/**
+ * \def POLARSSL_BLOWFISH_C
+ *
+ * Enable the Blowfish block cipher.
+ *
+ * Module:  library/blowfish.c
+ */
+// #define POLARSSL_BLOWFISH_C
+
+/**
+ * \def POLARSSL_CAMELLIA_C
+ *
+ * Enable the Camellia block cipher.
+ *
+ * Module:  library/camellia.c
+ * Caller:  library/ssl_tls.c
+ *
+ * This module enables the following ciphersuites (if other requisites are
+ * enabled as well):
+ *      TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384
+ *      TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384
+ *      TLS_DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384
+ *      TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384
+ *      TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384
+ *      TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256
+ *      TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA
+ *      TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256
+ *      TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256
+ *      TLS_DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256
+ *      TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256
+ *      TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256
+ *      TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256
+ *      TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA
+ *      TLS_DHE_PSK_WITH_CAMELLIA_256_GCM_SHA384
+ *      TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384
+ *      TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384
+ *      TLS_DHE_PSK_WITH_CAMELLIA_128_GCM_SHA256
+ *      TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256
+ *      TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256
+ *      TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384
+ *      TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256
+ *      TLS_RSA_WITH_CAMELLIA_256_CBC_SHA
+ *      TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256
+ *      TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256
+ *      TLS_RSA_WITH_CAMELLIA_128_CBC_SHA
+ *      TLS_RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384
+ *      TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384
+ *      TLS_RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256
+ *      TLS_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256
+ *      TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384
+ *      TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384
+ *      TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256
+ *      TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256
+ */
+// #define POLARSSL_CAMELLIA_C
+
+/**
+ * \def POLARSSL_CERTS_C
+ *
+ * Enable the test certificates.
+ *
+ * Module:  library/certs.c
+ * Caller:
+ *
+ * Requires: POLARSSL_PEM_PARSE_C
+ *
+ * This module is used for testing (ssl_client/server).
+ */
+// #define POLARSSL_CERTS_C
+
+/**
+ * \def POLARSSL_CIPHER_C
+ *
+ * Enable the generic cipher layer.
+ *
+ * Module:  library/cipher.c
+ * Caller:  library/ssl_tls.c
+ *
+ * Uncomment to enable generic cipher wrappers.
+ */
+// #define POLARSSL_CIPHER_C
+
+/**
+ * \def POLARSSL_CTR_DRBG_C
+ *
+ * Enable the CTR_DRBG AES-256-based random generator.
+ *
+ * Module:  library/ctr_drbg.c
+ * Caller:
+ *
+ * Requires: POLARSSL_AES_C
+ *
+ * This module provides the CTR_DRBG AES-256 random number generator.
+ */
+// #define POLARSSL_CTR_DRBG_C
+
+/**
+ * \def POLARSSL_DEBUG_C
+ *
+ * Enable the debug functions.
+ *
+ * Module:  library/debug.c
+ * Caller:  library/ssl_cli.c
+ *          library/ssl_srv.c
+ *          library/ssl_tls.c
+ *
+ * This module provides debugging functions.
+ */
+// #define POLARSSL_DEBUG_C
+
+/**
+ * \def POLARSSL_DES_C
+ *
+ * Enable the DES block cipher.
+ *
+ * Module:  library/des.c
+ * Caller:  library/pem.c
+ *          library/ssl_tls.c
+ *
+ * This module enables the following ciphersuites (if other requisites are
+ * enabled as well):
+ *      TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA
+ *      TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA
+ *      TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA
+ *      TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA
+ *      TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA
+ *      TLS_RSA_WITH_3DES_EDE_CBC_SHA
+ *      TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA
+ *      TLS_PSK_WITH_3DES_EDE_CBC_SHA
+ *
+ * PEM_PARSE uses DES/3DES for decrypting encrypted keys.
+ */
+// #define POLARSSL_DES_C
+
+/**
+ * \def POLARSSL_DHM_C
+ *
+ * Enable the Diffie-Hellman-Merkle module.
+ *
+ * Module:  library/dhm.c
+ * Caller:  library/ssl_cli.c
+ *          library/ssl_srv.c
+ *
+ * This module is used by the following key exchanges:
+ *      DHE-RSA, DHE-PSK
+ */
+// #define POLARSSL_DHM_C
+
+/**
+ * \def POLARSSL_ECDH_C
+ *
+ * Enable the elliptic curve Diffie-Hellman library.
+ *
+ * Module:  library/ecdh.c
+ * Caller:  library/ssl_cli.c
+ *          library/ssl_srv.c
+ *
+ * This module is used by the following key exchanges:
+ *      ECDHE-ECDSA, ECDHE-RSA, DHE-PSK
+ *
+ * Requires: POLARSSL_ECP_C
+ */
+// #define POLARSSL_ECDH_C
+
+/**
+ * \def POLARSSL_ECDSA_C
+ *
+ * Enable the elliptic curve DSA library.
+ *
+ * Module:  library/ecdsa.c
+ * Caller:
+ *
+ * This module is used by the following key exchanges:
+ *      ECDHE-ECDSA
+ *
+ * Requires: POLARSSL_ECP_C, POLARSSL_ASN1_WRITE_C, POLARSSL_ASN1_PARSE_C
+ */
+// #define POLARSSL_ECDSA_C
+
+/**
+ * \def POLARSSL_ECP_C
+ *
+ * Enable the elliptic curve over GF(p) library.
+ *
+ * Module:  library/ecp.c
+ * Caller:  library/ecdh.c
+ *          library/ecdsa.c
+ *
+ * Requires: POLARSSL_BIGNUM_C and at least one POLARSSL_ECP_DP_XXX_ENABLED
+ */
+// #define POLARSSL_ECP_C
+
+/**
+ * \def POLARSSL_ENTROPY_C
+ *
+ * Enable the platform-specific entropy code.
+ *
+ * Module:  library/entropy.c
+ * Caller:
+ *
+ * Requires: POLARSSL_SHA512_C
+ *
+ * This module provides a generic entropy pool
+ */
+// #define POLARSSL_ENTROPY_C
+
+/**
+ * \def POLARSSL_ERROR_C
+ *
+ * Enable error code to error string conversion.
+ *
+ * Module:  library/error.c
+ * Caller:
+ *
+ * This module enables err_strerror().
+ */
+// #define POLARSSL_ERROR_C
+
+/**
+ * \def POLARSSL_GCM_C
+ *
+ * Enable the Galois/Counter Mode (GCM) for AES.
+ *
+ * Module:  library/gcm.c
+ *
+ * Requires: POLARSSL_AES_C or POLARSSL_CAMELLIA_C
+ *
+ * This module enables the AES-GCM and CAMELLIA-GCM ciphersuites, if other
+ * requisites are enabled as well.
+ */
+// #define POLARSSL_GCM_C
+
+/**
+ * \def POLARSSL_HAVEGE_C
+ *
+ * Enable the HAVEGE random generator.
+ *
+ * Warning: the HAVEGE random generator is not suitable for virtualized
+ *          environments
+ *
+ * Warning: the HAVEGE random generator is dependent on timing and specific
+ *          processor traits. It is therefore not advised to use HAVEGE as
+ *          your applications primary random generator or primary entropy pool
+ *          input. As a secondary input to your entropy pool, it IS able add
+ *          the (limited) extra entropy it provides.
+ *
+ * Module:  library/havege.c
+ * Caller:
+ *
+ * Requires: POLARSSL_TIMING_C
+ *
+ * Uncomment to enable the HAVEGE random generator.
+ */
+//#define POLARSSL_HAVEGE_C
+
+/**
+ * \def POLARSSL_MD_C
+ *
+ * Enable the generic message digest layer.
+ *
+ * Module:  library/md.c
+ * Caller:
+ *
+ * Uncomment to enable generic message digest wrappers.
+ */
+// #define POLARSSL_MD_C
+
+/**
+ * \def POLARSSL_MD2_C
+ *
+ * Enable the MD2 hash algorithm.
+ *
+ * Module:  library/md2.c
+ * Caller:
+ *
+ * Uncomment to enable support for (rare) MD2-signed X.509 certs.
+ */
+//#define POLARSSL_MD2_C
+
+/**
+ * \def POLARSSL_MD4_C
+ *
+ * Enable the MD4 hash algorithm.
+ *
+ * Module:  library/md4.c
+ * Caller:
+ *
+ * Uncomment to enable support for (rare) MD4-signed X.509 certs.
+ */
+//#define POLARSSL_MD4_C
+
+/**
+ * \def POLARSSL_MD5_C
+ *
+ * Enable the MD5 hash algorithm.
+ *
+ * Module:  library/md5.c
+ * Caller:  library/md.c
+ *          library/pem.c
+ *          library/ssl_tls.c
+ *
+ * This module is required for SSL/TLS and X.509.
+ * PEM_PARSE uses MD5 for decrypting encrypted keys.
+ */
+#define POLARSSL_MD5_C
+
+/**
+ * \def POLARSSL_MEMORY_C
+ *
+ * Enable the memory allocation layer.
+ * By default PolarSSL uses the system-provided malloc() and free().
+ * (As long as POLARSSL_MEMORY_STDMALLOC and POLARSSL_MEMORY_STDFREE
+ * are defined and unmodified)
+ *
+ * This allows different allocators (self-implemented or provided)
+ *
+ * Enable this layer to allow use of alternative memory allocators.
+ */
+#define POLARSSL_MEMORY_C
+
+/**
+ * \def POLARSSL_MEMORY_BUFFER_ALLOC_C
+ *
+ * Enable the buffer allocator implementation that makes use of a (stack)
+ * based buffer to 'allocate' dynamic memory. (replaces malloc() and free()
+ * calls)
+ *
+ * Module:  library/memory_buffer_alloc.c
+ *
+ * Requires: POLARSSL_MEMORY_C
+ *
+ * Enable this module to enable the buffer memory allocator.
+ */
+#define POLARSSL_MEMORY_BUFFER_ALLOC_C
+
+/**
+ * \def POLARSSL_NET_C
+ *
+ * Enable the TCP/IP networking routines.
+ *
+ * Module:  library/net.c
+ *
+ * This module provides TCP/IP networking routines.
+ */
+// #define POLARSSL_NET_C
+
+/**
+ * \def POLARSSL_OID_C
+ *
+ * Enable the OID database.
+ *
+ * Module:  library/oid.c
+ * Caller:  library/asn1write.c
+ *          library/pkcs5.c
+ *          library/pkparse.c
+ *          library/pkwrite.c
+ *          library/rsa.c
+ *          library/x509.c
+ *          library/x509_create.c
+ *          library/x509_crl.c
+ *          library/x509_crt.c
+ *          library/x509_csr.c
+ *          library/x509write_crt.c
+ *          library/x509write_csr.c
+ *
+ * This modules translates between OIDs and internal values.
+ */
+#define POLARSSL_OID_C
+
+/**
+ * \def POLARSSL_PADLOCK_C
+ *
+ * Enable VIA Padlock support on x86.
+ *
+ * Module:  library/padlock.c
+ * Caller:  library/aes.c
+ *
+ * This modules adds support for the VIA PadLock on x86.
+ */
+// #define POLARSSL_PADLOCK_C
+
+/**
+ * \def POLARSSL_PBKDF2_C
+ *
+ * Enable PKCS#5 PBKDF2 key derivation function.
+ * DEPRECATED: Use POLARSSL_PKCS5_C instead
+ *
+ * Module:  library/pbkdf2.c
+ *
+ * Requires: POLARSSL_PKCS5_C
+ *
+ * This module adds support for the PKCS#5 PBKDF2 key derivation function.
+ */
+// #define POLARSSL_PBKDF2_C
+
+/**
+ * \def POLARSSL_PEM_PARSE_C
+ *
+ * Enable PEM decoding / parsing.
+ *
+ * Module:  library/pem.c
+ * Caller:  library/dhm.c
+ *          library/pkparse.c
+ *          library/x509_crl.c
+ *          library/x509_crt.c
+ *          library/x509_csr.c
+ *
+ * Requires: POLARSSL_BASE64_C
+ *
+ * This modules adds support for decoding / parsing PEM files.
+ */
+// #define POLARSSL_PEM_PARSE_C
+
+/**
+ * \def POLARSSL_PEM_WRITE_C
+ *
+ * Enable PEM encoding / writing.
+ *
+ * Module:  library/pem.c
+ * Caller:  library/pkwrite.c
+ *          library/x509write_crt.c
+ *          library/x509write_csr.c
+ *
+ * Requires: POLARSSL_BASE64_C
+ *
+ * This modules adds support for encoding / writing PEM files.
+ */
+// #define POLARSSL_PEM_WRITE_C
+
+/**
+ * \def POLARSSL_PK_C
+ *
+ * Enable the generic public (asymetric) key layer.
+ *
+ * Module:  library/pk.c
+ * Caller:  library/ssl_tls.c
+ *          library/ssl_cli.c
+ *          library/ssl_srv.c
+ *
+ * Requires: POLARSSL_RSA_C or POLARSSL_ECP_C
+ *
+ * Uncomment to enable generic public key wrappers.
+ */
+#define POLARSSL_PK_C
+
+/**
+ * \def POLARSSL_PK_PARSE_C
+ *
+ * Enable the generic public (asymetric) key parser.
+ *
+ * Module:  library/pkparse.c
+ * Caller:  library/x509_crt.c
+ *          library/x509_csr.c
+ *
+ * Requires: POLARSSL_PK_C
+ *
+ * Uncomment to enable generic public key parse functions.
+ */
+// #define POLARSSL_PK_PARSE_C
+
+/**
+ * \def POLARSSL_PK_WRITE_C
+ *
+ * Enable the generic public (asymetric) key writer.
+ *
+ * Module:  library/pkwrite.c
+ * Caller:  library/x509write.c
+ *
+ * Requires: POLARSSL_PK_C
+ *
+ * Uncomment to enable generic public key write functions.
+ */
+// #define POLARSSL_PK_WRITE_C
+
+/**
+ * \def POLARSSL_PKCS5_C
+ *
+ * Enable PKCS#5 functions.
+ *
+ * Module:  library/pkcs5.c
+ *
+ * Requires: POLARSSL_MD_C
+ *
+ * This module adds support for the PKCS#5 functions.
+ */
+// #define POLARSSL_PKCS5_C
+
+/**
+ * \def POLARSSL_PKCS11_C
+ *
+ * Enable wrapper for PKCS#11 smartcard support.
+ *
+ * Module:  library/pkcs11.c
+ * Caller:  library/pk.c
+ *
+ * Requires: POLARSSL_PK_C
+ *
+ * This module enables SSL/TLS PKCS #11 smartcard support.
+ * Requires the presence of the PKCS#11 helper library (libpkcs11-helper)
+ */
+//#define POLARSSL_PKCS11_C
+
+/**
+ * \def POLARSSL_PKCS12_C
+ *
+ * Enable PKCS#12 PBE functions.
+ * Adds algorithms for parsing PKCS#8 encrypted private keys
+ *
+ * Module:  library/pkcs12.c
+ * Caller:  library/pkparse.c
+ *
+ * Requires: POLARSSL_ASN1_PARSE_C, POLARSSL_CIPHER_C, POLARSSL_MD_C
+ * Can use:  POLARSSL_ARC4_C
+ *
+ * This module enables PKCS#12 functions.
+ */
+// #define POLARSSL_PKCS12_C
+
+/**
+ * \def POLARSSL_RSA_C
+ *
+ * Enable the RSA public-key cryptosystem.
+ *
+ * Module:  library/rsa.c
+ * Caller:  library/ssl_cli.c
+ *          library/ssl_srv.c
+ *          library/ssl_tls.c
+ *          library/x509.c
+ *
+ * This module is used by the following key exchanges:
+ *      RSA, DHE-RSA, ECDHE-RSA, RSA-PSK
+ *
+ * Requires: POLARSSL_BIGNUM_C, POLARSSL_OID_C
+ */
+#define POLARSSL_RSA_C
+
+/**
+ * \def POLARSSL_SHA1_C
+ *
+ * Enable the SHA1 cryptographic hash algorithm.
+ *
+ * Module:  library/sha1.c
+ * Caller:  library/md.c
+ *          library/ssl_cli.c
+ *          library/ssl_srv.c
+ *          library/ssl_tls.c
+ *          library/x509write_crt.c
+ *
+ * This module is required for SSL/TLS and SHA1-signed certificates.
+ */
+#define POLARSSL_SHA1_C
+
+/**
+ * \def POLARSSL_SHA256_C
+ *
+ * Enable the SHA-224 and SHA-256 cryptographic hash algorithms.
+ * (Used to be POLARSSL_SHA2_C)
+ *
+ * Module:  library/sha256.c
+ * Caller:  library/entropy.c
+ *          library/md.c
+ *          library/ssl_cli.c
+ *          library/ssl_srv.c
+ *          library/ssl_tls.c
+ *
+ * This module adds support for SHA-224 and SHA-256.
+ * This module is required for the SSL/TLS 1.2 PRF function.
+ */
+#define POLARSSL_SHA256_C
+
+/**
+ * \def POLARSSL_SHA512_C
+ *
+ * Enable the SHA-384 and SHA-512 cryptographic hash algorithms.
+ * (Used to be POLARSSL_SHA4_C)
+ *
+ * Module:  library/sha512.c
+ * Caller:  library/entropy.c
+ *          library/md.c
+ *          library/ssl_cli.c
+ *          library/ssl_srv.c
+ *
+ * This module adds support for SHA-384 and SHA-512.
+ */
+// #define POLARSSL_SHA512_C
+
+/**
+ * \def POLARSSL_SSL_CACHE_C
+ *
+ * Enable simple SSL cache implementation.
+ *
+ * Module:  library/ssl_cache.c
+ * Caller:
+ *
+ * Requires: POLARSSL_SSL_CACHE_C
+ */
+// #define POLARSSL_SSL_CACHE_C
+
+/**
+ * \def POLARSSL_SSL_CLI_C
+ *
+ * Enable the SSL/TLS client code.
+ *
+ * Module:  library/ssl_cli.c
+ * Caller:
+ *
+ * Requires: POLARSSL_SSL_TLS_C
+ *
+ * This module is required for SSL/TLS client support.
+ */
+// #define POLARSSL_SSL_CLI_C
+
+/**
+ * \def POLARSSL_SSL_SRV_C
+ *
+ * Enable the SSL/TLS server code.
+ *
+ * Module:  library/ssl_srv.c
+ * Caller:
+ *
+ * Requires: POLARSSL_SSL_TLS_C
+ *
+ * This module is required for SSL/TLS server support.
+ */
+// #define POLARSSL_SSL_SRV_C
+
+/**
+ * \def POLARSSL_SSL_TLS_C
+ *
+ * Enable the generic SSL/TLS code.
+ *
+ * Module:  library/ssl_tls.c
+ * Caller:  library/ssl_cli.c
+ *          library/ssl_srv.c
+ *
+ * Requires: POLARSSL_CIPHER_C, POLARSSL_MD_C
+ *           and at least one of the POLARSSL_SSL_PROTO_* defines
+ *
+ * This module is required for SSL/TLS.
+ */
+// #define POLARSSL_SSL_TLS_C
+
+/**
+ * \def POLARSSL_THREADING_C
+ *
+ * Enable the threading abstraction layer.
+ * By default PolarSSL assumes it is used in a non-threaded environment or that
+ * contexts are not shared between threads. If you do intend to use contexts
+ * between threads, you will need to enable this layer to prevent race
+ * conditions.
+ *
+ * Module:  library/threading.c
+ *
+ * This allows different threading implementations (self-implemented or
+ * provided).
+ *
+ * You will have to enable either POLARSSL_THREADING_ALT,
+ * POLARSSL_THREADING_PTHREAD or POLARSSL_THREADING_DUMMY.
+ *
+ * Enable this layer to allow use of mutexes within PolarSSL
+ */
+//#define POLARSSL_THREADING_C
+
+/**
+ * \def POLARSSL_TIMING_C
+ *
+ * Enable the portable timing interface.
+ *
+ * Module:  library/timing.c
+ * Caller:  library/havege.c
+ *
+ * This module is used by the HAVEGE random number generator.
+ */
+// #define POLARSSL_TIMING_C
+
+/**
+ * \def POLARSSL_VERSION_C
+ *
+ * Enable run-time version information.
+ *
+ * Module:  library/version.c
+ *
+ * This module provides run-time version information.
+ */
+// #define POLARSSL_VERSION_C
+
+/**
+ * \def POLARSSL_X509_USE_C
+ *
+ * Enable X.509 core for using certificates.
+ *
+ * Module:  library/x509.c
+ * Caller:  library/x509_crl.c
+ *          library/x509_crt.c
+ *          library/x509_csr.c
+ *
+ * Requires: POLARSSL_ASN1_PARSE_C, POLARSSL_BIGNUM_C, POLARSSL_OID_C,
+ *           POLARSSL_PK_PARSE_C
+ *
+ * This module is required for the X.509 parsing modules.
+ */
+// #define POLARSSL_X509_USE_C
+
+/**
+ * \def POLARSSL_X509_CRT_PARSE_C
+ *
+ * Enable X.509 certificate parsing.
+ *
+ * Module:  library/x509_crt.c
+ * Caller:  library/ssl_cli.c
+ *          library/ssl_srv.c
+ *          library/ssl_tls.c
+ *
+ * Requires: POLARSSL_X509_USE_C
+ *
+ * This module is required for X.509 certificate parsing.
+ */
+// #define POLARSSL_X509_CRT_PARSE_C
+
+/**
+ * \def POLARSSL_X509_CRL_PARSE_C
+ *
+ * Enable X.509 CRL parsing.
+ *
+ * Module:  library/x509_crl.c
+ * Caller:  library/x509_crt.c
+ *
+ * Requires: POLARSSL_X509_USE_C
+ *
+ * This module is required for X.509 CRL parsing.
+ */
+// #define POLARSSL_X509_CRL_PARSE_C
+
+/**
+ * \def POLARSSL_X509_CSR_PARSE_C
+ *
+ * Enable X.509 Certificate Signing Request (CSR) parsing.
+ *
+ * Module:  library/x509_csr.c
+ * Caller:  library/x509_crt_write.c
+ *
+ * Requires: POLARSSL_X509_USE_C
+ *
+ * This module is used for reading X.509 certificate request.
+ */
+// #define POLARSSL_X509_CSR_PARSE_C
+
+/**
+ * \def POLARSSL_X509_CREATE_C
+ *
+ * Enable X.509 core for creating certificates.
+ *
+ * Module:  library/x509_create.c
+ *
+ * Requires: POLARSSL_BIGNUM_C, POLARSSL_OID_C, POLARSSL_PK_WRITE_C
+ *
+ * This module is the basis for creating X.509 certificates and CSRs.
+ */
+// #define POLARSSL_X509_CREATE_C
+
+/**
+ * \def POLARSSL_X509_CRT_WRITE_C
+ *
+ * Enable creating X.509 certificates.
+ *
+ * Module:  library/x509_crt_write.c
+ *
+ * Requires: POLARSSL_CREATE_C
+ *
+ * This module is required for X.509 certificate creation.
+ */
+// #define POLARSSL_X509_CRT_WRITE_C
+
+/**
+ * \def POLARSSL_X509_CSR_WRITE_C
+ *
+ * Enable creating X.509 Certificate Signing Requests (CSR).
+ *
+ * Module:  library/x509_csr_write.c
+ *
+ * Requires: POLARSSL_CREATE_C
+ *
+ * This module is required for X.509 certificate request writing.
+ */
+// #define POLARSSL_X509_CSR_WRITE_C
+
+/**
+ * \def POLARSSL_XTEA_C
+ *
+ * Enable the XTEA block cipher.
+ *
+ * Module:  library/xtea.c
+ * Caller:
+ */
+// #define POLARSSL_XTEA_C
+
+/* \} name SECTION: PolarSSL modules */
+
+/* \} name */
+
+/*
+ * Sanity checks on defines and dependencies
+ */
+#if defined(POLARSSL_CERTS_C) && !defined(POLARSSL_PEM_PARSE_C)
+#error "POLARSSL_CERTS_C defined, but not all prerequisites"
+#endif
+
+#if defined(POLARSSL_CTR_DRBG_C) && !defined(POLARSSL_AES_C)
+#error "POLARSSL_CTR_DRBG_C defined, but not all prerequisites"
+#endif
+
+#if defined(POLARSSL_DHM_C) && !defined(POLARSSL_BIGNUM_C)
+#error "POLARSSL_DHM_C defined, but not all prerequisites"
+#endif
+
+#if defined(POLARSSL_ECDH_C) && !defined(POLARSSL_ECP_C)
+#error "POLARSSL_ECDH_C defined, but not all prerequisites"
+#endif
+
+#if defined(POLARSSL_ECDSA_C) &&            \
+    ( !defined(POLARSSL_ECP_C) ||           \
+      !defined(POLARSSL_ASN1_PARSE_C) ||    \
+      !defined(POLARSSL_ASN1_WRITE_C) )
+#error "POLARSSL_ECDSA_C defined, but not all prerequisites"
+#endif
+
+#if defined(POLARSSL_ECP_C) && ( !defined(POLARSSL_BIGNUM_C) || (   \
+    !defined(POLARSSL_ECP_DP_SECP192R1_ENABLED) &&                  \
+    !defined(POLARSSL_ECP_DP_SECP224R1_ENABLED) &&                  \
+    !defined(POLARSSL_ECP_DP_SECP256R1_ENABLED) &&                  \
+    !defined(POLARSSL_ECP_DP_SECP384R1_ENABLED) &&                  \
+    !defined(POLARSSL_ECP_DP_SECP521R1_ENABLED) &&                  \
+    !defined(POLARSSL_ECP_DP_BP256R1_ENABLED)   &&                  \
+    !defined(POLARSSL_ECP_DP_BP384R1_ENABLED)   &&                  \
+    !defined(POLARSSL_ECP_DP_BP512R1_ENABLED) ) )
+#error "POLARSSL_ECP_C defined, but not all prerequisites"
+#endif
+
+#if defined(POLARSSL_ENTROPY_C) && (!defined(POLARSSL_SHA512_C) &&      \
+                                    !defined(POLARSSL_SHA256_C))
+#error "POLARSSL_ENTROPY_C defined, but not all prerequisites"
+#endif
+#if defined(POLARSSL_ENTROPY_C) && defined(POLARSSL_SHA512_C) &&         \
+    defined(POLARSSL_CONFIG_OPTIONS) && (CTR_DRBG_ENTROPY_LEN > 64)
+#error "CTR_DRBG_ENTROPY_LEN value too high"
+#endif
+#if defined(POLARSSL_ENTROPY_C) && !defined(POLARSSL_SHA512_C) &&        \
+    defined(POLARSSL_CONFIG_OPTIONS) && (CTR_DRBG_ENTROPY_LEN > 32)
+#error "CTR_DRBG_ENTROPY_LEN value too high"
+#endif
+
+#if defined(POLARSSL_GCM_C) && (                                        \
+        !defined(POLARSSL_AES_C) && !defined(POLARSSL_CAMELLIA_C) )
+#error "POLARSSL_GCM_C defined, but not all prerequisites"
+#endif
+
+#if defined(POLARSSL_HAVEGE_C) && !defined(POLARSSL_TIMING_C)
+#error "POLARSSL_HAVEGE_C defined, but not all prerequisites"
+#endif
+
+#if defined(POLARSSL_KEY_EXCHANGE_DHE_PSK_ENABLED) && !defined(POLARSSL_DHM_C)
+#error "POLARSSL_KEY_EXCHANGE_DHE_PSK_ENABLED defined, but not all prerequisites"
+#endif
+
+#if defined(POLARSSL_KEY_EXCHANGE_ECDHE_PSK_ENABLED) &&                     \
+    !defined(POLARSSL_ECDH_C)
+#error "POLARSSL_KEY_EXCHANGE_ECDHE_PSK_ENABLED defined, but not all prerequisites"
+#endif
+
+#if defined(POLARSSL_KEY_EXCHANGE_DHE_RSA_ENABLED) &&                   \
+    ( !defined(POLARSSL_DHM_C) || !defined(POLARSSL_RSA_C) ||           \
+      !defined(POLARSSL_X509_CRT_PARSE_C) || !defined(POLARSSL_PKCS1_V15) )
+#error "POLARSSL_KEY_EXCHANGE_DHE_RSA_ENABLED defined, but not all prerequisites"
+#endif
+
+#if defined(POLARSSL_KEY_EXCHANGE_ECDHE_RSA_ENABLED) &&                 \
+    ( !defined(POLARSSL_ECDH_C) || !defined(POLARSSL_RSA_C) ||          \
+      !defined(POLARSSL_X509_CRT_PARSE_C) || !defined(POLARSSL_PKCS1_V15) )
+#error "POLARSSL_KEY_EXCHANGE_ECDHE_RSA_ENABLED defined, but not all prerequisites"
+#endif
+
+#if defined(POLARSSL_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED) &&                 \
+    ( !defined(POLARSSL_ECDH_C) || !defined(POLARSSL_ECDSA_C) ||          \
+      !defined(POLARSSL_X509_CRT_PARSE_C) )
+#error "POLARSSL_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED defined, but not all prerequisites"
+#endif
+
+#if defined(POLARSSL_KEY_EXCHANGE_RSA_PSK_ENABLED) &&                   \
+    ( !defined(POLARSSL_RSA_C) || !defined(POLARSSL_X509_CRT_PARSE_C) ||\
+      !defined(POLARSSL_PKCS1_V15) )
+#error "POLARSSL_KEY_EXCHANGE_RSA_PSK_ENABLED defined, but not all prerequisites"
+#endif
+
+#if defined(POLARSSL_KEY_EXCHANGE_RSA_ENABLED) &&                       \
+    ( !defined(POLARSSL_RSA_C) || !defined(POLARSSL_X509_CRT_PARSE_C) ||\
+      !defined(POLARSSL_PKCS1_V15) )
+#error "POLARSSL_KEY_EXCHANGE_RSA_ENABLED defined, but not all prerequisites"
+#endif
+
+#if defined(POLARSSL_MEMORY_BUFFER_ALLOC_C) && !defined(POLARSSL_MEMORY_C)
+#error "POLARSSL_MEMORY_BUFFER_ALLOC_C defined, but not all prerequisites"
+#endif
+
+#if defined(POLARSSL_PBKDF2_C) && !defined(POLARSSL_MD_C)
+#error "POLARSSL_PBKDF2_C defined, but not all prerequisites"
+#endif
+
+#if defined(POLARSSL_PEM_PARSE_C) && !defined(POLARSSL_BASE64_C)
+#error "POLARSSL_PEM_PARSE_C defined, but not all prerequisites"
+#endif
+
+#if defined(POLARSSL_PEM_WRITE_C) && !defined(POLARSSL_BASE64_C)
+#error "POLARSSL_PEM_WRITE_C defined, but not all prerequisites"
+#endif
+
+#if defined(POLARSSL_PK_PARSE_C) && !defined(POLARSSL_PK_C)
+#error "POLARSSL_PK_PARSE_C defined, but not all prerequisites"
+#endif
+
+#if defined(POLARSSL_PK_WRITE_C) && !defined(POLARSSL_PK_C)
+#error "POLARSSL_PK_WRITE_C defined, but not all prerequisites"
+#endif
+
+#if defined(POLARSSL_PKCS11_C) && !defined(POLARSSL_PK_C)
+#error "POLARSSL_PKCS11_C defined, but not all prerequisites"
+#endif
+
+#if defined(POLARSSL_RSA_C) && ( !defined(POLARSSL_BIGNUM_C) ||         \
+    !defined(POLARSSL_OID_C) )
+#error "POLARSSL_RSA_C defined, but not all prerequisites"
+#endif
+
+#if defined(POLARSSL_SSL_PROTO_SSL3) && ( !defined(POLARSSL_MD5_C) ||     \
+    !defined(POLARSSL_SHA1_C) )
+#error "POLARSSL_SSL_PROTO_SSL3 defined, but not all prerequisites"
+#endif
+
+#if defined(POLARSSL_SSL_PROTO_TLS1) && ( !defined(POLARSSL_MD5_C) ||     \
+    !defined(POLARSSL_SHA1_C) )
+#error "POLARSSL_SSL_PROTO_TLS1 defined, but not all prerequisites"
+#endif
+
+#if defined(POLARSSL_SSL_PROTO_TLS1_1) && ( !defined(POLARSSL_MD5_C) ||     \
+    !defined(POLARSSL_SHA1_C) )
+#error "POLARSSL_SSL_PROTO_TLS1_1 defined, but not all prerequisites"
+#endif
+
+#if defined(POLARSSL_SSL_PROTO_TLS1_2) && ( !defined(POLARSSL_SHA1_C) &&     \
+    !defined(POLARSSL_SHA256_C) && !defined(POLARSSL_SHA512_C) )
+#error "POLARSSL_SSL_PROTO_TLS1_2 defined, but not all prerequisites"
+#endif
+
+#if defined(POLARSSL_SSL_CLI_C) && !defined(POLARSSL_SSL_TLS_C)
+#error "POLARSSL_SSL_CLI_C defined, but not all prerequisites"
+#endif
+
+#if defined(POLARSSL_SSL_TLS_C) && ( !defined(POLARSSL_CIPHER_C) ||     \
+    !defined(POLARSSL_MD_C) )
+#error "POLARSSL_SSL_TLS_C defined, but not all prerequisites"
+#endif
+
+#if defined(POLARSSL_SSL_SRV_C) && !defined(POLARSSL_SSL_TLS_C)
+#error "POLARSSL_SSL_SRV_C defined, but not all prerequisites"
+#endif
+
+#if defined(POLARSSL_SSL_TLS_C) && (!defined(POLARSSL_SSL_PROTO_SSL3) && \
+    !defined(POLARSSL_SSL_PROTO_TLS1) && !defined(POLARSSL_SSL_PROTO_TLS1_1) && \
+    !defined(POLARSSL_SSL_PROTO_TLS1_2))
+#error "POLARSSL_SSL_TLS_C defined, but no protocols are active"
+#endif
+
+#if defined(POLARSSL_SSL_TLS_C) && (defined(POLARSSL_SSL_PROTO_SSL3) && \
+    defined(POLARSSL_SSL_PROTO_TLS1_1) && !defined(POLARSSL_SSL_PROTO_TLS1))
+#error "Illegal protocol selection"
+#endif
+
+#if defined(POLARSSL_SSL_TLS_C) && (defined(POLARSSL_SSL_PROTO_TLS1) && \
+    defined(POLARSSL_SSL_PROTO_TLS1_2) && !defined(POLARSSL_SSL_PROTO_TLS1_1))
+#error "Illegal protocol selection"
+#endif
+
+#if defined(POLARSSL_SSL_TLS_C) && (defined(POLARSSL_SSL_PROTO_SSL3) && \
+    defined(POLARSSL_SSL_PROTO_TLS1_2) && (!defined(POLARSSL_SSL_PROTO_TLS1) || \
+    !defined(POLARSSL_SSL_PROTO_TLS1_1)))
+#error "Illegal protocol selection"
+#endif
+
+#if defined(POLARSSL_SSL_SESSION_TICKETS) && defined(POLARSSL_SSL_TLS_C) && \
+    ( !defined(POLARSSL_AES_C) || !defined(POLARSSL_SHA256_C) ||            \
+      !defined(POLARSSL_CIPHER_MODE_CBC) )
+#error "POLARSSL_SSL_SESSION_TICKETS_C defined, but not all prerequisites"
+#endif
+
+#if defined(POLARSSL_THREADING_DUMMY)
+#if !defined(POLARSSL_THREADING_C) || defined(POLARSSL_THREADING_IMPL)
+#error "POLARSSL_THREADING_DUMMY defined, but not all prerequisites"
+#endif
+#define POLARSSL_THREADING_IMPL
+#endif
+
+#if defined(POLARSSL_THREADING_PTHREAD)
+#if !defined(POLARSSL_THREADING_C) || defined(POLARSSL_THREADING_IMPL)
+#error "POLARSSL_THREADING_PTHREAD defined, but not all prerequisites"
+#endif
+#define POLARSSL_THREADING_IMPL
+#endif
+
+#if defined(POLARSSL_THREADING_ALT)
+#if !defined(POLARSSL_THREADING_C) || defined(POLARSSL_THREADING_IMPL)
+#error "POLARSSL_THREADING_ALT defined, but not all prerequisites"
+#endif
+#define POLARSSL_THREADING_IMPL
+#endif
+
+#if defined(POLARSSL_THREADING_C) && !defined(POLARSSL_THREADING_IMPL)
+#error "POLARSSL_THREADING_C defined, single threading implementation required"
+#endif
+#undef POLARSSL_THREADING_IMPL
+
+#if defined(POLARSSL_X509_USE_C) && ( !defined(POLARSSL_BIGNUM_C) ||  \
+    !defined(POLARSSL_OID_C) || !defined(POLARSSL_ASN1_PARSE_C) ||      \
+    !defined(POLARSSL_PK_PARSE_C) )
+#error "POLARSSL_X509_USE_C defined, but not all prerequisites"
+#endif
+
+#if defined(POLARSSL_X509_CREATE_C) && ( !defined(POLARSSL_BIGNUM_C) ||  \
+    !defined(POLARSSL_OID_C) || !defined(POLARSSL_ASN1_WRITE_C) ||       \
+    !defined(POLARSSL_PK_WRITE_C) )
+#error "POLARSSL_X509_CREATE_C defined, but not all prerequisites"
+#endif
+
+#if defined(POLARSSL_X509_CRT_PARSE_C) && ( !defined(POLARSSL_X509_USE_C) )
+#error "POLARSSL_X509_CRT_PARSE_C defined, but not all prerequisites"
+#endif
+
+#if defined(POLARSSL_X509_CRL_PARSE_C) && ( !defined(POLARSSL_X509_USE_C) )
+#error "POLARSSL_X509_CRL_PARSE_C defined, but not all prerequisites"
+#endif
+
+#if defined(POLARSSL_X509_CSR_PARSE_C) && ( !defined(POLARSSL_X509_USE_C) )
+#error "POLARSSL_X509_CSR_PARSE_C defined, but not all prerequisites"
+#endif
+
+#if defined(POLARSSL_X509_CRT_WRITE_C) && ( !defined(POLARSSL_X509_CREATE_C) )
+#error "POLARSSL_X509_CRT_WRITE_C defined, but not all prerequisites"
+#endif
+
+#if defined(POLARSSL_X509_CSR_WRITE_C) && ( !defined(POLARSSL_X509_CREATE_C) )
+#error "POLARSSL_X509_CSR_WRITE_C defined, but not all prerequisites"
+#endif
+
+#endif /* config.h */
diff --git a/drivers/net/ethernet/acts/des.c b/drivers/net/ethernet/acts/des.c
new file mode 100755
index 0000000..f3a765d
--- /dev/null
+++ b/drivers/net/ethernet/acts/des.c
@@ -0,0 +1,1063 @@
+/*
+ *  FIPS-46-3 compliant Triple-DES implementation
+ *
+ *  Copyright (C) 2006-2014, ARM Limited, All Rights Reserved
+ *
+ *  This file is part of mbed TLS (https://tls.mbed.org)
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+/*
+ *  DES, on which TDES is based, was originally designed by Horst Feistel
+ *  at IBM in 1974, and was adopted as a standard by NIST (formerly NBS).
+ *
+ *  http://csrc.nist.gov/publications/fips/fips46-3/fips46-3.pdf
+ */
+
+#if !defined(MBEDTLS_CONFIG_FILE)
+#include "config.h"
+#else
+#include MBEDTLS_CONFIG_FILE
+#endif
+
+#define MBEDTLS_DES_C
+#if defined(MBEDTLS_DES_C)
+
+#include "des.h"
+
+#include <linux/string.h>
+
+#if defined(MBEDTLS_SELF_TEST)
+#if defined(MBEDTLS_PLATFORM_C)
+#include "mbedtls/platform.h"
+#else
+#include <stdio.h>
+#define mbedtls_printf printf
+#endif /* MBEDTLS_PLATFORM_C */
+#endif /* MBEDTLS_SELF_TEST */
+
+#if !defined(MBEDTLS_DES_ALT)
+
+/* Implementation that should never be optimized out by the compiler */
+static void mbedtls_zeroize( void *v, size_t n ) {
+    volatile unsigned char *p = v; while( n-- ) *p++ = 0;
+}
+
+/*
+ * 32-bit integer manipulation macros (big endian)
+ */
+#ifndef GET_UINT32_BE
+#define GET_UINT32_BE(n,b,i)                            \
+{                                                       \
+    (n) = ( (uint32_t) (b)[(i)    ] << 24 )             \
+        | ( (uint32_t) (b)[(i) + 1] << 16 )             \
+        | ( (uint32_t) (b)[(i) + 2] <<  8 )             \
+        | ( (uint32_t) (b)[(i) + 3]       );            \
+}
+#endif
+
+#ifndef PUT_UINT32_BE
+#define PUT_UINT32_BE(n,b,i)                            \
+{                                                       \
+    (b)[(i)    ] = (unsigned char) ( (n) >> 24 );       \
+    (b)[(i) + 1] = (unsigned char) ( (n) >> 16 );       \
+    (b)[(i) + 2] = (unsigned char) ( (n) >>  8 );       \
+    (b)[(i) + 3] = (unsigned char) ( (n)       );       \
+}
+#endif
+
+/*
+ * Expanded DES S-boxes
+ */
+static const uint32_t SB1[64] =
+{
+    0x01010400, 0x00000000, 0x00010000, 0x01010404,
+    0x01010004, 0x00010404, 0x00000004, 0x00010000,
+    0x00000400, 0x01010400, 0x01010404, 0x00000400,
+    0x01000404, 0x01010004, 0x01000000, 0x00000004,
+    0x00000404, 0x01000400, 0x01000400, 0x00010400,
+    0x00010400, 0x01010000, 0x01010000, 0x01000404,
+    0x00010004, 0x01000004, 0x01000004, 0x00010004,
+    0x00000000, 0x00000404, 0x00010404, 0x01000000,
+    0x00010000, 0x01010404, 0x00000004, 0x01010000,
+    0x01010400, 0x01000000, 0x01000000, 0x00000400,
+    0x01010004, 0x00010000, 0x00010400, 0x01000004,
+    0x00000400, 0x00000004, 0x01000404, 0x00010404,
+    0x01010404, 0x00010004, 0x01010000, 0x01000404,
+    0x01000004, 0x00000404, 0x00010404, 0x01010400,
+    0x00000404, 0x01000400, 0x01000400, 0x00000000,
+    0x00010004, 0x00010400, 0x00000000, 0x01010004
+};
+
+static const uint32_t SB2[64] =
+{
+    0x80108020, 0x80008000, 0x00008000, 0x00108020,
+    0x00100000, 0x00000020, 0x80100020, 0x80008020,
+    0x80000020, 0x80108020, 0x80108000, 0x80000000,
+    0x80008000, 0x00100000, 0x00000020, 0x80100020,
+    0x00108000, 0x00100020, 0x80008020, 0x00000000,
+    0x80000000, 0x00008000, 0x00108020, 0x80100000,
+    0x00100020, 0x80000020, 0x00000000, 0x00108000,
+    0x00008020, 0x80108000, 0x80100000, 0x00008020,
+    0x00000000, 0x00108020, 0x80100020, 0x00100000,
+    0x80008020, 0x80100000, 0x80108000, 0x00008000,
+    0x80100000, 0x80008000, 0x00000020, 0x80108020,
+    0x00108020, 0x00000020, 0x00008000, 0x80000000,
+    0x00008020, 0x80108000, 0x00100000, 0x80000020,
+    0x00100020, 0x80008020, 0x80000020, 0x00100020,
+    0x00108000, 0x00000000, 0x80008000, 0x00008020,
+    0x80000000, 0x80100020, 0x80108020, 0x00108000
+};
+
+static const uint32_t SB3[64] =
+{
+    0x00000208, 0x08020200, 0x00000000, 0x08020008,
+    0x08000200, 0x00000000, 0x00020208, 0x08000200,
+    0x00020008, 0x08000008, 0x08000008, 0x00020000,
+    0x08020208, 0x00020008, 0x08020000, 0x00000208,
+    0x08000000, 0x00000008, 0x08020200, 0x00000200,
+    0x00020200, 0x08020000, 0x08020008, 0x00020208,
+    0x08000208, 0x00020200, 0x00020000, 0x08000208,
+    0x00000008, 0x08020208, 0x00000200, 0x08000000,
+    0x08020200, 0x08000000, 0x00020008, 0x00000208,
+    0x00020000, 0x08020200, 0x08000200, 0x00000000,
+    0x00000200, 0x00020008, 0x08020208, 0x08000200,
+    0x08000008, 0x00000200, 0x00000000, 0x08020008,
+    0x08000208, 0x00020000, 0x08000000, 0x08020208,
+    0x00000008, 0x00020208, 0x00020200, 0x08000008,
+    0x08020000, 0x08000208, 0x00000208, 0x08020000,
+    0x00020208, 0x00000008, 0x08020008, 0x00020200
+};
+
+static const uint32_t SB4[64] =
+{
+    0x00802001, 0x00002081, 0x00002081, 0x00000080,
+    0x00802080, 0x00800081, 0x00800001, 0x00002001,
+    0x00000000, 0x00802000, 0x00802000, 0x00802081,
+    0x00000081, 0x00000000, 0x00800080, 0x00800001,
+    0x00000001, 0x00002000, 0x00800000, 0x00802001,
+    0x00000080, 0x00800000, 0x00002001, 0x00002080,
+    0x00800081, 0x00000001, 0x00002080, 0x00800080,
+    0x00002000, 0x00802080, 0x00802081, 0x00000081,
+    0x00800080, 0x00800001, 0x00802000, 0x00802081,
+    0x00000081, 0x00000000, 0x00000000, 0x00802000,
+    0x00002080, 0x00800080, 0x00800081, 0x00000001,
+    0x00802001, 0x00002081, 0x00002081, 0x00000080,
+    0x00802081, 0x00000081, 0x00000001, 0x00002000,
+    0x00800001, 0x00002001, 0x00802080, 0x00800081,
+    0x00002001, 0x00002080, 0x00800000, 0x00802001,
+    0x00000080, 0x00800000, 0x00002000, 0x00802080
+};
+
+static const uint32_t SB5[64] =
+{
+    0x00000100, 0x02080100, 0x02080000, 0x42000100,
+    0x00080000, 0x00000100, 0x40000000, 0x02080000,
+    0x40080100, 0x00080000, 0x02000100, 0x40080100,
+    0x42000100, 0x42080000, 0x00080100, 0x40000000,
+    0x02000000, 0x40080000, 0x40080000, 0x00000000,
+    0x40000100, 0x42080100, 0x42080100, 0x02000100,
+    0x42080000, 0x40000100, 0x00000000, 0x42000000,
+    0x02080100, 0x02000000, 0x42000000, 0x00080100,
+    0x00080000, 0x42000100, 0x00000100, 0x02000000,
+    0x40000000, 0x02080000, 0x42000100, 0x40080100,
+    0x02000100, 0x40000000, 0x42080000, 0x02080100,
+    0x40080100, 0x00000100, 0x02000000, 0x42080000,
+    0x42080100, 0x00080100, 0x42000000, 0x42080100,
+    0x02080000, 0x00000000, 0x40080000, 0x42000000,
+    0x00080100, 0x02000100, 0x40000100, 0x00080000,
+    0x00000000, 0x40080000, 0x02080100, 0x40000100
+};
+
+static const uint32_t SB6[64] =
+{
+    0x20000010, 0x20400000, 0x00004000, 0x20404010,
+    0x20400000, 0x00000010, 0x20404010, 0x00400000,
+    0x20004000, 0x00404010, 0x00400000, 0x20000010,
+    0x00400010, 0x20004000, 0x20000000, 0x00004010,
+    0x00000000, 0x00400010, 0x20004010, 0x00004000,
+    0x00404000, 0x20004010, 0x00000010, 0x20400010,
+    0x20400010, 0x00000000, 0x00404010, 0x20404000,
+    0x00004010, 0x00404000, 0x20404000, 0x20000000,
+    0x20004000, 0x00000010, 0x20400010, 0x00404000,
+    0x20404010, 0x00400000, 0x00004010, 0x20000010,
+    0x00400000, 0x20004000, 0x20000000, 0x00004010,
+    0x20000010, 0x20404010, 0x00404000, 0x20400000,
+    0x00404010, 0x20404000, 0x00000000, 0x20400010,
+    0x00000010, 0x00004000, 0x20400000, 0x00404010,
+    0x00004000, 0x00400010, 0x20004010, 0x00000000,
+    0x20404000, 0x20000000, 0x00400010, 0x20004010
+};
+
+static const uint32_t SB7[64] =
+{
+    0x00200000, 0x04200002, 0x04000802, 0x00000000,
+    0x00000800, 0x04000802, 0x00200802, 0x04200800,
+    0x04200802, 0x00200000, 0x00000000, 0x04000002,
+    0x00000002, 0x04000000, 0x04200002, 0x00000802,
+    0x04000800, 0x00200802, 0x00200002, 0x04000800,
+    0x04000002, 0x04200000, 0x04200800, 0x00200002,
+    0x04200000, 0x00000800, 0x00000802, 0x04200802,
+    0x00200800, 0x00000002, 0x04000000, 0x00200800,
+    0x04000000, 0x00200800, 0x00200000, 0x04000802,
+    0x04000802, 0x04200002, 0x04200002, 0x00000002,
+    0x00200002, 0x04000000, 0x04000800, 0x00200000,
+    0x04200800, 0x00000802, 0x00200802, 0x04200800,
+    0x00000802, 0x04000002, 0x04200802, 0x04200000,
+    0x00200800, 0x00000000, 0x00000002, 0x04200802,
+    0x00000000, 0x00200802, 0x04200000, 0x00000800,
+    0x04000002, 0x04000800, 0x00000800, 0x00200002
+};
+
+static const uint32_t SB8[64] =
+{
+    0x10001040, 0x00001000, 0x00040000, 0x10041040,
+    0x10000000, 0x10001040, 0x00000040, 0x10000000,
+    0x00040040, 0x10040000, 0x10041040, 0x00041000,
+    0x10041000, 0x00041040, 0x00001000, 0x00000040,
+    0x10040000, 0x10000040, 0x10001000, 0x00001040,
+    0x00041000, 0x00040040, 0x10040040, 0x10041000,
+    0x00001040, 0x00000000, 0x00000000, 0x10040040,
+    0x10000040, 0x10001000, 0x00041040, 0x00040000,
+    0x00041040, 0x00040000, 0x10041000, 0x00001000,
+    0x00000040, 0x10040040, 0x00001000, 0x00041040,
+    0x10001000, 0x00000040, 0x10000040, 0x10040000,
+    0x10040040, 0x10000000, 0x00040000, 0x10001040,
+    0x00000000, 0x10041040, 0x00040040, 0x10000040,
+    0x10040000, 0x10001000, 0x10001040, 0x00000000,
+    0x10041040, 0x00041000, 0x00041000, 0x00001040,
+    0x00001040, 0x00040040, 0x10000000, 0x10041000
+};
+
+/*
+ * PC1: left and right halves bit-swap
+ */
+static const uint32_t LHs[16] =
+{
+    0x00000000, 0x00000001, 0x00000100, 0x00000101,
+    0x00010000, 0x00010001, 0x00010100, 0x00010101,
+    0x01000000, 0x01000001, 0x01000100, 0x01000101,
+    0x01010000, 0x01010001, 0x01010100, 0x01010101
+};
+
+static const uint32_t RHs[16] =
+{
+    0x00000000, 0x01000000, 0x00010000, 0x01010000,
+    0x00000100, 0x01000100, 0x00010100, 0x01010100,
+    0x00000001, 0x01000001, 0x00010001, 0x01010001,
+    0x00000101, 0x01000101, 0x00010101, 0x01010101,
+};
+
+/*
+ * Initial Permutation macro
+ */
+#define DES_IP(X,Y)                                             \
+{                                                               \
+    T = ((X >>  4) ^ Y) & 0x0F0F0F0F; Y ^= T; X ^= (T <<  4);   \
+    T = ((X >> 16) ^ Y) & 0x0000FFFF; Y ^= T; X ^= (T << 16);   \
+    T = ((Y >>  2) ^ X) & 0x33333333; X ^= T; Y ^= (T <<  2);   \
+    T = ((Y >>  8) ^ X) & 0x00FF00FF; X ^= T; Y ^= (T <<  8);   \
+    Y = ((Y << 1) | (Y >> 31)) & 0xFFFFFFFF;                    \
+    T = (X ^ Y) & 0xAAAAAAAA; Y ^= T; X ^= T;                   \
+    X = ((X << 1) | (X >> 31)) & 0xFFFFFFFF;                    \
+}
+
+/*
+ * Final Permutation macro
+ */
+#define DES_FP(X,Y)                                             \
+{                                                               \
+    X = ((X << 31) | (X >> 1)) & 0xFFFFFFFF;                    \
+    T = (X ^ Y) & 0xAAAAAAAA; X ^= T; Y ^= T;                   \
+    Y = ((Y << 31) | (Y >> 1)) & 0xFFFFFFFF;                    \
+    T = ((Y >>  8) ^ X) & 0x00FF00FF; X ^= T; Y ^= (T <<  8);   \
+    T = ((Y >>  2) ^ X) & 0x33333333; X ^= T; Y ^= (T <<  2);   \
+    T = ((X >> 16) ^ Y) & 0x0000FFFF; Y ^= T; X ^= (T << 16);   \
+    T = ((X >>  4) ^ Y) & 0x0F0F0F0F; Y ^= T; X ^= (T <<  4);   \
+}
+
+/*
+ * DES round macro
+ */
+#define DES_ROUND(X,Y)                          \
+{                                               \
+    T = *SK++ ^ X;                              \
+    Y ^= SB8[ (T      ) & 0x3F ] ^              \
+         SB6[ (T >>  8) & 0x3F ] ^              \
+         SB4[ (T >> 16) & 0x3F ] ^              \
+         SB2[ (T >> 24) & 0x3F ];               \
+                                                \
+    T = *SK++ ^ ((X << 28) | (X >> 4));         \
+    Y ^= SB7[ (T      ) & 0x3F ] ^              \
+         SB5[ (T >>  8) & 0x3F ] ^              \
+         SB3[ (T >> 16) & 0x3F ] ^              \
+         SB1[ (T >> 24) & 0x3F ];               \
+}
+
+#define SWAP(a,b) { uint32_t t = a; a = b; b = t; t = 0; }
+
+void mbedtls_des_init( mbedtls_des_context *ctx )
+{
+    memset( ctx, 0, sizeof( mbedtls_des_context ) );
+}
+
+void mbedtls_des_free( mbedtls_des_context *ctx )
+{
+    if( ctx == NULL )
+        return;
+
+    mbedtls_zeroize( ctx, sizeof( mbedtls_des_context ) );
+}
+
+void mbedtls_des3_init( mbedtls_des3_context *ctx )
+{
+    memset( ctx, 0, sizeof( mbedtls_des3_context ) );
+}
+
+void mbedtls_des3_free( mbedtls_des3_context *ctx )
+{
+    if( ctx == NULL )
+        return;
+
+    mbedtls_zeroize( ctx, sizeof( mbedtls_des3_context ) );
+}
+
+static const unsigned char odd_parity_table[128] = { 1,  2,  4,  7,  8,
+        11, 13, 14, 16, 19, 21, 22, 25, 26, 28, 31, 32, 35, 37, 38, 41, 42, 44,
+        47, 49, 50, 52, 55, 56, 59, 61, 62, 64, 67, 69, 70, 73, 74, 76, 79, 81,
+        82, 84, 87, 88, 91, 93, 94, 97, 98, 100, 103, 104, 107, 109, 110, 112,
+        115, 117, 118, 121, 122, 124, 127, 128, 131, 133, 134, 137, 138, 140,
+        143, 145, 146, 148, 151, 152, 155, 157, 158, 161, 162, 164, 167, 168,
+        171, 173, 174, 176, 179, 181, 182, 185, 186, 188, 191, 193, 194, 196,
+        199, 200, 203, 205, 206, 208, 211, 213, 214, 217, 218, 220, 223, 224,
+        227, 229, 230, 233, 234, 236, 239, 241, 242, 244, 247, 248, 251, 253,
+        254 };
+
+void mbedtls_des_key_set_parity( unsigned char key[MBEDTLS_DES_KEY_SIZE] )
+{
+    int i;
+
+    for( i = 0; i < MBEDTLS_DES_KEY_SIZE; i++ )
+        key[i] = odd_parity_table[key[i] / 2];
+}
+
+/*
+ * Check the given key's parity, returns 1 on failure, 0 on SUCCESS
+ */
+int mbedtls_des_key_check_key_parity( const unsigned char key[MBEDTLS_DES_KEY_SIZE] )
+{
+    int i;
+
+    for( i = 0; i < MBEDTLS_DES_KEY_SIZE; i++ )
+        if( key[i] != odd_parity_table[key[i] / 2] )
+            return( 1 );
+
+    return( 0 );
+}
+
+/*
+ * Table of weak and semi-weak keys
+ *
+ * Source: http://en.wikipedia.org/wiki/Weak_key
+ *
+ * Weak:
+ * Alternating ones + zeros (0x0101010101010101)
+ * Alternating 'F' + 'E' (0xFEFEFEFEFEFEFEFE)
+ * '0xE0E0E0E0F1F1F1F1'
+ * '0x1F1F1F1F0E0E0E0E'
+ *
+ * Semi-weak:
+ * 0x011F011F010E010E and 0x1F011F010E010E01
+ * 0x01E001E001F101F1 and 0xE001E001F101F101
+ * 0x01FE01FE01FE01FE and 0xFE01FE01FE01FE01
+ * 0x1FE01FE00EF10EF1 and 0xE01FE01FF10EF10E
+ * 0x1FFE1FFE0EFE0EFE and 0xFE1FFE1FFE0EFE0E
+ * 0xE0FEE0FEF1FEF1FE and 0xFEE0FEE0FEF1FEF1
+ *
+ */
+
+#define WEAK_KEY_COUNT 16
+
+static const unsigned char weak_key_table[WEAK_KEY_COUNT][MBEDTLS_DES_KEY_SIZE] =
+{
+    { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 },
+    { 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE },
+    { 0x1F, 0x1F, 0x1F, 0x1F, 0x0E, 0x0E, 0x0E, 0x0E },
+    { 0xE0, 0xE0, 0xE0, 0xE0, 0xF1, 0xF1, 0xF1, 0xF1 },
+
+    { 0x01, 0x1F, 0x01, 0x1F, 0x01, 0x0E, 0x01, 0x0E },
+    { 0x1F, 0x01, 0x1F, 0x01, 0x0E, 0x01, 0x0E, 0x01 },
+    { 0x01, 0xE0, 0x01, 0xE0, 0x01, 0xF1, 0x01, 0xF1 },
+    { 0xE0, 0x01, 0xE0, 0x01, 0xF1, 0x01, 0xF1, 0x01 },
+    { 0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE },
+    { 0xFE, 0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE, 0x01 },
+    { 0x1F, 0xE0, 0x1F, 0xE0, 0x0E, 0xF1, 0x0E, 0xF1 },
+    { 0xE0, 0x1F, 0xE0, 0x1F, 0xF1, 0x0E, 0xF1, 0x0E },
+    { 0x1F, 0xFE, 0x1F, 0xFE, 0x0E, 0xFE, 0x0E, 0xFE },
+    { 0xFE, 0x1F, 0xFE, 0x1F, 0xFE, 0x0E, 0xFE, 0x0E },
+    { 0xE0, 0xFE, 0xE0, 0xFE, 0xF1, 0xFE, 0xF1, 0xFE },
+    { 0xFE, 0xE0, 0xFE, 0xE0, 0xFE, 0xF1, 0xFE, 0xF1 }
+};
+
+int mbedtls_des_key_check_weak( const unsigned char key[MBEDTLS_DES_KEY_SIZE] )
+{
+    int i;
+
+    for( i = 0; i < WEAK_KEY_COUNT; i++ )
+        if( memcmp( weak_key_table[i], key, MBEDTLS_DES_KEY_SIZE) == 0 )
+            return( 1 );
+
+    return( 0 );
+}
+
+#if !defined(MBEDTLS_DES_SETKEY_ALT)
+void mbedtls_des_setkey( uint32_t SK[32], const unsigned char key[MBEDTLS_DES_KEY_SIZE] )
+{
+    int i;
+    uint32_t X, Y, T;
+
+    GET_UINT32_BE( X, key, 0 );
+    GET_UINT32_BE( Y, key, 4 );
+
+    /*
+     * Permuted Choice 1
+     */
+    T =  ((Y >>  4) ^ X) & 0x0F0F0F0F;  X ^= T; Y ^= (T <<  4);
+    T =  ((Y      ) ^ X) & 0x10101010;  X ^= T; Y ^= (T      );
+
+    X =   (LHs[ (X      ) & 0xF] << 3) | (LHs[ (X >>  8) & 0xF ] << 2)
+        | (LHs[ (X >> 16) & 0xF] << 1) | (LHs[ (X >> 24) & 0xF ]     )
+        | (LHs[ (X >>  5) & 0xF] << 7) | (LHs[ (X >> 13) & 0xF ] << 6)
+        | (LHs[ (X >> 21) & 0xF] << 5) | (LHs[ (X >> 29) & 0xF ] << 4);
+
+    Y =   (RHs[ (Y >>  1) & 0xF] << 3) | (RHs[ (Y >>  9) & 0xF ] << 2)
+        | (RHs[ (Y >> 17) & 0xF] << 1) | (RHs[ (Y >> 25) & 0xF ]     )
+        | (RHs[ (Y >>  4) & 0xF] << 7) | (RHs[ (Y >> 12) & 0xF ] << 6)
+        | (RHs[ (Y >> 20) & 0xF] << 5) | (RHs[ (Y >> 28) & 0xF ] << 4);
+
+    X &= 0x0FFFFFFF;
+    Y &= 0x0FFFFFFF;
+
+    /*
+     * calculate subkeys
+     */
+    for( i = 0; i < 16; i++ )
+    {
+        if( i < 2 || i == 8 || i == 15 )
+        {
+            X = ((X <<  1) | (X >> 27)) & 0x0FFFFFFF;
+            Y = ((Y <<  1) | (Y >> 27)) & 0x0FFFFFFF;
+        }
+        else
+        {
+            X = ((X <<  2) | (X >> 26)) & 0x0FFFFFFF;
+            Y = ((Y <<  2) | (Y >> 26)) & 0x0FFFFFFF;
+        }
+
+        *SK++ =   ((X <<  4) & 0x24000000) | ((X << 28) & 0x10000000)
+                | ((X << 14) & 0x08000000) | ((X << 18) & 0x02080000)
+                | ((X <<  6) & 0x01000000) | ((X <<  9) & 0x00200000)
+                | ((X >>  1) & 0x00100000) | ((X << 10) & 0x00040000)
+                | ((X <<  2) & 0x00020000) | ((X >> 10) & 0x00010000)
+                | ((Y >> 13) & 0x00002000) | ((Y >>  4) & 0x00001000)
+                | ((Y <<  6) & 0x00000800) | ((Y >>  1) & 0x00000400)
+                | ((Y >> 14) & 0x00000200) | ((Y      ) & 0x00000100)
+                | ((Y >>  5) & 0x00000020) | ((Y >> 10) & 0x00000010)
+                | ((Y >>  3) & 0x00000008) | ((Y >> 18) & 0x00000004)
+                | ((Y >> 26) & 0x00000002) | ((Y >> 24) & 0x00000001);
+
+        *SK++ =   ((X << 15) & 0x20000000) | ((X << 17) & 0x10000000)
+                | ((X << 10) & 0x08000000) | ((X << 22) & 0x04000000)
+                | ((X >>  2) & 0x02000000) | ((X <<  1) & 0x01000000)
+                | ((X << 16) & 0x00200000) | ((X << 11) & 0x00100000)
+                | ((X <<  3) & 0x00080000) | ((X >>  6) & 0x00040000)
+                | ((X << 15) & 0x00020000) | ((X >>  4) & 0x00010000)
+                | ((Y >>  2) & 0x00002000) | ((Y <<  8) & 0x00001000)
+                | ((Y >> 14) & 0x00000808) | ((Y >>  9) & 0x00000400)
+                | ((Y      ) & 0x00000200) | ((Y <<  7) & 0x00000100)
+                | ((Y >>  7) & 0x00000020) | ((Y >>  3) & 0x00000011)
+                | ((Y <<  2) & 0x00000004) | ((Y >> 21) & 0x00000002);
+    }
+}
+#endif /* !MBEDTLS_DES_SETKEY_ALT */
+
+/*
+ * DES key schedule (56-bit, encryption)
+ */
+int mbedtls_des_setkey_enc( mbedtls_des_context *ctx, const unsigned char key[MBEDTLS_DES_KEY_SIZE] )
+{
+    mbedtls_des_setkey( ctx->sk, key );
+
+    return( 0 );
+}
+
+/*
+ * DES key schedule (56-bit, decryption)
+ */
+int mbedtls_des_setkey_dec( mbedtls_des_context *ctx, const unsigned char key[MBEDTLS_DES_KEY_SIZE] )
+{
+    int i;
+
+    mbedtls_des_setkey( ctx->sk, key );
+
+    for( i = 0; i < 16; i += 2 )
+    {
+        SWAP( ctx->sk[i    ], ctx->sk[30 - i] );
+        SWAP( ctx->sk[i + 1], ctx->sk[31 - i] );
+    }
+
+    return( 0 );
+}
+
+static void des3_set2key( uint32_t esk[96],
+                          uint32_t dsk[96],
+                          const unsigned char key[MBEDTLS_DES_KEY_SIZE*2] )
+{
+    int i;
+
+    mbedtls_des_setkey( esk, key );
+    mbedtls_des_setkey( dsk + 32, key + 8 );
+
+    for( i = 0; i < 32; i += 2 )
+    {
+        dsk[i     ] = esk[30 - i];
+        dsk[i +  1] = esk[31 - i];
+
+        esk[i + 32] = dsk[62 - i];
+        esk[i + 33] = dsk[63 - i];
+
+        esk[i + 64] = esk[i    ];
+        esk[i + 65] = esk[i + 1];
+
+        dsk[i + 64] = dsk[i    ];
+        dsk[i + 65] = dsk[i + 1];
+    }
+}
+
+/*
+ * Triple-DES key schedule (112-bit, encryption)
+ */
+int mbedtls_des3_set2key_enc( mbedtls_des3_context *ctx,
+                      const unsigned char key[MBEDTLS_DES_KEY_SIZE * 2] )
+{
+    uint32_t sk[96];
+
+    des3_set2key( ctx->sk, sk, key );
+    mbedtls_zeroize( sk,  sizeof( sk ) );
+
+    return( 0 );
+}
+
+/*
+ * Triple-DES key schedule (112-bit, decryption)
+ */
+int mbedtls_des3_set2key_dec( mbedtls_des3_context *ctx,
+                      const unsigned char key[MBEDTLS_DES_KEY_SIZE * 2] )
+{
+    uint32_t sk[96];
+
+    des3_set2key( sk, ctx->sk, key );
+    mbedtls_zeroize( sk,  sizeof( sk ) );
+
+    return( 0 );
+}
+
+static void des3_set3key( uint32_t esk[96],
+                          uint32_t dsk[96],
+                          const unsigned char key[24] )
+{
+    int i;
+
+    mbedtls_des_setkey( esk, key );
+    mbedtls_des_setkey( dsk + 32, key +  8 );
+    mbedtls_des_setkey( esk + 64, key + 16 );
+
+    for( i = 0; i < 32; i += 2 )
+    {
+        dsk[i     ] = esk[94 - i];
+        dsk[i +  1] = esk[95 - i];
+
+        esk[i + 32] = dsk[62 - i];
+        esk[i + 33] = dsk[63 - i];
+
+        dsk[i + 64] = esk[30 - i];
+        dsk[i + 65] = esk[31 - i];
+    }
+}
+
+/*
+ * Triple-DES key schedule (168-bit, encryption)
+ */
+int mbedtls_des3_set3key_enc( mbedtls_des3_context *ctx,
+                      const unsigned char key[MBEDTLS_DES_KEY_SIZE * 3] )
+{
+    uint32_t sk[96];
+
+    des3_set3key( ctx->sk, sk, key );
+    mbedtls_zeroize( sk,  sizeof( sk ) );
+
+    return( 0 );
+}
+
+/*
+ * Triple-DES key schedule (168-bit, decryption)
+ */
+int mbedtls_des3_set3key_dec( mbedtls_des3_context *ctx,
+                      const unsigned char key[MBEDTLS_DES_KEY_SIZE * 3] )
+{
+    uint32_t sk[96];
+
+    des3_set3key( sk, ctx->sk, key );
+    mbedtls_zeroize( sk,  sizeof( sk ) );
+
+    return( 0 );
+}
+
+/*
+ * DES-ECB block encryption/decryption
+ */
+#if !defined(MBEDTLS_DES_CRYPT_ECB_ALT)
+int mbedtls_des_crypt_ecb( mbedtls_des_context *ctx,
+                    const unsigned char input[8],
+                    unsigned char output[8] )
+{
+    int i;
+    uint32_t X, Y, T, *SK;
+
+    SK = ctx->sk;
+
+    GET_UINT32_BE( X, input, 0 );
+    GET_UINT32_BE( Y, input, 4 );
+
+    DES_IP( X, Y );
+
+    for( i = 0; i < 8; i++ )
+    {
+        DES_ROUND( Y, X );
+        DES_ROUND( X, Y );
+    }
+
+    DES_FP( Y, X );
+
+    PUT_UINT32_BE( Y, output, 0 );
+    PUT_UINT32_BE( X, output, 4 );
+
+    return( 0 );
+}
+#endif /* !MBEDTLS_DES_CRYPT_ECB_ALT */
+
+#if defined(MBEDTLS_CIPHER_MODE_CBC)
+/*
+ * DES-CBC buffer encryption/decryption
+ */
+int mbedtls_des_crypt_cbc( mbedtls_des_context *ctx,
+                    int mode,
+                    size_t length,
+                    unsigned char iv[8],
+                    const unsigned char *input,
+                    unsigned char *output )
+{
+    int i;
+    unsigned char temp[8];
+
+    if( length % 8 )
+        return( MBEDTLS_ERR_DES_INVALID_INPUT_LENGTH );
+
+    if( mode == MBEDTLS_DES_ENCRYPT )
+    {
+        while( length > 0 )
+        {
+            for( i = 0; i < 8; i++ )
+                output[i] = (unsigned char)( input[i] ^ iv[i] );
+
+            mbedtls_des_crypt_ecb( ctx, output, output );
+            memcpy( iv, output, 8 );
+
+            input  += 8;
+            output += 8;
+            length -= 8;
+        }
+    }
+    else /* MBEDTLS_DES_DECRYPT */
+    {
+        while( length > 0 )
+        {
+            memcpy( temp, input, 8 );
+            mbedtls_des_crypt_ecb( ctx, input, output );
+
+            for( i = 0; i < 8; i++ )
+                output[i] = (unsigned char)( output[i] ^ iv[i] );
+
+            memcpy( iv, temp, 8 );
+
+            input  += 8;
+            output += 8;
+            length -= 8;
+        }
+    }
+
+    return( 0 );
+}
+#endif /* MBEDTLS_CIPHER_MODE_CBC */
+
+/*
+ * 3DES-ECB block encryption/decryption
+ */
+#if !defined(MBEDTLS_DES3_CRYPT_ECB_ALT)
+int mbedtls_des3_crypt_ecb( mbedtls_des3_context *ctx,
+                     const unsigned char input[8],
+                     unsigned char output[8] )
+{
+    int i;
+    uint32_t X, Y, T, *SK;
+
+    SK = ctx->sk;
+
+    GET_UINT32_BE( X, input, 0 );
+    GET_UINT32_BE( Y, input, 4 );
+
+    DES_IP( X, Y );
+
+    for( i = 0; i < 8; i++ )
+    {
+        DES_ROUND( Y, X );
+        DES_ROUND( X, Y );
+    }
+
+    for( i = 0; i < 8; i++ )
+    {
+        DES_ROUND( X, Y );
+        DES_ROUND( Y, X );
+    }
+
+    for( i = 0; i < 8; i++ )
+    {
+        DES_ROUND( Y, X );
+        DES_ROUND( X, Y );
+    }
+
+    DES_FP( Y, X );
+
+    PUT_UINT32_BE( Y, output, 0 );
+    PUT_UINT32_BE( X, output, 4 );
+
+    return( 0 );
+}
+#endif /* !MBEDTLS_DES3_CRYPT_ECB_ALT */
+
+#if defined(MBEDTLS_CIPHER_MODE_CBC)
+/*
+ * 3DES-CBC buffer encryption/decryption
+ */
+int mbedtls_des3_crypt_cbc( mbedtls_des3_context *ctx,
+                     int mode,
+                     size_t length,
+                     unsigned char iv[8],
+                     const unsigned char *input,
+                     unsigned char *output )
+{
+    int i;
+    unsigned char temp[8];
+
+    if( length % 8 )
+        return( MBEDTLS_ERR_DES_INVALID_INPUT_LENGTH );
+
+    if( mode == MBEDTLS_DES_ENCRYPT )
+    {
+        while( length > 0 )
+        {
+            for( i = 0; i < 8; i++ )
+                output[i] = (unsigned char)( input[i] ^ iv[i] );
+
+            mbedtls_des3_crypt_ecb( ctx, output, output );
+            memcpy( iv, output, 8 );
+
+            input  += 8;
+            output += 8;
+            length -= 8;
+        }
+    }
+    else /* MBEDTLS_DES_DECRYPT */
+    {
+        while( length > 0 )
+        {
+            memcpy( temp, input, 8 );
+            mbedtls_des3_crypt_ecb( ctx, input, output );
+
+            for( i = 0; i < 8; i++ )
+                output[i] = (unsigned char)( output[i] ^ iv[i] );
+
+            memcpy( iv, temp, 8 );
+
+            input  += 8;
+            output += 8;
+            length -= 8;
+        }
+    }
+
+    return( 0 );
+}
+#endif /* MBEDTLS_CIPHER_MODE_CBC */
+
+#endif /* !MBEDTLS_DES_ALT */
+
+#if defined(MBEDTLS_SELF_TEST)
+/*
+ * DES and 3DES test vectors from:
+ *
+ * http://csrc.nist.gov/groups/STM/cavp/documents/des/tripledes-vectors.zip
+ */
+static const unsigned char des3_test_keys[24] =
+{
+    0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF,
+    0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0x01,
+    0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0x01, 0x23
+};
+
+static const unsigned char des3_test_buf[8] =
+{
+    0x4E, 0x6F, 0x77, 0x20, 0x69, 0x73, 0x20, 0x74
+};
+
+static const unsigned char des3_test_ecb_dec[3][8] =
+{
+    { 0xCD, 0xD6, 0x4F, 0x2F, 0x94, 0x27, 0xC1, 0x5D },
+    { 0x69, 0x96, 0xC8, 0xFA, 0x47, 0xA2, 0xAB, 0xEB },
+    { 0x83, 0x25, 0x39, 0x76, 0x44, 0x09, 0x1A, 0x0A }
+};
+
+static const unsigned char des3_test_ecb_enc[3][8] =
+{
+    { 0x6A, 0x2A, 0x19, 0xF4, 0x1E, 0xCA, 0x85, 0x4B },
+    { 0x03, 0xE6, 0x9F, 0x5B, 0xFA, 0x58, 0xEB, 0x42 },
+    { 0xDD, 0x17, 0xE8, 0xB8, 0xB4, 0x37, 0xD2, 0x32 }
+};
+
+#if defined(MBEDTLS_CIPHER_MODE_CBC)
+static const unsigned char des3_test_iv[8] =
+{
+    0x12, 0x34, 0x56, 0x78, 0x90, 0xAB, 0xCD, 0xEF,
+};
+
+static const unsigned char des3_test_cbc_dec[3][8] =
+{
+    { 0x12, 0x9F, 0x40, 0xB9, 0xD2, 0x00, 0x56, 0xB3 },
+    { 0x47, 0x0E, 0xFC, 0x9A, 0x6B, 0x8E, 0xE3, 0x93 },
+    { 0xC5, 0xCE, 0xCF, 0x63, 0xEC, 0xEC, 0x51, 0x4C }
+};
+
+static const unsigned char des3_test_cbc_enc[3][8] =
+{
+    { 0x54, 0xF1, 0x5A, 0xF6, 0xEB, 0xE3, 0xA4, 0xB4 },
+    { 0x35, 0x76, 0x11, 0x56, 0x5F, 0xA1, 0x8E, 0x4D },
+    { 0xCB, 0x19, 0x1F, 0x85, 0xD1, 0xED, 0x84, 0x39 }
+};
+#endif /* MBEDTLS_CIPHER_MODE_CBC */
+
+/*
+ * Checkup routine
+ */
+int mbedtls_des_self_test( int verbose )
+{
+    int i, j, u, v, ret = 0;
+    mbedtls_des_context ctx;
+    mbedtls_des3_context ctx3;
+    unsigned char buf[8];
+#if defined(MBEDTLS_CIPHER_MODE_CBC)
+    unsigned char prv[8];
+    unsigned char iv[8];
+#endif
+
+    mbedtls_des_init( &ctx );
+    mbedtls_des3_init( &ctx3 );
+    /*
+     * ECB mode
+     */
+    for( i = 0; i < 6; i++ )
+    {
+        u = i >> 1;
+        v = i  & 1;
+
+        if( verbose != 0 )
+            mbedtls_printf( "  DES%c-ECB-%3d (%s): ",
+                             ( u == 0 ) ? ' ' : '3', 56 + u * 56,
+                             ( v == MBEDTLS_DES_DECRYPT ) ? "dec" : "enc" );
+
+        memcpy( buf, des3_test_buf, 8 );
+
+        switch( i )
+        {
+        case 0:
+            mbedtls_des_setkey_dec( &ctx, des3_test_keys );
+            break;
+
+        case 1:
+            mbedtls_des_setkey_enc( &ctx, des3_test_keys );
+            break;
+
+        case 2:
+            mbedtls_des3_set2key_dec( &ctx3, des3_test_keys );
+            break;
+
+        case 3:
+            mbedtls_des3_set2key_enc( &ctx3, des3_test_keys );
+            break;
+
+        case 4:
+            mbedtls_des3_set3key_dec( &ctx3, des3_test_keys );
+            break;
+
+        case 5:
+            mbedtls_des3_set3key_enc( &ctx3, des3_test_keys );
+            break;
+
+        default:
+            return( 1 );
+        }
+
+        for( j = 0; j < 10000; j++ )
+        {
+            if( u == 0 )
+                mbedtls_des_crypt_ecb( &ctx, buf, buf );
+            else
+                mbedtls_des3_crypt_ecb( &ctx3, buf, buf );
+        }
+
+        if( ( v == MBEDTLS_DES_DECRYPT &&
+                memcmp( buf, des3_test_ecb_dec[u], 8 ) != 0 ) ||
+            ( v != MBEDTLS_DES_DECRYPT &&
+                memcmp( buf, des3_test_ecb_enc[u], 8 ) != 0 ) )
+        {
+            if( verbose != 0 )
+                mbedtls_printf( "failed\n" );
+
+            ret = 1;
+            goto exit;
+        }
+
+        if( verbose != 0 )
+            mbedtls_printf( "passed\n" );
+    }
+
+    if( verbose != 0 )
+        mbedtls_printf( "\n" );
+
+#if defined(MBEDTLS_CIPHER_MODE_CBC)
+    /*
+     * CBC mode
+     */
+    for( i = 0; i < 6; i++ )
+    {
+        u = i >> 1;
+        v = i  & 1;
+
+        if( verbose != 0 )
+            mbedtls_printf( "  DES%c-CBC-%3d (%s): ",
+                             ( u == 0 ) ? ' ' : '3', 56 + u * 56,
+                             ( v == MBEDTLS_DES_DECRYPT ) ? "dec" : "enc" );
+
+        memcpy( iv,  des3_test_iv,  8 );
+        memcpy( prv, des3_test_iv,  8 );
+        memcpy( buf, des3_test_buf, 8 );
+
+        switch( i )
+        {
+        case 0:
+            mbedtls_des_setkey_dec( &ctx, des3_test_keys );
+            break;
+
+        case 1:
+            mbedtls_des_setkey_enc( &ctx, des3_test_keys );
+            break;
+
+        case 2:
+            mbedtls_des3_set2key_dec( &ctx3, des3_test_keys );
+            break;
+
+        case 3:
+            mbedtls_des3_set2key_enc( &ctx3, des3_test_keys );
+            break;
+
+        case 4:
+            mbedtls_des3_set3key_dec( &ctx3, des3_test_keys );
+            break;
+
+        case 5:
+            mbedtls_des3_set3key_enc( &ctx3, des3_test_keys );
+            break;
+
+        default:
+            return( 1 );
+        }
+
+        if( v == MBEDTLS_DES_DECRYPT )
+        {
+            for( j = 0; j < 10000; j++ )
+            {
+                if( u == 0 )
+                    mbedtls_des_crypt_cbc( &ctx, v, 8, iv, buf, buf );
+                else
+                    mbedtls_des3_crypt_cbc( &ctx3, v, 8, iv, buf, buf );
+            }
+        }
+        else
+        {
+            for( j = 0; j < 10000; j++ )
+            {
+                unsigned char tmp[8];
+
+                if( u == 0 )
+                    mbedtls_des_crypt_cbc( &ctx, v, 8, iv, buf, buf );
+                else
+                    mbedtls_des3_crypt_cbc( &ctx3, v, 8, iv, buf, buf );
+
+                memcpy( tmp, prv, 8 );
+                memcpy( prv, buf, 8 );
+                memcpy( buf, tmp, 8 );
+            }
+
+            memcpy( buf, prv, 8 );
+        }
+
+        if( ( v == MBEDTLS_DES_DECRYPT &&
+                memcmp( buf, des3_test_cbc_dec[u], 8 ) != 0 ) ||
+            ( v != MBEDTLS_DES_DECRYPT &&
+                memcmp( buf, des3_test_cbc_enc[u], 8 ) != 0 ) )
+        {
+            if( verbose != 0 )
+                mbedtls_printf( "failed\n" );
+
+            ret = 1;
+            goto exit;
+        }
+
+        if( verbose != 0 )
+            mbedtls_printf( "passed\n" );
+    }
+#endif /* MBEDTLS_CIPHER_MODE_CBC */
+
+    if( verbose != 0 )
+        mbedtls_printf( "\n" );
+
+exit:
+    mbedtls_des_free( &ctx );
+    mbedtls_des3_free( &ctx3 );
+
+    return( ret );
+}
+
+#endif /* MBEDTLS_SELF_TEST */
+
+#endif /* MBEDTLS_DES_C */
\ No newline at end of file
diff --git a/drivers/net/ethernet/acts/des.h b/drivers/net/ethernet/acts/des.h
new file mode 100755
index 0000000..44d1133
--- /dev/null
+++ b/drivers/net/ethernet/acts/des.h
@@ -0,0 +1,307 @@
+/**
+ * \file des.h
+ *
+ * \brief DES block cipher
+ *
+ *  Copyright (C) 2006-2014, ARM Limited, All Rights Reserved
+ *
+ *  This file is part of mbed TLS (https://tls.mbed.org)
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifndef MBEDTLS_DES_H
+#define MBEDTLS_DES_H
+
+#if !defined(MBEDTLS_CONFIG_FILE)
+#include "config.h"
+#else
+#include MBEDTLS_CONFIG_FILE
+#endif
+
+#include <stddef.h>
+#include <linux/types.h>
+
+#define MBEDTLS_DES_ENCRYPT     1
+#define MBEDTLS_DES_DECRYPT     0
+
+#define MBEDTLS_ERR_DES_INVALID_INPUT_LENGTH              -0x0032  /**< The data input has an invalid length. */
+
+#define MBEDTLS_DES_KEY_SIZE    8
+
+#if !defined(MBEDTLS_DES_ALT)
+// Regular implementation
+//
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \brief          DES context structure
+ */
+typedef struct
+{
+    uint32_t sk[32];            /*!<  DES subkeys       */
+}
+mbedtls_des_context;
+
+/**
+ * \brief          Triple-DES context structure
+ */
+typedef struct
+{
+    uint32_t sk[96];            /*!<  3DES subkeys      */
+}
+mbedtls_des3_context;
+
+/**
+ * \brief          Initialize DES context
+ *
+ * \param ctx      DES context to be initialized
+ */
+void mbedtls_des_init( mbedtls_des_context *ctx );
+
+/**
+ * \brief          Clear DES context
+ *
+ * \param ctx      DES context to be cleared
+ */
+void mbedtls_des_free( mbedtls_des_context *ctx );
+
+/**
+ * \brief          Initialize Triple-DES context
+ *
+ * \param ctx      DES3 context to be initialized
+ */
+void mbedtls_des3_init( mbedtls_des3_context *ctx );
+
+/**
+ * \brief          Clear Triple-DES context
+ *
+ * \param ctx      DES3 context to be cleared
+ */
+void mbedtls_des3_free( mbedtls_des3_context *ctx );
+
+/**
+ * \brief          Set key parity on the given key to odd.
+ *
+ *                 DES keys are 56 bits long, but each byte is padded with
+ *                 a parity bit to allow verification.
+ *
+ * \param key      8-byte secret key
+ */
+void mbedtls_des_key_set_parity( unsigned char key[MBEDTLS_DES_KEY_SIZE] );
+
+/**
+ * \brief          Check that key parity on the given key is odd.
+ *
+ *                 DES keys are 56 bits long, but each byte is padded with
+ *                 a parity bit to allow verification.
+ *
+ * \param key      8-byte secret key
+ *
+ * \return         0 is parity was ok, 1 if parity was not correct.
+ */
+int mbedtls_des_key_check_key_parity( const unsigned char key[MBEDTLS_DES_KEY_SIZE] );
+
+/**
+ * \brief          Check that key is not a weak or semi-weak DES key
+ *
+ * \param key      8-byte secret key
+ *
+ * \return         0 if no weak key was found, 1 if a weak key was identified.
+ */
+int mbedtls_des_key_check_weak( const unsigned char key[MBEDTLS_DES_KEY_SIZE] );
+
+/**
+ * \brief          DES key schedule (56-bit, encryption)
+ *
+ * \param ctx      DES context to be initialized
+ * \param key      8-byte secret key
+ *
+ * \return         0
+ */
+int mbedtls_des_setkey_enc( mbedtls_des_context *ctx, const unsigned char key[MBEDTLS_DES_KEY_SIZE] );
+
+/**
+ * \brief          DES key schedule (56-bit, decryption)
+ *
+ * \param ctx      DES context to be initialized
+ * \param key      8-byte secret key
+ *
+ * \return         0
+ */
+int mbedtls_des_setkey_dec( mbedtls_des_context *ctx, const unsigned char key[MBEDTLS_DES_KEY_SIZE] );
+
+/**
+ * \brief          Triple-DES key schedule (112-bit, encryption)
+ *
+ * \param ctx      3DES context to be initialized
+ * \param key      16-byte secret key
+ *
+ * \return         0
+ */
+int mbedtls_des3_set2key_enc( mbedtls_des3_context *ctx,
+                      const unsigned char key[MBEDTLS_DES_KEY_SIZE * 2] );
+
+/**
+ * \brief          Triple-DES key schedule (112-bit, decryption)
+ *
+ * \param ctx      3DES context to be initialized
+ * \param key      16-byte secret key
+ *
+ * \return         0
+ */
+int mbedtls_des3_set2key_dec( mbedtls_des3_context *ctx,
+                      const unsigned char key[MBEDTLS_DES_KEY_SIZE * 2] );
+
+/**
+ * \brief          Triple-DES key schedule (168-bit, encryption)
+ *
+ * \param ctx      3DES context to be initialized
+ * \param key      24-byte secret key
+ *
+ * \return         0
+ */
+int mbedtls_des3_set3key_enc( mbedtls_des3_context *ctx,
+                      const unsigned char key[MBEDTLS_DES_KEY_SIZE * 3] );
+
+/**
+ * \brief          Triple-DES key schedule (168-bit, decryption)
+ *
+ * \param ctx      3DES context to be initialized
+ * \param key      24-byte secret key
+ *
+ * \return         0
+ */
+int mbedtls_des3_set3key_dec( mbedtls_des3_context *ctx,
+                      const unsigned char key[MBEDTLS_DES_KEY_SIZE * 3] );
+
+/**
+ * \brief          DES-ECB block encryption/decryption
+ *
+ * \param ctx      DES context
+ * \param input    64-bit input block
+ * \param output   64-bit output block
+ *
+ * \return         0 if successful
+ */
+int mbedtls_des_crypt_ecb( mbedtls_des_context *ctx,
+                    const unsigned char input[8],
+                    unsigned char output[8] );
+
+#if defined(MBEDTLS_CIPHER_MODE_CBC)
+/**
+ * \brief          DES-CBC buffer encryption/decryption
+ *
+ * \note           Upon exit, the content of the IV is updated so that you can
+ *                 call the function same function again on the following
+ *                 block(s) of data and get the same result as if it was
+ *                 encrypted in one call. This allows a "streaming" usage.
+ *                 If on the other hand you need to retain the contents of the
+ *                 IV, you should either save it manually or use the cipher
+ *                 module instead.
+ *
+ * \param ctx      DES context
+ * \param mode     MBEDTLS_DES_ENCRYPT or MBEDTLS_DES_DECRYPT
+ * \param length   length of the input data
+ * \param iv       initialization vector (updated after use)
+ * \param input    buffer holding the input data
+ * \param output   buffer holding the output data
+ */
+int mbedtls_des_crypt_cbc( mbedtls_des_context *ctx,
+                    int mode,
+                    size_t length,
+                    unsigned char iv[8],
+                    const unsigned char *input,
+                    unsigned char *output );
+#endif /* MBEDTLS_CIPHER_MODE_CBC */
+
+/**
+ * \brief          3DES-ECB block encryption/decryption
+ *
+ * \param ctx      3DES context
+ * \param input    64-bit input block
+ * \param output   64-bit output block
+ *
+ * \return         0 if successful
+ */
+int mbedtls_des3_crypt_ecb( mbedtls_des3_context *ctx,
+                     const unsigned char input[8],
+                     unsigned char output[8] );
+
+#if defined(MBEDTLS_CIPHER_MODE_CBC)
+/**
+ * \brief          3DES-CBC buffer encryption/decryption
+ *
+ * \note           Upon exit, the content of the IV is updated so that you can
+ *                 call the function same function again on the following
+ *                 block(s) of data and get the same result as if it was
+ *                 encrypted in one call. This allows a "streaming" usage.
+ *                 If on the other hand you need to retain the contents of the
+ *                 IV, you should either save it manually or use the cipher
+ *                 module instead.
+ *
+ * \param ctx      3DES context
+ * \param mode     MBEDTLS_DES_ENCRYPT or MBEDTLS_DES_DECRYPT
+ * \param length   length of the input data
+ * \param iv       initialization vector (updated after use)
+ * \param input    buffer holding the input data
+ * \param output   buffer holding the output data
+ *
+ * \return         0 if successful, or MBEDTLS_ERR_DES_INVALID_INPUT_LENGTH
+ */
+int mbedtls_des3_crypt_cbc( mbedtls_des3_context *ctx,
+                     int mode,
+                     size_t length,
+                     unsigned char iv[8],
+                     const unsigned char *input,
+                     unsigned char *output );
+#endif /* MBEDTLS_CIPHER_MODE_CBC */
+
+/**
+ * \brief          Internal function for key expansion.
+ *                 (Only exposed to allow overriding it,
+ *                 see MBEDTLS_DES_SETKEY_ALT)
+ *
+ * \param SK       Round keys
+ * \param key      Base key
+ */
+void mbedtls_des_setkey( uint32_t SK[32],
+                         const unsigned char key[MBEDTLS_DES_KEY_SIZE] );
+#ifdef __cplusplus
+}
+#endif
+
+#else  /* MBEDTLS_DES_ALT */
+#include "des_alt.h"
+#endif /* MBEDTLS_DES_ALT */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \brief          Checkup routine
+ *
+ * \return         0 if successful, or 1 if the test failed
+ */
+int mbedtls_des_self_test( int verbose );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* des.h */
\ No newline at end of file
diff --git a/drivers/net/ethernet/acts/ec_ethtool.c b/drivers/net/ethernet/acts/ec_ethtool.c
new file mode 100755
index 0000000..0559bd7
--- /dev/null
+++ b/drivers/net/ethernet/acts/ec_ethtool.c
@@ -0,0 +1,497 @@
+/*******************************************************************************
+ec_ethtool.c -- ethtool hooks for ethernet controller embedded in GL5201
+
+author : yunchf @Actions
+date : 2010-06-10
+version 0.1
+
+date : 2010-08-10
+version 1.0
+
+questions:
+1. set_pauseparam() hook should be modified later
+
+*******************************************************************************/
+
+#include "ethctrl.h"
+
+
+static const char *g_driver_name = "GL5201-eth-ctrl";
+static const char *g_driver_version = "Version - 0.1";
+
+#define ETH_STATS_LEN  (sizeof(struct net_device_stats) / sizeof(unsigned long))
+
+#define ETHTOOL_INFO_STR_LEN 32
+
+#define ECMD_SUPPORTED_MEDIA  \
+    (SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full | \
+    SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full)
+
+#define ECMD_ADVERTISED_MEDIA \
+    (ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full | \
+    ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Full)
+
+typedef enum {
+    EC_FC_NONE = 0,
+    EC_FC_TX_PAUSE,
+    EC_FC_RX_PAUSE,
+    EC_FC_FULL
+} ec_flowctrl_type_t;
+
+
+struct hw_regs_ranges {
+    int     start;
+    int     end;
+    int     interval;
+};
+
+
+/*------------------------------ ethtool hooks ------------------------------*/
+
+/**
+ * et_get_settings -- get transceiver's settings that are specified by @cmd
+ * @dev : target net device
+ * @cmd : requested command
+ * return 0 if success, otherwise fail
+ */
+static int et_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+    ec_priv_t *ecp = netdev_priv(dev);
+    struct mii_if_info *mii = &ecp->mii_info;
+    unsigned int advert;
+    unsigned int bmcr;
+
+
+    cmd->supported = (ECMD_SUPPORTED_MEDIA | SUPPORTED_Autoneg | SUPPORTED_TP | SUPPORTED_MII);
+
+    cmd->port = PORT_MII;       /* twisted-pair (TP) supported only */
+    cmd->transceiver = XCVR_INTERNAL;   /* internal transceiver supported only */
+    cmd->phy_address = mii->phy_id;
+    cmd->advertising = ADVERTISED_TP | ADVERTISED_MII;
+
+    /* get phy's supported advertise */
+    advert = mii->mdio_read(dev, mii->phy_id, MII_ADVERTISE);
+    if (advert & ADVERTISE_10HALF) {
+        cmd->advertising |= ADVERTISED_10baseT_Half;
+    }
+    if (advert & ADVERTISE_10FULL) {
+        cmd->advertising |= ADVERTISED_10baseT_Full;
+    }
+    if (advert & ADVERTISE_100HALF) {
+        cmd->advertising |= ADVERTISED_100baseT_Half;
+    }
+    if (advert & ADVERTISE_100FULL) {
+        cmd->advertising |= ADVERTISED_100baseT_Full;
+    }
+
+    /* get current speed, duplex and auto-negotiation mode */
+    bmcr = mii->mdio_read(dev, mii->phy_id, MII_BMCR);
+    if (bmcr & BMCR_ANENABLE) {
+        unsigned int lpa;
+        unsigned int neg;
+
+        cmd->autoneg = AUTONEG_ENABLE;
+        cmd->advertising |= ADVERTISED_Autoneg;
+
+        lpa = mii->mdio_read(dev, mii->phy_id, MII_LPA);
+        neg = mii_nway_result(advert & lpa);
+
+        if (neg == LPA_100FULL || neg == LPA_100HALF) {
+            cmd->speed = SPEED_100;
+        } else {
+            cmd->speed = SPEED_10;
+        }
+
+        if (neg == LPA_100FULL || neg == LPA_10FULL) {
+            cmd->duplex = DUPLEX_FULL;
+            mii->full_duplex = 1;       /* set-settings() does not set it if auto-neg */
+        } else {
+            cmd->duplex = DUPLEX_HALF;
+            mii->full_duplex = 0;
+        }
+    } else {
+        cmd->autoneg = AUTONEG_DISABLE;
+        cmd->speed = (bmcr & BMCR_SPEED100) ? SPEED_100 : SPEED_10;
+        cmd->duplex = (bmcr & BMCR_FULLDPLX) ? DUPLEX_FULL : DUPLEX_HALF;
+    }
+
+    /* ignore maxtxpkt, maxrxpkt for now */
+
+    return 0;
+
+}
+
+/**
+ * verify_et_cmd -- check the validity of requested command
+ * @mii : mii interface to setup 
+ * @cmd : requested command
+ * return 0 if requested command is valid, -EINVAL if not
+ */
+static inline int verify_et_cmd(const struct ethtool_cmd *cmd, const struct mii_if_info *mii)
+{
+    /* only support 10M and 100M currently */
+    if (SPEED_10 != cmd->speed && SPEED_100 != cmd->speed) {
+        return (-EINVAL);
+    }
+    if (DUPLEX_HALF != cmd->duplex && DUPLEX_FULL != cmd->duplex) {
+        return (-EINVAL);
+    }
+    if (PORT_MII != cmd->port) {
+        return (-EINVAL);
+    }
+    if (XCVR_INTERNAL != cmd->transceiver) {
+        return (-EINVAL);
+    }
+    if (cmd->phy_address != mii->phy_id) {
+        return (-EINVAL);
+    }
+    if (AUTONEG_DISABLE != cmd->autoneg && AUTONEG_ENABLE != cmd->autoneg) {
+        return (-EINVAL);
+    }
+    if (AUTONEG_ENABLE == cmd->autoneg) {
+        if (0 == (cmd->advertising & ECMD_ADVERTISED_MEDIA)) {
+            return (-EINVAL);
+        }
+    }
+
+    return (0);
+}
+
+
+/**
+ * set_autoneg_settings -- to setup @mii if the requested @cmd supports auto-negotiation 
+ */
+static void set_autoneg_settings(const struct ethtool_cmd *cmd, struct mii_if_info *mii)
+{
+    struct net_device *dev = mii->dev;
+    unsigned int bmcr;
+    unsigned int advert;
+    unsigned int tmp;
+
+
+    /* advertise only what has been requested */
+    advert = mii->mdio_read(dev, mii->phy_id, MII_ADVERTISE);
+    tmp = advert & ~(ADVERTISE_ALL | ADVERTISE_100BASE4);
+
+    if (cmd->advertising & ADVERTISED_10baseT_Half) {
+        tmp |= ADVERTISE_10HALF;
+    }
+    if (cmd->advertising & ADVERTISED_10baseT_Full) {
+        tmp |= ADVERTISE_10FULL;
+    }
+    if (cmd->advertising & ADVERTISED_100baseT_Half) {
+        tmp |= ADVERTISE_100HALF;
+    }
+    if (cmd->advertising & ADVERTISED_100baseT_Full) {
+        tmp |= ADVERTISE_100FULL;
+    }
+
+    if (advert != tmp) {
+        mii->mdio_write(dev, mii->phy_id, MII_ADVERTISE, tmp);
+        mii->advertising = tmp;
+    }
+
+    /* enable auto-negotiation, and force a re-negotiate */
+    bmcr = mii->mdio_read(dev, mii->phy_id, MII_BMCR);
+    bmcr |= (BMCR_ANENABLE | BMCR_ANRESTART);
+    mii->mdio_write(dev, mii->phy_id, MII_BMCR, bmcr);
+
+    mii->force_media = 0;
+
+    return;
+}
+
+
+/**
+ * set_forced_settings -- to setup @mii if the requested @cmd does not support auto-negotiation 
+ */
+static void set_forced_settings(const struct ethtool_cmd *cmd, struct mii_if_info *mii)
+{
+    struct net_device *dev = mii->dev;
+    unsigned int bmcr;
+    unsigned int new_bmcr;
+
+
+    /* disable auto-negotiation, set speed and duplexity */
+    bmcr = mii->mdio_read(dev, mii->phy_id, MII_BMCR);
+    new_bmcr = bmcr & ~(BMCR_ANENABLE | BMCR_SPEED100 | BMCR_FULLDPLX);
+
+    if (SPEED_100 == cmd->speed) {
+        new_bmcr |= BMCR_SPEED100;
+    }
+
+    if (DUPLEX_FULL == cmd->duplex) {
+        new_bmcr |= BMCR_FULLDPLX;
+        mii->full_duplex = 1;
+    } else {
+        mii->full_duplex = 0;
+    }
+
+    if (bmcr != new_bmcr) {
+
+        /* you can get a explanation from ec_netdev_ioctl() for SIOCSMIIREG command */
+        if (need_change_speed(new_bmcr, bmcr)) {
+            unsigned int changed = new_bmcr;
+
+            changed ^= BMCR_SPEED100;   /* exchange speed only */
+            mii->mdio_write(dev, mii->phy_id, MII_BMCR, changed);
+        }
+        mii->mdio_write(dev, mii->phy_id, MII_BMCR, new_bmcr);
+    }
+
+    mii->force_media = 1;
+
+    return;
+}
+
+
+/**
+ * et_set_settings -- setup transceiver of @dev net device according the requested @cmd
+ * @dev : net device to configure 
+ * @cmd : requested command
+ * return 0 if success, otherwise fail
+ */
+static int et_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+    ec_priv_t *ecp = netdev_priv(dev);
+    struct mii_if_info *mii = &ecp->mii_info;
+
+
+    if (verify_et_cmd(cmd, mii)) {
+        return (-EINVAL);
+    }
+
+    if (AUTONEG_ENABLE == cmd->autoneg) {
+        set_autoneg_settings(cmd, mii);
+    } else {
+        set_forced_settings(cmd, mii);
+    }
+
+    return (0);
+}
+
+
+/**
+ * et_get_drvinfo -- get driver's information of @dev net device
+ */
+static void et_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
+{
+    strncpy(info->driver, g_driver_name, ETHTOOL_INFO_STR_LEN);
+    strncpy(info->version, g_driver_version, ETHTOOL_INFO_STR_LEN);
+}
+
+
+
+
+/**
+ * et_get_regs_len -- get the number of registers of MAC
+ */
+static int et_get_regs_len(struct net_device *dev)
+{
+    int     len = 0;
+
+
+
+    return (len);
+}
+
+
+/**
+ * et_get_regs -- dump all register of MAC
+ */
+static void et_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *buf)
+{
+}
+
+static u32 et_get_msglevel(struct net_device *dev)
+{
+    ec_priv_t *ecp = netdev_priv(dev);
+    return (ecp->msg_enable);
+}
+
+
+static void et_set_msglevel(struct net_device *dev, u32 level)
+{
+    ec_priv_t *ecp = netdev_priv(dev);
+    ecp->msg_enable = level;
+}
+
+
+/**
+ * et_nway_reset -- re-negotiate the transceiver of @dev net device
+ * @dev : target net device
+ * return 0 if success, -EINVAL if fail
+ */
+static int et_nway_reset(struct net_device *dev)
+{
+    ec_priv_t *ecp = netdev_priv(dev);
+    struct mii_if_info *mii = &ecp->mii_info;
+    int     err = -EINVAL;
+    int     bmcr;
+
+    /* if autoneg is off, it's an error */
+    bmcr = mii->mdio_read(dev, mii->phy_id, MII_BMCR);
+
+    if (bmcr & BMCR_ANENABLE) {
+        bmcr |= BMCR_ANRESTART;
+        mii->mdio_write(dev, mii->phy_id, MII_BMCR, bmcr);
+        err = 0;
+    }
+
+    return (err);
+}
+
+
+static u32 et_get_link(struct net_device *dev)
+{
+	return (netif_carrier_ok(dev) ? 1 : 0);
+}
+
+static void et_get_pauseparam(struct net_device *dev, struct ethtool_pauseparam *epp)
+{
+    ec_priv_t *ecp = netdev_priv(dev);
+    volatile ethregs_t *regs = ecp->hwrp;
+
+    epp->autoneg = ecp->autoneg ? 1 : 0;
+    epp->tx_pause = regs->er_flowctrl & EC_FLOWCTRL_TPE ? 1 : 0;
+    epp->rx_pause = regs->er_flowctrl & EC_FLOWCTRL_RPE ? 1 : 0;
+}
+
+
+static inline int set_flowctrl_type(struct net_device *dev, ec_flowctrl_type_t fc)
+{
+    ec_priv_t *ecp = netdev_priv(dev);
+    volatile ethregs_t *hw_regs = ecp->hwrp;
+
+    // modify later,  relationship between different bits of flow control of csr20
+    switch (fc) {
+        case EC_FC_FULL:
+            hw_regs->er_flowctrl |= EC_FLOWCTRL_ENALL;
+            break;
+        case EC_FC_RX_PAUSE:
+            hw_regs->er_flowctrl &= ~EC_FLOWCTRL_ENALL;
+            hw_regs->er_flowctrl |= EC_FLOWCTRL_FCE | EC_FLOWCTRL_RPE;
+            break;
+        case EC_FC_TX_PAUSE:
+            hw_regs->er_flowctrl &= ~EC_FLOWCTRL_ENALL;
+            hw_regs->er_flowctrl |= EC_FLOWCTRL_TUE | EC_FLOWCTRL_TPE | EC_FLOWCTRL_FCE;
+            break;
+        case EC_FC_NONE:
+            hw_regs->er_flowctrl &= ~EC_FLOWCTRL_ENALL;
+            break;
+        default:
+            return (-1);
+    }
+    return (0);
+}
+
+
+/**
+ * et_set_pauseparam --  
+ */
+// XXXX NOTE :  modify later , in fact i dont know how to do it  currently
+static int et_set_pauseparam(struct net_device *dev, struct ethtool_pauseparam *epp)
+{
+    ec_priv_t *ecp = netdev_priv(dev);
+    ec_flowctrl_type_t type;
+    int     err = 0;
+
+    if (epp->autoneg) {
+
+        //set advertise to support pause
+        if (ecp->autoneg) {
+            if (netif_running(dev)) {
+                netif_carrier_off(dev); // stop rx and tx is better
+            }
+            ecp->phy_ops->phy_setup_advert(ecp, ADVERTISE_ALL | ADVERTISE_PAUSE_CAP);
+            ecp->phy_ops->phy_setup_aneg(ecp, true);    // can rise link change interrupt?
+            ecp->phy_ops->phy_read_status(ecp);
+        } else {
+            return (-1);
+        }
+    } else {
+        if (epp->rx_pause && epp->tx_pause) {
+            type = EC_FC_FULL;
+        } else if (epp->rx_pause && !epp->tx_pause) {
+            type = EC_FC_RX_PAUSE;
+        } else if (!epp->rx_pause && epp->tx_pause) {
+            type = EC_FC_TX_PAUSE;
+        } else {
+            type = EC_FC_NONE;
+        }
+        err = set_flowctrl_type(dev, type);
+    }
+    return (err);
+}
+
+
+struct stats_str {
+    char    string[ETH_GSTRING_LEN];
+};
+
+
+static struct stats_str g_stats_descs[ETH_STATS_LEN] = {
+    {"rx_packets"}, {"tx_packets"},
+    {"rx_bytes"}, {"tx_bytes"},
+    {"rx_errors"}, {"tx_errors"},
+    {"rx_dropped"}, {"tx_dropped"},
+    {"multicast"}, {"collisions"},
+    {"rx_length_errors"}, {"rx_over_errors"},
+    {"rx_crc_errors"}, {"rx_frame_errors"},
+    {"rx_fifo_errors"}, {"rx_missed_errors"},
+    {"tx_aborted_errors"}, {"tx_carrier_errors"},
+    {"tx_fifo_errors"}, {"tx_heartbeat_errors"},
+    {"tx_window_errors"}, {"rx_compressed"}, {"tx_compressed"}
+};
+
+
+static void et_get_strings(struct net_device *dev, u32 stringset, u8 * buf)
+{
+    if (ETH_SS_STATS == stringset) {
+        memcpy(buf, g_stats_descs, sizeof(g_stats_descs));
+    }
+}
+
+static void et_get_stats(struct net_device *dev, struct ethtool_stats *stats, u64 * data)
+{
+    int     len = ETH_STATS_LEN;
+    int     i;
+
+    for (i = 0; i < len; i++) {
+        data[i] = ((unsigned long *) &dev->stats)[i];;
+    }
+}
+
+static int et_get_sset_count(struct net_device *dev, int sset)
+{
+    switch (sset) {
+        case ETH_SS_STATS:
+            return ETH_STATS_LEN;
+        default:
+            return -EOPNOTSUPP;
+    }
+}
+
+
+static struct ethtool_ops ec_ethtool_ops = {
+	.get_settings = et_get_settings,
+	.set_settings = et_set_settings,
+	.get_drvinfo = et_get_drvinfo,
+	.get_regs_len = et_get_regs_len,
+	.get_regs = et_get_regs,
+	.get_msglevel = et_get_msglevel,
+	.set_msglevel = et_set_msglevel,
+	.nway_reset = et_nway_reset,
+	.get_link = et_get_link,
+	.get_pauseparam = et_get_pauseparam,
+	.set_pauseparam = et_set_pauseparam,
+	.get_strings = et_get_strings,
+	.get_ethtool_stats = et_get_stats,
+	.get_sset_count = et_get_sset_count
+};
+
+
+void ec_set_ethtool_ops(struct net_device *dev)
+{
+	dev->ethtool_ops = &ec_ethtool_ops;
+}
diff --git a/drivers/net/ethernet/acts/ec_hardware.h b/drivers/net/ethernet/acts/ec_hardware.h
new file mode 100755
index 0000000..c8ea525
--- /dev/null
+++ b/drivers/net/ethernet/acts/ec_hardware.h
@@ -0,0 +1,416 @@
+/******************************************************************************
+ec_hardware.h -- data structure and macros  about hardware architecture and 
+    registers of MAC and PHY
+
+author : yunchf @Actions
+date : 2010-04-08
+version 0.1
+
+data : 2010-08-10
+version 1.0
+
+******************************************************************************/
+
+#ifndef _EC_HARDWARE_H_
+#define _EC_HARDWARE_H_
+/*****************************************************************************/
+#include <mach/hardware.h>
+
+#undef getl
+#undef putl
+#define getl(a)    act_readl(a)
+#define putl(v, a) act_writel(v, a)
+
+#define ASOC_ETHERNET_PHY_ADDR (0x3)
+#define ASOC_ETHERNET_PHY_IRQ  OWL_IRQ_SIRQ0
+
+/*
+ * Should not read and write er_reserved* elements
+ */
+typedef struct ethregs {
+    unsigned long er_busmode;   /* offset 0x0; bus mode reg. */
+    unsigned long er_reserved0;
+    unsigned long er_txpoll;    /* 0x08; transmit poll demand reg. */
+    unsigned long er_reserved1;
+    unsigned long er_rxpoll;    /* 0x10; receive poll demand reg. */
+    unsigned long er_reserved2;
+    unsigned long er_rxbdbase;  /* 0x18; receive descriptor list base address reg. */
+    unsigned long er_reserved3;
+    unsigned long er_txbdbase;  /* 0x20; transmit descriptor list base address reg. */
+    unsigned long er_reserved4;
+    unsigned long er_status;    /* 0x28; status reg. */
+    unsigned long er_reserved5;
+    unsigned long er_opmode;    /* 0x30; operation mode reg. */
+    unsigned long er_reserved6;
+    unsigned long er_ienable;   /* 0x38; interrupt enable reg. */
+    unsigned long er_reserved7;
+    unsigned long er_mfocnt;    /* 0x40; missed frames and overflow counter reg. */
+    unsigned long er_reserved8;
+    unsigned long er_miimng;    /* 0x48; software mii, don't use it here  */
+    unsigned long er_reserved9;
+    unsigned long er_miism;     /* 0x50; mii serial management */
+    unsigned long er_reserved10;
+    unsigned long er_imctrl;    /* 0x58; general-purpose timer and interrupt mitigation control */
+    unsigned long er_reserved11[9];
+    unsigned long er_maclow;    /* 0x80; mac address low */
+    unsigned long er_reserved12;
+    unsigned long er_machigh;   /* 0x88; mac address high */
+    unsigned long er_reserved13;
+    unsigned long er_cachethr;  /* 0x90; pause time and cache thresholds */
+    unsigned long er_reserved14;
+    unsigned long er_fifothr;   /* 0x98; pause control fifo thresholds */
+    unsigned long er_reserved15;
+    unsigned long er_flowctrl;  /* 0xa0; flow control setup and status */
+    unsigned long er_reserved16[3];
+    unsigned long er_macctrl;   /* 0xb0; mac control */
+    unsigned long er_reserved17[83];
+
+    unsigned long er_rxstats[31];       /* 0x200~0x278; receive statistics regs. */
+    unsigned long er_reserved18[33];
+    unsigned long er_txstats[41];       /* 0x300~0x3A0; transmit statistics regs. */
+    unsigned long er_reserved19[23];
+} ethregs_t;
+
+/*
+ * statistical counter of transmission and reception
+ * NOTE : NOT using these registers in fact
+ */
+#define er_tx64         er_txstats[0]   /* offset:0x200 */
+#define er_tx65to127    er_txstats[2]
+#define er_tx128to255   er_txstats[4]
+#define er_tx256to511   er_txstats[6]
+#define er_tx512to1023  er_txstats[8]
+#define er_tx1024to1518 er_txstats[10]
+#define er_txtoolong    er_txstats[12]
+#define er_txoctok      er_txstats[14]
+#define er_txuniok      er_txstats[16]
+#define er_txmultiok    er_txstats[18]
+#define er_txbroadok    er_txstats[20]
+#define er_txpauseok    er_txstats[22]
+#define er_txcoll0      er_txstats[24]
+#define er_txcoll1      er_txstats[26]
+#define er_txcollmulti  er_txstats[28]
+#define er_txcoll16     er_txstats[30]
+#define er_txdefer      er_txstats[32]
+#define er_txlcerr      er_txstats[34]
+#define er_txmacerr     er_txstats[36]
+#define er_txtxcserr    er_txstats[38]  /* offset:0x298 */
+
+#define er_rx64         er_rxstats[0]   /* offset:0x300 */
+#define er_rx65to127    er_rxstats[2]
+#define er_rx128to255   er_rxstats[4]
+#define er_rx256to511   er_rxstats[6]
+#define er_rx512to1023  er_rxstats[8]
+#define er_rx1024to1518 er_rxstats[10]
+#define er_rxtoolong    er_rxstats[12]
+#define er_rxoctok      er_rxstats[14]
+#define er_rxuniok      er_rxstats[16]
+#define er_rxmultiok    er_rxstats[18]
+#define er_rxbroadok    er_rxstats[20]
+#define er_rxpauseok    er_rxstats[22]
+#define er_rxalignerr   er_rxstats[24]
+#define er_rxfcserr     er_rxstats[26]
+#define er_rxrxmiierr   er_rxstats[28]  /* offset:0x370 */
+
+/*
+ * receive and transmit buffer descriptor
+ */
+typedef struct buffer_descriptor {
+    unsigned long status;
+    unsigned long control;
+    unsigned long buf_addr;
+    unsigned long reserved;     /* we don't use second buffer address */
+} ec_bd_t;
+
+
+/*
+ * ethernet clock enable
+ */
+#define ASOC_ETH_CLOCK_EN  (0x1 << 22)
+#define ASOC_ETH_CLOCK_RST (0x1 << 20)
+
+
+/*
+ * rx bd status and control information
+ */
+#define RXBD_STAT_OWN (0x1 << 31)
+#define RXBD_STAT_FF  (0x1 << 30)       /*filtering fail */
+#define RXBD_STAT_FL(x) (((x) >> 16) & 0x3FFF)  /* frame leng */
+#define RXBD_STAT_ES  (0x1 << 15)       /* error summary */
+#define RXBD_STAT_DE  (0x1 << 14)       /* descriptor error */
+#define RXBD_STAT_RF  (0x1 << 11)       /* runt frame */
+#define RXBD_STAT_MF  (0x1 << 10)       /* multicast frame */
+#define RXBD_STAT_FS  (0x1 << 9)        /* first descriptor */
+#define RXBD_STAT_LS  (0x1 << 8)        /* last descriptor */
+#define RXBD_STAT_TL  (0x1 << 7)        /* frame too long */
+#define RXBD_STAT_CS  (0x1 << 6)        /* collision */
+#define RXBD_STAT_FT  (0x1 << 5)        /* frame type */
+#define RXBD_STAT_RE  (0x1 << 3)        /* mii error */
+#define RXBD_STAT_DB  (0x1 << 2)        /* byte not aligned */
+#define RXBD_STAT_CE  (0x1 << 1)        /* crc error */
+#define RXBD_STAT_ZERO  (0x1)
+
+#define RXBD_CTRL_RER (0x1 << 25)       /* receive end of ring */
+#define RXBD_CTRL_RCH (0x1 << 24)       /* using second buffer, not used here */
+#define RXBD_CTRL_RBS1(x) ((x) & 0x7FF) /* buffer1 size */
+
+/*
+ * tx bd status and control information
+ */
+#define TXBD_STAT_OWN (0x1 << 31)
+#define TXBD_STAT_ES  (0x1 << 15)       /* error summary */
+#define TXBD_STAT_LO  (0x1 << 11)       /* loss of carrier */
+#define TXBD_STAT_NC  (0x1 << 10)       /* no carrier */
+#define TXBD_STAT_LC  (0x1 << 9)        /* late collision */
+#define TXBD_STAT_EC  (0x1 << 8)        /* excessive collision */
+#define TXBD_STAT_CC(x)  (((x) >> 3) & 0xF)     /*  */
+#define TXBD_STAT_UF  (0x1 << 1)        /* underflow error */
+#define TXBD_STAT_DE  (0x1)     /* deferred */
+
+#define TXBD_CTRL_IC   (0x1 << 31)      /* interrupt on completion */
+#define TXBD_CTRL_LS   (0x1 << 30)      /* last descriptor */
+#define TXBD_CTRL_FS   (0x1 << 29)      /* first descriptor */
+#define TXBD_CTRL_FT1  (0x1 << 28)      /* filtering type  */
+#define TXBD_CTRL_SET  (0x1 << 27)      /* setup packet */
+#define TXBD_CTRL_AC   (0x1 << 26)      /* add crc disable */
+#define TXBD_CTRL_TER  (0x1 << 25)      /* transmit end of ring */
+#define TXBD_CTRL_TCH  (0x1 << 24)      /* second address chainded */
+#define TXBD_CTRL_DPD  (0x1 << 23)      /* disabled padding */
+#define TXBD_CTRL_FT0  (0x1 << 22)      /* filtering type, togethor with 28bit */
+#define TXBD_CTRL_TBS2(x)  (((x) & 0x7FF) << 11)        /* buf2 size, no use here */
+#define TXBD_CTRL_TBS1(x)  ((x) & 0x7FF)        /* buf1 size */
+#define TXBD_CTRL_TBS1M (0x7FF)
+
+/*
+ * bus mode register
+ */
+#define EC_BMODE_DBO    (0x1 << 20)     /*descriptor byte ordering mode */
+#define EC_BMODE_TAP(x) (((x) & 0x7) << 17)     /*transmit auto-polling */
+#define EC_BMODE_PBL(x) (((x) & 0x3F) << 8)     /*programmable burst length */
+#define EC_BMODE_BLE    (0x1 << 7)      /*big or little endian for data buffers */
+#define EC_BMODE_DSL(x) (((x) & 0x1F) << 2)     /*descriptors skip length */
+#define EC_BMODE_BAR    (0x1 << 1)      /*bus arbitration mode */
+#define EC_BMODE_SWR    (0x1)   /*software reset */
+
+/*
+ * transmit and receive poll demand register
+ */
+#define EC_TXPOLL_ST  (0x1)     /* leave suspended mode to running mode to start xmit */
+#define EC_RXPOLL_SR  (0x1)     /* leave suspended to running mode */
+
+/*
+ * status register 
+ */
+#define EC_STATUS_TSM  (0x7 << 20)      /*transmit process state */
+#define EC_TX_run_dsp  (0x3 << 20)
+#define EC_STATUS_RSM  (0x7 << 17)      /*receive process state */
+#define EC_RX_fetch_dsp (0x1 <<17)
+#define EC_RX_close_dsp (0x5 <<17)
+#define EC_RX_run_dsp 	(0x7 <<17)
+#define EC_STATUS_NIS  (0x1 << 16)      /*normal interrupt summary */
+#define EC_STATUS_AIS  (0x1 << 15)      /*abnormal interrupt summary */
+#define EC_STATUS_ERI  (0x1 << 14)      /*early receive interrupt */
+#define EC_STATUS_GTE  (0x1 << 11)      /*general-purpose timer expiration */
+#define EC_STATUS_ETI  (0x1 << 10)      /*early transmit interrupt */
+#define EC_STATUS_RPS  (0x1 << 8)       /*receive process stopped */
+#define EC_STATUS_RU   (0x1 << 7)       /*receive buffer unavailable */
+#define EC_STATUS_RI   (0x1 << 6)       /*receive interrupt */
+#define EC_STATUS_UNF  (0x1 << 5)       /*transmit underflow */
+#define EC_STATUS_LCIS (0x1 << 4)       /* link change status */
+#define EC_STATUS_LCIQ (0x1 << 3)       /* link change interrupt */
+#define EC_STATUS_TU   (0x1 << 2)       /*transmit buffer unavailable */
+#define EC_STATUS_TPS  (0x1 << 1)       /*transmit process stopped */
+#define EC_STATUS_TI   (0x1)    /*transmit interrupt */
+
+/*
+ * operation mode register
+ */
+#define EC_OPMODE_RA  (0x1 << 30)       /*receive all */
+#define EC_OPMODE_TTM (0x1 << 22)       /*transmit threshold mode */
+#define EC_OPMODE_SF  (0x1 << 21)       /*store and forward */
+#define EC_OPMODE_SPEED(x) (((x) & 0x3) << 16)  /*eth speed selection */
+#define EC_OPMODE_10M (0x1 << 17)       /* set when work on 10M, otherwise 100M */
+#define EC_OPMODE_TR(x)    (((x) & 0x3) << 14)  /*threshold control bits */
+#define EC_OPMODE_ST  (0x1 << 13)       /*start or stop transmit command */
+#define EC_OPMODE_LP  (0x1 << 10)       /*loopback mode */
+#define EC_OPMODE_FD  (0x1 << 9)        /*full duplex mode */
+#define EC_OPMODE_PM  (0x1 << 7)        /*pass all multicast */
+#define EC_OPMODE_PR  (0x1 << 6)        /*prmiscuous mode */
+#define EC_OPMODE_IF  (0x1 << 4)        /*inverse filtering */
+#define EC_OPMODE_PB  (0x1 << 3)        /*pass bad frames */
+#define EC_OPMODE_HO  (0x1 << 2)        /*hash only filtering mode */
+#define EC_OPMODE_SR  (0x1 << 1)        /*start or stop receive command */
+#define EC_OPMODE_HP  (0x1)     /*hash or perfect receive filtering mode */
+
+/*
+ * interrupt enable register
+ */
+#define EC_IEN_LCIE (0x1 << 17) /*link change interrupt enable */
+#define EC_IEN_NIE (0x1 << 16)  /*normal interrupt summary enable */
+#define EC_IEN_AIE (0x1 << 15)  /*abnormal interrupt summary enable */
+#define EC_IEN_ERE (0x1 << 14)  /*early receive interrupt enable */
+#define EC_IEN_GTE (0x1 << 11)  /*general-purpose timer overflow */
+#define EC_IEN_ETE (0x1 << 10)  /*early transmit interrupt enable */
+#define EC_IEN_RSE (0x1 << 8)   /*receive stopped enable */
+#define EC_IEN_RUE (0x1 << 7)   /*receive buffer unavailable enable */
+#define EC_IEN_RIE (0x1 << 6)   /*receive interrupt enable */
+#define EC_IEN_UNE (0x1 << 5)   /*underflow interrupt enable */
+#define EC_IEN_TUE (0x1 << 2)   /*transmit buffer unavailable enable */
+#define EC_IEN_TSE (0x1 << 1)   /*transmit stopped enable */
+#define EC_IEN_TIE (0x1)        /*transmit interrupt enable */
+//#define EC_IEN_ALL (0x3CDE7)
+#define EC_IEN_ALL (0x1CDE3)    /* TU interrupt disabled */
+
+/*
+ * missed frames and overflow counter register
+ */
+#define EC_MFOCNT_OCO  (0x1 << 28)      /*overflow flag */
+#define EC_MFOCNT_FOCM (0x3FF << 17)    /*fifo overflow counter */
+#define EC_MFOCNT_MFO  (0x1 << 16)      /*missed frame flag */
+#define EC_MFOCNT_MFCM (0xFFFF) /*missed frame counter */
+
+/*
+ * the mii serial management register
+ */
+#define MII_MNG_SB  (0x1 << 31) /*start transfer or busy */
+#define MII_MNG_CLKDIV(x) (((x) & 0x7) << 28)   /*clock divider */
+#define MII_MNG_OPCODE(x) (((x) & 0x3) << 26)   /*operation mode */
+#define MII_MNG_PHYADD(x) (((x) & 0x1F) << 21)  /*physical layer address */
+#define MII_MNG_REGADD(x) (((x) & 0x1F) << 16)  /*register address */
+#define MII_MNG_DATAM (0xFFFF)  /*register data mask */
+#define MII_MNG_DATA(x)   ((MII_MNG_DATAM) & (x))       /* data to write */
+#define MII_OP_WRITE 0x1
+#define MII_OP_READ  0x2
+#define MII_OP_CDS   0x3
+
+/*
+ * general purpose timer and interrupt mitigation control register
+ */
+#define EC_IMCTRL_CS     (0x1 << 31)    /*cycle size */
+#define EC_IMCTRL_TT(x)  (((x) & 0xF) << 27)    /*transmit timer */
+#define EC_IMCTRL_NTP(x) (((x) & 0x7) << 24)    /*number of transmit packets */
+#define EC_IMCTRL_RT(x)  (((x) & 0xF) << 20)    /*receive timer */
+#define EC_IMCTRL_NRP(x) (((x) & 0x7) << 17)    /*number of receive packets */
+#define EC_IMCTRL_CON    (0x1 << 16)    /*continuous mode */
+#define EC_IMCTRL_TIMM   (0xFFFF)       /*timer value */
+#define EC_IMCTRL_TIM(x) ((x) & 0xFFFF) /*timer value */
+
+/*
+ * pause time and cache thresholds register
+ */
+#define EC_CACHETHR_CPTL(x) (((x) & 0xFF) << 24)        /*cache pause threshold level */
+#define EC_CACHETHR_CRTL(x) (((x) & 0xFF) << 16)        /*cache restart threshold level */
+#define EC_CACHETHR_PQT(x)  ((x) & 0xFFFF)      /*flow control pause quanta time */
+
+/*
+ * fifo thresholds register
+ */
+#define EC_FIFOTHR_FPTL(x) (((x) & 0xFFFF) << 16)       /*fifo pause threshold level */
+#define EC_FIFOTHR_FRTL(x) ((x) & 0xFFFF)       /*fifo restart threshold level */
+
+/*
+ * flow control setup and status
+ */
+#define EC_FLOWCTRL_FCE (0x1 << 31)     /*flow control enable */
+#define EC_FLOWCTRL_TUE (0x1 << 30)     /*transmit un-pause frames enable */
+#define EC_FLOWCTRL_TPE (0x1 << 29)     /*transmit pause frames enable */
+#define EC_FLOWCTRL_RPE (0x1 << 28)     /*receive pause frames enable */
+#define EC_FLOWCTRL_BPE (0x1 << 27)     /*back pressure enable (only half-dup) */
+#define EC_FLOWCTRL_ENALL (0x1F << 27)
+#define EC_FLOWCTRL_PRS (0x1 << 1)      /*pause request sent */
+#define EC_FLOWCTRL_HTP (0x1)   /*host transmission paused */
+
+/*
+ * mac control register
+ */
+#define EC_MACCTRL_RRSB (0x1 << 8)      /*RMII_REFCLK select bit */
+#define EC_MACCTRL_SSDC(x) (((x) & 0xF) << 4) /*SMII SYNC delay half cycle */
+#define EC_MACCTRL_RCPS (0x1 << 1)      /*REF_CLK phase select */
+#define EC_MACCTRL_RSIS (0x1 << 0)      /*RMII or SMII interface select bit */
+
+#define MAC_CTRL_SMII (0x41) /* use smii; bit8: 0 REFCLK output, 1 input*/
+#define MAC_CTRL_RMII (0x0)  /* use rmii */
+
+
+/*
+ * phy control register
+ */
+#define EC_PHYCTRL_PDMC(x) (((x) & 0x3) << 16)  /*power down mode control */
+#define EC_PHYCTRL_LOOP    (0x1 << 12)  /*loopback mode */
+#define EC_PHYCTRL_MHZ(x)  (((x) & 0x3) << 4)   /* (x+1) times of 25MHZ */
+
+/*
+ * phy status register
+ */
+#define EC_PHYSTATUS_LINKED (0x1)       /*link status */
+
+/*
+ * phy reset control signals
+ */
+#define EC_PHYRESET_RST  (0x1)  /*low active reset signal */
+
+/*
+ * fxedp110hc0a - FARADAY Inc. PHY registers address
+ * prefer to using macros in mii.h
+ */
+#define PHY_REG_FTC1 0x10
+#define PHY_REG_FTC2 0x18
+
+#define PHY_FTC_PRL  (0x1 << 12)        /* support full parallel detection function */
+#define PHY_FTC_CMPT (0x3 << 2) /* prevent compatibility issues */
+
+
+/*
+ * phy KSZ8041TF
+ */
+#define MII_ICSR 0x19 /* interrupt control & status register */
+
+#define ICSR_LINKUP_EN   (0x1 << 13)
+#define ICSR_LINKDOWN_EN (0x1 << 12)
+#define ICSR_LINKDOWN_EN_2 (0x1 << 11)
+
+#define ICSR_LINKUP   (0x1 << 0)
+#define ICSR_LINKDOWN (0x1 << 2)
+
+
+#define MII_PHY_CTL2 0x1f
+#define PHY_CTL2_INT_LEVEL (0x1 << 9) /* interrupt pin active high:1, low:0 */
+
+
+/*
+ * phy RTL8201F
+ */
+#define PHY_RTL8201F_REG_RMSR           0x10
+#define PHY_RTL8201F_REG_INT_LED_FUNC   0x13
+#define PHY_RTL8201F_REG_PAGE_SELECT    0x1F
+#define PHY_RTL8201F_REG_INT_SNR        0x1E
+
+/* PHY_RTL8201F_PAGE_SELECT */
+#define PHY_RTL8201F_REG_PAGE_SELECT_SEVEN    0x7
+#define PHY_RTL8201F_REG_PAGE_SELECT_ZERO     0x0
+
+#define PHY_RTL8201F_LINK_STATUS_CHANGE     (0x1<<11)
+#define PHY_RTL8201F_RMSR_CLK_DIR_INPUT	    (0x1<<12)
+#define PHY_RTL8201F_RMSR_RMII_MODE	        (0x1<<3)
+#define PHY_RTL8201F_RMSR_RMII_RX_OFFSET    (0xF<<4)
+#define PHY_RTL8201F_RMSR_RMII_TX_OFFSET    (0xF<<8)
+#define PHY_RTL8201F_PIN_LINK_STATE_CHANGE  (0x1<<13)
+
+/*
+ * phy SR8201G
+ */
+#define PHY_SR8201G_REG_RMSR           0xC
+#define PHY_SR8201G_REG_INT_LED_FUNC   0xE
+#define PHY_SR8201G_REG_PAGE_SELECT    0xF
+#define PHY_SR8201G_REG_EXPAND         0x18
+
+/* PHY_SR8201G_PAGE_SELECT */
+#define PHY_SR8201G_REG_PAGE_SELECT_SEVEN    0x7
+#define PHY_SR8201G_REG_PAGE_SELECT_ZERO     0x0
+
+#define PHY_SR8201G_INT_PIN_SELECT             (0x1<<10)
+#define PHY_SR8201G_INT_PIN_LINK_STATE_CHANGE  (0x1<<11)
+#define PHY_SR8201G_CLK_DIR_INPUT	           (0x1<<12)
+/******************************************************************************/
+
+#endif                          /* _EC_HARDWARE_H_ */
diff --git a/drivers/net/ethernet/acts/ec_phy.c b/drivers/net/ethernet/acts/ec_phy.c
new file mode 100755
index 0000000..14004a2
--- /dev/null
+++ b/drivers/net/ethernet/acts/ec_phy.c
@@ -0,0 +1,863 @@
+/******************************************************************************
+ec_phy.c -- phy driver for fxedp110c0a  of FARADAY Inc.
+
+author : yunchf @Actions
+date : 2010-04-12
+version 0.1
+
+date : 2010-08-10
+version 1.0
+
+******************************************************************************/
+
+#include <linux/delay.h>
+#include "ethctrl.h"
+
+/*
+ * read and write phy register normally need not to wait for. sometimes about 7us
+ * but auto-negotiation may wait for a long time, about 140ms, and less than 2s
+ */
+#define MII_TIME_OUT 100
+#define PHY_AUTONEG_TIME_OUT 50
+
+extern int suspend_flag;
+
+unsigned short (*read_phy_reg)(ec_priv_t *, unsigned short) = NULL;
+int (*write_phy_reg)(ec_priv_t *, unsigned short, unsigned short) = NULL;
+
+#if 0
+/*------------------------------- phy driver hooks -----------------------------*/
+
+/**
+ * read_phy_reg - MII interface  to read  @reg_addr register of phy at @phy_addr
+ * return positive and zero value if success, or negative value if fail
+ */
+ //read PHY internal register by SPI
+//register address,return the register data
+unsigned short read_phy_reg_atc2605(ec_priv_t * ecp, unsigned short reg_addr)
+{
+	unsigned short temp;
+	struct atc260x_dev *atc260x = ecp->atc260x;
+
+	do {
+		temp = atc260x_reg_read(atc260x, atc2603_PHY_SMI_STAT);
+	}while(temp & 0x1); 	//waite for the SMI bus process completion
+
+	temp = 0x8100 | reg_addr;		//smi write operate,address
+	atc260x_reg_write(atc260x, atc2603_PHY_SMI_CONFIG, temp);
+	do {
+		temp = atc260x_reg_read(atc260x, atc2603_PHY_SMI_STAT);
+	}while(temp & 0x1); 	//waite for the SMI bus process completion
+
+	temp = atc260x_reg_read(atc260x, atc2603_PHY_SMI_DATA);
+	temp = temp & 0xffff;
+	return (temp);
+}
+
+/**
+ * write_phy_reg - MII interface  to write  @val to @reg_addr register of phy at @phy_addr
+ * return zero if success, negative value if fail
+ */
+ //write PHY internal register by SPI
+//register address,write data
+int write_phy_reg_atc2605(ec_priv_t * ecp, unsigned short reg_addr, unsigned short val)
+{
+    unsigned short temp;
+    struct atc260x_dev *atc260x = ecp->atc260x;
+
+	do {
+		temp = atc260x_reg_read(atc260x, atc2603_PHY_SMI_STAT);
+	}while(temp & 0x1); 	//waite for the SMI bus process completion
+
+	atc260x_reg_write(atc260x, atc2603_PHY_SMI_DATA, val);
+	temp = 0xc100 | reg_addr;		//smi write operate,address
+	atc260x_reg_write(atc260x, atc2603_PHY_SMI_CONFIG, temp);
+
+	return 0;
+}
+
+static int atc2605_hw_init(ec_priv_t *ecp)
+{
+	unsigned short atc260x_temp;
+	struct atc260x_dev *atc260x = ecp->atc260x;
+
+	/*ethernet mfp0 RMII 1st*/
+	//hw_rmii_get_pin();
+	//mac_rmii_get_pin();
+	/************************phy init*****************************/
+	/*enable phy clock*/
+	atc260x_reg_setbits(atc260x, atc2603_CMU_DEVRST, 0x200, 0x200);
+	udelay(100);
+
+	/*ethernet wrapper rest*/
+	atc260x_reg_setbits(atc260x, atc2603_CMU_DEVRST, 0x08, 0x0);
+	udelay(100);
+	atc260x_reg_setbits(atc260x, atc2603_CMU_DEVRST, 0x08, 0x08);
+	udelay(100);
+
+	/*GL5302 PHY avoid reboot bug, reset PLL*/
+	atc260x_reg_setbits(atc260x, atc2603_PHY_PLL_CTL0, 0x03, 0x02); //25Mhz
+	mdelay(5);
+	atc260x_reg_setbits(atc260x, atc2603_PHY_PLL_CTL1, 0x200, 0x200);//bit9=1,enetpll ALV LDO enable
+	mdelay(200);
+
+	atc260x_reg_setbits(atc260x, atc2603_PHY_PLL_CTL0, 0x03, 0x01); //bit0=1,bit1=0,ethernet pll enable ,24Mhz
+	mdelay(1);
+	/* 5203 PAD_CLKO_25M output 25MHz clock to 2605 */
+	atc260x_reg_setbits(atc260x, atc2603_PHY_PLL_CTL0, 0x03, 0x03); //25Mhz
+	mdelay(5);
+
+	atc260x_reg_write(atc260x, atc2603_PHY_CONFIG, 0x00);	    //auto, phy power on
+	atc260x_reg_write(atc260x, atc2603_PHY_ADDR, 0x01);		    //set phy address=  0x01
+	atc260x_reg_write(atc260x, atc2603_PHY_CTRL, 0x01);	        //rmii,100Mbps
+
+	//add  modify
+	atc260x_reg_write(atc260x, atc2603_PHY_HW_RST, 0x01);	    //reset the phy
+	udelay(100);
+	do
+	{
+		atc260x_temp = atc260x_reg_read(atc260x, atc2603_PHY_HW_RST);
+	}while(atc260x_temp & 0x1); //waite for reset process completion
+
+	/*enable RMII_REF_CLK and EXTIRQ pad and disable the other 6 RMII pad, gl5302 bug amend*/
+	atc260x_reg_setbits(atc260x, atc2603_PAD_EN, 0xff, 0x81);
+	udelay(100);
+
+	//pad_drv level 3 for fpga test
+	atc260x_reg_setbits(atc260x, atc2603_PAD_DRV1, 0xfff, 0x145);
+	//atc260x_reg_setbits(atc260x, atc2603_PAD_DRV1, 0xfff, 0x28a); //level 4
+	printk("5302 PAD_EN: 0x%x\n", (uint)atc260x_reg_read(atc260x, atc2603_PAD_EN));
+	printk("5302 PAD_DRV1: 0x%x\n", (uint)atc260x_reg_read(atc260x, atc2603_PAD_DRV1));
+
+	atc260x_reg_setbits(atc260x, atc2603_PHY_INT_CTRL, 0xf, 0xf);   //enable phy int control
+
+	/*clear phy INT_STAT*/
+	atc260x_reg_write(ecp->atc260x, atc2603_PHY_INT_STAT, 0xff);
+	//printk("1f.atc2603_PHY_INT_STAT:0x%x\n", atc260x_reg_read(atc260x, gl5302_PHY_INT_STAT));
+	udelay(100);
+
+	printk("5302 MFP_CTL0: 0x%x\n", (uint)atc260x_reg_read(atc260x, atc2603_MFP_CTL0));
+
+#ifdef ETHENRET_PHY_LOOP_BACK
+	/* phy loopback */
+	//atc260x_reg_setbits(atc260x, atc2603_PHY_CONFIG, 0x1 << 11, 0x1 << 11);
+	printk("phy config: 0x%x\n", (uint)atc260x_reg_read(atc260x, atc2603_PHY_CONFIG));
+	{
+		/* shut auto-negoiation */
+		ushort bmcr = read_phy_reg(ecp, MII_BMCR);
+		bmcr &= ~BMCR_ANENABLE;
+		write_phy_reg(ecp, MII_BMCR, bmcr);
+
+		bmcr = read_phy_reg(ecp, MII_BMCR);
+		bmcr |= BMCR_LOOPBACK;
+		write_phy_reg(ecp, MII_BMCR, bmcr);
+		printk("phy bmcr: 0x%x\n", (uint)read_phy_reg(ecp, MII_BMCR));
+	}
+#endif
+	return 0;
+}
+
+#endif //PGA0
+
+/******************************* RTL8201 *******************************/
+/**
+ * read_phy_reg - MII interface  to read  @reg_addr register of phy at @phy_addr
+ * return positive and zero value if success, or negative value if fail
+ * may be used by other standard ethernet phy
+ */
+unsigned short read_phy_reg_rtl8201(ec_priv_t * ecp, unsigned short reg_addr)
+{
+	u32 op_reg;
+	u32 phy_addr;
+
+	if((ecp->phy_addr) != 0xFF)
+		phy_addr = ecp->phy_addr;
+	else
+		phy_addr = ASOC_ETHERNET_PHY_ADDR;
+
+	do {
+		op_reg = getl(MAC_CSR10);
+	} while (op_reg & MII_MNG_SB);
+
+	putl(MII_MNG_SB | MII_MNG_OPCODE(MII_OP_READ) | MII_MNG_REGADD(reg_addr) |
+		MII_MNG_PHYADD(phy_addr), MAC_CSR10);
+
+	do {
+		op_reg = getl(MAC_CSR10);
+	} while (op_reg & MII_MNG_SB);
+
+	return (u16)MII_MNG_DATA(op_reg);
+}
+
+
+/**
+ * write_phy_reg - MII interface  to write  @val to @reg_addr register of phy at @phy_addr
+ * return zero if success, negative value if fail
+ * may be used by other standard ethernet phy
+ */
+int write_phy_reg_rtl8201(ec_priv_t * ecp, unsigned short reg_addr, unsigned short val)
+{
+	u32 op_reg;
+	u32 phy_addr;
+
+	if((ecp->phy_addr) != 0xFF)
+		phy_addr = ecp->phy_addr;
+	else
+		phy_addr = ASOC_ETHERNET_PHY_ADDR;
+
+	do {
+		op_reg = getl(MAC_CSR10);
+	} while (op_reg & MII_MNG_SB);
+
+	putl(MII_MNG_SB | MII_MNG_OPCODE(MII_OP_WRITE) | MII_MNG_REGADD(reg_addr) |
+		MII_MNG_PHYADD(phy_addr) | val, MAC_CSR10);
+
+	do {
+		op_reg = getl(MAC_CSR10);
+	} while (op_reg & MII_MNG_SB);
+
+	return 0;
+}
+/******************************* RTL8201 *******************************/
+
+
+/******************************* SR8201G *******************************/
+/**
+ * read_phy_reg - MII interface  to read  @reg_addr register of phy at @phy_addr
+ * return positive and zero value if success, or negative value if fail
+ * may be used by other standard ethernet phy
+ */
+unsigned short read_phy_reg_sr8201g(ec_priv_t * ecp, unsigned short reg_addr)
+{
+	u32 op_reg;
+	u32 phy_addr;
+	if((ecp->phy_addr)!=0xFF)
+		phy_addr=ecp->phy_addr;
+	else
+		phy_addr=ASOC_ETHERNET_PHY_ADDR;
+
+	do {
+		op_reg = getl(MAC_CSR10);
+	} while (op_reg & MII_MNG_SB);
+
+	putl(MII_MNG_SB | MII_MNG_OPCODE(MII_OP_READ) | MII_MNG_REGADD(reg_addr) |
+		MII_MNG_PHYADD(phy_addr), MAC_CSR10);
+
+	do {
+		op_reg = getl(MAC_CSR10);
+	} while (op_reg & MII_MNG_SB);
+
+	return (u16)MII_MNG_DATA(op_reg);
+}
+
+/**
+ * write_phy_reg - MII interface  to write  @val to @reg_addr register of phy at @phy_addr
+ * return zero if success, negative value if fail
+ * may be used by other standard ethernet phy
+ */
+int write_phy_reg_sr8201g(ec_priv_t * ecp, unsigned short reg_addr, unsigned short val)
+{
+	u32 op_reg;
+	u32 phy_addr;
+
+	if((ecp->phy_addr)!=0xFF)
+		phy_addr=ecp->phy_addr;
+	else
+		phy_addr=ASOC_ETHERNET_PHY_ADDR;
+
+	do {
+		op_reg = getl(MAC_CSR10);
+	} while (op_reg & MII_MNG_SB);
+
+	putl(MII_MNG_SB | MII_MNG_OPCODE(MII_OP_WRITE) | MII_MNG_REGADD(reg_addr) |
+		MII_MNG_PHYADD(phy_addr) | val, MAC_CSR10);
+
+	do {
+		op_reg = getl(MAC_CSR10);
+	} while (op_reg & MII_MNG_SB);
+
+	return 0;
+}
+/******************************* SR8201G *******************************/
+
+
+/******************************* KSZ8041 *******************************/
+/**
+ * read_phy_reg - MII interface  to read  @reg_addr register of phy at @phy_addr
+ * return positive and zero value if success, or negative value if fail
+ * may be used by other standard ethernet phy
+ */
+unsigned short read_phy_reg_ksz8041(ec_priv_t * ecp, unsigned short reg_addr)
+{
+	u32 op_reg;
+
+	do {
+		op_reg = getl(MAC_CSR10);
+	} while (op_reg & MII_MNG_SB);
+
+	putl(MII_MNG_SB | MII_MNG_OPCODE(MII_OP_READ) | MII_MNG_REGADD(reg_addr) |
+		MII_MNG_PHYADD(ASOC_ETHERNET_PHY_ADDR), MAC_CSR10);
+
+	do {
+		op_reg = getl(MAC_CSR10);
+	} while (op_reg & MII_MNG_SB);
+
+	return (u16)MII_MNG_DATA(op_reg);
+}
+
+
+/**
+ * write_phy_reg - MII interface  to write  @val to @reg_addr register of phy at @phy_addr
+ * return zero if success, negative value if fail
+ * may be used by other standard ethernet phy
+ */
+int write_phy_reg_ksz8041(ec_priv_t * ecp, unsigned short reg_addr, unsigned short val)
+{
+	u32 op_reg;
+
+	do {
+		op_reg = getl(MAC_CSR10);
+	} while (op_reg & MII_MNG_SB);
+
+	putl(MII_MNG_SB | MII_MNG_OPCODE(MII_OP_WRITE) | MII_MNG_REGADD(reg_addr) |
+		MII_MNG_PHYADD(ASOC_ETHERNET_PHY_ADDR) | val, MAC_CSR10);
+
+	do {
+		op_reg = getl(MAC_CSR10);
+	} while (op_reg & MII_MNG_SB);
+
+	return 0;
+}
+/******************************* KSZ8041 *******************************/
+
+
+static inline void phy_reg_set_bits(ec_priv_t * ecp, unsigned short reg_addr, int bits)
+{
+	unsigned short reg_val;
+	reg_val = read_phy_reg(ecp, reg_addr);
+	reg_val |= (unsigned short)bits;
+	printk(KERN_DEBUG" %s %d write reg_val:0x%x\n", __FUNCTION__,__LINE__,reg_val);
+	write_phy_reg(ecp, reg_addr, reg_val);
+	reg_val = read_phy_reg(ecp, reg_addr);
+	printk(KERN_DEBUG" %s %d write after read reg_val:0x%x\n", __FUNCTION__,__LINE__,reg_val);
+}
+
+static inline void phy_reg_clear_bits(ec_priv_t * ecp, unsigned short reg_addr, int bits)
+{
+	unsigned short reg_val;
+
+	reg_val = read_phy_reg(ecp, reg_addr);
+	reg_val &= ~(unsigned short)bits;
+	write_phy_reg(ecp, reg_addr, reg_val);
+}
+
+static inline int wait_for_aneg_completion(ec_priv_t * ecp)
+{
+    int     wait;
+    int     reg_val;
+    for (wait = PHY_AUTONEG_TIME_OUT; wait > 0; wait--) {
+        if (suspend_flag == 1) {
+            suspend_flag = 0;
+            break;
+        }
+        reg_val = read_phy_reg(ecp, MII_BMSR);
+        if (reg_val & BMSR_ANEGCOMPLETE)
+            break;
+
+        mdelay(100);
+        printk(KERN_DEBUG"%s", (wait % 200) ? "*" : "\n");
+    }
+    printk(KERN_DEBUG"exit\n");
+
+    return (!wait);
+}
+
+/**
+ * phy_init -- initialize phy - ATC2605 or KSZ8041
+ * return 0 if success, else fail
+ */
+static int phy_init(ec_priv_t * ecp)
+{
+	int     reg_val;
+	//u16 temp;
+	unsigned int cnt = 0;	
+	phy_reg_set_bits(ecp, MII_BMCR, BMCR_RESET);
+	do {
+		reg_val = read_phy_reg(ecp, MII_BMCR);
+		if (cnt++ > 1000) {
+			printk(KERN_ERR"ethernet phy BMCR_RESET timeout!!!\n");
+			break;
+		}
+	} while (reg_val & BMCR_RESET);
+
+	if (ecp->phy_model == ETH_PHY_MODEL_ATC2605) {
+		phy_reg_set_bits(ecp, PHY_REG_FTC1, PHY_FTC_PRL);
+		phy_reg_set_bits(ecp, PHY_REG_FTC2, PHY_FTC_CMPT);
+	} else if (ecp->phy_model == ETH_PHY_MODEL_KSZ8041TL) {
+		/* only turn on link up/down phy interrupt */
+		write_phy_reg(ecp, MII_ICSR, ICSR_LINKUP_EN | ICSR_LINKDOWN_EN);
+		printk(KERN_DEBUG"MII_ICSR:0x%x\n", (unsigned)read_phy_reg(ecp, MII_ICSR));
+		phy_reg_set_bits(ecp, MII_PHY_CTL2, PHY_CTL2_INT_LEVEL);
+		printk(KERN_DEBUG"MII_PHY_CTL2:0x%x\n", (unsigned)read_phy_reg(ecp, MII_PHY_CTL2));
+	} else if (ecp->phy_model == ETH_PHY_MODEL_RTL8201) {
+		write_phy_reg(ecp, PHY_RTL8201F_REG_PAGE_SELECT, PHY_RTL8201F_REG_PAGE_SELECT_SEVEN);
+#ifndef CONFIG_POLL_PHY_STATE
+		/* only turn on link up/down phy interrupt */
+		write_phy_reg(ecp, PHY_RTL8201F_REG_INT_LED_FUNC, PHY_RTL8201F_PIN_LINK_STATE_CHANGE);
+#endif
+		/*As datasheet says tx&rx offset's default value is 0xF but be zero in fact.Reset them*/
+		write_phy_reg(ecp, PHY_RTL8201F_REG_RMSR, 
+			PHY_RTL8201F_RMSR_CLK_DIR_INPUT | PHY_RTL8201F_RMSR_RMII_MODE|PHY_RTL8201F_RMSR_RMII_RX_OFFSET|PHY_RTL8201F_RMSR_RMII_TX_OFFSET);
+		write_phy_reg(ecp, PHY_RTL8201F_REG_PAGE_SELECT, PHY_RTL8201F_REG_PAGE_SELECT_ZERO);
+	} else if (ecp->phy_model == ETH_PHY_MODEL_SR8201G) {
+		write_phy_reg(ecp, PHY_SR8201G_REG_PAGE_SELECT, PHY_SR8201G_REG_PAGE_SELECT_SEVEN);
+#ifndef CONFIG_POLL_PHY_STATE
+		/* only turn on link up/down phy interrupt */
+		write_phy_reg(ecp, PHY_SR8201G_REG_INT_LED_FUNC, PHY_SR8201G_INT_PIN_SELECT | PHY_SR8201G_INT_PIN_LINK_STATE_CHANGE);
+#endif
+		write_phy_reg(ecp, PHY_SR8201G_REG_RMSR, PHY_SR8201G_CLK_DIR_INPUT);
+		write_phy_reg(ecp, PHY_SR8201G_REG_PAGE_SELECT, PHY_SR8201G_REG_PAGE_SELECT_ZERO);
+	}else {
+		printk(KERN_ERR"NOT supported phy model: %u\n", ecp->phy_model);
+	}
+#if 0
+	/* adjust tx current */
+	temp = read_phy_reg(ecp, 0x12);
+	temp  &= ~0x780;
+	//temp	|= 0x600; //1100, add 50+100uA
+	//temp	|= 0x680; //1101
+	//temp  |= 0x480; //1001
+	//temp	|= 0x280; //0101
+	//temp	|= 0x80; //0001
+	temp	|= 0x180; //0011, minus 50uA  max 2.57V
+	//temp	|= 0x780; //1111
+	write_phy_reg(ecp, 0x12, temp);
+	printk("PHY_REG_TXPN = 0x%x\n", (u32)read_phy_reg(ecp, 0x12));
+#endif
+#ifdef WORK_IN_10M_MODE
+	/* limit to 10M for 5203 MAC bug */
+	phy_reg_clear_bits(ecp, MII_ADVERTISE, ADVERTISE_100HALF | ADVERTISE_100FULL);
+#endif
+	printk(KERN_DEBUG"MII_ADVERTISE: 0x%04x\n", (uint)read_phy_reg(ecp, MII_ADVERTISE));
+	printk(KERN_DEBUG"%s %d MII_BMCR: 0x%04x\n", __FUNCTION__,__LINE__,(uint)read_phy_reg(ecp, MII_BMCR));
+
+	/* auto-negotiate and wait for completion, then get link status */
+	phy_reg_set_bits(ecp, MII_BMCR, BMCR_ANENABLE | BMCR_ANRESTART);
+	printk(KERN_DEBUG"start aneg...\n");
+	printk(KERN_DEBUG"%s %d MII_BMCR: 0x%04x\n",  __FUNCTION__,__LINE__,(uint)read_phy_reg(ecp, MII_BMCR));
+
+	/* wait_for_aneg_completion(ecp) sleep(), so it shall not be invoked in
+	 * ec_netdev_transmit_timeout() which runs in interrupt bottom half. */
+#if 0
+	printk("wait for aneg...\n");
+	if (wait_for_aneg_completion(ecp)) {
+		printk("MII_BMCR:0x%x\n", read_phy_reg(ecp, MII_BMCR));
+		printk("auto-negotiation is timeout.\n");
+		return (1);
+	}
+   int i = 0 ;
+	for (i = 0; i < MII_TIME_OUT; i++) {
+		reg_val = read_phy_reg(ecp, MII_BMSR);
+		if (reg_val & BMSR_LSTATUS) {
+			ecp->linked = true;
+			break;
+		}
+		udelay(1);
+	}
+	if (MII_TIME_OUT == i) {
+		ecp->linked = false;
+		printk("link fail.\n");
+		return (1);
+	}
+#else
+	/* not wait, set link status not connected and return*/
+	ecp->linked = false;
+#endif
+
+	printk(KERN_INFO"link status is: %s\n", ecp->linked ? "true" : "false");
+	return (0);
+}
+
+
+/**
+ * fdp110_setup_aneg - setup  or disable  auto-negotiation;
+ * if enable auto-neg, we enable and restart auto-neg, don't wait for it completion
+ * link change interrupt can capture it
+ * if disable auto-neg, but auto-neg is already disabled, then nothing to do, 
+ * else disable auto-neg
+ * return 0 if success, negative value if fail
+ */
+static int fdp110_setup_aneg(ec_priv_t * ecp, bool autoneg)
+{
+    int     bmcr;
+    int     err;
+
+    bmcr = read_phy_reg(ecp, MII_BMCR);
+    if (bmcr < 0) {
+        return (bmcr);
+    }
+
+    if (autoneg) {
+        bmcr |= BMCR_ANENABLE | BMCR_ANRESTART;
+        err = write_phy_reg(ecp, MII_BMCR, bmcr);
+        if (err < 0)
+            return (err);
+    } else if (bmcr & BMCR_ANENABLE) {
+        printk(KERN_INFO"disable auto-neg\n");
+        bmcr &= ~BMCR_ANENABLE;
+        err = write_phy_reg(ecp, MII_BMCR, bmcr);
+        if (err < 0)
+            return (err);
+    }
+
+    return (0);
+}
+
+
+static inline int restart_autoneg(ec_priv_t * ecp)
+{
+    int     bmcr_val;
+
+    bmcr_val = read_phy_reg(ecp, MII_BMCR);
+    if (bmcr_val < 0) {
+        return (bmcr_val);
+    }
+
+    bmcr_val |= BMCR_ANENABLE | BMCR_ANRESTART;
+    return (write_phy_reg(ecp, MII_BMCR, bmcr_val));
+}
+
+
+/**
+ * fdp110_setup_advert -- set auto-negotiation advertisement
+ * return positive value wrote to ANAR reg if success, negative value if fail 
+ */
+static int fdp110_setup_advert(ec_priv_t * ecp, int advertising)
+{
+    int     adv;
+    int     err;
+    const int supported = ADVERTISE_ALL | ADVERTISE_PAUSE_CAP;
+
+    adv = read_phy_reg(ecp, MII_ADVERTISE);
+    if (adv < 0) {
+        return (adv);
+    }
+
+    /* remove old supported features, but maintain others bit */
+    adv &= ~supported;
+    if (!(advertising & supported)) {
+        return (-1);
+    }
+    adv |= (advertising & supported);
+    err = write_phy_reg(ecp, MII_ADVERTISE, adv);
+    if (err < 0) {
+        return (err);
+    }
+
+    /* in fact, when we set new value to phy's advertisement reg, phy will auto-neg again,
+     * but some times it don't, so we manually force it auto-neg again.
+     * we don't wait for auto-neg completion, link change interrupt will capture it
+     */
+    err = restart_autoneg(ecp);
+
+    return (err < 0 ? err : adv);
+}
+
+
+/**
+ * fdp110_setup_forced -- configure phy work on @speed and @duplex mode forciblly
+ * NOTE: this will close auto-neg function
+ * return 0 if success, negative value if fail
+ */
+static int fdp110_setup_forced(ec_priv_t * ecp, int speed, int duplex)
+{
+    int     err = 0;
+    int     eval;
+    int     bmcr;
+
+    bmcr = read_phy_reg(ecp, MII_BMCR);
+    if (bmcr < 0) {
+        printk(KERN_ERR"error read bmcr\n");
+        return (-1);
+    }
+
+    eval = bmcr & ~(BMCR_ANENABLE | BMCR_SPEED100 | BMCR_FULLDPLX);
+    if (ETH_SPEED_100M == speed) {
+        eval |= BMCR_SPEED100;
+    }
+    if (ETH_DUP_FULL == duplex) {
+        eval |= BMCR_FULLDPLX;
+    }
+    if (eval != bmcr) {
+        err = write_phy_reg(ecp, MII_BMCR, eval);
+    }
+
+    return (err);
+}
+
+
+/**
+ * fdp110_setup_loopback -- setup or disable loopback
+ * return 0 if success, negative value if fail
+ */
+static int fdp110_setup_loopback(ec_priv_t * ecp, bool loopback)
+{
+    int     bmcr;
+    int     err = 0;
+    bool    changed = false;
+
+    bmcr = read_phy_reg(ecp, MII_BMCR);
+    if (bmcr < 0) {
+        return (bmcr);
+    }
+
+    if (loopback) {
+        if (!(bmcr & BMCR_LOOPBACK)) {
+            bmcr |= BMCR_LOOPBACK;
+            changed = true;
+        }
+    } else {
+        if (bmcr & BMCR_LOOPBACK) {
+            bmcr &= ~BMCR_LOOPBACK;
+            changed = true;
+        }
+    }
+
+    if (changed) {
+        err = write_phy_reg(ecp, MII_BMCR, bmcr);
+    }
+    printk(KERN_INFO"changed - %s \n", changed ? "true" : "false");
+
+    return (err);
+}
+
+
+/**
+ * fdp110_read_status -- read phy's status, according phy ancr, anar & anlpar regs
+ * return 0 if success, negative value if fail
+ */
+static int fdp110_read_status(ec_priv_t * ecp)
+{
+    int     adv;
+    int     lpa;
+    //int     bmsr;
+    int     bmcr;
+    //int     aner;
+    int speed;
+    int duplex;
+
+    if (wait_for_aneg_completion(ecp)) {
+        printk(KERN_INFO"MII_BMCR:0x%x\n", read_phy_reg(ecp, MII_BMCR));
+        printk(KERN_INFO"auto-negotiation is timeout.\n");
+        return (-1);
+    }
+
+    bmcr = read_phy_reg(ecp, MII_BMCR);
+    if (bmcr < 0)
+        return (bmcr);
+
+#if 0 /* FIXME: should check if both side have auto-negotiation ability */
+    bmsr = read_phy_reg(ecp, MII_BMSR);
+    if (bmsr < 0)
+        return (bmsr);
+
+    aner = read_phy_reg(ecp, MII_EXPANSION);
+    if (aner < 0)
+        return (aner);
+
+    ecp->autoneg = aner & EXPANSION_NWAY ? true : false;
+#else
+    ecp->autoneg = bmcr & BMCR_ANENABLE ? true : false;
+#endif
+    printk(KERN_DEBUG"ecp->autoneg:%d", (int)ecp->autoneg);
+
+    if (ecp->autoneg) {
+        lpa = read_phy_reg(ecp, MII_LPA);
+        if (lpa < 0) {
+            printk(KERN_ERR"lpa error : 0x%x\n", lpa);
+            return (lpa);
+        }
+
+        adv = read_phy_reg(ecp, MII_ADVERTISE);
+        if (adv < 0) {
+            printk(KERN_ERR"adv error : 0x%x\n", adv);
+            return (adv);
+        }
+
+        /* mii anar and'd anlpar to get mii abilities
+         * there is a priority order according to ieee 802.3u, as follow
+         * 100M-full, 100MbaseT4, 100M-half, 10M-full and last 10M-half
+         * fdp110 don't support 100MbaseT4
+         */
+        lpa &= adv;
+        ecp->speed = ETH_SPEED_10M;
+        ecp->duplex = ETH_DUP_HALF;
+
+        if ((lpa & (LPA_100FULL | LPA_100HALF))) {
+            ecp->speed = ETH_SPEED_100M;
+            if (lpa & LPA_100FULL)
+                ecp->duplex = ETH_DUP_FULL;
+        } else if ((lpa & LPA_10FULL)) {
+            ecp->duplex = ETH_DUP_FULL;
+        }
+
+        if (bmcr & BMCR_FULLDPLX) {
+            duplex = ETH_DUP_FULL;
+        } else {
+            duplex = ETH_DUP_HALF;
+        }
+        if (duplex != ecp->duplex) {
+            ecp->duplex = duplex;
+            printk(KERN_INFO"BMCR & ANLPAR duplex conflicts!!!\n");
+        }
+
+        if (bmcr & BMCR_SPEED100) {
+            speed = ETH_SPEED_100M;
+        } else {
+            speed = ETH_SPEED_10M;
+        }
+        if (speed != ecp->speed) {
+            ecp->speed = speed;
+            printk(KERN_INFO"BMCR & ANLPAR speed conflicts!!!\n");
+        }
+
+        if (ETH_DUP_FULL == ecp->duplex)
+            ecp->pause = (lpa & LPA_PAUSE_CAP) ? true : false;
+    } else {
+        ecp->duplex = (BMCR_FULLDPLX & bmcr) ? ETH_DUP_FULL : ETH_DUP_HALF;
+        ecp->speed = (BMCR_SPEED100 & bmcr) ? ETH_SPEED_100M : ETH_SPEED_10M;
+        ecp->pause = false;
+    }
+
+    printk(VT_GREEN "\n%s -> speed:%d, duplex:%s, pause: %s\n" VT_NORMAL,
+           ecp->autoneg ? "autoneg" : "forced", ecp->speed,
+           (ETH_DUP_FULL == ecp->duplex) ? "full" : "half",
+           ecp->pause ? "supported" : "non-supported");
+
+    return (0);
+}
+
+/**
+ * fdp110_get_link - get link state;
+ * we alse can get link status from MAC_CSR5[LCIS]
+ * return 0 if link not established, 1 if established, negative value if fail
+ */
+static int fdp110_get_link(ec_priv_t * ecp)
+{
+    int     bmsr;
+
+    bmsr = read_phy_reg(ecp, MII_BMSR);
+    if (bmsr < 0) {
+        return (bmsr);
+    }
+
+    return (!!(bmsr & BMSR_LSTATUS));
+}
+
+/**
+ * fdp110_suspend -- power down or power on the phy
+ * return 0 if success, negative if fail
+ */
+static int fdp110_suspend(ec_priv_t * ecp, bool power_down)
+{
+    int     reg_val;
+
+    reg_val = read_phy_reg(ecp, MII_BMCR);
+    if (reg_val < 0) {
+        return (reg_val);
+    }
+
+    if (power_down) {
+        reg_val |= BMCR_PDOWN;
+    } else {
+        reg_val &= ~BMCR_PDOWN;
+    }
+
+    return (write_phy_reg(ecp, MII_BMCR, reg_val));
+
+}
+
+
+static struct phy_info fdp110_ops = {
+    .id = 0x0,
+    .name = "fdp110", /* same to ATC2605 */
+    .phy_hw_init = NULL,//atc2605_hw_init,
+    .phy_init = phy_init,
+    .phy_suspend = fdp110_suspend,
+    .phy_setup_advert = fdp110_setup_advert,
+    .phy_setup_forced = fdp110_setup_forced,
+    .phy_setup_aneg = fdp110_setup_aneg,
+    .phy_setup_loopback = fdp110_setup_loopback,
+    .phy_read_status = fdp110_read_status,
+    .phy_get_link = fdp110_get_link,
+};
+
+static struct phy_info ksz8041_ops = {
+    .id = 0x0,
+    .name = "ksz8041",
+    .phy_hw_init = NULL, /* not need */
+    .phy_init = phy_init,
+    .phy_suspend = fdp110_suspend,
+    .phy_setup_advert = fdp110_setup_advert,
+    .phy_setup_forced = fdp110_setup_forced,
+    .phy_setup_aneg = fdp110_setup_aneg,
+    .phy_setup_loopback = fdp110_setup_loopback,
+    .phy_read_status = fdp110_read_status,
+    .phy_get_link = fdp110_get_link,
+};
+
+
+static struct phy_info rtl8201_ops = {
+    .id = 0x0,
+    .name = "rtl8201",
+    .phy_hw_init = NULL, /* not need */
+    .phy_init = phy_init,
+    .phy_suspend = fdp110_suspend,
+    .phy_setup_advert = fdp110_setup_advert,
+    .phy_setup_forced = fdp110_setup_forced,
+    .phy_setup_aneg = fdp110_setup_aneg,
+    .phy_setup_loopback = fdp110_setup_loopback,
+    .phy_read_status = fdp110_read_status,
+    .phy_get_link = fdp110_get_link,
+};
+
+static struct phy_info sr8201g_ops = {
+    .id = 0x0,
+    .name = "sr8201g",
+    .phy_hw_init = NULL, /* not need */
+    .phy_init = phy_init,
+    .phy_suspend = fdp110_suspend,
+    .phy_setup_advert = fdp110_setup_advert,
+    .phy_setup_forced = fdp110_setup_forced,
+    .phy_setup_aneg = fdp110_setup_aneg,
+    .phy_setup_loopback = fdp110_setup_loopback,
+    .phy_read_status = fdp110_read_status,
+    .phy_get_link = fdp110_get_link,
+};
+
+void ep_set_phy_ops(ec_priv_t * ecp)
+{
+	if (ecp->phy_model == ETH_PHY_MODEL_ATC2605) {
+		printk(KERN_INFO"phy model: ATC2605\n");
+		ecp->phy_ops = &fdp110_ops;
+		//read_phy_reg = read_phy_reg_atc2605;
+		//write_phy_reg = write_phy_reg_atc2605;
+	} else if (ecp->phy_model == ETH_PHY_MODEL_KSZ8041TL) {
+		printk(KERN_INFO"phy model: KSZ8041TL\n");
+		ecp->phy_ops = &ksz8041_ops;
+		read_phy_reg = read_phy_reg_ksz8041;
+		write_phy_reg = write_phy_reg_ksz8041;
+	} else if (ecp->phy_model == ETH_PHY_MODEL_RTL8201) {
+		printk(KERN_INFO"phy model: RTL8201\n");
+		ecp->phy_ops = &rtl8201_ops;
+		read_phy_reg = read_phy_reg_rtl8201;
+		write_phy_reg = write_phy_reg_rtl8201;
+	} else if (ecp->phy_model == ETH_PHY_MODEL_SR8201G){
+		printk(KERN_INFO "phy model: SR8201G\n");
+		ecp->phy_ops = &sr8201g_ops;
+		read_phy_reg = read_phy_reg_sr8201g;
+		write_phy_reg = write_phy_reg_sr8201g;
+	}else {
+		printk(KERN_INFO"NOT supported phy model: %u\n", ecp->phy_model);
+	}
+}
diff --git a/drivers/net/ethernet/acts/ethctrl.c b/drivers/net/ethernet/acts/ethctrl.c
new file mode 100755
index 0000000..d0d1bb5
--- /dev/null
+++ b/drivers/net/ethernet/acts/ethctrl.c
@@ -0,0 +1,3664 @@
+/******************************************************************************
+ ethctrl.c -- ethernet controller embedded in GL5202/GL5302
+ 
+ author : zhouyiliang  @Actions 
+ date : 2012-07-04 
+ version 0.1
+
+ 1. MAC address filter mode : only supports perfect filtering currently
+ 2. supports up to 14 multicast mac address
+ 
+******************************************************************************/
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/etherdevice.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/workqueue.h>
+#include <linux/gpio.h>
+#include <linux/workqueue.h>
+#include <linux/dma-mapping.h>
+#include <linux/fs.h>
+#include <linux/random.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/of_irq.h>
+#include <asm/io.h>
+#include <mach/irqs.h>
+#include <linux/clk.h>
+#include <mach/clkname.h>
+#include <mach/module-owl.h>
+#include <linux/ctype.h>
+#include <asm/system_info.h>
+
+#include "ethctrl.h"
+#include "des.h"
+
+// test needed
+#include <linux/stddef.h>
+#include <linux/of_gpio.h>
+
+#define SETUP_FRAME_LEN 192
+#define SETUP_FRAME_PAD 16
+
+/* 0xD0, reserve 16 bytes for align */
+#define SETUP_FRAME_RESV_LEN  (SETUP_FRAME_LEN + SETUP_FRAME_PAD)
+
+#define EC_SKB_ALIGN_BITS_MASK  0x3
+#define EC_SKB_ALIGNED  0x4
+
+/* 'mii -v' will read first 8 phy registers to get status */
+#define PHY_REG_ADDR_RANGE 0x7  
+#define PHY_ADDR_MASK (PHY_ADDR_LIMIT - 1)
+#define PHY_REG_NUM_MASK 0x7
+#define PHY_REG_BITS 16
+
+#define FLAG_PHY_RESET         1
+#define FLAG_PHY_NONE_RESET    0
+#define FLAG_CLOCK_RESET       1
+#define FLAG_CLOCK_NONT_RESET  1
+
+// need modify it later
+#ifdef EC_DEBUG
+#define NET_MSG_ENABLE  0 //( NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_LINK )
+#else
+#define NET_MSG_ENABLE  0
+#endif
+#define EC_TX_TIMEOUT (0.05*HZ)
+#define MAX_DEVICES 1
+#define MII_TIME_OUT 100
+
+static struct delayed_work resume_work;
+static struct workqueue_struct *resume_queue = NULL;
+
+#ifdef DETECT_POWER_SAVE
+static struct workqueue_struct *power_save_queue = NULL;
+#endif
+
+static char g_default_mac_addr[ETH_MAC_LEN] = {0x00, 0x18, 0xFE, 0x61, 0xD5, 0xD6};
+static struct net_device *g_eth_dev[MAX_DEVICES];
+
+static struct clk *ethernet_clk;
+
+static char *macaddr = "?";
+int suspend_flag = 0;
+module_param(macaddr, charp, 0);
+MODULE_PARM_DESC(macaddr, "MAC address");
+
+static const char g_banner[] __initdata = KERN_INFO "Ethernet controller driver\
+    for Actions GL5203, @2012 Actions.\n";
+
+#ifdef ETH_TEST_MODE
+static void print_frame_data(void *frame, int len);
+static struct sk_buff *get_skb_aligned(unsigned int len);
+static int ec_netdev_start_xmit(struct sk_buff *skb, struct net_device *dev);
+void print_mac_register(ec_priv_t *ecp);
+void print_phy_register(ec_priv_t *ecp);
+static void set_mac_according_aneg(ec_priv_t *ecp);
+#endif
+
+ssize_t netif_msg_show(struct device *dev, struct device_attribute *attr,
+        char *buf)
+{
+    struct net_device *ndev = to_net_dev(dev);
+    ec_priv_t *ecp = netdev_priv(ndev);
+
+    return sprintf(buf, "0x%x\n", ecp->msg_enable);
+}
+
+ssize_t netif_msg_store(struct device *dev, struct device_attribute *attr,
+         const char *buf, size_t count)
+{
+    struct net_device *ndev = to_net_dev(dev);
+    ec_priv_t *ecp = netdev_priv(ndev);
+    char *endp;
+    unsigned long new;
+    int ret = -EINVAL;
+
+    new = simple_strtoul(buf, &endp, 0);
+    if (endp == buf)
+        goto err;
+
+    ecp->msg_enable = (int)new;
+    return count;
+err:
+    return ret;
+}
+
+DEVICE_ATTR(netif_msg, S_IRUGO | S_IWUSR, netif_msg_show, netif_msg_store);
+
+ssize_t phy_state_show(struct device *dev, struct device_attribute *attr,
+        char *buf)
+{
+    struct net_device *ndev = g_eth_dev[0];
+    ec_priv_t *ecp = netdev_priv(ndev);
+
+    return sprintf(buf, "%s\n", ecp->linked ? "linked" : "disconnected");
+}
+DEVICE_ATTR(phy_state, S_IRUGO, phy_state_show, NULL);
+
+
+#ifdef ETH_TEST_MODE
+/* default -1 denote send single frame, [0, n] denote interval n us between 2 frames */
+static long continuity_interval = -1;
+
+ssize_t continuity_show(struct device *dev, struct device_attribute *attr,
+        char *buf)
+{
+    return sprintf(buf, "continuity_interval: %ld\n", continuity_interval);
+}
+
+ssize_t continuity_store(struct device *dev, struct device_attribute *attr,
+         const char *buf, size_t count)
+{
+    char *endp;
+    unsigned long new;
+    int ret = -EINVAL;
+
+    new = simple_strtoul(buf, &endp, 0);
+    if (endp == buf)
+        goto err;
+
+    continuity_interval = (long)new;
+    return count;
+err:
+    return ret;
+}
+
+DEVICE_ATTR(continuity, S_IRUGO | S_IWUGO, continuity_show, continuity_store);
+
+ssize_t send_pattern_show(struct device *dev, struct device_attribute *attr,
+	char *buf)
+{
+    return sprintf(buf, "pattern 0: all zero, 1: all one, 2: pseudo-random\n");
+}
+
+static void gen_frame_pattern(char *buf, int len, int pattern)
+{
+	//printk("buf: %p, len: %d, pattern: %d\n", buf, len, pattern);
+	switch (pattern) {
+	case 0:
+		memset(buf, 0, len);
+		break;
+	case 1:
+		memset(buf, 0xff, len);
+		break;
+	case 2:
+		get_random_bytes(buf, len);
+		break;
+	default:
+		printk(KERN_WARNING"not supported pattern: %d\n", pattern);
+		break;
+	}
+}
+
+static int send_pattern_continuous(int n, int pat, struct net_device *ndev)
+{
+	int ret = -EINVAL;
+	struct sk_buff *skb;
+	int i = 0;
+
+	while (i++ < n) {
+		if (NULL == (skb = get_skb_aligned(PKG_MAX_LEN))) {
+			printk(KERN_ERR"no memory!\n");
+			goto err;
+		}
+		skb->len = 1500;
+		gen_frame_pattern(skb->data, skb->len, pat);
+
+		ec_netdev_start_xmit(skb, ndev);
+		if (continuity_interval > 0)
+			udelay(continuity_interval);
+	}
+	return 0;
+err:
+	return ret;
+}
+
+ssize_t send_pattern_store(struct device *dev, struct device_attribute *attr,
+	const char *buf, size_t count)
+{
+	struct net_device *ndev = to_net_dev(dev);
+	char *endp;
+	unsigned long pat = 5;
+	int ret = -EINVAL;
+	struct sk_buff *skb;
+
+	pat = simple_strtoul(buf, &endp, 0);
+	if ((endp == buf) || (pat > 2))
+	    goto err;
+
+	if (NULL == (skb = get_skb_aligned(PKG_MAX_LEN))) {
+	    printk(KERN_ERR"no memory!\n");
+	    goto err;
+	}
+	skb->len = 1500;
+
+	gen_frame_pattern(skb->data, skb->len, (int)pat);
+	//printk("frame pattern:\n");
+	//print_frame_data(skb->data, skb->len);
+	ec_netdev_start_xmit(skb, ndev);
+
+	if (continuity_interval >= 0) {
+		if (continuity_interval > 0)
+			udelay(continuity_interval);
+		send_pattern_continuous(TX_RING_SIZE - 1, (int)pat, ndev);
+	}
+
+	return count;
+err:
+	return ret;
+}
+
+DEVICE_ATTR(send_pattern, S_IRUGO | S_IWUGO,
+	send_pattern_show, send_pattern_store);
+
+ssize_t test_mode_show(struct device *dev, struct device_attribute *attr,
+	char *buf)
+{
+    return sprintf(buf, "test mode: 10 or 100 Mbps\n");
+}
+
+ssize_t test_mode_store(struct device *dev, struct device_attribute *attr,
+	const char *buf, size_t count)
+{
+	struct net_device *ndev = to_net_dev(dev);
+	ec_priv_t *ecp = netdev_priv(ndev);
+	char *endp;
+	unsigned long mode = 0;
+	int ret = -EINVAL;
+	ushort temp;
+
+	mode = simple_strtoul(buf, &endp, 0);
+	if ((endp == buf) || ((mode != 10) && (mode != 100)))
+	    goto err;
+
+	ecp->test_mode = mode;
+	ecp->speed = mode;
+#if defined(CONFIG_PHY_REALTEK_RTL8201)
+	write_phy_reg(ecp,PHY_RTL8201F_REG_PAGE_SELECT,PHY_RTL8201F_REG_PAGE_SELECT_FOUR);
+	write_phy_reg(ecp,PHY_RTL8201F_REG_EEE_CAP_EN,0x4077);
+	write_phy_reg(ecp,PHY_RTL8201F_REG_EEE_CAP_SET,0xC5A0);
+	write_phy_reg(ecp,PHY_RTL8201F_REG_PAGE_SELECT,PHY_RTL8201F_REG_PAGE_SELECT_ZERO);
+#endif
+	if (ETH_SPEED_10M == ecp->speed) {
+		ecp->duplex = ETH_DUP_FULL;
+#if defined(CONFIG_PHY_REALTEK_RTL8201)
+		printk(KERN_INFO"RTL8201 can link by 10Mps Dumb Hub through Test fixture\n");
+#else
+		temp = read_phy_reg(ecp, PHY_REG_FTC1);
+		temp  &= ~0x40;  //clear bit 6
+		temp  |= 0x01;  //bit 0: force 10M link; bit6: force 100M
+		write_phy_reg(ecp, PHY_REG_FTC1, temp); //Set bit0
+#endif
+	} else {
+		ecp->duplex = ETH_DUP_FULL;
+#if defined(CONFIG_PHY_REALTEK_RTL8201)
+		write_phy_reg(ecp,MII_BMCR,BMCR_RESET);//Reset the phy,following is only to test the tx
+		mdelay(20);
+		write_phy_reg(ecp,0x18,0x0310);//Disable ALDPS
+		write_phy_reg(ecp,0x1C,0x40C0);//For MDIX
+#endif
+	}
+
+	printk(KERN_DEBUG"PHY_REG_FTC1 = 0x%x\n", (u32)read_phy_reg(ecp, PHY_REG_FTC1));
+	printk(KERN_DEBUG"PHY_REG_TXPN = 0x%x\n", (u32)read_phy_reg(ecp, 0x12));
+
+	/* shut auto-negoiation */
+	temp = read_phy_reg(ecp, MII_BMCR);
+	temp &= ~BMCR_ANENABLE;
+	write_phy_reg(ecp, MII_BMCR, temp);
+
+	set_mac_according_aneg(ecp);
+
+	printk(KERN_DEBUG"new_duplex = 0x%x\n", ecp->duplex);
+	printk(KERN_DEBUG"new_speed = 0x%x\n", ecp->speed);
+	print_phy_register(ecp);
+	print_mac_register(ecp);
+
+	return count;
+err:
+	return ret;
+}
+
+DEVICE_ATTR(test_mode, S_IRUGO | S_IWUGO, test_mode_show, test_mode_store);
+#endif /* ETH_TEST_MODE */
+
+static int ethernet_set_ref_clk(struct clk *clk, ulong tfreq)
+{
+	int ret = -1;
+	ulong freq;
+
+	printk(KERN_INFO"target freq: %lu\n", tfreq);
+	freq= clk_round_rate(clk, tfreq);
+	if (freq == tfreq) {
+		ret = clk_set_rate(clk, freq);
+		if (ret)
+			printk(KERN_ERR"set RMII_REF_CLK: %lu failed, errno: %d\n",
+				tfreq, -ret);
+	} else
+		printk(KERN_ERR"wrong RMII_REF_CLK: %lu\n", tfreq);
+
+	return ret;
+}
+
+static int ethernet_clock_config(int phy_mode)
+{
+	struct clk *clk;
+	int ret = -1;
+	ulong tfreq;
+
+	printk(KERN_INFO"phy_mode: %d\n", phy_mode);
+	clk = clk_get(NULL, CLKNAME_RMII_REF_CLK);
+	switch (phy_mode) {
+	case ETH_PHY_MODE_RMII:
+		tfreq = 50 * 1000 * 1000;
+		ret = ethernet_set_ref_clk(clk, tfreq);
+		break;
+	case ETH_PHY_MODE_SMII:
+		tfreq = 125 * 1000 * 1000;
+		ret = ethernet_set_ref_clk(clk, tfreq);
+		break;
+	default:
+		printk(KERN_ERR"not support phy mode: %d\n", phy_mode);
+	}
+
+	clk_put(clk);
+
+	return ret;
+}
+
+static void ethernet_clock_enable(int reset_flg)
+{
+#if 0
+	/* enable ethernet clk */
+	putl(ASOC_ETH_CLOCK_EN, CMU_DEVCLKEN1);
+
+	/* reset ethernet clk */
+	putl(getl(CMU_DEVRST1) & ~ASOC_ETH_CLOCK_RST, CMU_DEVRST1);
+	putl(getl(CMU_DEVRST1) | ASOC_ETH_CLOCK_RST, CMU_DEVRST1);
+#else
+	int ret;
+
+	if(ethernet_clk != NULL){
+		ret = clk_enable(ethernet_clk);
+		if (ret)
+			printk(KERN_ERR"enable ethernet clock failed, errno: %d\n", -ret);
+		udelay(100);
+		/* reset ethernet clk */
+		if(reset_flg){
+			//printk(KERN_INFO "%s: ethernet clk reset\n", __func__);
+			module_reset(MODULE_RST_ETHERNET);
+		}
+		udelay(100);
+	}
+#endif
+}
+
+static void ethernet_clock_disable(void)
+{
+#if 0
+	/* disable ethernet clk */
+	putl(getl(CMU_DEVCLKEN1) & ~ASOC_ETH_CLOCK_EN, CMU_DEVCLKEN1);
+#else
+	/*if(ethernet_clk != NULL){
+		clk_disable(ethernet_clk);
+		udelay(100);
+	}*/
+#endif
+}
+
+/* data is a ethernet frame */
+static void check_icmp_sequence(const void *data, const char *msg)
+{
+#define ptr_to_u32(data, off) (ntohl(*(u32*)((char *)data + off)))
+
+	printk(KERN_DEBUG"-- %s -- %p, icmp: 0x%x\n", msg, (char *)data + 0x14, (ptr_to_u32(data, 0x14) & 0xff));
+	if ((ptr_to_u32(data, 0x14) & 0xff) == 0x01) {// protocol icmp 0x01
+		printk(KERN_INFO"ICMP ");
+		if (((ptr_to_u32(data, 0x20) >> 8) & 0xff) == 0x8) //icmp type
+			printk(KERN_INFO"ping echo request, ");
+		else if (((ptr_to_u32(data, 0x20) >> 8) & 0xff) == 0x0)
+			printk(KERN_INFO"ping echo reply, ");
+		else
+			printk(KERN_INFO"not ping echo request or reply, ");
+		printk(KERN_INFO"sequence number: %u\n", ptr_to_u32(data, 0x28) >> 16);
+	} else {
+		printk(KERN_INFO"not a ICMP packet\n");
+	}
+}
+
+static void print_mac_address(const char *mac)
+{
+    int i;
+    for (i = 0; i < ETH_MAC_LEN - 1; i++) {
+        printk(KERN_DEBUG"%s %02x-", __func__,(unsigned int)mac[i] & 0xFF);
+    }
+    printk(KERN_DEBUG"%s %02x\n", __func__, (unsigned int)mac[i] & 0xFF);
+    return;
+}
+
+static int ctox(int c)
+{
+	int tmp;
+
+	if (!isxdigit(c)) {
+		printk(KERN_ERR"'%c' is not hex digit\n", (char)c);
+		return -1;
+	}
+
+	if ((c >= '0') && (c <= '9'))
+		tmp = c - '0';
+	else
+		tmp = (c | 0x20) - 'a' + 10;
+
+	return tmp;
+}
+
+static int parse_mac_address(const char *mac, int len)
+{
+	int tmp, tmp2;
+	int i = 0;
+	int j = 0;
+	char s[16] = "";
+	int c;
+
+	printk(KERN_DEBUG"ethernet mac address string: %s, len: %d\n", mac, strlen(mac));
+	if (17 == len) {
+		if (strlen(mac) > 17) {
+			printk(KERN_ERR"ethernet mac address string too long\n");
+			return -1;
+		}
+		while ((c = mac[i++]) != '\0') {
+			if (c == ':')
+				continue;
+			s[j++] = c;
+		}
+		s[j] = '\0';
+		printk(KERN_DEBUG"mac address string stripped colon: %s\n", s);
+	} else if (12 == len) {
+		if (strlen(mac) > 12) {
+			printk(KERN_ERR"ethernet mac address string too long\n");
+			return -1;
+		}
+		memcpy(s, mac, 12);
+		s[12] = '\0';
+	} else {
+		printk(KERN_ERR"length of ethernet mac address is not 12 or 17\n");
+		return -1;
+	}
+
+	for (i = 0; i < ETH_MAC_LEN; i++) {
+		tmp = ctox(s[i * 2]);
+		tmp2 = ctox(s[i * 2 + 1]);
+		tmp = (tmp * 16) + tmp2;
+		*(char *)(g_default_mac_addr + i) = tmp & 0xFF;
+	}
+
+	return 0;
+}
+
+static int read_mac_address(struct file *filp, char *mac, int *len)
+{
+	loff_t l;
+	loff_t offset = 0;
+	mm_segment_t fs;
+	int _len, i;
+
+	l = vfs_llseek(filp, 0, SEEK_END);
+	offset = vfs_llseek(filp, 0, SEEK_SET);
+	printk(KERN_INFO"%s file's actual len: %d\n", __func__,(int)l);
+	if (l >= 17) {
+		_len = 17;
+	} else if (l >= 12) {
+		_len = 12;
+	} else {
+		printk(KERN_ERR"mac address is too short\n");
+		return -1;
+	}
+	printk(KERN_INFO"%s file's len to be read: %d\n", __func__, _len);
+
+	fs = get_fs();
+	set_fs(get_ds());
+
+	l = vfs_read(filp, (char __user *)mac, (size_t)_len, &offset);
+	set_fs(fs);
+	printk(KERN_INFO"%s mac string len actually read: %d\n", __func__,(int)l);
+	if (l > 12) {
+		if ((mac[2] == ':') && (mac[5] == ':'))
+			_len = 17;
+		else
+			_len = 12;
+	} else if (12 == l) {
+		_len = 12;
+	} else {
+		printk(KERN_ERR"ethernet mac address not valid: %s\n", mac);
+		return -1;
+	}
+
+	*len = _len;
+	mac[_len] = '\0';
+	printk(KERN_INFO"%s ethernet mac address read from file: %s, len: %d\n", __func__, mac, _len);
+	for (i = 0; i < _len; i++) {
+		if (!isxdigit(mac[i]) && ':' != mac[i]) {
+			printk(KERN_ERR"mac address has invalid char: %c\n", mac[i]);
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
+static void get_mac_address_by_chip(unsigned char input[MBEDTLS_DES_KEY_SIZE],char *mac_address)
+{
+	unsigned char mac_array[ETH_MAC_LEN] = {0xF4,0x4E,0xFD,0,0,0};
+
+	mac_array[3] = input[0];
+	mac_array[4] = input[4];
+	mac_array[5] = input[7];
+
+	memcpy(mac_address,mac_array,ETH_MAC_LEN);
+	return;
+}
+
+extern int read_mi_item(char *name, void *buf, unsigned int count);
+
+/*
+* get_def_mac_addr:get the mac address,the priority as following:
+* 1.the mac address in the miscinfo;
+* 2.the ramdom address,need to enable in the dts;
+* 3.the local address,need to set this value in the dts;
+* 4.generate the mac address according to the serial number.
+*/
+static const char *get_def_mac_addr(struct platform_device *pdev)
+{
+    struct device_node *np = pdev->dev.of_node;
+    struct file *filp;
+    loff_t offset = 0;
+    char def_mac[20] = "";
+    const char *str;
+    mm_segment_t fs;
+    int len;
+    int ret;
+    unsigned long long system_serial = (unsigned long long)system_serial_low | ((unsigned long long)system_serial_high << 32);
+    mbedtls_des_context ctx;
+    unsigned char key_buff[MBEDTLS_DES_KEY_SIZE] = {1,4,13,21,59,67,69,127};
+    unsigned char input_value[MBEDTLS_DES_KEY_SIZE] = {0};
+    unsigned char output_value[MBEDTLS_DES_KEY_SIZE] = {0};
+
+//#define ETH_MAC_ADDR_BURNED_PATH "/sys/miscinfo/infos/ethmac"
+//#define ETH_MAC_ADDR_BURNED_PATH "/data/mac_address"
+#define ETH_MAC_ADDR_PATH "/config/mac_address.bin"
+#ifdef CONFIG_PLATFORM_UBUNTU
+#define ETH_MAC_ADDR_RANDDOM_PATH "/etc/mac_address_random"
+#else
+#define ETH_MAC_ADDR_RANDDOM_PATH "/data/mac_address_random"
+#endif
+
+    /*filp = filp_open(ETH_MAC_ADDR_BURNED_PATH, O_RDONLY, 0);
+    if (IS_ERR_OR_NULL(filp)) {
+        printk(KERN_ERR"file %s can't be opened\n", ETH_MAC_ADDR_BURNED_PATH);
+    } else {
+        if (!read_mac_address(filp, def_mac, &len)) {
+            parse_mac_address(def_mac, len);
+            printk(KERN_INFO"use burned mac address: ");
+            print_mac_address(g_default_mac_addr);
+            filp_close(filp, current->files);
+            return g_default_mac_addr;
+        }
+        filp_close(filp, current->files);
+    }*/
+    ret = read_mi_item("ETHMAC",def_mac,20);
+    if(ret > 0){
+        printk(KERN_DEBUG"Using the mac address in miscinfo.\n");
+        parse_mac_address(def_mac, ret);
+        return g_default_mac_addr;
+    }
+
+    ret = of_property_read_string(np, "random-mac-address", &str);
+    if (ret) {
+        printk(KERN_ERR"no random-mac-address in dts\n");
+    } else {
+        printk(KERN_INFO"random-mac-address: %s\n", str);
+        if (!strcmp("okay", str))
+            goto random_mac;
+    }
+
+    str = of_get_property(np, "local-mac-address", NULL);
+    if (str == NULL) {
+        printk(KERN_ERR"no local-mac-address in dts\n");
+    } else {
+        printk(KERN_INFO"local-mac-address: ");
+        print_mac_address(str);
+        memcpy(g_default_mac_addr, str, ETH_MAC_LEN);
+        return g_default_mac_addr;
+    }
+
+    //printk(KERN_DEBUG"%s 0x%llx\n",__func__,system_serial);
+    mbedtls_des_init(&ctx);
+    //printk(KERN_DEBUG"key_buff:0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n",key_buff[0],key_buff[1],key_buff[2],key_buff[3],key_buff[4],key_buff[5],key_buff[6],key_buff[7]);
+    if(mbedtls_des_key_check_key_parity(key_buff)){
+        mbedtls_des_key_set_parity(key_buff);
+    }
+    mbedtls_des_setkey_enc(&ctx,key_buff);
+    memcpy(input_value,&system_serial,MBEDTLS_DES_KEY_SIZE);
+    //printk(KERN_DEBUG"input_value:0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n",input_value[0],input_value[1],input_value[2],input_value[3],input_value[4],input_value[5],input_value[6],input_value[7]);
+    mbedtls_des_crypt_ecb(&ctx,input_value,output_value);
+    //printk(KERN_DEBUG"output_value:0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n",output_value[0],output_value[1],output_value[2],output_value[3],output_value[4],output_value[5],output_value[6],output_value[7]);
+    get_mac_address_by_chip(output_value,g_default_mac_addr);
+
+    printk(KERN_DEBUG"use the mac address by chip\n");
+    print_mac_address(g_default_mac_addr);
+    return g_default_mac_addr;
+
+random_mac:
+    filp = filp_open(ETH_MAC_ADDR_PATH, O_RDONLY, 0);
+    if (IS_ERR_OR_NULL(filp)) {
+        printk(KERN_ERR"file %s can't be opened\n", ETH_MAC_ADDR_PATH);
+    } else {
+        if (!read_mac_address(filp, def_mac, &len)) {
+            parse_mac_address(def_mac, len);
+            printk(KERN_INFO"use mac stored in file: ");
+            print_mac_address(g_default_mac_addr);
+            filp_close(filp, current->files);
+            return g_default_mac_addr;
+        }
+        filp_close(filp, current->files);
+    }
+
+    get_random_bytes(def_mac, ETH_MAC_LEN);
+    memcpy(g_default_mac_addr + 3, def_mac + 3, ETH_MAC_LEN - 3);
+
+    fs = get_fs();
+    set_fs(get_ds());
+
+    filp = filp_open(ETH_MAC_ADDR_RANDDOM_PATH, O_RDONLY, 0);
+    if (IS_ERR_OR_NULL(filp)) {
+        filp = filp_open(ETH_MAC_ADDR_RANDDOM_PATH, O_WRONLY | O_CREAT, 0640);
+        if (!IS_ERR_OR_NULL(filp)) {
+            printk(KERN_INFO"use random mac generated: ");
+            print_mac_address(g_default_mac_addr);
+            vfs_write(filp, (char __user *)g_default_mac_addr, ETH_MAC_LEN, &offset);
+            filp_close(filp, current->files);
+        }
+    } else {
+        if (vfs_read(filp, (char __user *)def_mac, ETH_MAC_LEN, &offset)
+            == ETH_MAC_LEN) {
+            memcpy(g_default_mac_addr, def_mac, ETH_MAC_LEN);
+            printk(KERN_INFO"use random mac stored: ");
+            print_mac_address(g_default_mac_addr);
+        }
+        filp_close(filp, current->files);
+    }
+
+    set_fs(fs);
+
+    return g_default_mac_addr;
+}
+
+static void print_frame_data(void *frame, int len)
+{
+    int i;
+    unsigned char *tmp = (unsigned char *)frame;
+
+    for (i = 0; i < len; i++) {
+        printk(KERN_DEBUG"%s %02x ", __func__, (unsigned int)(*tmp));
+        if (0xF == (i & 0xF)) {
+            printk(KERN_DEBUG"\n");
+        }
+        tmp++;
+    }
+    printk(KERN_DEBUG"\n");
+}
+
+static void print_tx_bds(ec_priv_t * priv)
+{
+    int     i;
+    ec_bd_t *tx_bds = priv->tx_bd_base;
+    volatile ec_bd_t *buf;
+
+    printk(KERN_DEBUG"---- tx ring status ----\n");
+    printk(KERN_DEBUG"tx_bd_base = 0x%p, tx_full = %u\n", priv->tx_bd_base, (unsigned)priv->tx_full);
+    printk(KERN_DEBUG"cur_tx = 0x%p, skb_cur = %u\n", priv->cur_tx, (unsigned)priv->skb_cur);
+    printk(KERN_DEBUG"dirty_tx = 0x%p, skb_dirty = %u\n", priv->dirty_tx, (unsigned)priv->skb_dirty);
+
+    printk(KERN_DEBUG"---- tx bds ----\n");
+    printk(KERN_DEBUG"     status\t control\t buf addr\n");
+
+    for (i = 0; i < TX_RING_SIZE; i++) {
+        buf = &tx_bds[i];
+        printk(KERN_DEBUG"%03d: 0x%08x\t 0x%08x\t 0x%08x\n", i, (unsigned int) buf->status,(unsigned int) buf->control, (unsigned int) buf->buf_addr);
+    }
+}
+
+void print_phy_register(ec_priv_t *ecp)
+{
+	printk(KERN_DEBUG"phy MII_BMCR: 0x%x\n", (uint)read_phy_reg(ecp, MII_BMCR));
+	printk(KERN_DEBUG"phy MII_BMSR: 0x%x\n", (uint)read_phy_reg(ecp, MII_BMSR));
+	printk(KERN_DEBUG"phy MII_PHYSID1: 0x%x\n", (uint)read_phy_reg(ecp, MII_PHYSID1));
+	printk(KERN_DEBUG"phy MII_PHYSID2: 0x%x\n", (uint)read_phy_reg(ecp, MII_PHYSID2));
+	printk(KERN_DEBUG"phy MII_ADVERTISE: 0x%x\n", (uint)read_phy_reg(ecp, MII_ADVERTISE));
+	printk(KERN_DEBUG"phy MII_LPA: 0x%x\n", (uint)read_phy_reg(ecp, MII_LPA));
+	printk(KERN_DEBUG"phy MII_CTRL1000: 0x%x\n", (uint)read_phy_reg(ecp, MII_CTRL1000));
+	printk(KERN_DEBUG"phy MII_STAT1000: 0x%x\n", (uint)read_phy_reg(ecp, MII_STAT1000));
+	printk(KERN_DEBUG"phy MII_MMD_CTRL: 0x%x\n", (uint)read_phy_reg(ecp, MII_MMD_CTRL));
+	printk(KERN_DEBUG"phy MII_MMD_DATA: 0x%x\n", (uint)read_phy_reg(ecp, MII_MMD_DATA));
+	printk(KERN_DEBUG"phy MII_ESTATUS: 0x%x\n", (uint)read_phy_reg(ecp, MII_ESTATUS));
+	printk(KERN_DEBUG"phy MII_DCOUNTER: 0x%x\n", (uint)read_phy_reg(ecp, MII_DCOUNTER));
+	printk(KERN_DEBUG"phy MII_FCSCOUNTER: 0x%x\n", (uint)read_phy_reg(ecp, MII_FCSCOUNTER));
+	printk(KERN_DEBUG"phy MII_NWAYTEST: 0x%x\n", (uint)read_phy_reg(ecp, MII_NWAYTEST));
+	printk(KERN_DEBUG"phy MII_RERRCOUNTER: 0x%x\n", (uint)read_phy_reg(ecp, MII_RERRCOUNTER));
+	printk(KERN_DEBUG"phy MII_SREVISION: 0x%x\n", (uint)read_phy_reg(ecp, MII_SREVISION));
+	printk(KERN_DEBUG"phy MII_EXPANSION: 0x%x\n", (uint)read_phy_reg(ecp, MII_EXPANSION));
+	printk(KERN_DEBUG"phy MII_RESV1: 0x%x\n", (uint)read_phy_reg(ecp, MII_RESV1));
+	printk(KERN_DEBUG"phy MII_LBRERROR: 0x%x\n", (uint)read_phy_reg(ecp, MII_LBRERROR));
+	printk(KERN_DEBUG"phy MII_PHYADDR: 0x%x\n", (uint)read_phy_reg(ecp, MII_PHYADDR));
+	printk(KERN_DEBUG"phy MII_RESV2: 0x%x\n", (uint)read_phy_reg(ecp, MII_RESV2));
+	printk(KERN_DEBUG"phy MII_TPISTATUS: 0x%x\n", (uint)read_phy_reg(ecp, MII_TPISTATUS));
+	printk(KERN_DEBUG"phy MII_NCONFIG: 0x%x\n", (uint)read_phy_reg(ecp, MII_NCONFIG));
+}
+
+void print_mac_register(ec_priv_t *ecp)
+{
+    volatile ethregs_t *hw_regs = ecp->hwrp;
+
+	printk(KERN_DEBUG "CMU_DEVCLKEN1:0x%x\n", act_readl(CMU_DEVCLKEN1));
+	printk(KERN_DEBUG "MFP_CTL0:0x%x\n", act_readl(MFP_CTL0));
+	printk(KERN_DEBUG "PAD_DRV0:0x%x\n", act_readl(PAD_DRV0));
+	printk(KERN_DEBUG "PAD_PULLCTL0:0x%x\n", act_readl(PAD_PULLCTL0));
+	printk(KERN_DEBUG "GPIO_AOUTEN:0x%x\n", act_readl(GPIO_AOUTEN));
+	printk(KERN_DEBUG "GPIO_AINEN:0x%x\n", act_readl(GPIO_AINEN));
+	printk(KERN_DEBUG "GPIO_ADAT:0x%x\n", act_readl(GPIO_ADAT));
+
+    /* CSR0~20 */
+    printk(KERN_DEBUG "MAC_CSR0:0x%08lx, address:%p\n", hw_regs->er_busmode, &hw_regs->er_busmode);
+    printk(KERN_DEBUG "MAC_CSR1:0x%08lx, address:%p\n", hw_regs->er_txpoll, &hw_regs->er_txpoll);
+    printk(KERN_DEBUG "MAC_CSR2:0x%08lx, address:%p\n", hw_regs->er_rxpoll, &hw_regs->er_rxpoll);
+    printk(KERN_DEBUG "MAC_CSR3:0x%08lx, address:%p\n", hw_regs->er_rxbdbase, &hw_regs->er_rxbdbase);
+    printk(KERN_DEBUG "MAC_CSR4:0x%08lx, address:%p\n", hw_regs->er_txbdbase, &hw_regs->er_txbdbase);
+    printk(KERN_DEBUG "MAC_CSR5:0x%08lx, address:%p\n", hw_regs->er_status, &hw_regs->er_status);
+    printk(KERN_DEBUG "MAC_CSR6:0x%08lx, address:%p\n", hw_regs->er_opmode, &hw_regs->er_opmode);
+    printk(KERN_DEBUG "MAC_CSR7:0x%08lx, address:%p\n", hw_regs->er_ienable, &hw_regs->er_ienable);
+    printk(KERN_DEBUG "MAC_CSR8:0x%08lx, address:%p\n", hw_regs->er_mfocnt, &hw_regs->er_mfocnt);
+    printk(KERN_DEBUG "MAC_CSR9:0x%08lx, address:%p\n", hw_regs->er_miimng, &hw_regs->er_miimng);
+    printk(KERN_DEBUG "MAC_CSR10:0x%08lx, address:%p\n", hw_regs->er_miism, &hw_regs->er_miism);
+    printk(KERN_DEBUG "MAC_CSR11:0x%08lx, address:%p\n", hw_regs->er_imctrl, &hw_regs->er_imctrl);
+    printk(KERN_DEBUG "MAC_CSR16:0x%08lx, address:%p\n", hw_regs->er_maclow, &hw_regs->er_maclow);
+    printk(KERN_DEBUG "MAC_CSR17:0x%08lx, address:%p\n", hw_regs->er_machigh, &hw_regs->er_machigh);
+    printk(KERN_DEBUG "MAC_CSR18:0x%08lx, address:%p\n", hw_regs->er_cachethr, &hw_regs->er_cachethr);
+    printk(KERN_DEBUG "MAC_CSR19:0x%08lx, address:%p\n", hw_regs->er_fifothr, &hw_regs->er_fifothr);
+    printk(KERN_DEBUG "MAC_CSR20:0x%08lx, address:%p\n", hw_regs->er_flowctrl, &hw_regs->er_flowctrl);
+
+    printk(KERN_DEBUG "MAC_CTRL: 0x%x:0x%x\n", MAC_CTRL, act_readl(MAC_CTRL));
+    return;
+}
+
+/*----------------------------------- mii hooks -------------------------------*/
+
+/**
+ * ec_mdio_read -  hook for struct mii_if_info{.mdio_read}
+ */
+static int ec_mdio_read(struct net_device *dev, int phy_addr, int reg_addr)
+{
+    ec_priv_t *ecp = netdev_priv(dev);
+    printk(KERN_DEBUG"read phy reg-%x\n", reg_addr);
+    return (read_phy_reg(ecp, reg_addr));
+}
+
+
+/**
+ * ec_mdio_write -  hook for struct mii_if_info{.mdio_write}
+ */
+static void ec_mdio_write(struct net_device *dev, int phy_addr, int reg_addr, int val)
+{
+    ec_priv_t *ecp = netdev_priv(dev);
+    write_phy_reg(ecp, reg_addr, val);
+    printk(KERN_DEBUG"write phy reg-%x, value-%x\n", reg_addr, val);
+}
+
+
+/*---------------------------------- MAC routines -----------------------------*/
+
+static inline void raw_tx_bd_init(ec_priv_t * ecp)
+{
+    int     i;
+    volatile ec_bd_t *tx_bds = ecp->tx_bd_base;
+
+    for (i = 0; i < TX_RING_SIZE; i++) {
+        tx_bds[i] = (ec_bd_t) {
+            .status = 0,        /* host own it */
+            .control = TXBD_CTRL_IC,
+            .buf_addr = 0,
+            .reserved = 0
+        };
+    }
+    tx_bds[i - 1].control |= TXBD_CTRL_TER;
+
+    return;
+}
+
+
+static inline void raw_rx_bd_init(ec_priv_t * ecp)
+{
+    int     i;
+    volatile ec_bd_t *rx_bds = ecp->rx_bd_base;
+
+    for (i = 0; i < RX_RING_SIZE; i++) {
+        rx_bds[i] = (ec_bd_t) {
+            .status = RXBD_STAT_OWN,
+            .control = RXBD_CTRL_RBS1(PKG_MAX_LEN),
+            .buf_addr = 0,
+            .reserved = 0
+        };
+    }
+    rx_bds[i - 1].control |= RXBD_CTRL_RER;
+
+    return;
+}
+
+
+/**
+ * get_skb_aligned - get a skb which the address of skb->data is 4B aligned
+ */
+static struct sk_buff *get_skb_aligned(unsigned int len)
+{
+    int     offset;
+    struct sk_buff *skb = NULL;
+
+    if (NULL == (skb = dev_alloc_skb(len))) {
+        return (NULL);
+    }
+    
+    offset = (unsigned long) skb->data & EC_SKB_ALIGN_BITS_MASK;
+    if (unlikely(offset)) {
+        skb_reserve(skb, EC_SKB_ALIGNED - offset);
+    }
+
+    return (skb);
+}
+
+
+static inline void free_rxtx_skbs(struct sk_buff **array, int len)
+{
+    int     i;
+
+    for (i = 0; i < len; i++) {
+        if (NULL != array[i]) {
+            dev_kfree_skb_any(array[i]);
+            array[i] = NULL;
+        }
+    }
+    return;
+}
+
+
+/**
+ * prepare_tx_bd -- preparation for tx buffer descripters
+ *
+ * always success
+ */
+static inline int prepare_tx_bd(ec_priv_t * ecp)
+{
+
+    volatile ec_bd_t *tx_bds_head = ecp->tx_bd_base;
+
+    ecp->cur_tx = (ec_bd_t *)tx_bds_head;
+    ecp->dirty_tx = (ec_bd_t *)tx_bds_head;
+    ecp->skb_cur = 0;
+    ecp->skb_dirty = 0;
+    ecp->tx_full = false;
+
+    free_rxtx_skbs(ecp->tx_skb, TX_RING_SIZE);
+    raw_tx_bd_init(ecp);
+
+    return (0);
+}
+
+
+/**
+ * prepare_rx_bd -- preparation for rx buffer descripters
+ *
+ * return 0 if success, return -1 if fail
+ */
+static int prepare_rx_bd(ec_priv_t * ecp)
+{
+    int     i;
+    struct sk_buff *skb = NULL;
+    volatile ec_bd_t *rx_bds_head = ecp->rx_bd_base;
+
+    //printk(KERN_DEBUG"ecp->rx_bd_base: %p\n", ecp->rx_bd_base);
+    ecp->cur_rx = (ec_bd_t *)rx_bds_head;
+    raw_rx_bd_init(ecp);
+
+    free_rxtx_skbs(ecp->rx_skb, RX_RING_SIZE);
+    
+    for (i = 0; i < RX_RING_SIZE; i++) {
+        if ((skb = get_skb_aligned(PKG_MAX_LEN))) {
+            ecp->rx_skb[i] = skb; 
+            /* should be 4-B aligned */
+            rx_bds_head[i].buf_addr = dma_map_single(&ecp->netdev->dev,
+                    skb->data, PKG_MAX_LEN, DMA_FROM_DEVICE);
+            //printk("rx_bds_head[%d].buf_addr:0x%lx\n", i, rx_bds_head[i].buf_addr);
+        } else {
+            printk(KERN_ERR"can't alloc skb\n");
+            free_rxtx_skbs(ecp->rx_skb, i);
+            raw_rx_bd_init(ecp);
+            return (-1);
+        }
+    }
+    //printk(KERN_DEBUG"ecp->cur_rx: %p\n", ecp->cur_rx);
+
+    return (0);
+}
+
+
+/* suitable for less than 7 chars of string */
+static inline int string_to_hex(char *str, int len)
+{
+    int     val;
+    int     i;
+    char    ch;
+
+    val = 0;
+    for (i = 0; i < len; i++) {
+        ch = str[i];
+        if ('0' <= ch && ch <= '9') {
+            val = (val << 4) + ch - '0';
+        } else if ('a' <= ch && ch <= 'f') {
+            val = (val << 4) + 10 + ch - 'a';
+        } else if ('A' <= ch && ch <= 'F') {
+            val = (val << 4) + 10 + ch - 'A';
+        } else {
+            return (-1);
+        }
+    }
+
+    return (val);
+}
+
+
+/**
+ * parse_mac_addr -- parse string of mac address to number mac address
+ *
+ * return 0 if success, negative value if fail
+ */
+static inline int parse_mac_addr(ec_priv_t * ecp, char *mac)
+{
+    int     i;
+    int     j;
+    int     result;
+    
+    /* string of mac - such as "01:02:03:04:05:06" */
+    if (17 != strlen(mac)) {
+        return (-1);
+    }
+
+    for (i = 0, j = 2; i < 5; i++, j += 3) {
+        if (':' != mac[j]) {
+            return (-1);
+        }
+    }
+
+    for (i = 0, j = 0; i < 6; i++, j += 3) {
+        result = string_to_hex(mac + j, 2);
+        if (-1 != result) {
+            ecp->overrided_mac[i] = (char) result;
+        } else {
+            return (result);
+        }
+    }
+
+    return (0);
+}
+
+
+static inline void fill_macaddr_regs(ec_priv_t * ecp, const char *mac_addr)
+{
+    volatile ethregs_t *hw_regs = ecp->hwrp;
+
+    hw_regs->er_maclow = *(unsigned long *) mac_addr;
+    hw_regs->er_machigh = *(unsigned short *) (mac_addr + 4);
+    return;
+}
+
+
+static inline void set_mac_addr(ec_priv_t * ecp)
+{
+    if (ecp->mac_addr) {
+        fill_macaddr_regs(ecp, ecp->mac_addr);
+        return;
+    }
+    
+    if ('?' != macaddr[0]) {
+        if ((0 == parse_mac_addr(ecp, macaddr)) && 
+		ether_addr_equal(macaddr, g_default_mac_addr)) {
+
+            fill_macaddr_regs(ecp, ecp->overrided_mac);
+            ecp->mac_addr = ecp->overrided_mac;
+            ecp->mac_overrided = true;
+            return;
+        }
+    }
+
+    fill_macaddr_regs(ecp, g_default_mac_addr);
+    ecp->mac_addr = g_default_mac_addr;
+    ecp->mac_overrided = false;
+    return;
+}
+
+
+/* NOTE: it has side effect for dest parameter */
+#define COPY_MAC_ADDR(dest, mac)  do {\
+    *(unsigned short *)(dest) = *(unsigned short *)(mac); \
+    *(unsigned short *)((dest) + 4) = *(unsigned short *)((mac) + 2); \
+    *(unsigned short *)((dest) + 8) = *(unsigned short *)((mac) + 4); \
+    (dest) += 12; \
+}while (0)
+
+
+/**
+ * build_setup_frame -- build setup-frame of mac address filter  in @buffer
+ *
+ * @buf_len should be longer than or equal  SETUP_FRAME_LEN (192 bytes), but we only 
+ * use SETUP_FRAME_LEN bytes exactly.
+ *
+ * return the address of @buffer if success, or NULL if not
+ */
+static char *build_setup_frame(ec_priv_t * ecp, char *buffer, int buf_len)
+{
+    char    broadcast_mac[ETH_MAC_LEN] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
+    char   *frame = buffer;
+    char   *mac;
+
+    if (NULL == buffer || buf_len < SETUP_FRAME_LEN) {
+        printk(KERN_ERR"error parameters\n");
+        return (NULL);
+    }
+
+    memset(frame, 0, SETUP_FRAME_LEN);
+
+    mac = (char *) ecp->mac_addr;
+    COPY_MAC_ADDR(frame, mac);
+    
+    mac = broadcast_mac;
+    COPY_MAC_ADDR(frame, mac);
+
+    /* fill multicast addresses */
+    if (!ecp->all_multicast && ecp->multicast) {
+        int     i;
+        int     count = ecp->multicast_list.count;
+
+        if (count > MULTICAST_LIST_LEN) {
+            count = MULTICAST_LIST_LEN;
+        }
+
+        for (i = 0; i < count; i++) {
+            mac = ecp->multicast_list.mac_array[i];
+            COPY_MAC_ADDR(frame, mac);
+        }
+    }
+
+    if (ecp->msg_enable) {
+        INFO_GREEN("overrided : %s -- multicast : %s\n",
+            ecp->mac_overrided ? "true" : "false",
+            ecp->multicast ? "true" : "false");
+    }
+
+    return (buffer);
+}
+
+
+/**
+ * transmit_setup_frame -- transmit setup-frame of  mac address filter
+ *
+ * the function is not thread-safety, thus in multithread envirement should hold ec_prive_t{.lock}.
+ * and before call it, ec_prive_t{.mac_addr} should point to a suitalbe mac address used
+ *
+ * MAC will raise CSR5.ETI interrupt after transmission of setup-frame, so we use uniform 
+ * manner  to deal with it.
+ *
+ * return 0 if success, -1 if fail
+ */
+static int transmit_setup_frame(ec_priv_t *ecp)
+{
+    struct sk_buff *skb = NULL;
+    volatile ec_bd_t *buf_des = ecp->cur_tx;
+
+    if (ecp->tx_full) {
+        /* may happen when change macs if not in open ethdev  */
+        printk(KERN_ERR"error : tx buffer is full.\n");
+        return (-1);
+    }
+    
+    /* will build a setup-frame in a skb */
+    skb = get_skb_aligned(SETUP_FRAME_RESV_LEN);
+    if (NULL == skb) {
+        printk(KERN_ERR"error : no memory for setup frame.\n");
+        return (-1);
+    }
+
+    skb_put(skb, SETUP_FRAME_LEN);
+
+    /* address of skb->data should be 4-bytes aligned */
+    if (NULL == build_setup_frame(ecp, skb->data, SETUP_FRAME_LEN)) {
+        printk(KERN_ERR"error : building of setup-frame failed.\n");
+        dev_kfree_skb_any(skb);
+        return (-1);
+    }
+
+    /* send it out as normal packet */
+    ecp->tx_skb[ecp->skb_cur] = skb;
+    ecp->skb_cur = (ecp->skb_cur + 1) & TX_RING_MOD_MASK;
+
+    /*
+     * Push the data cache so the NIC does not get stale memory data.
+     */
+    buf_des->buf_addr = dma_map_single(&ecp->netdev->dev, skb->data, PKG_MAX_LEN, DMA_TO_DEVICE);
+
+    buf_des->control &= (TXBD_CTRL_TER | TXBD_CTRL_IC); /* maintain these bits */
+    buf_des->control |= TXBD_CTRL_SET;
+    buf_des->control |= TXBD_CTRL_TBS1(SETUP_FRAME_LEN);
+    mb();
+    buf_des->status = TXBD_STAT_OWN;
+    mb();
+
+    /* when call the routine, TX and Rx should have already stopped */
+    ecp->hwrp->er_opmode |= EC_OPMODE_ST;
+    ecp->hwrp->er_txpoll = EC_TXPOLL_ST;  
+
+    if (buf_des->control & TXBD_CTRL_TER)
+        ecp->cur_tx = ecp->tx_bd_base;
+    else
+        ecp->cur_tx++;
+    
+    if (ecp->cur_tx == ecp->dirty_tx) {
+        ecp->tx_full = true;
+        netif_stop_queue(ecp->netdev);
+    }
+
+    /* resume old status */    
+    ecp->hwrp->er_opmode &= ~EC_OPMODE_ST;  
+	netif_stop_queue(ecp->netdev);
+    //printk(KERN_DEBUG"The end of transmit_setup_frame\n");
+    return (0);
+}
+
+
+/**
+  * when reconfigrate mac's mode, should stop tx and rx first.  so before call the following 
+  * tow function, make sure tx and rx have stopped
+ */
+static inline void set_mode_promisc(ec_priv_t * ecp, bool supported)
+{
+    volatile ethregs_t *hw_regs = ecp->hwrp;
+
+    ecp->promiscuous = supported;
+    if (supported) {
+        hw_regs->er_opmode |= EC_OPMODE_PR;
+        EC_NOP;
+    } else {
+        hw_regs->er_opmode &= ~EC_OPMODE_PR;
+        EC_NOP;
+    }
+    return;
+}
+
+static inline void set_mode_all_multicast(ec_priv_t * ecp, bool supported)
+{
+    volatile ethregs_t *hw_regs = ecp->hwrp;
+
+    ecp->all_multicast = supported;
+    if (supported)
+        hw_regs->er_opmode |= EC_OPMODE_PM;
+    else
+        hw_regs->er_opmode &= ~EC_OPMODE_PM;
+
+    return;
+}
+
+#if 0
+static void mac_rmii_get_pin(void)
+{
+    unsigned long mfp_ctl0;
+	unsigned long pad_drive;
+    unsigned long pad_pull_ctl0;
+	unsigned long mac_ctl_temp;
+	
+	//pad enable
+    act_writel(0x2, PAD_CTL);
+        
+	/*mac mfp config*/
+    mfp_ctl0 = act_readl(MFP_CTL0);
+    mfp_ctl0 &= 0xfff8003f;        // RMII pin
+    mfp_ctl0 |= 0x00000000;
+    act_writel(mfp_ctl0, MFP_CTL0);
+
+    mac_ctl_temp = act_readl(MAC_CTRL);
+	act_writel(mac_ctl_temp | 0x1<<1, MAC_CTRL);	// use RMII
+	
+    /*mac rmii pad drive - level2*/
+	pad_drive = act_readl(PAD_DRV0);
+    pad_drive &= ~0x00ffc000;
+	pad_drive |= 0x00554000;
+	act_writel(pad_drive, PAD_DRV0);
+
+	/*mac rmii pad drive - pad pull ctl*/
+	pad_pull_ctl0 = act_readl(PAD_PULLCTL0);
+    pad_pull_ctl0 &= ~0x00010000;
+	pad_pull_ctl0 |= 0x0;
+	act_writel(pad_pull_ctl0, PAD_PULLCTL0);
+}
+
+static int get_pin_count = 0;
+
+static int hw_rmii_get_pin(void) {
+	int result = 0;
+
+	get_pin_count++;
+	//printk("get_pin_count:%d\n", get_pin_count);
+	if (get_pin_count > 1) {
+		return 0;
+	}
+	
+	result = asoc_mfp_lock(MOD_ID_ETHERNET, MFP_OPT_CAN_SLEEP, NULL);
+	return result;
+}
+
+static int hw_rmii_release_pin(void) {
+	int result = 0;
+
+	get_pin_count--;
+	//printk("get_pin_count:%d\n", get_pin_count);
+	if (get_pin_count < 0) {
+		get_pin_count = 0;
+		return 0;
+	}
+
+	result = asoc_mfp_unlock(MOD_ID_ETHERNET, MFP_OPT_CAN_SLEEP);
+	return result;
+}
+#endif
+
+static void mac_init(ec_priv_t *ecp)
+{
+	volatile ethregs_t *hw_regs = ecp->hwrp;
+
+	//printk(KERN_DEBUG"%s %d\n",__FUNCTION__,__LINE__);
+	/* hardware soft reset, and set bus mode */
+	hw_regs->er_busmode |= EC_BMODE_SWR;
+	do {
+		udelay(10);
+	} while (hw_regs->er_busmode & EC_BMODE_SWR);
+
+	/* select clk input from external phy */
+
+	//printk("before MAC_CTRL: 0x%x\n", (unsigned)getl(MAC_CTRL));
+	putl(getl(MAC_CTRL) &(~(0x1<<1)), MAC_CTRL);
+	//printk("after MAC_CTRL: 0x%x\n", (unsigned)getl(MAC_CTRL));
+
+	hw_regs->er_miism &= 0x0;
+	hw_regs->er_miism |= 0xcc000000;
+	//putl(getl(MAC_CSR10) | 0x40000000, MAC_CSR10);
+	//printk("MAC_CSR10: 0x%x\n", (unsigned)getl(MAC_CSR10));
+	//printk("------------MAC_CSR10:0x%x\n", (unsigned)hw_regs->er_miism);
+
+
+	//printk("----------CMU_DEVCLKEN1:0x%x\n", act_readl(CMU_DEVCLKEN1));
+	//printk("----------CMU_DEVRST1:0x%x\n", act_readl(CMU_DEVRST1));
+	
+	/* for gl5202 fpga test, PBL = 16, 5203 default 16 */
+	//hw_regs->er_busmode |= 0x1000;
+
+	/* physical address */
+	hw_regs->er_txbdbase = ecp->tx_bd_paddr;
+	hw_regs->er_rxbdbase = ecp->rx_bd_paddr;
+	//printk("csr4-txbdbase:0x%x\n", (unsigned)hw_regs->er_txbdbase);
+	//printk("csr3-rxbdbase:0x%x\n", (unsigned)hw_regs->er_rxbdbase);
+
+	/* set flow control mode, force transmitor pause about 100ms */
+	hw_regs->er_cachethr = EC_CACHETHR_CPTL(0x0) | EC_CACHETHR_CRTL(0x0) | EC_CACHETHR_PQT(0x4FFF);
+	hw_regs->er_fifothr = EC_FIFOTHR_FPTL(0x40) | EC_FIFOTHR_FRTL(0x10);//hw_regs->er_fifothr = EC_FIFOTHR_FPTL(0x150) | EC_FIFOTHR_FRTL(0x84);
+	hw_regs->er_flowctrl = EC_FLOWCTRL_ENALL;
+
+	hw_regs->er_opmode |= EC_OPMODE_FD;
+	hw_regs->er_opmode |= EC_OPMODE_SPEED(0); //100M
+	//hw_regs->er_opmode |= EC_OPMODE_SF;  /* start transmit ONLY after whole packet get in tfifo */
+
+    //hw_regs->er_busmode |= EC_BMODE_TAP(0x1);
+    //hw_regs->er_busmode |= EC_BMODE_BAR;
+    //printk(KERN_DEBUG"hw_regs->er_busmode:0x%x\n", (unsigned)hw_regs->er_busmode);
+
+	/* default support PR, here clear it
+	 * XXX: due to MAC constraint, after write a reg, can't read it immediately
+	 * (write of regs has tow beats delay).
+	 */
+	hw_regs->er_opmode &= ~EC_OPMODE_PR;
+	//printk(KERN_DEBUG"hw_regs->er_opmode:0x%x\n", (unsigned)hw_regs->er_opmode);
+
+	
+	//interrupt mitigation control register 
+	hw_regs->er_imctrl = 0x004e0000; //NRP =7,RT =1,CS=0
+
+#if defined(ETHENRET_MAC_LOOP_BACK) || defined(ETHENRET_PHY_LOOP_BACK)
+	hw_regs->er_opmode |= EC_OPMODE_RA;
+#endif
+
+#ifdef ETHENRET_MAC_LOOP_BACK
+	/* mac internal loopback */
+	hw_regs->er_opmode |= EC_OPMODE_LP;
+	printk(KERN_DEBUG"MAC operation mode: 0x%x\n", (unsigned)hw_regs->er_opmode);
+#endif
+	//hw_regs->er_ienable = EC_IEN_ALL;   //all interrupt enable
+}
+
+static int _init_hardware(ec_priv_t *ecp,int clk_reset,int phy_reset)
+{
+	ethernet_clock_enable(clk_reset);
+
+	/* ATC2605 ONLY support output 50MHz RMII_REF_CLK to MAC, so phy hw init first */
+	if (ecp->phy_ops->phy_hw_init)
+		ecp->phy_ops->phy_hw_init(ecp);
+	//printk(KERN_DEBUG"%s %d\n",__FUNCTION__,__LINE__);
+	mac_init(ecp);
+	//print_mac_register(ecp);
+
+	if(phy_reset){
+		if ((ecp->phy_power_gpio.gpio > 0) && gpio_is_valid(ecp->phy_power_gpio.gpio)) { 
+			gpio_direction_output(ecp->phy_power_gpio.gpio, !ecp->phy_power_gpio.active);
+		}	
+		if ((ecp->phy_reset_gpio.gpio>0) && gpio_is_valid(ecp->phy_reset_gpio.gpio)){		        
+			gpio_direction_output(ecp->phy_reset_gpio.gpio, ecp->phy_reset_gpio.active);	
+			mdelay(10);        
+			gpio_direction_output(ecp->phy_reset_gpio.gpio, !ecp->phy_reset_gpio.active);		
+		}
+		mdelay(20);
+	}
+	/**********TEST FOR TAIWAN START******/
+	#if 0
+	putl(getl(GPIO_AOUTEN) | (0x1 << 22), GPIO_AOUTEN);
+    printk("%s %d gpioen:0x%x\n",__FUNCTION__,__LINE__,getl(GPIO_COUTEN));
+	putl(getl(GPIO_ADAT) & (0x0 << 22), GPIO_ADAT);
+	printk("%s %d gpio:0x%x\n",__FUNCTION__,__LINE__,getl(GPIO_CDAT));
+    mdelay(150);
+	putl(getl(GPIO_AOUTEN) & (0x0 << 22), GPIO_AOUTEN);
+	#endif//0
+	 /**********TEST FOR TAIWAN end******/
+	set_mac_addr(ecp);
+	//printk(KERN_DEBUG"mac address: ");
+	//print_mac_address(ecp->mac_addr);
+
+	if(phy_reset){
+		if (ecp->phy_ops->phy_init(ecp)) {
+			printk(KERN_ERR"error : initialize PHY fail\n");
+		}
+		//printk(KERN_DEBUG"%s %d\n",__FUNCTION__,__LINE__);
+		//print_phy_register(ecp);
+	}		
+	//mdelay(20);
+	return 0;
+}
+
+static int _deinit_hardware(ec_priv_t *ecp){
+	if (gpio_is_valid(ecp->phy_power_gpio.gpio)) { 
+		gpio_direction_output(ecp->phy_power_gpio.gpio,  ecp->phy_power_gpio.active);
+	}
+	return 0;
+}
+
+#ifdef DETECT_POWER_SAVE
+static void detect_power_save_timer_func(unsigned long data);
+
+static void init_power_save_timer(ec_priv_t *ecp)
+{
+    printk(KERN_DEBUG"%s \n",__func__);
+    init_timer(&ecp->detect_timer);
+    ecp->detect_timer.data = (unsigned long)ecp;
+    ecp->detect_timer.function = detect_power_save_timer_func;
+}
+
+static void start_power_save_timer(ec_priv_t *ecp, const unsigned ms)
+{
+    printk(KERN_DEBUG"%s \n",__func__);
+    mod_timer(&ecp->detect_timer, jiffies + msecs_to_jiffies(ms));
+}
+
+static void stop_power_save_timer(ec_priv_t *ecp)
+{
+    printk(KERN_DEBUG"%s \n", __func__);
+    if (timer_pending(&ecp->detect_timer))
+        del_timer_sync(&ecp->detect_timer);
+
+    cancel_work_sync(&ecp->power_save_work);
+    flush_workqueue(power_save_queue);
+}
+
+static void enable_hardware(ec_priv_t *ecp)
+{
+    unsigned long flags = 0;
+    int temp;
+
+    temp = read_phy_reg(ecp, MII_BMCR);
+    printk(KERN_DEBUG"MII_BMCR: 0x%x\n", (u32)temp);
+    write_phy_reg(ecp, MII_BMCR, temp & ~BMCR_PDOWN);
+    printk(KERN_DEBUG"exit POWER DOWN, MII_BMCR: 0x%x\n", (u32)read_phy_reg(ecp, MII_BMCR));
+
+    spin_lock_irqsave(&ecp->lock, flags);
+    ecp->enable = true;
+    spin_unlock_irqrestore(&ecp->lock, flags);
+}
+
+static void disable_hardware(ec_priv_t *ecp)
+{
+    unsigned long flags = 0;
+    unsigned short phy_int_status;
+    int temp;
+
+    phy_int_status = atc260x_reg_read(ecp->atc260x, atc2603_PHY_INT_STAT);
+    if (phy_int_status & 0x1) {
+        printk(KERN_DEBUG"already linked, not to power down\n");
+        return;
+    }
+
+    spin_lock_irqsave(&ecp->lock, flags);
+    if (ecp->linked) {
+        spin_unlock_irqrestore(&ecp->lock, flags);
+        printk(KERN_DEBUG"already linked, not to power down\n");
+        return;
+    }
+    ecp->enable = false;
+    spin_unlock_irqrestore(&ecp->lock, flags);
+
+    temp = read_phy_reg(ecp, MII_BMCR);
+    printk(KERN_DEBUG"MII_BMCR: 0x%x\n", (u32)temp);
+    write_phy_reg(ecp, MII_BMCR, temp | BMCR_PDOWN);
+    printk(KERN_DEBUG"enter POWER DOWN, MII_BMCR: 0x%x\n", (u32)read_phy_reg(ecp, MII_BMCR));
+}
+
+static void ethernet_power_save(struct work_struct *work)
+{
+    ec_priv_t *ecp = (ec_priv_t *)container_of(work, ec_priv_t, power_save_work);
+    printk(KERN_DEBUG"ecp->enable: %u\n", ecp->enable);
+
+    if (ecp->enable) {
+        disable_hardware(ecp);
+    } else {
+        enable_hardware(ecp);
+    }
+}
+
+static void detect_power_save_timer_func(unsigned long data)
+{
+    ec_priv_t *ecp = (ec_priv_t *)data;
+    unsigned long flags;
+
+    printk(KERN_DEBUG"ecp->enable: %u\n", ecp->enable);
+    if (!ecp->opened) {
+        printk(KERN_ERR"not opened yet\n");
+        return;
+    }
+
+    spin_lock_irqsave(&ecp->lock, flags);
+    if (ecp->linked) {
+        spin_unlock_irqrestore(&ecp->lock, flags);
+        printk(KERN_ERR"not linked yet\n");
+        return;
+    }
+    spin_unlock_irqrestore(&ecp->lock, flags);
+
+    if (ecp->enable) {
+        mod_timer(&ecp->detect_timer, jiffies + msecs_to_jiffies(4000));
+    } else {
+        mod_timer(&ecp->detect_timer, jiffies + msecs_to_jiffies(4000));
+    }
+
+    queue_work(power_save_queue, &ecp->power_save_work);
+}
+#endif /* DETECT_POWER_SAVE */
+
+static void set_phy_according_aneg(ec_priv_t *ecp)
+{
+	unsigned short old_bmcr;
+	//unsigned long phy_ctrl_status;
+
+	old_bmcr = read_phy_reg(ecp, MII_BMCR);
+	printk(KERN_DEBUG"old MII_BMCR: 0x%04x\n", (unsigned)old_bmcr);
+	#if 0
+	if (ecp->phy_model == ETH_PHY_MODEL_ATC2605) {
+		phy_ctrl_status = atc260x_reg_read(ecp->atc260x, atc2603_PHY_CTRL);
+		if (ETH_SPEED_10M == ecp->speed)
+			atc260x_reg_write(ecp->atc260x, atc2603_PHY_CTRL, phy_ctrl_status & 0x1e);
+		else
+			atc260x_reg_write(ecp->atc260x, atc2603_PHY_CTRL, phy_ctrl_status | 0x1);
+
+		printk("atc2603_PHY_CTRL: 0x%04x\n", (unsigned)atc260x_reg_read(ecp->atc260x, atc2603_PHY_CTRL));
+	}
+ 	#endif
+	if (ETH_SPEED_10M == ecp->speed)
+		old_bmcr &= ~BMCR_SPEED100;
+	else
+		old_bmcr |= BMCR_SPEED100;
+
+	if (ETH_DUP_FULL == ecp->duplex)
+		old_bmcr |= BMCR_FULLDPLX;
+	else
+		old_bmcr &= ~BMCR_FULLDPLX;
+
+	write_phy_reg(ecp, MII_BMCR, old_bmcr);
+	printk(KERN_DEBUG"new MII_BMCR: 0x%04x\n", (unsigned)read_phy_reg(ecp, MII_BMCR));
+}
+
+
+
+
+static void set_mac_according_aneg(ec_priv_t *ecp)
+{
+	volatile ethregs_t *hw_regs = ecp->hwrp;
+	unsigned long old_mode;
+
+	printk(KERN_DEBUG "%s\n",__func__);
+	old_mode = hw_regs->er_opmode;
+	printk(KERN_DEBUG"opmode regs old value - 0x%x\n", (int)old_mode);
+
+	hw_regs->er_opmode &= ~(EC_OPMODE_ST | EC_OPMODE_SR);
+
+	if (ETH_SPEED_10M == ecp->speed)
+		old_mode |= EC_OPMODE_10M;
+	else
+		old_mode &= ~EC_OPMODE_10M;
+
+	if (ETH_DUP_FULL == ecp->duplex)
+		old_mode |= EC_OPMODE_FD;
+	else
+		//old_mode &= ~EC_OPMODE_FD;
+		/* always set full duplex to work around for both half/full mode!*/
+		old_mode |= EC_OPMODE_FD;  /* mac bug! */
+
+	/*set phy during mac stopped */
+	set_phy_according_aneg(ecp);
+
+	hw_regs->er_opmode = old_mode;
+	printk(KERN_DEBUG"hw_regs->er_opmode:0x%lx\n", hw_regs->er_opmode);
+}
+
+
+/**
+ * ec_enet_tx -- sub-isr for tx interrupt
+ */
+static void subisr_enet_tx(ec_priv_t *ecp)
+{
+    struct net_device *dev = ecp->netdev;
+    volatile ec_bd_t *bdp;
+    struct sk_buff *skb;
+    unsigned long status;
+
+    spin_lock(&ecp->lock);
+    bdp = ecp->dirty_tx;
+
+    if (0 == ((status = bdp->status) & TXBD_STAT_OWN)) { /* don't enable CSR11 interrupt mitigation */
+#if 0
+	while (0 == ((status = bdp->status) & TXBD_STAT_OWN)) {
+        if (bdp == ecp->cur_tx && !ecp->tx_full) 
+            break;    /* tx queue is empty */
+#endif
+
+        skb = ecp->tx_skb[ecp->skb_dirty];
+        dma_unmap_single(&ecp->netdev->dev, bdp->buf_addr, skb->len, DMA_TO_DEVICE);
+
+        /* check for errors */
+        if (status & TXBD_STAT_ES) {
+            printk(KERN_ERR"tx error status : 0x%x\n", (unsigned int)status);
+            if (netif_msg_tx_err(ecp)) {
+                printk(KERN_INFO"position: %d\n", ecp->dirty_tx - ecp->tx_bd_base);
+                print_tx_bds(ecp);
+            }
+            dev->stats.tx_errors++;
+            if (status & TXBD_STAT_UF) 
+			{
+                dev->stats.tx_fifo_errors++;
+				printk(KERN_INFO"tx error status : 0x%x\n", (unsigned int)status);
+            }
+            if (status & TXBD_STAT_EC) 
+			{
+                dev->stats.tx_aborted_errors++;
+				printk(KERN_INFO"tx error status : 0x%x\n", (unsigned int)status);
+            }
+            if (status & TXBD_STAT_LC) 
+			{
+                dev->stats.tx_window_errors++;
+				printk(KERN_INFO"tx error status : 0x%x\n", (unsigned int)status);
+            }
+            if (status & TXBD_STAT_NC) 
+			{
+                dev->stats.tx_heartbeat_errors++;
+				//the mac ip has such a bug(misinformation)
+				//printk("tx error status : 0x%x\n", (unsigned int)status);
+            }
+            if (status & TXBD_STAT_LO) 
+			{
+                dev->stats.tx_carrier_errors++;
+				printk(KERN_INFO"tx error status : 0x%x\n", (unsigned int)status);
+            }
+        } 
+		else 
+		{
+            dev->stats.tx_packets++;
+        }
+
+        /* some collions occurred, but sent packet ok eventually */
+        if (status & TXBD_STAT_DE) 
+		{
+            dev->stats.collisions++;
+        }
+
+        if (netif_msg_tx_err(ecp)) {
+            check_icmp_sequence(skb->data, __func__);
+            printk(KERN_INFO"bdp->buf_addr:0x%lx\n", bdp->buf_addr);
+            printk(KERN_INFO"tx frame:\n");
+            print_frame_data(skb->data, skb->len);
+        }
+
+        dev_kfree_skb_any(skb);
+
+        ecp->tx_skb[ecp->skb_dirty] = NULL;
+        ecp->skb_dirty = (ecp->skb_dirty + 1) & TX_RING_MOD_MASK;
+
+        if (bdp->control & TXBD_CTRL_TER)
+            bdp = ecp->tx_bd_base;
+        else
+            bdp++;
+
+        if (ecp->tx_full) {
+            printk(KERN_ERR"tx bds available, skb_dirty:%d\n", ecp->skb_dirty);
+            ecp->tx_full = false;
+            if (netif_queue_stopped(dev))
+                netif_wake_queue(dev);
+        }
+        if (netif_queue_stopped(dev))
+	    netif_wake_queue(dev);
+    }
+//	else
+//		printk("tx bds status:0x%x\n", (unsigned int)status);
+#if 1
+    else if (ecp->tx_full) {
+        volatile ec_bd_t *bdp_next;
+
+        /* handle the case that bdp->status own bit not cleared by hw but the interrupt still comes */
+        if (bdp->control & TXBD_CTRL_TER)
+            bdp_next = ecp->tx_bd_base;
+        else
+            bdp_next = bdp + 1;
+
+        while (bdp_next != bdp) {
+            /* when tx full, if we find that some bd(s) has own bit is 0, which
+             * indicates that mac hw has transmitted it but the own bit left not cleared. */
+            if (!(bdp_next->status & TXBD_STAT_OWN)) {
+             printk(KERN_INFO"tx bd own bit not cleared!!!\n");
+
+#ifdef TX_DEBUG
+                print_mac_register(ecp);
+                print_tx_bds(ecp);
+#endif
+                bdp->status &= ~TXBD_STAT_OWN; /* clear own bit */
+                skb = ecp->tx_skb[ecp->skb_dirty];
+                dma_unmap_single(&ecp->netdev->dev, bdp->buf_addr, skb->len, DMA_TO_DEVICE);
+                dev_kfree_skb_any(skb);
+
+                ecp->tx_skb[ecp->skb_dirty] = NULL;
+                ecp->skb_dirty = (ecp->skb_dirty + 1) & TX_RING_MOD_MASK;
+
+                if (bdp->control & TXBD_CTRL_TER)
+                    bdp = ecp->tx_bd_base;
+                else
+                    bdp++;
+
+                ecp->tx_full = false;
+                if (netif_queue_stopped(dev))
+                    netif_wake_queue(dev);
+                break;
+            }
+            if (bdp_next->control & TXBD_CTRL_TER)
+                bdp_next = ecp->tx_bd_base;
+            else
+                bdp_next++;
+        }
+    }
+#endif
+    ecp->dirty_tx = (ec_bd_t *) bdp;
+
+    spin_unlock(&ecp->lock);
+    return;
+}
+
+
+/**
+ * ec_enet_rx -- sub-isr for rx interrupt
+ */
+static void subisr_enet_rx(ec_priv_t *ecp)
+{
+	struct net_device *dev = ecp->netdev;
+	volatile ec_bd_t *bdp;
+	struct sk_buff *new_skb;
+	struct sk_buff *skb_to_upper;
+	unsigned long status;
+	unsigned int  pkt_len;
+	int	index;
+//printk("%s %d\n",__FUNCTION__,__LINE__);
+#define RX_ERROR_CARED \
+	(RXBD_STAT_DE | RXBD_STAT_RF | RXBD_STAT_TL | RXBD_STAT_CS \
+	| RXBD_STAT_DB | RXBD_STAT_CE | RXBD_STAT_ZERO)
+
+	spin_lock(&ecp->lock);
+	BUG_ON(!ecp->opened);
+	bdp = ecp->cur_rx;
+#ifdef RX_DEBUG
+	if (unlikely(netif_msg_rx_err(ecp)))
+		printk(KERN_INFO"bdp: 0x%p\n", bdp);
+#endif
+
+	while (0 == ((status = bdp->status) & RXBD_STAT_OWN)) {
+		//printk("bdp->status:0x%08lx\n", bdp->status);
+		if (!(status & RXBD_STAT_LS))
+			printk(KERN_INFO"not last descriptor of a frame - status: 0x%08x.\n",
+				(unsigned int)status);
+#ifdef RX_DEBUG
+		if (unlikely(netif_msg_rx_err(ecp))) {
+			printk(KERN_INFO"bdp: 0x%p, bdp->status: 0x%08x\n", bdp, (u32)bdp->status);
+			printk(KERN_INFO"status: 0x%08x\n", (u32)status);
+		}
+#endif
+
+		/* check for rx errors. RXBD_STAT_ES includes RXBD_STAT_RE, and
+		* RXBD_STAT_RE always set, coz RE pin of 5201 ether mac is NC to
+		* 5302 ether phy. Don't care it now, it'll be fixed in 5203. */
+		//if (status & (RXBD_STAT_ES | RXBD_STAT_DB))
+		if (status & RX_ERROR_CARED) {
+			printk(KERN_ERR"%d: RX_ERROR status:0x%08lx\n", __LINE__, status);
+			dev->stats.rx_errors++;
+			if (status & RXBD_STAT_TL)
+				dev->stats.rx_length_errors++;
+			if (status & RXBD_STAT_CE)
+				dev->stats.rx_crc_errors++;
+			if (status & (RXBD_STAT_RF | RXBD_STAT_DB))
+				dev->stats.rx_frame_errors++;
+			if (status & RXBD_STAT_ZERO)
+				dev->stats.rx_fifo_errors++;
+			if (status & RXBD_STAT_DE)
+				dev->stats.rx_over_errors++;
+			if (status & RXBD_STAT_CS)
+				dev->stats.collisions++;
+			goto rx_done;
+		}
+
+		pkt_len = RXBD_STAT_FL(status);
+		if (pkt_len > ETH_PKG_MAX) { /* assure skb_put() not panic */
+			printk(KERN_ERR"pkt_len = %u\n", pkt_len);
+			dev->stats.rx_length_errors++;
+			goto rx_done;
+		}
+
+		if (NULL == (new_skb = get_skb_aligned(PKG_MAX_LEN))) {
+			dev->stats.rx_dropped++;
+			printk(KERN_ERR"no memory, just drop it.\n"); // no release version ??
+			goto rx_done;
+		}
+
+		dma_unmap_single(&ecp->netdev->dev, bdp->buf_addr, PKG_MAX_LEN, DMA_FROM_DEVICE);
+
+		dev->stats.rx_packets++;
+		dev->stats.rx_bytes += pkt_len;
+
+		index = bdp - ecp->rx_bd_base;
+		skb_to_upper = ecp->rx_skb[index];
+		ecp->rx_skb[index] = new_skb;
+
+		skb_put(skb_to_upper, pkt_len - ETH_CRC_LEN); /* modify its data length, remove CRC */
+/*#define RX_DEBUG
+#ifndef RX_DEBUG
+		if (unlikely(netif_msg_rx_err(ecp))) {
+			check_icmp_sequence(skb_to_upper->data, __func__);
+			printk(KERN_INFO"receive %u bytes\n", pkt_len);
+			printk(KERN_INFO"source mac - ");
+			print_mac_address(skb_to_upper->data + ETH_MAC_LEN);
+			printk(KERN_INFO"dest mac - ");
+			print_mac_address(skb_to_upper->data);
+			printk(KERN_INFO"receive data:\n");
+			print_frame_data(skb_to_upper->data, skb_to_upper->len);
+		}
+#endif*/
+		skb_to_upper->protocol = eth_type_trans(skb_to_upper, dev);
+		netif_rx(skb_to_upper);
+
+		bdp->buf_addr = dma_map_single(&ecp->netdev->dev, new_skb->data, PKG_MAX_LEN, DMA_FROM_DEVICE);
+		if (!bdp->buf_addr)
+			printk(KERN_ERR"dma map new_skb->data:%p failed\n", new_skb->data);
+
+rx_done:
+		/* mark MAC AHB owns the buffer, and clear other status */
+		bdp->status = RXBD_STAT_OWN;
+#ifdef RX_DEBUG
+		if (unlikely(netif_msg_rx_err(ecp)))
+			printk(KERN_ERR"bdp->status: 0x%08x\n", (u32)bdp->status);
+#endif
+		if (bdp->control & RXBD_CTRL_RER)
+			bdp = ecp->rx_bd_base;
+		else
+			bdp++;
+#ifdef RX_DEBUG
+		if (unlikely(netif_msg_rx_err(ecp)))
+			printk(KERN_ERR"bdp: 0x%p\n", bdp);
+#endif
+		/* start to receive packets, may be good in heavily loaded net */
+//		hw_regs->er_opmode |= EC_OPMODE_SR;  // maybe not need it here
+	} /* while */
+	
+	ecp->cur_rx = (ec_bd_t *) bdp;
+	spin_unlock(&ecp->lock);
+	return;
+}
+
+#ifdef CONFIG_POLL_PHY_STATE
+static void phy_detect_func(struct work_struct *work)
+{
+	struct net_device *dev =  g_eth_dev[0];
+	ec_priv_t *ecp = netdev_priv(dev);
+	//unsigned short phy_interrupt_status = 0;
+	unsigned short mmi_status = 0;
+	unsigned long flags;
+
+	if(ecp->phy_model == ETH_PHY_MODEL_RTL8201){
+		mmi_status =read_phy_reg(ecp, MII_BMSR);
+		mmi_status =read_phy_reg(ecp, MII_BMSR);//For the current link status,read this register twice as spec request
+	}else if(ecp->phy_model == ETH_PHY_MODEL_SR8201G){
+		mmi_status =read_phy_reg(ecp, MII_BMSR);
+	}
+	//printk(KERN_DEBUG"%s:mmi_status: 0x%x\n", __func__,(unsigned)mmi_status);
+
+	//if (ecp->phy_model != ETH_PHY_MODEL_ATC2605)
+	//	putl(getl(INTC_EXTCTL) | (0x1 << 16), INTC_EXTCTL);
+
+	//if((phy_interrupt_status & PHY_RTL8201F_LINK_STATUS_CHANGE) == 0)
+	//	return;
+
+	spin_lock_irqsave(&ecp->lock, flags);
+	ecp->linked = (mmi_status & BMSR_LSTATUS) ? true : false;
+	spin_unlock_irqrestore(&ecp->lock, flags);
+
+	if(ecp->last_link_status != ecp->linked){
+		if (ecp->linked) {
+			int i;
+#ifdef DETECT_POWER_SAVE
+			bool enable;
+
+			stop_power_save_timer(ecp);
+			spin_lock_irqsave(&ecp->lock, flags);
+			enable = ecp->enable;
+			spin_unlock_irqrestore(&ecp->lock, flags);
+			if (!enable) {
+				/* rarely occur, work ethernet_power_save() disabled phy! */
+				ecp->linked = false;
+				printk(KERN_INFO"ecp->enable is false!\n");
+				goto out;
+			}
+#endif
+			//printk("old_duplex = 0x%x\n", ecp->duplex);
+			//printk("old_speed = 0x%x\n", ecp->speed);
+
+			ecp->phy_ops->phy_read_status(ecp);
+			set_mac_according_aneg(ecp);
+
+			//printk("new_duplex = 0x%x\n", ecp->duplex);
+			//printk("new_speed = 0x%x\n", ecp->speed);
+
+			for (i = 0; i < MII_TIME_OUT; i++) {
+				if (read_phy_reg(ecp, MII_BMSR) & BMSR_LSTATUS) {
+					ecp->linked = true;
+					printk(KERN_INFO"link established.\n");
+					break;
+				}
+			}
+			if (MII_TIME_OUT == i) {
+				ecp->linked = false;
+				printk(KERN_ERR"link fail.\n");
+				goto out;
+			}
+		} else {
+			ecp->linked = false;
+		}
+	}
+out:
+	if(ecp->last_link_status != ecp->linked){
+		INFO_GREEN("ethernet link state:%s\n", ecp->linked ? "linked" : "disconnected");
+		if (ecp->linked) {
+			netif_carrier_on(ecp->netdev);
+			if (netif_queue_stopped(ecp->netdev))
+				netif_wake_queue(ecp->netdev);
+		} else {
+#ifdef DETECT_POWER_SAVE
+			start_power_save_timer(ecp, 1000);
+#endif
+			netif_carrier_off(ecp->netdev);
+		}
+	}
+	ecp->last_link_status=ecp->linked;
+	queue_delayed_work(ecp->phy_detect_queue, &ecp->phy_detect_work,msecs_to_jiffies(PHY_DETECT_DUTY));
+}
+#else
+static void netphy_irq_handle_do_work(struct work_struct *work)
+{
+	struct net_device *dev =  g_eth_dev[0];
+	ec_priv_t *ecp = netdev_priv(dev);
+	unsigned short phy_interrupt_status = 0;
+	unsigned short mmi_status = 0;
+	unsigned long flags;
+
+	printk(KERN_DEBUG"%s >> %d \n",__func__,__LINE__);
+
+	if(ecp->phy_model==ETH_PHY_MODEL_RTL8201){
+		phy_interrupt_status = read_phy_reg(ecp, PHY_RTL8201F_REG_INT_SNR);
+		printk(KERN_INFO"phy_interrupt_status: 0x%x\n", (unsigned)phy_interrupt_status);
+		mmi_status =read_phy_reg(ecp, MII_BMSR);
+		mmi_status =read_phy_reg(ecp, MII_BMSR);//For the current link status,read this register twice as spec request
+		printk(KERN_INFO"mmi_status: 0x%x\n", (unsigned)mmi_status);
+	}else if(ecp->phy_model==ETH_PHY_MODEL_SR8201G){
+		phy_interrupt_status = read_phy_reg(ecp, PHY_SR8201G_REG_EXPAND);
+		mmi_status =read_phy_reg(ecp, MII_BMSR);
+	}
+
+	if (ecp->phy_model != ETH_PHY_MODEL_ATC2605)
+		putl(getl(INTC_EXTCTL) | (0x1 << 16), INTC_EXTCTL);
+
+	/* As RTL8201 we only care the interrrupt about the linkstate change */
+	if (ecp->phy_model==ETH_PHY_MODEL_RTL8201){
+		if((phy_interrupt_status & PHY_RTL8201F_LINK_STATUS_CHANGE) == 0)
+			return;
+	}
+
+	spin_lock_irqsave(&ecp->lock, flags);
+	ecp->linked = (mmi_status & BMSR_LSTATUS) ? true : false;
+	spin_unlock_irqrestore(&ecp->lock, flags);
+
+	if (ecp->linked) {
+		int i;
+#ifdef DETECT_POWER_SAVE
+		bool enable;
+
+		stop_power_save_timer(ecp);
+		spin_lock_irqsave(&ecp->lock, flags);
+		enable = ecp->enable;
+		spin_unlock_irqrestore(&ecp->lock, flags);
+		if (!enable) {
+			/* rarely occur, work ethernet_power_save() disabled phy! */
+			ecp->linked = false;
+			printk(KERN_INFO"ecp->enable is false!\n");
+			goto out;
+		}
+#endif
+		printk(KERN_DEBUG"old_duplex = 0x%x\n", ecp->duplex);
+		printk(KERN_DEBUG"old_speed = 0x%x\n", ecp->speed);
+
+		ecp->phy_ops->phy_read_status(ecp);
+		set_mac_according_aneg(ecp);
+
+		printk(KERN_DEBUG"new_duplex = 0x%x\n", ecp->duplex);
+		printk(KERN_DEBUG"new_speed = 0x%x\n", ecp->speed);
+
+		for (i = 0; i < MII_TIME_OUT; i++) {
+			if (read_phy_reg(ecp, MII_BMSR) & BMSR_LSTATUS) {
+				ecp->linked = true;
+				printk(KERN_INFO"link established.\n");
+				break;
+			}
+		}
+		if (MII_TIME_OUT == i) {
+			ecp->linked = false;
+			printk(KERN_ERR"link fail.\n");
+			goto out;
+		}
+	} else {
+		ecp->linked = false;
+	}
+
+out:
+	if (ecp->linked) {
+		netif_carrier_on(ecp->netdev);
+		if (netif_queue_stopped(ecp->netdev))
+			netif_wake_queue(ecp->netdev);
+	} else {
+#ifdef DETECT_POWER_SAVE
+		start_power_save_timer(ecp, 1000);
+#endif
+		netif_carrier_off(ecp->netdev);
+	}
+	enable_irq(ecp->phy_irq);
+
+	INFO_GREEN("link:%s\n", ecp->linked ? "linked" : "disconnected");
+}
+
+
+/**
+ * ec_netdev_isr -- interrupt service routine for ethernet controller
+ */
+static irqreturn_t ec_netphy_isr(int irq, void *cookie)
+{
+	ec_priv_t *ecp = netdev_priv((struct net_device *) cookie);
+
+	disable_irq_nosync(ecp->phy_irq);
+    	queue_work(ecp->ethernet_work_queue,&ecp->netphy_irq_handle_work);
+	
+	return IRQ_HANDLED;
+}
+#endif
+
+/**
+ * ec_netdev_isr -- interrupt service routine for ethernet controller
+ */
+static irqreturn_t ec_netmac_isr(int irq, void *cookie)
+{
+	ec_priv_t *ecp = netdev_priv((struct net_device *) cookie);
+	volatile ethregs_t *hw_regs = ecp->hwrp;
+	unsigned long status = 0;
+	unsigned long intr_bits = 0;
+	struct net_device *dev = ecp->netdev;
+    	static unsigned long tx_cnt,rx_cnt;
+	unsigned long mac_status;
+	int ru_cnt = 0;
+	intr_bits = EC_STATUS_NIS | EC_STATUS_AIS;
+
+	disable_irq_nosync(ecp->mac_irq);
+	while ((status = hw_regs->er_status) & intr_bits) {
+		hw_regs->er_status = status;    /* clear status */
+		if (netif_msg_intr(ecp)) {
+			printk(KERN_INFO"interrupt status: 0x%8x\n", (int)status);
+			printk(KERN_INFO"status after clear: 0x%x\n", (int)hw_regs->er_status);
+		}
+
+		if (status & (EC_STATUS_TI | EC_STATUS_ETI)) {
+			subisr_enet_tx(ecp);
+			tx_cnt = 0;
+			mac_status = status & EC_STATUS_RSM;
+			if((mac_status == EC_RX_fetch_dsp)||(mac_status ==EC_RX_run_dsp)||(mac_status ==EC_RX_close_dsp) )
+				rx_cnt++;
+		}
+
+		/* RI & RU may come at same time, if RI handled, then RU needn't handle.
+		 * If RU comes & RI not comes, then we must handle RU interrupt. */
+		if (status & EC_STATUS_RI) {
+			subisr_enet_rx(ecp);
+			rx_cnt = 0;
+			mac_status = status & EC_STATUS_TSM;
+			if((mac_status == EC_STATUS_TSM)||(mac_status == EC_TX_run_dsp))
+				tx_cnt++;
+		} else if (status & EC_STATUS_RU) {
+			ru_cnt++;
+			/* set RPD could help if rx suspended & bd available */
+			if (ru_cnt == 2)
+				hw_regs->er_rxpoll = 0x1;
+			printk(KERN_ERR"---RU interrupt---, status: 0x%08x\n", (u32)status);
+		
+	#ifdef RX_DEBUG
+		    	printk(KERN_ERR"---while loops: %d, RU count: %d\n", i, ru_cnt);
+			print_rx_bds(ecp);
+		    	ecp->msg_enable |= 0x40;
+	#endif
+		    	subisr_enet_rx(ecp);
+	#ifdef RX_DEBUG
+		    	ecp->msg_enable &= ~0x40;
+		    	print_rx_bds(ecp);
+	#endif
+		    	/* guard against too many RU interrupts to avoid long time ISR handling */
+		    	if (ru_cnt > 3)
+				break;
+		}
+	}
+	enable_irq(ecp->mac_irq);
+    	 
+	if((tx_cnt>10)||(rx_cnt>10)){
+		if(tx_cnt>10)
+			printk(KERN_ERR"TX ERROR status: 0x%08x\n", (u32)status);
+		else{
+			printk(KERN_ERR"RX ERROR status: 0x%08x\n", (u32)status);
+			ecp->rx_timeout=true;
+		}	
+		rx_cnt = 0;
+		tx_cnt = 0;
+		netif_stop_queue(dev);
+		queue_work(ecp->ethernet_work_queue,&ecp->hardware_reset_work);
+	}
+	
+	return (IRQ_HANDLED);
+}
+
+/**
+ * ec_netdev_open -- open ethernet controller
+ *
+ * return 0 if success, negative value if fail
+ */
+static int ec_netdev_open(struct net_device *dev)
+{
+    int ret = 0;
+    ec_priv_t *ecp = netdev_priv(dev);
+    volatile ethregs_t *hw_regs = ecp->hwrp;
+    unsigned long flags = 0;
+
+    if (ecp->opened) {
+        printk(KERN_ERR"already opened\n");
+        return (0);
+    }
+#ifdef ETH_TEST_MODE
+    ecp->test_mode = 0;
+#endif
+
+    if (prepare_rx_bd(ecp) || prepare_tx_bd(ecp)) {
+        printk(KERN_ERR"error: NO memery for bds.\n");
+        return (-1);
+    }
+
+	if (_init_hardware(ecp,FLAG_CLOCK_RESET,FLAG_PHY_RESET)) {
+        printk(KERN_ERR"error: harware initialization failed.\n");
+        return (-1);
+    }
+
+    /* should after set_mac_addr() which will set ec_priv_t{.mac_addr} */
+    memcpy(dev->dev_addr, ecp->mac_addr, ETH_MAC_LEN);
+
+    spin_lock_irqsave(&ecp->lock, flags);
+
+    /* send out a mac setup frame */
+    if (transmit_setup_frame(ecp)) {
+        printk(KERN_ERR"error : transmit setup frame failed.\n");
+        spin_unlock_irqrestore(&ecp->lock, flags);
+        return (-1);
+    }
+    
+    /* start to tx & rx packets */
+    hw_regs->er_ienable = EC_IEN_ALL;
+    hw_regs->er_opmode |= EC_OPMODE_ST | EC_OPMODE_SR;
+
+#ifdef DETECT_POWER_SAVE
+    ecp->enable = true;
+#endif
+    ecp->opened = true;
+
+    /* init  mii_if_info struct */
+    ecp->mii_info.phy_id_mask = PHY_ADDR_MASK;
+    ecp->mii_info.reg_num_mask = PHY_REG_NUM_MASK;
+    ecp->mii_info.dev = dev;
+    ecp->mii_info.mdio_read = ec_mdio_read;
+    ecp->mii_info.mdio_write = ec_mdio_write;
+    ecp->mii_info.phy_id = ecp->phy_addr;
+    ecp->mii_info.force_media = 0;
+    ecp->mii_info.full_duplex = 1;
+    ecp->mii_info.supports_gmii = 0;
+    ecp->msg_enable = NET_MSG_ENABLE;
+
+    spin_unlock_irqrestore(&ecp->lock, flags);
+
+    if (ecp->linked) 
+        netif_carrier_on(dev);
+    else 
+        netif_carrier_off(dev);
+
+    printk(KERN_INFO "%s link %s.\n", dev->name, ecp->linked ? "on" : "off");
+
+#if 1
+    /* FIXME!used by KSZ8041, other phy may not need this */
+    if (ecp->phy_model != ETH_PHY_MODEL_ATC2605)
+        phy_cable_plug_irq_enable(0);/* enable high level active */
+#endif
+#ifdef CONFIG_POLL_PHY_STATE
+	queue_delayed_work(ecp->phy_detect_queue, &ecp->phy_detect_work, msecs_to_jiffies(PHY_DETECT_DUTY));
+#else
+    ret = request_irq(ecp->phy_irq,  ec_netphy_isr,
+                IRQF_TRIGGER_LOW | IRQF_ONESHOT, "ethernet_phy", dev);
+    if (ret < 0) {
+        printk(KERN_ERR"Unable to request IRQ: %d, ec_netphy_isr\n", ret);
+        return ret;
+    }
+    printk(KERN_INFO"IRQ %d requested, dev: %p\n", ecp->phy_irq, dev);
+#endif
+
+    ret = request_irq(ecp->mac_irq, (irq_handler_t)ec_netmac_isr,
+                IRQF_TRIGGER_NONE, "ethernet_mac", dev);
+    if (ret < 0) {
+        printk(KERN_ERR"Unable to request IRQ: %d, ec_netmac_isr\n", ret);
+        goto err_irq;
+    }
+    printk(KERN_INFO"IRQ %d requested\n", OWL_IRQ_ETHERNET);
+    //print_mac_register(ecp);
+
+#ifdef DETECT_POWER_SAVE
+    init_power_save_timer(ecp);
+    start_power_save_timer(ecp, 4000);
+#endif
+
+    netif_start_queue(dev);
+    return (0);
+
+err_irq:
+#ifndef CONFIG_POLL_PHY_STATE
+    free_irq(ecp->phy_irq, dev);
+#endif
+    return ret;
+}
+
+
+/**
+ * ec_netdev_close -- close ethernet controller
+ *
+ * return 0 if success, negative value if fail
+ */
+static int ec_netdev_close(struct net_device *dev)
+{
+    ec_priv_t *ecp = netdev_priv(dev);
+    volatile ethregs_t *hw_regs = ecp->hwrp;
+    unsigned long flags = 0;
+
+    printk(KERN_DEBUG"%s %d\n",__func__,__LINE__);
+    if (!ecp->opened) {
+        printk(KERN_ERR"already closed\n");
+        return (0);
+    }
+
+#ifdef DETECT_POWER_SAVE
+    stop_power_save_timer(ecp);
+#endif
+
+#if 1
+    /* FIXME!used by KSZ8041, other phy may not need this */
+    if (ecp->phy_model != ETH_PHY_MODEL_ATC2605)
+        phy_cable_plug_irq_disable();
+#endif
+	_deinit_hardware(ecp);
+    netif_stop_queue(dev);
+
+    spin_lock_irqsave(&ecp->lock, flags);
+#ifdef DETECT_POWER_SAVE
+    ecp->enable = false;
+#endif
+    ecp->opened = false;
+    ecp->linked = false;
+    hw_regs->er_opmode &= ~(EC_OPMODE_ST | EC_OPMODE_SR);
+
+    hw_regs->er_ienable = 0;
+
+    spin_unlock_irqrestore(&ecp->lock, flags);
+
+    free_irq(dev->irq, dev);
+#ifndef CONFIG_POLL_PHY_STATE
+    free_irq(ecp->phy_irq, dev);
+#endif
+    if (ecp->phy_model != ETH_PHY_MODEL_ATC2605)
+        goto phy_not_atc2605;
+
+phy_not_atc2605:
+    ethernet_clock_disable();
+    return (0);
+}
+
+
+/**
+ * ec_netdev_start_xmit -- transmit a skb
+ *
+ * NOTE: if CSR6.ST is not set, the xmit frame will fail
+ *
+ * return NETDEV_TX_OK if success, others if fail
+ */
+static int ec_netdev_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+    ec_priv_t *ecp = netdev_priv(dev);
+    volatile ethregs_t *hw_regs = ecp->hwrp;
+    volatile ec_bd_t *bdp;
+    unsigned long flags = 0;
+
+#ifndef ETH_TEST_MODE
+    if (!ecp->linked) {
+        printk(KERN_ERR"haven't setup linkage\n");
+        return (-2);
+    }
+#endif
+
+    if (ecp->tx_full) {
+		if(printk_ratelimit())
+        	printk(KERN_ERR"warnig : tx buffer list is full\n");
+        return (NETDEV_TX_BUSY);
+    }
+
+    spin_lock_irqsave(&ecp->lock, flags);
+    bdp = ecp->cur_tx;
+
+    if (bdp->status & TXBD_STAT_OWN) {
+        printk(KERN_ERR"%s: tx is full. should not happen\n", dev->name);
+        spin_unlock_irqrestore(&ecp->lock, flags);
+        return (NETDEV_TX_BUSY);
+    }
+
+    /* Push the data cache so the NIC does not get stale memory data. */
+    bdp->buf_addr = dma_map_single(&ecp->netdev->dev, skb->data, skb->len, DMA_TO_DEVICE);
+    if (!bdp->buf_addr)
+        printk(KERN_ERR"dma map skb->data:%p failed\n", skb->data);
+
+    bdp->status = 0;
+    bdp->control &= TXBD_CTRL_IC | TXBD_CTRL_TER; /* clear others */
+    bdp->control |= TXBD_CTRL_TBS1(skb->len);
+    bdp->control |= TXBD_CTRL_FS | TXBD_CTRL_LS;
+    mb();
+    bdp->status = TXBD_STAT_OWN;
+    mb();
+    {
+        volatile u32 tmp;
+        tmp = (u32)(bdp->status + bdp->control + bdp->buf_addr);
+    }
+	if(skb->len > 1518)
+		printk(KERN_ERR"tx length:%d\n", skb->len);
+    //printk("bdp->status: 0x%x\n", bdp->status);
+
+    //!for FPGA test, or else tx transmission gonna disorder
+    //udelay(1);
+
+    /* 
+      * leave xmit suspended mode to xmit running mode; another method is that first 
+      * stop xmit, then start xmit through clearing CSR6.13-ST then setting it again.
+      * before call this function, CSR6.13-ST should be set
+      */
+    hw_regs->er_txpoll = EC_TXPOLL_ST;
+
+    dev->stats.tx_bytes += skb->len; 
+    dev->trans_start = jiffies;
+
+    ecp->tx_skb[ecp->skb_cur] = skb;
+    ecp->skb_cur = (ecp->skb_cur + 1) & TX_RING_MOD_MASK;
+
+    if (!(hw_regs->er_status & EC_STATUS_TSM))
+        printk(KERN_ERR"tx stopped, hw_regs->er_status:0x%lx\n", hw_regs->er_status);
+
+    if (netif_msg_tx_err(ecp)) {
+        check_icmp_sequence(skb->data, __func__);
+        printk(KERN_INFO"%d, hw_regs->er_status:0x%lx\n", __LINE__, hw_regs->er_status);
+        printk(KERN_INFO"bdp->status:0x%x\n", (unsigned int)bdp->status);
+        printk(KERN_INFO"bdp->control:0x%x\n", (unsigned int)bdp->control);
+        printk(KERN_INFO"bdp->buf_addr:0x%x\n", (unsigned int)bdp->buf_addr);
+        printk(KERN_INFO"tx frame len:0x%x, skb->data:0x%x\n", skb->len, (int)skb->data);
+        printk(KERN_INFO"tx src mac: ");
+        print_mac_address(skb->data + ETH_MAC_LEN);
+        printk(KERN_INFO"tx dst mac: ");
+        print_mac_address(skb->data);
+        printk(KERN_INFO"tx frame:\n");
+        print_frame_data(skb->data, skb->len);
+    }
+
+    if (bdp->control & TXBD_CTRL_TER)
+        bdp = ecp->tx_bd_base;
+    else
+        bdp++;
+
+    if (bdp == ecp->dirty_tx) {
+        printk(KERN_ERR"tx is full, skb_dirty:%d\n", ecp->skb_dirty);
+        ecp->tx_full = true;
+        netif_stop_queue(dev);
+    }
+    netif_stop_queue(dev);
+
+    ecp->cur_tx = (ec_bd_t *)bdp;
+    spin_unlock_irqrestore(&ecp->lock, flags);
+
+    /*---------------debug -------------------*/
+#if 0
+    {
+        static timeout_reset_cnt = 0;
+        timeout_reset_cnt++;
+        if(timeout_reset_cnt >100000) {
+            timeout_reset_cnt =0;
+            ec_netdev_transmit_timeout(ecp->netdev);
+        }
+    }
+#endif
+
+    return (NETDEV_TX_OK);
+}
+
+
+/**
+ * ec_netdev_query_stats -- query statistics of ethernet controller
+ */
+static struct net_device_stats *ec_netdev_query_stats(struct net_device *dev)
+{
+    return (&dev->stats);
+}
+
+
+/**
+ * ec_netdev_set_mac_addr -- set mac a new address
+ *
+ * NOTE: when ethernet device has opened, can't change mac address, otherwise return 
+ * EBUSY error code.
+ *
+ * return 0 if success, others if fail
+ */
+static int ec_netdev_set_mac_addr(struct net_device *dev, void *addr)
+{
+    struct sockaddr *address = (struct sockaddr *) addr;
+    ec_priv_t *ecp = netdev_priv(dev); 
+    unsigned long flags = 0;
+    char    old_mac_addr[ETH_MAC_LEN];
+    bool old_overrided;
+
+    printk(KERN_DEBUG"%s %d\n",__func__,__LINE__);
+
+    if (!is_valid_ether_addr(address->sa_data)) {
+        printk(KERN_ERR"not valid mac address\n");
+        return (-EADDRNOTAVAIL);
+    }
+
+    /* if new mac address is the same as the old one, nothing to do */
+    if (!ether_addr_equal(ecp->mac_addr, address->sa_data)) {
+        printk(KERN_ERR"the same address ! \n");
+        return (0);
+    }
+
+    if (netif_running(dev)) {
+        printk(KERN_ERR"error : queue is busy\n");
+        return (-EBUSY);
+    }
+
+    spin_lock_irqsave(&ecp->lock, flags);
+
+    memcpy(old_mac_addr, ecp->mac_addr, ETH_MAC_LEN);
+    old_overrided = ecp->mac_overrided;
+
+    memcpy(ecp->overrided_mac, address->sa_data, dev->addr_len);
+
+    if (ether_addr_equal(g_default_mac_addr, ecp->overrided_mac)) {
+        ecp->mac_addr = ecp->overrided_mac;
+        ecp->mac_overrided = true;
+    } else {
+        ecp->mac_addr = g_default_mac_addr;
+        ecp->mac_overrided = false;
+    }
+
+    memcpy(dev->dev_addr, ecp->mac_addr, dev->addr_len);
+
+    /* if netdev is close now, just save new addr tmp, set it when open it */
+    if (!ecp->opened) {
+        spin_unlock_irqrestore(&ecp->lock, flags);
+        return (0);
+    }
+
+    fill_macaddr_regs(ecp, ecp->mac_addr);  /* for flow control */
+
+    /*
+     * errors only occur before frame is put into tx bds. in fact if frame is successfully built, 
+     * xmit never fail, otherwise mac controller may be something wrong.
+     */
+    if (transmit_setup_frame(ecp)) {
+        printk(KERN_ERR"error : transmit setup frame failed\n");
+
+        /* set back to old one */
+        fill_macaddr_regs(ecp, old_mac_addr);
+        
+        if (old_overrided) {
+            memcpy(ecp->overrided_mac, old_mac_addr, ETH_MAC_LEN);
+            ecp->mac_addr = ecp->overrided_mac;
+        } else {
+            ecp->mac_addr = g_default_mac_addr;
+        }
+        ecp->mac_overrided = old_overrided;
+        memcpy(dev->dev_addr, ecp->mac_addr, dev->addr_len);
+        spin_unlock_irqrestore(&ecp->lock, flags);
+        return (-1);
+    }
+
+    spin_unlock_irqrestore(&ecp->lock, flags);
+
+    return (0);
+}
+
+
+/**
+ * copy_multicast_list -- copy @list to local ec_priv_t{.multicast_list}
+ * may use it if multicast is supported when building setup-frame 
+ */
+static inline void copy_multicast_list(ec_priv_t *ecp, struct netdev_hw_addr_list *list)
+{
+    char (*mmac_list)[MULTICAST_LIST_LEN][ETH_MAC_LEN] = NULL;
+    struct netdev_hw_addr *ha = NULL;
+    int mmac_sum = 0;
+
+    mmac_list = &ecp->multicast_list.mac_array;
+#if 0
+    while (list && mmac_sum < MULTICAST_LIST_LEN) {
+        if (!is_multicast_ether_addr(list->dmi_addr)) {
+            //printk("there is one non-multicast addr\n");
+            continue;
+        }
+        
+#if EC_TRACED
+        printk("ok, add one : ");
+        print_mac_address(list->dmi_addr);
+#endif
+
+        memcpy((*mmac_list)[mmac_sum], list->dmi_addr, ETH_MAC_LEN);
+        list = list->next;
+        mmac_sum++;
+    }
+#endif
+
+    netdev_hw_addr_list_for_each(ha, list) {
+        if (mmac_sum >= MULTICAST_LIST_LEN) {
+            break;
+        }
+        if (!is_multicast_ether_addr(ha->addr)) {
+            //printk("there is one non-multicast addr\n");
+            continue;
+        }
+        memcpy((*mmac_list)[mmac_sum], ha->addr, ETH_MAC_LEN);
+        mmac_sum++;
+    }
+
+    ecp->multicast_list.count = mmac_sum; 
+
+    return;
+}
+
+
+static inline void parse_interface_flags(ec_priv_t *ecp, unsigned int flags)
+{
+    //printk(KERN_DEBUG"%s %d\n",__func__,__LINE__);
+    set_mode_promisc(ecp, (bool)(flags & IFF_PROMISC));
+    set_mode_all_multicast(ecp, (bool)(flags & IFF_ALLMULTI));
+    ecp->multicast = (bool)(flags & IFF_MULTICAST);
+    return;
+}
+
+/**
+ * ec_netdev_set_multicast_list -- set mac multicast address, meanwhile set promiscuous
+ * and all_multicast mode according to dev's flags
+ */
+static void ec_netdev_set_multicast_list(struct net_device *dev)
+{
+    ec_priv_t *ecp = netdev_priv(dev);
+    volatile ethregs_t *hw_regs = ecp->hwrp;
+    unsigned long flags = 0;
+    unsigned long old_srst_bits;
+
+#if EC_TRACED
+    printk(KERN_DEBUG"--- enter %s()\n", __func__);
+    printk(KERN_DEBUG"dev->flags - 0x%x\n", dev->flags);
+#endif
+
+    spin_lock_irqsave(&ecp->lock, flags);
+
+    old_srst_bits = hw_regs->er_opmode & (EC_OPMODE_SR | EC_OPMODE_ST);
+
+    /* stop tx & rx first */
+    hw_regs->er_opmode &= ~(EC_OPMODE_SR | EC_OPMODE_ST);
+
+    parse_interface_flags(ecp, dev->flags);
+
+    if (!ecp->all_multicast && ecp->multicast && dev->mc.count) {
+        if (dev->mc.count <= MULTICAST_LIST_LEN) {
+	        copy_multicast_list(ecp, &dev->mc);
+            transmit_setup_frame(ecp);
+        } else {
+            printk(KERN_ERR"too multicast addrs to support, open all_multi\n");
+            /* list is too long to support, so receive all multicast packets */
+            set_mode_all_multicast(ecp, true);
+        }
+    }
+    printk(KERN_DEBUG"%s %d \n",__func__,__LINE__);
+
+    hw_regs->er_opmode |= old_srst_bits;
+ 
+    spin_unlock_irqrestore(&ecp->lock, flags);
+
+    return;
+
+}
+
+static inline void modify_mii_info(struct mii_ioctl_data *data, struct mii_if_info *info)
+{
+    unsigned short val = data->val_in;
+
+    if (data->phy_id != info->phy_id)
+        return;
+
+    switch (data->reg_num) {
+    case MII_BMCR:
+    {
+        info->force_media = (val & (BMCR_RESET | BMCR_ANENABLE)) ? 0 : 1;
+
+        if (info->force_media && (val & BMCR_FULLDPLX))
+            info->full_duplex = 1;
+        else
+            info->full_duplex = 0;
+        break;
+    }
+    case MII_ADVERTISE:
+        info->advertising = val;
+        break;
+    default:
+        /* nothing to do */
+        break;
+    }
+
+    return;
+}
+
+
+/**
+ * ec_netdev_ioctrl -- net device's ioctrl hook
+ */
+static int ec_netdev_ioctrl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{    
+    ec_priv_t *ecp = netdev_priv(dev);
+    struct mii_ioctl_data *data = if_mii(ifr);
+    struct mii_if_info *info = &ecp->mii_info;
+    int     err = 0;
+
+#if EC_TRACED
+    printk(KERN_DEBUG"--- enter %s()\n", __func__);
+    printk(KERN_DEBUG"phy reg num - 0x%x, data - 0x%x, cmd:0x%x\n", data->reg_num, data->val_in, cmd);
+#endif
+
+    data->phy_id &= info->phy_id_mask;
+    data->reg_num &= info->reg_num_mask;
+
+    switch (cmd) {
+    case SIOCGMIIPHY:
+        data->phy_id = info->phy_id;
+        /* FALL THROUGH */
+    case SIOCGMIIREG:
+        //data->val_out = read_phy_reg(ecp, info->phy_id, data->reg_num);
+        data->val_out = read_phy_reg(ecp, 0x500 + data->reg_num);
+        break;
+
+    case SIOCSMIIREG:
+    {
+        unsigned short val = data->val_in;
+        //unsigned short old_val;
+
+        if (!capable(CAP_NET_ADMIN)) {
+            return (-EPERM);
+        }
+
+        modify_mii_info(data, info);
+        //printk("val : 0x%x\n", val);
+
+        /* when keep speed unchanged, but change duplex, CSR5.LCIQ will not raise
+         *  interrupt. if so ISR can't capture duplex status change.
+         * here we change speed first and then set it back to raise a LCIQ interrupt.
+         * has other better way???
+         */
+//            if (unlikely(info->force_media && MII_BMCR == data->reg_num)) {
+//                //old_val = read_phy_reg(ecp, info->phy_id, data->reg_num);
+//                old_val = read_phy_reg(ecp, data->reg_num);
+//                if (need_change_speed(val, old_val)) {
+//                    //printk("old bmcr: 0x%x\n", old_val);
+//                    old_val &= ~(BMCR_ANENABLE | BMCR_RESET);
+//                    old_val ^= BMCR_SPEED100;
+//                    //printk("exchanged old bmcr: 0x%x\n", old_val);
+//                    //write_phy_reg(ecp, info->phy_id, data->reg_num, old_val);
+//                    write_phy_reg(ecp, data->reg_num, old_val);
+//                }
+//            }
+
+        //write_phy_reg(ecp, info->phy_id, data->reg_num, val);
+        write_phy_reg(ecp, 0x500 + data->reg_num, val);
+        break;
+    }  /* end SIOCSMIIREG */
+
+    default:
+        err = -EOPNOTSUPP;
+        break;
+    }
+
+    return (err);
+
+    //return generic_mii_ioctl(&ecp->mii_info, data, cmd, NULL);
+}
+
+/**
+ * do hardware reset,this function is called when transmission timeout.
+*/
+static void hardware_reset_do_work(struct work_struct *work)
+{
+	struct net_device *dev =  g_eth_dev[0];
+	ec_priv_t *ecp = netdev_priv(dev);//(ec_priv_t *)container_of(work, ec_priv_t, hardware_reset_work);//
+	volatile ethregs_t *hw_regs = ecp->hwrp;
+	bool phy_reinit =false;
+	//spin_lock_irqsave(&ecp->lock, flags);
+
+	//netif_carrier_off(dev);
+
+    hw_regs->er_opmode &= ~(EC_OPMODE_SR | EC_OPMODE_ST);       // stop tx and rx
+    hw_regs->er_ienable = 0;
+
+    disable_irq(ecp->mac_irq);
+#ifdef CONFIG_POLL_PHY_STATE
+	cancel_delayed_work(&ecp->phy_detect_work);
+	flush_workqueue(ecp->phy_detect_queue);
+#else
+    disable_irq(ecp->phy_irq);
+#endif
+	//if tx timeout ֻ\B8\B4λmac\A3\AC\B2\BB\B8\B4λphy, \B7\F1\D4\F2\B6\BC\D7\F6reset
+#if 0   //timeout \D7\DC\CADz\BBreset phy
+    if(ecp->rx_timeout){
+    	  phy_reinit=true;
+				ecp->rx_timeout=false;    			
+				write_phy_reg(ecp, 0x0, 0x1<<15);
+				mdelay(5);
+				_deinit_hardware(ecp);
+				mdelay(30);
+		}		
+#endif
+
+	ethernet_clock_disable();
+
+	if (ecp->tx_bd_base)
+		dma_free_coherent(NULL, sizeof(ec_bd_t) * TX_RING_SIZE,
+				ecp->tx_bd_base, ecp->tx_bd_paddr);
+	if (ecp->rx_bd_base)
+		dma_free_coherent(NULL, sizeof(ec_bd_t) * RX_RING_SIZE,
+				ecp->rx_bd_base, ecp->rx_bd_paddr);
+	ecp->tx_bd_base = (ec_bd_t *)dma_alloc_coherent(NULL, sizeof(ec_bd_t) * TX_RING_SIZE, &ecp->tx_bd_paddr, GFP_KERNEL);
+    ecp->rx_bd_base = (ec_bd_t *)dma_alloc_coherent(NULL, sizeof(ec_bd_t) * RX_RING_SIZE, &ecp->rx_bd_paddr, GFP_KERNEL);
+
+    //printk(KERN_DEBUG"ecp->tx_bd_base:%p, ecp->tx_bd_paddr:%p\n", ecp->tx_bd_base, (void *)ecp->tx_bd_paddr);
+    //printk(KERN_DEBUG"ecp->rx_bd_base:%p, ecp->rx_bd_paddr:%p\n", ecp->rx_bd_base, (void *)ecp->rx_bd_paddr);
+    //printk(KERN_DEBUG"virt_to_phys(ecp->tx_bd_base):%p\n", (void *)virt_to_phys(ecp->tx_bd_base));
+
+    /* set default value of status */
+//    ecp->linked = false;
+//    ecp->opened = false;
+//    ecp->speed = ETH_SPEED_100M;
+//    ecp->duplex = ETH_DUP_FULL;
+    //spin_unlock_irqrestore(&ecp->lock, flags);
+	
+    if (prepare_rx_bd(ecp) || prepare_tx_bd(ecp)) {
+        INFO_RED("error : prepare bds failed\n");
+        return;
+    }
+    if(phy_reinit){
+    	phy_reinit=false;
+    	if (_init_hardware(ecp,FLAG_CLOCK_RESET,FLAG_PHY_RESET)) {
+			INFO_RED("error : harware init failed.\n");
+			return;
+    	}
+    }else{
+     	if (_init_hardware(ecp,FLAG_CLOCK_RESET,FLAG_PHY_NONE_RESET)) {
+			INFO_RED("error : harware init failed.\n");
+			return;
+    	}    
+    }
+
+    memcpy(dev->dev_addr, ecp->mac_addr, ETH_MAC_LEN);
+
+    parse_interface_flags(ecp, dev->flags);
+
+    if (transmit_setup_frame(ecp)) {  // recovery previous macs
+        INFO_RED("error : xmit setup frame failed\n");
+        return;
+    }
+
+    hw_regs->er_ienable = EC_IEN_ALL;
+    hw_regs->er_opmode |= (EC_OPMODE_SR | EC_OPMODE_ST);        /* start tx, rx */
+
+//#ifdef DETECT_POWER_SAVE
+//    ecp->enable = true;
+//      start_power_save_timer(ecp, 4000);
+//#endif
+//    ecp->opened = true;
+
+#ifdef CONFIG_POLL_PHY_STATE
+	queue_delayed_work(ecp->phy_detect_queue, &ecp->phy_detect_work,msecs_to_jiffies(PHY_DETECT_DUTY));
+#else
+    enable_irq(ecp->phy_irq);
+#endif
+    enable_irq(ecp->mac_irq);
+	return;
+	
+}
+/**
+ * ec_netdev_transmit_timeout -- process tx fails to complete within a period.
+ *
+ * This function is called when a packet transmission fails to complete within a  
+ * resonable period, on the assumption that an interrupts have been failed or the 
+ * interface is locked up. This function will reinitialize the hardware 
+ */
+static void ec_netdev_transmit_timeout(struct net_device *dev)
+{
+    ec_priv_t *ecp = netdev_priv(dev);
+	//static int reset = 0;
+#if 0
+    volatile ethregs_t *hw_regs = ecp->hwrp;
+
+    //unsigned long flags = 0;
+    /* times of timeout handled by subisr_enet_tx() */
+//    static int times = 0;
+    /* times of hardware reset, (times * reset) is the overall times of timeout */
+    volatile ec_bd_t *bdp;
+
+#define TX_TIMEOUT_TIMES_2_RESET 1
+//    printk(KERN_INFO "before tx isr, reg status : 0x%x\n", (int)hw_regs->er_status);
+    print_mac_register(ecp);
+    print_tx_bds(ecp);
+
+
+    /* handle situation that no TX interrupt comes & TX process is dead */
+    if (times < TX_TIMEOUT_TIMES_2_RESET) {
+        hw_regs->er_ienable &= ~(EC_IEN_TIE |EC_IEN_ETE);
+
+        bdp = ecp->dirty_tx;
+        if (bdp->status & TXBD_STAT_OWN) {
+            times++;
+        } else {
+            //subisr_enet_tx(ecp);
+//            printk(KERN_INFO "---TX timeout times: %d\n", times);
+            times = 0;
+        }
+        hw_regs->er_ienable |= EC_IEN_TIE | EC_IEN_ETE;
+#if 0
+        printk(VT_GREEN "after tx isr, reg status : 0x%x\n" VT_NORMAL, (int)hw_regs->er_status);
+        print_mac_register(ecp);
+        print_tx_bds(ecp);
+#endif
+        /* if tx still time out, then reset hardware */
+        return;
+    }
+    times = 0;
+
+    printk(KERN_INFO "before tx isr, reg status : 0x%x\n", (int)hw_regs->er_status);
+    print_mac_register(ecp);
+    print_tx_bds(ecp);
+#endif
+	netif_stop_queue(dev);
+    //reset++;
+#if 0    
+    printk(KERN_INFO "---TX timeout reset: %d\n", reset);
+	printk(KERN_INFO "MAC flowctrl : 0x%x\n", (int)hw_regs->er_flowctrl);
+	printk(KERN_INFO "MAC reg status : 0x%x\n", (int)hw_regs->er_status);
+#endif
+	queue_work(ecp->ethernet_work_queue,&ecp->hardware_reset_work);
+#if 0
+    spin_lock_irqsave(&ecp->lock, flags);
+
+    netif_stop_queue(dev);
+    netif_carrier_off(dev);
+
+    hw_regs->er_opmode &= ~(EC_OPMODE_SR | EC_OPMODE_ST);       // stop tx and rx
+    hw_regs->er_ienable = 0;
+
+    disable_irq(ecp->mac_irq);
+    disable_irq(dev->irq);
+    ethernet_clock_disable();
+
+    /* set default value of status */
+    ecp->linked = false;
+    ecp->opened = false;
+    ecp->speed = ETH_SPEED_100M;
+    ecp->duplex = ETH_DUP_FULL;
+    spin_unlock_irqrestore(&ecp->lock, flags);
+		
+
+    if (prepare_rx_bd(ecp) || prepare_tx_bd(ecp)) {
+        INFO_RED("error : prepare bds failed\n");
+        return;
+    }
+
+    if (_init_hardware(ecp)) {
+        INFO_RED("error : harware init failed.\n");
+        return;
+    }
+
+    memcpy(dev->dev_addr, ecp->mac_addr, ETH_MAC_LEN);
+
+    parse_interface_flags(ecp, dev->flags);
+
+    if (transmit_setup_frame(ecp)) {  // recovery previous macs
+        INFO_RED("error : xmit setup frame failed\n");
+        return;
+    }
+
+    hw_regs->er_ienable = EC_IEN_ALL;
+    hw_regs->er_opmode |= (EC_OPMODE_SR | EC_OPMODE_ST);        /* start tx, rx */
+
+#ifdef DETECT_POWER_SAVE
+    ecp->enable = true;
+    start_power_save_timer(ecp, 4000);
+#endif
+    ecp->opened = true;
+
+    enable_irq(dev->irq);
+    enable_irq(ecp->mac_irq);
+
+    /* we need make sure all right before arrive here. */
+    //netif_wake_queue(dev);
+#endif
+    return;
+}
+
+
+/*
+ * Internal function. Flush all scheduled work from the Ethernet work queue.
+ */
+static void ethernet_flush_scheduled_work(void)
+{
+	flush_workqueue(resume_queue);
+}
+
+
+static int asoc_ethernet_suspend(struct platform_device *pdev, pm_message_t m)
+{
+    struct net_device *dev =  g_eth_dev[0];
+    ec_priv_t *ecp = netdev_priv(dev);
+    volatile ethregs_t *hw_regs = ecp->hwrp;
+    unsigned long flags = 0;
+
+    dev_info(&pdev->dev, "asoc_ethernet_suspend()\n");
+
+    suspend_flag = 1;
+
+    disable_irq(ecp->mac_irq);
+#ifdef CONFIG_POLL_PHY_STATE
+	cancel_delayed_work_sync(&ecp->phy_detect_work);
+#else
+	disable_irq(ecp->phy_irq);
+#endif
+    _deinit_hardware(ecp);
+	mdelay(5);  
+
+    ecp->linked = false;
+            
+    cancel_delayed_work_sync(&resume_work);
+    ethernet_flush_scheduled_work();
+
+    netif_stop_queue(dev);
+    netif_carrier_off(dev);
+
+    spin_lock_irqsave(&ecp->lock, flags);
+    
+    hw_regs->er_opmode &= ~(EC_OPMODE_SR | EC_OPMODE_ST);  // stop tx and rx
+    hw_regs->er_ienable = 0;
+
+    free_rxtx_skbs(ecp->rx_skb, RX_RING_SIZE);
+    free_rxtx_skbs(ecp->tx_skb, TX_RING_SIZE);
+
+    spin_unlock_irqrestore(&ecp->lock, flags);
+
+    ethernet_clock_disable();
+
+    return 0;
+}
+
+
+static int ethernet_parse_gpio(struct device_node * of_node, const char * propname, struct owl_ethernet_gpio * gpio)
+{
+    enum of_gpio_flags gflags;
+    int	gpio_num;
+
+    gpio_num = of_get_named_gpio_flags(of_node, propname, 0, &gflags);
+    if (gpio_num >= 0) {
+        gpio->gpio = gpio_num;
+    } else {
+        gpio->gpio = -1;
+	 return -1;		
+    }
+
+    gpio->active= (gflags&OF_GPIO_ACTIVE_LOW) ;
+
+	printk(KERN_DEBUG"gpio %s num %d active %d\n", propname, gpio->gpio, gpio->active);
+
+    return 0;
+}
+
+
+static void ethernet_resume_handler(struct work_struct *work)
+{
+    struct net_device *dev =  g_eth_dev[0];
+
+    ec_priv_t *ecp = netdev_priv(dev);
+    volatile ethregs_t *hw_regs = ecp->hwrp;
+    unsigned long flags = 0;
+
+    printk(KERN_DEBUG"%s %d\n",__func__,__LINE__);
+    suspend_flag = 0;
+ #if 0
+    if (ecp->phy_model == ETH_PHY_MODEL_ATC2605) {
+        /*For gl5302 INT Pending unusual */
+        ethernet_clock_enable();
+        ecp->phy_ops->phy_hw_init(ecp);
+
+        /*ethernet wrapper rest and phy has no power*/
+        atc260x_reg_setbits(ecp->atc260x, atc2603_CMU_DEVRST, 0x08, 0x08);
+        udelay(100);
+        atc260x_reg_setbits(ecp->atc260x, atc2603_CMU_DEVRST, 0x08, 0x0);
+        udelay(100);
+  #endif //0
+       // ethernet_clock_disable();
+    
+
+    if (ecp->opened == false) {
+        printk(KERN_ERR"The ethernet is turned off\n");
+        return;
+    }
+   
+    ecp->linked = false;
+#ifdef CONFIG_POLL_PHY_STATE
+	ecp->last_link_status = false;
+#endif
+    spin_lock_irqsave(&ecp->lock, flags);
+    if (prepare_rx_bd(ecp) || prepare_tx_bd(ecp)) {
+        printk(KERN_ERR"error: prepare bds failed\n");
+        goto err_unlock;
+    }
+    spin_unlock_irqrestore(&ecp->lock, flags);
+
+    /*can't sleep */
+    if (_init_hardware(ecp,FLAG_CLOCK_NONT_RESET,FLAG_PHY_RESET)) {
+        printk(KERN_ERR"error: harware init failed.\n");
+        return;
+    }
+
+    spin_lock_irqsave(&ecp->lock, flags);
+
+    memcpy(dev->dev_addr, ecp->mac_addr, ETH_MAC_LEN);
+
+    parse_interface_flags(ecp, dev->flags);
+
+    /* send out a mac setup frame */
+    if (transmit_setup_frame(ecp)) {  // recovery previous macs
+        printk(KERN_ERR"error: xmit setup frame failed\n");
+        goto err_unlock;
+    }
+
+    hw_regs->er_ienable = EC_IEN_ALL;
+    hw_regs->er_opmode |= (EC_OPMODE_SR | EC_OPMODE_ST);
+    spin_unlock_irqrestore(&ecp->lock, flags);
+
+#ifndef CONFIG_POLL_PHY_STATE
+    enable_irq(ecp->phy_irq);
+#endif
+    enable_irq(ecp->mac_irq);
+#ifdef DETECT_POWER_SAVE
+    ecp->enable = true;
+    start_power_save_timer(ecp, 4000);
+#endif
+#ifdef CONFIG_POLL_PHY_STATE
+	queue_delayed_work(ecp->phy_detect_queue, &ecp->phy_detect_work,msecs_to_jiffies(PHY_DETECT_RESUME));
+	printk(KERN_INFO "phy detect by work queue\n");
+#endif
+
+    return;
+
+err_unlock:
+    spin_unlock_irqrestore(&ecp->lock, flags);
+}
+
+static int asoc_ethernet_resume(struct platform_device *pdev)
+{
+    dev_info(&pdev->dev, "asoc_ethernet_resume()\n");
+
+    queue_delayed_work(resume_queue, &resume_work, msecs_to_jiffies(PHY_RESUME_DELAY));
+    return 0;
+}
+
+/**
+ * ec_netdev_init -- initialize ethernet controller
+ *
+ * return 0 if success, others if fail
+ */
+static int ec_netdev_init(struct net_device *dev)
+{
+    ec_priv_t *ecp = netdev_priv(dev);
+    volatile ethregs_t *hw_regs = NULL;
+
+    printk(KERN_DEBUG"ETHERNET_BASE: 0x%x\n", ETHERNET_BASE);
+    printk(KERN_DEBUG"ecp->hwrp: 0x%p\n", ecp->hwrp);
+    /* ETHERNET_BASE address is taken from dts when driver probe,
+     * instead of hard-coding here */
+    /* ecp->hwrp = (volatile ethregs_t *)IO_ADDRESS(ETHERNET_BASE); */
+    ecp->netdev = dev;
+    hw_regs = ecp->hwrp;
+
+    /* set default value of status */
+#ifdef DETECT_POWER_SAVE
+    ecp->enable = false;
+#endif
+    ecp->linked = false;
+    ecp->opened = false;
+    ecp->mac_overrided = false;
+    ecp->multicast = false;
+    ecp->all_multicast = false;
+    ecp->promiscuous = false;
+    ecp->autoneg = true;
+    ecp->speed = ETH_SPEED_100M;
+    ecp->duplex = ETH_DUP_FULL;
+    ecp->mac_addr = NULL;
+
+    memset(&ecp->multicast_list, 0, sizeof(struct mac_list));
+    spin_lock_init(&ecp->lock);
+
+    //uncache address
+    ecp->tx_bd_base = (ec_bd_t *)dma_alloc_coherent(NULL, sizeof(ec_bd_t) * TX_RING_SIZE, &ecp->tx_bd_paddr, GFP_KERNEL);
+    ecp->rx_bd_base = (ec_bd_t *)dma_alloc_coherent(NULL, sizeof(ec_bd_t) * RX_RING_SIZE, &ecp->rx_bd_paddr, GFP_KERNEL);
+
+    printk(KERN_DEBUG"ecp->tx_bd_base:%p, ecp->tx_bd_paddr:%p\n", ecp->tx_bd_base, (void *)ecp->tx_bd_paddr);
+    printk(KERN_DEBUG"ecp->rx_bd_base:%p, ecp->rx_bd_paddr:%p\n", ecp->rx_bd_base, (void *)ecp->rx_bd_paddr);
+    printk(KERN_DEBUG"virt_to_phys(ecp->tx_bd_base):%p\n", (void *)virt_to_phys(ecp->tx_bd_base));
+
+    if (ecp->tx_bd_base == NULL || ecp->rx_bd_base == NULL) {
+        printk(KERN_ERR"dma_alloc mem failed, tx_bd_base:%p, rx_bd_base:%p\n",
+                ecp->tx_bd_base, ecp->rx_bd_base);
+
+        if (ecp->tx_bd_base)
+            dma_free_coherent(NULL, sizeof(ec_bd_t) * TX_RING_SIZE,
+                    ecp->tx_bd_base, ecp->tx_bd_paddr);
+        if (ecp->rx_bd_base)
+            dma_free_coherent(NULL, sizeof(ec_bd_t) * RX_RING_SIZE,
+                    ecp->rx_bd_base, ecp->rx_bd_paddr);
+
+        return -ENOMEM;
+    }
+   #if 0
+    if (ecp->phy_model == ETH_PHY_MODEL_ATC2605) {
+        /*For gl5302 INT Pending unusual */
+        ethernet_clock_enable();
+        ecp->phy_ops->phy_hw_init(ecp);
+    }
+  #endif //0
+    ecp->mac_addr = g_default_mac_addr;
+    ecp->mac_overrided = false;
+
+    /* should after set_mac_addr() which will set ec_priv_t{.mac_addr} */
+    memcpy(dev->dev_addr, ecp->mac_addr, ETH_MAC_LEN);
+
+    ether_setup(dev);
+
+    INFO_GREEN("net device : %s init over.\n", dev->name);
+
+    return (0);
+}
+
+static void ec_netdev_uninit(struct net_device *dev)
+{
+    ec_priv_t *ecp = netdev_priv(dev);
+
+    printk(KERN_DEBUG"%s %d\n",__func__,__LINE__);
+#if 0
+    if (ecp->tx_wq) {
+        destroy_workqueue(ecp->tx_wq);
+    }
+
+    if (ecp->rx_wq) {
+        destroy_workqueue(ecp->rx_wq);
+    }
+#endif
+
+    /* after all works have been completed and destroyed */
+    free_rxtx_skbs(ecp->rx_skb, RX_RING_SIZE);
+    free_rxtx_skbs(ecp->tx_skb, TX_RING_SIZE);
+
+    if (ecp->tx_bd_base)
+        dma_free_coherent(NULL, sizeof(ec_bd_t) * TX_RING_SIZE,
+                ecp->tx_bd_base, ecp->tx_bd_paddr);
+    if (ecp->rx_bd_base)
+        dma_free_coherent(NULL, sizeof(ec_bd_t) * RX_RING_SIZE,
+                ecp->rx_bd_base, ecp->rx_bd_paddr);
+}
+
+static const struct net_device_ops ec_netdev_ops = {
+    .ndo_init = ec_netdev_init,
+    .ndo_uninit = ec_netdev_uninit,
+    .ndo_open = ec_netdev_open,
+    .ndo_stop = ec_netdev_close,
+    .ndo_start_xmit = ec_netdev_start_xmit,
+    .ndo_set_rx_mode = ec_netdev_set_multicast_list,
+    .ndo_set_mac_address = ec_netdev_set_mac_addr,
+    .ndo_get_stats = ec_netdev_query_stats,
+    .ndo_tx_timeout = ec_netdev_transmit_timeout,
+    .ndo_validate_addr = eth_validate_addr,
+    .ndo_do_ioctl = ec_netdev_ioctrl,
+};
+
+static struct pinctrl *ppc;
+//static struct pinctrl_state *pps;
+
+static int ethernet_set_pin_mux(struct platform_device *pdev)
+{
+	int ret = 0;
+
+	ppc = pinctrl_get_select_default(&pdev->dev);
+	if (IS_ERR(ppc)) {
+		pr_err("pinctrl_get_select_default() error, ret = %ld\n",
+			PTR_ERR(ppc));
+		goto error;
+	}
+
+	//printk("MFP_CTL30:0x%x\n", act_readl(MFP_CTL3));
+    putl((getl(MFP_CTL3) | 0x1<<30) , MFP_CTL3);
+	//printk("MFP_CTL31:0x%x\n", act_readl(MFP_CTL3));
+	//pr_info("ethernet pinctrl select state successfully\n");
+
+	
+	//pr_info("ethernet pinctrl select state successfully\n");
+
+	putl((getl(PAD_DRV0) & 0xffff3fff) | 0x8000, PAD_DRV0);
+	//printk("PAD_DRV0:0x%x\n", act_readl(PAD_DRV0));
+
+	
+	return ret;
+
+error:
+	ret = (int)PTR_ERR(ppc);
+	ppc = NULL;
+	return ret;
+
+}
+
+static void ethernet_put_pin_mux(void)
+{
+	if (ppc)
+		pinctrl_put(ppc);
+}
+
+static int ethernet_phy_probe(struct platform_device *pdev)
+{
+	struct device_node *phy_node = pdev->dev.of_node;
+	struct net_device *dev = g_eth_dev[0];
+	ec_priv_t *ecp = netdev_priv(dev);
+	const char *str;
+	str = of_get_property(phy_node, "compatible", NULL);
+	printk(KERN_DEBUG"ethernet phy's compatible: %s\n", str);
+
+	/* The standard phy that register accessed via MDIO only support ksz8841tl now */
+	if (of_device_is_compatible(phy_node, "realk,rtl8201")) {
+		ecp->phy_model = ETH_PHY_MODEL_RTL8201;
+		printk(KERN_INFO"phy model is rtl8201\n");
+	} else if (of_device_is_compatible(phy_node, "SR8201G,sr8201g")){
+		ecp->phy_model = ETH_PHY_MODEL_SR8201G;
+		printk(KERN_INFO "phy model is sr8201g\n");
+	}else { /* ATC2605 or error */
+		printk(KERN_INFO"compatible of %s: %s\n", phy_node->full_name, str);
+	}
+
+#ifndef CONFIG_POLL_PHY_STATE
+	ecp->phy_irq = irq_of_parse_and_map(phy_node, 0);
+	printk(KERN_DEBUG"%s ecp->phy_irq=%d\n", __func__, ecp->phy_irq);
+    if (ecp->phy_irq < 0) {
+		printk(KERN_ERR"No IRQ resource for tp\n");
+    	return -ENODEV;
+    }
+#endif
+	device_create_file(&pdev->dev, &dev_attr_phy_state);
+	return 0;
+}
+
+static int __exit ethernet_phy_remove(struct platform_device *pdev)
+{
+	device_remove_file(&pdev->dev, &dev_attr_phy_state);
+	return 0;
+}
+
+#if defined(CONFIG_PHY_REALTEK_RTL8201)
+/* ethernet phy match table */
+static const struct of_device_id ethernet_phy_of_match[] __initconst = {
+	{ .compatible = "realtk,rtl8201", },
+	{},
+};
+#define ETHERNET_PHY_DRV_NAME "rtl8201"
+#elif defined(CONFIG_PHY_CORECHIP_SR8201G)
+static const struct of_device_id ethernet_phy_of_match[] __initconst = {
+	{ .compatible = "SR8201G,sr8201g", },
+	{},
+};
+#define ETHERNET_PHY_DRV_NAME "sr8201g"
+#else
+static const struct of_device_id ethernet_phy_of_match[] __initconst = {
+	{ .compatible = " ", },
+	{},
+};
+#define ETHERNET_PHY_DRV_NAME " "
+#endif
+
+MODULE_DEVICE_TABLE(of, ethernet_phy_of_match);
+
+static struct platform_driver __refdata ethernet_phy_driver = {
+    .probe      = ethernet_phy_probe,
+    .remove     = __exit_p(ethernet_phy_remove),
+    .driver     = {
+        .name   = ETHERNET_PHY_DRV_NAME,
+        .owner  = THIS_MODULE,
+	.of_match_table = ethernet_phy_of_match,
+    },
+};
+
+static int __init asoc_phy_driver_init(void)
+{
+	return platform_driver_register(&ethernet_phy_driver);
+}
+
+static void __exit asoc_phy_driver_exit(void)
+{
+    platform_driver_unregister(&ethernet_phy_driver);
+}
+
+static int __init asoc_ethernet_probe(struct platform_device *pdev)
+{
+	struct net_device *dev;
+	ec_priv_t *ecp;
+	int ret;
+	struct resource *res;
+	int phy_mode = ETH_PHY_MODE_RMII; /* use rmii as default */
+	const char *phy_mode_str,*phy_status_str;
+	struct device_node *phy_node;
+	const char *str;
+
+	if (!get_def_mac_addr(pdev))
+		printk(KERN_ERR"use same default mac\n");
+
+	ret = ethernet_set_pin_mux(pdev);
+	if (ret)
+		return ret;
+
+	ret = of_property_read_string(pdev->dev.of_node, "status", &phy_status_str);
+	if (ret == 0 && strcmp(phy_status_str, "okay") != 0) {
+		dev_info(&pdev->dev, "disabled by DTS\n");
+		return -ENODEV;
+	}
+	
+	ret = of_property_read_string(pdev->dev.of_node, "phy-mode", &phy_mode_str);
+	if (ret) {
+		/* if get phy mode failed, use default rmii */
+		printk(KERN_ERR"get phy mode failed, use rmii\n");
+	} else {
+		printk(KERN_DEBUG"phy_mode_str: %s\n", phy_mode_str);
+		if (!strcmp(phy_mode_str, "rmii"))
+			phy_mode = ETH_PHY_MODE_RMII;
+		else if (!strcmp(phy_mode_str, "smii"))
+			phy_mode = ETH_PHY_MODE_SMII;
+		else
+			printk(KERN_ERR"unknown phy mode: %s, use rmii\n", phy_mode_str);
+	}
+
+	ethernet_clk = clk_get(NULL, CLKNAME_CMUMOD_ETHERNET);
+	ret = clk_prepare(ethernet_clk);
+	if(ret)
+		printk(KERN_ERR"prepare ethernet clock faild,errno: %d\n",-ret);
+
+	ret = ethernet_clock_config(phy_mode);
+	if (ret) {
+		ethernet_put_pin_mux();
+		return ret;
+	}
+
+	printk(KERN_DEBUG"pdev->name: %s\n", pdev->name ? pdev->name : "<null>");
+	dev = alloc_etherdev(sizeof(struct dev_priv));
+	if (NULL == dev)
+		return -ENOMEM;
+	SET_NETDEV_DEV(dev,&pdev->dev);
+	
+#ifdef CONFIG_PLATFORM_UBUNTU
+    strcpy(dev->name, "eth%d");
+#else
+    sprintf(dev->name, "eth%d", 0);
+#endif
+
+	ecp = netdev_priv(dev);
+	g_eth_dev[0] = dev;
+	ecp->rx_timeout=false;
+	ecp->phy_mode = phy_mode;
+#ifdef CONFIG_POLL_PHY_STATE
+	ecp->last_link_status = false;
+#endif
+	printk(KERN_DEBUG"phy_mode: %u\n", ecp->phy_mode);
+
+	phy_node = of_parse_phandle(pdev->dev.of_node, "phy-handle", 0);
+	if (!phy_node) {
+		printk(KERN_ERR"phy-handle of ethernet node can't be parsed\n");
+		return -EINVAL;
+	}
+
+	if(of_property_read_u32(pdev->dev.of_node, "phy_addr", &ecp->phy_addr)) {
+		printk(KERN_INFO "can't get phy addr form DTS \n");
+	}
+#if defined(CONFIG_PHY_REALTEK_RTL8201)
+	ecp->phy_model = ETH_PHY_MODEL_RTL8201;
+#elif defined(CONFIG_PHY_CORECHIP_SR8201G)
+	ecp->phy_model = ETH_PHY_MODEL_SR8201G;
+#else
+	ecp->phy_model = ETH_PHY_MODEL_NONE;
+#endif
+
+	ret=ethernet_parse_gpio(pdev->dev.of_node, "phy-power-gpios",&ecp->phy_power_gpio);
+	if(ret < 0){
+		printk(KERN_ERR" %s  can't get phy power gpio\n", __FUNCTION__);
+	}
+		
+	ret=ethernet_parse_gpio(pdev->dev.of_node, "phy-reset-gpios",&ecp->phy_reset_gpio);
+	if(ret < 0){
+		printk(KERN_ERR" %s  can't get phy reset gpio\n", __FUNCTION__);
+	}
+
+	if (gpio_is_valid(ecp->phy_power_gpio.gpio)) { 
+		gpio_request(ecp->phy_power_gpio.gpio, "phy_power_gpio");  
+	}
+	if (gpio_is_valid(ecp->phy_reset_gpio.gpio)) {
+		gpio_request(ecp->phy_reset_gpio.gpio, "phy_reset_gpio"); 
+	}
+	
+	str = of_get_property(phy_node, "compatible", NULL);
+	if (of_device_is_compatible(phy_node, "actions,atc260x-ethernet")) {
+		ecp->phy_model = ETH_PHY_MODEL_ATC2605;
+		printk(KERN_DEBUG"phy model is ATC2605\n");
+		/* platform device atc260x-ethernet's been created by atc260x_dev.c */
+	} else {
+		/* all other standard phy that register accessed via MDIO are
+		 * recognized by ethernet_phy_probe() */
+		struct platform_device *phy_pdev;
+		const char *name = strstr(str, ",");
+		phy_pdev = of_platform_device_create(phy_node, ++name, pdev->dev.parent);
+		printk(KERN_DEBUG"ethernet phy name: %s\n", name);
+		if (!phy_pdev) {
+			printk(KERN_ERR"of_platform_device_create(%s) failed\n", name);
+			goto err_free;
+		}
+		ecp->phy_pdev = phy_pdev;
+	}
+
+	if (ret) {
+		printk(KERN_ERR"register ethernet phy driver failed\n");
+		goto err_free_phy;
+	}
+	printk(KERN_DEBUG"phy_model: %u\n", ecp->phy_model);
+
+	ret = -EINVAL;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		printk(KERN_ERR"no mem resource\n");
+		goto err_free_phy;
+	}
+	ecp->hwrp = (volatile ethregs_t *)IO_ADDRESS(res->start);
+	printk(KERN_DEBUG"res->start: %p, ecp->hwrp: %p\n",
+			(void *)res->start, (void *)ecp->hwrp);
+
+	ecp->mac_irq = dev->irq = platform_get_irq(pdev, 0);
+
+	if (ETH_PHY_MODE_SMII == phy_mode)
+		ecp->hwrp->er_macctrl = MAC_CTRL_SMII; /* use smii interface */
+	else
+		ecp->hwrp->er_macctrl = MAC_CTRL_RMII; /* use rmii interface */
+
+	dev->watchdog_timeo = EC_TX_TIMEOUT;
+	dev->netdev_ops = &ec_netdev_ops;
+	ec_set_ethtool_ops(dev);
+	ep_set_phy_ops(ecp);
+
+	ret = register_netdev(dev);
+	if (ret < 0) {
+		printk(KERN_ERR"register netdev ret:%d, [irq:%d, dev name:%s]\n",
+				ret, dev->irq, dev->name ? dev->name : "Unknown");
+		g_eth_dev[0] = NULL;
+		goto err_free_phy;
+	}
+	device_create_file(&dev->dev, &dev_attr_netif_msg);
+#ifdef ETH_TEST_MODE
+	device_create_file(&dev->dev, &dev_attr_continuity);
+	device_create_file(&dev->dev, &dev_attr_send_pattern);
+	device_create_file(&dev->dev, &dev_attr_test_mode);
+#endif
+	resume_queue = create_workqueue("kethernet_resume_work");
+	if (!resume_queue) {
+		printk(KERN_ERR"create workqueue kethernet_resume_work failed\n");
+		ret = -ENOMEM;
+		goto err_free_device_file;
+	}
+
+	INIT_DELAYED_WORK(&resume_work, ethernet_resume_handler);
+
+#ifdef DETECT_POWER_SAVE
+	power_save_queue = create_workqueue("kethernet_power_save_work");
+	if (!power_save_queue) {
+		ret = -ENOMEM;
+		goto error_free_resume_queue;
+	}
+	INIT_WORK(&ecp->power_save_work, ethernet_power_save);
+#endif
+
+	ecp->ethernet_work_queue= create_workqueue("ethernet_work_queue");
+	if(!ecp->ethernet_work_queue){
+		printk(KERN_ERR"create workqueue ethernet_work_queue failed\n");
+		ret = -ENOMEM;
+		goto err_remove_power_queue;
+	}
+	INIT_WORK(&ecp->hardware_reset_work,hardware_reset_do_work);
+#ifdef CONFIG_POLL_PHY_STATE
+	ecp->phy_detect_queue = create_workqueue("phy_detect_work");
+	if (!ecp->phy_detect_queue) {
+		ret = -ENOMEM;
+		goto err_remove_work_queue;
+	}
+	INIT_DELAYED_WORK(&ecp->phy_detect_work, phy_detect_func);
+#else
+	INIT_WORK(&ecp->netphy_irq_handle_work,netphy_irq_handle_do_work);
+#endif
+	printk(KERN_INFO"ethernet %s probe finish\n",dev->name);
+	return 0;
+err_remove_work_queue:
+	destroy_workqueue(ecp->ethernet_work_queue);
+err_remove_power_queue:
+#ifdef DETECT_POWER_SAVE
+	destroy_workqueue(power_save_queue);
+error_free_resume_queue:
+#endif
+	destroy_workqueue(resume_queue);
+err_free_device_file:
+	device_remove_file(&dev->dev, &dev_attr_netif_msg);
+#ifdef ETH_TEST_MODE
+	device_remove_file(&dev->dev, &dev_attr_send_pattern);
+	device_remove_file(&dev->dev, &dev_attr_test_mode);
+	device_remove_file(&dev->dev, &dev_attr_continuity);
+#endif
+	unregister_netdev(dev);
+err_free_phy:
+	if(ecp->phy_pdev)
+		platform_device_unregister(ecp->phy_pdev);
+err_free:	
+	if (dev) {
+		free_netdev(dev);
+		dev = NULL;
+	}
+	return ret;
+}
+
+static int __exit asoc_ethernet_remove(struct platform_device *pdev)
+{
+	struct net_device *dev = g_eth_dev[0];
+	ec_priv_t *ecp = netdev_priv(dev);
+
+#ifdef CONFIG_POLL_PHY_STATE
+	if(ecp->phy_detect_queue != NULL){
+		cancel_delayed_work_sync(&ecp->phy_detect_work);
+		destroy_workqueue(ecp->phy_detect_queue);
+	}
+#endif
+	if (dev) {
+		device_remove_file(&dev->dev, &dev_attr_netif_msg);
+#ifdef ETH_TEST_MODE
+		device_remove_file(&dev->dev, &dev_attr_send_pattern);
+		device_remove_file(&dev->dev, &dev_attr_test_mode);
+		device_remove_file(&dev->dev, &dev_attr_continuity);
+#endif
+		if(NULL != ecp->phy_pdev){
+			platform_device_unregister(ecp->phy_pdev);
+		}
+		if(NULL != ecp->ethernet_work_queue)
+			destroy_workqueue(ecp->ethernet_work_queue);
+		unregister_netdev(dev);
+		free_netdev(dev);
+	}
+	if (resume_queue)
+		destroy_workqueue(resume_queue);
+
+#ifdef DETECT_POWER_SAVE
+	destroy_workqueue(power_save_queue);
+#endif
+
+	platform_driver_unregister(&ethernet_phy_driver);
+	if(ethernet_clk != NULL){
+		clk_disable(ethernet_clk);
+		clk_unprepare(ethernet_clk);
+		clk_put(ethernet_clk);
+  }
+
+	ethernet_put_pin_mux();
+	return 0;
+}
+
+
+/* Match table for of_platform binding */
+static const struct of_device_id actions_ethernet_of_match[] __initconst = {
+	{ .compatible = "actions,owl-ethernet", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, actions_ethernet_of_match);
+
+static struct platform_driver __refdata asoc_ethernet_driver = {
+    .probe      = asoc_ethernet_probe,
+    .remove     = __exit_p(asoc_ethernet_remove),
+    .driver     = {
+        .name   = "owl-ethernet",
+        .owner  = THIS_MODULE,
+	.of_match_table = actions_ethernet_of_match,
+    },
+    .suspend     = asoc_ethernet_suspend,
+    .resume     = asoc_ethernet_resume,
+};
+
+static int __init asoc_ethernet_init(void)
+{
+	printk("%s %d\n",__FUNCTION__,__LINE__);
+    return platform_driver_register(&asoc_ethernet_driver);
+}
+module_init(asoc_ethernet_init);
+
+static void __exit asoc_ethernet_exit(void)
+{
+    platform_driver_unregister(&asoc_ethernet_driver);
+}
+module_exit(asoc_ethernet_exit);
+
+module_init(asoc_phy_driver_init);
+module_exit(asoc_phy_driver_exit);
+
+MODULE_ALIAS("platform:asoc-ethernet");
+MODULE_DESCRIPTION("asoc_ethernet pin");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Actions Semi, Inc");
+
+
+
diff --git a/drivers/net/ethernet/acts/ethctrl.h b/drivers/net/ethernet/acts/ethctrl.h
new file mode 100755
index 0000000..4747e9d
--- /dev/null
+++ b/drivers/net/ethernet/acts/ethctrl.h
@@ -0,0 +1,248 @@
+/******************************************************************************
+ ethctrl.h -- ethernet controller header for GL5201
+ 
+ author : yunchf  @Actions 
+ date : 2010-04-08 
+ version 0.1
+
+ date : 2010-08-10
+ version 1.0
+ 
+******************************************************************************/
+#ifndef _ETHCTRL_H_
+#define _ETHCTRL_H_
+
+/*****************************************************************************/
+
+//#define DETECT_POWER_SAVE
+
+#include <linux/spinlock.h>
+#include <linux/mii.h>
+#include <linux/ethtool.h>
+#include <linux/netdevice.h>
+#include "ec_hardware.h"
+
+#ifdef DETECT_POWER_SAVE
+#include <linux/timer.h>
+#endif
+
+#define MULTICAST_LIST_LEN 14
+#define ETH_MAC_LEN 6
+#define ETH_CRC_LEN 4
+#define RX_RING_SIZE 64
+
+#define RX_RING_MOD_MASK  (RX_RING_SIZE - 1)
+#ifndef ETH_TEST_MODE
+#define TX_RING_SIZE 32
+#else
+#define TX_RING_SIZE 128
+#endif
+
+#define TX_RING_MOD_MASK (TX_RING_SIZE - 1)
+#define TATOL_TXRX_BDS (RX_RING_SIZE + TX_RING_SIZE)
+
+#ifdef CONFIG_POLL_PHY_STATE
+#define PHY_RESUME_DELAY 2000
+#define PHY_DETECT_DUTY 300
+#define PHY_DETECT_RESUME 500
+#endif
+
+#define ETH_SPEED_10M 10
+#define ETH_SPEED_100M 100
+#define ETH_DUP_HALF 1
+#define ETH_DUP_FULL 2
+#define ETH_PKG_MIN 64
+#define ETH_PKG_MAX 1518
+#define PKG_RESERVE 18
+
+#define PKG_MIN_LEN (ETH_PKG_MIN)
+
+/* 0x600, reserve 18 byes for align adjustment */
+#define PKG_MAX_LEN (ETH_PKG_MAX + PKG_RESERVE)
+
+#define PHY_ADDR_LIMIT 0x20
+
+/* ANSI Color codes */
+#define VT(CODES)  "\033[" CODES "m"
+#define VT_NORMAL  VT("")
+#define VT_RED	   VT("0;32;31")
+#define VT_GREEN   VT("1;32")
+#define VT_YELLOW  VT("1;33")
+#define VT_BLUE    VT("1;34")
+#define VT_PURPLE  VT("0;35")
+
+#define EC_TRACED 0
+//#define EC_DEBUG
+#undef RX_DEBUG
+#undef TX_DEBUG
+//#define RX_DEBUG
+//#define TX_DEBUG
+
+//#define ETHENRET_MAC_LOOP_BACK
+//#define ETHENRET_PHY_LOOP_BACK
+//#define WORK_IN_10M_MODE
+
+#define _DBG(level, fmt, ...)  \
+    printk(level "%s():%d: " fmt, \
+        __func__, __LINE__, ## __VA_ARGS__)
+
+//#ifdef EC_DEBUG
+//#define printk(fmt, args...)  _DBG(KERN_INFO, fmt, ## args)
+//#else
+//#define printk(fmt, args...)  do {} while(0)
+//#endif
+
+//#define printk(fmt, args...)   _DBG(KERN_ERR, fmt, ## args)
+
+#define _INFO(color, fmt, ...) \
+    printk(color "" fmt ""VT_NORMAL, ## __VA_ARGS__)
+
+/* mainly used in test code */
+#define INFO_PURLPLE(fmt, args...) _INFO(VT_PURPLE, fmt, ## args)
+#define INFO_RED(fmt, args...)     _INFO(VT_RED, fmt, ## args)
+#define INFO_GREEN(fmt, args...)   _INFO(VT_GREEN, fmt, ## args)
+#define INFO_BLUE(fmt, args...)    _INFO(VT_BLUE, fmt, ## args)
+
+//#define EC_NOP __asm__ __volatile__ ("nop; nop; nop; nop" : :)
+#define EC_NOP
+
+enum eth_phy_model {
+	ETH_PHY_MODEL_NONE = 0,
+	ETH_PHY_MODEL_ATC2605, /* same as fdp110 */
+	ETH_PHY_MODEL_KSZ8041TL, /* Micrel KSZ8041TL */
+	ETH_PHY_MODEL_RTL8201, /* Realtek RTL8201 */
+	ETH_PHY_MODEL_SR8201G, /* Corechip SR8201G */
+	ETH_PHY_MODEL_MAX = ETH_PHY_MODEL_SR8201G,
+};
+
+enum eth_phy_mode {
+	ETH_PHY_MODE_RMII = 0,
+	ETH_PHY_MODE_SMII,
+	ETH_PHY_MODE_MAX,
+};
+
+typedef struct mac_list {
+    int     count;
+    char    mac_array[MULTICAST_LIST_LEN][ETH_MAC_LEN];
+} mac_list_t;
+
+struct owl_ethernet_gpio {
+    int gpio;
+    int active;
+};
+
+typedef struct phy_info phy_info_t;
+
+typedef struct dev_priv {
+    volatile ethregs_t *hwrp;
+    spinlock_t lock;
+    struct net_device *netdev;
+    struct atc260x_dev *atc260x;
+    unsigned int mac_irq;
+    unsigned int phy_irq;
+    unsigned int phy_model;
+    unsigned int phy_mode;
+#ifdef ETH_TEST_MODE
+    unsigned int test_mode;
+#endif
+
+    struct sk_buff *tx_skb[TX_RING_SIZE];       /* temp. save transmited skb */
+    ec_bd_t *tx_bd_base;
+    ec_bd_t *cur_tx;            /* the next tx free ring entry */
+    ec_bd_t *dirty_tx;          /* the ring entry to be freed */
+    ushort  skb_dirty;          /* = dirty_tx - tx_bd_base */
+    ushort  skb_cur;            /* = cur_tx - tx_bd_base */
+    dma_addr_t tx_bd_paddr;
+    bool    tx_full;
+
+    struct sk_buff *rx_skb[RX_RING_SIZE];       /* rx_bd buffers */
+    ec_bd_t *rx_bd_base;
+    ec_bd_t *cur_rx;            /* the next rx free ring entry */
+    dma_addr_t	rx_bd_paddr;
+
+#if 0
+    struct workqueue_struct *tx_wq;
+    struct work_struct tx_work;
+    struct work_struct tx_timeout_work;
+    struct sk_buff_head local_tx_queue;
+
+    struct workqueue_struct *rx_wq;
+    struct work_struct rx_work;
+#endif
+
+#ifdef DETECT_POWER_SAVE
+    struct timer_list detect_timer;
+    struct work_struct power_save_work;
+#endif
+	struct work_struct hardware_reset_work;
+	struct workqueue_struct *ethernet_work_queue;
+#ifdef CONFIG_POLL_PHY_STATE
+	struct workqueue_struct *phy_detect_queue;
+	struct delayed_work phy_detect_work;
+#else
+	struct work_struct netphy_irq_handle_work;
+#endif
+    //int phy_id;
+    int     phy_addr;
+    int     speed;
+    int     duplex;
+    bool    pause;
+    bool    autoneg;
+    phy_info_t *phy_ops;
+    struct mii_if_info mii_info;
+
+    int     msg_enable;
+    const char *mac_addr;       /* XXX : careful later added */
+    char    overrided_mac[ETH_MAC_LEN];
+    mac_list_t multicast_list;
+    bool    mac_overrided;
+    bool    multicast;
+    bool    all_multicast;
+    bool    promiscuous;
+    bool    opened;
+    bool    linked;
+#ifdef CONFIG_POLL_PHY_STATE
+	bool    last_link_status;
+#endif
+    bool    rx_timeout;
+#ifdef DETECT_POWER_SAVE
+    bool    enable;             // hardware enabled
+#endif
+	struct platform_device *phy_pdev;
+	struct owl_ethernet_gpio phy_power_gpio;
+	struct owl_ethernet_gpio phy_reset_gpio;
+} ec_priv_t;
+
+
+struct phy_info {
+    int     id;
+    char   *name;
+    int     (*phy_hw_init) (ec_priv_t * ecp);
+    int     (*phy_init) (ec_priv_t * ecp);
+    int     (*phy_suspend) (ec_priv_t * ecp, bool power_down);
+    int     (*phy_setup_advert) (ec_priv_t * ecp, int advertising);
+    int     (*phy_setup_forced) (ec_priv_t * ecp, int speed, int duplex);
+    int     (*phy_setup_aneg) (ec_priv_t * ecp, bool autoneg);
+    int     (*phy_setup_loopback) (ec_priv_t * ecp, bool loopback);
+    int     (*phy_read_status) (ec_priv_t * ecp);
+    int     (*phy_get_link) (ec_priv_t * ecp);
+};
+
+
+extern unsigned short (*read_phy_reg)(ec_priv_t *, unsigned short);
+extern int (*write_phy_reg)(ec_priv_t *, unsigned short, unsigned short);
+
+void ep_set_phy_ops(ec_priv_t * ecp);
+void ec_set_ethtool_ops(struct net_device *netdev);
+
+
+static inline bool need_change_speed(unsigned short new_bmcr, unsigned short old_bmcr)
+{
+    return (((new_bmcr ^ old_bmcr) & (BMCR_SPEED100 | BMCR_FULLDPLX)) == BMCR_FULLDPLX);
+}
+
+
+
+/******************************************************************************/
+
+#endif                          /* _ETHCTRL_H_ */
diff --git a/drivers/net/ethernet/sg8201g/Kconfig b/drivers/net/ethernet/sg8201g/Kconfig
new file mode 100755
index 0000000..e1c8725
--- /dev/null
+++ b/drivers/net/ethernet/sg8201g/Kconfig
@@ -0,0 +1,5 @@
+config NET_VENDOR_SG8201G
+	tristate "Actions Ethernet driver(SG8021G)"
+	default n
+	---help---
+		enable Actions Semi 520X ethernet driver
diff --git a/drivers/net/ethernet/sg8201g/Makefile b/drivers/net/ethernet/sg8201g/Makefile
new file mode 100755
index 0000000..d42948e
--- /dev/null
+++ b/drivers/net/ethernet/sg8201g/Makefile
@@ -0,0 +1,9 @@
+
+EXTRA_CFLAGS += -DDEF_LINUX 
+
+ifeq ($(CONFIG_MII),y)
+EXTRA_CFLAGS += -DMII
+endif
+obj-$(CONFIG_NET_VENDOR_SG8201G)	+= sg8201g_ethernet.o
+sg8201g_ethernet-objs := ec_ethtool.o ec_phy.o ethctrl.o
+
diff --git a/drivers/net/ethernet/sg8201g/ec_ethtool.c b/drivers/net/ethernet/sg8201g/ec_ethtool.c
new file mode 100755
index 0000000..c85c2c7
--- /dev/null
+++ b/drivers/net/ethernet/sg8201g/ec_ethtool.c
@@ -0,0 +1,592 @@
+/*******************************************************************************
+ec_ethtool.c -- ethtool hooks for ethernet controller embedded in GL5201
+
+author : yunchf @Actions
+date : 2010-06-10
+version 0.1
+
+date : 2010-08-10
+version 1.0
+
+questions:
+1. set_pauseparam() hook should be modified later
+
+*******************************************************************************/
+
+#include "ethctrl.h"
+
+
+static const char *g_driver_name = "GL5201-eth-ctrl";
+static const char *g_driver_version = "Version - 0.1";
+
+#define ETH_STATS_LEN  (sizeof(struct net_device_stats) / sizeof(unsigned long))
+
+#define ETHTOOL_INFO_STR_LEN 32
+
+#define ECMD_SUPPORTED_MEDIA  \
+    (SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full | \
+    SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full)
+
+#define ECMD_ADVERTISED_MEDIA \
+    (ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full | \
+    ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Full)
+
+typedef enum {
+    EC_FC_NONE = 0,
+    EC_FC_TX_PAUSE,
+    EC_FC_RX_PAUSE,
+    EC_FC_FULL
+} ec_flowctrl_type_t;
+
+
+struct hw_regs_ranges {
+    int     start;
+    int     end;
+    int     interval;
+};
+
+
+/*------------------------------ ethtool hooks ------------------------------*/
+
+/**
+ * et_get_settings -- get transceiver's settings that are specified by @cmd
+ * @dev : target net device
+ * @cmd : requested command
+ * return 0 if success, otherwise fail
+ */
+static int et_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+    ec_priv_t *ecp = netdev_priv(dev);
+    struct mii_if_info *mii = &ecp->mii_info;
+    unsigned int advert;
+    unsigned int bmcr;
+
+
+    cmd->supported = (ECMD_SUPPORTED_MEDIA | SUPPORTED_Autoneg | SUPPORTED_TP | SUPPORTED_MII);
+
+    cmd->port = PORT_MII;       /* twisted-pair (TP) supported only */
+    cmd->transceiver = XCVR_INTERNAL;   /* internal transceiver supported only */
+    cmd->phy_address = mii->phy_id;
+    cmd->advertising = ADVERTISED_TP | ADVERTISED_MII;
+
+    /* get phy's supported advertise */
+    advert = mii->mdio_read(dev, mii->phy_id, MII_ADVERTISE);
+    if (advert & ADVERTISE_10HALF) {
+        cmd->advertising |= ADVERTISED_10baseT_Half;
+    }
+    if (advert & ADVERTISE_10FULL) {
+        cmd->advertising |= ADVERTISED_10baseT_Full;
+    }
+    if (advert & ADVERTISE_100HALF) {
+        cmd->advertising |= ADVERTISED_100baseT_Half;
+    }
+    if (advert & ADVERTISE_100FULL) {
+        cmd->advertising |= ADVERTISED_100baseT_Full;
+    }
+
+    /* get current speed, duplex and auto-negotiation mode */
+    bmcr = mii->mdio_read(dev, mii->phy_id, MII_BMCR);
+    if (bmcr & BMCR_ANENABLE) {
+        unsigned int lpa;
+        unsigned int neg;
+
+        cmd->autoneg = AUTONEG_ENABLE;
+        cmd->advertising |= ADVERTISED_Autoneg;
+
+        lpa = mii->mdio_read(dev, mii->phy_id, MII_LPA);
+        neg = mii_nway_result(advert & lpa);
+
+        if (neg == LPA_100FULL || neg == LPA_100HALF) {
+            cmd->speed = SPEED_100;
+        } else {
+            cmd->speed = SPEED_10;
+        }
+
+        if (neg == LPA_100FULL || neg == LPA_10FULL) {
+            cmd->duplex = DUPLEX_FULL;
+            mii->full_duplex = 1;       /* set-settings() does not set it if auto-neg */
+        } else {
+            cmd->duplex = DUPLEX_HALF;
+            mii->full_duplex = 0;
+        }
+    } else {
+        cmd->autoneg = AUTONEG_DISABLE;
+        cmd->speed = (bmcr & BMCR_SPEED100) ? SPEED_100 : SPEED_10;
+        cmd->duplex = (bmcr & BMCR_FULLDPLX) ? DUPLEX_FULL : DUPLEX_HALF;
+    }
+
+    /* ignore maxtxpkt, maxrxpkt for now */
+
+    return 0;
+
+}
+
+#if 0
+static int et_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+    ec_priv_t *ecp = netdev_priv(dev);
+    int     err;
+
+    spin_lock_irq(&ecp->lock);
+    err = mii_ethtool_gset(&ecp->mii_info, cmd);
+    spin_unlock_irq(&ecp->lock);
+
+    /* the ethernet controller does not support 1000baseT */
+    cmd->supported &= ~(SUPPORTED_1000baseT_Half | SUPPORTED_1000baseT_Full);
+
+    return (err);
+}
+
+
+static int et_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+    ec_priv_t *ecp = netdev_priv(dev);
+    int     err;
+
+    printk("%s() autoneg : %d, speed: %d, duplex: %d\n", __func__, cmd->autoneg,
+           cmd->speed, cmd->duplex);
+    spin_lock_irq(&ecp->lock);
+    err = mii_ethtool_sset(&ecp->mii_info, cmd);
+    spin_unlock_irq(&ecp->lock);
+
+    return (err);
+}
+#endif
+
+
+/**
+ * verify_et_cmd -- check the validity of requested command
+ * @mii : mii interface to setup 
+ * @cmd : requested command
+ * return 0 if requested command is valid, -EINVAL if not
+ */
+static inline int verify_et_cmd(const struct ethtool_cmd *cmd, const struct mii_if_info *mii)
+{
+    /* only support 10M and 100M currently */
+    if (SPEED_10 != cmd->speed && SPEED_100 != cmd->speed) {
+        return (-EINVAL);
+    }
+    if (DUPLEX_HALF != cmd->duplex && DUPLEX_FULL != cmd->duplex) {
+        return (-EINVAL);
+    }
+    if (PORT_MII != cmd->port) {
+        return (-EINVAL);
+    }
+    if (XCVR_INTERNAL != cmd->transceiver) {
+        return (-EINVAL);
+    }
+    if (cmd->phy_address != mii->phy_id) {
+        return (-EINVAL);
+    }
+    if (AUTONEG_DISABLE != cmd->autoneg && AUTONEG_ENABLE != cmd->autoneg) {
+        return (-EINVAL);
+    }
+    if (AUTONEG_ENABLE == cmd->autoneg) {
+        if (0 == (cmd->advertising & ECMD_ADVERTISED_MEDIA)) {
+            return (-EINVAL);
+        }
+    }
+
+    return (0);
+}
+
+
+/**
+ * set_autoneg_settings -- to setup @mii if the requested @cmd supports auto-negotiation 
+ */
+static void set_autoneg_settings(const struct ethtool_cmd *cmd, struct mii_if_info *mii)
+{
+    struct net_device *dev = mii->dev;
+    unsigned int bmcr;
+    unsigned int advert;
+    unsigned int tmp;
+
+
+    /* advertise only what has been requested */
+    advert = mii->mdio_read(dev, mii->phy_id, MII_ADVERTISE);
+    tmp = advert & ~(ADVERTISE_ALL | ADVERTISE_100BASE4);
+
+    if (cmd->advertising & ADVERTISED_10baseT_Half) {
+        tmp |= ADVERTISE_10HALF;
+    }
+    if (cmd->advertising & ADVERTISED_10baseT_Full) {
+        tmp |= ADVERTISE_10FULL;
+    }
+    if (cmd->advertising & ADVERTISED_100baseT_Half) {
+        tmp |= ADVERTISE_100HALF;
+    }
+    if (cmd->advertising & ADVERTISED_100baseT_Full) {
+        tmp |= ADVERTISE_100FULL;
+    }
+
+    if (advert != tmp) {
+        mii->mdio_write(dev, mii->phy_id, MII_ADVERTISE, tmp);
+        mii->advertising = tmp;
+    }
+
+    /* enable auto-negotiation, and force a re-negotiate */
+    bmcr = mii->mdio_read(dev, mii->phy_id, MII_BMCR);
+    bmcr |= (BMCR_ANENABLE | BMCR_ANRESTART);
+    mii->mdio_write(dev, mii->phy_id, MII_BMCR, bmcr);
+
+    mii->force_media = 0;
+
+    return;
+}
+
+
+/**
+ * set_forced_settings -- to setup @mii if the requested @cmd does not support auto-negotiation 
+ */
+static void set_forced_settings(const struct ethtool_cmd *cmd, struct mii_if_info *mii)
+{
+    struct net_device *dev = mii->dev;
+    unsigned int bmcr;
+    unsigned int new_bmcr;
+
+
+    /* disable auto-negotiation, set speed and duplexity */
+    bmcr = mii->mdio_read(dev, mii->phy_id, MII_BMCR);
+    new_bmcr = bmcr & ~(BMCR_ANENABLE | BMCR_SPEED100 | BMCR_FULLDPLX);
+
+    if (SPEED_100 == cmd->speed) {
+        new_bmcr |= BMCR_SPEED100;
+    }
+
+    if (DUPLEX_FULL == cmd->duplex) {
+        new_bmcr |= BMCR_FULLDPLX;
+        mii->full_duplex = 1;
+    } else {
+        mii->full_duplex = 0;
+    }
+
+    if (bmcr != new_bmcr) {
+
+        /* you can get a explanation from ec_netdev_ioctl() for SIOCSMIIREG command */
+        if (need_change_speed(new_bmcr, bmcr)) {
+            unsigned int changed = new_bmcr;
+
+            changed ^= BMCR_SPEED100;   /* exchange speed only */
+            mii->mdio_write(dev, mii->phy_id, MII_BMCR, changed);
+        }
+        mii->mdio_write(dev, mii->phy_id, MII_BMCR, new_bmcr);
+    }
+
+    mii->force_media = 1;
+
+    return;
+}
+
+
+/**
+ * et_set_settings -- setup transceiver of @dev net device according the requested @cmd
+ * @dev : net device to configure 
+ * @cmd : requested command
+ * return 0 if success, otherwise fail
+ */
+static int et_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+    ec_priv_t *ecp = netdev_priv(dev);
+    struct mii_if_info *mii = &ecp->mii_info;
+
+
+    if (verify_et_cmd(cmd, mii)) {
+        return (-EINVAL);
+    }
+
+    if (AUTONEG_ENABLE == cmd->autoneg) {
+        set_autoneg_settings(cmd, mii);
+    } else {
+        set_forced_settings(cmd, mii);
+    }
+
+    return (0);
+}
+
+
+/**
+ * et_get_drvinfo -- get driver's information of @dev net device
+ */
+static void et_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
+{
+    strncpy(info->driver, g_driver_name, ETHTOOL_INFO_STR_LEN);
+    strncpy(info->version, g_driver_version, ETHTOOL_INFO_STR_LEN);
+}
+
+
+
+
+/**
+ * et_get_regs_len -- get the number of registers of MAC
+ */
+static int et_get_regs_len(struct net_device *dev)
+{
+    int     len = 0;
+
+
+
+    return (len);
+}
+
+
+/**
+ * et_get_regs -- dump all register of MAC
+ */
+static void et_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *buf)
+{
+//    ec_priv_t *ecp = netdev_priv(dev);
+//    struct hw_regs_ranges *rgs = BUILD_REGS_RANGES_ARRAY();
+//    unsigned long *bufp = (unsigned long *) buf;
+//    unsigned long *reg = NULL;
+//
+//    spin_lock_irq(&ecp->lock);
+//    regs->version = 0;
+//    while (rgs->start < rgs->end) {
+//        reg = (unsigned long *) ((char *) ecp->hwrp + rgs->start);
+//        while ((char *) reg - (char *) ecp->hwrp <= rgs->end) {
+//            *bufp = *reg;
+//            reg += rgs->interval;
+//            bufp++;
+//        }
+//        rgs++;
+//    }
+//
+//    spin_unlock_irq(&ecp->lock);
+}
+
+//static void    (*get_wol)(struct net_device *, struct ethtool_wolinfo *);
+//static int (*set_wol)(struct net_device *, struct ethtool_wolinfo *);
+
+
+static u32 et_get_msglevel(struct net_device *dev)
+{
+    ec_priv_t *ecp = netdev_priv(dev);
+    return (ecp->msg_enable);
+}
+
+
+static void et_set_msglevel(struct net_device *dev, u32 level)
+{
+    ec_priv_t *ecp = netdev_priv(dev);
+    ecp->msg_enable = level;
+}
+
+
+/**
+ * et_nway_reset -- re-negotiate the transceiver of @dev net device
+ * @dev : target net device
+ * return 0 if success, -EINVAL if fail
+ */
+static int et_nway_reset(struct net_device *dev)
+{
+    ec_priv_t *ecp = netdev_priv(dev);
+    struct mii_if_info *mii = &ecp->mii_info;
+    int     err = -EINVAL;
+    int     bmcr;
+
+    /* if autoneg is off, it's an error */
+    bmcr = mii->mdio_read(dev, mii->phy_id, MII_BMCR);
+
+    if (bmcr & BMCR_ANENABLE) {
+        bmcr |= BMCR_ANRESTART;
+        mii->mdio_write(dev, mii->phy_id, MII_BMCR, bmcr);
+        err = 0;
+    }
+
+    return (err);
+}
+
+
+static u32 et_get_link(struct net_device *dev)
+{
+
+   // ec_priv_t *ecp = netdev_priv(dev);
+    //return (ecp->phy_ops->phy_get_link(ecp));
+    return (netif_carrier_ok(dev) ? 1 : 0);
+}
+
+//static int (*get_eeprom_len)(struct net_device *);
+//static int (*get_eeprom)(struct net_device *, struct ethtool_eeprom *, u8 *);
+//static int (*set_eeprom)(struct net_device *, struct ethtool_eeprom *, u8 *);
+//static int (*get_coalesce)(struct net_device *, struct ethtool_coalesce *);
+//static int (*set_coalesce)(struct net_device *, struct ethtool_coalesce *);
+//static void    ec_get_ringparam(struct net_device *dev, struct ethtool_ringparam *ring)
+
+//static int (*set_ringparam)(struct net_device *, struct ethtool_ringparam *);
+
+
+static void et_get_pauseparam(struct net_device *dev, struct ethtool_pauseparam *epp)
+{
+    ec_priv_t *ecp = netdev_priv(dev);
+    volatile ethregs_t *regs = ecp->hwrp;
+
+    epp->autoneg = ecp->autoneg ? 1 : 0;
+    epp->tx_pause = regs->er_flowctrl & EC_FLOWCTRL_TPE ? 1 : 0;
+    epp->rx_pause = regs->er_flowctrl & EC_FLOWCTRL_RPE ? 1 : 0;
+}
+
+
+static inline int set_flowctrl_type(struct net_device *dev, ec_flowctrl_type_t fc)
+{
+    ec_priv_t *ecp = netdev_priv(dev);
+    volatile ethregs_t *hw_regs = ecp->hwrp;
+
+    // modify later,  relationship between different bits of flow control of csr20
+    switch (fc) {
+        case EC_FC_FULL:
+            hw_regs->er_flowctrl |= EC_FLOWCTRL_ENALL;
+            break;
+        case EC_FC_RX_PAUSE:
+            hw_regs->er_flowctrl &= ~EC_FLOWCTRL_ENALL;
+            hw_regs->er_flowctrl |= EC_FLOWCTRL_FCE | EC_FLOWCTRL_RPE;
+            break;
+        case EC_FC_TX_PAUSE:
+            hw_regs->er_flowctrl &= ~EC_FLOWCTRL_ENALL;
+            hw_regs->er_flowctrl |= EC_FLOWCTRL_TUE | EC_FLOWCTRL_TPE | EC_FLOWCTRL_FCE;
+            break;
+        case EC_FC_NONE:
+            hw_regs->er_flowctrl &= ~EC_FLOWCTRL_ENALL;
+            break;
+        default:
+            return (-1);
+    }
+    return (0);
+}
+
+
+/**
+ * et_set_pauseparam --  
+ */
+// XXXX NOTE :  modify later , in fact i dont know how to do it  currently
+static int et_set_pauseparam(struct net_device *dev, struct ethtool_pauseparam *epp)
+{
+    ec_priv_t *ecp = netdev_priv(dev);
+    ec_flowctrl_type_t type;
+    int     err = 0;
+
+    if (epp->autoneg) {
+
+        //set advertise to support pause
+        if (ecp->autoneg) {
+            if (netif_running(dev)) {
+                netif_carrier_off(dev); // stop rx and tx is better
+            }
+            ecp->phy_ops->phy_setup_advert(ecp, ADVERTISE_ALL | ADVERTISE_PAUSE_CAP);
+            ecp->phy_ops->phy_setup_aneg(ecp, true);    // can rise link change interrupt?
+            ecp->phy_ops->phy_read_status(ecp);
+
+            //ecp->phy_ops->phy_get_link(ecp);
+        } else {
+            return (-1);
+        }
+    } else {
+        if (epp->rx_pause && epp->tx_pause) {
+            type = EC_FC_FULL;
+        } else if (epp->rx_pause && !epp->tx_pause) {
+            type = EC_FC_RX_PAUSE;
+        } else if (!epp->rx_pause && epp->tx_pause) {
+            type = EC_FC_TX_PAUSE;
+        } else {
+            type = EC_FC_NONE;
+        }
+        err = set_flowctrl_type(dev, type);
+    }
+    return (err);
+}
+
+
+struct stats_str {
+    char    string[ETH_GSTRING_LEN];
+};
+
+
+static struct stats_str g_stats_descs[ETH_STATS_LEN] = {
+    {"rx_packets"}, {"tx_packets"},
+    {"rx_bytes"}, {"tx_bytes"},
+    {"rx_errors"}, {"tx_errors"},
+    {"rx_dropped"}, {"tx_dropped"},
+    {"multicast"}, {"collisions"},
+    {"rx_length_errors"}, {"rx_over_errors"},
+    {"rx_crc_errors"}, {"rx_frame_errors"},
+    {"rx_fifo_errors"}, {"rx_missed_errors"},
+    {"tx_aborted_errors"}, {"tx_carrier_errors"},
+    {"tx_fifo_errors"}, {"tx_heartbeat_errors"},
+    {"tx_window_errors"}, {"rx_compressed"}, {"tx_compressed"}
+};
+
+
+static void et_get_strings(struct net_device *dev, u32 stringset, u8 * buf)
+{
+    if (ETH_SS_STATS == stringset) {
+        memcpy(buf, g_stats_descs, sizeof(g_stats_descs));
+    }
+}
+
+// led blinking
+//static int ec_phys_id(struct net_device *dev, u32 id)
+
+static void et_get_stats(struct net_device *dev, struct ethtool_stats *stats, u64 * data)
+{
+
+    //ec_priv_t *ecp = netdev_priv(dev);
+    int     len = ETH_STATS_LEN;
+    int     i;
+
+    for (i = 0; i < len; i++) {
+        data[i] = ((unsigned long *) &dev->stats)[i];;
+    }
+}
+//static int ec_begin(struct net_device *dev)
+
+//static void    ec_complete(struct net_device *dev)
+
+//static u32     (*get_ufo)(struct net_device *);
+//static int     (*set_ufo)(struct net_device *, u32);
+
+//ethtool_op_get_flags()
+//static u32     ec_get_flags(struct net_device *dev)
+
+// ethtool_op_set_flags()
+//static int     ec_set_flags(struct net_device *dev, u32 flags)
+
+//static u32     ec_get_priv_flags(struct net_device *dev)
+
+//static int     ec_set_priv_flags(struct net_device *dev, u32 flags)
+
+
+static int et_get_sset_count(struct net_device *dev, int sset)
+{
+    switch (sset) {
+            //case ETH_SS_TEST:
+            //return EC_NUM_TEST;
+        case ETH_SS_STATS:
+            return ETH_STATS_LEN;
+        default:
+            return -EOPNOTSUPP;
+    }
+}
+
+
+static struct ethtool_ops ec_ethtool_ops = {
+    .get_settings = et_get_settings,
+    .set_settings = et_set_settings,
+    .get_drvinfo = et_get_drvinfo,
+    .get_regs_len = et_get_regs_len,
+    .get_regs = et_get_regs,
+    .get_msglevel = et_get_msglevel,
+    .set_msglevel = et_set_msglevel,
+    .nway_reset = et_nway_reset,
+    .get_link = et_get_link,
+    .get_pauseparam = et_get_pauseparam,
+    .set_pauseparam = et_set_pauseparam,
+    //.get_sg = ethtool_op_get_sg,
+    .get_strings = et_get_strings,
+    .get_ethtool_stats = et_get_stats,
+    .get_sset_count = et_get_sset_count
+};
+
+
+void ec_set_ethtool_ops(struct net_device *dev)
+{
+    SET_ETHTOOL_OPS(dev, &ec_ethtool_ops);
+}
diff --git a/drivers/net/ethernet/sg8201g/ec_hardware.h b/drivers/net/ethernet/sg8201g/ec_hardware.h
new file mode 100755
index 0000000..9cdda8e
--- /dev/null
+++ b/drivers/net/ethernet/sg8201g/ec_hardware.h
@@ -0,0 +1,382 @@
+/******************************************************************************
+ec_hardware.h -- data structure and macros  about hardware architecture and 
+    registers of MAC and PHY
+
+author : yunchf @Actions
+date : 2010-04-08
+version 0.1
+
+data : 2010-08-10
+version 1.0
+
+******************************************************************************/
+
+#ifndef _EC_HARDWARE_H_
+#define _EC_HARDWARE_H_
+/*****************************************************************************/
+#include <mach/hardware.h>
+
+#undef getl
+#undef putl
+#define getl(a)    act_readl(a)
+#define putl(v, a) act_writel(v, a)
+
+#define ASOC_ETHERNET_PHY_ADDR (0x1)		//phy\B5\D8ַ\A3\BAĬ\C8\CF0x1,\BF\C9ͨ\B9\FDDTS\D6\D0\C5\E4\D6\C3phy_addr\C0\B4\C5\E4\D6\C3
+#define ASOC_ETHERNET_PHY_IRQ  OWL_IRQ_SIRQ0
+
+/*
+ * Should not read and write er_reserved* elements
+ */
+typedef struct ethregs {
+    unsigned long er_busmode;   /* offset 0x0; bus mode reg. */
+    unsigned long er_reserved0;
+    unsigned long er_txpoll;    /* 0x08; transmit poll demand reg. */
+    unsigned long er_reserved1;
+    unsigned long er_rxpoll;    /* 0x10; receive poll demand reg. */
+    unsigned long er_reserved2;
+    unsigned long er_rxbdbase;  /* 0x18; receive descriptor list base address reg. */
+    unsigned long er_reserved3;
+    unsigned long er_txbdbase;  /* 0x20; transmit descriptor list base address reg. */
+    unsigned long er_reserved4;
+    unsigned long er_status;    /* 0x28; status reg. */
+    unsigned long er_reserved5;
+    unsigned long er_opmode;    /* 0x30; operation mode reg. */
+    unsigned long er_reserved6;
+    unsigned long er_ienable;   /* 0x38; interrupt enable reg. */
+    unsigned long er_reserved7;
+    unsigned long er_mfocnt;    /* 0x40; missed frames and overflow counter reg. */
+    unsigned long er_reserved8;
+    unsigned long er_miimng;    /* 0x48; software mii, don't use it here  */
+    unsigned long er_reserved9;
+    unsigned long er_miism;     /* 0x50; mii serial management */
+    unsigned long er_reserved10;
+    unsigned long er_imctrl;    /* 0x58; general-purpose timer and interrupt mitigation control */
+    unsigned long er_reserved11[9];
+    unsigned long er_maclow;    /* 0x80; mac address low */
+    unsigned long er_reserved12;
+    unsigned long er_machigh;   /* 0x88; mac address high */
+    unsigned long er_reserved13;
+    unsigned long er_cachethr;  /* 0x90; pause time and cache thresholds */
+    unsigned long er_reserved14;
+    unsigned long er_fifothr;   /* 0x98; pause control fifo thresholds */
+    unsigned long er_reserved15;
+    unsigned long er_flowctrl;  /* 0xa0; flow control setup and status */
+    unsigned long er_reserved16[3];
+    unsigned long er_macctrl;   /* 0xb0; mac control */
+    unsigned long er_reserved17[83];
+
+    unsigned long er_rxstats[31];       /* 0x200~0x278; receive statistics regs. */
+    unsigned long er_reserved18[33];
+    unsigned long er_txstats[41];       /* 0x300~0x3A0; transmit statistics regs. */
+    unsigned long er_reserved19[23];
+} ethregs_t;
+
+/*
+ * statistical counter of transmission and reception
+ * NOTE : NOT using these registers in fact
+ */
+#define er_tx64         er_txstats[0]   /* offset:0x200 */
+#define er_tx65to127    er_txstats[2]
+#define er_tx128to255   er_txstats[4]
+#define er_tx256to511   er_txstats[6]
+#define er_tx512to1023  er_txstats[8]
+#define er_tx1024to1518 er_txstats[10]
+#define er_txtoolong    er_txstats[12]
+#define er_txoctok      er_txstats[14]
+#define er_txuniok      er_txstats[16]
+#define er_txmultiok    er_txstats[18]
+#define er_txbroadok    er_txstats[20]
+#define er_txpauseok    er_txstats[22]
+#define er_txcoll0      er_txstats[24]
+#define er_txcoll1      er_txstats[26]
+#define er_txcollmulti  er_txstats[28]
+#define er_txcoll16     er_txstats[30]
+#define er_txdefer      er_txstats[32]
+#define er_txlcerr      er_txstats[34]
+#define er_txmacerr     er_txstats[36]
+#define er_txtxcserr    er_txstats[38]  /* offset:0x298 */
+
+#define er_rx64         er_rxstats[0]   /* offset:0x300 */
+#define er_rx65to127    er_rxstats[2]
+#define er_rx128to255   er_rxstats[4]
+#define er_rx256to511   er_rxstats[6]
+#define er_rx512to1023  er_rxstats[8]
+#define er_rx1024to1518 er_rxstats[10]
+#define er_rxtoolong    er_rxstats[12]
+#define er_rxoctok      er_rxstats[14]
+#define er_rxuniok      er_rxstats[16]
+#define er_rxmultiok    er_rxstats[18]
+#define er_rxbroadok    er_rxstats[20]
+#define er_rxpauseok    er_rxstats[22]
+#define er_rxalignerr   er_rxstats[24]
+#define er_rxfcserr     er_rxstats[26]
+#define er_rxrxmiierr   er_rxstats[28]  /* offset:0x370 */
+
+/*
+ * receive and transmit buffer descriptor
+ */
+typedef struct buffer_descriptor {
+    unsigned long status;
+    unsigned long control;
+    unsigned long buf_addr;
+    unsigned long reserved;     /* we don't use second buffer address */
+} ec_bd_t;
+
+
+/*
+ * ethernet clock enable
+ */
+#define ASOC_ETH_CLOCK_EN  (0x1 << 22)
+#define ASOC_ETH_CLOCK_RST (0x1 << 20)
+
+
+/*
+ * rx bd status and control information
+ */
+#define RXBD_STAT_OWN (0x1 << 31)
+#define RXBD_STAT_FF  (0x1 << 30)       /*filtering fail */
+#define RXBD_STAT_FL(x) (((x) >> 16) & 0x3FFF)  /* frame leng */
+#define RXBD_STAT_ES  (0x1 << 15)       /* error summary */
+#define RXBD_STAT_DE  (0x1 << 14)       /* descriptor error */
+#define RXBD_STAT_RF  (0x1 << 11)       /* runt frame */
+#define RXBD_STAT_MF  (0x1 << 10)       /* multicast frame */
+#define RXBD_STAT_FS  (0x1 << 9)        /* first descriptor */
+#define RXBD_STAT_LS  (0x1 << 8)        /* last descriptor */
+#define RXBD_STAT_TL  (0x1 << 7)        /* frame too long */
+#define RXBD_STAT_CS  (0x1 << 6)        /* collision */
+#define RXBD_STAT_FT  (0x1 << 5)        /* frame type */
+#define RXBD_STAT_RE  (0x1 << 3)        /* mii error */
+#define RXBD_STAT_DB  (0x1 << 2)        /* byte not aligned */
+#define RXBD_STAT_CE  (0x1 << 1)        /* crc error */
+#define RXBD_STAT_ZERO  (0x1)
+
+#define RXBD_CTRL_RER (0x1 << 25)       /* receive end of ring */
+#define RXBD_CTRL_RCH (0x1 << 24)       /* using second buffer, not used here */
+#define RXBD_CTRL_RBS1(x) ((x) & 0x7FF) /* buffer1 size */
+
+/*
+ * tx bd status and control information
+ */
+#define TXBD_STAT_OWN (0x1 << 31)
+#define TXBD_STAT_ES  (0x1 << 15)       /* error summary */
+#define TXBD_STAT_LO  (0x1 << 11)       /* loss of carrier */
+#define TXBD_STAT_NC  (0x1 << 10)       /* no carrier */
+#define TXBD_STAT_LC  (0x1 << 9)        /* late collision */
+#define TXBD_STAT_EC  (0x1 << 8)        /* excessive collision */
+#define TXBD_STAT_CC(x)  (((x) >> 3) & 0xF)     /*  */
+#define TXBD_STAT_UF  (0x1 << 1)        /* underflow error */
+#define TXBD_STAT_DE  (0x1)     /* deferred */
+
+#define TXBD_CTRL_IC   (0x1 << 31)      /* interrupt on completion */
+#define TXBD_CTRL_LS   (0x1 << 30)      /* last descriptor */
+#define TXBD_CTRL_FS   (0x1 << 29)      /* first descriptor */
+#define TXBD_CTRL_FT1  (0x1 << 28)      /* filtering type  */
+#define TXBD_CTRL_SET  (0x1 << 27)      /* setup packet */
+#define TXBD_CTRL_AC   (0x1 << 26)      /* add crc disable */
+#define TXBD_CTRL_TER  (0x1 << 25)      /* transmit end of ring */
+#define TXBD_CTRL_TCH  (0x1 << 24)      /* second address chainded */
+#define TXBD_CTRL_DPD  (0x1 << 23)      /* disabled padding */
+#define TXBD_CTRL_FT0  (0x1 << 22)      /* filtering type, togethor with 28bit */
+#define TXBD_CTRL_TBS2(x)  (((x) & 0x7FF) << 11)        /* buf2 size, no use here */
+#define TXBD_CTRL_TBS1(x)  ((x) & 0x7FF)        /* buf1 size */
+#define TXBD_CTRL_TBS1M (0x7FF)
+
+/*
+ * bus mode register
+ */
+#define EC_BMODE_DBO    (0x1 << 20)     /*descriptor byte ordering mode */
+#define EC_BMODE_TAP(x) (((x) & 0x7) << 17)     /*transmit auto-polling */
+#define EC_BMODE_PBL(x) (((x) & 0x3F) << 8)     /*programmable burst length */
+#define EC_BMODE_BLE    (0x1 << 7)      /*big or little endian for data buffers */
+#define EC_BMODE_DSL(x) (((x) & 0x1F) << 2)     /*descriptors skip length */
+#define EC_BMODE_BAR    (0x1 << 1)      /*bus arbitration mode */
+#define EC_BMODE_SWR    (0x1)   /*software reset */
+
+/*
+ * transmit and receive poll demand register
+ */
+#define EC_TXPOLL_ST  (0x1)     /* leave suspended mode to running mode to start xmit */
+#define EC_RXPOLL_SR  (0x1)     /* leave suspended to running mode */
+
+/*
+ * status register 
+ */
+#define EC_STATUS_TSM  (0x7 << 20)      /*transmit process state */
+#define EC_TX_run_dsp  (0x3 << 20)
+#define EC_STATUS_RSM  (0x7 << 17)      /*receive process state */
+#define EC_RX_fetch_dsp (0x1 <<17)
+#define EC_RX_close_dsp (0x5 <<17)
+#define EC_RX_run_dsp 	(0x7 <<17)
+#define EC_STATUS_NIS  (0x1 << 16)      /*normal interrupt summary */
+#define EC_STATUS_AIS  (0x1 << 15)      /*abnormal interrupt summary */
+#define EC_STATUS_ERI  (0x1 << 14)      /*early receive interrupt */
+#define EC_STATUS_GTE  (0x1 << 11)      /*general-purpose timer expiration */
+#define EC_STATUS_ETI  (0x1 << 10)      /*early transmit interrupt */
+#define EC_STATUS_RPS  (0x1 << 8)       /*receive process stopped */
+#define EC_STATUS_RU   (0x1 << 7)       /*receive buffer unavailable */
+#define EC_STATUS_RI   (0x1 << 6)       /*receive interrupt */
+#define EC_STATUS_UNF  (0x1 << 5)       /*transmit underflow */
+#define EC_STATUS_LCIS (0x1 << 4)       /* link change status */
+#define EC_STATUS_LCIQ (0x1 << 3)       /* link change interrupt */
+#define EC_STATUS_TU   (0x1 << 2)       /*transmit buffer unavailable */
+#define EC_STATUS_TPS  (0x1 << 1)       /*transmit process stopped */
+#define EC_STATUS_TI   (0x1)    /*transmit interrupt */
+
+/*
+ * operation mode register
+ */
+#define EC_OPMODE_RA  (0x1 << 30)       /*receive all */
+#define EC_OPMODE_TTM (0x1 << 22)       /*transmit threshold mode */
+#define EC_OPMODE_SF  (0x1 << 21)       /*store and forward */
+#define EC_OPMODE_SPEED(x) (((x) & 0x3) << 16)  /*eth speed selection */
+#define EC_OPMODE_10M (0x1 << 17)       /* set when work on 10M, otherwise 100M */
+#define EC_OPMODE_TR(x)    (((x) & 0x3) << 14)  /*threshold control bits */
+#define EC_OPMODE_ST  (0x1 << 13)       /*start or stop transmit command */
+#define EC_OPMODE_LP  (0x1 << 10)       /*loopback mode */
+#define EC_OPMODE_FD  (0x1 << 9)        /*full duplex mode */
+#define EC_OPMODE_PM  (0x1 << 7)        /*pass all multicast */
+#define EC_OPMODE_PR  (0x1 << 6)        /*prmiscuous mode */
+#define EC_OPMODE_IF  (0x1 << 4)        /*inverse filtering */
+#define EC_OPMODE_PB  (0x1 << 3)        /*pass bad frames */
+#define EC_OPMODE_HO  (0x1 << 2)        /*hash only filtering mode */
+#define EC_OPMODE_SR  (0x1 << 1)        /*start or stop receive command */
+#define EC_OPMODE_HP  (0x1)     /*hash or perfect receive filtering mode */
+
+/*
+ * interrupt enable register
+ */
+#define EC_IEN_LCIE (0x1 << 17) /*link change interrupt enable */
+#define EC_IEN_NIE (0x1 << 16)  /*normal interrupt summary enable */
+#define EC_IEN_AIE (0x1 << 15)  /*abnormal interrupt summary enable */
+#define EC_IEN_ERE (0x1 << 14)  /*early receive interrupt enable */
+#define EC_IEN_GTE (0x1 << 11)  /*general-purpose timer overflow */
+#define EC_IEN_ETE (0x1 << 10)  /*early transmit interrupt enable */
+#define EC_IEN_RSE (0x1 << 8)   /*receive stopped enable */
+#define EC_IEN_RUE (0x1 << 7)   /*receive buffer unavailable enable */
+#define EC_IEN_RIE (0x1 << 6)   /*receive interrupt enable */
+#define EC_IEN_UNE (0x1 << 5)   /*underflow interrupt enable */
+#define EC_IEN_TUE (0x1 << 2)   /*transmit buffer unavailable enable */
+#define EC_IEN_TSE (0x1 << 1)   /*transmit stopped enable */
+#define EC_IEN_TIE (0x1)        /*transmit interrupt enable */
+//#define EC_IEN_ALL (0x3CDE7)
+#define EC_IEN_ALL (0x1CDE3)    /* TU interrupt disabled */
+
+/*
+ * missed frames and overflow counter register
+ */
+#define EC_MFOCNT_OCO  (0x1 << 28)      /*overflow flag */
+#define EC_MFOCNT_FOCM (0x3FF << 17)    /*fifo overflow counter */
+#define EC_MFOCNT_MFO  (0x1 << 16)      /*missed frame flag */
+#define EC_MFOCNT_MFCM (0xFFFF) /*missed frame counter */
+
+/*
+ * the mii serial management register
+ */
+#define MII_MNG_SB  (0x1 << 31) /*start transfer or busy */
+#define MII_MNG_CLKDIV(x) (((x) & 0x7) << 28)   /*clock divider */
+#define MII_MNG_OPCODE(x) (((x) & 0x3) << 26)   /*operation mode */
+#define MII_MNG_PHYADD(x) (((x) & 0x1F) << 21)  /*physical layer address */
+#define MII_MNG_REGADD(x) (((x) & 0x1F) << 16)  /*register address */
+#define MII_MNG_DATAM (0xFFFF)  /*register data mask */
+#define MII_MNG_DATA(x)   ((MII_MNG_DATAM) & (x))       /* data to write */
+#define MII_OP_WRITE 0x1
+#define MII_OP_READ  0x2
+#define MII_OP_CDS   0x3
+
+/*
+ * general purpose timer and interrupt mitigation control register
+ */
+#define EC_IMCTRL_CS     (0x1 << 31)    /*cycle size */
+#define EC_IMCTRL_TT(x)  (((x) & 0xF) << 27)    /*transmit timer */
+#define EC_IMCTRL_NTP(x) (((x) & 0x7) << 24)    /*number of transmit packets */
+#define EC_IMCTRL_RT(x)  (((x) & 0xF) << 20)    /*receive timer */
+#define EC_IMCTRL_NRP(x) (((x) & 0x7) << 17)    /*number of receive packets */
+#define EC_IMCTRL_CON    (0x1 << 16)    /*continuous mode */
+#define EC_IMCTRL_TIMM   (0xFFFF)       /*timer value */
+#define EC_IMCTRL_TIM(x) ((x) & 0xFFFF) /*timer value */
+
+/*
+ * pause time and cache thresholds register
+ */
+#define EC_CACHETHR_CPTL(x) (((x) & 0xFF) << 24)        /*cache pause threshold level */
+#define EC_CACHETHR_CRTL(x) (((x) & 0xFF) << 16)        /*cache restart threshold level */
+#define EC_CACHETHR_PQT(x)  ((x) & 0xFFFF)      /*flow control pause quanta time */
+
+/*
+ * fifo thresholds register
+ */
+#define EC_FIFOTHR_FPTL(x) (((x) & 0xFFFF) << 16)       /*fifo pause threshold level */
+#define EC_FIFOTHR_FRTL(x) ((x) & 0xFFFF)       /*fifo restart threshold level */
+
+/*
+ * flow control setup and status
+ */
+#define EC_FLOWCTRL_FCE (0x1 << 31)     /*flow control enable */
+#define EC_FLOWCTRL_TUE (0x1 << 30)     /*transmit un-pause frames enable */
+#define EC_FLOWCTRL_TPE (0x1 << 29)     /*transmit pause frames enable */
+#define EC_FLOWCTRL_RPE (0x1 << 28)     /*receive pause frames enable */
+#define EC_FLOWCTRL_BPE (0x1 << 27)     /*back pressure enable (only half-dup) */
+#define EC_FLOWCTRL_ENALL (0x1F << 27)
+#define EC_FLOWCTRL_PRS (0x1 << 1)      /*pause request sent */
+#define EC_FLOWCTRL_HTP (0x1)   /*host transmission paused */
+
+/*
+ * mac control register
+ */
+#define EC_MACCTRL_RRSB (0x1 << 8)      /*RMII_REFCLK select bit */
+#define EC_MACCTRL_SSDC(x) (((x) & 0xF) << 4) /*SMII SYNC delay half cycle */
+#define EC_MACCTRL_RCPS (0x1 << 1)      /*REF_CLK phase select */
+#define EC_MACCTRL_RSIS (0x1 << 0)      /*RMII or SMII interface select bit */
+
+#define MAC_CTRL_SMII (0x41) /* use smii; bit8: 0 REFCLK output, 1 input*/
+#define MAC_CTRL_RMII (0x0)  /* use rmii */
+
+
+/*
+ * phy control register
+ */
+#define EC_PHYCTRL_PDMC(x) (((x) & 0x3) << 16)  /*power down mode control */
+#define EC_PHYCTRL_LOOP    (0x1 << 12)  /*loopback mode */
+#define EC_PHYCTRL_MHZ(x)  (((x) & 0x3) << 4)   /* (x+1) times of 25MHZ */
+
+/*
+ * phy status register
+ */
+#define EC_PHYSTATUS_LINKED (0x1)       /*link status */
+
+/*
+ * phy reset control signals
+ */
+#define EC_PHYRESET_RST  (0x1)  /*low active reset signal */
+
+/*
+ * fxedp110hc0a - FARADAY Inc. PHY registers address
+ * prefer to using macros in mii.h
+ */
+#define PHY_REG_FTC1 0x10
+#define PHY_REG_FTC2 0x18
+
+#define PHY_FTC_PRL  (0x1 << 12)        /* support full parallel detection function */
+#define PHY_FTC_CMPT (0x3 << 2) /* prevent compatibility issues */
+
+
+/*
+ * phy KSZ8041TF
+ */
+#define MII_ICSR 0x19 /* interrupt control & status register */
+
+#define ICSR_LINKUP_EN   (0x1 << 13)
+#define ICSR_LINKDOWN_EN (0x1 << 12)
+#define ICSR_LINKDOWN_EN_2 (0x1 << 11)
+
+#define ICSR_LINKUP   (0x1 << 0)
+#define ICSR_LINKDOWN (0x1 << 2)
+
+
+#define MII_PHY_CTL2 0x1f
+#define PHY_CTL2_INT_LEVEL (0x1 << 9) /* interrupt pin active high:1, low:0 */
+
+
+/******************************************************************************/
+
+#endif                          /* _EC_HARDWARE_H_ */
diff --git a/drivers/net/ethernet/sg8201g/ec_phy.c b/drivers/net/ethernet/sg8201g/ec_phy.c
new file mode 100755
index 0000000..aa1b4bd
--- /dev/null
+++ b/drivers/net/ethernet/sg8201g/ec_phy.c
@@ -0,0 +1,887 @@
+/******************************************************************************
+ec_phy.c -- phy driver for fxedp110c0a  of FARADAY Inc.
+
+author : yunchf @Actions
+date : 2010-04-12
+version 0.1
+
+date : 2010-08-10
+version 1.0
+
+******************************************************************************/
+
+#include <linux/delay.h>
+#include "ethctrl.h"
+
+/*
+ * read and write phy register normally need not to wait for. sometimes about 7us
+ * but auto-negotiation may wait for a long time, about 140ms, and less than 2s
+ */
+#define MII_TIME_OUT 100
+#define PHY_AUTONEG_TIME_OUT 50
+
+
+#if 0
+/*------------------------------- phy driver hooks -----------------------------*/
+
+/**
+ * read_phy_reg - MII interface  to read  @reg_addr register of phy at @phy_addr
+ * return positive and zero value if success, or negative value if fail
+ */
+ //read PHY internal register by SPI
+//register address,return the register data
+unsigned short read_phy_reg_atc2605(ec_priv_t * ecp, unsigned short reg_addr)
+{
+	unsigned short temp;
+	struct atc260x_dev *atc260x = ecp->atc260x;
+
+	do {
+		temp = atc260x_reg_read(atc260x, atc2603_PHY_SMI_STAT);
+	}while(temp & 0x1); 	//waite for the SMI bus process completion
+
+	temp = 0x8100 | reg_addr;		//smi write operate,address
+	atc260x_reg_write(atc260x, atc2603_PHY_SMI_CONFIG, temp);
+	do {
+		temp = atc260x_reg_read(atc260x, atc2603_PHY_SMI_STAT);
+	}while(temp & 0x1); 	//waite for the SMI bus process completion
+
+	temp = atc260x_reg_read(atc260x, atc2603_PHY_SMI_DATA);
+	temp = temp & 0xffff;
+	return (temp);
+}
+
+/**
+ * write_phy_reg - MII interface  to write  @val to @reg_addr register of phy at @phy_addr
+ * return zero if success, negative value if fail
+ */
+ //write PHY internal register by SPI
+//register address,write data
+int write_phy_reg_atc2605(ec_priv_t * ecp, unsigned short reg_addr, unsigned short val)
+{
+    unsigned short temp;
+    struct atc260x_dev *atc260x = ecp->atc260x;
+
+	do {
+		temp = atc260x_reg_read(atc260x, atc2603_PHY_SMI_STAT);
+	}while(temp & 0x1); 	//waite for the SMI bus process completion
+
+	atc260x_reg_write(atc260x, atc2603_PHY_SMI_DATA, val);
+	temp = 0xc100 | reg_addr;		//smi write operate,address
+	atc260x_reg_write(atc260x, atc2603_PHY_SMI_CONFIG, temp);
+
+	return 0;
+}
+#endif //PGA0
+/**
+ * read_phy_reg - MII interface  to read  @reg_addr register of phy at @phy_addr
+ * return positive and zero value if success, or negative value if fail
+ * may be used by other standard ethernet phy
+ */
+unsigned short read_phy_reg_rtl8201(ec_priv_t * ecp, unsigned short reg_addr)
+{
+	u32 op_reg;
+	u32 phy_addr;
+  if((ecp->phy_addr)!=0xFF)
+  	phy_addr=ecp->phy_addr;
+  else
+  	phy_addr=ASOC_ETHERNET_PHY_ADDR;	
+	do {
+		op_reg = getl(MAC_CSR10);
+	} while (op_reg & MII_MNG_SB);
+
+	putl(MII_MNG_SB | MII_MNG_OPCODE(MII_OP_READ) | MII_MNG_REGADD(reg_addr) |
+		MII_MNG_PHYADD(phy_addr), MAC_CSR10);
+
+	do {
+		op_reg = getl(MAC_CSR10);
+	} while (op_reg & MII_MNG_SB);
+
+	return (u16)MII_MNG_DATA(op_reg);
+}
+
+/**
+ * read_phy_reg - MII interface  to read  @reg_addr register of phy at @phy_addr
+ * return positive and zero value if success, or negative value if fail
+ * may be used by other standard ethernet phy
+ */
+unsigned short read_phy_reg_rs8201g(ec_priv_t * ecp, unsigned short reg_addr)
+{
+	u32 op_reg;
+	u32 phy_addr;
+  if((ecp->phy_addr)!=0xFF)
+  	phy_addr=ecp->phy_addr;
+  else
+  	phy_addr=ASOC_ETHERNET_PHY_ADDR;	
+	do {
+		op_reg = getl(MAC_CSR10);
+	} while (op_reg & MII_MNG_SB);
+
+	putl(MII_MNG_SB | MII_MNG_OPCODE(MII_OP_READ) | MII_MNG_REGADD(reg_addr) |
+		MII_MNG_PHYADD(phy_addr), MAC_CSR10);
+
+	do {
+		op_reg = getl(MAC_CSR10);
+	} while (op_reg & MII_MNG_SB);
+
+	return (u16)MII_MNG_DATA(op_reg);
+}
+
+
+
+
+
+
+
+
+/**
+ * write_phy_reg - MII interface  to write  @val to @reg_addr register of phy at @phy_addr
+ * return zero if success, negative value if fail
+ * may be used by other standard ethernet phy
+ */
+int write_phy_reg_rtl8201(ec_priv_t * ecp, unsigned short reg_addr, unsigned short val)
+{
+	u32 op_reg;
+	u32 phy_addr;
+  if((ecp->phy_addr)!=0xFF)
+  	phy_addr=ecp->phy_addr;
+  else
+  	phy_addr=ASOC_ETHERNET_PHY_ADDR;
+  	
+	do {
+		op_reg = getl(MAC_CSR10);
+	} while (op_reg & MII_MNG_SB);
+
+	putl(MII_MNG_SB | MII_MNG_OPCODE(MII_OP_WRITE) | MII_MNG_REGADD(reg_addr) |
+		MII_MNG_PHYADD(phy_addr) | val, MAC_CSR10);
+
+	do {
+		op_reg = getl(MAC_CSR10);
+	} while (op_reg & MII_MNG_SB);
+
+	return 0;
+}
+
+
+
+
+/**
+ * write_phy_reg - MII interface  to write  @val to @reg_addr register of phy at @phy_addr
+ * return zero if success, negative value if fail
+ * may be used by other standard ethernet phy
+ */
+int write_phy_reg_rs8201g(ec_priv_t * ecp, unsigned short reg_addr, unsigned short val)
+{
+	u32 op_reg;
+	u32 phy_addr;
+  if((ecp->phy_addr)!=0xFF)
+  	phy_addr=ecp->phy_addr;
+  else
+  	phy_addr=ASOC_ETHERNET_PHY_ADDR;	
+	do {
+		op_reg = getl(MAC_CSR10);
+	} while (op_reg & MII_MNG_SB);
+
+	putl(MII_MNG_SB | MII_MNG_OPCODE(MII_OP_WRITE) | MII_MNG_REGADD(reg_addr) |
+		MII_MNG_PHYADD(phy_addr) | val, MAC_CSR10);
+
+	do {
+		op_reg = getl(MAC_CSR10);
+	} while (op_reg & MII_MNG_SB);
+
+	return 0;
+}
+
+
+
+
+
+
+/**
+ * read_phy_reg - MII interface  to read  @reg_addr register of phy at @phy_addr
+ * return positive and zero value if success, or negative value if fail
+ * may be used by other standard ethernet phy
+ */
+unsigned short read_phy_reg_ksz8041(ec_priv_t * ecp, unsigned short reg_addr)
+{
+	u32 op_reg;
+	u32 phy_addr;
+  if((ecp->phy_addr)!=0xFF)
+  	phy_addr=ecp->phy_addr;
+  else
+  	phy_addr=ASOC_ETHERNET_PHY_ADDR;
+	do {
+		op_reg = getl(MAC_CSR10);
+	} while (op_reg & MII_MNG_SB);
+
+	putl(MII_MNG_SB | MII_MNG_OPCODE(MII_OP_READ) | MII_MNG_REGADD(reg_addr) |
+		MII_MNG_PHYADD(phy_addr), MAC_CSR10);
+
+	do {
+		op_reg = getl(MAC_CSR10);
+	} while (op_reg & MII_MNG_SB);
+
+	return (u16)MII_MNG_DATA(op_reg);
+}
+
+
+/**
+ * write_phy_reg - MII interface  to write  @val to @reg_addr register of phy at @phy_addr
+ * return zero if success, negative value if fail
+ * may be used by other standard ethernet phy
+ */
+int write_phy_reg_ksz8041(ec_priv_t * ecp, unsigned short reg_addr, unsigned short val)
+{
+	u32 op_reg;
+	u32 phy_addr;
+  if((ecp->phy_addr)!=0xFF)
+  	phy_addr=ecp->phy_addr;
+  else
+  	phy_addr=ASOC_ETHERNET_PHY_ADDR;
+	do {
+		op_reg = getl(MAC_CSR10);
+	} while (op_reg & MII_MNG_SB);
+
+	putl(MII_MNG_SB | MII_MNG_OPCODE(MII_OP_WRITE) | MII_MNG_REGADD(reg_addr) |
+		MII_MNG_PHYADD(phy_addr) | val, MAC_CSR10);
+
+	do {
+		op_reg = getl(MAC_CSR10);
+	} while (op_reg & MII_MNG_SB);
+
+	return 0;
+}
+
+unsigned short (*read_phy_reg)(ec_priv_t *, unsigned short) = NULL;
+int (*write_phy_reg)(ec_priv_t *, unsigned short, unsigned short) = NULL;
+
+static inline void phy_reg_set_bits(ec_priv_t * ecp, unsigned short reg_addr, int bits)
+{
+	unsigned short reg_val;
+	reg_val = read_phy_reg(ecp, reg_addr);
+	reg_val |= (unsigned short)bits;
+	printk(KERN_INFO " %s %d write reg_val:0x%x bits:0x%x\n", __FUNCTION__,__LINE__,reg_val,bits);
+	write_phy_reg(ecp, reg_addr, reg_val);
+	reg_val = read_phy_reg(ecp, reg_addr);
+	printk(KERN_INFO " %s %d write after read reg_val:0x%x\n", __FUNCTION__,__LINE__,reg_val);
+}
+
+static inline void phy_reg_clear_bits(ec_priv_t * ecp, unsigned short reg_addr, int bits)
+{
+	unsigned short reg_val;
+
+	reg_val = read_phy_reg(ecp, reg_addr);
+	reg_val &= ~(unsigned short)bits;
+	write_phy_reg(ecp, reg_addr, reg_val);
+}
+
+
+extern int suspend_flag;
+static inline int wait_for_aneg_completion(ec_priv_t * ecp)
+{
+    int     wait;
+    int     reg_val;
+    for (wait = PHY_AUTONEG_TIME_OUT; wait > 0; wait--) {
+        if (suspend_flag == 1) {
+            suspend_flag = 0;
+            break;
+        }
+        reg_val = read_phy_reg(ecp, MII_BMSR);
+        if (reg_val & BMSR_ANEGCOMPLETE)
+            break;
+
+        mdelay(100);
+        printk(KERN_INFO "%s", (wait % 200) ? "*" : "\n");
+    }
+    printk(KERN_INFO "exit\n");
+
+    return (!wait);
+}
+#if 0
+
+static int atc2605_hw_init(ec_priv_t *ecp)
+{
+	unsigned short atc260x_temp;
+	struct atc260x_dev *atc260x = ecp->atc260x;
+
+	/*ethernet mfp0 RMII 1st*/
+	//hw_rmii_get_pin();
+	//mac_rmii_get_pin();
+	/************************phy init*****************************/
+	/*enable phy clock*/
+	atc260x_reg_setbits(atc260x, atc2603_CMU_DEVRST, 0x200, 0x200);
+	udelay(100);
+
+	/*ethernet wrapper rest*/
+	atc260x_reg_setbits(atc260x, atc2603_CMU_DEVRST, 0x08, 0x0);
+	udelay(100);
+	atc260x_reg_setbits(atc260x, atc2603_CMU_DEVRST, 0x08, 0x08);
+	udelay(100);
+
+	/*GL5302 PHY avoid reboot bug, reset PLL*/
+	atc260x_reg_setbits(atc260x, atc2603_PHY_PLL_CTL0, 0x03, 0x02); //25Mhz
+	mdelay(5);
+	atc260x_reg_setbits(atc260x, atc2603_PHY_PLL_CTL1, 0x200, 0x200);//bit9=1,enetpll ALV LDO enable
+	mdelay(200);
+
+	atc260x_reg_setbits(atc260x, atc2603_PHY_PLL_CTL0, 0x03, 0x01); //bit0=1,bit1=0,ethernet pll enable ,24Mhz
+	mdelay(1);
+	/* 5203 PAD_CLKO_25M output 25MHz clock to 2605 */
+	atc260x_reg_setbits(atc260x, atc2603_PHY_PLL_CTL0, 0x03, 0x03); //25Mhz
+	mdelay(5);
+
+	atc260x_reg_write(atc260x, atc2603_PHY_CONFIG, 0x00);	    //auto, phy power on
+	atc260x_reg_write(atc260x, atc2603_PHY_ADDR, 0x01);		    //set phy address=  0x01
+	atc260x_reg_write(atc260x, atc2603_PHY_CTRL, 0x01);	        //rmii,100Mbps
+
+	//add  modify
+	atc260x_reg_write(atc260x, atc2603_PHY_HW_RST, 0x01);	    //reset the phy
+	udelay(100);
+	do
+	{
+		atc260x_temp = atc260x_reg_read(atc260x, atc2603_PHY_HW_RST);
+	}while(atc260x_temp & 0x1); //waite for reset process completion
+
+	/*enable RMII_REF_CLK and EXTIRQ pad and disable the other 6 RMII pad, gl5302 bug amend*/
+	atc260x_reg_setbits(atc260x, atc2603_PAD_EN, 0xff, 0x81);
+	udelay(100);
+
+	//pad_drv level 3 for fpga test
+	atc260x_reg_setbits(atc260x, atc2603_PAD_DRV1, 0xfff, 0x145);
+	//atc260x_reg_setbits(atc260x, atc2603_PAD_DRV1, 0xfff, 0x28a); //level 4
+	printk(KERN_INFO "5302 PAD_EN: 0x%x\n", (uint)atc260x_reg_read(atc260x, atc2603_PAD_EN));
+	printk(KERN_INFO "5302 PAD_DRV1: 0x%x\n", (uint)atc260x_reg_read(atc260x, atc2603_PAD_DRV1));
+
+	atc260x_reg_setbits(atc260x, atc2603_PHY_INT_CTRL, 0xf, 0xf);   //enable phy int control
+
+	/*clear phy INT_STAT*/
+	atc260x_reg_write(ecp->atc260x, atc2603_PHY_INT_STAT, 0xff);
+	//printk(KERN_INFO "1f.atc2603_PHY_INT_STAT:0x%x\n", atc260x_reg_read(atc260x, gl5302_PHY_INT_STAT));
+	udelay(100);
+
+	printk(KERN_INFO "5302 MFP_CTL0: 0x%x\n", (uint)atc260x_reg_read(atc260x, atc2603_MFP_CTL0));
+
+#ifdef ETHENRET_PHY_LOOP_BACK
+	/* phy loopback */
+	//atc260x_reg_setbits(atc260x, atc2603_PHY_CONFIG, 0x1 << 11, 0x1 << 11);
+	printk(KERN_INFO "phy config: 0x%x\n", (uint)atc260x_reg_read(atc260x, atc2603_PHY_CONFIG));
+	{
+		/* shut auto-negoiation */
+		ushort bmcr = read_phy_reg(ecp, MII_BMCR);
+		bmcr &= ~BMCR_ANENABLE;
+		write_phy_reg(ecp, MII_BMCR, bmcr);
+
+		bmcr = read_phy_reg(ecp, MII_BMCR);
+		bmcr |= BMCR_LOOPBACK;
+		write_phy_reg(ecp, MII_BMCR, bmcr);
+		printk(KERN_INFO "phy bmcr: 0x%x\n", (uint)read_phy_reg(ecp, MII_BMCR));
+	}
+#endif
+	return 0;
+}
+
+//rtl8201_phy_init
+
+#endif //PGA0
+
+
+
+/**
+ * phy_init -- initialize phy - ATC2605 or KSZ8041
+ * return 0 if success, else fail
+ */
+static int phy_init(ec_priv_t * ecp)
+{
+	int     reg_val;
+	//u16 temp;
+		unsigned int cnt = 0;	
+	phy_reg_set_bits(ecp, MII_BMCR, BMCR_RESET);
+	do {
+		reg_val = read_phy_reg(ecp, MII_BMCR);
+		if (cnt++ > 1000) {
+			printk(KERN_INFO "ethernet phy BMCR_RESET timeout!!!\n");
+			break;
+		}
+	} while (reg_val & BMCR_RESET);
+
+	if (ecp->phy_model == ETH_PHY_MODEL_ATC2605) {
+		printk(KERN_INFO "phy model: %u\n", ecp->phy_model);
+		phy_reg_set_bits(ecp, PHY_REG_FTC1, PHY_FTC_PRL);
+		phy_reg_set_bits(ecp, PHY_REG_FTC2, PHY_FTC_CMPT);
+	} else if (ecp->phy_model == ETH_PHY_MODEL_KSZ8041TL) {
+		printk(KERN_INFO "phy model: %u\n", ecp->phy_model);
+		/* only turn on link up/down phy interrupt */
+		write_phy_reg(ecp, MII_ICSR, ICSR_LINKUP_EN | ICSR_LINKDOWN_EN);
+		printk(KERN_INFO "MII_ICSR:0x%x\n", (unsigned)read_phy_reg(ecp, MII_ICSR));
+		phy_reg_set_bits(ecp, MII_PHY_CTL2, PHY_CTL2_INT_LEVEL);
+		printk(KERN_INFO "MII_PHY_CTL2:0x%x\n", (unsigned)read_phy_reg(ecp, MII_PHY_CTL2));
+	} else if (ecp->phy_model == ETH_PHY_MODEL_RTL8201) {
+		printk(KERN_INFO "phy model: %u\n", ecp->phy_model);
+		write_phy_reg(ecp, 0x1f, 0x7);
+		/* only turn on link up/down phy interrupt */
+		write_phy_reg(ecp, 0x13, ICSR_LINKUP_EN );
+		write_phy_reg(ecp, 0x10, 0x7FFB);
+		write_phy_reg(ecp, 0x1f, 0x0);
+	} else if (ecp->phy_model == ETH_PHY_MODEL_SR8201G) {
+#ifdef PHY_USE_POLL	
+		write_phy_reg(ecp, 0xf, 0x7);
+		write_phy_reg(ecp, 0xC, 0X1<<12);
+		write_phy_reg(ecp, 0xf, 0x0);
+#else
+		printk(KERN_INFO "phy model: %u\n", ecp->phy_model);
+		write_phy_reg(ecp, 0xf, 0x7);
+		/* only turn on link up/down phy interrupt */
+		write_phy_reg(ecp, 0xE, (0X1<<11) | (1 << 10) );
+		write_phy_reg(ecp, 0xC, 0X1<<12);
+		write_phy_reg(ecp, 0xf, 0x0);
+#endif		
+	} else {
+		printk(KERN_INFO "NOT supported phy model: %u\n", ecp->phy_model);
+	}
+	
+#if 0
+	/* adjust tx current */
+	temp = read_phy_reg(ecp, 0x12);
+	temp  &= ~0x780;
+	//temp	|= 0x600; //1100, add 50+100uA
+	//temp	|= 0x680; //1101
+	//temp  |= 0x480; //1001
+	//temp	|= 0x280; //0101
+	//temp	|= 0x80; //0001
+	temp	|= 0x180; //0011, minus 50uA  max 2.57V
+	//temp	|= 0x780; //1111
+	write_phy_reg(ecp, 0x12, temp);
+	printk(KERN_INFO "PHY_REG_TXPN = 0x%x\n", (u32)read_phy_reg(ecp, 0x12));
+#endif
+#ifdef WORK_IN_10M_MODE
+	/* limit to 10M for 5203 MAC bug */
+	phy_reg_clear_bits(ecp, MII_ADVERTISE, ADVERTISE_100HALF | ADVERTISE_100FULL);
+#endif
+	printk(KERN_INFO "MII_ADVERTISE: 0x%04x\n", (uint)read_phy_reg(ecp, MII_ADVERTISE));
+	printk(KERN_INFO "%s %d MII_BMCR: 0x%04x\n", __FUNCTION__,__LINE__,(uint)read_phy_reg(ecp, MII_BMCR));
+
+	/* auto-negotiate and wait for completion, then get link status */
+	phy_reg_set_bits(ecp, MII_BMCR, BMCR_ANENABLE | BMCR_ANRESTART);
+	printk(KERN_INFO "start aneg...\n");
+	printk(KERN_INFO "%s %d MII_BMCR: 0x%04x\n",  __FUNCTION__,__LINE__,(uint)read_phy_reg(ecp, MII_BMCR));
+
+	/* wait_for_aneg_completion(ecp) sleep(), so it shall not be invoked in
+	 * ec_netdev_transmit_timeout() which runs in interrupt bottom half. */
+#if 0
+	printk(KERN_INFO "wait for aneg...\n");
+	if (wait_for_aneg_completion(ecp)) {
+		printk(KERN_INFO "MII_BMCR:0x%x\n", read_phy_reg(ecp, MII_BMCR));
+		printk(KERN_INFO "auto-negotiation is timeout.\n");
+		return (1);
+	}
+   int i = 0 ;
+	for (i = 0; i < MII_TIME_OUT; i++) {
+		reg_val = read_phy_reg(ecp, MII_BMSR);
+		if (reg_val & BMSR_LSTATUS) {
+			ecp->linked = true;
+			break;
+		}
+		udelay(1);
+	}
+	if (MII_TIME_OUT == i) {
+		ecp->linked = false;
+		printk(KERN_INFO "link fail.\n");
+		return (1);
+	}
+#else
+	/* not wait, set link status not connected and return*/
+	ecp->linked = false;
+#endif
+
+	INFO_GREEN("\nlink status is: %s\n", ecp->linked ? "true" : "false");
+	return (0);
+}
+
+
+/**
+ * fdp110_setup_aneg - setup  or disable  auto-negotiation;
+ * if enable auto-neg, we enable and restart auto-neg, don't wait for it completion
+ * link change interrupt can capture it
+ * if disable auto-neg, but auto-neg is already disabled, then nothing to do, 
+ * else disable auto-neg
+ * return 0 if success, negative value if fail
+ */
+static int fdp110_setup_aneg(ec_priv_t * ecp, bool autoneg)
+{
+    int     bmcr;
+    int     err;
+
+    bmcr = read_phy_reg(ecp, MII_BMCR);
+    if (bmcr < 0) {
+        return (bmcr);
+    }
+
+    if (autoneg) {
+        bmcr |= BMCR_ANENABLE | BMCR_ANRESTART;
+        err = write_phy_reg(ecp, MII_BMCR, bmcr);
+        if (err < 0)
+            return (err);
+    } else if (bmcr & BMCR_ANENABLE) {
+        printk(KERN_INFO "disable auto-neg\n");
+        bmcr &= ~BMCR_ANENABLE;
+        err = write_phy_reg(ecp, MII_BMCR, bmcr);
+        if (err < 0)
+            return (err);
+    }
+
+    return (0);
+}
+
+
+static inline int restart_autoneg(ec_priv_t * ecp)
+{
+    int     bmcr_val;
+
+    bmcr_val = read_phy_reg(ecp, MII_BMCR);
+    if (bmcr_val < 0) {
+        return (bmcr_val);
+    }
+
+    bmcr_val |= BMCR_ANENABLE | BMCR_ANRESTART;
+    return (write_phy_reg(ecp, MII_BMCR, bmcr_val));
+}
+
+
+/**
+ * fdp110_setup_advert -- set auto-negotiation advertisement
+ * return positive value wrote to ANAR reg if success, negative value if fail 
+ */
+static int fdp110_setup_advert(ec_priv_t * ecp, int advertising)
+{
+    int     adv;
+    int     err;
+    const int supported = ADVERTISE_ALL | ADVERTISE_PAUSE_CAP;
+
+    adv = read_phy_reg(ecp, MII_ADVERTISE);
+    if (adv < 0) {
+        return (adv);
+    }
+
+    /* remove old supported features, but maintain others bit */
+    adv &= ~supported;
+    if (!(advertising & supported)) {
+        return (-1);
+    }
+    adv |= (advertising & supported);
+    err = write_phy_reg(ecp, MII_ADVERTISE, adv);
+    if (err < 0) {
+        return (err);
+    }
+
+    /* in fact, when we set new value to phy's advertisement reg, phy will auto-neg again,
+     * but some times it don't, so we manually force it auto-neg again.
+     * we don't wait for auto-neg completion, link change interrupt will capture it
+     */
+    err = restart_autoneg(ecp);
+
+    return (err < 0 ? err : adv);
+}
+
+
+/**
+ * fdp110_setup_forced -- configure phy work on @speed and @duplex mode forciblly
+ * NOTE: this will close auto-neg function
+ * return 0 if success, negative value if fail
+ */
+static int fdp110_setup_forced(ec_priv_t * ecp, int speed, int duplex)
+{
+    int     err = 0;
+    int     eval;
+    int     bmcr;
+
+    bmcr = read_phy_reg(ecp, MII_BMCR);
+    if (bmcr < 0) {
+        printk(KERN_INFO "error read bmcr\n");
+        return (-1);
+    }
+
+    eval = bmcr & ~(BMCR_ANENABLE | BMCR_SPEED100 | BMCR_FULLDPLX);
+    if (ETH_SPEED_100M == speed) {
+        eval |= BMCR_SPEED100;
+    }
+    if (ETH_DUP_FULL == duplex) {
+        eval |= BMCR_FULLDPLX;
+    }
+    if (eval != bmcr) {
+        err = write_phy_reg(ecp, MII_BMCR, eval);
+    }
+
+    return (err);
+}
+
+
+/**
+ * fdp110_setup_loopback -- setup or disable loopback
+ * return 0 if success, negative value if fail
+ */
+static int fdp110_setup_loopback(ec_priv_t * ecp, bool loopback)
+{
+    int     bmcr;
+    int     err = 0;
+    bool    changed = false;
+
+    bmcr = read_phy_reg(ecp, MII_BMCR);
+    if (bmcr < 0) {
+        return (bmcr);
+    }
+
+    if (loopback) {
+        if (!(bmcr & BMCR_LOOPBACK)) {
+            bmcr |= BMCR_LOOPBACK;
+            changed = true;
+        }
+    } else {
+        if (bmcr & BMCR_LOOPBACK) {
+            bmcr &= ~BMCR_LOOPBACK;
+            changed = true;
+        }
+    }
+
+    if (changed) {
+        err = write_phy_reg(ecp, MII_BMCR, bmcr);
+    }
+    printk(KERN_INFO "changed - %s \n", changed ? "true" : "false");
+
+    return (err);
+}
+
+
+/**
+ * fdp110_read_status -- read phy's status, according phy ancr, anar & anlpar regs
+ * return 0 if success, negative value if fail
+ */
+static int fdp110_read_status(ec_priv_t * ecp)
+{
+    int     adv;
+    int     lpa;
+    //int     bmsr;
+    int     bmcr;
+    //int     aner;
+    int speed;
+    int duplex;
+
+    if (wait_for_aneg_completion(ecp)) {
+        printk(KERN_INFO "MII_BMCR:0x%x\n", read_phy_reg(ecp, MII_BMCR));
+        printk(KERN_INFO "auto-negotiation is timeout.\n");
+        return (-1);
+    }
+
+    bmcr = read_phy_reg(ecp, MII_BMCR);
+    if (bmcr < 0)
+        return (bmcr);
+
+#if 0 /* FIXME: should check if both side have auto-negotiation ability */
+    bmsr = read_phy_reg(ecp, MII_BMSR);
+    if (bmsr < 0)
+        return (bmsr);
+
+    aner = read_phy_reg(ecp, MII_EXPANSION);
+    if (aner < 0)
+        return (aner);
+
+    ecp->autoneg = aner & EXPANSION_NWAY ? true : false;
+#else
+    ecp->autoneg = bmcr & BMCR_ANENABLE ? true : false;
+#endif
+    printk(KERN_INFO "ecp->autoneg:%d", (int)ecp->autoneg);
+
+    if (ecp->autoneg) {
+        lpa = read_phy_reg(ecp, MII_LPA);
+        if (lpa < 0) {
+            printk(KERN_INFO "lpa error : 0x%x\n", lpa);
+            return (lpa);
+        }
+
+        adv = read_phy_reg(ecp, MII_ADVERTISE);
+        if (adv < 0) {
+            printk(KERN_INFO "adv error : 0x%x\n", adv);
+            return (adv);
+        }
+
+        /* mii anar and'd anlpar to get mii abilities
+         * there is a priority order according to ieee 802.3u, as follow
+         * 100M-full, 100MbaseT4, 100M-half, 10M-full and last 10M-half
+         * fdp110 don't support 100MbaseT4
+         */
+        lpa &= adv;
+        ecp->speed = ETH_SPEED_10M;
+        ecp->duplex = ETH_DUP_HALF;
+
+        if ((lpa & (LPA_100FULL | LPA_100HALF))) {
+            ecp->speed = ETH_SPEED_100M;
+            if (lpa & LPA_100FULL)
+                ecp->duplex = ETH_DUP_FULL;
+        } else if ((lpa & LPA_10FULL)) {
+            ecp->duplex = ETH_DUP_FULL;
+        }
+
+        if (bmcr & BMCR_FULLDPLX) {
+            duplex = ETH_DUP_FULL;
+        } else {
+            duplex = ETH_DUP_HALF;
+        }
+        if (duplex != ecp->duplex) {
+            ecp->duplex = duplex;
+            printk(KERN_INFO "BMCR & ANLPAR duplex conflicts!!!\n");
+        }
+
+        if (bmcr & BMCR_SPEED100) {
+            speed = ETH_SPEED_100M;
+        } else {
+            speed = ETH_SPEED_10M;
+        }
+        if (speed != ecp->speed) {
+            ecp->speed = speed;
+            printk(KERN_INFO "BMCR & ANLPAR speed conflicts!!!\n");
+        }
+
+        if (ETH_DUP_FULL == ecp->duplex)
+            ecp->pause = (lpa & LPA_PAUSE_CAP) ? true : false;
+    } else {
+        ecp->duplex = (BMCR_FULLDPLX & bmcr) ? ETH_DUP_FULL : ETH_DUP_HALF;
+        ecp->speed = (BMCR_SPEED100 & bmcr) ? ETH_SPEED_100M : ETH_SPEED_10M;
+        ecp->pause = false;
+    }
+
+    printk(KERN_INFO VT_GREEN "\n%s -> speed:%d, duplex:%s, pause: %s\n" VT_NORMAL,
+           ecp->autoneg ? "autoneg" : "forced", ecp->speed,
+           (ETH_DUP_FULL == ecp->duplex) ? "full" : "half",
+           ecp->pause ? "supported" : "non-supported");
+
+    return (0);
+}
+
+/**
+ * fdp110_get_link - get link state;
+ * we alse can get link status from MAC_CSR5[LCIS]
+ * return 0 if link not established, 1 if established, negative value if fail
+ */
+static int fdp110_get_link(ec_priv_t * ecp)
+{
+    int     bmsr;
+
+    bmsr = read_phy_reg(ecp, MII_BMSR);
+    if (bmsr < 0) {
+        return (bmsr);
+    }
+
+    return (!!(bmsr & BMSR_LSTATUS));
+}
+
+/**
+ * fdp110_suspend -- power down or power on the phy
+ * return 0 if success, negative if fail
+ */
+static int fdp110_suspend(ec_priv_t * ecp, bool power_down)
+{
+    int     reg_val;
+
+    reg_val = read_phy_reg(ecp, MII_BMCR);
+    if (reg_val < 0) {
+        return (reg_val);
+    }
+
+    if (power_down) {
+        reg_val |= BMCR_PDOWN;
+    } else {
+        reg_val &= ~BMCR_PDOWN;
+    }
+
+    return (write_phy_reg(ecp, MII_BMCR, reg_val));
+
+}
+
+
+static struct phy_info fdp110_ops = {
+    .id = 0x0,
+    .name = "fdp110", /* same to ATC2605 */
+    .phy_hw_init = NULL,//atc2605_hw_init,
+    .phy_init = phy_init,
+    .phy_suspend = fdp110_suspend,
+    .phy_setup_advert = fdp110_setup_advert,
+    .phy_setup_forced = fdp110_setup_forced,
+    .phy_setup_aneg = fdp110_setup_aneg,
+    .phy_setup_loopback = fdp110_setup_loopback,
+    .phy_read_status = fdp110_read_status,
+    .phy_get_link = fdp110_get_link,
+};
+
+static struct phy_info ksz8041_ops = {
+    .id = 0x0,
+    .name = "ksz8041",
+    .phy_hw_init = NULL, /* not need */
+    .phy_init = phy_init,
+    .phy_suspend = fdp110_suspend,
+    .phy_setup_advert = fdp110_setup_advert,
+    .phy_setup_forced = fdp110_setup_forced,
+    .phy_setup_aneg = fdp110_setup_aneg,
+    .phy_setup_loopback = fdp110_setup_loopback,
+    .phy_read_status = fdp110_read_status,
+    .phy_get_link = fdp110_get_link,
+};
+
+
+static struct phy_info rs8201g_ops = {
+    .id = 0x0,
+    .name = "rs8201g",
+    .phy_hw_init = NULL, /* not need */
+    .phy_init = phy_init,
+    .phy_suspend = fdp110_suspend,
+    .phy_setup_advert = fdp110_setup_advert,
+    .phy_setup_forced = fdp110_setup_forced,
+    .phy_setup_aneg = fdp110_setup_aneg,
+    .phy_setup_loopback = fdp110_setup_loopback,
+    .phy_read_status = fdp110_read_status,
+    .phy_get_link = fdp110_get_link,
+};
+
+
+
+
+static struct phy_info rtl8201_ops = {
+    .id = 0x0,
+    .name = "rtl8201",
+    .phy_hw_init = NULL, /* not need */
+    .phy_init = phy_init,
+    .phy_suspend = fdp110_suspend,
+    .phy_setup_advert = fdp110_setup_advert,
+    .phy_setup_forced = fdp110_setup_forced,
+    .phy_setup_aneg = fdp110_setup_aneg,
+    .phy_setup_loopback = fdp110_setup_loopback,
+    .phy_read_status = fdp110_read_status,
+    .phy_get_link = fdp110_get_link,
+};
+
+
+
+
+void ep_set_phy_ops(ec_priv_t * ecp)
+{
+    if (ecp->phy_model == ETH_PHY_MODEL_ATC2605) {
+        printk(KERN_INFO "phy model: ATC2605\n");
+        ecp->phy_ops = &fdp110_ops;
+        //read_phy_reg = read_phy_reg_atc2605;
+        //write_phy_reg = write_phy_reg_atc2605;
+    } else if (ecp->phy_model == ETH_PHY_MODEL_KSZ8041TL) {
+        printk(KERN_INFO "phy model: KSZ8041TL\n");
+        ecp->phy_ops = &ksz8041_ops;
+        read_phy_reg = read_phy_reg_ksz8041;
+        write_phy_reg = write_phy_reg_ksz8041;
+    } else if (ecp->phy_model == ETH_PHY_MODEL_RTL8201) {
+        printk(KERN_INFO "phy model: RTL8201\n");
+        ecp->phy_ops = &rtl8201_ops;
+        read_phy_reg = read_phy_reg_rtl8201;
+        write_phy_reg = write_phy_reg_rtl8201;
+    } else if (ecp->phy_model == ETH_PHY_MODEL_SR8201G) {
+        printk(KERN_INFO "phy model: SR8201G\n");
+        ecp->phy_ops = &rs8201g_ops;
+        read_phy_reg = read_phy_reg_rs8201g;
+        write_phy_reg = write_phy_reg_rs8201g;
+    } else {
+        printk(KERN_INFO "NOT supported phy model: %u\n", ecp->phy_model);
+    }
+}
diff --git a/drivers/net/ethernet/sg8201g/ethctrl.c b/drivers/net/ethernet/sg8201g/ethctrl.c
new file mode 100755
index 0000000..35a7ceb
--- /dev/null
+++ b/drivers/net/ethernet/sg8201g/ethctrl.c
@@ -0,0 +1,3749 @@
+/******************************************************************************
+ ethctrl.c -- ethernet controller embedded in GL5202/GL5302
+ 
+ author : zhouyiliang  @Actions 
+ date : 2012-07-04 
+ version 0.1
+
+ 1. MAC address filter mode : only supports perfect filtering currently
+ 2. supports up to 14 multicast mac address
+ 
+******************************************************************************/
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/etherdevice.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/workqueue.h>
+#include <linux/gpio.h>
+#include <linux/workqueue.h>
+#include <linux/dma-mapping.h>
+#include <linux/fs.h>
+#include <linux/random.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/of_irq.h>
+#include <asm/io.h>
+#include <mach/irqs.h>
+#include <linux/clk.h>
+#include <mach/clkname.h>
+#include <mach/module-owl.h>
+#include <linux/ctype.h>
+
+#include "ethctrl.h"
+
+// test needed
+#include <linux/stddef.h>
+#include <linux/of_gpio.h>
+
+#define SETUP_FRAME_LEN 192
+#define SETUP_FRAME_PAD 16
+
+/* 0xD0, reserve 16 bytes for align */
+#define SETUP_FRAME_RESV_LEN  (SETUP_FRAME_LEN + SETUP_FRAME_PAD)
+
+#define EC_SKB_ALIGN_BITS_MASK  0x3
+#define EC_SKB_ALIGNED  0x4
+
+/* 'mii -v' will read first 8 phy registers to get status */
+#define PHY_REG_ADDR_RANGE 0x7  
+#define PHY_ADDR_MASK (PHY_ADDR_LIMIT - 1)
+#define PHY_REG_NUM_MASK 0x7
+#define PHY_REG_BITS 16
+
+#define PHY_RESUME_DELAY 2000 //\BB\BD\D0\D1ʱ\BC䣬2000 ms
+#define PHY_DETECT_DUTY 300		//\C2\D6ѯ\D6\DC\C6ڣ\AC300 ms
+#define PHY_DETECT_RESUME 500		//\BB\BD\D0Ѻ\F3 phy detectʱ\BC\E4 500ms
+// need modify it later
+#ifdef EC_DEBUG
+#define NET_MSG_ENABLE  0 //( NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_LINK )
+#else
+#define NET_MSG_ENABLE  0
+#endif
+#define EC_TX_TIMEOUT (2*HZ) /* 2s */
+#define MAX_DEVICES 1
+
+
+static struct delayed_work resume_work;
+static struct workqueue_struct *resume_queue = NULL;
+
+#ifdef DETECT_POWER_SAVE
+static struct workqueue_struct *power_save_queue = NULL;
+#endif
+
+#ifdef PHY_USE_POLL
+static struct workqueue_struct *phy_detect_queue= NULL;
+#endif
+
+static char g_default_mac_addr[ETH_MAC_LEN] = {0x00, 0x18, 0xFE, 0x61, 0xD5, 0xD6};
+static struct net_device *g_eth_dev[MAX_DEVICES];
+
+static char *macaddr = "?";
+
+int suspend_flag = 0;
+struct clk *e_clk;
+
+module_param(macaddr, charp, 0);
+MODULE_PARM_DESC(macaddr, "MAC address");
+
+static const char g_banner[] __initdata = KERN_INFO "Ethernet controller driver\
+    for Actions GL5203, @2012 Actions.\n";
+
+#ifdef ETH_TEST_MODE
+static void print_frame_data(void *frame, int len);
+static struct sk_buff *get_skb_aligned(unsigned int len);
+static int ec_netdev_start_xmit(struct sk_buff *skb, struct net_device *dev);
+void print_mac_register(ec_priv_t *ecp);
+void print_phy_register(ec_priv_t *ecp);
+static void set_mac_according_aneg(ec_priv_t *ecp);
+#endif
+
+ssize_t netif_msg_show(struct device *dev, struct device_attribute *attr,
+        char *buf)
+{
+    struct net_device *ndev = to_net_dev(dev);
+    ec_priv_t *ecp = netdev_priv(ndev);
+
+    return sprintf(buf, "0x%x\n", ecp->msg_enable);
+}
+
+ssize_t netif_msg_store(struct device *dev, struct device_attribute *attr,
+         const char *buf, size_t count)
+{
+    struct net_device *ndev = to_net_dev(dev);
+    ec_priv_t *ecp = netdev_priv(ndev);
+    char *endp;
+    unsigned long new;
+    int ret = -EINVAL;
+
+    new = simple_strtoul(buf, &endp, 0);
+    if (endp == buf)
+        goto err;
+
+    ecp->msg_enable = (int)new;
+    return count;
+err:
+    return ret;
+}
+
+DEVICE_ATTR(netif_msg, S_IRUGO | S_IWUSR, netif_msg_show, netif_msg_store);
+
+#ifdef ETH_TEST_MODE
+/* default -1 denote send single frame, [0, n] denote interval n us between 2 frames */
+static long continuity_interval = -1;
+
+ssize_t continuity_show(struct device *dev, struct device_attribute *attr,
+        char *buf)
+{
+    return sprintf(buf, "continuity_interval: %ld\n", continuity_interval);
+}
+
+ssize_t continuity_store(struct device *dev, struct device_attribute *attr,
+         const char *buf, size_t count)
+{
+    char *endp;
+    unsigned long new;
+    int ret = -EINVAL;
+
+    new = simple_strtoul(buf, &endp, 0);
+    if (endp == buf)
+        goto err;
+
+    continuity_interval = (long)new;
+    return count;
+err:
+    return ret;
+}
+
+DEVICE_ATTR(continuity, S_IRUGO | S_IWUGO, continuity_show, continuity_store);
+
+ssize_t send_pattern_show(struct device *dev, struct device_attribute *attr,
+	char *buf)
+{
+    return sprintf(buf, "pattern 0: all zero, 1: all one, 2: pseudo-random\n");
+}
+
+static void gen_frame_pattern(char *buf, int len, int pattern)
+{
+	//printk(KERN_INFO "buf: %p, len: %d, pattern: %d\n", buf, len, pattern);
+	switch (pattern) {
+	case 0:
+		memset(buf, 0, len);
+		break;
+	case 1:
+		memset(buf, 0xff, len);
+		break;
+	case 2:
+		get_random_bytes(buf, len);
+		break;
+	default:
+		printk(KERN_INFO "not supported pattern: %d\n", pattern);
+		break;
+	}
+}
+
+static int send_pattern_continuous(int n, int pat, struct net_device *ndev)
+{
+	int ret = -EINVAL;
+	struct sk_buff *skb;
+	int i = 0;
+
+	while (i++ < n) {
+		if (NULL == (skb = get_skb_aligned(PKG_MAX_LEN))) {
+			printk(KERN_INFO "no memory!\n");
+			goto err;
+		}
+		skb->len = 1500;
+		gen_frame_pattern(skb->data, skb->len, pat);
+
+		ec_netdev_start_xmit(skb, ndev);
+		if (continuity_interval > 0)
+			udelay(continuity_interval);
+	}
+	return 0;
+err:
+	return ret;
+}
+
+ssize_t send_pattern_store(struct device *dev, struct device_attribute *attr,
+	const char *buf, size_t count)
+{
+	struct net_device *ndev = to_net_dev(dev);
+	char *endp;
+	unsigned long pat = 5;
+	int ret = -EINVAL;
+	struct sk_buff *skb;
+
+	pat = simple_strtoul(buf, &endp, 0);
+	if ((endp == buf) || (pat > 2))
+	    goto err;
+
+	if (NULL == (skb = get_skb_aligned(PKG_MAX_LEN))) {
+	    printk(KERN_INFO "no memory!\n");
+	    goto err;
+	}
+	skb->len = 1500;
+
+	gen_frame_pattern(skb->data, skb->len, (int)pat);
+	//printk(KERN_INFO "frame pattern:\n");
+	//print_frame_data(skb->data, skb->len);
+	ec_netdev_start_xmit(skb, ndev);
+
+	if (continuity_interval >= 0) {
+		if (continuity_interval > 0)
+			udelay(continuity_interval);
+		send_pattern_continuous(TX_RING_SIZE - 1, (int)pat, ndev);
+	}
+
+	return count;
+err:
+	return ret;
+}
+
+DEVICE_ATTR(send_pattern, S_IRUGO | S_IWUGO,
+	send_pattern_show, send_pattern_store);
+
+ssize_t test_mode_show(struct device *dev, struct device_attribute *attr,
+	char *buf)
+{
+    return sprintf(buf, "test mode: 10 or 100 Mbps\n");
+}
+
+ssize_t test_mode_store(struct device *dev, struct device_attribute *attr,
+	const char *buf, size_t count)
+{
+	struct net_device *ndev = to_net_dev(dev);
+	ec_priv_t *ecp = netdev_priv(ndev);
+	char *endp;
+	unsigned long mode = 0;
+	int ret = -EINVAL;
+	ushort temp;
+
+	mode = simple_strtoul(buf, &endp, 0);
+	if ((endp == buf) || ((mode != 10) && (mode != 100)))
+	    goto err;
+
+	ecp->test_mode = mode;
+	ecp->speed = mode;
+	if (ETH_SPEED_10M == ecp->speed) {
+		ecp->duplex = ETH_DUP_FULL;
+		temp = read_phy_reg(ecp, PHY_REG_FTC1);
+		temp  &= ~0x40;  //clear bit 6
+		temp  |= 0x01;  //bit 0: force 10M link; bit6: force 100M
+		write_phy_reg(ecp, PHY_REG_FTC1, temp); //Set bit0
+	} else {
+		ecp->duplex = ETH_DUP_FULL;
+		temp = read_phy_reg(ecp, PHY_REG_FTC1);
+		temp  &= ~0x01;  //clear bit 0, 100M
+		temp  |= 0x40;  // bit6: force 100M
+		write_phy_reg(ecp, PHY_REG_FTC1, temp); //clear bit0
+
+		/* adjust tx current */
+		temp = read_phy_reg(ecp, 0x12);
+		temp  &= ~0x780;
+		//temp  |= 0x600; //1100, add 50+100uA
+		//temp  |= 0x680; //1101
+		//temp  |= 0x480; //1001
+		temp  |= 0x100; //0010
+		//temp  |= 0x280; //0101
+		//temp  |= 0x80; //0001
+		//temp  |= 0x180; //0011, minus 50uA  max 2.57V
+		//temp  |= 0x780; //1111
+		write_phy_reg(ecp, 0x12, temp);
+	}
+
+	printk(KERN_INFO "PHY_REG_FTC1 = 0x%x\n", (u32)read_phy_reg(ecp, PHY_REG_FTC1));
+	printk(KERN_INFO "PHY_REG_TXPN = 0x%x\n", (u32)read_phy_reg(ecp, 0x12));
+
+	/* shut auto-negoiation */
+	temp = read_phy_reg(ecp, MII_BMCR);
+	temp &= ~BMCR_ANENABLE;
+	write_phy_reg(ecp, MII_BMCR, temp);
+
+	set_mac_according_aneg(ecp);
+
+	printk(KERN_INFO "new_duplex = 0x%x\n", ecp->duplex);
+	printk(KERN_INFO "new_speed = 0x%x\n", ecp->speed);
+	print_phy_register(ecp);
+	print_mac_register(ecp);
+
+	return count;
+err:
+	return ret;
+}
+
+DEVICE_ATTR(test_mode, S_IRUGO | S_IWUGO, test_mode_show, test_mode_store);
+#endif /* ETH_TEST_MODE */
+
+static int ethernet_set_ref_clk(struct clk *clk, ulong tfreq)
+{
+	int ret = -1;
+	ulong freq;
+
+	printk(KERN_INFO "target freq: %lu\n", tfreq);
+	freq= clk_round_rate(clk, tfreq);
+	if (freq == tfreq) {
+		ret = clk_set_rate(clk, freq);
+		if (ret)
+			printk(KERN_INFO "set RMII_REF_CLK: %lu failed, errno: %d\n",
+				tfreq, -ret);
+	} else
+		printk(KERN_INFO "wrong RMII_REF_CLK: %lu\n", tfreq);
+
+	return ret;
+}
+
+static int ethernet_clock_config(int phy_mode)
+{
+	struct clk *clk;
+	int ret = -1;
+	ulong tfreq;
+
+	printk(KERN_INFO "phy_mode: %d\n", phy_mode);
+	clk = clk_get(NULL, CLKNAME_RMII_REF_CLK);
+	switch (phy_mode) {
+	case ETH_PHY_MODE_RMII:
+		tfreq = 50 * 1000 * 1000;
+		ret = ethernet_set_ref_clk(clk, tfreq);
+		break;
+	case ETH_PHY_MODE_SMII:
+		tfreq = 125 * 1000 * 1000;
+		ret = ethernet_set_ref_clk(clk, tfreq);
+		break;
+	default:
+		printk(KERN_INFO "not support phy mode: %d\n", phy_mode);
+	}
+
+	clk_put(clk);
+
+	return ret;
+}
+
+static void ethernet_clock_enable(int reset_flg)
+{
+#if 0
+    printk(KERN_ERR " %s  LINE:%d\n",__FUNCTION__,__LINE__);
+	/* enable ethernet clk */
+	putl(getl(0xb01600a4)|0x400000, 0xb01600a4);
+	udelay(100);
+	putl(getl(0xb0160084)|0x3,0xb0160084);
+	udelay(100);
+	 if(reset_flg){	
+	/* reset ethernet clk */
+		putl(getl(CMU_DEVRST1) & ~ASOC_ETH_CLOCK_RST, CMU_DEVRST1);
+		udelay(100);
+		printk(KERN_ERR " %s  LINE:%d\n",__FUNCTION__,__LINE__);
+		putl(getl(CMU_DEVRST1) | ASOC_ETH_CLOCK_RST, CMU_DEVRST1);
+		udelay(100);
+		//printk(KERN_ERR " %s  LINE:%d\n",__FUNCTION__,__LINE__);
+	 }
+	 printk(KERN_ERR " %s  LINE:%d\n",__FUNCTION__,__LINE__);
+
+#else
+//	struct clk *clk;
+	int ret;
+//	clk = clk_get(NULL, CLKNAME_CMUMOD_ETHERNET);
+//	ret = clk_prepare(e_clk);
+//	if (ret)
+//		printk(KERN_INFO "prepare ethernet clock failed, errno: %d\n", -ret);
+  if(e_clk!=NULL){
+		ret = clk_enable(e_clk);
+		if (ret)
+			printk(KERN_INFO "enable ethernet clock failed, errno: %d\n", -ret);
+//	clk_put(e_clk);
+	
+		udelay(100);
+
+	/* reset ethernet clk */
+  	if(reset_flg){	
+			  printk(KERN_INFO "func:%s: ethernet clk reset\n", __func__);
+	    	module_reset(MODULE_RST_ETHERNET);
+		}		    
+		udelay(100);
+	}
+#endif
+}
+
+static void ethernet_clock_disable(void)
+{
+#if 0
+	/* disable ethernet clk */
+	putl(getl(CMU_DEVCLKEN1) & ~ASOC_ETH_CLOCK_EN, CMU_DEVCLKEN1);
+#else
+//	struct clk *clk;
+
+//	clk = clk_get(NULL, CLKNAME_CMUMOD_ETHERNET);
+  if(e_clk!=NULL){
+//		clk_disable(e_clk);
+//	clk_unprepare(e_clk);
+//	clk_put(e_clk);
+	  udelay(100);
+	}
+#endif
+}
+
+/* data is a ethernet frame */
+static void check_icmp_sequence(const void *data, const char *msg)
+{
+#define ptr_to_u32(data, off) (ntohl(*(u32*)((char *)data + off)))
+
+	printk(KERN_INFO "-- %s -- %p, icmp: 0x%x\n", msg, (char *)data + 0x14, (ptr_to_u32(data, 0x14) & 0xff));
+	if ((ptr_to_u32(data, 0x14) & 0xff) == 0x01) {// protocol icmp 0x01
+		printk(KERN_INFO "ICMP ");
+		if (((ptr_to_u32(data, 0x20) >> 8) & 0xff) == 0x8) //icmp type
+			printk(KERN_INFO "ping echo request, ");
+		else if (((ptr_to_u32(data, 0x20) >> 8) & 0xff) == 0x0)
+			printk(KERN_INFO "ping echo reply, ");
+		else
+			printk(KERN_INFO "not ping echo request or reply, ");
+		printk(KERN_INFO "sequence number: %u\n", ptr_to_u32(data, 0x28) >> 16);
+	} else {
+		printk(KERN_INFO "not a ICMP packet\n");
+	}
+}
+
+static void print_mac_address(const char *mac)
+{
+    int i;
+    for (i = 0; i < ETH_MAC_LEN - 1; i++) {
+        printk(KERN_INFO "%02x-", (unsigned int)mac[i] & 0xFF);
+    }
+    printk(KERN_INFO "%02x\n", (unsigned int)mac[i] & 0xFF);
+    return;
+}
+
+static int ctox(int c)
+{
+	int tmp;
+
+	if (!isxdigit(c)) {
+		printk(KERN_INFO "'%c' is not hex digit\n", (char)c);
+		return -1;
+	}
+
+	if ((c >= '0') && (c <= '9'))
+		tmp = c - '0';
+	else
+		tmp = (c | 0x20) - 'a' + 10;
+
+	return tmp;
+}
+
+static int parse_mac_address(const char *mac, int len)
+{
+	int tmp, tmp2;
+	int i = 0;
+	int j = 0;
+	char s[16] = "";
+	int c;
+
+	printk(KERN_INFO "ethernet mac address string: %s, len: %d\n", mac, strlen(mac));
+	if (17 == len) {
+		if (strlen(mac) > 17) {
+			printk(KERN_INFO "ethernet mac address string too long\n");
+			return -1;
+		}
+		while ((c = mac[i++]) != '\0') {
+			if (c == ':')
+				continue;
+			s[j++] = c;
+		}
+		s[j] = '\0';
+		printk(KERN_INFO "mac address string stripped colon: %s\n", s);
+	} else if (12 == len) {
+		if (strlen(mac) > 12) {
+			printk(KERN_INFO "ethernet mac address string too long\n");
+			return -1;
+		}
+		memcpy(s, mac, 12);
+		s[12] = '\0';
+	} else {
+		printk(KERN_INFO "length of ethernet mac address is not 12 or 17\n");
+		return -1;
+	}
+
+	for (i = 0; i < ETH_MAC_LEN; i++) {
+		tmp = ctox(s[i * 2]);
+		tmp2 = ctox(s[i * 2 + 1]);
+		tmp = (tmp * 16) + tmp2;
+		*(char *)(g_default_mac_addr + i) = tmp & 0xFF;
+	}
+
+	return 0;
+}
+
+static int read_mac_address(struct file *filp, char *mac, int *len)
+{
+	loff_t l;
+	loff_t offset = 0;
+	mm_segment_t fs;
+	int _len, i;
+
+	l = vfs_llseek(filp, 0, SEEK_END);
+	offset = vfs_llseek(filp, 0, SEEK_SET);
+	printk(KERN_INFO "file's actual len: %d\n", (int)l);
+	if (l >= 17) {
+		_len = 17;
+	} else if (l >= 12) {
+		_len = 12;
+	} else {
+		printk( "mac address is too short\n");
+		return -1;
+	}
+	printk(KERN_INFO "file's len to be read: %d\n", _len);
+
+	fs = get_fs();
+	set_fs(get_ds());
+
+	l = vfs_read(filp, (char __user *)mac, (size_t)_len, &offset);
+	set_fs(fs);
+	printk(KERN_INFO "mac string len actually read: %d\n", (int)l);
+	if (l > 12) {
+		if ((mac[2] == ':') && (mac[5] == ':'))
+			_len = 17;
+		else
+			_len = 12;
+	} else if (12 == l) {
+		_len = 12;
+	} else {
+		printk(KERN_INFO "ethernet mac address not valid: %s\n", mac);
+		return -1;
+	}
+
+	*len = _len;
+	mac[_len] = '\0';
+	printk(KERN_INFO "ethernet mac address read from file: %s, len: %d\n", mac, _len);
+	for (i = 0; i < _len; i++) {
+		if (!isxdigit(mac[i]) && ':' != mac[i]) {
+			printk(KERN_INFO "mac address has invalid char: %c\n", mac[i]);
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
+/* if all the paths are not usable, use random mac each boot */
+static const char *get_def_mac_addr(struct platform_device *pdev)
+{
+    struct device_node *np = pdev->dev.of_node;
+    struct file *filp;
+    loff_t offset = 0;
+    char def_mac[20] = "";
+    const char *str;
+    mm_segment_t fs;
+    int len;
+    int ret;
+
+#define ETH_MAC_ADDR_BURNED_PATH "/sys/miscinfo/infos/ethmac"
+//#define ETH_MAC_ADDR_BURNED_PATH "/data/mac_address"
+#define ETH_MAC_ADDR_PATH "/config/mac_address.bin"
+#define ETH_MAC_ADDR_RANDDOM_PATH "/data/mac_address_random"
+
+    filp = filp_open(ETH_MAC_ADDR_BURNED_PATH, O_RDONLY, 0);
+    if (IS_ERR_OR_NULL(filp)) {
+        printk(KERN_INFO "file %s can't be opened\n", ETH_MAC_ADDR_BURNED_PATH);
+    } else {
+        if (!read_mac_address(filp, def_mac, &len)) {
+            parse_mac_address(def_mac, len);
+            printk(KERN_INFO "use burned mac address: ");
+            print_mac_address(g_default_mac_addr);
+            filp_close(filp, current->files);
+            return g_default_mac_addr;
+        }
+        filp_close(filp, current->files);
+    }
+
+    str = of_get_property(np, "local-mac-address", NULL);
+    if (str == NULL) {
+        printk(KERN_INFO "no local-mac-address in dts\n");
+    } else {
+        printk(KERN_INFO "local-mac-address: ");
+        print_mac_address(str);
+        memcpy(g_default_mac_addr, str, ETH_MAC_LEN);
+    }
+
+    ret = of_property_read_string(np, "random-mac-address", &str);
+    if (ret) {
+        printk(KERN_INFO "no random-mac-address in dts\n");
+    } else {
+        printk(KERN_INFO "random-mac-address: %s\n", str);
+        if (!strcmp("okay", str))
+            goto random_mac;
+    }
+
+    printk(KERN_INFO "no mac burned, use default mac address: ");
+    print_mac_address(g_default_mac_addr);
+    return g_default_mac_addr;
+
+random_mac:
+    filp = filp_open(ETH_MAC_ADDR_PATH, O_RDONLY, 0);
+    if (IS_ERR_OR_NULL(filp)) {
+        printk(KERN_INFO "file %s can't be opened\n", ETH_MAC_ADDR_PATH);
+    } else {
+        if (!read_mac_address(filp, def_mac, &len)) {
+            parse_mac_address(def_mac, len);
+            printk(KERN_INFO "use mac stored in file: ");
+            print_mac_address(g_default_mac_addr);
+            filp_close(filp, current->files);
+            return g_default_mac_addr;
+        }
+        filp_close(filp, current->files);
+    }
+
+    get_random_bytes(def_mac, ETH_MAC_LEN);
+    memcpy(g_default_mac_addr + 3, def_mac + 3, ETH_MAC_LEN - 3);
+
+    fs = get_fs();
+    set_fs(get_ds());
+
+    filp = filp_open(ETH_MAC_ADDR_RANDDOM_PATH, O_RDONLY, 0);
+    if (IS_ERR_OR_NULL(filp)) {
+        filp = filp_open(ETH_MAC_ADDR_RANDDOM_PATH, O_WRONLY | O_CREAT, 0640);
+        if (!IS_ERR_OR_NULL(filp)) {
+            printk(KERN_INFO "use random mac generated: ");
+            print_mac_address(g_default_mac_addr);
+            vfs_write(filp, (char __user *)g_default_mac_addr, ETH_MAC_LEN, &offset);
+            filp_close(filp, current->files);
+        }
+    } else {
+        if (vfs_read(filp, (char __user *)def_mac, ETH_MAC_LEN, &offset)
+            == ETH_MAC_LEN) {
+            memcpy(g_default_mac_addr, def_mac, ETH_MAC_LEN);
+            printk(KERN_INFO "use random mac stored: ");
+            print_mac_address(g_default_mac_addr);
+        }
+        filp_close(filp, current->files);
+    }
+
+    set_fs(fs);
+
+    return g_default_mac_addr;
+}
+
+static void print_frame_data(void *frame, int len)
+{
+    int i;
+    unsigned char *tmp = (unsigned char *)frame;
+
+    for (i = 0; i < len; i++) {
+        printk(KERN_INFO "%02x ",  (unsigned int)(*tmp));
+        if (0xF == (i & 0xF)) {
+            printk(KERN_INFO "\n");
+        }
+        tmp++;
+    }
+    printk(KERN_INFO "\n");
+}
+
+static void print_tx_bds(ec_priv_t * priv)
+{
+    int     i;
+    ec_bd_t *tx_bds = priv->tx_bd_base;
+    volatile ec_bd_t *buf;
+
+    printk(KERN_INFO "---- tx ring status ----\n");
+    printk(KERN_INFO "tx_bd_base = 0x%p, tx_full = %u\n", priv->tx_bd_base, (unsigned)priv->tx_full);
+    printk(KERN_INFO "cur_tx = 0x%p, skb_cur = %u\n", priv->cur_tx, (unsigned)priv->skb_cur);
+    printk(KERN_INFO "dirty_tx = 0x%p, skb_dirty = %u\n", priv->dirty_tx, (unsigned)priv->skb_dirty);
+
+    printk(KERN_INFO "---- tx bds ----\n");
+    printk(KERN_INFO "     status\t control\t buf addr\n");
+    for (i = 0; i < TX_RING_SIZE; i++) {
+        buf = &tx_bds[i];
+        printk(KERN_INFO "%03d: 0x%08x\t 0x%08x\t 0x%08x\n", i, (unsigned int) buf->status,
+               (unsigned int) buf->control, (unsigned int) buf->buf_addr);
+    }
+}
+
+static void print_rx_bds(ec_priv_t * priv)
+{
+    int     i;
+    ec_bd_t *rx_bds = priv->rx_bd_base;
+    volatile ec_bd_t *buf;
+
+    printk(KERN_INFO "---- rx ring status ----\n");
+    printk(KERN_INFO "rx_bd_base = 0x%p\n", priv->rx_bd_base);
+    printk(KERN_INFO "cur_rx = 0x%p\n", priv->cur_rx);
+
+    printk(KERN_INFO "---- rx bds ----\n");
+    printk(KERN_INFO "     status\t control\t buf addr\n");
+    for (i = 0; i < RX_RING_SIZE; i++) {
+        buf = &rx_bds[i];
+        printk(KERN_INFO "%03d: 0x%08x\t 0x%08x\t 0x%08x\n", i, (unsigned int) buf->status,
+               (unsigned int) buf->control, (unsigned int) buf->buf_addr);
+    }
+}
+
+void print_phy_register(ec_priv_t *ecp)
+{
+#if 0
+	printk(KERN_INFO "phy MII_BMCR: 0x%x\n", (uint)read_phy_reg(ecp, MII_BMCR));
+	printk(KERN_INFO "phy MII_BMSR: 0x%x\n", (uint)read_phy_reg(ecp, MII_BMSR));
+	printk(KERN_INFO "phy MII_PHYSID1: 0x%x\n", (uint)read_phy_reg(ecp, MII_PHYSID1));
+	printk(KERN_INFO "phy MII_PHYSID2: 0x%x\n", (uint)read_phy_reg(ecp, MII_PHYSID2));
+	printk(KERN_INFO "phy MII_ADVERTISE: 0x%x\n", (uint)read_phy_reg(ecp, MII_ADVERTISE));
+	printk(KERN_INFO "phy MII_LPA: 0x%x\n", (uint)read_phy_reg(ecp, MII_LPA));
+	printk(KERN_INFO "phy MII_CTRL1000: 0x%x\n", (uint)read_phy_reg(ecp, MII_CTRL1000));
+	printk(KERN_INFO "phy MII_STAT1000: 0x%x\n", (uint)read_phy_reg(ecp, MII_STAT1000));
+	printk(KERN_INFO "phy MII_MMD_CTRL: 0x%x\n", (uint)read_phy_reg(ecp, MII_MMD_CTRL));
+	printk(KERN_INFO "phy MII_MMD_DATA: 0x%x\n", (uint)read_phy_reg(ecp, MII_MMD_DATA));
+	printk(KERN_INFO "phy MII_ESTATUS: 0x%x\n", (uint)read_phy_reg(ecp, MII_ESTATUS));
+	printk(KERN_INFO "phy MII_DCOUNTER: 0x%x\n", (uint)read_phy_reg(ecp, MII_DCOUNTER));
+	printk(KERN_INFO "phy MII_FCSCOUNTER: 0x%x\n", (uint)read_phy_reg(ecp, MII_FCSCOUNTER));
+	printk(KERN_INFO "phy MII_NWAYTEST: 0x%x\n", (uint)read_phy_reg(ecp, MII_NWAYTEST));
+	printk(KERN_INFO "phy MII_RERRCOUNTER: 0x%x\n", (uint)read_phy_reg(ecp, MII_RERRCOUNTER));
+	printk(KERN_INFO "phy MII_SREVISION: 0x%x\n", (uint)read_phy_reg(ecp, MII_SREVISION));
+	printk(KERN_INFO "phy MII_EXPANSION: 0x%x\n", (uint)read_phy_reg(ecp, MII_EXPANSION));
+	printk(KERN_INFO "phy MII_RESV1: 0x%x\n", (uint)read_phy_reg(ecp, MII_RESV1));
+	printk(KERN_INFO "phy MII_LBRERROR: 0x%x\n", (uint)read_phy_reg(ecp, MII_LBRERROR));
+	printk(KERN_INFO "phy MII_PHYADDR: 0x%x\n", (uint)read_phy_reg(ecp, MII_PHYADDR));
+	printk(KERN_INFO "phy MII_RESV2: 0x%x\n", (uint)read_phy_reg(ecp, MII_RESV2));
+	printk(KERN_INFO "phy MII_TPISTATUS: 0x%x\n", (uint)read_phy_reg(ecp, MII_TPISTATUS));
+	printk(KERN_INFO "phy MII_NCONFIG: 0x%x\n", (uint)read_phy_reg(ecp, MII_NCONFIG));	
+#endif
+}
+
+void print_mac_register(ec_priv_t *ecp)
+{
+#if 0
+    volatile ethregs_t *hw_regs = ecp->hwrp;
+
+	printk(KERN_INFO "CMU_DEVCLKEN1:0x%x\n", act_readl(CMU_DEVCLKEN1));
+	printk(KERN_INFO "MFP_CTL0:0x%x\n", act_readl(MFP_CTL0));
+	printk(KERN_INFO "PAD_DRV0:0x%x\n", act_readl(PAD_DRV0));
+	printk(KERN_INFO "PAD_PULLCTL0:0x%x\n", act_readl(PAD_PULLCTL0));
+	printk(KERN_INFO "GPIO_AOUTEN:0x%x\n", act_readl(GPIO_AOUTEN));
+	printk(KERN_INFO "GPIO_AINEN:0x%x\n", act_readl(GPIO_AINEN));
+	printk(KERN_INFO "GPIO_ADAT:0x%x\n", act_readl(GPIO_ADAT));
+
+    /* CSR0~20 */
+    printk(KERN_INFO "MAC_CSR0:0x%08lx, address:%p\n", hw_regs->er_busmode, &hw_regs->er_busmode);
+    printk(KERN_INFO "MAC_CSR1:0x%08lx, address:%p\n", hw_regs->er_txpoll, &hw_regs->er_txpoll);
+    printk(KERN_INFO "MAC_CSR2:0x%08lx, address:%p\n", hw_regs->er_rxpoll, &hw_regs->er_rxpoll);
+    printk(KERN_INFO "MAC_CSR3:0x%08lx, address:%p\n", hw_regs->er_rxbdbase, &hw_regs->er_rxbdbase);
+    printk(KERN_INFO "MAC_CSR4:0x%08lx, address:%p\n", hw_regs->er_txbdbase, &hw_regs->er_txbdbase);
+    printk(KERN_INFO "MAC_CSR5:0x%08lx, address:%p\n", hw_regs->er_status, &hw_regs->er_status);
+    printk(KERN_INFO "MAC_CSR6:0x%08lx, address:%p\n", hw_regs->er_opmode, &hw_regs->er_opmode);
+    printk(KERN_INFO "MAC_CSR7:0x%08lx, address:%p\n", hw_regs->er_ienable, &hw_regs->er_ienable);
+    printk(KERN_INFO "MAC_CSR8:0x%08lx, address:%p\n", hw_regs->er_mfocnt, &hw_regs->er_mfocnt);
+    printk(KERN_INFO "MAC_CSR9:0x%08lx, address:%p\n", hw_regs->er_miimng, &hw_regs->er_miimng);
+    printk(KERN_INFO "MAC_CSR10:0x%08lx, address:%p\n", hw_regs->er_miism, &hw_regs->er_miism);
+    printk(KERN_INFO "MAC_CSR11:0x%08lx, address:%p\n", hw_regs->er_imctrl, &hw_regs->er_imctrl);
+    printk(KERN_INFO "MAC_CSR16:0x%08lx, address:%p\n", hw_regs->er_maclow, &hw_regs->er_maclow);
+    printk(KERN_INFO "MAC_CSR17:0x%08lx, address:%p\n", hw_regs->er_machigh, &hw_regs->er_machigh);
+    printk(KERN_INFO "MAC_CSR18:0x%08lx, address:%p\n", hw_regs->er_cachethr, &hw_regs->er_cachethr);
+    printk(KERN_INFO "MAC_CSR19:0x%08lx, address:%p\n", hw_regs->er_fifothr, &hw_regs->er_fifothr);
+    printk(KERN_INFO "MAC_CSR20:0x%08lx, address:%p\n", hw_regs->er_flowctrl, &hw_regs->er_flowctrl);
+
+    printk(KERN_INFO "MAC_CTRL: 0x%x:0x%x\n", MAC_CTRL, act_readl(MAC_CTRL));
+#endif
+    return;
+}
+
+/*----------------------------------- mii hooks -------------------------------*/
+
+/**
+ * ec_mdio_read -  hook for struct mii_if_info{.mdio_read}
+ */
+static int ec_mdio_read(struct net_device *dev, int phy_addr, int reg_addr)
+{
+    ec_priv_t *ecp = netdev_priv(dev);
+    printk(KERN_INFO "read phy reg-%x\n", reg_addr);
+    return (read_phy_reg(ecp, reg_addr));
+}
+
+
+/**
+ * ec_mdio_write -  hook for struct mii_if_info{.mdio_write}
+ */
+static void ec_mdio_write(struct net_device *dev, int phy_addr, int reg_addr, int val)
+{
+    ec_priv_t *ecp = netdev_priv(dev);
+    write_phy_reg(ecp, reg_addr, val);
+    printk(KERN_INFO "write phy reg-%x, value-%x\n", reg_addr, val);
+}
+
+
+/*---------------------------------- MAC routines -----------------------------*/
+
+static inline void raw_tx_bd_init(ec_priv_t * ecp)
+{
+    int     i;
+    volatile ec_bd_t *tx_bds = ecp->tx_bd_base;
+
+    for (i = 0; i < TX_RING_SIZE; i++) {
+        tx_bds[i] = (ec_bd_t) {
+            .status = 0,        /* host own it */
+            .control = TXBD_CTRL_IC,
+            .buf_addr = 0,
+            .reserved = 0
+        };
+    }
+    tx_bds[i - 1].control |= TXBD_CTRL_TER;
+
+    return;
+}
+
+
+static inline void raw_rx_bd_init(ec_priv_t * ecp)
+{
+    int     i;
+    volatile ec_bd_t *rx_bds = ecp->rx_bd_base;
+
+    for (i = 0; i < RX_RING_SIZE; i++) {
+        rx_bds[i] = (ec_bd_t) {
+            .status = RXBD_STAT_OWN,
+            .control = RXBD_CTRL_RBS1(PKG_MAX_LEN),
+            .buf_addr = 0,
+            .reserved = 0
+        };
+    }
+    rx_bds[i - 1].control |= RXBD_CTRL_RER;
+
+    return;
+}
+
+
+/**
+ * get_skb_aligned - get a skb which the address of skb->data is 4B aligned
+ */
+static struct sk_buff *get_skb_aligned(unsigned int len)
+{
+    int     offset;
+    struct sk_buff *skb = NULL;
+
+    if (NULL == (skb = dev_alloc_skb(len))) {
+        return (NULL);
+    }
+    
+    offset = (unsigned long) skb->data & EC_SKB_ALIGN_BITS_MASK;
+    if (unlikely(offset)) {
+        skb_reserve(skb, EC_SKB_ALIGNED - offset);
+    }
+
+    return (skb);
+}
+
+
+static inline void free_rxtx_skbs(struct sk_buff **array, int len)
+{
+    int     i;
+
+    for (i = 0; i < len; i++) {
+        if (NULL != array[i]) {
+            dev_kfree_skb_any(array[i]);
+            array[i] = NULL;
+        }
+    }
+    return;
+}
+
+
+/**
+ * prepare_tx_bd -- preparation for tx buffer descripters
+ *
+ * always success
+ */
+static inline int prepare_tx_bd(ec_priv_t * ecp)
+{
+
+    volatile ec_bd_t *tx_bds_head = ecp->tx_bd_base;
+
+    ecp->cur_tx = (ec_bd_t *)tx_bds_head;
+    ecp->dirty_tx = (ec_bd_t *)tx_bds_head;
+    ecp->skb_cur = 0;
+    ecp->skb_dirty = 0;
+    ecp->tx_full = false;
+
+    free_rxtx_skbs(ecp->tx_skb, TX_RING_SIZE);
+    raw_tx_bd_init(ecp);
+
+    return (0);
+}
+
+
+/**
+ * prepare_rx_bd -- preparation for rx buffer descripters
+ *
+ * return 0 if success, return -1 if fail
+ */
+static int prepare_rx_bd(ec_priv_t * ecp)
+{
+    int     i;
+    struct sk_buff *skb = NULL;
+    volatile ec_bd_t *rx_bds_head = ecp->rx_bd_base;
+
+    printk(KERN_INFO "ecp->rx_bd_base: %p\n", ecp->rx_bd_base);
+    ecp->cur_rx = (ec_bd_t *)rx_bds_head;
+    raw_rx_bd_init(ecp);
+
+    free_rxtx_skbs(ecp->rx_skb, RX_RING_SIZE);
+    
+    for (i = 0; i < RX_RING_SIZE; i++) {
+        if ((skb = get_skb_aligned(PKG_MAX_LEN))) {
+            ecp->rx_skb[i] = skb; 
+            /* should be 4-B aligned */
+            rx_bds_head[i].buf_addr = dma_map_single(&ecp->netdev->dev,
+                    skb->data, PKG_MAX_LEN, DMA_FROM_DEVICE);
+            //printk(KERN_INFO "rx_bds_head[%d].buf_addr:0x%lx\n", i, rx_bds_head[i].buf_addr);
+        } else {
+            printk(KERN_INFO "can't alloc skb\n");
+            free_rxtx_skbs(ecp->rx_skb, i);
+            raw_rx_bd_init(ecp);
+            return (-1);
+        }
+    }
+    printk(KERN_INFO "ecp->cur_rx: %p\n", ecp->cur_rx);
+
+    return (0);
+}
+
+
+/* suitable for less than 7 chars of string */
+static inline int string_to_hex(char *str, int len)
+{
+    int     val;
+    int     i;
+    char    ch;
+
+    val = 0;
+    for (i = 0; i < len; i++) {
+        ch = str[i];
+        if ('0' <= ch && ch <= '9') {
+            val = (val << 4) + ch - '0';
+        } else if ('a' <= ch && ch <= 'f') {
+            val = (val << 4) + 10 + ch - 'a';
+        } else if ('A' <= ch && ch <= 'F') {
+            val = (val << 4) + 10 + ch - 'A';
+        } else {
+            return (-1);
+        }
+    }
+
+    return (val);
+}
+
+
+/**
+ * parse_mac_addr -- parse string of mac address to number mac address
+ *
+ * return 0 if success, negative value if fail
+ */
+static inline int parse_mac_addr(ec_priv_t * ecp, char *mac)
+{
+    int     i;
+    int     j;
+    int     result;
+    
+    /* string of mac - such as "01:02:03:04:05:06" */
+    if (17 != strlen(mac)) {
+        return (-1);
+    }
+
+    for (i = 0, j = 2; i < 5; i++, j += 3) {
+        if (':' != mac[j]) {
+            return (-1);
+        }
+    }
+
+    for (i = 0, j = 0; i < 6; i++, j += 3) {
+        result = string_to_hex(mac + j, 2);
+        if (-1 != result) {
+            ecp->overrided_mac[i] = (char) result;
+        } else {
+            return (result);
+        }
+    }
+
+    return (0);
+}
+
+
+static inline void fill_macaddr_regs(ec_priv_t * ecp, const char *mac_addr)
+{
+    volatile ethregs_t *hw_regs = ecp->hwrp;
+
+    hw_regs->er_maclow = *(unsigned long *) mac_addr;
+    hw_regs->er_machigh = *(unsigned short *) (mac_addr + 4);
+    return;
+}
+
+
+static inline void set_mac_addr(ec_priv_t * ecp)
+{
+    if (ecp->mac_addr) {
+        fill_macaddr_regs(ecp, ecp->mac_addr);
+        printk(KERN_INFO "using previous one\n");
+        return;
+    }
+    
+    if ('?' != macaddr[0]) {
+        printk(KERN_INFO "parse mannual mac address\n");
+        if ((0 == parse_mac_addr(ecp, macaddr)) && 
+            compare_ether_addr(macaddr, g_default_mac_addr)) {
+
+            fill_macaddr_regs(ecp, ecp->overrided_mac);
+            ecp->mac_addr = ecp->overrided_mac;
+            ecp->mac_overrided = true;
+            return;
+        }
+    }
+
+    printk(KERN_INFO "set default mac address \n");
+
+    fill_macaddr_regs(ecp, g_default_mac_addr);
+    ecp->mac_addr = g_default_mac_addr;
+    ecp->mac_overrided = false;
+    return;
+}
+
+
+/* NOTE: it has side effect for dest parameter */
+#define COPY_MAC_ADDR(dest, mac)  do {\
+    *(unsigned short *)(dest) = *(unsigned short *)(mac); \
+    *(unsigned short *)((dest) + 4) = *(unsigned short *)((mac) + 2); \
+    *(unsigned short *)((dest) + 8) = *(unsigned short *)((mac) + 4); \
+    (dest) += 12; \
+}while (0)
+
+
+/**
+ * build_setup_frame -- build setup-frame of mac address filter  in @buffer
+ *
+ * @buf_len should be longer than or equal  SETUP_FRAME_LEN (192 bytes), but we only 
+ * use SETUP_FRAME_LEN bytes exactly.
+ *
+ * return the address of @buffer if success, or NULL if not
+ */
+static char *build_setup_frame(ec_priv_t * ecp, char *buffer, int buf_len)
+{
+    char    broadcast_mac[ETH_MAC_LEN] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
+    char   *frame = buffer;
+    char   *mac;
+
+    if (NULL == buffer || buf_len < SETUP_FRAME_LEN) {
+        printk(KERN_INFO "error parameters\n");
+        return (NULL);
+    }
+
+    memset(frame, 0, SETUP_FRAME_LEN);
+
+    mac = (char *) ecp->mac_addr;
+    COPY_MAC_ADDR(frame, mac);
+    
+    mac = broadcast_mac;
+    COPY_MAC_ADDR(frame, mac);
+
+    /* fill multicast addresses */
+    if (!ecp->all_multicast && ecp->multicast) {
+        int     i;
+        int     count = ecp->multicast_list.count;
+
+        if (count > MULTICAST_LIST_LEN) {
+            count = MULTICAST_LIST_LEN;
+        }
+
+        for (i = 0; i < count; i++) {
+            mac = ecp->multicast_list.mac_array[i];
+            COPY_MAC_ADDR(frame, mac);
+        }
+    }
+
+    if (ecp->msg_enable) {
+        INFO_GREEN("overrided : %s -- multicast : %s\n",
+            ecp->mac_overrided ? "true" : "false",
+            ecp->multicast ? "true" : "false");
+    }
+
+    return (buffer);
+}
+
+
+/**
+ * transmit_setup_frame -- transmit setup-frame of  mac address filter
+ *
+ * the function is not thread-safety, thus in multithread envirement should hold ec_prive_t{.lock}.
+ * and before call it, ec_prive_t{.mac_addr} should point to a suitalbe mac address used
+ *
+ * MAC will raise CSR5.ETI interrupt after transmission of setup-frame, so we use uniform 
+ * manner  to deal with it.
+ *
+ * return 0 if success, -1 if fail
+ */
+static int transmit_setup_frame(ec_priv_t *ecp)
+{
+    struct sk_buff *skb = NULL;
+    volatile ec_bd_t *buf_des = ecp->cur_tx;
+
+    if (ecp->tx_full) {
+        /* may happen when change macs if not in open ethdev  */
+        printk(KERN_INFO "error : tx buffer is full.\n");
+        return (-1);
+    }
+    
+    /* will build a setup-frame in a skb */
+    skb = get_skb_aligned(SETUP_FRAME_RESV_LEN);
+    if (NULL == skb) {
+        printk( "error : no memory for setup frame.\n");
+        return (-1);
+    }
+
+    skb_put(skb, SETUP_FRAME_LEN);
+
+    /* address of skb->data should be 4-bytes aligned */
+    if (NULL == build_setup_frame(ecp, skb->data, SETUP_FRAME_LEN)) {
+        printk( "error : building of setup-frame failed.\n");
+        dev_kfree_skb_any(skb);
+        return (-1);
+    }
+
+    /* send it out as normal packet */
+    ecp->tx_skb[ecp->skb_cur] = skb;
+    ecp->skb_cur = (ecp->skb_cur + 1) & TX_RING_MOD_MASK;
+
+    /*
+     * Push the data cache so the NIC does not get stale memory data.
+     */
+    buf_des->buf_addr = dma_map_single(&ecp->netdev->dev, skb->data, PKG_MAX_LEN, DMA_TO_DEVICE);
+
+    buf_des->control &= (TXBD_CTRL_TER | TXBD_CTRL_IC); /* maintain these bits */
+    buf_des->control |= TXBD_CTRL_SET;
+    buf_des->control |= TXBD_CTRL_TBS1(SETUP_FRAME_LEN);
+    mb();
+    buf_des->status = TXBD_STAT_OWN;
+    mb();
+
+    /* when call the routine, TX and Rx should have already stopped */
+    ecp->hwrp->er_opmode |= EC_OPMODE_ST;
+    ecp->hwrp->er_txpoll = EC_TXPOLL_ST;  
+
+    if (buf_des->control & TXBD_CTRL_TER)
+        ecp->cur_tx = ecp->tx_bd_base;
+    else
+        ecp->cur_tx++;
+    
+    if (ecp->cur_tx == ecp->dirty_tx) {
+        ecp->tx_full = true;
+        netif_stop_queue(ecp->netdev);
+    }
+
+    /* resume old status */    
+    ecp->hwrp->er_opmode &= ~EC_OPMODE_ST;  
+	netif_stop_queue(ecp->netdev);
+    printk(KERN_INFO "The end of transmit_setup_frame\n");
+    return (0);
+}
+
+
+/**
+  * when reconfigrate mac's mode, should stop tx and rx first.  so before call the following 
+  * tow function, make sure tx and rx have stopped
+ */
+static inline void set_mode_promisc(ec_priv_t * ecp, bool supported)
+{
+    volatile ethregs_t *hw_regs = ecp->hwrp;
+
+    ecp->promiscuous = supported;
+    if (supported) {
+        hw_regs->er_opmode |= EC_OPMODE_PR;
+        EC_NOP;
+    } else {
+        hw_regs->er_opmode &= ~EC_OPMODE_PR;
+        EC_NOP;
+    }
+    return;
+}
+
+static inline void set_mode_all_multicast(ec_priv_t * ecp, bool supported)
+{
+    volatile ethregs_t *hw_regs = ecp->hwrp;
+
+    ecp->all_multicast = supported;
+    if (supported)
+        hw_regs->er_opmode |= EC_OPMODE_PM;
+    else
+        hw_regs->er_opmode &= ~EC_OPMODE_PM;
+
+    return;
+}
+
+#if 0
+static void mac_rmii_get_pin(void)
+{
+    unsigned long mfp_ctl0;
+	unsigned long pad_drive;
+    unsigned long pad_pull_ctl0;
+	unsigned long mac_ctl_temp;
+	
+	//pad enable
+    act_writel(0x2, PAD_CTL);
+        
+	/*mac mfp config*/
+    mfp_ctl0 = act_readl(MFP_CTL0);
+    mfp_ctl0 &= 0xfff8003f;        // RMII pin
+    mfp_ctl0 |= 0x00000000;
+    act_writel(mfp_ctl0, MFP_CTL0);
+
+    mac_ctl_temp = act_readl(MAC_CTRL);
+	act_writel(mac_ctl_temp | 0x1<<1, MAC_CTRL);	// use RMII
+	
+    /*mac rmii pad drive - level2*/
+	pad_drive = act_readl(PAD_DRV0);
+    pad_drive &= ~0x00ffc000;
+	pad_drive |= 0x00554000;
+	act_writel(pad_drive, PAD_DRV0);
+
+	/*mac rmii pad drive - pad pull ctl*/
+	pad_pull_ctl0 = act_readl(PAD_PULLCTL0);
+    pad_pull_ctl0 &= ~0x00010000;
+	pad_pull_ctl0 |= 0x0;
+	act_writel(pad_pull_ctl0, PAD_PULLCTL0);
+}
+
+static int get_pin_count = 0;
+
+static int hw_rmii_get_pin(void) {
+	int result = 0;
+
+	get_pin_count++;
+	//printk(KERN_INFO "get_pin_count:%d\n", get_pin_count);
+	if (get_pin_count > 1) {
+		return 0;
+	}
+	
+	result = asoc_mfp_lock(MOD_ID_ETHERNET, MFP_OPT_CAN_SLEEP, NULL);
+	return result;
+}
+
+static int hw_rmii_release_pin(void) {
+	int result = 0;
+
+	get_pin_count--;
+	//printk(KERN_INFO "get_pin_count:%d\n", get_pin_count);
+	if (get_pin_count < 0) {
+		get_pin_count = 0;
+		return 0;
+	}
+
+	result = asoc_mfp_unlock(MOD_ID_ETHERNET, MFP_OPT_CAN_SLEEP);
+	return result;
+}
+#endif
+
+static void mac_init(ec_priv_t *ecp)
+{
+	volatile ethregs_t *hw_regs = ecp->hwrp;
+
+//	printk(KERN_INFO "%s %d\n",__FUNCTION__,__LINE__);
+	/* hardware soft reset, and set bus mode */
+	hw_regs->er_busmode |= EC_BMODE_SWR;
+	do {
+		udelay(10);
+	} while (hw_regs->er_busmode & EC_BMODE_SWR);
+
+	/* select clk input from external phy */
+
+//	printk(KERN_INFO "before MAC_CTRL: 0x%x\n", (unsigned)getl(MAC_CTRL));
+	putl(getl(MAC_CTRL) &(~(0x1<<1)), MAC_CTRL);			//no need to inverter ref clk
+//	printk(KERN_INFO "after MAC_CTRL: 0x%x\n", (unsigned)getl(MAC_CTRL));
+
+	hw_regs->er_miism &= 0x0;
+	hw_regs->er_miism |= 0xcc000000;
+	//putl(getl(MAC_CSR10) | 0x40000000, MAC_CSR10);
+//	printk(KERN_INFO "MAC_CSR10: 0x%x\n", (unsigned)getl(MAC_CSR10));
+//    printk(KERN_INFO "------------MAC_CSR10:0x%x\n", (unsigned)hw_regs->er_miism);
+
+
+//	printk(KERN_INFO "----------CMU_DEVCLKEN1:0x%x\n", act_readl(CMU_DEVCLKEN1));
+//	printk(KERN_INFO "----------CMU_DEVRST1:0x%x\n", act_readl(CMU_DEVRST1));
+	
+	/* for gl5202 fpga test, PBL = 16, 5203 default 16 */
+	//hw_regs->er_busmode |= 0x1000;
+
+	/* physical address */
+	hw_regs->er_txbdbase = ecp->tx_bd_paddr;
+	hw_regs->er_rxbdbase = ecp->rx_bd_paddr;
+//	printk(KERN_INFO "csr4-txbdbase:0x%x\n", (unsigned)hw_regs->er_txbdbase);
+//	printk(KERN_INFO "csr3-rxbdbase:0x%x\n", (unsigned)hw_regs->er_rxbdbase);
+
+	/* set flow control mode, force transmitor pause about 100ms */
+/*
+	hw_regs->er_cachethr = EC_CACHETHR_CPTL(0x0) | EC_CACHETHR_CRTL(0x0) | EC_CACHETHR_PQT(0x4FFF);
+//	hw_regs->er_fifothr = EC_FIFOTHR_FPTL(0x40) | EC_FIFOTHR_FRTL(0x10);
+	hw_regs->er_fifothr = EC_FIFOTHR_FPTL(0x150) | EC_FIFOTHR_FRTL(0x84);
+*/
+	hw_regs->er_cachethr = EC_CACHETHR_CPTL(0x0) | EC_CACHETHR_CRTL(0x0) | EC_CACHETHR_PQT(0x4FFF);
+	hw_regs->er_fifothr = EC_FIFOTHR_FPTL(0x40) | EC_FIFOTHR_FRTL(0x10);//hw_regs->er_fifothr = EC_FIFOTHR_FPTL(0x150) | EC_FIFOTHR_FRTL(0x84);
+	hw_regs->er_flowctrl = EC_FLOWCTRL_ENALL;
+
+	hw_regs->er_opmode |= EC_OPMODE_FD;
+	hw_regs->er_opmode |= EC_OPMODE_SPEED(0); //100M
+//	hw_regs->er_opmode |= EC_OPMODE_SF;  /* start transmit ONLY after whole packet get in tfifo */
+
+    //hw_regs->er_busmode |= EC_BMODE_TAP(0x1);
+    //hw_regs->er_busmode |= EC_BMODE_BAR;
+//    printk(KERN_INFO "hw_regs->er_busmode:0x%x\n", (unsigned)hw_regs->er_busmode);
+
+	/* default support PR, here clear it
+	 * XXX: due to MAC constraint, after write a reg, can't read it immediately
+	 * (write of regs has tow beats delay).
+	 */
+	hw_regs->er_opmode &= ~EC_OPMODE_PR;
+//	printk(KERN_INFO "hw_regs->er_opmode:0x%x\n", (unsigned)hw_regs->er_opmode);
+
+	
+	//interrupt mitigation control register 
+	hw_regs->er_imctrl = 0x004e0000; //NRP =7,RT =1,CS=0
+
+#if defined(ETHENRET_MAC_LOOP_BACK) || defined(ETHENRET_PHY_LOOP_BACK)
+	hw_regs->er_opmode |= EC_OPMODE_RA;
+#endif
+
+#ifdef ETHENRET_MAC_LOOP_BACK
+	/* mac internal loopback */
+	hw_regs->er_opmode |= EC_OPMODE_LP;
+	printk(KERN_INFO "MAC operation mode: 0x%x\n", (unsigned)hw_regs->er_opmode);
+#endif
+	//hw_regs->er_ienable = EC_IEN_ALL;   //all interrupt enable
+}
+
+static int _init_hardware(ec_priv_t *ecp,int clk_reset,int phy_reset)
+{
+	ethernet_clock_enable(clk_reset);
+
+	/* ATC2605 ONLY support output 50MHz RMII_REF_CLK to MAC, so phy hw init first */
+	if (ecp->phy_ops->phy_hw_init)
+		ecp->phy_ops->phy_hw_init(ecp);
+//	printk(KERN_INFO "%s %d\n",__FUNCTION__,__LINE__);
+	mac_init(ecp);
+	print_mac_register(ecp);
+
+if(phy_reset){
+	if (gpio_is_valid(ecp->phy_power_gpio.gpio)) { 
+		gpio_direction_output(ecp->phy_power_gpio.gpio,  !ecp->phy_power_gpio.active);
+	}	
+	if (gpio_is_valid(ecp->phy_reset_gpio.gpio)){	        
+		gpio_direction_output(ecp->phy_reset_gpio.gpio,   ecp->phy_reset_gpio.active);		
+	}
+	mdelay(10);
+	if (gpio_is_valid(ecp->phy_reset_gpio.gpio)){	        
+		gpio_direction_output(ecp->phy_reset_gpio.gpio,   !ecp->phy_reset_gpio.active);		
+	}	
+}
+	/**********TEST FOR TAIWAN START******/
+	#if 0
+	putl(getl(GPIO_AOUTEN) | (0x1 << 22), GPIO_AOUTEN);
+    printk(KERN_INFO "%s %d gpioen:0x%x\n",__FUNCTION__,__LINE__,getl(GPIO_COUTEN));
+	putl(getl(GPIO_ADAT) & (0x0 << 22), GPIO_ADAT);
+	printk(KERN_INFO "%s %d gpio:0x%x\n",__FUNCTION__,__LINE__,getl(GPIO_CDAT));
+    mdelay(150);
+	putl(getl(GPIO_AOUTEN) & (0x0 << 22), GPIO_AOUTEN);
+	#endif//0
+	 /**********TEST FOR TAIWAN end******/
+	set_mac_addr(ecp);
+//	INFO_BLUE("mac address: ");
+//	print_mac_address(ecp->mac_addr);
+
+if(phy_reset){
+	if (ecp->phy_ops->phy_init(ecp)) {
+		printk("error : initialize PHY fail\n");
+	}
+	printk(KERN_INFO "%s %d\n",__FUNCTION__,__LINE__);
+	print_phy_register(ecp);
+}		
+	/*enable RMII_REF_CLK and EXTIRQ pad and disable the other 6 RMII pad, gl5302 bug amend*/
+	/*enable the other 6 RMII pad, gl5302 bug amend*/
+    #if 0	
+      if (ecp->phy_model == ETH_PHY_MODEL_ATC2605) {
+		atc260x_reg_setbits(ecp->atc260x, atc2603_PAD_EN, 0x7e, 0x7e);
+		udelay(100);
+	}
+      #endif //0
+	return 0;
+}
+
+static int _deinit_hardware(ec_priv_t *ecp){
+	if (gpio_is_valid(ecp->phy_power_gpio.gpio)) { 
+		gpio_direction_output(ecp->phy_power_gpio.gpio,  ecp->phy_power_gpio.active);
+	}
+}
+
+#ifdef DETECT_POWER_SAVE
+static void detect_power_save_timer_func(unsigned long data);
+
+static void init_power_save_timer(ec_priv_t *ecp)
+{
+    printk(KERN_INFO "\n");
+    init_timer(&ecp->detect_timer);
+    ecp->detect_timer.data = (unsigned long)ecp;
+    ecp->detect_timer.function = detect_power_save_timer_func;
+}
+
+static void start_power_save_timer(ec_priv_t *ecp, const unsigned ms)
+{
+    printk(KERN_INFO "\n");
+    mod_timer(&ecp->detect_timer, jiffies + msecs_to_jiffies(ms));
+}
+
+static void stop_power_save_timer(ec_priv_t *ecp)
+{
+    printk(KERN_INFO "\n");
+    if (timer_pending(&ecp->detect_timer))
+        del_timer_sync(&ecp->detect_timer);
+
+    cancel_work_sync(&ecp->power_save_work);
+    flush_workqueue(power_save_queue);
+}
+
+static void enable_hardware(ec_priv_t *ecp)
+{
+    unsigned long flags = 0;
+    int temp;
+
+    temp = read_phy_reg(ecp, MII_BMCR);
+    printk(KERN_INFO "MII_BMCR: 0x%x\n", (u32)temp);
+    write_phy_reg(ecp, MII_BMCR, temp & ~BMCR_PDOWN);
+    printk(KERN_INFO "exit POWER DOWN, MII_BMCR: 0x%x\n", (u32)read_phy_reg(ecp, MII_BMCR));
+
+    spin_lock_irqsave(&ecp->lock, flags);
+    ecp->enable = true;
+    spin_unlock_irqrestore(&ecp->lock, flags);
+}
+
+static void disable_hardware(ec_priv_t *ecp)
+{
+    unsigned long flags = 0;
+    unsigned short phy_int_status;
+    int temp;
+
+    phy_int_status = atc260x_reg_read(ecp->atc260x, atc2603_PHY_INT_STAT);
+    if (phy_int_status & 0x1) {
+        printk(KERN_INFO "already linked, not to power down\n");
+        return;
+    }
+
+    spin_lock_irqsave(&ecp->lock, flags);
+    if (ecp->linked) {
+        spin_unlock_irqrestore(&ecp->lock, flags);
+        printk(KERN_INFO "already linked, not to power down\n");
+        return;
+    }
+    ecp->enable = false;
+    spin_unlock_irqrestore(&ecp->lock, flags);
+
+    temp = read_phy_reg(ecp, MII_BMCR);
+    printk(KERN_INFO "MII_BMCR: 0x%x\n", (u32)temp);
+    write_phy_reg(ecp, MII_BMCR, temp | BMCR_PDOWN);
+    printk(KERN_INFO "enter POWER DOWN, MII_BMCR: 0x%x\n", (u32)read_phy_reg(ecp, MII_BMCR));
+}
+
+
+static void ethernet_power_save(struct work_struct *work)
+{
+    ec_priv_t *ecp = (ec_priv_t *)container_of(work, ec_priv_t, power_save_work);
+    printk(KERN_INFO "ecp->enable: %u\n", ecp->enable);
+
+    if (ecp->enable) {
+        disable_hardware(ecp);
+    } else {
+        enable_hardware(ecp);
+    }
+}
+
+static void detect_power_save_timer_func(unsigned long data)
+{
+    ec_priv_t *ecp = (ec_priv_t *)data;
+    unsigned long flags;
+
+    printk(KERN_INFO "ecp->enable: %u\n", ecp->enable);
+    if (!ecp->opened) {
+        printk(KERN_INFO "not opened yet\n");
+        return;
+    }
+
+    spin_lock_irqsave(&ecp->lock, flags);
+    if (ecp->linked) {
+        spin_unlock_irqrestore(&ecp->lock, flags);
+        printk(KERN_INFO "not linked yet\n");
+        return;
+    }
+    spin_unlock_irqrestore(&ecp->lock, flags);
+
+    if (ecp->enable) {
+        mod_timer(&ecp->detect_timer, jiffies + msecs_to_jiffies(4000));
+    } else {
+        mod_timer(&ecp->detect_timer, jiffies + msecs_to_jiffies(4000));
+    }
+
+    queue_work(power_save_queue, &ecp->power_save_work);
+}
+#endif /* DETECT_POWER_SAVE */
+
+static void set_phy_according_aneg(ec_priv_t *ecp)
+{
+	unsigned short old_bmcr;
+	unsigned long phy_ctrl_status;
+
+	old_bmcr = read_phy_reg(ecp, MII_BMCR);
+//	printk(KERN_INFO "old MII_BMCR: 0x%04x\n", (unsigned)old_bmcr);
+   #if 0
+	if (ecp->phy_model == ETH_PHY_MODEL_ATC2605) {
+		phy_ctrl_status = atc260x_reg_read(ecp->atc260x, atc2603_PHY_CTRL);
+		if (ETH_SPEED_10M == ecp->speed)
+			atc260x_reg_write(ecp->atc260x, atc2603_PHY_CTRL, phy_ctrl_status & 0x1e);
+		else
+			atc260x_reg_write(ecp->atc260x, atc2603_PHY_CTRL, phy_ctrl_status | 0x1);
+
+		printk(KERN_INFO "atc2603_PHY_CTRL: 0x%04x\n", (unsigned)atc260x_reg_read(ecp->atc260x, atc2603_PHY_CTRL));
+	}
+ 	#endif
+	if (ETH_SPEED_10M == ecp->speed)
+		old_bmcr &= ~BMCR_SPEED100;
+	else
+		old_bmcr |= BMCR_SPEED100;
+
+	if (ETH_DUP_FULL == ecp->duplex)
+		old_bmcr |= BMCR_FULLDPLX;
+	else
+		old_bmcr &= ~BMCR_FULLDPLX;
+
+	write_phy_reg(ecp, MII_BMCR, old_bmcr);
+//	printk(KERN_INFO "new MII_BMCR: 0x%04x\n", (unsigned)read_phy_reg(ecp, MII_BMCR));
+}
+
+
+
+
+static void set_mac_according_aneg(ec_priv_t *ecp)
+{
+	volatile ethregs_t *hw_regs = ecp->hwrp;
+	unsigned long old_mode;
+
+//	 printk(KERN_INFO "%s\n",__func__);
+	old_mode = hw_regs->er_opmode;
+//	printk(KERN_INFO "opmode regs old value - 0x%x\n", (int)old_mode);
+
+	hw_regs->er_opmode &= ~(EC_OPMODE_ST | EC_OPMODE_SR);
+
+	if (ETH_SPEED_10M == ecp->speed)
+		old_mode |= EC_OPMODE_10M;
+	else
+		old_mode &= ~EC_OPMODE_10M;
+
+	if (ETH_DUP_FULL == ecp->duplex)
+		old_mode |= EC_OPMODE_FD;
+	else
+		//old_mode &= ~EC_OPMODE_FD;
+		/* always set full duplex to work around for both half/full mode!*/
+		old_mode |= EC_OPMODE_FD;  /* mac bug! */
+
+	/*set phy during mac stopped */
+	set_phy_according_aneg(ecp);
+
+	hw_regs->er_opmode = old_mode;
+//	printk(KERN_INFO "hw_regs->er_opmode:0x%lx\n", hw_regs->er_opmode);
+}
+
+
+/**
+ * ec_enet_tx -- sub-isr for tx interrupt
+ */
+static void subisr_enet_tx(ec_priv_t *ecp)
+{
+    struct net_device *dev = ecp->netdev;
+    volatile ec_bd_t *bdp;
+    struct sk_buff *skb;
+    unsigned long status;
+
+    spin_lock(&ecp->lock);
+    bdp = ecp->dirty_tx;
+
+    if (0 == ((status = bdp->status) & TXBD_STAT_OWN)) { /* don't enable CSR11 interrupt mitigation */
+#if 0
+	while (0 == ((status = bdp->status) & TXBD_STAT_OWN)) {
+        if (bdp == ecp->cur_tx && !ecp->tx_full) 
+            break;    /* tx queue is empty */
+#endif
+
+        skb = ecp->tx_skb[ecp->skb_dirty];
+        dma_unmap_single(&ecp->netdev->dev, bdp->buf_addr, skb->len, DMA_TO_DEVICE);
+
+        /* check for errors */
+        if (status & TXBD_STAT_ES) {
+            printk(KERN_INFO "tx error status : 0x%x\n", (unsigned int)status);
+            if (netif_msg_tx_err(ecp)) {
+                printk(KERN_INFO "position: %d\n", ecp->dirty_tx - ecp->tx_bd_base);
+                print_tx_bds(ecp);
+            }
+            dev->stats.tx_errors++;
+            if (status & TXBD_STAT_UF) 
+			{
+                dev->stats.tx_fifo_errors++;
+				printk(KERN_INFO "tx error status : 0x%x\n", (unsigned int)status);
+            }
+            if (status & TXBD_STAT_EC) 
+			{
+                dev->stats.tx_aborted_errors++;
+				printk(KERN_INFO "tx error status : 0x%x\n", (unsigned int)status);
+            }
+            if (status & TXBD_STAT_LC) 
+			{
+                dev->stats.tx_window_errors++;
+				printk(KERN_INFO "tx error status : 0x%x\n", (unsigned int)status);
+            }
+            if (status & TXBD_STAT_NC) 
+			{
+                dev->stats.tx_heartbeat_errors++;
+				//the mac ip has such a bug(misinformation)
+				//printk(KERN_INFO "tx error status : 0x%x\n", (unsigned int)status);
+            }
+            if (status & TXBD_STAT_LO) 
+			{
+                dev->stats.tx_carrier_errors++;
+				printk(KERN_INFO "tx error status : 0x%x\n", (unsigned int)status);
+            }
+        } 
+		else 
+		{
+            dev->stats.tx_packets++;
+        }
+
+        /* some collions occurred, but sent packet ok eventually */
+        if (status & TXBD_STAT_DE) 
+		{
+            dev->stats.collisions++;
+        }
+
+        if (netif_msg_tx_err(ecp)) {
+            check_icmp_sequence(skb->data, __func__);
+            printk(KERN_INFO "bdp->buf_addr:0x%lx\n", bdp->buf_addr);
+            printk(KERN_INFO "tx frame:\n");
+            print_frame_data(skb->data, skb->len);
+        }
+
+        dev_kfree_skb_any(skb);
+
+        ecp->tx_skb[ecp->skb_dirty] = NULL;
+        ecp->skb_dirty = (ecp->skb_dirty + 1) & TX_RING_MOD_MASK;
+
+        if (bdp->control & TXBD_CTRL_TER)
+            bdp = ecp->tx_bd_base;
+        else
+            bdp++;
+
+        if (ecp->tx_full) {
+            printk(KERN_INFO "tx bds available, skb_dirty:%d\n", ecp->skb_dirty);
+            ecp->tx_full = false;
+            if (netif_queue_stopped(dev))
+                netif_wake_queue(dev);
+        }
+        if (netif_queue_stopped(dev))
+	    netif_wake_queue(dev);
+    }
+//	else
+//		printk(KERN_INFO "tx bds status:0x%x\n", (unsigned int)status);
+#if 1
+    else if (ecp->tx_full) {
+        volatile ec_bd_t *bdp_next;
+
+        /* handle the case that bdp->status own bit not cleared by hw but the interrupt still comes */
+        if (bdp->control & TXBD_CTRL_TER)
+            bdp_next = ecp->tx_bd_base;
+        else
+            bdp_next = bdp + 1;
+
+        while (bdp_next != bdp) {
+            /* when tx full, if we find that some bd(s) has own bit is 0, which
+             * indicates that mac hw has transmitted it but the own bit left not cleared. */
+            if (!(bdp_next->status & TXBD_STAT_OWN)) {
+             printk(KERN_INFO "tx bd own bit not cleared!!!\n");
+
+#ifdef TX_DEBUG
+                print_mac_register(ecp);
+                print_tx_bds(ecp);
+#endif
+                bdp->status &= ~TXBD_STAT_OWN; /* clear own bit */
+                skb = ecp->tx_skb[ecp->skb_dirty];
+                dma_unmap_single(&ecp->netdev->dev, bdp->buf_addr, skb->len, DMA_TO_DEVICE);
+                dev_kfree_skb_any(skb);
+
+                ecp->tx_skb[ecp->skb_dirty] = NULL;
+                ecp->skb_dirty = (ecp->skb_dirty + 1) & TX_RING_MOD_MASK;
+
+                if (bdp->control & TXBD_CTRL_TER)
+                    bdp = ecp->tx_bd_base;
+                else
+                    bdp++;
+
+                ecp->tx_full = false;
+                if (netif_queue_stopped(dev))
+                    netif_wake_queue(dev);
+                break;
+            }
+            if (bdp_next->control & TXBD_CTRL_TER)
+                bdp_next = ecp->tx_bd_base;
+            else
+                bdp_next++;
+        }
+    }
+#endif
+    ecp->dirty_tx = (ec_bd_t *) bdp;
+
+    spin_unlock(&ecp->lock);
+    return;
+}
+
+
+/**
+ * ec_enet_rx -- sub-isr for rx interrupt
+ */
+static void subisr_enet_rx(ec_priv_t *ecp)
+{
+	struct net_device *dev = ecp->netdev;
+	volatile ethregs_t *hw_regs = ecp->hwrp;
+	volatile ec_bd_t *bdp;
+	struct sk_buff *new_skb;
+	struct sk_buff *skb_to_upper;
+	unsigned long status;
+	unsigned int  pkt_len;
+	int	index;
+//printk(KERN_INFO "%s %d\n",__FUNCTION__,__LINE__);
+#define RX_ERROR_CARED \
+	(RXBD_STAT_DE | RXBD_STAT_RF | RXBD_STAT_TL | RXBD_STAT_CS \
+	| RXBD_STAT_DB | RXBD_STAT_CE | RXBD_STAT_ZERO)
+
+	spin_lock(&ecp->lock);
+	BUG_ON(!ecp->opened);
+	bdp = ecp->cur_rx;
+#ifdef RX_DEBUG
+	if (unlikely(netif_msg_rx_err(ecp)))
+		printk(KERN_INFO "bdp: 0x%p\n", bdp);
+#endif
+
+	while (0 == ((status = bdp->status) & RXBD_STAT_OWN)) {
+		//printk(KERN_INFO "bdp->status:0x%08lx\n", bdp->status);
+		if (!(status & RXBD_STAT_LS))
+			printk(KERN_INFO "not last descriptor of a frame - status: 0x%08x.\n",
+				(unsigned int)status);
+#ifdef RX_DEBUG
+		if (unlikely(netif_msg_rx_err(ecp))) {
+			printk(KERN_INFO "bdp: 0x%p, bdp->status: 0x%08x\n", bdp, (u32)bdp->status);
+			printk(KERN_INFO "status: 0x%08x\n", (u32)status);
+		}
+#endif
+
+		/* check for rx errors. RXBD_STAT_ES includes RXBD_STAT_RE, and
+		* RXBD_STAT_RE always set, coz RE pin of 5201 ether mac is NC to
+		* 5302 ether phy. Don't care it now, it'll be fixed in 5203. */
+		//if (status & (RXBD_STAT_ES | RXBD_STAT_DB))
+		if (status & RX_ERROR_CARED) {
+			printk("%d: RX_ERROR status:0x%08lx\n", __LINE__, status);
+			dev->stats.rx_errors++;
+			if (status & RXBD_STAT_TL)
+				dev->stats.rx_length_errors++;
+			if (status & RXBD_STAT_CE)
+				dev->stats.rx_crc_errors++;
+			if (status & (RXBD_STAT_RF | RXBD_STAT_DB))
+				dev->stats.rx_frame_errors++;
+			if (status & RXBD_STAT_ZERO)
+				dev->stats.rx_fifo_errors++;
+			if (status & RXBD_STAT_DE)
+				dev->stats.rx_over_errors++;
+			if (status & RXBD_STAT_CS)
+				dev->stats.collisions++;
+			goto rx_done;
+		}
+
+		pkt_len = RXBD_STAT_FL(status);
+		if (pkt_len > ETH_PKG_MAX) { /* assure skb_put() not panic */
+			printk(KERN_INFO "pkt_len = %u\n", pkt_len);
+			dev->stats.rx_length_errors++;
+			goto rx_done;
+		}
+
+		if (NULL == (new_skb = get_skb_aligned(PKG_MAX_LEN))) {
+			dev->stats.rx_dropped++;
+			printk(KERN_INFO "no memory, just drop it.\n"); // no release version ??
+			goto rx_done;
+		}
+
+		dma_unmap_single(&ecp->netdev->dev, bdp->buf_addr, PKG_MAX_LEN, DMA_FROM_DEVICE);
+
+		dev->stats.rx_packets++;
+		dev->stats.rx_bytes += pkt_len;
+
+		index = bdp - ecp->rx_bd_base;
+		skb_to_upper = ecp->rx_skb[index];
+		ecp->rx_skb[index] = new_skb;
+
+		skb_put(skb_to_upper, pkt_len - ETH_CRC_LEN); /* modify its data length, remove CRC */
+//#define RX_DEBUG
+#ifdef RX_DEBUG
+		if (unlikely(netif_msg_rx_err(ecp))) {
+			check_icmp_sequence(skb_to_upper->data, __func__);
+			printk(KERN_INFO "receive %u bytes\n", pkt_len);
+			printk(KERN_INFO "source mac - ");
+			print_mac_address(skb_to_upper->data + ETH_MAC_LEN);
+			printk(KERN_INFO "dest mac - ");
+			print_mac_address(skb_to_upper->data);
+			printk(KERN_INFO "receive data:\n");
+			print_frame_data(skb_to_upper->data, skb_to_upper->len);
+		}
+#endif
+		skb_to_upper->protocol = eth_type_trans(skb_to_upper, dev);
+		netif_rx(skb_to_upper);
+
+		bdp->buf_addr = dma_map_single(&ecp->netdev->dev, new_skb->data, PKG_MAX_LEN, DMA_FROM_DEVICE);
+		if (!bdp->buf_addr)
+			printk(KERN_INFO "dma map new_skb->data:%p failed\n", new_skb->data);
+
+rx_done:
+		/* mark MAC AHB owns the buffer, and clear other status */
+		bdp->status = RXBD_STAT_OWN;
+#ifdef RX_DEBUG
+		if (unlikely(netif_msg_rx_err(ecp)))
+			printk(KERN_INFO "bdp->status: 0x%08x\n", (u32)bdp->status);
+#endif
+		if (bdp->control & RXBD_CTRL_RER)
+			bdp = ecp->rx_bd_base;
+		else
+			bdp++;
+#ifdef RX_DEBUG
+		if (unlikely(netif_msg_rx_err(ecp)))
+			printk(KERN_INFO "bdp: 0x%p\n", bdp);
+#endif
+		/* start to receive packets, may be good in heavily loaded net */
+//		hw_regs->er_opmode |= EC_OPMODE_SR;  // maybe not need it here
+	} /* while */
+	
+	ecp->cur_rx = (ec_bd_t *) bdp;
+	spin_unlock(&ecp->lock);
+	return;
+}
+
+
+static void phy_detect_func(struct work_struct *work)
+{
+    #define MII_TIME_OUT 50
+	
+    ec_priv_t *ecp = (ec_priv_t *)container_of(work, ec_priv_t, phy_detect_work);
+    unsigned short phy_int_status = 0;
+    unsigned short bmode = 0;
+    unsigned long flags;
+
+   /**for rtl8201***********/
+   if (ecp->phy_model==ETH_PHY_MODEL_RTL8201)
+   {
+		phy_int_status = read_phy_reg(ecp, 0x1e);
+		printk(KERN_INFO "phy_int_status: 0x%x\n", (unsigned)phy_int_status);
+		bmode =read_phy_reg(ecp, 0x1);
+		printk(KERN_INFO "bmode_status: 0x%x\n", (unsigned)bmode);
+	}
+	   if (ecp->phy_model==ETH_PHY_MODEL_SR8201G)
+   {
+		phy_int_status = read_phy_reg(ecp, 0x18);
+//		printk(KERN_INFO "phy_int_status: 0x%x\n", (unsigned)phy_int_status);
+//		printk(KERN_INFO "intterupt linkstatus chg : 0x%x\n", read_phy_reg(ecp, 14));
+		bmode =read_phy_reg(ecp, 0x1);
+//		printk(KERN_INFO "bmode_status: 0x%x\n", (unsigned)bmode);
+	}
+
+#if 1
+	/* FIXME!used by KSZ8041, other phy may not need this */
+	if (ecp->phy_model != ETH_PHY_MODEL_ATC2605)
+		/* if SIRQ edge-triggered, pending bit must be cleared */
+		putl(getl(INTC_EXTCTL) | (0x1 << 16), INTC_EXTCTL);
+#endif
+ 
+
+	   /**for rtl8201***********/
+   if (ecp->phy_model==ETH_PHY_MODEL_RTL8201)
+   {
+		if((phy_int_status & (0x1<<11)) == 0)
+		return IRQ_HANDLED;
+
+	ecp->linked = (bmode & 0x1<<2) ? true : false;
+
+    }
+    if (ecp->phy_model==ETH_PHY_MODEL_SR8201G)
+   {
+	ecp->linked = (bmode & (0x1<<2)) ? true : false;
+    }
+    if(ecp->last_link_status!=ecp->linked){ 
+	if (ecp->linked) {
+		int i;
+#ifdef DETECT_POWER_SAVE
+		bool enable;
+
+		stop_power_save_timer(ecp);
+		spin_lock_irqsave(&ecp->lock, flags);
+		enable = ecp->enable;
+		spin_unlock_irqrestore(&ecp->lock, flags);
+		if (!enable) {
+			/* rarely occur, work ethernet_power_save() disabled phy! */
+			ecp->linked = false;
+			printk(KERN_INFO "ecp->enable is false!\n");
+			goto out;
+		}
+#endif
+//		printk(KERN_INFO "old_duplex = 0x%x\n", ecp->duplex);
+//		printk(KERN_INFO "old_speed = 0x%x\n", ecp->speed);
+
+		ecp->phy_ops->phy_read_status(ecp);
+		set_mac_according_aneg(ecp);
+
+//		printk(KERN_INFO "new_duplex = 0x%x\n", ecp->duplex);
+//		printk(KERN_INFO "new_speed = 0x%x\n", ecp->speed);
+
+		for (i = 0; i < MII_TIME_OUT; i++) {
+			if (read_phy_reg(ecp, MII_BMSR) & BMSR_LSTATUS) {
+				ecp->linked = true;
+//				printk(KERN_INFO "link established.\n");
+				break;
+			}
+		}
+		if (MII_TIME_OUT == i) {
+			ecp->linked = false;
+//			printk(KERN_INFO "link fail.\n");
+			goto out;
+		}
+	} else {
+		ecp->linked = false;
+	}
+   } 
+out:
+   if(ecp->last_link_status!=ecp->linked){	
+	if (ecp->linked) {
+		netif_carrier_on(ecp->netdev);
+		if (netif_queue_stopped(ecp->netdev))
+			netif_wake_queue(ecp->netdev);
+	} else {
+#ifdef DETECT_POWER_SAVE
+		start_power_save_timer(ecp, 1000);
+#endif
+		netif_carrier_off(ecp->netdev);
+	}
+	}
+	//INFO_GREEN("link:%s\n", ecp->linked ? "linked" : "disconnected");	
+	ecp->last_link_status=ecp->linked;	
+      queue_delayed_work(phy_detect_queue, &ecp->phy_detect_work,msecs_to_jiffies(PHY_DETECT_DUTY));
+}
+/**
+ * ec_netdev_isr -- interrupt service routine for ethernet controller
+ */
+static irqreturn_t ec_netphy_isr(int irq, void *cookie)
+{
+#define MII_TIME_OUT 100
+
+	ec_priv_t *ecp = netdev_priv((struct net_device *) cookie);
+	unsigned short phy_int_status = 0;
+	unsigned short bmode = 0;
+	unsigned long flags;
+
+  #if 0
+	if (ecp->phy_model == ETH_PHY_MODEL_ATC2605) {
+		phy_int_status = atc260x_reg_read(ecp->atc260x, atc2603_PHY_INT_STAT);
+		/* clear phy int pending */
+		atc260x_reg_write(ecp->atc260x, atc2603_PHY_INT_STAT, phy_int_status);
+		printk(KERN_INFO "phy_int_status: 0x%04x\n", (unsigned)phy_int_status);
+	} else {
+   #endif //0
+   /**for rtl8201***********/
+   if (ecp->phy_model==ETH_PHY_MODEL_RTL8201)
+   {
+		phy_int_status = read_phy_reg(ecp, 0x1e);
+		printk(KERN_INFO "phy_int_status: 0x%x\n", (unsigned)phy_int_status);
+		bmode =read_phy_reg(ecp, 0x1);
+		printk(KERN_INFO "bmode_status: 0x%x\n", (unsigned)bmode);
+	}
+	   if (ecp->phy_model==ETH_PHY_MODEL_SR8201G)
+   {
+		phy_int_status = read_phy_reg(ecp, 0x18);
+//		printk(KERN_INFO "phy_int_status: 0x%x\n", (unsigned)phy_int_status);
+//		printk(KERN_INFO "intterupt linkstatus chg : 0x%x\n", read_phy_reg(ecp, 14));
+		bmode =read_phy_reg(ecp, 0x1);
+//		printk(KERN_INFO "bmode_status: 0x%x\n", (unsigned)bmode);
+	}
+	 /************************/
+#ifdef ETH_TEST_MODE
+	if (ecp->test_mode) {
+		printk(KERN_INFO "test mode: %u\n", ecp->test_mode);
+		return IRQ_HANDLED;
+	}
+#endif
+
+#if 1
+	/* FIXME!used by KSZ8041, other phy may not need this */
+	if (ecp->phy_model != ETH_PHY_MODEL_ATC2605)
+		/* if SIRQ edge-triggered, pending bit must be cleared */
+		putl(getl(INTC_EXTCTL) | (0x1 << 16), INTC_EXTCTL);
+#endif
+ 
+
+	   /**for rtl8201***********/
+   if (ecp->phy_model==ETH_PHY_MODEL_RTL8201)
+   {
+		if((phy_int_status & (0x1<<11)) == 0)
+		return IRQ_HANDLED;
+
+	spin_lock_irqsave(&ecp->lock, flags);
+	ecp->linked = (bmode & 0x1<<2) ? true : false;
+	spin_unlock_irqrestore(&ecp->lock, flags);
+
+	}
+	   if (ecp->phy_model==ETH_PHY_MODEL_SR8201G)
+   {
+/*
+		if((phy_int_status & (0x1<<0)) == 1)
+		return IRQ_HANDLED;
+*/
+	spin_lock_irqsave(&ecp->lock, flags);
+	ecp->linked = (bmode & 0x1<<2) ? true : false;
+	spin_unlock_irqrestore(&ecp->lock, flags);
+
+	}
+	
+	if (ecp->linked) {
+		int i;
+#ifdef DETECT_POWER_SAVE
+		bool enable;
+
+		stop_power_save_timer(ecp);
+		spin_lock_irqsave(&ecp->lock, flags);
+		enable = ecp->enable;
+		spin_unlock_irqrestore(&ecp->lock, flags);
+		if (!enable) {
+			/* rarely occur, work ethernet_power_save() disabled phy! */
+			ecp->linked = false;
+			printk(KERN_INFO "ecp->enable is false!\n");
+			goto out;
+		}
+#endif
+//		printk(KERN_INFO "old_duplex = 0x%x\n", ecp->duplex);
+//		printk(KERN_INFO "old_speed = 0x%x\n", ecp->speed);
+
+		ecp->phy_ops->phy_read_status(ecp);
+		set_mac_according_aneg(ecp);
+
+//		printk(KERN_INFO "new_duplex = 0x%x\n", ecp->duplex);
+//		printk(KERN_INFO "new_speed = 0x%x\n", ecp->speed);
+
+		for (i = 0; i < MII_TIME_OUT; i++) {
+			if (read_phy_reg(ecp, MII_BMSR) & BMSR_LSTATUS) {
+				ecp->linked = true;
+//				printk(KERN_INFO "link established.\n");
+				break;
+			}
+			//udelay(1);
+		}
+		if (MII_TIME_OUT == i) {
+			ecp->linked = false;
+//			printk(KERN_INFO "link fail.\n");
+			goto out;
+		}
+	} else {
+		ecp->linked = false;
+	}
+
+out:
+	if (ecp->linked) {
+		netif_carrier_on(ecp->netdev);
+		if (netif_queue_stopped(ecp->netdev))
+			netif_wake_queue(ecp->netdev);
+	} else {
+#ifdef DETECT_POWER_SAVE
+		start_power_save_timer(ecp, 1000);
+#endif
+		netif_carrier_off(ecp->netdev);
+	}
+
+	INFO_GREEN("link:%s\n", ecp->linked ? "linked" : "disconnected");
+	//print_phy_register(ecp);
+	//print_mac_register(ecp);
+
+	return IRQ_HANDLED;
+}
+
+/**
+ * ec_netdev_isr -- interrupt service routine for ethernet controller
+ */
+static irqreturn_t ec_netmac_isr(int irq, void *cookie)
+{
+    ec_priv_t *ecp = netdev_priv((struct net_device *) cookie);
+    volatile ethregs_t *hw_regs = ecp->hwrp;
+    unsigned long status = 0;
+    unsigned long intr_bits = 0;
+    unsigned long flags = 0;    
+	struct net_device *dev = ecp->netdev;
+    static unsigned long tx_cnt,rx_cnt;
+	unsigned long mac_status;
+    int ru_cnt = 0;
+     int i = 0;
+    intr_bits = EC_STATUS_NIS | EC_STATUS_AIS;
+//   	spin_lock(&ecp->lock);    
+    disable_irq_nosync(ecp->mac_irq);
+    /* xmit setup frame raise ETI, but not TI, this is only reason to pay attention to it */
+//    interested = EC_STATUS_TI | EC_STATUS_RI | EC_STATUS_ETI | EC_STATUS_RU;
+//	 printk(KERN_INFO "%s %d hw_regs->er_status=0x%x\n",__FUNCTION__,__LINE__,hw_regs->er_status);
+    while ((status = hw_regs->er_status) & intr_bits) {
+        hw_regs->er_status = status;    /* clear status */
+        if (netif_msg_intr(ecp)) {
+//            printk(KERN_INFO "interrupt status: 0x%8x\n", (int)status);
+//            printk(KERN_INFO "status after clear: 0x%x\n", (int)hw_regs->er_status);
+        }
+
+        //if (status & EC_STATUS_TU)
+        //    printk(KERN_INFO "---TU interrupt---\n");
+
+        /* when set CSR0.TAP will induce endless loopback, get rid of uninteresting ones */
+//        if (!(status & interested)) {
+//            printk(KERN_INFO "NOT interested status: 0x%08x\n", (u32)status);
+//            break;
+//        }
+
+        if (status & (EC_STATUS_TI | EC_STATUS_ETI)) {
+            subisr_enet_tx(ecp);
+			tx_cnt = 0;
+			mac_status = status & EC_STATUS_RSM;
+			if((mac_status == EC_RX_fetch_dsp)||(mac_status ==EC_RX_run_dsp)||(mac_status ==EC_RX_close_dsp) )
+				rx_cnt++;
+        }
+
+        /* RI & RU may come at same time, if RI handled, then RU needn't handle.
+         * If RU comes & RI not comes, then we must handle RU interrupt. */
+        if (status & EC_STATUS_RI) {
+		    //printk(KERN_INFO "%s %d  RX INTERRUPT\n",__FUNCTION__,__LINE__);
+            subisr_enet_rx(ecp);
+			rx_cnt = 0;
+			mac_status = status & EC_STATUS_TSM;
+			if((mac_status == EC_STATUS_TSM)||(mac_status == EC_TX_run_dsp))
+				tx_cnt++;
+        } else if (status & EC_STATUS_RU) {
+            ru_cnt++;
+            /* set RPD could help if rx suspended & bd available */
+            if (ru_cnt == 2)
+                hw_regs->er_rxpoll = 0x1;
+			printk(KERN_INFO "---RU interrupt---, status: 0x%08x\n", (u32)status);
+#ifdef RX_DEBUG
+            printk(KERN_INFO "---while loops: %d, RU count: %d\n", i, ru_cnt);
+            print_rx_bds(ecp);
+            ecp->msg_enable |= 0x40;
+#endif
+            subisr_enet_rx(ecp);
+#ifdef RX_DEBUG
+            ecp->msg_enable &= ~0x40;
+            print_rx_bds(ecp);
+#endif
+            /* guard against too many RU interrupts to avoid long time ISR handling */
+            if (ru_cnt > 3)
+                break;
+        }
+    }
+    enable_irq(ecp->mac_irq);
+    	 
+	if((tx_cnt>10)||(rx_cnt>10)){
+		if(tx_cnt>10)
+			printk(KERN_INFO "TX ERROR status: 0x%08x\n", (u32)status);
+		else{
+			printk(KERN_INFO "RX ERROR status: 0x%08x\n", (u32)status);
+			ecp->rx_timeout=true;
+		}	
+		rx_cnt = 0;
+		tx_cnt = 0;
+		netif_stop_queue(dev);
+		schedule_work(&ecp->hardware_reset_work);
+	}
+	
+    return (IRQ_HANDLED);
+}
+
+/* phy int pin connected to sirq0 */
+static void phy_cable_plug_irq_enable(int level)
+{
+    /* sirq0: clear pending */
+    putl((getl(INTC_EXTCTL) | (0x1 << 16)) & ~0x0101, INTC_EXTCTL);
+    printk(KERN_INFO "INTC_EXTCTL: 0x%08x\n", getl(INTC_EXTCTL));
+
+    if (!level) { /* low level active, pull up */
+        putl((getl(PAD_PULLCTL0) & 0xffff7fff) | 0x00004000, PAD_PULLCTL0);
+        putl((getl(INTC_EXTCTL) | (0x3 << 21)) & ~(0x1 << 23), INTC_EXTCTL);
+    } else { /* high level active, pull down*/
+        putl((getl(PAD_PULLCTL0) & 0xffffbfff) | 0x00008000, PAD_PULLCTL0);
+        putl(getl(INTC_EXTCTL) | (0x1 << 21), INTC_EXTCTL);
+    }
+    printk(KERN_INFO "PAD_PULLCTL0: 0x%08x\n", getl(PAD_PULLCTL0));
+    printk(KERN_INFO "INTC_EXTCTL: 0x%08x\n", getl(INTC_EXTCTL));
+}
+
+static void phy_cable_plug_irq_disable(void)
+{
+    putl(getl(INTC_EXTCTL) & ~(0x1 << 21) & ~0x0101, INTC_EXTCTL);
+    putl(getl(PAD_PULLCTL0) & ~(0x3 << 14), PAD_PULLCTL0);
+    printk(KERN_INFO "PAD_PULLCTL0: 0x%08x\n", getl(PAD_PULLCTL0));
+    printk(KERN_INFO "INTC_EXTCTL: 0x%08x\n", getl(INTC_EXTCTL));
+}
+
+/**
+ * ec_netdev_open -- open ethernet controller
+ *
+ * return 0 if success, negative value if fail
+ */
+static int ec_netdev_open(struct net_device *dev)
+{
+    int ret = 0;
+    ec_priv_t *ecp = netdev_priv(dev);
+    volatile ethregs_t *hw_regs = ecp->hwrp;
+    unsigned long flags = 0;
+
+	
+	
+    if (ecp->opened) {
+        printk(KERN_INFO "already opened\n");
+        return (0);
+    }
+#ifdef ETH_TEST_MODE
+    ecp->test_mode = 0;
+#endif
+
+    if (prepare_rx_bd(ecp) || prepare_tx_bd(ecp)) {
+        printk(KERN_INFO "error: NO memery for bds.\n");
+        return (-1);
+    }
+
+    	if (_init_hardware(ecp,1,1)) {
+        printk(KERN_INFO "error: harware initialization failed.\n");
+        return (-1);
+    }
+
+    /* should after set_mac_addr() which will set ec_priv_t{.mac_addr} */
+    memcpy(dev->dev_addr, ecp->mac_addr, ETH_MAC_LEN);
+
+    spin_lock_irqsave(&ecp->lock, flags);
+
+    /* send out a mac setup frame */
+    if (transmit_setup_frame(ecp)) {
+        printk(KERN_INFO "error : transmit setup frame failed.\n");
+        spin_unlock_irqrestore(&ecp->lock, flags);
+        return (-1);
+    }
+    
+    /* start to tx & rx packets */
+    hw_regs->er_ienable = EC_IEN_ALL;
+    hw_regs->er_opmode |= EC_OPMODE_ST | EC_OPMODE_SR;
+
+#ifdef DETECT_POWER_SAVE
+    ecp->enable = true;
+#endif
+    ecp->opened = true;
+
+    /* init  mii_if_info struct */
+    ecp->mii_info.phy_id_mask = PHY_ADDR_MASK;
+    ecp->mii_info.reg_num_mask = PHY_REG_NUM_MASK;
+    ecp->mii_info.dev = dev;
+    ecp->mii_info.mdio_read = ec_mdio_read;
+    ecp->mii_info.mdio_write = ec_mdio_write;
+    ecp->mii_info.phy_id = ecp->phy_addr;
+    ecp->mii_info.force_media = 0;
+    ecp->mii_info.full_duplex = 1;
+    ecp->mii_info.supports_gmii = 0;
+    ecp->msg_enable = NET_MSG_ENABLE;
+
+    spin_unlock_irqrestore(&ecp->lock, flags);
+
+    if (ecp->linked) 
+        netif_carrier_on(dev);
+    else 
+        netif_carrier_off(dev);
+
+    printk(KERN_INFO "%s link %s.\n", dev->name, ecp->linked ? "on" : "off");
+
+#if 1
+    /* FIXME!used by KSZ8041, other phy may not need this */
+    if (ecp->phy_model != ETH_PHY_MODEL_ATC2605)
+        phy_cable_plug_irq_enable(0);/* enable high level active */
+#endif
+//rc=  request_irq(client->irq, gsl_ts_irq, IRQF_TRIGGER_RISING | IRQF_DISABLED, client->name, ts);
+
+#ifdef PHY_USE_POLL
+    queue_delayed_work(phy_detect_queue, &ecp->phy_detect_work,msecs_to_jiffies(PHY_DETECT_DUTY));
+        printk(KERN_INFO "phy detect by work queue\n");	
+#else
+ret = request_irq(dev->irq,  ec_netphy_isr,
+                IRQF_TRIGGER_FALLING , "ethernet_phy", dev);
+    if (ret < 0) {
+        printk(KERN_INFO "Unable to request IRQ: %d, ec_netphy_isr\n", ret);
+        return ret;
+    }
+    printk(KERN_INFO "IRQ %d requested, dev: %p\n", dev->irq, dev);
+#endif	
+
+    ret = request_irq(OWL_IRQ_ETHERNET, (irq_handler_t)ec_netmac_isr,
+                0, "ethernet_mac", dev);
+    if (ret < 0) {
+        printk(KERN_INFO "Unable to request IRQ: %d, ec_netmac_isr\n", ret);
+        goto err_irq;
+    }
+    printk(KERN_INFO "IRQ %d requested\n", OWL_IRQ_ETHERNET);
+
+    print_mac_register(ecp);
+
+#ifdef DETECT_POWER_SAVE
+    init_power_save_timer(ecp);
+    start_power_save_timer(ecp, 4000);
+#endif
+
+    netif_start_queue(dev);
+    return (0);
+
+err_irq:
+#ifndef PHY_USE_POLL
+    free_irq(dev->irq, dev);
+#endif
+    return ret;
+}
+
+
+/**
+ * ec_netdev_close -- close ethernet controller
+ *
+ * return 0 if success, negative value if fail
+ */
+static int ec_netdev_close(struct net_device *dev)
+{
+    ec_priv_t *ecp = netdev_priv(dev);
+    //struct atc260x_dev *atc260x = ecp->atc260x;
+    volatile ethregs_t *hw_regs = ecp->hwrp;
+    unsigned long flags = 0;
+    //unsigned short atc260x_temp;
+
+    printk(KERN_INFO "\n");
+    if (!ecp->opened) {
+        printk(KERN_INFO "already closed\n");
+        return (0);
+    }
+
+#ifdef DETECT_POWER_SAVE
+    stop_power_save_timer(ecp);
+#endif
+
+#if 1
+    /* FIXME!used by KSZ8041, other phy may not need this */
+    if (ecp->phy_model != ETH_PHY_MODEL_ATC2605)
+        phy_cable_plug_irq_disable();
+#endif
+
+	_deinit_hardware(ecp);
+
+    netif_stop_queue(dev);
+
+    spin_lock_irqsave(&ecp->lock, flags);
+#ifdef DETECT_POWER_SAVE
+    ecp->enable = false;
+#endif
+    ecp->opened = false;
+    ecp->linked = false;	
+    hw_regs->er_opmode &= ~(EC_OPMODE_ST | EC_OPMODE_SR);
+
+    hw_regs->er_ienable = 0;
+
+    spin_unlock_irqrestore(&ecp->lock, flags);
+
+    free_irq(OWL_IRQ_ETHERNET, dev);
+
+#ifndef PHY_USE_POLL
+    free_irq(dev->irq, dev);
+#endif
+    if (ecp->phy_model != ETH_PHY_MODEL_ATC2605)
+        goto phy_not_atc2605;
+   #if 0
+    /* turn off both link status & speed LEDs after ethernet down */
+    atc260x_reg_write(atc260x, atc2603_PHY_HW_RST, 0x01);  //reset the phy
+    udelay(100);  //! not work if removed
+    do {
+        atc260x_temp = atc260x_reg_read(atc260x, atc2603_PHY_HW_RST);
+    }while(atc260x_temp & 0x1); //waite for reset process completion
+
+    //need power down phy and mac
+    /*ethernet wrapper rest and phy has no power*/
+    atc260x_reg_setbits(atc260x, atc2603_CMU_DEVRST, 0x08, 0x08);
+    udelay(100);
+    atc260x_reg_setbits(atc260x, atc2603_CMU_DEVRST, 0x08, 0x0);
+    udelay(100);
+    atc260x_reg_setbits(atc260x, atc2603_CMU_DEVRST, 0x200, 0x0);
+    udelay(100);
+    #endif //0
+phy_not_atc2605:
+    ethernet_clock_disable();
+    return (0);
+}
+
+
+/**
+ * ec_netdev_start_xmit -- transmit a skb
+ *
+ * NOTE: if CSR6.ST is not set, the xmit frame will fail
+ *
+ * return NETDEV_TX_OK if success, others if fail
+ */
+static int ec_netdev_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+    ec_priv_t *ecp = netdev_priv(dev);
+    volatile ethregs_t *hw_regs = ecp->hwrp;
+    volatile ec_bd_t *bdp;
+    unsigned long flags = 0;
+
+#ifndef ETH_TEST_MODE
+    if (!ecp->linked) {
+        printk(KERN_INFO "haven't setup linkage\n");
+        return (-2);
+    }
+#endif
+
+    if (ecp->tx_full) {
+		if(printk_ratelimit())
+        	printk(KERN_INFO "warnig : tx buffer list is full\n");
+        return (NETDEV_TX_BUSY);
+    }
+
+    spin_lock_irqsave(&ecp->lock, flags);
+    bdp = ecp->cur_tx;
+
+    if (bdp->status & TXBD_STAT_OWN) {
+        printk(KERN_INFO "%s: tx is full. should not happen\n", dev->name);
+        spin_unlock_irqrestore(&ecp->lock, flags);
+        return (NETDEV_TX_BUSY);
+    }
+
+    /* Push the data cache so the NIC does not get stale memory data. */
+    bdp->buf_addr = dma_map_single(&ecp->netdev->dev, skb->data, skb->len, DMA_TO_DEVICE);
+    if (!bdp->buf_addr)
+        printk(KERN_INFO "dma map skb->data:%p failed\n", skb->data);
+
+    bdp->status = 0;
+    bdp->control &= TXBD_CTRL_IC | TXBD_CTRL_TER; /* clear others */
+    bdp->control |= TXBD_CTRL_TBS1(skb->len);
+    bdp->control |= TXBD_CTRL_FS | TXBD_CTRL_LS;
+    mb();
+    bdp->status = TXBD_STAT_OWN;
+    mb();
+    {
+        volatile u32 tmp;
+        tmp = (u32)(bdp->status + bdp->control + bdp->buf_addr);
+    }
+	if(skb->len > 1518)
+		printk(KERN_INFO "tx length:%d\n", skb->len);
+    //printk(KERN_INFO "bdp->status: 0x%x\n", bdp->status);
+
+    //!for FPGA test, or else tx transmission gonna disorder
+    //udelay(1);
+
+    /* 
+      * leave xmit suspended mode to xmit running mode; another method is that first 
+      * stop xmit, then start xmit through clearing CSR6.13-ST then setting it again.
+      * before call this function, CSR6.13-ST should be set
+      */
+    hw_regs->er_txpoll = EC_TXPOLL_ST;
+
+    dev->stats.tx_bytes += skb->len; 
+    dev->trans_start = jiffies;
+
+    ecp->tx_skb[ecp->skb_cur] = skb;
+    ecp->skb_cur = (ecp->skb_cur + 1) & TX_RING_MOD_MASK;
+
+    if (!(hw_regs->er_status & EC_STATUS_TSM))
+        printk(KERN_INFO "tx stopped, hw_regs->er_status:0x%lx\n", hw_regs->er_status);
+
+    if (netif_msg_tx_err(ecp)) {
+        check_icmp_sequence(skb->data, __func__);
+        printk(KERN_INFO "%d, hw_regs->er_status:0x%lx\n", __LINE__, hw_regs->er_status);
+        printk(KERN_INFO "bdp->status:0x%x\n", (unsigned int)bdp->status);
+        printk(KERN_INFO "bdp->control:0x%x\n", (unsigned int)bdp->control);
+        printk(KERN_INFO "bdp->buf_addr:0x%x\n", (unsigned int)bdp->buf_addr);
+        printk(KERN_INFO "tx frame len:0x%x, skb->data:0x%x\n", skb->len, (int)skb->data);
+        printk(KERN_INFO "tx src mac: ");
+        print_mac_address(skb->data + ETH_MAC_LEN);
+        printk(KERN_INFO "tx dst mac: ");
+        print_mac_address(skb->data);
+        printk(KERN_INFO "tx frame:\n");
+        print_frame_data(skb->data, skb->len);
+    }
+
+    if (bdp->control & TXBD_CTRL_TER)
+        bdp = ecp->tx_bd_base;
+    else
+        bdp++;
+
+    if (bdp == ecp->dirty_tx) {
+        printk(KERN_INFO "tx is full, skb_dirty:%d\n", ecp->skb_dirty);
+        ecp->tx_full = true;
+        netif_stop_queue(dev);
+    }
+    netif_stop_queue(dev);
+
+    ecp->cur_tx = (ec_bd_t *)bdp;
+    spin_unlock_irqrestore(&ecp->lock, flags);
+
+    /*---------------debug -------------------*/
+#if 0
+    {
+        static timeout_reset_cnt = 0;
+        timeout_reset_cnt++;
+        if(timeout_reset_cnt >100000) {
+            timeout_reset_cnt =0;
+            ec_netdev_transmit_timeout(ecp->netdev);
+        }
+    }
+#endif
+
+    return (NETDEV_TX_OK);
+}
+
+
+/**
+ * ec_netdev_query_stats -- query statistics of ethernet controller
+ */
+static struct net_device_stats *ec_netdev_query_stats(struct net_device *dev)
+{
+    return (&dev->stats);
+}
+
+
+/**
+ * ec_netdev_set_mac_addr -- set mac a new address
+ *
+ * NOTE: when ethernet device has opened, can't change mac address, otherwise return 
+ * EBUSY error code.
+ *
+ * return 0 if success, others if fail
+ */
+static int ec_netdev_set_mac_addr(struct net_device *dev, void *addr)
+{
+    struct sockaddr *address = (struct sockaddr *) addr;
+    ec_priv_t *ecp = netdev_priv(dev); 
+    unsigned long flags = 0;
+    char    old_mac_addr[ETH_MAC_LEN];
+    bool old_overrided;
+
+    printk(KERN_INFO "\n");
+
+    if (!is_valid_ether_addr(address->sa_data)) {
+        printk(KERN_INFO "not valid mac address\n");
+        return (-EADDRNOTAVAIL);
+    }
+
+    /* if new mac address is the same as the old one, nothing to do */
+    if (!compare_ether_addr(ecp->mac_addr, address->sa_data)) {
+        printk(KERN_INFO "the same address ! \n");
+        return (0);
+    }
+
+    if (netif_running(dev)) {
+        printk(KERN_INFO "error : queue is busy\n");
+        return (-EBUSY);
+    }
+
+    spin_lock_irqsave(&ecp->lock, flags);
+
+    memcpy(old_mac_addr, ecp->mac_addr, ETH_MAC_LEN);
+    old_overrided = ecp->mac_overrided;
+
+    memcpy(ecp->overrided_mac, address->sa_data, dev->addr_len);
+
+    if (compare_ether_addr(g_default_mac_addr, ecp->overrided_mac)) {
+        ecp->mac_addr = ecp->overrided_mac;
+        ecp->mac_overrided = true;
+    } else {
+        ecp->mac_addr = g_default_mac_addr;
+        ecp->mac_overrided = false;
+    }
+
+    memcpy(dev->dev_addr, ecp->mac_addr, dev->addr_len);
+
+    /* if netdev is close now, just save new addr tmp, set it when open it */
+    if (!ecp->opened) {
+        spin_unlock_irqrestore(&ecp->lock, flags);
+        return (0);
+    }
+
+    fill_macaddr_regs(ecp, ecp->mac_addr);  /* for flow control */
+
+    /*
+     * errors only occur before frame is put into tx bds. in fact if frame is successfully built, 
+     * xmit never fail, otherwise mac controller may be something wrong.
+     */
+    if (transmit_setup_frame(ecp)) {
+        printk(KERN_INFO "error : transmit setup frame failed\n");
+
+        /* set back to old one */
+        fill_macaddr_regs(ecp, old_mac_addr);
+        
+        if (old_overrided) {
+            memcpy(ecp->overrided_mac, old_mac_addr, ETH_MAC_LEN);
+            ecp->mac_addr = ecp->overrided_mac;
+        } else {
+            ecp->mac_addr = g_default_mac_addr;
+        }
+        ecp->mac_overrided = old_overrided;
+        memcpy(dev->dev_addr, ecp->mac_addr, dev->addr_len);
+        spin_unlock_irqrestore(&ecp->lock, flags);
+        return (-1);
+    }
+
+    spin_unlock_irqrestore(&ecp->lock, flags);
+
+    return (0);
+}
+
+
+/**
+ * copy_multicast_list -- copy @list to local ec_priv_t{.multicast_list}
+ * may use it if multicast is supported when building setup-frame 
+ */
+static inline void copy_multicast_list(ec_priv_t *ecp, struct netdev_hw_addr_list *list)
+{
+    char (*mmac_list)[MULTICAST_LIST_LEN][ETH_MAC_LEN] = NULL;
+    struct netdev_hw_addr *ha = NULL;
+    int mmac_sum = 0;
+
+    mmac_list = &ecp->multicast_list.mac_array;
+#if 0
+    while (list && mmac_sum < MULTICAST_LIST_LEN) {
+        if (!is_multicast_ether_addr(list->dmi_addr)) {
+            //printk(KERN_INFO "there is one non-multicast addr\n");
+            continue;
+        }
+        
+#if EC_TRACED
+        printk(KERN_INFO "ok, add one : ");
+        print_mac_address(list->dmi_addr);
+#endif
+
+        memcpy((*mmac_list)[mmac_sum], list->dmi_addr, ETH_MAC_LEN);
+        list = list->next;
+        mmac_sum++;
+    }
+#endif
+
+    netdev_hw_addr_list_for_each(ha, list) {
+        if (mmac_sum >= MULTICAST_LIST_LEN) {
+            break;
+        }
+        if (!is_multicast_ether_addr(ha->addr)) {
+            //printk(KERN_INFO "there is one non-multicast addr\n");
+            continue;
+        }
+        memcpy((*mmac_list)[mmac_sum], ha->addr, ETH_MAC_LEN);
+        mmac_sum++;
+    }
+
+    ecp->multicast_list.count = mmac_sum; 
+
+    return;
+}
+
+
+static inline void parse_interface_flags(ec_priv_t *ecp, unsigned int flags)
+{
+    printk(KERN_INFO "\n");
+    set_mode_promisc(ecp, (bool)(flags & IFF_PROMISC));
+    set_mode_all_multicast(ecp, (bool)(flags & IFF_ALLMULTI));
+    ecp->multicast = (bool)(flags & IFF_MULTICAST);
+    return;
+}
+
+/**
+ * ec_netdev_set_multicast_list -- set mac multicast address, meanwhile set promiscuous
+ * and all_multicast mode according to dev's flags
+ */
+static void ec_netdev_set_multicast_list(struct net_device *dev)
+{
+    ec_priv_t *ecp = netdev_priv(dev);
+    volatile ethregs_t *hw_regs = ecp->hwrp;
+    unsigned long flags = 0;
+    unsigned long old_srst_bits;
+
+#if EC_TRACED
+    printk(KERN_INFO "--- enter %s()\n", __func__);
+    printk(KERN_INFO "dev->flags - 0x%x\n", dev->flags);
+#endif
+
+    spin_lock_irqsave(&ecp->lock, flags);
+
+    old_srst_bits = hw_regs->er_opmode & (EC_OPMODE_SR | EC_OPMODE_ST);
+
+    /* stop tx & rx first */
+    hw_regs->er_opmode &= ~(EC_OPMODE_SR | EC_OPMODE_ST);
+
+    parse_interface_flags(ecp, dev->flags);
+
+    if (!ecp->all_multicast && ecp->multicast && dev->mc.count) {
+        if (dev->mc.count <= MULTICAST_LIST_LEN) {
+	        copy_multicast_list(ecp, &dev->mc);
+            transmit_setup_frame(ecp);
+        } else {
+            printk(KERN_INFO "too multicast addrs to support, open all_multi\n");
+            /* list is too long to support, so receive all multicast packets */
+            set_mode_all_multicast(ecp, true);
+        }
+    }
+    printk(KERN_INFO "\n");
+
+    hw_regs->er_opmode |= old_srst_bits;
+ 
+    spin_unlock_irqrestore(&ecp->lock, flags);
+
+    return;
+
+}
+
+static inline void modify_mii_info(struct mii_ioctl_data *data, struct mii_if_info *info)
+{
+    unsigned short val = data->val_in;
+
+    if (data->phy_id != info->phy_id)
+        return;
+
+    switch (data->reg_num) {
+    case MII_BMCR:
+    {
+        info->force_media = (val & (BMCR_RESET | BMCR_ANENABLE)) ? 0 : 1;
+
+        if (info->force_media && (val & BMCR_FULLDPLX))
+            info->full_duplex = 1;
+        else
+            info->full_duplex = 0;
+        break;
+    }
+    case MII_ADVERTISE:
+        info->advertising = val;
+        break;
+    default:
+        /* nothing to do */
+        break;
+    }
+
+    return;
+}
+
+
+/**
+ * ec_netdev_ioctrl -- net device's ioctrl hook
+ */
+static int ec_netdev_ioctrl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{    
+    ec_priv_t *ecp = netdev_priv(dev);
+    struct mii_ioctl_data *data = if_mii(ifr);
+    struct mii_if_info *info = &ecp->mii_info;
+    int     err = 0;
+
+#if EC_TRACED
+    printk(KERN_INFO "--- enter %s()\n", __func__);
+    printk(KERN_INFO "phy reg num - 0x%x, data - 0x%x, cmd:0x%x\n", data->reg_num, data->val_in, cmd);
+#endif
+
+    data->phy_id &= info->phy_id_mask;
+    data->reg_num &= info->reg_num_mask;
+
+    switch (cmd) {
+    case SIOCGMIIPHY:
+        data->phy_id = info->phy_id;
+        /* FALL THROUGH */
+    case SIOCGMIIREG:
+        //data->val_out = read_phy_reg(ecp, info->phy_id, data->reg_num);
+        data->val_out = read_phy_reg(ecp, 0x500 + data->reg_num);
+        break;
+
+    case SIOCSMIIREG:
+    {
+        unsigned short val = data->val_in;
+        //unsigned short old_val;
+
+        if (!capable(CAP_NET_ADMIN)) {
+            return (-EPERM);
+        }
+
+        modify_mii_info(data, info);
+        //printk(KERN_INFO "val : 0x%x\n", val);
+
+        /* when keep speed unchanged, but change duplex, CSR5.LCIQ will not raise
+         *  interrupt. if so ISR can't capture duplex status change.
+         * here we change speed first and then set it back to raise a LCIQ interrupt.
+         * has other better way???
+         */
+//            if (unlikely(info->force_media && MII_BMCR == data->reg_num)) {
+//                //old_val = read_phy_reg(ecp, info->phy_id, data->reg_num);
+//                old_val = read_phy_reg(ecp, data->reg_num);
+//                if (need_change_speed(val, old_val)) {
+//                    //printk(KERN_INFO "old bmcr: 0x%x\n", old_val);
+//                    old_val &= ~(BMCR_ANENABLE | BMCR_RESET);
+//                    old_val ^= BMCR_SPEED100;
+//                    //printk(KERN_INFO "exchanged old bmcr: 0x%x\n", old_val);
+//                    //write_phy_reg(ecp, info->phy_id, data->reg_num, old_val);
+//                    write_phy_reg(ecp, data->reg_num, old_val);
+//                }
+//            }
+
+        //write_phy_reg(ecp, info->phy_id, data->reg_num, val);
+        write_phy_reg(ecp, 0x500 + data->reg_num, val);
+        break;
+    }  /* end SIOCSMIIREG */
+
+    default:
+        err = -EOPNOTSUPP;
+        break;
+    }
+
+    return (err);
+
+    //return generic_mii_ioctl(&ecp->mii_info, data, cmd, NULL);
+}
+
+/**
+ * do hardware reset,this function is called when transmission timeout.
+*/
+static void hardware_reset_do_work(struct work_struct *work)
+{
+	struct net_device *dev =  g_eth_dev[0];
+	ec_priv_t *ecp = netdev_priv(dev);//(ec_priv_t *)container_of(work, ec_priv_t, hardware_reset_work);//
+	volatile ethregs_t *hw_regs = ecp->hwrp;
+  bool phy_reinit =false;
+	//spin_lock_irqsave(&ecp->lock, flags);
+
+//    netif_carrier_off(dev);
+
+    hw_regs->er_opmode &= ~(EC_OPMODE_SR | EC_OPMODE_ST);       // stop tx and rx
+    hw_regs->er_ienable = 0;
+
+    disable_irq(ecp->mac_irq);
+#ifdef PHY_USE_POLL
+    cancel_delayed_work(&ecp->phy_detect_work);
+    flush_workqueue(phy_detect_queue);
+#else
+    disable_irq(dev->irq);
+#endif
+		//if tx timeout ֻ\B8\B4λmac\A3\AC\B2\BB\B8\B4λphy, \B7\F1\D4\F2\B6\BC\D7\F6reset
+#if 0   //timeout \D7\DC\CADz\BBreset phy
+    if(ecp->rx_timeout){
+    	  phy_reinit=true;
+				ecp->rx_timeout=false;    			
+				write_phy_reg(ecp, 0x0, 0x1<<15);
+				mdelay(5);
+				_deinit_hardware(ecp);
+				mdelay(30);
+		}		
+#endif
+		
+    ethernet_clock_disable();
+
+    /* set default value of status */
+//    ecp->linked = false;
+//    ecp->opened = false;
+//    ecp->speed = ETH_SPEED_100M;
+//    ecp->duplex = ETH_DUP_FULL;
+    //spin_unlock_irqrestore(&ecp->lock, flags);
+	
+    if (prepare_rx_bd(ecp) || prepare_tx_bd(ecp)) {
+        INFO_RED("error : prepare bds failed\n");
+        return;
+    }
+    if(phy_reinit){
+    	phy_reinit=false;
+    	if (_init_hardware(ecp,1,1)) {
+      	  INFO_RED("error : harware init failed.\n");
+        	return;
+    	}
+    }else{
+     	if (_init_hardware(ecp,1,0)) {
+      	  INFO_RED("error : harware init failed.\n");
+        	return;
+    	}    
+    }		
+
+    memcpy(dev->dev_addr, ecp->mac_addr, ETH_MAC_LEN);
+
+    parse_interface_flags(ecp, dev->flags);
+
+    if (transmit_setup_frame(ecp)) {  // recovery previous macs
+        INFO_RED("error : xmit setup frame failed\n");
+        return;
+    }
+
+    hw_regs->er_ienable = EC_IEN_ALL;
+    hw_regs->er_opmode |= (EC_OPMODE_SR | EC_OPMODE_ST);        /* start tx, rx */
+
+//#ifdef DETECT_POWER_SAVE
+//    ecp->enable = true;
+//      start_power_save_timer(ecp, 4000);
+//#endif
+//    ecp->opened = true;
+
+#ifdef PHY_USE_POLL
+    queue_delayed_work(phy_detect_queue, &ecp->phy_detect_work,msecs_to_jiffies(PHY_DETECT_DUTY));
+#else
+    enable_irq(dev->irq);
+#endif
+    enable_irq(ecp->mac_irq);
+	return;
+	
+}
+/**
+ * ec_netdev_transmit_timeout -- process tx fails to complete within a period.
+ *
+ * This function is called when a packet transmission fails to complete within a  
+ * resonable period, on the assumption that an interrupts have been failed or the 
+ * interface is locked up. This function will reinitialize the hardware 
+ */
+static void ec_netdev_transmit_timeout(struct net_device *dev)
+{
+    ec_priv_t *ecp = netdev_priv(dev);
+	static int reset = 0;
+    volatile ethregs_t *hw_regs = ecp->hwrp;
+    unsigned long flags = 0;    
+#if 0
+    //unsigned long flags = 0;
+    /* times of timeout handled by subisr_enet_tx() */
+//    static int times = 0;
+    /* times of hardware reset, (times * reset) is the overall times of timeout */
+    volatile ec_bd_t *bdp;
+
+#define TX_TIMEOUT_TIMES_2_RESET 1
+//    printk(KERN_INFO "before tx isr, reg status : 0x%x\n", (int)hw_regs->er_status);
+    print_mac_register(ecp);
+    print_tx_bds(ecp);
+
+
+    /* handle situation that no TX interrupt comes & TX process is dead */
+    if (times < TX_TIMEOUT_TIMES_2_RESET) {
+        hw_regs->er_ienable &= ~(EC_IEN_TIE |EC_IEN_ETE);
+
+        bdp = ecp->dirty_tx;
+        if (bdp->status & TXBD_STAT_OWN) {
+            times++;
+        } else {
+            //subisr_enet_tx(ecp);
+//            printk(KERN_INFO "---TX timeout times: %d\n", times);
+            times = 0;
+        }
+        hw_regs->er_ienable |= EC_IEN_TIE | EC_IEN_ETE;
+#if 0
+        printk(VT_GREEN "after tx isr, reg status : 0x%x\n" VT_NORMAL, (int)hw_regs->er_status);
+        print_mac_register(ecp);
+        print_tx_bds(ecp);
+#endif
+        /* if tx still time out, then reset hardware */
+        return;
+    }
+    times = 0;
+
+    printk(KERN_INFO "before tx isr, reg status : 0x%x\n", (int)hw_regs->er_status);
+    print_mac_register(ecp);
+    print_tx_bds(ecp);
+#endif
+	netif_stop_queue(dev);
+    reset++;
+#if 0    
+    printk(KERN_INFO "---TX timeout reset: %d\n", reset);
+	printk(KERN_INFO "MAC flowctrl : 0x%x\n", (int)hw_regs->er_flowctrl);
+	printk(KERN_INFO "MAC reg status : 0x%x\n", (int)hw_regs->er_status);
+#endif	  
+	schedule_work(&ecp->hardware_reset_work);
+#if 0
+    spin_lock_irqsave(&ecp->lock, flags);
+
+    netif_stop_queue(dev);
+    netif_carrier_off(dev);
+
+    hw_regs->er_opmode &= ~(EC_OPMODE_SR | EC_OPMODE_ST);       // stop tx and rx
+    hw_regs->er_ienable = 0;
+
+    disable_irq(ecp->mac_irq);
+    disable_irq(dev->irq);
+    ethernet_clock_disable();
+
+    /* set default value of status */
+    ecp->linked = false;
+    ecp->opened = false;
+    ecp->speed = ETH_SPEED_100M;
+    ecp->duplex = ETH_DUP_FULL;
+    spin_unlock_irqrestore(&ecp->lock, flags);
+		
+
+    if (prepare_rx_bd(ecp) || prepare_tx_bd(ecp)) {
+        INFO_RED("error : prepare bds failed\n");
+        return;
+    }
+
+    if (_init_hardware(ecp,1)) {
+        INFO_RED("error : harware init failed.\n");
+        return;
+    }
+
+    memcpy(dev->dev_addr, ecp->mac_addr, ETH_MAC_LEN);
+
+    parse_interface_flags(ecp, dev->flags);
+
+    if (transmit_setup_frame(ecp)) {  // recovery previous macs
+        INFO_RED("error : xmit setup frame failed\n");
+        return;
+    }
+
+    hw_regs->er_ienable = EC_IEN_ALL;
+    hw_regs->er_opmode |= (EC_OPMODE_SR | EC_OPMODE_ST);        /* start tx, rx */
+
+#ifdef DETECT_POWER_SAVE
+    ecp->enable = true;
+    start_power_save_timer(ecp, 4000);
+#endif
+    ecp->opened = true;
+
+    enable_irq(dev->irq);
+    enable_irq(ecp->mac_irq);
+
+    /* we need make sure all right before arrive here. */
+    //netif_wake_queue(dev);
+#endif
+    return;
+}
+
+
+/*
+ * Internal function. Flush all scheduled work from the Ethernet work queue.
+ */
+static void ethernet_flush_scheduled_work(void)
+{
+	flush_workqueue(resume_queue);
+}
+
+
+static int asoc_ethernet_suspend(struct platform_device *pdev, pm_message_t m)
+{
+    struct net_device *dev =  g_eth_dev[0];
+    ec_priv_t *ecp = netdev_priv(dev);
+    volatile ethregs_t *hw_regs = ecp->hwrp;
+    unsigned long flags = 0;
+
+    dev_info(&pdev->dev, "asoc_ethernet_suspend()\n");
+
+    suspend_flag = 1;
+
+    disable_irq(ecp->mac_irq);
+    
+	  _deinit_hardware(ecp);
+	  mdelay(5);  
+#ifdef PHY_USE_POLL 	
+    cancel_delayed_work_sync(&ecp->phy_detect_work);
+//    flush_workqueue(phy_detect_queue);
+#else
+    disable_irq(dev->irq);
+#endif
+
+    ecp->linked = false;
+            
+    cancel_delayed_work_sync(&resume_work);
+    ethernet_flush_scheduled_work();
+
+    netif_stop_queue(dev);
+    netif_carrier_off(dev);
+
+    spin_lock_irqsave(&ecp->lock, flags);
+    
+    hw_regs->er_opmode &= ~(EC_OPMODE_SR | EC_OPMODE_ST);  // stop tx and rx
+    hw_regs->er_ienable = 0;
+
+    free_rxtx_skbs(ecp->rx_skb, RX_RING_SIZE);
+    free_rxtx_skbs(ecp->tx_skb, TX_RING_SIZE);
+
+    spin_unlock_irqrestore(&ecp->lock, flags);
+
+
+
+    ethernet_clock_disable();
+
+    return 0;
+}
+
+
+static int ethernet_parse_gpio(struct device_node * of_node, const char * propname, struct owl_ethernet_gpio * gpio)
+{
+    enum of_gpio_flags gflags;
+    int	gpio_num;
+
+    gpio_num = of_get_named_gpio_flags(of_node, propname, 0, &gflags);
+    if (gpio_num >= 0) {
+        gpio->gpio = gpio_num;
+    } else {
+        gpio->gpio = -1;
+	 return -1;		
+    }
+
+    gpio->active= (gflags&OF_GPIO_ACTIVE_LOW) ;
+
+    return 0;
+}
+
+
+static void ethernet_resume_handler(struct work_struct *work)
+{
+    struct net_device *dev =  g_eth_dev[0];
+
+    ec_priv_t *ecp = netdev_priv(dev);
+    volatile ethregs_t *hw_regs = ecp->hwrp;
+    unsigned long flags = 0;
+ 
+    printk(KERN_INFO "\n");
+    suspend_flag = 0;
+ #if 0
+    if (ecp->phy_model == ETH_PHY_MODEL_ATC2605) {
+        /*For gl5302 INT Pending unusual */
+        ethernet_clock_enable();
+        ecp->phy_ops->phy_hw_init(ecp);
+
+        /*ethernet wrapper rest and phy has no power*/
+        atc260x_reg_setbits(ecp->atc260x, atc2603_CMU_DEVRST, 0x08, 0x08);
+        udelay(100);
+        atc260x_reg_setbits(ecp->atc260x, atc2603_CMU_DEVRST, 0x08, 0x0);
+        udelay(100);
+  #endif //0
+       // ethernet_clock_disable();
+    
+
+    if (ecp->opened == false) {
+        printk(KERN_INFO "The ethernet is turned off\n");
+        return;
+    }
+   
+    ecp->last_link_status=ecp->linked = false;
+    			
+    spin_lock_irqsave(&ecp->lock, flags);
+    if (prepare_rx_bd(ecp) || prepare_tx_bd(ecp)) {
+        printk(KERN_INFO "error: prepare bds failed\n");
+        goto err_unlock;
+    }
+    spin_unlock_irqrestore(&ecp->lock, flags);
+
+    /*can't sleep */
+
+    if (_init_hardware(ecp,0,1)) {
+        printk(KERN_INFO "error: harware init failed.\n");
+        return;
+    }
+
+    spin_lock_irqsave(&ecp->lock, flags);
+
+    memcpy(dev->dev_addr, ecp->mac_addr, ETH_MAC_LEN);
+
+    parse_interface_flags(ecp, dev->flags);
+
+    /* send out a mac setup frame */
+    if (transmit_setup_frame(ecp)) {  // recovery previous macs
+        printk(KERN_INFO "error: xmit setup frame failed\n");
+        goto err_unlock;
+    }
+
+    hw_regs->er_ienable = EC_IEN_ALL;
+    hw_regs->er_opmode |= (EC_OPMODE_SR | EC_OPMODE_ST);
+    spin_unlock_irqrestore(&ecp->lock, flags);
+#ifndef PHY_USE_POLL 
+    enable_irq(dev->irq);
+#endif
+    enable_irq(ecp->mac_irq);
+#ifdef DETECT_POWER_SAVE
+    ecp->enable = true;
+    start_power_save_timer(ecp, 4000);
+#endif
+
+#ifdef PHY_USE_POLL
+     queue_delayed_work(phy_detect_queue, &ecp->phy_detect_work,msecs_to_jiffies(PHY_DETECT_RESUME));		//\B1\D8\D0\EB\B5ȴ\FDresume\BA\F3\B2\C5\C4\DC\D7\F6detect
+     printk(KERN_INFO "phy detect by work queue\n");	
+#endif
+    //netif_wake_queue(dev);
+    return;
+
+err_unlock:
+    spin_unlock_irqrestore(&ecp->lock, flags);
+}
+
+static int asoc_ethernet_resume(struct platform_device *pdev)
+{
+    dev_info(&pdev->dev, "asoc_ethernet_resume()\n");
+    struct net_device *dev =  g_eth_dev[0];
+    ec_priv_t *ecp = netdev_priv(dev);
+    queue_delayed_work(resume_queue, &resume_work, msecs_to_jiffies(PHY_RESUME_DELAY));
+	
+    return 0;
+}
+
+/**
+ * ec_netdev_init -- initialize ethernet controller
+ *
+ * return 0 if success, others if fail
+ */
+static int ec_netdev_init(struct net_device *dev)
+{
+    ec_priv_t *ecp = netdev_priv(dev);
+    volatile ethregs_t *hw_regs = NULL;
+
+    printk(KERN_INFO "ETHERNET_BASE: 0x%x\n", ETHERNET_BASE);
+    printk(KERN_INFO "ecp->hwrp: 0x%p\n", ecp->hwrp);
+    /* ETHERNET_BASE address is taken from dts when driver probe,
+     * instead of hard-coding here */
+    /* ecp->hwrp = (volatile ethregs_t *)IO_ADDRESS(ETHERNET_BASE); */
+    ecp->netdev = dev;
+    hw_regs = ecp->hwrp;
+
+    /* set default value of status */
+#ifdef DETECT_POWER_SAVE
+    ecp->enable = false;
+#endif
+    ecp->linked = false;
+    ecp->opened = false;
+    ecp->mac_overrided = false;
+    ecp->multicast = false;
+    ecp->all_multicast = false;
+    ecp->promiscuous = false;
+    ecp->autoneg = true;
+    ecp->speed = ETH_SPEED_100M;
+    ecp->duplex = ETH_DUP_FULL;
+    ecp->mac_addr = NULL;
+
+    memset(&ecp->multicast_list, 0, sizeof(struct mac_list));
+    spin_lock_init(&ecp->lock);
+
+    //uncache address
+    ecp->tx_bd_base = (ec_bd_t *)dma_alloc_coherent(NULL, sizeof(ec_bd_t) * TX_RING_SIZE, &ecp->tx_bd_paddr, GFP_KERNEL);
+    ecp->rx_bd_base = (ec_bd_t *)dma_alloc_coherent(NULL, sizeof(ec_bd_t) * RX_RING_SIZE, &ecp->rx_bd_paddr, GFP_KERNEL);
+
+    printk(KERN_INFO "ecp->tx_bd_base:%p, ecp->tx_bd_paddr:%p\n", ecp->tx_bd_base, (void *)ecp->tx_bd_paddr);
+    printk(KERN_INFO "ecp->rx_bd_base:%p, ecp->rx_bd_paddr:%p\n", ecp->rx_bd_base, (void *)ecp->rx_bd_paddr);
+    printk(KERN_INFO "virt_to_phys(ecp->tx_bd_base):%p\n", (void *)virt_to_phys(ecp->tx_bd_base));
+
+    if (ecp->tx_bd_base == NULL || ecp->rx_bd_base == NULL) {
+        printk(KERN_INFO "dma_alloc mem failed, tx_bd_base:%p, rx_bd_base:%p\n",
+                ecp->tx_bd_base, ecp->rx_bd_base);
+
+        if (ecp->tx_bd_base)
+            dma_free_coherent(NULL, sizeof(ec_bd_t) * TX_RING_SIZE,
+                    ecp->tx_bd_base, ecp->tx_bd_paddr);
+        if (ecp->rx_bd_base)
+            dma_free_coherent(NULL, sizeof(ec_bd_t) * RX_RING_SIZE,
+                    ecp->rx_bd_base, ecp->rx_bd_paddr);
+
+        return -ENOMEM;
+    }
+   #if 0
+    if (ecp->phy_model == ETH_PHY_MODEL_ATC2605) {
+        /*For gl5302 INT Pending unusual */
+        ethernet_clock_enable();
+        ecp->phy_ops->phy_hw_init(ecp);
+    }
+  #endif //0
+    ecp->mac_addr = g_default_mac_addr;
+    ecp->mac_overrided = false;
+
+    /* should after set_mac_addr() which will set ec_priv_t{.mac_addr} */
+    memcpy(dev->dev_addr, ecp->mac_addr, ETH_MAC_LEN);
+
+    ether_setup(dev);
+
+    INFO_GREEN("net device : %s init over.\n", dev->name);
+  #if 0
+    if (ecp->phy_model == ETH_PHY_MODEL_ATC2605) {
+        hw_regs->er_opmode &= ~(EC_OPMODE_SR | EC_OPMODE_ST);  // stop tx and rx
+        hw_regs->er_ienable = 0;
+
+        /*ethernet wrapper rest and phy has no power*/
+        atc260x_reg_setbits(ecp->atc260x, atc2603_CMU_DEVRST, 0x08, 0x08);
+        udelay(100);
+        atc260x_reg_setbits(ecp->atc260x, atc2603_CMU_DEVRST, 0x08, 0x0);
+        udelay(100);
+
+        ethernet_clock_disable();
+    }
+    #endif //0
+    return (0);
+}
+
+static void ec_netdev_uninit(struct net_device *dev)
+{
+    ec_priv_t *ecp = netdev_priv(dev);
+
+    printk(KERN_INFO "\n");
+#if 0
+    if (ecp->tx_wq) {
+        destroy_workqueue(ecp->tx_wq);
+    }
+
+    if (ecp->rx_wq) {
+        destroy_workqueue(ecp->rx_wq);
+    }
+#endif
+
+    /* after all works have been completed and destroyed */
+    free_rxtx_skbs(ecp->rx_skb, RX_RING_SIZE);
+    free_rxtx_skbs(ecp->tx_skb, TX_RING_SIZE);
+
+    if (ecp->tx_bd_base)
+        dma_free_coherent(NULL, sizeof(ec_bd_t) * TX_RING_SIZE,
+                ecp->tx_bd_base, ecp->tx_bd_paddr);
+    if (ecp->rx_bd_base)
+        dma_free_coherent(NULL, sizeof(ec_bd_t) * RX_RING_SIZE,
+                ecp->rx_bd_base, ecp->rx_bd_paddr);
+}
+
+static const struct net_device_ops ec_netdev_ops = {
+    .ndo_init = ec_netdev_init,
+    .ndo_uninit = ec_netdev_uninit,
+    .ndo_open = ec_netdev_open,
+    .ndo_stop = ec_netdev_close,
+    .ndo_start_xmit = ec_netdev_start_xmit,
+    .ndo_set_rx_mode = ec_netdev_set_multicast_list,
+    .ndo_set_mac_address = ec_netdev_set_mac_addr,
+    .ndo_get_stats = ec_netdev_query_stats,
+    .ndo_tx_timeout = ec_netdev_transmit_timeout,
+    .ndo_validate_addr = eth_validate_addr,
+    .ndo_do_ioctl = ec_netdev_ioctrl,
+};
+
+static struct pinctrl *ppc;
+//static struct pinctrl_state *pps;
+
+static int ethernet_set_pin_mux(struct platform_device *pdev)
+{
+	int ret = 0;
+
+	ppc = pinctrl_get_select_default(&pdev->dev);
+	if (IS_ERR(ppc)) {
+		pr_err("pinctrl_get_select_default() error, ret = %ld\n",
+			PTR_ERR(ppc));
+		goto error;
+	}
+
+	pr_info("ethernet pinctrl select state successfully\n");
+
+	putl((getl(PAD_DRV0) & 0xffff3fff) | 0x8000, PAD_DRV0);
+	printk(KERN_INFO "PAD_DRV0:0x%x\n", act_readl(PAD_DRV0));
+
+	
+	return ret;
+
+error:
+	ret = (int)PTR_ERR(ppc);
+	ppc = NULL;
+	return ret;
+
+}
+
+static void ethernet_put_pin_mux(void)
+{
+	if (ppc)
+		pinctrl_put(ppc);
+}
+
+static int ethernet_phy_probe(struct platform_device *pdev)
+{
+	struct device_node *phy_node = pdev->dev.of_node;
+	struct net_device *dev = g_eth_dev[0];
+	struct resource *res;
+	ec_priv_t *ecp = netdev_priv(dev);
+	const char *str;
+	printk(KERN_INFO " %s  %d\n", __FUNCTION__,__LINE__);
+	str = of_get_property(phy_node, "compatible", NULL);
+	printk(KERN_INFO "ethernet phy's compatible: %s\n", str);
+
+	/* The standard phy that register accessed via MDIO only support ksz8841tl now */
+	if (of_device_is_compatible(phy_node, "realk,rtl8201")) {
+		ecp->phy_model = ETH_PHY_MODEL_RTL8201;
+		printk(KERN_INFO "phy model is rtl8201\n");
+	} else if (of_device_is_compatible(phy_node, "SR8201G,sr8201g")) {
+		ecp->phy_model = ETH_PHY_MODEL_SR8201G;
+		printk(KERN_INFO "phy model is sr8201g\n");
+	} { /* ATC2605 or error */
+		printk(KERN_INFO "compatible of %s: %s\n", phy_node->full_name, str);
+	}
+
+	printk(KERN_INFO "phy_node->full_name: %s\n", phy_node->full_name);
+
+#ifndef PHY_USE_POLL
+	        dev->irq = irq_of_parse_and_map(phy_node, 0);
+			printk(KERN_INFO "dev->irq=%d\n",dev->irq);
+    	if (dev->irq < 0) {
+            printk(KERN_INFO "No IRQ resource for tp\n");
+    		return -ENODEV;
+    	}
+#endif
+
+	#if 0
+	if (ecp->phy_model == ETH_PHY_MODEL_ATC2605)
+		ecp->atc260x = dev_get_drvdata(pdev->dev.parent);
+	else
+		ecp->atc260x = NULL;
+     #endif//0
+	/*res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+	if (!res) {
+		printk(KERN_INFO "phy %s has no irq resource\n", phy_node->full_name);
+		return -EINVAL;
+	}
+	/dev->irq = res->start;
+	printk(KERN_INFO "phy irq is %u\n", dev->irq);
+*/
+	return 0;
+}
+
+static int __exit ethernet_phy_remove(struct platform_device *pdev)
+{
+	return 0;
+}
+
+/* ethernet phy match table */
+static const struct of_device_id ethernet_phy_of_match[] __initconst = {
+	{ .compatible = "SR8201G,sr8201g", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, ethernet_phy_of_match);
+
+static struct platform_driver ethernet_phy_driver = {
+    .probe      = ethernet_phy_probe,
+    .remove     = __exit_p(ethernet_phy_remove),
+    .driver     = {
+        .name   = "rtl8201",
+        .owner  = THIS_MODULE,
+	.of_match_table = ethernet_phy_of_match,
+    },
+};
+
+static int __init asoc_ethernet_probe(struct platform_device *pdev)
+{
+	struct net_device *dev;
+	ec_priv_t *ecp;
+	int ret;
+	struct resource *res;
+	int phy_mode = ETH_PHY_MODE_RMII; /* use rmii as default */
+	const char *phy_mode_str,*phy_status_str;
+	struct device_node *phy_node;
+	const char *str;
+
+	if (!get_def_mac_addr(pdev))
+		printk(KERN_INFO "use same default mac\n");
+
+	ret = ethernet_set_pin_mux(pdev);
+	if (ret)
+		return ret;
+
+	ret = of_property_read_string(pdev->dev.of_node, "status", &phy_status_str);
+	if (ret == 0 && strcmp(phy_status_str, "okay") != 0) {
+		dev_info(&pdev->dev, "disabled by DTS\n");
+		return -ENODEV;
+	}
+	
+	ret = of_property_read_string(pdev->dev.of_node, "phy-mode", &phy_mode_str);
+	if (ret) {
+		/* if get phy mode failed, use default rmii */
+		printk(KERN_INFO "get phy mode failed, use rmii\n");
+	} else {
+		printk(KERN_INFO "phy_mode_str: %s\n", phy_mode_str);
+		if (!strcmp(phy_mode_str, "rmii"))
+			phy_mode = ETH_PHY_MODE_RMII;
+		else if (!strcmp(phy_mode_str, "smii"))
+			phy_mode = ETH_PHY_MODE_SMII;
+		else
+			printk(KERN_INFO "unknown phy mode: %s, use rmii\n", phy_mode_str);
+	}
+
+	ret = ethernet_clock_config(phy_mode);
+	 putl(getl(CMU_ETHERNETPLL) | (0x1<<1), CMU_ETHERNETPLL);
+	if (ret) {
+		ethernet_put_pin_mux();
+		return ret;
+	}
+
+	printk(KERN_INFO "pdev->name: %s\n", pdev->name ? pdev->name : "<null>");
+	dev = alloc_etherdev(sizeof(struct dev_priv));
+	SET_NETDEV_DEV(dev,&pdev->dev);
+	if (NULL == dev)
+		return -ENOMEM;
+	sprintf(dev->name, "eth%d", 0);
+	ecp = netdev_priv(dev);
+	g_eth_dev[0] = dev;
+	ecp->last_link_status=false;
+	ecp->rx_timeout=false;
+	ecp->phy_mode = phy_mode;
+	ecp->phy_addr=0xff;
+	printk(KERN_INFO "phy_mode: %u\n", ecp->phy_mode);
+
+	phy_node = of_parse_phandle(pdev->dev.of_node, "phy-handle", 0);
+	if (!phy_node) {
+		printk(KERN_INFO "phy-handle of ethernet node can't be parsed\n");
+		return -EINVAL;
+	}
+
+	ecp->phy_model = ETH_PHY_MODEL_SR8201G; /* default ATC2605 phy */
+
+  if (of_property_read_u32(pdev->dev.of_node, "phy_addr", &ecp->phy_addr)) {
+		printk(KERN_INFO "can't get phy addr form DTS \n");      
+  }
+    
+	ret=ethernet_parse_gpio(pdev->dev.of_node, "phy-power-gpios",&ecp->phy_power_gpio);
+	if(ret<0){
+		printk(KERN_INFO " %s  can't get phy power gpio\n", __FUNCTION__);
+	}
+		
+	ret=ethernet_parse_gpio(pdev->dev.of_node, "phy-reset-gpios",&ecp->phy_reset_gpio);
+
+      if (gpio_is_valid(ecp->phy_power_gpio.gpio)) {       
+	  	gpio_request(ecp->phy_power_gpio.gpio, "phy_power_gpio");        
+	}  
+	if (gpio_is_valid(ecp->phy_reset_gpio.gpio)) {     
+		 gpio_request(ecp->phy_reset_gpio.gpio, "phy_reset_gpio");       
+	} 
+	
+	str = of_get_property(phy_node, "compatible", NULL);
+	if (of_device_is_compatible(phy_node, "actions,atc260x-ethernet")) {
+		ecp->phy_model = ETH_PHY_MODEL_ATC2605;
+		printk(KERN_INFO "phy model is ATC2605\n");
+		/* platform device atc260x-ethernet's been created by atc260x_dev.c */
+	} else {
+		/* all other standard phy that register accessed via MDIO are
+		 * recognized by ethernet_phy_probe() 
+		struct platform_device *phy_pdev;
+		const char *name = strstr(str, ",");
+		phy_pdev = of_platform_device_create(phy_node, ++name, &pdev->dev);
+		printk(KERN_INFO "ethernet phy name: %s\n", name);
+		if (!phy_pdev) {
+			printk(KERN_INFO "of_platform_device_create(%s) failed\n", name);
+			goto err_free;
+		}*/
+	}
+	
+	e_clk = clk_get(NULL, CLKNAME_CMUMOD_ETHERNET);
+
+	ret = clk_prepare(e_clk);
+	if (ret)
+		printk(KERN_INFO "prepare ethernet clock failed, errno: %d\n", -ret);
+		
+	ret = platform_driver_register(&ethernet_phy_driver);
+	if (ret) {
+		printk(KERN_INFO "register ethernet phy driver failed\n");
+		goto err_free;
+	}
+	printk(KERN_INFO "phy_model: %u\n", ecp->phy_model);
+
+	ret = -EINVAL;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		printk(KERN_INFO "no mem resource\n");
+		goto err_free;
+	}
+	ecp->hwrp = (volatile ethregs_t *)IO_ADDRESS(res->start);
+	printk(KERN_INFO "res->start: %p, ecp->hwrp: %p\n",
+			(void *)res->start, (void *)ecp->hwrp);
+
+	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+	if (!res) {
+		printk(KERN_INFO "no irq resource\n");
+		goto err_free;
+	}
+	ecp->mac_irq = res->start;
+
+	printk(KERN_INFO "ecp->mac_irq: %u, dev->irq: %u\n", ecp->mac_irq, dev->irq);
+#if 0
+	ecp->hwrp = (volatile ethregs_t *)IO_ADDRESS(ETHERNET_BASE);
+	ecp->mac_irq = OWL_IRQ_ETHERNET;
+	dev->irq = ASOC_ETHERNET_PHY_IRQ;
+#endif
+	//dev->irq = ASOC_ETHERNET_PHY_IRQ;
+	if (ETH_PHY_MODE_SMII == phy_mode)
+		ecp->hwrp->er_macctrl = MAC_CTRL_SMII; /* use smii interface */
+	else
+		ecp->hwrp->er_macctrl = MAC_CTRL_RMII; /* use rmii interface */
+
+	dev->watchdog_timeo = EC_TX_TIMEOUT;
+	dev->netdev_ops = &ec_netdev_ops;
+	ec_set_ethtool_ops(dev);
+	ep_set_phy_ops(ecp);
+
+	ret = register_netdev(dev);
+	if (ret < 0) {
+		printk(KERN_INFO "register netdev ret:%d, [irq:%d, dev name:%s]\n",
+				ret, dev->irq, dev->name ? dev->name : "Unknown");
+		g_eth_dev[0] = NULL;
+		goto err_free;
+	}
+	device_create_file(&dev->dev, &dev_attr_netif_msg);
+#ifdef ETH_TEST_MODE
+	device_create_file(&dev->dev, &dev_attr_continuity);
+	device_create_file(&dev->dev, &dev_attr_send_pattern);
+	device_create_file(&dev->dev, &dev_attr_test_mode);
+#endif
+	resume_queue = create_workqueue("kethernet_resume_work");
+	if (!resume_queue) {
+		printk(KERN_INFO "create workqueue kethernet_resume_work failed\n");
+		ret = -ENOMEM;
+		goto err_remove;
+	}
+
+	INIT_DELAYED_WORK(&resume_work, ethernet_resume_handler);
+
+#ifdef DETECT_POWER_SAVE
+	power_save_queue = create_workqueue("kethernet_power_save_work");
+	if (!power_save_queue) {
+		ret = -ENOMEM;
+		destroy_workqueue(resume_queue);
+		goto err_remove;
+	}
+	INIT_WORK(&ecp->power_save_work, ethernet_power_save);
+#endif
+#ifdef PHY_USE_POLL
+	phy_detect_queue = create_workqueue("phy_detect_work");
+	if (!phy_detect_queue) {
+		ret = -ENOMEM;
+		goto err_remove;
+	}
+	INIT_DELAYED_WORK(&ecp->phy_detect_work, phy_detect_func);
+#endif
+	INIT_WORK(&ecp->hardware_reset_work,hardware_reset_do_work);
+	return 0;
+
+err_remove:
+	device_remove_file(&dev->dev, &dev_attr_netif_msg);
+#ifdef ETH_TEST_MODE
+	device_remove_file(&dev->dev, &dev_attr_send_pattern);
+	device_remove_file(&dev->dev, &dev_attr_test_mode);
+	device_remove_file(&dev->dev, &dev_attr_continuity);
+#endif
+	unregister_netdev(dev);
+
+err_free:
+	if (dev) {
+		free_netdev(dev);
+		dev = NULL;
+	}
+	return ret;
+}
+
+static int __exit asoc_ethernet_remove(struct platform_device *pdev)
+{
+	struct net_device *dev = g_eth_dev[0];
+  ec_priv_t *ecp = netdev_priv(dev);
+#ifdef PHY_USE_POLL
+    if(phy_detect_queue!=NULL){     	
+      cancel_delayed_work_sync(&ecp->phy_detect_work);   
+	  	destroy_workqueue(phy_detect_queue);
+	  	phy_detect_queue=NULL;
+	  }
+#endif	
+	if (dev) {
+		device_remove_file(&dev->dev, &dev_attr_netif_msg);
+#ifdef ETH_TEST_MODE
+		device_remove_file(&dev->dev, &dev_attr_send_pattern);
+		device_remove_file(&dev->dev, &dev_attr_test_mode);
+		device_remove_file(&dev->dev, &dev_attr_continuity);
+#endif
+		unregister_netdev(dev);
+		free_netdev(dev);
+	}
+	if (resume_queue)
+		destroy_workqueue(resume_queue);
+
+#ifdef DETECT_POWER_SAVE
+	destroy_workqueue(power_save_queue);
+#endif
+
+	platform_driver_unregister(&ethernet_phy_driver);
+	if(e_clk!=NULL){
+  clk_disable(e_clk);
+		clk_unprepare(e_clk);  	
+  clk_put(e_clk);
+  }
+
+	
+	ethernet_put_pin_mux();
+	return 0;
+}
+
+
+/* Match table for of_platform binding */
+static const struct of_device_id actions_ethernet_of_match[] __initconst = {
+	{ .compatible = "actions,owl-ethernet", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, actions_ethernet_of_match);
+
+static struct platform_driver asoc_ethernet_driver = {
+    .probe      = asoc_ethernet_probe,
+    .remove     = __exit_p(asoc_ethernet_remove),
+    .driver     = {
+        .name   = "owl-ethernet",
+        .owner  = THIS_MODULE,
+	.of_match_table = actions_ethernet_of_match,
+    },
+    .suspend     = asoc_ethernet_suspend,
+    .resume     = asoc_ethernet_resume,
+};
+
+static int __init asoc_ethernet_init(void)
+{
+	printk(KERN_INFO "%s %d\n",__FUNCTION__,__LINE__);
+    return platform_driver_register(&asoc_ethernet_driver);
+}
+module_init(asoc_ethernet_init);
+
+static void __exit asoc_ethernet_exit(void)
+{
+    platform_driver_unregister(&asoc_ethernet_driver);
+}
+module_exit(asoc_ethernet_exit);
+
+MODULE_ALIAS("platform:asoc-ethernet");
+MODULE_DESCRIPTION("asoc_ethernet pin");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Actions Semi, Inc");
+
+
+
diff --git a/drivers/net/ethernet/sg8201g/ethctrl.h b/drivers/net/ethernet/sg8201g/ethctrl.h
new file mode 100755
index 0000000..6d0444c
--- /dev/null
+++ b/drivers/net/ethernet/sg8201g/ethctrl.h
@@ -0,0 +1,240 @@
+/******************************************************************************
+ ethctrl.h -- ethernet controller header for GL5201
+ 
+ author : yunchf  @Actions 
+ date : 2010-04-08 
+ version 0.1
+
+ date : 2010-08-10
+ version 1.0
+ 
+******************************************************************************/
+#ifndef _ETHCTRL_H_
+#define _ETHCTRL_H_
+
+/*****************************************************************************/
+
+//#define DETECT_POWER_SAVE
+
+#include <linux/spinlock.h>
+#include <linux/mii.h>
+#include <linux/ethtool.h>
+#include <linux/netdevice.h>
+//#include <mach/atc260x.h>
+#include "ec_hardware.h"
+
+#ifdef DETECT_POWER_SAVE
+#include <linux/timer.h>
+#endif
+
+//#define ETH_TEST_MODE
+
+#define MULTICAST_LIST_LEN 14
+#define ETH_MAC_LEN 6
+#define ETH_CRC_LEN 4
+#define RX_RING_SIZE 64
+
+#define RX_RING_MOD_MASK  (RX_RING_SIZE - 1)
+#ifndef ETH_TEST_MODE
+#define TX_RING_SIZE 32
+#else
+#define TX_RING_SIZE 128
+#endif
+
+#define TX_RING_MOD_MASK (TX_RING_SIZE - 1)
+#define TATOL_TXRX_BDS (RX_RING_SIZE + TX_RING_SIZE)
+
+
+#define ETH_SPEED_10M 10
+#define ETH_SPEED_100M 100
+#define ETH_DUP_HALF 1
+#define ETH_DUP_FULL 2
+#define ETH_PKG_MIN 64
+#define ETH_PKG_MAX 1518
+#define PKG_RESERVE 18
+
+#define PKG_MIN_LEN (ETH_PKG_MIN)
+
+/* 0x600, reserve 18 byes for align adjustment */
+#define PKG_MAX_LEN (ETH_PKG_MAX + PKG_RESERVE)
+
+#define PHY_ADDR_LIMIT 0x20
+
+#define PHY_USE_POLL	/*phy\C2\D6ѯ\B7\BDʽ\BC\EC\B2⣬\B7\F1\D4\F2\B2\C9\D3\C3\D6жϷ\BDʽ*/
+
+/* ANSI Color codes */
+#define VT(CODES)  "\033[" CODES "m"
+#define VT_NORMAL  VT("")
+#define VT_RED	   VT("0;32;31")
+#define VT_GREEN   VT("1;32")
+#define VT_YELLOW  VT("1;33")
+#define VT_BLUE    VT("1;34")
+#define VT_PURPLE  VT("0;35")
+
+#define EC_TRACED 0
+#define EC_DEBUG
+#undef RX_DEBUG
+#undef TX_DEBUG
+//#define RX_DEBUG
+//#define TX_DEBUG
+
+//#define ETHENRET_MAC_LOOP_BACK
+//#define ETHENRET_PHY_LOOP_BACK
+//#define WORK_IN_10M_MODE
+
+#define _DBG(level, fmt, ...)  \
+    printk(level "%s():%d: " fmt, \
+        __func__, __LINE__, ## __VA_ARGS__)
+
+#ifdef EC_DEBUG
+#define printk(fmt, args...)  _DBG(KERN_INFO, fmt, ## args)
+#else
+#define printk(fmt, args...)  do {} while(0)
+#endif
+
+#define printk(fmt, args...)   _DBG(KERN_ERR, fmt, ## args)
+
+#define _INFO(color, fmt, ...) \
+    printk(color "" fmt ""VT_NORMAL, ## __VA_ARGS__)
+
+/* mainly used in test code */
+#define INFO_PURLPLE(fmt, args...) _INFO(VT_PURPLE, fmt, ## args)
+#define INFO_RED(fmt, args...)     _INFO(VT_RED, fmt, ## args)
+#define INFO_GREEN(fmt, args...)   _INFO(VT_GREEN, fmt, ## args)
+#define INFO_BLUE(fmt, args...)    _INFO(VT_BLUE, fmt, ## args)
+
+//#define EC_NOP __asm__ __volatile__ ("nop; nop; nop; nop" : :)
+#define EC_NOP
+
+enum eth_phy_model {
+	ETH_PHY_MODEL_ATC2605 = 0, /* same as fdp110 */
+	ETH_PHY_MODEL_KSZ8041TL, /* Micrel KSZ8041TL */
+	ETH_PHY_MODEL_RTL8201, /* Micrel KSZ8041TL */
+	ETH_PHY_MODEL_SR8201G, /* Micrel KSZ8041TL */
+	ETH_PHY_MODEL_MAX,
+};
+
+enum eth_phy_mode {
+	ETH_PHY_MODE_RMII = 0,
+	ETH_PHY_MODE_SMII,
+	ETH_PHY_MODE_MAX,
+};
+
+typedef struct mac_list {
+    int     count;
+    char    mac_array[MULTICAST_LIST_LEN][ETH_MAC_LEN];
+} mac_list_t;
+
+struct owl_ethernet_gpio {
+    int gpio;
+    int active;
+};
+
+typedef struct phy_info phy_info_t;
+
+typedef struct dev_priv {
+    volatile ethregs_t *hwrp;
+    spinlock_t lock;
+    struct net_device *netdev;
+    struct atc260x_dev *atc260x;
+    unsigned int mac_irq;
+    unsigned int phy_model;
+    unsigned int phy_mode;
+#ifdef ETH_TEST_MODE
+    unsigned int test_mode;
+#endif
+
+    struct sk_buff *tx_skb[TX_RING_SIZE];       /* temp. save transmited skb */
+    ec_bd_t *tx_bd_base;
+    ec_bd_t *cur_tx;            /* the next tx free ring entry */
+    ec_bd_t *dirty_tx;          /* the ring entry to be freed */
+    ushort  skb_dirty;          /* = dirty_tx - tx_bd_base */
+    ushort  skb_cur;            /* = cur_tx - tx_bd_base */
+    dma_addr_t tx_bd_paddr;
+    bool    tx_full;
+
+    struct sk_buff *rx_skb[RX_RING_SIZE];       /* rx_bd buffers */
+    ec_bd_t *rx_bd_base;
+    ec_bd_t *cur_rx;            /* the next rx free ring entry */
+    dma_addr_t	rx_bd_paddr;
+
+#if 0
+    struct workqueue_struct *tx_wq;
+    struct work_struct tx_work;
+    struct work_struct tx_timeout_work;
+    struct sk_buff_head local_tx_queue;
+
+    struct workqueue_struct *rx_wq;
+    struct work_struct rx_work;
+#endif
+
+#ifdef DETECT_POWER_SAVE
+    struct timer_list detect_timer;
+    struct work_struct power_save_work;
+#endif
+	struct work_struct hardware_reset_work;
+#ifdef PHY_USE_POLL
+	struct delayed_work phy_detect_work;
+#endif
+    //int phy_id;
+    int     phy_addr;
+    int     speed;
+    int     duplex;
+    bool    pause;
+    bool    autoneg;
+    phy_info_t *phy_ops;
+    struct mii_if_info mii_info;
+
+    int     msg_enable;
+    const char *mac_addr;       /* XXX : careful later added */
+    char    overrided_mac[ETH_MAC_LEN];
+    mac_list_t multicast_list;
+    bool    mac_overrided;
+    bool    multicast;
+    bool    all_multicast;
+    bool    promiscuous;
+    bool    opened;
+    bool    linked;
+    bool    last_link_status;	
+    bool    rx_timeout;
+#ifdef DETECT_POWER_SAVE
+    bool    enable;             // hardware enabled
+#endif
+   struct owl_ethernet_gpio phy_power_gpio;
+   struct owl_ethernet_gpio phy_reset_gpio;
+
+} ec_priv_t;
+
+
+struct phy_info {
+    int     id;
+    char   *name;
+    int     (*phy_hw_init) (ec_priv_t * ecp);
+    int     (*phy_init) (ec_priv_t * ecp);
+    int     (*phy_suspend) (ec_priv_t * ecp, bool power_down);
+    int     (*phy_setup_advert) (ec_priv_t * ecp, int advertising);
+    int     (*phy_setup_forced) (ec_priv_t * ecp, int speed, int duplex);
+    int     (*phy_setup_aneg) (ec_priv_t * ecp, bool autoneg);
+    int     (*phy_setup_loopback) (ec_priv_t * ecp, bool loopback);
+    int     (*phy_read_status) (ec_priv_t * ecp);
+    int     (*phy_get_link) (ec_priv_t * ecp);
+};
+
+
+extern unsigned short (*read_phy_reg)(ec_priv_t *, unsigned short);
+extern int (*write_phy_reg)(ec_priv_t *, unsigned short, unsigned short);
+
+void ep_set_phy_ops(ec_priv_t * ecp);
+void ec_set_ethtool_ops(struct net_device *netdev);
+
+
+static inline bool need_change_speed(unsigned short new_bmcr, unsigned short old_bmcr)
+{
+    return (((new_bmcr ^ old_bmcr) & (BMCR_SPEED100 | BMCR_FULLDPLX)) == BMCR_FULLDPLX);
+}
+
+
+
+/******************************************************************************/
+
+#endif                          /* _ETHCTRL_H_ */
-- 
2.7.4



More information about the linux-yocto mailing list