initial merge of infineon code for amazon, pci is still broken a bit. a big thank...
authorJohn Crispin <john@openwrt.org>
Mon, 23 Jul 2007 22:10:11 +0000 (22:10 +0000)
committerJohn Crispin <john@openwrt.org>
Mon, 23 Jul 2007 22:10:11 +0000 (22:10 +0000)
SVN-Revision: 8137

47 files changed:
target/linux/amazon-2.6/Makefile [new file with mode: 0644]
target/linux/amazon-2.6/base-files/default/etc/config/network [new file with mode: 0644]
target/linux/amazon-2.6/config/default [new file with mode: 0644]
target/linux/amazon-2.6/files/arch/mips/amazon/Kconfig [new file with mode: 0644]
target/linux/amazon-2.6/files/arch/mips/amazon/Makefile [new file with mode: 0644]
target/linux/amazon-2.6/files/arch/mips/amazon/dma-core.c [new file with mode: 0644]
target/linux/amazon-2.6/files/arch/mips/amazon/dma-core.h [new file with mode: 0644]
target/linux/amazon-2.6/files/arch/mips/amazon/interrupt.c [new file with mode: 0644]
target/linux/amazon-2.6/files/arch/mips/amazon/pci.c [new file with mode: 0644]
target/linux/amazon-2.6/files/arch/mips/amazon/prom.c [new file with mode: 0644]
target/linux/amazon-2.6/files/arch/mips/amazon/setup.c [new file with mode: 0644]
target/linux/amazon-2.6/files/drivers/atm/amazon_tpe.c [new file with mode: 0644]
target/linux/amazon-2.6/files/drivers/char/admmod.c [new file with mode: 0644]
target/linux/amazon-2.6/files/drivers/char/amazon_mei.c [new file with mode: 0644]
target/linux/amazon-2.6/files/drivers/char/amazon_wdt.c [new file with mode: 0644]
target/linux/amazon-2.6/files/drivers/char/ifx_ssc.c [new file with mode: 0644]
target/linux/amazon-2.6/files/drivers/mtd/maps/amazon.c [new file with mode: 0644]
target/linux/amazon-2.6/files/drivers/net/amazon_sw.c [new file with mode: 0644]
target/linux/amazon-2.6/files/drivers/serial/amazon_asc.c [new file with mode: 0644]
target/linux/amazon-2.6/files/include/asm-mips/amazon/adm6996.h [new file with mode: 0644]
target/linux/amazon-2.6/files/include/asm-mips/amazon/amazon.h [new file with mode: 0644]
target/linux/amazon-2.6/files/include/asm-mips/amazon/amazon_dma.h [new file with mode: 0644]
target/linux/amazon-2.6/files/include/asm-mips/amazon/amazon_mei.h [new file with mode: 0644]
target/linux/amazon-2.6/files/include/asm-mips/amazon/amazon_mei_app.h [new file with mode: 0644]
target/linux/amazon-2.6/files/include/asm-mips/amazon/amazon_mei_app_ioctl.h [new file with mode: 0644]
target/linux/amazon-2.6/files/include/asm-mips/amazon/amazon_mei_ioctl.h [new file with mode: 0644]
target/linux/amazon-2.6/files/include/asm-mips/amazon/amazon_sw.h [new file with mode: 0644]
target/linux/amazon-2.6/files/include/asm-mips/amazon/amazon_tpe.h [new file with mode: 0644]
target/linux/amazon-2.6/files/include/asm-mips/amazon/amazon_wdt.h [new file with mode: 0644]
target/linux/amazon-2.6/files/include/asm-mips/amazon/atm_defines.h [new file with mode: 0644]
target/linux/amazon-2.6/files/include/asm-mips/amazon/atm_mib.h [new file with mode: 0644]
target/linux/amazon-2.6/files/include/asm-mips/amazon/ifx_peripheral_definitions.h [new file with mode: 0644]
target/linux/amazon-2.6/files/include/asm-mips/amazon/ifx_ssc.h [new file with mode: 0644]
target/linux/amazon-2.6/files/include/asm-mips/amazon/ifx_ssc_defines.h [new file with mode: 0644]
target/linux/amazon-2.6/files/include/asm-mips/amazon/irq.h [new file with mode: 0644]
target/linux/amazon-2.6/files/include/asm-mips/amazon/model.h [new file with mode: 0644]
target/linux/amazon-2.6/files/include/asm-mips/amazon/port.h [new file with mode: 0644]
target/linux/amazon-2.6/files/include/asm-mips/amazon/serial.h [new file with mode: 0644]
target/linux/amazon-2.6/files/include/asm-mips/mach-amazon/irq.h [new file with mode: 0644]
target/linux/amazon-2.6/files/include/asm-mips/mach-amazon/mangle-port.h [new file with mode: 0644]
target/linux/amazon-2.6/image/Makefile [new file with mode: 0644]
target/linux/amazon-2.6/patches/100-board.patch [new file with mode: 0644]
target/linux/amazon-2.6/patches/110-char_drivers.patch [new file with mode: 0644]
target/linux/amazon-2.6/patches/130-mtd_drivers.patch [new file with mode: 0644]
target/linux/amazon-2.6/patches/140-net_drivers.patch [new file with mode: 0644]
target/linux/amazon-2.6/patches/150-serial_driver.patch [new file with mode: 0644]
target/linux/amazon-2.6/patches/160-cfi-swap.patch [new file with mode: 0644]

diff --git a/target/linux/amazon-2.6/Makefile b/target/linux/amazon-2.6/Makefile
new file mode 100644 (file)
index 0000000..1967d52
--- /dev/null
@@ -0,0 +1,25 @@
+# 
+# Copyright (C) 2006 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+include $(TOPDIR)/rules.mk
+
+ARCH:=mips
+BOARD:=amazon
+BOARDNAME:=Infineon Amazon
+FEATURES:=squashfs jffs2 broken
+
+define Target/Description
+       Build firmware images for Infineon Amazon boards
+endef
+
+KERNELNAME:="uImage"
+
+include $(INCLUDE_DIR)/kernel-build.mk
+
+# include the profiles
+-include profiles/*.mk
+
+$(eval $(call BuildKernel))
diff --git a/target/linux/amazon-2.6/base-files/default/etc/config/network b/target/linux/amazon-2.6/base-files/default/etc/config/network
new file mode 100644 (file)
index 0000000..72e39f8
--- /dev/null
@@ -0,0 +1,14 @@
+# Copyright (C) 2006 OpenWrt.org
+
+config interface loopback
+       option ifname   lo
+       option proto    static
+       option ipaddr   127.0.0.1
+       option netmask  255.0.0.0
+
+config interface lan
+       option ifname   eth1
+       option type     bridge
+       option proto    static
+       option ipaddr   192.168.1.1
+       option netmask  255.255.255.0
diff --git a/target/linux/amazon-2.6/config/default b/target/linux/amazon-2.6/config/default
new file mode 100644 (file)
index 0000000..2229e63
--- /dev/null
@@ -0,0 +1,211 @@
+CONFIG_32BIT=y
+# CONFIG_64BIT is not set
+# CONFIG_64BIT_PHYS_ADDR is not set
+CONFIG_AMAZON=y
+CONFIG_AMAZON_ASC_UART=y
+CONFIG_AMAZON_MTD=y
+CONFIG_AMAZON_NET_SW=y
+CONFIG_AMAZON_PCI=y
+CONFIG_AMAZON_WDT=y
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+# CONFIG_ATM is not set
+# CONFIG_ATMEL is not set
+CONFIG_BASE_SMALL=0
+# CONFIG_BCM43XX is not set
+CONFIG_BITREVERSE=y
+# CONFIG_BT is not set
+CONFIG_CMDLINE="console=ttyS0,115200 rootfstype=squashfs,jffs2 init=/bin/sh"
+CONFIG_CPU_BIG_ENDIAN=y
+CONFIG_CPU_HAS_LLSC=y
+CONFIG_CPU_HAS_PREFETCH=y
+CONFIG_CPU_HAS_SYNC=y
+# CONFIG_CPU_LITTLE_ENDIAN is not set
+CONFIG_CPU_MIPS32=y
+CONFIG_CPU_MIPS32_R1=y
+# CONFIG_CPU_MIPS32_R2 is not set
+# CONFIG_CPU_MIPS64_R1 is not set
+# CONFIG_CPU_MIPS64_R2 is not set
+CONFIG_CPU_MIPSR1=y
+# CONFIG_CPU_NEVADA is not set
+# CONFIG_CPU_R10000 is not set
+# CONFIG_CPU_R3000 is not set
+# CONFIG_CPU_R4300 is not set
+# CONFIG_CPU_R4X00 is not set
+# CONFIG_CPU_R5000 is not set
+# CONFIG_CPU_R5432 is not set
+# CONFIG_CPU_R6000 is not set
+# CONFIG_CPU_R8000 is not set
+# CONFIG_CPU_RM7000 is not set
+# CONFIG_CPU_RM9000 is not set
+# CONFIG_CPU_SB1 is not set
+CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y
+CONFIG_CPU_SUPPORTS_HIGHMEM=y
+# CONFIG_CPU_TX39XX is not set
+# CONFIG_CPU_TX49XX is not set
+# CONFIG_CPU_VR41XX is not set
+# CONFIG_DDB5477 is not set
+# CONFIG_DM9000 is not set
+CONFIG_DMA_NEED_PCI_MAP_STATE=y
+CONFIG_DMA_NONCOHERENT=y
+CONFIG_EARLY_PRINTK=y
+CONFIG_FS_POSIX_ACL=y
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+# CONFIG_GENERIC_GPIO is not set
+# CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ is not set
+# CONFIG_GEN_RTC is not set
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAVE_STD_PC_SERIAL_PORT=y
+# CONFIG_HERMES is not set
+# CONFIG_HOSTAP is not set
+CONFIG_HW_HAS_PCI=y
+CONFIG_HW_RANDOM=y
+# CONFIG_I2C is not set
+# CONFIG_IDE is not set
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_IPW2100 is not set
+# CONFIG_IPW2200 is not set
+CONFIG_IRQ_CPU=y
+CONFIG_JFFS2_FS_DEBUG=0
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+# CONFIG_MACH_DECSTATION is not set
+# CONFIG_MACH_JAZZ is not set
+# CONFIG_MACH_VR41XX is not set
+CONFIG_MIPS=y
+# CONFIG_MIPS_ATLAS is not set
+# CONFIG_MIPS_BOSPORUS is not set
+# CONFIG_MIPS_COBALT is not set
+# CONFIG_MIPS_DB1000 is not set
+# CONFIG_MIPS_DB1100 is not set
+# CONFIG_MIPS_DB1200 is not set
+# CONFIG_MIPS_DB1500 is not set
+# CONFIG_MIPS_DB1550 is not set
+# CONFIG_MIPS_EV64120 is not set
+CONFIG_MIPS_L1_CACHE_SHIFT=5
+# CONFIG_MIPS_MALTA is not set
+# CONFIG_MIPS_MIRAGE is not set
+# CONFIG_MIPS_MTX1 is not set
+CONFIG_MIPS_MT_DISABLED=y
+# CONFIG_MIPS_MT_SMP is not set
+# CONFIG_MIPS_MT_SMTC is not set
+# CONFIG_MIPS_PB1000 is not set
+# CONFIG_MIPS_PB1100 is not set
+# CONFIG_MIPS_PB1200 is not set
+# CONFIG_MIPS_PB1500 is not set
+# CONFIG_MIPS_PB1550 is not set
+# CONFIG_MIPS_SEAD is not set
+# CONFIG_MIPS_SIM is not set
+# CONFIG_MIPS_VPE_LOADER is not set
+# CONFIG_MIPS_XXS1500 is not set
+# CONFIG_MOMENCO_JAGUAR_ATX is not set
+# CONFIG_MOMENCO_OCELOT is not set
+# CONFIG_MOMENCO_OCELOT_3 is not set
+# CONFIG_MOMENCO_OCELOT_C is not set
+# CONFIG_MOMENCO_OCELOT_G is not set
+CONFIG_MTD=y
+# CONFIG_MTD_ABSENT is not set
+CONFIG_MTD_AMAZON_BUS_WIDTH_16=y
+# CONFIG_MTD_AMAZON_BUS_WIDTH_32 is not set
+# CONFIG_MTD_AMAZON_BUS_WIDTH_8 is not set
+# CONFIG_MTD_AMAZON_FLASH_SIZE_16 is not set
+# CONFIG_MTD_AMAZON_FLASH_SIZE_2 is not set
+CONFIG_MTD_AMAZON_FLASH_SIZE_4=y
+# CONFIG_MTD_AMAZON_FLASH_SIZE_8 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 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# 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=y
+# 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=y
+# 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=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_OBSOLETE_CHIPS is not set
+# CONFIG_MTD_ONENAND is not set
+# CONFIG_MTD_OTP is not set
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_PCI is not set
+# CONFIG_MTD_PHRAM is not set
+CONFIG_MTD_PHYSMAP=y
+CONFIG_MTD_PHYSMAP_BANKWIDTH=0
+CONFIG_MTD_PHYSMAP_LEN=0x0
+CONFIG_MTD_PHYSMAP_START=0x0
+# CONFIG_MTD_PLATRAM is not set
+# CONFIG_MTD_PMC551 is not set
+# CONFIG_MTD_RAM is not set
+CONFIG_MTD_REDBOOT_DIRECTORY_BLOCK=-3
+CONFIG_MTD_REDBOOT_PARTS=y
+CONFIG_MTD_REDBOOT_PARTS_READONLY=y
+# CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_NET_PCI is not set
+CONFIG_NET_SCH_FIFO=y
+# CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_PAGE_SIZE_16KB is not set
+CONFIG_PAGE_SIZE_4KB=y
+# CONFIG_PAGE_SIZE_64KB is not set
+# CONFIG_PAGE_SIZE_8KB is not set
+# CONFIG_PCIPCWATCHDOG is not set
+# CONFIG_PMC_YOSEMITE is not set
+# CONFIG_PNPACPI is not set
+# CONFIG_PNX8550_JBS is not set
+# CONFIG_PNX8550_STB810 is not set
+# CONFIG_PRISM54 is not set
+# CONFIG_RTC is not set
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
+# CONFIG_SERIAL_8250 is not set
+# CONFIG_SGI_IP22 is not set
+# CONFIG_SGI_IP27 is not set
+# CONFIG_SGI_IP32 is not set
+# CONFIG_SIBYTE_BIGSUR is not set
+# CONFIG_SIBYTE_CARMEL is not set
+# CONFIG_SIBYTE_CRHINE is not set
+# CONFIG_SIBYTE_CRHONE is not set
+# CONFIG_SIBYTE_LITTLESUR is not set
+# CONFIG_SIBYTE_PTSWARM is not set
+# CONFIG_SIBYTE_RHONE is not set
+# CONFIG_SIBYTE_SENTOSA is not set
+# CONFIG_SIBYTE_SWARM is not set
+# CONFIG_SOFT_WATCHDOG is not set
+# CONFIG_SPARSEMEM_STATIC is not set
+CONFIG_SYSVIPC_SYSCTL=y
+CONFIG_SYS_HAS_CPU_MIPS32_R1=y
+CONFIG_SYS_HAS_EARLY_PRINTK=y
+CONFIG_SYS_SUPPORTS_32BIT_KERNEL=y
+CONFIG_SYS_SUPPORTS_ARBIT_HZ=y
+CONFIG_SYS_SUPPORTS_BIG_ENDIAN=y
+# CONFIG_TOSHIBA_JMR3927 is not set
+# CONFIG_TOSHIBA_RBTX4927 is not set
+# CONFIG_TOSHIBA_RBTX4938 is not set
+CONFIG_TRAD_SIGNALS=y
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_USB is not set
diff --git a/target/linux/amazon-2.6/files/arch/mips/amazon/Kconfig b/target/linux/amazon-2.6/files/arch/mips/amazon/Kconfig
new file mode 100644 (file)
index 0000000..179e35e
--- /dev/null
@@ -0,0 +1,63 @@
+# copyright 2007 john crispin <blogic@openwrt.org>
+
+menu "Amazon built-in"
+
+config AMAZON_ASC_UART
+       bool "Amazon asc uart"
+       select SERIAL_CORE
+       select SERIAL_CORE_CONSOLE
+       default y
+
+config AMAZON_PCI
+       bool "Amazon PCI support"
+       default y
+       select HW_HAS_PCI
+       select PCI
+
+config AMAZON_NET_SW
+       bool "Amazon network"
+       default y
+
+config AMAZON_WDT
+       bool "Amazon watchdog timer"
+       default y
+
+config AMAZON_MTD
+       bool "Amazon MTD map"
+       default y
+
+choice 
+       prompt "Flash Size"
+       depends on AMAZON_MTD
+
+config MTD_AMAZON_FLASH_SIZE_2
+       bool "2MB"
+
+config MTD_AMAZON_FLASH_SIZE_4
+       bool "4MB"
+
+config MTD_AMAZON_FLASH_SIZE_8
+       bool "8MB"
+
+config MTD_AMAZON_FLASH_SIZE_16
+       bool "16MB"
+
+endchoice
+
+choice 
+       prompt "Bus Width"
+       depends on AMAZON_MTD
+
+config MTD_AMAZON_BUS_WIDTH_8
+       bool "8-bit"
+
+config MTD_AMAZON_BUS_WIDTH_16
+       bool "16-bit"
+
+config MTD_AMAZON_BUS_WIDTH_32
+       bool "32-bit"
+
+endchoice
+
+
+endmenu
diff --git a/target/linux/amazon-2.6/files/arch/mips/amazon/Makefile b/target/linux/amazon-2.6/files/arch/mips/amazon/Makefile
new file mode 100644 (file)
index 0000000..9cdc100
--- /dev/null
@@ -0,0 +1,9 @@
+#
+#  Copyright 2007 openwrt.org
+#       John Crispin <blogic@openwrt.org>
+#
+# Makefile for Infineon Amazon
+#
+obj-y := dma-core.o interrupt.o prom.o setup.o
+obj-$(CONFIG_PCI) += pci.o
+
diff --git a/target/linux/amazon-2.6/files/arch/mips/amazon/dma-core.c b/target/linux/amazon-2.6/files/arch/mips/amazon/dma-core.c
new file mode 100644 (file)
index 0000000..242bc77
--- /dev/null
@@ -0,0 +1,1455 @@
+/*
+ *   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.
+ */
+//-----------------------------------------------------------------------
+/*
+ * Description:
+ *     Driver for Infineon Amazon DMA
+ */
+//-----------------------------------------------------------------------
+/* Author:     Wu Qi Ming[Qi-Ming.Wu@infineon.com]
+ * Created:    7-April-2004
+ */
+//-----------------------------------------------------------------------
+/* History
+ * Last changed on: 4-May-2004
+ * Last changed by: <peng.liu@infineon.com>
+ * Reason: debug
+ */
+//----------------------------------------------------------------------- 
+/* Last changed on: 03-Dec-2004
+ * Last changed by: peng.liu@infineon.com
+ * Reason: recover from TPE bug 
+ */
+
+//000004:fchang 2005/6/2 Modified by Linpeng as described below
+//----------------------------------------------------------------------- 
+/* Last changed on: 28-Jan-2004
+ * Last changed by: peng.liu@infineon.com
+ * Reason: 
+ * - handle "out of memory" bug
+ */
+//000003:tc.chen 2005/06/16 fix memory leak when Tx buffer full (heaving traffic).
+//507261:tc.chen 2005/07/26 re-organize code address map to improve performance.
+
+#if defined(CONFIG_MODVERSIONS) && !defined(MODVERSIONS)
+#define MODVERSIONS
+#endif
+
+#if defined(MODVERSIONS) && !defined(__GENKSYMS__)
+#include <linux/modversions.h>
+#endif
+
+#ifndef EXPORT_SYMTAB
+#define EXPORT_SYMTAB                  /* need this one 'cause we export symbols */
+#endif
+
+#undef DMA_NO_POLLING
+
+/* no TX interrupt handling */
+#define NO_TX_INT
+/* need for DMA workaround */
+#undef AMAZON_DMA_TPE_AAL5_RECOVERY
+
+#ifdef AMAZON_DMA_TPE_AAL5_RECOVERY
+#define MAX_SYNC_FAILS 1000000 // 000004:fchang
+unsigned int dma_sync_fails = 0;
+unsigned int total_dma_tpe_reset = 0;
+int (*tpe_reset) (void);
+int (*tpe_start) (void);
+int (*tpe_inject) (void);
+#endif                                                 // AMAZON_DMA_TPE_AAL5_RECOVERY
+
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/fs.h>
+#include <linux/errno.h>
+#include <linux/proc_fs.h>
+#include <linux/stat.h>
+#include <linux/mm.h>
+#include <linux/tty.h>
+#include <linux/selection.h>
+#include <linux/kmod.h>
+#include <linux/vmalloc.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <asm/uaccess.h>
+#include <linux/errno.h>
+#include <asm/io.h>
+
+#include <asm/amazon/amazon.h>
+#include <asm/amazon/irq.h>
+#include <asm/amazon/amazon_dma.h>
+#include "dma-core.h"
+
+#define AMAZON_DMA_EMSG(fmt, args...) printk( KERN_ERR  "%s: " fmt,__FUNCTION__, ## args)
+
+static irqreturn_t dma_interrupt(int irq, void *dev_id);
+extern void mask_and_ack_amazon_irq(unsigned int irq_nr);
+
+/***************************************** global data *******************************************/
+u64 *g_desc_list;
+dev_list *g_current_dev = NULL;
+dev_list *g_head_dev = NULL;
+dev_list *g_tail_dev = NULL;
+channel_info g_log_chan[CHAN_TOTAL_NUM + 1];
+struct proc_dir_entry *g_amazon_dma_dir;
+static u8 rx_chan_list_len = 0;
+static u8 tx_chan_list_len = 0;
+static int rx_chan_list[RX_CHAN_NUM + 1];
+static int tx_chan_list[TX_CHAN_NUM + 1];
+static u32 comb_isr_mask[CHAN_TOTAL_NUM];
+
+static inline int is_rx_chan(int chan_no)
+/*judge if this is an rx channel*/
+{
+       int result = 0;
+       if (chan_no < RX_CHAN_NUM)
+               result = 1;
+       return result;
+}
+
+/* Ugly, Channel ON register is badly mapped to channel no. */
+static u8 ch_on_mapping[CHAN_TOTAL_NUM] =
+       { 0, 1, 2, 3, 6, 7, 10, 4, 5, 8, 9, 11 };
+
+/* Brief:      check wether the chan_no is legal
+ * Parameter:          chan_no: logical channel number
+ * Return:     0 if is not valid
+ *             1 if is valid
+ */
+static inline int is_valid_dma_ch(int chan_no)
+{
+       return ((chan_no >= 0) && (chan_no < CHAN_TOTAL_NUM));
+}
+
+/* Brief:      check whether a channel is open through Channel ON register
+ * Parameter:  chan_no: logical channel number
+ * Return:     1 channel is open
+ *             0 not yet
+ *             EINVAL: invalid parameter
+ */
+static inline int is_channel_open(int chan_no)
+{
+       return (AMAZON_DMA_REG32(AMAZON_DMA_CH_ON) &
+                       (1 << ch_on_mapping[chan_no]));
+}
+
+/* Brief: add a list entry
+ * Description: 
+ *     always add to the tail and no redundancy allowed. (i.e. entries are unique)
+ *     0       : entry deleted
+ *     <0      : not deleted (due to not unique)
+ */
+static inline int _add_list_entry(int *list, int size_of_list, int entry)
+{
+       int i;
+       for (i = 0; i < size_of_list; i++) {
+               if (list[i] == entry)
+                       break;
+               if (list[i] < 0) {
+                       list[i] = entry;
+                       return 0;
+               }
+       }
+       return -1;
+}
+
+/* Brief: delete a list entry
+ * Description:
+ *     find the entry and remove it. shift all entries behind it one step forward if necessary\
+ * Return:
+ *     0       : entry deleted
+ *     <0      : not deleted (due to not found?)
+ */
+static inline int _delete_list_entry(int *list, int size_of_list,
+                                                                        int entry)
+{
+       int i, j;
+       for (i = 0; i < size_of_list; i++) {
+               if (list[i] == entry) {
+                       for (j = i; j < size_of_list; j++) {
+                               list[j] = list[j + 1];
+                               if (list[j + 1] < 0) {
+                                       break;
+                               }
+                       }
+                       return 0;
+               }
+       }
+       return -1;
+}
+
+/* Brief:      enable a channel through Channel ON register
+ * Parameter:  chan_no: logical channel number
+ * Description:        
+ *     Please don't open a channel without a valid descriptor (hardware pitfall)
+ */
+static inline void open_channel(int chan_no)
+{
+       AMAZON_DMA_REG32(AMAZON_DMA_CH_ON) |= (1 << ch_on_mapping[chan_no]);
+       if (is_rx_chan(chan_no)) {
+               if (_add_list_entry(rx_chan_list, RX_CHAN_NUM, chan_no) == 0) {
+                       rx_chan_list_len++;
+               } else {
+                       AMAZON_DMA_DMSG("cannot add chan %d to open list\n", chan_no);
+               }
+       } else {
+               if (_add_list_entry(tx_chan_list, TX_CHAN_NUM, chan_no) == 0) {
+                       tx_chan_list_len++;
+               } else {
+                       AMAZON_DMA_DMSG("cannot add chan %d to open list\n", chan_no);
+               }
+       }
+}
+
+/* Brief:      disable a channel through Channel ON register
+ * Parameter:  chan_no: logical channel number
+ */
+
+static inline void close_channel(int chan_no)
+{
+       AMAZON_DMA_REG32(AMAZON_DMA_CH_ON) &= ~(1 << ch_on_mapping[chan_no]);
+       if (is_rx_chan(chan_no)) {
+               if (_delete_list_entry(rx_chan_list, RX_CHAN_NUM, chan_no) == 0) {
+                       rx_chan_list_len--;
+               } else {
+                       AMAZON_DMA_DMSG("cannot remove chan %d from open list \n",
+                                                       chan_no);
+               }
+       } else {
+               if (_delete_list_entry(tx_chan_list, TX_CHAN_NUM, chan_no) == 0) {
+                       tx_chan_list_len--;
+               } else {
+                       AMAZON_DMA_DMSG("cannot remove chan %d from open list \n",
+                                                       chan_no);
+               }
+       }
+}
+
+/* Brief: clear RX interrupt
+ */
+inline void rx_chan_clear_isr(int chan_no)
+{
+#ifdef DMA_NO_POLLING
+       AMAZON_DMA_REG32(AMAZON_DMA_CH0_ISR + chan_no * AMAZON_DMA_CH_STEP) =
+               (AMAZON_DMA_REG32
+                (AMAZON_DMA_CH0_ISR +
+                 chan_no *
+                 AMAZON_DMA_CH_STEP) & (DMA_ISR_CPT | DMA_ISR_EOP | DMA_ISR_CMDCPT
+                                                                | DMA_ISR_DURR));
+#else
+       AMAZON_DMA_REG32(AMAZON_DMA_CH0_ISR + chan_no * AMAZON_DMA_CH_STEP) =
+               (AMAZON_DMA_REG32
+                (AMAZON_DMA_CH0_ISR +
+                 chan_no *
+                 AMAZON_DMA_CH_STEP) & (DMA_ISR_CPT | DMA_ISR_EOP |
+                                                                DMA_ISR_CMDCPT));
+#endif
+}
+
+
+/* Brief:      hacking function, this will reset all descriptors back to DMA
+ */
+static void dma_reset_all_descriptors(int chan_no)
+{
+       volatile struct rx_desc *rx_desc_p = NULL;
+       int i;
+       rx_desc_p =
+               (struct rx_desc *) g_desc_list +
+               g_log_chan[chan_no].offset_from_base;
+       for (i = 0; i < g_log_chan[chan_no].desc_len; i++) {
+               rx_desc_p->status.word &=
+                       (~(DMA_DESC_SOP_SET | DMA_DESC_EOP_SET | DMA_DESC_CPT_SET));
+               rx_desc_p->status.word |=
+                       (DMA_DESC_OWN_DMA | g_log_chan[chan_no].packet_size);
+               rx_desc_p++;
+       }
+}
+
+#ifdef AMAZON_DMA_TPE_AAL5_RECOVERY
+/* Brief:      Reset DMA descriptors 
+ */
+static void amazon_dma_reset_tpe_rx(int chan_no)
+{
+       struct tx_desc *tx_desc_p = NULL;
+       int j, i = 0;
+
+       // wait until all TX channels stop transmitting
+       for (j = 9; j <= 10; j++) {
+               tx_desc_p =
+                       (struct tx_desc *) g_desc_list +
+                       g_log_chan[j].offset_from_base;
+               for (i = 0; i < g_log_chan[j].desc_len; i++) {
+                       while ((tx_desc_p->status.field.OWN != CPU_OWN)) {
+                               AMAZON_DMA_DMSG("DMA TX in progress\n");        // 000004:fchang
+                               udelay(100);
+                       }
+                       tx_desc_p++;
+               }
+       }
+
+       if (tpe_reset) {
+               total_dma_tpe_reset++;
+               AMAZON_DMA_DMSG
+                       ("\n===============resetting TPE========================== \n");
+               if ((*tpe_reset) ()) {
+                       panic("cannot reset TPE engien\n");     // 000004:fchang
+               }
+       } else {
+               panic("no tpe_reset function\n");       // 000004:fchang
+               return;
+       }
+       dma_reset_all_descriptors(chan_no);
+       rx_chan_clear_isr(chan_no);
+       mb();
+
+       // send EoP
+       if (tpe_inject) {
+               if ((*tpe_inject) ()) {
+                       panic("cannot inject a cell\n");        // 000004:fchang
+               }
+       } else {
+               AMAZON_DMA_EMSG("no tpe_inject function\n");
+               return;
+       }
+       mb();
+       while (1) {
+               if (AMAZON_DMA_REG32
+                       (AMAZON_DMA_CH0_ISR +
+                        chan_no * AMAZON_DMA_CH_STEP) & (DMA_ISR_CPT)) {
+                       rx_chan_clear_isr(chan_no);
+                       mb();
+                       dma_reset_all_descriptors(chan_no);
+                       if (g_log_chan[chan_no].current_desc ==
+                               (g_log_chan[chan_no].desc_len - 1)) {
+                               g_log_chan[chan_no].current_desc = 0;
+                       } else {
+                               g_log_chan[chan_no].current_desc++;
+                       }
+                       break;
+               }
+               mdelay(1);
+       }
+       mb();
+#if 0
+       AMAZON_DMA_REG32(AMAZON_DMA_CH_ON) &= ~(1 << ch_on_mapping[chan_no]);
+       while (AMAZON_DMA_REG32(AMAZON_DMA_CH_ON) &
+                  (1 << ch_on_mapping[chan_no])) {
+               printk("TPE channel still on\n");
+               mdelay(1);
+       }
+
+       // AMAZON_DMA_REG32(AMAZON_DMA_CH_RST) = (1<<chan_no);
+       mb();
+       AMAZON_DMA_REG32(AMAZON_DMA_CH0_MSK + chan_no * AMAZON_DMA_CH_STEP) =
+               0x32;
+       mb();
+       rx_chan_clear_isr(chan_no);
+       dma_reset_all_descriptors(chan_no);
+       mb();
+       AMAZON_DMA_REG32(AMAZON_DMA_CH_ON) |= (1 << ch_on_mapping[chan_no]);
+       // g_log_chan[chan_no].current_desc=0;
+       mb();
+       mdelay(1);
+#endif
+       if (tpe_start) {
+               (*tpe_start) ();
+       } else {
+               AMAZON_DMA_EMSG("cannot restart TPE engien\n");
+       }
+}
+#endif                                                 // AMAZON_DMA_TPE_AAL5_RECOVERY
+
+
+/* Brief:      RX channel interrupt handler 
+ * Parameter:  RX channel no
+ * Description: the interrupt handler for each RX channel
+ *             1. check descriptor, clear ISR if no incoming packet
+ *             2. inform upper layer to receive packet (and update descriptors)
+ */
+inline void rx_chan_intr_handler(int chan_no)
+{
+       volatile struct rx_desc *rx_desc_p = NULL;
+
+       /* fetch the current descriptor */
+       rx_desc_p =
+               (struct rx_desc *) g_desc_list +
+               g_log_chan[chan_no].offset_from_base +
+               g_log_chan[chan_no].current_desc;
+
+       g_log_chan[chan_no].dma_dev->current_rx_chan =
+               chan_no - g_log_chan[chan_no].dma_dev->logic_rx_chan_base;
+
+       // workaround for DMA pitfall: complete bit set happends before the
+       // other two bits (own,eop) are ready
+       if ((rx_desc_p->status.field.EoP != 1)
+               || (rx_desc_p->status.field.OWN != CPU_OWN)
+               || (rx_desc_p->status.field.data_length ==
+                       g_log_chan[chan_no].packet_size)) {
+#ifdef AMAZON_DMA_TPE_AAL5_RECOVERY
+               if (chan_no == 4 || chan_no == 5) {
+                       dma_sync_fails++;
+                       if (dma_sync_fails > MAX_SYNC_FAILS) {
+                               // detect bug
+                               rx_desc_p0 =
+                                       (struct rx_desc *) g_desc_list +
+                                       g_log_chan[chan_no].offset_from_base;
+                               rx_desc_p1 =
+                                       (struct rx_desc *) g_desc_list +
+                                       g_log_chan[chan_no].offset_from_base + 1;
+                               if ((rx_desc_p0->status.field.OWN == CPU_OWN
+                                        && rx_desc_p0->status.field.EoP != 1)
+                                       && (rx_desc_p1->status.field.OWN == CPU_OWN
+                                               && rx_desc_p1->status.field.EoP != 1)) {
+                                       amazon_dma_reset_tpe_rx(chan_no);
+                                       dma_sync_fails = 0;
+                                       return;
+                               }
+                               dma_sync_fails = 0;
+                               AMAZON_DMA_DMSG("too many times ch:%d\n", chan_no);     // 000004:fchang
+                               return;
+                       }
+                       udelay(10);                     // 000004:fchang
+               }
+#endif                                                 // //AMAZON_DMA_TPE_AAL5_RECOVERY
+               return;
+       }
+
+       /* inform the upper layer to receive the packet */
+       g_log_chan[chan_no].intr_handler(g_log_chan[chan_no].dma_dev, RCV_INT);
+       /* check the next descriptor, if still contains the incoming packet,
+          then do not clear the interrupt status */
+       rx_desc_p =
+               (struct rx_desc *) g_desc_list +
+               g_log_chan[chan_no].offset_from_base +
+               g_log_chan[chan_no].current_desc;
+       if (!
+               ((rx_desc_p->status.field.OWN == CPU_OWN)
+                && (rx_desc_p->status.field.C == 1))) {
+               rx_chan_clear_isr(chan_no);
+       }
+}
+
+
+/* Brief:      TX channel interrupt handler 
+ * Parameter:  TX channel no
+ * Description: the interrupt handler for each TX channel
+ * 1. check all the descripters,if any of them had transmitted a packet, then free buffer
+ * because we cannot garantee the which one has already transmitted out, we have to go through all the descriptors here
+ * 2. clear the interrupt status bit
+ */
+inline void tx_chan_intr_handler(int chan_no)
+{
+       struct tx_desc *tx_desc_p = NULL;
+       int i = 0;
+
+       tx_desc_p =
+               (struct tx_desc *) g_desc_list +
+               g_log_chan[chan_no].offset_from_base;
+
+       for (i = 0; i < g_log_chan[chan_no].desc_len; i++) {
+               if ((tx_desc_p->status.field.OWN == CPU_OWN)
+                       && (tx_desc_p->status.field.C == 1)) {
+                       /* if already transmitted, then free the buffer */
+                       g_log_chan[chan_no].
+                               buffer_free((u8 *) __va(tx_desc_p->Data_Pointer),
+                                                       g_log_chan[chan_no].opt[i]);
+                       tx_desc_p->status.field.C = 0;
+                       /* inform the upper layer about the completion of the
+                          transmitted packet, the upper layer may want to free the
+                          packet */
+                       g_log_chan[chan_no].intr_handler(g_log_chan[chan_no].dma_dev,
+                                                                                        TRANSMIT_CPT_INT);
+               }
+               tx_desc_p++;
+       }
+
+       /* after all these operations, clear the interrupt status bit */
+       AMAZON_DMA_REG32(AMAZON_DMA_CH0_ISR + chan_no * AMAZON_DMA_CH_STEP) =
+               (AMAZON_DMA_REG32
+                (AMAZON_DMA_CH0_ISR +
+                 chan_no *
+                 AMAZON_DMA_CH_STEP) & (DMA_ISR_CPT | DMA_ISR_EOP |
+                                                                DMA_ISR_CMDCPT));
+}
+
+/*     Brief:  DMA interrupt handler
+ */
+static irqreturn_t dma_interrupt(int irq, void *dev_id)
+{
+       int i = 0;
+       int chan_no;
+       u32 isr = 0;
+#ifdef NO_TX_INT                               // 000004:fchang
+       static int cnt = 0;                     // 000004:fchang
+#endif                                                 // 000004:fchang
+       while ((isr =
+                       AMAZON_DMA_REG32(AMAZON_DMA_COMB_ISR)) & (COMB_ISR_RX_MASK |
+                                                                                                         COMB_ISR_TX_MASK)) {
+               if (isr & COMB_ISR_RX_MASK) {
+                       // RX Channels: start WFQ algorithm
+                       chan_no = CHAN_TOTAL_NUM;
+                       for (i = 0; i < RX_CHAN_NUM; i++) {
+                               if ((isr & (comb_isr_mask[i]))
+                                       && (g_log_chan[i].weight > 0)) {
+                                       if (g_log_chan[chan_no].weight < g_log_chan[i].weight) {
+                                               chan_no = i;
+                                       }
+                               }
+                       }
+                       if (chan_no < CHAN_TOTAL_NUM) {
+                               rx_chan_intr_handler(chan_no);
+                       } else {
+                               for (i = 0; i < RX_CHAN_NUM; i++) {
+                                       g_log_chan[i].weight = g_log_chan[i].default_weight;
+                               }
+                       }
+               }
+#ifdef NO_TX_INT
+               cnt++;
+               if (cnt == 10) {
+                       cnt = 0;
+                       for (i = 0; i < tx_chan_list_len; i++) {
+                               if (AMAZON_DMA_REG32
+                                       (AMAZON_DMA_CH0_ISR +
+                                        tx_chan_list[i] *
+                                        AMAZON_DMA_CH_STEP) & (DMA_ISR_CPT | DMA_ISR_EOP)) {
+                                       tx_chan_intr_handler(tx_chan_list[i]);
+                               }
+                       }
+               }
+#else
+               if (isr & COMB_ISR_TX_MASK) {
+                       // TX channels: RR
+                       for (i = 0; i < tx_chan_list_len; i++) {
+                               if (isr & (comb_isr_mask[tx_chan_list[i]])) {
+                                       tx_chan_intr_handler(tx_chan_list[i]);
+                               }
+                       }
+               }
+#endif
+       }                                                       // while 
+       return IRQ_HANDLED;
+}
+
+
+/*     Brief:  read a packet from DMA RX channel
+ *     Parameter:
+ *     Return: packet length
+ *     Description:
+ *             This is called back in a context of DMA interrupt
+ *             1. prepare new descriptor
+ *             2. read data
+ *             3. update WFQ weight
+ */
+//507261:tc.chen int dma_device_read(struct dma_device_info* dma_dev, u8** dataptr, void** opt)
+int asmlinkage dma_device_read(struct dma_device_info *dma_dev,
+                                                          u8 ** dataptr, void **opt)
+{
+       u8 *buf;
+       int len;
+       int chan_no = 0;
+       int byte_offset = 0;
+
+       struct rx_desc *rx_desc_p;
+       void *p = NULL;
+       int current_desc;
+
+       chan_no = dma_dev->logic_rx_chan_base + dma_dev->current_rx_chan;
+       current_desc = g_log_chan[chan_no].current_desc;
+       rx_desc_p =
+               (struct rx_desc *) (g_desc_list +
+                                                       g_log_chan[chan_no].offset_from_base +
+                                                       current_desc);
+       buf = (u8 *) __va(rx_desc_p->Data_Pointer);     /* extract the virtual
+                                                                                                  address of the data
+                                                                                                  pointer */
+       len = rx_desc_p->status.field.data_length;      /* extract the data length */
+#ifndef        CONFIG_MIPS_UNCACHED
+       dma_cache_inv((unsigned long) buf, len);
+#endif                                                 // CONFIG_MIPS_UNCACHED
+       *(u32 *) dataptr = (u32) buf;
+       if (opt) {
+               *(int *) opt = (int) g_log_chan[chan_no].opt[current_desc];     /* read 
+                                                                                                                                          out 
+                                                                                                                                          the 
+                                                                                                                                          opt 
+                                                                                                                                          information */
+       }
+
+       buf =
+               (u8 *) g_log_chan[chan_no].buffer_alloc(g_log_chan[chan_no].
+                                                                                               packet_size, &byte_offset,
+                                                                                               &p);
+       // should check null!!!!
+       if (buf == NULL || p == NULL) {
+               *(u32 *) dataptr = 0;
+               *(int *) opt = 0;
+               len = 0;
+       } else {
+               g_log_chan[chan_no].opt[current_desc] = p;
+               /* reduce the weight for WFQ algorithm */
+               g_log_chan[chan_no].weight -= len;
+               rx_desc_p->Data_Pointer = (u32) CPHYSADDR((u32) buf);
+       }
+       if (current_desc == g_log_chan[chan_no].desc_len - 1) {
+               current_desc = 0;
+       } else {
+               current_desc++;
+       }
+       g_log_chan[chan_no].current_desc = current_desc;
+
+       rx_desc_p->status.word = DMA_DESC_OWN_DMA
+               | (byte_offset << DMA_DESC_BYTEOFF_SHIFT)
+               | g_log_chan[chan_no].packet_size;
+       return len;
+}
+
+/*     Brief:  write a packet through DMA RX channel to peripheral
+ *     Parameter:
+ *     Return: packet length
+ *     Description:
+ *
+ */
+u64 dma_tx_drop = 0;
+//507261:tc.chen int dma_device_write(struct dma_device_info* dma_dev, u8* dataptr, int len,void* opt)
+int asmlinkage dma_device_write(struct dma_device_info *dma_dev,
+                                                               u8 * dataptr, int len, void *opt)
+{
+       int chan_no = 0;
+       struct tx_desc *tx_desc_p;
+
+       int byte_offset = 0;
+       int current_desc;
+       static int cnt = 0;                     // 000004:fchang
+
+       unsigned long flag;
+       local_irq_save(flag);
+
+       chan_no = dma_dev->logic_tx_chan_base + dma_dev->current_tx_chan;
+       current_desc = g_log_chan[chan_no].current_desc;
+       tx_desc_p =
+               (struct tx_desc *) (g_desc_list +
+                                                       g_log_chan[chan_no].offset_from_base +
+                                                       current_desc);
+       // 000003:tc.chen if(tx_desc_p->status.field.OWN==DMA_OWN){
+       if (tx_desc_p->status.field.OWN == DMA_OWN || tx_desc_p->status.field.C == 1) { // 000003:tc.chen
+               AMAZON_DMA_DMSG("no TX desc for CPU, drop packet\n");
+               dma_tx_drop++;
+               g_log_chan[chan_no].intr_handler(dma_dev, TX_BUF_FULL_INT);
+               local_irq_restore(flag);
+               return 0;
+       }
+       g_log_chan[chan_no].opt[current_desc] = opt;
+
+       /* byte offset----to adjust the starting address of the data buffer,
+          should be multiple of the burst length. */
+       byte_offset =
+               ((u32) CPHYSADDR((u32) dataptr)) % (g_log_chan[chan_no].burst_len *
+                                                                                       4);
+#ifndef        CONFIG_MIPS_UNCACHED
+       dma_cache_wback((unsigned long) dataptr, len);
+       wmb();
+#endif                                                 // CONFIG_MIPS_UNCACHED
+
+       tx_desc_p->Data_Pointer = (u32) CPHYSADDR((u32) dataptr) - byte_offset;
+       wmb();
+       tx_desc_p->status.word = DMA_DESC_OWN_DMA
+               | DMA_DESC_SOP_SET
+               | DMA_DESC_EOP_SET | (byte_offset << DMA_DESC_BYTEOFF_SHIFT)
+               | len;
+       wmb();
+       if (is_channel_open(chan_no) == 0) {
+               // turn on if necessary
+               open_channel(chan_no);
+       }
+#ifdef DMA_NO_POLLING
+       if ((AMAZON_DMA_REG32
+                (AMAZON_DMA_CH0_ISR +
+                 chan_no * AMAZON_DMA_CH_STEP) & (DMA_ISR_DURR | DMA_ISR_CPT)) ==
+               (DMA_ISR_DURR)) {
+               // clear DURR if (CPT is AND set and DURR is set)
+               AMAZON_DMA_REG32(AMAZON_DMA_CH0_ISR +
+                                                chan_no * AMAZON_DMA_CH_STEP) = DMA_ISR_DURR;
+       }
+#endif
+
+       if (current_desc == (g_log_chan[chan_no].desc_len - 1)) {
+               current_desc = 0;
+       } else {
+               current_desc++;
+       }
+
+
+       g_log_chan[chan_no].current_desc = current_desc;
+       tx_desc_p =
+               (struct tx_desc *) (g_desc_list +
+                                                       g_log_chan[chan_no].offset_from_base +
+                                                       current_desc);
+       // 000003:tc.chen if(tx_desc_p->status.field.OWN==DMA_OWN){
+       if (tx_desc_p->status.field.OWN == DMA_OWN || tx_desc_p->status.field.C == 1) { // 000003:tc.chen
+               g_log_chan[chan_no].intr_handler(dma_dev, TX_BUF_FULL_INT);
+       }
+#ifdef NO_TX_INT
+//000004:fchang Start
+       cnt++;
+       if (cnt == 5) {
+               cnt = 0;
+               tx_chan_intr_handler(chan_no);
+       }
+//000004:fchang End
+#endif
+       local_irq_restore(flag);        // 000004:fchang
+       return len;
+}
+
+
+
+int desc_list_proc_read(char *buf, char **start, off_t offset,
+                                               int count, int *eof, void *data)
+{
+       int i;
+       u32 *p = (u32 *) g_desc_list;
+       int len = 0;
+       len += sprintf(buf + len, "descriptor list:\n");
+       for (i = 0; i < 120; i++) {
+               len += sprintf(buf + len, "%d\n", i);
+               len += sprintf(buf + len, "%08x\n", *(p + i * 2 + 1));
+               len += sprintf(buf + len, "%08x\n", *(p + i * 2));
+
+       }
+
+       return len;
+
+}
+
+int channel_weight_proc_read(char *buf, char **start, off_t offset,
+                                                        int count, int *eof, void *data)
+{
+
+       // int i=0;
+       int len = 0;
+       len += sprintf(buf + len, "Qos dma channel weight list\n");
+       len +=
+               sprintf(buf + len,
+                               "channel_num default_weight current_weight device Tx/Rx\n");
+       len +=
+               sprintf(buf + len,
+                               "     0      %08x        %08x      Switch   Rx0\n",
+                               g_log_chan[0].default_weight, g_log_chan[0].weight);
+       len +=
+               sprintf(buf + len,
+                               "     1      %08x        %08x      Switch   Rx1\n",
+                               g_log_chan[1].default_weight, g_log_chan[1].weight);
+       len +=
+               sprintf(buf + len,
+                               "     2      %08x        %08x      Switch   Rx2\n",
+                               g_log_chan[2].default_weight, g_log_chan[2].weight);
+       len +=
+               sprintf(buf + len,
+                               "     3      %08x        %08x      Switch   Rx3\n",
+                               g_log_chan[3].default_weight, g_log_chan[3].weight);
+       len +=
+               sprintf(buf + len,
+                               "     4      %08x        %08x      Switch   Tx0\n",
+                               g_log_chan[4].default_weight, g_log_chan[4].weight);
+       len +=
+               sprintf(buf + len,
+                               "     5      %08x        %08x      Switch   Tx1\n",
+                               g_log_chan[5].default_weight, g_log_chan[5].weight);
+       /* 
+          len+=sprintf(buf+len," 6 %08x %08x TPE
+          Rx0\n",g_log_chan[6].default_weight, g_log_chan[6].weight);
+          len+=sprintf(buf+len," 7 %08x %08x TPE
+          Rx0\n",g_log_chan[7].default_weight, g_log_chan[7].weight);
+          len+=sprintf(buf+len," 8 %08x %08x TPE
+          Tx0\n",g_log_chan[8].default_weight, g_log_chan[8].weight);
+          len+=sprintf(buf+len," 9 %08x %08x TPE
+          Rx0\n",g_log_chan[9].default_weight, g_log_chan[9].weight);
+          len+=sprintf(buf+len," 10 %08x %08x DPLUS
+          Rx0\n",g_log_chan[10].default_weight, g_log_chan[10].weight);
+          len+=sprintf(buf+len," 11 %08x %08x DPLUS
+          Rx0\n",g_log_chan[11].default_weight, g_log_chan[11].weight); */
+       return len;
+}
+
+int dma_register_proc_read(char *buf, char **start, off_t offset,
+                                                  int count, int *eof, void *data)
+{
+       dev_list *temp_dev;
+       int len = 0;;
+
+       len += sprintf(buf + len, "amazon dma driver\n");
+       len += sprintf(buf + len, "version 1.0\n");
+       len += sprintf(buf + len, "devices registered:\n");
+       for (temp_dev = g_head_dev; temp_dev; temp_dev = temp_dev->next) {
+               len += sprintf(buf + len, "%s ", temp_dev->dev->device_name);
+       }
+       len += sprintf(buf + len, "\n");
+       len += sprintf(buf + len, "CH_ON=%08x\n", AMAZON_DMA_REG32(AMAZON_DMA_CH_ON));
+       len += sprintf(buf + len, "CH_RST=%08x\n", AMAZON_DMA_REG32(AMAZON_DMA_CH_RST));
+       len += sprintf(buf + len, "CH0_ISR=%08x\n",     AMAZON_DMA_REG32(AMAZON_DMA_CH0_ISR));
+       len += sprintf(buf + len, "CH1_ISR=%08x\n",     AMAZON_DMA_REG32(AMAZON_DMA_CH1_ISR));
+       len += sprintf(buf + len, "CH2_ISR=%08x\n",     AMAZON_DMA_REG32(AMAZON_DMA_CH2_ISR));
+       len += sprintf(buf + len, "CH3_ISR=%08x\n",     AMAZON_DMA_REG32(AMAZON_DMA_CH3_ISR));
+       len += sprintf(buf + len, "CH4_ISR=%08x\n",     AMAZON_DMA_REG32(AMAZON_DMA_CH4_ISR));
+       len += sprintf(buf + len, "CH5_ISR=%08x\n",     AMAZON_DMA_REG32(AMAZON_DMA_CH5_ISR));
+       len += sprintf(buf + len, "CH6_ISR=%08x\n",     AMAZON_DMA_REG32(AMAZON_DMA_CH6_ISR));
+       len += sprintf(buf + len, "CH7_ISR=%08x\n", AMAZON_DMA_REG32(AMAZON_DMA_CH7_ISR));
+       len +=          sprintf(buf + len, "CH8_ISR=%08x\n",
+                               AMAZON_DMA_REG32(AMAZON_DMA_CH8_ISR));
+       len +=
+               sprintf(buf + len, "CH9_ISR=%08x\n",
+                               AMAZON_DMA_REG32(AMAZON_DMA_CH9_ISR));
+       len +=
+               sprintf(buf + len, "CH10_ISR=%08x\n",
+                               AMAZON_DMA_REG32(AMAZON_DMA_CH10_ISR));
+       len +=
+               sprintf(buf + len, "CH11_ISR=%08x\n",
+                               AMAZON_DMA_REG32(AMAZON_DMA_CH11_ISR));
+       len +=
+               sprintf(buf + len, "LCH0_MSK=%08x\n",
+                               AMAZON_DMA_REG32(AMAZON_DMA_CH0_MSK));
+       len +=
+               sprintf(buf + len, "LCH1_MSK=%08x\n",
+                               AMAZON_DMA_REG32(AMAZON_DMA_CH1_MSK));
+       len +=
+               sprintf(buf + len, "LCH2_MSK=%08x\n",
+                               AMAZON_DMA_REG32(AMAZON_DMA_CH2_MSK));
+       len +=
+               sprintf(buf + len, "LCH3_MSK=%08x\n",
+                               AMAZON_DMA_REG32(AMAZON_DMA_CH3_MSK));
+       len +=
+               sprintf(buf + len, "LCH4_MSK=%08x\n",
+                               AMAZON_DMA_REG32(AMAZON_DMA_CH4_MSK));
+       len +=
+               sprintf(buf + len, "LCH5_MSK=%08x\n",
+                               AMAZON_DMA_REG32(AMAZON_DMA_CH5_MSK));
+       len +=
+               sprintf(buf + len, "LCH6_MSK=%08x\n",
+                               AMAZON_DMA_REG32(AMAZON_DMA_CH6_MSK));
+       len +=
+               sprintf(buf + len, "LCH7_MSK=%08x\n",
+                               AMAZON_DMA_REG32(AMAZON_DMA_CH7_MSK));
+       len +=
+               sprintf(buf + len, "LCH8_MSK=%08x\n",
+                               AMAZON_DMA_REG32(AMAZON_DMA_CH8_MSK));
+       len +=
+               sprintf(buf + len, "LCH9_MSK=%08x\n",
+                               AMAZON_DMA_REG32(AMAZON_DMA_CH9_MSK));
+       len +=
+               sprintf(buf + len, "LCH10_MSK=%08x\n",
+                               AMAZON_DMA_REG32(AMAZON_DMA_CH10_MSK));
+       len +=
+               sprintf(buf + len, "LCH11_MSK=%08x\n",
+                               AMAZON_DMA_REG32(AMAZON_DMA_CH11_MSK));
+       len +=
+               sprintf(buf + len, "Desc_BA=%08x\n",
+                               AMAZON_DMA_REG32(AMAZON_DMA_Desc_BA));
+       len +=
+               sprintf(buf + len, "LCH0_DES_LEN=%08x\n",
+                               AMAZON_DMA_REG32(AMAZON_DMA_CH0_DES_LEN));
+       len +=
+               sprintf(buf + len, "LCH1_DES_LEN=%08x\n",
+                               AMAZON_DMA_REG32(AMAZON_DMA_CH1_DES_LEN));
+       len +=
+               sprintf(buf + len, "LCH2_DES_LEN=%08x\n",
+                               AMAZON_DMA_REG32(AMAZON_DMA_CH2_DES_LEN));
+       len +=
+               sprintf(buf + len, "LCH3_DES_LEN=%08x\n",
+                               AMAZON_DMA_REG32(AMAZON_DMA_CH3_DES_LEN));
+       len +=
+               sprintf(buf + len, "LCH4_DES_LEN=%08x\n",
+                               AMAZON_DMA_REG32(AMAZON_DMA_CH4_DES_LEN));
+       len +=
+               sprintf(buf + len, "LCH5_DES_LEN=%08x\n",
+                               AMAZON_DMA_REG32(AMAZON_DMA_CH5_DES_LEN));
+       len +=
+               sprintf(buf + len, "LCH6_DES_LEN=%08x\n",
+                               AMAZON_DMA_REG32(AMAZON_DMA_CH6_DES_LEN));
+       len +=
+               sprintf(buf + len, "LCH7_DES_LEN=%08x\n",
+                               AMAZON_DMA_REG32(AMAZON_DMA_CH7_DES_LEN));
+       len +=
+               sprintf(buf + len, "LCH8_DES_LEN=%08x\n",
+                               AMAZON_DMA_REG32(AMAZON_DMA_CH8_DES_LEN));
+       len +=
+               sprintf(buf + len, "LCH9_DES_LEN=%08x\n",
+                               AMAZON_DMA_REG32(AMAZON_DMA_CH9_DES_LEN));
+       len +=
+               sprintf(buf + len, "LCH10_DES_LEN=%08x\n",
+                               AMAZON_DMA_REG32(AMAZON_DMA_CH10_DES_LEN));
+       len +=
+               sprintf(buf + len, "LCH11_DES_LEN=%08x\n",
+                               AMAZON_DMA_REG32(AMAZON_DMA_CH11_DES_LEN));
+       len +=
+               sprintf(buf + len, "LCH1_DES_OFST=%08x\n",
+                               AMAZON_DMA_REG32(AMAZON_DMA_CH1_DES_OFST));
+       len +=
+               sprintf(buf + len, "LCH2_DES_OFST=%08x\n",
+                               AMAZON_DMA_REG32(AMAZON_DMA_CH2_DES_OFST));
+       len +=
+               sprintf(buf + len, "LCH3_DES_OFST=%08x\n",
+                               AMAZON_DMA_REG32(AMAZON_DMA_CH3_DES_OFST));
+       len +=
+               sprintf(buf + len, "LCH4_DES_OFST=%08x\n",
+                               AMAZON_DMA_REG32(AMAZON_DMA_CH4_DES_OFST));
+       len +=
+               sprintf(buf + len, "LCH5_DES_OFST=%08x\n",
+                               AMAZON_DMA_REG32(AMAZON_DMA_CH5_DES_OFST));
+       len +=
+               sprintf(buf + len, "LCH6_DES_OFST=%08x\n",
+                               AMAZON_DMA_REG32(AMAZON_DMA_CH6_DES_OFST));
+       len +=
+               sprintf(buf + len, "LCH7_DES_OFST=%08x\n",
+                               AMAZON_DMA_REG32(AMAZON_DMA_CH7_DES_OFST));
+       len +=
+               sprintf(buf + len, "LCH8_DES_OFST=%08x\n",
+                               AMAZON_DMA_REG32(AMAZON_DMA_CH8_DES_OFST));
+       len +=
+               sprintf(buf + len, "LCH9_DES_OFST=%08x\n",
+                               AMAZON_DMA_REG32(AMAZON_DMA_CH9_DES_OFST));
+       len +=
+               sprintf(buf + len, "LCH10_DES_OFST=%08x\n",
+                               AMAZON_DMA_REG32(AMAZON_DMA_CH10_DES_OFST));
+       len +=
+               sprintf(buf + len, "LCH11_DES_OFST=%08x\n",
+                               AMAZON_DMA_REG32(AMAZON_DMA_CH11_DES_OFST));
+       len +=
+               sprintf(buf + len, "AMAZON_DMA_SW_BL=%08x\n",
+                               AMAZON_DMA_REG32(AMAZON_DMA_SW_BL));
+       len +=
+               sprintf(buf + len, "AMAZON_DMA_TPE_BL=%08x\n",
+                               AMAZON_DMA_REG32(AMAZON_DMA_TPE_BL));
+       len +=
+               sprintf(buf + len, "DPlus2FPI_BL=%08x\n",
+                               AMAZON_DMA_REG32(AMAZON_DMA_DPlus2FPI_BL));
+       len +=
+               sprintf(buf + len, "GRX_BUF_LEN=%08x\n",
+                               AMAZON_DMA_REG32(AMAZON_DMA_GRX_BUF_LEN));
+       len +=
+               sprintf(buf + len, "DMA_ECON_REG=%08x\n",
+                               AMAZON_DMA_REG32(AMAZON_DMA_DMA_ECON_REG));
+       len +=
+               sprintf(buf + len, "POLLING_REG=%08x\n",
+                               AMAZON_DMA_REG32(AMAZON_DMA_POLLING_REG));
+       len +=
+               sprintf(buf + len, "CH_WGT=%08x\n",
+                               AMAZON_DMA_REG32(AMAZON_DMA_CH_WGT));
+       len +=
+               sprintf(buf + len, "TX_WGT=%08x\n",
+                               AMAZON_DMA_REG32(AMAZON_DMA_TX_WGT));
+       len +=
+               sprintf(buf + len, "DPlus2FPI_CLASS=%08x\n",
+                               AMAZON_DMA_REG32(AMAZON_DMA_DPLus2FPI_CLASS));
+       len +=
+               sprintf(buf + len, "COMB_ISR=%08x\n",
+                               AMAZON_DMA_REG32(AMAZON_DMA_COMB_ISR));
+#ifdef AMAZON_DMA_TPE_AAL5_RECOVERY
+       len += sprintf(buf + len, "TPE fails:%u\n", total_dma_tpe_reset);       // 000004:fchang
+#endif
+       return len;
+}
+
+/*     Brief:  initialize DMA registers
+ *     Description:
+ */
+static void dma_chip_init(void)
+{
+       int i;
+       for (i = 0; i < CHAN_TOTAL_NUM; i++) {
+               AMAZON_DMA_REG32(AMAZON_DMA_CH1_DES_OFST +
+                                                i * AMAZON_DMA_CH_STEP) = DEFAULT_OFFSET;
+       }
+#ifdef DMA_NO_POLLING
+       AMAZON_DMA_REG32(AMAZON_DMA_POLLING_REG) = 0;
+#else
+       // enable poll mode and set polling counter
+       AMAZON_DMA_REG32(AMAZON_DMA_POLLING_REG) = DMA_POLLING_CNT | DMA_POLLING_ENABLE;
+#endif
+       // to enable DMA drop
+       AMAZON_DMA_REG32(AMAZON_DMA_GRX_BUF_LEN) = 0x10000;
+}
+
+int insert_dev_list(dev_list * dev)
+{
+       dev_list *temp_dev;
+       if (g_head_dev == NULL) {
+               g_head_dev = dev;
+               g_tail_dev = dev;
+               dev->prev = NULL;
+               dev->next = NULL;
+       } else {
+               for (temp_dev = g_head_dev; temp_dev; temp_dev = temp_dev->next) {
+                       if (temp_dev->weight < dev->weight) {
+                               if (temp_dev->prev)
+                                       temp_dev->prev->next = dev;
+
+                               dev->prev = temp_dev->prev;
+                               dev->next = temp_dev;
+                               temp_dev->prev = dev;
+                               if (temp_dev == g_head_dev)
+                                       g_head_dev = dev;
+                               break;
+                       }
+               }
+
+               if (!temp_dev) {
+                       g_tail_dev->next = dev;
+                       dev->prev = g_tail_dev;
+                       dev->next = NULL;
+                       g_tail_dev = dev;
+               }
+
+       }
+
+       return 1;
+}
+
+u8 *common_buffer_alloc(int len, int *byte_offset, void **opt)
+{
+       u8 *buffer = (u8 *) kmalloc(len * sizeof(u8), GFP_KERNEL);
+       *byte_offset = 0;
+       return buffer;
+
+}
+
+int common_buffer_free(u8 * dataptr, void *opt)
+{
+       if (dataptr)
+               kfree(dataptr);
+       return 0;
+}
+
+
+int register_dev(struct dma_device_info *dma_dev)
+{
+       int i, j, temp;
+       int burst_reg = 0;
+       u8 *buffer;
+       void *p = NULL;
+       int byte_offset = 0;
+
+       struct rx_desc *rx_desc_p;
+       struct tx_desc *tx_desc_p;
+       if (strcmp(dma_dev->device_name, "switch1") == 0) {
+               AMAZON_DMA_REG32(AMAZON_DMA_CH_RST) = SWITCH1_RST_MASK; // resest
+                                                                                                                               // channel 
+                                                                                                                               // 1st 
+               AMAZON_DMA_REG32(AMAZON_DMA_DMA_ECON_REG) |= 0x3;       // endian
+                                                                                                                       // conversion
+                                                                                                                       // for Switch
+               burst_reg = AMAZON_DMA_SW_BL;
+               dma_dev->logic_rx_chan_base = switch_rx_chan_base;
+               dma_dev->logic_tx_chan_base = switch_tx_chan_base;
+       }
+
+       else if (strcmp(dma_dev->device_name, "switch2") == 0) {
+               AMAZON_DMA_REG32(AMAZON_DMA_CH_RST) = SWITCH2_RST_MASK; // resest
+                                                                                                                               // channel 
+                                                                                                                               // 1st
+               AMAZON_DMA_REG32(AMAZON_DMA_DMA_ECON_REG) |= 0x3;       // endian
+                                                                                                                       // conversion
+                                                                                                                       // for Switch
+               burst_reg = AMAZON_DMA_SW_BL;
+               dma_dev->logic_rx_chan_base = switch2_rx_chan_base;
+               dma_dev->logic_tx_chan_base = switch2_tx_chan_base;
+
+       } else if (strcmp(dma_dev->device_name, "TPE") == 0) {
+               AMAZON_DMA_REG32(AMAZON_DMA_CH_RST) = TPE_RST_MASK;     // resest
+                                                                                                                       // channel 1st 
+                                                                                                                       // 
+               burst_reg = AMAZON_DMA_TPE_BL;
+               dma_dev->logic_rx_chan_base = TPE_rx_chan_base;
+               dma_dev->logic_tx_chan_base = TPE_tx_chan_base;
+       }
+
+       else if (strcmp(dma_dev->device_name, "DPlus") == 0) {
+               AMAZON_DMA_REG32(AMAZON_DMA_CH_RST) = DPlus2FPI_RST_MASK;       // resest 
+                                                                                                                                       // channel 
+                                                                                                                                       // 1st
+               dma_dev->logic_rx_chan_base = DPLus2FPI_rx_chan_base;
+               dma_dev->logic_tx_chan_base = DPLus2FPI_tx_chan_base;
+
+       }
+
+       i = 0;
+       for (temp = dma_dev->tx_burst_len; temp > 2; temp /= 2) {
+               i += 1;
+       }
+
+
+       AMAZON_DMA_REG32(burst_reg) = i << 1;
+       i = 0;
+       for (temp = dma_dev->rx_burst_len; temp > 2; temp /= 2) {
+               i += 1;
+       }
+       AMAZON_DMA_REG32(burst_reg) += i;
+
+       for (i = 0; i < dma_dev->num_rx_chan; i++) {
+
+               temp = dma_dev->logic_rx_chan_base + i;
+               g_log_chan[temp].dma_dev = dma_dev;
+               g_log_chan[temp].weight = dma_dev->rx_chan[i].weight;
+               g_log_chan[temp].default_weight = dma_dev->rx_chan[i].weight;
+               g_log_chan[temp].current_desc = 0;
+               g_log_chan[temp].desc_ofst = DEFAULT_OFFSET;
+               g_log_chan[temp].desc_len = dma_dev->rx_chan[i].desc_num;
+               g_log_chan[temp].offset_from_base = temp * DEFAULT_OFFSET;
+               g_log_chan[temp].packet_size = dma_dev->rx_chan[i].packet_size;
+
+               AMAZON_DMA_REG32(AMAZON_DMA_CH0_DES_LEN + temp * AMAZON_DMA_CH_STEP) = dma_dev->rx_chan[i].desc_num;
+               // enable interrupt mask
+               if (temp == 4 || temp == 5) {
+                       AMAZON_DMA_REG32(AMAZON_DMA_CH0_MSK + temp * AMAZON_DMA_CH_STEP) = 0x32;
+               } else {
+                       AMAZON_DMA_REG32(AMAZON_DMA_CH0_MSK + temp * AMAZON_DMA_CH_STEP) = 0x36;
+               }
+               strcpy(g_log_chan[temp].device_name, dma_dev->device_name);
+               g_log_chan[temp].burst_len = dma_dev->rx_burst_len;
+               g_log_chan[temp].control = dma_dev->rx_chan[i].control;
+
+
+               /* specify the buffer allocation and free method */
+               if (dma_dev->buffer_alloc)
+                       g_log_chan[temp].buffer_alloc = dma_dev->buffer_alloc;
+               else
+                       g_log_chan[temp].buffer_alloc = common_buffer_alloc;
+
+               if (dma_dev->buffer_free)
+                       g_log_chan[temp].buffer_free = dma_dev->buffer_free;
+               else
+                       g_log_chan[temp].buffer_free = common_buffer_free;
+
+               if (dma_dev->intr_handler)
+                       g_log_chan[temp].intr_handler = dma_dev->intr_handler;
+               else
+                       g_log_chan[temp].intr_handler = NULL;
+
+               for (j = 0; j < g_log_chan[temp].desc_len; j++) {
+                       rx_desc_p = (struct rx_desc *) (g_desc_list + g_log_chan[temp].offset_from_base + j);
+                       rx_desc_p->status.word = 0;
+                       rx_desc_p->status.field.data_length = g_log_chan[temp].packet_size;
+                       buffer = (u8 *) g_log_chan[temp].buffer_alloc(g_log_chan[temp].packet_size, &byte_offset, &p);
+                       rx_desc_p->Data_Pointer = (u32) CPHYSADDR((u32) buffer);
+                       rx_desc_p->status.field.byte_offset = byte_offset;
+                       /* fix me, should check if the addresss comply with the burst
+                          lenght requirment */
+                       g_log_chan[temp].opt[j] = p;
+                       rx_desc_p->status.field.OWN = DMA_OWN;
+
+               }
+               /* open or close the channel */
+               if (g_log_chan[temp].control)
+                       open_channel(temp);
+               else
+                       close_channel(temp);
+       }
+
+       for (i = 0; i < dma_dev->num_tx_chan; i++) {
+               temp = dma_dev->logic_tx_chan_base + i;
+               g_log_chan[temp].dma_dev = dma_dev;
+               g_log_chan[temp].weight = dma_dev->tx_chan[i].weight;
+               g_log_chan[temp].default_weight = dma_dev->tx_chan[i].weight;
+               g_log_chan[temp].current_desc = 0;
+               g_log_chan[temp].desc_ofst = DEFAULT_OFFSET;
+               g_log_chan[temp].desc_len = dma_dev->tx_chan[i].desc_num;
+               g_log_chan[temp].offset_from_base = temp * DEFAULT_OFFSET;
+               g_log_chan[temp].packet_size = dma_dev->tx_chan[i].packet_size;
+
+               AMAZON_DMA_REG32(AMAZON_DMA_CH0_DES_LEN + temp * AMAZON_DMA_CH_STEP) = dma_dev->tx_chan[i].desc_num;
+               // enable interrupt mask
+#ifdef NO_TX_INT
+               AMAZON_DMA_REG32(AMAZON_DMA_CH0_MSK + temp * AMAZON_DMA_CH_STEP) = 0x3e;
+#else
+               AMAZON_DMA_REG32(AMAZON_DMA_CH0_MSK + temp * AMAZON_DMA_CH_STEP) = 0x36;
+#endif
+
+               strcpy(g_log_chan[temp].device_name, dma_dev->device_name);
+               g_log_chan[temp].burst_len = dma_dev->tx_burst_len;
+               g_log_chan[temp].control = dma_dev->tx_chan[i].control;
+
+               if (dma_dev->buffer_alloc)
+                       g_log_chan[temp].buffer_alloc = dma_dev->buffer_alloc;
+               else
+                       g_log_chan[temp].buffer_alloc = common_buffer_alloc;
+
+               if (dma_dev->buffer_free)
+                       g_log_chan[temp].buffer_free = dma_dev->buffer_free;
+               else
+                       g_log_chan[temp].buffer_free = common_buffer_free;
+
+               if (dma_dev->intr_handler)
+                       g_log_chan[temp].intr_handler = dma_dev->intr_handler;
+               else
+                       g_log_chan[temp].intr_handler = NULL;
+
+               for (j = 0; j < g_log_chan[temp].desc_len; j++) {
+
+                       tx_desc_p =
+                               (struct tx_desc *) (g_desc_list +
+                                                                       g_log_chan[temp].offset_from_base + j);
+                       tx_desc_p->status.word = 0;
+                       tx_desc_p->status.field.data_length =
+                               g_log_chan[temp].packet_size;
+                       tx_desc_p->status.field.OWN = CPU_OWN;
+
+               }
+               /* workaround DMA pitfall, we never turn on channel if we don't
+                  have proper descriptors */
+               if (!g_log_chan[temp].control) {
+                       close_channel(temp);
+               }
+
+       }
+
+       return 0;
+}
+
+int dma_device_register(struct dma_device_info *dma_dev)
+{
+       dev_list *temp_dev;
+       temp_dev = (dev_list *) kmalloc(sizeof(dev_list), GFP_KERNEL);
+       temp_dev->dev = dma_dev;
+       temp_dev->weight = dma_dev->weight;
+       insert_dev_list(temp_dev);
+       /* check whether this is a known device */
+       if ((strcmp(dma_dev->device_name, "switch1") == 0)
+               || (strcmp(dma_dev->device_name, "TPE") == 0)
+               || (strcmp(dma_dev->device_name, "switch2") == 0)
+               || (strcmp(dma_dev->device_name, "DPlus") == 0)) {
+               register_dev(dma_dev);
+       }
+
+       return 0;
+}
+
+
+int unregister_dev(struct dma_device_info *dma_dev)
+{
+       int i, j, temp;
+       u8 *buffer;
+       struct rx_desc *rx_desc_p;
+
+       for (i = 0; i < dma_dev->num_rx_chan; i++) {
+               temp = dma_dev->logic_rx_chan_base + i;
+               close_channel(temp);
+               for (j = 0; j < g_log_chan[temp].desc_len; j++) {
+                       rx_desc_p =
+                               (struct rx_desc *) (g_desc_list +
+                                                                       g_log_chan[temp].offset_from_base + j);
+                       buffer = (u8 *) __va(rx_desc_p->Data_Pointer);
+                       g_log_chan[temp].buffer_free(buffer, g_log_chan[temp].opt[j]);
+               }
+       }
+       for (i = 0; i < dma_dev->num_tx_chan; i++) {
+               temp = dma_dev->logic_tx_chan_base + i;
+               close_channel(temp);
+       }
+       return 0;
+}
+
+int dma_device_unregister(struct dma_device_info *dev)
+{
+       dev_list *temp_dev;
+       for (temp_dev = g_head_dev; temp_dev; temp_dev = temp_dev->next) {
+               if (strcmp(dev->device_name, temp_dev->dev->device_name) == 0) {
+                       if ((strcmp(dev->device_name, "switch1") == 0)
+                               || (strcmp(dev->device_name, "TPE") == 0)
+                               || (strcmp(dev->device_name, "switch2") == 0)
+                               || (strcmp(dev->device_name, "DPlus") == 0))
+                               unregister_dev(dev);
+                       if (temp_dev == g_head_dev) {
+                               g_head_dev = temp_dev->next;
+                               kfree(temp_dev);
+                       } else {
+                               if (temp_dev == g_tail_dev)
+                                       g_tail_dev = temp_dev->prev;
+                               if (temp_dev->prev)
+                                       temp_dev->prev->next = temp_dev->next;
+                               if (temp_dev->next)
+                                       temp_dev->next->prev = temp_dev->prev;
+                               kfree(temp_dev);
+                       }
+                       break;
+               }
+
+       }
+       return 0;
+}
+
+void dma_device_update_rx(struct dma_device_info *dma_dev)
+{
+       int i, temp;
+       for (i = 0; i < dma_dev->num_rx_chan; i++) {
+               temp = dma_dev->logic_rx_chan_base + i;
+               g_log_chan[temp].control = dma_dev->rx_chan[i].control;
+
+               if (g_log_chan[temp].control)
+                       open_channel(temp);
+               else
+                       close_channel(temp);
+       }
+
+}
+
+void dma_device_update_tx(struct dma_device_info *dma_dev)
+{
+       int i, temp;
+       for (i = 0; i < dma_dev->num_tx_chan; i++) {
+               temp = dma_dev->logic_tx_chan_base + i;
+               g_log_chan[temp].control = dma_dev->tx_chan[i].control;
+               if (g_log_chan[temp].control) {
+                       /* we turn on channel when send out the very first packet */
+                       // open_channel(temp);
+               } else
+                       close_channel(temp);
+       }
+}
+
+int dma_device_update(struct dma_device_info *dma_dev)
+{
+       dma_device_update_rx(dma_dev);
+       dma_device_update_tx(dma_dev);
+       return 0;
+}
+
+static int dma_open(struct inode *inode, struct file *file)
+{
+       return 0;
+}
+
+static int dma_release(struct inode *inode, struct file *file)
+{
+       /* release the resources */
+       return 0;
+}
+
+static int dma_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+       int value = 0;
+       int result = 0;
+       int chan_no = 0;
+
+       switch (cmd) {
+       case 0:                                 /* get register value */
+               break;
+       case 1:                                 /* return channel weight */
+               chan_no = *((int *) arg);
+               *((int *) arg + 1) = g_log_chan[chan_no].default_weight;
+               break;
+       case 2:                                 /* set channel weight */
+               chan_no = *((int *) arg);
+               value = *((int *) arg + 1);
+               printk("new weight=%08x\n", value);
+               g_log_chan[chan_no].default_weight = value;
+               break;
+       default:
+               break;
+       }
+       return result;
+}
+
+
+static struct file_operations dma_fops = {
+  owner:THIS_MODULE,
+  open:dma_open,
+  release:dma_release,
+  ioctl:dma_ioctl,
+};
+
+static int dma_init(void)
+{
+       int result = 0;
+       int i;
+       printk("initialising dma core\n");
+       result = register_chrdev(DMA_MAJOR, "dma-core", &dma_fops);
+       if (result) {
+               AMAZON_DMA_EMSG("cannot register device dma-core!\n");
+               return result;
+       }
+       result = request_irq(AMAZON_DMA_INT, dma_interrupt, SA_INTERRUPT, "dma-core", (void *) &dma_interrupt);
+       if (result) {
+               AMAZON_DMA_EMSG("error, cannot get dma_irq!\n");
+               free_irq(AMAZON_DMA_INT, (void *) &dma_interrupt);
+               return -EFAULT;
+       }
+
+       g_desc_list = (u64 *) KSEG1ADDR(__get_free_page(GFP_DMA));
+
+       if (g_desc_list == NULL) {
+               AMAZON_DMA_EMSG("no memory for desriptor\n");
+               return -ENOMEM;
+       }
+       memset(g_desc_list, 0, PAGE_SIZE);
+       AMAZON_DMA_REG32(AMAZON_DMA_Desc_BA) = (u32) CPHYSADDR((u32) g_desc_list);
+       g_amazon_dma_dir = proc_mkdir("amazon_dma", NULL);
+       create_proc_read_entry("dma_register", 0, g_amazon_dma_dir, dma_register_proc_read, NULL);
+       create_proc_read_entry("g_desc_list", 0, g_amazon_dma_dir, desc_list_proc_read, NULL);
+       create_proc_read_entry("channel_weight", 0, g_amazon_dma_dir, channel_weight_proc_read, NULL);
+
+       dma_chip_init();
+       for (i = 0; i < (RX_CHAN_NUM + 1); i++) {
+               rx_chan_list[i] = -1;
+       }
+       for (i = 0; i < (TX_CHAN_NUM + 1); i++) {
+               tx_chan_list[i] = -1;
+       }
+
+       for (i = 0; i < CHAN_TOTAL_NUM; i++) {
+               comb_isr_mask[i] = 0x80000000 >> (i);
+       }
+
+       g_log_chan[CHAN_TOTAL_NUM].weight = 0;
+       printk("initialising dma core ... done\n");
+
+       return 0;
+}
+
+arch_initcall(dma_init);
+
+
+void dma_cleanup(void)
+{
+       dev_list *temp_dev;
+
+       unregister_chrdev(DMA_MAJOR, "dma-core");
+       for (temp_dev = g_head_dev; temp_dev; temp_dev = temp_dev->next) {
+               kfree(temp_dev);
+       }
+       free_page(KSEG0ADDR((unsigned long) g_desc_list));
+       remove_proc_entry("channel_weight", g_amazon_dma_dir);
+       remove_proc_entry("dma_list", g_amazon_dma_dir);
+       remove_proc_entry("dma_register", g_amazon_dma_dir);
+       remove_proc_entry("amazon_dma", NULL);
+       /* release the resources */
+       free_irq(AMAZON_DMA_INT, (void *) &dma_interrupt);
+}
+
+EXPORT_SYMBOL(dma_device_register);
+EXPORT_SYMBOL(dma_device_unregister);
+EXPORT_SYMBOL(dma_device_read);
+EXPORT_SYMBOL(dma_device_write);
+EXPORT_SYMBOL(dma_device_update);
+EXPORT_SYMBOL(dma_device_update_rx);
+
+MODULE_LICENSE("GPL");
diff --git a/target/linux/amazon-2.6/files/arch/mips/amazon/dma-core.h b/target/linux/amazon-2.6/files/arch/mips/amazon/dma-core.h
new file mode 100644 (file)
index 0000000..cb3d456
--- /dev/null
@@ -0,0 +1,69 @@
+#ifndef DMA_CORE_H 
+#define DMA_CORE_H 
+
+#define AMAZON_DMA_REG32(reg_num)  *((volatile u32*)(reg_num))
+#define AMAZON_DMA_CH_STEP            4
+
+#define COMB_ISR_RX_MASK 0xfe000000
+#define COMB_ISR_TX_MASK 0x01f00000
+
+
+#define DMA_OWN   1
+#define CPU_OWN   0   
+#define DMA_MAJOR 250
+
+//Descriptors
+#define DMA_DESC_OWN_CPU               0x0
+#define DMA_DESC_OWN_DMA               0x80000000
+#define DMA_DESC_CPT_SET               0x40000000
+#define DMA_DESC_SOP_SET               0x20000000
+#define DMA_DESC_EOP_SET               0x10000000
+
+#define switch_rx_chan_base 0
+#define switch_tx_chan_base 7
+#define switch2_rx_chan_base 2
+#define switch2_tx_chan_base 8
+#define TPE_rx_chan_base    4
+#define TPE_tx_chan_base    9
+#define DPLus2FPI_rx_chan_base  6
+#define DPLus2FPI_tx_chan_base  11 
+
+#define RX_CHAN_NUM 7
+#define TX_CHAN_NUM 5
+#define CHAN_TOTAL_NUM       (RX_CHAN_NUM+TX_CHAN_NUM)
+#define DEFAULT_OFFSET 20
+#define DESCRIPTOR_SIZE 8
+
+typedef struct dev_list{
+   struct dma_device_info* dev;
+   int weight;
+   struct dev_list* prev;
+   struct dev_list* next;
+}dev_list; 
+
+typedef struct channel_info{
+   char device_name[16];
+   int occupied;
+   enum attr_t attr;  
+   int current_desc;
+   int weight;
+   int default_weight;
+   int desc_num;
+   int burst_len;
+   int desc_len;
+   int desc_ofst;
+   int packet_size;
+   int offset_from_base;
+   int control;
+   void* opt[DEFAULT_OFFSET];
+   u8* (*buffer_alloc)(int len,int* offset, void** opt);
+   int (*buffer_free)(u8* dataptr,void* opt);
+   int (*intr_handler)(struct dma_device_info* info,int status);
+
+   struct dma_device_info* dma_dev;
+}channel_info;
+
+
+
+#endif
+
diff --git a/target/linux/amazon-2.6/files/arch/mips/amazon/interrupt.c b/target/linux/amazon-2.6/files/arch/mips/amazon/interrupt.c
new file mode 100644 (file)
index 0000000..6702ecf
--- /dev/null
@@ -0,0 +1,238 @@
+/*
+ *  Gary Jennejohn (C) 2003 <gj@denx.de>
+ *  Copyright (C) 2007 Felix Fietkau <nbd@openwrt.org>
+ *
+ *  This program is free software; you can distribute it and/or modify it
+ *  under the terms of the GNU General Public License (Version 2) as
+ *  published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope 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.
+ *
+ * Routines for generic manipulation of the interrupts found on the 
+ * AMAZON boards.
+ */
+
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/kernel_stat.h>
+#include <linux/module.h>
+
+#include <asm/amazon/amazon.h>
+#include <asm/amazon/irq.h>
+#include <asm/bootinfo.h>
+#include <asm/irq_cpu.h>
+#include <asm/irq.h>
+#include <asm/time.h>
+
+static void amazon_disable_irq(unsigned int irq_nr)
+{
+       /* have to access the correct register here */
+       if (irq_nr <= INT_NUM_IM0_IRL11 && irq_nr >= INT_NUM_IM0_IRL0)
+               /* access IM0 DMA channels */
+               *AMAZON_ICU_IM0_IER &= (~(AMAZON_DMA_H_MASK));
+       else if (irq_nr <= INT_NUM_IM0_IRL31 && irq_nr >= INT_NUM_IM0_IRL12)
+               /* access IM0 except DMA*/
+               *AMAZON_ICU_IM0_IER &= (~AMAZON_ICU_IM0_IER_IR(irq_nr));
+       else if (irq_nr <= INT_NUM_IM1_IRL31 && irq_nr >= INT_NUM_IM1_IRL0)
+               /* access IM1 */
+               *AMAZON_ICU_IM1_IER &= (~AMAZON_ICU_IM1_IER_IR(irq_nr - INT_NUM_IM1_IRL0));
+       else if (irq_nr <= INT_NUM_IM2_IRL31 && irq_nr >= INT_NUM_IM2_IRL0)
+               /* access IM2 */
+               *AMAZON_ICU_IM2_IER &= (~AMAZON_ICU_IM2_IER_IR(irq_nr - INT_NUM_IM2_IRL0));
+       else if (irq_nr <= INT_NUM_IM3_IRL31 && irq_nr >= INT_NUM_IM3_IRL0)
+               /* access IM3 */
+               *AMAZON_ICU_IM3_IER &= (~AMAZON_ICU_IM3_IER_IR((irq_nr - INT_NUM_IM3_IRL0)));
+       else if (irq_nr <= INT_NUM_IM4_IRL31 && irq_nr >= INT_NUM_IM4_IRL0)
+               /* access IM4 */
+               *AMAZON_ICU_IM4_IER &= (~AMAZON_ICU_IM4_IER_IR((irq_nr - INT_NUM_IM4_IRL0)));
+}
+
+static void amazon_mask_and_ack_irq(unsigned int irq_nr)
+{
+       /* have to access the correct register here */
+       if (irq_nr <= INT_NUM_IM0_IRL11 && irq_nr >= INT_NUM_IM0_IRL0) {
+               /* access IM0 DMA channels */
+               *AMAZON_ICU_IM0_IER &= (~(AMAZON_DMA_H_MASK)); /* mask */
+               *AMAZON_ICU_IM0_ISR = AMAZON_DMA_H_MASK; /* ack */
+       } else if (irq_nr <= INT_NUM_IM0_IRL31 && irq_nr >= INT_NUM_IM0_IRL12) {
+               /* access IM0 except DMA */
+               *AMAZON_ICU_IM0_IER &= ~AMAZON_ICU_IM0_IER_IR(irq_nr - INT_NUM_IM0_IRL0); /* mask */
+               *AMAZON_ICU_IM0_ISR = AMAZON_ICU_IM0_ISR_IR(irq_nr - INT_NUM_IM0_IRL0); /* ack */
+       } else if (irq_nr <= INT_NUM_IM1_IRL31 && irq_nr >= INT_NUM_IM1_IRL0) {
+               /* access IM1 */
+               *AMAZON_ICU_IM1_IER &= ~AMAZON_ICU_IM1_IER_IR(irq_nr - INT_NUM_IM1_IRL0); /* mask */
+               *AMAZON_ICU_IM1_ISR = AMAZON_ICU_IM1_ISR_IR(irq_nr - INT_NUM_IM1_IRL0); /* ack */
+       } else if (irq_nr <= INT_NUM_IM2_IRL31 && irq_nr >= INT_NUM_IM2_IRL0) {
+               /* access IM2 */
+               *AMAZON_ICU_IM2_IER &= ~AMAZON_ICU_IM2_IER_IR(irq_nr - INT_NUM_IM2_IRL0); /* mask */
+               *AMAZON_ICU_IM2_ISR = AMAZON_ICU_IM2_ISR_IR(irq_nr - INT_NUM_IM2_IRL0); /* ack */
+       } else if (irq_nr <= INT_NUM_IM3_IRL31 && irq_nr >= INT_NUM_IM3_IRL0) {
+               /* access IM3 */
+               *AMAZON_ICU_IM3_IER &= ~AMAZON_ICU_IM3_IER_IR(irq_nr - INT_NUM_IM3_IRL0); /* mask */
+               *AMAZON_ICU_IM3_ISR = AMAZON_ICU_IM3_ISR_IR(irq_nr - INT_NUM_IM3_IRL0); /* ack */
+       } else if (irq_nr <= INT_NUM_IM4_IRL31 && irq_nr >= INT_NUM_IM4_IRL0) {
+               *AMAZON_ICU_IM4_IER &= ~AMAZON_ICU_IM4_IER_IR(irq_nr - INT_NUM_IM4_IRL0); /* mask */
+               *AMAZON_ICU_IM4_ISR = AMAZON_ICU_IM4_ISR_IR(irq_nr - INT_NUM_IM4_IRL0); /* ack */
+       }
+}
+
+static void amazon_enable_irq(unsigned int irq_nr)
+{
+       /* have to access the correct register here */
+       if (irq_nr <= INT_NUM_IM0_IRL11 && irq_nr >= INT_NUM_IM0_IRL0)
+               /* access IM0 DMA*/
+               *AMAZON_ICU_IM0_IER |= AMAZON_DMA_H_MASK;
+       else if (irq_nr <= INT_NUM_IM0_IRL31 && irq_nr >= INT_NUM_IM0_IRL12)
+               /* access IM0 except DMA*/
+               *AMAZON_ICU_IM0_IER |= AMAZON_ICU_IM0_IER_IR(irq_nr - INT_NUM_IM0_IRL0);
+       else if (irq_nr <= INT_NUM_IM1_IRL31 && irq_nr >= INT_NUM_IM1_IRL0)
+               /* access IM1 */
+               *AMAZON_ICU_IM1_IER |= AMAZON_ICU_IM1_IER_IR(irq_nr - INT_NUM_IM1_IRL0);
+       else if (irq_nr <= INT_NUM_IM2_IRL31 && irq_nr >= INT_NUM_IM2_IRL0)
+               /* access IM2 */
+               *AMAZON_ICU_IM2_IER |= AMAZON_ICU_IM2_IER_IR(irq_nr - INT_NUM_IM2_IRL0);
+       else if (irq_nr <= INT_NUM_IM3_IRL31 && irq_nr >= INT_NUM_IM3_IRL0)
+               /* access IM3 */
+               *AMAZON_ICU_IM3_IER |= AMAZON_ICU_IM3_IER_IR((irq_nr - INT_NUM_IM3_IRL0));
+       else if (irq_nr <= INT_NUM_IM4_IRL31 && irq_nr >= INT_NUM_IM4_IRL0)
+               /* access IM4 */
+               *AMAZON_ICU_IM4_IER |= AMAZON_ICU_IM4_IER_IR((irq_nr - INT_NUM_IM4_IRL0));
+}
+
+static unsigned int amazon_startup_irq(unsigned int irq)
+{
+       amazon_enable_irq(irq);
+       return 0;
+}
+
+static void amazon_end_irq(unsigned int irq)
+{
+       if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) {
+               amazon_enable_irq(irq);
+       }
+}
+
+static struct hw_interrupt_type amazon_irq_type = {
+       "AMAZON",
+       .startup = amazon_startup_irq,
+       .enable = amazon_enable_irq,
+       .disable = amazon_disable_irq,
+       .unmask = amazon_enable_irq,
+       .ack = amazon_mask_and_ack_irq,
+       .mask = amazon_disable_irq,
+       .mask_ack = amazon_mask_and_ack_irq,
+       .end = amazon_end_irq
+};
+
+/* Cascaded interrupts from IM0 */
+static inline void amazon_hw0_irqdispatch(void)
+{
+       u32 irq;
+                                                                                                                                                                                                
+       irq = (*AMAZON_ICU_IM_VEC) & AMAZON_ICU_IM0_VEC_MASK;
+       if (irq <= 11 && irq >= 0) {
+               //DMA fixed to IM0_IRL0
+               irq = 0;
+       }
+       do_IRQ(irq + INT_NUM_IM0_IRL0);
+}
+                                                                                                         
+/* Cascaded interrupts from IM1 */
+static inline void amazon_hw1_irqdispatch(void)
+{
+       u32 irq;
+
+       irq = ((*AMAZON_ICU_IM_VEC) & AMAZON_ICU_IM1_VEC_MASK) >> 5;
+       do_IRQ(irq + INT_NUM_IM1_IRL0);
+}
+
+/* Cascaded interrupts from IM2 */
+static inline void amazon_hw2_irqdispatch(void)
+{
+       u32 irq;
+                                                                                                                                                                                                
+       irq = ((*AMAZON_ICU_IM_VEC) & AMAZON_ICU_IM2_VEC_MASK) >> 10;
+       do_IRQ(irq + INT_NUM_IM2_IRL0);
+}
+
+/* Cascaded interrupts from IM3 */
+static inline void amazon_hw3_irqdispatch(void)
+{
+       u32 irq;
+
+       irq = ((*AMAZON_ICU_IM_VEC) & AMAZON_ICU_IM3_VEC_MASK) >> 15;
+       do_IRQ(irq + INT_NUM_IM3_IRL0);
+}
+
+/* Cascaded interrupts from IM4 */
+static inline void amazon_hw4_irqdispatch(void)
+{
+       u32 irq;
+
+       irq = ((*AMAZON_ICU_IM_VEC) & AMAZON_ICU_IM4_VEC_MASK) >> 20;
+       do_IRQ(irq + INT_NUM_IM4_IRL0);
+}
+
+asmlinkage void plat_irq_dispatch(void)
+{
+       unsigned int pending = read_c0_status() & read_c0_cause() & ST0_IM;
+       if (pending & CAUSEF_IP7){
+               do_IRQ(MIPS_CPU_TIMER_IRQ);
+       }
+       else if (pending & CAUSEF_IP2)
+               amazon_hw0_irqdispatch();
+       else if (pending & CAUSEF_IP3)
+               amazon_hw1_irqdispatch();
+       else if (pending & CAUSEF_IP4)
+               amazon_hw2_irqdispatch();
+       else if (pending & CAUSEF_IP5)
+               amazon_hw3_irqdispatch();
+       else if (pending & CAUSEF_IP6)
+               amazon_hw4_irqdispatch();
+       else
+               printk("Spurious IRQ: CAUSE=0x%08x\n", read_c0_status());
+}
+
+static struct irqaction cascade = {
+       .handler        = no_action,
+       .flags          = SA_INTERRUPT,
+       .name           = "cascade",
+};
+
+
+/* Function for careful CP0 interrupt mask access */
+
+void __init arch_init_irq(void)
+{
+       int i;
+
+       /* mask all interrupt sources */
+       *AMAZON_ICU_IM0_IER = 0;
+       *AMAZON_ICU_IM1_IER = 0;
+       *AMAZON_ICU_IM2_IER = 0;
+       *AMAZON_ICU_IM3_IER = 0;
+       *AMAZON_ICU_IM4_IER = 0;
+
+       mips_cpu_irq_init();
+
+       /* set up irq cascade */
+       for (i = 2; i <= 6; i++) {
+               setup_irq(i, &cascade);
+       }
+
+       for (i = INT_NUM_IRQ0; i <= INT_NUM_IM4_IRL31; i++) {
+               irq_desc[i].status      = IRQ_DISABLED;
+               irq_desc[i].action      = 0;
+               irq_desc[i].depth       = 1;
+               set_irq_chip(i, &amazon_irq_type);
+       }
+}
diff --git a/target/linux/amazon-2.6/files/arch/mips/amazon/pci.c b/target/linux/amazon-2.6/files/arch/mips/amazon/pci.c
new file mode 100644 (file)
index 0000000..ab305a9
--- /dev/null
@@ -0,0 +1,293 @@
+/*
+ *  Carsten Langgaard, carstenl@mips.com
+ *  Copyright (C) 1999, 2000 MIPS Technologies, Inc.  All rights reserved.
+ *  Copyright (C) 2007 Felix Fietkau <nbd@openwrt.org>
+ *
+ *  This program is free software; you can distribute it and/or modify it
+ *  under the terms of the GNU General Public License (Version 2) as
+ *  published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope 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.
+ */
+
+/* FIXME: convert nasty volatile register derefs to readl/writel calls */
+
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <asm/io.h>
+#include <asm/paccess.h>
+#include <asm/amazon/irq.h>
+#include <asm/amazon/amazon.h>
+
+#define AMAZON_PCI_REG32( addr )                 (*(volatile u32 *)(addr))
+#ifndef AMAZON_PCI_MEM_BASE
+#define AMAZON_PCI_MEM_BASE    0xb2000000
+#endif
+#define AMAZON_PCI_MEM_SIZE    0x00400000
+#define AMAZON_PCI_IO_BASE     0xb2400000
+#define AMAZON_PCI_IO_SIZE     0x00002000
+
+#define AMAZON_PCI_CFG_BUSNUM_SHF 16
+#define AMAZON_PCI_CFG_DEVNUM_SHF 11
+#define AMAZON_PCI_CFG_FUNNUM_SHF 8
+
+#define PCI_ACCESS_READ  0
+#define PCI_ACCESS_WRITE 1
+
+static inline u32 amazon_r32(u32 addr)
+{
+       u32 *ptr = (u32 *) addr;
+       return __raw_readl(ptr);
+}
+
+static inline void amazon_w32(u32 addr, u32 val)
+{
+       u32 *ptr = (u32 *) addr;
+       __raw_writel(val, ptr);
+}
+
+
+static struct resource pci_io_resource = {
+       .name = "io pci IO space",
+#if 0
+       .start = AMAZON_PCI_IO_BASE,
+       .end = AMAZON_PCI_IO_BASE + AMAZON_PCI_IO_SIZE - 1,
+#endif
+       .start = 0,
+       .end = AMAZON_PCI_IO_SIZE - 1,
+       .flags = IORESOURCE_IO
+};
+
+static struct resource pci_mem_resource = {
+       .name = "ext pci memory space",
+       .start = AMAZON_PCI_MEM_BASE,
+       .end = AMAZON_PCI_MEM_BASE + AMAZON_PCI_MEM_SIZE - 1,
+       .flags = IORESOURCE_MEM
+};
+
+static inline u32 amazon_pci_swap(u32 val)
+{
+#ifdef CONFIG_AMAZON_PCI_HW_SWAP
+       return swab32(val);
+#else
+       return val;
+#endif
+}
+
+static int amazon_pci_config_access(unsigned char access_type,
+       struct pci_bus *bus, unsigned int devfn, unsigned int where, u32 *data)
+{
+       unsigned long flags;
+       u32 pci_addr;
+       u32 val;
+       int ret;
+   
+       /* Amazon support slot from 0 to 15 */
+       /* devfn 0 & 0x20 is itself */
+       if ((bus != 0) || (devfn == 0) || (devfn == 0x20))
+               return 1;
+
+       pci_addr=AMAZON_PCI_CFG_BASE |
+               bus->number << AMAZON_PCI_CFG_BUSNUM_SHF |
+               devfn << AMAZON_PCI_CFG_FUNNUM_SHF |
+               (where & ~0x3);
+    
+       local_irq_save(flags);
+       if (access_type == PCI_ACCESS_WRITE) {
+               val = amazon_pci_swap(*data);
+               ret = put_dbe(val, (u32 *)pci_addr);
+       } else {
+               ret = get_dbe(val, (u32 *)pci_addr);
+               *data = amazon_pci_swap(val);
+       }
+
+       amazon_w32(PCI_MODE, amazon_r32(PCI_MODE) & (~(1<<PCI_MODE_cfgok_bit)));
+       amazon_w32(STATUS_COMMAND_ADDR, amazon_r32(STATUS_COMMAND_ADDR));
+       amazon_w32(PCI_MODE, amazon_r32(PCI_MODE) | (~(1<<PCI_MODE_cfgok_bit)));
+       local_irq_restore(flags);
+
+       return ret; 
+}
+
+
+static int amazon_pci_read(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 *val)
+{
+       u32 data = 0;
+       int ret = PCIBIOS_SUCCESSFUL;
+
+       if (amazon_pci_config_access(PCI_ACCESS_READ, bus, devfn, where, &data)) {
+               data = ~0;
+               ret = -1;
+       }
+
+       switch (size) {
+               case 1:
+                       *((u8 *) val) = (data >> ((where & 3) << 3)) & 0xff;
+                       break;
+               case 2:
+                       *((u16 *) val) = (data >> ((where & 3) << 3)) & 0xffff;
+                       break;
+               case 4:
+                       *val = data;
+                       break;
+               default:
+                       return -1;
+       }
+
+       return ret;
+}
+
+
+static int amazon_pci_write(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 val)
+{
+       if (size != 4) {
+               u32 data;
+
+               if (amazon_pci_config_access(PCI_ACCESS_READ, bus, devfn, where, &data))
+                       return -1;
+
+               if (size == 1)
+                       val = (data & ~(0xff << ((where & 3) << 3))) | (val << ((where & 3) << 3));
+               else if (size == 2)
+                       val = (data & ~(0xffff << ((where & 3) << 3))) | (val << ((where & 3) << 3));
+               else
+                       return -1;
+       }
+
+       if (amazon_pci_config_access(PCI_ACCESS_WRITE, bus, devfn, where, &val))
+              return -1;
+
+       return PCIBIOS_SUCCESSFUL;
+}
+
+static struct pci_ops amazon_pci_ops = {
+       amazon_pci_read,
+       amazon_pci_write
+};
+
+static struct pci_controller amazon_pci_controller = {
+       .pci_ops = &amazon_pci_ops,
+       .mem_resource = &pci_mem_resource,
+       .io_resource = &pci_io_resource
+};
+
+int __init pcibios_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+{
+       switch (slot) {
+               case 13:
+                       /* IDSEL = AD29 --> USB Host Controller */
+                       return INT_NUM_IM2_IRL15;
+               case 14:
+                       /* IDSEL = AD30 --> mini PCI connector */
+                       return INT_NUM_IM2_IRL14;
+               default:
+                       printk("Warning: no IRQ found for PCI device in slot %d, pin %d\n", slot, pin);
+                       return 0;
+       }
+}
+
+int pcibios_plat_dev_init(struct pci_dev *dev)
+{
+       switch(dev->irq) {
+               case INT_NUM_IM2_IRL15:
+                       /* 
+                        * IDSEL = AD29 --> USB Host Controller
+                        * PCI_INTA/B/C--GPIO Port0.2--EXIN3
+                        * IN/ALT0:1 ALT1:0
+                        * PULL UP
+                        */
+                       (*AMAZON_GPIO_P0_DIR) = (*AMAZON_GPIO_P0_DIR) & 0xfffffffb;
+                       (*AMAZON_GPIO_P0_ALTSEL0) = (*AMAZON_GPIO_P0_ALTSEL0)| 4;
+                       (*AMAZON_GPIO_P0_ALTSEL1) = (*AMAZON_GPIO_P0_ALTSEL1)& 0xfffffffb;
+                       (*AMAZON_GPIO_P0_PUDSEL) =  (*AMAZON_GPIO_P0_PUDSEL) | 4;
+                       (*AMAZON_GPIO_P0_PUDEN) = (*AMAZON_GPIO_P0_PUDEN) | 4;
+                       //External Interrupt Node
+                       (*AMAZON_ICU_EXTINTCR) = (*AMAZON_ICU_EXTINTCR)|0x6000; /* Low Level triggered */
+                       (*AMAZON_ICU_IRNEN) = (*AMAZON_ICU_IRNEN)|0x8;
+                       pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq);
+                       break;
+               case INT_NUM_IM2_IRL14:
+                       /* 
+                        * IDSEL = AD30 --> mini PCI connector 
+                        * PCI_INTA--GPIO Port0.1--EXIN2
+                        * IN/ALT0:1 ALT1:0
+                        * PULL UP
+                        */
+                       (*AMAZON_GPIO_P0_DIR) = (*AMAZON_GPIO_P0_DIR) & 0xfffffffd;
+                       (*AMAZON_GPIO_P0_ALTSEL0) = (*AMAZON_GPIO_P0_ALTSEL0)| 2;
+                       (*AMAZON_GPIO_P0_ALTSEL1) = (*AMAZON_GPIO_P0_ALTSEL1)& 0xfffffffd;
+                       (*AMAZON_GPIO_P0_PUDSEL) =  (*AMAZON_GPIO_P0_PUDSEL) | 2;
+                       (*AMAZON_GPIO_P0_PUDEN) = (*AMAZON_GPIO_P0_PUDEN) | 2;
+                       //External Interrupt Node
+                       (*AMAZON_ICU_EXTINTCR) = (*AMAZON_ICU_EXTINTCR)|0x600;
+                       (*AMAZON_ICU_IRNEN) = (*AMAZON_ICU_IRNEN)|0x4;
+                       pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq);
+                       break;
+               default:
+                       return 1;
+       }
+       return 0;
+}
+
+int amazon_pci_init(void)
+{
+       u32 temp_buffer;
+
+#ifdef CONFIG_AMAZON_PCI_HW_SWAP
+       AMAZON_PCI_REG32(IRM) = AMAZON_PCI_REG32(IRM) | (1<<27) | (1<<28);
+       wmb();
+#endif
+
+       AMAZON_PCI_REG32(CLOCK_CONTROL) = AMAZON_PCI_REG32(CLOCK_CONTROL) | (1<<ARB_CTRL_bit);
+       amazon_w32(PCI_MODE, amazon_r32(PCI_MODE) & (~(1<<PCI_MODE_cfgok_bit)));
+
+       AMAZON_PCI_REG32(STATUS_COMMAND_ADDR) = AMAZON_PCI_REG32(STATUS_COMMAND_ADDR) | (1<<BUS_MASTER_ENABLE_BIT) |(1<<MEM_SPACE_ENABLE_BIT);
+
+       temp_buffer = AMAZON_PCI_REG32(PCI_ARB_CTRL_STATUS_ADDR);
+       temp_buffer = temp_buffer | (1<< INTERNAL_ARB_ENABLE_BIT);
+       temp_buffer = temp_buffer & ~(3<< PCI_MASTER0_REQ_MASK_2BITS);
+       temp_buffer = temp_buffer & ~(3<< PCI_MASTER0_GNT_MASK_2BITS);
+
+       /* flash */
+       temp_buffer = temp_buffer & ~(3<< PCI_MASTER1_REQ_MASK_2BITS);
+       temp_buffer = temp_buffer & ~(3<< PCI_MASTER1_GNT_MASK_2BITS);
+
+       /* external master */
+       temp_buffer = temp_buffer & ~(3<< PCI_MASTER2_REQ_MASK_2BITS);
+       temp_buffer = temp_buffer & ~(3<< PCI_MASTER2_GNT_MASK_2BITS);
+
+       AMAZON_PCI_REG32(PCI_ARB_CTRL_STATUS_ADDR) = temp_buffer;
+       wmb();
+
+       AMAZON_PCI_REG32(FPI_ADDRESS_MAP_0) = 0xb2000000;
+       AMAZON_PCI_REG32(FPI_ADDRESS_MAP_1) = 0xb2100000;
+       AMAZON_PCI_REG32(FPI_ADDRESS_MAP_2) = 0xb2200000;
+       AMAZON_PCI_REG32(FPI_ADDRESS_MAP_3) = 0xb2300000;
+       AMAZON_PCI_REG32(FPI_ADDRESS_MAP_4) = 0xb2400000;
+       AMAZON_PCI_REG32(FPI_ADDRESS_MAP_5) = 0xb2500000;
+       AMAZON_PCI_REG32(FPI_ADDRESS_MAP_6) = 0xb2600000;
+       AMAZON_PCI_REG32(FPI_ADDRESS_MAP_7) = 0xb2700000;
+          
+       AMAZON_PCI_REG32(BAR11_MASK) = 0x0f000008;
+       AMAZON_PCI_REG32(PCI_ADDRESS_MAP_11) = 0x0;
+       AMAZON_PCI_REG32(BAR1_ADDR) = 0x0;
+       amazon_w32(PCI_MODE, amazon_r32(PCI_MODE) | (~(1<<PCI_MODE_cfgok_bit)));
+       //use 8 dw burse length
+       AMAZON_PCI_REG32(FPI_BURST_LENGTH) = 0x303;
+
+       set_io_port_base(ioremap(AMAZON_PCI_IO_BASE, AMAZON_PCI_IO_SIZE));
+       register_pci_controller(&amazon_pci_controller);
+       return 0;
+}
+arch_initcall(amazon_pci_init);
diff --git a/target/linux/amazon-2.6/files/arch/mips/amazon/prom.c b/target/linux/amazon-2.6/files/arch/mips/amazon/prom.c
new file mode 100644 (file)
index 0000000..d60c3fa
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * copyright 2007 john crispin <blogic@openwrt.org> 
+ */
+#include <linux/init.h>
+#include <linux/string.h>
+#include <linux/ctype.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/bootmem.h>
+#include <linux/ioport.h>
+#include <asm/bootinfo.h>
+#include <asm/amazon/amazon.h>
+#include <asm/amazon/irq.h>
+#include <asm/amazon/model.h>
+#include <asm/cpu.h>
+
+void prom_putchar(char c)
+{
+       /* Wait for FIFO to empty */
+       while (((*AMAZON_ASC_FSTAT) >> 8) != 0x00) ;
+       /* Crude cr/nl handling is better than none */
+       if(c == '\n')
+               *AMAZON_ASC_TBUF=('\r');
+       *AMAZON_ASC_TBUF=(c);
+}
+
+void prom_printf(const char * fmt, ...)
+{
+       va_list args;
+       int l;
+       char *p, *buf_end;
+       char buf[1024]; 
+
+       va_start(args, fmt);
+       l = vsprintf(buf, fmt, args); /* hopefully i < sizeof(buf) */
+       va_end(args);
+       buf_end = buf + l;
+       
+       for (p = buf; p < buf_end; p++)
+               prom_putchar(*p);
+}
+
+
+void __init prom_init(void)
+{
+       mips_machgroup = MACH_GROUP_INFINEON;
+       mips_machtype = MACH_INFINEON_AMAZON;
+
+       strcpy(&(arcs_cmdline[0]), "console=ttyS0,115200 rootfstype=squashfs,jffs2 init=/etc/preinit");
+       
+       add_memory_region(0x00000000, 0x1000000, BOOT_MEM_RAM);
+}
+
+void prom_free_prom_memory(void)
+{
+}
+
+const char *get_system_type(void)
+{
+       return BOARD_SYSTEM_TYPE;
+}
diff --git a/target/linux/amazon-2.6/files/arch/mips/amazon/setup.c b/target/linux/amazon-2.6/files/arch/mips/amazon/setup.c
new file mode 100644 (file)
index 0000000..4cd3b9b
--- /dev/null
@@ -0,0 +1,216 @@
+/*
+ *      Copyright (C) 2004 Peng Liu <peng.liu@infineon.com>
+ *      Copyright (C) 2007 John Crispin <blogic@openwrt.org>
+ *      Copyright (C) 2007 Felix Fietkau <nbd@openwrt.org>
+ *      
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+ *
+ */
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+
+#include <asm/reboot.h>
+#include <asm/system.h>
+#include <asm/time.h>
+#include <asm/cpu.h>
+#include <asm/bootinfo.h>
+#include <asm/irq.h>
+#include <asm/mipsregs.h>
+#include <asm/amazon/amazon.h>
+#include <asm/amazon/irq.h>
+#include <asm/amazon/model.h>
+
+extern void prom_printf(const char * fmt, ...);
+static void amazon_reboot_setup(void);
+
+/* the CPU clock rate - lifted from u-boot */
+unsigned int amazon_get_cpu_hz(void)
+{
+       /*-----------------------------------*/
+       /**CGU CPU Clock Reduction Register***/ 
+       /*-----------------------------------*/
+       switch((*AMAZON_CGU_CPUCRD) & 0x3){
+               case 0:
+                       /*divider ration 1/1, 235 MHz clock */
+                       return 235000000;
+               case 1:
+                       /*divider ration 2/3, 235 MHz clock, clock not accurate, here */
+                       return 150000000;
+               case 2:
+                       /*divider ration 1/2, 235 MHz clock */
+                       return 117500000;
+               default:
+                       /*divider ration 1/4, 235 MHz clock */
+                       return 58750000;
+       }
+}
+
+/* the FPI clock rate - lifted from u-boot */
+unsigned int amazon_get_fpi_hz(void)
+{
+       unsigned int  clkCPU;
+       clkCPU = amazon_get_cpu_hz();
+
+       /*-------------------------------------*/
+       /***CGU Clock Divider Select Register***/
+       /*-------------------------------------*/
+       switch ((*AMAZON_CGU_DIV) & 0x3)
+       {
+               case 1:
+                       return clkCPU >> 1;
+               case 2:
+                       return clkCPU >> 2;
+               default:
+                       return clkCPU;
+               /* '11' is reserved */
+       }
+}
+
+/* get the CPU version number  - based on sysLib.c from VxWorks sources */
+/* this doesn't really belong here, but it's a convenient location */
+unsigned int amazon_get_cpu_ver(void)
+{
+       static unsigned int cpu_ver = 0;
+       if (cpu_ver == 0)
+               cpu_ver = *AMAZON_MCD_CHIPID & 0xFFFFF000;
+       return cpu_ver;
+}
+
+void amazon_time_init(void)
+{
+       mips_hpt_frequency = amazon_get_cpu_hz()/2;
+       printk("mips_hpt_frequency:%d\n",mips_hpt_frequency);
+}
+
+extern int hr_time_resolution;
+
+/* ISR GPTU Timer 6 for high resolution timer */
+static void amazon_timer6_interrupt(int irq, void *dev_id)
+{
+       timer_interrupt(AMAZON_TIMER6_INT, NULL);
+}
+
+static struct irqaction hrt_irqaction = {
+       .handler = amazon_timer6_interrupt,
+       .flags = SA_INTERRUPT,
+       .name = "hrt",
+};
+
+/*
+ * THe CPU counter for System timer, set to HZ
+ * GPTU Timer 6 for high resolution timer, set to hr_time_resolution
+ * Also misuse this routine to print out the CPU type and clock.
+ */
+void __init plat_timer_setup(struct irqaction *irq)
+{
+       /* cpu counter for timer interrupts */
+       setup_irq(MIPS_CPU_TIMER_IRQ, irq);
+
+#if 0
+       /* to generate the first CPU timer interrupt */
+       write_c0_compare(read_c0_count() + amazon_get_cpu_hz()/(2*HZ));
+#endif
+
+       /* enable the timer in the PMU */
+       *(AMAZON_PMU_PWDCR) = (*(AMAZON_PMU_PWDCR))| AMAZON_PMU_PWDCR_GPT|AMAZON_PMU_PWDCR_FPI;
+       /* setup the GPTU for timer tick  f_fpi == f_gptu*/
+       *(AMAZON_GPTU_CLC) = 0x100;
+
+       *(AMAZON_GPTU_CAPREL) = 0xffff;
+       *(AMAZON_GPTU_T6CON) = 0x80C0;
+       //setup_irq(AMAZON_TIMER6_INT,&hrt_irqaction);
+
+#if 0
+#ifdef CONFIG_HIGH_RES_TIMERS
+       /* GPTU timer 6 */
+       int retval;
+       if ( hr_time_resolution > 200000000 || hr_time_resolution < 40) {
+               prom_printf("hr_time_resolution is out of range, HIGH_RES_TIMER is diabled.\n");
+               return;
+       }
+       
+       /* enable the timer in the PMU */
+        *(AMAZON_PMU_PWDCR) = (*(AMAZON_PMU_PWDCR))| AMAZON_PMU_PWDCR_GPT|AMAZON_PMU_PWDCR_FPI;
+       /* setup the GPTU for timer tick  f_fpi == f_gptu*/
+       *(AMAZON_GPTU_CLC) = 0x100;
+
+       *(AMAZON_GPTU_CAPREL) = 0xffff;
+       *(AMAZON_GPTU_T6CON) = 0x80C0;
+       
+       retval = setup_irq(AMAZON_TIMER6_INT,&hrt_irqaction);
+       if (retval){
+               prom_printf("reqeust_irq failed %d. HIGH_RES_TIMER is diabled\n",AMAZON_TIMER6_INT);            
+       }
+#endif //CONFIG_HIGH_RES_TIMERS                
+#endif
+}
+
+void __init plat_mem_setup(void)
+{      
+       u32 chipid = 0;
+       u32 part_no = 0;
+       
+       chipid = *(AMAZON_MCD_CHIPID);
+       part_no = AMAZON_MCD_CHIPID_PART_NUMBER_GET(chipid);
+       
+       if(part_no == AMAZON_CHIPID_YANGTSE){
+               prom_printf("Yangtse Version\n");       
+       } else if (part_no == AMAZON_CHIPID_STANDARD) {
+               prom_printf(SYSTEM_MODEL_NAME "\n");
+       } else {
+               prom_printf("unknown version %8x\n",part_no);
+       }
+       
+       amazon_reboot_setup();
+       board_time_init = amazon_time_init;
+
+       //stop reset TPE and DFE
+       *(AMAZON_RST_REQ) = 0x0;
+       //clock
+       *(AMAZON_PMU_PWDCR) = 0x3fff;
+       //reenable trace capability
+       part_no = *(AMAZON_BCU_ECON);
+}
+
+static void amazon_machine_restart(char *command)
+{
+    local_irq_disable();
+    *AMAZON_RST_REQ = AMAZON_RST_ALL;
+    for (;;) ;
+}
+
+static void amazon_machine_halt(void)
+{
+    printk(KERN_NOTICE "System halted.\n");
+    local_irq_disable();
+    for (;;) ;
+}
+
+static void amazon_machine_power_off(void)
+{
+       printk(KERN_NOTICE "Please turn off the power now.\n");
+    local_irq_disable();
+    for (;;) ;
+}
+
+static void amazon_reboot_setup(void)
+{
+       _machine_restart = amazon_machine_restart;
+       _machine_halt = amazon_machine_halt;
+       pm_power_off = amazon_machine_power_off;
+}
diff --git a/target/linux/amazon-2.6/files/drivers/atm/amazon_tpe.c b/target/linux/amazon-2.6/files/drivers/atm/amazon_tpe.c
new file mode 100644 (file)
index 0000000..cf3e407
--- /dev/null
@@ -0,0 +1,3074 @@
+/*
+ *   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.
+ */
+//-----------------------------------------------------------------------
+/*
+ * Description:
+ *     Driver for Infineon Amazon TPE
+ */
+//-----------------------------------------------------------------------
+/* Author:     peng.liu@infineon.com
+ * Created:    12-April-2004
+ */
+//-----------------------------------------------------------------------
+/* History
+ * Last changed on: 13 Oct. 2004
+ * Last changed by: peng.liu@infineon.com
+ * Last changed on: 28 Jan. 2004
+ * Last changed by: peng.liu@infineon.com
+ * Last changed Reason:
+ *     - AAL5R may send more bytes than expected in MFL (so far, confirmed as 64 bytes)
+ */
+// 507261:tc.chen 2005/07/26 re-organize code address map to improve performance.
+// 507281:tc.chen 2005/07/28 fix f4 segment isssue
+/* 511045:linmars 2005/11/04 from Liu.Peng: change NRT_VBR bandwidth calculation based on scr instead of pcr */
+#ifndef __KERNEL__
+#define __KERNEL__
+#endif 
+#ifndef EXPORT_SYMTAB
+#define EXPORT_SYMTAB
+#endif
+
+/*TPE level loopback, bypass AWARE DFE */
+#undef TPE_LOOPBACK
+
+/* enable debug options */                     
+#undef AMAZON_ATM_DEBUG
+
+/* enable rx error packet analysis */
+#undef AMAZON_ATM_DEBUG_RX
+
+/* test AAL5 Interrupt */
+#undef  AMAZON_TPE_TEST_AAL5_INT
+
+/* dump packet */
+#undef AMAZON_TPE_DUMP
+
+/* read ARC register*/
+/* this register is located in side DFE module*/
+#undef AMAZON_TPE_READ_ARC
+
+/* software controlled reassembly */
+#undef AMAZON_TPE_SCR
+
+/* recovery from AAL5 bug */
+#undef AMAZON_TPE_AAL5_RECOVERY
+
+#if defined(AMAZON_TPE_READ_ARC) || defined(AMAZON_TPE_AAL5_RECOVERY)
+#define ALPHAEUS_BASE_ADDR     0x31c00
+#define A_CFG_ADDR             (ALPHAEUS_BASE_ADDR+0x04)
+#define AR_CB0_STATUS_ADDR             (ALPHAEUS_BASE_ADDR+0x2c)
+#define AR_CB1_STATUS_ADDR             (ALPHAEUS_BASE_ADDR+0x30)
+#define AT_CELL0_ADDR          (ALPHAEUS_BASE_ADDR+0x90)
+#define AR_CELL0_ADDR          (ALPHAEUS_BASE_ADDR+0x1a0)
+#define AR_CD_CNT0_ADDR                (ALPHAEUS_BASE_ADDR+0x1c8)
+#endif
+
+#include <linux/module.h>
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/kernel.h> 
+#include <linux/slab.h>  
+#include <linux/fs.h> 
+#include <linux/types.h>
+#include <linux/errno.h>  
+#include <linux/time.h>
+#include <linux/atm.h>
+#include <linux/atmdev.h>
+#include <linux/netdevice.h>
+#include <asm/byteorder.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+#include <asm/atomic.h>
+#include <asm/bitops.h>
+#include <asm/system.h>
+
+#include <asm/amazon/amazon.h>
+#include <asm/amazon/irq.h>
+
+#include <linux/in.h>
+#include <linux/netdevice.h> 
+#include <linux/etherdevice.h> 
+#include <linux/ip.h>
+#include <linux/tcp.h> 
+#include <linux/skbuff.h>
+#include <linux/in6.h>
+#include <linux/delay.h>
+#include <asm/amazon/atm_defines.h>
+#include <asm/amazon/amazon_dma.h>
+#include <asm/amazon/amazon_tpe.h>
+
+#if defined(AMAZON_TPE_READ_ARC) || defined(AMAZON_TPE_AAL5_RECOVERY)
+#include <asm/amazon/amazon_mei.h>
+#include <asm/amazon/amazon_mei_app.h>
+#endif
+
+#define AMAZON_TPE_EMSG(fmt, args...) printk( KERN_ERR  "%s: " fmt,__FUNCTION__, ## args)
+
+/***************************************** External Functions *******************************************/
+extern unsigned int amazon_get_fpi_hz(void);
+extern void mask_and_ack_amazon_irq(unsigned int irq_nr);
+extern void amz_push_oam(unsigned char *);
+
+//amazon_mei.c
+#if defined(AMAZON_TPE_READ_ARC) || defined(AMAZON_TPE_AAL5_RECOVERY)
+extern MEI_ERROR meiDebugRead(u32 srcaddr, u32 *databuff, u32 databuffsize);
+extern MEI_ERROR meiDebugWrite(u32 destaddr, u32 *databuff, u32 databuffsize);
+#endif
+
+/***************************************** Internal Functions *******************************************/
+int amazon_atm_read_procmem(char *buf, char **start, off_t offset,int count, int *eof, void *data);
+/***************************************** Global Data *******************************************/
+amazon_atm_dev_t g_atm_dev;            //device data
+static struct tq_struct swex_start_task;       //BH task
+static struct tq_struct swex_complete_task;    //BH task
+#ifdef AMAZON_TPE_SCR
+static struct tq_struct a5r_task;              //BH task
+#endif
+static struct dma_device_info  g_dma_dev;      //for DMA
+static struct atm_dev * amazon_atm_devs[AMAZON_ATM_PORT_NUM];
+static struct oam_last_activity g_oam_time_stamp[AMAZON_ATM_MAX_VCC_NUM];
+static u8 g_oam_cell[AMAZON_AAL0_SDU+4];       //for OAM cells
+#ifdef AMAZON_CHECK_LINK
+static int adsl_link_status;                   //ADSL link status, 0:down, 1:up
+#endif //AMAZON_CHECK_LINK
+/***************************************** Module Parameters *************************************/
+// Parameter Definition for module
+static int port_enable0 = 1;                           // Variable for parameter port_enable0
+static int port_enable1 = 0;                           // Variable for parameter port_enable1
+static int port_max_conn0 = 15;                                // Variable for parameter port_max_conn0
+static int port_max_conn1 = 0;                         // Variable for parameter port_max_conn1
+static int port_cell_rate_up0 = 7500;                  // Variable for parameter port_cell_rate_up0
+static int port_cell_rate_up1 = 7500;                  // Variable for parameter port_cell_rate_up1
+
+
+static int qsb_tau = 1;                                        // Variable for parameter qsb_tau
+static int qsb_srvm = 0xf;                             // Variable for parameter qsb_srvm
+static int qsb_tstep = 4 ;                             // Variable for parameter qsb_tstep
+
+static int cbm_nrt = 3900;                             // Variable for parameter cbm_nrt
+static int cbm_clp0 =3500;                             // Variable for parameter cbm_clp0
+static int cbm_clp1 =3200;                             // Variable for parameter cbm_clp1
+static int cbm_free_cell_no = AMAZON_ATM_FREE_CELLS;   // Variable for parameter cbm_free_cell_no
+
+static int a5_fill_pattern = 0x7e;                     // Variable for parameter a5_fill_pattern '~'
+static int a5s_mtu = 0x700;                            // mtu for tx
+static int a5r_mtu = 0x700;                            // mtu for rx
+
+static int oam_q_threshold =   64;                     // oam queue threshold, minium value 64
+static int rx_q_threshold =    1000;                   // rx queue threshold, minium value 64
+static int tx_q_threshold =    800;                    // tx queue threshold, minium value 64
+
+MODULE_PARM(port_max_conn0, "i");
+MODULE_PARM_DESC(port_max_conn0, "Maximum atm connection for port #0");
+MODULE_PARM(port_max_conn1, "i");
+MODULE_PARM_DESC(port_max_conn1, "Maximum atm connection for port #1");
+MODULE_PARM(port_enable0, "i");
+MODULE_PARM_DESC(port_enable0, "0 -> port disabled, 1->port enabled");
+MODULE_PARM(port_enable1, "i");
+MODULE_PARM_DESC(port_enable1, "0 -> port disabled, 1->port enabled");
+MODULE_PARM(port_cell_rate_up0, "i");
+MODULE_PARM_DESC(port_cell_rate_up0, "ATM port upstream rate in cells/s");
+MODULE_PARM(port_cell_rate_up1, "i");
+MODULE_PARM_DESC(port_cell_rate_up1, "ATM port upstream rate in cells/s");
+
+MODULE_PARM(qsb_tau,"i");
+MODULE_PARM_DESC(qsb_tau, "Cell delay variation. value must be > 0");
+MODULE_PARM(qsb_srvm, "i");
+MODULE_PARM_DESC(qsb_srvm, "Maximum burst size");
+MODULE_PARM(qsb_tstep, "i");
+MODULE_PARM_DESC(qsb_tstep, "n*32 cycles per sbs cycles n=1,2,4");
+
+MODULE_PARM(cbm_nrt, "i");
+MODULE_PARM_DESC(cbm_nrt, "Non real time threshold for cell buffer");
+MODULE_PARM(cbm_clp0, "i");
+MODULE_PARM_DESC(cbm_clp0, "Threshold for cells with cell loss priority 0");
+MODULE_PARM(cbm_clp1, "i");
+MODULE_PARM_DESC(cbm_clp1, "Threshold for cells with cell loss priority 1");
+MODULE_PARM(cbm_free_cell_no, "i");
+MODULE_PARM_DESC(cbm_free_cell_no, "Number of cells in the cell buffer manager");
+
+MODULE_PARM(a5_fill_pattern, "i");
+MODULE_PARM_DESC(a5_fill_pattern, "filling pattern (PAD) for aal5 frames");
+MODULE_PARM(a5s_mtu, "i");
+MODULE_PARM_DESC(a5s_mtu, "max. SDU for upstream");
+MODULE_PARM(a5r_mtu, "i");
+MODULE_PARM_DESC(a5r_mtu, "max. SDU for downstream");                                                                               
+
+MODULE_PARM(oam_q_threshold, "i");
+MODULE_PARM_DESC(oam_q_threshold, "oam queue threshold");
+
+MODULE_PARM(rx_q_threshold, "i");
+MODULE_PARM_DESC(rx_q_threshold, "downstream/rx queue threshold");
+
+MODULE_PARM(tx_q_threshold, "i");
+MODULE_PARM_DESC(tx_q_threshold, "upstream/tx queue threshold");
+
+/***************************************** local functions *************************************/
+/* Brief: valid QID
+ * Return: 1 if valid
+ *        0 if not
+ */
+static inline int valid_qid(int qid)
+{
+       return ( (qid>0) && (qid<AMAZON_ATM_MAX_QUEUE_NUM));
+}
+
+/*
+ * Brief: align to 16 bytes boundary 
+ * Parameter:
+ *     skb
+ * Description:
+ *     use skb_reserve to adjust the data pointer
+ *     don't change head pointer
+ *     pls allocate extrac 16 bytes before call this function
+ */
+static void inline alloc_align_16(struct sk_buff * skb)
+{
+       if ( ( ((u32) (skb->data)) & 15) != 0){
+               AMAZON_TPE_DMSG("need to adjust the alignment manually\n");
+               skb_reserve(skb, 16 - (((u32) (skb->data)) & 15) );
+       }
+
+}
+
+/*
+ * Brief: initialize the device according to the module paramters
+ * Return: not NULL    -       ok
+ *        NULL         -       fails
+ * Description: arrange load parameters and call the hardware initialization routines
+ */
+static void atm_init_parameters(amazon_atm_dev_t *dev)
+{
+       //port setting
+       dev->ports[0].enable = port_enable0;
+       dev->ports[0].max_conn = port_max_conn0;
+       dev->ports[0].tx_max_cr = port_cell_rate_up0;
+       if (port_enable1){
+               dev->ports[1].enable = port_enable1;
+               dev->ports[1].max_conn = port_max_conn1;
+               dev->ports[1].tx_max_cr = port_cell_rate_up1;
+       }
+
+       //aal5
+       dev->aal5.padding_byte = a5_fill_pattern;
+       dev->aal5.tx_max_sdu = a5s_mtu;
+       dev->aal5.rx_max_sdu = a5r_mtu;
+
+       //cbm
+       dev->cbm.nrt_thr = cbm_nrt;
+       dev->cbm.clp0_thr = cbm_clp0;
+       dev->cbm.clp1_thr = cbm_clp1;
+       dev->cbm.free_cell_cnt = cbm_free_cell_no;
+
+       //qsb
+       dev->qsb.tau = qsb_tau;
+       dev->qsb.tstepc =qsb_tstep;
+       dev->qsb.sbl = qsb_srvm;
+       
+       //allocate on the fly
+       dev->cbm.mem_addr = NULL;
+       dev->cbm.qd_addr = NULL;
+}
+
+
+/*     Brief:          Find QID for VCC
+ *     Parameters:     vcc     - VCC data structure
+ *     Return Value:   -EINVAL         - VCC not found
+ *                     qid             - QID for this VCC
+ *     Description:
+ *     This function returns the QID of a given VCC
+ */
+static int amazon_atm_get_queue(struct atm_vcc* vcc)
+{
+       int     i;
+       for (i=0;i<AMAZON_ATM_MAX_QUEUE_NUM;i++) {
+               if (g_atm_dev.queues[i].vcc == vcc) return i;
+       }
+       return -EINVAL;
+}
+
+
+/*
+ *     Brief:          Find QID for VPI/VCI
+ *     Parameters:     vpi     - VPI to found
+ *                     vci     - VCI to found
+ *
+ *     Return Value:   -EINVAL         - VPI/VCI not found
+ *                     qid             - QID for this VPI/VCI
+ *
+ *     Description:
+ *     This function returns the QID for a given VPI/VCI. itf doesn't matter
+ */
+static int amazon_atm_find_vpivci(u8 vpi, u16 vci)
+{
+       int     i;
+       struct atm_vcc * vcc;
+       for (i=0;i<AMAZON_ATM_MAX_QUEUE_NUM;i++) {
+               if ( (vcc = g_atm_dev.queues[i].vcc)!= NULL) {
+                       if ((vcc->vpi == vpi) && (vcc->vci == vci)) return i;
+               }
+       }
+       return -EINVAL;
+}
+
+/*     Brief:          Find QID for VPI
+ *     Parameters:     vpi     - VPI to found
+ *     Return Value:   -EINVAL         - VPI not found
+ *                     qid             - QID for this VPI
+ *
+ *     Description:
+ *     This function returns the QID for a given VPI. itf and VCI don't matter
+ */
+static int amazon_atm_find_vpi(u8 vpi)
+{
+       int     i;
+       for (i=0;i<AMAZON_ATM_MAX_QUEUE_NUM;i++) {
+               if ( g_atm_dev.queues[i].vcc!= NULL) {
+                       if (g_atm_dev.queues[i].vcc->vpi == vpi) return i;
+               }
+       }
+       return -EINVAL;
+}
+
+/*
+ *     Brief:          Clears QID entries for VCC
+ *
+ *     Parameters:     vcc     - VCC to found
+ *
+ *     Description:
+ *     This function searches for the given VCC and sets it to NULL if found.
+ */
+static inline void amazon_atm_clear_vcc(int i)
+{
+       g_atm_dev.queues[i].vcc = NULL;
+       g_atm_dev.queues[i].free = 1;
+}
+
+
+/*
+ * Brief:      dump skb data
+ */
+static inline void dump_skb(u32 len, char * data)
+{
+#ifdef AMAZON_TPE_DUMP
+       int i;
+       for(i=0;i<len;i++){     
+               printk("%2.2x ",(u8)(data[i]));
+               if (i % 16 == 15)
+                       printk("\n");
+       }
+       printk("\n");
+#endif
+}
+
+/*
+ * Brief:      dump queue descriptor
+ */
+static inline void dump_qd(int qid)
+{
+#ifdef AMAZON_TPE_DUMP
+       u8 * qd_addr;
+       if (valid_qid(qid) != 1) return;
+       qd_addr = (u8 *) KSEG1ADDR((unsigned long)g_atm_dev.cbm.qd_addr);
+       AMAZON_TPE_EMSG("qid: %u [%8x][%8x][%8x][%8x]\n", qid
+               ,readl(qd_addr+qid*CBM_QD_SIZE+0x0)
+               ,readl(qd_addr+qid*CBM_QD_SIZE+0x4)
+               ,readl(qd_addr+qid*CBM_QD_SIZE+0x8)
+               ,readl(qd_addr+qid*CBM_QD_SIZE+0xc));
+#endif
+}
+
+/*
+ * Brief:      release TX skbuff
+ */
+static inline void amazon_atm_free_tx_skb_vcc(struct atm_vcc *vcc, struct sk_buff *skb)
+{
+       if ( vcc->pop != NULL) {
+               vcc->pop(vcc, skb);
+        } else {
+               dev_kfree_skb_any(skb);
+        }
+}
+/*
+ * Brief:      release TX skbuff
+ */
+static inline void amazon_atm_free_tx_skb(struct sk_buff *skb)
+{
+       struct atm_vcc* vcc = ATM_SKB(skb)->vcc;
+       if (vcc!=NULL){
+               amazon_atm_free_tx_skb_vcc(vcc,skb);
+       } else {
+               dev_kfree_skb_any(skb);//fchang:Added
+       }
+}
+
+/* Brief:      divide by 64 and round up
+ */
+static inline u32 divide_by_64_round_up(int input)
+{
+       u32 tmp1;
+       tmp1 = (u32) input;
+        tmp1 = (tmp1%64)?(tmp1/64 + 1): (tmp1/64);
+        if (tmp1 == 0) tmp1 = 1;
+       return tmp1;
+}
+
+/*
+ * Brief:      statistics
+ */
+#ifdef AMAZON_ATM_DEBUG
+static inline void queue_statics(int qid, qs_t idx)
+{
+       if (valid_qid(qid)){
+               g_atm_dev.queues[qid].qs[idx]++;
+       }
+}
+#else  //not AMAZON_ATM_DEBUG
+static inline void queue_statics(int qid, qs_t idx){}
+#endif //AMAZON_ATM_DEBUG              
+
+
+/*     Brief:  set dma tx full, i.e. there is no available descriptors
+ */
+static void inline atm_dma_full(void)
+{
+       AMAZON_TPE_DMSG("ch0 is full\n");
+       atomic_set(&g_atm_dev.dma_tx_free_0,0);
+}
+
+/*
+ *     Brief   set dma tx free (at least one descript is available)
+ */
+inline static void atm_dma_free(void)
+{
+       AMAZON_TPE_DMSG("ch0 is free\n");
+       atomic_set(&g_atm_dev.dma_tx_free_0,1);
+}
+
+
+/*     Brief:          return the status of DMA TX descriptors
+ *     Parameters:     TX channel  (DMA_TX_CH0, TX_CH1)
+ *     Return:
+ *             1:      there are availabel TX descriptors
+ *             0:      no available
+ *     Description:
+ *
+ */
+inline int dma_may_send(int ch)
+{
+       if (atomic_read(&g_atm_dev.dma_tx_free_0)){
+               return 1;
+       }
+       return 0;
+}
+
+/******************************* global functions *********************************/ 
+/*
+ *     Brief:          SWIE Cell Extraction Start Routine
+ *                     and task routine for swex_complete_task
+ *     Parameters:     irq_stat        - interrupt status
+ *
+ *     Description:
+ *     This is the routine for extracting cell. It will schedule itself if the hardware is busy.
+ *     This routine runs in interrupt context
+ */
+void amazon_atm_swex(void * irq_stat)
+{
+       u32 ex_stat=0;
+       u32 addr;
+       // Read extraction status register
+       ex_stat = readl(CBM_HWEXSTAT0_ADDR);
+
+       // Check if extraction/insertion is in progress 
+       if ( (ex_stat & CBM_EXSTAT_SCB) || (ex_stat & CBM_EXSTAT_FB) || (test_and_set_bit(SWIE_LOCK, &(g_atm_dev.swie.lock))!=0)) {
+               AMAZON_TPE_DMSG(" extraction in progress. Will wait\n");
+               swex_start_task.data = irq_stat;
+               queue_task(&swex_start_task, &tq_immediate);
+               mark_bh(IMMEDIATE_BH);
+       }else {
+               // Extract QID
+               g_atm_dev.swie.qid = (((u32)irq_stat) >> 24);
+               AMAZON_TPE_DMSG("extracting from qid=%u\n",g_atm_dev.swie.qid);
+               //read status word
+               addr = KSEG1ADDR((unsigned long)g_atm_dev.cbm.qd_addr);
+               addr = readl((addr + g_atm_dev.swie.qid * 0x10 + 4) & 0xFFFFFFC0);
+               addr = KSEG1ADDR(addr);
+               g_atm_dev.swie.sw = readl(addr+52)&SWIE_ADDITION_DATA_MASK;
+               AMAZON_TPE_DMSG("cell addition word: %8x \n", g_atm_dev.swie.sw);
+               
+               // Start extraction
+               AMAZON_WRITE_REGISTER_L(g_atm_dev.swie.qid | SWIE_CBM_PID_SUBADDR, CBM_HWEXPAR0_ADDR);
+               AMAZON_WRITE_REGISTER_L(SWIE_CBM_SCE0, CBM_HWEXCMD_ADDR);
+       }
+}
+#ifdef AMAZON_TPE_SCR
+u32 g_a5r_wait=0;
+/*
+ *     Brief:          AAL5 Packet Extraction Routine  and task routine for a5r_task
+ *     Parameters:     irq_stat        - interrupt status
+ *
+ *     Description:
+ *     This is the routine for extracting frame. It will schedule itself if the hardware is busy.
+ *     This routine runs in interrupt context
+ */
+void amazon_atm_a5r(void* qid)
+{
+       volatile u32 ex_stat=0;
+       u32 addr;
+       u32 a5r_wait=0;
+
+       ex_stat = readl(CBM_HWEXSTAT0_ADDR);
+#if 0
+       // Check if extraction/insertion is in progress 
+       if ( (ex_stat & CBM_EXSTAT_SCB) || (ex_stat & CBM_EXSTAT_FB) ) {
+               AMAZON_TPE_DMSG(" extraction in progress. Will wait\n");
+               a5r_task.data = qid;
+               queue_task(&a5r_task, &tq_immediate);
+               mark_bh(IMMEDIATE_BH);
+       }else {
+               AMAZON_TPE_DMSG("extracting from qid=%u\n",(u8)qid);
+               // Start extraction
+               AMAZON_WRITE_REGISTER_L(((u8)qid) | CBM_HWEXPAR_PN_A5, CBM_HWEXPAR0_ADDR);
+               AMAZON_WRITE_REGISTER_L(CBM_HWEXCMD_FE0, CBM_HWEXCMD_ADDR);
+       }
+#else
+       //while ( (ex_stat & CBM_EXSTAT_SCB) || (ex_stat & CBM_EXSTAT_FB) ) {
+       while ( ex_stat != 0x80){
+               a5r_wait++;
+               ex_stat = readl(CBM_HWEXSTAT0_ADDR);
+#if    0
+               if (a5r_wait >= 0xffffff){
+                       a5r_wait=0;
+                       printk(".");
+               }
+#endif
+       }
+       if (a5r_wait > g_a5r_wait){
+               g_a5r_wait = a5r_wait;
+       }
+       AMAZON_WRITE_REGISTER_L(((u8)qid) | CBM_HWEXPAR_PN_A5, CBM_HWEXPAR0_ADDR);
+       AMAZON_WRITE_REGISTER_L(CBM_HWEXCMD_FE0, CBM_HWEXCMD_ADDR);
+#endif
+}
+
+#endif //AMAZON_TPE_SCR
+
+/*     Brief:  Handle F4/F5 OAM cell
+ *     Return:
+ *             0       ok
+ *             <0      fails
+ */
+static int inline amazon_handle_oam_cell(void *data, u8 vpi, u16 vci,u32 status)
+{
+       struct atm_vcc*         vcc=NULL;
+       int qid;
+       if (!status&SWIE_EOAM_MASK){
+               AMAZON_TPE_EMSG("unknown cell received, discarded\n");
+               goto amazon_handle_oam_cell_err_exit;
+       }else if (status&SWIE_ECRC10ERROR_MASK){
+               AMAZON_TPE_EMSG("CRC-10 Error Status:%8x, discarded\n", status);
+               goto amazon_handle_oam_cell_err_exit;
+       }else{
+               if(status & (SWIE_EVCI3_MASK |SWIE_EVCI4_MASK)){
+                       //F4 level (VPI) OAM, Assume duplex
+                       qid = amazon_atm_find_vpi(vpi)+CBM_RX_OFFSET;
+               }else if (status & (SWIE_EPTI4_MASK|SWIE_EPTI5_MASK)){
+                       //F5 level (VCI) OAM, Assume duplex
+                       qid = amazon_atm_find_vpivci(vpi,vci)+CBM_RX_OFFSET;                    
+               }else{
+                       qid = -1;
+                       AMAZON_TPE_EMSG("non-F4/F5 OAM cells?, discarded\n");
+                       goto amazon_handle_oam_cell_err_exit;
+               }
+       }
+       if (valid_qid(qid) && ((vcc = g_atm_dev.queues[qid].vcc)!=NULL)){
+               //TODO, should we do this for ALL OAM types? (Actually only User and CC)
+               g_atm_dev.queues[qid].access_time=xtime;
+               if (vcc->push_oam){
+                       (*vcc->push_oam)(vcc,data);
+               }else{
+                       amz_push_oam(data);
+               }
+       }else{
+               AMAZON_TPE_EMSG("no VCC yet\n");
+               goto amazon_handle_oam_cell_err_exit;
+       }
+       return 0;
+amazon_handle_oam_cell_err_exit:       
+       dump_skb(AMAZON_AAL0_SDU,(char *)data); 
+       return -1;
+}
+
+/*     Brief:  SWIE Cell Extraction Finish Routine 
+ *             and task routine for swex_complete_task
+ *     Description:
+ *     1.Allocate a buffer of type struct sk_buff
+ *     2.Copy the data from the temporary memory to this buffer
+ *     3.Push the data to upper layer
+ *     4.Update the statistical data if necessary
+ *     5.Release the temporary data
+
+ */
+void amazon_atm_swex_push(void * data)
+{
+       struct atm_vcc*         vcc=NULL;
+       struct sk_buff*         skb=NULL;
+       struct amazon_atm_cell_header * cell_header;
+       u32 status;
+       int qid;
+       if (!data){
+               AMAZON_TPE_EMSG("data is NULL\n");
+               return;
+       }
+       qid = ((u8*)data)[AMAZON_AAL0_SDU];
+       status = ((u32*)data)[ATM_AAL0_SDU/4];
+       cell_header = (struct amazon_atm_cell_header *) data;
+       if (valid_qid(qid) != 1){
+               AMAZON_TPE_EMSG("error qid: %u\n",qid);
+               AMAZON_TPE_EMSG("unknown cells recieved\n");
+       }else if (qid == AMAZON_ATM_OAM_Q_ID){
+               //OAM or RM or OTHER cell
+               //Find real connection
+               
+#ifdef IKOS_MINI_BOOT  
+               //for OAM loop back test
+               dump_skb(56,(char *)data);
+               //kfree(data);  using g_oam_cell
+               return;
+#endif //IKOS_MINI_BOOT                                
+#ifdef TPE_LOOPBACK                                    
+               amz_push_oam(data);
+               return;
+#endif//TPE_LOOPBACK
+               int ret = 0;
+               ret = amazon_handle_oam_cell(data,cell_header->bit.vpi,cell_header->bit.vci,status);
+               if (ret == 0)
+                                       return;
+                               }else{
+               //should be normal AAL0 cells
+               // Get VCC
+               vcc = g_atm_dev.queues[qid].vcc;
+               if (vcc != NULL) {
+                       AMAZON_TPE_DMSG("push to upper layer\n");
+                       skb = dev_alloc_skb(AMAZON_AAL0_SDU);
+                       if (skb != NULL) {
+                               //skb->dev=vcc->dev;
+                               memcpy(skb_put(skb, AMAZON_AAL0_SDU), data, AMAZON_AAL0_SDU);
+                               skb->stamp = xtime;
+                               ATM_SKB(skb)->vcc = vcc;
+                               (*g_atm_dev.queues[qid].push)(vcc,skb,0);
+                       }else{
+                               AMAZON_TPE_EMSG(" No memory left for incoming AAL0 cell! Cell discarded!\n");
+                               //inform the upper layer
+                               (*g_atm_dev.queues[qid].push)(vcc,skb,-ENOMEM);
+                               atomic_inc(&vcc->stats->rx_drop);
+                       }
+               }else{
+                       AMAZON_TPE_EMSG("invalid qid %u\n",qid);
+               }
+       }
+       //kfree(data);  using g_oam_cell
+}
+
+/*
+ *     Brief:          Interrupt handler for software cell extraction (done)
+ *     Parameters:     irq     - CPPN for this interrupt
+ *                     data    - Device ID for this interrupt
+ *                     regs    - Register file
+ *
+ *     Description:
+ *     When a software extraction is finished this interrupt is issued.
+ *     It reads the cell data and sends it to the ATM stack.
+ */
+void amazon_atm_swex_isr(int irq, void *data, struct pt_regs *regs)
+{
+       u32 * cell = NULL;
+       int i;
+       //ATM_AAL0 SDU + QID
+       AMAZON_TPE_DMSG("SWIE extraction done\n");
+       cell = (u32 *) g_oam_cell;
+       if (cell != NULL){
+               //convert to host byte order from big endian
+               for(i=0;i<ATM_AAL0_SDU;i+=4){
+                       cell[i/4]=readl(SWIE_ECELL_ADDR+i);     
+               }
+               cell[ATM_AAL0_SDU/4]= g_atm_dev.swie.sw;
+               ((u8*)cell)[AMAZON_AAL0_SDU] = g_atm_dev.swie.qid;
+#ifdef IKOS_MINI_BOOT
+       for(i=0;i<ATM_AAL0_SDU;i+=4){
+               AMAZON_TPE_DMSG("[%2x][%2x][%2x][%2x]\n",
+                       ((char*)cell)[i],
+                       ((char*)cell)[i+1],
+                       ((char*)cell)[i+2],
+                       ((char*)cell)[i+3]
+                       );
+       }
+       AMAZON_TPE_DMSG("qid: %u\n", ((u8*)cell)[AMAZON_AAL0_SDU]);
+       amazon_atm_swex_push((void *) cell);
+#else //not IKOS_MINI_BOOT
+       swex_complete_task.data = cell;
+       queue_task(&swex_complete_task,&tq_immediate);
+       mark_bh(IMMEDIATE_BH);
+#endif //not IKOS_MINI_BOOT
+       }else{
+               AMAZON_TPE_EMSG("no memory for receiving AAL0 cell\n");
+       }
+       
+       /* release the lock and check */
+       if (test_and_clear_bit(SWIE_LOCK,&(g_atm_dev.swie.lock)) == 0){
+               AMAZON_TPE_EMSG("swie lock is already released\n");
+       }
+       wake_up(&g_atm_dev.swie.sleep);
+}
+/*     Brief:          Interrupt handler for software cell insertion
+ *
+ *     Parameters:     irq     - CPPN for this interrupt
+ *                     data    - Device ID for this interrupt
+ *                     regs    - Register file
+ *
+ *     Description:
+ *     When a software insertion is finished this interrupt is issued.
+ *     The only purpose is to release the semaphore and read the status register.
+ */
+void amazon_atm_swin_isr(int irq, void *data, struct pt_regs *regs)
+{
+       AMAZON_TPE_DMSG("SWIE insertion done\n");
+       /* release the lock and check */
+       if (test_and_clear_bit(SWIE_LOCK,&(g_atm_dev.swie.lock)) == 0){
+               AMAZON_TPE_EMSG("swie lock is already released");
+       }
+       // Release semaphore
+       up(&g_atm_dev.swie.in_sem);
+
+}
+/*     Brief:          Interrupt handler for software cell insertion & extraction
+ *     Parameters:     irq     - CPPN for this interrupt
+ *                     data    - Device ID for this interrupt
+ *                     regs    - Register file
+ *     Description:
+ *     When a software insertion or extractionis finished this interrupt is issued.
+ */
+void amazon_atm_swie_isr(int irq, void *data, struct pt_regs *regs)
+{
+       u32     status=0;
+       // Read status register
+       status = readl(SWIE_ISTAT_ADDR);
+       AMAZON_TPE_DMSG("insertion status: %8x\n", status);
+       if (status & SWIE_ISTAT_DONE){
+               //clear interrupt in peripheral and ICU
+               AMAZON_WRITE_REGISTER_L(SRC_TOS_MIPS | SRC_CLRR|SRC_SRE_ENABLE | AMAZON_SWIE_INT, SWIE_ISRC_ADDR);
+               mask_and_ack_amazon_irq(AMAZON_SWIE_INT);
+               
+               amazon_atm_swin_isr(irq,data,regs);
+       }
+       status = readl(SWIE_ESTAT_ADDR);
+       AMAZON_TPE_DMSG("extraction status: %8x\n", status);
+       if (status & SWIE_ESTAT_DONE){
+               //clear interrupt
+               AMAZON_WRITE_REGISTER_L(SRC_TOS_MIPS | SRC_CLRR|SRC_SRE_ENABLE | AMAZON_SWIE_INT, SWIE_ESRC_ADDR);
+               mask_and_ack_amazon_irq(AMAZON_SWIE_INT);
+               
+               amazon_atm_swex_isr(irq,data,regs);
+       }
+       //clear interrupt in ICU
+}
+/*
+ *     Brief:          Insert ATM cell into CBM
+ *     Parameters:     queue   - Target queue
+ *                     cell    - Pointer to cell data
+ *     Return Value:   EBUSY           - CBM is busy
+ *                     0               - OK, cell inserted
+ *     Description:
+ *     This function inserts a cell into the CBM using the software insertion
+ *     method. The format of the cell should be
+ *     Little Endian (address starting from 0)
+ *             H3, H2, H1, H0, P3, P2, P1, P0, P7, P6, P5, P4, ..., P47, P46, P45, P44
+ *     Big Endian (address starting from 0)
+ *             H0, H1, H2, H3, P0, P1, P2, P3, P4, P5, P6, P7, ..., P44, P45, P46, P47
+ *     This function does not free memory!!!
+ */
+int amazon_atm_swin(u8 queue, void* cell)
+{
+       u32     status=0;
+       int i;
+       // Read status register
+       status = readl(SWIE_ISTAT_ADDR);
+       AMAZON_TPE_DMSG(" SWIE status=0x%08x\n",status);
+
+       AMAZON_TPE_DMSG(" Inserting cell qid=%u\n",queue);
+       
+#ifdef AMAZON_CHECK_LINK
+       if (adsl_link_status == 0){
+               return -EFAULT; 
+       }
+#endif //AMAZON_CHECK_LINK
+
+       // Get semaphore (if possible)
+       if (down_interruptible(&g_atm_dev.swie.in_sem)) {
+               return -ERESTARTSYS;
+       }
+       /* try to set lock */
+       wait_event_interruptible(g_atm_dev.swie.sleep,(test_and_set_bit(SWIE_LOCK,&(g_atm_dev.swie.lock)) == 0));
+       if (signal_pending(current)){
+               return -ERESTARTSYS; 
+       }
+
+       // Store cell in CBM memory
+       for(i=0;i<ATM_AAL0_SDU;i+=4){
+               AMAZON_WRITE_REGISTER_L(((u32*)cell)[i/4],SWIE_ICELL_ADDR+i);
+       }
+       //Store queue id
+       AMAZON_WRITE_REGISTER_L((u32) queue,SWIE_IQID_ADDR);
+
+       //Start SWIE
+       AMAZON_WRITE_REGISTER_L(SWIE_ICMD_START,SWIE_ICMD_ADDR);
+       
+       return 0;
+}
+
+#ifdef AMAZON_ATM_DEBUG
+/*
+ *     Brief:          Interrupt handler for HTU
+ *
+ *     Parameters:     irq     - CPPN for this interrupt
+ *                     data    - Device ID for this interrupt
+ *                     regs    - Register file
+ *
+ */
+void amazon_atm_htu_isr(int irq, void *data, struct pt_regs *regs)
+{
+       u32     irq_stat=0;
+
+       // Read interrupt status register
+       irq_stat = readl(HTU_ISR0_ADDR);
+       AMAZON_TPE_DMSG("HTU status: %8x\n",irq_stat);
+       //Clear interrupt in CBM and ICU
+       AMAZON_WRITE_REGISTER_L(SRC_CLRR|SRC_TOS_MIPS | SRC_SRE_ENABLE | AMAZON_HTU_INT, HTU_SRC0_ADDR);
+       mask_and_ack_amazon_irq(AMAZON_HTU_INT);        
+       // Check if Any Cell Arrived
+       if (irq_stat & (HTU_ISR_NE | HTU_ISR_PNE) ) {
+               AMAZON_TPE_EMSG("INFNOENTRY %8x\n", readl(HTU_INFNOENTRY_ADDR));                
+       }else if (irq_stat & (HTU_ISR_TORD|HTU_ISR_PT)){
+               AMAZON_TPE_EMSG("Time Out %8x\n", readl(HTU_INFTIMEOUT_ADDR));
+       }else if (irq_stat & HTU_ISR_IT){
+               AMAZON_TPE_EMSG("Interrupt Test\n");
+       }else if (irq_stat & HTU_ISR_OTOC){
+               AMAZON_TPE_EMSG("Overflow of Time Out Counter\n");
+       }else if (irq_stat & HTU_ISR_ONEC){
+               AMAZON_TPE_EMSG("Overflow of No Entry Counter\n");
+       }else{
+               AMAZON_TPE_EMSG("unknown HTU interrupt occurs %8x\n", irq_stat);
+       }
+
+}
+#endif //AMAZON_ATM_DEBUG
+
+#ifdef AMAZON_TPE_TEST_AAL5_INT
+/*
+ *     Brief:          Interrupt handler for AAL5
+ *
+ *     Parameters:     irq     - CPPN for this interrupt
+ *                     data    - Device ID for this interrupt
+ *                     regs    - Register file
+ *
+ */
+void amazon_atm_aal5_isr(int irq, void *data, struct pt_regs *regs)
+{
+       volatile u32 irq_stat=0;
+
+       // Read interrupt status register
+       irq_stat = readl(AAL5_SISR0_ADDR);
+       if (irq_stat){
+               AMAZON_TPE_EMSG("A5S status: %8x\n",irq_stat);
+               //Clear interrupt in CBM and ICU
+               AMAZON_WRITE_REGISTER_L(SRC_CLRR|SRC_TOS_MIPS | SRC_SRE_ENABLE | AMAZON_AAL5_INT, AAL5_SSRC0_ADDR);
+               mask_and_ack_amazon_irq(AMAZON_AAL5_INT);       
+       }
+       irq_stat = readl(AAL5_RISR0_ADDR);
+       if (irq_stat){
+               AMAZON_TPE_EMSG("A5R status: %8x\n",irq_stat);
+               //Clear interrupt in CBM and ICU
+               AMAZON_WRITE_REGISTER_L(SRC_CLRR|SRC_TOS_MIPS | SRC_SRE_ENABLE | AMAZON_AAL5_INT, AAL5_RSRC0_ADDR);
+               mask_and_ack_amazon_irq(AMAZON_AAL5_INT);       
+       }
+}
+#endif //AMAZON_TPE_TEST_AAL5_INT
+
+/*
+ *     Brief:          Interrupt handler for CBM
+ *
+ *     Parameters:     irq     - CPPN for this interrupt
+ *                     data    - Device ID for this interrupt
+ *                     regs    - Register file
+ *
+ *     Description:
+ *     This is the MIPS interrupt handler for the CBM. It processes incoming cells
+ *     for SWIE queues.
+ */
+void amazon_atm_cbm_isr(int irq, void *data, struct pt_regs *regs)
+{
+       u32     irq_stat=0;
+       u8 qid=0;
+
+       // Read interrupt status register
+       while ( (irq_stat = readl(CBM_INTINF0_ADDR))){
+               AMAZON_TPE_DMSG("CBM INT status: %8x\n",irq_stat);
+               //Clear interrupt in CBM and ICU
+               AMAZON_WRITE_REGISTER_L(SRC_CLRR|SRC_TOS_MIPS | SRC_SRE_ENABLE | AMAZON_CBM_INT, CBM_SRC0_ADDR);
+               qid = (u8) ((irq_stat & CBM_INTINF0_QID_MASK)>>CBM_INTINF0_QID_SHIFT);
+#ifdef AMAZON_TPE_SCR  
+               if (irq_stat & CBM_INTINF0_EF){
+                       amazon_atm_a5r((void*)qid);
+               }
+#endif
+               // Check if Any Cell Arrived
+               if (irq_stat & CBM_INTINF0_ACA) {
+                       amazon_atm_swex((void *)irq_stat);              
+               }
+               //TX AAL5 PDU discard
+               if (irq_stat & CBM_INTINF0_OPF){
+                       if ( (qid) < CBM_RX_OFFSET ){
+                               g_atm_dev.mib_counter.tx_drop++;
+                       }
+                       queue_statics(qid, QS_HW_DROP);
+               }
+               if (irq_stat & (CBM_INTINF0_ERR|CBM_INTINF0_Q0E|CBM_INTINF0_Q0I|CBM_INTINF0_RDE)){
+                       AMAZON_TPE_EMSG("CBM INT status: %8x\n",irq_stat);
+                       if (irq_stat & CBM_INTINF0_ERR){
+                               AMAZON_TPE_EMSG("CBM Error: FPI Bus Error\n");
+                       }
+                       if (irq_stat & CBM_INTINF0_Q0E){
+                               AMAZON_TPE_EMSG("CBM Error: Queue 0 Extract\n");
+                       }
+                       if (irq_stat & CBM_INTINF0_Q0I){
+                               AMAZON_TPE_EMSG("CBM Error: Queue 0 Extract\n");
+                       }
+                       if (irq_stat & CBM_INTINF0_RDE){
+                               AMAZON_TPE_EMSG("CBM Error: Read Empty Queue %u\n",qid);
+                               dump_qd(qid);
+                       }
+               }               
+       }
+       mask_and_ack_amazon_irq(AMAZON_CBM_INT);
+}
+
+/*     Brief:  check the status word after AAL SDU after reassembly
+ */
+static inline void check_aal5_error(u8 stw0, u8 stw1, int qid)
+{
+       if (stw0 & AAL5_STW0_MFL){
+               AMAZON_TPE_DMSG("Maximum Frame Length\n");
+               g_atm_dev.queues[qid].aal5VccOverSizedSDUs++;
+       } 
+       if (stw0 & AAL5_STW0_CRC){
+               AMAZON_TPE_DMSG("CRC\n");
+               g_atm_dev.queues[qid].aal5VccCrcErrors++;
+       }
+#ifdef AMAZON_ATM_DEBUG_RX
+       AMAZON_TPE_EMSG("qid:%u stw0:%8x stw1:%8x\n",qid,stw0,stw1);
+#endif
+}
+
+/* Brief:      Process DMA rx data
+ * Parameters:
+       dma_dev:        pointer to the dma_device_info, provided by us when register the dma device
+ * Return:     no
+ * Description: DMA interrupt handerl with OoS support. It is called when there is some data in rx direction.
+ *
+ */
+//507261:tc.chen void atm_process_dma_rx(struct dma_device_info* dma_dev)
+void __system atm_process_dma_rx(struct dma_device_info* dma_dev)
+{
+        u8 * head=NULL;
+        u32 length=0;
+        u8 stw0=0;
+        u8 stw1=0;
+
+       struct sk_buff * skb=NULL;
+       struct atm_vcc * vcc=NULL;
+       int qid=0;
+#ifdef AMAZON_ATM_DEBUG_RX
+       static int dma_rx_dump=0;
+       static u32 seq=0;
+       
+       seq++;
+       if (dma_rx_dump>0){
+               printk("\n=========================[%u]=========================\n",seq);
+       }
+#endif 
+       length=dma_device_read(dma_dev,&head,(void**)&skb);
+       AMAZON_TPE_DMSG("receive %8p[%u] from DMA\n", head,length);
+       if (head == NULL||length<=0) {
+               AMAZON_TPE_DMSG("dma_read null \n");
+               goto error_exit;
+       }
+
+       if (length > (g_atm_dev.aal5.rx_max_sdu+64)){
+               AMAZON_TPE_EMSG("received packet too large (%u)\n",length);
+               goto error_exit;
+       }
+       //check AAL5R trail for error and qid
+       //last byte is qid
+       length--;
+       qid = (int) head[length];
+       AMAZON_TPE_DMSG("head[%u] qid %u\n",length, qid);
+       //STW0 is always 4 bytes before qid
+       length -= 4;
+       stw0 = head[length]&0xff;
+       AMAZON_TPE_DMSG("head[%u] stw0 %8x\n",length, stw0);
+       //position of STW1 depends on the BE bits
+       length = length-4 + (stw0&AAL5_STW0_BE);
+       stw1 = head[length]&0xff;
+       AMAZON_TPE_DMSG("head[%u] stw1 %8x\n",length, stw1);    
+       if ( (stw0 & AAL5_STW0_MASK) || (stw1 & AAL5_STW1_MASK) ){
+               //AAL5 Error
+               check_aal5_error(stw0, stw1,qid);               
+               goto error_exit;
+       }
+       //make data pointers consistent
+       //UU + CPI
+       length -= 2;
+       AMAZON_TPE_DMSG("packet length %u\n", length);
+
+       //error: cannot restore the qid
+       if (valid_qid(qid) != 1){
+               AMAZON_TPE_EMSG("received frame in invalid qid %u!\n", qid);
+               goto error_exit;
+       }
+       vcc = g_atm_dev.queues[qid].vcc;
+       if (vcc == NULL){
+               AMAZON_TPE_EMSG("received frame in invalid vcc, qid=%u!\n",qid);
+               goto error_exit;
+       }
+       if (skb == NULL){
+               AMAZON_TPE_EMSG("cannot restore skb pointer!\n");
+               goto error_exit;
+       }
+       skb_put(skb,length);
+       skb->stamp = xtime;
+       g_atm_dev.queues[qid].access_time=xtime;
+       if ((*g_atm_dev.queues[qid].push)(vcc,skb,0)){
+               g_atm_dev.mib_counter.rx_drop++;
+               queue_statics(qid, QS_SW_DROP);                                 
+       }else{
+               g_atm_dev.mib_counter.rx++;
+               adsl_led_flash();//joelin adsl led
+               queue_statics(qid, QS_PKT);
+               AMAZON_TPE_DMSG("push successful!\n");
+       }
+#ifdef AMAZON_ATM_DEBUG_RX
+       if (dma_rx_dump>0){
+               printk("\nOK packet [dump=%u] length=%u\n",dma_rx_dump,length);
+               dump_skb(length+7, head);
+       }
+       if (dma_rx_dump >0) dma_rx_dump--;
+#endif 
+       return ;
+error_exit:
+#ifdef AMAZON_ATM_DEBUG_RX
+       if ( (head!=NULL) && (length >0)){
+               AMAZON_TPE_EMSG("length=%u\n",length);
+               dump_skb(length+5, head);
+       }       
+       dma_rx_dump++;
+#endif 
+       g_atm_dev.mib_counter.rx_err++;
+       queue_statics(qid, QS_ERR);
+       /*
+       if (vcc){
+               (*g_atm_dev.queues[qid].push)(vcc,skb,1);       
+       }
+       */
+       if (skb != NULL) {
+               dev_kfree_skb_any(skb);
+       }
+       return;
+}
+
+/*Brief:       ISR for DMA pseudo interrupt
+ *Parameter:
+       dma_dev:        pointer to the dma_device_info, provided by us when register the dma device
+       intr_status:    
+               RCV_INT:                rx data available
+               TX_BUF_FULL_INT:        tx descriptor run out of
+               TRANSMIT_CPT_INT:       tx descriptor available again
+ *Return:
+       0 for success???
+ */
+//507261:tc.chen int amazon_atm_dma_handler(struct dma_device_info* dma_dev, int intr_status)
+int __system amazon_atm_dma_handler(struct dma_device_info* dma_dev, int intr_status)
+{
+       AMAZON_TPE_DMSG("status:%u\n",intr_status);
+       switch (intr_status) {
+               case RCV_INT:
+                       atm_process_dma_rx(dma_dev);
+                       break;
+               case TX_BUF_FULL_INT:
+                       //TX full: no descriptors
+                       atm_dma_full();
+                       break;
+               case TRANSMIT_CPT_INT:
+                       //TX free: at least one descriptor
+                       atm_dma_free();
+                       break;
+               default:
+                       AMAZON_TPE_EMSG("unknown status!\n");
+       }
+       return 0;
+}
+
+/*Brief:       free buffer for DMA tx
+ *Parameter:
+       dataptr:        pointers to data buffer
+       opt:            optional parameter, used to convey struct skb pointer, passwd in dma_device_write
+ *Return:
+       0 for success???
+ *Description:
+       called by DMA module to release data buffer after DMA tx transaction
+ *Error:
+       cannot restore skb pointer
+ */
+int amazon_atm_free_tx(u8*dataptr, void* opt)
+{
+       struct sk_buff *skb;
+       if (opt){
+               AMAZON_TPE_DMSG("free skb%8p\n",opt);
+               skb = (struct sk_buff *)opt;
+               amazon_atm_free_tx_skb(skb);
+       }else{
+               AMAZON_TPE_EMSG("BUG: cannot restore skb pointer!\n");
+       }
+       return 0;
+}
+
+/*Brief:       allocate buffer & do alignment
+ */
+inline struct sk_buff * amazon_atm_alloc_buffer(int len)
+{
+       struct sk_buff *skb;
+       skb = dev_alloc_skb(len+16);
+       if (skb){
+               //alignment requriements (4x32 bits (16 bytes) boundary)
+               alloc_align_16(skb);
+       }
+       return skb;
+}
+
+/*Brief:       allocate buffer for DMA rx
+ *Parameter:
+       len: length
+       opt: optional data to convey the skb pointer, which will be returned to me in interrupt handler,
+ *Return:
+       pointer to buffer, NULL means error?
+ *Description:
+       must make sure byte alignment
+ */
+       
+u8* amazon_atm_alloc_rx(int len, int* offset, void **opt)
+{
+       struct sk_buff *skb;
+       *offset = 0;
+       skb = amazon_atm_alloc_buffer(len);
+       if (skb){
+               AMAZON_TPE_DMSG("alloc skb->data:%8p len:%u\n",skb->data,len);
+               *(struct sk_buff**)opt = skb;
+       }else{
+               AMAZON_TPE_DMSG("no memory for receiving atm frame!\n");
+               return NULL;
+       }
+       return skb->data;
+}
+
+
+
+
+/* Brief:      Allocate kernel memory for sending a datagram.
+ * Parameters
+ *     vcc     virtual connection
+ *     size    data buffer size
+ * Return:
+ *     NULL    fail
+ *     sk_buff a pointer to a sk_buff
+ * Description:
+ *  This function can allocate our own additional memory for AAL5S inbound
+ * header (8bytes). We have to replace the protocol default one (alloc_tx in /net/atm/common.c) 
+ * when we open the device.
+ * byte alignment is done is DMA driver.
+ */
+struct sk_buff *amazon_atm_alloc_tx(struct atm_vcc *vcc,unsigned int size)
+{
+       struct sk_buff *skb;
+
+       if (!dma_may_send(DMA_TX_CH0)){
+               AMAZON_TPE_EMSG("no DMA descriptor available!\n");
+               return NULL;
+       }
+       //AAL5 inbound header space + alignment extra buffer
+       size+=8+AAL5S_INBOUND_HEADER;
+
+        if (atomic_read(&vcc->tx_inuse) && !atm_may_send(vcc,size)) {
+                AMAZON_TPE_EMSG("Sorry tx_inuse = %u, size = %u, sndbuf = %u\n",
+                    atomic_read(&vcc->tx_inuse),size,vcc->sk->sndbuf);
+                return NULL;
+        }
+
+        skb = amazon_atm_alloc_buffer(size);
+       if (skb == NULL){
+               AMAZON_TPE_EMSG("no memory\n");
+               return NULL;
+       }
+       AMAZON_TPE_DMSG("dev_alloc_skb(%u) = %x\n", skb->len, (u32)skb);
+        AMAZON_TPE_DMSG("tx_inuse %u += %u\n",atomic_read(&vcc->tx_inuse),skb->truesize);
+        atomic_add(skb->truesize+ATM_PDU_OVHD,&vcc->tx_inuse);
+
+       //reserve for AAL5 inbound header
+       skb_reserve(skb,AAL5S_INBOUND_HEADER);
+        return skb;
+}
+
+
+/* Brief:      change per queue QSB setting according to vcc qos parameters
+ * Paramters:
+ *     vcc:    atm_vcc pointer 
+ *     qid:    CBM queue id (1~15)
+ * Return:
+  */
+static inline void set_qsb(struct atm_vcc *vcc, struct atm_qos *qos, int qid)
+{
+       qsb_qptl_t      qptl;
+       qsb_qvpt_t      qvpt;
+       u32 tmp=0;
+       unsigned int qsb_clk;
+       
+       qsb_clk = amazon_get_fpi_hz()>>1;
+        
+       AMAZON_TPE_EMSG("Class=%u MAX_PCR=%u PCR=%u MIN_PCR=%u SCR=%u MBS=%u CDV=%u\n"
+               ,qos->txtp.traffic_class
+               ,qos->txtp.max_pcr
+               ,qos->txtp.pcr
+               ,qos->txtp.min_pcr
+               ,qos->txtp.scr
+               ,qos->txtp.mbs
+               ,qos->txtp.cdv
+               );
+       
+       // PCR limiter
+       if (qos->txtp.max_pcr == 0){    
+               qptl.bit.tprs = 0;                  /* 0 disables the PCR limiter */
+       }else {
+               // peak cell rate will be slightly lower than requested (maximum rate / pcr)= (qsbclock/2^3 * timestep/4)/pcr
+               tmp = (( (qsb_clk * g_atm_dev.qsb.tstepc)>>5)/ qos->txtp.max_pcr ) + 1;
+               // check if an overfow occured
+               if (tmp > QSB_TP_TS_MAX) {
+                       AMAZON_TPE_EMSG("max_pcr is too small, max_pcr:%u tprs:%u\n",qos->txtp.max_pcr, tmp);
+                       qptl.bit.tprs = QSB_TP_TS_MAX;
+               }else{
+                       qptl.bit.tprs = tmp;
+               }
+       }
+       //WFQ
+       if (qos->txtp.traffic_class == ATM_CBR  || qos->txtp.traffic_class ==ATM_VBR_RT){
+               // real time queue gets weighted fair queueing bypass
+               qptl.bit.twfq  = 0;
+       }else if (qos->txtp.traffic_class ==ATM_VBR_NRT ||qos->txtp.traffic_class ==ATM_UBR_PLUS ){
+               // wfq calculation here are based on virtual cell rates, to reduce granularity for large rates
+               // wfq factor is maximum cell rate / garenteed cell rate.
+               //qptl.bit.twfq = g_atm_dev.qsb.min_cr * QSB_WFQ_NONUBR_MAX / qos->txtp.min_pcr;
+               if (qos->txtp.min_pcr == 0) {
+                       AMAZON_TPE_EMSG("<warning> MIN_PCR should not be zero\n");
+                       qptl.bit.twfq = QSB_WFQ_NONUBR_MAX;
+               }else{
+                       tmp = QSB_GCR_MIN * QSB_WFQ_NONUBR_MAX / qos->txtp.min_pcr;             
+                       if (tmp == 0 ){
+                               qptl.bit.twfq = 1;
+                       }else if (tmp > QSB_WFQ_NONUBR_MAX){
+                               AMAZON_TPE_EMSG("min_pcr is too small, min_pcr:%u twfq:%u\n",qos->txtp.min_pcr, tmp);
+                               qptl.bit.twfq = QSB_WFQ_NONUBR_MAX;
+                       }else{
+                               qptl.bit.twfq = tmp;    
+                       }
+               }
+       }else if (qos->txtp.traffic_class == ATM_UBR){
+               // ubr bypass, twfq set to maximum value
+               qptl.bit.twfq = QSB_WFQ_UBR_BYPASS;
+       }else{
+               //tx is diabled, treated as UBR
+               AMAZON_TPE_EMSG("<warning> unsupported traffic class %u \n", qos->txtp.traffic_class);
+               qos->txtp.traffic_class = ATM_UBR;
+               qptl.bit.twfq = QSB_WFQ_UBR_BYPASS;
+       }
+       
+       //SCR Leaky Bucket Shaper VBR.0/VBR.1
+       if (qos->txtp.traffic_class ==ATM_VBR_RT || qos->txtp.traffic_class ==ATM_VBR_NRT){
+               if (qos->txtp.scr == 0){
+                       //SCR == 0 disable the shaper
+                       qvpt.bit.ts = 0;
+                       qvpt.bit.taus = 0;
+               }else{
+                       //CLP
+                       if (vcc->atm_options&ATM_ATMOPT_CLP){
+                               //CLP1
+                               qptl.bit.vbr = 1;
+                       }else{
+                               //CLP0
+                               qptl.bit.vbr = 0;
+                       }
+                       //TS and TauS
+                       tmp = (( (qsb_clk * g_atm_dev.qsb.tstepc)>>5)/ qos->txtp.scr ) + 1;
+                       if (tmp > QSB_TP_TS_MAX) {
+                               AMAZON_TPE_EMSG("scr is too small, scr:%u ts:%u\n",qos->txtp.scr, tmp);
+                               qvpt.bit.ts = QSB_TP_TS_MAX;
+                       }else{
+                               qvpt.bit.ts = tmp;
+                       }
+                       tmp = (qos->txtp.mbs - 1)*(qvpt.bit.ts - qptl.bit.tprs)/64;
+                       if (tmp > QSB_TAUS_MAX){
+                               AMAZON_TPE_EMSG("mbs is too large, mbr:%u taus:%u\n",qos->txtp.mbs, tmp);
+                               qvpt.bit.taus = QSB_TAUS_MAX;
+                       }else if (tmp == 0){
+                               qvpt.bit.taus = 1;
+                       }else{
+                               qvpt.bit.taus = tmp;
+                       }
+               }
+       }else{
+               qvpt.w0 = 0;
+       }
+       //write the QSB Queue Parameter Table (QPT)
+       AMAZON_WRITE_REGISTER_L(QSB_QPT_SET_MASK,QSB_RTM_ADDR);
+       AMAZON_WRITE_REGISTER_L(qptl.w0, QSB_RTD_ADDR);
+       AMAZON_WRITE_REGISTER_L((QSB_TABLESEL_QPT<<QSB_TABLESEL_SHIFT)
+               | QSB_RAMAC_REG_LOW
+               | QSB_WRITE
+               | qid
+               ,QSB_RAMAC_ADDR);
+       //write the QSB Queue VBR Parameter Table (QVPT)
+       AMAZON_WRITE_REGISTER_L(QSB_QVPT_SET_MASK,QSB_RTM_ADDR);
+       AMAZON_WRITE_REGISTER_L(qvpt.w0, QSB_RTD_ADDR);
+       AMAZON_WRITE_REGISTER_L((QSB_TABLESEL_QVPT<<QSB_TABLESEL_SHIFT)
+               | QSB_RAMAC_REG_LOW
+               | QSB_WRITE
+               | qid
+               ,QSB_RAMAC_ADDR);       
+       AMAZON_TPE_EMSG("tprs:%u twfq:%u ts:%u taus:%u\n",qptl.bit.tprs,qptl.bit.twfq,qvpt.bit.ts,qvpt.bit.taus);
+}
+
+/* 
+ * Brief:      create/change CBM queue descriptor
+ * Parameter:  
+ *     vcc:    atm_vcc pointer 
+ *     qid:    CBM queue id (1~15)
+ */
+static inline void set_qd(struct atm_vcc *vcc, u32 qid)
+{
+       u32 tx_config=0,rx_config=0;
+       u32 itf = (u32) vcc->itf;
+       u32 dma_qos=0;
+       u8 * qd_addr=NULL;
+               
+       tx_config|=CBM_QD_W3_WM_EN|CBM_QD_W3_CLPt;
+       //RT: check if the connection is a real time connection
+       if (vcc->qos.txtp.traffic_class == ATM_CBR || vcc->qos.txtp.traffic_class == ATM_VBR_RT){
+               tx_config|= CBM_QD_W3_RT;
+       }else{
+               tx_config|= CBM_QD_W3_AAL5; //don't set the AAL5 flag if it is a RT service
+       }
+       rx_config = tx_config;
+       
+       if(vcc->qos.aal == ATM_AAL5){   
+               //QoS: DMA QoS according to the traffic class
+               switch (vcc->qos.txtp.traffic_class){
+                       case ATM_CBR: dma_qos = CBR_DMA_QOS;break;
+                       case ATM_VBR_RT: dma_qos = VBR_RT_DMA_QOS;break;
+                       case ATM_VBR_NRT: dma_qos = VBR_NRT_DMA_QOS;break;
+                       case ATM_UBR_PLUS: dma_qos = UBR_PLUS_DMA_QOS;break;
+                       case ATM_UBR: dma_qos = UBR_DMA_QOS;break;
+               }
+       
+               //TX: upstream, AAL5(EPD or PPD), NOINT, SBid
+               tx_config |= CBM_QD_W3_DIR_UP|CBM_QD_W3_INT_NOINT|(itf&CBM_QD_W3_SBID_MASK);
+               //RX: DMA QoS, downstream, no interrupt, AAL5(EPD, PPD), NO INT, HCR
+#ifdef AMAZON_TPE_SCR
+               rx_config |= dma_qos|CBM_QD_W3_DIR_DOWN|CBM_QD_W3_INT_EOF;
+#else          
+               rx_config |= dma_qos|CBM_QD_W3_DIR_DOWN|CBM_QD_W3_INT_NOINT|CBM_QD_W3_HCR;
+#endif         
+       }else {
+               //should be AAL0        
+               //upstream, NOINT, SBid
+               tx_config |= CBM_QD_W3_DIR_UP|CBM_QD_W3_INT_NOINT|(itf&CBM_QD_W3_SBID_MASK);
+               //RX: downstream, ACA interrupt, 
+               rx_config |= CBM_QD_W3_DIR_DOWN|CBM_QD_W3_INT_ACA;
+       }
+
+       //Threshold: maximum threshold for tx/rx queue, which is adjustable in steps of 64 cells
+       tx_config |=    ( (divide_by_64_round_up(tx_q_threshold)&0xffff)<<CBM_QD_W3_THRESHOLD_SHIFT) & CBM_QD_W3_THRESHOLD_MASK;
+       rx_config |=    ( (divide_by_64_round_up(rx_q_threshold)&0xffff)<<CBM_QD_W3_THRESHOLD_SHIFT) & CBM_QD_W3_THRESHOLD_MASK;
+       
+       qd_addr = (u8*) KSEG1ADDR((unsigned long)g_atm_dev.cbm.qd_addr);
+       //TX
+       AMAZON_WRITE_REGISTER_L(tx_config, (qd_addr+qid*CBM_QD_SIZE + 0xc));
+       AMAZON_WRITE_REGISTER_L(0, (qd_addr+qid*CBM_QD_SIZE + 0x8));
+       //RX
+       AMAZON_WRITE_REGISTER_L(rx_config, (qd_addr+(qid+CBM_RX_OFFSET)*CBM_QD_SIZE + 0xc));
+       AMAZON_WRITE_REGISTER_L(0, (qd_addr+(qid+CBM_RX_OFFSET)*CBM_QD_SIZE + 0x8));
+}
+/*
+ * Brief:      add HTU table entry
+ * Parameter:  
+ *     vpi.vci:
+ *     qid:    CBM queue id (DEST is qid + CBM_RX_OFFSET)
+ *     idx:    entry id (starting from zero to 14)
+ * Return:
+ *     0:      sucessful
+ *     EIO:    HTU table entry cannot be written
+ */
+
+inline int set_htu_entry(u8 vpi, u16 vci, u8 qid, u8 idx)
+{
+       int i = 0;
+       u32 tmp1=0;
+       while ((tmp1 = readl(HTU_RAMSTAT_ADDR))!=0 && i < 1024) i++;
+       if (i > 1024)
+       {
+               AMAZON_TPE_EMSG("timeout\n");
+               return -EIO;
+       }
+       // write address register,
+       AMAZON_WRITE_REGISTER_L(idx, HTU_RAMADDR_ADDR);
+       // configure transmit queue
+       tmp1 = vpi<<24|vci<<8;
+       tmp1|=  HTU_RAMDAT1_VCON        // valid connection the entry is not validated here !!!!!!!!!!!!!!!!
+               |HTU_RAMDAT1_VCI3       // vci3 -> oam queue
+               |HTU_RAMDAT1_VCI4       // vci4 -> oam queue
+               |HTU_RAMDAT1_VCI6       // vci6 -> rm queue
+               |HTU_RAMDAT1_PTI4       // pti4 -> oam queue
+               |HTU_RAMDAT1_PTI5;      // pti5 -> oam queue
+
+       // ramdat 1 (in params & oam handling)
+       AMAZON_WRITE_REGISTER_L( tmp1, HTU_RAMDAT1_ADDR);
+       // ramdat 2 (out params & oam handling)
+       tmp1 = ((qid+CBM_RX_OFFSET)&HTU_RAMDAT2_QID_MASK)
+               |HTU_RAMDAT2_PTI6
+               |HTU_RAMDAT2_PTI7
+               |HTU_RAMDAT2_F4U
+               |HTU_RAMDAT2_F5U
+               ;
+       AMAZON_WRITE_REGISTER_L( tmp1, HTU_RAMDAT2_ADDR);
+       wmb();
+       // write HTU entry
+       AMAZON_WRITE_REGISTER_L(HTU_RAMCMD_WR, HTU_RAMCMD_ADDR);
+       return 0;
+}
+/*
+ * Brief:      add HTU table entry
+ * Parameter:  
+ *     vcc:    atm_vcc pointer
+ *     qid:    CBM queue id
+ * Return:
+ *     0:      sucessful
+ *     EIO:    HTU table entry cannot be written
+ */
+inline static int set_htu(struct atm_vcc *vcc, u32 qid)
+{
+       return set_htu_entry(vcc->vpi, vcc->vci, qid, (qid - CBM_DEFAULT_Q_OFFSET));
+}
+
+/* 
+ * Brief:      allocate a queue
+ * Return:     
+ *             <=0     no available queues
+ *             >0      qid
+ */
+static int atm_allocate_q(short itf)
+{
+       int i;
+       u32 tmp1=0;
+       int qid=0;
+       amazon_atm_port_t * dev;
+       dev = &g_atm_dev.ports[itf];
+       //find start queue id for this interface
+       for (i=0; i< itf; i++)
+       {
+               qid+= g_atm_dev.ports[i].max_conn;
+       }
+       // apply default queue offset ( oam, free cell queue, others, rm )
+       qid += CBM_DEFAULT_Q_OFFSET;
+       tmp1 = qid;
+       // search for a free queue
+       while ( (qid<tmp1+dev->max_conn)
+               && ( g_atm_dev.queues[qid].free != 1)) {
+               qid++;;
+       }
+       // if none was found, send failure message and return
+       if ( tmp1+dev->max_conn == qid)
+       {
+               return -EFAULT;
+       }
+       return qid;
+       
+}
+/* Brief:      open a aal5 or aal0 connection
+ */
+static int atm_open(struct atm_vcc *vcc, push_back_t push)
+{
+       int err=0;
+       int qid=0;
+       amazon_atm_port_t * port = & g_atm_dev.ports[vcc->itf];
+       unsigned long flags;
+       /***************** check bandwidth ******************/
+       /* 511045:linmars change ATM_VBR_NRT to use scr instead of pcr */
+       if ((vcc->qos.txtp.traffic_class==ATM_CBR&&vcc->qos.txtp.max_pcr>port->tx_rem_cr)
+       ||(vcc->qos.txtp.traffic_class==ATM_VBR_RT&&vcc->qos.txtp.max_pcr>port->tx_rem_cr)
+       ||(vcc->qos.txtp.traffic_class==ATM_VBR_NRT&&vcc->qos.txtp.scr>port->tx_rem_cr) 
+       ||(vcc->qos.txtp.traffic_class==ATM_UBR_PLUS&&vcc->qos.txtp.min_pcr>port->tx_rem_cr)
+       ) {
+                AMAZON_TPE_EMSG("not enough bandwidth left (%u) cells per seconds \n",port->tx_rem_cr);
+                return -EINVAL;
+       }
+       if ( (qid = amazon_atm_find_vpivci(vcc->vpi, vcc->vci)) >0 ){
+               AMAZON_TPE_EMSG("vpi:%u vci:%u is alreay open on queue:%u\n", vcc->vpi, vcc->vci, qid);
+               return -EADDRINUSE;
+       }
+
+       /***************** allocate entry queueID for this port *****************/
+       if ( (qid=atm_allocate_q(vcc->itf)) <= 0){
+               AMAZON_TPE_EMSG("port: %u max:%u qid: %u\n", vcc->itf, port->max_conn, qid);
+               AMAZON_TPE_EMSG("no availabel connections for this port:%u\n",vcc->itf);
+               return -EINVAL;
+       }
+       /**************QSB parameters and CBM descriptors*************/
+       set_qsb(vcc, &vcc->qos, qid);
+       set_qd(vcc, qid);
+       mb();
+       err=set_htu(vcc,qid);
+       if (err){
+               AMAZON_TPE_EMSG("set htu entry fails %u\n",err);
+               return err;
+       }
+       /************set internal mapping*************/
+       local_irq_save(flags);
+       g_atm_dev.queues[qid].free = 0;
+       g_atm_dev.queues[qid].vcc = vcc;
+       g_atm_dev.queues[qid].push = push;
+       g_atm_dev.queues[qid+CBM_RX_OFFSET].free = 0;
+       g_atm_dev.queues[qid+CBM_RX_OFFSET].vcc = vcc;
+       g_atm_dev.queues[qid+CBM_RX_OFFSET].push = push;
+       /******************reserve bandwidth**********************/
+       if (vcc->qos.txtp.traffic_class == ATM_CBR){
+               //CBR, real time connection, reserve PCR
+               port->tx_cur_cr += vcc->qos.txtp.max_pcr;
+               port->tx_rem_cr -= vcc->qos.txtp.max_pcr;
+       }else if (vcc->qos.txtp.traffic_class == ATM_VBR_RT){
+               //VBR_RT, real time connection, reserve PCR
+               port->tx_cur_cr += vcc->qos.txtp.max_pcr;
+               port->tx_rem_cr -= vcc->qos.txtp.max_pcr;
+       }else if (vcc->qos.txtp.traffic_class == ATM_VBR_NRT){
+               //VBR_NRT, reserve SCR
+               port->tx_cur_cr += vcc->qos.txtp.pcr;
+               port->tx_rem_cr -= vcc->qos.txtp.pcr;
+       }else if (vcc->qos.txtp.traffic_class == ATM_UBR_PLUS){
+               //UBR_PLUS, reserve MCR
+               port->tx_cur_cr += vcc->qos.txtp.min_pcr;
+               port->tx_rem_cr -= vcc->qos.txtp.min_pcr;
+       }
+       local_irq_restore(flags);
+       return err;
+}
+/* Brief:      Open ATM connection
+ * Parameters:         atm_vcc - Pointer to VCC data structure
+ *             vpi     - VPI value for new connection
+ *             vci     - VCI value for new connection
+ *
+ * Return:     0       - sucessful
+ *             -ENOMEM - No memory available
+ *             -EINVAL - No bandwidth/queue/ or unsupported AAL type
+ * Description:
+ *     This function opens an ATM connection on a specific device/interface
+ *
+ */
+int    amazon_atm_open(struct atm_vcc *vcc,push_back_t push)
+{
+       int err=0;
+
+       AMAZON_TPE_DMSG("vpi %u vci %u  itf %u aal %u\n"
+               ,vcc->vpi
+               ,vcc->vci
+               ,vcc->itf
+               ,vcc->qos.aal
+               );
+               
+       AMAZON_TPE_DMSG("tx cl %u bw %u mtu %u\n"
+               ,vcc->qos.txtp.traffic_class
+               ,vcc->qos.txtp.max_pcr
+               ,vcc->qos.txtp.max_sdu
+               );
+       AMAZON_TPE_DMSG("rx cl %u bw %u mtu %u\n"
+               ,vcc->qos.rxtp.traffic_class
+               ,vcc->qos.rxtp.max_pcr
+               ,vcc->qos.rxtp.max_sdu
+               );
+       if (vcc->qos.aal == ATM_AAL5 || vcc->qos.aal == ATM_AAL0){
+               err = atm_open(vcc,push);
+       }else{
+               AMAZON_TPE_EMSG("unsupported aal type %u\n", vcc->qos.aal);
+               err = -EPROTONOSUPPORT;
+       };
+       if (err == 0 ){
+               //replace the default memory allocation function with our own
+               vcc->alloc_tx = amazon_atm_alloc_tx;
+               set_bit(ATM_VF_READY,&vcc->flags);
+       }
+       return err;
+}
+
+/* Brief:      Send ATM OAM cell
+ * Parameters:         atm_vcc - Pointer to VCC data structure
+ *             skb     - Pointer to sk_buff structure, that contains the data
+ * Return:     0               - sucessful
+ *             -ENOMEM         - No memory available
+ *             -EINVAL         - Not supported
+ * Description:
+ * This function sends a cell over and ATM connection
+ * We always release the skb
+ * TODO: flags handling (ATM_OF_IMMED, ATM_OF_INRATE)
+ */
+int    amazon_atm_send_oam(struct atm_vcc *vcc, void * cell, int flags)
+{
+       int err=0;
+       int qid=0;
+       struct amazon_atm_cell_header * cell_header;
+       // Get cell header
+       cell_header = (struct amazon_atm_cell_header*) cell;
+       if ((cell_header->bit.pti == ATM_PTI_SEGF5) || (cell_header->bit.pti == ATM_PTI_E2EF5)) {
+               qid = amazon_atm_find_vpivci( cell_header->bit.vpi, cell_header->bit.vci);
+       }else if (cell_header->bit.vci == 0x3 || cell_header->bit.vci == 0x4) {
+               //507281:tc.chen qid = amazon_atm_find_vpi((int) cell_header->bit.vpi);
+               // 507281:tc.chen start
+               u8 f4_vpi;
+               f4_vpi = cell_header->bit.vpi;
+               qid = amazon_atm_find_vpi(f4_vpi );
+               // 507281:tc.chen end
+       }else{
+               //non-OAM cells, always invalid
+               qid = -EINVAL;
+       }
+       if (qid == -EINVAL) {
+               err =  -EINVAL;
+               AMAZON_TPE_EMSG("not valid AAL0 packet\n");
+       }else{
+               //send the cell using swie
+#ifdef TPE_LOOPBACK
+               err = amazon_atm_swin(AMAZON_ATM_OAM_Q_ID, cell);
+#else          
+               err = amazon_atm_swin(qid, cell);
+#endif
+       }
+       //kfree(cell);
+       return err;
+}
+
+/* Brief:      Send AAL5 frame through DMA
+ * Parameters:         vpi     - virtual path id 
+ *             vci     - virtual circuit id
+ *             clp     - cell loss priority
+ *             qid     - CBM queue to be sent to
+ *             skb     - packet to be sent
+ * Return:     0               - sucessful
+ *             -ENOMEM         - No memory available
+ *             -EINVAL         - Not supported
+ * Description:
+ * This function sends a AAL5 frame over and ATM connection
+ *     1. make sure that the data is aligned to 4x32-bit boundary
+ *     2. provide the inbound data (CPCS-UU and CPI, not used here)
+ *     3. set CLPn
+ *     4. send the frame by DMA
+ *     5. release the buffer ???
+ ** use our own allocation alloc_tx
+ ** we make sure the alignment and additional memory
+ *** we always release the skb
+
+ */
+int amazon_atm_dma_tx(u8 vpi, u16 vci, u8 clp, u8 qid, struct sk_buff *skb) 
+{
+       int err=0,need_pop=1;
+       u32 * data=NULL;
+       int nwrite=0;
+       struct sk_buff *skb_tmp;
+       u32 len=skb->len;       
+
+       //AAL5S inbound header 8 bytes
+       if (skb->len > g_atm_dev.aal5.tx_max_sdu - AAL5S_INBOUND_HEADER) {
+               AMAZON_TPE_DMSG("tx_max_sdu:%u\n",g_atm_dev.aal5.tx_max_sdu); 
+               AMAZON_TPE_DMSG("skb too large [%u]!\n",skb->len);
+               err = -EMSGSIZE;
+               goto atm_dma_tx_error_exit;
+       }
+       
+       //Check the byte alignment requirement and header space
+       if ( ( ((u32)(skb->data)%16) !=AAL5S_INBOUND_HEADER)|| (skb_headroom(skb)<AAL5S_INBOUND_HEADER)){
+               //not aligned or no space for header, fall back to memcpy
+               skb_tmp = dev_alloc_skb(skb->len+16);
+               if (skb_tmp==NULL){
+                       err = - ENOMEM;                 
+                       goto atm_dma_tx_error_exit;     
+               }
+               alloc_align_16(skb_tmp);
+               g_atm_dev.aal5.cnt_cpy++;
+               skb_reserve(skb_tmp,AAL5S_INBOUND_HEADER);
+               memcpy(skb_put(skb_tmp,skb->len), skb->data, skb->len);
+               amazon_atm_free_tx_skb(skb);
+               need_pop=0;
+               skb = skb_tmp;
+       }
+       //Provide AAL5S inbound header
+       data = (u32 *)skb_push(skb,8);
+       data[0] = __be32_to_cpu(vpi<<20|vci<<4|clp);
+       data[1] = __be32_to_cpu(g_atm_dev.aal5.padding_byte<<8|qid);
+       
+       len = skb->len;
+
+       //send through DMA
+       AMAZON_TPE_DMSG("AAL5S header 0 %8x\n", data[0]);
+       AMAZON_TPE_DMSG("AAL5S header 0 %8x\n", data[1]);
+       AMAZON_TPE_DMSG("about to call dma_write len: %u\n", len);
+       nwrite=dma_device_write( &g_dma_dev,skb->data,len,skb);
+       if (nwrite != len) {
+               //DMA descriptors full
+//             AMAZON_TPE_EMSG("AAL5 packet drop due to DMA nwrite:%u skb->len:%u\n", nwrite,len);
+               AMAZON_TPE_DMSG("AAL5 packet drop due to DMA nwrite:%u skb->len:%u\n", nwrite,len);
+               err = -EAGAIN;
+               goto atm_dma_tx_drop_exit;
+       }
+       AMAZON_TPE_DMSG("just finish call dma_write\n");
+       //release in the "dma done" call-back
+       return 0;
+atm_dma_tx_error_exit:
+       g_atm_dev.mib_counter.tx_err++; 
+       queue_statics(qid, QS_ERR);
+       goto atm_dma_tx_exit;
+       
+atm_dma_tx_drop_exit:
+       g_atm_dev.mib_counter.tx_drop++;
+       queue_statics(qid, QS_SW_DROP);
+atm_dma_tx_exit:
+       if (need_pop){
+               amazon_atm_free_tx_skb(skb);
+       }else{
+               dev_kfree_skb_any(skb);
+       }
+       return err;
+}
+
+/* Brief:      Send AAL0/AAL5 packet
+ * Parameters:         atm_vcc - Pointer to VCC data structure
+ *             skb     - Pointer to sk_buff structure, that contains the data
+ * Return:     0               - sucessful
+ *             -ENOMEM         - No memory available
+ *             -EINVAL         - Not supported
+ * Description:
+ *     See amazon_atm_dma_tx
+ */
+int    amazon_atm_send(struct atm_vcc *vcc,struct sk_buff *skb)
+{
+       int qid=0;
+       u8 clp=0;
+        int err=0;
+       u32 wm=0;
+
+       if (vcc == NULL || skb == NULL){
+               AMAZON_TPE_EMSG("invalid parameter\n");
+               return -EINVAL;
+       }
+       ATM_SKB(skb)->vcc = vcc;
+       qid = amazon_atm_get_queue(vcc);
+       if (valid_qid(qid) != 1) {
+               AMAZON_TPE_EMSG("invalid vcc!\n");
+               err = -EINVAL;
+               goto atm_send_err_exit;
+       }
+       
+       //Send AAL0 using SWIN
+       if (vcc->qos.aal == ATM_AAL0){
+#ifdef  TPE_LOOPBACK
+               err=amazon_atm_swin((qid+CBM_RX_OFFSET), skb->data);    
+#else
+               err=amazon_atm_swin(qid, skb->data);
+#endif
+               if (err){
+                       goto atm_send_err_exit;
+               }       
+               goto atm_send_exit;
+       }
+       
+       //Should be AAl5
+       //MIB counter
+       g_atm_dev.mib_counter.tx++;
+       adsl_led_flash();//joelin adsl led
+       queue_statics(qid, QS_PKT);
+
+#ifdef AMAZON_CHECK_LINK
+       //check adsl link 
+       if (adsl_link_status == 0){
+               //link down
+               AMAZON_TPE_DMSG("ADSL link down, discarded!\n");
+               err=-EFAULT;
+               goto atm_send_drop_exit;
+       }
+#endif
+       clp = (vcc->atm_options&ATM_ATMOPT_CLP)?1:0;
+       //check watermark first
+       wm = readl(CBM_WMSTAT0_ADDR);
+       if (  (wm & (1<<qid))
+           ||( (vcc->qos.txtp.traffic_class != ATM_CBR
+                &&vcc->qos.txtp.traffic_class != ATM_VBR_RT) 
+               &(wm & (CBM_WM_NRT_MASK | (clp&CBM_WM_CLP1_MASK)) ))){
+               //wm hit: discard
+               AMAZON_TPE_DMSG("watermark hit, discarded!\n");
+               err=-EFAULT;
+               goto atm_send_drop_exit;
+       }
+#ifdef  TPE_LOOPBACK
+       return amazon_atm_dma_tx(vcc->vpi, vcc->vci,clp, (qid+CBM_RX_OFFSET),skb);
+#else  
+       return amazon_atm_dma_tx(vcc->vpi, vcc->vci,clp, qid,skb);
+#endif
+
+atm_send_exit: 
+       amazon_atm_free_tx_skb_vcc(vcc,skb);    
+       return 0;
+       
+atm_send_drop_exit:
+       g_atm_dev.mib_counter.tx_drop++;
+       queue_statics(qid,QS_SW_DROP);
+atm_send_err_exit:     
+       amazon_atm_free_tx_skb_vcc(vcc,skb);
+       return err;
+}
+
+/* Brief:      Return ATM port related MIB
+ * Parameter:  interface number
+        atm_cell_ifEntry_t
+ */
+int amazon_atm_cell_mib(atm_cell_ifEntry_t* to,u32 itf)
+{
+       g_atm_dev.mib_counter.htu_unp += readl(HTU_MIBCIUP);
+       to->ifInUnknownProtos = g_atm_dev.mib_counter.htu_unp;
+#ifdef AMAZON_TPE_READ_ARC
+       u32 reg_val=0;
+       meiDebugRead((AR_CELL0_ADDR+itf*4),&reg_val,1);
+       g_atm_dev.mib_counter.rx_cells += reg_val;
+       reg_val=0;
+       meiDebugWrite((AR_CELL0_ADDR+itf*4),&reg_val,1);
+       to->ifHCInOctets_h = (g_atm_dev.mib_counter.rx_cells * 53)>>32;
+       to->ifHCInOctets_l = (g_atm_dev.mib_counter.rx_cells * 53) & 0xffff;
+       
+       meiDebugRead((AT_CELL0_ADDR+itf*4),&reg_val,1);
+       g_atm_dev.mib_counter.tx_cells += reg_val;
+       reg_val=0;
+       meiDebugWrite((AT_CELL0_ADDR+itf*4),&reg_val,1);
+       to->ifHCOutOctets_h = (g_atm_dev.mib_counter.tx_cells * 53)>>32;
+       to->ifHCOutOctets_l = (g_atm_dev.mib_counter.rx_cells * 53) & 0xffff;
+       
+       meiDebugRead((AR_CD_CNT0_ADDR+itf*4),&reg_val,1);
+       g_atm_dev.mib_counter.rx_err_cells += reg_val;
+       reg_val=0;
+       meiDebugWrite((AR_CD_CNT0_ADDR+itf*4),&reg_val,1);
+       to->ifInErrors = g_atm_dev.mib_counter.rx_err_cells;
+       
+       to->ifOutErrors = 0;
+#else
+       to->ifHCInOctets_h = 0;
+       to->ifHCInOctets_l = 0;
+       to->ifHCOutOctets_h = 0;
+       to->ifHCOutOctets_l = 0;
+       to->ifInErrors = 0;
+       to->ifOutErrors = 0;
+#endif
+       return 0;
+}
+
+/* Brief:      Return ATM AAL5 related MIB
+ * Parameter:
+        atm_aal5_ifEntry_t
+ */
+int amazon_atm_aal5_mib(atm_aal5_ifEntry_t* to)
+{
+       u32 reg_l,reg_h;
+       //AAL5R received Octets from ATM
+       reg_l = readl(AAL5_RIOL_ADDR);
+       reg_h = readl(AAL5_RIOM_ADDR);
+       g_atm_dev.mib_counter.rx_cnt_h +=reg_h;
+       if (reg_l + g_atm_dev.mib_counter.rx_cnt_l < reg_l){
+               g_atm_dev.mib_counter.rx_cnt_h++;
+       }
+       
+       g_atm_dev.mib_counter.rx_cnt_l+= reg_l;
+       //AAL5S sent Octets to ATM
+       reg_l = readl(AAL5_SOOL_ADDR);
+       reg_h = readl(AAL5_SOOM_ADDR);
+       g_atm_dev.mib_counter.tx_cnt_h +=reg_h;
+       if (reg_l + g_atm_dev.mib_counter.tx_cnt_l < reg_l){
+               g_atm_dev.mib_counter.tx_cnt_h++;
+       }
+       g_atm_dev.mib_counter.tx_cnt_l+= reg_l;
+
+
+       g_atm_dev.mib_counter.tx_ppd += readl(CBM_AAL5ODIS_ADDR);
+       g_atm_dev.mib_counter.rx_drop += readl(CBM_AAL5IDIS_ADDR);
+       
+       //store 
+       to->ifHCInOctets_h = g_atm_dev.mib_counter.rx_cnt_h;
+       to->ifHCInOctets_l = g_atm_dev.mib_counter.rx_cnt_l;
+       to->ifHCOutOctets_h = g_atm_dev.mib_counter.tx_cnt_h;
+       to->ifHCOutOctets_l = g_atm_dev.mib_counter.tx_cnt_l;
+       to->ifOutDiscards = g_atm_dev.mib_counter.tx_drop;
+       to->ifInDiscards = g_atm_dev.mib_counter.rx_drop;
+
+       //Software provided counters
+       //packets passed to higher layer
+       to->ifInUcastPkts = g_atm_dev.mib_counter.rx;
+       //packets passed from higher layer
+       to->ifOutUcastPkts = g_atm_dev.mib_counter.tx;
+       //number of wrong downstream packets
+       to->ifInErrors = g_atm_dev.mib_counter.rx_err;
+       //number of wrong upstream packets
+       to->ifOutErros = g_atm_dev.mib_counter.tx_err;
+
+       return 0;
+}
+/* Brief:      Return ATM AAL5 VCC related MIB from internale use
+ * Parameter:
+ *     qid
+ *     atm_aal5_vcc_t
+ */
+static int __amazon_atm_vcc_mib(int qid, atm_aal5_vcc_t* to)
+{
+       //aal5VccCrcErrors
+       to->aal5VccCrcErrors = g_atm_dev.queues[qid].aal5VccCrcErrors;
+       to->aal5VccOverSizedSDUs =g_atm_dev.queues[qid].aal5VccOverSizedSDUs;
+       to->aal5VccSarTimeOuts = 0; //not supported yet
+       return 0;
+}
+/* Brief:      Return ATM AAL5 VCC related MIB from vpi/vci
+ * Parameter:  atm_vcc
+ *      atm_aal5_vcc_t
+ */
+int amazon_atm_vcc_mib_x(int vpi, int vci,atm_aal5_vcc_t* to)
+{
+       int qid=0;
+       int err=0;
+       qid =  amazon_atm_find_vpivci(vpi, vci);
+       if (qid >0 ){
+               err = __amazon_atm_vcc_mib(qid,to);
+       }else{
+               return -EINVAL;
+       }
+       return err;
+}
+
+
+/* Brief:      Return ATM AAL5 VCC related MIB
+ * Parameter:  atm_vcc
+ *      atm_aal5_vcc_t
+ */
+int amazon_atm_vcc_mib(struct atm_vcc *vcc,atm_aal5_vcc_t* to)
+{
+       int qid=0;
+       int err=0;
+       qid =  amazon_atm_get_queue(vcc);
+       if (qid >0 ){
+               err = __amazon_atm_vcc_mib(qid,to);
+       }else{
+               return -EINVAL;
+       }
+       return err;
+}
+
+/* Brief:      Close ATM connection
+ * Parameters:         atm_vcc - Pointer to VCC data structure
+ * Return:     no
+ * Description:
+ * This function closes the given ATM connection
+ */
+void   amazon_atm_close(struct atm_vcc *vcc){
+       int i;
+       int qid=0;
+       u32 tmp1;
+       u8 * qd_addr;
+       unsigned long flags;
+       if (vcc == NULL){
+               AMAZON_TPE_EMSG("invalid parameter. vcc is null\n");
+               return;
+       }
+       u32 itf = (u32) vcc->itf;
+       //release bandwidth
+       if (vcc->qos.txtp.traffic_class == ATM_CBR){
+               g_atm_dev.ports[itf].tx_rem_cr += vcc->qos.txtp.max_pcr;
+               g_atm_dev.ports[itf].tx_cur_cr -= vcc->qos.txtp.max_pcr;
+       }else if (vcc->qos.txtp.traffic_class == ATM_VBR_RT){
+               g_atm_dev.ports[itf].tx_rem_cr += vcc->qos.txtp.max_pcr;
+               g_atm_dev.ports[itf].tx_cur_cr -= vcc->qos.txtp.max_pcr;
+       }else if (vcc->qos.txtp.traffic_class == ATM_VBR_NRT){
+               g_atm_dev.ports[itf].tx_rem_cr += vcc->qos.txtp.pcr;
+               g_atm_dev.ports[itf].tx_cur_cr -= vcc->qos.txtp.pcr;
+       }else if (vcc->qos.txtp.traffic_class == ATM_UBR_PLUS){
+               g_atm_dev.ports[itf].tx_rem_cr += vcc->qos.txtp.min_pcr;
+               g_atm_dev.ports[itf].tx_cur_cr -= vcc->qos.txtp.min_pcr;
+       }
+
+       qid = amazon_atm_get_queue(vcc);
+       if (qid == -EINVAL){
+               AMAZON_TPE_EMSG("unknown vcc %u.%u.%u\n", vcc->itf, vcc->vpi, vcc->vci);
+               return;
+       }
+       local_irq_save(flags);
+       //Disable HTU entry
+       i=0;
+       while ((tmp1 = readl(HTU_RAMSTAT_ADDR))!=0 && i < HTU_RAM_ACCESS_MAX) i++;
+       if (i == HTU_RAM_ACCESS_MAX){
+               AMAZON_TPE_EMSG("HTU RAM ACCESS out of time\n");
+       }
+
+       // write address register
+       AMAZON_WRITE_REGISTER_L(qid - CBM_DEFAULT_Q_OFFSET, HTU_RAMADDR_ADDR);
+       // invalidate the connection
+       AMAZON_WRITE_REGISTER_L(0, HTU_RAMDAT1_ADDR);
+       // write command
+       AMAZON_WRITE_REGISTER_L(HTU_RAMCMD_WR,HTU_RAMCMD_ADDR);
+       
+       qd_addr = (u8 *) KSEG1ADDR((unsigned long)g_atm_dev.cbm.qd_addr);
+#ifdef AMAZON_ATM_DEBUG
+       tmp1 = readl(qd_addr+qid*CBM_QD_SIZE+0x8) & 0xffff;
+       AMAZON_TPE_DMSG("TX queue has %u cells \n", tmp1);
+       tmp1 = readl( qd_addr+(qid+CBM_RX_OFFSET)*CBM_QD_SIZE+0x08)&0xffff;
+       AMAZON_TPE_DMSG("RX queue has %u cells \n", tmp1);
+#endif 
+       // set threshold of txqueue to 0
+       tmp1 = readl(qd_addr+qid*CBM_QD_SIZE+0x0c);
+       tmp1&= (~ CBM_QD_W3_THRESHOLD_MASK);
+       AMAZON_WRITE_REGISTER_L(tmp1, (qd_addr+qid*CBM_QD_SIZE+0x0c));
+       // set threshold of rxqueue to 0
+       tmp1 = readl( qd_addr+(qid+CBM_RX_OFFSET)*CBM_QD_SIZE+0x0c);
+       tmp1&= (~ CBM_QD_W3_THRESHOLD_MASK);
+       AMAZON_WRITE_REGISTER_L(tmp1,(qd_addr+(qid+CBM_RX_OFFSET)*CBM_QD_SIZE+0x0c));
+
+       //clear internal mapping
+       amazon_atm_clear_vcc(qid);
+       amazon_atm_clear_vcc(qid+CBM_RX_OFFSET);
+
+       local_irq_restore(flags);
+}
+
+
+/* Brief:      initialize internal data structure
+ */
+static void atm_constructor(amazon_atm_dev_t * dev)
+{
+       int i;
+       memset(dev,0,sizeof(amazon_atm_dev_t));
+       atm_init_parameters(dev);
+       //internal: queue "free" flag
+       for(i=1;i<AMAZON_ATM_MAX_QUEUE_NUM;i++) {
+               //dev->queues[i].vcc=NULL;
+               dev->queues[i].free = 1;
+       }
+       for(i=0;i<AMAZON_ATM_PORT_NUM;i++){
+               dev->ports[i].tx_rem_cr = dev->ports[i].tx_max_cr;
+       }
+       //MIB
+       atomic_set(&dev->dma_tx_free_0,1); //initially there should be free descriptors
+}
+
+/* Brief:      return round up base-2 logarithm
+ */
+static inline int get_log_2(u32 value)
+{
+       int i=0,j=1;
+       while (i<11){
+               if (j>=value) break;
+               j=j<<1;
+               i++;
+       }
+       AMAZON_TPE_DMSG("round up base-2 logarithm of %u is %u\n", value, i);
+       return i;
+}
+
+/* Brief:      TPE hardware initialization
+ * Parameter:  specifiy the configurations of the hardware
+ */
+static inline int atm_init_hard(amazon_atm_dev_t * dev)
+{
+       int i;
+       u32 tmp1, tmp2, tmp3;
+       u8 * mem_addr=NULL;
+       u8 * qd_addr=NULL;
+       //PMU power on the module 1st
+       *(AMAZON_PMU_PWDCR) =   (*AMAZON_PMU_PWDCR) | (AMAZON_PMU_PWDCR_TPE);
+       //Reset the module
+       *(AMAZON_RST_REQ) = (* AMAZON_RST_REQ) | (AMAZON_RST_REQ_TPE);
+       mb();
+       mdelay(100);
+       *(AMAZON_RST_REQ) = (* AMAZON_RST_REQ) & (~(AMAZON_RST_REQ_TPE));
+       mb();
+       
+       unsigned long qsb_clk = amazon_get_fpi_hz()>>1;
+       /*********allocate & arrange memory for CBM *********/
+       if (dev->cbm.mem_addr == NULL){
+               dev->cbm.allocated = 1;
+               mem_addr = (u8 *)__get_free_pages(GFP_KERNEL, get_log_2(((CBM_CELL_SIZE * dev->cbm.free_cell_cnt) >>PAGE_SHIFT) + 1));
+               if (mem_addr != NULL){ 
+                       dev->cbm.mem_addr = mem_addr;
+               } else  {
+                       goto init_no_mem;
+               }
+       }
+       if (dev->cbm.qd_addr == NULL){
+#ifdef CONFIG_USE_VENUS
+               //to work around a bug, bit15 of QDOFF address should be 1,Aug4, 2004
+               //thus, we allocate 64k memory          
+               qd_addr = (u8 *)__get_free_pages(GFP_KERNEL, 4);
+               if (qd_addr != NULL) {
+                       dev->cbm.qd_addr_free = (u8*) (((unsigned long) qd_addr));
+                       dev->cbm.qd_addr = (u8*) (((unsigned long) qd_addr) | 0x8000);
+               }else{
+                       goto init_no_mem;
+               }
+#else  //CONFIG_USE_VENUS
+               qd_addr = (u8 *)kmalloc( CBM_QD_SIZE * AMAZON_ATM_MAX_QUEUE_NUM, GFP_KERNEL);
+               if (qd_addr != NULL) {
+                       dev->cbm.qd_addr = qd_addr;
+               }else {
+                       goto init_no_mem;
+               }
+#endif //CONFIG_USE_VENUS                      
+       }
+//#ifndef CONFIG_MIPS_UNCACHED
+       mem_addr = (u8 *)KSEG1ADDR((unsigned long)dev->cbm.mem_addr);
+       qd_addr = (u8 *)KSEG1ADDR((unsigned long)dev->cbm.qd_addr);
+//#endif
+       //CBM reset cell queue memory, 64 bytes / cell
+       memset_io(mem_addr, 0, CBM_CELL_SIZE * dev->cbm.free_cell_cnt);
+       //make a link list, last 4 bytes is pointer
+       for(i=1;i<dev->cbm.free_cell_cnt;i++){
+               AMAZON_WRITE_REGISTER_L(CPHYSADDR((mem_addr + CBM_CELL_SIZE * i)),(mem_addr + CBM_CELL_SIZE * (i-1) + 0x3c));
+       }
+       //reset queue descriptor
+       memset_io(qd_addr, 0, CBM_QD_SIZE * AMAZON_ATM_MAX_QUEUE_NUM);
+       //init word 0-2 of q0 (free cell list)
+       //address of last cell
+       AMAZON_WRITE_REGISTER_L(CPHYSADDR((mem_addr + CBM_CELL_SIZE * (dev->cbm.free_cell_cnt-1))), qd_addr);
+       //address of first cell
+       AMAZON_WRITE_REGISTER_L(CPHYSADDR((mem_addr)), (qd_addr + 4));
+       //no. of free cells
+       AMAZON_WRITE_REGISTER_L(dev->cbm.free_cell_cnt,(qd_addr + 8));
+       //init q descriptor for OAM receiving
+       AMAZON_WRITE_REGISTER_L((CBM_QD_W3_INT_ACA | (divide_by_64_round_up(oam_q_threshold)&0xff)<< CBM_QD_W3_THRESHOLD_SHIFT), (qd_addr + AMAZON_ATM_OAM_Q_ID * CBM_QD_SIZE + 0x0c));
+//     AMAZON_WRITE_REGISTER_L((CBM_QD_W3_INT_ACA | (u32)oam_q_threshold<< CBM_QD_W3_THRESHOLD_SHIFT), (qd_addr + AMAZON_ATM_OAM_Q_ID * CBM_QD_SIZE + 0x0c));
+       //config CBM
+       //set offset address and threshold
+       AMAZON_WRITE_REGISTER_L(CPHYSADDR(qd_addr), CBM_QDOFF_ADDR);
+       AMAZON_WRITE_REGISTER_L(((dev->cbm.nrt_thr&CBM_THR_MASK)|CBM_WM_3_1), CBM_NRTTHR_ADDR);
+       AMAZON_WRITE_REGISTER_L(((dev->cbm.clp0_thr&CBM_THR_MASK)|CBM_WM_3_1), CBM_CLP0THR_ADDR);
+       AMAZON_WRITE_REGISTER_L(((dev->cbm.clp1_thr&CBM_THR_MASK)|CBM_WM_3_1), CBM_CLP1THR_ADDR);
+       //config interrupts
+       AMAZON_WRITE_REGISTER_L( CBM_IMR_MASK & (~(CBM_IMR_ACA|CBM_IMR_Q0E|CBM_IMR_Q0I|CBM_IMR_RDE|CBM_IMR_OPF|CBM_IMR_ERR              
+#ifdef AMAZON_ATM_DEBUG        
+                                               |CBM_IMR_DISC|CBM_IMR_QFD|CBM_IMR_NFCA|CBM_IMR_CLP1TR|CBM_IMR_CLP0TR|CBM_IMR_NRTTR|CBM_IMR_QTR
+#endif 
+#ifdef AMAZON_TPE_SCR
+                                               |CBM_IMR_EF 
+#endif
+                                                       )), CBM_IMR0_ADDR);
+       AMAZON_WRITE_REGISTER_L(SRC_CLRR|SRC_TOS_MIPS | SRC_SRE_ENABLE | AMAZON_CBM_INT, CBM_SRC0_ADDR);
+       
+       //HTU
+       //RAM entry for number of possible connections per interface
+       tmp1 = dev->ports[0].max_conn?dev->ports[0].max_conn-1:0;
+       AMAZON_WRITE_REGISTER_L(tmp1, HTU_RX0_ADDR);
+       for(i=1;i<AMAZON_ATM_PORT_NUM;i++){
+               tmp1+=dev->ports[i].max_conn;
+               AMAZON_WRITE_REGISTER_L(tmp1, HTU_RX0_ADDR + 4 * i);
+       }
+       dev->cbm.max_q_off = tmp1+1;
+       //Queue ID for OAM/RM/Other cells
+       AMAZON_WRITE_REGISTER_L (AMAZON_ATM_OAM_Q_ID, HTU_DESTOAM_ADDR);
+       AMAZON_WRITE_REGISTER_L( AMAZON_ATM_RM_Q_ID, HTU_DESTRM_ADDR);
+       AMAZON_WRITE_REGISTER_L( AMAZON_ATM_OTHER_Q_ID, HTU_DESTOTHER_ADDR);
+       //Timeout
+       AMAZON_WRITE_REGISTER_L((u32) HTUTIMEOUT, HTU_TIMEOUT_ADDR);
+#ifdef AMAZON_ATM_DEBUG
+        AMAZON_WRITE_REGISTER_L((u32) HTU_ISR_MASK 
+                               &(~(HTU_ISR_NE|HTU_ISR_TORD|HTU_ISR_OTOC|HTU_ISR_ONEC|HTU_ISR_PNE|HTU_ISR_PT)), HTU_IMR0_ADDR);
+       AMAZON_WRITE_REGISTER_L(SRC_CLRR|SRC_TOS_MIPS|SRC_SRE_ENABLE|AMAZON_HTU_INT,HTU_SRC0_ADDR);
+#endif
+       //QSB
+       //global setting, TstepC, SBL, Tau
+       //Tau
+       AMAZON_WRITE_REGISTER_L(dev->qsb.tau, QSB_TAU_ADDR);
+       //SBL
+       AMAZON_WRITE_REGISTER_L(dev->qsb.sbl, QSB_SBL_ADDR);
+       //tstep
+       AMAZON_WRITE_REGISTER_L(dev->qsb.tstepc>>1, QSB_CONFIG_ADDR);
+
+       //port settting
+       for(i=0;i<AMAZON_ATM_PORT_NUM;i++){
+               if ( (dev->ports[i].enable) && (dev->ports[i].tx_max_cr!=0) ){
+                       tmp1 = ((qsb_clk * dev->qsb.tstepc) >>1) / dev->ports[i].tx_max_cr;
+                       tmp2 = tmp1 / 64;       //integer value of Tsb
+                       tmp3 = tmp1%64 + 1;     //fractional part of Tsb
+                       //carry over to integer part (?)
+                       if (tmp3 == 64) {
+                               tmp3 = 0;
+                               tmp2++;
+                       }
+                       if (tmp2 == 0){
+                               tmp2 = 1;
+                               tmp3 = 1;
+                       }
+                       //1. set mask 2. write value to data transfer register 3. start the transfer
+                       //SCT(FracRate)
+                       AMAZON_WRITE_REGISTER_L(QSB_SET_SCT_MASK, QSB_RTM_ADDR);
+                       AMAZON_WRITE_REGISTER_L(tmp3,QSB_RTD_ADDR);
+                       AMAZON_WRITE_REGISTER_L(((QSB_TABLESEL_SCT<<QSB_TABLESEL_SHIFT)|QSB_RAMAC_REG_LOW|QSB_WRITE|i),QSB_RAMAC_ADDR);
+                       //SPT(SBV + PN + IntRage)
+                       AMAZON_WRITE_REGISTER_L(QSB_SET_SPT_MASK, QSB_RTM_ADDR);
+                       AMAZON_WRITE_REGISTER_L(QSB_SPT_SBVALID|tmp2|(i<<16),QSB_RTD_ADDR);
+                       AMAZON_WRITE_REGISTER_L(((QSB_TABLESEL_SPT<<QSB_TABLESEL_SHIFT)|QSB_RAMAC_REG_LOW|QSB_WRITE|i),QSB_RAMAC_ADDR);
+
+
+               }
+       }
+       
+       //SWIE: Setup Service Request Control Registers to enable interrupts
+       AMAZON_WRITE_REGISTER_L(SRC_CLRR|SRC_TOS_MIPS | SRC_SRE_ENABLE | AMAZON_SWIE_INT, SWIE_ISRC_ADDR);
+       AMAZON_WRITE_REGISTER_L(SRC_CLRR|SRC_TOS_MIPS | SRC_SRE_ENABLE | AMAZON_SWIE_INT, SWIE_ESRC_ADDR);
+
+       wmb();
+#ifdef AMAZON_TPE_TEST_AAL5_INT
+       AMAZON_WRITE_REGISTER_L(AAL5R_ISR_FE,AAL5_RIMR0_ADDR);
+       AMAZON_WRITE_REGISTER_L(0, AAL5_SIMR0_ADDR);
+       AMAZON_WRITE_REGISTER_L(SRC_CLRR|SRC_TOS_MIPS | SRC_SRE_ENABLE | AMAZON_AAL5_INT,AAL5_SSRC0_ADDR);
+       AMAZON_WRITE_REGISTER_L(SRC_CLRR|SRC_TOS_MIPS | SRC_SRE_ENABLE | AMAZON_AAL5_INT,AAL5_RSRC0_ADDR);
+#endif //AMAZON_TPE_TEST_AAL5_INT
+
+       AMAZON_WRITE_REGISTER_L(dev->aal5.tx_max_sdu,AAL5_SMFL_ADDR);   
+       AMAZON_WRITE_REGISTER_L(dev->aal5.rx_max_sdu,AAL5_RMFL_ADDR);
+       AMAZON_WRITE_REGISTER_L(AAL5_SCMD_MODE_POLL // enable polling mode
+                                       |AAL5_SCMD_SS
+                                       |AAL5_SCMD_AR
+                                       ,AAL5_SCMD_ADDR);
+       //start CBM
+       AMAZON_WRITE_REGISTER_L(CBM_CFG_START,CBM_CFG_ADDR);
+       wmb();
+       return 0;
+init_no_mem:
+       if (mem_addr != NULL) free_pages((unsigned long)mem_addr,get_log_2(((CBM_CELL_SIZE * dev->cbm.free_cell_cnt) >>PAGE_SHIFT) + 1));
+       
+#ifdef CONFIG_USE_VENUS        
+       //to work around a bug, bit15 of QDOFF address should be 1
+       if (qd_addr != NULL) free_pages((unsigned long)qd_addr,4);
+#else //CONFIG_USE_VENUS
+       if (qd_addr != NULL) kfree(qd_addr);    
+#endif //CONFIG_USE_VENUS      
+       return -ENOMEM;
+}
+
+/*     
+ *     Brief:  Create entry in /proc for status information
+ */
+void atm_create_proc(void)
+{
+       create_proc_read_entry("amazon_atm", 0,NULL, amazon_atm_read_procmem,(void*)PROC_ATM);
+        create_proc_read_entry("amazon_atm_mib", 0,NULL, amazon_atm_read_procmem,(void*)PROC_MIB);
+        create_proc_read_entry("amazon_atm_vcc", 0,NULL, amazon_atm_read_procmem,(void*)PROC_VCC);
+#if 0  
+       create_proc_read_entry("amazon_atm_aal5", 0,NULL, amazon_atm_read_procmem,(void*)PROC_AAL5);
+        create_proc_read_entry("amazon_atm_cbm", 0,NULL, amazon_atm_read_procmem,(void*)PROC_CBM);
+        create_proc_read_entry("amazon_atm_htu", 0,NULL, amazon_atm_read_procmem,(void*)PROC_HTU);
+        create_proc_read_entry("amazon_atm_qsb", 0,NULL, amazon_atm_read_procmem,(void*)PROC_QSB);
+        create_proc_read_entry("amazon_atm_swie", 0,NULL, amazon_atm_read_procmem,(void*)PROC_SWIE);
+#endif
+}
+
+/*
+ *     Brief:  Delete entry in /proc for status information
+ */
+void atm_delete_proc(void)
+{
+       remove_proc_entry("amazon_atm", NULL);
+        remove_proc_entry("amazon_atm_mib", NULL);
+        remove_proc_entry("amazon_atm_vcc", NULL);
+#if 0  
+       remove_proc_entry("amazon_atm_aal5", NULL);
+        remove_proc_entry("amazon_atm_cbm", NULL);
+        remove_proc_entry("amazon_atm_htu", NULL);
+        remove_proc_entry("amazon_atm_qsb", NULL);
+        remove_proc_entry("amazon_atm_swie", NULL);
+#endif 
+}
+/* Brief:      Initialize ATM module
+ * Parameters:         no
+ * Return:     &g_atm_dev - sucessful
+ *             NULL    - fails: 
+ *                     1. invalid parameter
+ *                     2. No memory available
+ * Description:
+ *  This function configure the TPE components according to the input info,
+ *     -CBM
+ *     -HTU
+ *     -QSB
+ *     -AAL5
+ *
+ */
+amazon_atm_dev_t * amazon_atm_create(void)
+{
+       int i;
+       AMAZON_TPE_DMSG("atm_init\n");
+       /************initialize global data structure****************/
+       atm_constructor(&g_atm_dev);
+       /***********allocate kernel resources****************/
+       //bottom halfs for SWEX
+       swex_start_task.routine = amazon_atm_swex;
+       swex_start_task.data = NULL;
+       swex_complete_task.routine = amazon_atm_swex_push;
+       swex_complete_task.data = NULL;
+#ifdef AMAZON_TPE_SCR
+       a5r_task.routine = amazon_atm_a5r;
+       a5r_task.data = NULL;
+#endif //AMAZON_TPE_SCR
+       //SWIN semaphore
+       sema_init(&(g_atm_dev.swie.in_sem), 1);
+       //SWIE lock
+       clear_bit(SWIE_LOCK, &(g_atm_dev.swie.lock));
+       //SWIE wait queue
+       init_waitqueue_head(&(g_atm_dev.swie.sleep));
+       atm_create_proc();
+               
+       //register DMA
+       memset(&g_dma_dev,0,sizeof(struct dma_device_info));
+       strcpy(g_dma_dev.device_name,"TPE");
+       g_dma_dev.weight=1; 
+       g_dma_dev.num_tx_chan=2;
+       g_dma_dev.num_rx_chan=2; 
+       g_dma_dev.ack=1;
+       g_dma_dev.tx_burst_len=4;
+       g_dma_dev.rx_burst_len=4;
+       //DMA TX
+
+       for(i=0;i<1;i++){
+               g_dma_dev.tx_chan[i].weight=QOS_DEFAULT_WGT;
+                       g_dma_dev.tx_chan[i].desc_num=10;
+                       g_dma_dev.tx_chan[i].packet_size=g_atm_dev.aal5.tx_max_sdu + AAL5S_INBOUND_HEADER;
+                       g_dma_dev.tx_chan[i].control=1;
+       }
+       //DMA RX
+       for(i=0;i<2;i++){
+                       g_dma_dev.rx_chan[i].weight=QOS_DEFAULT_WGT;
+               /* BingTao's suggestion, change from 5->10 will prevent packet loss in NO_TX_INT mode */
+               g_dma_dev.rx_chan[i].desc_num=10;
+               g_dma_dev.rx_chan[i].packet_size=(g_atm_dev.aal5.rx_max_sdu + AAL5R_TRAILER_LEN+0x10f)&(~0xf);
+               g_dma_dev.rx_chan[i].control=1;
+       }
+       g_dma_dev.intr_handler=amazon_atm_dma_handler;
+       g_dma_dev.buffer_alloc=amazon_atm_alloc_rx;
+       g_dma_dev.buffer_free=amazon_atm_free_tx;
+       dma_device_register(&g_dma_dev);
+/***********intialize the atm hardware ****************/
+       if ( atm_init_hard(&g_atm_dev) != 0){
+               return NULL;
+       }
+       //start CBM
+       AMAZON_WRITE_REGISTER_L(CBM_CFG_START,CBM_CFG_ADDR);
+       wmb();
+
+       //Start HTU
+       AMAZON_WRITE_REGISTER_L(HTU_CFG_START ,HTU_CFG_ADDR);
+       wmb();
+
+
+       // Register interrupts for insertion and extraction
+       request_irq(AMAZON_SWIE_INT, amazon_atm_swie_isr, SA_INTERRUPT, "tpe_swie", NULL);
+       request_irq(AMAZON_CBM_INT, amazon_atm_cbm_isr, SA_INTERRUPT, "tpe_cbm", NULL);
+#ifdef AMAZON_ATM_DEBUG
+       request_irq(AMAZON_HTU_INT , amazon_atm_htu_isr, SA_INTERRUPT, "tpe_htu", NULL);
+#endif
+#ifdef AMAZON_TPE_TEST_AAL5_INT        
+       request_irq(AMAZON_AAL5_INT, amazon_atm_aal5_isr, SA_INTERRUPT, "tpe_aal5", NULL);
+#endif
+       return &g_atm_dev;
+}
+
+/* Brief:      clean up atm
+ * Parameters:         no
+ * Return:     no
+ * Description:
+ *  Disable the device.
+ */
+void   amazon_atm_cleanup(void){
+       int i;
+       clear_bit(SWIE_LOCK, &(g_atm_dev.swie.lock));
+       wake_up(&g_atm_dev.swie.sleep);
+       up(&g_atm_dev.swie.in_sem);
+       // diable SWIE interrupts
+       AMAZON_WRITE_REGISTER_L(0, SWIE_ISRC_ADDR);
+       AMAZON_WRITE_REGISTER_L(0, SWIE_ESRC_ADDR);
+       wmb();
+
+       // Disable schedulers ( including interrupts )-----------------------
+       for (i = 0; i < AMAZON_ATM_PORT_NUM; i++);
+       {
+               AMAZON_WRITE_REGISTER_L(QSB_SET_SPT_SBVALID_MASK, QSB_RTM_ADDR);
+               AMAZON_WRITE_REGISTER_L( 0 ,QSB_RTD_ADDR);
+               AMAZON_WRITE_REGISTER_L( (QSB_TABLESEL_SPT<<QSB_TABLESEL_SHIFT)
+                                               | QSB_RAMAC_REG_LOW
+                                               | QSB_WRITE
+                                               | i,
+                                               QSB_RAMAC_ADDR);
+       }
+       // disable QSB_Interrupts
+       AMAZON_WRITE_REGISTER_L( 0, QSB_IMR_ADDR);
+       AMAZON_WRITE_REGISTER_L( 0, QSB_SRC_ADDR);
+       // disable CBM interrupts
+       AMAZON_WRITE_REGISTER_L( 0      , CBM_IMR0_ADDR);
+       AMAZON_WRITE_REGISTER_L( 0 , CBM_SRC0_ADDR);
+       // set CBM start bit to 0
+       AMAZON_WRITE_REGISTER_L(0,CBM_CFG_ADDR);
+       // request hardware extraction of queue 0, wich should force the CBM
+       // to recognize that the start bit is not set
+       AMAZON_WRITE_REGISTER_L(CBM_HWEXPAR_PN_A5, CBM_HWEXPAR0_ADDR);
+       // write frame extraction command into the hw extract command register
+       AMAZON_WRITE_REGISTER_L(CBM_HWEXCMD_FE0, CBM_HWEXCMD_ADDR);
+       // disable htu
+       // disable all HTU interrupts
+       AMAZON_WRITE_REGISTER_L(0  ,HTU_IMR0_ADDR);
+       AMAZON_WRITE_REGISTER_L(0  ,HTU_SRC0_ADDR);
+       
+       if (g_atm_dev.cbm.allocated){
+               free_pages((unsigned long)g_atm_dev.cbm.mem_addr, get_log_2(((CBM_CELL_SIZE * g_atm_dev.cbm.free_cell_cnt) >>PAGE_SHIFT)+1));
+#ifdef CONFIG_USE_VENUS
+               //to work around a bug, bit15 of QDOFF address should be 1
+               free_pages((unsigned long)g_atm_dev.cbm.qd_addr_free,4);
+#else //CONFIG_USE_VENUS
+               kfree(g_atm_dev.cbm.qd_addr);
+#endif //CONFIG_USE_VENUS                                              
+       }
+       atm_delete_proc();
+       // free interrupts for insertion and extraction
+       dma_device_unregister(&g_dma_dev);
+       free_irq(AMAZON_SWIE_INT, NULL);
+       free_irq(AMAZON_CBM_INT, NULL);
+#ifdef AMAZON_ATM_DEBUG
+       free_irq(AMAZON_HTU_INT, NULL);
+#endif
+#ifdef AMAZON_TPE_TEST_AAL5_INT
+       free_irq(AMAZON_AAL5_INT, NULL);
+#endif
+
+}
+
+/************************ ATM network interface ***********************************************/
+/*     Brief:          getsockopt
+ */
+int amazon_atm_getsockopt(struct atm_vcc *vcc, int level, int optname, char *optval, int optlen)
+{
+       int err=0;
+       atm_aal5_vcc_t mib_vcc;
+       AMAZON_TPE_DMSG("1\n");
+       switch (optname){
+               case    SO_AMAZON_ATM_MIB_VCC:
+                       AMAZON_TPE_DMSG("2\n");
+                       err = amazon_atm_vcc_mib(vcc, &mib_vcc);
+                       AMAZON_TPE_DMSG("%u\n",mib_vcc.aal5VccCrcErrors);
+                        err = copy_to_user((void *)optval,&mib_vcc, sizeof(mib_vcc));
+                        AMAZON_TPE_DMSG("err %u\n",err);
+                        break;
+                default:
+                       return -EFAULT;
+       }
+       return err;
+}
+
+/*     Brief:          IOCTL
+ */
+
+int amazon_atm_ioctl(struct atm_dev *dev,unsigned int cmd,void *arg)
+{
+       int     err=0;
+       //MIB
+       atm_cell_ifEntry_t mib_cell;
+       atm_aal5_ifEntry_t mib_aal5;
+       atm_aal5_vcc_x_t mib_vcc;
+       if (_IOC_TYPE(cmd) != AMAZON_ATM_IOC_MAGIC) return -ENOTTY;
+       if (_IOC_NR(cmd) > AMAZON_ATM_IOC_MAXNR) return -ENOTTY;
+
+       if (_IOC_DIR(cmd) & _IOC_READ)
+               err = !access_ok(VERIFY_WRITE, (void *)arg, _IOC_SIZE(cmd));
+       else if (_IOC_DIR(cmd) & _IOC_WRITE)
+               err =  !access_ok(VERIFY_READ, (void *)arg, _IOC_SIZE(cmd));
+       if (err) {
+               AMAZON_TPE_EMSG("acess verification fails \n");
+               return -EFAULT;
+       }
+       switch(cmd) {
+               case AMAZON_ATM_MIB_CELL:
+                       err = amazon_atm_cell_mib(&mib_cell,(u32)arg);
+                       if (err==0){
+                               err = __copy_to_user((void *)arg,&mib_cell,sizeof(mib_cell));
+                       }else{
+                               AMAZON_TPE_EMSG("cannot get MIB ATM_CELL\n");
+                       }
+                       break;
+               case AMAZON_ATM_MIB_AAL5:
+                       err = amazon_atm_aal5_mib(&mib_aal5);
+                       if (err==0){
+                               err=__copy_to_user(arg, &mib_aal5, sizeof(mib_aal5));
+                       }else{
+                               AMAZON_TPE_EMSG("cannot get MIB ATM_AAL5\n");
+                       }
+                       break;
+               case AMAZON_ATM_MIB_VCC:
+                       err=__copy_from_user(&mib_vcc,arg, sizeof(mib_vcc));
+                       AMAZON_TPE_DMSG("return of copy_from_user %x\n",err);
+                       err = amazon_atm_vcc_mib_x(mib_vcc.vpi, mib_vcc.vci, &(mib_vcc.mib_vcc));
+                       if (err==0){
+                               err=__copy_to_user(arg, &mib_vcc, sizeof(mib_vcc));     
+                       }else{
+                               AMAZON_TPE_EMSG("cannot get MIB ATM_VCC\n");
+                       }
+                               
+               default:
+                       return -ENOTTY;
+       }
+       return err;
+}
+/*     Brief:  return a link list of OAM related time stamp info
+ *     Parameter:      none
+ *     Return: 
+               a link list of "struct oam_last_activity" data
+ *     Description:
+               Each time, a F4/F5 cell or AAL5 packet is received, the time stamp is updated.
+               Through this call, u get a list of this time stamp for all active connection.
+               Please note that u have read-only access.
+ */
+const struct oam_last_activity* get_oam_time_stamp()
+{
+       int i,j;
+       for(i=CBM_DEFAULT_Q_OFFSET+CBM_RX_OFFSET,j=0;i<CBM_RX_OFFSET+CBM_DEFAULT_Q_OFFSET+AMAZON_ATM_MAX_VCC_NUM;i++){
+               if (g_atm_dev.queues[i].free != 1 && g_atm_dev.queues[i].vcc != NULL){
+                       //active connection
+                       if (j !=0 ){
+                               g_oam_time_stamp[j-1].next = &g_oam_time_stamp[j];
+                       }
+                       g_oam_time_stamp[j].vpi = g_atm_dev.queues[i].vcc->vpi;
+                       g_oam_time_stamp[j].vci = g_atm_dev.queues[i].vcc->vci;
+                       g_oam_time_stamp[j].stamp = g_atm_dev.queues[i].access_time;
+                       g_oam_time_stamp[j].next = NULL;
+                       j++;
+               }
+       }
+       if (j==0) {
+               return NULL;
+       }else{
+               return g_oam_time_stamp;
+       }
+}
+
+
+/*     Brief:  call back routine for rx
+ *     Parameter:
+ *             vcc atm_vcc pointer
+ *             skb     data if no error
+               err     error flag, 0: no error, 1:error
+ *     Return: 
+ *             0       
+ *             <>0     cannot push up
+ *     Description:
+ *             release the packet if cannot push up
+ */
+static int amazon_atm_net_push(struct atm_vcc *vcc,struct sk_buff *skb, int err)
+{
+       if (err){
+               if (vcc && vcc->stats) {
+                       atomic_inc(&vcc->stats->rx_err);
+               }
+       }else{  
+               ATM_SKB(skb)->vcc = vcc;
+       
+               if (!atm_charge(vcc, skb->truesize)){
+                       //no space this vcc
+                       AMAZON_TPE_EMSG("no space for this vcc\n");
+                       dev_kfree_skb_any(skb);
+                       return -ENOMEM;
+               }
+               atomic_inc(&vcc->stats->rx);
+               AMAZON_TPE_DMSG("push to vcc\n");
+               vcc->push(vcc,skb);
+       }
+       return 0;
+}
+int    amazon_atm_net_send_oam(struct atm_vcc*vcc, void *cell, int flags)
+{
+       return amazon_atm_send_oam(vcc,cell,flags);
+}
+
+int    amazon_atm_net_send(struct atm_vcc *vcc,struct sk_buff *skb)
+{
+       int err=0;
+       if (vcc->qos.aal == ATM_AAL0 || vcc->qos.aal == ATM_AAL5) {
+               err=amazon_atm_send(vcc,skb);
+       }else{
+               //not supported
+               err =  -EPROTONOSUPPORT;
+       }
+       if (err){
+               atomic_inc(&vcc->stats->tx_err);
+       }else{
+               atomic_inc(&vcc->stats->tx);
+       }
+       AMAZON_TPE_DMSG("sent, tx_inuse:%u\n", atomic_read(&vcc->tx_inuse));
+       return err;
+}
+
+int    amazon_atm_net_open(struct atm_vcc *vcc,short vpi, int vci)
+{
+       vcc->itf = (int)  vcc->dev->dev_data;
+       vcc->vpi = vpi;
+       vcc->vci = vci;
+       return(amazon_atm_open(vcc,amazon_atm_net_push));
+}
+
+static int amazon_atm_change_qos(struct atm_vcc *vcc, struct atm_qos *qos, int flgs)
+{
+       int qid;
+       
+       if (vcc == NULL || qos == NULL){
+               AMAZON_TPE_EMSG("invalid parameters\n");
+               return -EINVAL;
+       }
+       qid = amazon_atm_get_queue(vcc);
+       if (valid_qid(qid) != 1) {
+               AMAZON_TPE_EMSG("no vcc connection opened\n");
+               return -EINVAL;
+       }
+       set_qsb(vcc,qos,qid);
+       return 0;
+}
+
+static struct atmdev_ops amazon_atm_ops = {
+   open:       amazon_atm_net_open,
+   close:      amazon_atm_close,
+   ioctl:      amazon_atm_ioctl,
+   send:       amazon_atm_net_send,
+   send_oam:   amazon_atm_net_send_oam,
+//   getsockopt:       amazon_atm_getsockopt,
+   change_qos: amazon_atm_change_qos,
+//   proc_read:        amazon_atm_proc_read,
+   owner:      THIS_MODULE,
+};                             // ATM device callback functions
+
+/*
+ * brief "/proc" function
+ */
+int amazon_atm_read_procmem(char *buf, char **start, off_t offset,int count, int *eof, void *data)
+{
+       int buf_off=0;  /* for buf */
+       int i=0,j=0;
+       int type= (u32)data;//which module
+       atm_aal5_ifEntry_t mib_aal5;
+       atm_cell_ifEntry_t mib_cell;
+       atm_aal5_vcc_t mib_vcc;
+       switch(type){
+               case PROC_MIB:
+                       //MIB counter
+                       amazon_atm_aal5_mib(&mib_aal5);
+                       //TX:
+                       buf_off+=sprintf(buf+buf_off,"\n============= AAL5 Upstream =========\n");
+                       buf_off+=sprintf(buf+buf_off,"received %u (pkts) from upper layer\n", mib_aal5.ifOutUcastPkts);
+                       buf_off+=sprintf(buf+buf_off,"errors: %u (pkts)\n",mib_aal5.ifOutErros);
+                       buf_off+=sprintf(buf+buf_off,"discards: %u (ptks)\n", mib_aal5.ifOutDiscards);
+                       buf_off+=sprintf(buf+buf_off,"transmitted: %x-%x (bytes) \n",
+                                       mib_aal5.ifHCOutOctets_h, mib_aal5.ifHCOutOctets_l);
+                       //RX:
+                       buf_off+=sprintf(buf+buf_off,"\n============= AAL5 Downstream =========\n");
+                       buf_off+=sprintf(buf+buf_off,"received %x-%x (bytes)\n",
+                                       mib_aal5.ifHCInOctets_h,mib_aal5.ifHCInOctets_l);
+                       buf_off+=sprintf(buf+buf_off,"discards: %u (ptks)\n",mib_aal5.ifInDiscards);
+                       buf_off+=sprintf(buf+buf_off,"errors: %u (ptks)\n",mib_aal5.ifInErrors);
+                       buf_off+=sprintf(buf+buf_off,"passed %u (ptks) to upper layer\n",mib_aal5.ifInUcastPkts);
+                       
+                       //Cell level
+                       buf_off+=sprintf(buf+buf_off,"\n============= ATM Cell =========\n");
+                       amazon_atm_cell_mib(&mib_cell,0);
+#ifdef AMAZON_TPE_READ_ARC                     
+                       buf_off+=sprintf(buf+buf_off,"Port 0: downstream received: %x-%x (bytes)\n",mib_cell.ifHCInOctets_h,mib_cell.ifHCInOctets_l);
+                       buf_off+=sprintf(buf+buf_off,"Port 0: upstream transmitted: %x-%x (bytes)\n",mib_cell.ifHCOutOctets_h,mib_cell.ifHCOutOctets_l);
+                       buf_off+=sprintf(buf+buf_off,"Port 0: downstream errors: %u (cells)\n",mib_cell.ifInErrors);
+                       amazon_atm_cell_mib(&mib_cell,1);
+                       buf_off+=sprintf(buf+buf_off,"Port 1: downstream received: %x-%x (bytes)\n",mib_cell.ifHCInOctets_h,mib_cell.ifHCInOctets_l);
+                       buf_off+=sprintf(buf+buf_off,"Port 1: upstream transmitted: %x-%x (bytes)\n",mib_cell.ifHCOutOctets_h,mib_cell.ifHCOutOctets_l);
+                       buf_off+=sprintf(buf+buf_off,"Port 1: downstream errors: %u (cells)\n",mib_cell.ifInErrors);
+#endif
+                       buf_off+=sprintf(buf+buf_off,"HTU discards: %u (cells)\n",mib_cell.ifInUnknownProtos);
+                       
+                       buf_off+=sprintf(buf+buf_off,"\n====== Specials =====\n");
+                       buf_off+=sprintf(buf+buf_off,"AAL5S PPD: %u (cells)\n",g_atm_dev.mib_counter.tx_ppd);
+#ifdef AMAZON_TPE_SCR
+                       buf_off+=sprintf(buf+buf_off,"Reassembly wait: %u \n",g_a5r_wait);
+#endif
+                       break;
+               case PROC_ATM:
+                       //Interface (Port)
+                       buf_off+=sprintf(buf+buf_off,"[Interfaces]\n");
+                       for(i=0;i<AMAZON_ATM_PORT_NUM;i++){
+                               if (g_atm_dev.ports[i].enable==0){
+                                       buf_off+=sprintf(buf+buf_off,"\tport[%u] not in use\n",i);
+                               }else{
+                                       buf_off+=sprintf(buf+buf_off,"\tport[%u]\n\t\tmax_conn=%u\n"
+                                                                       ,i
+                                                                       ,g_atm_dev.ports[i].max_conn
+                                                                       );
+                                       buf_off+=sprintf(buf+buf_off,"\t\ttx_max=%u\n\t\trem=%u\n\t\tcur=%u\n"
+                                                                       ,g_atm_dev.ports[i].tx_max_cr
+                                                                       ,g_atm_dev.ports[i].tx_rem_cr
+                                                                       ,g_atm_dev.ports[i].tx_cur_cr
+                                                                       );
+                               }
+
+                       }
+                       //Units Info
+                       //AAL5
+                       buf_off+=sprintf(buf+buf_off,"[AAL5]\n\tpad=%c(%x)\n\trx_mtu=%u\n\ttx_mtu=%u\n"
+                                       ,g_atm_dev.aal5.padding_byte
+                                       ,g_atm_dev.aal5.padding_byte
+                                       ,g_atm_dev.aal5.rx_max_sdu
+                                       ,g_atm_dev.aal5.tx_max_sdu
+                                       );
+                       //CBM
+                       buf_off+=sprintf(buf+buf_off,
+                               "[CBM]\n\tnrt_thr=%u\n\tclp0_thr=%u\n\tclp1_thr=%u\n\ttx_q_threshold=%u\n\trx_q_threshold=%u\n\toam_q_threshold=%u\n\tfree_cell_cnt=%u\n"
+                                       ,g_atm_dev.cbm.nrt_thr
+                                       ,g_atm_dev.cbm.clp0_thr
+                                       ,g_atm_dev.cbm.clp1_thr
+                                       ,tx_q_threshold
+                                       ,rx_q_threshold
+                                       ,oam_q_threshold
+                                       ,g_atm_dev.cbm.free_cell_cnt
+                                       );
+                       //QSB
+                       buf_off+=sprintf(buf+buf_off,"[QSB]\n\ttau=%u\n\ttstepc=%u\n\tsbl=%u\n"
+                                       ,g_atm_dev.qsb.tau
+                                       ,g_atm_dev.qsb.tstepc
+                                       ,g_atm_dev.qsb.sbl
+                                       );
+                       buf_off+=sprintf(buf+buf_off,"[Debugging]\n\taal5_need_copy=%u\n",g_atm_dev.aal5.cnt_cpy);
+                       break;
+               case PROC_VCC:
+                       for(i=CBM_DEFAULT_Q_OFFSET,j=0;i<g_atm_dev.cbm.max_q_off+CBM_DEFAULT_Q_OFFSET;i++){
+                               if (g_atm_dev.queues[i].free!=1){
+                                       buf_off+=sprintf(buf+buf_off,"vcc[%u]\n\tvpi=%u vci=%u itf=%u qid=%u access_time=%u.%u\n"
+                                                                       ,j++
+                                                                       ,g_atm_dev.queues[i].vcc->vpi
+                                                                       ,g_atm_dev.queues[i].vcc->vci
+                                                                       ,g_atm_dev.queues[i].vcc->itf
+                                                                       ,i
+                                                                       ,(u32)g_atm_dev.queues[i+CBM_RX_OFFSET].access_time.tv_sec
+                                                                       ,(u32)g_atm_dev.queues[i+CBM_RX_OFFSET].access_time.tv_usec
+                                                                       );
+                                       buf_off+=sprintf(buf+buf_off,"\tqos_tx class=%u max_pcr=%u pcr=%u min_pcr=%u scr=%u mbs=%u cdv=%u\n"
+                                                                       ,g_atm_dev.queues[i].vcc->qos.txtp.traffic_class
+                                                                       ,g_atm_dev.queues[i].vcc->qos.txtp.max_pcr
+                                                                       ,g_atm_dev.queues[i].vcc->qos.txtp.pcr
+                                                                       ,g_atm_dev.queues[i].vcc->qos.txtp.min_pcr
+                                                                       ,g_atm_dev.queues[i].vcc->qos.txtp.scr
+                                                                       ,g_atm_dev.queues[i].vcc->qos.txtp.mbs
+                                                                       ,g_atm_dev.queues[i].vcc->qos.txtp.cdv
+                                                                       );
+                                       buf_off+=sprintf(buf+buf_off,"\tqos_rx class=%u max_pcr=%u pcr=%u min_pcr=%u scr=%u mbs=%u cdv=%u\n"
+                                                                       ,g_atm_dev.queues[i].vcc->qos.rxtp.traffic_class
+                                                                       ,g_atm_dev.queues[i].vcc->qos.rxtp.max_pcr
+                                                                       ,g_atm_dev.queues[i].vcc->qos.rxtp.pcr
+                                                                       ,g_atm_dev.queues[i].vcc->qos.rxtp.min_pcr
+                                                                       ,g_atm_dev.queues[i].vcc->qos.rxtp.scr
+                                                                       ,g_atm_dev.queues[i].vcc->qos.rxtp.mbs
+                                                                       ,g_atm_dev.queues[i].vcc->qos.rxtp.cdv
+                                                                       );
+                                       __amazon_atm_vcc_mib((i+CBM_RX_OFFSET),&mib_vcc);
+                                       buf_off+=sprintf(buf+buf_off,"\tCRC error=%u\n", mib_vcc.aal5VccCrcErrors);
+                                       buf_off+=sprintf(buf+buf_off,"\toversized packet=%u\n", mib_vcc.aal5VccOverSizedSDUs);
+#ifdef         AMAZON_ATM_DEBUG
+                                       if ( valid_qid(i+CBM_RX_OFFSET)){
+                                       buf_off+=sprintf(buf+buf_off,"\tdownstream statics\n" );
+                                       buf_off+=sprintf(buf+buf_off,"\t\tpackets=%u\n",g_atm_dev.queues[i+CBM_RX_OFFSET].qs[QS_PKT]);
+                                       buf_off+=sprintf(buf+buf_off,"\t\terr_packets=%u\n",g_atm_dev.queues[i+CBM_RX_OFFSET].qs[QS_ERR] );
+                                       buf_off+=sprintf(buf+buf_off,"\t\tsw_dropped=%u\n",g_atm_dev.queues[i+CBM_RX_OFFSET].qs[QS_SW_DROP] );
+                                       }
+
+                                       buf_off+=sprintf(buf+buf_off,"\tupstream statics\n" );
+                                       buf_off+=sprintf(buf+buf_off,"\t\tpackets=%u\n",g_atm_dev.queues[i].qs[QS_PKT]);
+                                       buf_off+=sprintf(buf+buf_off,"\t\terr_packets=%u\n",g_atm_dev.queues[i].qs[QS_ERR] );
+                                       buf_off+=sprintf(buf+buf_off,"\t\thw_dropped=%u\n",g_atm_dev.queues[i].qs[QS_HW_DROP] );
+                                       buf_off+=sprintf(buf+buf_off,"\t\tsw_dropped=%u\n",g_atm_dev.queues[i].qs[QS_SW_DROP] );
+
+#endif                                 
+       
+                               }
+
+                       }
+                       break;
+               default:
+                       break;
+       }
+       if(buf_off>0)   *eof = 1;
+       return buf_off;
+}
+
+#ifdef AMAZON_TPE_AAL5_RECOVERY
+extern int (*tpe_reset)(void);
+extern int (*tpe_start)(void);
+extern int (*tpe_inject)(void);
+/*     Brief:          Reset TPE hardware
+ *     Description
+ *             This is a wordaround for AAL5 bug. It tries to reset TPE.
+ *      take care of software
+ *      setup all previous connection
+ */
+int amazon_tpe_reset(void)
+{
+       struct atm_vcc * vcc;   
+       int err=0;
+       int i;
+       u8 * qd_addr;
+       u32 reg_l, reg_h;
+       unsigned int a_cfg_value=0;
+       unsigned int a_cfg_old_value=0;
+       atm_aal5_ifEntry_t mib_aal5;
+       atm_cell_ifEntry_t mib_cell;
+       
+       //make sure all cells transmitting out first
+       //Segmentation done
+       amazon_atm_aal5_mib(&mib_aal5);
+       reg_l = g_atm_dev.mib_counter.tx_cnt_l;
+       reg_h = g_atm_dev.mib_counter.tx_cnt_h;
+       while(1){
+               mdelay(10);
+               amazon_atm_aal5_mib(&mib_aal5);
+               if( (reg_l == g_atm_dev.mib_counter.tx_cnt_l) && (reg_h == g_atm_dev.mib_counter.tx_cnt_h) ){
+                       break;
+               }
+               AMAZON_TPE_DMSG("AAL5 Segmentation still in progress!\n");
+               reg_l = g_atm_dev.mib_counter.tx_cnt_l;
+               reg_h = g_atm_dev.mib_counter.tx_cnt_h;
+       }
+       //QSB done
+       qd_addr = (u8 *) KSEG1ADDR((unsigned long)g_atm_dev.cbm.qd_addr);
+       for (i=1;i<15;i++){
+               while ( (err=readl(qd_addr+i*CBM_QD_SIZE+0x8)&0xffff) !=0  ){
+                       mdelay(20);
+                       AMAZON_TPE_DMSG("queue %u not empty (%u)\n",i,err);
+               }
+       }
+       //insurance for interfaces between Aware and CARB
+       mdelay(100);
+       amazon_atm_cell_mib(&mib_cell,0);
+       amazon_atm_cell_mib(&mib_cell,1);
+       amazon_atm_aal5_mib(&mib_aal5);
+       
+       mb();
+       while ( (AMAZON_READ_REGISTER_L(AR_CELLRDY_BC0) != 0 ) || (AMAZON_READ_REGISTER_L(AR_CELLRDY_BC0) != 0 )  ){
+               AMAZON_TPE_EMSG("\nwaiting for AWARE");
+               AMAZON_TPE_EMSG(" BC0 %u ", AMAZON_READ_REGISTER_L(AR_CELLRDY_BC0));
+               AMAZON_TPE_EMSG(" BC1 %u ", AMAZON_READ_REGISTER_L(AR_CELLRDY_BC1));
+               AMAZON_TPE_EMSG("\n");
+               mdelay(1);
+       }
+       // disable AAI module
+       meiDebugRead(A_CFG_ADDR,&a_cfg_value,1);        
+       a_cfg_old_value=a_cfg_value;
+       a_cfg_value &= (~(0x2800));
+       meiDebugWrite(A_CFG_ADDR,&a_cfg_value,1);       
+       //clear buffer
+       a_cfg_value = 0x1;
+       meiDebugWrite(AR_CB0_STATUS_ADDR,&a_cfg_value,1);       
+       meiDebugWrite(AR_CB1_STATUS_ADDR,&a_cfg_value,1);       
+
+       if ( atm_init_hard(&g_atm_dev) != 0){
+               return -EIO;
+       }
+       sema_init(&(g_atm_dev.swie.in_sem), 1);
+       //SWIE lock
+       clear_bit(SWIE_LOCK, &(g_atm_dev.swie.lock));
+       //SWIE wait queue
+       init_waitqueue_head(&(g_atm_dev.swie.sleep));
+       
+       for (i=CBM_DEFAULT_Q_OFFSET;i<AMAZON_ATM_MAX_QUEUE_NUM/2;i++) {
+               vcc = g_atm_dev.queues[i].vcc;
+               if (vcc != NULL){
+                       set_qsb(vcc, &vcc->qos, i);
+                       set_qd(vcc, i);
+                       mb();
+                       err=set_htu(vcc,i);
+                       if (err){
+                               AMAZON_TPE_EMSG("set htu entry fails %u\n",err);
+                       }
+               }
+       }
+       meiDebugWrite(A_CFG_ADDR,&a_cfg_old_value,1);   
+#if 0
+       //reset DFE
+       *(AMAZON_RST_REQ) = (* AMAZON_RST_REQ) | (AMAZON_RST_REQ_DFE);
+       mb();
+       *(AMAZON_RST_REQ) = (* AMAZON_RST_REQ) &  (~AMAZON_RST_REQ_DFE);
+       mb();
+#endif
+       
+       return 0;
+}
+
+/* Brief:      Send a ATM EoP packet to save DMA channel
+ */
+int amazon_tpe_inject_debug_cell(void)
+{
+       //Send a ATM cell to save DMA channel
+       u8 qid;
+       unsigned char atm_cell[48];
+       qid = 0x11;
+       AMAZON_TPE_DMSG("qid = %d\n",qid);
+       memset(atm_cell,0,48);
+       atm_cell[3] = 0x2;
+       if ( amazon_atm_swin(qid,atm_cell)) {
+               AMAZON_TPE_EMSG("cannot insert EoP cell\n");
+               return -1;
+       }
+       return 0;
+}
+
+/* Brief:      start HTU (TPE)
+ */
+
+int amazon_tpe_start(void)
+{
+       AMAZON_WRITE_REGISTER_L(HTU_CFG_START ,HTU_CFG_ADDR);
+       wmb();
+       return 0;
+}
+#endif //AMAZON_TPE_AAL5_RECOVERY
+
+#ifdef AMAZON_CHECK_LINK
+extern int (*adsl_link_notify)(int);
+/*     Brief:  notify link status of ADSL link
+ *     Parameters:     0       link down
+ *                     1       link up
+ *     Returns:        0       OK
+ *     Details:        called by MEI driver 
+ *     should update status and inform upper layer
+ */
+int amazon_tpe_link_notify(int status)
+{
+       adsl_link_status = status;
+       AMAZON_TPE_DMSG("link status %s\n",(status==1)?"Up":"Down");
+       if (status == 0){
+               //wait until no cells in upstream queues
+               set_current_state(TASK_INTERRUPTIBLE);
+               schedule_timeout(2*HZ);
+       }
+       return 0;
+}
+#endif //ifdef AMAZON_CHECK_LINK
+
+/*
+ *     Brief:          Initialize ATM module
+ *
+ *     Return Value:   ENOMEM          - No memory available
+ *                     EBUSY           - Cannot register atm device
+ *                     ERESTARTSYS     - Process interrupted by other signal
+ *                     0               - OK, module initialized
+ *
+ *     Description:
+ *     This function registers an atm device for all UTOPIA devices.
+ *     It also allocates memory for the private device data structures
+ */
+int __init amazon_atm_net_init(void)
+{
+       int i;
+       int err=0;
+       amazon_atm_dev_t *dev = NULL;
+       
+       if ((dev=amazon_atm_create()) != NULL){
+               for(i=0;i<AMAZON_ATM_PORT_NUM;i++){
+                       if (!dev->ports[i].enable){
+                               amazon_atm_devs[i] = NULL;
+                               continue;
+                       }
+                       amazon_atm_devs[i] =atm_dev_register("amazon_atm",&amazon_atm_ops,-1,0UL);
+                       if (amazon_atm_devs[i] == NULL){
+                               AMAZON_TPE_EMSG("atm_dev_register fails\n");
+                               err = -EIO;
+                               goto amazon_atm_net_init_exit;
+                       }else{
+                               AMAZON_TPE_DMSG("registering device %u\n",i);
+                               amazon_atm_devs[i]->ci_range.vpi_bits = 8;
+                               amazon_atm_devs[i]->ci_range.vci_bits = 16;
+                               amazon_atm_devs[i]->link_rate = dev->ports[i].tx_max_cr;
+                               amazon_atm_devs[i]->dev_data = (void *) i;
+                       }
+               }
+                       
+       }else{
+               err = -ENOMEM;
+               AMAZON_TPE_EMSG("cannot init atm device\n");
+               goto amazon_atm_net_init_exit;
+       }
+#ifdef AMAZON_TPE_AAL5_RECOVERY        
+       tpe_reset = & amazon_tpe_reset;
+       tpe_start = & amazon_tpe_start;
+       tpe_inject = & amazon_tpe_inject_debug_cell;
+#endif //AMAZON_TPE_AAL5_RECOVERY
+#ifdef AMAZON_CHECK_LINK
+       adsl_link_notify=amazon_tpe_link_notify;
+#endif //AMAZON_CHECK_LINK
+amazon_atm_net_init_exit:
+       return err;
+}
+
+void __exit amazon_atm_net_cleanup(void)
+{
+       int i;
+       amazon_atm_cleanup();
+       for(i=0;i<AMAZON_ATM_PORT_NUM;i++){
+               if (amazon_atm_devs[i] != NULL){
+                       AMAZON_TPE_DMSG("unregister dev %u\n",i);
+                       atm_dev_deregister(amazon_atm_devs[i]);
+               }
+       }
+       return;
+}
+EXPORT_SYMBOL(get_oam_time_stamp);
+
+MODULE_LICENSE ("GPL"); 
+MODULE_AUTHOR("Infineon IFAP DC COM peng.liu@infineon.com");
+MODULE_DESCRIPTION("AMAZON ATM driver");
+
+module_init(amazon_atm_net_init);
+module_exit(amazon_atm_net_cleanup);
+
+
+
+
diff --git a/target/linux/amazon-2.6/files/drivers/char/admmod.c b/target/linux/amazon-2.6/files/drivers/char/admmod.c
new file mode 100644 (file)
index 0000000..0229f53
--- /dev/null
@@ -0,0 +1,1486 @@
+/******************************************************************************
+     Copyright (c) 2004, Infineon Technologies.  All rights reserved.
+
+                               No Warranty
+   Because the program is licensed free of charge, there is no warranty for
+   the program, to the extent permitted by applicable law.  Except when
+   otherwise stated in writing the copyright holders and/or other parties
+   provide the program "as is" without warranty of any kind, either
+   expressed or implied, including, but not limited to, the implied
+   warranties of merchantability and fitness for a particular purpose. The
+   entire risk as to the quality and performance of the program is with
+   you.  should the program prove defective, you assume the cost of all
+   necessary servicing, repair or correction.
+
+   In no event unless required by applicable law or agreed to in writing
+   will any copyright holder, or any other party who may modify and/or
+   redistribute the program as permitted above, be liable to you for
+   damages, including any general, special, incidental or consequential
+   damages arising out of the use or inability to use the program
+   (including but not limited to loss of data or data being rendered
+   inaccurate or losses sustained by you or third parties or a failure of
+   the program to operate with any other programs), even if such holder or
+   other party has been advised of the possibility of such damages.
+ ******************************************************************************
+   Module      : admmod.c
+   Date        : 2004-09-01
+   Description : JoeLin
+   Remarks:
+
+   Revision:
+       MarsLin, add to support VLAN
+
+ *****************************************************************************/
+//000001.joelin 2005/06/02 add"ADM6996_MDC_MDIO_MODE" define, 
+//             if define ADM6996_MDC_MDIO_MODE==> ADM6996LC and ADM6996I will be in MDIO/MDC(SMI)(16 bit) mode,
+//             amazon should contrl ADM6996 by MDC/MDIO pin
+//             if undef ADM6996_MDC_MDIO_MODE==> ADM6996  will be in EEProm(32 bit) mode,
+//             amazon should contrl ADM6996 by GPIO15,16,17,18  pin
+/* 507281:linmars 2005/07/28 support MDIO/EEPROM config mode */
+/* 509201:linmars remove driver testing codes */
+
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/proc_fs.h>
+#include <linux/delay.h>
+#include <asm/uaccess.h>
+#include <linux/init.h>
+#include <linux/ioctl.h>
+#include <asm/atomic.h>
+#include <asm-mips/amazon/amazon.h>
+#include <asm-mips/amazon/adm6996.h>
+//#include <linux/amazon/adm6996.h>
+
+
+unsigned int ifx_sw_conf[ADM_SW_MAX_PORT_NUM+1] = \
+       {ADM_SW_PORT0_CONF, ADM_SW_PORT1_CONF, ADM_SW_PORT2_CONF, \
+       ADM_SW_PORT3_CONF, ADM_SW_PORT4_CONF, ADM_SW_PORT5_CONF};
+unsigned int ifx_sw_bits[8] = \
+       {0x1, 0x3, 0x7, 0xf, 0x1f, 0x3f, 0x7f, 0xff};
+unsigned int ifx_sw_vlan_port[6] = {0, 2, 4, 6, 7, 8};
+//050613:fchang 
+/* 507281:linmars start */
+#ifdef CONFIG_SWITCH_ADM6996_MDIO
+#define ADM6996_MDC_MDIO_MODE 1 //000001.joelin
+#else
+#undef ADM6996_MDC_MDIO_MODE
+#endif
+/* 507281:linmars end */
+#define adm6996i 0
+#define adm6996lc 1
+#define adm6996l  2
+unsigned int adm6996_mode=adm6996i;
+/*
+  initialize GPIO pins.
+  output mode, low
+*/
+void ifx_gpio_init(void)
+{
+ //GPIO16,17,18 direction:output
+ //GPIO16,17,18 output 0
+    AMAZON_SW_REG(AMAZON_GPIO_P1_DIR) |= (GPIO_MDIO|GPIO_MDCS|GPIO_MDC);
+    AMAZON_SW_REG(AMAZON_GPIO_P1_OUT) =AMAZON_SW_REG(AMAZON_GPIO_P1_IN)& ~(GPIO_MDIO|GPIO_MDCS|GPIO_MDC);
+
+}
+
+/* read one bit from mdio port */
+int ifx_sw_mdio_readbit(void)
+{
+    //int val;
+
+    //val = (AMAZON_SW_REG(GPIO_conf0_REG) & GPIO0_INPUT_MASK) >> 8;
+    //return val;
+    //GPIO16
+    return AMAZON_SW_REG(AMAZON_GPIO_P1_IN)&1;
+}
+
+/*
+  MDIO mode selection
+  1 -> output
+  0 -> input
+
+  switch input/output mode of GPIO 0
+*/
+void ifx_mdio_mode(int mode)
+{
+//    AMAZON_SW_REG(GPIO_conf0_REG) = mode ? GPIO_ENABLEBITS :
+//                             ((GPIO_ENABLEBITS | MDIO_INPUT) & ~MDIO_OUTPUT_EN);
+    mode?(AMAZON_SW_REG(AMAZON_GPIO_P1_DIR)|=GPIO_MDIO):
+         (AMAZON_SW_REG(AMAZON_GPIO_P1_DIR)&=~GPIO_MDIO);
+    /*int r=AMAZON_SW_REG(AMAZON_GPIO_P1_DIR);
+    mode?(r|=GPIO_MDIO):(r&=~GPIO_MDIO);
+    AMAZON_SW_REG(AMAZON_GPIO_P1_DIR)=r;*/
+}
+
+void ifx_mdc_hi(void)
+{
+    //GPIO_SET_HI(GPIO_MDC);
+    //AMAZON_SW_REG(AMAZON_GPIO_P1_OUT)|=GPIO_MDC;
+    /*int r=AMAZON_SW_REG(AMAZON_GPIO_P1_OUT);
+    r|=GPIO_MDC;
+    AMAZON_SW_REG(AMAZON_GPIO_P1_OUT)=r;*/
+
+    AMAZON_SW_REG(AMAZON_GPIO_P1_OUT)=AMAZON_SW_REG(AMAZON_GPIO_P1_IN)|GPIO_MDC;
+}
+
+void ifx_mdio_hi(void)
+{
+    //GPIO_SET_HI(GPIO_MDIO);
+    //AMAZON_SW_REG(AMAZON_GPIO_P1_OUT)|=GPIO_MDIO;
+    /*int r=AMAZON_SW_REG(AMAZON_GPIO_P1_OUT);
+    r|=GPIO_MDIO;
+    AMAZON_SW_REG(AMAZON_GPIO_P1_OUT)=r;*/
+
+    AMAZON_SW_REG(AMAZON_GPIO_P1_OUT)=AMAZON_SW_REG(AMAZON_GPIO_P1_IN)|GPIO_MDIO;
+}
+
+void ifx_mdcs_hi(void)
+{
+    //GPIO_SET_HI(GPIO_MDCS);
+    //AMAZON_SW_REG(AMAZON_GPIO_P1_OUT)|=GPIO_MDCS;
+    /*int r=AMAZON_SW_REG(AMAZON_GPIO_P1_OUT);
+    r|=GPIO_MDCS;
+    AMAZON_SW_REG(AMAZON_GPIO_P1_OUT)=r;*/
+
+    AMAZON_SW_REG(AMAZON_GPIO_P1_OUT)=AMAZON_SW_REG(AMAZON_GPIO_P1_IN)|GPIO_MDCS;
+}
+
+void ifx_mdc_lo(void)
+{
+    //GPIO_SET_LOW(GPIO_MDC);
+    //AMAZON_SW_REG(AMAZON_GPIO_P1_OUT)&=~GPIO_MDC;
+    /*int r=AMAZON_SW_REG(AMAZON_GPIO_P1_OUT);
+    r&=~GPIO_MDC;
+    AMAZON_SW_REG(AMAZON_GPIO_P1_OUT)=r;*/
+
+    AMAZON_SW_REG(AMAZON_GPIO_P1_OUT)=AMAZON_SW_REG(AMAZON_GPIO_P1_IN)&(~GPIO_MDC);
+}
+
+void ifx_mdio_lo(void)
+{
+    //GPIO_SET_LOW(GPIO_MDIO);
+    //AMAZON_SW_REG(AMAZON_GPIO_P1_OUT)&=~GPIO_MDIO;
+    /*int r=AMAZON_SW_REG(AMAZON_GPIO_P1_OUT);
+    r&=~GPIO_MDIO;
+    AMAZON_SW_REG(AMAZON_GPIO_P1_OUT)=r;*/
+
+    AMAZON_SW_REG(AMAZON_GPIO_P1_OUT)=AMAZON_SW_REG(AMAZON_GPIO_P1_IN)&(~GPIO_MDIO);
+}
+
+void ifx_mdcs_lo(void)
+{
+    //GPIO_SET_LOW(GPIO_MDCS);
+    //AMAZON_SW_REG(AMAZON_GPIO_P1_OUT)&=~GPIO_MDCS;
+    /*int r=AMAZON_SW_REG(AMAZON_GPIO_P1_OUT);
+    r&=~GPIO_MDCS;
+    AMAZON_SW_REG(AMAZON_GPIO_P1_OUT)=r;*/
+    
+    AMAZON_SW_REG(AMAZON_GPIO_P1_OUT)=AMAZON_SW_REG(AMAZON_GPIO_P1_IN)&(~GPIO_MDCS);
+}
+
+/*
+  mdc pulse
+  0 -> 1 -> 0
+*/
+static void ifx_sw_mdc_pulse(void)
+{
+    ifx_mdc_lo();
+    udelay(ADM_SW_MDC_DOWN_DELAY);
+    ifx_mdc_hi();
+    udelay(ADM_SW_MDC_UP_DELAY);
+    ifx_mdc_lo();
+}
+
+/*
+  mdc toggle
+  1 -> 0
+*/
+static void ifx_sw_mdc_toggle(void)
+{
+    ifx_mdc_hi();
+    udelay(ADM_SW_MDC_UP_DELAY);
+    ifx_mdc_lo();
+    udelay(ADM_SW_MDC_DOWN_DELAY);
+}
+
+/*
+  enable eeprom write
+  For ATC 93C66 type EEPROM; accessing ADM6996 internal EEPROM type registers
+*/
+static void ifx_sw_eeprom_write_enable(void)
+{
+    unsigned int op;
+
+    ifx_mdcs_lo();
+    ifx_mdc_lo();
+    ifx_mdio_hi();
+    udelay(ADM_SW_CS_DELAY);
+    /* enable chip select */
+    ifx_mdcs_hi();
+    udelay(ADM_SW_CS_DELAY);
+    /* start bit */
+    ifx_mdio_hi();
+    ifx_sw_mdc_pulse();
+
+    /* eeprom write enable */
+    op = ADM_SW_BIT_MASK_4;
+    while (op)
+    {
+        if (op & ADM_SW_EEPROM_WRITE_ENABLE)
+            ifx_mdio_hi();
+        else
+            ifx_mdio_lo();
+
+        ifx_sw_mdc_pulse();
+        op >>= 1;
+    }
+
+    op = ADM_SW_BIT_MASK_1 << (EEPROM_TYPE - 3);
+    while (op)
+    {
+        ifx_mdio_lo();
+        ifx_sw_mdc_pulse();
+        op >>= 1;
+    }
+    /* disable chip select */
+    ifx_mdcs_lo();
+    udelay(ADM_SW_CS_DELAY);
+    ifx_sw_mdc_pulse();
+}
+
+/*
+  disable eeprom write
+*/
+static void ifx_sw_eeprom_write_disable(void)
+{
+    unsigned int op;
+
+    ifx_mdcs_lo();
+    ifx_mdc_lo();
+    ifx_mdio_hi();
+    udelay(ADM_SW_CS_DELAY);
+    /* enable chip select */
+    ifx_mdcs_hi();
+    udelay(ADM_SW_CS_DELAY);
+
+    /* start bit */
+    ifx_mdio_hi();
+    ifx_sw_mdc_pulse();
+    /* eeprom write disable */
+    op = ADM_SW_BIT_MASK_4;
+    while (op)
+    {
+        if (op & ADM_SW_EEPROM_WRITE_DISABLE)
+            ifx_mdio_hi();
+        else
+            ifx_mdio_lo();
+
+        ifx_sw_mdc_pulse();
+        op >>= 1;
+    }
+
+    op = ADM_SW_BIT_MASK_1 << (EEPROM_TYPE - 3);
+    while (op)
+    {
+        ifx_mdio_lo();
+
+        ifx_sw_mdc_pulse();
+        op >>= 1;
+    }
+    /* disable chip select */
+    ifx_mdcs_lo();
+    udelay(ADM_SW_CS_DELAY);
+    ifx_sw_mdc_pulse();
+}
+
+/*
+  read registers from ADM6996
+  serial registers start at 0x200 (addr bit 9 = 1b)
+  EEPROM registers -> 16bits; Serial registers -> 32bits
+*/
+#ifdef ADM6996_MDC_MDIO_MODE //smi mode//000001.joelin
+static int ifx_sw_read_adm6996i_smi(unsigned int addr, unsigned int *dat)
+{
+   addr=(addr<<16)&0x3ff0000;
+   AMAZON_SW_REG(AMAZON_SW_MDIO_ACC) =(0xC0000000|addr);
+   while ((AMAZON_SW_REG(AMAZON_SW_MDIO_ACC))&0x80000000){};
+   *dat=((AMAZON_SW_REG(AMAZON_SW_MDIO_ACC))&0x0FFFF);
+    return 0;
+}
+#endif
+
+static int ifx_sw_read_adm6996i(unsigned int addr, unsigned int *dat)
+{
+    unsigned int op;
+
+    ifx_gpio_init();
+
+    ifx_mdcs_hi();
+    udelay(ADM_SW_CS_DELAY);
+
+    ifx_mdcs_lo();
+    ifx_mdc_lo();
+    ifx_mdio_lo();
+
+    udelay(ADM_SW_CS_DELAY);
+
+    /* preamble, 32 bit 1 */
+    ifx_mdio_hi();
+    op = ADM_SW_BIT_MASK_32;
+    while (op)
+    {
+        ifx_sw_mdc_pulse();
+        op >>= 1;
+    }
+
+    /* command start (01b) */
+    op = ADM_SW_BIT_MASK_2;
+    while (op)
+    {
+        if (op & ADM_SW_SMI_START)
+            ifx_mdio_hi();
+        else
+            ifx_mdio_lo();
+
+        ifx_sw_mdc_pulse();
+        op >>= 1;
+    }
+
+    /* read command (10b) */
+    op = ADM_SW_BIT_MASK_2;
+    while (op)
+    {
+        if (op & ADM_SW_SMI_READ)
+            ifx_mdio_hi();
+        else
+            ifx_mdio_lo();
+
+        ifx_sw_mdc_pulse();
+        op >>= 1;
+    }
+
+    /* send address A9 ~ A0 */
+    op = ADM_SW_BIT_MASK_10;
+    while (op)
+    {
+        if (op & addr)
+            ifx_mdio_hi();
+        else
+            ifx_mdio_lo();
+
+        ifx_sw_mdc_pulse();
+        op >>= 1;
+    }
+
+    /* turnaround bits */
+    op = ADM_SW_BIT_MASK_2;
+    ifx_mdio_hi();
+    while (op)
+    {
+        ifx_sw_mdc_pulse();
+        op >>= 1;
+    }
+
+    udelay(ADM_SW_MDC_DOWN_DELAY);
+
+    /* set MDIO pin to input mode */
+    ifx_mdio_mode(ADM_SW_MDIO_INPUT);
+
+    /* start read data */
+    *dat = 0;
+//adm6996i    op = ADM_SW_BIT_MASK_32;
+    op = ADM_SW_BIT_MASK_16;//adm6996i
+    while (op)
+    {
+        *dat <<= 1;
+        if (ifx_sw_mdio_readbit()) *dat |= 1;
+        ifx_sw_mdc_toggle();
+
+        op >>= 1;
+    }
+
+    /* set MDIO to output mode */
+    ifx_mdio_mode(ADM_SW_MDIO_OUTPUT);
+
+    /* dummy clock */
+    op = ADM_SW_BIT_MASK_4;
+    ifx_mdio_lo();
+    while(op)
+    {
+        ifx_sw_mdc_pulse();
+        op >>= 1;
+    }
+
+    ifx_mdc_lo();
+    ifx_mdio_lo();
+    ifx_mdcs_hi();
+
+    /* EEPROM registers */
+//adm6996i    if (!(addr & 0x200))
+//adm6996i    {
+//adm6996i        if (addr % 2)
+//adm6996i            *dat >>= 16;
+//adm6996i        else
+//adm6996i        *dat &= 0xffff;
+//adm6996i    }
+
+    return 0;
+}
+//adm6996
+static int ifx_sw_read_adm6996l(unsigned int addr, unsigned int *dat)
+{
+    unsigned int op;
+
+    ifx_gpio_init();
+
+    ifx_mdcs_hi();
+    udelay(ADM_SW_CS_DELAY);
+
+    ifx_mdcs_lo();
+    ifx_mdc_lo();
+    ifx_mdio_lo();
+
+    udelay(ADM_SW_CS_DELAY);
+
+    /* preamble, 32 bit 1 */
+    ifx_mdio_hi();
+    op = ADM_SW_BIT_MASK_32;
+    while (op)
+    {
+        ifx_sw_mdc_pulse();
+        op >>= 1;
+    }
+
+    /* command start (01b) */
+    op = ADM_SW_BIT_MASK_2;
+    while (op)
+    {
+        if (op & ADM_SW_SMI_START)
+            ifx_mdio_hi();
+        else
+            ifx_mdio_lo();
+
+        ifx_sw_mdc_pulse();
+        op >>= 1;
+    }
+
+    /* read command (10b) */
+    op = ADM_SW_BIT_MASK_2;
+    while (op)
+    {
+        if (op & ADM_SW_SMI_READ)
+            ifx_mdio_hi();
+        else
+            ifx_mdio_lo();
+
+        ifx_sw_mdc_pulse();
+        op >>= 1;
+    }
+
+    /* send address A9 ~ A0 */
+    op = ADM_SW_BIT_MASK_10;
+    while (op)
+    {
+        if (op & addr)
+            ifx_mdio_hi();
+        else
+            ifx_mdio_lo();
+
+        ifx_sw_mdc_pulse();
+        op >>= 1;
+    }
+
+    /* turnaround bits */
+    op = ADM_SW_BIT_MASK_2;
+    ifx_mdio_hi();
+    while (op)
+    {
+        ifx_sw_mdc_pulse();
+        op >>= 1;
+    }
+
+    udelay(ADM_SW_MDC_DOWN_DELAY);
+
+    /* set MDIO pin to input mode */
+    ifx_mdio_mode(ADM_SW_MDIO_INPUT);
+
+    /* start read data */
+    *dat = 0;
+    op = ADM_SW_BIT_MASK_32;
+    while (op)
+    {
+        *dat <<= 1;
+        if (ifx_sw_mdio_readbit()) *dat |= 1;
+        ifx_sw_mdc_toggle();
+
+        op >>= 1;
+    }
+
+    /* set MDIO to output mode */
+    ifx_mdio_mode(ADM_SW_MDIO_OUTPUT);
+
+    /* dummy clock */
+    op = ADM_SW_BIT_MASK_4;
+    ifx_mdio_lo();
+    while(op)
+    {
+        ifx_sw_mdc_pulse();
+        op >>= 1;
+    }
+
+    ifx_mdc_lo();
+    ifx_mdio_lo();
+    ifx_mdcs_hi();
+
+    /* EEPROM registers */
+    if (!(addr & 0x200))
+    {
+        if (addr % 2)
+            *dat >>= 16;
+        else
+        *dat &= 0xffff;
+    }
+
+    return 0;
+}
+
+static int ifx_sw_read(unsigned int addr, unsigned int *dat)
+{
+#ifdef ADM6996_MDC_MDIO_MODE //smi mode ////000001.joelin
+       ifx_sw_read_adm6996i_smi(addr,dat);
+#else  
+       if (adm6996_mode==adm6996i) ifx_sw_read_adm6996i(addr,dat);
+               else ifx_sw_read_adm6996l(addr,dat);
+#endif         
+       return 0;
+       
+}
+
+/*
+  write register to ADM6996 eeprom registers
+*/
+//for adm6996i -start
+#ifdef ADM6996_MDC_MDIO_MODE //smi mode //000001.joelin
+static int ifx_sw_write_adm6996i_smi(unsigned int addr, unsigned int dat)
+{
+   AMAZON_SW_REG(AMAZON_SW_MDIO_ACC) = ((addr<<16)&0x3ff0000)|dat|0x80000000;
+   while ((AMAZON_SW_REG(AMAZON_SW_MDIO_ACC))&0x80000000){};
+  
+    return 0;
+}
+#endif //ADM6996_MDC_MDIO_MODE //000001.joelin
+
+static int ifx_sw_write_adm6996i(unsigned int addr, unsigned int dat)
+{
+    unsigned int op;
+
+    ifx_gpio_init();
+
+    ifx_mdcs_hi();
+    udelay(ADM_SW_CS_DELAY);
+
+    ifx_mdcs_lo();
+    ifx_mdc_lo();
+    ifx_mdio_lo();
+
+    udelay(ADM_SW_CS_DELAY);
+
+    /* preamble, 32 bit 1 */
+    ifx_mdio_hi();
+    op = ADM_SW_BIT_MASK_32;
+    while (op)
+    {
+        ifx_sw_mdc_pulse();
+        op >>= 1;
+    }
+
+    /* command start (01b) */
+    op = ADM_SW_BIT_MASK_2;
+    while (op)
+    {
+        if (op & ADM_SW_SMI_START)
+            ifx_mdio_hi();
+        else
+            ifx_mdio_lo();
+
+        ifx_sw_mdc_pulse();
+        op >>= 1;
+    }
+
+    /* write command (01b) */
+    op = ADM_SW_BIT_MASK_2;
+    while (op)
+    {
+        if (op & ADM_SW_SMI_WRITE)
+            ifx_mdio_hi();
+        else
+            ifx_mdio_lo();
+
+        ifx_sw_mdc_pulse();
+        op >>= 1;
+    }
+
+    /* send address A9 ~ A0 */
+    op = ADM_SW_BIT_MASK_10;
+    while (op)
+    {
+        if (op & addr)
+            ifx_mdio_hi();
+        else
+            ifx_mdio_lo();
+
+        ifx_sw_mdc_pulse();
+        op >>= 1;
+    }
+
+    /* turnaround bits */
+    op = ADM_SW_BIT_MASK_2;
+    ifx_mdio_hi();
+    while (op)
+    {
+        ifx_sw_mdc_pulse();
+        op >>= 1;
+    }
+
+    udelay(ADM_SW_MDC_DOWN_DELAY);
+
+    /* set MDIO pin to output mode */
+    ifx_mdio_mode(ADM_SW_MDIO_OUTPUT);
+
+  
+    /* start write data */
+    op = ADM_SW_BIT_MASK_16;
+    while (op)
+    {
+        if (op & dat)
+            ifx_mdio_hi();
+        else
+            ifx_mdio_lo();
+
+        ifx_sw_mdc_toggle();
+        op >>= 1;
+    }
+
+ //   /* set MDIO to output mode */
+ //   ifx_mdio_mode(ADM_SW_MDIO_OUTPUT);
+
+    /* dummy clock */
+    op = ADM_SW_BIT_MASK_4;
+    ifx_mdio_lo();
+    while(op)
+    {
+        ifx_sw_mdc_pulse();
+        op >>= 1;
+    }
+
+    ifx_mdc_lo();
+    ifx_mdio_lo();
+    ifx_mdcs_hi();
+
+    /* EEPROM registers */
+//adm6996i    if (!(addr & 0x200))
+//adm6996i    {
+//adm6996i        if (addr % 2)
+//adm6996i            *dat >>= 16;
+//adm6996i        else
+//adm6996i        *dat &= 0xffff;
+//adm6996i    }
+
+    return 0;
+}
+//for adm6996i-end
+static int ifx_sw_write_adm6996l(unsigned int addr, unsigned int dat)
+{
+    unsigned int op;
+
+    ifx_gpio_init();
+
+    /* enable write */
+    ifx_sw_eeprom_write_enable();
+
+    /* chip select */
+    ifx_mdcs_hi();
+    udelay(ADM_SW_CS_DELAY);
+
+    /* issue write command */
+    /* start bit */
+    ifx_mdio_hi();
+    ifx_sw_mdc_pulse();
+
+    /* EEPROM write command */
+    op = ADM_SW_BIT_MASK_2;
+    while (op)
+    {
+        if (op & ADM_SW_EEPROM_WRITE)
+            ifx_mdio_hi();
+        else
+            ifx_mdio_lo();
+
+        ifx_sw_mdc_pulse();
+        op >>= 1;
+    }
+
+    /* send address A7 ~ A0 */
+    op = ADM_SW_BIT_MASK_1 << (EEPROM_TYPE - 1);
+
+    while (op)
+    {
+        if (op & addr)
+            ifx_mdio_hi();
+        else
+            ifx_mdio_lo();
+
+        ifx_sw_mdc_toggle();
+        op >>= 1;
+    }
+
+    /* start write data */
+    op = ADM_SW_BIT_MASK_16;
+    while (op)
+    {
+        if (op & dat)
+            ifx_mdio_hi();
+        else
+            ifx_mdio_lo();
+
+        ifx_sw_mdc_toggle();
+        op >>= 1;
+    }
+
+    /* disable cs & wait 1 clock */
+    ifx_mdcs_lo();
+    udelay(ADM_SW_CS_DELAY);
+    ifx_sw_mdc_toggle();
+
+    ifx_sw_eeprom_write_disable();
+
+    return 0;
+}
+
+static int ifx_sw_write(unsigned int addr, unsigned int dat)
+{
+#ifdef ADM6996_MDC_MDIO_MODE //smi mode ////000001.joelin
+       ifx_sw_write_adm6996i_smi(addr,dat);
+#else  //000001.joelin
+       if (adm6996_mode==adm6996i) ifx_sw_write_adm6996i(addr,dat);
+               else ifx_sw_write_adm6996l(addr,dat);
+#endif //000001.joelin
+       return 0;
+}
+
+/*
+  do switch PHY reset
+*/
+int ifx_sw_reset(void)
+{
+    /* reset PHY */
+    ifx_sw_write(ADM_SW_PHY_RESET, 0);
+
+    return 0;
+}
+
+/* 509201:linmars start */
+#if 0
+/*
+  check port status
+*/
+int ifx_check_port_status(int port)
+{
+    unsigned int val;
+
+    if ((port < 0) || (port > ADM_SW_MAX_PORT_NUM))
+    {
+        ifx_printf(("error on port number (%d)!!\n", port));
+        return -1;
+    }
+
+    ifx_sw_read(ifx_sw_conf[port], &val);
+    if (ifx_sw_conf[port]%2) val >>= 16;
+    /* only 16bits are effective */
+    val &= 0xFFFF;
+
+    ifx_printf(("Port %d status (%.8x): \n", port, val));
+
+    if (val & ADM_SW_PORT_FLOWCTL)
+        ifx_printf(("\t802.3x flow control supported!\n"));
+    else
+        ifx_printf(("\t802.3x flow control not supported!\n"));
+
+    if (val & ADM_SW_PORT_AN)
+        ifx_printf(("\tAuto negotiation ON!\n"));
+    else
+        ifx_printf(("\tAuto negotiation OFF!\n"));
+
+    if (val & ADM_SW_PORT_100M)
+        ifx_printf(("\tLink at 100M!\n"));
+    else
+        ifx_printf(("\tLink at 10M!\n"));
+
+    if (val & ADM_SW_PORT_FULL)
+        ifx_printf(("\tFull duplex!\n"));
+    else
+        ifx_printf(("\tHalf duplex!\n"));
+
+    if (val & ADM_SW_PORT_DISABLE)
+        ifx_printf(("\tPort disabled!\n"));
+    else
+        ifx_printf(("\tPort enabled!\n"));
+
+    if (val & ADM_SW_PORT_TOS)
+        ifx_printf(("\tTOS enabled!\n"));
+    else
+        ifx_printf(("\tTOS disabled!\n"));
+
+    if (val & ADM_SW_PORT_PPRI)
+        ifx_printf(("\tPort priority first!\n"));
+    else
+        ifx_printf(("\tVLAN or TOS priority first!\n"));
+
+    if (val & ADM_SW_PORT_MDIX)
+        ifx_printf(("\tAuto MDIX!\n"));
+    else
+        ifx_printf(("\tNo auto MDIX\n"));
+
+    ifx_printf(("\tPVID: %d\n", \
+           ((val >> ADM_SW_PORT_PVID_SHIFT)&ifx_sw_bits[ADM_SW_PORT_PVID_BITS])));
+
+    return 0;
+}
+/*
+  initialize a VLAN
+  clear all VLAN bits
+*/
+int ifx_sw_vlan_init(int vlanid)
+{
+    ifx_sw_write(ADM_SW_VLAN0_CONF + vlanid, 0);
+
+    return 0;
+}
+
+/*
+  add a port to certain vlan
+*/
+int ifx_sw_vlan_add(int port, int vlanid)
+{
+    int reg = 0;
+
+    if ((port < 0) || (port > ADM_SW_MAX_PORT_NUM) || (vlanid < 0) ||
+        (vlanid > ADM_SW_MAX_VLAN_NUM))
+    {
+        ifx_printf(("Port number or VLAN number ERROR!!\n"));
+        return -1;
+    }
+    ifx_sw_read(ADM_SW_VLAN0_CONF + vlanid, &reg);
+    reg |= (1 << ifx_sw_vlan_port[port]);
+    ifx_sw_write(ADM_SW_VLAN0_CONF + vlanid, reg);
+
+    return 0;
+}
+
+/*
+  delete a given port from certain vlan
+*/
+int ifx_sw_vlan_del(int port, int vlanid)
+{
+    unsigned int reg = 0;
+
+    if ((port < 0) || (port > ADM_SW_MAX_PORT_NUM) || (vlanid < 0) || (vlanid > ADM_SW_MAX_VLAN_NUM))
+    {
+        ifx_printf(("Port number or VLAN number ERROR!!\n"));
+        return -1;
+    }
+    ifx_sw_read(ADM_SW_VLAN0_CONF + vlanid, &reg);
+    reg &= ~(1 << ifx_sw_vlan_port[port]);
+    ifx_sw_write(ADM_SW_VLAN0_CONF + vlanid, reg);
+
+    return 0;
+}
+
+/*
+  default VLAN setting
+
+  port 0~3 as untag port and PVID = 1
+  VLAN1: port 0~3 and port 5 (MII)
+*/
+static int ifx_sw_init(void)
+{
+    ifx_printf(("Setting default ADM6996 registers... \n"));
+
+    /* MAC clone, 802.1q based VLAN */
+    ifx_sw_write(ADM_SW_VLAN_MODE, 0xff30);
+    /* auto MDIX, PVID=1, untag */
+    ifx_sw_write(ADM_SW_PORT0_CONF, 0x840f);
+    ifx_sw_write(ADM_SW_PORT1_CONF, 0x840f);
+    ifx_sw_write(ADM_SW_PORT2_CONF, 0x840f);
+    ifx_sw_write(ADM_SW_PORT3_CONF, 0x840f);
+    /* auto MDIX, PVID=2, untag */
+    ifx_sw_write(ADM_SW_PORT5_CONF, 0x880f);
+    /* port 0~3 & 5 as VLAN1 */
+    ifx_sw_write(ADM_SW_VLAN0_CONF+1, 0x0155);
+
+    return 0;
+}
+#endif
+/* 509201:linmars end */
+
+int adm_open(struct inode *node, struct file *filp)
+{
+    MOD_INC_USE_COUNT;
+    return 0;
+}
+
+ssize_t adm_read(struct file *filep, char *buf, size_t count, loff_t *ppos)
+{
+    return count;
+}
+
+ssize_t adm_write(struct file *filep, const char *buf, size_t count, loff_t *ppos)
+{
+    return count;
+}
+
+/* close */
+int adm_release(struct inode *inode, struct file *filp)
+{
+    MOD_DEC_USE_COUNT;
+    return 0;
+}
+
+/* IOCTL function */
+int adm_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long args)
+{
+    PREGRW uREGRW;
+    unsigned int rtval;
+    unsigned int val;          //6996i
+    unsigned int control[6] ;  //6996i
+    unsigned int status[6] ;   //6996i
+    
+    PMACENTRY mMACENTRY;//adm6996i
+    PPROTOCOLFILTER uPROTOCOLFILTER ;///adm6996i
+
+    if (_IOC_TYPE(cmd) != ADM_MAGIC)
+    {
+        printk("adm_ioctl: IOC_TYPE(%x) != ADM_MAGIC(%x)! \n", _IOC_TYPE(cmd), ADM_MAGIC);
+        return (-EINVAL);
+    }
+
+    if(_IOC_NR(cmd) >= KEY_IOCTL_MAX_KEY)
+    {
+        printk(KERN_WARNING "adm_ioctl: IOC_NR(%x) invalid! \n", _IOC_NR(cmd));
+        return (-EINVAL);
+    }
+
+    switch (cmd)
+    {
+        case ADM_IOCTL_REGRW:
+        {
+            uREGRW = (PREGRW)kmalloc(sizeof(REGRW), GFP_KERNEL);
+            rtval = copy_from_user(uREGRW, (PREGRW)args, sizeof(REGRW));
+            if (rtval != 0)
+            {
+                printk("ADM_IOCTL_REGRW: copy from user FAILED!! \n");
+                return (-EFAULT);
+            }
+
+            switch(uREGRW->mode)
+            {
+                case REG_READ:
+                    uREGRW->value = 0x12345678;//inl(uREGRW->addr);
+                    copy_to_user((PREGRW)args, uREGRW, sizeof(REGRW));
+                    break;
+                case REG_WRITE:
+                    //outl(uREGRW->value, uREGRW->addr);
+                    break;
+
+                default:
+                    printk("No such Register Read/Write function!! \n");
+                    return (-EFAULT);
+            }
+            kfree(uREGRW);
+            break;
+        }
+
+        case ADM_SW_IOCTL_REGRW:
+        {
+            unsigned int val = 0xff;
+
+            uREGRW = (PREGRW)kmalloc(sizeof(REGRW), GFP_KERNEL);
+            rtval = copy_from_user(uREGRW, (PREGRW)args, sizeof(REGRW));
+            if (rtval != 0)
+            {
+                printk("ADM_IOCTL_REGRW: copy from user FAILED!! \n");
+                return (-EFAULT);
+            }
+
+            switch(uREGRW->mode)
+            {
+                case REG_READ:
+                    ifx_sw_read(uREGRW->addr, &val);
+                    uREGRW->value = val;
+                    copy_to_user((PREGRW)args, uREGRW, sizeof(REGRW));
+                    break;
+
+                case REG_WRITE:
+                    ifx_sw_write(uREGRW->addr, uREGRW->value);
+                    break;
+                default:
+                    printk("No such Register Read/Write function!! \n");
+                    return (-EFAULT);
+            }
+            kfree(uREGRW);
+            break;
+        }
+/* 509201:linmars start */
+#if 0
+        case ADM_SW_IOCTL_PORTSTS:
+            for (rtval = 0; rtval < ADM_SW_MAX_PORT_NUM+1; rtval++)
+                ifx_check_port_status(rtval);
+            break;
+        case ADM_SW_IOCTL_INIT:
+            ifx_sw_init();
+            break;
+#endif
+/* 509201:linmars end */
+//adm6996i
+        case ADM_SW_IOCTL_MACENTRY_ADD:
+        case ADM_SW_IOCTL_MACENTRY_DEL:
+        case ADM_SW_IOCTL_MACENTRY_GET_INIT:
+        case ADM_SW_IOCTL_MACENTRY_GET_MORE:
+                
+
+           mMACENTRY = (PMACENTRY)kmalloc(sizeof(MACENTRY), GFP_KERNEL);
+            rtval = copy_from_user(mMACENTRY, (PMACENTRY)args, sizeof(MACENTRY));
+            if (rtval != 0)
+            {
+                printk("ADM_SW_IOCTL_MACENTRY: copy from user FAILED!! \n");
+                return (-EFAULT);
+            }
+           control[0]=(mMACENTRY->mac_addr[1]<<8)+mMACENTRY->mac_addr[0]     ; 
+           control[1]=(mMACENTRY->mac_addr[3]<<8)+mMACENTRY->mac_addr[2]      ;         
+           control[2]=(mMACENTRY->mac_addr[5]<<8)+mMACENTRY->mac_addr[4]     ;
+           control[3]=(mMACENTRY->fid&0xf)+((mMACENTRY->portmap&0x3f)<<4);
+           if (((mMACENTRY->info_type)&0x01)) control[4]=(mMACENTRY->ctrl.info_ctrl)+0x1000; //static ,info control
+               else    control[4]=((mMACENTRY->ctrl.age_timer)&0xff);//not static ,agetimer
+               if (cmd==ADM_SW_IOCTL_MACENTRY_GET_INIT) {      
+                  //initial  the pointer to the first address  
+                                  val=0x8000;//busy ,status5[15]
+                                  while(val&0x8000){           //check busy ?
+                                         ifx_sw_read(0x125, &val);
+                                       }    
+                                  control[5]=0x030;//initial the first address 
+                                  ifx_sw_write(0x11f,control[5]);
+                                               
+                                       
+                                  val=0x8000;//busy ,status5[15]
+                                  while(val&0x8000){           //check busy ?
+                                         ifx_sw_read(0x125, &val);
+                                       }               
+                       
+                  }    //if (cmd==ADM_SW_IOCTL_MACENTRY_GET_INIT)                                                              
+           if (cmd==ADM_SW_IOCTL_MACENTRY_ADD) control[5]=0x07;//create a new address
+               else if (cmd==ADM_SW_IOCTL_MACENTRY_DEL) control[5]=0x01f;//erased an existed address
+               else if ((cmd==ADM_SW_IOCTL_MACENTRY_GET_INIT)||(cmd==ADM_SW_IOCTL_MACENTRY_GET_MORE)) 
+                       control[5]=0x02c;//search by the mac address field
+           
+           val=0x8000;//busy ,status5[15]
+           while(val&0x8000){          //check busy ?
+                 ifx_sw_read(0x125, &val);
+               }
+               ifx_sw_write(0x11a,control[0]); 
+               ifx_sw_write(0x11b,control[1]); 
+               ifx_sw_write(0x11c,control[2]); 
+               ifx_sw_write(0x11d,control[3]); 
+               ifx_sw_write(0x11e,control[4]); 
+               ifx_sw_write(0x11f,control[5]); 
+           val=0x8000;//busy ,status5[15]
+           while(val&0x8000){          //check busy ?
+                 ifx_sw_read(0x125, &val);
+               }       
+           val=((val&0x7000)>>12);//result ,status5[14:12]
+           mMACENTRY->result=val;
+   
+           if (!val) {
+                       printk(" Command OK!! \n");
+                       if ((cmd==ADM_SW_IOCTL_MACENTRY_GET_INIT)||(cmd==ADM_SW_IOCTL_MACENTRY_GET_MORE)) {
+                                       ifx_sw_read(0x120,&(status[0]));        
+                                       ifx_sw_read(0x121,&(status[1]));        
+                                       ifx_sw_read(0x122,&(status[2]));        
+                                       ifx_sw_read(0x123,&(status[3]));        
+                                       ifx_sw_read(0x124,&(status[4]));        
+                                       ifx_sw_read(0x125,&(status[5]));        
+               
+                                       
+                                       mMACENTRY->mac_addr[0]=(status[0]&0x00ff)       ;
+                                       mMACENTRY->mac_addr[1]=(status[0]&0xff00)>>8    ;
+                                       mMACENTRY->mac_addr[2]=(status[1]&0x00ff)    ;
+                                       mMACENTRY->mac_addr[3]=(status[1]&0xff00)>>8 ;
+                                       mMACENTRY->mac_addr[4]=(status[2]&0x00ff)    ;
+                                       mMACENTRY->mac_addr[5]=(status[2]&0xff00)>>8 ;
+                                       mMACENTRY->fid=(status[3]&0xf);
+                                       mMACENTRY->portmap=((status[3]>>4)&0x3f);
+                                       if (status[5]&0x2) {//static info_ctrl //status5[1]????
+                                               mMACENTRY->ctrl.info_ctrl=(status[4]&0x00ff);
+                                               mMACENTRY->info_type=1;
+                                                       }
+                                       else {//not static age_timer
+                                               mMACENTRY->ctrl.age_timer=(status[4]&0x00ff);
+                                               mMACENTRY->info_type=0;
+                                                       }
+//status5[13]????                                      mMACENTRY->occupy=(status[5]&0x02)>>1;//status5[1]
+                                       mMACENTRY->occupy=(status[5]&0x02000)>>13;//status5[13] ???
+                                       mMACENTRY->bad=(status[5]&0x04)>>2;//status5[2]
+                               }//if ((cmd==ADM_SW_IOCTL_MACENTRY_GET_INIT)||(cmd==ADM_SW_IOCTL_MACENTRY_GET_MORE)) 
+                       
+               }
+           else if (val==0x001)  
+                printk(" All Entry Used!! \n");
+            else if (val==0x002) 
+                printk("  Entry Not Found!! \n");
+            else if (val==0x003) 
+                printk(" Try Next Entry!! \n");
+            else if (val==0x005)  
+                printk(" Command Error!! \n");   
+            else   
+                printk(" UnKnown Error!! \n");
+                
+            copy_to_user((PMACENTRY)args, mMACENTRY,sizeof(MACENTRY));    
+                
+           break;  
+        case ADM_SW_IOCTL_FILTER_ADD:
+        case ADM_SW_IOCTL_FILTER_DEL:
+        case ADM_SW_IOCTL_FILTER_GET:
+
+            uPROTOCOLFILTER = (PPROTOCOLFILTER)kmalloc(sizeof(PROTOCOLFILTER), GFP_KERNEL);
+            rtval = copy_from_user(uPROTOCOLFILTER, (PPROTOCOLFILTER)args, sizeof(PROTOCOLFILTER));
+            if (rtval != 0)
+            {
+                printk("ADM_SW_IOCTL_FILTER_ADD: copy from user FAILED!! \n");
+                return (-EFAULT);
+            }
+            
+               if(cmd==ADM_SW_IOCTL_FILTER_DEL) {      //delete filter
+                       uPROTOCOLFILTER->ip_p=00;       //delet filter
+                       uPROTOCOLFILTER->action=00;     //delete filter
+               }                                       //delete filter
+
+            ifx_sw_read(((uPROTOCOLFILTER->protocol_filter_num/2)+0x68), &val);//rx68~rx6b,protocol filter0~7  
+
+               if (((uPROTOCOLFILTER->protocol_filter_num)%2)==00){    
+                       if(cmd==ADM_SW_IOCTL_FILTER_GET) uPROTOCOLFILTER->ip_p= val&0x00ff;//get filter ip_p
+                               else val=(val&0xff00)|(uPROTOCOLFILTER->ip_p);//set filter ip_p
+               }
+               else {
+                       if(cmd==ADM_SW_IOCTL_FILTER_GET) uPROTOCOLFILTER->ip_p= (val>>8);//get filter ip_p
+                               else val=(val&0x00ff)|((uPROTOCOLFILTER->ip_p)<<8);//set filter ip_p
+               }       
+            if(cmd!=ADM_SW_IOCTL_FILTER_GET) ifx_sw_write(((uPROTOCOLFILTER->protocol_filter_num/2)+0x68), val);//write rx68~rx6b,protocol filter0~7   
+                       
+            ifx_sw_read(0x95, &val);   //protocol filter action
+            if(cmd==ADM_SW_IOCTL_FILTER_GET) {
+                       uPROTOCOLFILTER->action= ((val>>(uPROTOCOLFILTER->protocol_filter_num*2))&0x3);//get filter action
+                       copy_to_user((PPROTOCOLFILTER)args, uPROTOCOLFILTER, sizeof(PROTOCOLFILTER));
+               
+               }
+               else {
+                       val=(val&(~(0x03<<(uPROTOCOLFILTER->protocol_filter_num*2))))|(((uPROTOCOLFILTER->action)&0x03)<<(uPROTOCOLFILTER->protocol_filter_num*2));
+  //                   printk("%d----\n",val);
+                       ifx_sw_write(0x95, val);        //write protocol filter action          
+               }
+               
+            break;
+//adm6996i  
+
+        /* others */
+        default:
+            return -EFAULT;
+    }
+    /* end of switch */
+    return 0;
+}
+
+/* Santosh: handle IGMP protocol filter ADD/DEL/GET */
+int adm_process_protocol_filter_request (unsigned int cmd, PPROTOCOLFILTER uPROTOCOLFILTER)
+{
+    unsigned int val;          //6996i
+
+       if(cmd==ADM_SW_IOCTL_FILTER_DEL) {      //delete filter
+       uPROTOCOLFILTER->ip_p=00;       //delet filter
+       uPROTOCOLFILTER->action=00;     //delete filter
+       }                                       //delete filter
+
+    ifx_sw_read(((uPROTOCOLFILTER->protocol_filter_num/2)+0x68), &val);//rx68~rx6b,protocol filter0~7  
+
+    if (((uPROTOCOLFILTER->protocol_filter_num)%2)==00){       
+       if(cmd==ADM_SW_IOCTL_FILTER_GET) uPROTOCOLFILTER->ip_p= val&0x00ff;//get filter ip_p
+        else val=(val&0xff00)|(uPROTOCOLFILTER->ip_p);//set filter ip_p
+    }
+    else {
+       if(cmd==ADM_SW_IOCTL_FILTER_GET) uPROTOCOLFILTER->ip_p= (val>>8);//get filter ip_p
+       else val=(val&0x00ff)|((uPROTOCOLFILTER->ip_p)<<8);//set filter ip_p
+    }  
+    if(cmd!=ADM_SW_IOCTL_FILTER_GET) ifx_sw_write(((uPROTOCOLFILTER->protocol_filter_num/2)+0x68), val);//write rx68~rx6b,protocol filter0~7   
+                       
+       ifx_sw_read(0x95, &val);        //protocol filter action
+    if(cmd==ADM_SW_IOCTL_FILTER_GET) {
+               uPROTOCOLFILTER->action= ((val>>(uPROTOCOLFILTER->protocol_filter_num*2))&0x3);//get filter action
+    }
+    else {
+       val=(val&(~(0x03<<(uPROTOCOLFILTER->protocol_filter_num*2))))|(((uPROTOCOLFILTER->action)&0x03)<<(uPROTOCOLFILTER->protocol_filter_num*2));
+        ifx_sw_write(0x95, val);       //write protocol filter action          
+    }
+               
+       return 0;
+}
+
+
+/* Santosh: function for MAC ENTRY ADD/DEL/GET */
+
+int adm_process_mac_table_request (unsigned int cmd, PMACENTRY mMACENTRY)
+{
+    unsigned int rtval;
+    unsigned int val;          //6996i
+    unsigned int control[6] ;  //6996i
+    unsigned int status[6] ;   //6996i
+
+       // printk ("adm_process_mac_table_request: enter\n");   
+
+    control[0]=(mMACENTRY->mac_addr[1]<<8)+mMACENTRY->mac_addr[0]     ; 
+    control[1]=(mMACENTRY->mac_addr[3]<<8)+mMACENTRY->mac_addr[2]      ;         
+    control[2]=(mMACENTRY->mac_addr[5]<<8)+mMACENTRY->mac_addr[4]     ;
+    control[3]=(mMACENTRY->fid&0xf)+((mMACENTRY->portmap&0x3f)<<4);
+
+    if (((mMACENTRY->info_type)&0x01)) control[4]=(mMACENTRY->ctrl.info_ctrl)+0x1000; //static ,info control
+               else    control[4]=((mMACENTRY->ctrl.age_timer)&0xff);//not static ,agetimer
+               if (cmd==ADM_SW_IOCTL_MACENTRY_GET_INIT) {      
+                 //initial  the pointer to the first address   
+                  val=0x8000;//busy ,status5[15]
+                  while(val&0x8000){           //check busy ?
+                  ifx_sw_read(0x125, &val);
+               }    
+               control[5]=0x030;//initial the first address    
+               ifx_sw_write(0x11f,control[5]);
+                                               
+                                       
+                                  val=0x8000;//busy ,status5[15]
+                                  while(val&0x8000){           //check busy ?
+                                         ifx_sw_read(0x125, &val);
+                                       }               
+                       
+                  }    //if (cmd==ADM_SW_IOCTL_MACENTRY_GET_INIT)                                                              
+           if (cmd==ADM_SW_IOCTL_MACENTRY_ADD) control[5]=0x07;//create a new address
+               else if (cmd==ADM_SW_IOCTL_MACENTRY_DEL) control[5]=0x01f;//erased an existed address
+               else if ((cmd==ADM_SW_IOCTL_MACENTRY_GET_INIT)||(cmd==ADM_SW_IOCTL_MACENTRY_GET_MORE)) 
+                       control[5]=0x02c;//search by the mac address field
+           
+           val=0x8000;//busy ,status5[15]
+           while(val&0x8000){          //check busy ?
+                 ifx_sw_read(0x125, &val);
+               }
+               ifx_sw_write(0x11a,control[0]); 
+               ifx_sw_write(0x11b,control[1]); 
+               ifx_sw_write(0x11c,control[2]); 
+               ifx_sw_write(0x11d,control[3]); 
+               ifx_sw_write(0x11e,control[4]); 
+               ifx_sw_write(0x11f,control[5]); 
+           val=0x8000;//busy ,status5[15]
+           while(val&0x8000){          //check busy ?
+                 ifx_sw_read(0x125, &val);
+               }       
+           val=((val&0x7000)>>12);//result ,status5[14:12]
+           mMACENTRY->result=val;
+   
+           if (!val) {
+                       printk(" Command OK!! \n");
+                       if ((cmd==ADM_SW_IOCTL_MACENTRY_GET_INIT)||(cmd==ADM_SW_IOCTL_MACENTRY_GET_MORE)) {
+                                       ifx_sw_read(0x120,&(status[0]));        
+                                       ifx_sw_read(0x121,&(status[1]));        
+                                       ifx_sw_read(0x122,&(status[2]));        
+                                       ifx_sw_read(0x123,&(status[3]));        
+                                       ifx_sw_read(0x124,&(status[4]));        
+                                       ifx_sw_read(0x125,&(status[5]));        
+               
+                                       
+                                       mMACENTRY->mac_addr[0]=(status[0]&0x00ff)       ;
+                                       mMACENTRY->mac_addr[1]=(status[0]&0xff00)>>8    ;
+                                       mMACENTRY->mac_addr[2]=(status[1]&0x00ff)    ;
+                                       mMACENTRY->mac_addr[3]=(status[1]&0xff00)>>8 ;
+                                       mMACENTRY->mac_addr[4]=(status[2]&0x00ff)    ;
+                                       mMACENTRY->mac_addr[5]=(status[2]&0xff00)>>8 ;
+                                       mMACENTRY->fid=(status[3]&0xf);
+                                       mMACENTRY->portmap=((status[3]>>4)&0x3f);
+                                       if (status[5]&0x2) {//static info_ctrl //status5[1]????
+                                               mMACENTRY->ctrl.info_ctrl=(status[4]&0x00ff);
+                                               mMACENTRY->info_type=1;
+                                                       }
+                                       else {//not static age_timer
+                                               mMACENTRY->ctrl.age_timer=(status[4]&0x00ff);
+                                               mMACENTRY->info_type=0;
+                                                       }
+//status5[13]????                                      mMACENTRY->occupy=(status[5]&0x02)>>1;//status5[1]
+                                       mMACENTRY->occupy=(status[5]&0x02000)>>13;//status5[13] ???
+                                       mMACENTRY->bad=(status[5]&0x04)>>2;//status5[2]
+                               }//if ((cmd==ADM_SW_IOCTL_MACENTRY_GET_INIT)||(cmd==ADM_SW_IOCTL_MACENTRY_GET_MORE)) 
+                       
+               }
+           else if (val==0x001)  
+                printk(" All Entry Used!! \n");
+            else if (val==0x002) 
+                printk("  Entry Not Found!! \n");
+            else if (val==0x003) 
+                printk(" Try Next Entry!! \n");
+            else if (val==0x005)  
+                printk(" Command Error!! \n");   
+            else   
+                printk(" UnKnown Error!! \n");
+
+       // printk ("adm_process_mac_table_request: Exit\n");    
+       return 0;
+}
+
+/* Santosh: End of function for MAC ENTRY ADD/DEL*/
+struct file_operations adm_ops =
+{
+    read: adm_read,
+    write: adm_write,
+    open: adm_open,
+    release: adm_release,
+    ioctl: adm_ioctl
+};
+
+int adm_proc(char *buf, char **start, off_t offset, int count, int *eof, void *data)
+{
+    int len = 0;
+
+    len += sprintf(buf+len, " ************ Registers ************ \n");
+    *eof = 1;
+    return len;
+}
+
+int __init init_adm6996_module(void)
+{
+    unsigned int val = 000;
+    unsigned int val1 = 000;
+
+    printk("Loading ADM6996 driver... \n");
+
+    /* if running on adm5120 */
+    /* set GPIO 0~2 as adm6996 control pins */
+    //outl(0x003f3f00, 0x12000028);
+    /* enable switch port 5 (MII) as RMII mode (5120MAC <-> 6996MAC) */
+    //outl(0x18a, 0x12000030);
+    /* group adm5120 port 1 ~ 5 as VLAN0, port 5 & 6(CPU) as VLAN1 */
+    //outl(0x417e, 0x12000040);
+    /* end adm5120 fixup */
+#ifdef ADM6996_MDC_MDIO_MODE //smi mode //000001.joelin
+    register_chrdev(69, "adm6996", &adm_ops);
+    AMAZON_SW_REG(AMAZON_SW_MDIO_CFG) = 0x27be;
+    AMAZON_SW_REG(AMAZON_SW_EPHY) = 0xfc;
+    adm6996_mode=adm6996i;
+    ifx_sw_read(0xa0, &val);
+    ifx_sw_read(0xa1, &val1);
+    val=((val1&0x0f)<<16)|val;
+    printk ("\nADM6996 SMI Mode-");
+    printk ("Chip ID:%5x \n ", val);
+#else    //000001.joelin
+    AMAZON_SW_REG(AMAZON_SW_MDIO_CFG) = 0x2c50;
+    AMAZON_SW_REG(AMAZON_SW_EPHY) = 0xff;
+
+    AMAZON_SW_REG(AMAZON_GPIO_P1_ALTSEL0) &= ~(GPIO_MDIO|GPIO_MDCS|GPIO_MDC);
+    AMAZON_SW_REG(AMAZON_GPIO_P1_ALTSEL1) &= ~(GPIO_MDIO|GPIO_MDCS|GPIO_MDC);
+    AMAZON_SW_REG(AMAZON_GPIO_P1_OD) |= (GPIO_MDIO|GPIO_MDCS|GPIO_MDC);
+  
+    ifx_gpio_init();
+    register_chrdev(69, "adm6996", &adm_ops);
+    mdelay(100);
+
+    /* create proc entries */
+    //  create_proc_read_entry("admide", 0, NULL, admide_proc, NULL);
+
+//joelin adm6996i support start
+    adm6996_mode=adm6996i;
+    ifx_sw_read(0xa0, &val);
+    adm6996_mode=adm6996l;
+    ifx_sw_read(0x200, &val1);
+//  printk ("\n %0x \n",val1);
+    if ((val&0xfff0)==0x1020) {
+        printk ("\n ADM6996I .. \n");
+        adm6996_mode=adm6996i; 
+    }
+    else if ((val1&0xffffff00)==0x71000) {//71010 or 71020
+        printk ("\n ADM6996LC .. \n");
+        adm6996_mode=adm6996lc;        
+    }
+    else  {
+        printk ("\n ADM6996L .. \n");
+        adm6996_mode=adm6996l; 
+    }
+#endif //ADM6996_MDC_MDIO_MODE //smi mode //000001.joelin      
+
+    if ((adm6996_mode==adm6996lc)||(adm6996_mode==adm6996i)){
+#if 0  /* removed by MarsLin */
+        ifx_sw_write(0x29,0xc000);
+        ifx_sw_write(0x30,0x0985);
+#else
+        ifx_sw_read(0xa0, &val);
+        if (val == 0x1021) // for both 6996LC and 6996I, only AB version need the patch
+            ifx_sw_write(0x29, 0x9000);
+        ifx_sw_write(0x30,0x0985);
+#endif
+    }
+//joelin adm6996i support end
+    return 0;
+}
+
+void __exit cleanup_adm6996_module(void)
+{
+    printk("Free ADM device driver... \n");
+
+    unregister_chrdev(69, "adm6996");
+
+    /* remove proc entries */
+    //  remove_proc_entry("admide", NULL);
+}
+
+/* MarsLin, add start */
+#if defined(CONFIG_IFX_NFEXT_AMAZON_SWITCH_PHYPORT) || defined(CONFIG_IFX_NFEXT_AMAZON_SWITCH_PHYPORT_MODULE)
+    #define SET_BIT(reg, mask)         reg |= (mask)
+    #define CLEAR_BIT(reg, mask)       reg &= (~mask)
+    static int ifx_hw_reset(void)
+    {
+        CLEAR_BIT((*AMAZON_GPIO_P0_ALTSEL0),0x2000);
+        CLEAR_BIT((*AMAZON_GPIO_P0_ALTSEL1),0x2000);
+        SET_BIT((*AMAZON_GPIO_P0_OD),0x2000);
+        SET_BIT((*AMAZON_GPIO_P0_DIR), 0x2000);
+       CLEAR_BIT((*AMAZON_GPIO_P0_OUT), 0x2000);
+       mdelay(500);
+       SET_BIT((*AMAZON_GPIO_P0_OUT), 0x2000);
+        cleanup_adm6996_module();
+        return init_adm6996_module();
+    }
+    int (*adm6996_hw_reset)(void) = ifx_hw_reset;
+    EXPORT_SYMBOL(adm6996_hw_reset);
+    EXPORT_SYMBOL(adm6996_mode);
+    int (*adm6996_sw_read)(unsigned int addr, unsigned int *data) = ifx_sw_read;
+    EXPORT_SYMBOL(adm6996_sw_read);
+    int (*adm6996_sw_write)(unsigned int addr, unsigned int data) = ifx_sw_write;
+    EXPORT_SYMBOL(adm6996_sw_write);
+#endif
+/* MarsLin, add end */
+
+/* Santosh: for IGMP proxy/snooping, Begin */
+EXPORT_SYMBOL (adm_process_mac_table_request);
+EXPORT_SYMBOL (adm_process_protocol_filter_request);
+/* Santosh: for IGMP proxy/snooping, End */
+       
+MODULE_DESCRIPTION("ADMtek 6996 Driver");
+MODULE_AUTHOR("Joe Lin <joe.lin@infineon.com>");
+MODULE_LICENSE("GPL");
+
+module_init(init_adm6996_module);
+module_exit(cleanup_adm6996_module);
+
diff --git a/target/linux/amazon-2.6/files/drivers/char/amazon_mei.c b/target/linux/amazon-2.6/files/drivers/char/amazon_mei.c
new file mode 100644 (file)
index 0000000..7efe52e
--- /dev/null
@@ -0,0 +1,7918 @@
+/* ============================================================================
+ * Copyright (C) 2004 -Infineon Technologies AG.
+ *
+ * All rights reserved.
+ * ============================================================================
+ *
+ *============================================================================
+ * Licensed under GNU GPL v2
+ * ============================================================================
+ */
+
+/* ===========================================================================
+ *
+ * File Name:   amazon_mei.c
+ * Author :     Ou Ke
+ *
+ * ===========================================================================
+ *
+ * Project: Amazon
+ *
+ * ===========================================================================
+ * Contents:This file implements the MEI driver for Amazon ADSL/ADSL2+
+ *  controller.
+ *  
+ * ===========================================================================
+ * References: 
+ *
+ */
+
+
+/* ===========================================================================
+ * Revision History:
+ *             12/1/2005 : Ritesh Banerjee
+ *                     - Create a kernel thread kmibpoll to poll for periodic RFC 2662
+ *                     and RFC 3440 counters. Removes the need for user space 
+ *                     adsl_mibpoll_daemon and saves atleast 30KB of RAM.
+ *
+ * $Log$
+ * ===========================================================================
+ */
+
+/*
+ * ===========================================================================
+ *                           INCLUDE FILES
+ * ===========================================================================
+ */
+//000002:fchang 2005/6/2 joelin 04/27/2005 for pcm clock
+//000003:fchang 2005/6/2 Henry added for Amazon-E support
+//165001:henryhsu 2005/9/6 Modify for adsl firmware version 1.2.1.2.0.1 DATA_LED can't flash.
+// 509221:tc.chen 2005/09/22 Reset DFE added when MEI_TO_ARC_CS_DONE not cleared by ARC
+// 603221:tc.chen 2006/03/21 added APIs to support the WEB related parameters for ADSL Statistics
+
+#ifndef EXPORT_SYMTAB
+#define EXPORT_SYMTAB
+#endif
+#define AMAZON_MEI_MIB_RFC3440
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/module.h>               
+#include <linux/version.h>
+#include <linux/types.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <asm/irq.h>
+#include <asm/segment.h>
+#include <asm/semaphore.h>
+#include <linux/init.h>                                  
+#include <linux/ioport.h>
+#include <asm/uaccess.h>                       
+#include <linux/proc_fs.h>
+#include <asm/io.h>
+#include <linux/vmalloc.h>
+#include <linux/delay.h>
+#include <linux/poll.h>
+#include <linux/list.h>
+#include <linux/time.h>
+
+#include <asm/amazon/amazon.h>
+#include <asm/irq.h>
+#include <asm/amazon/irq.h>
+#include <asm/amazon/amazon_mei.h>
+#include <asm/amazon/amazon_mei_app.h>
+#include <asm/amazon/amazon_mei_ioctl.h>
+#include <asm/amazon/amazon_mei_app_ioctl.h>
+
+#define SET_BIT(reg, mask)                  reg |= (mask)
+#define CLEAR_BIT(reg, mask)                reg &= (~mask)
+#define CLEAR_BITS(reg, mask)               CLEAR_BIT(reg, mask)
+#define SET_BITS(reg, mask)                 SET_BIT(reg, mask)
+#define SET_BITFIELD(reg, mask, off, val)   {reg &= (~mask); reg |= (val << off);}
+
+extern void mask_and_ack_amazon_irq(unsigned int irq_nr);
+
+#ifdef AMAZON_CHECK_LINK
+//amazon_tpe.c
+extern int (*adsl_link_notify)(int);
+#endif //AMAZON_CHECK_LINK
+
+// for ARC memory access
+#define WHILE_DELAY 20000
+#define AMAZON_DMA_DEBUG_MUTEX
+
+
+//TODO
+#undef DFE_LOOPBACK
+#define ARC_READY_ACK
+
+static amazon_mei_mib * current_intvl;
+static struct list_head interval_list;
+static amazon_mei_mib * mei_mib;
+
+static int reboot_firsttime=1;//000002:fchang
+
+       //PCM
+#define PCM_CHANNEL_NUM                2       //1 rx, 1 tx
+static pcm_data_struct pcm_data[PCM_CHANNEL_NUM]__attribute__ ((aligned(4)));  //0=tx0, 1=rx0, 2=tx1, 3=rx1
+static u32 pcm_start_addr;
+//#define PCM_HRT_TIME_HZ              4000    //?us
+#define PCM_ACCESS_DEBUG
+static int irqtimes=0;
+#undef DATA_LED_ON_MODE
+#define ADSL_LED_SUPPORT       //joelin for adsl led
+#ifdef ADSL_LED_SUPPORT
+static int firmware_support_led=0; //joelin version check      for adsl led    
+static int stop_led_module=0;  //wakeup and clean led module
+static int led_support_check=0;        //1.1.2.7.1.1
+#endif //ADSL_LED_SUPPORT
+#define IFX_DYING_GASP
+#ifdef IFX_DYING_GASP
+static wait_queue_head_t wait_queue_dying_gasp;        //dying gasp
+//struct tq_struct dying_gasp_task;            //dying gasp
+static wait_queue_head_t wait_queue_uas_poll;  //joelin 04/16/2005
+static u16 unavailable_seconds=0;              //joelin 04/16/2005
+static meidebug lop_debugwr;                           //dying gasp
+#endif //IFX_DYING_GASP
+static int dbg_int=0;
+//#define DEBUG_ACCESS_DELAY   for(dbg_int=0;dbg_int<100;dbg_int++){;}
+#define DEBUG_ACCESS_DELAY
+static u8 sampledata[512];
+static int firsttime[PCM_CHANNEL_NUM]={0,1};
+static int num_cmp[PCM_CHANNEL_NUM]={0,0};
+static int pcm_start_loc[PCM_CHANNEL_NUM]={0,0}; 
+
+       // for clearEoC 
+//#define MEI_CLREOC_BUFF_SIZE 512     //double the receive fifo size, bytes
+//static u8 clreoc[MEI_CLREOC_BUFF_SIZE]__attribute__ ((aligned(4)));  //buffer to hold clearEoC data in bytes
+#undef AMAZON_CLEAR_EOC
+#ifdef AMAZON_CLEAR_EOC
+extern void ifx_push_eoc(struct sk_buff * pkt);
+#endif
+static int meiResetArc(void); 
+#define IFX_POP_EOC_DONE       0
+#define IFX_POP_EOC_FAIL       -1
+static struct list_head clreoc_list;
+static amazon_clreoc_pkt * clreoc_pkt;
+#define CLREOC_BUFF_SIZE       12      //number of clreoc commands being buffered
+//static int clreoc_wr=0;
+//static int clreoc_rd=0;              //used to control clreoc circular buffer 
+static wait_queue_head_t wait_queue_clreoc;
+#ifdef ADSL_LED_SUPPORT
+static wait_queue_head_t wait_queue_led;       //adsl led
+static wait_queue_head_t wait_queue_led_polling;// adsl led
+struct tq_struct led_task;                     // adsl led
+static DECLARE_TASK_QUEUE(tq_ifx_led);         // task
+int adsl_led_flash_task(void *ptr);            // adsl led
+#endif //ADSL_LED_SUPPORT
+static void * clreoc_command_pkt=NULL;
+static int clreoc_max_tx_len=0;
+
+// 603221:tc.chen start
+#define ME_HDLC_IDLE 0
+#define ME_HDLC_INVALID_MSG 1
+#define ME_HDLC_MSG_QUEUED 2
+#define ME_HDLC_MSG_SENT 3
+#define ME_HDLC_RESP_RCVD 4
+#define ME_HDLC_RESP_TIMEOUT 5
+#define ME_HDLC_RX_BUF_OVERFLOW 6
+#define ME_HDLC_UNRESOLVED 1
+#define ME_HDLC_RESOLVED 2
+// 603221:tc.chen end
+
+#ifdef LOCK_RETRY
+static int reboot_lock=0;
+#endif
+
+static mib_previous_read mib_pread={0,0,0,0,0,0,0,0,0,0,0,0};
+static mib_flags_pretime mib_pflagtime;// initialized when module loaded
+
+       static u32 ATUC_PERF_LOFS=0;
+       static u32 ATUC_PERF_LOSS=0;
+       static u32 ATUC_PERF_ESS=0;
+       static u32 ATUC_PERF_INITS=0;
+       static u32 ATUR_PERF_LOFS=0;
+       static u32 ATUR_PERF_LOSS=0;
+       static u32 ATUR_PERF_LPR=0;
+       static u32 ATUR_PERF_ESS=0;
+       static u32 ATUR_CHAN_RECV_BLK=0;
+       static u32 ATUR_CHAN_TX_BLK=0;
+       static u32 ATUR_CHAN_CORR_BLK=0;
+       static u32 ATUR_CHAN_UNCORR_BLK=0;
+       //RFC-3440
+       static u32 ATUC_PERF_STAT_FASTR=0;
+       static u32 ATUC_PERF_STAT_FAILED_FASTR=0;
+       static u32 ATUC_PERF_STAT_SESL=0;
+       static u32 ATUC_PERF_STAT_UASL=0;
+       static u32 ATUR_PERF_STAT_SESL=0;
+       static u32 ATUR_PERF_STAT_UASL=0;
+
+       static adslChanPrevTxRate PrevTxRate={0,0};
+       static adslPhysCurrStatus CurrStatus={0,0};
+       static ChanType chantype={0,0};
+       static adslLineAlarmConfProfileEntry AlarmConfProfile={"No Name\0",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1};
+// 603221:tc.chen start
+       static adslFarEndPerfStats FarendStatsData;
+       struct timeval FarendData_acquire_time={0};
+       static u32 adsl_mode,adsl_mode_extend; // adsl mode : adsl/ 2/ 2+
+       static adslInitStats AdslInitStatsData;
+//603221:tc.chen end
+static u32 loop_diagnostics_mode=0;
+static wait_queue_head_t wait_queue_loop_diagnostic;
+#ifdef AMAZON_MEI_MIB_RFC3440
+       static adslLineAlarmConfProfileExtEntry AlarmConfProfileExt={"No Name\0",0,0,0,0,0,0};
+#endif
+
+static int showtime=0;
+static int loop_diagnostics_completed=0;
+//////////////////////////////////////////////////////////////////////////////////
+static int phy_mei_net_init(struct net_device * dev);
+static int interleave_mei_net_init(struct net_device * dev);
+static int fast_mei_net_init(struct net_device * dev);
+static struct net_device_stats * phy_mei_net_get_stats(struct net_device * dev);
+static struct net_device_stats * interleave_mei_net_get_stats(struct net_device * dev);
+static struct net_device_stats * fast_mei_net_get_stats(struct net_device * dev);
+
+typedef struct mei_priv{
+        struct net_device_stats stats;
+}mei_priv;
+
+static struct net_device phy_mei_net = { init: phy_mei_net_init, name: "MEI_PHY"};
+static struct net_device interleave_mei_net = { init: interleave_mei_net_init, name: "MEI_INTL"};
+static struct net_device fast_mei_net = { init: fast_mei_net_init, name: "MEI_FAST"};
+///////////////////////////////////////////////////////////////////////////////////
+
+static int major=AMAZON_MEI_MAJOR;
+
+static struct semaphore mei_sema;
+
+// Mei to ARC CMV count, reply count, ARC Indicator count
+static int indicator_count=0;
+static int cmv_count=0;
+static int reply_count=0;
+static u16 Recent_indicator[MSG_LENGTH];
+
+// Used in interrupt handler as flags
+static int arcmsgav=0;
+static int cmv_reply=0;
+static int cmv_waiting=0;
+
+#define PROC_ITEMS 8
+
+long mei_debug_mode = 0; //509221:tc.chen for adsl firmware debug
+
+//  to wait for arc cmv reply, sleep on wait_queue_arcmsgav;
+static wait_queue_head_t wait_queue_arcmsgav;
+static wait_queue_head_t wait_queue_codeswap;
+static wait_queue_head_t wait_queue_mibdaemon;
+static wait_queue_head_t wait_queue_reboot;
+static u32 * image_buffer=NULL;                // holding adsl firmware image
+static u16 RxMessage[MSG_LENGTH]__attribute__ ((aligned(4)));
+static u16 TxMessage[MSG_LENGTH]__attribute__ ((aligned(4)));                                                                                                               
+static u32 * mei_arc_swap_buff=NULL;           //  holding swap pages
+static ARC_IMG_HDR * img_hdr;
+static int reboot_flag;
+
+#ifdef DFE_LOOPBACK
+#include "arc_pm.h"
+#endif
+
+
+/////////////////               net device                              ///////////////////////////////////////////////////
+static int phy_mei_net_init(struct net_device * dev)
+{
+        //ether_setup(dev);
+        dev->get_stats = phy_mei_net_get_stats;
+        dev->ip_ptr = NULL;
+       dev->type = 94;
+       
+//     dev->mtu=12345;
+       dev->flags=IFF_UP;
+       
+        dev->priv = kmalloc(sizeof(struct mei_priv), GFP_KERNEL);
+        if(dev->priv == NULL)
+                return -ENOMEM;
+        memset(dev->priv, 0, sizeof(struct mei_priv));
+        return 0;
+}
+
+static int interleave_mei_net_init(struct net_device * dev)
+{
+        //ether_setup(dev);
+        dev->get_stats = interleave_mei_net_get_stats;
+        dev->ip_ptr = NULL;
+       dev->type = 124;
+       dev->flags=IFF_UP;
+        dev->priv = kmalloc(sizeof(struct mei_priv), GFP_KERNEL);
+        if(dev->priv == NULL)
+                return -ENOMEM;
+        memset(dev->priv, 0, sizeof(struct mei_priv));
+        return 0;
+}
+
+static int fast_mei_net_init(struct net_device * dev)
+{
+        //ether_setup(dev);
+        dev->get_stats = fast_mei_net_get_stats;
+        dev->ip_ptr = NULL;
+       dev->type = 125;
+       dev->flags=IFF_UP;
+        dev->priv = kmalloc(sizeof(struct mei_priv), GFP_KERNEL);
+        if(dev->priv == NULL)
+                return -ENOMEM;
+        memset(dev->priv, 0, sizeof(struct mei_priv));
+        return 0;
+}
+
+static struct net_device_stats * phy_mei_net_get_stats(struct net_device * dev)
+{
+        struct mei_priv * priv;
+        priv = (struct mei_priv *)dev->priv;
+       // update statistics
+       (priv->stats).rx_packets = ATUR_CHAN_RECV_BLK;
+       (priv->stats).tx_packets = ATUR_CHAN_TX_BLK;
+       (priv->stats).rx_errors = ATUR_CHAN_CORR_BLK + ATUR_CHAN_UNCORR_BLK;
+       (priv->stats).rx_dropped = ATUR_CHAN_UNCORR_BLK;
+       
+        return &(priv->stats);
+}
+
+static struct net_device_stats * interleave_mei_net_get_stats(struct net_device * dev)
+{
+        struct mei_priv * priv;
+        priv = (struct mei_priv *)dev->priv;
+       // update statistics
+       (priv->stats).rx_packets = ATUR_CHAN_RECV_BLK;
+       (priv->stats).tx_packets = ATUR_CHAN_TX_BLK;
+       (priv->stats).rx_errors = ATUR_CHAN_CORR_BLK + ATUR_CHAN_UNCORR_BLK;
+       (priv->stats).rx_dropped = ATUR_CHAN_UNCORR_BLK;
+       
+        return &(priv->stats);
+}
+
+static struct net_device_stats * fast_mei_net_get_stats(struct net_device * dev)
+{
+        struct mei_priv * priv;
+        priv = (struct mei_priv *)dev->priv;
+       // update statistics
+       (priv->stats).rx_packets = ATUR_CHAN_RECV_BLK;
+       (priv->stats).tx_packets = ATUR_CHAN_TX_BLK;
+       (priv->stats).rx_errors = ATUR_CHAN_CORR_BLK + ATUR_CHAN_UNCORR_BLK;
+       (priv->stats).rx_dropped = ATUR_CHAN_UNCORR_BLK;
+       
+        return &(priv->stats);
+}
+/////////////////               mei access Rd/Wr methods       ///////////////////////////////////////////////////
+void meiLongwordWrite(u32 ul_address, u32 ul_data)
+{
+       *((volatile u32 *)ul_address) = ul_data;
+       asm("SYNC");
+       return;
+} //   end of "meiLongwordWrite(..."
+
+void meiLongwordRead(u32 ul_address, u32 *pul_data)
+{
+       *pul_data = *((volatile u32 *)ul_address);
+       asm("SYNC");
+       return;
+} //   end of "meiLongwordRead(..."
+
+MEI_ERROR meiDMAWrite(u32 destaddr, u32 *databuff, u32 databuffsize)
+{
+       u32 *p = databuff;
+       u32 temp;
+       u32 flags;
+
+       if( destaddr & 3)
+               return MEI_FAILURE;
+
+#ifdef AMAZON_DMA_DEBUG_MUTEX
+       save_flags(flags);
+       cli();
+#endif
+               
+
+       //      Set the write transfer address
+       meiLongwordWrite(MEI_XFR_ADDR, destaddr);
+
+       //      Write the data pushed across DMA
+       while (databuffsize--)
+       {
+               temp = *p;
+               if(databuff==(u32 *)TxMessage)  // swap half word
+                       temp = ((temp & 0xffff)<<16) + ((temp & 0xffff0000)>>16);
+               meiLongwordWrite(MEI_DATA_XFR, temp);
+               p++;
+       } //    end of "while(..."
+
+#ifdef AMAZON_DMA_DEBUG_MUTEX
+       restore_flags(flags);   
+#endif
+       
+       return MEI_SUCCESS;
+
+} //   end of "meiDMAWrite(..."
+
+MEI_ERROR meiDMAWrite_16(u32 destaddr, u32 *databuff, u32 databuffsize)
+{
+       u32 *p = databuff;
+       u32 temp;
+       u32 flags;
+
+       if( destaddr & 3)
+               return MEI_FAILURE;
+               
+#ifdef AMAZON_DMA_DEBUG_MUTEX
+       save_flags(flags);
+       cli();
+#endif
+               
+
+       //      Set the write transfer address
+       meiLongwordWrite(MEI_XFR_ADDR, destaddr);
+
+       //      Write the data pushed across DMA
+       while (databuffsize--)
+       {
+               temp = *p;
+               temp = ((temp & 0xffff)<<16) + ((temp & 0xffff0000)>>16);//swap half word
+               meiLongwordWrite(MEI_DATA_XFR, temp);
+               p++;
+       } //    end of "while(..."
+       
+#ifdef AMAZON_DMA_DEBUG_MUTEX
+       restore_flags(flags);
+#endif
+
+       return MEI_SUCCESS;
+
+} //   end of "meiDMAWrite_16(..."
+
+MEI_ERROR meiDMAWrite_8(u32 destaddr, u32 *databuff, u32 databuffsize)
+{
+       u32 *p = databuff;
+       u32 temp;
+       u32 flags;
+
+       if( destaddr & 3)
+               return MEI_FAILURE;
+               
+#ifdef AMAZON_DMA_DEBUG_MUTEX
+       save_flags(flags);
+       cli();
+#endif
+               
+
+       //      Set the write transfer address
+       meiLongwordWrite(MEI_XFR_ADDR, destaddr);
+
+       //      Write the data pushed across DMA
+       while (databuffsize--)
+       {
+               temp = *p;
+               temp = ((temp & 0xff)<<24) + ((temp & 0xff00)<<8)+ ((temp & 0xff0000)>>8)+ ((temp & 0xff000000)>>24);//swap byte
+               meiLongwordWrite(MEI_DATA_XFR, temp);
+               p++;
+       } //    end of "while(..."
+       
+#ifdef AMAZON_DMA_DEBUG_MUTEX
+       restore_flags(flags);
+#endif
+
+       return MEI_SUCCESS;
+
+} //   end of "meiDMAWrite_8(..."
+
+MEI_ERROR meiDMARead(u32 srcaddr, u32 *databuff, u32 databuffsize)
+{
+       u32 *p = databuff;
+       u32 temp;
+       u32 flags;
+       
+       if( srcaddr & 3)
+               return MEI_FAILURE;
+
+#ifdef AMAZON_DMA_DEBUG_MUTEX
+       save_flags(flags);
+       cli();
+#endif
+       
+
+       //      Set the read transfer address
+       meiLongwordWrite(MEI_XFR_ADDR, srcaddr);
+
+       //      Read the data popped across DMA
+       while (databuffsize--)
+       {
+               meiLongwordRead(MEI_DATA_XFR, &temp);
+               if(databuff==(u32 *)RxMessage)  // swap half word
+                       temp = ((temp & 0xffff)<<16) + ((temp & 0xffff0000)>>16);
+               *p=temp;
+               p++;
+       } //    end of "while(..."
+
+#ifdef AMAZON_DMA_DEBUG_MUTEX
+       restore_flags(flags);
+#endif
+
+       return MEI_SUCCESS;
+
+} //   end of "meiDMARead(..."
+
+MEI_ERROR meiDMARead_16(u32 srcaddr, u32 *databuff, u32 databuffsize)
+{
+       u32 *p = databuff;
+       u32 temp;
+       u32 flags;
+       
+       if( srcaddr & 3)
+               return MEI_FAILURE;
+               
+#ifdef AMAZON_DMA_DEBUG_MUTEX
+       save_flags(flags);
+       cli();
+#endif
+               
+
+       //      Set the read transfer address
+       meiLongwordWrite(MEI_XFR_ADDR, srcaddr);
+
+       //      Read the data popped across DMA
+       while (databuffsize--)
+       {
+               meiLongwordRead(MEI_DATA_XFR, &temp);
+               temp = ((temp & 0xffff)<<16) + ((temp & 0xffff0000)>>16);
+               *p=temp;
+               p++;
+       } //    end of "while(..."
+       
+#ifdef AMAZON_DMA_DEBUG_MUTEX
+       restore_flags(flags);
+#endif
+
+       return MEI_SUCCESS;
+
+} //   end of "meiDMARead_16(..."
+
+MEI_ERROR meiDMARead_8(u32 srcaddr, u32 *databuff, u32 databuffsize)
+{
+       u32 *p = databuff;
+       u32 temp;
+       u32 flags;
+       
+       if( srcaddr & 3)
+               return MEI_FAILURE;
+               
+#ifdef AMAZON_DMA_DEBUG_MUTEX
+       save_flags(flags);
+       cli();
+#endif
+               
+
+       //      Set the read transfer address
+       meiLongwordWrite(MEI_XFR_ADDR, srcaddr);
+
+       //      Read the data popped across DMA
+       while (databuffsize--)
+       {
+               meiLongwordRead(MEI_DATA_XFR, &temp);
+               temp = ((temp & 0xff)<<24) + ((temp & 0xff00)<<8)+ ((temp & 0xff0000)>>8)+ ((temp & 0xff000000)>>24);//swap byte
+               *p=temp;
+               p++;
+       } //    end of "while(..."
+       
+#ifdef AMAZON_DMA_DEBUG_MUTEX
+       restore_flags(flags);
+#endif
+
+       return MEI_SUCCESS;
+
+} //   end of "meiDMARead_8(..."
+
+void meiPollForDbgDone(void)
+{
+       u32     query = 0;
+       int     i=0;
+       while (i<WHILE_DELAY)
+       {
+               meiLongwordRead(ARC_TO_MEI_INT, &query);
+               query &= (ARC_TO_MEI_DBG_DONE);
+               if(query)
+                       break;
+               i++;
+               if(i==WHILE_DELAY){
+#ifdef AMAZON_MEI_DEBUG_ON
+                       printk("\n\n PollforDbg fail");
+#endif
+               }
+                       DEBUG_ACCESS_DELAY;
+       } 
+       meiLongwordWrite(ARC_TO_MEI_INT,  ARC_TO_MEI_DBG_DONE);  // to clear this interrupt
+} //   end of "meiPollForDbgDone(..."
+
+MEI_ERROR meiDebugWrite_8(u32 destaddr, u32 *databuff, u32 databuffsize)
+{
+       u32 i;
+       u32 temp = 0x0;
+       u32 address = 0x0;
+       u32 *buffer = 0x0;
+       u32 flags;
+       
+#ifdef AMAZON_DMA_DEBUG_MUTEX
+       save_flags(flags);
+       cli();
+#endif
+       
+
+       //      Open the debug port before DMP memory write
+       meiLongwordRead(MEI_CONTROL, &temp);
+               DEBUG_ACCESS_DELAY;     
+       temp |= (HOST_MSTR);
+       meiLongwordWrite(MEI_CONTROL, temp);
+               DEBUG_ACCESS_DELAY;
+       meiLongwordWrite(MEI_DEBUG_DEC, MEI_DEBUG_DEC_DMP1_MASK);
+               DEBUG_ACCESS_DELAY;
+
+       //      For the requested length, write the address and write the data
+       address = destaddr;
+       buffer = databuff;
+       for (i=0; i < databuffsize; i++)
+       {
+               meiLongwordWrite(MEI_DEBUG_WAD, address);
+                       DEBUG_ACCESS_DELAY;
+               temp=*buffer;
+               temp = ((temp & 0xff)<<24) + ((temp & 0xff00)<<8)+ ((temp & 0xff0000)>>8)+ ((temp & 0xff000000)>>24);//swap byte
+               meiLongwordWrite(MEI_DEBUG_DATA, temp);
+                       DEBUG_ACCESS_DELAY;
+               meiPollForDbgDone();
+               address += 4;
+               buffer++;
+       } //    end of "for(..."
+
+       //      Close the debug port after DMP memory write
+       meiLongwordRead(MEI_CONTROL, &temp);
+               DEBUG_ACCESS_DELAY;
+       temp &= ~(HOST_MSTR);
+       meiLongwordWrite(MEI_CONTROL, temp);
+               DEBUG_ACCESS_DELAY;
+               
+#ifdef AMAZON_DMA_DEBUG_MUTEX
+       restore_flags(flags);
+#endif
+
+       //      Return
+       return MEI_SUCCESS;
+
+} //   end of "meiDebugWrite_8(..."
+
+MEI_ERROR meiDebugRead_8(u32 srcaddr, u32 *databuff, u32 databuffsize)
+{
+       u32 i;
+       u32 temp = 0x0;
+       u32 address = 0x0;
+       u32 *buffer = 0x0;
+       u32 flags;
+       
+#ifdef AMAZON_DMA_DEBUG_MUTEX
+       save_flags(flags);
+       cli();
+#endif
+       
+
+       //      Open the debug port before DMP memory read
+       meiLongwordRead(MEI_CONTROL, &temp);
+               DEBUG_ACCESS_DELAY;
+       temp |= (HOST_MSTR);
+       meiLongwordWrite(MEI_CONTROL, temp);
+               DEBUG_ACCESS_DELAY;
+       meiLongwordWrite(MEI_DEBUG_DEC, MEI_DEBUG_DEC_DMP2_MASK);
+               DEBUG_ACCESS_DELAY;
+
+       //      For the requested length, write the address and read the data
+       address = srcaddr;
+       buffer = databuff;
+       for (i=0; i<databuffsize; i++)
+       {
+               meiLongwordWrite(MEI_DEBUG_RAD, address);
+                       DEBUG_ACCESS_DELAY;
+               meiPollForDbgDone();
+               meiLongwordRead(MEI_DEBUG_DATA, &temp);
+                       DEBUG_ACCESS_DELAY;
+               temp = ((temp & 0xff)<<24) + ((temp & 0xff00)<<8)+ ((temp & 0xff0000)>>8)+ ((temp & 0xff000000)>>24);//swap byte
+               *buffer=temp;
+               address += 4;
+               buffer++;
+       } //    end of "for(..."
+
+       //      Close the debug port after DMP memory read
+       meiLongwordRead(MEI_CONTROL, &temp);
+               DEBUG_ACCESS_DELAY;
+       temp &= ~(HOST_MSTR);
+       meiLongwordWrite(MEI_CONTROL, temp);
+               DEBUG_ACCESS_DELAY;
+               
+#ifdef AMAZON_DMA_DEBUG_MUTEX
+       restore_flags(flags);
+#endif
+
+       //      Return
+       return MEI_SUCCESS;
+
+} //   end of "meiDebugRead_8(..."
+
+MEI_ERROR meiDebugWrite_16(u32 destaddr, u32 *databuff, u32 databuffsize)
+{
+       u32 i;
+       u32 temp = 0x0;
+       u32 address = 0x0;
+       u32 *buffer = 0x0;
+       u32 flags;
+       
+#ifdef AMAZON_DMA_DEBUG_MUTEX
+       save_flags(flags);
+       cli();
+#endif
+       
+
+       //      Open the debug port before DMP memory write
+       meiLongwordRead(MEI_CONTROL, &temp);
+               DEBUG_ACCESS_DELAY;
+       temp |= (HOST_MSTR);
+       meiLongwordWrite(MEI_CONTROL, temp);
+               DEBUG_ACCESS_DELAY;
+       meiLongwordWrite(MEI_DEBUG_DEC, MEI_DEBUG_DEC_DMP1_MASK);
+               DEBUG_ACCESS_DELAY;
+
+       //      For the requested length, write the address and write the data
+       address = destaddr;
+       buffer = databuff;
+       for (i=0; i < databuffsize; i++)
+       {
+               meiLongwordWrite(MEI_DEBUG_WAD, address);
+                       DEBUG_ACCESS_DELAY;
+               temp=*buffer;
+               temp = ((temp & 0xffff)<<16) + ((temp & 0xffff0000)>>16);//swap half word
+               meiLongwordWrite(MEI_DEBUG_DATA, temp);
+                       DEBUG_ACCESS_DELAY;
+               meiPollForDbgDone();
+               address += 4;
+               buffer++;
+       } //    end of "for(..."
+
+       //      Close the debug port after DMP memory write
+       meiLongwordRead(MEI_CONTROL, &temp);
+               DEBUG_ACCESS_DELAY;
+       temp &= ~(HOST_MSTR);
+       meiLongwordWrite(MEI_CONTROL, temp);
+               DEBUG_ACCESS_DELAY;
+               
+#ifdef AMAZON_DMA_DEBUG_MUTEX
+       restore_flags(flags);
+#endif
+
+       //      Return
+       return MEI_SUCCESS;
+
+} //   end of "meiDebugWrite_16(..."
+
+MEI_ERROR meiDebugRead_16(u32 srcaddr, u32 *databuff, u32 databuffsize)
+{
+       u32 i;
+       u32 temp = 0x0;
+       u32 address = 0x0;
+       u32 *buffer = 0x0;
+       u32 flags;
+       
+#ifdef AMAZON_DMA_DEBUG_MUTEX
+       save_flags(flags);
+       cli();
+#endif
+       
+
+       //      Open the debug port before DMP memory read
+       meiLongwordRead(MEI_CONTROL, &temp);
+               DEBUG_ACCESS_DELAY;
+       temp |= (HOST_MSTR);
+       meiLongwordWrite(MEI_CONTROL, temp);
+               DEBUG_ACCESS_DELAY;
+       meiLongwordWrite(MEI_DEBUG_DEC, MEI_DEBUG_DEC_DMP2_MASK);
+               DEBUG_ACCESS_DELAY;
+
+       //      For the requested length, write the address and read the data
+       address = srcaddr;
+       buffer = databuff;
+       for (i=0; i<databuffsize; i++)
+       {
+               meiLongwordWrite(MEI_DEBUG_RAD, address);
+                       DEBUG_ACCESS_DELAY;
+               meiPollForDbgDone();
+               meiLongwordRead(MEI_DEBUG_DATA, &temp);
+                       DEBUG_ACCESS_DELAY;
+               temp = ((temp & 0xffff)<<16) + ((temp & 0xffff0000)>>16);//swap half word
+               *buffer=temp;
+               address += 4;
+               buffer++;
+       } //    end of "for(..."
+
+       //      Close the debug port after DMP memory read
+       meiLongwordRead(MEI_CONTROL, &temp);
+               DEBUG_ACCESS_DELAY;
+       temp &= ~(HOST_MSTR);
+       meiLongwordWrite(MEI_CONTROL, temp);
+               DEBUG_ACCESS_DELAY;
+               
+#ifdef AMAZON_DMA_DEBUG_MUTEX
+       restore_flags(flags);
+#endif
+
+       //      Return
+       return MEI_SUCCESS;
+
+} //   end of "meiDebugRead_16(..."
+
+MEI_ERROR meiDebugWrite(u32 destaddr, u32 *databuff, u32 databuffsize)
+{
+       u32 i;
+       u32 temp = 0x0;
+       u32 address = 0x0;
+       u32 *buffer = 0x0;
+       u32 flags;
+       
+#ifdef AMAZON_DMA_DEBUG_MUTEX
+       save_flags(flags);
+       cli();
+#endif
+       
+
+       //      Open the debug port before DMP memory write
+       meiLongwordRead(MEI_CONTROL, &temp);
+               DEBUG_ACCESS_DELAY;
+       temp |= (HOST_MSTR);
+       meiLongwordWrite(MEI_CONTROL, temp);
+               DEBUG_ACCESS_DELAY;
+       meiLongwordWrite(MEI_DEBUG_DEC, MEI_DEBUG_DEC_DMP1_MASK);
+               DEBUG_ACCESS_DELAY;
+
+       //      For the requested length, write the address and write the data
+       address = destaddr;
+       buffer = databuff;
+       for (i=0; i < databuffsize; i++)
+       {
+               meiLongwordWrite(MEI_DEBUG_WAD, address);
+                       DEBUG_ACCESS_DELAY;
+               temp=*buffer;
+               meiLongwordWrite(MEI_DEBUG_DATA, temp);
+                       DEBUG_ACCESS_DELAY;
+               meiPollForDbgDone();
+               address += 4;
+               buffer++;
+       } //    end of "for(..."
+
+       //      Close the debug port after DMP memory write
+       meiLongwordRead(MEI_CONTROL, &temp);
+               DEBUG_ACCESS_DELAY;
+       temp &= ~(HOST_MSTR);
+       meiLongwordWrite(MEI_CONTROL, temp);
+               DEBUG_ACCESS_DELAY;
+
+#ifdef AMAZON_DMA_DEBUG_MUTEX
+       restore_flags(flags);
+#endif
+
+       //      Return
+       return MEI_SUCCESS;
+
+} //   end of "meiDebugWrite(..."
+
+MEI_ERROR meiDebugRead(u32 srcaddr, u32 *databuff, u32 databuffsize)
+{
+       u32 i;
+       u32 temp = 0x0;
+       u32 address = 0x0;
+       u32 *buffer = 0x0;
+       u32 flags;
+       
+#ifdef AMAZON_DMA_DEBUG_MUTEX
+       save_flags(flags);
+       cli();
+#endif
+       
+
+       //      Open the debug port before DMP memory read
+       meiLongwordRead(MEI_CONTROL, &temp);
+               DEBUG_ACCESS_DELAY;
+       temp |= (HOST_MSTR);
+       meiLongwordWrite(MEI_CONTROL, temp);
+               DEBUG_ACCESS_DELAY;
+       meiLongwordWrite(MEI_DEBUG_DEC, MEI_DEBUG_DEC_DMP2_MASK);
+               DEBUG_ACCESS_DELAY;
+
+       //      For the requested length, write the address and read the data
+       address = srcaddr;
+       buffer = databuff;
+       for (i=0; i<databuffsize; i++)
+       {
+               meiLongwordWrite(MEI_DEBUG_RAD, address);
+                       DEBUG_ACCESS_DELAY;
+               meiPollForDbgDone();
+               meiLongwordRead(MEI_DEBUG_DATA, &temp);
+                       DEBUG_ACCESS_DELAY;
+               *buffer=temp;
+               address += 4;
+               buffer++;
+       } //    end of "for(..."
+
+       //      Close the debug port after DMP memory read
+       meiLongwordRead(MEI_CONTROL, &temp);
+               DEBUG_ACCESS_DELAY;
+       temp &= ~(HOST_MSTR);
+       meiLongwordWrite(MEI_CONTROL, temp);
+               DEBUG_ACCESS_DELAY;
+               
+#ifdef AMAZON_DMA_DEBUG_MUTEX
+       restore_flags(flags);
+#endif
+
+       //      Return
+       return MEI_SUCCESS;
+
+} //   end of "meiDebugRead(..."
+EXPORT_SYMBOL(meiDebugRead);
+
+void meiMailboxInterruptsDisable(void)
+{
+       meiLongwordWrite(ARC_TO_MEI_INT_MASK, 0x0);
+} //   end of "meiMailboxInterruptsDisable(..."
+
+void meiMailboxInterruptsEnable(void)
+{
+       meiLongwordWrite(ARC_TO_MEI_INT_MASK, MSGAV_EN); 
+} //   end of "meiMailboxInterruptsEnable(..."
+
+MEI_ERROR meiMailboxWrite(u16 *msgsrcbuffer, u16 msgsize)
+{
+       int i;
+       u32 arc_mailbox_status = 0x0;
+       u32 temp=0;
+       MEI_ERROR meiMailboxError = MEI_SUCCESS;
+
+       //      Check arc if mailbox write can be initiated
+/*     meiLongwordRead(MEI_TO_ARC_INT, &arc_mailbox_status);
+       if ((arc_mailbox_status & MEI_TO_ARC_MSGAV))
+       {
+               return MEI_MAILBOX_FULL;
+       }
+*/
+       //      Write to mailbox
+       meiMailboxError = meiDMAWrite(MEI_TO_ARC_MAILBOX, (u32*)msgsrcbuffer, msgsize/2);
+       meiMailboxError = meiDMAWrite(MEI_TO_ARC_MAILBOXR, (u32 *)(&temp), 1); 
+
+       //      Notify arc that mailbox write completed
+    &n