[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(ðernet_phy_driver);
+}
+
+static void __exit asoc_phy_driver_exit(void)
+{
+ platform_driver_unregister(ðernet_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(ðernet_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(ðernet_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(ðernet_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