--- /dev/null
+#
+# 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))
--- /dev/null
+# 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
--- /dev/null
+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
--- /dev/null
+# 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
--- /dev/null
+#
+# 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
+
--- /dev/null
+/*
+ * 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");
--- /dev/null
+#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
+
--- /dev/null
+/*
+ * 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);
+ }
+}
--- /dev/null
+/*
+ * 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);
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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),®_val,1);
+ g_atm_dev.mib_counter.rx_cells += reg_val;
+ reg_val=0;
+ meiDebugWrite((AR_CELL0_ADDR+itf*4),®_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),®_val,1);
+ g_atm_dev.mib_counter.tx_cells += reg_val;
+ reg_val=0;
+ meiDebugWrite((AT_CELL0_ADDR+itf*4),®_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),®_val,1);
+ g_atm_dev.mib_counter.rx_err_cells += reg_val;
+ reg_val=0;
+ meiDebugWrite((AR_CD_CNT0_ADDR+itf*4),®_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);
+
+
+
+
+
--- /dev/null
+/******************************************************************************
+ 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 |= (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 &= ~(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);
+
--- /dev/null
+/* ============================================================================
+ * 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