add preliminary support for Storm SL3512 based devices, not ready yet
authorImre Kaloz <kaloz@openwrt.org>
Sun, 27 Apr 2008 17:03:01 +0000 (17:03 +0000)
committerImre Kaloz <kaloz@openwrt.org>
Sun, 27 Apr 2008 17:03:01 +0000 (17:03 +0000)
SVN-Revision: 10956

15 files changed:
package/madwifi/Makefile
target/linux/storm/Makefile [new file with mode: 0644]
target/linux/storm/config-default [new file with mode: 0644]
target/linux/storm/image/Makefile [new file with mode: 0644]
target/linux/storm/patches/1001-arch.patch [new file with mode: 0644]
target/linux/storm/patches/1002-gmac.patch [new file with mode: 0644]
target/linux/storm/patches/1003-gmac_one_phy.patch [new file with mode: 0644]
target/linux/storm/patches/1004-gmac-enable-napi.patch [new file with mode: 0644]
target/linux/storm/patches/1005-gmac-napi-mask-intrs.patch [new file with mode: 0644]
target/linux/storm/patches/1006-gmac-napi-tx.patch [new file with mode: 0644]
target/linux/storm/patches/1020-mtd.patch [new file with mode: 0644]
target/linux/storm/patches/1021-serial.patch [new file with mode: 0644]
target/linux/storm/patches/1100-gpio.patch [new file with mode: 0644]
toolchain/Config.in
toolchain/uClibc/config/arm.storm [new file with mode: 0644]

index d502e33f5946b5b4aabda591c40583c32aff17ab..697f2b68a53a134a5f28d45db5c08a59b6638d39 100644 (file)
@@ -48,6 +48,9 @@ endif
 ifeq ($(ARCH),powerpc)
   HAL_TARGET:=powerpc-be-elf
 endif
 ifeq ($(ARCH),powerpc)
   HAL_TARGET:=powerpc-be-elf
 endif
+ifeq ($(BOARD),storm)
+  HAL_TARGET:=armv4-le-elf
+endif
 
 ifneq ($(CONFIG_TARGET_atheros),)
   BUS:=AHB
 
 ifneq ($(CONFIG_TARGET_atheros),)
   BUS:=AHB
diff --git a/target/linux/storm/Makefile b/target/linux/storm/Makefile
new file mode 100644 (file)
index 0000000..c0d0023
--- /dev/null
@@ -0,0 +1,28 @@
+#
+# Copyright (C) 2006-2008 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+include $(TOPDIR)/rules.mk
+
+ARCH:=arm
+BOARD:=storm
+BOARDNAME:=Storm SL3512
+FEATURES:=squashfs pci broken
+
+LINUX_VERSION:=2.6.23.16
+
+include $(INCLUDE_DIR)/target.mk
+
+define Target/Description
+       Build images for boards based on the Storm Semiconductor SL3512, eg. Wiligear WBD-111
+endef
+
+define Kernel/Configure
+       $(call Kernel/Configure/Default)
+       $(SED) 's,.*CONFIG_AEABI.*,$(if $(CONFIG_EABI_SUPPORT),CONFIG_AEABI=y,# CONFIG_AEABI is not set),' $(LINUX_DIR)/.config
+       $(if $(CONFIG_EABI_SUPPORT),echo '# CONFIG_OABI_COMPAT is not set' >> $(LINUX_DIR)/.config)
+endef
+
+$(eval $(call BuildTarget))
diff --git a/target/linux/storm/config-default b/target/linux/storm/config-default
new file mode 100644 (file)
index 0000000..043d5fe
--- /dev/null
@@ -0,0 +1,358 @@
+# CONFIG_AEABI is not set
+CONFIG_ALIGNMENT_TRAP=y
+# CONFIG_ARCH_AAEC2000 is not set
+# CONFIG_ARCH_AT91 is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_CLPS7500 is not set
+# CONFIG_ARCH_CO285 is not set
+# CONFIG_ARCH_DAVINCI is not set
+# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_EP93XX is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_H720X is not set
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+# CONFIG_ARCH_IMX is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_IOP13XX is not set
+# CONFIG_ARCH_IOP32X is not set
+# CONFIG_ARCH_IOP33X is not set
+# CONFIG_ARCH_IXP2000 is not set
+# CONFIG_ARCH_IXP23XX is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_KS8695 is not set
+# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_LH7A40X is not set
+# CONFIG_ARCH_MXC is not set
+# CONFIG_ARCH_NETX is not set
+# CONFIG_ARCH_NS9XXX is not set
+# CONFIG_ARCH_OMAP is not set
+# CONFIG_ARCH_PNX4008 is not set
+# CONFIG_ARCH_PXA is not set
+# CONFIG_ARCH_REALVIEW is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_SHARK is not set
+CONFIG_ARCH_SL2312=y
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+# CONFIG_ARCH_VERSATILE is not set
+CONFIG_ARM=y
+# CONFIG_ARPD is not set
+# CONFIG_ARTHUR is not set
+# CONFIG_ATM is not set
+CONFIG_BASE_SMALL=0
+# CONFIG_BINFMT_AOUT is not set
+CONFIG_BITREVERSE=y
+# CONFIG_BLK_DEV is not set
+# CONFIG_BLK_DEV_INITRD is not set
+# CONFIG_BONDING is not set
+CONFIG_BOUNCE=y
+CONFIG_BRIDGE=m
+CONFIG_BRIDGE_NETFILTER=y
+# CONFIG_BRIDGE_NF_EBTABLES is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_BT is not set
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+# CONFIG_CIFS is not set
+# CONFIG_CLS_U32_PERF is not set
+CONFIG_CMDLINE="root=/dev/mtdblock2 rootfstype=squashfs,jffs2 noinitrd console=ttySL0,19200 init=/etc/preinit mem=32M loglevel=8"
+# CONFIG_CONFIGFS_FS is not set
+CONFIG_CPU_32=y
+CONFIG_CPU_32v4=y
+CONFIG_CPU_ABRT_EV4=y
+CONFIG_CPU_CACHE_FA=y
+CONFIG_CPU_CACHE_VIVT=y
+CONFIG_CPU_COPY_FA=y
+CONFIG_CPU_CP15=y
+CONFIG_CPU_CP15_MMU=y
+# CONFIG_CPU_DCACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_WRITETHROUGH is not set
+CONFIG_CPU_FA526=y
+CONFIG_CPU_FA_BTB=y
+# CONFIG_CPU_ICACHE_DISABLE is not set
+CONFIG_CPU_TLB_FA=y
+# CONFIG_CRC_ITU_T is not set
+# CONFIG_CRYPTO is not set
+CONFIG_DEBUG_BUGVERBOSE=y
+# CONFIG_DEBUG_DEVRES is not set
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_DEBUG_ERRORS is not set
+# CONFIG_DEBUG_INFO is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_KOBJECT is not set
+# CONFIG_DEBUG_LIST is not set
+# CONFIG_DEBUG_LL is not set
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+# CONFIG_DEBUG_LOCK_ALLOC is not set
+# CONFIG_DEBUG_MUTEXES is not set
+# CONFIG_DEBUG_SHIRQ is not set
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_USER is not set
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEFAULT_DEADLINE is not set
+CONFIG_DEFAULT_IOSCHED="noop"
+CONFIG_DEFAULT_NOOP=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_DETECT_SOFTLOCKUP is not set
+CONFIG_DEVPORT=y
+# CONFIG_DM9000 is not set
+CONFIG_ELF_CORE=y
+CONFIG_ENABLE_MUST_CHECK=y
+# CONFIG_EPOLL is not set
+# CONFIG_EXT2_FS is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_FAULT_INJECTION is not set
+CONFIG_FORCED_INLINING=y
+# CONFIG_FPE_FASTFPE is not set
+# CONFIG_FPE_NWFPE is not set
+CONFIG_FRAME_POINTER=y
+# CONFIG_FUTEX is not set
+# CONFIG_FW_LOADER is not set
+CONFIG_GEMINI_GPIO_DEV=y
+# CONFIG_GEMINI_IPI is not set
+# CONFIG_GENERIC_CLOCKEVENTS is not set
+# CONFIG_GENERIC_GPIO is not set
+# CONFIG_GENERIC_TIME is not set
+# CONFIG_HAMRADIO is not set
+CONFIG_HARDIRQS_SW_RESEND=y
+CONFIG_HAS_DMA=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_HFS_FS is not set
+CONFIG_HW_RANDOM=y
+# CONFIG_I2C is not set
+# CONFIG_IDE is not set
+# CONFIG_IEEE80211 is not set
+# CONFIG_IFB is not set
+# CONFIG_IKCONFIG is not set
+# CONFIG_IMQ is not set
+# CONFIG_INET6_TUNNEL is not set
+# CONFIG_INET6_XFRM_TUNNEL is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_DIAG is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_INET_XFRM_MODE_BEET=y
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_IOSCHED_DEADLINE is not set
+# CONFIG_IPSEC_NAT_TRAVERSAL is not set
+# CONFIG_IPV6 is not set
+CONFIG_IP_MROUTE=y
+# CONFIG_IP_NF_ARPTABLES is not set
+CONFIG_IP_NF_FILTER=m
+CONFIG_IP_NF_IPTABLES=m
+CONFIG_IP_NF_MANGLE=m
+# CONFIG_IP_NF_MATCH_AH is not set
+# CONFIG_IP_NF_MATCH_ECN is not set
+# CONFIG_IP_NF_MATCH_IPP2P is not set
+# CONFIG_IP_NF_MATCH_OWNER is not set
+# CONFIG_IP_NF_MATCH_RECENT is not set
+# CONFIG_IP_NF_MATCH_TIME is not set
+# CONFIG_IP_NF_MATCH_TOS is not set
+# CONFIG_IP_NF_MATCH_TTL is not set
+# CONFIG_IP_NF_QUEUE is not set
+# CONFIG_IP_NF_SET is not set
+# CONFIG_IP_NF_TARGET_ECN is not set
+# CONFIG_IP_NF_TARGET_IMQ is not set
+# CONFIG_IP_NF_TARGET_LOG is not set
+# CONFIG_IP_NF_TARGET_REJECT is not set
+# CONFIG_IP_NF_TARGET_ROUTE is not set
+# CONFIG_IP_NF_TARGET_TOS is not set
+# CONFIG_IP_NF_TARGET_TTL is not set
+# CONFIG_IP_NF_TARGET_ULOG is not set
+CONFIG_IP_PIMSM_V1=y
+CONFIG_IP_PIMSM_V2=y
+# CONFIG_ISDN is not set
+# CONFIG_ISO9660_FS is not set
+# CONFIG_JFFS2_RTIME is not set
+# CONFIG_JFFS2_SUMMARY is not set
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+CONFIG_KMOD=y
+CONFIG_LLC=m
+# CONFIG_LLC2 is not set
+# CONFIG_LOCK_STAT is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_MINI_FO is not set
+# CONFIG_MISC_DEVICES is not set
+# CONFIG_MSDOS_FS is not set
+CONFIG_MTD=y
+# CONFIG_MTD_ABSENT is not set
+# CONFIG_MTD_AFS_PARTS is not set
+# CONFIG_MTD_ARM_INTEGRATOR is not set
+CONFIG_MTD_BLKDEVS=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_MTD_BLOCK2MTD is not set
+CONFIG_MTD_CFI=y
+CONFIG_MTD_CFI_ADV_OPTIONS=y
+CONFIG_MTD_CFI_AMDSTD=y
+# CONFIG_MTD_CFI_BE_BYTE_SWAP is not set
+CONFIG_MTD_CFI_GEOMETRY=y
+CONFIG_MTD_CFI_I1=y
+# CONFIG_MTD_CFI_I2 is not set
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+# CONFIG_MTD_CFI_INTELEXT is not set
+# CONFIG_MTD_CFI_LE_BYTE_SWAP is not set
+CONFIG_MTD_CFI_NOSWAP=y
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
+CONFIG_MTD_CHAR=y
+# CONFIG_MTD_CMDLINE_PARTS is not set
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+# CONFIG_MTD_CONCAT is not set
+# CONFIG_MTD_DEBUG is not set
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+CONFIG_MTD_GEN_PROBE=y
+# CONFIG_MTD_JEDECPROBE is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_1 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_4 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_ONENAND is not set
+# CONFIG_MTD_OTP is not set
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_PHYSMAP is not set
+# CONFIG_MTD_PLATRAM is not set
+# CONFIG_MTD_PMC551 is not set
+# CONFIG_MTD_RAM is not set
+CONFIG_MTD_REDBOOT_DIRECTORY_BLOCK=-1
+CONFIG_MTD_REDBOOT_PARTS=y
+# CONFIG_MTD_REDBOOT_PARTS_READONLY is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ROOTFS_ROOT_DEV is not set
+# CONFIG_MTD_ROOTFS_SPLIT is not set
+# CONFIG_MTD_SERIAL is not set
+CONFIG_MTD_SL2312_CFI=y
+# CONFIG_MTD_SL2312_SERIAL_ATMEL is not set
+# CONFIG_MTD_SL2312_SERIAL_ST is not set
+# CONFIG_MTD_SLRAM is not set
+CONFIG_NETFILTER_XTABLES=m
+# CONFIG_NETFILTER_XT_MATCH_DSCP is not set
+# CONFIG_NETFILTER_XT_MATCH_ESP is not set
+# CONFIG_NETFILTER_XT_MATCH_HASHLIMIT is not set
+# CONFIG_NETFILTER_XT_MATCH_LENGTH is not set
+# CONFIG_NETFILTER_XT_MATCH_LIMIT is not set
+# CONFIG_NETFILTER_XT_MATCH_MAC is not set
+# CONFIG_NETFILTER_XT_MATCH_MARK is not set
+# CONFIG_NETFILTER_XT_MATCH_MULTIPORT is not set
+# CONFIG_NETFILTER_XT_MATCH_PHYSDEV is not set
+# CONFIG_NETFILTER_XT_MATCH_PKTTYPE is not set
+# CONFIG_NETFILTER_XT_MATCH_POLICY is not set
+# CONFIG_NETFILTER_XT_MATCH_PORTSCAN is not set
+# CONFIG_NETFILTER_XT_MATCH_STRING is not set
+# CONFIG_NETFILTER_XT_MATCH_TCPMSS is not set
+# CONFIG_NETFILTER_XT_MATCH_U32 is not set
+# CONFIG_NETFILTER_XT_TARGET_CHAOS is not set
+# CONFIG_NETFILTER_XT_TARGET_CLASSIFY is not set
+# CONFIG_NETFILTER_XT_TARGET_DELUDE is not set
+# CONFIG_NETFILTER_XT_TARGET_DSCP is not set
+# CONFIG_NETFILTER_XT_TARGET_MARK is not set
+# CONFIG_NETFILTER_XT_TARGET_NFLOG is not set
+# CONFIG_NETFILTER_XT_TARGET_TARPIT is not set
+# CONFIG_NETFILTER_XT_TARGET_TCPMSS is not set
+# CONFIG_NETFILTER_XT_TARGET_TRACE is not set
+# CONFIG_NET_ACT_GACT is not set
+# CONFIG_NET_ACT_IPT is not set
+# CONFIG_NET_ACT_MIRRED is not set
+# CONFIG_NET_ACT_PEDIT is not set
+# CONFIG_NET_CLS_RSVP is not set
+# CONFIG_NET_CLS_RSVP6 is not set
+# CONFIG_NET_EMATCH is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_KEY is not set
+# CONFIG_NET_PCI is not set
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_NET_SCH_DSMARK is not set
+# CONFIG_NET_SCH_ESFQ is not set
+# CONFIG_NET_SCH_GRED is not set
+# CONFIG_NET_SCH_HFSC is not set
+# CONFIG_NET_SCH_HTB is not set
+# CONFIG_NET_SCH_INGRESS is not set
+# CONFIG_NET_SCH_PRIO is not set
+# CONFIG_NET_SCH_RED is not set
+# CONFIG_NET_SCH_RR is not set
+# CONFIG_NET_SCH_SFQ is not set
+# CONFIG_NET_SCH_TBF is not set
+# CONFIG_NET_SCH_TEQL is not set
+# CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_NEW_LEDS is not set
+# CONFIG_NFSD is not set
+# CONFIG_NFS_FS is not set
+# CONFIG_NF_CONNTRACK is not set
+# CONFIG_NF_CONNTRACK_ENABLED is not set
+# CONFIG_NLS is not set
+# CONFIG_NO_IDLE_HZ is not set
+# CONFIG_NO_IOPORT is not set
+# CONFIG_NVRAM is not set
+# CONFIG_OUTER_CACHE is not set
+CONFIG_PACKET=m
+# CONFIG_PARTITION_ADVANCED is not set
+# CONFIG_PCIPCWATCHDOG is not set
+# CONFIG_PCI_DEBUG is not set
+CONFIG_PCI_SYSCALL=y
+# CONFIG_PPP is not set
+CONFIG_PRINTK_TIME=y
+# CONFIG_PROVE_LOCKING is not set
+# CONFIG_RCU_TORTURE_TEST is not set
+CONFIG_RTC_LIB=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_SCHED_DEBUG is not set
+# CONFIG_SCSI is not set
+# CONFIG_SCSI_DMA is not set
+# CONFIG_SERIAL_8250 is not set
+CONFIG_SERIAL_SL2312=y
+CONFIG_SERIAL_SL2312_CONSOLE=y
+# CONFIG_SHMEM is not set
+# CONFIG_SL2312_LPC is not set
+# CONFIG_SL2312_SHARE_PIN is not set
+# CONFIG_SL2312_USB is not set
+CONFIG_SL3516_ASIC=y
+# CONFIG_SMC91X is not set
+# CONFIG_SOFT_WATCHDOG is not set
+# CONFIG_SOUND is not set
+# CONFIG_SPARSEMEM_STATIC is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4096
+# CONFIG_STANDALONE is not set
+# CONFIG_SWAP is not set
+# CONFIG_SYN_COOKIES is not set
+CONFIG_SYSFS_DEPRECATED=y
+# CONFIG_SYSVIPC is not set
+CONFIG_SYS_SUPPORTS_APM_EMULATION=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+# CONFIG_TICK_ONESHOT is not set
+# CONFIG_TIMER_STATS is not set
+CONFIG_TINY_SHMEM=y
+# CONFIG_TUN is not set
+# CONFIG_UDF_FS is not set
+CONFIG_UID16=y
+# CONFIG_USB_SUPPORT is not set
+# CONFIG_USER_NS is not set
+CONFIG_VECTORS_BASE=0xffff0000
+# CONFIG_VFAT_FS is not set
+# CONFIG_VGASTATE is not set
+# CONFIG_VIDEO_DEV is not set
+CONFIG_VLAN_8021Q=m
+# CONFIG_WLAN_80211 is not set
+# CONFIG_XFRM_USER is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_XIP_KERNEL is not set
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_ZBOOT_ROM_TEXT=0x0
diff --git a/target/linux/storm/image/Makefile b/target/linux/storm/image/Makefile
new file mode 100644 (file)
index 0000000..b061c6d
--- /dev/null
@@ -0,0 +1,41 @@
+# 
+# Copyright (C) 2007 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+include $(TOPDIR)/rules.mk
+include $(INCLUDE_DIR)/image.mk
+
+define Image/Prepare
+       cp $(LINUX_DIR)/arch/arm/boot/zImage $(KDIR)/zImage
+endef
+
+define Image/BuildKernel
+       cp $(KDIR)/zImage $(BIN_DIR)/openwrt-$(BOARD)-zImage
+#
+# XXX - FIXME
+#
+#      BIN_DIR=$(BIN_DIR) $(TOPDIR)/scripts/arm-magic.sh
+endef
+
+define Image/Build
+       $(call Image/Build/$(1),$(1))
+endef
+
+define Image/Build/jffs2-64k
+       dd if=$(KDIR)/root.$(1) of=$(BIN_DIR)/openwrt-$(BOARD)-$(1).img bs=65536 conv=sync
+endef
+
+define Image/Build/jffs2-128k
+       dd if=$(KDIR)/root.$(1) of=$(BIN_DIR)/openwrt-$(BOARD)-$(1).img bs=131072 conv=sync
+       $(call Image/Build/slug,$(1))
+endef
+
+define Image/Build/squashfs
+    $(call prepare_generic_squashfs,$(KDIR)/root.squashfs)
+       dd if=$(KDIR)/root.$(1) of=$(BIN_DIR)/openwrt-$(BOARD)-$(1).img bs=131072 conv=sync
+       $(call Image/Build/slug,$(1))
+endef
+
+$(eval $(call BuildImage))
diff --git a/target/linux/storm/patches/1001-arch.patch b/target/linux/storm/patches/1001-arch.patch
new file mode 100644 (file)
index 0000000..8fb9d21
--- /dev/null
@@ -0,0 +1,9010 @@
+Index: linux-2.6.23.16/arch/arm/Kconfig
+===================================================================
+--- linux-2.6.23.16.orig/arch/arm/Kconfig      2008-03-13 17:46:04.000791190 +0200
++++ linux-2.6.23.16/arch/arm/Kconfig   2008-03-13 17:48:24.508798285 +0200
+@@ -220,6 +220,9 @@
+       help
+         This enables support for the Cirrus EP93xx series of CPUs.
++config ARCH_SL2312
++    bool "SL2312"
++
+ config ARCH_FOOTBRIDGE
+       bool "FootBridge"
+       select FOOTBRIDGE
+@@ -414,6 +417,8 @@
+ source "arch/arm/mach-footbridge/Kconfig"
++source "arch/arm/mach-sl2312/Kconfig"
++
+ source "arch/arm/mach-integrator/Kconfig"
+ source "arch/arm/mach-iop32x/Kconfig"
+@@ -549,6 +554,16 @@
+ config PCI_SYSCALL
+       def_bool PCI
++config SL2312_LPC
++    bool "LPC Host Support"
++    depends on ARCH_SL2312
++    help
++
++config SL2312_LPC_IT8712
++    bool "IT8712 Support"
++    depends on ARCH_SL2312 && SL2312_LPC
++    help
++
+ # Select the host bridge type
+ config PCI_HOST_VIA82C505
+       bool
+@@ -988,6 +1003,10 @@
+ source "drivers/mtd/Kconfig"
+ endif
++if ARCH_SL2312
++source "drivers/telephony/Kconfig"
++endif
++
+ source "drivers/parport/Kconfig"
+ source "drivers/pnp/Kconfig"
+@@ -997,7 +1016,7 @@
+ if PCMCIA || ARCH_CLPS7500 || ARCH_IOP32X || ARCH_IOP33X || ARCH_IXP4XX \
+       || ARCH_L7200 || ARCH_LH7A40X || ARCH_PXA || ARCH_RPC \
+       || ARCH_S3C2410 || ARCH_SA1100 || ARCH_SHARK || FOOTBRIDGE \
+-      || ARCH_IXP23XX
++      || ARCH_IXP23XX || ARCH_SL2312
+ source "drivers/ide/Kconfig"
+ endif
+Index: linux-2.6.23.16/arch/arm/Makefile
+===================================================================
+--- linux-2.6.23.16.orig/arch/arm/Makefile     2008-03-13 17:46:04.500819685 +0200
++++ linux-2.6.23.16/arch/arm/Makefile  2008-03-13 17:48:24.508798285 +0200
+@@ -72,6 +72,7 @@
+ tune-$(CONFIG_CPU_ARM922T)    :=-mtune=arm9tdmi
+ tune-$(CONFIG_CPU_ARM925T)    :=-mtune=arm9tdmi
+ tune-$(CONFIG_CPU_ARM926T)    :=-mtune=arm9tdmi
++tune-$(CONFIG_CPU_FA52X)    :=-mtune=arm9tdmi
+ tune-$(CONFIG_CPU_SA110)      :=-mtune=strongarm110
+ tune-$(CONFIG_CPU_SA1100)     :=-mtune=strongarm1100
+ tune-$(CONFIG_CPU_XSCALE)     :=$(call cc-option,-mtune=xscale,-mtune=strongarm110) -Wa,-mcpu=xscale
+@@ -111,6 +112,7 @@
+  machine-$(CONFIG_ARCH_PXA)      := pxa
+  machine-$(CONFIG_ARCH_L7200)    := l7200
+  machine-$(CONFIG_ARCH_INTEGRATOR) := integrator
++ machine-$(CONFIG_ARCH_SL2312)     := sl2312
+  textofs-$(CONFIG_ARCH_CLPS711X)   := 0x00028000
+  machine-$(CONFIG_ARCH_CLPS711X)   := clps711x
+  machine-$(CONFIG_ARCH_IOP32X)           := iop32x
+Index: linux-2.6.23.16/arch/arm/boot/compressed/Makefile
+===================================================================
+--- linux-2.6.23.16.orig/arch/arm/boot/compressed/Makefile     2008-03-13 17:46:04.500819685 +0200
++++ linux-2.6.23.16/arch/arm/boot/compressed/Makefile  2008-03-13 17:48:24.508798285 +0200
+@@ -19,6 +19,10 @@
+ OBJS          += head-shark.o ofw-shark.o
+ endif
++ifeq ($(CONFIG_ARCH_SL2312),y)
++OBJS          += head-sl2312.o
++endif
++
+ ifeq ($(CONFIG_ARCH_L7200),y)
+ OBJS          += head-l7200.o
+ endif
+Index: linux-2.6.23.16/arch/arm/boot/compressed/head-sl2312.S
+===================================================================
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.23.16/arch/arm/boot/compressed/head-sl2312.S     2008-03-13 17:48:24.508798285 +0200
+@@ -0,0 +1,6 @@
++#include <asm/mach-types.h>
++#include <asm/arch/sl2312.h>
++
++              .section        ".start", "ax"
++              mov     r7, #MACH_TYPE_SL2312
++
+Index: linux-2.6.23.16/arch/arm/boot/compressed/head.S
+===================================================================
+--- linux-2.6.23.16.orig/arch/arm/boot/compressed/head.S       2008-03-13 17:46:04.500819685 +0200
++++ linux-2.6.23.16/arch/arm/boot/compressed/head.S    2008-03-13 17:48:24.508798285 +0200
+@@ -57,6 +57,17 @@
+               mov     \rb, #0x50000000
+               add     \rb, \rb, #0x4000 * CONFIG_S3C_LOWLEVEL_UART_PORT
+               .endm
++/*****************************************************
++ *      for Storlink SoC
++ *****************************************************/
++#elif defined(CONFIG_ARCH_SL2312)
++              .macro  loadsp, rb
++              mov     \rb, #0x16000000
++              .endm
++              .macro  writeb, rb
++              strb    \rb, [r3, #0]
++              .endm
++/****************************************************/
+ #else
+               .macro  loadsp, rb
+               addruart \rb
+@@ -116,7 +127,28 @@
+               .rept   8
+               mov     r0, r0
+               .endr
+-
++/*****************************************************************************
++ *  for Storlink Soc -- on chip UART
++ *****************************************************************************/
++#ifndef CONFIG_SERIAL_IT8712          // Jason test
++@                mov     r3, #0x22000000
++                mov     r3, #0x42000000
++                mov     r11, #0x80
++                strb    r11, [r3, #0xc]
++                mov     r11, #0x0
++                strb    r11, [r3, #0x4]
++#ifndef CONFIG_SL3516_ASIC
++                mov     r11, #0x9C            /*0x9c->19200 0x4E->38400 0x34->57600 */
++#else
++              mov     r11, #0x9C              /* 0x61 for 30MHz on GeminiA chip*/
++#endif
++                strb    r11, [r3, #0x0]
++                mov     r11, #0x03
++                strb    r11, [r3, #0xc]
++                      mov     r11, #0xFB
++                strb    r11, [r3, #0x18]
++#endif
++/*****************************************************************************/
+               b       1f
+               .word   0x016f2818              @ Magic numbers to help the loader
+               .word   start                   @ absolute load/run zImage address
+@@ -458,6 +490,39 @@
+               mcr     p15, 0, r0, c7, c5, 4   @ ISB
+               mov     pc, r12
++/*****************************************************************************
++ *  for Storlink Soc -- CPU cache
++ *****************************************************************************/
++__fa526_cache_on:
++                mov     r12, lr
++                bl      __setup_mmu
++                mov     r0, #0
++                mcr     p15, 0, r0, c7, c6, 0   @ Invalidate D cache
++                mcr     p15, 0, r0, c7, c5, 0   @ Invalidate I cache
++                mcr     p15, 0, r0, c7, c10, 4  @ drain write buffer
++                mcr     p15, 0, r0, c8, c7, 0   @ flush I,D TLBs
++                mcr     p15, 0, r3, c2, c0, 0   @ load page table pointer
++                mov     r0, #-1
++                mcr     p15, 0, r0, c3, c0, 0   @ load domain access register
++                mrc     p15, 0, r0, c1, c0, 0
++                mov     r0, r0
++                mov     r0, r0
++#ifndef CONFIG_CPU_DCACHE_DISABLE
++        orr     r0, r0, #0x0004                 @ .... .... .... .1..
++#endif
++#ifndef CONFIG_CPU_ICACHE_DISABLE
++        orr     r0, r0, #0x1000                 @ ...1 .... .... ....
++#endif
++
++#ifndef DEBUG
++                orr     r0, r0, #0x0039         @ Write buffer, mmu
++#endif
++                mcr     p15, 0, r0, c1, c0
++                mov     r0, r0
++                mov     r0, r0
++                mov     pc, r12
++/********************************************************************************/
++
+ __arm6_mmu_cache_on:
+               mov     r12, lr
+               bl      __setup_mmu
+@@ -625,6 +690,16 @@
+               @ These match on the architecture ID
++/*****************************************************************************
++ *  for Storlink Soc -- CPU architecture ID
++ *****************************************************************************/
++        .word   0x66015261              @ FA526
++        .word   0xff01fff1
++        b       __fa526_cache_on
++        b       __fa526_cache_off
++        b       __fa526_cache_flush
++/*****************************************************************************/
++
+               .word   0x00020000              @ ARMv4T
+               .word   0x000f0000
+               b       __armv4_mmu_cache_on
+@@ -712,6 +787,23 @@
+               mcr     p15, 0, r0, c8, c7, 0   @ invalidate whole TLB
+               mov     pc, r12
++/*****************************************************************************
++ *  for Storlink Soc -- CPU cache
++ *****************************************************************************/
++__fa526_cache_off:
++        mrc     p15, 0, r0, c1, c0
++        bic     r0, r0, #0x000d
++        mov     r1, #0
++        mcr     p15, 0, r1, c7, c14, 0  @ clean and invalidate D cache
++        mcr     p15, 0, r1, c7, c10, 4  @ drain WB
++        mcr     p15, 0, r0, c1, c0      @ turn MMU and cache off
++        mov     r0, #0
++        mcr     p15, 0, r0, c7, c5, 0   @ invalidate whole cache v4
++        mcr     p15, 0, r0, c8, c7, 0   @ invalidate whole TLB v4
++        mov     pc, lr
++/*****************************************************************************/
++
++
+ __arm6_mmu_cache_off:
+               mov     r0, #0x00000030         @ ARM6 control reg.
+               b       __armv3_mmu_cache_off
+@@ -759,6 +851,17 @@
+               mcr     p15, 0, ip, c7, c10, 4  @ drain WB
+               mov     pc, lr
+               
++/*****************************************************************************
++ *  for Storlink Soc -- CPU cache
++ *****************************************************************************/
++__fa526_cache_flush:
++                mov     r1, #0
++                mcr     p15, 0, r1, c7, c14, 0  @ clean and invalidate D cache
++                mcr     p15, 0, r1, c7, c5, 0   @ flush I cache
++                mcr     p15, 0, r1, c7, c10, 4  @ drain WB
++                mov     pc, lr
++/*****************************************************************************/
++
+ __armv6_mmu_cache_flush:
+               mov     r1, #0
+Index: linux-2.6.23.16/arch/arm/boot/compressed/it8712.h
+===================================================================
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.23.16/arch/arm/boot/compressed/it8712.h  2008-03-13 17:48:24.508798285 +0200
+@@ -0,0 +1,25 @@
++
++#ifndef __IT8712_H__
++#define __IT8712_H__
++
++#include "asm/arch/sl2312.h"
++
++#define IT8712_IO_BASE                        SL2312_LPC_IO_BASE
++//#define IT8712_IO_BASE                      0x27000000
++// Device LDN
++#define LDN_SERIAL1                           0x01
++#define LDN_SERIAL2                           0x02
++#define LDN_PARALLEL                  0x03
++#define LDN_KEYBOARD                  0x05
++#define LDN_MOUSE                             0x06
++#define LDN_GPIO                              0x07
++
++#define IT8712_UART1_PORT             0x3F8
++#define IT8712_UART2_PORT             0x2F8
++
++#define IT8712_GPIO_BASE              0x800   // 0x800-0x804 for GPIO set1-set5
++
++void LPCSetConfig(char LdnNumber, char Index, char data);
++char LPCGetConfig(char LdnNumber, char Index);
++
++#endif
+Index: linux-2.6.23.16/arch/arm/boot/compressed/misc.c
+===================================================================
+--- linux-2.6.23.16.orig/arch/arm/boot/compressed/misc.c       2008-03-13 17:46:04.500819685 +0200
++++ linux-2.6.23.16/arch/arm/boot/compressed/misc.c    2008-03-13 17:48:24.508798285 +0200
+@@ -30,7 +30,7 @@
+ #include <asm/arch/uncompress.h>
+ #ifdef CONFIG_DEBUG_ICEDCC
+-
++#include "it8712.h"
+ #ifdef CONFIG_CPU_V6
+ static void icedcc_putc(int ch)
+@@ -69,6 +69,7 @@
+ #define flush()       do { } while (0)
+ #endif
++#if 0
+ static void putstr(const char *ptr)
+ {
+       char c;
+@@ -81,11 +82,36 @@
+       flush();
+ }
++#endif
+ #endif
+ #define __ptr_t void *
++#ifdef CONFIG_SERIAL_IT8712
++unsigned int it8712_uart_base;
++#define UART_RX         0
++#define UART_TX         0
++#define UART_DLL        0
++#define UART_TRG        0
++#define UART_DLM        1
++#define UART_IER        1
++#define UART_FCTR       1
++#define UART_IIR        2
++#define UART_FCR        2
++#define UART_EFR        2
++#define UART_LCR        3
++#define UART_MCR        4
++#define UART_LSR        5
++#define UART_MSR        6
++#define UART_SCR        7
++#define UART_EMSR       7
++void LPCEnterMBPnP(void);
++void LPCExitMBPnP(void);
++int SearchIT8712(void);
++int InitLPCInterface(void);
++#endif
++
+ /*
+  * Optimised C version of memzero for the ARM.
+  */
+@@ -346,6 +372,9 @@
+ decompress_kernel(ulg output_start, ulg free_mem_ptr_p, ulg free_mem_ptr_end_p,
+                 int arch_id)
+ {
++#ifdef CONFIG_SERIAL_IT8712
++        unsigned char *addr;
++#endif
+       output_data             = (uch *)output_start;  /* Points to kernel start */
+       free_mem_ptr            = free_mem_ptr_p;
+       free_mem_ptr_end        = free_mem_ptr_end_p;
+@@ -353,6 +382,33 @@
+       arch_decomp_setup();
++#ifdef CONFIG_SERIAL_IT8712
++
++        InitLPCInterface();
++        LPCSetConfig(0, 0x02, 0x01);
++        LPCSetConfig(LDN_SERIAL1, 0x30, 0x1);
++        LPCSetConfig(LDN_SERIAL1, 0x23, 0x0);
++        it8712_uart_base = IT8712_IO_BASE;
++        it8712_uart_base += ((LPCGetConfig(LDN_SERIAL1, 0x60) << 8) + LPCGetConfig(LDN_SERIAL1, 0x61));
++
++        do {
++        addr = (unsigned char *)(it8712_uart_base + UART_LCR) ;
++        *addr = 0x80;
++        // Set Baud Rate
++        addr = (unsigned char *)(it8712_uart_base+UART_DLL);
++        *addr = 0x06 ;
++        addr = (unsigned char *)(it8712_uart_base+UART_DLM);
++        *addr = 0x00 ;
++
++        addr = (unsigned char *)(it8712_uart_base+UART_LCR);    // LCR
++        *addr = 0x07 ;
++        addr = (unsigned char *)(it8712_uart_base+UART_MCR);    // MCR
++        *addr = 0x08 ;
++        addr = (unsigned char *)(it8712_uart_base+UART_FCR);    // FCR
++        *addr = 0x01 ;
++      } while(0);
++#endif
++
+       makecrc();
+       putstr("Uncompressing Linux...");
+       gunzip();
+@@ -374,4 +430,119 @@
+       return 0;
+ }
+ #endif
++
++#ifdef CONFIG_SERIAL_IT8712
++
++#define LPC_KEY_ADDR    (unsigned char *)(SL2312_LPC_IO_BASE + 0x2e)
++#define LPC_DATA_ADDR   (unsigned char *)(SL2312_LPC_IO_BASE + 0x2f)
++#define LPC_BUS_CTRL                    *( unsigned char*) (SL2312_LPC_HOST_BASE + 0)
++#define LPC_BUS_STATUS                  *( unsigned char*) (SL2312_LPC_HOST_BASE + 2)
++#define LPC_SERIAL_IRQ_CTRL             *( unsigned char*) (SL2312_LPC_HOST_BASE + 4)
++
++char LPCGetConfig(char LdnNumber, char Index)
++{
++        char rtn;
++        unsigned char *addr ;
++
++        LPCEnterMBPnP();                                // Enter IT8712 MB PnP mode
++
++        addr = LPC_KEY_ADDR;
++        *addr = 0x07 ;
++
++        addr = LPC_DATA_ADDR;
++        *addr = LdnNumber ;
++
++        addr = LPC_KEY_ADDR;
++        *addr = Index ;
++
++        addr = LPC_DATA_ADDR ;
++        rtn = *addr ;
++
++        LPCExitMBPnP();
++        return rtn;
++
++}
++
++void LPCSetConfig(char LdnNumber, char Index, char data)
++{
++        unsigned char *addr;
++        LPCEnterMBPnP();                                // Enter IT8712 MB PnP mode
++        addr = LPC_KEY_ADDR;
++        *addr = 0x07;
++        addr = LPC_DATA_ADDR;
++        *addr = LdnNumber;
++        addr = LPC_KEY_ADDR;
++        *addr = Index;
++        addr = LPC_DATA_ADDR;
++        *addr = data;
++
++        LPCExitMBPnP();
++}
++
++//unsigned char key[4] ;
++void LPCEnterMBPnP(void)
++{
++        unsigned char *addr;
++        addr = LPC_KEY_ADDR;
++        unsigned char key[4] = {0x87, 0x01, 0x55, 0x55};
++
++              do {
++              *addr = key[0];
++              *addr = key[1];
++              *addr = key[2];
++              *addr = key[3];
++              }while(0);
++}
++
++void LPCExitMBPnP(void)
++{
++        unsigned char *addr;
++        addr = LPC_KEY_ADDR;
++        *addr = 0x02 ;
++
++        addr = LPC_DATA_ADDR;
++        *addr = 0x02 ;
++}
++
++int InitLPCInterface(void)
++{
++        int i;
++        LPC_BUS_CTRL = 0xc0;
++        LPC_SERIAL_IRQ_CTRL = 0xc0;
++
++        for(i=0;i<0x2000;i++) ;
++
++        LPC_SERIAL_IRQ_CTRL = 0x80;
++        if (!SearchIT8712()) ;
++//                    while(1);
++        return 0;
++}
++
++int SearchIT8712(void)
++{
++        unsigned char Id1, Id2;
++        unsigned short Id;
++        unsigned char *addr;
++
++        LPCEnterMBPnP();
++        addr = LPC_KEY_ADDR;
++        *addr = 0x20 ;
++        addr = LPC_DATA_ADDR;
++        Id1 = *addr ;
++
++        addr = LPC_KEY_ADDR;
++        *addr = 0x21 ;
++        addr = LPC_DATA_ADDR;
++        Id2 = *addr ;
++
++        Id = (Id1 << 8) | Id2;
++        LPCExitMBPnP();
++
++        if (Id == 0x8712)
++                return 1;
++        else
++                return 0;
++}
++
++#endif
+       
+Index: linux-2.6.23.16/arch/arm/kernel/entry-armv.S
+===================================================================
+--- linux-2.6.23.16.orig/arch/arm/kernel/entry-armv.S  2008-03-13 17:46:04.500819685 +0200
++++ linux-2.6.23.16/arch/arm/kernel/entry-armv.S       2008-03-13 17:48:24.508798285 +0200
+@@ -18,6 +18,8 @@
+ #include <asm/memory.h>
+ #include <asm/glue.h>
+ #include <asm/vfpmacros.h>
++#include <asm/arch/irqs.h>
++#include <asm/hardware.h>
+ #include <asm/arch/entry-macro.S>
+ #include <asm/thread_notify.h>
+Index: linux-2.6.23.16/arch/arm/kernel/irq.c
+===================================================================
+--- linux-2.6.23.16.orig/arch/arm/kernel/irq.c 2008-03-13 17:46:04.500819685 +0200
++++ linux-2.6.23.16/arch/arm/kernel/irq.c      2008-03-13 17:48:24.508798285 +0200
+@@ -40,6 +40,8 @@
+ #include <asm/system.h>
+ #include <asm/mach/time.h>
++extern int fixup_irq(unsigned int irq);
++
+ /*
+  * No architecture-specific irq_finish function defined in arm/arch/irqs.h.
+  */
+@@ -111,8 +113,11 @@
+ asmlinkage void __exception asm_do_IRQ(unsigned int irq, struct pt_regs *regs)
+ {
+       struct pt_regs *old_regs = set_irq_regs(regs);
+-      struct irq_desc *desc = irq_desc + irq;
++//    struct irq_desc *desc = irq_desc + irq;
++      struct irq_desc *desc;
++      irq = fixup_irq(irq);
++      desc = irq_desc + irq;
+       /*
+        * Some hardware gives randomly wrong interrupts.  Rather
+        * than crashing, do something sensible.
+Index: linux-2.6.23.16/arch/arm/kernel/process.c
+===================================================================
+--- linux-2.6.23.16.orig/arch/arm/kernel/process.c     2008-03-13 17:46:04.500819685 +0200
++++ linux-2.6.23.16/arch/arm/kernel/process.c  2008-03-13 17:48:24.508798285 +0200
+@@ -117,7 +117,7 @@
+ void (*pm_idle)(void);
+ EXPORT_SYMBOL(pm_idle);
+-void (*pm_power_off)(void);
++//void (*pm_power_off)(void);
+ EXPORT_SYMBOL(pm_power_off);
+ void (*arm_pm_restart)(char str) = arm_machine_restart;
+@@ -188,13 +188,37 @@
+ void machine_halt(void)
+ {
++      unsigned int reg_v;
++
++      printk("arch_power_off\n");
++
++      reg_v = readl(IO_ADDRESS(SL2312_POWER_CTRL_BASE) + 0x04);
++      reg_v &= ~0x00000002;
++      reg_v |= 0x1;
++      mdelay(5);
++      // Power off
++      __raw_writel( reg_v, IO_ADDRESS(SL2312_POWER_CTRL_BASE) + 0x04);
++
+ }
+ void machine_power_off(void)
+ {
+-      if (pm_power_off)
++      unsigned int reg_v;
++
++//    if (pm_power_off)
++      if (&pm_power_off!=NULL)
+               pm_power_off();
++
++      printk("arch_power_off\n");
++
++      reg_v = readl(IO_ADDRESS(SL2312_POWER_CTRL_BASE) + 0x04);
++      reg_v &= ~0x00000002;
++      reg_v |= 0x1;
++      mdelay(5);
++      // Power off
++      __raw_writel( reg_v, IO_ADDRESS(SL2312_POWER_CTRL_BASE) + 0x04);
++
+ }
+ void machine_restart(char * __unused)
+Index: linux-2.6.23.16/arch/arm/kernel/time.c
+===================================================================
+--- linux-2.6.23.16.orig/arch/arm/kernel/time.c        2008-03-13 17:46:04.500819685 +0200
++++ linux-2.6.23.16/arch/arm/kernel/time.c     2008-03-13 17:48:24.508798285 +0200
+@@ -502,8 +502,13 @@
+ device_initcall(timer_init_sysfs);
++extern unsigned int rtc_get_time_second(void);
++
+ void __init time_init(void)
+ {
++#ifdef CONFIG_SL2312_RTC
++      xtime.tv_sec  = rtc_get_time_second() ;
++#endif
+ #ifndef CONFIG_GENERIC_TIME
+       if (system_timer->offset == NULL)
+               system_timer->offset = dummy_gettimeoffset;
+Index: linux-2.6.23.16/arch/arm/mach-sl2312/Kconfig
+===================================================================
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.23.16/arch/arm/mach-sl2312/Kconfig       2008-03-13 17:48:24.508798285 +0200
+@@ -0,0 +1,33 @@
++
++menu "SL2312"
++
++config SL3516_ASIC
++      bool "SL3516 ASIC version"
++      depends on ARCH_SL2312
++      help
++        This option to select AISC or FPGA
++config PCI
++       bool "SL2312 PCI"
++       depends on ARCH_SL2312
++       help
++         This option to enable Storlink PCI controller
++
++config SL2312_LPC
++       bool "SL2312 LPC"
++       depends on ARCH_SL2312
++       help
++         This option to enable Low Pin Count controller
++
++config SL2312_USB
++       bool "SL2312 USB"
++       depends on ARCH_SL2312
++       help
++         This option to enable USB OTG host controller
++
++config GEMINI_IPI
++       bool "Gemini IPI test"
++       depends on ARCH_SL2312
++       help
++       Enable this option to test dual cpu Inter-Processor-Interrupt
++endmenu
++
+Index: linux-2.6.23.16/arch/arm/mach-sl2312/Makefile
+===================================================================
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.23.16/arch/arm/mach-sl2312/Makefile      2008-03-13 17:48:24.508798285 +0200
+@@ -0,0 +1,16 @@
++#
++# Makefile for the linux kernel.
++#
++
++# Object file lists.
++
++obj-y                 := arch.o irq.o mm.o time.o sl3516_device.o
++obj-m                 :=
++obj-n                 :=
++
++
++obj-$(CONFIG_PCI) += pci.o
++obj-$(CONFIG_SL2312_LPC) += lpc.o
++obj-$(CONFIG_SL2312_USB) += sl2312-otg.o # sl2312-otg-1.o
++obj-$(CONFIG_GEMINI_XOR_ACCE) += xor.o
++obj-$(CONFIG_GEMINI_IPI)      += gemini_ipi.o
+Index: linux-2.6.23.16/arch/arm/mach-sl2312/Makefile.boot
+===================================================================
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.23.16/arch/arm/mach-sl2312/Makefile.boot 2008-03-13 17:48:24.508798285 +0200
+@@ -0,0 +1,5 @@
++   zreladdr-y := 0x00008000
++params_phys-y := 0x00508100
++#params_phys-y        := 0x00008100
++initrd_phys-y := 0x00800000
++
+Index: linux-2.6.23.16/arch/arm/mach-sl2312/arch.c
+===================================================================
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.23.16/arch/arm/mach-sl2312/arch.c        2008-03-13 17:48:24.508798285 +0200
+@@ -0,0 +1,72 @@
++/*
++ *  linux/arch/arm/mach-epxa10db/arch.c
++ *
++ *  Copyright (C) 2000 Deep Blue Solutions Ltd
++ *  Copyright (C) 2001 Altera Corporation
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++ */
++#include <linux/types.h>
++#include <linux/init.h>
++
++#include <asm/hardware.h>
++#include <asm/setup.h>
++#include <asm/mach-types.h>
++#include <asm/mach/time.h>
++#include <asm/mach/arch.h>
++
++extern void sl2312_map_io(void);
++extern void sl2312_init_irq(void);
++extern unsigned long sl2312_gettimeoffset (void);
++extern void __init sl2312_time_init(void);
++
++static struct sys_timer sl2312_timer = {
++      .init           = sl2312_time_init,
++      .offset         = sl2312_gettimeoffset,
++};
++
++static void __init
++sl2312_fixup(struct machine_desc *desc, struct tag *tags,
++                 char **cmdline, struct meminfo *mi)
++{
++        mi->nr_banks      = 1;
++        mi->bank[0].start = 0;
++#ifdef CONFIG_GEMINI_IPI
++        mi->bank[0].size  = (64*1024*1024);  // 128M
++#else
++        mi->bank[0].size  = (128*1024*1024);  // 128M
++#endif
++        mi->bank[0].node  = 0;
++}
++
++/* MACHINE_START(SL2312, "GeminiA")
++      MAINTAINER("Storlink Semi")
++      BOOT_MEM(0x00000000, 0x90000000, 0xf0000000)
++        FIXUP(sl2312_fixup)
++      MAPIO(sl2312_map_io)
++      INITIRQ(sl2312_init_irq)
++      .timer = &sl2312_timer,
++MACHINE_END */
++
++MACHINE_START(SL2312, "GeminiA")
++      /* .phys_ram    = 0x00000000, */
++      .phys_io        = 0x7fffc000,
++      .io_pg_offst    = ((0xffffc000) >> 18) & 0xfffc,
++      .boot_params    = 0x100,
++      .fixup      = sl2312_fixup,
++      .map_io         = sl2312_map_io,
++      .init_irq       = sl2312_init_irq,
++      .timer          = &sl2312_timer,
++MACHINE_END
+Index: linux-2.6.23.16/arch/arm/mach-sl2312/gemini_ipi.c
+===================================================================
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.23.16/arch/arm/mach-sl2312/gemini_ipi.c  2008-03-15 16:53:01.339687322 +0200
+@@ -0,0 +1,593 @@
++/*
++ * FILE NAME sl_cir.c
++ *
++ * BRIEF MODULE DESCRIPTION
++ *  IPI Driver for CPU1.
++ *
++ *  Author: StorLink, Corp.
++ *          Jason Lee
++ *
++ * Copyright 2002~2006 StorLink, Corp.
++ *
++ *  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  SOFTWARE  IS PROVIDED   ``AS  IS'' AND   ANY  EXPRESS OR IMPLIED
++ *  WARRANTIES,   INCLUDING, BUT NOT  LIMit8712D  TO, THE IMPLIED WARRANTIES OF
++ *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
++ *  NO  EVENT  SHALL   THE AUTHOR  BE LIABLE FOR ANY   DIRECT, INDIRECT,
++ *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ *  NOT LIMit8712D   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF
++ *  USE, DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
++ *  ANY THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT
++ *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++ *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ *
++ *  You should have received a copy of the  GNU General Public License along
++ *  with this program; if not, writ8712  to the Free Software Foundation, Inc.,
++ *  675 Mass Ave, Cambridge, MA 02139, USA.
++ */
++
++#include <linux/module.h>
++#include <linux/types.h>
++#include <linux/kernel.h>
++#include <linux/miscdevice.h>
++#include <linux/init.h>
++#include <linux/pagemap.h>
++#include <asm/uaccess.h>
++#include <linux/ioport.h>
++#include <linux/sched.h>
++#include <linux/delay.h>
++#include <linux/fs.h>
++#include <linux/interrupt.h>
++#include <asm/io.h>
++#include <asm/delay.h>
++#include <linux/signal.h>
++#include <asm/arch/sl2312.h>
++#include <asm/arch/int_ctrl.h>
++#include <asm/arch/ipi.h>
++#include <linux/dma-mapping.h>
++
++
++#include <linux/mm.h>
++
++#include <linux/bootmem.h>
++
++#include <asm/hardware.h>
++#include <asm/page.h>
++#include <asm/setup.h>
++#include <asm/pgtable.h>
++#include <asm/pgalloc.h>
++
++#include <asm/mach/map.h>
++
++
++static int sl_ipi_debug = 1 ;
++#define DEB(x)  if(sl_ipi_debug>=1) x
++
++#define SRAM_PTR              IO_ADDRESS(SL2312_SRAM_BASE)
++volatile JSCALE_REQ_T *req=(JSCALE_REQ_T*)SRAM_PTR;
++volatile JSCALE_RSP_T *rsp=(JSCALE_RSP_T*)(SRAM_PTR+0x20);
++
++unsigned int jscale_status=0;
++
++#define JSCALE_WAIT   0
++#define XXXXXX_WAIT   1
++#define MAX_WAIT_Q    8
++wait_queue_head_t gemini_ipi_wait[MAX_WAIT_Q];
++
++#define DRAMCTL_DMA_CTL               0X20
++#define DRAMCTL_DMA_SA                0X24
++#define DRAMCTL_DMA_DA                0X28
++#define DRAMCTL_DMA_CNT               0X2C
++#define MEMCPY_UNIT           0x40000
++int hw_memcpy(const void *to, const void *from, unsigned int bytes)
++{
++      unsigned int reg_a,reg_d;
++      int count = bytes,i=0;
++
++      consistent_sync((unsigned int *)to, bytes, DMA_BIDIRECTIONAL);
++      consistent_sync((unsigned int *)from,bytes, DMA_TO_DEVICE);
++
++      DEB(printk("hwmemcpy:count %d\n",count));
++      while(count>0){
++              // SA
++              reg_a = IO_ADDRESS(SL2312_DRAM_CTRL_BASE)+DRAMCTL_DMA_SA;
++              reg_d = (unsigned int )__virt_to_phys(from) + i*MEMCPY_UNIT;
++              DEB(printk("hwmemcpy:from 0x%08x\n",reg_d));
++              writel(reg_d,reg_a);
++              // DA
++              reg_a = IO_ADDRESS(SL2312_DRAM_CTRL_BASE)+DRAMCTL_DMA_DA;
++              reg_d = (unsigned int )__virt_to_phys(to) + i*MEMCPY_UNIT;
++              writel(reg_d,reg_a);
++              DEB(printk("hwmemcpy:to 0x%08x\n",reg_d));
++              // byte count
++              reg_a = IO_ADDRESS(SL2312_DRAM_CTRL_BASE)+DRAMCTL_DMA_CNT;
++              reg_d = (count>=MEMCPY_UNIT)?MEMCPY_UNIT:count;
++              writel(reg_d,reg_a);
++              // start DMA
++              reg_a = IO_ADDRESS(SL2312_DRAM_CTRL_BASE)+DRAMCTL_DMA_CTL;
++              writel(0x80000001,reg_a);
++
++              do{
++                      cond_resched();
++//                    msleep(4);
++                      reg_d = readl(IO_ADDRESS(SL2312_DRAM_CTRL_BASE)+DRAMCTL_DMA_CTL);
++              }while(reg_d&0x1);
++
++              count -= MEMCPY_UNIT;
++              i++;
++      }
++
++      return bytes;
++}
++
++static irqreturn_t ipi_interrupt()
++{
++      unsigned int id=getcpuid(),tmp;
++
++      //dmac_inv_range(__phys_to_virt(SL2312_SRAM_BASE),__phys_to_virt(SHAREADDR)+0x2000);
++
++
++      // Clear Interrupt
++      if(id==CPU0) {
++              tmp = readl(CPU1_STATUS);
++              tmp &= ~CPU_IPI_BIT_MASK;
++              writel(tmp,CPU1_STATUS);
++      }
++      else{
++              tmp = readl(CPU0_STATUS);
++              tmp &= ~CPU_IPI_BIT_MASK;
++              writel(tmp,CPU0_STATUS);
++      }
++
++      //
++      DEB(printk("ipi interrupt:0x%x\n",rsp->status));
++      switch(rsp->status){
++              case JSCALE_STATUS_OK:
++
++                      break;
++              case JSCALE_UNKNOWN_MSG_TYPE:
++
++                      break;
++              case JSCALE_FAILED_FILE_SIZE:
++
++                      break;
++              case JSCALE_FAILED_MALLOC:
++
++                      break;
++              case JSCALE_FAILED_FORMAT:
++
++                      break;
++              case JSCALE_DECODE_ERROR:
++
++                      break;
++
++      }
++      jscale_status = rsp->status;
++//    wake_up(&gemini_ipi_wait[JSCALE_WAIT]);
++
++      return IRQ_HANDLED;
++}
++
++static int gemini_ipi_open(struct inode *inode, struct file *file)
++{
++      DEB(printk("ipi open\n"));
++      return 0;
++}
++
++
++static int gemini_ipi_release(struct inode *inode, struct file *file)
++{
++      DEB(printk("ipi release\n"));
++      return 0;
++}
++
++
++static int gemini_ipi_ioctl(struct inode *inode, struct file *file,
++      unsigned int cmd, unsigned long arg)
++{
++      JSCALE_RSP_T tmp;
++
++      switch(cmd) {
++              case GEMINI_IPI_JSCALE_REQ:
++                      DEB(printk("ipi:ioctl jscale request %dX%d Q:%d\n",req->ScaledImageWidth,req->ScaledImageHeight,req->ScaledImageQuality));
++                      if (copy_from_user(req, (JSCALE_REQ_T *)arg, sizeof(JSCALE_REQ_T)))
++                              return -EFAULT;
++                      req->hdr.type = IPC_JSCALE_REQ_MSG;
++                      req->hdr.length = sizeof(JSCALE_REQ_T);
++                      req->input_location  = CPU_1_DATA_OFFSET;
++                      req->output_location = CPU_1_DATA_OFFSET;
++                      break;
++              case GEMINI_IPI_JSCALE_STAT:
++                      DEB(printk("ipi:ioctl jscale stat \n"));
++                      if(jscale_status==JSCALE_BUSY){                                         // not yet
++                              tmp.status = JSCALE_BUSY;
++                              if (copy_to_user((JSCALE_RSP_T *)arg,&tmp, sizeof(JSCALE_RSP_T)))
++                                      return -EFAULT;
++                      }
++                      else{                                                                                           // finish or error
++                              if (copy_to_user((JSCALE_RSP_T *)arg,rsp, sizeof(JSCALE_RSP_T)))
++                                      return -EFAULT;
++                      }
++                      break;
++              default:
++                      printk("IPI: Error IOCTL number\n");
++                      return -ENOIOCTLCMD;
++      }
++
++      return 0;
++}
++
++#define SRAM_SIZE     0x2000
++static ssize_t gemini_ipi_write(struct file *file_p, const char *buf, size_t count, loff_t * ppos)
++{
++      int i=0,tmp=0,j;
++      const char *ptr=(unsigned int)__phys_to_virt(CPU_1_MEM_BASE+CPU_1_DATA_OFFSET);
++      DEB(printk("ipi:write 0x%x to 0x%x length:%d\n",&buf,ptr,count));
++      memcpy(ptr,buf,count);
++      consistent_sync(ptr,count, DMA_TO_DEVICE);
++      //hw_memcpy(ptr,&buf,count);
++
++/*    if(count>SRAM_SIZE){
++              for(i=0;i<(count/SRAM_SIZE);i++)
++                      raid_memcpy(ptr+i*SRAM_SIZE,buf+i*SRAM_SIZE,SRAM_SIZE);
++              if(count%SRAM_SIZE)
++                      raid_memcpy(ptr+i*SRAM_SIZE,buf+i*SRAM_SIZE,count%SRAM_SIZE);
++      }
++      else
++              raid_memcpy(ptr,buf,count);
++*/
++
++/*    for(i=0;i<count;i++){
++              if(buf[i]!=ptr[i])
++                      printk("ipi error:offset %d valud %x[should %x]\n",i,ptr[i],buf[i]);
++      }
++
++      printk("===========input buf===============\n");
++      for(i=0;i<64;i+=16){
++              for(j=0;j<16;j++)
++                      printk("%02x ",buf[i+j]);
++              printk("\n");
++              cond_resched();
++      }
++      printk("===========output buf==============\n");
++      for(i=0;i<64;i+=16){
++              for(j=0;j<16;j++)
++                      printk("%02x ",ptr[i+j]);
++              printk("\n");
++              cond_resched();
++      }
++*/
++      // send irq for CPU1
++      tmp |= CPU_IPI_BIT_MASK;
++      writel(tmp,CPU0_STATUS);
++      jscale_status = JSCALE_BUSY;
++
++      return count;
++}
++
++static ssize_t gemini_ipi_read(struct file * file_p, char *buf, size_t length, loff_t * ppos)
++{
++      int i=0;
++      const char *ptr=(unsigned int )__phys_to_virt(CPU_1_MEM_BASE+CPU_1_DATA_OFFSET);
++
++      consistent_sync(ptr,length, DMA_FROM_DEVICE);
++      memcpy(buf,ptr,length);
++      DEB(printk("ipi:read 0x%x to 0x%x length:%d\n",ptr,buf,length));
++
++      //consistent_sync((unsigned int *)ptr,0x2000, DMA_FROM_DEVICE);         // invalid
++      //hw_memcpy(buf,ptr,length);
++
++      // need encoded file size ********
++/*    if(count>SRAM_SIZE){
++              for(i=0;i<(count/SRAM_SIZE);i++)
++                      raid_memcpy(buf+i*SRAM_SIZE,p_mbox->message+i*SRAM_SIZE,SRAM_SIZE);
++              if(count%0xFFFF)
++                      raid_memcpy(buf+i*SRAM_SIZE,p_mbox->message+i*SRAM_SIZE,length%SRAM_SIZE);
++      }
++      else
++              raid_memcpy(buf,p_mbox->message,length);
++*/
++      return length;
++}
++
++void do_mapping_read(struct address_space *mapping,
++                           struct file_ra_state *_ra,
++                           struct file *filp,
++                           loff_t *ppos,
++                           read_descriptor_t *desc,
++                           read_actor_t actor)
++{
++      struct inode *inode = mapping->host;
++      unsigned long index;
++      unsigned long end_index;
++      unsigned long offset;
++      unsigned long last_index;
++      unsigned long next_index;
++      unsigned long prev_index;
++      loff_t isize;
++      struct page *cached_page;
++      int error;
++      struct file_ra_state ra = *_ra;
++
++      cached_page = NULL;
++      index = *ppos >> PAGE_CACHE_SHIFT;
++      next_index = index;
++      prev_index = ra.prev_page;
++      last_index = (*ppos + desc->count + PAGE_CACHE_SIZE-1) >> PAGE_CACHE_SHIFT;
++      offset = *ppos & ~PAGE_CACHE_MASK;
++
++      isize = i_size_read(inode);
++      if (!isize)
++              goto out;
++
++      end_index = (isize - 1) >> PAGE_CACHE_SHIFT;
++      for (;;) {
++              struct page *page;
++              unsigned long nr, ret;
++
++              /* nr is the maximum number of bytes to copy from this page */
++              nr = PAGE_CACHE_SIZE;
++              if (index >= end_index) {
++                      if (index > end_index)
++                              goto out;
++                      nr = ((isize - 1) & ~PAGE_CACHE_MASK) + 1;
++                      if (nr <= offset) {
++                              goto out;
++                      }
++              }
++              nr = nr - offset;
++
++              cond_resched();
++              if (index == next_index)
++                      next_index = page_cache_readahead(mapping, &ra, filp,
++                                      index, last_index - index);
++
++find_page:
++              page = find_get_page(mapping, index);
++              if (unlikely(page == NULL)) {
++                      handle_ra_miss(mapping, &ra, index);
++                      goto no_cached_page;
++              }
++              if (!PageUptodate(page))
++                      goto page_not_up_to_date;
++page_ok:
++
++              /* If users can be writing to this page using arbitrary
++               * virtual addresses, take care about potential aliasing
++               * before reading the page on the kernel side.
++               */
++              if (mapping_writably_mapped(mapping))
++                      flush_dcache_page(page);
++
++              /*
++               * When (part of) the same page is read multiple times
++               * in succession, only mark it as accessed the first time.
++               */
++              if (prev_index != index)
++                      mark_page_accessed(page);
++              prev_index = index;
++
++              /*
++               * Ok, we have the page, and it's up-to-date, so
++               * now we can copy it to user space...
++               *
++               * The actor routine returns how many bytes were actually used..
++               * NOTE! This may not be the same as how much of a user buffer
++               * we filled up (we may be padding etc), so we can only update
++               * "pos" here (the actor routine has to update the user buffer
++               * pointers and the remaining count).
++               */
++              ret = actor(desc, page, offset, nr);
++              offset += ret;
++              index += offset >> PAGE_CACHE_SHIFT;
++              offset &= ~PAGE_CACHE_MASK;
++
++              page_cache_release(page);
++              if (ret == nr && desc->count)
++                      continue;
++              goto out;
++
++page_not_up_to_date:
++              /* Get exclusive access to the page ... */
++              lock_page(page);
++
++              /* Did it get unhashed before we got the lock? */
++              if (!page->mapping) {
++                      unlock_page(page);
++                      page_cache_release(page);
++                      continue;
++              }
++
++              /* Did somebody else fill it already? */
++              if (PageUptodate(page)) {
++                      unlock_page(page);
++                      goto page_ok;
++              }
++
++readpage:
++              /* Start the actual read. The read will unlock the page. */
++              error = mapping->a_ops->readpage(filp, page);
++
++              if (unlikely(error))
++                      goto readpage_error;
++
++              if (!PageUptodate(page)) {
++                      lock_page(page);
++                      if (!PageUptodate(page)) {
++                              if (page->mapping == NULL) {
++                                      /*
++                                       * invalidate_inode_pages got it
++                                       */
++                                      unlock_page(page);
++                                      page_cache_release(page);
++                                      goto find_page;
++                              }
++                              unlock_page(page);
++                              error = -EIO;
++                              goto readpage_error;
++                      }
++                      unlock_page(page);
++              }
++
++              /*
++               * i_size must be checked after we have done ->readpage.
++               *
++               * Checking i_size after the readpage allows us to calculate
++               * the correct value for "nr", which means the zero-filled
++               * part of the page is not copied back to userspace (unless
++               * another truncate extends the file - this is desired though).
++               */
++              isize = i_size_read(inode);
++              end_index = (isize - 1) >> PAGE_CACHE_SHIFT;
++              if (unlikely(!isize || index > end_index)) {
++                      page_cache_release(page);
++                      goto out;
++              }
++
++              /* nr is the maximum number of bytes to copy from this page */
++              nr = PAGE_CACHE_SIZE;
++              if (index == end_index) {
++                      nr = ((isize - 1) & ~PAGE_CACHE_MASK) + 1;
++                      if (nr <= offset) {
++                              page_cache_release(page);
++                              goto out;
++                      }
++              }
++              nr = nr - offset;
++              goto page_ok;
++
++readpage_error:
++              /* UHHUH! A synchronous read error occurred. Report it */
++              desc->error = error;
++              page_cache_release(page);
++              goto out;
++
++no_cached_page:
++              /*
++               * Ok, it wasn't cached, so we need to create a new
++               * page..
++               */
++              if (!cached_page) {
++                      cached_page = page_cache_alloc_cold(mapping);
++                      if (!cached_page) {
++                              desc->error = -ENOMEM;
++                              goto out;
++                      }
++              }
++              error = add_to_page_cache_lru(cached_page, mapping,
++                                              index, GFP_KERNEL);
++              if (error) {
++                      if (error == -EEXIST)
++                              goto find_page;
++                      desc->error = error;
++                      goto out;
++              }
++              page = cached_page;
++              cached_page = NULL;
++              goto readpage;
++      }
++
++out:
++      *_ra = ra;
++
++      *ppos = ((loff_t) index << PAGE_CACHE_SHIFT) + offset;
++      if (cached_page)
++              page_cache_release(cached_page);
++      if (filp)
++              file_accessed(filp);
++}
++
++int ipi_send_actor(read_descriptor_t * desc, struct page *page, unsigned long offset, unsigned long size)
++{
++      ssize_t written;
++      unsigned long count = desc->count;
++      struct file *file = desc->arg.data;
++      unsigned int *ptr_to=(unsigned int)__phys_to_virt(CPU_1_MEM_BASE+CPU_1_DATA_OFFSET) + desc->written;
++      void *ptr_from;
++
++      if (size > count)
++              size = count;
++
++      ptr_from = page_address(page)+offset;
++      written = memcpy(ptr_to,ptr_from,size);
++
++      if (written < 0) {
++              desc->error = written;
++              written = 0;
++      }
++      desc->count = count - written;
++      desc->written += written;
++      return written;
++}
++
++ssize_t gemini_ipi_sendfile(struct file *in_file, loff_t *ppos,
++                       size_t count, read_actor_t actor, void *TARGET)
++{
++      read_descriptor_t desc;
++
++      if (!count)
++              return 0;
++
++      desc.written = 0;
++      desc.count = count;
++      desc.arg.data = TARGET;
++      desc.error = 0;
++
++      do_mapping_read(in_file->f_mapping,&in_file->f_ra,in_file, ppos, &desc, ipi_send_actor);
++
++      if (desc.written)
++              return desc.written;
++      return desc.error;
++}
++static struct file_operations gemini_ipi_fops = {
++      .owner  =       THIS_MODULE,
++      .ioctl  =       gemini_ipi_ioctl,
++      .open   =       gemini_ipi_open,
++      .release=       gemini_ipi_release,
++      .write  =       gemini_ipi_write,
++      .read   =       gemini_ipi_read,
++      .sendfile = gemini_ipi_sendfile,
++};
++
++#ifndef STORLINK_IPI
++#define STORLINK_IPI  242             // Documents/devices.txt suggest to use 240~255 for local driver!!
++#endif
++
++static struct miscdevice gemini_ipi_miscdev =
++{
++      STORLINK_IPI,
++      "slave_ipc",
++      &gemini_ipi_fops
++};
++
++int __init sl_ipi_init(void)
++{
++
++      printk("Gemini IPI Driver Initialization...\n");
++      printk("REQ Head :0x%x(phy:0x%x)\n",(unsigned int)req,(unsigned int)SL2312_SRAM_BASE);
++      printk("RSP Head :0x%x(phy:0x%x)\n",(unsigned int)rsp,(unsigned int)SL2312_SRAM_BASE+0x20);
++      printk("Data buff:0x%x(phy:0x%x)\n",__phys_to_virt(CPU_1_MEM_BASE+CPU_1_DATA_OFFSET),CPU_1_MEM_BASE+CPU_1_DATA_OFFSET);
++
++      misc_register(&gemini_ipi_miscdev);
++
++      if (request_irq(IRQ_CPU0_IP_IRQ_OFFSET, ipi_interrupt, SA_INTERRUPT, "ipi", NULL))
++              printk("Error: Register IRQ for Storlink IPI failed\n");
++
++      return 0;
++}
++
++void __exit sl_ipi_exit(void)
++{
++
++}
++
++module_init(sl_ipi_init);
++module_exit(sl_ipi_exit);
++
++MODULE_AUTHOR("Jason Lee <jason@storlink.com.tw>");
++MODULE_DESCRIPTION("Storlink IPI driver");
++MODULE_LICENSE("GPL");
+Index: linux-2.6.23.16/arch/arm/mach-sl2312/hw_xor.h
+===================================================================
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.23.16/arch/arm/mach-sl2312/hw_xor.h      2008-03-13 17:48:24.508798285 +0200
+@@ -0,0 +1,573 @@
++/*
++*  linux/include/asm-arm/xor.h
++*
++*  Copyright (C) 2001 Storlink Semi.
++*     Jason Lee <jason@storlink.com.tw>
++*
++*/
++#include <asm/arch/sl2312.h>
++#include <asm/io.h>
++//#include <linux/compatmac.h>
++
++#undef BIG_ENDIAN
++#define CPU           0
++#define DMA           1
++
++#define DESC_NO       8
++#define TX_DESC_NUM           DESC_NO
++#define RX_DESC_NUM           DESC_NO
++
++#define RAID_BASE_ADDR        IO_ADDRESS(SL2312_RAID_BASE)
++
++#define SRAM_PAR_0k           0
++#define SRAM_PAR_4k           1
++#define SRAM_PAR_8k           2
++#define SRAM_PAR_16k          3
++#define SRAM_PAR_SIZE SRAM_PAR_8k
++
++#define RUNNING               0x1
++#define COMPLETE      0x2
++#define ERROR                 0x4
++
++#define CMD_XOR               0x0
++#define CMD_FILL      0x1
++#define CMD_CPY               0x3
++#define CMD_CHK               0x4
++
++enum RAID_DMA_REGISTER {
++      RAID_DMA_DEVICE_ID              = 0xff00,
++      RAID_DMA_STATUS                 = 0xff04,
++      RAID_FCHDMA_CTRL                = 0xff08,
++      RAID_FCHDMA_FIRST_DESC  = 0xff0C,
++      RAID_FCHDMA_CURR_DESC   = 0xff10,
++      RAID_STRDMA_CTRL                = 0xff14,
++      RAID_STRDMA_FIRST_DESC  = 0xff18,
++      RAID_STRDMA_CURR_DESC   = 0xff1C,
++      RAID_TX_FLG_REG                 = 0xff24,
++      RAID_RX_FLG_REG                 = 0xff34,
++      RAID_PCR                                = 0xff50,
++      SMC_CMD_REG                             = 0xff60,
++      SMC_STATUS_REG                  = 0xff64
++      };
++
++enum RAID_FUNC_MODE {
++      RAID_XOR                        = 0,
++      RAID_MIX                        = 2,
++      RAID_SRAM                       = 3,
++      RAID_ENDIAN                     = 4,
++      RAID_MEM_BLK            = 5,
++      RAID_MEM2MEM            = 7,
++      RAID_BUF_SIZE           = 8,
++      RAID_ERR_TEST           = 9,
++      RAID_BURST                      = 10,
++      RAID_BUS                        = 11
++      };
++
++typedef struct reg_info {
++      int mask;
++      char err[32];
++      int offset;
++} REG_INFO;
++
++/********************************************************/
++/*    the definition of RAID DMA Module Register      */
++/********************************************************/
++typedef union
++{
++      unsigned int bit32;
++      struct bits_ff00
++      {
++              #ifdef BIG_ENDIAN
++              unsigned int                            : 8;
++              unsigned int teytPerr           : 4; /* define protocol error under tsPErrI*/
++              unsigned int reytPerr           : 14; /* define protocol error under rsPErrI */
++              unsigned int device_id          : 12;
++              unsigned int revision_id        : 4;
++              #else
++              unsigned int revision_id        : 4;
++              unsigned int device_id          : 12;
++              unsigned int reytPerr           : 14; /* define protocol error under rsPErrI */
++              unsigned int teytPerr           : 4; /* define protocol error under tsPErrI*/
++              unsigned int                            : 8;
++              #endif
++      } bits;
++} RAID_DMA_DEVICE_ID_T;
++
++typedef union
++{
++      unsigned int bits32;
++      struct bits_ff04
++      {
++              #ifdef BIG_ENDIAN
++              unsigned int tsFinishI          : 1; /* owner bit error interrupt */
++              unsigned int tsDErrI            : 1; /* AHB bus error interrupt */
++              unsigned int tsPErrI            : 1; /* RAID XOR fetch descriptor protocol error interrupt */
++              unsigned int tsEODI                     : 1; /* RAID XOR fetch DMA end of descriptor interrupt */
++              unsigned int tsEOFI                     : 1; /* RAID XOR fetch DMA end of frame interrupt */
++              unsigned int rsFinishI          : 1; /* owner bit error interrupt */
++              unsigned int rsDErrI            : 1; /* AHB bus error while RAID XOR store interrupt */
++              unsigned int rsPErrI            : 1; /* RAID XOR store descriptor protocol error interrupt */
++              unsigned int rsEODI                     : 1; /* RAID XOR store DMA end of descriptor interrupt */
++              unsigned int rsEOFI                     : 1; /* RAID XOR store DMA end of frame interrupt */
++              unsigned int inter                      : 8; /* pattern check error interrupt */
++              unsigned int                            : 5;
++              unsigned int Loopback           : 1; /* loopback */
++              unsigned int intEnable          : 8; /*pattern check error interrupt enable */
++              #else
++              unsigned int intEnable          : 8; /*pattern check error interrupt enable */
++              unsigned int Loopback           : 1; /* loopback */
++              unsigned int                            : 5;
++              unsigned int inter                      : 8; /* pattern check error interrupt */
++              unsigned int rsEOFI                     : 1; /* RAID XOR store DMA end of frame interrupt */
++              unsigned int rsEODI                     : 1; /* RAID XOR store DMA end of descriptor interrupt */
++              unsigned int rsPErrI            : 1; /* RAID XOR store descriptor protocol error interrupt */
++              unsigned int rsDErrI            : 1; /* AHB bus error while RAID XOR store interrupt */
++              unsigned int rsFinishI          : 1; /* owner bit error interrupt */
++              unsigned int tsEOFI                     : 1; /* RAID XOR fetch DMA end of frame interrupt */
++              unsigned int tsEODI                     : 1; /* RAID XOR fetch DMA end of descriptor interrupt */
++              unsigned int tsPErrI            : 1; /* RAID XOR fetch descriptor protocol error interrupt */
++              unsigned int tsDErrI            : 1; /* AHB bus error interrupt */
++              unsigned int tsFinishI          : 1; /* owner bit error interrupt */
++              #endif
++      } bits;
++} RAID_DMA_STATUS_T;
++
++
++typedef union
++{
++      unsigned int bits32;
++      struct bits_ff08
++      {
++              #ifdef BIG_ENDIAN
++              unsigned int td_start           :  1;   /* Start DMA transfer */
++              unsigned int td_continue        :  1;   /* Continue DMA operation */
++              unsigned int td_chain_mode      :  1;   /* Descriptor Chain Mode;1-Descriptor Chain mode, 0-Direct DMA mode*/
++              unsigned int                            :  1;
++              unsigned int td_prot            :  4;   /* DMA protection control */
++              unsigned int td_burst_size  :  2;       /* DMA max burst size for every AHB request */
++              unsigned int td_bus                 :  2;       /* peripheral bus width */
++              unsigned int td_endian          :  1;   /* AHB Endian. 0-little endian; 1-big endian */
++              unsigned int td_finish_en   :  1;       /* DMA Finish Event Interrupt Enable;1-enable;0-mask */
++              unsigned int td_fail_en         :  1;   /* DMA Fail Interrupt Enable;1-enable;0-mask */
++              unsigned int td_perr_en         :  1;   /* Protocol Failure Interrupt Enable;1-enable;0-mask */
++              unsigned int td_eod_en          :  1;   /* End of Descriptor interrupt Enable;1-enable;0-mask */
++              unsigned int td_eof_en      :  1;   /* End of frame interrupt Enable;1-enable;0-mask */
++              unsigned int                            : 14;
++              #else
++              unsigned int                            : 14;
++              unsigned int td_eof_en      :  1;   /* End of frame interrupt Enable;1-enable;0-mask */
++              unsigned int td_eod_en          :  1;   /* End of Descriptor interrupt Enable;1-enable;0-mask */
++              unsigned int td_perr_en         :  1;   /* Protocol Failure Interrupt Enable;1-enable;0-mask */
++              unsigned int td_fail_en         :  1;   /* DMA Fail Interrupt Enable;1-enable;0-mask */
++              unsigned int td_finish_en   :  1;       /* DMA Finish Event Interrupt Enable;1-enable;0-mask */
++              unsigned int td_endian          :  1;   /* AHB Endian. 0-little endian; 1-big endian */
++              unsigned int td_bus                 :  2;       /* peripheral bus width;0 - 8 bits;1 - 16 bits */
++              unsigned int td_burst_size  :  2;       /* TxDMA max burst size for every AHB request */
++              unsigned int td_prot            :  4;   /* TxDMA protection control */
++              unsigned int                            :  1;
++              unsigned int td_chain_mode      :  1;   /* Descriptor Chain Mode;1-Descriptor Chain mode, 0-Direct DMA mode*/
++              unsigned int td_continue        :  1;   /* Continue DMA operation */
++              unsigned int td_start           :  1;   /* Start DMA transfer */
++              #endif
++      } bits;
++} RAID_TXDMA_CTRL_T;
++
++typedef union
++{
++      unsigned int bits32;
++      struct bits_ff0c
++      {
++              #ifdef BIG_ENDIAN
++              unsigned int td_first_des_ptr   : 28;/* first descriptor address */
++              unsigned int td_busy                    :  1;/* 1-TxDMA busy; 0-TxDMA idle */
++              unsigned int                                    :  3;
++              #else
++              unsigned int                                    :  3;
++              unsigned int td_busy                    :  1;/* 1-TxDMA busy; 0-TxDMA idle */
++              unsigned int td_first_des_ptr   : 28;/* first descriptor address */
++              #endif
++      } bits;
++} RAID_TXDMA_FIRST_DESC_T;
++
++typedef union
++{
++      unsigned int bits32;
++      struct bits_ff10
++      {
++              #ifdef BIG_ENDIAN
++              unsigned int ndar                       : 28;   /* next descriptor address */
++              unsigned int eofie                      :  1;   /* end of frame interrupt enable */
++              unsigned int                            :  1;
++              unsigned int sof_eof            :  2;
++              #else
++              unsigned int sof_eof            :  2;
++              unsigned int                            :  1;
++              unsigned int eofie                      :  1;   /* end of frame interrupt enable */
++              unsigned int ndar                       : 28;   /* next descriptor address */
++              #endif
++      } bits;
++} RAID_TXDMA_CURR_DESC_T;
++
++typedef union
++{
++      unsigned int bits32;
++      struct bits_ff14
++      {
++              #ifdef BIG_ENDIAN
++              unsigned int rd_start           :  1;   /* Start DMA transfer */
++              unsigned int rd_continue        :  1;   /* Continue DMA operation */
++              unsigned int rd_chain_mode      :  1;   /* Descriptor Chain Mode;1-Descriptor Chain mode, 0-Direct DMA mode*/
++              unsigned int                            :  1;
++              unsigned int rd_prot            :  4;   /* DMA protection control */
++              unsigned int rd_burst_size  :  2;       /* DMA max burst size for every AHB request */
++              unsigned int rd_bus                 :  2;       /* peripheral bus width;0 - 8 bits;1 - 16 bits */
++              unsigned int rd_endian          :  1;   /* AHB Endian. 0-little endian; 1-big endian */
++              unsigned int rd_finish_en   :  1;       /* DMA Finish Event Interrupt Enable;1-enable;0-mask */
++              unsigned int rd_fail_en         :  1;   /* DMA Fail Interrupt Enable;1-enable;0-mask */
++              unsigned int rd_perr_en         :  1;   /* Protocol Failure Interrupt Enable;1-enable;0-mask */
++              unsigned int rd_eod_en          :  1;   /* End of Descriptor interrupt Enable;1-enable;0-mask */
++              unsigned int rd_eof_en      :  1;   /* End of frame interrupt Enable;1-enable;0-mask */
++              unsigned int                            : 14;
++              #else
++              unsigned int                            : 14;
++              unsigned int rd_eof_en      :  1;   /* End of frame interrupt Enable;1-enable;0-mask */
++              unsigned int rd_eod_en          :  1;   /* End of Descriptor interrupt Enable;1-enable;0-mask */
++              unsigned int rd_perr_en         :  1;   /* Protocol Failure Interrupt Enable;1-enable;0-mask */
++              unsigned int rd_fail_en         :  1;   /* DMA Fail Interrupt Enable;1-enable;0-mask */
++              unsigned int rd_finish_en   :  1;       /* DMA Finish Event Interrupt Enable;1-enable;0-mask */
++              unsigned int rd_endian          :  1;   /* AHB Endian. 0-little endian; 1-big endian */
++              unsigned int rd_bus                 :  2;       /* peripheral bus width;0 - 8 bits;1 - 16 bits */
++              unsigned int rd_burst_size  :  2;       /* DMA max burst size for every AHB request */
++              unsigned int rd_prot            :  4;   /* DMA protection control */
++              unsigned int                            :  1;
++              unsigned int rd_chain_mode      :  1;   /* Descriptor Chain Mode;1-Descriptor Chain mode, 0-Direct DMA mode*/
++              unsigned int rd_continue        :  1;   /* Continue DMA operation */
++              unsigned int rd_start           :  1;   /* Start DMA transfer */
++              #endif
++      } bits;
++} RAID_RXDMA_CTRL_T;
++
++typedef union
++{
++      unsigned int bits32;
++      struct bits_ff18
++      {
++              #ifdef BIG_ENDIAN
++              unsigned int rd_first_des_ptr   : 28;/* first descriptor address */
++              unsigned int rd_busy                    :  1;/* 1-RxDMA busy; 0-RxDMA idle */
++              unsigned int                                    :  3;
++              #else
++              unsigned int                                    :  3;
++              unsigned int rd_busy                    :  1;/* 1-RxDMA busy; 0-RxDMA idle */
++              unsigned int rd_first_des_ptr   : 28;/* first descriptor address */
++              #endif
++      } bits;
++} RAID_RXDMA_FIRST_DESC_T;
++
++typedef union
++{
++      unsigned int bits32;
++      struct bits_ff1c
++      {
++              #ifdef BIG_ENDIAN
++              unsigned int ndar                       : 28;   /* next descriptor address */
++              unsigned int eofie                      :  1;   /* end of frame interrupt enable */
++              unsigned int dec                        :  1;   /* AHB bus address increment(0)/decrement(1) */
++              unsigned int sof_eof            :  2;
++              #else
++              unsigned int sof_eof            :  2;
++              unsigned int dec                        :  1;   /* AHB bus address increment(0)/decrement(1) */
++              unsigned int eofie                      :  1;   /* end of frame interrupt enable */
++              unsigned int ndar                       : 28;   /* next descriptor address */
++              #endif
++      } bits;
++} RAID_RXDMA_CURR_DESC_T;
++
++typedef union
++{
++      unsigned int bit32;
++      struct bits_ff50
++      {
++              unsigned int pat                        : 32; /* data for pattern check */
++      } bits;
++} RAID_PACR_T;
++
++/******************************************************/
++/*    the definition of DMA Descriptor Register     */
++/******************************************************/
++typedef struct raid_descriptor_t
++{
++      union func_ctrl_t
++      {
++              unsigned int bit32;
++              struct bits_0000
++              {
++                      #ifdef BIG_ENDIAN
++                      unsigned int own                                : 1; /* owner bit */
++                      unsigned int derr                               : 1;    /* data error during processing this descriptor */
++                      unsigned int perr                               : 1;    /* protocol error during processing this descriptor */
++                      unsigned int raid_ctrl_status   : 7; /* pass RAID XOR fetch/store control status to CPU */
++                      unsigned int desc_cnt                   : 6;
++                      unsigned int buffer_size                : 16;   /* transfer buffer size associated with current description*/
++                      #else
++                      unsigned int buffer_size                : 16;   /* transfer buffer size associated with current description*/
++                      unsigned int desc_cnt                   : 6;
++                      unsigned int raid_ctrl_status   : 7; /* pass RAID XOR fetch/store control status to CPU */
++                      unsigned int perr                               : 1;    /* protocol error during processing this descriptor */
++                      unsigned int derr                               : 1;    /* data error during processing this descriptor */
++                      unsigned int own                                : 1; /* owner bit */
++                      #endif
++              } bits;
++      } func_ctrl;
++
++      union flg_status_t
++      {
++              unsigned int bits32;
++              struct bit_004
++              {
++                      #ifdef BIG_ENDIAN
++                      unsigned int bcc                : 16;
++                      unsigned int                    : 13
++                      unsigned int mode               : 3;
++                      #else
++                      unsigned int mode               : 3;
++                      unsigned int                    : 13;
++                      unsigned int bcc                : 16;
++                      #endif
++              } bits_cmd_status;
++      } flg_status;  //Sanders
++
++      unsigned int buf_addr;
++
++      union next_desc_addr_t
++      {
++              unsigned int bits32;
++              struct bits_000c
++              {
++                      #ifdef BIG_ENDIAN
++                      unsigned int ndar               : 28; /* next descriptor address */
++                      unsigned int eofie              : 1; /* end of frame interrupt enable */
++                      unsigned int                    : 1;
++                      unsigned int sof_eof    : 2; /* the position of the descriptor in chain */
++                      #else
++                      unsigned int sof_eof    : 2; /* the position of the descriptor in chain */
++                      unsigned int                    : 1;
++                      unsigned int eofie              : 1; /* end of frame interrupt enable */
++                      unsigned int ndar               : 28; /* next descriptor address */
++                      #endif
++              } bits;
++      } next_desc_addr;
++} RAID_DESCRIPTOR_T;
++
++/******************************************************/
++/*    the offset of RAID SMC register               */
++/******************************************************/
++enum RAID_SMC_REGISTER {
++      RAID_SMC_CMD_REG                = 0xff60,
++      RAID_SMC_STATUS_REG             = 0xff64
++      };
++
++/******************************************************/
++/*    the definition of RAID SMC module register    */
++/******************************************************/
++typedef union
++{
++      unsigned int bits32;
++      struct bits_ff60
++      {
++              #ifdef BIG_ENDIAN
++              unsigned int pat_mode           : 2; /* partition mode selection */
++              unsigned int                            : 14;
++              unsigned int device_id          : 12;
++              unsigned int revision_id        : 4;
++              #else
++              unsigned int revision_id        : 4;
++              unsigned int device_id          : 12;
++              unsigned int                            : 14;
++              unsigned int pat_mode           : 2; /* partition mode selection */
++              #endif
++      } bits;
++} RAID_SMC_CMD;
++
++typedef union
++{
++      unsigned int bits32;
++      struct bits_ff64
++      {
++              #ifdef BIG_ENDIAN
++              unsigned int addr_err1          : 1; /* address is out of range for controller 1 */
++              unsigned int ahb_err1           : 1; /* AHB bus error for controller 1 */
++              unsigned int                            : 14;
++              unsigned int addr_err2          : 1;    /* address is out of range for controller 2 */
++              unsigned int ahb_err2           : 1; /* AHB bus error for controller 2 */
++              unsigned int                            : 14;
++              #else
++              unsigned int                            : 14;
++              unsigned int ahb_err2           : 1; /* AHB bus error for controller 2 */
++              unsigned int addr_err2          : 1;    /* address is out of range for controller 2 */
++              unsigned int                            : 14;
++              unsigned int ahb_err1           : 1; /* AHB bus error for controller 1 */
++              unsigned int addr_err1          : 1; /* address is out of range for controller 1 */
++              #endif
++      } bits;
++} RAID_SMC_STATUS;
++
++typedef struct RAID_S
++{
++      const char *device_name;
++      wait_queue_head_t wait;
++      unsigned int busy;
++      int irq;
++      unsigned int status;
++      RAID_DESCRIPTOR_T *tx_desc;  /*   point to virtual TX descriptor address */
++      RAID_DESCRIPTOR_T *rx_desc;  /* point ot virtual RX descriptor address */
++      RAID_DESCRIPTOR_T *tx_cur_desc; /* current TX descriptor */
++      RAID_DESCRIPTOR_T *rx_cur_desc; /* current RX descriptor */
++      RAID_DESCRIPTOR_T *tx_finished_desc;
++      RAID_DESCRIPTOR_T *rx_finished_desc;
++      RAID_DESCRIPTOR_T *tx_first_desc;
++      RAID_DESCRIPTOR_T *rx_first_desc;
++
++//    unsigned int *tx_buf[TX_DESC_NUM];
++      unsigned int *rx_desc_dma;                      // physical address of rx_descript
++      unsigned int *tx_desc_dma;                      // physical address of tx_descript
++      unsigned int *rx_bufs_dma;
++      unsigned int *tx_bufs_dma;
++
++} RAID_T;
++
++struct reg_ioctl
++{
++      unsigned int reg_addr;
++      unsigned int val_in;
++      unsigned int val_out;
++};
++
++typedef struct dma_ctrl {
++      int sram;
++      int prot;
++      int burst;
++      int bus;
++      int endian;
++      int mode;
++} DMA_CTRL;
++
++
++#ifdef XOR_SW_FILL_IN
++
++#define __XOR(a1, a2) a1 ^= a2
++
++#define GET_BLOCK_2(dst) \
++      __asm__("ldmia  %0, {%1, %2}" \
++              : "=r" (dst), "=r" (a1), "=r" (a2) \
++              : "0" (dst))
++
++#define GET_BLOCK_4(dst) \
++      __asm__("ldmia  %0, {%1, %2, %3, %4}" \
++              : "=r" (dst), "=r" (a1), "=r" (a2), "=r" (a3), "=r" (a4) \
++              : "0" (dst))
++
++#define XOR_BLOCK_2(src) \
++      __asm__("ldmia  %0!, {%1, %2}" \
++              : "=r" (src), "=r" (b1), "=r" (b2) \
++              : "0" (src)); \
++      __XOR(a1, b1); __XOR(a2, b2);
++
++#define XOR_BLOCK_4(src) \
++      __asm__("ldmia  %0!, {%1, %2, %3, %4}" \
++              : "=r" (src), "=r" (b1), "=r" (b2), "=r" (b3), "=r" (b4) \
++              : "0" (src)); \
++      __XOR(a1, b1); __XOR(a2, b2); __XOR(a3, b3); __XOR(a4, b4)
++
++#define PUT_BLOCK_2(dst) \
++      __asm__ __volatile__("stmia     %0!, {%2, %3}" \
++              : "=r" (dst) \
++              : "0" (dst), "r" (a1), "r" (a2))
++
++#define PUT_BLOCK_4(dst) \
++      __asm__ __volatile__("stmia     %0!, {%2, %3, %4, %5}" \
++              : "=r" (dst) \
++              : "0" (dst), "r" (a1), "r" (a2), "r" (a3), "r" (a4))
++
++static void
++xor_arm4regs_2(unsigned long bytes, unsigned long *p1, unsigned long *p2)
++{
++      unsigned int lines = bytes / sizeof(unsigned long) / 4;
++      register unsigned int a1 __asm__("r4");
++      register unsigned int a2 __asm__("r5");
++      register unsigned int a3 __asm__("r6");
++      register unsigned int a4 __asm__("r7");
++      register unsigned int b1 __asm__("r8");
++      register unsigned int b2 __asm__("r9");
++      register unsigned int b3 __asm__("ip");
++      register unsigned int b4 __asm__("lr");
++
++      do {
++              GET_BLOCK_4(p1);
++              XOR_BLOCK_4(p2);
++              PUT_BLOCK_4(p1);
++      } while (--lines);
++}
++
++static void
++xor_arm4regs_3(unsigned long bytes, unsigned long *p1, unsigned long *p2,
++              unsigned long *p3)
++{
++      unsigned int lines = bytes / sizeof(unsigned long) / 4;
++      register unsigned int a1 __asm__("r4");
++      register unsigned int a2 __asm__("r5");
++      register unsigned int a3 __asm__("r6");
++      register unsigned int a4 __asm__("r7");
++      register unsigned int b1 __asm__("r8");
++      register unsigned int b2 __asm__("r9");
++      register unsigned int b3 __asm__("ip");
++      register unsigned int b4 __asm__("lr");
++
++      do {
++              GET_BLOCK_4(p1);
++              XOR_BLOCK_4(p2);
++              XOR_BLOCK_4(p3);
++              PUT_BLOCK_4(p1);
++      } while (--lines);
++}
++
++static void
++xor_arm4regs_4(unsigned long bytes, unsigned long *p1, unsigned long *p2,
++              unsigned long *p3, unsigned long *p4)
++{
++      unsigned int lines = bytes / sizeof(unsigned long) / 2;
++      register unsigned int a1 __asm__("r8");
++      register unsigned int a2 __asm__("r9");
++      register unsigned int b1 __asm__("ip");
++      register unsigned int b2 __asm__("lr");
++
++      do {
++              GET_BLOCK_2(p1);
++              XOR_BLOCK_2(p2);
++              XOR_BLOCK_2(p3);
++              XOR_BLOCK_2(p4);
++              PUT_BLOCK_2(p1);
++      } while (--lines);
++}
++
++static void
++xor_arm4regs_5(unsigned long bytes, unsigned long *p1, unsigned long *p2,
++              unsigned long *p3, unsigned long *p4, unsigned long *p5)
++{
++      unsigned int lines = bytes / sizeof(unsigned long) / 2;
++      register unsigned int a1 __asm__("r8");
++      register unsigned int a2 __asm__("r9");
++      register unsigned int b1 __asm__("ip");
++      register unsigned int b2 __asm__("lr");
++
++      do {
++              GET_BLOCK_2(p1);
++              XOR_BLOCK_2(p2);
++              XOR_BLOCK_2(p3);
++              XOR_BLOCK_2(p4);
++              XOR_BLOCK_2(p5);
++              PUT_BLOCK_2(p1);
++      } while (--lines);
++}
++#endif        //XOR_SW_FILL_IN
++
+Index: linux-2.6.23.16/arch/arm/mach-sl2312/irq.c
+===================================================================
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.23.16/arch/arm/mach-sl2312/irq.c 2008-03-14 11:58:14.702460322 +0200
+@@ -0,0 +1,202 @@
++/*
++ *  linux/arch/arm/mach-epxa10db/irq.c
++ *
++ *  Copyright (C) 2001 Altera Corporation
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++ */
++#include <linux/init.h>
++#include <linux/ioport.h>
++#include <linux/stddef.h>
++#include <linux/list.h>
++#include <linux/sched.h>
++#include <asm/hardware.h>
++#include <asm/irq.h>
++#include <asm/io.h>
++#include <asm/mach/irq.h>
++#include <asm/arch/platform.h>
++#include <asm/arch/int_ctrl.h>
++
++#ifdef CONFIG_PCI
++#include <asm/arch/pci.h>
++#endif
++
++int fixup_irq(unsigned int irq)
++{
++#ifdef CONFIG_PCI
++      if (irq == IRQ_PCI) {
++              return sl2312_pci_get_int_src();
++      }
++#endif
++      return irq;
++}
++
++static void sl2312_ack_irq(unsigned int irq)
++{
++   __raw_writel(1 << irq, IRQ_CLEAR(IO_ADDRESS(SL2312_INTERRUPT_BASE)));
++}
++
++static void sl2312_mask_irq(unsigned int irq)
++{
++      unsigned int mask;
++
++#ifdef CONFIG_PCI
++      if (irq >= PCI_IRQ_OFFSET)
++      {
++              mask = __raw_readl(IRQ_MASK(IO_ADDRESS(SL2312_INTERRUPT_BASE)));
++              mask &= ~IRQ_PCI_MASK ;
++              __raw_writel(mask, IRQ_MASK(IO_ADDRESS(SL2312_INTERRUPT_BASE)));
++              sl2312_pci_mask_irq(irq - PCI_IRQ_OFFSET);
++      }
++      else
++#endif
++      if(irq >= FIQ_OFFSET)
++      {
++           mask = __raw_readl(FIQ_MASK(IO_ADDRESS(SL2312_INTERRUPT_BASE)));
++           mask &= ~(1 << (irq - FIQ_OFFSET));
++           __raw_writel(mask, FIQ_MASK(IO_ADDRESS(SL2312_INTERRUPT_BASE)));
++        }
++        else
++        {
++           mask = __raw_readl(IRQ_MASK(IO_ADDRESS(SL2312_INTERRUPT_BASE)));
++           mask &= ~(1 << irq);
++           __raw_writel(mask, IRQ_MASK(IO_ADDRESS(SL2312_INTERRUPT_BASE)));
++        }
++
++}
++
++static void sl2312_unmask_irq(unsigned int irq)
++{
++      unsigned int mask;
++
++#ifdef CONFIG_PCI
++      if (irq >= PCI_IRQ_OFFSET)
++      {
++              mask = __raw_readl(IRQ_MASK(IO_ADDRESS(SL2312_INTERRUPT_BASE)));
++              mask |= IRQ_PCI_MASK ;
++              __raw_writel(mask, IRQ_MASK(IO_ADDRESS(SL2312_INTERRUPT_BASE)));
++              sl2312_pci_unmask_irq(irq - PCI_IRQ_OFFSET);
++      }
++      else
++#endif
++      if(irq >= FIQ_OFFSET)
++        {
++          mask = __raw_readl(FIQ_MASK(IO_ADDRESS(SL2312_INTERRUPT_BASE)));
++          mask |= (1 << (irq - FIQ_OFFSET));
++          __raw_writel(mask, FIQ_MASK(IO_ADDRESS(SL2312_INTERRUPT_BASE)));
++      }
++        else
++        {
++          mask = __raw_readl(IRQ_MASK(IO_ADDRESS(SL2312_INTERRUPT_BASE)));
++          mask |= (1 << irq);
++          __raw_writel(mask, IRQ_MASK(IO_ADDRESS(SL2312_INTERRUPT_BASE)));
++        }
++}
++
++static struct irq_chip sl2312_level_irq = {
++        .ack            = sl2312_mask_irq,
++        .mask           = sl2312_mask_irq,
++        .unmask         = sl2312_unmask_irq,
++//            .set_type       = ixp4xx_set_irq_type,
++};
++
++static struct irq_chip sl2312_edge_irq = {
++        .ack            = sl2312_ack_irq,
++        .mask           = sl2312_mask_irq,
++        .unmask         = sl2312_unmask_irq,
++//            .set_type       = ixp4xx_set_irq_type,
++};
++
++static struct resource irq_resource = {
++        .name   = "irq_handler",
++        .start  = IO_ADDRESS(SL2312_INTERRUPT_BASE),
++        .end    = IO_ADDRESS(FIQ_STATUS(SL2312_INTERRUPT_BASE))+4,
++};
++
++void __init sl2312_init_irq(void)
++{
++      unsigned int i, mode, level;
++
++    request_resource(&iomem_resource, &irq_resource);
++
++      for (i = 0; i < NR_IRQS; i++)
++      {
++          if((i>=IRQ_TIMER1 && i<=IRQ_TIMER3)||(i>=IRQ_SERIRQ0 && i<=IRQ_SERIRQ_MAX))
++        {
++              set_irq_chip(i, &sl2312_edge_irq);
++              set_irq_handler(i, handle_edge_irq);
++        }
++          else
++        {
++              set_irq_chip(i, &sl2312_level_irq);
++            set_irq_handler(i,handle_level_irq);
++        }
++        set_irq_flags(i, IRQF_VALID | IRQF_PROBE);
++      }
++
++      /* Disable all interrupt */
++      __raw_writel(0,IRQ_MASK(IO_ADDRESS(SL2312_INTERRUPT_BASE)));
++      __raw_writel(0,FIQ_MASK(IO_ADDRESS(SL2312_INTERRUPT_BASE)));
++
++      /* Set interrupt mode */
++    /* emac & ipsec type is level trigger and high active */
++    mode = __raw_readl(IRQ_TMODE(IO_ADDRESS(SL2312_INTERRUPT_BASE)));
++    level = __raw_readl(IRQ_TLEVEL(IO_ADDRESS(SL2312_INTERRUPT_BASE)));
++
++      mode &= ~IRQ_GMAC0_MASK;
++      level &= ~IRQ_GMAC0_MASK;
++
++      mode &= ~IRQ_GMAC1_MASK;
++      level &= ~IRQ_GMAC1_MASK;
++
++      mode &= ~IRQ_IPSEC_MASK;
++      level &= ~IRQ_IPSEC_MASK;
++
++      // for IDE0,1, high active and level trigger
++      mode &= ~IRQ_IDE0_MASK;
++      level &= ~IRQ_IDE0_MASK;
++      mode &= ~IRQ_IDE1_MASK;
++      level &= ~IRQ_IDE1_MASK;
++
++
++      // for PCI, high active and level trigger
++      mode &= ~IRQ_PCI_MASK;
++      level &= ~IRQ_PCI_MASK;
++
++      // for USB, high active and level trigger
++      mode &= ~IRQ_USB0_MASK;
++      level &= ~IRQ_USB0_MASK;
++
++      mode &= ~IRQ_USB1_MASK;
++      level &= ~IRQ_USB1_MASK;
++
++      // for LPC, high active and edge trigger
++      mode |= 0xffff0000;
++      level &= 0x0000ffff;
++
++      // for GPIO, high active and level trigger
++      mode &= ~(IRQ_GPIO_MASK);
++      level &= ~(IRQ_GPIO_MASK);
++
++      mode &= ~(IRQ_GPIO1_MASK);
++      level &= ~(IRQ_GPIO1_MASK);
++
++      mode &= ~(IRQ_GPIO2_MASK);
++      level &= ~(IRQ_GPIO2_MASK);
++
++      __raw_writel(mode,IRQ_TMODE(IO_ADDRESS(SL2312_INTERRUPT_BASE)));
++      __raw_writel(level,IRQ_TLEVEL(IO_ADDRESS(SL2312_INTERRUPT_BASE)));
++
++}
+Index: linux-2.6.23.16/arch/arm/mach-sl2312/lpc.c
+===================================================================
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.23.16/arch/arm/mach-sl2312/lpc.c 2008-03-13 17:48:24.508798285 +0200
+@@ -0,0 +1,125 @@
++/*
++ *
++ * BRIEF MODULE DESCRIPTION
++ *    ITE Semi IT8712 Super I/O functions.
++ *
++ * Copyright 2001 MontaVista Software Inc.
++ * Author: MontaVista Software, Inc.
++ *            ppopov@mvista.com or source@mvista.com
++ *
++ *  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  SOFTWARE  IS PROVIDED   ``AS  IS'' AND   ANY  EXPRESS OR IMPLIED
++ *  WARRANTIES,   INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
++ *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
++ *  NO  EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT, INDIRECT,
++ *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ *  NOT LIMITED   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF
++ *  USE, DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
++ *  ANY THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT
++ *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++ *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ *
++ *  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.,
++ *  675 Mass Ave, Cambridge, MA 02139, USA.
++ */
++#include <linux/kernel.h>
++#include <linux/delay.h>
++#include <asm/io.h>
++#include <asm/types.h>
++#include <asm/arch/it8712.h>
++#include <linux/init.h>
++#include <asm/arch/hardware.h>
++
++#ifndef TRUE
++#define TRUE 1
++#endif
++
++#ifndef FALSE
++#define FALSE 0
++#endif
++
++
++// MB PnP configuration register
++#define LPC_KEY_ADDR  (IO_ADDRESS(SL2312_LPC_IO_BASE) + 0x2e)
++#define LPC_DATA_ADDR (IO_ADDRESS(SL2312_LPC_IO_BASE) + 0x2f)
++
++#define LPC_BUS_CTRL                  *(volatile unsigned char*) (IO_ADDRESS(SL2312_LPC_HOST_BASE) + 0)
++#define LPC_BUS_STATUS                        *(volatile unsigned char*) (IO_ADDRESS(SL2312_LPC_HOST_BASE) + 2)
++#define LPC_SERIAL_IRQ_CTRL           *(volatile unsigned char*) (IO_ADDRESS(SL2312_LPC_HOST_BASE) + 4)
++
++int it8712_exist;
++
++static void LPCEnterMBPnP(void)
++{
++      int i;
++      unsigned char key[4] = {0x87, 0x01, 0x55, 0x55};
++
++      for (i = 0; i<4; i++)
++              outb(key[i], LPC_KEY_ADDR);
++
++}
++
++static void LPCExitMBPnP(void)
++{
++      outb(0x02, LPC_KEY_ADDR);
++      outb(0x02, LPC_DATA_ADDR);
++}
++
++void LPCSetConfig(char LdnNumber, char Index, char data)
++{
++      LPCEnterMBPnP();                                // Enter IT8712 MB PnP mode
++      outb(0x07, LPC_KEY_ADDR);
++      outb(LdnNumber, LPC_DATA_ADDR);
++      outb(Index, LPC_KEY_ADDR);
++      outb(data, LPC_DATA_ADDR);
++      LPCExitMBPnP();
++}
++
++char LPCGetConfig(char LdnNumber, char Index)
++{
++      char rtn;
++
++      LPCEnterMBPnP();                                // Enter IT8712 MB PnP mode
++      outb(0x07, LPC_KEY_ADDR);
++      outb(LdnNumber, LPC_DATA_ADDR);
++      outb(Index, LPC_KEY_ADDR);
++      rtn = inb(LPC_DATA_ADDR);
++      LPCExitMBPnP();
++      return rtn;
++}
++
++static int SearchIT8712(void)
++{
++      unsigned char Id1, Id2;
++      unsigned short Id;
++
++      LPCEnterMBPnP();
++      outb(0x20, LPC_KEY_ADDR); /* chip id byte 1 */
++      Id1 = inb(LPC_DATA_ADDR);
++      outb(0x21, LPC_KEY_ADDR); /* chip id byte 2 */
++      Id2 = inb(LPC_DATA_ADDR);
++      Id = (Id1 << 8) | Id2;
++      LPCExitMBPnP();
++      if (Id == 0x8712)
++              return TRUE;
++      else
++              return FALSE;
++}
++
++int InitLPCInterface(void)
++{
++      LPC_BUS_CTRL = 0xc0;
++      LPC_SERIAL_IRQ_CTRL = 0xc0;
++      mdelay(1);              // wait for 1 serial IRQ cycle
++      LPC_SERIAL_IRQ_CTRL = 0x80;
++      it8712_exist = SearchIT8712();
++      printk("IT8712 %s exist\n", it8712_exist?"":"doesn't");
++      return 0;
++}
++
++//__initcall(InitLPCInterface);
+Index: linux-2.6.23.16/arch/arm/mach-sl2312/mm.c
+===================================================================
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.23.16/arch/arm/mach-sl2312/mm.c  2008-03-13 17:48:24.508798285 +0200
+@@ -0,0 +1,80 @@
++/*
++ *  linux/arch/arm/mach-epxa10db/mm.c
++ *
++ *  MM routines for Altera'a Epxa10db board
++ *
++ *  Copyright (C) 2001 Altera Corporation
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++ */
++#include <linux/sched.h>
++#include <linux/mm.h>
++#include <linux/init.h>
++
++#include <asm/hardware.h>
++#include <asm/io.h>
++#include <asm/pgtable.h>
++#include <asm/page.h>
++#include <asm/sizes.h>
++
++#include <asm/mach/map.h>
++
++/* Page table mapping for I/O region */
++static struct map_desc sl2312_io_desc[] __initdata = {
++#ifdef CONFIG_GEMINI_IPI
++{__phys_to_virt(CPU_1_MEM_BASE),         __phys_to_pfn(CPU_1_MEM_BASE),        SZ_64M,  MT_MEMORY},
++#endif
++{IO_ADDRESS(SL2312_SRAM_BASE),         __phys_to_pfn(SL2312_SRAM_BASE),        SZ_512K,  MT_DEVICE},
++{IO_ADDRESS(SL2312_DRAM_CTRL_BASE),    __phys_to_pfn(SL2312_DRAM_CTRL_BASE),   SZ_512K,  MT_DEVICE},
++{IO_ADDRESS(SL2312_GLOBAL_BASE),       __phys_to_pfn(SL2312_GLOBAL_BASE),      SZ_512K,  MT_DEVICE},
++{IO_ADDRESS(SL2312_WAQTCHDOG_BASE),    __phys_to_pfn(SL2312_WAQTCHDOG_BASE),   SZ_512K,  MT_DEVICE},
++{IO_ADDRESS(SL2312_UART_BASE),         __phys_to_pfn(SL2312_UART_BASE),        SZ_512K,  MT_DEVICE},
++{IO_ADDRESS(SL2312_TIMER_BASE),        __phys_to_pfn(SL2312_TIMER_BASE),       SZ_512K,  MT_DEVICE},
++{IO_ADDRESS(SL2312_LCD_BASE),          __phys_to_pfn(SL2312_LCD_BASE),         SZ_512K,  MT_DEVICE},
++{IO_ADDRESS(SL2312_RTC_BASE),          __phys_to_pfn(SL2312_RTC_BASE),         SZ_512K,  MT_DEVICE},
++{IO_ADDRESS(SL2312_SATA_BASE),         __phys_to_pfn(SL2312_SATA_BASE),        SZ_512K,  MT_DEVICE},
++{IO_ADDRESS(SL2312_LPC_HOST_BASE),     __phys_to_pfn(SL2312_LPC_HOST_BASE),    SZ_512K,  MT_DEVICE},
++{IO_ADDRESS(SL2312_LPC_IO_BASE),       __phys_to_pfn(SL2312_LPC_IO_BASE),      SZ_512K,  MT_DEVICE},
++{IO_ADDRESS(SL2312_INTERRUPT_BASE),    __phys_to_pfn(SL2312_INTERRUPT_BASE),   SZ_512K,  MT_DEVICE},
++{IO_ADDRESS(SL2312_INTERRUPT1_BASE),   __phys_to_pfn(SL2312_INTERRUPT1_BASE),  SZ_512K,  MT_DEVICE},
++{IO_ADDRESS(SL2312_SSP_CTRL_BASE),     __phys_to_pfn(SL2312_SSP_CTRL_BASE),    SZ_512K,  MT_DEVICE},
++{IO_ADDRESS(SL2312_POWER_CTRL_BASE),   __phys_to_pfn(SL2312_POWER_CTRL_BASE),  SZ_512K,  MT_DEVICE},
++{IO_ADDRESS(SL2312_CIR_BASE),          __phys_to_pfn(SL2312_CIR_BASE),         SZ_512K,  MT_DEVICE},
++{IO_ADDRESS(SL2312_GPIO_BASE),         __phys_to_pfn(SL2312_GPIO_BASE),        SZ_512K,  MT_DEVICE},
++{IO_ADDRESS(SL2312_GPIO_BASE1),        __phys_to_pfn(SL2312_GPIO_BASE1),       SZ_512K,  MT_DEVICE},
++{IO_ADDRESS(SL2312_GPIO_BASE2),        __phys_to_pfn(SL2312_GPIO_BASE2),       SZ_512K,  MT_DEVICE},
++{IO_ADDRESS(SL2312_PCI_IO_BASE),         __phys_to_pfn(SL2312_PCI_IO_BASE),      SZ_512K,  MT_DEVICE},
++{IO_ADDRESS(SL2312_PCI_MEM_BASE),        __phys_to_pfn(SL2312_PCI_MEM_BASE),     SZ_512K,  MT_DEVICE},
++#ifdef CONFIG_NET_SL351X
++{IO_ADDRESS(SL2312_TOE_BASE),         __phys_to_pfn(SL2312_TOE_BASE)       ,   SZ_512K,  MT_DEVICE},
++#endif
++{IO_ADDRESS(SL2312_GMAC0_BASE),              __phys_to_pfn(SL2312_GMAC0_BASE),           SZ_512K,  MT_DEVICE},
++{IO_ADDRESS(SL2312_GMAC1_BASE),              __phys_to_pfn(SL2312_GMAC1_BASE),           SZ_512K,  MT_DEVICE},
++{IO_ADDRESS(SL2312_SECURITY_BASE),     __phys_to_pfn(SL2312_SECURITY_BASE),    SZ_512K,  MT_DEVICE},
++{IO_ADDRESS(SL2312_IDE0_BASE),         __phys_to_pfn(SL2312_IDE0_BASE),        SZ_512K,  MT_DEVICE},
++{IO_ADDRESS(SL2312_IDE1_BASE),         __phys_to_pfn(SL2312_IDE1_BASE),        SZ_512K,  MT_DEVICE},
++{IO_ADDRESS(SL2312_RAID_BASE),         __phys_to_pfn(SL2312_RAID_BASE),        SZ_512K,  MT_DEVICE},
++{IO_ADDRESS(SL2312_FLASH_CTRL_BASE),   __phys_to_pfn(SL2312_FLASH_CTRL_BASE),  SZ_512K,  MT_DEVICE},
++{IO_ADDRESS(SL2312_DRAM_CTRL_BASE),    __phys_to_pfn(SL2312_DRAM_CTRL_BASE),   SZ_512K,  MT_DEVICE},
++{IO_ADDRESS(SL2312_GENERAL_DMA_BASE),  __phys_to_pfn(SL2312_GENERAL_DMA_BASE), SZ_512K,  MT_DEVICE},
++{IO_ADDRESS(SL2312_USB0_BASE),         __phys_to_pfn(SL2312_USB_BASE),         SZ_512K,  MT_DEVICE},
++{IO_ADDRESS(SL2312_USB1_BASE),         __phys_to_pfn(SL2312_USB1_BASE),        SZ_512K,  MT_DEVICE},
++{FLASH_VADDR(SL2312_FLASH_BASE),       __phys_to_pfn(SL2312_FLASH_BASE),       SZ_16M,    MT_DEVICE},
++};
++
++void __init sl2312_map_io(void)
++{
++      iotable_init(sl2312_io_desc, ARRAY_SIZE(sl2312_io_desc));
++}
+Index: linux-2.6.23.16/arch/arm/mach-sl2312/pci.c
+===================================================================
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.23.16/arch/arm/mach-sl2312/pci.c 2008-03-14 12:56:27.401497897 +0200
+@@ -0,0 +1,359 @@
++/*
++ *  linux/arch/arm/mach-sl2312/pci_sl2312.c
++ *
++ *  PCI functions for sl2312 host PCI bridge
++ *
++ *  Copyright (C) 2003 StorLink Corp.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++ */
++#include <linux/sched.h>
++#include <linux/kernel.h>
++#include <linux/pci.h>
++#include <linux/ptrace.h>
++#include <linux/slab.h>
++#include <linux/ioport.h>
++#include <linux/interrupt.h>
++#include <linux/spinlock.h>
++#include <linux/init.h>
++
++#include <asm/sizes.h>
++#include <asm/hardware.h>
++#include <asm/irq.h>
++#include <asm/system.h>
++#include <asm/mach/pci.h>
++#include <asm/mach/irq.h>
++#include <asm/mach-types.h>
++
++#include <asm/arch/pci.h>
++
++//#define DEBUG
++
++// sl2312 PCI bridge access routines
++
++#define PCI_IOSIZE_REG        (*(volatile unsigned long *) (IO_ADDRESS(SL2312_PCI_IO_BASE)))
++#define PCI_PROT_REG  (*(volatile unsigned long *) (IO_ADDRESS(SL2312_PCI_IO_BASE) + 0x04))
++#define PCI_CTRL_REG  (*(volatile unsigned long *) (IO_ADDRESS(SL2312_PCI_IO_BASE) + 0x08))
++#define PCI_SOFTRST_REG       (*(volatile unsigned long *) (IO_ADDRESS(SL2312_PCI_IO_BASE) + 0x10))
++#define PCI_CONFIG_REG        (*(volatile unsigned long *) (IO_ADDRESS(SL2312_PCI_IO_BASE) + 0x28))
++#define PCI_DATA_REG  (*(volatile unsigned long *) (IO_ADDRESS(SL2312_PCI_IO_BASE) + 0x2C))
++
++static spinlock_t sl2312_pci_lock = SPIN_LOCK_UNLOCKED;
++// for initialize PCI devices
++struct resource pci_ioport_resource = {
++              .name = "PCI I/O Space",
++              .start = IO_ADDRESS(SL2312_PCI_IO_BASE) + 0x100,
++              .end = IO_ADDRESS(SL2312_PCI_IO_BASE) + SZ_512K - 1,
++              .flags = IORESOURCE_IO,
++};
++struct resource pci_iomem_resource = {
++              .name = "PCI Mem Space",
++              .start = SL2312_PCI_MEM_BASE,
++              .end = SL2312_PCI_MEM_BASE + SZ_128M - 1,
++              .flags = IORESOURCE_MEM,
++};
++
++static int sl2312_read_config(struct pci_bus *bus, unsigned int devfn, int where,int size, u32 *val)
++{
++      unsigned long addr,data;
++      unsigned long flags;
++
++      spin_lock_irqsave(&sl2312_pci_lock, flags);
++    addr = 0x80000000 | (PCI_SLOT(devfn) << 11) | (PCI_FUNC(devfn) << 8) | (where & ~3);
++      PCI_CONFIG_REG = addr;
++      data = PCI_DATA_REG;
++
++      switch (size) {
++      case 1:
++          *val = (u8) (data >> ((where & 0x03) * 8));
++              break;
++      case 2:
++          *val = (u16) (data >> ((where & 0x02) * 8));
++              break;
++      case 4:
++          *val = data;
++      if ((where >= 0x10) && (where <= 0x24)) {
++              if ((*val & 0xfff00000) == SL2312_PCI_IO_BASE) {
++                      *val &= 0x000fffff;
++                      *val |= IO_ADDRESS(SL2312_PCI_IO_BASE);
++              }
++      }
++              break;
++      }
++      spin_unlock_irqrestore(&sl2312_pci_lock, flags);
++//    printk("READ==>slot=%d fn=%d where=%d value=%x\n",PCI_SLOT(devfn),PCI_FUNC(devfn),where,*val);
++      return PCIBIOS_SUCCESSFUL;
++}
++
++static int sl2312_write_config(struct pci_bus *bus, unsigned int devfn, int where,int size, u32 val)
++{
++      unsigned long addr,data;
++      unsigned long flags;
++
++      spin_lock_irqsave(&sl2312_pci_lock, flags);
++    addr = 0x80000000 | (PCI_SLOT(devfn) << 11) | (PCI_FUNC(devfn) << 8) | (where & ~3);
++      PCI_CONFIG_REG = addr;
++      data = PCI_DATA_REG;
++
++      switch (size) {
++      case 1:
++      data &= ~(0xff << ((where & 0x03) * 8));
++      data |= (val << ((where & 0x03) * 8));
++      PCI_DATA_REG = data;
++              break;
++      case 2:
++      data &= ~(0xffff << ((where & 0x02) * 8));
++      data |= (val << ((where & 0x02) * 8));
++      PCI_DATA_REG = data;
++              break;
++      case 4:
++      if ((where >= 0x10) && (where <= 0x24)) {
++              if ((val & 0xfff00000) == IO_ADDRESS(SL2312_PCI_IO_BASE)) {
++                      val &= 0x000fffff;
++                      val |= SL2312_PCI_IO_BASE;
++              }
++      }
++          PCI_DATA_REG = val;
++              break;
++      }
++      spin_unlock_irqrestore(&sl2312_pci_lock, flags);
++
++//    printk("WRITE==> slot=%d fn=%d where=%d value=%x \n",PCI_SLOT(devfn),PCI_FUNC(devfn),where,val);
++      return PCIBIOS_SUCCESSFUL;
++}
++
++static struct pci_ops sl2312_pci_ops = {
++      .read   = sl2312_read_config,
++      .write  = sl2312_write_config,
++};
++
++
++int __init sl2312_pci_setup_resources(struct resource **resource)
++{
++      PCI_IOSIZE_REG = 0;             // 1M IO size
++      PCI_CTRL_REG = 0x06;
++
++      resource[0] = &pci_ioport_resource;
++      resource[1] = &pci_iomem_resource;
++      resource[2] = NULL;
++
++      return 1;
++}
++
++//static int sl2312_pci_fault(unsigned long addr, struct pt_regs *regs)
++//{
++//    return 1;
++//}
++
++
++/**********************************************************************
++ * MASK(disable) PCI interrupt
++ *    0: PCI INTA, 1: PCI INTB, ...           // for Linux interrupt routing
++ *   16: PERR                                                         // for PCI module internal use
++ *   17: SERR,.. respect to PCI CTRL2 REG
++ **********************************************************************/
++void sl2312_pci_mask_irq(unsigned int irq)
++{
++    struct pci_bus bus;
++      unsigned int tmp;
++
++    bus.number = 0;
++    sl2312_read_config(&bus, 0, SL2312_PCI_CTRL2, 4, &tmp);
++      if (irq < 16) {                                         // for linux int routing
++              tmp &= ~(1 << (irq + 16 + 6));
++      }
++      else {
++              tmp &= ~(1 << irq);
++      }
++    sl2312_write_config(&bus, 0, SL2312_PCI_CTRL2, 4, tmp);
++}
++
++/* UNMASK(enable) PCI interrupt */
++void sl2312_pci_unmask_irq(unsigned int irq)
++{
++    struct pci_bus bus;
++      unsigned int tmp;
++
++    bus.number = 0;
++    sl2312_read_config(&bus, 0, SL2312_PCI_CTRL2, 4, &tmp);
++      if (irq < 16) {                                         // for linux int routing
++              tmp |= (1 << (irq + 16 + 6));
++      }
++      else {
++              tmp |= (1 << irq);
++      }
++    sl2312_write_config(&bus, 0, SL2312_PCI_CTRL2, 4, tmp);
++}
++
++/* Get PCI interrupt source */
++int sl2312_pci_get_int_src(void)
++{
++    struct pci_bus bus;
++      unsigned int tmp=0;
++
++    bus.number = 0;
++    sl2312_read_config(&bus, 0, SL2312_PCI_CTRL2, 4, &tmp);
++      if (tmp & (1 << 28)) {          // PCI INTA
++        sl2312_write_config(&bus, 0, SL2312_PCI_CTRL2, 4, tmp);
++              return IRQ_PCI_INTA;
++      }
++      if (tmp & (1 << 29)) {          // PCI INTB
++        sl2312_write_config(&bus, 0, SL2312_PCI_CTRL2, 4, tmp);
++              return IRQ_PCI_INTB;
++      }
++      if (tmp & (1 << 30)) {          // PCI INTC
++        sl2312_write_config(&bus, 0, SL2312_PCI_CTRL2, 4, tmp);
++              return IRQ_PCI_INTC;
++      }
++      if (tmp & (1 << 31)) {          // PCI INTD
++        sl2312_write_config(&bus, 0, SL2312_PCI_CTRL2, 4, tmp);
++              return IRQ_PCI_INTD;
++      }
++      // otherwise, it should be a PCI error
++      return IRQ_PCI;
++}
++
++static irqreturn_t sl2312_pci_irq(int irq, void *devid)
++{
++    struct irq_desc *desc;
++      struct irqaction *action;
++      int retval = 0;
++
++    return 1;
++
++      irq = sl2312_pci_get_int_src();
++      desc = &irq_desc[irq];
++      action = desc->action;
++      do {
++              retval |= action->handler(irq, devid);
++              action = action->next;
++      } while (action);
++
++    return 1;
++}
++
++//extern int (*external_fault)(unsigned long addr, struct pt_regs *regs);
++
++void __init sl2312_pci_preinit(void)
++{
++    struct pci_bus bus;
++      unsigned long flags;
++      unsigned int temp;
++      int ret;
++
++      /*
++       * Hook in our fault handler for PCI errors
++       */
++//    external_fault = sl2312_pci_fault;
++
++      spin_lock_irqsave(&sl2312_pci_lock, flags);
++
++      /*
++       * Grab the PCI interrupt.
++       */
++      ret = request_irq(IRQ_PCI, sl2312_pci_irq, 0, "sl2312 pci int", NULL);
++      if (ret)
++              printk(KERN_ERR "PCI: unable to grab PCI error "
++                     "interrupt: %d\n", ret);
++
++      spin_unlock_irqrestore(&sl2312_pci_lock, flags);
++
++      // setup pci bridge
++    bus.number = 0;   /* device 0, function 0 */
++      temp = (SL2312_PCI_DMA_MEM1_BASE & 0xfff00000) | (SL2312_PCI_DMA_MEM1_SIZE << 16);
++    sl2312_write_config(&bus, 0, SL2312_PCI_MEM1_BASE_SIZE, 4, temp);
++}
++
++/*
++ *    No swizzle on SL2312
++ */
++static u8 __init sl2312_pci_swizzle(struct pci_dev *dev, u8 *pinp)
++{
++      return PCI_SLOT(dev->devfn);
++}
++
++/*
++ * map the specified device/slot/pin to an IRQ.  This works out such
++ * that slot 9 pin 1 is INT0, pin 2 is INT1, and slot 10 pin 1 is INT1.
++ */
++static int __init sl2312_pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
++{
++      int intnr = ((slot  + (pin - 1)) & 3) + 4;  /* the IRQ number of PCI bridge */
++
++      // printk("%s : slot = %d  pin = %d \n",__func__,slot,pin);
++    switch (slot)
++    {
++        case 12:
++              if (pin==1)
++              {
++                      intnr = 3;
++                  }
++                  else
++                  {
++                      intnr = 0;
++                  }
++            break;
++        case 11:
++                  intnr = (2 + (pin - 1)) & 3;
++            break;
++        case 10:
++                  intnr = (1 + (pin - 1)) & 3;
++            break;
++        case  9:
++                  intnr = (pin - 1) & 3;
++            break;
++    }
++//    if (slot == 10)
++//            intnr = (1 + (pin - 1)) & 3;
++//    else if (slot == 9)
++//            intnr = (pin - 1) & 3;
++      return (IRQ_PCI_INTA + intnr);
++}
++
++struct pci_bus * __init sl2312_pci_scan_bus(int nr, struct pci_sys_data *sysdata)
++{
++      return (pci_scan_bus(0, &sl2312_pci_ops, sysdata));
++
++}
++
++int __init sl2312_pci_setup(int nr, struct pci_sys_data *sys)
++{
++      int ret = 0;
++
++      if (nr == 0) {
++              ret = sl2312_pci_setup_resources(sys->resource);
++      }
++
++      return ret;
++}
++
++
++struct hw_pci sl2312_pci __initdata = {
++      .setup          =       sl2312_pci_setup,
++      .preinit                =       sl2312_pci_preinit,
++      .nr_controllers =   1,
++      .swizzle                =       sl2312_pci_swizzle,
++      .map_irq                =       sl2312_pci_map_irq,
++      .scan           =   sl2312_pci_scan_bus,
++};
++
++static int __init sl2312_pci_init(void)
++{
++      if (machine_is_sl2312())
++              pci_common_init(&sl2312_pci);
++      return 0;
++}
++
++subsys_initcall(sl2312_pci_init);
+Index: linux-2.6.23.16/arch/arm/mach-sl2312/sl2312-otg-1.c
+===================================================================
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.23.16/arch/arm/mach-sl2312/sl2312-otg-1.c        2008-03-15 16:53:18.340655940 +0200
+@@ -0,0 +1,64 @@
++/*
++ *  linux/arch/arm/mach-pxa/sl2312.c
++ *
++ *  Author:   Nicolas Pitre
++ *  Created:  Nov 05, 2002
++ *  Copyright:        MontaVista Software Inc.
++ *
++ * Code specific to sl2312 aka Bulverde.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/pm.h>
++#include <linux/device.h>
++#include "asm/arch/sl2312.h"
++#include "asm/arch/irqs.h"
++#include <asm/hardware.h>
++#include <asm/irq.h>
++#include <linux/platform_device.h>
++
++/*
++ * device registration specific to sl2312.
++ */
++
++static u64 sl2312_dmamask_1 = 0xffffffffUL;
++
++static struct resource sl2312_otg_resources_1[] = {
++      [0] = {
++              .start  = 0x69000000,
++              .end    = 0x69000fff,
++              .flags  = IORESOURCE_MEM,
++      },
++      [1] = {
++              .start  = IRQ_USB1,
++              .end    = IRQ_USB1,
++              .flags  = IORESOURCE_IRQ,
++      },
++};
++
++static struct platform_device ehci_1_device = {
++      .name           = "ehci-hcd-FOTG2XX",
++      .id             = -1,
++      .dev            = {
++              .dma_mask = &sl2312_dmamask_1,
++              .coherent_dma_mask = 0xffffffff,
++      },
++      .num_resources  = ARRAY_SIZE(sl2312_otg_resources_1),
++      .resource       = sl2312_otg_resources_1,
++};
++
++static struct platform_device *devices[] __initdata = {
++      &ehci_1_device,
++};
++
++static int __init sl2312_1_init(void)
++{
++      return platform_add_devices(devices, ARRAY_SIZE(devices));
++}
++
++subsys_initcall(sl2312_1_init);
+Index: linux-2.6.23.16/arch/arm/mach-sl2312/sl2312-otg.c
+===================================================================
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.23.16/arch/arm/mach-sl2312/sl2312-otg.c  2008-03-14 12:33:51.324219457 +0200
+@@ -0,0 +1,87 @@
++/*
++ *  linux/arch/arm/mach-pxa/sl2312.c
++ *
++ *  Author:   Nicolas Pitre
++ *  Created:  Nov 05, 2002
++ *  Copyright:        MontaVista Software Inc.
++ *
++ * Code specific to sl2312 aka Bulverde.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/pm.h>
++#include <linux/device.h>
++#include "asm/arch/sl2312.h"
++#include "asm/arch/irqs.h"
++#include <asm/hardware.h>
++#include <asm/irq.h>
++#include <linux/platform_device.h>
++
++/*
++ * device registration specific to sl2312.
++ */
++
++static u64 sl2312_dmamask = 0xffffffffUL;
++
++static struct resource sl2312_otg_resources_1[] = {
++      [0] = {
++              .start  = 0x68000000,
++              .end    = 0x68000fff,
++              .flags  = IORESOURCE_MEM,
++      },
++      [1] = {
++              .start  = IRQ_USB0,
++              .end    = IRQ_USB0,
++              .flags  = IORESOURCE_IRQ,
++      },
++};
++static struct resource sl2312_otg_resources_2[] = {
++      [2] = {
++              .start  = 0x69000000,
++              .end    = 0x69000fff,
++              .flags  = IORESOURCE_MEM,
++      },
++      [3] = {
++              .start  = IRQ_USB1,
++              .end    = IRQ_USB1,
++              .flags  = IORESOURCE_IRQ,
++      },
++};
++
++static struct platform_device ehci_device_1 = {
++      .name           = "ehci-hcd-FOTG2XX",
++      .id             = 1,
++      .dev            = {
++              .dma_mask = &sl2312_dmamask,
++              .coherent_dma_mask = 0xffffffff,
++      },
++      .num_resources  = ARRAY_SIZE(sl2312_otg_resources_1),
++      .resource       = sl2312_otg_resources_1,
++};
++
++static struct platform_device ehci_device_2 = {
++      .name           = "ehci-hcd-FOTG2XX",
++      .id             = 2,
++      .dev            = {
++              .dma_mask = &sl2312_dmamask,
++              .coherent_dma_mask = 0xffffffff,
++      },
++      .num_resources  = ARRAY_SIZE(sl2312_otg_resources_2),
++      .resource       = sl2312_otg_resources_2,
++};
++
++static struct platform_device *devices[] __initdata = {
++      &ehci_device_1, /* &ehci_device_2, */
++};
++
++static int __init sl2312_init(void)
++{
++      return platform_add_devices(devices, ARRAY_SIZE(devices));
++}
++
++subsys_initcall(sl2312_init);
+Index: linux-2.6.23.16/arch/arm/mach-sl2312/sl3516_device.c
+===================================================================
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.23.16/arch/arm/mach-sl2312/sl3516_device.c       2008-03-14 12:19:14.774267722 +0200
+@@ -0,0 +1,89 @@
++/*
++ *  linux/arch/arm/mach-2312/sl3516_device.c
++ *
++ *  Author:   Nicolas Pitre
++ *  Created:  Nov 05, 2002
++ *  Copyright:        MontaVista Software Inc.
++ *
++ * Code specific to sl2312 aka Bulverde.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/pm.h>
++#include <linux/device.h>
++#include <linux/platform_device.h>
++#include "asm/arch/sl2312.h"
++#include "asm/arch/irqs.h"
++#include <asm/hardware.h>
++#include <asm/irq.h>
++
++/*
++ * device registration specific to sl2312.
++ */
++
++static u64 sl3516_dmamask = 0xffffffffUL;
++
++static struct resource sl3516_sata_resources[] = {
++      [0] = {
++              .start  = 0x63400000,
++              .end    = 0x63400040,
++              .flags  = IORESOURCE_MEM,
++      },
++      [1] = {
++              .start  = IRQ_IDE1,
++              .end    = IRQ_IDE1,
++              .flags  = IORESOURCE_IRQ,
++      },
++};
++
++static struct platform_device sata_device = {
++      .name           = "lepus-sata",
++      .id             = -1,
++      .dev            = {
++              .dma_mask = &sl3516_dmamask,
++              .coherent_dma_mask = 0xffffffff,
++      },
++      .num_resources  = ARRAY_SIZE(sl3516_sata_resources),
++      .resource       = sl3516_sata_resources,
++};
++
++static struct resource sl3516_sata0_resources[] = {
++      [0] = {
++              .start  = 0x63000000,
++              .end    = 0x63000040,
++              .flags  = IORESOURCE_MEM,
++      },
++      [1] = {
++              .start  = IRQ_IDE0,
++              .end    = IRQ_IDE0,
++              .flags  = IORESOURCE_IRQ,
++      },
++};
++
++static struct platform_device sata0_device = {
++      .name           = "lepus-sata0",
++      .id             = -1,
++      .dev            = {
++              .dma_mask = &sl3516_dmamask,
++              .coherent_dma_mask = 0xffffffff,
++      },
++      .num_resources  = ARRAY_SIZE(sl3516_sata0_resources),
++      .resource       = sl3516_sata0_resources,
++};
++
++static struct platform_device *sata_devices[] __initdata = {
++      &sata_device,
++      &sata0_device,
++};
++
++static int __init sl3516_init(void)
++{
++      return platform_add_devices(sata_devices, ARRAY_SIZE(sata_devices));
++}
++
++subsys_initcall(sl3516_init);
+Index: linux-2.6.23.16/arch/arm/mach-sl2312/time.c
+===================================================================
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.23.16/arch/arm/mach-sl2312/time.c        2008-03-14 12:16:06.263525107 +0200
+@@ -0,0 +1,134 @@
++/*
++ *  linux/include/asm-arm/arch-epxa10db/time.h
++ *
++ *  Copyright (C) 2001 Altera Corporation
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++ */
++#include <linux/interrupt.h>
++#include <linux/irq.h>
++#include <asm/io.h>
++#include <asm/system.h>
++#include <asm/leds.h>
++#include <asm/arch/hardware.h>
++#include <asm/mach/time.h>
++#define TIMER_TYPE (volatile unsigned int*)
++#include <asm/arch/timer.h>
++// #define FIQ_PLUS     1
++
++
++/*
++ * IRQ handler for the timer
++ */
++static irqreturn_t sl2312_timer_interrupt(int irq, void *dev_id)
++{
++//        unsigned int led;
++      // ...clear the interrupt
++#ifdef FIQ_PLUS
++      *((volatile unsigned int *)FIQ_CLEAR(IO_ADDRESS(SL2312_INTERRUPT_BASE))) |= (unsigned int)(IRQ_TIMER1_MASK);
++#else
++      *((volatile unsigned int *)IRQ_CLEAR(IO_ADDRESS(SL2312_INTERRUPT_BASE))) |= (unsigned int)(IRQ_TIMER2_MASK);
++#endif
++
++#if 0
++        if(!(jiffies % HZ))
++        {
++            led = jiffies / HZ;
++//            printk("ticks %x \n", led);
++          }
++      do_leds();
++      do_timer(regs);
++      do_profile(regs);
++#endif
++    timer_tick();
++    return IRQ_HANDLED;
++}
++
++static struct irqaction sl2312_timer_irq = {
++      .name           = "SL2312 Timer Tick",
++      .flags          = IRQF_DISABLED | IRQF_TIMER,
++      .handler        = sl2312_timer_interrupt,
++};
++
++unsigned long sl2312_gettimeoffset (void)
++{
++    return 0L;
++}
++
++/*
++ * Set up timer interrupt, and return the current time in seconds.
++ */
++void __init sl2312_time_init(void)
++{
++      // For clock rate adjusting
++      unsigned int tick_rate=0;
++
++#ifdef CONFIG_SL3516_ASIC
++      unsigned int clock_rate_base = 130000000;
++      unsigned int reg_v=0;
++
++      //--> Add by jason for clock adjust
++      reg_v = readl(IO_ADDRESS((SL2312_GLOBAL_BASE+GLOBAL_STATUS)));
++      reg_v >>= 15;
++      tick_rate = (clock_rate_base + (reg_v & 0x07)*10000000);
++
++      //  FPGA use AHB bus tick rate
++      printk("Bus: %dMHz",tick_rate/1000000);
++
++      tick_rate /= 6;                         // APB bus run AHB*(1/6)
++
++      switch((reg_v>>3)&3){
++              case 0: printk("(1/1)\n") ;
++                                      break;
++              case 1: printk("(3/2)\n") ;
++                                      break;
++              case 2: printk("(24/13)\n") ;
++                                      break;
++              case 3: printk("(2/1)\n") ;
++                                      break;
++      }
++      //<--
++#else
++      printk("Bus: %dMHz(1/1)\n",CLOCK_TICK_RATE/1000000);            // FPGA use 20MHz
++      tick_rate = CLOCK_TICK_RATE;
++#endif
++
++
++      /*
++       * Make irqs happen for the system timer
++       */
++      // initialize timer interrupt
++      // low active and edge trigger
++#ifdef FIQ_PLUS
++      *((volatile unsigned int *)FIQ_TMODE(IO_ADDRESS(SL2312_INTERRUPT_BASE))) |= (unsigned int)(IRQ_TIMER1_MASK);
++      *((volatile unsigned int *)FIQ_LEVEL(IO_ADDRESS(SL2312_INTERRUPT_BASE))) |= (unsigned int)(IRQ_TIMER1_MASK);
++      setup_irq(IRQ_TIMER1, &sl2312_timer_irq);
++      /* Start the timer */
++      *TIMER_COUNT(IO_ADDRESS(SL2312_TIMER1_BASE))=(unsigned int)(tick_rate/HZ);
++      *TIMER_LOAD(IO_ADDRESS(SL2312_TIMER1_BASE))=(unsigned int)(tick_rate/HZ);
++      *TIMER_CR(IO_ADDRESS(SL2312_TIMER1_BASE))=(unsigned int)(TIMER_1_CR_ENABLE_MSK|TIMER_1_CR_INT_MSK);
++#else
++      *((volatile unsigned int *)IRQ_TMODE(IO_ADDRESS(SL2312_INTERRUPT_BASE))) |= (unsigned int)(IRQ_TIMER2_MASK);
++      *((volatile unsigned int *)IRQ_TLEVEL(IO_ADDRESS(SL2312_INTERRUPT_BASE))) |= (unsigned int)(IRQ_TIMER2_MASK);
++      setup_irq(IRQ_TIMER2, &sl2312_timer_irq);
++      /* Start the timer */
++      *TIMER_COUNT(IO_ADDRESS(SL2312_TIMER2_BASE))=(unsigned int)(tick_rate/HZ);
++      *TIMER_LOAD(IO_ADDRESS(SL2312_TIMER2_BASE))=(unsigned int)(tick_rate/HZ);
++      *TIMER_CR(IO_ADDRESS(SL2312_TIMER1_BASE))=(unsigned int)(TIMER_2_CR_ENABLE_MSK|TIMER_2_CR_INT_MSK);
++#endif
++
++}
++
++
+Index: linux-2.6.23.16/arch/arm/mach-sl2312/xor.c
+===================================================================
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.23.16/arch/arm/mach-sl2312/xor.c 2008-03-13 17:48:24.508798285 +0200
+@@ -0,0 +1,1200 @@
++/*
++ * arch/arm/mach-sl2312/xor.c
++ *
++ * Support functions for the Gemini Soc. This is
++ * a HW XOR unit that is specifically designed for use with RAID5
++ * applications.  This driver provides an interface that is used by
++ * the Linux RAID stack.
++ *
++ * Original Author: Jason Lee<jason@storlink.com.tw>
++ *
++ * Contributors:Sanders<sanders@storlink.com.tw>
++                              Jason Lee<jason@storlink.com.tw>
++ *
++ *
++ * Maintainer: Jason Lee<jason@storlink.com.tw>
++ *
++ * Copyright (C) 2005 Storlink Corporation
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ *
++ * History:   (06/25/2005, DJ) Initial Creation
++ *
++ *    Versing 1.0.0   Initial version
++ */
++
++#include <linux/types.h>
++#include <linux/init.h>
++#include <linux/sched.h>
++#include <linux/spinlock.h>
++#include <linux/slab.h>
++#include <linux/errno.h>
++#include <linux/interrupt.h>
++#include <linux/sched.h>
++#include <linux/wait.h>
++#include <linux/list.h>
++#include <linux/pci.h>
++#include <linux/delay.h>
++#include <linux/dma-mapping.h>
++#include <linux/mm.h>
++#include <asm/irq.h>
++#include <asm/delay.h>
++#include <asm/uaccess.h>
++#include <asm/cacheflush.h>
++#include <asm/hardware.h>
++#include <asm/arch/xor.h>
++#include <asm/pci.h>
++#include <linux/version.h>
++
++/*
++ * pick up local definitions
++ */
++#define XOR_SW_FILL_IN
++#include "hw_xor.h"
++
++
++//#define XOR_DEBUG
++//#define XOR_TEST    1
++#ifdef XOR_TEST
++#define TEST_ITERATION 1000
++#define SPIN_WAIT     1
++#endif
++#ifdef XOR_DEBUG
++#define DPRINTK(s, args...) printk("Gemini XOR: " s "\n", ## args)
++#define DENTER() DPRINTK("Entered...\n");
++#define DEXIT() DPRINTK("Exited...\n");
++#else
++#define DPRINTK(s, args...)
++#define DENTER()
++#define DEXIT()
++#endif
++
++//#define SPIN_WAIT
++
++/* globals */
++static RAID_T tp;
++static RAID_TXDMA_CTRL_T      txdma_ctrl;
++RAID_RXDMA_CTRL_T                     rxdma_ctrl;
++
++//#ifndef SPIN_WAIT
++static spinlock_t         raid_lock;
++//#endif
++
++static unsigned int     tx_desc_virtual_base;
++static unsigned int     rx_desc_virtual_base;
++RAID_DESCRIPTOR_T     *tx_desc_ptr;
++RAID_DESCRIPTOR_T     *rx_desc_ptr;
++
++/* static prototypes */
++#define DMA_MALLOC(size,handle)               pci_alloc_consistent(NULL,size,handle)
++#define DMA_MFREE(mem,size,handle)    pci_free_consistent(NULL,size,mem,handle)
++
++static int gemini_xor_init_desc(void);
++
++static unsigned int raid_read_reg(unsigned int offset)
++{
++    unsigned int    reg_val;
++
++    reg_val = readl(RAID_BASE_ADDR + offset);
++      return (reg_val);
++}
++
++static void raid_write_reg(unsigned int offset,unsigned int data,unsigned int bit_mask)
++{
++      unsigned int reg_val;
++    unsigned int *addr;
++
++      reg_val = ( raid_read_reg(offset) & (~bit_mask) ) | (data & bit_mask);
++      addr = (unsigned int *)(RAID_BASE_ADDR + offset);
++    writel(reg_val,addr);
++      return;
++}
++
++#ifndef SPIN_WAIT
++__inline__ void xor_queue_descriptor(void)
++{
++      unsigned int flags,status=1;
++
++      DPRINTK("Going to sleep");
++
++      while(status){
++              yield();
++              //schedule();
++              spin_lock_irqsave(&raid_lock,flags);
++              status = tp.busy;
++              spin_unlock_irqrestore(&raid_lock, flags);
++      }
++//    tp.status = COMPLETE;
++      DPRINTK("woken up!");
++
++}
++#endif
++
++#ifdef SPIN_WAIT
++static void gemini_xor_isr(int d_n)
++#else
++#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,4,28)
++static void gemini_xor_isr(int irq, void *dev_id, struct pt_regs *regs)
++#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
++static irqreturn_t gemini_xor_isr(int irq, void *dev_instance, struct pt_regs *regs)
++#endif
++#endif
++{
++
++      unsigned int err;
++      RAID_DMA_STATUS_T       dma_status;
++//    RAID_DESCRIPTOR_T *rdesc,*tdesc;
++//    unsigned int *paddr;
++
++      dma_status.bits32 = raid_read_reg(RAID_DMA_STATUS);
++#ifdef SPIN_WAIT
++      while( (dma_status.bits32& (1<<31) ) ==0 ){
++              udelay(1);
++              dma_status.bits32 = raid_read_reg(RAID_DMA_STATUS);
++      }
++
++/*    tdesc = tp.tx_first_desc;
++      rdesc = tp.rx_first_desc;
++      for(d_n;d_n>0;d_n--){
++              if( tdesc->func_ctrl.bits.own == DMA ){
++                      paddr = tdesc;
++                      printk("error tx desc:0x%x\n",*paddr++);
++                      printk("error tx desc:0x%x\n",*paddr++);
++                      printk("error tx desc:0s%x\n",*paddr++);
++                      printk("error tx desc:0x%x\n",*paddr);
++                      while(1);
++              }
++              tdesc = (RAID_DESCRIPTOR_T *)((tdesc->next_desc_addr.bits32 & 0xfffffff0)+tx_desc_virtual_base);
++      }
++
++      if( rdesc->func_ctrl.bits.own == DMA ){
++              paddr = rdesc;
++              printk("error rx desc:0x%x\n",*paddr++);
++              printk("error rx desc:0x%x\n",*paddr++);
++              printk("error rx desc:0s%x\n",*paddr++);
++              printk("error rx desc:0x%x\n",*paddr);
++              while(1);
++      }
++*/
++#endif
++
++      if(dma_status.bits32 & ((1<<31)|(1<<26))){
++              // if no bug , we can turn off rx finish interrupt
++              dma_status.bits32 = raid_read_reg(RAID_DMA_STATUS);
++              err = raid_read_reg(RAID_DMA_DEVICE_ID);
++              tp.busy = 0;
++
++              if(err&0x00FF0000){
++                      tp.status = ERROR;
++                      printk("XOR:<HW>%s error code %x\n",(err&0x00F00000)?"tx":"rx",err);
++
++#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,4,28)
++                      return ;
++#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
++#ifndef SPIN_WAIT
++                      return IRQ_RETVAL(IRQ_HANDLED);
++#endif
++#endif
++              }
++              // 16~19 rx error code
++              // 20~23 tx error codd
++
++              dma_status.bits.tsFinishI = 1;
++              dma_status.bits.rsFinishI = 1;
++              raid_write_reg(RAID_DMA_STATUS, dma_status.bits32,0x84000000);  // clear INT
++
++//            printk("xor %d\n",d_n);
++#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,4,28)
++                      return ;
++#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
++#ifndef SPIN_WAIT
++                      return IRQ_RETVAL(IRQ_HANDLED);
++#endif
++#endif
++      }
++
++      #if LINUX_VERSION_CODE <= KERNEL_VERSION(2,4,28)
++              return ;
++      #elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
++      #ifndef SPIN_WAIT
++              printk("XOR: DMA status register(0x%8x)\n",dma_status.bits32);
++              return IRQ_RETVAL(IRQ_HANDLED);
++      #endif
++      #endif
++}
++
++void
++xor_gemini_2(unsigned long bytes, unsigned long *p1, unsigned long *p2)
++{
++      int status=0;
++      unsigned int flags;
++
++      if(bytes > (1<<(SRAM_PAR_SIZE+11))){
++              printk("XOR: out of SRAM partition!![0x%x]\n",(unsigned int)bytes);
++      }
++
++      spin_lock_irqsave(&raid_lock,flags);
++      while(tp.status != COMPLETE){
++              spin_unlock_irqrestore(&raid_lock, flags);
++              //printk("XOR yield2\n");
++#ifdef XOR_SW_FILL_IN
++              xor_arm4regs_2(bytes,p1,p2);
++              return ;
++#else
++              yield();
++#endif
++      }
++      spin_unlock_irqrestore(&raid_lock, flags);
++      tp.status = RUNNING;
++
++      // flush the cache to memory before H/W XOR touches them
++      consistent_sync(p1, bytes, DMA_BIDIRECTIONAL);
++      consistent_sync(p2, bytes, DMA_TO_DEVICE);
++
++
++      tp.tx_desc = tp.tx_first_desc;
++      tp.rx_desc = tp.rx_first_desc;
++      if((tp.tx_desc->func_ctrl.bits.own == CPU)/*&&(tp.rx_desc->func_ctrl.bits.own == DMA)*/){
++              // prepare tx descript
++              raid_write_reg(RAID_FCHDMA_CURR_DESC,(unsigned int)tp.tx_desc-tx_desc_virtual_base,0xffffffff);
++              tp.tx_desc->buf_addr = (unsigned int)__pa(p1);          // physical address
++      tp.tx_desc->func_ctrl.bits.buffer_size = bytes;                 /* total frame byte count */
++//            tp.tx_desc->flg_status.bits_cmd_status.bcc = 2;                 // first descript
++//            tp.tx_desc->flg_status.bits_cmd_status.mode = 0;                // only support XOR command
++              tp.tx_desc->flg_status.bits32 = 0x00020000;
++      tp.tx_desc->next_desc_addr.bits.sof_eof = 0x03;          /*only one descriptor*/
++      tp.tx_desc->func_ctrl.bits.own = DMA;                           /* set owner bit */
++      tp.tx_cur_desc = (RAID_DESCRIPTOR_T *)((tp.tx_desc->next_desc_addr.bits32 & 0xfffffff0)+tx_desc_virtual_base);
++              wmb();
++      tp.tx_desc = tp.tx_cur_desc;
++      tp.tx_desc->buf_addr = (unsigned int)__pa(p2);          // pysical address
++      tp.tx_desc->func_ctrl.bits.buffer_size = bytes;                 /* total frame byte count */
++//            tp.tx_desc->flg_status.bits_cmd_status.bcc = 1;                 // last descript
++//            tp.tx_desc->flg_status.bits_cmd_status.mode = 0;                // only support XOR command
++              tp.tx_desc->flg_status.bits32 = 0x00010000;
++      tp.tx_desc->func_ctrl.bits.own = DMA;                           /* set owner bit */
++      tp.tx_desc->next_desc_addr.bits32 = 0x0000000b;// end of descript
++      tp.tx_cur_desc = (RAID_DESCRIPTOR_T *)((tp.tx_desc->next_desc_addr.bits32 & 0xfffffff0)+tx_desc_virtual_base);                                                  // keep last descript
++
++      wmb();
++      // prepare rx descript
++      raid_write_reg(RAID_STRDMA_CURR_DESC,(unsigned int)tp.rx_desc-rx_desc_virtual_base,0xFFFFFFFf);
++      tp.rx_desc->buf_addr = (unsigned int)__pa(p1);
++      tp.rx_desc->func_ctrl.bits.buffer_size = bytes;                 /* total frame byte count */
++      tp.rx_desc->flg_status.bits32 = 0;                              // link data from XOR
++//            tp.rx_cur_desc->next_desc_addr.bits.sof_eof = 0x03;          /*only one descriptor*/
++      tp.rx_desc->func_ctrl.bits.own = DMA;                           /* set owner bit */
++      tp.rx_desc->next_desc_addr.bits32 = 0x0000000b;// end of descript
++
++      }
++      else{
++              /* no free tx descriptor */
++              printk("XOR:no free tx descript");
++              return ;
++      }
++
++      // change status
++//    tp.status = RUNNING;
++      status = tp.busy = 1;
++
++      // start tx DMA
++      rxdma_ctrl.bits.rd_start = 1;
++      // start rx DMA
++      txdma_ctrl.bits.td_start = 1;
++
++      raid_write_reg(RAID_FCHDMA_CTRL, txdma_ctrl.bits32,0x80000000);
++      raid_write_reg(RAID_STRDMA_CTRL, rxdma_ctrl.bits32,0x80000000);
++
++#ifdef SPIN_WAIT
++      gemini_xor_isr(2);
++#else
++      xor_queue_descriptor();
++#endif
++
++      tp.tx_desc->next_desc_addr.bits32 = ((unsigned long)tp.tx_first_desc - tx_desc_virtual_base + sizeof(RAID_DESCRIPTOR_T)*2) ;
++      tp.status = COMPLETE;
++//    tp.rx_desc->next_desc_addr.bits32 = ((unsigned long)tp.rx_first_desc - tx_desc_virtual_base + sizeof(RAID_DESCRIPTOR_T)*1) ;
++//    tp.rx_desc = tp.rx_first_desc ;
++//    tp.rx_desc->func_ctrl.bits.own = DMA;
++
++}
++
++void
++xor_gemini_3(unsigned long bytes, unsigned long *p1, unsigned long *p2,
++              unsigned long *p3)
++{
++      int status=0;
++      unsigned int flags;
++
++      if(bytes > (1<<(SRAM_PAR_SIZE+11))){
++              printk("XOR: out of SRAM partition!![0x%x]\n",(unsigned int)bytes);
++      }
++
++      spin_lock_irqsave(&raid_lock,flags);
++      if(tp.status != COMPLETE){
++              spin_unlock_irqrestore(&raid_lock, flags);
++              //printk("XOR yield3\n");
++#ifdef XOR_SW_FILL_IN
++              xor_arm4regs_3(bytes,p1,p2,p3);
++              return;
++#else
++              yield();
++#endif
++      }
++      spin_unlock_irqrestore(&raid_lock, flags);
++      tp.status = RUNNING;
++
++      // flush the cache to memory before H/W XOR touches them
++      consistent_sync(p1, bytes, DMA_BIDIRECTIONAL);
++      consistent_sync(p2, bytes, DMA_TO_DEVICE);
++      consistent_sync(p3, bytes, DMA_TO_DEVICE);
++
++      tp.tx_desc = tp.tx_first_desc;
++      tp.rx_desc = tp.rx_first_desc;
++      if((tp.tx_desc->func_ctrl.bits.own == CPU)/*&&(tp.rx_desc->func_ctrl.bits.own == DMA)*/){
++              // prepare tx descript
++              raid_write_reg(RAID_FCHDMA_CURR_DESC,(unsigned int)tp.tx_desc-tx_desc_virtual_base,0xffffffff);
++              tp.tx_desc->buf_addr = (unsigned int)__pa(p1);          // physical address
++      tp.tx_desc->func_ctrl.bits.buffer_size = bytes;                 /* total frame byte count */
++//            tp.tx_desc->flg_status.bits_cmd_status.bcc = 2;                 // first descript
++//            tp.tx_desc->flg_status.bits_cmd_status.mode = 0;                // only support XOR command
++              tp.tx_desc->flg_status.bits32 = 0x00020000;
++      tp.tx_desc->next_desc_addr.bits.sof_eof = 0x03;          /*only one descriptor*/
++      tp.tx_desc->func_ctrl.bits.own = DMA;                           /* set owner bit */
++      tp.tx_cur_desc = (RAID_DESCRIPTOR_T *)((tp.tx_desc->next_desc_addr.bits32 & 0xfffffff0)+tx_desc_virtual_base);
++
++      tp.tx_desc = tp.tx_cur_desc;
++      tp.tx_desc->buf_addr = (unsigned int)__pa(p2);          // pysical address
++      tp.tx_desc->func_ctrl.bits.buffer_size = bytes;                 /* total frame byte count */
++//            tp.tx_desc->flg_status.bits_cmd_status.bcc = 0;                 // first descript
++//            tp.tx_desc->flg_status.bits_cmd_status.mode = 0;                // only support XOR command
++              tp.tx_desc->flg_status.bits32 = 0x0000000;
++      tp.tx_desc->next_desc_addr.bits.sof_eof = 0x03;          /*only one descriptor*/
++      tp.tx_desc->func_ctrl.bits.own = DMA;                           /* set owner bit */
++      tp.tx_cur_desc = (RAID_DESCRIPTOR_T *)((tp.tx_desc->next_desc_addr.bits32 & 0xfffffff0)+tx_desc_virtual_base);
++
++      tp.tx_desc = tp.tx_cur_desc;
++      tp.tx_desc->buf_addr = (unsigned int)__pa(p3);          // pysical address
++      tp.tx_desc->func_ctrl.bits.buffer_size = bytes;                 /* total frame byte count */
++//            tp.tx_desc->flg_status.bits_cmd_status.bcc = 1;                 // last descript
++//            tp.tx_desc->flg_status.bits_cmd_status.mode = 0;                // only support XOR command
++              tp.tx_desc->flg_status.bits32 = 0x00010000;
++      tp.tx_desc->func_ctrl.bits.own = DMA;                           /* set owner bit */
++      tp.tx_desc->next_desc_addr.bits32 = 0x0000000b;// end of descript
++      tp.tx_cur_desc = (RAID_DESCRIPTOR_T *)((tp.tx_desc->next_desc_addr.bits32 & 0xfffffff0)+tx_desc_virtual_base);                                                  // keep last descript
++
++      // prepare rx descript
++      raid_write_reg(RAID_STRDMA_CURR_DESC,(unsigned int)tp.rx_desc-rx_desc_virtual_base,0xFFFFFFFf);
++      tp.rx_desc->buf_addr = (unsigned int)__pa(p1);
++      tp.rx_desc->func_ctrl.bits.buffer_size = bytes;                 /* total frame byte count */
++      tp.rx_desc->flg_status.bits32 = 0;                              // link data from XOR
++//            tp.rx_cur_desc->next_desc_addr.bits.sof_eof = 0x03;          /*only one descriptor*/
++      tp.rx_desc->func_ctrl.bits.own = DMA;                           /* set owner bit */
++      tp.rx_desc->next_desc_addr.bits32 = 0x0000000b;// end of descript
++
++      }
++      else{
++              /* no free tx descriptor */
++              printk("XOR:no free tx descript \n");
++              return ;
++      }
++
++      // change status
++//    tp.status = RUNNING;
++      status = tp.busy = 1;
++
++      // start tx DMA
++      rxdma_ctrl.bits.rd_start = 1;
++      // start rx DMA
++      txdma_ctrl.bits.td_start = 1;
++      wmb();
++      raid_write_reg(RAID_FCHDMA_CTRL, txdma_ctrl.bits32,0x80000000);
++      raid_write_reg(RAID_STRDMA_CTRL, rxdma_ctrl.bits32,0x80000000);
++
++#ifdef SPIN_WAIT
++      gemini_xor_isr(3);
++#else
++      xor_queue_descriptor();
++#endif
++      tp.tx_desc->next_desc_addr.bits32 = ((unsigned long)tp.tx_first_desc - tx_desc_virtual_base + sizeof(RAID_DESCRIPTOR_T)*3) | 0x0B;
++      tp.status = COMPLETE;
++//    tp.rx_desc->next_desc_addr.bits32 = ((unsigned long)tp.rx_first_desc - tx_desc_virtual_base + sizeof(RAID_DESCRIPTOR_T)*1) | 0x0B;
++      //tp.rx_desc = tp.rx_first_desc ;
++//    tp.rx_desc->func_ctrl.bits.own = DMA;
++
++}
++
++void
++xor_gemini_4(unsigned long bytes, unsigned long *p1, unsigned long *p2,
++              unsigned long *p3, unsigned long *p4)
++{
++      int status=0;
++      unsigned int flags;
++
++      if(bytes > (1<<(SRAM_PAR_SIZE+11))){
++              printk("XOR: out of SRAM partition!![0x%x]\n",(unsigned int)bytes);
++      }
++
++      spin_lock_irqsave(&raid_lock,flags);
++      if(tp.status != COMPLETE){
++              spin_unlock_irqrestore(&raid_lock, flags);
++              //printk("S\n");
++#ifdef XOR_SW_FILL_IN
++              xor_arm4regs_4(bytes,p1,p2,p3,p4);
++              return;
++#else
++              msleep(1);
++              yield();
++#endif
++      }
++      spin_unlock_irqrestore(&raid_lock, flags);
++
++      tp.status = RUNNING;
++
++      // flush the cache to memory before H/W XOR touches them
++      consistent_sync(p1, bytes, DMA_BIDIRECTIONAL);
++      consistent_sync(p2, bytes, DMA_TO_DEVICE);
++      consistent_sync(p3, bytes, DMA_TO_DEVICE);
++      consistent_sync(p4, bytes, DMA_TO_DEVICE);
++
++      tp.tx_desc = tp.tx_first_desc;
++      tp.rx_desc = tp.rx_first_desc;
++      if((tp.tx_desc->func_ctrl.bits.own == CPU)/*&&(tp.rx_desc->func_ctrl.bits.own == DMA)*/){
++              // prepare tx descript
++              raid_write_reg(RAID_FCHDMA_CURR_DESC,(unsigned int)tp.tx_desc-tx_desc_virtual_base,0xffffffff);
++              tp.tx_desc->buf_addr = (unsigned int)__pa(p1);          // physical address
++      tp.tx_desc->func_ctrl.bits.buffer_size = bytes;                 /* total frame byte count */
++//            tp.tx_desc->flg_status.bits_cmd_status.bcc = 2;                 // first descript
++//            tp.tx_desc->flg_status.bits_cmd_status.mode = 0;                // only support XOR command
++              tp.tx_desc->flg_status.bits32 = 0x00020000;
++      tp.tx_desc->next_desc_addr.bits.sof_eof = 0x03;          /*only one descriptor*/
++      tp.tx_desc->func_ctrl.bits.own = DMA;                           /* set owner bit */
++      tp.tx_cur_desc = (RAID_DESCRIPTOR_T *)((tp.tx_desc->next_desc_addr.bits32 & 0xfffffff0)+tx_desc_virtual_base);
++
++      tp.tx_desc = tp.tx_cur_desc;
++      tp.tx_cur_desc->buf_addr = (unsigned int)__pa(p2);              // pysical address
++      tp.tx_desc->func_ctrl.bits.buffer_size = bytes;                 /* total frame byte count */
++//            tp.tx_desc->flg_status.bits_cmd_status.bcc = 0;                 // first descript
++//            tp.tx_desc->flg_status.bits_cmd_status.mode = 0;                // only support XOR command
++              tp.tx_desc->flg_status.bits32 = 0x00000000;
++      tp.tx_cur_desc->next_desc_addr.bits.sof_eof = 0x03;          /*only one descriptor*/
++      tp.tx_desc->func_ctrl.bits.own = DMA;                           /* set owner bit */
++      tp.tx_cur_desc = (RAID_DESCRIPTOR_T *)((tp.tx_desc->next_desc_addr.bits32 & 0xfffffff0)+tx_desc_virtual_base);
++
++      tp.tx_desc = tp.tx_cur_desc;
++      tp.tx_desc->buf_addr = (unsigned int)__pa(p3);          // pysical address
++      tp.tx_desc->func_ctrl.bits.buffer_size = bytes;                 /* total frame byte count */
++//            tp.tx_desc->flg_status.bits_cmd_status.bcc = 0;                 // first descript
++//            tp.tx_desc->flg_status.bits_cmd_status.mode = 0;                // only support XOR command
++              tp.tx_desc->flg_status.bits32 = 0x00000000;
++      tp.tx_desc->next_desc_addr.bits.sof_eof = 0x03;          /*only one descriptor*/
++      tp.tx_desc->func_ctrl.bits.own = DMA;                           /* set owner bit */
++      tp.tx_cur_desc = (RAID_DESCRIPTOR_T *)((tp.tx_desc->next_desc_addr.bits32 & 0xfffffff0)+tx_desc_virtual_base);
++
++
++      tp.tx_desc = tp.tx_cur_desc;
++      tp.tx_desc->buf_addr = (unsigned int)__pa(p4);          // pysical address
++      tp.tx_desc->func_ctrl.bits.buffer_size = bytes;                 /* total frame byte count */
++//            tp.tx_desc->flg_status.bits_cmd_status.bcc = 1;                 // last descript
++//            tp.tx_desc->flg_status.bits_cmd_status.mode = 0;                // only support XOR command
++              tp.tx_desc->flg_status.bits32 = 0x00010000;
++//            tp.tx_cur_desc->next_desc_addr.bits.sof_eof = 0x03;          /*only one descriptor*/
++      tp.tx_desc->func_ctrl.bits.own = DMA;                           /* set owner bit */
++      tp.tx_desc->next_desc_addr.bits32 = 0x0000000b;// end of descript
++      tp.tx_cur_desc = (RAID_DESCRIPTOR_T *)((tp.tx_desc->next_desc_addr.bits32 & 0xfffffff0)+tx_desc_virtual_base);                                                  // keep last descript
++
++      // prepare rx descript
++      raid_write_reg(RAID_STRDMA_CURR_DESC,(unsigned int)tp.rx_desc-rx_desc_virtual_base,0xFFFFFFFF);
++      tp.rx_desc->buf_addr = (unsigned int)__pa(p1);
++      tp.rx_desc->func_ctrl.bits.buffer_size = bytes;                 /* total frame byte count */
++      tp.rx_desc->flg_status.bits32 = 0;                              // link data from XOR
++//            tp.rx_cur_desc->next_desc_addr.bits.sof_eof = 0x03;          /*only one descriptor*/
++      tp.rx_desc->func_ctrl.bits.own = DMA;                           /* set owner bit */
++      tp.rx_desc->next_desc_addr.bits32 = 0x0000000b;// end of descript
++
++      }
++      else{
++              /* no free tx descriptor */
++              printk("XOR:no free tx descript");
++              return ;
++      }
++
++      // change status
++//    tp.status = RUNNING;
++      status = tp.busy = 1;
++
++      // start tx DMA
++      rxdma_ctrl.bits.rd_start = 1;
++      // start rx DMA
++      txdma_ctrl.bits.td_start = 1;
++      wmb();
++      raid_write_reg(RAID_FCHDMA_CTRL, txdma_ctrl.bits32,0x80000000);
++      raid_write_reg(RAID_STRDMA_CTRL, rxdma_ctrl.bits32,0x80000000);
++
++#ifdef SPIN_WAIT
++      gemini_xor_isr(4);
++#else
++      xor_queue_descriptor();
++#endif
++
++      tp.tx_desc->next_desc_addr.bits32 = ((unsigned long)tp.tx_first_desc - tx_desc_virtual_base + sizeof(RAID_DESCRIPTOR_T)*4) | 0x0B;
++      tp.status = COMPLETE;
++//    tp.rx_desc->next_desc_addr.bits32 = ((unsigned long)tp.rx_first_desc - tx_desc_virtual_base + sizeof(RAID_DESCRIPTOR_T)*1) | 0x0B;
++      //tp.rx_desc = tp.rx_first_desc ;
++//    tp.rx_desc->func_ctrl.bits.own = DMA;
++
++}
++
++void
++xor_gemini_5(unsigned long bytes, unsigned long *p1, unsigned long *p2,
++              unsigned long *p3, unsigned long *p4, unsigned long *p5)
++{
++
++      int status=0;
++      unsigned int flags;
++
++
++      if(bytes > (1<<(SRAM_PAR_SIZE+11))){
++              printk("XOR: out of SRAM partition!![0x%x]\n",(unsigned int)bytes);
++      }
++
++      spin_lock_irqsave(&raid_lock,flags);
++      while(tp.status != COMPLETE){
++              spin_unlock_irqrestore(&raid_lock, flags);
++              //printk("XOR yield5\n");
++#ifdef XOR_SW_FILL_IN
++              xor_arm4regs_5(bytes,p1,p2,p3,p4,p5);
++              return;
++#else
++              msleep(1);
++              yield();
++#endif
++      }
++      spin_unlock_irqrestore(&raid_lock, flags);
++      tp.status = RUNNING;
++
++      // flush the cache to memory before H/W XOR touches them
++      consistent_sync(p1, bytes, DMA_BIDIRECTIONAL);
++      consistent_sync(p2, bytes, DMA_TO_DEVICE);
++      consistent_sync(p3, bytes, DMA_TO_DEVICE);
++      consistent_sync(p4, bytes, DMA_TO_DEVICE);
++      consistent_sync(p5, bytes, DMA_TO_DEVICE);
++
++      tp.tx_desc = tp.tx_first_desc;
++      tp.rx_desc = tp.rx_first_desc;
++      if((tp.tx_desc->func_ctrl.bits.own == CPU)/*&&(tp.rx_desc->func_ctrl.bits.own == DMA)*/){
++              // prepare tx descript
++              raid_write_reg(RAID_FCHDMA_CURR_DESC,(unsigned int)tp.tx_desc-tx_desc_virtual_base,0xffffffff);
++              tp.tx_desc->buf_addr = (unsigned int)__pa(p1);          // physical address
++      tp.tx_desc->func_ctrl.bits.buffer_size = bytes;                 /* total frame byte count */
++//            tp.tx_desc->flg_status.bits_cmd_status.bcc = 2;                 // first descript
++//            tp.tx_desc->flg_status.bits_cmd_status.mode = 0;                // only support XOR command
++              tp.tx_desc->flg_status.bits32 = 0x00020000;
++      tp.tx_desc->next_desc_addr.bits.sof_eof = 0x03;          /*only one descriptor*/
++      wmb();
++      tp.tx_desc->func_ctrl.bits.own = DMA;                           /* set owner bit */
++      tp.tx_cur_desc = (RAID_DESCRIPTOR_T *)((tp.tx_desc->next_desc_addr.bits32 & 0xfffffff0)+tx_desc_virtual_base);
++
++      tp.tx_desc = tp.tx_cur_desc;
++      tp.tx_desc->buf_addr = (unsigned int)__pa(p2);          // pysical address
++      tp.tx_desc->func_ctrl.bits.buffer_size = bytes;                 /* total frame byte count */
++//            tp.tx_desc->flg_status.bits_cmd_status.bcc = 0;                 // first descript
++//            tp.tx_desc->flg_status.bits_cmd_status.mode = 0;                // only support XOR command
++              tp.tx_desc->flg_status.bits32 = 0x00000000;
++      tp.tx_desc->next_desc_addr.bits.sof_eof = 0x03;          /*only one descriptor*/
++      wmb();
++      tp.tx_desc->func_ctrl.bits.own = DMA;                           /* set owner bit */
++      tp.tx_cur_desc = (RAID_DESCRIPTOR_T *)((tp.tx_desc->next_desc_addr.bits32 & 0xfffffff0)+tx_desc_virtual_base);
++
++      tp.tx_desc = tp.tx_cur_desc;
++      tp.tx_desc->buf_addr = (unsigned int)__pa(p3);          // pysical address
++      tp.tx_desc->func_ctrl.bits.buffer_size = bytes;                 /* total frame byte count */
++//            tp.tx_desc->flg_status.bits_cmd_status.bcc = 0;                 // first descript
++//            tp.tx_desc->flg_status.bits_cmd_status.mode = 0;                // only support XOR command
++              tp.tx_desc->flg_status.bits32 = 0x00000000;
++      tp.tx_desc->next_desc_addr.bits.sof_eof = 0x03;          /*only one descriptor*/
++      wmb();
++      tp.tx_desc->func_ctrl.bits.own = DMA;                           /* set owner bit */
++      tp.tx_cur_desc = (RAID_DESCRIPTOR_T *)((tp.tx_desc->next_desc_addr.bits32 & 0xfffffff0)+tx_desc_virtual_base);
++
++              tp.tx_desc = tp.tx_cur_desc;
++      tp.tx_desc->buf_addr = (unsigned int)__pa(p4);          // pysical address
++      tp.tx_desc->func_ctrl.bits.buffer_size = bytes;                 /* total frame byte count */
++//            tp.tx_desc->flg_status.bits_cmd_status.bcc = 0;                 // first descript
++//            tp.tx_desc->flg_status.bits_cmd_status.mode = 0;                // only support XOR command
++              tp.tx_desc->flg_status.bits32 = 0x00000000;
++      tp.tx_desc->next_desc_addr.bits.sof_eof = 0x03;          /*only one descriptor*/
++      wmb();
++      tp.tx_desc->func_ctrl.bits.own = DMA;                           /* set owner bit */
++      tp.tx_cur_desc = (RAID_DESCRIPTOR_T *)((tp.tx_desc->next_desc_addr.bits32 & 0xfffffff0)+tx_desc_virtual_base);
++
++
++      tp.tx_desc = tp.tx_cur_desc;
++      tp.tx_desc->buf_addr = (unsigned int)__pa(p5);          // pysical address
++      tp.tx_desc->func_ctrl.bits.buffer_size = bytes;                 /* total frame byte count */
++//            tp.tx_desc->flg_status.bits_cmd_status.bcc = 1;                 // last descript
++//            tp.tx_desc->flg_status.bits_cmd_status.mode = 0;                // only support XOR command
++//            tp.tx_cur_desc->next_desc_addr.bits.sof_eof = 0x03;          /*only one descriptor*/
++              tp.tx_desc->flg_status.bits32 = 0x00010000;
++      tp.tx_desc->func_ctrl.bits.own = DMA;                           /* set owner bit */
++      tp.tx_desc->next_desc_addr.bits32 = 0x0000000b;// end of descript
++      tp.tx_cur_desc = (RAID_DESCRIPTOR_T *)((tp.tx_desc->next_desc_addr.bits32 & 0xfffffff0)+tx_desc_virtual_base);
++      tp.tx_finished_desc = tp.tx_desc;                                                               // keep last descript
++
++      // prepare rx descript
++      raid_write_reg(RAID_STRDMA_CURR_DESC,(unsigned int)tp.rx_desc-rx_desc_virtual_base,0xFFFFFFFF);
++      tp.rx_desc->buf_addr = (unsigned int)__pa(p1);
++      tp.rx_desc->func_ctrl.bits.buffer_size = bytes;                 /* total frame byte count */
++      tp.rx_desc->flg_status.bits32 = 0;                              // link data from XOR
++//            tp.rx_cur_desc->next_desc_addr.bits.sof_eof = 0x03;          /*only one descriptor*/
++      tp.rx_desc->func_ctrl.bits.own = DMA;                           /* set owner bit */
++      tp.rx_desc->next_desc_addr.bits32 = 0x0000000b;// end of descript
++
++      }
++      else{
++              /* no free tx descriptor */
++              printk("XOR:no free tx descript");
++              return ;
++      }
++
++      // change status
++//    tp.status = RUNNING;
++      status = tp.busy = 1;
++
++      // start tx DMA
++      rxdma_ctrl.bits.rd_start = 1;
++      // start rx DMA
++      txdma_ctrl.bits.td_start = 1;
++      wmb();
++      raid_write_reg(RAID_FCHDMA_CTRL, txdma_ctrl.bits32,0x80000000);
++      raid_write_reg(RAID_STRDMA_CTRL, rxdma_ctrl.bits32,0x80000000);
++
++#ifdef SPIN_WAIT
++      gemini_xor_isr(5);
++#else
++      xor_queue_descriptor();
++#endif
++
++      tp.tx_desc->next_desc_addr.bits32 = ((unsigned long)tp.tx_first_desc - tx_desc_virtual_base + sizeof(RAID_DESCRIPTOR_T)*5) | 0x0B;
++      tp.status = COMPLETE;
++//    tp.rx_desc->next_desc_addr.bits32 = ((unsigned long)tp.rx_first_desc - tx_desc_virtual_base + sizeof(RAID_DESCRIPTOR_T)*1) | 0x0B;
++      //tp.rx_desc = tp.rx_first_desc ;
++//    tp.rx_desc->func_ctrl.bits.own = DMA;
++
++}
++
++#ifdef XOR_TEST
++void
++raid_memset(unsigned int *p1, unsigned int pattern, unsigned int bytes)
++{
++      int status=0,i;
++
++      if(bytes > (1<<(SRAM_PAR_SIZE+11))){
++              printk("XOR: out of SRAM partition!![0x%x]\n",(unsigned int)bytes);
++      }
++
++      *p1 = pattern;
++
++      // flush the cache to memory before H/W XOR touches them
++      consistent_sync(p1, bytes, DMA_BIDIRECTIONAL);
++
++      while(tp.status != COMPLETE){
++              DPRINTK("XOR yield\n");
++              //schedule();
++              yield();
++      }
++      tp.status = RUNNING;
++
++      tp.tx_desc = tp.tx_first_desc;
++      tp.rx_desc = tp.rx_first_desc;
++      if((tp.tx_desc->func_ctrl.bits.own == CPU)/*&&(tp.rx_desc->func_ctrl.bits.own == DMA)*/){
++              // prepare tx descript
++              raid_write_reg(RAID_FCHDMA_CURR_DESC,(unsigned int)tp.tx_desc-tx_desc_virtual_base,0xFFFFFFFF);
++              tp.tx_desc->buf_addr = (unsigned int)__pa(p1);          // physical address
++      tp.tx_desc->func_ctrl.bits.buffer_size = 4;             /* total frame byte count */
++      tp.tx_desc->flg_status.bits_cmd_status.bcc = bytes;                     // bytes to fill
++      tp.tx_desc->flg_status.bits_cmd_status.mode = CMD_FILL;         // only support memory FILL command
++      tp.tx_desc->next_desc_addr.bits.sof_eof = 0x03;          /*only one descriptor*/
++      tp.tx_desc->func_ctrl.bits.own = DMA;                           /* set owner bit */
++      tp.tx_desc->next_desc_addr.bits32 = 0x0000000b;
++//            tp.tx_cur_desc = (RAID_DESCRIPTOR_T *)((tp.tx_desc->next_desc_addr.bits32 & 0xFFFFFFF0)+tx_desc_virtual_base);
++
++      // prepare rx descript
++      raid_write_reg(RAID_STRDMA_CURR_DESC,(unsigned int)tp.rx_desc-rx_desc_virtual_base,0xFFFFFFFF);
++      tp.rx_desc->buf_addr = (unsigned int)__pa(p1);
++      tp.rx_desc->func_ctrl.bits.buffer_size = bytes;                 /* total frame byte count */
++      tp.rx_desc->flg_status.bits32 = 0;                              // link data from XOR
++      tp.rx_cur_desc->next_desc_addr.bits.sof_eof = 0x03;          /*only one descriptor*/
++      tp.rx_desc->func_ctrl.bits.own = DMA;                           /* set owner bit */
++//            tp.rx_cur_desc = (RAID_DESCRIPTOR_T *)((tp.rx_cur_desc->next_desc_addr.bits32 & 0xfffffff0)+rx_desc_virtual_base);
++      tp.rx_desc->next_desc_addr.bits32 = 0x0000000b;// end of descript
++      tp.rx_finished_desc = tp.rx_desc;
++
++      }
++      else{
++              /* no free tx descriptor */
++              printk("XOR:no free tx descript");
++              return ;
++      }
++
++      // change status
++      //tp.status = RUNNING;
++      status = tp.busy = 1;
++
++      // start tx DMA
++      rxdma_ctrl.bits.rd_start = 1;
++      // start rx DMA
++      txdma_ctrl.bits.td_start = 1;
++
++      raid_write_reg(RAID_FCHDMA_CTRL, txdma_ctrl.bits32,0x80000000);
++      raid_write_reg(RAID_STRDMA_CTRL, rxdma_ctrl.bits32,0x80000000);
++
++#ifdef SPIN_WAIT
++      gemini_xor_isr(2);
++#else
++      xor_queue_descriptor();
++#endif
++
++      for(i=1; i<(bytes/sizeof(int)); i++) {
++              if(p1[0]!=p1[i]){
++                      printk("pattern set error!\n");
++                      while(1);
++              }
++      }
++
++      tp.tx_desc->next_desc_addr.bits32 = ((unsigned long)tp.tx_first_desc - tx_desc_virtual_base + sizeof(RAID_DESCRIPTOR_T)*1) ;
++      tp.status = COMPLETE;
++//    tp.rx_desc->next_desc_addr.bits32 = ((unsigned long)tp.rx_first_desc - tx_desc_virtual_base + sizeof(RAID_DESCRIPTOR_T)*1) ;
++      //tp.rx_desc = tp.rx_first_desc ;
++//    tp.rx_desc->func_ctrl.bits.own = DMA;
++
++}
++#endif
++
++void
++raid_memcpy(unsigned int *to, unsigned int *from, unsigned int bytes)
++{
++      int status=0,i;
++
++      if(bytes > (1<<(SRAM_PAR_SIZE+11))){
++              printk("XOR: out of SRAM partition!![0x%x]\n",(unsigned int)bytes);
++      }
++
++      // flush the cache to memory before H/W XOR touches them
++      consistent_sync(to, bytes, DMA_BIDIRECTIONAL);
++      consistent_sync(from,bytes, DMA_TO_DEVICE);
++
++      while(tp.status != COMPLETE){
++              DPRINTK("XOR yield\n");
++              //schedule();
++              yield();
++      }
++      tp.status = RUNNING;
++
++      tp.tx_desc = tp.tx_first_desc;
++      tp.rx_desc = tp.rx_first_desc;
++      if((tp.tx_desc->func_ctrl.bits.own == CPU)/*&&(tp.rx_desc->func_ctrl.bits.own == DMA)*/){
++              // prepare tx descript
++              raid_write_reg(RAID_FCHDMA_CURR_DESC,(unsigned int)tp.tx_desc-tx_desc_virtual_base,0xFFFFFFFF);
++              tp.tx_desc->buf_addr = (unsigned int)__pa(from);                // physical address
++      tp.tx_desc->func_ctrl.bits.buffer_size = bytes;                 /* total frame byte count */
++      tp.tx_desc->flg_status.bits32 = CMD_CPY;                // only support memory FILL command
++      tp.tx_desc->next_desc_addr.bits.sof_eof = 0x03;          /*only one descriptor*/
++      tp.tx_desc->func_ctrl.bits.own = DMA;                           /* set owner bit */
++      tp.tx_desc->next_desc_addr.bits32 = 0x0000000b;
++//            tp.tx_cur_desc = (RAID_DESCRIPTOR_T *)((tp.tx_desc->next_desc_addr.bits32 & 0xFFFFFFF0)+tx_desc_virtual_base);
++
++      // prepare rx descript
++      raid_write_reg(RAID_STRDMA_CURR_DESC,(unsigned int)tp.rx_desc-rx_desc_virtual_base,0xFFFFFFFF);
++      tp.rx_desc->buf_addr = (unsigned int)__pa(to);
++      tp.rx_desc->func_ctrl.bits.buffer_size = bytes;                 /* total frame byte count */
++      tp.rx_desc->flg_status.bits32 = 0;                              // link data from XOR
++      tp.rx_cur_desc->next_desc_addr.bits.sof_eof = 0x03;          /*only one descriptor*/
++      tp.rx_desc->func_ctrl.bits.own = DMA;                           /* set owner bit */
++//            tp.rx_cur_desc = (RAID_DESCRIPTOR_T *)((tp.rx_cur_desc->next_desc_addr.bits32 & 0xfffffff0)+rx_desc_virtual_base);
++      tp.rx_desc->next_desc_addr.bits32 = 0x0000000b;// end of descript
++
++      }
++      else{
++              /* no free tx descriptor */
++              printk("XOR:no free tx descript");
++              return ;
++      }
++
++      // change status
++      //tp.status = RUNNING;
++      status = tp.busy = 1;
++
++      // start tx DMA
++      rxdma_ctrl.bits.rd_start = 1;
++      // start rx DMA
++      txdma_ctrl.bits.td_start = 1;
++
++      raid_write_reg(RAID_FCHDMA_CTRL, txdma_ctrl.bits32,0x80000000);
++      raid_write_reg(RAID_STRDMA_CTRL, rxdma_ctrl.bits32,0x80000000);
++
++#ifdef SPIN_WAIT
++      gemini_xor_isr(2);
++#else
++      xor_queue_descriptor();
++#endif
++
++#ifdef XOR_TEST
++      for(i=1; i<(bytes/sizeof(int)); i++) {
++              if(to[i]!=from[i]){
++                      printk("pattern check error!\n");
++                      printk("offset=0x%x p1=%x p2=%x\n",i*4,to[i],from[i]);
++                      while(1);
++              }
++      }
++#endif
++
++      tp.tx_desc->next_desc_addr.bits32 = ((unsigned long)tp.tx_first_desc - tx_desc_virtual_base + sizeof(RAID_DESCRIPTOR_T)*1) ;
++      tp.status = COMPLETE;
++//    tp.rx_desc->next_desc_addr.bits32 = ((unsigned long)tp.rx_first_desc - tx_desc_virtual_base + sizeof(RAID_DESCRIPTOR_T)*1) ;
++      //tp.rx_desc = tp.rx_first_desc ;
++//    tp.rx_desc->func_ctrl.bits.own = DMA;
++
++}
++EXPORT_SYMBOL(raid_memcpy);
++
++#ifdef XOR_TEST
++int
++raid_memchk(unsigned int *p1, unsigned int pattern, unsigned int bytes)
++{
++      int status=0;
++      RAID_DMA_STATUS_T       dma_status;
++
++      if(bytes > (1<<(SRAM_PAR_SIZE+11))){
++              printk("XOR: out of SRAM partition!![0x%x]\n",(unsigned int)bytes);
++      }
++
++      status = ((pattern&0xFFFF)%bytes )/4;
++      p1[status] = pattern;
++
++      while(tp.status != COMPLETE){
++              DPRINTK("XOR yield\n");
++              //schedule();
++              yield();
++      }
++      tp.status = RUNNING;
++
++      // flush the cache to memory before H/W XOR touches them
++      consistent_sync(p1, bytes, DMA_BIDIRECTIONAL);
++
++      tp.tx_desc = tp.tx_first_desc;
++      if((tp.tx_desc->func_ctrl.bits.own == CPU)/*&&(tp.rx_desc->func_ctrl.bits.own == DMA)*/){
++              // prepare tx descript
++              raid_write_reg(RAID_FCHDMA_CURR_DESC,(unsigned int)tp.tx_desc-tx_desc_virtual_base,0xFFFFFFFF);
++              tp.tx_desc->buf_addr = (unsigned int)__pa(p1);          // physical address
++      tp.tx_desc->func_ctrl.bits.raid_ctrl_status = 0;
++      tp.tx_desc->func_ctrl.bits.buffer_size = bytes ;                /* total frame byte count */
++      tp.tx_desc->flg_status.bits32 = CMD_CHK;                // only support memory FILL command
++      tp.tx_desc->next_desc_addr.bits.sof_eof = 0x03;          /*only one descriptor*/
++      tp.tx_desc->func_ctrl.bits.own = DMA;                           /* set owner bit */
++      tp.tx_desc->next_desc_addr.bits32 = 0x0000000b;
++//            tp.tx_cur_desc = (RAID_DESCRIPTOR_T *)((tp.tx_desc->next_desc_addr.bits32 & 0xFFFFFFF0)+tx_desc_virtual_base);
++
++      }
++      else{
++              /* no free tx descriptor */
++              printk("XOR:no free tx descript");
++              return -1;
++      }
++
++      // change status
++      //tp.status = RUNNING;
++      status = tp.busy = 1;
++
++      // start tx DMA
++      txdma_ctrl.bits.td_start = 1;
++
++      raid_write_reg(RAID_FCHDMA_CTRL, txdma_ctrl.bits32,0x80000000);
++//    raid_write_reg(RAID_STRDMA_CTRL, rxdma_ctrl.bits32,0x80000000);
++
++#ifdef SPIN_WAIT
++      gemini_xor_isr(2);
++#else
++      xor_queue_descriptor();
++#endif
++
++//    dma_status.bits32 = raid_read_reg(RAID_DMA_STATUS);
++//    if (dma_status.bits32 & (1<<15))        {
++
++      if((tp.tx_first_desc->func_ctrl.bits.raid_ctrl_status & 0x2)) {
++              status = 1;
++//            raid_write_reg(RAID_DMA_STATUS,0x00008000,0x00080000);
++      }
++      else{
++              status = 0;
++      }
++
++      tp.tx_desc->next_desc_addr.bits32 = ((unsigned long)tp.tx_first_desc - tx_desc_virtual_base + sizeof(RAID_DESCRIPTOR_T)*1) ;
++      tp.status = COMPLETE;
++//    tp.rx_desc->func_ctrl.bits.own = DMA;
++      return status ;
++}
++#endif
++
++int __init gemini_xor_init(void)
++{
++      unsigned int res;
++      unsigned int *paddr1,*paddr2,*paddr3,i;
++      unsigned volatile char  *charact;
++      unsigned volatile short *two_char;
++      unsigned volatile int   *four_char;
++
++      // init descript
++      res = gemini_xor_init_desc();
++      if(res) {
++              printk("Init RAID Descript Fail!!\n");
++              return -res;
++      }
++
++      tp.device_name = "Gemini XOR Acceleration";
++
++      // request irq
++#ifndef SPIN_WAIT
++      res = request_irq(IRQ_RAID, gemini_xor_isr, SA_INTERRUPT, tp.device_name, NULL);
++#endif
++      if(res){
++              printk(KERN_ERR "%s: unable to request IRQ %d for "
++                     "HW XOR %d\n", tp.device_name, IRQ_RAID, res);
++              return -EBUSY;
++      }
++
++#ifdef XOR_TEST
++
++RETEST:
++      paddr1 = kmalloc(0x1000,GFP_KERNEL);
++      paddr2 = kmalloc(0x1000,GFP_KERNEL);
++      paddr3 = kmalloc(0x1000,GFP_KERNEL);
++      for(i=0;i<TEST_ITERATION;i++) {
++              printk("XOR test round %d\n",i);
++              for(res=0;res<(0x1000)/sizeof(int);res++){              // prepare data pattern
++                      paddr1[res]= readl(0xf62000ac);
++                      paddr2[res]= readl(0xf62000ac);
++              }
++              for(res=0;res<0x1000/sizeof(int);res++){                // calculate xor by software
++                      paddr3[res] = paddr1[res]^paddr2[res];
++              }
++              xor_gemini_2(0x1000,paddr1,paddr2);                             // calculate xor by hw
++              for(res=0;res<0x1000/sizeof(int);res++){                // check error
++                      if(paddr1[res]!=paddr3[res]){
++                              printk("XOR ERROR\n");
++                              printk("[%d][0x%x]=0x%x should be %x\n",res,&paddr1[res],paddr1[res],paddr3[res]);
++                              while(1);
++                      }
++              }
++      }
++      kfree(paddr1);
++      kfree(paddr2);
++      kfree(paddr3);
++
++
++      // memcpy test
++      paddr1 = kmalloc(0x4000,GFP_KERNEL);
++      for(i=0;i<TEST_ITERATION;i++) {
++              for(res=0;res<(0x4000)/sizeof(int);res++)
++                      paddr1[res]= readl(0xf62000ac);
++
++              printk("MEMCOPY round %d\n",i);
++              paddr2 = kmalloc(0x4000,GFP_KERNEL);
++              raid_memcpy(paddr2,paddr1,0x4000);
++              kfree(paddr2);
++      }
++      kfree(paddr1);
++
++      // memset test
++      for(i=0;i<TEST_ITERATION;i++) {
++              raid_memset(paddr1,0xFFFFFFFF,0x4000);
++              res = readl(0xf62000ac);
++              printk("MEMFILL fill 0x%x round %d\n",res,i);
++              paddr1 = kmalloc(0x4000,GFP_KERNEL);
++              raid_memset(paddr1,res,0x4000);
++              raid_memset(paddr1,0x0,0x4000);
++              kfree(paddr1);
++      }
++
++      paddr1 = kmalloc(0x4000,GFP_KERNEL);
++      for(i=0;i<TEST_ITERATION;i++){
++              raid_memset(paddr1, i,0x4000);
++              printk("Pattern check same ? ");
++              res = raid_memchk(paddr1, i,0x4000);
++              printk("%s\n",res?"Fail":"OK");
++              if(res) while(1);
++
++              printk("Pattern check diff ? ");
++              res = raid_memchk(paddr1,readl(0xf62000ac),0x4000);
++              printk("%s\n",res?"OK":"Fail");
++              if(!res)        while(1);
++      }
++      kfree(paddr1);
++
++      // SRAM test
++      raid_write_reg(RAID_PCR, 0,0x00000003);
++      for(i=0;i<TEST_ITERATION;i++) {
++              printk("SRAM test %d\n",i);
++              charact = 0xF7000000;
++              two_char = 0xF7000000;
++              four_char = 0xF7000000;
++              for(res=0;res<(16*1024)/sizeof(char);res++) {           // 8-bit access
++                      *charact++ = (unsigned char)res;
++              }
++              charact = 0xF7000000;
++              for(res=0;res<(16*1024)/sizeof(char);res++) {
++                      if(*charact++ != (unsigned char)res){
++                              printk("SRAM data error(8)\n");
++                              while(1);
++                      }
++              }
++
++              for(res=0;res<(16*1024)/sizeof(short);res++) {          // 16-bit access
++                      *two_char++ = (unsigned short)res;
++              }
++              two_char = 0xF7000000;
++              for(res=0;res<(16*1024)/sizeof(short);res++) {
++                      if(*two_char++ != (unsigned short)res){
++                              printk("SRAM data error(16)\n");
++                              while(1);
++                      }
++              }
++
++              for(res=0;res<(16*1024)/sizeof(int);res++) {            // 32-bit access
++                      *four_char++ = (unsigned int)res;
++              }
++              four_char = 0xF7000000;
++              for(res=0;res<(16*1024)/sizeof(int);res++) {
++                      if(*four_char++ != (unsigned int)res){
++                              printk("SRAM data error(32)\n");
++                              while(1);
++                      }
++              }
++      }
++      raid_write_reg(RAID_PCR, SRAM_PAR_SIZE,0x00000003);
++
++#endif
++      return 0;
++}
++
++void __exit gemini_xor_exit(void)
++{
++      DMA_MFREE(tp.tx_desc, TX_DESC_NUM*sizeof(RAID_DESCRIPTOR_T),(unsigned int)tp.tx_desc_dma);
++      DMA_MFREE(tp.rx_desc, RX_DESC_NUM*sizeof(RAID_DESCRIPTOR_T),(unsigned int)tp.rx_desc_dma);
++      free_irq(IRQ_RAID, NULL);
++}
++
++
++static int gemini_xor_init_desc(void)
++{
++      unsigned int i;
++      dma_addr_t          tx_first_desc_dma;
++      dma_addr_t          rx_first_desc_dma;
++      RAID_DMA_STATUS_T       dma_status;
++
++      printk("Initial RAID Descripter...\n");
++
++      tp.tx_desc = (RAID_DESCRIPTOR_T*)DMA_MALLOC(TX_DESC_NUM*sizeof(RAID_DESCRIPTOR_T),(dma_addr_t *)&tp.tx_desc_dma);
++    tx_desc_virtual_base = (unsigned int)tp.tx_desc - (unsigned int)tp.tx_desc_dma;
++    memset(tp.tx_desc,0x00,TX_DESC_NUM*sizeof(RAID_DESCRIPTOR_T));
++
++      tp.rx_desc = (RAID_DESCRIPTOR_T*)DMA_MALLOC(RX_DESC_NUM*sizeof(RAID_DESCRIPTOR_T),(dma_addr_t *)&tp.rx_desc_dma);
++    rx_desc_virtual_base = (unsigned int)tp.rx_desc - (unsigned int)tp.rx_desc_dma;
++    memset(tp.rx_desc,0x00,RX_DESC_NUM*sizeof(RAID_DESCRIPTOR_T));
++      printk("XOR:tx_desc = %08x\n",(unsigned int)tp.tx_desc);
++    printk("XOR:rx_desc = %08x\n",(unsigned int)tp.rx_desc);
++      printk("XOR:tx_desc_dma = %08x\n",(unsigned int)tp.tx_desc_dma);
++      printk("XOR:rx_desc_dma = %08x\n",(unsigned int)tp.rx_desc_dma);
++
++      if ((tp.tx_desc == NULL) || (tp.rx_desc == NULL)) {
++              if (tp.tx_desc)
++                      DMA_MFREE(tp.tx_desc, TX_DESC_NUM*sizeof(RAID_DESCRIPTOR_T),(dma_addr_t)tp.tx_desc_dma);
++              if (tp.rx_desc)
++                      DMA_MFREE(tp.rx_desc, RX_DESC_NUM*sizeof(RAID_DESCRIPTOR_T),(dma_addr_t)tp.rx_desc_dma);
++              return -ENOMEM;
++      }
++
++      tp.tx_cur_desc = tp.tx_desc;  /* virtual address */
++      tp.tx_finished_desc = tp.tx_desc; /* virtual address */
++      tx_first_desc_dma = (dma_addr_t)tp.tx_desc_dma; /* physical address */
++      for (i = 1; i < TX_DESC_NUM; i++) {
++              tp.tx_desc->func_ctrl.bits.own = CPU;
++              tp.tx_desc->func_ctrl.bits.buffer_size = 0;
++              tp.tx_desc_dma = tp.tx_desc_dma + sizeof(RAID_DESCRIPTOR_T);
++//            tp.tx_desc->next_desc_addr.bits32 = (unsigned int)tp.tx_desc_dma | 0x0B;
++              tp.tx_desc->next_desc_addr.bits32 = ((unsigned int)tx_first_desc_dma | 0x0B) + i*0x10;
++              tp.tx_desc = &tp.tx_desc[1];
++      }
++      tp.tx_desc->func_ctrl.bits.own = DMA;
++      tp.tx_desc->next_desc_addr.bits32 = (unsigned int)tx_first_desc_dma|0x0b;
++      tp.tx_desc = tp.tx_cur_desc;
++      tp.tx_desc_dma = (unsigned int*)tx_first_desc_dma;
++      tp.tx_first_desc = tp.tx_desc ;
++
++      tp.rx_cur_desc = tp.rx_desc;  /* virtual address */
++      tp.rx_finished_desc = tp.rx_desc; /* virtual address */
++      rx_first_desc_dma = (dma_addr_t)tp.rx_desc_dma; /* physical address */
++      for (i = 1; i < RX_DESC_NUM; i++) {
++              tp.rx_desc->func_ctrl.bits.own = DMA;
++              tp.rx_desc->func_ctrl.bits.buffer_size = 0;
++              tp.rx_desc_dma = tp.rx_desc_dma + sizeof(RAID_DESCRIPTOR_T);
++//            tp.rx_desc->next_desc_addr.bits32 = (unsigned int)tp.rx_desc_dma | 0x0B;
++              tp.rx_desc->next_desc_addr.bits32 = ((unsigned int)rx_first_desc_dma | 0x0B) + i*0x10;
++              tp.rx_desc = &tp.rx_desc[1];
++      }
++      tp.rx_desc->func_ctrl.bits.own = DMA;
++      tp.rx_desc->next_desc_addr.bits32 = rx_first_desc_dma|0x0b;
++      tp.rx_desc = tp.rx_cur_desc;
++      tp.rx_desc_dma = (unsigned int*)rx_first_desc_dma;
++      tp.rx_first_desc = tp.rx_desc ;
++      tp.busy = 0;
++      tp.status = COMPLETE;
++
++      // Partition SRAM size
++      raid_write_reg(RAID_PCR, SRAM_PAR_SIZE,0x00000003);
++
++      // config tx DMA controler
++      txdma_ctrl.bits32 = 0;
++      txdma_ctrl.bits.td_start = 0;
++      txdma_ctrl.bits.td_continue = 1;
++      txdma_ctrl.bits.td_chain_mode = 1;
++      txdma_ctrl.bits.td_prot = 0;
++      txdma_ctrl.bits.td_burst_size = 1;
++      txdma_ctrl.bits.td_bus = 3;
++      txdma_ctrl.bits.td_endian = 0;
++      txdma_ctrl.bits.td_finish_en = 1;
++      txdma_ctrl.bits.td_fail_en = 1;
++      txdma_ctrl.bits.td_perr_en = 1;
++      txdma_ctrl.bits.td_eod_en = 0;  // enable tx descript
++      txdma_ctrl.bits.td_eof_en = 0;
++      raid_write_reg(RAID_FCHDMA_CTRL, txdma_ctrl.bits32,0xFFFFFFFF);
++
++      // config rx DMA controler
++      rxdma_ctrl.bits32 = 0;
++      rxdma_ctrl.bits.rd_start = 0;
++      rxdma_ctrl.bits.rd_continue = 1;
++      rxdma_ctrl.bits.rd_chain_mode = 1;
++      rxdma_ctrl.bits.rd_prot = 0;
++      rxdma_ctrl.bits.rd_burst_size = 1;
++      rxdma_ctrl.bits.rd_bus = 3;
++      rxdma_ctrl.bits.rd_endian = 0;
++      rxdma_ctrl.bits.rd_finish_en = 0;
++      rxdma_ctrl.bits.rd_fail_en = 1;
++      rxdma_ctrl.bits.rd_perr_en = 1;
++      rxdma_ctrl.bits.rd_eod_en = 0;
++      rxdma_ctrl.bits.rd_eof_en = 0;
++      raid_write_reg(RAID_STRDMA_CTRL, rxdma_ctrl.bits32,0xFFFFFFFF);
++
++      // enable interrupt
++      dma_status.bits32 = 3;  // enable RpInt
++      raid_write_reg(RAID_DMA_STATUS, dma_status.bits32,0xFFFFFFFF);
++
++      return 0;
++}
++
++module_init(gemini_xor_init);
++module_exit(gemini_xor_exit);
++
+Index: linux-2.6.23.16/arch/arm/mm/Kconfig
+===================================================================
+--- linux-2.6.23.16.orig/arch/arm/mm/Kconfig   2008-03-13 17:46:04.500819685 +0200
++++ linux-2.6.23.16/arch/arm/mm/Kconfig        2008-03-13 17:48:24.508798285 +0200
+@@ -187,6 +187,26 @@
+         Say Y if you want support for the ARM926T processor.
+         Otherwise, say N.
++###### for Storlink SoC ######
++config CPU_FA526
++      bool "FA526 processor"
++      depends on ARCH_SL2312
++      default y
++      select CPU_32v4
++      select CPU_ABRT_EV4
++      select CPU_CACHE_FA
++      select CPU_CACHE_VIVT
++      select CPU_CP15_MMU
++      select CPU_COPY_FA
++      select CPU_TLB_FA
++      select CPU_FA_BTB
++      help
++        The FA526 is a version of the ARM9 compatible processor, but with smaller
++        instruction and data caches. It is used in Storlink Sword device family.
++
++        Say Y if you want support for the FA526 processor.
++        Otherwise, say N.
++
+ # ARM940T
+ config CPU_ARM940T
+       bool "Support ARM940T processor" if ARCH_INTEGRATOR
+@@ -461,6 +481,9 @@
+ config CPU_CACHE_VIPT
+       bool
++config CPU_CACHE_FA
++      bool
++
+ if MMU
+ # The copy-page model
+ config CPU_COPY_V3
+@@ -475,6 +498,12 @@
+ config CPU_COPY_V6
+       bool
++config CPU_COPY_FA
++      bool
++
++config CPU_FA_BTB
++      bool
++
+ # This selects the TLB model
+ config CPU_TLB_V3
+       bool
+@@ -534,6 +563,14 @@
+ config IO_36
+       bool
++config CPU_TLB_FA
++      bool
++      help
++        //TODO
++        Faraday ARM FA526 architecture, unified TLB with writeback cache
++        and invalidate instruction cache entry. Branch target buffer is also
++        supported.
++
+ comment "Processor Features"
+ config ARM_THUMB
+@@ -600,7 +637,7 @@
+ config CPU_DCACHE_WRITETHROUGH
+       bool "Force write through D-cache"
+-      depends on (CPU_ARM740T || CPU_ARM920T || CPU_ARM922T || CPU_ARM925T || CPU_ARM926T || CPU_ARM940T || CPU_ARM946E || CPU_ARM1020) && !CPU_DCACHE_DISABLE
++      depends on (CPU_ARM740T || CPU_ARM920T || CPU_ARM922T || CPU_ARM925T || CPU_ARM926T || CPU_ARM940T || CPU_ARM946E || CPU_ARM1020 || CPU_FA526) && !CPU_DCACHE_DISABLE
+       default y if CPU_ARM925T
+       help
+         Say Y here to use the data cache in writethrough mode. Unless you
+Index: linux-2.6.23.16/arch/arm/mm/Makefile
+===================================================================
+--- linux-2.6.23.16.orig/arch/arm/mm/Makefile  2008-03-13 17:46:04.500819685 +0200
++++ linux-2.6.23.16/arch/arm/mm/Makefile       2008-03-13 17:48:24.508798285 +0200
+@@ -32,6 +32,7 @@
+ obj-$(CONFIG_CPU_CACHE_V4WB)  += cache-v4wb.o
+ obj-$(CONFIG_CPU_CACHE_V6)    += cache-v6.o
+ obj-$(CONFIG_CPU_CACHE_V7)    += cache-v7.o
++obj-$(CONFIG_CPU_CACHE_FA)    += cache-fa.o
+ obj-$(CONFIG_CPU_COPY_V3)     += copypage-v3.o
+ obj-$(CONFIG_CPU_COPY_V4WT)   += copypage-v4wt.o
+@@ -40,6 +41,7 @@
+ obj-$(CONFIG_CPU_SA1100)      += copypage-v4mc.o
+ obj-$(CONFIG_CPU_XSCALE)      += copypage-xscale.o
+ obj-$(CONFIG_CPU_XSC3)                += copypage-xsc3.o
++obj-$(CONFIG_CPU_COPY_FA)     += copypage-fa.o
+ obj-$(CONFIG_CPU_TLB_V3)      += tlb-v3.o
+ obj-$(CONFIG_CPU_TLB_V4WT)    += tlb-v4.o
+@@ -47,6 +49,7 @@
+ obj-$(CONFIG_CPU_TLB_V4WBI)   += tlb-v4wbi.o
+ obj-$(CONFIG_CPU_TLB_V6)      += tlb-v6.o
+ obj-$(CONFIG_CPU_TLB_V7)      += tlb-v7.o
++obj-$(CONFIG_CPU_TLB_FA)      += tlb-fa.o
+ obj-$(CONFIG_CPU_ARM610)      += proc-arm6_7.o
+ obj-$(CONFIG_CPU_ARM710)      += proc-arm6_7.o
+@@ -60,6 +63,7 @@
+ obj-$(CONFIG_CPU_ARM926T)     += proc-arm926.o
+ obj-$(CONFIG_CPU_ARM940T)     += proc-arm940.o
+ obj-$(CONFIG_CPU_ARM946E)     += proc-arm946.o
++obj-$(CONFIG_CPU_FA526)               += proc-fa526.o
+ obj-$(CONFIG_CPU_ARM1020)     += proc-arm1020.o
+ obj-$(CONFIG_CPU_ARM1020E)    += proc-arm1020e.o
+ obj-$(CONFIG_CPU_ARM1022)     += proc-arm1022.o
+Index: linux-2.6.23.16/arch/arm/mm/cache-fa.S
+===================================================================
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.23.16/arch/arm/mm/cache-fa.S     2008-03-13 18:01:19.552965535 +0200
+@@ -0,0 +1,400 @@
++/*
++ *  linux/arch/arm/mm/cache-fa.S
++ *
++ *  Copyright (C) 2005 Faraday Corp.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ *  Processors: FA520 FA526 FA626     
++ * 03/31/2005 :       Luke Lee created, modified from cache-v4wb.S
++ * 04/06/2005 :       1. Read CR0-1 and determine the cache size dynamically,
++ *               to suit all Faraday CPU series
++ *            2. Fixed all functions
++ * 04/08/2005 :       insert CONFIG_CPU_ICACHE_DISABLE and CONFIG_CPU_DCACHE_DISABLE
++ * 04/12/2005 :       TODO: make this processor dependent or a self-modifying code to 
++ *            inline cache len/size info into the instructions, as reading cache 
++ *            size and len info in memory could cause another cache miss.
++ * 05/05/2005 :       Modify fa_flush_user_cache_range to comply APCS.
++ * 05/19/2005 :       Adjust for boundary conditions.
++ */
++#include <linux/linkage.h>
++#include <linux/init.h>
++#include <asm/hardware.h>
++#include <asm/page.h>
++#include "proc-macros.S"
++
++#define CACHE_DLINESIZE          16
++#ifdef CONFIG_SL3516_ASIC
++#define CACHE_DSIZE      8192
++#else
++#define CACHE_DSIZE      16384 
++#endif 
++#define CACHE_ILINESIZE          16
++#define CACHE_ISIZE      16384
++
++/* Luke Lee 04/06/2005 ins begin */
++/*
++ *    initialize_cache_info()
++ *
++ *    Automatic detection of DSIZE, DLEN, ISIZE, ILEN variables according to 
++ *    system register CR0-1
++ *    Destroyed register: r0, r1, r2, r3, ip
++ */
++      .align
++ENTRY(fa_initialize_cache_info)
++      mov     r3, #1                          @ r3 always = 1
++      adr     ip, __fa_cache_ilen
++      
++      mrc     p15, 0, r0, c0, c0, 1
++      /* ILEN */
++      and     r1, r0, #3                      @ bits [1:0]
++      add     r1, r1, #3                      @ cache line size is at least 8 bytes (2^3)
++      mov     r2, r3, lsl r1                  @ r2 = 1<<r1
++      str     r2, [ip], #4
++      /* ISIZE */
++      mov     r1, r0, lsr #6                  @ bits [8:6]
++      and     r1, r1, #7
++      add     r1, r1, #9                      @ cache size is at least 512 bytes (2^9)
++      mov     r2, r3, lsl r1
++      str     r2, [ip], #4
++      /* DLEN */
++      mov     r1, r0, lsr #12
++      and     r1, r1, #3                      @ bits [13:12]
++      add     r1, r1, #3                      @ cache line size is at least 8 bytes (2^3)
++      mov     r2, r3, lsl r1                  @ r2 = 1<<r1
++      str     r2, [ip], #4
++      /* DSIZE */
++      mov     r1, r0, lsr #18                 @ bits [20:18]
++      and     r1, r1, #7
++      add     r1, r1, #9                      @ cache size is at least 512 bytes (2^9)
++      mov     r2, r3, lsl r1
++      str     r2, [ip]
++      mov     pc, lr
++
++      /* Warning : Do not change the order ! Successive codes depends on this */
++      .align
++      .globl __fa_cache_ilen, __fa_cache_isize, __fa_cache_dlen, __fa_cache_dsize
++__fa_cache_ilen:
++      .word   0                               @ instruction cache line length
++__fa_cache_isize:
++      .word   0                               @ instruction cache size
++__fa_cache_dlen:
++      .word   0                               @ data cahce line length        
++__fa_cache_dsize:
++      .word   0                               @ data cache size
++
++/* Luke Lee 04/06/2005 ins end */
++
++/*
++ *    flush_user_cache_all()
++ *
++ *    Clean and invalidate all cache entries in a particular address
++ *    space.
++ */
++ENTRY(fa_flush_user_cache_all)
++      /* FALLTHROUGH */
++/*
++ *    flush_kern_cache_all()
++ *
++ *    Clean and invalidate the entire cache.
++ */
++ENTRY(fa_flush_kern_cache_all)
++/* Luke Lee 04/06/2005 mod ok */
++      mov     ip, #0
++      
++#ifndef CONFIG_CPU_ICACHE_DISABLE
++      mcr     p15, 0, ip, c7, c5, 0           @ invalidate I cache
++#endif
++      
++__flush_whole_cache:
++      
++#ifndef CONFIG_CPU_DCACHE_DISABLE
++      mov     ip, #0
++#  ifdef CONFIG_CPU_DCACHE_WRITETHROUGH
++      mcr     p15, 0, ip, c7, c6, 0           @ invalidate D cache
++#  else
++      mcr     p15, 0, ip, c7,c14, 0           @ clean/invalidate D cache
++#  endif
++#endif /*CONFIG_CPU_DCACHE_DISABLE*/
++      
++#ifndef CONFIG_CPU_FA_WB_DISABLE      
++      mcr     p15, 0, ip, c7, c10, 4          @ drain write buffer
++#endif
++      
++#ifdef CONFIG_CPU_FA_BTB
++      mcr     p15, 0, ip, c7, c5, 6           @ invalidate BTB
++      nop
++      nop
++#endif
++      
++/* Luke Lee 04/06/2005 que todo tofix : should iscratchpad and dscratchpad be invalidated ? */
++      mov     pc, lr
++
++/*
++ *    flush_user_cache_range(start, end, flags)
++ *
++ *    Invalidate a range of cache entries in the specified
++ *    address space.
++ *
++ *    - start - start address (inclusive, page aligned)
++ *    - end   - end address (exclusive, page aligned)
++ *    - flags - vma_area_struct flags describing address space
++ */
++ENTRY(fa_flush_user_cache_range)
++
++/* Luke Lee 04/06/2005 mod ok */
++      /* Luke Lee 04/07/2005 ins 1 */
++      mov     ip, #0
++      sub     r3, r1, r0                      @ calculate total size
++#ifndef CONFIG_CPU_ICACHE_DISABLE
++      tst     r2, #VM_EXEC                    @ executable region?
++      mcrne   p15, 0, ip, c7, c5, 0           @ invalidate I cache
++#endif
++
++#ifndef CONFIG_CPU_DCACHE_DISABLE     
++      /* Luke Lee 04/06/2005 ins 2 mod 1 */
++      cmp     r3, #CACHE_DSIZE                @ total size >= limit?
++      bhs     __flush_whole_cache             @ flush whole D cache
++
++      //debug_Aaron
++        bic     r0, r0, #CACHE_DLINESIZE-1  
++      mcr     p15, 0, r0, c7, c14, 1          @ clean and invalidate boundary D entry
++        bic     r1, r1, #CACHE_DLINESIZE-1  
++      mcr     p15, 0, r1, c7, c14, 1          @ clean and invalidate boundary D entry
++
++
++1:    /* Luke Lee 04/06/2005 del 2 ins 5 */
++      
++#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH
++      mcr     p15, 0, r0, c7, c6, 1           @ invalidate D entry
++#else
++      mcr     p15, 0, r0, c7, c14, 1          @ clean and invalidate D entry
++#endif
++      /* Luke Lee 04/06/2005 mod 1 */
++      add     r0, r0, #CACHE_DLINESIZE
++      cmp     r0, r1
++      bls     1b                              @ Luke Lee 05/19/2005
++#endif        /* CONFIG_CPU_DCACHE_DISABLE */
++      
++#ifndef CONFIG_CPU_FA_WB_DISABLE
++      tst     r2, #VM_EXEC
++      /* Luke Lee 04/06/2005 mod 1 tofix todo : ne->eq */
++      mcreq   p15, 0, r4, c7, c10, 4          @ drain write buffer
++#endif
++
++      /* Luke Lee 04/06/2005 ins block */
++#ifdef CONFIG_CPU_FA_BTB
++        tst     r2, #VM_EXEC
++      mov     ip, #0
++      mcrne   p15, 0, ip, c7, c5, 6           @ invalidate BTB
++      nop
++      nop
++#endif
++      mov     pc, lr
++
++/*
++ *    flush_kern_dcache_page(void *page)
++ *
++ *    Ensure no D cache aliasing occurs, either with itself or
++ *    the I cache
++ *
++ *    - addr  - page aligned address
++ */
++ENTRY(fa_flush_kern_dcache_page)
++      add     r1, r0, #PAGE_SZ
++      /* fall through */
++
++/*
++ *    coherent_kern_range(start, end)
++ *
++ *    Ensure coherency between the Icache and the Dcache in the
++ *    region described by start.  If you have non-snooping
++ *    Harvard caches, you need to implement this function.
++ *
++ *    - start  - virtual start address
++ *    - end    - virtual end address
++ */
++ENTRY(fa_coherent_kern_range)
++      /* fall through */
++
++/*
++ *    coherent_user_range(start, end)
++ *
++ *    Ensure coherency between the Icache and the Dcache in the
++ *    region described by start.  If you have non-snooping
++ *    Harvard caches, you need to implement this function.
++ *
++ *    - start  - virtual start address
++ *    - end    - virtual end address
++ */
++ENTRY(fa_coherent_user_range)
++
++/* Luke Lee 04/06/2005 mod ok */
++      /* Luke Lee 04/06/2005 ins 3 mod 1 */
++      bic     r0, r0, #CACHE_DLINESIZE-1
++
++ //debug_Aaron
++        bic     r0, r0, #CACHE_DLINESIZE-1
++        mcr     p15, 0, r0, c7, c14, 1          @ clean and invalidate boundary D entry
++        bic     r1, r1, #CACHE_DLINESIZE-1
++        mcr     p15, 0, r1, c7, c14, 1          @ clean and invalidate boundary D entry
++
++#if !(defined(CONFIG_CPU_DCACHE_DISABLE) && defined(CONFIG_CPU_ICACHE_DISABLE))
++1:    /* Luke Lee 04/06/2005 del 2 ins 5 mod 1 */
++#ifndef CONFIG_CPU_DCACHE_DISABLE     
++#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH
++      mcr     p15, 0, r0, c7, c6, 1           @ invalidate D entry
++#else
++      mcr     p15, 0, r0, c7, c14, 1          @ clean and invalidate D entry
++#endif
++#endif /* CONFIG_CPU_DCACHE_DISABLE */
++      
++#ifndef CONFIG_CPU_ICACHE_DISABLE
++      mcr     p15, 0, r0, c7, c5, 1           @ invalidate I entry
++#endif
++      add     r0, r0, #CACHE_DLINESIZE
++      cmp     r0, r1
++      bls     1b                              @ Luke Lee 05/19/2005 blo->bls  
++#endif /* !(defined(CONFIG_CPU_DCACHE_DISABLE) && defined(CONFIG_CPU_ICACHE_DISABLE)) */
++
++      mov     ip, #0
++#ifdef CONFIG_CPU_FA_BTB
++      mcr     p15, 0, ip, c7, c5, 6           @ invalidate BTB
++      nop
++      nop
++#endif
++
++/* Luke Lee 04/08/2005 ins 1 skp 1 ins 1 */
++#ifndef CONFIG_CPU_FA_WB_DISABLE
++      mcr     p15, 0, ip, c7, c10, 4          @ drain WB
++#endif
++
++      mov     pc, lr
++
++/*
++ *    dma_inv_range(start, end)
++ *
++ *    Invalidate (discard) the specified virtual address range.
++ *    May not write back any entries.  If 'start' or 'end'
++ *    are not cache line aligned, those lines must be written
++ *    back.
++ *
++ *    - start  - virtual start address
++ *    - end    - virtual end address
++ */
++ENTRY(fa_dma_inv_range)
++
++/* Luke Lee 04/06/2005 mod ok */
++
++#ifndef CONFIG_CPU_DCACHE_DISABLE     
++
++ //debug_Aaron
++        bic     r0, r0, #CACHE_DLINESIZE-1
++        mcr     p15, 0, r0, c7, c6, 1          @ invalidate boundary D entry
++        bic     r1, r1, #CACHE_DLINESIZE-1
++        mcr     p15, 0, r1, c7, c6, 1          @ invalidate boundary D entry
++
++      /* Luke Lee 04/06/2005 ins 4 mod 2 */
++#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH
++      tst     r0, #CACHE_DLINESIZE -1
++      bic     r0, r0, #CACHE_DLINESIZE -1
++
++//debug_Aaron
++      //mcrne p15, 0, r0, c7, c10, 1          @ clean boundary D entry
++
++      /* Luke Lee 04/06/2005 mod 1 */
++      /* Luke Lee 05/19/2005 always clean the end-point boundary mcrne->mcr */
++      ////tst r1, #CACHE_DLINESIZE -1
++      //mcr   p15, 0, r1, c7, c10, 1          @ clean boundary D entry
++      /* Luke Lee 04/06/2005 ins 1 */
++#else
++      bic     r0, r0, #CACHE_DLINESIZE -1     
++#endif
++
++//debug_Aaron 
++1:    mcr     p15, 0, r0, c7, c6, 1           @ invalidate D entry
++//1:  mcr     p15, 0, r0, c7, c14, 1          @ clean and invalidate D entry
++
++      /* Luke Lee 04/06/2005 mod 1 */ 
++      add     r0, r0, #CACHE_DLINESIZE
++      cmp     r0, r1
++      bls     1b                              @ Luke Lee 05/19/2005 blo->bls
++#endif /* CONFIG_CPU_DCACHE_DISABLE */
++
++      /* Luke Lee 04/06/2005 ins 1 */         
++#ifndef CONFIG_CPU_FA_WB_DISABLE
++      mov     r0, #0
++      mcr     p15, 0, r0, c7, c10, 4          @ drain write buffer
++#endif        
++
++      mov     pc, lr
++
++/*
++ *    dma_clean_range(start, end)
++ *
++ *    Clean (write back) the specified virtual address range.
++ *
++ *    - start  - virtual start address
++ *    - end    - virtual end address
++ */
++ENTRY(fa_dma_clean_range)
++
++/* Luke Lee 04/06/2005 mod ok */
++#ifndef CONFIG_CPU_DCACHE_DISABLE     
++
++ //debug_Aaron
++        bic     r0, r0, #CACHE_DLINESIZE-1
++        mcr     p15, 0, r0, c7, c10, 1          @ clean boundary D entry
++        bic     r1, r1, #CACHE_DLINESIZE-1
++        mcr     p15, 0, r1, c7, c10, 1          @ clean boundary D entry
++
++      /* Luke Lee 04/06/2005 ins 4 mod 2 */
++#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH
++      bic     r0, r0, #CACHE_DLINESIZE - 1
++
++//debug_Aaron
++1:    mcr     p15, 0, r0, c7, c10, 1          @ clean D entry
++//1:  mcr     p15, 0, r0, c7, c14, 1          @ clean D entry
++      add     r0, r0, #CACHE_DLINESIZE
++      cmp     r0, r1
++      bls     1b                              @ Luke Lee 05/19/2005 blo->bls
++      /* Luke Lee 04/06/2005 ins 2 */
++#endif
++#endif /* CONFIG_CPU_DCACHE_DISABLE */
++
++#ifndef CONFIG_CPU_FA_WB_DISABLE
++      mov     r0, #0  
++      mcr     p15, 0, r0, c7, c10, 4          @ drain write buffer
++#endif        
++
++      mov     pc, lr
++
++/*
++ *    dma_flush_range(start, end)
++ *
++ *    Clean and invalidate the specified virtual address range.
++ *
++ *    - start  - virtual start address
++ *    - end    - virtual end address
++ *
++ *    This is actually the same as fa_coherent_kern_range()
++ */
++      .globl  fa_dma_flush_range
++      .set    fa_dma_flush_range, fa_coherent_kern_range
++
++      __INITDATA
++
++      .type   fa_cache_fns, #object
++ENTRY(fa_cache_fns)
++      .long   fa_flush_kern_cache_all
++      .long   fa_flush_user_cache_all
++      .long   fa_flush_user_cache_range
++      .long   fa_coherent_kern_range
++      .long   fa_coherent_user_range
++      .long   fa_flush_kern_dcache_page
++      .long   fa_dma_inv_range
++      .long   fa_dma_clean_range
++      .long   fa_dma_flush_range
++      .size   fa_cache_fns, . - fa_cache_fns
+Index: linux-2.6.23.16/arch/arm/mm/copypage-fa.S
+===================================================================
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.23.16/arch/arm/mm/copypage-fa.S  2008-03-13 17:48:24.508798285 +0200
+@@ -0,0 +1,106 @@
++/*
++ *  linux/arch/arm/lib/copypage-fa.S
++ *
++ *  Copyright (C) 2005 Faraday Corp.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ *  ASM optimised string functions
++ * 05/18/2005 :       Luke Lee created, modified from copypage-v4wb.S
++ */
++#include <linux/linkage.h>
++#include <linux/init.h>
++#include <asm/asm-offsets.h>
++
++      .text
++/*
++ * ARMv4 optimised copy_user_page for Faraday processors
++ *
++ * We flush the destination cache lines just before we write the data into the
++ * corresponding address.  Since the Dcache is read-allocate, this removes the
++ * Dcache aliasing issue.  The writes will be forwarded to the write buffer,
++ * and merged as appropriate.
++ *
++ * Note: We rely on all ARMv4 processors implementing the "invalidate D line"
++ * instruction.  If your processor does not supply this, you have to write your
++ * own copy_user_page that does the right thing.
++ *
++ * copy_user_page(to,from,vaddr)
++ */
++      .align  4
++ENTRY(fa_copy_user_page)
++#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH
++      /* Write through */
++      stmfd   sp!, {r4, lr}                   @ 2
++      mov     r2, #PAGE_SZ/32                 @ 1
++
++      ldmia   r1!, {r3, r4, ip, lr}           @ 4
++1:    stmia   r0!, {r3, r4, ip, lr}           @ 4
++      ldmia   r1!, {r3, r4, ip, lr}           @ 4+1
++      subs    r2, r2, #1                      @ 1
++      stmia   r0!, {r3, r4, ip, lr}           @ 4
++      ldmneia r1!, {r3, r4, ip, lr}           @ 4
++      bne     1b                              @ 1
++
++      mcr     p15, 0, r2, c7, c7, 0           @ flush ID cache
++      ldmfd   sp!, {r4, pc}                   @ 3
++#else
++      /* Write back */
++      stmfd   sp!, {r4, lr}                   @ 2
++      mov     r2, #PAGE_SZ/32                 @ 1
++
++1:    ldmia   r1!, {r3, r4, ip, lr}           @ 4
++      mcr     p15, 0, r0, c7, c6, 1           @ 1   invalidate D line
++      stmia   r0!, {r3, r4, ip, lr}           @ 4
++      ldmia   r1!, {r3, r4, ip, lr}           @ 4
++      mcr     p15, 0, r0, c7, c6, 1           @ 1   invalidate D line
++      stmia   r0!, {r3, r4, ip, lr}           @ 4
++      subs    r2, r2, #1                      @ 1
++      bne     1b
++      mcr     p15, 0, r2, c7, c10, 4          @ 1   drain WB
++      ldmfd   sp!, {r4, pc}                   @ 3
++#endif
++
++/*
++ * ARMv4 optimised clear_user_page
++ *
++ * Same story as above.
++ */
++      .align  4
++ENTRY(fa_clear_user_page)
++      str     lr, [sp, #-4]!
++      mov     r1, #PAGE_SZ/32                 @ 1
++      mov     r2, #0                          @ 1
++      mov     r3, #0                          @ 1
++      mov     ip, #0                          @ 1
++      mov     lr, #0                          @ 1
++#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH
++      /* Write through */
++1:    stmia   r0!, {r2, r3, ip, lr}           @ 4
++      stmia   r0!, {r2, r3, ip, lr}           @ 4
++      subs    r1, r1, #1                      @ 1
++      bne     1b                              @ 1
++
++      mcr     p15, 0, r1, c7, c7, 0           @ flush ID cache
++      ldr     pc, [sp], #4
++#else
++      /* Write back */
++1:    mcr     p15, 0, r0, c7, c6, 1           @ 1   invalidate D line
++      stmia   r0!, {r2, r3, ip, lr}           @ 4
++      mcr     p15, 0, r0, c7, c6, 1           @ 1   invalidate D line
++      stmia   r0!, {r2, r3, ip, lr}           @ 4
++      subs    r1, r1, #1                      @ 1
++      bne     1b                              @ 1
++      mcr     p15, 0, r1, c7, c10, 4          @ 1   drain WB
++      ldr     pc, [sp], #4
++#endif
++
++      __INITDATA
++
++      .type   fa_user_fns, #object
++ENTRY(fa_user_fns)
++      .long   fa_clear_user_page
++      .long   fa_copy_user_page
++      .size   fa_user_fns, . - fa_user_fns
+Index: linux-2.6.23.16/arch/arm/mm/init.c
+===================================================================
+--- linux-2.6.23.16.orig/arch/arm/mm/init.c    2008-03-13 17:46:04.500819685 +0200
++++ linux-2.6.23.16/arch/arm/mm/init.c 2008-03-13 17:48:24.508798285 +0200
+@@ -23,6 +23,7 @@
+ #include <asm/mach/arch.h>
+ #include <asm/mach/map.h>
++#include <asm/arch/ipi.h>
+ #include "mm.h"
+@@ -252,6 +253,11 @@
+               initrd_end = initrd_start + phys_initrd_size;
+       }
+ #endif
++#ifdef CONFIG_GEMINI_IPI
++      printk("CPU ID:%d\n",getcpuid());
++//    reserve_bootmem_node(NODE_DATA(0), 0x400000, 0x400000);         //CPU0 space
++//    reserve_bootmem_node(NODE_DATA(0), SHAREADDR, SHARE_MEM_SIZE);          //share memory
++#endif
+       /*
+        * Finally, reserve any node zero regions.
+Index: linux-2.6.23.16/arch/arm/mm/proc-fa526.S
+===================================================================
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.23.16/arch/arm/mm/proc-fa526.S   2008-03-14 14:59:46.823166907 +0200
+@@ -0,0 +1,407 @@
++/*
++ *  linux/arch/arm/mm/proc-fa526.S: MMU functions for FA526
++ *
++ *  Copyright (C) 2005 Faraday Corp.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++ *
++ *
++ * These are the low level assembler for performing cache and TLB
++ * functions on the fa526.
++ *
++ *  Written by : Luke Lee
++ */
++#include <linux/linkage.h>
++#include <linux/init.h>
++#include <asm/assembler.h>
++#include <asm/pgtable.h>
++#include <asm/pgtable-hwdef.h>
++#include <asm/elf.h>
++#include <asm/hardware.h>
++#include <asm/page.h>
++#include <asm/ptrace.h>
++#include <asm/system.h>
++#include "proc-macros.S"
++
++#define CACHE_DLINESIZE          16
++
++      .text
++/*
++ * cpu_fa526_proc_init()
++ */
++ENTRY(cpu_fa526_proc_init)
++      /* MMU is already ON here, ICACHE, DCACHE conditionally disabled */
++
++        mov     r0, #1
++      nop
++      nop
++        mcr     p15, 0, r0, c1, c1, 0         @ turn-on ECR
++      nop
++      nop
++
++      mrc     p15, 0, r0, c1, c0, 0           @ read ctrl register
++
++#ifdef CONFIG_CPU_FA_BTB
++      orr     r0, r0, #CR_Z
++#else
++      bic     r0, r0, #CR_Z
++#endif
++#ifdef CONFIG_CPU_FA_WB_DISABLE
++      mov     r1, #0
++      mcr     p15, 0, r1, c7, c10, 4          @ drain write buffer
++      nop
++      nop
++      bic     r0, r0, #CR_W
++#else
++      orr     r0, r0, #CR_W
++#endif
++#ifdef CONFIG_CPU_DCACHE_DISABLE
++      bic     r0, r0, #CR_C
++#else
++      orr     r0, r0, #CR_C
++#endif
++#ifdef CONFIG_CPU_ICACHE_DISABLE
++      bic     r0, r0, #CR_I
++#else
++      orr     r0, r0, #CR_I
++#endif
++
++      nop
++      nop
++      mcr     p15, 0, r0, c1, c0, 0
++      nop
++      nop
++
++      mov     r5, lr
++      bl      fa_initialize_cache_info        @ destroy r0~r4
++      mov     pc, r5                          @ return
++
++
++/*
++ * cpu_fa526_proc_fin()
++ */
++ENTRY(cpu_fa526_proc_fin)
++      stmfd   sp!, {lr}
++      mov     ip, #PSR_F_BIT | PSR_I_BIT | SVC_MODE
++      msr     cpsr_c, ip
++
++      bl      fa_flush_kern_cache_all
++      mrc     p15, 0, r0, c1, c0, 0           @ ctrl register
++      bic     r0, r0, #0x1000                 @ ...i............
++      bic     r0, r0, #0x000e                 @ ............wca.
++      mcr     p15, 0, r0, c1, c0, 0           @ disable caches
++
++      nop
++      nop
++      ldmfd   sp!, {pc}
++
++/*
++ * cpu_fa526_reset(loc)
++ *
++ * Perform a soft reset of the system.  Put the CPU into the
++ * same state as it would be if it had been reset, and branch
++ * to what would be the reset vector.
++ *
++ * loc: location to jump to for soft reset
++ */
++      .align  4
++ENTRY(cpu_fa526_reset)
++      mov     ip, #0
++      mcr     p15, 0, ip, c7, c7, 0           @ invalidate I,D caches
++#ifndef CONFIG_CPU_FA_WB_DISABLE
++      mcr     p15, 0, ip, c7, c10, 4          @ drain WB
++#endif
++      mcr     p15, 0, ip, c8, c7, 0           @ invalidate I & D TLBs
++      mrc     p15, 0, ip, c1, c0, 0           @ ctrl register
++      bic     ip, ip, #0x000f                 @ ............wcam
++      bic     ip, ip, #0x1100                 @ ...i...s........
++
++      bic     ip, ip, #0x0800                 @ BTB off
++      mcr     p15, 0, ip, c1, c0, 0           @ ctrl register
++      nop
++      nop
++      mov     pc, r0
++
++/*
++ * cpu_fa526_do_idle()
++ */
++      .align  4
++ENTRY(cpu_fa526_do_idle)
++
++#ifdef CONFIG_CPU_FA_IDLE
++      nop
++      nop
++      mcr     p15, 0, r0, c7, c0, 4           @ Wait for interrupt (IDLE mode)
++#endif
++      mov     pc, lr
++
++
++ENTRY(cpu_fa526_dcache_clean_area)
++
++#ifndef CONFIG_CPU_DCACHE_DISABLE
++#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH
++1:    mcr     p15, 0, r0, c7, c10, 1          @ clean D entry
++      add     r0, r0, #CACHE_DLINESIZE
++      subs    r1, r1, #CACHE_DLINESIZE
++      bhi     1b
++#endif
++#endif
++      mov     pc, lr
++
++
++/* =============================== PageTable ============================== */
++
++/*
++ * cpu_fa526_switch_mm(pgd)
++ *
++ * Set the translation base pointer to be as described by pgd.
++ *
++ * pgd: new page tables
++ */
++      .align  4
++
++      .globl  fault_address
++fault_address:
++      .long   0
++
++ENTRY(cpu_fa526_switch_mm)
++
++      mov     ip, #0
++#ifndef CONFIG_CPU_DCACHE_DISABLE
++#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH
++      mcr     p15, 0, ip, c7, c6, 0           @ invalidate D cache
++#else
++      mcr     p15, 0, ip, c7, c14, 0          @ Clean and invalidate whole DCache
++#endif
++#endif /*CONFIG_CPU_DCACHE_DISABLE*/
++
++#ifndef CONFIG_CPU_ICACHE_DISABLE
++      mcr     p15, 0, ip, c7, c5, 0           @ invalidate I cache
++#endif
++
++#ifndef CONFIG_CPU_FA_WB_DISABLE
++      mcr     p15, 0, ip, c7, c10, 4          @ drain WB
++#endif
++
++#ifdef CONFIG_CPU_FA_BTB
++      mcr     p15, 0, ip, c7, c5, 6           @ invalidate BTB since mm changed
++      nop
++      nop
++#endif
++      bic     r0, r0, #0xff                   @ clear bits [7:0]
++      bic     r0, r0, #0x3f00                 @ clear bits [13:8]
++      mcr     p15, 0, r0, c2, c0, 0           @ load page table pointer
++      mcr     p15, 0, ip, c8, c7, 0           @ invalidate UTLB
++      nop
++      nop
++      mov     pc, lr
++
++/*
++ * cpu_fa526_set_pte_ext(ptep, pte, ext)
++ *
++ * Set a PTE and flush it out
++ */
++      .align  4
++ENTRY(cpu_fa526_set_pte_ext)
++      str     r1, [r0], #-2048                @ linux version
++
++      eor     r1, r1, #L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_WRITE | L_PTE_DIRTY
++
++      bic     r2, r1, #PTE_SMALL_AP_MASK
++      bic     r2, r2, #PTE_TYPE_MASK
++      orr     r2, r2, #PTE_TYPE_SMALL
++
++      tst     r1, #L_PTE_USER                 @ User?
++      orrne   r2, r2, #PTE_SMALL_AP_URO_SRW
++
++      tst     r1, #L_PTE_WRITE | L_PTE_DIRTY  @ Write and Dirty?
++      orreq   r2, r2, #PTE_SMALL_AP_UNO_SRW
++
++      tst     r1, #L_PTE_PRESENT | L_PTE_YOUNG        @ Present and Young?
++      movne   r2, #0
++
++#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH
++      eor     r3, r2, #0x0a                   @ C & small page?  1010
++      tst     r3, #0x0b                       @                  1011
++      biceq   r2, r2, #4
++#endif
++      str     r2, [r0]                        @ hardware version
++
++      mov     r2, #0
++      mcr     p15, 0, r2, c7, c10, 0          @ clean D cache all
++
++#ifndef CONFIG_CPU_FA_WB_DISABLE
++      mcr     p15, 0, r2, c7, c10, 4          @ drain WB
++#endif
++#ifdef CONFIG_CPU_FA_BTB
++      mcr     p15, 0, r2, c7, c5, 6           @ invalidate BTB
++      nop
++      nop
++#endif
++      mov     pc, lr
++
++      __INIT
++
++      .type   __fa526_setup, #function
++__fa526_setup:
++      /* On return of this routine, r0 must carry correct flags for CFG register */
++      mov     r0, #0
++      mcr     p15, 0, r0, c7, c7              @ invalidate I,D caches on v4
++      mcr     p15, 0, r0, c7, c10, 4          @ drain write buffer on v4
++      mcr     p15, 0, r0, c8, c7              @ invalidate I,D TLBs on v4
++
++      mcr     p15, 0, r0, c7, c5, 5           @ invalidate IScratchpad RAM
++
++        mov     r0, #1
++        mcr     p15, 0, r0, c1, c1, 0         @ turn-on ECR
++
++      mrc     p15, 0, r0, c9, c1, 0           @ DScratchpad
++      bic     r0, r0, #1
++      mcr     p15, 0, r0, c9, c1, 0
++      mrc     p15, 0, r0, c9, c1, 1           @ IScratchpad
++      bic     r0, r0, #1
++      mcr     p15, 0, r0, c9, c1, 1
++
++      mov     r0, #0
++      mcr     p15, 0, r0, c1, c1, 0           @ turn-off ECR
++
++#ifdef CONFIG_CPU_FA_BTB
++      mcr     p15, 0, r0, c7, c5, 6           @ invalidate BTB All
++      nop
++      nop
++#endif
++
++      mov     r0, #0x1f                       @ Domains 0, 1 = manager, 2 = client
++      mcr     p15, 0, r0, c3, c0              @ load domain access register
++
++      mrc     p15, 0, r0, c1, c0              @ get control register v4
++      ldr     r5, fa526_cr1_clear
++      bic     r0, r0, r5
++      ldr     r5, fa526_cr1_set
++      orr     r0, r0, r5
++
++#ifdef CONFIG_CPU_FA_BTB
++      orr     r0, r0, #CR_Z
++#else
++      bic     r0, r0, #CR_Z
++#endif
++#ifdef CONFIG_CPU_FA_WB_DISABLE
++      mov     r12, #0
++      mcr     p15, 0, r12, c7, c10, 4         @ drain write buffer
++      nop
++      nop
++      bic     r0, r0, #CR_W                   @ .... .... .... 1...
++#else
++      orr     r0, r0, #CR_W
++#endif
++
++      mov     pc, lr
++      .size   __fa526_setup, . - __fa526_setup
++
++      /*
++       * .RVI ZFRS BLDP WCAM
++       * ..11 0001 .111 1101
++       *
++       */
++      .type   fa526_cr1_clear, #object
++      .type   fa526_cr1_set, #object
++fa526_cr1_clear:
++      .word   0x3f3f
++fa526_cr1_set:
++      .word   0x317D
++
++      __INITDATA
++
++/*
++ * Purpose : Function pointers used to access above functions - all calls
++ *         come through these
++ */
++      .type   fa526_processor_functions, #object
++fa526_processor_functions:
++      .word   v4_early_abort
++      .word   cpu_fa526_proc_init
++      .word   cpu_fa526_proc_fin
++      .word   cpu_fa526_reset
++      .word   cpu_fa526_do_idle
++      .word   cpu_fa526_dcache_clean_area
++      .word   cpu_fa526_switch_mm
++      .word   cpu_fa526_set_pte_ext
++      .size   fa526_processor_functions, . - fa526_processor_functions
++
++      .section ".rodata"
++
++      .type   cpu_arch_name, #object
++cpu_arch_name:
++      .asciz  "armv4"
++      .size   cpu_arch_name, . - cpu_arch_name
++
++      .type   cpu_elf_name, #object
++cpu_elf_name:
++      .asciz  "v4"
++      .size   cpu_elf_name, . - cpu_elf_name
++
++      .type   cpu_fa526_name, #object
++cpu_fa526_name:
++      .ascii  "FA526"
++#ifndef CONFIG_CPU_ICACHE_DISABLE
++      .ascii  "i"
++#endif
++#ifndef CONFIG_CPU_DCACHE_DISABLE
++      .ascii  "d"
++#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH
++      .ascii  "(wt)"
++#else
++      .ascii  "(wb)"
++#endif
++#endif
++      .ascii  "\0"
++      .size   cpu_fa526_name, . - cpu_fa526_name
++
++      .align
++
++      .section ".proc.info.init", #alloc, #execinstr
++
++#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH
++#define __PMD_SECT_BUFFERABLE 0
++#else
++#define __PMD_SECT_BUFFERABLE PMD_SECT_BUFFERABLE
++#endif
++
++      .type   __fa526_proc_info,#object
++__fa526_proc_info:
++      .long   0x66015261
++      .long   0xff01fff1
++      .long   PMD_TYPE_SECT | \
++              __PMD_SECT_BUFFERABLE | \
++              PMD_SECT_CACHEABLE | \
++              PMD_BIT4 | \
++              PMD_SECT_AP_WRITE | \
++              PMD_SECT_AP_READ
++      .long   PMD_TYPE_SECT | \
++              PMD_BIT4 | \
++              PMD_SECT_AP_WRITE | \
++              PMD_SECT_AP_READ
++      b       __fa526_setup
++      .long   cpu_arch_name
++      .long   cpu_elf_name
++      .long   HWCAP_SWP | HWCAP_HALF
++      .long   cpu_fa526_name
++      .long   fa526_processor_functions
++      .long   fa_tlb_fns
++      .long   fa_user_fns
++      .long   fa_cache_fns
++      .size   __fa526_proc_info, . - __fa526_proc_info
++
++
+Index: linux-2.6.23.16/arch/arm/mm/tlb-fa.S
+===================================================================
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.23.16/arch/arm/mm/tlb-fa.S       2008-03-13 17:48:24.508798285 +0200
+@@ -0,0 +1,96 @@
++/*
++ *  linux/arch/arm/mm/tlb-fa.S
++ *
++ *  Copyright (C) 2005 Faraday Corp.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ *  ARM architecture version 4, Faraday variation.
++ *  This assume an unified TLBs, with a write buffer, and branch target buffer (BTB)
++ *
++ *  Processors: FA520 FA526 FA626
++ *  03/31/2005 : Created by Luke Lee, modified from tlb-v4wbi.S
++ *  05/06/2005 : Fixed buggy CPU versions that did not invalidate the associated
++ *               data cache entries when invalidating TLB entries.
++ */
++#include <linux/linkage.h>
++#include <linux/init.h>
++#include <asm/asm-offsets.h>
++#include <asm/tlbflush.h>
++#include "proc-macros.S"
++
++
++/*
++ *    flush_user_tlb_range(start, end, mm)
++ *
++ *    Invalidate a range of TLB entries in the specified address space.
++ *
++ *    - start - range start address
++ *    - end   - range end address
++ *    - mm    - mm_struct describing address space
++ */
++      .align  4
++ENTRY(fa_flush_user_tlb_range)
++
++      vma_vm_mm ip, r2
++      act_mm  r3                              @ get current->active_mm
++      eors    r3, ip, r3                      @ == mm ?
++      movne   pc, lr                          @ no, we dont do anything
++      mov     r3, #0
++
++#ifndef CONFIG_CPU_FA_WB_DISABLE
++      mcr     p15, 0, r3, c7, c10, 4          @ drain WB
++#endif
++
++      vma_vm_flags r2, r2
++      bic     r0, r0, #0x0ff
++      bic     r0, r0, #0xf00
++
++1:    mcr     p15, 0, r0, c8, c7, 1           @ invalidate UTLB entry
++      add     r0, r0, #PAGE_SZ
++      cmp     r0, r1
++      bls     1b                              @ Luke Lee 05/19/2005 blo -> bls
++
++#ifdef CONFIG_CPU_FA_BTB
++      mcr     p15, 0, r3, c7, c5, 6           @ invalidate BTB
++      nop
++      nop
++#endif
++      mov     pc, lr
++
++
++ENTRY(fa_flush_kern_tlb_range)
++      mov     r3, #0
++
++      mcr     p15, 0, r3, c7, c10, 0          @ clean Dcache all 06/03/2005
++
++#ifndef CONFIG_CPU_FA_WB_DISABLE
++      mcr     p15, 0, r3, c7, c10, 4          @ drain WB
++#endif
++
++      bic     r0, r0, #0x0ff
++      bic     r0, r0, #0xf00
++1:
++      mcr     p15, 0, r0, c8, c7, 1           @ invalidate UTLB entry
++      add     r0, r0, #PAGE_SZ
++      cmp     r0, r1
++      bls     1b                              @ Luke Lee 05/19/2005 blo -> bls
++
++#ifdef CONFIG_CPU_FA_BTB
++      mcr     p15, 0, r3, c7, c5, 6           @ invalidate BTB
++      nop
++      nop
++#endif
++      mov     pc, lr
++
++
++      __INITDATA
++
++      .type   fa_tlb_fns, #object
++ENTRY(fa_tlb_fns)
++      .long   fa_flush_user_tlb_range
++      .long   fa_flush_kern_tlb_range
++      .long   fa_tlb_flags
++      .size   fa_tlb_fns, . - fa_tlb_fns
+Index: linux-2.6.23.16/arch/arm/tools/mach-types
+===================================================================
+--- linux-2.6.23.16.orig/arch/arm/tools/mach-types     2008-03-13 17:46:04.500819685 +0200
++++ linux-2.6.23.16/arch/arm/tools/mach-types  2008-03-13 17:48:24.508798285 +0200
+@@ -208,7 +208,8 @@
+ fester                        SA1100_FESTER           FESTER                  191
+ gpi                   ARCH_GPI                GPI                     192
+ smdk2410              ARCH_SMDK2410           SMDK2410                193
+-i519                  ARCH_I519               I519                    194
++#i519                 ARCH_I519               I519                    194
++sl2312          ARCH_SL2312         SL2312          194
+ nexio                 SA1100_NEXIO            NEXIO                   195
+ bitbox                        SA1100_BITBOX           BITBOX                  196
+ g200                  SA1100_G200             G200                    197
+Index: linux-2.6.23.16/include/asm-arm/arch-sl2312/SL_gpio.h
+===================================================================
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.23.16/include/asm-arm/arch-sl2312/SL_gpio.h      2008-03-13 17:48:24.508798285 +0200
+@@ -0,0 +1,59 @@
++#define GPIO_MINOR_LAST 31
++#define GPIO_MAJOR    120     // Experiemental
++
++#define GPIO_IRQ_NBR  12
++
++#define GPIOBASEADDR          (IO_ADDRESS(0x021000000))
++
++#define GPIODATAOUTOFF                0x00
++#define GPIODATAINOFF         0x04
++#define GPIOPINDIROFF         0x08
++#define GPIOPINBYPASSOFF      0x0C
++#define GPIODATASETOFF                0x10
++#define GPIODATACLEAROFF      0x14
++#define GPIOPINPULLENBOFF     0x18
++#define GPIOPINPULLTPOFF      0x1C
++#define GPIOINTRENBOFF                0x20
++#define GPIOINTRRAWSOFF               0x24
++#define GPIOINTRMASKEDSTATEOFF        0x28
++#define GPIOINTRMASKOFF               0x2C
++#define GPIOINTRCLEAROFF      0x30
++#define GPIOINTRTRIGGEROFF    0x34
++#define GPIOINTRBOTHOFF               0x38
++#define GPIOINTRRISENEGOFF    0x3C
++#define GPIOBNCEENBOFF                0x40
++#define GPIOBNCEPRESOFF               0x44
++
++#define GPIO_IOCTRL_SETDIR    0x20
++#define GPIO_IOCTRL_SET               0x40
++#define GPIO_IOCTRL_CLEAR     0x50
++#define GPIO_IOCTRL_ENBINT    0x60
++#define GPIO_IOCTRL_MASKINT   0x70
++#define GPIO_IOCTRL_LVLTRIG   0x75
++#define GPIO_IOCTRL_EDGINT    0x77
++#define GPIO_IOCTRL_EDGPOLINT 0x78
++#define GPIO_IOCTRL_BYPASS    0x30
++#define GPIO_IOCTRL_PRESCLK   0x80
++#define GPIO_IOCTRL_CLKVAL    0x90
++#define GPIO_IOCTRL_PULLENB   0xA0
++#define GPIO_IOCTRL_PULLTYPE  0xA8
++
++
++#define GPIO_MAJOR    120     /* experimental MAJOR number */
++                              // Minor - 0 : 31 gpio pins
++
++#define GPIO_SET      0x01
++#define GPIO_CLEAR    0x01
++
++#define GPIO_INPUT    0
++#define GPIO_OUTPUT   1
++#define GPIO_EDGEINTR         0
++#define GPIO_EDGESINGL        0
++#define GPIO_EDGEBOTH 1
++#define GPIO_POSITIVE 0
++#define GPIO_ENBINT   1
++#define GPIO_DISABLEMASK      1
++#define GPIO_PULLDOWN 0
++#define GPIO_PULLUP   1
++#define GPIO_ENABLEPULL       1
++#define GPIO_DISABLEPULL      0
+Index: linux-2.6.23.16/include/asm-arm/arch-sl2312/debug-macro.S
+===================================================================
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.23.16/include/asm-arm/arch-sl2312/debug-macro.S  2008-03-13 17:48:24.508798285 +0200
+@@ -0,0 +1,20 @@
++/* linux/include/asm-arm/arch-ebsa110/debug-macro.S
++ *
++ * Debugging macro include header
++ *
++ *  Copyright (C) 1994-1999 Russell King
++ *  Moved from linux/arch/arm/kernel/debug.S by Ben Dooks
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++**/
++
++              .macro  addruart,rx
++              mov     \rx, #0x42000000
++              .endm
++
++#define UART_SHIFT    2
++#define FLOW_CONTROL
++#include <asm/hardware/debug-8250.S>
+Index: linux-2.6.23.16/include/asm-arm/arch-sl2312/dma.h
+===================================================================
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.23.16/include/asm-arm/arch-sl2312/dma.h  2008-03-13 17:48:24.508798285 +0200
+@@ -0,0 +1,28 @@
++/*
++ *  linux/include/asm-arm/arch-camelot/dma.h
++ *
++ *  Copyright (C) 1997,1998 Russell King
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++ */
++#ifndef __ASM_ARCH_DMA_H
++#define __ASM_ARCH_DMA_H
++
++#define MAX_DMA_ADDRESS               0xffffffff
++
++#define MAX_DMA_CHANNELS      0
++
++#endif /* _ASM_ARCH_DMA_H */
++
+Index: linux-2.6.23.16/include/asm-arm/arch-sl2312/entry-macro.S
+===================================================================
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.23.16/include/asm-arm/arch-sl2312/entry-macro.S  2008-03-13 17:49:18.511875745 +0200
+@@ -0,0 +1,42 @@
++/*
++ * include/asm-arm/arch-arm/entry-macro.S
++ *
++ * Low-level IRQ helper macros for ebsa110 platform.
++ *
++ * This file is licensed under  the terms of the GNU General Public
++ * License version 2. This program is licensed "as is" without any
++ * warranty of any kind, whether express or implied.
++ */
++#include <asm/arch/platform.h>
++#include <asm/arch/int_ctrl.h>
++
++
++                .macro  disable_fiq
++                .endm
++
++                .macro  get_irqnr_preamble, base, tmp
++                .endm
++
++                .macro  arch_ret_to_user, tmp1, tmp2
++                .endm
++
++                .macro  get_irqnr_and_base, irqnr, irqstat, base, tmp
++                ldr     \irqstat, =IRQ_STATUS(IO_ADDRESS(SL2312_INTERRUPT_BASE))
++                ldr     \irqnr,[\irqstat]
++                cmp     \irqnr,#0
++                beq     2313f
++                mov     \tmp,\irqnr
++                mov     \irqnr,#0
++2312:
++                tst     \tmp, #1
++                bne     2313f
++                add     \irqnr, \irqnr, #1
++                mov     \tmp, \tmp, lsr #1
++                cmp     \irqnr, #31
++                bcc     2312b
++2313:
++                .endm
++
++                .macro  irq_prio_table
++                .endm
++
+Index: linux-2.6.23.16/include/asm-arm/arch-sl2312/flash.h
+===================================================================
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.23.16/include/asm-arm/arch-sl2312/flash.h        2008-03-13 17:48:24.508798285 +0200
+@@ -0,0 +1,83 @@
++#ifndef __ASM_ARM_ARCH_FLASH_H
++#define __ASM_ARM_ARCH_FLASH_H
++
++#define FLASH_START                                     SL2312_FLASH_BASE
++#define SFLASH_SIZE                                   0x00400000
++#define SPAGE_SIZE                                    0x200
++#define BLOCK_ERASE                                   0x50
++#define BUFFER1_READ                                  0x54
++#define BUFFER2_READ                                  0x56
++#define PAGE_ERASE                                    0x81
++#define MAIN_MEMORY_PAGE_READ                         0x52
++#define MAIN_MEMORY_PROGRAM_BUFFER1                   0x82
++#define MAIN_MEMORY_PROGRAM_BUFFER2                   0x85
++#define BUFFER1_TO_MAIN_MEMORY                        0x83
++#define BUFFER2_TO_MAIN_MEMORY                        0x86
++#define MAIN_MEMORY_TO_BUFFER1                        0x53
++#define MAIN_MEMORY_TO_BUFFER2                        0x55
++#define BUFFER1_WRITE                                 0x84
++#define BUFFER2_WRITE                                 0x87
++#define AUTO_PAGE_REWRITE_BUFFER1                     0x58
++#define AUTO_PAGE_REWRITE_BUFFER2                     0x59
++#define READ_STATUS                                   0x57
++
++#define MAIN_MEMORY_PAGE_READ_SPI                     0xD2
++#define BUFFER1_READ_SPI                              0xD4
++#define BUFFER2_READ_SPI                              0xD6
++#define READ_STATUS_SPI                               0xD7
++
++#define       FLASH_ACCESS_OFFSET                             0x00000010
++#define       FLASH_ADDRESS_OFFSET                            0x00000014
++#define       FLASH_WRITE_DATA_OFFSET                         0x00000018
++#define       FLASH_READ_DATA_OFFSET                          0x00000018
++#define SERIAL_FLASH_CHIP1_EN            0x00010000  // 16th bit = 1
++#define SERIAL_FLASH_CHIP0_EN            0x00000000  // 16th bit = 0
++#define AT45DB321_PAGE_SHIFT                   0xa
++#define AT45DB642_PAGE_SHIFT                   0xb
++#define CONTINUOUS_MODE                        0x00008000
++
++#define FLASH_ACCESS_ACTION_OPCODE                      0x0000
++#define FLASH_ACCESS_ACTION_OPCODE_DATA                 0x0100
++#define FLASH_ACCESS_ACTION_SHIFT_ADDRESS               0x0200
++#define FLASH_ACCESS_ACTION_SHIFT_ADDRESS_DATA          0x0300
++#define FLASH_ACCESS_ACTION_SHIFT_ADDRESS_X_DATA          0x0400
++#define FLASH_ACCESS_ACTION_SHIFT_ADDRESS_2X_DATA         0x0500
++#define FLASH_ACCESS_ACTION_SHIFT_ADDRESS_3X_DATA         0x0600
++#define FLASH_ACCESS_ACTION_SHIFT_ADDRESS_4X_DATA         0x0700
++//#define FLASH_ACCESS_ACTION_SHIFT_ADDRESS_X_DATA        0x0600
++//#define FLASH_ACCESS_ACTION_SHIFT_ADDRESS_4X_DATA       0x0700
++
++#define M25P80_PAGE_SIZE  0x100
++#define M25P80_SECTOR_SIZE  0x10000
++
++
++//#define M25P80_BULK_ERASE                                      1
++//#define M25P80_SECTOR_ERASE                                    2
++//#define M25P80_SECTOR_SIZE                                     0x10000
++
++#define M25P80_WRITE_ENABLE                           0x06
++#define M25P80_WRITE_DISABLE                          0x04
++#define M25P80_READ_STATUS                            0x05
++#define M25P80_WRITE_STATUS                           0x01
++#define M25P80_READ                                   0x03
++#define M25P80_FAST_READ                              0x0B
++#define M25P80_PAGE_PROGRAM                           0x02
++#define M25P80_SECTOR_ERASE                           0xD8
++#define M25P80_BULK_ERASE                             0xC7
++#define FLASH_ERR_OK                                                  0x0
++
++extern void address_to_page(__u32, __u16 *, __u16 *);
++extern void main_memory_page_read(__u8, __u16, __u16, __u8 *);
++extern void buffer_to_main_memory(__u8, __u16);
++extern void main_memory_to_buffer(__u8, __u16);
++extern void main_memory_page_program(__u8, __u16, __u16, __u8);
++extern void atmel_flash_read_page(__u32, __u8 *, __u32);
++extern void atmel_erase_page(__u8, __u16);
++extern void atmel_read_status(__u8, __u8 *);
++extern void atmel_flash_program_page(__u32, __u8 *, __u32);
++extern void atmel_buffer_write(__u8, __u16, __u8);
++extern void flash_delay(void);
++
++extern int m25p80_sector_erase(__u32 address, __u32 schip_en);
++
++#endif
+Index: linux-2.6.23.16/include/asm-arm/arch-sl2312/gemini_cir.h
+===================================================================
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.23.16/include/asm-arm/arch-sl2312/gemini_cir.h   2008-03-13 17:48:24.508798285 +0200
+@@ -0,0 +1,102 @@
++#ifndef _ASM_ARCH_CIR_H
++#define _ASM_ARCH_CIR_H
++#include <linux/ioctl.h>
++
++#define VCR_KEY_POWER         0x613E609F
++#define TV1_KEY_POWER         0x40040100
++#define TV1_KEY_POWER_EXT     0xBCBD
++#define RC5_KER_POWER         0x0CF3
++
++#define VCC_H_ACT_PER         (16-1)
++#define VCC_L_ACT_PER         (8-1)
++#define VCC_DATA_LEN          (32-1)
++#define TV1_H_ACT_PER         (8-1)
++#define TV1_L_ACT_PER         (4-1)
++#define TV1_DATA_LEN          (48-1)
++
++#define VCC_BAUD              540
++#define TV1_BAUD              430
++#ifdef  CONFIG_SL3516_ASIC
++#define       EXT_CLK                 60
++#else
++#define       EXT_CLK                 20
++#endif
++
++#define       NEC_PROTOCOL    0x0
++#define       RC5_PROTOCOL    0x1
++#define VCC_PROTOCOL  0x0
++#define TV1_PROTOCOL  0x01
++
++#ifndef       SL2312_CIR_BASE
++#define       SL2312_CIR_BASE         0x4C000000
++#endif
++#define       CIR_BASE_ADDR           IO_ADDRESS(SL2312_CIR_BASE)
++#define STORLINK_CIR_ID               0x00010400
++
++#define       CIR_IP_ID               *(volatile unsigned int *)(CIR_BASE_ADDR + 0x00)
++#define       CIR_CTR_REG             *(volatile unsigned int *)(CIR_BASE_ADDR + 0x04)
++#define       CIR_STATUS_REG          *(volatile unsigned int *)(CIR_BASE_ADDR + 0x08)
++#define       CIR_RX_REG              *(volatile unsigned int *)(CIR_BASE_ADDR + 0x0C)
++#define       CIR_RX_EXT_REG          *(volatile unsigned int *)(CIR_BASE_ADDR + 0x10)
++#define       CIR_PWR_REG             *(volatile unsigned int *)(CIR_BASE_ADDR + 0x14)
++#define       CIR_PWR_EXT_REG         *(volatile unsigned int *)(CIR_BASE_ADDR + 0x18)
++#define       CIR_TX_CTR_REG          *(volatile unsigned int *)(CIR_BASE_ADDR + 0x1C)
++#define       CIR_TX_FEQ_REG          *(volatile unsigned int *)(CIR_BASE_ADDR + 0x20)
++#define       CIR_TX_REG              *(volatile unsigned int *)(CIR_BASE_ADDR + 0x24)
++#define       CIR_TX_EXT_REG          *(volatile unsigned int *)(CIR_BASE_ADDR + 0x28)
++
++
++#ifndef       SL2312_POWER_CTRL_BASE
++#define       SL2312_POWER_CTRL_BASE          0x4B000000
++#endif
++
++#ifndef PWR_BASE_ADDR
++#define       PWR_BASE_ADDR           IO_ADDRESS(SL2312_POWER_CTRL_BASE)
++#endif
++#define       PWR_CTRL_ID             *(unsigned int*)(PWR_BASE_ADDR+0x00)
++#define       PWR_CTRL_REG            *(unsigned int*)(PWR_BASE_ADDR+0x04)
++#define       PWR_STATUS_REG          *(unsigned int*)(PWR_BASE_ADDR+0x08)
++
++
++#define BIT(x)                        (1<<x)
++#define TX_STATUS             BIT(3)
++
++#define       PWR_STAT_CIR            0x10
++#define       PWR_STAT_RTC            0x20
++#define       PWR_STAT_PUSH           0x40
++#define       PWR_SHUTDOWN            0x01
++
++#define CARR_FREQ             38000
++
++struct cir_ioctl_data {
++      __u32 data;
++};
++struct cir_ioctl_data48 {
++      __u32 timeout;
++      __u32 length;
++      __u8  ret;
++      __u32 data;
++      __u32 data_ext;
++};
++#define OLD_DATA                      0
++#define NEW_RECEIVE                   1
++
++#define       CIR_IOCTL_BASE          ('I'|'R')
++#define CIR_SET_BAUDRATE                      _IOW (CIR_IOCTL_BASE,  0, struct cir_ioctl_data)
++#define CIR_SET_HIGH_PERIOD                   _IOW (CIR_IOCTL_BASE,  1, struct cir_ioctl_data)
++#define CIR_SET_LOW_PERIOD                    _IOW (CIR_IOCTL_BASE,  2, struct cir_ioctl_data)
++#define CIR_SET_PROTOCOL                      _IOW (CIR_IOCTL_BASE,  3, struct cir_ioctl_data)
++#define CIR_SET_ENABLE_COMPARE                _IOW (CIR_IOCTL_BASE,  4, struct cir_ioctl_data)
++#define CIR_SET_ENABLE_DEMOD          _IOW (CIR_IOCTL_BASE,  5, struct cir_ioctl_data)
++#define CIR_SET_POWER_KEY                     _IOW (CIR_IOCTL_BASE,  6, struct cir_ioctl_data)
++#define CIR_GET_BAUDRATE                      _IOR (CIR_IOCTL_BASE,  7, struct cir_ioctl_data)
++#define CIR_GET_HIGH_PERIOD                   _IOR (CIR_IOCTL_BASE,  8 ,struct cir_ioctl_data)
++#define CIR_GET_LOW_PERIOD                    _IOR (CIR_IOCTL_BASE,  9 ,struct cir_ioctl_data)
++#define CIR_GET_PROTOCOL                      _IOR (CIR_IOCTL_BASE, 10, struct cir_ioctl_data)
++#define CIR_GET_ENABLE_COMPARE                _IOR (CIR_IOCTL_BASE, 11, struct cir_ioctl_data)
++#define CIR_GET_ENABLE_DEMOD          _IOR (CIR_IOCTL_BASE, 12, struct cir_ioctl_data)
++#define CIR_GET_POWER_KEY                     _IOR (CIR_IOCTL_BASE, 13, struct cir_ioctl_data)
++#define CIR_GET_DATA                          _IOWR (CIR_IOCTL_BASE, 14, struct cir_ioctl_data48)
++#define CIR_WAIT_INT_DATA                     _IOWR (CIR_IOCTL_BASE, 15, struct cir_ioctl_data48)
++
++#endif //_ASM_ARCH_CIR_H
+Index: linux-2.6.23.16/include/asm-arm/arch-sl2312/gemini_gpio.h
+===================================================================
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.23.16/include/asm-arm/arch-sl2312/gemini_gpio.h  2008-03-13 17:48:24.508798285 +0200
+@@ -0,0 +1,77 @@
++/*
++ * FILE NAME gemini_gpio.h
++ *
++ * BRIEF MODULE DESCRIPTION
++ *    Generic Gemini GPIO
++ *
++ *  Author: Storlink Software [Device driver]
++ *          Jason Lee <jason@storlink.com.tw>
++ *
++ * Copyright 2005 Storlink Inc.
++ *
++ *  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  SOFTWARE  IS PROVIDED   ``AS  IS'' AND   ANY  EXPRESS OR IMPLIED
++ *  WARRANTIES,   INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
++ *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
++ *  NO  EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT, INDIRECT,
++ *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ *  NOT LIMITED   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF
++ *  USE, DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
++ *  ANY THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT
++ *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++ *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ *
++ *  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.,
++ *  675 Mass Ave, Cambridge, MA 02139, USA.
++ */
++
++#ifndef __GEMINI_GPIO_H
++#define __GEMINI_GPIO_H
++
++#include <linux/ioctl.h>
++
++#define STATUS_HIGH   1
++#define STATUS_LOW    0
++#define DIRECT_OUT    1
++#define DIRECT_IN     0
++
++#define EDGE_TRIG     0
++#define RISING_EDGE   0
++#define FALL_EDGE     1
++#define SINGLE_EDGE   0
++#define BOTH_EDGE     1
++
++#define LEVEL_TRIG    1
++#define HIGH_ACTIVE   0
++#define LOW_ACTIVE    1
++
++struct gemini_gpio_ioctl_data {
++      __u32 pin;
++      __u8 status;                    // status or pin direction
++                                      // 0: status low or Input
++                                      // 1: status high or Output
++
++      /* these member are used to config GPIO interrupt parameter */
++      __u8    use_default;            // if not sure ,set this argument 1
++      __u8    trig_type;              // 0/1:edge/level triger ?
++      __u8    trig_polar;             // 0/1:rising/falling high/low active ?
++      __u8    trig_both;              // 0/1:single/both detect both ?
++};
++
++#define GEMINI_GPIO_IOCTL_BASE        'Z'
++
++#define GEMINI_SET_GPIO_PIN_DIR               _IOW (GEMINI_GPIO_IOCTL_BASE,16, struct gemini_gpio_ioctl_data)
++#define       GEMINI_SET_GPIO_PIN_STATUS      _IOW (GEMINI_GPIO_IOCTL_BASE,17, struct gemini_gpio_ioctl_data)
++#define       GEMINI_GET_GPIO_PIN_STATUS      _IOWR(GEMINI_GPIO_IOCTL_BASE,18, struct gemini_gpio_ioctl_data)
++#define GEMINI_WAIT_GPIO_PIN_INT      _IOWR(GEMINI_GPIO_IOCTL_BASE,19, struct gemini_gpio_ioctl_data)
++
++
++extern void init_gpio_int(__u32 pin,__u8 trig_type,__u8 trig_polar,__u8 trig_both);
++extern int request_gpio_irq(int bit,void (*handler)(int),char level,char high,char both);
++extern int free_gpio_irq(int bit);
++#endif
+Index: linux-2.6.23.16/include/asm-arm/arch-sl2312/gemini_i2s.h
+===================================================================
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.23.16/include/asm-arm/arch-sl2312/gemini_i2s.h   2008-03-13 17:48:24.508798285 +0200
+@@ -0,0 +1,169 @@
++#ifndef __GEMINI_I2S_H__
++#define __GEMINI_I2S_H__
++#include <linux/ioctl.h>
++#include <linux/types.h>
++#include <asm/arch-sl2312/irqs.h>
++
++typedef __u16 UINT16;
++typedef __u32 UINT32;
++typedef __u8 UINT8;
++typedef __u8 BOOL;
++
++/***************************************/
++/* define GPIO module base address     */
++/***************************************/
++#define DMA_CONTROL_PHY_BASE  (IO_ADDRESS(SL2312_GENERAL_DMA_BASE))
++#define DMA_CONTROL_SSP_BASE  (IO_ADDRESS(SL2312_SSP_CTRL_BASE))
++#define SSP_INT                               IRQ_SSP
++#define GPIO_BASE_ADDR      (IO_ADDRESS(SL2312_GPIO_BASE))
++#define GPIO_BASE_ADDR1      (IO_ADDRESS(SL2312_GPIO_BASE1))
++#define GLOBAL_BASE      (IO_ADDRESS(SL2312_GLOBAL_BASE))
++
++/* define read/write register utility */
++#define READ_SSP_REG(offset)                  (__raw_readl(offset+DMA_CONTROL_SSP_BASE))
++#define WRITE_SSP_REG(offset,val)     (__raw_writel(val,offset+DMA_CONTROL_SSP_BASE))
++
++#define READ_GPIO_REG(offset)                 (__raw_readl(offset+GPIO_BASE_ADDR))
++#define WRITE_GPIO_REG(offset,val)    (__raw_writel(val,offset+GPIO_BASE_ADDR))
++
++#define READ_GPIO1_REG(offset)                        (__raw_readl(offset+GPIO_BASE_ADDR1))
++#define WRITE_GPIO1_REG(offset,val)   (__raw_writel(val,offset+GPIO_BASE_ADDR1))
++
++#define READ_DMA_REG(offset)                  (__raw_readl(offset+DMA_CONTROL_PHY_BASE))
++#define WRITE_DMA_REG(offset,val)     (__raw_writel(val,offset+DMA_CONTROL_PHY_BASE))
++
++#define READ_GLOBAL_REG(offset)                       (__raw_readl(offset+GLOBAL_BASE))
++#define WRITE_GLOBAL_REG(offset,val)  (__raw_writel(val,offset+GLOBAL_BASE))
++
++#define SSP_GPIO_INT          IRQ_GPIO
++
++#ifndef CONFIG_SL3516_ASIC
++#define SSP_GPIO_INT_BIT    0x00000400                                //GPIO[10] : SLIC interrupt pin
++
++#define GPIO_EECK          0x00000040         /*   SCK: GPIO[06]   */
++#define GPIO_EECS          0x00000080                 /*   SCS: GPIO[07]   */
++#define GPIO_MISO          0x00000200         /*   SDO: GPIO[09]   receive from 6996*/
++#define GPIO_MOSI          0x00000100         /*   SDI: GPIO[08]   send to 6996*/
++#define GPIO_MISO_BIT  9
++#else
++#define SSP_GPIO_INT_BIT    0x00000001                                //GPIO[0] : SLIC interrupt pin
++
++//#if 0
++//#define GPIO_EECK        0x80000000         /*   SCK: GPIO1[31]   */
++//#define GPIO_EECS        0x40000000                 /*   SCS: GPIO1[30]   */
++//#define GPIO_MISO        0x20000000         /*   SDO: GPIO1[29]   receive from 6996*/
++//#define GPIO_MOSI        0x10000000         /*   SDI: GPIO1[28]   send to 6996*/
++//#define GPIO_MISO_BIT       29
++//#else
++//#define GPIO_EECK        0x00000100         /*   SCK: GPIO1[08]   */
++//#define GPIO_EECS        0x08000000                 /*   SCS: GPIO1[27]   */
++//#define GPIO_MISO        0x00000080         /*   SDO: GPIO1[07]   receive from 6996*/
++//#define GPIO_MOSI        0x00000200         /*   SDI: GPIO1[09]   send to 6996*/
++//#define GPIO_MISO_BIT       7
++//#endif
++#endif
++
++
++enum GPIO_REG
++{
++      GPIO_DATA_OUT           = 0x00,
++      GPIO_DATA_IN            = 0x04,
++      GPIO_PIN_DIR            = 0x08,
++      GPIO_BY_PASS            = 0x0c,
++      GPIO_DATA_SET           = 0x10,
++      GPIO_DATA_CLEAR         = 0x14,
++      GPIO_INT_ENABLE     = 0x20,
++      GPIO_INT_RAWSTATE   = 0x24,
++      GPIO_INT_MASKSTATE  = 0x28,
++      GPIO_INT_MASK       = 0x2C,
++      GPIO_INT_CLEAR      = 0x30,
++      GPIO_INT_TRIGGER    = 0x34,
++      GPIO_INT_BOTH       = 0x38,
++      GPIO_INT_POLARITY   = 0x3C
++};
++
++typedef struct
++{
++      UINT32 src_addr;
++      UINT32 dst_addr;
++      UINT32 llp;
++      UINT32 ctrl_size;
++      UINT32 owner;
++}DMA_LLP_t;
++
++typedef struct
++{
++      UINT32 owner;
++      UINT32 src_addr;
++      UINT32 ctrl_size;
++}IOCTL_LLP_t;
++
++typedef unsigned char byte;
++typedef unsigned short word;
++typedef unsigned long dword;
++
++/* DMA Registers */
++#define       DMA_INT                                 0x00000000
++#define       DMA_INT_TC                              0x00000004
++#define       DMA_CFG                                 0x00000024
++#define       DMA_INT_TC_CLR                          0x00000008
++#define       DMA_TC                                          0x00000014
++#define       DMA_CSR                                         0x00000024
++#define       DMA_SYNC                                        0x00000028
++
++#define       DMA_CH2_CSR                             0x00000140
++#define       DMA_CH2_CFG                             0x00000144
++#define       DMA_CH2_SRC_ADDR                0x00000148
++#define       DMA_CH2_DST_ADDR                0x0000014c
++#define       DMA_CH2_LLP                             0x00000150
++#define       DMA_CH2_SIZE                            0x00000154
++
++#define       DMA_CH3_CSR                             0x00000160
++#define       DMA_CH3_CFG                             0x00000164
++#define       DMA_CH3_SRC_ADDR                0x00000168
++#define       DMA_CH3_DST_ADDR                0x0000016c
++#define       DMA_CH3_LLP                             0x00000170
++#define       DMA_CH3_SIZE                            0x00000174
++
++#define    SSP_DEVICE_ID                      0x00
++#define    SSP_CTRL_STATUS                    0x04
++#define          SSP_FRAME_CTRL           0x08
++#define    SSP_BAUD_RATE            0x0c
++#define    SSP_FRAME_CTRL2          0x10
++#define    SSP_FIFO_CTRL            0x14
++#define    SSP_TX_SLOT_VALID0       0x18
++#define    SSP_TX_SLOT_VALID1       0x1c
++#define    SSP_TX_SLOT_VALID2       0x20
++#define    SSP_TX_SLOT_VALID3       0x24
++#define    SSP_RX_SLOT_VALID0       0x28
++#define    SSP_RX_SLOT_VALID1       0x2c
++#define    SSP_RX_SLOT_VALID2       0x30
++#define    SSP_RX_SLOT_VALID3       0x34
++#define    SSP_SLOT_SIZE0           0x38
++#define    SSP_SLOT_SIZE1           0x3c
++#define    SSP_SLOT_SIZE2           0x40
++#define    SSP_SLOT_SIZE3           0x44
++#define    SSP_READ_PORT            0x48
++#define    SSP_WRITE_PORT           0x4c
++
++
++
++#define SSP_I2S_INIT_BUF                      _IO  ('q', 0x00)
++#define SSP_I2S_STOP_DMA                      _IO  ('q', 0x01)
++#define SSP_I2S_FILE_LEN                      _IOW  ('q', 0x2, int)
++/*
++#define SSP_GET_HOOK_STATUS                   _IOR  ('q', 0xC0, int)
++#define SSP_GET_LINEFEED                      _IOR  ('q', 0xC1, int)
++#define SSP_SET_LINEFEED                      _IOW  ('q', 0xC2, int)
++#define SSP_GET_REG                 _IOWR ('q', 0xC3, struct Ssp_reg *)
++#define SSP_SET_REG                 _IOWR ('q', 0xC4, struct Ssp_reg *)
++#define SSP_GEN_OFFHOOK_TONE          _IO   ('q', 0xC5)
++#define SSP_GEN_BUSY_TONE                     _IO   ('q', 0xC6)
++#define SSP_GEN_RINGBACK_TONE         _IO   ('q', 0xC7)
++#define SSP_GEN_CONGESTION_TONE               _IO   ('q', 0xC8)
++#define SSP_DISABLE_DIALTONE          _IO   ('q', 0xC9)
++#define SSP_PHONE_RING_START          _IO   ('q', 0xCA)
++*/
++
++
++#endif //__GEMINI_I2S_H__
+Index: linux-2.6.23.16/include/asm-arm/arch-sl2312/gemini_ssp.h
+===================================================================
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.23.16/include/asm-arm/arch-sl2312/gemini_ssp.h   2008-03-13 17:48:24.508798285 +0200
+@@ -0,0 +1,263 @@
++/******************************************************************************
++ *    gemini_ssp.h
++ *
++ *
++ *****************************************************************************/
++
++#include <linux/types.h>
++#include <asm/arch-sl2312/irqs.h>
++#include <linux/phonedev.h>
++#include <linux/telephony.h>
++//#include "proslic.h"
++
++typedef __u16 UINT16;
++typedef __u32 UINT32;
++typedef __u8 UINT8;
++typedef __u8 BOOL;
++
++#define TRUE 1
++#define FALSE 0
++
++/***************************************/
++/* define GPIO module base address     */
++/***************************************/
++#define DMA_CONTROL_PHY_BASE  (IO_ADDRESS(SL2312_GENERAL_DMA_BASE))
++#define DMA_CONTROL_SSP_BASE  (IO_ADDRESS(SL2312_SSP_CTRL_BASE))
++#define SSP_INT                               IRQ_SSP
++#define GPIO_BASE_ADDR      (IO_ADDRESS(SL2312_GPIO_BASE))
++#define GPIO_BASE_ADDR1      (IO_ADDRESS(SL2312_GPIO_BASE1))
++#define GLOBAL_BASE      (IO_ADDRESS(SL2312_GLOBAL_BASE))
++
++/* define read/write register utility */
++#define READ_SSP_REG(offset)                  (__raw_readl(offset+DMA_CONTROL_SSP_BASE))
++#define WRITE_SSP_REG(offset,val)     (__raw_writel(val,offset+DMA_CONTROL_SSP_BASE))
++
++#define READ_GPIO_REG(offset)                 (__raw_readl(offset+GPIO_BASE_ADDR))
++#define WRITE_GPIO_REG(offset,val)    (__raw_writel(val,offset+GPIO_BASE_ADDR))
++
++#define READ_GPIO1_REG(offset)                        (__raw_readl(offset+GPIO_BASE_ADDR1))
++#define WRITE_GPIO1_REG(offset,val)   (__raw_writel(val,offset+GPIO_BASE_ADDR1))
++
++#define READ_DMA_REG(offset)                  (__raw_readl(offset+DMA_CONTROL_PHY_BASE))
++#define WRITE_DMA_REG(offset,val)     (__raw_writel(val,offset+DMA_CONTROL_PHY_BASE))
++
++#define READ_GLOBAL_REG(offset)                       (__raw_readl(offset+GLOBAL_BASE))
++#define WRITE_GLOBAL_REG(offset,val)  (__raw_writel(val,offset+GLOBAL_BASE))
++
++
++#define SSP_GPIO_INT          IRQ_GPIO
++
++#ifndef CONFIG_SL3516_ASIC
++#define SSP_GPIO_INT_BIT    0x00000400                                //GPIO[10] : SLIC interrupt pin
++
++#define GPIO_EECK          0x00000040         /*   SCK: GPIO[06]   */
++#define GPIO_EECS          0x00000080                 /*   SCS: GPIO[07]   */
++#define GPIO_MISO          0x00000200         /*   SDO: GPIO[09]   receive from 6996*/
++#define GPIO_MOSI          0x00000100         /*   SDI: GPIO[08]   send to 6996*/
++#define GPIO_MISO_BIT  9
++#else
++#define SSP_GPIO_INT_BIT    0x00000001                                //GPIO[0] : SLIC interrupt pin
++
++//#if 0
++//#define GPIO_EECK        0x80000000         /*   SCK: GPIO1[31]   */
++//#define GPIO_EECS        0x40000000                 /*   SCS: GPIO1[30]   */
++//#define GPIO_MISO        0x20000000         /*   SDO: GPIO1[29]   receive from 6996*/
++//#define GPIO_MOSI        0x10000000         /*   SDI: GPIO1[28]   send to 6996*/
++//#define GPIO_MISO_BIT       29
++//#else
++//#define GPIO_EECK        0x00000100         /*   SCK: GPIO1[08]   */
++//#define GPIO_EECS        0x08000000                 /*   SCS: GPIO1[27]   */
++//#define GPIO_MISO        0x00000080         /*   SDO: GPIO1[07]   receive from 6996*/
++//#define GPIO_MOSI        0x00000200         /*   SDI: GPIO1[09]   send to 6996*/
++//#define GPIO_MISO_BIT       7
++//#endif
++#endif
++
++
++enum GPIO_REG
++{
++      GPIO_DATA_OUT           = 0x00,
++      GPIO_DATA_IN            = 0x04,
++      GPIO_PIN_DIR            = 0x08,
++      GPIO_BY_PASS            = 0x0c,
++      GPIO_DATA_SET           = 0x10,
++      GPIO_DATA_CLEAR         = 0x14,
++      GPIO_INT_ENABLE     = 0x20,
++      GPIO_INT_RAWSTATE   = 0x24,
++      GPIO_INT_MASKSTATE  = 0x28,
++      GPIO_INT_MASK       = 0x2C,
++      GPIO_INT_CLEAR      = 0x30,
++      GPIO_INT_TRIGGER    = 0x34,
++      GPIO_INT_BOTH       = 0x38,
++      GPIO_INT_POLARITY   = 0x3C
++};
++
++
++#define SPI_ADD_LEN        7                  // bits of Address
++#define SPI_DAT_LEN        8                  // bits of Data
++
++
++
++//#ifdef MIDWAY_DIAG
++#define       DAISY_MODE      1
++#if (DAISY_MODE==1)
++#define NUMBER_OF_CHAN        2
++#else
++#define NUMBER_OF_CHAN        1
++#endif
++#define LLP_SIZE   8
++#define SBUF_SIZE  512 //0xff0 //2560
++#define DBUF_SIZE  SBUF_SIZE*NUMBER_OF_CHAN //0xff0 //2560
++#define TBUF_SIZE  (LLP_SIZE)*DBUF_SIZE
++#define DESC_NUM   1
++#define DTMF_NUM   20
++
++/* define owner bit of SSP */
++//data into SSP and transfer to AP==> SSP_Rx
++//data out of SSP and transfer to SLIC==> SSP_Tx
++#define CPU           0
++#define DMA           1
++
++#define DMA_DEMO   0
++#define DMA_NDEMO  1
++//#define DMA_NONE   2
++
++enum exceptions {
++      PROSLICiNSANE,
++      TIMEoUTpOWERuP,
++      TIMEoUTpOWERdOWN,
++      POWERlEAK,
++      TIPoRrINGgROUNDsHORT,
++      POWERaLARMQ1,
++      POWERaLARMQ2,
++      POWERaLARMQ3,
++      POWERaLARMQ4,
++      POWERaLARMQ5,
++      OWERaLARMQ6,
++      CM_CAL_ERR
++};
++
++typedef struct
++{
++      UINT32 src_addr;
++      UINT32 dst_addr;
++      UINT32 llp;
++      UINT32 ctrl_size;
++}DMA_LLP_t;
++
++typedef struct {
++      unsigned int own ;
++      char  *tbuf;
++      //UINT32 *LinkAddrT;
++      DMA_LLP_t LLPT[LLP_SIZE];
++}DMA_Tx_t;
++
++typedef struct {
++      unsigned int own ;
++      char  *rbuf;
++      //UINT32 *LinkAddrR;
++      DMA_LLP_t LLPR[LLP_SIZE];
++}DMA_Rx_t;
++
++//typedef struct {
++//    //UINT32 init_stat;
++//    struct chipStruct chipData ; /* Represents a proslics state, cached information, and timers */
++//    struct phone_device p;
++//
++//
++//}SSP_SLIC;
++
++
++
++/* DMA Registers */
++#define       DMA_INT                                 0x00000000
++#define       DMA_INT_TC                              0x00000004
++#define       DMA_CFG                                 0x00000024
++#define       DMA_INT_TC_CLR                          0x00000008
++#define       DMA_TC                                          0x00000014
++#define       DMA_CSR                                         0x00000024
++#define       DMA_SYNC                                        0x00000028
++
++#define       DMA_CH2_CSR                             0x00000140
++#define       DMA_CH2_CFG                             0x00000144
++#define       DMA_CH2_SRC_ADDR                0x00000148
++#define       DMA_CH2_DST_ADDR                0x0000014c
++#define       DMA_CH2_LLP                             0x00000150
++#define       DMA_CH2_SIZE                            0x00000154
++
++#define       DMA_CH3_CSR                             0x00000160
++#define       DMA_CH3_CFG                             0x00000164
++#define       DMA_CH3_SRC_ADDR                0x00000168
++#define       DMA_CH3_DST_ADDR                0x0000016c
++#define       DMA_CH3_LLP                             0x00000170
++#define       DMA_CH3_SIZE                            0x00000174
++
++#define    SSP_DEVICE_ID                      0x00
++#define    SSP_CTRL_STATUS                    0x04
++#define          SSP_FRAME_CTRL           0x08
++#define    SSP_BAUD_RATE            0x0c
++#define    SSP_FRAME_CTRL2          0x10
++#define    SSP_FIFO_CTRL            0x14
++#define    SSP_TX_SLOT_VALID0       0x18
++#define    SSP_TX_SLOT_VALID1       0x1c
++#define    SSP_TX_SLOT_VALID2       0x20
++#define    SSP_TX_SLOT_VALID3       0x24
++#define    SSP_RX_SLOT_VALID0       0x28
++#define    SSP_RX_SLOT_VALID1       0x2c
++#define    SSP_RX_SLOT_VALID2       0x30
++#define    SSP_RX_SLOT_VALID3       0x34
++#define    SSP_SLOT_SIZE0           0x38
++#define    SSP_SLOT_SIZE1           0x3c
++#define    SSP_SLOT_SIZE2           0x40
++#define    SSP_SLOT_SIZE3           0x44
++#define    SSP_READ_PORT            0x48
++#define    SSP_WRITE_PORT           0x4c
++
++
++void printFreq_Revision(int num);
++void SLIC_SPI_write(int num, UINT8 ,UINT8);
++UINT8 SLIC_SPI_read(int num, UINT8);
++void SLIC_SPI_write_bit(char);
++void SLIC_SPI_ind_write(int num, UINT8, UINT16);
++UINT16 SLIC_SPI_ind_read(int num, UINT8);
++void SLIC_SPI_CS_enable(UINT8);
++unsigned int SLIC_SPI_read_bit(void);
++void SLIC_SPI_pre_st(void);
++UINT32 ssp_init(void);
++UINT16 SLIC_SPI_get_identifier(int num);
++int selfTest(int num);
++void exception (int num, enum exceptions e);
++int SLIC_init(int num);
++UINT8 version(int num);
++UINT8 chipType (int num);
++void SLIC_init_ind_reg_set(int num);
++UINT8 powerUp(int num);
++UINT8 powerLeakTest(int num);
++void SLIC_init_reg_set(int num);
++int calibrate(int num);
++void goActive(int num);
++void clearInterrupts(int num);
++void setState(int num, int);
++UINT8 loopStatus(int num);
++int verifyIndirectRegisters(int num);
++int verifyIndirectReg(int num, UINT8 , UINT16);
++void sendProSLICID(int num);
++void disableOscillators(int num);
++UINT8 checkSum(int num, char * string );
++void fskInitialization (int num);
++void fskByte(int num, UINT8 c);
++void waitForInterrupt (int num);
++//void findNumber(void);
++UINT8 dtmfAction(int num);
++UINT8 digit(int num);
++void interrupt_init(void);
++//void gemini_slic_isr (int );
++int groundShort(int num);
++void clearAlarmBits(int num);
++void stopRinging(int num);
++void activateRinging(int num);
++void initializeLoopDebounceReg(int num);
++void busyJapan(int num) ;
++void ringBackJapan(int num) ;
++void stateMachine(int num);
++
+Index: linux-2.6.23.16/include/asm-arm/arch-sl2312/hardware.h
+===================================================================
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.23.16/include/asm-arm/arch-sl2312/hardware.h     2008-03-14 12:48:02.872746442 +0200
+@@ -0,0 +1,47 @@
++/*
++ *  linux/include/asm-arm/arch-epxa10/hardware.h
++ *
++ *  This file contains the hardware definitions of the Integrator.
++ *
++ *  Copyright (C) 1999 ARM Limited.
++ *  Copyright (C) 2001 Altera Corporation
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++ */
++#ifndef __ASM_ARCH_HARDWARE_H
++#define __ASM_ARCH_HARDWARE_H
++
++#include <asm/arch/platform.h>
++
++#define pcibios_assign_all_busses()   1
++
++/*
++ * Where in virtual memory the IO devices (timers, system controllers
++ * and so on)
++ *
++ * macro to get at IO space when running virtually
++*/
++
++#define IO_ADDRESS(x)      (((x&0xfff00000)>>4)|(x & 0x000fffff)|0xF0000000)
++#define FLASH_VBASE         0xFE000000
++#define FLASH_SIZE 0x1000000// 8M
++#define FLASH_START         SL2312_FLASH_BASE
++#define FLASH_VADDR(x)      ((x & 0x00ffffff)|0xFE000000)       // flash virtual address
++
++#define PCIBIOS_MIN_IO                                        0x100           // 0x000-0x100 AHB reg and PCI config, data
++#define PCIBIOS_MIN_MEM                                       0
++
++#endif
++
+Index: linux-2.6.23.16/include/asm-arm/arch-sl2312/int_ctrl.h
+===================================================================
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.23.16/include/asm-arm/arch-sl2312/int_ctrl.h     2008-03-13 17:48:24.508798285 +0200
+@@ -0,0 +1,171 @@
++/*
++ *
++ *  This file contains the register definitions for the Excalibur
++ *  Timer TIMER00.
++ *
++ *  Copyright (C) 2001 Altera Corporation
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++ */
++
++#ifndef __INT_CTRL_H
++#define __INT_CTRL_H
++
++#define PCI_IRQ_OFFSET                          64    /* PCI start IRQ number */
++#define FIQ_OFFSET                32
++
++#define IRQ_SOURCE(base_addr)   (INT_CTRL_TYPE(base_addr  + 0x00))
++#define IRQ_MASK(base_addr)     (INT_CTRL_TYPE (base_addr  + 0x04 ))
++#define IRQ_CLEAR(base_addr)    (INT_CTRL_TYPE (base_addr  + 0x08 ))
++#define IRQ_TMODE(base_addr)    (INT_CTRL_TYPE (base_addr  + 0x0C ))
++#define IRQ_TLEVEL(base_addr)    (INT_CTRL_TYPE (base_addr  + 0x10 ))
++#define IRQ_STATUS(base_addr)   (INT_CTRL_TYPE (base_addr  + 0x14 ))
++#define FIQ_SOURCE(base_addr)   (INT_CTRL_TYPE (base_addr  + 0x20 ))
++#define FIQ_MASK(base_addr)     (INT_CTRL_TYPE (base_addr  + 0x24 ))
++#define FIQ_CLEAR(base_addr)    (INT_CTRL_TYPE (base_addr  + 0x28 ))
++#define FIQ_TMODE(base_addr)    (INT_CTRL_TYPE (base_addr  + 0x2C ))
++#define FIQ_LEVEL(base_addr)    (INT_CTRL_TYPE (base_addr  + 0x30 ))
++#define FIQ_STATUS(base_addr)   (INT_CTRL_TYPE (base_addr  + 0x34 ))
++
++#ifdef CONFIG_SL3516_ASIC
++#define       IRQ_SERIRQ0_OFFSET                      30
++#define       IRQ_PCID_OFFSET                         29
++#define       IRQ_PCIC_OFFSET                         28
++#define       IRQ_PCIB_OFFSET                         27
++#define IRQ_PWR_OFFSET                                        26
++#define IRQ_CIR_OFFSET                                                25
++#define       IRQ_GPIO2_OFFSET                        24
++#define       IRQ_GPIO1_OFFSET                        23
++#define       IRQ_GPIO_OFFSET                         22
++#define       IRQ_SSP_OFFSET                          21
++#define IRQ_LPC_OFFSET                      20
++#define IRQ_LCD_OFFSET                      19
++#define       IRQ_UART_OFFSET                         18
++#define       IRQ_RTC_OFFSET                                  17
++#define       IRQ_TIMER3_OFFSET                       16
++#define       IRQ_TIMER2_OFFSET                       15
++#define       IRQ_TIMER1_OFFSET                       14
++#define IRQ_FLASH_OFFSET                                      12
++#define       IRQ_USB1_OFFSET                         11
++#define IRQ_USB0_OFFSET                                               10
++#define       IRQ_DMA_OFFSET                          9
++#define       IRQ_PCI_OFFSET                          8
++#define       IRQ_IPSEC_OFFSET                        7
++#define       IRQ_RAID_OFFSET                     6
++#define       IRQ_IDE1_OFFSET                         5
++#define       IRQ_IDE0_OFFSET                         4
++#define       IRQ_WATCHDOG_OFFSET                 3
++#define       IRQ_GMAC1_OFFSET                    2
++#define IRQ_GMAC0_OFFSET                                      1
++#define       IRQ_CPU0_IP_IRQ_OFFSET              0
++
++#define       IRQ_SERIRQ0_MASK                        (1<<30)
++#define IRQ_PCID_MASK                                 (1<<29)
++#define IRQ_PCIC_MASK                                 (1<<28)
++#define IRQ_PCIB_MASK                                 (1<<27)
++#define IRQ_PWR_MASK                                  (1<<26)
++#define IRQ_CIR_MASK                                          (1<<25)
++#define       IRQ_GPIO2_MASK                          (1<<24)
++#define       IRQ_GPIO1_MASK                          (1<<23)
++#define       IRQ_GPIO_MASK                       (1<<22)
++#define       IRQ_SSP_MASK                        (1<<21)
++#define IRQ_LPC_MASK                        (1<<20)
++#define IRQ_LCD_MASK                        (1<<19)
++#define       IRQ_UART_MASK                       (1<<18)
++#define       IRQ_RTC_MASK                                (1<<17)
++#define       IRQ_TIMER3_MASK                     (1<<16)
++#define       IRQ_TIMER2_MASK                     (1<<15)
++#define       IRQ_TIMER1_MASK                     (1<<14)
++#define IRQ_FLASH_MASK                                            (1<<12)
++#define       IRQ_USB1_MASK                       (1<<11)
++#define IRQ_USB0_MASK                                     (1<<10)
++#define       IRQ_DMA_MASK                        (1<< 9)
++#define       IRQ_PCI_MASK                        (1<< 8)
++#define       IRQ_IPSEC_MASK                              (1<< 7)
++#define       IRQ_RAID_MASK                       (1<< 6)
++#define       IRQ_IDE1_MASK                       (1<< 5)
++#define       IRQ_IDE0_MASK                       (1<< 4)
++#define       IRQ_WATCHDOG_MASK                   (1<< 3)
++#define       IRQ_GMAC1_MASK                      (1<< 2)
++#define IRQ_GMAC0_MASK                                            (1<< 1)
++#define       IRQ_CPU0_IP_IRQ_MASK                (1<< 0)
++#else
++#define       IRQ_SERIRQ0_OFFSET                      30
++#define       IRQ_PCID_OFFSET                         29
++#define       IRQ_PCIC_OFFSET                         28
++#define       IRQ_PCIB_OFFSET                         27
++#define IRQ_PWR_OFFSET                                        26
++#define IRQ_CIR_OFFSET                                                25
++#define       IRQ_GPIO2_OFFSET                        24
++#define       IRQ_GPIO1_OFFSET                        23
++#define       IRQ_GPIO_OFFSET                         22
++#define       IRQ_SSP_OFFSET                          21
++#define IRQ_LPC_OFFSET                      20
++#define IRQ_LCD_OFFSET                      19
++#define       IRQ_UART_OFFSET                         18
++#define       IRQ_RTC_OFFSET                                  17
++#define       IRQ_TIMER3_OFFSET                       16
++#define       IRQ_TIMER2_OFFSET                       15
++#define       IRQ_TIMER1_OFFSET                       14
++#define IRQ_FLASH_OFFSET                                      12
++#define       IRQ_USB1_OFFSET                         11
++#define IRQ_USB0_OFFSET                                               10
++#define       IRQ_DMA_OFFSET                          9
++#define       IRQ_PCI_OFFSET                          8
++#define       IRQ_IPSEC_OFFSET                        7
++#define       IRQ_RAID_OFFSET                     6
++#define       IRQ_IDE1_OFFSET                         5
++#define       IRQ_IDE0_OFFSET                         4
++#define       IRQ_WATCHDOG_OFFSET                 3
++#define       IRQ_GMAC1_OFFSET                    2
++#define IRQ_GMAC0_OFFSET                                      1
++#define       IRQ_CPU0_IP_IRQ_OFFSET              0
++
++#define       IRQ_SERIRQ0_MASK                        (1<<30)
++#define IRQ_PCID_MASK                                 (1<<29)
++#define IRQ_PCIC_MASK                                 (1<<28)
++#define IRQ_PCIB_MASK                                 (1<<27)
++#define IRQ_PWR_MASK                                  (1<<26)
++#define IRQ_CIR_MASK                                          (1<<25)
++#define       IRQ_GPIO2_MASK                          (1<<24)
++#define       IRQ_GPIO1_MASK                          (1<<23)
++#define       IRQ_GPIO_MASK                       (1<<22)
++#define       IRQ_SSP_MASK                        (1<<21)
++#define IRQ_LPC_MASK                        (1<<20)
++#define IRQ_LCD_MASK                        (1<<19)
++#define       IRQ_UART_MASK                       (1<<18)
++#define       IRQ_RTC_MASK                                (1<<17)
++#define       IRQ_TIMER3_MASK                     (1<<16)
++#define       IRQ_TIMER2_MASK                     (1<<15)
++#define       IRQ_TIMER1_MASK                     (1<<14)
++#define IRQ_FLASH_MASK                                            (1<<12)
++#define       IRQ_USB1_MASK                       (1<<11)
++#define IRQ_USB0_MASK                                     (1<<10)
++#define       IRQ_DMA_MASK                        (1<< 9)
++#define       IRQ_PCI_MASK                        (1<< 8)
++#define       IRQ_IPSEC_MASK                              (1<< 7)
++#define       IRQ_RAID_MASK                       (1<< 6)
++#define       IRQ_IDE1_MASK                       (1<< 5)
++#define       IRQ_IDE0_MASK                       (1<< 4)
++#define       IRQ_WATCHDOG_MASK                   (1<< 3)
++#define       IRQ_GMAC1_MASK                      (1<< 2)
++#define IRQ_GMAC0_MASK                                            (1<< 1)
++#define       IRQ_CPU0_IP_IRQ_MASK                (1<< 0)
++#endif
++
++
++#endif /* __INT_CTRL_H */
++
++
+Index: linux-2.6.23.16/include/asm-arm/arch-sl2312/io.h
+===================================================================
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.23.16/include/asm-arm/arch-sl2312/io.h   2008-03-13 17:48:24.508798285 +0200
+@@ -0,0 +1,50 @@
++/*
++ *  linux/include/asm-arm/arch-epxa10db/io.h
++ *
++ *  Copyright (C) 1999 ARM Limited
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++ */
++#ifndef __ASM_ARM_ARCH_IO_H
++#define __ASM_ARM_ARCH_IO_H
++
++#define IO_SPACE_LIMIT 0xffffffff
++
++
++/*
++ * Generic virtual read/write
++ */
++/*
++#define __arch_getw(a)                (*(volatile unsigned short *)(a))
++#define __arch_putw(v,a)      (*(volatile unsigned short *)(a) = (v))
++*/
++/*#define outsw   __arch_writesw
++#define outsl   __arch_writesl
++#define outsb   __arch_writesb
++#define insb    __arch_readsb
++#define insw    __arch_readsw
++#define insl    __arch_readsl*/
++
++#define __io(a)                       (a)
++#define __mem_pci(a)            (a)
++/*
++#define __arch_getw(a)                        (*(volatile unsigned short  *)(a))
++#define __arch_putw(v,a)              (*(volatile unsigned short *)(a) = (v))
++*/
++#define iomem_valid_addr(off,size) (1)
++#define iomem_to_phys(off) (off)
++
++
++#endif
+Index: linux-2.6.23.16/include/asm-arm/arch-sl2312/ipi.h
+===================================================================
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.23.16/include/asm-arm/arch-sl2312/ipi.h  2008-03-13 17:48:24.508798285 +0200
+@@ -0,0 +1,189 @@
++/*
++ *  linux/include/asm-arm/arch-sl2312/system.h
++ *
++ *  Copyright (C) 1999 ARM Limited
++ *  Copyright (C) 2000 Deep Blue Solutions Ltd
++ *  Copyright (C) 2001 Altera Corporation
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++ */
++#ifndef __ASM_ARCH_IPI_H
++#define __ASM_ARCH_IPI_H
++#include <asm/io.h>
++
++//#define spin_lock(x)        spin_lock_dt(x)
++//#define spin_unlock(x)      spin_unlock_dt(x)
++
++#define SWAP_OFFSET                                                   0x400000
++#define SWAP_SIZE                                                     0x400000
++
++#define SHARE_MEM_ADDR                                                0x2000000
++#define SHARE_MEM_SIZE                                                1024*1024
++
++
++//--> Add by jason for IPI testing
++// memory layout for maste & slave bin
++#define MASTERTEXT      0x8000
++#define SLAVETEXT             0x108000
++#define SHARESIZE             0x4000
++#define SHAREADDR             SHARE_MEM_ADDR // starting 8M
++
++// CPU1 reset release
++#define GLOBAL_BASE           IO_ADDRESS(0x40000000)
++#define GLOBAL_SOFTRESET      (GLOBAL_BASE + 0x0C)
++#define CPU1_RESET_BIT_MASK     0x40000000
++
++// IPI , need to redefine the folliwing,  bug
++#define CPU0_STATUS                   (GLOBAL_BASE + 0x0038)
++#define CPU1_STATUS                   (GLOBAL_BASE + 0x003C)
++#define CPU_IPI_BIT_MASK    0x80000000
++
++/* Your basic SMP spinlocks, allowing only a single CPU anywhere
++*/
++typedef struct {
++       volatile unsigned int lock;
++} spinlock_dt;
++
++
++#define         MASTER_BIT      0x01
++#define         SLAVE_BIT       0x02
++#define         HEART_BIT       0x04
++#define         IPI0_IRQ_BIT    0x08
++#define         IPI0_FIQ_BIT    0x10
++#define         IPI1_IRQ_BIT    0x20
++#define         IPI1_FIQ_BIT    0x40
++
++#define IRQ     0
++#define FIQ     1
++#define DONE    0xff
++
++#define         CPU0            0x0
++#define         CPU1            0x1
++
++#define         MAXCHAR         128*1024
++typedef struct  {
++       int flag;
++       int uart_flag;
++       int cnt;
++       spinlock_dt lk;
++       char message[MAXCHAR];
++}s_mailbox;
++
++// JScale proj definition
++typedef struct {
++      u16             type;                           // message Type
++      u16             length;                         // message length, including message header
++} IPC_MSG_HDR_T;
++
++typedef struct{
++      IPC_MSG_HDR_T   hdr;
++      u32                             input_location;
++      u32                             input_size;
++      u32                             output_location;
++      u16                     ScaledImageWidth;
++      u16                     ScaledImageHeight;
++      u8                      ScaledImageQuality;
++      u8                      MaintainResultionRatio;
++      u8                      TwoStepScaling;
++      u8                      InputFormat;
++      u8                              verbose;
++      u8                              reserved[3];
++} JSCALE_REQ_T;
++
++typedef struct{
++      IPC_MSG_HDR_T   hdr;
++      u32                             status;
++      u32                             code;
++      u32                             output_size;
++} JSCALE_RSP_T;
++
++#define IPC_JSCALE_REQ_MSG                    0       // JScale request from CPU-0 to CPU-1
++#define IPC_JSCALE_RSP_MSG                    1       // JScale response from CPU-1 to CPU-0
++
++enum {
++      JSCALE_STATUS_OK = 0,
++      JSCALE_UNKNOWN_MSG_TYPE,
++      JSCALE_FAILED_FILE_SIZE,
++      JSCALE_FAILED_MALLOC,
++      JSCALE_FAILED_FORMAT,
++      JSCALE_DECODE_ERROR,
++      JSCALE_BUSY,
++};
++// <-- JScale
++
++#define GEMINI_IPI_IOCTL_BASE 'Z'
++#define GEMINI_IPI_JSCALE_REQ         _IOW (GEMINI_IPI_IOCTL_BASE,0,JSCALE_REQ_T)
++#define GEMINI_IPI_JSCALE_STAT                _IOR (GEMINI_IPI_IOCTL_BASE,1,JSCALE_RSP_T)
++
++
++/*
++* Simple spin lock operations.
++*
++*/
++
++#define spin_is_locked_dt(x)((x)->lock != 0)
++
++static inline int test_and_set_dt(spinlock_dt *lock)
++{
++unsigned long tmp;
++__asm__ __volatile__(
++"swp     %0, %2, [%1]\n"
++: "=&r" (tmp)
++: "r" (&lock->lock), "r" (1)
++: "cc", "memory");
++
++return tmp;
++}
++
++static inline void spin_lock_dt(spinlock_dt *lock)
++{
++
++unsigned long tmp;
++__asm__ __volatile__(
++"1:     ldr   %0, [%1]\n"
++"teq     %0, #0\n"
++"swpeq   %0, %2, [%1]\n"
++"       teqeq   %0, #0\n"
++"       bne     1b"
++       : "=&r" (tmp)
++       : "r" (&lock->lock), "r" (1)
++       : "cc", "memory");
++}
++
++static inline void spin_unlock_dt(spinlock_dt *lock)
++{
++       __asm__ __volatile__(
++"       str     %1, [%0]"
++       :
++       : "r" (&lock->lock), "r" (0)
++       : "cc", "memory");
++}
++
++static inline int getcpuid(void)
++{
++       int cpuid;
++
++      __asm__(
++"mrc p8, 0, r0, c0, c0, 0\n"
++"mov %0, r0"
++       :"=r"(cpuid)
++       :
++       :"r0");
++       return (cpuid & 0x07);
++}
++
++
++
++#endif
+Index: linux-2.6.23.16/include/asm-arm/arch-sl2312/irq.h
+===================================================================
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.23.16/include/asm-arm/arch-sl2312/irq.h  2008-03-13 17:48:24.508798285 +0200
+@@ -0,0 +1,23 @@
++/*
++ *  linux/include/asm-arm/arch-sl2312/irq.h
++ *
++ *  Copyright (C) 1999 ARM Limited
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++ */
++
++ // Since we have PCI interrupt which the interrupt line is pseudo
++ // we need do some fixup
++int fixup_irq(int irq);
+Index: linux-2.6.23.16/include/asm-arm/arch-sl2312/irqs.h
+===================================================================
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.23.16/include/asm-arm/arch-sl2312/irqs.h 2008-03-13 17:48:24.508798285 +0200
+@@ -0,0 +1,102 @@
++/*
++ *  linux/include/asm-arm/arch-camelot/irqs.h
++ *
++ *  Copyright (C) 2001 Altera Corporation
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++ */
++
++/* Use the Excalibur chip definitions */
++#define INT_CTRL_TYPE
++#include "asm/arch/int_ctrl.h"
++
++#ifdef CONFIG_SL3516_ASIC
++#define       IRQ_SERIRQ_MAX                                  31
++#define       IRQ_SERIRQ1                                             31
++#define       IRQ_SERIRQ0                     30
++#define       IRQ_PCID                                29
++#define       IRQ_PCIC                        28
++#define       IRQ_PCIB                                27
++#define IRQ_PWR                                                       26
++#define IRQ_CIR                                                       25
++#define       IRQ_GPIO2                       24
++#define       IRQ_GPIO1                       23
++#define       IRQ_GPIO                                22
++#define       IRQ_SSP                         21
++#define IRQ_LPC                         20
++#define IRQ_LCD                         19
++#define       IRQ_UART                                18
++#define       IRQ_RTC                                 17
++#define       IRQ_TIMER3                      16
++#define       IRQ_TIMER2                      15
++#define       IRQ_TIMER1                      14
++#define IRQ_FLASH                                             12
++#define       IRQ_USB1                        11
++#define IRQ_USB0                                              10
++#define       IRQ_DMA                         9
++#define       IRQ_PCI                                 8
++#define       IRQ_IPSEC                               7
++#define       IRQ_RAID                        6
++#define       IRQ_IDE1                        5
++#define       IRQ_IDE0                                4
++#define       IRQ_WATCHDOG                    3
++#define       IRQ_GMAC1                       2
++#define IRQ_GMAC0                                             1
++#define       IRQ_CPU0_IP_IRQ                 0
++#else
++#define       IRQ_SERIRQ_MAX                                  31
++#define       IRQ_SERIRQ1                                             31
++#define       IRQ_SERIRQ0                     30
++#define       IRQ_PCID                                29
++#define       IRQ_PCIC                        28
++#define       IRQ_PCIB                                27
++#define IRQ_PWR                                                       26
++#define IRQ_CIR                                                       25
++#define       IRQ_GPIO2                       24
++#define       IRQ_GPIO1                       23
++#define       IRQ_GPIO                                22
++#define       IRQ_SSP                         21
++#define IRQ_LPC                         20
++#define IRQ_LCD                         19
++#define       IRQ_UART                                18
++#define       IRQ_RTC                                 17
++#define       IRQ_TIMER3                      16
++#define       IRQ_TIMER2                      15
++#define       IRQ_TIMER1                      14
++#define IRQ_FLASH                                             12
++#define       IRQ_USB1                        11
++#define IRQ_USB0                                              10
++#define       IRQ_DMA                         9
++#define       IRQ_PCI                                 8
++#define       IRQ_IPSEC                               7
++#define       IRQ_RAID                        6
++#define       IRQ_IDE1                        5
++#define       IRQ_IDE0                                4
++#define       IRQ_WATCHDOG                    3
++#define       IRQ_GMAC1                       2
++#define IRQ_GMAC0                                             1
++#endif
++
++#define ARCH_TIMER_IRQ                               IRQ_TIMER2   /* for MV 4.0 */
++
++#define IRQ_PCI_INTA                                 PCI_IRQ_OFFSET + 0
++#define IRQ_PCI_INTB                                 PCI_IRQ_OFFSET + 1
++#define IRQ_PCI_INTC                                 PCI_IRQ_OFFSET + 2
++#define IRQ_PCI_INTD                                 PCI_IRQ_OFFSET + 3
++
++#define NR_IRQS                           (IRQ_PCI_INTD + 4)
++
++
++
+Index: linux-2.6.23.16/include/asm-arm/arch-sl2312/it8712.h
+===================================================================
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.23.16/include/asm-arm/arch-sl2312/it8712.h       2008-03-13 17:48:24.508798285 +0200
+@@ -0,0 +1,24 @@
++
++#ifndef __IT8712_H__
++#define __IT8712_H__
++
++#include "asm/arch/sl2312.h"
++
++#define IT8712_IO_BASE                        SL2312_LPC_IO_BASE
++// Device LDN
++#define LDN_SERIAL1                           0x01
++#define LDN_SERIAL2                           0x02
++#define LDN_PARALLEL                  0x03
++#define LDN_KEYBOARD                  0x05
++#define LDN_MOUSE                             0x06
++#define LDN_GPIO                              0x07
++
++#define IT8712_UART1_PORT             0x3F8
++#define IT8712_UART2_PORT             0x2F8
++
++#define IT8712_GPIO_BASE              0x800   // 0x800-0x804 for GPIO set1-set5
++
++void LPCSetConfig(char LdnNumber, char Index, char data);
++char LPCGetConfig(char LdnNumber, char Index);
++
++#endif
+Index: linux-2.6.23.16/include/asm-arm/arch-sl2312/memory.h
+===================================================================
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.23.16/include/asm-arm/arch-sl2312/memory.h       2008-03-13 17:48:24.508798285 +0200
+@@ -0,0 +1,38 @@
++/*
++ *  linux/include/asm-arm/arch-sl2312/memory.h
++ *
++ *  Copyright (C) 2001 Altera Corporation
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++ */
++#ifndef __ASM_ARCH_MMU_H
++#define __ASM_ARCH_MMU_H
++
++/*
++ * Physical DRAM offset.
++ */
++#define PHYS_OFFSET   UL(0x00000000)
++
++/*
++ * Virtual view <-> DMA view memory address translations
++ * virt_to_bus: Used to translate the virtual address to an
++ *              address suitable to be passed to set_dma_addr
++ * bus_to_virt: Used to convert an address for DMA operations
++ *              to an address that the kernel can use.
++ */
++#define __virt_to_bus(x)      (x - PAGE_OFFSET + /*SDRAM_BASE*/0)
++#define __bus_to_virt(x)      (x - /*SDRAM_BASE*/0 + PAGE_OFFSET)
++
++#endif
+Index: linux-2.6.23.16/include/asm-arm/arch-sl2312/param.h
+===================================================================
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.23.16/include/asm-arm/arch-sl2312/param.h        2008-03-13 17:48:24.508798285 +0200
+@@ -0,0 +1,20 @@
++/*
++ *  linux/include/asm-arm/arch-epxa10db/param.h
++ *
++ *  Copyright (C) 1999 ARM Limited
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++ */
++
+Index: linux-2.6.23.16/include/asm-arm/arch-sl2312/pci.h
+===================================================================
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.23.16/include/asm-arm/arch-sl2312/pci.h  2008-03-13 17:48:24.508798285 +0200
+@@ -0,0 +1,18 @@
++
++#ifndef __SL2312_PCI_H__
++#define __SL2312_PCI_H__
++
++#define SL2312_PCI_PMC                                0x40
++#define SL2312_PCI_PMCSR                      0x44
++#define SL2312_PCI_CTRL1                      0x48
++#define SL2312_PCI_CTRL2                      0x4c
++#define SL2312_PCI_MEM1_BASE_SIZE     0x50
++#define SL2312_PCI_MEM2_BASE_SIZE     0x54
++#define SL2312_PCI_MEM3_BASE_SIZE     0x58
++
++
++void sl2312_pci_mask_irq(unsigned int irq);
++void sl2312_pci_unmask_irq(unsigned int irq);
++int sl2312_pci_get_int_src(void);
++
++#endif
+Index: linux-2.6.23.16/include/asm-arm/arch-sl2312/platform.h
+===================================================================
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.23.16/include/asm-arm/arch-sl2312/platform.h     2008-03-13 17:48:24.508798285 +0200
+@@ -0,0 +1,7 @@
++#ifndef PLATFORM_H
++#define PLATFORM_H
++#include "sl2312.h"
++
++#define MAXIRQNUM 68
++#endif
++
+Index: linux-2.6.23.16/include/asm-arm/arch-sl2312/preempt.h
+===================================================================
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.23.16/include/asm-arm/arch-sl2312/preempt.h      2008-03-13 17:48:24.508798285 +0200
+@@ -0,0 +1,63 @@
++/*
++ * include/asm-arm/arch-sl2312/preempt.h
++ *
++ * Timing support for preempt-stats, kfi, ilatency patches
++ *
++ * Author: dsingleton <dsingleton@mvista.com>
++ *
++ * 2001-2004 (c) MontaVista Software, Inc. This file is licensed under
++ * the terms of the GNU General Public License version 2. This program
++ * is licensed "as is" without any warranty of any kind, whether express
++ * or implied.
++ */
++
++#ifndef _ASM_ARCH_PREEMT_H
++#define _ASM_ARCH_PREEMT_H
++
++#include <asm/arch/hardware.h>
++#include <asm/arch/sl2312.h>
++
++static inline unsigned long clock_diff(unsigned long start, unsigned long stop)
++{
++        return (start - stop);
++}
++
++static inline unsigned int readclock(void)
++{
++      unsigned int    x;
++
++      x = readl(IO_ADDRESS(SL2312_TIMER2_BASE));
++      return x;
++}
++
++static inline unsigned __ticks_per_usec(void)
++{
++#ifdef CONFIG_SL3516_ASIC
++      unsigned int ahb_clock_rate_base=130;  /* unit = MHz*/
++      unsigned int reg_v=0;
++      unsigned int ticks_usec;
++
++      reg_v = readl(IO_ADDRESS((SL2312_GLOBAL_BASE+4)));
++      reg_v >>=15;
++      ticks_usec = (ahb_clock_rate_base + (reg_v & 0x07)*10)>>2;
++
++#else
++      unsigned int ticks_usec=20;
++#endif
++
++    return ticks_usec;
++}
++
++/*
++ * timer 1 runs @ 6Mhz  6 ticks = 1 microsecond
++ * and is configed as a count down timer.
++ */
++#define TICKS_PER_USEC                    __ticks_per_usec()
++#define ARCH_PREDEFINES_TICKS_PER_USEC
++
++#define clock_to_usecs(x)         ((x) / TICKS_PER_USEC)
++
++#define INTERRUPTS_ENABLED(x)   (!(x & PSR_I_BIT))
++
++#endif
++
+Index: linux-2.6.23.16/include/asm-arm/arch-sl2312/sl2312.h
+===================================================================
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.23.16/include/asm-arm/arch-sl2312/sl2312.h       2008-03-13 17:48:24.508798285 +0200
+@@ -0,0 +1,254 @@
++#ifndef __sl2312_h
++#define __sl2312_h
++
++/****************************************************************************
++ * Copyright  Storlink Corp 2002-2003.  All rights reserved.                *
++ *--------------------------------------------------------------------------*
++ * Name:board.s                                                             *
++ * Description:  SL231x specfic define                                      *
++ * Author: Plus Chen                                                        *
++ * Version: 0.9 Create
++ ****************************************************************************/
++
++/*
++  CPE address map;
++
++               +====================================================
++    0x00000000 | FLASH
++    0x0FFFFFFF |
++               |====================================================
++    0x10000000 | SDRAM
++    0x1FFFFFFF |
++               |====================================================
++    0x20000000 | Global Registers        0x20000000-0x20FFFFFF
++               | EMAC and DMA            0x21000000-0x21FFFFFF
++               | UART Module             0x22000000-0x22FFFFFF
++               | Timer Module            0x23000000-0x23FFFFFF
++               | Interrupt Module        0x24000000-0x24FFFFFF
++               | RTC Module              0x25000000-0x25FFFFFF
++               | LPC Host Controller     0x26000000-0x26FFFFFF
++               | LPC Peripherial IO      0x27000000-0x27FFFFFF
++               | WatchDog Timer          0x28000000-0x28FFFFFF
++    0x2FFFFFFF | Reserved                0x29000000-0x29FFFFFF
++               |=====================================================
++    0x30000000 | PCI IO, Configuration Registers
++    0x3FFFFFFF |
++               |=====================================================
++    0x40000000 | PCI Memory
++    0x4FFFFFFF |
++               |=====================================================
++    0x50000000 | Ethernet MAC and DMA    0x50000000-0x50FFFFFF
++               | Security and DMA        0x51000000-0x51FFFFFF
++               | IDE Channel 0 Register  0x52000000-0x527FFFFF
++               | IDE Channel 1 Register  0x52800000-0x52FFFFFF
++               | USB Register            0x53000000-0x53FFFFFF
++               | Flash Controller        0x54000000-0x54FFFFFF
++               | DRAM Controller         0x55000000-0x55FFFFFF
++    0x5FFFFFFF | Reserved                0x56000000-0x5FFFFFFF
++               |=====================================================
++    0x60000000 | Reserved
++    0x6FFFFFFF |
++               |=====================================================
++    0x70000000 | FLASH shadow Memory
++    0x7FFFFFFF |
++               |=====================================================
++    0x80000000 | Big Endian of memory    0x00000000-0x7FFFFFFF
++    0xFFFFFFFF |
++               +=====================================================
++*/
++
++
++
++/*-------------------------------------------------------------------------------
++ Memory Map definitions
++-------------------------------------------------------------------------------- */
++#define TEST          1
++#if 0
++
++static inline int GETCPUID()
++{
++       int cpuid;
++      __asm__(
++"mrc p8, 0, r0, c0, c0, 0\n"
++"mov %0, r0"
++       :"=r"(cpuid)
++       :
++       :"r0");
++       return (cpuid & 0x07);
++}
++#endif
++#define SL2312_SRAM_BASE                0x70000000       //  SRAM base after remap
++#define SL2312_DRAM_BASE                0x00000000       //  DRAM base after remap
++#define SL2312_RAM_BASE                 0x10000000       //  RAM code base before remap
++#define SL2312_FLASH_BASE                 0x30000000
++#define SL2312_ROM_BASE                 0x30000000
++#define SL2312_GLOBAL_BASE              0x40000000
++#define SL2312_WAQTCHDOG_BASE           0x41000000
++#define SL2312_UART_BASE                0x42000000
++#define SL2312_TIMER_BASE               0x43000000
++#define SL2312_LCD_BASE                 0x44000000
++#define SL2312_RTC_BASE                 0x45000000
++#define SL2312_SATA_BASE                0x46000000
++#define SL2312_LPC_HOST_BASE            0x47000000
++#define SL2312_LPC_IO_BASE              0x47800000
++// #define SL2312_INTERRUPT_BASE           0x48000000
++#define SL2312_INTERRUPT0_BASE          0x48000000
++#define SL2312_INTERRUPT1_BASE          0x49000000
++//#define SL2312_INTERRUPT_BASE               ((getcpuid()==0)?SL2312_INTERRUPT0_BASE:SL2312_INTERRUPT1_BASE)
++#define SL2312_INTERRUPT_BASE             0x48000000
++#define SL2312_SSP_CTRL_BASE            0x4A000000
++#define SL2312_POWER_CTRL_BASE          0x4B000000
++#define SL2312_CIR_BASE                 0x4C000000
++#define SL2312_GPIO_BASE                0x4D000000
++#define SL2312_GPIO_BASE1               0x4E000000
++#define SL2312_GPIO_BASE2               0x4F000000
++#define SL2312_PCI_IO_BASE              0x50000000
++#define SL2312_PCI_MEM_BASE             0x58000000
++#ifdef  CONFIG_NET_SL351X
++#define SL2312_TOE_BASE                 0x60000000
++#define SL2312_GMAC0_BASE               0x6000A000
++#define SL2312_GMAC1_BASE               0x6000E000
++#else
++#define SL2312_GMAC0_BASE               0x60000000
++#define SL2312_GMAC1_BASE               0x61000000
++#endif
++#define SL2312_SECURITY_BASE            0x62000000
++#define SL2312_IDE0_BASE                0x63000000
++#define SL2312_IDE1_BASE                      0x63400000
++#define SL2312_RAID_BASE                0x64000000
++#define SL2312_FLASH_CTRL_BASE          0x65000000
++#define SL2312_DRAM_CTRL_BASE           0x66000000
++#define SL2312_GENERAL_DMA_BASE         0x67000000
++#define SL2312_USB_BASE                 0x68000000
++#define SL2312_USB0_BASE                0x68000000
++#define SL2312_USB1_BASE                0x69000000
++#define SL2312_FLASH_SHADOW             0x30000000
++#define SL2312_BIG_ENDIAN_BASE                        0x80000000
++
++#ifdef CONFIG_GEMINI_IPI
++#define CPU_1_MEM_BASE                        0x4000000                               // 64 MB
++#define CPU_1_DATA_OFFSET             0x4000000-0x300000              // Offset 61 MB
++#endif
++
++#define SL2312_TIMER1_BASE              SL2312_TIMER_BASE
++#define SL2312_TIMER2_BASE              (SL2312_TIMER_BASE + 0x10)
++#define SL2312_TIMER3_BASE              (SL2312_TIMER_BASE + 0x20)
++
++#define SL2312_PCI_DMA_MEM1_BASE              0x00000000
++#define SL2312_PCI_DMA_MEM2_BASE              0x00000000
++#define SL2312_PCI_DMA_MEM3_BASE              0x00000000
++#define SL2312_PCI_DMA_MEM1_SIZE              7
++#define SL2312_PCI_DMA_MEM2_SIZE              6
++#define SL2312_PCI_DMA_MEM3_SIZE              6
++
++/*-------------------------------------------------------------------------------
++ Global Module
++---------------------------------------------------------------------------------*/
++#define GLOBAL_ID                       0x00
++#define GLOBAL_CHIP_ID                  0x002311
++#define GLOBAL_CHIP_REV                 0xA0
++#define GLOBAL_STATUS                   0x04
++#define GLOBAL_CONTROL                  0x1C
++#define GLOBAL_REMAP_BIT                0x01
++#define GLOBAL_RESET_REG              0x0C
++#define GLOBAL_MISC_REG                                       0x30
++#define PFLASH_SHARE_BIT                              0x02
++
++#define GLOBAL_RESET          (1<<31)
++#define RESET_CPU1                    (1<<30)
++#define RESET_SATA1                   (1<<27)
++#define RESET_SATA0                   (1<<26)
++#define RESET_CIR                     (1<<25)
++#define RESET_EXT_DEV         (1<<24)
++#define RESET_WD                      (1<<23)
++#define RESET_GPIO2                   (1<<22)
++#define RESET_GPIO1                   (1<<21)
++#define RESET_GPIO0                   (1<<20)
++#define RESET_SSP                     (1<<19)
++#define RESET_UART                    (1<<18)
++#define RESET_TIMER                   (1<<17)
++#define RESET_RTC                     (1<<16)
++#define RESET_INT0                    (1<<15)
++#define RESET_INT1                    (1<<14)
++#define RESET_LCD                     (1<<13)
++#define RESET_LPC                     (1<<12)
++#define RESET_APB                     (1<<11)
++#define RESET_DMA                     (1<<10)
++#define RESET_USB1                    (1<<9 )
++#define RESET_USB0                    (1<<8 )
++#define RESET_PCI                     (1<<7 )
++#define RESET_GMAC1                   (1<<6 )
++#define RESET_GMAC0                   (1<<5 )
++#define RESET_IPSEC                   (1<<4 )
++#define RESET_RAID                    (1<<3 )
++#define RESET_IDE                     (1<<2 )
++#define RESET_FLASH                   (1<<1 )
++#define RESET_DRAM                    (1<<0 )
++
++
++
++
++
++
++
++
++/*-------------------------------------------------------------------------------
++ DRAM Module
++---------------------------------------------------------------------------------*/
++#define DRAM_SIZE_32M                   0x2000000
++#define DRAM_SIZE_64M                   0x4000000
++#define DRAM_SIZE_128M                  0x8000000
++
++#define DRAM_SIZE                       DRAM_SIZE_128M
++
++#define DRAM_SDRMR                      0x00
++#define SDRMR_DISABLE_DLL               0x80010000
++
++/*------------------------------------------------------------------------------
++ Share Pin Flag
++--------------------------------------------------------------------------------*/
++#ifdef CONFIG_SL2312_SHARE_PIN
++#define FLASH_SHARE_BIT                    0
++#define UART_SHARE_BIT                     1
++#define EMAC_SHARE_BIT                     2
++#define IDE_RW_SHARE_BIT                   3
++#define IDE_CMD_SHARE_BIT                  4
++#endif
++/*-------------------------------------------------------------------------------
++ System Clock
++---------------------------------------------------------------------------------*/
++
++#ifndef SYS_CLK
++#ifdef CONFIG_SL3516_ASIC
++#define SYS_CLK                         150000000
++#else
++#define SYS_CLK                       20000000
++#endif
++#endif
++
++#define AHB_CLK                       SYS_CLK
++#define MAX_TIMER                     3
++#ifndef APB_CLK
++#ifdef CONFIG_SL3516_ASIC
++#define APB_CLK                       (SYS_CLK / 6)
++#else
++#define APB_CLK                               SYS_CLK
++#endif
++#endif
++
++#ifdef CONFIG_SL3516_ASIC
++#define UART_CLK                        48000000      // 30000000 for GeminiA chip, else 48000000
++#else
++#define UART_CLK                      48000000
++#endif
++
++#define SL2312_BAUD_115200              (UART_CLK / 1843200)
++#define SL2312_BAUD_57600               (UART_CLK / 921600)
++#define SL2312_BAUD_38400                     (UART_CLK / 614400)
++#define SL2312_BAUD_19200               (UART_CLK / 307200)
++#define SL2312_BAUD_14400               (UART_CLK / 230400)
++#define SL2312_BAUD_9600                (UART_CLK / 153600)
++
++#endif
++
++
+Index: linux-2.6.23.16/include/asm-arm/arch-sl2312/sl2312_ipsec.h
+===================================================================
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.23.16/include/asm-arm/arch-sl2312/sl2312_ipsec.h 2008-03-13 17:48:24.508798285 +0200
+@@ -0,0 +1,684 @@
++#ifndef _IPSEC_DIAG_H
++#define _IPSEC_DIAG_H
++
++#include <linux/scatterlist.h>
++
++#define BIG_ENDIAN    0
++
++#define IPSEC_TEST    0
++#define ZERO_COPY     1
++
++#define UINT unsigned int
++#define BYTE unsigned char
++
++/* define cipher algorithm */
++enum CIPHER {
++      DES_ECB_E       =20,
++      TDES_ECB_E      =21,
++      AES_ECB_E       =22,
++      DES_CBC_E       =24,
++      TDES_CBC_E      =25,
++      AES_CBC_E       =26,
++
++      DES_ECB_D       =27,
++      TDES_ECB_D      =28,
++      AES_ECB_D       =29,
++      DES_CBC_D       =31,
++      TDES_CBC_D      =32,
++      AES_CBC_D       =33,
++      A_SHA1      =12,
++      A_HMAC_SHA1 =13,
++      A_MD5       =14,
++      A_HMAC_MD5  =15,
++};
++
++// opMode
++#define CIPHER_ENC    0x1
++#define CIPHER_DEC    0x3
++#define AUTH          0x4
++#define ENC_AUTH      0x5
++#define AUTH_DEC      0x7
++
++// cipherAlgorithm
++#define CBC_DES       0x4
++#define CBC_3DES      0x5
++#define CBC_AES       0x6
++#define ECB_DES       0x0
++#define ECB_3DES      0x1
++#define ECB_AES       0x2
++
++// authAlgorithm
++#define SHA1         0
++#define MD5          1
++#define HMAC_SHA1    2
++#define HMAC_MD5     3
++#define FCS          4
++
++//cipher mode
++#define ECB          0
++#define CBC          1
++
++// authMode
++#define AUTH_APPEND  0
++#define AUTH_CHKVAL  1
++
++/******************************************************/
++/*          the offset of IPSEC DMA register          */
++/******************************************************/
++enum IPSEC_DMA_REGISTER {
++      IPSEC_DMA_DEVICE_ID             = 0xff00,
++      IPSEC_DMA_STATUS                = 0xff04,
++      IPSEC_TXDMA_CTRL                = 0xff08,
++      IPSEC_TXDMA_FIRST_DESC  = 0xff0c,
++      IPSEC_TXDMA_CURR_DESC   = 0xff10,
++      IPSEC_RXDMA_CTRL                = 0xff14,
++      IPSEC_RXDMA_FIRST_DESC  = 0xff18,
++      IPSEC_RXDMA_CURR_DESC   = 0xff1c,
++      IPSEC_TXDMA_BUF_ADDR    = 0xff28,
++      IPSEC_RXDMA_BUF_ADDR    = 0xff38,
++      IPSEC_RXDMA_BUF_SIZE            = 0xff30,
++};
++
++#define IPSEC_STATUS_REG    0x00a8
++#define IPSEC_RAND_NUM_REG  0x00ac
++
++/******************************************************/
++/* the field definition of IPSEC DMA Module Register  */
++/******************************************************/
++typedef union
++{
++      unsigned int bits32;
++      struct bit2_ff00
++      {
++#if (BIG_ENDIAN==1)
++              unsigned int p_wclk             :  4;   /* DMA_APB write clock period */
++              unsigned int p_rclk             :  4;   /* DMA_APB read clock period */
++              unsigned int                            :  8;
++              unsigned int device_id          : 12;
++              unsigned int revision_id        :  4;
++#else
++              unsigned int revision_id        :  4;
++              unsigned int device_id          : 12;
++              unsigned int                            :  8;
++              unsigned int p_rclk             :  4;   /* DMA_APB read clock period */
++              unsigned int p_wclk             :  4;   /* DMA_APB write clock period */
++#endif
++      } bits;
++} IPSEC_DMA_DEVICE_ID_T;
++
++typedef union
++{
++      unsigned int bits32;
++      struct bit2_ff04
++      {
++#if (BIG_ENDIAN==1)
++              unsigned int ts_finish          :  1;   /* finished tx interrupt */
++              unsigned int ts_derr            :  1;   /* AHB Bus Error while tx */
++              unsigned int ts_perr            :  1;   /* Tx Descriptor protocol error */
++              unsigned int ts_eodi            :  1;   /* TxDMA end of descriptor interrupt */
++              unsigned int ts_eofi            :  1;   /* TxDMA end of frame interrupt */
++              unsigned int rs_finish          :  1;   /* finished rx interrupt */
++              unsigned int rs_derr            :  1;   /* AHB Bus Error while rx */
++              unsigned int rs_perr            :  1;   /* Rx Descriptor protocol error */
++              unsigned int rs_eodi            :  1;   /* RxDMA end of descriptor interrupt */
++              unsigned int rs_eofi            :  1;   /* RxDMA end of frame interrupt */
++        unsigned int intr           :  8;   /* Peripheral interrupt */
++              unsigned int dma_reset          :  1;   /* write 1 to this bit will cause DMA HClk domain soft reset */
++              unsigned int peri_reset         :  1;   /* write 1 to this bit will cause DMA PClk domain soft reset */
++              unsigned int                            :  3;
++              unsigned int loop_back          :  1;   /* loopback TxDMA to RxDMA */
++        unsigned int intr_enable    :  8;   /* Peripheral Interrupt Enable */
++#else
++        unsigned int intr_enable    :  8;   /* Peripheral Interrupt Enable */
++              unsigned int loop_back          :  1;   /* loopback TxDMA to RxDMA */
++              unsigned int                            :  3;
++              unsigned int peri_reset         :  1;   /* write 1 to this bit will cause DMA PClk domain soft reset */
++              unsigned int dma_reset          :  1;   /* write 1 to this bit will cause DMA HClk domain soft reset */
++        unsigned int intr           :  8;   /* Peripheral interrupt */
++              unsigned int rs_eofi            :  1;   /* RxDMA end of frame interrupt */
++              unsigned int rs_eodi            :  1;   /* RxDMA end of descriptor interrupt */
++              unsigned int rs_perr            :  1;   /* Rx Descriptor protocol error */
++              unsigned int rs_derr            :  1;   /* AHB Bus Error while rx */
++              unsigned int rs_finish          :  1;   /* finished rx interrupt */
++              unsigned int ts_eofi            :  1;   /* TxDMA end of frame interrupt */
++              unsigned int ts_eodi            :  1;   /* TxDMA end of descriptor interrupt */
++              unsigned int ts_perr            :  1;   /* Tx Descriptor protocol error */
++              unsigned int ts_derr            :  1;   /* AHB Bus Error while tx */
++              unsigned int ts_finish          :  1;   /* finished tx interrupt */
++#endif
++      } bits;
++} IPSEC_DMA_STATUS_T;
++
++typedef union
++{
++      unsigned int bits32;
++      struct bit2_ff08
++      {
++#if (BIG_ENDIAN==1)
++              unsigned int td_start           :  1;   /* Start DMA transfer */
++              unsigned int td_continue        :  1;   /* Continue DMA operation */
++              unsigned int td_chain_mode      :  1;   /* Descriptor Chain Mode;1-Descriptor Chain mode, 0-Direct DMA mode*/
++              unsigned int                            :  1;
++              unsigned int td_prot            :  4;   /* TxDMA protection control */
++              unsigned int td_burst_size  :  2;       /* TxDMA max burst size for every AHB request */
++              unsigned int td_bus                 :  2;       /* peripheral bus width;0 - 8 bits;1 - 16 bits */
++              unsigned int td_endian          :  1;   /* AHB Endian. 0-little endian; 1-big endian */
++              unsigned int td_finish_en   :  1;       /* DMA Finish Event Interrupt Enable;1-enable;0-mask */
++              unsigned int td_fail_en         :  1;   /* DMA Fail Interrupt Enable;1-enable;0-mask */
++              unsigned int td_perr_en         :  1;   /* Protocol Failure Interrupt Enable;1-enable;0-mask */
++              unsigned int td_eod_en          :  1;   /* End of Descriptor interrupt Enable;1-enable;0-mask */
++              unsigned int td_eof_en      :  1;   /* End of frame interrupt Enable;1-enable;0-mask */
++              unsigned int                            : 14;
++#else
++              unsigned int                            : 14;
++              unsigned int td_eof_en      :  1;   /* End of frame interrupt Enable;1-enable;0-mask */
++              unsigned int td_eod_en          :  1;   /* End of Descriptor interrupt Enable;1-enable;0-mask */
++              unsigned int td_perr_en         :  1;   /* Protocol Failure Interrupt Enable;1-enable;0-mask */
++              unsigned int td_fail_en         :  1;   /* DMA Fail Interrupt Enable;1-enable;0-mask */
++              unsigned int td_finish_en   :  1;       /* DMA Finish Event Interrupt Enable;1-enable;0-mask */
++              unsigned int td_endian          :  1;   /* AHB Endian. 0-little endian; 1-big endian */
++              unsigned int td_bus                 :  2;       /* peripheral bus width;0 - 8 bits;1 - 16 bits */
++              unsigned int td_burst_size  :  2;       /* TxDMA max burst size for every AHB request */
++              unsigned int td_prot            :  4;   /* TxDMA protection control */
++              unsigned int                            :  1;
++              unsigned int td_chain_mode      :  1;   /* Descriptor Chain Mode;1-Descriptor Chain mode, 0-Direct DMA mode*/
++              unsigned int td_continue        :  1;   /* Continue DMA operation */
++              unsigned int td_start           :  1;   /* Start DMA transfer */
++#endif
++      } bits;
++} IPSEC_TXDMA_CTRL_T;
++
++typedef union
++{
++      unsigned int bits32;
++      struct bit2_ff0c
++      {
++#if (BIG_ENDIAN==1)
++              unsigned int td_first_des_ptr   : 28;/* first descriptor address */
++              unsigned int td_busy                    :  1;/* 1-TxDMA busy; 0-TxDMA idle */
++              unsigned int                                    :  3;
++#else
++              unsigned int                                    :  3;
++              unsigned int td_busy                    :  1;/* 1-TxDMA busy; 0-TxDMA idle */
++              unsigned int td_first_des_ptr   : 28;/* first descriptor address */
++#endif
++      } bits;
++} IPSEC_TXDMA_FIRST_DESC_T;
++
++typedef union
++{
++      unsigned int bits32;
++      struct bit2_ff10
++      {
++#if (BIG_ENDIAN==1)
++              unsigned int ndar                       : 28;   /* next descriptor address */
++              unsigned int eofie                      :  1;   /* end of frame interrupt enable */
++              unsigned int dec                        :  1;   /* AHB bus address increment(0)/decrement(1) */
++              unsigned int sof_eof            :  2;
++#else
++              unsigned int sof_eof            :  2;
++              unsigned int dec                        :  1;   /* AHB bus address increment(0)/decrement(1) */
++              unsigned int eofie                      :  1;   /* end of frame interrupt enable */
++              unsigned int ndar                       : 28;   /* next descriptor address */
++#endif
++      } bits;
++} IPSEC_TXDMA_CURR_DESC_T;
++
++
++typedef union
++{
++      unsigned int bits32;
++      struct bit2_ff14
++      {
++#if (BIG_ENDIAN==1)
++              unsigned int rd_start           :  1;   /* Start DMA transfer */
++              unsigned int rd_continue        :  1;   /* Continue DMA operation */
++              unsigned int rd_chain_mode      :  1;   /* Descriptor Chain Mode;1-Descriptor Chain mode, 0-Direct DMA mode*/
++              unsigned int                            :  1;
++              unsigned int rd_prot            :  4;   /* DMA protection control */
++              unsigned int rd_burst_size  :  2;       /* DMA max burst size for every AHB request */
++              unsigned int rd_bus                 :  2;       /* peripheral bus width;0 - 8 bits;1 - 16 bits */
++              unsigned int rd_endian          :  1;   /* AHB Endian. 0-little endian; 1-big endian */
++              unsigned int rd_finish_en   :  1;       /* DMA Finish Event Interrupt Enable;1-enable;0-mask */
++              unsigned int rd_fail_en         :  1;   /* DMA Fail Interrupt Enable;1-enable;0-mask */
++              unsigned int rd_perr_en         :  1;   /* Protocol Failure Interrupt Enable;1-enable;0-mask */
++              unsigned int rd_eod_en          :  1;   /* End of Descriptor interrupt Enable;1-enable;0-mask */
++              unsigned int rd_eof_en      :  1;   /* End of frame interrupt Enable;1-enable;0-mask */
++              unsigned int                            : 14;
++#else
++              unsigned int                            : 14;
++              unsigned int rd_eof_en      :  1;   /* End of frame interrupt Enable;1-enable;0-mask */
++              unsigned int rd_eod_en          :  1;   /* End of Descriptor interrupt Enable;1-enable;0-mask */
++              unsigned int rd_perr_en         :  1;   /* Protocol Failure Interrupt Enable;1-enable;0-mask */
++              unsigned int rd_fail_en         :  1;   /* DMA Fail Interrupt Enable;1-enable;0-mask */
++              unsigned int rd_finish_en   :  1;       /* DMA Finish Event Interrupt Enable;1-enable;0-mask */
++              unsigned int rd_endian          :  1;   /* AHB Endian. 0-little endian; 1-big endian */
++              unsigned int rd_bus                 :  2;       /* peripheral bus width;0 - 8 bits;1 - 16 bits */
++              unsigned int rd_burst_size  :  2;       /* DMA max burst size for every AHB request */
++              unsigned int rd_prot            :  4;   /* DMA protection control */
++              unsigned int                            :  1;
++              unsigned int rd_chain_mode      :  1;   /* Descriptor Chain Mode;1-Descriptor Chain mode, 0-Direct DMA mode*/
++              unsigned int rd_continue        :  1;   /* Continue DMA operation */
++              unsigned int rd_start           :  1;   /* Start DMA transfer */
++#endif
++      } bits;
++} IPSEC_RXDMA_CTRL_T;
++
++typedef union
++{
++      unsigned int bits32;
++      struct bit2_ff18
++      {
++#if (BIG_ENDIAN==1)
++              unsigned int rd_first_des_ptr   : 28;/* first descriptor address */
++              unsigned int rd_busy                    :  1;/* 1-RxDMA busy; 0-RxDMA idle */
++              unsigned int                                    :  3;
++#else
++              unsigned int                                    :  3;
++              unsigned int rd_busy                    :  1;/* 1-RxDMA busy; 0-RxDMA idle */
++              unsigned int rd_first_des_ptr   : 28;/* first descriptor address */
++#endif
++      } bits;
++} IPSEC_RXDMA_FIRST_DESC_T;
++
++typedef union
++{
++      unsigned int bits32;
++      struct bit2_ff1c
++      {
++#if (BIG_ENDIAN==1)
++              unsigned int ndar                       : 28;   /* next descriptor address */
++              unsigned int eofie                      :  1;   /* end of frame interrupt enable */
++              unsigned int dec                        :  1;   /* AHB bus address increment(0)/decrement(1) */
++              unsigned int sof_eof            :  2;
++#else
++              unsigned int sof_eof            :  2;
++              unsigned int dec                        :  1;   /* AHB bus address increment(0)/decrement(1) */
++              unsigned int eofie                      :  1;   /* end of frame interrupt enable */
++              unsigned int ndar                       : 28;   /* next descriptor address */
++#endif
++      } bits;
++} IPSEC_RXDMA_CURR_DESC_T;
++
++
++
++/******************************************************/
++/*    the field definition of IPSEC module Register   */
++/******************************************************/
++typedef union
++{
++      unsigned int id;
++      struct bit_0000
++      {
++#if (BIG_ENDIAN==1)
++              unsigned int device_id          : 28;
++              unsigned int revision_id        :  4;
++#else
++              unsigned int revision_id        :  4;
++              unsigned int device_id          : 28;
++#endif
++      } bits;
++} IPSEC_ID_T;
++
++typedef union
++{
++    unsigned int control;
++    struct bit_0004
++    {
++#if (BIG_ENDIAN==1)
++        unsigned int op_mode            :  4; /* Operation Mode for the IPSec Module */
++        unsigned int                    :  1;
++        unsigned int cipher_algorithm   :  3;
++        unsigned int aesnk              :  4; /* AES Key Size */
++        unsigned int mix_key_sel        :  1; /* 0:use rCipherKey0-3  1:use Key Mixer */
++        unsigned int                    :  2;
++        unsigned int fcs_stream_copy    :  1; /* enable authentication stream copy */
++        unsigned int auth_mode          :  1; /* 0-Append or 1-Check Authentication Result */
++        unsigned int auth_algorithm     :  3;
++        unsigned int                    :  1;
++        unsigned int auth_check_len     :  3; /* Number of 32-bit words to be check or appended */
++                                              /* by the authentication module */
++        unsigned int process_id         :  8; /* Used to identify process.This number will be */
++                                              /* copied to the descriptor status of received packet*/
++#else
++        unsigned int process_id         :  8; /* Used to identify process.This number will be */
++                                              /* copied to the descriptor status of received packet*/
++        unsigned int auth_check_len     :  3; /* Number of 32-bit words to be check or appended */
++                                              /* by the authentication module */
++        unsigned int                    :  1;
++        unsigned int auth_algorithm     :  3;
++        unsigned int auth_mode          :  1; /* 0-Append or 1-Check Authentication Result */
++        unsigned int fcs_stream_copy    :  1; /* enable authentication stream copy */
++        unsigned int                    :  2;
++        unsigned int mix_key_sel        :  1; /* 0:use rCipherKey0-3  1:use Key Mixer */
++        unsigned int aesnk              :  4; /* AES Key Size */
++        unsigned int cipher_algorithm   :  3;
++        unsigned int                    :  1;
++        unsigned int op_mode            :  4; /* Operation Mode for the IPSec Module */
++#endif
++    } bits;
++} IPSEC_CONTROL_T;
++
++
++typedef union
++{
++    unsigned int cipher_packet;
++    struct bit_0008
++    {
++#if (BIG_ENDIAN==1)
++        unsigned int cipher_header_len    : 16; /* The header length to be skipped by the cipher */
++        unsigned int cipher_algorithm_len : 16; /* The length of message body to be encrypted/decrypted */
++#else
++        unsigned int cipher_algorithm_len : 16; /* The length of message body to be encrypted/decrypted */
++        unsigned int cipher_header_len    : 16; /* The header length to be skipped by the cipher */
++#endif
++    } bits;
++} IPSEC_CIPHER_PACKET_T;
++
++typedef union
++{
++    unsigned int auth_packet;
++    struct bit_000c
++    {
++#if (BIG_ENDIAN==1)
++        unsigned int auth_header_len    : 16; /* The header length that is to be skipped by the authenticator */
++        unsigned int auth_algorithm_len : 16; /* The length of message body that is to be authenticated */
++#else
++        unsigned int auth_algorithm_len : 16; /* The length of message body that is to be authenticated */
++        unsigned int auth_header_len    : 16; /* The header length that is to be skipped by the authenticator */
++#endif
++    } bits;
++} IPSEC_AUTH_PACKET_T;
++
++typedef union
++{
++    unsigned int status;
++    struct bit_00a8
++    {
++#if (BIG_ENDIAN==1)
++        unsigned int auth_cmp_rslt  :  1; /* Authentication Compare result */
++        unsigned int wep_crc_ok     :  1; /* WEP ICV compare result */
++        unsigned int tkip_mic_ok    :  1; /* TKIP Mic compare result */
++        unsigned int ccm_mic_ok     :  1; /* CCM Mic compare result */
++        unsigned int                : 16;
++        unsigned int parser_err_code:  4; /* Authentication Compare result */
++        unsigned int auth_err_code  :  4; /* Authentication module error code */
++        unsigned int cipher_err_code:  4; /* Cipher module erroe code */
++#else
++        unsigned int cipher_err_code:  4; /* Cipher module erroe code */
++        unsigned int auth_err_code  :  4; /* Authentication module error code */
++        unsigned int parser_err_code:  4; /* Authentication Compare result */
++        unsigned int                : 16;
++        unsigned int ccm_mic_ok     :  1; /* CCM Mic compare result */
++        unsigned int tkip_mic_ok    :  1; /* TKIP Mic compare result */
++        unsigned int wep_crc_ok     :  1; /* WEP ICV compare result */
++        unsigned int auth_cmp_rslt  :  1; /* Authentication Compare result */
++#endif
++    } bits;
++} IPSEC_STATUS_T;
++
++
++
++/************************************************************************/
++/*              IPSec Descriptor Format                                 */
++/************************************************************************/
++typedef struct descriptor_t
++{
++      union frame_control_t
++      {
++              unsigned int bits32;
++              struct bits_0000
++              {
++#if (BIG_ENDIAN==1)
++                      unsigned int own                : 1;    /* owner bit. 0-CPU, 1-DMA */
++                      unsigned int derr               : 1;    /* data error during processing this descriptor */
++                      unsigned int perr               : 1;    /* protocol error during processing this descriptor */
++                      unsigned int            : 1;    /* authentication compare result */
++                      unsigned int            : 6;    /* checksum[15:8] */
++                      unsigned int desc_count : 6;    /* number of descriptors used for the current frame */
++                      unsigned int buffer_size:16;    /* transfer buffer size associated with current description*/
++#else
++                      unsigned int buffer_size:16;    /* transfer buffer size associated with current description*/
++                      unsigned int desc_count : 6;    /* number of descriptors used for the current frame */
++                      unsigned int            : 6;    /* checksum[15:8] */
++                      unsigned int            : 1;    /* authentication compare result */
++                      unsigned int perr               : 1;    /* protocol error during processing this descriptor */
++                      unsigned int derr               : 1;    /* data error during processing this descriptor */
++                      unsigned int own                : 1;    /* owner bit. 0-CPU, 1-DMA */
++#endif
++              } bits;
++      } frame_ctrl;
++
++      union flag_status_t
++      {
++              unsigned int bits32;
++              struct bits_0004
++              {
++#if (BIG_ENDIAN==1)
++//            unsigned int checksum   : 8; /* checksum[7:0] */
++                      unsigned int            : 4;
++                      unsigned int auth_result: 1;
++                      unsigned int wep_crc_ok : 1;
++                      unsigned int tkip_mic_ok: 1;
++                      unsigned int ccmp_mic_ok: 1;
++                      unsigned int process_id : 8;
++                      unsigned int frame_count:16;
++#else
++                      unsigned int frame_count:16;
++                      unsigned int process_id : 8;
++                      unsigned int ccmp_mic_ok: 1;
++                      unsigned int tkip_mic_ok: 1;
++                      unsigned int wep_crc_ok : 1;
++                      unsigned int auth_result: 1;
++                      unsigned int            : 4;
++//            unsigned int checksum   : 8; /* checksum[7:0] */
++#endif
++              } bits_rx_status;
++
++              struct bits_0005
++              {
++#if (BIG_ENDIAN==1)
++            unsigned int            : 8;
++                      unsigned int process_id : 8;
++                      unsigned int frame_count:16;
++#else
++                      unsigned int frame_count:16;
++                      unsigned int process_id : 8;
++            unsigned int            : 8;
++#endif
++              } bits_tx_status;
++
++              struct bits_0006
++              {
++#if (BIG_ENDIAN==1)
++                      unsigned int            :22;
++                      unsigned int tqflag     :10;
++#else
++                      unsigned int tqflag     :10;
++                      unsigned int            :22;
++#endif
++              } bits_tx_flag;
++      } flag_status;
++
++      unsigned int buf_adr;   /* data buffer address */
++
++      union next_desc_t
++      {
++              unsigned int next_descriptor;
++              struct bits_000c
++              {
++#if (BIG_ENDIAN==1)
++                      unsigned int ndar               :28;    /* next descriptor address */
++                      unsigned int eofie              : 1;    /* end of frame interrupt enable */
++                      unsigned int dec                : 1;    /* AHB bus address. 0-increment; 1-decrement */
++                      unsigned int sof_eof    : 2;    /* 00-the linking descriptor   01-the last descriptor of a frame*/
++                                                      /* 10-the first descriptor of a frame    11-only one descriptor for a frame*/
++#else
++                      unsigned int sof_eof    : 2;    /* 00-the linking descriptor   01-the last descriptor of a frame*/
++                                                      /* 10-the first descriptor of a frame    11-only one descriptor for a frame*/
++                      unsigned int dec                : 1;    /* AHB bus address. 0-increment; 1-decrement */
++                      unsigned int eofie              : 1;    /* end of frame interrupt enable */
++                      unsigned int ndar               :28;    /* next descriptor address */
++#endif
++              } bits;
++      } next_desc;
++} IPSEC_DESCRIPTOR_T;
++
++
++typedef struct IPSEC_S
++{
++    unsigned char       *tx_bufs;
++    unsigned char       *rx_bufs;
++      IPSEC_DESCRIPTOR_T      *tx_desc;           /* point to virtual TX descriptor address*/
++      IPSEC_DESCRIPTOR_T      *rx_desc;           /* point to virtual RX descriptor address*/
++      IPSEC_DESCRIPTOR_T      *tx_cur_desc;   /* point to current TX descriptor */
++      IPSEC_DESCRIPTOR_T      *rx_cur_desc;   /* point to current RX descriptor */
++      IPSEC_DESCRIPTOR_T  *tx_finished_desc;
++      IPSEC_DESCRIPTOR_T  *rx_finished_desc;
++      dma_addr_t          rx_desc_dma;        /* physical RX descriptor address */
++      dma_addr_t          tx_desc_dma;    /* physical TX descriptor address */
++      dma_addr_t          rx_bufs_dma;    /* physical RX descriptor address */
++      dma_addr_t          tx_bufs_dma;    /* physical TX descriptor address */
++} IPSEC_T;
++
++
++/*=====================================================================================================*/
++/*  Data Structure of IPSEC Control Packet  */
++/*=====================================================================================================*/
++typedef struct IPSEC_ECB_AUTH_S
++{
++    IPSEC_CONTROL_T         control; /* control parameter */
++    IPSEC_CIPHER_PACKET_T   cipher; /* cipher packet parameter */
++    IPSEC_AUTH_PACKET_T     auth;   /* authentication packet parameter */
++    unsigned char           cipher_key[8*4];
++    unsigned char           auth_check_val[5*4];
++} IPSEC_ECB_AUTH_T;
++
++typedef struct IPSEC_CBC_AUTH_S
++{
++    IPSEC_CONTROL_T         control; /* control parameter */
++    IPSEC_CIPHER_PACKET_T   cipher; /* cipher packet parameter */
++    IPSEC_AUTH_PACKET_T     auth;   /* authentication packet parameter */
++    unsigned char           cipher_iv[4*4];
++    unsigned char           cipher_key[8*4];
++    unsigned char           auth_check_val[5*4];
++} IPSEC_CBC_AUTH_T;
++
++typedef struct IPSEC_ECB_HMAC_AUTH_S
++{
++    IPSEC_CONTROL_T         control; /* control parameter */
++    IPSEC_CIPHER_PACKET_T   cipher; /* cipher packet parameter */
++    IPSEC_AUTH_PACKET_T     auth;   /* authentication packet parameter */
++    unsigned char           cipher_key[8*4];
++    unsigned char           auth_key[16*4];
++    unsigned char           auth_check_val[5*4];
++} IPSEC_ECB_AUTH_HMAC_T;
++
++typedef struct IPSEC_CBC_HMAC_AUTH_S
++{
++    IPSEC_CONTROL_T         control; /* control parameter */
++    IPSEC_CIPHER_PACKET_T   cipher; /* cipher packet parameter */
++    IPSEC_AUTH_PACKET_T     auth;   /* authentication packet parameter */
++    unsigned char           cipher_iv[4*4];
++    unsigned char           cipher_key[8*4];
++    unsigned char           auth_key[16*4];
++    unsigned char           auth_check_val[5*4];
++} IPSEC_CBC_AUTH_HMAC_T;
++
++typedef struct IPSEC_HMAC_AUTH_S
++{
++    IPSEC_CONTROL_T         control; /* control parameter */
++    IPSEC_AUTH_PACKET_T     auth;   /* authentication packet parameter */
++    unsigned char           auth_key[16*4];
++    unsigned char           auth_check_val[5*4];
++} IPSEC_HMAC_AUTH_T;
++
++typedef union
++{
++    unsigned char auth_pkt[28];
++
++    struct IPSEC_AUTH_S
++    {
++        IPSEC_CONTROL_T         control; /* control parameter(4-byte) */
++        IPSEC_AUTH_PACKET_T     auth;   /* authentication packet parameter(4-byte) */
++        unsigned char           auth_check_val[5*4];
++    } var;
++} IPSEC_AUTH_T;
++
++typedef struct IPSEC_CIPHER_CBC_S
++{
++    IPSEC_CONTROL_T         control; /* control parameter */
++    IPSEC_CIPHER_PACKET_T   cipher; /* cipher packet parameter */
++    unsigned char           cipher_iv[4*4];
++    unsigned char           cipher_key[8*4];
++} IPSEC_CIPHER_CBC_T;
++
++typedef struct IPSEC_CIPHER_ECB_S
++{
++    IPSEC_CONTROL_T         control; /* control parameter */
++    IPSEC_CIPHER_PACKET_T   cipher; /* cipher packet parameter */
++    unsigned char           cipher_key[8*4];
++} IPSEC_CIPHER_ECB_T;
++
++
++/****************************************************************************
++ *                          Structure Definition                            *
++ ****************************************************************************/
++struct IPSEC_PACKET_S
++{
++    unsigned int    op_mode;            /* CIPHER_ENC(1),CIPHER_DEC(3),AUTH(4),ENC_AUTH(5),AUTH_DEC(7) */
++    unsigned int    cipher_algorithm;   /* ECB_DES(0),ECB_3DES(1),ECB_AES(2),CBC_DES(4),CBC_3DES(5),CBC_AES(6) */
++    unsigned int    auth_algorithm;     /* SHA1(0),MD5(1),HMAC_SHA1(2),HMAC_MD5(3),FCS(4) */
++    unsigned int    auth_result_mode;   /* AUTH_APPEND(0),AUTH_CHKVAL(1) */
++    unsigned int    process_id;         /* Used to identify the process */
++    unsigned int    auth_header_len;    /* Header length to be skipped by the authenticator */
++    unsigned int    auth_algorithm_len; /* Length of message body that is to be authenticated */
++    unsigned int    cipher_header_len;  /* Header length to be skipped by the cipher */
++    unsigned int    cipher_algorithm_len;   /* Length of message body to be encrypted or decrypted */
++    unsigned char   iv[16];             /* Initial vector used for DES,3DES,AES */
++    unsigned int    iv_size;            /* Initial vector size */
++    unsigned char   auth_key[64];       /* authentication key */
++    unsigned int    auth_key_size;      /* authentication key size */
++    unsigned char   cipher_key[32];     /* cipher key */
++    unsigned int    cipher_key_size;    /* cipher key size */
++    struct scatterlist *in_packet;         /* input_packet buffer pointer */
++    //unsigned char           *in_packet;         /* input_packet buffer pointer */
++    unsigned int    pkt_len;            /* input total packet length */
++    unsigned char   auth_checkval[20];  /* Authentication check value/FCS check value */
++    struct IPSEC_PACKET_S *next,*prev;        /* pointer to next/previous operation to perform on buffer */
++    void (*callback)(struct IPSEC_PACKET_S *); /* function to call when done authentication/cipher */
++    unsigned char   *out_packet;        /* output_packet buffer pointer */
++    //struct scatterlist *out_packet;        /* output_packet buffer pointer */
++    unsigned int    out_pkt_len;        /* output total packet length */
++    unsigned int    auth_cmp_result;    /* authentication compare result */
++    unsigned int    checksum;           /* checksum value */
++    unsigned int    status;             /* ipsec return status. 0:success, others:fail */
++#if (IPSEC_TEST == 1)
++    unsigned char    *sw_packet;         /* for test only */
++    unsigned int    sw_pkt_len;         /* for test only */
++#endif
++} ;
++
++/*****************************************************************************
++ * Function    : ipsec_crypto_hw_process
++ * Description : This function processes H/W authentication and cipher.
++ *       Input : op_info - the authentication and cipher information for IPSec module.
++ *      Output : none.
++ *      Return : 0 - success, others - failure.
++ *****************************************************************************/
++int ipsec_crypto_hw_process(struct IPSEC_PACKET_S  *op_info);
++
++int ipsec_get_cipher_algorithm(unsigned char *alg_name,unsigned int alg_mode);
++int ipsec_get_auth_algorithm(unsigned char *alg_name,unsigned int alg_mode);
++#if 0
++void ipsec_sw_authentication(char *data,unsigned int data_len,char *authkey,char authAlgorithm,char *auth_result);
++void ipsec_sw_cipher(unsigned char *pt,unsigned int pt_len, unsigned char *cipher_key, unsigned int key_size,
++                            unsigned char *iv,unsigned int cipherAlgorithm,unsigned char *ct);
++void ipsec_sw_auth_cipher(unsigned int op_mode,char *data,unsigned int data_len,
++                                BYTE *auth_key,char authAlgorithm,char *auth_result,
++                                char *pt, unsigned int pt_len,char *cipher_key, int key_size,
++                                char *iv, char cipherAlgorithm,char *ct);
++#endif
++
++
++#endif
+Index: linux-2.6.23.16/include/asm-arm/arch-sl2312/sl_random.h
+===================================================================
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.23.16/include/asm-arm/arch-sl2312/sl_random.h    2008-03-13 17:48:24.508798285 +0200
+@@ -0,0 +1,2 @@
++#define RANDOM_ADD            (IO_ADDRESS (0x051000000) + 0x0AC)
++
+Index: linux-2.6.23.16/include/asm-arm/arch-sl2312/system.h
+===================================================================
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.23.16/include/asm-arm/arch-sl2312/system.h       2008-03-13 17:48:24.508798285 +0200
+@@ -0,0 +1,54 @@
++/*
++ *  linux/include/asm-arm/arch-sl2312/system.h
++ *
++ *  Copyright (C) 1999 ARM Limited
++ *  Copyright (C) 2000 Deep Blue Solutions Ltd
++ *  Copyright (C) 2001 Altera Corporation
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++ */
++#ifndef __ASM_ARCH_SYSTEM_H
++#define __ASM_ARCH_SYSTEM_H
++
++#include <asm/arch/platform.h>
++#include <asm/arch/hardware.h>
++#include <asm/arch/it8712.h>
++#include <asm/io.h>
++
++static void arch_idle(void)
++{
++      /*
++       * This should do all the clock switching
++       * and wait for interrupt tricks
++       */
++      cpu_do_idle();
++}
++
++extern __inline__ void arch_reset(char mode)
++{
++      __raw_writel( (int) GLOBAL_RESET|RESET_CPU1, IO_ADDRESS(SL2312_GLOBAL_BASE) + GLOBAL_RESET_REG);
++}
++
++
++void (*pm_power_off)(void);
++//{
++//    printk("arch_power_off\n");
++
++      // Power off
++//    __raw_writel( (int) 0x00000001, IO_ADDRESS(SL2312_POWER_CTRL_BASE) + 0x04);
++
++//}
++
++#endif
+Index: linux-2.6.23.16/include/asm-arm/arch-sl2312/timer.h
+===================================================================
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.23.16/include/asm-arm/arch-sl2312/timer.h        2008-03-13 17:48:24.508798285 +0200
+@@ -0,0 +1,53 @@
++/*
++ *
++ *  This file contains the register definitions for the Excalibur
++ *  Timer TIMER00.
++ *
++ *  Copyright (C) 2001 Altera Corporation
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++ */
++#ifndef __TIMER_H
++#define __TIMER_H
++
++/*
++ * Register definitions for the timers
++ */
++
++#define TIMER_COUNT(BASE_ADDR)          (TIMER_TYPE (BASE_ADDR  + 0x00 ))
++#define TIMER_LOAD(BASE_ADDR)           (TIMER_TYPE (BASE_ADDR  + 0x04 ))
++#define TIMER_MATCH1(BASE_ADDR)         (TIMER_TYPE (BASE_ADDR  + 0x08 ))
++#define TIMER_MATCH2(BASE_ADDR)         (TIMER_TYPE (BASE_ADDR  + 0x0C ))
++#define TIMER_CR(BASE_ADDR)             (TIMER_TYPE (BASE_ADDR  + 0x30 ))
++#define TIMER_1_CR_ENABLE_MSK                     (0x00000001)
++#define TIMER_1_CR_ENABLE_OFST                    (0)
++#define TIMER_1_CR_CLOCK_MSK                      (0x00000002)
++#define TIMER_1_CR_CLOCK_OFST                     (1)
++#define TIMER_1_CR_INT_MSK                    (0x00000004)
++#define TIMER_1_CR_INT_OFST               (2)
++#define TIMER_2_CR_ENABLE_MSK                     (0x00000008)
++#define TIMER_2_CR_ENABLE_OFST                    (3)
++#define TIMER_2_CR_CLOCK_MSK                      (0x00000010)
++#define TIMER_2_CR_CLOCK_OFST                     (4)
++#define TIMER_2_CR_INT_MSK                    (0x00000020)
++#define TIMER_2_CR_INT_OFST               (5)
++#define TIMER_3_CR_ENABLE_MSK                     (0x00000040)
++#define TIMER_3_CR_ENABLE_OFST                    (6)
++#define TIMER_3_CR_CLOCK_MSK                      (0x00000080)
++#define TIMER_3_CR_CLOCK_OFST                     (7)
++#define TIMER_3_CR_INT_MSK                    (0x00000100)
++#define TIMER_3_CR_INT_OFST               (8)
++
++#endif /* __TIMER00_H */
+Index: linux-2.6.23.16/include/asm-arm/arch-sl2312/timex.h
+===================================================================
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.23.16/include/asm-arm/arch-sl2312/timex.h        2008-03-13 17:48:24.508798285 +0200
+@@ -0,0 +1,29 @@
++/*
++ *  linux/include/asm-arm/arch-epxa10db/timex.h
++ *
++ *  Excalibur timex specifications
++ *
++ *  Copyright (C) 2001 Altera Corporation
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++ */
++
++/*
++ * ??
++ */
++#include <asm/arch/sl2312.h>
++
++#define CLOCK_TICK_RATE               APB_CLK
++
+Index: linux-2.6.23.16/include/asm-arm/arch-sl2312/uart.h
+===================================================================
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.23.16/include/asm-arm/arch-sl2312/uart.h 2008-03-13 17:48:24.508798285 +0200
+@@ -0,0 +1,100 @@
++/* *
++ *  Copyright (C) 2001 Altera Corporation
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++ */
++#ifndef __UART_H
++#define __UART_H
++
++/*
++ * Register definitions for the UART
++ */
++
++#define UART_TX_FIFO_SIZE      (15)
++
++#define UART_RBR(BASE_ADDR) (UART_TYPE (BASE_ADDR  + 0x00))  // read
++#define UART_THR(BASE_ADDR) (UART_TYPE (BASE_ADDR  + 0x00))  // write
++#define UART_IER(BASE_ADDR) (UART_TYPE (BASE_ADDR  + 0x04))
++#define UART_IER_MS                                 (0x08)
++#define UART_IER_RLS                                (0x04)
++#define UART_IER_TE                                 (0x02)
++#define UART_IER_DR                                 (0x01)
++#define UART_IIR(BASE_ADDR) (UART_TYPE (BASE_ADDR  + 0x08))   // read
++#define UART_IIR_NONE                             (0x01)      /* No interrupt pending */
++#define UART_IIR_RLS                              (0x06)      /* Receive Line Status */
++#define UART_IIR_DR                               (0x04)      /* Receive Data Ready */
++#define UART_IIR_TIMEOUT                          (0x0c)      /* Receive Time Out */
++#define UART_IIR_TE                               (0x02)      /* THR Empty */
++#define UART_IIR_MODEM                            (0x00)      /* Modem Status */
++#define UART_FCR(BASE_ADDR) (UART_TYPE (BASE_ADDR  + 0x08))  // write
++#define UART_FCR_FE                               (0x01)      /* FIFO Enable */
++#define UART_FCR_RXFR                             (0x02)      /* Rx FIFO Reset */
++#define UART_FCR_TXFR                             (0x04)      /* Tx FIFO Reset */
++#define UART_FCR_FIFO_1C                            (0x00)
++#define UART_FCR_FIFO_4C                            (0x40)
++#define UART_FCR_FIFO_8C                            (0x80)
++#define UART_FCR_FIFO_14C                           (0xC0)
++#define UART_LCR(BASE_ADDR) (UART_TYPE (BASE_ADDR  + 0x0C))
++#define UART_LCR_MSK                                (0x03)
++#define UART_LCR_LEN5                             (0x00)
++#define UART_LCR_LEN6                             (0x01)
++#define UART_LCR_LEN7                             (0x02)
++#define UART_LCR_LEN8                             (0x03)
++#define UART_LCR_STOP                             (0x04)
++#define UART_LCR_EVEN                             (0x18)      /* Even Parity */
++#define UART_LCR_ODD                              (0x08)      /* Odd Parity */
++#define UART_LCR_PE                               (0x08)      /* Parity Enable */
++#define UART_LCR_SETBREAK                         (0x40)      /* Set Break condition */
++#define UART_LCR_STICKPARITY                      (0x20)      /* Stick Parity Enable */
++#define UART_LCR_DLAB                             (0x80)      /* Divisor Latch Access Bit */
++#define UART_MCR(BASE_ADDR) (UART_TYPE (BASE_ADDR  + 0x10))
++#define UART_MCR_DTR                              (0x1)       /* Data Terminal Ready */
++#define UART_MCR_RTS                              (0x2)       /* Request to Send */
++#define UART_MCR_OUT1                             (0x4)       /* output       1 */
++#define UART_MCR_OUT2                             (0x8)       /* output2 or global interrupt enable */
++#define UART_MCR_LPBK                             (0x10)      /* loopback mode */
++#define UART_MCR_MASK                               (0xE3)
++#define UART_LSR(BASE_ADDR) (UART_TYPE (BASE_ADDR  + 0x14))
++#define UART_LSR_DR                               (0x01)      /* Data Ready */
++#define UART_LSR_OE                               (0x02)      /* Overrun Error */
++#define UART_LSR_PE                               (0x04)      /* Parity Error */
++#define UART_LSR_FE                               (0x08)      /* Framing Error */
++#define UART_LSR_BI                                 (0x10)            /* Break Interrupt */
++#define UART_LSR_THRE                               (0x20)            /* THR Empty */
++#define UART_LSR_TE                                 (0x40)            /* Transmitte Empty */
++#define UART_LSR_DE                                 (0x80)            /* FIFO Data Error */
++#define UART_MSR(BASE_ADDR) (UART_TYPE (BASE_ADDR  + 0x18))
++#define UART_MSR_DELTACTS                         (0x01)      /* Delta CTS */
++#define UART_MSR_DELTADSR                         (0x02)      /* Delta DSR */
++#define UART_MSR_TERI                             (0x04)      /* Trailing Edge RI */
++#define UART_MSR_DELTACD                          (0x08)      /* Delta CD */
++#define UART_MSR_CTS                              (0x10)      /* Clear To Send */
++#define UART_MSR_DSR                              (0x20)      /* Data Set Ready */
++#define UART_MSR_RI                               (0x40)      /* Ring Indicator */
++#define UART_MSR_DCD                              (0x80)      /* Data Carrier Detect */
++#define UART_SPR(BASE_ADDR) (UART_TYPE (BASE_ADDR  + 0x1C))
++#define UART_DIV_LO(BASE_ADDR) (UART_TYPE (BASE_ADDR  + 0x0))
++#define UART_DIV_HI(BASE_ADDR) (UART_TYPE (BASE_ADDR  + 0x4))
++#define UART_PSR(BASE_ADDR) (UART_TYPE (BASE_ADDR  + 0x8))
++#define UART_MDR(BASE_ADDR) (UART_TYPE (BASE_ADDR  + 0x20))
++#define UART_MDR_SERIAL                             (0x0)
++
++#define UART_MSR_DDCD 0x08    /* Delta DCD */
++#define UART_MSR_DDSR 0x02    /* Delta DSR */
++#define UART_MSR_DCTS 0x01    /* Delta CTS */
++#define UART_MSR_ANY_DELTA 0x0F       /* Any of the delta bits! */
++
++
++#endif /* __UART_H */
+Index: linux-2.6.23.16/include/asm-arm/arch-sl2312/uncompress.h
+===================================================================
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.23.16/include/asm-arm/arch-sl2312/uncompress.h   2008-03-13 17:48:24.508798285 +0200
+@@ -0,0 +1,94 @@
++/*
++ *  linux/include/asm-arm/arch-epxa10db/uncompress.h
++ *
++ *  Copyright (C) 1999 ARM Limited
++ *  Copyright (C) 2001 Altera Corporation
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++ */
++#include "asm/arch/platform.h"
++#include "asm/arch/hardware.h"
++#define UART_TYPE (volatile unsigned int*)
++#ifndef CONFIG_SERIAL_IT8712
++#include "asm/arch/uart.h"
++#endif
++extern unsigned int it8712_uart_base;
++
++/*
++ * This does not append a newline
++ */
++static void putstr(const char *s)
++{
++
++#ifdef CONFIG_SERIAL_IT8712
++
++      unsigned char *base,*status,stat;
++      int i ;
++
++      status = (unsigned char*)it8712_uart_base + 5;
++      base = (unsigned char*)it8712_uart_base ;
++
++      while (*s) {
++
++              stat = *status;
++              while (!(stat&0x20)) {                          // check status
++                      for(i=0;i<0x10;i++)     ;
++                      status = (unsigned char*)it8712_uart_base + 5;
++                      stat = *status ;
++              }
++
++              *base = *s;
++              barrier();
++
++              if (*s == '\n') {
++                      stat = *status;
++                      while (!(stat&0x20)) {                  // check status
++                              for(i=0;i<0x10;i++)     ;
++                              status = (unsigned char*)it8712_uart_base + 5;
++                              stat = *status ;
++              }
++
++                      barrier();
++                      *base = '\r';
++              }
++              s++;
++      }
++
++#else
++      while (*s) {
++              while (!(*UART_LSR(SL2312_UART_BASE) &
++                       UART_LSR_THRE));
++                     barrier();
++
++              *UART_THR(SL2312_UART_BASE) = *s;
++
++              if (*s == '\n') {
++                      while (!(*UART_LSR(SL2312_UART_BASE) &
++                               UART_LSR_THRE));
++                              barrier();
++
++                      *UART_THR(SL2312_UART_BASE) = '\r';
++              }
++              s++;
++      }
++#endif
++}
++
++/*
++ * nothing to do
++ */
++#define arch_decomp_setup()
++
++#define arch_decomp_wdog()
+Index: linux-2.6.23.16/include/asm-arm/arch-sl2312/vmalloc.h
+===================================================================
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.23.16/include/asm-arm/arch-sl2312/vmalloc.h      2008-03-13 17:48:24.508798285 +0200
+@@ -0,0 +1,36 @@
++/*
++ *  linux/include/asm-arm/arch-epxa10db/vmalloc.h
++ *
++ *  Copyright (C) 2000 Russell King.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++ */
++
++/*
++ * Just any arbitrary offset to the start of the vmalloc VM area: the
++ * current 8MB value just means that there will be a 8MB "hole" after the
++ * physical memory until the kernel virtual memory starts.  That means that
++ * any out-of-bounds memory accesses will hopefully be caught.
++ * The vmalloc() routines leaves a hole of 4kB between each vmalloced
++ * area for the same reason. ;)
++ */
++#define VMALLOC_OFFSET          (8*1024*1024)
++#define VMALLOC_START   (((unsigned long)high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1))
++#define VMALLOC_VMADDR(x) ((unsigned long)(x))
++#define VMALLOC_END       (PAGE_OFFSET + 0x10000000)
++
++//#define MODULE_START    (PAGE_OFFSET - 16*1048576)
++//#define MODULE_END      (PAGE_OFFSET)
++
+Index: linux-2.6.23.16/include/asm-arm/arch-sl2312/watchdog.h
+===================================================================
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.23.16/include/asm-arm/arch-sl2312/watchdog.h     2008-03-13 17:48:24.508798285 +0200
+@@ -0,0 +1,58 @@
++#ifndef __WATCHDOG_H
++#define __WATCHDOG_H
++
++#define WATCHDOG_BASE                   (IO_ADDRESS (SL2312_WAQTCHDOG_BASE))
++#define WATCHDOG_COUNTER                  (WATCHDOG_BASE + 0x00)
++#define WATCHDOG_LOAD                     (WATCHDOG_BASE + 0x04)
++#define WATCHDOG_RESTART                  (WATCHDOG_BASE + 0x08)
++#define WATCHDOG_CR                       (WATCHDOG_BASE + 0x0C)
++#define WATCHDOG_STATUS                   (WATCHDOG_BASE + 0x10)
++#define WATCHDOG_CLEAR                    (WATCHDOG_BASE + 0x14)
++#define WATCHDOG_INTRLEN                  (WATCHDOG_BASE + 0x18)
++
++#define WATCHDOG_WDENABLE_MSK                   (0x00000001)
++#define WATCHDOG_WDENABLE_OFST                  (0)
++#define WATCHDOG_WDRST_MSK              (0x00000002)
++#define WATCHDOG_WDRST_OFST             (1)
++#define WATCHDOG_WDINTR_MSK             (0x00000004)
++#define WATCHDOG_WDINTR_OFST            (2)
++#define WATCHDOG_WDEXT_MSK              (0x00000008)
++#define WATCHDOG_WDEXT_OFST             (3)
++#define WATCHDOG_WDCLOCK_MSK            (0x00000010)
++#define WATCHDOG_WDCLOCK_OFST                   (4)
++#define WATCHDOG_CR_MASK                  (0x0000001F)
++
++#define WATCHDOG_CLEAR_STATUS             0x1
++#define WATCHDOG_ENABLE                   1
++#define WATCHDOG_DISABLE                  0
++#define WATCHDOG_RESTART_VALUE            0x5AB9
++
++#define WATCHDOG_MINOR                          130
++
++#define WATCHDOG_IOCTRL_DISABLE                 0x01
++#define WATCHDOG_IOCTRL_SETTIME                 0x02
++#define WATCHDOG_IOCTRL_ENABLE                  0x03
++#define WATCHDOG_IOCTRL_RESTART                 0x04
++
++#define WATCHDOG_TIMEOUT_SCALE            APB_CLK
++#define WATCHDOG_TIMEOUT_MARGIN           30
++#define WATCHDOG_DRIVER_OPEN              1
++#define WATCHDOG_DRIVER_CLOSE             0
++
++
++static void     watchdog_disable(void);
++static void     watchdog_enable(void);
++static int      watchdog_open(struct inode *, struct file *);
++static int      watchdog_release(struct inode *, struct file *);
++static ssize_t  watchdog_read(struct file *, char *, size_t, loff_t *);
++static ssize_t  watchdog_write(struct file *, const char *, size_t, loff_t *);
++static int      watchdog_ioctl(struct inode *, struct file *, unsigned int, unsigned long);
++#ifdef WATCHDOG_TEST
++static void watchdog_fire(int, void *, struct pt_regs *);
++#endif
++
++
++
++
++
++#endif
+Index: linux-2.6.23.16/include/asm-arm/arch-sl2312/xor.h
+===================================================================
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.23.16/include/asm-arm/arch-sl2312/xor.h  2008-03-13 17:48:24.508798285 +0200
+@@ -0,0 +1,29 @@
++/*
++ * include/asm-arm/arch-sl2312/xor.h
++ *
++ * Copyright (C) 2005 Storlink Corp.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#ifndef _ASM_ARCH_XOR_H
++#define _ASM_ARCH_XOR_H
++
++/*
++ * Function prototypes
++ */
++void xor_gemini_2(unsigned long bytes, unsigned long *p1, unsigned long *p2);
++
++void xor_gemini_3(unsigned long bytes, unsigned long *p1, unsigned long *p2,
++                           unsigned long *p3);
++
++void xor_gemini_4(unsigned long bytes, unsigned long *p1, unsigned long *p2,
++                           unsigned long *p3, unsigned long *p4);
++
++void xor_gemini_5(unsigned long bytes, unsigned long *p1, unsigned long *p2,
++                           unsigned long *p3, unsigned long *p4, unsigned long *p5);
++
++#endif /* _ASM_ARCH_XOR_H */
++
+Index: linux-2.6.23.16/include/asm-arm/cacheflush.h
+===================================================================
+--- linux-2.6.23.16.orig/include/asm-arm/cacheflush.h  2008-03-13 17:46:04.500819685 +0200
++++ linux-2.6.23.16/include/asm-arm/cacheflush.h       2008-03-13 17:48:24.508798285 +0200
+@@ -46,6 +46,18 @@
+ # define MULTI_CACHE 1
+ #endif
++/***********************************************************************
++ *             Storlink SoC -- Cache
++ ***********************************************************************/
++#if defined(CONFIG_CPU_FA526)
++# ifdef _CACHE
++#  define MULTI_CACHE 1
++# else
++#  define _CACHE fa
++# endif
++#endif
++/***********************************************************************/
++
+ #if defined(CONFIG_CPU_ARM926T)
+ # ifdef _CACHE
+ #  define MULTI_CACHE 1
+Index: linux-2.6.23.16/include/asm-arm/page.h
+===================================================================
+--- linux-2.6.23.16.orig/include/asm-arm/page.h        2008-03-13 17:46:04.500819685 +0200
++++ linux-2.6.23.16/include/asm-arm/page.h     2008-03-13 17:48:24.508798285 +0200
+@@ -74,6 +74,18 @@
+ # endif
+ #endif
++/***********************************************************************
++ *             Storlink SoC -- flash
++ ***********************************************************************/
++#ifdef CONFIG_CPU_COPY_FA
++# ifdef _USER
++#  define MULTI_USER 1
++# else
++#  define _USER fa
++# endif
++#endif
++/***********************************************************************/
++
+ #ifdef CONFIG_CPU_SA1100
+ # ifdef _USER
+ #  define MULTI_USER 1
+Index: linux-2.6.23.16/include/asm-arm/proc-fns.h
+===================================================================
+--- linux-2.6.23.16.orig/include/asm-arm/proc-fns.h    2008-03-13 17:46:04.500819685 +0200
++++ linux-2.6.23.16/include/asm-arm/proc-fns.h 2008-03-13 17:48:24.508798285 +0200
+@@ -89,6 +89,14 @@
+ #   define CPU_NAME cpu_arm922
+ #  endif
+ # endif
++# ifdef CONFIG_CPU_FA526
++#  ifdef CPU_NAME
++#   undef  MULTI_CPU
++#   define MULTI_CPU
++#  else
++#   define CPU_NAME cpu_fa526
++#  endif
++# endif
+ # ifdef CONFIG_CPU_ARM925T
+ #  ifdef CPU_NAME
+ #   undef  MULTI_CPU
+Index: linux-2.6.23.16/include/asm-arm/tlbflush.h
+===================================================================
+--- linux-2.6.23.16.orig/include/asm-arm/tlbflush.h    2008-03-13 17:46:04.500819685 +0200
++++ linux-2.6.23.16/include/asm-arm/tlbflush.h 2008-03-13 17:58:18.542650345 +0200
+@@ -39,6 +39,8 @@
+ #define TLB_V6_D_ASID (1 << 17)
+ #define TLB_V6_I_ASID (1 << 18)
++#define TLB_DINVAL      (1 << 28)
++#define TLB_BTB         (1 << 29)
+ #define TLB_DCLEAN    (1 << 30)
+ #define TLB_WB                (1 << 31)
+@@ -52,6 +54,7 @@
+  *      v4wb  - ARMv4 with write buffer without I TLB flush entry instruction
+  *      v4wbi - ARMv4 with write buffer with I TLB flush entry instruction
+  *      v6wbi - ARMv6 with write buffer with I TLB flush entry instruction
++ *    fa    - ARMv4 with write buffer with UTLB and branch target buffer (BTB)
+  */
+ #undef _TLB
+ #undef MULTI_TLB
+@@ -86,6 +89,44 @@
+ # define v4_always_flags      (-1UL)
+ #endif
++#ifdef CONFIG_CPU_FA_BTB
++#define __TLB_BTB      TLB_BTB
++#else
++#define __TLB_BTB      0
++#endif
++
++#ifdef CONFIG_CPU_FA_WB_DISABLE
++#define __TLB_WB       0
++#else
++#define __TLB_WB       TLB_WB
++#endif
++
++/* Fix buggy CPU which doesn't invalidate Dcache properly */
++#ifdef CONFIG_CPU_FA520
++#define __TLB_DINVAL   TLB_DINVAL
++#elif defined(CONFIG_CPU_FA526)
++//#define __TLB_DINVAL   TLB_DINVAL
++#define __TLB_DINVAL   0
++#else
++#define __TLB_DINVAL   0
++#endif
++
++#define fa_tlb_flags  (__TLB_WB | __TLB_BTB | __TLB_DINVAL | TLB_DCLEAN | \
++                         TLB_V4_U_FULL | TLB_V4_U_PAGE)
++
++#ifdef CONFIG_CPU_TLB_FA
++# define fa_possible_flags    fa_tlb_flags
++# define fa_always_flags      fa_tlb_flags
++# ifdef _TLB
++#  define MULTI_TLB 1
++# else
++#  define _TLB fa
++# endif
++#else
++# define fa_possible_flags    0
++# define fa_always_flags      (-1UL)
++#endif
++
+ #define v4wbi_tlb_flags       (TLB_WB | TLB_DCLEAN | \
+                        TLB_V4_I_FULL | TLB_V4_D_FULL | \
+                        TLB_V4_I_PAGE | TLB_V4_D_PAGE)
+@@ -246,12 +287,14 @@
+                                v4_possible_flags | \
+                                v4wbi_possible_flags | \
+                                v4wb_possible_flags | \
++                 fa_possible_flags | \
+                                v6wbi_possible_flags)
+ #define always_tlb_flags      (v3_always_flags & \
+                                v4_always_flags & \
+                                v4wbi_always_flags & \
+                                v4wb_always_flags & \
++                 fa_always_flags & \
+                                v6wbi_always_flags)
+ #define tlb_flag(f)   ((always_tlb_flags & (f)) || (__tlb_flag & possible_tlb_flags & (f)))
+@@ -261,6 +304,9 @@
+       const int zero = 0;
+       const unsigned int __tlb_flag = __cpu_tlb_flags;
++      if (tlb_flag(TLB_DINVAL))
++              asm("mcr%? p15, 0, %0, c7, c14, 0" : : "r" (zero));
++
+       if (tlb_flag(TLB_WB))
+               dsb();
+@@ -281,6 +327,13 @@
+               dsb();
+               isb();
+       }
++
++      if (tlb_flag(TLB_BTB))
++      {
++        asm("mcr%? p15, 0, %0, c7, c5, 6" : : "r" (zero));
++              asm("mov r0, r0" : : );
++              asm("mov r0, r0" : : );
++      }
+ }
+ static inline void local_flush_tlb_mm(struct mm_struct *mm)
+@@ -289,6 +342,9 @@
+       const int asid = ASID(mm);
+       const unsigned int __tlb_flag = __cpu_tlb_flags;
++      if (tlb_flag(TLB_DINVAL))
++              asm("mcr%? p15, 0, %0, c7, c14, 0" : : "r" (zero));
++
+       if (tlb_flag(TLB_WB))
+               dsb();
+@@ -317,6 +373,14 @@
+               asm("mcr p15, 0, %0, c7, c5, 6" : : "r" (zero) : "cc");
+               dsb();
+       }
++
++      if (tlb_flag(TLB_BTB))
++      {
++        asm("mcr%? p15, 0, %0, c7, c5, 6" : : "r" (zero));
++              asm("mov r0, r0" : : );
++              asm("mov r0, r0" : : );
++      }
++
+ }
+ static inline void
+@@ -327,6 +391,9 @@
+       uaddr = (uaddr & PAGE_MASK) | ASID(vma->vm_mm);
++      if (tlb_flag(TLB_DINVAL))
++        asm("mcr%? p15, 0, %0, c7, c14, 0" : : "r" (zero)); // clean & invalidate data cache all
++
+       if (tlb_flag(TLB_WB))
+               dsb();
+@@ -357,6 +424,13 @@
+               asm("mcr p15, 0, %0, c7, c5, 6" : : "r" (zero) : "cc");
+               dsb();
+       }
++
++      if (tlb_flag(TLB_BTB))
++      {
++        asm("mcr%? p15, 0, %0, c7, c5, 6" : : "r" (zero));
++              asm("mov r0, r0" : : );
++              asm("mov r0, r0" : : );
++      }
+ }
+ static inline void local_flush_tlb_kernel_page(unsigned long kaddr)
+@@ -366,6 +440,9 @@
+       kaddr &= PAGE_MASK;
++      if (tlb_flag(TLB_DINVAL))
++        asm("mcr%? p15, 0, %0, c7, c14, 0" : : "r" (zero));
++
+       if (tlb_flag(TLB_WB))
+               dsb();
+@@ -386,6 +463,12 @@
+               asm("mcr p15, 0, %0, c8, c6, 1" : : "r" (kaddr) : "cc");
+       if (tlb_flag(TLB_V6_I_PAGE))
+               asm("mcr p15, 0, %0, c8, c5, 1" : : "r" (kaddr) : "cc");
++      if (tlb_flag(TLB_BTB))
++      {
++        asm("mcr%? p15, 0, %0, c7, c5, 6" : : "r" (zero));
++              asm("mov r0, r0" : : );
++              asm("mov r0, r0" : : );
++      }
+       if (tlb_flag(TLB_V6_I_FULL | TLB_V6_D_FULL |
+                    TLB_V6_I_PAGE | TLB_V6_D_PAGE |
+@@ -412,6 +495,7 @@
+  */
+ static inline void flush_pmd_entry(pmd_t *pmd)
+ {
++      const unsigned int zero = 0;
+       const unsigned int __tlb_flag = __cpu_tlb_flags;
+       if (tlb_flag(TLB_DCLEAN))
+@@ -419,15 +503,30 @@
+                       : : "r" (pmd) : "cc");
+       if (tlb_flag(TLB_WB))
+               dsb();
++
++      if (tlb_flag(TLB_BTB)) // Luke Lee 05/16/2005
++      {
++        asm("mcr%? p15, 0, %0, c7, c5, 6" : : "r" (zero));
++              asm("mov r0, r0" : : );
++              asm("mov r0, r0" : : );
++      }
+ }
+ static inline void clean_pmd_entry(pmd_t *pmd)
+ {
++    const unsigned int zero = 0; // Luke Lee 05/16/2005 ins 1
+       const unsigned int __tlb_flag = __cpu_tlb_flags;
+       if (tlb_flag(TLB_DCLEAN))
+               asm("mcr        p15, 0, %0, c7, c10, 1  @ flush_pmd"
+                       : : "r" (pmd) : "cc");
++
++      if (tlb_flag(TLB_BTB)) // Luke Lee 05/16/2005
++      {
++        asm("mcr%? p15, 0, %0, c7, c5, 6" : : "r" (zero));
++              asm("mov r0, r0" : : );
++              asm("mov r0, r0" : : );
++      }
+ }
+ #undef tlb_flag
+Index: linux-2.6.23.16/include/asm-arm/xor.h
+===================================================================
+--- linux-2.6.23.16.orig/include/asm-arm/xor.h 2008-03-13 17:46:04.500819685 +0200
++++ linux-2.6.23.16/include/asm-arm/xor.h      2008-03-13 17:48:24.508798285 +0200
+@@ -139,3 +139,18 @@
+               xor_speed(&xor_block_8regs);    \
+               xor_speed(&xor_block_32regs);   \
+       } while (0)
++
++#ifdef CONFIG_GEMINI_XOR_ACCE
++#include <asm/arch/xor.h>
++static struct xor_block_template xor_block_gemini = {
++      .name   = "gemini xor acceleration",
++      .do_2   = xor_gemini_2,
++      .do_3   = xor_gemini_3,
++      .do_4   = xor_gemini_4,
++      .do_5   = xor_gemini_5,};
++#undef XOR_TRY_TEMPLATES
++#define XOR_TRY_TEMPLATES                     \
++      do {                                    \
++      xor_speed(&xor_block_gemini); \
++      } while (0)
++#endif
+Index: linux-2.6.23.16/include/linux/apm_bios.h
+===================================================================
+--- linux-2.6.23.16.orig/include/linux/apm_bios.h      2008-03-13 17:46:04.500819685 +0200
++++ linux-2.6.23.16/include/linux/apm_bios.h   2008-03-13 17:48:24.508798285 +0200
+@@ -217,4 +217,24 @@
+ #define APM_IOC_STANDBY               _IO('A', 1)
+ #define APM_IOC_SUSPEND               _IO('A', 2)
++// add by jason for power control
++struct pwc_ioctl_data {
++      unsigned int action;    // sword struct
++      unsigned int data;      // stand shutdown time for PWC_SET_SHUT_TIME
++                              // stand shutdown source for PWC_WAIT_BTN
++};
++
++#define POWEROFF              0x01
++#define RESTORE_DEFAULT       0x02
++#define SYSTEM_REBOOT 0x04
++
++#define PWR_SRC_CIR           0x10
++#define PWR_SRC_RTC           0x20
++#define PWR_SRC_BTN           0x40
++
++#define       PWC_IOCTL_BASE                  'A'                             // use linux APM ioctl
++#define PWC_SET_SHUT_TIME             _IOW('A', 16, struct pwc_ioctl_data)
++#define PWC_WAIT_BTN                  _IOR('A', 17, struct pwc_ioctl_data)
++#define PWC_SHUTDOWN                  _IO ('A', 18)
++
+ #endif        /* LINUX_APM_H */
+Index: linux-2.6.23.16/kernel/time.c
+===================================================================
+--- linux-2.6.23.16.orig/kernel/time.c 2008-03-13 17:46:04.500819685 +0200
++++ linux-2.6.23.16/kernel/time.c      2008-03-13 17:48:24.508798285 +0200
+@@ -76,6 +76,7 @@
+  * why not move it into the appropriate arch directory (for those
+  * architectures that need it).
+  */
++extern void rtc_set_time_second(unsigned int second);
+  
+ asmlinkage long sys_stime(time_t __user *tptr)
+ {
+@@ -87,6 +88,10 @@
+       tv.tv_nsec = 0;
++#ifdef CONFIG_SL2312_RTC
++    rtc_set_time_second(tv.tv_sec);
++#endif
++
+       err = security_settime(&tv, NULL);
+       if (err)
+               return err;
diff --git a/target/linux/storm/patches/1002-gmac.patch b/target/linux/storm/patches/1002-gmac.patch
new file mode 100644 (file)
index 0000000..82c72fb
--- /dev/null
@@ -0,0 +1,18584 @@
+Index: linux-2.6.23.16/drivers/net/sl2312_emac.c
+===================================================================
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.23.16/drivers/net/sl2312_emac.c  2008-03-15 16:59:16.361058585 +0200
+@@ -0,0 +1,4604 @@
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/compiler.h>
++#include <linux/pci.h>
++#include <linux/init.h>
++#include <linux/ioport.h>
++#include <linux/netdevice.h>
++#include <linux/etherdevice.h>
++#include <linux/rtnetlink.h>
++#include <linux/delay.h>
++#include <linux/ethtool.h>
++#include <linux/mii.h>
++#include <linux/completion.h>
++#include <asm/hardware.h>
++#include <asm/io.h>
++#include <asm/irq.h>
++#include <asm/semaphore.h>
++#include <asm/arch-sl2312/irqs.h>
++#include <asm/arch/it8712.h>
++#include <asm/arch/sl2312.h>
++#include <linux/mtd/kvctl.h>
++#include <linux/sysctl_storlink.h>
++
++#define BIG_ENDIAN    0
++
++#define GMAC_DEBUG      0
++
++#define GMAC_PHY_IF     2
++
++/* define PHY address */
++#define HPHY_ADDR   0x01
++#define GPHY_ADDR   0x02
++
++#define CONFIG_ADM_6999 1
++/* define chip information */
++#define DRV_NAME                      "SL2312"
++#define DRV_VERSION                   "0.1.1"
++#define SL2312_DRIVER_NAME  DRV_NAME " Fast Ethernet driver " DRV_VERSION
++
++/* define TX/RX descriptor parameter */
++#define MAX_ETH_FRAME_SIZE    1920
++#define TX_BUF_SIZE                   MAX_ETH_FRAME_SIZE
++#define TX_DESC_NUM                   128
++#define TX_BUF_TOT_LEN                (TX_BUF_SIZE * TX_DESC_NUM)
++#define RX_BUF_SIZE                   MAX_ETH_FRAME_SIZE
++#define RX_DESC_NUM                   256
++#define RX_BUF_TOT_LEN                (RX_BUF_SIZE * RX_DESC_NUM)
++#define MAX_ISR_WORK        20
++
++unsigned int int_status = 0;
++
++/* define GMAC base address */
++#define GMAC_PHYSICAL_BASE_ADDR           (SL2312_GMAC_BASE)
++#define GMAC_BASE_ADDR                            (IO_ADDRESS(GMAC_PHYSICAL_BASE_ADDR))
++#define GMAC_GLOBAL_BASE_ADDR       (IO_ADDRESS(SL2312_GLOBAL_BASE))
++
++#define GMAC0_BASE                  (IO_ADDRESS(SL2312_GMAC0_BASE))
++#define GMAC1_BASE                  (IO_ADDRESS(SL2312_GMAC1_BASE))
++
++/* memory management utility */
++#define DMA_MALLOC(size,handle)               pci_alloc_consistent(NULL,size,handle)
++#define DMA_MFREE(mem,size,handle)    pci_free_consistent(NULL,size,mem,handle)
++
++//#define gmac_read_reg(offset)       (readl(GMAC_BASE_ADDR + offset))
++//#define gmac_write_reg(offset,data,mask)  writel( (gmac_read_reg(offset)&~mask) |(data&mask),(GMAC_BASE_ADDR+offset))
++
++/* define owner bit */
++#define CPU           0
++#define DMA           1
++
++#define ACTIVE      1
++#define NONACTIVE   0
++
++#define CONFIG_SL_NAPI
++
++#ifndef CONFIG_SL2312_MPAGE
++#define CONFIG_SL2312_MPAGE
++#endif
++
++#ifdef CONFIG_SL2312_MPAGE
++#include <linux/skbuff.h>
++#include <linux/ip.h>
++#include <linux/tcp.h>
++#endif
++
++#ifndef CONFIG_TXINT_DISABLE
++//#define CONFIG_TXINT_DISABLE
++#endif
++
++enum phy_state
++{
++    LINK_DOWN   = 0,
++    LINK_UP     = 1
++};
++
++
++/* transmit timeout value */
++#define TX_TIMEOUT  (6*HZ)
++
++/***************************************/
++/* the offset address of GMAC register */
++/***************************************/
++enum GMAC_REGISTER {
++      GMAC_STA_ADD0   = 0x0000,
++      GMAC_STA_ADD1   = 0x0004,
++      GMAC_STA_ADD2   = 0x0008,
++      GMAC_RX_FLTR    = 0x000c,
++      GMAC_MCAST_FIL0 = 0x0010,
++      GMAC_MCAST_FIL1 = 0x0014,
++      GMAC_CONFIG0    = 0x0018,
++      GMAC_CONFIG1    = 0x001c,
++      GMAC_CONFIG2    = 0x0020,
++      GMAC_BNCR               = 0x0024,
++      GMAC_RBNR               = 0x0028,
++      GMAC_STATUS             = 0x002c,
++      GMAC_IN_DISCARDS= 0x0030,
++      GMAC_IN_ERRORS  = 0x0034,
++      GMAC_IN_MCAST   = 0x0038,
++      GMAC_IN_BCAST   = 0x003c,
++      GMAC_IN_MAC1    = 0x0040,
++      GMAC_IN_MAC2    = 0x0044
++};
++
++/*******************************************/
++/* the offset address of GMAC DMA register */
++/*******************************************/
++enum GMAC_DMA_REGISTER {
++      GMAC_DMA_DEVICE_ID              = 0xff00,
++      GMAC_DMA_STATUS                 = 0xff04,
++      GMAC_TXDMA_CTRL                 = 0xff08,
++      GMAC_TXDMA_FIRST_DESC   = 0xff0c,
++      GMAC_TXDMA_CURR_DESC    = 0xff10,
++      GMAC_RXDMA_CTRL                 = 0xff14,
++      GMAC_RXDMA_FIRST_DESC   = 0xff18,
++      GMAC_RXDMA_CURR_DESC    = 0xff1c,
++};
++
++/*******************************************/
++/* the register structure of GMAC          */
++/*******************************************/
++typedef union
++{
++      unsigned int bits32;
++      struct bit1_0004
++      {
++#if (BIG_ENDIAN==1)
++              unsigned int sta_add2_l16       : 16;   /* station MAC address2 bits 15 to 0 */
++              unsigned int sta_add1_h16       : 16;   /* station MAC address1 bits 47 to 32 */
++#else
++              unsigned int sta_add1_h16       : 16;   /* station MAC address1 bits 47 to 32 */
++              unsigned int sta_add2_l16       : 16;   /* station MAC address2 bits 15 to 0 */
++#endif
++      } bits;
++} GMAC_STA_ADD1_T;
++
++typedef union
++{
++      unsigned int bits32;
++      struct bit1_000c
++      {
++#if (BIG_ENDIAN==1)
++              unsigned int                            : 27;
++              unsigned int error                      :  1;   /* enable receive of all error frames */
++              unsigned int promiscuous        :  1;   /* enable receive of all frames */
++              unsigned int broadcast          :  1;   /* enable receive of broadcast frames */
++              unsigned int multicast          :  1;   /* enable receive of multicast frames that pass multicast filter */
++              unsigned int unicast            :  1;   /* enable receive of unicast frames that are sent to STA address */
++#else
++              unsigned int unicast            :  1;   /* enable receive of unicast frames that are sent to STA address */
++              unsigned int multicast          :  1;   /* enable receive of multicast frames that pass multicast filter */
++              unsigned int broadcast          :  1;   /* enable receive of broadcast frames */
++              unsigned int promiscuous        :  1;   /* enable receive of all frames */
++              unsigned int error                      :  1;   /* enable receive of all error frames */
++              unsigned int                            : 27;
++#endif
++      } bits;
++} GMAC_RX_FLTR_T;
++
++typedef union
++{
++      unsigned int bits32;
++      struct bit1_0018
++      {
++#if (BIG_ENDIAN==1)
++              unsigned int : 10;
++              unsigned int inv_rx_clk     : 1;        /* Inverse RX Clock */
++              unsigned int rising_latch   : 1;
++        unsigned int rx_tag_remove  :  1;   /* Remove Rx VLAN tag */
++        unsigned int ipv6_tss_rx_en :  1;   /* IPv6 TSS RX enable */
++        unsigned int ipv4_tss_rx_en :  1;   /* IPv4 TSS RX enable */
++        unsigned int rgmii_en       :  1;   /* RGMII in-band status enable */
++              unsigned int tx_fc_en           :  1;   /* TX flow control enable */
++              unsigned int rx_fc_en           :  1;   /* RX flow control enable */
++              unsigned int sim_test           :  1;   /* speed up timers in simulation */
++              unsigned int dis_col            :  1;   /* disable 16 collisions abort function */
++              unsigned int dis_bkoff          :  1;   /* disable back-off function */
++              unsigned int max_len            :  3;   /* maximum receive frame length allowed */
++              unsigned int adj_ifg            :  4;   /* adjust IFG from 96+/-56 */
++        unsigned int                :  1;   /* reserved */
++              unsigned int loop_back          :  1;   /* transmit data loopback enable */
++              unsigned int dis_rx                     :  1;   /* disable receive */
++              unsigned int dis_tx                     :  1;   /* disable transmit */
++#else
++              unsigned int dis_tx                     :  1;   /* disable transmit */
++              unsigned int dis_rx                     :  1;   /* disable receive */
++              unsigned int loop_back          :  1;   /* transmit data loopback enable */
++        unsigned int                :  1;   /* reserved */
++              unsigned int adj_ifg            :  4;   /* adjust IFG from 96+/-56 */
++              unsigned int max_len            :  3;   /* maximum receive frame length allowed */
++              unsigned int dis_bkoff          :  1;   /* disable back-off function */
++              unsigned int dis_col            :  1;   /* disable 16 collisions abort function */
++              unsigned int sim_test           :  1;   /* speed up timers in simulation */
++              unsigned int rx_fc_en           :  1;   /* RX flow control enable */
++              unsigned int tx_fc_en           :  1;   /* TX flow control enable */
++        unsigned int rgmii_en       :  1;   /* RGMII in-band status enable */
++        unsigned int ipv4_tss_rx_en :  1;   /* IPv4 TSS RX enable */
++        unsigned int ipv6_tss_rx_en :  1;   /* IPv6 TSS RX enable */
++        unsigned int rx_tag_remove  :  1;   /* Remove Rx VLAN tag */
++              unsigned int rising_latch   :  1;
++              unsigned int inv_rx_clk : 1;    /* Inverse RX Clock */
++              unsigned int : 10;
++#endif
++      } bits;
++} GMAC_CONFIG0_T;
++
++typedef union
++{
++      unsigned int bits32;
++      struct bit1_001c
++      {
++#if (BIG_ENDIAN==1)
++              unsigned int                            : 28;
++              unsigned int buf_size           :  4;   /* per packet buffer size */
++#else
++              unsigned int buf_size           :  4;   /* per packet buffer size */
++              unsigned int                            : 28;
++#endif
++      } bits;
++} GMAC_CONFIG1_T;
++
++typedef union
++{
++      unsigned int bits32;
++      struct bit1_0020
++      {
++#if (BIG_ENDIAN==1)
++              unsigned int rel_threshold      : 16;   /* flow control release threshold */
++              unsigned int set_threshold      : 16;   /* flow control set threshold */
++#else
++              unsigned int set_threshold      : 16;   /* flow control set threshold */
++              unsigned int rel_threshold      : 16;   /* flow control release threshold */
++#endif
++      } bits;
++} GMAC_CONFIG2_T;
++
++typedef union
++{
++      unsigned int bits32;
++      struct bit1_0024
++      {
++#if (BIG_ENDIAN==1)
++              unsigned int                            : 16;
++              unsigned int buf_num            : 16;   /* return buffer number from software */
++#else
++              unsigned int buf_num            : 16;   /* return buffer number from software */
++              unsigned int                            : 16;
++#endif
++      } bits;
++} GMAC_BNCR_T;
++
++typedef union
++{
++      unsigned int bits32;
++      struct bit1_0028
++      {
++#if (BIG_ENDIAN==1)
++              unsigned int                            : 16;
++              unsigned int buf_remain         : 16;   /* remaining buffer number */
++#else
++              unsigned int buf_remain         : 16;   /* remaining buffer number */
++              unsigned int                            : 16;
++#endif
++      } bits;
++} GMAC_RBNR_T;
++
++typedef union
++{
++      unsigned int bits32;
++      struct bit1_002c
++      {
++#if (BIG_ENDIAN==1)
++              unsigned int                            : 25;
++              unsigned int mii_rmii           :  2;   /* PHY interface type */
++              unsigned int phy_mode           :  1;   /* PHY interface mode in 10M-bps */
++              unsigned int duplex                     :  1;   /* duplex mode */
++              unsigned int speed                      :  2;   /* link speed(00->2.5M 01->25M 10->125M) */
++              unsigned int link                       :  1;   /* link status */
++#else
++              unsigned int link                       :  1;   /* link status */
++              unsigned int speed                      :  2;   /* link speed(00->2.5M 01->25M 10->125M) */
++              unsigned int duplex                     :  1;   /* duplex mode */
++              unsigned int phy_mode           :  1;   /* PHY interface mode in 10M-bps */
++              unsigned int mii_rmii           :  2;   /* PHY interface type */
++              unsigned int                            : 25;
++#endif
++      } bits;
++} GMAC_STATUS_T;
++
++
++typedef union
++{
++      unsigned int bits32;
++      struct bit1_009
++      {
++#if (BIG_ENDIAN==1)
++              unsigned int                            : 10;
++              unsigned int tx_fail            :  1;   /* Tx fail interrupt */
++              unsigned int cnt_full           :  1;   /* MIB counters half full interrupt */
++              unsigned int rx_pause_on        :  1;   /* received pause on frame interrupt */
++              unsigned int tx_pause_on        :  1;   /* transmit pause on frame interrupt */
++              unsigned int rx_pause_off   :  1;       /* received pause off frame interrupt */
++              unsigned int tx_pause_off       :  1;   /* received pause off frame interrupt */
++              unsigned int rx_overrun         :  1;   /* GMAC Rx FIFO overrun interrupt */
++              unsigned int tx_underrun        :  1;   /* GMAC Tx FIFO underrun interrupt */
++              unsigned int                            :  6;
++              unsigned int m_tx_fail          :  1;   /* Tx fail interrupt mask */
++              unsigned int m_cnt_full         :  1;   /* MIB counters half full interrupt mask */
++              unsigned int m_rx_pause_on      :  1;   /* received pause on frame interrupt mask */
++              unsigned int m_tx_pause_on  :  1;       /* transmit pause on frame interrupt mask */
++              unsigned int m_rx_pause_off :  1;       /* received pause off frame interrupt mask */
++              unsigned int m_tx_pause_off     :  1;   /* received pause off frame interrupt mask */
++              unsigned int m_rx_overrun       :  1;   /* GMAC Rx FIFO overrun interrupt mask */
++              unsigned int m_tx_underrun      :  1;   /* GMAC Tx FIFO underrun interrupt mask */
++#else
++              unsigned int m_tx_underrun      :  1;   /* GMAC Tx FIFO underrun interrupt mask */
++              unsigned int m_rx_overrun       :  1;   /* GMAC Rx FIFO overrun interrupt mask */
++              unsigned int m_tx_pause_off     :  1;   /* received pause off frame interrupt mask */
++              unsigned int m_rx_pause_off :  1;       /* received pause off frame interrupt mask */
++              unsigned int m_tx_pause_on  :  1;       /* transmit pause on frame interrupt mask */
++              unsigned int m_rx_pause_on      :  1;   /* received pause on frame interrupt mask */
++              unsigned int m_cnt_full         :  1;   /* MIB counters half full interrupt mask */
++              unsigned int m_tx_fail          :  1;   /* Tx fail interrupt mask */
++              unsigned int                            :  6;
++              unsigned int tx_underrun        :  1;   /* GMAC Tx FIFO underrun interrupt */
++              unsigned int rx_overrun         :  1;   /* GMAC Rx FIFO overrun interrupt */
++              unsigned int tx_pause_off       :  1;   /* received pause off frame interrupt */
++              unsigned int rx_pause_off   :  1;       /* received pause off frame interrupt */
++              unsigned int tx_pause_on        :  1;   /* transmit pause on frame interrupt */
++              unsigned int rx_pause_on        :  1;   /* received pause on frame interrupt */
++              unsigned int cnt_full           :  1;   /* MIB counters half full interrupt */
++              unsigned int tx_fail            :  1;   /* Tx fail interrupt */
++              unsigned int                            : 10;
++#endif
++      } bits;
++} GMAC_INT_MASK_T;
++
++
++/*******************************************/
++/* the register structure of GMAC DMA      */
++/*******************************************/
++typedef union
++{
++      unsigned int bits32;
++      struct bit2_ff00
++      {
++#if (BIG_ENDIAN==1)
++              unsigned int                :  7;   /* reserved */
++              unsigned int s_ahb_err          :  1;   /* Slave AHB bus error */
++              unsigned int tx_err_code    :  4;   /* TxDMA error code */
++              unsigned int rx_err_code        :  4;   /* RxDMA error code */
++              unsigned int device_id          : 12;
++              unsigned int revision_id        :  4;
++#else
++              unsigned int revision_id        :  4;
++              unsigned int device_id          : 12;
++              unsigned int rx_err_code        :  4;   /* RxDMA error code */
++              unsigned int tx_err_code    :  4;   /* TxDMA error code */
++              unsigned int s_ahb_err          :  1;   /* Slave AHB bus error */
++              unsigned int                :  7;   /* reserved */
++#endif
++      } bits;
++} GMAC_DMA_DEVICE_ID_T;
++
++typedef union
++{
++      unsigned int bits32;
++      struct bit2_ff04
++      {
++#if (BIG_ENDIAN==1)
++              unsigned int ts_finish          :  1;   /* finished tx interrupt */
++              unsigned int ts_derr            :  1;   /* AHB Bus Error while tx */
++              unsigned int ts_perr            :  1;   /* Tx Descriptor protocol error */
++              unsigned int ts_eodi            :  1;   /* TxDMA end of descriptor interrupt */
++              unsigned int ts_eofi            :  1;   /* TxDMA end of frame interrupt */
++              unsigned int rs_finish          :  1;   /* finished rx interrupt */
++              unsigned int rs_derr            :  1;   /* AHB Bus Error while rx */
++              unsigned int rs_perr            :  1;   /* Rx Descriptor protocol error */
++              unsigned int rs_eodi            :  1;   /* RxDMA end of descriptor interrupt */
++              unsigned int rs_eofi            :  1;   /* RxDMA end of frame interrupt */
++              unsigned int                    :  1;   /* Tx fail interrupt */
++              unsigned int cnt_full           :  1;   /* MIB counters half full interrupt */
++              unsigned int rx_pause_on        :  1;   /* received pause on frame interrupt */
++              unsigned int tx_pause_on        :  1;   /* transmit pause on frame interrupt */
++              unsigned int rx_pause_off   :  1;       /* received pause off frame interrupt */
++              unsigned int tx_pause_off       :  1;   /* received pause off frame interrupt */
++              unsigned int rx_overrun         :  1;   /* GMAC Rx FIFO overrun interrupt */
++              unsigned int link_change        :  1;   /* GMAC link changed Interrupt for RGMII mode */
++              unsigned int                    :  1;
++              unsigned int                    :  1;
++              unsigned int                            :  3;
++              unsigned int loop_back          :  1;   /* loopback TxDMA to RxDMA */
++              unsigned int                    :  1;   /* Tx fail interrupt mask */
++              unsigned int m_cnt_full         :  1;   /* MIB counters half full interrupt mask */
++              unsigned int m_rx_pause_on      :  1;   /* received pause on frame interrupt mask */
++              unsigned int m_tx_pause_on  :  1;       /* transmit pause on frame interrupt mask */
++              unsigned int m_rx_pause_off :  1;       /* received pause off frame interrupt mask */
++              unsigned int m_tx_pause_off     :  1;   /* received pause off frame interrupt mask */
++              unsigned int m_rx_overrun       :  1;   /* GMAC Rx FIFO overrun interrupt mask */
++              unsigned int m_link_change      :  1;   /* GMAC link changed Interrupt mask for RGMII mode */
++#else
++              unsigned int m_link_change      :  1;   /* GMAC link changed Interrupt mask for RGMII mode */
++              unsigned int m_rx_overrun       :  1;   /* GMAC Rx FIFO overrun interrupt mask */
++              unsigned int m_tx_pause_off     :  1;   /* received pause off frame interrupt mask */
++              unsigned int m_rx_pause_off :  1;       /* received pause off frame interrupt mask */
++              unsigned int m_tx_pause_on  :  1;       /* transmit pause on frame interrupt mask */
++              unsigned int m_rx_pause_on      :  1;   /* received pause on frame interrupt mask */
++              unsigned int m_cnt_full         :  1;   /* MIB counters half full interrupt mask */
++              unsigned int                    :  1;   /* Tx fail interrupt mask */
++              unsigned int loop_back          :  1;   /* loopback TxDMA to RxDMA */
++              unsigned int                            :  3;
++              unsigned int                    :  1;
++              unsigned int                    :  1;
++              unsigned int link_change        :  1;   /* GMAC link changed Interrupt for RGMII mode */
++              unsigned int rx_overrun         :  1;   /* GMAC Rx FIFO overrun interrupt */
++              unsigned int tx_pause_off       :  1;   /* received pause off frame interrupt */
++              unsigned int rx_pause_off   :  1;       /* received pause off frame interrupt */
++              unsigned int tx_pause_on        :  1;   /* transmit pause on frame interrupt */
++              unsigned int rx_pause_on        :  1;   /* received pause on frame interrupt */
++              unsigned int cnt_full           :  1;   /* MIB counters half full interrupt */
++              unsigned int                    :  1;   /* Tx fail interrupt */
++              unsigned int rs_eofi            :  1;   /* RxDMA end of frame interrupt */
++              unsigned int rs_eodi            :  1;   /* RxDMA end of descriptor interrupt */
++              unsigned int rs_perr            :  1;   /* Rx Descriptor protocol error */
++              unsigned int rs_derr            :  1;   /* AHB Bus Error while rx */
++              unsigned int rs_finish          :  1;   /* finished rx interrupt */
++              unsigned int ts_eofi            :  1;   /* TxDMA end of frame interrupt */
++              unsigned int ts_eodi            :  1;   /* TxDMA end of descriptor interrupt */
++              unsigned int ts_perr            :  1;   /* Tx Descriptor protocol error */
++              unsigned int ts_derr            :  1;   /* AHB Bus Error while tx */
++              unsigned int ts_finish          :  1;   /* finished tx interrupt */
++#endif
++      } bits;
++} GMAC_DMA_STATUS_T;
++
++typedef union
++{
++      unsigned int bits32;
++      struct bit2_ff08
++      {
++#if (BIG_ENDIAN==1)
++              unsigned int td_start           :  1;   /* Start DMA transfer */
++              unsigned int td_continue        :  1;   /* Continue DMA operation */
++              unsigned int td_chain_mode      :  1;   /* Descriptor Chain Mode;1-Descriptor Chain mode, 0-Direct DMA mode*/
++              unsigned int                            :  1;
++              unsigned int td_prot            :  4;   /* TxDMA protection control */
++              unsigned int td_burst_size  :  2;       /* TxDMA max burst size for every AHB request */
++              unsigned int td_bus                 :  2;       /* peripheral bus width;0x->8 bits,10->16 bits,11->32 bits */
++              unsigned int td_endian          :  1;   /* AHB Endian. 0-little endian; 1-big endian */
++              unsigned int td_finish_en   :  1;       /* DMA Finish Event Interrupt Enable;1-enable;0-mask */
++              unsigned int td_fail_en         :  1;   /* DMA Fail Interrupt Enable;1-enable;0-mask */
++              unsigned int td_perr_en         :  1;   /* Protocol Failure Interrupt Enable;1-enable;0-mask */
++              unsigned int td_eod_en          :  1;   /* End of Descriptor interrupt Enable;1-enable;0-mask */
++              unsigned int td_eof_en      :  1;   /* End of frame interrupt Enable;1-enable;0-mask */
++              unsigned int                            : 14;
++#else
++              unsigned int                            : 14;
++              unsigned int td_eof_en      :  1;   /* End of frame interrupt Enable;1-enable;0-mask */
++              unsigned int td_eod_en          :  1;   /* End of Descriptor interrupt Enable;1-enable;0-mask */
++              unsigned int td_perr_en         :  1;   /* Protocol Failure Interrupt Enable;1-enable;0-mask */
++              unsigned int td_fail_en         :  1;   /* DMA Fail Interrupt Enable;1-enable;0-mask */
++              unsigned int td_finish_en   :  1;       /* DMA Finish Event Interrupt Enable;1-enable;0-mask */
++              unsigned int td_endian          :  1;   /* AHB Endian. 0-little endian; 1-big endian */
++              unsigned int td_bus                 :  2;       /* peripheral bus width;0x->8 bits,10->16 bits,11->32 bits */
++              unsigned int td_burst_size  :  2;       /* TxDMA max burst size for every AHB request */
++              unsigned int td_prot            :  4;   /* TxDMA protection control */
++              unsigned int                            :  1;
++              unsigned int td_chain_mode      :  1;   /* Descriptor Chain Mode;1-Descriptor Chain mode, 0-Direct DMA mode*/
++              unsigned int td_continue        :  1;   /* Continue DMA operation */
++              unsigned int td_start           :  1;   /* Start DMA transfer */
++#endif
++      } bits;
++} GMAC_TXDMA_CTRL_T;
++
++
++typedef union
++{
++      unsigned int bits32;
++      struct bit2_ff0c
++      {
++#if (BIG_ENDIAN==1)
++              unsigned int td_first_des_ptr   : 28;/* first descriptor address */
++              unsigned int td_busy                    :  1;/* 1-TxDMA busy; 0-TxDMA idle */
++              unsigned int                                    :  3;
++#else
++              unsigned int                                    :  3;
++              unsigned int td_busy                    :  1;/* 1-TxDMA busy; 0-TxDMA idle */
++              unsigned int td_first_des_ptr   : 28;/* first descriptor address */
++#endif
++      } bits;
++} GMAC_TXDMA_FIRST_DESC_T;
++
++typedef union
++{
++      unsigned int bits32;
++      struct bit2_ff10
++      {
++#if (BIG_ENDIAN==1)
++              unsigned int ndar                       : 28;   /* next descriptor address */
++              unsigned int eofie                      :  1;   /* end of frame interrupt enable */
++              unsigned int                            :  1;
++              unsigned int sof_eof            :  2;
++#else
++              unsigned int sof_eof            :  2;
++              unsigned int                            :  1;
++              unsigned int eofie                      :  1;   /* end of frame interrupt enable */
++              unsigned int ndar                       : 28;   /* next descriptor address */
++#endif
++      } bits;
++} GMAC_TXDMA_CURR_DESC_T;
++
++
++typedef union
++{
++      unsigned int bits32;
++      struct bit2_ff14
++      {
++#if (BIG_ENDIAN==1)
++              unsigned int rd_start           :  1;   /* Start DMA transfer */
++              unsigned int rd_continue        :  1;   /* Continue DMA operation */
++              unsigned int rd_chain_mode      :  1;   /* Descriptor Chain Mode;1-Descriptor Chain mode, 0-Direct DMA mode*/
++              unsigned int                            :  1;
++              unsigned int rd_prot            :  4;   /* DMA protection control */
++              unsigned int rd_burst_size  :  2;       /* DMA max burst size for every AHB request */
++              unsigned int rd_bus                 :  2;       /* peripheral bus width;0x->8 bits,10->16 bits,11->32 bits */
++              unsigned int rd_endian          :  1;   /* AHB Endian. 0-little endian; 1-big endian */
++              unsigned int rd_finish_en   :  1;       /* DMA Finish Event Interrupt Enable;1-enable;0-mask */
++              unsigned int rd_fail_en         :  1;   /* DMA Fail Interrupt Enable;1-enable;0-mask */
++              unsigned int rd_perr_en         :  1;   /* Protocol Failure Interrupt Enable;1-enable;0-mask */
++              unsigned int rd_eod_en          :  1;   /* End of Descriptor interrupt Enable;1-enable;0-mask */
++              unsigned int rd_eof_en      :  1;   /* End of frame interrupt Enable;1-enable;0-mask */
++              unsigned int                            : 14;
++#else
++              unsigned int                            : 14;
++              unsigned int rd_eof_en      :  1;   /* End of frame interrupt Enable;1-enable;0-mask */
++              unsigned int rd_eod_en          :  1;   /* End of Descriptor interrupt Enable;1-enable;0-mask */
++              unsigned int rd_perr_en         :  1;   /* Protocol Failure Interrupt Enable;1-enable;0-mask */
++              unsigned int rd_fail_en         :  1;   /* DMA Fail Interrupt Enable;1-enable;0-mask */
++              unsigned int rd_finish_en   :  1;       /* DMA Finish Event Interrupt Enable;1-enable;0-mask */
++              unsigned int rd_endian          :  1;   /* AHB Endian. 0-little endian; 1-big endian */
++              unsigned int rd_bus                 :  2;       /* peripheral bus width;0x->8 bits,10->16 bits,11->32 bits */
++              unsigned int rd_burst_size  :  2;       /* DMA max burst size for every AHB request */
++              unsigned int rd_prot            :  4;   /* DMA protection control */
++              unsigned int                            :  1;
++              unsigned int rd_chain_mode      :  1;   /* Descriptor Chain Mode;1-Descriptor Chain mode, 0-Direct DMA mode*/
++              unsigned int rd_continue        :  1;   /* Continue DMA operation */
++              unsigned int rd_start           :  1;   /* Start DMA transfer */
++#endif
++      } bits;
++} GMAC_RXDMA_CTRL_T;
++
++
++typedef union
++{
++      unsigned int bits32;
++      struct bit2_ff18
++      {
++#if (BIG_ENDIAN==1)
++              unsigned int rd_first_des_ptr   : 28;/* first descriptor address */
++              unsigned int rd_busy                    :  1;/* 1-RxDMA busy; 0-RxDMA idle */
++              unsigned int                                    :  3;
++#else
++              unsigned int                                    :  3;
++              unsigned int rd_busy                    :  1;/* 1-RxDMA busy; 0-RxDMA idle */
++              unsigned int rd_first_des_ptr   : 28;/* first descriptor address */
++#endif
++      } bits;
++} GMAC_RXDMA_FIRST_DESC_T;
++
++typedef union
++{
++      unsigned int bits32;
++      struct bit2_ff1c
++      {
++#if (BIG_ENDIAN==1)
++              unsigned int ndar                       : 28;   /* next descriptor address */
++              unsigned int eofie                      :  1;   /* end of frame interrupt enable */
++              unsigned int                            :  1;
++              unsigned int sof_eof            :  2;
++#else
++              unsigned int sof_eof            :  2;
++              unsigned int                            :  1;
++              unsigned int eofie                      :  1;   /* end of frame interrupt enable */
++              unsigned int ndar                       : 28;   /* next descriptor address */
++#endif
++      } bits;
++} GMAC_RXDMA_CURR_DESC_T;
++
++
++/********************************************/
++/*          Descriptor Format               */
++/********************************************/
++
++typedef struct descriptor_t
++{
++      union frame_control_t
++      {
++              unsigned int bits32;
++              struct bits_0000
++              {
++#if (BIG_ENDIAN==1)
++                      unsigned int own                : 1;    /* owner bit. 0-CPU, 1-DMA */
++                      unsigned int derr               : 1;    /* data error during processing this descriptor */
++                      unsigned int perr               : 1;    /* protocol error during processing this descriptor */
++                      unsigned int csum_state : 3;    /* checksum error status */
++                      unsigned int vlan_tag   : 1;    /* 802.1q vlan tag packet */
++                      unsigned int frame_state: 3;    /* reference Rx Status1 */
++                      unsigned int desc_count : 6;    /* number of descriptors used for the current frame */
++                      unsigned int buffer_size:16;    /* transfer buffer size associated with current description*/
++#else
++                      unsigned int buffer_size:16;    /* transfer buffer size associated with current description*/
++                      unsigned int desc_count : 6;    /* number of descriptors used for the current frame */
++                      unsigned int frame_state: 3;    /* reference Rx Status1 */
++                      unsigned int vlan_tag   : 1;    /* 802.1q vlan tag packet */
++                      unsigned int csum_state : 3;    /* checksum error status */
++                      unsigned int perr               : 1;    /* protocol error during processing this descriptor */
++                      unsigned int derr               : 1;    /* data error during processing this descriptor */
++                      unsigned int own                : 1;    /* owner bit. 0-CPU, 1-DMA */
++#endif
++              } bits_rx;
++
++              struct bits_0001
++              {
++#if (BIG_ENDIAN==1)
++                      unsigned int own                : 1;    /* owner bit. 0-CPU, 1-DMA */
++                      unsigned int derr               : 1;    /* data error during processing this descriptor */
++                      unsigned int perr               : 1;    /* protocol error during processing this descriptor */
++                      unsigned int            : 6;
++                      unsigned int success_tx : 1;    /* successful transmitted */
++                      unsigned int desc_count : 6;    /* number of descriptors used for the current frame */
++                      unsigned int buffer_size:16;    /* transfer buffer size associated with current description*/
++#else
++                      unsigned int buffer_size:16;    /* transfer buffer size associated with current description*/
++                      unsigned int desc_count : 6;    /* number of descriptors used for the current frame */
++                      unsigned int success_tx : 1;    /* successful transmitted */
++                      unsigned int            : 6;
++                      unsigned int perr               : 1;    /* protocol error during processing this descriptor */
++                      unsigned int derr               : 1;    /* data error during processing this descriptor */
++                      unsigned int own                : 1;    /* owner bit. 0-CPU, 1-DMA */
++#endif
++        } bits_tx_in;
++
++              struct bits_0002
++              {
++#if (BIG_ENDIAN==1)
++                      unsigned int own                : 1;    /* owner bit. 0-CPU, 1-DMA */
++                      unsigned int derr               : 1;    /* data error during processing this descriptor */
++                      unsigned int perr               : 1;    /* protocol error during processing this descriptor */
++                      unsigned int            : 2;
++                      unsigned int udp_csum_en: 1;    /* TSS UDP checksum enable */
++                      unsigned int tcp_csum_en: 1;    /* TSS TCP checksum enable */
++                      unsigned int ipv6_tx_en : 1;    /* TSS IPv6 TX enable */
++                      unsigned int ip_csum_en : 1;    /* TSS IPv4 IP Header checksum enable */
++                      unsigned int vlan_enable: 1;    /* VLAN TIC insertion enable */
++                      unsigned int desc_count : 6;    /* number of descriptors used for the current frame */
++                      unsigned int buffer_size:16;    /* transfer buffer size associated with current description*/
++#else
++                      unsigned int buffer_size:16;    /* transfer buffer size associated with current description*/
++                      unsigned int desc_count : 6;    /* number of descriptors used for the current frame */
++                      unsigned int vlan_enable: 1;    /* VLAN TIC insertion enable */
++                      unsigned int ip_csum_en : 1;    /* TSS IPv4 IP Header checksum enable */
++                      unsigned int ipv6_tx_en : 1;    /* TSS IPv6 TX enable */
++                      unsigned int tcp_csum_en: 1;    /* TSS TCP checksum enable */
++                      unsigned int udp_csum_en: 1;    /* TSS UDP checksum enable */
++                      unsigned int            : 2;
++                      unsigned int perr               : 1;    /* protocol error during processing this descriptor */
++                      unsigned int derr               : 1;    /* data error during processing this descriptor */
++                      unsigned int own                : 1;    /* owner bit. 0-CPU, 1-DMA */
++#endif
++        } bits_tx_out;
++
++      } frame_ctrl;
++
++      union flag_status_t
++      {
++              unsigned int bits32;
++              struct bits_0004
++              {
++#if (BIG_ENDIAN==1)
++            unsigned int priority   : 3;    /* user priority extracted from receiving frame*/
++            unsigned int cfi        : 1;      /* cfi extracted from receiving frame*/
++                      unsigned int vlan_id    :12;    /* VLAN ID extracted from receiving frame */
++                      unsigned int frame_count:16;    /* received frame byte count,include CRC,not include VLAN TIC */
++#else
++                      unsigned int frame_count:16;    /* received frame byte count,include CRC,not include VLAN TIC */
++                      unsigned int vlan_id    :12;    /* VLAN ID extracted from receiving frame */
++            unsigned int cfi        : 1;      /* cfi extracted from receiving frame*/
++            unsigned int priority   : 3;    /* user priority extracted from receiving frame*/
++#endif
++              } bits_rx_status;
++
++              struct bits_0005
++              {
++#if (BIG_ENDIAN==1)
++            unsigned int priority   : 3;    /* user priority to transmit*/
++            unsigned int cfi        : 1;      /* cfi to transmit*/
++                      unsigned int vlan_id    :12;    /* VLAN ID to transmit */
++                      unsigned int frame_count:16;    /* total tx frame byte count */
++#else
++                      unsigned int frame_count:16;    /* total tx frame byte count */
++                      unsigned int vlan_id    :12;    /* VLAN ID to transmit */
++            unsigned int cfi        : 1;      /* cfi to transmit*/
++            unsigned int priority   : 3;    /* user priority to transmit*/
++#endif
++              } bits_tx_flag;
++      } flag_status;
++
++      unsigned int buf_adr;   /* data buffer address */
++
++      union next_desc_t
++      {
++              unsigned int next_descriptor;
++              struct bits_000c
++              {
++#if (BIG_ENDIAN==1)
++                      unsigned int ndar               :28;    /* next descriptor address */
++                      unsigned int eofie              : 1;    /* end of frame interrupt enable */
++                      unsigned int                    : 1;
++                      unsigned int sof_eof    : 2;    /* 00-the linking descriptor   01-the last descriptor of a frame*/
++                                                      /* 10-the first descriptor of a frame    11-only one descriptor for a frame*/
++#else
++                      unsigned int sof_eof    : 2;    /* 00-the linking descriptor   01-the last descriptor of a frame*/
++                                                      /* 10-the first descriptor of a frame    11-only one descriptor for a frame*/
++                      unsigned int                    : 1;
++                      unsigned int eofie              : 1;    /* end of frame interrupt enable */
++                      unsigned int ndar               :28;    /* next descriptor address */
++#endif
++              } bits;
++      } next_desc;
++} GMAC_DESCRIPTOR_T;
++
++typedef struct gmac_conf {
++      struct net_device *dev;
++      int portmap;
++      int vid;
++      int flag;     /* 1: active  0: non-active */
++} sys_gmac_conf;
++
++struct gmac_private {
++      unsigned char       *tx_bufs;   /* Tx bounce buffer region. */
++      unsigned char       *rx_bufs;
++      GMAC_DESCRIPTOR_T       *tx_desc;       /* point to virtual TX descriptor address*/
++      GMAC_DESCRIPTOR_T       *rx_desc;       /* point to virtual RX descriptor address*/
++      GMAC_DESCRIPTOR_T       *tx_cur_desc;   /* point to current TX descriptor */
++      GMAC_DESCRIPTOR_T       *rx_cur_desc;   /* point to current RX descriptor */
++      GMAC_DESCRIPTOR_T   *tx_finished_desc;
++      GMAC_DESCRIPTOR_T   *rx_finished_desc;
++      unsigned long       cur_tx;
++      unsigned int        cur_rx;     /* Index into the Rx buffer of next Rx pkt. */
++      unsigned int        tx_flag;
++      unsigned long       dirty_tx;
++      unsigned char       *tx_buf[TX_DESC_NUM];       /* Tx bounce buffers */
++      dma_addr_t          tx_desc_dma; /* physical TX descriptor address */
++      dma_addr_t          rx_desc_dma;        /* physical RX descriptor address */
++      dma_addr_t          tx_bufs_dma; /* physical TX descriptor address */
++      dma_addr_t          rx_bufs_dma; /* physical RX descriptor address */
++    struct net_device_stats  stats;
++      pid_t               thr_pid;
++      wait_queue_head_t   thr_wait;
++      struct completion   thr_exited;
++    spinlock_t          lock;
++    int                 time_to_die;
++      unsigned int            tx_desc_hdr[GMAC_PHY_IF];       /* the descriptor which sw can fill */
++      unsigned int            tx_desc_tail[GMAC_PHY_IF];      /* the descriptor which is not cleaned yet */
++};
++
++
++struct reg_ioctl_data {
++    unsigned int    reg_addr;   /* the register address */
++    unsigned int    val_in;     /* data write to the register */
++    unsigned int    val_out;    /* data read from the register */
++};
++
++#ifdef CONFIG_SL2312_MPAGE
++typedef struct tx_data_t {
++      int     freeable; // 1 when it's skb. it can be freed in tx interrupt handler
++      struct sk_buff* skb; // skb
++      int     desc_in_use; // 1 when the desc is in use. 0 when desc is available.
++      long end_seq; // to find out packets are in seq.
++      // so this value is the seq of next packet.
++} tx_data;
++#endif
++
++/*************************************************************
++ *         Global Variable
++ *************************************************************/
++struct semaphore        sem_gmac;   /* semaphore for share pins issue */
++
++/*************************************************************
++ *        Static Global Variable
++ *************************************************************/
++// static unsigned int     MAC_BASE_ADDR = GMAC0_BASE;
++static unsigned int     gmac_base_addr[GMAC_PHY_IF] = {GMAC0_BASE,GMAC1_BASE};
++static unsigned int     gmac_irq[GMAC_PHY_IF] = {IRQ_GMAC0,IRQ_GMAC1};
++static struct net_device *gmac_dev[GMAC_PHY_IF];
++
++static unsigned int     FLAG_SWITCH=0;        /* if 1-->switch chip presented. if 0-->switch chip unpresented */
++static unsigned int     flow_control_enable[GMAC_PHY_IF] = {1,1};
++static unsigned int     pre_phy_status[GMAC_PHY_IF] = {LINK_DOWN,LINK_DOWN};
++static unsigned int     tx_desc_virtual_base[GMAC_PHY_IF];
++static unsigned int     rx_desc_virtual_base[GMAC_PHY_IF];
++static unsigned int     full_duplex = 1;
++static unsigned int     speed = 1;
++#ifdef CONFIG_SL2312_MPAGE
++static tx_data                    tx_skb[GMAC_PHY_IF][TX_DESC_NUM];
++#else
++static struct sk_buff   *tx_skb[GMAC_PHY_IF][TX_DESC_NUM];
++#endif
++static struct sk_buff   *rx_skb[GMAC_PHY_IF][RX_DESC_NUM];
++static unsigned int     tx_desc_start_adr[GMAC_PHY_IF];
++static unsigned int     rx_desc_start_adr[GMAC_PHY_IF];
++static unsigned char    eth0_mac[6]= {0x00,0x50,0xc2,0x2b,0xd3,0x25};
++static unsigned char    eth1_mac[6]= {0x00,0x50,0xc2,0x2b,0xdf,0xfe};
++static unsigned int     next_tick = 3 * HZ;
++
++static unsigned int     phy_addr[GMAC_PHY_IF] = {0x01,0x02};  /* define PHY address */
++
++DECLARE_WAIT_QUEUE_HEAD(gmac_queue);
++//static      wait_queue_t    wait;
++
++struct gmac_conf VLAN_conf[] = {
++#ifdef CONFIG_ADM_6999
++      { (struct net_device *)0,0x7F,1 },
++      { (struct net_device *)0,0x80,2 }
++#endif
++#ifdef CONFIG_ADM_6996
++      { (struct net_device *)0,0x0F,1 },
++      { (struct net_device *)0,0x10,2 }
++#endif
++};
++
++#define NUM_VLAN_IF   (sizeof(VLAN_conf)/sizeof(struct gmac_conf))
++
++
++/************************************************/
++/*            GMAC function declare             */
++/************************************************/
++
++unsigned int mii_read(unsigned char phyad,unsigned char regad);
++void mii_write(unsigned char phyad,unsigned char regad,unsigned int value);
++static void gmac_set_phy_status(struct net_device *dev);
++static void gmac_get_phy_status(struct net_device *dev);
++static int gmac_phy_thread (void *data);
++static int gmac_set_mac_address(struct net_device *dev, void *addr);
++static void gmac_tx_timeout(struct net_device *dev);
++static void gmac_tx_packet_complete(struct net_device *dev);
++static int gmac_start_xmit(struct sk_buff *skb, struct net_device *dev);
++static void gmac_set_rx_mode(struct net_device *dev);
++static void gmac_rx_packet(struct net_device *dev);
++static int gmac_open (struct net_device *dev);
++static int gmac_netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
++
++static unsigned int gmac_get_dev_index(struct net_device *dev);
++static unsigned int gmac_select_interface(struct net_device *dev);
++
++#ifdef CONFIG_SL2312_MPAGE
++int printk_all(int dev_index, struct gmac_private* tp);
++#endif
++
++/****************************************/
++/*    SPI Function Declare            */
++/****************************************/
++void SPI_write(unsigned char addr,unsigned int value);
++unsigned int SPI_read(unsigned char table,unsigned char addr);
++void SPI_write_bit(char bit_EEDO);
++unsigned int SPI_read_bit(void);
++void SPI_default(void);
++void SPI_reset(unsigned char rstype,unsigned char port_cnt);
++void SPI_pre_st(void);
++void SPI_CS_enable(unsigned char enable);
++void SPI_Set_VLAN(unsigned char LAN,unsigned int port_mask);
++void SPI_Set_tag(unsigned int port,unsigned tag);
++void SPI_Set_PVID(unsigned int PVID,unsigned int port_mask);
++unsigned int SPI_Get_PVID(unsigned int port);
++void SPI_mac_lock(unsigned int port, unsigned char lock);
++void SPI_get_port_state(unsigned int port);
++void SPI_port_enable(unsigned int port,unsigned char enable);
++unsigned int SPI_get_identifier(void);
++void SPI_get_status(unsigned int port);
++
++/****************************************/
++/*    VLAN Function Declare                   */
++/****************************************/
++int getVLANfromdev (struct net_device *dev );
++struct net_device * getdevfromVLAN( int VID);
++
++
++
++/************************************************/
++/*                 function body                */
++/************************************************/
++#if 0
++void hw_memcpy(void *to,const void *from,unsigned long n)
++{
++    writel(from,SL2312_DRAM_CTRL_BASE+0x20);  /* set source address */
++    writel(to,SL2312_DRAM_CTRL_BASE+0x24);    /* set destination address */
++    writel(n,SL2312_DRAM_CTRL_BASE+0x28);     /* set byte count */
++    writel(0x00000001,SL2312_DRAM_CTRL_BASE+0x2c);
++    while (readl(SL2312_DRAM_CTRL_BASE+0x2c));
++}
++#endif
++
++static unsigned int gmac_read_reg(unsigned int addr)
++{
++    unsigned int    reg_val;
++//    unsigned int    flags;
++//    spinlock_t     lock;
++
++//    spin_lock_irqsave(&lock, flags);
++    reg_val = readl(addr);    // Gary Chen
++//    spin_unlock_irqrestore(&lock, flags);
++      return (reg_val);
++}
++
++static void gmac_write_reg(unsigned int addr,unsigned int data,unsigned int bit_mask)
++{
++      unsigned int    reg_val;
++    //unsigned int    *addr;
++//    unsigned int    flags;
++//    spinlock_t     lock;
++
++//    spin_lock_irqsave(&lock, flags);
++      reg_val = ( gmac_read_reg(addr) & (~bit_mask) ) | (data & bit_mask);
++    writel(reg_val,addr);
++//    spin_unlock_irqrestore(&lock, flags);
++      return;
++}
++
++
++static void gmac_sw_reset(struct net_device *dev)
++{
++    unsigned int    index;
++    unsigned int    reg_val;
++
++    index = gmac_get_dev_index(dev);
++    if (index==0)
++        reg_val = readl(GMAC_GLOBAL_BASE_ADDR+0x0c) | 0x00000020;   /* GMAC0 S/W reset */
++    else
++        reg_val = readl(GMAC_GLOBAL_BASE_ADDR+0x0c) | 0x00000040;   /* GMAC1 S/W reset */
++
++    writel(reg_val,GMAC_GLOBAL_BASE_ADDR+0x0c);
++    return;
++}
++
++static void gmac_get_mac_address(void)
++{
++#ifdef CONFIG_MTD
++      extern int get_vlaninfo(vlaninfo* vlan);
++    static vlaninfo    vlan[2];
++
++    if (get_vlaninfo(&vlan[0]))
++    {
++        memcpy(eth0_mac,vlan[0].mac,6);
++        VLAN_conf[0].vid = vlan[0].vlanid;
++        VLAN_conf[0].portmap = vlan[0].vlanmap;
++        memcpy(eth1_mac,vlan[1].mac,6);
++        VLAN_conf[1].vid = vlan[1].vlanid;
++        VLAN_conf[1].portmap = vlan[1].vlanmap;
++    }
++#else
++    unsigned int reg_val;
++
++    reg_val = readl(IO_ADDRESS(SL2312_SECURITY_BASE)+0xac);
++    eth0_mac[4] = (reg_val & 0xff00) >> 8;
++    eth0_mac[5] = reg_val & 0x00ff;
++    reg_val = readl(IO_ADDRESS(SL2312_SECURITY_BASE)+0xac);
++    eth1_mac[4] = (reg_val & 0xff00) >> 8;
++    eth1_mac[5] = reg_val & 0x00ff;
++#endif
++    return;
++}
++
++static unsigned int gmac_get_dev_index(struct net_device *dev)
++{
++    unsigned int    i;
++
++    /* get device index number */
++    for (i=0;i<GMAC_PHY_IF;i++)
++    {
++        if (gmac_dev[i]==dev)
++        {
++            return(i);
++        }
++    }
++    return (0xff);
++}
++
++static unsigned int gmac_select_interface(struct net_device *dev)
++{
++    unsigned int    index;
++
++    index = gmac_get_dev_index(dev);
++    // MAC_BASE_ADDR = gmac_base_addr[index]; // Gary Chen
++    return (index);
++}
++
++
++static void gmac_dump_register(struct net_device *dev)
++{
++#if 0
++    unsigned int   i,val,index;
++
++    index = gmac_select_interface(dev);
++
++    printk("========== GMAC%d ==========\n",index);
++    for (i=0;i<=0x7c;i=i+4)
++    {
++        val = gmac_read_reg(gmac_base_addr[index] + i);
++        printk("offset = %08x   value = %08x\n",i,val);
++    }
++    for (i=0xff00;i<=0xff7c;i=i+4)
++    {
++        val = gmac_read_reg(gmac_base_addr[index] + i);
++        printk("offset = %08x   value = %08x\n",i,val);
++    }
++#endif
++}
++
++static int gmac_init_chip(struct net_device *dev)
++{
++      GMAC_RBNR_T             rbnr_val,rbnr_mask;
++      GMAC_CONFIG2_T  config2_val;
++      GMAC_CONFIG0_T  config0,config0_mask;
++      GMAC_CONFIG1_T  config1;
++      struct sockaddr sock;
++      unsigned int    status;
++      unsigned int    phy_mode;
++      unsigned int    index;
++
++    index = gmac_get_dev_index(dev);
++
++    /* set GMAC RMII mode */
++    if (index==0)
++        phy_mode = 0;   /* 0->MII 1->GMII 2->RGMII(10/100) 3->RGMII(1000) */
++    else
++        phy_mode = 2;   /* 0->MII 1->GMII 2->RGMII(10/100) 3->RGMII(1000) */
++
++    /* set PHY operation mode */
++    status = (phy_mode<<5) | 0x11 | (full_duplex<<3) | (speed<<1);
++    gmac_write_reg(gmac_base_addr[index] + GMAC_STATUS,status ,0x0000007f);
++
++      /* set station MAC address1 and address2 */
++      if (index==0)
++          memcpy(&sock.sa_data[0],&eth0_mac[0],6);
++    else
++          memcpy(&sock.sa_data[0],&eth1_mac[0],6);
++    gmac_set_mac_address(dev,(void *)&sock);
++
++    /* set RX_FLTR register to receive all multicast packet */
++    gmac_write_reg(gmac_base_addr[index] + GMAC_RX_FLTR,0x0000001F,0x0000001f);
++    //gmac_write_reg(gmac_base_addr[index] + GMAC_RX_FLTR,0x00000007,0x0000001f);
++
++      /* set per packet buffer size */
++      config1.bits32 = 0;
++    config1.bits.buf_size = 11; /* buffer size = 2048-byte */
++    gmac_write_reg(gmac_base_addr[index] + GMAC_CONFIG1,config1.bits32,0x0000000f);
++
++      /* set flow control threshold */
++      config2_val.bits32 = 0;
++      config2_val.bits.set_threshold = RX_DESC_NUM/4;
++      config2_val.bits.rel_threshold = RX_DESC_NUM*3/4;
++      gmac_write_reg(gmac_base_addr[index] + GMAC_CONFIG2,config2_val.bits32,0xffffffff);
++
++      /* init remaining buffer number register */
++      rbnr_val.bits32 = 0;
++      rbnr_val.bits.buf_remain = RX_DESC_NUM;
++      rbnr_mask.bits32 = 0;
++      rbnr_mask.bits.buf_remain = 0xffff;
++      gmac_write_reg(gmac_base_addr[index] + GMAC_RBNR,rbnr_val.bits32,rbnr_mask.bits32);
++
++    /* disable TX/RX and disable internal loop back */
++    config0.bits32 = 0;
++    config0_mask.bits32 = 0;
++    config0.bits.max_len = 2;
++    if (flow_control_enable[index]==1)
++    {
++        config0.bits.tx_fc_en = 1; /* enable tx flow control */
++        config0.bits.rx_fc_en = 1; /* enable rx flow control */
++        printk("Enable MAC Flow Control...\n");
++    }
++    else
++    {
++        config0.bits.tx_fc_en = 0; /* disable tx flow control */
++        config0.bits.rx_fc_en = 0; /* disable rx flow control */
++        printk("Disable MAC Flow Control...\n");
++    }
++    config0.bits.dis_rx = 1;  /* disable rx */
++    config0.bits.dis_tx = 1;  /* disable tx */
++    config0.bits.loop_back = 0; /* enable/disable GMAC loopback */
++      config0.bits.inv_rx_clk = 0;
++      config0.bits.rising_latch = 1;
++      config0.bits.ipv4_tss_rx_en = 1;  /* enable H/W to check ip checksum */
++      config0.bits.ipv6_tss_rx_en = 1;  /* enable H/W to check ip checksum */
++
++    config0_mask.bits.max_len = 7;
++    config0_mask.bits.tx_fc_en = 1;
++    config0_mask.bits.rx_fc_en = 1;
++    config0_mask.bits.dis_rx = 1;
++    config0_mask.bits.dis_tx = 1;
++    config0_mask.bits.loop_back = 1;
++    config0_mask.bits.inv_rx_clk = 1;
++      config0_mask.bits.rising_latch = 1;
++      config0_mask.bits.ipv4_tss_rx_en = 1;
++      config0_mask.bits.ipv6_tss_rx_en = 1;
++    gmac_write_reg(gmac_base_addr[index] + GMAC_CONFIG0,config0.bits32,config0_mask.bits32);
++
++      return (0);
++}
++
++static void gmac_enable_tx_rx(struct net_device *dev)
++{
++      GMAC_CONFIG0_T  config0,config0_mask;
++      int                             dev_index;
++
++    dev_index = gmac_select_interface(dev);
++
++    /* enable TX/RX */
++    config0.bits32 = 0;
++    config0_mask.bits32 = 0;
++    config0.bits.dis_rx = 0;  /* enable rx */
++    config0.bits.dis_tx = 0;  /* enable tx */
++    config0_mask.bits.dis_rx = 1;
++    config0_mask.bits.dis_tx = 1;
++    gmac_write_reg(gmac_base_addr[dev_index] + GMAC_CONFIG0,config0.bits32,config0_mask.bits32);
++}
++
++static void gmac_disable_tx_rx(struct net_device *dev)
++{
++      GMAC_CONFIG0_T  config0,config0_mask;
++      int                             dev_index;
++
++    dev_index = gmac_select_interface(dev);
++
++    /* enable TX/RX */
++    config0.bits32 = 0;
++    config0_mask.bits32 = 0;
++    config0.bits.dis_rx = 1;  /* disable rx */
++    config0.bits.dis_tx = 1;  /* disable tx */
++    config0_mask.bits.dis_rx = 1;
++    config0_mask.bits.dis_tx = 1;
++    gmac_write_reg(gmac_base_addr[dev_index] + GMAC_CONFIG0,config0.bits32,config0_mask.bits32);
++}
++
++#ifdef CONFIG_SL_NAPI
++static int gmac_rx_poll_ga(struct net_device *dev, int *budget)
++{
++      struct gmac_private *tp = dev->priv;
++      struct sk_buff          *skb;
++    GMAC_RXDMA_CTRL_T       rxdma_ctrl,rxdma_ctrl_mask;
++      GMAC_RXDMA_FIRST_DESC_T rxdma_busy;
++    GMAC_DESCRIPTOR_T   *rx_desc;
++      unsigned int            pkt_size;
++      unsigned int        desc_count;
++    unsigned int        vid;
++//    unsigned int        priority;
++      unsigned int        own;
++      unsigned int        good_frame = 0;
++      unsigned int        index;
++      unsigned int        dev_index;
++      int                 work = 0;
++      int                 work_done = 0;
++      int                 quota = min(dev->quota, *budget);
++
++    dev_index = gmac_select_interface(dev);
++
++      for (;;)
++      {
++        own = tp->rx_cur_desc->frame_ctrl.bits32 >> 31;
++        if (own == CPU) /* check owner bit */
++        {
++              rx_desc = tp->rx_cur_desc;
++#if (GMAC_DEBUG==1)
++              /* check error interrupt */
++              if ( (rx_desc->frame_ctrl.bits_rx.derr==1)||(rx_desc->frame_ctrl.bits_rx.perr==1) )
++              {
++              printk("%s::Rx Descriptor Processing Error !!!\n",__func__);
++          }
++#endif
++          /* get frame information from the first descriptor of the frame */
++              pkt_size = rx_desc->flag_status.bits_rx_status.frame_count - 4;  /*total byte count in a frame*/
++#if (GMAC_DEBUG==1)
++            priority = rx_desc->flag_status.bits_rx_status.priority;    /* 802.1p priority */
++#endif
++            vid = rx_desc->flag_status.bits_rx_status.vlan_id;          /* 802.1q vlan id */
++            if (vid == 0)
++            {
++                vid = 1;    /* default vlan */
++            }
++              desc_count = rx_desc->frame_ctrl.bits_rx.desc_count; /* get descriptor count per frame */
++
++              if (rx_desc->frame_ctrl.bits_rx.frame_state == 0x000) /* good frame */
++              {
++                      tp->stats.rx_bytes += pkt_size;
++                      tp->stats.rx_packets++;
++                      good_frame = 1;
++              }
++              else
++              {
++                      tp->stats.rx_errors++;
++                      good_frame = 0;
++                      printk("RX status: 0x%x\n",rx_desc->frame_ctrl.bits_rx.frame_state);
++              }
++      }
++      else
++      {
++          work_done = 1;
++          break;  /* Rx process is completed */
++      }
++
++        if (good_frame == 1)
++        {
++            /* get rx skb buffer index */
++            index = ((unsigned int)tp->rx_cur_desc - rx_desc_start_adr[dev_index]) / sizeof(GMAC_DESCRIPTOR_T);
++            if (rx_skb[dev_index][index])
++            {
++                skb_reserve (rx_skb[dev_index][index], 2);    /* 16 byte align the IP fields. */
++                rx_skb[dev_index][index]->dev = dev;
++                rx_skb[dev_index][index]->ip_summed = CHECKSUM_UNNECESSARY;
++                          skb_put(rx_skb[dev_index][index],pkt_size);
++                          rx_skb[dev_index][index]->protocol = eth_type_trans(rx_skb[dev_index][index],dev); /* set skb protocol */
++                          netif_rx(rx_skb[dev_index][index]);  /* socket rx */
++                          dev->last_rx = jiffies;
++
++                          /* allocate rx skb buffer */
++                if ( (skb = dev_alloc_skb(RX_BUF_SIZE))==NULL)  /* allocate socket buffer */
++                {
++                    printk("%s::skb buffer allocation fail !\n",__func__);
++                }
++                rx_skb[dev_index][index] = skb;
++                tp->rx_cur_desc->buf_adr = (unsigned int)__pa(skb->data) | 0x02;    /* insert two bytes in the beginning of rx data */
++            }
++            else
++            {
++                printk("%s::rx skb index error !\n",__func__);
++            }
++        }
++
++          tp->rx_cur_desc->frame_ctrl.bits_rx.own = DMA; /* release rx descriptor to DMA */
++        /* point to next rx descriptor */
++        tp->rx_cur_desc = (GMAC_DESCRIPTOR_T *)((tp->rx_cur_desc->next_desc.next_descriptor & 0xfffffff0)+rx_desc_virtual_base[dev_index]);
++
++        /* release buffer to Remaining Buffer Number Register */
++        if (flow_control_enable[dev_index] ==1)
++        {
++//            gmac_write_reg(gmac_base_addr[dev_index] + GMAC_BNCR,desc_count,0x0000ffff);
++            writel(desc_count,(unsigned int *)(gmac_base_addr[dev_index] + GMAC_BNCR));
++        }
++
++              if (work++ >= quota )
++              {
++                      break;
++              }
++    }
++
++    /* if RX DMA process is stoped , restart it */
++      rxdma_busy.bits.rd_first_des_ptr = gmac_read_reg(gmac_base_addr[dev_index] + GMAC_RXDMA_FIRST_DESC);
++      if (rxdma_busy.bits.rd_busy == 0)
++      {
++          rxdma_ctrl.bits32 = 0;
++      rxdma_ctrl.bits.rd_start = 1;    /* start RX DMA transfer */
++          rxdma_ctrl.bits.rd_continue = 1; /* continue RX DMA operation */
++          rxdma_ctrl_mask.bits32 = 0;
++      rxdma_ctrl_mask.bits.rd_start = 1;
++          rxdma_ctrl_mask.bits.rd_continue = 1;
++          gmac_write_reg(gmac_base_addr[dev_index] + GMAC_RXDMA_CTRL,rxdma_ctrl.bits32,rxdma_ctrl_mask.bits32);
++    }
++
++      dev->quota -= work;
++      *budget -= work;
++      if (work_done==1)
++      {
++          /* Receive descriptor is empty now */
++        netif_rx_complete(dev);
++        /* enable receive interrupt */
++        gmac_write_reg(gmac_base_addr[dev_index] + GMAC_RXDMA_CTRL,0x0007c000,0x0007c000);   /* enable rx interrupt */
++        return 0;
++    }
++    else
++    {
++        return -1;
++    }
++}
++
++static int gmac_rx_poll_gb(struct net_device *dev, int *budget)
++{
++      struct gmac_private *tp = dev->priv;
++      struct sk_buff          *skb;
++    GMAC_RXDMA_CTRL_T       rxdma_ctrl,rxdma_ctrl_mask;
++      GMAC_RXDMA_FIRST_DESC_T rxdma_busy;
++    GMAC_DESCRIPTOR_T   *rx_desc;
++      unsigned int            pkt_size;
++      unsigned int        desc_count;
++    unsigned int        vid;
++//    unsigned int        priority;
++      unsigned int        own;
++      unsigned int        good_frame = 0;
++      unsigned int        index;
++      unsigned int        dev_index;
++      int                 work = 0;
++      int                 work_done = 0;
++      int                 quota = min(dev->quota, *budget);
++
++    dev_index = gmac_select_interface(dev);
++
++      for (;;)
++      {
++        own = tp->rx_cur_desc->frame_ctrl.bits32 >> 31;
++        if (own == CPU) /* check owner bit */
++        {
++              rx_desc = tp->rx_cur_desc;
++#if (GMAC_DEBUG==1)
++              /* check error interrupt */
++              if ( (rx_desc->frame_ctrl.bits_rx.derr==1)||(rx_desc->frame_ctrl.bits_rx.perr==1) )
++              {
++              printk("%s::Rx Descriptor Processing Error !!!\n",__func__);
++          }
++#endif
++          /* get frame information from the first descriptor of the frame */
++              pkt_size = rx_desc->flag_status.bits_rx_status.frame_count - 4;  /*total byte count in a frame*/
++#if (GMAC_DEBUG==1)
++            priority = rx_desc->flag_status.bits_rx_status.priority;    /* 802.1p priority */
++#endif
++            vid = rx_desc->flag_status.bits_rx_status.vlan_id;          /* 802.1q vlan id */
++            if (vid == 0)
++            {
++                vid = 1;    /* default vlan */
++            }
++              desc_count = rx_desc->frame_ctrl.bits_rx.desc_count; /* get descriptor count per frame */
++
++              if (rx_desc->frame_ctrl.bits_rx.frame_state == 0x000) /* good frame */
++              {
++                      tp->stats.rx_bytes += pkt_size;
++                      tp->stats.rx_packets++;
++                      good_frame = 1;
++              }
++              else
++              {
++                      tp->stats.rx_errors++;
++                      good_frame = 0;
++                      printk("RX status: 0x%x\n",rx_desc->frame_ctrl.bits_rx.frame_state);
++              }
++      }
++      else
++      {
++          work_done = 1;
++          break;  /* Rx process is completed */
++      }
++
++        if (good_frame == 1)
++        {
++            /* get rx skb buffer index */
++            index = ((unsigned int)tp->rx_cur_desc - rx_desc_start_adr[dev_index]) / sizeof(GMAC_DESCRIPTOR_T);
++            if (rx_skb[dev_index][index])
++            {
++                skb_reserve (rx_skb[dev_index][index], 2);    /* 16 byte align the IP fields. */
++                rx_skb[dev_index][index]->dev = dev;
++                rx_skb[dev_index][index]->ip_summed = CHECKSUM_UNNECESSARY;
++                          skb_put(rx_skb[dev_index][index],pkt_size);
++                          rx_skb[dev_index][index]->protocol = eth_type_trans(rx_skb[dev_index][index],dev); /* set skb protocol */
++                          netif_rx(rx_skb[dev_index][index]);  /* socket rx */
++                          dev->last_rx = jiffies;
++
++                          /* allocate rx skb buffer */
++                if ( (skb = dev_alloc_skb(RX_BUF_SIZE))==NULL)  /* allocate socket buffer */
++                {
++                    printk("%s::skb buffer allocation fail !\n",__func__);
++                }
++                rx_skb[dev_index][index] = skb;
++                tp->rx_cur_desc->buf_adr = (unsigned int)__pa(skb->data) | 0x02;    /* insert two bytes in the beginning of rx data */
++            }
++            else
++            {
++                printk("%s::rx skb index error !\n",__func__);
++            }
++        }
++
++          tp->rx_cur_desc->frame_ctrl.bits_rx.own = DMA; /* release rx descriptor to DMA */
++        /* point to next rx descriptor */
++        tp->rx_cur_desc = (GMAC_DESCRIPTOR_T *)((tp->rx_cur_desc->next_desc.next_descriptor & 0xfffffff0)+rx_desc_virtual_base[dev_index]);
++
++        /* release buffer to Remaining Buffer Number Register */
++        if (flow_control_enable[dev_index] ==1)
++        {
++//            gmac_write_reg(gmac_base_addr[dev_index] + GMAC_BNCR,desc_count,0x0000ffff);
++            writel(desc_count,(unsigned int *)(gmac_base_addr[dev_index] + GMAC_BNCR));
++        }
++
++              if (work++ >= quota )
++              {
++                      break;
++              }
++    }
++
++    /* if RX DMA process is stoped , restart it */
++      rxdma_busy.bits.rd_first_des_ptr = gmac_read_reg(gmac_base_addr[dev_index] + GMAC_RXDMA_FIRST_DESC);
++      if (rxdma_busy.bits.rd_busy == 0)
++      {
++          rxdma_ctrl.bits32 = 0;
++      rxdma_ctrl.bits.rd_start = 1;    /* start RX DMA transfer */
++          rxdma_ctrl.bits.rd_continue = 1; /* continue RX DMA operation */
++          rxdma_ctrl_mask.bits32 = 0;
++      rxdma_ctrl_mask.bits.rd_start = 1;
++          rxdma_ctrl_mask.bits.rd_continue = 1;
++          gmac_write_reg(gmac_base_addr[dev_index] + GMAC_RXDMA_CTRL,rxdma_ctrl.bits32,rxdma_ctrl_mask.bits32);
++    }
++
++      dev->quota -= work;
++      *budget -= work;
++      if (work_done==1)
++      {
++          /* Receive descriptor is empty now */
++        netif_rx_complete(dev);
++        /* enable receive interrupt */
++        gmac_write_reg(gmac_base_addr[dev_index] + GMAC_RXDMA_CTRL,0x0007c000,0x0007c000);   /* enable rx interrupt */
++        return 0;
++    }
++    else
++    {
++        return -1;
++    }
++}
++
++#endif
++
++static void gmac_rx_packet(struct net_device *dev)
++{
++      struct gmac_private *tp = dev->priv;
++      struct sk_buff          *skb;
++    GMAC_RXDMA_CTRL_T       rxdma_ctrl,rxdma_ctrl_mask;
++      GMAC_RXDMA_FIRST_DESC_T rxdma_busy;
++    GMAC_DESCRIPTOR_T   *rx_desc;
++      unsigned int            pkt_size;
++      unsigned int        desc_count;
++    unsigned int        vid;
++//    unsigned int        priority;
++      unsigned int        own;
++      unsigned int        good_frame = 0;
++      unsigned int        i,index;
++      unsigned int        dev_index;
++
++    dev_index = gmac_select_interface(dev);
++
++      for (i=0;i<256;i++)
++      {
++        own = tp->rx_cur_desc->frame_ctrl.bits32 >> 31;
++        if (own == CPU) /* check owner bit */
++        {
++              rx_desc = tp->rx_cur_desc;
++#if (GMAC_DEBUG==1)
++              /* check error interrupt */
++              if ( (rx_desc->frame_ctrl.bits_rx.derr==1)||(rx_desc->frame_ctrl.bits_rx.perr==1) )
++              {
++              printk("%s::Rx Descriptor Processing Error !!!\n",__func__);
++          }
++#endif
++          /* get frame information from the first descriptor of the frame */
++              pkt_size = rx_desc->flag_status.bits_rx_status.frame_count - 4;  /*total byte count in a frame*/
++#if (GMAC_DEBUG==1)
++            priority = rx_desc->flag_status.bits_rx_status.priority;    /* 802.1p priority */
++#endif
++            vid = rx_desc->flag_status.bits_rx_status.vlan_id;          /* 802.1q vlan id */
++            if (vid == 0)
++            {
++                vid = 1;    /* default vlan */
++            }
++              desc_count = rx_desc->frame_ctrl.bits_rx.desc_count; /* get descriptor count per frame */
++
++              if (rx_desc->frame_ctrl.bits_rx.frame_state == 0x000) /* good frame */
++              {
++                      tp->stats.rx_bytes += pkt_size;
++                      tp->stats.rx_packets++;
++                      good_frame = 1;
++              }
++              else
++              {
++                      tp->stats.rx_errors++;
++                      good_frame = 0;
++                      printk("RX status: 0x%x\n",rx_desc->frame_ctrl.bits_rx.frame_state);
++              }
++      }
++      else
++      {
++          break;  /* Rx process is completed */
++      }
++
++        if (good_frame == 1)
++        {
++            /* get rx skb buffer index */
++            index = ((unsigned int)tp->rx_cur_desc - rx_desc_start_adr[dev_index]) / sizeof(GMAC_DESCRIPTOR_T);
++            if (rx_skb[dev_index][index])
++            {
++                skb_reserve (rx_skb[dev_index][index], 2);    /* 16 byte align the IP fields. */
++                rx_skb[dev_index][index]->dev = dev;
++                rx_skb[dev_index][index]->ip_summed = CHECKSUM_UNNECESSARY;
++                          skb_put(rx_skb[dev_index][index],pkt_size);
++                          rx_skb[dev_index][index]->protocol = eth_type_trans(rx_skb[dev_index][index],dev); /* set skb protocol */
++                          netif_rx(rx_skb[dev_index][index]);  /* socket rx */
++                          dev->last_rx = jiffies;
++
++                          /* allocate rx skb buffer */
++                if ( (skb = dev_alloc_skb(RX_BUF_SIZE))==NULL)  /* allocate socket buffer */
++                {
++                    printk("%s::skb buffer allocation fail !\n",__func__);
++                }
++                rx_skb[dev_index][index] = skb;
++                tp->rx_cur_desc->buf_adr = (unsigned int)__pa(skb->data) | 0x02;    /* insert two bytes in the beginning of rx data */
++            }
++            else
++            {
++                printk("%s::rx skb index error !\n",__func__);
++            }
++        }
++
++          tp->rx_cur_desc->frame_ctrl.bits_rx.own = DMA; /* release rx descriptor to DMA */
++        /* point to next rx descriptor */
++        tp->rx_cur_desc = (GMAC_DESCRIPTOR_T *)((tp->rx_cur_desc->next_desc.next_descriptor & 0xfffffff0)+rx_desc_virtual_base[dev_index]);
++
++        /* release buffer to Remaining Buffer Number Register */
++        if (flow_control_enable[dev_index] ==1)
++        {
++            gmac_write_reg(gmac_base_addr[dev_index] + GMAC_BNCR,desc_count,0x0000ffff);
++        }
++    }
++
++    /* if RX DMA process is stoped , restart it */
++      rxdma_busy.bits.rd_first_des_ptr = gmac_read_reg(gmac_base_addr[dev_index] + GMAC_RXDMA_FIRST_DESC);
++      if (rxdma_busy.bits.rd_busy == 0)
++      {
++          rxdma_ctrl.bits32 = 0;
++      rxdma_ctrl.bits.rd_start = 1;    /* start RX DMA transfer */
++          rxdma_ctrl.bits.rd_continue = 1; /* continue RX DMA operation */
++          rxdma_ctrl_mask.bits32 = 0;
++      rxdma_ctrl_mask.bits.rd_start = 1;
++          rxdma_ctrl_mask.bits.rd_continue = 1;
++          gmac_write_reg(gmac_base_addr[dev_index] + GMAC_RXDMA_CTRL,rxdma_ctrl.bits32,rxdma_ctrl_mask.bits32);
++    }
++}
++
++#ifdef CONFIG_SL2312_MPAGE
++static inline void free_tx_buf(int dev_index, int desc_index)
++{
++      if (tx_skb[dev_index][desc_index].freeable &&
++          tx_skb[dev_index][desc_index].skb) {
++              struct sk_buff* skb = tx_skb[dev_index][desc_index].skb;
++              //printk("free_skb %x, len %d\n", skb, skb->len);
++#ifdef CONFIG_TXINT_DISABLE
++              dev_kfree_skb(skb);
++#else
++              dev_kfree_skb_irq(skb);
++#endif
++              tx_skb[dev_index][desc_index].skb = 0;
++      }
++}
++
++#ifdef CONFIG_TXINT_DISABLE
++static void gmac_tx_packet_complete(struct net_device *dev)
++{
++      struct gmac_private     *tp = dev->priv;
++    GMAC_DESCRIPTOR_T     *tx_hw_complete_desc, *next_desc;
++    unsigned int desc_cnt=0;
++    unsigned int i,index,dev_index;
++    unsigned int tx_current_descriptor = 0;
++      // int own_dma = 0;
++
++    dev_index = gmac_select_interface(dev);
++
++      index = ((unsigned int)tp->tx_finished_desc - tx_desc_start_adr[dev_index]) / sizeof(GMAC_DESCRIPTOR_T);
++      if (tx_skb[dev_index][index].desc_in_use && tp->tx_finished_desc->frame_ctrl.bits_tx_in.own == CPU) {
++              free_tx_buf(dev_index, index);
++              tx_skb[dev_index][index].desc_in_use = 0;
++      }
++      next_desc = (GMAC_DESCRIPTOR_T*)((tp->tx_finished_desc->next_desc.next_descriptor & 0xfffffff0) + tx_desc_virtual_base[dev_index]);
++
++      for (;;) {
++              tx_hw_complete_desc = (GMAC_DESCRIPTOR_T *)((gmac_read_reg(gmac_base_addr[dev_index] + GMAC_TXDMA_CURR_DESC) & 0xfffffff0)+ tx_desc_virtual_base[dev_index]);
++              if (next_desc == tx_hw_complete_desc)
++                      break;
++              if (next_desc->frame_ctrl.bits_tx_in.own == CPU) {
++                      if (next_desc->frame_ctrl.bits_tx_in.success_tx == 1) {
++                              tp->stats.tx_bytes += next_desc->flag_status.bits_tx_flag.frame_count;
++                              tp->stats.tx_packets ++;
++                      } else {
++                              tp->stats.tx_errors++;
++                      }
++                      desc_cnt = next_desc->frame_ctrl.bits_tx_in.desc_count;
++                      for (i=1; i<desc_cnt; i++) {
++                              /* get tx skb buffer index */
++                              index = ((unsigned int)next_desc - tx_desc_start_adr[dev_index]) / sizeof(GMAC_DESCRIPTOR_T);
++                              next_desc->frame_ctrl.bits_tx_in.own = CPU;
++                              free_tx_buf(dev_index, index);
++                              tx_skb[dev_index][index].desc_in_use = 0;
++                              tp->tx_desc_tail[dev_index] = (tp->tx_desc_tail[dev_index] +1) & (TX_DESC_NUM-1);
++                              /* release Tx descriptor to CPU */
++                              next_desc = (GMAC_DESCRIPTOR_T *)((next_desc->next_desc.next_descriptor & 0xfffffff0)+tx_desc_virtual_base[dev_index]);
++                      }
++                      /* get tx skb buffer index */
++                      index = ((unsigned int)next_desc - tx_desc_start_adr[dev_index]) / sizeof(GMAC_DESCRIPTOR_T);
++                      /* free skb buffer */
++                      next_desc->frame_ctrl.bits_tx_in.own = CPU;
++                      free_tx_buf(dev_index, index);
++                      tx_skb[dev_index][index].desc_in_use = 0;
++                      tp->tx_desc_tail[dev_index] = (tp->tx_desc_tail[dev_index] +1) & (TX_DESC_NUM-1);
++                      tp->tx_finished_desc = next_desc;
++//                    printk("finish tx_desc index %d\n", index);
++                      next_desc = (GMAC_DESCRIPTOR_T *)((next_desc->next_desc.next_descriptor & 0xfffffff0)+tx_desc_virtual_base[dev_index]);
++              }
++              else
++                      break;
++      }
++      if (netif_queue_stopped(dev))
++      {
++              netif_wake_queue(dev);
++      }
++
++}
++#else
++static void gmac_tx_packet_complete(struct net_device *dev)
++{
++      struct gmac_private     *tp = dev->priv;
++      GMAC_DESCRIPTOR_T           *tx_hw_complete_desc;
++      unsigned int desc_cnt=0;
++      unsigned int i,index,dev_index;
++      unsigned int tx_current_descriptor = 0;
++      // int own_dma = 0;
++
++      dev_index = gmac_select_interface(dev);
++
++      index = ((unsigned int)tp->tx_finished_desc - tx_desc_start_adr[dev_index]) / sizeof(GMAC_DESCRIPTOR_T);
++
++      /* check tx status and accumulate tx statistics */
++      for (;;)
++      {
++
++        for (i=0;i<1000;i++)
++        {
++            tx_current_descriptor = gmac_read_reg(gmac_base_addr[dev_index] + GMAC_TXDMA_CURR_DESC);
++            if ( ((tx_current_descriptor & 0x00000003)==0x00000003) ||  /* only one descriptor */
++                 ((tx_current_descriptor & 0x00000003)==0x00000001) )   /* the last descriptor */
++            {
++                break;
++            }
++            udelay(1);
++        }
++        if (i==1000)
++        {
++//            gmac_dump_register(dev);
++//            printk("%s: tx current descriptor = %x \n",__func__,tx_current_descriptor);
++//            printk_all(dev_index, tp);
++            continue;
++        }
++
++          /* get tx H/W completed descriptor virtual address */
++      tx_hw_complete_desc = (GMAC_DESCRIPTOR_T *)((tx_current_descriptor & 0xfffffff0)+ tx_desc_virtual_base[dev_index]);
++//            tx_hw_complete_desc = (GMAC_DESCRIPTOR_T *)((gmac_read_reg(gmac_base_addr[dev_index] + GMAC_TXDMA_CURR_DESC) & 0xfffffff0)+ tx_desc_virtual_base[dev_index]);
++          if (tp->tx_finished_desc == tx_hw_complete_desc ) // ||
++                  //tx_skb[dev_index][index].desc_in_use )   /* complete tx processing */
++              {
++                      break;
++              }
++
++        for (;;)
++        {
++              if (tp->tx_finished_desc->frame_ctrl.bits_tx_in.own == CPU)
++              {
++    #if (GMAC_DEBUG==1)
++                      if ( (tp->tx_finished_desc->frame_ctrl.bits_tx_in.derr) ||
++                         (tp->tx_finished_desc->frame_ctrl.bits_tx_in.perr) )
++                      {
++                              printk("%s::Descriptor Processing Error !!!\n",__func__);
++                      }
++    #endif
++                      if (tp->tx_finished_desc->frame_ctrl.bits_tx_in.success_tx == 1)
++                      {
++                              tp->stats.tx_bytes += tp->tx_finished_desc->flag_status.bits_tx_flag.frame_count;
++                              tp->stats.tx_packets ++;
++                      }
++                      else
++                      {
++                              tp->stats.tx_errors++;
++                      }
++                      desc_cnt = tp->tx_finished_desc->frame_ctrl.bits_tx_in.desc_count;
++                      for (i=1; i<desc_cnt; i++)  /* multi-descriptor in one packet */
++                      {
++                              /* get tx skb buffer index */
++                              index = ((unsigned int)tp->tx_finished_desc - tx_desc_start_adr[dev_index]) / sizeof(GMAC_DESCRIPTOR_T);
++                              tp->tx_finished_desc->frame_ctrl.bits_tx_in.own = CPU;
++                              free_tx_buf(dev_index, index);
++                              tx_skb[dev_index][index].desc_in_use = 0;
++                              /* release Tx descriptor to CPU */
++                              tp->tx_finished_desc = (GMAC_DESCRIPTOR_T *)((tp->tx_finished_desc->next_desc.next_descriptor & 0xfffffff0)+tx_desc_virtual_base[dev_index]);
++                      }
++                      /* get tx skb buffer index */
++                      index = ((unsigned int)tp->tx_finished_desc - tx_desc_start_adr[dev_index]) / sizeof(GMAC_DESCRIPTOR_T);
++                      /* free skb buffer */
++                      tp->tx_finished_desc->frame_ctrl.bits_tx_in.own = CPU;
++                      free_tx_buf(dev_index, index);
++                      tx_skb[dev_index][index].desc_in_use = 0;
++                      tp->tx_finished_desc = (GMAC_DESCRIPTOR_T *)((tp->tx_finished_desc->next_desc.next_descriptor & 0xfffffff0)+tx_desc_virtual_base[dev_index]);
++
++                  if (tp->tx_finished_desc == tx_hw_complete_desc )
++                      {
++                              break;
++                      }
++            }
++              else
++              {
++                      break;
++                      }
++              }
++      }
++
++      if (netif_queue_stopped(dev))
++      {
++              netif_wake_queue(dev);
++      }
++
++}
++#endif
++#else
++
++static void gmac_tx_packet_complete(struct net_device *dev)
++{
++      struct gmac_private     *tp = dev->priv;
++    GMAC_DESCRIPTOR_T     *tx_hw_complete_desc;
++    unsigned int desc_cnt=0;
++    unsigned int i,index,dev_index;
++
++    dev_index = gmac_select_interface(dev);
++
++      /* get tx H/W completed descriptor virtual address */
++      tx_hw_complete_desc = (GMAC_DESCRIPTOR_T *)((gmac_read_reg(gmac_base_addr[dev_index] + GMAC_TXDMA_CURR_DESC) & 0xfffffff0)+ tx_desc_virtual_base[dev_index]);
++      /* check tx status and accumulate tx statistics */
++    for (;;)
++    {
++        if (tp->tx_finished_desc == tx_hw_complete_desc)   /* complete tx processing */
++        {
++            break;
++        }
++      if (tp->tx_finished_desc->frame_ctrl.bits_tx_in.own == CPU)
++      {
++#if (GMAC_DEBUG==1)
++          if ( (tp->tx_finished_desc->frame_ctrl.bits_tx_in.derr) ||
++               (tp->tx_finished_desc->frame_ctrl.bits_tx_in.perr) )
++          {
++              printk("%s::Descriptor Processing Error !!!\n",__func__);
++          }
++#endif
++            if (tp->tx_finished_desc->frame_ctrl.bits_tx_in.success_tx == 1)
++            {
++                tp->stats.tx_bytes += tp->tx_finished_desc->flag_status.bits_tx_flag.frame_count;
++                tp->stats.tx_packets ++;
++            }
++            else
++            {
++                tp->stats.tx_errors++;
++            }
++            desc_cnt = tp->tx_finished_desc->frame_ctrl.bits_tx_in.desc_count;
++              for (i=1; i<desc_cnt; i++)  /* multi-descriptor in one packet */
++              {
++                /* get tx skb buffer index */
++                index = ((unsigned int)tp->tx_finished_desc - tx_desc_start_adr[dev_index]) / sizeof(GMAC_DESCRIPTOR_T);
++                /* free skb buffer */
++                if (tx_skb[dev_index][index])
++                {
++                          dev_kfree_skb_irq(tx_skb[dev_index][index]);
++                      }
++                  /* release Tx descriptor to CPU */
++                tp->tx_finished_desc = (GMAC_DESCRIPTOR_T *)((tp->tx_finished_desc->next_desc.next_descriptor & 0xfffffff0)+tx_desc_virtual_base[dev_index]);
++                tp->tx_finished_desc->frame_ctrl.bits_tx_in.own = CPU;
++              }
++            /* get tx skb buffer index */
++            index = ((unsigned int)tp->tx_finished_desc - tx_desc_start_adr[dev_index]) / sizeof(GMAC_DESCRIPTOR_T);
++            /* free skb buffer */
++            if (tx_skb[dev_index][index])
++            {
++                  dev_kfree_skb_irq(tx_skb[dev_index][index]);
++              }
++            tp->tx_finished_desc = (GMAC_DESCRIPTOR_T *)((tp->tx_finished_desc->next_desc.next_descriptor & 0xfffffff0)+tx_desc_virtual_base[dev_index]);
++      }
++    }
++
++      if (netif_queue_stopped(dev))
++      {
++          netif_wake_queue(dev);
++      }
++
++}
++
++
++#endif
++
++#if 0
++static void gmac_weird_interrupt(struct net_device *dev)
++{
++    gmac_dump_register(dev);
++}
++#endif
++
++/* The interrupt handler does all of the Rx thread work and cleans up
++   after the Tx thread. */
++static irqreturn_t gmac_interrupt (int irq, void *dev_instance, struct pt_regs *regs)
++{
++      struct net_device       *dev = (struct net_device *)dev_instance;
++      GMAC_RXDMA_FIRST_DESC_T rxdma_busy;
++//    GMAC_TXDMA_FIRST_DESC_T txdma_busy;
++//    GMAC_TXDMA_CTRL_T       txdma_ctrl,txdma_ctrl_mask;
++    GMAC_RXDMA_CTRL_T       rxdma_ctrl,rxdma_ctrl_mask;
++      GMAC_DMA_STATUS_T           status;
++    unsigned int            i,dev_index;
++      int                     handled = 0;
++
++    dev_index = gmac_select_interface(dev);
++
++      handled = 1;
++
++#ifdef CONFIG_SL_NAPI
++      disable_irq(gmac_irq[dev_index]);   /* disable GMAC interrupt */
++
++    status.bits32 = gmac_read_reg(gmac_base_addr[dev_index] + GMAC_DMA_STATUS);        /* read DMA status */
++    gmac_write_reg(gmac_base_addr[dev_index] + GMAC_DMA_STATUS,status.bits32,status.bits32);    /* clear DMA status */
++
++    if (status.bits.rx_overrun == 1)
++    {
++              printk("%s::RX Overrun !!!%d\n",__func__,gmac_read_reg(gmac_base_addr[dev_index] + GMAC_RBNR));
++         gmac_dump_register(dev);
++        /* if RX DMA process is stoped , restart it */
++        rxdma_busy.bits32 = gmac_read_reg(gmac_base_addr[dev_index] + GMAC_RXDMA_FIRST_DESC) ;
++        if (rxdma_busy.bits.rd_busy == 0)
++        {
++            /* restart Rx DMA process */
++              rxdma_ctrl.bits32 = 0;
++              rxdma_ctrl.bits.rd_start = 1;    /* start RX DMA transfer */
++            rxdma_ctrl.bits.rd_continue = 1; /* continue RX DMA operation */
++            rxdma_ctrl_mask.bits32 = 0;
++              rxdma_ctrl_mask.bits.rd_start = 1;
++            rxdma_ctrl_mask.bits.rd_continue = 1;
++            gmac_write_reg(gmac_base_addr[dev_index] + GMAC_RXDMA_CTRL,rxdma_ctrl.bits32,rxdma_ctrl_mask.bits32);
++        }
++    }
++
++    /* process rx packet */
++      if (netif_running(dev) && ((status.bits.rs_eofi==1)||(status.bits.rs_finish==1)))
++      {
++        if (likely(netif_rx_schedule_prep(dev)))
++        {
++            gmac_write_reg(gmac_base_addr[dev_index] + GMAC_RXDMA_CTRL,0,0x0007c000);   /* disable rx interrupt */
++            __netif_rx_schedule(dev);
++        }
++    }
++#ifndef CONFIG_TXINT_DISABLE
++    /* process tx packet */
++      if (netif_running(dev) && ((status.bits.ts_eofi==1)||(status.bits.ts_finish==1)))
++      {
++              gmac_tx_packet_complete(dev);
++      }
++#endif
++
++      enable_irq(gmac_irq[dev_index]);    /* enable GMAC interrupt */
++    return IRQ_RETVAL(handled);
++#endif
++
++   /* disable GMAC interrupt */
++      disable_irq(gmac_irq[dev_index]);
++    for (i=0;i<MAX_ISR_WORK;i++)
++    {
++        /* read DMA status */
++          status.bits32 = gmac_read_reg(gmac_base_addr[dev_index] + GMAC_DMA_STATUS);
++int_status = status.bits32;
++          /* clear DMA status */
++        gmac_write_reg(gmac_base_addr[dev_index] + GMAC_DMA_STATUS,status.bits32,status.bits32);
++
++        if ((status.bits32 & 0xffffc000)==0)
++        {
++            break;
++        }
++
++          if (status.bits.rx_overrun == 1)
++          {
++                      printk("%s::RX Overrun !!!%d\n",__func__,gmac_read_reg(gmac_base_addr[dev_index] + GMAC_RBNR));
++              gmac_dump_register(dev);
++            /* if RX DMA process is stoped , restart it */
++              rxdma_busy.bits32 = gmac_read_reg(gmac_base_addr[dev_index] + GMAC_RXDMA_FIRST_DESC) ;
++              if (rxdma_busy.bits.rd_busy == 0)
++              {
++                  /* restart Rx DMA process */
++              rxdma_ctrl.bits32 = 0;
++              rxdma_ctrl.bits.rd_start = 1;    /* start RX DMA transfer */
++                  rxdma_ctrl.bits.rd_continue = 1; /* continue RX DMA operation */
++                  rxdma_ctrl_mask.bits32 = 0;
++              rxdma_ctrl_mask.bits.rd_start = 1;
++                  rxdma_ctrl_mask.bits.rd_continue = 1;
++                  gmac_write_reg(gmac_base_addr[dev_index] + GMAC_RXDMA_CTRL,rxdma_ctrl.bits32,rxdma_ctrl_mask.bits32);
++            }
++          }
++
++        /* receive rx interrupt */
++      if (netif_running(dev) && ((status.bits.rs_eofi==1)||(status.bits.rs_finish==1)))
++      {
++              gmac_rx_packet(dev);
++//                    gmac_tx_packet_complete(dev);
++        }
++
++        /* receive tx interrupt */
++      // if (netif_running(dev) && (status.bits.ts_finish==1))
++#ifndef CONFIG_TXINT_DISABLE
++      if (netif_running(dev) && ((status.bits.ts_eofi==1)||
++                         (status.bits.ts_finish==1)))
++      {
++              gmac_tx_packet_complete(dev);
++      }
++#endif
++      /* check uncommon events */
++/*        if ((status.bits32 & 0x632fc000)!=0)
++        {
++            printk("%s::DMA Status = %08x \n",__func__,status.bits32);
++            gmac_weird_interrupt(dev);
++        }
++*/
++      }
++
++    /* enable GMAC interrupt */
++      enable_irq(gmac_irq[dev_index]);
++      //printk("gmac_interrupt complete!\n\n");
++      return IRQ_RETVAL(handled);
++}
++
++static void gmac_hw_start(struct net_device *dev)
++{
++      struct gmac_private     *tp = dev->priv;
++      GMAC_TXDMA_CURR_DESC_T  tx_desc;
++      GMAC_RXDMA_CURR_DESC_T  rx_desc;
++    GMAC_TXDMA_CTRL_T       txdma_ctrl,txdma_ctrl_mask;
++    GMAC_RXDMA_CTRL_T       rxdma_ctrl,rxdma_ctrl_mask;
++      GMAC_DMA_STATUS_T       dma_status,dma_status_mask;
++      int                                             dev_index;
++
++    dev_index = gmac_select_interface(dev);
++
++      /* program TxDMA Current Descriptor Address register for first descriptor */
++      tx_desc.bits32 = (unsigned int)(tp->tx_desc_dma);
++      tx_desc.bits.eofie = 1;
++      tx_desc.bits.sof_eof = 0x03;
++      gmac_write_reg(gmac_base_addr[dev_index] + GMAC_TXDMA_CURR_DESC,tx_desc.bits32,0xffffffff);
++      gmac_write_reg(gmac_base_addr[dev_index] + 0xff2c,tx_desc.bits32,0xffffffff);   /* tx next descriptor address */
++
++      /* program RxDMA Current Descriptor Address register for first descriptor */
++      rx_desc.bits32 = (unsigned int)(tp->rx_desc_dma);
++      rx_desc.bits.eofie = 1;
++      rx_desc.bits.sof_eof = 0x03;
++      gmac_write_reg(gmac_base_addr[dev_index] + GMAC_RXDMA_CURR_DESC,rx_desc.bits32,0xffffffff);
++      gmac_write_reg(gmac_base_addr[dev_index] + 0xff3c,rx_desc.bits32,0xffffffff);   /* rx next descriptor address */
++
++      /* enable GMAC interrupt & disable loopback */
++      dma_status.bits32 = 0;
++      dma_status.bits.loop_back = 0;  /* disable DMA loop-back mode */
++//    dma_status.bits.m_tx_fail = 1;
++      dma_status.bits.m_cnt_full = 1;
++      dma_status.bits.m_rx_pause_on = 1;
++      dma_status.bits.m_tx_pause_on = 1;
++      dma_status.bits.m_rx_pause_off = 1;
++      dma_status.bits.m_tx_pause_off = 1;
++      dma_status.bits.m_rx_overrun = 1;
++      dma_status.bits.m_link_change = 1;
++      dma_status_mask.bits32 = 0;
++      dma_status_mask.bits.loop_back = 1;
++//    dma_status_mask.bits.m_tx_fail = 1;
++      dma_status_mask.bits.m_cnt_full = 1;
++      dma_status_mask.bits.m_rx_pause_on = 1;
++      dma_status_mask.bits.m_tx_pause_on = 1;
++      dma_status_mask.bits.m_rx_pause_off = 1;
++      dma_status_mask.bits.m_tx_pause_off = 1;
++      dma_status_mask.bits.m_rx_overrun = 1;
++      dma_status_mask.bits.m_link_change = 1;
++      gmac_write_reg(gmac_base_addr[dev_index] + GMAC_DMA_STATUS,dma_status.bits32,dma_status_mask.bits32);
++
++    /* program tx dma control register */
++      txdma_ctrl.bits32 = 0;
++      txdma_ctrl.bits.td_start = 0;    /* start TX DMA transfer */
++      txdma_ctrl.bits.td_continue = 0; /* continue Tx DMA operation */
++      txdma_ctrl.bits.td_chain_mode = 1;  /* chain mode */
++      txdma_ctrl.bits.td_prot = 0;
++      txdma_ctrl.bits.td_burst_size = 2;  /* DMA burst size for every AHB request */
++      txdma_ctrl.bits.td_bus = 2;         /* peripheral bus width */
++      txdma_ctrl.bits.td_endian = 0;      /* little endian */
++#ifdef CONFIG_TXINT_DISABLE
++      txdma_ctrl.bits.td_finish_en = 0;   /* DMA finish event interrupt disable */
++#else
++      txdma_ctrl.bits.td_finish_en = 1;   /* DMA finish event interrupt enable */
++#endif
++      txdma_ctrl.bits.td_fail_en = 1;     /* DMA fail interrupt enable */
++      txdma_ctrl.bits.td_perr_en = 1;     /* protocol failure interrupt enable */
++      txdma_ctrl.bits.td_eod_en = 0;      /* disable Tx End of Descriptor Interrupt */
++      //txdma_ctrl.bits.td_eod_en = 0;      /* disable Tx End of Descriptor Interrupt */
++#ifdef CONFIG_TXINT_DISABLE
++      txdma_ctrl.bits.td_eof_en = 0;      /* end of frame interrupt disable */
++#else
++      txdma_ctrl.bits.td_eof_en = 1;      /* end of frame interrupt enable */
++#endif
++      txdma_ctrl_mask.bits32 = 0;
++      txdma_ctrl_mask.bits.td_start = 1;
++      txdma_ctrl_mask.bits.td_continue = 1;
++      txdma_ctrl_mask.bits.td_chain_mode = 1;
++      txdma_ctrl_mask.bits.td_prot = 15;
++      txdma_ctrl_mask.bits.td_burst_size = 3;
++      txdma_ctrl_mask.bits.td_bus = 3;
++      txdma_ctrl_mask.bits.td_endian = 1;
++      txdma_ctrl_mask.bits.td_finish_en = 1;
++      txdma_ctrl_mask.bits.td_fail_en = 1;
++      txdma_ctrl_mask.bits.td_perr_en = 1;
++      txdma_ctrl_mask.bits.td_eod_en = 1;
++      //txdma_ctrl_mask.bits.td_eod_en = 1;
++      txdma_ctrl_mask.bits.td_eof_en = 1;
++      gmac_write_reg(gmac_base_addr[dev_index] + GMAC_TXDMA_CTRL,txdma_ctrl.bits32,txdma_ctrl_mask.bits32);
++
++    /* program rx dma control register */
++      rxdma_ctrl.bits32 = 0;
++      rxdma_ctrl.bits.rd_start = 1;    /* start RX DMA transfer */
++      rxdma_ctrl.bits.rd_continue = 1; /* continue RX DMA operation */
++      rxdma_ctrl.bits.rd_chain_mode = 1;  /* chain mode */
++      rxdma_ctrl.bits.rd_prot = 0;
++      rxdma_ctrl.bits.rd_burst_size = 2;  /* DMA burst size for every AHB request */
++      rxdma_ctrl.bits.rd_bus = 2;         /* peripheral bus width */
++      rxdma_ctrl.bits.rd_endian = 0;      /* little endian */
++      rxdma_ctrl.bits.rd_finish_en = 1;   /* DMA finish event interrupt enable */
++      rxdma_ctrl.bits.rd_fail_en = 1;     /* DMA fail interrupt enable */
++      rxdma_ctrl.bits.rd_perr_en = 1;     /* protocol failure interrupt enable */
++      rxdma_ctrl.bits.rd_eod_en = 0;      /* disable Rx End of Descriptor Interrupt */
++      rxdma_ctrl.bits.rd_eof_en = 1;      /* end of frame interrupt enable */
++      rxdma_ctrl_mask.bits32 = 0;
++      rxdma_ctrl_mask.bits.rd_start = 1;
++      rxdma_ctrl_mask.bits.rd_continue = 1;
++      rxdma_ctrl_mask.bits.rd_chain_mode = 1;
++      rxdma_ctrl_mask.bits.rd_prot = 15;
++      rxdma_ctrl_mask.bits.rd_burst_size = 3;
++      rxdma_ctrl_mask.bits.rd_bus = 3;
++      rxdma_ctrl_mask.bits.rd_endian = 1;
++      rxdma_ctrl_mask.bits.rd_finish_en = 1;
++      rxdma_ctrl_mask.bits.rd_fail_en = 1;
++      rxdma_ctrl_mask.bits.rd_perr_en = 1;
++      rxdma_ctrl_mask.bits.rd_eod_en = 1;
++      rxdma_ctrl_mask.bits.rd_eof_en = 1;
++      gmac_write_reg(gmac_base_addr[dev_index] + GMAC_RXDMA_CTRL,rxdma_ctrl.bits32,rxdma_ctrl_mask.bits32);
++    return;
++}
++
++static void gmac_hw_stop(struct net_device *dev)
++{
++    GMAC_TXDMA_CTRL_T       txdma_ctrl,txdma_ctrl_mask;
++    GMAC_RXDMA_CTRL_T       rxdma_ctrl,rxdma_ctrl_mask;
++      int                                     dev_index;
++
++    dev_index = gmac_select_interface(dev);
++
++    /* program tx dma control register */
++      txdma_ctrl.bits32 = 0;
++      txdma_ctrl.bits.td_start = 0;
++      txdma_ctrl.bits.td_continue = 0;
++      txdma_ctrl_mask.bits32 = 0;
++      txdma_ctrl_mask.bits.td_start = 1;
++      txdma_ctrl_mask.bits.td_continue = 1;
++      gmac_write_reg(gmac_base_addr[dev_index] + GMAC_TXDMA_CTRL,txdma_ctrl.bits32,txdma_ctrl_mask.bits32);
++    /* program rx dma control register */
++      rxdma_ctrl.bits32 = 0;
++      rxdma_ctrl.bits.rd_start = 0;    /* stop RX DMA transfer */
++      rxdma_ctrl.bits.rd_continue = 0; /* stop continue RX DMA operation */
++      rxdma_ctrl_mask.bits32 = 0;
++      rxdma_ctrl_mask.bits.rd_start = 1;
++      rxdma_ctrl_mask.bits.rd_continue = 1;
++      gmac_write_reg(gmac_base_addr[dev_index] + GMAC_RXDMA_CTRL,rxdma_ctrl.bits32,rxdma_ctrl_mask.bits32);
++}
++
++static int gmac_init_desc_buf(struct net_device *dev)
++{
++      struct gmac_private *tp = dev->priv;
++      struct sk_buff          *skb;
++      dma_addr_t          tx_first_desc_dma=0;
++      dma_addr_t          rx_first_desc_dma=0;
++      dma_addr_t          rx_first_buf_dma=0;
++      unsigned int        i,index;
++
++    printk("Descriptor buffer init......\n");
++
++    /* get device index number */
++    index = gmac_get_dev_index(dev);
++#ifdef CONFIG_SL2312_MPAGE
++      for (i=0; i<TX_DESC_NUM; i++) {
++              tx_skb[index][i].freeable = 0;
++              tx_skb[index][i].skb = 0;
++              tx_skb[index][i].desc_in_use = 0;
++              tx_skb[index][i].end_seq = 0;
++      }
++#else
++    for (i=0;i<TX_DESC_NUM;i++)
++    {
++        tx_skb[index][i] = NULL;
++    }
++#endif
++    for (i=0;i<RX_DESC_NUM;i++)
++    {
++        rx_skb[index][i] = NULL;
++    }
++
++      /* allocates TX/RX descriptors */
++      tp->tx_desc = DMA_MALLOC(TX_DESC_NUM*sizeof(GMAC_DESCRIPTOR_T),(dma_addr_t *)&tp->tx_desc_dma);
++    tx_desc_virtual_base[index] = (unsigned int)tp->tx_desc - (unsigned int)tp->tx_desc_dma;
++    memset(tp->tx_desc,0x00,TX_DESC_NUM*sizeof(GMAC_DESCRIPTOR_T));
++      tp->rx_desc = DMA_MALLOC(RX_DESC_NUM*sizeof(GMAC_DESCRIPTOR_T),(dma_addr_t *)&tp->rx_desc_dma);
++    rx_desc_virtual_base[index] = (unsigned int)tp->rx_desc - (unsigned int)tp->rx_desc_dma;
++    memset(tp->rx_desc,0x00,RX_DESC_NUM*sizeof(GMAC_DESCRIPTOR_T));
++    tx_desc_start_adr[index] = (unsigned int)tp->tx_desc;   /* for tx skb index calculation */
++    rx_desc_start_adr[index] = (unsigned int)tp->rx_desc;   /* for rx skb index calculation */
++    printk("tx_desc = %08x\n",(unsigned int)tp->tx_desc);
++    printk("rx_desc = %08x\n",(unsigned int)tp->rx_desc);
++      printk("tx_desc_dma = %08x\n",tp->tx_desc_dma);
++      printk("rx_desc_dma = %08x\n",tp->rx_desc_dma);
++
++      if (tp->tx_desc==0x00 || tp->rx_desc==0x00)
++      {
++              free_irq(dev->irq, dev);
++
++              if (tp->tx_desc)
++                      DMA_MFREE(tp->tx_desc, TX_DESC_NUM*sizeof(GMAC_DESCRIPTOR_T),tp->tx_desc_dma);
++              if (tp->rx_desc)
++                      DMA_MFREE(tp->rx_desc, RX_DESC_NUM*sizeof(GMAC_DESCRIPTOR_T),tp->rx_desc_dma);
++              return -ENOMEM;
++      }
++
++      /* TX descriptors initial */
++      tp->tx_cur_desc = tp->tx_desc;  /* virtual address */
++      tp->tx_finished_desc = tp->tx_desc; /* virtual address */
++      tx_first_desc_dma = tp->tx_desc_dma; /* physical address */
++      for (i = 1; i < TX_DESC_NUM; i++)
++      {
++              tp->tx_desc->frame_ctrl.bits_tx_out.own = CPU; /* set owner to CPU */
++              tp->tx_desc->frame_ctrl.bits_tx_out.buffer_size = TX_BUF_SIZE;  /* set tx buffer size for descriptor */
++              tp->tx_desc_dma = tp->tx_desc_dma + sizeof(GMAC_DESCRIPTOR_T); /* next tx descriptor DMA address */
++              tp->tx_desc->next_desc.next_descriptor = tp->tx_desc_dma | 0x0000000b;
++              tp->tx_desc = &tp->tx_desc[1] ; /* next tx descriptor virtual address */
++      }
++      /* the last descriptor will point back to first descriptor */
++      tp->tx_desc->frame_ctrl.bits_tx_out.own = CPU;
++      tp->tx_desc->frame_ctrl.bits_tx_out.buffer_size = TX_BUF_SIZE;
++      tp->tx_desc->next_desc.next_descriptor = tx_first_desc_dma | 0x0000000b;
++      tp->tx_desc = tp->tx_cur_desc;
++      tp->tx_desc_dma = tx_first_desc_dma;
++
++      /* RX descriptors initial */
++      tp->rx_cur_desc = tp->rx_desc;  /* virtual address */
++      rx_first_desc_dma = tp->rx_desc_dma; /* physical address */
++      for (i = 1; i < RX_DESC_NUM; i++)
++      {
++        if ( (skb = dev_alloc_skb(RX_BUF_SIZE))==NULL)  /* allocate socket buffer */
++        {
++            printk("%s::skb buffer allocation fail !\n",__func__);
++        }
++        rx_skb[index][i-1] = skb;
++        tp->rx_desc->buf_adr = (unsigned int)__pa(skb->data) | 0x02;    /* insert two bytes in the beginning of rx data */
++              tp->rx_desc->frame_ctrl.bits_rx.own = DMA;  /* set owner bit to DMA */
++              tp->rx_desc->frame_ctrl.bits_rx.buffer_size = RX_BUF_SIZE; /* set rx buffer size for descriptor */
++              tp->rx_bufs_dma = tp->rx_bufs_dma + RX_BUF_SIZE;    /* point to next buffer address */
++              tp->rx_desc_dma = tp->rx_desc_dma + sizeof(GMAC_DESCRIPTOR_T); /* next rx descriptor DMA address */
++              tp->rx_desc->next_desc.next_descriptor = tp->rx_desc_dma | 0x0000000b;
++              tp->rx_desc = &tp->rx_desc[1]; /* next rx descriptor virtual address */
++      }
++      /* the last descriptor will point back to first descriptor */
++    if ( (skb = dev_alloc_skb(RX_BUF_SIZE))==NULL)  /* allocate socket buffer */
++    {
++        printk("%s::skb buffer allocation fail !\n",__func__);
++    }
++    rx_skb[index][i-1] = skb;
++    tp->rx_desc->buf_adr = (unsigned int)__pa(skb->data) | 0x02;    /* insert two bytes in the beginning of rx data */
++      tp->rx_desc->frame_ctrl.bits_rx.own = DMA;
++      tp->rx_desc->frame_ctrl.bits_rx.buffer_size = RX_BUF_SIZE;
++      tp->rx_desc->next_desc.next_descriptor = rx_first_desc_dma | 0x0000000b;
++      tp->rx_desc = tp->rx_cur_desc;
++      tp->rx_desc_dma = rx_first_desc_dma;
++      tp->rx_bufs_dma = rx_first_buf_dma;
++
++      for (i=0; i<GMAC_PHY_IF; i++) {
++              tp->tx_desc_hdr[i] = 0;
++              tp->tx_desc_tail[i] = 0;
++      }
++      return (0);
++}
++
++static int gmac_clear_counter (struct net_device *dev)
++{
++      struct gmac_private *tp = dev->priv;
++      unsigned int    dev_index;
++
++    dev_index = gmac_select_interface(dev);
++//    tp = gmac_dev[index]->priv;
++    /* clear counter */
++    gmac_read_reg(gmac_base_addr[dev_index] + GMAC_IN_DISCARDS);
++    gmac_read_reg(gmac_base_addr[dev_index] + GMAC_IN_ERRORS);
++    tp->stats.tx_bytes = 0;
++    tp->stats.tx_packets = 0;
++      tp->stats.tx_errors = 0;
++    tp->stats.rx_bytes = 0;
++      tp->stats.rx_packets = 0;
++      tp->stats.rx_errors = 0;
++    tp->stats.rx_dropped = 0;
++      return (0);
++}
++
++static int gmac_open (struct net_device *dev)
++{
++      struct gmac_private     *tp = dev->priv;
++      int    retval;
++
++    gmac_select_interface(dev);
++
++      /* chip reset */
++      gmac_sw_reset(dev);
++
++    /* allocates tx/rx descriptor and buffer memory */
++    gmac_init_desc_buf(dev);
++
++    /* get mac address from FLASH */
++    gmac_get_mac_address();
++
++    /* set PHY register to start autonegition process */
++    gmac_set_phy_status(dev);
++
++      /* GMAC initialization */
++      if (gmac_init_chip(dev))
++      {
++              printk (KERN_ERR "GMAC init fail\n");
++      }
++
++    /* start DMA process */
++      gmac_hw_start(dev);
++
++    /* enable tx/rx register */
++    gmac_enable_tx_rx(dev);
++
++    /* clear statistic counter */
++    gmac_clear_counter(dev);
++
++      netif_start_queue (dev);
++
++    /* hook ISR */
++      retval = request_irq (dev->irq, gmac_interrupt, SA_INTERRUPT, dev->name, dev);
++      if (retval)
++              return retval;
++
++      if(!FLAG_SWITCH)
++      {
++      init_waitqueue_head (&tp->thr_wait);
++      init_completion(&tp->thr_exited);
++
++      tp->time_to_die = 0;
++      tp->thr_pid = kernel_thread (gmac_phy_thread, dev, CLONE_FS | CLONE_FILES);
++      if (tp->thr_pid < 0)
++      {
++              printk (KERN_WARNING "%s: unable to start kernel thread\n",dev->name);
++      }
++    }
++      return (0);
++}
++
++static int gmac_close(struct net_device *dev)
++{
++    struct gmac_private *tp = dev->priv;
++    unsigned int        i,dev_index;
++    unsigned int        ret;
++
++    dev_index = gmac_get_dev_index(dev);
++
++    /* stop tx/rx packet */
++    gmac_disable_tx_rx(dev);
++
++    /* stop the chip's Tx and Rx DMA processes */
++      gmac_hw_stop(dev);
++
++    netif_stop_queue(dev);
++
++    /* disable interrupts by clearing the interrupt mask */
++    synchronize_irq();
++    free_irq(dev->irq,dev);
++
++      DMA_MFREE(tp->tx_desc, TX_DESC_NUM*sizeof(GMAC_DESCRIPTOR_T),(unsigned int)tp->tx_desc_dma);
++      DMA_MFREE(tp->rx_desc, RX_DESC_NUM*sizeof(GMAC_DESCRIPTOR_T),(unsigned int)tp->rx_desc_dma);
++
++#ifdef CONFIG_SL2312_MPAGE
++//    kfree(tx_skb);
++#endif
++
++    for (i=0;i<RX_DESC_NUM;i++)
++    {
++        if (rx_skb[dev_index][i])
++        {
++            dev_kfree_skb(rx_skb[dev_index][i]);
++        }
++    }
++      if(!FLAG_SWITCH)
++      {
++      if (tp->thr_pid >= 0)
++      {
++                  tp->time_to_die = 1;
++              wmb();
++              ret = kill_proc (tp->thr_pid, SIGTERM, 1);
++              if (ret)
++              {
++                      printk (KERN_ERR "%s: unable to signal thread\n", dev->name);
++                      return ret;
++              }
++//                    wait_for_completion (&tp->thr_exited);
++      }
++    }
++
++    return (0);
++}
++
++#ifdef CONFIG_SL2312_MPAGE
++int printk_all(int dev_index, struct gmac_private* tp)
++{
++      int i=0;
++    unsigned int tx_current_descriptor = 0;
++    int hw_index;
++    int fi;
++    GMAC_DESCRIPTOR_T* tmp_desc;
++
++      GMAC_DESCRIPTOR_T* cur_desc=tp->tx_cur_desc;
++      fi = ((unsigned int)cur_desc - tx_desc_start_adr[dev_index]) / sizeof(GMAC_DESCRIPTOR_T);
++      printk("tmp_desc %x, id %d\n", (int)cur_desc, fi);
++
++      tmp_desc = (GMAC_DESCRIPTOR_T*)((gmac_read_reg(gmac_base_addr[dev_index] + GMAC_TXDMA_CURR_DESC) & 0xfffffff0) + tx_desc_virtual_base[dev_index]);
++      hw_index = ((unsigned int)tmp_desc - tx_desc_start_adr[dev_index])/ sizeof(GMAC_DESCRIPTOR_T);
++      printk("hd_desc %x, ind %d, fin desc %x\n",(int)tmp_desc, hw_index, (int)tp->tx_finished_desc);
++
++      for (i=0; i<TX_DESC_NUM; i++) {
++              printk("**id %4d, hw_index %4d ==> ", fi, hw_index);
++              printk("fc %8x ", tmp_desc->frame_ctrl.bits32);
++              printk("fs %8x ", tmp_desc->flag_status.bits32);
++              printk("fb %8x ", tmp_desc->buf_adr);
++              printk("fd %8x\n",  tmp_desc->next_desc.next_descriptor);
++              tmp_desc = (GMAC_DESCRIPTOR_T*)((tmp_desc->next_desc.next_descriptor & 0xfffffff0) + tx_desc_virtual_base[dev_index]);
++              fi = ((unsigned int)tmp_desc - tx_desc_start_adr[dev_index]) / sizeof(GMAC_DESCRIPTOR_T);
++      }
++    tx_current_descriptor = gmac_read_reg(gmac_base_addr[dev_index] + GMAC_TXDMA_CURR_DESC);
++    printk("%s: tx current descriptor = %x \n",__func__,tx_current_descriptor);
++    printk("%s: interrupt status = %x \n",__func__,int_status);
++    return 0;
++}
++
++int cleanup_desc(int dev_index, struct gmac_private* tp)
++{
++      int i=0;
++      int index = ((unsigned int)tp->tx_cur_desc - tx_desc_start_adr[dev_index])/sizeof(GMAC_DESCRIPTOR_T);
++      GMAC_DESCRIPTOR_T* fill_desc = tp->tx_cur_desc;
++
++      for (i=0; i< TX_DESC_NUM; i++)
++      {
++              fill_desc->frame_ctrl.bits_tx_out.own = CPU;
++              fill_desc->frame_ctrl.bits_tx_out.buffer_size = TX_BUF_SIZE;
++              tx_skb[dev_index][index].desc_in_use = 0;
++              free_tx_buf(dev_index, index);
++              printk("cleanup di %d\n", index);
++              fill_desc = (GMAC_DESCRIPTOR_T*)((fill_desc->next_desc.next_descriptor & 0xfffffff0) + tx_desc_virtual_base[dev_index]);
++              index++;
++              if (index > TX_DESC_NUM)
++                      index = 0;
++      }
++      return 1;
++}
++
++size_t get_available_tx_desc(struct net_device* dev, int dev_index)
++{
++      struct gmac_private *tp = dev->priv;
++      unsigned int desc_hdr = tp->tx_desc_hdr[dev_index];
++      unsigned int desc_tail = tp->tx_desc_tail[dev_index];
++      int available_desc_num = (TX_DESC_NUM - desc_hdr + desc_tail) & (TX_DESC_NUM-1);
++      if (!available_desc_num) {
++              if (tx_skb[dev_index][desc_hdr].desc_in_use)
++                      return 0;
++              else
++                      return TX_DESC_NUM;
++      }
++      return available_desc_num;
++}
++
++int check_free_tx_desc(int dev_index, int n, GMAC_DESCRIPTOR_T* desc)
++{
++      int i,index;
++      GMAC_DESCRIPTOR_T* tmp_desc = desc;
++
++      if (n > TX_DESC_NUM)
++              return 0;
++
++      index = ((unsigned int)tmp_desc - tx_desc_start_adr[dev_index])/sizeof(GMAC_DESCRIPTOR_T);
++      for (i=0; i<n; i++)
++      {
++              if (tx_skb[dev_index][index].desc_in_use)
++              {
++                      printk("sw desc %d is in use\n", index);
++                      /* cleanup all the descriptors to check if DMA still running */
++                      return 0;
++              }
++              index++;
++              if (index == TX_DESC_NUM)
++                      index = 0;
++      }
++      return 1;
++}
++
++#define TCPHDRLEN(tcp_hdr)  ((ntohs(*((__u16 *)tcp_hdr + 6)) >> 12) & 0x000F)
++
++inline int fill_in_desc(int dev_index, GMAC_DESCRIPTOR_T *desc, char* data, int len, int total_len, int sof, int freeable, int ownership, struct sk_buff* skb)
++{
++      int index = ((unsigned int)desc - tx_desc_start_adr[dev_index]) / sizeof(GMAC_DESCRIPTOR_T);
++
++      if (desc->frame_ctrl.bits_tx_in.own == CPU)
++      {
++              tx_skb[dev_index][index].freeable = freeable;
++              if ((sof & 0x01) && skb) {
++                      tx_skb[dev_index][index].skb = skb;
++              }
++              else
++                      tx_skb[dev_index][index].skb = 0;
++
++              if (sof != 2)
++                      tx_skb[dev_index][index].desc_in_use = 1;
++              else
++                      tx_skb[dev_index][index].desc_in_use = 0;
++
++              consistent_sync(data, len, PCI_DMA_TODEVICE);
++              desc->buf_adr = (unsigned int)__pa(data);
++              desc->frame_ctrl.bits_tx_out.buffer_size = len;
++              desc->flag_status.bits_tx_flag.frame_count = total_len;
++              desc->next_desc.bits.eofie = 1;
++              desc->next_desc.bits.sof_eof = sof;
++              desc->frame_ctrl.bits_tx_out.vlan_enable = 0;
++              desc->frame_ctrl.bits_tx_out.ip_csum_en = 1;     /* TSS IPv4 IP header checksum enable */
++              desc->frame_ctrl.bits_tx_out.ipv6_tx_en = 1;    /* TSS IPv6 tx enable */
++              desc->frame_ctrl.bits_tx_out.tcp_csum_en = 1;    /* TSS TCP checksum enable */
++              desc->frame_ctrl.bits_tx_out.udp_csum_en = 1;    /* TSS UDP checksum enable */
++        wmb();
++              desc->frame_ctrl.bits_tx_out.own = ownership;
++//            consistent_sync(desc, sizeof(GMAC_DESCRIPTOR_T), PCI_DMA_TODEVICE);
++      }
++      return 0;
++}
++#endif
++
++static int gmac_start_xmit(struct sk_buff *skb, struct net_device *dev)
++{
++      struct gmac_private     *tp = dev->priv;
++      GMAC_TXDMA_CTRL_T               tx_ctrl,tx_ctrl_mask;
++      GMAC_TXDMA_FIRST_DESC_T txdma_busy;
++      unsigned int            len = skb->len;
++      unsigned int            dev_index;
++      static unsigned int     pcount = 0;
++#ifdef CONFIG_SL2312_MPAGE
++    GMAC_DESCRIPTOR_T *fill_desc;
++      int snd_pages = skb_shinfo(skb)->nr_frags;  /* get number of descriptor */
++      int desc_needed = 1; // for jumbo packet, one descriptor is enough.
++      int header_len = skb->len;
++    struct iphdr      *ip_hdr;
++    struct tcphdr     *tcp_hdr;
++    int             tcp_hdr_len;
++    int             data_len;
++    int             prv_index;
++    long            seq_num;
++    int             first_desc_index;
++    int             ownership, freeable;
++    int             eof;
++      int             i=0;
++#endif
++#ifdef CONFIG_TXINT_DISABLE
++      int                             available_desc_cnt = 0;
++#endif
++
++    dev_index = gmac_select_interface(dev);
++
++#ifdef CONFIG_TXINT_DISABLE
++      available_desc_cnt = get_available_tx_desc(dev, dev_index);
++
++      if (available_desc_cnt < (TX_DESC_NUM >> 2)) {
++              gmac_tx_packet_complete(dev);
++      }
++#endif
++
++#ifdef CONFIG_SL2312_MPAGE
++
++      fill_desc = tp->tx_cur_desc;
++      if(!fill_desc) {
++              printk("cur_desc is NULL!\n");
++              return -1;
++      }
++
++      if (storlink_ctl.recvfile==2)
++      {
++          printk("snd_pages=%d skb->len=%d\n",snd_pages,skb->len);
++      }
++
++      if (snd_pages)
++              desc_needed += snd_pages;   /* decriptors needed for this large packet */
++
++      if (!check_free_tx_desc(dev_index, desc_needed, fill_desc)) {
++              printk("no available desc!\n");
++        gmac_dump_register(dev);
++              printk_all(dev_index, tp);
++              tp->stats.tx_dropped++;
++              if (pcount++ > 10)
++              {
++                  for (;;);
++              }
++              return -1;
++      }
++
++      first_desc_index = ((unsigned int)fill_desc - tx_desc_start_adr[dev_index]) / sizeof(GMAC_DESCRIPTOR_T);
++
++      /* check if the tcp packet is in order*/
++      ip_hdr = (struct iphdr*) &(skb->data[14]);
++      tcp_hdr = (struct tcphdr*) &(skb->data[14+ip_hdr->ihl * 4]);
++      tcp_hdr_len = TCPHDRLEN(tcp_hdr) * 4;
++      data_len = skb->len - 14 - ip_hdr->ihl *4 - tcp_hdr_len;
++
++      prv_index = first_desc_index-1;
++      if (prv_index <0)
++          prv_index += TX_DESC_NUM;
++      seq_num = ntohl(tcp_hdr->seq);
++
++      if (snd_pages)
++      {
++              // calculate header length
++              // check fragment total length and header len = skb len - frag len
++              // or parse the header.
++              for (i=0; i<snd_pages; i++) {
++                      skb_frag_t* frag = &skb_shinfo(skb)->frags[i];
++                      header_len -= frag->size;
++              }
++              ownership = CPU;
++              freeable = 0;
++              /* fill header into first descriptor */
++              fill_in_desc(dev_index, fill_desc, skb->data, header_len, len, 2, freeable, ownership, 0);
++              fill_desc = (GMAC_DESCRIPTOR_T*)((fill_desc->next_desc.next_descriptor & 0xfffffff0) + tx_desc_virtual_base[dev_index]);
++              tx_skb[dev_index][first_desc_index].end_seq = seq_num + data_len;
++
++              eof = 0;
++              ownership = DMA;
++              for (i=0; i<snd_pages; i++)
++              {
++                      skb_frag_t* frag = &skb_shinfo(skb)->frags[i];
++                      int start_pos = frag->page_offset;
++                      char* data_buf = page_address(frag->page);
++                      int data_size = frag->size;
++                      int cur_index;
++
++                      if (i == snd_pages-1)
++                      {
++                              eof=1;
++                              freeable = 1;
++                      }
++                      fill_in_desc(dev_index, fill_desc, data_buf+(start_pos), data_size,
++                                   len, eof, freeable, ownership, skb);
++                      cur_index = ((unsigned int)fill_desc - tx_desc_start_adr[dev_index]) / sizeof(GMAC_DESCRIPTOR_T);
++
++                      fill_desc = (GMAC_DESCRIPTOR_T*)((fill_desc->next_desc.next_descriptor & 0xfffffff0) + tx_desc_virtual_base[dev_index]);
++              }
++              /* pass the ownership of the first descriptor to hardware */
++//        disable_irq(gmac_irq[dev_index]);
++              tx_skb[dev_index][first_desc_index].desc_in_use = 1;
++        wmb();
++              tp->tx_cur_desc->frame_ctrl.bits_tx_out.own = DMA;
++//            consistent_sync(tp->tx_cur_desc, sizeof(GMAC_DESCRIPTOR_T), PCI_DMA_TODEVICE);
++              tp->tx_cur_desc = fill_desc;
++              dev->trans_start = jiffies;
++//        enable_irq(gmac_irq[dev_index]);
++      }
++      else if ( tp->tx_cur_desc->frame_ctrl.bits_tx_out.own == CPU )
++      {
++//            tx_skb[dev_index][first_desc_index].end_seq = seq_num + data_len;
++//        disable_irq(gmac_irq[dev_index]);
++              fill_in_desc(dev_index, tp->tx_cur_desc, skb->data, skb->len, skb->len, 3, 1, DMA, skb);
++//        enable_irq(gmac_irq[dev_index]);
++              //consistent_sync(tp->tx_cur_desc, sizeof(GMAC_DESCRIPTOR_T), PCI_DMA_TODEVICE);
++              tp->tx_cur_desc = (GMAC_DESCRIPTOR_T*)((tp->tx_cur_desc->next_desc.next_descriptor & 0xfffffff0) + tx_desc_virtual_base[dev_index]);
++              dev->trans_start = jiffies;
++      }
++      else
++      {
++              printk("gmac tx drop!\n");
++              tp->stats.tx_dropped++;
++              return -1;
++      }
++
++#ifdef CONFIG_TXINT_DISABLE
++      tp->tx_desc_hdr[dev_index] = (tp->tx_desc_hdr[dev_index] + desc_needed) & (TX_DESC_NUM-1);
++#endif
++
++#else
++    if ((tp->tx_cur_desc->frame_ctrl.bits_tx_out.own == CPU) && (len < TX_BUF_SIZE))
++      {
++        index = ((unsigned int)tp->tx_cur_desc - tx_desc_start_adr[dev_index]) / sizeof(GMAC_DESCRIPTOR_T);
++        tx_skb[dev_index][index] = skb;
++        consistent_sync(skb->data,skb->len,PCI_DMA_TODEVICE);
++        tp->tx_cur_desc->buf_adr = (unsigned int)__pa(skb->data);
++      tp->tx_cur_desc->flag_status.bits_tx_flag.frame_count = len;    /* total frame byte count */
++      tp->tx_cur_desc->next_desc.bits.sof_eof = 0x03;                 /*only one descriptor*/
++              tp->tx_cur_desc->frame_ctrl.bits_tx_out.buffer_size = len;      /* descriptor byte count */
++        tp->tx_cur_desc->frame_ctrl.bits_tx_out.vlan_enable = 0;
++        tp->tx_cur_desc->frame_ctrl.bits_tx_out.ip_csum_en = 0;     /* TSS IPv4 IP header checksum enable */
++        tp->tx_cur_desc->frame_ctrl.bits_tx_out.ipv6_tx_en = 0 ;    /* TSS IPv6 tx enable */
++        tp->tx_cur_desc->frame_ctrl.bits_tx_out.tcp_csum_en = 0;    /* TSS TCP checksum enable */
++        tp->tx_cur_desc->frame_ctrl.bits_tx_out.udp_csum_en = 0;    /* TSS UDP checksum enable */
++        wmb();
++      tp->tx_cur_desc->frame_ctrl.bits_tx_out.own = DMA;              /* set owner bit */
++      tp->tx_cur_desc = (GMAC_DESCRIPTOR_T *)((tp->tx_cur_desc->next_desc.next_descriptor & 0xfffffff0)+tx_desc_virtual_base[dev_index]);
++      dev->trans_start = jiffies;
++      }
++      else
++      {
++              /* no free tx descriptor */
++              dev_kfree_skb(skb);
++          netif_stop_queue(dev);
++              tp->stats.tx_dropped++;
++              return (-1);
++      }
++#endif
++      /* if TX DMA process is stoped , restart it */
++      txdma_busy.bits32 = gmac_read_reg(gmac_base_addr[dev_index] + GMAC_TXDMA_FIRST_DESC);
++      if (txdma_busy.bits.td_busy == 0)
++      {
++              /* restart DMA process */
++              tx_ctrl.bits32 = 0;
++              tx_ctrl.bits.td_start = 1;
++              tx_ctrl.bits.td_continue = 1;
++              tx_ctrl_mask.bits32 = 0;
++              tx_ctrl_mask.bits.td_start = 1;
++              tx_ctrl_mask.bits.td_continue = 1;
++              gmac_write_reg(gmac_base_addr[dev_index] + GMAC_TXDMA_CTRL,tx_ctrl.bits32,tx_ctrl_mask.bits32);
++      }
++      return (0);
++}
++
++
++struct net_device_stats * gmac_get_stats(struct net_device *dev)
++{
++    struct gmac_private *tp = dev->priv;
++    unsigned long       flags;
++    unsigned int        pkt_drop;
++    unsigned int        pkt_error;
++    unsigned int        dev_index;
++
++    dev_index = gmac_select_interface(dev);
++
++//    if (storlink_ctl.recvfile==3)
++//    {
++//        printk("GMAC_GLOBAL_BASE_ADDR=%x\n", readl(GMAC_GLOBAL_BASE_ADDR+0x30));
++//        gmac_dump_register(dev);
++//        printk_all(0, dev);
++//    }
++
++    if (netif_running(dev))
++    {
++        /* read H/W counter */
++        spin_lock_irqsave(&tp->lock,flags);
++        pkt_drop = gmac_read_reg(gmac_base_addr[dev_index] + GMAC_IN_DISCARDS);
++        pkt_error = gmac_read_reg(gmac_base_addr[dev_index] + GMAC_IN_ERRORS);
++        tp->stats.rx_dropped = tp->stats.rx_dropped + pkt_drop;
++        tp->stats.rx_errors = tp->stats.rx_errors + pkt_error;
++        spin_unlock_irqrestore(&tp->lock,flags);
++    }
++    return &tp->stats;
++}
++
++static unsigned const ethernet_polynomial = 0x04c11db7U;
++static inline u32 ether_crc (int length, unsigned char *data)
++{
++      int crc = -1;
++      unsigned int i;
++      unsigned int crc_val=0;
++
++      while (--length >= 0) {
++              unsigned char current_octet = *data++;
++              int bit;
++              for (bit = 0; bit < 8; bit++, current_octet >>= 1)
++                      crc = (crc << 1) ^ ((crc < 0) ^ (current_octet & 1) ?
++                           ethernet_polynomial : 0);
++      }
++      crc = ~crc;
++      for (i=0;i<32;i++)
++      {
++              crc_val = crc_val + (((crc << i) & 0x80000000) >> (31-i));
++      }
++      return crc_val;
++}
++
++static void gmac_set_rx_mode(struct net_device *dev)
++{
++    GMAC_RX_FLTR_T      filter;
++      unsigned int        mc_filter[2];       /* Multicast hash filter */
++    int                 bit_nr;
++      unsigned int        i, dev_index;
++
++    dev_index = gmac_select_interface(dev);
++
++//    printk("%s : dev->flags = %x \n",__func__,dev->flags);
++//    dev->flags |= IFF_ALLMULTI;  /* temp */
++    filter.bits32 = 0;
++    filter.bits.error = 0;
++      if (dev->flags & IFF_PROMISC)
++      {
++          filter.bits.error = 1;
++        filter.bits.promiscuous = 1;
++        filter.bits.broadcast = 1;
++        filter.bits.multicast = 1;
++        filter.bits.unicast = 1;
++              mc_filter[1] = mc_filter[0] = 0xffffffff;
++      }
++      else if (dev->flags & IFF_ALLMULTI)
++      {
++        filter.bits.promiscuous = 1;
++        filter.bits.broadcast = 1;
++        filter.bits.multicast = 1;
++        filter.bits.unicast = 1;
++              mc_filter[1] = mc_filter[0] = 0xffffffff;
++      }
++      else
++      {
++              struct dev_mc_list *mclist;
++
++        filter.bits.promiscuous = 1;
++        filter.bits.broadcast = 1;
++        filter.bits.multicast = 1;
++        filter.bits.unicast = 1;
++              mc_filter[1] = mc_filter[0] = 0;
++              for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;i++, mclist = mclist->next)
++              {
++            bit_nr = ether_crc(ETH_ALEN,mclist->dmi_addr) & 0x0000003f;
++            if (bit_nr < 32)
++            {
++                mc_filter[0] = mc_filter[0] | (1<<bit_nr);
++            }
++            else
++            {
++                mc_filter[1] = mc_filter[1] | (1<<(bit_nr-32));
++            }
++              }
++      }
++    filter.bits32 = 0x1f;
++    gmac_write_reg(gmac_base_addr[dev_index] + GMAC_RX_FLTR,filter.bits32,0xffffffff);
++
++    gmac_write_reg(gmac_base_addr[dev_index] + GMAC_MCAST_FIL0,mc_filter[0],0xffffffff);
++    gmac_write_reg(gmac_base_addr[dev_index] + GMAC_MCAST_FIL1,mc_filter[1],0xffffffff);
++    return;
++}
++
++static int gmac_set_mac_address(struct net_device *dev, void *addr)
++{
++      struct sockaddr *sock;
++      unsigned int    reg_val;
++      unsigned int    dev_index;
++    unsigned int    i;
++
++    dev_index = gmac_select_interface(dev);
++
++      sock = (struct sockaddr *) addr;
++      for (i = 0; i < 6; i++)
++      {
++              dev->dev_addr[i] = sock->sa_data[i];
++      }
++
++    reg_val = dev->dev_addr[0] + (dev->dev_addr[1]<<8) + (dev->dev_addr[2]<<16) + (dev->dev_addr[3]<<24);
++    gmac_write_reg(gmac_base_addr[dev_index] + GMAC_STA_ADD0,reg_val,0xffffffff);
++    reg_val = dev->dev_addr[4] + (dev->dev_addr[5]<<8) ;
++    gmac_write_reg(gmac_base_addr[dev_index] + GMAC_STA_ADD1,reg_val,0x0000ffff);
++    memcpy(&eth0_mac[0],&dev->dev_addr[0],6);
++    printk("Storlink %s address = ",dev->name);
++    printk("%02x",dev->dev_addr[0]);
++    printk("%02x",dev->dev_addr[1]);
++    printk("%02x",dev->dev_addr[2]);
++    printk("%02x",dev->dev_addr[3]);
++    printk("%02x",dev->dev_addr[4]);
++    printk("%02x\n",dev->dev_addr[5]);
++
++    return (0);
++}
++
++static void gmac_tx_timeout(struct net_device *dev)
++{
++      GMAC_TXDMA_CTRL_T               tx_ctrl,tx_ctrl_mask;
++    GMAC_TXDMA_FIRST_DESC_T     txdma_busy;
++    int                                                       dev_index;
++
++    dev_index = gmac_select_interface(dev);
++
++    /* if TX DMA process is stoped , restart it */
++      txdma_busy.bits32 = gmac_read_reg(gmac_base_addr[dev_index] + GMAC_TXDMA_FIRST_DESC);
++      if (txdma_busy.bits.td_busy == 0)
++      {
++              /* restart DMA process */
++              tx_ctrl.bits32 = 0;
++              tx_ctrl.bits.td_start = 1;
++              tx_ctrl.bits.td_continue = 1;
++              tx_ctrl_mask.bits32 = 0;
++              tx_ctrl_mask.bits.td_start = 1;
++              tx_ctrl_mask.bits.td_continue = 1;
++              gmac_write_reg(gmac_base_addr[dev_index] + GMAC_TXDMA_CTRL,tx_ctrl.bits32,tx_ctrl_mask.bits32);
++      }
++      netif_wake_queue(dev);
++    return;
++}
++
++static int gmac_netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
++{
++      int rc = 0;
++    unsigned char *hwa = rq->ifr_ifru.ifru_hwaddr.sa_data;
++
++      if (!netif_running(dev))
++      {
++          printk("Before changing the H/W address,please down the device.\n");
++              return -EINVAL;
++    }
++
++      switch (cmd) {
++      case SIOCETHTOOL:
++        break;
++
++    case SIOCSIFHWADDR:
++        gmac_set_mac_address(dev,hwa);
++        break;
++
++      case SIOCGMIIPHY:       /* Get the address of the PHY in use. */
++      case SIOCDEVPRIVATE:    /* binary compat, remove in 2.5 */
++        break;
++
++      case SIOCGMIIREG:       /* Read the specified MII register. */
++      case SIOCDEVPRIVATE+1:
++              break;
++
++      case SIOCSMIIREG:       /* Write the specified MII register */
++      case SIOCDEVPRIVATE+2:
++              break;
++
++      default:
++              rc = -EOPNOTSUPP;
++              break;
++      }
++
++      return rc;
++}
++
++static void gmac_cleanup_module(void)
++{
++    int i;
++
++    for (i=0;i<GMAC_PHY_IF;i++)
++    {
++        unregister_netdev(gmac_dev[i]);
++    }
++      return ;
++}
++
++static int __init gmac_init_module(void)
++{
++      struct gmac_private *tp;
++      struct net_device *dev[GMAC_PHY_IF];
++      unsigned int i;
++
++#ifdef MODULE
++      printk (KERN_INFO RTL8139_DRIVER_NAME "\n");
++#endif
++//    init_waitqueue_entry(&wait, current);
++
++      printk("GMAC Init......\n");
++      for(i = 0; i<GMAC_PHY_IF; i++)
++      {
++              dev[i] = alloc_etherdev(sizeof(struct gmac_private));
++              if (dev[i] == NULL)
++              {
++                      printk (KERN_ERR "Can't allocate ethernet device #%d .\n",i);
++                      return -ENOMEM;
++              }
++        gmac_dev[i] = dev[i];
++
++              SET_MODULE_OWNER(dev[i]);
++
++              tp = dev[i]->priv;
++
++              dev[i]->base_addr = gmac_base_addr[i];
++              dev[i]->irq = gmac_irq[i];
++          dev[i]->open = gmac_open;
++          dev[i]->stop = gmac_close;
++              dev[i]->hard_start_xmit = gmac_start_xmit;
++              dev[i]->get_stats = gmac_get_stats;
++              dev[i]->set_multicast_list = gmac_set_rx_mode;
++              dev[i]->set_mac_address = gmac_set_mac_address;
++              dev[i]->do_ioctl = gmac_netdev_ioctl;
++              dev[i]->tx_timeout = gmac_tx_timeout;
++              dev[i]->watchdog_timeo = TX_TIMEOUT;
++              dev[i]->features |= NETIF_F_SG|NETIF_F_HW_CSUM|NETIF_F_TSO;
++#ifdef CONFIG_SL_NAPI
++        printk("NAPI driver is enabled.\n");
++        if (i==0)
++        {
++              dev[i]->poll = gmac_rx_poll_ga;
++              dev[i]->weight = 64;
++          }
++          else
++          {
++              dev[i]->poll = gmac_rx_poll_gb;
++              dev[i]->weight = 64;
++          }
++#endif
++
++              if (register_netdev(dev[i]))
++              {
++                      gmac_cleanup_module();
++                      return(-1);
++              }
++      }
++
++#ifdef CONFIG_SL3516_ASIC
++{
++    unsigned int    val;
++
++    /* set GMAC global register */
++    val = readl(GMAC_GLOBAL_BASE_ADDR+0x10);
++    val = val | 0x005a0000;
++    writel(val,GMAC_GLOBAL_BASE_ADDR+0x10);
++    writel(0x07f007f0,GMAC_GLOBAL_BASE_ADDR+0x1c);
++    writel(0x77770000,GMAC_GLOBAL_BASE_ADDR+0x20);
++    writel(0x77770000,GMAC_GLOBAL_BASE_ADDR+0x24);
++      val = readl(GMAC_GLOBAL_BASE_ADDR+0x04);
++      if((val&(1<<20))==0){           // GMAC1 enable
++              val = readl(GMAC_GLOBAL_BASE_ADDR+0x30);
++              val = (val & 0xe7ffffff) | 0x08000000;
++              writel(val,GMAC_GLOBAL_BASE_ADDR+0x30);
++      }
++
++}
++#endif
++
++//    printk("%s: dev0=%x  dev1=%x \n",__func__,dev[0],dev[1]);
++//    FLAG_SWITCH = 0 ;
++//    FLAG_SWITCH = SPI_get_identifier();
++//    if(FLAG_SWITCH)
++//    {
++//            printk("Configure ADM699X...\n");
++//            SPI_default();  //Add by jason for ADM699X configuration
++//    }
++      return (0);
++}
++
++
++module_init(gmac_init_module);
++module_exit(gmac_cleanup_module);
++
++static int gmac_phy_thread (void *data)
++{
++      struct net_device   *dev = data;
++      struct gmac_private *tp = dev->priv;
++      unsigned long       timeout;
++
++    daemonize("%s", dev->name);
++      allow_signal(SIGTERM);
++//    reparent_to_init();
++//    spin_lock_irq(&current->sigmask_lock);
++//    sigemptyset(&current->blocked);
++//    recalc_sigpending(current);
++//    spin_unlock_irq(&current->sigmask_lock);
++//    strncpy (current->comm, dev->name, sizeof(current->comm) - 1);
++//    current->comm[sizeof(current->comm) - 1] = '\0';
++
++      while (1)
++      {
++          timeout = next_tick;
++              do
++              {
++                      timeout = interruptible_sleep_on_timeout (&tp->thr_wait, timeout);
++              } while (!signal_pending (current) && (timeout > 0));
++
++              if (signal_pending (current))
++              {
++//                    spin_lock_irq(&current->sigmask_lock);
++                      flush_signals(current);
++//                    spin_unlock_irq(&current->sigmask_lock);
++              }
++
++              if (tp->time_to_die)
++                      break;
++
++//        printk("%s : Polling PHY Status...%x\n",__func__,dev);
++              rtnl_lock ();
++        gmac_get_phy_status(dev);
++              rtnl_unlock ();
++      }
++      complete_and_exit (&tp->thr_exited, 0);
++}
++
++static void gmac_set_phy_status(struct net_device *dev)
++{
++    GMAC_STATUS_T   status;
++    unsigned int    reg_val;
++    unsigned int    i = 0;
++    unsigned int    index;
++
++    if (FLAG_SWITCH==1)
++    {
++        return; /* GMAC connects to a switch chip, not PHY */
++    }
++
++    index = gmac_get_dev_index(dev);
++
++    if (index == 0)
++    {
++//            mii_write(phy_addr[index],0x04,0x0461); /* advertisement 10M full duplex, pause capable on */
++//            mii_write(phy_addr[index],0x04,0x0421); /* advertisement 10M half duplex, pause capable on */
++      mii_write(phy_addr[index],0x04,0x05e1); /* advertisement 100M full duplex, pause capable on */
++//            mii_write(phy_addr[index],0x04,0x04a1); /* advertisement 100M half duplex, pause capable on */
++#ifdef CONFIG_SL3516_ASIC
++      mii_write(phy_addr[index],0x09,0x0300); /* advertisement 1000M full duplex, pause capable on */
++//            mii_write(phy_addr[index],0x09,0x0000); /* advertisement 1000M full duplex, pause capable on */
++#endif
++    }
++    else
++    {
++//            mii_write(phy_addr[index],0x04,0x0461); /* advertisement 10M full duplex, pause capable on */
++//            mii_write(phy_addr[index],0x04,0x0421); /* advertisement 10M half duplex, pause capable on */
++      mii_write(phy_addr[index],0x04,0x05e1); /* advertisement 100M full duplex, pause capable on */
++//            mii_write(phy_addr[index],0x04,0x04a1); /* advertisement 100M half duplex, pause capable on */
++#ifdef CONFIG_SL3516_ASIC
++//            mii_write(phy_addr[index],0x09,0x0000); /* advertisement no 1000M */
++      mii_write(phy_addr[index],0x09,0x0300); /* advertisement 1000M full duplex, pause capable on */
++#endif
++      }
++
++    mii_write(phy_addr[index],0x00,0x1200); /* Enable and Restart Auto-Negotiation */
++    mii_write(phy_addr[index],0x18,0x0041); /* Enable Active led */
++    while (((reg_val=mii_read(phy_addr[index],0x01)) & 0x00000004)!=0x04)
++    {
++        i++;
++        if (i > 30)
++        {
++            break;
++        }
++      msleep(100);
++    }
++    if (i>30)
++    {
++        pre_phy_status[index] = LINK_DOWN;
++              clear_bit(__LINK_STATE_START, &dev->state);
++        netif_stop_queue(dev);
++        storlink_ctl.link = 0;
++        printk("Link Down (%04x) ",reg_val);
++    }
++    else
++    {
++        pre_phy_status[index] = LINK_UP;
++              set_bit(__LINK_STATE_START, &dev->state);
++        netif_wake_queue(dev);
++        storlink_ctl.link = 1;
++        printk("Link Up (%04x) ",reg_val);
++    }
++
++    status.bits32 = 0;
++    reg_val = mii_read(phy_addr[index],10);
++    printk("reg_val0 = %x \n",reg_val);
++    if ((reg_val & 0x0800) == 0x0800)
++    {
++        status.bits.duplex = 1;
++        status.bits.speed = 2;
++        printk(" 1000M/Full \n");
++    }
++    else if ((reg_val & 0x0400) == 0x0400)
++    {
++        status.bits.duplex = 0;
++        status.bits.speed = 2;
++        printk(" 1000M/Half \n");
++    }
++    else
++    {
++        reg_val = (mii_read(phy_addr[index],0x05) & 0x05E0) >> 5;
++        printk("reg_val1 = %x \n",reg_val);
++        if ((reg_val & 0x08)==0x08) /* 100M full duplex */
++        {
++                status.bits.duplex = 1;
++                status.bits.speed = 1;
++                printk(" 100M/Full \n");
++        }
++        else if ((reg_val & 0x04)==0x04) /* 100M half duplex */
++        {
++                status.bits.duplex = 0;
++                status.bits.speed = 1;
++                printk(" 100M/Half \n");
++        }
++        else if ((reg_val & 0x02)==0x02) /* 10M full duplex */
++        {
++                status.bits.duplex = 1;
++                status.bits.speed = 0;
++                printk(" 10M/Full \n");
++        }
++        else if ((reg_val & 0x01)==0x01) /* 10M half duplex */
++        {
++                status.bits.duplex = 0;
++                status.bits.speed = 0;
++                printk(" 100M/Half \n");
++        }
++    }
++
++    reg_val = (mii_read(phy_addr[index],0x05) & 0x05E0) >> 5;
++    if ((reg_val & 0x20)==0x20)
++    {
++        flow_control_enable[index] = 1;
++        printk("Flow Control Enable. \n");
++    }
++    else
++    {
++        flow_control_enable[index] = 0;
++        printk("Flow Control Disable. \n");
++    }
++    full_duplex = status.bits.duplex;
++    speed = status.bits.speed;
++}
++
++static void gmac_get_phy_status(struct net_device *dev)
++{
++      GMAC_CONFIG0_T  config0,config0_mask;
++    GMAC_STATUS_T   status;
++    unsigned int    reg_val;
++    unsigned int    index;
++
++    index = gmac_select_interface(dev);
++
++    status.bits32 = 0;
++    status.bits.phy_mode = 1;
++
++#ifdef CONFIG_SL3516_ASIC
++    status.bits.mii_rmii = 2;   /* default value for ASIC version */
++//    status.bits.speed = 1;
++#else
++    if (index==0)
++        status.bits.mii_rmii = 0;
++    else
++        status.bits.mii_rmii = 2;
++#endif
++
++    /* read PHY status register */
++    reg_val = mii_read(phy_addr[index],0x01);
++    if ((reg_val & 0x0024) == 0x0024) /* link is established and auto_negotiate process completed */
++    {
++        /* read PHY Auto-Negotiation Link Partner Ability Register */
++        reg_val = mii_read(phy_addr[index],10);
++        if ((reg_val & 0x0800) == 0x0800)
++        {
++            status.bits.mii_rmii = 3;  /* RGMII 1000Mbps mode */
++            status.bits.duplex = 1;
++            status.bits.speed = 2;
++        }
++        else if ((reg_val & 0x0400) == 0x0400)
++        {
++            status.bits.mii_rmii = 3;  /* RGMII 1000Mbps mode */
++            status.bits.duplex = 0;
++            status.bits.speed = 2;
++        }
++        else
++        {
++            reg_val = (mii_read(phy_addr[index],0x05) & 0x05E0) >> 5;
++            if ((reg_val & 0x08)==0x08) /* 100M full duplex */
++            {
++                    status.bits.mii_rmii = 2;  /* RGMII 10/100Mbps mode */
++                    status.bits.duplex = 1;
++                    status.bits.speed = 1;
++            }
++            else if ((reg_val & 0x04)==0x04) /* 100M half duplex */
++            {
++                    status.bits.mii_rmii = 2;  /* RGMII 10/100Mbps mode */
++                    status.bits.duplex = 0;
++                    status.bits.speed = 1;
++            }
++            else if ((reg_val & 0x02)==0x02) /* 10M full duplex */
++            {
++                    status.bits.mii_rmii = 2;  /* RGMII 10/100Mbps mode */
++                    status.bits.duplex = 1;
++                    status.bits.speed = 0;
++            }
++            else if ((reg_val & 0x01)==0x01) /* 10M half duplex */
++            {
++                    status.bits.mii_rmii = 2;  /* RGMII 10/100Mbps mode */
++                    status.bits.duplex = 0;
++                    status.bits.speed = 0;
++            }
++        }
++        status.bits.link = LINK_UP; /* link up */
++        netif_wake_queue(dev);
++
++        reg_val = (mii_read(phy_addr[index],0x05) & 0x05E0) >> 5;
++        if ((reg_val & 0x20)==0x20)
++        {
++            if (flow_control_enable[index] == 0)
++            {
++                config0.bits32 = 0;
++                config0_mask.bits32 = 0;
++                config0.bits.tx_fc_en = 1; /* enable tx flow control */
++                config0.bits.rx_fc_en = 1; /* enable rx flow control */
++                config0_mask.bits.tx_fc_en = 1;
++                config0_mask.bits.rx_fc_en = 1;
++                gmac_write_reg(gmac_base_addr[index] + GMAC_CONFIG0,config0.bits32,config0_mask.bits32);
++//                printk("eth%d Flow Control Enable. \n",index);
++            }
++            flow_control_enable[index] = 1;
++        }
++        else
++        {
++            if (flow_control_enable[index] == 1)
++            {
++                config0.bits32 = 0;
++                config0_mask.bits32 = 0;
++                config0.bits.tx_fc_en = 0; /* disable tx flow control */
++                config0.bits.rx_fc_en = 0; /* disable rx flow control */
++                config0_mask.bits.tx_fc_en = 1;
++                config0_mask.bits.rx_fc_en = 1;
++                gmac_write_reg(gmac_base_addr[index] + GMAC_CONFIG0,config0.bits32,config0_mask.bits32);
++//                printk("eth%d Flow Control Disable. \n",index);
++            }
++            flow_control_enable[index] = 0;
++        }
++
++        if (pre_phy_status[index] == LINK_DOWN)
++        {
++            gmac_enable_tx_rx(dev);
++            pre_phy_status[index] = LINK_UP;
++                      set_bit(__LINK_STATE_START, &dev->state);
++                      storlink_ctl.link = 1;
++//                    printk("eth%d Link Up ...\n",index);
++        }
++    }
++    else
++    {
++        status.bits.link = LINK_DOWN; /* link down */
++        netif_stop_queue(dev);
++        flow_control_enable[index] = 0;
++        storlink_ctl.link = 0;
++        if (pre_phy_status[index] == LINK_UP)
++        {
++            gmac_disable_tx_rx(dev);
++            pre_phy_status[index] = LINK_DOWN;
++                      clear_bit(__LINK_STATE_START, &dev->state);
++//                    printk("eth%d Link Down ...\n",index);
++      }
++
++    }
++
++    reg_val = gmac_read_reg(gmac_base_addr[index] + GMAC_STATUS);
++    if (reg_val != status.bits32)
++    {
++        gmac_write_reg(gmac_base_addr[index] + GMAC_STATUS,status.bits32,0x0000007f);
++    }
++}
++
++/***************************************/
++/* define GPIO module base address     */
++/***************************************/
++#define GPIO_BASE_ADDR  (IO_ADDRESS(SL2312_GPIO_BASE))
++
++/* define GPIO pin for MDC/MDIO */
++
++// for gemini ASIC
++#ifdef CONFIG_SL3516_ASIC
++#define H_MDC_PIN           22
++#define H_MDIO_PIN          21
++#define G_MDC_PIN           22
++#define G_MDIO_PIN          21
++#else
++#define H_MDC_PIN           3
++#define H_MDIO_PIN          2
++#define G_MDC_PIN           0
++#define G_MDIO_PIN          1
++#endif
++
++//#define GPIO_MDC             0x80000000
++//#define GPIO_MDIO            0x00400000
++
++static unsigned int GPIO_MDC = 0;
++static unsigned int GPIO_MDIO = 0;
++static unsigned int GPIO_MDC_PIN = 0;
++static unsigned int GPIO_MDIO_PIN = 0;
++
++// For PHY test definition!!
++#define LPC_EECK              0x02
++#define LPC_EDIO              0x04
++#define LPC_GPIO_SET          3
++#define LPC_BASE_ADDR         IO_ADDRESS(IT8712_IO_BASE)
++#define inb_gpio(x)           inb(LPC_BASE_ADDR + IT8712_GPIO_BASE + x)
++#define outb_gpio(x, y)               outb(y, LPC_BASE_ADDR + IT8712_GPIO_BASE + x)
++
++enum GPIO_REG
++{
++    GPIO_DATA_OUT   = 0x00,
++    GPIO_DATA_IN    = 0x04,
++    GPIO_PIN_DIR    = 0x08,
++    GPIO_BY_PASS    = 0x0c,
++    GPIO_DATA_SET   = 0x10,
++    GPIO_DATA_CLEAR = 0x14,
++};
++/***********************/
++/*    MDC : GPIO[31]   */
++/*    MDIO: GPIO[22]   */
++/***********************/
++
++/***************************************************
++* All the commands should have the frame structure:
++*<PRE><ST><OP><PHYAD><REGAD><TA><DATA><IDLE>
++****************************************************/
++
++/*****************************************************************
++* Inject a bit to NWay register through CSR9_MDC,MDIO
++*******************************************************************/
++void mii_serial_write(char bit_MDO) // write data into mii PHY
++{
++#if 0 //def CONFIG_SL2312_LPC_IT8712
++      unsigned char iomode,status;
++
++      iomode = LPCGetConfig(LDN_GPIO, 0xc8 + LPC_GPIO_SET);
++      iomode |= (LPC_EECK|LPC_EDIO) ;                         // Set EECK,EDIO,EECS output
++      LPCSetConfig(LDN_GPIO, 0xc8 + LPC_GPIO_SET, iomode);
++
++      if(bit_MDO)
++      {
++              status = inb_gpio( LPC_GPIO_SET);
++              status |= LPC_EDIO ;            //EDIO high
++              outb_gpio(LPC_GPIO_SET, status);
++      }
++      else
++      {
++              status = inb_gpio( LPC_GPIO_SET);
++              status &= ~(LPC_EDIO) ;         //EDIO low
++              outb_gpio(LPC_GPIO_SET, status);
++      }
++
++      status |= LPC_EECK ;            //EECK high
++      outb_gpio(LPC_GPIO_SET, status);
++
++      status &= ~(LPC_EECK) ;         //EECK low
++      outb_gpio(LPC_GPIO_SET, status);
++
++#else
++    unsigned int addr;
++    unsigned int value;
++
++    addr = GPIO_BASE_ADDR + GPIO_PIN_DIR;
++    value = readl(addr) | GPIO_MDC | GPIO_MDIO; /* set MDC/MDIO Pin to output */
++    writel(value,addr);
++    if(bit_MDO)
++    {
++        addr = (GPIO_BASE_ADDR + GPIO_DATA_SET);
++        writel(GPIO_MDIO,addr); /* set MDIO to 1 */
++        addr = (GPIO_BASE_ADDR + GPIO_DATA_SET);
++        writel(GPIO_MDC,addr); /* set MDC to 1 */
++        addr = (GPIO_BASE_ADDR + GPIO_DATA_CLEAR);
++        writel(GPIO_MDC,addr); /* set MDC to 0 */
++    }
++    else
++    {
++        addr = (GPIO_BASE_ADDR + GPIO_DATA_CLEAR);
++        writel(GPIO_MDIO,addr); /* set MDIO to 0 */
++        addr = (GPIO_BASE_ADDR + GPIO_DATA_SET);
++        writel(GPIO_MDC,addr); /* set MDC to 1 */
++        addr = (GPIO_BASE_ADDR + GPIO_DATA_CLEAR);
++        writel(GPIO_MDC,addr); /* set MDC to 0 */
++    }
++
++#endif
++}
++
++/**********************************************************************
++* read a bit from NWay register through CSR9_MDC,MDIO
++***********************************************************************/
++unsigned int mii_serial_read(void) // read data from mii PHY
++{
++#if 0 //def CONFIG_SL2312_LPC_IT8712
++      unsigned char iomode,status;
++      unsigned int value ;
++
++      iomode = LPCGetConfig(LDN_GPIO, 0xc8 + LPC_GPIO_SET);
++      iomode &= ~(LPC_EDIO) ;         // Set EDIO input
++      iomode |= (LPC_EECK) ;          // Set EECK,EECS output
++      LPCSetConfig(LDN_GPIO, 0xc8 + LPC_GPIO_SET, iomode);
++
++      status = inb_gpio( LPC_GPIO_SET);
++      status |= LPC_EECK ;            //EECK high
++      outb_gpio(LPC_GPIO_SET, status);
++
++      status &= ~(LPC_EECK) ;         //EECK low
++      outb_gpio(LPC_GPIO_SET, status);
++
++      value = inb_gpio( LPC_GPIO_SET);
++
++      value = value>>2 ;
++      value &= 0x01;
++
++      return value ;
++
++#else
++    unsigned int *addr;
++    unsigned int value;
++
++    addr = (unsigned int *)(GPIO_BASE_ADDR + GPIO_PIN_DIR);
++    value = readl(addr) & ~GPIO_MDIO; //0xffbfffff;   /* set MDC to output and MDIO to input */
++    writel(value,addr);
++
++    addr = (unsigned int *)(GPIO_BASE_ADDR + GPIO_DATA_SET);
++    writel(GPIO_MDC,addr); /* set MDC to 1 */
++    addr = (unsigned int *)(GPIO_BASE_ADDR + GPIO_DATA_CLEAR);
++    writel(GPIO_MDC,addr); /* set MDC to 0 */
++
++    addr = (unsigned int *)(GPIO_BASE_ADDR + GPIO_DATA_IN);
++    value = readl(addr);
++    value = (value & (1<<GPIO_MDIO_PIN)) >> GPIO_MDIO_PIN;
++    return(value);
++
++#endif
++}
++
++/***************************************
++* preamble + ST
++***************************************/
++void mii_pre_st(void)
++{
++    unsigned char i;
++
++    for(i=0;i<32;i++) // PREAMBLE
++        mii_serial_write(1);
++    mii_serial_write(0); // ST
++    mii_serial_write(1);
++}
++
++
++/******************************************
++* Read MII register
++* phyad -> physical address
++* regad -> register address
++***************************************** */
++unsigned int mii_read(unsigned char phyad,unsigned char regad)
++{
++    unsigned int i,value;
++    unsigned int bit;
++
++    if (phyad == GPHY_ADDR)
++    {
++        GPIO_MDC_PIN = G_MDC_PIN;   /* assigned MDC pin for giga PHY */
++        GPIO_MDIO_PIN = G_MDIO_PIN; /* assigned MDIO pin for giga PHY */
++    }
++    else
++    {
++        GPIO_MDC_PIN = H_MDC_PIN;   /* assigned MDC pin for 10/100 PHY */
++        GPIO_MDIO_PIN = H_MDIO_PIN; /* assigned MDIO pin for 10/100 PHY */
++    }
++    GPIO_MDC = (1<<GPIO_MDC_PIN);
++    GPIO_MDIO = (1<<GPIO_MDIO_PIN);
++
++    mii_pre_st(); // PRE+ST
++    mii_serial_write(1); // OP
++    mii_serial_write(0);
++
++    for (i=0;i<5;i++) { // PHYAD
++        bit= ((phyad>>(4-i)) & 0x01) ? 1 :0 ;
++        mii_serial_write(bit);
++    }
++
++    for (i=0;i<5;i++) { // REGAD
++        bit= ((regad>>(4-i)) & 0x01) ? 1 :0 ;
++        mii_serial_write(bit);
++    }
++
++    mii_serial_read(); // TA_Z
++//    if((bit=mii_serial_read()) !=0 ) // TA_0
++//    {
++//        return(0);
++//    }
++    value=0;
++    for (i=0;i<16;i++) { // READ DATA
++        bit=mii_serial_read();
++        value += (bit<<(15-i)) ;
++    }
++
++    mii_serial_write(0); // dumy clock
++    mii_serial_write(0); // dumy clock
++//printk("%s: phy_addr=%x reg_addr=%x value=%x \n",__func__,phyad,regad,value);
++    return(value);
++}
++
++/******************************************
++* Write MII register
++* phyad -> physical address
++* regad -> register address
++* value -> value to be write
++***************************************** */
++void mii_write(unsigned char phyad,unsigned char regad,unsigned int value)
++{
++    unsigned int i;
++    char bit;
++
++printk("%s: phy_addr=%x reg_addr=%x value=%x \n",__func__,phyad,regad,value);
++    if (phyad == GPHY_ADDR)
++    {
++        GPIO_MDC_PIN = G_MDC_PIN;   /* assigned MDC pin for giga PHY */
++        GPIO_MDIO_PIN = G_MDIO_PIN; /* assigned MDIO pin for giga PHY */
++    }
++    else
++    {
++        GPIO_MDC_PIN = H_MDC_PIN;   /* assigned MDC pin for 10/100 PHY */
++        GPIO_MDIO_PIN = H_MDIO_PIN; /* assigned MDIO pin for 10/100 PHY */
++    }
++    GPIO_MDC = (1<<GPIO_MDC_PIN);
++    GPIO_MDIO = (1<<GPIO_MDIO_PIN);
++
++    mii_pre_st(); // PRE+ST
++    mii_serial_write(0); // OP
++    mii_serial_write(1);
++    for (i=0;i<5;i++) { // PHYAD
++        bit= ((phyad>>(4-i)) & 0x01) ? 1 :0 ;
++        mii_serial_write(bit);
++    }
++
++    for (i=0;i<5;i++) { // REGAD
++        bit= ((regad>>(4-i)) & 0x01) ? 1 :0 ;
++        mii_serial_write(bit);
++    }
++    mii_serial_write(1); // TA_1
++    mii_serial_write(0); // TA_0
++
++    for (i=0;i<16;i++) { // OUT DATA
++        bit= ((value>>(15-i)) & 0x01) ? 1 : 0 ;
++        mii_serial_write(bit);
++    }
++    mii_serial_write(0); // dumy clock
++    mii_serial_write(0); // dumy clock
++}
++
++
++
++
++
++
++
++
++
++/*                            NOTES
++ *   The instruction set of the 93C66/56/46/26/06 chips are as follows:
++ *
++ *               Start  OP        *
++ *     Function   Bit  Code  Address**  Data     Description
++ *     -------------------------------------------------------------------
++ *     READ        1    10   A7 - A0             Reads data stored in memory,
++ *                                               starting at specified address
++ *     EWEN        1    00   11XXXXXX            Write enable must precede
++ *                                               all programming modes
++ *     ERASE       1    11   A7 - A0             Erase register A7A6A5A4A3A2A1A0
++ *     WRITE       1    01   A7 - A0   D15 - D0  Writes register
++ *     ERAL        1    00   10XXXXXX            Erase all registers
++ *     WRAL        1    00   01XXXXXX  D15 - D0  Writes to all registers
++ *     EWDS        1    00   00XXXXXX            Disables all programming
++ *                                               instructions
++ *    *Note: A value of X for address is a don't care condition.
++ *    **Note: There are 8 address bits for the 93C56/66 chips unlike
++ *          the 93C46/26/06 chips which have 6 address bits.
++ *
++ *   The 93Cx6 has a four wire interface: clock, chip select, data in, and
++ *   data out.While the ADM6996 uning three interface: clock, chip select,and data line.
++ *   The input and output are the same pin. ADM6996 can only recognize the write cmd.
++ *   In order to perform above functions, you need
++ *   1. to enable the chip select .
++ *   2. send one clock of dummy clock
++ *   3. send start bit and opcode
++ *   4. send 8 bits address and 16 bits data
++ *   5. to disable the chip select.
++ *                                                    Jason Lee 2003/07/30
++ */
++
++/***************************************/
++/* define GPIO module base address     */
++/***************************************/
++#define GPIO_EECS          0x00400000         /*   EECS: GPIO[22]   */
++//#define GPIO_MOSI        0x20000000         /*   EEDO: GPIO[29]   send to 6996*/
++#define GPIO_MISO          0x40000000         /*   EEDI: GPIO[30]   receive from 6996*/
++#define GPIO_EECK          0x80000000         /*   EECK: GPIO[31]   */
++
++#define ADM_EECS              0x01
++#define ADM_EECK              0x02
++#define ADM_EDIO              0x04
++/*************************************************************
++* SPI protocol for ADM6996 control
++**************************************************************/
++#define SPI_OP_LEN         0x03               // the length of start bit and opcode
++#define SPI_OPWRITE        0X05               // write
++#define SPI_OPREAD         0X06               // read
++#define SPI_OPERASE        0X07               // erase
++#define SPI_OPWTEN         0X04               // write enable
++#define SPI_OPWTDIS        0X04               // write disable
++#define SPI_OPERSALL       0X04               // erase all
++#define SPI_OPWTALL        0X04               // write all
++
++#define SPI_ADD_LEN        8                  // bits of Address
++#define SPI_DAT_LEN        16                 // bits of Data
++#define ADM6996_PORT_NO            6                  // the port number of ADM6996
++#define ADM6999_PORT_NO            9                  // the port number of ADM6999
++#ifdef CONFIG_ADM_6996
++      #define ADM699X_PORT_NO         ADM6996_PORT_NO
++#endif
++#ifdef CONFIG_ADM_6999
++      #define ADM699X_PORT_NO         ADM6999_PORT_NO
++#endif
++#define LPC_GPIO_SET          3
++#define LPC_BASE_ADDR                 IO_ADDRESS(IT8712_IO_BASE)
++
++extern int it8712_exist;
++
++#define inb_gpio(x)                   inb(LPC_BASE_ADDR + IT8712_GPIO_BASE + x)
++#define outb_gpio(x, y)               outb(y, LPC_BASE_ADDR + IT8712_GPIO_BASE + x)
++
++/****************************************/
++/*    Function Declare                */
++/****************************************/
++/*
++void SPI_write(unsigned char addr,unsigned int value);
++unsigned int SPI_read(unsigned char table,unsigned char addr);
++void SPI_write_bit(char bit_EEDO);
++unsigned int SPI_read_bit(void);
++void SPI_default(void);
++void SPI_reset(unsigned char rstype,unsigned char port_cnt);
++void SPI_pre_st(void);
++void SPI_CS_enable(unsigned char enable);
++void SPI_Set_VLAN(unsigned char LAN,unsigned int port_mask);
++void SPI_Set_tag(unsigned int port,unsigned tag);
++void SPI_Set_PVID(unsigned int PVID,unsigned int port_mask);
++void SPI_mac_lock(unsigned int port, unsigned char lock);
++void SPI_get_port_state(unsigned int port);
++void SPI_port_enable(unsigned int port,unsigned char enable);
++
++void SPI_get_status(unsigned int port);
++*/
++
++struct PORT_CONFIG
++{
++      unsigned char auto_negotiation; // 0:Disable    1:Enable
++      unsigned char speed;            // 0:10M        1:100M
++      unsigned char duplex;           // 0:Half       1:Full duplex
++      unsigned char Tag;              // 0:Untag      1:Tag
++      unsigned char port_disable;     // 0:port enable        1:disable
++      unsigned char pvid;             // port VLAN ID 0001
++      unsigned char mdix;             // Crossover judgement. 0:Disable 1:Enable
++      unsigned char mac_lock;         // MAC address Lock 0:Disable 1:Enable
++};
++
++struct PORT_STATUS
++{
++      unsigned char link;             // 0:not link   1:link established
++      unsigned char speed;            // 0:10M        1:100M
++      unsigned char duplex;           // 0:Half       1:Full duplex
++      unsigned char flow_ctl;         // 0:flow control disable 1:enable
++      unsigned char mac_lock;         // MAC address Lock 0:Disable 1:Enable
++      unsigned char port_disable;     // 0:port enable        1:disable
++
++      // Serial Management
++      unsigned long rx_pac_count;             //receive packet count
++      unsigned long rx_pac_byte;              //receive packet byte count
++      unsigned long tx_pac_count;             //transmit packet count
++      unsigned long tx_pac_byte;              //transmit packet byte count
++      unsigned long collision_count;          //error count
++      unsigned long error_count ;
++
++      unsigned long rx_pac_count_overflow;            //overflow flag
++      unsigned long rx_pac_byte_overflow;
++      unsigned long tx_pac_count_overflow;
++      unsigned long tx_pac_byte_overflow;
++      unsigned long collision_count_overflow;
++      unsigned long error_count_overflow;
++};
++
++struct PORT_CONFIG port_config[ADM699X_PORT_NO];      // 0~3:LAN , 4:WAN , 5:MII
++static struct PORT_STATUS port_state[ADM699X_PORT_NO];
++
++/******************************************
++* SPI_write
++* addr -> Write Address
++* value -> value to be write
++***************************************** */
++void SPI_write(unsigned char addr,unsigned int value)
++{
++      int     i;
++      char    bit;
++#ifdef CONFIG_IT8712_GPIO
++      char    status;
++#else
++    int     ad1;
++#endif
++
++#ifdef CONFIG_IT8712_GPIO
++      status = inb_gpio(LPC_GPIO_SET);
++      status &= ~(ADM_EDIO) ;         //EDIO low
++      outb_gpio(LPC_GPIO_SET, status);
++#else
++      ad1 = (GPIO_BASE_ADDR + GPIO_DATA_CLEAR);
++      writel(GPIO_MISO,ad1); /* set MISO to 0 */
++#endif
++      SPI_CS_enable(1);
++
++      SPI_write_bit(0);       //dummy clock
++
++      //send write command (0x05)
++      for(i=SPI_OP_LEN-1;i>=0;i--)
++      {
++              bit = (SPI_OPWRITE>>i)& 0x01;
++              SPI_write_bit(bit);
++      }
++      // send 8 bits address (MSB first, LSB last)
++      for(i=SPI_ADD_LEN-1;i>=0;i--)
++      {
++              bit = (addr>>i)& 0x01;
++              SPI_write_bit(bit);
++      }
++      // send 16 bits data (MSB first, LSB last)
++      for(i=SPI_DAT_LEN-1;i>=0;i--)
++      {
++              bit = (value>>i)& 0x01;
++              SPI_write_bit(bit);
++      }
++
++      SPI_CS_enable(0);       // CS low
++
++      for(i=0;i<0xFFF;i++) ;
++#ifdef CONFIG_IT8712_GPIO
++      status = inb_gpio(LPC_GPIO_SET);
++      status &= ~(ADM_EDIO) ;         //EDIO low
++      outb_gpio(LPC_GPIO_SET, status);
++#else
++      ad1 = (GPIO_BASE_ADDR + GPIO_DATA_CLEAR);
++      writel(GPIO_MISO,ad1); /* set MISO to 0 */
++#endif
++}
++
++
++/************************************
++* SPI_write_bit
++* bit_EEDO -> 1 or 0 to be written
++************************************/
++void SPI_write_bit(char bit_EEDO)
++{
++#ifdef CONFIG_IT8712_GPIO
++      unsigned char iomode,status;
++
++      iomode = LPCGetConfig(LDN_GPIO, 0xc8 + LPC_GPIO_SET);
++      iomode |= (ADM_EECK|ADM_EDIO|ADM_EECS) ;                                // Set EECK,EDIO,EECS output
++      LPCSetConfig(LDN_GPIO, 0xc8 + LPC_GPIO_SET, iomode);
++
++      if(bit_EEDO)
++      {
++              status = inb_gpio( LPC_GPIO_SET);
++              status |= ADM_EDIO ;            //EDIO high
++              outb_gpio(LPC_GPIO_SET, status);
++      }
++      else
++      {
++              status = inb_gpio( LPC_GPIO_SET);
++              status &= ~(ADM_EDIO) ;         //EDIO low
++              outb_gpio(LPC_GPIO_SET, status);
++      }
++
++      status |= ADM_EECK ;            //EECK high
++      outb_gpio(LPC_GPIO_SET, status);
++
++      status &= ~(ADM_EECK) ;         //EECK low
++      outb_gpio(LPC_GPIO_SET, status);
++
++#else
++      unsigned int addr;
++      unsigned int value;
++
++      addr = (GPIO_BASE_ADDR + GPIO_PIN_DIR);
++      value = readl(addr) |GPIO_EECK |GPIO_MISO ;   /* set EECK/MISO Pin to output */
++      writel(value,addr);
++      if(bit_EEDO)
++      {
++              addr = (GPIO_BASE_ADDR + GPIO_DATA_SET);
++              writel(GPIO_MISO,addr); /* set MISO to 1 */
++              writel(GPIO_EECK,addr); /* set EECK to 1 */
++              addr = (GPIO_BASE_ADDR + GPIO_DATA_CLEAR);
++              writel(GPIO_EECK,addr); /* set EECK to 0 */
++      }
++      else
++      {
++              addr = (GPIO_BASE_ADDR + GPIO_DATA_CLEAR);
++              writel(GPIO_MISO,addr); /* set MISO to 0 */
++              addr = (GPIO_BASE_ADDR + GPIO_DATA_SET);
++              writel(GPIO_EECK,addr); /* set EECK to 1 */
++              addr = (GPIO_BASE_ADDR + GPIO_DATA_CLEAR);
++              writel(GPIO_EECK,addr); /* set EECK to 0 */
++      }
++
++      return ;
++#endif
++}
++
++/**********************************************************************
++* read a bit from ADM6996 register
++***********************************************************************/
++unsigned int SPI_read_bit(void) // read data from
++{
++#ifdef CONFIG_IT8712_GPIO
++      unsigned char iomode,status;
++      unsigned int value ;
++
++      iomode = LPCGetConfig(LDN_GPIO, 0xc8 + LPC_GPIO_SET);
++      iomode &= ~(ADM_EDIO) ;         // Set EDIO input
++      iomode |= (ADM_EECS|ADM_EECK) ;         // Set EECK,EECS output
++      LPCSetConfig(LDN_GPIO, 0xc8 + LPC_GPIO_SET, iomode);
++
++      status = inb_gpio( LPC_GPIO_SET);
++      status |= ADM_EECK ;            //EECK high
++      outb_gpio(LPC_GPIO_SET, status);
++
++      status &= ~(ADM_EECK) ;         //EECK low
++      outb_gpio(LPC_GPIO_SET, status);
++
++      value = inb_gpio( LPC_GPIO_SET);
++
++      value = value>>2 ;
++      value &= 0x01;
++
++      return value ;
++#else
++      unsigned int addr;
++      unsigned int value;
++
++      addr = (GPIO_BASE_ADDR + GPIO_PIN_DIR);
++      value = readl(addr) & (~GPIO_MISO);   // set EECK to output and MISO to input
++      writel(value,addr);
++
++      addr =(GPIO_BASE_ADDR + GPIO_DATA_SET);
++      writel(GPIO_EECK,addr); // set EECK to 1
++      addr = (GPIO_BASE_ADDR + GPIO_DATA_CLEAR);
++      writel(GPIO_EECK,addr); // set EECK to 0
++
++      addr = (GPIO_BASE_ADDR + GPIO_DATA_IN);
++      value = readl(addr) ;
++      value = value >> 30;
++      return value ;
++#endif
++}
++
++/******************************************
++* SPI_default
++* EEPROM content default value
++*******************************************/
++void SPI_default(void)
++{
++      int i;
++#ifdef CONFIG_ADM_6999
++      SPI_write(0x11,0xFF30);
++      for(i=1;i<8;i++)
++              SPI_write(i,0x840F);
++
++      SPI_write(0x08,0x880F);                 //port 8 Untag, PVID=2
++      SPI_write(0x09,0x881D);                 //port 9 Tag, PVID=2 ,10M
++      SPI_write(0x14,0x017F);                 //Group 0~6,8 as VLAN 1
++      SPI_write(0x15,0x0180);                 //Group 7,8 as VLAN 2
++#endif
++
++#ifdef CONFIG_ADM_6996
++      SPI_write(0x11,0xFF30);
++      SPI_write(0x01,0x840F);                 //port 0~3 Untag ,PVID=1 ,100M ,duplex
++      SPI_write(0x03,0x840F);
++      SPI_write(0x05,0x840F);
++      SPI_write(0x07,0x840F);
++      SPI_write(0x08,0x880F);                 //port 4 Untag, PVID=2
++      SPI_write(0x09,0x881D);                 //port 5 Tag, PVID=2 ,10M
++      SPI_write(0x14,0x0155);                 //Group 0~3,5 as VLAN 1
++      SPI_write(0x15,0x0180);                 //Group 4,5 as VLAN 2
++
++#endif
++
++      for(i=0x16;i<=0x22;i++)
++              SPI_write((unsigned char)i,0x0000);             // clean VLAN¡@map 3~15
++
++      for (i=0;i<NUM_VLAN_IF;i++)                             // Set VLAN ID map 1,2
++              SPI_Set_PVID( VLAN_conf[i].vid,  VLAN_conf[i].portmap);
++
++      for(i=0;i<ADM699X_PORT_NO;i++)                          // reset count
++              SPI_reset(0,i);
++}
++
++/*************************************************
++* SPI_reset
++* rstype -> reset type
++*         0:reset all count for 'port_cnt' port
++*         1:reset specified count 'port_cnt'
++* port_cnt   ->  port number or counter index
++***************************************************/
++void SPI_reset(unsigned char rstype,unsigned char port_cnt)
++{
++
++      int i;
++#ifdef CONFIG_IT8712_GPIO
++    char status;
++#else
++      int ad1;
++#endif
++      char bit;
++
++#ifdef CONFIG_IT8712_GPIO
++      status = inb_gpio(LPC_GPIO_SET);
++      status &= ~(ADM_EDIO) ;         //EDIO low
++      outb_gpio(LPC_GPIO_SET, status);
++#else
++      ad1 = (GPIO_BASE_ADDR + GPIO_DATA_CLEAR);
++      writel(GPIO_MISO,ad1); /* set MISO to 0 */
++#endif
++
++      SPI_CS_enable(0);       // CS low
++
++      SPI_pre_st(); // PRE+ST
++      SPI_write_bit(0); // OP
++      SPI_write_bit(1);
++
++      SPI_write_bit(1);               // Table select, must be 1 -> reset Counter
++
++      SPI_write_bit(0);               // Device Address
++      SPI_write_bit(0);
++
++      rstype &= 0x01;
++      SPI_write_bit(rstype);          // Reset type 0:clear dedicate port's all counters 1:clear dedicate counter
++
++      for (i=5;i>=0;i--)              // port or cnt index
++      {
++              bit = port_cnt >> i ;
++              bit &= 0x01 ;
++              SPI_write_bit(bit);
++      }
++
++      SPI_write_bit(0);               // dumy clock
++      SPI_write_bit(0);               // dumy clock
++
++#ifdef CONFIG_IT8712_GPIO
++      status = inb_gpio(LPC_GPIO_SET);
++      status &= ~(ADM_EDIO) ;         //EDIO low
++      outb_gpio(LPC_GPIO_SET, status);
++#else
++      ad1 = (GPIO_BASE_ADDR + GPIO_DATA_CLEAR);
++      writel(GPIO_MISO,ad1); /* set MISO to 0 */
++#endif
++}
++
++/*****************************************************
++* SPI_pre_st
++* preambler: 32 bits '1'   start bit: '01'
++*****************************************************/
++void SPI_pre_st(void)
++{
++      int i;
++
++      for(i=0;i<32;i++) // PREAMBLE
++              SPI_write_bit(1);
++      SPI_write_bit(0); // ST
++      SPI_write_bit(1);
++}
++
++
++/***********************************************************
++* SPI_CS_enable
++* before access ,you have to enable Chip Select. (pull high)
++* When fisish, you should pull low !!
++*************************************************************/
++void SPI_CS_enable(unsigned char enable)
++{
++#ifdef CONFIG_IT8712_GPIO
++
++      unsigned char iomode,status;
++
++      iomode = LPCGetConfig(LDN_GPIO, 0xc8 + LPC_GPIO_SET);
++      iomode |= (ADM_EECK|ADM_EDIO|ADM_EECS) ;                                // Set EECK,EDIO,EECS output
++      LPCSetConfig(LDN_GPIO, 0xc8 + LPC_GPIO_SET, iomode);
++
++
++      status = inb_gpio( LPC_GPIO_SET);
++      if(enable)
++              status |= ADM_EECS ;            //EECS high
++      else
++              status &= ~(ADM_EECS) ; //EECS low
++
++      outb_gpio(LPC_GPIO_SET, status);
++
++
++      status |= ADM_EECK ;            //EECK high
++      outb_gpio(LPC_GPIO_SET, status);
++
++      status &= ~(ADM_EECK) ;         //EECK low
++      outb_gpio(LPC_GPIO_SET, status);
++
++#else
++      unsigned int addr,value;
++
++      addr = (GPIO_BASE_ADDR + GPIO_PIN_DIR);
++      value = readl(addr) |GPIO_EECS |GPIO_EECK;   /* set EECS/EECK Pin to output */
++      writel(value,addr);
++
++      if(enable)
++      {
++              addr = (GPIO_BASE_ADDR + GPIO_DATA_SET);
++              writel(GPIO_EECS,addr); /* set EECS to 1 */
++
++      }
++      else
++      {
++              addr = (GPIO_BASE_ADDR + GPIO_DATA_CLEAR);
++              writel(GPIO_EECS,addr); /* set EECS to 0 */
++              addr = (GPIO_BASE_ADDR + GPIO_DATA_SET);
++              writel(GPIO_EECK,addr); /* set EECK to 1 */     // at least one clock after CS low
++              addr = (GPIO_BASE_ADDR + GPIO_DATA_CLEAR);
++              writel(GPIO_EECK,addr); /* set EECK to 0 */
++      }
++#endif
++}
++
++/*********************************************************
++* SPI_Set_VLAN: group ports as VLAN
++* LAN  -> VLAN number : 0~16
++* port_mask -> ports which would group as LAN
++*            ex. 0x03 = 0000 0011
++*                     port 0 and port 1
++*********************************************************/
++void SPI_Set_VLAN(unsigned char LAN,unsigned int port_mask)
++{
++      unsigned int i,value=0;
++      unsigned reg_add = 0x13 + LAN ;
++
++      for(i=0;i<ADM6996_PORT_NO;i++)
++      {       if(port_mask&0x01)
++              {
++                      switch(i)
++                      {
++                              case 0: value|=0x0001;  break;  //port0:bit[0]
++                              case 1: value|=0x0004;  break;  //port1:bit[2]
++                              case 2: value|=0x0010;  break;  //port2:bit[4]
++                              case 3: value|=0x0040;  break;  //port3:bit[6]
++                              case 4: value|=0x0080;  break;  //port4:bit[7]
++                              case 5: value|=0x0100;  break;  //port5:bit[8]
++                      }
++              }
++              port_mask >>= 1;
++      }
++
++      SPI_write(reg_add,value);
++}
++
++
++/*******************************************
++* SPI_Set_tag
++* port -> port number to set tag or untag
++* tag  -> 0/set untag,  1/set tag
++* In general, tag is for MII port. LAN and
++* WAN port is configed as untag!!
++********************************************/
++void SPI_Set_tag(unsigned int port,unsigned tag)
++{
++      unsigned int regadd,value;
++
++      // mapping port's register !! (0,1,2,3,4,5) ==> (1,3,5,7,8,9)
++      if(port<=3)
++              regadd=2*port+1;
++      else if(port==4) regadd = 8 ;
++      else regadd = 9 ;
++
++
++      value = SPI_read(0,regadd);             //read original setting
++
++      if(tag)
++              value |= 0x0010 ;               // set tag
++      else
++              value &= 0xFFEF ;               // set untag
++
++      SPI_write(regadd,value);                // write back!!
++}
++
++/************************************************
++* SPI_Set_PVID
++* PVID -> PVID number :
++* port_mask -> ports which would group as LAN
++*            ex. 0x0F = 0000 1111 ==> port 0~3
++************************************************/
++void SPI_Set_PVID(unsigned int PVID,unsigned int port_mask)
++{
++      unsigned int i,value=0;
++
++      PVID &= 0x000F ;
++
++      for(i=0;i<ADM699X_PORT_NO;i++)
++      {       if(port_mask&0x01)
++              {
++#ifdef CONFIG_ADM_6996
++                      switch(i)
++                      {
++                              case 0:
++                                      value = SPI_read(0,0x01);       // read original value
++                                      value &= 0xC3FF ;                       //set PVIC column as 0 first
++                                      value |= PVID << 10 ;           //Set PVID column as PVID
++                                      SPI_write(0x01,value);          //write back
++                                      break;
++                              case 1:
++                                      value = SPI_read(0,0x03);
++                                      value &= 0xC3FF ;
++                                      value |= PVID << 10 ;
++                                      SPI_write(0x03,value);
++                                      break;
++                              case 2:
++                                      value = SPI_read(0,0x05);
++                                      value &= 0xC3FF ;
++                                      value |= PVID << 10 ;
++                                      SPI_write(0x05,value);
++                                      break;
++                              case 3:
++                                      value = SPI_read(0,0x07);
++                                      value &= 0xC3FF ;
++                                      value |= PVID << 10 ;
++                                      SPI_write(0x07,value);
++                                      break;
++                              case 4:
++                                      value = SPI_read(0,0x08);
++                                      value &= 0xC3FF ;
++                                      value |= PVID << 10 ;
++                                      SPI_write(0x08,value);
++                                      break;
++                              case 5:
++                                      value = SPI_read(0,0x09);
++                                      value &= 0xC3FF ;
++                                      value |= PVID << 10 ;
++                                      SPI_write(0x09,value);
++                                      break;
++                      }
++#endif
++#ifdef CONFIG_ADM_6999
++                      value = SPI_read(0,(unsigned char)i+1);
++                      value &= 0xC3FF ;
++                      value |= PVID << 10 ;
++                      SPI_write((unsigned char)i+1,value);
++#endif
++              }
++              port_mask >>= 1;
++      }
++}
++
++
++/************************************************
++* SPI_get_PVID
++* port -> which ports to VID
++************************************************/
++unsigned int SPI_Get_PVID(unsigned int port)
++{
++      unsigned int value=0;
++
++      if (port>=ADM6996_PORT_NO)
++              return 0;
++
++      switch(port)
++      {
++              case 0:
++                      value = SPI_read(0,0x01);       // read original value
++                      value &= 0x3C00 ;               // get VID
++                      value = value >> 10 ;           // Shift
++                      break;
++              case 1:
++                      value = SPI_read(0,0x03);
++                      value &= 0x3C00 ;
++                      value = value >> 10 ;
++                      break;
++              case 2:
++                      value = SPI_read(0,0x05);
++                      value &= 0x3C00 ;
++                      value = value >> 10 ;
++                      break;
++              case 3:
++                      value = SPI_read(0,0x07);
++                      value &= 0x3C00 ;
++                      value = value >> 10 ;
++                      break;
++              case 4:
++                      value = SPI_read(0,0x08);
++                      value &= 0x3C00 ;
++                      value = value >> 10 ;
++                      break;
++              case 5:
++                      value = SPI_read(0,0x09);
++                      value &= 0x3C00 ;
++                      value = value >> 10 ;
++                      break;
++      }
++      return value ;
++}
++
++
++/**********************************************
++* SPI_mac_clone
++* port -> the port which will lock or unlock
++* lock -> 0/the port will be unlock
++*       1/the port will be locked
++**********************************************/
++void SPI_mac_lock(unsigned int port, unsigned char lock)
++{
++      unsigned int i,value=0;
++
++      value = SPI_read(0,0x12);               // read original
++
++      for(i=0;i<ADM6996_PORT_NO;i++)
++      {       if(lock)                                // lock port
++              {
++                      switch(port)
++                      {
++                              case 0: value|=0x0001;  break;  //port0:bit[0]
++                              case 1: value|=0x0004;  break;  //port1:bit[2]
++                              case 2: value|=0x0010;  break;  //port2:bit[4]
++                              case 3: value|=0x0040;  break;  //port3:bit[6]
++                              case 4: value|=0x0080;  break;  //port4:bit[7]
++                              case 5: value|=0x0100;  break;  //port5:bit[8]
++                      }
++              }
++              else
++              {
++                      switch(i)                       // unlock port
++                      {
++                              case 0: value&=0xFFFE;  break;
++                              case 1: value&=0xFFFB;  break;
++                              case 2: value&=0xFFEF;  break;
++                              case 3: value&=0xFFBF;  break;
++                              case 4: value&=0xFF7F;  break;
++                              case 5: value&=0xFEFF;  break;
++                      }
++              }
++      }
++
++      SPI_write(0x12,value);
++}
++
++
++/***************************************************
++* SPI_learn_pause
++* pause = 01-80-c2-00-00-01
++* DA=distination address
++* forward -> 0: if DA == pause then drop and stop mac learning
++*          1: if DA == pause ,then forward it
++***************************************************/
++void SPI_pause_cmd_forward(unsigned char forward)
++{
++      unsigned int value=0;
++
++      value = SPI_read(0,0x2C);               // read original setting
++      if(forward)
++              value |= 0x2000;                // set bit[13] '1'
++      else
++              value &= 0xDFFF;                // set bit[13] '0'
++
++      SPI_write(0x2C,value);
++
++}
++
++
++/************************************************
++* SPI_read
++* table -> which table to be read: 1/count  0/EEPROM
++* addr  -> Address to be read
++* return : Value of the register
++*************************************************/
++unsigned int SPI_read(unsigned char table,unsigned char addr)
++{
++      int i ;
++      unsigned int value=0;
++      unsigned int bit;
++#ifdef CONFIG_IT8712_GPIO
++      unsigned char status;
++#else
++    unsigned int ad1;
++#endif
++
++#ifdef CONFIG_IT8712_GPIO
++      status = inb_gpio(LPC_GPIO_SET);
++      status &= ~(ADM_EDIO) ;         //EDIO low
++      outb_gpio(LPC_GPIO_SET, status);
++#else
++      ad1 = (GPIO_BASE_ADDR + GPIO_DATA_CLEAR);
++      writel(GPIO_MISO,ad1); /* set MISO to 0 */
++#endif
++
++      SPI_CS_enable(0);
++
++      SPI_pre_st(); // PRE+ST
++      SPI_write_bit(1); // OPCODE '10' for read
++      SPI_write_bit(0);
++
++      (table==1) ? SPI_write_bit(1) : SPI_write_bit(0) ;      // table select
++
++      SPI_write_bit(0);               // Device Address
++      SPI_write_bit(0);
++
++
++      // send 7 bits address to be read
++      for (i=6;i>=0;i--) {
++              bit= ((addr>>i) & 0x01) ? 1 :0 ;
++              SPI_write_bit(bit);
++      }
++
++
++      // turn around
++      SPI_read_bit(); // TA_Z
++
++      value=0;
++      for (i=31;i>=0;i--) { // READ DATA
++              bit=SPI_read_bit();
++              value |= bit << i ;
++      }
++
++      SPI_read_bit(); // dumy clock
++      SPI_read_bit(); // dumy clock
++
++      if(!table)                                      // EEPROM, only fetch 16 bits data
++      {
++          if(addr&0x01)                               // odd number content (register,register-1)
++                  value >>= 16 ;                      // so we remove the rear 16bits
++          else                                        // even number content (register+1,register),
++                  value &= 0x0000FFFF ;               // so we keep the rear 16 bits
++      }
++
++
++      SPI_CS_enable(0);
++
++#ifdef CONFIG_IT8712_GPIO
++      status = inb_gpio(LPC_GPIO_SET);
++      status &= ~(ADM_EDIO) ;         //EDIO low
++      outb_gpio(LPC_GPIO_SET, status);
++#else
++      ad1 = (GPIO_BASE_ADDR + GPIO_DATA_CLEAR);
++      writel(GPIO_MISO,ad1); /* set MISO to 0 */
++#endif
++
++      return(value);
++
++}
++
++
++
++/**************************************************
++* SPI_port_en
++* port -> Number of port to config
++* enable -> 1/ enable this port
++*         0/ disable this port
++**************************************************/
++void SPI_port_enable(unsigned int port,unsigned char enable)
++{
++      unsigned int reg_val ;
++      unsigned char reg_add ;
++
++      if(port<=3)
++              reg_add=2*port+1;
++      else if(port==4) reg_add = 8 ;
++      else reg_add = 9 ;
++
++      reg_val = SPI_read(0,reg_add);
++      if(enable)
++      {
++              reg_val &= 0xFFDF ;
++              SPI_write(reg_add,reg_val);
++      }
++      else
++      {
++              reg_val |= 0x0020 ;
++              SPI_write(reg_add,reg_val);
++      }
++}
++
++/********************************************************
++* get port status
++* port -> specify the port number to get configuration
++*********************************************************/
++void SPI_get_status(unsigned int port)
++{
++/*    unsigned int reg_val,add_offset[6];
++      struct PORT_STATUS *status;
++      status = &port_state[port];
++
++      if(port>(ADM6996_PORT_NO-1))
++              return ;
++
++      // Link estabilish , speed, deplex, flow control ?
++      if(port < 5 )
++      {
++              reg_val = SPI_read(1, 1) ;
++              if(port < 4)
++                      reg_val >>= port*8 ;
++              else
++                      reg_val >>=28 ;
++              status->link = reg_val & 0x00000001 ;
++              status->speed = reg_val  & 0x00000002 ;
++              status->duplex = reg_val & 0x00000004 ;
++              status->flow_ctl = reg_val & 0x00000008 ;
++      }
++      else if(port ==5 )
++      {
++              reg_val = SPI_read(1, 2) ;
++              status->link = reg_val & 0x00000001 ;
++              status->speed = reg_val  & 0x00000002 ;
++              status->duplex = reg_val & 0x00000008 ;
++              status->flow_ctl = reg_val & 0x00000010 ;
++      }
++
++      //   Mac Lock ?
++      reg_val = SPI_read(0,0x12);
++      switch(port)
++      {
++              case 0: status->mac_lock = reg_val & 0x00000001;
++              case 1: status->mac_lock = reg_val & 0x00000004;
++              case 2: status->mac_lock = reg_val & 0x00000010;
++              case 3: status->mac_lock = reg_val & 0x00000040;
++              case 4: status->mac_lock = reg_val & 0x00000080;
++              case 5: status->mac_lock = reg_val & 0x00000100;
++      }
++
++      // port enable ?
++      add_offset[0] = 0x01 ;          add_offset[1] = 0x03 ;
++      add_offset[2] = 0x05 ;          add_offset[3] = 0x07 ;
++      add_offset[4] = 0x08 ;          add_offset[5] = 0x09 ;
++      reg_val = SPI_read(0,add_offset[port]);
++      status->port_disable = reg_val & 0x0020;
++
++
++      //  Packet Count ...
++      add_offset[0] = 0x04 ;          add_offset[1] = 0x06 ;
++      add_offset[2] = 0x08 ;          add_offset[3] = 0x0a ;
++      add_offset[4] = 0x0b ;          add_offset[5] = 0x0c ;
++
++      reg_val = SPI_read(1,add_offset[port]);
++      status->rx_pac_count = reg_val ;
++      reg_val = SPI_read(1,add_offset[port]+9);
++      status->rx_pac_byte = reg_val ;
++      reg_val = SPI_read(1,add_offset[port]+18);
++      status->tx_pac_count = reg_val ;
++      reg_val = SPI_read(1,add_offset[port]+27);
++      status->tx_pac_byte = reg_val ;
++      reg_val = SPI_read(1,add_offset[port]+36);
++      status->collision_count = reg_val ;
++      reg_val = SPI_read(1,add_offset[port]+45);
++      status->error_count = reg_val ;
++      reg_val = SPI_read(1, 0x3A);
++      switch(port)
++      {
++              case 0: status->rx_pac_count_overflow = reg_val & 0x00000001;
++                      status->rx_pac_byte_overflow = reg_val & 0x00000200 ;
++              case 1: status->rx_pac_count_overflow = reg_val & 0x00000004;
++                      status->rx_pac_byte_overflow = reg_val & 0x00000800 ;
++              case 2: status->rx_pac_count_overflow = reg_val & 0x00000010;
++                      status->rx_pac_byte_overflow = reg_val & 0x00002000 ;
++              case 3: status->rx_pac_count_overflow = reg_val & 0x00000040;;
++                      status->rx_pac_byte_overflow = reg_val & 0x00008000 ;
++              case 4: status->rx_pac_count_overflow = reg_val & 0x00000080;
++                      status->rx_pac_byte_overflow = reg_val & 0x00010000 ;
++              case 5: status->rx_pac_count_overflow = reg_val & 0x00000100;
++                      status->rx_pac_byte_overflow = reg_val & 0x00020000 ;
++      }
++
++      reg_val = SPI_read(1, 0x3B);
++      switch(port)
++      {
++              case 0: status->tx_pac_count_overflow = reg_val & 0x00000001;
++                      status->tx_pac_byte_overflow  = reg_val & 0x00000200 ;
++              case 1: status->tx_pac_count_overflow  = reg_val & 0x00000004;
++                      status->tx_pac_byte_overflow  = reg_val & 0x00000800 ;
++              case 2: status->tx_pac_count_overflow  = reg_val & 0x00000010;
++                      status->tx_pac_byte_overflow  = reg_val & 0x00002000 ;
++              case 3: status->tx_pac_count_overflow  = reg_val & 0x00000040;;
++                      status->tx_pac_byte_overflow  = reg_val & 0x00008000 ;
++              case 4: status->tx_pac_count_overflow  = reg_val & 0x00000080;
++                      status->tx_pac_byte_overflow  = reg_val & 0x00010000 ;
++              case 5: status->tx_pac_count_overflow  = reg_val & 0x00000100;
++                      status->tx_pac_byte_overflow  = reg_val & 0x00020000 ;
++      }
++*/
++
++      unsigned int reg_val;
++      struct PORT_STATUS *status;
++      status = &port_state[port];
++
++      if(port>=ADM6999_PORT_NO)
++              return ;
++
++      // Link estabilish , speed, deplex, flow control ?
++      if(port < ADM6999_PORT_NO-1 )
++      {
++              reg_val = SPI_read(1, 0x01) ;
++              reg_val = reg_val >> port*4 ;
++              status->link = reg_val & 0x00000001 ;
++              status->speed = reg_val  & 0x00000002 ;
++              status->duplex = reg_val & 0x00000004 ;
++              status->flow_ctl = reg_val & 0x00000008 ;
++      }
++      else if(port == (ADM6999_PORT_NO-1) )
++      {
++              reg_val = SPI_read(1, 0x02) ;
++              status->link = reg_val & 0x00000001 ;
++              status->speed = reg_val  & 0x00000002 ;
++              status->duplex = reg_val & 0x00000008 ;
++              status->flow_ctl = reg_val & 0x00000010 ;
++      }
++
++      // Mac Lock ?
++      reg_val = SPI_read(0,0x12);
++      reg_val = reg_val >> port ;
++      reg_val = reg_val & 0x01 ;
++      status->mac_lock = reg_val ? 0x01:0x00 ;
++
++      // port enable ?
++      reg_val = SPI_read(0,(unsigned char)port+1);
++      status->port_disable = reg_val & 0x0020;
++
++      //  Packet Count ...
++      reg_val = SPI_read(1,(unsigned char)port+0x04);
++      status->rx_pac_count = reg_val ;
++      reg_val = SPI_read(1,(unsigned char)port+0x0D);
++      status->rx_pac_byte = reg_val ;
++      reg_val = SPI_read(1,(unsigned char)port+0x16);
++      status->tx_pac_count = reg_val ;
++      reg_val = SPI_read(1,(unsigned char)port+0x1F);
++      status->tx_pac_byte = reg_val ;
++      reg_val = SPI_read(1,(unsigned char)port+0x28);
++      status->collision_count = reg_val ;
++      reg_val = SPI_read(1,(unsigned char)port+0x31);
++      status->error_count = reg_val ;
++      reg_val = SPI_read(1, 0x3A);
++      reg_val = reg_val >> port ;
++      status->rx_pac_count_overflow = reg_val & 0x00000001;
++      reg_val = reg_val >> 0x09 ;
++      status->rx_pac_byte_overflow = reg_val & 0x00000001 ;
++
++      reg_val = SPI_read(1, 0x3B);
++      reg_val = reg_val >> port ;
++      status->tx_pac_count_overflow = reg_val & 0x00000001;
++      reg_val = reg_val >> 0x09 ;
++      status->tx_pac_byte_overflow  = reg_val & 0x00000001 ;
++
++      reg_val = SPI_read(1, 0x3C);
++      reg_val = reg_val >> port ;
++      status->collision_count_overflow = reg_val & 0x00000001;
++      reg_val = reg_val >> 0x09 ;
++      status->error_count_overflow  = reg_val & 0x00000001 ;
++
++}
++
++unsigned int SPI_get_identifier(void)
++{
++      unsigned int flag=0;
++
++#ifdef CONFIG_IT8712_GPIO
++
++      if (!it8712_exist) {
++              return -ENODEV;
++      }
++      printk("it8712_gpio init\n");
++
++      /* initialize registers */
++      // switch all multi-function pins to GPIO
++      LPCSetConfig(LDN_GPIO, 0x28, 0xff);
++
++      // set simple I/O base address
++      LPCSetConfig(LDN_GPIO, 0x62, IT8712_GPIO_BASE >> 8);
++      LPCSetConfig(LDN_GPIO, 0x63, (unsigned char) IT8712_GPIO_BASE >> 8);
++
++      // select GPIO to simple I/O
++      LPCSetConfig(LDN_GPIO, 0xc3, 0xff);
++
++      // enable internal pull-up
++      LPCSetConfig(LDN_GPIO, 0xbb, 0xff);
++
++#endif
++
++      flag = SPI_read(1,0x00);
++      printk("Get ADM identifier %6x\n",flag);
++      if ((flag & 0xFFFF0) == 0x21120) {
++              printk("ADM699X Found\n");
++              return 1;
++      }
++      else {
++              printk("ADM699X not Found\n");
++              return 0;
++      }
++}
++
+Index: linux-2.6.23.16/drivers/net/sl351x_crc16.c
+===================================================================
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.23.16/drivers/net/sl351x_crc16.c 2008-03-15 16:57:25.854761029 +0200
+@@ -0,0 +1,93 @@
++/****************************************************************************
++* Name                        : sl351x_crc16.c
++* Description :
++*             Implement CRC16
++*             refer to RFC1662
++* History
++*
++*     Date            Writer          Description
++*     -----------     -----------     -------------------------------------------------
++*     09/14/2005      Gary Chen       Create
++*
++****************************************************************************/
++
++#define INITFCS16             0xffff  /* Initial FCS value */
++#define GOODFCS16             0xf0b8  /* Good final FCS value */
++#define SWAP_WORD(x)  (unsigned short)((((unsigned short)x & 0x00FF) << 8) |  \
++                                                                               (((unsigned short)x & 0xFF00) >> 8))
++
++/*----------------------------------------------------------------------
++*     x**0 + x**5 + x**12 + x**16
++*----------------------------------------------------------------------*/
++static const unsigned short crc16_tbl[256] = {
++      0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
++      0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
++      0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
++      0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
++      0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
++      0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
++      0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
++      0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
++      0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
++      0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
++      0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
++      0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
++      0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
++      0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
++      0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
++      0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
++      0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
++      0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
++      0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
++      0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
++      0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
++      0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
++      0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
++      0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
++      0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
++      0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
++      0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
++      0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
++      0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
++      0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
++      0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
++      0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
++};
++
++/*----------------------------------------------------------------------
++* hash_crc16
++*----------------------------------------------------------------------*/
++unsigned short hash_crc16(unsigned short crc, unsigned char *datap, unsigned long len)
++{
++    while (len--)
++    {
++        crc = (crc >> 8) ^ crc16_tbl[(crc ^ (*datap++)) & 0xff];
++    }
++
++    return (crc);
++
++}
++
++/*----------------------------------------------------------------------
++* hash_check_crc16
++*----------------------------------------------------------------------*/
++unsigned long hash_check_crc16(unsigned char *datap, unsigned long len)
++{
++    unsigned short crc;
++
++    crc = hash_crc16(INITFCS16, datap, len );
++    return (crc == GOODFCS16) ?  0 : 1;
++}
++
++/*----------------------------------------------------------------------
++* hash_gen_crc16
++*----------------------------------------------------------------------*/
++unsigned short hash_gen_crc16(unsigned char *datap, unsigned long len)
++{
++    unsigned short crc;
++
++    crc = hash_crc16(INITFCS16, datap, len);
++    crc ^= 0xffff;
++
++    return(SWAP_WORD(crc));
++}
+Index: linux-2.6.23.16/drivers/net/sl351x_gmac.c
+===================================================================
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.23.16/drivers/net/sl351x_gmac.c  2008-03-15 16:59:23.361457295 +0200
+@@ -0,0 +1,5622 @@
++/**************************************************************************
++* Copyright 2006 StorLink Semiconductors, Inc.  All rights reserved.
++*--------------------------------------------------------------------------
++* Name                        : sl351x_gmac.c
++* Description :
++*             Ethernet device driver for Storlink SL351x FPGA
++*
++* History
++*
++*     Date            Writer          Description
++*     -----------     -----------     -------------------------------------------------
++*     08/22/2005      Gary Chen       Create and implement
++*   27/10/2005  CH Hsu      Porting to Linux
++*
++****************************************************************************/
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/slab.h>
++#include <linux/mm.h>
++#include <linux/compiler.h>
++#include <linux/pci.h>
++#include <linux/init.h>
++#include <linux/ioport.h>
++#include <linux/netdevice.h>
++#include <linux/etherdevice.h>
++#include <linux/rtnetlink.h>
++#include <linux/delay.h>
++#include <linux/ethtool.h>
++#include <linux/mii.h>
++#include <linux/completion.h>
++#include <asm/hardware.h>
++#include <asm/io.h>
++#include <asm/irq.h>
++#include <asm/semaphore.h>
++#include <asm/arch/irqs.h>
++#include <asm/arch/it8712.h>
++#include <linux/mtd/kvctl.h>
++#include <linux/skbuff.h>
++#include <linux/in.h>
++#include <linux/ip.h>
++#include <linux/tcp.h>
++#include <linux/udp.h>
++
++#include <linux/mtd/kvctl.h>
++
++#define        MIDWAY
++#define        SL_LEPUS
++#define VITESSE_G5SWITCH      1
++
++#ifndef CONFIG_SL351x_RXTOE
++//#define CONFIG_SL351x_RXTOE 1
++#endif
++#undef CONFIG_SL351x_RXTOE
++
++#include <asm/arch/sl2312.h>
++#include <asm/arch/sl351x_gmac.h>
++#include <asm/arch/sl351x_hash_cfg.h>
++#include <asm/arch/sl351x_nat_cfg.h>
++
++#ifdef CONFIG_SL351x_SYSCTL
++#include <linux/sysctl_storlink.h>
++#endif
++
++#ifdef CONFIG_SL351x_RXTOE
++#include <asm/arch/sl351x_toe.h>
++#include <net/tcp.h>
++#include <linux/tcp.h>
++#include <linux/ip.h>
++#endif
++
++// #define SL351x_TEST_WORKAROUND
++#ifdef CONFIG_SL351x_NAT
++#define CONFIG_SL_NAPI                                        1
++#endif
++#define GMAX_TX_INTR_DISABLED                 1
++#define DO_HW_CHKSUM                                  1
++#define ENABLE_TSO                                            1
++#define GMAC_USE_TXQ0                                 1
++// #define NAT_WORKAROUND_BY_RESET_GMAC       1
++// #define HW_RXBUF_BY_KMALLOC                        1
++//#define _DUMP_TX_TCP_CONTENT        1
++#define       br_if_ioctl                                             1
++#define GMAC_LEN_1_2_ISSUE                            1
++
++#define GMAC_EXISTED_FLAG                     0x5566abcd
++#define CONFIG_MAC_NUM                                GMAC_NUM
++#define GMAC0_BASE                                    TOE_GMAC0_BASE
++#define GMAC1_BASE                                    TOE_GMAC1_BASE
++#define PAUSE_SET_HW_FREEQ                    (TOE_HW_FREEQ_DESC_NUM / 2)
++#define PAUSE_REL_HW_FREEQ                    ((TOE_HW_FREEQ_DESC_NUM / 2) + 10)
++#define DEFAULT_RXQ_MAX_CNT                   256
++#ifdef        L2_jumbo_frame
++#define TCPHDRLEN(tcp_hdr)  ((ntohs(*((__u16 *)tcp_hdr + 6)) >> 12) & 0x000F)
++#endif
++
++/* define chip information */
++#define DRV_NAME                                      "SL351x"
++#define DRV_VERSION                                   "0.1.4"
++#define SL351x_DRIVER_NAME            DRV_NAME " Giga Ethernet driver " DRV_VERSION
++
++#define toe_gmac_enable_interrupt(irq)        enable_irq(irq)
++#define toe_gmac_disable_interrupt(irq)       disable_irq(irq)
++
++#ifdef SL351x_GMAC_WORKAROUND
++#define GMAC_SHORT_FRAME_THRESHOLD            10
++static struct timer_list gmac_workround_timer_obj;
++void sl351x_poll_gmac_hanged_status(u32 data);
++#ifdef CONFIG_SL351x_NAT
++//#define IxscriptMate_1518                           1
++      void sl351x_nat_workaround_init(void);
++      #ifndef NAT_WORKAROUND_BY_RESET_GMAC
++              static void sl351x_nat_workaround_handler(void);
++      #endif
++#endif
++#endif
++
++#ifdef GMAC_LEN_1_2_ISSUE
++      #define _DEBUG_PREFETCH_NUM     256
++static        int     _debug_prefetch_cnt;
++static        char _debug_prefetch_buf[_DEBUG_PREFETCH_NUM][4] __attribute__((aligned(4)));
++#endif
++/*************************************************************
++ *         Global Variable
++ *************************************************************/
++static int    gmac_initialized = 0;
++TOE_INFO_T toe_private_data;
++//static int          do_again = 0;
++spinlock_t gmac_fq_lock;
++unsigned int FLAG_SWITCH;
++
++static unsigned int           next_tick = 3 * HZ;
++static unsigned char          eth_mac[CONFIG_MAC_NUM][6]= {{0x00,0x11,0x11,0x87,0x87,0x87}, {0x00,0x22,0x22,0xab,0xab,0xab}};
++
++#undef CONFIG_SL351x_RXTOE
++extern NAT_CFG_T nat_cfg;
++
++/************************************************/
++/*                 function declare             */
++/************************************************/
++static int gmac_set_mac_address(struct net_device *dev, void *addr);
++static unsigned int gmac_get_phy_vendor(int phy_addr);
++static void gmac_set_phy_status(struct net_device *dev);
++void gmac_get_phy_status(struct net_device *dev);
++static int gmac_netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
++static void gmac_tx_timeout(struct net_device *dev);
++static int gmac_phy_thread (void *data);
++struct net_device_stats * gmac_get_stats(struct net_device *dev);
++static int gmac_start_xmit(struct sk_buff *skb, struct net_device *dev);
++static void gmac_set_rx_mode(struct net_device *dev);
++static irqreturn_t toe_gmac_interrupt (int irq, void *dev_instance, struct pt_regs *regs);
++static void toe_gmac_handle_default_rxq(struct net_device *dev, GMAC_INFO_T *tp);
++unsigned int mii_read(unsigned char phyad,unsigned char regad);
++void mii_write(unsigned char phyad,unsigned char regad,unsigned int value);
++void mac_init_drv(void);
++
++static void toe_init_free_queue(void);
++static void toe_init_swtx_queue(void);
++static void toe_init_default_queue(void);
++#ifdef CONFIG_SL351x_RXTOE
++static void toe_init_interrupt_queue(void);
++#endif
++static void toe_init_interrupt_config(void);
++static void toe_gmac_sw_reset(void);
++static int toe_gmac_init_chip(struct net_device *dev);
++static void toe_gmac_enable_tx_rx(struct net_device* dev);
++static void toe_gmac_disable_tx_rx(struct net_device *dev);
++static void toe_gmac_hw_start(struct net_device *dev);
++static void toe_gmac_hw_stop(struct net_device *dev);
++static int toe_gmac_clear_counter(struct net_device *dev);
++static void toe_init_gmac(struct net_device *dev);
++static  void toe_gmac_tx_complete(GMAC_INFO_T *tp, unsigned int tx_qid, struct net_device *dev, int interrupt);
++#ifdef CONFIG_SL_NAPI
++static int gmac_rx_poll(struct net_device *dev, int *budget);
++// static void toe_gmac_disable_rx(struct net_device *dev);
++// static void toe_gmac_enable_rx(struct net_device *dev);
++#endif
++
++u32 mac_read_dma_reg(int mac, unsigned int offset);
++void mac_write_dma_reg(int mac, unsigned int offset, u32 data);
++void mac_stop_txdma(struct net_device *dev);
++void mac_get_sw_tx_weight(struct net_device *dev, char *weight);
++void mac_set_sw_tx_weight(struct net_device *dev, char *weight);
++void mac_get_hw_tx_weight(struct net_device *dev, char *weight);
++void mac_set_hw_tx_weight(struct net_device *dev, char *weight);
++static inline void toe_gmac_fill_free_q(void);
++
++#ifdef VITESSE_G5SWITCH
++extern int Get_Set_port_status(void);
++extern int SPI_default(void);
++extern unsigned int SPI_get_identifier(void);
++void gmac_get_switch_status(struct net_device *dev);
++unsigned int Giga_switch=0;
++unsigned int switch_port_no=0;
++unsigned int ever_dwon=0;
++#endif
++
++/************************************************/
++/*            GMAC function declare             */
++/************************************************/
++static int gmac_open (struct net_device *dev);
++static int gmac_close (struct net_device *dev);
++static void gmac_cleanup_module(void);
++static void gmac_get_mac_address(void);
++
++#ifdef CONFIG_SL351x_NAT
++static void toe_init_hwtx_queue(void);
++extern void sl351x_nat_init(void);
++extern void sl351x_nat_input(struct sk_buff *skb, int port, void *l3off, void *l4off);
++extern int sl351x_nat_output(struct sk_buff *skb, int port);
++extern int sl351x_nat_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
++#endif
++
++#ifdef CONFIG_SL351x_RXTOE
++extern void set_toeq_hdr(struct toe_conn* connection, TOE_INFO_T* toe, struct net_device *dev);
++extern void sl351x_toe_init(void);
++extern void toe_gmac_handle_toeq(struct net_device *dev, GMAC_INFO_T* tp, __u32 status);
++extern struct toe_conn* init_toeq(int ipver, void* iph, struct tcphdr* tcp_hdr, TOE_INFO_T* toe, unsigned char* l2hdr);
++#endif
++
++int mac_set_rule_reg(int mac, int rule, int enabled, u32 reg0, u32 reg1, u32 reg2);
++void mac_set_rule_enable_bit(int mac, int rule, int data);
++int mac_set_rule_action(int mac, int rule, int data);
++int mac_get_MRxCRx(int mac, int rule, int ctrlreg);
++void mac_set_MRxCRx(int mac, int rule, int ctrlreg, u32 data);
++
++/*----------------------------------------------------------------------
++*     Ethernet Driver init
++*----------------------------------------------------------------------*/
++
++static int __init gmac_init_module(void)
++{
++      GMAC_INFO_T             *tp;
++      struct net_device       *dev;
++      int             i,j;
++      unsigned int    chip_id;
++//    unsigned int chip_version;
++
++#ifdef CONFIG_SL3516_ASIC
++{
++    unsigned int    val;
++    /* set GMAC global register */
++    val = readl(GMAC_GLOBAL_BASE_ADDR+0x10);
++    val = val | 0x005f0000;
++    writel(val,GMAC_GLOBAL_BASE_ADDR+0x10);
++//    writel(0xb737b737,GMAC_GLOBAL_BASE_ADDR+0x1c); //For Socket Board
++    writel(0x77777777,GMAC_GLOBAL_BASE_ADDR+0x20);
++//    writel(0xa737b747,GMAC_GLOBAL_BASE_ADDR+0x1c);//For Mounting Board
++
++      //debug_Aaron
++    //writel(0xa7f0a7f0,GMAC_GLOBAL_BASE_ADDR+0x1c);//For Mounting Board
++    writel(0xa7f0b7f0,GMAC_GLOBAL_BASE_ADDR+0x1c);//For Mounting Board
++
++    writel(0x77777777,GMAC_GLOBAL_BASE_ADDR+0x24);
++      writel(0x09200030,GMAC_GLOBAL_BASE_ADDR+0x2C);
++      val = readl(GMAC_GLOBAL_BASE_ADDR+0x04);
++      if((val&(1<<20))==0){           // GMAC1 enable
++              val = readl(GMAC_GLOBAL_BASE_ADDR+0x30);
++              val = (val & 0xe7ffffff) | 0x08000000;
++              writel(val,GMAC_GLOBAL_BASE_ADDR+0x30);
++      }
++}
++#endif
++
++#ifdef VITESSE_G5SWITCH
++      Giga_switch = SPI_get_identifier();
++      if(Giga_switch)
++              switch_port_no = SPI_default();
++#endif
++
++      chip_id = readl(GMAC_GLOBAL_BASE_ADDR+0x0);
++      if (chip_id == 0x3512C1)
++      {
++              writel(0x5787a5f0,GMAC_GLOBAL_BASE_ADDR+0x1c);//For 3512 Switch Board
++              writel(0x55557777,GMAC_GLOBAL_BASE_ADDR+0x20);//For 3512 Switch Board
++      }
++//#endif
++
++      mac_init_drv();
++
++      printk (KERN_INFO SL351x_DRIVER_NAME " built at %s %s\n", __DATE__, __TIME__);
++
++//    init_waitqueue_entry(&wait, current);
++
++      // printk("GMAC Init......\n");
++
++      i = 0;
++      for(j = 0; i<CONFIG_MAC_NUM; j++)
++      {
++              i=j;
++              if(Giga_switch){                // if gswitch present, swap eth0/1
++                      if(j==0)
++                              i=1;
++                      else if(j==1)
++                              i=0;
++              }
++
++              tp = (GMAC_INFO_T *)&toe_private_data.gmac[i];
++              tp->dev = NULL;
++              if (tp->existed != GMAC_EXISTED_FLAG) continue;
++
++              dev = alloc_etherdev(0);
++              if (dev == NULL)
++              {
++                      printk (KERN_ERR "Can't allocate ethernet device #%d .\n",i);
++                      return -ENOMEM;
++              }
++
++              dev->priv=tp;
++              tp->dev = dev;
++
++              SET_MODULE_OWNER(dev);
++
++              // spin_lock_init(&tp->lock);
++              spin_lock_init(&gmac_fq_lock);
++              dev->base_addr = tp->base_addr;
++              dev->irq = tp->irq;
++          dev->open = gmac_open;
++          dev->stop = gmac_close;
++              dev->hard_start_xmit = gmac_start_xmit;
++              dev->get_stats = gmac_get_stats;
++              dev->set_multicast_list = gmac_set_rx_mode;
++              dev->set_mac_address = gmac_set_mac_address;
++              dev->do_ioctl = gmac_netdev_ioctl;
++              dev->tx_timeout = gmac_tx_timeout;
++              dev->watchdog_timeo = GMAC_DEV_TX_TIMEOUT;
++#ifdef        L2_jumbo_frame
++              dev->mtu = 2018; //2002  ,2018
++#endif
++              if (tp->port_id == 0)
++                      dev->tx_queue_len = TOE_GMAC0_SWTXQ_DESC_NUM;
++              else
++                      dev->tx_queue_len = TOE_GMAC1_SWTXQ_DESC_NUM;
++
++#ifdef DO_HW_CHKSUM
++              dev->features |= NETIF_F_SG|NETIF_F_HW_CSUM;
++#ifdef ENABLE_TSO
++              dev->features |= NETIF_F_TSO;
++#endif
++#endif
++#ifdef CONFIG_SL_NAPI
++        dev->poll = gmac_rx_poll;
++        dev->weight = 64;
++#endif
++
++              if (register_netdev(dev))
++              {
++                      gmac_cleanup_module();
++                      return(-1);
++              }
++      }
++
++
++//    FLAG_SWITCH = 0 ;
++//    FLAG_SWITCH = SPI_get_identifier();
++//    if(FLAG_SWITCH)
++//    {
++//            printk("Configure ADM699X...\n");
++//            SPI_default();  //Add by jason for ADM699X configuration
++//    }
++      return (0);
++}
++
++/*----------------------------------------------------------------------
++*     gmac_cleanup_module
++*----------------------------------------------------------------------*/
++
++static void gmac_cleanup_module(void)
++{
++    int i;
++
++#ifdef SL351x_GMAC_WORKAROUND
++      del_timer(&gmac_workround_timer_obj);
++#endif
++
++    for (i=0;i<CONFIG_MAC_NUM;i++)
++    {
++      if (toe_private_data.gmac[i].dev)
++      {
++              unregister_netdev(toe_private_data.gmac[i].dev);
++              toe_private_data.gmac[i].dev = NULL;
++        }
++    }
++      return ;
++}
++
++module_init(gmac_init_module);
++module_exit(gmac_cleanup_module);
++
++
++/*----------------------------------------------------------------------
++*     gmac_read_reg
++*----------------------------------------------------------------------*/
++static inline unsigned int gmac_read_reg(unsigned int base, unsigned int offset)
++//static unsigned int gmac_read_reg(unsigned int base, unsigned int offset)
++{
++    volatile unsigned int reg_val;
++
++    reg_val = readl(base + offset);
++      return (reg_val);
++}
++
++/*----------------------------------------------------------------------
++*     gmac_write_reg
++*----------------------------------------------------------------------*/
++static inline void gmac_write_reg(unsigned int base, unsigned int offset,unsigned int data,unsigned int bit_mask)
++//static void gmac_write_reg(unsigned int base, unsigned int offset,unsigned int data,unsigned int bit_mask)
++{
++      volatile unsigned int reg_val;
++    unsigned int *addr;
++
++      reg_val = ( gmac_read_reg(base, offset) & (~bit_mask) ) | (data & bit_mask);
++      addr = (unsigned int *)(base + offset);
++    writel(reg_val,addr);
++      return;
++}
++
++/*----------------------------------------------------------------------
++*     mac_init_drv
++*----------------------------------------------------------------------*/
++void mac_init_drv(void)
++{
++      TOE_INFO_T                      *toe;
++      int                                     i;
++      QUEUE_THRESHOLD_T       threshold;
++      u32                                     *destp;
++      unsigned int            chip_id,chip_version;
++
++      chip_id = readl(GMAC_GLOBAL_BASE_ADDR+0x0);
++      chip_version = chip_id & 0x1 ;
++
++      if (!gmac_initialized)
++      {
++              gmac_initialized = 1;
++
++              // clear non TOE Queue Header Area
++              destp = (u32 *)TOE_NONTOE_QUE_HDR_BASE;
++              for (; destp < (u32 *)NONTOE_Q_HDR_AREA_END; destp++)
++                      *destp = 0x00;
++
++              // clear TOE Queue Header Area
++              destp = (u32 *)TOE_TOE_QUE_HDR_BASE;
++              for (; destp < (u32 *)TOE_Q_HDR_AREA_END; destp++)
++                      *destp = 0x00;
++
++              // init private data
++              toe = (TOE_INFO_T *)&toe_private_data;
++              memset((void *)toe, 0, sizeof(TOE_INFO_T));
++              toe->gmac[0].base_addr = GMAC0_BASE;
++              toe->gmac[1].base_addr = GMAC1_BASE;
++              toe->gmac[0].dma_base_addr = TOE_GMAC0_DMA_BASE;
++              toe->gmac[1].dma_base_addr = TOE_GMAC1_DMA_BASE;
++        toe->gmac[0].auto_nego_cfg = 1;
++        toe->gmac[1].auto_nego_cfg = 1;
++#ifdef CONFIG_SL3516_ASIC
++        toe->gmac[0].speed_cfg = GMAC_SPEED_1000;
++        toe->gmac[1].speed_cfg = GMAC_SPEED_1000;
++#else
++              toe->gmac[0].speed_cfg = GMAC_SPEED_100;
++        toe->gmac[1].speed_cfg = GMAC_SPEED_100;
++#endif
++        toe->gmac[0].full_duplex_cfg = 1;
++        toe->gmac[1].full_duplex_cfg = 1;
++#ifdef CONFIG_SL3516_ASIC
++        toe->gmac[0].phy_mode = GMAC_PHY_RGMII_1000;
++        toe->gmac[1].phy_mode = GMAC_PHY_RGMII_1000;
++#else
++              toe->gmac[0].phy_mode = GMAC_PHY_RGMII_100;
++        toe->gmac[1].phy_mode = GMAC_PHY_RGMII_100;
++#endif
++        toe->gmac[0].port_id = GMAC_PORT0;
++        toe->gmac[1].port_id = GMAC_PORT1;
++        toe->gmac[0].phy_addr = 0x1;
++        toe->gmac[1].phy_addr = 2;
++//      toe->gmac[0].irq = SL2312_INTERRUPT_GMAC0;
++              toe->gmac[0].irq =1;
++//      toe->gmac[1].irq = SL2312_INTERRUPT_GMAC1;
++              toe->gmac[1].irq =2;
++        toe->gmac[0].mac_addr1 = &eth_mac[0][0];
++        toe->gmac[1].mac_addr1 = &eth_mac[1][0];
++
++              for (i=0; i<CONFIG_MAC_NUM; i++)
++              {
++                      unsigned int data, phy_vendor;
++                      gmac_write_reg(toe->gmac[i].base_addr, GMAC_STA_ADD2, 0x55aa55aa, 0xffffffff);
++                      data = gmac_read_reg(toe->gmac[i].base_addr, GMAC_STA_ADD2);
++                      if (data == 0x55aa55aa)
++                      {
++#ifdef VITESSE_G5SWITCH
++                              if(Giga_switch && (i==1)){
++                                      toe->gmac[i].existed = GMAC_EXISTED_FLAG;
++                                      break;
++                              }
++#endif
++                              phy_vendor = gmac_get_phy_vendor(toe->gmac[i].phy_addr);
++                              if (phy_vendor != 0 && phy_vendor != 0xffffffff)
++                                      toe->gmac[i].existed = GMAC_EXISTED_FLAG;
++                      }
++              }
++
++              // Write GLOBAL_QUEUE_THRESHOLD_REG
++              threshold.bits32 = 0;
++              threshold.bits.swfq_empty = (TOE_SW_FREEQ_DESC_NUM > 256) ? 255 :
++                                                      TOE_SW_FREEQ_DESC_NUM/2;
++              threshold.bits.hwfq_empty = (TOE_HW_FREEQ_DESC_NUM > 256) ? 256/4 :
++                                                      TOE_HW_FREEQ_DESC_NUM/4;
++              threshold.bits.toe_class = (TOE_TOE_DESC_NUM > 256) ? 256/4 :
++                                                      TOE_TOE_DESC_NUM/4;
++              threshold.bits.intrq = (TOE_INTR_DESC_NUM > 256) ? 256/4 :
++                                                      TOE_INTR_DESC_NUM/4;
++              writel(threshold.bits32, TOE_GLOBAL_BASE + GLOBAL_QUEUE_THRESHOLD_REG);
++
++              FLAG_SWITCH = 0;
++              toe_gmac_sw_reset();
++              toe_init_free_queue();
++              toe_init_swtx_queue();
++#ifdef CONFIG_SL351x_NAT
++              toe_init_hwtx_queue();
++#endif
++              toe_init_default_queue();
++#ifdef CONFIG_SL351x_RXTOE
++              toe_init_interrupt_queue();
++#endif
++              toe_init_interrupt_config();
++
++#if defined(CONFIG_SL351x_NAT) || defined(CONFIG_SL351x_RXTOE)
++              sl351x_hash_init();
++#else
++      {
++              volatile u32 *dp1, *dp2, dword;
++
++              dp1 = (volatile u32 *) TOE_V_BIT_BASE;
++              dp2 = (volatile u32 *) TOE_A_BIT_BASE;
++
++              for (i=0; i<HASH_TOTAL_ENTRIES/32; i++)
++              {
++                      *dp1++ = 0;
++                      dword = *dp2++; // read-clear
++              }
++      }
++#endif
++      }
++
++#ifdef SL351x_GMAC_WORKAROUND
++#ifdef CONFIG_SL351x_NAT
++      sl351x_nat_workaround_init();
++#endif
++      init_timer(&gmac_workround_timer_obj);
++      if (chip_version == 1)
++      {
++              gmac_workround_timer_obj.expires = jiffies * 50;
++      }
++      else
++      {
++              gmac_workround_timer_obj.expires = jiffies + 2;
++      }
++      gmac_workround_timer_obj.data = (unsigned long)&gmac_workround_timer_obj;
++      gmac_workround_timer_obj.function = (void *)&sl351x_poll_gmac_hanged_status;
++      add_timer(&gmac_workround_timer_obj);
++#endif
++}
++
++/*----------------------------------------------------------------------
++*     toe_init_free_queue
++*     (1) Initialize the Free Queue Descriptor Base Address & size
++*             Register: TOE_GLOBAL_BASE + 0x0004
++*     (2) Initialize DMA Read/Write pointer for
++*             SW Free Queue and HW Free Queue
++*     (3)     Initialize DMA Descriptors for
++*             SW Free Queue and HW Free Queue,
++*----------------------------------------------------------------------*/
++static void toe_init_free_queue(void)
++{
++      int                             i;
++      TOE_INFO_T                      *toe;
++      DMA_RWPTR_T                     rwptr_reg;
++//    unsigned int            rwptr_addr;
++      unsigned int            desc_buf;
++      GMAC_RXDESC_T           *sw_desc_ptr;
++      struct sk_buff          *skb;
++#ifdef CONFIG_SL351x_NAT
++      GMAC_RXDESC_T           *desc_ptr;
++      unsigned int            buf_ptr;
++#endif
++
++      toe = (TOE_INFO_T *)&toe_private_data;
++      desc_buf = (unsigned int)DMA_MALLOC((TOE_SW_FREEQ_DESC_NUM * sizeof(GMAC_RXDESC_T)),
++                                              (dma_addr_t *)&toe->sw_freeq_desc_base_dma) ;
++      sw_desc_ptr = (GMAC_RXDESC_T *)desc_buf;
++      if (!desc_buf)
++      {
++              printk("%s::DMA_MALLOC fail !\n",__func__);
++              return;
++      }
++      memset((void *)desc_buf, 0, TOE_SW_FREEQ_DESC_NUM * sizeof(GMAC_RXDESC_T));
++
++      // DMA Queue Base & Size
++      writel((toe->sw_freeq_desc_base_dma & DMA_Q_BASE_MASK) | TOE_SW_FREEQ_DESC_POWER,
++                      TOE_GLOBAL_BASE + GLOBAL_SW_FREEQ_BASE_SIZE_REG);
++
++      // init descriptor base
++      toe->swfq_desc_base = desc_buf;
++
++      // SW Free Queue Read/Write Pointer
++      rwptr_reg.bits.wptr = TOE_SW_FREEQ_DESC_NUM - 1;
++      rwptr_reg.bits.rptr = 0;
++      toe->fq_rx_rwptr.bits32 = rwptr_reg.bits32;
++      writel(rwptr_reg.bits32, TOE_GLOBAL_BASE + GLOBAL_SWFQ_RWPTR_REG);
++
++      // SW Free Queue Descriptors
++      for (i=0; i<TOE_SW_FREEQ_DESC_NUM; i++)
++      {
++              sw_desc_ptr->word0.bits.buffer_size = SW_RX_BUF_SIZE;
++              sw_desc_ptr->word1.bits.sw_id = i;      // used to locate skb
++              if ( (skb = dev_alloc_skb(SW_RX_BUF_SIZE))==NULL)  /* allocate socket buffer */
++              {
++                      printk("%s::skb buffer allocation fail !\n",__func__); while(1);
++              }
++              REG32(skb->data) = (unsigned int)skb;
++              skb_reserve(skb, SKB_RESERVE_BYTES);
++              // toe->rx_skb[i] = skb;
++              sw_desc_ptr->word2.buf_adr = (unsigned int)__pa(skb->data);
++//            consistent_sync((unsigned int)desc_ptr, sizeof(GMAC_RXDESC_T), PCI_DMA_TODEVICE);
++              sw_desc_ptr++;
++      }
++
++#ifdef CONFIG_SL351x_NAT
++      if (sizeof(skb->cb) < 64)
++      {
++                      printk("==> %s:: sk structure is incorrect -->Change to cb[64] !\n",__func__); while(1);
++      }
++      // init hardware free queues
++      desc_buf = (unsigned int)DMA_MALLOC((TOE_HW_FREEQ_DESC_NUM * sizeof(GMAC_RXDESC_T)),
++                                              (dma_addr_t *)&toe->hw_freeq_desc_base_dma) ;
++      desc_ptr = (GMAC_RXDESC_T *)desc_buf;
++      if (!desc_buf)
++      {
++              printk("%s::DMA_MALLOC fail !\n",__func__);
++              return;
++      }
++      memset((void *)desc_buf, 0, TOE_HW_FREEQ_DESC_NUM * sizeof(GMAC_RXDESC_T));
++
++      // DMA Queue Base & Size
++      writel((toe->hw_freeq_desc_base_dma & DMA_Q_BASE_MASK) | TOE_HW_FREEQ_DESC_POWER,
++                      TOE_GLOBAL_BASE + GLOBAL_HW_FREEQ_BASE_SIZE_REG);
++
++      // init descriptor base
++      toe->hwfq_desc_base = desc_buf;
++
++      // HW Free Queue Read/Write Pointer
++      rwptr_reg.bits.wptr = TOE_HW_FREEQ_DESC_NUM - 1;
++      rwptr_reg.bits.rptr = 0;
++      writel(rwptr_reg.bits32, TOE_GLOBAL_BASE + GLOBAL_HWFQ_RWPTR_REG);
++#ifndef HW_RXBUF_BY_KMALLOC
++      buf_ptr = (unsigned int)DMA_MALLOC(TOE_HW_FREEQ_DESC_NUM * HW_RX_BUF_SIZE,
++                                              (dma_addr_t *)&toe->hwfq_buf_base_dma);
++#else
++      buf_ptr = (unsigned int)kmalloc(TOE_HW_FREEQ_DESC_NUM * HW_RX_BUF_SIZE, GFP_KERNEL);
++      toe->hwfq_buf_base_dma = __pa(buf_ptr);
++#endif
++      if (!buf_ptr)
++      {
++              printk("===> %s::Failed to allocate HW TxQ Buffers!\n",__func__);
++              while(1);       // could not be happened, if happened, adjust the buffer descriptor number
++              return;
++      }
++
++      toe->hwfq_buf_base = buf_ptr;
++      toe->hwfq_buf_end_dma = toe->hwfq_buf_base_dma + (TOE_HW_FREEQ_DESC_NUM * HW_RX_BUF_SIZE);
++      buf_ptr = (unsigned int)toe->hwfq_buf_base_dma;
++      for (i=0; i<TOE_HW_FREEQ_DESC_NUM; i++)
++      {
++              desc_ptr->word0.bits.buffer_size = HW_RX_BUF_SIZE;
++              desc_ptr->word1.bits.sw_id = i;
++              desc_ptr->word2.buf_adr = (unsigned int)buf_ptr;
++//            consistent_sync((unsigned int)desc_ptr, sizeof(GMAC_RXDESC_T), PCI_DMA_TODEVICE);
++              // consistent_sync((unsigned int)buf_ptr, HW_RX_BUF_SIZE, PCI_DMA_TODEVICE);
++              desc_ptr++;
++              buf_ptr += HW_RX_BUF_SIZE;
++      }
++#else
++      // DMA Queue Base & Size
++      writel((0) | TOE_SW_FREEQ_DESC_POWER,
++                      TOE_GLOBAL_BASE + GLOBAL_HW_FREEQ_BASE_SIZE_REG);
++      rwptr_reg.bits.wptr = TOE_HW_FREEQ_DESC_NUM - 1;
++      rwptr_reg.bits.rptr = 0;
++      writel(rwptr_reg.bits32, TOE_GLOBAL_BASE + GLOBAL_HWFQ_RWPTR_REG);
++
++#endif
++}
++/*----------------------------------------------------------------------
++*     toe_init_swtx_queue
++*     (2) Initialize the GMAC 0/1 SW TXQ Queue Descriptor Base Address & sizeup
++*             GMAC_SW_TX_QUEUE_BASE_REG(0x0050)
++*     (2) Initialize DMA Read/Write pointer for
++*             GMAC 0/1 SW TX Q0-5
++*----------------------------------------------------------------------*/
++static void toe_init_swtx_queue(void)
++{
++      int                             i;
++      TOE_INFO_T                      *toe;
++      DMA_RWPTR_T                     rwptr_reg;
++      unsigned int            rwptr_addr;
++      unsigned int            desc_buf;
++
++
++      toe = (TOE_INFO_T *)&toe_private_data;
++
++      // GMAC-0, SW-TXQ
++      // The GMAC-0 and GMAC-0 maybe have different descriptor number
++      // so, not use for instruction
++      desc_buf = (unsigned int)DMA_MALLOC((TOE_GMAC0_SWTXQ_DESC_NUM * TOE_SW_TXQ_NUM * sizeof(GMAC_TXDESC_T)),
++                                              (dma_addr_t *)&toe->gmac[0].swtxq_desc_base_dma) ;
++      toe->gmac[0].swtxq_desc_base = desc_buf;
++      if (!desc_buf)
++      {
++              printk("%s::DMA_MALLOC fail !\n",__func__);
++              return  ;
++      }
++      memset((void *)desc_buf, 0,     TOE_GMAC0_SWTXQ_DESC_NUM * TOE_SW_TXQ_NUM * sizeof(GMAC_TXDESC_T));
++      writel((toe->gmac[0].swtxq_desc_base_dma & DMA_Q_BASE_MASK) | TOE_GMAC0_SWTXQ_DESC_POWER,
++                      TOE_GMAC0_DMA_BASE+ GMAC_SW_TX_QUEUE_BASE_REG);
++
++      // GMAC0 SW TX Q0-Q5
++      rwptr_reg.bits.wptr = 0;
++      rwptr_reg.bits.rptr = 0;
++      rwptr_addr = TOE_GMAC0_DMA_BASE + GMAC_SW_TX_QUEUE0_PTR_REG;
++      for (i=0; i<TOE_SW_TXQ_NUM; i++)
++      {
++              toe->gmac[0].swtxq[i].rwptr_reg = rwptr_addr;
++              toe->gmac[0].swtxq[i].desc_base = desc_buf;
++              toe->gmac[0].swtxq[i].total_desc_num = TOE_GMAC0_SWTXQ_DESC_NUM;
++              desc_buf += TOE_GMAC0_SWTXQ_DESC_NUM * sizeof(GMAC_TXDESC_T);
++              writel(rwptr_reg.bits32, rwptr_addr);
++              rwptr_addr+=4;
++      }
++
++      // GMAC-1, SW-TXQ
++      desc_buf = (unsigned int)DMA_MALLOC((TOE_GMAC1_SWTXQ_DESC_NUM * TOE_SW_TXQ_NUM * sizeof(GMAC_TXDESC_T)),
++                                              (dma_addr_t *)&toe->gmac[1].swtxq_desc_base_dma) ;
++      toe->gmac[1].swtxq_desc_base = desc_buf;
++      if (!desc_buf)
++      {
++              printk("%s::DMA_MALLOC fail !\n",__func__);
++              return  ;
++      }
++      memset((void *)desc_buf, 0,     TOE_GMAC1_SWTXQ_DESC_NUM * TOE_SW_TXQ_NUM * sizeof(GMAC_TXDESC_T));
++      writel((toe->gmac[1].swtxq_desc_base_dma & DMA_Q_BASE_MASK) | TOE_GMAC1_SWTXQ_DESC_POWER,
++                      TOE_GMAC1_DMA_BASE+ GMAC_SW_TX_QUEUE_BASE_REG);
++
++
++      // GMAC1 SW TX Q0-Q5
++      rwptr_reg.bits.wptr = 0;
++      rwptr_reg.bits.rptr = 0;
++      rwptr_addr = TOE_GMAC1_DMA_BASE + GMAC_SW_TX_QUEUE0_PTR_REG;
++      for (i=0; i<TOE_SW_TXQ_NUM; i++)
++      {
++              toe->gmac[1].swtxq[i].rwptr_reg = rwptr_addr;
++              toe->gmac[1].swtxq[i].desc_base = desc_buf;
++              toe->gmac[1].swtxq[i].total_desc_num = TOE_GMAC1_SWTXQ_DESC_NUM;
++              desc_buf += TOE_GMAC1_SWTXQ_DESC_NUM * sizeof(GMAC_TXDESC_T);
++              writel(rwptr_reg.bits32, rwptr_addr);
++              rwptr_addr+=4;
++      }
++}
++
++/*----------------------------------------------------------------------
++*     toe_init_hwtx_queue
++*     (2) Initialize the GMAC 0/1 HW TXQ Queue Descriptor Base Address & size
++*             GMAC_HW_TX_QUEUE_BASE_REG(0x0054)
++*     (2) Initialize DMA Read/Write pointer for
++*             GMAC 0/1 HW TX Q0-5
++*----------------------------------------------------------------------*/
++#ifdef CONFIG_SL351x_NAT
++static void toe_init_hwtx_queue(void)
++{
++      int                             i;
++      TOE_INFO_T                      *toe;
++      DMA_RWPTR_T                     rwptr_reg;
++      unsigned int            rwptr_addr;
++      unsigned int            desc_buf;
++
++      toe = (TOE_INFO_T *)&toe_private_data;
++      // GMAC-0, HW-TXQ
++      // The GMAC-0 and GMAC-0 maybe have different descriptor number
++      // so, not use for instruction
++      desc_buf = (unsigned int)DMA_MALLOC((TOE_GMAC0_HWTXQ_DESC_NUM * TOE_HW_TXQ_NUM * sizeof(GMAC_TXDESC_T)),
++                                              (dma_addr_t *)&toe->gmac[0].hwtxq_desc_base_dma) ;
++      toe->gmac[0].hwtxq_desc_base = desc_buf;
++      if (!desc_buf)
++      {
++              printk("%s::DMA_MALLOC fail !\n",__func__);
++              return  ;
++      }
++      memset((void *)desc_buf, 0,     TOE_GMAC0_HWTXQ_DESC_NUM * TOE_HW_TXQ_NUM * sizeof(GMAC_TXDESC_T));
++      writel((toe->gmac[0].hwtxq_desc_base_dma & DMA_Q_BASE_MASK) | TOE_GMAC0_HWTXQ_DESC_POWER,
++                      TOE_GMAC0_DMA_BASE+ GMAC_HW_TX_QUEUE_BASE_REG);
++
++      // GMAC0 HW TX Q0-Q5
++      rwptr_reg.bits.wptr = 0;
++      rwptr_reg.bits.rptr = 0;
++      rwptr_addr = TOE_GMAC0_DMA_BASE + GMAC_HW_TX_QUEUE0_PTR_REG;
++      for (i=0; i<TOE_HW_TXQ_NUM; i++)
++      {
++              toe->gmac[0].hwtxq[i].desc_base = desc_buf;
++              desc_buf += TOE_GMAC0_HWTXQ_DESC_NUM * sizeof(GMAC_TXDESC_T);
++              writel(rwptr_reg.bits32, rwptr_addr);
++              rwptr_addr+=4;
++      }
++
++      // GMAC-1, HW-TXQ
++      desc_buf = (unsigned int)DMA_MALLOC((TOE_GMAC1_HWTXQ_DESC_NUM * TOE_HW_TXQ_NUM * sizeof(GMAC_TXDESC_T)),
++                                              (dma_addr_t *)&toe->gmac[1].hwtxq_desc_base_dma) ;
++      toe->gmac[1].hwtxq_desc_base = desc_buf;
++      if (!desc_buf)
++      {
++              printk("%s::DMA_MALLOC fail !\n",__func__);
++              return  ;
++      }
++      memset((void *)desc_buf, 0,     TOE_GMAC1_HWTXQ_DESC_NUM * TOE_HW_TXQ_NUM * sizeof(GMAC_TXDESC_T));
++      writel((toe->gmac[1].hwtxq_desc_base_dma & DMA_Q_BASE_MASK) | TOE_GMAC1_HWTXQ_DESC_POWER,
++                      TOE_GMAC1_DMA_BASE+ GMAC_HW_TX_QUEUE_BASE_REG);
++
++      // GMAC1 HW TX Q0-Q5
++      rwptr_reg.bits.wptr = 0;
++      rwptr_reg.bits.rptr = 0;
++      rwptr_addr = TOE_GMAC1_DMA_BASE + GMAC_HW_TX_QUEUE0_PTR_REG;
++      for (i=0; i<TOE_HW_TXQ_NUM; i++)
++      {
++              toe->gmac[1].hwtxq[i].desc_base = desc_buf;
++              desc_buf += TOE_GMAC1_HWTXQ_DESC_NUM * sizeof(GMAC_TXDESC_T);
++              writel(rwptr_reg.bits32, rwptr_addr);
++              rwptr_addr+=4;
++      }
++}
++#endif
++
++/*----------------------------------------------------------------------
++*     toe_init_default_queue
++*     (1) Initialize the default 0/1 Queue Header
++*             Register: TOE_DEFAULT_Q0_HDR_BASE (0x60002000)
++*                               TOE_DEFAULT_Q1_HDR_BASE (0x60002008)
++*     (2)     Initialize Descriptors of Default Queue 0/1
++*----------------------------------------------------------------------*/
++static void toe_init_default_queue(void)
++{
++      TOE_INFO_T                              *toe;
++      volatile NONTOE_QHDR_T  *qhdr;
++      GMAC_RXDESC_T                   *desc_ptr;
++      DMA_SKB_SIZE_T                  skb_size;
++
++      toe = (TOE_INFO_T *)&toe_private_data;
++      desc_ptr = (GMAC_RXDESC_T *)DMA_MALLOC((TOE_DEFAULT_Q0_DESC_NUM * sizeof(GMAC_RXDESC_T)),
++                                                                                      (dma_addr_t *)&toe->gmac[0].default_desc_base_dma);
++      if (!desc_ptr)
++      {
++              printk("%s::DMA_MALLOC fail !\n",__func__);
++              return  ;
++      }
++      memset((void *)desc_ptr, 0, TOE_DEFAULT_Q0_DESC_NUM * sizeof(GMAC_RXDESC_T));
++      toe->gmac[0].default_desc_base = (unsigned int)desc_ptr;
++      toe->gmac[0].default_desc_num = TOE_DEFAULT_Q0_DESC_NUM;
++      qhdr = (volatile NONTOE_QHDR_T *)TOE_DEFAULT_Q0_HDR_BASE;
++      qhdr->word0.base_size = ((unsigned int)toe->gmac[0].default_desc_base_dma & NONTOE_QHDR0_BASE_MASK) | TOE_DEFAULT_Q0_DESC_POWER;
++      qhdr->word1.bits32 = 0;
++      toe->gmac[0].rx_rwptr.bits32 = 0;
++      toe->gmac[0].default_qhdr = (NONTOE_QHDR_T *)qhdr;
++      desc_ptr = (GMAC_RXDESC_T *)DMA_MALLOC((TOE_DEFAULT_Q1_DESC_NUM * sizeof(GMAC_RXDESC_T)),
++                                                                                      (dma_addr_t *)&toe->gmac[1].default_desc_base_dma);
++      if (!desc_ptr)
++      {
++              printk("%s::DMA_MALLOC fail !\n",__func__);
++              return  ;
++      }
++      memset((void *)desc_ptr, 0, TOE_DEFAULT_Q1_DESC_NUM * sizeof(GMAC_RXDESC_T));
++      toe->gmac[1].default_desc_base = (unsigned int)desc_ptr;
++      toe->gmac[1].default_desc_num = TOE_DEFAULT_Q1_DESC_NUM;
++      qhdr = (volatile NONTOE_QHDR_T *)TOE_DEFAULT_Q1_HDR_BASE;
++      qhdr->word0.base_size = ((unsigned int)toe->gmac[1].default_desc_base_dma & NONTOE_QHDR0_BASE_MASK) | TOE_DEFAULT_Q1_DESC_POWER;
++      qhdr->word1.bits32 = 0;
++      toe->gmac[1].rx_rwptr.bits32 = 0;
++      toe->gmac[1].default_qhdr = (NONTOE_QHDR_T *)qhdr;
++
++      skb_size.bits.hw_skb_size = HW_RX_BUF_SIZE;
++      skb_size.bits.sw_skb_size = SW_RX_BUF_SIZE;
++      writel(skb_size.bits32, TOE_GLOBAL_BASE + GLOBAL_DMA_SKB_SIZE_REG);
++}
++
++/*----------------------------------------------------------------------
++*     toe_init_interrupt_queue
++*     (1) Initialize the Interrupt Queue Header
++*             Register: TOE_INTR_Q_HDR_BASE (0x60002080)
++*     (2)     Initialize Descriptors of Interrupt Queues
++*----------------------------------------------------------------------*/
++#ifdef CONFIG_SL351x_RXTOE
++static void toe_init_interrupt_queue(void)
++{
++      TOE_INFO_T                              *toe;
++      volatile NONTOE_QHDR_T  *qhdr;
++      INTR_QHDR_T                             *desc_ptr;
++      // unsigned int                 desc_buf_addr;
++      int                                             i;
++
++      toe = (TOE_INFO_T *)&toe_private_data;
++      desc_ptr = (INTR_QHDR_T *)DMA_MALLOC((TOE_INTR_QUEUE_NUM * TOE_INTR_DESC_NUM * sizeof(INTR_QHDR_T)),
++                                                                                      (dma_addr_t *)&toe->intr_desc_base_dma);
++      if (!desc_ptr)
++      {
++              printk("%s::DMA_MALLOC interrupt queue fail !\n",__func__);
++              return  ;
++      }
++      /*
++      desc_buf_addr = (unsigned int)DMA_MALLOC((TOE_INTR_DESC_NUM * sizeof(TOE_QHDR_T)),
++                                                                                              (dma_addr_t *)&toe->intr_buf_base_dma);
++      if (!desc_buf_addr)
++      {
++              printk("%s::DMA_MALLOC interrupt desc fail !\n",__func__);
++              return  ;
++      }*/
++      printk("#### %s::Intr Q desc %x\n", __func__, (u32)desc_ptr);
++
++      memset((void *)desc_ptr, 0, TOE_INTR_QUEUE_NUM * TOE_INTR_DESC_NUM * sizeof(INTR_QHDR_T));
++//    memset((void *)desc_buf_addr, 0, TOE_INTR_DESC_NUM * sizeof(TOE_QHDR_T));
++      toe->intr_desc_base = (unsigned int)desc_ptr;
++      toe->intr_desc_num = TOE_INTR_DESC_NUM;
++
++      qhdr = (volatile NONTOE_QHDR_T *)TOE_INTR_Q_HDR_BASE;
++//    intrq = (INTRQ_INFO_T*) &toe->intrq[0];
++      for (i=0; i<TOE_INTR_QUEUE_NUM; i++, qhdr++)
++      {
++              qhdr->word0.base_size = ((unsigned int)toe->intr_desc_base_dma & NONTOE_QHDR0_BASE_MASK) | TOE_INTR_DESC_POWER;
++              qhdr->word1.bits32 = 0;
++              desc_ptr += TOE_INTR_DESC_NUM;
++      }
++}
++
++#endif
++
++/*----------------------------------------------------------------------
++*     toe_init_interrupt_config
++*     Interrupt Select Registers are used to map interrupt to int0 or int1
++*     Int0 and int1 are wired to CPU 0/1 GMAC 0/1
++*     Interrupt Device Inteface data are used to pass device info to
++*             upper device deiver or store status/statistics
++*     ISR handler
++*             (1) If status bit ON but masked, the prinf error message (bug issue)
++*             (2) If select bits are for me, handle it, else skip to let
++*                     the other ISR handles it.
++*  Notes:
++*             GMACx init routine (for eCOS) or open routine (for Linux)
++*       enable the interrupt bits only which are selected for him.
++*
++*     Default Setting:
++*             GMAC0 intr bits ------> int0 ----> eth0
++*             GMAC1 intr bits ------> int1 ----> eth1
++*             TOE intr -------------> int0 ----> eth0
++*             Classification Intr --> int0 ----> eth0
++*             Default Q0 -----------> int0 ----> eth0
++*             Default Q1 -----------> int1 ----> eth1
++*----------------------------------------------------------------------*/
++static void toe_init_interrupt_config(void)
++{
++      // clear all status bits
++      writel(0xffffffff, TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_STATUS_0_REG);
++      writel(0xffffffff, TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_STATUS_1_REG);
++      writel(0xffffffff, TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_STATUS_2_REG);
++      writel(0xffffffff, TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_STATUS_3_REG);
++      writel(0xffffffff, TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_STATUS_4_REG);
++
++      // Init select registers
++      writel(0, TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_SELECT_0_REG);
++      writel(0, TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_SELECT_1_REG);
++      writel(0, TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_SELECT_2_REG);
++      writel(0, TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_SELECT_3_REG);
++      writel(0, TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_SELECT_4_REG);
++
++      // disable all interrupt
++      writel(0, TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_ENABLE_0_REG);
++      writel(0, TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_ENABLE_1_REG);
++      writel(0, TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_ENABLE_2_REG);
++      writel(0, TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_ENABLE_3_REG);
++      writel(0, TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_ENABLE_4_REG);
++}
++
++/*----------------------------------------------------------------------
++*     toe_init_gmac
++*----------------------------------------------------------------------*/
++static void toe_init_gmac(struct net_device *dev)
++{
++      GMAC_INFO_T             *tp = dev->priv;
++      TOE_INFO_T              *toe;
++      u32                     data;
++
++      if (!gmac_initialized)
++              return ;
++
++      if (!tp->existed)
++              return;
++
++      tp->dev = dev;
++      tp->flow_control_enable = 1;
++      tp->pre_phy_status = LINK_DOWN;
++      tp->full_duplex_status = tp->full_duplex_cfg;
++      tp->speed_status = tp->speed_status;
++
++#if 0
++   /* get mac address from FLASH */
++    gmac_get_mac_address();
++#endif
++
++    /* set PHY register to start autonegition process */
++    gmac_set_phy_status(dev);
++
++      /* GMAC initialization */
++      if ( toe_gmac_init_chip(dev) )
++      {
++              printk ("GMAC %d init fail\n", tp->port_id);
++      }
++
++    /* clear statistic counter */
++    toe_gmac_clear_counter(dev);
++
++      memset((void *)&tp->ifStatics, 0, sizeof(struct net_device_stats));
++
++      /* -----------------------------------------------------------
++      Enable GMAC interrupt & disable loopback
++      Notes:
++              GMACx init routine (for eCOS) or open routine (for Linux)
++              enable the interrupt bits only which are selected for him.
++      --------------------------------------------------------------*/
++      toe = (TOE_INFO_T *)&toe_private_data;
++
++      // Enable Interrupt Bits
++      if (tp->port_id == 0)
++      {
++              tp->intr0_selected =    GMAC0_TXDERR_INT_BIT     | GMAC0_TXPERR_INT_BIT         |
++                                      GMAC0_RXDERR_INT_BIT     | GMAC0_RXPERR_INT_BIT         |
++                                  GMAC0_SWTQ05_FIN_INT_BIT | GMAC0_SWTQ05_EOF_INT_BIT |
++                                  GMAC0_SWTQ04_FIN_INT_BIT | GMAC0_SWTQ04_EOF_INT_BIT |
++                                  GMAC0_SWTQ03_FIN_INT_BIT | GMAC0_SWTQ03_EOF_INT_BIT |
++                                  GMAC0_SWTQ02_FIN_INT_BIT | GMAC0_SWTQ02_EOF_INT_BIT |
++                                  GMAC0_SWTQ01_FIN_INT_BIT | GMAC0_SWTQ01_EOF_INT_BIT |
++                                  GMAC0_SWTQ00_FIN_INT_BIT | GMAC0_SWTQ00_EOF_INT_BIT;
++
++#ifdef GMAX_TX_INTR_DISABLED
++          tp->intr0_enabled =         0;
++#else
++          tp->intr0_enabled =         GMAC0_SWTQ00_FIN_INT_BIT | GMAC0_SWTQ00_EOF_INT_BIT;
++#endif
++
++          tp->intr1_selected =        TOE_IQ_ALL_BITS                  | TOE_CLASS_RX_INT_BITS        |
++                                                      GMAC0_HWTQ03_EOF_INT_BIT | GMAC0_HWTQ02_EOF_INT_BIT |
++                                                      GMAC0_HWTQ01_EOF_INT_BIT | GMAC0_HWTQ00_EOF_INT_BIT |
++                                                      DEFAULT_Q0_INT_BIT;
++          tp->intr1_enabled =         DEFAULT_Q0_INT_BIT | TOE_IQ_ALL_BITS;
++          tp->intr2_selected =        0xffffffff;      // TOE Queue 32-63 FUUL Intr
++          tp->intr2_enabled =         0xffffffff;
++          tp->intr3_selected =        0xffffffff;      // TOE Queue 0-31 FUUL Intr
++          tp->intr3_enabled =         0xffffffff;
++          tp->intr4_selected =        GMAC0_INT_BITS | CLASS_RX_FULL_INT_BITS |
++                                                      HWFQ_EMPTY_INT_BIT | SWFQ_EMPTY_INT_BIT;
++          tp->intr4_enabled =         GMAC0_INT_BITS | SWFQ_EMPTY_INT_BIT;
++
++          data = readl(TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_SELECT_0_REG) & ~tp->intr0_selected;
++          writel(data, TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_SELECT_0_REG);
++          data = readl(TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_SELECT_1_REG) & ~tp->intr1_selected;
++          writel(data, TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_SELECT_1_REG);
++          data = readl(TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_SELECT_2_REG) & ~tp->intr2_selected;
++          writel(data, TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_SELECT_2_REG);
++          data = readl(TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_SELECT_3_REG) & ~tp->intr3_selected;
++          writel(data, TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_SELECT_3_REG);
++          data = readl(TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_SELECT_4_REG) & ~tp->intr4_selected;
++          writel(data, TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_SELECT_4_REG);
++      }
++      else
++      {
++              tp->intr0_selected =    GMAC1_TXDERR_INT_BIT     | GMAC1_TXPERR_INT_BIT         |
++                                      GMAC1_RXDERR_INT_BIT     | GMAC1_RXPERR_INT_BIT         |
++                                  GMAC1_SWTQ15_FIN_INT_BIT | GMAC1_SWTQ15_EOF_INT_BIT |
++                                  GMAC1_SWTQ14_FIN_INT_BIT | GMAC1_SWTQ14_EOF_INT_BIT |
++                                  GMAC1_SWTQ13_FIN_INT_BIT | GMAC1_SWTQ13_EOF_INT_BIT |
++                                  GMAC1_SWTQ12_FIN_INT_BIT | GMAC1_SWTQ12_EOF_INT_BIT |
++                                  GMAC1_SWTQ11_FIN_INT_BIT | GMAC1_SWTQ11_EOF_INT_BIT |
++                                  GMAC1_SWTQ10_FIN_INT_BIT | GMAC1_SWTQ10_EOF_INT_BIT;
++#ifdef GMAX_TX_INTR_DISABLED
++          tp->intr0_enabled =         0;
++#else
++          tp->intr0_enabled =         GMAC1_SWTQ10_FIN_INT_BIT | GMAC1_SWTQ10_EOF_INT_BIT;
++#endif
++
++          tp->intr1_selected =        DEFAULT_Q1_INT_BIT;
++          tp->intr1_enabled =         DEFAULT_Q1_INT_BIT | TOE_IQ_ALL_BITS;
++          tp->intr2_selected =        0;       // TOE Queue 32-63 FUUL Intr
++          tp->intr2_enabled =         0;
++          tp->intr3_selected =        0;       // TOE Queue 0-31 FUUL Intr
++          tp->intr3_enabled =         0;
++          tp->intr4_selected =        GMAC1_INT_BITS;
++          tp->intr4_enabled =         GMAC1_INT_BITS;
++
++          if (toe->gmac[0].existed != GMAC_EXISTED_FLAG)
++          {
++              tp->intr1_selected      |=      TOE_IQ_ALL_BITS | TOE_CLASS_RX_INT_BITS |
++                                                              GMAC0_HWTQ03_EOF_INT_BIT | GMAC0_HWTQ02_EOF_INT_BIT |
++                                                              GMAC0_HWTQ01_EOF_INT_BIT | GMAC0_HWTQ00_EOF_INT_BIT;
++              tp->intr1_enabled       |=      TOE_IQ_ALL_BITS;
++              tp->intr2_selected      |=      0xffffffff;      // TOE Queue 32-63 FUUL Intr
++              tp->intr2_enabled       |=      0xffffffff;
++              tp->intr3_selected      |=      0xffffffff;      // TOE Queue 0-31 FUUL Intr
++              tp->intr3_enabled       |=      0xffffffff;
++              tp->intr4_selected      |=      CLASS_RX_FULL_INT_BITS |
++                                                              HWFQ_EMPTY_INT_BIT | SWFQ_EMPTY_INT_BIT;
++              tp->intr4_enabled       |=      SWFQ_EMPTY_INT_BIT;
++              }
++          data = readl(TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_SELECT_0_REG) | tp->intr0_selected;
++          writel(data, TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_SELECT_0_REG);
++          data = readl(TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_SELECT_1_REG) | tp->intr1_selected;
++          writel(data, TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_SELECT_1_REG);
++          data = readl(TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_SELECT_2_REG) | tp->intr2_selected;
++          writel(data, TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_SELECT_2_REG);
++          data = readl(TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_SELECT_3_REG) | tp->intr3_selected;
++          writel(data, TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_SELECT_3_REG);
++          data = readl(TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_SELECT_4_REG) | tp->intr4_selected;
++          writel(data, TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_SELECT_4_REG);
++      }
++
++      // enable only selected bits
++      gmac_write_reg(TOE_GLOBAL_BASE, GLOBAL_INTERRUPT_ENABLE_0_REG,
++                                      tp->intr0_enabled, tp->intr0_selected);
++      gmac_write_reg(TOE_GLOBAL_BASE, GLOBAL_INTERRUPT_ENABLE_1_REG,
++                                      tp->intr1_enabled, tp->intr1_selected);
++      gmac_write_reg(TOE_GLOBAL_BASE, GLOBAL_INTERRUPT_ENABLE_2_REG,
++                                      tp->intr2_enabled, tp->intr2_selected);
++      gmac_write_reg(TOE_GLOBAL_BASE, GLOBAL_INTERRUPT_ENABLE_3_REG,
++                                      tp->intr3_enabled, tp->intr3_selected);
++      gmac_write_reg(TOE_GLOBAL_BASE, GLOBAL_INTERRUPT_ENABLE_4_REG,
++                                      tp->intr4_enabled, tp->intr4_selected);
++
++    /* start DMA process */
++      toe_gmac_hw_start(dev);
++
++    /* enable tx/rx register */
++    toe_gmac_enable_tx_rx(dev);
++
++//    toe_gmac_enable_interrupt(tp->irq);
++
++    return ;
++}
++
++
++/*----------------------------------------------------------------------
++* toe_gmac_sw_reset
++*----------------------------------------------------------------------*/
++static void toe_gmac_sw_reset(void)
++{
++      unsigned int    reg_val;
++      reg_val = readl(GMAC_GLOBAL_BASE_ADDR+GLOBAL_RESET_REG) | 0x00000060;   /* GMAC0 S/W reset */
++    writel(reg_val,GMAC_GLOBAL_BASE_ADDR+GLOBAL_RESET_REG);
++    udelay(100);
++    return;
++}
++
++/*----------------------------------------------------------------------
++*     toe_gmac_init_chip
++*----------------------------------------------------------------------*/
++static int toe_gmac_init_chip(struct net_device *dev)
++{
++      GMAC_INFO_T     *tp = dev->priv;
++      GMAC_CONFIG2_T  config2_val;
++      GMAC_CONFIG0_T  config0,config0_mask;
++      GMAC_CONFIG1_T  config1;
++      #ifdef CONFIG_SL351x_NAT
++      GMAC_CONFIG3_T  config3_val;
++      #endif
++      GMAC_TX_WCR0_T  hw_weigh;
++      GMAC_TX_WCR1_T  sw_weigh;
++//    GMAC_HASH_ENABLE_REG0_T hash_ctrl;
++//
++#if 0 /* mac address will be set in late_initcall */
++      struct sockaddr sock;
++      // GMAC_AHB_WEIGHT_T    ahb_weight, ahb_weight_mask;
++
++
++      /* set station MAC address1 and address2 */
++      memcpy(&sock.sa_data[0],&eth_mac[tp->port_id][0],6);
++      gmac_set_mac_address(dev,(void *)&sock);
++#endif
++
++      /* set RX_FLTR register to receive all multicast packet */
++      gmac_write_reg(tp->base_addr, GMAC_RX_FLTR, 0x00000007,0x0000001f);
++      //    gmac_write_reg(tp->base_addr, GMAC_RX_FLTR, 0x00000007,0x0000001f);
++      //gmac_write_reg(tp->base_addr, GMAC_RX_FLTR,0x00000007,0x0000001f);
++
++      /* set per packet buffer size */
++      //      config1.bits32 = 0x002004;      //next version
++      /* set flow control threshold */
++      config1.bits32 = 0;
++      config1.bits.set_threshold = 32 / 2;
++      config1.bits.rel_threshold = 32 / 4 * 3;
++      gmac_write_reg(tp->base_addr, GMAC_CONFIG1, config1.bits32, 0xffffffff);
++
++      /* set flow control threshold */
++      config2_val.bits32 = 0;
++      config2_val.bits.set_threshold = TOE_SW_FREEQ_DESC_NUM/2;
++      config2_val.bits.rel_threshold = TOE_SW_FREEQ_DESC_NUM*3/4;
++      gmac_write_reg(tp->base_addr, GMAC_CONFIG2, config2_val.bits32,0xffffffff);
++
++      #ifdef CONFIG_SL351x_NAT
++      /* set HW free queue flow control threshold */
++      config3_val.bits32 = 0;
++      config3_val.bits.set_threshold = PAUSE_SET_HW_FREEQ;
++      config3_val.bits.rel_threshold = PAUSE_REL_HW_FREEQ;
++      gmac_write_reg(tp->base_addr, GMAC_CONFIG3, config3_val.bits32,0xffffffff);
++      #endif
++      /* set_mcast_filter mask*/
++      //      gmac_write_reg(tp->base_addr,GMAC_MCAST_FIL0,0x0,0xffffffff);
++      //  gmac_write_reg(tp->base_addr,GMAC_MCAST_FIL1,0x0,0xffffffff);
++
++      /* disable TX/RX and disable internal loop back */
++      config0.bits32 = 0;
++      config0_mask.bits32 = 0;
++
++      //debug_Aaron
++#ifdef        L2_jumbo_frame
++      config0.bits.max_len = 5;
++#else
++      config0.bits.max_len = 2;
++#endif
++
++      if (tp->flow_control_enable==1)
++      {
++              config0.bits.tx_fc_en = 1; /* enable tx flow control */
++              config0.bits.rx_fc_en = 1; /* enable rx flow control */
++              printk("Enable MAC Flow Control...\n");
++      }
++      else
++      {
++              config0.bits.tx_fc_en = 0; /* disable tx flow control */
++              config0.bits.rx_fc_en = 0; /* disable rx flow control */
++              printk("Disable MAC Flow Control...\n");
++      }
++      config0.bits.dis_rx = 1;  /* disable rx */
++      config0.bits.dis_tx = 1;  /* disable tx */
++      config0.bits.loop_back = 0; /* enable/disable GMAC loopback */
++      config0.bits.rx_err_detect = 1;
++      config0.bits.rgmii_en = 0;
++      config0.bits.rgmm_edge = 1;
++      config0.bits.rxc_inv = 0;
++      config0.bits.ipv4_rx_chksum = 1;  /* enable H/W to check ip checksum */
++      config0.bits.ipv6_rx_chksum = 1;  /* enable H/W to check ip checksum */
++      config0.bits.port0_chk_hwq = 1; // GaryChen 3/24/2006 2:26PM
++      config0.bits.port1_chk_hwq = 1; // GaryChen 3/24/2006 2:26PM
++      config0.bits.port0_chk_toeq = 1;
++      config0.bits.port1_chk_toeq = 1;
++      config0.bits.port0_chk_classq = 1;
++      config0.bits.port1_chk_classq = 1;
++
++      config0_mask.bits.max_len = 7;
++      config0_mask.bits.tx_fc_en = 1;
++      config0_mask.bits.rx_fc_en = 1;
++      config0_mask.bits.dis_rx = 1;
++      config0_mask.bits.dis_tx = 1;
++      config0_mask.bits.loop_back = 1;
++      config0_mask.bits.rgmii_en = 1;
++      config0_mask.bits.rgmm_edge = 1;
++      config0_mask.bits.rxc_inv = 1;
++      config0_mask.bits.ipv4_rx_chksum = 1;
++      config0_mask.bits.ipv6_rx_chksum = 1;
++      config0_mask.bits.port0_chk_hwq = 1;
++      config0_mask.bits.port1_chk_hwq = 1;
++      config0_mask.bits.port0_chk_toeq = 1;
++      config0_mask.bits.port1_chk_toeq = 1;
++      config0_mask.bits.port0_chk_classq = 1;
++      config0_mask.bits.port1_chk_classq = 1;
++      config0_mask.bits.rx_err_detect = 1;
++
++      #if 0
++      config0.bits.dis_rx = 1;  /* disable rx */
++      config0.bits.dis_tx = 1;  /* disable tx */
++      config0.bits.loop_back = 0; /* enable/disable GMAC loopback */
++      config0.bits.txc_inv = 0;
++      config0.bits.rgmii_en = 0;
++      config0.bits.rgmm_edge = 1;
++      config0.bits.rxc_inv = 1;
++      config0.bits.ipv4_tss_rx_en = 1;  /* enable H/W to check ip checksum */
++      config0.bits.ipv6_tss_rx_en = 1;  /* enable H/W to check ip checksum */
++
++      config0_mask.bits.max_len = 3;
++      config0_mask.bits.tx_fc_en = 1;
++      config0_mask.bits.rx_fc_en = 1;
++      config0_mask.bits.dis_rx = 1;
++      config0_mask.bits.dis_tx = 1;
++      config0_mask.bits.loop_back = 1;
++      config0_mask.bits.rgmii_en = 1;
++      config0_mask.bits.rgmm_edge = 1;
++      config0_mask.bits.txc_inv = 1;
++      config0_mask.bits.rxc_inv = 1;
++      config0_mask.bits.ipv4_tss_rx_en = 1;
++      config0_mask.bits.ipv6_tss_rx_en = 1;
++      #endif
++
++      gmac_write_reg(tp->base_addr, GMAC_CONFIG0, config0.bits32,config0_mask.bits32);
++
++      #if 1
++      hw_weigh.bits32 = 0;
++      hw_weigh.bits.hw_tq3 = 1;
++      hw_weigh.bits.hw_tq2 = 1;
++      hw_weigh.bits.hw_tq1 = 1;
++      hw_weigh.bits.hw_tq0 = 1;
++      gmac_write_reg(tp->dma_base_addr, GMAC_TX_WEIGHTING_CTRL_0_REG, hw_weigh.bits32, 0xffffffff);
++
++      sw_weigh.bits32 = 0;
++      sw_weigh.bits.sw_tq5 = 1;
++      sw_weigh.bits.sw_tq4 = 1;
++      sw_weigh.bits.sw_tq3 = 1;
++      sw_weigh.bits.sw_tq2 = 1;
++      sw_weigh.bits.sw_tq1 = 1;
++      sw_weigh.bits.sw_tq0 = 1;
++      gmac_write_reg(tp->dma_base_addr, GMAC_TX_WEIGHTING_CTRL_1_REG, sw_weigh.bits32, 0xffffffff);
++      #endif
++
++      #if 0
++      ahb_weight.bits32 = 0;
++      ahb_weight_mask.bits32 = 0;
++      ahb_weight.bits.rx_weight = 1;
++      ahb_weight.bits.tx_weight = 1;
++      ahb_weight.bits.hash_weight = 1;
++      ahb_weight.bits.pre_req = 0x1f;
++      ahb_weight.bits.tqDV_threshold = 0;
++      ahb_weight_mask.bits.rx_weight = 0x1f;
++      ahb_weight_mask.bits.tx_weight = 0x1f;
++      ahb_weight_mask.bits.hash_weight = 0x1f;
++      ahb_weight_mask.bits.pre_req = 0x1f;
++      ahb_weight_mask.bits.tqDV_threshold = 0x1f;
++      gmac_write_reg(tp->dma_base_addr, GMAC_AHB_WEIGHT_REG, ahb_weight.bits32, ahb_weight_mask.bits32);
++      #endif
++
++      #if defined(CONFIG_SL351x_NAT) || defined(CONFIG_SL351x_RXTOE)
++      gmac_write_reg(tp->dma_base_addr, GMAC_SPR0, IPPROTO_TCP, 0xffffffff);
++      #endif
++      #ifdef CONFIG_SL351x_NAT
++      gmac_write_reg(tp->dma_base_addr, GMAC_SPR1, IPPROTO_UDP, 0xffffffff);
++      gmac_write_reg(tp->dma_base_addr, GMAC_SPR2, IPPROTO_GRE, 0xffffffff);
++      gmac_write_reg(tp->dma_base_addr, GMAC_SPR3, 0xff, 0xffffffff);
++      gmac_write_reg(tp->dma_base_addr, GMAC_SPR4, 0xff, 0xffffffff);
++      gmac_write_reg(tp->dma_base_addr, GMAC_SPR5, 0xff, 0xffffffff);
++      gmac_write_reg(tp->dma_base_addr, GMAC_SPR6, 0xff, 0xffffffff);
++      gmac_write_reg(tp->dma_base_addr, GMAC_SPR7, 0xff, 0xffffffff);
++
++      sl351x_nat_init();
++      #endif
++
++      #ifdef CONFIG_SL351x_RXTOE
++      /* setup matching rule to TOE */
++      sl351x_toe_init();
++      #endif
++
++      // for A1 ASIC version
++//    hash_ctrl.bits32 = 0;
++//    hash_ctrl.bits.timing = 6;
++//    gmac_write_reg(tp->dma_base_addr, GMAC_HASH_ENGINE_REG0, hash_ctrl.bits32, 0xffffffff);
++
++      return (0);
++}
++
++/*----------------------------------------------------------------------
++*     toe_gmac_enable_tx_rx
++*----------------------------------------------------------------------*/
++static void toe_gmac_enable_tx_rx(struct net_device *dev)
++{
++      GMAC_INFO_T             *tp = dev->priv;
++      GMAC_CONFIG0_T  config0,config0_mask;
++
++    /* enable TX/RX */
++    config0.bits32 = 0;
++    config0_mask.bits32 = 0;
++    config0.bits.dis_rx = 0;  /* enable rx */
++    config0.bits.dis_tx = 0;  /* enable tx */
++    config0_mask.bits.dis_rx = 1;
++    config0_mask.bits.dis_tx = 1;
++    gmac_write_reg(tp->base_addr, GMAC_CONFIG0, config0.bits32,config0_mask.bits32);
++}
++/*----------------------------------------------------------------------
++*     toe_gmac_disable_rx
++*----------------------------------------------------------------------*/
++#if 0
++static void toe_gmac_disable_rx(struct net_device *dev)
++{
++      GMAC_INFO_T             *tp = dev->priv;
++      GMAC_CONFIG0_T  config0,config0_mask;
++
++    /* enable TX/RX */
++    config0.bits32 = 0;
++    config0_mask.bits32 = 0;
++    config0.bits.dis_rx = 1;  /* disable rx */
++//    config0.bits.dis_tx = 1;  /* disable tx */
++    config0_mask.bits.dis_rx = 1;
++//     config0_mask.bits.dis_tx = 1;
++    gmac_write_reg(tp->base_addr, GMAC_CONFIG0, config0.bits32,config0_mask.bits32);
++}
++#endif
++/*----------------------------------------------------------------------
++*     toe_gmac_enable_rx
++*----------------------------------------------------------------------*/
++#if 0
++static void toe_gmac_enable_rx(struct net_device *dev)
++{
++      GMAC_INFO_T             *tp = dev->priv;
++      GMAC_CONFIG0_T  config0,config0_mask;
++
++    /* enable TX/RX */
++    config0.bits32 = 0;
++    config0_mask.bits32 = 0;
++    config0.bits.dis_rx = 0;  /* enable rx */
++//    config0.bits.dis_tx = 0;  /* enable tx */
++    config0_mask.bits.dis_rx = 1;
++//    config0_mask.bits.dis_tx = 1;
++    gmac_write_reg(tp->base_addr, GMAC_CONFIG0, config0.bits32,config0_mask.bits32);
++}
++#endif
++/*----------------------------------------------------------------------
++*     toe_gmac_disable_tx_rx
++*----------------------------------------------------------------------*/
++static void toe_gmac_disable_tx_rx(struct net_device *dev)
++{
++      GMAC_INFO_T             *tp = dev->priv;
++      GMAC_CONFIG0_T  config0,config0_mask;
++
++    /* enable TX/RX */
++    config0.bits32 = 0;
++    config0_mask.bits32 = 0;
++    config0.bits.dis_rx = 1;  /* disable rx */
++    config0.bits.dis_tx = 1;  /* disable tx */
++    config0_mask.bits.dis_rx = 1;
++    config0_mask.bits.dis_tx = 1;
++    gmac_write_reg(tp->base_addr, GMAC_CONFIG0, config0.bits32,config0_mask.bits32);
++}
++
++/*----------------------------------------------------------------------
++*     toe_gmac_hw_start
++*----------------------------------------------------------------------*/
++static void toe_gmac_hw_start(struct net_device *dev)
++{
++      GMAC_INFO_T                             *tp = (GMAC_INFO_T *)dev->priv;
++      GMAC_DMA_CTRL_T                 dma_ctrl, dma_ctrl_mask;
++
++
++    /* program dma control register */
++      dma_ctrl.bits32 = 0;
++      dma_ctrl.bits.rd_enable = 1;
++      dma_ctrl.bits.td_enable = 1;
++      dma_ctrl.bits.loopback = 0;
++      dma_ctrl.bits.drop_small_ack = 0;
++      dma_ctrl.bits.rd_prot = 0;
++      dma_ctrl.bits.rd_burst_size = 3;
++      dma_ctrl.bits.rd_insert_bytes = RX_INSERT_BYTES;
++      dma_ctrl.bits.rd_bus = 3;
++      dma_ctrl.bits.td_prot = 0;
++      dma_ctrl.bits.td_burst_size = 3;
++      dma_ctrl.bits.td_bus = 3;
++
++      dma_ctrl_mask.bits32 = 0;
++      dma_ctrl_mask.bits.rd_enable = 1;
++      dma_ctrl_mask.bits.td_enable = 1;
++      dma_ctrl_mask.bits.loopback = 1;
++      dma_ctrl_mask.bits.drop_small_ack = 1;
++      dma_ctrl_mask.bits.rd_prot = 3;
++      dma_ctrl_mask.bits.rd_burst_size = 3;
++      dma_ctrl_mask.bits.rd_insert_bytes = 3;
++      dma_ctrl_mask.bits.rd_bus = 3;
++      dma_ctrl_mask.bits.td_prot = 0x0f;
++      dma_ctrl_mask.bits.td_burst_size = 3;
++      dma_ctrl_mask.bits.td_bus = 3;
++
++      gmac_write_reg(tp->dma_base_addr, GMAC_DMA_CTRL_REG, dma_ctrl.bits32, dma_ctrl_mask.bits32);
++
++    return;
++}
++
++/*----------------------------------------------------------------------
++*     toe_gmac_hw_stop
++*----------------------------------------------------------------------*/
++static void toe_gmac_hw_stop(struct net_device *dev)
++{
++      GMAC_INFO_T                     *tp = (GMAC_INFO_T *)dev->priv;
++      GMAC_DMA_CTRL_T         dma_ctrl, dma_ctrl_mask;
++
++    /* program dma control register */
++      dma_ctrl.bits32 = 0;
++      dma_ctrl.bits.rd_enable = 0;
++      dma_ctrl.bits.td_enable = 0;
++
++      dma_ctrl_mask.bits32 = 0;
++      dma_ctrl_mask.bits.rd_enable = 1;
++      dma_ctrl_mask.bits.td_enable = 1;
++
++      gmac_write_reg(tp->dma_base_addr, GMAC_DMA_CTRL_REG, dma_ctrl.bits32, dma_ctrl_mask.bits32);
++}
++
++/*----------------------------------------------------------------------
++*     toe_gmac_clear_counter
++*----------------------------------------------------------------------*/
++static int toe_gmac_clear_counter (struct net_device *dev)
++{
++      GMAC_INFO_T     *tp = (GMAC_INFO_T *)dev->priv;
++
++    /* clear counter */
++    gmac_read_reg(tp->base_addr, GMAC_IN_DISCARDS);
++    gmac_read_reg(tp->base_addr, GMAC_IN_ERRORS);
++    gmac_read_reg(tp->base_addr, GMAC_IN_MCAST);
++    gmac_read_reg(tp->base_addr, GMAC_IN_BCAST);
++    gmac_read_reg(tp->base_addr, GMAC_IN_MAC1);
++    gmac_read_reg(tp->base_addr, GMAC_IN_MAC2);
++              tp->ifStatics.tx_bytes = 0;
++              tp->ifStatics.tx_packets = 0;
++              tp->ifStatics.tx_errors = 0;
++              tp->ifStatics.rx_bytes = 0;
++              tp->ifStatics.rx_packets = 0;
++              tp->ifStatics.rx_errors = 0;
++              tp->ifStatics.rx_dropped = 0;
++      return (0);
++}
++
++
++/*----------------------------------------------------------------------
++*     toe_gmac_tx_complete
++*----------------------------------------------------------------------*/
++static  void toe_gmac_tx_complete(GMAC_INFO_T *tp, unsigned int tx_qid,
++                                                                              struct net_device *dev, int interrupt)
++{
++      volatile GMAC_TXDESC_T  *curr_desc;
++      GMAC_TXDESC_0_T                 word0;
++      GMAC_TXDESC_1_T                 word1;
++      unsigned int                    desc_count;
++//    struct net_device_stats *isPtr = (struct net_device_stats *)&tp->ifStatics;
++      GMAC_SWTXQ_T                    *swtxq;
++      DMA_RWPTR_T                             rwptr;
++
++      /* get tx H/W completed descriptor virtual address */
++      /* check tx status and accumulate tx statistics */
++      swtxq = &tp->swtxq[tx_qid];
++      swtxq->intr_cnt++;
++      for (;;)
++      {
++              rwptr.bits32 = readl(swtxq->rwptr_reg);
++              if (rwptr.bits.rptr == swtxq->finished_idx)
++                      break;
++      curr_desc = (volatile GMAC_TXDESC_T *)swtxq->desc_base + swtxq->finished_idx;
++//            consistent_sync((void *)curr_desc, sizeof(GMAC_TXDESC_T), PCI_DMA_FROMDEVICE);
++              word0.bits32 = curr_desc->word0.bits32;
++              word1.bits32 = curr_desc->word1.bits32;
++
++              if (word0.bits.status_tx_ok)
++              {
++                      tp->ifStatics.tx_bytes += word1.bits.byte_count;
++                      desc_count = word0.bits.desc_count;
++                      if (desc_count==0)
++                      {
++                              printk("%s::Desc 0x%x = 0x%x, desc_count=%d\n",__func__, (u32)curr_desc, word0.bits32, desc_count);
++                              while(1);
++                      }
++                      while (--desc_count)
++                      {
++                              word0.bits.status_tx_ok = 0;
++                              curr_desc->word0.bits32 = word0.bits32;
++                              swtxq->finished_idx = RWPTR_ADVANCE_ONE(swtxq->finished_idx, swtxq->total_desc_num);
++                              curr_desc = (GMAC_TXDESC_T *)swtxq->desc_base + swtxq->finished_idx;
++                              word0.bits32 = curr_desc->word0.bits32;
++#ifdef _DUMP_TX_TCP_CONTENT
++                              if (curr_desc->word0.bits.buffer_size < 16)
++                              {
++                                      int a;
++                                      char *datap;
++                                      printk("\t Tx Finished Desc 0x%x Len %d Addr 0x%08x: ", (u32)curr_desc, curr_desc->word0.bits.buffer_size, curr_desc->word2.buf_adr);
++                                      datap = (char *)__va(curr_desc->word2.buf_adr);
++                                      for (a=0; a<8 && a<curr_desc->word0.bits.buffer_size; a++, datap++)
++                                      {
++                                              printk("0x%02x ", *datap);
++                                      }
++                                      printk("\n");
++                              }
++#endif
++                      }
++
++                      word0.bits.status_tx_ok = 0;
++                      if (swtxq->tx_skb[swtxq->finished_idx])
++                      {
++                              if (interrupt)
++                                      dev_kfree_skb_irq(swtxq->tx_skb[swtxq->finished_idx]);
++                              else
++                                      dev_kfree_skb(swtxq->tx_skb[swtxq->finished_idx]);
++                              swtxq->tx_skb[swtxq->finished_idx] = NULL;
++                      }
++                      curr_desc->word0.bits32 = word0.bits32;
++                      swtxq->curr_finished_desc = (GMAC_TXDESC_T *)curr_desc;
++                      swtxq->total_finished++;
++                      tp->ifStatics.tx_packets++;
++                      swtxq->finished_idx = RWPTR_ADVANCE_ONE(swtxq->finished_idx, swtxq->total_desc_num);
++              }
++              else
++              {
++                      // tp->ifStatics.tx_errors++;
++                      // printk("%s::Tx Descriptor is !!!\n",__func__);
++                      // wait ready by breaking
++                      break;
++              }
++      }
++
++      if (netif_queue_stopped(dev))
++      {
++              netif_wake_queue(dev);
++      }
++}
++
++/*----------------------------------------------------------------------
++*     gmac_start_xmit
++*----------------------------------------------------------------------*/
++static int gmac_start_xmit(struct sk_buff *skb, struct net_device *dev)
++{
++      GMAC_INFO_T                     *tp= dev->priv;
++//    static unsigned int     pcount = 0;
++//    unsigned int                    tx_qid;
++    DMA_RWPTR_T                               rwptr;
++      volatile GMAC_TXDESC_T  *curr_desc;
++      int                                     snd_pages = skb_shinfo(skb)->nr_frags + 1;  /* get number of descriptor */
++      int                                     frag_id = 0;
++      int                                     len, total_len = skb->len;
++      struct net_device_stats *isPtr;
++      unsigned int                    free_desc;
++      GMAC_SWTXQ_T                    *swtxq;
++      register unsigned long  word0, word1, word2, word3;
++      unsigned short                  wptr, rptr;
++#ifdef        L2_jumbo_frame
++      int header_len = skb->len;
++      struct iphdr    *ip_hdr;
++    struct tcphdr     *tcp_hdr;
++    int             tcp_hdr_len;
++    unsigned char     *ptr;
++    int             data_len,a;
++    unsigned int    val;
++#endif
++
++#ifdef GMAC_LEN_1_2_ISSUE
++      int                                             total_pages;
++      total_pages = snd_pages;
++#endif
++
++      isPtr = (struct net_device_stats *)&tp->ifStatics;
++#if 1
++      if (skb->len >= 0x10000)
++      {
++//            spin_unlock(&tp->tx_mutex);
++              isPtr->tx_dropped++;
++              printk("%s::[GMAC %d] skb->len %d >= 64K\n", __func__, tp->port_id, skb->len);
++              netif_stop_queue(dev);
++              return 1;
++    }
++#endif
++
++#if 0
++      if (storlink_ctl.recvfile==2)
++      {
++          printk("snd_pages=%d skb->len=%d\n",snd_pages,skb->len);
++      }
++#endif
++
++#ifdef GMAC_USE_TXQ0
++      #define tx_qid  0
++#endif
++
++      swtxq = &tp->swtxq[tx_qid];
++
++//    spin_lock(&tp->tx_mutex);
++    rwptr.bits32 = readl(swtxq->rwptr_reg);
++      wptr = rwptr.bits.wptr;
++      rptr = rwptr.bits.rptr;
++
++      // check finished desc or empty BD
++      // cannot check by read ptr of RW PTR register,
++      // because the HW complete to send but the SW may NOT handle it
++#ifndef       GMAX_TX_INTR_DISABLED
++      if (wptr >= swtxq->finished_idx)
++              free_desc = swtxq->total_desc_num - wptr - 1 + swtxq->finished_idx;
++      else
++              free_desc = swtxq->finished_idx - wptr - 1;
++
++      if (free_desc < snd_pages)
++      {
++//            spin_unlock(&tp->tx_mutex);
++              isPtr->tx_dropped++;
++//            printk("GMAC %d No available descriptor!\n", tp->port_id);
++              netif_stop_queue(dev);
++              return 1;
++    }
++#else
++      toe_gmac_tx_complete(tp, tx_qid, dev, 0);
++
++      if (wptr >= swtxq->finished_idx)
++              free_desc = swtxq->total_desc_num - wptr - 1 + swtxq->finished_idx;
++      else
++              free_desc = swtxq->finished_idx - wptr - 1;
++      if (free_desc < snd_pages)
++      {
++//            spin_unlock(&tp->tx_mutex);
++              isPtr->tx_dropped++;
++//            printk("GMAC %d No available descriptor!\n", tp->port_id);
++              netif_stop_queue(dev);
++              return 1;
++    }
++
++#if 0
++      printk("1: free_desc=%d, wptr=%d, finished_idx=%d\n", free_desc, wptr, swtxq->finished_idx);
++      if ((free_desc < (snd_pages << 2)) ||
++          (free_desc < (swtxq->total_desc_num >> 2)))
++      {
++              printk("2: free_desc = %d\n", free_desc);
++              toe_gmac_tx_complete(tp, tx_qid, dev, 0);
++              rwptr.bits32 = readl(swtxq->rwptr_reg);
++              wptr = rwptr.bits.wptr;
++              if (wptr>= swtxq->finished_idx)
++                      free_desc = swtxq->total_desc_num - wptr -1 + swtxq->finished_idx;
++              else
++                      free_desc = swtxq->finished_idx - wptr - 1;
++      }
++#endif
++#endif
++
++#ifdef        L2_jumbo_frame
++//            data_len = skb->len - 14 - ip_hdr->ihl *4 - tcp_hdr_len;
++//            if ((skb->nh.iph->protocol == __constant_htons(ETH_P_IP)) && ((skb->nh.iph->protocol & 0x00ff)  == IPPROTO_TCP))
++//            if (skb->nh.iph->protocol == 0x006 && (skb->nh.iph->protocol == __constant_htons(ETH_P_IP)))
++              if (((skb->nh.iph->protocol & 0x00ff)  == IPPROTO_TCP))
++              {
++                              ip_hdr = (struct iphdr*)(skb->nh.iph);
++                              tcp_hdr = (struct tcphdr*)(skb->h.th);
++                              tcp_hdr_len = TCPHDRLEN(tcp_hdr) * 4;
++                              tcp_hdr_len = TCPHDRLEN(tcp_hdr) * 4;
++
++                              if ((skb->h.th->syn) && (tcp_hdr_len > 20))
++                              {
++                                      ptr = (unsigned char *)(tcp_hdr+1);
++                                      if ((ptr[0] == 0x02) && (ptr[1] == 0x04) && (ptr[2] == 0x07) && (ptr[3] == 0xba)) // 0x07 aa=2016-54=1962  ,0x07ba=2032-54=1978
++                                      {
++                                              ptr[2]=0x20;    //23
++                                              ptr[3]=0x00;    //00
++                                              printk("-----> Change MSS to 8K \n" );
++                                      }
++                              }
++              }
++//            if ((ip_hdr->protocol & 0x00ff) != IPPROTO_TCP)
++//            if ((tcp_hdr_len > 20) && (skb->h.th->syn))
++#endif
++
++
++#if 0
++      if (snd_pages > 1)
++              printk("-----> snd_pages=%d\n", snd_pages);
++      if (total_len > 1514)
++      {
++              printk("-----> total_len=%d\n", total_len);
++      }
++#endif
++
++    while (snd_pages)
++    {
++      char *pkt_datap;
++
++      curr_desc = (GMAC_TXDESC_T *)swtxq->desc_base + wptr;
++//            consistent_sync((void *)curr_desc, sizeof(GMAC_TXDESC_T), PCI_DMA_FROMDEVICE);
++#if 0
++//#if (GMAC_DEBUG==1)
++      // if curr_desc->word2.buf_adr !=0 means that the ISR does NOT handle it
++      // if (curr_desc->word2.buf_adr)
++      if (swtxq->tx_skb[wptr])
++      {
++              printk("Error! Stop due to TX descriptor's buffer is not freed!\n");
++              while(1);
++              dev_kfree_skb(swtxq->tx_skb[wptr]);
++              swtxq->tx_skb[wptr] = NULL;
++              }
++#endif
++
++              if (frag_id == 0)
++              {
++#if 0
++                      int i;
++                      pkt_datap = skb->data;
++                      len = total_len;
++                      for (i=0; i<skb_shinfo(skb)->nr_frags; i++)
++                      {
++                              skb_frag_t* frag = &skb_shinfo(skb)->frags[i];
++                              len -= frag->size;
++                      }
++#else
++                      pkt_datap = skb->data;
++                      len = total_len - skb->data_len;
++#endif
++              }
++              else
++              {
++                      skb_frag_t* frag = &skb_shinfo(skb)->frags[frag_id-1];
++                      pkt_datap = page_address(frag->page) + frag->page_offset;
++                      len = frag->size;
++                      if (len > total_len)
++                      {
++                              printk("===> Fatal Error! Send Frag size %d > Total Size %d!!!!!\n",
++                                      len, total_len);
++                      }
++              }
++
++              /* set TX descriptor */
++              /* copy packet to descriptor buffer address */
++              // curr_desc->word0.bits32 = len;    /* total frame byte count */
++              word0 = len;
++#ifdef        L2_jumbo_frame
++              word3 = (dev->mtu+14) | EOFIE_BIT;  //2016 ,2032
++#else
++              word3 = 1514 | EOFIE_BIT;
++#endif
++
++#ifdef DO_HW_CHKSUM
++#ifdef        L2_jumbo_frame
++              if (total_len >= (dev->mtu+14) && (skb->nh.iph->protocol == 0x011) && skb->nh.iph && (skb->nh.iph->frag_off & __constant_htons(0x3fff)))
++#else
++              if (total_len <= 1514 && skb->nh.iph && (skb->nh.iph->frag_off & __constant_htons(0x3fff)))
++#endif
++                      word1  = total_len |
++                                      TSS_IP_CHKSUM_BIT  |
++                                      TSS_IPV6_ENABLE_BIT |
++                                      TSS_MTU_ENABLE_BIT;
++              else
++                      word1 = total_len |
++                                      TSS_UDP_CHKSUM_BIT |
++                                      TSS_TCP_CHKSUM_BIT |
++                                      TSS_IP_CHKSUM_BIT  |
++                                      TSS_IPV6_ENABLE_BIT |
++                                      TSS_MTU_ENABLE_BIT;
++#else
++              word1 = total_len | TSS_MTU_ENABLE_BIT;
++#endif
++              word2 = (unsigned long)__pa(pkt_datap);
++
++              if (frag_id == 0)
++              {
++                      word3 |= SOF_BIT;       // SOF
++              }
++
++              if (snd_pages == 1)
++              {
++                      word3 |= EOF_BIT;       // EOF
++                      swtxq->tx_skb[wptr] = skb;
++#ifdef CONFIG_SL351x_NAT
++                      if (nat_cfg.enabled && sl351x_nat_output(skb, tp->port_id))
++                              word1 |= TSS_IP_FIXED_LEN_BIT;
++#endif
++              }
++              else
++                      swtxq->tx_skb[wptr] = NULL;
++              // word1 |= TSS_IP_FIXED_LEN_BIT;
++#if 1
++#ifdef CONFIG_SL351x_RXTOE
++              // check if this frame has the mission to enable toe hash entry..
++              // if rx_max_pktsize ==0, do not enable RXTOE
++              if (TCP_SKB_CB(skb)->connection && storlink_ctl.rx_max_pktsize) {
++                      set_toeq_hdr(TCP_SKB_CB(skb)->connection, &toe_private_data, dev);
++              }
++#endif
++#endif
++#ifdef _DUMP_TX_TCP_CONTENT
++              if (len < 16 && frag_id && skb->h.th && (skb->h.th->source == __constant_htons(445) || skb->h.th->source == __constant_htons(139)))
++              {
++                      int a;
++                      char *datap;
++                      printk("Tx Desc 0x%x Frag %d Len %d [IP-ID 0x%x] 0x%08x: ", (u32)curr_desc, frag_id, len, htons(skb->nh.iph->id), (u32)pkt_datap);
++                      datap = (char *)pkt_datap;
++                      for (a=0; a<8 && a<len; a++, datap++)
++                      {
++                              printk("0x%02x ", *datap);
++                      }
++                      printk("\n");
++              }
++#endif
++
++#ifdef GMAC_LEN_1_2_ISSUE
++              if ((total_pages!=snd_pages) && (len == 1 || len == 2 ) && ((u32)pkt_datap & 0x03))
++              {
++                      memcpy((void *)&_debug_prefetch_buf[_debug_prefetch_cnt][0], pkt_datap, len);
++                      pkt_datap = (char *)&_debug_prefetch_buf[_debug_prefetch_cnt][0];
++                      word2 = (unsigned long)__pa(pkt_datap);
++                      _debug_prefetch_cnt++;
++                      if (_debug_prefetch_cnt >= _DEBUG_PREFETCH_NUM)
++                              _debug_prefetch_cnt = 0;
++              }
++#endif
++
++              consistent_sync((void *)pkt_datap, len, PCI_DMA_TODEVICE);
++              wmb();
++              curr_desc->word0.bits32 = word0;
++              curr_desc->word1.bits32 = word1;
++              curr_desc->word2.bits32 = word2;
++              curr_desc->word3.bits32 = word3;
++              swtxq->curr_tx_desc = (GMAC_TXDESC_T *)curr_desc;
++//            consistent_sync((void *)curr_desc, sizeof(GMAC_TXDESC_T), PCI_DMA_TODEVICE);
++#ifdef _DUMP_TX_TCP_CONTENT
++              if (len < 16 && frag_id && skb->h.th && (skb->h.th->source == __constant_htons(445) || skb->h.th->source == __constant_htons(139)))
++              {
++                      int a;
++                      char *datap;
++                      printk("\t 0x%08x: ", (u32)pkt_datap);
++                      datap = (char *)pkt_datap;
++                      for (a=0; a<8 && a<len; a++, datap++)
++                      {
++                              printk("0x%02x ", *datap);
++                      }
++                      printk("\n");
++              }
++#endif
++              free_desc--;
++              wmb();
++              wptr = RWPTR_ADVANCE_ONE(wptr, swtxq->total_desc_num);
++              frag_id++;
++              snd_pages--;
++      }
++
++    swtxq->total_sent++;
++      SET_WPTR(swtxq->rwptr_reg, wptr);
++      dev->trans_start = jiffies;
++
++
++      // printk("MAC %d Qid %d rwptr = 0x%x, curr_desc=0x%x\n", skb->tx_port_id, tx_qid, rwptr.bits32, curr_desc);
++//#ifdef      GMAX_TX_INTR_DISABLED
++//            toe_gmac_tx_complete(tp, tx_qid, dev, 0);
++//#endif
++      return (0);
++}
++
++/*----------------------------------------------------------------------
++* gmac_set_mac_address
++*----------------------------------------------------------------------*/
++
++static int gmac_set_mac_address(struct net_device *dev, void *addr)
++{
++      GMAC_INFO_T             *tp= dev->priv;
++      struct sockaddr *sock;
++      unsigned int    reg_val;
++    unsigned int    i;
++
++      sock = (struct sockaddr *) addr;
++      for (i = 0; i < 6; i++)
++      {
++              dev->dev_addr[i] = sock->sa_data[i];
++      }
++
++    reg_val = dev->dev_addr[0] + (dev->dev_addr[1]<<8) + (dev->dev_addr[2]<<16) + (dev->dev_addr[3]<<24);
++    gmac_write_reg(tp->base_addr,GMAC_STA_ADD0,reg_val,0xffffffff);
++    reg_val = dev->dev_addr[4] + (dev->dev_addr[5]<<8);
++    gmac_write_reg(tp->base_addr,GMAC_STA_ADD1,reg_val,0x0000ffff);
++      memcpy(&eth_mac[tp->port_id][0],&dev->dev_addr[0],6);
++
++    printk("Storlink %s address = ",dev->name);
++    printk("%02x",dev->dev_addr[0]);
++    printk("%02x",dev->dev_addr[1]);
++    printk("%02x",dev->dev_addr[2]);
++    printk("%02x",dev->dev_addr[3]);
++    printk("%02x",dev->dev_addr[4]);
++    printk("%02x\n",dev->dev_addr[5]);
++
++    return (0);
++}
++
++/*----------------------------------------------------------------------
++* gmac_get_mac_address
++*     get mac address from FLASH
++*----------------------------------------------------------------------*/
++static void gmac_get_mac_address(void)
++{
++#ifdef CONFIG_MTD
++      extern int get_vlaninfo(vlaninfo* vlan);
++    static vlaninfo    vlan[2];
++
++    if (get_vlaninfo(&vlan[0]))
++    {
++        memcpy((void *)&eth_mac[0][0],vlan[0].mac,6);
++        // VLAN_conf[0].vid = vlan[0].vlanid;
++        // VLAN_conf[0].portmap = vlan[0].vlanmap;
++        memcpy((void *)&eth_mac[1][0],vlan[1].mac,6);
++        // VLAN_conf[1].vid = vlan[1].vlanid;
++        // VLAN_conf[1].portmap = vlan[1].vlanmap;
++    }
++#else
++    unsigned int reg_val;
++
++    reg_val = readl(IO_ADDRESS(TOE_GMAC0_BASE)+0xac);
++    eth_mac[0][4] = (reg_val & 0xff00) >> 8;
++    eth_mac[0][5] = reg_val & 0x00ff;
++    reg_val = readl(IO_ADDRESS(SL2312_SECURITY_BASE)+0xac);
++    eth_mac[1][4] = (reg_val & 0xff00) >> 8;
++    eth_mac[1][5] = reg_val & 0x00ff;
++#endif
++    return;
++}
++
++
++/*----------------------------------------------------------------------
++* mac_stop_txdma
++*----------------------------------------------------------------------*/
++void mac_stop_txdma(struct net_device *dev)
++{
++      GMAC_INFO_T                             *tp = (GMAC_INFO_T *)dev->priv;
++      GMAC_DMA_CTRL_T                 dma_ctrl, dma_ctrl_mask;
++      GMAC_TXDMA_FIRST_DESC_T txdma_busy;
++
++      // wait idle
++      do
++      {
++              txdma_busy.bits32 = gmac_read_reg(tp->dma_base_addr, GMAC_DMA_TX_FIRST_DESC_REG);
++      } while (txdma_busy.bits.td_busy);
++
++    /* program dma control register */
++      dma_ctrl.bits32 = 0;
++      dma_ctrl.bits.rd_enable = 0;
++      dma_ctrl.bits.td_enable = 0;
++
++      dma_ctrl_mask.bits32 = 0;
++      dma_ctrl_mask.bits.rd_enable = 1;
++      dma_ctrl_mask.bits.td_enable = 1;
++
++      gmac_write_reg(tp->dma_base_addr, GMAC_DMA_CTRL_REG, dma_ctrl.bits32, dma_ctrl_mask.bits32);
++}
++
++/*----------------------------------------------------------------------
++* mac_start_txdma
++*----------------------------------------------------------------------*/
++void mac_start_txdma(struct net_device *dev)
++{
++      GMAC_INFO_T                     *tp = (GMAC_INFO_T *)dev->priv;
++      GMAC_DMA_CTRL_T         dma_ctrl, dma_ctrl_mask;
++
++    /* program dma control register */
++      dma_ctrl.bits32 = 0;
++      dma_ctrl.bits.rd_enable = 1;
++      dma_ctrl.bits.td_enable = 1;
++
++      dma_ctrl_mask.bits32 = 0;
++      dma_ctrl_mask.bits.rd_enable = 1;
++      dma_ctrl_mask.bits.td_enable = 1;
++
++      gmac_write_reg(tp->dma_base_addr, GMAC_DMA_CTRL_REG, dma_ctrl.bits32, dma_ctrl_mask.bits32);
++}
++
++
++/*----------------------------------------------------------------------
++* gmac_get_stats
++*----------------------------------------------------------------------*/
++
++struct net_device_stats * gmac_get_stats(struct net_device *dev)
++{
++    GMAC_INFO_T *tp = (GMAC_INFO_T *)dev->priv;
++    // unsigned int        flags;
++    unsigned int        pkt_drop;
++    unsigned int        pkt_error;
++
++    if (netif_running(dev))
++    {
++        /* read H/W counter */
++        // spin_lock_irqsave(&tp->lock,flags);
++        pkt_drop = gmac_read_reg(tp->base_addr,GMAC_IN_DISCARDS);
++        pkt_error = gmac_read_reg(tp->base_addr,GMAC_IN_ERRORS);
++        tp->ifStatics.rx_dropped = tp->ifStatics.rx_dropped + pkt_drop;
++        tp->ifStatics.rx_errors = tp->ifStatics.rx_errors + pkt_error;
++        // spin_unlock_irqrestore(&tp->lock,flags);
++    }
++    return &tp->ifStatics;
++}
++
++
++
++/*----------------------------------------------------------------------
++* mac_get_sw_tx_weight
++*----------------------------------------------------------------------*/
++void mac_get_sw_tx_weight(struct net_device *dev, char *weight)
++{
++      GMAC_TX_WCR1_T  sw_weigh;
++    GMAC_INFO_T               *tp = (GMAC_INFO_T *)dev->priv;
++
++      sw_weigh.bits32 = gmac_read_reg(tp->dma_base_addr, GMAC_TX_WEIGHTING_CTRL_1_REG);
++
++      weight[0] = sw_weigh.bits.sw_tq0;
++      weight[1] = sw_weigh.bits.sw_tq1;
++      weight[2] = sw_weigh.bits.sw_tq2;
++      weight[3] = sw_weigh.bits.sw_tq3;
++      weight[4] = sw_weigh.bits.sw_tq4;
++      weight[5] = sw_weigh.bits.sw_tq5;
++}
++
++/*----------------------------------------------------------------------
++* mac_set_sw_tx_weight
++*----------------------------------------------------------------------*/
++void mac_set_sw_tx_weight(struct net_device *dev, char *weight)
++{
++      GMAC_TX_WCR1_T  sw_weigh;
++    GMAC_INFO_T               *tp = (GMAC_INFO_T *)dev->priv;
++
++      sw_weigh.bits32 = 0;
++      sw_weigh.bits.sw_tq0 = weight[0];
++      sw_weigh.bits.sw_tq1 = weight[1];
++      sw_weigh.bits.sw_tq2 = weight[2];
++      sw_weigh.bits.sw_tq3 = weight[3];
++      sw_weigh.bits.sw_tq4 = weight[4];
++      sw_weigh.bits.sw_tq5 = weight[5];
++
++      gmac_write_reg(tp->dma_base_addr, GMAC_TX_WEIGHTING_CTRL_1_REG, sw_weigh.bits32, 0xffffffff);
++}
++
++/*----------------------------------------------------------------------
++* mac_get_hw_tx_weight
++*----------------------------------------------------------------------*/
++void mac_get_hw_tx_weight(struct net_device *dev, char *weight)
++{
++      GMAC_TX_WCR0_T  hw_weigh;
++    GMAC_INFO_T               *tp = (GMAC_INFO_T *)dev->priv;
++
++      hw_weigh.bits32 = gmac_read_reg(tp->dma_base_addr, GMAC_TX_WEIGHTING_CTRL_0_REG);
++
++      weight[0] = hw_weigh.bits.hw_tq0;
++      weight[1] = hw_weigh.bits.hw_tq1;
++      weight[2] = hw_weigh.bits.hw_tq2;
++      weight[3] = hw_weigh.bits.hw_tq3;
++}
++
++/*----------------------------------------------------------------------
++* mac_set_hw_tx_weight
++*----------------------------------------------------------------------*/
++void mac_set_hw_tx_weight(struct net_device *dev, char *weight)
++{
++      GMAC_TX_WCR0_T  hw_weigh;
++    GMAC_INFO_T               *tp = (GMAC_INFO_T *)dev->priv;
++
++      hw_weigh.bits32 = 0;
++      hw_weigh.bits.hw_tq0 = weight[0];
++      hw_weigh.bits.hw_tq1 = weight[1];
++      hw_weigh.bits.hw_tq2 = weight[2];
++      hw_weigh.bits.hw_tq3 = weight[3];
++
++      gmac_write_reg(tp->dma_base_addr, GMAC_TX_WEIGHTING_CTRL_0_REG, hw_weigh.bits32, 0xffffffff);
++}
++
++/*----------------------------------------------------------------------
++* mac_start_tx_dma
++*----------------------------------------------------------------------*/
++int mac_start_tx_dma(int mac)
++{
++      GMAC_DMA_CTRL_T dma_ctrl, dma_ctrl_mask;
++
++      dma_ctrl.bits32 = 0;
++      dma_ctrl.bits.td_enable = 1;
++
++      dma_ctrl_mask.bits32 = 0;
++      dma_ctrl_mask.bits.td_enable = 1;
++
++      if (mac == 0)
++      gmac_write_reg(TOE_GMAC0_DMA_BASE, GMAC_DMA_CTRL_REG, dma_ctrl.bits32, dma_ctrl_mask.bits32);
++      else
++      gmac_write_reg(TOE_GMAC1_DMA_BASE, GMAC_DMA_CTRL_REG, dma_ctrl.bits32, dma_ctrl_mask.bits32);
++      return  1;
++}
++
++/*----------------------------------------------------------------------
++* mac_stop_tx_dma
++*----------------------------------------------------------------------*/
++int mac_stop_tx_dma(int mac)
++{
++      GMAC_DMA_CTRL_T dma_ctrl, dma_ctrl_mask;
++
++      dma_ctrl.bits32 = 0;
++      dma_ctrl.bits.td_enable = 0;
++
++      dma_ctrl_mask.bits32 = 0;
++      dma_ctrl_mask.bits.td_enable = 1;
++
++      if (mac == 0)
++      gmac_write_reg(TOE_GMAC0_DMA_BASE, GMAC_DMA_CTRL_REG, dma_ctrl.bits32, dma_ctrl_mask.bits32);
++      else
++      gmac_write_reg(TOE_GMAC1_DMA_BASE, GMAC_DMA_CTRL_REG, dma_ctrl.bits32, dma_ctrl_mask.bits32);
++      return  1;
++}
++
++/*----------------------------------------------------------------------
++* mac_read_reg(int mac, unsigned int offset)
++*----------------------------------------------------------------------*/
++unsigned int mac_read_reg(int mac, unsigned int offset)
++{
++      switch (mac)
++      {
++              case 0:
++                      return gmac_read_reg(TOE_GMAC0_BASE, offset);
++              case 1:
++                      return gmac_read_reg(TOE_GMAC1_BASE, offset);
++              default:
++                      return 0;
++      }
++}
++
++/*----------------------------------------------------------------------
++* mac_write_reg
++*----------------------------------------------------------------------*/
++void mac_write_reg(int mac, unsigned int offset, unsigned data)
++{
++      switch (mac)
++      {
++              case 0:
++                      gmac_write_reg(GMAC0_BASE, offset, data, 0xffffffff);
++                      break;
++              case 1:
++                      gmac_write_reg(GMAC1_BASE, offset, data, 0xffffffff);
++                      break;
++      }
++}
++
++/*----------------------------------------------------------------------
++* mac_read_dma_reg(int mac, unsigned int offset)
++*----------------------------------------------------------------------*/
++u32 mac_read_dma_reg(int mac, unsigned int offset)
++{
++      switch (mac)
++      {
++              case 0:
++                      return gmac_read_reg(TOE_GMAC0_DMA_BASE, offset);
++              case 1:
++                      return gmac_read_reg(TOE_GMAC1_DMA_BASE, offset);
++              default:
++                      return 0;
++      }
++}
++
++/*----------------------------------------------------------------------
++* mac_write_dma_reg
++*----------------------------------------------------------------------*/
++void mac_write_dma_reg(int mac, unsigned int offset, u32 data)
++{
++      switch (mac)
++      {
++              case 0:
++                      gmac_write_reg(TOE_GMAC0_DMA_BASE, offset, data, 0xffffffff);
++                      break;
++              case 1:
++                      gmac_write_reg(TOE_GMAC1_DMA_BASE, offset, data, 0xffffffff);
++                      break;
++      }
++}
++
++/*----------------------------------------------------------------------
++* ether_crc
++*----------------------------------------------------------------------*/
++static unsigned const ethernet_polynomial = 0x04c11db7U;
++static unsigned int ether_crc (int length, unsigned char *data)
++{
++      int crc = -1;
++      unsigned int i;
++      unsigned int crc_val=0;
++
++      while (--length >= 0) {
++              unsigned char current_octet = *data++;
++              int bit;
++              for (bit = 0; bit < 8; bit++, current_octet >>= 1)
++                      crc = (crc << 1) ^ ((crc < 0) ^ (current_octet & 1) ?
++                           ethernet_polynomial : 0);
++      }
++      crc = ~crc;
++      for (i=0;i<32;i++)
++      {
++              crc_val = crc_val + (((crc << i) & 0x80000000) >> (31-i));
++      }
++      return crc_val;
++}
++
++
++
++/*----------------------------------------------------------------------
++* mac_set_rx_mode
++*----------------------------------------------------------------------*/
++void mac_set_rx_mode(int pid, unsigned int data)
++{
++      unsigned int    base;
++
++      base = (pid == 0) ? GMAC0_BASE : GMAC1_BASE;
++
++    gmac_write_reg(base, GMAC_RX_FLTR, data, 0x0000001f);
++    return;
++}
++
++
++/*----------------------------------------------------------------------
++* gmac_open
++*----------------------------------------------------------------------*/
++
++static int gmac_open (struct net_device *dev)
++{
++      GMAC_INFO_T  *tp = (GMAC_INFO_T *)dev->priv;
++      int                                     retval;
++      TOE_INFO_T                              *toe;
++      toe = (TOE_INFO_T *)&toe_private_data;
++
++    /* hook ISR */
++      retval = request_irq (dev->irq, toe_gmac_interrupt, SA_INTERRUPT, dev->name, dev);
++      if (retval)
++              return retval;
++
++      toe_init_gmac(dev);
++
++      if(!FLAG_SWITCH)
++      {
++      init_waitqueue_head (&tp->thr_wait);
++      init_completion(&tp->thr_exited);
++
++      tp->time_to_die = 0;
++      tp->thr_pid = kernel_thread (gmac_phy_thread, dev, CLONE_FS | CLONE_FILES);
++      if (tp->thr_pid < 0)
++      {
++              printk (KERN_WARNING "%s: unable to start kernel thread\n",dev->name);
++      }
++    }
++
++      tp->operation = 1;
++
++      netif_start_queue (dev);
++
++      return (0);
++}
++
++/*----------------------------------------------------------------------
++* gmac_close
++*----------------------------------------------------------------------*/
++static int gmac_close(struct net_device *dev)
++{
++    TOE_INFO_T                        *toe;
++//    GMAC_RXDESC_T           *sw_desc_ptr,*desc_ptr;
++//    unsigned int            buf_ptr;
++      GMAC_INFO_T     *tp = dev->priv;
++      unsigned int            ret;
++
++      toe = (TOE_INFO_T *)&toe_private_data;
++
++      tp->operation = 0;
++
++    netif_stop_queue(dev);
++    mdelay(20);
++
++    /* stop tx/rx packet */
++    toe_gmac_disable_tx_rx(dev);
++    mdelay(20);
++
++    /* stop the chip's Tx and Rx DMA processes */
++      toe_gmac_hw_stop(dev);
++
++      toe_gmac_disable_interrupt(tp->irq);
++
++    /* disable interrupts by clearing the interrupt mask */
++    synchronize_irq();
++    free_irq(dev->irq,dev);
++
++//    DMA_MFREE(sw_desc_ptr, (TOE_SW_FREEQ_DESC_NUM * sizeof(GMAC_RXDESC_T),(dma_addr_t *)&toe->sw_freeq_desc_base_dma);
++//    DMA_MFREE(desc_ptr, TOE_HW_FREEQ_DESC_NUM * sizeof(GMAC_RXDESC_T),(dma_addr_t *)&toe->hw_freeq_desc_base_dma);
++//    DMA_MFREE(buf_ptr, TOE_HW_FREEQ_DESC_NUM) * HW_RX_BUF_SIZE),(dma_addr_t *)&toe->hwfq_buf_base_dma);
++//    DMA_MFREE(toe->gmac[0].swtxq_desc_base , TOE_GMAC0_SWTXQ_DESC_NUM * TOE_SW_TXQ_NUM * sizeof(GMAC_TXDESC_T),(dma_addr_t *)&toe->gmac[0].swtxq_desc_base_dma);
++//    DMA_MFREE(toe->gmac[1].swtxq_desc_base , TOE_GMAC0_SWTXQ_DESC_NUM * TOE_SW_TXQ_NUM * sizeof(GMAC_TXDESC_T),(dma_addr_t *)&toe->gmac[1].swtxq_desc_base_dma);
++//    DMA_MFREE(toe->gmac[0].hwtxq_desc_base_dma , TOE_GMAC0_HWTXQ_DESC_NUM * TOE_HW_TXQ_NUM * sizeof(GMAC_TXDESC_T),(dma_addr_t *)&toe->gmac[0].hwtxq_desc_base_dma);
++//    DMA_MFREE(toe->gmac[1].hwtxq_desc_base_dma , TOE_GMAC0_SWTXQ_DESC_NUM * TOE_HW_TXQ_NUM * sizeof(GMAC_TXDESC_T),(dma_addr_t *)&toe->gmac[1].hwtxq_desc_base_dma);
++//    DMA_MFREE(toe->gmac[0].default_desc_base_dma ,TOE_DEFAULT_Q0_DESC_NUM * sizeof(GMAC_TXDESC_T),(dma_addr_t *)&toe->gmac[0].default_desc_base_dma);
++//    DMA_MFREE(toe->gmac[1].default_desc_base_dma , TOE_DEFAULT_Q0_DESC_NUM * sizeof(GMAC_TXDESC_T),(dma_addr_t *)&toe->gmac[1].default_desc_base_dma);
++//    DMA_MFREE(toe->intr_desc_base_dma , TOE_INTR_QUEUE_NUM * TOE_INTR_DESC_NUM * sizeof(GMAC_RXDESC_T),(dma_addr_t *)&toe->intr_desc_base_dma);
++//    DMA_MFREE(toe->intr_buf_base_dma , TOE_INTR_DESC_NUM * sizeof(TOE_QHDR_T),(dma_addr_t *)&toe->intr_buf_base_dma);
++
++      if(!FLAG_SWITCH)
++      {
++      if (tp->thr_pid >= 0)
++      {
++                  tp->time_to_die = 1;
++              wmb();
++              ret = kill_proc (tp->thr_pid, SIGTERM, 1);
++              if (ret)
++              {
++                      printk (KERN_ERR "%s: unable to signal thread\n", dev->name);
++                      return ret;
++              }
++//                    wait_for_completion (&tp->thr_exited);
++      }
++    }
++
++    return (0);
++}
++
++/*----------------------------------------------------------------------
++* toe_gmac_fill_free_q
++* allocate buffers for free queue.
++*----------------------------------------------------------------------*/
++static inline void toe_gmac_fill_free_q(void)
++{
++      struct sk_buff  *skb;
++      volatile DMA_RWPTR_T    fq_rwptr;
++      volatile GMAC_RXDESC_T  *fq_desc;
++      unsigned long   flags;
++      // unsigned short max_cnt=TOE_SW_FREEQ_DESC_NUM>>1;
++
++      fq_rwptr.bits32 = readl(TOE_GLOBAL_BASE + GLOBAL_SWFQ_RWPTR_REG);
++      spin_lock_irqsave(&gmac_fq_lock, flags);
++      //while ((max_cnt--) && (unsigned short)RWPTR_ADVANCE_ONE(fq_rwptr.bits.wptr,
++      //                              TOE_SW_FREEQ_DESC_NUM) != fq_rwptr.bits.rptr) {
++      while ((unsigned short)RWPTR_ADVANCE_ONE(fq_rwptr.bits.wptr,
++                                      TOE_SW_FREEQ_DESC_NUM) != fq_rwptr.bits.rptr) {
++              if ((skb = dev_alloc_skb(SW_RX_BUF_SIZE)) == NULL) {
++                      printk("%s::skb allocation fail!\n", __func__);
++                      //while(1);
++                      break;
++              }
++              REG32(skb->data) = (unsigned int)skb;
++              skb_reserve(skb, SKB_RESERVE_BYTES);
++              // fq_rwptr.bits32 = readl(TOE_GLOBAL_BASE + GLOBAL_SWFQ_RWPTR_REG);
++              fq_rwptr.bits.wptr = RWPTR_ADVANCE_ONE(fq_rwptr.bits.wptr,
++                      TOE_SW_FREEQ_DESC_NUM);
++              fq_desc = (GMAC_RXDESC_T*)toe_private_data.swfq_desc_base+fq_rwptr.bits.wptr;
++              fq_desc->word2.buf_adr = (unsigned int)__pa(skb->data);
++              SET_WPTR(TOE_GLOBAL_BASE+GLOBAL_SWFQ_RWPTR_REG, fq_rwptr.bits.wptr);
++              toe_private_data.fq_rx_rwptr.bits32 = fq_rwptr.bits32;
++      }
++      spin_unlock_irqrestore(&gmac_fq_lock, flags);
++}
++// EXPORT_SYMBOL(toe_gmac_fill_free_q);
++
++/*----------------------------------------------------------------------
++* toe_gmac_interrupt
++*----------------------------------------------------------------------*/
++static irqreturn_t toe_gmac_interrupt (int irq, void *dev_instance, struct pt_regs *regs)
++{
++      struct net_device   *dev = (struct net_device *)dev_instance;
++      TOE_INFO_T                      *toe;
++      GMAC_INFO_T             *tp = (GMAC_INFO_T *)dev->priv;
++      unsigned int            status0;
++      unsigned int            status1;
++      unsigned int            status2;
++      unsigned int            status3;
++      unsigned int            status4;
++
++//    struct net_device_stats *isPtr = (struct net_device_stats *)&tp->ifStatics;
++      toe = (TOE_INFO_T *)&toe_private_data;
++//    handle NAPI
++#ifdef CONFIG_SL_NAPI
++if (storlink_ctl.pauseoff == 1)
++{
++/* disable GMAC interrupt */
++    //toe_gmac_disable_interrupt(tp->irq);
++
++//    isPtr->interrupts++;
++      /* read Interrupt status */
++      status0 = readl(TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_STATUS_0_REG);
++      status1 = readl(TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_STATUS_1_REG);
++      status2 = readl(TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_STATUS_2_REG);
++      status3 = readl(TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_STATUS_3_REG);
++      status4 = readl(TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_STATUS_4_REG);
++      // prompt warning if status bit ON but not enabled
++#if 0
++      if (status0 & ~tp->intr0_enabled)
++              printk("Intr 0 Status error. status = 0x%X, enable = 0x%X\n",
++                              status0, tp->intr0_enabled);
++      if (status1 & ~tp->intr1_enabled)
++              printk("Intr 1 Status error. status = 0x%X, enable = 0x%X\n",
++                              status1, tp->intr1_enabled);
++      if (status2 & ~tp->intr2_enabled)
++              printk("Intr 2 Status error. status = 0x%X, enable = 0x%X\n",
++                              status2, tp->intr2_enabled);
++      if (status3 & ~tp->intr3_enabled)
++              printk("Intr 3 Status error. status = 0x%X, enable = 0x%X\n",
++                              status3, tp->intr3_enabled);
++      if (status4 & ~tp->intr4_enabled)
++              printk("Intr 4 Status error. status = 0x%X, enable = 0x%X\n",
++                              status4, tp->intr4_enabled);
++#endif
++
++      if (status0)
++              writel(status0 & tp->intr0_enabled, TOE_GLOBAL_BASE+GLOBAL_INTERRUPT_STATUS_0_REG);
++      if (status1)
++              writel(status1 & tp->intr1_enabled, TOE_GLOBAL_BASE+GLOBAL_INTERRUPT_STATUS_1_REG);
++      if (status2)
++              writel(status2 & tp->intr2_enabled, TOE_GLOBAL_BASE+GLOBAL_INTERRUPT_STATUS_2_REG);
++      if (status3)
++              writel(status3 & tp->intr3_enabled, TOE_GLOBAL_BASE+GLOBAL_INTERRUPT_STATUS_3_REG);
++      if (status4)
++              writel(status4 & tp->intr4_enabled, TOE_GLOBAL_BASE+GLOBAL_INTERRUPT_STATUS_4_REG);
++#if 0
++      /* handle freeq interrupt first */
++      if (status4 & tp->intr4_enabled) {
++              if ((status4 & SWFQ_EMPTY_INT_BIT) && (tp->intr4_enabled & SWFQ_EMPTY_INT_BIT))
++              {
++                      // unsigned long data = REG32(TOE_GLOBAL_BASE + GLOBAL_SWFQ_RWPTR_REG);
++                      //gmac_write_reg(TOE_GLOBAL_BASE, GLOBAL_INTERRUPT_ENABLE_4_REG,
++                      //      tp->intr4_enabled & ~SWFQ_EMPTY_INT_BIT, SWFQ_EMPTY_INT_BIT);
++
++                      if (toe->gmac[0].dev && netif_running(toe->gmac[0].dev))
++                              toe_gmac_handle_default_rxq(toe->gmac[0].dev,&toe->gmac[0]);
++                      if (toe->gmac[1].dev && netif_running(toe->gmac[1].dev))
++                              toe_gmac_handle_default_rxq(toe->gmac[1].dev,&toe->gmac[1]);
++                      printk("\nfreeq int\n");
++                      toe_gmac_fill_free_q();
++                      tp->sw_fq_empty_cnt++;
++
++              }
++      }
++#endif
++      // Interrupt Status 1
++      if (status1 & tp->intr1_enabled)
++      {
++              #define G1_INTR0_BITS   (GMAC1_HWTQ13_EOF_INT_BIT | GMAC1_HWTQ12_EOF_INT_BIT | GMAC1_HWTQ11_EOF_INT_BIT | GMAC1_HWTQ10_EOF_INT_BIT)
++              #define G0_INTR0_BITS   (GMAC0_HWTQ03_EOF_INT_BIT | GMAC0_HWTQ02_EOF_INT_BIT | GMAC0_HWTQ01_EOF_INT_BIT | GMAC0_HWTQ00_EOF_INT_BIT)
++              // Handle GMAC 0/1 HW Tx queue 0-3 EOF events
++              // Only count
++              // TOE, Classification, and default queues interrupts are handled by ISR
++              // because they should pass packets to upper layer
++              if (tp->port_id == 0)
++              {
++                      if (netif_running(dev) && (status1 & G0_INTR0_BITS) && (tp->intr1_enabled & G0_INTR0_BITS))
++                      {
++                              if (status1 & GMAC0_HWTQ03_EOF_INT_BIT)
++                                      tp->hwtxq[3].eof_cnt++;
++                              if (status1 & GMAC0_HWTQ02_EOF_INT_BIT)
++                                      tp->hwtxq[2].eof_cnt++;
++                              if (status1 & GMAC0_HWTQ01_EOF_INT_BIT)
++                                      tp->hwtxq[1].eof_cnt++;
++                              if (status1 & GMAC0_HWTQ00_EOF_INT_BIT)
++                                      tp->hwtxq[0].eof_cnt++;
++                      }
++                              if (netif_running(dev) && (status1 & DEFAULT_Q0_INT_BIT) && (tp->intr1_enabled & DEFAULT_Q0_INT_BIT))
++                              {
++                                      if (likely(netif_rx_schedule_prep(dev)))
++                              {
++                                      unsigned int data32;
++                                      // disable GMAC-0 rx interrupt
++                                      // class-Q & TOE-Q are implemented in future
++                                      //data32 = readl(TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_ENABLE_1_REG);
++                                      //data32 &= ~DEFAULT_Q0_INT_BIT;
++                                              //writel(data32, TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_ENABLE_1_REG);
++                                              //printk("\%s: DEFAULT_Q0_INT_BIT===================>>>>>>>>>>>>\n",__func__);
++                                              writel(0x0, TOE_GLOBAL_BASE+GLOBAL_INTERRUPT_ENABLE_1_REG);
++                                              //tp->total_q_cnt_napi=0;
++                                              //rx_time = jiffies;
++                                              //rx_old_bytes = isPtr->rx_bytes;
++                              __netif_rx_schedule(dev);
++                              }
++                      }
++              }
++              else if (tp->port_id == 1)
++              {
++                      if (netif_running(dev) && (status1 & G1_INTR0_BITS) && (tp->intr1_enabled & G1_INTR0_BITS))
++                      {
++                              if (status1 & GMAC1_HWTQ13_EOF_INT_BIT)
++                                      tp->hwtxq[3].eof_cnt++;
++                              if (status1 & GMAC1_HWTQ12_EOF_INT_BIT)
++                                      tp->hwtxq[2].eof_cnt++;
++                              if (status1 & GMAC1_HWTQ11_EOF_INT_BIT)
++                                      tp->hwtxq[1].eof_cnt++;
++                              if (status1 & GMAC1_HWTQ10_EOF_INT_BIT)
++                                      tp->hwtxq[0].eof_cnt++;
++                      }
++
++                      if (netif_running(dev) && (status1 & DEFAULT_Q1_INT_BIT) && (tp->intr1_enabled & DEFAULT_Q1_INT_BIT))
++                      {
++                              if (likely(netif_rx_schedule_prep(dev)))
++                      {
++                              unsigned int data32;
++                              // disable GMAC-0 rx interrupt
++                              // class-Q & TOE-Q are implemented in future
++                              //data32 = readl(TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_ENABLE_1_REG);
++                              //data32 &= ~DEFAULT_Q1_INT_BIT;
++                                      //writel(data32, TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_ENABLE_1_REG);
++                                      //printk("\%s: 1111111111--->DEFAULT_Q1_INT_BIT===================>>>>>>>>>>>>\n",__func__);
++                                      writel(0x0, TOE_GLOBAL_BASE+GLOBAL_INTERRUPT_ENABLE_1_REG);
++                                      //tp->total_q_cnt_napi=0;
++                                      //rx_time = jiffies;
++                                      //rx_old_bytes = isPtr->rx_bytes;
++                              __netif_rx_schedule(dev);
++                      }
++                      }
++              }
++      }
++
++      // Interrupt Status 0
++      if (status0 & tp->intr0_enabled)
++      {
++              #define ERR_INTR_BITS   (GMAC0_TXDERR_INT_BIT | GMAC0_TXPERR_INT_BIT |  \
++                                                               GMAC1_TXDERR_INT_BIT | GMAC1_TXPERR_INT_BIT |  \
++                                                               GMAC0_RXDERR_INT_BIT | GMAC0_RXPERR_INT_BIT |  \
++                                                               GMAC1_RXDERR_INT_BIT | GMAC1_RXPERR_INT_BIT)
++
++              if (status0 &  ERR_INTR_BITS)
++              {
++                      if ((status0 & GMAC0_TXDERR_INT_BIT) && (tp->intr0_enabled & GMAC0_TXDERR_INT_BIT))
++                      {
++                              tp->txDerr_cnt[0]++;
++                              printk("GMAC0 TX AHB Bus Error!\n");
++                      }
++                      if ((status0 & GMAC0_TXPERR_INT_BIT) && (tp->intr0_enabled & GMAC0_TXPERR_INT_BIT))
++                      {
++                              tp->txPerr_cnt[0]++;
++                              printk("GMAC0 Tx Descriptor Protocol Error!\n");
++                      }
++                      if ((status0 & GMAC1_TXDERR_INT_BIT) && (tp->intr0_enabled & GMAC1_TXDERR_INT_BIT))
++                      {
++                              tp->txDerr_cnt[1]++;
++                              printk("GMAC1 Tx AHB Bus Error!\n");
++                      }
++                      if ((status0 & GMAC1_TXPERR_INT_BIT) && (tp->intr0_enabled & GMAC1_TXPERR_INT_BIT))
++                      {
++                              tp->txPerr_cnt[1]++;
++                              printk("GMAC1 Tx Descriptor Protocol Error!\n");
++                      }
++
++                      if ((status0 & GMAC0_RXDERR_INT_BIT) && (tp->intr0_enabled & GMAC0_RXDERR_INT_BIT))
++                      {
++                              tp->RxDerr_cnt[0]++;
++                              printk("GMAC0 Rx AHB Bus Error!\n");
++                      }
++                      if ((status0 & GMAC0_RXPERR_INT_BIT) && (tp->intr0_enabled & GMAC0_RXPERR_INT_BIT))
++                      {
++                              tp->RxPerr_cnt[0]++;
++                              printk("GMAC0 Rx Descriptor Protocol Error!\n");
++                      }
++                      if ((status0 & GMAC1_RXDERR_INT_BIT) && (tp->intr0_enabled & GMAC1_RXDERR_INT_BIT))
++                      {
++                              tp->RxDerr_cnt[1]++;
++                              printk("GMAC1 Rx AHB Bus Error!\n");
++                      }
++                      if ((status0 & GMAC1_RXPERR_INT_BIT) && (tp->intr0_enabled & GMAC1_RXPERR_INT_BIT))
++                      {
++                              tp->RxPerr_cnt[1]++;
++                              printk("GMAC1 Rx Descriptor Protocol Error!\n");
++                      }
++              }
++
++#ifndef       GMAX_TX_INTR_DISABLED
++              if (tp->port_id == 1 && netif_running(dev) &&
++                      (((status0 & GMAC1_SWTQ10_FIN_INT_BIT) && (tp->intr0_enabled & GMAC1_SWTQ10_FIN_INT_BIT))
++                      ||
++                      ((status0 & GMAC1_SWTQ10_EOF_INT_BIT) && (tp->intr0_enabled & GMAC1_SWTQ10_EOF_INT_BIT))))
++              {
++                      toe_gmac_tx_complete(&toe_private_data.gmac[1], 0, dev, 1);
++              }
++
++              if (tp->port_id == 0 && netif_running(dev) &&
++                      (((status0 & GMAC0_SWTQ00_FIN_INT_BIT) && (tp->intr0_enabled & GMAC0_SWTQ00_FIN_INT_BIT))
++                      ||
++                      ((status0 & GMAC0_SWTQ00_EOF_INT_BIT) && (tp->intr0_enabled & GMAC0_SWTQ00_EOF_INT_BIT))))
++              {
++                      toe_gmac_tx_complete(&toe_private_data.gmac[0], 0, dev, 1);
++              }
++#endif
++      }
++      // Interrupt Status 4
++      if (status4 & tp->intr4_enabled)
++      {
++              #define G1_INTR4_BITS           (0xff000000)
++              #define G0_INTR4_BITS           (0x00ff0000)
++
++              if (tp->port_id == 0)
++              {
++                      if ((status4 & G0_INTR4_BITS) && (tp->intr4_enabled & G0_INTR4_BITS))
++                      {
++                              if (status4 & GMAC0_RESERVED_INT_BIT)
++                                      printk("GMAC0_RESERVED_INT_BIT is ON\n");
++                              if (status4 & GMAC0_MIB_INT_BIT)
++                                      tp->mib_full_cnt++;
++                              if (status4 & GMAC0_RX_PAUSE_ON_INT_BIT)
++                                      tp->rx_pause_on_cnt++;
++                              if (status4 & GMAC0_TX_PAUSE_ON_INT_BIT)
++                                      tp->tx_pause_on_cnt++;
++                              if (status4 & GMAC0_RX_PAUSE_OFF_INT_BIT)
++                                      tp->rx_pause_off_cnt++;
++                              if (status4 & GMAC0_TX_PAUSE_OFF_INT_BIT)
++                                      tp->rx_pause_off_cnt++;
++                              if (status4 & GMAC0_RX_OVERRUN_INT_BIT)
++                                      tp->rx_overrun_cnt++;
++                              if (status4 & GMAC0_STATUS_CHANGE_INT_BIT)
++                                      tp->status_changed_cnt++;
++                      }
++              }
++              else if (tp->port_id == 1)
++              {
++                      if ((status4 & G1_INTR4_BITS) && (tp->intr4_enabled & G1_INTR4_BITS))
++                      {
++                              if (status4 & GMAC1_RESERVED_INT_BIT)
++                                      printk("GMAC1_RESERVED_INT_BIT is ON\n");
++                              if (status4 & GMAC1_MIB_INT_BIT)
++                                      tp->mib_full_cnt++;
++                              if (status4 & GMAC1_RX_PAUSE_ON_INT_BIT)
++                              {
++                                      printk("Gmac pause on\n");
++                                      tp->rx_pause_on_cnt++;
++                              }
++                              if (status4 & GMAC1_TX_PAUSE_ON_INT_BIT)
++                              {
++                                      printk("Gmac pause on\n");
++                                      tp->tx_pause_on_cnt++;
++                              }
++                              if (status4 & GMAC1_RX_PAUSE_OFF_INT_BIT)
++                              {
++                                      printk("Gmac pause off\n");
++                                      tp->rx_pause_off_cnt++;
++                              }
++                              if (status4 & GMAC1_TX_PAUSE_OFF_INT_BIT)
++                              {
++                                      printk("Gmac pause off\n");
++                                      tp->rx_pause_off_cnt++;
++                              }
++                              if (status4 & GMAC1_RX_OVERRUN_INT_BIT)
++                              {
++                                      //printk("Gmac Rx Overrun \n");
++                                      tp->rx_overrun_cnt++;
++                              }
++                              if (status4 & GMAC1_STATUS_CHANGE_INT_BIT)
++                                      tp->status_changed_cnt++;
++                      }
++              }
++      }
++
++      //toe_gmac_enable_interrupt(tp->irq);
++#ifdef IxscriptMate_1518
++      if (storlink_ctl.pauseoff == 1)
++      {
++              GMAC_CONFIG0_T config0;
++              config0.bits32 = readl(TOE_GMAC0_BASE+GMAC_CONFIG0);
++              config0.bits.dis_rx = 0;
++              writel(config0.bits32, TOE_GMAC0_BASE+GMAC_CONFIG0);
++              config0.bits32 = readl(TOE_GMAC1_BASE+GMAC_CONFIG0);
++              config0.bits.dis_rx = 0;
++              writel(config0.bits32, TOE_GMAC1_BASE+GMAC_CONFIG0);
++      }
++#endif
++//     enable_irq(gmac_irq[dev_index]);
++      //printk("gmac_interrupt complete!\n\n");
++//    return IRQ_RETVAL(handled);
++      return  IRQ_RETVAL(1);
++}
++else
++{
++#endif        //endif NAPI
++
++
++      /* disable GMAC interrupt */
++    toe_gmac_disable_interrupt(tp->irq);
++
++//    isPtr->interrupts++;
++      /* read Interrupt status */
++      status0 = readl(TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_STATUS_0_REG);
++      status1 = readl(TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_STATUS_1_REG);
++      status2 = readl(TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_STATUS_2_REG);
++      status3 = readl(TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_STATUS_3_REG);
++      status4 = readl(TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_STATUS_4_REG);
++      // prompt warning if status bit ON but not enabled
++#if 0
++      if (status0 & ~tp->intr0_enabled)
++              printk("Intr 0 Status error. status = 0x%X, enable = 0x%X\n",
++                              status0, tp->intr0_enabled);
++      if (status1 & ~tp->intr1_enabled)
++              printk("Intr 1 Status error. status = 0x%X, enable = 0x%X\n",
++                              status1, tp->intr1_enabled);
++      if (status2 & ~tp->intr2_enabled)
++              printk("Intr 2 Status error. status = 0x%X, enable = 0x%X\n",
++                              status2, tp->intr2_enabled);
++      if (status3 & ~tp->intr3_enabled)
++              printk("Intr 3 Status error. status = 0x%X, enable = 0x%X\n",
++                              status3, tp->intr3_enabled);
++      if (status4 & ~tp->intr4_enabled)
++              printk("Intr 4 Status error. status = 0x%X, enable = 0x%X\n",
++                              status4, tp->intr4_enabled);
++#endif
++#define       INTERRUPT_SELECT                        1
++      if (status0)
++              writel(status0 & tp->intr0_enabled, TOE_GLOBAL_BASE+GLOBAL_INTERRUPT_STATUS_0_REG);
++      if (status1)
++              writel(status1 & tp->intr1_enabled, TOE_GLOBAL_BASE+GLOBAL_INTERRUPT_STATUS_1_REG);
++      if (status2)
++              writel(status2 & tp->intr2_enabled, TOE_GLOBAL_BASE+GLOBAL_INTERRUPT_STATUS_2_REG);
++      if (status3)
++              writel(status3 & tp->intr3_enabled, TOE_GLOBAL_BASE+GLOBAL_INTERRUPT_STATUS_3_REG);
++      if (status4)
++              writel(status4 & tp->intr4_enabled, TOE_GLOBAL_BASE+GLOBAL_INTERRUPT_STATUS_4_REG);
++
++      /* handle freeq interrupt first */
++      if (status4 & tp->intr4_enabled) {
++              if ((status4 & SWFQ_EMPTY_INT_BIT) && (tp->intr4_enabled & SWFQ_EMPTY_INT_BIT))
++              {
++                      // unsigned long data = REG32(TOE_GLOBAL_BASE + GLOBAL_SWFQ_RWPTR_REG);
++                      //gmac_write_reg(TOE_GLOBAL_BASE, GLOBAL_INTERRUPT_ENABLE_4_REG,
++                      //      tp->intr4_enabled & ~SWFQ_EMPTY_INT_BIT, SWFQ_EMPTY_INT_BIT);
++
++                      //gmac_write_reg(TOE_GLOBAL_BASE, GLOBAL_INTERRUPT_STATUS_4_REG,
++                      //      SWFQ_EMPTY_INT_BIT, SWFQ_EMPTY_INT_BIT);
++                      if (toe->gmac[0].dev && netif_running(toe->gmac[0].dev))
++                              toe_gmac_handle_default_rxq(toe->gmac[0].dev,&toe->gmac[0]);
++                      if (toe->gmac[1].dev && netif_running(toe->gmac[1].dev))
++                              toe_gmac_handle_default_rxq(toe->gmac[1].dev,&toe->gmac[1]);
++                      printk("\nfreeq int\n");
++                      toe_gmac_fill_free_q();
++                      tp->sw_fq_empty_cnt++;
++
++                      gmac_write_reg(TOE_GLOBAL_BASE, GLOBAL_INTERRUPT_STATUS_4_REG, status4,
++                              SWFQ_EMPTY_INT_BIT);
++              }
++      }
++
++      // Interrupt Status 1
++      if (status1 & tp->intr1_enabled)
++      {
++              #define G1_INTR0_BITS   (GMAC1_HWTQ13_EOF_INT_BIT | GMAC1_HWTQ12_EOF_INT_BIT | GMAC1_HWTQ11_EOF_INT_BIT | GMAC1_HWTQ10_EOF_INT_BIT)
++              #define G0_INTR0_BITS   (GMAC0_HWTQ03_EOF_INT_BIT | GMAC0_HWTQ02_EOF_INT_BIT | GMAC0_HWTQ01_EOF_INT_BIT | GMAC0_HWTQ00_EOF_INT_BIT)
++              // Handle GMAC 0/1 HW Tx queue 0-3 EOF events
++              // Only count
++              // TOE, Classification, and default queues interrupts are handled by ISR
++              // because they should pass packets to upper layer
++              if (tp->port_id == 0)
++              {
++#ifndef       INTERRUPT_SELECT
++                      if (netif_running(dev) && (status1 & G0_INTR0_BITS) && (tp->intr1_enabled & G0_INTR0_BITS))
++                      {
++                              if (status1 & GMAC0_HWTQ03_EOF_INT_BIT)
++                                      tp->hwtxq[3].eof_cnt++;
++                              if (status1 & GMAC0_HWTQ02_EOF_INT_BIT)
++                                      tp->hwtxq[2].eof_cnt++;
++                              if (status1 & GMAC0_HWTQ01_EOF_INT_BIT)
++                                      tp->hwtxq[1].eof_cnt++;
++                              if (status1 & GMAC0_HWTQ00_EOF_INT_BIT)
++                                      tp->hwtxq[0].eof_cnt++;
++#endif        //INTERRUPT_SELECT
++#ifndef       INTERRUPT_SELECT
++                      }
++#endif        //INTERRUPT_SELECT
++                      if (netif_running(dev) && (status1 & DEFAULT_Q0_INT_BIT) && (tp->intr1_enabled & DEFAULT_Q0_INT_BIT))
++                      {
++                              tp->default_q_intr_cnt++;
++                              toe_gmac_handle_default_rxq(dev, tp);
++                      }
++#ifdef CONFIG_SL351x_RXTOE
++                      if (netif_running(dev) && (status1 & TOE_IQ_ALL_BITS) &&
++                          (tp->intr1_enabled & TOE_IQ_ALL_BITS)) {
++                              //printk("status %x, bits %x, slct %x\n", status1, TOE_IQ_ALL_BITS, tp->intr1_selected);
++                              toe_gmac_handle_toeq(dev, tp, status1);
++                              //toe_gmac_handle_toeq(dev, toe, tp, status1);
++                      }
++#endif
++              }
++              else if (tp->port_id == 1)
++              {
++#ifndef       INTERRUPT_SELECT
++                      if (netif_running(dev) && (status1 & G1_INTR0_BITS) && (tp->intr1_enabled & G1_INTR0_BITS))
++                      {
++                              if (status1 & GMAC1_HWTQ13_EOF_INT_BIT)
++                                      tp->hwtxq[3].eof_cnt++;
++                              if (status1 & GMAC1_HWTQ12_EOF_INT_BIT)
++                                      tp->hwtxq[2].eof_cnt++;
++                              if (status1 & GMAC1_HWTQ11_EOF_INT_BIT)
++                                      tp->hwtxq[1].eof_cnt++;
++                              if (status1 & GMAC1_HWTQ10_EOF_INT_BIT)
++                                      tp->hwtxq[0].eof_cnt++;
++#endif        //INTERRUPT_SELECT
++#ifndef       INTERRUPT_SELECT
++                      }
++#endif        //INTERRUPT_SELECT
++                      if (netif_running(dev) && (status1 & DEFAULT_Q1_INT_BIT) && (tp->intr1_enabled & DEFAULT_Q1_INT_BIT))
++                      {
++                              tp->default_q_intr_cnt++;
++                              toe_gmac_handle_default_rxq(dev, tp);
++                      }
++#ifdef CONFIG_SL351x_RXTOE
++                      if (netif_running(dev) && (status1 & TOE_IQ_ALL_BITS) &&
++                          (tp->intr1_enabled & TOE_IQ_ALL_BITS)) {
++                              //printk("status %x, bits %x, slct %x\n", status1, TOE_IQ_ALL_BITS, tp->intr1_selected);
++                              toe_gmac_handle_toeq(dev, tp, status1);
++                              //toe_gmac_handle_toeq(dev, toe, tp, status1);
++                      }
++#endif
++              }
++      }
++
++
++      // Interrupt Status 0
++      if (status0 & tp->intr0_enabled)
++      {
++
++              #define ERR_INTR_BITS   (GMAC0_TXDERR_INT_BIT | GMAC0_TXPERR_INT_BIT |  \
++                                                               GMAC1_TXDERR_INT_BIT | GMAC1_TXPERR_INT_BIT |  \
++                                                               GMAC0_RXDERR_INT_BIT | GMAC0_RXPERR_INT_BIT |  \
++                                                               GMAC1_RXDERR_INT_BIT | GMAC1_RXPERR_INT_BIT)
++#ifndef       INTERRUPT_SELECT
++              if (status0 &  ERR_INTR_BITS)
++              {
++                      if ((status0 & GMAC0_TXDERR_INT_BIT) && (tp->intr0_enabled & GMAC0_TXDERR_INT_BIT))
++                      {
++                              tp->txDerr_cnt[0]++;
++                              printk("GMAC0 TX AHB Bus Error!\n");
++                      }
++                      if ((status0 & GMAC0_TXPERR_INT_BIT) && (tp->intr0_enabled & GMAC0_TXPERR_INT_BIT))
++                      {
++                              tp->txPerr_cnt[0]++;
++                              printk("GMAC0 Tx Descriptor Protocol Error!\n");
++                      }
++                      if ((status0 & GMAC1_TXDERR_INT_BIT) && (tp->intr0_enabled & GMAC1_TXDERR_INT_BIT))
++                      {
++                              tp->txDerr_cnt[1]++;
++                              printk("GMAC1 Tx AHB Bus Error!\n");
++                      }
++                      if ((status0 & GMAC1_TXPERR_INT_BIT) && (tp->intr0_enabled & GMAC1_TXPERR_INT_BIT))
++                      {
++                              tp->txPerr_cnt[1]++;
++                              printk("GMAC1 Tx Descriptor Protocol Error!\n");
++                      }
++
++                      if ((status0 & GMAC0_RXDERR_INT_BIT) && (tp->intr0_enabled & GMAC0_RXDERR_INT_BIT))
++                      {
++                              tp->RxDerr_cnt[0]++;
++                              printk("GMAC0 Rx AHB Bus Error!\n");
++                      }
++                      if ((status0 & GMAC0_RXPERR_INT_BIT) && (tp->intr0_enabled & GMAC0_RXPERR_INT_BIT))
++                      {
++                              tp->RxPerr_cnt[0]++;
++                              printk("GMAC0 Rx Descriptor Protocol Error!\n");
++                      }
++                      if ((status0 & GMAC1_RXDERR_INT_BIT) && (tp->intr0_enabled & GMAC1_RXDERR_INT_BIT))
++                      {
++                              tp->RxDerr_cnt[1]++;
++                              printk("GMAC1 Rx AHB Bus Error!\n");
++                      }
++                      if ((status0 & GMAC1_RXPERR_INT_BIT) && (tp->intr0_enabled & GMAC1_RXPERR_INT_BIT))
++                      {
++                              tp->RxPerr_cnt[1]++;
++                              printk("GMAC1 Rx Descriptor Protocol Error!\n");
++                      }
++              }
++#endif        //INTERRUPT_SELECT
++#ifndef       GMAX_TX_INTR_DISABLED
++              if (tp->port_id == 1 && netif_running(dev) &&
++                      (((status0 & GMAC1_SWTQ10_FIN_INT_BIT) && (tp->intr0_enabled & GMAC1_SWTQ10_FIN_INT_BIT))
++                      ||
++                      ((status0 & GMAC1_SWTQ10_EOF_INT_BIT) && (tp->intr0_enabled & GMAC1_SWTQ10_EOF_INT_BIT))))
++              {
++                      toe_gmac_tx_complete(&toe_private_data.gmac[1], 0, dev, 1);
++              }
++
++              if (tp->port_id == 0 && netif_running(dev) &&
++                      (((status0 & GMAC0_SWTQ00_FIN_INT_BIT) && (tp->intr0_enabled & GMAC0_SWTQ00_FIN_INT_BIT))
++                      ||
++                      ((status0 & GMAC0_SWTQ00_EOF_INT_BIT) && (tp->intr0_enabled & GMAC0_SWTQ00_EOF_INT_BIT))))
++              {
++                      toe_gmac_tx_complete(&toe_private_data.gmac[0], 0, dev, 1);
++              }
++#endif
++              // clear enabled status bits
++      }
++      // Interrupt Status 4
++#ifndef       INTERRUPT_SELECT
++      if (status4 & tp->intr4_enabled)
++      {
++              #define G1_INTR4_BITS           (0xff000000)
++              #define G0_INTR4_BITS           (0x00ff0000)
++
++              if (tp->port_id == 0)
++              {
++                      if ((status4 & G0_INTR4_BITS) && (tp->intr4_enabled & G0_INTR4_BITS))
++                      {
++                              if (status4 & GMAC0_RESERVED_INT_BIT)
++                                      printk("GMAC0_RESERVED_INT_BIT is ON\n");
++                              if (status4 & GMAC0_MIB_INT_BIT)
++                                      tp->mib_full_cnt++;
++                              if (status4 & GMAC0_RX_PAUSE_ON_INT_BIT)
++                                      tp->rx_pause_on_cnt++;
++                              if (status4 & GMAC0_TX_PAUSE_ON_INT_BIT)
++                                      tp->tx_pause_on_cnt++;
++                              if (status4 & GMAC0_RX_PAUSE_OFF_INT_BIT)
++                                      tp->rx_pause_off_cnt++;
++                              if (status4 & GMAC0_TX_PAUSE_OFF_INT_BIT)
++                                      tp->rx_pause_off_cnt++;
++                              if (status4 & GMAC0_RX_OVERRUN_INT_BIT)
++                                      tp->rx_overrun_cnt++;
++                              if (status4 & GMAC0_STATUS_CHANGE_INT_BIT)
++                                      tp->status_changed_cnt++;
++                      }
++              }
++              else if (tp->port_id == 1)
++              {
++                      if ((status4 & G1_INTR4_BITS) && (tp->intr4_enabled & G1_INTR4_BITS))
++                      {
++                              if (status4 & GMAC1_RESERVED_INT_BIT)
++                                      printk("GMAC1_RESERVED_INT_BIT is ON\n");
++                              if (status4 & GMAC1_MIB_INT_BIT)
++                                      tp->mib_full_cnt++;
++                              if (status4 & GMAC1_RX_PAUSE_ON_INT_BIT)
++                              {
++                                      //printk("Gmac pause on\n");
++                                      tp->rx_pause_on_cnt++;
++                              }
++                              if (status4 & GMAC1_TX_PAUSE_ON_INT_BIT)
++                              {
++                                      //printk("Gmac pause on\n");
++                                      tp->tx_pause_on_cnt++;
++                              }
++                              if (status4 & GMAC1_RX_PAUSE_OFF_INT_BIT)
++                              {
++                                      //printk("Gmac pause off\n");
++                                      tp->rx_pause_off_cnt++;
++                              }
++                              if (status4 & GMAC1_TX_PAUSE_OFF_INT_BIT)
++                              {
++                                      //printk("Gmac pause off\n");
++                                      tp->rx_pause_off_cnt++;
++                              }
++                              if (status4 & GMAC1_RX_OVERRUN_INT_BIT)
++                              {
++                                      //printk("Gmac Rx Overrun \n");
++                                      tp->rx_overrun_cnt++;
++                              }
++                              if (status4 & GMAC1_STATUS_CHANGE_INT_BIT)
++                                      tp->status_changed_cnt++;
++                      }
++              }
++#if 0
++              if ((status4 & SWFQ_EMPTY_INT_BIT) && (tp->intr4_enabled & SWFQ_EMPTY_INT_BIT))
++              {
++                      // unsigned long data = REG32(TOE_GLOBAL_BASE + GLOBAL_SWFQ_RWPTR_REG);
++//                    mac_stop_rxdma(tp->sc);
++                      gmac_write_reg(TOE_GLOBAL_BASE, GLOBAL_INTERRUPT_ENABLE_4_REG,
++                              tp->intr4_enabled & ~SWFQ_EMPTY_INT_BIT, SWFQ_EMPTY_INT_BIT);
++
++                      gmac_write_reg(TOE_GLOBAL_BASE, GLOBAL_INTERRUPT_STATUS_4_REG,
++                              SWFQ_EMPTY_INT_BIT, SWFQ_EMPTY_INT_BIT);
++                      toe_gmac_fill_free_q();
++                      tp->sw_fq_empty_cnt++;
++
++                      gmac_write_reg(TOE_GLOBAL_BASE, GLOBAL_INTERRUPT_STATUS_4_REG, status4,
++                              SWFQ_EMPTY_INT_BIT);
++//#if 0
++/*                    if (netif_running(dev))
++                              toe_gmac_handle_default_rxq(dev, tp);
++                      printk("SWFQ_EMPTY_INT_BIT is ON!\n");  // should not be happened */
++//#endif
++              }
++#endif
++      }
++#endif        //INTERRUPT_SELECT
++      toe_gmac_enable_interrupt(tp->irq);
++//enable gmac rx function when do RFC 2544
++#ifdef IxscriptMate_1518
++      if (storlink_ctl.pauseoff == 1)
++      {
++              GMAC_CONFIG0_T config0;
++              config0.bits32 = readl(TOE_GMAC0_BASE+GMAC_CONFIG0);
++              config0.bits.dis_rx = 0;
++              writel(config0.bits32, TOE_GMAC0_BASE+GMAC_CONFIG0);
++              config0.bits32 = readl(TOE_GMAC1_BASE+GMAC_CONFIG0);
++              config0.bits.dis_rx = 0;
++              writel(config0.bits32, TOE_GMAC1_BASE+GMAC_CONFIG0);
++      }
++#endif
++      //printk("gmac_interrupt complete!\n\n");
++//    return IRQ_RETVAL(handled);
++      return  IRQ_RETVAL(1);
++#ifdef CONFIG_SL_NAPI
++}
++#endif
++}
++
++/*----------------------------------------------------------------------
++*     toe_gmac_handle_default_rxq
++*     (1) Get rx Buffer for default Rx queue
++*     (2) notify or call upper-routine to handle it
++*     (3) get a new buffer and insert it into SW free queue
++*     (4) Note: The SW free queue Read-Write Pointer should be locked when accessing
++*----------------------------------------------------------------------*/
++//static inline void toe_gmac_handle_default_rxq(struct net_device *dev, GMAC_INFO_T *tp)
++static void toe_gmac_handle_default_rxq(struct net_device *dev, GMAC_INFO_T *tp)
++{
++      TOE_INFO_T                      *toe;
++    GMAC_RXDESC_T     *curr_desc;
++      struct sk_buff          *skb;
++    DMA_RWPTR_T                       rwptr;
++      unsigned int            pkt_size;
++      int                                     max_cnt;
++      unsigned int        desc_count;
++      unsigned int        good_frame, chksum_status, rx_status;
++      struct net_device_stats *isPtr = (struct net_device_stats *)&tp->ifStatics;
++
++//when do ixia RFC 2544 test and packet size is select 1518 bytes,disable gmace rx function immediately after one interrupt come in.
++#ifdef IxscriptMate_1518
++      if (storlink_ctl.pauseoff == 1)
++      {
++              GMAC_CONFIG0_T config0;
++              config0.bits32 = readl(TOE_GMAC0_BASE+GMAC_CONFIG0);
++              config0.bits.dis_rx = 1;
++              writel(config0.bits32, TOE_GMAC0_BASE+GMAC_CONFIG0);
++              config0.bits32 = readl(TOE_GMAC1_BASE+GMAC_CONFIG0);
++              config0.bits.dis_rx = 1;
++              writel(config0.bits32, TOE_GMAC1_BASE+GMAC_CONFIG0);
++      }
++#endif
++      rwptr.bits32 = readl(&tp->default_qhdr->word1);
++#if 0
++      if (rwptr.bits.rptr != tp->rx_rwptr.bits.rptr)
++      {
++              mac_stop_txdma((struct net_device *)tp->dev);
++              printk("Default Queue HW RD ptr (0x%x) != SW RD Ptr (0x%x)\n",
++                              rwptr.bits32, tp->rx_rwptr.bits.rptr);
++              while(1);
++      }
++#endif
++      toe = (TOE_INFO_T *)&toe_private_data;
++      max_cnt = DEFAULT_RXQ_MAX_CNT;
++      while ((--max_cnt) && rwptr.bits.rptr != rwptr.bits.wptr)
++//    while (rwptr.bits.rptr != rwptr.bits.wptr)
++      {
++//if packet size is not 1518 for RFC 2544,enable gmac rx function.The other packet size have RX workaround.
++#ifdef IxscriptMate_1518
++      if (storlink_ctl.pauseoff == 1)
++              {
++                      if (pkt_size != 1514)
++                      {
++                                              GMAC_CONFIG0_T config0;
++                                              config0.bits32 = readl(TOE_GMAC0_BASE+GMAC_CONFIG0);
++                                              config0.bits.dis_rx = 0;
++                                              writel(config0.bits32, TOE_GMAC0_BASE+GMAC_CONFIG0);
++                                              config0.bits32 = readl(TOE_GMAC1_BASE+GMAC_CONFIG0);
++                                              config0.bits.dis_rx = 0;
++                                              writel(config0.bits32, TOE_GMAC1_BASE+GMAC_CONFIG0);
++                      }
++              }
++#endif
++      curr_desc = (GMAC_RXDESC_T *)tp->default_desc_base + rwptr.bits.rptr;
++//            consistent_sync(curr_desc, sizeof(GMAC_RXDESC_T), PCI_DMA_FROMDEVICE);
++              tp->default_q_cnt++;
++      tp->rx_curr_desc = (unsigned int)curr_desc;
++      rx_status = curr_desc->word0.bits.status;
++      chksum_status = curr_desc->word0.bits.chksum_status;
++      tp->rx_status_cnt[rx_status]++;
++      tp->rx_chksum_cnt[chksum_status]++;
++        pkt_size = curr_desc->word1.bits.byte_count;  /*total byte count in a frame*/
++              desc_count = curr_desc->word0.bits.desc_count; /* get descriptor count per frame */
++              good_frame=1;
++              if ((curr_desc->word0.bits32 & (GMAC_RXDESC_0_T_derr | GMAC_RXDESC_0_T_perr))
++                      || (pkt_size < 60)
++                  || (chksum_status & 0x4)
++                      || rx_status)
++              {
++                      good_frame = 0;
++                      if (curr_desc->word0.bits32 & GMAC_RXDESC_0_T_derr)
++                              printk("%s::derr (GMAC-%d)!!!\n", __func__, tp->port_id);
++                      if (curr_desc->word0.bits32 & GMAC_RXDESC_0_T_perr)
++                              printk("%s::perr (GMAC-%d)!!!\n", __func__, tp->port_id);
++                      if (rx_status)
++                      {
++                              if (rx_status == 4 || rx_status == 7)
++                                      isPtr->rx_crc_errors++;
++//                            printk("%s::Status=%d (GMAC-%d)!!!\n", __func__, rx_status, tp->port_id);
++                      }
++#ifdef SL351x_GMAC_WORKAROUND
++                      else if (pkt_size < 60)
++                      {
++                              if (tp->short_frames_cnt < GMAC_SHORT_FRAME_THRESHOLD)
++                                      tp->short_frames_cnt++;
++                              if (tp->short_frames_cnt >= GMAC_SHORT_FRAME_THRESHOLD)
++                              {
++                                      GMAC_CONFIG0_T config0;
++                                      config0.bits32 = readl(TOE_GMAC0_BASE+GMAC_CONFIG0);
++                                      config0.bits.dis_rx = 1;
++                                      writel(config0.bits32, TOE_GMAC0_BASE+GMAC_CONFIG0);
++                                      config0.bits32 = readl(TOE_GMAC1_BASE+GMAC_CONFIG0);
++                                      config0.bits.dis_rx = 1;
++                                      writel(config0.bits32, TOE_GMAC1_BASE+GMAC_CONFIG0);
++                              }
++                      }
++#endif
++//                    if (chksum_status)
++//                            printk("%s::Checksum Status=%d (GMAC-%d)!!!\n", __func__, chksum_status, tp->port_id);
++                      skb = (struct sk_buff *)(REG32(__va(curr_desc->word2.buf_adr) - SKB_RESERVE_BYTES));
++                      dev_kfree_skb_irq(skb);
++              }
++              if (good_frame)
++              {
++                      if (curr_desc->word0.bits.drop)
++                              printk("%s::Drop (GMAC-%d)!!!\n", __func__, tp->port_id);
++//                    if (chksum_status)
++//                            printk("%s::Checksum Status=%d (GMAC-%d)!!!\n", __func__, chksum_status, tp->port_id);
++
++              /* get frame information from the first descriptor of the frame */
++#ifdef SL351x_GMAC_WORKAROUND
++                      if (tp->short_frames_cnt >= GMAC_SHORT_FRAME_THRESHOLD)
++                      {
++                              GMAC_CONFIG0_T config0;
++                              config0.bits32 = readl(TOE_GMAC0_BASE+GMAC_CONFIG0);
++                              config0.bits.dis_rx = 0;
++                              writel(config0.bits32, TOE_GMAC0_BASE+GMAC_CONFIG0);
++                              config0.bits32 = readl(TOE_GMAC1_BASE+GMAC_CONFIG0);
++                              config0.bits.dis_rx = 0;
++                              writel(config0.bits32, TOE_GMAC1_BASE+GMAC_CONFIG0);
++                      }
++                      tp->short_frames_cnt = 0;
++#endif
++                      isPtr->rx_packets++;
++                      skb = (struct sk_buff *)(REG32(__va(curr_desc->word2.buf_adr - SKB_RESERVE_BYTES)));
++                      if (!skb)
++                      {
++                              printk("Fatal Error!!skb==NULL\n");
++                              goto next_rx;
++                      }
++                      tp->curr_rx_skb = skb;
++                      // consistent_sync((void *)__va(curr_desc->word2.buf_adr), pkt_size, PCI_DMA_FROMDEVICE);
++
++      //              curr_desc->word2.buf_adr = 0;
++
++                      skb_reserve (skb, RX_INSERT_BYTES);     /* 16 byte align the IP fields. */
++                      skb_put(skb, pkt_size);
++                      skb->dev = dev;
++                      if (chksum_status == RX_CHKSUM_IP_UDP_TCP_OK)
++                      {
++                              skb->ip_summed = CHECKSUM_UNNECESSARY;
++#ifdef CONFIG_SL351x_NAT
++                              if (nat_cfg.enabled && curr_desc->word3.bits.l3_offset && curr_desc->word3.bits.l4_offset)
++                              {
++                                      struct iphdr    *ip_hdr;
++                                      ip_hdr = (struct iphdr *)&(skb->data[curr_desc->word3.bits.l3_offset]);
++                                      sl351x_nat_input(skb,
++                                                                      tp->port_id,
++                                                                      (void *)curr_desc->word3.bits.l3_offset,
++                                                                      (void *)curr_desc->word3.bits.l4_offset);
++                              }
++#endif
++                              skb->protocol = eth_type_trans(skb,dev); /* set skb protocol */
++#if 0
++#ifdef CONFIG_SL351x_RXTOE
++                              if (storlink_ctl.rx_max_pktsize) {
++                                      struct iphdr    *ip_hdr;
++                                      struct tcphdr   *tcp_hdr;
++                                      int ip_hdrlen;
++
++                                      ip_hdr = (struct iphdr*)&(skb->data[0]);
++                                      if ((skb->protocol == __constant_htons(ETH_P_IP)) &&
++                                         ((ip_hdr->protocol & 0x00ff) == IPPROTO_TCP)) {
++                                              ip_hdrlen = ip_hdr->ihl << 2;
++                                              tcp_hdr = (struct tcphdr*)&(skb->data[ip_hdrlen]);
++                                              if (tcp_hdr->syn) {
++                                                      struct toe_conn* connection = init_toeq(ip_hdr->version,
++                                                                      ip_hdr, tcp_hdr, toe, &(skb->data[0]) - 14);
++                                                      TCP_SKB_CB(skb)->connection = connection;
++                                                      //      hash_dump_entry(TCP_SKB_CB(skb)->connection->hash_entry_index);
++                                                      //              printk("%s::skb data %x, conn %x, mode %x\n",
++                                                      //                      __func__, skb->data, connection, connection->mode);
++                                              }
++                                      }
++                              }
++#endif
++#endif
++                      }
++                      else if (chksum_status == RX_CHKSUM_IP_OK_ONLY)
++                      {
++                              skb->ip_summed = CHECKSUM_UNNECESSARY;
++#ifdef CONFIG_SL351x_NAT
++                              if (nat_cfg.enabled && curr_desc->word3.bits.l3_offset && curr_desc->word3.bits.l4_offset)
++                              {
++                                      struct iphdr            *ip_hdr;
++                                      //struct tcphdr         *tcp_hdr;
++                                      ip_hdr = (struct iphdr *)&(skb->data[curr_desc->word3.bits.l3_offset]);
++                                      //tcp_hdr = (struct tcphdr *)&(skb->data[curr_desc->word3.bits.l4_offset]);
++                                      if (ip_hdr->protocol == IPPROTO_UDP)
++                                      {
++                                              sl351x_nat_input(skb,
++                                                                              tp->port_id,
++                                                                              (void *)curr_desc->word3.bits.l3_offset,
++                                                                              (void *)curr_desc->word3.bits.l4_offset);
++                                      }
++                                      else if (ip_hdr->protocol == IPPROTO_GRE)
++                                      {
++                                              sl351x_nat_input(skb,
++                                                                      tp->port_id,
++                                                                      (void *)curr_desc->word3.bits.l3_offset,
++                                                                      (void *)curr_desc->word3.bits.l4_offset);
++                                      }
++                              }
++#endif
++                              skb->protocol = eth_type_trans(skb,dev); /* set skb protocol */
++                      }
++                      else
++                      {
++                              skb->protocol = eth_type_trans(skb,dev); /* set skb protocol */
++                      }
++
++                      netif_rx(skb);  /* socket rx */
++                      dev->last_rx = jiffies;
++
++                      isPtr->rx_bytes += pkt_size;
++
++        }
++
++next_rx:
++              // advance one for Rx default Q 0/1
++              rwptr.bits.rptr = RWPTR_ADVANCE_ONE(rwptr.bits.rptr, tp->default_desc_num);
++              SET_RPTR(&tp->default_qhdr->word1, rwptr.bits.rptr);
++      tp->rx_rwptr.bits32 = rwptr.bits32;
++
++              toe_gmac_fill_free_q();
++      }
++}
++
++/*----------------------------------------------------------------------
++* gmac_get_phy_vendor
++*----------------------------------------------------------------------*/
++static unsigned int gmac_get_phy_vendor(int phy_addr)
++{
++    unsigned int      reg_val;
++    reg_val=(mii_read(phy_addr,0x02) << 16) + mii_read(phy_addr,0x03);
++    return reg_val;
++}
++
++/*----------------------------------------------------------------------
++* gmac_set_phy_status
++*----------------------------------------------------------------------*/
++void gmac_set_phy_status(struct net_device *dev)
++{
++      GMAC_INFO_T *tp = dev->priv;
++      GMAC_STATUS_T   status;
++      unsigned int    reg_val, ability,wan_port_id;
++      unsigned int    i = 0;
++
++#ifdef VITESSE_G5SWITCH
++      if((tp->port_id == GMAC_PORT1)&&(Giga_switch==1)){
++#if 0
++              rcv_mask = SPI_read(2,0,0x10);                  // Receive mask
++              rcv_mask |= 0x4F;
++              for(i=0;i<4;i++){
++                      reg_val = BIT(26)|(i<<21)|(10<<16);
++                      SPI_write(3,0,1,reg_val);
++                      msleep(10);
++                      reg_val = SPI_read(3,0,2);
++                      if(reg_val & 0x0c00){
++                              printk("Port%d:Giga mode\n",i);
++                              SPI_write(1,i,0x00,0x300701B1);
++                              SPI_write(1,i,0x00,0x10070181);
++                              switch_pre_link[i]=LINK_UP;
++                              switch_pre_speed[i]=GMAC_SPEED_1000;
++                      }
++                      else{
++                              reg_val = BIT(26)|(i<<21)|(5<<16);
++                              SPI_write(3,0,1,reg_val);
++                              msleep(10);
++                              ability = (reg_val = SPI_read(3,0,2)&0x5e0) >>5;
++                              if ((ability & 0x0C)) /* 100M full duplex */
++                              {
++                                      SPI_write(1,i,0x00,0x30050472);
++                                      SPI_write(1,i,0x00,0x10050442);
++                                      printk("Port%d:100M\n",i);
++                                      switch_pre_link[i]=LINK_UP;
++                              switch_pre_speed[i]=GMAC_SPEED_100;
++                              }
++                              else if((ability & 0x03)) /* 10M full duplex */
++                              {
++                                      SPI_write(1,i,0x00,0x30050473);
++                                      SPI_write(1,i,0x00,0x10050443);
++                                      printk("Port%d:10M\n",i);
++                                      switch_pre_link[i]=LINK_UP;
++                                      switch_pre_speed[i]=GMAC_SPEED_10;
++                              }
++                              else{
++                                      SPI_write(1,i,0x00,BIT(16));                    // disable RX
++                                      SPI_write(5,0,0x0E,BIT(i));                     // dicard packet
++                                      while((SPI_read(5,0,0x0C)&BIT(i))==0)           // wait to be empty
++                                              msleep(1);
++
++                                      SPI_write(1,i,0x00,0x20000030);                 // PORT_RST
++                                      switch_pre_link[i]=LINK_DOWN;
++                                      switch_pre_speed[i]=GMAC_SPEED_10;
++                                      rcv_mask &= ~BIT(i);
++                                      SPI_write(2,0,0x10,rcv_mask);                   // Disable Receive
++                              }
++                      }
++              }
++#endif
++              gmac_get_switch_status(dev);
++              gmac_write_reg(tp->base_addr, GMAC_STATUS, 0x7d, 0x0000007f);
++//            SPI_write(2,0,0x10,rcv_mask);                   // Enable Receive
++              return ;
++      }
++#endif
++
++      reg_val = gmac_get_phy_vendor(tp->phy_addr);
++      printk("GMAC-%d Addr %d Vendor ID: 0x%08x\n", tp->port_id, tp->phy_addr, reg_val);
++
++      switch (tp->phy_mode)
++      {
++              case GMAC_PHY_GMII:
++              mii_write(tp->phy_addr,0x04,0x05e1); /* advertisement 100M full duplex, pause capable on */
++              #ifdef CONFIG_SL3516_ASIC
++              mii_write(tp->phy_addr,0x09,0x0300); /* advertise 1000M full/half duplex */
++              #else
++              mii_write(tp->phy_addr,0x09,0x0000); /* advertise no 1000M full/half duplex */
++              #endif
++              break;
++              case GMAC_PHY_RGMII_100:
++              mii_write(tp->phy_addr,0x04,0x05e1); /* advertisement 100M full duplex, pause capable on */
++              mii_write(tp->phy_addr,0x09,0x0000); /* advertise no 1000M */
++              break;
++              case GMAC_PHY_RGMII_1000:
++              mii_write(tp->phy_addr,0x04,0x05e1); /* advertisement 100M full duplex, pause capable on */
++              #ifdef CONFIG_SL3516_ASIC
++              mii_write(tp->phy_addr,0x09,0x0300); /* advertise 1000M full/half duplex */
++              #else
++              mii_write(tp->phy_addr,0x09,0x0000); /* advertise no 1000M full/half duplex */
++              #endif
++              break;
++              case GMAC_PHY_MII:
++              default:
++              mii_write(tp->phy_addr,0x04,0x05e1); /* advertisement 100M full duplex, pause capable on */
++              mii_write(tp->phy_addr,0x09,0x0000); /* advertise no 1000M */
++              break;
++      }
++
++      mii_write(tp->phy_addr,0x18,0x0041);    // Phy active led
++      if (tp->auto_nego_cfg)
++      {
++              reg_val = 0x1200 | (1 << 15);
++              mii_write(tp->phy_addr,0x00,reg_val); /* Enable and Restart Auto-Negotiation */
++              mdelay(500);
++              reg_val &= ~(1 << 15);
++              mii_write(tp->phy_addr, 0x00, reg_val);
++      }
++      else
++      {
++              reg_val = 0;
++              reg_val |= (tp->full_duplex_cfg) ? (1 << 8) : 0;
++              reg_val |= (tp->speed_cfg == GMAC_SPEED_1000) ? (1 << 6) : 0;
++              reg_val |= (tp->speed_cfg == GMAC_SPEED_100) ? (1 << 13) : 0;
++              mii_write(tp->phy_addr, 0x00, reg_val);
++              mdelay(100);
++
++              reg_val |= (1 << 15);   // Reset PHY;
++              mii_write(tp->phy_addr, 0x00, reg_val);
++      }
++
++      status.bits32 = 0;
++      /* set PHY operation mode */
++      status.bits.mii_rmii = tp->phy_mode;
++      status.bits.reserved = 1;
++      mdelay(100);
++      while (((reg_val=mii_read(tp->phy_addr,0x01)) & 0x00000004)!=0x04)
++      {
++              msleep(100);
++              i++;
++              if (i > 30)
++              break;
++      }
++      if (i>30)
++      {
++              tp->pre_phy_status = LINK_DOWN;
++              status.bits.link = LINK_DOWN;
++              //              clear_bit(__LINK_STATE_START, &dev->state);
++              printk("Link Down (0x%04x) ", reg_val);
++              if(Giga_switch == 1)
++              {
++                              wan_port_id = 1;
++#ifdef CONFIG_SL351x_SYSCTL
++                              storlink_ctl.link[ wan_port_id] = 0;
++#endif
++              }
++              else
++              {
++#ifdef CONFIG_SL351x_SYSCTL
++                              storlink_ctl.link[ tp->port_id] = 0;
++#endif
++              }
++      }
++      else
++      {
++              tp->pre_phy_status = LINK_UP;
++              status.bits.link = LINK_UP;
++              //              set_bit(__LINK_STATE_START, &dev->state);
++              printk("Link Up (0x%04x) ",reg_val);
++              if(Giga_switch == 1)
++              {
++                              wan_port_id = 1;
++#ifdef CONFIG_SL351x_SYSCTL
++                              storlink_ctl.link[ wan_port_id] = 1;
++#endif
++              }
++              else
++              {
++#ifdef CONFIG_SL351x_SYSCTL
++                              storlink_ctl.link[ tp->port_id] = 1;
++#endif
++              }
++      }
++      //    value = mii_read(PHY_ADDR,0x05);
++
++      ability = (mii_read(tp->phy_addr,0x05) & 0x05E0) >> 5;
++
++      //#ifdef CONFIG_SL3516_ASIC
++      reg_val = mii_read(tp->phy_addr,10);
++      printk("MII REG 10 = 0x%x\n",reg_val);
++
++      if ((reg_val & 0x0800) == 0x0800)
++      {
++              status.bits.duplex = 1;
++              status.bits.speed = 2;
++              if (status.bits.mii_rmii == GMAC_PHY_RGMII_100)
++              status.bits.mii_rmii = GMAC_PHY_RGMII_1000;
++
++              printk(" 1000M/Full \n");
++      }
++      else if ((reg_val & 0x0400) == 0x0400)
++      {
++              status.bits.duplex = 0;
++              status.bits.speed = 2;
++              if (status.bits.mii_rmii == GMAC_PHY_RGMII_100)
++              status.bits.mii_rmii = GMAC_PHY_RGMII_1000;
++
++              printk(" 1000M/Half \n");
++      }
++      //#endif
++      else
++      {
++              #ifdef CONFIG_SL3516_ASIC
++              if (status.bits.mii_rmii == GMAC_PHY_RGMII_1000)
++              status.bits.mii_rmii = GMAC_PHY_RGMII_100;
++              #endif
++              printk("MII REG 5 (bit 5:15) = 0x%x\n", ability);
++              if ((ability & 0x08)==0x08) /* 100M full duplex */
++              {
++                      status.bits.duplex = 1;
++                      status.bits.speed = 1;
++                      printk(" 100M/Full\n");
++
++              }
++              else if ((ability & 0x04)==0x04) /* 100M half duplex */
++              {
++                      status.bits.duplex = 0;
++                      status.bits.speed = 1;
++                      printk(" 100M/Half\n");
++
++              }
++              else if ((ability & 0x02)==0x02) /* 10M full duplex */
++              {
++                      status.bits.duplex = 1;
++                      status.bits.speed = 0;
++                      printk(" 10M/Full\n");
++
++              }
++              else if ((ability & 0x01)==0x01) /* 10M half duplex */
++              {
++                      status.bits.duplex = 0;
++                      status.bits.speed = 0;
++                      printk(" 10M/Half\n");
++
++              }
++      }
++      if ((ability & 0x20)==0x20)
++      {
++              tp->flow_control_enable = 1;
++              printk("Flow Control Enable.\n");
++      }
++      else
++      {
++              tp->flow_control_enable = 0;
++              printk("Flow Control Disable.\n");
++      }
++      tp->full_duplex_status = status.bits.duplex;
++      tp->speed_status = status.bits.speed;
++      if (!tp->auto_nego_cfg)
++      {
++              status.bits.duplex = tp->full_duplex_cfg;
++              status.bits.speed = tp->speed_cfg;
++      }
++      toe_gmac_disable_tx_rx(dev);
++      mdelay(10);
++      gmac_write_reg(tp->base_addr, GMAC_STATUS, status.bits32, 0x0000007f);
++      toe_gmac_enable_tx_rx(dev);
++}
++
++/*----------------------------------------------------------------------
++* gmac_phy_thread
++*----------------------------------------------------------------------*/
++static int gmac_phy_thread (void *data)
++{
++      struct net_device   *dev = data;
++      GMAC_INFO_T *tp = dev->priv;
++      unsigned long       timeout;
++
++    daemonize("%s", dev->name);
++      allow_signal(SIGTERM);
++//    reparent_to_init();
++//    spin_lock_irq(&current->sigmask_lock);
++//    sigemptyset(&current->blocked);
++//    recalc_sigpending(current);
++//    spin_unlock_irq(&current->sigmask_lock);
++//    strncpy (current->comm, dev->name, sizeof(current->comm) - 1);
++//    current->comm[sizeof(current->comm) - 1] = '\0';
++
++      while (1)
++      {
++          timeout = next_tick;
++              do
++              {
++                      timeout = interruptible_sleep_on_timeout (&tp->thr_wait, timeout);
++              } while (!signal_pending (current) && (timeout > 0));
++
++              if (signal_pending (current))
++              {
++//                    spin_lock_irq(&current->sigmask_lock);
++                      flush_signals(current);
++//                    spin_unlock_irq(&current->sigmask_lock);
++              }
++
++              if (tp->time_to_die)
++                      break;
++
++              // printk("%s : Polling MAC %d PHY Status...\n",__func__, tp->port_id);
++              rtnl_lock ();
++              if (tp->auto_nego_cfg){
++#ifdef VITESSE_G5SWITCH
++                      if((tp->port_id == GMAC_PORT1)&&(Giga_switch==1))
++                              gmac_get_switch_status(dev);
++                      else
++#endif
++                              gmac_get_phy_status(dev); //temp remove
++              }
++              rtnl_unlock ();
++      }
++      complete_and_exit (&tp->thr_exited, 0);
++}
++
++/*----------------------------------------------------------------------
++* gmac_get_switch_status
++*----------------------------------------------------------------------*/
++#ifdef VITESSE_G5SWITCH
++void gmac_get_switch_status(struct net_device *dev)
++{
++      GMAC_INFO_T *tp = dev->priv;
++      GMAC_CONFIG0_T  config0,config0_mask;
++      unsigned int    switch_port_id;
++      int get_link=0;
++
++      get_link = Get_Set_port_status();
++      if(get_link){                           // link
++              if(ever_dwon){
++                      ever_dwon = 0;
++                      toe_gmac_enable_tx_rx(dev);
++                      netif_wake_queue(dev);
++                      set_bit(__LINK_STATE_START, &dev->state);
++              }
++      }
++      else{                                   // all down
++              //printk("All link down\n");
++              ever_dwon=1;
++              netif_stop_queue(dev);
++              toe_gmac_disable_tx_rx(dev);
++              clear_bit(__LINK_STATE_START, &dev->state);
++      }
++
++      if ( tp->port_id == 1 )
++              switch_port_id = 0;
++#ifdef CONFIG_SL351x_SYSCTL
++      if (get_link)
++      {
++              storlink_ctl.link[switch_port_id] = 1;
++      }
++      else
++      {
++              storlink_ctl.link[switch_port_id] = 0;
++      }
++      if (storlink_ctl.pauseoff == 1)
++              {
++                      if (tp->flow_control_enable == 1)
++                      {
++                              config0.bits32 = 0;
++                              config0_mask.bits32 = 0;
++                              config0.bits.tx_fc_en = 0; /* disable tx flow control */
++                              config0.bits.rx_fc_en = 0; /* disable rx flow control */
++                              config0_mask.bits.tx_fc_en = 1;
++                              config0_mask.bits.rx_fc_en = 1;
++                              gmac_write_reg(tp->base_addr, GMAC_CONFIG0,config0.bits32,config0_mask.bits32);
++                              printk("Disable SWITCH Flow Control...\n");
++                      }
++                              tp->flow_control_enable = 0;
++              }
++              else
++#endif
++              {
++                      if (tp->flow_control_enable == 0)
++                      {
++                              config0.bits32 = 0;
++                              config0_mask.bits32 = 0;
++                              config0.bits.tx_fc_en = 1; /* enable tx flow control */
++                              config0.bits.rx_fc_en = 1; /* enable rx flow control */
++                              config0_mask.bits.tx_fc_en = 1;
++                              config0_mask.bits.rx_fc_en = 1;
++                              gmac_write_reg(tp->base_addr, GMAC_CONFIG0,config0.bits32,config0_mask.bits32);
++                              printk("Enable SWITCH Flow Control...\n");
++                      }
++                      tp->flow_control_enable = 1;
++              }
++      return ;
++
++}
++#endif
++
++/*----------------------------------------------------------------------
++* gmac_get_phy_status
++*----------------------------------------------------------------------*/
++void gmac_get_phy_status(struct net_device *dev)
++{
++      GMAC_INFO_T *tp = dev->priv;
++      GMAC_CONFIG0_T  config0,config0_mask;
++      GMAC_STATUS_T   status, old_status;
++      unsigned int    reg_val,ability,wan_port_id;
++
++      old_status.bits32 = status.bits32 = gmac_read_reg(tp->base_addr, GMAC_STATUS);
++
++
++      /* read PHY status register */
++      reg_val = mii_read(tp->phy_addr,0x01);
++      if ((reg_val & 0x0024) == 0x0024) /* link is established and auto_negotiate process completed */
++      {
++              ability = (mii_read(tp->phy_addr,0x05) & 0x05E0) >> 5;
++              /* read PHY Auto-Negotiation Link Partner Ability Register */
++              #ifdef CONFIG_SL3516_ASIC
++              reg_val = mii_read(tp->phy_addr,10);
++              if ((reg_val & 0x0800) == 0x0800)
++              {
++                      status.bits.duplex = 1;
++                      status.bits.speed = 2;
++                      if (status.bits.mii_rmii == GMAC_PHY_RGMII_100)
++                      status.bits.mii_rmii = GMAC_PHY_RGMII_1000;
++              }
++              else if ((reg_val & 0x0400) == 0x0400)
++              {
++                      status.bits.duplex = 0;
++                      status.bits.speed = 2;
++                      if (status.bits.mii_rmii == GMAC_PHY_RGMII_100)
++                      status.bits.mii_rmii = GMAC_PHY_RGMII_1000;
++              }
++              else
++              #endif
++              {
++                      #ifdef CONFIG_SL3516_ASIC
++                      if (status.bits.mii_rmii == GMAC_PHY_RGMII_1000)
++                      status.bits.mii_rmii = GMAC_PHY_RGMII_100;
++                      #endif
++                      if ((ability & 0x08)==0x08) /* 100M full duplex */
++                      {
++                              status.bits.duplex = 1;
++                              status.bits.speed = 1;
++                      }
++                      else if ((ability & 0x04)==0x04) /* 100M half duplex */
++                      {
++                              status.bits.duplex = 0;
++                              status.bits.speed = 1;
++                      }
++                      else if ((ability & 0x02)==0x02) /* 10M full duplex */
++                      {
++                              status.bits.duplex = 1;
++                              status.bits.speed = 0;
++                      }
++                      else if ((ability & 0x01)==0x01) /* 10M half duplex */
++                      {
++                              status.bits.duplex = 0;
++                              status.bits.speed = 0;
++                      }
++              }
++              status.bits.link = LINK_UP; /* link up */
++              if(Giga_switch==1)
++              {
++                              wan_port_id = 1;
++#ifdef CONFIG_SL351x_SYSCTL
++                              storlink_ctl.link[ wan_port_id] = 1;
++              }
++              else
++              {
++                              storlink_ctl.link[ tp->port_id] = 1;
++#endif
++              }
++              if ((ability & 0x20)==0x20)
++              {
++                      if (tp->flow_control_enable == 0)
++                      {
++                              config0.bits32 = 0;
++                              config0_mask.bits32 = 0;
++                              config0.bits.tx_fc_en = 1; /* enable tx flow control */
++                              config0.bits.rx_fc_en = 1; /* enable rx flow control */
++                              config0_mask.bits.tx_fc_en = 1;
++                              config0_mask.bits.rx_fc_en = 1;
++                              gmac_write_reg(tp->base_addr, GMAC_CONFIG0,config0.bits32,config0_mask.bits32);
++                              printk("GMAC-%d Flow Control Enable.\n", tp->port_id);
++                      }
++                      tp->flow_control_enable = 1;
++              }
++              else
++              {
++                      if (tp->flow_control_enable == 1)
++                      {
++                              config0.bits32 = 0;
++                              config0_mask.bits32 = 0;
++                              config0.bits.tx_fc_en = 0; /* disable tx flow control */
++                              config0.bits.rx_fc_en = 0; /* disable rx flow control */
++                              config0_mask.bits.tx_fc_en = 1;
++                              config0_mask.bits.rx_fc_en = 1;
++                              gmac_write_reg(tp->base_addr, GMAC_CONFIG0,config0.bits32,config0_mask.bits32);
++                              printk("GMAC-%d Flow Control Disable.\n", tp->port_id);
++                      }
++                      tp->flow_control_enable = 0;
++              }
++
++              if (tp->pre_phy_status == LINK_DOWN)
++              {
++                      printk("GMAC-%d LINK_UP......\n",tp->port_id);
++                      tp->pre_phy_status = LINK_UP;
++              }
++      }
++      else
++      {
++              status.bits.link = LINK_DOWN; /* link down */
++              if(Giga_switch == 1)
++              {
++                              wan_port_id = 1;
++#ifdef CONFIG_SL351x_SYSCTL
++                              storlink_ctl.link[ wan_port_id] = 0;
++              }
++              else
++              {
++                              storlink_ctl.link[ tp->port_id] = 0;
++#endif
++              }
++              if (tp->pre_phy_status == LINK_UP)
++              {
++                      printk("GMAC-%d LINK_Down......\n",tp->port_id);
++                      tp->pre_phy_status = LINK_DOWN;
++              }
++      }
++
++      tp->full_duplex_status = status.bits.duplex;
++      tp->speed_status = status.bits.speed;
++      if (!tp->auto_nego_cfg)
++      {
++              status.bits.duplex = tp->full_duplex_cfg;
++              status.bits.speed = tp->speed_cfg;
++      }
++
++      if (old_status.bits32 != status.bits32)
++      {
++              netif_stop_queue(dev);
++              toe_gmac_disable_tx_rx(dev);
++              clear_bit(__LINK_STATE_START, &dev->state);
++              printk("GMAC-%d Change Status Bits 0x%x-->0x%x\n",tp->port_id, old_status.bits32, status.bits32);
++              mdelay(10); // let GMAC consume packet
++              gmac_write_reg(tp->base_addr, GMAC_STATUS, status.bits32, 0x0000007f);
++              if (status.bits.link == LINK_UP)
++              {
++                      toe_gmac_enable_tx_rx(dev);
++                      netif_wake_queue(dev);
++                      set_bit(__LINK_STATE_START, &dev->state);
++              }
++      }
++}
++
++/***************************************/
++/* define GPIO module base address     */
++/***************************************/
++#define GPIO_BASE_ADDR  (IO_ADDRESS(SL2312_GPIO_BASE))
++#define GPIO_BASE_ADDR1  (IO_ADDRESS(SL2312_GPIO_BASE1))
++
++/* define GPIO pin for MDC/MDIO */
++#ifdef CONFIG_SL3516_ASIC
++#define H_MDC_PIN           22
++#define H_MDIO_PIN          21
++#define G_MDC_PIN           22
++#define G_MDIO_PIN          21
++#else
++#define H_MDC_PIN           3
++#define H_MDIO_PIN          2
++#define G_MDC_PIN           0
++#define G_MDIO_PIN          1
++#endif
++
++//#define GPIO_MDC             0x80000000
++//#define GPIO_MDIO            0x00400000
++
++static unsigned int GPIO_MDC = 0;
++static unsigned int GPIO_MDIO = 0;
++static unsigned int GPIO_MDC_PIN = 0;
++static unsigned int GPIO_MDIO_PIN = 0;
++
++// For PHY test definition!!
++#define LPC_EECK              0x02
++#define LPC_EDIO              0x04
++#define LPC_GPIO_SET          3
++#define LPC_BASE_ADDR         IO_ADDRESS(IT8712_IO_BASE)
++#define inb_gpio(x)           inb(LPC_BASE_ADDR + IT8712_GPIO_BASE + x)
++#define outb_gpio(x, y)               outb(y, LPC_BASE_ADDR + IT8712_GPIO_BASE + x)
++
++enum GPIO_REG
++{
++    GPIO_DATA_OUT   = 0x00,
++    GPIO_DATA_IN    = 0x04,
++    GPIO_PIN_DIR    = 0x08,
++    GPIO_BY_PASS    = 0x0c,
++    GPIO_DATA_SET   = 0x10,
++    GPIO_DATA_CLEAR = 0x14,
++};
++/***********************/
++/*    MDC : GPIO[31]   */
++/*    MDIO: GPIO[22]   */
++/***********************/
++
++/***************************************************
++* All the commands should have the frame structure:
++*<PRE><ST><OP><PHYAD><REGAD><TA><DATA><IDLE>
++****************************************************/
++
++/*****************************************************************
++* Inject a bit to NWay register through CSR9_MDC,MDIO
++*******************************************************************/
++void mii_serial_write(char bit_MDO) // write data into mii PHY
++{
++#ifdef CONFIG_SL2312_LPC_IT8712
++      unsigned char iomode,status;
++
++      iomode = LPCGetConfig(LDN_GPIO, 0xc8 + LPC_GPIO_SET);
++      iomode |= (LPC_EECK|LPC_EDIO) ;                         // Set EECK,EDIO,EECS output
++      LPCSetConfig(LDN_GPIO, 0xc8 + LPC_GPIO_SET, iomode);
++
++      if(bit_MDO)
++      {
++              status = inb_gpio( LPC_GPIO_SET);
++              status |= LPC_EDIO ;            //EDIO high
++              outb_gpio(LPC_GPIO_SET, status);
++      }
++      else
++      {
++              status = inb_gpio( LPC_GPIO_SET);
++              status &= ~(LPC_EDIO) ;         //EDIO low
++              outb_gpio(LPC_GPIO_SET, status);
++      }
++
++      status |= LPC_EECK ;            //EECK high
++      outb_gpio(LPC_GPIO_SET, status);
++
++      status &= ~(LPC_EECK) ;         //EECK low
++      outb_gpio(LPC_GPIO_SET, status);
++
++#else
++    unsigned int addr;
++    unsigned int value;
++
++    addr = GPIO_BASE_ADDR + GPIO_PIN_DIR;
++    value = readl(addr) | GPIO_MDC | GPIO_MDIO; /* set MDC/MDIO Pin to output */
++    writel(value,addr);
++    if(bit_MDO)
++    {
++        addr = (GPIO_BASE_ADDR + GPIO_DATA_SET);
++        writel(GPIO_MDIO,addr); /* set MDIO to 1 */
++        addr = (GPIO_BASE_ADDR + GPIO_DATA_SET);
++        writel(GPIO_MDC,addr); /* set MDC to 1 */
++        addr = (GPIO_BASE_ADDR + GPIO_DATA_CLEAR);
++        writel(GPIO_MDC,addr); /* set MDC to 0 */
++    }
++    else
++    {
++        addr = (GPIO_BASE_ADDR + GPIO_DATA_CLEAR);
++        writel(GPIO_MDIO,addr); /* set MDIO to 0 */
++        addr = (GPIO_BASE_ADDR + GPIO_DATA_SET);
++        writel(GPIO_MDC,addr); /* set MDC to 1 */
++        addr = (GPIO_BASE_ADDR + GPIO_DATA_CLEAR);
++        writel(GPIO_MDC,addr); /* set MDC to 0 */
++    }
++
++#endif
++}
++
++/**********************************************************************
++* read a bit from NWay register through CSR9_MDC,MDIO
++***********************************************************************/
++unsigned int mii_serial_read(void) // read data from mii PHY
++{
++#ifdef CONFIG_SL2312_LPC_IT8712
++      unsigned char iomode,status;
++      unsigned int value ;
++
++      iomode = LPCGetConfig(LDN_GPIO, 0xc8 + LPC_GPIO_SET);
++      iomode &= ~(LPC_EDIO) ;         // Set EDIO input
++      iomode |= (LPC_EECK) ;          // Set EECK,EECS output
++      LPCSetConfig(LDN_GPIO, 0xc8 + LPC_GPIO_SET, iomode);
++
++      status = inb_gpio( LPC_GPIO_SET);
++      status |= LPC_EECK ;            //EECK high
++      outb_gpio(LPC_GPIO_SET, status);
++
++      status &= ~(LPC_EECK) ;         //EECK low
++      outb_gpio(LPC_GPIO_SET, status);
++
++      value = inb_gpio( LPC_GPIO_SET);
++
++      value = value>>2 ;
++      value &= 0x01;
++
++      return value ;
++
++#else
++    unsigned int *addr;
++    unsigned int value;
++
++    addr = (unsigned int *)(GPIO_BASE_ADDR + GPIO_PIN_DIR);
++    value = readl(addr) & ~GPIO_MDIO; //0xffbfffff;   /* set MDC to output and MDIO to input */
++    writel(value,addr);
++
++    addr = (unsigned int *)(GPIO_BASE_ADDR + GPIO_DATA_SET);
++    writel(GPIO_MDC,addr); /* set MDC to 1 */
++    addr = (unsigned int *)(GPIO_BASE_ADDR + GPIO_DATA_CLEAR);
++    writel(GPIO_MDC,addr); /* set MDC to 0 */
++
++    addr = (unsigned int *)(GPIO_BASE_ADDR + GPIO_DATA_IN);
++    value = readl(addr);
++    value = (value & (1<<GPIO_MDIO_PIN)) >> GPIO_MDIO_PIN;
++    return(value);
++
++#endif
++}
++
++/***************************************
++* preamble + ST
++***************************************/
++void mii_pre_st(void)
++{
++    unsigned char i;
++
++    for(i=0;i<32;i++) // PREAMBLE
++        mii_serial_write(1);
++    mii_serial_write(0); // ST
++    mii_serial_write(1);
++}
++
++
++/******************************************
++* Read MII register
++* phyad -> physical address
++* regad -> register address
++***************************************** */
++unsigned int mii_read(unsigned char phyad,unsigned char regad)
++{
++    unsigned int i,value;
++    unsigned int bit;
++
++    if (phyad == GPHY_ADDR)
++    {
++        GPIO_MDC_PIN = G_MDC_PIN;   /* assigned MDC pin for giga PHY */
++        GPIO_MDIO_PIN = G_MDIO_PIN; /* assigned MDIO pin for giga PHY */
++    }
++    else
++    {
++        GPIO_MDC_PIN = H_MDC_PIN;   /* assigned MDC pin for 10/100 PHY */
++        GPIO_MDIO_PIN = H_MDIO_PIN; /* assigned MDIO pin for 10/100 PHY */
++    }
++    GPIO_MDC = (1<<GPIO_MDC_PIN);
++    GPIO_MDIO = (1<<GPIO_MDIO_PIN);
++
++    mii_pre_st(); // PRE+ST
++    mii_serial_write(1); // OP
++    mii_serial_write(0);
++
++    for (i=0;i<5;i++) { // PHYAD
++        bit= ((phyad>>(4-i)) & 0x01) ? 1 :0 ;
++        mii_serial_write(bit);
++    }
++
++    for (i=0;i<5;i++) { // REGAD
++        bit= ((regad>>(4-i)) & 0x01) ? 1 :0 ;
++        mii_serial_write(bit);
++    }
++
++    mii_serial_read(); // TA_Z
++//    if((bit=mii_serial_read()) !=0 ) // TA_0
++//    {
++//        return(0);
++//    }
++    value=0;
++    for (i=0;i<16;i++) { // READ DATA
++        bit=mii_serial_read();
++        value += (bit<<(15-i)) ;
++    }
++
++    mii_serial_write(0); // dumy clock
++    mii_serial_write(0); // dumy clock
++
++      //printk("%s: phy_addr=0x%x reg_addr=0x%x value=0x%x \n",__func__,phyad,regad,value);
++    return(value);
++}
++
++/******************************************
++* Write MII register
++* phyad -> physical address
++* regad -> register address
++* value -> value to be write
++***************************************** */
++void mii_write(unsigned char phyad,unsigned char regad,unsigned int value)
++{
++    unsigned int i;
++    char bit;
++
++      printk("%s: phy_addr=0x%x reg_addr=0x%x value=0x%x \n",__func__,phyad,regad,value);
++    if (phyad == GPHY_ADDR)
++    {
++        GPIO_MDC_PIN = G_MDC_PIN;   /* assigned MDC pin for giga PHY */
++        GPIO_MDIO_PIN = G_MDIO_PIN; /* assigned MDIO pin for giga PHY */
++    }
++    else
++    {
++        GPIO_MDC_PIN = H_MDC_PIN;   /* assigned MDC pin for 10/100 PHY */
++        GPIO_MDIO_PIN = H_MDIO_PIN; /* assigned MDIO pin for 10/100 PHY */
++    }
++    GPIO_MDC = (1<<GPIO_MDC_PIN);
++    GPIO_MDIO = (1<<GPIO_MDIO_PIN);
++
++    mii_pre_st(); // PRE+ST
++    mii_serial_write(0); // OP
++    mii_serial_write(1);
++    for (i=0;i<5;i++) { // PHYAD
++        bit= ((phyad>>(4-i)) & 0x01) ? 1 :0 ;
++        mii_serial_write(bit);
++    }
++
++    for (i=0;i<5;i++) { // REGAD
++        bit= ((regad>>(4-i)) & 0x01) ? 1 :0 ;
++        mii_serial_write(bit);
++    }
++    mii_serial_write(1); // TA_1
++    mii_serial_write(0); // TA_0
++
++    for (i=0;i<16;i++) { // OUT DATA
++        bit= ((value>>(15-i)) & 0x01) ? 1 : 0 ;
++        mii_serial_write(bit);
++    }
++    mii_serial_write(0); // dumy clock
++    mii_serial_write(0); // dumy clock
++}
++
++/*----------------------------------------------------------------------
++* gmac_set_rx_mode
++*----------------------------------------------------------------------*/
++static void gmac_set_rx_mode(struct net_device *dev)
++{
++    GMAC_RX_FLTR_T      filter;
++      unsigned int        mc_filter[2];       /* Multicast hash filter */
++    int                 bit_nr;
++      unsigned int        i;
++      GMAC_INFO_T             *tp = dev->priv;
++
++//    printk("%s : dev->flags = %x \n",__func__,dev->flags);
++//    dev->flags |= IFF_ALLMULTI;  /* temp */
++    filter.bits32 = 0;
++    filter.bits.error = 0;
++      if (dev->flags & IFF_PROMISC)
++      {
++          filter.bits.error = 1;
++        filter.bits.promiscuous = 1;
++        filter.bits.broadcast = 1;
++        filter.bits.multicast = 1;
++        filter.bits.unicast = 1;
++              mc_filter[1] = mc_filter[0] = 0xffffffff;
++      }
++      else if (dev->flags & IFF_ALLMULTI)
++      {
++//        filter.bits.promiscuous = 1;
++        filter.bits.broadcast = 1;
++        filter.bits.multicast = 1;
++        filter.bits.unicast = 1;
++              mc_filter[1] = mc_filter[0] = 0xffffffff;
++      }
++      else
++      {
++              struct dev_mc_list *mclist;
++
++//        filter.bits.promiscuous = 1;
++        filter.bits.broadcast = 1;
++        filter.bits.multicast = 1;
++        filter.bits.unicast = 1;
++              mc_filter[1] = mc_filter[0] = 0;
++              for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;i++, mclist = mclist->next)
++              {
++            bit_nr = ether_crc(ETH_ALEN,mclist->dmi_addr) & 0x0000003f;
++            if (bit_nr < 32)
++            {
++                mc_filter[0] = mc_filter[0] | (1<<bit_nr);
++            }
++            else
++            {
++                mc_filter[1] = mc_filter[1] | (1<<(bit_nr-32));
++            }
++              }
++      }
++    gmac_write_reg(tp->base_addr,GMAC_RX_FLTR,filter.bits32,0xffffffff);  //chech base address!!!
++    gmac_write_reg(tp->base_addr,GMAC_MCAST_FIL0,mc_filter[0],0xffffffff);
++    gmac_write_reg(tp->base_addr,GMAC_MCAST_FIL1,mc_filter[1],0xffffffff);
++    return;
++}
++
++#ifdef CONFIG_SL_NAPI
++/*----------------------------------------------------------------------
++* gmac_rx_poll
++*----------------------------------------------------------------------*/
++static int gmac_rx_poll(struct net_device *dev, int *budget)
++{
++      TOE_INFO_T                      *toe;
++    GMAC_RXDESC_T     *curr_desc;
++      struct sk_buff          *skb;
++    DMA_RWPTR_T                       rwptr;
++      unsigned int            pkt_size;
++      unsigned int        desc_count;
++      unsigned int        good_frame, chksum_status, rx_status;
++      int                 rx_pkts_num = 0;
++      int                 quota = min(dev->quota, *budget);
++      GMAC_INFO_T                     *tp = (GMAC_INFO_T *)dev->priv;
++      unsigned int            status4;
++      volatile DMA_RWPTR_T    fq_rwptr;
++      int                                     max_cnt = TOE_SW_FREEQ_DESC_NUM;//TOE_SW_FREEQ_DESC_NUM = 64
++      //unsigned long         rx_old_bytes;
++      struct net_device_stats *isPtr = (struct net_device_stats *)&tp->ifStatics;
++      //unsigned long long    rx_time;
++
++
++
++#if 1
++      if (do_again)
++      {
++                      toe_gmac_fill_free_q();
++                      status4 = readl(TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_STATUS_4_REG);
++                      fq_rwptr.bits32 = readl(TOE_GLOBAL_BASE + GLOBAL_SWFQ_RWPTR_REG);
++                      //printk("\n%s:: do_again toe_gmac_fill_free_q =======>status4=0x%x =====fq_rwptr =0x%8x======>JKJKJKJKJKJKJKJKJ \n", __func__,status4,fq_rwptr.bits32);
++                      if (fq_rwptr.bits.wptr != fq_rwptr.bits.rptr)
++                      {
++                                              //status4 = readl(TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_STATUS_4_REG);
++                                              do_again =0;
++                                              //netif_rx_complete(dev);
++                                              gmac_write_reg(TOE_GLOBAL_BASE, GLOBAL_INTERRUPT_STATUS_4_REG, status4, 0x1);
++                                              fq_rwptr.bits32 = readl(TOE_GLOBAL_BASE + GLOBAL_SWFQ_RWPTR_REG);
++                                              rwptr.bits32 = readl(&tp->default_qhdr->word1);
++                      }
++                      else
++                              return 1;
++      }
++#endif
++      rwptr.bits32 = readl(&tp->default_qhdr->word1);
++#if 0
++      if (rwptr.bits.rptr != tp->rx_rwptr.bits.rptr)
++      {
++              mac_stop_txdma((struct net_device *)tp->dev);
++              printk("Default Queue HW RD ptr (0x%x) != SW RD Ptr (0x%x)\n",
++                              rwptr.bits32, tp->rx_rwptr.bits.rptr);
++              while(1);
++      }
++#endif
++      toe = (TOE_INFO_T *)&toe_private_data;
++
++      fq_rwptr.bits32 = readl(TOE_GLOBAL_BASE + GLOBAL_SWFQ_RWPTR_REG);
++      //printk("%s:---Before-------------->Default Queue HW RW ptr (0x%8x),   fq_rwptr =0x%8x \n",__func__,rwptr.bits32,fq_rwptr.bits32 );
++      //printk("%s:---Before while   rx_pkts_num=%d------rx_finished_idx=0x%x------->Default_Q [rwptr.bits.rptr(SW)=0x%x,   rwptr.bits.wptr(HW) = 0x%x ]---->Free_Q(SW_HW) = 0x%8x \n",__func__,rx_pkts_num,rx_finished_idx,rwptr.bits.rptr,rwptr.bits.wptr,fq_rwptr.bits32 );
++//    while ((--max_cnt) && (rwptr.bits.rptr != rwptr.bits.wptr) && (rx_pkts_num < quota))
++
++      while ((rwptr.bits.rptr != rwptr.bits.wptr) && (rx_pkts_num < quota))
++      {
++
++      curr_desc = (GMAC_RXDESC_T *)tp->default_desc_base + rwptr.bits.rptr;
++              tp->default_q_cnt++;
++      tp->rx_curr_desc = (unsigned int)curr_desc;
++      rx_status = curr_desc->word0.bits.status;
++      chksum_status = curr_desc->word0.bits.chksum_status;
++      tp->rx_status_cnt[rx_status]++;
++      tp->rx_chksum_cnt[chksum_status]++;
++        pkt_size = curr_desc->word1.bits.byte_count;  /*total byte count in a frame*/
++              desc_count = curr_desc->word0.bits.desc_count; /* get descriptor count per frame */
++              good_frame=1;
++              if ((curr_desc->word0.bits32 & (GMAC_RXDESC_0_T_derr | GMAC_RXDESC_0_T_perr))
++                      || (pkt_size < 60)
++                  || (chksum_status & 0x4)
++                  || rx_status )
++//                    || rx_status || (rwptr.bits.rptr > rwptr.bits.wptr ))
++              {
++                      good_frame = 0;
++                      if (curr_desc->word0.bits32 & GMAC_RXDESC_0_T_derr)
++                              printk("%s::derr (GMAC-%d)!!!\n", __func__, tp->port_id);
++                      if (curr_desc->word0.bits32 & GMAC_RXDESC_0_T_perr)
++                              printk("%s::perr (GMAC-%d)!!!\n", __func__, tp->port_id);
++                      if (rx_status)
++                      {
++                              if (rx_status == 4 || rx_status == 7)
++                                      isPtr->rx_crc_errors++;
++//                            printk("%s::Status=%d (GMAC-%d)!!!\n", __func__, rx_status, tp->port_id);
++                      }
++#ifdef SL351x_GMAC_WORKAROUND
++                      else if (pkt_size < 60)
++                      {
++                              if (tp->short_frames_cnt < GMAC_SHORT_FRAME_THRESHOLD)
++                                      tp->short_frames_cnt++;
++                              if (tp->short_frames_cnt >= GMAC_SHORT_FRAME_THRESHOLD)
++                              {
++                                      GMAC_CONFIG0_T config0;
++                                      config0.bits32 = readl(TOE_GMAC0_BASE+GMAC_CONFIG0);
++                                      config0.bits.dis_rx = 1;
++                                      writel(config0.bits32, TOE_GMAC0_BASE+GMAC_CONFIG0);
++                                      config0.bits32 = readl(TOE_GMAC1_BASE+GMAC_CONFIG0);
++                                      config0.bits.dis_rx = 1;
++                                      writel(config0.bits32, TOE_GMAC1_BASE+GMAC_CONFIG0);
++                              }
++                      }
++#endif
++//                    if (chksum_status)
++//                            printk("%s::Checksum Status=%d (GMAC-%d)!!!\n", __func__, chksum_status, tp->port_id);
++                      skb = (struct sk_buff *)(REG32(__va(curr_desc->word2.buf_adr) - SKB_RESERVE_BYTES));
++                      dev_kfree_skb_irq(skb);
++              }
++              if (good_frame)
++              {
++                      if (curr_desc->word0.bits.drop)
++                              printk("%s::Drop (GMAC-%d)!!!\n", __func__, tp->port_id);
++//                    if (chksum_status)
++//                            printk("%s::Checksum Status=%d (GMAC-%d)!!!\n", __func__, chksum_status, tp->port_id);
++
++#ifdef SL351x_GMAC_WORKAROUND
++                      if (tp->short_frames_cnt >= GMAC_SHORT_FRAME_THRESHOLD)
++                      {
++                              GMAC_CONFIG0_T config0;
++                              config0.bits32 = readl(TOE_GMAC0_BASE+GMAC_CONFIG0);
++                              config0.bits.dis_rx = 0;
++                              writel(config0.bits32, TOE_GMAC0_BASE+GMAC_CONFIG0);
++                              config0.bits32 = readl(TOE_GMAC1_BASE+GMAC_CONFIG0);
++                              config0.bits.dis_rx = 0;
++                              writel(config0.bits32, TOE_GMAC1_BASE+GMAC_CONFIG0);
++                      }
++                      tp->short_frames_cnt = 0;
++#endif
++              /* get frame information from the first descriptor of the frame */
++                      isPtr->rx_packets++;
++                      //consistent_sync((void *)__va(curr_desc->word2.buf_adr), pkt_size, PCI_DMA_FROMDEVICE);
++                      skb = (struct sk_buff *)(REG32(__va(curr_desc->word2.buf_adr) - SKB_RESERVE_BYTES));
++                      tp->curr_rx_skb = skb;
++      //              curr_desc->word2.buf_adr = 0;
++
++                  //skb_reserve (skb, SKB_RESERVE_BYTES);
++                      skb_reserve (skb, RX_INSERT_BYTES);     /* 2 byte align the IP fields. */
++                      //if ((skb->tail+pkt_size) > skb->end )
++                      //printk("%s::------------->Here skb->len=%d,pkt_size= %d,skb->head=0x%x,skb->tail= 0x%x, skb->end= 0x%x\n", __func__, skb->len, pkt_size,skb->head,skb->tail,skb->end);
++                      skb_put(skb, pkt_size);
++
++
++                      skb->dev = dev;
++                      if (chksum_status == RX_CHKSUM_IP_UDP_TCP_OK)
++                      {
++                              skb->ip_summed = CHECKSUM_UNNECESSARY;
++#ifdef CONFIG_SL351x_NAT
++                              if (nat_cfg.enabled && curr_desc->word3.bits.l3_offset && curr_desc->word3.bits.l4_offset)
++                              {
++                                      struct iphdr    *ip_hdr;
++                                      ip_hdr = (struct iphdr *)&(skb->data[curr_desc->word3.bits.l3_offset]);
++                                      sl351x_nat_input(skb,
++                                                                      tp->port_id,
++                                                                      (void *)curr_desc->word3.bits.l3_offset,
++                                                                      (void *)curr_desc->word3.bits.l4_offset);
++                              }
++#endif
++                              skb->protocol = eth_type_trans(skb,dev); /* set skb protocol */
++#if 0
++#ifdef CONFIG_SL351x_RXTOE
++                              if (storlink_ctl.rx_max_pktsize) {
++                                      struct iphdr    *ip_hdr;
++                                      struct tcphdr   *tcp_hdr;
++                                      int ip_hdrlen;
++
++                                      ip_hdr = (struct iphdr*)&(skb->data[0]);
++                                      if ((skb->protocol == __constant_htons(ETH_P_IP)) &&
++                                         ((ip_hdr->protocol & 0x00ff) == IPPROTO_TCP)) {
++                                              ip_hdrlen = ip_hdr->ihl << 2;
++                                              tcp_hdr = (struct tcphdr*)&(skb->data[ip_hdrlen]);
++                                              if (tcp_hdr->syn) {
++                                                      struct toe_conn* connection = init_toeq(ip_hdr->version,
++                                                                      ip_hdr, tcp_hdr, toe, &(skb->data[0]) - 14);
++                                                      TCP_SKB_CB(skb)->connection = connection;
++                                                      //      hash_dump_entry(TCP_SKB_CB(skb)->connection->hash_entry_index);
++                                                      //              printk("%s::skb data %x, conn %x, mode %x\n",
++                                                      //                      __func__, skb->data, connection, connection->mode);
++                                              }
++                                      }
++                              }
++#endif
++#endif
++                      }
++                      else if (chksum_status == RX_CHKSUM_IP_OK_ONLY)
++                      {
++                              skb->ip_summed = CHECKSUM_UNNECESSARY;
++#ifdef CONFIG_SL351x_NAT
++                              if (nat_cfg.enabled && curr_desc->word3.bits.l3_offset && curr_desc->word3.bits.l4_offset)
++                              {
++                                      struct iphdr    *ip_hdr;
++                                      ip_hdr = (struct iphdr *)&(skb->data[curr_desc->word3.bits.l3_offset]);
++                                      if (ip_hdr->protocol == IPPROTO_UDP)
++                                      {
++                                              sl351x_nat_input(skb,
++                                                                              tp->port_id,
++                                                                              (void *)curr_desc->word3.bits.l3_offset,
++                                                                              (void *)curr_desc->word3.bits.l4_offset);
++                                      }
++                                      else if (ip_hdr->protocol == IPPROTO_GRE)
++                                      {
++                                              sl351x_nat_input(skb,
++                                                                      tp->port_id,
++                                                                      (void *)curr_desc->word3.bits.l3_offset,
++                                                                      (void *)curr_desc->word3.bits.l4_offset);
++                                      }
++                              }
++#endif
++                              skb->protocol = eth_type_trans(skb,dev); /* set skb protocol */
++                      }
++                      else
++                      {
++                              skb->protocol = eth_type_trans(skb,dev); /* set skb protocol */
++                      }
++                      //netif_rx(skb);  /* socket rx */
++                      netif_receive_skb(skb); //For NAPI
++                      dev->last_rx = jiffies;
++
++                      isPtr->rx_bytes += pkt_size;
++                      //printk("------------------->isPtr->rx_bytes = %d\n",isPtr->rx_bytes);
++
++
++        }
++              // advance one for Rx default Q 0/1
++              rwptr.bits.rptr = RWPTR_ADVANCE_ONE(rwptr.bits.rptr, tp->default_desc_num);
++              SET_RPTR(&tp->default_qhdr->word1, rwptr.bits.rptr);
++      tp->rx_rwptr.bits32 = rwptr.bits32;
++              rx_pkts_num++;
++              //rwptr.bits32 = readl(&tp->default_qhdr->word1);//try read default_qhdr again
++              //fq_rwptr.bits32 = readl(TOE_GLOBAL_BASE + GLOBAL_SWFQ_RWPTR_REG);
++              //printk("%s:---Loop  -------->rx_pkts_num=%d------------>Default Queue HW RW ptr = (0x%8x),   fq_rwptr =0x%8x \n",__func__,rx_pkts_num,rwptr.bits32,fq_rwptr.bits32 );
++#if 0
++              if ((status4 & 0x1) == 0)
++              {
++                      //if (!((dev->last_rx <= (rx_time + 2)) &&  (isPtr->rx_bytes > (rx_old_bytes + 1000000 ))))
++                      if (tp->total_q_cnt_napi < 1024)
++                      {
++                              tp->total_q_cnt_napi++;
++                              toe_gmac_fill_free_q();  //for iperf test disable
++                      }
++                      //else
++                              //printk("%s:---isPtr->rx_bytes =%u , rx_old_bytes =%u\n",__func__,isPtr->rx_bytes,rx_old_bytes );
++
++              }
++#endif
++              //rwptr.bits.rptr = RWPTR_ADVANCE_ONE(rwptr.bits.rptr, tp->default_desc_num);
++              //printk("%s:---Loop  -------->rx_pkts_num=%d----rwptr.bits.rptr=0x%x-------->Default Queue HW RW ptr = (0x%8x),   fq_rwptr =0x%8x \n",__func__,rx_pkts_num,rwptr.bits.rptr,rwptr.bits32,fq_rwptr.bits32 );
++              //printk("%s:---Loop  rx_pkts_num=%d------rwptr.bits.rptr=0x%x------->Default_Q [rwptr.bits.rptr(SW)=0x%x,   rwptr.bits.wptr(HW) = 0x%x ]---->Free_Q(SW_HW) = 0x%8x \n",__func__,rx_pkts_num,rwptr.bits.rptr,rwptr.bits.rptr,rwptr.bits.wptr,fq_rwptr.bits32 );
++      }
++      // advance one for Rx default Q 0/1
++
++              //rwptr.bits.rptr = RWPTR_ADVANCE_ONE(rwptr.bits.rptr, tp->default_desc_num);
++              //SET_RPTR(&tp->default_qhdr->word1, rwptr.bits.rptr);
++      //tp->rx_rwptr.bits32 = rwptr.bits32;
++      //rwptr.bits.rptr = rwptr.bits.rptr;
++
++      dev->quota -= rx_pkts_num;
++      *budget -= rx_pkts_num;
++
++      status4 = readl(TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_STATUS_4_REG);//try read SWFQ empty again
++      //fq_rwptr.bits32 = readl(TOE_GLOBAL_BASE + GLOBAL_SWFQ_RWPTR_REG);
++      rwptr.bits32 = readl(&tp->default_qhdr->word1); //try read default_qhdr again
++      //printk("%s:---After    rx_pkts_num=%d------rwptr.bits.rptr=0x%x------->Default_Q [rwptr.bits.rptr(SW)=0x%x,   rwptr.bits.wptr(HW) = 0x%x ]---->Free_Q(SW_HW) = 0x%8x \n",__func__,rx_pkts_num,rwptr.bits.rptr,rwptr.bits.rptr,rwptr.bits.wptr,fq_rwptr.bits32 );
++//    if (rwptr.bits.rptr > rwptr.bits.wptr )
++//                    {
++                              //toe_gmac_disable_rx(dev);
++                              //wait_event_interruptible_timeout(freeq_wait,
++                                      //(rx_pkts_num == 100), CMTP_INTEROP_TIMEOUT);
++                              //printk("\n%s:: return 22222=======> rx_pkts_num =%d,   rwptr.bits.rptr=%d,   rwptr.bits.wptr = %d ====---------=======>JKJKJKJKJK\n",
++                                      //__func__,rx_pkts_num,rwptr.bits.rptr,rwptr.bits.wptr);
++//                            return 1;
++//                    }
++
++      if (rwptr.bits.rptr == rwptr.bits.wptr)
++      {
++              unsigned int data32;
++                      //printk("%s:---[rwptr.bits.rptr == rwptr.bits.wptr]   rx_pkts_num=%d------rwptr.bits.rptr=0x%x------->Default_Q [rwptr.bits.rptr(SW)=0x%x,   rwptr.bits.wptr(HW) = 0x%x ]---->Free_Q(SW_HW) = 0x%8x \n",__func__,rx_pkts_num,rwptr.bits.rptr,rwptr.bits.rptr,rwptr.bits.wptr,fq_rwptr.bits32 );
++
++          /* Receive descriptor is empty now */
++#if 1
++     if (status4 & 0x1)
++                      {
++                              do_again =1;
++                              //writel(0x40400000, TOE_GLOBAL_BASE+GLOBAL_INTERRUPT_ENABLE_4_REG); //disable SWFQ empty interrupt
++                              //toe_gmac_disable_interrupt(tp->irq);
++                              tp->sw_fq_empty_cnt++;
++                              //toe_gmac_disable_rx(dev);
++                              writel(0x07960202, TOE_GMAC0_BASE+GMAC_CONFIG0);
++                              writel(0x07960202, TOE_GMAC1_BASE+GMAC_CONFIG0);
++                              //printk("\n%s ::  freeq int-----tp->sw_fq_empty_cnt  =%d---------====================----------------->\n",__func__,tp->sw_fq_empty_cnt);
++                              //while ((fq_rwptr.bits.wptr >= (fq_rwptr.bits.rptr+256)) || (fq_rwptr.bits.wptr <= (fq_rwptr.bits.rptr+256)))
++                              //{
++                                      //gmac_write_reg(TOE_GLOBAL_BASE, GLOBAL_INTERRUPT_STATUS_4_REG, status4,
++                                      //0x1);
++                              //printk("\n%s::fq_rwptr.wrptr = %x =======> ===========>here \n", __func__,fq_rwptr.bits32);
++                              //if ((status4 & 0x1) == 0)
++                                      //break;
++                               return 1;
++                              //}
++
++                      }
++#endif
++        //toe_gmac_fill_free_q();
++        netif_rx_complete(dev);
++        // enable GMAC-0 rx interrupt
++        // class-Q & TOE-Q are implemented in future
++        //data32 = readl(TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_ENABLE_1_REG);
++        //if (tp->port_id == 0)
++              //data32 |= DEFAULT_Q0_INT_BIT;
++        //else
++              //data32 |= DEFAULT_Q1_INT_BIT;
++        //writel(data32, TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_ENABLE_1_REG);
++              writel(0x3, TOE_GLOBAL_BASE+GLOBAL_INTERRUPT_ENABLE_1_REG);
++              //printk("\n%s::netif_rx_complete-->  rx_pkts_num =%d,   rwptr.bits.rptr=0x%x,   rwptr.bits.wptr = 0x%x ====---------=======>JKJKJKJKJK\n",
++              //__func__,rx_pkts_num,rwptr.bits.rptr,rwptr.bits.wptr);
++        writel(0x07960200, TOE_GMAC0_BASE+GMAC_CONFIG0);
++              writel(0x07960200, TOE_GMAC1_BASE+GMAC_CONFIG0);
++        return 0;
++    }
++    else
++    {
++        //printk("\n%s:: return 1 -->status4= 0x%x,rx_pkts_num =%d,   rwptr.bits.rptr=0x%x,   rwptr.bits.wptr = 0x%x  ======> \n", __func__,status4,rx_pkts_num,rwptr.bits.rptr,rwptr.bits.wptr);
++        return 1;
++    }
++}
++#endif
++
++/*----------------------------------------------------------------------
++* gmac_tx_timeout
++*----------------------------------------------------------------------*/
++void gmac_tx_timeout(struct net_device *dev)
++{
++      GMAC_INFO_T                             *tp = (GMAC_INFO_T *)dev->priv;
++
++#ifdef CONFIG_SL351x_SYSCTL
++      if (tp->operation && storlink_ctl.link[tp->port_id])
++#else
++      if (tp->operation)
++#endif
++      {
++              netif_wake_queue(dev);
++      }
++}
++
++
++
++/*----------------------------------------------------------------------
++* mac_set_rule_reg
++*----------------------------------------------------------------------*/
++int mac_set_rule_reg(int mac, int rule, int enabled, u32 reg0, u32 reg1, u32 reg2)
++{
++      int             total_key_dwords;
++
++      total_key_dwords = 1;
++
++      if (reg0 & MR_L2_BIT)
++      {
++              if (reg0 & MR_DA_BIT) total_key_dwords += 2;
++              if (reg0 & MR_SA_BIT) total_key_dwords += 2;
++              if ((reg0 & MR_DA_BIT) && ( reg0 & MR_SA_BIT)) total_key_dwords--;
++              if (reg0 & (MR_PPPOE_BIT | MR_VLAN_BIT)) total_key_dwords++;
++      }
++      if (reg0 & MR_L3_BIT)
++      {
++              if (reg0 & (MR_IP_HDR_LEN_BIT | MR_TOS_TRAFFIC_BIT | MR_SPR_BITS))
++                      total_key_dwords++;
++              if (reg0 & MR_FLOW_LABLE_BIT) total_key_dwords++;
++              if ((reg0 & MR_IP_VER_BIT) == 0) // IPv4
++              {
++                      if (reg1 & 0xff000000) total_key_dwords += 1;
++                      if (reg1 & 0x00ff0000) total_key_dwords += 1;
++              }
++              else
++              {
++                      if (reg1 & 0xff000000) total_key_dwords += 4;
++                      if (reg1 & 0x00ff0000) total_key_dwords += 4;
++              }
++      }
++      if (reg0 & MR_L4_BIT)
++      {
++              if (reg1 & 0x0000f000) total_key_dwords += 1;
++              if (reg1 & 0x00000f00) total_key_dwords += 1;
++              if (reg1 & 0x000000f0) total_key_dwords += 1;
++              if (reg1 & 0x0000000f) total_key_dwords += 1;
++              if (reg2 & 0xf0000000) total_key_dwords += 1;
++              if (reg2 & 0x0f000000) total_key_dwords += 1;
++      }
++      if (reg0 & MR_L7_BIT)
++      {
++              if (reg2 & 0x00f00000) total_key_dwords += 1;
++              if (reg2 & 0x000f0000) total_key_dwords += 1;
++              if (reg2 & 0x0000f000) total_key_dwords += 1;
++              if (reg2 & 0x00000f00) total_key_dwords += 1;
++              if (reg2 & 0x000000f0) total_key_dwords += 1;
++              if (reg2 & 0x0000000f) total_key_dwords += 1;
++      }
++
++      if (total_key_dwords > HASH_MAX_KEY_DWORD)
++              return -1;
++
++      if (total_key_dwords == 0 && enabled)
++              return -2;
++
++      mac_set_rule_enable_bit(mac, rule, 0);
++      if (enabled)
++      {
++              mac_set_MRxCRx(mac, rule, 0, reg0);
++              mac_set_MRxCRx(mac, rule, 1, reg1);
++              mac_set_MRxCRx(mac, rule, 2, reg2);
++              mac_set_rule_action(mac, rule, total_key_dwords);
++              mac_set_rule_enable_bit(mac, rule, enabled);
++      }
++      else
++      {
++              mac_set_rule_action(mac, rule, 0);
++      }
++      return total_key_dwords;
++}
++
++/*----------------------------------------------------------------------
++* mac_get_rule_enable_bit
++*----------------------------------------------------------------------*/
++int mac_get_rule_enable_bit(int mac, int rule)
++{
++      switch (rule)
++      {
++              case 0: return ((mac_read_dma_reg(mac, GMAC_HASH_ENGINE_REG0) >> 15) & 1);
++              case 1: return ((mac_read_dma_reg(mac, GMAC_HASH_ENGINE_REG0) >> 31) & 1);
++              case 2: return ((mac_read_dma_reg(mac, GMAC_HASH_ENGINE_REG1) >> 15) & 1);
++              case 3: return ((mac_read_dma_reg(mac, GMAC_HASH_ENGINE_REG1) >> 31) & 1);
++              default: return 0;
++      }
++}
++
++/*----------------------------------------------------------------------
++* mac_set_rule_enable_bit
++*----------------------------------------------------------------------*/
++void mac_set_rule_enable_bit(int mac, int rule, int data)
++{
++      u32 reg;
++
++      if (data & ~1)
++              return;
++
++      switch (rule)
++      {
++              case 0:
++                      reg = (mac_read_dma_reg(mac, GMAC_HASH_ENGINE_REG0) & ~(1<<15)) | (data << 15);
++                      mac_write_dma_reg(mac, GMAC_HASH_ENGINE_REG0, reg);
++                      break;
++              case 1:
++                      reg = (mac_read_dma_reg(mac, GMAC_HASH_ENGINE_REG0) & ~(1<<31)) | (data << 31);
++                      mac_write_dma_reg(mac, GMAC_HASH_ENGINE_REG0, reg);
++                      break;
++              case 2:
++                      reg = (mac_read_dma_reg(mac, GMAC_HASH_ENGINE_REG1) & ~(1<<15)) | (data << 15);
++                      mac_write_dma_reg(mac, GMAC_HASH_ENGINE_REG1, reg);
++                      break;
++              case 3:
++                      reg = (mac_read_dma_reg(mac, GMAC_HASH_ENGINE_REG1) & ~(1<<31)) | (data << 31);
++                      mac_write_dma_reg(mac, GMAC_HASH_ENGINE_REG1, reg);
++      }
++}
++
++/*----------------------------------------------------------------------
++* mac_set_rule_action
++*----------------------------------------------------------------------*/
++int mac_set_rule_action(int mac, int rule, int data)
++{
++      u32 reg;
++
++      if (data > 32)
++              return -1;
++
++      if (data)
++              data = (data << 6) | (data + HASH_ACTION_DWORDS);
++      switch (rule)
++      {
++              case 0:
++                      reg = (mac_read_dma_reg(mac, GMAC_HASH_ENGINE_REG0) & ~(0x7ff));
++                      mac_write_dma_reg(mac, GMAC_HASH_ENGINE_REG0, reg | data);
++                      break;
++              case 1:
++                      reg = (mac_read_dma_reg(mac, GMAC_HASH_ENGINE_REG0) & ~(0x7ff<<16));
++                      mac_write_dma_reg(mac, GMAC_HASH_ENGINE_REG0, reg | (data << 16));
++                      break;
++              case 2:
++                      reg = (mac_read_dma_reg(mac, GMAC_HASH_ENGINE_REG1) & ~(0x7ff));
++                      mac_write_dma_reg(mac, GMAC_HASH_ENGINE_REG1,  reg | data);
++                      break;
++              case 3:
++                      reg = (mac_read_dma_reg(mac, GMAC_HASH_ENGINE_REG1) & ~(0x7ff<<16));
++                      mac_write_dma_reg(mac, GMAC_HASH_ENGINE_REG1, reg | (data << 16));
++                      break;
++              default:
++                      return -1;
++      }
++
++      return 0;
++}
++/*----------------------------------------------------------------------
++* mac_get_MRxCRx
++*----------------------------------------------------------------------*/
++int mac_get_MRxCRx(int mac, int rule, int ctrlreg)
++{
++      int reg;
++
++      switch (rule)
++      {
++              case 0: reg = GMAC_MR0CR0 + ctrlreg * 4; break;
++              case 1: reg = GMAC_MR1CR0 + ctrlreg * 4; break;
++              case 2: reg = GMAC_MR2CR0 + ctrlreg * 4; break;
++              case 3: reg = GMAC_MR3CR0 + ctrlreg * 4; break;
++              default: return 0;
++      }
++      return mac_read_dma_reg(mac, reg);
++}
++
++/*----------------------------------------------------------------------
++* mac_set_MRxCRx
++*----------------------------------------------------------------------*/
++void mac_set_MRxCRx(int mac, int rule, int ctrlreg, u32 data)
++{
++      int reg;
++
++      switch (rule)
++      {
++              case 0: reg = GMAC_MR0CR0 + ctrlreg * 4; break;
++              case 1: reg = GMAC_MR1CR0 + ctrlreg * 4; break;
++              case 2: reg = GMAC_MR2CR0 + ctrlreg * 4; break;
++              case 3: reg = GMAC_MR3CR0 + ctrlreg * 4; break;
++              default: return;
++      }
++      mac_write_dma_reg(mac, reg, data);
++}
++
++/*----------------------------------------------------------------------
++* mac_set_rule_priority
++*----------------------------------------------------------------------*/
++void mac_set_rule_priority(int mac, int p0, int p1, int p2, int p3)
++{
++      int                     i;
++      GMAC_MRxCR0_T   reg[4];
++
++      for (i=0; i<4; i++)
++              reg[i].bits32 = mac_get_MRxCRx(mac, i, 0);
++
++      reg[0].bits.priority = p0;
++      reg[1].bits.priority = p1;
++      reg[2].bits.priority = p2;
++      reg[3].bits.priority = p3;
++
++      for (i=0; i<4; i++)
++              mac_set_MRxCRx(mac, i, 0, reg[i].bits32);
++}
++
++/*----------------------------------------------------------------------
++* gmac_netdev_ioctl
++*----------------------------------------------------------------------*/
++static int gmac_netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
++{
++      int                             rc = 0;
++    unsigned char             *hwa = rq->ifr_ifru.ifru_hwaddr.sa_data;
++
++#ifdef br_if_ioctl
++    struct                            ethtool_cmd ecmd;       //br_if.c will call this ioctl
++      GMAC_INFO_T             *tp = dev->priv;
++#endif
++
++#ifdef        CONFIG_SL351x_NAT
++      if (cmd == SIOCDEVPRIVATE)
++              return sl351x_nat_ioctl(dev, rq, cmd);
++#endif
++
++      switch (cmd) {
++      case SIOCETHTOOL:
++#ifdef br_if_ioctl    //br_if.c will call this ioctl
++              if (!netif_running(dev))
++              {
++                      printk("Before changing the H/W address,please down the device.\n");
++                      return -EINVAL;
++              }
++              memset((void *) &ecmd, 0, sizeof (ecmd));
++                  ecmd.supported =
++                      SUPPORTED_Autoneg | SUPPORTED_TP | SUPPORTED_MII |
++                    SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full |
++                    SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full;
++                          ecmd.port = PORT_TP;
++                  ecmd.transceiver = XCVR_EXTERNAL;
++                  ecmd.phy_address = tp->phy_addr;
++                  switch (tp->speed_status)
++                  {
++                  case GMAC_SPEED_10: ecmd.speed = SPEED_10; break;
++                  case GMAC_SPEED_100: ecmd.speed = SPEED_100; break;
++                  case GMAC_SPEED_1000: ecmd.speed = SPEED_1000; break;
++                  default: ecmd.speed = SPEED_10; break;
++                 }
++                  ecmd.duplex = tp->full_duplex_status ? DUPLEX_FULL : DUPLEX_HALF;
++                  ecmd.advertising = ADVERTISED_TP;
++                  ecmd.advertising |= ADVERTISED_Autoneg;
++                  ecmd.autoneg = AUTONEG_ENABLE;
++                    if (copy_to_user(rq->ifr_data, &ecmd, sizeof (ecmd)))
++                      return -EFAULT;
++#endif
++
++        break;
++
++    case SIOCSIFHWADDR:
++              if (!netif_running(dev))
++              {
++                      printk("Before changing the H/W address,please down the device.\n");
++                      return -EINVAL;
++              }
++        gmac_set_mac_address(dev,hwa);
++        break;
++
++      case SIOCGMIIPHY:       /* Get the address of the PHY in use. */
++        break;
++
++      case SIOCGMIIREG:       /* Read the specified MII register. */
++              break;
++
++      case SIOCSMIIREG:       /* Write the specified MII register */
++              break;
++
++      default:
++              rc = -EOPNOTSUPP;
++              break;
++      }
++
++      return rc;
++}
++
++#ifdef SL351x_GMAC_WORKAROUND
++
++#define GMAC_TX_STATE_OFFSET  0x60
++#define GMAC_RX_STATE_OFFSET  0x64
++#define GMAC_POLL_HANGED_NUM  200
++#define GMAC_RX_HANGED_STATE  0x4b2000
++#define GMAC_RX_HANGED_MASK           0xdff000
++#define GMAC_TX_HANGED_STATE  0x34012
++#define GMAC_TX_HANGED_MASK           0xfffff
++#define TOE_GLOBAL_REG_SIZE           (0x78/sizeof(u32))
++#define TOE_DMA_REG_SIZE              (0xd0/sizeof(u32))
++#define TOE_GMAC_REG_SIZE             (0x30/sizeof(u32))
++#define GMAC0_RX_HANG_BIT             (1 << 0)
++#define GMAC0_TX_HANG_BIT             (1 << 1)
++#define GMAC1_RX_HANG_BIT             (1 << 2)
++#define GMAC1_TX_HANG_BIT             (1 << 3)
++
++int           gmac_in_do_workaround;
++#if 0
++int           debug_cnt, poll_max_cnt;
++#endif
++u32           gmac_workaround_cnt[4];
++u32           toe_global_reg[TOE_GLOBAL_REG_SIZE];
++u32           toe_dma_reg[GMAC_NUM][TOE_DMA_REG_SIZE];
++u32           toe_gmac_reg[GMAC_NUM][TOE_GMAC_REG_SIZE];
++u32           gmac_short_frame_workaround_cnt[2];
++
++static void sl351x_gmac_release_buffers(void);
++static void sl351x_gmac_release_swtx_q(void);
++static void sl351x_gmac_release_rx_q(void);
++#ifdef _TOEQ_CLASSQ_READY_
++static void sl351x_gmac_release_class_q(void);
++static void sl351x_gmac_release_toe_q(void);
++static void sl351x_gmac_release_intr_q(void);
++#endif
++static void sl351x_gmac_release_sw_free_q(void);
++static void sl351x_gmac_release_hw_free_q(void);
++#ifdef CONFIG_SL351x_NAT
++static int get_free_desc_cnt(unsigned long rwptr, int total);
++static void sl351x_gmac_release_hwtx_q(void);
++u32     sl351x_nat_workaround_cnt;
++#endif
++void sl351x_gmac_save_reg(void);
++void sl351x_gmac_restore_reg(void);
++
++
++/*----------------------------------------------------------------------
++*     sl351x_poll_gmac_hanged_status
++*     - Called by timer routine, period 10ms
++*     - If (state != 0 && state == prev state && )
++*----------------------------------------------------------------------*/
++void sl351x_poll_gmac_hanged_status(u32 data)
++{
++      int                     i;
++      u32                     state;
++      TOE_INFO_T              *toe;
++      GMAC_INFO_T             *tp;
++      u32                             hanged_state;
++      // int                          old_operation[GMAC_NUM];
++#ifdef CONFIG_SL351x_NAT
++      u32                             hw_free_cnt;
++#endif
++
++      if (gmac_in_do_workaround)
++              return;
++
++      gmac_in_do_workaround = 1;
++
++      toe = (TOE_INFO_T *)&toe_private_data;
++      hanged_state = 0;
++
++#ifdef SL351x_TEST_WORKAROUND
++      if (toe->gmac[0].operation || toe->gmac[1].operation)
++      {
++              debug_cnt++;
++              if (debug_cnt == (30 * HZ))
++              {
++                      debug_cnt = 0;
++                      hanged_state = GMAC0_RX_HANG_BIT;
++                      goto do_workaround;
++              }
++      }
++#endif
++      if (toe->gmac[0].operation)
++              hanged_state |= GMAC0_RX_HANG_BIT | GMAC0_TX_HANG_BIT;
++
++#if (GMAC_NUM > 1)
++      if (toe->gmac[1].operation)
++              hanged_state |= GMAC1_RX_HANG_BIT | GMAC1_TX_HANG_BIT;
++#endif
++
++      for (i=0; i<GMAC_POLL_HANGED_NUM; i++)
++      {
++              if (hanged_state & GMAC0_RX_HANG_BIT)
++              {
++                      state = readl(TOE_GMAC0_BASE + GMAC_RX_STATE_OFFSET) & GMAC_RX_HANGED_MASK;
++                      if (state != GMAC_RX_HANGED_STATE)
++                              hanged_state &= ~GMAC0_RX_HANG_BIT;
++              }
++              if (hanged_state & GMAC0_TX_HANG_BIT)
++              {
++                      state = readl(TOE_GMAC0_BASE + GMAC_TX_STATE_OFFSET) & GMAC_TX_HANGED_MASK;
++                      if (state != GMAC_TX_HANGED_STATE)
++                              hanged_state &= ~GMAC0_TX_HANG_BIT;
++              }
++#if (GMAC_NUM > 1)
++              if (hanged_state & GMAC1_RX_HANG_BIT)
++              {
++                      state = readl(TOE_GMAC1_BASE + GMAC_RX_STATE_OFFSET) & GMAC_RX_HANGED_MASK;
++                      if (state != GMAC_RX_HANGED_STATE)
++                              hanged_state &= ~GMAC1_RX_HANG_BIT;
++              }
++              if (hanged_state & GMAC1_TX_HANG_BIT)
++              {
++                      state = readl(TOE_GMAC1_BASE + GMAC_TX_STATE_OFFSET) & GMAC_TX_HANGED_MASK;
++                      if (state != GMAC_TX_HANGED_STATE)
++                              hanged_state &= ~GMAC1_TX_HANG_BIT;
++              }
++#endif
++              if (!hanged_state)
++              {
++#if 0
++                      if (i < poll_max_cnt)
++                              poll_max_cnt = i;
++#endif
++                      if (toe->gmac[0].short_frames_cnt >= GMAC_SHORT_FRAME_THRESHOLD)
++                      {
++                              gmac_short_frame_workaround_cnt[0]++;
++                              toe->gmac[0].short_frames_cnt = 0;
++                              goto do_workaround;
++                      }
++#if (GMAC_NUM > 1)
++                      if (toe->gmac[1].short_frames_cnt >= GMAC_SHORT_FRAME_THRESHOLD)
++                      {
++                              gmac_short_frame_workaround_cnt[1]++;
++                              toe->gmac[1].short_frames_cnt = 0;
++                              goto do_workaround;
++                      }
++#endif
++
++#ifdef CONFIG_SL351x_NAT
++                      hw_free_cnt = readl(TOE_GLOBAL_BASE + GLOBAL_HWFQ_RWPTR_REG);
++                      hw_free_cnt = get_free_desc_cnt(hw_free_cnt, TOE_HW_FREEQ_DESC_NUM);
++#ifdef NAT_WORKAROUND_BY_RESET_GMAC
++                      if (readl(TOE_GLOBAL_BASE + 0x4084) && (hw_free_cnt <= PAUSE_SET_HW_FREEQ))
++                      {
++                              sl351x_nat_workaround_cnt++;
++                              goto do_workaround;
++                      }
++#else
++                      if (readl(TOE_GLOBAL_BASE + 0x4084) && (hw_free_cnt <= (PAUSE_SET_HW_FREEQ*2)))
++                      {
++                              sl351x_nat_workaround_cnt++;
++                              sl351x_nat_workaround_handler();
++                      }
++#endif
++#endif
++                      gmac_in_do_workaround = 0;
++                      add_timer(&gmac_workround_timer_obj);
++                      return;
++              }
++      }
++
++do_workaround:
++
++      gmac_initialized = 0;
++      if (hanged_state)
++      {
++              if (hanged_state & GMAC0_RX_HANG_BIT) gmac_workaround_cnt[0]++;
++              if (hanged_state & GMAC0_TX_HANG_BIT) gmac_workaround_cnt[1]++;
++              if (hanged_state & GMAC1_RX_HANG_BIT) gmac_workaround_cnt[2]++;
++              if (hanged_state & GMAC1_TX_HANG_BIT) gmac_workaround_cnt[3]++;
++      }
++
++      for (i=0; i<GMAC_NUM; i++)
++      {
++              tp=(GMAC_INFO_T *)&toe->gmac[i];
++              // old_operation[i] = tp->operation;
++              if (tp->operation)
++              {
++                      netif_stop_queue(tp->dev);
++                      clear_bit(__LINK_STATE_START, &tp->dev->state);
++                      toe_gmac_disable_interrupt(tp->irq);
++                      toe_gmac_disable_tx_rx(tp->dev);
++                      toe_gmac_hw_stop(tp->dev);
++              }
++      }
++
++      // clear all status bits
++      writel(0xffffffff, TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_STATUS_0_REG);
++      writel(0xffffffff, TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_STATUS_1_REG);
++      writel(0xffffffff, TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_STATUS_2_REG);
++      writel(0xffffffff, TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_STATUS_3_REG);
++      writel(0xffffffff, TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_STATUS_4_REG);
++
++#if 0
++      if ((hanged_state & GMAC0_RX_HANG_BIT) &&
++              (readl(TOE_GMAC0_DMA_BASE + 0xdc) & 0xf0))
++      {
++              struct sk_buff *skb;
++              unsigned int buf;
++              buf = readl(TOE_GMAC0_DMA_BASE + 0x68) & ~3;
++#ifdef CONFIG_SL351x_NAT
++              if (buf < toe->hwfq_buf_base_dma || buf > toe->hwfq_buf_end_dma)
++#endif
++              {
++                      skb = (struct sk_buff *)(REG32(buf - SKB_RESERVE_BYTES));
++                      printk("GMAC-0 free a loss SKB 0x%x\n", (u32)skb);
++                      dev_kfree_skb(skb);
++              }
++      }
++      if ((hanged_state & GMAC1_RX_HANG_BIT)  &&
++              (readl(TOE_GMAC1_DMA_BASE + 0xdc) & 0xf0))
++      {
++              struct sk_buff *skb;
++              unsigned int buf;
++              buf = readl(TOE_GMAC1_DMA_BASE + 0x68) & ~3;
++#ifdef CONFIG_SL351x_NAT
++              if (buf < toe->hwfq_buf_base_dma || buf > toe->hwfq_buf_end_dma)
++#endif
++              {
++                      skb = (struct sk_buff *)(REG32(buf - SKB_RESERVE_BYTES));
++                      printk("GMAC-1 free a loss SKB 0x%x\n", (u32)skb);
++                      dev_kfree_skb(skb);
++              }
++      }
++#endif
++
++      sl351x_gmac_release_buffers();
++      sl351x_gmac_save_reg();
++      toe_gmac_sw_reset();
++      sl351x_gmac_restore_reg();
++
++      if (toe->gmac[0].default_qhdr->word1.bits32)
++      {
++              // printk("===> toe->gmac[0].default_qhdr->word1 = 0x%x\n", toe->gmac[0].default_qhdr->word1);
++              sl351x_gmac_release_rx_q();
++              writel(0, &toe->gmac[0].default_qhdr->word1);
++      }
++      if (toe->gmac[1].default_qhdr->word1.bits32)
++      {
++              // printk("===> toe->gmac[1].default_qhdr->word1 = 0x%x\n", toe->gmac[1].default_qhdr->word1);
++              sl351x_gmac_release_rx_q();
++              writel(0, &toe->gmac[1].default_qhdr->word1);
++      }
++
++      gmac_initialized = 1;
++
++#ifdef        CONFIG_SL351x_NAT
++      writel(0, TOE_GLOBAL_BASE + 0x4084);
++#endif
++
++      for (i=0; i<GMAC_NUM; i++)
++      {
++              tp=(GMAC_INFO_T *)&toe->gmac[i];
++              if (tp->operation)
++              {
++                      toe_gmac_enable_interrupt(tp->irq);
++                      toe_gmac_hw_start(tp->dev);
++                      toe_gmac_enable_tx_rx(tp->dev);
++                      netif_wake_queue(tp->dev);
++                      set_bit(__LINK_STATE_START, &tp->dev->state);
++              }
++      }
++
++      gmac_in_do_workaround = 0;
++      add_timer(&gmac_workround_timer_obj);
++}
++
++/*----------------------------------------------------------------------
++*     get_free_desc_cnt
++*----------------------------------------------------------------------*/
++#ifdef CONFIG_SL351x_NAT
++static int get_free_desc_cnt(unsigned long rwptr, int total)
++{
++      unsigned short wptr = rwptr & 0xffff;
++      unsigned short rptr = rwptr >> 16;
++
++      if (wptr >= rptr)
++              return (total - wptr + rptr);
++      else
++              return (rptr - wptr);
++}
++#endif
++/*----------------------------------------------------------------------
++*     sl351x_gmac_release_buffers
++*----------------------------------------------------------------------*/
++static void sl351x_gmac_release_buffers(void)
++{
++      // Free buffers & Descriptors in all SW Tx Queues
++      sl351x_gmac_release_swtx_q();
++
++      // Free buffers in Default Rx Queues
++      sl351x_gmac_release_rx_q();
++
++#ifdef _TOEQ_CLASSQ_READY_
++      // Free buffers in Classification Queues
++      sl351x_gmac_release_class_q();
++
++      // Free buffers in TOE Queues
++      sl351x_gmac_release_toe_q();
++
++      // Free buffers in Interrupt Queues
++      sl351x_gmac_release_intr_q();
++#endif
++
++      // Free buffers & descriptors in SW free queue
++      sl351x_gmac_release_sw_free_q();
++
++      // Free buffers & descriptors in HW free queue
++      sl351x_gmac_release_hw_free_q();
++
++#ifdef CONFIG_SL351x_NAT
++      // Free buffers & descriptors in HW free queue
++      sl351x_gmac_release_hwtx_q();
++#endif
++}
++/*----------------------------------------------------------------------
++*     sl351x_gmac_release_swtx_q
++*----------------------------------------------------------------------*/
++static void sl351x_gmac_release_swtx_q(void)
++{
++      int                             i, j;
++      GMAC_TXDESC_T   *curr_desc;
++      unsigned int    desc_count;
++      TOE_INFO_T              *toe;
++      GMAC_INFO_T             *tp;
++      GMAC_SWTXQ_T    *swtxq;
++      DMA_RWPTR_T             rwptr;
++
++      toe = (TOE_INFO_T *)&toe_private_data;
++      tp = (GMAC_INFO_T *)&toe->gmac[0];
++      for (i=0; i<GMAC_NUM; i++, tp++)
++      {
++              if (!tp->existed) continue;
++              swtxq = (GMAC_SWTXQ_T *)&tp->swtxq[0];
++              for (j=0; j<TOE_SW_TXQ_NUM; j++, swtxq++)
++              {
++                      for (;;)
++                      {
++                              rwptr.bits32 = readl(swtxq->rwptr_reg);
++                              if (rwptr.bits.rptr == swtxq->finished_idx)
++                              break;
++                              curr_desc = (GMAC_TXDESC_T *)swtxq->desc_base + swtxq->finished_idx;
++                              // if (curr_desc->word0.bits.status_tx_ok)
++                              {
++                                      desc_count = curr_desc->word0.bits.desc_count;
++                                      while (--desc_count)
++                                      {
++                                              curr_desc->word0.bits.status_tx_ok = 0;
++                                              swtxq->finished_idx = RWPTR_ADVANCE_ONE(swtxq->finished_idx, swtxq->total_desc_num);
++                                              curr_desc = (GMAC_TXDESC_T *)swtxq->desc_base + swtxq->finished_idx;
++                                      }
++
++                                      curr_desc->word0.bits.status_tx_ok = 0;
++                                      if (swtxq->tx_skb[swtxq->finished_idx])
++                                      {
++                                              dev_kfree_skb_irq(swtxq->tx_skb[swtxq->finished_idx]);
++                                              swtxq->tx_skb[swtxq->finished_idx] = NULL;
++                                      }
++                              }
++                              swtxq->finished_idx = RWPTR_ADVANCE_ONE(swtxq->finished_idx, swtxq->total_desc_num);
++                      }
++                      writel(0, swtxq->rwptr_reg);
++                      swtxq->finished_idx = 0;
++              }
++      }
++
++}
++/*----------------------------------------------------------------------
++*     sl351x_gmac_release_rx_q
++*----------------------------------------------------------------------*/
++static void sl351x_gmac_release_rx_q(void)
++{
++      int                             i;
++      TOE_INFO_T              *toe;
++      GMAC_INFO_T             *tp;
++      DMA_RWPTR_T             rwptr;
++      volatile GMAC_RXDESC_T  *curr_desc;
++      struct sk_buff                  *skb;
++
++      toe = (TOE_INFO_T *)&toe_private_data;
++      tp = (GMAC_INFO_T *)&toe->gmac[0];
++      for (i=0; i<GMAC_NUM; i++, tp++)
++      {
++              if (!tp->existed) continue;
++              rwptr.bits32 = readl(&tp->default_qhdr->word1);
++              while (rwptr.bits.rptr != rwptr.bits.wptr)
++              {
++                      curr_desc = (GMAC_RXDESC_T *)tp->default_desc_base + rwptr.bits.rptr;
++                      skb = (struct sk_buff *)(REG32(__va(curr_desc->word2.buf_adr) - SKB_RESERVE_BYTES));
++                      dev_kfree_skb_irq(skb);
++                      rwptr.bits.rptr = RWPTR_ADVANCE_ONE(rwptr.bits.rptr, tp->default_desc_num);
++                      SET_RPTR(&tp->default_qhdr->word1, rwptr.bits.rptr);
++                      rwptr.bits32 = readl(&tp->default_qhdr->word1);
++              }  // while
++              writel(0, &tp->default_qhdr->word1);
++              tp->rx_rwptr.bits32 = 0;
++      } // for
++
++}
++/*----------------------------------------------------------------------
++*     sl351x_gmac_release_class_q
++*----------------------------------------------------------------------*/
++#ifdef _TOEQ_CLASSQ_READY_
++static void sl351x_gmac_release_class_q(void)
++{
++      int                             i;
++      TOE_INFO_T              *toe;
++      CLASSQ_INFO_T   *classq;
++      DMA_RWPTR_T             rwptr;
++      volatile GMAC_RXDESC_T  *curr_desc;
++      struct sk_buff                  *skb;
++
++      toe = (TOE_INFO_T *)&toe_private_data;
++      classq = (CLASSQ_INFO_T *)&toe->classq[0];
++      for (i=0; i<TOE_CLASS_QUEUE_NUM; i++, classq++)
++      {
++              rwptr.bits32 = readl(&classq->qhdr->word1);
++              while (rwptr.bits.rptr != rwptr.bits.wptr)
++              {
++                      curr_desc = (GMAC_RXDESC_T *)classq->desc_base + rwptr.bits.rptr;
++                      skb = (struct sk_buff *)(REG32(__va(curr_desc->word2.buf_adr) - SKB_RESERVE_BYTES));
++                      dev_kfree_skb_irq(skb);
++                      rwptr.bits.rptr = RWPTR_ADVANCE_ONE(rwptr.bits.rptr, classq->desc_num);
++                      SET_RPTR(&classq->qhdr->word1, rwptr.bits.rptr);
++                      rwptr.bits32 = readl(&classq->qhdr->word1);
++              }  // while
++              writel(0, &classq->qhdr->word1);
++              classq->rwptr.bits32 = 0;
++      } // for
++
++}
++#endif
++/*----------------------------------------------------------------------
++*     sl351x_gmac_release_toe_q
++*----------------------------------------------------------------------*/
++#ifdef _TOEQ_CLASSQ_READY_
++static void sl351x_gmac_release_toe_q(void)
++{
++      int                             i;
++      TOE_INFO_T              *toe;
++      TOEQ_INFO_T             *toeq_info;
++      TOE_QHDR_T              *toe_qhdr;
++      DMA_RWPTR_T             rwptr;
++      volatile GMAC_RXDESC_T  *curr_desc;
++      unsigned int    rptr, wptr;
++      GMAC_RXDESC_T   *toe_curr_desc;
++      struct sk_buff                  *skb;
++
++      toe = (TOE_INFO_T *)&toe_private_data;
++      toe_qhdr = (TOE_QHDR_T *)TOE_TOE_QUE_HDR_BASE;
++      for (i=0; i<TOE_TOE_QUEUE_NUM; i++, toe_qhdr++)
++      {
++              toeq_info = (TOEQ_INFO_T *)&toe->toeq[i];
++              wptr = toe_qhdr->word1.bits.wptr;
++              rptr = toe_qhdr->word1.bits.rptr;
++              while (rptr != wptr)
++              {
++                      toe_curr_desc = (GMAC_RXDESC_T *)toeq_info->desc_base + rptr;
++                      skb = (struct sk_buff *)(REG32(__va(toe_curr_desc->word2.buf_adr) - SKB_RESERVE_BYTES));
++                      dev_kfree_skb_irq(skb);
++                      rptr = RWPTR_ADVANCE_ONE(rptr, toeq_info->desc_num);
++                      SET_RPTR(&toe_qhdr->word1.bits32, rptr);
++                      wptr = toe_qhdr->word1.bits.wptr;
++                      rptr = toe_qhdr->word1.bits.rptr;
++              }
++              toe_qhdr->word1.bits32 = 0;
++              toeq_info->rwptr.bits32 = 0;
++      }
++}
++#endif
++/*----------------------------------------------------------------------
++*     sl351x_gmac_release_intr_q
++*----------------------------------------------------------------------*/
++#ifdef _TOEQ_CLASSQ_READY_
++static void sl351x_gmac_release_intr_q(void)
++{
++}
++#endif
++/*----------------------------------------------------------------------
++*     sl351x_gmac_release_sw_free_q
++*----------------------------------------------------------------------*/
++static void sl351x_gmac_release_sw_free_q(void)
++{
++      TOE_INFO_T                              *toe;
++      volatile DMA_RWPTR_T    fq_rwptr;
++      volatile GMAC_RXDESC_T  *fq_desc;
++
++      toe = (TOE_INFO_T *)&toe_private_data;
++      fq_rwptr.bits32 = readl(TOE_GLOBAL_BASE + GLOBAL_SWFQ_RWPTR_REG);
++
++      while ((unsigned short)RWPTR_ADVANCE_ONE(fq_rwptr.bits.wptr, TOE_SW_FREEQ_DESC_NUM) != fq_rwptr.bits.rptr)
++      {
++              struct sk_buff *skb;
++              if ((skb = dev_alloc_skb(SW_RX_BUF_SIZE))==NULL)  /* allocate socket buffer */
++              {
++                      printk("%s::skb buffer allocation fail !\n",__func__); while(1);
++              }
++              // *(unsigned int *)(skb->data) = (unsigned int)skb;
++              REG32(skb->data) = (unsigned long)skb;
++              skb_reserve(skb, SKB_RESERVE_BYTES);
++
++              fq_rwptr.bits.wptr = RWPTR_ADVANCE_ONE(fq_rwptr.bits.wptr, TOE_SW_FREEQ_DESC_NUM);
++              fq_desc = (volatile GMAC_RXDESC_T *)toe->swfq_desc_base + fq_rwptr.bits.wptr;
++              fq_desc->word2.buf_adr = (unsigned int)__pa(skb->data);
++              SET_WPTR(TOE_GLOBAL_BASE + GLOBAL_SWFQ_RWPTR_REG, fq_rwptr.bits.wptr);
++              fq_rwptr.bits32 = readl(TOE_GLOBAL_BASE + GLOBAL_SWFQ_RWPTR_REG);
++      }
++
++      toe->fq_rx_rwptr.bits.wptr = TOE_SW_FREEQ_DESC_NUM - 1;
++      toe->fq_rx_rwptr.bits.rptr = 0;
++      writel(toe->fq_rx_rwptr.bits32, TOE_GLOBAL_BASE + GLOBAL_SWFQ_RWPTR_REG);
++
++}
++/*----------------------------------------------------------------------
++*     sl351x_gmac_release_hw_free_q
++*----------------------------------------------------------------------*/
++static void sl351x_gmac_release_hw_free_q(void)
++{
++      DMA_RWPTR_T                     rwptr_reg;
++
++#ifdef CONFIG_SL351x_NAT
++      int                                     i;
++      TOE_INFO_T                      *toe;
++      GMAC_RXDESC_T           *desc_ptr;
++      unsigned int            buf_ptr;
++
++      toe = (TOE_INFO_T *)&toe_private_data;
++      desc_ptr = (GMAC_RXDESC_T *)toe->hwfq_desc_base;
++      buf_ptr = (unsigned int)toe->hwfq_buf_base_dma;
++      for (i=0; i<TOE_HW_FREEQ_DESC_NUM; i++)
++      {
++              desc_ptr->word0.bits.buffer_size = HW_RX_BUF_SIZE;
++              desc_ptr->word1.bits.sw_id = i;
++              desc_ptr->word2.buf_adr = (unsigned int)buf_ptr;
++              desc_ptr++;
++              buf_ptr += HW_RX_BUF_SIZE;
++      }
++#endif
++      rwptr_reg.bits.wptr = TOE_HW_FREEQ_DESC_NUM - 1;
++      rwptr_reg.bits.rptr = 0;
++      writel(rwptr_reg.bits32, TOE_GLOBAL_BASE + GLOBAL_HWFQ_RWPTR_REG);
++}
++
++/*----------------------------------------------------------------------
++*     sl351x_gmac_release_hw_free_q
++*----------------------------------------------------------------------*/
++#ifdef CONFIG_SL351x_NAT
++static void sl351x_gmac_release_hwtx_q(void)
++{
++      int                             i;
++      unsigned int    rwptr_addr;
++
++      rwptr_addr = TOE_GMAC0_DMA_BASE + GMAC_HW_TX_QUEUE0_PTR_REG;
++      for (i=0; i<TOE_HW_TXQ_NUM; i++)
++      {
++              writel(0, rwptr_addr);
++              rwptr_addr+=4;
++      }
++      rwptr_addr = TOE_GMAC1_DMA_BASE + GMAC_HW_TX_QUEUE0_PTR_REG;
++      for (i=0; i<TOE_HW_TXQ_NUM; i++)
++      {
++              writel(0, rwptr_addr);
++              rwptr_addr+=4;
++      }
++}
++#endif
++
++/*----------------------------------------------------------------------
++*     sl351x_gmac_save_reg
++*----------------------------------------------------------------------*/
++void sl351x_gmac_save_reg(void)
++{
++      int     i;
++      volatile u32    *destp;
++      unsigned int    srce_addr;
++
++      srce_addr = TOE_GLOBAL_BASE;
++      destp = (volatile u32 *)toe_global_reg;
++      for (i=0; i<TOE_GLOBAL_REG_SIZE; i++, destp++, srce_addr+=4)
++              *destp = readl(srce_addr);
++
++      srce_addr = TOE_GMAC0_DMA_BASE;
++      destp = (volatile u32 *)&toe_dma_reg[0][0];
++      for (i=0; i<TOE_DMA_REG_SIZE; i++, destp++, srce_addr+=4)
++      {
++              if (srce_addr ==  (TOE_GMAC0_DMA_BASE+0x38))
++                      srce_addr = (TOE_GMAC0_DMA_BASE+0x50);
++              if (srce_addr ==  (TOE_GMAC0_DMA_BASE+0x58))
++                      srce_addr = (TOE_GMAC0_DMA_BASE+0x70);
++
++              *destp = readl(srce_addr);
++      }
++      srce_addr = TOE_GMAC1_DMA_BASE;
++      destp = (volatile u32 *)&toe_dma_reg[1][0];
++      for (i=0; i<TOE_DMA_REG_SIZE; i++, destp++, srce_addr+=4)
++      {
++              if (srce_addr ==  (TOE_GMAC0_DMA_BASE+0x38))
++                      srce_addr = (TOE_GMAC0_DMA_BASE+0x50);
++              if (srce_addr ==  (TOE_GMAC0_DMA_BASE+0x58))
++                      srce_addr = (TOE_GMAC0_DMA_BASE+0x70);
++
++              *destp = readl(srce_addr);
++      }
++
++      srce_addr = TOE_GMAC0_BASE;
++      destp = (volatile u32 *)&toe_gmac_reg[0][0];
++      for (i=0; i<TOE_GMAC_REG_SIZE; i++, destp++, srce_addr+=4)
++              *destp = readl(srce_addr);
++
++      srce_addr = TOE_GMAC1_BASE;
++      destp = (volatile u32 *)&toe_gmac_reg[1][0];
++      for (i=0; i<TOE_GMAC_REG_SIZE; i++, destp++, srce_addr+=4)
++              *destp = readl(srce_addr);
++}
++
++/*----------------------------------------------------------------------
++*     sl351x_gmac_restore_reg
++*----------------------------------------------------------------------*/
++void sl351x_gmac_restore_reg(void)
++{
++      int     i;
++      volatile u32    *srcep;
++      unsigned int    dest_addr;
++
++      srcep = (volatile u32 *)&toe_dma_reg[0][0];
++      dest_addr = TOE_GMAC0_DMA_BASE;
++      for (i=0; i<TOE_DMA_REG_SIZE; i++, dest_addr+=4, srcep++)
++      {
++              if (dest_addr == (TOE_GMAC0_DMA_BASE+0x38))
++                      dest_addr = (TOE_GMAC0_DMA_BASE+0x50);
++              if (dest_addr == (TOE_GMAC0_DMA_BASE+0x58))
++                      dest_addr = (TOE_GMAC0_DMA_BASE+0x70);
++
++              writel(*srcep, dest_addr);
++              // gmac_write_reg(dest_addr, 0, *srcep, 0xffffffff);
++      }
++      srcep = (volatile u32 *)&toe_dma_reg[1][0];
++      dest_addr = TOE_GMAC1_DMA_BASE;
++      for (i=0; i<TOE_DMA_REG_SIZE; i++, dest_addr+=4, srcep++)
++      {
++              if (dest_addr == (TOE_GMAC0_DMA_BASE+0x38))
++                      dest_addr = (TOE_GMAC0_DMA_BASE+0x50);
++              if (dest_addr == (TOE_GMAC0_DMA_BASE+0x58))
++                      dest_addr = (TOE_GMAC0_DMA_BASE+0x70);
++
++              writel(*srcep, dest_addr);
++              // gmac_write_reg(dest_addr, 0, *srcep, 0xffffffff);
++      }
++
++      srcep = (volatile u32 *)&toe_gmac_reg[0][0];
++      dest_addr = TOE_GMAC0_BASE;
++      for (i=0; i<TOE_GMAC_REG_SIZE; i++, dest_addr+=4, srcep++)
++              writel(*srcep, dest_addr);
++
++      srcep = (volatile u32 *)&toe_gmac_reg[1][0];
++      dest_addr = TOE_GMAC1_BASE;
++      for (i=0; i<TOE_GMAC_REG_SIZE; i++, dest_addr+=4, srcep++)
++              writel(*srcep, dest_addr);
++
++      srcep = (volatile u32 *)toe_global_reg;
++      dest_addr = TOE_GLOBAL_BASE;
++      for (i=0; i<TOE_GLOBAL_REG_SIZE; i++, dest_addr+=4, srcep++)
++              writel(*srcep, dest_addr);
++
++}
++
++#ifdef CONFIG_SL351x_NAT
++/*----------------------------------------------------------------------
++*     sl351x_nat_workaround_init
++*----------------------------------------------------------------------*/
++#define NAT_WORAROUND_DESC_POWER      (6)
++#define NAT_WORAROUND_DESC_NUM                (2 << NAT_WORAROUND_DESC_POWER)
++dma_addr_t sl351x_nat_workaround_desc_dma;
++void sl351x_nat_workaround_init(void)
++{
++      unsigned int    desc_buf;
++
++      desc_buf = (unsigned int)DMA_MALLOC((NAT_WORAROUND_DESC_NUM * sizeof(GMAC_RXDESC_T)),
++                                              (dma_addr_t *)&sl351x_nat_workaround_desc_dma) ;
++      memset((void *)desc_buf, 0, NAT_WORAROUND_DESC_NUM * sizeof(GMAC_RXDESC_T));
++
++      // DMA Queue Base & Size
++      writel((sl351x_nat_workaround_desc_dma & DMA_Q_BASE_MASK) | NAT_WORAROUND_DESC_POWER,
++                      TOE_GLOBAL_BASE + 0x4080);
++      writel(0, TOE_GLOBAL_BASE + 0x4084);
++}
++
++/*----------------------------------------------------------------------
++*     sl351x_nat_workaround_handler
++*----------------------------------------------------------------------*/
++#ifndef NAT_WORKAROUND_BY_RESET_GMAC
++static void sl351x_nat_workaround_handler(void)
++{
++      int                                     i;
++      DMA_RWPTR_T                     rwptr;
++      GMAC_RXDESC_T           *desc_ptr;
++      unsigned int            buf_ptr;
++      TOE_INFO_T                      *toe;
++      GMAC_CONFIG0_T          config0;
++      unsigned int            rwptr_addr;
++
++      toe = (TOE_INFO_T *)&toe_private_data;
++
++      // disable Rx of GMAC-0 & 1
++      config0.bits32 = readl(TOE_GMAC0_BASE+GMAC_CONFIG0);
++      config0.bits.dis_rx = 1;
++      writel(config0.bits32, TOE_GMAC0_BASE+GMAC_CONFIG0);
++      config0.bits32 = readl(TOE_GMAC1_BASE+GMAC_CONFIG0);
++      config0.bits.dis_rx = 1;
++      writel(config0.bits32, TOE_GMAC1_BASE+GMAC_CONFIG0);
++
++      // wait GMAC-0 HW Tx finished
++      rwptr_addr = TOE_GMAC0_DMA_BASE + GMAC_HW_TX_QUEUE0_PTR_REG;
++      for (i=0; i<TOE_HW_TXQ_NUM; i++)
++      {
++              rwptr.bits32 = readl(rwptr_addr);
++              if (rwptr.bits.rptr != rwptr.bits.wptr)
++                      return; // wait the HW to send packets and release buffers
++              rwptr_addr+=4;
++      }
++      rwptr_addr = TOE_GMAC1_DMA_BASE + GMAC_HW_TX_QUEUE0_PTR_REG;
++      for (i=0; i<TOE_HW_TXQ_NUM; i++)
++      {
++              rwptr.bits32 = readl(rwptr_addr);
++              if (rwptr.bits.rptr != rwptr.bits.wptr)
++                      return; // wait the HW to send packets and release buffers
++              rwptr_addr+=4;
++      }
++
++      // printk("sl351x_nat_workaround_handler %d\n", sl351x_nat_workaround_cnt);
++      desc_ptr = (GMAC_RXDESC_T *)toe->hwfq_desc_base;
++      buf_ptr = (unsigned int)toe->hwfq_buf_base_dma;
++      for (i=0; i<TOE_HW_FREEQ_DESC_NUM; i++)
++      {
++              desc_ptr->word0.bits.buffer_size = HW_RX_BUF_SIZE;
++              desc_ptr->word1.bits.sw_id = i;
++              desc_ptr->word2.buf_adr = (unsigned int)buf_ptr;
++              desc_ptr++;
++              buf_ptr += HW_RX_BUF_SIZE;
++      }
++      rwptr.bits32 = readl(TOE_GLOBAL_BASE + GLOBAL_HWFQ_RWPTR_REG);
++      rwptr.bits.wptr = RWPTR_RECEDE_ONE(rwptr.bits.rptr, TOE_HW_FREEQ_DESC_NUM);
++      writel(rwptr.bits32, TOE_GLOBAL_BASE + GLOBAL_HWFQ_RWPTR_REG);
++      writel(0, TOE_GLOBAL_BASE + 0x4084);
++
++      // Enable Rx of GMAC-0 & 1
++      config0.bits32 = readl(TOE_GMAC0_BASE+GMAC_CONFIG0);
++      config0.bits.dis_rx = 0;
++      writel(config0.bits32, TOE_GMAC0_BASE+GMAC_CONFIG0);
++      config0.bits32 = readl(TOE_GMAC1_BASE+GMAC_CONFIG0);
++      config0.bits.dis_rx = 0;
++      writel(config0.bits32, TOE_GMAC1_BASE+GMAC_CONFIG0);
++}
++#endif
++#endif // CONFIG_SL351x_NAT
++
++#endif // SL351x_GMAC_WORKAROUND
++
++/* get the mac addresses from flash
++ *can't do this in module_init because mtd driver is initialized after ethernet
++ */
++static __init int sl351x_mac_address_init(void)
++{
++      GMAC_INFO_T             *tp;
++      struct sockaddr sock;
++      int i;
++
++      /* get mac address from FLASH */
++      gmac_get_mac_address();
++
++      for (i = 0; i < GMAC_NUM; i++) {
++              tp = (GMAC_INFO_T *)&toe_private_data.gmac[i];
++              memcpy(&sock.sa_data[0],&eth_mac[tp->port_id][0],6);
++              gmac_set_mac_address(tp->dev,(void *)&sock);
++      }
++
++        return 0;
++}
++late_initcall(sl351x_mac_address_init);
++
++
+Index: linux-2.6.23.16/drivers/net/sl351x_hash.c
+===================================================================
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.23.16/drivers/net/sl351x_hash.c  2008-03-15 16:59:32.361970401 +0200
+@@ -0,0 +1,713 @@
++/**************************************************************************
++* Copyright 2006 StorLink Semiconductors, Inc.  All rights reserved.
++*--------------------------------------------------------------------------
++* Name                        : sl351x_hash.c
++* Description :
++*             Handle Storlink SL351x Hash Functions
++*
++* History
++*
++*     Date            Writer          Description
++*----------------------------------------------------------------------------
++*     03/13/2006      Gary Chen       Create and implement
++*
++****************************************************************************/
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/compiler.h>
++#include <linux/pci.h>
++#include <linux/init.h>
++#include <linux/ioport.h>
++#include <linux/netdevice.h>
++#include <linux/etherdevice.h>
++#include <linux/rtnetlink.h>
++#include <linux/delay.h>
++#include <linux/ethtool.h>
++#include <linux/mii.h>
++#include <linux/completion.h>
++#include <asm/hardware.h>
++#include <asm/io.h>
++#include <asm/irq.h>
++#include <asm/semaphore.h>
++#include <asm/arch/irqs.h>
++#include <asm/arch/it8712.h>
++#include <linux/mtd/kvctl.h>
++#include <linux/skbuff.h>
++#include <linux/in.h>
++#include <linux/ip.h>
++#include <linux/tcp.h>
++#include <linux/list.h>
++#define        MIDWAY
++#define        SL_LEPUS
++
++#include <asm/arch/sl2312.h>
++#include <asm/arch/sl351x_gmac.h>
++#include <asm/arch/sl351x_hash_cfg.h>
++
++#ifndef RXTOE_DEBUG
++#define RXTOE_DEBUG
++#endif
++#undef RXTOE_DEBUG
++
++/*----------------------------------------------------------------------
++* Definition
++*----------------------------------------------------------------------*/
++#define       hash_printf                             printk
++
++#define HASH_TIMER_PERIOD             (30)    // seconds
++#define HASH_ILLEGAL_INDEX            0xffff
++
++/*----------------------------------------------------------------------
++* Variables
++*----------------------------------------------------------------------*/
++u32                                   hash_nat_owner_bits[HASH_TOTAL_ENTRIES/32];
++char                          hash_tables[HASH_TOTAL_ENTRIES][HASH_MAX_BYTES] __attribute__ ((aligned(16)));
++static struct timer_list hash_timer_obj;
++LIST_HEAD(hash_timeout_list);
++
++/*----------------------------------------------------------------------
++* Functions
++*----------------------------------------------------------------------*/
++void dm_long(u32 location, int length);
++static void hash_timer_func(u32 data);
++
++/*----------------------------------------------------------------------
++* hash_init
++*----------------------------------------------------------------------*/
++void sl351x_hash_init(void)
++{
++      int i;
++      volatile u32 *dp1, *dp2, dword;
++
++      dp1 = (volatile u32 *) TOE_V_BIT_BASE;
++      dp2 = (volatile u32 *) TOE_A_BIT_BASE;
++
++      for (i=0; i<HASH_TOTAL_ENTRIES/32; i++)
++      {
++              *dp1++ = 0;
++              dword = *dp2++; // read-clear
++      }
++      memset((void *)&hash_nat_owner_bits, 0, sizeof(hash_nat_owner_bits));
++      memset((void *)&hash_tables, 0, sizeof(hash_tables));
++
++      init_timer(&hash_timer_obj);
++      hash_timer_obj.expires = jiffies + (HASH_TIMER_PERIOD * HZ);
++      hash_timer_obj.data = (unsigned long)&hash_timer_obj;
++      hash_timer_obj.function = (void *)&hash_timer_func;
++      add_timer(&hash_timer_obj);
++
++#if (HASH_MAX_BYTES == 128)
++      writel((unsigned long)__pa(&hash_tables) | 3,   // 32 words
++                      TOE_GLOBAL_BASE + GLOBAL_HASH_TABLE_BASE_REG);
++#elif (HASH_MAX_BYTES == 64)
++      writel((unsigned long)__pa(&hash_tables) | 2,   // 16 words
++                      TOE_GLOBAL_BASE + GLOBAL_HASH_TABLE_BASE_REG);
++#else
++      #error Incorrect setting for HASH_MAX_BYTES
++#endif
++
++}
++/*----------------------------------------------------------------------
++* hash_add_entry
++*----------------------------------------------------------------------*/
++int hash_add_entry(HASH_ENTRY_T *entry)
++{
++      int     rc;
++      u32     key[HASH_MAX_DWORDS];
++      rc = hash_build_keys((u32 *)&key, entry);
++      if (rc < 0)
++              return -1;
++      hash_write_entry(entry, (unsigned char*) &key[0]);
++//    hash_set_valid_flag(entry->index, 1);
++//    printk("Dump hash key!\n");
++//    dump_hash_key(entry);
++      return entry->index;
++}
++
++/*----------------------------------------------------------------------
++* hash_set_valid_flag
++*----------------------------------------------------------------------*/
++void hash_set_valid_flag(int index, int valid)
++{
++      register u32 reg32;
++
++      reg32 = TOE_V_BIT_BASE + (index/32) * 4;
++
++      if (valid)
++      {
++              writel(readl(reg32) | (1 << (index%32)), reg32);
++      }
++      else
++      {
++              writel(readl(reg32) & ~(1 << (index%32)), reg32);
++      }
++}
++
++/*----------------------------------------------------------------------
++* hash_set_nat_owner_flag
++*----------------------------------------------------------------------*/
++void hash_set_nat_owner_flag(int index, int valid)
++{
++      if (valid)
++      {
++              hash_nat_owner_bits[index/32] |= (1 << (index % 32));
++      }
++      else
++      {
++              hash_nat_owner_bits[index/32] &= ~(1 << (index % 32));
++      }
++}
++
++
++/*----------------------------------------------------------------------
++* hash_build_keys
++*----------------------------------------------------------------------*/
++int hash_build_keys(u32 *destp, HASH_ENTRY_T *entry)
++{
++      u32     data;
++      unsigned char   *cp;
++      int                             i, j;
++      unsigned short  index;
++      int                     total;
++
++      memset((void *)destp, 0, HASH_MAX_BYTES);
++      cp = (unsigned char *)destp;
++
++      if (entry->key_present.port || entry->key_present.Ethertype)
++      {
++              HASH_PUSH_WORD(cp, entry->key.Ethertype);               // word 0
++              HASH_PUSH_BYTE(cp, entry->key.port);                    // Byte 2
++              HASH_PUSH_BYTE(cp, 0);                                                  // Byte 3
++      }
++      else
++      {
++              HASH_PUSH_DWORD(cp, 0);
++      }
++
++      if (entry->key_present.da || entry->key_present.sa)
++      {
++              unsigned char mac[4];
++              if (entry->key_present.da)
++              {
++                      for (i=0; i<4; i++)
++                              HASH_PUSH_BYTE(cp, entry->key.da[i]);
++              }
++              mac[0] = (entry->key_present.da) ? entry->key.da[4] : 0;
++              mac[1] = (entry->key_present.da) ? entry->key.da[5] : 0;
++              mac[2] = (entry->key_present.sa) ? entry->key.sa[0] : 0;
++              mac[3] = (entry->key_present.sa) ? entry->key.sa[1] : 0;
++              data = mac[0] + (mac[1]<<8) + (mac[2]<<16) + (mac[3]<<24);
++              HASH_PUSH_DWORD(cp, data);
++              if (entry->key_present.sa)
++              {
++                      for (i=2; i<6; i++)
++                              HASH_PUSH_BYTE(cp, entry->key.sa[i]);
++              }
++      }
++
++      if (entry->key_present.pppoe_sid || entry->key_present.vlan_id)
++      {
++              HASH_PUSH_WORD(cp, entry->key.vlan_id);         // low word
++              HASH_PUSH_WORD(cp, entry->key.pppoe_sid);       // high word
++      }
++      if (entry->key_present.ipv4_hdrlen || entry->key_present.ip_tos || entry->key_present.ip_protocol)
++      {
++              HASH_PUSH_BYTE(cp, entry->key.ip_protocol);             // Byte 0
++              HASH_PUSH_BYTE(cp, entry->key.ip_tos);                  // Byte 1
++              HASH_PUSH_BYTE(cp, entry->key.ipv4_hdrlen);             // Byte 2
++              HASH_PUSH_BYTE(cp, 0);                                                  // Byte 3
++      }
++
++      if (entry->key_present.ipv6_flow_label)
++      {
++              HASH_PUSH_DWORD(cp, entry->key.ipv6_flow_label);        // low word
++      }
++      if (entry->key_present.sip)
++      {
++              // input (entry->key.sip[i]) is network-oriented
++              // output (hash key) is host-oriented
++              for (i=3; i>=0; i--)
++                      HASH_PUSH_BYTE(cp, entry->key.sip[i]);
++              if (entry->key.ipv6)
++              {
++                      for (i=4; i<16; i+=4)
++                      {
++                              for (j=i+3; j>=i; j--)
++                                      HASH_PUSH_BYTE(cp, entry->key.sip[j]);
++                      }
++              }
++      }
++      if (entry->key_present.dip)
++      {
++              // input (entry->key.sip[i]) is network-oriented
++              // output (hash key) is host-oriented
++              for (i=3; i>=0; i--)
++                      HASH_PUSH_BYTE(cp, entry->key.dip[i]);
++              if (entry->key.ipv6)
++              {
++                      for (i=4; i<16; i+=4)
++                      {
++                              for (j=i+3; j>=i; j--)
++                                      HASH_PUSH_BYTE(cp, entry->key.dip[j]);
++                      }
++              }
++      }
++
++      if (entry->key_present.l4_bytes_0_3)
++      {
++              HASH_PUSH_BYTE(cp, entry->key.l4_bytes[0]);
++              HASH_PUSH_BYTE(cp, entry->key.l4_bytes[1]);
++              HASH_PUSH_BYTE(cp, entry->key.l4_bytes[2]);
++              HASH_PUSH_BYTE(cp, entry->key.l4_bytes[3]);
++      }
++      if (entry->key_present.l4_bytes_4_7)
++      {
++              HASH_PUSH_BYTE(cp, entry->key.l4_bytes[4]);
++              HASH_PUSH_BYTE(cp, entry->key.l4_bytes[5]);
++              HASH_PUSH_BYTE(cp, entry->key.l4_bytes[6]);
++              HASH_PUSH_BYTE(cp, entry->key.l4_bytes[7]);
++      }
++      if (entry->key_present.l4_bytes_8_11)
++      {
++              HASH_PUSH_BYTE(cp, entry->key.l4_bytes[8]);
++              HASH_PUSH_BYTE(cp, entry->key.l4_bytes[9]);
++              HASH_PUSH_BYTE(cp, entry->key.l4_bytes[10]);
++              HASH_PUSH_BYTE(cp, entry->key.l4_bytes[11]);
++      }
++      if (entry->key_present.l4_bytes_12_15)
++      {
++              HASH_PUSH_BYTE(cp, entry->key.l4_bytes[12]);
++              HASH_PUSH_BYTE(cp, entry->key.l4_bytes[13]);
++              HASH_PUSH_BYTE(cp, entry->key.l4_bytes[14]);
++              HASH_PUSH_BYTE(cp, entry->key.l4_bytes[15]);
++      }
++      if (entry->key_present.l4_bytes_16_19)
++      {
++              HASH_PUSH_BYTE(cp, entry->key.l4_bytes[16]);
++              HASH_PUSH_BYTE(cp, entry->key.l4_bytes[17]);
++              HASH_PUSH_BYTE(cp, entry->key.l4_bytes[18]);
++              HASH_PUSH_BYTE(cp, entry->key.l4_bytes[19]);
++      }
++      if (entry->key_present.l4_bytes_20_23)
++      {
++              HASH_PUSH_BYTE(cp, entry->key.l4_bytes[20]);
++              HASH_PUSH_BYTE(cp, entry->key.l4_bytes[21]);
++              HASH_PUSH_BYTE(cp, entry->key.l4_bytes[22]);
++              HASH_PUSH_BYTE(cp, entry->key.l4_bytes[23]);
++      }
++      if (entry->key_present.l7_bytes_0_3)
++      {
++              HASH_PUSH_BYTE(cp, entry->key.l7_bytes[0]);
++              HASH_PUSH_BYTE(cp, entry->key.l7_bytes[1]);
++              HASH_PUSH_BYTE(cp, entry->key.l7_bytes[2]);
++              HASH_PUSH_BYTE(cp, entry->key.l7_bytes[3]);
++      }
++      if (entry->key_present.l7_bytes_4_7)
++      {
++              HASH_PUSH_BYTE(cp, entry->key.l7_bytes[4]);
++              HASH_PUSH_BYTE(cp, entry->key.l7_bytes[5]);
++              HASH_PUSH_BYTE(cp, entry->key.l7_bytes[6]);
++              HASH_PUSH_BYTE(cp, entry->key.l7_bytes[7]);
++      }
++      if (entry->key_present.l7_bytes_8_11)
++      {
++              HASH_PUSH_BYTE(cp, entry->key.l7_bytes[8]);
++              HASH_PUSH_BYTE(cp, entry->key.l7_bytes[9]);
++              HASH_PUSH_BYTE(cp, entry->key.l7_bytes[10]);
++              HASH_PUSH_BYTE(cp, entry->key.l7_bytes[11]);
++      }
++      if (entry->key_present.l7_bytes_12_15)
++      {
++              HASH_PUSH_BYTE(cp, entry->key.l7_bytes[12]);
++              HASH_PUSH_BYTE(cp, entry->key.l7_bytes[13]);
++              HASH_PUSH_BYTE(cp, entry->key.l7_bytes[14]);
++              HASH_PUSH_BYTE(cp, entry->key.l7_bytes[15]);
++      }
++      if (entry->key_present.l7_bytes_16_19)
++      {
++              HASH_PUSH_BYTE(cp, entry->key.l7_bytes[16]);
++              HASH_PUSH_BYTE(cp, entry->key.l7_bytes[17]);
++              HASH_PUSH_BYTE(cp, entry->key.l7_bytes[18]);
++              HASH_PUSH_BYTE(cp, entry->key.l7_bytes[19]);
++      }
++      if (entry->key_present.l7_bytes_20_23)
++      {
++              HASH_PUSH_BYTE(cp, entry->key.l7_bytes[20]);
++              HASH_PUSH_BYTE(cp, entry->key.l7_bytes[21]);
++              HASH_PUSH_BYTE(cp, entry->key.l7_bytes[22]);
++              HASH_PUSH_BYTE(cp, entry->key.l7_bytes[23]);
++      }
++
++      // get hash index
++      total = (u32)((u32)cp - (u32)destp) / (sizeof(u32));
++
++      if (total > HASH_MAX_KEY_DWORD)
++      {
++              //hash_printf("Total key words (%d) is too large (> %d)!\n",
++              //                              total, HASH_MAX_KEY_DWORD);
++              return -1;
++      }
++
++      if (entry->key_present.port || entry->key_present.Ethertype)
++              index = hash_gen_crc16((unsigned char *)destp, total * 4);
++      else
++      {
++              if (total == 1)
++              {
++                      hash_printf("No key is assigned!\n");
++                      return -1;
++              }
++
++              index = hash_gen_crc16((unsigned char *)(destp+1), (total-1) * 4);
++      }
++
++      entry->index = index & HASH_BITS_MASK;
++
++      //hash_printf("Total key words = %d, Hash Index= %d\n",
++      //                              total, entry->index);
++
++      cp = (unsigned char *)destp;
++      cp+=3;
++      HASH_PUSH_BYTE(cp, entry->rule);        // rule
++
++      entry->total_dwords = total;
++
++      return total;
++}
++
++/*----------------------------------------------------------------------
++* hash_build_nat_keys
++*----------------------------------------------------------------------*/
++void hash_build_nat_keys(u32 *destp, HASH_ENTRY_T *entry)
++{
++      unsigned char   *cp;
++      int                             i;
++      unsigned short  index;
++      int                     total;
++
++      memset((void *)destp, 0, HASH_MAX_BYTES);
++
++      cp = (unsigned char *)destp + 2;
++      HASH_PUSH_BYTE(cp, entry->key.port);
++      cp++;
++
++      if (entry->key_present.pppoe_sid || entry->key_present.vlan_id)
++      {
++              HASH_PUSH_WORD(cp, entry->key.vlan_id);         // low word
++              HASH_PUSH_WORD(cp, entry->key.pppoe_sid);       // high word
++      }
++
++      HASH_PUSH_BYTE(cp, entry->key.ip_protocol);
++      cp+=3;
++
++      // input (entry->key.sip[i]) is network-oriented
++      // output (hash key) is host-oriented
++      for (i=3; i>=0; i--)
++              HASH_PUSH_BYTE(cp, entry->key.sip[i]);
++
++      // input (entry->key.sip[i]) is network-oriented
++      // output (hash key) is host-oriented
++      for (i=3; i>=0; i--)
++              HASH_PUSH_BYTE(cp, entry->key.dip[i]);
++
++      HASH_PUSH_BYTE(cp, entry->key.l4_bytes[0]);
++      HASH_PUSH_BYTE(cp, entry->key.l4_bytes[1]);
++      HASH_PUSH_BYTE(cp, entry->key.l4_bytes[2]);
++      HASH_PUSH_BYTE(cp, entry->key.l4_bytes[3]);
++
++      // get hash index
++      total = (u32)((u32)cp - (u32)destp) / (sizeof(u32));
++
++      index = hash_gen_crc16((unsigned char *)destp, total * 4);
++      entry->index = index & ((1 << HASH_BITS) - 1);
++
++      cp = (unsigned char *)destp;
++      cp+=3;
++      HASH_PUSH_BYTE(cp, entry->rule);        // rule
++
++      entry->total_dwords = total;
++}
++
++/*----------------------------------------------------------------------
++* hash_build_toe_keys
++*----------------------------------------------------------------------*/
++int hash_build_toe_keys(u32 *destp, HASH_ENTRY_T *entry)
++{
++      unsigned long   data;
++      unsigned char   *cp;
++      unsigned short  index;
++      int     i;
++      int total;
++      //printk("%s\n", __func__);
++      memset((void*)destp, 0, HASH_MAX_BYTES);
++      cp = (unsigned char*)destp;
++
++      if(entry->key_present.port || entry->key_present.Ethertype) {
++              data = (entry->key.port << 16) + entry->key.Ethertype;
++              HASH_PUSH_DWORD(cp, data);
++      } else
++              HASH_PUSH_DWORD(cp, 0);
++
++      if (entry->key_present.da || entry->key_present.sa) {
++              unsigned char   mac[4];
++              if (entry->key_present.da) {
++                      data = (entry->key.da[0]) + (entry->key.da[1] << 8) +
++                                 (entry->key.da[2] << 16) + (entry->key.da[3] <<24);
++                      HASH_PUSH_DWORD(cp, data);
++              }
++              mac[0] = (entry->key_present.da) ? entry->key.da[4] : 0;
++              mac[1] = (entry->key_present.da) ? entry->key.da[5] : 0;
++              mac[2] = (entry->key_present.sa) ? entry->key.sa[0] : 0;
++              mac[3] = (entry->key_present.sa) ? entry->key.sa[1] : 0;
++              data = mac[0] + (mac[1]<<8) + (mac[2]<<16) + (mac[3]<<24);
++              HASH_PUSH_DWORD(cp, data);
++              if (entry->key_present.sa) {
++                      data = (entry->key.sa[2]) + (entry->key.sa[3] << 8) +
++                                 (entry->key.sa[4] << 16) + (entry->key.sa[5] <<24);
++                      HASH_PUSH_DWORD(cp, data);
++              }
++      }
++
++      if (entry->key_present.ip_protocol) {
++              unsigned char ip_protocol;
++              ip_protocol = entry->key.ip_protocol;
++              data = ip_protocol;
++              HASH_PUSH_DWORD(cp, data);
++      }
++
++      if (entry->key_present.ipv6_flow_label) {
++              unsigned long flow_label;
++              flow_label  = entry->key.ipv6_flow_label;
++              data = flow_label & 0xfffff;
++              HASH_PUSH_DWORD(cp, data);
++      }
++
++      if (entry->key_present.sip)     {
++              {
++                      data = IPIV(entry->key.sip[0], entry->key.sip[1],
++                                      entry->key.sip[2], entry->key.sip[3]);
++                      HASH_PUSH_DWORD(cp, data);
++                      if (entry->key.ipv6) {
++                              for (i=4; i<16; i+=4) {
++                                      data = IPIV(entry->key.sip[i+0], entry->key.sip[i+1],
++                                                      entry->key.sip[i+2], entry->key.sip[i+3]);
++                                      HASH_PUSH_DWORD(cp, data);
++                              }
++                      }
++              }
++      }
++
++      if (entry->key_present.dip)     {
++              {
++                      data = IPIV(entry->key.dip[0], entry->key.dip[1],
++                                              entry->key.dip[2], entry->key.dip[3]);
++                      HASH_PUSH_DWORD(cp, data);
++                      if (entry->key.ipv6) {
++                              for (i=4; i<16; i+=4) {
++                                      data = IPIV(entry->key.dip[i+0], entry->key.dip[i+1],
++                                                              entry->key.dip[i+2], entry->key.dip[i+3]);
++                                      HASH_PUSH_DWORD(cp, data);
++                              }
++                      }
++              }
++      }
++      if (entry->key_present.l4_bytes_0_3)
++      {
++              unsigned char *datap;
++              datap = &entry->key.l4_bytes[0];
++              data =  datap[0] +      (datap[1] << 8) + (datap[2] << 16) + (datap[3] << 24);
++              HASH_PUSH_DWORD(cp, data);
++      }
++      if (entry->key_present.l7_bytes_0_3)
++      {
++              unsigned char *datap;
++              datap = &entry->key.l7_bytes[0];
++              data =  datap[0] +      (datap[1] << 8) + (datap[2] << 16) + (datap[3] << 24);
++              HASH_PUSH_DWORD(cp, data);
++      }
++      if (entry->key_present.l7_bytes_4_7)
++      {
++              unsigned char *datap;
++              datap = &entry->key.l7_bytes[4];
++              data =  datap[0] +      (datap[1] << 8) + (datap[2] << 16) + (datap[3] << 24);
++              HASH_PUSH_DWORD(cp, data);
++      }
++
++      total = (unsigned long)((unsigned long)cp - (unsigned long)destp) / (sizeof(u32));
++      if (total > HASH_MAX_KEY_DWORD) {
++              //printf("Total key words (%d) is too large (> %d)!\n",
++              //              total, HASH_MAX_KEY_DWORD);
++              return -1;
++      }
++      index = hash_gen_crc16((unsigned char*)(destp + 1), (total-1)*4);
++      entry->index = index & ((1 << HASH_BITS)-1);
++
++      cp = (unsigned char*) destp;
++      cp += 3;
++      HASH_PUSH_BYTE(cp, entry->rule);
++      entry->total_dwords = total;
++      return total;
++}
++
++/*----------------------------------------------------------------------
++* hash_add_toe_entry
++*----------------------------------------------------------------------*/
++int hash_add_toe_entry(HASH_ENTRY_T *entry)
++{
++      int     rc;
++      u32     key[HASH_MAX_DWORDS];
++
++      rc = hash_build_toe_keys((u32 *)&key, entry);
++      if (rc < 0)
++              return -1;
++      hash_write_entry(entry, (unsigned char*) &key[0]);
++      //hash_dump_entry(entry->index);
++//    hash_set_valid_flag(entry->index, 1);
++//    printk("Dump hash key!\n");
++//    dump_hash_key(entry);
++      return entry->index;
++}
++
++
++/*----------------------------------------------------------------------
++* hash_write_entry
++*----------------------------------------------------------------------*/
++int hash_write_entry(HASH_ENTRY_T *entry, unsigned char *key)
++{
++      int             i;
++      u32             *srcep, *destp, *destp2;
++
++      srcep = (u32 *)key;
++      destp2 = destp = (u32 *)&hash_tables[entry->index][0];
++
++      for (i=0; i<(entry->total_dwords); i++, srcep++, destp++)
++              *destp = *srcep;
++
++      srcep = (u32 *)&entry->action;
++      *destp++ = *srcep;
++
++      srcep = (u32 *)&entry->param;
++      for (i=0; i<(sizeof(ENTRY_PARAM_T)/sizeof(*destp)); i++, srcep++, destp++)
++              *destp = *srcep;
++
++      memset(destp, 0, (HASH_MAX_DWORDS-entry->total_dwords-HASH_ACTION_DWORDS) * sizeof(u32));
++
++      consistent_sync(destp2, (entry->total_dwords+HASH_ACTION_DWORDS) * 4, PCI_DMA_TODEVICE);
++      return 0;
++}
++
++/*----------------------------------------------------------------------
++* hash_timer_func
++*----------------------------------------------------------------------*/
++static void hash_timer_func(u32 data)
++{
++      int                                     i, j, idx;
++      volatile u32            *own_p, *valid_p;
++      u32                                     own_bits, a_bits;
++      int                                     period = HASH_TIMER_PERIOD;
++
++      valid_p = (volatile u32 *)TOE_V_BIT_BASE;
++      own_p = (volatile u32 *)hash_nat_owner_bits;
++      for (i=0, idx=0; i<(HASH_TOTAL_ENTRIES/32); i++, own_p++, valid_p++, idx+=32)
++      {
++              a_bits = readl(TOE_A_BIT_BASE + (i*4));
++              own_bits = *own_p;
++              if (own_bits)
++              {
++                      for (j=0; own_bits && j<32; j++)
++                      {
++                              if (own_bits & 1)
++                              {
++                                      short *counter_p, *interval_p;
++                                      NAT_HASH_ENTRY_T        *nat_entry;
++                                      GRE_HASH_ENTRY_T        *gre_entry;
++                                      nat_entry = (NAT_HASH_ENTRY_T *)hash_get_entry(idx+j);
++                                      gre_entry = (GRE_HASH_ENTRY_T *)nat_entry;
++                                      if (nat_entry->key.ip_protocol == IPPROTO_GRE)
++                                      {
++                                              counter_p = (short *)&gre_entry->tmo.counter;
++                                              interval_p = (short *)&gre_entry->tmo.interval;
++                                      }
++                                      else
++                                      {
++                                              counter_p = (short *)&nat_entry->tmo.counter;
++                                              interval_p = (short *)&nat_entry->tmo.interval;
++                                      }
++                                      if (a_bits & 1)
++                                      {
++                                              *counter_p = *interval_p;
++                                      }
++                                      else
++                                      {
++                                              *counter_p -= HASH_TIMER_PERIOD;
++                                              if (*counter_p <= 0)
++                                              {
++                                                      *valid_p &= ~(1 << j);          // invalidate it
++                                                      *own_p &= ~(1 << j);            // release ownership for NAT
++                                                      *counter_p = 0;
++                                                      // hash_printf("%lu %s: Clear hash index: %d\n", jiffies/HZ, __func__, i*32+j);
++                                              }
++                                              else if (period > *counter_p)
++                                              {
++                                                      period = *counter_p;
++                                              }
++                                      }
++                              }
++                              a_bits >>= 1;
++                              own_bits >>=1;
++                      }
++              }
++      }
++
++      hash_timer_obj.expires = jiffies + (period * HZ);
++      add_timer((struct timer_list *)data);
++}
++
++/*----------------------------------------------------------------------
++* dm_long
++*----------------------------------------------------------------------*/
++void dm_long(u32 location, int length)
++{
++      u32             *start_p, *curr_p, *end_p;
++      u32             *datap, data;
++      int             i;
++
++      //if (length > 1024)
++      //      length = 1024;
++
++      start_p = (u32 *)location;
++      end_p = (u32 *)location + length;
++      curr_p = (u32 *)((u32)location & 0xfffffff0);
++      datap = (u32 *)location;
++      while (curr_p < end_p)
++      {
++              hash_printf("0x%08x: ",(u32)curr_p & 0xfffffff0);
++              for (i=0; i<4; i++)
++              {
++                      if (curr_p < start_p || curr_p >= end_p)
++               hash_printf("         ");
++                      else
++                      {
++                              data = *datap;
++                              hash_printf("%08X ", data);
++                      }
++                      if (i==1)
++              hash_printf("- ");
++
++                      curr_p++;
++                      datap++;
++              }
++        hash_printf("\n");
++      }
++}
++
++/*----------------------------------------------------------------------
++* hash_dump_entry
++*----------------------------------------------------------------------*/
++void hash_dump_entry(int index)
++{
++      hash_printf("Hash Index %d:\n", index);
++      dm_long((u32)&hash_tables[index][0], HASH_MAX_DWORDS);
++}
++
++
+Index: linux-2.6.23.16/drivers/net/sl351x_nat.c
+===================================================================
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.23.16/drivers/net/sl351x_nat.c   2008-03-15 16:59:39.862397640 +0200
+@@ -0,0 +1,1736 @@
++/****************************************************************************
++* Copyright 2006 StorLink Semiconductors, Inc.  All rights reserved.
++*----------------------------------------------------------------------------
++* Name                        : sl351x_nat.c
++* Description :
++*             Handle Storlink SL351x NAT Functions
++*
++*
++* Packet Flow:
++*
++*            (xmit)+<--- SW NAT -->+(xmit)
++*                  |       ^^      |
++*                  |       ||      |
++*                  |       ||      |
++*   Client <---> GMAC-x  HW-NAT  GMAC-y  <---> Server
++*
++*
++* History
++*
++*     Date            Writer          Description
++*----------------------------------------------------------------------------
++*     03/13/2006      Gary Chen       Create and implement
++*
++*
++****************************************************************************/
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/compiler.h>
++#include <linux/pci.h>
++#include <linux/init.h>
++#include <linux/ioport.h>
++#include <linux/netdevice.h>
++#include <linux/etherdevice.h>
++#include <linux/rtnetlink.h>
++#include <linux/delay.h>
++#include <linux/ethtool.h>
++#include <linux/mii.h>
++#include <linux/completion.h>
++#include <asm/hardware.h>
++#include <asm/io.h>
++#include <asm/irq.h>
++#include <asm/semaphore.h>
++#include <asm/arch/irqs.h>
++#include <asm/arch/it8712.h>
++#include <linux/mtd/kvctl.h>
++#include <linux/skbuff.h>
++#include <linux/if_ether.h>
++#include <linux/if_pppox.h>
++#include <linux/in.h>
++#include <linux/ip.h>
++#include <linux/tcp.h>
++#include <linux/udp.h>
++#include <linux/ppp_defs.h>
++
++#define        MIDWAY
++#define        SL_LEPUS
++
++#include <asm/arch/sl2312.h>
++#include <asm/arch/sl351x_gmac.h>
++#include <asm/arch/sl351x_hash_cfg.h>
++#include <asm/arch/sl351x_nat_cfg.h>
++#ifdef CONFIG_NETFILTER
++#include <linux/netfilter_ipv4/ip_conntrack.h>
++#include <linux/netfilter_ipv4/ip_conntrack_tcp.h>
++#endif
++
++//#define NAT_DEBUG_MSG               1
++#define _NOT_CHECK_SIP_DIP
++//#define     SL351x_NAT_TEST_BY_SMARTBITS            1       // Initialize 32 hash entries and test by SmartBITS
++#define VITESSE_G5SWITCH      1
++
++#ifdef CONFIG_SL351x_NAT
++
++/*----------------------------------------------------------------------
++* Definition
++*----------------------------------------------------------------------*/
++#ifdef CONFIG_SL3516_ASIC
++#define CONFIG_SL351x_NAT_TCP_UDP
++#define CONFIG_SL351x_NAT_GRE
++#define CONFIG_SL351x_TCP_UDP_RULE_ID 0
++#define CONFIG_SL351x_GRE_RULE_ID             1
++#else
++#define CONFIG_SL351x_NAT_TCP_UDP
++//#define CONFIG_SL351x_NAT_GRE
++#define CONFIG_SL351x_TCP_UDP_RULE_ID 0
++#define CONFIG_SL351x_GRE_RULE_ID             0
++#endif
++
++#define       nat_printf                                      printk
++#define NAT_FTP_CTRL_PORT                     (21)    // TCP
++#define NAT_H323_PORT                         (1720)  // TCP
++#define NAT_T120_PORT                         (1503)  // TCP
++#define NAT_PPTP_PORT                         (1723)  // TCP
++#define NAT_TFTP_PORT                                 (69)    // UDP
++#define NAT_DNS_PORT                          (53)    // UDP
++#define NAT_NTP_PORT                          (123)   // UDP
++#define NAT_RAS_PORT                          (1719)  // UDP
++#define NAT_BOOTP67_PORT                      (67)    // UDP
++#define NAT_BOOTP68_PORT                      (68)    // UDP
++
++#define NAT_TCP_PORT_MAX                      64
++#define NAT_UDP_PORT_MAX                      64
++
++#define GRE_PROTOCOL                          (0x880b)
++#define GRE_PROTOCOL_SWAP                     __constant_htons(0x880b)
++
++#ifdef VITESSE_G5SWITCH
++extern int Giga_switch;
++#endif
++
++typedef struct
++{
++      u16             flags_ver;
++      u16             protocol;
++      u16             payload_length;
++      u16             call_id;
++      u32             seq;
++      u32             ack;
++} GRE_PKTHDR_T;
++
++/*----------------------------------------------------------------------
++* NAT Configuration
++*
++* Note: Any change for network setting, the NAT configuration should
++*       be changed also.
++*     cfg->lan_port   0 if GMAC-0, 1: if GMAC-1
++*     cfg->wan_port   0 if GMAC-0, 1: if GMAC-1
++*     cfg->lan_ipaddr, cfg->lan_gateway, cfg->lan_netmask
++*     cfg->wan_ipaddr, cfg->wan_gateway, cfg->wan_netmask
++*
++*----------------------------------------------------------------------*/
++NAT_CFG_T             nat_cfg;
++static int            nat_initialized;
++u32                   nat_collision;
++
++#ifdef CONFIG_SL351x_NAT_TCP_UDP
++static u16            fixed_tcp_port_list[]={NAT_FTP_CTRL_PORT,
++                                                                              NAT_H323_PORT,
++                                                                              // NAT_T120_PORT,
++                                                                              NAT_PPTP_PORT,
++                                                                              0};
++static u16            fixed_udp_port_list[]={NAT_DNS_PORT,
++                                                                              NAT_NTP_PORT,
++                                                                              NAT_TFTP_PORT,
++                                                                              NAT_RAS_PORT,
++                                                                              NAT_BOOTP67_PORT,
++                                                                              NAT_BOOTP68_PORT,
++                                                                              0};
++#endif
++
++// #define _HAVE_DYNAMIC_PORT_LIST
++#ifdef _HAVE_DYNAMIC_PORT_LIST
++static u16            dynamic_tcp_port_list[NAT_TCP_PORT_MAX+1];
++static u16            dynamic_udp_port_list[NAT_UDP_PORT_MAX+1]};
++#endif
++
++/*----------------------------------------------------------------------
++* Functions
++*----------------------------------------------------------------------*/
++int sl351x_nat_tcp_udp_output(struct sk_buff *skb, int port);
++int sl351x_nat_udp_output(struct sk_buff *skb, int port);
++int sl351x_nat_gre_output(struct sk_buff *skb, int port);
++
++extern int mac_set_rule_reg(int mac, int rule, int enabled, u32 reg0, u32 reg1, u32 reg2);
++extern void hash_dump_entry(int index);
++extern void mac_get_hw_tx_weight(struct net_device *dev, char *weight);
++extern void mac_set_hw_tx_weight(struct net_device *dev, char *weight);
++
++#ifdef SL351x_NAT_TEST_BY_SMARTBITS
++static void nat_init_test_entry(void);
++#endif
++/*----------------------------------------------------------------------
++* sl351x_nat_init
++*     initialize a NAT matching rule
++*     Called by SL351x Driver
++*             key             : port, protocol, Sip, Dip, Sport, Dport
++*             Action  : Srce Q: HW Free Queue,
++*                               Dest Q: HW TxQ
++*                               Change DA
++*                               Change SA
++*                 Change Sip or Dip
++*                       Change Sport or Dport
++*----------------------------------------------------------------------*/
++void sl351x_nat_init(void)
++{
++      int                                     rc;
++      GMAC_MRxCR0_T           mrxcr0;
++      GMAC_MRxCR1_T           mrxcr1;
++      GMAC_MRxCR2_T           mrxcr2;
++      NAT_CFG_T                       *cfg;
++
++      if (nat_initialized)
++              return;
++
++      nat_initialized = 1;
++
++      if ((sizeof(NAT_HASH_ENTRY_T) > HASH_MAX_BYTES) ||
++              (sizeof(GRE_HASH_ENTRY_T) > HASH_MAX_BYTES))
++      {
++              nat_printf("NAT_HASH_ENTRY_T structure Size is too larger!\n");
++              while(1);
++      }
++
++      cfg = (NAT_CFG_T *)&nat_cfg;
++      memset((void *)cfg, 0, sizeof(NAT_CFG_T));
++#ifdef _HAVE_DYNAMIC_PORT_LIST
++      memset((void *)dynamic_tcp_port_list, 0, sizeof(dynamic_tcp_port_list));
++      memset((void *)dynamic_udp_port_list, 0, sizeof(dynamic_udp_port_list));
++#endif
++
++#ifdef VITESSE_G5SWITCH
++      if(Giga_switch)
++      {
++              cfg->enabled                    = 1;
++              cfg->tcp_udp_rule_id    = CONFIG_SL351x_TCP_UDP_RULE_ID;
++              cfg->gre_rule_id                = CONFIG_SL351x_GRE_RULE_ID;
++              cfg->lan_port                   = 1;
++              cfg->wan_port                   = 0;
++              cfg->default_hw_txq     = 3;
++              cfg->tcp_tmo_interval   = 60;
++              cfg->udp_tmo_interval   = 180;
++              cfg->gre_tmo_interval   = 60;
++      }
++      else
++      {
++              cfg->enabled                    = 1;
++              cfg->tcp_udp_rule_id    = CONFIG_SL351x_TCP_UDP_RULE_ID;
++              cfg->gre_rule_id                = CONFIG_SL351x_GRE_RULE_ID;
++              cfg->lan_port                   = 0;
++              cfg->wan_port                   = 1;
++              cfg->default_hw_txq     = 3;
++              cfg->tcp_tmo_interval   = 60;
++              cfg->udp_tmo_interval   = 180;
++              cfg->gre_tmo_interval   = 60;
++
++      }
++#endif
++
++#if 1 //      debug purpose
++      cfg->ipcfg[0].total                             = 1;
++      cfg->ipcfg[0].entry[0].ipaddr   = IPIV(192,168,2,92);
++      cfg->ipcfg[0].entry[0].netmask  = IPIV(255,255,255,0);
++      cfg->ipcfg[1].total                             = 1;
++      cfg->ipcfg[1].entry[0].ipaddr   = IPIV(192,168,1,200);
++      cfg->ipcfg[1].entry[0].netmask  = IPIV(255,255,255,0);
++#endif
++
++#if 1
++      cfg->xport.total = 0;
++#else
++      cfg->xport.total = 4;
++
++      // H.323/H.225 Call setup
++      cfg->xport.entry[0].protocol = IPPROTO_TCP;
++      cfg->xport.entry[0].sport_start = 0;
++      cfg->xport.entry[0].sport_end = 0;
++      cfg->xport.entry[0].dport_start = 1720;
++      cfg->xport.entry[0].dport_end = 1720;
++      cfg->xport.entry[1].protocol = IPPROTO_TCP;
++      cfg->xport.entry[1].sport_start = 1720;
++      cfg->xport.entry[1].sport_end = 1720;
++      cfg->xport.entry[1].dport_start = 0;
++      cfg->xport.entry[1].dport_end = 0;
++
++      // RAS Setup
++      cfg->xport.entry[2].protocol = IPPROTO_UDP;
++      cfg->xport.entry[2].sport_start = 0;
++      cfg->xport.entry[2].sport_end = 0;
++      cfg->xport.entry[2].dport_start = 1719;
++      cfg->xport.entry[2].dport_end = 1719;
++      cfg->xport.entry[3].protocol = IPPROTO_UDP;
++      cfg->xport.entry[3].sport_start = 1719;
++      cfg->xport.entry[3].sport_end = 1719;
++      cfg->xport.entry[3].dport_start = 0;
++      cfg->xport.entry[3].dport_end = 0;
++#endif
++
++#ifdef CONFIG_SL351x_NAT_TCP_UDP
++      mrxcr0.bits32 = 0;
++      mrxcr1.bits32 = 0;
++      mrxcr2.bits32 = 0;
++      mrxcr0.bits.port = 1;
++      mrxcr0.bits.l3 = 1;
++      mrxcr0.bits.l4 = 1;
++      mrxcr1.bits.sip = 1;
++      mrxcr1.bits.dip = 1;
++      mrxcr1.bits.l4_byte0_15 = 0x0f; // Byte 0-3
++      mrxcr0.bits.sprx = 3;
++
++      rc = mac_set_rule_reg(cfg->lan_port, cfg->tcp_udp_rule_id, 1, mrxcr0.bits32, mrxcr1.bits32, mrxcr2.bits32);
++      if (rc < 0)
++      {
++              nat_printf("NAT Failed to set MAC-%d Rule %d!\n", cfg->lan_port, cfg->tcp_udp_rule_id);
++      }
++
++      if (cfg->lan_port != cfg->wan_port)
++      {
++              rc = mac_set_rule_reg(cfg->wan_port, cfg->tcp_udp_rule_id, 1, mrxcr0.bits32, mrxcr1.bits32, mrxcr2.bits32);
++              if (rc < 0)
++              {
++                      nat_printf("NAT Failed to set MAC-%d Rule %d!\n", cfg->wan_port, cfg->tcp_udp_rule_id);
++              }
++      }
++#endif
++
++#ifdef CONFIG_SL351x_NAT_GRE
++      mrxcr0.bits32 = 0;
++      mrxcr1.bits32 = 0;
++      mrxcr2.bits32 = 0;
++      mrxcr0.bits.port = 1;
++      mrxcr0.bits.l3 = 1;
++      mrxcr0.bits.l4 = 1;
++      mrxcr1.bits.sip = 1;
++      mrxcr1.bits.dip = 1;
++      mrxcr1.bits.l4_byte0_15 = 0xcc; // Byte 2, 3, 6, 7
++      mrxcr0.bits.sprx = 4;                   // see GMAC driver about SPR
++
++      rc = mac_set_rule_reg(cfg->lan_port, cfg->gre_rule_id, 1, mrxcr0.bits32, mrxcr1.bits32, mrxcr2.bits32);
++      if (rc < 0)
++      {
++              nat_printf("NAT Failed to set MAC-%d Rule %d!\n", cfg->lan_port, cfg->gre_rule_id);
++      }
++
++      if (cfg->lan_port != cfg->wan_port)
++      {
++              rc = mac_set_rule_reg(cfg->wan_port, cfg->gre_rule_id, 1, mrxcr0.bits32, mrxcr1.bits32, mrxcr2.bits32);
++              if (rc < 0)
++              {
++                      nat_printf("NAT Failed to set MAC-%d Rule %d!\n", cfg->wan_port, cfg->gre_rule_id);
++              }
++      }
++#endif
++
++#ifdef SL351x_NAT_TEST_BY_SMARTBITS
++      nat_init_test_entry();
++#endif
++}
++
++/*----------------------------------------------------------------------
++* nat_build_keys
++*     Note: To call this routine, the key->rule_id MUST be zero
++*----------------------------------------------------------------------*/
++static inline int nat_build_keys(NAT_KEY_T *key)
++{
++      return hash_gen_crc16((unsigned char *)key, NAT_KEY_SIZE) & HASH_BITS_MASK;
++}
++
++/*----------------------------------------------------------------------
++* gre_build_keys
++*     Note: To call this routine, the key->rule_id MUST be zero
++*----------------------------------------------------------------------*/
++static inline int gre_build_keys(GRE_KEY_T *key)
++{
++      return hash_gen_crc16((unsigned char *)key, GRE_KEY_SIZE) & HASH_BITS_MASK;
++}
++
++/*----------------------------------------------------------------------
++* nat_write_hash_entry
++*----------------------------------------------------------------------*/
++static inline int nat_write_hash_entry(int index, void *hash_entry)
++{
++      int             i;
++      u32             *srcep, *destp, *destp2;
++
++      srcep = (u32 *)hash_entry;
++      destp = destp2 = (u32 *)&hash_tables[index][0];
++
++      for (i=0; i<(NAT_HASH_ENTRY_SIZE/sizeof(u32)); i++)
++              *destp++ = *srcep++;
++
++      consistent_sync(destp2, NAT_HASH_ENTRY_SIZE, PCI_DMA_TODEVICE);
++      return 0;
++}
++
++/*----------------------------------------------------------------------
++* gre_write_hash_entry
++*----------------------------------------------------------------------*/
++static inline int gre_write_hash_entry(int index, void *hash_entry)
++{
++      int             i;
++      u32             *srcep, *destp, *destp2;
++
++      srcep = (u32 *)hash_entry;
++      destp = destp2 = (u32 *)&hash_tables[index][0];
++
++      for (i=0; i<(GRE_HASH_ENTRY_SIZE/sizeof(u32)); i++)
++              *destp++ = *srcep++;
++
++      consistent_sync(destp2, GRE_HASH_ENTRY_SIZE, PCI_DMA_TODEVICE);
++      return 0;
++}
++
++/*----------------------------------------------------------------------
++* sl351x_nat_find_ipcfg
++*     return NULL if not found
++*----------------------------------------------------------------------*/
++static NAT_IP_ENTRY_T *sl351x_nat_find_ipcfg(u32 ipaddr, int port)
++{
++      int                             i;
++      NAT_IP_ENTRY_T  *ipcfg;
++
++      ipcfg = (NAT_IP_ENTRY_T *)&nat_cfg.ipcfg[port].entry[0];
++      for (i=0; i<nat_cfg.ipcfg[port].total; i++, ipcfg++)
++      {
++              if (ipaddr == ipcfg->ipaddr)
++              {
++                      return ipcfg;
++              }
++      }
++      return NULL;
++}
++
++/*----------------------------------------------------------------------
++* sl351x_nat_assign_qid
++*----------------------------------------------------------------------*/
++static int sl351x_nat_assign_qid(u8 proto, u32 sip, u32 dip, u16 sport, u16 dport)
++{
++      int                             i, total, qid;
++      NAT_WRULE_ENTRY_T       *entry;
++
++      for (qid = 0; qid<CONFIG_NAT_TXQ_NUM; qid++)
++      {
++              if (qid == nat_cfg.default_hw_txq)
++                      continue;
++
++              entry = (NAT_WRULE_ENTRY_T *)&nat_cfg.wrule[qid].entry[0];
++              total = nat_cfg.wrule[qid].total;
++              for (i=0; i<total; i++, entry++)
++              {
++                      if (!entry->protocol || entry->protocol==proto)
++                      {
++                              //if (!entry->sip_start && !entry->dip_start && !entry->sport_start && !entry->dport_start)
++                              //      continue; // UI take care
++                              if (entry->sip_start && !((sip >= entry->sip_start) &&
++                                                                         (sip <= entry->sip_end)))
++                                      continue;
++                              if (entry->dip_start && !((dip >= entry->dip_start) &&
++                                                                         (dip <= entry->dip_end)))
++                                      continue;
++                              if (entry->sport_start && !((sport >= entry->sport_start) &&
++                                                                         (sport <= entry->sport_end)))
++                                      continue;
++                              if (entry->dport_start && !((dport >= entry->dport_start)
++                                                                     && (dport <= entry->dport_end)))
++                                      continue;
++                              return qid;
++                      }
++              }
++      }
++      return nat_cfg.default_hw_txq;
++}
++
++/*----------------------------------------------------------------------
++* sl351x_nat_input
++*     Handle NAT input frames
++*     Called by SL351x Driver - Handle Default Rx Queue
++*     Notes: The caller must make sure that the l3off & l4offset should not be zero.
++*     SL351x NAT Frames should meet the following conditions:
++*     1. TCP or UDP frame
++*     2. Cannot be special ALGs ports which TCP/UDP data is updated
++*     3. LAN-IN Frames:
++*             Source IP is in the LAN subnet and Destination is not in the LAN subnet
++*     4. WAN-IN Frames
++*             Destination IP is in the WAN port IP
++*
++*     Example Ports
++*     1. TCP/UDP data is updated
++*             (a) FTP Control Packet
++*             (b) VoIP Packets
++*             (c) etc. (add in future)
++*     2. UDP Low packet rate, not worth
++*             (b) TFTP Destination Port is 69
++*             (b) DNS  53
++*             (c) NTP  123
++*             (d) etc. (add in future)
++*----------------------------------------------------------------------*/
++void sl351x_nat_input(struct sk_buff *skb, int port, void *l3off, void *l4off)
++{
++      int                             i, found;
++      u32                                     sip, dip;
++      u16                                     sport, dport;
++      struct ethhdr           *ether_hdr;
++      struct iphdr            *ip_hdr;
++      struct tcphdr           *tcp_hdr;
++      struct pppoe_hdr        *pppoe_hdr;
++      NAT_CB_T                        *nat_cb;
++      u8                                      proto, pppoe_frame=0;
++      NAT_CFG_T                       *cfg;
++      u16                                     ppp_proto;
++      NAT_IP_ENTRY_T          *ipcfg;
++      NAT_XPORT_ENTRY_T       *xentry;
++      GRE_PKTHDR_T            *gre_hdr;
++#ifdef CONFIG_SL351x_NAT_TCP_UDP
++      u16                             *port_ptr;
++#endif
++
++      cfg = (NAT_CFG_T *)&nat_cfg;
++      if (!cfg->enabled || !cfg->ipcfg[port].total)
++              return;
++
++      ip_hdr = (struct iphdr *)&(skb->data[(u32)l3off]);
++      proto = ip_hdr->protocol;
++
++      tcp_hdr = (struct tcphdr *)&(skb->data[(u32)l4off]);
++      gre_hdr = (GRE_PKTHDR_T *)tcp_hdr;
++      sport = ntohs(tcp_hdr->source);
++      dport = ntohs(tcp_hdr->dest);
++
++      sip = ntohl(ip_hdr->saddr);
++      dip = ntohl(ip_hdr->daddr);
++
++      if (dip == IPIV(255,255,255,255))
++              return;
++
++      if (port == cfg->lan_port)
++      {
++              ipcfg = (NAT_IP_ENTRY_T *)&cfg->ipcfg[port].entry[0];
++              for (i=0, found=0; i<cfg->ipcfg[port].total; i++, ipcfg++)
++              {
++                      u32 subnet = ipcfg->ipaddr & ipcfg->netmask;
++                      if (((sip & ipcfg->netmask) == subnet) &&
++                              ((dip & ipcfg->netmask) != subnet))
++                      {
++                              found = 1;
++                              break;
++                      }
++              }
++              if (!found)
++                      return;
++      }
++      else
++      {
++#ifndef _NOT_CHECK_SIP_DIP    // enable it if know and get the wan ip address
++              if (!sl351x_nat_find_ipcfg(dip, port))
++              {
++                      printk("WAN->LAN Incorrect Dip %d.%d.%d.%d\n", HIPQUAD(dip));
++                      return;
++              }
++#endif
++              ether_hdr = (struct ethhdr *)skb->data;
++              pppoe_hdr = (struct pppoe_hdr *)(ether_hdr + 1);
++              ppp_proto = *(u16 *)&pppoe_hdr->tag[0];
++              if (ether_hdr->h_proto == __constant_htons(ETH_P_PPP_SES)       // 0x8864
++                      && ppp_proto == __constant_htons(PPP_IP) )                              // 0x21
++              {
++                      pppoe_frame = 1;
++              }
++      }
++
++#ifdef CONFIG_SL351x_NAT_TCP_UDP
++      if (proto == IPPROTO_TCP)
++      {
++#ifdef        NAT_DEBUG_MSG
++              nat_printf("From   GMAC-%d: 0x%-4X TCP %d.%d.%d.%d [%d] --> %d.%d.%d.%d [%d]",
++                              port, ntohs(ip_hdr->id),
++                              NIPQUAD(ip_hdr->saddr), sport,
++                              NIPQUAD(ip_hdr->daddr), dport);
++              if (tcp_flag_word(tcp_hdr) & TCP_FLAG_SYN) nat_printf(" SYN");
++              if (tcp_flag_word(tcp_hdr) & TCP_FLAG_FIN) nat_printf(" FIN");
++              if (tcp_flag_word(tcp_hdr) & TCP_FLAG_RST) nat_printf(" RST");
++              if (tcp_flag_word(tcp_hdr) & TCP_FLAG_ACK) nat_printf(" ACK");
++              nat_printf("\n");
++#endif
++              // if (tcp_flag_word(tcp_hdr) & (TCP_FLAG_SYN | TCP_FLAG_FIN | TCP_FLAG_RST))
++              if (tcp_flag_word(tcp_hdr) & (TCP_FLAG_SYN))
++              {
++                      return;
++              }
++              port_ptr = fixed_tcp_port_list;
++              for (i=0; *port_ptr; i++, port_ptr++)
++              {
++                      if (sport == *port_ptr || dport == *port_ptr)
++                              return;
++              }
++#ifdef _HAVE_DYNAMIC_PORT_LIST
++              port_ptr = dynamic_tcp_port_list;
++              for (i=0; *port_ptr; i++, port_ptr++)
++              {
++                      if (sport == *port_ptr || dport == *port_ptr)
++                              return;
++              }
++#endif
++      }
++      else if (proto == IPPROTO_UDP)
++      {
++#ifdef        NAT_DEBUG_MSG
++              nat_printf("From   GMAC-%d: 0x%-4X UDP %d.%d.%d.%d [%d] --> %d.%d.%d.%d [%d]",
++                              port, ntohs(ip_hdr->id),
++                              NIPQUAD(ip_hdr->saddr), sport,
++                              NIPQUAD(ip_hdr->daddr), dport);
++              nat_printf("\n");
++#endif
++              port_ptr = fixed_udp_port_list;
++              for (i=0; *port_ptr; i++, port_ptr++)
++              {
++                      if (sport == *port_ptr || dport == *port_ptr)
++                              return;
++              }
++#ifdef _HAVE_DYNAMIC_PORT_LIST
++              port_ptr = dynamic_udp_port_list;
++              for (i=0; *port_ptr; i++, port_ptr++)
++              {
++                      if (sport == *port_ptr || dport == *port_ptr)
++                              return;
++              }
++#endif
++      }
++      else
++#endif        // CONFIG_SL351x_NAT_TCP_UDP
++#ifdef CONFIG_SL351x_NAT_GRE
++      if (proto == IPPROTO_GRE)
++      {
++              if (gre_hdr->protocol != GRE_PROTOCOL_SWAP)
++                      return;
++#ifdef        NAT_DEBUG_MSG
++              nat_printf("From   GMAC-%d: 0x%-4X GRE %d.%d.%d.%d [%d] --> %d.%d.%d.%d",
++                              port, ntohs(ip_hdr->id),
++                              NIPQUAD(ip_hdr->saddr), ntohs(gre_hdr->call_id),
++                              NIPQUAD(ip_hdr->daddr));
++              nat_printf("\n");
++#endif
++      }
++      else
++#endif
++              return;
++
++
++      // check xport list
++      xentry = (NAT_XPORT_ENTRY_T *)&cfg->xport.entry[0];
++      for (i=0; i<cfg->xport.total; i++, xentry++)
++      {
++              if (!xentry->protocol || xentry->protocol == proto)
++              {
++                      //if (!xentry->sport_start && !xentry->dport_start) // UI take care
++                      //      continue;
++                      if (xentry->sport_start && !((sport >= xentry->sport_start) &&
++                                                                         (sport <= xentry->sport_end)))
++                              continue;
++                      if (xentry->dport_start && !((dport >= xentry->dport_start)
++                                                                     && (dport <= xentry->dport_end)))
++                              continue;
++                      return;
++              }
++      }
++
++      nat_cb = NAT_SKB_CB(skb);
++      if (((u32)nat_cb & 3))
++      {
++              nat_printf("%s ERROR! nat_cb is not alignment!!!!!!\n", __func__);
++              return;
++      }
++      nat_cb->tag = NAT_CB_TAG;
++      memcpy(nat_cb->sa, skb->data+6, 6);
++      nat_cb->sip = ip_hdr->saddr;
++      nat_cb->dip = ip_hdr->daddr;
++      if (proto == IPPROTO_GRE)
++      {
++              nat_cb->sport = gre_hdr->protocol;
++              nat_cb->dport = gre_hdr->call_id;
++      }
++      else
++      {
++              nat_cb->sport = tcp_hdr->source;
++              nat_cb->dport = tcp_hdr->dest;
++      }
++      nat_cb->pppoe_frame = pppoe_frame;
++}
++
++/*----------------------------------------------------------------------
++* sl351x_nat_output
++*     Handle NAT output frames
++*     Called by SL351x Driver - Transmit
++*
++*     1. If not SL351x NAT frames, return FALSE
++*     2. LAN-to-WAN frames
++*             (1) Sip must be WAN IP
++*     3. If TCP SY/RST/FIN frame, return
++*     4. Build the hash key and get the hash index
++*     5. If V-Bit is ON, return.
++*     6. Write hash entry and validate it
++*
++*----------------------------------------------------------------------*/
++int sl351x_nat_output(struct sk_buff *skb, int port)
++{
++      struct iphdr            *ip_hdr;
++      u8                                      proto;
++      NAT_CB_T                        *nat_cb;
++
++      nat_cb = NAT_SKB_CB(skb);
++      if (nat_cb->tag != NAT_CB_TAG)
++              return 0;
++
++      if (((u32)nat_cb & 3))
++      {
++              nat_printf("%s ERROR! nat_cb is not alignment!!!!!!\n", __func__);
++              return 0;
++      }
++      ip_hdr = (struct iphdr *)skb->h.ipiph;
++      proto = ip_hdr->protocol;
++
++      switch (proto)
++      {
++              case IPPROTO_TCP:
++              case IPPROTO_UDP:
++                      return sl351x_nat_tcp_udp_output(skb, port);
++              case IPPROTO_GRE:
++                      return sl351x_nat_gre_output(skb, port);
++      }
++      return 0;
++}
++
++/*----------------------------------------------------------------------
++* sl351x_nat_tcp_udp_output
++*     Handle NAT TCP/UDP output frames
++*----------------------------------------------------------------------*/
++int sl351x_nat_tcp_udp_output(struct sk_buff *skb, int port)
++{
++      u32                                     sip, dip;
++      struct ethhdr           *ether_hdr;
++      struct iphdr            *ip_hdr;
++      struct tcphdr           *tcp_hdr;
++      struct pppoe_hdr        *pppoe_hdr;
++      NAT_CB_T                        *nat_cb;
++      NAT_CFG_T                       *cfg;
++      u8                                      proto;
++      u16                                     sport, dport, ppp_proto;
++      u32                                     hash_data[HASH_MAX_DWORDS];
++      NAT_HASH_ENTRY_T        *hash_entry;
++      int                                     hash_index;
++      struct ip_conntrack *nat_ip_conntrack;
++      enum ip_conntrack_info ctinfo;
++
++      nat_cb = NAT_SKB_CB(skb);
++      cfg = (NAT_CFG_T *)&nat_cfg;
++
++      ether_hdr = (struct ethhdr *)skb->data;
++      ip_hdr = (struct iphdr *)skb->h.ipiph;
++      tcp_hdr = (struct tcphdr *)((u32)ip_hdr + (ip_hdr->ihl<<2));
++      sip = ntohl(ip_hdr->saddr);
++      dip = ntohl(ip_hdr->daddr);
++      proto = ip_hdr->protocol;
++      sport = ntohs(tcp_hdr->source);
++      dport = ntohs(tcp_hdr->dest);
++
++#ifdef        NAT_DEBUG_MSG
++      {
++              nat_printf("To   GMAC-%d: 0x%-4X [%d] %d.%d.%d.%d [%d] --> %d.%d.%d.%d [%d]",
++                              port, ntohs(ip_hdr->id), proto,
++                              NIPQUAD(ip_hdr->saddr), sport,
++                              NIPQUAD(ip_hdr->daddr), dport);
++              if (proto == IPPROTO_TCP)
++              {
++                      if (tcp_flag_word(tcp_hdr) & TCP_FLAG_SYN) nat_printf(" SYN");
++                      if (tcp_flag_word(tcp_hdr) & TCP_FLAG_FIN) nat_printf(" FIN");
++                      if (tcp_flag_word(tcp_hdr) & TCP_FLAG_RST) nat_printf(" RST");
++                      if (tcp_flag_word(tcp_hdr) & TCP_FLAG_ACK) nat_printf(" ACK");
++              }
++              nat_printf("\n");
++      }
++#endif
++      nat_ip_conntrack = ip_conntrack_get(skb, &ctinfo);
++      if (!nat_ip_conntrack)
++      {
++              nat_printf("IP conntrack info is not found!\n");
++              return 0;
++      }
++      // nat_printf("nat_ip_conntrack = 0x%x, status=0x%lx, ctinfo=%d\n", (u32)nat_ip_conntrack, nat_ip_conntrack->status, ctinfo);
++      // if (nat_ip_conntrack->master || nat_ip_conntrack->helper)
++      if (nat_ip_conntrack->helper)
++      {
++              nat_printf("Sport=%d Dport=%d master=0x%x, helper=0x%x\n", sport, dport, (u32)nat_ip_conntrack->master, (u32)nat_ip_conntrack->helper);
++              return 0;
++      }
++
++      //if (proto == IPPROTO_TCP && !(nat_ip_conntrack->status & IPS_ASSURED))
++      //      return 0;
++
++#ifdef        NAT_DEBUG_MSG
++      nat_printf("nat_ip_conntrack=0x%x, nat_cb->state=%d\n", (u32)nat_ip_conntrack, nat_cb->state);
++      nat_printf("lan2wan_hash_index=%d,  wan2lan_hash_index=%d\n", nat_ip_conntrack->lan2wan_hash_index, nat_ip_conntrack->wan2lan_hash_index);
++      nat_printf("lan2wan_collision=%d, wan2lan_collision=%d\n", nat_ip_conntrack->lan2wan_collision, nat_ip_conntrack->wan2lan_collision);
++#endif
++      if (proto == IPPROTO_TCP)
++      {
++              if (nat_cb->state >= TCP_CONNTRACK_FIN_WAIT && nat_cb->state <= TCP_CONNTRACK_CLOSE)
++              {
++                      if      (nat_ip_conntrack->lan2wan_hash_index)
++                      {
++#ifdef        NAT_DEBUG_MSG
++                              nat_printf("Invalidate LAN->WAN hash entry %d\n", nat_ip_conntrack->lan2wan_hash_index - 1);
++#endif
++                              hash_nat_disable_owner(nat_ip_conntrack->lan2wan_hash_index - 1);
++                              hash_invalidate_entry(nat_ip_conntrack->lan2wan_hash_index - 1);
++                              nat_ip_conntrack->lan2wan_hash_index = 0;
++                      }
++                      if      (nat_ip_conntrack->wan2lan_hash_index)
++                      {
++#ifdef        NAT_DEBUG_MSG
++                              nat_printf("Invalidate WAN->LAN hash entry %d\n", nat_ip_conntrack->wan2lan_hash_index - 1);
++#endif
++                              hash_nat_disable_owner(nat_ip_conntrack->wan2lan_hash_index - 1);
++                              hash_invalidate_entry(nat_ip_conntrack->wan2lan_hash_index - 1);
++                              nat_ip_conntrack->wan2lan_hash_index = 0;
++                      }
++                      return 0;
++
++              }
++              else if (nat_cb->state != TCP_CONNTRACK_ESTABLISHED)
++              {
++                      return 0;
++              }
++      }
++      if (proto == IPPROTO_TCP && (tcp_flag_word(tcp_hdr) & (TCP_FLAG_SYN | TCP_FLAG_FIN | TCP_FLAG_RST)))
++      // if (proto == IPPROTO_TCP &&  (tcp_flag_word(tcp_hdr) & (TCP_FLAG_SYN)))
++              return 0;
++
++      hash_entry = (NAT_HASH_ENTRY_T *)&hash_data;
++      if (port == cfg->wan_port)      // LAN-to-WAN
++      {
++              if (nat_ip_conntrack->lan2wan_hash_index || nat_ip_conntrack->lan2wan_collision)
++                      return 0;
++#ifndef _NOT_CHECK_SIP_DIP    // enable it if know and get the wan ip address
++              if (!sl351x_nat_find_ipcfg(sip, port))
++              {
++                      printk("LAN->WAN Incorrect Sip %d.%d.%d.%d\n", HIPQUAD(sip));
++                      return 0;
++              }
++#endif
++              // Note: unused fields (including rule_id) MUST be zero
++              hash_entry->key.Ethertype       = 0;
++              hash_entry->key.port_id         = cfg->lan_port;
++              hash_entry->key.rule_id         = 0;
++              hash_entry->key.ip_protocol = proto;
++              hash_entry->key.reserved1       = 0;
++              hash_entry->key.reserved2       = 0;
++              hash_entry->key.sip             = ntohl(nat_cb->sip);
++              hash_entry->key.dip             = ntohl(nat_cb->dip);
++              hash_entry->key.sport           = nat_cb->sport;
++              hash_entry->key.dport           = nat_cb->dport;
++
++              hash_index = nat_build_keys(&hash_entry->key);
++
++#ifdef NAT_DEBUG_LAN_HASH_TIMEOUT
++              if (hash_get_nat_owner_flag(hash_index))
++                      return 0;
++#endif
++              if (hash_get_valid_flag(hash_index))
++              {
++                      nat_ip_conntrack->lan2wan_collision = 1;
++                      nat_collision++;
++#if 0
++                      if (proto == IPPROTO_TCP && (tcp_flag_word(tcp_hdr) & (TCP_FLAG_FIN | TCP_FLAG_RST)))
++                      {
++                              if (memcmp((void *)&hash_entry->key, hash_get_entry(hash_index), sizeof(NAT_KEY_T)) == 0)
++                              {
++                                      hash_nat_disable_owner(hash_index);
++                                      hash_invalidate_entry(hash_index); // Must last one, else HW Tx fast SW
++                                      // nat_printf("Invalidate nat hash entry %d\n", hash_index);
++                              }
++                      }
++#endif
++                      return 0;
++              }
++
++              // write hash entry
++              hash_entry->key.rule_id = cfg->tcp_udp_rule_id;
++              memcpy(hash_entry->param.da, skb->data, 6);
++              memcpy(hash_entry->param.sa, skb->data+6, 6);
++              hash_entry->param.Sip = sip;
++              hash_entry->param.Dip = dip;
++              hash_entry->param.Sport = sport;
++              hash_entry->param.Dport = dport;
++              hash_entry->param.vlan = 0;
++              hash_entry->param.sw_id = 0;
++              hash_entry->param.mtu = 0;
++              // check PPPoE
++              pppoe_hdr = (struct pppoe_hdr *)(ether_hdr + 1);
++              ppp_proto = *(u16 *)&pppoe_hdr->tag[0];
++              if (ether_hdr->h_proto == __constant_htons(ETH_P_PPP_SES)       // 0x8864
++                      && ppp_proto == __constant_htons(PPP_IP) )                              // 0x21
++              {
++                      hash_entry->action.dword = NAT_PPPOE_LAN2WAN_ACTIONS;
++                      hash_entry->param.pppoe = htons(pppoe_hdr->sid);
++              }
++              else
++              {
++                      hash_entry->action.dword = NAT_LAN2WAN_ACTIONS;
++                      hash_entry->param.pppoe = 0;
++              }
++              hash_entry->action.bits.dest_qid = sl351x_nat_assign_qid(proto, sip, dip, sport, dport);
++              hash_entry->action.bits.dest_qid +=     (cfg->wan_port==0) ? TOE_GMAC0_HW_TXQ0_QID : TOE_GMAC1_HW_TXQ0_QID;
++              hash_entry->tmo.counter = hash_entry->tmo.interval =
++                                              (proto == IPPROTO_TCP) ? cfg->tcp_tmo_interval : cfg->udp_tmo_interval;
++              nat_write_hash_entry(hash_index, hash_entry);
++              // nat_printf("%lu Validate a LAN hash entry %d\n", jiffies/HZ, hash_index);
++              // hash_dump_entry(hash_index);
++              hash_nat_enable_owner(hash_index);
++              hash_validate_entry(hash_index); // Must last one, else HW Tx fast than SW
++              nat_ip_conntrack->lan2wan_hash_index = hash_index + 1;
++              nat_ip_conntrack->hw_nat |= 1;
++              return 0;
++      }
++      else // WAN-to-LAN
++      {
++              if (nat_ip_conntrack->wan2lan_hash_index || nat_ip_conntrack->wan2lan_collision)
++                      return 0;
++
++              // Note: unused fields (including rule_id) MUST be zero
++              hash_entry->key.Ethertype       = 0;
++              hash_entry->key.port_id         = cfg->wan_port;
++              hash_entry->key.rule_id         = 0;
++              hash_entry->key.ip_protocol = proto;
++              hash_entry->key.reserved1       = 0;
++              hash_entry->key.reserved2       = 0;
++              hash_entry->key.sip             = ntohl(nat_cb->sip);
++              hash_entry->key.dip             = ntohl(nat_cb->dip);
++              hash_entry->key.sport           = nat_cb->sport;
++              hash_entry->key.dport           = nat_cb->dport;
++
++              hash_index = nat_build_keys(&hash_entry->key);
++
++#ifdef NAT_DEBUG_WAN_HASH_TIMEOUT
++              if (hash_get_nat_owner_flag(hash_index))
++                      return 0;
++#endif
++              if (hash_get_valid_flag(hash_index))
++              {
++                      nat_ip_conntrack->wan2lan_collision = 1;
++                      nat_collision++;
++#if 0
++                      if (proto == IPPROTO_TCP && (tcp_flag_word(tcp_hdr) & (TCP_FLAG_FIN | TCP_FLAG_RST)))
++                      {
++                              if (memcmp((void *)&hash_entry->key, hash_get_entry(hash_index), sizeof(NAT_KEY_T)) == 0)
++                              {
++                                      hash_nat_disable_owner(hash_index);
++                                      hash_invalidate_entry(hash_index); // Must last one, else HW Tx fast SW
++                                      // nat_printf("Invalidate nat hash entry %d\n", hash_index);
++                              }
++                      }
++#endif
++                      return 0;
++              }
++
++              // write hash entry
++              hash_entry->key.rule_id = cfg->tcp_udp_rule_id;
++              memcpy(hash_entry->param.da, skb->data, 6);
++              memcpy(hash_entry->param.sa, skb->data+6, 6);
++              hash_entry->param.Sip = sip;
++              hash_entry->param.Dip = dip;
++              hash_entry->param.Sport = sport;
++              hash_entry->param.Dport = dport;
++              hash_entry->param.vlan = 0;
++              hash_entry->param.pppoe = 0;
++              hash_entry->param.sw_id = 0;
++              hash_entry->param.mtu = 0;
++              hash_entry->action.dword = (nat_cb->pppoe_frame) ? NAT_PPPOE_WAN2LAN_ACTIONS : NAT_WAN2LAN_ACTIONS;
++              hash_entry->action.bits.dest_qid = sl351x_nat_assign_qid(proto, sip, dip, sport, dport);
++              hash_entry->action.bits.dest_qid += (cfg->lan_port==0) ? TOE_GMAC0_HW_TXQ0_QID : TOE_GMAC1_HW_TXQ0_QID;;
++              hash_entry->tmo.counter = hash_entry->tmo.interval =
++                                              (proto == IPPROTO_TCP) ? cfg->tcp_tmo_interval : cfg->udp_tmo_interval;
++              nat_write_hash_entry(hash_index, hash_entry);
++
++              // nat_printf("%lu Validate a WAN hash entry %d\n", jiffies/HZ, hash_index);
++              // hash_dump_entry(hash_index);
++              hash_nat_enable_owner(hash_index);
++              hash_validate_entry(hash_index); // Must last one, else HW Tx fast SW
++              nat_ip_conntrack->wan2lan_hash_index = hash_index + 1;
++              nat_ip_conntrack->hw_nat |= 2;
++              return 0;
++      }
++      return 0;
++}
++
++/*----------------------------------------------------------------------
++* sl351x_nat_gre_output
++*     Handle NAT GRE output frames
++*----------------------------------------------------------------------*/
++int sl351x_nat_gre_output(struct sk_buff *skb, int port)
++{
++      u32                                     sip, dip;
++      struct ethhdr           *ether_hdr;
++      struct iphdr            *ip_hdr;
++      struct pppoe_hdr        *pppoe_hdr;
++      GRE_PKTHDR_T            *gre_hdr;
++      NAT_CB_T                        *nat_cb;
++      NAT_CFG_T                       *cfg;
++      u16                                     ppp_proto;
++      u32                                     hash_data[HASH_MAX_DWORDS];
++      GRE_HASH_ENTRY_T        *hash_entry;
++      int                                     hash_index;
++      struct ip_conntrack *nat_ip_conntrack;
++      enum ip_conntrack_info ctinfo;
++
++      nat_cb = NAT_SKB_CB(skb);
++      cfg = (NAT_CFG_T *)&nat_cfg;
++
++      ether_hdr = (struct ethhdr *)skb->data;
++      ip_hdr = (struct iphdr *)skb->h.ipiph;
++      gre_hdr = (GRE_PKTHDR_T *)((u32)ip_hdr + (ip_hdr->ihl<<2));
++      sip = ntohl(ip_hdr->saddr);
++      dip = ntohl(ip_hdr->daddr);
++
++#ifdef        NAT_DEBUG_MSG
++      {
++              nat_printf("To   GMAC-%d: 0x%-4X GRE %d.%d.%d.%d [%d] --> %d.%d.%d.%d",
++                              port, ntohs(ip_hdr->id),
++                              NIPQUAD(ip_hdr->saddr), ntohs(gre_hdr->call_id),
++                              NIPQUAD(ip_hdr->daddr));
++              nat_printf("\n");
++      }
++#endif
++      nat_ip_conntrack = ip_conntrack_get(skb, &ctinfo);
++      if (nat_ip_conntrack)
++      {
++              // if (nat_ip_conntrack->master || nat_ip_conntrack->helper)
++              if (nat_ip_conntrack->helper)
++              {
++                      nat_printf("GRE Call-ID=%d, master=0x%x, helper=0x%x\n", ntohs(gre_hdr->call_id), (u32)nat_ip_conntrack->master, (u32)nat_ip_conntrack->helper);
++                      return 0;
++              }
++              if (!(nat_ip_conntrack->status & IPS_ASSURED))
++                      return 0;
++      }
++
++      hash_entry = (GRE_HASH_ENTRY_T *)&hash_data;
++      if (port == cfg->wan_port)      // LAN-to-WAN
++      {
++#ifdef _NOT_CHECK_SIP_DIP     // enable it if know and get the wan ip address
++              if (!sl351x_nat_find_ipcfg(sip, port))
++              {
++                      printk("LAN->WAN Incorrect Sip %d.%d.%d.%d\n", HIPQUAD(sip));
++                      return 0;
++              }
++#endif
++              // Note: unused fields (including rule_id) MUST be zero
++              hash_entry->key.Ethertype       = 0;
++              hash_entry->key.port_id         = cfg->lan_port;
++              hash_entry->key.rule_id         = 0;
++              hash_entry->key.ip_protocol = IPPROTO_GRE;
++              hash_entry->key.reserved1       = 0;
++              hash_entry->key.reserved2       = 0;
++              hash_entry->key.reserved3       = 0;
++              hash_entry->key.reserved4       = 0;
++              hash_entry->key.sip             = ntohl(nat_cb->sip);
++              hash_entry->key.dip             = ntohl(nat_cb->dip);
++              hash_entry->key.protocol        = nat_cb->sport;
++              hash_entry->key.call_id         = nat_cb->dport;
++
++              hash_index = gre_build_keys(&hash_entry->key);
++
++#ifdef NAT_DEBUG_LAN_HASH_TIMEOUT
++              if (hash_get_nat_owner_flag(hash_index))
++                      return 0;
++#endif
++              if (hash_get_valid_flag(hash_index))
++              {
++                      return 0;
++              }
++
++              // write hash entry
++              hash_entry->key.rule_id = cfg->gre_rule_id;
++              memcpy(hash_entry->param.da, skb->data, 6);
++              memcpy(hash_entry->param.sa, skb->data+6, 6);
++              hash_entry->param.Sip = sip;
++              hash_entry->param.Dip = dip;
++              hash_entry->param.Sport = 0;
++              hash_entry->param.Dport = ntohs(gre_hdr->call_id);
++              hash_entry->param.vlan = 0;
++              hash_entry->param.sw_id = 0;
++              hash_entry->param.mtu = 0;
++              // check PPPoE
++              pppoe_hdr = (struct pppoe_hdr *)(ether_hdr + 1);
++              ppp_proto = *(u16 *)&pppoe_hdr->tag[0];
++              if (ether_hdr->h_proto == __constant_htons(ETH_P_PPP_SES)       // 0x8864
++                      && ppp_proto == __constant_htons(PPP_IP) )                              // 0x21
++              {
++                      hash_entry->action.dword = NAT_PPPOE_PPTP_LAN2WAN_ACTIONS;
++                      hash_entry->param.pppoe = htons(pppoe_hdr->sid);
++              }
++              else
++              {
++                      hash_entry->action.dword = NAT_PPTP_LAN2WAN_ACTIONS;
++                      hash_entry->param.pppoe = 0;
++              }
++              hash_entry->action.bits.dest_qid = sl351x_nat_assign_qid(IPPROTO_GRE, sip, dip, 0, ntohs(gre_hdr->call_id));
++              hash_entry->action.bits.dest_qid +=     (cfg->wan_port==0) ? TOE_GMAC0_HW_TXQ0_QID : TOE_GMAC1_HW_TXQ0_QID;
++              hash_entry->tmo.counter = hash_entry->tmo.interval = cfg->gre_tmo_interval;
++              gre_write_hash_entry(hash_index, hash_entry);
++              // nat_printf("%lu Validate a LAN hash entry %d\n", jiffies/HZ, hash_index);
++              // hash_dump_entry(hash_index);
++              hash_nat_enable_owner(hash_index);
++              hash_validate_entry(hash_index); // Must last one, else HW Tx fast than SW
++              return 0;
++      }
++      else // WAN-to-LAN
++      {
++              // Note: unused fields (including rule_id) MUST be zero
++              hash_entry->key.Ethertype       = 0;
++              hash_entry->key.port_id         = cfg->wan_port;
++              hash_entry->key.rule_id         = 0;
++              hash_entry->key.ip_protocol = IPPROTO_GRE;
++              hash_entry->key.reserved1       = 0;
++              hash_entry->key.reserved2       = 0;
++              hash_entry->key.reserved3       = 0;
++              hash_entry->key.reserved4       = 0;
++              hash_entry->key.sip             = ntohl(nat_cb->sip);
++              hash_entry->key.dip             = ntohl(nat_cb->dip);
++              hash_entry->key.protocol        = nat_cb->sport;
++              hash_entry->key.call_id         = nat_cb->dport;
++
++              hash_index = gre_build_keys(&hash_entry->key);
++
++#ifdef NAT_DEBUG_WAN_HASH_TIMEOUT
++              if (hash_get_nat_owner_flag(hash_index))
++                      return 0;
++#endif
++              if (hash_get_valid_flag(hash_index))
++              {
++                      return 0;
++              }
++
++              // write hash entry
++              hash_entry->key.rule_id = cfg->gre_rule_id;
++              memcpy(hash_entry->param.da, skb->data, 6);
++              memcpy(hash_entry->param.sa, skb->data+6, 6);
++              hash_entry->param.Sip = sip;
++              hash_entry->param.Dip = dip;
++              hash_entry->param.Sport = 0;
++              hash_entry->param.Dport = ntohs(gre_hdr->call_id);
++              hash_entry->param.vlan = 0;
++              hash_entry->param.pppoe = 0;
++              hash_entry->param.sw_id = 0;
++              hash_entry->param.mtu = 0;
++              hash_entry->action.dword = (nat_cb->pppoe_frame) ? NAT_PPPOE_PPTP_WAN2LAN_ACTIONS : NAT_PPTP_WAN2LAN_ACTIONS;
++              hash_entry->action.bits.dest_qid = sl351x_nat_assign_qid(IPPROTO_GRE, sip, dip, 0, ntohs(gre_hdr->call_id));
++              hash_entry->action.bits.dest_qid += (cfg->lan_port==0) ? TOE_GMAC0_HW_TXQ0_QID : TOE_GMAC1_HW_TXQ0_QID;;
++              hash_entry->tmo.counter = hash_entry->tmo.interval = cfg->gre_tmo_interval;
++              gre_write_hash_entry(hash_index, hash_entry);
++
++              // nat_printf("%lu Validate a WAN hash entry %d\n", jiffies/HZ, hash_index);
++              // hash_dump_entry(hash_index);
++              hash_nat_enable_owner(hash_index);
++              hash_validate_entry(hash_index); // Must last one, else HW Tx fast SW
++              return 0;
++      }
++      return 0;
++}
++
++
++#ifdef _HAVE_DYNAMIC_PORT_LIST
++/*----------------------------------------------------------------------
++* sl_nat_add_port
++*----------------------------------------------------------------------*/
++void sl_nat_add_port(u8 protocol, u16 port)
++{
++      int     i;
++      u16             *port_ptr;
++
++      if (protocol == IPPROTO_TCP)
++              port_ptr = dynamic_tcp_port_list;
++      else if (protocol == IPPROTO_UDP)
++              port_ptr = dynamic_udp_port_list;
++      else
++              return;
++
++      for (i=0; *port_ptr; i++)
++      {
++              if (port == *port_ptr)
++                      return;
++              port_ptr++;
++      }
++      port_ptr++;
++      *port_ptr = port;
++}
++
++/*----------------------------------------------------------------------
++* sl_nat_remove_port
++*----------------------------------------------------------------------*/
++void sl_nat_remove_port(u8 protocol, u16 port)
++{
++      int     i, j;
++      u16             *port_ptr, *next;
++
++      if (protocol == IPPROTO_TCP)
++              port_ptr = dynamic_tcp_port_list;
++      else if (protocol == IPPROTO_UDP)
++              port_ptr = dynamic_udp_port_list;
++      else
++              return;
++
++      for (i=0; *port_ptr; i++, port_ptr++)
++      {
++              if (port == *port_ptr)
++              {
++                      port_next = port_ptr + 1;
++                      for (j=i+1; *port_next; i++, j++)
++                              *port_ptr++ = *port_next++;
++                      *port_ptr = 0;
++                      return;
++              }
++      }
++}
++#endif
++
++/*----------------------------------------------------------------------
++* sl351x_nat_ioctl
++*----------------------------------------------------------------------*/
++int sl351x_nat_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
++{
++      GMAC_INFO_T             *tp = (GMAC_INFO_T *)dev->priv;
++      int                             i, j, port_id;
++    NATCMD_HDR_T              nat_hdr;
++    NAT_REQ_E                 ctrl;
++      unsigned char           *req_datap;
++      NAT_IP_ENTRY_T          *ipcfg;
++      NAT_XPORT_ENTRY_T       *xport_entry;
++      NAT_WRULE_ENTRY_T       *wrule_entry;
++      unsigned int            qid;
++
++      if (copy_from_user((void *)&nat_hdr, rq->ifr_data, sizeof(nat_hdr)))
++              return -EFAULT;
++      req_datap = (unsigned char *)rq->ifr_data + sizeof(nat_hdr);
++      port_id = tp->port_id;
++      switch (nat_hdr.cmd) {
++      case NATSSTATUS:
++              if (!capable(CAP_NET_ADMIN))
++                      return -EPERM;
++              if (nat_hdr.len != sizeof(NAT_STATUS_T))
++                      return -EPERM;
++              if (copy_from_user((void *)&ctrl.status, req_datap, sizeof(ctrl.status)))
++                      return -EFAULT;
++              if (ctrl.status.enable != 0 && ctrl.status.enable != 1)
++                      return -EPERM;
++              // sl351x_nat_set_enabled_flag(ctrl.status.enable);
++              if (nat_cfg.enabled && (ctrl.status.enable == 0))
++              {
++                      for (i=0; i<HASH_TOTAL_ENTRIES; i++)
++                      {
++                              if (hash_get_nat_owner_flag(i))
++                              {
++                                      hash_nat_disable_owner(i);
++                                      hash_invalidate_entry(i);
++                              }
++                      }
++              }
++              nat_cfg.enabled = ctrl.status.enable;
++              break;
++      case NATGSTATUS:
++              if (nat_hdr.len != sizeof(NAT_STATUS_T))
++                      return -EPERM;
++              ctrl.status.enable = nat_cfg.enabled;
++              if (copy_to_user(req_datap, (void *)&ctrl.status, sizeof(ctrl.status)))
++                      return -EFAULT;
++              break;
++      case NATSETPORT:
++              if (!capable(CAP_NET_ADMIN))
++                      return -EPERM;
++              if (nat_hdr.len != sizeof(NAT_PORTCFG_T))
++                      return -EPERM;
++              if (copy_from_user((void *)&ctrl.portcfg, req_datap, sizeof(ctrl.portcfg)))
++                      return -EFAULT;
++              if (ctrl.portcfg.portmap == 0)
++                      nat_cfg.lan_port = port_id;
++              else if (ctrl.portcfg.portmap == 1)
++                      nat_cfg.wan_port = port_id;
++              else
++                      return -EPERM;
++              break;
++      case NATGETPORT:
++              if (nat_hdr.len != sizeof(NAT_PORTCFG_T))
++                      return -EPERM;
++              if (nat_cfg.lan_port == port_id)
++                      ctrl.portcfg.portmap = 0;
++              else if (nat_cfg.wan_port == port_id)
++                      ctrl.portcfg.portmap = 1;
++              else
++                      return -EPERM;
++              if (copy_to_user(req_datap, (void *)&ctrl.portcfg, sizeof(ctrl.portcfg)))
++                      return -EFAULT;
++              break;
++      case NATADDIP:
++              if (!capable(CAP_NET_ADMIN))
++                      return -EPERM;
++              if (nat_hdr.len != sizeof(NAT_IPCFG_T))
++                      return -EPERM;
++              i = nat_cfg.ipcfg[port_id].total;
++              if (i >= CONFIG_NAT_MAX_IP_NUM)
++                      return -E2BIG;
++              if (copy_from_user((void *)&nat_cfg.ipcfg[port_id].entry[i], req_datap, sizeof(NAT_IPCFG_T)))
++                      return -EFAULT;
++              nat_cfg.ipcfg[port_id].total++;
++              break;
++      case NATDELIP:
++              if (!capable(CAP_NET_ADMIN))
++                      return -EPERM;
++              if (nat_hdr.len != sizeof(NAT_IPCFG_T))
++                      return -EPERM;
++              if (copy_from_user((void *)&ctrl.ipcfg, req_datap, sizeof(ctrl.ipcfg)))
++                      return -EFAULT;
++              ipcfg = (NAT_IP_ENTRY_T *)&nat_cfg.ipcfg[port_id].entry[0];
++              for (i=0; i<nat_cfg.ipcfg[port_id].total; i++, ipcfg++)
++              {
++                      if (ipcfg->ipaddr == ctrl.ipcfg.entry.ipaddr)
++                      {
++                              NAT_IP_ENTRY_T *ipcfg_next;
++                              ipcfg_next = ipcfg + 1;
++                              for (j=i+1; j < nat_cfg.ipcfg[port_id].total; i++, j++)
++                              {
++                                      memcpy((void *)ipcfg, (void *)ipcfg_next, sizeof(NAT_IP_ENTRY_T));
++                                      ipcfg++;
++                                      ipcfg_next++;
++                              }
++                              ipcfg->ipaddr = 0;
++                              ipcfg->netmask = 0;
++                              nat_cfg.ipcfg[port_id].total--;
++                              return 0;
++                      }
++              }
++              return -ENOENT;
++      case NATGETIP:
++              if (nat_hdr.len != sizeof(NAT_IPCFG_ALL_T))
++                      return -EPERM;
++              if (copy_to_user(req_datap, (void *)&nat_cfg.ipcfg[port_id], sizeof(NAT_IPCFG_ALL_T)))
++                      return -EFAULT;
++              break;
++      case NATAXPORT:
++              if (!capable(CAP_NET_ADMIN))
++                      return -EPERM;
++              if (nat_hdr.len != sizeof(NAT_XPORT_T))
++                      return -EPERM;
++              i = nat_cfg.xport.total;
++              if (i >= CONFIG_NAT_MAX_XPORT)
++                      return -E2BIG;
++              if (copy_from_user((void *)&nat_cfg.xport.entry[i], req_datap, sizeof(NAT_XPORT_T)))
++                      return -EFAULT;
++              nat_cfg.xport.total++;
++              break;
++      case NATDXPORT:
++              if (!capable(CAP_NET_ADMIN))
++                      return -EPERM;
++              if (nat_hdr.len != sizeof(NAT_XPORT_T))
++                      return -EPERM;
++              if (copy_from_user((void *)&ctrl.xport, req_datap, sizeof(NAT_XPORT_T)))
++                      return -EFAULT;
++              xport_entry = (NAT_XPORT_ENTRY_T *)&nat_cfg.xport.entry[0];
++              for (i=0; i<nat_cfg.xport.total; i++, xport_entry++)
++              {
++                      if (memcmp((void *)xport_entry, (void *)&ctrl.xport, sizeof(NAT_XPORT_ENTRY_T)) == 0)
++                      {
++                              NAT_XPORT_ENTRY_T *xport_next;
++                              xport_next = xport_entry + 1;
++                              for (j=i+1; j < nat_cfg.xport.total; i++, j++)
++                              {
++                                      memcpy((void *)xport_entry, (void *)xport_next, sizeof(NAT_XPORT_ENTRY_T));
++                                      xport_entry++;
++                                      xport_next++;
++                              }
++                              memset((void *)xport_entry, 0, sizeof(NAT_XPORT_ENTRY_T));
++                              nat_cfg.xport.total--;
++                              return 0;
++                      }
++              }
++              return -ENOENT;
++      case NATGXPORT:
++              if (nat_hdr.len != sizeof(NAT_XPORT_ALL_T))
++                      return -EPERM;
++              if (copy_to_user(req_datap, (void *)&nat_cfg.xport, sizeof(NAT_XPORT_ALL_T)))
++                      return -EFAULT;
++              break;
++      case NATSWEIGHT:
++              if (!capable(CAP_NET_ADMIN))
++                      return -EPERM;
++              if (nat_hdr.len != sizeof(NAT_WEIGHT_T))
++                      return -EPERM;
++              if (copy_from_user((void *)&nat_cfg.weight, req_datap, sizeof(NAT_WEIGHT_T)))
++                      return -EFAULT;
++              mac_set_hw_tx_weight(dev, (char *)&nat_cfg.weight);
++              break;
++      case NATGWEIGHT:
++              if (nat_hdr.len != sizeof(NAT_WEIGHT_T))
++                      return -EPERM;
++              mac_get_hw_tx_weight(dev, (char *)&nat_cfg.weight);
++              if (copy_to_user(req_datap, (void *)&nat_cfg.weight, sizeof(NAT_WEIGHT_T)))
++                      return -EFAULT;
++              break;
++      case NATAWRULE:
++              if (!capable(CAP_NET_ADMIN))
++                      return -EPERM;
++              if (nat_hdr.len != sizeof(NAT_WRULE_T))
++                      return -EPERM;
++              if (copy_from_user((void *)&qid, req_datap, sizeof(qid)))
++                      return -EFAULT;
++              if (qid > CONFIG_NAT_TXQ_NUM)
++                      return -EPERM;
++              i = nat_cfg.wrule[qid].total;
++              if (i >= CONFIG_NAT_MAX_WRULE)
++                      return -E2BIG;
++              if (copy_from_user((void *)&nat_cfg.wrule[qid].entry[i], req_datap+sizeof(qid), sizeof(NAT_WRULE_T)))
++                      return -EFAULT;
++              nat_cfg.wrule[qid].total++;
++              break;
++      case NATDWRULE:
++              if (!capable(CAP_NET_ADMIN))
++                      return -EPERM;
++              if (nat_hdr.len != sizeof(NAT_WRULE_T))
++                      return -EPERM;
++              if (copy_from_user((void *)&ctrl.wrule, req_datap, sizeof(NAT_WRULE_T)))
++                      return -EFAULT;
++              qid = ctrl.wrule.qid;
++              if (qid >= CONFIG_NAT_TXQ_NUM)
++                      return -EPERM;
++              wrule_entry = (NAT_WRULE_ENTRY_T *)&nat_cfg.wrule[qid].entry[0];
++              for (i=0; i<nat_cfg.wrule[qid].total; i++, wrule_entry++)
++              {
++                      if (memcmp((void *)wrule_entry, (void *)&ctrl.wrule.entry, sizeof(NAT_WRULE_ENTRY_T)) == 0)
++                      {
++                              NAT_WRULE_ENTRY_T *wrule_next;
++                              wrule_next = wrule_entry + 1;
++                              for (j=i+1; j < nat_cfg.wrule[qid].total; i++, j++)
++                              {
++                                      memcpy((void *)wrule_entry, (void *)wrule_next, sizeof(NAT_WRULE_ENTRY_T));
++                                      wrule_entry++;
++                                      wrule_next++;
++                              }
++                              memset((void *)wrule_entry, 0, sizeof(NAT_WRULE_ENTRY_T));
++                              nat_cfg.wrule[qid].total--;
++                              return 0;
++                      }
++              }
++              return -ENOENT;
++      case NATGWRULE:
++              if (nat_hdr.len != sizeof(NAT_WRULE_ALL_T))
++                      return -EPERM;
++              if (copy_from_user((void *)&qid, req_datap, sizeof(qid)))
++                      return -EFAULT;
++              if (qid >= CONFIG_NAT_TXQ_NUM)
++                      return -EPERM;
++              if (copy_to_user(req_datap, (void *)&nat_cfg.wrule[qid], sizeof(NAT_WRULE_ALL_T)))
++                      return -EFAULT;
++              break;
++      case NATSDEFQ:
++              if (!capable(CAP_NET_ADMIN))
++                      return -EPERM;
++              if (nat_hdr.len != sizeof(NAT_QUEUE_T))
++                      return -EPERM;
++              if (copy_from_user((void *)&nat_cfg.default_hw_txq, req_datap, sizeof(u32)))
++                      return -EFAULT;
++              break;
++      case NATGDEFQ:
++              if (nat_hdr.len != sizeof(NAT_QUEUE_T))
++                      return -EPERM;
++              if (copy_to_user(req_datap, (void *)&nat_cfg.default_hw_txq, sizeof(u32)))
++                      return -EFAULT;
++      case NATRMIPCFG:
++              nat_cfg.ipcfg[port_id].total = 0;
++              break;
++      case NATTESTENTRY:
++              if (!capable(CAP_NET_ADMIN))
++                      return -EPERM;
++              if (nat_hdr.len != sizeof(NAT_TESTENTRY_T))
++                      return -EPERM;
++              if (copy_from_user((void *)&ctrl.init_entry, req_datap, sizeof(ctrl.init_entry)))
++                      return -EFAULT;
++              if (ctrl.init_entry.init_enable != 0 && ctrl.init_entry.init_enable != 1)
++                      return -EPERM;
++              nat_cfg.init_enabled = ctrl.init_entry.init_enable;
++              break;
++
++      default:
++              return -EPERM;
++      }
++
++      return 0;
++}
++
++/*----------------------------------------------------------------------
++*     nat_init_test_entry
++*     Initialize NAT test hash entries
++*
++*     SmartBits P1  -----> Lepus GMAC 0 --------------+
++*                                                                                                     |
++*                                                                                                     |
++*             P3  <----- Lepus GMAC 1 -- HW TxQ0 <--+
++*                                                                       -- HW TxQ1 <--+
++*                                                                       -- HW TxQ2 <--+
++*                                                                       -- HW TxQ3 <--+
++*
++*     SmartBits P1  <----- Lepus GMAC 0 -- HW TxQ0 <--+
++*                                                                       -- HW TxQ1 <--+
++*                                     -- HW TxQ2 <--+
++*                                                                       -- HW TxQ3 <--+
++*                                                                                                     |
++*                                                                                                     |
++*             P3  -----> Lepus GMAC 1 --------------+
++*
++*   LAN GMAC0 <--------------------------------------------> GMAC1 WAN
++*     192.168.[x].[y]:50 --> 168.95.[x].[y]:80 ---TXQ[y-1]---> 192.168.2.254:200[y] --> 168.95.[x].[y]:80
++*     192.168.[x].[y]:50 <-- 168.95.[x].[y]:80 <--TXQ[y-1]---- 192.168.2.254:200[y] <-- 168.95.[x].[y]:80
++*   where:
++*             [x] : Packet Type
++*             [y] : Tx Queue, 1 for TxQ0, 2 for TxQ1, 3 for TxQ2, 4 for TxQ3,
++*
++*
++* Packet Type:
++* 1. TCP Frames <---> TCP Frames
++*   LAN GMAC0 <--------------------------------> GMAC1 WAN
++*     192.168.1.1:50 --> 168.95.1.1:80 ---TXQ0---> 192.168.2.254:2001 --> 168.95.1.1:80
++*     192.168.1.1:50 <-- 168.95.1.1:80 <--TXQ0---- 192.168.2.254:2001 <-- 168.95.1.1:80
++*
++*     192.168.1.2:50 --> 168.95.1.2:80 ---TXQ1---> 192.168.2.254:2002 --> 168.95.1.2:80
++*     192.168.1.2:50 <-- 168.95.1.2:80 <--TXQ1---- 192.168.2.254:2002 <-- 168.95.1.2:80
++*
++*     192.168.1.3:50 --> 168.95.1.3:80 ---TXQ2---> 192.168.2.254:2003 --> 168.95.1.3:80
++*     192.168.1.3:50 <-- 168.95.1.3:80 <--TXQ2---- 192.168.2.254:2003 <-- 168.95.1.3:80
++*
++*     192.168.1.4:50 --> 168.95.1.4:80 ---TXQ3---> 192.168.2.254:2004 --> 168.95.1.4:80
++*     192.168.1.4:50 <-- 168.95.1.4:80 <--TXQ3---- 192.168.2.254:2004 <-- 168.95.1.4:80
++*
++* 2 TCP Frames <----> PPPoE + TCP Frames
++*   LAN GMAC0 <--------------------------------> GMAC1 WAN
++*     192.168.2.1:50 --> 168.95.2.1:80 ---TXQ0---> 192.168.2.254:2001 --> 168.95.2.1:80
++*     192.168.2.1:50 <-- 168.95.2.1:80 <--TXQ0---- 192.168.2.254:2001 <-- 168.95.2.1:80
++*
++*     192.168.2.2:50 --> 168.95.2.2:80 ---TXQ1---> 192.168.2.254:2002 --> 168.95.2.2:80
++*     192.168.2.2:50 <-- 168.95.2.2:80 <--TXQ1---- 192.168.2.254:2002 <-- 168.95.2.2:80
++*
++*     192.168.2.3:50 --> 168.95.2.3:80 ---TXQ2---> 192.168.2.254:2003 --> 168.95.2.3:80
++*     192.168.2.3:50 <-- 168.95.2.3:80 <--TXQ2---- 192.168.2.254:2003 <-- 168.95.2.3:80
++*
++*     192.168.2.4:50 --> 168.95.2.4:80 ---TXQ3---> 192.168.2.254:2004 --> 168.95.2.4:80
++*     192.168.2.4:50 <-- 168.95.2.4:80 <--TXQ3---- 192.168.2.254:2004 <-- 168.95.2.4:80
++*
++* 3 TCP Frames <----> VLAN + PPPoE + TCP Frames
++*   LAN GMAC0 <--------------------------------> GMAC1 WAN
++*     192.168.3.1:50 --> 168.95.3.1:80 ---TXQ0---> 192.168.2.254:2001 --> 168.95.3.1:80
++*     192.168.3.1:50 <-- 168.95.3.1:80 <--TXQ0---- 192.168.2.254:2001 <-- 168.95.3.1:80
++*
++*     192.168.3.2:50 --> 168.95.3.2:80 ---TXQ1---> 192.168.2.254:2002 --> 168.95.3.2:80
++*     192.168.3.2:50 <-- 168.95.3.2:80 <--TXQ1---- 192.168.2.254:2002 <-- 168.95.3.2:80
++*
++*     192.168.3.3:50 --> 168.95.3.3:80 ---TXQ2---> 192.168.2.254:2003 --> 168.95.3.3:80
++*     192.168.3.3:50 <-- 168.95.3.3:80 <--TXQ2---- 192.168.2.254:2003 <-- 168.95.3.3:80
++*
++*     192.168.3.4:50 --> 168.95.3.4:80 ---TXQ3---> 192.168.2.254:2004 --> 168.95.3.4:80
++*     192.168.3.4:50 <-- 168.95.3.4:80 <--TXQ3---- 192.168.2.254:2004 <-- 168.95.3.4:80
++*
++* 4 VLAN-A + TCP Frames <----> VLAN-B + PPPoE + TCP Frames
++*   LAN GMAC0 <--------------------------------> GMAC1 WAN
++*     192.168.4.1:50 --> 168.95.4.1:80 ---TXQ0---> 192.168.2.254:2001 --> 168.95.4.1:80
++*     192.168.4.1:50 <-- 168.95.4.1:80 <--TXQ0---- 192.168.2.254:2001 <-- 168.95.4.1:80
++*
++*     192.168.4.2:50 --> 168.95.4.2:80 ---TXQ1---> 192.168.2.254:2002 --> 168.95.4.2:80
++*     192.168.4.2:50 <-- 168.95.4.2:80 <--TXQ1---- 192.168.2.254:2002 <-- 168.95.4.2:80
++*
++*     192.168.4.3:50 --> 168.95.4.3:80 ---TXQ2---> 192.168.2.254:2003 --> 168.95.4.3:80
++*     192.168.4.3:50 <-- 168.95.4.3:80 <--TXQ2---- 192.168.2.254:2003 <-- 168.95.4.3:80
++*
++*     192.168.4.4:50 --> 168.95.4.4:80 ---TXQ3---> 192.168.2.254:2004 --> 168.95.4.4:80
++*     192.168.4.4:50 <-- 168.95.4.4:80 <--TXQ3---- 192.168.2.254:2004 <-- 168.95.4.4:80
++*
++*
++*
++*----------------------------------------------------------------------*/
++#ifdef SL351x_NAT_TEST_BY_SMARTBITS
++#define       NAT_IPIV(a,b,c,d)                       ((a<<24)+(b<<16)+(c<<8)+d)
++#define     NAT_TEST_CLIENT_IP                        NAT_IPIV(192,168,1,1)
++#define     NAT_TEST_SERVER_IP                        NAT_IPIV(168,95,1,1)
++#define               NAT_TEST_LAN_IP                         NAT_IPIV(192,168,1,254)
++#define               NAT_TEST_WAN_IP                         NAT_IPIV(192,168,2,254)
++#define     NAT_TEST_MAP_PORT_BASE            2001
++#define     NAT_TEST_SPORT                            50
++#define     NAT_TEST_DPORT                            80
++#define     NAT_TEST_PROTOCOL                 6
++u8                    nat_test_lan_target_da[6]={0x00,0x11,0x22,0x33,0x44,0x55};
++u8                    nat_test_wan_target_da[6]={0x00,0xaa,0xbb,0xcc,0xdd,0xee};
++u8                    nat_test_lan_my_da[6]={0x00,0x11,0x11,0x11,0x11,0x11};
++u8                    nat_test_wan_my_da[6]={0x00,0x22,0x22,0x22,0x22,0x22};
++static void nat_init_test_entry(void)
++{
++      int                             i, j ;
++      NAT_HASH_ENTRY_T        *hash_entry;
++      u32                                     sip, dip;
++      u32                                     hash_data[HASH_MAX_DWORDS];
++      NAT_CFG_T                       *cfg;
++      int                                     hash_index;
++
++      cfg = (NAT_CFG_T *)&nat_cfg;
++      hash_entry = (NAT_HASH_ENTRY_T *)&hash_data;
++      hash_entry->key.Ethertype       = 0;
++      hash_entry->key.rule_id         = 0;
++      hash_entry->key.ip_protocol = IPPROTO_TCP;
++      hash_entry->key.reserved1       = 0;
++      hash_entry->key.reserved2       = 0;
++      // hash_entry->key.sip          = NAT_TEST_CLIENT_IP;
++      // hash_entry->key.dip          = NAT_TEST_SERVER_IP;
++      hash_entry->key.sport           = htons(NAT_TEST_SPORT);
++      hash_entry->key.dport           = htons(NAT_TEST_DPORT);
++      hash_entry->key.rule_id = cfg->tcp_udp_rule_id;
++      hash_entry->action.dword = NAT_LAN2WAN_ACTIONS;
++
++      sip = NAT_TEST_CLIENT_IP;
++      dip = NAT_TEST_SERVER_IP;
++
++      // Init TCP <------> TCP hash entries
++      // LAN --> WAN
++      // (1) TCP --> TCP
++      // (2) TCP --> PPPoE + TCP
++      // (3) TCP --> VLAN-B + PPPoE + TCP
++      // (4) TCP + VLAN-A --> VLAN-B + PPPoE + TCP
++      memcpy(hash_entry->param.da, nat_test_wan_target_da, 6);
++      memcpy(hash_entry->param.sa, nat_test_wan_my_da, 6);
++      hash_entry->key.port_id = cfg->lan_port;
++      for (i=0; i<TOE_HW_TXQ_NUM; i++)
++      {
++              if (i < 2)
++              {
++                      hash_entry->action.bits.dest_qid = i+2;
++              }
++              else
++              {
++                      hash_entry->action.bits.dest_qid = i;
++              }
++              hash_entry->action.bits.dest_qid += (cfg->wan_port==0) ? TOE_GMAC0_HW_TXQ0_QID : TOE_GMAC1_HW_TXQ0_QID;
++              hash_entry->param.Sport = NAT_TEST_MAP_PORT_BASE+i;
++              hash_entry->param.Dport = NAT_TEST_DPORT;
++              for (j=0; j<4; j++)
++              {
++                      hash_entry->key.sip = sip + i + j*0x100;
++                      hash_entry->key.dip = dip + i + j*0x100;
++                      hash_entry->param.Dip = hash_entry->key.dip;
++                      hash_entry->param.Sip = NAT_TEST_WAN_IP;
++                      switch (j)
++                      {
++                      case 0:
++                              hash_entry->action.bits.pppoe = 0;
++                              hash_entry->param.pppoe = 0;
++                              hash_entry->action.bits.vlan = 0;
++                              hash_entry->param.vlan = 0;
++                              break;
++                      case 1:
++                              hash_entry->action.bits.pppoe = 1;
++                              hash_entry->param.pppoe = i+1;
++                              hash_entry->action.bits.vlan = 0;
++                              hash_entry->param.vlan = 0;
++                              break;
++                      case 2:
++                              hash_entry->action.bits.pppoe = 1;
++                              hash_entry->param.pppoe = i+1;
++                              hash_entry->action.bits.vlan = 1;
++                              hash_entry->param.vlan = i+10;
++                              break;
++                      case 3:
++                              hash_entry->action.bits.pppoe = 1;
++                              hash_entry->param.pppoe = i+1;
++                              hash_entry->action.bits.vlan = 1;
++                              hash_entry->param.vlan = i+10;
++                              break;
++                      }
++                      hash_entry->tmo.counter = hash_entry->tmo.interval = 0x7fff;
++                      hash_index = nat_build_keys(&hash_entry->key);
++                      nat_write_hash_entry(hash_index, hash_entry);
++                      hash_nat_enable_owner(hash_index);
++                      hash_validate_entry(hash_index); // Must last one, else HW Tx fast than SW
++              }
++      }
++
++
++      // WAN --> LAN
++      hash_entry->key.port_id         = cfg->wan_port;
++      hash_entry->key.sport           = htons(NAT_TEST_DPORT);
++      hash_entry->key.dport           = htons(NAT_TEST_DPORT);
++      hash_entry->key.rule_id         = cfg->tcp_udp_rule_id;
++      hash_entry->action.dword        = NAT_WAN2LAN_ACTIONS;
++      hash_entry->key.sport           = htons(NAT_TEST_DPORT);
++      memcpy(hash_entry->param.da, nat_test_lan_target_da, 6);
++      memcpy(hash_entry->param.sa, nat_test_lan_my_da, 6);
++      for (i=0; i<TOE_HW_TXQ_NUM; i++)
++      {
++              hash_entry->key.dport = htons(NAT_TEST_MAP_PORT_BASE + i);
++              if (i < 2)
++              {
++                      hash_entry->action.bits.dest_qid = i+2;
++              }
++              else
++              {
++                      hash_entry->action.bits.dest_qid = i;
++              }
++              hash_entry->action.bits.dest_qid += (cfg->lan_port==0) ? TOE_GMAC0_HW_TXQ0_QID : TOE_GMAC1_HW_TXQ0_QID;
++              hash_entry->param.Dport = NAT_TEST_SPORT;
++              hash_entry->param.Sport = NAT_TEST_DPORT;
++              hash_entry->param.da[5] = i;
++              for (j=0; j<4; j++)
++              {
++                      hash_entry->key.sip = (dip + i + j*0x100);
++                      hash_entry->key.dip = (NAT_TEST_WAN_IP);
++                      hash_entry->param.Sip = hash_entry->key.sip;
++                      hash_entry->param.Dip = sip + i + j*0x100;
++                      switch (j)
++                      {
++                      case 0:
++                              hash_entry->action.bits.pppoe = 0;
++                              hash_entry->param.pppoe = 0;
++                              hash_entry->action.bits.vlan = 0;
++                              hash_entry->param.vlan = 0;
++                              break;
++                      case 1:
++                              hash_entry->action.bits.pppoe = 2;
++                              hash_entry->param.pppoe = i+1;
++                              hash_entry->action.bits.vlan = 0;
++                              hash_entry->param.vlan = 0;
++                              break;
++                      case 2:
++                              hash_entry->action.bits.pppoe = 2;
++                              hash_entry->param.pppoe = i+1;
++                              hash_entry->action.bits.vlan = 2;
++                              hash_entry->param.vlan = i+5;
++                              break;
++                      case 3:
++                              hash_entry->action.bits.pppoe = 1;
++                              hash_entry->param.pppoe = i+1;
++                              hash_entry->action.bits.vlan = 1;
++                              hash_entry->param.vlan = i+5;
++                              break;
++                      }
++                      hash_entry->tmo.counter = hash_entry->tmo.interval = 0x7fff;
++                      hash_index = nat_build_keys(&hash_entry->key);
++                      nat_write_hash_entry(hash_index, hash_entry);
++                      hash_nat_enable_owner(hash_index);
++                      hash_validate_entry(hash_index); // Must last one, else HW Tx fast than SW
++              }
++      }
++}
++#endif        // SL351x_NAT_TEST_BY_SMARTBITS
++
++#endif // CONFIG_SL351x_NAT
++
+Index: linux-2.6.23.16/drivers/net/sl351x_proc.c
+===================================================================
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.23.16/drivers/net/sl351x_proc.c  2008-03-15 16:59:48.862910740 +0200
+@@ -0,0 +1,578 @@
++/****************************************************************************
++* Copyright 2006 Storlink Corp.  All rights reserved.
++*----------------------------------------------------------------------------
++* Name                        : sl351x_proc.c
++* Description :
++*             Handle Proc Routines for Storlink SL351x Platform
++*
++* History
++*
++*     Date            Writer          Description
++*----------------------------------------------------------------------------
++*     04/13/2006      Gary Chen       Create and implement
++*
++*
++****************************************************************************/
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/compiler.h>
++#include <linux/pci.h>
++#include <linux/init.h>
++#include <linux/ioport.h>
++#include <linux/netdevice.h>
++#include <linux/etherdevice.h>
++#include <linux/rtnetlink.h>
++#include <linux/delay.h>
++#include <linux/ethtool.h>
++#include <linux/mii.h>
++#include <linux/completion.h>
++#include <asm/hardware.h>
++#include <asm/io.h>
++#include <asm/irq.h>
++#include <asm/semaphore.h>
++#include <asm/arch/irqs.h>
++#include <asm/arch/it8712.h>
++#include <linux/mtd/kvctl.h>
++#include <linux/skbuff.h>
++#include <linux/if_ether.h>
++#include <linux/if_pppox.h>
++#include <linux/in.h>
++#include <linux/ip.h>
++#include <linux/tcp.h>
++#include <linux/ppp_defs.h>
++#ifdef CONFIG_NETFILTER
++#include <linux/netfilter_ipv4/ip_conntrack.h>
++#endif
++#include <linux/proc_fs.h>
++#include <linux/seq_file.h>
++#include <linux/percpu.h>
++#ifdef CONFIG_SYSCTL
++#include <linux/sysctl.h>
++#endif
++
++#define        MIDWAY
++#define        SL_LEPUS
++
++// #define PROC_DEBUG_MSG     1
++
++#include <asm/arch/sl2312.h>
++#include <asm/arch/sl351x_gmac.h>
++#include <asm/arch/sl351x_hash_cfg.h>
++#include <asm/arch/sl351x_nat_cfg.h>
++#include <asm/arch/sl351x_toe.h>
++
++#ifdef CONFIG_PROC_FS
++/*----------------------------------------------------------------------
++* Definition
++*----------------------------------------------------------------------*/
++#define       proc_printf                                     printk
++#define SL351x_GMAC_PROC_NAME         "sl351x_gmac"
++#define SL351x_NAT_PROC_NAME          "sl351x_nat"
++#define SL351x_TOE_PROC_NAME          "sl351x_toe"
++
++/*----------------------------------------------------------------------
++* Function Definition
++*----------------------------------------------------------------------*/
++#ifdef CONFIG_SL351x_NAT
++static int nat_ct_open(struct inode *inode, struct file *file);
++static void *nat_ct_seq_start(struct seq_file *s, loff_t *pos);
++static void nat_ct_seq_stop(struct seq_file *s, void *v);
++static void *nat_ct_seq_next(struct seq_file *s, void *v, loff_t *pos);
++static int nat_ct_seq_show(struct seq_file *s, void *v);
++#endif
++
++#ifdef CONFIG_SL351x_RXTOE
++static int toe_ct_open(struct inode *inode, struct file *file);
++static void *toe_ct_seq_start(struct seq_file *s, loff_t *pos);
++static void toe_ct_seq_stop(struct seq_file *s, void *v);
++static void *toe_ct_seq_next(struct seq_file *s, void *v, loff_t *pos);
++static int toe_ct_seq_show(struct seq_file *s, void *v);
++extern int sl351x_get_toe_conn_flag(int index);
++extern struct toe_conn * sl351x_get_toe_conn_info(int index);
++#endif
++
++static int gmac_ct_open(struct inode *inode, struct file *file);
++static void *gmac_ct_seq_start(struct seq_file *s, loff_t *pos);
++static void gmac_ct_seq_stop(struct seq_file *s, void *v);
++static void *gmac_ct_seq_next(struct seq_file *s, void *v, loff_t *pos);
++static int gmac_ct_seq_show(struct seq_file *s, void *v);
++
++
++/*----------------------------------------------------------------------
++* Data
++*----------------------------------------------------------------------*/
++#ifdef CONFIG_SYSCTL
++// static struct ctl_table_header *nat_ct_sysctl_header;
++#endif
++
++#ifdef CONFIG_SL351x_NAT
++static struct seq_operations nat_ct_seq_ops = {
++      .start = nat_ct_seq_start,
++      .next  = nat_ct_seq_next,
++      .stop  = nat_ct_seq_stop,
++      .show  = nat_ct_seq_show
++};
++
++static struct file_operations nat_file_ops= {
++      .owner   = THIS_MODULE,
++      .open    = nat_ct_open,
++      .read    = seq_read,
++      .llseek  = seq_lseek,
++      .release = seq_release
++};
++#endif // CONFIG_SL351x_NAT
++
++#ifdef CONFIG_SL351x_RXTOE
++static struct seq_operations toe_ct_seq_ops = {
++      .start = toe_ct_seq_start,
++      .next  = toe_ct_seq_next,
++      .stop  = toe_ct_seq_stop,
++      .show  = toe_ct_seq_show
++};
++
++static struct file_operations toe_file_ops= {
++      .owner   = THIS_MODULE,
++      .open    = toe_ct_open,
++      .read    = seq_read,
++      .llseek  = seq_lseek,
++      .release = seq_release
++};
++#endif
++
++static struct seq_operations gmac_ct_seq_ops = {
++      .start = gmac_ct_seq_start,
++      .next  = gmac_ct_seq_next,
++      .stop  = gmac_ct_seq_stop,
++      .show  = gmac_ct_seq_show
++};
++
++static struct file_operations gmac_file_ops= {
++      .owner   = THIS_MODULE,
++      .open    = gmac_ct_open,
++      .read    = seq_read,
++      .llseek  = seq_lseek,
++      .release = seq_release
++};
++
++#ifdef SL351x_GMAC_WORKAROUND
++extern u32 gmac_workaround_cnt[4];
++extern u32 gmac_short_frame_workaround_cnt[2];
++#ifdef CONFIG_SL351x_NAT
++      extern u32 sl351x_nat_workaround_cnt;
++#endif
++#endif
++/*----------------------------------------------------------------------
++* nat_ct_open
++*----------------------------------------------------------------------*/
++#ifdef CONFIG_SL351x_NAT
++static int nat_ct_open(struct inode *inode, struct file *file)
++{
++      return seq_open(file, &nat_ct_seq_ops);
++}
++#endif // CONFIG_SL351x_NAT
++/*----------------------------------------------------------------------
++* nat_ct_seq_start
++* find the first
++*----------------------------------------------------------------------*/
++#ifdef CONFIG_SL351x_NAT
++static void *nat_ct_seq_start(struct seq_file *s, loff_t *pos)
++{
++      int i;
++
++      // proc_printf("%s: *pos=%d\n", __func__, (int)*pos);
++      for (i=*pos; i<HASH_TOTAL_ENTRIES; i++)
++      {
++              if (hash_get_nat_owner_flag(i))
++              {
++                      *pos = i;
++                      return (void *)(i+1);
++              }
++      }
++      return NULL;
++}
++#endif // CONFIG_SL351x_NAT
++/*----------------------------------------------------------------------
++* nat_ct_seq_stop
++*----------------------------------------------------------------------*/
++#ifdef CONFIG_SL351x_NAT
++static void nat_ct_seq_stop(struct seq_file *s, void *v)
++{
++}
++#endif // CONFIG_SL351x_NAT
++/*----------------------------------------------------------------------
++* nat_ct_seq_next
++*----------------------------------------------------------------------*/
++#ifdef CONFIG_SL351x_NAT
++static void *nat_ct_seq_next(struct seq_file *s, void *v, loff_t *pos)
++{
++      int i;
++
++      // proc_printf("%s: *pos=%d\n", __func__, (int)*pos);
++      (*pos)++;
++      for (i=*pos; i<HASH_TOTAL_ENTRIES; i++)
++      {
++              if (hash_get_nat_owner_flag(i))
++              {
++                      *pos = i;
++                      return (void *)(i+1);
++              }
++      }
++      return NULL;
++}
++#endif // CONFIG_SL351x_NAT
++/*----------------------------------------------------------------------
++* nat_ct_seq_show
++*----------------------------------------------------------------------*/
++#ifdef CONFIG_SL351x_NAT
++static int nat_ct_seq_show(struct seq_file *s, void *v)
++{
++      int                             idx;
++      NAT_HASH_ENTRY_T        *nat_entry;
++      GRE_HASH_ENTRY_T        *gre_entry;
++
++      idx = (int)v;
++      if (idx<=0 || idx >HASH_TOTAL_ENTRIES)
++              return -ENOSPC;
++
++      idx--;
++      nat_entry = (NAT_HASH_ENTRY_T *)&hash_tables[idx];
++      gre_entry = (GRE_HASH_ENTRY_T *)nat_entry;
++      if (nat_entry->key.ip_protocol == IPPROTO_GRE)
++      {
++              if (seq_printf(s, "%4d: KEY MAC-%d [%d] %u.%u.%u.%u [%u]-->%u.%u.%u.%u\n",
++                                      idx, gre_entry->key.port_id, gre_entry->key.ip_protocol,
++                                      HIPQUAD(gre_entry->key.sip), ntohs(gre_entry->key.call_id),
++                                      HIPQUAD(gre_entry->key.dip)))
++                      return -ENOSPC;
++              if (seq_printf(s, "      PARAMETER: %u.%u.%u.%u -->%u.%u.%u.%u [%u] Timeout:%ds\n",
++                                      HIPQUAD(gre_entry->param.Sip),
++                                      HIPQUAD(gre_entry->param.Dip), gre_entry->param.Dport,
++                                      gre_entry->tmo.counter))
++                      return -ENOSPC;
++      }
++      else
++      {
++              if (seq_printf(s, "%4d: KEY MAC-%d [%d] %u.%u.%u.%u [%u]-->%u.%u.%u.%u [%u]\n",
++                                      idx, nat_entry->key.port_id, nat_entry->key.ip_protocol,
++                                      HIPQUAD(nat_entry->key.sip), ntohs(nat_entry->key.sport),
++                                      HIPQUAD(nat_entry->key.dip), ntohs(nat_entry->key.dport)))
++                      return -ENOSPC;
++              if (seq_printf(s, "      PARAMETER: %u.%u.%u.%u [%u]-->%u.%u.%u.%u [%u] Timeout:%ds\n",
++                                      HIPQUAD(nat_entry->param.Sip), nat_entry->param.Sport,
++                                      HIPQUAD(nat_entry->param.Dip), nat_entry->param.Dport,
++                                      nat_entry->tmo.counter))
++                      return -ENOSPC;
++      }
++      return 0;
++}
++#endif // CONFIG_SL351x_NAT
++
++/*----------------------------------------------------------------------
++* toe_ct_open
++*----------------------------------------------------------------------*/
++#ifdef CONFIG_SL351x_RXTOE
++static int toe_ct_open(struct inode *inode, struct file *file)
++{
++      return seq_open(file, &toe_ct_seq_ops);
++}
++#endif
++/*----------------------------------------------------------------------
++* toe_ct_seq_start
++* find the first
++*----------------------------------------------------------------------*/
++#ifdef CONFIG_SL351x_RXTOE
++static void *toe_ct_seq_start(struct seq_file *s, loff_t *pos)
++{
++      int i;
++
++      // proc_printf("%s: *pos=%d\n", __func__, (int)*pos);
++      for (i=*pos; i<TOE_TOE_QUEUE_NUM; i++)
++      {
++              if (sl351x_get_toe_conn_flag(i))
++              {
++                      *pos = i;
++                      return (void *)(i+1);
++              }
++      }
++      return NULL;
++}
++#endif
++/*----------------------------------------------------------------------
++* toe_ct_seq_stop
++*----------------------------------------------------------------------*/
++#ifdef CONFIG_SL351x_RXTOE
++static void toe_ct_seq_stop(struct seq_file *s, void *v)
++{
++}
++#endif
++/*----------------------------------------------------------------------
++* toe_ct_seq_next
++*----------------------------------------------------------------------*/
++#ifdef CONFIG_SL351x_RXTOE
++static void *toe_ct_seq_next(struct seq_file *s, void *v, loff_t *pos)
++{
++      int i;
++
++      // proc_printf("%s: *pos=%d\n", __func__, (int)*pos);
++      (*pos)++;
++      for (i=*pos; i<TOE_TOE_QUEUE_NUM; i++)
++      {
++              if (sl351x_get_toe_conn_flag(i))
++              {
++                      *pos = i;
++                      return (void *)(i+1);
++              }
++      }
++      return NULL;
++}
++#endif
++/*----------------------------------------------------------------------
++* toe_ct_seq_show
++*----------------------------------------------------------------------*/
++#ifdef CONFIG_SL351x_RXTOE
++static int toe_ct_seq_show(struct seq_file *s, void *v)
++{
++      int                             idx;
++      struct toe_conn         *toe_entry;
++
++      idx = (int)v;
++      if (idx<=0 || idx >TOE_TOE_QUEUE_NUM)
++              return -ENOSPC;
++
++      idx--;
++      toe_entry = (struct toe_conn *)sl351x_get_toe_conn_info(idx);
++      if (!toe_entry)
++              return -ENOSPC;
++
++      if (seq_printf(s, "%4d: Qid %d MAC-%d TCP %u.%u.%u.%u [%u]-->%u.%u.%u.%u [%u]\n",
++                              idx, toe_entry->qid, toe_entry->gmac->port_id,
++                              NIPQUAD(toe_entry->saddr[0]), ntohs(toe_entry->source),
++                              NIPQUAD(toe_entry->daddr[0]), ntohs(toe_entry->dest)))
++                      return -ENOSPC;
++      return 0;
++}
++#endif
++/*----------------------------------------------------------------------
++* gmac_ct_open
++*----------------------------------------------------------------------*/
++static int gmac_ct_open(struct inode *inode, struct file *file)
++{
++      return seq_open(file, &gmac_ct_seq_ops);
++}
++
++/*----------------------------------------------------------------------
++* gmac_ct_seq_start
++* find the first
++*----------------------------------------------------------------------*/
++static void *gmac_ct_seq_start(struct seq_file *s, loff_t *pos)
++{
++      int i;
++      i = (int)*pos + 1;;
++
++      if (i > 9)
++              return NULL;
++      else
++              return (void *)i;
++}
++
++/*----------------------------------------------------------------------
++* gmac_ct_seq_stop
++*----------------------------------------------------------------------*/
++static void gmac_ct_seq_stop(struct seq_file *s, void *v)
++{
++}
++
++/*----------------------------------------------------------------------
++* gmac_ct_seq_next
++*----------------------------------------------------------------------*/
++static void *gmac_ct_seq_next(struct seq_file *s, void *v, loff_t *pos)
++{
++      int i;
++
++      // proc_printf("%s: *pos=%d\n", __func__, (int)*pos);
++
++      (*pos)++;
++      i = (int)*pos + 1;;
++
++      if (i > 9)
++              return NULL;
++      else
++              return (void *)i;
++}
++
++/*----------------------------------------------------------------------
++* seq_dm_long
++*----------------------------------------------------------------------*/
++static void seq_dm_long(struct seq_file *s, u32 location, int length)
++{
++      u32             *start_p, *curr_p, *end_p;
++      u32             *datap, data;
++      int             i;
++
++      //if (length > 1024)
++      //      length = 1024;
++
++      start_p = (u32 *)location;
++      end_p = (u32 *)location + length;
++      curr_p = (u32 *)((u32)location & 0xfffffff0);
++      datap = (u32 *)location;
++      while (curr_p < end_p)
++      {
++              cond_resched();
++              seq_printf(s, "0x%08x: ",(u32)curr_p & 0xfffffff0);
++              for (i=0; i<4; i++)
++              {
++                      if (curr_p < start_p || curr_p >= end_p)
++               seq_printf(s, "         ");
++                      else
++                      {
++                              data = *datap;
++                              seq_printf(s, "%08X ", data);
++                      }
++                      if (i==1)
++              seq_printf(s, "- ");
++
++                      curr_p++;
++                      datap++;
++              }
++        seq_printf(s, "\n");
++      }
++}
++
++/*----------------------------------------------------------------------
++* gmac_ct_seq_show
++*----------------------------------------------------------------------*/
++static int gmac_ct_seq_show(struct seq_file *s, void *v)
++{
++      switch ((int)v)
++      {
++              case 1:
++                      seq_printf(s, "\nGMAC Global Registers\n");
++                      seq_dm_long(s, TOE_GLOBAL_BASE, 32);
++                      break;
++              case 2:
++                      seq_printf(s, "\nGMAC Non-TOE Queue Header\n");
++                      seq_dm_long(s, TOE_NONTOE_QUE_HDR_BASE, 12);
++                      break;
++              case 3:
++                      seq_printf(s, "\nGMAC TOE Queue Header\n");
++                      seq_dm_long(s, TOE_TOE_QUE_HDR_BASE, 12);
++                      break;
++              case 4:
++                      seq_printf(s, "\nGMAC-0 DMA Registers\n");
++                      seq_dm_long(s, TOE_GMAC0_DMA_BASE, 52);
++                      break;
++              case 5:
++                      seq_printf(s, "\nGMAC-0 Registers\n");
++                      seq_dm_long(s, TOE_GMAC0_BASE, 32);
++                      break;
++              case 6:
++                      seq_printf(s, "\nGMAC-1 DMA Registers\n");
++                      seq_dm_long(s, TOE_GMAC1_DMA_BASE, 52);
++                      break;
++              case 7:
++                      seq_printf(s, "\nGMAC-1 Registers\n");
++                      seq_dm_long(s, TOE_GMAC1_BASE, 32);
++                      break;
++              case 8:
++                      seq_printf(s, "\nGLOBAL Registers\n");
++                      seq_dm_long(s, GMAC_GLOBAL_BASE_ADDR, 16);
++                      break;
++              case 9:
++#ifdef SL351x_GMAC_WORKAROUND
++                      seq_printf(s, "\nGMAC-0 Rx/Tx/Short Workaround: %u, %u, %u\n", gmac_workaround_cnt[0], gmac_workaround_cnt[1], gmac_short_frame_workaround_cnt[0]);
++                      seq_printf(s, "GMAC-1 Rx/Tx/Short Workaround: %u, %u, %u\n", gmac_workaround_cnt[2], gmac_workaround_cnt[3], gmac_short_frame_workaround_cnt[1]);
++#ifdef CONFIG_SL351x_NAT
++                      seq_printf(s, "NAT Workaround: %u\n", sl351x_nat_workaround_cnt);
++#endif
++#endif
++                      break;
++              default:
++                      return -ENOSPC;
++      }
++      return 0;
++}
++
++/*----------------------------------------------------------------------
++* init
++*----------------------------------------------------------------------*/
++static int __init init(void)
++{
++      struct proc_dir_entry *proc_gmac=NULL;
++
++#ifdef CONFIG_SL351x_NAT
++      struct proc_dir_entry *proc_nat=NULL;
++#endif
++
++#ifdef CONFIG_SL351x_RXTOE
++      struct proc_dir_entry *proc_toe=NULL;
++#endif
++
++#ifdef CONFIG_SYSCTL
++      // nat_ct_sysctl_header = NULL;
++#endif
++      proc_gmac = proc_net_fops_create(SL351x_GMAC_PROC_NAME, 0440, &gmac_file_ops);
++      if (!proc_gmac) goto init_bad;
++
++#ifdef CONFIG_SL351x_NAT
++      proc_nat = proc_net_fops_create(SL351x_NAT_PROC_NAME, 0440, &nat_file_ops);
++      if (!proc_nat) goto init_bad;
++#endif // CONFIG_SL351x_NAT
++
++#ifdef CONFIG_SL351x_RXTOE
++      proc_toe = proc_net_fops_create(SL351x_TOE_PROC_NAME, 0440, &toe_file_ops);
++      if (!proc_toe) goto init_bad;
++#endif
++
++#ifdef CONFIG_SYSCTL
++      // nat_ct_sysctl_header = register_sysctl_table(nat_ct_net_table, 0);
++      // if (!nat_ct_sysctl_header) goto init_bad;
++#endif
++
++      return 0;
++
++init_bad:
++      if (proc_gmac) proc_net_remove(SL351x_GMAC_PROC_NAME);
++
++#ifdef CONFIG_SL351x_NAT
++      if (proc_nat) proc_net_remove(SL351x_NAT_PROC_NAME);
++#endif
++
++#ifdef CONFIG_SL351x_RXTOE
++      if (proc_toe) proc_net_remove(SL351x_NAT_PROC_NAME);
++#endif
++
++#ifdef CONFIG_SYSCTL
++      // if (nat_ct_sysctl_header) unregister_sysctl_table(nat_ct_sysctl_header);
++#endif
++      proc_printf("SL351x NAT Proc: can't create proc or register sysctl.\n");
++      return -ENOMEM;
++}
++
++/*----------------------------------------------------------------------
++* fini
++*----------------------------------------------------------------------*/
++static void __exit fini(void)
++{
++      proc_net_remove(SL351x_GMAC_PROC_NAME);
++
++#ifdef CONFIG_SL351x_NAT
++      proc_net_remove(SL351x_NAT_PROC_NAME);
++#endif
++
++#ifdef CONFIG_SL351x_RXTOE
++      proc_net_remove(SL351x_TOE_PROC_NAME);
++#endif
++
++#ifdef CONFIG_SYSCTL
++      // unregister_sysctl_table(nat_ct_sysctl_header);
++#endif
++}
++
++/*----------------------------------------------------------------------
++* module
++*----------------------------------------------------------------------*/
++module_init(init);
++module_exit(fini);
++
++#endif        // CONFIG_PROC_FS
+Index: linux-2.6.23.16/drivers/net/sl351x_toe.c
+===================================================================
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.23.16/drivers/net/sl351x_toe.c   2008-03-15 16:57:25.854761029 +0200
+@@ -0,0 +1,1083 @@
++/**************************************************************************
++* Copyright 2006 StorLink Semiconductors, Inc.  All rights reserved.
++*--------------------------------------------------------------------------
++* Name                        : sl351x_toe.c
++* Description :
++*             Provide TOE routines for SL351x
++*
++* History
++*
++*     Date            Writer          Description
++*----------------------------------------------------------------------------
++*                             Xiaochong
++*
++****************************************************************************/
++
++#include <linux/pci.h>
++#include <linux/ip.h>
++#include <linux/ipv6.h>
++#include <linux/tcp.h>
++#include <linux/slab.h>
++#include <linux/etherdevice.h>
++#include <asm/io.h>
++#include <linux/sysctl_storlink.h>
++#include <net/tcp.h>
++#include <linux/if_ether.h>
++#include <asm/arch/sl351x_gmac.h>
++#include <asm/arch/sl351x_toe.h>
++#include <asm/arch/sl351x_hash_cfg.h>
++#include <asm/arch/sl351x_nat_cfg.h>
++
++static int in_toe_isr;
++static int toe_initialized=0;
++
++static struct toe_conn        toe_connections[TOE_TOE_QUEUE_NUM];
++EXPORT_SYMBOL(toe_connections);
++static __u32 toe_connection_bits[TOE_TOE_QUEUE_NUM/32] __attribute__ ((aligned(16)));
++struct sk_buff* gen_pure_ack(struct toe_conn* connection, TOE_QHDR_T* toe_qhdr, INTR_QHDR_T *intr_curr_desc);
++
++extern struct storlink_sysctl storlink_ctl;
++extern TOE_INFO_T toe_private_data;
++extern spinlock_t gmac_fq_lock;
++extern void mac_write_dma_reg(int mac, unsigned int offset, u32 data);
++extern int mac_set_rule_reg(int mac, int rule, int enabled, u32 reg0, u32 reg1, u32 reg2);
++extern int hash_add_toe_entry(HASH_ENTRY_T *entry);
++extern void toe_gmac_fill_free_q(void);
++
++#define _DEBUG_SKB_           1
++#ifdef _DEBUG_SKB_
++/*---------------------------------------------------------------------------
++ * _debug_skb
++ *-------------------------------------------------------------------------*/
++static inline void _debug_skb(struct sk_buff *skb, GMAC_RXDESC_T *toe_curr_desc, u32 data)
++{
++      if ((u32)skb < 0x1000)
++      {
++              printk("%s skb=%x\n", __func__, (u32)skb);
++              while(1);
++      }
++      REG32(__va(toe_curr_desc->word2.buf_adr)-SKB_RESERVE_BYTES) = data;
++}
++#else
++#define _debug_skb(x, y, z)
++#endif
++
++/*---------------------------------------------------------------------------
++ * get_connection_seq_num
++ *-------------------------------------------------------------------------*/
++u32 get_connection_seq_num(unsigned short qid)
++{
++      TOE_QHDR_T      *toe_qhdr;
++
++      toe_qhdr = (TOE_QHDR_T*)TOE_TOE_QUE_HDR_BASE;
++      toe_qhdr += qid;
++      return (u32)toe_qhdr->word3.seq_num;
++}
++EXPORT_SYMBOL(get_connection_seq_num);
++
++/*---------------------------------------------------------------------------
++ * get_connection_ack_num
++ *-------------------------------------------------------------------------*/
++u32 get_connection_ack_num(unsigned short qid)
++{
++      TOE_QHDR_T      *toe_qhdr;
++
++      toe_qhdr = (TOE_QHDR_T*)TOE_TOE_QUE_HDR_BASE;
++      toe_qhdr += qid;
++      return (u32)toe_qhdr->word4.ack_num;
++}
++EXPORT_SYMBOL(get_connection_ack_num);
++
++/*---------------------------------------------------------------------------
++ * dump_toe_qhdr
++ *-------------------------------------------------------------------------*/
++void dump_toe_qhdr(TOE_QHDR_T *toe_qhdr)
++{
++      printk("TOE w1 %x, w2 %x, w3 %x\n", toe_qhdr->word1.bits32,
++              toe_qhdr->word2.bits32, toe_qhdr->word3.bits32);
++      printk("w4 %x, w5 %x, w6 %x\n", toe_qhdr->word4.bits32,
++              toe_qhdr->word5.bits32, toe_qhdr->word6.bits32);
++}
++
++/*---------------------------------------------------------------------------
++ * dump_intrq_desc
++ *-------------------------------------------------------------------------*/
++void dump_intrq_desc(INTR_QHDR_T *intr_curr_desc)
++{
++      printk("INTR w0 %x, w1 %x, seq %x\n", intr_curr_desc->word0.bits32,
++              intr_curr_desc->word1.bits32, intr_curr_desc->word2.bits32);
++      printk("ack %x, w4 %x\n", intr_curr_desc->word3.bits32,
++              intr_curr_desc->word4.bits32);
++}
++
++/*---------------------------------------------------------------------------
++ * This routine will initialize a TOE matching rule
++ * called by SL351x GMAC driver.
++ *-------------------------------------------------------------------------*/
++void sl351x_toe_init(void)
++{
++      GMAC_MRxCR0_T   mrxcr0;
++      GMAC_MRxCR1_T   mrxcr1;
++      GMAC_MRxCR2_T   mrxcr2;
++      int     rule, rc;
++
++      if (toe_initialized)
++              return;
++
++      toe_initialized = 1;
++
++#ifndef CONFIG_SL351x_NAT
++      mrxcr0.bits32 = 0;
++      mrxcr1.bits32 = 0;
++      mrxcr2.bits32 = 0;
++      mrxcr0.bits.l3 = 1;
++      mrxcr0.bits.l4 = 1;
++      mrxcr1.bits.sip = 1;
++      mrxcr1.bits.dip = 1;
++      mrxcr1.bits.l4_byte0_15 = 0x0f;
++      mrxcr0.bits.sprx = 1;
++      rule = 0;
++      rc = mac_set_rule_reg(0, rule, 1, mrxcr0.bits32, mrxcr1.bits32,
++                                              mrxcr2.bits32);
++      if (rc<0) {
++              printk("%s::Set MAC 0 rule fail!\n", __func__);
++      }
++      rc = mac_set_rule_reg(1, rule, 1, mrxcr0.bits32, mrxcr1.bits32,
++                                              mrxcr2.bits32);
++      if (rc<0) {
++              printk("%s::Set MAC 1 rule fail!\n", __func__);
++      }
++#endif // CONFIG_SL351x_NAT
++}
++
++/*---------------------------------------------------------------------------
++ * dump_intrq_desc
++ * assign an interrupt queue number to a give tcp queue
++ *-------------------------------------------------------------------------*/
++int get_interrupt_queue_id(int tcp_qid)
++{
++      return (int)(tcp_qid & 0x0003);
++}
++
++/*---------------------------------------------------------------------------
++ * reset_connection_index
++ * reset the connection bit by given index
++ *-------------------------------------------------------------------------*/
++void reset_connection_index(__u8 index)
++{
++      __u32 mask = ~(0xffffffff & (1<< (index&0x1f)));
++      toe_connection_bits[index>>5] = toe_connection_bits[index>>5] & mask;
++}
++
++/*---------------------------------------------------------------------------
++ * update_timer
++ *-------------------------------------------------------------------------*/
++void update_timer(struct toe_conn* connection)
++{
++//    if (time_before(jiffies, connection->last_rx_jiffies+3))
++//    if ((jiffies + 0xffffffff - connection->last_rx_jiffies) & 0x3)
++//    if (connection->last_rx_jiffies > jiffies)
++//            printk("%s::jif %g, last_rx_jif %g\n", __func__, jiffies, connection->last_rx_jiffies);
++/*    if ((long)(jiffies + 2)< 3) { // overflow...
++              printk("%s::jiffies %x\n", __func__, jiffies);
++      } */
++//    if ((long)(jiffies - connection->last_rx_jiffies)< 2)
++//            return;
++      connection->last_rx_jiffies = jiffies;
++      // gary chen mod_timer(&connection->rx_timer, jiffies+2);
++      connection->rx_timer.expires = jiffies + 2;
++      add_timer(&connection->rx_timer);
++//    printk("%s::nt %x, lj %x\n", __func__, (jiffies+2), connection->last_rx_jiffies);
++}
++
++/*---------------------------------------------------------------------------
++ * gen_pure_ack
++ *-------------------------------------------------------------------------*/
++struct sk_buff* gen_pure_ack(struct toe_conn* connection, TOE_QHDR_T* toe_qhdr,
++INTR_QHDR_T *intr_curr_desc)
++{
++      struct sk_buff  *skb;
++      struct iphdr    *ip_hdr;
++      struct tcphdr   *tcp_hdr;
++      struct ethhdr   *eth_hdr;
++
++      if ((skb= dev_alloc_skb(RX_BUF_SIZE))==NULL) {
++              printk("%s::alloc pure ack fail!\n", __func__);
++              return NULL;
++      }
++      skb_reserve(skb, RX_INSERT_BYTES);
++      memset(skb->data, 0, 60);
++
++      eth_hdr = (struct ethhdr*)&(skb->data[0]);
++      memcpy(eth_hdr, &connection->l2_hdr, sizeof(struct ethhdr));
++
++      ip_hdr = (struct iphdr*)&(skb->data[14]);
++      ip_hdr->version = connection->ip_ver;
++      ip_hdr->ihl = 20>>2;
++      ip_hdr->tot_len = ntohs(40);
++      ip_hdr->frag_off = htons(IP_DF);
++      ip_hdr->ttl = 128;
++      ip_hdr->protocol = 0x06;
++      ip_hdr->saddr = connection->saddr[0];
++      ip_hdr->daddr = connection->daddr[0];
++//    printk("%s ip sa %x, da %x\n",
++//            __func__, ntohl(ip_hdr->saddr), ntohl(ip_hdr->daddr));
++
++      tcp_hdr = (struct tcphdr*)&(skb->data[34]);
++      tcp_hdr->source = connection->source;
++      tcp_hdr->dest = connection->dest;
++      if (intr_curr_desc) {
++              tcp_hdr->seq = htonl(intr_curr_desc->word2.seq_num);
++              tcp_hdr->ack_seq = htonl(intr_curr_desc->word3.ack_num);
++              tcp_hdr->window = htons(intr_curr_desc->word0.bits.win_size);
++      } else {
++              tcp_hdr->seq = htonl(toe_qhdr->word3.seq_num);
++              tcp_hdr->ack_seq = htonl(toe_qhdr->word4.ack_num);
++              tcp_hdr->window = htons(toe_qhdr->word6.bits.WinSize);
++      }
++      tcp_hdr->ack = 1;
++      tcp_hdr->doff = 20 >> 2;
++#if 0
++      if (!intr_curr_desc) {
++              unsigned char byte;
++              for (i=0; i<20; i++) {
++                      byte = skb->data[34+i];
++                      printk("%x ", byte);
++              }
++              printk("\n");
++      }
++#endif
++      TCP_SKB_CB(skb)->connection = connection;
++      return skb;
++}
++
++/*---------------------------------------------------------------------------
++ * connection_rx_timer
++ *-------------------------------------------------------------------------*/
++void connection_rx_timer(unsigned long *data)
++{
++      struct toe_conn *connection = (struct toe_conn*)data;
++      unsigned int    tcp_qid, toeq_wptr;
++      unsigned int    pkt_size, desc_count;
++      struct sk_buff  *skb;
++      GMAC_RXDESC_T   *toe_curr_desc;
++      TOE_QHDR_T      *toe_qhdr;
++      struct net_device       *dev;
++      unsigned long   conn_flags;
++      DMA_RWPTR_T             toeq_rwptr;
++      unsigned short  timeout_descs;
++
++      if (in_toe_isr)
++              printk("%s::in_toe_isr=%d!\n", __func__, in_toe_isr);
++
++      if (connection) {
++              /* should we disable gmac interrupt first? */
++              if (!connection->gmac)
++                      printk("%s::conn gmac %x!\n", __func__, (u32)connection->gmac);
++              local_irq_save(conn_flags);
++              if (!spin_trylock(&connection->conn_lock)) {
++                      local_irq_restore(conn_flags);
++                      // timer should be updated by the toeq isr. So no need to update here.
++                      printk("%s::conn_lock is held by ISR!\n", __func__);
++                      return;
++              }
++              disable_irq(connection->gmac->irq);
++
++              /* disable hash entry and get toeq desc. */
++              hash_set_valid_flag(connection->hash_entry_index, 0);
++              do{} while(0);  /* wait until HW finish */
++
++              dev = connection->dev;
++              if (!dev)
++                      printk("%s::conn dev NULL!\n", __func__);
++              tcp_qid = connection->qid;
++              toe_qhdr = (TOE_QHDR_T *)(TOE_TOE_QUE_HDR_BASE +
++                            tcp_qid * sizeof(TOE_QHDR_T));
++              toeq_rwptr.bits32 = readl(&toe_qhdr->word1);
++              toeq_wptr = toe_qhdr->word1.bits.wptr;
++              timeout_descs = toeq_wptr - toeq_rwptr.bits.rptr;
++
++              if (toeq_rwptr.bits.rptr == toeq_wptr) {
++                      if (toe_qhdr->word5.bits32) {
++                              // shall we check toe_qhdr->word2.bits?
++                              skb = gen_pure_ack(connection, toe_qhdr, (INTR_QHDR_T *)NULL);
++                              skb_put(skb, 54);
++                              skb->dev = connection->dev;
++                              skb->ip_summed = CHECKSUM_UNNECESSARY;
++                              skb->protocol = eth_type_trans(skb, connection->dev);
++                              netif_rx(skb);
++                              connection->dev->last_rx = jiffies;
++                      }
++              } else {
++                      while (toeq_rwptr.bits.rptr != toeq_rwptr.bits.wptr) {
++                              /* we just simply send those packets to tcp? */
++                              toe_curr_desc = (GMAC_RXDESC_T*)(toe_private_data.toe_desc_base[tcp_qid]
++                                      + toeq_rwptr.bits.rptr * sizeof(GMAC_RXDESC_T));
++                              connection->curr_desc = toe_curr_desc;
++                              if (toe_curr_desc->word3.bits.ctrl_flag) {
++                                      printk("%s::ctrl flag! %x, conn rptr %d, to %d, jif %x, conn_jif %x\n",
++                                              __func__, toe_curr_desc->word3.bits32,
++                                              connection->toeq_rwptr.bits.rptr, timeout_descs,
++                                              (u32)jiffies, (u32)connection->last_rx_jiffies);
++                              }
++                              desc_count = toe_curr_desc->word0.bits.desc_count;
++                              pkt_size = toe_curr_desc->word1.bits.byte_count;
++                              consistent_sync((void*)__va(toe_curr_desc->word2.buf_adr), pkt_size,
++                                      PCI_DMA_FROMDEVICE);
++                              skb = (struct sk_buff*)(REG32(__va(toe_curr_desc->word2.buf_adr)-
++                                      SKB_RESERVE_BYTES));
++                              _debug_skb(skb, (GMAC_RXDESC_T *)toe_curr_desc, 0x02);
++                              connection->curr_rx_skb = skb;
++                              skb_reserve(skb, RX_INSERT_BYTES);
++                              skb_put(skb, pkt_size);
++                              skb->dev = dev;
++                              skb->protocol = eth_type_trans(skb, dev);
++                              {
++                                      struct iphdr* ip_hdr = (struct iphdr*)&(skb->data[0]);
++                                      if (toe_curr_desc->word3.bits.ctrl_flag)
++                                              printk("%s::ip id %x\n", __func__, ntohs(ip_hdr->id));
++                              }
++                              skb->ip_summed = CHECKSUM_UNNECESSARY;
++
++                              netif_rx(skb);
++                              dev->last_rx = jiffies;
++#if 0
++                              if ((skb = dev_alloc_skb(RX_BUF_SIZE)) == NULL) {
++                                      printk("%s::alloc buf fail!\n", __func__);
++                              }
++                              *(unsigned int*)(skb->data) = (unsigned int)skb;
++                              connection->curr_rx_skb = skb;
++                              skb_reserve(skb, SKB_RESERVE_BYTES);
++                              spin_lock_irqsave(&connection->gmac->rx_mutex, flags);
++                              fq_rwptr.bits32 = readl(TOE_GLOBAL_BASE + GLOBAL_SWFQ_RWPTR_REG);
++                              if (toe_private_data.fq_rx_rwptr.bits.wptr != fq_rwptr.bits.wptr) {
++                                      mac_stop_txdma((struct net_device*)connection->dev);
++                                      spin_unlock_irqrestore(&connection->gmac->rx_mutex, flags);
++                                      while(1);
++                              }
++                              fq_desc = (GMAC_RXDESC_T*)toe_private_data.swfq_desc_base + fq_rwptr.bits.wptr;
++                              fq_desc->word2.buf_adr = (unsigned int)__pa(skb->data);
++                              fq_rwptr.bits.wptr = RWPTR_ADVANCE_ONE(fq_rwptr.bits.wptr, TOE_SW_FREEQ_DESC_NUM);
++                              SET_WPTR(TOE_GLOBAL_BASE+GLOBAL_SWFQ_RWPTR_REG, fq_rwptr.bits.wptr);
++                              toe_private_data.fq_rx_rwptr.bits32 = fq_rwptr.bits32;
++                              spin_unlock_irqrestore(&connection->gmac->rx_mutex, flags);
++#endif
++//                            spin_lock_irqsave(&connection->gmac->rx_mutex, flags);
++                              toeq_rwptr.bits.rptr = RWPTR_ADVANCE_ONE(toeq_rwptr.bits.rptr, TOE_TOE_DESC_NUM);
++                              SET_RPTR(&toe_qhdr->word1, toeq_rwptr.bits.rptr);
++//                            spin_unlock_irqrestore(&connection->gmac->rx_mutex, flags);
++                              connection->toeq_rwptr.bits32 = toeq_rwptr.bits32;
++                      }
++                      toeq_rwptr.bits32 = readl(&toe_qhdr->word1);
++//                    toe_gmac_fill_free_q();
++              }
++              connection->last_rx_jiffies = jiffies;
++              if (connection->status != TCP_CONN_CLOSED)
++                      mod_timer(&connection->rx_timer, jiffies+2);
++              if (connection->status != TCP_CONN_ESTABLISHED)
++                      printk("%s::conn status %x\n", __func__, connection->status);
++              hash_set_valid_flag(connection->hash_entry_index, 1);
++              enable_irq(connection->gmac->irq);
++              // Gary Chen spin_unlock_irqrestore(&connection->conn_lock, conn_flags);
++      }
++}
++
++/*---------------------------------------------------------------------------
++ * free_toeq_descs
++ *-------------------------------------------------------------------------*/
++void free_toeq_descs(int qid, TOE_INFO_T *toe)
++{
++      void    *desc_ptr;
++
++      desc_ptr = (void*)toe->toe_desc_base[qid];
++      pci_free_consistent(NULL, TOE_TOE_DESC_NUM*sizeof(GMAC_RXDESC_T), desc_ptr,
++         (dma_addr_t)toe->toe_desc_base_dma[qid]);
++      toe->toe_desc_base[qid] = 0;
++}
++
++/*---------------------------------------------------------------------------
++ * set_toeq_hdr
++ *-------------------------------------------------------------------------*/
++void set_toeq_hdr(struct toe_conn*    connection, TOE_INFO_T* toe, struct net_device *dev)
++{
++      volatile TOE_QHDR_T     *toe_qhdr;
++      volatile unsigned int   toeq_wptr; // toeq_rptr
++      volatile GMAC_RXDESC_T  *toe_curr_desc;
++      struct sk_buff  *skb;
++      unsigned int    pkt_size;
++      DMA_RWPTR_T     toeq_rwptr;
++
++      if (connection->status == TCP_CONN_CLOSING) {
++              connection->status = TCP_CONN_CLOSED;
++              hash_set_valid_flag(connection->hash_entry_index, 0);
++              // remove timer first.
++              // del_timer_sync(&(connection->rx_timer));
++              // check if any queued frames last time.
++              toe_qhdr = (volatile TOE_QHDR_T*)TOE_TOE_QUE_HDR_BASE;
++              toe_qhdr += connection->qid;
++              toeq_rwptr.bits32 = readl(&toe_qhdr->word1);
++
++              //toeq_rptr = toe_qhdr->word1.bits.rptr;
++              toeq_wptr = toe_qhdr->word1.bits.wptr;
++              while (toeq_rwptr.bits.rptr != toeq_wptr) {
++                      printk("%s::pending frames in TOE Queue before closing!\n", __func__);
++                      toe_curr_desc = (GMAC_RXDESC_T*)(toe->toe_desc_base[connection->qid] +
++                              toe_qhdr->word1.bits.rptr*sizeof(GMAC_RXDESC_T));
++                      connection->curr_desc = (GMAC_RXDESC_T *)toe_curr_desc;
++                      pkt_size = toe_curr_desc->word1.bits.byte_count;
++                      consistent_sync((void*)__va(toe_curr_desc->word2.buf_adr), pkt_size,
++                              PCI_DMA_FROMDEVICE);
++                      skb = (struct sk_buff*)(REG32(__va(toe_curr_desc->word2.buf_adr) -
++                              SKB_RESERVE_BYTES));
++                      _debug_skb(skb, (GMAC_RXDESC_T *)toe_curr_desc, 0x03);
++                      connection->curr_rx_skb = skb;
++                      skb_reserve(skb, RX_INSERT_BYTES);
++                      skb_put(skb, pkt_size);
++                      skb->dev = connection->dev;
++                      skb->protocol = eth_type_trans(skb, connection->dev);
++                      skb->ip_summed = CHECKSUM_UNNECESSARY;
++                      netif_rx(skb);
++                      connection->dev->last_rx = jiffies;
++
++                      toeq_rwptr.bits.rptr = RWPTR_ADVANCE_ONE(toeq_rwptr.bits.rptr, TOE_TOE_DESC_NUM);
++                      SET_RPTR(&toe_qhdr->word1, toeq_rwptr.bits.rptr);
++              }
++              free_toeq_descs(connection->qid, toe);
++              // shall we re-fill free queue?
++
++              reset_connection_index(connection->qid);
++              //memset(connection, 0, sizeof(struct toe_conn));
++              printk(" del timer and close connection %x, qid %d\n", (u32)connection, connection->qid);
++              return;
++      }
++      /* enable or setup toe queue header */
++      if (connection->status == TCP_CONN_CONNECTING && storlink_ctl.rx_max_pktsize) {
++              volatile TOE_QHDR_T     *qhdr;
++              int iq_id;
++              connection->status = TCP_CONN_ESTABLISHED;
++              qhdr = (volatile TOE_QHDR_T*)((unsigned int)TOE_TOE_QUE_HDR_BASE +
++                             connection->qid * sizeof(TOE_QHDR_T));
++
++              iq_id = get_interrupt_queue_id(connection->qid);
++              connection->dev = dev;
++              connection->gmac = dev->priv;
++              connection->toeq_rwptr.bits32 = 0;
++
++//            qhdr->word6.bits.iq_num = iq_id;
++              qhdr->word6.bits.MaxPktSize = (connection->max_pktsize)>>2; // in word.
++              qhdr->word7.bits.AckThreshold = connection->ack_threshold;
++              qhdr->word7.bits.SeqThreshold = connection->seq_threshold;
++
++              // init timer.
++#if 1
++              init_timer(&connection->rx_timer);
++              connection->rx_timer.expires = jiffies + 5;
++              connection->rx_timer.data = (unsigned long)connection;
++              connection->rx_timer.function = (void *)&connection_rx_timer;
++              add_timer(&connection->rx_timer);
++              connection->last_rx_jiffies = jiffies;
++              printk("init_timer %x\n", (u32)jiffies);
++#endif
++              hash_set_valid_flag(connection->hash_entry_index, 1);
++              return;
++      } else {
++              printk("%s::conn status %x, rx_pktsize %d\n",
++                      __func__, connection->status, storlink_ctl.rx_max_pktsize);
++      }
++}
++
++/*---------------------------------------------------------------------------
++ * get_connection_index
++ * get_connection_index will find an available index for the connection,
++ * when allocate a new connection is needed.
++ * we find available Qid from AV bits and write to hash_table, so that when RxTOE
++ * packet is received, sw_id from ToeQ descriptor is also the Qid of conneciton Q.
++ *-------------------------------------------------------------------------*/
++int get_connection_index(void)
++{
++      int i=0, j=0, index=-1;
++      __u32   connection_bits;
++
++      for (i = 0; i< TOE_TOE_QUEUE_NUM/32; i++) {
++              connection_bits = ~(toe_connection_bits[i]);
++              if (connection_bits == 0)
++                      // all 32 bits are used.
++                      continue;
++
++              for (j=0; j<32; j++) {
++                      if (connection_bits & 0x01) {
++                              index = i*32 + j;
++                              return index;
++                      }
++                      connection_bits = connection_bits >> 1;
++              }
++      }
++      return index;
++}
++
++/*---------------------------------------------------------------------------
++ * set_toe_connection
++ *-------------------------------------------------------------------------*/
++void set_toe_connection(int index, int val)
++{
++      if (val) {
++              toe_connection_bits[index/32] |= (1<<(index%32));
++      } else {
++              toe_connection_bits[index/32] &= (~(1<<(index%32)));
++      }
++}
++
++/*---------------------------------------------------------------------------
++ * sl351x_get_toe_conn_flag
++ *-------------------------------------------------------------------------*/
++int sl351x_get_toe_conn_flag(int index)
++{
++      if (index < TOE_TOE_QUEUE_NUM)
++              return (toe_connection_bits[index/32] & (1 << (index %32)));
++      else
++              return 0;
++}
++
++/*---------------------------------------------------------------------------
++ * sl351x_get_toe_conn_info
++ *-------------------------------------------------------------------------*/
++struct toe_conn * sl351x_get_toe_conn_info(int index)
++{
++      if (index < TOE_TOE_QUEUE_NUM)
++              return (struct toe_conn *)&toe_connections[index];
++      else
++              return NULL;
++}
++
++/*---------------------------------------------------------------------------
++ * create_sw_toe_connection
++ *-------------------------------------------------------------------------*/
++struct toe_conn* create_sw_toe_connection(int qid, int ip_ver, void* ip_hdr,
++      struct tcphdr* tcp_hdr)
++{
++      struct toe_conn*        connection =  &(toe_connections[qid]);
++
++      connection->ip_ver = (__u8)ip_ver;
++      connection->qid = (__u8)qid;
++      connection->source = (__u16)tcp_hdr->source;
++      connection->dest = (__u16)tcp_hdr->dest;
++      if (ip_ver == 4) {
++              struct iphdr* iph = (struct iphdr*) ip_hdr;
++              connection->saddr[0] = (__u32)iph->saddr;
++              connection->daddr[0] = (__u32)iph->daddr;
++//            printk("%s::saddr %x, daddr %x\n", __func__,
++//                    ntohl(connection->saddr[0]), ntohl(connection->daddr[0]));
++      } else if (ip_ver == 6) {
++              struct ipv6hdr *iph = (struct ipv6hdr*)ip_hdr;
++              int i=0;
++              for (i=0; i<4; i++) {
++                      connection->saddr[i] = (__u32)iph->saddr.in6_u.u6_addr32[i];
++                      connection->daddr[i] = (__u32)iph->daddr.in6_u.u6_addr32[i];
++              }
++      }
++      connection->status = TCP_CONN_CREATION;
++      return connection;
++}
++
++/*---------------------------------------------------------------------------
++ * fill_toeq_buf
++ *-------------------------------------------------------------------------*/
++int fill_toeq_buf(int index, TOE_INFO_T* toe)
++{
++      volatile TOE_QHDR_T     *qhdr;
++      //struct toe_conn* connection;
++      GMAC_RXDESC_T   *desc_ptr;
++
++      if (!toe->toe_desc_base[index]) {
++              // first time. init.
++              desc_ptr = (GMAC_RXDESC_T*)(pci_alloc_consistent(NULL, TOE_TOE_DESC_NUM
++                          *sizeof(GMAC_RXDESC_T), (dma_addr_t*)&toe->toe_desc_base_dma[index]));
++
++              toe->toe_desc_num = TOE_TOE_DESC_NUM;
++              toe->toe_desc_base[index] = (unsigned int)desc_ptr;
++      }
++      qhdr = (volatile TOE_QHDR_T*)((unsigned int)TOE_TOE_QUE_HDR_BASE +
++                                                                      index*sizeof(TOE_QHDR_T));
++      //connection = (struct toe_conn*)&(toe_connections[index]);
++
++      qhdr->word0.base_size = ((unsigned int)toe->toe_desc_base_dma[index]&TOE_QHDR0_BASE_MASK)
++                                      | TOE_TOE_DESC_POWER;
++      qhdr->word1.bits32 = 0;
++      qhdr->word2.bits32 = 0;
++      qhdr->word3.bits32 = 0;
++      qhdr->word4.bits32 = 0;
++      qhdr->word5.bits32 = 0;
++      return 1;
++}
++
++/*---------------------------------------------------------------------------
++ * create_toe_hash_entry_smb
++ * add SMB header in hash entry.
++ *-------------------------------------------------------------------------*/
++int create_toe_hash_entry_smb(int ip_ver, void* ip_hdr, struct tcphdr* tcp_hdr,
++      int sw_id)
++{
++      HASH_ENTRY_T    hash_entry, *entry;
++      int     hash_entry_index;
++      int i;
++
++      entry = (HASH_ENTRY_T*)&hash_entry;
++      memset((void*)entry, 0, sizeof(HASH_ENTRY_T));
++      entry->rule = 0;
++
++      /* enable fields of hash key */
++      entry->key_present.ip_protocol = 1;
++      entry->key_present.sip = 1;
++      entry->key_present.dip = 1;
++      entry->key_present.l4_bytes_0_3 = 1;    // src port and dest port
++      entry->key_present.l7_bytes_0_3 = 0;    // do we need to enable NETBIOS? how?
++      entry->key_present.l7_bytes_4_7 = 1;    // "SMB" header
++
++      /* hash key */
++      entry->key.ip_protocol = IPPROTO_TCP;
++      if (ip_ver == 4) {
++              struct iphdr *iph = (struct iphdr*)ip_hdr;
++              memcpy(entry->key.sip, &iph->saddr, 4);
++              memcpy(entry->key.dip, &iph->daddr, 4);
++      } else if (ip_ver == 6) {
++              struct ipv6hdr *iph = (struct ipv6hdr*)ip_hdr;
++              for (i=0; i<4; i++) {
++                      memcpy(&(entry->key.sip[i*4]), &(iph->saddr.in6_u.u6_addr32[i]), 4);
++                      memcpy(&(entry->key.dip[i*4]), &(iph->daddr.in6_u.u6_addr32[i]), 4);
++              }
++      }
++      *(__u16*)&entry->key.l4_bytes[0] = tcp_hdr->source;
++      *(__u16*)&entry->key.l4_bytes[2] = tcp_hdr->dest;
++
++      entry->key.l7_bytes[4] = 0xff;
++      entry->key.l7_bytes[5] = 0x53;
++      entry->key.l7_bytes[6] = 0x4d;
++      entry->key.l7_bytes[7] = 0x42;
++
++      /* action of hash entry match */
++      entry->action.sw_id = 1;
++      entry->action.dest_qid = (__u8)TOE_TOE_QID(sw_id);
++      entry->action.srce_qid = 0;
++      hash_entry_index = hash_add_toe_entry(entry);
++
++      return hash_entry_index;
++}
++
++// best performance of tcp streaming.
++/*---------------------------------------------------------------------------
++ * create_toe_hash_entry_smb
++ * add SMB header in hash entry.
++ *-------------------------------------------------------------------------*/
++int create_toe_hash_entry_ftp(int ip_ver, void* ip_hdr, struct tcphdr* tcphdr)
++{
++      return 0;
++}
++
++// is hash entry for nfs needed?
++
++/*
++ * Create a TOE hash entry by given ip addresses and tcp port numbers.
++ * hash entry index will be saved in sw connection.
++ */
++/*---------------------------------------------------------------------------
++ * create_toe_hash_entry
++ *-------------------------------------------------------------------------*/
++int create_toe_hash_entry(int ip_ver, void* ip_hdr, struct tcphdr* tcp_hdr, int sw_id)
++{
++      HASH_ENTRY_T    hash_entry, *entry;
++//    unsigned long   hash_key[HASH_MAX_DWORDS];
++      int     hash_entry_index;
++
++      entry = (HASH_ENTRY_T*) &hash_entry;
++      memset((void*)entry, 0, sizeof(HASH_ENTRY_T));
++      entry->rule = 0;
++      /* enable fields of hash key */
++      entry->key_present.ip_protocol = 1;
++      entry->key_present.sip = 1;
++      entry->key_present.dip = 1;
++      entry->key_present.l4_bytes_0_3 = 1;    // src port and dest port
++
++      /* hash key */
++      entry->key.ip_protocol = IPPROTO_TCP;
++      if (ip_ver == 4) {
++              // key of ipv4
++              struct iphdr* iph = (struct iphdr*)ip_hdr;
++              memcpy(entry->key.sip, &iph->saddr, 4);
++              memcpy(entry->key.dip, &iph->daddr, 4);
++      } else if (ip_ver == 6) {
++              // key of ipv6
++              int i=0;
++              struct ipv6hdr *iph = (struct ipv6hdr*)ip_hdr;
++              for (i=0; i<4; i++) {
++                      memcpy(&(entry->key.sip[i*4]), &(iph->saddr.in6_u.u6_addr32[i]), 4);
++                      memcpy(&(entry->key.dip[i*4]), &(iph->daddr.in6_u.u6_addr32[i]), 4);
++              }
++      }
++      *(__u16*)&entry->key.l4_bytes[0] = tcp_hdr->source;
++      *(__u16*)&entry->key.l4_bytes[2] = tcp_hdr->dest;
++      // is it necessary to write ip version to hash key?
++
++      /* action of hash entry match */
++      entry->action.sw_id = 1;
++      entry->action.dest_qid = (__u8)TOE_TOE_QID(sw_id);
++      entry->action.srce_qid = 0;     // 0 for SW FreeQ. 1 for HW FreeQ.
++      hash_entry_index = hash_add_toe_entry(entry);
++//    printk("\n%s. sw_id %d, hash_entry index %x\n",
++//            __func__, TOE_TOE_QID(sw_id), hash_entry_index);
++      return hash_entry_index;
++}
++
++/*---------------------------------------------------------------------------
++ * init_toeq
++ * 1. Reserve a TOE Queue id first, to get the sw toe_connection.
++ * 2. Setup the hash entry with given iphdr and tcphdr, save hash entry index
++ *    in sw toe_connection.
++ * 3. Prepare sw toe_connection and allocate buffers.
++ * 4. Validate hash entry.
++ *-------------------------------------------------------------------------*/
++struct toe_conn* init_toeq(int ipver, void* iph, struct tcphdr* tcp_hdr,
++      TOE_INFO_T* toe, unsigned char* l2hdr)
++{
++//    printk("\t*** %s, ipver %d\n", __func__, ipver);
++      int qid=-1;
++      struct toe_conn* connection;
++      int hash_entry_index;
++      // int i=0;
++      unsigned short  dest_port = ntohs(tcp_hdr->dest);
++
++      if (dest_port == 445) {
++              printk("%s::SMB/CIFS connection\n", __func__);
++      } else if (dest_port == 20) {
++              printk("%s::ftp-data connection\n", __func__);
++      } else if (dest_port == 2049) {
++              printk("%s::nfs daemon connection\n", __func__);
++      }
++      qid = get_connection_index();
++      if (qid<0)
++              return 0;       // setup toeq failure
++      set_toe_connection(qid, 1); // reserve this sw toeq.
++
++      //connection = (struct toe_conn*)&(toe_connections[qid]);
++      hash_entry_index = create_toe_hash_entry(ipver, iph, tcp_hdr, qid);
++      if (hash_entry_index <0) {
++              printk("%s::release toe hash entry!\n", __func__);
++              set_toe_connection(qid, 0); // release this sw toeq.
++              return 0;
++      }
++      connection = create_sw_toe_connection(qid, ipver, iph, tcp_hdr);
++      connection->hash_entry_index = (__u16) hash_entry_index;
++
++      fill_toeq_buf(qid, toe);
++      memcpy(&connection->l2_hdr, l2hdr, sizeof(struct ethhdr));
++      spin_lock_init(&connection->conn_lock);
++
++      return connection;
++}
++
++#if 0
++/*----------------------------------------------------------------------
++*   toe_init_toe_queue
++*   (1) Initialize the TOE Queue Header
++*       Register: TOE_TOE_QUE_HDR_BASE (0x60003000)
++*   (2) Initialize Descriptors of TOE Queues
++*----------------------------------------------------------------------*/
++void toe_init_toe_queue(TOE_INFO_T* toe)
++{
++}
++EXPORT_SYMBOL(toe_init_toe_queue);
++#endif
++
++/*---------------------------------------------------------------------------
++ * dump_jumbo_skb
++ *-------------------------------------------------------------------------*/
++void dump_jumbo_skb(struct jumbo_frame *jumbo_skb)
++{
++      if (jumbo_skb->skb0) {
++//            printk("%s. jumbo skb %x, len %d\n",
++//                    __func__, jumbo_skb->skb0->data, jumbo_skb->skb0->len);
++              netif_rx(jumbo_skb->skb0);
++      }
++      jumbo_skb->skb0 = 0;
++      jumbo_skb->tail = 0;
++      jumbo_skb->iphdr0 = 0;
++      jumbo_skb->tcphdr0 = 0;
++}
++
++/* ---------------------------------------------------------------------
++ * Append skb to skb0. skb0 is the jumbo frame that will be passed to
++ * kernel tcp.
++ * --------------------------------------------------------------------*/
++void rx_append_skb(struct jumbo_frame *jumbo_skb, struct sk_buff* skb, int payload_len)
++{
++      struct iphdr* iphdr0 = (struct iphdr*)&(skb->data[0]);
++      int ip_hdrlen = iphdr0->ihl << 2;
++      struct tcphdr* tcphdr0 = (struct tcphdr*)&(skb->data[ip_hdrlen]);
++
++      if (!jumbo_skb->skb0) {
++              // head of the jumbo frame.
++              jumbo_skb->skb0 = skb;
++              jumbo_skb->tail = 0;
++              jumbo_skb->iphdr0 = iphdr0;
++              jumbo_skb->tcphdr0 = tcphdr0;
++      } else {
++              if (!jumbo_skb->tail)
++                      skb_shinfo(jumbo_skb->skb0)->frag_list = skb;
++              else
++                      (jumbo_skb->tail)->next = skb;
++              jumbo_skb->tail = skb;
++
++              // do we need to change truesize as well?
++              jumbo_skb->skb0->len += payload_len;
++              jumbo_skb->skb0->data_len += payload_len;
++
++              jumbo_skb->iphdr0->tot_len = htons(ntohs(jumbo_skb->iphdr0->tot_len)+payload_len);
++              jumbo_skb->tcphdr0->ack_seq = tcphdr0->ack_seq;
++              jumbo_skb->tcphdr0->window = tcphdr0->window;
++
++              skb->len += payload_len;
++              skb->data_len = 0;
++              skb->data += ntohs(iphdr0->tot_len) - payload_len;
++      }
++}
++
++/*----------------------------------------------------------------------
++* toe_gmac_handle_toeq
++* (1) read interrupt Queue to get TOE Q.
++* (2) get packet fro TOE Q and send to upper layer handler.
++* (3) allocate new buffers and put to TOE Q. Intr Q buffer is recycled.
++*----------------------------------------------------------------------*/
++void toe_gmac_handle_toeq(struct net_device *dev, GMAC_INFO_T* tp, __u32 status)
++{
++      //volatile INTRQ_INFO_T *intrq_info;
++      //TOEQ_INFO_T           *toeq_info;
++      volatile NONTOE_QHDR_T  *intr_qhdr;
++      volatile TOE_QHDR_T             *toe_qhdr;
++      volatile INTR_QHDR_T    *intr_curr_desc;
++      TOE_INFO_T      *toe = &toe_private_data;
++
++      volatile GMAC_RXDESC_T  *toe_curr_desc; // , *fq_desc;// *tmp_desc;
++      volatile DMA_RWPTR_T    intr_rwptr, toeq_rwptr;  // fq_rwptr;
++
++      unsigned int    pkt_size, desc_count, tcp_qid;
++      volatile unsigned int   toeq_wptr;
++      struct toe_conn*                connection;
++      int             i, frag_id = 0;
++      // unsigned long        toeq_flags;
++      struct jumbo_frame      jumbo_skb;
++      struct sk_buff  *skb;
++      __u32   interrupt_status;
++
++      in_toe_isr++;
++
++      interrupt_status = status >> 24;
++      // get interrupt queue header
++      intr_qhdr = (volatile NONTOE_QHDR_T*)TOE_INTR_Q_HDR_BASE;
++      memset(&jumbo_skb, 0, sizeof(struct jumbo_frame));
++
++      for (i=0; i<TOE_INTR_QUEUE_NUM; i++, intr_qhdr++) {
++              if (!(interrupt_status & 0x0001)) {
++                      // no interrupt of this IntQ
++                      interrupt_status = interrupt_status >> 1;
++                      continue;
++              }
++              interrupt_status = interrupt_status >> 1;
++              intr_rwptr.bits32 = readl(&intr_qhdr->word1);
++
++              while ( intr_rwptr.bits.rptr != intr_rwptr.bits.wptr) {
++                      int max_pktsize = 1;
++                      // get interrupt queue descriptor.
++                      intr_curr_desc = (INTR_QHDR_T*)toe->intr_desc_base +
++                              i* TOE_INTR_DESC_NUM + intr_rwptr.bits.rptr;
++//                    printk("%s::int %x\n", __func__, intr_curr_desc->word1.bits32);
++                      // get toeq id
++                      tcp_qid = (u8)intr_curr_desc->word1.bits.tcp_qid - (u8)TOE_TOE_QID(0);
++                      // get toeq queue header
++                      toe_qhdr = (volatile TOE_QHDR_T*) TOE_TOE_QUE_HDR_BASE;
++                      toe_qhdr += tcp_qid;
++                      connection = &toe_connections[tcp_qid];
++                      del_timer(&connection->rx_timer);
++                      // Gary Chen spin_lock_irqsave(&connection->conn_lock, toeq_flags);
++                      // handling interrupts of this TOE Q.
++                      if (intr_curr_desc->word1.bits.ctl || intr_curr_desc->word1.bits.osq ||
++                              intr_curr_desc->word1.bits.abn)
++                              max_pktsize = 0;
++                      if (!max_pktsize || intr_curr_desc->word1.bits.TotalPktSize) {
++                              desc_count=0;
++                              // wptr in intl queue is where this TOE interrupt should stop.
++                              toeq_rwptr.bits32 = readl(&toe_qhdr->word1);
++                              toeq_wptr = intr_curr_desc->word0.bits.wptr;
++                              if (connection->toeq_rwptr.bits.rptr != toeq_rwptr.bits.rptr)
++                                      printk("conn rptr %d, hw rptr %d\n",
++                                              connection->toeq_rwptr.bits.rptr, toeq_rwptr.bits.rptr);
++
++                              if (intr_curr_desc->word1.bits.ctl &&
++                                      (toeq_rwptr.bits.rptr == toeq_wptr)) {
++                                      printk("\nctrl frame, but not in TOE queue! conn rptr %d, hw wptr %d\n",
++                                              connection->toeq_rwptr.bits.rptr, toeq_wptr);
++//                                    dump_toe_qhdr(toe_qhdr);
++//                                    dump_intrq_desc(intr_curr_desc);
++                              }
++                              // while (toeq_rwptr.bits.rptr != intr_curr_desc->word0.bits.wptr) {
++                              while (toe_qhdr->word1.bits.rptr != intr_curr_desc->word0.bits.wptr) {
++                                      frag_id++;
++                                      toe_curr_desc = (volatile GMAC_RXDESC_T *)(toe->toe_desc_base[tcp_qid]
++                                              + toe_qhdr->word1.bits.rptr *sizeof(GMAC_RXDESC_T));
++                                      connection->curr_desc = (GMAC_RXDESC_T *)toe_curr_desc;
++                                      desc_count = toe_curr_desc->word0.bits.desc_count;
++                                      pkt_size = toe_curr_desc->word1.bits.byte_count;
++                                      consistent_sync((void*)__va(toe_curr_desc->word2.buf_adr), pkt_size,
++                                              PCI_DMA_FROMDEVICE);
++                                      skb = (struct sk_buff*)(REG32(__va(toe_curr_desc->word2.buf_adr)-
++                                              SKB_RESERVE_BYTES));
++                                      _debug_skb(skb, (GMAC_RXDESC_T *)toe_curr_desc, 0x01);
++                                      connection->curr_rx_skb = skb;
++                                      skb_reserve(skb, RX_INSERT_BYTES);
++                                      if ((skb->len + pkt_size) > (1514+16))
++                                      {
++                                              printk("skb->len=%d, pkt_size=%d\n",skb->len, pkt_size);
++                                              while(1);
++                                      }
++
++                                      skb_put(skb, pkt_size);
++                                      skb->dev = dev;
++                                      skb->protocol = eth_type_trans(skb, dev);
++                                      skb->ip_summed = CHECKSUM_UNNECESSARY;
++
++                                      if (toe_curr_desc->word3.bits32 & 0x1b000000)
++                                              dump_jumbo_skb(&jumbo_skb);
++
++                                      rx_append_skb(&jumbo_skb, skb, pkt_size-toe_curr_desc->word3.bits.l7_offset);
++//                                    spin_lock_irqsave(&gmac_fq_lock, flags);
++                                      toeq_rwptr.bits.rptr = RWPTR_ADVANCE_ONE(toeq_rwptr.bits.rptr, TOE_TOE_DESC_NUM);
++                                      SET_RPTR(&toe_qhdr->word1, toeq_rwptr.bits.rptr);
++//                                    spin_unlock_irqrestore(&gmac_fq_lock, flags);
++                                      if (storlink_ctl.fqint_threshold)
++                                              continue;
++#if 0
++//#if (HANDLE_FREEQ_METHOD == HANDLE_FREEQ_INDIVIDUAL)
++                                      if ((skb = dev_alloc_skb(RX_BUF_SIZE)) == NULL) {
++                                              printk("%s::toe queue alloc buffer ", __func__);
++                                      }
++                                      *(unsigned int*)(skb->data) = (unsigned int)skb;
++                                      connection->curr_rx_skb = skb;
++                                      skb_reserve(skb, SKB_RESERVE_BYTES);
++
++                                      spin_lock_irqsave(&gmac_fq_lock, flags);
++                                      fq_rwptr.bits32 = readl(TOE_GLOBAL_BASE + GLOBAL_SWFQ_RWPTR_REG);
++                                      if (toe->fq_rx_rwptr.bits.wptr != fq_rwptr.bits.wptr) {
++                                              printk("%s::fq_rx_rwptr %x\n", __func__, toe->fq_rx_rwptr.bits32);
++                                              mac_stop_txdma((struct net_device*) tp->dev);
++                                              spin_unlock_irqrestore(&gmac_fq_lock, flags);
++                                              while(1);
++                                      }
++                                      fq_desc = (GMAC_RXDESC_T*)toe->swfq_desc_base + fq_rwptr.bits.wptr;
++                                      fq_desc->word2.buf_adr = (unsigned int)__pa(skb->data);
++
++                                      fq_rwptr.bits.wptr = RWPTR_ADVANCE_ONE(fq_rwptr.bits.wptr, TOE_SW_FREEQ_DESC_NUM);
++                                      SET_WPTR(TOE_GLOBAL_BASE + GLOBAL_SWFQ_RWPTR_REG, fq_rwptr.bits.wptr);
++                                      toe->fq_rx_rwptr.bits32 = fq_rwptr.bits32;
++                                      spin_unlock_irqrestore(&gmac_fq_lock, flags);
++#endif
++                              } // end of this multi-desc.
++                              dump_jumbo_skb(&jumbo_skb);
++                              dev->last_rx = jiffies;
++                              connection->toeq_rwptr.bits32 = toeq_rwptr.bits32;
++                      } else if (intr_curr_desc->word1.bits.sat) {
++                              toeq_rwptr.bits32 = readl(&toe_qhdr->word1);
++                              toeq_wptr = intr_curr_desc->word0.bits.wptr;
++                              if (connection->toeq_rwptr.bits.rptr != toeq_rwptr.bits.rptr)
++                                      printk("SAT. conn rptr %d, hw rptr %d\n",
++                                              connection->toeq_rwptr.bits.rptr, toeq_rwptr.bits.rptr);
++/*
++                                      printk("%s::SAT int!, ackcnt %x, seqcnt %x, rptr %d, wptr %d, ack %x, qhack %x\n",
++                                              __func__, intr_curr_desc->word4.bits.AckCnt, intr_curr_desc->word4.bits.SeqCnt,
++                                              toeq_rptr, toeq_wptr, intr_curr_desc->word3.ack_num, toe_qhdr->word4.ack_num);*/
++                              /* pure ack */
++                              if (toeq_rwptr.bits.rptr == toeq_wptr) {
++                                      if (intr_curr_desc->word4.bits32) {
++                                              skb = gen_pure_ack(connection, (TOE_QHDR_T *)toe_qhdr, (INTR_QHDR_T *)intr_curr_desc);
++                                              skb_put(skb, 60);
++                                              skb->dev = connection->dev;
++                                              skb->ip_summed = CHECKSUM_UNNECESSARY;
++                                              skb->protocol = eth_type_trans(skb, connection->dev);
++                                              netif_rx(skb);
++                                      } else
++                                              printk("%s::SAT Interrupt!. But cnt is 0!\n", __func__);
++                              } else {
++                                      // while (toeq_rwptr.bits.rptr != toeq_wptr) {
++                                      while (toe_qhdr->word1.bits.rptr != intr_curr_desc->word0.bits.wptr) {
++                                              toe_curr_desc = (volatile GMAC_RXDESC_T*)(toe->toe_desc_base[tcp_qid]
++                                                      + toe_qhdr->word1.bits.rptr * sizeof(GMAC_RXDESC_T));
++                                              connection->curr_desc = (GMAC_RXDESC_T *)toe_curr_desc;
++                                              desc_count = toe_curr_desc->word0.bits.desc_count;
++                                              pkt_size = toe_curr_desc->word1.bits.byte_count;
++                                              consistent_sync((void*)__va(toe_curr_desc->word2.buf_adr), pkt_size,
++                                                      PCI_DMA_FROMDEVICE);
++                                              // if ( ((toeq_rwptr.bits.rptr +1)&(TOE_TOE_DESC_NUM-1)) == toeq_wptr) {
++                                              if ( RWPTR_ADVANCE_ONE(toe_qhdr->word1.bits.rptr, TOE_TOE_DESC_NUM) == toeq_wptr) {
++                                                      skb = (struct sk_buff*)(REG32(__va(toe_curr_desc->word2.buf_adr) -
++                                                              SKB_RESERVE_BYTES));
++                                                      _debug_skb(skb, (GMAC_RXDESC_T *)toe_curr_desc, 0x04);
++                                                      connection->curr_rx_skb = skb;
++                                                      skb_reserve(skb, RX_INSERT_BYTES);
++                                                      skb_put(skb, pkt_size);
++                                                      skb->dev = dev;
++                                                      skb->protocol = eth_type_trans(skb, dev);
++                                                      skb->ip_summed = CHECKSUM_UNNECESSARY;
++                                                      // printk("toeq_rptr %d, wptr %d\n", toeq_rptr, toeq_wptr);
++                                                      netif_rx(skb);
++                                                      dev->last_rx = jiffies;
++/*
++                                                      if ((skb = dev_alloc_skb(RX_BUF_SIZE)) == NULL) {
++
++                                                      }
++                                                      *(unsigned int*)(skb->data) = (unsigned int) skb;
++                                                      skb_reserve(skb, SKB_RESERVE_BYTES); */
++                                              } else {
++                                                      // reuse this skb, append to free queue..
++                                                      skb = (struct sk_buff*)(REG32(__va(toe_curr_desc->word2.buf_adr)-
++                                                              SKB_RESERVE_BYTES));
++                                                      _debug_skb(skb, (GMAC_RXDESC_T *)toe_curr_desc, 0x05);
++                                                      connection->curr_rx_skb = skb;
++                                                      dev_kfree_skb_irq(skb);
++                                              }
++#if 0
++                                              spin_lock_irqsave(&gmac_fq_lock, flags);
++                                              fq_rwptr.bits32 = readl(TOE_GLOBAL_BASE + GLOBAL_SWFQ_RWPTR_REG);
++/*                                            if (toe->fq_rx_rwptr.bits.wptr != fq_rwptr.bits.wptr) {
++                                                      printk("%s::fq_rx_rwptr %x\n", __func__, toe->fq_rx_rwptr.bits32);
++                                                      mac_stop_txdma((struct net_device*) tp->dev);
++                                                      spin_unlock_irqrestore(&gmac_fq_lock, flags);
++                                                      while(1);
++                                              } */
++                                              fq_desc = (GMAC_RXDESC_T*)toe->swfq_desc_base + fq_rwptr.bits.wptr;
++                                              fq_desc->word2.buf_adr = (unsigned int)__pa(skb->data);
++
++                                              fq_rwptr.bits.wptr = RWPTR_ADVANCE_ONE(fq_rwptr.bits.wptr, TOE_SW_FREEQ_DESC_NUM);
++                                              SET_WPTR(TOE_GLOBAL_BASE + GLOBAL_SWFQ_RWPTR_REG, fq_rwptr.bits.wptr);
++                                              toe->fq_rx_rwptr.bits32 = fq_rwptr.bits32;
++      //                                      spin_unlock_irqrestore(&gmac_fq_lock, flags);
++#endif
++//                                            spin_lock_irqsave(&gmac_fq_lock, flags);
++                                              toeq_rwptr.bits.rptr = RWPTR_ADVANCE_ONE(toeq_rwptr.bits.rptr, TOE_TOE_DESC_NUM);
++                                              SET_RPTR(&toe_qhdr->word1, toeq_rwptr.bits.rptr);
++//                                            spin_unlock_irqrestore(&gmac_fq_lock, flags);
++                                      }
++                              } // end of ACK with options.
++                              connection->toeq_rwptr.bits32 = toeq_rwptr.bits32;
++                              // Gary Chen spin_unlock_irqrestore(&connection->conn_lock, toeq_flags);
++//                            }
++                      };
++                      update_timer(connection);
++                      // any protection against interrupt queue header?
++                      intr_rwptr.bits.rptr = RWPTR_ADVANCE_ONE(intr_rwptr.bits.rptr, TOE_INTR_DESC_NUM);
++                      SET_RPTR(&intr_qhdr->word1, intr_rwptr.bits.rptr);
++                      intr_rwptr.bits32 = readl(&intr_qhdr->word1);
++                      toe_gmac_fill_free_q();
++              } // end of this interrupt Queue processing.
++      } // end of all interrupt Queues.
++
++      in_toe_isr = 0;
++}
++
++
+Index: linux-2.6.23.16/drivers/net/sl_lepus_hash.c
+===================================================================
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.23.16/drivers/net/sl_lepus_hash.c        2008-03-15 16:59:57.863423587 +0200
+@@ -0,0 +1,553 @@
++/**************************************************************************
++* Copyright 2006 StorLink Semiconductors, Inc.  All rights reserved.
++*--------------------------------------------------------------------------
++* Name                        : sl_lepus_hash.c
++* Description :
++*             Handle Storlink Lepus Hash Functions
++*
++* History
++*
++*     Date            Writer          Description
++*----------------------------------------------------------------------------
++*     03/13/2006      Gary Chen       Create and implement
++*
++****************************************************************************/
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/compiler.h>
++#include <linux/pci.h>
++#include <linux/init.h>
++#include <linux/ioport.h>
++#include <linux/netdevice.h>
++#include <linux/etherdevice.h>
++#include <linux/rtnetlink.h>
++#include <linux/delay.h>
++#include <linux/ethtool.h>
++#include <linux/mii.h>
++#include <linux/completion.h>
++#include <asm/hardware.h>
++#include <asm/io.h>
++#include <asm/irq.h>
++#include <asm/semaphore.h>
++#include <asm/arch/irqs.h>
++#include <asm/arch/it8712.h>
++#include <linux/mtd/kvctl.h>
++#include <linux/skbuff.h>
++#include <linux/ip.h>
++#include <linux/tcp.h>
++#include <linux/list.h>
++#define        MIDWAY
++#define        SL_LEPUS
++
++#include <asm/arch/sl2312.h>
++#include <asm/arch/sl_lepus_gmac.h>
++#include <asm/arch/sl_hash_cfg.h>
++
++#ifndef RXTOE_DEBUG
++#define RXTOE_DEBUG
++#endif
++#undef RXTOE_DEBUG
++
++/*----------------------------------------------------------------------
++* Definition
++*----------------------------------------------------------------------*/
++#define       hash_printf                             printk
++
++#define HASH_TIMER_PERIOD             (60*HZ) // seconds
++#define HASH_ILLEGAL_INDEX            0xffff
++
++/*----------------------------------------------------------------------
++* Variables
++*----------------------------------------------------------------------*/
++u32                                   hash_activate_bits[HASH_TOTAL_ENTRIES/32];
++u32                                   hash_nat_owner_bits[HASH_TOTAL_ENTRIES/32];
++char                          hash_tables[HASH_TOTAL_ENTRIES][HASH_MAX_BYTES] __attribute__ ((aligned(16)));
++static struct timer_list hash_timer_obj;
++LIST_HEAD(hash_timeout_list);
++
++/*----------------------------------------------------------------------
++* Functions
++*----------------------------------------------------------------------*/
++void dm_long(u32 location, int length);
++static void hash_timer_func(u32 data);
++
++/*----------------------------------------------------------------------
++* hash_init
++*----------------------------------------------------------------------*/
++void hash_init(void)
++{
++      int i;
++      volatile u32 *dp1, *dp2, dword;
++
++      dp1 = (volatile u32 *) TOE_V_BIT_BASE;
++      dp2 = (volatile u32 *) TOE_A_BIT_BASE;
++
++      for (i=0; i<HASH_TOTAL_ENTRIES/32; i++)
++      {
++              *dp1++ = 0;
++              dword = *dp2++; // read-clear
++      }
++      memset((void *)&hash_nat_owner_bits, 0, sizeof(hash_nat_owner_bits));
++      memset((void *)&hash_tables, 0, sizeof(hash_tables));
++
++      init_timer(&hash_timer_obj);
++      hash_timer_obj.expires = jiffies + HASH_TIMER_PERIOD;
++      hash_timer_obj.data = (unsigned long)&hash_timer_obj;
++      hash_timer_obj.function = (void *)&hash_timer_func;
++      add_timer(&hash_timer_obj);
++
++#if (HASH_MAX_BYTES == 128)
++      writel((unsigned long)__pa(&hash_tables) | 3,   // 32 words
++                      TOE_GLOBAL_BASE + GLOBAL_HASH_TABLE_BASE_REG);
++#elif (HASH_MAX_BYTES == 64)
++      writel((unsigned long)__pa(&hash_tables) | 2,   // 16 words
++                      TOE_GLOBAL_BASE + GLOBAL_HASH_TABLE_BASE_REG);
++#else
++      #error Incorrect setting for HASH_MAX_BYTES
++#endif
++
++}
++/*----------------------------------------------------------------------
++* hash_add_entry
++*----------------------------------------------------------------------*/
++int hash_add_entry(HASH_ENTRY_T *entry)
++{
++      int     rc;
++      u32     key[HASH_MAX_DWORDS];
++      rc = hash_build_keys((u32 *)&key, entry);
++      if (rc < 0)
++              return -1;
++      hash_write_entry(entry, (unsigned char*) &key[0]);
++//    hash_set_valid_flag(entry->index, 1);
++//    printk("Dump hash key!\n");
++//    dump_hash_key(entry);
++      return entry->index;
++}
++
++/*----------------------------------------------------------------------
++* hash_set_valid_flag
++*----------------------------------------------------------------------*/
++void hash_set_valid_flag(int index, int valid)
++{
++      register u32 reg32;
++
++      reg32 = TOE_V_BIT_BASE + (index/32) * 4;
++
++      if (valid)
++      {
++              writel(readl(reg32) | (1 << (index%32)), reg32);
++      }
++      else
++      {
++              writel(readl(reg32) & ~(1 << (index%32)), reg32);
++      }
++}
++
++/*----------------------------------------------------------------------
++* hash_set_nat_owner_flag
++*----------------------------------------------------------------------*/
++void hash_set_nat_owner_flag(int index, int valid)
++{
++      if (valid)
++      {
++              hash_nat_owner_bits[index/32] |= (1 << (index % 32));
++      }
++      else
++      {
++              hash_nat_owner_bits[index/32] &= ~(1 << (index % 32));
++      }
++}
++
++
++/*----------------------------------------------------------------------
++* hash_build_keys
++*----------------------------------------------------------------------*/
++int hash_build_keys(u32 *destp, HASH_ENTRY_T *entry)
++{
++      u32     data;
++      unsigned char   *cp;
++      int                             i, j;
++      unsigned short  index;
++      int                     total;
++
++      memset((void *)destp, 0, HASH_MAX_BYTES);
++      cp = (unsigned char *)destp;
++
++      if (entry->key_present.port || entry->key_present.Ethertype)
++      {
++              HASH_PUSH_WORD(cp, entry->key.Ethertype);               // word 0
++              HASH_PUSH_BYTE(cp, entry->key.port);                    // Byte 2
++              HASH_PUSH_BYTE(cp, 0);                                                  // Byte 3
++      }
++      else
++      {
++              HASH_PUSH_DWORD(cp, 0);
++      }
++
++      if (entry->key_present.da || entry->key_present.sa)
++      {
++              unsigned char mac[4];
++              if (entry->key_present.da)
++              {
++                      for (i=0; i<4; i++)
++                              HASH_PUSH_BYTE(cp, entry->key.da[i]);
++              }
++              mac[0] = (entry->key_present.da) ? entry->key.da[4] : 0;
++              mac[1] = (entry->key_present.da) ? entry->key.da[5] : 0;
++              mac[2] = (entry->key_present.sa) ? entry->key.sa[0] : 0;
++              mac[3] = (entry->key_present.sa) ? entry->key.sa[1] : 0;
++              data = mac[0] + (mac[1]<<8) + (mac[2]<<16) + (mac[3]<<24);
++              HASH_PUSH_DWORD(cp, data);
++              if (entry->key_present.sa)
++              {
++                      for (i=2; i<6; i++)
++                              HASH_PUSH_BYTE(cp, entry->key.sa[i]);
++              }
++      }
++
++      if (entry->key_present.pppoe_sid || entry->key_present.vlan_id)
++      {
++              HASH_PUSH_WORD(cp, entry->key.vlan_id);         // low word
++              HASH_PUSH_WORD(cp, entry->key.pppoe_sid);       // high word
++      }
++      if (entry->key_present.ipv4_hdrlen || entry->key_present.ip_tos || entry->key_present.ip_protocol)
++      {
++              HASH_PUSH_BYTE(cp, entry->key.ip_protocol);             // Byte 0
++              HASH_PUSH_BYTE(cp, entry->key.ip_tos);                  // Byte 1
++              HASH_PUSH_BYTE(cp, entry->key.ipv4_hdrlen);             // Byte 2
++              HASH_PUSH_BYTE(cp, 0);                                                  // Byte 3
++      }
++
++      if (entry->key_present.ipv6_flow_label)
++      {
++              HASH_PUSH_DWORD(cp, entry->key.ipv6_flow_label);        // low word
++      }
++      if (entry->key_present.sip)
++      {
++              // input (entry->key.sip[i]) is network-oriented
++              // output (hash key) is host-oriented
++              for (i=3; i>=0; i--)
++                      HASH_PUSH_BYTE(cp, entry->key.sip[i]);
++              if (entry->key.ipv6)
++              {
++                      for (i=4; i<16; i+=4)
++                      {
++                              for (j=i+3; j>=i; j--)
++                                      HASH_PUSH_BYTE(cp, entry->key.sip[j]);
++                      }
++              }
++      }
++      if (entry->key_present.dip)
++      {
++              // input (entry->key.sip[i]) is network-oriented
++              // output (hash key) is host-oriented
++              for (i=3; i>=0; i--)
++                      HASH_PUSH_BYTE(cp, entry->key.dip[i]);
++              if (entry->key.ipv6)
++              {
++                      for (i=4; i<16; i+=4)
++                      {
++                              for (j=i+3; j>=i; j--)
++                                      HASH_PUSH_BYTE(cp, entry->key.dip[j]);
++                      }
++              }
++      }
++
++      if (entry->key_present.l4_bytes_0_3)
++      {
++              HASH_PUSH_BYTE(cp, entry->key.l4_bytes[0]);
++              HASH_PUSH_BYTE(cp, entry->key.l4_bytes[1]);
++              HASH_PUSH_BYTE(cp, entry->key.l4_bytes[2]);
++              HASH_PUSH_BYTE(cp, entry->key.l4_bytes[3]);
++      }
++      if (entry->key_present.l4_bytes_4_7)
++      {
++              HASH_PUSH_BYTE(cp, entry->key.l4_bytes[4]);
++              HASH_PUSH_BYTE(cp, entry->key.l4_bytes[5]);
++              HASH_PUSH_BYTE(cp, entry->key.l4_bytes[6]);
++              HASH_PUSH_BYTE(cp, entry->key.l4_bytes[7]);
++      }
++      if (entry->key_present.l4_bytes_8_11)
++      {
++              HASH_PUSH_BYTE(cp, entry->key.l4_bytes[8]);
++              HASH_PUSH_BYTE(cp, entry->key.l4_bytes[9]);
++              HASH_PUSH_BYTE(cp, entry->key.l4_bytes[10]);
++              HASH_PUSH_BYTE(cp, entry->key.l4_bytes[11]);
++      }
++      if (entry->key_present.l4_bytes_12_15)
++      {
++              HASH_PUSH_BYTE(cp, entry->key.l4_bytes[12]);
++              HASH_PUSH_BYTE(cp, entry->key.l4_bytes[13]);
++              HASH_PUSH_BYTE(cp, entry->key.l4_bytes[14]);
++              HASH_PUSH_BYTE(cp, entry->key.l4_bytes[15]);
++      }
++      if (entry->key_present.l4_bytes_16_19)
++      {
++              HASH_PUSH_BYTE(cp, entry->key.l4_bytes[16]);
++              HASH_PUSH_BYTE(cp, entry->key.l4_bytes[17]);
++              HASH_PUSH_BYTE(cp, entry->key.l4_bytes[18]);
++              HASH_PUSH_BYTE(cp, entry->key.l4_bytes[19]);
++      }
++      if (entry->key_present.l4_bytes_20_23)
++      {
++              HASH_PUSH_BYTE(cp, entry->key.l4_bytes[20]);
++              HASH_PUSH_BYTE(cp, entry->key.l4_bytes[21]);
++              HASH_PUSH_BYTE(cp, entry->key.l4_bytes[22]);
++              HASH_PUSH_BYTE(cp, entry->key.l4_bytes[23]);
++      }
++      if (entry->key_present.l7_bytes_0_3)
++      {
++              HASH_PUSH_BYTE(cp, entry->key.l7_bytes[0]);
++              HASH_PUSH_BYTE(cp, entry->key.l7_bytes[1]);
++              HASH_PUSH_BYTE(cp, entry->key.l7_bytes[2]);
++              HASH_PUSH_BYTE(cp, entry->key.l7_bytes[3]);
++      }
++      if (entry->key_present.l7_bytes_4_7)
++      {
++              HASH_PUSH_BYTE(cp, entry->key.l7_bytes[4]);
++              HASH_PUSH_BYTE(cp, entry->key.l7_bytes[5]);
++              HASH_PUSH_BYTE(cp, entry->key.l7_bytes[6]);
++              HASH_PUSH_BYTE(cp, entry->key.l7_bytes[7]);
++      }
++      if (entry->key_present.l7_bytes_8_11)
++      {
++              HASH_PUSH_BYTE(cp, entry->key.l7_bytes[8]);
++              HASH_PUSH_BYTE(cp, entry->key.l7_bytes[9]);
++              HASH_PUSH_BYTE(cp, entry->key.l7_bytes[10]);
++              HASH_PUSH_BYTE(cp, entry->key.l7_bytes[11]);
++      }
++      if (entry->key_present.l7_bytes_12_15)
++      {
++              HASH_PUSH_BYTE(cp, entry->key.l7_bytes[12]);
++              HASH_PUSH_BYTE(cp, entry->key.l7_bytes[13]);
++              HASH_PUSH_BYTE(cp, entry->key.l7_bytes[14]);
++              HASH_PUSH_BYTE(cp, entry->key.l7_bytes[15]);
++      }
++      if (entry->key_present.l7_bytes_16_19)
++      {
++              HASH_PUSH_BYTE(cp, entry->key.l7_bytes[16]);
++              HASH_PUSH_BYTE(cp, entry->key.l7_bytes[17]);
++              HASH_PUSH_BYTE(cp, entry->key.l7_bytes[18]);
++              HASH_PUSH_BYTE(cp, entry->key.l7_bytes[19]);
++      }
++      if (entry->key_present.l7_bytes_20_23)
++      {
++              HASH_PUSH_BYTE(cp, entry->key.l7_bytes[20]);
++              HASH_PUSH_BYTE(cp, entry->key.l7_bytes[21]);
++              HASH_PUSH_BYTE(cp, entry->key.l7_bytes[22]);
++              HASH_PUSH_BYTE(cp, entry->key.l7_bytes[23]);
++      }
++
++      // get hash index
++      total = (u32)((u32)cp - (u32)destp) / (sizeof(u32));
++
++      if (total > HASH_MAX_KEY_DWORD)
++      {
++              //hash_printf("Total key words (%d) is too large (> %d)!\n",
++              //                              total, HASH_MAX_KEY_DWORD);
++              return -1;
++      }
++
++      if (entry->key_present.port || entry->key_present.Ethertype)
++              index = hash_gen_crc16((unsigned char *)destp, total * 4);
++      else
++      {
++              if (total == 1)
++              {
++                      hash_printf("No key is assigned!\n");
++                      return -1;
++              }
++
++              index = hash_gen_crc16((unsigned char *)(destp+1), (total-1) * 4);
++      }
++
++      entry->index = index & HASH_BITS_MASK;
++
++      //hash_printf("Total key words = %d, Hash Index= %d\n",
++      //                              total, entry->index);
++
++      cp = (unsigned char *)destp;
++      cp+=3;
++      HASH_PUSH_BYTE(cp, entry->rule);        // rule
++
++      entry->total_dwords = total;
++
++      return total;
++}
++
++/*----------------------------------------------------------------------
++* hash_build_nat_keys
++*----------------------------------------------------------------------*/
++void hash_build_nat_keys(u32 *destp, HASH_ENTRY_T *entry)
++{
++      unsigned char   *cp;
++      int                             i;
++      unsigned short  index;
++      int                     total;
++
++      memset((void *)destp, 0, HASH_MAX_BYTES);
++
++      cp = (unsigned char *)destp + 2;
++      HASH_PUSH_BYTE(cp, entry->key.port);
++      cp++;
++
++      if (entry->key_present.pppoe_sid || entry->key_present.vlan_id)
++      {
++              HASH_PUSH_WORD(cp, entry->key.vlan_id);         // low word
++              HASH_PUSH_WORD(cp, entry->key.pppoe_sid);       // high word
++      }
++
++      HASH_PUSH_BYTE(cp, entry->key.ip_protocol);
++      cp+=3;
++
++      // input (entry->key.sip[i]) is network-oriented
++      // output (hash key) is host-oriented
++      for (i=3; i>=0; i--)
++              HASH_PUSH_BYTE(cp, entry->key.sip[i]);
++
++      // input (entry->key.sip[i]) is network-oriented
++      // output (hash key) is host-oriented
++      for (i=3; i>=0; i--)
++              HASH_PUSH_BYTE(cp, entry->key.dip[i]);
++
++      HASH_PUSH_BYTE(cp, entry->key.l4_bytes[0]);
++      HASH_PUSH_BYTE(cp, entry->key.l4_bytes[1]);
++      HASH_PUSH_BYTE(cp, entry->key.l4_bytes[2]);
++      HASH_PUSH_BYTE(cp, entry->key.l4_bytes[3]);
++
++      // get hash index
++      total = (u32)((u32)cp - (u32)destp) / (sizeof(u32));
++
++      index = hash_gen_crc16((unsigned char *)destp, total * 4);
++      entry->index = index & ((1 << HASH_BITS) - 1);
++
++      cp = (unsigned char *)destp;
++      cp+=3;
++      HASH_PUSH_BYTE(cp, entry->rule);        // rule
++
++      entry->total_dwords = total;
++}
++
++
++/*----------------------------------------------------------------------
++* hash_write_entry
++*----------------------------------------------------------------------*/
++int hash_write_entry(HASH_ENTRY_T *entry, unsigned char *key)
++{
++      int             i;
++      u32             *srcep, *destp, *destp2;
++
++      srcep = (u32 *)key;
++      destp2 = destp = (u32 *)&hash_tables[entry->index][0];
++
++      for (i=0; i<(entry->total_dwords); i++, srcep++, destp++)
++              *destp = *srcep;
++
++      srcep = (u32 *)&entry->action;
++      *destp++ = *srcep;
++
++      srcep = (u32 *)&entry->param;
++      for (i=0; i<(sizeof(ENTRY_PARAM_T)/sizeof(*destp)); i++, srcep++, destp++)
++              *destp = *srcep;
++
++      memset(destp, 0, (HASH_MAX_DWORDS-entry->total_dwords-HASH_ACTION_DWORDS) * sizeof(u32));
++
++      consistent_sync(destp2, (entry->total_dwords+HASH_ACTION_DWORDS) * 4, PCI_DMA_TODEVICE);
++      return 0;
++}
++
++/*----------------------------------------------------------------------
++* hash_timer_func
++*----------------------------------------------------------------------*/
++static void hash_timer_func(u32 data)
++{
++      int                             i, j;
++      volatile u32    *active_p, *own_p, *valid_p;
++      u32                             a_bits, own_bits;
++
++      valid_p = (volatile u32 *)TOE_V_BIT_BASE;
++      active_p = (volatile u32 *)hash_activate_bits;
++      own_p = (volatile u32 *)hash_nat_owner_bits;
++      for (i=0; i<(HASH_TOTAL_ENTRIES/32); i++, own_p++, active_p++, valid_p++)
++      {
++              *active_p |= readl(TOE_A_BIT_BASE + (i*4));
++              a_bits = *active_p;
++              own_bits = *own_p;
++              if (own_bits)
++              {
++#ifndef DEBUG_NAT_MIXED_HW_SW_TX
++                      a_bits = own_bits & ~a_bits;
++#else
++                      a_bits = own_bits & a_bits;
++#endif
++                      for (j=0; a_bits && j<32; j++)
++                      {
++                              if (a_bits & 1)
++                              {
++                                      *valid_p &= ~(1 << j);          // invalidate it
++#if !(defined(NAT_DEBUG_LAN_HASH_TIMEOUT) || defined(NAT_DEBUG_WAN_HASH_TIMEOUT))
++                                      *own_p &= ~(1 << j);            // release ownership for NAT
++#endif
++// #ifdef DEBUG_NAT_MIXED_HW_SW_TX
++#if 0
++                                      hash_printf("%lu %s: Clear hash index: %d\n", jiffies/HZ, __func__, i*32+j);
++#endif
++                              }
++                              a_bits >>= 1;
++                      }
++                      *active_p &= ~own_bits;         // deactivate it for next polling
++              }
++      }
++
++      hash_timer_obj.expires = jiffies + HASH_TIMER_PERIOD;
++      add_timer((struct timer_list *)data);
++}
++
++/*----------------------------------------------------------------------
++* dm_long
++*----------------------------------------------------------------------*/
++void dm_long(u32 location, int length)
++{
++      u32             *start_p, *curr_p, *end_p;
++      u32             *datap, data;
++      int             i;
++
++      //if (length > 1024)
++      //      length = 1024;
++
++      start_p = (u32 *)location;
++      end_p = (u32 *)location + length;
++      curr_p = (u32 *)((u32)location & 0xfffffff0);
++      datap = (u32 *)location;
++      while (curr_p < end_p)
++      {
++              hash_printf("0x%08x: ",(u32)curr_p & 0xfffffff0);
++              for (i=0; i<4; i++)
++              {
++                      if (curr_p < start_p || curr_p >= end_p)
++               hash_printf("         ");
++                      else
++                      {
++                              data = *datap;
++                              hash_printf("%08X ", data);
++                      }
++                      if (i==1)
++              hash_printf("- ");
++
++                      curr_p++;
++                      datap++;
++              }
++        hash_printf("\n");
++      }
++}
++
++/*----------------------------------------------------------------------
++* hash_dump_entry
++*----------------------------------------------------------------------*/
++void hash_dump_entry(int index)
++{
++      hash_printf("Hash Index %d:\n", index);
++      dm_long((u32)&hash_tables[index][0], HASH_MAX_DWORDS);
++}
++
++
+Index: linux-2.6.23.16/drivers/net/sl_switch.c
+===================================================================
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.23.16/drivers/net/sl_switch.c    2008-03-15 17:00:08.364022040 +0200
+@@ -0,0 +1,650 @@
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/ioport.h>
++#include <linux/delay.h>
++#include <asm/hardware.h>
++#include <asm/io.h>
++
++#define GMAC_GLOBAL_BASE_ADDR       (IO_ADDRESS(SL2312_GLOBAL_BASE))
++#define GPIO_BASE_ADDR1  (IO_ADDRESS(SL2312_GPIO_BASE1))
++enum GPIO_REG
++{
++    GPIO_DATA_OUT   = 0x00,
++    GPIO_DATA_IN    = 0x04,
++    GPIO_PIN_DIR    = 0x08,
++    GPIO_BY_PASS    = 0x0c,
++    GPIO_DATA_SET   = 0x10,
++    GPIO_DATA_CLEAR = 0x14,
++};
++
++#define GMAC_SPEED_10                 0
++#define GMAC_SPEED_100                        1
++#define GMAC_SPEED_1000                       2
++
++enum phy_state
++{
++    LINK_DOWN   = 0,
++    LINK_UP     = 1
++};
++
++#ifndef BIT
++#define BIT(x)                                                (1 << (x))
++#endif
++
++//int Get_Set_port_status();
++unsigned int SPI_read_bit(void);
++void SPI_write_bit(char bit_EEDO);
++void SPI_write(unsigned char block,unsigned char subblock,unsigned char addr,unsigned int value);
++unsigned int SPI_read(unsigned char block,unsigned char subblock,unsigned char addr);
++int SPI_default(void);
++void SPI_CS_enable(unsigned char enable);
++unsigned int SPI_get_identifier(void);
++void phy_write(unsigned char port_no,unsigned char reg,unsigned int val);
++unsigned int phy_read(unsigned char port_no,unsigned char reg);
++void phy_write_masked(unsigned char port_no,unsigned char reg,unsigned int val,unsigned int mask);
++void init_seq_7385(unsigned char port_no) ;
++void phy_receiver_init (unsigned char port_no);
++
++#define PORT_NO               4
++int switch_pre_speed[PORT_NO]={0,0,0,0};
++int switch_pre_link[PORT_NO]={0,0,0,0};
++
++
++
++
++
++/*                            NOTES
++ *   The Protocol of the SPI are as follows:
++ *
++ *                       Bit7 Bit6 Bit5 Bit4 Bit3 Bit2 Bit1 Bit0
++ *    byte0     |   Block id  | r/w | sub-block        |
++ *    byte1     |             Address                  |
++ *    byte2     |             Data                     |
++ *    byte3     |             Data                     |
++ *    byte4     |             Data                     |
++ *    byte5     |             Data                     |
++ */
++
++
++
++
++/***************************************/
++/* define GPIO module base address     */
++/***************************************/
++#define GPIO_EECS          0x80000000         /*   EECS: GPIO[22]   */
++#define GPIO_MOSI          0x20000000         /*   EEDO: GPIO[29]   send to 6996*/
++#define GPIO_MISO          0x40000000         /*   EEDI: GPIO[30]   receive from 6996*/
++#define GPIO_EECK          0x10000000         /*   EECK: GPIO[31]   */
++
++/*************************************************************
++* SPI protocol for ADM6996 control
++**************************************************************/
++#define SPI_OP_LEN         0x08               // the length of start bit and opcode
++#define SPI_OPWRITE        0X05               // write
++#define SPI_OPREAD         0X06               // read
++#define SPI_OPERASE        0X07               // erase
++#define SPI_OPWTEN         0X04               // write enable
++#define SPI_OPWTDIS        0X04               // write disable
++#define SPI_OPERSALL       0X04               // erase all
++#define SPI_OPWTALL        0X04               // write all
++
++#define SPI_ADD_LEN        8                  // bits of Address
++#define SPI_DAT_LEN        32                 // bits of Data
++
++
++/****************************************/
++/*    Function Declare                */
++/****************************************/
++
++//unsigned int SPI_read_bit(void);
++//void SPI_write_bit(char bit_EEDO);
++//unsigned int SPI_read_bit(void);
++/******************************************
++* SPI_write
++* addr -> Write Address
++* value -> value to be write
++***************************************** */
++void phy_receiver_init (unsigned char port_no)
++{
++    phy_write(port_no,31,0x2a30);
++    phy_write_masked(port_no, 12, 0x0200, 0x0300);
++    phy_write(port_no,31,0);
++}
++
++void phy_write(unsigned char port_no,unsigned char reg,unsigned int val)
++{
++      unsigned int cmd;
++
++      cmd = (port_no<<21)|(reg<<16)|val;
++      SPI_write(3,0,1,cmd);
++}
++
++unsigned int phy_read(unsigned char port_no,unsigned char reg)
++{
++      unsigned int cmd,reg_val;
++
++      cmd = BIT(26)|(port_no<<21)|(reg<<16);
++      SPI_write(3,0,1,cmd);
++      msleep(2);
++      reg_val = SPI_read(3,0,2);
++      return reg_val;
++}
++
++void phy_write_masked(unsigned char port_no,unsigned char reg,unsigned int val,unsigned int mask)
++{
++      unsigned int cmd,reg_val;
++
++      cmd = BIT(26)|(port_no<<21)|(reg<<16);  // Read reg_val
++      SPI_write(3,0,1,cmd);
++      mdelay(2);
++      reg_val = SPI_read(3,0,2);
++      reg_val &= ~mask;                       // Clear masked bit
++      reg_val |= (val&mask) ;                 // set masked bit ,if true
++      cmd = (port_no<<21)|(reg<<16)|reg_val;
++      SPI_write(3,0,1,cmd);
++}
++
++void init_seq_7385(unsigned char port_no)
++{
++      unsigned char rev;
++
++      phy_write(port_no, 31, 0x2a30);
++      phy_write_masked(port_no, 8, 0x0200, 0x0200);
++      phy_write(port_no, 31, 0x52b5);
++      phy_write(port_no, 16, 0xb68a);
++      phy_write_masked(port_no, 18, 0x0003, 0xff07);
++      phy_write_masked(port_no, 17, 0x00a2, 0x00ff);
++      phy_write(port_no, 16, 0x968a);
++      phy_write(port_no, 31, 0x2a30);
++      phy_write_masked(port_no, 8, 0x0000, 0x0200);
++      phy_write(port_no, 31, 0x0000); /* Read revision */
++      rev = phy_read(port_no, 3) & 0x000f;
++      if (rev == 0)
++      {
++              phy_write(port_no, 31, 0x2a30);
++              phy_write_masked(port_no, 8, 0x0200, 0x0200);
++              phy_write(port_no, 31, 0x52b5);
++              phy_write(port_no, 18, 0x0000);
++              phy_write(port_no, 17, 0x0689);
++              phy_write(port_no, 16, 0x8f92);
++              phy_write(port_no, 31, 0x52B5);
++              phy_write(port_no, 18, 0x0000);
++              phy_write(port_no, 17, 0x0E35);
++              phy_write(port_no, 16, 0x9786);
++              phy_write(port_no, 31, 0x2a30);
++              phy_write_masked(port_no, 8, 0x0000, 0x0200);
++              phy_write(port_no, 23, 0xFF80);
++              phy_write(port_no, 23, 0x0000);
++      }
++      phy_write(port_no, 31, 0x0000);
++      phy_write(port_no, 18, 0x0048);
++      if (rev == 0)
++      {
++              phy_write(port_no, 31, 0x2a30);
++              phy_write(port_no, 20, 0x6600);
++              phy_write(port_no, 31, 0x0000);
++              phy_write(port_no, 24, 0xa24e);
++      }
++      else
++      {
++              phy_write(port_no, 31, 0x2a30);
++              phy_write_masked(port_no, 22, 0x0240, 0x0fc0);
++              phy_write_masked(port_no, 20, 0x4000, 0x6000);
++              phy_write(port_no, 31, 1);
++              phy_write_masked(port_no, 20, 0x6000, 0xe000);
++              phy_write(port_no, 31, 0x0000);
++      }
++}
++
++int Get_Set_port_status()
++{
++      unsigned int    reg_val,ability,rcv_mask,mac_config;
++      int is_link=0;
++      int i;
++
++      rcv_mask = SPI_read(2,0,0x10);                  // Receive mask
++
++      for(i=0;i<4;i++){
++              reg_val = phy_read(i,1);
++              if ((reg_val & 0x0024) == 0x0024) /* link is established and auto_negotiate process completed */
++              {
++                      is_link=1;
++                      if(switch_pre_link[i]==LINK_DOWN){              // Link Down ==> Link up
++
++                              rcv_mask |= BIT(i);                     // Enable receive
++
++                              reg_val = phy_read(i,10);
++                              if(reg_val & 0x0c00){
++                                      printk("Port%d:Giga mode\n",i);
++//                                    SPI_write(1,i,0x00,0x300701B1);
++                                      mac_config = 0x00060004|(6<<6);
++
++                                      SPI_write(1,i,0x00,((mac_config & 0xfffffff8) | 1) | 0x20000030);       // reset port
++                                      mac_config |= (( BIT(i) << 19) | 0x08000000);
++                                      SPI_write(1,i,0x00,mac_config);
++                                      SPI_write(1,i,0x04,0x000300ff);         // flow control
++
++                                      reg_val = SPI_read(5,0,0x12);
++                                      reg_val &= ~BIT(i);
++                                      SPI_write(5,0,0x12,reg_val);
++
++                                      reg_val = SPI_read(1,i,0x00);
++                                      reg_val |= 0x10010000;
++                                      SPI_write(1,i,0x00,reg_val);
++//                                    SPI_write(1,i,0x00,0x10070181);
++                                      switch_pre_link[i]=LINK_UP;
++                                      switch_pre_speed[i]=GMAC_SPEED_1000;
++                              }
++                              else{
++                                      reg_val = phy_read(i,5);
++                                      ability = (reg_val&0x5e0) >>5;
++                                      if ((ability & 0x0C)) /* 100M */
++                                      {
++//                                            SPI_write(1,i,0x00,0x30050472);
++                                              if((ability&0x08)==0)           // Half
++                                                      mac_config = 0x00040004 |(17<<6);
++                                              else                            // Full
++                                                      mac_config = 0x00040004 |(17<<6);
++
++                                              SPI_write(1,i,0x00,((mac_config & 0xfffffff8) | 1) | 0x20000030);       // reset port
++                                              mac_config |= (( BIT(i) << 19) | 0x08000000);
++                                              SPI_write(1,i,0x00,mac_config);
++                                              SPI_write(1,i,0x04,0x000300ff);         // flow control
++
++                                              reg_val = SPI_read(5,0,0x12);
++                                              reg_val &= ~BIT(i);
++                                              SPI_write(5,0,0x12,reg_val);
++
++                                              reg_val = SPI_read(1,i,0x00);
++                                              reg_val &= ~0x08000000;
++                                              reg_val |= 0x10010000;
++                                              SPI_write(1,i,0x00,reg_val);
++//                                            SPI_write(1,i,0x00,0x10050442);
++                                              printk("Port%d:100M\n",i);
++                                              switch_pre_link[i]=LINK_UP;
++                                              switch_pre_speed[i]=GMAC_SPEED_100;
++                                      }
++                                      else if((ability & 0x03)) /* 10M */
++                                      {
++//                                            SPI_write(1,i,0x00,0x30050473);
++                                              if((ability&0x2)==0)            // Half
++                                                      mac_config = 0x00040004 |(17<<6);
++                                              else                            // Full
++                                                      mac_config = 0x00040004 |(17<<6);
++
++                                              SPI_write(1,i,0x00,((mac_config & 0xfffffff8) | 1) | 0x20000030);       // reset port
++                                              mac_config |= (( BIT(i) << 19) | 0x08000000);
++                                              SPI_write(1,i,0x00,mac_config);
++                                              SPI_write(1,i,0x04,0x000300ff);         // flow control
++
++                                              reg_val = SPI_read(5,0,0x12);
++                                              reg_val &= ~BIT(i);
++                                              SPI_write(5,0,0x12,reg_val);
++
++                                              reg_val = SPI_read(1,i,0x00);
++                                              reg_val &= ~0x08000000;
++                                              reg_val |= 0x10010000;
++                                              SPI_write(1,i,0x00,reg_val);
++//                                            SPI_write(1,i,0x00,0x10050443);
++                                              printk("Port%d:10M\n",i);
++                                              switch_pre_link[i]=LINK_UP;
++                                              switch_pre_speed[i]=GMAC_SPEED_10;
++                                      }
++                                      else{
++                                              SPI_write(1,i,0x00,0x20000030);
++                                              printk("Port%d:Unknown mode\n",i);
++                                              switch_pre_link[i]=LINK_DOWN;
++                                              switch_pre_speed[i]=GMAC_SPEED_10;
++                                      }
++                              }
++                      }
++                      else{                                           // Link up ==> Link UP
++
++                      }
++              }
++              else{                                                   // Link Down
++                      if(switch_pre_link[i]==LINK_UP){
++                              printk("Port%d:Link Down\n",i);
++                              //phy_receiver_init(i);
++                              reg_val = SPI_read(1,i,0);
++                              reg_val &= ~BIT(16);
++                              SPI_write(1,i,0x00,reg_val);                    // disable RX
++                              SPI_write(5,0,0x0E,BIT(i));                     // dicard packet
++                              while((SPI_read(5,0,0x0C)&BIT(i))==0)           // wait to be empty
++                                      msleep(1);
++                              SPI_write(1,i,0x00,0x20000030);                 // PORT_RST
++                              SPI_write(5,0,0x0E,SPI_read(5,0,0x0E) & ~BIT(i));// accept packet
++
++                              reg_val = SPI_read(5,0,0x12);
++                              reg_val |= BIT(i);
++                              SPI_write(5,0,0x12,reg_val);
++                      }
++                      switch_pre_link[i]=LINK_DOWN;
++                      rcv_mask &= ~BIT(i);                    // disable receive
++              }
++      }
++
++      SPI_write(2,0,0x10,rcv_mask);                   // Receive mask
++      return is_link;
++
++}
++EXPORT_SYMBOL(Get_Set_port_status);
++
++void SPI_write(unsigned char block,unsigned char subblock,unsigned char addr,unsigned int value)
++{
++      int     i;
++      char    bit;
++      unsigned int data;
++
++      SPI_CS_enable(1);
++
++      data = (block<<5) | 0x10 | subblock;
++
++      //send write command
++      for(i=SPI_OP_LEN-1;i>=0;i--)
++      {
++              bit = (data>>i)& 0x01;
++              SPI_write_bit(bit);
++      }
++
++      // send 8 bits address (MSB first, LSB last)
++      for(i=SPI_ADD_LEN-1;i>=0;i--)
++      {
++              bit = (addr>>i)& 0x01;
++              SPI_write_bit(bit);
++      }
++      // send 32 bits data (MSB first, LSB last)
++      for(i=SPI_DAT_LEN-1;i>=0;i--)
++      {
++              bit = (value>>i)& 0x01;
++              SPI_write_bit(bit);
++      }
++
++      SPI_CS_enable(0);       // CS low
++
++}
++
++
++/************************************
++* SPI_write_bit
++* bit_EEDO -> 1 or 0 to be written
++************************************/
++void SPI_write_bit(char bit_EEDO)
++{
++      unsigned int addr;
++      unsigned int value;
++
++      addr = (GPIO_BASE_ADDR1 + GPIO_PIN_DIR);
++      value = readl(addr) |GPIO_EECK |GPIO_MOSI ;   /* set EECK/MISO Pin to output */
++      writel(value,addr);
++      if(bit_EEDO)
++      {
++              addr = (GPIO_BASE_ADDR1 + GPIO_DATA_SET);
++              writel(GPIO_MOSI,addr); /* set MISO to 1 */
++
++      }
++      else
++      {
++              addr = (GPIO_BASE_ADDR1 + GPIO_DATA_CLEAR);
++              writel(GPIO_MOSI,addr); /* set MISO to 0 */
++      }
++      addr = (GPIO_BASE_ADDR1 + GPIO_DATA_SET);
++      writel(GPIO_EECK,addr); /* set EECK to 1 */
++      addr = (GPIO_BASE_ADDR1 + GPIO_DATA_CLEAR);
++      writel(GPIO_EECK,addr); /* set EECK to 0 */
++
++      //return ;
++}
++
++/**********************************************************************
++* read a bit from ADM6996 register
++***********************************************************************/
++unsigned int SPI_read_bit(void) // read data from
++{
++      unsigned int addr;
++      unsigned int value;
++
++      addr = (GPIO_BASE_ADDR1 + GPIO_PIN_DIR);
++      value = readl(addr) & (~GPIO_MISO);   // set EECK to output and MISO to input
++      writel(value,addr);
++
++      addr =(GPIO_BASE_ADDR1 + GPIO_DATA_SET);
++      writel(GPIO_EECK,addr); // set EECK to 1
++
++
++      addr = (GPIO_BASE_ADDR1 + GPIO_DATA_IN);
++      value = readl(addr) ;
++
++      addr = (GPIO_BASE_ADDR1 + GPIO_DATA_CLEAR);
++      writel(GPIO_EECK,addr); // set EECK to 0
++
++
++      value = value >> 30;
++      return value ;
++}
++
++/******************************************
++* SPI_default
++* EEPROM content default value
++*******************************************/
++int SPI_default(void)
++{
++      int i;
++      unsigned reg_val,cmd;
++
++#if 0
++      SPI_write(7,0,0x1C,0x01);                               // map code space to 0
++
++      reg_val = SPI_read(7,0,0x10);
++      reg_val |= 0x0146;
++      reg_val &= ~0x0001;
++      SPI_write(7,0,0x10,reg_val);                            // reset iCPU and enable ext_access
++      SPI_write(7,0,0x11,0x0000);                             // start address
++      for(i=0;i<sizeof(vts_img);i++){
++              SPI_write(7,0,0x12,vts_img[i]);                 // fill in ROM data
++      }
++      reg_val |= BIT(0)|BIT(3);
++      SPI_write(7,0,0x10,reg_val);                            // release iCPU
++      SPI_write(7,0,0x10,SPI_read(7,0,0x10)&~BIT(7));                         // release iCPU
++      return ;
++#endif
++
++
++      for(i=0;i<15;i++){
++              if(i!=6 && i!=7)
++                      SPI_write(3,2,0,0x1010400+i);           // Initial memory
++              mdelay(1);
++      }
++
++      mdelay(30);
++
++      SPI_write(2,0,0xB0,0x05);                       // Clear MAC table
++      SPI_write(2,0,0xD0,0x03);                       // Clear VLAN
++
++      //for(i=0;i<5;i++)
++      SPI_write(1,6,0x19,0x2C);                       // Double Data rate
++
++      for(i=0;i<4;i++){
++              SPI_write(1,i,0x00,0x30050472);         // MAC configure
++              SPI_write(1,i,0x00,0x10050442);         // MAC configure
++              SPI_write(1,i,0x10,0x5F4);              // Max length
++              SPI_write(1,i,0x04,0x00030000);         // Flow control
++              SPI_write(1,i,0xDF,0x00000001);         // Flow control
++              SPI_write(1,i,0x08,0x000050c2);         // Flow control mac high
++              SPI_write(1,i,0x0C,0x002b00f1);         // Flow control mac low
++              SPI_write(1,i,0x6E,BIT(3));             // forward pause frame
++      }
++      SPI_write(1,i,0x00,0x20000030);                 // set port 4 as reset
++
++      SPI_write(1,6,0x00,0x300701B1);                 // MAC configure
++      SPI_write(1,6,0x00,0x10070181);                 // MAC configure
++      SPI_write(1,6,0x10,0x5F4);                      // Max length
++      SPI_write(1,6,0x04,0x00030000);         // Flow control
++      SPI_write(1,6,0xDF,0x00000002);         // Flow control
++      SPI_write(1,6,0x08,0x000050c2);         // Flow control mac high
++      SPI_write(1,6,0x0C,0x002b00f1);         // Flow control mac low
++      SPI_write(1,6,0x6E,BIT(3));             // forward pause frame
++
++
++      //SPI_write(7,0,0x05,0x31);                     // MII delay for loader
++      //SPI_write(7,0,0x05,0x01);                     // MII delay for kernel
++      SPI_write(7,0,0x05,0x33);
++
++      SPI_write(2,0,0x10,0x4F);                       // Receive mask
++
++      mdelay(50);
++
++      SPI_write(7,0,0x14,0x02);                       // Release Reset
++
++      mdelay(3);
++
++      for(i=0;i<4;i++){
++              init_seq_7385(i);
++              phy_receiver_init(i);
++              cmd = BIT(26)|(i<<21)|(0x1B<<16);       // Config LED
++              SPI_write(3,0,1,cmd);
++              mdelay(10);
++              reg_val = SPI_read(3,0,2);
++              reg_val &= 0xFF00;
++              reg_val |= 0x61;
++              cmd = (i<<21)|(0x1B<<16)|reg_val;
++              SPI_write(3,0,1,cmd);
++
++              cmd = BIT(26)|(i<<21)|(0x04<<16);       // Pause enable
++              SPI_write(3,0,1,cmd);
++              mdelay(10);
++              reg_val = SPI_read(3,0,2);
++              reg_val |= BIT(10)|BIT(11);
++              cmd = (i<<21)|(0x04<<16)|reg_val;
++              SPI_write(3,0,1,cmd);
++
++              cmd = BIT(26)|(i<<21)|(0x0<<16);        // collision test and re-negotiation
++              SPI_write(3,0,1,cmd);
++              mdelay(10);
++              reg_val = SPI_read(3,0,2);
++              reg_val |= BIT(7)|BIT(8)|BIT(9);
++              cmd = (i<<21)|(0x0<<16)|reg_val;
++              SPI_write(3,0,1,cmd);
++      }
++      init_seq_7385(i);
++      writel(0x5787a7f0,GMAC_GLOBAL_BASE_ADDR+0x1c);//For switch timing
++      return 4;               // return port_no
++}
++EXPORT_SYMBOL(SPI_default);
++
++/***********************************************************
++* SPI_CS_enable
++* before access ,you have to enable Chip Select. (pull high)
++* When fisish, you should pull low !!
++*************************************************************/
++void SPI_CS_enable(unsigned char enable)
++{
++
++      unsigned int addr,value;
++
++      addr = (GPIO_BASE_ADDR1 + GPIO_PIN_DIR);
++      value = readl(addr) |GPIO_EECS |GPIO_EECK;   /* set EECS/EECK Pin to output */
++      writel(value,addr);
++
++      if(enable)
++      {
++              addr = (GPIO_BASE_ADDR1 + GPIO_DATA_CLEAR);
++              writel(GPIO_EECK,addr); /* set EECK to 0 */     // pull low clk first
++              addr = (GPIO_BASE_ADDR1 + GPIO_DATA_CLEAR);
++              writel(GPIO_EECS,addr); /* set EECS to 0 */
++
++      }
++      else
++      {
++              addr = (GPIO_BASE_ADDR1 + GPIO_DATA_SET);
++              writel(GPIO_EECK,addr); /* set EECK to 1 */     // pull high clk before disable
++              writel(GPIO_EECS,addr); /* set EECS to 1 */
++      }
++}
++
++
++/************************************************
++* SPI_read
++* table -> which table to be read: 1/count  0/EEPROM
++* addr  -> Address to be read
++* return : Value of the register
++*************************************************/
++unsigned int SPI_read(unsigned char block,unsigned char subblock,unsigned char addr)
++{
++      int     i;
++      char    bit;
++      unsigned int data,value=0;
++
++      SPI_CS_enable(1);
++
++      data = (block<<5) | subblock;
++
++      //send write command
++      for(i=SPI_OP_LEN-1;i>=0;i--)
++      {
++              bit = (data>>i)& 0x01;
++              SPI_write_bit(bit);
++      }
++
++      // send 8 bits address (MSB first, LSB last)
++      for(i=SPI_ADD_LEN-1;i>=0;i--)
++      {
++              bit = (addr>>i)& 0x01;
++              SPI_write_bit(bit);
++      }
++
++      // dummy read for chip ready
++      for(i=0;i<8;i++)
++              SPI_read_bit();
++
++
++      // read 32 bits data (MSB first, LSB last)
++      for(i=SPI_DAT_LEN-1;i>=0;i--)
++      {
++              bit = SPI_read_bit();
++              value |= bit<<i;
++      }
++
++      SPI_CS_enable(0);       // CS low
++      return(value);
++
++}
++
++void pull_low_gpio(unsigned int val)
++{
++
++      unsigned int addr,value;
++
++      addr = (GPIO_BASE_ADDR1 + GPIO_DATA_CLEAR);
++      writel(val,addr); /* set pin low to save power*/
++
++      addr = (GPIO_BASE_ADDR1 + GPIO_PIN_DIR);
++      value = readl(addr) & ~ val;   /* set Pin to input */
++      writel(value,addr);
++
++//    value = readl(GMAC_GLOBAL_BASE_ADDR+0x0C);      // reset GPIO1 module(self clear)
++//    value |= BIT(21);
++//    writel(value,GMAC_GLOBAL_BASE_ADDR+0x0C);
++}
++
++unsigned int SPI_get_identifier(void)
++{
++      unsigned int flag=0;
++
++      SPI_write(7,0,0x01,0x01);
++      flag = SPI_read(7,0,0x18);  // chip id
++      if((flag & 0x0ffff000)==0x07385000){
++              printk("Get VSC-switch ID 0x%08x\n",flag);
++              //Giga_switch = 1;;
++              return 1;
++      }
++      else{
++              printk("VSC-switch not found\n");
++              //Giga_switch = 0;
++              pull_low_gpio(GPIO_EECK|GPIO_MOSI|GPIO_MISO|GPIO_EECS); // reduce power consume
++              return 0;
++      }
++}
++EXPORT_SYMBOL(SPI_get_identifier);
++
+Index: linux-2.6.23.16/include/asm-arm/arch-sl2312/sl351x_gmac.h
+===================================================================
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.23.16/include/asm-arm/arch-sl2312/sl351x_gmac.h  2008-03-15 16:57:25.854761029 +0200
+@@ -0,0 +1,2223 @@
++/****************************************************************************
++* Copyright 2006 StorLink Semiconductors, Inc.  All rights reserved.
++*--------------------------------------------------------------------------
++* Name                        : sl351x_gmac.h
++* Description :
++*             Define for device driver of Storlink SL351x network Engine
++*
++* Historych
++*
++*     Date            Writer          Description
++*     -----------     -----------     -------------------------------------------------
++*     08/22/2005      Gary Chen       Create and implement
++*
++****************************************************************************/
++#ifndef _GMAC_SL351x_H
++#define _GMAC_SL351x_H
++#include <linux/skbuff.h>
++
++#define SL351x_GMAC_WORKAROUND                1
++
++#undef BIG_ENDIAN
++#define BIG_ENDIAN                            0
++#define GMAC_DEBUG                            1
++#define GMAC_NUM                                      2
++//#define     L2_jumbo_frame                          1
++
++#define _PACKED_                                      __attribute__ ((aligned(1), packed))
++
++#ifndef BIT
++#define BIT(x)                                                (1 << (x))
++#endif
++
++#define REG32(addr)                           (*(volatile unsigned long  * const)(addr))
++
++#define DMA_MALLOC(size,handle)               pci_alloc_consistent(NULL,size,handle)
++#define DMA_MFREE(mem,size,handle)    pci_free_consistent(NULL,size,mem,handle)
++
++// Define frame size
++#define ETHER_ADDR_LEN                                6
++#define GMAC_MAX_ETH_FRAME_SIZE               1514
++#define GMAC_TX_BUF_SIZE                      ((GMAC_MAX_ETH_FRAME_SIZE + 31) & (~31))
++#define MAX_ISR_WORK                  20
++
++#ifdef        L2_jumbo_frame
++#define SW_RX_BUF_SIZE                                9234    // 2048 ,9234
++#else
++#define SW_RX_BUF_SIZE                                1536    // 2048
++#endif
++
++#define HW_RX_BUF_SIZE                                1536    // 2048
++
++#define GMAC_DEV_TX_TIMEOUT           (10*HZ)                 //add by CH
++#define       SKB_RESERVE_BYTES                       16
++
++/**********************************************************************
++ * Base Register
++ **********************************************************************/
++#define TOE_BASE                                      (IO_ADDRESS(SL2312_TOE_BASE))
++#define GMAC_GLOBAL_BASE_ADDR       (IO_ADDRESS(SL2312_GLOBAL_BASE))
++
++#define TOE_GLOBAL_BASE                               (TOE_BASE + 0x0000)
++#define TOE_NONTOE_QUE_HDR_BASE               (TOE_BASE + 0x2000)
++#define TOE_TOE_QUE_HDR_BASE          (TOE_BASE + 0x3000)
++#define TOE_V_BIT_BASE                                (TOE_BASE + 0x4000)
++#define TOE_A_BIT_BASE                                (TOE_BASE + 0x6000)
++#define TOE_GMAC0_DMA_BASE                    (TOE_BASE + 0x8000)
++#define TOE_GMAC0_BASE                                (TOE_BASE + 0xA000)
++#define TOE_GMAC1_DMA_BASE                    (TOE_BASE + 0xC000)
++#define TOE_GMAC1_BASE                                (TOE_BASE + 0xE000)
++
++/**********************************************************************
++ * Queue ID
++ **********************************************************************/
++#define TOE_SW_FREE_QID                               0x00
++#define TOE_HW_FREE_QID                               0x01
++#define TOE_GMAC0_SW_TXQ0_QID         0x02
++#define TOE_GMAC0_SW_TXQ1_QID         0x03
++#define TOE_GMAC0_SW_TXQ2_QID         0x04
++#define TOE_GMAC0_SW_TXQ3_QID         0x05
++#define TOE_GMAC0_SW_TXQ4_QID         0x06
++#define TOE_GMAC0_SW_TXQ5_QID         0x07
++#define TOE_GMAC0_HW_TXQ0_QID         0x08
++#define TOE_GMAC0_HW_TXQ1_QID         0x09
++#define TOE_GMAC0_HW_TXQ2_QID         0x0A
++#define TOE_GMAC0_HW_TXQ3_QID         0x0B
++#define TOE_GMAC1_SW_TXQ0_QID         0x12
++#define TOE_GMAC1_SW_TXQ1_QID         0x13
++#define TOE_GMAC1_SW_TXQ2_QID         0x14
++#define TOE_GMAC1_SW_TXQ3_QID         0x15
++#define TOE_GMAC1_SW_TXQ4_QID         0x16
++#define TOE_GMAC1_SW_TXQ5_QID         0x17
++#define TOE_GMAC1_HW_TXQ0_QID         0x18
++#define TOE_GMAC1_HW_TXQ1_QID         0x19
++#define TOE_GMAC1_HW_TXQ2_QID         0x1A
++#define TOE_GMAC1_HW_TXQ3_QID         0x1B
++#define TOE_GMAC0_DEFAULT_QID         0x20
++#define TOE_GMAC1_DEFAULT_QID         0x21
++#define TOE_CLASSIFICATION_QID(x)     (0x22 + x)      // 0x22 ~ 0x2F
++#define TOE_TOE_QID(x)                                (0x40 + x)      // 0x40 ~ 0x7F
++
++/**********************************************************************
++ * TOE DMA Queue Number should be 2^n, n = 6...12
++ * TOE DMA Queues are the following queue types:
++ *            SW Free Queue, HW Free Queue,
++ *            GMAC 0/1 SW TX Q0-5, and GMAC 0/1 HW TX Q0-5
++ * They have same descriptor numbers.
++ * The base address and descriptor number are configured at
++ * DMA Queues Descriptor Ring Base Address/Size Register (offset 0x0004)
++ **********************************************************************/
++#define TOE_SW_FREEQ_DESC_POWER               10
++#define TOE_SW_FREEQ_DESC_NUM         (1<<TOE_SW_FREEQ_DESC_POWER)
++#define TOE_HW_FREEQ_DESC_POWER               8
++#define TOE_HW_FREEQ_DESC_NUM         (1<<TOE_HW_FREEQ_DESC_POWER)
++#define TOE_GMAC0_SWTXQ_DESC_POWER    8
++#define TOE_GMAC0_SWTXQ_DESC_NUM      (1<<TOE_GMAC0_SWTXQ_DESC_POWER)
++#define TOE_GMAC0_HWTXQ_DESC_POWER    8
++#define TOE_GMAC0_HWTXQ_DESC_NUM      (1<<TOE_GMAC0_HWTXQ_DESC_POWER)
++#define TOE_GMAC1_SWTXQ_DESC_POWER    8
++#define TOE_GMAC1_SWTXQ_DESC_NUM      (1<<TOE_GMAC1_SWTXQ_DESC_POWER)
++#define TOE_GMAC1_HWTXQ_DESC_POWER    8
++#define TOE_GMAC1_HWTXQ_DESC_NUM      (1<<TOE_GMAC1_HWTXQ_DESC_POWER)
++#define TOE_DEFAULT_Q0_DESC_POWER     8
++#define TOE_DEFAULT_Q0_DESC_NUM               (1<<TOE_DEFAULT_Q0_DESC_POWER)
++#define TOE_DEFAULT_Q1_DESC_POWER     8
++#define TOE_DEFAULT_Q1_DESC_NUM               (1<<TOE_DEFAULT_Q1_DESC_POWER)
++#define TOE_TOE_DESC_POWER                    8
++#define TOE_TOE_DESC_NUM                      (1<<TOE_TOE_DESC_POWER)
++#define TOE_CLASS_DESC_POWER          8
++#define TOE_CLASS_DESC_NUM                    (1<<TOE_CLASS_DESC_POWER)
++#define TOE_INTR_DESC_POWER                   8
++#define TOE_INTR_DESC_NUM                     (1<<TOE_INTR_DESC_POWER)
++
++#define TOE_TOE_QUEUE_MAX                     64
++#define TOE_TOE_QUEUE_NUM                     64
++#define TOE_CLASS_QUEUE_MAX                   14
++#define TOE_CLASS_QUEUE_NUM                   14
++#define TOE_INTR_QUEUE_MAX                    4
++#define TOE_INTR_QUEUE_NUM                    4
++#define TOE_SW_TXQ_MAX                                6
++#define TOE_SW_TXQ_NUM                                1
++#define TOE_HW_TXQ_MAX                                4
++#define TOE_HW_TXQ_NUM                                4
++#define _max(x,y)                                     ((x>y) ? x :y)
++#define TX_DESC_NUM                                   _max(TOE_GMAC0_SWTXQ_DESC_NUM, TOE_GMAC1_SWTXQ_DESC_NUM)
++
++#define RWPTR_ADVANCE_ONE(x, max)     ((x == (max -1)) ? 0 : x+1)
++#define RWPTR_RECEDE_ONE(x, max)      ((x == 0) ? (max -1) : x-1)
++#define SET_WPTR(addr, data)          (*(volatile u16 * const)((u32)(addr)+2) = (u16)data)
++#define SET_RPTR(addr, data)          (*(volatile u16 * const)((u32)(addr)) = (u16)data)
++
++/**********************************************************************
++ * Global registers
++ * #define TOE_GLOBAL_BASE                    (TOE_BASE + 0x0000)
++ * Base 0x60000000
++ **********************************************************************/
++#define GLOBAL_TOE_VERSION_REG                        0x0000
++#define GLOBAL_SW_FREEQ_BASE_SIZE_REG 0x0004
++#define GLOBAL_HW_FREEQ_BASE_SIZE_REG 0x0008
++#define GLOBAL_DMA_SKB_SIZE_REG                       0x0010
++#define GLOBAL_SWFQ_RWPTR_REG                 0x0014
++#define GLOBAL_HWFQ_RWPTR_REG                 0x0018
++#define GLOBAL_INTERRUPT_STATUS_0_REG 0x0020
++#define GLOBAL_INTERRUPT_ENABLE_0_REG 0x0024
++#define GLOBAL_INTERRUPT_SELECT_0_REG 0x0028
++#define GLOBAL_INTERRUPT_STATUS_1_REG 0x0030
++#define GLOBAL_INTERRUPT_ENABLE_1_REG 0x0034
++#define GLOBAL_INTERRUPT_SELECT_1_REG 0x0038
++#define GLOBAL_INTERRUPT_STATUS_2_REG 0x0040
++#define GLOBAL_INTERRUPT_ENABLE_2_REG 0x0044
++#define GLOBAL_INTERRUPT_SELECT_2_REG 0x0048
++#define GLOBAL_INTERRUPT_STATUS_3_REG 0x0050
++#define GLOBAL_INTERRUPT_ENABLE_3_REG 0x0054
++#define GLOBAL_INTERRUPT_SELECT_3_REG 0x0058
++#define GLOBAL_INTERRUPT_STATUS_4_REG 0x0060
++#define GLOBAL_INTERRUPT_ENABLE_4_REG 0x0064
++#define GLOBAL_INTERRUPT_SELECT_4_REG 0x0068
++#define GLOBAL_HASH_TABLE_BASE_REG            0x006C
++#define GLOBAL_QUEUE_THRESHOLD_REG            0x0070
++
++/**********************************************************************
++ * GMAC 0/1 DMA/TOE register
++ * #define TOE_GMAC0_DMA_BASE         (TOE_BASE + 0x8000)
++ * #define TOE_GMAC1_DMA_BASE         (TOE_BASE + 0xC000)
++ * Base 0x60008000 or 0x6000C000
++ **********************************************************************/
++#define GMAC_DMA_CTRL_REG                             0x0000
++#define GMAC_TX_WEIGHTING_CTRL_0_REG  0x0004
++#define GMAC_TX_WEIGHTING_CTRL_1_REG  0x0008
++#define GMAC_SW_TX_QUEUE0_PTR_REG             0x000C
++#define GMAC_SW_TX_QUEUE1_PTR_REG             0x0010
++#define GMAC_SW_TX_QUEUE2_PTR_REG             0x0014
++#define GMAC_SW_TX_QUEUE3_PTR_REG             0x0018
++#define GMAC_SW_TX_QUEUE4_PTR_REG             0x001C
++#define GMAC_SW_TX_QUEUE5_PTR_REG             0x0020
++#define GMAC_HW_TX_QUEUE0_PTR_REG             0x0024
++#define GMAC_HW_TX_QUEUE1_PTR_REG             0x0028
++#define GMAC_HW_TX_QUEUE2_PTR_REG             0x002C
++#define GMAC_HW_TX_QUEUE3_PTR_REG             0x0030
++#define GMAC_DMA_TX_FIRST_DESC_REG            0x0038
++#define GMAC_DMA_TX_CURR_DESC_REG             0x003C
++#define GMAC_DMA_TX_DESC_WORD0_REG            0x0040
++#define GMAC_DMA_TX_DESC_WORD1_REG            0x0044
++#define GMAC_DMA_TX_DESC_WORD2_REG            0x0048
++#define GMAC_DMA_TX_DESC_WORD3_REG            0x004C
++#define GMAC_SW_TX_QUEUE_BASE_REG             0x0050
++#define GMAC_HW_TX_QUEUE_BASE_REG             0x0054
++#define GMAC_DMA_RX_FIRST_DESC_REG            0x0058
++#define GMAC_DMA_RX_CURR_DESC_REG             0x005C
++#define GMAC_DMA_RX_DESC_WORD0_REG            0x0060
++#define GMAC_DMA_RX_DESC_WORD1_REG            0x0064
++#define GMAC_DMA_RX_DESC_WORD2_REG            0x0068
++#define GMAC_DMA_RX_DESC_WORD3_REG            0x006C
++#define GMAC_HASH_ENGINE_REG0                 0x0070
++#define GMAC_HASH_ENGINE_REG1                 0x0074
++#define GMAC_MR0CR0                                           0x0078  // matching rule 0 Control register 0
++#define GMAC_MR0CR1                                           0x007C  // matching rule 0 Control register 1
++#define GMAC_MR0CR2                                           0x0080  // matching rule 0 Control register 2
++#define GMAC_MR1CR0                                           0x0084  // matching rule 1 Control register 0
++#define GMAC_MR1CR1                                           0x0088  // matching rule 1 Control register 1
++#define GMAC_MR1CR2                                           0x008C  // matching rule 1 Control register 2
++#define GMAC_MR2CR0                                           0x0090  // matching rule 2 Control register 0
++#define GMAC_MR2CR1                                           0x0094  // matching rule 2 Control register 1
++#define GMAC_MR2CR2                                           0x0098  // matching rule 2 Control register 2
++#define GMAC_MR3CR0                                           0x009C  // matching rule 3 Control register 0
++#define GMAC_MR3CR1                                           0x00A0  // matching rule 3 Control register 1
++#define GMAC_MR3CR2                                           0x00A4  // matching rule 3 Control register 2
++#define GMAC_SPR0                                             0x00A8  // Support Protocol Regsister 0
++#define GMAC_SPR1                                             0x00AC  // Support Protocol Regsister 1
++#define GMAC_SPR2                                             0x00B0  // Support Protocol Regsister 2
++#define GMAC_SPR3                                             0x00B4  // Support Protocol Regsister 3
++#define GMAC_SPR4                                             0x00B8  // Support Protocol Regsister 4
++#define GMAC_SPR5                                             0x00BC  // Support Protocol Regsister 5
++#define GMAC_SPR6                                             0x00C0  // Support Protocol Regsister 6
++#define GMAC_SPR7                                             0x00C4  // Support Protocol Regsister 7
++#define GMAC_AHB_WEIGHT_REG                           0x00C8  // GMAC Hash/Rx/Tx AHB Weighting register
++
++/**********************************************************************
++ * TOE GMAC 0/1 register
++ * #define TOE_GMAC0_BASE                             (TOE_BASE + 0xA000)
++ * #define TOE_GMAC1_BASE                             (TOE_BASE + 0xE000)
++ * Base 0x6000A000 or 0x6000E000
++ **********************************************************************/
++enum GMAC_REGISTER {
++      GMAC_STA_ADD0   = 0x0000,
++      GMAC_STA_ADD1   = 0x0004,
++      GMAC_STA_ADD2   = 0x0008,
++      GMAC_RX_FLTR    = 0x000c,
++      GMAC_MCAST_FIL0 = 0x0010,
++      GMAC_MCAST_FIL1 = 0x0014,
++      GMAC_CONFIG0    = 0x0018,
++      GMAC_CONFIG1    = 0x001c,
++      GMAC_CONFIG2    = 0x0020,
++      GMAC_CONFIG3    = 0x0024,
++      GMAC_RESERVED   = 0x0028,
++      GMAC_STATUS             = 0x002c,
++      GMAC_IN_DISCARDS= 0x0030,
++      GMAC_IN_ERRORS  = 0x0034,
++      GMAC_IN_MCAST   = 0x0038,
++      GMAC_IN_BCAST   = 0x003c,
++      GMAC_IN_MAC1    = 0x0040,       // for STA 1 MAC Address
++      GMAC_IN_MAC2    = 0x0044        // for STA 2 MAC Address
++};
++/**********************************************************************
++ * TOE version Register (offset 0x0000)
++ **********************************************************************/
++typedef union
++{
++      unsigned int bits32;
++      struct bit
++      {
++#if (BIG_ENDIAN==1)
++
++              unsigned int reserved           : 15;   // bit 31:17
++              unsigned int v_bit_mode         : 1;    // bit 16               1: 128-entry
++              unsigned int device_id          : 12;   // bit 15:4     Device ID
++              unsigned int revision_id        : 4;    // bit  3:0     Revision ID
++#else
++              unsigned int revision_id        : 4;    // bit  3:0     Revision ID
++              unsigned int device_id          : 12;   // bit 15:4     Device ID
++              unsigned int v_bit_mode         : 1;    // bit 16               1: 128-entry
++              unsigned int reserved           : 15;   // bit 31:17
++#endif
++      } bits;
++} TOE_VERSION_T;
++
++
++/**********************************************************************
++ * DMA Queues description Ring Base Address/Size Register (offset 0x0004)
++ **********************************************************************/
++typedef union
++{
++      unsigned int bits32;
++      unsigned int base_size;
++} DMA_Q_BASE_SIZE_T;
++#define DMA_Q_BASE_MASK       (~0x0f)
++
++/**********************************************************************
++ * DMA SKB Buffer register (offset 0x0008)
++ **********************************************************************/
++typedef union
++{
++      unsigned int bits32;
++      struct bit_0008
++      {
++#if (BIG_ENDIAN==1)
++
++              unsigned int hw_skb_size        : 16;   // bit 31:16    HW Free poll SKB Size
++              unsigned int sw_skb_size        : 16;   // bit 15:0     SW Free poll SKB Size
++#else
++              unsigned int sw_skb_size        : 16;   // bit 15:0     SW Free poll SKB Size
++              unsigned int hw_skb_size        : 16;   // bit 31:16    HW Free poll SKB Size
++#endif
++      } bits;
++} DMA_SKB_SIZE_T;
++
++/**********************************************************************
++ * DMA SW Free Queue Read/Write Pointer Register (offset 0x000C)
++ **********************************************************************/
++typedef union
++{
++      unsigned int bits32;
++      struct bit_000c
++      {
++#if (BIG_ENDIAN==1)
++
++              unsigned int wptr                       : 16;   // bit 31:16    Write Ptr, RW
++              unsigned int rptr                       : 16;   // bit 15:0             Read Ptr, RO
++#else
++              unsigned int rptr                       : 16;   // bit 15:0             Read Ptr, RO
++              unsigned int wptr                       : 16;   // bit 31:16    Write Ptr, RW
++#endif
++      } bits;
++} DMA_RWPTR_T;
++
++/**********************************************************************
++ * DMA HW Free Queue Read/Write Pointer Register (offset 0x0010)
++ **********************************************************************/
++// see DMA_RWPTR_T structure
++
++/**********************************************************************
++ * Interrupt Status Register 0        (offset 0x0020)
++ * Interrupt Mask Register 0  (offset 0x0024)
++ * Interrupt Select Register 0        (offset 0x0028)
++ **********************************************************************/
++typedef union
++{
++      unsigned int bits32;
++      struct bit_0020
++      {
++#if (BIG_ENDIAN==1)
++              unsigned int txDerr1            : 1;    // bit 31       GMAC1 AHB Bus Error while Tx
++              unsigned int txPerr1            : 1;    // bit 30       GMAC1 Tx Descriptor Protocol Error
++              unsigned int txDerr0            : 1;    // bit 29       GMAC0 AHB Bus Error while Tx
++              unsigned int txPerr0            : 1;    // bit 28       GMAC0 Tx Descriptor Protocol Error
++              unsigned int rxDerr1            : 1;    // bit 27       GMAC1 AHB Bus Error while Rx
++              unsigned int rxPerr1            : 1;    // bit 26       GMAC1 Rx Descriptor Protocol Error
++              unsigned int rxDerr0            : 1;    // bit 25       GMAC0 AHB Bus Error while Rx
++              unsigned int rxPerr0            : 1;    // bit 24       GMAC0 Rx Descriptor Protocol Error
++              unsigned int swtq15_fin         : 1;    // bit 23       GMAC1 SW Tx Queue 5 Finish Interrupt
++              unsigned int swtq14_fin         : 1;    // bit 22       GMAC1 SW Tx Queue 4 Finish Interrupt
++              unsigned int swtq13_fin         : 1;    // bit 21       GMAC1 SW Tx Queue 3 Finish Interrupt
++              unsigned int swtq12_fin         : 1;    // bit 20       GMAC1 SW Tx Queue 2 Finish Interrupt
++              unsigned int swtq11_fin         : 1;    // bit 19       GMAC1 SW Tx Queue 1 Finish Interrupt
++              unsigned int swtq10_fin         : 1;    // bit 18       GMAC1 SW Tx Queue 0 Finish Interrupt
++              unsigned int swtq05_fin         : 1;    // bit 17       GMAC0 SW Tx Queue 5 Finish Interrupt
++              unsigned int swtq04_fin         : 1;    // bit 16       GMAC0 SW Tx Queue 4 Finish Interrupt
++              unsigned int swtq03_fin         : 1;    // bit 15       GMAC0 SW Tx Queue 3 Finish Interrupt
++              unsigned int swtq02_fin         : 1;    // bit 14       GMAC0 SW Tx Queue 2 Finish Interrupt
++              unsigned int swtq01_fin         : 1;    // bit 13       GMAC0 SW Tx Queue 1 Finish Interrupt
++              unsigned int swtq00_fin         : 1;    // bit 12       GMAC0 SW Tx Queue 0 Finish Interrupt
++              unsigned int swtq15_eof         : 1;    // bit 11       GMAC1 SW Tx Queue 5 EOF Interrupt
++              unsigned int swtq14_eof         : 1;    // bit 10       GMAC1 SW Tx Queue 4 EOF Interrupt
++              unsigned int swtq13_eof         : 1;    // bit 9        GMAC1 SW Tx Queue 3 EOF Interrupt
++              unsigned int swtq12_eof         : 1;    // bit 8        GMAC1 SW Tx Queue 2 EOF Interrupt
++              unsigned int swtq11_eof         : 1;    // bit 7        GMAC1 SW Tx Queue 1 EOF Interrupt
++              unsigned int swtq10_eof         : 1;    // bit 6        GMAC1 SW Tx Queue 0 EOF Interrupt
++              unsigned int swtq05_eof         : 1;    // bit 5        GMAC0 SW Tx Queue 5 EOF Interrupt
++              unsigned int swtq04_eof         : 1;    // bit 4        GMAC0 SW Tx Queue 4 EOF Interrupt
++              unsigned int swtq03_eof         : 1;    // bit 3        GMAC0 SW Tx Queue 3 EOF Interrupt
++              unsigned int swtq02_eof         : 1;    // bit 2        GMAC0 SW Tx Queue 2 EOF Interrupt
++              unsigned int swtq01_eof         : 1;    // bit 1        GMAC0 SW Tx Queue 1 EOF Interrupt
++              unsigned int swtq00_eof         : 1;    // bit 0        GMAC0 SW Tx Queue 0 EOF Interrupt
++#else
++              unsigned int swtq00_eof         : 1;    // bit 0        GMAC0 SW Tx Queue 0 EOF Interrupt
++              unsigned int swtq01_eof         : 1;    // bit 1        GMAC0 SW Tx Queue 1 EOF Interrupt
++              unsigned int swtq02_eof         : 1;    // bit 2        GMAC0 SW Tx Queue 2 EOF Interrupt
++              unsigned int swtq03_eof         : 1;    // bit 3        GMAC0 SW Tx Queue 3 EOF Interrupt
++              unsigned int swtq04_eof         : 1;    // bit 4        GMAC0 SW Tx Queue 4 EOF Interrupt
++              unsigned int swtq05_eof         : 1;    // bit 5        GMAC0 SW Tx Queue 5 EOF Interrupt
++              unsigned int swtq10_eof         : 1;    // bit 6        GMAC1 SW Tx Queue 0 EOF Interrupt
++              unsigned int swtq11_eof         : 1;    // bit 7        GMAC1 SW Tx Queue 1 EOF Interrupt
++              unsigned int swtq12_eof         : 1;    // bit 8        GMAC1 SW Tx Queue 2 EOF Interrupt
++              unsigned int swtq13_eof         : 1;    // bit 9        GMAC1 SW Tx Queue 3 EOF Interrupt
++              unsigned int swtq14_eof         : 1;    // bit 10       GMAC1 SW Tx Queue 4 EOF Interrupt
++              unsigned int swtq15_eof         : 1;    // bit 11       GMAC1 SW Tx Queue 5 EOF Interrupt
++              unsigned int swtq00_fin         : 1;    // bit 12       GMAC0 SW Tx Queue 0 Finish Interrupt
++              unsigned int swtq01_fin         : 1;    // bit 13       GMAC0 SW Tx Queue 1 Finish Interrupt
++              unsigned int swtq02_fin         : 1;    // bit 14       GMAC0 SW Tx Queue 2 Finish Interrupt
++              unsigned int swtq03_fin         : 1;    // bit 15       GMAC0 SW Tx Queue 3 Finish Interrupt
++              unsigned int swtq04_fin         : 1;    // bit 16       GMAC0 SW Tx Queue 4 Finish Interrupt
++              unsigned int swtq05_fin         : 1;    // bit 17       GMAC0 SW Tx Queue 5 Finish Interrupt
++              unsigned int swtq10_fin         : 1;    // bit 18       GMAC1 SW Tx Queue 0 Finish Interrupt
++              unsigned int swtq11_fin         : 1;    // bit 19       GMAC1 SW Tx Queue 1 Finish Interrupt
++              unsigned int swtq12_fin         : 1;    // bit 20       GMAC1 SW Tx Queue 2 Finish Interrupt
++              unsigned int swtq13_fin         : 1;    // bit 21       GMAC1 SW Tx Queue 3 Finish Interrupt
++              unsigned int swtq14_fin         : 1;    // bit 22       GMAC1 SW Tx Queue 4 Finish Interrupt
++              unsigned int swtq15_fin         : 1;    // bit 23       GMAC1 SW Tx Queue 5 Finish Interrupt
++              unsigned int rxPerr0            : 1;    // bit 24       GMAC0 Rx Descriptor Protocol Error
++              unsigned int rxDerr0            : 1;    // bit 25       GMAC0 AHB Bus Error while Rx
++              unsigned int rxPerr1            : 1;    // bit 26       GMAC1 Rx Descriptor Protocol Error
++              unsigned int rxDerr1            : 1;    // bit 27       GMAC1 AHB Bus Error while Rx
++              unsigned int txPerr0            : 1;    // bit 28       GMAC0 Tx Descriptor Protocol Error
++              unsigned int txDerr0            : 1;    // bit 29       GMAC0 AHB Bus Error while Tx
++              unsigned int txPerr1            : 1;    // bit 30       GMAC1 Tx Descriptor Protocol Error
++              unsigned int txDerr1            : 1;    // bit 31       GMAC1 AHB Bus Error while Tx
++#endif
++      } bits;
++} INTR_REG0_T;
++
++#define GMAC1_TXDERR_INT_BIT          BIT(31)
++#define GMAC1_TXPERR_INT_BIT          BIT(30)
++#define GMAC0_TXDERR_INT_BIT          BIT(29)
++#define GMAC0_TXPERR_INT_BIT          BIT(28)
++#define GMAC1_RXDERR_INT_BIT          BIT(27)
++#define GMAC1_RXPERR_INT_BIT          BIT(26)
++#define GMAC0_RXDERR_INT_BIT          BIT(25)
++#define GMAC0_RXPERR_INT_BIT          BIT(24)
++#define GMAC1_SWTQ15_FIN_INT_BIT      BIT(23)
++#define GMAC1_SWTQ14_FIN_INT_BIT      BIT(22)
++#define GMAC1_SWTQ13_FIN_INT_BIT      BIT(21)
++#define GMAC1_SWTQ12_FIN_INT_BIT      BIT(20)
++#define GMAC1_SWTQ11_FIN_INT_BIT      BIT(19)
++#define GMAC1_SWTQ10_FIN_INT_BIT      BIT(18)
++#define GMAC0_SWTQ05_FIN_INT_BIT      BIT(17)
++#define GMAC0_SWTQ04_FIN_INT_BIT      BIT(16)
++#define GMAC0_SWTQ03_FIN_INT_BIT      BIT(15)
++#define GMAC0_SWTQ02_FIN_INT_BIT      BIT(14)
++#define GMAC0_SWTQ01_FIN_INT_BIT      BIT(13)
++#define GMAC0_SWTQ00_FIN_INT_BIT      BIT(12)
++#define GMAC1_SWTQ15_EOF_INT_BIT      BIT(11)
++#define GMAC1_SWTQ14_EOF_INT_BIT      BIT(10)
++#define GMAC1_SWTQ13_EOF_INT_BIT      BIT(9)
++#define GMAC1_SWTQ12_EOF_INT_BIT      BIT(8)
++#define GMAC1_SWTQ11_EOF_INT_BIT      BIT(7)
++#define GMAC1_SWTQ10_EOF_INT_BIT      BIT(6)
++#define GMAC0_SWTQ05_EOF_INT_BIT      BIT(5)
++#define GMAC0_SWTQ04_EOF_INT_BIT      BIT(4)
++#define GMAC0_SWTQ03_EOF_INT_BIT      BIT(3)
++#define GMAC0_SWTQ02_EOF_INT_BIT      BIT(2)
++#define GMAC0_SWTQ01_EOF_INT_BIT      BIT(1)
++#define GMAC0_SWTQ00_EOF_INT_BIT      BIT(0)
++
++
++/**********************************************************************
++ * Interrupt Status Register 1        (offset 0x0030)
++ * Interrupt Mask Register 1  (offset 0x0034)
++ * Interrupt Select Register 1        (offset 0x0038)
++ **********************************************************************/
++typedef union
++{
++      unsigned int bits32;
++      struct bit_0030
++      {
++#if (BIG_ENDIAN==1)
++              unsigned int toe_iq3_full       : 1;    // bit 31       TOE Interrupt Queue 3 Full Interrupt
++              unsigned int toe_iq2_full       : 1;    // bit 30       TOE Interrupt Queue 2 Full Interrupt
++              unsigned int toe_iq1_full       : 1;    // bit 29       TOE Interrupt Queue 1 Full Interrupt
++              unsigned int toe_iq0_full       : 1;    // bit 28       TOE Interrupt Queue 0 Full Interrupt
++              unsigned int toe_iq3_intr       : 1;    // bit 27       TOE Interrupt Queue 3 with Interrupts
++              unsigned int toe_iq2_intr       : 1;    // bit 26       TOE Interrupt Queue 2 with Interrupts
++              unsigned int toe_iq1_intr       : 1;    // bit 25       TOE Interrupt Queue 1 with Interrupts
++              unsigned int toe_iq0_intr       : 1;    // bit 24       TOE Interrupt Queue 0 with Interrupts
++              unsigned int hwtq13_eof         : 1;    // bit 23       GMAC1 HW Tx Queue3 EOF Interrupt
++              unsigned int hwtq12_eof         : 1;    // bit 22       GMAC1 HW Tx Queue2 EOF Interrupt
++              unsigned int hwtq11_eof         : 1;    // bit 21       GMAC1 HW Tx Queue1 EOF Interrupt
++              unsigned int hwtq10_eof         : 1;    // bit 20       GMAC1 HW Tx Queue0 EOF Interrupt
++              unsigned int hwtq03_eof         : 1;    // bit 19       GMAC0 HW Tx Queue3 EOF Interrupt
++              unsigned int hwtq02_eof         : 1;    // bit 18       GMAC0 HW Tx Queue2 EOF Interrupt
++              unsigned int hwtq01_eof         : 1;    // bit 17       GMAC0 HW Tx Queue1 EOF Interrupt
++              unsigned int hwtq00_eof         : 1;    // bit 16       GMAC0 HW Tx Queue0 EOF Interrupt
++              unsigned int class_rx           : 14;   // bit 15:2     Classification Queue Rx Interrupt
++              unsigned int default_q1_eof     : 1;    // bit 1        Default Queue 1 EOF Interrupt
++              unsigned int default_q0_eof     : 1;    // bit 0        Default Queue 0 EOF Interrupt
++#else
++              unsigned int default_q0_eof     : 1;    // bit 0        Default Queue 0 EOF Interrupt
++              unsigned int default_q1_eof     : 1;    // bit 1        Default Queue 1 EOF Interrupt
++              unsigned int class_rx           : 14;   // bit 15:2     Classification Queue Rx Interrupt
++              unsigned int hwtq00_eof         : 1;    // bit 16       GMAC0 HW Tx Queue0 EOF Interrupt
++              unsigned int hwtq01_eof         : 1;    // bit 17       GMAC0 HW Tx Queue1 EOF Interrupt
++              unsigned int hwtq02_eof         : 1;    // bit 18       GMAC0 HW Tx Queue2 EOF Interrupt
++              unsigned int hwtq03_eof         : 1;    // bit 19       GMAC0 HW Tx Queue3 EOF Interrupt
++              unsigned int hwtq10_eof         : 1;    // bit 20       GMAC1 HW Tx Queue0 EOF Interrupt
++              unsigned int hwtq11_eof         : 1;    // bit 21       GMAC1 HW Tx Queue1 EOF Interrupt
++              unsigned int hwtq12_eof         : 1;    // bit 22       GMAC1 HW Tx Queue2 EOF Interrupt
++              unsigned int hwtq13_eof         : 1;    // bit 23       GMAC1 HW Tx Queue3 EOF Interrupt
++              unsigned int toe_iq0_intr       : 1;    // bit 24       TOE Interrupt Queue 0 with Interrupts
++              unsigned int toe_iq1_intr       : 1;    // bit 25       TOE Interrupt Queue 1 with Interrupts
++              unsigned int toe_iq2_intr       : 1;    // bit 26       TOE Interrupt Queue 2 with Interrupts
++              unsigned int toe_iq3_intr       : 1;    // bit 27       TOE Interrupt Queue 3 with Interrupts
++              unsigned int toe_iq0_full       : 1;    // bit 28       TOE Interrupt Queue 0 Full Interrupt
++              unsigned int toe_iq1_full       : 1;    // bit 29       TOE Interrupt Queue 1 Full Interrupt
++              unsigned int toe_iq2_full       : 1;    // bit 30       TOE Interrupt Queue 2 Full Interrupt
++              unsigned int toe_iq3_full       : 1;    // bit 31       TOE Interrupt Queue 3 Full Interrupt
++#endif
++      } bits;
++} INTR_REG1_T;
++
++#define TOE_IQ3_FULL_INT_BIT          BIT(31)
++#define TOE_IQ2_FULL_INT_BIT          BIT(30)
++#define TOE_IQ1_FULL_INT_BIT          BIT(29)
++#define TOE_IQ0_FULL_INT_BIT          BIT(28)
++#define TOE_IQ3_INT_BIT                               BIT(27)
++#define TOE_IQ2_INT_BIT                               BIT(26)
++#define TOE_IQ1_INT_BIT                               BIT(25)
++#define TOE_IQ0_INT_BIT                               BIT(24)
++#define GMAC1_HWTQ13_EOF_INT_BIT      BIT(23)
++#define GMAC1_HWTQ12_EOF_INT_BIT      BIT(22)
++#define GMAC1_HWTQ11_EOF_INT_BIT      BIT(21)
++#define GMAC1_HWTQ10_EOF_INT_BIT      BIT(20)
++#define GMAC0_HWTQ03_EOF_INT_BIT      BIT(19)
++#define GMAC0_HWTQ02_EOF_INT_BIT      BIT(18)
++#define GMAC0_HWTQ01_EOF_INT_BIT      BIT(17)
++#define GMAC0_HWTQ00_EOF_INT_BIT      BIT(16)
++#define CLASS_RX_INT_BIT(x)                   BIT((x+2))
++#define DEFAULT_Q1_INT_BIT                    BIT(1)
++#define DEFAULT_Q0_INT_BIT                    BIT(0)
++
++#define TOE_IQ_INT_BITS                               (TOE_IQ0_INT_BIT | TOE_IQ1_INT_BIT | \
++                                                      TOE_IQ2_INT_BIT | TOE_IQ3_INT_BIT)
++#define       TOE_IQ_FULL_BITS                        (TOE_IQ0_FULL_INT_BIT | TOE_IQ1_FULL_INT_BIT | \
++                                                      TOE_IQ2_FULL_INT_BIT | TOE_IQ3_FULL_INT_BIT)
++#define       TOE_IQ_ALL_BITS                         (TOE_IQ_INT_BITS | TOE_IQ_FULL_BITS)
++#define TOE_CLASS_RX_INT_BITS         0xfffc
++
++/**********************************************************************
++ * Interrupt Status Register 2        (offset 0x0040)
++ * Interrupt Mask Register 2  (offset 0x0044)
++ * Interrupt Select Register 2        (offset 0x0048)
++ **********************************************************************/
++typedef union
++{
++      unsigned int bits32;
++      struct bit_0040
++      {
++#if (BIG_ENDIAN==1)
++              unsigned int toe_q31_full       : 1;    // bit 31       TOE Queue 31 Full Interrupt
++              unsigned int toe_q30_full       : 1;    // bit 30       TOE Queue 30 Full Interrupt
++              unsigned int toe_q29_full       : 1;    // bit 29       TOE Queue 29 Full Interrupt
++              unsigned int toe_q28_full       : 1;    // bit 28       TOE Queue 28 Full Interrupt
++              unsigned int toe_q27_full       : 1;    // bit 27       TOE Queue 27 Full Interrupt
++              unsigned int toe_q26_full       : 1;    // bit 26       TOE Queue 26 Full Interrupt
++              unsigned int toe_q25_full       : 1;    // bit 25       TOE Queue 25 Full Interrupt
++              unsigned int toe_q24_full       : 1;    // bit 24       TOE Queue 24 Full Interrupt
++              unsigned int toe_q23_full       : 1;    // bit 23       TOE Queue 23 Full Interrupt
++              unsigned int toe_q22_full       : 1;    // bit 22       TOE Queue 22 Full Interrupt
++              unsigned int toe_q21_full       : 1;    // bit 21       TOE Queue 21 Full Interrupt
++              unsigned int toe_q20_full       : 1;    // bit 20       TOE Queue 20 Full Interrupt
++              unsigned int toe_q19_full       : 1;    // bit 19       TOE Queue 19 Full Interrupt
++              unsigned int toe_q18_full       : 1;    // bit 18       TOE Queue 18 Full Interrupt
++              unsigned int toe_q17_full       : 1;    // bit 17       TOE Queue 17 Full Interrupt
++              unsigned int toe_q16_full       : 1;    // bit 16       TOE Queue 16 Full Interrupt
++              unsigned int toe_q15_full       : 1;    // bit 15       TOE Queue 15 Full Interrupt
++              unsigned int toe_q14_full       : 1;    // bit 14       TOE Queue 14 Full Interrupt
++              unsigned int toe_q13_full       : 1;    // bit 13       TOE Queue 13 Full Interrupt
++              unsigned int toe_q12_full       : 1;    // bit 12       TOE Queue 12 Full Interrupt
++              unsigned int toe_q11_full       : 1;    // bit 11       TOE Queue 11 Full Interrupt
++              unsigned int toe_q10_full       : 1;    // bit 10       TOE Queue 10 Full Interrupt
++              unsigned int toe_q9_full        : 1;    // bit 9        TOE Queue 9 Full Interrupt
++              unsigned int toe_q8_full        : 1;    // bit 8        TOE Queue 8 Full Interrupt
++              unsigned int toe_q7_full        : 1;    // bit 7        TOE Queue 7 Full Interrupt
++              unsigned int toe_q6_full        : 1;    // bit 6        TOE Queue 6 Full Interrupt
++              unsigned int toe_q5_full        : 1;    // bit 5        TOE Queue 5 Full Interrupt
++              unsigned int toe_q4_full        : 1;    // bit 4        TOE Queue 4 Full Interrupt
++              unsigned int toe_q3_full        : 1;    // bit 3        TOE Queue 3 Full Interrupt
++              unsigned int toe_q2_full        : 1;    // bit 2        TOE Queue 2 Full Interrupt
++              unsigned int toe_q1_full        : 1;    // bit 1        TOE Queue 1 Full Interrupt
++              unsigned int toe_q0_full        : 1;    // bit 0        TOE Queue 0 Full Interrupt
++#else
++              unsigned int toe_q0_full        : 1;    // bit 0        TOE Queue 0 Full Interrupt
++              unsigned int toe_q1_full        : 1;    // bit 1        TOE Queue 1 Full Interrupt
++              unsigned int toe_q2_full        : 1;    // bit 2        TOE Queue 2 Full Interrupt
++              unsigned int toe_q3_full        : 1;    // bit 3        TOE Queue 3 Full Interrupt
++              unsigned int toe_q4_full        : 1;    // bit 4        TOE Queue 4 Full Interrupt
++              unsigned int toe_q5_full        : 1;    // bit 5        TOE Queue 5 Full Interrupt
++              unsigned int toe_q6_full        : 1;    // bit 6        TOE Queue 6 Full Interrupt
++              unsigned int toe_q7_full        : 1;    // bit 7        TOE Queue 7 Full Interrupt
++              unsigned int toe_q8_full        : 1;    // bit 8        TOE Queue 8 Full Interrupt
++              unsigned int toe_q9_full        : 1;    // bit 9        TOE Queue 9 Full Interrupt
++              unsigned int toe_q10_full       : 1;    // bit 10       TOE Queue 10 Full Interrupt
++              unsigned int toe_q11_full       : 1;    // bit 11       TOE Queue 11 Full Interrupt
++              unsigned int toe_q12_full       : 1;    // bit 12       TOE Queue 12 Full Interrupt
++              unsigned int toe_q13_full       : 1;    // bit 13       TOE Queue 13 Full Interrupt
++              unsigned int toe_q14_full       : 1;    // bit 14       TOE Queue 14 Full Interrupt
++              unsigned int toe_q15_full       : 1;    // bit 15       TOE Queue 15 Full Interrupt
++              unsigned int toe_q16_full       : 1;    // bit 16       TOE Queue 16 Full Interrupt
++              unsigned int toe_q17_full       : 1;    // bit 17       TOE Queue 17 Full Interrupt
++              unsigned int toe_q18_full       : 1;    // bit 18       TOE Queue 18 Full Interrupt
++              unsigned int toe_q19_full       : 1;    // bit 19       TOE Queue 19 Full Interrupt
++              unsigned int toe_q20_full       : 1;    // bit 20       TOE Queue 20 Full Interrupt
++              unsigned int toe_q21_full       : 1;    // bit 21       TOE Queue 21 Full Interrupt
++              unsigned int toe_q22_full       : 1;    // bit 22       TOE Queue 22 Full Interrupt
++              unsigned int toe_q23_full       : 1;    // bit 23       TOE Queue 23 Full Interrupt
++              unsigned int toe_q24_full       : 1;    // bit 24       TOE Queue 24 Full Interrupt
++              unsigned int toe_q25_full       : 1;    // bit 25       TOE Queue 25 Full Interrupt
++              unsigned int toe_q26_full       : 1;    // bit 26       TOE Queue 26 Full Interrupt
++              unsigned int toe_q27_full       : 1;    // bit 27       TOE Queue 27 Full Interrupt
++              unsigned int toe_q28_full       : 1;    // bit 28       TOE Queue 28 Full Interrupt
++              unsigned int toe_q29_full       : 1;    // bit 29       TOE Queue 29 Full Interrupt
++              unsigned int toe_q30_full       : 1;    // bit 30       TOE Queue 30 Full Interrupt
++              unsigned int toe_q31_full       : 1;    // bit 31       TOE Queue 31 Full Interrupt
++#endif
++      } bits;
++} INTR_REG2_T;
++
++#define TOE_QL_FULL_INT_BIT(x)                BIT(x)
++
++/**********************************************************************
++ * Interrupt Status Register 3        (offset 0x0050)
++ * Interrupt Mask Register 3  (offset 0x0054)
++ * Interrupt Select Register 3        (offset 0x0058)
++ **********************************************************************/
++typedef union
++{
++      unsigned int bits32;
++      struct bit_0050
++      {
++#if (BIG_ENDIAN==1)
++              unsigned int toe_q63_full       : 1;    // bit 63       TOE Queue 63 Full Interrupt
++              unsigned int toe_q62_full       : 1;    // bit 62       TOE Queue 62 Full Interrupt
++              unsigned int toe_q61_full       : 1;    // bit 61       TOE Queue 61 Full Interrupt
++              unsigned int toe_q60_full       : 1;    // bit 60       TOE Queue 60 Full Interrupt
++              unsigned int toe_q59_full       : 1;    // bit 59       TOE Queue 59 Full Interrupt
++              unsigned int toe_q58_full       : 1;    // bit 58       TOE Queue 58 Full Interrupt
++              unsigned int toe_q57_full       : 1;    // bit 57       TOE Queue 57 Full Interrupt
++              unsigned int toe_q56_full       : 1;    // bit 56       TOE Queue 56 Full Interrupt
++              unsigned int toe_q55_full       : 1;    // bit 55       TOE Queue 55 Full Interrupt
++              unsigned int toe_q54_full       : 1;    // bit 54       TOE Queue 54 Full Interrupt
++              unsigned int toe_q53_full       : 1;    // bit 53       TOE Queue 53 Full Interrupt
++              unsigned int toe_q52_full       : 1;    // bit 52       TOE Queue 52 Full Interrupt
++              unsigned int toe_q51_full       : 1;    // bit 51       TOE Queue 51 Full Interrupt
++              unsigned int toe_q50_full       : 1;    // bit 50       TOE Queue 50 Full Interrupt
++              unsigned int toe_q49_full       : 1;    // bit 49       TOE Queue 49 Full Interrupt
++              unsigned int toe_q48_full       : 1;    // bit 48       TOE Queue 48 Full Interrupt
++              unsigned int toe_q47_full       : 1;    // bit 47       TOE Queue 47 Full Interrupt
++              unsigned int toe_q46_full       : 1;    // bit 46       TOE Queue 46 Full Interrupt
++              unsigned int toe_q45_full       : 1;    // bit 45       TOE Queue 45 Full Interrupt
++              unsigned int toe_q44_full       : 1;    // bit 44       TOE Queue 44 Full Interrupt
++              unsigned int toe_q43_full       : 1;    // bit 43       TOE Queue 43 Full Interrupt
++              unsigned int toe_q42_full       : 1;    // bit 42       TOE Queue 42 Full Interrupt
++              unsigned int toe_q41_full       : 1;    // bit 41       TOE Queue 41 Full Interrupt
++              unsigned int toe_q40_full       : 1;    // bit 40       TOE Queue 40 Full Interrupt
++              unsigned int toe_q39_full       : 1;    // bit 39       TOE Queue 39 Full Interrupt
++              unsigned int toe_q38_full       : 1;    // bit 38       TOE Queue 38 Full Interrupt
++              unsigned int toe_q37_full       : 1;    // bit 37       TOE Queue 37 Full Interrupt
++              unsigned int toe_q36_full       : 1;    // bit 36       TOE Queue 36 Full Interrupt
++              unsigned int toe_q35_full       : 1;    // bit 35       TOE Queue 35 Full Interrupt
++              unsigned int toe_q34_full       : 1;    // bit 34       TOE Queue 34 Full Interrupt
++              unsigned int toe_q33_full       : 1;    // bit 33       TOE Queue 33 Full Interrupt
++              unsigned int toe_q32_full       : 1;    // bit 32       TOE Queue 32 Full Interrupt
++#else
++              unsigned int toe_q32_full       : 1;    // bit 32       TOE Queue 32 Full Interrupt
++              unsigned int toe_q33_full       : 1;    // bit 33       TOE Queue 33 Full Interrupt
++              unsigned int toe_q34_full       : 1;    // bit 34       TOE Queue 34 Full Interrupt
++              unsigned int toe_q35_full       : 1;    // bit 35       TOE Queue 35 Full Interrupt
++              unsigned int toe_q36_full       : 1;    // bit 36       TOE Queue 36 Full Interrupt
++              unsigned int toe_q37_full       : 1;    // bit 37       TOE Queue 37 Full Interrupt
++              unsigned int toe_q38_full       : 1;    // bit 38       TOE Queue 38 Full Interrupt
++              unsigned int toe_q39_full       : 1;    // bit 39       TOE Queue 39 Full Interrupt
++              unsigned int toe_q40_full       : 1;    // bit 40       TOE Queue 40 Full Interrupt
++              unsigned int toe_q41_full       : 1;    // bit 41       TOE Queue 41 Full Interrupt
++              unsigned int toe_q42_full       : 1;    // bit 42       TOE Queue 42 Full Interrupt
++              unsigned int toe_q43_full       : 1;    // bit 43       TOE Queue 43 Full Interrupt
++              unsigned int toe_q44_full       : 1;    // bit 44       TOE Queue 44 Full Interrupt
++              unsigned int toe_q45_full       : 1;    // bit 45       TOE Queue 45 Full Interrupt
++              unsigned int toe_q46_full       : 1;    // bit 46       TOE Queue 46 Full Interrupt
++              unsigned int toe_q47_full       : 1;    // bit 47       TOE Queue 47 Full Interrupt
++              unsigned int toe_q48_full       : 1;    // bit 48       TOE Queue 48 Full Interrupt
++              unsigned int toe_q49_full       : 1;    // bit 49       TOE Queue 49 Full Interrupt
++              unsigned int toe_q50_full       : 1;    // bit 50       TOE Queue 50 Full Interrupt
++              unsigned int toe_q51_full       : 1;    // bit 51       TOE Queue 51 Full Interrupt
++              unsigned int toe_q52_full       : 1;    // bit 52       TOE Queue 52 Full Interrupt
++              unsigned int toe_q53_full       : 1;    // bit 53       TOE Queue 53 Full Interrupt
++              unsigned int toe_q54_full       : 1;    // bit 54       TOE Queue 54 Full Interrupt
++              unsigned int toe_q55_full       : 1;    // bit 55       TOE Queue 55 Full Interrupt
++              unsigned int toe_q56_full       : 1;    // bit 56       TOE Queue 56 Full Interrupt
++              unsigned int toe_q57_full       : 1;    // bit 57       TOE Queue 57 Full Interrupt
++              unsigned int toe_q58_full       : 1;    // bit 58       TOE Queue 58 Full Interrupt
++              unsigned int toe_q59_full       : 1;    // bit 59       TOE Queue 59 Full Interrupt
++              unsigned int toe_q60_full       : 1;    // bit 60       TOE Queue 60 Full Interrupt
++              unsigned int toe_q61_full       : 1;    // bit 61       TOE Queue 61 Full Interrupt
++              unsigned int toe_q62_full       : 1;    // bit 62       TOE Queue 62 Full Interrupt
++              unsigned int toe_q63_full       : 1;    // bit 63       TOE Queue 63 Full Interrupt
++#endif
++      } bits;
++} INTR_REG3_T;
++
++#define TOE_QH_FULL_INT_BIT(x)                BIT(x-32)
++
++/**********************************************************************
++ * Interrupt Status Register 4        (offset 0x0060)
++ * Interrupt Mask Register 4  (offset 0x0064)
++ * Interrupt Select Register 4        (offset 0x0068)
++ **********************************************************************/
++typedef union
++{
++      unsigned char byte;
++      struct bit_0060
++      {
++#if (BIG_ENDIAN==1)
++              unsigned char reserved          : 1;    //
++              unsigned char cnt_full          : 1;    // MIB counters half full interrupt
++              unsigned char rx_pause_on       : 1;    // received pause on frame interrupt
++              unsigned char tx_pause_on       : 1;    // transmit pause on frame interrupt
++              unsigned char rx_pause_off  : 1;        // received pause off frame interrupt
++              unsigned char tx_pause_off      : 1;    // received pause off frame interrupt
++              unsigned char rx_overrun        : 1;    // GMAC Rx FIFO overrun interrupt
++              unsigned char status_changed: 1;        // Status Changed Intr for RGMII Mode
++#else
++              unsigned char status_changed: 1;        // Status Changed Intr for RGMII Mode
++              unsigned char rx_overrun        : 1;   // GMAC Rx FIFO overrun interrupt
++              unsigned char tx_pause_off      : 1;    // received pause off frame interrupt
++              unsigned char rx_pause_off  : 1;        // received pause off frame interrupt
++              unsigned char tx_pause_on       : 1;    // transmit pause on frame interrupt
++              unsigned char rx_pause_on       : 1;    // received pause on frame interrupt
++              unsigned char cnt_full          : 1;    // MIB counters half full interrupt
++              unsigned char reserved          : 1;    //
++#endif
++      } _PACKED_ bits;
++} _PACKED_ GMAC_INTR_T;
++
++typedef union
++{
++      unsigned int bits32;
++      struct bit_0060_2
++      {
++#if (BIG_ENDIAN==1)
++              GMAC_INTR_T             gmac1;
++              GMAC_INTR_T             gmac0;
++              unsigned int    class_qf_int: 14;       // bit 15:2 Classification Rx Queue13-0 Full Intr.
++              unsigned int    hwfq_empty      : 1;    // bit 1        Hardware Free Queue Empty Intr.
++              unsigned int    swfq_empty      : 1;    // bit 0        Software Free Queue Empty Intr.
++#else
++#endif
++              unsigned int    swfq_empty      : 1;    // bit 0        Software Free Queue Empty Intr.
++              unsigned int    hwfq_empty      : 1;    // bit 1        Hardware Free Queue Empty Intr.
++              unsigned int    class_qf_int: 14;       // bit 15:2 Classification Rx Queue13-0 Full Intr.
++              GMAC_INTR_T             gmac0;
++              GMAC_INTR_T             gmac1;
++      } bits;
++} INTR_REG4_T;
++
++#define GMAC1_RESERVED_INT_BIT                BIT(31)
++#define GMAC1_MIB_INT_BIT                     BIT(30)
++#define GMAC1_RX_PAUSE_ON_INT_BIT     BIT(29)
++#define GMAC1_TX_PAUSE_ON_INT_BIT     BIT(28)
++#define GMAC1_RX_PAUSE_OFF_INT_BIT    BIT(27)
++#define GMAC1_TX_PAUSE_OFF_INT_BIT    BIT(26)
++#define GMAC1_RX_OVERRUN_INT_BIT      BIT(25)
++#define GMAC1_STATUS_CHANGE_INT_BIT   BIT(24)
++#define GMAC0_RESERVED_INT_BIT                BIT(23)
++#define GMAC0_MIB_INT_BIT                     BIT(22)
++#define GMAC0_RX_PAUSE_ON_INT_BIT     BIT(21)
++#define GMAC0_TX_PAUSE_ON_INT_BIT     BIT(20)
++#define GMAC0_RX_PAUSE_OFF_INT_BIT    BIT(19)
++#define GMAC0_TX_PAUSE_OFF_INT_BIT    BIT(18)
++#define GMAC0_RX_OVERRUN_INT_BIT      BIT(17)
++#define GMAC0_STATUS_CHANGE_INT_BIT   BIT(16)
++#define CLASS_RX_FULL_INT_BIT(x)      BIT((x+2))
++#define HWFQ_EMPTY_INT_BIT                    BIT(1)
++#define SWFQ_EMPTY_INT_BIT                    BIT(0)
++
++#if 1
++#define GMAC0_INT_BITS                                (GMAC0_MIB_INT_BIT)
++#define GMAC1_INT_BITS                                (GMAC1_MIB_INT_BIT)
++#else
++#define GMAC0_INT_BITS                                (GMAC0_RESERVED_INT_BIT | GMAC0_MIB_INT_BIT | \
++                                                                       GMAC0_RX_PAUSE_ON_INT_BIT | GMAC0_TX_PAUSE_ON_INT_BIT |        \
++                                                                       GMAC0_RX_PAUSE_OFF_INT_BIT | GMAC0_TX_PAUSE_OFF_INT_BIT |      \
++                                                                       GMAC0_RX_OVERRUN_INT_BIT | GMAC0_STATUS_CHANGE_INT_BIT)
++#define GMAC1_INT_BITS                                (GMAC1_RESERVED_INT_BIT | GMAC1_MIB_INT_BIT | \
++                                                                       GMAC1_RX_PAUSE_ON_INT_BIT | GMAC1_TX_PAUSE_ON_INT_BIT |        \
++                                                                       GMAC1_RX_PAUSE_OFF_INT_BIT | GMAC1_TX_PAUSE_OFF_INT_BIT |      \
++                                                                       GMAC1_RX_OVERRUN_INT_BIT | GMAC1_STATUS_CHANGE_INT_BIT)
++#endif
++
++#define CLASS_RX_FULL_INT_BITS                0xfffc
++
++/**********************************************************************
++ * GLOBAL_QUEUE_THRESHOLD_REG         (offset 0x0070)
++ **********************************************************************/
++typedef union
++{
++      unsigned int bits32;
++      struct bit_0070_2
++      {
++#if (BIG_ENDIAN==1)
++              unsigned int    toe_class       : 8;    // 31:24
++              unsigned int    intrq           : 8;    // 23:16
++              unsigned int    hwfq_empty      : 8;    // 15:8         Hardware Free Queue Empty Threshold
++              unsigned int    swfq_empty      : 8;    //  7:0         Software Free Queue Empty Threshold
++#else
++#endif
++              unsigned int    swfq_empty      : 8;    //  7:0         Software Free Queue Empty Threshold
++              unsigned int    hwfq_empty      : 8;    // 15:8         Hardware Free Queue Empty Threshold
++              unsigned int    intrq           : 8;    // 23:16
++              unsigned int    toe_class       : 8;    // 31:24
++      } bits;
++} QUEUE_THRESHOLD_T;
++
++
++/**********************************************************************
++ * GMAC DMA Control Register
++ * GMAC0 offset 0x8000
++ * GMAC1 offset 0xC000
++ **********************************************************************/
++typedef union
++{
++      unsigned int bits32;
++      struct bit_8000
++      {
++#if (BIG_ENDIAN==1)
++              unsigned int    rd_enable               : 1;    // bit 31       Rx DMA Enable
++              unsigned int    td_enable               : 1;    // bit 30       Tx DMA Enable
++              unsigned int    loopback                : 1;    // bit 29       Loopback TxDMA to RxDMA
++              unsigned int    drop_small_ack  : 1;    // bit 28       1: Drop, 0: Accept
++              unsigned int    reserved                : 10;   // bit 27:18
++              unsigned int    rd_insert_bytes : 2;    // bit 17:16
++              unsigned int    rd_prot                 : 4;    // bit 15:12 DMA Protection Control
++              unsigned int    rd_burst_size   : 2;    // bit 11:10 DMA max burst size for every AHB request
++              unsigned int    rd_bus              : 2;        // bit 9:8      Peripheral Bus Width
++              unsigned int    td_prot                 : 4;    // bit 7:4  TxDMA protection control
++              unsigned int    td_burst_size   : 2;    // bit 3:2      TxDMA max burst size for every AHB request
++              unsigned int    td_bus              : 2;        // bit 1:0  Peripheral Bus Width
++#else
++              unsigned int    td_bus              : 2;        // bit 1:0  Peripheral Bus Width
++              unsigned int    td_burst_size   : 2;    // bit 3:2      TxDMA max burst size for every AHB request
++              unsigned int    td_prot                 : 4;    // bit 7:4  TxDMA protection control
++              unsigned int    rd_bus              : 2;        // bit 9:8      Peripheral Bus Width
++              unsigned int    rd_burst_size   : 2;    // bit 11:10 DMA max burst size for every AHB request
++              unsigned int    rd_prot                 : 4;    // bit 15:12 DMA Protection Control
++              unsigned int    rd_insert_bytes : 2;    // bit 17:16
++              unsigned int    reserved                : 10;   // bit 27:18
++              unsigned int    drop_small_ack  : 1;    // bit 28       1: Drop, 0: Accept
++              unsigned int    loopback                : 1;    // bit 29       Loopback TxDMA to RxDMA
++              unsigned int    td_enable               : 1;    // bit 30       Tx DMA Enable
++              unsigned int    rd_enable               : 1;    // bit 31       Rx DMA Enable
++#endif
++      } bits;
++} GMAC_DMA_CTRL_T;
++
++/**********************************************************************
++ * GMAC Tx Weighting Control Register 0
++ * GMAC0 offset 0x8004
++ * GMAC1 offset 0xC004
++ **********************************************************************/
++typedef union
++{
++      unsigned int bits32;
++      struct bit_8004
++      {
++#if (BIG_ENDIAN==1)
++              unsigned int    reserved                : 8;    // bit 31:24
++              unsigned int    hw_tq3                  : 6;    // bit 23:18    HW TX Queue 0
++              unsigned int    hw_tq2                  : 6;    // bit 17:12    HW TX Queue 1
++              unsigned int    hw_tq1                  : 6;    // bit 11:6             HW TX Queue 2
++              unsigned int    hw_tq0                  : 6;    // bit 5:0              HW TX Queue 3
++#else
++              unsigned int    hw_tq0                  : 6;    // bit 5:0              HW TX Queue 3
++              unsigned int    hw_tq1                  : 6;    // bit 11:6             HW TX Queue 2
++              unsigned int    hw_tq2                  : 6;    // bit 17:12    HW TX Queue 1
++              unsigned int    hw_tq3                  : 6;    // bit 23:18    HW TX Queue 0
++              unsigned int    reserved                : 8;    // bit 31:24
++#endif
++      } bits;
++} GMAC_TX_WCR0_T;     // Weighting Control Register 0
++
++/**********************************************************************
++ * GMAC Tx Weighting Control Register 1
++ * GMAC0 offset 0x8008
++ * GMAC1 offset 0xC008
++ **********************************************************************/
++typedef union
++{
++      unsigned int bits32;
++      struct bit_8008
++      {
++#if (BIG_ENDIAN==1)
++              unsigned int    reserved                : 2;    // bit 31:30
++              unsigned int    sw_tq5                  : 5;    // bit 29:25    SW TX Queue 5
++              unsigned int    sw_tq4                  : 5;    // bit 24:20    SW TX Queue 4
++              unsigned int    sw_tq3                  : 5;    // bit 19:15    SW TX Queue 3
++              unsigned int    sw_tq2                  : 5;    // bit 14:10    SW TX Queue 2
++              unsigned int    sw_tq1                  : 5;    // bit 9:5              SW TX Queue 1
++              unsigned int    sw_tq0                  : 5;    // bit 4:0              SW TX Queue 0
++#else
++              unsigned int    sw_tq0                  : 5;    // bit 4:0              SW TX Queue 0
++              unsigned int    sw_tq1                  : 5;    // bit 9:5              SW TX Queue 1
++              unsigned int    sw_tq2                  : 5;    // bit 14:10    SW TX Queue 2
++              unsigned int    sw_tq3                  : 5;    // bit 19:15    SW TX Queue 3
++              unsigned int    sw_tq4                  : 5;    // bit 24:20    SW TX Queue 4
++              unsigned int    sw_tq5                  : 5;    // bit 29:25    SW TX Queue 5
++              unsigned int    reserved                : 2;    // bit 31:30
++#endif
++      } bits;
++} GMAC_TX_WCR1_T;     // Weighting Control Register 1
++
++/**********************************************************************
++ * Queue Read/Write Pointer
++ * GMAC SW TX Queue 0~5 Read/Write Pointer register
++ * GMAC0 offset 0x800C ~ 0x8020
++ * GMAC1 offset 0xC00C ~ 0xC020
++ * GMAC HW TX Queue 0~3 Read/Write Pointer register
++ * GMAC0 offset 0x8024 ~ 0x8030
++ * GMAC1 offset 0xC024 ~ 0xC030
++ **********************************************************************/
++// see DMA_RWPTR_T structure
++
++/**********************************************************************
++ * GMAC DMA Tx First Description Address Register
++ * GMAC0 offset 0x8038
++ * GMAC1 offset 0xC038
++ **********************************************************************/
++typedef union
++{
++      unsigned int bits32;
++      struct bit_8038
++      {
++#if (BIG_ENDIAN==1)
++              unsigned int td_first_des_ptr   : 28;   // bit 31:4     first descriptor address
++              unsigned int td_busy                    :  1;   // bit 3        1: TxDMA busy; 0: TxDMA idle
++              unsigned int reserved                   :  3;
++#else
++              unsigned int reserved                   :  3;
++              unsigned int td_busy                    :  1;   // bit 3        1: TxDMA busy; 0: TxDMA idle
++              unsigned int td_first_des_ptr   : 28;   // bit 31:4     first descriptor address
++#endif
++      } bits;
++} GMAC_TXDMA_FIRST_DESC_T;
++
++/**********************************************************************
++ * GMAC DMA Tx Current Description Address Register
++ * GMAC0 offset 0x803C
++ * GMAC1 offset 0xC03C
++ **********************************************************************/
++typedef union
++{
++      unsigned int bits32;
++      struct bit_803C
++      {
++#if (BIG_ENDIAN==1)
++              unsigned int td_curr_desc_ptr   : 28;   // bit 31:4     current descriptor address
++              unsigned int reserved                   :  4;
++#else
++              unsigned int reserved                   :  4;
++              unsigned int td_curr_desc_ptr   : 28;   // bit 31:4     current descriptor address
++#endif
++      } bits;
++} GMAC_TXDMA_CURR_DESC_T;
++
++/**********************************************************************
++ * GMAC DMA Tx Description Word 0 Register
++ * GMAC0 offset 0x8040
++ * GMAC1 offset 0xC040
++ **********************************************************************/
++typedef union
++{
++      unsigned int bits32;
++      struct bit_8040
++      {
++#if (BIG_ENDIAN==1)
++              unsigned int reserved           : 1;    // bit 31
++              unsigned int derr                       : 1;    // bit 30        data error during processing this descriptor
++              unsigned int perr                       : 1;    // bit 29        protocol error during processing this descriptor
++              unsigned int status_rvd         : 6;    // bit 28:23 Tx Status, Reserved bits
++              unsigned int status_tx_ok       : 1;    // bit 22    Tx Status, 1: Successful 0: Failed
++              unsigned int desc_count         : 6;    // bit 21:16 number of descriptors used for the current frame
++              unsigned int buffer_size        : 16;   // bit 15:0  Transfer size
++#else
++              unsigned int buffer_size        : 16;   // bit 15:0  Transfer size
++              unsigned int desc_count         : 6;    // bit 21:16 number of descriptors used for the current frame
++              unsigned int status_tx_ok       : 1;    // bit 22    Tx Status, 1: Successful 0: Failed
++              unsigned int status_rvd         : 6;    // bit 28:23 Tx Status, Reserved bits
++              unsigned int perr                       : 1;    // bit 29        protocol error during processing this descriptor
++              unsigned int derr                       : 1;    // bit 30        data error during processing this descriptor
++              unsigned int reserved           : 1;    // bit 31
++#endif
++      } bits;
++} GMAC_TXDESC_0_T;
++
++/**********************************************************************
++ * GMAC DMA Tx Description Word 1 Register
++ * GMAC0 offset 0x8044
++ * GMAC1 offset 0xC044
++ **********************************************************************/
++typedef union
++{
++      unsigned int bits32;
++      struct txdesc_word1
++      {
++#if (BIG_ENDIAN==1)
++              unsigned int    reserved        : 9;    // bit 31:23    Tx Flag, Reserved
++              unsigned int    ip_fixed_len: 1;        // bit 22
++              unsigned int    bypass_tss      : 1;    // bit 21
++              unsigned int    udp_chksum      : 1;    // bit 20               UDP Checksum Enable
++              unsigned int    tcp_chksum      : 1;    // bit 19               TCP Checksum Enable
++              unsigned int    ipv6_enable     : 1;    // bit 18               IPV6 Tx Enable
++              unsigned int    ip_chksum       : 1;    // bit 17               IPV4 Header Checksum Enable
++              unsigned int    mtu_enable      : 1;    // bit 16               TSS segmentation use MTU setting
++              unsigned int    byte_count      : 16;   // bit 15: 0    Tx Frame Byte Count
++#else
++              unsigned int    byte_count      : 16;   // bit 15: 0    Tx Frame Byte Count
++              unsigned int    mtu_enable      : 1;    // bit 16               TSS segmentation use MTU setting
++              unsigned int    ip_chksum       : 1;    // bit 17               IPV4 Header Checksum Enable
++              unsigned int    ipv6_enable     : 1;    // bit 18               IPV6 Tx Enable
++              unsigned int    tcp_chksum      : 1;    // bit 19               TCP Checksum Enable
++              unsigned int    udp_chksum      : 1;    // bit 20               UDP Checksum Enable
++              unsigned int    bypass_tss      : 1;    // bit 21
++              unsigned int    ip_fixed_len: 1;        // bit 22
++              unsigned int    reserved        : 9;    // bit 31:23    Tx Flag, Reserved
++#endif
++      } bits;
++} GMAC_TXDESC_1_T;
++
++#define TSS_IP_FIXED_LEN_BIT  BIT(22)
++#define TSS_UDP_CHKSUM_BIT            BIT(20)
++#define TSS_TCP_CHKSUM_BIT            BIT(19)
++#define TSS_IPV6_ENABLE_BIT           BIT(18)
++#define TSS_IP_CHKSUM_BIT             BIT(17)
++#define TSS_MTU_ENABLE_BIT            BIT(16)
++
++/**********************************************************************
++ * GMAC DMA Tx Description Word 2 Register
++ * GMAC0 offset 0x8048
++ * GMAC1 offset 0xC048
++ **********************************************************************/
++typedef union
++{
++      unsigned int    bits32;
++      unsigned int    buf_adr;
++} GMAC_TXDESC_2_T;
++
++/**********************************************************************
++ * GMAC DMA Tx Description Word 3 Register
++ * GMAC0 offset 0x804C
++ * GMAC1 offset 0xC04C
++ **********************************************************************/
++typedef union
++{
++      unsigned int bits32;
++      struct txdesc_word3
++      {
++#if (BIG_ENDIAN==1)
++              unsigned int    sof_eof         : 2;    // bit 31:30    11: only one, 10: first, 01: last, 00: linking
++              unsigned int    eofie           : 1;    // bit 29               End of frame interrupt enable
++              unsigned int    reserved        : 18;   // bit 28:11
++              unsigned int    mtu_size        : 11;   // bit 10: 0    Tx Frame Byte Count
++#else
++              unsigned int    mtu_size        : 11;   // bit 10: 0    Tx Frame Byte Count
++              unsigned int    reserved        : 18;   // bit 28:11
++              unsigned int    eofie           : 1;    // bit 29               End of frame interrupt enable
++              unsigned int    sof_eof         : 2;    // bit 31:30    11: only one, 10: first, 01: last, 00: linking
++#endif
++      } bits;
++} GMAC_TXDESC_3_T;
++#define SOF_EOF_BIT_MASK      0x3fffffff
++#define SOF_BIT                               0x80000000
++#define EOF_BIT                               0x40000000
++#define EOFIE_BIT                     BIT(29)
++#define MTU_SIZE_BIT_MASK     0x7ff
++
++/**********************************************************************
++ * GMAC Tx Descriptor
++ **********************************************************************/
++typedef struct
++{
++      GMAC_TXDESC_0_T word0;
++      GMAC_TXDESC_1_T word1;
++      GMAC_TXDESC_2_T word2;
++      GMAC_TXDESC_3_T word3;
++} GMAC_TXDESC_T;
++
++
++/**********************************************************************
++ * GMAC DMA Rx First Description Address Register
++ * GMAC0 offset 0x8058
++ * GMAC1 offset 0xC058
++ **********************************************************************/
++typedef union
++{
++      unsigned int bits32;
++      struct bit_8058
++      {
++#if (BIG_ENDIAN==1)
++              unsigned int rd_first_des_ptr   : 28;   // bit 31:4 first descriptor address
++              unsigned int rd_busy                    :  1;   // bit 3        1-RxDMA busy; 0-RxDMA idle
++              unsigned int reserved                   :  3;   // bit 2:0
++#else
++              unsigned int reserved                   :  3;   // bit 2:0
++              unsigned int rd_busy                    :  1;   // bit 3        1-RxDMA busy; 0-RxDMA idle
++              unsigned int rd_first_des_ptr   : 28;   // bit 31:4 first descriptor address
++#endif
++      } bits;
++} GMAC_RXDMA_FIRST_DESC_T;
++
++/**********************************************************************
++ * GMAC DMA Rx Current Description Address Register
++ * GMAC0 offset 0x805C
++ * GMAC1 offset 0xC05C
++ **********************************************************************/
++typedef union
++{
++      unsigned int bits32;
++      struct bit_805C
++      {
++#if (BIG_ENDIAN==1)
++              unsigned int rd_curr_des_ptr    : 28;   // bit 31:4 current descriptor address
++              unsigned int reserved                   :  4;   // bit 3:0
++#else
++              unsigned int reserved                   :  4;   // bit 3:0
++              unsigned int rd_curr_des_ptr    : 28;   // bit 31:4 current descriptor address
++#endif
++      } bits;
++} GMAC_RXDMA_CURR_DESC_T;
++
++/**********************************************************************
++ * GMAC DMA Rx Description Word 0 Register
++ * GMAC0 offset 0x8060
++ * GMAC1 offset 0xC060
++ **********************************************************************/
++typedef union
++{
++      unsigned int bits32;
++      struct bit_8060
++      {
++#if (BIG_ENDIAN==1)
++              unsigned int drop                       : 1;    // bit 31        TOE/CIS Queue Full dropped packet to default queue
++              unsigned int derr                       : 1;    // bit 30        data error during processing this descriptor
++              unsigned int perr                       : 1;    // bit 29        protocol error during processing this descriptor
++              unsigned int chksum_status      : 3;    // bit 28:26 Check Sum Status
++              unsigned int status                     : 4;    // bit 24:22 Status of rx frame
++              unsigned int desc_count         : 6;    // bit 21:16 number of descriptors used for the current frame
++              unsigned int buffer_size        : 16;   // bit 15:0  number of descriptors used for the current frame
++#else
++              unsigned int buffer_size        : 16;   // bit 15:0  number of descriptors used for the current frame
++              unsigned int desc_count         : 6;    // bit 21:16 number of descriptors used for the current frame
++              unsigned int status                     : 4;    // bit 24:22 Status of rx frame
++              unsigned int chksum_status      : 3;    // bit 28:26 Check Sum Status
++              unsigned int perr                       : 1;    // bit 29        protocol error during processing this descriptor
++              unsigned int derr                       : 1;    // bit 30        data error during processing this descriptor
++              unsigned int drop                       : 1;    // bit 31        TOE/CIS Queue Full dropped packet to default queue
++#endif
++      } bits;
++} GMAC_RXDESC_0_T;
++
++#define               GMAC_RXDESC_0_T_derr                            BIT(30)
++#define               GMAC_RXDESC_0_T_perr                            BIT(29)
++#define               GMAC_RXDESC_0_T_chksum_status(x)        BIT((x+26))
++#define               GMAC_RXDESC_0_T_status(x)                       BIT((x+22))
++#define               GMAC_RXDESC_0_T_desc_count(x)           BIT((x+16))
++
++#define       RX_CHKSUM_IP_UDP_TCP_OK                 0
++#define       RX_CHKSUM_IP_OK_ONLY                    1
++#define       RX_CHKSUM_NONE                                  2
++#define       RX_CHKSUM_IP_ERR_UNKNOWN                4
++#define       RX_CHKSUM_IP_ERR                                5
++#define       RX_CHKSUM_TCP_UDP_ERR                   6
++#define RX_CHKSUM_NUM                                 8
++
++#define RX_STATUS_GOOD_FRAME                  0
++#define RX_STATUS_TOO_LONG_GOOD_CRC           1
++#define RX_STATUS_RUNT_FRAME                  2
++#define RX_STATUS_SFD_NOT_FOUND                       3
++#define RX_STATUS_CRC_ERROR                           4
++#define RX_STATUS_TOO_LONG_BAD_CRC            5
++#define RX_STATUS_ALIGNMENT_ERROR             6
++#define RX_STATUS_TOO_LONG_BAD_ALIGN  7
++#define RX_STATUS_RX_ERR                              8
++#define RX_STATUS_DA_FILTERED                 9
++#define RX_STATUS_BUFFER_FULL                 10
++#define RX_STATUS_NUM                                 16
++
++
++/**********************************************************************
++ * GMAC DMA Rx Description Word 1 Register
++ * GMAC0 offset 0x8064
++ * GMAC1 offset 0xC064
++ **********************************************************************/
++typedef union
++{
++      unsigned int bits32;
++      struct rxdesc_word1
++      {
++#if (BIG_ENDIAN==1)
++              unsigned int    sw_id           : 16;   // bit 31:16    Software ID
++              unsigned int    byte_count      : 16;   // bit 15: 0    Rx Frame Byte Count
++#else
++              unsigned int    byte_count      : 16;   // bit 15: 0    Rx Frame Byte Count
++              unsigned int    sw_id           : 16;   // bit 31:16    Software ID
++#endif
++      } bits;
++} GMAC_RXDESC_1_T;
++
++/**********************************************************************
++ * GMAC DMA Rx Description Word 2 Register
++ * GMAC0 offset 0x8068
++ * GMAC1 offset 0xC068
++ **********************************************************************/
++typedef union
++{
++      unsigned int    bits32;
++      unsigned int    buf_adr;
++} GMAC_RXDESC_2_T;
++
++#define RX_INSERT_NONE                0
++#define RX_INSERT_1_BYTE      1
++#define RX_INSERT_2_BYTE      2
++#define RX_INSERT_3_BYTE      3
++
++#define RX_INSERT_BYTES               RX_INSERT_2_BYTE
++/**********************************************************************
++ * GMAC DMA Rx Description Word 3 Register
++ * GMAC0 offset 0x806C
++ * GMAC1 offset 0xC06C
++ **********************************************************************/
++typedef union
++{
++      unsigned int bits32;
++      struct rxdesc_word3
++      {
++#if (BIG_ENDIAN==1)
++              unsigned int    sof_eof         : 2;    // bit 31:30    11: only one, 10: first, 01: last, 00: linking
++              unsigned int    eofie           : 1;    // bit 29               End of frame interrupt enable
++              unsigned int    ctrl_flag       : 1;    // bit 28               Control Flag is present
++              unsigned int    out_of_seq      : 1;    // bit 27               Out of Sequence packet
++              unsigned int    option          : 1;    // bit 26               IPV4 option or IPV6 extension header
++              unsigned int    abnormal        : 1;    // bit 25               abnormal case found
++              unsigned int    dup_ack         : 1;    // bit 24               Duplicated ACK detected
++              unsigned int    l7_offset       : 8;    // bit 23: 16   L7 data offset
++              unsigned int    l4_offset       : 8;    // bit 15: 8    L4 data offset
++              unsigned int    l3_offset       : 8;    // bit 7: 0             L3 data offset
++#else
++              unsigned int    l3_offset       : 8;    // bit 7: 0             L3 data offset
++              unsigned int    l4_offset       : 8;    // bit 15: 8    L4 data offset
++              unsigned int    l7_offset       : 8;    // bit 23: 16   L7 data offset
++              unsigned int    dup_ack         : 1;    // bit 24               Duplicated ACK detected
++              unsigned int    abnormal        : 1;    // bit 25               abnormal case found
++              unsigned int    option          : 1;    // bit 26               IPV4 option or IPV6 extension header
++              unsigned int    out_of_seq      : 1;    // bit 27               Out of Sequence packet
++              unsigned int    ctrl_flag       : 1;    // bit 28               Control Flag is present
++              unsigned int    eofie           : 1;    // bit 29               End of frame interrupt enable
++              unsigned int    sof_eof         : 2;    // bit 31:30    11: only one, 10: first, 01: last, 00: linking
++#endif
++      } bits;
++} GMAC_RXDESC_3_T;
++
++/**********************************************************************
++ * GMAC Rx Descriptor
++ **********************************************************************/
++typedef struct
++{
++      GMAC_RXDESC_0_T word0;
++      GMAC_RXDESC_1_T word1;
++      GMAC_RXDESC_2_T word2;
++      GMAC_RXDESC_3_T word3;
++} GMAC_RXDESC_T;
++
++/**********************************************************************
++ * GMAC Hash Engine Enable/Action Register 0 Offset Register
++ * GMAC0 offset 0x8070
++ * GMAC1 offset 0xC070
++ **********************************************************************/
++typedef union
++{
++      unsigned int bits32;
++      struct bit_8070
++      {
++#if (BIG_ENDIAN==1)
++              unsigned int    mr1en           : 1;    // bit 31               Enable Matching Rule 1
++              unsigned int    reserved1       : 1;    // bit 30
++              unsigned int    timing          : 3;    // bit 29:27
++              unsigned int    mr1_action      : 5;    // bit 26:22    Matching Rule 1 action offset
++              unsigned int    mr1hel          : 6;    // bit 21:16    match rule 1 hash entry size
++              unsigned int    mr0en           : 1;    // bit 15               Enable Matching Rule 0
++              unsigned int    reserved0       : 4;    // bit 14:11
++              unsigned int    mr0_action      : 5;    // bit 10:6             Matching Rule 0 action offset
++              unsigned int    mr0hel          : 6;    // bit 5:0              match rule 0 hash entry size
++#else
++              unsigned int    mr0hel          : 6;    // bit 5:0              match rule 0 hash entry size
++              unsigned int    mr0_action      : 5;    // bit 10:6             Matching Rule 0 action offset
++              unsigned int    reserved0       : 4;    // bit 14:11
++              unsigned int    mr0en           : 1;    // bit 15               Enable Matching Rule 0
++              unsigned int    mr1hel          : 6;    // bit 21:16    match rule 1 hash entry size
++              unsigned int    mr1_action      : 5;    // bit 26:22    Matching Rule 1 action offset
++              unsigned int    timing          : 3;    // bit 29:27
++              unsigned int    reserved1       : 1;    // bit 30
++              unsigned int    mr1en           : 1;    // bit 31               Enable Matching Rule 1
++#endif
++      } bits;
++} GMAC_HASH_ENABLE_REG0_T;
++
++/**********************************************************************
++ * GMAC Hash Engine Enable/Action Register 1 Offset Register
++ * GMAC0 offset 0x8074
++ * GMAC1 offset 0xC074
++ **********************************************************************/
++typedef union
++{
++      unsigned int bits32;
++      struct bit_8074
++      {
++#if (BIG_ENDIAN==1)
++              unsigned int    mr3en           : 1;    // bit 31               Enable Matching Rule 3
++              unsigned int    reserved3       : 4;    // bit 30:27
++              unsigned int    mr3_action      : 5;    // bit 26:22    Matching Rule 3 action offset
++              unsigned int    mr3hel          : 6;    // bit 21:16    match rule 3 hash entry size
++              unsigned int    mr2en           : 1;    // bit 15               Enable Matching Rule 2
++              unsigned int    reserved2       : 4;    // bit 14:11
++              unsigned int    mr2_action      : 5;    // bit 10:6             Matching Rule 2 action offset
++              unsigned int    mr2hel          : 6;    // bit 5:0              match rule 2 hash entry size
++#else
++              unsigned int    mr2hel          : 6;    // bit 5:0              match rule 2 hash entry size
++              unsigned int    mr2_action      : 5;    // bit 10:6             Matching Rule 2 action offset
++              unsigned int    reserved2       : 4;    // bit 14:11
++              unsigned int    mr2en           : 1;    // bit 15               Enable Matching Rule 2
++              unsigned int    mr3hel          : 6;    // bit 21:16    match rule 3 hash entry size
++              unsigned int    mr3_action      : 5;    // bit 26:22    Matching Rule 3 action offset
++              unsigned int    reserved1       : 4;    // bit 30:27
++              unsigned int    mr3en           : 1;    // bit 31               Enable Matching Rule 3
++#endif
++      } bits;
++} GMAC_HASH_ENABLE_REG1_T;
++
++
++/**********************************************************************
++ * GMAC Matching Rule Control Register 0
++ * GMAC0 offset 0x8078
++ * GMAC1 offset 0xC078
++ **********************************************************************/
++typedef union
++{
++      unsigned int bits32;
++      struct bit_8078
++      {
++#if (BIG_ENDIAN==1)
++              unsigned int    l2                      : 1;    // bit 31               L2 matching enable
++              unsigned int    l3                      : 1;    // bit 30               L3 matching enable
++              unsigned int    l4                      : 1;    // bit 29               L4 matching enable
++              unsigned int    l7                      : 1;    // bit 28               L7 matching enable
++              unsigned int    port            : 1;    // bit 27               PORT ID matching enable
++              unsigned int    priority        : 3;    // bit 26:24    priority if multi-rules matched
++              unsigned int    da                      : 1;    // bit 23               MAC DA enable
++              unsigned int    sa                      : 1;    // bit 22               MAC SA enable
++              unsigned int    ether_type      : 1;    // bit 21               Ethernet type enable
++              unsigned int    vlan            : 1;    // bit 20               VLAN ID enable
++              unsigned int    pppoe           : 1;    // bit 19               PPPoE Session ID enable
++              unsigned int    reserved1       : 3;    // bit 18:16
++              unsigned int    ip_version      : 1;    // bit 15               0: IPV4, 1: IPV6
++              unsigned int    ip_hdr_len      : 1;    // bit 14               IPV4 Header length
++              unsigned int    flow_lable      : 1;    // bit 13               IPV6 Flow label
++              unsigned int    tos_traffic     : 1;    // bit 12               IPV4 TOS or IPV6 Traffice Class
++              unsigned int    reserved2       : 4;    // bit 11:8
++              unsigned int    sprx            : 8;    // bit 7:0              Support Protocol Register 7:0
++#else
++              unsigned int    sprx            : 8;    // bit 7:0              Support Protocol Register 7:0
++              unsigned int    reserved2       : 4;    // bit 11:8
++              unsigned int    tos_traffic     : 1;    // bit 12               IPV4 TOS or IPV6 Traffice Class
++              unsigned int    flow_lable      : 1;    // bit 13               IPV6 Flow label
++              unsigned int    ip_hdr_len      : 1;    // bit 14               IPV4 Header length
++              unsigned int    ip_version      : 1;    // bit 15               0: IPV4, 1: IPV6
++              unsigned int    reserved1       : 3;    // bit 18:16
++              unsigned int    pppoe           : 1;    // bit 19               PPPoE Session ID enable
++              unsigned int    vlan            : 1;    // bit 20               VLAN ID enable
++              unsigned int    ether_type      : 1;    // bit 21               Ethernet type enable
++              unsigned int    sa                      : 1;    // bit 22               MAC SA enable
++              unsigned int    da                      : 1;    // bit 23               MAC DA enable
++              unsigned int    priority        : 3;    // bit 26:24    priority if multi-rules matched
++              unsigned int    port            : 1;    // bit 27               PORT ID matching enable
++              unsigned int    l7                      : 1;    // bit 28               L7 matching enable
++              unsigned int    l4                      : 1;    // bit 29               L4 matching enable
++              unsigned int    l3                      : 1;    // bit 30               L3 matching enable
++              unsigned int    l2                      : 1;    // bit 31               L2 matching enable
++#endif
++      } bits;
++} GMAC_MRxCR0_T;
++
++#define MR_L2_BIT                     BIT(31)
++#define MR_L3_BIT                     BIT(30)
++#define MR_L4_BIT                     BIT(29)
++#define MR_L7_BIT                     BIT(28)
++#define MR_PORT_BIT                   BIT(27)
++#define MR_PRIORITY_BIT               BIT(26)
++#define MR_DA_BIT                     BIT(23)
++#define MR_SA_BIT                     BIT(22)
++#define MR_ETHER_TYPE_BIT     BIT(21)
++#define MR_VLAN_BIT                   BIT(20)
++#define MR_PPPOE_BIT          BIT(19)
++#define MR_IP_VER_BIT         BIT(15)
++#define MR_IP_HDR_LEN_BIT     BIT(14)
++#define MR_FLOW_LABLE_BIT     BIT(13)
++#define MR_TOS_TRAFFIC_BIT    BIT(12)
++#define MR_SPR_BIT(x)         BIT(x)
++#define MR_SPR_BITS           0xff
++
++/**********************************************************************
++ * GMAC Matching Rule Control Register 1
++ * GMAC0 offset 0x807C
++ * GMAC1 offset 0xC07C
++ **********************************************************************/
++ typedef union
++{
++      unsigned int bits32;
++      struct bit_807C
++      {
++#if (BIG_ENDIAN==1)
++              unsigned int    sip                     : 1;    // bit 31               Srce IP
++              unsigned int    sip_netmask     : 7;    // bit 30:24    Srce IP net mask, number of mask bits
++              unsigned int    dip                     : 1;    // bit 23               Dest IP
++              unsigned int    dip_netmask     : 7;    // bit 22:16    Dest IP net mask, number of mask bits
++              unsigned int    l4_byte0_15     : 16;   // bit 15: 0
++#else
++              unsigned int    l4_byte0_15     : 16;   // bit 15: 0
++              unsigned int    dip_netmask     : 7;    // bit 22:16    Dest IP net mask, number of mask bits
++              unsigned int    dip                     : 1;    // bit 23               Dest IP
++              unsigned int    sip_netmask     : 7;    // bit 30:24    Srce IP net mask, number of mask bits
++              unsigned int    sip                     : 1;    // bit 31               Srce IP
++#endif
++      } bits;
++} GMAC_MRxCR1_T;
++
++/**********************************************************************
++ * GMAC Matching Rule Control Register 2
++ * GMAC0 offset 0x8080
++ * GMAC1 offset 0xC080
++ **********************************************************************/
++ typedef union
++{
++      unsigned int bits32;
++      struct bit_8080
++      {
++#if (BIG_ENDIAN==1)
++              unsigned int    l4_byte16_24: 8;        // bit 31: 24
++              unsigned int    l7_byte0_23     : 24;   // bit 23:0
++#else
++              unsigned int    l7_byte0_23     : 24;   // bit 23:0
++              unsigned int    l4_byte16_24: 8;        // bit 31: 24
++#endif
++      } bits;
++} GMAC_MRxCR2_T;
++
++
++/**********************************************************************
++ * GMAC Support registers
++ * GMAC0 offset 0x80A8
++ * GMAC1 offset 0xC0A8
++ **********************************************************************/
++ typedef union
++{
++      unsigned int bits32;
++      struct bit_80A8
++      {
++#if (BIG_ENDIAN==1)
++              unsigned int    reserved: 21;   // bit 31:11
++              unsigned int    swap    : 3;    // bit 10:8             Swap
++              unsigned int    protocol: 8;    // bit 7:0              Supported protocol
++#else
++              unsigned int    protocol: 8;    // bit 7:0              Supported protocol
++              unsigned int    swap    : 3;    // bit 10:8             Swap
++              unsigned int    reserved: 21;   // bit 31:11
++#endif
++      } bits;
++} GMAC_SPR_T;
++
++/**********************************************************************
++ * GMAC_AHB_WEIGHT registers
++ * GMAC0 offset 0x80C8
++ * GMAC1 offset 0xC0C8
++ **********************************************************************/
++ typedef union
++{
++      unsigned int bits32;
++      struct bit_80C8
++      {
++#if (BIG_ENDIAN==1)
++              unsigned int    reserved                : 7;    // 31:25
++              unsigned int    tqDV_threshold  : 5;    // 24:20 DMA TqCtrl to Start tqDV FIFO Threshold
++              unsigned int    pre_req                 : 5;    // 19:15 Rx Data Pre Request FIFO Threshold
++              unsigned int    tx_weight               : 5;    // 14:10
++              unsigned int    rx_weight               : 5;    // 9:5
++              unsigned int    hash_weight             : 5;    // 4:0
++#else
++              unsigned int    hash_weight             : 5;    // 4:0
++              unsigned int    rx_weight               : 5;    // 9:5
++              unsigned int    tx_weight               : 5;    // 14:10
++              unsigned int    pre_req                 : 5;    // 19:15 Rx Data Pre Request FIFO Threshold
++              unsigned int    tqDV_threshold  : 5;    // 24:20 DMA TqCtrl to Start tqDV FIFO Threshold
++              unsigned int    reserved                : 7;    // 31:25
++#endif
++      } bits;
++} GMAC_AHB_WEIGHT_T;
++/**********************************************************************
++ * the register structure of GMAC
++ **********************************************************************/
++
++/**********************************************************************
++ * GMAC RX FLTR
++ * GMAC0 Offset 0xA00C
++ * GMAC1 Offset 0xE00C
++ **********************************************************************/
++typedef union
++{
++      unsigned int bits32;
++      struct bit1_000c
++      {
++#if (BIG_ENDIAN==1)
++              unsigned int                            : 27;
++              unsigned int error                      :  1;   /* enable receive of all error frames */
++              unsigned int promiscuous        :  1;   /* enable receive of all frames */
++              unsigned int broadcast          :  1;   /* enable receive of broadcast frames */
++              unsigned int multicast          :  1;   /* enable receive of multicast frames that pass multicast filter */
++              unsigned int unicast            :  1;   /* enable receive of unicast frames that are sent to STA address */
++#else
++              unsigned int unicast            :  1;   /* enable receive of unicast frames that are sent to STA address */
++              unsigned int multicast          :  1;   /* enable receive of multicast frames that pass multicast filter */
++              unsigned int broadcast          :  1;   /* enable receive of broadcast frames */
++              unsigned int promiscuous        :  1;   /* enable receive of all frames */
++              unsigned int error                      :  1;   /* enable receive of all error frames */
++              unsigned int                            : 27;
++#endif
++      } bits;
++} GMAC_RX_FLTR_T;
++
++/**********************************************************************
++ * GMAC Configuration 0
++ * GMAC0 Offset 0xA018
++ * GMAC1 Offset 0xE018
++ **********************************************************************/
++typedef union
++{
++      unsigned int bits32;
++      struct bit1_0018
++      {
++#if (BIG_ENDIAN==1)
++              unsigned int reserved           :  2;   // 31
++              unsigned int port1_chk_classq :  1;     // 29
++              unsigned int port0_chk_classq :  1;     // 28
++              unsigned int port1_chk_toeq     :  1;   // 27
++              unsigned int port0_chk_toeq     :  1;   // 26
++              unsigned int port1_chk_hwq      :  1;   // 25
++              unsigned int port0_chk_hwq      :  1;   // 24
++              unsigned int rx_err_detect  :  1;       // 23
++              unsigned int ipv6_exthdr_order: 1;      // 22
++              unsigned int rxc_inv            :  1;   // 21
++              unsigned int rgmm_edge          :  1;   // 20
++        unsigned int rx_tag_remove  :  1;   /* 19: Remove Rx VLAN tag */
++        unsigned int ipv6_rx_chksum :  1;   /* 18: IPv6 RX Checksum enable */
++        unsigned int ipv4_rx_chksum :  1;   /* 17: IPv4 RX Checksum enable */
++        unsigned int rgmii_en       :  1;   /* 16: RGMII in-band status enable */
++              unsigned int tx_fc_en           :  1;   /* 15: TX flow control enable */
++              unsigned int rx_fc_en           :  1;   /* 14: RX flow control enable */
++              unsigned int sim_test           :  1;   /* 13: speed up timers in simulation */
++              unsigned int dis_col            :  1;   /* 12: disable 16 collisions abort function */
++              unsigned int dis_bkoff          :  1;   /* 11: disable back-off function */
++              unsigned int max_len            :  3;   /* 8-10 maximum receive frame length allowed */
++              unsigned int adj_ifg            :  4;   /* 4-7: adjust IFG from 96+/-56 */
++        unsigned int flow_ctrl      :  1;   /* 3: flow control also trigged by Rx queues */
++              unsigned int loop_back          :  1;   /* 2: transmit data loopback enable */
++              unsigned int dis_rx                     :  1;   /* 1: disable receive */
++              unsigned int dis_tx                     :  1;   /* 0: disable transmit */
++#else
++              unsigned int dis_tx                     :  1;   /* 0: disable transmit */
++              unsigned int dis_rx                     :  1;   /* 1: disable receive */
++              unsigned int loop_back          :  1;   /* 2: transmit data loopback enable */
++        unsigned int flow_ctrl      :  1;   /* 3: flow control also trigged by Rx queues */
++              unsigned int adj_ifg            :  4;   /* 4-7: adjust IFG from 96+/-56 */
++              unsigned int max_len            :  3;   /* 8-10 maximum receive frame length allowed */
++              unsigned int dis_bkoff          :  1;   /* 11: disable back-off function */
++              unsigned int dis_col            :  1;   /* 12: disable 16 collisions abort function */
++              unsigned int sim_test           :  1;   /* 13: speed up timers in simulation */
++              unsigned int rx_fc_en           :  1;   /* 14: RX flow control enable */
++              unsigned int tx_fc_en           :  1;   /* 15: TX flow control enable */
++        unsigned int rgmii_en       :  1;   /* 16: RGMII in-band status enable */
++        unsigned int ipv4_rx_chksum :  1;   /* 17: IPv4 RX Checksum enable */
++        unsigned int ipv6_rx_chksum :  1;   /* 18: IPv6 RX Checksum enable */
++        unsigned int rx_tag_remove  :  1;   /* 19: Remove Rx VLAN tag */
++              unsigned int rgmm_edge          :  1;   // 20
++              unsigned int rxc_inv            :  1;   // 21
++              unsigned int ipv6_exthdr_order: 1;      // 22
++              unsigned int rx_err_detect  :  1;       // 23
++              unsigned int port0_chk_hwq      :  1;   // 24
++              unsigned int port1_chk_hwq      :  1;   // 25
++              unsigned int port0_chk_toeq     :  1;   // 26
++              unsigned int port1_chk_toeq     :  1;   // 27
++              unsigned int port0_chk_classq :  1;     // 28
++              unsigned int port1_chk_classq :  1;     // 29
++              unsigned int reserved           :  2;   // 31
++#endif
++      } bits;
++} GMAC_CONFIG0_T;
++
++/**********************************************************************
++ * GMAC Configuration 1
++ * GMAC0 Offset 0xA01C
++ * GMAC1 Offset 0xE01C
++ **********************************************************************/
++typedef union
++{
++      unsigned int bits32;
++      struct bit1_001c
++      {
++#if (BIG_ENDIAN==1)
++              unsigned int reserved           : 16;
++              unsigned int rel_threshold      : 8;    /* flow control release threshold */
++              unsigned int set_threshold      : 8;    /* flow control set threshold */
++#else
++              unsigned int set_threshold      : 8;    /* flow control set threshold */
++              unsigned int rel_threshold      : 8;    /* flow control release threshold */
++              unsigned int reserved           : 16;
++#endif
++      } bits;
++} GMAC_CONFIG1_T;
++
++#define GMAC_FLOWCTRL_SET_MAX         32
++#define GMAC_FLOWCTRL_SET_MIN         0
++#define GMAC_FLOWCTRL_RELEASE_MAX     32
++#define GMAC_FLOWCTRL_RELEASE_MIN     0
++
++/**********************************************************************
++ * GMAC Configuration 2
++ * GMAC0 Offset 0xA020
++ * GMAC1 Offset 0xE020
++ **********************************************************************/
++typedef union
++{
++      unsigned int bits32;
++      struct bit1_0020
++      {
++#if (BIG_ENDIAN==1)
++              unsigned int rel_threshold      : 16;   /* flow control release threshold */
++              unsigned int set_threshold      : 16;   /* flow control set threshold */
++#else
++              unsigned int set_threshold      : 16;   /* flow control set threshold */
++              unsigned int rel_threshold      : 16;   /* flow control release threshold */
++#endif
++      } bits;
++} GMAC_CONFIG2_T;
++
++/**********************************************************************
++ * GMAC Configuration 3
++ * GMAC0 Offset 0xA024
++ * GMAC1 Offset 0xE024
++ **********************************************************************/
++typedef union
++{
++      unsigned int bits32;
++      struct bit1_0024
++      {
++#if (BIG_ENDIAN==1)
++              unsigned int rel_threshold      : 16;   /* flow control release threshold */
++              unsigned int set_threshold      : 16;   /* flow control set threshold */
++#else
++              unsigned int set_threshold      : 16;   /* flow control set threshold */
++              unsigned int rel_threshold      : 16;   /* flow control release threshold */
++#endif
++      } bits;
++} GMAC_CONFIG3_T;
++
++
++/**********************************************************************
++ * GMAC STATUS
++ * GMAC0 Offset 0xA02C
++ * GMAC1 Offset 0xE02C
++ **********************************************************************/
++typedef union
++{
++      unsigned int bits32;
++      struct bit1_002c
++      {
++#if (BIG_ENDIAN==1)
++              unsigned int                            : 25;
++              unsigned int mii_rmii           :  2;   /* PHY interface type */
++              unsigned int reserved           :  1;
++              unsigned int duplex                     :  1;   /* duplex mode */
++              unsigned int speed                      :  2;   /* link speed(00->2.5M 01->25M 10->125M) */
++              unsigned int link                       :  1;   /* link status */
++#else
++              unsigned int link                       :  1;   /* link status */
++              unsigned int speed                      :  2;   /* link speed(00->2.5M 01->25M 10->125M) */
++              unsigned int duplex                     :  1;   /* duplex mode */
++              unsigned int reserved           :  1;
++              unsigned int mii_rmii           :  2;   /* PHY interface type */
++              unsigned int                            : 25;
++#endif
++      } bits;
++} GMAC_STATUS_T;
++
++#define GMAC_SPEED_10                 0
++#define GMAC_SPEED_100                        1
++#define GMAC_SPEED_1000                       2
++
++#define GMAC_PHY_MII                  0
++#define GMAC_PHY_GMII                 1
++#define GMAC_PHY_RGMII_100            2
++#define GMAC_PHY_RGMII_1000           3
++
++/**********************************************************************
++ * Queue Header
++ *    (1) TOE Queue Header
++ *    (2) Non-TOE Queue Header
++ *    (3) Interrupt Queue Header
++ *
++ * memory Layout
++ *    TOE Queue Header
++ *     0x60003000 +---------------------------+ 0x0000
++ *                            |     TOE Queue 0 Header        |
++ *                            |         8 * 4 Bytes       |
++ *                            +---------------------------+ 0x0020
++ *                            |     TOE Queue 1 Header        |
++ *                            |         8 * 4 Bytes           |
++ *                            +---------------------------+ 0x0040
++ *                            |       ......                          |
++ *                            |                                               |
++ *                            +---------------------------+
++ *
++ *    Non TOE Queue Header
++ *     0x60002000 +---------------------------+ 0x0000
++ *                            |   Default Queue 0 Header  |
++ *                            |         2 * 4 Bytes           |
++ *                            +---------------------------+ 0x0008
++ *                            |   Default Queue 1 Header      |
++ *                            |         2 * 4 Bytes           |
++ *                            +---------------------------+ 0x0010
++ *                            |   Classification Queue 0      |
++ *                            |         2 * 4 Bytes           |
++ *                            +---------------------------+
++ *                            |   Classification Queue 1      |
++ *                            |         2 * 4 Bytes           |
++ *                            +---------------------------+ (n * 8 + 0x10)
++ *                            |               ...                             |
++ *                            |         2 * 4 Bytes           |
++ *                            +---------------------------+ (13 * 8 + 0x10)
++ *                            |   Classification Queue 13     |
++ *                            |         2 * 4 Bytes           |
++ *                            +---------------------------+ 0x80
++ *                            |      Interrupt Queue 0        |
++ *                            |         2 * 4 Bytes           |
++ *                            +---------------------------+
++ *                            |      Interrupt Queue 1        |
++ *                            |         2 * 4 Bytes           |
++ *                            +---------------------------+
++ *                            |      Interrupt Queue 2        |
++ *                            |         2 * 4 Bytes           |
++ *                            +---------------------------+
++ *                            |      Interrupt Queue 3        |
++ *                            |         2 * 4 Bytes           |
++ *                            +---------------------------+
++ *
++ **********************************************************************/
++#define TOE_QUEUE_HDR_ADDR(n)         (TOE_TOE_QUE_HDR_BASE + n * 32)
++#define TOE_Q_HDR_AREA_END                    (TOE_QUEUE_HDR_ADDR(TOE_TOE_QUEUE_MAX+1))
++#define TOE_DEFAULT_Q0_HDR_BASE               (TOE_NONTOE_QUE_HDR_BASE + 0x00)
++#define TOE_DEFAULT_Q1_HDR_BASE               (TOE_NONTOE_QUE_HDR_BASE + 0x08)
++#define TOE_CLASS_Q_HDR_BASE          (TOE_NONTOE_QUE_HDR_BASE + 0x10)
++#define TOE_INTR_Q_HDR_BASE                   (TOE_NONTOE_QUE_HDR_BASE + 0x80)
++#define INTERRUPT_QUEUE_HDR_ADDR(n)   (TOE_INTR_Q_HDR_BASE + n * 8)
++#define NONTOE_Q_HDR_AREA_END         (INTERRUPT_QUEUE_HDR_ADDR(TOE_INTR_QUEUE_MAX+1))
++/**********************************************************************
++ * TOE Queue Header Word 0
++ **********************************************************************/
++typedef union
++{
++      unsigned int bits32;
++      unsigned int base_size;
++} TOE_QHDR0_T;
++
++#define TOE_QHDR0_BASE_MASK   (~0x0f)
++
++/**********************************************************************
++ * TOE Queue Header Word 1
++ **********************************************************************/
++typedef union
++{
++      unsigned int bits32;
++      struct bit_qhdr1
++      {
++#if (BIG_ENDIAN==1)
++
++              unsigned int wptr                       : 16;   // bit 31:16
++              unsigned int rptr                       : 16;   // bit 15:0
++#else
++              unsigned int rptr                       : 16;   // bit 15:0
++              unsigned int wptr                       : 16;   // bit 31:16
++#endif
++      } bits;
++} TOE_QHDR1_T;
++
++/**********************************************************************
++ * TOE Queue Header Word 2
++ **********************************************************************/
++typedef union
++{
++      unsigned int bits32;
++      struct bit_qhdr2
++      {
++#if (BIG_ENDIAN==1)
++
++              unsigned int usd                        : 1;    // bit 31               0: if no data assembled yet
++              unsigned int ctl                        : 1;    // bit 30               1: have control flag bits (except ack)
++              unsigned int osq                        : 1;    // bit 29               1: out of sequence
++              unsigned int sat                        : 1;    // bit 28               1: SeqCnt > SeqThreshold, or AckCnt > AckThreshold
++              unsigned int ip_opt                     : 1;    // bit 27               1: have IPV4 option or IPV6 Extension header
++              unsigned int tcp_opt            : 1;    // bit 26               1: Have TCP option
++              unsigned int abn                        : 1;    // bit 25               1: Abnormal case Found
++              unsigned int dack                       : 1;    // bit 24               1: Duplicated ACK
++              unsigned int reserved           : 7;    // bit 23:17
++              unsigned int TotalPktSize       : 17;   // bit 16: 0    Total packet size
++#else
++              unsigned int TotalPktSize       : 17;   // bit 16: 0    Total packet size
++              unsigned int reserved           : 7;    // bit 23:17
++              unsigned int dack                       : 1;    // bit 24               1: Duplicated ACK
++              unsigned int abn                        : 1;    // bit 25               1: Abnormal case Found
++              unsigned int tcp_opt            : 1;    // bit 26               1: Have TCP option
++              unsigned int ip_opt                     : 1;    // bit 27               1: have IPV4 option or IPV6 Extension header
++              unsigned int sat                        : 1;    // bit 28               1: SeqCnt > SeqThreshold, or AckCnt > AckThreshold
++              unsigned int osq                        : 1;    // bit 29               1: out of sequence
++              unsigned int ctl                        : 1;    // bit 30               1: have control flag bits (except ack)
++              unsigned int usd                        : 1;    // bit 31               0: if no data assembled yet
++#endif
++      } bits;
++} TOE_QHDR2_T;
++
++/**********************************************************************
++ * TOE Queue Header Word 3
++ **********************************************************************/
++typedef union
++{
++      unsigned int bits32;
++      unsigned int seq_num;
++} TOE_QHDR3_T;
++
++/**********************************************************************
++ * TOE Queue Header Word 4
++ **********************************************************************/
++typedef union
++{
++      unsigned int bits32;
++      unsigned int ack_num;
++} TOE_QHDR4_T;
++
++/**********************************************************************
++ * TOE Queue Header Word 5
++ **********************************************************************/
++typedef union
++{
++      unsigned int bits32;
++      struct bit_qhdr5
++      {
++#if (BIG_ENDIAN==1)
++
++              unsigned int SeqCnt             : 16;   // bit 31:16
++              unsigned int AckCnt             : 16;   // bit 15:0
++#else
++              unsigned int AckCnt             : 16;   // bit 15:0
++              unsigned int SeqCnt             : 16;   // bit 31:16
++#endif
++      } bits;
++} TOE_QHDR5_T;
++
++/**********************************************************************
++ * TOE Queue Header Word 6
++ **********************************************************************/
++typedef union
++{
++      unsigned int bits32;
++      struct bit_qhdr6
++      {
++#if (BIG_ENDIAN==1)
++
++              unsigned int MaxPktSize : 14;   // bit 31:18
++              unsigned int iq_num             : 2;    // bit 17:16
++              unsigned int WinSize    : 16;   // bit 15:0
++#else
++              unsigned int WinSize    : 16;   // bit 15:0
++              unsigned int iq_num             : 2;    // bit 17:16
++              unsigned int MaxPktSize : 14;   // bit 31:18
++#endif
++      } bits;
++} TOE_QHDR6_T;
++
++/**********************************************************************
++ * TOE Queue Header Word 7
++ **********************************************************************/
++typedef union
++{
++      unsigned int bits32;
++      struct bit_qhdr7
++      {
++#if (BIG_ENDIAN==1)
++
++              unsigned int SeqThreshold       : 16;   // bit 31:16
++              unsigned int AckThreshold       : 16;   // bit 15:0
++#else
++              unsigned int AckThreshold       : 16;   // bit 15:0
++              unsigned int SeqThreshold       : 16;   // bit 31:16
++#endif
++      } bits;
++} TOE_QHDR7_T;
++
++/**********************************************************************
++ * TOE Queue Header
++ **********************************************************************/
++typedef struct
++{
++      TOE_QHDR0_T             word0;
++      TOE_QHDR1_T             word1;
++      TOE_QHDR2_T             word2;
++      TOE_QHDR3_T             word3;
++      TOE_QHDR4_T             word4;
++      TOE_QHDR5_T             word5;
++      TOE_QHDR6_T             word6;
++      TOE_QHDR7_T             word7;
++} TOE_QHDR_T;
++
++/**********************************************************************
++ * NONTOE Queue Header Word 0
++ **********************************************************************/
++typedef union
++{
++      unsigned int bits32;
++      unsigned int base_size;
++} NONTOE_QHDR0_T;
++
++#define NONTOE_QHDR0_BASE_MASK        (~0x0f)
++
++/**********************************************************************
++ * NONTOE Queue Header Word 1
++ **********************************************************************/
++typedef union
++{
++      unsigned int bits32;
++      struct bit_nonqhdr1
++      {
++#if (BIG_ENDIAN==1)
++
++              unsigned int wptr                       : 16;   // bit 31:16
++              unsigned int rptr                       : 16;   // bit 15:0
++#else
++              unsigned int rptr                       : 16;   // bit 15:0
++              unsigned int wptr                       : 16;   // bit 31:16
++#endif
++      } bits;
++} NONTOE_QHDR1_T;
++
++/**********************************************************************
++ * Non-TOE Queue Header
++ **********************************************************************/
++typedef struct
++{
++      NONTOE_QHDR0_T          word0;
++      NONTOE_QHDR1_T          word1;
++} NONTOE_QHDR_T;
++
++/**********************************************************************
++ * Interrupt Queue Header Word 0
++ **********************************************************************/
++typedef union
++{
++      unsigned int bits32;
++      struct bit_intrqhdr0
++      {
++#if (BIG_ENDIAN==1)
++
++              unsigned int wptr               : 16;   // bit 31:16    Write Pointer where hw stopped
++              unsigned int win_size   : 16;   // bit 15:0     Descriptor Ring Size
++#else
++              unsigned int win_size   : 16;   // bit 15:0     Descriptor Ring Size
++              unsigned int wptr               : 16;   // bit 31:16    Write Pointer where hw stopped
++#endif
++      } bits;
++} INTR_QHDR0_T;
++
++/**********************************************************************
++ * Interrupt Queue Header Word 1
++ **********************************************************************/
++typedef union
++{
++      unsigned int bits32;
++      struct bit_intrqhdr1
++      {
++#if (BIG_ENDIAN==1)
++
++              unsigned int ctl                        : 1;    // bit 31               1: have control flag bits (except ack)
++              unsigned int osq                        : 1;    // bit 30               1: out of sequence
++              unsigned int sat                        : 1;    // bit 29               1: SeqCnt > SeqThreshold, or AckCnt > AckThreshold
++              unsigned int ip_opt                     : 1;    // bit 28               1: have IPV4 option or IPV6 Extension header
++              unsigned int tcp_opt            : 1;    // bit 27               1: Have TCP option
++              unsigned int abn                        : 1;    // bit 26               1: Abnormal case Found
++              unsigned int dack                       : 1;    // bit 25               1: Duplicated ACK
++              unsigned int tcp_qid            : 8;    // bit 24:17    TCP Queue ID
++              unsigned int TotalPktSize       : 17;   // bit 16: 0    Total packet size
++#else
++              unsigned int TotalPktSize       : 17;   // bit 16: 0    Total packet size
++              unsigned int tcp_qid            : 8;    // bit 24:17    TCP Queue ID
++              unsigned int dack                       : 1;    // bit 25               1: Duplicated ACK
++              unsigned int abn                        : 1;    // bit 26               1: Abnormal case Found
++              unsigned int tcp_opt            : 1;    // bit 27               1: Have TCP option
++              unsigned int ip_opt                     : 1;    // bit 28               1: have IPV4 option or IPV6 Extension header
++              unsigned int sat                        : 1;    // bit 29               1: SeqCnt > SeqThreshold, or AckCnt > AckThreshold
++              unsigned int osq                        : 1;    // bit 30               1: out of sequence
++              unsigned int ctl                        : 1;    // bit 31               1: have control flag bits (except ack)
++#endif
++      } bits;
++} INTR_QHDR1_T;
++
++/**********************************************************************
++ * Interrupt Queue Header Word 2
++ **********************************************************************/
++typedef union
++{
++      unsigned int bits32;
++      unsigned int seq_num;
++} INTR_QHDR2_T;
++
++/**********************************************************************
++ * Interrupt Queue Header Word 3
++ **********************************************************************/
++typedef union
++{
++      unsigned int bits32;
++      unsigned int ack_num;
++} INTR_QHDR3_T;
++
++/**********************************************************************
++ * Interrupt Queue Header Word 4
++ **********************************************************************/
++typedef union
++{
++      unsigned int bits32;
++      struct bit_intrqhdr4
++      {
++#if (BIG_ENDIAN==1)
++
++              unsigned int SeqCnt             : 16;   // bit 31:16    Seq# change since last seq# intr.
++              unsigned int AckCnt             : 16;   // bit 15:0     Ack# change since last ack# intr.
++#else
++              unsigned int AckCnt             : 16;   // bit 15:0             Ack# change since last ack# intr.
++              unsigned int SeqCnt             : 16;   // bit 31:16    Seq# change since last seq# intr.
++#endif
++      } bits;
++} INTR_QHDR4_T;
++
++/**********************************************************************
++ * Interrupt Queue Header
++ **********************************************************************/
++typedef struct
++{
++      INTR_QHDR0_T            word0;
++      INTR_QHDR1_T            word1;
++      INTR_QHDR2_T            word2;
++      INTR_QHDR3_T            word3;
++      INTR_QHDR4_T            word4;
++      unsigned int            word5;
++      unsigned int            word6;
++      unsigned int            word7;
++} INTR_QHDR_T;
++
++/**********************************************************************
++ * GMAC Conf
++ **********************************************************************/
++typedef struct gmac_conf {
++      struct net_device *dev;
++      int portmap;
++      int vid;
++      int flag;     /* 1: active  0: non-active */
++} sys_gmac_conf;
++
++/**********************************************************************
++ * GMAC private data
++ **********************************************************************/
++typedef struct {
++      unsigned int            rwptr_reg;
++      unsigned int            desc_base;
++      unsigned int            total_desc_num;
++      unsigned short          finished_idx;
++      GMAC_TXDESC_T           *curr_tx_desc;
++      GMAC_TXDESC_T           *curr_finished_desc;
++      struct sk_buff          *tx_skb[TX_DESC_NUM];
++      unsigned long           total_sent;
++      unsigned long           total_finished;
++      unsigned long           intr_cnt;
++} GMAC_SWTXQ_T;
++
++typedef struct {
++      unsigned int            desc_base;
++      unsigned long           eof_cnt;
++} GMAC_HWTXQ_T;
++
++typedef struct gmac_private{
++      struct net_device       *dev;
++      unsigned int            existed;
++      unsigned int            port_id;        // 0 or 1
++      unsigned int            base_addr;
++      unsigned int            dma_base_addr;
++      unsigned char           *mac_addr1;
++      unsigned char           *mac_addr2;
++      unsigned int            swtxq_desc_base;
++      unsigned int            hwtxq_desc_base;
++      GMAC_SWTXQ_T            swtxq[TOE_SW_TXQ_NUM];
++      GMAC_HWTXQ_T            hwtxq[TOE_HW_TXQ_NUM];
++      NONTOE_QHDR_T           *default_qhdr;
++      unsigned int            default_desc_base;
++      unsigned int            default_desc_num;
++      unsigned int            rx_curr_desc;
++      DMA_RWPTR_T                     rx_rwptr;
++      struct sk_buff          *curr_rx_skb;
++      dma_addr_t                      default_desc_base_dma;
++      dma_addr_t                      swtxq_desc_base_dma;
++      dma_addr_t                      hwtxq_desc_base_dma;
++      unsigned int            irq;
++      unsigned int            flow_control_enable     ;
++      unsigned int            pre_phy_status;
++      unsigned int            full_duplex_cfg;
++      unsigned int            speed_cfg;
++      unsigned int            auto_nego_cfg;
++      unsigned int            full_duplex_status;
++      unsigned int            speed_status;
++      unsigned int            phy_mode;       /* 0->MII 1->GMII 2->RGMII(10/100) 3->RGMII(1000) */
++      unsigned int            phy_addr;
++      unsigned int            intr0_enabled;  // 1: enabled
++      unsigned int            intr1_enabled;  // 1: enabled
++      unsigned int            intr2_enabled;  // 1: enabled
++      unsigned int            intr3_enabled;  // 1: enabled
++      unsigned int            intr4_enabled;  // 1: enabled
++//    unsigned int            intr4_enabled_1;        // 1: enabled
++      unsigned int            intr0_selected; // 1: selected
++      unsigned int            intr1_selected; // 1: selected
++      unsigned int            intr2_selected; // 1: selected
++      unsigned int            intr3_selected; // 1: selected
++      unsigned int            intr4_selected; // 1: selected
++      // void                                 (*gmac_rcv_handler)(struct sk_buff *, int);
++      struct net_device_stats ifStatics;
++      unsigned long           txDerr_cnt[GMAC_NUM];
++      unsigned long           txPerr_cnt[GMAC_NUM];
++      unsigned long           RxDerr_cnt[GMAC_NUM];
++      unsigned long           RxPerr_cnt[GMAC_NUM];
++      unsigned int            isr_rx_cnt;
++      unsigned int            isr_tx_cnt;
++      unsigned long           rx_discard;
++      unsigned long           rx_error;
++      unsigned long           rx_mcast;
++      unsigned long           rx_bcast;
++      unsigned long           rx_status_cnt[8];
++      unsigned long           rx_chksum_cnt[8];
++      unsigned long           rx_sta1_ucast;  // for STA 1 MAC Address
++      unsigned long           rx_sta2_ucast;  // for STA 2 MAC Address
++      unsigned long           mib_full_cnt;
++      unsigned long           rx_pause_on_cnt;
++      unsigned long           tx_pause_on_cnt;
++      unsigned long           rx_pause_off_cnt;
++      unsigned long           tx_pause_off_cnt;
++      unsigned long           rx_overrun_cnt;
++      unsigned long           status_changed_cnt;
++      unsigned long           default_q_cnt;
++      unsigned long           hw_fq_empty_cnt;
++      unsigned long           sw_fq_empty_cnt;
++      unsigned long           default_q_intr_cnt;
++      pid_t               thr_pid;
++      wait_queue_head_t   thr_wait;
++      struct completion   thr_exited;
++    spinlock_t          lock;
++    int                 time_to_die;
++    int                                       operation;
++#ifdef SL351x_GMAC_WORKAROUND
++    unsigned long             short_frames_cnt;
++#endif
++}GMAC_INFO_T ;
++
++typedef struct toe_private {
++      unsigned int    swfq_desc_base;
++      unsigned int    hwfq_desc_base;
++      unsigned int    hwfq_buf_base;
++//    unsigned int    toe_desc_base[TOE_TOE_QUEUE_NUM];
++//    unsigned int    toe_desc_num;
++//    unsigned int    class_desc_base;
++//    unsigned int    class_desc_num;
++//    unsigned int    intr_desc_base;
++//    unsigned int    intr_desc_num;
++//    unsigned int    intr_buf_base;
++      DMA_RWPTR_T             fq_rx_rwptr;
++      GMAC_INFO_T             gmac[GMAC_NUM];
++      dma_addr_t              sw_freeq_desc_base_dma;
++      dma_addr_t              hw_freeq_desc_base_dma;
++      dma_addr_t              hwfq_buf_base_dma;
++      dma_addr_t              hwfq_buf_end_dma;
++//    dma_addr_t              toe_desc_base_dma[TOE_TOE_QUEUE_NUM];
++//    dma_addr_t              class_desc_base_dma;
++//    dma_addr_t              intr_desc_base_dma;
++//    dma_addr_t              intr_buf_base_dma;
++//    unsigned long   toe_iq_intr_full_cnt[TOE_INTR_QUEUE_NUM];
++//    unsigned long   toe_iq_intr_cnt[TOE_INTR_QUEUE_NUM];
++//    unsigned long   toe_q_intr_full_cnt[TOE_TOE_QUEUE_NUM];
++//    unsigned long   class_q_intr_full_cnt[TOE_CLASS_QUEUE_NUM];
++//    unsigned long   class_q_intr_cnt[TOE_CLASS_QUEUE_NUM];
++} TOE_INFO_T;
++
++extern TOE_INFO_T toe_private_data;
++
++#define GMAC_PORT0    0
++#define GMAC_PORT1    1
++/**********************************************************************
++ * PHY Definition
++ **********************************************************************/
++#define HPHY_ADDR                     0x01
++#define GPHY_ADDR                     0x02
++
++enum phy_state
++{
++    LINK_DOWN   = 0,
++    LINK_UP     = 1
++};
++
++/* transmit timeout value */
++
++#endif //_GMAC_SL351x_H
+Index: linux-2.6.23.16/include/asm-arm/arch-sl2312/sl351x_hash_cfg.h
+===================================================================
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.23.16/include/asm-arm/arch-sl2312/sl351x_hash_cfg.h      2008-03-15 16:57:25.854761029 +0200
+@@ -0,0 +1,365 @@
++/*-----------------------------------------------------------------------------------
++*     sl351x_hash_cfg.h
++*
++*     Description:
++*     
++*     History:
++*
++*     9/14/2005       Gary Chen       Create
++*
++*-------------------------------------------------------------------------------------*/
++#ifndef _SL351x_HASH_CFG_H_
++#define _SL351x_HASH_CFG_H_   1
++
++// #define NAT_DEBUG_MSG      1
++// #define DEBUG_NAT_MIXED_HW_SW_TX   1
++#ifdef DEBUG_NAT_MIXED_HW_SW_TX
++      // #define NAT_DEBUG_LAN_HASH_TIMEOUT   1
++      // #define NAT_DEBUG_WAN_HASH_TIMEOUT   1
++#endif
++
++#define IPIV(a,b,c,d)         ((a<<24)+(b<<16)+(c<<8)+d)
++#define       IPIV1(a)                        ((a>>24)&0xff)
++#define       IPIV2(a)                        ((a>>16)&0xff)
++#define IPIV3(a)                      ((a>>8)&0xff)
++#define IPIV4(a)                      ((a)&0xff)
++
++#define HASH_MAX_BYTES                        64      // 128
++#define HASH_ACTION_DWORDS            9
++#define HASH_MAX_DWORDS                       (HASH_MAX_BYTES / sizeof(u32))
++#define HASH_MAX_KEY_DWORD            (HASH_MAX_DWORDS - HASH_ACTION_DWORDS)
++#define HASH_INIT_KEY                 0x534C4F52
++#define HASH_BITS                             12      // 12 : Normal, 7: Simulation
++#define HASH_TOTAL_ENTRIES            (1 << HASH_BITS)
++#define HASH_MAX_ENTRIES              (1 << 12)
++#define HASH_TOE_ENTRIES              (HASH_TOTAL_ENTRIES >> 5)
++#define HASH_BITS_MASK                        ((1 << HASH_BITS) - 1)
++
++#define hash_lock(lock)                       // spin_lock_bh(lock)
++#define hash_unlock(lock)             // spin_unlock_bh(lock)
++
++/*----------------------------------------------------------------------
++ *  special macro
++ ----------------------------------------------------------------------*/
++#define HASH_PUSH_WORD(cp, data)      {*cp++ = (((u16)(data))     ) & 0xff;   \
++                                                                      *cp++ = (((u16)(data)) >> 8) & 0xff;} 
++#define HASH_PUSH_DWORD(cp, data)     {*cp++ = (u8)(((u32)(data))      ) & 0xff;      \
++                                                                      *cp++ = (u8)(((u32)(data)) >>  8) & 0xff;       \
++                                                                      *cp++ = (u8)(((u32)(data)) >> 16) & 0xff;       \
++                                                                      *cp++ = (u8)(((u32)(data)) >> 24) & 0xff;}
++#define HASH_PUSH_BYTE(cp, data)      {*cp++ = ((u8)(data)) & 0xff;}
++
++/*----------------------------------------------------------------------
++ *  key
++ ----------------------------------------------------------------------*/
++typedef struct {
++      u8              port;
++      u16             Ethertype;
++      u8              da[6];
++      u8              sa[6];
++      u16             pppoe_sid;      
++      u16             vlan_id;        
++      u8              ipv4_hdrlen;    
++      u8              ip_tos; 
++      u8              ip_protocol;    
++      u32             ipv6_flow_label;
++      u8              sip[16];
++      u8              dip[16];
++      //__u32                 sip[4];
++      //__u32                 dip[4];
++      u8              l4_bytes[24];
++      u8              l7_bytes[24];
++      u8              ipv6;   // 1: IPv6, 0: IPV4
++} ENTRY_KEY_T;
++
++/*----------------------------------------------------------------------
++ *  key for NAT
++ *    Note: packed
++ ----------------------------------------------------------------------*/
++typedef struct {
++      u16             Ethertype;              // not used
++      u8              port_id;
++      u8              rule_id;
++      u8              ip_protocol;
++      u8              reserved1;              // ip_tos, not used
++      u16             reserved2;              // not used
++      u32             sip;
++      u32             dip;
++      u16             sport;
++      u16             dport;
++} NAT_KEY_T;
++
++#define NAT_KEY_DWORD_SIZE    (sizeof(NAT_KEY_T)/sizeof(u32))
++#define NAT_KEY_SIZE          (sizeof(NAT_KEY_T))
++
++/*----------------------------------------------------------------------
++ *  key for NAT
++ *    Note: packed
++ ----------------------------------------------------------------------*/
++typedef struct {
++      u16             Ethertype;              // not used
++      u8              port_id;
++      u8              rule_id;
++      u8              ip_protocol;
++      u8              reserved1;              // ip_tos, not used
++      u16             reserved2;              // not used
++      u32             sip;
++      u32             dip;
++      u16             reserved3;
++      u16             protocol;
++      u16             reserved4;
++      u16             call_id;
++} GRE_KEY_T;
++
++#define GRE_KEY_DWORD_SIZE    (sizeof(GRE_KEY_T)/sizeof(u32))
++#define GRE_KEY_SIZE          (sizeof(GRE_KEY_T))
++/*----------------------------------------------------------------------
++ *  key present or not
++ ----------------------------------------------------------------------*/
++typedef struct {
++      u32             port                    : 1;
++      u32             Ethertype               : 1;
++      u32             da                              : 1;
++      u32             sa                              : 1;
++      u32             pppoe_sid               : 1;    
++      u32             vlan_id                 : 1;    
++      u32             ipv4_hdrlen             : 1;    
++      u32             ip_tos                  : 1;
++      u32             ip_protocol             : 1;    
++      u32             ipv6_flow_label : 1;
++      u32             sip                             : 1;
++      u32             dip                             : 1;
++      u32             l4_bytes_0_3    : 1;
++      u32             l4_bytes_4_7    : 1;
++      u32             l4_bytes_8_11   : 1;
++      u32             l4_bytes_12_15  : 1;
++      u32             l4_bytes_16_19  : 1;
++      u32             l4_bytes_20_23  : 1;
++      u32             l7_bytes_0_3    : 1;
++      u32             l7_bytes_4_7    : 1;
++      u32             l7_bytes_8_11   : 1;
++      u32             l7_bytes_12_15  : 1;
++      u32             l7_bytes_16_19  : 1;
++      u32             l7_bytes_20_23  : 1;
++      u32             reserved                : 8;
++} KEY_FIELD_T;
++
++/*----------------------------------------------------------------------
++ *  action
++ ----------------------------------------------------------------------*/
++typedef struct {
++      u32             reserved0       : 5;    // bit 0:4
++      u32             pppoe           : 2;    // bit 5:6
++      u32             vlan            : 2;    // bit 7:8
++      u32             sa                      : 1;    // bit 9
++      u32             da                      : 1;    // bit 10
++      u32             Dport           : 1;    // bit 11
++      u32             Sport           : 1;    // bit 12
++      u32             Dip                     : 1;    // bit 13
++      u32             Sip                     : 1;    // bit 14
++      u32             sw_id           : 1;    // bit 15
++      u32             frag            : 1;    // bit 16
++      u32             option          : 1;    // bit 17
++      u32             ttl_0           : 1;    // bit 18
++      u32             ttl_1           : 1;    // bit 19
++      u32             mtu                     : 1;    // bit 20
++      u32             exception       : 1;    // bit 21
++      u32             srce_qid        : 1;    // bit 22
++      u32             discard         : 1;    // bit 23
++      u32             dest_qid        : 8;    // bit 24:31
++} ENTRY_ACTION_T;
++
++#define ACTION_DISCARD_BIT            BIT(23)
++#define ACTION_SRCE_QID_BIT           BIT(22)
++#define ACTION_EXCEPTION_BIT  BIT(21)
++#define ACTION_MTU_BIT                        BIT(20)
++#define ACTION_TTL_1_BIT              BIT(19)
++#define ACTION_TTL_0_BIT              BIT(18)
++#define ACTION_IP_OPTION              BIT(17)
++#define ACTION_FRAG_BIT                       BIT(16)
++#define ACTION_SWID_BIT                       BIT(15)
++#define ACTION_SIP_BIT                        BIT(14)
++#define ACTION_DIP_BIT                        BIT(13)
++#define ACTION_SPORT_BIT              BIT(12)
++#define ACTION_DPORT_BIT              BIT(11)
++#define ACTION_DA_BIT                 BIT(10)
++#define ACTION_SA_BIT                 BIT(9)
++#define ACTION_VLAN_DEL_BIT           BIT(8)
++#define ACTION_VLAN_INS_BIT           BIT(7)
++#define ACTION_PPPOE_DEL_BIT  BIT(6)
++#define ACTION_PPPOE_INS_BIT  BIT(5)
++#define ACTION_L4_THIRD_BIT           BIT(4)
++#define ACTION_L4_FOURTH_BIT  BIT(3)
++
++#define NAT_ACTION_BITS                       (ACTION_SRCE_QID_BIT  | ACTION_EXCEPTION_BIT |  \
++                                                              ACTION_TTL_1_BIT | ACTION_TTL_0_BIT |                   \
++                                                              ACTION_IP_OPTION | ACTION_FRAG_BIT |                    \
++                                                              ACTION_DA_BIT | ACTION_SA_BIT)
++#define NAT_LAN2WAN_ACTIONS           (NAT_ACTION_BITS | ACTION_SIP_BIT | ACTION_SPORT_BIT)
++#define NAT_WAN2LAN_ACTIONS           (NAT_ACTION_BITS | ACTION_DIP_BIT | ACTION_DPORT_BIT)
++#define NAT_PPPOE_LAN2WAN_ACTIONS     (NAT_LAN2WAN_ACTIONS | ACTION_PPPOE_INS_BIT)
++#define NAT_PPPOE_WAN2LAN_ACTIONS     (NAT_WAN2LAN_ACTIONS | ACTION_PPPOE_DEL_BIT)
++#define NAT_PPTP_LAN2WAN_ACTIONS      (NAT_ACTION_BITS | ACTION_SIP_BIT | ACTION_L4_FOURTH_BIT)
++#define NAT_PPTP_WAN2LAN_ACTIONS      (NAT_ACTION_BITS | ACTION_DIP_BIT | ACTION_L4_FOURTH_BIT)
++#define NAT_PPPOE_PPTP_LAN2WAN_ACTIONS        (NAT_PPTP_LAN2WAN_ACTIONS | ACTION_PPPOE_INS_BIT)
++#define NAT_PPPOE_PPTP_WAN2LAN_ACTIONS        (NAT_PPTP_WAN2LAN_ACTIONS | ACTION_PPPOE_DEL_BIT)
++                                                              
++/*----------------------------------------------------------------------
++ *  parameter
++ ----------------------------------------------------------------------*/
++typedef struct {
++      u8              da[6];
++      u8              sa[6];
++      u16             vlan;   
++      u16     pppoe;  
++      u32             Sip;
++      u32             Dip;
++      u16     Sport;  
++      u16     Dport;  
++      u16     sw_id;  
++      u16     mtu;    
++} ENTRY_PARAM_T;
++
++/*----------------------------------------------------------------------
++ *  Hash Entry
++ ----------------------------------------------------------------------*/
++typedef struct {
++      char                    rule;
++      ENTRY_KEY_T             key;
++      KEY_FIELD_T             key_present;
++      ENTRY_ACTION_T  action;
++      ENTRY_PARAM_T   param;
++      int                             index;
++      int                             total_dwords;
++} HASH_ENTRY_T;
++
++/*----------------------------------------------------------------------
++ *  NAT Hash Entry
++ ----------------------------------------------------------------------*/
++typedef struct {
++      short   counter;
++      short   interval;
++} HASH_TIMEOUT_T;
++
++/*----------------------------------------------------------------------
++ *  NAT Hash Entry for TCP/UDP protocol
++ ----------------------------------------------------------------------*/
++typedef struct {
++      NAT_KEY_T                       key;
++      union {
++              u32                             dword;
++              ENTRY_ACTION_T  bits;
++      } action;
++      ENTRY_PARAM_T           param;
++      HASH_TIMEOUT_T          tmo;    // used by software only, to use memory space efficiently
++} NAT_HASH_ENTRY_T;
++
++#define NAT_HASH_ENTRY_SIZE           (sizeof(NAT_HASH_ENTRY_T))
++
++/*----------------------------------------------------------------------
++ *  GRE Hash Entry for PPTP/GRE protocol
++ ----------------------------------------------------------------------*/
++typedef struct {
++      GRE_KEY_T                       key;
++      union {
++              u32                             dword;
++              ENTRY_ACTION_T  bits;
++      } action;
++      ENTRY_PARAM_T           param;
++      HASH_TIMEOUT_T          tmo;    // used by software only, to use memory space efficiently
++} GRE_HASH_ENTRY_T;
++
++#define GRE_HASH_ENTRY_SIZE           (sizeof(GRE_HASH_ENTRY_T))
++
++/*----------------------------------------------------------------------
++ *  External Variables
++ ----------------------------------------------------------------------*/
++extern char                           hash_tables[HASH_TOTAL_ENTRIES][HASH_MAX_BYTES] __attribute__ ((aligned(16)));
++extern u32                            hash_nat_owner_bits[HASH_TOTAL_ENTRIES/32];
++/*----------------------------------------------------------------------
++* hash_get_valid_flag
++*----------------------------------------------------------------------*/
++static inline int hash_get_valid_flag(int index)
++{
++      volatile u32 *hash_valid_bits_ptr = (volatile u32 *)TOE_V_BIT_BASE;
++
++#ifdef SL351x_GMAC_WORKAROUND
++      if (index >= (0x80 * 8) && index < (0x8c * 8))
++              return 1;
++#endif        
++      return (hash_valid_bits_ptr[index/32] & (1 << (index %32)));
++}
++
++/*----------------------------------------------------------------------
++* hash_get_nat_owner_flag
++*----------------------------------------------------------------------*/
++static inline int hash_get_nat_owner_flag(int index)
++{
++      return (hash_nat_owner_bits[index/32] & (1 << (index %32)));
++}
++
++/*----------------------------------------------------------------------
++* hash_validate_entry
++*----------------------------------------------------------------------*/
++static inline void hash_validate_entry(int index)
++{
++      volatile u32    *hash_valid_bits_ptr = (volatile u32 *)TOE_V_BIT_BASE;
++      register int    ptr = index/32, bits = 1 << (index %32);
++      
++      hash_valid_bits_ptr[ptr] |= bits;
++}
++
++/*----------------------------------------------------------------------
++* hash_invalidate_entry
++*----------------------------------------------------------------------*/
++static inline void hash_invalidate_entry(int index)
++{
++      volatile u32 *hash_valid_bits_ptr = (volatile u32 *)TOE_V_BIT_BASE;
++      register int    ptr = index/32, bits = 1 << (index %32);
++      
++      hash_valid_bits_ptr[ptr] &= ~(bits);
++}
++
++/*----------------------------------------------------------------------
++* hash_nat_enable_owner
++*----------------------------------------------------------------------*/
++static inline void hash_nat_enable_owner(int index)
++{
++      hash_nat_owner_bits[index/32] |= (1 << (index % 32));
++}
++
++/*----------------------------------------------------------------------
++* hash_nat_disable_owner
++*----------------------------------------------------------------------*/
++static inline void hash_nat_disable_owner(int index)
++{
++      hash_nat_owner_bits[index/32] &= ~(1 << (index % 32));
++}
++
++/*----------------------------------------------------------------------
++* hash_get_entry
++*----------------------------------------------------------------------*/
++static inline void *hash_get_entry(int index)
++{
++      return (void*) &hash_tables[index][0];
++}
++
++/*----------------------------------------------------------------------
++* Functions
++*----------------------------------------------------------------------*/
++extern int hash_add_entry(HASH_ENTRY_T *entry);
++extern void sl351x_hash_init(void);
++extern void hash_set_valid_flag(int index, int valid);
++extern void hash_set_nat_owner_flag(int index, int valid);
++extern void *hash_get_entry(int index);
++extern int hash_build_keys(u32 *destp, HASH_ENTRY_T *entry);
++extern void hash_build_nat_keys(u32 *destp, HASH_ENTRY_T *entry);
++extern int hash_write_entry(HASH_ENTRY_T *entry, u8 *key);
++extern int hash_add_entry(HASH_ENTRY_T *entry);
++extern        u16 hash_crc16(u16 crc, u8 *datap, u32 len);
++extern        u16 hash_gen_crc16(u8 *datap, u32 len);
++
++#endif // _SL351x_HASH_CFG_H_
++
++
++
+Index: linux-2.6.23.16/include/asm-arm/arch-sl2312/sl351x_nat_cfg.h
+===================================================================
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.23.16/include/asm-arm/arch-sl2312/sl351x_nat_cfg.h       2008-03-15 16:57:25.854761029 +0200
+@@ -0,0 +1,211 @@
++/**************************************************************************
++* Copyright 2006 StorLink Semiconductors, Inc.  All rights reserved.                
++*--------------------------------------------------------------------------
++*     sl_nat_cfg.h
++*
++*     Description:
++*             - Define the Device Control Commands for NAT Configuration
++*     
++*     History:
++*
++*     4/28/2006       Gary Chen       Create
++*
++*-----------------------------------------------------------------------------*/
++#ifndef _SL351x_NAT_CFG_H_
++#define _SL351x_NAT_CFG_H_    1
++
++/*----------------------------------------------------------------------
++* Confiuration
++*----------------------------------------------------------------------*/
++#ifdef CONFIG_NETFILTER
++#define CONFIG_SL351x_NAT                     1
++#undef CONFIG_SL351x_NAT
++#undef CONFIG_SL351x_SYSCTL
++#endif
++#define CONFIG_NAT_MAX_IP_NUM         4       // per device (eth0 or eth1)
++#define CONFIG_NAT_MAX_XPORT          64
++#define CONFIG_NAT_MAX_WRULE          16      // per Queue
++#define CONFIG_NAT_TXQ_NUM                    4
++/*----------------------------------------------------------------------
++* Command set
++*----------------------------------------------------------------------*/
++#define SIOCDEVSL351x SIOCDEVPRIVATE  // 0x89F0
++#define NATSSTATUS            0
++#define NATGSTATUS            1
++#define NATSETPORT            2
++#define NATGETPORT            3
++#define NATADDIP              4
++#define NATDELIP              5
++#define NATGETIP              6
++#define NATAXPORT             7
++#define NATDXPORT             8
++#define NATGXPORT             9
++#define NATSWEIGHT            10
++#define NATGWEIGHT            11
++#define NATAWRULE             12
++#define NATDWRULE             13
++#define NATGWRULE             14
++#define NATSDEFQ              15
++#define NATGDEFQ              16
++#define NATRMIPCFG            17              // remove IP config
++#define NATTESTENTRY  18
++#define NATSETMEM             19
++#define NATSHOWMEM            20
++/*----------------------------------------------------------------------
++* Command Structure
++*----------------------------------------------------------------------*/
++// Common Header
++typedef struct {
++      unsigned short          cmd;    // command ID
++      unsigned short          len;    // data length, excluding this header
++} NATCMD_HDR_T;
++
++// NATSSTATUS & NATGSTATUS commands
++typedef struct {
++      unsigned char           enable;
++} NAT_STATUS_T;       
++
++// NATSETPORT & NATGETPORT commands
++typedef struct {
++      unsigned char           portmap;
++} NAT_PORTCFG_T;
++
++typedef struct {
++      unsigned int            ipaddr;
++      unsigned int            netmask;
++} NAT_IP_ENTRY_T;
++
++// NATADDIP & NATDELIP commands
++typedef struct {
++      NAT_IP_ENTRY_T  entry;
++} NAT_IPCFG_T;
++
++// NATGETIP command
++typedef struct {
++      unsigned int    total;
++      NAT_IP_ENTRY_T  entry[CONFIG_NAT_MAX_IP_NUM];
++} NAT_IPCFG_ALL_T;
++
++typedef struct {
++      unsigned int            protocol;
++      unsigned short          sport_start;
++      unsigned short          sport_end;
++      unsigned short          dport_start;
++      unsigned short          dport_end;
++} NAT_XPORT_ENTRY_T;
++
++// NATAXPORT & NATDXPORT Commands
++typedef struct {
++      NAT_XPORT_ENTRY_T       entry;
++} NAT_XPORT_T;
++
++// NATGXPORT Command
++typedef struct {
++      unsigned int            total;
++      NAT_XPORT_ENTRY_T       entry[CONFIG_NAT_MAX_XPORT];
++} NAT_XPORT_ALL_T;
++
++// NATSWEIGHT & NATGWEIGHT Commands
++typedef struct {
++      unsigned char           weight[CONFIG_NAT_TXQ_NUM];
++} NAT_WEIGHT_T;
++
++typedef struct {
++      unsigned int            protocol;
++      unsigned int            sip_start;
++      unsigned int            sip_end;
++      unsigned int            dip_start;
++      unsigned int            dip_end;
++      unsigned short          sport_start;
++      unsigned short          sport_end;
++      unsigned short          dport_start;
++      unsigned short          dport_end;
++} NAT_WRULE_ENTRY_T;  
++
++// NATAWRULE & NATDWRULE Commands
++typedef struct {
++      unsigned int            qid;
++      NAT_WRULE_ENTRY_T       entry;
++} NAT_WRULE_T;
++
++// NATGWRULE Command
++typedef struct {
++      unsigned int            total;
++      NAT_WRULE_ENTRY_T       entry[CONFIG_NAT_MAX_WRULE];
++} NAT_WRULE_ALL_T;
++
++// NATSDEFQ & NATGDEFQ commands
++typedef struct {
++      unsigned int            qid;
++} NAT_QUEUE_T;        
++
++// NATTESTENTRY 
++typedef struct {
++      u_int16_t               cmd;    // command ID
++      u_int16_t               len;    // data length, excluding this header
++      u_int8_t                init_enable;
++} NAT_TESTENTRY_T;    
++      
++typedef union
++{
++      NAT_STATUS_T            status;
++      NAT_PORTCFG_T           portcfg;
++      NAT_IPCFG_T                     ipcfg;
++      NAT_XPORT_T                     xport;
++      NAT_WEIGHT_T            weight;
++      NAT_WRULE_T                     wrule;
++      NAT_QUEUE_T                     queue;
++      NAT_TESTENTRY_T init_entry;
++} NAT_REQ_E;
++      
++/*----------------------------------------------------------------------
++* NAT Configuration
++*     - Used by driver only
++*----------------------------------------------------------------------*/
++typedef struct {
++      unsigned int            enabled;
++      unsigned int            init_enabled;
++      unsigned int            tcp_udp_rule_id;
++      unsigned int            gre_rule_id;
++      unsigned int            lan_port;
++      unsigned int            wan_port;
++      unsigned int            default_hw_txq;
++      short                           tcp_tmo_interval;
++      short                           udp_tmo_interval;
++      short                           gre_tmo_interval;
++      NAT_IPCFG_ALL_T         ipcfg[2];       // LAN/WAN port
++      NAT_XPORT_ALL_T         xport;
++      NAT_WEIGHT_T            weight;
++      NAT_WRULE_ALL_T         wrule[CONFIG_NAT_TXQ_NUM];
++} NAT_CFG_T;
++
++/*----------------------------------------------------------------------
++* NAT Control Block
++*     - Used by driver only
++*     - Stores LAN-IN or WAN-IN information
++*     - WAN-OUT and LAN-OUT driver use them to build up a hash entry
++*     - NOTES: To update this data structure, MUST take care of alignment issue
++*   -          MUST make sure that the size of skbuff structure must 
++*            be larger than (40 + sizof(NAT_CB_T))
++*----------------------------------------------------------------------*/
++typedef struct {
++      unsigned short          tag;
++      unsigned char           sa[6];
++      unsigned int            sip;
++      unsigned int            dip;
++      unsigned short          sport;
++      unsigned short          dport;
++      unsigned char           pppoe_frame;
++      unsigned char           state;                  // same to enum tcp_conntrack
++      unsigned char           reserved[2];
++} NAT_CB_T;
++
++#define NAT_CB_TAG            0x4C53  // "SL"
++#define NAT_CB_SIZE           sizeof(NAT_CB_T)
++// #define NAT_SKB_CB(skb)    (NAT_CB_T *)(((unsigned int)&((skb)->cb[40]) + 3) & ~3)  // for align 4
++#define NAT_SKB_CB(skb)       (NAT_CB_T *)&((skb)->cb[40])  // for align 4
++
++#endif // _SL351x_NAT_CFG_H_
++
++
++
+Index: linux-2.6.23.16/include/asm-arm/arch-sl2312/sl351x_toe.h
+===================================================================
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.23.16/include/asm-arm/arch-sl2312/sl351x_toe.h   2008-03-15 16:57:25.854761029 +0200
+@@ -0,0 +1,88 @@
++/**************************************************************************
++* Copyright 2006 StorLink Semiconductors, Inc.  All rights reserved.
++*--------------------------------------------------------------------------
++* Name                        : sl351x_toe.h
++* Description :
++*             Define for TOE driver of Storlink SL351x
++*
++* History
++*
++*     Date            Writer          Description
++*----------------------------------------------------------------------------
++*                             Xiaochong       Create
++*
++****************************************************************************/
++#ifndef __SL351x_TOE_H
++#define __SL351x_TOE_H        1
++#include <net/sock.h>
++#include <asm/arch/sl351x_gmac.h>
++#include <linux/timer.h>
++#include <linux/netdevice.h>
++#include <linux/ip.h>
++#include <linux/if_ether.h>
++/*
++ * TOE_CONN_T is data structure of tcp connection info, used at both
++ * device layer and kernel tcp layer
++ * skb is the jumbo frame
++ */
++
++struct toe_conn{
++      __u8    qid;            // connection qid 0~63.
++      __u8    ip_ver;         // 0: not used; 4: ipv4; 6: ipv6.
++      /* hash key of the connection */
++      __u16   source;
++      __u16   dest;
++      __u32   saddr[4];
++      __u32   daddr[4];
++
++      __u32   seq;
++      __u32   ack_seq;
++
++      /* these fields are used to set TOE QHDR */
++      __u32   ack_threshold;
++      __u32   seq_threshold;
++      __u16   max_pktsize;
++
++      /* used by sw toe, accumulated ack_seq of ack frames */
++      __u16   ack_cnt;
++      /* used by sw toe, accumulated data frames held at driver */
++      __u16   cur_pktsize;
++
++      __u8    status;
++#define       TCP_CONN_UNDEFINE               0X00
++#define       TCP_CONN_CREATION               0X01
++#define       TCP_CONN_CONNECTING             0X02
++#define       TCP_CONN_ESTABLISHED    0X04
++#define       TCP_CONN_RESET                  0X08    // this is used for out-of-order
++                                                      // or congestion window is small
++#define       TCP_CONN_CLOSING                0X10
++#define       TCP_CONN_CLOSED                 0x11
++
++      __u16   hash_entry_index;       /* associated hash entry */
++
++      // one timer per connection. Otherwise all connections should be scanned
++      // in a timeout interrupt, and timeout interrupt is triggered no matter
++      // a connection is actually timeout or not.
++      struct timer_list       rx_timer;
++      unsigned long           last_rx_jiffies;
++      GMAC_INFO_T                     *gmac;
++      struct net_device       *dev;
++
++      //      for generating pure ack frame.
++      struct ethhdr           l2_hdr;
++      struct iphdr            l3_hdr;
++
++      spinlock_t                      conn_lock;
++      DMA_RWPTR_T                     toeq_rwptr;
++      GMAC_RXDESC_T           *curr_desc;
++      struct sk_buff          *curr_rx_skb;
++};
++
++struct jumbo_frame {
++      struct sk_buff  *skb0;          // the head of jumbo frame
++      struct sk_buff  *tail;          // the tail of jumbo frame
++      struct iphdr    *iphdr0;        // the ip hdr of skb0.
++      struct tcphdr   *tcphdr0;       // the tcp hdr of skb0.
++};
++
++#endif // __SL351x_TOE_H
diff --git a/target/linux/storm/patches/1003-gmac_one_phy.patch b/target/linux/storm/patches/1003-gmac_one_phy.patch
new file mode 100644 (file)
index 0000000..4697a2b
--- /dev/null
@@ -0,0 +1,13 @@
+Index: linux-2.6.x/include/asm-arm/arch-sl2312/sl351x_gmac.h
+===================================================================
+--- linux-2.6.x.orig/include/asm-arm/arch-sl2312/sl351x_gmac.h 2007-09-04 14:18:28.540865746 +0300
++++ linux-2.6.x/include/asm-arm/arch-sl2312/sl351x_gmac.h      2007-09-04 14:15:55.584200244 +0300
+@@ -21,7 +21,7 @@
+ #undef BIG_ENDIAN
+ #define BIG_ENDIAN                            0
+ #define GMAC_DEBUG                            1
+-#define GMAC_NUM                                      2
++#define GMAC_NUM                                      1
+ //#define     L2_jumbo_frame                          1
+ #define _PACKED_                                      __attribute__ ((aligned(1), packed))
diff --git a/target/linux/storm/patches/1004-gmac-enable-napi.patch b/target/linux/storm/patches/1004-gmac-enable-napi.patch
new file mode 100644 (file)
index 0000000..6317160
--- /dev/null
@@ -0,0 +1,83 @@
+Index: linux-2.6.23.16/drivers/net/sl351x_gmac.c
+===================================================================
+--- linux-2.6.23.16.orig/drivers/net/sl351x_gmac.c     2008-03-15 16:59:23.361457295 +0200
++++ linux-2.6.23.16/drivers/net/sl351x_gmac.c  2008-03-15 17:00:32.365389612 +0200
+@@ -68,9 +68,11 @@
+ #include <linux/ip.h>
+ #endif
++/* Enables NAPI unconditionally */
++#define CONFIG_SL_NAPI                                        1
++
+ // #define SL351x_TEST_WORKAROUND
+ #ifdef CONFIG_SL351x_NAT
+-#define CONFIG_SL_NAPI                                        1
+ #endif
+ #define GMAX_TX_INTR_DISABLED                 1
+ #define DO_HW_CHKSUM                                  1
+@@ -124,12 +126,17 @@
+  *************************************************************/
+ static int    gmac_initialized = 0;
+ TOE_INFO_T toe_private_data;
+-//static int          do_again = 0;
++static int            do_again = 0;
+ spinlock_t gmac_fq_lock;
+ unsigned int FLAG_SWITCH;
+ static unsigned int           next_tick = 3 * HZ;
+-static unsigned char          eth_mac[CONFIG_MAC_NUM][6]= {{0x00,0x11,0x11,0x87,0x87,0x87}, {0x00,0x22,0x22,0xab,0xab,0xab}};
++static unsigned char          eth_mac[CONFIG_MAC_NUM][6]= {
++              {0x00,0x11,0x11,0x87,0x87,0x87},
++#if GMAC_NUM != 1
++              {0x00,0x22,0x22,0xab,0xab,0xab}
++#endif
++};
+ #undef CONFIG_SL351x_RXTOE
+ extern NAT_CFG_T nat_cfg;
+@@ -2443,7 +2450,8 @@
+       toe = (TOE_INFO_T *)&toe_private_data;
+ //    handle NAPI
+ #ifdef CONFIG_SL_NAPI
+-if (storlink_ctl.pauseoff == 1)
++      /* XXX: check this, changed from 'storlink_ctl.pauseoff == 1' to if (1) */
++if (1)
+ {
+ /* disable GMAC interrupt */
+     //toe_gmac_disable_interrupt(tp->irq);
+@@ -2530,7 +2538,7 @@
+                               {
+                                       if (likely(netif_rx_schedule_prep(dev)))
+                               {
+-                                      unsigned int data32;
++                                      // unsigned int data32;
+                                       // disable GMAC-0 rx interrupt
+                                       // class-Q & TOE-Q are implemented in future
+                                       //data32 = readl(TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_ENABLE_1_REG);
+@@ -2563,7 +2571,7 @@
+                       {
+                               if (likely(netif_rx_schedule_prep(dev)))
+                       {
+-                              unsigned int data32;
++                              // unsigned int data32;
+                               // disable GMAC-0 rx interrupt
+                               // class-Q & TOE-Q are implemented in future
+                               //data32 = readl(TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_ENABLE_1_REG);
+@@ -4217,7 +4225,7 @@
+       GMAC_INFO_T                     *tp = (GMAC_INFO_T *)dev->priv;
+       unsigned int            status4;
+       volatile DMA_RWPTR_T    fq_rwptr;
+-      int                                     max_cnt = TOE_SW_FREEQ_DESC_NUM;//TOE_SW_FREEQ_DESC_NUM = 64
++      // int                                  max_cnt = TOE_SW_FREEQ_DESC_NUM;//TOE_SW_FREEQ_DESC_NUM = 64
+       //unsigned long         rx_old_bytes;
+       struct net_device_stats *isPtr = (struct net_device_stats *)&tp->ifStatics;
+       //unsigned long long    rx_time;
+@@ -4479,7 +4487,7 @@
+       if (rwptr.bits.rptr == rwptr.bits.wptr)
+       {
+-              unsigned int data32;
++              // unsigned int data32;
+                       //printk("%s:---[rwptr.bits.rptr == rwptr.bits.wptr]   rx_pkts_num=%d------rwptr.bits.rptr=0x%x------->Default_Q [rwptr.bits.rptr(SW)=0x%x,   rwptr.bits.wptr(HW) = 0x%x ]---->Free_Q(SW_HW) = 0x%8x \n",__func__,rx_pkts_num,rwptr.bits.rptr,rwptr.bits.rptr,rwptr.bits.wptr,fq_rwptr.bits32 );
+           /* Receive descriptor is empty now */
diff --git a/target/linux/storm/patches/1005-gmac-napi-mask-intrs.patch b/target/linux/storm/patches/1005-gmac-napi-mask-intrs.patch
new file mode 100644 (file)
index 0000000..b072fe2
--- /dev/null
@@ -0,0 +1,250 @@
+Index: linux-2.6.23.16/drivers/net/sl351x_gmac.c
+===================================================================
+--- linux-2.6.23.16.orig/drivers/net/sl351x_gmac.c     2008-03-15 17:00:32.365389612 +0200
++++ linux-2.6.23.16/drivers/net/sl351x_gmac.c  2008-03-15 17:00:55.366700383 +0200
+@@ -127,6 +127,7 @@
+ static int    gmac_initialized = 0;
+ TOE_INFO_T toe_private_data;
+ static int            do_again = 0;
++static int rx_poll_enabled;
+ spinlock_t gmac_fq_lock;
+ unsigned int FLAG_SWITCH;
+@@ -1065,7 +1066,8 @@
+           tp->intr3_enabled =         0xffffffff;
+           tp->intr4_selected =        GMAC0_INT_BITS | CLASS_RX_FULL_INT_BITS |
+                                                       HWFQ_EMPTY_INT_BIT | SWFQ_EMPTY_INT_BIT;
+-          tp->intr4_enabled =         GMAC0_INT_BITS | SWFQ_EMPTY_INT_BIT;
++          tp->intr4_enabled =         GMAC0_INT_BITS | SWFQ_EMPTY_INT_BIT| GMAC0_RX_OVERRUN_INT_BIT;
++          // GMAC0_TX_PAUSE_OFF_INT_BIT| GMAC0_MIB_INT_BIT;
+           data = readl(TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_SELECT_0_REG) & ~tp->intr0_selected;
+           writel(data, TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_SELECT_0_REG);
+@@ -1115,7 +1117,7 @@
+               tp->intr3_enabled       |=      0xffffffff;
+               tp->intr4_selected      |=      CLASS_RX_FULL_INT_BITS |
+                                                               HWFQ_EMPTY_INT_BIT | SWFQ_EMPTY_INT_BIT;
+-              tp->intr4_enabled       |=      SWFQ_EMPTY_INT_BIT;
++              tp->intr4_enabled       |=      SWFQ_EMPTY_INT_BIT | GMAC1_RX_OVERRUN_INT_BIT;
+               }
+           data = readl(TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_SELECT_0_REG) | tp->intr0_selected;
+           writel(data, TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_SELECT_0_REG);
+@@ -2408,7 +2410,7 @@
+       // unsigned short max_cnt=TOE_SW_FREEQ_DESC_NUM>>1;
+       fq_rwptr.bits32 = readl(TOE_GLOBAL_BASE + GLOBAL_SWFQ_RWPTR_REG);
+-      spin_lock_irqsave(&gmac_fq_lock, flags);
++      // spin_lock_irqsave(&gmac_fq_lock, flags);
+       //while ((max_cnt--) && (unsigned short)RWPTR_ADVANCE_ONE(fq_rwptr.bits.wptr,
+       //                              TOE_SW_FREEQ_DESC_NUM) != fq_rwptr.bits.rptr) {
+       while ((unsigned short)RWPTR_ADVANCE_ONE(fq_rwptr.bits.wptr,
+@@ -2428,10 +2430,47 @@
+               SET_WPTR(TOE_GLOBAL_BASE+GLOBAL_SWFQ_RWPTR_REG, fq_rwptr.bits.wptr);
+               toe_private_data.fq_rx_rwptr.bits32 = fq_rwptr.bits32;
+       }
+-      spin_unlock_irqrestore(&gmac_fq_lock, flags);
++      // spin_unlock_irqrestore(&gmac_fq_lock, flags);
+ }
+ // EXPORT_SYMBOL(toe_gmac_fill_free_q);
++static void gmac_registers(const char *message)
++{
++      unsigned int            status0;
++      unsigned int            status1;
++      unsigned int            status2;
++      unsigned int            status3;
++      unsigned int            status4;
++
++      printk("%s\n", message);
++
++      status0 = readl(TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_STATUS_0_REG);
++      status1 = readl(TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_STATUS_1_REG);
++      status2 = readl(TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_STATUS_2_REG);
++      status3 = readl(TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_STATUS_3_REG);
++      status4 = readl(TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_STATUS_4_REG);
++
++      printk("status: s0:%08X, s1:%08X, s2:%08X, s3:%08X, s4:%08X\n",
++                 status0, status1, status2, status3, status4);
++
++      status0 = readl(TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_ENABLE_0_REG);
++      status1 = readl(TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_ENABLE_1_REG);
++      status2 = readl(TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_ENABLE_2_REG);
++      status3 = readl(TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_ENABLE_3_REG);
++      status4 = readl(TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_ENABLE_4_REG);
++
++      printk("mask  : s0:%08X, s1:%08X, s2:%08X, s3:%08X, s4:%08X\n",
++                 status0, status1, status2, status3, status4);
++
++      status0 = readl(TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_SELECT_0_REG);
++      status1 = readl(TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_SELECT_1_REG);
++      status2 = readl(TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_SELECT_2_REG);
++      status3 = readl(TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_SELECT_3_REG);
++      status4 = readl(TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_SELECT_4_REG);
++
++      printk("select: s0:%08X, s1:%08X, s2:%08X, s3:%08X, s4:%08X\n",
++                 status0, status1, status2, status3, status4);
++}
+ /*----------------------------------------------------------------------
+ * toe_gmac_interrupt
+ *----------------------------------------------------------------------*/
+@@ -2492,6 +2531,7 @@
+               writel(status3 & tp->intr3_enabled, TOE_GLOBAL_BASE+GLOBAL_INTERRUPT_STATUS_3_REG);
+       if (status4)
+               writel(status4 & tp->intr4_enabled, TOE_GLOBAL_BASE+GLOBAL_INTERRUPT_STATUS_4_REG);
++
+ #if 0
+       /* handle freeq interrupt first */
+       if (status4 & tp->intr4_enabled) {
+@@ -2536,10 +2576,31 @@
+                       }
+                               if (netif_running(dev) && (status1 & DEFAULT_Q0_INT_BIT) && (tp->intr1_enabled & DEFAULT_Q0_INT_BIT))
+                               {
+-                                      if (likely(netif_rx_schedule_prep(dev)))
++                                      if (!rx_poll_enabled && likely(netif_rx_schedule_prep(dev)))
+                               {
+-                                      // unsigned int data32;
+-                                      // disable GMAC-0 rx interrupt
++                                      unsigned int data32;
++
++                                              if (rx_poll_enabled)
++                                                              gmac_registers("check #1");
++
++                                              BUG_ON(rx_poll_enabled == 1);
++
++#if 0
++                                      /* Masks GMAC-0 rx interrupt */
++                                              data32  = readl(TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_ENABLE_1_REG);
++                                              data32 &= ~(DEFAULT_Q0_INT_BIT);
++                                              writel(data32, TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_ENABLE_1_REG);
++
++                                      /* Masks GMAC-0 queue empty interrupt */
++                                              data32  = readl(TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_ENABLE_4_REG);
++                                              data32 &= ~DEFAULT_Q0_INT_BIT;
++                                              writel(data32, TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_ENABLE_4_REG);
++
++                                              data32  = readl(TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_SELECT_4_REG);
++                                              data32 &= ~DEFAULT_Q0_INT_BIT;
++                                              writel(data32, TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_SELECT_4_REG);
++#endif
++
+                                       // class-Q & TOE-Q are implemented in future
+                                       //data32 = readl(TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_ENABLE_1_REG);
+                                       //data32 &= ~DEFAULT_Q0_INT_BIT;
+@@ -2549,7 +2610,8 @@
+                                               //tp->total_q_cnt_napi=0;
+                                               //rx_time = jiffies;
+                                               //rx_old_bytes = isPtr->rx_bytes;
+-                              __netif_rx_schedule(dev);
++                                              __netif_rx_schedule(dev);
++                                              rx_poll_enabled = 1;
+                               }
+                       }
+               }
+@@ -2569,9 +2631,31 @@
+                       if (netif_running(dev) && (status1 & DEFAULT_Q1_INT_BIT) && (tp->intr1_enabled & DEFAULT_Q1_INT_BIT))
+                       {
+-                              if (likely(netif_rx_schedule_prep(dev)))
++                              if (!rx_poll_enabled && likely(netif_rx_schedule_prep(dev)))
+                       {
+-                              // unsigned int data32;
++                              unsigned int data32;
++
++                                      if (rx_poll_enabled)
++                                                      gmac_registers("check #2");
++
++                                      BUG_ON(rx_poll_enabled == 1);
++
++#if 0
++                                      /* Masks GMAC-1 rx interrupt */
++                                      data32  = readl(TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_ENABLE_1_REG);
++                                      data32 &= ~(DEFAULT_Q1_INT_BIT);
++                                      writel(data32, TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_ENABLE_1_REG);
++
++                              /* Masks GMAC-1 queue empty interrupt */
++                                      data32  = readl(TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_ENABLE_4_REG);
++                                      data32 &= ~DEFAULT_Q1_INT_BIT;
++                                      writel(data32, TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_ENABLE_4_REG);
++
++                                      data32  = readl(TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_SELECT_4_REG);
++                                      data32 &= ~DEFAULT_Q1_INT_BIT;
++                                      writel(data32, TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_SELECT_4_REG);
++#endif
++
+                               // disable GMAC-0 rx interrupt
+                               // class-Q & TOE-Q are implemented in future
+                               //data32 = readl(TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_ENABLE_1_REG);
+@@ -2583,9 +2667,13 @@
+                                       //rx_time = jiffies;
+                                       //rx_old_bytes = isPtr->rx_bytes;
+                               __netif_rx_schedule(dev);
++                              rx_poll_enabled = 1;
+                       }
+                       }
+               }
++      } else {
++
++              gmac_registers("check #3");
+       }
+       // Interrupt Status 0
+@@ -3306,8 +3394,10 @@
+               SET_RPTR(&tp->default_qhdr->word1, rwptr.bits.rptr);
+       tp->rx_rwptr.bits32 = rwptr.bits32;
+-              toe_gmac_fill_free_q();
+       }
++
++      /* Handles first available packets only then refill the queue. */
++      toe_gmac_fill_free_q();
+ }
+ /*----------------------------------------------------------------------
+@@ -4217,6 +4307,7 @@
+     GMAC_RXDESC_T     *curr_desc;
+       struct sk_buff          *skb;
+     DMA_RWPTR_T                       rwptr;
++    unsigned int data32;
+       unsigned int            pkt_size;
+       unsigned int        desc_count;
+       unsigned int        good_frame, chksum_status, rx_status;
+@@ -4231,7 +4322,7 @@
+       //unsigned long long    rx_time;
+-
++      BUG_ON(rx_poll_enabled == 0);
+ #if 1
+       if (do_again)
+       {
+@@ -4516,6 +4607,30 @@
+ #endif
+         //toe_gmac_fill_free_q();
+         netif_rx_complete(dev);
++
++              rx_poll_enabled = 0;
++
++              data32 = readl(TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_ENABLE_1_REG);
++              if (tp->port_id == 0)
++                              data32 |= DEFAULT_Q0_INT_BIT;
++              else
++                              data32 |= DEFAULT_Q1_INT_BIT;
++              writel(data32, TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_ENABLE_1_REG);
++
++              data32 = readl(TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_ENABLE_4_REG);
++              if (tp->port_id == 0)
++                              data32 |= DEFAULT_Q0_INT_BIT;
++              else
++                              data32 |= DEFAULT_Q1_INT_BIT;
++              writel(data32, TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_ENABLE_4_REG);
++
++              data32 = readl(TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_SELECT_4_REG);
++              if (tp->port_id == 0)
++                              data32 |= DEFAULT_Q0_INT_BIT;
++              else
++                              data32 |= DEFAULT_Q1_INT_BIT;
++              writel(data32, TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_SELECT_4_REG);
++
+         // enable GMAC-0 rx interrupt
+         // class-Q & TOE-Q are implemented in future
+         //data32 = readl(TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_ENABLE_1_REG);
diff --git a/target/linux/storm/patches/1006-gmac-napi-tx.patch b/target/linux/storm/patches/1006-gmac-napi-tx.patch
new file mode 100644 (file)
index 0000000..7ba63b8
--- /dev/null
@@ -0,0 +1,2098 @@
+Index: linux-2.6.23.16/drivers/net/sl351x_gmac.c
+===================================================================
+--- linux-2.6.23.16.orig/drivers/net/sl351x_gmac.c     2008-03-15 17:00:55.366700383 +0200
++++ linux-2.6.23.16/drivers/net/sl351x_gmac.c  2008-03-15 17:01:08.367441241 +0200
+@@ -43,9 +43,13 @@
+ #include <linux/mtd/kvctl.h>
++#define GET_RPTR(x) ((x) & 0xFFFF)
++#define GET_WPTR(x) ((x) >> 16)
++
+ #define        MIDWAY
+ #define        SL_LEPUS
+-#define VITESSE_G5SWITCH      1
++// #define VITESSE_G5SWITCH   1
++#undef VITESSE_G5SWITCH
+ #ifndef CONFIG_SL351x_RXTOE
+ //#define CONFIG_SL351x_RXTOE 1
+@@ -126,7 +130,6 @@
+  *************************************************************/
+ static int    gmac_initialized = 0;
+ TOE_INFO_T toe_private_data;
+-static int            do_again = 0;
+ static int rx_poll_enabled;
+ spinlock_t gmac_fq_lock;
+ unsigned int FLAG_SWITCH;
+@@ -190,7 +193,7 @@
+ void mac_set_sw_tx_weight(struct net_device *dev, char *weight);
+ void mac_get_hw_tx_weight(struct net_device *dev, char *weight);
+ void mac_set_hw_tx_weight(struct net_device *dev, char *weight);
+-static inline void toe_gmac_fill_free_q(void);
++static inline void toe_gmac_fill_free_q(int count);
+ #ifdef VITESSE_G5SWITCH
+ extern int Get_Set_port_status(void);
+@@ -295,12 +298,14 @@
+       for(j = 0; i<CONFIG_MAC_NUM; j++)
+       {
+               i=j;
++#ifdef VITESSE_G5SWITCH
+               if(Giga_switch){                // if gswitch present, swap eth0/1
+                       if(j==0)
+                               i=1;
+                       else if(j==1)
+                               i=0;
+               }
++#endif
+               tp = (GMAC_INFO_T *)&toe_private_data.gmac[i];
+               tp->dev = NULL;
+@@ -459,7 +464,7 @@
+               toe->gmac[1].dma_base_addr = TOE_GMAC1_DMA_BASE;
+         toe->gmac[0].auto_nego_cfg = 1;
+         toe->gmac[1].auto_nego_cfg = 1;
+-#ifdef CONFIG_SL3516_ASIC
++#ifndef CONFIG_SL3516_ASIC
+         toe->gmac[0].speed_cfg = GMAC_SPEED_1000;
+         toe->gmac[1].speed_cfg = GMAC_SPEED_1000;
+ #else
+@@ -508,7 +513,7 @@
+               // Write GLOBAL_QUEUE_THRESHOLD_REG
+               threshold.bits32 = 0;
+               threshold.bits.swfq_empty = (TOE_SW_FREEQ_DESC_NUM > 256) ? 255 :
+-                                                      TOE_SW_FREEQ_DESC_NUM/2;
++                                                      TOE_SW_FREEQ_DESC_NUM/16;
+               threshold.bits.hwfq_empty = (TOE_HW_FREEQ_DESC_NUM > 256) ? 256/4 :
+                                                       TOE_HW_FREEQ_DESC_NUM/4;
+               threshold.bits.toe_class = (TOE_TOE_DESC_NUM > 256) ? 256/4 :
+@@ -613,18 +618,25 @@
+       rwptr_reg.bits.rptr = 0;
+       toe->fq_rx_rwptr.bits32 = rwptr_reg.bits32;
+       writel(rwptr_reg.bits32, TOE_GLOBAL_BASE + GLOBAL_SWFQ_RWPTR_REG);
++      printk("SWFQ: %08X\n", readl(TOE_GLOBAL_BASE + GLOBAL_SWFQ_RWPTR_REG));
+       // SW Free Queue Descriptors
+       for (i=0; i<TOE_SW_FREEQ_DESC_NUM; i++)
+       {
++              void *data = NULL;
+               sw_desc_ptr->word0.bits.buffer_size = SW_RX_BUF_SIZE;
+-              sw_desc_ptr->word1.bits.sw_id = i;      // used to locate skb
++              sw_desc_ptr->word1.bits.sw_id = 0;      // used to locate skb
+               if ( (skb = dev_alloc_skb(SW_RX_BUF_SIZE))==NULL)  /* allocate socket buffer */
+               {
+                       printk("%s::skb buffer allocation fail !\n",__func__); while(1);
+               }
+-              REG32(skb->data) = (unsigned int)skb;
++
++              data = skb->data;
+               skb_reserve(skb, SKB_RESERVE_BYTES);
++
++              REG32(data + 0) = (unsigned int)skb;
++              REG32(data + 4) = (unsigned short)i;
++
+               // toe->rx_skb[i] = skb;
+               sw_desc_ptr->word2.buf_adr = (unsigned int)__pa(skb->data);
+ //            consistent_sync((unsigned int)desc_ptr, sizeof(GMAC_RXDESC_T), PCI_DMA_TODEVICE);
+@@ -851,14 +863,14 @@
+ *----------------------------------------------------------------------*/
+ static void toe_init_default_queue(void)
+ {
+-      TOE_INFO_T                              *toe;
++      TOE_INFO_T              *toe;
+       volatile NONTOE_QHDR_T  *qhdr;
+-      GMAC_RXDESC_T                   *desc_ptr;
+-      DMA_SKB_SIZE_T                  skb_size;
++      GMAC_RXDESC_T           *desc_ptr;
++      DMA_SKB_SIZE_T          skb_size;
+       toe = (TOE_INFO_T *)&toe_private_data;
+       desc_ptr = (GMAC_RXDESC_T *)DMA_MALLOC((TOE_DEFAULT_Q0_DESC_NUM * sizeof(GMAC_RXDESC_T)),
+-                                                                                      (dma_addr_t *)&toe->gmac[0].default_desc_base_dma);
++                                             (dma_addr_t *)&toe->gmac[0].default_desc_base_dma);
+       if (!desc_ptr)
+       {
+               printk("%s::DMA_MALLOC fail !\n",__func__);
+@@ -866,14 +878,17 @@
+       }
+       memset((void *)desc_ptr, 0, TOE_DEFAULT_Q0_DESC_NUM * sizeof(GMAC_RXDESC_T));
+       toe->gmac[0].default_desc_base = (unsigned int)desc_ptr;
++      printk("toe->gmac[0].default_desc_base_dma: %08X\n", toe->gmac[0].default_desc_base_dma);
++
+       toe->gmac[0].default_desc_num = TOE_DEFAULT_Q0_DESC_NUM;
+       qhdr = (volatile NONTOE_QHDR_T *)TOE_DEFAULT_Q0_HDR_BASE;
+       qhdr->word0.base_size = ((unsigned int)toe->gmac[0].default_desc_base_dma & NONTOE_QHDR0_BASE_MASK) | TOE_DEFAULT_Q0_DESC_POWER;
+       qhdr->word1.bits32 = 0;
+       toe->gmac[0].rx_rwptr.bits32 = 0;
+       toe->gmac[0].default_qhdr = (NONTOE_QHDR_T *)qhdr;
++
+       desc_ptr = (GMAC_RXDESC_T *)DMA_MALLOC((TOE_DEFAULT_Q1_DESC_NUM * sizeof(GMAC_RXDESC_T)),
+-                                                                                      (dma_addr_t *)&toe->gmac[1].default_desc_base_dma);
++                                             (dma_addr_t *)&toe->gmac[1].default_desc_base_dma);
+       if (!desc_ptr)
+       {
+               printk("%s::DMA_MALLOC fail !\n",__func__);
+@@ -1071,12 +1086,16 @@
+           data = readl(TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_SELECT_0_REG) & ~tp->intr0_selected;
+           writel(data, TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_SELECT_0_REG);
++
+           data = readl(TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_SELECT_1_REG) & ~tp->intr1_selected;
+           writel(data, TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_SELECT_1_REG);
++
+           data = readl(TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_SELECT_2_REG) & ~tp->intr2_selected;
+           writel(data, TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_SELECT_2_REG);
++
+           data = readl(TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_SELECT_3_REG) & ~tp->intr3_selected;
+           writel(data, TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_SELECT_3_REG);
++
+           data = readl(TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_SELECT_4_REG) & ~tp->intr4_selected;
+           writel(data, TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_SELECT_4_REG);
+       }
+@@ -1176,11 +1195,11 @@
+       GMAC_CONFIG2_T  config2_val;
+       GMAC_CONFIG0_T  config0,config0_mask;
+       GMAC_CONFIG1_T  config1;
+-      #ifdef CONFIG_SL351x_NAT
+       GMAC_CONFIG3_T  config3_val;
+-      #endif
+       GMAC_TX_WCR0_T  hw_weigh;
+       GMAC_TX_WCR1_T  sw_weigh;
++
++      uint32_t weight = 0;
+ //    GMAC_HASH_ENABLE_REG0_T hash_ctrl;
+ //
+ #if 0 /* mac address will be set in late_initcall */
+@@ -1202,24 +1221,23 @@
+       //      config1.bits32 = 0x002004;      //next version
+       /* set flow control threshold */
+       config1.bits32 = 0;
+-      config1.bits.set_threshold = 32 / 2;
+-      config1.bits.rel_threshold = 32 / 4 * 3;
++      config1.bits.set_threshold = (32 / 2);
++      config1.bits.rel_threshold = (32 / 4) * 3;
+       gmac_write_reg(tp->base_addr, GMAC_CONFIG1, config1.bits32, 0xffffffff);
+-      /* set flow control threshold */
++      /* TODO: set flow control threshold */
+       config2_val.bits32 = 0;
+-      config2_val.bits.set_threshold = TOE_SW_FREEQ_DESC_NUM/2;
+-      config2_val.bits.rel_threshold = TOE_SW_FREEQ_DESC_NUM*3/4;
++      config2_val.bits.set_threshold = TOE_SW_FREEQ_DESC_NUM/4;
++      config2_val.bits.rel_threshold = TOE_SW_FREEQ_DESC_NUM/2;
+       gmac_write_reg(tp->base_addr, GMAC_CONFIG2, config2_val.bits32,0xffffffff);
+-      #ifdef CONFIG_SL351x_NAT
+-      /* set HW free queue flow control threshold */
++      /* TODO: set HW free queue flow control threshold */
+       config3_val.bits32 = 0;
+       config3_val.bits.set_threshold = PAUSE_SET_HW_FREEQ;
+       config3_val.bits.rel_threshold = PAUSE_REL_HW_FREEQ;
+       gmac_write_reg(tp->base_addr, GMAC_CONFIG3, config3_val.bits32,0xffffffff);
+-      #endif
+-      /* set_mcast_filter mask*/
++
++      /* TODO: set_mcast_filter mask*/
+       //      gmac_write_reg(tp->base_addr,GMAC_MCAST_FIL0,0x0,0xffffffff);
+       //  gmac_write_reg(tp->base_addr,GMAC_MCAST_FIL1,0x0,0xffffffff);
+@@ -1249,7 +1267,7 @@
+       config0.bits.dis_rx = 1;  /* disable rx */
+       config0.bits.dis_tx = 1;  /* disable tx */
+       config0.bits.loop_back = 0; /* enable/disable GMAC loopback */
+-      config0.bits.rx_err_detect = 1;
++      config0.bits.rx_err_detect = 1; /* TODO: was 1, means disabled, 0 enabled ! */
+       config0.bits.rgmii_en = 0;
+       config0.bits.rgmm_edge = 1;
+       config0.bits.rxc_inv = 0;
+@@ -1342,6 +1360,9 @@
+       gmac_write_reg(tp->dma_base_addr, GMAC_AHB_WEIGHT_REG, ahb_weight.bits32, ahb_weight_mask.bits32);
+       #endif
++      weight = gmac_read_reg(tp->dma_base_addr, GMAC_AHB_WEIGHT_REG);
++      printk("====> %08X\n", weight);
++
+       #if defined(CONFIG_SL351x_NAT) || defined(CONFIG_SL351x_RXTOE)
+       gmac_write_reg(tp->dma_base_addr, GMAC_SPR0, IPPROTO_TCP, 0xffffffff);
+       #endif
+@@ -1552,7 +1573,7 @@
+               rwptr.bits32 = readl(swtxq->rwptr_reg);
+               if (rwptr.bits.rptr == swtxq->finished_idx)
+                       break;
+-      curr_desc = (volatile GMAC_TXDESC_T *)swtxq->desc_base + swtxq->finished_idx;
++              curr_desc = (volatile GMAC_TXDESC_T *)swtxq->desc_base + swtxq->finished_idx;
+ //            consistent_sync((void *)curr_desc, sizeof(GMAC_TXDESC_T), PCI_DMA_FROMDEVICE);
+               word0.bits32 = curr_desc->word0.bits32;
+               word1.bits32 = curr_desc->word1.bits32;
+@@ -1573,6 +1594,7 @@
+                               swtxq->finished_idx = RWPTR_ADVANCE_ONE(swtxq->finished_idx, swtxq->total_desc_num);
+                               curr_desc = (GMAC_TXDESC_T *)swtxq->desc_base + swtxq->finished_idx;
+                               word0.bits32 = curr_desc->word0.bits32;
++
+ #ifdef _DUMP_TX_TCP_CONTENT
+                               if (curr_desc->word0.bits.buffer_size < 16)
+                               {
+@@ -1592,12 +1614,12 @@
+                       word0.bits.status_tx_ok = 0;
+                       if (swtxq->tx_skb[swtxq->finished_idx])
+                       {
+-                              if (interrupt)
+-                                      dev_kfree_skb_irq(swtxq->tx_skb[swtxq->finished_idx]);
+-                              else
+-                                      dev_kfree_skb(swtxq->tx_skb[swtxq->finished_idx]);
++                              dev_kfree_skb(swtxq->tx_skb[swtxq->finished_idx]);
+                               swtxq->tx_skb[swtxq->finished_idx] = NULL;
++                      } else {
++                              BUG();
+                       }
++
+                       curr_desc->word0.bits32 = word0.bits32;
+                       swtxq->curr_finished_desc = (GMAC_TXDESC_T *)curr_desc;
+                       swtxq->total_finished++;
+@@ -1624,31 +1646,29 @@
+ *----------------------------------------------------------------------*/
+ static int gmac_start_xmit(struct sk_buff *skb, struct net_device *dev)
+ {
+-      GMAC_INFO_T                     *tp= dev->priv;
+-//    static unsigned int     pcount = 0;
+-//    unsigned int                    tx_qid;
+-    DMA_RWPTR_T                               rwptr;
+-      volatile GMAC_TXDESC_T  *curr_desc;
+-      int                                     snd_pages = skb_shinfo(skb)->nr_frags + 1;  /* get number of descriptor */
+-      int                                     frag_id = 0;
+-      int                                     len, total_len = skb->len;
++      GMAC_INFO_T *tp= dev->priv;
++      DMA_RWPTR_T rwptr;
++      GMAC_TXDESC_T *curr_desc;
++      int snd_pages = skb_shinfo(skb)->nr_frags + 1;  /* get number of descriptor */
++      int frag_id = 0;
++      int len, total_len = skb->len;
+       struct net_device_stats *isPtr;
+-      unsigned int                    free_desc;
+-      GMAC_SWTXQ_T                    *swtxq;
++      unsigned int free_desc;
++      GMAC_SWTXQ_T *swtxq;
+       register unsigned long  word0, word1, word2, word3;
+       unsigned short                  wptr, rptr;
+ #ifdef        L2_jumbo_frame
+       int header_len = skb->len;
+       struct iphdr    *ip_hdr;
+-    struct tcphdr     *tcp_hdr;
+-    int             tcp_hdr_len;
+-    unsigned char     *ptr;
+-    int             data_len,a;
+-    unsigned int    val;
++      struct tcphdr   *tcp_hdr;
++      int             tcp_hdr_len;
++      unsigned char   *ptr;
++      int             data_len,a;
++      unsigned int    val;
+ #endif
+ #ifdef GMAC_LEN_1_2_ISSUE
+-      int                                             total_pages;
++      int total_pages;
+       total_pages = snd_pages;
+ #endif
+@@ -1664,13 +1684,6 @@
+     }
+ #endif
+-#if 0
+-      if (storlink_ctl.recvfile==2)
+-      {
+-          printk("snd_pages=%d skb->len=%d\n",snd_pages,skb->len);
+-      }
+-#endif
+-
+ #ifdef GMAC_USE_TXQ0
+       #define tx_qid  0
+ #endif
+@@ -1703,9 +1716,9 @@
+       toe_gmac_tx_complete(tp, tx_qid, dev, 0);
+       if (wptr >= swtxq->finished_idx)
+-              free_desc = swtxq->total_desc_num - wptr - 1 + swtxq->finished_idx;
++              free_desc = swtxq->total_desc_num - wptr + swtxq->finished_idx;
+       else
+-              free_desc = swtxq->finished_idx - wptr - 1;
++              free_desc = swtxq->finished_idx - wptr;
+       if (free_desc < snd_pages)
+       {
+ //            spin_unlock(&tp->tx_mutex);
+@@ -2063,9 +2076,10 @@
+ struct net_device_stats * gmac_get_stats(struct net_device *dev)
+ {
+     GMAC_INFO_T *tp = (GMAC_INFO_T *)dev->priv;
++#if 0 /* don't read stats from hardware, scary numbers. */
+     // unsigned int        flags;
+-    unsigned int        pkt_drop;
+-    unsigned int        pkt_error;
++    unsigned int        pkt_drop = 0;
++    unsigned int        pkt_error = 0;
+     if (netif_running(dev))
+     {
+@@ -2073,10 +2087,14 @@
+         // spin_lock_irqsave(&tp->lock,flags);
+         pkt_drop = gmac_read_reg(tp->base_addr,GMAC_IN_DISCARDS);
+         pkt_error = gmac_read_reg(tp->base_addr,GMAC_IN_ERRORS);
++      printk("**** stack: %lu, hw: %lu\n", tp->ifStatics.rx_dropped, pkt_drop);
++
+         tp->ifStatics.rx_dropped = tp->ifStatics.rx_dropped + pkt_drop;
+         tp->ifStatics.rx_errors = tp->ifStatics.rx_errors + pkt_error;
+         // spin_unlock_irqrestore(&tp->lock,flags);
+     }
++#endif
++
+     return &tp->ifStatics;
+ }
+@@ -2401,36 +2419,63 @@
+ * toe_gmac_fill_free_q
+ * allocate buffers for free queue.
+ *----------------------------------------------------------------------*/
+-static inline void toe_gmac_fill_free_q(void)
++static inline void toe_gmac_fill_free_q(int count)
+ {
+       struct sk_buff  *skb;
+       volatile DMA_RWPTR_T    fq_rwptr;
+       volatile GMAC_RXDESC_T  *fq_desc;
+-      unsigned long   flags;
++      unsigned long flags;
++      unsigned short index;
++      int filled = 0;
++      static int entered;
+       // unsigned short max_cnt=TOE_SW_FREEQ_DESC_NUM>>1;
++      BUG_ON(entered == 1);
++
++      entered = 1;
++
++
+       fq_rwptr.bits32 = readl(TOE_GLOBAL_BASE + GLOBAL_SWFQ_RWPTR_REG);
+       // spin_lock_irqsave(&gmac_fq_lock, flags);
+       //while ((max_cnt--) && (unsigned short)RWPTR_ADVANCE_ONE(fq_rwptr.bits.wptr,
+       //                              TOE_SW_FREEQ_DESC_NUM) != fq_rwptr.bits.rptr) {
+-      while ((unsigned short)RWPTR_ADVANCE_ONE(fq_rwptr.bits.wptr,
+-                                      TOE_SW_FREEQ_DESC_NUM) != fq_rwptr.bits.rptr) {
++      index = fq_rwptr.bits.wptr;
++#if 0
++      printk("wptr: %hu, rptr: %hu, refill idx: %hu\n",
++             GET_RPTR(fq_rwptr.bits32),
++             GET_WPTR(fq_rwptr.bits32),
++             index);
++#endif
++
++      index = RWPTR_ADVANCE_ONE(index, TOE_SW_FREEQ_DESC_NUM);
++      fq_desc = (GMAC_RXDESC_T*)toe_private_data.swfq_desc_base + index;
++      while (fq_desc->word2.buf_adr == 0) {
++              void *data = NULL;
++
+               if ((skb = dev_alloc_skb(SW_RX_BUF_SIZE)) == NULL) {
+                       printk("%s::skb allocation fail!\n", __func__);
+-                      //while(1);
+-                      break;
++                      goto out;
+               }
+-              REG32(skb->data) = (unsigned int)skb;
++              ++ filled;
++              data = skb->data;
+               skb_reserve(skb, SKB_RESERVE_BYTES);
+-              // fq_rwptr.bits32 = readl(TOE_GLOBAL_BASE + GLOBAL_SWFQ_RWPTR_REG);
+-              fq_rwptr.bits.wptr = RWPTR_ADVANCE_ONE(fq_rwptr.bits.wptr,
+-                      TOE_SW_FREEQ_DESC_NUM);
+-              fq_desc = (GMAC_RXDESC_T*)toe_private_data.swfq_desc_base+fq_rwptr.bits.wptr;
++
++              REG32(data + 0) = (unsigned int)skb;
++              REG32(data + 4) = (unsigned short)index;
++
++              // printk("refill skb: %p, idx: %hu\n", skb, index);
+               fq_desc->word2.buf_adr = (unsigned int)__pa(skb->data);
+-              SET_WPTR(TOE_GLOBAL_BASE+GLOBAL_SWFQ_RWPTR_REG, fq_rwptr.bits.wptr);
+-              toe_private_data.fq_rx_rwptr.bits32 = fq_rwptr.bits32;
++      writel(0x07960202, TOE_GMAC0_BASE+GMAC_CONFIG0);
++              SET_WPTR(TOE_GLOBAL_BASE+GLOBAL_SWFQ_RWPTR_REG, index);
++      writel(0x07960200, TOE_GMAC0_BASE+GMAC_CONFIG0);
++
++              index = RWPTR_ADVANCE_ONE(index, TOE_SW_FREEQ_DESC_NUM);
++              fq_desc = (GMAC_RXDESC_T*)toe_private_data.swfq_desc_base+index;
+       }
++out:
+       // spin_unlock_irqrestore(&gmac_fq_lock, flags);
++
++      entered = 0;
+ }
+ // EXPORT_SYMBOL(toe_gmac_fill_free_q);
+@@ -2442,14 +2487,14 @@
+       unsigned int            status3;
+       unsigned int            status4;
+-      printk("%s\n", message);
+-
+       status0 = readl(TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_STATUS_0_REG);
+       status1 = readl(TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_STATUS_1_REG);
+       status2 = readl(TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_STATUS_2_REG);
+       status3 = readl(TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_STATUS_3_REG);
+       status4 = readl(TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_STATUS_4_REG);
++      printk("%s\n", message);
++
+       printk("status: s0:%08X, s1:%08X, s2:%08X, s3:%08X, s4:%08X\n",
+                  status0, status1, status2, status3, status4);
+@@ -2468,8 +2513,9 @@
+       status3 = readl(TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_SELECT_3_REG);
+       status4 = readl(TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_SELECT_4_REG);
+-      printk("select: s0:%08X, s1:%08X, s2:%08X, s3:%08X, s4:%08X\n",
+-                 status0, status1, status2, status3, status4);
++      if (status0 || status1 || status2 || status3 || status4)
++                      printk("select: s0:%08X, s1:%08X, s2:%08X, s3:%08X, s4:%08X\n",
++                                 status0, status1, status2, status3, status4);
+ }
+ /*----------------------------------------------------------------------
+ * toe_gmac_interrupt
+@@ -2485,75 +2531,44 @@
+       unsigned int            status3;
+       unsigned int            status4;
+-//    struct net_device_stats *isPtr = (struct net_device_stats *)&tp->ifStatics;
+       toe = (TOE_INFO_T *)&toe_private_data;
+-//    handle NAPI
+-#ifdef CONFIG_SL_NAPI
+-      /* XXX: check this, changed from 'storlink_ctl.pauseoff == 1' to if (1) */
+-if (1)
+-{
+-/* disable GMAC interrupt */
+-    //toe_gmac_disable_interrupt(tp->irq);
+-//    isPtr->interrupts++;
++      if (0 && rx_poll_enabled) {
++              gmac_registers("interrupt handler");
++      }
++
+       /* read Interrupt status */
+       status0 = readl(TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_STATUS_0_REG);
+       status1 = readl(TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_STATUS_1_REG);
+       status2 = readl(TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_STATUS_2_REG);
+       status3 = readl(TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_STATUS_3_REG);
+       status4 = readl(TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_STATUS_4_REG);
+-      // prompt warning if status bit ON but not enabled
++
+ #if 0
+-      if (status0 & ~tp->intr0_enabled)
+-              printk("Intr 0 Status error. status = 0x%X, enable = 0x%X\n",
+-                              status0, tp->intr0_enabled);
+-      if (status1 & ~tp->intr1_enabled)
+-              printk("Intr 1 Status error. status = 0x%X, enable = 0x%X\n",
+-                              status1, tp->intr1_enabled);
+-      if (status2 & ~tp->intr2_enabled)
+-              printk("Intr 2 Status error. status = 0x%X, enable = 0x%X\n",
+-                              status2, tp->intr2_enabled);
+-      if (status3 & ~tp->intr3_enabled)
+-              printk("Intr 3 Status error. status = 0x%X, enable = 0x%X\n",
+-                              status3, tp->intr3_enabled);
+-      if (status4 & ~tp->intr4_enabled)
+-              printk("Intr 4 Status error. status = 0x%X, enable = 0x%X\n",
+-                              status4, tp->intr4_enabled);
++      /* handle freeq interrupt first */
++      if (status4 & SWFQ_EMPTY_INT_BIT)
++      {
++              toe_gmac_fill_free_q();
++              writel(status4 & SWFQ_EMPTY_INT_BIT, TOE_GLOBAL_BASE+GLOBAL_INTERRUPT_STATUS_4_REG);
++              tp->sw_fq_empty_cnt++;
++      }
+ #endif
++      if (status4 & GMAC0_MIB_INT_BIT)
++              writel(GMAC0_MIB_INT_BIT, TOE_GLOBAL_BASE+GLOBAL_INTERRUPT_STATUS_4_REG);
++
++      if (status4 & GMAC0_RX_OVERRUN_INT_BIT)
++              writel(GMAC0_RX_OVERRUN_INT_BIT, TOE_GLOBAL_BASE+GLOBAL_INTERRUPT_STATUS_4_REG);
++
+       if (status0)
+               writel(status0 & tp->intr0_enabled, TOE_GLOBAL_BASE+GLOBAL_INTERRUPT_STATUS_0_REG);
+-      if (status1)
+-              writel(status1 & tp->intr1_enabled, TOE_GLOBAL_BASE+GLOBAL_INTERRUPT_STATUS_1_REG);
+       if (status2)
+               writel(status2 & tp->intr2_enabled, TOE_GLOBAL_BASE+GLOBAL_INTERRUPT_STATUS_2_REG);
+       if (status3)
+               writel(status3 & tp->intr3_enabled, TOE_GLOBAL_BASE+GLOBAL_INTERRUPT_STATUS_3_REG);
+-      if (status4)
+-              writel(status4 & tp->intr4_enabled, TOE_GLOBAL_BASE+GLOBAL_INTERRUPT_STATUS_4_REG);
+-
+-#if 0
+-      /* handle freeq interrupt first */
+-      if (status4 & tp->intr4_enabled) {
+-              if ((status4 & SWFQ_EMPTY_INT_BIT) && (tp->intr4_enabled & SWFQ_EMPTY_INT_BIT))
+-              {
+-                      // unsigned long data = REG32(TOE_GLOBAL_BASE + GLOBAL_SWFQ_RWPTR_REG);
+-                      //gmac_write_reg(TOE_GLOBAL_BASE, GLOBAL_INTERRUPT_ENABLE_4_REG,
+-                      //      tp->intr4_enabled & ~SWFQ_EMPTY_INT_BIT, SWFQ_EMPTY_INT_BIT);
+-
+-                      if (toe->gmac[0].dev && netif_running(toe->gmac[0].dev))
+-                              toe_gmac_handle_default_rxq(toe->gmac[0].dev,&toe->gmac[0]);
+-                      if (toe->gmac[1].dev && netif_running(toe->gmac[1].dev))
+-                              toe_gmac_handle_default_rxq(toe->gmac[1].dev,&toe->gmac[1]);
+-                      printk("\nfreeq int\n");
+-                      toe_gmac_fill_free_q();
+-                      tp->sw_fq_empty_cnt++;
+-              }
+-      }
+-#endif
+       // Interrupt Status 1
+-      if (status1 & tp->intr1_enabled)
++      if ((status1 & 3) || (status4 & 1))
+       {
+               #define G1_INTR0_BITS   (GMAC1_HWTQ13_EOF_INT_BIT | GMAC1_HWTQ12_EOF_INT_BIT | GMAC1_HWTQ11_EOF_INT_BIT | GMAC1_HWTQ10_EOF_INT_BIT)
+               #define G0_INTR0_BITS   (GMAC0_HWTQ03_EOF_INT_BIT | GMAC0_HWTQ02_EOF_INT_BIT | GMAC0_HWTQ01_EOF_INT_BIT | GMAC0_HWTQ00_EOF_INT_BIT)
+@@ -2563,7 +2578,7 @@
+               // because they should pass packets to upper layer
+               if (tp->port_id == 0)
+               {
+-                      if (netif_running(dev) && (status1 & G0_INTR0_BITS) && (tp->intr1_enabled & G0_INTR0_BITS))
++                      if (((status1 & G0_INTR0_BITS) && (tp->intr1_enabled & G0_INTR0_BITS)) || (status4 & 1))
+                       {
+                               if (status1 & GMAC0_HWTQ03_EOF_INT_BIT)
+                                       tp->hwtxq[3].eof_cnt++;
+@@ -2574,50 +2589,51 @@
+                               if (status1 & GMAC0_HWTQ00_EOF_INT_BIT)
+                                       tp->hwtxq[0].eof_cnt++;
+                       }
+-                              if (netif_running(dev) && (status1 & DEFAULT_Q0_INT_BIT) && (tp->intr1_enabled & DEFAULT_Q0_INT_BIT))
++                      if (status1 & DEFAULT_Q0_INT_BIT || status4 & 1)
++                      {
++                              if (likely(netif_rx_schedule_prep(dev)))
+                               {
+-                                      if (!rx_poll_enabled && likely(netif_rx_schedule_prep(dev)))
+-                              {
+-                                      unsigned int data32;
++                                      unsigned int data32;
++
++                                      BUG_ON(rx_poll_enabled == 1);
+-                                              if (rx_poll_enabled)
+-                                                              gmac_registers("check #1");
++                                      /* Masks GMAC-0 rx interrupt */
++                                      data32  = readl(TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_ENABLE_1_REG);
++                                      data32 &= ~(DEFAULT_Q0_INT_BIT);
++                                      writel(data32, TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_ENABLE_1_REG);
+-                                              BUG_ON(rx_poll_enabled == 1);
++                                      /* Masks GMAC-0 queue empty interrupt */
++                                      data32  = readl(TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_ENABLE_4_REG);
++                                      data32 &= ~DEFAULT_Q0_INT_BIT;
++                                      writel(data32, TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_ENABLE_4_REG);
++                                      __netif_rx_schedule(dev);
++                                      rx_poll_enabled = 1;
++                              } else {
+ #if 0
+-                                      /* Masks GMAC-0 rx interrupt */
+-                                              data32  = readl(TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_ENABLE_1_REG);
+-                                              data32 &= ~(DEFAULT_Q0_INT_BIT);
+-                                              writel(data32, TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_ENABLE_1_REG);
+-
+-                                      /* Masks GMAC-0 queue empty interrupt */
+-                                              data32  = readl(TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_ENABLE_4_REG);
+-                                              data32 &= ~DEFAULT_Q0_INT_BIT;
+-                                              writel(data32, TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_ENABLE_4_REG);
+-
+-                                              data32  = readl(TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_SELECT_4_REG);
+-                                              data32 &= ~DEFAULT_Q0_INT_BIT;
+-                                              writel(data32, TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_SELECT_4_REG);
+-#endif
+-
+-                                      // class-Q & TOE-Q are implemented in future
+-                                      //data32 = readl(TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_ENABLE_1_REG);
+-                                      //data32 &= ~DEFAULT_Q0_INT_BIT;
+-                                              //writel(data32, TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_ENABLE_1_REG);
+-                                              //printk("\%s: DEFAULT_Q0_INT_BIT===================>>>>>>>>>>>>\n",__func__);
+-                                              writel(0x0, TOE_GLOBAL_BASE+GLOBAL_INTERRUPT_ENABLE_1_REG);
+-                                              //tp->total_q_cnt_napi=0;
+-                                              //rx_time = jiffies;
+-                                              //rx_old_bytes = isPtr->rx_bytes;
+-                                              __netif_rx_schedule(dev);
+-                                              rx_poll_enabled = 1;
+-                              }
++                                      unsigned int data32;
++
++                                      if (rx_poll_enabled)
++                                              gmac_registers("->poll() running.");
++                                      /* Masks GMAC-0 rx interrupt */
++                                      data32  = readl(TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_ENABLE_1_REG);
++                                      data32 &= ~(DEFAULT_Q0_INT_BIT);
++                                      writel(data32, TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_ENABLE_1_REG);
++
++                                      /* Masks GMAC-0 queue empty interrupt */
++                                      data32  = readl(TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_ENABLE_4_REG);
++                                      data32 &= ~DEFAULT_Q0_INT_BIT;
++                                      writel(data32, TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_ENABLE_4_REG);
++#endif
++                              }
++                      } else {
++                              if (0)
++                                      gmac_registers("status1 & DEFAULT_Q0_INT_BIT || status4 & 1");
+                       }
+               }
+-              else if (tp->port_id == 1)
++              else if (tp->port_id == 1 && netif_running(dev))
+               {
+-                      if (netif_running(dev) && (status1 & G1_INTR0_BITS) && (tp->intr1_enabled & G1_INTR0_BITS))
++                      if ((status1 & G1_INTR0_BITS) && (tp->intr1_enabled & G1_INTR0_BITS))
+                       {
+                               if (status1 & GMAC1_HWTQ13_EOF_INT_BIT)
+                                       tp->hwtxq[3].eof_cnt++;
+@@ -2629,14 +2645,14 @@
+                                       tp->hwtxq[0].eof_cnt++;
+                       }
+-                      if (netif_running(dev) && (status1 & DEFAULT_Q1_INT_BIT) && (tp->intr1_enabled & DEFAULT_Q1_INT_BIT))
++                      if ((status1 & DEFAULT_Q1_INT_BIT) && (tp->intr1_enabled & DEFAULT_Q1_INT_BIT))
+                       {
+                               if (!rx_poll_enabled && likely(netif_rx_schedule_prep(dev)))
+-                      {
+-                              unsigned int data32;
++                              {
++                                      unsigned int data32;
+                                       if (rx_poll_enabled)
+-                                                      gmac_registers("check #2");
++                                              gmac_registers("check #2");
+                                       BUG_ON(rx_poll_enabled == 1);
+@@ -2646,7 +2662,7 @@
+                                       data32 &= ~(DEFAULT_Q1_INT_BIT);
+                                       writel(data32, TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_ENABLE_1_REG);
+-                              /* Masks GMAC-1 queue empty interrupt */
++                                      /* Masks GMAC-1 queue empty interrupt */
+                                       data32  = readl(TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_ENABLE_4_REG);
+                                       data32 &= ~DEFAULT_Q1_INT_BIT;
+                                       writel(data32, TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_ENABLE_4_REG);
+@@ -2656,24 +2672,21 @@
+                                       writel(data32, TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_SELECT_4_REG);
+ #endif
+-                              // disable GMAC-0 rx interrupt
+-                              // class-Q & TOE-Q are implemented in future
+-                              //data32 = readl(TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_ENABLE_1_REG);
+-                              //data32 &= ~DEFAULT_Q1_INT_BIT;
++                                      // disable GMAC-0 rx interrupt
++                                      // class-Q & TOE-Q are implemented in future
++                                      //data32 = readl(TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_ENABLE_1_REG);
++                                      //data32 &= ~DEFAULT_Q1_INT_BIT;
+                                       //writel(data32, TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_ENABLE_1_REG);
+                                       //printk("\%s: 1111111111--->DEFAULT_Q1_INT_BIT===================>>>>>>>>>>>>\n",__func__);
+                                       writel(0x0, TOE_GLOBAL_BASE+GLOBAL_INTERRUPT_ENABLE_1_REG);
+                                       //tp->total_q_cnt_napi=0;
+                                       //rx_time = jiffies;
+                                       //rx_old_bytes = isPtr->rx_bytes;
+-                              __netif_rx_schedule(dev);
+-                              rx_poll_enabled = 1;
+-                      }
++                                      __netif_rx_schedule(dev);
++                                      rx_poll_enabled = 1;
++                              }
+                       }
+               }
+-      } else {
+-
+-              gmac_registers("check #3");
+       }
+       // Interrupt Status 0
+@@ -2814,676 +2827,93 @@
+               }
+       }
+-      //toe_gmac_enable_interrupt(tp->irq);
+-#ifdef IxscriptMate_1518
+-      if (storlink_ctl.pauseoff == 1)
+-      {
+-              GMAC_CONFIG0_T config0;
+-              config0.bits32 = readl(TOE_GMAC0_BASE+GMAC_CONFIG0);
+-              config0.bits.dis_rx = 0;
+-              writel(config0.bits32, TOE_GMAC0_BASE+GMAC_CONFIG0);
+-              config0.bits32 = readl(TOE_GMAC1_BASE+GMAC_CONFIG0);
+-              config0.bits.dis_rx = 0;
+-              writel(config0.bits32, TOE_GMAC1_BASE+GMAC_CONFIG0);
+-      }
+-#endif
+-//     enable_irq(gmac_irq[dev_index]);
+-      //printk("gmac_interrupt complete!\n\n");
+-//    return IRQ_RETVAL(handled);
+       return  IRQ_RETVAL(1);
+ }
+-else
+-{
+-#endif        //endif NAPI
++/*----------------------------------------------------------------------
++* gmac_get_phy_vendor
++*----------------------------------------------------------------------*/
++static unsigned int gmac_get_phy_vendor(int phy_addr)
++{
++    unsigned int      reg_val;
++    reg_val=(mii_read(phy_addr,0x02) << 16) + mii_read(phy_addr,0x03);
++    return reg_val;
++}
+-      /* disable GMAC interrupt */
+-    toe_gmac_disable_interrupt(tp->irq);
++/*----------------------------------------------------------------------
++* gmac_set_phy_status
++*----------------------------------------------------------------------*/
++void gmac_set_phy_status(struct net_device *dev)
++{
++      GMAC_INFO_T *tp = dev->priv;
++      GMAC_STATUS_T   status;
++      unsigned int    reg_val, ability,wan_port_id;
++      unsigned int    i = 0;
+-//    isPtr->interrupts++;
+-      /* read Interrupt status */
+-      status0 = readl(TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_STATUS_0_REG);
+-      status1 = readl(TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_STATUS_1_REG);
+-      status2 = readl(TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_STATUS_2_REG);
+-      status3 = readl(TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_STATUS_3_REG);
+-      status4 = readl(TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_STATUS_4_REG);
+-      // prompt warning if status bit ON but not enabled
++#ifdef VITESSE_G5SWITCH
++      if((tp->port_id == GMAC_PORT1)&&(Giga_switch==1)){
+ #if 0
+-      if (status0 & ~tp->intr0_enabled)
+-              printk("Intr 0 Status error. status = 0x%X, enable = 0x%X\n",
+-                              status0, tp->intr0_enabled);
+-      if (status1 & ~tp->intr1_enabled)
+-              printk("Intr 1 Status error. status = 0x%X, enable = 0x%X\n",
+-                              status1, tp->intr1_enabled);
+-      if (status2 & ~tp->intr2_enabled)
+-              printk("Intr 2 Status error. status = 0x%X, enable = 0x%X\n",
+-                              status2, tp->intr2_enabled);
+-      if (status3 & ~tp->intr3_enabled)
+-              printk("Intr 3 Status error. status = 0x%X, enable = 0x%X\n",
+-                              status3, tp->intr3_enabled);
+-      if (status4 & ~tp->intr4_enabled)
+-              printk("Intr 4 Status error. status = 0x%X, enable = 0x%X\n",
+-                              status4, tp->intr4_enabled);
+-#endif
+-#define       INTERRUPT_SELECT                        1
+-      if (status0)
+-              writel(status0 & tp->intr0_enabled, TOE_GLOBAL_BASE+GLOBAL_INTERRUPT_STATUS_0_REG);
+-      if (status1)
+-              writel(status1 & tp->intr1_enabled, TOE_GLOBAL_BASE+GLOBAL_INTERRUPT_STATUS_1_REG);
+-      if (status2)
+-              writel(status2 & tp->intr2_enabled, TOE_GLOBAL_BASE+GLOBAL_INTERRUPT_STATUS_2_REG);
+-      if (status3)
+-              writel(status3 & tp->intr3_enabled, TOE_GLOBAL_BASE+GLOBAL_INTERRUPT_STATUS_3_REG);
+-      if (status4)
+-              writel(status4 & tp->intr4_enabled, TOE_GLOBAL_BASE+GLOBAL_INTERRUPT_STATUS_4_REG);
+-
+-      /* handle freeq interrupt first */
+-      if (status4 & tp->intr4_enabled) {
+-              if ((status4 & SWFQ_EMPTY_INT_BIT) && (tp->intr4_enabled & SWFQ_EMPTY_INT_BIT))
+-              {
+-                      // unsigned long data = REG32(TOE_GLOBAL_BASE + GLOBAL_SWFQ_RWPTR_REG);
+-                      //gmac_write_reg(TOE_GLOBAL_BASE, GLOBAL_INTERRUPT_ENABLE_4_REG,
+-                      //      tp->intr4_enabled & ~SWFQ_EMPTY_INT_BIT, SWFQ_EMPTY_INT_BIT);
+-
+-                      //gmac_write_reg(TOE_GLOBAL_BASE, GLOBAL_INTERRUPT_STATUS_4_REG,
+-                      //      SWFQ_EMPTY_INT_BIT, SWFQ_EMPTY_INT_BIT);
+-                      if (toe->gmac[0].dev && netif_running(toe->gmac[0].dev))
+-                              toe_gmac_handle_default_rxq(toe->gmac[0].dev,&toe->gmac[0]);
+-                      if (toe->gmac[1].dev && netif_running(toe->gmac[1].dev))
+-                              toe_gmac_handle_default_rxq(toe->gmac[1].dev,&toe->gmac[1]);
+-                      printk("\nfreeq int\n");
+-                      toe_gmac_fill_free_q();
+-                      tp->sw_fq_empty_cnt++;
+-
+-                      gmac_write_reg(TOE_GLOBAL_BASE, GLOBAL_INTERRUPT_STATUS_4_REG, status4,
+-                              SWFQ_EMPTY_INT_BIT);
+-              }
+-      }
+-
+-      // Interrupt Status 1
+-      if (status1 & tp->intr1_enabled)
+-      {
+-              #define G1_INTR0_BITS   (GMAC1_HWTQ13_EOF_INT_BIT | GMAC1_HWTQ12_EOF_INT_BIT | GMAC1_HWTQ11_EOF_INT_BIT | GMAC1_HWTQ10_EOF_INT_BIT)
+-              #define G0_INTR0_BITS   (GMAC0_HWTQ03_EOF_INT_BIT | GMAC0_HWTQ02_EOF_INT_BIT | GMAC0_HWTQ01_EOF_INT_BIT | GMAC0_HWTQ00_EOF_INT_BIT)
+-              // Handle GMAC 0/1 HW Tx queue 0-3 EOF events
+-              // Only count
+-              // TOE, Classification, and default queues interrupts are handled by ISR
+-              // because they should pass packets to upper layer
+-              if (tp->port_id == 0)
+-              {
+-#ifndef       INTERRUPT_SELECT
+-                      if (netif_running(dev) && (status1 & G0_INTR0_BITS) && (tp->intr1_enabled & G0_INTR0_BITS))
+-                      {
+-                              if (status1 & GMAC0_HWTQ03_EOF_INT_BIT)
+-                                      tp->hwtxq[3].eof_cnt++;
+-                              if (status1 & GMAC0_HWTQ02_EOF_INT_BIT)
+-                                      tp->hwtxq[2].eof_cnt++;
+-                              if (status1 & GMAC0_HWTQ01_EOF_INT_BIT)
+-                                      tp->hwtxq[1].eof_cnt++;
+-                              if (status1 & GMAC0_HWTQ00_EOF_INT_BIT)
+-                                      tp->hwtxq[0].eof_cnt++;
+-#endif        //INTERRUPT_SELECT
+-#ifndef       INTERRUPT_SELECT
+-                      }
+-#endif        //INTERRUPT_SELECT
+-                      if (netif_running(dev) && (status1 & DEFAULT_Q0_INT_BIT) && (tp->intr1_enabled & DEFAULT_Q0_INT_BIT))
+-                      {
+-                              tp->default_q_intr_cnt++;
+-                              toe_gmac_handle_default_rxq(dev, tp);
++              rcv_mask = SPI_read(2,0,0x10);                  // Receive mask
++              rcv_mask |= 0x4F;
++              for(i=0;i<4;i++){
++                      reg_val = BIT(26)|(i<<21)|(10<<16);
++                      SPI_write(3,0,1,reg_val);
++                      msleep(10);
++                      reg_val = SPI_read(3,0,2);
++                      if(reg_val & 0x0c00){
++                              printk("Port%d:Giga mode\n",i);
++                              SPI_write(1,i,0x00,0x300701B1);
++                              SPI_write(1,i,0x00,0x10070181);
++                              switch_pre_link[i]=LINK_UP;
++                              switch_pre_speed[i]=GMAC_SPEED_1000;
+                       }
+-#ifdef CONFIG_SL351x_RXTOE
+-                      if (netif_running(dev) && (status1 & TOE_IQ_ALL_BITS) &&
+-                          (tp->intr1_enabled & TOE_IQ_ALL_BITS)) {
+-                              //printk("status %x, bits %x, slct %x\n", status1, TOE_IQ_ALL_BITS, tp->intr1_selected);
+-                              toe_gmac_handle_toeq(dev, tp, status1);
+-                              //toe_gmac_handle_toeq(dev, toe, tp, status1);
++                      else{
++                              reg_val = BIT(26)|(i<<21)|(5<<16);
++                              SPI_write(3,0,1,reg_val);
++                              msleep(10);
++                              ability = (reg_val = SPI_read(3,0,2)&0x5e0) >>5;
++                              if ((ability & 0x0C)) /* 100M full duplex */
++                              {
++                                      SPI_write(1,i,0x00,0x30050472);
++                                      SPI_write(1,i,0x00,0x10050442);
++                                      printk("Port%d:100M\n",i);
++                                      switch_pre_link[i]=LINK_UP;
++                              switch_pre_speed[i]=GMAC_SPEED_100;
++                              }
++                              else if((ability & 0x03)) /* 10M full duplex */
++                              {
++                                      SPI_write(1,i,0x00,0x30050473);
++                                      SPI_write(1,i,0x00,0x10050443);
++                                      printk("Port%d:10M\n",i);
++                                      switch_pre_link[i]=LINK_UP;
++                                      switch_pre_speed[i]=GMAC_SPEED_10;
++                              }
++                              else{
++                                      SPI_write(1,i,0x00,BIT(16));                    // disable RX
++                                      SPI_write(5,0,0x0E,BIT(i));                     // dicard packet
++                                      while((SPI_read(5,0,0x0C)&BIT(i))==0)           // wait to be empty
++                                              msleep(1);
++
++                                      SPI_write(1,i,0x00,0x20000030);                 // PORT_RST
++                                      switch_pre_link[i]=LINK_DOWN;
++                                      switch_pre_speed[i]=GMAC_SPEED_10;
++                                      rcv_mask &= ~BIT(i);
++                                      SPI_write(2,0,0x10,rcv_mask);                   // Disable Receive
++                              }
+                       }
+-#endif
+               }
+-              else if (tp->port_id == 1)
+-              {
+-#ifndef       INTERRUPT_SELECT
+-                      if (netif_running(dev) && (status1 & G1_INTR0_BITS) && (tp->intr1_enabled & G1_INTR0_BITS))
+-                      {
+-                              if (status1 & GMAC1_HWTQ13_EOF_INT_BIT)
+-                                      tp->hwtxq[3].eof_cnt++;
+-                              if (status1 & GMAC1_HWTQ12_EOF_INT_BIT)
+-                                      tp->hwtxq[2].eof_cnt++;
+-                              if (status1 & GMAC1_HWTQ11_EOF_INT_BIT)
+-                                      tp->hwtxq[1].eof_cnt++;
+-                              if (status1 & GMAC1_HWTQ10_EOF_INT_BIT)
+-                                      tp->hwtxq[0].eof_cnt++;
+-#endif        //INTERRUPT_SELECT
+-#ifndef       INTERRUPT_SELECT
+-                      }
+-#endif        //INTERRUPT_SELECT
+-                      if (netif_running(dev) && (status1 & DEFAULT_Q1_INT_BIT) && (tp->intr1_enabled & DEFAULT_Q1_INT_BIT))
+-                      {
+-                              tp->default_q_intr_cnt++;
+-                              toe_gmac_handle_default_rxq(dev, tp);
+-                      }
+-#ifdef CONFIG_SL351x_RXTOE
+-                      if (netif_running(dev) && (status1 & TOE_IQ_ALL_BITS) &&
+-                          (tp->intr1_enabled & TOE_IQ_ALL_BITS)) {
+-                              //printk("status %x, bits %x, slct %x\n", status1, TOE_IQ_ALL_BITS, tp->intr1_selected);
+-                              toe_gmac_handle_toeq(dev, tp, status1);
+-                              //toe_gmac_handle_toeq(dev, toe, tp, status1);
+-                      }
+ #endif
+-              }
++              gmac_get_switch_status(dev);
++              gmac_write_reg(tp->base_addr, GMAC_STATUS, 0x7d, 0x0000007f);
++//            SPI_write(2,0,0x10,rcv_mask);                   // Enable Receive
++              return ;
+       }
++#endif
++      reg_val = gmac_get_phy_vendor(tp->phy_addr);
++      printk("GMAC-%d Addr %d Vendor ID: 0x%08x\n", tp->port_id, tp->phy_addr, reg_val);
+-      // Interrupt Status 0
+-      if (status0 & tp->intr0_enabled)
+-      {
+-
+-              #define ERR_INTR_BITS   (GMAC0_TXDERR_INT_BIT | GMAC0_TXPERR_INT_BIT |  \
+-                                                               GMAC1_TXDERR_INT_BIT | GMAC1_TXPERR_INT_BIT |  \
+-                                                               GMAC0_RXDERR_INT_BIT | GMAC0_RXPERR_INT_BIT |  \
+-                                                               GMAC1_RXDERR_INT_BIT | GMAC1_RXPERR_INT_BIT)
+-#ifndef       INTERRUPT_SELECT
+-              if (status0 &  ERR_INTR_BITS)
+-              {
+-                      if ((status0 & GMAC0_TXDERR_INT_BIT) && (tp->intr0_enabled & GMAC0_TXDERR_INT_BIT))
+-                      {
+-                              tp->txDerr_cnt[0]++;
+-                              printk("GMAC0 TX AHB Bus Error!\n");
+-                      }
+-                      if ((status0 & GMAC0_TXPERR_INT_BIT) && (tp->intr0_enabled & GMAC0_TXPERR_INT_BIT))
+-                      {
+-                              tp->txPerr_cnt[0]++;
+-                              printk("GMAC0 Tx Descriptor Protocol Error!\n");
+-                      }
+-                      if ((status0 & GMAC1_TXDERR_INT_BIT) && (tp->intr0_enabled & GMAC1_TXDERR_INT_BIT))
+-                      {
+-                              tp->txDerr_cnt[1]++;
+-                              printk("GMAC1 Tx AHB Bus Error!\n");
+-                      }
+-                      if ((status0 & GMAC1_TXPERR_INT_BIT) && (tp->intr0_enabled & GMAC1_TXPERR_INT_BIT))
+-                      {
+-                              tp->txPerr_cnt[1]++;
+-                              printk("GMAC1 Tx Descriptor Protocol Error!\n");
+-                      }
+-
+-                      if ((status0 & GMAC0_RXDERR_INT_BIT) && (tp->intr0_enabled & GMAC0_RXDERR_INT_BIT))
+-                      {
+-                              tp->RxDerr_cnt[0]++;
+-                              printk("GMAC0 Rx AHB Bus Error!\n");
+-                      }
+-                      if ((status0 & GMAC0_RXPERR_INT_BIT) && (tp->intr0_enabled & GMAC0_RXPERR_INT_BIT))
+-                      {
+-                              tp->RxPerr_cnt[0]++;
+-                              printk("GMAC0 Rx Descriptor Protocol Error!\n");
+-                      }
+-                      if ((status0 & GMAC1_RXDERR_INT_BIT) && (tp->intr0_enabled & GMAC1_RXDERR_INT_BIT))
+-                      {
+-                              tp->RxDerr_cnt[1]++;
+-                              printk("GMAC1 Rx AHB Bus Error!\n");
+-                      }
+-                      if ((status0 & GMAC1_RXPERR_INT_BIT) && (tp->intr0_enabled & GMAC1_RXPERR_INT_BIT))
+-                      {
+-                              tp->RxPerr_cnt[1]++;
+-                              printk("GMAC1 Rx Descriptor Protocol Error!\n");
+-                      }
+-              }
+-#endif        //INTERRUPT_SELECT
+-#ifndef       GMAX_TX_INTR_DISABLED
+-              if (tp->port_id == 1 && netif_running(dev) &&
+-                      (((status0 & GMAC1_SWTQ10_FIN_INT_BIT) && (tp->intr0_enabled & GMAC1_SWTQ10_FIN_INT_BIT))
+-                      ||
+-                      ((status0 & GMAC1_SWTQ10_EOF_INT_BIT) && (tp->intr0_enabled & GMAC1_SWTQ10_EOF_INT_BIT))))
+-              {
+-                      toe_gmac_tx_complete(&toe_private_data.gmac[1], 0, dev, 1);
+-              }
+-
+-              if (tp->port_id == 0 && netif_running(dev) &&
+-                      (((status0 & GMAC0_SWTQ00_FIN_INT_BIT) && (tp->intr0_enabled & GMAC0_SWTQ00_FIN_INT_BIT))
+-                      ||
+-                      ((status0 & GMAC0_SWTQ00_EOF_INT_BIT) && (tp->intr0_enabled & GMAC0_SWTQ00_EOF_INT_BIT))))
+-              {
+-                      toe_gmac_tx_complete(&toe_private_data.gmac[0], 0, dev, 1);
+-              }
+-#endif
+-              // clear enabled status bits
+-      }
+-      // Interrupt Status 4
+-#ifndef       INTERRUPT_SELECT
+-      if (status4 & tp->intr4_enabled)
+-      {
+-              #define G1_INTR4_BITS           (0xff000000)
+-              #define G0_INTR4_BITS           (0x00ff0000)
+-
+-              if (tp->port_id == 0)
+-              {
+-                      if ((status4 & G0_INTR4_BITS) && (tp->intr4_enabled & G0_INTR4_BITS))
+-                      {
+-                              if (status4 & GMAC0_RESERVED_INT_BIT)
+-                                      printk("GMAC0_RESERVED_INT_BIT is ON\n");
+-                              if (status4 & GMAC0_MIB_INT_BIT)
+-                                      tp->mib_full_cnt++;
+-                              if (status4 & GMAC0_RX_PAUSE_ON_INT_BIT)
+-                                      tp->rx_pause_on_cnt++;
+-                              if (status4 & GMAC0_TX_PAUSE_ON_INT_BIT)
+-                                      tp->tx_pause_on_cnt++;
+-                              if (status4 & GMAC0_RX_PAUSE_OFF_INT_BIT)
+-                                      tp->rx_pause_off_cnt++;
+-                              if (status4 & GMAC0_TX_PAUSE_OFF_INT_BIT)
+-                                      tp->rx_pause_off_cnt++;
+-                              if (status4 & GMAC0_RX_OVERRUN_INT_BIT)
+-                                      tp->rx_overrun_cnt++;
+-                              if (status4 & GMAC0_STATUS_CHANGE_INT_BIT)
+-                                      tp->status_changed_cnt++;
+-                      }
+-              }
+-              else if (tp->port_id == 1)
+-              {
+-                      if ((status4 & G1_INTR4_BITS) && (tp->intr4_enabled & G1_INTR4_BITS))
+-                      {
+-                              if (status4 & GMAC1_RESERVED_INT_BIT)
+-                                      printk("GMAC1_RESERVED_INT_BIT is ON\n");
+-                              if (status4 & GMAC1_MIB_INT_BIT)
+-                                      tp->mib_full_cnt++;
+-                              if (status4 & GMAC1_RX_PAUSE_ON_INT_BIT)
+-                              {
+-                                      //printk("Gmac pause on\n");
+-                                      tp->rx_pause_on_cnt++;
+-                              }
+-                              if (status4 & GMAC1_TX_PAUSE_ON_INT_BIT)
+-                              {
+-                                      //printk("Gmac pause on\n");
+-                                      tp->tx_pause_on_cnt++;
+-                              }
+-                              if (status4 & GMAC1_RX_PAUSE_OFF_INT_BIT)
+-                              {
+-                                      //printk("Gmac pause off\n");
+-                                      tp->rx_pause_off_cnt++;
+-                              }
+-                              if (status4 & GMAC1_TX_PAUSE_OFF_INT_BIT)
+-                              {
+-                                      //printk("Gmac pause off\n");
+-                                      tp->rx_pause_off_cnt++;
+-                              }
+-                              if (status4 & GMAC1_RX_OVERRUN_INT_BIT)
+-                              {
+-                                      //printk("Gmac Rx Overrun \n");
+-                                      tp->rx_overrun_cnt++;
+-                              }
+-                              if (status4 & GMAC1_STATUS_CHANGE_INT_BIT)
+-                                      tp->status_changed_cnt++;
+-                      }
+-              }
+-#if 0
+-              if ((status4 & SWFQ_EMPTY_INT_BIT) && (tp->intr4_enabled & SWFQ_EMPTY_INT_BIT))
+-              {
+-                      // unsigned long data = REG32(TOE_GLOBAL_BASE + GLOBAL_SWFQ_RWPTR_REG);
+-//                    mac_stop_rxdma(tp->sc);
+-                      gmac_write_reg(TOE_GLOBAL_BASE, GLOBAL_INTERRUPT_ENABLE_4_REG,
+-                              tp->intr4_enabled & ~SWFQ_EMPTY_INT_BIT, SWFQ_EMPTY_INT_BIT);
+-
+-                      gmac_write_reg(TOE_GLOBAL_BASE, GLOBAL_INTERRUPT_STATUS_4_REG,
+-                              SWFQ_EMPTY_INT_BIT, SWFQ_EMPTY_INT_BIT);
+-                      toe_gmac_fill_free_q();
+-                      tp->sw_fq_empty_cnt++;
+-
+-                      gmac_write_reg(TOE_GLOBAL_BASE, GLOBAL_INTERRUPT_STATUS_4_REG, status4,
+-                              SWFQ_EMPTY_INT_BIT);
+-//#if 0
+-/*                    if (netif_running(dev))
+-                              toe_gmac_handle_default_rxq(dev, tp);
+-                      printk("SWFQ_EMPTY_INT_BIT is ON!\n");  // should not be happened */
+-//#endif
+-              }
+-#endif
+-      }
+-#endif        //INTERRUPT_SELECT
+-      toe_gmac_enable_interrupt(tp->irq);
+-//enable gmac rx function when do RFC 2544
+-#ifdef IxscriptMate_1518
+-      if (storlink_ctl.pauseoff == 1)
+-      {
+-              GMAC_CONFIG0_T config0;
+-              config0.bits32 = readl(TOE_GMAC0_BASE+GMAC_CONFIG0);
+-              config0.bits.dis_rx = 0;
+-              writel(config0.bits32, TOE_GMAC0_BASE+GMAC_CONFIG0);
+-              config0.bits32 = readl(TOE_GMAC1_BASE+GMAC_CONFIG0);
+-              config0.bits.dis_rx = 0;
+-              writel(config0.bits32, TOE_GMAC1_BASE+GMAC_CONFIG0);
+-      }
+-#endif
+-      //printk("gmac_interrupt complete!\n\n");
+-//    return IRQ_RETVAL(handled);
+-      return  IRQ_RETVAL(1);
+-#ifdef CONFIG_SL_NAPI
+-}
+-#endif
+-}
+-
+-/*----------------------------------------------------------------------
+-*     toe_gmac_handle_default_rxq
+-*     (1) Get rx Buffer for default Rx queue
+-*     (2) notify or call upper-routine to handle it
+-*     (3) get a new buffer and insert it into SW free queue
+-*     (4) Note: The SW free queue Read-Write Pointer should be locked when accessing
+-*----------------------------------------------------------------------*/
+-//static inline void toe_gmac_handle_default_rxq(struct net_device *dev, GMAC_INFO_T *tp)
+-static void toe_gmac_handle_default_rxq(struct net_device *dev, GMAC_INFO_T *tp)
+-{
+-      TOE_INFO_T                      *toe;
+-    GMAC_RXDESC_T     *curr_desc;
+-      struct sk_buff          *skb;
+-    DMA_RWPTR_T                       rwptr;
+-      unsigned int            pkt_size;
+-      int                                     max_cnt;
+-      unsigned int        desc_count;
+-      unsigned int        good_frame, chksum_status, rx_status;
+-      struct net_device_stats *isPtr = (struct net_device_stats *)&tp->ifStatics;
+-
+-//when do ixia RFC 2544 test and packet size is select 1518 bytes,disable gmace rx function immediately after one interrupt come in.
+-#ifdef IxscriptMate_1518
+-      if (storlink_ctl.pauseoff == 1)
+-      {
+-              GMAC_CONFIG0_T config0;
+-              config0.bits32 = readl(TOE_GMAC0_BASE+GMAC_CONFIG0);
+-              config0.bits.dis_rx = 1;
+-              writel(config0.bits32, TOE_GMAC0_BASE+GMAC_CONFIG0);
+-              config0.bits32 = readl(TOE_GMAC1_BASE+GMAC_CONFIG0);
+-              config0.bits.dis_rx = 1;
+-              writel(config0.bits32, TOE_GMAC1_BASE+GMAC_CONFIG0);
+-      }
+-#endif
+-      rwptr.bits32 = readl(&tp->default_qhdr->word1);
+-#if 0
+-      if (rwptr.bits.rptr != tp->rx_rwptr.bits.rptr)
+-      {
+-              mac_stop_txdma((struct net_device *)tp->dev);
+-              printk("Default Queue HW RD ptr (0x%x) != SW RD Ptr (0x%x)\n",
+-                              rwptr.bits32, tp->rx_rwptr.bits.rptr);
+-              while(1);
+-      }
+-#endif
+-      toe = (TOE_INFO_T *)&toe_private_data;
+-      max_cnt = DEFAULT_RXQ_MAX_CNT;
+-      while ((--max_cnt) && rwptr.bits.rptr != rwptr.bits.wptr)
+-//    while (rwptr.bits.rptr != rwptr.bits.wptr)
+-      {
+-//if packet size is not 1518 for RFC 2544,enable gmac rx function.The other packet size have RX workaround.
+-#ifdef IxscriptMate_1518
+-      if (storlink_ctl.pauseoff == 1)
+-              {
+-                      if (pkt_size != 1514)
+-                      {
+-                                              GMAC_CONFIG0_T config0;
+-                                              config0.bits32 = readl(TOE_GMAC0_BASE+GMAC_CONFIG0);
+-                                              config0.bits.dis_rx = 0;
+-                                              writel(config0.bits32, TOE_GMAC0_BASE+GMAC_CONFIG0);
+-                                              config0.bits32 = readl(TOE_GMAC1_BASE+GMAC_CONFIG0);
+-                                              config0.bits.dis_rx = 0;
+-                                              writel(config0.bits32, TOE_GMAC1_BASE+GMAC_CONFIG0);
+-                      }
+-              }
+-#endif
+-      curr_desc = (GMAC_RXDESC_T *)tp->default_desc_base + rwptr.bits.rptr;
+-//            consistent_sync(curr_desc, sizeof(GMAC_RXDESC_T), PCI_DMA_FROMDEVICE);
+-              tp->default_q_cnt++;
+-      tp->rx_curr_desc = (unsigned int)curr_desc;
+-      rx_status = curr_desc->word0.bits.status;
+-      chksum_status = curr_desc->word0.bits.chksum_status;
+-      tp->rx_status_cnt[rx_status]++;
+-      tp->rx_chksum_cnt[chksum_status]++;
+-        pkt_size = curr_desc->word1.bits.byte_count;  /*total byte count in a frame*/
+-              desc_count = curr_desc->word0.bits.desc_count; /* get descriptor count per frame */
+-              good_frame=1;
+-              if ((curr_desc->word0.bits32 & (GMAC_RXDESC_0_T_derr | GMAC_RXDESC_0_T_perr))
+-                      || (pkt_size < 60)
+-                  || (chksum_status & 0x4)
+-                      || rx_status)
+-              {
+-                      good_frame = 0;
+-                      if (curr_desc->word0.bits32 & GMAC_RXDESC_0_T_derr)
+-                              printk("%s::derr (GMAC-%d)!!!\n", __func__, tp->port_id);
+-                      if (curr_desc->word0.bits32 & GMAC_RXDESC_0_T_perr)
+-                              printk("%s::perr (GMAC-%d)!!!\n", __func__, tp->port_id);
+-                      if (rx_status)
+-                      {
+-                              if (rx_status == 4 || rx_status == 7)
+-                                      isPtr->rx_crc_errors++;
+-//                            printk("%s::Status=%d (GMAC-%d)!!!\n", __func__, rx_status, tp->port_id);
+-                      }
+-#ifdef SL351x_GMAC_WORKAROUND
+-                      else if (pkt_size < 60)
+-                      {
+-                              if (tp->short_frames_cnt < GMAC_SHORT_FRAME_THRESHOLD)
+-                                      tp->short_frames_cnt++;
+-                              if (tp->short_frames_cnt >= GMAC_SHORT_FRAME_THRESHOLD)
+-                              {
+-                                      GMAC_CONFIG0_T config0;
+-                                      config0.bits32 = readl(TOE_GMAC0_BASE+GMAC_CONFIG0);
+-                                      config0.bits.dis_rx = 1;
+-                                      writel(config0.bits32, TOE_GMAC0_BASE+GMAC_CONFIG0);
+-                                      config0.bits32 = readl(TOE_GMAC1_BASE+GMAC_CONFIG0);
+-                                      config0.bits.dis_rx = 1;
+-                                      writel(config0.bits32, TOE_GMAC1_BASE+GMAC_CONFIG0);
+-                              }
+-                      }
+-#endif
+-//                    if (chksum_status)
+-//                            printk("%s::Checksum Status=%d (GMAC-%d)!!!\n", __func__, chksum_status, tp->port_id);
+-                      skb = (struct sk_buff *)(REG32(__va(curr_desc->word2.buf_adr) - SKB_RESERVE_BYTES));
+-                      dev_kfree_skb_irq(skb);
+-              }
+-              if (good_frame)
+-              {
+-                      if (curr_desc->word0.bits.drop)
+-                              printk("%s::Drop (GMAC-%d)!!!\n", __func__, tp->port_id);
+-//                    if (chksum_status)
+-//                            printk("%s::Checksum Status=%d (GMAC-%d)!!!\n", __func__, chksum_status, tp->port_id);
+-
+-              /* get frame information from the first descriptor of the frame */
+-#ifdef SL351x_GMAC_WORKAROUND
+-                      if (tp->short_frames_cnt >= GMAC_SHORT_FRAME_THRESHOLD)
+-                      {
+-                              GMAC_CONFIG0_T config0;
+-                              config0.bits32 = readl(TOE_GMAC0_BASE+GMAC_CONFIG0);
+-                              config0.bits.dis_rx = 0;
+-                              writel(config0.bits32, TOE_GMAC0_BASE+GMAC_CONFIG0);
+-                              config0.bits32 = readl(TOE_GMAC1_BASE+GMAC_CONFIG0);
+-                              config0.bits.dis_rx = 0;
+-                              writel(config0.bits32, TOE_GMAC1_BASE+GMAC_CONFIG0);
+-                      }
+-                      tp->short_frames_cnt = 0;
+-#endif
+-                      isPtr->rx_packets++;
+-                      skb = (struct sk_buff *)(REG32(__va(curr_desc->word2.buf_adr - SKB_RESERVE_BYTES)));
+-                      if (!skb)
+-                      {
+-                              printk("Fatal Error!!skb==NULL\n");
+-                              goto next_rx;
+-                      }
+-                      tp->curr_rx_skb = skb;
+-                      // consistent_sync((void *)__va(curr_desc->word2.buf_adr), pkt_size, PCI_DMA_FROMDEVICE);
+-
+-      //              curr_desc->word2.buf_adr = 0;
+-
+-                      skb_reserve (skb, RX_INSERT_BYTES);     /* 16 byte align the IP fields. */
+-                      skb_put(skb, pkt_size);
+-                      skb->dev = dev;
+-                      if (chksum_status == RX_CHKSUM_IP_UDP_TCP_OK)
+-                      {
+-                              skb->ip_summed = CHECKSUM_UNNECESSARY;
+-#ifdef CONFIG_SL351x_NAT
+-                              if (nat_cfg.enabled && curr_desc->word3.bits.l3_offset && curr_desc->word3.bits.l4_offset)
+-                              {
+-                                      struct iphdr    *ip_hdr;
+-                                      ip_hdr = (struct iphdr *)&(skb->data[curr_desc->word3.bits.l3_offset]);
+-                                      sl351x_nat_input(skb,
+-                                                                      tp->port_id,
+-                                                                      (void *)curr_desc->word3.bits.l3_offset,
+-                                                                      (void *)curr_desc->word3.bits.l4_offset);
+-                              }
+-#endif
+-                              skb->protocol = eth_type_trans(skb,dev); /* set skb protocol */
+-#if 0
+-#ifdef CONFIG_SL351x_RXTOE
+-                              if (storlink_ctl.rx_max_pktsize) {
+-                                      struct iphdr    *ip_hdr;
+-                                      struct tcphdr   *tcp_hdr;
+-                                      int ip_hdrlen;
+-
+-                                      ip_hdr = (struct iphdr*)&(skb->data[0]);
+-                                      if ((skb->protocol == __constant_htons(ETH_P_IP)) &&
+-                                         ((ip_hdr->protocol & 0x00ff) == IPPROTO_TCP)) {
+-                                              ip_hdrlen = ip_hdr->ihl << 2;
+-                                              tcp_hdr = (struct tcphdr*)&(skb->data[ip_hdrlen]);
+-                                              if (tcp_hdr->syn) {
+-                                                      struct toe_conn* connection = init_toeq(ip_hdr->version,
+-                                                                      ip_hdr, tcp_hdr, toe, &(skb->data[0]) - 14);
+-                                                      TCP_SKB_CB(skb)->connection = connection;
+-                                                      //      hash_dump_entry(TCP_SKB_CB(skb)->connection->hash_entry_index);
+-                                                      //              printk("%s::skb data %x, conn %x, mode %x\n",
+-                                                      //                      __func__, skb->data, connection, connection->mode);
+-                                              }
+-                                      }
+-                              }
+-#endif
+-#endif
+-                      }
+-                      else if (chksum_status == RX_CHKSUM_IP_OK_ONLY)
+-                      {
+-                              skb->ip_summed = CHECKSUM_UNNECESSARY;
+-#ifdef CONFIG_SL351x_NAT
+-                              if (nat_cfg.enabled && curr_desc->word3.bits.l3_offset && curr_desc->word3.bits.l4_offset)
+-                              {
+-                                      struct iphdr            *ip_hdr;
+-                                      //struct tcphdr         *tcp_hdr;
+-                                      ip_hdr = (struct iphdr *)&(skb->data[curr_desc->word3.bits.l3_offset]);
+-                                      //tcp_hdr = (struct tcphdr *)&(skb->data[curr_desc->word3.bits.l4_offset]);
+-                                      if (ip_hdr->protocol == IPPROTO_UDP)
+-                                      {
+-                                              sl351x_nat_input(skb,
+-                                                                              tp->port_id,
+-                                                                              (void *)curr_desc->word3.bits.l3_offset,
+-                                                                              (void *)curr_desc->word3.bits.l4_offset);
+-                                      }
+-                                      else if (ip_hdr->protocol == IPPROTO_GRE)
+-                                      {
+-                                              sl351x_nat_input(skb,
+-                                                                      tp->port_id,
+-                                                                      (void *)curr_desc->word3.bits.l3_offset,
+-                                                                      (void *)curr_desc->word3.bits.l4_offset);
+-                                      }
+-                              }
+-#endif
+-                              skb->protocol = eth_type_trans(skb,dev); /* set skb protocol */
+-                      }
+-                      else
+-                      {
+-                              skb->protocol = eth_type_trans(skb,dev); /* set skb protocol */
+-                      }
+-
+-                      netif_rx(skb);  /* socket rx */
+-                      dev->last_rx = jiffies;
+-
+-                      isPtr->rx_bytes += pkt_size;
+-
+-        }
+-
+-next_rx:
+-              // advance one for Rx default Q 0/1
+-              rwptr.bits.rptr = RWPTR_ADVANCE_ONE(rwptr.bits.rptr, tp->default_desc_num);
+-              SET_RPTR(&tp->default_qhdr->word1, rwptr.bits.rptr);
+-      tp->rx_rwptr.bits32 = rwptr.bits32;
+-
+-      }
+-
+-      /* Handles first available packets only then refill the queue. */
+-      toe_gmac_fill_free_q();
+-}
+-
+-/*----------------------------------------------------------------------
+-* gmac_get_phy_vendor
+-*----------------------------------------------------------------------*/
+-static unsigned int gmac_get_phy_vendor(int phy_addr)
+-{
+-    unsigned int      reg_val;
+-    reg_val=(mii_read(phy_addr,0x02) << 16) + mii_read(phy_addr,0x03);
+-    return reg_val;
+-}
+-
+-/*----------------------------------------------------------------------
+-* gmac_set_phy_status
+-*----------------------------------------------------------------------*/
+-void gmac_set_phy_status(struct net_device *dev)
+-{
+-      GMAC_INFO_T *tp = dev->priv;
+-      GMAC_STATUS_T   status;
+-      unsigned int    reg_val, ability,wan_port_id;
+-      unsigned int    i = 0;
+-
+-#ifdef VITESSE_G5SWITCH
+-      if((tp->port_id == GMAC_PORT1)&&(Giga_switch==1)){
+-#if 0
+-              rcv_mask = SPI_read(2,0,0x10);                  // Receive mask
+-              rcv_mask |= 0x4F;
+-              for(i=0;i<4;i++){
+-                      reg_val = BIT(26)|(i<<21)|(10<<16);
+-                      SPI_write(3,0,1,reg_val);
+-                      msleep(10);
+-                      reg_val = SPI_read(3,0,2);
+-                      if(reg_val & 0x0c00){
+-                              printk("Port%d:Giga mode\n",i);
+-                              SPI_write(1,i,0x00,0x300701B1);
+-                              SPI_write(1,i,0x00,0x10070181);
+-                              switch_pre_link[i]=LINK_UP;
+-                              switch_pre_speed[i]=GMAC_SPEED_1000;
+-                      }
+-                      else{
+-                              reg_val = BIT(26)|(i<<21)|(5<<16);
+-                              SPI_write(3,0,1,reg_val);
+-                              msleep(10);
+-                              ability = (reg_val = SPI_read(3,0,2)&0x5e0) >>5;
+-                              if ((ability & 0x0C)) /* 100M full duplex */
+-                              {
+-                                      SPI_write(1,i,0x00,0x30050472);
+-                                      SPI_write(1,i,0x00,0x10050442);
+-                                      printk("Port%d:100M\n",i);
+-                                      switch_pre_link[i]=LINK_UP;
+-                              switch_pre_speed[i]=GMAC_SPEED_100;
+-                              }
+-                              else if((ability & 0x03)) /* 10M full duplex */
+-                              {
+-                                      SPI_write(1,i,0x00,0x30050473);
+-                                      SPI_write(1,i,0x00,0x10050443);
+-                                      printk("Port%d:10M\n",i);
+-                                      switch_pre_link[i]=LINK_UP;
+-                                      switch_pre_speed[i]=GMAC_SPEED_10;
+-                              }
+-                              else{
+-                                      SPI_write(1,i,0x00,BIT(16));                    // disable RX
+-                                      SPI_write(5,0,0x0E,BIT(i));                     // dicard packet
+-                                      while((SPI_read(5,0,0x0C)&BIT(i))==0)           // wait to be empty
+-                                              msleep(1);
+-
+-                                      SPI_write(1,i,0x00,0x20000030);                 // PORT_RST
+-                                      switch_pre_link[i]=LINK_DOWN;
+-                                      switch_pre_speed[i]=GMAC_SPEED_10;
+-                                      rcv_mask &= ~BIT(i);
+-                                      SPI_write(2,0,0x10,rcv_mask);                   // Disable Receive
+-                              }
+-                      }
+-              }
+-#endif
+-              gmac_get_switch_status(dev);
+-              gmac_write_reg(tp->base_addr, GMAC_STATUS, 0x7d, 0x0000007f);
+-//            SPI_write(2,0,0x10,rcv_mask);                   // Enable Receive
+-              return ;
+-      }
+-#endif
+-
+-      reg_val = gmac_get_phy_vendor(tp->phy_addr);
+-      printk("GMAC-%d Addr %d Vendor ID: 0x%08x\n", tp->port_id, tp->phy_addr, reg_val);
+-
+-      switch (tp->phy_mode)
++      switch (tp->phy_mode)
+       {
+               case GMAC_PHY_GMII:
+               mii_write(tp->phy_addr,0x04,0x05e1); /* advertisement 100M full duplex, pause capable on */
+@@ -3552,6 +2982,7 @@
+               status.bits.link = LINK_DOWN;
+               //              clear_bit(__LINK_STATE_START, &dev->state);
+               printk("Link Down (0x%04x) ", reg_val);
++#ifdef VITESSE_G5SWITCH
+               if(Giga_switch == 1)
+               {
+                               wan_port_id = 1;
+@@ -3565,6 +2996,7 @@
+                               storlink_ctl.link[ tp->port_id] = 0;
+ #endif
+               }
++#endif
+       }
+       else
+       {
+@@ -3572,6 +3004,7 @@
+               status.bits.link = LINK_UP;
+               //              set_bit(__LINK_STATE_START, &dev->state);
+               printk("Link Up (0x%04x) ",reg_val);
++#ifdef VITESSE_G5SWITCH
+               if(Giga_switch == 1)
+               {
+                               wan_port_id = 1;
+@@ -3585,6 +3018,7 @@
+                               storlink_ctl.link[ tp->port_id] = 1;
+ #endif
+               }
++#endif
+       }
+       //    value = mii_read(PHY_ADDR,0x05);
+@@ -3863,6 +3297,7 @@
+                       }
+               }
+               status.bits.link = LINK_UP; /* link up */
++#ifdef VITESSE_G5SWITCH
+               if(Giga_switch==1)
+               {
+                               wan_port_id = 1;
+@@ -3874,6 +3309,7 @@
+                               storlink_ctl.link[ tp->port_id] = 1;
+ #endif
+               }
++#endif
+               if ((ability & 0x20)==0x20)
+               {
+                       if (tp->flow_control_enable == 0)
+@@ -3914,6 +3350,7 @@
+       else
+       {
+               status.bits.link = LINK_DOWN; /* link down */
++#ifdef VITESSE_G5SWITCH
+               if(Giga_switch == 1)
+               {
+                               wan_port_id = 1;
+@@ -3925,6 +3362,7 @@
+                               storlink_ctl.link[ tp->port_id] = 0;
+ #endif
+               }
++#endif
+               if (tp->pre_phy_status == LINK_UP)
+               {
+                       printk("GMAC-%d LINK_Down......\n",tp->port_id);
+@@ -4298,86 +3736,102 @@
+ }
+ #ifdef CONFIG_SL_NAPI
++
++static int gmax_rx(struct net_device *dev, int *budget)
++{
++      return 0;
++}
++
++static int gmac_tx(struct net_device *dev, int *budget)
++{
++      return 0;
++}
++
+ /*----------------------------------------------------------------------
+ * gmac_rx_poll
+ *----------------------------------------------------------------------*/
+ static int gmac_rx_poll(struct net_device *dev, int *budget)
+ {
+-      TOE_INFO_T                      *toe;
+-    GMAC_RXDESC_T     *curr_desc;
+-      struct sk_buff          *skb;
+-    DMA_RWPTR_T                       rwptr;
+-    unsigned int data32;
+-      unsigned int            pkt_size;
+-      unsigned int        desc_count;
+-      unsigned int        good_frame, chksum_status, rx_status;
+-      int                 rx_pkts_num = 0;
+-      int                 quota = min(dev->quota, *budget);
+-      GMAC_INFO_T                     *tp = (GMAC_INFO_T *)dev->priv;
+-      unsigned int            status4;
+-      volatile DMA_RWPTR_T    fq_rwptr;
+-      // int                                  max_cnt = TOE_SW_FREEQ_DESC_NUM;//TOE_SW_FREEQ_DESC_NUM = 64
+-      //unsigned long         rx_old_bytes;
++      TOE_INFO_T      *toe;
++      GMAC_RXDESC_T   *curr_desc;
++      struct sk_buff  *skb;
++      DMA_RWPTR_T     rwptr;
++      unsigned int    data32;
++      unsigned int    pkt_size;
++      unsigned int    desc_count;
++      unsigned int    good_frame, chksum_status, rx_status;
++      int             rx_pkts_num = 0;
++      int             quota = min(dev->quota, *budget);
++      GMAC_INFO_T     *tp = (GMAC_INFO_T *)dev->priv;
++      unsigned int    status1;
++      unsigned int    status4;
+       struct net_device_stats *isPtr = (struct net_device_stats *)&tp->ifStatics;
+-      //unsigned long long    rx_time;
+-
+       BUG_ON(rx_poll_enabled == 0);
+-#if 1
+-      if (do_again)
+-      {
+-                      toe_gmac_fill_free_q();
+-                      status4 = readl(TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_STATUS_4_REG);
+-                      fq_rwptr.bits32 = readl(TOE_GLOBAL_BASE + GLOBAL_SWFQ_RWPTR_REG);
+-                      //printk("\n%s:: do_again toe_gmac_fill_free_q =======>status4=0x%x =====fq_rwptr =0x%8x======>JKJKJKJKJKJKJKJKJ \n", __func__,status4,fq_rwptr.bits32);
+-                      if (fq_rwptr.bits.wptr != fq_rwptr.bits.rptr)
+-                      {
+-                                              //status4 = readl(TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_STATUS_4_REG);
+-                                              do_again =0;
+-                                              //netif_rx_complete(dev);
+-                                              gmac_write_reg(TOE_GLOBAL_BASE, GLOBAL_INTERRUPT_STATUS_4_REG, status4, 0x1);
+-                                              fq_rwptr.bits32 = readl(TOE_GLOBAL_BASE + GLOBAL_SWFQ_RWPTR_REG);
+-                                              rwptr.bits32 = readl(&tp->default_qhdr->word1);
+-                      }
+-                      else
+-                              return 1;
+-      }
+-#endif
+-      rwptr.bits32 = readl(&tp->default_qhdr->word1);
+-#if 0
+-      if (rwptr.bits.rptr != tp->rx_rwptr.bits.rptr)
+-      {
+-              mac_stop_txdma((struct net_device *)tp->dev);
+-              printk("Default Queue HW RD ptr (0x%x) != SW RD Ptr (0x%x)\n",
+-                              rwptr.bits32, tp->rx_rwptr.bits.rptr);
+-              while(1);
+-      }
+-#endif
++
+       toe = (TOE_INFO_T *)&toe_private_data;
+-      fq_rwptr.bits32 = readl(TOE_GLOBAL_BASE + GLOBAL_SWFQ_RWPTR_REG);
+-      //printk("%s:---Before-------------->Default Queue HW RW ptr (0x%8x),   fq_rwptr =0x%8x \n",__func__,rwptr.bits32,fq_rwptr.bits32 );
+-      //printk("%s:---Before while   rx_pkts_num=%d------rx_finished_idx=0x%x------->Default_Q [rwptr.bits.rptr(SW)=0x%x,   rwptr.bits.wptr(HW) = 0x%x ]---->Free_Q(SW_HW) = 0x%8x \n",__func__,rx_pkts_num,rx_finished_idx,rwptr.bits.rptr,rwptr.bits.wptr,fq_rwptr.bits32 );
+-//    while ((--max_cnt) && (rwptr.bits.rptr != rwptr.bits.wptr) && (rx_pkts_num < quota))
++rx_poll_retry:
++      status1 = readl(TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_STATUS_1_REG);
++      if (status1 & 1) {
++              writel(1, TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_STATUS_1_REG);
++      }
++      rwptr.bits32 = readl(&tp->default_qhdr->word1);
+       while ((rwptr.bits.rptr != rwptr.bits.wptr) && (rx_pkts_num < quota))
+       {
+-
+-      curr_desc = (GMAC_RXDESC_T *)tp->default_desc_base + rwptr.bits.rptr;
++              curr_desc = (GMAC_RXDESC_T *)tp->default_desc_base + rwptr.bits.rptr;
+               tp->default_q_cnt++;
+-      tp->rx_curr_desc = (unsigned int)curr_desc;
+-      rx_status = curr_desc->word0.bits.status;
+-      chksum_status = curr_desc->word0.bits.chksum_status;
+-      tp->rx_status_cnt[rx_status]++;
+-      tp->rx_chksum_cnt[chksum_status]++;
+-        pkt_size = curr_desc->word1.bits.byte_count;  /*total byte count in a frame*/
++              tp->rx_curr_desc = (unsigned int)curr_desc;
++              rx_status = curr_desc->word0.bits.status;
++              chksum_status = curr_desc->word0.bits.chksum_status;
++              tp->rx_status_cnt[rx_status]++;
++              tp->rx_chksum_cnt[chksum_status]++;
++              pkt_size = curr_desc->word1.bits.byte_count;  /*total byte count in a frame*/
+               desc_count = curr_desc->word0.bits.desc_count; /* get descriptor count per frame */
+               good_frame=1;
++
++              if (0) {
++
++                              int free, busy;
++                              uint32_t rwptr1;
++                              uint32_t rwptr2;
++
++                              rwptr1 = readl(TOE_GLOBAL_BASE + GLOBAL_SWFQ_RWPTR_REG);
++                              free = (GET_WPTR(rwptr1) - GET_RPTR(rwptr1)) & 0xFF;
++
++                              rwptr2 = readl(&tp->default_qhdr->word1);
++                              busy = (GET_RPTR(rwptr2) - GET_WPTR(rwptr2)) & 0xFF;
++
++                              if (GET_WPTR(rwptr1) == GET_RPTR(rwptr1)) {
++                                      printk("frame  status: %d\n"
++                                             "SWFQ: wptr: %hu, rptr: %hu, free: %d\n"
++                                             "GMAC: wptr: %hu, rptr: %hu, free: %d\n",
++                                             rx_status,
++                                             GET_WPTR(rwptr1), GET_RPTR(rwptr1), free,
++                                             GET_WPTR(rwptr2), GET_RPTR(rwptr2), busy);
++                              }
++              }
++
++              {
++                      GMAC_RXDESC_T   *fq_desc;
++                      void *data;
++                      struct sk_buff *skb;
++                      unsigned short idx;
++
++                      skb = (struct sk_buff *)(REG32(__va(curr_desc->word2.buf_adr) - SKB_RESERVE_BYTES));
++                      idx = (unsigned short)(REG32(__va(curr_desc->word2.buf_adr) - SKB_RESERVE_BYTES + 4));
++
++                      BUG_ON(idx > TOE_SW_FREEQ_DESC_NUM);
++                      BUG_ON(skb == NULL);
++                      fq_desc = (GMAC_RXDESC_T*)toe->swfq_desc_base + idx;
++                      fq_desc->word2.buf_adr = 0;
++              }
++
+               if ((curr_desc->word0.bits32 & (GMAC_RXDESC_0_T_derr | GMAC_RXDESC_0_T_perr))
+-                      || (pkt_size < 60)
++                  || (pkt_size < 60)
+                   || (chksum_status & 0x4)
+                   || rx_status )
+-//                    || rx_status || (rwptr.bits.rptr > rwptr.bits.wptr ))
+               {
+                       good_frame = 0;
+                       if (curr_desc->word0.bits32 & GMAC_RXDESC_0_T_derr)
+@@ -4388,7 +3842,6 @@
+                       {
+                               if (rx_status == 4 || rx_status == 7)
+                                       isPtr->rx_crc_errors++;
+-//                            printk("%s::Status=%d (GMAC-%d)!!!\n", __func__, rx_status, tp->port_id);
+                       }
+ #ifdef SL351x_GMAC_WORKAROUND
+                       else if (pkt_size < 60)
+@@ -4407,17 +3860,32 @@
+                               }
+                       }
+ #endif
+-//                    if (chksum_status)
+-//                            printk("%s::Checksum Status=%d (GMAC-%d)!!!\n", __func__, chksum_status, tp->port_id);
+                       skb = (struct sk_buff *)(REG32(__va(curr_desc->word2.buf_adr) - SKB_RESERVE_BYTES));
+-                      dev_kfree_skb_irq(skb);
++                      dev_kfree_skb(skb);
++
++                      if (0) {
++                              int free, busy;
++                              uint32_t rwptr1;
++                              uint32_t rwptr2;
++
++                              rwptr1 = readl(TOE_GLOBAL_BASE + GLOBAL_SWFQ_RWPTR_REG);
++                              free = (GET_WPTR(rwptr1) - GET_RPTR(rwptr1)) & 0xFF;
++
++                              rwptr2 = readl(&tp->default_qhdr->word1);
++                              busy = (GET_RPTR(rwptr2) - GET_WPTR(rwptr2)) & 0xFF;
++
++                              printk("frame  status: %d\n"
++                                     "SWFQ: wptr: %hu, rptr: %hu, free: %d\n"
++                                     "GMAC: wptr: %hu, rptr: %hu, free: %d\n",
++                                     rx_status,
++                                     GET_WPTR(rwptr1), GET_RPTR(rwptr1), free,
++                                     GET_WPTR(rwptr2), GET_RPTR(rwptr2), busy);
++                      }
+               }
+               if (good_frame)
+               {
+                       if (curr_desc->word0.bits.drop)
+                               printk("%s::Drop (GMAC-%d)!!!\n", __func__, tp->port_id);
+-//                    if (chksum_status)
+-//                            printk("%s::Checksum Status=%d (GMAC-%d)!!!\n", __func__, chksum_status, tp->port_id);
+ #ifdef SL351x_GMAC_WORKAROUND
+                       if (tp->short_frames_cnt >= GMAC_SHORT_FRAME_THRESHOLD)
+@@ -4432,225 +3900,118 @@
+                       }
+                       tp->short_frames_cnt = 0;
+ #endif
+-              /* get frame information from the first descriptor of the frame */
++                      /* get frame information from the first descriptor of the frame */
+                       isPtr->rx_packets++;
+-                      //consistent_sync((void *)__va(curr_desc->word2.buf_adr), pkt_size, PCI_DMA_FROMDEVICE);
++                      consistent_sync((void *)__va(curr_desc->word2.buf_adr), pkt_size, PCI_DMA_FROMDEVICE);
+                       skb = (struct sk_buff *)(REG32(__va(curr_desc->word2.buf_adr) - SKB_RESERVE_BYTES));
+                       tp->curr_rx_skb = skb;
+-      //              curr_desc->word2.buf_adr = 0;
+-                  //skb_reserve (skb, SKB_RESERVE_BYTES);
+                       skb_reserve (skb, RX_INSERT_BYTES);     /* 2 byte align the IP fields. */
+-                      //if ((skb->tail+pkt_size) > skb->end )
+-                      //printk("%s::------------->Here skb->len=%d,pkt_size= %d,skb->head=0x%x,skb->tail= 0x%x, skb->end= 0x%x\n", __func__, skb->len, pkt_size,skb->head,skb->tail,skb->end);
+                       skb_put(skb, pkt_size);
+-
+                       skb->dev = dev;
+                       if (chksum_status == RX_CHKSUM_IP_UDP_TCP_OK)
+                       {
+                               skb->ip_summed = CHECKSUM_UNNECESSARY;
+-#ifdef CONFIG_SL351x_NAT
+-                              if (nat_cfg.enabled && curr_desc->word3.bits.l3_offset && curr_desc->word3.bits.l4_offset)
+-                              {
+-                                      struct iphdr    *ip_hdr;
+-                                      ip_hdr = (struct iphdr *)&(skb->data[curr_desc->word3.bits.l3_offset]);
+-                                      sl351x_nat_input(skb,
+-                                                                      tp->port_id,
+-                                                                      (void *)curr_desc->word3.bits.l3_offset,
+-                                                                      (void *)curr_desc->word3.bits.l4_offset);
+-                              }
+-#endif
+                               skb->protocol = eth_type_trans(skb,dev); /* set skb protocol */
+-#if 0
+-#ifdef CONFIG_SL351x_RXTOE
+-                              if (storlink_ctl.rx_max_pktsize) {
+-                                      struct iphdr    *ip_hdr;
+-                                      struct tcphdr   *tcp_hdr;
+-                                      int ip_hdrlen;
+-
+-                                      ip_hdr = (struct iphdr*)&(skb->data[0]);
+-                                      if ((skb->protocol == __constant_htons(ETH_P_IP)) &&
+-                                         ((ip_hdr->protocol & 0x00ff) == IPPROTO_TCP)) {
+-                                              ip_hdrlen = ip_hdr->ihl << 2;
+-                                              tcp_hdr = (struct tcphdr*)&(skb->data[ip_hdrlen]);
+-                                              if (tcp_hdr->syn) {
+-                                                      struct toe_conn* connection = init_toeq(ip_hdr->version,
+-                                                                      ip_hdr, tcp_hdr, toe, &(skb->data[0]) - 14);
+-                                                      TCP_SKB_CB(skb)->connection = connection;
+-                                                      //      hash_dump_entry(TCP_SKB_CB(skb)->connection->hash_entry_index);
+-                                                      //              printk("%s::skb data %x, conn %x, mode %x\n",
+-                                                      //                      __func__, skb->data, connection, connection->mode);
+-                                              }
+-                                      }
+-                              }
+-#endif
+-#endif
+                       }
+                       else if (chksum_status == RX_CHKSUM_IP_OK_ONLY)
+                       {
+                               skb->ip_summed = CHECKSUM_UNNECESSARY;
+-#ifdef CONFIG_SL351x_NAT
+-                              if (nat_cfg.enabled && curr_desc->word3.bits.l3_offset && curr_desc->word3.bits.l4_offset)
+-                              {
+-                                      struct iphdr    *ip_hdr;
+-                                      ip_hdr = (struct iphdr *)&(skb->data[curr_desc->word3.bits.l3_offset]);
+-                                      if (ip_hdr->protocol == IPPROTO_UDP)
+-                                      {
+-                                              sl351x_nat_input(skb,
+-                                                                              tp->port_id,
+-                                                                              (void *)curr_desc->word3.bits.l3_offset,
+-                                                                              (void *)curr_desc->word3.bits.l4_offset);
+-                                      }
+-                                      else if (ip_hdr->protocol == IPPROTO_GRE)
+-                                      {
+-                                              sl351x_nat_input(skb,
+-                                                                      tp->port_id,
+-                                                                      (void *)curr_desc->word3.bits.l3_offset,
+-                                                                      (void *)curr_desc->word3.bits.l4_offset);
+-                                      }
+-                              }
+-#endif
+                               skb->protocol = eth_type_trans(skb,dev); /* set skb protocol */
+                       }
+                       else
+                       {
+                               skb->protocol = eth_type_trans(skb,dev); /* set skb protocol */
+                       }
+-                      //netif_rx(skb);  /* socket rx */
++
+                       netif_receive_skb(skb); //For NAPI
+                       dev->last_rx = jiffies;
+                       isPtr->rx_bytes += pkt_size;
+-                      //printk("------------------->isPtr->rx_bytes = %d\n",isPtr->rx_bytes);
+-
++              }
+-        }
+               // advance one for Rx default Q 0/1
+               rwptr.bits.rptr = RWPTR_ADVANCE_ONE(rwptr.bits.rptr, tp->default_desc_num);
+               SET_RPTR(&tp->default_qhdr->word1, rwptr.bits.rptr);
+-      tp->rx_rwptr.bits32 = rwptr.bits32;
++              tp->rx_rwptr.bits32 = rwptr.bits32;
+               rx_pkts_num++;
+-              //rwptr.bits32 = readl(&tp->default_qhdr->word1);//try read default_qhdr again
+-              //fq_rwptr.bits32 = readl(TOE_GLOBAL_BASE + GLOBAL_SWFQ_RWPTR_REG);
+-              //printk("%s:---Loop  -------->rx_pkts_num=%d------------>Default Queue HW RW ptr = (0x%8x),   fq_rwptr =0x%8x \n",__func__,rx_pkts_num,rwptr.bits32,fq_rwptr.bits32 );
+-#if 0
+-              if ((status4 & 0x1) == 0)
+-              {
+-                      //if (!((dev->last_rx <= (rx_time + 2)) &&  (isPtr->rx_bytes > (rx_old_bytes + 1000000 ))))
+-                      if (tp->total_q_cnt_napi < 1024)
+-                      {
+-                              tp->total_q_cnt_napi++;
+-                              toe_gmac_fill_free_q();  //for iperf test disable
+-                      }
+-                      //else
+-                              //printk("%s:---isPtr->rx_bytes =%u , rx_old_bytes =%u\n",__func__,isPtr->rx_bytes,rx_old_bytes );
++              // rwptr.bits32 = readl(&tp->default_qhdr->word1);
++              status4 = readl(TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_STATUS_4_REG);
++              if (status4 & 1) {
++                      writel(status4 & SWFQ_EMPTY_INT_BIT, TOE_GLOBAL_BASE+GLOBAL_INTERRUPT_STATUS_4_REG);
+               }
++
++              toe_gmac_fill_free_q(5);
++      }
++
++#if 0
++      /* avoid races with hard_start_xmit() */
++
++      spin_lock(&gmac_fq_lock);
++      toe_gmac_tx_complete(&toe_private_data.gmac[0], 0, dev, 1);
++      spin_unlock(&gmac_fq_lock);
+ #endif
+-              //rwptr.bits.rptr = RWPTR_ADVANCE_ONE(rwptr.bits.rptr, tp->default_desc_num);
+-              //printk("%s:---Loop  -------->rx_pkts_num=%d----rwptr.bits.rptr=0x%x-------->Default Queue HW RW ptr = (0x%8x),   fq_rwptr =0x%8x \n",__func__,rx_pkts_num,rwptr.bits.rptr,rwptr.bits32,fq_rwptr.bits32 );
+-              //printk("%s:---Loop  rx_pkts_num=%d------rwptr.bits.rptr=0x%x------->Default_Q [rwptr.bits.rptr(SW)=0x%x,   rwptr.bits.wptr(HW) = 0x%x ]---->Free_Q(SW_HW) = 0x%8x \n",__func__,rx_pkts_num,rwptr.bits.rptr,rwptr.bits.rptr,rwptr.bits.wptr,fq_rwptr.bits32 );
++
++      status4 = readl(TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_STATUS_4_REG);
++      if (status4 & 1)
++      {
++              writel(status4 & SWFQ_EMPTY_INT_BIT, TOE_GLOBAL_BASE+GLOBAL_INTERRUPT_STATUS_4_REG);
++              status4 = readl(TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_STATUS_4_REG);
++              toe_gmac_fill_free_q(rx_pkts_num);
+       }
+-      // advance one for Rx default Q 0/1
+-              //rwptr.bits.rptr = RWPTR_ADVANCE_ONE(rwptr.bits.rptr, tp->default_desc_num);
+-              //SET_RPTR(&tp->default_qhdr->word1, rwptr.bits.rptr);
+-      //tp->rx_rwptr.bits32 = rwptr.bits32;
+-      //rwptr.bits.rptr = rwptr.bits.rptr;
++      rwptr.bits32 = readl(&tp->default_qhdr->word1);
++      if (rwptr.bits.rptr != rwptr.bits.wptr &&
++          quota > rx_pkts_num)
++              goto rx_poll_retry;
+       dev->quota -= rx_pkts_num;
+       *budget -= rx_pkts_num;
+-      status4 = readl(TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_STATUS_4_REG);//try read SWFQ empty again
+-      //fq_rwptr.bits32 = readl(TOE_GLOBAL_BASE + GLOBAL_SWFQ_RWPTR_REG);
+-      rwptr.bits32 = readl(&tp->default_qhdr->word1); //try read default_qhdr again
+-      //printk("%s:---After    rx_pkts_num=%d------rwptr.bits.rptr=0x%x------->Default_Q [rwptr.bits.rptr(SW)=0x%x,   rwptr.bits.wptr(HW) = 0x%x ]---->Free_Q(SW_HW) = 0x%8x \n",__func__,rx_pkts_num,rwptr.bits.rptr,rwptr.bits.rptr,rwptr.bits.wptr,fq_rwptr.bits32 );
+-//    if (rwptr.bits.rptr > rwptr.bits.wptr )
+-//                    {
+-                              //toe_gmac_disable_rx(dev);
+-                              //wait_event_interruptible_timeout(freeq_wait,
+-                                      //(rx_pkts_num == 100), CMTP_INTEROP_TIMEOUT);
+-                              //printk("\n%s:: return 22222=======> rx_pkts_num =%d,   rwptr.bits.rptr=%d,   rwptr.bits.wptr = %d ====---------=======>JKJKJKJKJK\n",
+-                                      //__func__,rx_pkts_num,rwptr.bits.rptr,rwptr.bits.wptr);
+-//                            return 1;
+-//                    }
+-
+-      if (rwptr.bits.rptr == rwptr.bits.wptr)
++      /* Receive queue is empty now */
++      if (quota >= rx_pkts_num)
+       {
+-              // unsigned int data32;
+-                      //printk("%s:---[rwptr.bits.rptr == rwptr.bits.wptr]   rx_pkts_num=%d------rwptr.bits.rptr=0x%x------->Default_Q [rwptr.bits.rptr(SW)=0x%x,   rwptr.bits.wptr(HW) = 0x%x ]---->Free_Q(SW_HW) = 0x%8x \n",__func__,rx_pkts_num,rwptr.bits.rptr,rwptr.bits.rptr,rwptr.bits.wptr,fq_rwptr.bits32 );
+-
+-          /* Receive descriptor is empty now */
+-#if 1
+-     if (status4 & 0x1)
+-                      {
+-                              do_again =1;
+-                              //writel(0x40400000, TOE_GLOBAL_BASE+GLOBAL_INTERRUPT_ENABLE_4_REG); //disable SWFQ empty interrupt
+-                              //toe_gmac_disable_interrupt(tp->irq);
+-                              tp->sw_fq_empty_cnt++;
+-                              //toe_gmac_disable_rx(dev);
+-                              writel(0x07960202, TOE_GMAC0_BASE+GMAC_CONFIG0);
+-                              writel(0x07960202, TOE_GMAC1_BASE+GMAC_CONFIG0);
+-                              //printk("\n%s ::  freeq int-----tp->sw_fq_empty_cnt  =%d---------====================----------------->\n",__func__,tp->sw_fq_empty_cnt);
+-                              //while ((fq_rwptr.bits.wptr >= (fq_rwptr.bits.rptr+256)) || (fq_rwptr.bits.wptr <= (fq_rwptr.bits.rptr+256)))
+-                              //{
+-                                      //gmac_write_reg(TOE_GLOBAL_BASE, GLOBAL_INTERRUPT_STATUS_4_REG, status4,
+-                                      //0x1);
+-                              //printk("\n%s::fq_rwptr.wrptr = %x =======> ===========>here \n", __func__,fq_rwptr.bits32);
+-                              //if ((status4 & 0x1) == 0)
+-                                      //break;
+-                               return 1;
+-                              //}
++              unsigned long flags;
++              netif_rx_complete(dev);
++              rx_poll_enabled = 0;
++#if 0
++              status1 = readl(TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_STATUS_1_REG);
++              if (status1 & 1) {
++                      if (netif_rx_reschedule(dev, rx_pkts_num)) {
++                              rx_poll_enabled = 1;
++                              return 1;
+                       }
++              }
+ #endif
+-        //toe_gmac_fill_free_q();
+-        netif_rx_complete(dev);
+-
+-              rx_poll_enabled = 0;
+-              data32 = readl(TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_ENABLE_1_REG);
+-              if (tp->port_id == 0)
+-                              data32 |= DEFAULT_Q0_INT_BIT;
+-              else
+-                              data32 |= DEFAULT_Q1_INT_BIT;
+-              writel(data32, TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_ENABLE_1_REG);
++              spin_lock_irqsave(&gmac_fq_lock, flags);
+               data32 = readl(TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_ENABLE_4_REG);
+               if (tp->port_id == 0)
+-                              data32 |= DEFAULT_Q0_INT_BIT;
++                      data32 |= DEFAULT_Q0_INT_BIT;
+               else
+-                              data32 |= DEFAULT_Q1_INT_BIT;
++                      data32 |= DEFAULT_Q1_INT_BIT;
+               writel(data32, TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_ENABLE_4_REG);
+-              data32 = readl(TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_SELECT_4_REG);
++              data32 = readl(TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_ENABLE_1_REG);
+               if (tp->port_id == 0)
+-                              data32 |= DEFAULT_Q0_INT_BIT;
++                      data32 |= DEFAULT_Q0_INT_BIT;
+               else
+-                              data32 |= DEFAULT_Q1_INT_BIT;
+-              writel(data32, TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_SELECT_4_REG);
++                      data32 |= DEFAULT_Q1_INT_BIT;
++              writel(data32, TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_ENABLE_1_REG);
+-        // enable GMAC-0 rx interrupt
+-        // class-Q & TOE-Q are implemented in future
+-        //data32 = readl(TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_ENABLE_1_REG);
+-        //if (tp->port_id == 0)
+-              //data32 |= DEFAULT_Q0_INT_BIT;
+-        //else
+-              //data32 |= DEFAULT_Q1_INT_BIT;
+-        //writel(data32, TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_ENABLE_1_REG);
+-              writel(0x3, TOE_GLOBAL_BASE+GLOBAL_INTERRUPT_ENABLE_1_REG);
+-              //printk("\n%s::netif_rx_complete-->  rx_pkts_num =%d,   rwptr.bits.rptr=0x%x,   rwptr.bits.wptr = 0x%x ====---------=======>JKJKJKJKJK\n",
+-              //__func__,rx_pkts_num,rwptr.bits.rptr,rwptr.bits.wptr);
+-        writel(0x07960200, TOE_GMAC0_BASE+GMAC_CONFIG0);
+-              writel(0x07960200, TOE_GMAC1_BASE+GMAC_CONFIG0);
+-        return 0;
+-    }
+-    else
+-    {
+-        //printk("\n%s:: return 1 -->status4= 0x%x,rx_pkts_num =%d,   rwptr.bits.rptr=0x%x,   rwptr.bits.wptr = 0x%x  ======> \n", __func__,status4,rx_pkts_num,rwptr.bits.rptr,rwptr.bits.wptr);
+-        return 1;
+-    }
++              spin_unlock_irqrestore(&gmac_fq_lock, flags);
++
++              return 0;
++      }
++      else
++      {
++              /* not done, will call ->poll() later. */
++              return 1;
++      }
+ }
+ #endif
+@@ -5114,6 +4475,7 @@
+                       {
+                               sl351x_nat_workaround_cnt++;
+                               sl351x_nat_workaround_handler();
++                              printk("%():%d - workaround\n", __func__, __LINE__);
+                       }
+ #endif
+ #endif
+@@ -5124,6 +4486,7 @@
+       }
+ do_workaround:
++      printk("doing workaround ?!\n");
+       gmac_initialized = 0;
+       if (hanged_state)
+@@ -5290,6 +4653,7 @@
+       GMAC_SWTXQ_T    *swtxq;
+       DMA_RWPTR_T             rwptr;
++      printk("**** %s():%d\n", __func__, __LINE__);
+       toe = (TOE_INFO_T *)&toe_private_data;
+       tp = (GMAC_INFO_T *)&toe->gmac[0];
+       for (i=0; i<GMAC_NUM; i++, tp++)
+@@ -5341,6 +4705,7 @@
+       volatile GMAC_RXDESC_T  *curr_desc;
+       struct sk_buff                  *skb;
++      printk("**** %s():%d\n", __func__, __LINE__);
+       toe = (TOE_INFO_T *)&toe_private_data;
+       tp = (GMAC_INFO_T *)&toe->gmac[0];
+       for (i=0; i<GMAC_NUM; i++, tp++)
+@@ -5374,6 +4739,7 @@
+       volatile GMAC_RXDESC_T  *curr_desc;
+       struct sk_buff                  *skb;
++      printk("**** %s():%d\n", __func__, __LINE__);
+       toe = (TOE_INFO_T *)&toe_private_data;
+       classq = (CLASSQ_INFO_T *)&toe->classq[0];
+       for (i=0; i<TOE_CLASS_QUEUE_NUM; i++, classq++)
+@@ -5410,6 +4776,7 @@
+       GMAC_RXDESC_T   *toe_curr_desc;
+       struct sk_buff                  *skb;
++      printk("**** %s():%d\n", __func__, __LINE__);
+       toe = (TOE_INFO_T *)&toe_private_data;
+       toe_qhdr = (TOE_QHDR_T *)TOE_TOE_QUE_HDR_BASE;
+       for (i=0; i<TOE_TOE_QUEUE_NUM; i++, toe_qhdr++)
+Index: linux-2.6.23.16/include/asm-arm/arch-sl2312/sl351x_gmac.h
+===================================================================
+--- linux-2.6.23.16.orig/include/asm-arm/arch-sl2312/sl351x_gmac.h     2008-03-15 17:00:21.364762892 +0200
++++ linux-2.6.23.16/include/asm-arm/arch-sl2312/sl351x_gmac.h  2008-03-15 17:01:08.367441241 +0200
+@@ -107,7 +107,7 @@
+  * The base address and descriptor number are configured at
+  * DMA Queues Descriptor Ring Base Address/Size Register (offset 0x0004)
+  **********************************************************************/
+-#define TOE_SW_FREEQ_DESC_POWER               10
++#define TOE_SW_FREEQ_DESC_POWER               8
+ #define TOE_SW_FREEQ_DESC_NUM         (1<<TOE_SW_FREEQ_DESC_POWER)
+ #define TOE_HW_FREEQ_DESC_POWER               8
+ #define TOE_HW_FREEQ_DESC_NUM         (1<<TOE_HW_FREEQ_DESC_POWER)
+@@ -123,12 +123,12 @@
+ #define TOE_DEFAULT_Q0_DESC_NUM               (1<<TOE_DEFAULT_Q0_DESC_POWER)
+ #define TOE_DEFAULT_Q1_DESC_POWER     8
+ #define TOE_DEFAULT_Q1_DESC_NUM               (1<<TOE_DEFAULT_Q1_DESC_POWER)
+-#define TOE_TOE_DESC_POWER                    8
+-#define TOE_TOE_DESC_NUM                      (1<<TOE_TOE_DESC_POWER)
++#define TOE_TOE_DESC_POWER            8
++#define TOE_TOE_DESC_NUM              (1<<TOE_TOE_DESC_POWER)
+ #define TOE_CLASS_DESC_POWER          8
+-#define TOE_CLASS_DESC_NUM                    (1<<TOE_CLASS_DESC_POWER)
+-#define TOE_INTR_DESC_POWER                   8
+-#define TOE_INTR_DESC_NUM                     (1<<TOE_INTR_DESC_POWER)
++#define TOE_CLASS_DESC_NUM            (1<<TOE_CLASS_DESC_POWER)
++#define TOE_INTR_DESC_POWER           8
++#define TOE_INTR_DESC_NUM             (1<<TOE_INTR_DESC_POWER)
+ #define TOE_TOE_QUEUE_MAX                     64
+ #define TOE_TOE_QUEUE_NUM                     64
diff --git a/target/linux/storm/patches/1020-mtd.patch b/target/linux/storm/patches/1020-mtd.patch
new file mode 100644 (file)
index 0000000..7d5d7bc
--- /dev/null
@@ -0,0 +1,4981 @@
+Index: linux-2.6.23.16/drivers/mtd/chips/Kconfig
+===================================================================
+--- linux-2.6.23.16.orig/drivers/mtd/chips/Kconfig     2008-03-15 17:03:14.374622039 +0200
++++ linux-2.6.23.16/drivers/mtd/chips/Kconfig  2008-03-15 17:03:17.874821522 +0200
+@@ -220,6 +220,13 @@
+         This option enables basic support for ROM chips accessed through
+         a bus mapping driver.
++config MTD_SERIAL
++      tristate "Support for Serial chips in bus mapping"
++      depends on MTD
++      help
++        This option enables basic support for Serial chips accessed through
++        a bus mapping driver.
++
+ config MTD_ABSENT
+       tristate "Support for absent chips in bus mapping"
+       help
+Index: linux-2.6.23.16/drivers/mtd/chips/cfi_cmdset_0002.c
+===================================================================
+--- linux-2.6.23.16.orig/drivers/mtd/chips/cfi_cmdset_0002.c   2008-03-15 17:03:14.374622039 +0200
++++ linux-2.6.23.16/drivers/mtd/chips/cfi_cmdset_0002.c        2008-03-15 17:03:17.874821522 +0200
+@@ -39,10 +39,15 @@
+ #include <linux/mtd/cfi.h>
+ #include <linux/mtd/xip.h>
++//****** Storlink SoC ******
+ #define AMD_BOOTLOC_BUG
+-#define FORCE_WORD_WRITE 0
+-
+-#define MAX_WORD_RETRIES 3
++//#define FORCE_WORD_WRITE 0
++#define FORCE_WORD_WRITE 1
++#define FORCE_FAST_PROG 0
++
++//#define MAX_WORD_RETRIES 3
++#define MAX_WORD_RETRIES 3 // CONFIG_MTD_CFI_AMDSTD_RETRY
++//**************************
+ #define MANUFACTURER_AMD      0x0001
+ #define MANUFACTURER_ATMEL    0x001F
+@@ -322,6 +327,13 @@
+ #endif
+               bootloc = extp->TopBottom;
++//****** Storlink SoC ******
++              if(bootloc == 5)
++              {
++                      bootloc = 3;
++                      extp->TopBottom = 3;
++              }
++//**************************
+               if ((bootloc != 2) && (bootloc != 3)) {
+                       printk(KERN_WARNING "%s: CFI does not contain boot "
+                              "bank location. Assuming top.\n", map->name);
+@@ -340,6 +352,9 @@
+                               cfi->cfiq->EraseRegionInfo[j] = swap;
+                       }
+               }
++#ifdef CONFIG_MTD_MAP_BANK_WIDTH_1
++              cfi->device_type = CFI_DEVICETYPE_X8;
++#endif
+               /* Set the default CFI lock/unlock addresses */
+               cfi->addr_unlock1 = 0x555;
+               cfi->addr_unlock2 = 0x2aa;
+@@ -461,6 +476,7 @@
+       map_word d, t;
+       d = map_read(map, addr);
++      udelay(20);     //Storlink SoC
+       t = map_read(map, addr);
+       return map_word_equal(map, d, t);
+@@ -626,7 +642,9 @@
+       default:
+               printk(KERN_ERR "MTD: put_chip() called with oldstate %d!!\n", chip->oldstate);
+       }
++//****** Storlink SoC ******
+       wake_up(&chip->wq);
++//**************************
+ }
+ #ifdef CONFIG_MTD_XIP
+@@ -940,7 +958,9 @@
+       cfi_send_gen_cmd(0x90, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
+       cfi_send_gen_cmd(0x00, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
++//****** Storlink SoC ******
+       wake_up(&chip->wq);
++//**************************
+       spin_unlock(chip->mutex);
+       return 0;
+@@ -1005,7 +1025,10 @@
+        */
+       unsigned long uWriteTimeout = ( HZ / 1000 ) + 1;
+       int ret = 0;
+-      map_word oldd;
++//****** Storlink SoC ******
++//    map_word oldd;
++      map_word oldd, tmp;
++//**************************
+       int retry_cnt = 0;
+       adr += chip->start;
+@@ -1037,9 +1060,15 @@
+       ENABLE_VPP(map);
+       xip_disable(map, chip, adr);
+  retry:
++//****** Storlink SoC ******
++#if FORCE_FAST_PROG  /* Unlock bypass */
++      cfi_send_gen_cmd(0xA0, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
++#else
+       cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
+       cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, cfi->device_type, NULL);
+       cfi_send_gen_cmd(0xA0, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
++#endif
++//**************************
+       map_write(map, datum, adr);
+       chip->state = FL_WRITING;
+@@ -1072,7 +1101,13 @@
+               }
+               if (chip_ready(map, adr))
+-                      break;
++              {
++                      tmp = map_read(map, adr);
++                      if(map_word_equal(map, tmp, datum))
++//                            goto op_done;
++                break;
++
++              }
+               /* Latency issues. Drop the lock, wait a while and retry */
+               UDELAY(map, chip, adr, 1);
+@@ -1084,8 +1119,17 @@
+               /* FIXME - should have reset delay before continuing */
+               if (++retry_cnt <= MAX_WORD_RETRIES)
++              {
++//****** Storlink SoC ******
++#if FORCE_FAST_PROG
++                      cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
++                      cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, cfi->device_type, NULL);
++                      cfi_send_gen_cmd(0x20, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
++              //udelay(1);
++#endif
++                      udelay(1);
+                       goto retry;
+-
++              }
+               ret = -EIO;
+       }
+       xip_enable(map, chip, adr);
+@@ -1171,7 +1215,14 @@
+                               return 0;
+               }
+       }
+-
++//****** Storlink SoC ******
++      map_write( map, CMD(0xF0), chipstart );
++#if FORCE_FAST_PROG
++              cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chipstart, map, cfi, cfi->device_type, NULL);
++              cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chipstart, map, cfi, cfi->device_type, NULL);
++              cfi_send_gen_cmd(0x20, cfi->addr_unlock1, chipstart, map, cfi, cfi->device_type, NULL);
++#endif
++//**************************
+       /* We are now aligned, write as much as possible */
+       while(len >= map_bankwidth(map)) {
+               map_word datum;
+@@ -1181,7 +1232,15 @@
+               ret = do_write_oneword(map, &cfi->chips[chipnum],
+                                      ofs, datum);
+               if (ret)
++              {
++//****** Storlink SoC ******
++#if FORCE_FAST_PROG
++                      /* Get out of unlock bypass mode */
++                      cfi_send_gen_cmd(0x90, 0, chipstart, map, cfi, cfi->device_type, NULL);
++                      cfi_send_gen_cmd(0x00, 0, chipstart, map, cfi, cfi->device_type, NULL);
++#endif
+                       return ret;
++              }
+               ofs += map_bankwidth(map);
+               buf += map_bankwidth(map);
+@@ -1189,19 +1248,38 @@
+               len -= map_bankwidth(map);
+               if (ofs >> cfi->chipshift) {
++//****** Storlink SoC ******
++#if FORCE_FAST_PROG
++                      /* Get out of unlock bypass mode */
++                      cfi_send_gen_cmd(0x90, 0, chipstart, map, cfi, cfi->device_type, NULL);
++                      cfi_send_gen_cmd(0x00, 0, chipstart, map, cfi, cfi->device_type, NULL);
++#endif
+                       chipnum ++;
+                       ofs = 0;
+                       if (chipnum == cfi->numchips)
+                               return 0;
+                       chipstart = cfi->chips[chipnum].start;
++#if FORCE_FAST_PROG
++                      /* Go into unlock bypass mode for next set of chips */
++                      cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chipstart, map, cfi, cfi->device_type, NULL);
++                      cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chipstart, map, cfi, cfi->device_type, NULL);
++                      cfi_send_gen_cmd(0x20, cfi->addr_unlock1, chipstart, map, cfi, cfi->device_type, NULL);
++#endif
+               }
+       }
++#if FORCE_FAST_PROG
++      /* Get out of unlock bypass mode */
++      cfi_send_gen_cmd(0x90, 0, chipstart, map, cfi, cfi->device_type, NULL);
++      cfi_send_gen_cmd(0x00, 0, chipstart, map, cfi, cfi->device_type, NULL);
++#endif
++
+       /* Write the trailing bytes if any */
+       if (len & (map_bankwidth(map)-1)) {
+               map_word tmp_buf;
+  retry1:
++
+               spin_lock(cfi->chips[chipnum].mutex);
+               if (cfi->chips[chipnum].state != FL_READY) {
+@@ -1221,7 +1299,11 @@
+ #endif
+                       goto retry1;
+               }
+-
++#if FORCE_FAST_PROG
++              cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chipstart, map, cfi, cfi->device_type, NULL);
++              cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chipstart, map, cfi, cfi->device_type, NULL);
++              cfi_send_gen_cmd(0x20, cfi->addr_unlock1, chipstart, map, cfi, cfi->device_type, NULL);
++#endif
+               tmp_buf = map_read(map, ofs + chipstart);
+               spin_unlock(cfi->chips[chipnum].mutex);
+@@ -1231,11 +1313,23 @@
+               ret = do_write_oneword(map, &cfi->chips[chipnum],
+                               ofs, tmp_buf);
+               if (ret)
++              {
++#if FORCE_FAST_PROG
++      /* Get out of unlock bypass mode */
++      cfi_send_gen_cmd(0x90, 0, chipstart, map, cfi, cfi->device_type, NULL);
++      cfi_send_gen_cmd(0x00, 0, chipstart, map, cfi, cfi->device_type, NULL);
++#endif
+                       return ret;
+-
++              }
++#if FORCE_FAST_PROG
++      /* Get out of unlock bypass mode */
++      cfi_send_gen_cmd(0x90, 0, chipstart, map, cfi, cfi->device_type, NULL);
++      cfi_send_gen_cmd(0x00, 0, chipstart, map, cfi, cfi->device_type, NULL);
++#endif
+               (*retlen) += len;
+       }
++      map_write( map, CMD(0xF0), chipstart );
+       return 0;
+ }
+@@ -1275,6 +1369,7 @@
+       ENABLE_VPP(map);
+       xip_disable(map, chip, cmd_adr);
++      map_write( map, CMD(0xF0), chip->start );       //Storlink
+       cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
+       cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, cfi->device_type, NULL);
+       //cfi_send_gen_cmd(0xA0, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
+@@ -1535,6 +1630,9 @@
+       DECLARE_WAITQUEUE(wait, current);
+       int ret = 0;
++#ifdef CONFIG_SL2312_SHARE_PIN
++      mtd_lock();                             // sl2312 share pin lock
++#endif
+       adr += chip->start;
+       spin_lock(chip->mutex);
+@@ -1613,6 +1711,9 @@
+       chip->state = FL_READY;
+       put_chip(map, chip, adr);
+       spin_unlock(chip->mutex);
++#ifdef CONFIG_SL2312_SHARE_PIN
++      mtd_unlock();                           // sl2312 share pin lock
++#endif
+       return ret;
+ }
+Index: linux-2.6.23.16/drivers/mtd/chips/map_serial.c
+===================================================================
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.23.16/drivers/mtd/chips/map_serial.c     2008-03-15 17:03:17.874821522 +0200
+@@ -0,0 +1,188 @@
++/*
++ * Common code to handle map devices which are simple ROM
++ * (C) 2000 Red Hat. GPL'd.
++ * $Id: map_serial.c,v 1.3 2006/06/05 02:34:54 middle Exp $
++ */
++
++#include <linux/version.h>
++#include <linux/module.h>
++#include <linux/types.h>
++#include <linux/kernel.h>
++#include <asm/io.h>
++
++#include <asm/byteorder.h>
++#include <linux/errno.h>
++#include <linux/slab.h>
++
++#include <asm/hardware.h>
++#include <linux/mtd/map.h>
++#include <linux/mtd/mtd.h>
++#include <linux/init.h> //add
++#include <asm/arch/sl2312.h>
++#include <asm/arch/flash.h>
++
++static int mapserial_erase(struct mtd_info *mtd, struct erase_info *instr);
++static int mapserial_read (struct mtd_info *, loff_t, size_t, size_t *, u_char *);
++static int mapserial_write (struct mtd_info *, loff_t, size_t, size_t *, const u_char *);
++static void mapserial_nop (struct mtd_info *);
++struct mtd_info *map_serial_probe(struct map_info *map);
++
++extern int m25p80_sector_erase(__u32 address, __u32 schip_en);
++
++static struct mtd_chip_driver mapserial_chipdrv = {
++      probe: map_serial_probe,
++      name: "map_serial",
++      module: THIS_MODULE
++};
++
++struct mtd_info *map_serial_probe(struct map_info *map)
++{
++      struct mtd_info *mtd;
++
++      mtd = kmalloc(sizeof(*mtd), GFP_KERNEL);
++      if (!mtd)
++              return NULL;
++
++      memset(mtd, 0, sizeof(*mtd));
++
++      map->fldrv = &mapserial_chipdrv;
++      mtd->priv = map;
++      mtd->name = map->name;
++      mtd->type = MTD_OTHER;
++      mtd->erase = mapserial_erase;
++      mtd->size = map->size;
++      mtd->read = mapserial_read;
++      mtd->write = mapserial_write;
++      mtd->sync = mapserial_nop;
++      mtd->flags = (MTD_WRITEABLE|MTD_ERASEABLE);
++//    mtd->erasesize = 512; // page size;
++#ifdef CONFIG_MTD_SL2312_SERIAL_ST
++      mtd->erasesize = M25P80_SECTOR_SIZE; // block size;
++#else
++      mtd->erasesize = 0x1000; // block size;
++#endif
++
++      __module_get(THIS_MODULE);
++      //MOD_INC_USE_COUNT;
++      return mtd;
++}
++
++#define       FLASH_ACCESS_OFFSET                             0x00000010
++#define       FLASH_ADDRESS_OFFSET                            0x00000014
++#define       FLASH_WRITE_DATA_OFFSET                         0x00000018
++#define       FLASH_READ_DATA_OFFSET                          0x00000018
++
++static __u32 readflash_ctrl_reg(__u32 ofs)
++{
++    __u32 *base;
++
++    base = (__u32 *)IO_ADDRESS((SL2312_FLASH_CTRL_BASE + ofs));
++    return __raw_readl(base);
++}
++
++static void writeflash_ctrl_reg(__u32 data, __u32 ofs)
++{
++    __u32 *base;
++
++    base = (__u32 *)IO_ADDRESS((SL2312_FLASH_CTRL_BASE + ofs));
++    __raw_writel(data, base);
++}
++
++static int mapserial_erase_block(struct map_info *map,unsigned int block)
++{
++
++      __u32 address;
++#ifdef CONFIG_MTD_SL2312_SERIAL_ST
++
++      if(!m25p80_sector_erase(block, 0))
++              return (MTD_ERASE_DONE);
++#else
++      __u32 opcode;
++      __u32 count=0;
++//      __u8  status;
++
++ //     printk("mapserial_erase_block : erase block %d \n",block);
++//      opcode = 0x80000000 | FLASH_ACCESS_ACTION_SHIFT_ADDRESS | cmd;
++      opcode = 0x80000000 | 0x0200 | 0x50;
++      address = (block << 13);
++      writeflash_ctrl_reg(address,FLASH_ADDRESS_OFFSET);
++      writeflash_ctrl_reg(opcode,FLASH_ACCESS_OFFSET);
++      opcode=readflash_ctrl_reg(FLASH_ACCESS_OFFSET);
++      while(opcode&0x80000000)
++      {
++          opcode = readflash_ctrl_reg(FLASH_ACCESS_OFFSET);
++          count++;
++          if (count > 10000)
++          {
++            return (MTD_ERASE_FAILED);
++          }
++      }
++      return (MTD_ERASE_DONE);
++#endif
++}
++
++static int mapserial_erase(struct mtd_info *mtd, struct erase_info *instr)
++{
++      struct map_info *map = (struct map_info *)mtd->priv;
++    unsigned int    addr;
++    int             len;
++    unsigned int    block;
++    unsigned int    ret=0;
++
++      addr = instr->addr;
++      len = instr->len;
++    while (len > 0)
++    {
++        block = addr / mtd->erasesize;
++#ifdef CONFIG_MTD_SL2312_SERIAL_ST
++        ret = mapserial_erase_block(map,addr);
++#else
++              ret = mapserial_erase_block(map,block);
++#endif
++        addr = addr + mtd->erasesize;
++        len = len - mtd->erasesize;
++    }
++    return (ret);
++}
++
++static int mapserial_read (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf)
++{
++      struct map_info *map = (struct map_info *)mtd->priv;
++//        printk("mapserial_read : \n");
++      map->copy_from(map, buf, from, len);
++      *retlen = len;
++      return 0;
++}
++
++static void mapserial_nop(struct mtd_info *mtd)
++{
++      /* Nothing to see here */
++}
++
++static int mapserial_write (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf)
++{
++      struct map_info *map = (struct map_info *)mtd->priv;
++//    printk("mapserial_write : buf %x to %x len %x \n",(int)buf, (int)to, (int)len);
++      //map->copy_to(map, buf, to, len);
++      map->copy_to(map, to, buf, len);
++      *retlen = len;
++      return 0;
++}
++
++int __init map_serial_init(void)
++{
++      register_mtd_chip_driver(&mapserial_chipdrv);
++      return 0;
++}
++
++static void __exit map_serial_exit(void)
++{
++      unregister_mtd_chip_driver(&mapserial_chipdrv);
++}
++
++module_init(map_serial_init);
++module_exit(map_serial_exit);
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>");
++MODULE_DESCRIPTION("MTD chip driver for ROM chips");
+Index: linux-2.6.23.16/drivers/mtd/maps/Kconfig
+===================================================================
+--- linux-2.6.23.16.orig/drivers/mtd/maps/Kconfig      2008-03-15 17:03:14.374622039 +0200
++++ linux-2.6.23.16/drivers/mtd/maps/Kconfig   2008-03-15 17:03:17.874821522 +0200
+@@ -614,5 +614,30 @@
+         This selection automatically selects the map_ram driver.
++#***************************************************************************************
++# Storlink parallel/Serial Flash configuration
++#***************************************************************************************
++config MTD_SL2312_CFI
++        tristate "CFI Flash device mapped on SL2312"
++        depends on MTD_CFI
++        help
++          Map driver for SL2312 demo board.
++
++config MTD_SL2312_SERIAL_ATMEL
++        tristate "ATMEL Serial Flash device mapped on SL2312"
++        depends on MTD_PARTITIONS && ARCH_SL2312
++        help
++          Map driver for SL2312 demo board.
++
++config MTD_SL2312_SERIAL_ST
++        tristate "ST Serial Flash device mapped on SL2312"
++        depends on MTD_PARTITIONS && ARCH_SL2312
++        help
++          Map driver for SL2312 demo board.
++
++config SL2312_SHARE_PIN
++        tristate "Parallel Flash share pin on SL2312 ASIC"
++        depends on SL3516_ASIC
++
+ endmenu
+Index: linux-2.6.23.16/drivers/mtd/maps/sl2312-flash-atmel.c
+===================================================================
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.23.16/drivers/mtd/maps/sl2312-flash-atmel.c      2008-03-15 17:04:02.877385981 +0200
+@@ -0,0 +1,554 @@
++/*
++ * $Id: sl2312-flash-atmel.c,v 1.2 2006/06/05 02:35:57 middle Exp $
++ *
++ * Flash and EPROM on Hitachi Solution Engine and similar boards.
++ *
++ * (C) 2001 Red Hat, Inc.
++ *
++ * GPL'd
++ */
++
++#include <linux/module.h>
++#include <linux/types.h>
++#include <linux/kernel.h>
++
++#include <asm/io.h>
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/map.h>
++#include <linux/mtd/partitions.h>
++#include <asm/hardware.h>
++
++#include <asm/arch/sl2312.h>
++#include <asm/arch/flash.h>
++#include <linux/init.h> //add
++
++
++#define  g_page_addr  AT45DB321_PAGE_SHIFT    //321 : shift 10  ; 642 : shift 11
++#define  g_chipen     SERIAL_FLASH_CHIP0_EN   //atmel
++
++extern int parse_redboot_partitions(struct mtd_info *master, struct mtd_partition **pparts);
++
++void address_to_page(__u32 address, __u16 *page, __u16 *offset)
++{
++    *page = address / SPAGE_SIZE;
++    *offset = address % SPAGE_SIZE;
++}
++
++static __u32 read_flash_ctrl_reg(__u32 ofs)
++{
++    __u32 *base;
++
++    base = (__u32 *)IO_ADDRESS((SL2312_FLASH_CTRL_BASE + ofs));
++    return __raw_readl(base);
++}
++
++static void write_flash_ctrl_reg(__u32 ofs,__u32 data)
++{
++    __u32 *base;
++
++    base = (__u32 *)IO_ADDRESS((SL2312_FLASH_CTRL_BASE + ofs));
++    __raw_writel(data, base);
++}
++
++void atmel_read_status(__u8 cmd, __u8 *data)
++{
++      __u32 opcode;
++      __u32 value;
++
++      opcode = 0x80000000 | FLASH_ACCESS_ACTION_OPCODE_DATA | cmd | g_chipen;
++      write_flash_ctrl_reg(FLASH_ACCESS_OFFSET, opcode);
++      opcode=read_flash_ctrl_reg(FLASH_ACCESS_OFFSET);
++      while(opcode&0x80000000)
++      {
++          opcode=read_flash_ctrl_reg(FLASH_ACCESS_OFFSET);
++          flash_delay();
++          schedule();
++      }
++
++      value=read_flash_ctrl_reg(FLASH_READ_DATA_OFFSET);
++      *data = value & 0xff;
++}
++
++void main_memory_page_read(__u8 cmd, __u16 page, __u16 offset, __u8 *data)
++{
++      __u32 opcode;
++      __u32 address;
++      __u32 value;
++
++      opcode = 0x80000000 | FLASH_ACCESS_ACTION_SHIFT_ADDRESS_4X_DATA | cmd | g_chipen;
++      address = (page << g_page_addr) + offset;
++      write_flash_ctrl_reg(FLASH_ADDRESS_OFFSET, address);
++      write_flash_ctrl_reg(FLASH_ACCESS_OFFSET, opcode);
++      opcode=read_flash_ctrl_reg(FLASH_ACCESS_OFFSET);
++      while(opcode&0x80000000)
++      {
++          opcode=read_flash_ctrl_reg(FLASH_ACCESS_OFFSET);
++          flash_delay();
++          schedule();
++      }
++
++      value=read_flash_ctrl_reg(FLASH_READ_DATA_OFFSET);
++      *data = value & 0xff;
++}
++
++void buffer_to_main_memory(__u8 cmd, __u16 page)
++{
++      __u32 opcode;
++      __u32 address;
++      __u8  status;
++
++      opcode = 0x80000000 | FLASH_ACCESS_ACTION_SHIFT_ADDRESS | cmd | g_chipen;
++      address = (page << g_page_addr);
++      write_flash_ctrl_reg(FLASH_ADDRESS_OFFSET, address);
++      write_flash_ctrl_reg(FLASH_ACCESS_OFFSET, opcode);
++      opcode=read_flash_ctrl_reg(FLASH_ACCESS_OFFSET);
++      while(opcode&0x80000000)
++      {
++          opcode=read_flash_ctrl_reg(FLASH_ACCESS_OFFSET);
++          flash_delay();
++          schedule();
++      }
++      atmel_read_status(READ_STATUS_SPI, &status);
++      while(!(status&0x80))
++      {
++          atmel_read_status(READ_STATUS_SPI, &status);
++          flash_delay();
++          schedule();
++      }
++
++}
++
++
++void atmel_flash_read_page(__u32 address, __u8 *buffer, __u32 len)
++{
++    __u8  byte;
++    __u16 page, offset;
++    __u16 i;
++
++    address_to_page(address, &page, &offset);
++
++     for(i=0; i<len; i++,offset++)
++    {
++        main_memory_page_read(MAIN_MEMORY_PAGE_READ_SPI , page, offset, &byte);
++        buffer [i]= byte;
++    }
++}
++
++void atmel_flash_program_page(__u32 address, __u8 *buffer, __u32 len)
++{
++    __u8  pattern;
++    __u16 page, offset;
++    __u32 i;
++
++    address_to_page(address, &page, &offset);
++ //   printk("atmel_flash_program_page: offset %x len %x page %x \n", offset, len, page);
++
++    if(offset)
++          main_memory_to_buffer(MAIN_MEMORY_TO_BUFFER1,page);
++
++    for(i=0; i<len; i++,offset++)
++    {
++        pattern = buffer[i];
++        atmel_buffer_write(BUFFER1_WRITE,offset,pattern);
++    }
++
++  //  printk("atmel_flash_program_page: offset %x \n", offset);
++    buffer_to_main_memory(BUFFER1_TO_MAIN_MEMORY, page);
++  //  printk("atmel_flash_program_page: buffer_to_main_memory %x page\n", page);
++
++}
++
++
++void main_memory_to_buffer(__u8 cmd, __u16 page)
++{
++      __u32 opcode;
++      __u32 address;
++      __u8  status;
++
++      opcode = 0x80000000 | FLASH_ACCESS_ACTION_SHIFT_ADDRESS | cmd | g_chipen;
++      address = (page << g_page_addr);
++      write_flash_ctrl_reg(FLASH_ADDRESS_OFFSET, address);
++      write_flash_ctrl_reg(FLASH_ACCESS_OFFSET, opcode);
++      opcode=read_flash_ctrl_reg(FLASH_ACCESS_OFFSET);
++      while(opcode&0x80000000)
++      {
++          opcode=read_flash_ctrl_reg(FLASH_ACCESS_OFFSET);
++          flash_delay();
++          schedule();
++      }
++      atmel_read_status(READ_STATUS_SPI, &status);
++      while(!(status&0x80))
++      {
++          atmel_read_status(READ_STATUS_SPI, &status);
++          flash_delay();
++          schedule();
++      }
++
++}
++
++void main_memory_page_program(__u8 cmd, __u16 page, __u16 offset, __u8 data)
++{
++      __u32 opcode;
++      __u32 address;
++      __u8  status;
++
++      opcode = 0x80000000 | FLASH_ACCESS_ACTION_SHIFT_ADDRESS_DATA | cmd | g_chipen;
++      address = (page << g_page_addr) + offset;
++      write_flash_ctrl_reg(FLASH_ADDRESS_OFFSET, address);
++      write_flash_ctrl_reg(FLASH_WRITE_DATA_OFFSET, data);
++      write_flash_ctrl_reg(FLASH_ACCESS_OFFSET, opcode);
++      opcode=read_flash_ctrl_reg(FLASH_ACCESS_OFFSET);
++      while(opcode&0x80000000)
++      {
++          opcode=read_flash_ctrl_reg(FLASH_ACCESS_OFFSET);
++          flash_delay();
++          schedule();
++      }
++      atmel_read_status(READ_STATUS_SPI, &status);
++      while(!(status&0x80))
++      {
++          atmel_read_status(READ_STATUS_SPI, &status);
++          flash_delay();
++          schedule();
++      }
++}
++
++void atmel_buffer_write(__u8 cmd, __u16 offset, __u8 data)
++{
++      __u32 opcode;
++      __u32 address;
++
++      opcode = 0x80000000 | FLASH_ACCESS_ACTION_SHIFT_ADDRESS_DATA | cmd  | g_chipen;
++      address = offset;
++      write_flash_ctrl_reg(FLASH_ADDRESS_OFFSET, address);
++      write_flash_ctrl_reg(FLASH_WRITE_DATA_OFFSET, data);
++      write_flash_ctrl_reg(FLASH_ACCESS_OFFSET, opcode);
++      opcode=read_flash_ctrl_reg(FLASH_ACCESS_OFFSET);
++      while(opcode&0x80000000)
++      {
++          opcode=read_flash_ctrl_reg(FLASH_ACCESS_OFFSET);
++          flash_delay();
++          schedule();
++      }
++
++}
++
++void atmel_erase_page(__u8 cmd, __u16 page)
++{
++      __u32 opcode;
++      __u32 address;
++      __u8  status;
++
++      opcode = 0x80000000 | FLASH_ACCESS_ACTION_SHIFT_ADDRESS | cmd | g_chipen;
++      address = (page << g_page_addr);
++      write_flash_ctrl_reg(FLASH_ADDRESS_OFFSET, address);
++      write_flash_ctrl_reg(FLASH_ACCESS_OFFSET, opcode);
++      opcode=read_flash_ctrl_reg(FLASH_ACCESS_OFFSET);
++      while(opcode&0x80000000)
++      {
++          opcode=read_flash_ctrl_reg(FLASH_ACCESS_OFFSET);
++          flash_delay();
++          schedule();
++      }
++      atmel_read_status(READ_STATUS_SPI, &status);
++      while(!(status&0x80))
++      {
++          atmel_read_status(READ_STATUS_SPI, &status);
++          flash_delay();
++          schedule();
++      }
++
++}
++
++void atmel_erase_block(__u8 cmd, __u16 block)
++{
++      __u32 opcode;
++      __u32 address;
++      __u8  status;
++
++      opcode = 0x80000000 | FLASH_ACCESS_ACTION_SHIFT_ADDRESS | cmd | g_chipen;
++      address = (block << 13);
++      write_flash_ctrl_reg(FLASH_ADDRESS_OFFSET, address);
++      write_flash_ctrl_reg(FLASH_ACCESS_OFFSET, opcode);
++      opcode=read_flash_ctrl_reg(FLASH_ACCESS_OFFSET);
++      while(opcode&0x80000000)
++      {
++          opcode=read_flash_ctrl_reg(FLASH_ACCESS_OFFSET);
++          flash_delay();
++          schedule();
++      }
++      atmel_read_status(READ_STATUS_SPI, &status);
++      while(!(status&0x80))
++      {
++          atmel_read_status(READ_STATUS_SPI, &status);
++          flash_delay();
++          schedule();
++      }
++
++}
++
++void flash_delay(void)
++{
++      int i;
++
++      for(i=0; i<50; i++)
++           i=i;
++}
++
++
++
++
++__u32 sl2312_read32(struct map_info *map, unsigned long ofs)
++{
++
++#if 0
++    __u16 page, offset;
++    __u32 pattern;
++    __u8  byte, i;
++
++     pattern = 0;
++     address_to_page(ofs, &page, &offset);
++     for(i=0; i<4; i++, offset++)
++    {
++        pattern = pattern << 8;
++        main_memory_page_read(MAIN_MEMORY_PAGE_READ_SPI , page, offset, &byte);
++//printk("sl2312_read32:: address = %08x  data = %c \n",ofs,byte);
++        pattern += byte;
++    }
++    return pattern;
++#else
++      return read_flash_ctrl_reg(ofs);
++#endif
++
++}
++
++__u8 sl2312_read8(struct map_info *map, unsigned long ofs)
++{
++    __u16 page, offset;
++    __u8  byte;
++
++     address_to_page(ofs, &page, &offset);
++     main_memory_page_read(MAIN_MEMORY_PAGE_READ_SPI , page, offset, &byte);
++       //printk("sl2312_read8:: address = %08x  data = %c \n",ofs,byte);
++     return byte;
++
++}
++
++void sl2312_write32(struct map_info *map, __u32 d, unsigned long ofs)
++{
++#if 0
++    __u16 page, offset;
++    __u8  byte, i;
++
++     address_to_page(ofs, &page, &offset);
++     for(i=0; i<4; i++, offset++)
++    {
++      byte = d & 0xff;
++        main_memory_page_program(MAIN_MEMORY_PROGRAM_BUFFER1, page, offset, byte);
++        d = d >> 8;
++//printk("sl2312_write32:: address = %08x  data = %c \n",ofs,byte);
++    }
++#else
++      write_flash_ctrl_reg(ofs, d);
++#endif
++}
++
++void sl2312_write8(struct map_info *map, __u8 d, unsigned long ofs)
++{
++     __u16 page, offset;
++
++     address_to_page(ofs, &page, &offset);
++     main_memory_page_program(MAIN_MEMORY_PROGRAM_BUFFER1, page, offset, d);
++//printk("sl2312_write8:: address = %08x  data = %c \n",ofs,d);
++
++}
++
++void sl2312_copy_from(struct map_info *map, void *buf, unsigned long ofs, ssize_t len)
++{
++     __u32 size;
++     __u8  *buffer;
++     __u32 length;//i, j,
++
++     //printk("sl2312_copy_from:: address = %08x  datalen = %d \n",ofs,len);
++
++     length = len;
++     buffer = (__u8 *)buf;
++     while(len)
++     {
++        size = SPAGE_SIZE - (ofs%SPAGE_SIZE);
++        if(size > len)
++            size = len;
++        atmel_flash_read_page(ofs, buffer, size);
++        buffer+=size;
++        ofs+=size;
++        len -= size;
++     }
++
++#if 0
++        buffer = (__u8 *)buf;
++        for(i=0; i<length; i+=16)
++       {
++          for(j=0; j<16; j++,buffer++)
++         {
++            if((i*16+j)<length)
++              printk("%x  ",(int)*buffer);
++       }
++          printk("\n");
++       }
++
++       printk("\n");
++#endif
++
++}
++
++
++void sl2312_copy_to(struct map_info *map, unsigned long ofs, void *buf, ssize_t len)
++{
++     __u32 size;
++     __u8  *buffer;
++
++     buffer = (__u8 *)buf;
++     //printk("sl2312_copy_to:offset %x len %x \n", ofs, len);
++//     printk("sl2312_copy_to:buf is %x \n", (int)buf);
++
++     while(len)
++     {
++        size = SPAGE_SIZE - (ofs%SPAGE_SIZE);
++        if(size > len)
++            size = len;
++        atmel_flash_program_page(ofs, buffer, size);
++        buffer+=size;
++        ofs+=size;
++      len-=size;
++    }
++
++
++}
++
++
++static struct mtd_info *serial_mtd;
++
++static struct mtd_partition *parsed_parts;
++
++static struct map_info sl2312_serial_map = {
++//    name: "SL2312 serial flash",
++//    size: 4194304, //0x400000,
++//            //buswidth: 4,
++//    bankwidth: 4,
++//    phys:            SL2312_FLASH_BASE,
++//#ifdef CONFIG_MTD_COMPLEX_MAPPINGS
++//    //read32: sl2312_read32,
++//    //read8: sl2312_read8,
++//    copy_from: sl2312_copy_from,
++//    //write8: sl2312_write8,
++//    //write32: sl2312_write32,
++//    read: sl2312_read32,
++//    write: sl2312_write32,
++//    copy_to: sl2312_copy_to
++//#endif
++      .name = "SL2312 serial flash",
++      .size = 4194304, //0x400000,
++              //buswidth: 4,
++      .bankwidth = 4,
++      .phys =          SL2312_FLASH_BASE,
++#ifdef CONFIG_MTD_COMPLEX_MAPPINGS
++      //read32: sl2312_read32,
++      //read8: sl2312_read8,
++      .copy_from = sl2312_copy_from,
++      //write8: sl2312_write8,
++      //write32: sl2312_write32,
++      .read = sl2312_read32,
++      .write = sl2312_write32,
++      .copy_to = sl2312_copy_to
++#endif
++};
++
++
++
++static struct mtd_partition sl2312_partitions[] = {
++
++
++      ///* boot code */
++      //{ name: "bootloader", offset: 0x00000000, size: 0x20000, },
++      ///* kernel image */
++      //{ name: "kerel image", offset: 0x000020000, size: 0x2E0000 },
++      ///* All else is writable (e.g. JFFS) */
++      //{ name: "user data", offset: 0x00300000, size: 0x00100000, },
++      /* boot code */
++      { .name = "bootloader", .offset = 0x00000000, .size = 0x20000, },
++      /* kernel image */
++      { .name = "kerel image", .offset = 0x000020000, .size = 0xE0000 },
++      /* All else is writable (e.g. JFFS) */
++      { .name = "user data", .offset = 0x00100000, .size = 0x00300000, },
++
++
++};
++
++
++
++static int __init init_sl2312_maps(void)
++{
++      int nr_parts = 0;
++      struct mtd_partition *parts;
++
++      serial_mtd = kmalloc(sizeof(struct mtd_info), GFP_KERNEL);
++      if (!serial_mtd)
++              return NULL;
++
++      memset(serial_mtd, 0, sizeof(struct mtd_info));
++      //sl2312flash_map.virt = (unsigned long)ioremap(SL2312_FLASH_BASE, FLASH_SIZE);
++    //sl2312_serial_map.map_priv_1 = (unsigned long)ioremap(SL2312_FLASH_BASE, SFLASH_SIZE);//(unsigned long)FLASH_VBASE;
++    sl2312_serial_map.virt = (unsigned long)ioremap(SL2312_FLASH_BASE, SFLASH_SIZE);//(unsigned long)ioremap(FLASH_START, SFLASH_SIZE);
++    if (!sl2312_serial_map.virt) {
++              printk(" failed to ioremap \n");
++              return -EIO;
++      }
++      serial_mtd = do_map_probe("map_serial", &sl2312_serial_map);
++      if (serial_mtd) {
++              //serial_mtd->module = THIS_MODULE;
++              serial_mtd->owner = THIS_MODULE;
++
++      }
++
++#ifdef CONFIG_MTD_REDBOOT_PARTS
++      nr_parts = parse_redboot_partitions(serial_mtd, &parsed_parts);
++      if (nr_parts > 0)
++              printk(KERN_NOTICE "Found RedBoot partition table.\n");
++      else if (nr_parts < 0)
++              printk(KERN_NOTICE "Error looking for RedBoot partitions.\n");
++#else
++      parsed_parts = sl2312_partitions;
++      parts = sl2312_partitions;
++      nr_parts = sizeof(sl2312_partitions)/sizeof(*parts);
++      nr_parts = sizeof(sl2312_partitions)/sizeof(*parsed_parts);
++#endif /* CONFIG_MTD_REDBOOT_PARTS */
++
++      if (nr_parts > 0)
++          add_mtd_partitions(serial_mtd, parsed_parts, nr_parts);
++      else
++          add_mtd_device(serial_mtd);
++
++      return 0;
++}
++
++static void __exit cleanup_sl2312_maps(void)
++{
++      if (parsed_parts)
++          del_mtd_partitions(serial_mtd);
++      else
++          del_mtd_device(serial_mtd);
++
++      map_destroy(serial_mtd);
++
++
++}
++
++module_init(init_sl2312_maps);
++module_exit(cleanup_sl2312_maps);
++
++
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Plus Chen <plus@storlink.com.tw>");
++MODULE_DESCRIPTION("MTD map driver for Storlink Sword boards");
++
+Index: linux-2.6.23.16/drivers/mtd/maps/sl2312-flash-cfi.c
+===================================================================
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.23.16/drivers/mtd/maps/sl2312-flash-cfi.c        2008-03-15 17:04:09.377756409 +0200
+@@ -0,0 +1,370 @@
++/*======================================================================
++
++   This program is free software; you can redistribute it and/or modify
++   it under the terms of the GNU General Public License as published by
++   the Free Software Foundation; either version 2 of the License, or
++   (at your option) any later version.
++
++   This program is distributed in the hope that it will be useful,
++   but WITHOUT ANY WARRANTY; without even the implied warranty of
++   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++   GNU General Public License for more details.
++
++   You should have received a copy of the GNU General Public License
++   along with this program; if not, write to the Free Software
++   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++======================================================================*/
++
++#include <linux/module.h>
++#include <linux/types.h>
++#include <linux/kernel.h>
++#include <linux/slab.h>
++#include <linux/ioport.h>
++#include <linux/init.h>
++#include <linux/string.h>
++
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/map.h>
++#include <linux/mtd/partitions.h>
++
++#include <asm/hardware.h>
++#include <asm/io.h>
++#include <asm/system.h>
++#include <asm/arch/sl2312.h>
++#include <linux/mtd/kvctl.h>
++#include "sl2312_flashmap.h"
++
++
++//extern int parse_afs_partitions(struct mtd_info *, struct mtd_partition **);
++
++/* the base address of FLASH control register */
++#define FLASH_CONTROL_BASE_ADDR           (IO_ADDRESS(SL2312_FLASH_CTRL_BASE))
++#define SL2312_GLOBAL_BASE_ADDR     (IO_ADDRESS(SL2312_GLOBAL_BASE))
++
++/* define read/write register utility */
++#define FLASH_READ_REG(offset)                        (__raw_readl(offset+FLASH_CONTROL_BASE_ADDR))
++#define FLASH_WRITE_REG(offset,val)   (__raw_writel(val,offset+FLASH_CONTROL_BASE_ADDR))
++
++/* the offset of FLASH control register */
++enum EMAC_REGISTER {
++      FLASH_ID        = 0x0000,
++      FLASH_STATUS    = 0x0008,
++      FLASH_TYPE      = 0x000c,
++      FLASH_ACCESS    = 0x0020,
++      FLASH_ADDRESS   = 0x0024,
++      FLASH_DATA              = 0x0028,
++      FLASH_TIMING    = 0x002c,
++};
++
++//#define FLASH_BASE  FLASH_CONTROL_BASE_ADDR
++//#define FLASH_SIZE  0x00800000 //INTEGRATOR_FLASH_SIZE
++
++//#define FLASH_PART_SIZE 8388608
++
++static unsigned int flash_indirect_access = 0;
++
++#ifdef CONFIG_SL2312_SHARE_PIN
++static unsigned int chip_en = 0x00000000;
++
++void sl2312flash_enable_parallel_flash(void)
++{
++    unsigned int    reg_val;
++
++    reg_val = readl(SL2312_GLOBAL_BASE_ADDR + 0x30);
++    reg_val = reg_val & 0xfffffffd;
++    writel(reg_val,SL2312_GLOBAL_BASE_ADDR + 0x30);
++    return;
++}
++
++void sl2312flash_disable_parallel_flash(void)
++{
++    unsigned int    reg_val;
++
++    reg_val = readl(SL2312_GLOBAL_BASE_ADDR + 0x30);
++    reg_val = reg_val | 0x00000002;
++    writel(reg_val,SL2312_GLOBAL_BASE_ADDR + 0x30);
++    return;
++}
++#endif
++
++
++static struct map_info sl2312flash_map =
++{
++      name:           "SL2312 CFI Flash",
++      size:       FLASH_SIZE,
++      bankwidth:   2,
++      //bankwidth:   1, //for 8 bits width
++    phys:       SL2312_FLASH_BASE,
++};
++
++static struct mtd_info *mtd;
++#if 0
++static struct mtd_partition sl2312_partitions[] = {
++      /* boot code */
++      {
++              name: "bootloader",
++              offset: 0x00000000,
++              size: 0x20000,
++//            mask_flags: MTD_WRITEABLE,
++      },
++      /* kernel image */
++      {
++              name: "kerel image",
++              offset: 0x00020000,
++              size: 0x2E0000
++      },
++      /* All else is writable (e.g. JFFS) */
++      {
++              name: "user data",
++              offset: 0x00300000,
++              size: 0x00100000,
++      }
++};
++#endif
++
++
++
++static int __init sl2312flash_init(void)
++{
++      struct mtd_partition *parts;
++      int nr_parts = 0;
++      int ret;
++#ifndef CONFIG_SL2312_SHARE_PIN
++    unsigned int    reg_val;
++#endif
++
++    printk("SL2312 MTD Driver Init.......\n");
++
++#ifndef CONFIG_SL2312_SHARE_PIN
++      /* enable flash */
++    reg_val = readl(SL2312_GLOBAL_BASE_ADDR + 0x30);
++    reg_val = reg_val & 0xfffffffd;
++    writel(reg_val,SL2312_GLOBAL_BASE_ADDR + 0x30);
++#else
++    sl2312flash_enable_parallel_flash();      /* enable Parallel FLASH */
++#endif
++    FLASH_WRITE_REG(FLASH_ACCESS,0x00004000); /* parallel flash direct access mode */
++    ret = FLASH_READ_REG(FLASH_ACCESS);
++    if (ret == 0x00004000)
++    {
++        flash_indirect_access = 0;  /* parallel flash direct access */
++    }
++    else
++    {
++        flash_indirect_access = 1;  /* parallel flash indirect access */
++    }
++
++      /*
++       * Also, the CFI layer automatically works out what size
++       * of chips we have, and does the necessary identification
++       * for us automatically.
++       */
++#ifdef CONFIG_GEMINI_IPI
++      sl2312flash_map.virt = FLASH_VBASE;//(unsigned int *)ioremap(SL2312_FLASH_BASE, FLASH_SIZE);
++#else
++      sl2312flash_map.virt = (unsigned int *)ioremap(SL2312_FLASH_BASE, FLASH_SIZE);
++#endif
++      //printk("sl2312flash_map.virt  = %08x\n",(unsigned int)sl2312flash_map.virt);
++
++//    simple_map_init(&sl2312flash_map);
++
++      mtd = do_map_probe("cfi_probe", &sl2312flash_map);
++      if (!mtd)
++      {
++#ifdef CONFIG_SL2312_SHARE_PIN
++        sl2312flash_disable_parallel_flash();      /* disable Parallel FLASH */
++#endif
++              return -ENXIO;
++      }
++      mtd->owner = THIS_MODULE;
++//    mtd->erase = flash_erase;
++//    mtd->read = flash_read;
++//    mtd->write = flash_write;
++
++    parts = sl2312_partitions;
++      nr_parts = sizeof(sl2312_partitions)/sizeof(*parts);
++      ret = add_mtd_partitions(mtd, parts, nr_parts);
++      /*If we got an error, free all resources.*/
++      if (ret < 0) {
++              del_mtd_partitions(mtd);
++              map_destroy(mtd);
++      }
++#ifdef CONFIG_SL2312_SHARE_PIN
++    sl2312flash_disable_parallel_flash();      /* disable Parallel FLASH */
++#endif
++    printk("SL2312 MTD Driver Init Success ......\n");
++      return ret;
++}
++
++static void __exit sl2312flash_exit(void)
++{
++      if (mtd) {
++              del_mtd_partitions(mtd);
++              map_destroy(mtd);
++      }
++
++      if (sl2312flash_map.virt) {
++          iounmap((void *)sl2312flash_map.virt);
++          sl2312flash_map.virt = 0;
++      }
++}
++
++char chrtohex(char c)
++{
++  char val;
++  if ((c >= '0') && (c <= '9'))
++  {
++    val = c - '0';
++    return val;
++  }
++  else if ((c >= 'a') && (c <= 'f'))
++  {
++    val = 10 + (c - 'a');
++    return val;
++  }
++  else if ((c >= 'A') && (c <= 'F'))
++  {
++    val = 10 + (c - 'A');
++    return val;
++  }
++  printk("<1>Error number\n");
++  return 0;
++}
++
++
++int get_vlaninfo(vlaninfo* vlan)
++{
++      vctl_mheader head;
++      vctl_entry entry;
++      struct mtd_info *mymtd=NULL;
++      int i, j, loc = 0;
++      char *payload=0, *tmp1, *tmp2, tmp3[9];
++      size_t retlen;
++
++      #ifdef CONFIG_SL2312_SHARE_PIN
++      sl2312flash_enable_parallel_flash();
++      #endif
++      for(i=0;i<MAX_MTD_DEVICES;i++)
++      {
++              mymtd=get_mtd_device(NULL,i);
++              //    printk("mymtd->name: %s\n", mymtd->name);
++              if(mymtd && !strcmp(mymtd->name,"VCTL"))
++              {
++                      //      printk("%s\n", mymtd->name);
++                      break;
++              }
++      }
++      if( i >= MAX_MTD_DEVICES)
++      {
++              printk("Can't find version control\n");
++              #ifdef CONFIG_SL2312_SHARE_PIN
++              sl2312flash_disable_parallel_flash();
++              #endif
++              return 0;
++      }
++
++      if (!mymtd | !mymtd->read)
++      {
++              printk("<1>Can't read Version Configuration\n");
++              #ifdef CONFIG_SL2312_SHARE_PIN
++              sl2312flash_disable_parallel_flash();
++              #endif
++              return 0;
++      }
++
++      mymtd->read(mymtd, 0, VCTL_HEAD_SIZE, &retlen, (u_char*)&head);
++      //  printk("entry header: %c%c%c%c\n", head.header[0], head.header[1], head.header[2], head.header[3]);
++      //  printk("entry number: %x\n", head.entry_num);
++      if ( strncmp(head.header, "FLFM", 4) )
++      {
++              printk("VCTL is a erase block\n");
++              #ifdef CONFIG_SL2312_SHARE_PIN
++              sl2312flash_disable_parallel_flash();
++              #endif
++              return 0;
++      }
++      loc += retlen;
++      for (i = 0; i < head.entry_num; i++)
++      {
++              mymtd->read(mymtd, loc, VCTL_ENTRY_LEN, &retlen, (u_char*)&entry);
++              //    printk("type: %x\n", entry.type);
++              //    printk("size: %x\n", entry.size);
++              strncpy(tmp3, entry.header, 4);
++              if (entry.type == VCT_VLAN)
++              {
++                      for (j = 0; j < 6 ; j++)
++                      {
++                              vlan[0].mac[j] = 0;
++                              vlan[1].mac[j] = 0;
++                      }
++                      vlan[0].vlanid = 1;
++                      vlan[1].vlanid = 2;
++                      vlan[0].vlanmap = 0x7F;
++                      vlan[1].vlanmap = 0x80;
++
++                      payload = (char *)kmalloc(entry.size - VCTL_ENTRY_LEN, GFP_KERNEL);
++                      loc += VCTL_ENTRY_LEN;
++                      mymtd->read(mymtd, loc, entry.size - VCTL_ENTRY_LEN, &retlen, payload);
++                      //      printk("%s\n", payload);
++                      tmp1 = strstr(payload, "MAC1:");
++                      tmp2 = strstr(payload, "MAC2:");
++                      if(!tmp1||!tmp2){
++                              kfree(payload);
++                              #ifdef CONFIG_SL2312_SHARE_PIN
++                              sl2312flash_disable_parallel_flash();
++                              #endif
++                              printk("Error VCTL format!!\n");
++                              return 0;
++                      }
++                      tmp1 += 7;
++                      tmp2 += 7;
++
++
++                      for (j = 0; j < 6; j++)
++                      {
++                              vlan[0].mac[j] = chrtohex(tmp1[2*j])*16 + chrtohex(tmp1[(2*j)+1]);
++                              vlan[1].mac[j] = chrtohex(tmp2[2*j])*16 + chrtohex(tmp2[(2*j)+1]);
++                      }
++                      tmp1 = strstr(payload, "ID1:");
++                      tmp2 = strstr(payload, "ID2:");
++                      tmp1 += 4;
++                      tmp2 += 4;
++                      vlan[0].vlanid = tmp1[0] - '0';
++                      vlan[1].vlanid = tmp2[0] - '0';
++                      tmp1 = strstr(payload, "MAP1:");
++                      tmp2 = strstr(payload, "MAP2:");
++                      tmp1 += 7;
++                      tmp2 += 7;
++                      vlan[0].vlanmap = chrtohex(tmp1[0]) * 16 + chrtohex(tmp1[1]);
++                      vlan[1].vlanmap = chrtohex(tmp2[0]) * 16 + chrtohex(tmp2[1]);
++                      //  printk("Vlan1 id:%x map:%02x mac:%x%x%x%x%x%x\n", vlan[0].vlanid, vlan[0].vlanmap, vlan[0].mac[0], vlan[0].mac[1], vlan[0].mac[2], vlan[0].mac[3], vlan[0].mac[4], vlan[0].mac[5]);
++                      //  printk("Vlan2 id:%x map:%02x mac:%x%x%x%x%x%x\n", vlan[1].vlanid, vlan[1].vlanmap, vlan[1].mac[0], vlan[1].mac[1], vlan[1].mac[2], vlan[1].mac[3], vlan[1].mac[4], vlan[1].mac[5]);
++                      break;
++              }
++              loc += entry.size;
++      }
++      if ( entry.type == VCT_VLAN )
++      {
++              #ifdef CONFIG_SL2312_SHARE_PIN
++              sl2312flash_disable_parallel_flash();
++              #endif
++              kfree(payload);
++              return 1;
++      }
++      if (i >= head.entry_num)
++      printk("Can't find vlan information\n");
++      #ifdef CONFIG_SL2312_SHARE_PIN
++      sl2312flash_disable_parallel_flash();
++      #endif
++      return 0;
++}
++
++EXPORT_SYMBOL(get_vlaninfo);
++
++
++module_init(sl2312flash_init);
++module_exit(sl2312flash_exit);
++
++MODULE_AUTHOR("Storlink Ltd");
++MODULE_DESCRIPTION("CFI map driver");
++MODULE_LICENSE("GPL");
+Index: linux-2.6.23.16/drivers/mtd/maps/sl2312-flash-m25p80.c
+===================================================================
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.23.16/drivers/mtd/maps/sl2312-flash-m25p80.c     2008-03-15 17:04:15.378098557 +0200
+@@ -0,0 +1,498 @@
++/*
++ * $Id: sl2312-flash-m25p80.c,v 1.2 2006/06/02 08:46:02 middle Exp $
++ *
++ * Flash and EPROM on Hitachi Solution Engine and similar boards.
++ *
++ * (C) 2001 Red Hat, Inc.
++ *
++ * GPL'd
++ */
++
++#include <linux/module.h>
++#include <linux/types.h>
++#include <linux/kernel.h>
++
++#include <asm/io.h>
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/map.h>
++#include <linux/mtd/partitions.h>
++#include <asm/hardware.h>
++
++#include <asm/arch/sl2312.h>
++#include <asm/arch/flash.h>
++#include <linux/init.h> //add
++#define  g_chipen     SERIAL_FLASH_CHIP0_EN   //ST
++
++//static int m25p80_page_program(__u32 address, __u8 data, __u32 schip_en);
++static void m25p80_write_cmd(__u8 cmd, __u32 schip_en);
++extern int parse_redboot_partitions(struct mtd_info *master, struct mtd_partition **pparts);
++
++
++static __u32 read_flash_ctrl_reg(__u32 ofs)
++{
++    __u32 *base;
++
++    base = (__u32 *)IO_ADDRESS((SL2312_FLASH_CTRL_BASE + ofs));
++    return __raw_readl(base);
++}
++
++static void write_flash_ctrl_reg(__u32 ofs,__u32 data)
++{
++    __u32 *base;
++
++    base = (__u32 *)IO_ADDRESS((SL2312_FLASH_CTRL_BASE + ofs));
++    __raw_writel(data, base);
++}
++
++static void m25p80_read(__u32 address, __u8 *data, __u32 schip_en)
++{
++      __u32 opcode,status;
++      __u32 value;
++
++      //opcode = 0x80000000 | FLASH_ACCESS_ACTION_OPCODE_DATA | M25P80_READ;
++      opcode = 0x80000000 | FLASH_ACCESS_ACTION_SHIFT_ADDRESS_DATA | M25P80_READ;
++      write_flash_ctrl_reg(FLASH_ADDRESS_OFFSET, address);
++
++              opcode|=g_chipen;
++
++      write_flash_ctrl_reg(FLASH_ACCESS_OFFSET, opcode);
++      status=read_flash_ctrl_reg(FLASH_ACCESS_OFFSET);
++      while(status&0x80000000)
++      {
++          status=read_flash_ctrl_reg(FLASH_ACCESS_OFFSET);
++          flash_delay();
++          schedule();
++      }
++
++      value=read_flash_ctrl_reg(FLASH_READ_DATA_OFFSET);
++      *data = value & 0xff;
++}
++
++static int m25p80_page_program(__u32 address, __u8 *data, __u32 schip_en)
++{
++      __u32 opcode;
++      __u32  status;
++        __u32 tmp;
++        int res = FLASH_ERR_OK;
++        //volatile FLASH_DATA_T* data_ptr = (volatile FLASH_DATA_T*) data;
++        opcode = 0x80000000 | FLASH_ACCESS_ACTION_OPCODE_DATA | M25P80_READ_STATUS;
++
++                    opcode|=g_chipen;
++
++          write_flash_ctrl_reg(FLASH_ACCESS_OFFSET, opcode);
++          tmp=read_flash_ctrl_reg(FLASH_ACCESS_OFFSET);
++                              while(tmp&0x80000000)
++                              {
++                                  tmp=read_flash_ctrl_reg(FLASH_ACCESS_OFFSET);
++                                  flash_delay();
++                                  schedule();
++                              }
++          //middle delay_ms(130);
++          status = read_flash_ctrl_reg(FLASH_READ_DATA_OFFSET);
++          if((status&0x02)==0x02)
++                {
++                     //middle delay_ms(100);
++               m25p80_write_cmd(M25P80_WRITE_DISABLE, schip_en);
++          }
++
++
++      m25p80_write_cmd(M25P80_WRITE_ENABLE, schip_en);
++      ////middle delay_ms(10);
++      opcode = 0x80000000 | FLASH_ACCESS_ACTION_SHIFT_ADDRESS_DATA | M25P80_PAGE_PROGRAM;
++      write_flash_ctrl_reg(FLASH_ADDRESS_OFFSET, address);
++      write_flash_ctrl_reg(FLASH_WRITE_DATA_OFFSET, *data);
++
++      //status = read_flash_ctrl_reg(FLASH_READ_DATA_OFFSET);
++      //while(status!=data)
++      //{
++      //    status = read_flash_ctrl_reg(FLASH_READ_DATA_OFFSET);
++      //    //middle delay_ms(10);
++      //}
++
++              opcode|=g_chipen;
++
++      write_flash_ctrl_reg(FLASH_ACCESS_OFFSET, opcode);
++      tmp=read_flash_ctrl_reg(FLASH_ACCESS_OFFSET);
++                              while(tmp&0x80000000)
++                              {
++                                  tmp=read_flash_ctrl_reg(FLASH_ACCESS_OFFSET);
++                                  flash_delay();
++                                  schedule();
++                              }
++      //opcode=read_flash_ctrl_reg(FLASH_ACCESS_OFFSET);
++
++      opcode = 0x80000000 | FLASH_ACCESS_ACTION_OPCODE_DATA | M25P80_READ_STATUS;
++
++              opcode|=g_chipen;
++
++
++      write_flash_ctrl_reg(FLASH_ACCESS_OFFSET, opcode);
++      tmp=read_flash_ctrl_reg(FLASH_ACCESS_OFFSET);
++                              while(tmp&0x80000000)
++                              {
++                                  tmp=read_flash_ctrl_reg(FLASH_ACCESS_OFFSET);
++                                  flash_delay();
++                                  schedule();
++                              }
++      status = read_flash_ctrl_reg(FLASH_READ_DATA_OFFSET);
++      //while(status&0xfd)
++      while(status&0x01)
++      {
++                //if((status&0x9c)!=0)
++                //    printf("  m25p80_page_program   Protect Status = %x\n",status);
++                write_flash_ctrl_reg(FLASH_ACCESS_OFFSET, opcode);
++                tmp=read_flash_ctrl_reg(FLASH_ACCESS_OFFSET);
++                              while(tmp&0x80000000)
++                              {
++                                  tmp=read_flash_ctrl_reg(FLASH_ACCESS_OFFSET);
++                                  flash_delay();
++                                  schedule();
++                              }
++          status = read_flash_ctrl_reg(FLASH_READ_DATA_OFFSET);
++          flash_delay();
++          schedule();
++          //middle delay_ms(50);
++      }
++      //printf("status = %x, data = %x\n",status,data);
++      if((status&0x02)==0x02)
++      {
++        //middle delay_ms(100);
++          m25p80_write_cmd(M25P80_WRITE_DISABLE, schip_en);
++      }
++    //};//while (len > 0)
++    return res;
++}
++
++void m25p80_copy_from(struct map_info *map, void *buf, unsigned long ofs, ssize_t len)
++{
++//     __u32 size;
++     __u8  *buffer;
++     __u32 length;//i, j,
++
++      length = len;
++     buffer = (__u8 *)buf;
++     while(len)
++     {
++        m25p80_read(ofs, buffer, g_chipen);
++        buffer++;
++        ofs++;
++        len --;
++     }        ;
++
++}
++
++__u32 m25p80_read32(struct map_info *map, unsigned long ofs)
++{
++
++      return read_flash_ctrl_reg(ofs);
++
++
++}
++
++void m25p80_write32(struct map_info *map, __u32 d, unsigned long ofs)
++{
++
++      write_flash_ctrl_reg(ofs, d);
++
++}
++
++void m25p80_copy_to(struct map_info *map, unsigned long ofs, void *buf, ssize_t len)
++{
++     __u32 size, i, ret;
++
++     while(len > 0)
++     {
++        if(len >= M25P80_PAGE_SIZE)
++                      size = M25P80_PAGE_SIZE;
++              else
++                      size = len;
++
++        for(i=0;i<size;i++)
++          {
++              ret = m25p80_page_program( (ofs+i),  (buf+i),  g_chipen);
++          }
++        buf+=M25P80_PAGE_SIZE;
++        ofs+=M25P80_PAGE_SIZE;
++              len-=M25P80_PAGE_SIZE;
++
++    };
++
++
++}
++
++static struct mtd_info *serial_mtd;
++
++static struct mtd_partition *parsed_parts;
++
++static struct map_info m25p80_map = {
++
++      .name = "SL2312 serial flash m25p80",
++      .size = 1048576, //0x100000,
++              //buswidth: 4,
++      .bankwidth = 4,
++      .phys =          SL2312_FLASH_BASE,
++#ifdef CONFIG_MTD_COMPLEX_MAPPINGS
++      .copy_from = m25p80_copy_from,
++      .read = m25p80_read32,
++      .write = m25p80_write32,
++      .copy_to = m25p80_copy_to
++#endif
++};
++
++
++
++static struct mtd_partition m25p80_partitions[] = {
++
++      /* boot code */
++      { .name = "bootloader", .offset = 0x00000000, .size = 0x20000, },
++      /* kernel image */
++      { .name = "kerel image", .offset = 0x000020000, .size = 0xC0000 },
++      /* All else is writable (e.g. JFFS) */
++      { .name = "user data", .offset = 0x000E0000, .size = 0x00010000, },
++
++
++};
++
++void flash_delay()
++{
++      int i,j;
++      for(i=0;i<0x100;i++)
++              j=i*3+5;
++}
++
++int m25p80_sector_erase(__u32 address, __u32 schip_en)
++{
++      __u32 opcode;
++      __u32  status;
++      __u32 tmp;
++      int res = FLASH_ERR_OK;
++      //printf("\n-->m25p80_sector_erase");
++      if(address >= FLASH_START)
++              address-=FLASH_START;
++
++      m25p80_write_cmd(M25P80_WRITE_ENABLE, schip_en);
++      //printf("\n     m25p80_sector_erase : after we-en");
++      opcode = 0x80000000 | FLASH_ACCESS_ACTION_SHIFT_ADDRESS | M25P80_SECTOR_ERASE;
++      write_flash_ctrl_reg(FLASH_ADDRESS_OFFSET, address);
++      #ifdef MIDWAY_DIAG
++              opcode|=schip_en;
++      #endif
++      write_flash_ctrl_reg(FLASH_ACCESS_OFFSET, opcode);
++      tmp=read_flash_ctrl_reg(FLASH_ACCESS_OFFSET);
++                              while(tmp&0x80000000)
++                              {
++                                  tmp=read_flash_ctrl_reg(FLASH_ACCESS_OFFSET);
++                                  flash_delay();
++                                  schedule();
++                              }
++
++      opcode = 0x80000000 | FLASH_ACCESS_ACTION_OPCODE_DATA | M25P80_READ_STATUS;
++      #ifdef MIDWAY_DIAG
++              opcode|=schip_en;
++      #endif
++
++      write_flash_ctrl_reg(FLASH_ACCESS_OFFSET, opcode);
++      tmp=read_flash_ctrl_reg(FLASH_ACCESS_OFFSET);
++                              while(tmp&0x80000000)
++                              {
++                                  tmp=read_flash_ctrl_reg(FLASH_ACCESS_OFFSET);
++                                  flash_delay();
++                                  schedule();
++                              }
++      status = read_flash_ctrl_reg(FLASH_READ_DATA_OFFSET);
++      //while(status&0xfd)
++      while(status&0x01)
++      {
++                //if((status&0x9c)!=0)
++                //    printf("  m25p80_sector_erase   Protect Status = %x\n",status);
++                write_flash_ctrl_reg(FLASH_ACCESS_OFFSET, opcode);
++                tmp=read_flash_ctrl_reg(FLASH_ACCESS_OFFSET);
++                              while(tmp&0x80000000)
++                              {
++                                  tmp=read_flash_ctrl_reg(FLASH_ACCESS_OFFSET);
++                                  flash_delay();
++                                  schedule();
++                              }
++          status = read_flash_ctrl_reg(FLASH_READ_DATA_OFFSET);
++          flash_delay();
++          schedule();
++          //middle delay_ms(50);
++      }
++      if((status&0x02)==0x02)
++      {
++                //middle delay_ms(100);
++          m25p80_write_cmd(M25P80_WRITE_DISABLE, schip_en);
++      }
++      //printf("\n<--m25p80_sector_erase");
++      return res;
++}
++
++static void m25p80_write_cmd(__u8 cmd, __u32 schip_en)
++{
++      __u32 opcode,tmp;
++      __u32  status;
++
++
++
++
++      opcode = 0x80000000 | FLASH_ACCESS_ACTION_OPCODE | cmd;
++
++              opcode|=g_chipen;
++
++      write_flash_ctrl_reg(FLASH_ACCESS_OFFSET, opcode);
++      tmp=read_flash_ctrl_reg(FLASH_ACCESS_OFFSET);
++      while(tmp&0x80000000)
++      {
++          tmp=read_flash_ctrl_reg(FLASH_ACCESS_OFFSET);
++          flash_delay();
++          schedule();
++      }
++      //////
++      opcode = 0x80000000 | FLASH_ACCESS_ACTION_OPCODE_DATA | M25P80_READ_STATUS;
++
++              opcode|=g_chipen;
++
++      write_flash_ctrl_reg(FLASH_ACCESS_OFFSET, opcode);
++      tmp=read_flash_ctrl_reg(FLASH_ACCESS_OFFSET);
++      while(tmp&0x80000000)
++      {
++          tmp=read_flash_ctrl_reg(FLASH_ACCESS_OFFSET);
++          flash_delay();
++          schedule();
++      }
++      //middle delay_ms(130);
++      status = read_flash_ctrl_reg(FLASH_READ_DATA_OFFSET);
++      //printf("\ncmd =%x  status = %x",cmd,status);
++      if(cmd==M25P80_WRITE_ENABLE)
++      {
++              //printf("\n**-->enable**  status = %x",status);
++              //middle delay_ms(100);
++                 while((status&0x03) != 2)
++                 {
++                      //if((status&0x9c)!=0)
++                      //    printf("  M25P80_WRITE_ENABLE   Protect Status = %x\n",status);
++
++                        write_flash_ctrl_reg(FLASH_ACCESS_OFFSET, opcode);
++                        tmp=read_flash_ctrl_reg(FLASH_ACCESS_OFFSET);
++                              while(tmp&0x80000000)
++                              {
++                                  tmp=read_flash_ctrl_reg(FLASH_ACCESS_OFFSET);
++                                  //flash_delay();
++                              }
++                     status = read_flash_ctrl_reg(FLASH_READ_DATA_OFFSET);
++                     //printf("\n**enable**  status = %x",status);
++                     flash_delay();
++                     schedule();
++                     //middle delay_ms(100);
++                 }
++      }
++      else if(cmd==M25P80_WRITE_DISABLE)
++      {
++                 //while((status&0x03) == 2)
++                 //   printf("\n**disable**  status = %x",status);
++                 //middle delay_ms(100);
++                 while((status&0x03) != 0)
++                 {
++             //m25p80_write_status((status&0xfd),schip_en);
++                     write_flash_ctrl_reg(FLASH_ACCESS_OFFSET, opcode);
++                     tmp=read_flash_ctrl_reg(FLASH_ACCESS_OFFSET);
++                      while(tmp&0x80000000)
++                      {
++                          tmp=read_flash_ctrl_reg(FLASH_ACCESS_OFFSET);
++                          flash_delay();
++                          schedule();
++                      }
++                     status = read_flash_ctrl_reg(FLASH_READ_DATA_OFFSET);
++                     //printf("\n**disable**  status = %x",status);
++                     flash_delay();
++                     schedule();
++                     //middle delay_ms(50);
++                 }
++      }
++      else
++      {
++                 //while((status&0x01) !=0)
++                 while((status&0x01) !=0)
++                 {
++                        write_flash_ctrl_reg(FLASH_ACCESS_OFFSET, opcode);
++                        tmp=read_flash_ctrl_reg(FLASH_ACCESS_OFFSET);
++                              while(tmp&0x80000000)
++                              {
++                                  tmp=read_flash_ctrl_reg(FLASH_ACCESS_OFFSET);
++                                  flash_delay();
++                                  schedule();
++                              }
++                     status = read_flash_ctrl_reg(FLASH_READ_DATA_OFFSET);
++                     flash_delay();
++                     schedule();
++                     //middle delay_ms(50);
++                 }
++      }
++      //////
++
++      //printf("\n<--  status = %x",status);
++}
++
++static int __init init_sl2312_m25p80(void)
++{
++      int nr_parts = 0;
++      struct mtd_partition *parts;
++
++      serial_mtd = kmalloc(sizeof(struct mtd_info), GFP_KERNEL);
++      if (!serial_mtd)
++              return NULL;
++
++      memset(serial_mtd, 0, sizeof(struct mtd_info));
++      m25p80_map.virt = (unsigned long)ioremap(SL2312_FLASH_BASE, SFLASH_SIZE);//(unsigned long)ioremap(FLASH_START, SFLASH_SIZE);
++    if (!m25p80_map.virt) {
++              printk(" failed to ioremap \n");
++              return -EIO;
++      }
++      serial_mtd = do_map_probe("map_serial", &m25p80_map);
++      if (serial_mtd) {
++              serial_mtd->owner = THIS_MODULE;
++
++      }
++
++#ifdef CONFIG_MTD_REDBOOT_PARTS
++      nr_parts = parse_redboot_partitions(serial_mtd, &parsed_parts);
++      if (nr_parts > 0)
++              printk(KERN_NOTICE "Found RedBoot partition table.\n");
++      else if (nr_parts < 0)
++              printk(KERN_NOTICE "Error looking for RedBoot partitions.\n");
++#else
++      parsed_parts = m25p80_partitions;
++      parts = m25p80_partitions;
++      nr_parts = sizeof(m25p80_partitions)/sizeof(*parts);
++      nr_parts = sizeof(m25p80_partitions)/sizeof(*parsed_parts);
++#endif /* CONFIG_MTD_REDBOOT_PARTS */
++
++      if (nr_parts > 0)
++          add_mtd_partitions(serial_mtd, parsed_parts, nr_parts);
++      else
++          add_mtd_device(serial_mtd);
++
++      return 0;
++}
++
++static void __exit cleanup_sl2312_m25p80(void)
++{
++      if (parsed_parts)
++          del_mtd_partitions(serial_mtd);
++      else
++          del_mtd_device(serial_mtd);
++
++      map_destroy(serial_mtd);
++
++
++}
++
++module_init(init_sl2312_m25p80);
++module_exit(cleanup_sl2312_m25p80);
++
++
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Plus Chen <plus@storlink.com.tw>");
++MODULE_DESCRIPTION("MTD map driver for Storlink Sword boards");
++
+Index: linux-2.6.23.16/drivers/mtd/maps/sl2312_flashmap.h
+===================================================================
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.23.16/drivers/mtd/maps/sl2312_flashmap.h 2008-03-15 17:03:17.874821522 +0200
+@@ -0,0 +1,21 @@
++/*
++ * Please note that the name are used in mkflash script. Therefore
++ * don't change them.  If you want to add different partitions, you
++ * will need to modify mkflash script as well so that the end image
++ * is what you include here!
++ *
++ * Also, the 7th item is always the size, so please don't add extra
++ * spaces in the name or other items.
++ *
++ *  - Alan
++ */
++
++static struct mtd_partition sl2312_partitions[] = {
++      { name: "RedBoot",       offset: 0x00000000, size: 0x00020000, },
++      { name: "Kernel",        offset: 0x00020000, size: 0x00100000, },
++      { name: "Ramdisk",       offset: 0x00120000, size: 0x00500000, },
++      { name: "etc",           offset: 0x00620000, size: 0x001A0000, },
++      { name: "VCTL",          offset: 0x007C0000, size: 0x00010000, },
++      { name: "cfg",           offset: 0x007D0000, size: 0x00020000, },
++      { name: "FIS directory", offset: 0x007F0000, size: 0x00010000, }
++};
+Index: linux-2.6.23.16/drivers/mtd/maps/sl2312_flashmap.h.16MB
+===================================================================
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.23.16/drivers/mtd/maps/sl2312_flashmap.h.16MB    2008-03-15 17:03:17.874821522 +0200
+@@ -0,0 +1,21 @@
++/*
++ * Please note that the name are used in mkflash script. Therefore
++ * don't change them.  If you want to add different partitions, you
++ * will need to modify mkflash script as well so that the end image
++ * is what you include here!
++ *
++ * Also, the 7th item is always the size, so please don't add extra
++ * spaces in the name or other items.
++ *
++ *  - Alan
++ */
++
++static struct mtd_partition sl2312_partitions[] = {
++      { name: "RedBoot",       offset: 0x00000000, size: 0x00020000, },
++      { name: "Kernel",        offset: 0x00020000, size: 0x00300000, },
++      { name: "Ramdisk",       offset: 0x00320000, size: 0x00600000, },
++      { name: "Application",   offset: 0x00920000, size: 0x00600000, },
++      { name: "VCTL",          offset: 0x00F20000, size: 0x00020000, },
++      { name: "CurConf",       offset: 0x00F40000, size: 0x000A0000, },
++      { name: "FIS directory", offset: 0x00FE0000, size: 0x00020000, }
++};
+Index: linux-2.6.23.16/drivers/mtd/maps/sl2312_flashmap.h.8MB
+===================================================================
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.23.16/drivers/mtd/maps/sl2312_flashmap.h.8MB     2008-03-15 17:03:17.874821522 +0200
+@@ -0,0 +1,21 @@
++/*
++ * Please note that the name are used in mkflash script. Therefore
++ * don't change them.  If you want to add different partitions, you
++ * will need to modify mkflash script as well so that the end image
++ * is what you include here!
++ *
++ * Also, the 7th item is always the size, so please don't add extra
++ * spaces in the name or other items.
++ *
++ *  - Alan
++ */
++
++static struct mtd_partition sl2312_partitions[] = {
++      { name: "RedBoot",       offset: 0x00000000, size: 0x00020000, },
++      { name: "Kernel",        offset: 0x00020000, size: 0x00200000, },
++      { name: "Ramdisk",       offset: 0x00220000, size: 0x00280000, },
++      { name: "Application",   offset: 0x004A0000, size: 0x00300000, },
++      { name: "VCTL",          offset: 0x007A0000, size: 0x00020000, },
++      { name: "CurConf",       offset: 0x007C0000, size: 0x00020000, },
++      { name: "FIS directory", offset: 0x007E0000, size: 0x00020000, }
++};
+Index: linux-2.6.23.16/drivers/mtd/mtdchar.c
+===================================================================
+--- linux-2.6.23.16.orig/drivers/mtd/mtdchar.c 2008-03-15 17:03:14.374622039 +0200
++++ linux-2.6.23.16/drivers/mtd/mtdchar.c      2008-03-15 17:03:17.874821522 +0200
+@@ -59,6 +59,77 @@
+       enum mtd_file_modes mode;
+ };
++/***********************************************************************
++/*             Storlink SoC -- flash
++/***********************************************************************/
++#ifdef CONFIG_SL2312_SHARE_PIN
++unsigned int share_pin_flag=0;                // bit0:FLASH, bit1:UART, bit2:EMAC, bit3-4:IDE
++unsigned int check_sleep_flag=0;      // bit0:FLASH, bit1:IDE
++static spinlock_t sl2312_flash_lock = SPIN_LOCK_UNLOCKED;
++EXPORT_SYMBOL(share_pin_flag);
++int dbg=0;
++DECLARE_WAIT_QUEUE_HEAD(wq);
++extern struct wait_queue_head_t *flash_wait;
++unsigned int flash_req=0;
++void mtd_lock()
++{
++      struct task_struct *tsk = current;
++      unsigned int value ;
++      unsigned long flags;
++      flash_req = 1;
++      DECLARE_WAITQUEUE(wait, tsk);
++      add_wait_queue(&wq, &wait);
++      for(;;)
++      {
++              set_task_state(tsk, TASK_INTERRUPTIBLE);
++              spin_lock_irqsave(&sl2312_flash_lock,flags);
++              if((share_pin_flag&0x1E)){//||(check_sleep_flag&0x00000002)) {
++                      spin_unlock_irqrestore(&sl2312_flash_lock, flags);
++                      check_sleep_flag |= 0x00000001;
++                      if(dbg)
++                              printk("mtd yield %x %x\n",share_pin_flag,check_sleep_flag);
++                      wake_up_interruptible(&flash_wait);
++                      schedule();
++              }
++              else {
++                      check_sleep_flag &= ~0x01;
++                      share_pin_flag |= 0x00000001 ;                  // set share pin flag
++                      spin_unlock_irqrestore(&sl2312_flash_lock, flags);
++                      value = readl(IO_ADDRESS((SL2312_GLOBAL_BASE+GLOBAL_MISC_REG)));
++                      value = value & (~PFLASH_SHARE_BIT) ;
++                      writel(value,IO_ADDRESS((SL2312_GLOBAL_BASE+GLOBAL_MISC_REG)));
++                      if(dbg)
++                              printk("mtd Go %x %x\n",share_pin_flag,check_sleep_flag);
++                      tsk->state = TASK_RUNNING;
++                      remove_wait_queue(&wq, &wait);
++                      return ;
++              }
++      }
++}
++
++void mtd_unlock()
++{
++      unsigned int value ;
++      unsigned long flags;
++
++      spin_lock_irqsave(&sl2312_flash_lock,flags);            // Disable IRQ
++      value = readl(IO_ADDRESS((SL2312_GLOBAL_BASE+GLOBAL_MISC_REG)));
++      value = value | PFLASH_SHARE_BIT ;                              // Disable Flash PADs
++      writel(value,IO_ADDRESS((SL2312_GLOBAL_BASE+GLOBAL_MISC_REG)));
++      share_pin_flag &= ~(0x00000001);                        // clear share pin flag
++      check_sleep_flag &= ~0x00000001;
++      spin_unlock_irqrestore(&sl2312_flash_lock, flags);      // Restore IRQ
++      if (check_sleep_flag & 0x00000002)
++      {
++              check_sleep_flag &= ~(0x00000002);
++              wake_up_interruptible(&flash_wait);
++      }
++      DEBUG(MTD_DEBUG_LEVEL0, "Flash Unlock...\n");
++      flash_req = 0;
++}
++#endif
++/***********************************************************************/
++
+ static loff_t mtd_lseek (struct file *file, loff_t offset, int orig)
+ {
+       struct mtd_file_info *mfi = file->private_data;
+@@ -162,13 +233,21 @@
+       int len;
+       char *kbuf;
++#ifdef CONFIG_SL2312_SHARE_PIN
++      mtd_lock();                             // sl2312 share pin lock
++#endif
++
+       DEBUG(MTD_DEBUG_LEVEL0,"MTD_read\n");
+       if (*ppos + count > mtd->size)
+               count = mtd->size - *ppos;
+-      if (!count)
++      if (!count){
++#ifdef CONFIG_SL2312_SHARE_PIN
++      mtd_unlock();                           // sl2312 share pin lock
++#endif
+               return 0;
++      }
+       /* FIXME: Use kiovec in 2.5 to lock down the user's buffers
+          and pass them directly to the MTD functions */
+@@ -178,8 +257,12 @@
+       else
+               kbuf=kmalloc(count, GFP_KERNEL);
+-      if (!kbuf)
++      if (!kbuf) {
++#ifdef CONFIG_SL2312_SHARE_PIN
++      mtd_unlock();                           // sl2312 share pin lock
++#endif
+               return -ENOMEM;
++      }
+       while (count) {
+@@ -224,6 +307,9 @@
+                       *ppos += retlen;
+                       if (copy_to_user(buf, kbuf, retlen)) {
+                               kfree(kbuf);
++#ifdef CONFIG_SL2312_SHARE_PIN
++                              mtd_unlock();                           // sl2312 share pin lock
++#endif
+                               return -EFAULT;
+                       }
+                       else
+@@ -235,13 +321,19 @@
+                               count = 0;
+               }
+               else {
+-                      kfree(kbuf);
++                      kfree(kbuf);
++#ifdef CONFIG_SL2312_SHARE_PIN
++                      mtd_unlock();                           // sl2312 share pin lock
++#endif
+                       return ret;
+               }
+       }
+       kfree(kbuf);
++#ifdef CONFIG_SL2312_SHARE_PIN
++      mtd_unlock();                           // sl2312 share pin lock
++#endif
+       return total_retlen;
+ } /* mtd_read */
+@@ -255,24 +347,40 @@
+       int ret=0;
+       int len;
++#ifdef CONFIG_SL2312_SHARE_PIN
++      mtd_lock();                             // sl2312 share pin lock
++#endif
++
+       DEBUG(MTD_DEBUG_LEVEL0,"MTD_write\n");
+-      if (*ppos == mtd->size)
++      if (*ppos == mtd->size){
++#ifdef CONFIG_SL2312_SHARE_PIN
++      mtd_unlock();                           // sl2312 share pin lock
++#endif
+               return -ENOSPC;
++      }
+       if (*ppos + count > mtd->size)
+               count = mtd->size - *ppos;
+-      if (!count)
++      if (!count){
++#ifdef CONFIG_SL2312_SHARE_PIN
++      mtd_unlock();                           // sl2312 share pin lock
++#endif
+               return 0;
++      }
+       if (count > MAX_KMALLOC_SIZE)
+               kbuf=kmalloc(MAX_KMALLOC_SIZE, GFP_KERNEL);
+       else
+               kbuf=kmalloc(count, GFP_KERNEL);
+-      if (!kbuf)
++      if (!kbuf) {
++#ifdef CONFIG_SL2312_SHARE_PIN
++              mtd_unlock();                           // sl2312 share pin lock
++#endif
+               return -ENOMEM;
++      }
+       while (count) {
+@@ -283,6 +391,9 @@
+               if (copy_from_user(kbuf, buf, len)) {
+                       kfree(kbuf);
++#ifdef CONFIG_SL2312_SHARE_PIN
++                      mtd_unlock();                           // sl2312 share pin lock
++#endif
+                       return -EFAULT;
+               }
+@@ -323,11 +434,17 @@
+               }
+               else {
+                       kfree(kbuf);
++#ifdef CONFIG_SL2312_SHARE_PIN
++                      mtd_unlock();                           // sl2312 share pin lock
++#endif
+                       return ret;
+               }
+       }
+       kfree(kbuf);
++#ifdef CONFIG_SL2312_SHARE_PIN
++      mtd_unlock();                           // sl2312 share pin lock
++#endif
+       return total_retlen;
+ } /* mtd_write */
+@@ -381,36 +498,67 @@
+       u_long size;
+       struct mtd_info_user info;
++#ifdef CONFIG_SL2312_SHARE_PIN
++      mtd_lock();                             // sl2312 share pin lock
++#endif
++
+       DEBUG(MTD_DEBUG_LEVEL0, "MTD_ioctl\n");
+       size = (cmd & IOCSIZE_MASK) >> IOCSIZE_SHIFT;
+       if (cmd & IOC_IN) {
+               if (!access_ok(VERIFY_READ, argp, size))
++              {
++#ifdef CONFIG_SL2312_SHARE_PIN
++                      mtd_unlock();                           // sl2312 share pin lock
++#endif
+                       return -EFAULT;
++              }
+       }
+       if (cmd & IOC_OUT) {
+               if (!access_ok(VERIFY_WRITE, argp, size))
++              {
++#ifdef CONFIG_SL2312_SHARE_PIN
++                      mtd_unlock();                           // sl2312 share pin lock
++#endif
+                       return -EFAULT;
++              }
+       }
+       switch (cmd) {
+       case MEMGETREGIONCOUNT:
+               if (copy_to_user(argp, &(mtd->numeraseregions), sizeof(int)))
++              {
++#ifdef CONFIG_SL2312_SHARE_PIN
++                      mtd_unlock();                           // sl2312 share pin lock
++#endif
+                       return -EFAULT;
++              }
+               break;
+       case MEMGETREGIONINFO:
+       {
+               struct region_info_user ur;
+-              if (copy_from_user(&ur, argp, sizeof(struct region_info_user)))
++              if (copy_from_user(&ur, argp, sizeof(struct region_info_user))) {
++#ifdef CONFIG_SL2312_SHARE_PIN
++                      mtd_unlock();                           // sl2312 share pin lock
++#endif
+                       return -EFAULT;
++              }
+-              if (ur.regionindex >= mtd->numeraseregions)
++              if (ur.regionindex >= mtd->numeraseregions) {
++#ifdef CONFIG_SL2312_SHARE_PIN
++                      mtd_unlock();                           // sl2312 share pin lock
++#endif
+                       return -EINVAL;
++              }
+               if (copy_to_user(argp, &(mtd->eraseregions[ur.regionindex]),
+-                              sizeof(struct mtd_erase_region_info)))
++                              sizeof(struct mtd_erase_region_info))) {
++#ifdef CONFIG_SL2312_SHARE_PIN
++                      mtd_unlock();                           // sl2312 share pin lock
++#endif
+                       return -EFAULT;
++              }
+               break;
+       }
+@@ -433,7 +581,12 @@
+               struct erase_info *erase;
+               if(!(file->f_mode & 2))
++              {
++#ifdef CONFIG_SL2312_SHARE_PIN
++                      mtd_unlock();                           // sl2312 share pin lock
++#endif
+                       return -EPERM;
++              }
+               erase=kzalloc(sizeof(struct erase_info),GFP_KERNEL);
+               if (!erase)
+@@ -447,6 +600,9 @@
+                       if (copy_from_user(&erase->addr, argp,
+                                   sizeof(struct erase_info_user))) {
+                               kfree(erase);
++#ifdef CONFIG_SL2312_SHARE_PIN
++                              mtd_unlock();                           // sl2312 share pin lock
++#endif
+                               return -EFAULT;
+                       }
+                       erase->mtd = mtd;
+@@ -484,14 +640,26 @@
+               struct mtd_oob_buf buf;
+               struct mtd_oob_ops ops;
+-              if(!(file->f_mode & 2))
++              if(!(file->f_mode & 2)) {
++#ifdef CONFIG_SL2312_SHARE_PIN
++                      mtd_unlock();                           // sl2312 share pin lock
++#endif
+                       return -EPERM;
++              }
+-              if (copy_from_user(&buf, argp, sizeof(struct mtd_oob_buf)))
++              if (copy_from_user(&buf, argp, sizeof(struct mtd_oob_buf))) {
++#ifdef CONFIG_SL2312_SHARE_PIN
++                      mtd_unlock();                           // sl2312 share pin lock
++#endif
+                       return -EFAULT;
++              }
+-              if (buf.length > 4096)
++              if (buf.length > 4096) {
++#ifdef CONFIG_SL2312_SHARE_PIN
++                      mtd_unlock();                           // sl2312 share pin lock
++#endif
+                       return -EINVAL;
++              }
+               if (!mtd->write_oob)
+                       ret = -EOPNOTSUPP;
+@@ -499,8 +667,12 @@
+                       ret = access_ok(VERIFY_READ, buf.ptr,
+                                       buf.length) ? 0 : EFAULT;
+-              if (ret)
++              if (ret) {
++#ifdef CONFIG_SL2312_SHARE_PIN
++                      mtd_unlock();                           // sl2312 share pin lock
++#endif
+                       return ret;
++              }
+               ops.ooblen = buf.length;
+               ops.ooboffs = buf.start & (mtd->oobsize - 1);
+@@ -536,19 +708,35 @@
+               struct mtd_oob_buf buf;
+               struct mtd_oob_ops ops;
+-              if (copy_from_user(&buf, argp, sizeof(struct mtd_oob_buf)))
++              if (copy_from_user(&buf, argp, sizeof(struct mtd_oob_buf))) {
++#ifdef CONFIG_SL2312_SHARE_PIN
++                      mtd_unlock();                           // sl2312 share pin lock
++#endif
+                       return -EFAULT;
++              }
+-              if (buf.length > 4096)
++              if (buf.length > 4096) {
++#ifdef CONFIG_SL2312_SHARE_PIN
++                      mtd_unlock();                           // sl2312 share pin lock
++#endif
+                       return -EINVAL;
++              }
+-              if (!mtd->read_oob)
++              if (!mtd->read_oob) {
++#ifdef CONFIG_SL2312_SHARE_PIN
++                      mtd_unlock();                           // sl2312 share pin lock
++#endif
+                       ret = -EOPNOTSUPP;
++              }
+               else
+                       ret = access_ok(VERIFY_WRITE, buf.ptr,
+                                       buf.length) ? 0 : -EFAULT;
+-              if (ret)
++              if (ret) {
++#ifdef CONFIG_SL2312_SHARE_PIN
++                      mtd_unlock();                           // sl2312 share pin lock
++#endif
+                       return ret;
++              }
+               ops.ooblen = buf.length;
+               ops.ooboffs = buf.start & (mtd->oobsize - 1);
+@@ -580,7 +768,12 @@
+               struct erase_info_user info;
+               if (copy_from_user(&info, argp, sizeof(info)))
++              {
++#ifdef CONFIG_SL2312_SHARE_PIN
++                      mtd_unlock();                           // sl2312 share pin lock
++#endif
+                       return -EFAULT;
++              }
+               if (!mtd->lock)
+                       ret = -EOPNOTSUPP;
+@@ -594,7 +787,12 @@
+               struct erase_info_user info;
+               if (copy_from_user(&info, argp, sizeof(info)))
++              {
++#ifdef CONFIG_SL2312_SHARE_PIN
++                      mtd_unlock();                           // sl2312 share pin lock
++#endif
+                       return -EFAULT;
++              }
+               if (!mtd->unlock)
+                       ret = -EOPNOTSUPP;
+@@ -629,11 +827,21 @@
+               loff_t offs;
+               if (copy_from_user(&offs, argp, sizeof(loff_t)))
++              {
++#ifdef CONFIG_SL2312_SHARE_PIN
++                      mtd_unlock();                           // sl2312 share pin lock
++#endif
+                       return -EFAULT;
++              }
+               if (!mtd->block_isbad)
+                       ret = -EOPNOTSUPP;
+               else
++              {
++#ifdef CONFIG_SL2312_SHARE_PIN
++                      mtd_unlock();                           // sl2312 share pin lock
++#endif
+                       return mtd->block_isbad(mtd, offs);
++              }
+               break;
+       }
+@@ -642,11 +850,21 @@
+               loff_t offs;
+               if (copy_from_user(&offs, argp, sizeof(loff_t)))
++              {
++#ifdef CONFIG_SL2312_SHARE_PIN
++                      mtd_unlock();                           // sl2312 share pin lock
++#endif
+                       return -EFAULT;
++              }
+               if (!mtd->block_markbad)
+                       ret = -EOPNOTSUPP;
+               else
++              {
++#ifdef CONFIG_SL2312_SHARE_PIN
++                      mtd_unlock();                           // sl2312 share pin lock
++#endif
+                       return mtd->block_markbad(mtd, offs);
++              }
+               break;
+       }
+@@ -654,8 +872,12 @@
+       case OTPSELECT:
+       {
+               int mode;
+-              if (copy_from_user(&mode, argp, sizeof(int)))
++              if (copy_from_user(&mode, argp, sizeof(int))) {
++#ifdef CONFIG_SL2312_SHARE_PIN
++                      mtd_unlock();                           // sl2312 share pin lock
++#endif
+                       return -EFAULT;
++              }
+               mfi->mode = MTD_MODE_NORMAL;
+@@ -670,7 +892,12 @@
+       {
+               struct otp_info *buf = kmalloc(4096, GFP_KERNEL);
+               if (!buf)
++              {
++#ifdef CONFIG_SL2312_SHARE_PIN
++                      mtd_unlock();                           // sl2312 share pin lock
++#endif
+                       return -ENOMEM;
++              }
+               ret = -EOPNOTSUPP;
+               switch (mfi->mode) {
+               case MTD_MODE_OTP_FACTORY:
+@@ -701,12 +928,24 @@
+       {
+               struct otp_info info;
+-              if (mfi->mode != MTD_MODE_OTP_USER)
++              if (mfi->mode != MTD_MODE_OTP_USER) {
++#ifdef CONFIG_SL2312_SHARE_PIN
++                      mtd_unlock();                           // sl2312 share pin lock
++#endif
+                       return -EINVAL;
+-              if (copy_from_user(&info, argp, sizeof(info)))
++              }
++              if (copy_from_user(&info, argp, sizeof(info))) {
++#ifdef CONFIG_SL2312_SHARE_PIN
++                      mtd_unlock();                           // sl2312 share pin lock
++#endif
+                       return -EFAULT;
+-              if (!mtd->lock_user_prot_reg)
++              }
++              if (!mtd->lock_user_prot_reg) {
++#ifdef CONFIG_SL2312_SHARE_PIN
++                      mtd_unlock();                           // sl2312 share pin lock
++#endif
+                       return -EOPNOTSUPP;
++              }
+               ret = mtd->lock_user_prot_reg(mtd, info.start, info.length);
+               break;
+       }
+@@ -742,8 +981,12 @@
+                       break;
+               case MTD_MODE_RAW:
+-                      if (!mtd->read_oob || !mtd->write_oob)
++                      if (!mtd->read_oob || !mtd->write_oob) {
++#ifdef CONFIG_SL2312_SHARE_PIN
++                              mtd_unlock();                           // sl2312 share pin lock
++#endif
+                               return -EOPNOTSUPP;
++                      }
+                       mfi->mode = arg;
+               case MTD_MODE_NORMAL:
+@@ -766,6 +1009,10 @@
+               ret = -ENOTTY;
+       }
++#ifdef CONFIG_SL2312_SHARE_PIN
++      mtd_unlock();                           // sl2312 share pin lock
++#endif
++
+       return ret;
+ } /* memory_ioctl */
+Index: linux-2.6.23.16/drivers/mtd/nand/Kconfig
+===================================================================
+--- linux-2.6.23.16.orig/drivers/mtd/nand/Kconfig      2008-03-15 17:03:14.374622039 +0200
++++ linux-2.6.23.16/drivers/mtd/nand/Kconfig   2008-03-15 17:03:17.874821522 +0200
+@@ -44,6 +44,13 @@
+         This enables the driver for the autronix autcpu12 board to
+         access the SmartMediaCard.
++config MTD_NAND_SL2312
++      tristate "NAND Flash device on Storlink board"
++      depends on ARM && MTD_NAND && ARCH_SL2312
++      help
++        This enables the driver for the Storlink board to
++        access the nand device.
++
+ config MTD_NAND_EDB7312
+       tristate "Support for Cirrus Logic EBD7312 evaluation board"
+       depends on ARCH_EDB7312
+Index: linux-2.6.23.16/drivers/mtd/nand/sl2312-flash-nand.c
+===================================================================
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.23.16/drivers/mtd/nand/sl2312-flash-nand.c       2008-03-15 17:03:17.874821522 +0200
+@@ -0,0 +1,2287 @@
++/*
++ *  drivers/mtd/sl2312.c
++ *
++ * $Id: sl2312-flash-nand.c,v 1.5 2006/06/15 07:02:29 middle Exp $
++ *
++ * Copyright (C) 2001 Toshiba Corporation
++ *
++ * 2003 (c) MontaVista Software, Inc. This file is licensed under
++ * the terms of the GNU General Public License version 2. This program
++ * is licensed "as is" without any warranty of any kind, whether express
++ * or implied.
++ *
++ */
++
++#include <linux/slab.h>
++#include <linux/init.h>
++#include <linux/module.h>
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/nand.h>
++#include <linux/mtd/nand_ecc.h>
++#include <linux/mtd/partitions.h>
++#include <linux/delay.h>
++#include <asm/io.h>
++#include <asm/hardware.h>
++#include <asm/arch/sl2312.h>
++#include "sl2312-flash-nand.h"
++
++
++#include <linux/errno.h>
++#include <linux/sched.h>
++#include <linux/types.h>
++#include <linux/mtd/compatmac.h>
++#include <linux/interrupt.h>
++#include <linux/bitops.h>
++
++
++/*
++ * NAND low-level MTD interface functions
++ */
++static void sl2312_nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len);
++static void sl2312_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len);
++static int sl2312_nand_verify_buf(struct mtd_info *mtd, const u_char *buf, int len);
++
++static int sl2312_nand_read (struct mtd_info *mtd, loff_t from, size_t len, size_t * retlen, u_char * buf);
++static int sl2312_nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, size_t * retlen, u_char * buf, u_char * eccbuf, struct nand_oobinfo *oobsel);
++static int sl2312_nand_read_oob (struct mtd_info *mtd, loff_t from, size_t len, size_t * retlen, u_char * buf);
++static int sl2312_nand_write (struct mtd_info *mtd, loff_t to, size_t len, size_t * retlen, const u_char * buf);
++static int sl2312_nand_write_ecc (struct mtd_info *mtd, loff_t to, size_t len,
++                         size_t * retlen, const u_char * buf, u_char * eccbuf, struct nand_oobinfo *oobsel);
++static int sl2312_nand_write_oob (struct mtd_info *mtd, loff_t to, size_t len, size_t * retlen, const u_char *buf);
++static int sl2312_nand_writev (struct mtd_info *mtd, const struct kvec *vecs,
++                      unsigned long count, loff_t to, size_t * retlen);
++static int sl2312_nand_writev_ecc (struct mtd_info *mtd, const struct kvec *vecs,
++                      unsigned long count, loff_t to, size_t * retlen, u_char *eccbuf, struct nand_oobinfo *oobsel);
++static int sl2312_nand_erase (struct mtd_info *mtd, struct erase_info *instr, int allowbbt);
++static void sl2312_nand_sync (struct mtd_info *mtd);
++static int sl2312_nand_write_page (struct mtd_info *mtd, struct nand_chip *this, int page, u_char *oob_buf,  struct nand_oobinfo *oobsel);
++static int sl2312_nand_block_checkbad (struct mtd_info *mtd, loff_t ofs, int getchip, int allowbbt);
++static int sl2312_nand_erase_block(struct mtd_info *mtd, int page);
++
++/*
++ * MTD structure for sl2312 NDFMC
++ */
++static struct mtd_info *sl2312_mtd = NULL;
++static int nand_page=0,nand_col=0;
++
++/* Define default oob placement schemes for large and small page devices */
++static struct nand_oobinfo nand_oob_8 = {
++      .useecc = MTD_NANDECC_AUTOPLACE,
++      .eccbytes = 3,
++      .eccpos = {0, 1, 2},
++      .oobfree = { {3, 2}, {6, 2} }
++};
++
++static struct nand_oobinfo nand_oob_16 = {
++      .useecc = MTD_NANDECC_AUTOPLACE,
++      .eccbytes = 6,
++      .eccpos = {0, 1, 2, 3, 6, 7},
++      .oobfree = { {8, 8} }
++};
++
++static struct nand_oobinfo nand_oob_64 = {
++      .useecc = MTD_NANDECC_AUTOPLACE,
++      .eccbytes = 24,
++      .eccpos = {
++              40, 41, 42, 43, 44, 45, 46, 47,
++              48, 49, 50, 51, 52, 53, 54, 55,
++              56, 57, 58, 59, 60, 61, 62, 63},
++      .oobfree = { {2, 38} }
++};
++
++
++/*
++ * Define partitions for flash device
++ */
++/* the base address of FLASH control register */
++#define FLASH_CONTROL_BASE_ADDR           (IO_ADDRESS(SL2312_FLASH_CTRL_BASE))
++#define SL2312_GLOBAL_BASE_ADDR     (IO_ADDRESS(SL2312_GLOBAL_BASE))
++//#define SL2312_FLASH_BASE_ADDR      (IO_ADDRESS(SL2312_FLASH_BASE))
++#define SL2312_FLASH_BASE_ADDR       FLASH_VADDR(SL2312_FLASH_BASE)
++static unsigned int CHIP_EN;
++/* define read/write register utility */
++//#define FLASH_READ_REG(offset)                      (__raw_readl(offset+FLASH_CONTROL_BASE_ADDR))
++//#define FLASH_WRITE_REG(offset,val)         (__raw_writel(val,offset+FLASH_CONTROL_BASE_ADDR))
++//#define FLASH_READ_DATA(offset)                     (__raw_readb(offset+SL2312_FLASH_BASE_ADDR))
++//#define FLASH_WRITE_DATA(offset,val)        (__raw_writeb(val,offset+SL2312_FLASH_BASE_ADDR))
++
++unsigned int FLASH_READ_REG(unsigned int addr)
++{
++    unsigned int *base;
++    unsigned int data;
++
++    base = (unsigned int *)(FLASH_CONTROL_BASE_ADDR + addr);
++    data = *base;
++    return (data);
++}
++
++void FLASH_WRITE_REG(unsigned int addr,unsigned int data)
++{
++    unsigned int *base;
++
++    base = (unsigned int *)(FLASH_CONTROL_BASE_ADDR + addr);
++    *base = data;
++    return;
++}
++
++unsigned int FLASH_READ_DATA(unsigned int addr)
++{
++    unsigned char *base;
++    unsigned int data;
++
++    base = (unsigned char *)(SL2312_FLASH_BASE_ADDR + addr);
++    data = *base;
++    return (data);
++}
++
++void FLASH_WRITE_DATA(unsigned int addr,unsigned int data)
++{
++    unsigned char *base;
++
++    base = (unsigned char *)(SL2312_FLASH_BASE_ADDR + addr);
++    *base = data;
++    return;
++}
++
++/* the offset of FLASH control register */
++enum NFLASH_REGISTER {
++      NFLASH_ID                       = 0x0000,
++      NFLASH_STATUS                   = 0x0008,
++      NFLASH_TYPE                     = 0x000c,
++      NFLASH_ACCESS                   = 0x0030,
++      NFLASH_COUNT                    = 0x0034,
++      NFLASH_CMD_ADDR                 = 0x0038,
++      NFLASH_ADDRESS                  = 0x003C,
++      NFLASH_DATA                             = 0x0040,
++      NFLASH_TIMING                   = 0x004C,
++      NFLASH_ECC_STATUS               = 0x0050,
++      NFLASH_ECC_CONTROL              = 0x0054,
++      NFLASH_ECC_OOB                  = 0x005c,
++      NFLASH_ECC_CODE_GEN0    = 0x0060,
++      NFLASH_ECC_CODE_GEN1    = 0x0064,
++      NFLASH_ECC_CODE_GEN2    = 0x0068,
++      NFLASH_ECC_CODE_GEN3    = 0x006C,
++      NFLASH_FIFO_CONTROL             = 0x0070,
++      NFLASH_FIFO_STATUS              = 0x0074,
++      NFLASH_FIFO_ADDRESS             = 0x0078,
++      NFLASH_FIFO_DATA                = 0x007c,
++};
++
++
++
++//#define FLASH_BASE  FLASH_CONTROL_BASE_ADDR
++//#define FLASH_SIZE  0x00800000 //INTEGRATOR_FLASH_SIZE
++
++//#define FLASH_PART_SIZE 8388608
++
++//static unsigned int flash_indirect_access = 0;
++
++
++#ifdef CONFIG_SL2312_SHARE_PIN
++void sl2312flash_enable_nand_flash(void)
++{
++    unsigned int    reg_val;
++
++    reg_val = readl(SL2312_GLOBAL_BASE_ADDR + 0x30);
++    reg_val = reg_val & 0xfffffffb;
++    writel(reg_val,SL2312_GLOBAL_BASE_ADDR + 0x30);
++    return;
++}
++
++void sl2312flash_disable_nand_flash(void)
++{
++    unsigned int    reg_val;
++
++    reg_val = readl(SL2312_GLOBAL_BASE_ADDR + 0x30);
++    reg_val = reg_val | 0x00000004;
++    writel(reg_val,SL2312_GLOBAL_BASE_ADDR + 0x30);
++    return;
++}
++#endif
++
++extern struct nand_oobinfo jffs2_oobinfo;
++/*
++ * Define partitions for flash devices
++ */
++
++static struct mtd_partition sl2312_partitions[] = {
++      { name: "RedBoot", offset: 0x00000000, size: 0x0020000, },
++      { name: "Kernel", offset: 0x00020000, size: 0x00200000, },
++      { name: "Ramdisk", offset: 0x00220000, size: 0x00280000, },
++      { name: "Application", offset: 0x004A0000, size: 0x00320000, },
++      { name: "VCTL", offset: 0x007C0000, size: 0x20000, },
++      { name: "CurConf", offset: 0x007E0000, size: 0x20000, },
++      { name: "FIS directory", offset: 0x007e0000, size: 0x00020000, }
++
++};
++
++
++/*
++ *    hardware specific access to control-lines
++*/
++static void sl2312_hwcontrol(struct mtd_info *mtd, int cmd)
++{
++
++      return ;
++}
++
++static int sl2312_nand_scan_bbt(struct mtd_info *mtd)
++{
++      return 0;
++}
++
++/**
++ * nand_block_isbad - [MTD Interface] Check whether the block at the given offset is bad
++ * @mtd:      MTD device structure
++ * @ofs:      offset relative to mtd start
++ */
++static int sl2312_nand_block_isbad (struct mtd_info *mtd, loff_t ofs)
++{
++      /* Check for invalid offset */
++      if (ofs > mtd->size)
++              return -EINVAL;
++
++      return sl2312_nand_block_checkbad (mtd, ofs, 1, 0);
++}
++
++/**
++ * nand_block_checkbad - [GENERIC] Check if a block is marked bad
++ * @mtd:      MTD device structure
++ * @ofs:      offset from device start
++ * @getchip:  0, if the chip is already selected
++ * @allowbbt: 1, if its allowed to access the bbt area
++ *
++ * Check, if the block is bad. Either by reading the bad block table or
++ * calling of the scan function.
++ */
++
++static int sl2312_nand_erase_block(struct mtd_info *mtd, int page)
++{
++      int opcode;
++      /* Send commands to erase a page */
++              FLASH_WRITE_REG(NFLASH_ECC_CONTROL, 0x00000000); //set 31b = 0
++
++              if(mtd->oobblock > 528)
++                  FLASH_WRITE_REG(NFLASH_COUNT, 0x7f0fff21);  // 3 address & 2 command
++              else
++                  FLASH_WRITE_REG(NFLASH_COUNT, 0x7f0fff11);  // 2 address & 2 command
++
++              FLASH_WRITE_REG(NFLASH_CMD_ADDR, 0x0000d060); // write read id command
++              FLASH_WRITE_REG(NFLASH_ADDRESS, page); //write address 0x00
++
++
++
++              /* read maker code */
++              opcode = 0x80003000|DWIDTH|CHIP_EN; //set start bit & 8bits write command
++              FLASH_WRITE_REG(NFLASH_ACCESS, opcode);
++
++              while(opcode&0x80000000) //polling flash access 31b
++              {
++           opcode=FLASH_READ_REG(NFLASH_ACCESS);
++           //sl2312_flash_delay();
++           schedule();
++           //cond_resched();
++              }
++}
++
++void sl2312_flash_delay(void)
++{
++      int i;
++
++      for(i=0; i<50; i++)
++           i=i;
++}
++
++static int sl2312_nand_block_checkbad (struct mtd_info *mtd, loff_t ofs, int getchip, int allowbbt)
++{
++      struct nand_chip *this = mtd->priv;
++
++      if (!this->bbt)
++              return this->block_bad(mtd, ofs, getchip);
++
++      /* Return info from the table */
++      return nand_isbad_bbt (mtd, ofs, allowbbt);
++}
++
++/**
++ * nand_block_markbad - [MTD Interface] Mark the block at the given offset as bad
++ * @mtd:      MTD device structure
++ * @ofs:      offset relative to mtd start
++ */
++static int sl2312_nand_block_markbad (struct mtd_info *mtd, loff_t ofs)
++{
++      struct nand_chip *this = mtd->priv;
++      int ret;
++
++        if ((ret = sl2312_nand_block_isbad(mtd, ofs))) {
++              /* If it was bad already, return success and do nothing. */
++              if (ret > 0)
++                      return 0;
++              return ret;
++        }
++
++      return this->block_markbad(mtd, ofs);
++}
++
++/*
++ *    Get chip for selected access
++ */
++static inline void sl2312_nand_get_chip (struct nand_chip *this, struct mtd_info *mtd, int new_state, int *erase_state)
++{
++
++      DECLARE_WAITQUEUE (wait, current);
++
++      /*
++       * Grab the lock and see if the device is available
++       * For erasing, we keep the spinlock until the
++       * erase command is written.
++      */
++retry:
++      spin_lock_bh (&this->chip_lock);
++
++      if (this->state == FL_READY) {
++              this->state = new_state;
++              if (new_state != FL_ERASING)
++                      spin_unlock_bh (&this->chip_lock);
++              return;
++      }
++
++      if (this->state == FL_ERASING) {
++              if (new_state != FL_ERASING) {
++                      this->state = new_state;
++                      spin_unlock_bh (&this->chip_lock);
++                      this->select_chip(mtd, 0);      /* select in any case */
++                      this->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
++                      return;
++              }
++      }
++
++      set_current_state (TASK_UNINTERRUPTIBLE);
++      add_wait_queue (&this->wq, &wait);
++      spin_unlock_bh (&this->chip_lock);
++      schedule ();
++      remove_wait_queue (&this->wq, &wait);
++      goto retry;
++}
++
++/*
++*     read device ready pin
++*/
++static int sl2312_device_ready(struct mtd_info *mtd)
++{
++      int ready;
++
++      FLASH_WRITE_REG(NFLASH_ECC_CONTROL, 0x00000000); //set 31b = 0
++      FLASH_WRITE_REG(NFLASH_COUNT, 0x7f000070); //set only command no address and two data
++
++      FLASH_WRITE_REG(NFLASH_CMD_ADDR, 0x00000070); //write read status command
++
++
++      ready = 0x80002000|DWIDTH|CHIP_EN; //set start bit & 8bits read command
++      FLASH_WRITE_REG(NFLASH_ACCESS, ready);
++
++      while(ready&0x80000000) //polling flash access 31b
++    {
++        ready=FLASH_READ_REG(NFLASH_ACCESS);
++        //sl2312_flash_delay();
++              schedule();
++    }
++    FLASH_WRITE_REG(NFLASH_ACCESS, NFLASH_DIRECT);
++              ready=FLASH_READ_REG(NFLASH_DATA)&0xff;
++      return ready;
++}
++void sl2312_enable_hwecc(struct mtd_info *mtd, int mode)
++{
++      /* reset first */
++      FLASH_WRITE_REG(NFLASH_ECC_CONTROL, 0x80000001); //set 31b = 0
++
++}
++
++
++void sl2312_device_setup(void)
++{
++
++}
++static u_char sl2312_nand_read_byte(struct mtd_info *mtd)
++{
++
++        unsigned int    data=0, page=0, col=0, tmp, i;
++
++        printk ("**************************sl2312_nand_read_byte !! \n");
++        //page = FLASH_READ_REG(NFLASH_ADDRESS)&0xffffff00;
++        //col  = FLASH_READ_REG(NFLASH_ADDRESS)&0x000000ff;
++        page = nand_page;
++        col  = nand_col;
++        for(i=0;i<(mtd->oobblock+mtd->oobsize);i++)
++        {
++              if(i==col)
++                              data = FLASH_READ_DATA(page*mtd->oobblock +i);
++                      else
++                              tmp = FLASH_READ_DATA(page*mtd->oobblock +i);
++        }
++        return data&0xff;
++}
++
++static void sl2312_nand_write_byte(struct mtd_info *mtd, u_char byte)
++{
++        //struct nand_chip *this = mtd->priv;
++        unsigned int    page=0, col=0, i;
++        u_char *databuf,oobbuf[mtd->oobsize];
++        size_t  retlen;
++        retlen=0;
++              printk ("********************sl2312_nand_write_byte !! \n");
++              page = nand_page;
++        col  = nand_col;
++              databuf = kmalloc (mtd->oobsize+mtd->oobblock,GFP_KERNEL);
++
++              if (!databuf) {
++                      printk ("sl2312_nand_write_byte : Unable to allocate SL2312 NAND MTD device structure.\n");
++
++              }
++
++               for(i=0;i<(mtd->oobblock+mtd->oobsize);i++)
++              databuf[i] = FLASH_READ_DATA(page*mtd->oobblock +i);
++
++        databuf[col] = byte;
++        sl2312_nand_write_ecc (mtd, page, mtd->oobblock, &retlen, databuf, oobbuf, NULL);
++
++}
++
++static void sl2312_nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
++{
++      int i, page=0,col=0;
++      struct nand_chip *this = mtd->priv;
++      u_char *databuf, *oobbuf;
++        size_t  retlen;
++        retlen=0;
++
++
++              printk ("***********************sl2312_nand_write_buf !! \n");
++              databuf = &(this->data_buf[0]);
++              oobbuf = &(this->data_buf[mtd->oobblock]);
++              for (i = 0; i < mtd->oobsize; i++)
++                      oobbuf[i] = 0xff;
++
++      if(len < mtd->oobblock)
++      {
++              //addr = FLASH_READ_REG(NFLASH_ADDRESS);
++              //page = FLASH_READ_REG(NFLASH_ADDRESS)&0xffffff00;
++              //col  = FLASH_READ_REG(NFLASH_ADDRESS)&0x000000ff;
++              page = nand_page;
++        col  = nand_col;
++
++              sl2312_nand_read_ecc (mtd, page, mtd->oobblock , &retlen, databuf, oobbuf, NULL);
++
++        for(i=col;i<len;i++)
++              databuf[col+i] = buf[i];
++
++        sl2312_nand_write_ecc (mtd, page, mtd->oobblock, &retlen, databuf, oobbuf, NULL);
++
++      }
++
++}
++
++static void sl2312_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
++{
++      int i, page=0,col=0,addr=0,tmp=0;
++      //struct nand_chip *this = mtd->priv;
++      printk ("********************sl2312_nand_read_buf !! \n");
++      if(len < mtd->oobblock)
++      {
++              //addr = FLASH_READ_REG(NFLASH_ADDRESS);
++              //page = FLASH_READ_REG(NFLASH_ADDRESS)&0xffffff00;
++              //col  = FLASH_READ_REG(NFLASH_ADDRESS)&0x000000ff;
++              page = nand_page;
++        col  = nand_col;
++              for (i=col; i<((mtd->oobblock+mtd->oobsize)-col); i++)
++              {
++                      if(i<len)
++                              buf[i] = FLASH_READ_DATA(addr+i);
++                      else
++                              tmp = FLASH_READ_DATA(addr+i);
++              }
++      }
++}
++
++static int sl2312_nand_verify_buf(struct mtd_info *mtd, const u_char *buf, int len)
++{
++      int i;
++      //struct nand_chip *this = mtd->priv;
++      u_char *datatmp, *oobtmp;
++      size_t  retlen;
++      retlen=0;
++
++      datatmp = kmalloc (mtd->oobblock,GFP_KERNEL);
++      oobtmp = kmalloc (mtd->oobsize,GFP_KERNEL);
++
++      if ((!datatmp)||(!oobtmp)) {
++              printk ("sl2312_nand_verify_buf : Unable to allocate SL2312 NAND MTD device structure.\n");
++
++      }
++      //page = nand_page;
++      for(i=0;i<mtd->oobblock;i++)
++              datatmp[i] = FLASH_READ_DATA(nand_page*mtd->oobblock +i);
++      /* read oobdata */
++      for (i = 0; i <  mtd->oobsize; i++)
++              oobtmp[i] = FLASH_READ_DATA(nand_page*mtd->oobblock + mtd->oobblock + i);
++
++      if(len==mtd->oobblock)
++      {
++              for (i=0; i<len; i++)
++              {
++                      if (buf[i] != datatmp[i])
++                      {
++                              kfree(datatmp);
++                              kfree(oobtmp);
++                              printk("Data verify error -> page: %x, byte: %x \n",nand_page,i);
++                              return i;
++                      }
++              }
++      }
++      else if(len == mtd->oobsize)
++      {
++              for (i=0; i<len; i++)
++              {
++                      if (buf[i] != oobtmp[i])
++                      {
++                              kfree(datatmp);
++                              kfree(oobtmp);
++                              printk("OOB verify error -> page: %x, byte: %x \n",nand_page,i);
++                              return i;
++                      }
++              }
++      }
++      else
++      {
++              printk (KERN_WARNING "sl2312_nand_verify_buf : verify length not match 0x%08x\n", len);
++              kfree(datatmp);
++              kfree(oobtmp);
++              return -1;
++      }
++
++      kfree(datatmp);
++      kfree(oobtmp);
++      return 0;
++}
++
++/*
++ * Send command to NAND device
++ */
++static void sl2312_nand_command (struct mtd_info *mtd, unsigned command, int column, int page_addr)
++{
++      register struct nand_chip *this = mtd->priv;
++      int opcode;
++
++
++      /*
++       * program and erase have their own busy handlers
++       * status and sequential in needs no delay
++      */
++      switch (command) {
++
++      case NAND_CMD_PAGEPROG:
++      case NAND_CMD_ERASE1:
++      case NAND_CMD_ERASE2:
++      case NAND_CMD_SEQIN:
++      case NAND_CMD_STATUS:
++      case NAND_CMD_READ0:
++
++              /*
++               * Write out the command to the device.
++               */
++              if (column != -1 || page_addr != -1) {
++
++                      /* Serially input address */
++                      if (column != -1)
++                              //FLASH_WRITE_REG(NFLASH_ADDRESS,column);
++                              nand_col=column;
++
++                      opcode = FLASH_READ_REG(NFLASH_ADDRESS);
++
++                      if (page_addr != -1)
++                              //FLASH_WRITE_REG(NFLASH_ADDRESS,opcode|(page_addr<<8));
++                              nand_page = page_addr;
++
++              }
++              return;
++
++      case NAND_CMD_RESET:
++              if (this->dev_ready)
++                      break;
++              FLASH_WRITE_REG(NFLASH_ECC_CONTROL, 0x00000000); //set 31b = 0
++              FLASH_WRITE_REG(NFLASH_COUNT, 0x7f0fff70); //set only command and no other data
++              FLASH_WRITE_REG(NFLASH_CMD_ADDR, NAND_CMD_RESET); //write reset command
++
++              opcode = 0x80002000|DWIDTH|CHIP_EN; //set start bit & 8bits read command
++              FLASH_WRITE_REG(NFLASH_ACCESS, opcode);
++
++              while(opcode&0x80000000) //polling flash access 31b
++              {
++           opcode=FLASH_READ_REG(NFLASH_ACCESS);
++           //sl2312_flash_delay();
++           schedule();
++              }
++              while ( !(sl2312_device_ready(mtd) & 0x40));
++              {
++                      FLASH_WRITE_REG(NFLASH_ACCESS, NFLASH_DIRECT);
++                      //sl2312_flash_delay();
++                      schedule();
++                      return;
++              }
++      /* This applies to read commands */
++      default:
++              /*
++               * If we don't have access to the busy pin, we apply the given
++               * command delay
++              */
++              if (!this->dev_ready) {
++                      udelay (this->chip_delay);
++                      FLASH_WRITE_REG(NFLASH_ACCESS, NFLASH_DIRECT);
++                      return;
++              }
++      }
++
++      /* wait until command is processed */
++      while (!this->dev_ready(mtd));
++
++}
++/*Add function*/
++static void nand_read_id(int chip_no, unsigned char *id)
++{
++      unsigned int opcode, i;
++
++      if(chip_no==0)
++              CHIP_EN = NFLASH_CHIP0_EN;
++      else
++              CHIP_EN = NFLASH_CHIP1_EN;
++
++      opcode = FLASH_READ_REG(NFLASH_TYPE);
++
++      FLASH_WRITE_REG(NFLASH_ECC_CONTROL, 0x00000000); //set 31b = 0
++      if((opcode&0x00000300)<=0x00000100)
++          FLASH_WRITE_REG(NFLASH_COUNT, 0x7f000100); //set only command & address and two data
++      else
++          FLASH_WRITE_REG(NFLASH_COUNT, 0x7f000300); //set only command & address and 4 data
++
++      FLASH_WRITE_REG(NFLASH_CMD_ADDR, 0x00000090); //write read id command
++      FLASH_WRITE_REG(NFLASH_ADDRESS, 0x00000000); //write address 0x00
++
++      /* read maker code */
++      opcode = 0x80002000|DWIDTH|CHIP_EN;//|chip0_en; //set start bit & 8bits read command
++      FLASH_WRITE_REG(NFLASH_ACCESS, opcode);
++      opcode=FLASH_READ_REG(NFLASH_ACCESS);
++              while(opcode&0x80000000) //polling flash access 31b
++              {
++           opcode=FLASH_READ_REG(NFLASH_ACCESS);
++           //sl2312_flash_delay();
++           schedule();
++              }
++
++    opcode = FLASH_READ_REG(NFLASH_DATA);
++    if(DWIDTH==NFLASH_WiDTH16)
++    {
++                      id[0] = opcode&0xff;
++                      id[1] = (opcode&0xff00)>>8;
++    }
++    else
++    {
++          id[0] = opcode&0xff;
++          opcode = 0x80002000|DWIDTH|CHIP_EN;//|chip0_en; //set start bit & 8bits read command
++                      FLASH_WRITE_REG(NFLASH_ACCESS, opcode);
++                      opcode=FLASH_READ_REG(NFLASH_ACCESS);
++                      while(opcode&0x80000000) //polling flash access 31b
++              {
++             opcode=FLASH_READ_REG(NFLASH_ACCESS);
++             //sl2312_flash_delay();
++             schedule();
++              }
++              opcode = FLASH_READ_REG(NFLASH_DATA);
++                      id[1] = (opcode&0xff00)>>8;
++
++                      opcode=FLASH_READ_REG(NFLASH_TYPE);
++                      if((opcode&0x300)>0x100)
++                      {
++                          for(i=0;i<2;i++)
++                          {
++                                      //data cycle 3 & 4 ->not use
++                                      opcode = 0x80002000|DWIDTH|CHIP_EN;//set start bit & 8bits read command
++                                      FLASH_WRITE_REG(NFLASH_ACCESS, opcode);
++                                      opcode=FLASH_READ_REG(NFLASH_ACCESS);
++                                      while(opcode&0x80000000) //polling flash access 31b
++                                      {
++                                 opcode=FLASH_READ_REG(NFLASH_ACCESS);
++                                 //sl2312_flash_delay();
++                                 schedule();
++                                      }
++
++                                      opcode=FLASH_READ_REG(NFLASH_DATA);
++                                      id[2+i] = (opcode&(0xff0000<<i*8))>>(8*(2+i));
++                          }
++                      }
++    }
++    FLASH_WRITE_REG(NFLASH_ACCESS, NFLASH_DIRECT);
++}
++
++/*
++ * NAND erase a block
++ */
++static int sl2312_nand_erase (struct mtd_info *mtd, struct erase_info *instr, int allowbbt)
++{
++      int page, len, status, pages_per_block, ret, chipnr;
++      struct nand_chip *this = mtd->priv;
++
++      DEBUG (MTD_DEBUG_LEVEL3,
++             "nand_erase: start = 0x%08x, len = %i\n", (unsigned int) instr->addr, (unsigned int) instr->len);
++
++      /* Start address must align on block boundary */
++      if (instr->addr & ((1 << this->phys_erase_shift) - 1)) {
++              DEBUG (MTD_DEBUG_LEVEL0, "nand_erase: Unaligned address\n");
++              return -EINVAL;
++      }
++
++      /* Length must align on block boundary */
++      if (instr->len & ((1 << this->phys_erase_shift) - 1)) {
++              DEBUG (MTD_DEBUG_LEVEL0, "nand_erase: Length not block aligned\n");
++              return -EINVAL;
++      }
++
++      /* Do not allow erase past end of device */
++      if ((instr->len + instr->addr) > mtd->size) {
++              DEBUG (MTD_DEBUG_LEVEL0, "nand_erase: Erase past end of device\n");
++              return -EINVAL;
++      }
++
++      instr->fail_addr = 0xffffffff;
++
++      /* Grab the lock and see if the device is available */
++      sl2312_nand_get_chip (this, mtd, FL_ERASING, NULL);
++
++      /* Shift to get first page */
++      page = (int) (instr->addr >> this->page_shift);
++      chipnr = (int) (instr->addr >> this->chip_shift);
++
++      /* Calculate pages in each block */
++      pages_per_block = 1 << (this->phys_erase_shift - this->page_shift);
++
++      /* Select the NAND device */
++      //this->select_chip(mtd, chipnr);
++      this->select_chip(mtd, 0);
++
++      /* Check the WP bit */
++      /* Check, if it is write protected */
++      status = sl2312_device_ready(mtd);
++      if (!(status & 0x80)) {
++              DEBUG (MTD_DEBUG_LEVEL0, "nand_erase: Device is write protected!!!\n");
++              instr->state = MTD_ERASE_FAILED;
++              goto erase_exit;
++      }
++
++      /* Loop through the pages */
++      len = instr->len;
++
++      instr->state = MTD_ERASING;
++
++      while (len) {
++              /* Check if we have a bad block, we do not erase bad blocks ! */
++              if (this->block_bad(mtd, ((loff_t) page) << this->page_shift, 0)) {
++                      printk (KERN_WARNING "nand_erase: attempt to erase a bad block at page 0x%08x\n", page);
++                      //instr->state = MTD_ERASE_FAILED;
++                      //goto erase_exit;
++              }
++
++              /* Invalidate the page cache, if we erase the block which contains
++                 the current cached page */
++              if (page <= this->pagebuf && this->pagebuf < (page + pages_per_block))
++                      this->pagebuf = -1;
++              /////////
++
++              ///* Send commands to erase a page */
++              //FLASH_WRITE_REG(NFLASH_ECC_CONTROL, 0x00000000); //set 31b = 0
++          //
++              //if(mtd->oobblock > 528)
++              //    FLASH_WRITE_REG(NFLASH_COUNT, 0x7f0fff21);  // 3 address & 2 command
++              //else
++              //    FLASH_WRITE_REG(NFLASH_COUNT, 0x7f0fff11);  // 2 address & 2 command
++              //
++              //FLASH_WRITE_REG(NFLASH_CMD_ADDR, 0x0000d060); // write read id command
++              //FLASH_WRITE_REG(NFLASH_ADDRESS, page); //write address 0x00
++              //
++              //
++              //
++              ///* read maker code */
++              //opcode = 0x80003000|DWIDTH|CHIP_EN; //set start bit & 8bits write command
++              //FLASH_WRITE_REG(NFLASH_ACCESS, opcode);
++              //
++              //while(opcode&0x80000000) //polling flash access 31b
++              //{
++        //   opcode=FLASH_READ_REG(NFLASH_ACCESS);
++        //   //sl2312_flash_delay();
++        //   schedule();
++        //   //cond_resched();
++              //}
++              sl2312_nand_erase_block(mtd, page);
++              //////////////
++              status = this->waitfunc (mtd, this, FL_ERASING);
++              /* See if block erase succeeded */
++              if (status & 0x01) {
++                      DEBUG (MTD_DEBUG_LEVEL0, "nand_erase: " "Failed erase, page 0x%08x\n", page);
++                      instr->state = MTD_ERASE_FAILED;
++                      instr->fail_addr = (page << this->page_shift);
++                      goto erase_exit;
++              }
++
++              /* Increment page address and decrement length */
++              len -= (1 << this->phys_erase_shift);
++              page += pages_per_block;
++
++              /* Check, if we cross a chip boundary */
++              if (len && !(page & this->pagemask)) {
++                      chipnr++;
++                      this->select_chip(mtd, 0);
++                      this->select_chip(mtd, 0);
++              }
++              //sl2312_flash_delay();
++           schedule();
++           //cond_resched();
++      }
++      instr->state = MTD_ERASE_DONE;
++
++erase_exit:
++      /* De-select the NAND device */
++      this->select_chip(mtd, 0);
++      spin_unlock_bh (&this->chip_lock);
++
++      ret = instr->state == MTD_ERASE_DONE ? 0 : -EIO;;
++      /* Do call back function */
++      if (!ret && instr->callback)
++              instr->callback (instr);
++
++      /* The device is ready */
++      spin_lock_bh (&this->chip_lock);
++      this->state = FL_READY;
++      spin_unlock_bh (&this->chip_lock);
++      FLASH_WRITE_REG(NFLASH_ACCESS, NFLASH_DIRECT);
++      /* Return more or less happy */
++      return ret;
++}
++
++static void sl2312_nand_select_chip(struct mtd_info *mtd, int chip)
++{
++      //struct nand_chip *this = mtd->priv;
++
++      switch(chip) {
++      case -1:
++              CHIP_EN = NFLASH_CHIP0_EN;
++              break;
++      case 0:
++              CHIP_EN = NFLASH_CHIP0_EN;
++              break;
++      case 1:
++              CHIP_EN = NFLASH_CHIP1_EN;
++              break;
++      default:
++                      CHIP_EN = NFLASH_CHIP0_EN;
++                      break;
++      }
++}
++
++/**
++ * nand_default_block_markbad - [DEFAULT] mark a block bad
++ * @mtd:      MTD device structure
++ * @ofs:      offset from device start
++ *
++ * This is the default implementation, which can be overridden by
++ * a hardware specific driver.
++*/
++static int sl2312_nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs)
++{
++      struct nand_chip *this = mtd->priv;
++      u_char buf[2] = {0, 0};
++      size_t  retlen;
++      int block;
++
++      /* Get block number */
++      block = ((int) ofs) >> this->bbt_erase_shift;
++      this->bbt[block >> 2] |= 0x01 << ((block & 0x03) << 1);
++
++      /* Do we have a flash based bad block table ? */
++      if (this->options & NAND_USE_FLASH_BBT)
++              return nand_update_bbt (mtd, ofs);
++
++      /* We write two bytes, so we dont have to mess with 16 bit access */
++      ofs += mtd->oobsize + (this->badblockpos & ~0x01);
++      return sl2312_nand_write_oob (mtd, ofs , 2, &retlen, buf);
++}
++
++/* Appropriate chip should already be selected */
++static int sl2312_nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip)//(struct mtd_info *mtd, unsigned long page, )
++{
++      u_char *buf, *oobbuf;
++      size_t  retlen;
++      unsigned long page, chipnr;
++      struct nand_chip *this = mtd->priv;
++
++      if (getchip) {
++              page = (int)(ofs >> this->page_shift);
++              chipnr = (int)(ofs >> this->chip_shift);
++
++              /* Grab the lock and see if the device is available */
++              sl2312_nand_get_chip (this, mtd, FL_READING, NULL);
++              /* Select the NAND device */
++              this->select_chip(mtd, chipnr);
++      } else
++              page = (int) ofs;
++
++      buf = kmalloc (mtd->oobblock,GFP_KERNEL);
++      oobbuf = kmalloc (mtd->oobsize,GFP_KERNEL);
++
++      if ((!buf)||(!oobbuf)) {
++              printk ("sl2312_nand_block_bad : Unable to allocate SL2312 NAND MTD device structure.\n");
++
++      }
++
++      sl2312_nand_read_ecc (mtd, page, mtd->oobblock , &retlen, buf, oobbuf, NULL);
++
++
++      if(((mtd->oobblock < 528)&&(oobbuf[5] != 0xff))||((mtd->oobblock > 528)&&(oobbuf[0] != 0xff)))
++      {
++              kfree(buf);
++              kfree(oobbuf);
++              return 1;
++      }
++
++      kfree(buf);
++      kfree(oobbuf);
++      return 0;
++}
++
++/*
++*     Use NAND read ECC
++*/
++static int sl2312_nand_read (struct mtd_info *mtd, loff_t from, size_t len, size_t * retlen, u_char * buf)
++{
++      return sl2312_nand_read_ecc (mtd, from, len, retlen, buf, NULL, NULL);
++}
++
++/*
++ * NAND read with ECC
++ */
++static int sl2312_nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
++                        size_t * retlen, u_char * buf, u_char * oob_buf, struct nand_oobinfo *oobsel)
++{
++      int j, col, page, opcode, i;
++      int end=0;//, ecc=0;//, end_page=0;
++      int erase_state = 0;
++      int read = 0, oob = 0, ecc_failed = 0;//, ecc_status = 0
++      struct nand_chip *this = mtd->priv;
++      u_char *data_poi, *oob_data = oob_buf;
++      //u_char ecc_calc[6];
++      //u_char ecc_code[6];
++      int     eccmode;
++      int     *oob_config;
++
++
++
++      // use chip default if zero
++      if (oobsel == NULL)
++              oobsel = &mtd->oobinfo;
++
++      eccmode = oobsel->useecc ? this->eccmode : NAND_ECC_NONE;
++      oob_config = oobsel->eccpos;
++
++      DEBUG (MTD_DEBUG_LEVEL3, "nand_read_ecc: from = 0x%08x, len = %i\n", (unsigned int) from, (int) len);
++
++      /* Do not allow reads past end of device */
++      if ((from + len) > mtd->size) {
++              DEBUG (MTD_DEBUG_LEVEL0, "nand_read_ecc: Attempt read beyond end of device\n");
++              *retlen = 0;
++              return -EINVAL;
++      }
++
++      /* Grab the lock and see if the device is available */
++      sl2312_nand_get_chip (this, mtd ,FL_READING, &erase_state);
++
++      /* Select the NAND device */
++      this->select_chip(mtd, 0);
++
++      /* First we calculate the starting page */
++      page = from >> this->page_shift;
++
++      //end_page = mtd->oobblock + mtd->oobsize;
++      end = mtd->oobblock;
++      //ecc = mtd->eccsize;
++      /* Get raw starting column */
++      col = (from & (mtd->oobblock - 1));
++
++
++      /* Send the read command */
++      //this->cmdfunc (mtd, NAND_CMD_READ0, 0x00, page);
++
++      /* Loop until all data read */
++      FLASH_WRITE_REG(NFLASH_ACCESS, NFLASH_DIRECT);
++      while (read < len) {
++
++              //udelay(1200);
++              /* If we have consequent page reads, apply delay or wait for ready/busy pin */
++              if (read) {
++                      if (!this->dev_ready)
++                              udelay (this->chip_delay);
++                      else
++                              while (!this->dev_ready(mtd));
++              }
++
++              /*
++               * If the read is not page aligned, we have to read into data buffer
++               * due to ecc, else we read into return buffer direct
++               */
++              if (!col && (len - read) >= end)
++                      data_poi = &buf[read];
++              else
++                      data_poi = this->data_buf;
++
++              /* get oob area, if we have no oob buffer from fs-driver */
++              if (!oob_buf) {
++                      oob_data = &this->data_buf[end];
++                      oob = 0;
++              }
++
++              j = 0;
++              switch (eccmode) {
++                      case NAND_ECC_NONE: {   /* No ECC, Read in a page */
++                              FLASH_WRITE_REG(NFLASH_ECC_CONTROL, 0x0); //set 31b = 0
++                              break;
++                      }
++
++                      case NAND_ECC_SOFT:     /* Software ECC 3/256: Read in a page + oob data */
++                              break;
++
++                      case NAND_ECC_HW3_256: /* Hardware ECC 3 byte /256 byte data: Read in first 256 byte, get ecc, */
++                              break;
++
++                      case NAND_ECC_HW3_512:
++                      case NAND_ECC_HW6_512: /* Hardware ECC 3/6 byte / 512 byte data : Read in a page  */
++                              FLASH_WRITE_REG(NFLASH_ECC_CONTROL, 0x80000001); //set 31b = 0
++                              break;
++
++                      default:
++                              printk (KERN_WARNING "Invalid NAND_ECC_MODE %d\n", this->eccmode);
++                              FLASH_WRITE_REG(NFLASH_ECC_CONTROL, 0x0);
++                              //BUG();
++              }//end switch
++
++                      for(i=0;i<end;i++)
++                      {
++                              //udelay(7);
++                              data_poi[i] = FLASH_READ_DATA(page*mtd->oobblock +i);
++                      }
++                      /* read oobdata */
++                      for (i = 0; i <  mtd->oobsize; i++)
++                      {
++                              //udelay(7);
++                              oob_data[oob + i] = FLASH_READ_DATA(page*mtd->oobblock +end+i);
++                      }
++
++              /* Skip ECC, if not active */
++                      if (eccmode == NAND_ECC_NONE)
++                              goto readdata;
++
++                      // compare ecc and correct data
++
++                              opcode=FLASH_READ_REG(NFLASH_ECC_STATUS);
++                              while(!(opcode&0x80000000)) //polling flash access 31b
++                              {
++                                 opcode=FLASH_READ_REG(NFLASH_ECC_STATUS);
++                                 //sl2312_flash_delay();
++                                 schedule();
++                              }
++                              for(j=0;j<(end/512);j++)
++                              {//for 2k page
++
++                                      opcode = 0x00000000|oob_data[mtd->oobsize-3-4*j]<<16|oob_data[mtd->oobsize-2-4*j]<<8|oob_data[mtd->oobsize-1-4*j];
++
++                                      //opcode=FLASH_READ_REG(NFLASH_ECC_CODE_GEN0+(j*4));
++
++                                      FLASH_WRITE_REG(NFLASH_ECC_OOB, opcode);
++                                      opcode = 0x00000000|(j<<8); //select ECC code generation 0
++                                      FLASH_WRITE_REG(NFLASH_ECC_CONTROL, opcode); //???
++
++                                      opcode=FLASH_READ_REG(NFLASH_ECC_STATUS);
++                                      if((opcode&0x00000003)==0x03)
++                                      {
++                                              printk (KERN_WARNING "\nPageRead Uncorrectable error !!\n");
++                                              ecc_failed++;
++                                      }
++                                      else if((opcode&0x00000003)==0x01)
++                                      {
++                                              printk (KERN_WARNING "\nPageRead One bit data error !!");
++                                              // correct data
++                                              if((data_poi[(opcode&0xff80)>>7]>>((opcode&0x38)>>3))%1)
++                                                      data_poi[(opcode&0xff80)>>7] &= ~(1<<((opcode&0x38)>>3));
++                                              else
++                                                      data_poi[(opcode&0xff80)>>7] |= (1<<((opcode&0x38)>>3));
++
++                                      }
++                                      else if((opcode&0x00000003)==0x02)
++                                      {
++                                              printk (KERN_WARNING "\nPageRead One bit ECC error !!\n");
++                                      }
++                                      else if((opcode&0x00000003)==0x00)
++                                      {
++
++                                      }
++
++                              }//for 2k page
++readdata:
++              if (col || (len - read) < end) {
++                      for (j = col; j < end && read < len; j++)
++                              buf[read++] = data_poi[j];
++              } else
++                      read += mtd->oobblock;
++              /* For subsequent reads align to page boundary. */
++              col = 0;
++              /* Increment page address */
++              page++;
++              schedule();
++      }
++      /* De-select the NAND device */
++      //this->select_chip(mtd, -1);
++      FLASH_WRITE_REG(NFLASH_ECC_CONTROL, 0x0); //set 31b = 0
++      FLASH_WRITE_REG(NFLASH_ACCESS, NFLASH_INDIRECT);
++      /* Wake up anyone waiting on the device */
++      spin_lock_bh (&this->chip_lock);
++      this->state = FL_READY;
++      wake_up (&this->wq);
++      spin_unlock_bh (&this->chip_lock);
++
++      /*
++       * Return success, if no ECC failures, else -EIO
++       * fs driver will take care of that, because
++       * retlen == desired len and result == -EIO
++       */
++      *retlen = read;
++      return ecc_failed ? -EIO : 0;
++}
++
++/*
++ * Wait for command done. This applies to erase and program only
++ * Erase can take up to 400ms and program up to 20ms according to
++ * general NAND and SmartMedia specs
++ *
++*/
++static int sl2312_nand_waitfunc(struct mtd_info *mtd, struct nand_chip *this, int state)
++{
++      unsigned long   timeo = jiffies;
++      int     status, opcode;
++
++      if (state == FL_ERASING)
++               timeo += (HZ * 400) / 1000;
++      else
++               timeo += (HZ * 20) / 1000;
++
++      spin_lock_bh (&this->chip_lock);
++      FLASH_WRITE_REG(NFLASH_ECC_CONTROL, 0x00000000); //set 31b = 0
++      FLASH_WRITE_REG(NFLASH_COUNT, 0x007f000070); //set only command no address and two data
++
++      FLASH_WRITE_REG(NFLASH_CMD_ADDR, 0x00000070); //write read status command
++
++
++      opcode = 0x80002000|DWIDTH|CHIP_EN; //set start bit & 8bits read command
++      FLASH_WRITE_REG(NFLASH_ACCESS, opcode);
++
++      while(opcode&0x80000000) //polling flash access 31b
++    {
++        opcode=FLASH_READ_REG(NFLASH_ACCESS);
++        //sl2312_flash_delay();
++        schedule();
++    }
++
++      while (time_before(jiffies, timeo)) {
++              /* Check, if we were interrupted */
++              if (this->state != state) {
++                      spin_unlock_bh (&this->chip_lock);
++                      FLASH_WRITE_REG(NFLASH_ACCESS, NFLASH_DIRECT);
++                      return 0;
++              }
++              if (this->dev_ready) {
++                      if (this->dev_ready(mtd))
++                              break;
++              }
++              if (FLASH_READ_REG(NFLASH_DATA) & 0x40)
++                      break;
++
++              spin_unlock_bh (&this->chip_lock);
++              yield ();
++              spin_lock_bh (&this->chip_lock);
++      }
++      status = FLASH_READ_REG(NFLASH_DATA)&0xff;
++      spin_unlock_bh (&this->chip_lock);
++      FLASH_WRITE_REG(NFLASH_ACCESS, NFLASH_DIRECT);
++      return status;
++}
++
++static int sl2312_nand_read_oob (struct mtd_info *mtd, loff_t from, size_t len, size_t * retlen, u_char * buf)
++{
++      int i, col, page, j=0;
++      //int erase_state = 0;
++      struct nand_chip *this = mtd->priv;
++      u_char *databuf, *oobbuf;
++
++      databuf = &this->data_buf[0];
++      oobbuf = &this->data_buf[mtd->oobblock];
++              for (i = 0; i < mtd->oobsize; i++)
++                      oobbuf[i] = 0xff;
++
++      DEBUG (MTD_DEBUG_LEVEL3, "nand_read_oob: from = 0x%08x, len = %i\n", (unsigned int) from, (int) len);
++
++      /* Shift to get page */
++      page = ((int) from) >> this->page_shift;
++
++      /* Mask to get column */
++      col = from & (mtd->oobsize-1);  //0x0f;
++
++      /* Initialize return length value */
++      *retlen = 0;
++      sl2312_nand_read_ecc (mtd, page, mtd->oobblock , retlen, databuf, oobbuf, NULL);
++      for(i=col,j=0;i<mtd->oobsize||i<(col+len);i++,j++)
++              buf[j] = oobbuf[i];
++
++      *retlen = j ;
++      return 0;
++}
++
++#define NOTALIGNED(x) (x & (mtd->oobblock-1)) != 0
++/*
++*     Use NAND write ECC
++*/
++static int sl2312_nand_write (struct mtd_info *mtd, loff_t to, size_t len, size_t * retlen, const u_char * buf)
++{
++      return (sl2312_nand_write_ecc (mtd, to, len, retlen, buf, NULL, NULL));
++}
++
++/*
++ * NAND write with ECC
++ */
++static int sl2312_nand_write_ecc (struct mtd_info *mtd, loff_t to, size_t len,
++                         size_t * retlen, const u_char * buf, u_char * eccbuf, struct nand_oobinfo *oobsel)
++{
++      int page, ret = 0, oob = 0, written = 0;
++      struct nand_chip *this = mtd->priv;
++
++      DEBUG (MTD_DEBUG_LEVEL3, "nand_write_ecc: to = 0x%08x, len = %i\n", (unsigned int) to, (int) len);
++
++
++      /* Do not allow write past end of device */
++      if ((to + len) > mtd->size) {
++              DEBUG (MTD_DEBUG_LEVEL0, "nand_write_ecc: Attempt to write past end of page\n");
++              return -EINVAL;
++      }
++
++      /* reject writes, which are not page aligned */
++      if (NOTALIGNED (to) || NOTALIGNED(len)) {
++              printk (KERN_NOTICE "nand_write_ecc: Attempt to write not page aligned data\n");
++              return -EINVAL;
++      }
++
++      // if oobsel is NULL, use chip defaults
++      if (oobsel == NULL)
++              oobsel = &mtd->oobinfo;
++
++      /* Shift to get page */
++      page = ((int) to) >> this->page_shift;
++
++      /* Grab the lock and see if the device is available */
++      sl2312_nand_get_chip (this, mtd, FL_WRITING, NULL);
++
++      /* Select the NAND device */
++      this->select_chip(mtd, 0);
++
++      /* Check the WP bit */
++      if (!(sl2312_device_ready(mtd) & 0x80)) {
++              DEBUG (MTD_DEBUG_LEVEL0, "nand_write_ecc: Device is write protected!!!\n");
++              ret = -EIO;
++              goto out;
++      }
++
++      /* Loop until all data is written */
++      while (written < len) {
++              //udelay(100);
++              int cnt = mtd->oobblock;
++              this->data_poi = (u_char*) &buf[written];
++              /* We use the same function for write and writev */
++              if (eccbuf) {
++                      ret = sl2312_nand_write_page (mtd, this, page, &eccbuf[oob], oobsel);
++                      oob += mtd->oobsize;
++              } else
++                      ret = sl2312_nand_write_page (mtd, this, page, NULL, oobsel);
++
++              if (ret)
++                      goto out;
++
++              /* Update written bytes count */
++              written += cnt;
++              /* Increment page address */
++              page++;
++      }
++
++out:
++      /* De-select the NAND device */
++      //this->select_chip(mtd, -1);
++
++      /* Wake up anyone waiting on the device */
++      spin_lock_bh (&this->chip_lock);
++      this->state = FL_READY;
++      wake_up (&this->wq);
++      spin_unlock_bh (&this->chip_lock);
++
++      *retlen = written;
++      return ret;
++}
++
++/*
++ *    Nand_page_program function is used for write and writev !
++ *    This function will always program a full page of data
++ *    If you call it with a non page aligned buffer, you're lost :)
++ */
++static int sl2312_nand_write_page (struct mtd_info *mtd, struct nand_chip *this, int page, u_char *oob_buf,  struct nand_oobinfo *oobsel)
++{
++      int     i, j, status, opcode;
++      u_char  ecc_code[16], *oob_data;
++      int     eccmode = oobsel->useecc ? this->eccmode : NAND_ECC_NONE;
++      //int   *oob_config = oobsel->eccpos;
++
++      /* pad oob area, if we have no oob buffer from fs-driver */
++      if (!oob_buf) {
++              oob_data = &this->data_buf[mtd->oobblock];
++              for (i = 0; i < mtd->oobsize; i++)
++                      oob_data[i] = 0xff;
++      } else
++              oob_data = oob_buf;
++
++      /* Send command to begin auto page programming */
++
++      memset(oob_data,0xff,mtd->oobsize);
++      /* Write out complete page of data, take care of eccmode */
++      switch (eccmode) {
++      /* No ecc and software ecc 3/256, write all */
++      case NAND_ECC_NONE:
++              printk (KERN_WARNING "Writing data without ECC to NAND-FLASH is not recommended\n");
++              FLASH_WRITE_REG(NFLASH_ECC_CONTROL, 0x0); //set 31b = 0
++              break;
++      case NAND_ECC_SOFT:
++              break;
++
++      /* Hardware ecc 3 byte / 256 data, write first half, get ecc, then second, if 512 byte pagesize */
++      case NAND_ECC_HW3_256:
++              break;
++
++      /* Hardware ecc 3 byte / 512 byte data, write full page */
++      case NAND_ECC_HW3_512:
++              FLASH_WRITE_REG(NFLASH_ECC_CONTROL, 0x80000001); //set 31b = 0
++
++      /* Hardware ecc 6 byte / 512 byte data, write full page */
++      case NAND_ECC_HW6_512:
++              break;
++
++      default:
++              printk (KERN_WARNING "Invalid NAND_ECC_MODE %d\n", this->eccmode);
++              FLASH_WRITE_REG(NFLASH_ECC_CONTROL, 0x0); //set 31b = 0
++              //BUG();
++      }
++
++      FLASH_WRITE_REG(NFLASH_ACCESS, NFLASH_DIRECT);
++
++      for(i=0;i<mtd->oobblock;i++)
++      {
++              //udelay(5);
++              FLASH_WRITE_DATA((page*mtd->oobblock)+i,this->data_poi[i]);
++      }
++      ///////////////
++      if(eccmode!=NAND_ECC_NONE)
++      {
++              opcode=FLASH_READ_REG(NFLASH_ECC_STATUS);
++              while(!(opcode&0x80000000)) //polling flash access 31b
++      {
++                 opcode=FLASH_READ_REG(NFLASH_ECC_STATUS);
++                 //sl2312_flash_delay();
++                 schedule();
++      }
++
++
++      for(i=0;i<(mtd->oobblock/512);i++)
++      {
++              opcode=FLASH_READ_REG(NFLASH_ECC_CODE_GEN0+(i*4));
++
++              for(j=3;j>0;j--)
++                    oob_data[(mtd->oobsize-j-(i*4))] = (opcode<<((4-j)*8)) >>24;
++
++              for(j=0;j<4;j++)
++              {
++                      ecc_code[15-i*4] = opcode;
++                      ecc_code[15-i*4-1] = opcode>>8;
++                      ecc_code[15-i*4-2] = opcode>>16;
++              }
++      }
++
++      //disable ecc
++      FLASH_WRITE_REG(NFLASH_ECC_CONTROL, 0x00000000);
++
++      /* Write out OOB data */
++      for(i=0;i<mtd->oobsize;i++)
++      {
++              //udelay(5);
++                      FLASH_WRITE_DATA((page*mtd->oobblock)+mtd->oobblock+i,oob_data[i]);
++              }
++    }
++    else
++    {
++      for(i=0;i<mtd->oobsize;i++)
++      {
++              //udelay(5);
++                      FLASH_WRITE_DATA((page*mtd->oobblock)+mtd->oobblock+i,0xff);
++              }
++    }
++
++
++      /* call wait ready function */
++      status = this->waitfunc (mtd, this, FL_WRITING);
++      FLASH_WRITE_REG(NFLASH_ECC_CONTROL, 0x0); //set 31b = 0
++      /* See if device thinks it succeeded */
++      if (status & 0x01) {
++              DEBUG (MTD_DEBUG_LEVEL0, "%s: " "Failed write, page 0x%08x, ", __FUNCTION__, page);
++              FLASH_WRITE_REG(NFLASH_ECC_CONTROL, 0x0); //set 31b = 0
++              return -EIO;
++      }
++
++#ifdef CONFIG_MTD_NAND_VERIFY_WRITE
++      /*
++       * The NAND device assumes that it is always writing to
++       * a cleanly erased page. Hence, it performs its internal
++       * write verification only on bits that transitioned from
++       * 1 to 0. The device does NOT verify the whole page on a
++       * byte by byte basis. It is possible that the page was
++       * not completely erased or the page is becoming unusable
++       * due to wear. The read with ECC would catch the error
++       * later when the ECC page check fails, but we would rather
++       * catch it early in the page write stage. Better to write
++       * no data than invalid data.
++       */
++
++      /* Send command to read back the page */
++      this->cmdfunc (mtd, NAND_CMD_READ0, 0, page);
++      /* Loop through and verify the data */
++      if (this->verify_buf(mtd, this->data_poi, mtd->oobblock)) {
++              DEBUG (MTD_DEBUG_LEVEL0, "%s: " "Failed write verify, page 0x%08x ", __FUNCTION__, page);
++              return -EIO;
++      }
++
++      /* check, if we have a fs-supplied oob-buffer */
++      if (oob_buf) {
++              if (this->verify_buf(mtd, oob_data, mtd->oobsize)) {
++                      DEBUG (MTD_DEBUG_LEVEL0, "%s: " "Failed write verify, page 0x%08x ", __FUNCTION__, page);
++                      return -EIO;
++              }
++      } else {
++              if (eccmode != NAND_ECC_NONE) {
++                      int ecc_bytes = 0;
++
++                      switch (this->eccmode) {
++                      case NAND_ECC_SOFT:
++                      case NAND_ECC_HW3_256: ecc_bytes = (mtd->oobblock == 512) ? 6 : 3; break;
++                      case NAND_ECC_HW3_512: ecc_bytes = 3; break;
++                      case NAND_ECC_HW6_512: ecc_bytes = 6; break;
++                      }
++
++
++
++                      for(i=0;i < (mtd->oobblock+mtd->oobsize);i++)
++                      {
++                              if(i>=mtd->oobblock)
++                                      oob_data[i-mtd->oobblock] = FLASH_READ_DATA((page*mtd->oobblock) +i);
++                              else
++                                      oob_data[0] = FLASH_READ_DATA((page*mtd->oobblock) +i);
++                      }
++
++                      if(this->eccmode == NAND_ECC_HW3_512)
++                      {
++                              for(i=0;i<(mtd->oobblock/512);i++)
++                      {
++                              for(j=0;j<3;j++)
++                              {
++                                  if (oob_data[mtd->oobsize-1-j-4*i] != ecc_code[15-j-4*i]) {
++                                                      DEBUG (MTD_DEBUG_LEVEL0,
++                                                             "%s: Failed ECC write "
++                                                     "verify, page 0x%08x, " "%6i bytes were succesful\n", __FUNCTION__, page, i);
++                                                      return -EIO;
++                                              }
++                              }
++                      }
++                      }
++              }//eccmode != NAND_ECC_NONE
++      }
++      /*
++       * Terminate the read command. This is faster than sending a reset command or
++       * applying a 20us delay before issuing the next programm sequence.
++       * This is not a problem for all chips, but I have found a bunch of them.
++       */
++      //this->select_chip(mtd, -1);
++      //this->select_chip(mtd, 0);
++#endif
++
++      return 0;
++}
++
++/*
++ * NAND write with iovec
++ */
++static int sl2312_nand_writev (struct mtd_info *mtd, const struct kvec *vecs, unsigned long count,
++              loff_t to, size_t * retlen)
++{
++      return (sl2312_nand_writev_ecc (mtd, vecs, count, to, retlen, NULL, 0));
++}
++
++static int sl2312_nand_writev_ecc (struct mtd_info *mtd, const struct kvec *vecs, unsigned long count,
++              loff_t to, size_t * retlen, u_char *eccbuf, struct nand_oobinfo *oobsel)
++{
++      int i, page, len, total_len, ret = 0, written = 0;
++      struct nand_chip *this = mtd->priv;
++
++      /* Calculate total length of data */
++      total_len = 0;
++      for (i = 0; i < count; i++)
++              total_len += (int) vecs[i].iov_len;
++
++      DEBUG (MTD_DEBUG_LEVEL3,
++             "nand_writev: to = 0x%08x, len = %i, count = %ld\n", (unsigned int) to, (unsigned int) total_len, count);
++
++      /* Do not allow write past end of page */
++      if ((to + total_len) > mtd->size) {
++              DEBUG (MTD_DEBUG_LEVEL0, "nand_writev: Attempted write past end of device\n");
++              return -EINVAL;
++      }
++
++      /* reject writes, which are not page aligned */
++      if (NOTALIGNED (to) || NOTALIGNED(total_len)) {
++              printk (KERN_NOTICE "nand_write_ecc: Attempt to write not page aligned data\n");
++              return -EINVAL;
++      }
++
++      // if oobsel is NULL, use chip defaults
++      if (oobsel == NULL)
++              oobsel = &mtd->oobinfo;
++
++      /* Shift to get page */
++      page = ((int) to) >> this->page_shift;
++
++      /* Grab the lock and see if the device is available */
++      sl2312_nand_get_chip (this, mtd, FL_WRITING, NULL);
++
++      /* Select the NAND device */
++      this->select_chip(mtd, 0);
++
++      /* Check the WP bit */
++      if (!(sl2312_device_ready(mtd) & 0x80)) {
++              DEBUG (MTD_DEBUG_LEVEL0, "sl2312_nand_writev_ecc: Device is write protected!!!\n");
++              ret = -EIO;
++              goto out;
++      }
++
++      /* Loop until all iovecs' data has been written */
++      len = 0;
++      while (count) {
++              /*
++               *  Check, if the tuple gives us not enough data for a
++               *  full page write. Then we can use the iov direct,
++               *  else we have to copy into data_buf.
++               */
++              if ((vecs->iov_len - len) >= mtd->oobblock) {
++                      this->data_poi = (u_char *) vecs->iov_base;
++                      this->data_poi += len;
++                      len += mtd->oobblock;
++                      /* Check, if we have to switch to the next tuple */
++                      if (len >= (int) vecs->iov_len) {
++                              vecs++;
++                              len = 0;
++                              count--;
++                      }
++              } else {
++                      /*
++                       * Read data out of each tuple until we have a full page
++                       * to write or we've read all the tuples.
++                      */
++                      int cnt = 0;
++                      while ((cnt < mtd->oobblock) && count) {
++                              if (vecs->iov_base != NULL && vecs->iov_len) {
++                                      this->data_buf[cnt++] = ((u_char *) vecs->iov_base)[len++];
++                              }
++                              /* Check, if we have to switch to the next tuple */
++                              if (len >= (int) vecs->iov_len) {
++                                      vecs++;
++                                      len = 0;
++                                      count--;
++                              }
++                      }
++                      this->data_poi = this->data_buf;
++              }
++
++              /* We use the same function for write and writev !) */
++              ret = sl2312_nand_write_page (mtd, this, page, NULL, oobsel);
++              if (ret)
++                      goto out;
++
++              /* Update written bytes count */
++              written += mtd->oobblock;;
++
++              /* Increment page address */
++              page++;
++      }
++
++out:
++      /* De-select the NAND device */
++      //this->select_chip(mtd, -1);
++
++      /* Wake up anyone waiting on the device */
++      spin_lock_bh (&this->chip_lock);
++      this->state = FL_READY;
++      wake_up (&this->wq);
++      spin_unlock_bh (&this->chip_lock);
++
++      *retlen = written;
++      return ret;
++}
++
++/*
++static u_char ffchars[] = {
++      0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++      0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
++};
++*/
++/*
++ * NAND write out-of-band
++ */
++static int sl2312_nand_write_oob (struct mtd_info *mtd, loff_t to, size_t len, size_t * retlen, const u_char * buf)
++{
++      int column, page, status, ret = 0, j=0;
++      struct nand_chip *this = mtd->priv;
++      u_char *databuf, *oobbuf;
++
++
++              databuf = &this->data_buf[0];
++              oobbuf = &this->data_buf[mtd->oobblock];
++              for (j = 0; j < mtd->oobsize; j++)
++                      oobbuf[j] = 0xff;
++//#ifdef CONFIG_MTD_NAND_VERIFY_WRITE
++//    int     i;
++//#endif
++
++      DEBUG (MTD_DEBUG_LEVEL3, "nand_write_oob: to = 0x%08x, len = %i\n", (unsigned int) to, (int) len);
++
++      /* Shift to get page */
++      page = ((int) to) >> this->page_shift;
++
++      /* Mask to get column */
++      column = to & 0x1f;
++
++      /* Initialize return length value */
++      *retlen = 0;
++
++      /* Do not allow write past end of page */
++      if ((column + len) > mtd->oobsize) {
++              DEBUG (MTD_DEBUG_LEVEL0, "nand_write_oob: Attempt to write past end of page\n");
++              return -EINVAL;
++      }
++
++      /* Grab the lock and see if the device is available */
++      sl2312_nand_get_chip (this, mtd, FL_WRITING, NULL);
++
++      /* Select the NAND device */
++      this->select_chip(mtd, 0);
++
++      /* Reset the chip. Some chips (like the Toshiba TC5832DC found
++         in one of my DiskOnChip 2000 test units) will clear the whole
++         data page too if we don't do this. I have no clue why, but
++         I seem to have 'fixed' it in the doc2000 driver in
++         August 1999.  dwmw2. */
++      this->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
++
++      /* Check the WP bit */
++      if (!(sl2312_device_ready(mtd) & 0x80)) {
++              DEBUG (MTD_DEBUG_LEVEL0, "nand_write_oob: Device is write protected!!!\n");
++              ret = -EIO;
++              goto out;
++      }
++      /* Write out desired data */
++      this->cmdfunc (mtd, NAND_CMD_SEQIN, mtd->oobblock, page);
++
++      sl2312_nand_read_ecc (mtd, page, mtd->oobblock , retlen, databuf, oobbuf, NULL);
++
++    for(j=column;j<(column+len);j++)
++      oobbuf[j] = buf[j-column];
++    sl2312_nand_write_ecc (mtd, page, mtd->oobblock, retlen, databuf, oobbuf, NULL);
++
++      status = this->waitfunc (mtd, this, FL_WRITING);
++
++      /* See if device thinks it succeeded */
++      if (status & 0x01) {
++              DEBUG (MTD_DEBUG_LEVEL0, "nand_write_oob: " "Failed write, page 0x%08x\n", page);
++              ret = -EIO;
++              goto out;
++      }
++      /* Return happy */
++      *retlen = len;
++
++
++out:
++      /* De-select the NAND device */
++      //this->select_chip(mtd, -1);
++
++      /* Wake up anyone waiting on the device */
++      spin_lock_bh (&this->chip_lock);
++      this->state = FL_READY;
++      wake_up (&this->wq);
++      spin_unlock_bh (&this->chip_lock);
++
++      return ret;
++}
++
++/*
++ * NAND sync
++ */
++static void sl2312_nand_sync (struct mtd_info *mtd)
++{
++      struct nand_chip *this = mtd->priv;
++      DECLARE_WAITQUEUE (wait, current);
++
++      DEBUG (MTD_DEBUG_LEVEL3, "nand_sync: called\n");
++
++retry:
++      /* Grab the spinlock */
++      spin_lock_bh (&this->chip_lock);
++
++      /* See what's going on */
++      switch (this->state) {
++      case FL_READY:
++      case FL_SYNCING:
++              this->state = FL_SYNCING;
++              spin_unlock_bh (&this->chip_lock);
++              break;
++
++      default:
++              /* Not an idle state */
++              add_wait_queue (&this->wq, &wait);
++              spin_unlock_bh (&this->chip_lock);
++              schedule ();
++
++              remove_wait_queue (&this->wq, &wait);
++              goto retry;
++      }
++
++      /* Lock the device */
++      spin_lock_bh (&this->chip_lock);
++
++      /* Set the device to be ready again */
++      if (this->state == FL_SYNCING) {
++              this->state = FL_READY;
++              wake_up (&this->wq);
++      }
++
++      /* Unlock the device */
++      spin_unlock_bh (&this->chip_lock);
++}
++
++
++/*
++ * Scan for the NAND device
++ */
++int sl2312_nand_scan (struct mtd_info *mtd, int maxchips)
++{
++      int i, j, nand_maf_id, nand_dev_id, busw;
++      struct nand_chip *this = mtd->priv;
++      unsigned char id[4];
++
++      /* Get buswidth to select the correct functions*/
++      busw = this->options & NAND_BUSWIDTH_16;
++
++      /* check for proper chip_delay setup, set 20us if not */
++      if (!this->chip_delay)
++              this->chip_delay = 20;
++
++      /* check, if a user supplied command function given */
++      if (this->cmdfunc == NULL)
++              this->cmdfunc = sl2312_nand_command;
++
++      /* check, if a user supplied wait function given */
++      if (this->waitfunc == NULL)
++              this->waitfunc = sl2312_nand_waitfunc;
++
++      if (!this->select_chip)
++              this->select_chip = sl2312_nand_select_chip;
++      if (!this->write_byte)
++              this->write_byte = sl2312_nand_write_byte; //busw ? nand_write_byte16 : nand_write_byte;
++      if (!this->read_byte)
++              this->read_byte = sl2312_nand_read_byte; //busw ? nand_read_byte16 : nand_read_byte;
++//    if (!this->write_word)
++//            this->write_word = nand_write_word;
++//    if (!this->read_word)
++//            this->read_word = nand_read_word;
++//    if (!this->block_bad)
++              this->block_bad = sl2312_nand_block_bad; //nand_block_bad;
++      if (!this->block_markbad)
++              this->block_markbad = sl2312_nand_default_block_markbad;
++      if (!this->write_buf)
++              this->write_buf = sl2312_nand_write_buf; //busw ? nand_write_buf16 : nand_write_buf;
++      if (!this->read_buf)
++              this->read_buf = sl2312_nand_read_buf; //busw ? nand_read_buf16 : nand_read_buf;
++      if (!this->verify_buf)
++              this->verify_buf = sl2312_nand_verify_buf; //busw ? nand_verify_buf16 : nand_verify_buf;
++      if (!this->scan_bbt)
++              this->scan_bbt = sl2312_nand_scan_bbt;
++
++      /* Select the device */
++      this->select_chip(mtd, 0);
++
++      /* Read manufacturer and device IDs */
++      nand_read_id(0,id);
++
++      nand_maf_id = id[0];
++      nand_dev_id = id[1];
++
++      /* Print and store flash device information */
++      for (i = 0; nand_flash_ids[i].name != NULL; i++) {
++
++              if (nand_dev_id != nand_flash_ids[i].id)
++                      continue;
++
++              if (!mtd->name) mtd->name = nand_flash_ids[i].name;
++              this->chipsize = nand_flash_ids[i].chipsize << 20;
++
++              /* New devices have all the information in additional id bytes */
++              if (!nand_flash_ids[i].pagesize) {
++                      int extid;
++
++                      /* The 4th id byte is the important one */
++                      extid = id[3];
++                      /* Calc pagesize */
++                      mtd->oobblock = 1024 << (extid & 0x3);
++                      extid >>= 2;
++                      /* Calc oobsize */
++                      mtd->oobsize = (8 << (extid & 0x03)) * (mtd->oobblock / 512);
++                      extid >>= 2;
++                      /* Calc blocksize. Blocksize is multiples of 64KiB */
++                      mtd->erasesize = (64 * 1024)  << (extid & 0x03);
++                      extid >>= 2;
++                      /* Get buswidth information */
++                      busw = (extid & 0x01) ? NAND_BUSWIDTH_16 : 0;
++
++              } else {
++                      /* Old devices have this data hardcoded in the
++                       * device id table */
++                      mtd->erasesize = nand_flash_ids[i].erasesize;
++                      mtd->oobblock = nand_flash_ids[i].pagesize;
++                      mtd->oobsize = mtd->oobblock / 32;
++                      busw = nand_flash_ids[i].options & NAND_BUSWIDTH_16;
++              }
++
++              /* Check, if buswidth is correct. Hardware drivers should set
++               * this correct ! */
++              if (busw != (this->options & NAND_BUSWIDTH_16)) {
++                      printk (KERN_INFO "NAND device: Manufacturer ID:"
++                              " 0x%02x, Chip ID: 0x%02x (%s %s)\n", nand_maf_id, nand_dev_id,
++                              nand_manuf_ids[i].name , mtd->name);
++                      printk (KERN_WARNING
++                              "NAND bus width %d instead %d bit\n",
++                                      (this->options & NAND_BUSWIDTH_16) ? 16 : 8,
++                                      busw ? 16 : 8);
++                      this->select_chip(mtd, -1);
++                      return 1;
++              }
++
++              /* Calculate the address shift from the page size */
++              this->page_shift = ffs(mtd->oobblock) - 1;
++              this->bbt_erase_shift = this->phys_erase_shift = ffs(mtd->erasesize) - 1;
++              this->chip_shift = ffs(this->chipsize) - 1;
++
++              /* Set the bad block position */
++              this->badblockpos = mtd->oobblock > 512 ?
++                      NAND_LARGE_BADBLOCK_POS : NAND_SMALL_BADBLOCK_POS;
++
++              /* Get chip options, preserve non chip based options */
++              this->options &= ~NAND_CHIPOPTIONS_MSK;
++              this->options |= nand_flash_ids[i].options & NAND_CHIPOPTIONS_MSK;
++              /* Set this as a default. Board drivers can override it, if neccecary */
++              this->options |= NAND_NO_AUTOINCR;
++              /* Check if this is a not a samsung device. Do not clear the options
++               * for chips which are not having an extended id.
++               */
++              if (nand_maf_id != NAND_MFR_SAMSUNG && !nand_flash_ids[i].pagesize)
++                      this->options &= ~NAND_SAMSUNG_LP_OPTIONS;
++
++              /* Check for AND chips with 4 page planes */
++      //      if (this->options & NAND_4PAGE_ARRAY)
++      //              this->erase_cmd = multi_erase_cmd;
++      //      else
++      //              this->erase_cmd = single_erase_cmd;
++
++              /* Do not replace user supplied command function ! */
++      //      if (mtd->oobblock > 512 && this->cmdfunc == nand_command)
++      //              this->cmdfunc = nand_command_lp;
++
++              /* Try to identify manufacturer */
++              for (j = 0; nand_manuf_ids[j].id != 0x0; j++) {
++                      if (nand_manuf_ids[j].id == nand_maf_id)
++                              break;
++              }
++              printk (KERN_INFO "NAND device: Manufacturer ID:"
++                      " 0x%02x, Chip ID: 0x%02x (%s %s)\n", nand_maf_id, nand_dev_id,
++                      nand_manuf_ids[j].name , nand_flash_ids[i].name);
++              break;
++      }
++      /////////////////////////////
++
++      for (i=1; i < maxchips; i++) {
++              this->select_chip(mtd, i);
++
++              /* Send the command for reading device ID */
++              nand_read_id(1,id);
++
++              /* Read manufacturer and device IDs */
++              if (nand_maf_id != id[0] ||
++                  nand_dev_id != id[1])
++                      break;
++      }
++      if (i > 1)
++              printk(KERN_INFO "%d NAND chips detected\n", i);
++
++      /* Allocate buffers, if neccecary */
++      if (!this->oob_buf) {
++              size_t len;
++              len = mtd->oobsize << (this->phys_erase_shift - this->page_shift);
++              this->oob_buf = kmalloc (len, GFP_KERNEL);
++              if (!this->oob_buf) {
++                      printk (KERN_ERR "nand_scan(): Cannot allocate oob_buf\n");
++                      return -ENOMEM;
++              }
++              this->options |= NAND_OOBBUF_ALLOC;
++      }
++
++      if (!this->data_buf) {
++              size_t len;
++              len = mtd->oobblock + mtd->oobsize;
++              this->data_buf = kmalloc (len, GFP_KERNEL);
++              if (!this->data_buf) {
++                      if (this->options & NAND_OOBBUF_ALLOC)
++                              kfree (this->oob_buf);
++                      printk (KERN_ERR "nand_scan(): Cannot allocate data_buf\n");
++                      return -ENOMEM;
++              }
++              this->options |= NAND_DATABUF_ALLOC;
++      }
++
++      /* Store the number of chips and calc total size for mtd */
++      this->numchips = i;
++      mtd->size = i * this->chipsize;
++      /* Convert chipsize to number of pages per chip -1. */
++      this->pagemask = (this->chipsize >> this->page_shift) - 1;
++      /* Preset the internal oob buffer */
++      memset(this->oob_buf, 0xff, mtd->oobsize << (this->phys_erase_shift - this->page_shift));
++
++      /* If no default placement scheme is given, select an
++       * appropriate one */
++      if (!this->autooob) {
++              /* Select the appropriate default oob placement scheme for
++               * placement agnostic filesystems */
++              switch (mtd->oobsize) {
++              case 8:
++                      this->autooob = &nand_oob_8;
++                      break;
++              case 16:
++                      this->autooob = &nand_oob_16;
++                      break;
++              case 64:
++                      this->autooob = &nand_oob_64;
++                      break;
++              default:
++                      printk (KERN_WARNING "No oob scheme defined for oobsize %d\n",
++                              mtd->oobsize);
++                      BUG();
++              }
++      }
++
++      /* The number of bytes available for the filesystem to place fs dependend
++       * oob data */
++      if (this->options & NAND_BUSWIDTH_16) {
++              mtd->oobavail = mtd->oobsize - (this->autooob->eccbytes + 2);
++              if (this->autooob->eccbytes & 0x01)
++                      mtd->oobavail--;
++      } else
++              mtd->oobavail = mtd->oobsize - (this->autooob->eccbytes + 1);
++
++
++      /*
++       * check ECC mode, default to software
++       * if 3byte/512byte hardware ECC is selected and we have 256 byte pagesize
++       * fallback to software ECC
++      */
++      this->eccsize = 256;    /* set default eccsize */
++      this->eccbytes = 3;
++
++      switch (this->eccmode) {
++      case NAND_ECC_HW12_2048:
++              if (mtd->oobblock < 2048) {
++                      printk(KERN_WARNING "2048 byte HW ECC not possible on %d byte page size, fallback to SW ECC\n",
++                             mtd->oobblock);
++                      this->eccmode = NAND_ECC_SOFT;
++                      this->calculate_ecc = nand_calculate_ecc;
++                      this->correct_data = nand_correct_data;
++              } else
++                      this->eccsize = 2048;
++              break;
++
++      case NAND_ECC_HW3_512:
++      case NAND_ECC_HW6_512:
++      case NAND_ECC_HW8_512:
++              if (mtd->oobblock == 256) {
++                      printk (KERN_WARNING "512 byte HW ECC not possible on 256 Byte pagesize, fallback to SW ECC \n");
++                      this->eccmode = NAND_ECC_SOFT;
++                      this->calculate_ecc = nand_calculate_ecc;
++                      this->correct_data = nand_correct_data;
++              } else
++                      this->eccsize = 512; /* set eccsize to 512 */
++              break;
++
++      case NAND_ECC_HW3_256:
++              break;
++
++      case NAND_ECC_NONE:
++              printk (KERN_WARNING "NAND_ECC_NONE selected by board driver. This is not recommended !!\n");
++              this->eccmode = NAND_ECC_NONE;
++              break;
++
++      case NAND_ECC_SOFT:
++              this->calculate_ecc = nand_calculate_ecc;
++              this->correct_data = nand_correct_data;
++              break;
++
++      default:
++              printk (KERN_WARNING "Invalid NAND_ECC_MODE %d\n", this->eccmode);
++              BUG();
++      }
++
++      /* Check hardware ecc function availability and adjust number of ecc bytes per
++       * calculation step
++      */
++      switch (this->eccmode) {
++      case NAND_ECC_HW12_2048:
++              this->eccbytes += 4;
++      case NAND_ECC_HW8_512:
++              this->eccbytes += 2;
++      case NAND_ECC_HW6_512:
++              this->eccbytes += 3;
++//    case NAND_ECC_HW3_512:
++      case NAND_ECC_HW3_256:
++              if (this->calculate_ecc && this->correct_data && this->enable_hwecc)
++                      break;
++              printk (KERN_WARNING "No ECC functions supplied, Hardware ECC not possible\n");
++              BUG();
++      }
++
++      mtd->eccsize = this->eccsize;
++
++      /* Set the number of read / write steps for one page to ensure ECC generation */
++      switch (this->eccmode) {
++      case NAND_ECC_HW12_2048:
++              this->eccsteps = mtd->oobblock / 2048;
++              break;
++      case NAND_ECC_HW3_512:
++      case NAND_ECC_HW6_512:
++      case NAND_ECC_HW8_512:
++              this->eccsteps = mtd->oobblock / 512;
++              break;
++      case NAND_ECC_HW3_256:
++      case NAND_ECC_SOFT:
++              this->eccsteps = mtd->oobblock / 256;
++              break;
++
++      case NAND_ECC_NONE:
++              this->eccsteps = 1;
++              break;
++      }
++
++      /* Initialize state, waitqueue and spinlock */
++      this->state = FL_READY;
++      init_waitqueue_head (&this->wq);
++      spin_lock_init (&this->chip_lock);
++
++      /* De-select the device */
++      this->select_chip(mtd, 0);
++
++      /* Print warning message for no device */
++      if (!mtd->size) {
++              printk (KERN_WARNING "No NAND device found!!!\n");
++              return 1;
++      }
++
++      /* Fill in remaining MTD driver data */
++      mtd->type = MTD_NANDFLASH;
++      mtd->flags = MTD_CAP_NANDFLASH | MTD_ECC;
++      mtd->ecctype = MTD_ECC_SW;
++      mtd->erase = sl2312_nand_erase;
++      mtd->point = NULL;
++      mtd->unpoint = NULL;
++      mtd->read = sl2312_nand_read;
++      mtd->write = sl2312_nand_write;
++      mtd->read_ecc = sl2312_nand_read_ecc;
++      mtd->write_ecc = sl2312_nand_write_ecc;
++      mtd->read_oob = sl2312_nand_read_oob;
++      mtd->write_oob = sl2312_nand_write_oob;
++      mtd->readv = NULL;
++      mtd->writev = sl2312_nand_writev;
++      mtd->writev_ecc = sl2312_nand_writev_ecc;
++      mtd->sync = sl2312_nand_sync;
++      mtd->lock = NULL;
++      mtd->unlock = NULL;
++      mtd->suspend = NULL;
++      mtd->resume = NULL;
++      mtd->block_isbad = sl2312_nand_block_isbad;
++      mtd->block_markbad = sl2312_nand_block_markbad;
++
++      /* and make the autooob the default one */
++      memcpy(&mtd->oobinfo, this->autooob, sizeof(mtd->oobinfo));
++
++      mtd->owner = THIS_MODULE;
++
++      /* Build bad block table */
++      return this->scan_bbt (mtd);
++}
++
++/*End Add function*/
++
++/*
++ * Main initialization routine
++ */
++extern int nand_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_ecc, u_char *calc_ecc);
++
++int __init sl2312_mtd_init (void)
++{
++      struct nand_chip *this;
++      int err = 0;
++      struct mtd_partition *parts;
++      int nr_parts = 0;
++      int ret, data, *base;
++
++      printk("NAND MTD Driver Start Init ......\n");
++
++      base = (unsigned int *)(IO_ADDRESS(SL2312_GLOBAL_BASE) + 0x30);
++      data = *base;
++      data&=0xffffffeb;
++      data|=0x3; //disable p & s flash
++        *base = data;
++
++      /* Allocate memory for MTD device structure and private data */
++      sl2312_mtd = kmalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip), GFP_KERNEL);
++      if (!sl2312_mtd) {
++              printk ("Unable to allocate SL2312 NAND MTD device structure.\n");
++              err = -ENOMEM;
++              goto out;
++      }
++
++      //  sl2312_device_setup();
++
++      /* io is indirect via a register so don't need to ioremap address */
++
++      /* Get pointer to private data */
++      this = (struct nand_chip *) (&sl2312_mtd[1]);
++
++      /* Initialize structures */
++      memset((char *) sl2312_mtd, 0, sizeof(struct mtd_info));
++      memset((char *) this, 0, sizeof(struct nand_chip));
++
++      /* Link the private data with the MTD structure */
++      sl2312_mtd->priv = this;
++      sl2312_mtd->name = "sl2312-nand";
++
++      /* Set address of NAND IO lines */
++      this->IO_ADDR_R = (void __iomem *)IO_ADDRESS((SL2312_FLASH_CTRL_BASE+NFLASH_DATA)); //(unsigned long)&(sl2312_ndfmcptr->dtr);
++      this->IO_ADDR_W = (void __iomem *)IO_ADDRESS((SL2312_FLASH_CTRL_BASE+NFLASH_DATA)); //(unsigned long)&(sl2312_ndfmcptr->dtr);
++      this->read_byte = sl2312_nand_read_byte;
++    this->write_byte = sl2312_nand_write_byte;
++    this->write_buf = sl2312_nand_write_buf;
++      this->read_buf = sl2312_nand_read_buf;
++      this->verify_buf = sl2312_nand_verify_buf;
++      this->select_chip = sl2312_nand_select_chip;
++      this->block_bad = sl2312_nand_block_bad;
++      this->hwcontrol = sl2312_hwcontrol;
++      this->dev_ready = sl2312_device_ready;
++      this->cmdfunc = sl2312_nand_command;
++      this->waitfunc = sl2312_nand_waitfunc;
++      //this->calculate_ecc = sl2312_readecc;
++      this->enable_hwecc = sl2312_enable_hwecc;
++      this->eccmode = NAND_ECC_HW3_512;
++      /*this->eccsize = 512;  */
++      /* 20 us command delay time */
++      this->chip_delay = 20;
++
++      this->correct_data = nand_correct_data;
++//    this->scan_bbt = sl2312_nand_scan_bbt;
++
++      /* Allocate memory for internal data buffer */
++      this->data_buf = kmalloc (sizeof(u_char) * (sl2312_mtd->oobblock + sl2312_mtd->oobsize), GFP_KERNEL);
++      if (!this->data_buf) {
++              printk ("Unable to allocate NAND data buffer.\n");
++              err = -ENOMEM;
++              goto out_ior;
++      }
++
++      /* Scan to find existance of the device */
++      if (sl2312_nand_scan(sl2312_mtd, 1)) {
++              err = -ENXIO;
++              goto out_ior;
++      }
++
++      /* Register the partitions */
++      parts = sl2312_partitions;
++      nr_parts = sizeof(sl2312_partitions)/sizeof(*parts);
++
++      ret = add_mtd_partitions(sl2312_mtd, sl2312_partitions, nr_parts);
++      /*If we got an error, free all resources.*/
++      if (ret < 0) {
++              del_mtd_partitions(sl2312_mtd);
++              map_destroy(sl2312_mtd);
++      }
++      goto out;
++
++//out_buf:
++//    kfree (this->data_buf);
++out_ior:
++out:
++      printk("NAND MTD Driver Init Success ......\n");
++      return err;
++}
++
++module_init(sl2312_mtd_init);
++
++/*
++ * Clean up routine
++ */
++#ifdef MODULE
++static void __exit sl2312_cleanup (void)
++{
++      struct nand_chip *this = (struct nand_chip *) &sl2312_mtd[1];
++
++      /* Unregister partitions */
++      del_mtd_partitions(sl2312_mtd);
++
++      /* Unregister the device */
++      del_mtd_device (sl2312_mtd);
++
++      /* Free internal data buffers */
++      kfree (this->data_buf);
++
++      /* Free the MTD device structure */
++      kfree (sl2312_mtd);
++}
++module_exit(sl2312_cleanup);
++#endif
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Alice Hennessy <ahennessy@mvista.com>");
++MODULE_DESCRIPTION("Glue layer for SmartMediaCard on Toshiba RBsl2312");
+Index: linux-2.6.23.16/drivers/mtd/nand/sl2312-flash-nand.h
+===================================================================
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.23.16/drivers/mtd/nand/sl2312-flash-nand.h       2008-03-15 17:04:25.878696749 +0200
+@@ -0,0 +1,24 @@
++#ifndef SL2312_FLASH_NAND_H
++#define SL2312_FLASH_NAND_H
++
++#include <linux/wait.h>
++#include <linux/spinlock.h>
++
++/*Add function*/
++static void nand_read_id(int chip_no,unsigned char *id);
++
++
++
++#define       NFLASH_WiDTH8              0x00000000
++#define       NFLASH_WiDTH16             0x00000400
++#define       NFLASH_WiDTH32             0x00000800
++#define NFLASH_CHIP0_EN            0x00000000  // 16th bit = 0
++#define NFLASH_CHIP1_EN            0x00010000  // 16th bit = 1
++#define       NFLASH_DIRECT              0x00004000
++#define       NFLASH_INDIRECT            0x00000000
++
++
++#define       DWIDTH             NFLASH_WiDTH8
++
++
++#endif /* SL2312_FLASH_NAND_H */
+Index: linux-2.6.23.16/include/linux/mtd/kvctl.h
+===================================================================
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.23.16/include/linux/mtd/kvctl.h  2008-03-15 17:03:17.874821522 +0200
+@@ -0,0 +1,40 @@
++#ifndef KVCTL_H
++#define KVCTL_H
++
++#define VCTL_HEAD_SIZE        8
++#define VCTL_ENTRY_LEN        20
++
++typedef struct
++{
++  char header[4];
++  unsigned int entry_num;
++} vctl_mheader;
++
++typedef struct
++{
++  char header[4];
++  unsigned int size;
++  unsigned int type;
++  char majorver[4];
++  char minorver[4];
++  unsigned char *payload;
++} vctl_entry;
++
++typedef struct
++{
++  unsigned char mac[6];
++  unsigned char vlanid;
++  unsigned char vlanmap;
++} vlaninfo;
++
++#define VCT_VENDORSPEC                0
++#define VCT_BOOTLOADER                1
++#define VCT_KERNEL            2
++#define VCT_VERCTL            3
++#define VCT_CURRCONF          4
++#define VCT_DEFAULTCONF               5
++#define VCT_ROOTFS            6
++#define VCT_APP                       7
++#define VCT_VLAN              8
++
++#endif
+Index: linux-2.6.23.16/drivers/mtd/maps/Makefile
+===================================================================
+--- linux-2.6.23.16.orig/drivers/mtd/maps/Makefile     2008-03-15 17:03:14.374622039 +0200
++++ linux-2.6.23.16/drivers/mtd/maps/Makefile  2008-03-15 17:03:17.874821522 +0200
+@@ -71,3 +71,7 @@
+ obj-$(CONFIG_MTD_OMAP_NOR)    += omap_nor.o
+ obj-$(CONFIG_MTD_MTX1)                += mtx-1_flash.o
+ obj-$(CONFIG_MTD_TQM834x)     += tqm834x.o
++###### for Storlink Soc #######
++obj-$(CONFIG_MTD_SL2312_CFI) += sl2312-flash-cfi.o
++obj-$(CONFIG_MTD_SL2312_SERIAL_ATMEL) += sl2312-flash-atmel.o
++obj-$(CONFIG_MTD_SL2312_SERIAL_ST) += sl2312-flash-m25p80.o
diff --git a/target/linux/storm/patches/1021-serial.patch b/target/linux/storm/patches/1021-serial.patch
new file mode 100644 (file)
index 0000000..90880d6
--- /dev/null
@@ -0,0 +1,2825 @@
+Index: linux-2.6.23.16/drivers/serial/it8712.c
+===================================================================
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.23.16/drivers/serial/it8712.c    2008-03-15 17:59:53.568330991 +0200
+@@ -0,0 +1,858 @@
++/*
++ *  linux/drivers/char/serial_uart00.c
++ *
++ *  Driver for UART00 serial ports
++ *
++ *  Based on drivers/char/serial_amba.c, by ARM Limited &
++ *                                          Deep Blue Solutions Ltd.
++ *  Copyright 2001 Altera Corporation
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++ *
++ *  $Id: it8712.c,v 1.2 2006/06/06 06:36:04 middle Exp $
++ *
++ */
++#include <linux/module.h>
++#include <linux/tty.h>
++#include <linux/ioport.h>
++#include <linux/init.h>
++#include <linux/serial.h>
++#include <linux/console.h>
++#include <linux/sysrq.h>
++#include <asm/hardware.h>
++#include <asm/system.h>
++#include <asm/io.h>
++#include <asm/irq.h>
++#include <asm/uaccess.h>
++#include <asm/bitops.h>
++#include <asm/sizes.h>
++
++#if defined(CONFIG_SERIAL_IT8712_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
++#define SUPPORT_SYSRQ
++#endif
++
++#include <linux/serial_core.h>
++#include <asm/arch/sl2312.h>
++#include <asm/arch/int_ctrl.h>
++#include <asm/arch/it8712.h>
++#include "it8712.h"
++
++//#define DEBUG           1
++#define UART_NR               1
++
++#define SERIAL_IT8712_NAME    "ttySI"
++#define SERIAL_IT8712_MAJOR   204
++#define SERIAL_IT8712_MINOR   41      /* Temporary - will change in future */
++#define SERIAL_IT8712_NR      UART_NR
++#define UART_PORT_SIZE 0x50
++#define LPC_HOST_CONTINUE_MODE        0x00000040
++
++#define IT8712_NO_PORTS         UART_NR
++#define IT8712_ISR_PASS_LIMIT 256
++
++#define LPC_BUS_CTRL  *(unsigned int*)(IO_ADDRESS(SL2312_LPC_HOST_BASE + 4))
++#define LPC_BUS_STATUS        *(unsigned int*)(IO_ADDRESS(SL2312_LPC_HOST_BASE + 4))
++#define LPC_SERIAL_IRQ_CTRL   *(unsigned int*)(IO_ADDRESS(SL2312_LPC_HOST_BASE + 8))
++#define LPC_SERIAL_IRQ_STATUS *(unsigned int*)(IO_ADDRESS(SL2312_LPC_HOST_BASE + 0x0c))
++#define LPC_SERIAL_IRQ_TRITYPE *(unsigned int*)(IO_ADDRESS(SL2312_LPC_HOST_BASE + 0x10))
++#define LPC_SERIAL_IRQ_POLARITY       *(unsigned int*)(IO_ADDRESS(SL2312_LPC_HOST_BASE + 0x14))
++#define LPC_SERIAL_IRQ_ENABLE *(unsigned int*)(IO_ADDRESS(SL2312_LPC_HOST_BASE + 0x18))
++
++
++
++
++/*
++ * Access macros for the SL2312 UARTs
++ */
++#define UART_GET_INT_STATUS(p)        (inb(((p)->membase+UART_IIR)) & 0x0F)  // interrupt identification
++#define UART_PUT_IER(p, c)      outb(c,((p)->membase+UART_IER))         // interrupt enable
++#define UART_GET_IER(p)         inb(((p)->membase+UART_IER))
++#define UART_PUT_CHAR(p, c)     outb(c,((p)->membase+UART_TX))         // transmitter holding
++#define UART_GET_CHAR(p)        inb(((p)->membase+UART_RX))            // receive buffer
++#define UART_GET_LSR(p)         inb(((p)->membase+UART_LSR))            // line status
++#define UART_GET_MSR(p)         inb(((p)->membase+UART_MSR))            // modem status
++#define UART_GET_MCR(p)         inb(((p)->membase+UART_MCR))            // modem control
++#define UART_PUT_MCR(p, c)      outb(c,((p)->membase+UART_MCR))
++#define UART_GET_LCR(p)         inb(((p)->membase+UART_LCR))       // mode control
++#define UART_PUT_LCR(p, c)      outb(c,((p)->membase+UART_LCR))
++#define UART_PUT_FCR(p, c)      outb(c,((p)->membase+UART_FCR))       // fifo control
++#define UART_GET_DIV_HI(p)    inb(((p)->membase+UART_DLM))
++#define UART_PUT_DIV_HI(p, c) outb(c,((p)->membase+UART_DLM))
++#define UART_GET_DIV_LO(p)    inb(((p)->membase+UART_DLL))
++#define UART_PUT_DIV_LO(p, c) outb(c,((p)->membase+UART_DLL))
++#define UART_PUT_MDR(p, c)      outb(c,UART_MDR((p)->membase))
++#define UART_RX_DATA(s)               ((s) & UART_LSR_DR)
++#define UART_TX_READY(s)      ((s) & UART_LSR_THRE)
++
++static void it8712_stop_tx(struct uart_port *port, u_int from_tty)
++{
++        unsigned int reg;
++
++        //printk("it8712 stop tx : \n");
++        reg = UART_GET_IER(port);
++        reg &= ~(UART_IER_THRI);
++      UART_PUT_IER(port, reg);
++}
++
++static void it8712_stop_rx(struct uart_port *port)
++{
++        unsigned int reg;
++
++        //printk("it8712 stop rx : \n");
++        reg = UART_GET_IER(port);
++        reg &= ~(UART_IER_RDI);
++      UART_PUT_IER(port, reg);
++
++}
++
++static void it8712_enable_ms(struct uart_port *port)
++{
++        unsigned int reg;
++
++        //printk("it8712 enable ms : \n");
++
++        reg = UART_GET_IER(port);
++        reg |= (UART_IER_MSI);
++      UART_PUT_IER(port, reg);
++
++}
++
++static void it8712_rx_chars(struct uart_port *port, struct pt_regs *regs)
++{
++      struct tty_struct *tty = port->info->tty;
++      unsigned int status, mask, ch, flg, ignored = 0;
++
++ //       printk("it8712_rx_chars : \n");
++      status = UART_GET_LSR(port);
++      while (UART_RX_DATA(status)) {
++
++              /*
++               * We need to read rds before reading the
++               * character from the fifo
++               */
++              ch = UART_GET_CHAR(port);
++              port->icount.rx++;
++
++              if (tty->flip.count >= TTY_FLIPBUF_SIZE)
++                      goto ignore_char;
++
++              flg = TTY_NORMAL;
++
++              /*
++               * Note that the error handling code is
++               * out of the main execution path
++               */
++
++              if (status & (UART_LSR_OE|UART_LSR_PE|UART_LSR_FE|UART_LSR_BI|UART_LSR_DE))
++                      goto handle_error;
++              if (uart_handle_sysrq_char(port, ch, regs))
++                      goto ignore_char;
++
++      error_return:
++              *tty->flip.flag_buf_ptr++ = flg;
++              *tty->flip.char_buf_ptr++ = ch;
++              tty->flip.count++;
++      ignore_char:
++              status = UART_GET_LSR(port);
++      } // end of while
++out:
++      tty_flip_buffer_push(tty);
++      return;
++
++handle_error:
++      if (status & UART_LSR_BI) {
++              status &= ~(UART_LSR_FE);
++              port->icount.brk++;
++
++#ifdef SUPPORT_SYSRQ
++              if (uart_handle_break(port))
++                      goto ignore_char;
++#endif
++      } else if (status & UART_LSR_PE)
++              port->icount.parity++;
++      else if (status & UART_LSR_FE)
++              port->icount.frame++;
++
++      if (status & UART_LSR_OE)
++              port->icount.overrun++;
++
++      if (status & port->ignore_status_mask) {
++              if (++ignored > 100)
++                      goto out;
++              goto ignore_char;
++      }
++
++      mask = status & port->read_status_mask;
++
++      if (mask & UART_LSR_BI)
++              flg = TTY_BREAK;
++      else if (mask & UART_LSR_PE)
++              flg = TTY_PARITY;
++      else if (mask & UART_LSR_FE)
++              flg = TTY_FRAME;
++
++      if (status & UART_LSR_OE) {
++              /*
++               * CHECK: does overrun affect the current character?
++               * ASSUMPTION: it does not.
++               */
++              *tty->flip.flag_buf_ptr++ = flg;
++              *tty->flip.char_buf_ptr++ = ch;
++              tty->flip.count++;
++              if (tty->flip.count >= TTY_FLIPBUF_SIZE)
++                      goto ignore_char;
++              ch = 0;
++              flg = TTY_OVERRUN;
++      }
++#ifdef SUPPORT_SYSRQ
++      port->sysrq = 0;
++#endif
++      goto error_return;
++}
++
++static void it8712_tx_chars(struct uart_port *port)
++{
++        struct circ_buf *xmit = &port->info->xmit;
++      int count;
++
++      if (port->x_char) {
++              while(!(UART_GET_LSR(port)&UART_LSR_THRE));
++              UART_PUT_CHAR(port, port->x_char);
++              port->icount.tx++;
++              port->x_char = 0;
++
++              return;
++      }
++      if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
++              it8712_stop_tx(port, 0);
++              return;
++      }
++
++      count = port->fifosize >> 1;
++      do {
++              while(!(UART_GET_LSR(port)&UART_LSR_THRE));
++              UART_PUT_CHAR(port, xmit->buf[xmit->tail]);
++              xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
++              port->icount.tx++;
++              if (uart_circ_empty(xmit))
++                      break;
++      } while (--count > 0);
++
++      if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
++              uart_write_wakeup(port);
++
++      if (uart_circ_empty(xmit))
++              it8712_stop_tx(port, 0);
++}
++
++static void it8712_start_tx(struct uart_port *port, unsigned int tty_start)
++{
++        unsigned int reg;
++
++        //printk("it8712 start tx : \n");
++        reg = UART_GET_IER(port);
++        reg |= (UART_IER_THRI);
++      UART_PUT_IER(port, reg);
++      it8712_tx_chars(port);
++}
++
++static void it8712_modem_status(struct uart_port *port)
++{
++      unsigned int status;
++
++//        printk("it8712 modem status : \n");
++
++      status = UART_GET_MSR(port);
++
++      if (!(status & (UART_MSR_DCTS | UART_MSR_DDSR |
++                     UART_MSR_TERI | UART_MSR_DDCD)))
++              return;
++
++        if (status & UART_MSR_DDCD)
++                uart_handle_dcd_change(port, status & UART_MSR_DCD);
++
++        if (status & UART_MSR_DDSR)
++                port->icount.dsr++;
++
++        if (status & UART_MSR_DCTS)
++                uart_handle_cts_change(port, status & UART_MSR_CTS);
++
++      wake_up_interruptible(&port->info->delta_msr_wait);
++
++}
++
++static irqreturn_t  it8712_int(int irq, void *dev_id, struct pt_regs *regs)
++{
++      struct uart_port *port = dev_id;
++      unsigned int status, pass_counter = 0, data;
++
++
++              data = LPC_SERIAL_IRQ_STATUS;
++      if((data&0x10)==0x10)
++      {
++              status = UART_GET_INT_STATUS(port);
++              do {
++//                         printk("it8712_int: status %x \n", status);
++                      switch(status)
++                      {
++                         case UART_IIR_RDI:
++                         case UART_IIR_RLSI:
++                         case UART_IIR_RCTO:
++                              it8712_rx_chars(port, regs);
++                         break;
++                         case UART_IIR_THRI:
++                              it8712_tx_chars(port);
++                         break;
++                         case UART_IIR_MSI:
++                              it8712_modem_status(port);
++                         break;
++                         default:
++                         break;
++                      }
++                      if (pass_counter++ > IT8712_ISR_PASS_LIMIT)
++                              break;
++
++                      status = UART_GET_INT_STATUS(port);
++              } while (status);
++      }
++
++              status = 0;
++        status |= (IRQ_LPC_MASK);
++        *((volatile unsigned int *)IRQ_CLEAR(IO_ADDRESS(SL2312_INTERRUPT_BASE))) = status;
++
++      //cnt=0;
++      //do{
++      //      data = LPC_SERIAL_IRQ_STATUS;
++              LPC_SERIAL_IRQ_STATUS = data;
++      //      cnt++;
++      //}while(data);
++      //if(cnt>2)
++      //      printf("it8712_uart_Isr clear LPC_SERIAL_IRQ_STATUS %x \n", cnt);
++        return IRQ_HANDLED;
++}
++
++static u_int it8712_tx_empty(struct uart_port *port)
++{
++//        printk("it8712 tx empty : \n");
++
++      return ((UART_GET_LSR(port) & UART_LSR_THRE)? TIOCSER_TEMT : 0);
++}
++
++static u_int it8712_get_mctrl(struct uart_port *port)
++{
++      unsigned int result = 0;
++      unsigned int status;
++
++//        printk("it8712 get mctrl : \n");
++
++      status = UART_GET_MSR(port);
++      if (status & UART_MSR_DCD)
++              result |= TIOCM_CAR;
++      if (status & UART_MSR_DSR)
++              result |= TIOCM_DSR;
++      if (status & UART_MSR_CTS)
++              result |= TIOCM_CTS;
++      if (status & UART_MSR_RI)
++              result |= TIOCM_RI;
++
++      return result;
++}
++
++static void it8712_set_mctrl_null(struct uart_port *port, u_int mctrl)
++{
++}
++
++static void it8712_break_ctl(struct uart_port *port, int break_state)
++{
++      unsigned int lcr;
++
++//        printk("it8712 break ctl : \n");
++
++      lcr = UART_GET_LCR(port);
++      if (break_state == -1)
++              lcr |= UART_LCR_SBC;
++      else
++              lcr &= ~UART_LCR_SBC;
++      UART_PUT_LCR(port, lcr);
++}
++
++static inline u_int uart_calculate_quot(struct uart_port *port, u_int baud)
++{
++      u_int quot;
++
++      /* Special case: B0 rate */
++      if (!baud)
++              baud = 9600;
++
++      quot = (port->uartclk/(16 * baud)) ;
++
++      return quot;
++}
++static void it8712_set_termios(struct uart_port *port, struct termios *termios,
++                               struct termios *old)
++{
++      unsigned int  uart_mc, old_ier, baud, quot;
++      unsigned long flags;
++
++        termios->c_cflag |= CREAD;
++        termios->c_cflag |= CLOCAL;
++#ifdef DEBUG
++      printk("it8712_set_cflag(0x%x) called\n", cflag);
++#endif
++        baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16);
++        quot = uart_get_divisor(port, baud);
++
++      /* byte size and parity */
++      switch (termios->c_cflag & CSIZE) {
++      case CS5:
++              uart_mc = UART_LCR_WLEN5;
++              break;
++      case CS6:
++              uart_mc = UART_LCR_WLEN6;
++              break;
++      case CS7:
++              uart_mc = UART_LCR_WLEN7;
++              break;
++      default: // CS8
++              uart_mc = UART_LCR_WLEN8;
++              break;
++      }
++
++      if (termios->c_cflag & CSTOPB)
++              uart_mc|= UART_LCR_STOP;
++      if (termios->c_cflag & PARENB) {
++              uart_mc |= UART_LCR_EVEN;
++              if (!(termios->c_cflag & PARODD))
++                      uart_mc |= UART_LCR_ODD;
++      }
++
++        spin_lock_irqsave(&port->lock, flags);
++        /*
++         * Update the per-port timeout
++         */
++        uart_update_timeout(port, termios->c_cflag, baud);
++      port->read_status_mask = UART_LSR_OE;
++      if (termios->c_iflag & INPCK)
++              port->read_status_mask |= UART_LSR_FE | UART_LSR_PE;
++      if (termios->c_iflag & (BRKINT | PARMRK))
++              port->read_status_mask |= UART_LSR_BI;
++
++      /*
++       * Characters to ignore
++       */
++      port->ignore_status_mask = 0;
++      if (termios->c_iflag & IGNPAR)
++              port->ignore_status_mask |= UART_LSR_FE | UART_LSR_PE;
++      if (termios->c_iflag & IGNBRK) {
++              port->ignore_status_mask |= UART_LSR_BI;
++              /*
++               * If we're ignoring parity and break indicators,
++               * ignore overruns to (for real raw support).
++               */
++              if (termios->c_iflag & IGNPAR)
++                      port->ignore_status_mask |= UART_LSR_OE;
++      }
++
++      old_ier = UART_GET_IER(port);
++
++        if(UART_ENABLE_MS(port, termios->c_cflag))
++             old_ier |= UART_IER_MSI;
++
++      /* Set baud rate */
++      quot = quot / 13;
++      UART_PUT_LCR(port, UART_LCR_DLAB);
++      UART_PUT_DIV_LO(port, (quot & 0xff));
++      UART_PUT_DIV_HI(port, ((quot & 0xf00) >> 8));
++
++      UART_PUT_LCR(port, uart_mc);
++//    UART_PUT_LCR(port, 0x07); // ???? it is wired
++        UART_PUT_MCR(port, 0x08);
++        UART_PUT_FCR(port, 0x01);
++      UART_PUT_IER(port, 0x07);
++
++      spin_unlock_irqrestore(&port->lock, flags);
++}
++
++static int it8712_startup(struct uart_port *port)
++{
++      int retval, i;
++      unsigned int regs;
++
++        //printk("it8712 startup : \n");
++
++      /*
++       * Use iobase to store a pointer to info. We need this to start a
++       * transmission as the tranmittr interrupt is only generated on
++       * the transition to the idle state
++       */
++
++      //      regs = 0;
++    //    regs |= (IRQ_LPC_MASK);
++    //    *((volatile unsigned int *)IRQ_CLEAR(IO_ADDRESS(SL2312_INTERRUPT_BASE))) = regs;
++
++      /*
++       * Allocate the IRQ
++       */
++      retval = request_irq(port->irq, it8712_int, SA_INTERRUPT, "it8712", port);
++      if (retval)
++              return retval;
++
++      //printk("Init LPC int...........\n");
++        /* setup interrupt controller  */
++        regs = *((volatile unsigned int *)IRQ_TMODE(IO_ADDRESS(SL2312_INTERRUPT_BASE)));
++        regs &= ~(IRQ_LPC_MASK);
++        *((volatile unsigned int *)IRQ_TMODE(IO_ADDRESS(SL2312_INTERRUPT_BASE))) = regs;
++        regs = *((volatile unsigned int *)IRQ_TLEVEL(IO_ADDRESS(SL2312_INTERRUPT_BASE)));
++        regs &= ~(IRQ_LPC_MASK);
++        *((volatile unsigned int *)IRQ_TLEVEL(IO_ADDRESS(SL2312_INTERRUPT_BASE))) = regs;
++        *((volatile unsigned int *)IRQ_MASK(IO_ADDRESS(SL2312_INTERRUPT_BASE))) |= (unsigned int)(IRQ_LPC_MASK);
++
++      LPC_SERIAL_IRQ_POLARITY = 0x10; //0x10; //0x02;
++      LPC_SERIAL_IRQ_TRITYPE = 0x10; //0x10;//
++      LPC_SERIAL_IRQ_ENABLE = 0x10;
++
++      LPC_BUS_CTRL = 0xc0;
++      LPC_SERIAL_IRQ_CTRL = 0xc0;
++      for(i=0;i<1000;i++) ;
++      LPC_SERIAL_IRQ_CTRL = 0x80;
++      /*
++       * Finally, enable interrupts. Use the TII interrupt to minimise
++       * the number of interrupts generated. If higher performance is
++       * needed, consider using the TI interrupt with a suitable FIFO
++       * threshold
++       */
++      //UART_PUT_IER(port, (UART_IER_RDI|UART_IER_THRI));
++      UART_PUT_IER(port, (UART_IER_RDI|UART_IER_THRI|UART_IER_RLSI));//middle
++
++      return 0;
++}
++
++static void it8712_shutdown(struct uart_port *port)
++{
++        //printk("it8712 shutdown : \n");
++
++      /*
++       * disable all interrupts, disable the port
++       */
++      UART_PUT_IER(port, 0x0);
++
++      /* disable break condition and fifos */
++//    UART_PUT_MCR(port, (UART_GET_MCR(port)&UART_MCR_MASK));
++
++      /*
++       * Free the interrupt
++       */
++      free_irq(port->irq, port);
++}
++
++static const char *it8712_type(struct uart_port *port)
++{
++      return port->type == PORT_IT8712 ? "IT8712" : NULL;
++}
++
++/*
++ * Release the memory region(s) being used by 'port'
++ */
++static void it8712_release_port(struct uart_port *port)
++{
++//        printk("it8712 release port : \n");
++
++      release_mem_region(port->mapbase, UART_PORT_SIZE);
++}
++
++/*
++ * Request the memory region(s) being used by 'port'
++ */
++static int it8712_request_port(struct uart_port *port)
++{
++      return request_mem_region(port->mapbase, UART_PORT_SIZE,
++                                  "serial_it8712") != NULL ? 0 : -EBUSY;
++}
++
++/*
++ * Configure/autoconfigure the port.
++ */
++static void it8712_config_port(struct uart_port *port, int flags)
++{
++
++      if (flags & UART_CONFIG_TYPE) {
++              if (it8712_request_port(port) == 0)
++                      port->type = PORT_IT8712;
++      }
++}
++
++/*
++ * verify the new serial_struct (for TIOCSSERIAL).
++ */
++static int it8712_verify_port(struct uart_port *port, struct serial_struct *ser)
++{
++      int ret = 0;
++
++      if (ser->type != PORT_UNKNOWN && ser->type != PORT_UART00)
++              ret = -EINVAL;
++      if (ser->irq < 0 || ser->irq >= NR_IRQS)
++              ret = -EINVAL;
++      if (ser->baud_base < 9600)
++              ret = -EINVAL;
++      return ret;
++}
++
++static struct uart_ops it8712_pops = {
++      .tx_empty       = it8712_tx_empty,
++      .set_mctrl      = it8712_set_mctrl_null,
++      .get_mctrl      = it8712_get_mctrl,
++      .stop_tx        = it8712_stop_tx,
++      .start_tx       = it8712_start_tx,
++      .stop_rx        = it8712_stop_rx,
++      .enable_ms      = it8712_enable_ms,
++      .break_ctl      = it8712_break_ctl,
++      .startup        = it8712_startup,
++      .shutdown       = it8712_shutdown,
++      .set_termios    = it8712_set_termios,
++      .type           = it8712_type,
++      .release_port   = it8712_release_port,
++      .request_port   = it8712_request_port,
++      .config_port    = it8712_config_port,
++      .verify_port    = it8712_verify_port,
++};
++
++#ifdef CONFIG_ARCH_SL2312
++
++static struct uart_port it8712_ports[UART_NR] = {
++      {
++              membase:        (void *)0,
++              mapbase:        0,
++              iotype:         SERIAL_IO_MEM,
++              irq:            0,
++              uartclk:        UART_CLK/2,
++              fifosize:       16,
++              ops:            &it8712_pops,
++              flags:          ASYNC_BOOT_AUTOCONF,
++      }
++};
++
++#endif
++
++#ifdef CONFIG_SERIAL_IT8712_CONSOLE
++#ifdef used_and_not_const_char_pointer
++static int it8712_console_read(struct uart_port *port, char *s, u_int count)
++{
++      unsigned int status;
++      int c;
++#ifdef DEBUG
++      printk("it8712_console_read() called\n");
++#endif
++
++      c = 0;
++      while (c < count) {
++              status = UART_GET_LSR(port);
++              if (UART_RX_DATA(status)) {
++                      *s++ = UART_GET_CHAR(port);
++                      c++;
++              } else {
++                      // nothing more to get, return
++                      return c;
++              }
++      }
++      // return the count
++      return c;
++}
++#endif
++static void it8712_console_write(struct console *co, const char *s, unsigned count)
++{
++#ifdef CONFIG_ARCH_SL2312
++      struct uart_port *port = it8712_ports + co->index;
++      unsigned int status, old_ies;
++      int i;
++
++      /*
++       *      First save the CR then disable the interrupts
++       */
++      old_ies = UART_GET_IER(port);
++      //if(old_ies!=7)
++      //{
++      //
++      //      printk("old_ies = %x\n",old_ies);
++      //      old_ies = 7;
++      //}
++      UART_PUT_IER(port,0x0);
++
++      /*
++       *      Now, do each character
++       */
++      for (i = 0; i < count; i++) {
++              do {
++                      status = UART_GET_LSR(port);
++              } while (!UART_TX_READY(status));
++              UART_PUT_CHAR(port, s[i]);
++              if (s[i] == '\n') {
++                      do {
++                              status = UART_GET_LSR(port);
++                      } while (!UART_TX_READY(status));
++                      UART_PUT_CHAR(port, '\r');
++              }
++      }
++
++      /*
++       *      Finally, wait for transmitter to become empty
++       *      and restore the IES
++       */
++      do {
++              status = UART_GET_LSR(port);
++      } while (!(status&UART_LSR_THRE));
++      UART_PUT_IER(port, old_ies);
++#endif
++}
++
++static void /*__init*/ it8712_console_get_options(struct uart_port *port, int *baud, int *parity, int *bits)
++{
++      //printk("it8712 console get options : \n");
++
++      u_int uart_mc, quot;
++      uart_mc= UART_GET_MCR(port);
++
++      *parity = 'n';
++      if (uart_mc & UART_LCR_PARITY) {
++              if (uart_mc & UART_LCR_EVEN)
++                      *parity = 'e';
++              else
++                      *parity = 'o';
++      }
++
++      switch (uart_mc & UART_LCR_MSK){
++
++      case UART_LCR_WLEN5:
++              *bits = 5;
++              break;
++      case UART_LCR_WLEN6:
++              *bits = 6;
++              break;
++      case UART_LCR_WLEN7:
++              *bits = 7;
++              break;
++      case UART_LCR_WLEN8:
++              *bits = 8;
++              break;
++      }
++      UART_PUT_MCR(port,UART_LCR_DLAB);
++      quot = UART_GET_DIV_LO(port) | (UART_GET_DIV_HI(port) << 8);
++      UART_PUT_MCR(port,uart_mc);
++      *baud = (port->uartclk / (16 *quot));
++}
++
++static int __init it8712_console_setup(struct console *co, char *options)
++{
++      struct uart_port *port;
++      int baud = 38400;
++      int bits = 8;
++      int parity = 'n';
++      int flow= 'n';
++      int base;//, irq;
++      int i ;
++
++      printk("it8712 console setup : \n");
++
++      LPCSetConfig(0, 0x02, 0x01);
++        LPCSetConfig(LDN_SERIAL1, 0x30, 0x1);
++        LPCSetConfig(LDN_SERIAL1, 0x23, 0x0);
++      base = IT8712_IO_BASE;
++      base += ((LPCGetConfig(LDN_SERIAL1, 0x60) << 8) + LPCGetConfig(LDN_SERIAL1, 0x61));
++      it8712_ports[0].mapbase = base;
++      it8712_ports[0].membase = (void *)IO_ADDRESS(base);
++      it8712_ports[0].irq = IRQ_LPC_OFFSET;
++    //        irq = LPCGetConfig(LDN_SERIAL1, 0x70);
++      //it8712_ports[0].irq += irq;
++
++      //printk("it8712 irq is %x \n", it8712_ports[0].irq);
++
++      // setup LPC Host 'quiet mode'
++      //*((volatile unsigned int *)IO_ADDRESS((SL2312_LPC_HOST_BASE+0x04))) |= LPC_HOST_CONTINUE_MODE ;
++      //for(i=0;i<1000;i++) ;                                         // delay
++      //*((volatile unsigned int *)IO_ADDRESS((SL2312_LPC_HOST_BASE+0x04))) &= ~(LPC_HOST_CONTINUE_MODE) ;
++      LPC_BUS_CTRL = 0xc0;
++      LPC_SERIAL_IRQ_CTRL = 0xc0;
++      for(i=0;i<1000;i++) ;
++      LPC_SERIAL_IRQ_CTRL = 0x80;
++
++#ifdef CONFIG_ARCH_SL2312
++      /*
++       * Check whether an invalid uart number has been specified, and
++       * if so, search for the first available port that does have
++       * console support.
++       */
++      port = uart_get_console(it8712_ports,IT8712_NO_PORTS,co);
++#else
++      return -ENODEV;
++#endif
++
++      if (options)
++              uart_parse_options(options, &baud, &parity, &bits, &flow);
++      else
++              it8712_console_get_options(port, &baud, &parity, &bits);
++
++      return uart_set_options(port, co, baud, parity, bits, flow);
++}
++
++extern struct uart_driver it8712_reg;
++static struct console it8712_console = {
++      .name           = SERIAL_IT8712_NAME,
++      .write          = it8712_console_write,
++      .device         = uart_console_device,
++        .setup          = it8712_console_setup,
++      .flags          = CON_PRINTBUFFER,
++      .index          = 0,
++        .data           = &it8712_reg,
++};
++
++static int __init it8712_console_init(void)
++{
++      register_console(&it8712_console);
++        return 0;
++}
++
++console_initcall(it8712_console_init);
++
++#define IT8712_CONSOLE        &it8712_console
++#else
++#define IT8712_CONSOLE        NULL
++#endif
++
++static struct uart_driver it8712_reg = {
++      .owner                  = NULL,
++      .driver_name            = SERIAL_IT8712_NAME,
++      .dev_name               = SERIAL_IT8712_NAME,
++        .major                  = SERIAL_IT8712_MAJOR,
++      .minor                  = SERIAL_IT8712_MINOR,
++      .nr                     = UART_NR,
++      .cons                   = IT8712_CONSOLE,
++};
++
++static int __init it8712_init(void)
++{
++        int result;
++      //printk("serial_it8712: it871212_init \n");
++
++
++        result = uart_register_driver(&it8712_reg);
++        if(result)
++             return result;
++      result = uart_add_one_port(&it8712_reg, &it8712_ports[0]);
++
++        return result;
++
++}
++
++
++__initcall(it8712_init);
+Index: linux-2.6.23.16/drivers/serial/it8712.h
+===================================================================
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.23.16/drivers/serial/it8712.h    2008-03-15 17:59:53.568330991 +0200
+@@ -0,0 +1,135 @@
++#define UART_RX               0       /* In:  Receive buffer (DLAB=0) */
++#define UART_TX               0       /* Out: Transmit buffer (DLAB=0) */
++#define UART_DLL      0       /* Out: Divisor Latch Low (DLAB=1) */
++#define UART_TRG      0       /* (LCR=BF) FCTR bit 7 selects Rx or Tx
++                               * In: Fifo count
++                               * Out: Fifo custom trigger levels
++                               * XR16C85x only */
++
++#define UART_DLM      1       /* Out: Divisor Latch High (DLAB=1) */
++#define UART_IER      1       /* Out: Interrupt Enable Register */
++#define UART_FCTR     1       /* (LCR=BF) Feature Control Register
++                               * XR16C85x only */
++
++#define UART_IIR      2       /* In:  Interrupt ID Register */
++#define UART_FCR      2       /* Out: FIFO Control Register */
++#define UART_EFR      2       /* I/O: Extended Features Register */
++                              /* (DLAB=1, 16C660 only) */
++
++#define UART_LCR      3       /* Out: Line Control Register */
++#define UART_MCR      4       /* Out: Modem Control Register */
++#define UART_LSR      5       /* In:  Line Status Register */
++#define UART_MSR      6       /* In:  Modem Status Register */
++#define UART_SCR      7       /* I/O: Scratch Register */
++#define UART_EMSR     7       /* (LCR=BF) Extended Mode Select Register
++                               * FCTR bit 6 selects SCR or EMSR
++                               * XR16c85x only */
++
++/*
++ * These are the definitions for the FIFO Control Register
++ * (16650 only)
++ */
++#define UART_FCR_ENABLE_FIFO  0x01 /* Enable the FIFO */
++#define UART_FCR_CLEAR_RCVR   0x02 /* Clear the RCVR FIFO */
++#define UART_FCR_CLEAR_XMIT   0x04 /* Clear the XMIT FIFO */
++#define UART_FCR_DMA_SELECT   0x08 /* For DMA applications */
++#define UART_FCR_TRIGGER_MASK 0xC0 /* Mask for the FIFO trigger range */
++#define UART_FCR_TRIGGER_1    0x00 /* Mask for trigger set at 1 */
++#define UART_FCR_TRIGGER_4    0x40 /* Mask for trigger set at 4 */
++#define UART_FCR_TRIGGER_8    0x80 /* Mask for trigger set at 8 */
++#define UART_FCR_TRIGGER_14   0xC0 /* Mask for trigger set at 14 */
++/* 16650 redefinitions */
++#define UART_FCR6_R_TRIGGER_8 0x00 /* Mask for receive trigger set at 1 */
++#define UART_FCR6_R_TRIGGER_16        0x40 /* Mask for receive trigger set at 4 */
++#define UART_FCR6_R_TRIGGER_24  0x80 /* Mask for receive trigger set at 8 */
++#define UART_FCR6_R_TRIGGER_28        0xC0 /* Mask for receive trigger set at 14 */
++#define UART_FCR6_T_TRIGGER_16        0x00 /* Mask for transmit trigger set at 16 */
++#define UART_FCR6_T_TRIGGER_8 0x10 /* Mask for transmit trigger set at 8 */
++#define UART_FCR6_T_TRIGGER_24  0x20 /* Mask for transmit trigger set at 24 */
++#define UART_FCR6_T_TRIGGER_30        0x30 /* Mask for transmit trigger set at 30 */
++/* TI 16750 definitions */
++#define UART_FCR7_64BYTE      0x20 /* Go into 64 byte mode */
++
++/*
++ * These are the definitions for the Line Control Register
++ *
++ * Note: if the word length is 5 bits (UART_LCR_WLEN5), then setting
++ * UART_LCR_STOP will select 1.5 stop bits, not 2 stop bits.
++ */
++#define UART_LCR_DLAB 0x80    /* Divisor latch access bit */
++#define UART_LCR_SBC  0x40    /* Set break control */
++#define UART_LCR_SPAR 0x20    /* Stick parity (?) */
++#define UART_LCR_EPAR 0x10    /* Even parity select */
++#define UART_LCR_PARITY       0x08    /* Parity Enable */
++#define UART_LCR_STOP 0x04    /* Stop bits: 0=1 stop bit, 1= 2 stop bits */
++#define UART_LCR_WLEN5  0x00  /* Wordlength: 5 bits */
++#define UART_LCR_WLEN6  0x01  /* Wordlength: 6 bits */
++#define UART_LCR_WLEN7  0x02  /* Wordlength: 7 bits */
++#define UART_LCR_WLEN8  0x03  /* Wordlength: 8 bits */
++#define UART_LCR_EVEN   0x18    /* Even parity */
++#define UART_LCR_ODD    0x08    /* Odd parity */
++#define UART_LCR_MSK    0x03
++/*
++ * These are the definitions for the Line Status Register
++ */
++#define UART_LSR_DE     0x80    /* FIFO Data Error */
++#define UART_LSR_TEMT 0x40    /* Transmitter empty */
++#define UART_LSR_THRE 0x20    /* Transmit-hold-register empty */
++#define UART_LSR_BI   0x10    /* Break interrupt indicator */
++#define UART_LSR_FE   0x08    /* Frame error indicator */
++#define UART_LSR_PE   0x04    /* Parity error indicator */
++#define UART_LSR_OE   0x02    /* Overrun error indicator */
++#define UART_LSR_DR   0x01    /* Receiver data ready */
++
++/*
++ * These are the definitions for the Interrupt Identification Register
++ */
++#define UART_IIR_NO_INT       0x01    /* No interrupts pending */
++#define UART_IIR_ID   0x06    /* Mask for the interrupt ID */
++
++#define UART_IIR_MSI  0x00    /* Modem status interrupt */
++#define UART_IIR_THRI 0x02    /* Transmitter holding register empty */
++#define UART_IIR_RDI  0x04    /* Receiver data interrupt */
++#define UART_IIR_RLSI 0x06    /* Receiver line status interrupt */
++#define UART_IIR_RCTO 0x0c    /* Receiver character timeout interrupt */
++/*
++ * These are the definitions for the Interrupt Enable Register
++ */
++#define UART_IER_MSI  0x08    /* Enable Modem status interrupt */
++#define UART_IER_RLSI 0x04    /* Enable receiver line status interrupt */
++#define UART_IER_THRI 0x02    /* Enable Transmitter holding register int. */
++#define UART_IER_RDI  0x01    /* Enable receiver data interrupt */
++/*
++ * Sleep mode for ST16650 and TI16750.
++ * Note that for 16650, EFR-bit 4 must be selected as well.
++ */
++#define UART_IERX_SLEEP  0x10 /* Enable sleep mode */
++
++/*
++ * These are the definitions for the Modem Control Register
++ */
++#define UART_MCR_LOOP 0x10    /* Enable loopback test mode */
++#define UART_MCR_OUT2 0x08    /* Out2 complement */
++#define UART_MCR_OUT1 0x04    /* Out1 complement */
++#define UART_MCR_RTS  0x02    /* RTS complement */
++#define UART_MCR_DTR  0x01    /* DTR complement */
++
++/*
++ * These are the definitions for the Modem Status Register
++ */
++#define UART_MSR_DCD  0x80    /* Data Carrier Detect */
++#define UART_MSR_RI   0x40    /* Ring Indicator */
++#define UART_MSR_DSR  0x20    /* Data Set Ready */
++#define UART_MSR_CTS  0x10    /* Clear to Send */
++#define UART_MSR_DDCD 0x08    /* Delta DCD */
++#define UART_MSR_TERI 0x04    /* Trailing edge ring indicator */
++#define UART_MSR_DDSR 0x02    /* Delta DSR */
++#define UART_MSR_DCTS 0x01    /* Delta CTS */
++#define UART_MSR_ANY_DELTA 0x0F       /* Any of the delta bits! */
++
++#define UART_PARITY_NONE      0x00
++#define UART_PARITY_ODD               0x01
++#define UART_PARITY_EVEN      0x02
++
++
++
+Index: linux-2.6.23.16/drivers/serial/serial_it8712.c
+===================================================================
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.23.16/drivers/serial/serial_it8712.c     2008-03-15 17:59:53.568330991 +0200
+@@ -0,0 +1,876 @@
++/*
++ *  linux/drivers/char/serial_uart00.c
++ *
++ *  Driver for UART00 serial ports
++ *
++ *  Based on drivers/char/serial_amba.c, by ARM Limited &
++ *                                          Deep Blue Solutions Ltd.
++ *  Copyright 2001 Altera Corporation
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++ *
++ *  $Id: serial_it8712.c,v 1.1.1.1 2006/04/03 08:41:00 amos_lee Exp $
++ *
++ */
++#include <linux/module.h>
++
++#include <linux/errno.h>
++#include <linux/signal.h>
++#include <linux/sched.h>
++#include <linux/interrupt.h>
++#include <linux/tty.h>
++#include <linux/tty_flip.h>
++#include <linux/major.h>
++#include <linux/string.h>
++#include <linux/fcntl.h>
++#include <linux/ptrace.h>
++#include <linux/ioport.h>
++#include <linux/mm.h>
++#include <linux/slab.h>
++#include <linux/init.h>
++#include <linux/circ_buf.h>
++#include <linux/serial.h>
++#include <linux/console.h>
++#include <linux/sysrq.h>
++
++#include <asm/system.h>
++#include <asm/io.h>
++#include <asm/irq.h>
++#include <asm/uaccess.h>
++#include <asm/bitops.h>
++#include <asm/sizes.h>
++
++#if defined(CONFIG_SERIAL_IT8712_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
++#define SUPPORT_SYSRQ
++#endif
++
++#include <linux/serial_core.h>
++#include <asm/arch/sl2312.h>
++#include <asm/arch/int_ctrl.h>
++#include <asm/arch/it8712.h>
++#include "serial_it8712.h"
++
++//#define DEBUG           1
++#define UART_NR               1
++
++#define SERIAL_IT8712_NAME    "ttySI"
++#define SERIAL_IT8712_MAJOR   204
++#define SERIAL_IT8712_MINOR   41      /* Temporary - will change in future */
++#define SERIAL_IT8712_NR      UART_NR
++#define UART_PORT_SIZE 0x50
++
++#define CALLOUT_IT8712_NAME   "cuaslI"
++#define CALLOUT_IT8712_MAJOR  205
++#define CALLOUT_IT8712_MINOR  41      /* Temporary - will change in future */
++#define CALLOUT_IT8712_NR     UART_NR
++#define LPC_HOST_CONTINUE_MODE        0x00000040
++
++#define IT8712_NO_PORTS         UART_NR
++
++static struct tty_driver normal, callout;
++static struct tty_struct *it8712_table[UART_NR];
++static struct termios *it8712_termios[UART_NR], *it8712_termios_locked[UART_NR];
++static struct console it8712_console;
++
++#define IT8712_ISR_PASS_LIMIT 256
++
++/*
++ * Access macros for the SL2312 UARTs
++ */
++#define UART_GET_INT_STATUS(p)        (inb(((p)->membase+UART_IIR)) & 0x0F)  // interrupt identification
++#define UART_PUT_IER(p, c)      outb(c,((p)->membase+UART_IER))         // interrupt enable
++#define UART_GET_IER(p)         inb(((p)->membase+UART_IER))
++#define UART_PUT_CHAR(p, c)     outb(c,((p)->membase+UART_TX))         // transmitter holding
++#define UART_GET_CHAR(p)        inb(((p)->membase+UART_RX))            // receive buffer
++#define UART_GET_LSR(p)         inb(((p)->membase+UART_LSR))            // line status
++#define UART_GET_MSR(p)         inb(((p)->membase+UART_MSR))            // modem status
++#define UART_GET_MCR(p)         inb(((p)->membase+UART_MCR))            // modem control
++#define UART_PUT_MCR(p, c)      outb(c,((p)->membase+UART_MCR))
++#define UART_GET_LCR(p)         inb(((p)->membase+UART_LCR))       // mode control
++#define UART_PUT_LCR(p, c)      outb(c,((p)->membase+UART_LCR))
++#define UART_PUT_FCR(p, c)      outb(c,((p)->membase+UART_FCR))       // fifo control
++#define UART_GET_DIV_HI(p)    inb(((p)->membase+UART_DLM))
++#define UART_PUT_DIV_HI(p, c) outb(c,((p)->membase+UART_DLM))
++#define UART_GET_DIV_LO(p)    inb(((p)->membase+UART_DLL))
++#define UART_PUT_DIV_LO(p, c) outb(c,((p)->membase+UART_DLL))
++#define UART_PUT_MDR(p, c)      outb(c,UART_MDR((p)->membase))
++#define UART_RX_DATA(s)               ((s) & UART_LSR_DR)
++#define UART_TX_READY(s)      ((s) & UART_LSR_THRE)
++
++static void it8712_stop_tx(struct uart_port *port, u_int from_tty)
++{
++        unsigned int reg;
++
++//        printk("it8712 stop tx : \n");
++        reg = UART_GET_IER(port);
++        reg &= ~(UART_IER_THRI);
++      UART_PUT_IER(port, reg);
++}
++
++static void it8712_stop_rx(struct uart_port *port)
++{
++        unsigned int reg;
++
++//        printk("it8712 stop rx : \n");
++        reg = UART_GET_IER(port);
++        reg &= ~(UART_IER_RDI);
++      UART_PUT_IER(port, reg);
++
++}
++
++static void it8712_enable_ms(struct uart_port *port)
++{
++        unsigned int reg;
++
++//        printk("it8712 enable ms : \n");
++
++        reg = UART_GET_IER(port);
++        reg |= (UART_IER_MSI);
++      UART_PUT_IER(port, reg);
++
++}
++
++static void
++it8712_rx_chars(struct uart_info *info, struct pt_regs *regs)
++{
++      struct tty_struct *tty = info->tty;
++      unsigned int status, mask, ch, flg, ignored = 0;
++      struct uart_port *port = info->port;
++
++ //       printk("it8712_rx_chars : \n");
++      status = UART_GET_LSR(port);
++      while (UART_RX_DATA(status)) {
++
++              /*
++               * We need to read rds before reading the
++               * character from the fifo
++               */
++              ch = UART_GET_CHAR(port);
++              port->icount.rx++;
++
++              if (tty->flip.count >= TTY_FLIPBUF_SIZE)
++                      goto ignore_char;
++
++              flg = TTY_NORMAL;
++
++              /*
++               * Note that the error handling code is
++               * out of the main execution path
++               */
++
++              if (status & (UART_LSR_OE|UART_LSR_PE|UART_LSR_FE|UART_LSR_BI|UART_LSR_DE))
++                      goto handle_error;
++              if (uart_handle_sysrq_char(info, ch, regs))
++                      goto ignore_char;
++
++      error_return:
++              *tty->flip.flag_buf_ptr++ = flg;
++              *tty->flip.char_buf_ptr++ = ch;
++              tty->flip.count++;
++      ignore_char:
++              status = UART_GET_LSR(port);
++      } // end of while
++out:
++      tty_flip_buffer_push(tty);
++      return;
++
++handle_error:
++      if (status & UART_LSR_BI) {
++              status &= ~(UART_LSR_FE);
++              port->icount.brk++;
++
++#ifdef SUPPORT_SYSRQ
++              if (uart_handle_break(info, &it8712_console))
++                      goto ignore_char;
++#endif
++      } else if (status & UART_LSR_PE)
++              port->icount.parity++;
++      else if (status & UART_LSR_FE)
++              port->icount.frame++;
++
++      if (status & UART_LSR_OE)
++              port->icount.overrun++;
++
++      if (status & port->ignore_status_mask) {
++              if (++ignored > 100)
++                      goto out;
++              goto ignore_char;
++      }
++
++      mask = status & port->read_status_mask;
++
++      if (mask & UART_LSR_BI)
++              flg = TTY_BREAK;
++      else if (mask & UART_LSR_PE)
++              flg = TTY_PARITY;
++      else if (mask & UART_LSR_FE)
++              flg = TTY_FRAME;
++
++      if (status & UART_LSR_OE) {
++              /*
++               * CHECK: does overrun affect the current character?
++               * ASSUMPTION: it does not.
++               */
++              *tty->flip.flag_buf_ptr++ = flg;
++              *tty->flip.char_buf_ptr++ = ch;
++              tty->flip.count++;
++              if (tty->flip.count >= TTY_FLIPBUF_SIZE)
++                      goto ignore_char;
++              ch = 0;
++              flg = TTY_OVERRUN;
++      }
++#ifdef SUPPORT_SYSRQ
++      info->sysrq = 0;
++#endif
++      goto error_return;
++}
++
++static void it8712_tx_chars(struct uart_info *info)
++{
++      int count;
++      struct uart_port *port=info->port;
++
++      if (port->x_char) {
++              while(!(UART_GET_LSR(port)&UART_LSR_THRE));
++              UART_PUT_CHAR(port, port->x_char);
++              port->icount.tx++;
++              port->x_char = 0;
++
++              return;
++      }
++      if (info->xmit.head == info->xmit.tail
++          || info->tty->stopped
++          || info->tty->hw_stopped) {
++              it8712_stop_tx(info->port, 0);
++              return;
++      }
++
++      count = port->fifosize >> 1;
++      do {
++              while(!(UART_GET_LSR(port)&UART_LSR_THRE));
++              UART_PUT_CHAR(port, info->xmit.buf[info->xmit.tail]);
++              info->xmit.tail = (info->xmit.tail + 1) & (UART_XMIT_SIZE - 1);
++              port->icount.tx++;
++              if (info->xmit.head == info->xmit.tail)
++                      break;
++      } while (--count > 0);
++
++      if (CIRC_CNT(info->xmit.head,
++                   info->xmit.tail,
++                   UART_XMIT_SIZE) < WAKEUP_CHARS)
++              uart_event(info, EVT_WRITE_WAKEUP);
++
++      if (info->xmit.head == info->xmit.tail)
++              it8712_stop_tx(info->port, 0);
++}
++
++static void it8712_start_tx(struct uart_port *port, u_int nonempty, u_int from_tty)
++{
++        unsigned int reg;
++      struct uart_info *info=(struct uart_info*)(port->iobase);
++
++//        printk("it8712 start tx : \n");
++        reg = UART_GET_IER(port);
++        reg |= (UART_IER_THRI);
++      UART_PUT_IER(port, reg);
++      it8712_tx_chars(info);
++}
++
++static void it8712_modem_status(struct uart_info *info)
++{
++      unsigned int status;
++      struct uart_icount *icount = &info->port->icount;
++
++//        printk("it8712 modem status : \n");
++
++      status = UART_GET_MSR(info->port);
++
++      if (!(status & (UART_MSR_DCTS | UART_MSR_DDSR |
++                     UART_MSR_TERI | UART_MSR_DDCD)))
++              return;
++
++      if (status & UART_MSR_DCD) {
++              icount->dcd++;
++#ifdef CONFIG_HARD_PPS
++              if ((info->flags & ASYNC_HARDPPS_CD) &&
++                  (status & UART_MSR_DCD_MSK))
++                      hardpps();
++#endif
++              if (info->flags & ASYNC_CHECK_CD) {
++                      if (status & UART_MSR_DCD)
++                              wake_up_interruptible(&info->open_wait);
++                      else if (!((info->flags & ASYNC_CALLOUT_ACTIVE) &&
++                                 (info->flags & ASYNC_CALLOUT_NOHUP))) {
++                              if (info->tty)
++                                      tty_hangup(info->tty);
++                      }
++              }
++      }
++
++      if (status & UART_MSR_DDSR)
++              icount->dsr++;
++
++      if (status & UART_MSR_DCTS) {
++              icount->cts++;
++
++              if (info->flags & ASYNC_CTS_FLOW) {
++                      status &= UART_MSR_CTS;
++
++                      if (info->tty->hw_stopped) {
++                              if (status) {
++                                      info->tty->hw_stopped = 0;
++                                      info->ops->start_tx(info->port, 1, 0);
++                                      uart_event(info, EVT_WRITE_WAKEUP);
++                              }
++                      } else {
++                              if (!status) {
++                                      info->tty->hw_stopped = 1;
++                                      info->ops->stop_tx(info->port, 0);
++                              }
++                      }
++              }
++      }
++      wake_up_interruptible(&info->delta_msr_wait);
++
++}
++
++static void it8712_int(int irq, void *dev_id, struct pt_regs *regs)
++{
++      struct uart_info *info = dev_id;
++      unsigned int status, pass_counter = 0;
++
++      status = UART_GET_INT_STATUS(info->port);
++      do {
++//                 printk("it8712_int: status %x \n", status);
++              switch(status)
++              {
++                 case UART_IIR_RDI:
++                 case UART_IIR_RLSI:
++                 case UART_IIR_RCTO:
++                      it8712_rx_chars(info, regs);
++                 break;
++                 case UART_IIR_THRI:
++                      it8712_tx_chars(info);
++                 break;
++                 case UART_IIR_MSI:
++                      it8712_modem_status(info);
++                 break;
++                 default:
++                 break;
++              }
++              if (pass_counter++ > IT8712_ISR_PASS_LIMIT)
++                      break;
++
++              status = UART_GET_INT_STATUS(info->port);
++      } while (status);
++}
++
++static u_int it8712_tx_empty(struct uart_port *port)
++{
++//        printk("it8712 tx empty : \n");
++
++      return ((UART_GET_LSR(port) & UART_LSR_THRE)? TIOCSER_TEMT : 0);
++}
++
++static u_int it8712_get_mctrl(struct uart_port *port)
++{
++      unsigned int result = 0;
++      unsigned int status;
++
++//        printk("it8712 get mctrl : \n");
++
++      status = UART_GET_MSR(port);
++      if (status & UART_MSR_DCD)
++              result |= TIOCM_CAR;
++      if (status & UART_MSR_DSR)
++              result |= TIOCM_DSR;
++      if (status & UART_MSR_CTS)
++              result |= TIOCM_CTS;
++      if (status & UART_MSR_RI)
++              result |= TIOCM_RI;
++
++      return result;
++}
++
++static void it8712_set_mctrl_null(struct uart_port *port, u_int mctrl)
++{
++}
++
++static void it8712_break_ctl(struct uart_port *port, int break_state)
++{
++      unsigned int lcr;
++
++//        printk("it8712 break ctl : \n");
++
++      lcr = UART_GET_LCR(port);
++      if (break_state == -1)
++              lcr |= UART_LCR_SBC;
++      else
++              lcr &= ~UART_LCR_SBC;
++      UART_PUT_LCR(port, lcr);
++}
++
++static inline u_int uart_calculate_quot(struct uart_info *info, u_int baud)
++{
++      u_int quot;
++
++      /* Special case: B0 rate */
++      if (!baud)
++              baud = 9600;
++
++      quot = (info->port->uartclk/(16 * baud)) ;
++
++      return quot;
++}
++static void it8712_change_speed(struct uart_port *port, u_int cflag, u_int iflag, u_int quot)
++{
++      u_int uart_mc=0, old_ier;
++      unsigned long flags;
++
++#ifdef DEBUG
++      printk("it8712_set_cflag(0x%x) called\n", cflag);
++#endif
++
++
++      /* byte size and parity */
++      switch (cflag & CSIZE) {
++      case CS5: uart_mc = UART_LCR_WLEN5; break;
++      case CS6: uart_mc = UART_LCR_WLEN6; break;
++      case CS7: uart_mc = UART_LCR_WLEN7; break;
++      default:  uart_mc = UART_LCR_WLEN8; break; // CS8
++      }
++      if (cflag & CSTOPB)
++              uart_mc|= UART_LCR_STOP;
++      if (cflag & PARENB) {
++              uart_mc |= UART_LCR_EVEN;
++              if (!(cflag & PARODD))
++                      uart_mc |= UART_LCR_ODD;
++      }
++
++      port->read_status_mask = UART_LSR_OE;
++      if (iflag & INPCK)
++              port->read_status_mask |= UART_LSR_FE | UART_LSR_PE;
++      if (iflag & (BRKINT | PARMRK))
++              port->read_status_mask |= UART_LSR_BI;
++
++      /*
++       * Characters to ignore
++       */
++      port->ignore_status_mask = 0;
++      if (iflag & IGNPAR)
++              port->ignore_status_mask |= UART_LSR_FE | UART_LSR_PE;
++      if (iflag & IGNBRK) {
++              port->ignore_status_mask |= UART_LSR_BI;
++              /*
++               * If we're ignoring parity and break indicators,
++               * ignore overruns to (for real raw support).
++               */
++              if (iflag & IGNPAR)
++                      port->ignore_status_mask |= UART_LSR_OE;
++      }
++
++      /* first, disable everything */
++      save_flags(flags); cli();
++      old_ier = UART_GET_IER(port);
++
++      if ((port->flags & ASYNC_HARDPPS_CD) ||
++          (cflag & CRTSCTS) || !(cflag & CLOCAL))
++              old_ier |= UART_IER_MSI;
++
++      /* Set baud rate */
++      quot = quot / 13;
++      UART_PUT_LCR(port, UART_LCR_DLAB);
++      UART_PUT_DIV_LO(port, (quot & 0xff));
++      UART_PUT_DIV_HI(port, ((quot & 0xf00) >> 8));
++
++      UART_PUT_LCR(port, uart_mc);
++//    UART_PUT_LCR(port, 0x07); // ???? it is wired
++        UART_PUT_MCR(port, 0x08);
++        UART_PUT_FCR(port, 0x01);
++      UART_PUT_IER(port, 0x05);
++
++      restore_flags(flags);
++}
++
++static int it8712_startup(struct uart_port *port, struct uart_info *info)
++{
++      int retval;
++      unsigned int regs;
++
++//        printk("it8712 startup : \n");
++
++      /*
++       * Use iobase to store a pointer to info. We need this to start a
++       * transmission as the tranmittr interrupt is only generated on
++       * the transition to the idle state
++       */
++
++      port->iobase=(u_int)info;
++
++      /*
++       * Allocate the IRQ
++       */
++      retval = request_irq(port->irq, it8712_int, SA_INTERRUPT, "it8712", info);
++      if (retval)
++              return retval;
++
++        /* setup interrupt controller  */
++        regs = *((volatile unsigned int *)IRQ_TMODE(IO_ADDRESS(SL2312_INTERRUPT_BASE)));
++        regs |= (IRQ_SERIRQ0_MASK);
++        *((volatile unsigned int *)IRQ_TMODE(IO_ADDRESS(SL2312_INTERRUPT_BASE))) = regs;
++        regs = *((volatile unsigned int *)IRQ_LEVEL(IO_ADDRESS(SL2312_INTERRUPT_BASE)));
++        regs &= ~(IRQ_SERIRQ0_MASK);
++        *((volatile unsigned int *)IRQ_LEVEL(IO_ADDRESS(SL2312_INTERRUPT_BASE))) = regs;
++        *((volatile unsigned int *)IRQ_MASK(IO_ADDRESS(SL2312_INTERRUPT_BASE))) |= (unsigned int)(IRQ_SERIRQ0_MASK);
++
++      /*
++       * Finally, enable interrupts. Use the TII interrupt to minimise
++       * the number of interrupts generated. If higher performance is
++       * needed, consider using the TI interrupt with a suitable FIFO
++       * threshold
++       */
++      UART_PUT_IER(port, (UART_IER_RDI|UART_IER_THRI));
++
++      return 0;
++}
++
++static void it8712_shutdown(struct uart_port *port, struct uart_info *info)
++{
++//        printk("it8712 shutdown : \n");
++
++      /*
++       * disable all interrupts, disable the port
++       */
++      UART_PUT_IER(port, 0x0);
++
++      /* disable break condition and fifos */
++//    UART_PUT_MCR(port, (UART_GET_MCR(port)&UART_MCR_MASK));
++
++      /*
++       * Free the interrupt
++       */
++      free_irq(port->irq, info);
++}
++
++static const char *it8712_type(struct uart_port *port)
++{
++      return port->type == PORT_IT8712 ? "IT8712" : NULL;
++}
++
++/*
++ * Release the memory region(s) being used by 'port'
++ */
++static void it8712_release_port(struct uart_port *port)
++{
++//        printk("it8712 release port : \n");
++
++      release_mem_region(port->mapbase, UART_PORT_SIZE);
++}
++
++/*
++ * Request the memory region(s) being used by 'port'
++ */
++static int it8712_request_port(struct uart_port *port)
++{
++      return request_mem_region(port->mapbase, UART_PORT_SIZE,
++                                  "serial_it8712") != NULL ? 0 : -EBUSY;
++}
++
++/*
++ * Configure/autoconfigure the port.
++ */
++static void it8712_config_port(struct uart_port *port, int flags)
++{
++
++      if (flags & UART_CONFIG_TYPE) {
++              if (it8712_request_port(port) == 0)
++                      port->type = PORT_IT8712;
++      }
++}
++
++/*
++ * verify the new serial_struct (for TIOCSSERIAL).
++ */
++static int it8712_verify_port(struct uart_port *port, struct serial_struct *ser)
++{
++      int ret = 0;
++
++      if (ser->type != PORT_UNKNOWN && ser->type != PORT_UART00)
++              ret = -EINVAL;
++      if (ser->irq < 0 || ser->irq >= NR_IRQS)
++              ret = -EINVAL;
++      if (ser->baud_base < 9600)
++              ret = -EINVAL;
++      return ret;
++}
++
++static struct uart_ops it8712_pops = {
++      tx_empty:       it8712_tx_empty,
++      set_mctrl:      it8712_set_mctrl_null,
++      get_mctrl:      it8712_get_mctrl,
++      stop_tx:        it8712_stop_tx,
++      start_tx:       it8712_start_tx,
++      stop_rx:        it8712_stop_rx,
++      enable_ms:      it8712_enable_ms,
++      break_ctl:      it8712_break_ctl,
++      startup:        it8712_startup,
++      shutdown:       it8712_shutdown,
++      change_speed:   it8712_change_speed,
++      type:           it8712_type,
++      release_port:   it8712_release_port,
++      request_port:   it8712_request_port,
++      config_port:    it8712_config_port,
++      verify_port:    it8712_verify_port,
++};
++
++#ifdef CONFIG_ARCH_SL2312
++
++static struct uart_port it8712_ports[UART_NR] = {
++      {
++              membase:        (void *)0,
++              mapbase:        0,
++              iotype:         SERIAL_IO_MEM,
++              irq:            0,
++              uartclk:        UART_CLK/2,
++              fifosize:       16,
++              ops:            &it8712_pops,
++              flags:          ASYNC_BOOT_AUTOCONF,
++      }
++};
++
++#endif
++
++#ifdef CONFIG_SERIAL_IT8712_CONSOLE
++#ifdef used_and_not_const_char_pointer
++static int it8712_console_read(struct uart_port *port, char *s, u_int count)
++{
++      unsigned int status;
++      int c;
++#ifdef DEBUG
++      printk("it8712_console_read() called\n");
++#endif
++
++      c = 0;
++      while (c < count) {
++              status = UART_GET_LSR(port);
++              if (UART_RX_DATA(status)) {
++                      *s++ = UART_GET_CHAR(port);
++                      c++;
++              } else {
++                      // nothing more to get, return
++                      return c;
++              }
++      }
++      // return the count
++      return c;
++}
++#endif
++static void it8712_console_write(struct console *co, const char *s, unsigned count)
++{
++#ifdef CONFIG_ARCH_SL2312
++      struct uart_port *port = it8712_ports + co->index;
++      unsigned int status, old_ies;
++      int i;
++
++      /*
++       *      First save the CR then disable the interrupts
++       */
++      old_ies = UART_GET_IER(port);
++      UART_PUT_IER(port,0x0);
++
++      /*
++       *      Now, do each character
++       */
++      for (i = 0; i < count; i++) {
++              do {
++                      status = UART_GET_LSR(port);
++              } while (!UART_TX_READY(status));
++              UART_PUT_CHAR(port, s[i]);
++              if (s[i] == '\n') {
++                      do {
++                              status = UART_GET_LSR(port);
++                      } while (!UART_TX_READY(status));
++                      UART_PUT_CHAR(port, '\r');
++              }
++      }
++
++      /*
++       *      Finally, wait for transmitter to become empty
++       *      and restore the IES
++       */
++      do {
++              status = UART_GET_LSR(port);
++      } while (!(status&UART_LSR_THRE));
++      UART_PUT_IER(port, old_ies);
++#endif
++}
++
++static kdev_t it8712_console_device(struct console *co)
++{
++      return MKDEV(SERIAL_IT8712_MAJOR, SERIAL_IT8712_MINOR + co->index);
++}
++
++static int it8712_console_wait_key(struct console *co)
++{
++#ifdef CONFIG_ARCH_SL2312
++      struct uart_port *port = (it8712_ports + co->index);
++      unsigned int status;
++
++      do {
++              status = UART_GET_LSR(port);
++      } while (!UART_RX_DATA(status));
++      return UART_GET_CHAR(port);
++#else
++      return 0;
++#endif
++}
++
++static void /*__init*/ it8712_console_get_options(struct uart_port *port, int *baud, int *parity, int *bits)
++{
++      printk("it8712 console get options : \n");
++
++      u_int uart_mc, quot;
++      uart_mc= UART_GET_MCR(port);
++
++      *parity = 'n';
++      if (uart_mc & UART_LCR_PARITY) {
++              if (uart_mc & UART_LCR_EVEN)
++                      *parity = 'e';
++              else
++                      *parity = 'o';
++      }
++
++      switch (uart_mc & UART_LCR_MSK){
++
++      case UART_LCR_WLEN5:
++              *bits = 5;
++              break;
++      case UART_LCR_WLEN6:
++              *bits = 6;
++              break;
++      case UART_LCR_WLEN7:
++              *bits = 7;
++              break;
++      case UART_LCR_WLEN8:
++              *bits = 8;
++              break;
++      }
++      UART_PUT_MCR(port,UART_LCR_DLAB);
++      quot = UART_GET_DIV_LO(port) | (UART_GET_DIV_HI(port) << 8);
++      UART_PUT_MCR(port,uart_mc);
++      *baud = (port->uartclk / (16 *quot));
++}
++
++static int __init it8712_console_setup(struct console *co, char *options)
++{
++      struct uart_port *port;
++      int baud = 38400;
++      int bits = 8;
++      int parity = 'n';
++      int flow= 'n';
++      int base, irq;
++      int i ;
++
++//    printk("it8712 console setup : \n");
++
++      LPCSetConfig(0, 0x02, 0x01);
++        LPCSetConfig(LDN_SERIAL1, 0x30, 0x1);
++        LPCSetConfig(LDN_SERIAL1, 0x23, 0x0);
++      base = IT8712_IO_BASE;
++      base += ((LPCGetConfig(LDN_SERIAL1, 0x60) << 8) + LPCGetConfig(LDN_SERIAL1, 0x61));
++      it8712_ports[0].mapbase = base;
++      it8712_ports[0].membase = IO_ADDRESS(base);
++      it8712_ports[0].irq = IRQ_SERIRQ0_OFFSET;
++              irq = LPCGetConfig(LDN_SERIAL1, 0x70);
++      it8712_ports[0].irq += irq;
++
++      printk("it8712 irq is %x %x \n", it8712_ports[0].irq, irq);
++
++      // setup LPC Host 'quiet mode'
++      *((volatile unsigned int *)IO_ADDRESS((SL2312_LPC_HOST_BASE+0x04))) |= LPC_HOST_CONTINUE_MODE ;
++      for(i=0;i<1000;i++) ;                                           // delay
++      *((volatile unsigned int *)IO_ADDRESS((SL2312_LPC_HOST_BASE+0x04))) &= ~(LPC_HOST_CONTINUE_MODE) ;
++
++#ifdef CONFIG_ARCH_SL2312
++      /*
++       * Check whether an invalid uart number has been specified, and
++       * if so, search for the first available port that does have
++       * console support.
++       */
++      port = uart_get_console(it8712_ports,IT8712_NO_PORTS,co);
++#else
++      return -ENODEV;
++#endif
++
++      if (options)
++              uart_parse_options(options, &baud, &parity, &bits, &flow);
++      else
++              it8712_console_get_options(port, &baud, &parity, &bits);
++
++      return uart_set_options(port, co, baud, parity, bits, flow);
++}
++
++static struct console it8712_console = {
++      name:           SERIAL_IT8712_NAME,
++      write:          it8712_console_write,
++#ifdef used_and_not_const_char_pointer
++      read:           it8712_console_read,
++#endif
++      device:         it8712_console_device,
++//    wait_key:       it8712_console_wait_key,
++      setup:          it8712_console_setup,
++      flags:          (CON_PRINTBUFFER|CON_ENABLED),
++      index:          -1,
++};
++
++void __init it8712_console_init(void)
++{
++      register_console(&it8712_console);
++}
++
++#define IT8712_CONSOLE        &it8712_console
++#else
++#define IT8712_CONSOLE        NULL
++#endif
++
++static struct uart_driver it8712_reg = {
++      owner:                  NULL,
++      normal_major:           SERIAL_IT8712_MAJOR,
++      normal_name:            SERIAL_IT8712_NAME,
++      normal_driver:          &normal,
++      callout_major:          CALLOUT_IT8712_MAJOR,
++      callout_name:           CALLOUT_IT8712_NAME,
++      callout_driver:         &callout,
++      table:                  it8712_table,
++      termios:                it8712_termios,
++      termios_locked:         it8712_termios_locked,
++      minor:                  SERIAL_IT8712_MINOR,
++      nr:                     UART_NR,
++#ifdef CONFIG_ARCH_SL2312
++      port:                   it8712_ports,
++#endif
++      state:                  NULL,
++      cons:                   IT8712_CONSOLE,
++};
++
++static int __init it8712_init(void)
++{
++//    printk("serial_it8712: it871212_init \n");
++
++      return uart_register_driver(&it8712_reg);
++}
++
++
++__initcall(it8712_init);
+Index: linux-2.6.23.16/drivers/serial/serial_sl2312.c
+===================================================================
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.23.16/drivers/serial/serial_sl2312.c     2008-03-17 12:30:50.290536619 +0200
+@@ -0,0 +1,827 @@
++/*
++ *  linux/drivers/char/serial_uart00.c
++ *
++ *  Driver for UART00 serial ports
++ *
++ *  Based on drivers/char/serial_amba.c, by ARM Limited &
++ *                                          Deep Blue Solutions Ltd.
++ *  Copyright 2001 Altera Corporation
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++ *
++ *  $Id: serial_sl2312.c,v 1.1.1.1 2006/04/03 08:41:00 amos_lee Exp $
++ *
++ */
++#include <linux/module.h>
++
++#include <linux/errno.h>
++#include <linux/signal.h>
++#include <linux/sched.h>
++#include <linux/interrupt.h>
++#include <linux/tty.h>
++#include <linux/tty_flip.h>
++#include <linux/major.h>
++#include <linux/string.h>
++#include <linux/fcntl.h>
++#include <linux/ptrace.h>
++#include <linux/ioport.h>
++#include <linux/mm.h>
++#include <linux/slab.h>
++#include <linux/init.h>
++#include <linux/circ_buf.h>
++#include <linux/serial.h>
++#include <linux/console.h>
++#include <linux/sysrq.h>
++#include <linux/serial_core.h>
++
++#include <asm/system.h>
++#include <asm/hardware.h>
++#include <asm/io.h>
++#include <asm/irq.h>
++#include <asm/uaccess.h>
++#include <asm/bitops.h>
++#include <asm/sizes.h>
++#include <linux/spinlock.h>
++#include <linux/irq.h>
++
++
++#if defined(CONFIG_SERIAL_SL2312_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
++#define SUPPORT_SYSRQ
++#endif
++
++#include <asm/arch/sl2312.h>
++#define UART_TYPE (volatile unsigned int*)
++#include <asm/arch/uart.h>
++#include <asm/arch/int_ctrl.h>
++
++// #define DEBUG           1
++#define UART_NR               1
++
++
++#define SERIAL_SL2312_NAME    "ttySL"
++#define SERIAL_SL2312_MAJOR   204
++#define SERIAL_SL2312_MINOR   40      /* Temporary - will change in future */
++#define SERIAL_SL2312_NR      UART_NR
++#define UART_PORT_SIZE 0x50
++
++#define SL2312_NO_PORTS         UART_NR
++#define SL2312_ISR_PASS_LIMIT 256
++
++/*
++ * Access macros for the SL2312 UARTs
++ */
++#define UART_GET_INT_STATUS(p)        (inl(UART_IIR((p)->membase)) & 0x0F)      // interrupt identification
++#define UART_PUT_IER(p, c)      outl(c,UART_IER((p)->membase))    // interrupt enable
++#define UART_GET_IER(p)         inl(UART_IER((p)->membase))
++#define UART_PUT_CHAR(p, c)     outl(c,UART_THR((p)->membase))    // transmitter holding
++#define UART_GET_CHAR(p)        inl(UART_RBR((p)->membase))       // receive buffer
++#define UART_GET_LSR(p)         inl(UART_LSR((p)->membase))       // line status
++#define UART_GET_MSR(p)         inl(UART_MSR((p)->membase))       // modem status
++#define UART_GET_MCR(p)         inl(UART_MCR((p)->membase))       // modem control
++#define UART_PUT_MCR(p, c)      outl(c,UART_MCR((p)->membase))
++#define UART_GET_LCR(p)         inl(UART_LCR((p)->membase))       // mode control
++#define UART_PUT_LCR(p, c)      outl(c,UART_LCR((p)->membase))
++#define UART_GET_DIV_HI(p)    inl(UART_DIV_HI((p)->membase))
++#define UART_PUT_DIV_HI(p, c) outl(c,UART_DIV_HI((p)->membase))
++#define UART_GET_DIV_LO(p)    inl(UART_DIV_LO((p)->membase))
++#define UART_PUT_DIV_LO(p, c) outl(c,UART_DIV_LO((p)->membase))
++#define UART_PUT_MDR(p, c)      outl(c,UART_MDR((p)->membase))
++#define UART_RX_DATA(s)               ((s) & UART_LSR_DR)
++#define UART_TX_READY(s)      ((s) & UART_LSR_THRE)
++
++
++static void sl2312_stop_tx(struct uart_port *port)
++{
++        unsigned int reg;
++
++//        printk("sl2312 stop tx : \n");
++        reg = UART_GET_IER(port);
++        reg &= ~(UART_IER_TE);
++      UART_PUT_IER(port, reg);
++}
++
++static void sl2312_stop_rx(struct uart_port *port)
++{
++        unsigned int reg;
++
++//        printk("sl2312 stop rx : \n");
++        reg = UART_GET_IER(port);
++        reg &= ~(UART_IER_DR);
++      UART_PUT_IER(port, reg);
++
++}
++
++static void sl2312_enable_ms(struct uart_port *port)
++{
++        unsigned int reg;
++
++//        printk("sl2312 enable ms : \n");
++
++        reg = UART_GET_IER(port);
++        reg |= (UART_IER_MS);
++      UART_PUT_IER(port, reg);
++
++}
++
++static void
++sl2312_rx_chars(struct uart_port *port)
++{
++      struct tty_struct *tty = port->info->tty;
++      unsigned int status, mask, ch, flg, ignored = 0;
++
++
++ //       printk("sl2312_rx_chars : \n");
++      status = UART_GET_LSR(port);
++      while (UART_RX_DATA(status)) {
++
++              /*
++               * We need to read rds before reading the
++               * character from the fifo
++               */
++              ch = UART_GET_CHAR(port);
++              port->icount.rx++;
++
++              //if (tty->flip.count >= TTY_FLIPBUF_SIZE)
++              if (tty && !tty_buffer_request_room(tty, 1))
++                      goto ignore_char;
++
++              flg = TTY_NORMAL;
++
++              /*
++               * Note that the error handling code is
++               * out of the main execution path
++               */
++
++              if (status & (UART_LSR_OE|UART_LSR_PE|UART_LSR_FE|UART_LSR_BI|UART_LSR_DE))
++                      goto handle_error;
++              if (uart_handle_sysrq_char(port, ch))
++                      goto ignore_char;
++
++      error_return:
++              //*tty->flip.flag_buf_ptr++ = flg;
++              //*tty->flip.char_buf_ptr++ = ch;
++              //tty->flip.count++;
++              tty_insert_flip_char(tty, ch, flg);
++      ignore_char:
++              status = UART_GET_LSR(port);
++      } // end of while
++out:
++      tty_flip_buffer_push(tty);
++      return;
++
++handle_error:
++      if (status & UART_LSR_BI) {
++              status &= ~(UART_LSR_FE);
++              port->icount.brk++;
++
++#ifdef SUPPORT_SYSRQ
++              if (uart_handle_break(port))
++                      goto ignore_char;
++#endif
++      } else if (status & UART_LSR_PE)
++              port->icount.parity++;
++      else if (status & UART_LSR_FE)
++              port->icount.frame++;
++
++      if (status & UART_LSR_OE)
++              port->icount.overrun++;
++
++      if (status & port->ignore_status_mask) {
++              if (++ignored > 100)
++                      goto out;
++              goto ignore_char;
++      }
++
++      mask = status & port->read_status_mask;
++
++      if (mask & UART_LSR_BI)
++              flg = TTY_BREAK;
++      else if (mask & UART_LSR_PE)
++              flg = TTY_PARITY;
++      else if (mask & UART_LSR_FE)
++              flg = TTY_FRAME;
++
++      if (status & UART_LSR_OE) {
++              /*
++               * CHECK: does overrun affect the current character?
++               * ASSUMPTION: it does not.
++               */
++              //*tty->flip.flag_buf_ptr++ = flg;
++              //*tty->flip.char_buf_ptr++ = ch;
++              //tty->flip.count++;
++
++              tty_insert_flip_char(tty, 0, TTY_BREAK);
++
++              // if (tty->flip.count >= TTY_FLIPBUF_SIZE)
++              if (tty_buffer_request_room(tty, 1))
++                      goto ignore_char;
++              ch = 0;
++              flg = TTY_OVERRUN;
++      }
++#ifdef SUPPORT_SYSRQ
++      port->sysrq = 0;
++#endif
++      goto error_return;
++}
++
++static void sl2312_tx_chars(struct uart_port *port)
++{
++      struct circ_buf *xmit = &port->info->xmit;
++      int count;
++
++
++      if (port->x_char) {
++              while(!(UART_GET_LSR(port)&UART_LSR_THRE));
++              UART_PUT_CHAR(port, port->x_char);
++              port->icount.tx++;
++              port->x_char = 0;
++
++              return;
++      }
++      if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
++              sl2312_stop_tx(port);
++
++              return;
++      }
++
++      count = port->fifosize >> 1;
++      do {
++              while(!(UART_GET_LSR(port)&UART_LSR_THRE));
++              UART_PUT_CHAR(port, xmit->buf[xmit->tail]);
++              xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
++              port->icount.tx++;
++              if (uart_circ_empty(xmit))
++                      break;
++      } while (--count > 0);
++
++      if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
++              uart_write_wakeup(port);
++
++      if (uart_circ_empty(xmit))
++              sl2312_stop_tx(port);
++
++}
++
++static void sl2312_start_tx(struct uart_port *port)
++{
++        unsigned int reg;
++
++//        printk("sl2312 start tx : \n");
++        reg = UART_GET_IER(port);
++        reg |= (UART_IER_TE);
++      UART_PUT_IER(port, reg);
++
++      sl2312_tx_chars(port);
++}
++
++static void sl2312_modem_status(struct uart_port *port)
++{
++      unsigned int status;
++
++//        printk("it8712 modem status : \n");
++
++      status = UART_GET_MSR(port);
++
++      if (!(status & (UART_MSR_DCTS | UART_MSR_DDSR |
++                     UART_MSR_TERI | UART_MSR_DDCD)))
++              return;
++
++        if (status & UART_MSR_DDCD)
++                uart_handle_dcd_change(port, status & UART_MSR_DCD);
++
++        if (status & UART_MSR_DDSR)
++                port->icount.dsr++;
++
++        if (status & UART_MSR_DCTS)
++                uart_handle_cts_change(port, status & UART_MSR_CTS);
++
++      wake_up_interruptible(&port->info->delta_msr_wait);
++
++}
++
++static irqreturn_t sl2312_int(int irq, void *dev_id)
++{
++      struct uart_port *port = dev_id;
++      unsigned int status, pass_counter = 0;
++
++      status = UART_GET_INT_STATUS(port);
++      do {
++              switch(status)
++              {
++                 case UART_IIR_DR:
++                 case UART_IIR_RLS:
++                      sl2312_rx_chars(port);
++                 break;
++                 case UART_IIR_TE:
++                      sl2312_tx_chars(port);
++                 break;
++                 case UART_IIR_MODEM:
++                      sl2312_modem_status(port);
++                 break;
++                 default:
++                 break;
++              }
++              if (pass_counter++ > SL2312_ISR_PASS_LIMIT)
++                      break;
++
++              status = UART_GET_INT_STATUS(port);
++      } while (status);
++
++      return IRQ_HANDLED;
++}
++
++static u_int sl2312_tx_empty(struct uart_port *port)
++{
++//        printk("sl2312 tx empty : \n");
++
++      return ((UART_GET_LSR(port) & UART_LSR_TE)? TIOCSER_TEMT : 0);
++}
++
++static u_int sl2312_get_mctrl(struct uart_port *port)
++{
++      unsigned int result = 0;
++      unsigned int status;
++
++//        printk("sl2312 get mctrl : \n");
++
++      status = UART_GET_MSR(port);
++      if (status & UART_MSR_DCD)
++              result |= TIOCM_CAR;
++      if (status & UART_MSR_DSR)
++              result |= TIOCM_DSR;
++      if (status & UART_MSR_CTS)
++              result |= TIOCM_CTS;
++      if (status & UART_MSR_RI)
++              result |= TIOCM_RI;
++
++      return result;
++}
++
++static void sl2312_set_mctrl_null(struct uart_port *port, u_int mctrl)
++{
++}
++
++static void sl2312_break_ctl(struct uart_port *port, int break_state)
++{
++      unsigned int lcr;
++
++//        printk("sl2312 break ctl : \n");
++
++      lcr = UART_GET_LCR(port);
++      if (break_state == -1)
++              lcr |= UART_LCR_SETBREAK;
++      else
++              lcr &= ~UART_LCR_SETBREAK;
++      UART_PUT_LCR(port, lcr);
++}
++
++static inline u_int uart_calculate_quot(struct uart_port *port, u_int baud)
++{
++      u_int quot;
++
++      /* Special case: B0 rate */
++      if (!baud)
++              baud = 9600;
++
++      quot = (port->uartclk / (16 * baud)-1)  ;
++
++      return quot;
++}
++
++static void sl2312_set_termios(struct uart_port *port, struct ktermios *termios,
++                               struct ktermios *old)
++{
++      unsigned int  uart_mc, old_ier, baud, quot;
++      unsigned long flags;
++
++        termios->c_cflag |= CREAD;
++#ifdef DEBUG
++      printk("it8712_set_cflag(0x%x) called\n", cflag);
++#endif
++        baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16);
++        quot = (port->uartclk / (16 * baud))  ;
++        //uart_get_divisor(port, baud);
++
++      /* byte size and parity */
++      switch (termios->c_cflag & CSIZE) {
++      case CS5:
++              uart_mc = UART_LCR_LEN5;
++              break;
++      case CS6:
++              uart_mc = UART_LCR_LEN6;
++              break;
++      case CS7:
++              uart_mc = UART_LCR_LEN7;
++              break;
++      default: // CS8
++              uart_mc = UART_LCR_LEN8;
++              break;
++      }
++
++      if (termios->c_cflag & CSTOPB)
++              uart_mc|= UART_LCR_STOP;
++      if (termios->c_cflag & PARENB) {
++              uart_mc |= UART_LCR_EVEN;
++              if (!(termios->c_cflag & PARODD))
++                      uart_mc |= UART_LCR_ODD;
++      }
++
++    spin_lock_irqsave(&port->lock, flags);
++        /*
++         * Update the per-port timeout
++         */
++        uart_update_timeout(port, termios->c_cflag, baud);
++      port->read_status_mask = UART_LSR_OE;
++      if (termios->c_iflag & INPCK)
++              port->read_status_mask |= UART_LSR_FE | UART_LSR_PE;
++      if (termios->c_iflag & (BRKINT | PARMRK))
++              port->read_status_mask |= UART_LSR_BI;
++
++      /*
++       * Characters to ignore
++       */
++      port->ignore_status_mask = 0;
++      if (termios->c_iflag & IGNPAR)
++              port->ignore_status_mask |= UART_LSR_FE | UART_LSR_PE;
++      if (termios->c_iflag & IGNBRK) {
++              port->ignore_status_mask |= UART_LSR_BI;
++              /*
++               * If we're ignoring parity and break indicators,
++               * ignore overruns to (for real raw support).
++               */
++              if (termios->c_iflag & IGNPAR)
++                      port->ignore_status_mask |= UART_LSR_OE;
++      }
++
++      //save_flags(flags); cli();
++      old_ier = UART_GET_IER(port);
++
++        if(UART_ENABLE_MS(port, termios->c_cflag))
++             old_ier |= UART_IER_MS;
++
++      /* Set baud rate */
++      UART_PUT_LCR(port, UART_LCR_DLAB);
++      UART_PUT_DIV_LO(port, (quot & 0xff));
++      UART_PUT_DIV_HI(port, ((quot & 0xf00) >> 8));
++
++      UART_PUT_LCR(port, uart_mc);
++      UART_PUT_IER(port, old_ier);
++
++      //restore_flags(flags);
++      spin_unlock_irqrestore(&port->lock, flags);
++}
++
++
++
++static int sl2312_startup(struct uart_port *port)
++{
++      int retval;
++      unsigned int regs;
++
++//        printk("sl2312 startup : \n");
++
++      /*
++       * Use iobase to store a pointer to info. We need this to start a
++       * transmission as the tranmittr interrupt is only generated on
++       * the transition to the idle state
++       */
++
++      /*
++       * Allocate the IRQ
++       */
++      retval = request_irq(port->irq, sl2312_int, IRQF_DISABLED, "sl2312", port);
++      if (retval)
++              return retval;
++
++        /* setup interrupt controller  */
++        regs = *((volatile unsigned int *)IRQ_TMODE(IO_ADDRESS(SL2312_INTERRUPT_BASE)));
++        regs &= ~(IRQ_UART_MASK);
++        *((volatile unsigned int *)IRQ_TMODE(IO_ADDRESS(SL2312_INTERRUPT_BASE))) = regs;
++        regs = *((volatile unsigned int *)IRQ_TLEVEL(IO_ADDRESS(SL2312_INTERRUPT_BASE)));
++        regs &= ~(IRQ_UART_MASK);
++        *((volatile unsigned int *)IRQ_TLEVEL(IO_ADDRESS(SL2312_INTERRUPT_BASE))) = regs;
++        *((volatile unsigned int *)IRQ_MASK(IO_ADDRESS(SL2312_INTERRUPT_BASE))) |= (unsigned int)(IRQ_UART_MASK);
++
++      /*
++       * Finally, enable interrupts. Use the TII interrupt to minimise
++       * the number of interrupts generated. If higher performance is
++       * needed, consider using the TI interrupt with a suitable FIFO
++       * threshold
++       */
++      UART_PUT_IER(port, (UART_IER_DR|UART_IER_TE));
++
++      return 0;
++}
++
++static void sl2312_shutdown(struct uart_port *port)
++{
++//        printk("sl2312 shutdown : \n");
++
++      /*
++       * disable all interrupts, disable the port
++       */
++      UART_PUT_IER(port, 0x0);
++
++      /* disable break condition and fifos */
++//    UART_PUT_MCR(port, (UART_GET_MCR(port)&UART_MCR_MASK));
++
++      /*
++       * Free the interrupt
++       */
++      free_irq(port->irq, port);
++}
++
++static const char *sl2312_type(struct uart_port *port)
++{
++      return port->type == PORT_SL2312 ? "SL2312" : NULL;
++}
++
++/*
++ * Release the memory region(s) being used by 'port'
++ */
++static void sl2312_release_port(struct uart_port *port)
++{
++//        printk("sl2312 release port : \n");
++
++      release_mem_region(port->mapbase, UART_PORT_SIZE);
++}
++
++/*
++ * Request the memory region(s) being used by 'port'
++ */
++static int sl2312_request_port(struct uart_port *port)
++{
++      return request_mem_region(port->mapbase, UART_PORT_SIZE,
++                                  "serial_sl2312") != NULL ? 0 : -EBUSY;
++}
++
++/*
++ * Configure/autoconfigure the port.
++ */
++static void sl2312_config_port(struct uart_port *port, int flags)
++{
++
++      if (flags & UART_CONFIG_TYPE) {
++              if (sl2312_request_port(port) == 0)
++                      port->type = PORT_SL2312;
++      }
++}
++
++/*
++ * verify the new serial_struct (for TIOCSSERIAL).
++ */
++static int sl2312_verify_port(struct uart_port *port, struct serial_struct *ser)
++{
++      int ret = 0;
++
++      if (ser->type != PORT_UNKNOWN && ser->type != PORT_UART00)
++              ret = -EINVAL;
++      if (ser->irq < 0 || ser->irq >= NR_IRQS)
++              ret = -EINVAL;
++      if (ser->baud_base < 9600)
++              ret = -EINVAL;
++      return ret;
++}
++
++static struct uart_ops sl2312_pops = {
++      .tx_empty               =sl2312_tx_empty,
++      .set_mctrl              =sl2312_set_mctrl_null,
++      .get_mctrl              =sl2312_get_mctrl,
++      .stop_tx                =sl2312_stop_tx,
++      .start_tx               =sl2312_start_tx,
++      .stop_rx                =sl2312_stop_rx,
++      .enable_ms              =sl2312_enable_ms,
++      .break_ctl              =sl2312_break_ctl,
++      .startup                =sl2312_startup,
++      .shutdown               =sl2312_shutdown,
++      .set_termios    =sl2312_set_termios,
++      .type                   =sl2312_type,
++      .release_port   =sl2312_release_port,
++      .request_port   =sl2312_request_port,
++      .config_port    =sl2312_config_port,
++      .verify_port    =sl2312_verify_port,
++};
++
++#ifdef CONFIG_ARCH_SL2312
++
++static struct uart_port sl2312_ports[UART_NR] = {
++      {
++              membase:        (void *)IO_ADDRESS(SL2312_UART_BASE),
++              mapbase:        SL2312_UART_BASE,
++              iotype:         SERIAL_IO_MEM,
++              irq:            IRQ_UART,
++              uartclk:        UART_CLK,
++              fifosize:       16,
++              ops:            &sl2312_pops,
++              flags:          ASYNC_BOOT_AUTOCONF,
++      }
++};
++
++#endif
++
++#ifdef CONFIG_SERIAL_SL2312_CONSOLE
++#ifdef used_and_not_const_char_pointer
++static int sl2312_console_read(struct uart_port *port, char *s, u_int count)
++{
++      unsigned int status;
++      int c;
++#ifdef DEBUG
++      printk("sl2312_console_read() called\n");
++#endif
++
++      c = 0;
++      while (c < count) {
++              status = UART_GET_LSR(port);
++              if (UART_RX_DATA(status)) {
++                      *s++ = UART_GET_CHAR(port);
++                      c++;
++              } else {
++                      // nothing more to get, return
++                      return c;
++              }
++      }
++      // return the count
++      return c;
++}
++#endif
++static void sl2312_console_write(struct console *co, const char *s, unsigned count)
++{
++#ifdef CONFIG_ARCH_SL2312
++      struct uart_port *port = sl2312_ports + co->index;
++      unsigned int status, old_ies;
++      int i;
++
++      /*
++       *      First save the CR then disable the interrupts
++       */
++      old_ies = UART_GET_IER(port);
++      UART_PUT_IER(port,0x0);
++
++      /*
++       *      Now, do each character
++       */
++      for (i = 0; i < count; i++) {
++              do {
++                      status = UART_GET_LSR(port);
++              } while (!UART_TX_READY(status));
++              UART_PUT_CHAR(port, s[i]);
++              if (s[i] == '\n') {
++                      do {
++                              status = UART_GET_LSR(port);
++                      } while (!UART_TX_READY(status));
++                      UART_PUT_CHAR(port, '\r');
++              }
++      }
++
++      /*
++       *      Finally, wait for transmitter to become empty
++       *      and restore the IES
++       */
++      do {
++              status = UART_GET_LSR(port);
++      } while (!(status&UART_LSR_TE));
++      UART_PUT_IER(port, old_ies);
++#endif
++}
++
++#if 0
++static void sl2312_console_device(struct console *co,int *index)
++{
++
++      struct uart_driver *p = co->data;
++    *index = co->index;
++    return p->tty_driver;
++
++}
++#endif
++
++static void /*__init*/ sl2312_console_get_options(struct uart_port *port, int *baud, int *parity, int *bits)
++{
++//    printk("sl2312 console get options : \n");
++
++      u_int uart_mc, quot;
++      uart_mc= UART_GET_MCR(port);
++
++      *parity = 'n';
++      if (uart_mc & UART_LCR_PE) {
++              if (uart_mc & UART_LCR_EVEN)
++                      *parity = 'e';
++              else
++                      *parity = 'o';
++      }
++
++      switch (uart_mc & UART_LCR_MSK){
++
++      case UART_LCR_LEN5:
++              *bits = 5;
++              break;
++      case UART_LCR_LEN6:
++              *bits = 6;
++              break;
++      case UART_LCR_LEN7:
++              *bits = 7;
++              break;
++      case UART_LCR_LEN8:
++              *bits = 8;
++              break;
++      }
++      UART_PUT_MCR(port,UART_LCR_DLAB);
++      quot = UART_GET_DIV_LO(port) | (UART_GET_DIV_HI(port) << 8);
++      UART_PUT_MCR(port,uart_mc);
++      *baud = port->uartclk / (16 *quot );
++}
++
++static int __init sl2312_console_setup(struct console *co, char *options)
++{
++      struct uart_port *port;
++      int baud = 19200;
++      int bits = 8;
++      int parity = 'n';
++      int flow= 'n';
++
++      printk("sl2312 console setup : \n");
++
++#ifdef CONFIG_ARCH_SL2312
++      /*
++       * Check whether an invalid uart number has been specified, and
++       * if so, search for the first available port that does have
++       * console support.
++       */
++      port = uart_get_console(sl2312_ports,SL2312_NO_PORTS,co);
++#else
++      return -ENODEV;
++#endif
++
++      if (options)
++              uart_parse_options(options, &baud, &parity, &bits, &flow);
++      else
++              sl2312_console_get_options(port, &baud, &parity, &bits);
++
++      return uart_set_options(port, co, baud, parity, bits, flow);
++}
++
++extern struct uart_driver sl2312_reg;
++static struct console sl2312_console = {
++      .name      = SERIAL_SL2312_NAME,
++      .write          = sl2312_console_write,
++      .device         = uart_console_device,
++//    .device         = sl2312_console_device,
++      .setup          = sl2312_console_setup,
++//    .flags          = (CON_PRINTBUFFER|CON_ENABLED),
++      .flags          = CON_PRINTBUFFER,
++      .index          = -1,
++      .data       = &sl2312_reg,
++};
++
++static int __init sl2312_console_init(void)
++{
++      register_console(&sl2312_console);
++      return 0;
++
++}
++
++console_initcall(sl2312_console_init);
++
++#define SL2312_CONSOLE        &sl2312_console
++#else
++#define SL2312_CONSOLE        NULL
++#endif
++
++// static
++struct uart_driver sl2312_reg = {
++      .owner         = NULL,
++      .driver_name    = SERIAL_SL2312_NAME,
++      .dev_name               = SERIAL_SL2312_NAME,
++      .major          = SERIAL_SL2312_MAJOR,
++      .minor                  = SERIAL_SL2312_MINOR,
++      .nr                             = UART_NR,
++      .cons                   = SL2312_CONSOLE,
++};
++
++static int __init sl2312_init(void)
++{
++       int result;
++      //printk("serial_it8712: it871212_init \n");
++
++        result = uart_register_driver(&sl2312_reg);
++        if(result)
++             return result;
++      result = uart_add_one_port(&sl2312_reg, &sl2312_ports[0]);
++
++        return result;
++}
++
++
++__initcall(sl2312_init);
+Index: linux-2.6.23.16/include/linux/serial_core.h
+===================================================================
+--- linux-2.6.23.16.orig/include/linux/serial_core.h   2008-03-15 17:59:22.566564448 +0200
++++ linux-2.6.23.16/include/linux/serial_core.h        2008-03-15 17:59:53.568330991 +0200
+@@ -147,6 +147,10 @@
+ #define PORT_SB1250_DUART     77
++/* Storlink Soc */
++#define PORT_SL2312     72
++#define PORT_IT8712     73
++
+ #ifdef __KERNEL__
+ #include <linux/compiler.h>
+Index: linux-2.6.23.16/drivers/char/Makefile
+===================================================================
+--- linux-2.6.23.16.orig/drivers/char/Makefile 2008-03-15 17:59:22.566564448 +0200
++++ linux-2.6.23.16/drivers/char/Makefile      2008-03-17 12:19:43.252524398 +0200
+@@ -70,6 +70,16 @@
+ obj-$(CONFIG_APPLICOM)                += applicom.o
+ obj-$(CONFIG_SONYPI)          += sonypi.o
+ obj-$(CONFIG_RTC)             += rtc.o
++
++###  for Storlink SoC ###
++obj-$(CONFIG_SL2312_RTC) += sl2312_rtc.o
++obj-$(CONFIG_IT8712_GPIO)   += it8712_gpio.o
++obj-$(CONFIG_GEMINI_GPIO)   += gemini_gpio.o
++obj-$(CONFIG_GEMINI_PWC) += gemini_pwr.o
++obj-$(CONFIG_GEMINI_CIR)    += gemini_cir.o
++obj-$(CONFIG_GEMINI_I2S)    += gemini_i2s.o
++obj-$(CONFIG_SL2312_WATCHDOG) += sl2312_wd.o
++
+ obj-$(CONFIG_HPET)            += hpet.o
+ obj-$(CONFIG_GEN_RTC)         += genrtc.o
+ obj-$(CONFIG_EFI_RTC)         += efirtc.o
+Index: linux-2.6.23.16/drivers/serial/Kconfig
+===================================================================
+--- linux-2.6.23.16.orig/drivers/serial/Kconfig        2008-03-15 17:59:22.566564448 +0200
++++ linux-2.6.23.16/drivers/serial/Kconfig     2008-03-15 17:59:53.568330991 +0200
+@@ -280,6 +280,56 @@
+ comment "Non-8250 serial port support"
++config SERIAL_SL2312
++      bool "SL2312  serial port (sl2312) support"
++      depends on ARCH_SL2312
++      select SERIAL_CORE
++      select SERIAL_SL2312_CONSOLE
++      help
++         Say Y here if you want to use the hard logic uart on SWORD. This
++         driver also supports soft logic implentations of this uart core.
++
++config SERIAL_SL2312_CONSOLE
++      bool "Support for console on SL2312 serial port"
++      depends on SERIAL_SL2312
++      select SERIAL_CORE_CONSOLE
++      help
++        Say Y here if you want to support a serial console on an SWORD
++        hard logic uart or uart00 IP core.
++
++        Even if you say Y here, the currently visible virtual console
++        (/dev/tty0) will still be used as the system console by default, but
++        you can alter that using a kernel command line option such as
++        "console=ttySL0". (Try "man bootparam" or see the documentation of
++        your boot loader (lilo or loadlin) about how to pass options to the
++        kernel at boot time.)
++
++
++config SERIAL_IT8712
++      bool "Sl2312 serial port(IT8712) support"
++      depends on ARM && ARCH_SL2312 && SL2312_LPC
++      select SERIAL_CORE
++      select SERIAL_IT8712_CONSOLE
++      help
++        Say Y here if you want to use the hard logic uart on Excalibur. This
++        driver also supports soft logic implentations of this uart core.
++
++config SERIAL_IT8712_CONSOLE
++      bool "Support for console on Sword serial port(IT8712)"
++      depends on SERIAL_IT8712
++      select SERIAL_CORE_CONSOLE
++      help
++        Say Y here if you want to support a serial console on an Excalibur
++        hard logic uart or uart00 IP core.
++
++        Even if you say Y here, the currently visible virtual console
++        (/dev/tty0) will still be used as the system console by default, but
++        you can alter that using a kernel command line option such as
++        "console=ttySI0". (Try "man bootparam" or see the documentation of
++        your boot loader (lilo or loadlin) about how to pass options to the
++        kernel at boot time.)
++
++
+ config SERIAL_AMBA_PL010
+       tristate "ARM AMBA PL010 serial port support"
+       depends on ARM_AMBA && (BROKEN || !ARCH_VERSATILE)
+Index: linux-2.6.23.16/drivers/serial/Makefile
+===================================================================
+--- linux-2.6.23.16.orig/drivers/serial/Makefile       2008-03-15 17:59:22.566564448 +0200
++++ linux-2.6.23.16/drivers/serial/Makefile    2008-03-15 17:59:53.568330991 +0200
+@@ -62,5 +62,7 @@
+ obj-$(CONFIG_SERIAL_ATMEL) += atmel_serial.o
+ obj-$(CONFIG_SERIAL_UARTLITE) += uartlite.o
+ obj-$(CONFIG_SERIAL_NETX) += netx-serial.o
++obj-$(CONFIG_SERIAL_IT8712) += it8712.o
++obj-$(CONFIG_SERIAL_SL2312) += serial_sl2312.o
+ obj-$(CONFIG_SERIAL_OF_PLATFORM) += of_serial.o
+ obj-$(CONFIG_SERIAL_KS8695) += serial_ks8695.o
diff --git a/target/linux/storm/patches/1100-gpio.patch b/target/linux/storm/patches/1100-gpio.patch
new file mode 100644 (file)
index 0000000..d2ea727
--- /dev/null
@@ -0,0 +1,390 @@
+Index: linux-2.6.23.16/drivers/char/gemini_gpio_dev.c
+===================================================================
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.23.16/drivers/char/gemini_gpio_dev.c     2008-03-15 17:05:28.382258620 +0200
+@@ -0,0 +1,356 @@
++/*
++ *    GPIO driver for Gemini board
++ *    Provides /dev/gpio
++ */
++
++#include <linux/version.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/proc_fs.h>
++#include <linux/fcntl.h>
++#include <linux/miscdevice.h>
++#include <asm/uaccess.h>      /* copy_to_user, copy_from_user */
++
++#include <asm/hardware.h>
++#include <asm/io.h>
++#include <asm/arch/sl2312.h>
++#include <asm/arch/irqs.h>
++#include <asm/arch/gemini_gpio.h>
++
++#define GEMINI_GPIO_BASE1             IO_ADDRESS(SL2312_GPIO_BASE)
++#define GEMINI_GPIO_BASE2             IO_ADDRESS(SL2312_GPIO_BASE1)
++
++#define GPIO_SET      2
++#define MAX_GPIO_LINE 32*GPIO_SET
++
++wait_queue_head_t gemini_gpio_wait[MAX_GPIO_LINE];
++
++enum GPIO_REG
++{
++    GPIO_DATA_OUT             = 0x00,
++    GPIO_DATA_IN              = 0x04,
++    GPIO_PIN_DIR              = 0x08,
++    GPIO_BY_PASS              = 0x0C,
++    GPIO_DATA_SET             = 0x10,
++    GPIO_DATA_CLEAR           = 0x14,
++    GPIO_PULL_ENABLE          = 0x18,
++    GPIO_PULL_TYPE                    = 0x1C,
++    GPIO_INT_ENABLE           = 0x20,
++    GPIO_INT_RAW_STATUS       = 0x24,
++    GPIO_INT_MASK_STATUS      = 0x28,
++    GPIO_INT_MASK                     = 0x2C,
++    GPIO_INT_CLEAR                    = 0x30,
++    GPIO_INT_TRIG                     = 0x34,
++    GPIO_INT_BOTH                     = 0x38,
++    GPIO_INT_POLAR                    = 0x3C
++};
++
++unsigned int regist_gpio_int0=0,regist_gpio_int1=0;
++
++/* defines a specific GPIO bit number and state */
++struct gpio_bit {
++      unsigned char bit;
++      unsigned char state;
++};
++
++#define GPIO_MAJOR    10
++#define GPIO_MINOR    127
++
++/*
++ * ioctl calls that are permitted to the /dev/gpio interface
++ */
++#define GPIO_GET_BIT  0x0000001
++#define GPIO_SET_BIT  0x0000002
++#define GPIO_GET_CONFIG       0x0000003
++#define GPIO_SET_CONFIG 0x0000004
++
++//#define GPIO_CONFIG_OUT  1
++//#define GPIO_CONFIG_IN   2
++
++
++
++#define DEVICE_NAME "gpio"
++
++//#define DEBUG
++
++/*
++ * GPIO interface
++ */
++
++/* /dev/gpio */
++static int gpio_ioctl(struct inode *inode, struct file *file,
++                     unsigned int cmd, unsigned long arg);
++
++/* /proc/driver/gpio */
++static int gpio_read_proc(char *page, char **start, off_t off,
++                         int count, int *eof, void *data);
++
++static unsigned char gpio_status;        /* bitmapped status byte.       */
++
++/* functions for set/get gpio lines on storlink cpu */
++
++void gpio_line_get(unsigned char pin, u32 * data)
++{
++      unsigned int set = pin >>5;             // each GPIO set has 32 pins
++      unsigned int status,addr;
++
++      addr = (set ? GEMINI_GPIO_BASE2:GEMINI_GPIO_BASE1) + GPIO_DATA_IN;
++      status = readl(addr);
++#ifdef DEBUG
++      printk("status = %08X, pin = %d, set = %d\n", status, pin, set);
++#endif
++      if (set)
++                      *data = (status&(1<<(pin-32)))?1:0;
++      else
++                      *data = (status&(1<<pin))?1:0;
++}
++
++void gpio_line_set(unsigned char pin, u32 high)
++{
++      unsigned char set = pin >>5;            // each GPIO set has 32 pins
++      unsigned int status=0,addr;
++
++      addr = (set ? GEMINI_GPIO_BASE2:GEMINI_GPIO_BASE1)+(high?GPIO_DATA_SET:GPIO_DATA_CLEAR);
++
++      status &= ~(1 << (pin %32));
++      status |= (1 << (pin % 32));
++      writel(status,addr);
++}
++
++/*
++ * pin = [0..63]
++ * mode =
++ *                    1 -- OUT
++ *                    2 -- IN
++ */
++void gpio_line_config(unsigned char pin, unsigned char mode)
++{
++      unsigned char set = pin >>5;            // each GPIO set has 32 pins
++      unsigned int status,addr;
++
++      addr = (set ? GEMINI_GPIO_BASE2:GEMINI_GPIO_BASE1)+GPIO_PIN_DIR;
++      status = readl(addr);
++
++      status &= ~(1 << (pin %32));
++      if (mode == 1)
++                      status |= (1 << (pin % 32)); /* PinDir: 0 - input, 1 - output */
++
++      writel(status,addr);
++#if 0
++      /* enable pullup-high if mode is input */
++
++      addr = (set ? GEMINI_GPIO_BASE2:GEMINI_GPIO_BASE1)+GPIO_PULL_ENABLE;
++      status = readl(addr);
++
++      status &= ~(1 << (pin %32));
++      if (mode == 2) /* input */
++                      status |= (1 << (pin % 32)); /* PullEnable: 0 - disable, 1 - enable */
++
++      writel(status,addr);
++
++      addr = (set ? GEMINI_GPIO_BASE2:GEMINI_GPIO_BASE1)+GPIO_PULL_TYPE;
++      status = readl(addr);
++
++      status &= ~(1 << (pin %32));
++      if (mode == 2) /* input */
++                      status |= (1 << (pin % 32)); /* PullType: 0 - low, 1 - high */
++
++      writel(status,addr);
++#endif
++}
++
++#define GPIO_IS_OPEN             0x01    /* means /dev/gpio is in use     */
++
++/*
++ *      Now all the various file operations that we export.
++ */
++static int gpio_ioctl(struct inode *inode, struct file *file,
++                         unsigned int cmd, unsigned long arg)
++{
++              struct gpio_bit bit;
++              u32 val;
++
++              if (copy_from_user(&bit, (struct gpio_bit *)arg,
++                                                              sizeof(bit)))
++                              return -EFAULT;
++
++              switch (cmd) {
++
++                              case GPIO_GET_BIT:
++                                              gpio_line_get(bit.bit, &val);
++                                              bit.state = val;
++                                              return copy_to_user((void *)arg, &bit, sizeof(bit)) ? -EFAULT : 0;
++                              case GPIO_SET_BIT:
++                                              val = bit.state;
++                                              gpio_line_set(bit.bit, val);
++                                              return 0;
++                              case GPIO_GET_CONFIG:
++                                              // gpio_line_config(bit.bit, bit.state);
++                                              return copy_to_user((void *)arg, &bit, sizeof(bit)) ? -EFAULT : 0;
++                              case GPIO_SET_CONFIG:
++                                              val = bit.state;
++                                              gpio_line_config(bit.bit, bit.state);
++                                              return 0;
++              }
++              return -EINVAL;
++}
++
++
++static int gpio_open(struct inode *inode, struct file *file)
++{
++        if (gpio_status & GPIO_IS_OPEN)
++                return -EBUSY;
++
++        gpio_status |= GPIO_IS_OPEN;
++        return 0;
++}
++
++
++static int gpio_release(struct inode *inode, struct file *file)
++{
++        /*
++         * Turn off all interrupts once the device is no longer
++         * in use and clear the data.
++         */
++
++        gpio_status &= ~GPIO_IS_OPEN;
++        return 0;
++}
++
++
++/*
++ *      The various file operations we support.
++ */
++
++static struct file_operations gpio_fops = {
++        .owner          = THIS_MODULE,
++        .ioctl          = gpio_ioctl,
++        .open           = gpio_open,
++        .release        = gpio_release,
++};
++
++static struct miscdevice gpio_dev =
++{
++        .minor          = GPIO_MINOR,
++        .name           = "gpio",
++        .fops           = &gpio_fops,
++};
++
++
++
++
++#ifdef CONFIG_PROC_FS
++static struct proc_dir_entry *dir;
++
++/*
++ *      Info exported via "/proc/driver/gpio".
++ */
++static int gpio_get_status(char *buf)
++{
++    char *p = buf;
++      u32 val = 0;
++      int i;
++      int bit;
++#ifdef DEBUG
++      u32 addr;
++
++      for (i = 0; i < 0x20; i+=4 ) {
++                      addr = IO_ADDRESS(SL2312_GPIO_BASE) + i;
++                      val = readl(addr);
++                      p+=sprintf(p, "GPIO0: 0x%02X: %08X\n", i, val );
++      }
++      for (i = 0; i < 0x20; i+=4 ) {
++                      addr = IO_ADDRESS(SL2312_GPIO_BASE1) + i;
++                      val = readl(addr);
++                      p+=sprintf(p, "GPIO1: 0x%02X: %08X\n", i, val );
++      }
++#endif
++
++      for (i = 0; i < 32; i++) {
++                      gpio_line_get(i, &bit);
++                      if (bit)
++                                      val |= (1 << i);
++      }
++      p += sprintf(p, "gpio0\t: 0x%08x\n", val);
++
++      val = 0;
++      for (i = 32; i < 64; i++) {
++                      gpio_line_get(i, &bit);
++                      if (bit)
++                                      val |= (1 << i);
++      }
++      p += sprintf(p, "gpio1\t: 0x%08x\n", val);
++
++      return p - buf;
++}
++
++
++/* /proc/driver/gpio read op
++ */
++static int gpio_read_proc(char *page, char **start, off_t off,
++                             int count, int *eof, void *data)
++{
++        int len = gpio_get_status (page);
++
++        if (len <= off+count)
++                      *eof = 1;
++        *start = page + off;
++        len -= off;
++        if ( len > count )
++                      len = count;
++        if ( len < 0 )
++                      len = 0;
++        return len;
++}
++#endif /* CONFIG_PROC_FS */
++
++
++static int __init gpio_init_module(void)
++{
++        int retval;
++#ifdef CONFIG_PROC_FS
++      struct proc_dir_entry *res;
++#endif
++
++        /* register /dev/gpio file ops */
++      //retval = register_chrdev(GPIO_MAJOR, DEVICE_NAME, &gpio_fops);
++      retval = misc_register(&gpio_dev);
++        if(retval < 0)
++                return retval;
++
++#ifdef CONFIG_PROC_FS
++      dir = proc_mkdir("driver/gpio", NULL);
++      if (!dir) {
++              misc_deregister(&gpio_dev);
++              return -ENOMEM;
++      }
++        /* register /proc/driver/gpio */
++      res = create_proc_entry("info", 0644, dir);
++      if (res) {
++              res->read_proc= gpio_read_proc;
++      } else {
++              misc_deregister(&gpio_dev);
++              return -ENOMEM;
++      }
++#endif
++
++      printk("%s: GPIO driver loaded\n", __FILE__);
++
++      return 0;
++}
++
++static void __exit gpio_cleanup_module(void)
++{
++      remove_proc_entry ("info", dir);
++        misc_deregister(&gpio_dev);
++
++      printk("%s: GPIO driver unloaded\n", __FILE__);
++}
++
++module_init(gpio_init_module);
++module_exit(gpio_cleanup_module);
++
++MODULE_AUTHOR("Jonas Majauskas");
++MODULE_LICENSE("GPL");
++
+Index: linux-2.6.23.16/drivers/char/Kconfig
+===================================================================
+--- linux-2.6.23.16.orig/drivers/char/Kconfig  2008-03-13 17:45:54.000221290 +0200
++++ linux-2.6.23.16/drivers/char/Kconfig       2008-03-15 17:05:09.381175866 +0200
+@@ -1064,5 +1064,12 @@
+ source "drivers/s390/char/Kconfig"
++config GEMINI_GPIO_DEV
++      tristate "GPIO driver for Gemini board (provides /dev/gpio)"
++      depends on ARCH_SL2312
++      default n
++      help
++        GPIO driver for Gemini boards - SL3512, SL3516.
++
+ endmenu
+Index: linux-2.6.23.16/drivers/char/Makefile
+===================================================================
+--- linux-2.6.23.16.orig/drivers/char/Makefile 2008-03-15 17:04:35.879266660 +0200
++++ linux-2.6.23.16/drivers/char/Makefile      2008-03-15 17:05:09.381175866 +0200
+@@ -115,6 +115,7 @@
+ obj-$(CONFIG_HANGCHECK_TIMER) += hangcheck-timer.o
+ obj-$(CONFIG_TCG_TPM)         += tpm/
++obj-$(CONFIG_GEMINI_GPIO_DEV)         += gemini_gpio_dev.o
+ obj-$(CONFIG_PS3_FLASH)               += ps3flash.o
index c73e0929090b417591ebde63a6fb3abcd3de33d0..a6b0683498ca9929cc12a9d88e14752012c21231 100644 (file)
@@ -85,6 +85,7 @@ config TARGET_OPTIMIZATION
        default "-Os -pipe -march=i486 -funit-at-a-time" if TARGET_rdc
        default "-Os -pipe -mips32 -mtune=mips32 -funit-at-a-time" if mipsel || mips
        default "-Os -pipe -march=armv5te -mtune=xscale -funit-at-a-time" if TARGET_ixp4xx || TARGET_iop32x || TARGET_pxa
        default "-Os -pipe -march=i486 -funit-at-a-time" if TARGET_rdc
        default "-Os -pipe -mips32 -mtune=mips32 -funit-at-a-time" if mipsel || mips
        default "-Os -pipe -march=armv5te -mtune=xscale -funit-at-a-time" if TARGET_ixp4xx || TARGET_iop32x || TARGET_pxa
+       default "-Os -pipe -march=armv4t -mtune=arm9tdmi -funit-at-a-time" if TARGET_storm
        default "-Os -pipe -funit-at-a-time"
        help
          Optimizations to use when building for the target host.
        default "-Os -pipe -funit-at-a-time"
        help
          Optimizations to use when building for the target host.
diff --git a/toolchain/uClibc/config/arm.storm b/toolchain/uClibc/config/arm.storm
new file mode 100644 (file)
index 0000000..ee109d7
--- /dev/null
@@ -0,0 +1,210 @@
+#
+# Automatically generated make config: don't edit
+#
+# TARGET_alpha is not set
+TARGET_arm=y
+# TARGET_avr32 is not set
+# TARGET_bfin is not set
+# TARGET_cris is not set
+# TARGET_e1 is not set
+# TARGET_frv is not set
+# TARGET_h8300 is not set
+# TARGET_hppa is not set
+# TARGET_i386 is not set
+# TARGET_i960 is not set
+# TARGET_ia64 is not set
+# TARGET_m68k is not set
+# TARGET_microblaze is not set
+# TARGET_mips is not set
+# TARGET_nios is not set
+# TARGET_nios2 is not set
+# TARGET_powerpc is not set
+# TARGET_sh is not set
+# TARGET_sh64 is not set
+# TARGET_sparc is not set
+# TARGET_v850 is not set
+# TARGET_vax is not set
+# TARGET_x86_64 is not set
+
+#
+# Target Architecture Features and Options
+#
+TARGET_ARCH="arm"
+FORCE_OPTIONS_FOR_ARCH=y
+# CONFIG_ARM_OABI is not set
+CONFIG_ARM_EABI=y
+USE_BX=y
+# CONFIG_GENERIC_ARM is not set
+# CONFIG_ARM610 is not set
+# CONFIG_ARM710 is not set
+# CONFIG_ARM7TDMI is not set
+# CONFIG_ARM720T is not set
+CONFIG_ARM920T=y
+# CONFIG_ARM922T is not set
+# CONFIG_ARM926T is not set
+# CONFIG_ARM10T is not set
+# CONFIG_ARM1136JF_S is not set
+# CONFIG_ARM1176JZ_S is not set
+# CONFIG_ARM1176JZF_S is not set
+# CONFIG_ARM_SA110 is not set
+# CONFIG_ARM_SA1100 is not set
+# CONFIG_ARM_XSCALE is not set
+# CONFIG_ARM_IWMMXT is not set
+ARCH_ANY_ENDIAN=y
+# ARCH_WANTS_BIG_ENDIAN is not set
+ARCH_WANTS_LITTLE_ENDIAN=y
+ARCH_HAS_MMU=y
+ARCH_USE_MMU=y
+UCLIBC_HAS_FLOATS=y
+UCLIBC_HAS_FPU=y
+UCLIBC_HAS_SOFT_FLOAT=y
+DO_C99_MATH=y
+KERNEL_SOURCE="./toolchain_build_arm/linux"
+KERNEL_HEADERS="./toolchain_build_arm/linux/include"
+HAVE_DOT_CONFIG=y
+
+#
+# General Library Settings
+#
+# HAVE_NO_PIC is not set
+DOPIC=y
+# HAVE_NO_SHARED is not set
+HAVE_SHARED=y
+# ARCH_HAS_NO_LDSO is not set
+BUILD_UCLIBC_LDSO=y
+# FORCE_SHAREABLE_TEXT_SEGMENTS is not set
+LDSO_LDD_SUPPORT=y
+LDSO_CACHE_SUPPORT=y
+# LDSO_PRELOAD_FILE_SUPPORT is not set
+LDSO_BASE_FILENAME="ld.so"
+LDSO_RUNPATH=y
+# DL_FINI_CRT_COMPAT is not set
+UCLIBC_CTOR_DTOR=y
+# HAS_NO_THREADS is not set
+UCLIBC_HAS_THREADS=y
+# PTHREADS_DEBUG_SUPPORT is not set
+UCLIBC_HAS_LFS=y
+LINUXTHREADS_OLD=y
+# UCLIBC_STATIC_LDCONFIG is not set
+# MALLOC is not set
+# MALLOC_SIMPLE is not set
+MALLOC_STANDARD=y
+MALLOC_GLIBC_COMPAT=y
+UCLIBC_DYNAMIC_ATEXIT=y
+COMPAT_ATEXIT=y
+# UCLIBC_SUSV3_LEGACY is not set
+UCLIBC_SUSV3_LEGACY_MACROS=y
+UCLIBC_HAS_SHADOW=y
+UCLIBC_HAS_PROGRAM_INVOCATION_NAME=y
+UCLIBC_HAS___PROGNAME=y
+# UNIX98PTY_ONLY is not set
+ASSUME_DEVPTS=y
+UCLIBC_HAS_TM_EXTENSIONS=y
+UCLIBC_HAS_TZ_CACHING=y
+UCLIBC_HAS_TZ_FILE=y
+UCLIBC_HAS_TZ_FILE_READ_MANY=y
+UCLIBC_TZ_FILE_PATH="/etc/TZ"
+
+#
+# Advanced Library Settings
+#
+UCLIBC_PWD_BUFFER_SIZE=256
+UCLIBC_GRP_BUFFER_SIZE=256
+
+#
+# Networking Support
+#
+UCLIBC_HAS_IPV6=y
+UCLIBC_HAS_RPC=y
+UCLIBC_HAS_FULL_RPC=y
+# UCLIBC_HAS_REENTRANT_RPC is not set
+# UCLIBC_USE_NETLINK is not set
+UCLIBC_HAS_BSD_RES_CLOSE=y
+
+#
+# String and Stdio Support
+#
+UCLIBC_HAS_STRING_GENERIC_OPT=y
+UCLIBC_HAS_STRING_ARCH_OPT=y
+UCLIBC_HAS_CTYPE_TABLES=y
+UCLIBC_HAS_CTYPE_SIGNED=y
+# UCLIBC_HAS_CTYPE_UNSAFE is not set
+UCLIBC_HAS_CTYPE_CHECKED=y
+# UCLIBC_HAS_CTYPE_ENFORCED is not set
+UCLIBC_HAS_WCHAR=y
+# UCLIBC_HAS_LOCALE is not set
+UCLIBC_HAS_HEXADECIMAL_FLOATS=y
+UCLIBC_HAS_GLIBC_CUSTOM_PRINTF=y
+UCLIBC_PRINTF_SCANF_POSITIONAL_ARGS=9
+UCLIBC_HAS_SCANF_GLIBC_A_FLAG=y
+# UCLIBC_HAS_STDIO_BUFSIZ_NONE is not set
+# UCLIBC_HAS_STDIO_BUFSIZ_256 is not set
+# UCLIBC_HAS_STDIO_BUFSIZ_512 is not set
+# UCLIBC_HAS_STDIO_BUFSIZ_1024 is not set
+# UCLIBC_HAS_STDIO_BUFSIZ_2048 is not set
+UCLIBC_HAS_STDIO_BUFSIZ_4096=y
+# UCLIBC_HAS_STDIO_BUFSIZ_8192 is not set
+UCLIBC_HAS_STDIO_BUILTIN_BUFFER_NONE=y
+# UCLIBC_HAS_STDIO_BUILTIN_BUFFER_4 is not set
+# UCLIBC_HAS_STDIO_BUILTIN_BUFFER_8 is not set
+# UCLIBC_HAS_STDIO_SHUTDOWN_ON_ABORT is not set
+UCLIBC_HAS_STDIO_GETC_MACRO=y
+UCLIBC_HAS_STDIO_PUTC_MACRO=y
+UCLIBC_HAS_STDIO_AUTO_RW_TRANSITION=y
+# UCLIBC_HAS_FOPEN_LARGEFILE_MODE is not set
+UCLIBC_HAS_FOPEN_EXCLUSIVE_MODE=y
+UCLIBC_HAS_GLIBC_CUSTOM_STREAMS=y
+UCLIBC_HAS_PRINTF_M_SPEC=y
+UCLIBC_HAS_ERRNO_MESSAGES=y
+# UCLIBC_HAS_SYS_ERRLIST is not set
+UCLIBC_HAS_SIGNUM_MESSAGES=y
+# UCLIBC_HAS_SYS_SIGLIST is not set
+UCLIBC_HAS_GNU_GETOPT=y
+UCLIBC_HAS_GNU_GETSUBOPT=y
+
+#
+# Big and Tall
+#
+UCLIBC_HAS_REGEX=y
+UCLIBC_HAS_REGEX_OLD=y
+UCLIBC_HAS_FNMATCH=y
+UCLIBC_HAS_FNMATCH_OLD=y
+UCLIBC_HAS_WORDEXP=y
+UCLIBC_HAS_FTW=y
+UCLIBC_HAS_GLOB=y
+UCLIBC_HAS_GNU_GLOB=y
+
+#
+# Library Installation Options
+#
+SHARED_LIB_LOADER_PREFIX="/lib"
+RUNTIME_PREFIX="/"
+DEVEL_PREFIX="/usr/"
+
+#
+# Security options
+#
+# UCLIBC_BUILD_PIE is not set
+# UCLIBC_HAS_ARC4RANDOM is not set
+# HAVE_NO_SSP is not set
+# UCLIBC_HAS_SSP is not set
+UCLIBC_BUILD_RELRO=y
+# UCLIBC_BUILD_NOW is not set
+UCLIBC_BUILD_NOEXECSTACK=y
+
+#
+# uClibc development/debugging options
+#
+CROSS_COMPILER_PREFIX=""
+UCLIBC_EXTRA_CFLAGS=""
+# DODEBUG is not set
+# DODEBUG_PT is not set
+DOSTRIP=y
+# DOASSERTS is not set
+# SUPPORT_LD_DEBUG is not set
+# SUPPORT_LD_DEBUG_EARLY is not set
+# UCLIBC_MALLOC_DEBUGGING is not set
+WARNINGS="-Wall"
+# EXTRA_WARNINGS is not set
+# DOMULTI is not set
+# UCLIBC_MJN3_ONLY is not set