# HG changeset patch
# User Matt Mackall <mpm@selenic.com>
# Date 1249941537 18000
# Node ID 9b3b2b2a5478a20ffbf5fa1b36156c6c1533c5cf
# Parent  ac71465c2912ec4c5a56465b8c92b9611b8031d1
imported patch comcerto-drivers-net
* * *
imported patch 28-mii
* * *
imported patch windriver-drivers-net

diff -r e137be04dc4d arch/arm/mach-comcerto/include/mach/msp_ioctl.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/arch/arm/mach-comcerto/include/mach/msp_ioctl.h	Mon Aug 17 16:45:23 2009 -0500
@@ -0,0 +1,56 @@
+/*
+ *  linux/include/asm-arm/arch-comcerto/msp_ioctl.h
+ *
+ *  Copyright (C) 2004,2005 Mindspeed Technologies, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef _MSP_IOCTL_H
+#define _MSP_IOCTL_H
+
+struct MSP_IOCTL_IMAGE
+{
+	void *buf;
+	unsigned long len;
+};
+
+struct MSP_IOCTL_MEM_DUMP
+{
+	void *buf;
+	unsigned long addr;
+	unsigned long len;
+};
+
+#ifdef __KERNEL__
+int msp_ioctl_from_csp(unsigned int cmd, unsigned long arg);
+
+/* Only valid when called from the CSP */
+#define MSP_IOCTL_RESET_MSP_LOAD_FROM_KERNELBUF		_IOR(MSP_IOC_TYPE, 5, struct MSP_IOCTL_IMAGE)
+#define MSP_IOCTL_RESET_MSP_DUMP_TO_KERNELBUF		_IOWR(MSP_IOC_TYPE, 6, struct MSP_IOCTL_IMAGE)
+
+#endif
+
+#define MSP_IOC_TYPE					'm'
+#define MSP_IOCTL_DISPLAY_MSP_FROM_NORFLASH		_IO(MSP_IOC_TYPE, 1)
+#define MSP_IOCTL_RESET_MSP_LOAD_FROM_NORFLASH		_IO(MSP_IOC_TYPE, 2)
+#define MSP_IOCTL_RESET_MSP_LOAD_FROM_BUF		_IOR(MSP_IOC_TYPE, 3, struct MSP_IOCTL_IMAGE)
+#define MSP_IOCTL_RESET_MSP_DUMP_TO_BUF			_IOR(MSP_IOC_TYPE, 4, struct MSP_IOCTL_MEM_DUMP)
+
+#define MSP_DEVICE_NAME		"/dev/msp"
+
+#define MSP_DEVICE_MAJOR_NUM	237         /* this could be whatever you want, as long as it does not conflict with other modules */
+
+#endif /* _MSP_IOCTL_H */
diff -r e137be04dc4d drivers/net/Kconfig
--- a/drivers/net/Kconfig	Mon Aug 10 16:58:57 2009 -0500
+++ b/drivers/net/Kconfig	Mon Aug 17 16:45:23 2009 -0500
@@ -177,6 +177,8 @@
 
 source "drivers/net/phy/Kconfig"
 
+source "drivers/net/comcerto/Kconfig"
+
 #
 #	Ethernet
 #
diff -r e137be04dc4d drivers/net/Makefile
--- a/drivers/net/Makefile	Mon Aug 10 16:58:57 2009 -0500
+++ b/drivers/net/Makefile	Mon Aug 17 16:45:23 2009 -0500
@@ -41,6 +41,8 @@
 
 obj-$(CONFIG_ROADRUNNER) += rrunner.o
 
+obj-$(CONFIG_NET_COMCERTO) += comcerto/
+
 obj-$(CONFIG_HAPPYMEAL) += sunhme.o
 obj-$(CONFIG_SUNLANCE) += sunlance.o
 obj-$(CONFIG_SUNQE) += sunqe.o
diff -r e137be04dc4d drivers/net/comcerto/Kconfig
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/net/comcerto/Kconfig	Mon Aug 17 16:45:23 2009 -0500
@@ -0,0 +1,30 @@
+config NET_COMCERTO
+	bool "Mindspeed Comcerto Network infrastructure"
+	depends on ARCH_M821XX
+	help
+
+config COMCERTO_ETH
+	tristate "Mindspeed's Comcerto Ethernet Driver"
+	depends on  NET_COMCERTO && !COMCERTO_DATA_VED
+	default y
+
+config COMCERTO_FPP
+        tristate " Mindspeed's Fast Packet Processor Driver"
+        depends on (ARCH_M821XX || ARCH_M822XX)
+        default m
+
+config COMCERTO_VED
+        tristate "Mindspeed's Comcerto Control over Virtual Ethernet Driver"
+        depends on  NET_COMCERTO
+        default y
+
+config COMCERTO_MSP_HOTPLUG
+        tristate "MSP firmware reset managed over Virtual Ethernet Driver"
+        depends on  NET_COMCERTO
+        default y
+
+config COMCERTO_MSP_COREDUMP
+        tristate "MSP Coredump Functionality"
+        depends on COMCERTO_VED
+        default y
+
diff -r e137be04dc4d drivers/net/comcerto/Makefile
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/net/comcerto/Makefile	Mon Aug 17 16:45:23 2009 -0500
@@ -0,0 +1,7 @@
+ifeq ($(CONFIG_COMCERTO_ETH), y)
+	obj-y += comcerto_eth.o
+	obj-$(CONFIG_ARCH_M821XX) += comcerto_gemac.o comcerto_gem_AL.o comcerto_mii.o comcerto_ethtool.o comcerto_sysfs.o
+endif
+	obj-$(CONFIG_COMCERTO_FPP) += comcerto_fpp.o
+	obj-$(CONFIG_COMCERTO_VED) += comcerto_ved.o comcerto_smi_part.o comcerto_smi_queue.o comcerto_msp.o
+	obj-$(CONFIG_COMCERTO_MSP_COREDUMP) += comcerto_coredump.o
diff -r e137be04dc4d drivers/net/comcerto/comcerto_coredump.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/net/comcerto/comcerto_coredump.c	Mon Aug 17 16:45:23 2009 -0500
@@ -0,0 +1,320 @@
+/*
+ * drivers/net/comcerto/ comcerto_sysfs.c
+ *
+  *  Copyright (C) 2006 Mindspeed Technologies, Inc.
+  *
+  * This program is free software; you can redistribute it and/or modify
+  * it under the terms of the GNU General Public License as published by
+  * the Free Software Foundation; either version 2 of the License, or
+  * (at your option) any later version.
+  *
+  * This 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/kernel.h>
+#include <linux/vmalloc.h>
+#include <linux/proc_fs.h>
+#include <linux/module.h>
+#include <asm/arch/msp_ioctl.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+
+
+#define MSP_DEVICE_NAME						"/dev/msp"
+#define MSP_DEVICE_MAJOR_NUM			237 /* This could be whatever you want, as long as it does not conflict with other modules */
+#define USER											(1 << 2)
+#define KERNEL										(1 << 3)
+
+
+/*
+ * memcpy_fromio_toxxx - Copies the specified memory to the user space buffer.
+ * @dst: destination buffer
+ * @src: source buffer
+ * @len: size
+ * @flags: flag
+ *
+ * Returns: 0 on success, -1 on error.
+ */
+int memcpy_fromio_toxxx(void *dst, void *src, unsigned long len, u8 flags)
+{
+	unsigned long len_now;
+	void *buf;
+	int rc;
+
+	if (flags & KERNEL)
+	{
+		memcpy_fromio(dst, src, len);
+	}
+	else if (flags & USER)
+	{
+		buf = vmalloc(SZ_128K);
+		
+		if (!buf)
+		{
+			printk(KERN_ERR "error allocating temporary buffer\n");
+			rc = -ENOMEM;
+			goto err;
+		}
+
+		while (len)
+		{
+			len_now = len > SZ_128K ? SZ_128K : len;
+
+			memcpy_fromio(buf, src, len_now);
+
+			if (copy_to_user(dst, buf, len_now))
+			{
+				printk(KERN_ERR "error copying to user\n");
+				rc = -EFAULT;
+				goto err1;
+			}
+
+			src += len_now;
+			dst += len_now;
+			len -= len_now;
+		}
+
+		vfree(buf);
+	}
+
+	return 0;
+
+err1:
+	vfree(buf);
+
+err:
+	return rc;
+}
+
+
+/*
+ * comcerto_dump_msp - Desides from where (memory address) to copy the info.
+ * @addr: base address from where to dump memory
+ * @buf: user space buffer
+ * @len: size
+ * @flags: flag
+ *
+ * Returns: len on success, -1 on error.
+ */
+int comcerto_dump_msp(unsigned long addr, void *buf, unsigned long len, u8 flags)
+{
+	unsigned long aram_size;
+	unsigned long offset;
+	int rc;
+
+	if (!len)
+	{
+		printk(KERN_ERR "MSP coredump invalid size\n");
+		rc = -EINVAL;
+		goto err;
+	}
+
+	aram_size = ARAM_MEMORY_SIZE;
+
+	if ((SDRAM_MSP_MEMORY_PHY <= addr)  && (addr < (SDRAM_MSP_MEMORY_PHY + SDRAM_MSP_MEMORY_SIZE)))
+	{
+		offset = addr - SDRAM_MSP_MEMORY_PHY;
+
+		if ((offset + len) > SDRAM_MSP_MEMORY_SIZE)
+			len = SDRAM_MSP_MEMORY_SIZE - offset;
+
+		rc = memcpy_fromio_toxxx(buf, (void *)SDRAM_MSP_MEMORY_VADDR + offset, len, flags);
+
+		if (rc)
+			goto err;
+	}
+	else if ((COMCERTO_ARAM_BASE <= addr) && (addr < (COMCERTO_ARAM_BASE + aram_size)))
+	{
+		offset = addr - COMCERTO_ARAM_BASE;
+
+		if ((offset + len) > aram_size)
+			len = aram_size - offset;
+
+		rc = memcpy_fromio_toxxx(buf, (void *)ARAM_MEMORY_VADDR + offset, len, flags);
+
+		if (rc)
+			goto err;
+	}
+	else 
+	{
+		printk(KERN_ERR "Invalid coredump memory range %#lx-%#lx\n", addr, addr + len - 1);
+		rc = -EINVAL;
+		goto err;
+	}
+
+	return len;
+
+  err:
+		return rc;
+}
+
+
+/*
+ * msp_ioctl_from_csp - Switches to different ioctl commands and calls appropriate functions. 
+ * @cmd: ioctl command
+ * @arg: buffer address
+ *
+ * Returns: 0 on success, -1 on error.
+ */
+int msp_ioctl_from_csp(unsigned int cmd, unsigned long arg)
+{
+	struct MSP_IOCTL_MEM_DUMP *dump;
+	int rc = 0;
+
+	switch (cmd)
+	{
+		case MSP_IOCTL_RESET_MSP_DUMP_TO_BUF:
+			printk(KERN_INFO "MSP memdump (to user buffer)\n");
+			dump = (struct MSP_IOCTL_MEM_DUMP *) arg;
+			rc = comcerto_dump_msp(dump->addr, dump->buf, dump->len, USER);
+
+			if (rc < 0)
+				break;
+
+			dump->len = rc;
+			rc = 0;
+			break;
+
+		default:
+			printk(KERN_ERR "invalid MSP ioctl (%#x)\n", cmd);
+			rc = -EINVAL;
+			break;
+	}
+
+	return rc;
+}
+
+
+/*
+ * msp_ioctl - Device driver's ioctl function.
+ *
+ * Returns: 0 on success, -1 on error.
+ */
+static int msp_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+	struct MSP_IOCTL_MEM_DUMP dump;
+	int rc;
+
+	printk(KERN_INFO "msp_ioctl(%#lx, %#lx, %#lx)\n", (unsigned long)file, (unsigned long)cmd, arg);
+
+	if (_IOC_TYPE(cmd) != MSP_IOC_TYPE)
+	{
+		rc = -EINVAL;
+		goto err;
+	}
+
+	switch (cmd)
+	{
+		case MSP_IOCTL_RESET_MSP_DUMP_TO_BUF:
+			if (copy_from_user(&dump, (struct MSP_IOCTL_MEM_DUMP *)arg, sizeof(struct MSP_IOCTL_MEM_DUMP)))
+			{
+				printk(KERN_ERR "msp_ioctl: error copying data from user space\n");
+				rc = -EFAULT;
+				goto err;
+			}
+
+			rc = msp_ioctl_from_csp(cmd, (unsigned long)&dump);
+
+			if (rc)
+				goto err;
+
+			if (copy_to_user((struct MSP_IOCTL_MEM_DUMP *)arg, &dump, sizeof(struct MSP_IOCTL_MEM_DUMP)))
+			{
+				printk(KERN_ERR "msp_ioctl: error copying data to user space\n");
+				rc = -EFAULT;
+				goto err;
+			}
+			break;
+		
+		default:
+			rc = -EINVAL;
+			goto err;
+			break;
+	}
+
+	return 0;
+
+  err:
+		return rc;
+}
+
+
+/*
+ * msp_open - Device driver's open function.
+ *
+ * Returns: 0 on success, -1 on error.
+ */
+static int msp_open(struct inode *inode, struct file *file)
+{
+	printk(KERN_INFO "msp_open(%#lx)\n", (unsigned long)file);
+
+	return 0;
+}
+
+
+/*
+ * msp_release - Device driver's release function.
+ *
+ * Returns: 0 on success, -1 on error.
+ */
+static int msp_release(struct inode *inode, struct file *file)
+{
+	printk(KERN_INFO "msp_release(%#lx)\n", (unsigned long)file);
+
+	return 0;
+}
+
+/*
+ * Device driver's file operations structure.
+ */
+struct file_operations msp_fops =
+{
+	.owner = THIS_MODULE,
+	.open = msp_open,
+	.release = msp_release,
+	.ioctl = msp_ioctl,
+};
+
+
+/*
+ * msp_init_module - Device driver's init_module function.
+ *
+ * Returns: 0 on success, -1 on error.
+ */
+static int __init msp_init_module(void)
+{
+	if (register_chrdev(MSP_DEVICE_MAJOR_NUM, MSP_DEVICE_NAME, &msp_fops))
+	{
+		printk(KERN_ERR "Unable to register char device");
+		goto err1;
+	}
+
+	return 0;
+
+	err1:
+		return -1;
+}
+
+
+/*
+ * msp_cleanup_module - Device driver's cleanup_module function.
+ *
+ * Returns: 0 on success, -1 on error.
+ */
+static void __exit msp_cleanup_module(void)
+{
+	unregister_chrdev(MSP_DEVICE_MAJOR_NUM, MSP_DEVICE_NAME);
+}
+
+EXPORT_SYMBOL(msp_ioctl_from_csp);
+
+module_init(msp_init_module);
+module_exit(msp_cleanup_module);
+
diff -r e137be04dc4d drivers/net/comcerto/comcerto_emac.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/net/comcerto/comcerto_emac.c	Mon Aug 17 16:45:23 2009 -0500
@@ -0,0 +1,405 @@
+/*
+ *  linux/drivers/net/comcerto/comcerto_emac.c
+ *
+ *  Copyright (C) 2006 Mindspeed Technologies, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This 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/delay.h>
+
+#include "comcerto_idma.h"
+#include "comcerto_emac.h"
+#include "comcerto_eth.h"
+
+
+#define EMACWKA 1
+/* private prototype functions. */
+static int Init_EMACIP(void *base_address);
+static int Init_EMACIP_IF(void *base_address);
+static int Init_EMAC_DMA(void *base_address);
+static int
+EMAC_Add_ARC_Entry(void *base_address, char *MAC_address, char Index);
+int comcerto_emac_add_ARC_entry(struct net_device *dev, char *MAC_address);
+
+/**************************************************************************
+ *
+ *      NAME:          EMAC_Add_ARC_Entry
+ *
+ *      USAGE:          parameter(s):
+ *							MAC address to add
+ *							Index to ARC Memory
+ *	                      return value
+ *							BOOL
+ *
+ *      DESCRIPTION:	This is a static function, only used by the EMAC driver
+ *
+ *
+ ***************************************************************************/
+static int EMAC_Add_ARC_Entry(void *base_address, char *MAC_address, char Index)
+{
+	unsigned int Temp;
+	char Offset, tmp;
+
+	if (Index >= MAX_ARC_ENTRIES)
+		return 0;
+	/* Odd index */
+	if (Index & 0x01) {
+		tmp = Index - 1;
+		Offset = (tmp << 2) + (tmp << 1);
+		Offset += 4;
+		Temp = *MAC_address++;
+		Temp <<= 8;
+		Temp |= *MAC_address++;
+		writel((readl(EMAC_ARC_TABLE(base_address) + Offset) & \
+					0xFFFF0000) | Temp,
+				(EMAC_ARC_TABLE(base_address) + Offset));
+		Offset += 4;
+		Temp = *MAC_address++;
+		Temp <<= 8;
+		Temp |= *MAC_address++;
+		Temp <<= 8;
+		Temp |= *MAC_address++;
+		Temp <<= 8;
+		Temp |= *MAC_address++;
+		writel(Temp, EMAC_ARC_TABLE(base_address) + Offset);
+	} else {
+		Offset = (Index << 2) + (Index << 1);
+		Temp = *MAC_address++;
+		Temp <<= 8;
+		Temp |= *MAC_address++;
+		Temp <<= 8;
+		Temp |= *MAC_address++;
+		Temp <<= 8;
+		Temp |= *MAC_address++;
+		writel(Temp, EMAC_ARC_TABLE(base_address) + Offset);
+		Offset += 4;
+		Temp = *MAC_address++;
+		Temp <<= 8;
+		Temp |= *MAC_address++;
+		Temp <<= 16;
+		writel((readl(EMAC_ARC_TABLE(base_address) + Offset) & \
+					0x0000FFFF) | Temp,
+				(EMAC_ARC_TABLE(base_address) + Offset));
+	}
+	return 1;
+}
+
+/****************************************************************************
+ *
+ *      NAME:          Init_EMACIP
+ *
+ *      USAGE:          parameter(s):
+ *                                     init_option ---
+ *                                       1: add ARC entry,
+ *                                       0: do NOT add ARC entry
+ *	                      return value:
+ *							none
+ *
+ *      DESCRIPTION:
+ *
+ *
+ *****************************************************************************/
+static int Init_EMACIP(void *base_address)
+{
+	int Status = 1;
+	int i;
+
+	/* EMAC_MACCTRL register : set FullDup (as MII_Conn is high),
+	 * Conn as Force MII, and Soft reset */
+	writel(MAC_MIIRATE | MAC_RESET, EMAC_MACCTRL(base_address));
+	/* wait reset done */
+	while (readl(EMAC_MACCTRL(base_address)) & MAC_RESET);
+
+	/* EMAC_ARC_TABLE init */
+	for (i = 0; i < (6 * MAX_ARC_ENTRIES); i += 4)
+		writel(0x0, EMAC_ARC_TABLE(base_address) + i);
+
+	/* EMAC_ARCCTRL : accept BroadCast only
+	 * (Local MAC address no yet defined) */
+	writel(ARC_COMPENA | ARC_BROADACC, EMAC_ARCCTRL(base_address));
+
+	writel(TX_EN, EMAC_TXCTRL(base_address));
+
+#ifdef DEBUG_IGNORECRC
+	writel(RX_EN | RX_IGNORECRC | RX_SHORTEN | RX_EN_GOOD,
+			EMAC_RXCTRL(base_address));
+#else
+	writel(RX_EN | RX_STRIPCRC, EMAC_RXCTRL(base_address));
+
+#endif
+
+	writel(0x0, EMAC_ARCENA(base_address));
+
+	return Status;
+
+}
+
+/*******************************************************************************
+ *
+ *      NAME:          Init_EMACIP_IF
+ *
+ *      USAGE:          parameter(s):
+ *								none
+ *	                      return value:
+ *								none
+ *
+ *      DESCRIPTION:
+ *
+ *
+ ********************************************************************************/
+static int Init_EMACIP_IF(void *base_address)
+{
+	int Status = 1;
+
+	/* Init EMAC Operation Controlling Register */
+	*(unsigned int *)EMAC_OCR(base_address) = EMAC_OCR_CAMHITL | (0x20 << 16) ;
+
+	if ((u32)base_address == COMCERTO_APB_EMAC1_BASE)
+		*(unsigned int *)EMAC_ICR(base_address) = 0x700;
+
+	*(unsigned int *)EMAC_HOST_FIFO_CONTROL(base_address) = 0x1f;
+	*(unsigned int *)EMAC_HOST_FIFO_TXHIGH(base_address) = 0x000f3;
+	*(unsigned int *)EMAC_HOST_FIFO_TXLOW(base_address) = 0x00F0;
+	*(unsigned int *)EMAC_HOST_FIFO_RXHIGH(base_address) = 0x13;
+	*(unsigned int *)EMAC_HOST_FIFO_RXLOW(base_address) = 0x12;
+
+	*(unsigned int *)EMAC_ARM_FIFO_TXHIGH(base_address) = 0xc0;
+	*(unsigned int *)EMAC_ARM_FIFO_TXLOW(base_address) = 0x20;
+	*(unsigned int *)EMAC_ARM_FIFO_RXHIGH(base_address) = 0xe0;
+	*(unsigned int *)EMAC_ARM_FIFO_RXLOW(base_address) = 0x40;
+	*(unsigned int *)EMAC_ARM_FIFO_CONTROL(base_address) = 0xc;
+
+	comcerto_asb_arbitration(ASA_TC_REQIDMAEN);
+
+	return Status;
+}
+
+/*******************************************************************************
+ *
+ *      NAME:          Init_EMAC_DMA
+ *
+ *      USAGE:          parameter(s):
+ *								none
+ *	                      return value:
+ *								none
+ *
+ *      DESCRIPTION:
+ *
+ *
+ ********************************************************************************/
+static int Init_EMAC_DMA(void * base_address)
+{
+
+	/* Init IDMA */
+	/* Memory to EMAC (Tx) */
+	/* burst size 255, priority */
+	*(unsigned int *)MMEM_BURST(base_address) = (IDMA_BURST_MASK & 0xFF) | (IDMA_PRTY_MASK & 0x0200);
+	*(unsigned int *)MMEM_START(base_address) = 0;
+
+	/* EMAC to Memory (Rx)
+	 * burst size 255, priority 1 */
+	*(unsigned int *)EMMM_BURST(base_address) = (IDMA_BURST_MASK & 0xff) | (IDMA_PRTY_MASK & 0x0100);
+	*(unsigned int *)EMMM_START(base_address) = 0;
+	return 1;
+
+}
+
+int comcerto_emac_init(struct net_device *dev, unsigned int *head)
+{
+	struct eth_priv *priv = (struct eth_priv *)dev->priv;
+	int status = 0;
+	int i;
+	int dma_base = priv->IDMA_baseaddr;
+	int emac_base = priv->EMAC_baseaddr;
+
+
+	*(unsigned int *)EMMM_SOFT_RESET(dma_base) = 0x1;
+	*(unsigned int *)MMEM_SOFT_RESET(dma_base) = 0x1;
+	status = Init_EMACIP_IF((void *)emac_base);
+	status &= Init_EMACIP((void *)emac_base);
+
+	/* Set the latency timer for value.
+	*/
+	for (i = 0; i < 100; i++)
+		udelay(100);
+	/* burst size 255 */
+	*(u32 *)MMEM_BURST(dma_base) = (IDMA_BURST_MASK	& 0xFF);
+	*(u32 *)MMEM_START(dma_base) = 0;
+
+	*(u32 *)EMMM_BURST(dma_base) = (IDMA_BURST_MASK	& 0xFF);
+	*(u32 *)EMMM_START(dma_base) = 0;
+
+	comcerto_emac_add_ARC_entry(dev, (unsigned char *)dev->dev_addr);
+
+	*(unsigned int *)EMMM_HEAD(dma_base) = (unsigned int)head;
+	*(unsigned int *)EMMM_START(dma_base) |= IDMA_START;
+
+	return status;
+
+}
+
+void comcerto_emac_halt(struct net_device *dev)
+{
+	struct eth_priv *priv = (struct eth_priv *)dev->priv;
+	int dma_base = priv->IDMA_baseaddr;
+	int emac_base = priv->EMAC_baseaddr;
+
+	*(unsigned int *)EMMM_SOFT_RESET(dma_base) = 0x1;
+	*(unsigned int *)MMEM_SOFT_RESET(dma_base) = 0x1;
+	/* Clear Bits 4, 19 and 20 of ISR to
+	 * clear any pending EMAC interrupts */
+	Init_EMACIP_IF((void *)emac_base);
+	Init_EMACIP((void *)emac_base);
+	Init_EMAC_DMA((void *)emac_base);
+	return;
+}
+
+
+/* MDIO section */
+
+/****************************************************************************
+ *
+ * MDIO Access
+ *
+ * MDIO bus is connected only to EMAC0
+ * But we can access to PHY for EMAC1 using MDIO bus on EMAC0
+ *
+ *    Station Management Data Control and Address (MD_CA)
+ *    15    14   13   12    11   10   9  8  7  6  5  4   3   2  1  0
+ *   ---------------------------------------------------------------
+ *   | Reserved    |PreSup|Busy| Wr |      PHY     |     Addr      |
+ *   ---------------------------------------------------------------
+ *
+ ****************************************************************************/
+static int emac_wait_mdio_bus(unsigned long emac_base)
+{
+	int i;
+	unsigned short essai;
+	/*if BUSY bit is set, it means that an operation is already performing */
+	for (i = 0 ; i < 100; i++) {
+		essai = __raw_readw(EMAC_MDCA(emac_base));
+		if ((essai & 0x800) == 0)
+			return 0;
+
+		udelay(20); /*If busy, wait 20 us and try again */
+	}
+
+	printk("VED: Warning MDIO bus still busy after 2ms\n");
+	return -1;
+}
+
+int comcerto_emac_mdio_read(struct net_device *dev, int addr, int reg)
+{
+	unsigned short mdca_register = 0;
+
+	struct eth_priv *priv = (struct eth_priv *)dev->priv;
+	int emac_base = priv->EMAC_baseaddr;
+
+	if (emac_wait_mdio_bus(emac_base))
+		return 0;
+
+	mdca_register |= reg;
+	mdca_register |= addr << 5;
+	mdca_register |= 0x800;	/*Set BUSY Bit */
+	__raw_writew(mdca_register, EMAC_MDCA(emac_base));
+
+	/*Wait for answer */
+	if (emac_wait_mdio_bus(emac_base))
+		return 0;
+	else
+		return __raw_readl(EMAC_MDDATA(emac_base));
+
+}
+
+void comcerto_emac_mdio_write(struct net_device *dev, \
+			int addr, int reg, int data)
+{
+	unsigned short mdca_register = 0;
+
+	struct eth_priv *priv = (struct eth_priv *)dev->priv;
+	int emac_base = priv->EMAC_baseaddr;
+
+	if (emac_wait_mdio_bus(emac_base))
+		return ;
+
+	/*Write data into MDDATA register */
+	__raw_writew(data, EMAC_MDDATA(emac_base));
+
+	/*Write MD_CA register */
+	mdca_register |= reg;
+	mdca_register |= addr << 5;
+	mdca_register |= 0x400;	/*Set Wr bit */
+	mdca_register |= 0x700;	/*Set BUSY Bit */
+	__raw_writew(mdca_register, EMAC_MDCA(emac_base));
+}
+
+int comcerto_emac_promiscuousmode(struct net_device *dev, u8 enable)
+{
+	int temp;
+	struct eth_priv *priv = (struct eth_priv *)dev->priv;
+	int emac_base = priv->EMAC_baseaddr;
+
+	if (enable == 1) {
+		/* Activate Promiscuous mode */
+		temp = readl(EMAC_ARCCTRL(emac_base));
+		temp &= ~ARC_COMPENA;
+		temp |= ARC_NEGARC;
+		__raw_writel(temp, EMAC_ARCCTRL(emac_base));
+	} else {
+		/* Desactivate Promiscuous mode */
+		temp = readl(EMAC_ARCCTRL(emac_base));
+		temp &= ~ARC_NEGARC;
+		temp |= ARC_COMPENA;
+		__raw_writel(temp, EMAC_ARCCTRL(emac_base));
+	}
+
+	return 0;
+}
+
+/*******************************************************************************
+ *
+ *      NAME:          add_EMAC_ARC_Entry
+ *
+ *      USAGE:          parameter(s):
+ *						-MAC address
+ *	                      return value:
+ *						Index of ARC memory
+ *						-1 if no update or error
+ *
+ *      DESCRIPTION:
+ *
+ *
+ ********************************************************************************/
+int comcerto_emac_add_ARC_entry(struct net_device *dev, char *MAC_address)
+{
+	struct eth_priv *priv = (struct eth_priv *)dev->priv;
+	int base_address = priv->EMAC_baseaddr;
+	char Index = 2;
+
+	if (EMAC_Add_ARC_Entry((void *)base_address, MAC_address, Index)) {
+		*(unsigned int *)EMAC_ARCENA(base_address) |= (1 << Index);
+		*(unsigned int *)EMAC_ARCCTRL(base_address) |= ARC_COMPENA;
+
+		return Index;
+	} else
+		return -1;
+
+}
+
+int comcerto_emac_check_frame_status(u32 status)
+{
+	return (status & RX_CHECK_ERROR)? 0 : 1;
+}
diff -r e137be04dc4d drivers/net/comcerto/comcerto_emac.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/net/comcerto/comcerto_emac.h	Mon Aug 17 16:45:23 2009 -0500
@@ -0,0 +1,327 @@
+/*
+ *  linux/drivers/net/comcerto/comcerto_gemac.h
+ *
+ *  Copyright (C) 2006 Mindspeed Technologies, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef _COMCERTO_EMAC_H
+#define _COMCERTO_EMAC_H
+
+#include <asm/io.h>
+#include <mach/hardware.h>
+
+#define MAX_ARC_ENTRIES				3
+
+/* ******** EMAC registers and masks ***************** */
+#define EMAC_BASE                               0x000000
+
+/* Arm side FIFO control registers */
+#define EMAC_ARM_FIFO_TXDATABYTE(base)		APB_VADDR(base + 0x4000)
+#define EMAC_ARM_FIFO_RXDATABYTE(base)		APB_VADDR(base + 0x4000)
+#define EMAC_ARM_FIFO_TXDATAHWORD(base)	APB_VADDR(base + 0x8000)
+#define EMAC_ARM_FIFO_RXDATAHWORD(base)	APB_VADDR(base + 0x8000)
+#define EMAC_ARM_FIFO_TXDATAWORD(base)		APB_VADDR(base + 0xC000)
+#define EMAC_ARM_FIFO_RXDATAWORD(base)		APB_VADDR(base + 0xC000)
+
+#define EMAC_ARM_FIFO_CONTROL(base)			APB_VADDR(base + 0x0000)
+#define EMAC_ARM_FIFO_STATUS(base)			APB_VADDR(base + 0x0004)
+#define EMAC_ARM_FIFO_IACK(base)				APB_VADDR(base + 0x0004)
+#define EMAC_ARM_BIST(base)					APB_VADDR(base + 0x0008)
+#define EMAC_ARM_FIFO_TXSIZE(base)			APB_VADDR(base + 0x0014)
+
+#define EMAC_ARM_FIFO_TXHIGH(base)			APB_VADDR(base + 0x0018)
+#define EMAC_ARM_FIFO_TXLOW(base)			APB_VADDR(base + 0x001c)
+#define EMAC_ARM_FIFO_RXSIZE(base)			APB_VADDR(base + 0x0024)
+#define EMAC_ARM_FIFO_RXHIGH(base)			APB_VADDR(base + 0x0028)
+#define EMAC_ARM_FIFO_RXLOW(base)			APB_VADDR(base + 0x002c)
+
+/* ARM fifo control bits */
+#define EMAC_ARM_RXDREQWE			0x0004
+#define EMAC_ARM_TXDREQRE			0x0008
+#define EMAC_ARM_TXCMPLTIE			0x0020
+#define EMAC_ARM_TXFIE				0x0040
+#define EMAC_ARM_TXTHIE				0x0080
+#define EMAC_ARM_RXEIE				0x0100
+#define EMAC_ARM_RXTHIE				0x0200
+#define EMAC_ARM_TXM3IE				0x0400
+#define EMAC_ARM_RXM3IE				0x0800
+#define EMAC_ARM_TXFF_RES			0x1000
+#define EMAC_ARM_RXFF_RES			0x2000
+
+/* Host side FIFO control registers */
+#define EMAC_HOST_FIFO_CONTROL(base)		APB_VADDR(base  + 0xD000)
+#define EMAC_HOST_FIFO_IACK(base)			APB_VADDR(base  + 0xD004)
+#define EMAC_HOST_FIFO_STATUS(base)			APB_VADDR(base  + 0xD004)
+#define EMAC_HOST_FIFO_TXSIZE(base)			APB_VADDR(base  + 0xD010)
+#define EMAC_HOST_FIFO_TXHIGH(base)			APB_VADDR(base  + 0xD014)
+#define EMAC_HOST_FIFO_TXLOW(base)			APB_VADDR(base  + 0xD018)
+#define EMAC_HOST_FIFO_RXSIZE(base)			APB_VADDR(base  + 0xD020)
+#define EMAC_HOST_FIFO_RXHIGH(base)			APB_VADDR(base  + 0xD024)
+#define EMAC_HOST_FIFO_RXLOW(base)			APB_VADDR(base  + 0xD028)
+
+/* Host fifo control bits */
+#define EMAC_HOST_TXFF_EN			0x0001
+#define EMAC_HOST_HBTXRQ_EN			0x0002
+#define EMAC_HOST_RXFF_EN			0x0008
+#define EMAC_HOST_HBRXRQ_EN			0x0010
+#define EMAC_HOST_TXCP_INH			0x0020
+#define EMAC_HOST_TXEIE				0x0100
+#define EMAC_HOST_TXTHIE			0x0200
+#define EMAC_HOST_TXM3IE			0x0400
+#define EMAC_HOST_RXCMPLTIE			0x0800
+#define EMAC_HOST_RXFIE				0x1000
+#define EMAC_HOST_RXTHIE			0x2000
+#define EMAC_HOST_RXM3IE			0x4000
+#define EMAC_HOST_TRGABORTIE			0x8000
+
+/* Memory BIST register masks */
+#define EMAC_RXBIST_RESET			0x00000001
+#define EMAC_RXBIST_TEST			0x00000002
+#define EMAC_RXBIST_DBG				0x00000004
+#define EMAC_RXBIST_RESUME_RTN			0x00000008
+#define EMAC_RXBIST_DONE			0x00000010
+#define EMAC_RXBIST_FAIL			0x00000020
+#define EMAC_RXBIST_START_RTN			0x00000040
+#define EMAC_TXBIST_RESET			0x00000100
+#define EMAC_TXBIST_TEST			0x00000200
+#define EMAC_TXBIST_DBG				0x00000400
+#define EMAC_TXBIST_RESUME_RTN			0x00000800
+#define EMAC_TXBIST_DONE			0x00001000
+#define EMAC_TXBIST_FAIL			0x00002000
+#define EMAC_TXBIST_START_RTN			0x00004000
+
+/* EMAC Operation Controling Register */
+#define EMAC_OCR(base)		APB_VADDR(base + 0xE000)
+#define EMAC_OCR_ROMCKSE			0x00000003
+#define EMAC_OCR_MDCCKSE			0x0000000C
+#define EMAC_OCR_MIIFDL				0x00000010
+#define EMAC_OCR_MII100L			0x00000020
+#define EMAC_OCR_MIILINKL			0x00000040
+#define EMAC_OCR_MIICONN			0x00000080
+#define EMAC_OCR_TESTMODE			0x00000100
+#define EMAC_OCR_CAMHITL			0x00000200
+#define EMAC_OCR_EMACLPBK			0x00000400
+#define EMAC_OCR_RES11				0x00000800
+#define EMAC_OCR_RES12				0x00001000
+#define EMAC_OCR_RES13				0x00002000
+#define EMAC_OCR_RES14				0x00004000
+#define EMAC_OCR_RXPCKSIZE			0x00FF8000
+#define EMAC_OCR_RES24				0x01000000
+#define EMAC_OCR_RES25				0x02000000
+#define EMAC_OCR_RES26				0x04000000
+#define EMAC_OCR_RES27				0x08000000
+#define EMAC_OCR_STSFFREQIE			0x10000000
+#define EMAC_OCR_RXSTATIE			0x20000000
+#define EMAC_OCR_TXSTATIE			0x40000000
+#define EMAC_OCR_MIIRQIE			0x80000000
+
+/* EMAC Input Controlled Register */
+#define EMAC_ICR(base)				APB_VADDR((base + 0xE004))
+#define EMAC_ICR_TXFRMOPT				0x00000007
+
+/* EMAC I/F Interrupt Register Status */
+#define EMAC_IF_INT(base)				APB_VADDR((base +  0xE008))
+#define EMAC_INPUT_STSFFREQIRQ			0x10000000	/* Read Only */
+#define EMAC_INPUT_RXSTATIRQ			0x20000000
+#define EMAC_INPUT_TXSTATIRQ			0x40000000
+#define EMAC_INPUT_MIIRQIRQ			0x80000000
+/* EMAC I/F Interrupt Acknowledge Register (same as previsous) */
+#define EMAC_INPUT_STSFFREQIAK			0x10000000	/* Write Only */
+#define EMAC_INPUT_RXSTATIAK			0x20000000
+#define EMAC_INPUT_TXSTATIAK			0x40000000
+
+/* EMAC Output Status */
+#define EMAC_OUTPUT(base)				APB_VADDR((base  + 0xE00C))
+#define EMAC_OUT_REV_ID				0x0000000F
+#define REV_SIM					0x0000000E
+
+#define EMAC_OUT_INTLINK			0x00000010
+#define EMAC_OUT_CAMLOAD			0x00000020
+
+/* EMAC RX status FIFO depth */
+#define EMAC_RX_STAT_FIFO_DEPTH(base)			APB_VADDR((base +  0xE0100))
+
+/* EMAC RX status FIFO data */
+#define EMAC_RX_STAT_FIFO_DATA(base)			APB_VADDR((base +  0xE020))
+#define EMAC_RX_STAT_TYPE			0x18000000
+#define EMAC_RX_STAT_PKTCNT			0x000000FF
+#define EMAC_RX_STAT_IPSTA			0x03FFFFFF
+
+/* EMAC ARC TABLE */
+#define EMAC_ARC_TABLE(base)				APB_VADDR((base +  0xE200))
+
+/* EMAC IP CSR register */
+#define EMAC_FLOWCTRL_BASE(base)			APB_VADDR((base +  0xE330))
+#define EMAC_FLOWCTRL_PAUSECNT(base)			(EMAC_FLOWCTRL_BASE(base) + 0x00)
+#define EMAC_FLOWCTRL_REMPAUSECNT(base)		(EMAC_FLOWCTRL_BASE(base) + 0x04)
+
+#define EMAC_CTRL_BASE(base)				APB_VADDR((base +  0xE340))
+#define EMAC_MACCTRL(base)				(EMAC_CTRL_BASE(base) + 0x00)
+#define EMAC_ARCCTRL(base)				(EMAC_CTRL_BASE(base) + 0x04)
+#define EMAC_TXCTRL(base)				(EMAC_CTRL_BASE(base)+ 0x08)
+#define EMAC_TXSTATUS(base)				(EMAC_CTRL_BASE(base) + 0x0C)
+#define EMAC_RXCTRL(base)				(EMAC_CTRL_BASE(base) + 0x10)
+#define EMAC_RXSTATUS(base)				(EMAC_CTRL_BASE(base) + 0x14)
+#define EMAC_MDDATA(base)			(EMAC_CTRL_BASE(base) + 0x18)
+#define EMAC_MDCA(base)				(EMAC_CTRL_BASE(base) + 0x1C)
+
+#define EMAC_ARCENA(base)				(EMAC_CTRL_BASE(base) + 0x28)
+
+#define EMAC_PROMCTL(base)				(EMAC_CTRL_BASE(base) + 0x2C)
+#define EMAC_PROMDATA(base)				(EMAC_CTRL_BASE(base) + 0x30)
+
+#define EMAC_MISSCNT(base)			(EMAC_CTRL_BASE(base) + 0x3C)
+
+#define EMAC_RMON_BASE(base)				APB_VADDR((base + 0xE400))
+#define EMAC_CNTDATA(base)				(EMAC_RMON_BASE(base) + 0x00)
+#define EMAC_CNTACC(base)				(EMAC_RMON_BASE(base) + 0x04)
+#define EMAC_TXRMONIE(base)				(EMAC_RMON_BASE(base) + 0x08)
+#define EMAC_RXRMONIE(base)				(EMAC_RMON_BASE(base) + 0x0C)
+
+/* EMAC_MACCTRL  bits */
+#define MAC_HALTREQ		0x0001
+#define MAC_HALTIMM		0x0002
+#define MAC_RESET		0x0004
+#define MAC_FULLDUP		0x0008
+#define MAC_LOOPBACK	        0x0010
+
+#define MAC_CONN_MSK	        0x0060
+#define MAC_AUTORATE	        0x0000
+#define MAC_10MBITS		0x0020
+#define MAC_MIIRATE		0x0040
+
+#define MAC_LOOP10		0x0080
+#define MAC_LNKCHG		0x0100
+#define MAC_RES9		0x0200
+#define MAC_MISSROLL	        0x0400
+#define MAC_RES11		0x0800
+#define MAC_RES12		0x1000
+#define MAC_ENMISSROLL	        0x2000
+#define MAC_RES14		0x4000
+#define MAC_LINK10		0x8000
+
+/* EMAC_ARCCTRL bits */
+
+#define ARC_STATIONACC		0x0001
+#define ARC_GROUPACC		0x0002
+#define ARC_BROADACC		0x0004
+#define ARC_NEGARC		0x0008
+#define ARC_COMPENA		0x0010
+#define ARC_RESERVED		0xFFE0
+
+/* EMAC_TXCTRL bits */
+#define TX_EN			0x0001
+#define TX_HALT			0x0002
+#define TX_NOPAD		0x0004
+#define TX_NOCRC		0x0008
+#define TX_FBACK		0x0010
+#define TX_NOEXDEF		0x0020
+#define TX_SDPAUSE		0x0040
+#define TX_MII10		0x0080
+
+#define TX_EN_UNDER		0x0100
+#define TX_EN_EXDEF		0x0200
+#define TX_EN_LCARR		0x0400
+#define TX_EN_EXCOLL		0x0800
+#define TX_EN_LATECOLL		0x1000
+#define TX_EN_TXPAR		0x2000
+#define TX_EN_COMP		0x4000
+
+/* EMAC_RXCTRL bits */
+#define RX_EN			0x0001
+#define RX_HALT			0x0002
+#define RX_LONGEN		0x0004
+#define RX_SHORTEN		0x0008
+#define RX_STRIPCRC		0x0010
+#define RX_PASSCTL		0x0020
+#define RX_IGNORECRC		0x0040
+#define RX_RES7			0x0080	/* reserved */
+
+#define RX_EN_ALIGN		0x0100
+#define RX_EN_CRCERR		0x0200
+#define RX_EN_OVERFLOW		0x0400
+#define RX_EN_LONGERR		0x0800
+#define RX_RES12		0x1000
+#define RX_EN_RXPAR		0x2000
+#define RX_EN_GOOD		0x4000
+#define RX_RES15		0x8000
+
+
+/* EMAC RX Status (EMAC IP Rx_Stat CSR
+ * bit [29..4] mapped on bits [25..0]) */
+#define RX_STA_LENERR		0x00000001
+#define RX_STA_CTLRCVD		0x00000002
+#define RX_STA_INTRX			0x00000004
+#define RX_STA_RX10			0x00000008
+#define RX_STA_ALIGNERR		0x00000010
+#define RX_STA_CRCERR		0x00000020
+#define RX_STA_OVERFLW		0x00000040
+#define RX_STA_LONGERR		0x00000080
+#define RX_STA_RES12			0x00000100
+#define RX_STA_RXPAR		0x00000200
+#define RX_STA_GOOD			0x00000400
+#define RX_STA_HALTED		0x00000800
+#define RX_STA_RES16			0x00001000
+#define RX_STA_MCAST		0x00002000
+#define RX_STA_BCAST			0x00004000
+#define RX_STA_VLAN			0x00008000
+#define RX_STA_PAUSE			0x00010000
+#define RX_STA_ARCSTA		0x001E0000
+#define RX_STA_ARCSTA_TOSS	0x00000000
+#define RX_STA_ARCSTA_KEEP	0x00100000
+#define RX_STA_ARCENT		0x03E00000
+#define RX_STA_KEEP			0x04000000
+#define RX_STA_TOSS			0x00000000
+
+#define RX_CHECK_ERROR		(RX_STA_CRCERR | RX_STA_OVERFLW | RX_STA_LONGERR | RX_STA_ALIGNERR | RX_STA_RXPAR)
+
+/* EMAC TX Status */
+#define TX_STA_TXCOLL		0x0000000F
+#define TX_STA_EXCOLL		0x00000010
+#define TX_STA_TXDEFER		0x00000020
+#define TX_STA_PAUSED		0x00000040
+#define TX_STA_INTTX		0x00000080
+#define TX_STA_UNDER		0x00000100
+#define TX_STA_EXDEFER		0x00000200
+#define TX_STA_LCARR		0x00000400
+#define TX_STA_TX10		0x00000800
+#define TX_STA_LATECOLL		0x00001000
+#define TX_STA_TXPAR		0x00002000
+#define TX_STA_COMP		0x00004000
+#define TX_STA_TXHALTED		0x00008000
+#define TX_STA_SQERR		0x00010000
+#define TX_STA_MCAST		0x00020000
+#define TX_STA_BCAST		0x00040000
+#define TX_STA_VLAN		0x00080000
+#define TX_STA_MACC		0x00100000
+#define TX_STA_PAUSE		0x00200000
+#define TX_STA_HNR		0x00400000
+
+#define EMAC_IRQ_BIT		0x00000100
+
+#define EMAC_disable_rx(base)\
+	__raw_writel(__raw_readl(EMAC_RXCTRL(base)) & ~RX_EN, EMAC_RXCTRL(base));
+
+#define EMAC_disable_tx(base)\
+	__raw_writel(__raw_readl(EMAC_TXCTRL(base)) & ~TX_EN, EMAC_TXCTRL(base));
+
+#define EMAC_enable_rx(base)\
+	__raw_writel(__raw_readl(EMAC_RXCTRL(base)) | RX_EN, EMAC_RXCTRL(base));
+
+#define EMAC_enable_tx(base)\
+	__raw_writel(__raw_readl(EMAC_TXCTRL(base)) | TX_EN, EMAC_TXCTRL(base));
+#endif /* _COMCERTO_EMAC_H */
diff -r e137be04dc4d drivers/net/comcerto/comcerto_eth.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/net/comcerto/comcerto_eth.c	Mon Aug 17 16:45:23 2009 -0500
@@ -0,0 +1,1918 @@
+ /*
+  *  linux/drivers/net/comcerto/comcerto_eth.c
+  *
+  *  Copyright (C) 2006 Mindspeed Technologies, Inc.
+  *
+  * This program is free software; you can redistribute it and/or modify
+  * it under the terms of the GNU General Public License as published by
+  * the Free Software Foundation; either version 2 of the License, or
+  * (at your option) any later version.
+  *
+  * This 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/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/dma-mapping.h>
+#include <linux/dmapool.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/ethtool.h>
+#include <linux/mii.h>
+#include <linux/phy.h>
+#include <linux/platform_device.h>
+
+
+#include <net/ip.h>
+#include <net/sock.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/delay.h>
+#include <asm/mach/irq.h>
+#include <mach/hardware.h>
+#include <mach/comcerto-devices.h>
+#include <mach/memory.h>
+#include <mach/debug.h>
+#include <net/fpp_ops.h>
+
+#include "comcerto_eth.h"
+#include "comcerto_idma.h"
+#include "comcerto_mii.h"
+
+
+const char comcerto_eth_driver_name[] = "Comcerto Gigabit Ethernet";
+const char comcerto_eth_driver_version[] = "1.0";
+
+extern struct comcerto_eth_platform_data comcerto_gem0_pdata;
+extern struct comcerto_eth_platform_data comcerto_gem1_pdata;
+extern struct ethtool_ops comcerto_ethtool_ops;
+
+static struct fpp_ops eth_fpp_ops = {0, };
+
+#define COMCERTO_TIMEOUT
+#define TX_TIMEOUT      (1*HZ)
+
+#define IP_SEC_HEADROOM	64
+#define PKT_BUF_SZ (2048-IP_SEC_HEADROOM)
+
+#ifdef RX_SCATTERING
+/* minimize fisrt bdec len to 14
+ * (BDESC0_LEN - NET_IP_ALIGN - 16) */
+#define BDESC0_LEN	2
+#endif
+
+
+static void comcerto_eth_release_buffers(struct net_device *dev);
+static int comcerto_eth_init_buffers(struct net_device *dev);
+irqreturn_t comcerto_eth_interrupt(int irq, void *dev_id);
+static void comcerto_adjust_link(struct net_device *dev);
+static void comcerto_reset_task(struct work_struct *work);
+
+extern void comcerto_emac_halt(struct net_device *dev);
+extern int comcerto_emac_init(struct net_device *dev);
+extern int comcerto_emac_mdio_read(struct net_device *dev, int addr, int reg);
+extern void comcerto_emac_mdio_write(struct net_device *dev, int addr, int reg, int data);
+extern int comcerto_emac_promiscuousmode(struct net_device *dev, u8 enable);
+extern void comcerto_emac_halt(struct net_device *dev);
+int comcerto_emac_add_ARC_entry(struct net_device *dev, char *MAC_address);
+extern void comcerto_emac_restart(struct eth_priv *priv);
+extern int comcerto_emac_check_frame_status(u32 status);
+extern void comcerto_emac_checksum(u32 status, struct sk_buff *skb);
+extern void comcerto_emac_restart_tx(struct eth_priv *priv);
+extern irqreturn_t comcerto_gemac_interrupt(int irq, void *dev_id);
+extern void comcerto_gemac_setduplex(struct net_device *dev, int duplex);
+extern void comcerto_gemac_setspeed(struct net_device *dev, int speed);
+#ifdef CONFIG_NET_POLL_CONTROLLER
+static void comcerto_eth_poll_controller(struct net_device *dev);
+#endif
+
+extern void comcerto_init_sysfs(struct net_device *dev);
+
+static void comcerto_invalidate_DC_range(unsigned long vaddr, unsigned long length)
+{
+	unsigned long to = vaddr + length - 1;
+
+	asm(
+		"tst	%0, #32 - 1\n"
+		"bic	%0, %0, #32 - 1\n"
+		"mcrne	p15, 0, %0, c7, c10, 1\n"	/*@ clean D line*/
+		"tst	%1, #32 - 1\n"
+		"bic	%1, %1, #32 - 1\n"
+		"mcrne	p15, 0, %1, c7, c14, 1\n"	/*@ clean & invalidate D line*/
+		"mcrr	p15, 0, %1, %0, c6\n"
+		:
+		: "r" (vaddr), "r" (to)
+		: "cc");
+}
+
+static void comcerto_prefetch_DC_range(unsigned long vaddr, unsigned long length)
+{
+	unsigned long to = vaddr + length - 1;
+
+	asm(
+		"mcrr	p15, 2, %1, %0, c12\n"
+		:
+		: "r" (vaddr), "r" (to)
+		: "cc");
+}
+
+
+static inline void comcerto_edma_disable_int(unsigned int irq)
+{
+	if (irq < 32)
+		__raw_writel(__raw_readl(COMCERTO_INTC_CSP_IRQMASK_0) & \
+				~(1UL << irq), COMCERTO_INTC_CSP_IRQMASK_0);
+	else
+		__raw_writel(__raw_readl(COMCERTO_INTC_CSP_IRQMASK_1) & \
+				~(1UL << (irq - 32)), COMCERTO_INTC_CSP_IRQMASK_1);
+}
+
+static inline void comcerto_edma_enable_int(unsigned int irq)
+{
+	if (irq < 32)
+		__raw_writel(__raw_readl(COMCERTO_INTC_CSP_IRQMASK_0) | \
+				(1UL << irq), COMCERTO_INTC_CSP_IRQMASK_0);
+	else
+		__raw_writel(__raw_readl(COMCERTO_INTC_CSP_IRQMASK_1) | \
+				(1UL << (irq - 32)), COMCERTO_INTC_CSP_IRQMASK_1);
+}
+
+static inline void comcerto_edma_ack_int(unsigned int irq)
+{
+	if (irq < 32)
+		__raw_writel(__raw_readl(COMCERTO_INTC_STATUS_REG_0) & \
+				(1UL << irq), COMCERTO_INTC_STATUS_REG_0);
+	else
+		__raw_writel(__raw_readl(COMCERTO_INTC_STATUS_REG_1) & \
+				(1UL << (irq - 32)), COMCERTO_INTC_STATUS_REG_1);
+}
+
+static inline int comcerto_edma_get_int_status(unsigned int irq)
+{
+	if (irq < 32)
+		return __raw_readl(COMCERTO_INTC_STATUS_REG_0) & (1UL << irq);
+	else
+		return __raw_readl(COMCERTO_INTC_STATUS_REG_1) & (1UL << (irq - 32));
+}
+
+static inline void comcerto_edma_generate_int(unsigned int irq)
+{
+	if (irq < 32)
+		__raw_writel((1UL << irq), COMCERTO_INTC_SET_STATUS_REG_0);
+	else
+		__raw_writel((1UL << (irq - 32)), COMCERTO_INTC_SET_STATUS_REG_1);
+
+}
+
+#ifdef COMCERTO_TIMEOUT
+static void comcerto_reset_task(struct work_struct *work)
+{
+	struct eth_priv *priv = container_of(work, struct eth_priv, reset_task);
+	struct net_device *dev = priv->dev;
+
+	if (dev->flags & IFF_UP)
+		comcerto_emac_restart_tx(priv);
+
+	netif_tx_schedule_all(dev);
+}
+
+static void
+comcerto_tx_timeout(struct net_device *dev)
+{
+	struct eth_priv *priv = netdev_priv(dev);
+	PDEBUG(1, "%s  comcerto_tx_timeout\n", dev->name);
+
+	dev->stats.tx_errors++;
+	schedule_work(&priv->reset_task);
+}
+#endif
+
+static void comcerto_edma_halt_tx(struct net_device *dev)
+{
+	struct eth_priv *priv = netdev_priv(dev);
+	u32 dma_base  = (u32)priv->IDMA_baseaddr;
+
+	if (priv->fast_path_enabled)
+		writel(0, MMEM_START(dma_base));
+
+	writel(0x1, MMEM_SOFT_RESET(dma_base));
+}
+
+static void comcerto_edma_start_tx(struct net_device *dev, void *head)
+{
+	struct eth_priv *priv = netdev_priv(dev);
+	u32 dma_base  = (u32)priv->IDMA_baseaddr;
+
+	writel(phys_desc(priv, head), MMEM_HEAD(dma_base));
+}
+
+
+static void comcerto_edma_halt_rx(struct net_device *dev)
+{
+	struct eth_priv *priv = netdev_priv(dev);
+	u32 dma_base  = (u32)priv->IDMA_baseaddr;
+
+	if (priv->fast_path_enabled)
+		writel(0, EMMM_START(dma_base));
+
+	writel(0x1, EMMM_SOFT_RESET(dma_base));
+}
+
+static void comcerto_edma_start_rx(struct net_device *dev, void *head)
+{
+	struct eth_priv *priv = netdev_priv(dev);
+	u32 dma_base  = (u32)priv->IDMA_baseaddr;
+
+	writel(phys_desc(priv, head), EMMM_HEAD(dma_base));
+	writel(readl(EMMM_START(dma_base)) | IDMA_START, EMMM_START(dma_base));
+}
+
+static void comcerto_edma_init(struct net_device *dev)
+{
+	struct eth_priv *priv = netdev_priv(dev);
+	u32 dma_base  = (u32)priv->IDMA_baseaddr;
+	int i;
+
+	writel(0x1, EMMM_SOFT_RESET(dma_base));
+	writel(0x1, MMEM_SOFT_RESET(dma_base));
+	for (i = 0; i < 100; i++)
+		udelay(100);
+
+	writel(priv->tx_lock_size, MMEM_BURST(dma_base));
+	writel(0x0, MMEM_START(dma_base));
+
+	writel(priv->rx_lock_size, EMMM_BURST(dma_base));
+	writel(0x0, EMMM_START(dma_base));
+}
+
+static phy_interface_t comcerto_get_interface(struct net_device *dev)
+{
+	struct eth_priv *priv = netdev_priv(dev);
+	u32 mii_mode = priv->einfo->mii_config;
+
+	if (priv->einfo->gemac_mode & (GEMAC_SW_CONF)) {
+		switch (mii_mode) {
+		case CONFIG_COMCERTO_USE_GMII:
+			return PHY_INTERFACE_MODE_GMII;
+			break;
+		case CONFIG_COMCERTO_USE_RGMII:
+			return PHY_INTERFACE_MODE_RGMII;
+			break;
+		case CONFIG_COMCERTO_USE_RMII:
+			return PHY_INTERFACE_MODE_RMII;
+			break;
+
+		default:
+		case CONFIG_COMCERTO_USE_MII:
+			return PHY_INTERFACE_MODE_MII;
+			break;
+
+		}
+	} else {
+		/* Bootstrap config read from controller */
+		BUG();
+		return 0;
+	}
+
+}
+
+/* Initializes driver's PHY state, and attaches to the PHY.
+ * Returns 0 on success.
+ */
+static int comcerto_init_phy(struct net_device *dev)
+{
+#ifdef CONFIG_EVM_ROUTER
+	u16 tmp;
+#endif
+	struct eth_priv *priv = netdev_priv(dev);
+	uint gigabit_support =
+		priv->einfo->phy_flags & GEMAC_PHY_1000 ?
+		(SUPPORTED_1000baseT_Full | SUPPORTED_1000baseT_Half) : 0;
+	struct phy_device *phydev;
+	char phy_id[BUS_ID_SIZE];
+	phy_interface_t interface;
+
+	priv->oldlink = 0;
+	priv->oldspeed = 0;
+	priv->oldduplex = -1;
+
+	snprintf(phy_id, BUS_ID_SIZE, PHY_ID_FMT, priv->einfo->bus_id, \
+						priv->einfo->phy_id);
+
+	interface = comcerto_get_interface(dev);
+
+	priv->oldlink = 0;
+	priv->oldspeed = 0;
+	priv->oldduplex = -1;
+
+	sprintf(phy_id, PHY_ID_FMT, priv->einfo->bus_id, priv->einfo->phy_id);
+
+	phydev = phy_connect(dev, phy_id, &comcerto_adjust_link, 0, interface);
+
+	if (IS_ERR(phydev)) {
+		printk(KERN_ERR "%s: Could not attach to PHY\n", dev->name);
+		return PTR_ERR(phydev);
+	}
+
+	/* Remove any features not supported by the controller */
+	phydev->supported |= (COMCERTO_SUPPORTED | gigabit_support);
+	phydev->advertising = phydev->supported;
+
+	priv->phydev = phydev;
+
+#ifdef CONFIG_EVM_ROUTER
+	tmp = phy_read(priv->phydev, COMCERTO_RTL_PHY_LED_ADDR);
+	tmp &= COMCERTO_RTL_PHY_MASK1;
+	tmp |= COMCERTO_RTL_PHY_MASK2;
+	phy_write(priv->phydev, COMCERTO_RTL_PHY_LED_ADDR, tmp);
+#endif
+
+	return 0;
+}
+
+static int comcerto_fast_path_set(struct net_device *dev, unsigned short state)
+{
+	struct eth_priv *priv = netdev_priv(dev);
+	unsigned char msg[20];
+	int rc = 0;
+
+	if (!eth_fpp_ops.write) {
+		printk (KERN_ERR "comcerto_fast_path_set(): fpp ops not registered\n");
+		goto err;
+	}
+
+	memset(msg, 0, 20);
+
+	if (priv->id)
+		msg[0] = 1;
+	else
+		msg[0] = 0;
+
+	if (state) {
+		strcpy(msg + 2, dev->name);
+		memcpy(msg + 14, dev->dev_addr, 6);
+
+		if ((rc = eth_fpp_ops.write(CMD_TX_ENABLE, 20, (unsigned short *)msg)) != 0)
+			goto err;
+
+		if ((rc = eth_fpp_ops.write(CMD_RX_ENABLE, 2, (unsigned short *)msg)) != 0)
+			goto err;
+	} else {
+		if ((rc = eth_fpp_ops.write(CMD_RX_DISABLE, 2, (unsigned short *)msg)) != 0)
+			goto err;
+
+		if ((rc = eth_fpp_ops.write(CMD_TX_DISABLE, 2, (unsigned short *)msg)) != 0)
+			goto err;
+	}
+
+	return 0;
+
+err:
+	return -1;
+}
+
+/* Bring the controller up and running */
+int comcerto_eth_start(struct net_device *dev)
+{
+	struct eth_priv *priv = netdev_priv(dev);
+
+	if (comcerto_eth_init_buffers(dev)) {
+		if (netif_msg_ifup(priv))
+			printk(KERN_ERR "%s: Could not allocate buffer descriptors!\n",
+					dev->name);
+		return -ENOMEM;
+	}
+
+	if (priv->phydev)
+		phy_start(priv->phydev);
+
+	/* Start the controller */
+	comcerto_edma_init(dev);
+	comcerto_edma_start_rx(dev, priv->RxRing[0]);
+	comcerto_edma_start_tx(dev, priv->TxRing[0]);
+
+	return 0;
+
+}
+
+void comcerto_eth_stop(struct net_device *dev)
+{
+	struct eth_priv *priv = netdev_priv(dev);
+	unsigned long flags;
+
+	PDEBUG(1, "%s  comcerto_tx_timeout enter\n", dev->name);
+	/* Lock it down */
+	spin_lock_irqsave(&priv->txlock, flags);
+	spin_lock(&priv->rxlock);
+
+	comcerto_edma_halt_tx(dev);
+	comcerto_edma_halt_rx(dev);
+
+	spin_unlock(&priv->rxlock);
+	spin_unlock_irqrestore(&priv->txlock, flags);
+
+	if (priv->phydev)
+		phy_stop(priv->phydev);
+
+	comcerto_eth_release_buffers(dev);
+	PDEBUG(1, "%s  comcerto_tx_timeout exit\n", dev->name);
+}
+
+static void comcerto_watchdog(unsigned long data)
+{
+	struct net_device *dev = (struct net_device *)data;
+	struct eth_priv *priv = netdev_priv(dev);
+
+	/* Do the rest outside of interrupt context */
+	schedule_work(&priv->watchdog_task);
+}
+
+static void comcerto_watchdog_task(struct work_struct *work)
+{
+	struct eth_priv *priv =
+		container_of(work, struct eth_priv, watchdog_task);
+
+	spin_lock(&priv->txlock);
+
+	/* Force detection of hung controller every watchdog period */
+	if (__raw_readl(MMEM_START(priv->IDMA_baseaddr)) == 1) {
+		if (priv->TxCurrent == virt_desc(priv, \
+			__raw_readl(MMEM_HEAD(priv->IDMA_baseaddr)))) {\
+			comcerto_emac_restart_tx(priv);
+		} else
+			priv->TxCurrent = virt_desc(priv, \
+			__raw_readl(MMEM_HEAD(priv->IDMA_baseaddr)));
+	}
+
+
+	/* Reset the timer */
+	mod_timer(&priv->watchdog_timer, jiffies +  1 * HZ);
+	spin_unlock(&priv->txlock);
+}
+
+int comcerto_eth_open(struct net_device *dev)
+{
+	int rc = 0;
+	struct eth_priv *priv = netdev_priv(dev);
+	u16 tmp;
+
+	napi_enable(&priv->napi);
+	if (priv->fast_path_enabled) {
+		if (priv->id) {
+			priv->EDMAtx_int = IRQ_VDMA1_TX + 32;
+			priv->EDMArx_int = IRQ_VDMA1_RX + 32;
+			priv->IDMA_baseaddr = VDMA1_BASE_VADDR;
+
+			priv->tx_free_ring = TX_FREE_RING1_BASE_VADDR;
+		} else {
+			priv->EDMAtx_int = IRQ_VDMA0_TX + 32;
+			priv->EDMArx_int = IRQ_VDMA0_RX + 32;
+			priv->IDMA_baseaddr = VDMA0_BASE_VADDR;
+
+			priv->tx_free_ring = TX_FREE_RING0_BASE_VADDR;
+		}
+
+		priv->RxMaxRingSize = SLOW_PATH_DESC_NT;
+		priv->TxMaxRingSize = SLOW_PATH_DESC_NT;
+		priv->RxRingSize = SLOW_PATH_DESC_NT;
+		priv->TxRingSize = SLOW_PATH_DESC_NT;
+	} else {
+		priv->EDMAtx_int = priv->slow_path_EDMAtx_int;
+		priv->EDMArx_int = priv->slow_path_EDMArx_int;
+		priv->IDMA_baseaddr = priv->slow_path_IDMA_baseaddr;
+
+		priv->RxRingSize = DEFAULT_RX_DESC_NT;
+		priv->RxMaxRingSize = MAX_RX_DESC_NT;
+		priv->TxRingSize = DEFAULT_TX_DESC_NT;
+		priv->TxMaxRingSize = MAX_TX_DESC_NT;
+	}
+
+	dev->irq = priv->EDMArx_int;
+
+	rc = request_irq(priv->EDMArx_int, comcerto_eth_interrupt, \
+			IRQF_DISABLED, "comcerto_ethRx", dev);
+	if (rc) {
+		printk(KERN_INFO "Failed to get the Rx IRQ = %d\n", priv->EDMArx_int);
+		goto out_rx;
+	}
+
+	rc = request_irq(priv->EDMAtx_int, comcerto_eth_interrupt, \
+			IRQF_DISABLED, "comcerto_ethTx", dev);
+	if (rc) {
+		printk(KERN_INFO "Failed to get the Tx IRQ = %d\n", priv->EDMAtx_int);
+		goto out_tx;
+	}
+
+	if (!priv->fast_path_enabled) {
+		rc = request_irq(priv->EMAC_int, comcerto_gemac_interrupt, \
+					IRQF_DISABLED, "comcerto_gemac", dev);
+		if (rc) {
+			printk(KERN_INFO "Failed to get the Tx IRQ = %d\n", priv->EMAC_int);
+			goto out_gemac;
+		}
+	}
+	set_irq_handler(priv->EDMArx_int, handle_simple_irq);
+	set_irq_handler(priv->EDMAtx_int, handle_simple_irq);
+
+	comcerto_emac_init(dev);
+
+	if (!is_valid_ether_addr(dev->dev_addr)) {
+		printk(KERN_INFO "%s  Invalid MAC address \n", dev->name);
+		rc = -EADDRNOTAVAIL;
+		goto out;
+	}
+
+	comcerto_emac_add_ARC_entry(dev, dev->dev_addr);
+
+	if (!(priv->einfo->phy_flags & GEMAC_NO_PHY)) {
+		rc = comcerto_init_phy(dev);
+		if (rc) {
+			printk(KERN_INFO "%s Failed to get phy = \n", dev->name);
+			goto out_phy;
+		}
+
+		if (priv->einfo->phy_flags & GEMAC_PHY_RGMII_ADD_DELAY) {
+			tmp = phy_read(priv->phydev, 20);
+			/* enable additional delay on Rx_clk and TX_clk */
+			tmp |= 0x0082;
+			phy_write(priv->phydev, 20, tmp);
+			/* sw reset */
+			phy_write(priv->phydev, MII_BMCR, BMCR_RESET);
+			while (phy_read(priv->phydev, MII_BMCR) & BMCR_RESET);
+		}
+	}
+
+	rc = comcerto_eth_start(dev);
+	if (rc)
+		goto out;
+
+	if (priv->fast_path_enabled)
+		comcerto_fast_path_set(dev, 1);
+
+	netif_wake_queue(dev);
+
+	return rc;
+
+out:
+	/* Disconnect from the PHY */
+	if (priv->phydev) {
+		phy_disconnect(priv->phydev);
+		priv->phydev = NULL;
+	}
+
+out_phy:
+	comcerto_emac_halt(dev);
+
+	if (!priv->fast_path_enabled)
+		free_irq(priv->EMAC_int, dev);
+
+out_gemac:
+	free_irq(priv->EDMAtx_int, dev);
+
+out_tx:
+	free_irq(priv->EDMArx_int, dev);
+
+out_rx:
+	napi_disable(&priv->napi);
+	return rc;
+}
+
+
+int comcerto_eth_close(struct net_device *dev)
+{
+	struct eth_priv *priv = netdev_priv(dev);
+
+	napi_disable(&priv->napi);
+	cancel_work_sync(&priv->reset_task);
+	netif_stop_queue(dev);
+
+	if (priv->fast_path_enabled)
+		comcerto_fast_path_set(dev, 0);
+
+	comcerto_eth_stop(dev);
+
+	/* Disconnect from the PHY */
+	if (priv->phydev) {
+		phy_disconnect(priv->phydev);
+		priv->phydev = NULL;
+	}
+
+	comcerto_emac_halt(dev);
+
+	/* Free the IRQs */
+	if (!priv->fast_path_enabled)
+		free_irq(priv->EMAC_int, dev);
+
+	free_irq(priv->EDMAtx_int, dev);
+	free_irq(priv->EDMArx_int, dev);
+
+	return 0;
+}
+
+static int comcerto_set_mac_address(struct net_device *dev, void *addr)
+{
+	struct sockaddr *sa = addr;
+
+	if (!is_valid_ether_addr(sa->sa_data))
+		return -EADDRNOTAVAIL;
+
+	memcpy(dev->dev_addr, sa->sa_data, ETH_ALEN);
+
+	comcerto_emac_add_ARC_entry(dev, (unsigned char *)dev->dev_addr);
+	return 0;
+}
+
+static void comcerto_eth_set_multi(struct net_device *dev)
+{
+	struct dev_mc_list  *mcptr;
+	struct eth_priv *priv = netdev_priv(dev);
+	GEM_DEVICE *gemdev = (GEM_DEVICE *)&priv->gemdev;
+	u8          *addr_start = NULL; /* start of address */
+	MAC_ADDR    hash_addr;          /* hash register structure */
+	u8          temp1, temp2, temp3, temp4, temp5, temp6, temp7, temp8;
+	int         i, result;          /* index into hash register to set.. */
+
+
+	if (dev->flags & IFF_PROMISC) {
+		if (netif_msg_drv(priv))
+			printk(KERN_INFO "%s: Entering promiscuous mode.\n",
+					dev->name);
+		gem_enable_copy_all(gemdev);
+	} else {
+		gem_disable_copy_all(gemdev);
+	}
+
+	/* Enable broadcast frame reception if required. */
+	if (dev->flags  & IFF_BROADCAST) {
+		gem_allow_broadcast(gemdev);
+	} else {
+		if (netif_msg_drv(priv))
+			printk(KERN_INFO "%s: disabling broadcast frame reception.\n",
+					dev->name);
+		gem_no_broadcast(gemdev);
+	}
+
+	if (dev->flags & IFF_ALLMULTI) {
+		/* Set the hash to rx all multicast frames */
+		hash_addr.bottom = 0xFFFFFFFF;
+		hash_addr.top = 0xFFFFFFFF;
+		gem_set_hash(gemdev, &hash_addr);
+		gem_enable_multicast(gemdev);
+	} else if (dev->mc_count > 0) {
+		hash_addr.bottom = 0;
+		hash_addr.top = 0;
+		gem_set_hash(gemdev, &hash_addr);
+
+		mcptr = dev->mc_list;
+
+		for (i = 0; i < dev->mc_count; i++) {
+			addr_start = (unsigned char *)&mcptr->dmi_addr;
+
+			if (netif_msg_drv(priv))
+				printk(KERN_DEBUG \
+					"Adding multicast address \
+					%X:%X:%X:%X:%X:%X to gem filter\n",
+					addr_start[0], addr_start[1], \
+					addr_start[2], addr_start[3], \
+					addr_start[4], addr_start[5]);
+
+			temp1 = addr_start[0] & 0x3F;
+			temp2 = ((addr_start[0] & 0xC0)  >> 6)| ((addr_start[1] & 0x0F) << 2);
+			temp3 = ((addr_start[1] & 0xF0) >> 4) | ((addr_start[2] & 0x03) << 4);
+			temp4 = (addr_start[2] & 0xFC) >> 2 ;
+			temp5 = addr_start[3] & 0x3F;
+			temp6 = ((addr_start[3] & 0xC0) >> 6) | ((addr_start[4] & 0x0F) << 2);
+			temp7 = ((addr_start[4] & 0xF0) >>4) | ((addr_start[5] & 0x03) << 4);
+			temp8 = ((addr_start[5] &0xFC) >> 2);
+
+			result = temp1 ^ temp2 ^ temp3 ^ temp4 ^ temp5 ^ temp6 ^
+				temp7 ^ temp8;
+
+			if (result >= GEM_HASH_REG_BITS)
+				break;
+			else
+				if (result < 32)
+					hash_addr.bottom |= (1 << result);
+				else
+					hash_addr.top |= (1 << (result - 32));
+			mcptr = mcptr->next;
+		}
+		gem_set_hash(gemdev, &hash_addr);
+		gem_enable_multicast(gemdev);
+	}
+
+	if (dev->flags & IFF_LOOPBACK)
+		gem_set_loop(gemdev, LB_LOCAL);
+
+	return;
+}
+
+static int comcerto_eth_change_mtu(struct net_device *dev, int new_mtu)
+{
+
+	return 0;
+}
+
+static void comcerto_eth_release_buffers(struct net_device *dev)
+{
+	struct eth_priv *priv = netdev_priv(dev);
+	struct sk_buff *skb;
+	int i;
+	void *data;
+
+	spin_lock(&priv->rxlock);
+
+	if (priv->fast_path_enabled) {
+		for (i = 0; i < priv->RxRingSize; i++) {
+			if (priv->RxRing[i]->System) {
+				priv->RxRing[i]->FControl = 0;
+				priv->RxRing[i]->FStatus &= ~IDMA_FSTATUS_FRAME_DONE_MASK;
+				priv->RxRing[i]->System = 0;
+
+				data = \
+					(void *)((u32)phys_to_virt(\
+					priv->RxRing[i]->BDesc[0].BPtr) & \
+					~(FPP_SKB_SIZE - 1));
+
+				if (eth_fpp_ops.del_buffer)
+					eth_fpp_ops.del_buffer(data);
+
+				kfree(data);
+			}
+		}
+	} else {
+		for (i = 0; i < priv->RxRingSize; i++) {
+			data = (void *)priv->RxRing[i]->System;
+			if (data) {
+				priv->RxRing[i]->FControl = 0;
+				priv->RxRing[i]->FStatus &= ~IDMA_FSTATUS_FRAME_DONE_MASK;
+				priv->RxRing[i]->System = 0;
+				kfree(data);
+			}
+		}
+	}
+
+	priv->RxtocleanIndex = 0;
+	priv->RxtofillIndex = 0;
+	priv->Rxmarker = priv->RxRingSize - 1;
+	spin_unlock(&priv->rxlock);
+
+	spin_lock(&priv->txlock);
+	for (i = 0; i < priv->TxRingSize; i++) {
+		skb = (struct sk_buff *)priv->TxRing[i]->System;
+		if (skb) {
+			dev_kfree_skb(skb);
+			priv->TxRing[i]->System = 0;
+		}
+	}
+	priv->Txtosend = 0;
+	priv->Txdone = 0;
+	/* always keep one as marker */
+	priv->Txavail = priv->TxRingSize - 1;
+
+	spin_unlock(&priv->txlock);
+}
+
+
+static int comcerto_eth_free_tx_packets(struct net_device *dev)
+{
+	struct eth_priv *priv = netdev_priv(dev);
+	PFDesc ThisFdesc;
+	int tx_cleaned = 0;
+	struct sk_buff *skb;
+
+	spin_lock(&priv->txlock);
+
+	/* Tx done : free corresponding skb */
+	do {
+		comcerto_edma_ack_int(priv->EDMAtx_int);
+
+		/* With zero copy fast path skb's are free using a different queue */
+		if (priv->fast_path_enabled)
+			while ((skb = (struct sk_buff *)priv->tx_free_ring[priv->tx_free_cur]) != NULL) {
+				priv->tx_free_ring[priv->tx_free_cur] = 0;
+				dev_kfree_skb(skb);
+				priv->tx_free_cur = (priv->tx_free_cur + 1) & (TX_FREE_RING_SIZE - 1);
+				priv->tx_free_avail++;
+			}
+
+		while (1) {
+			ThisFdesc = priv->TxRing[priv->Txdone];
+			if (ThisFdesc->FStatus & IDMA_FSTATUS_FRAME_DONE_MASK) {
+
+				if (priv->TxCurrent == ThisFdesc) {
+					priv->TxCurrent = NULL;
+				}
+
+				ThisFdesc->FStatus = 0;
+				ThisFdesc->FControl = IDMA_FCONTROL_IRQEN;
+
+				if (likely((skb = (struct sk_buff *)ThisFdesc->System) != NULL)) {
+					dev->stats.tx_packets++;
+					dev->stats.tx_bytes += ThisFdesc->BDesc[0].BControl & IDMA_BCONTROL_BLEN_MASK;
+
+					if (!priv->fast_path_enabled)
+						dev_kfree_skb(skb);
+
+					ThisFdesc->System = 0;
+				}
+
+				tx_cleaned = 1;
+				priv->Txavail++;
+
+				/* ring buffer empty */
+				if ((priv->fast_path_enabled) && (priv->Txavail == (priv->TxRingSize - 1)))
+					writel(0x0, MMEM_START(priv->IDMA_baseaddr));
+			} else
+				break;
+
+			priv->Txdone = (priv->Txdone + 1) & (priv->TxRingSize - 1);
+		}
+	} while (comcerto_edma_get_int_status(priv->EDMAtx_int));
+
+	/* Recover from running out of Tx resources in xmit_frame */
+	if (unlikely(priv->Txavail && (priv->tx_free_avail || \
+		!priv->fast_path_enabled) && netif_queue_stopped(dev))) {
+
+		netif_wake_queue(dev);
+	}
+
+	spin_unlock(&priv->txlock);
+
+	return tx_cleaned;
+
+}
+
+
+static int comcerto_eth_init_buffers(struct net_device *dev)
+{
+	struct eth_priv *priv = netdev_priv(dev);
+	dma_addr_t desc_addr;
+	u8 *data;
+	int i;
+
+	desc_addr = (dma_addr_t)priv->ARAM_baseaddr_v;
+	for (i = 0; i < priv->RxRingSize; i++) {
+#ifdef IDMA_1K_ADDR_WA
+		/***** 1K boundary IDMA bug ******/
+		if (((u32)desc_addr & 0x3E0) == 0x3E0)
+			desc_addr += sizeof(FDesc);
+		/***** 1K boundary IDMA bug ******/
+#endif
+		if (desc_addr >= ((dma_addr_t)priv->ARAM_baseaddr_v + priv->ARAM_size))	{
+			printk(KERN_ERR "comcerto_eth_init_buffers: unable to allocated Rx ring\n");
+			goto err;
+		}
+		priv->RxRing[i] = (struct tFDesc *)desc_addr;
+		memset(priv->RxRing[i], 0, sizeof(FDesc));
+
+		priv->RxRing[i]->FStatus = 0;
+
+		if (priv->fast_path_enabled) {
+
+			data = kmalloc(FPP_SKB_SIZE, GFP_ATOMIC | GFP_DMA);
+			if (!data) {
+				printk(KERN_ERR "comcerto_eth_init_buffers: unable to allocate buffers\n");
+				goto err;
+			}
+
+			priv->RxRing[i]->System = (u32)data;
+
+			if (eth_fpp_ops.add_buffer)
+				eth_fpp_ops.add_buffer(data);
+
+			comcerto_invalidate_DC_range((u32)data + sizeof(struct list_head), \
+					FPP_SKB_SIZE -	sizeof(struct list_head));
+
+			priv->RxRing[i]->BDesc[0].BPtr = virt_to_phys(data);
+			priv->RxRing[i]->BDesc[0].BControl =  0;
+
+			priv->RxRing[i]->FControl = IDMA_FCONTROL_FREADY | IDMA_FCONTROL_IRQEN;
+		} else {
+			/*Allocate the buffer in DMA zone means L1 cacheable, L2 non-cacheable*/
+			data = kmalloc(SKB_DATA_ALIGN(PKT_BUF_SZ + \
+				priv->align_pad + NET_SKB_PAD) + \
+				sizeof(struct skb_shared_info), GFP_ATOMIC | GFP_DMA);
+			if (!data) {
+				printk(KERN_ERR "comcerto_eth_init_buffers: unable to allocate buffers\n");
+				goto err;
+			}
+
+			comcerto_invalidate_DC_range((u32)data + \
+				IP_SEC_HEADROOM + priv->align_pad + \
+				NET_SKB_PAD, PKT_BUF_SZ-IP_SEC_HEADROOM);
+
+			priv->RxRing[i]->System = (u32)data;
+#ifdef RX_SCATTERING
+			priv->RxRing[i]->BDesc[0].BPtr = virt_to_phys(data + priv->align_pad + NET_SKB_PAD);
+			priv->RxRing[i]->BDesc[0].BControl =  BDESC0_LEN ;
+			priv->RxRing[i]->BDesc[1].BPtr = virt_to_phys(data + priv->align_pad + NET_SKB_PAD + BDESC0_LEN);
+			priv->RxRing[i]->BDesc[1].BControl = PKT_BUF_SZ | IDMA_BCONTROL_BLAST;
+
+			priv->RxRing[i]->FControl = IDMA_FCONTROL_FREADY | IDMA_FCONTROL_IRQEN | IDMA_FCONTROL_SCATTER;
+#else
+			priv->RxRing[i]->BDesc[0].BPtr = virt_to_phys(data + IP_SEC_HEADROOM + priv->align_pad + NET_SKB_PAD);
+			priv->RxRing[i]->BDesc[0].BControl =  0 ;
+
+			priv->RxRing[i]->FControl = IDMA_FCONTROL_FREADY | IDMA_FCONTROL_IRQEN;
+#endif
+		}
+
+		if (i != 0)
+			priv->RxRing[i - 1]->Next = (struct tFDesc *)phys_desc(priv, desc_addr);
+
+		desc_addr += sizeof(FDesc);
+	}
+
+	priv->RxtocleanIndex = 0;
+	priv->RxtofillIndex = 0;
+	priv->Rxmarker = priv->RxRingSize - 1;
+#ifdef NO_IDMA_STOP
+	priv->RxRing[priv->Rxmarker]->Next = (struct tFDesc *)phys_desc(priv, priv->RxRing[priv->Rxmarker]);
+#else
+	priv->RxRing[priv->Rxmarker]->Next = (struct tFDesc *)phys_desc(priv, priv->RxRing[0]);
+#ifdef RX_SCATTERING
+	priv->RxRing[priv->Rxmarker]->FControl = IDMA_FCONTROL_IRQEN | IDMA_FCONTROL_SCATTER;
+#else
+	priv->RxRing[priv->Rxmarker]->FControl = IDMA_FCONTROL_IRQEN ;
+#endif
+#endif
+
+	for (i = 0; i < priv->TxRingSize; i++) {
+#ifdef IDMA_1K_ADDR_WA
+		/***** 1K boundary IDMA bug ******/
+		if (((u32)desc_addr & 0x3E0) == 0x3E0)
+			desc_addr += sizeof(FDesc);
+		/***** 1K boundary IDMA bug ******/
+#endif
+		if (desc_addr > ((dma_addr_t)priv->ARAM_baseaddr_v + priv->ARAM_size))	{
+			printk(KERN_ERR "comcerto_eth_init_buffers: unable to allocated Tx ring\n");
+			goto err;
+		}
+		priv->TxRing[i] = (struct tFDesc *)desc_addr;
+
+		if (priv->TxRing[i] == NULL) {
+			printk(KERN_ERR "comcerto_eth_init_buffers: unable to allocated tx dma pool\n");
+			goto err;
+		}
+
+		priv->TxRing[i]->FStatus = 0;
+		priv->TxRing[i]->FControl = IDMA_FCONTROL_IRQEN;
+		priv->TxRing[i]->System = 0;
+		priv->TxRing[i]->BDesc[0].BControl = 0;
+
+		if (i != 0)
+			priv->TxRing[i - 1]->Next = (struct tFDesc *)phys_desc(priv, desc_addr);
+
+		desc_addr += sizeof(FDesc);
+	}
+
+	priv->TxRing[priv->TxRingSize - 1]->Next = (struct tFDesc *)phys_desc(priv, priv->TxRing[0]);
+	priv->TxRing[priv->TxRingSize - 1]->FControl = IDMA_FCONTROL_IRQEN;
+	priv->Txtosend = 0;
+	priv->Txdone = 0;
+	priv->Txavail = priv->TxRingSize - 1;
+
+	if (priv->fast_path_enabled) {
+		memset(priv->tx_free_ring, 0, TX_FREE_RING_SIZE * sizeof(u32));
+		priv->tx_free_cur = 0;
+		priv->tx_free_avail = TX_FREE_RING_SIZE;
+	}
+
+	return 0;
+
+err:
+	comcerto_eth_release_buffers(dev);
+
+	return -ENOMEM;
+}
+
+static int
+comcerto_hardware_send_packet(struct net_device *dev, struct sk_buff *skb)
+{
+	struct eth_priv *priv = netdev_priv(dev);
+	PFDesc ThisFdesc;
+	int err = 0;
+	u_int32_t priority;
+
+	if (unlikely(!priv->Txavail || (!priv->tx_free_avail && priv->fast_path_enabled))) {
+		err = -ENOMEM;
+		goto err_unlock;
+	}
+
+	ThisFdesc = priv->TxRing[priv->Txtosend];
+	ThisFdesc->BDesc[0].BPtr = virt_to_phys(skb->data);
+	ThisFdesc->BDesc[0].BControl = (skb->len) | IDMA_BCONTROL_BLAST;
+
+	dma_cache_maint(skb->data, skb->len, DMA_TO_DEVICE);
+
+	/* FIXME - for now invalidate the entire buffer range, since FPP may write to it
+	   later we should try to invalidate only the needed range */
+	dma_cache_maint(skb->head, skb->end - skb->head, DMA_FROM_DEVICE);
+
+	ThisFdesc->System = (u32)skb;
+	ThisFdesc->FStatus = 0;
+	ThisFdesc->FControl = 0;
+
+	/* DMA doesn't use bit 8-10, We use it to communicate the priority between CSP and FPP */
+	if (skb->mark & 0x7)
+		priority = skb->mark;
+	else
+		priority = priv->default_priority;
+	ThisFdesc->FControl |= (priority & 0x7) << 8;
+
+	if (priv->fast_path_enabled)
+		priv->tx_free_avail--;
+
+	ThisFdesc->FControl |= IDMA_FCONTROL_FREADY;
+
+	priv->Txtosend = (priv->Txtosend + 1) & (priv->TxRingSize - 1);
+	priv->Txavail--;
+	if (unlikely(!priv->Txavail || (!priv->tx_free_avail && priv->fast_path_enabled)))
+		err = -ENOSPC;
+
+	writel(IDMA_START, MMEM_START(priv->IDMA_baseaddr));
+
+	if (priv->fast_path_enabled)
+		comcerto_edma_generate_int(IRQ_TOFPP_DMA + 32);
+
+err_unlock:
+	return err;
+}
+
+
+static int comcerto_eth_send_packet(struct sk_buff *skb, struct net_device *dev)
+{
+	struct eth_priv *priv = netdev_priv(dev);
+	unsigned long flags;
+	int result = 0;
+
+	local_irq_save(flags);
+
+	if (!spin_trylock(&priv->txlock)) {
+		/* Collision - tell upper layer to requeue */
+		local_irq_restore(flags);
+		return NETDEV_TX_LOCKED;
+	}
+
+	result = comcerto_hardware_send_packet(dev, skb);
+
+	switch (result) {
+	case -ENOSPC:
+		/* We queued the skb, but now we're out of space. */
+		PDEBUG(1, "%s  comcerto_eth_send_packet No space for Tx \n", dev->name);
+		netif_stop_queue(dev);
+		dev->stats.tx_fifo_errors++;
+		break;
+	case -ENOMEM:
+		/* This is a hard error - log it. */
+		PDEBUG(1, "%s  comcerto_eth_send_packet Out of Tx resources, returning skb\n", dev->name);
+		netif_stop_queue(dev);
+		spin_unlock_irqrestore(&priv->txlock, flags);
+		return NETDEV_TX_BUSY;
+	}
+
+	dev->trans_start = jiffies;
+	spin_unlock_irqrestore(&priv->txlock, flags);
+
+	return NETDEV_TX_OK;
+}
+
+#define inc_rx_idx(idxname) (idxname = (idxname + 1) & (priv->RxRingSize - 1))
+
+/*
+ ** comcerto_eth_rx_fast_refill -
+ ** recycle buffer from RxtocleanIndex to RxtofillIndex part of the rx ring.
+ ** Limitation:
+ ** Call has to be made _before_ the Rxtoclean index is incremented.
+ ** By design code can not leave the data in place (would require too much code.
+ */
+	static inline int
+comcerto_eth_rx_fast_refill(struct eth_priv *priv, void *data)
+{
+	PFDesc ThisFdesc;
+
+	if (priv->RxtofillIndex == priv->RxtocleanIndex) {
+		return 1; /* There was nothing to fill */
+	}
+
+	ThisFdesc = priv->RxRing[priv->RxtofillIndex];
+
+	if (priv->fast_path_enabled) {
+		ThisFdesc->System = (u32)data;
+
+		if (eth_fpp_ops.add_buffer)
+			eth_fpp_ops.add_buffer(data);
+
+		ThisFdesc->BDesc[0].BPtr = virt_to_phys(data);
+		ThisFdesc->BDesc[0].BControl =  0;
+
+	} else {
+		ThisFdesc->System = (u32)data;
+
+#ifdef RX_SCATTERING
+		ThisFdesc->BDesc[0].BPtr = virt_to_phys(data + priv->align_pad + NET_SKB_PAD);
+		ThisFdesc->BDesc[0].BControl =  BDESC0_LEN;
+		ThisFdesc->BDesc[1].BPtr = virt_to_phys(data + BDESC0_LEN + priv->align_pad + NET_SKB_PAD);
+		ThisFdesc->BDesc[1].BControl = PKT_BUF_SZ | IDMA_BCONTROL_BLAST;
+# else /* RX_SCATTERING */
+		ThisFdesc->BDesc[0].BPtr = virt_to_phys(data + IP_SEC_HEADROOM + priv->align_pad + NET_SKB_PAD);
+		ThisFdesc->BDesc[0].BControl =  0 ;
+# endif /* RX_SCATTERING */
+	}
+
+	ThisFdesc->FStatus = 0;
+	inc_rx_idx(priv->RxtofillIndex);
+	priv->fast_filled += sizeof(struct tFDesc);
+	return 0;
+}
+
+static int comcerto_eth_rx_refill(struct net_device *dev)
+{
+	struct eth_priv *priv = netdev_priv(dev);
+	u8 *data;
+	int ret = 0;
+	int marker;
+	PFDesc ThisFdesc = NULL;
+
+	if ((priv->RxtofillIndex != priv->RxtocleanIndex) || ( priv->fast_filled)) {
+		marker = priv->Rxmarker;
+		priv->fast_filled = 0;
+		while (priv->RxtofillIndex != priv->RxtocleanIndex) {
+			/* loop thru rx FDescs */
+			ThisFdesc = priv->RxRing[priv->RxtofillIndex];
+			/* allocate a new skb for this RxRing element */
+			if (priv->fast_path_enabled) {
+				data = kmalloc(FPP_SKB_SIZE, GFP_ATOMIC | GFP_DMA);
+				if (likely(data)) {
+					ThisFdesc->System = (u32)data;
+
+					if (eth_fpp_ops.add_buffer)
+						eth_fpp_ops.add_buffer(data);
+
+					comcerto_invalidate_DC_range((u32)data + \
+						sizeof(struct list_head), FPP_SKB_SIZE - \
+						sizeof(struct list_head));
+
+					ThisFdesc->BDesc[0].BPtr = virt_to_phys(data);
+					ThisFdesc->BDesc[0].BControl =  0;
+
+					ThisFdesc->FStatus = 0;
+				} else {
+					printk("comcerto emac rx: low on mem - packet dropped\n");
+					ret = -EAGAIN;
+					break;
+				}
+			} else {
+
+				/*Allocate the buffer in DMA zone means
+				 * L1 cacheable, L2 non-cacheable*/
+				data = kmalloc(SKB_DATA_ALIGN(PKT_BUF_SZ +  \
+					priv->align_pad + NET_SKB_PAD) + \
+					sizeof(struct skb_shared_info), \
+					GFP_ATOMIC | GFP_DMA);
+				if (likely(data)) {
+
+					comcerto_invalidate_DC_range((u32)data
+						+ IP_SEC_HEADROOM \
+						+ priv->align_pad \
+						+ NET_SKB_PAD, \
+						PKT_BUF_SZ-IP_SEC_HEADROOM);
+
+					ThisFdesc->System = (u32) data;
+#ifdef RX_SCATTERING
+					ThisFdesc->BDesc[0].BPtr = \
+						virt_to_phys(data + \
+						priv->align_pad + NET_SKB_PAD);
+
+					ThisFdesc->BDesc[0].BControl =  BDESC0_LEN;
+					ThisFdesc->BDesc[1].BPtr = \
+						virt_to_phys(data + \
+						BDESC0_LEN + priv->align_pad + \
+						NET_SKB_PAD);
+
+					ThisFdesc->BDesc[1].BControl = PKT_BUF_SZ | IDMA_BCONTROL_BLAST;
+#else /* RX_SCATTERING */
+					ThisFdesc->BDesc[0].BPtr = \
+						virt_to_phys(data + \
+						IP_SEC_HEADROOM + \
+						priv->align_pad + NET_SKB_PAD);
+
+					ThisFdesc->BDesc[0].BControl =  0 ;
+#endif /* RX_SCATTERING */
+
+					comcerto_invalidate_DC_range((u32)data \
+						+ IP_SEC_HEADROOM \
+						+ priv->align_pad \
+						+ NET_SKB_PAD, \
+						PKT_BUF_SZ-IP_SEC_HEADROOM);
+
+					ThisFdesc->FStatus = 0;
+				} else {
+					printk("comcerto emac rx: low on mem - packet dropped\n");
+					ret = -EAGAIN;
+					break;
+				}
+			}
+
+			inc_rx_idx(priv->RxtofillIndex);
+		}
+
+		if (priv->RxtofillIndex)
+			priv->Rxmarker = priv->RxtofillIndex-1;
+		else
+			priv->Rxmarker = priv->RxRingSize-1;
+
+#ifdef NO_IDMA_STOP
+		priv->RxRing[priv->Rxmarker]->Next = (struct tFDesc *)phys_desc(priv, priv->RxRing[priv->Rxmarker]);
+		if (marker == priv->RxRingSize-1)
+			priv->RxRing[marker]->Next = (struct tFDesc *)phys_desc(priv, priv->RxRing[0]);
+		else
+			priv->RxRing[marker]->Next = (struct tFDesc *)phys_desc(priv, priv->RxRing[marker+1]);
+
+#else
+#ifdef RX_SCATTERING
+		priv->RxRing[priv->Rxmarker]->FControl = IDMA_FCONTROL_IRQEN | IDMA_FCONTROL_SCATTER;
+		priv->RxRing[marker]->FControl = IDMA_FCONTROL_FREADY | IDMA_FCONTROL_IRQEN | IDMA_FCONTROL_SCATTER;
+#else
+		priv->RxRing[priv->Rxmarker]->FControl = IDMA_FCONTROL_IRQEN ;
+		priv->RxRing[marker]->FControl = IDMA_FCONTROL_FREADY | IDMA_FCONTROL_IRQEN ;
+#endif
+#endif
+
+	}
+
+#ifdef NO_IDMA_STOP
+	if ((priv->RxtofillIndex == priv->RxtocleanIndex) && \
+		(__raw_readl(EMMM_HEAD(priv->IDMA_baseaddr)) == \
+		 phys_desc(priv, priv->RxRing[priv->Rxmarker]))) {
+		__raw_writel(1, EMMM_SOFT_RESET(priv->IDMA_baseaddr));
+		__raw_writel(phys_desc(priv, priv->RxRing[priv->RxtocleanIndex]), EMMM_HEAD(priv->IDMA_baseaddr));
+		__raw_writel(1, EMMM_START(priv->IDMA_baseaddr));
+
+	}
+#else
+	if ((priv->RxtofillIndex == priv->RxtocleanIndex) && \
+		(__raw_readl(EMMM_START(priv->IDMA_baseaddr)) == 0)) {
+		spin_lock(&priv->txlock);
+		PDEBUG(1, "%s  comcerto_eth_rx_refill rx full !!0x%X \n", \
+			dev->name, __raw_readl(EMMM_HEAD(priv->IDMA_baseaddr)));
+		if (!priv->fast_path_enabled)
+			comcerto_emac_restart(priv);
+		else
+			__raw_writel(1, EMMM_START(priv->IDMA_baseaddr));
+
+		spin_unlock(&priv->txlock);
+	}
+#endif
+	return (ret);
+}
+
+#if	(MAX_RX_DESC_NT == 64)
+#	define NUM_RX_DESC_NT_LOG 6
+#elif	(MAX_RX_DESC_NT == 128)
+#	define NUM_RX_DESC_NT_LOG 7
+#elif (MAX_RX_DESC_NT == 256)
+#	define NUM_RX_DESC_NT_LOG 8
+#else
+/* Power of 2 is needed for masks as well as for LOG */
+#	error "MAX_RX_DESC_NT is expected to be power of 2"
+#endif
+
+static inline int comcerto_eth_rx_packet(struct net_device *dev, unsigned int *work_done,
+		unsigned int work_to_do)
+{
+	struct eth_priv *priv = netdev_priv(dev);
+	PFDesc ThisFdesc = NULL;
+	void *data_addr;
+	void *buff_addr;
+	int offset;
+	int length;
+	struct sk_buff *skb;
+	int ret = 0;
+	int status;
+	int tmp;
+	u16 tmp16;
+	struct iphdr *iph;
+	unsigned int scaled_work = 0, drop_acc = 0;
+
+	PDEBUG(0, "%s  comcerto_eth_rx_packet \n", dev->name);
+#define AVG_SAMPLE_LOG 3
+	ThisFdesc = priv->RxRing[priv->RxtocleanIndex];
+	status = ThisFdesc->FStatus;
+	if ((status & IDMA_FSTATUS_FRAME_DONE_MASK) == 0) {
+		if ((((priv->Rxmarker - priv->RxtocleanIndex+priv->RxRingSize)&(priv->RxRingSize-1)) == 1) && \
+					(jiffies != dev->last_rx))  {
+			 /* It is cheaper to just change
+			  * state wout looking what it was */
+			priv->cng_state = CNG_OFF;
+			/* Poor man's decay */
+			priv->cng_avg = ((priv->cng_avg<<AVG_SAMPLE_LOG)-priv->cng_avg)>>AVG_SAMPLE_LOG;
+		}
+		return ret;
+	}
+
+	do {
+		comcerto_edma_ack_int(priv->EDMArx_int);
+		if (priv->cng_ctl >= 0) {
+			if (jiffies > (dev->last_rx + 1)) {
+				priv->cng_state = CNG_OFF;
+				priv->cng_avg = 0;
+			}
+			tmp = priv->fast_filled + \
+			      ((priv->RxRingSize*sizeof(struct tFDesc) + \
+				readl(EMMM_HEAD(priv->IDMA_baseaddr)) - \
+				phys_desc(priv, priv->RxRing[priv->RxtofillIndex]) ) & \
+			       (priv->RxRingSize*sizeof(struct tFDesc) - 1));
+
+			priv->cng_avg = ((priv->cng_avg<<AVG_SAMPLE_LOG) - \
+					priv->cng_avg+tmp)>>AVG_SAMPLE_LOG;
+#define  effective_fill (priv->cng_avg)
+#if (CNG_DEBUG_FILL)
+			priv->cng_fill_avg = (priv->cng_fill_avg << 8) | ((effective_fill >> FDesc_SZ_LOG) & 0xff);
+			priv->cng_fill = (priv->cng_fill << 8) | ((tmp >> FDesc_SZ_LOG) & 0xff);
+#endif	 /* (CNG_DEBUG_FILL) */
+			drop_acc = priv->cng_acc + (effective_fill >> (NUM_RX_DESC_NT_LOG+FDesc_SZ_LOG -2));
+
+			if ((priv->cng_state != CNG_OFF) && (effective_fill < priv->cng_off_thr))
+				priv->cng_state = CNG_OFF;
+			else if (effective_fill >  priv->cng_on_thr)
+				priv->cng_state = CNG_ON;
+#undef effective_fill
+#undef AVG_SAMPLE_LOG
+		}
+		while (1) {
+			if(unlikely(work_done && *work_done >= work_to_do)) {
+				ret = -EAGAIN;
+				PDEBUG(0, "%s  comcerto_eth_rx_packet FDesc 0x%X, RxtocleanIndex %d \n", \
+					dev->name, (u32)ThisFdesc, \
+					priv->RxtocleanIndex);
+				PDEBUG(0, "%s  comcerto_eth_rx_packet work_done %d, work_to_do %d \n", \
+					dev->name, *work_done, work_to_do);
+				// goto done_exit;
+				return ret;
+			}
+
+			// loop thru rx FDescs
+			ThisFdesc = priv->RxRing[priv->RxtocleanIndex];
+			status = ThisFdesc->FStatus;
+			if ((status & IDMA_FSTATUS_FRAME_DONE_MASK) == 0) {
+				PDEBUG(0, "%s  comcerto_eth_rx_packet done, FDesc 0x%X, RxtocleanIndex %d \n", \
+					dev->name, (u32)ThisFdesc, priv->RxtocleanIndex);
+				/* goto done_inner;
+				 * here you are pointing to a buffer that
+				 * has not been filled by the emac,
+				 * ie there is nothing to pass to upper layer
+				*/
+				break;
+			}
+#ifdef NO_IDMA_STOP
+			if (ThisFdesc->Next == (struct tFDesc *)phys_desc(priv, ThisFdesc)) {
+				PDEBUG(0, "%s  comcerto_eth_rx_packet done, FDesc 0x%X, RxtocleanIndex %d \n", \
+					dev->name, (u32)ThisFdesc, priv->RxtocleanIndex);
+				return ret;
+			}
+#endif
+#ifdef RX_SCATTERING
+			if (ThisFdesc->BDesc[0].BControl & IDMA_BCONTROL_SCATTER_BLAST)
+				length = ThisFdesc->BDesc[0].BControl & 0x0000ffff;
+			else
+				length = ThisFdesc->BDesc[1].BControl & 0x0000ffff;
+#else
+			length = ThisFdesc->BDesc[0].BControl & 0x0000ffff;
+#endif
+			data_addr = phys_to_virt(ThisFdesc->BDesc[0].BPtr);
+
+			if (priv->fast_path_enabled) {
+				buff_addr = (void *)((u32)data_addr & ~(FPP_SKB_SIZE - 1));
+				offset = data_addr - buff_addr;
+
+				if (eth_fpp_ops.del_buffer)
+					eth_fpp_ops.del_buffer(buff_addr);
+
+			} else {
+				buff_addr = (void *)ThisFdesc->System;
+				offset = IP_SEC_HEADROOM + priv->align_pad + NET_SKB_PAD;
+			}
+
+			if (length > PKT_BUF_SZ) {
+				printk("Comcerto Emac: frame too big (%d bytes)!\n", length);
+				length = PKT_BUF_SZ;
+			}
+
+			if (comcerto_emac_check_frame_status(status)) {
+				/* Pass the packet up to the protocol layers. */
+				/* recv the packet, data_addr should be a
+				 * virtual address, length should be the
+				 * length of the rcvd packet in bytes
+				 */
+
+				if ((priv->cng_state == CNG_ON)) {
+					if (status & RX_STA_VLAN) {
+						iph = (struct iphdr *)(data_addr + ETH_HLEN + 4);
+						tmp16 = *(u16 *)(data_addr + ETH_HLEN + 2);
+					} else {
+						iph = (struct iphdr*)(data_addr + ETH_HLEN);
+						tmp16 = *(u16 *)(data_addr + ETH_HLEN - 2);
+					}
+					scaled_work += 1;
+					if (scaled_work >= drop_acc)
+						scaled_work = 0;					/* do not look at priority once
+					 * at CNG_W times */
+					if ((scaled_work) &&
+						(tmp16 == ntohs( ETH_P_IP)) && \
+						((iph->tos & 0xe0) == 0)) {
+pkt_drop:
+						if (comcerto_eth_rx_fast_refill(priv, buff_addr))
+							kfree(buff_addr);
+						else
+							comcerto_invalidate_DC_range((u32)data_addr+ETH_HLEN-2, 8);
+						ThisFdesc->System = 0;
+						dev->stats.rx_dropped++;
+
+						goto eth_rx_dropped_packet;
+					}
+				}
+
+				if (priv->fast_path_enabled)
+					skb = alloc_skb_header(FPP_SKB_SIZE, buff_addr, GFP_ATOMIC);
+				else
+					skb = alloc_skb_header( \
+						SKB_DATA_ALIGN(PKT_BUF_SZ + \
+						priv->align_pad + \
+						NET_SKB_PAD) + \
+						sizeof(struct skb_shared_info), \
+						buff_addr, GFP_ATOMIC);
+
+				if (unlikely(skb == NULL))
+					goto pkt_drop;
+				/* ethernet + ip + tcp */
+				comcerto_prefetch_DC_range((u32)data_addr, 14 + 20 + 8);
+				skb_reserve(skb, offset);
+
+				ThisFdesc->System = 0;
+
+				/* Packet will be processed */
+				skb->dev = dev;
+				skb_put(skb, length);
+				skb->protocol = eth_type_trans(skb, dev);
+
+				/*Was Checksums verified by the hardware ? */
+				comcerto_emac_checksum(status, skb);
+
+				netif_receive_skb(skb);
+				dev->stats.rx_packets++;
+				dev->stats.rx_bytes += length;
+				dev->last_rx = jiffies;
+				if (work_done)
+					(*work_done)++;
+			} else {
+				if (comcerto_eth_rx_fast_refill(priv, buff_addr))
+					kfree(buff_addr);
+
+				ThisFdesc->System = 0;
+				dev->stats.rx_errors++;
+			}
+eth_rx_dropped_packet:
+			inc_rx_idx(priv->RxtocleanIndex);
+		}
+		/* done_inner:; */
+	} while (comcerto_edma_get_int_status(priv->EDMArx_int));
+
+	return ret;
+}
+
+static int comcerto_eth_poll(struct napi_struct *napi, int budget)
+{
+	unsigned int work_to_do = budget;
+	unsigned int work_done = 0;
+	int tx_cleaned = 0;
+	unsigned long flags;
+	struct eth_priv *priv = container_of(napi, struct eth_priv, napi);
+	struct net_device *dev = priv->dev;
+
+	priv->fast_filled = 0;
+	comcerto_eth_rx_packet(dev, &work_done, work_to_do);
+	comcerto_eth_rx_refill(dev);
+
+	tx_cleaned = comcerto_eth_free_tx_packets(dev);
+
+	PDEBUG(0, "%s  comcerto_eth_poll , work_done %d , tx_cleaned %d\n", \
+			dev->name, work_done, tx_cleaned);
+
+	/* If no Rx and Tx cleanup work was done, exit polling mode. */
+	if ((!tx_cleaned && (work_done == 0)) || !netif_running(dev)) {
+		napi_complete(napi);
+		PDEBUG(0, "%s  comcerto_eth_poll re-enable irqs \n", dev->name);
+
+		local_irq_save(flags);
+		comcerto_edma_enable_int(priv->EDMArx_int);
+		comcerto_edma_enable_int(priv->EDMAtx_int);
+		local_irq_restore(flags);
+	}
+
+	return work_done;
+}
+
+
+irqreturn_t comcerto_eth_interrupt(int irq, void *dev_id)
+{
+	struct net_device *dev = (struct net_device *)dev_id;
+	struct eth_priv *priv = netdev_priv(dev);
+	unsigned long flags;
+
+
+	PDEBUG(0, "%s  comcerto_eth_interrupt irq %d\n", dev->name, irq);
+
+	if (napi_schedule_prep(&priv->napi)) {
+		PDEBUG(0, "%s  comcerto_eth_interrupt irq %d: schedule poll\n",
+					dev->name, irq);
+		local_irq_save(flags);
+
+		comcerto_edma_disable_int(priv->EDMArx_int);
+		comcerto_edma_disable_int(priv->EDMAtx_int);
+		local_irq_restore(flags);
+		__napi_schedule(&priv->napi);
+	} else if (netif_running(dev)) {
+		PDEBUG(0, "%s comcerto_eth_interrupt irq %d bug! interrupt while in poll\n", \
+				dev->name, irq);
+		/* FIX by disabling interrupts  */
+		local_irq_save(flags);
+		comcerto_edma_disable_int(priv->EDMArx_int);
+		comcerto_edma_disable_int(priv->EDMAtx_int);
+		local_irq_restore(flags);
+	} else /* simply ack */
+		comcerto_edma_ack_int(irq);
+
+	return IRQ_HANDLED;
+}
+
+#ifdef CONFIG_NET_POLL_CONTROLLER
+static void comcerto_eth_poll_controller(struct net_device *dev)
+{
+	disable_irq(dev->irq);
+	comcerto_eth_interrupt(dev->irq, dev);
+	enable_irq(dev->irq);
+}
+#endif
+
+static int comcerto_eth_probe(struct platform_device *pdev)
+{
+	struct net_device *dev = NULL;
+	struct eth_priv *priv = NULL;
+	struct comcerto_eth_platform_data *einfo;
+	struct resource *r;
+	int idx;
+	int err = 0;
+	einfo = (struct comcerto_eth_platform_data *) pdev->dev.platform_data;
+
+	printk(KERN_DEBUG "comcerto gemac %d: probe \n", pdev->id);
+
+	if (NULL == einfo) {
+		printk(KERN_ERR "comcerto gemac %d: Missing additional data!\n",
+				pdev->id);
+
+		return -ENODEV;
+	}
+
+	/* Create an ethernet device instance */
+	dev = alloc_etherdev(sizeof(*priv));
+
+	if (NULL == dev)
+		return -ENOMEM;
+
+	priv = netdev_priv(dev);
+	priv->dev = dev;
+
+	priv->id = pdev->id;
+
+	/* Set the info in the priv to the current info */
+	priv->einfo = einfo;
+
+	/* fill out IRQ fields */
+	priv->slow_path_EDMAtx_int = platform_get_irq_byname(pdev, "tx");
+	priv->slow_path_EDMArx_int = platform_get_irq_byname(pdev, "rx");
+	priv->EMAC_int = platform_get_irq_byname(pdev, "gemac");
+
+	if (priv->slow_path_EDMAtx_int < 0 || \
+		priv->slow_path_EDMArx_int < 0 || priv->EMAC_int < 0)
+		goto regs_fail;
+
+	/* get a pointer to the gemac register memory */
+	r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "gemac");
+#if defined(USE_IOREMAP)
+	priv->EMAC_baseaddr  = ioremap(r->start, r->end-r->start+1);
+#else
+	priv->EMAC_baseaddr  = (void *)APB_VADDR(r->start);
+#endif
+	if (priv->EMAC_baseaddr == 0) {
+		err = -ENOMEM;
+		goto regs_fail;
+	}
+
+	/* get a pointer to the IDMA register memory */
+	r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "idma");
+#if defined(USE_IOREMAP)
+	priv->slow_path_IDMA_baseaddr  = ioremap(r->start, r->end-r->start+1);
+#else
+	priv->slow_path_IDMA_baseaddr  = (void *)APB_VADDR(r->start);
+#endif
+
+	if (priv->slow_path_IDMA_baseaddr == 0) {
+		err = -ENOMEM;
+		goto IDMA_fail;
+	}
+
+	/* get a pointer to the internal memory (if any) used for descriptors*/
+	r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "aram");
+#if defined(USE_IOREMAP)
+	priv->ARAM_baseaddr_v = ioremap(r->start, r->end-r->start+1);
+#else
+	priv->ARAM_baseaddr_v = aram_to_virt(r->start);
+#endif
+	if (priv->ARAM_baseaddr_v == 0) {
+		err = -ENOMEM;
+		goto ARAM_fail;
+	}
+	priv->ARAM_baseaddr_p = (dma_addr_t)r->start;
+	priv->ARAM_size  = r->end - r->start + 1;
+
+	spin_lock_init(&priv->txlock);
+	spin_lock_init(&priv->rxlock);
+	INIT_WORK(&priv->reset_task, comcerto_reset_task);
+
+	platform_set_drvdata(pdev, dev);
+
+	/* Copy the station address into the dev structure, */
+	memcpy(dev->dev_addr, einfo->mac_addr, MAC_ADDR_LEN);
+
+	err = dev_alloc_name(dev, einfo->name);
+	if (err < 0) {
+		printk(KERN_ERR \
+		"%s: Cannot allocate  net device name, aborting.\n", \
+		einfo->name);
+		goto register_fail;
+	}
+
+	SET_NETDEV_DEV(dev, &pdev->dev);
+
+	/* Fill in the dev structure */
+	dev->open = comcerto_eth_open;
+	dev->hard_start_xmit = comcerto_eth_send_packet;
+#ifdef COMCERTO_TIMEOUT
+	dev->tx_timeout = comcerto_tx_timeout;
+	dev->watchdog_timeo = TX_TIMEOUT;
+#endif
+	netif_napi_add(dev, &priv->napi, comcerto_eth_poll, COMCERTO_DEV_WEIGHT);
+	dev->stop = comcerto_eth_close;
+	dev->change_mtu = comcerto_eth_change_mtu;
+	dev->mtu = 1500;
+	dev->set_multicast_list = comcerto_eth_set_multi;
+	dev->set_mac_address = comcerto_set_mac_address;
+
+	dev->ethtool_ops = &comcerto_ethtool_ops;
+
+	/* Enable most messages by default */
+	priv->msg_enable = (NETIF_MSG_IFUP << 1) - 1;
+
+#ifdef CONFIG_NET_POLL_CONTROLLER
+	dev->poll_controller = comcerto_eth_poll_controller;
+#endif
+
+	err = register_netdev(dev);
+
+	if (err) {
+		printk(KERN_ERR "%s: Cannot register net device, aborting.\n",
+				dev->name);
+		goto register_fail;
+	}
+
+	init_timer(&priv->watchdog_timer);
+	priv->watchdog_timer.function = &comcerto_watchdog;
+	priv->watchdog_timer.data = (unsigned long) dev;
+
+	INIT_WORK(&priv->watchdog_task, comcerto_watchdog_task);
+	/* Create all the sysfs files */
+	comcerto_init_sysfs(dev);
+
+	/* Print out the device info */
+	printk(KERN_INFO DEVICE_NAME, dev->name);
+	for (idx = 0; idx < 6; idx++)
+		printk("%2.2x%c", dev->dev_addr[idx], idx == 5 ? ' ' : ':');
+	printk("\n");
+
+	return 0;
+
+register_fail:
+#if defined(USE_IOREMAP)
+	iounmap(priv->ARAM_baseaddr_v);
+#endif
+ARAM_fail:
+#if defined(USE_IOREMAP)
+	iounmap((void *)priv->slow_path_IDMA_baseaddr);
+#endif
+IDMA_fail:
+#if defined(USE_IOREMAP)
+	iounmap(priv->EMAC_baseaddr);
+#endif
+regs_fail:
+	free_netdev(dev);
+	return err;
+}
+
+
+static void comcerto_adjust_link(struct net_device *dev)
+{
+	struct eth_priv *priv = netdev_priv(dev);
+	unsigned long flags;
+	struct phy_device *phydev = priv->phydev;
+	int new_state = 0;
+
+	PDEBUG(0,  "%s comcerto_adjust_link\n", dev->name);
+
+	spin_lock_irqsave(&priv->txlock, flags);
+	if (phydev->link) {
+		/* Now we make sure that we can be in full duplex mode.
+		 * If not, we operate in half-duplex mode. */
+		if (phydev->duplex != priv->oldduplex) {
+			new_state = 1;
+			comcerto_gemac_setduplex(dev, phydev->duplex);
+			priv->oldduplex = phydev->duplex;
+
+		}
+
+		if (phydev->speed != priv->oldspeed) {
+			new_state = 1;
+			comcerto_gemac_setspeed(dev, phydev->speed);
+			priv->oldspeed = phydev->speed;
+		}
+
+		if (!priv->oldlink) {
+			new_state = 1;
+			priv->oldlink = 1;
+		}
+	} else if (priv->oldlink) {
+		new_state = 1;
+		priv->oldlink = 0;
+		priv->oldspeed = 0;
+		priv->oldduplex = -1;
+	}
+
+	if (new_state && netif_msg_link(priv))
+		phy_print_status(phydev);
+
+	spin_unlock_irqrestore(&priv->txlock, flags);
+}
+
+static int comcerto_eth_remove(struct platform_device *pdev)
+{
+	struct net_device *dev = platform_get_drvdata(pdev);
+#if defined (USE_IOREMAP)
+	struct eth_priv *priv = netdev_priv(dev);
+#endif
+	platform_set_drvdata(pdev, NULL);
+
+#if defined (USE_IOREMAP)
+	iounmap(priv->ARAM_baseaddr_v);
+	iounmap((void *)priv->slow_path_IDMA_baseaddr);
+	iounmap(priv->EMAC_baseaddr);
+#endif
+	free_netdev(dev);
+
+	return 0;
+}
+
+
+/* Structure for a device driver */
+static struct platform_driver comcerto_eth_driver = {
+	.probe = comcerto_eth_probe,
+	.remove = comcerto_eth_remove,
+	.driver	= {
+		.name = "comcerto-eth",
+		.owner = THIS_MODULE,
+	},
+};
+
+/*
+ *	This is a kernel command line parameter. The format is as following:
+ *	hwaddress=<interface name>,<mac address>,<interface name>,<mac address> ....
+ *	This parameter is mainly use when mounting the root filesytem over NFS.
+ *	For all the other cases, the MAC address will be given through the ifconfig application
+ *	i.e: ifconfig <interface name> hw ether <mac address>
+ */
+static int __init hwaddress_setup(char *str)
+{
+	int index = 0;
+	int i = 0;
+	unsigned char *pchar = (unsigned char *)str;
+
+	for (i = 0; i < 2; i++) {
+		if (strncmp(pchar, ETH0, 4) == 0) {
+			pchar = strpbrk(pchar, ",");
+			++pchar;
+			index = 0;
+			while (pchar && (index < ETH_ALEN)) {
+				if (pchar) {
+					unsigned char tmp = simple_strtol(pchar, NULL, 16);
+					comcerto_gem0_pdata.mac_addr[index++] = (unsigned char)tmp;
+					pchar += 3;
+				}
+			}
+		} else if (strncmp(pchar, WAN0, 4) == 0) {
+			pchar = strpbrk(pchar, ",");
+			++pchar;
+			index = 0;
+			while (pchar && (index < ETH_ALEN)) {
+				if (pchar) {
+					unsigned char tmp = simple_strtol(pchar, NULL, 16);
+					comcerto_gem1_pdata.mac_addr[index++] = (unsigned char)tmp;
+					pchar += 3;
+				}
+			}
+		}
+	}
+
+	return 1;
+}
+
+int comcerto_eth_register_fpp_ops(t_fpp_ops *ops)
+{
+	eth_fpp_ops.write = ops->write;
+	eth_fpp_ops.read = ops->read;
+	eth_fpp_ops.add_buffer = ops->add_buffer;
+	eth_fpp_ops.del_buffer = ops->del_buffer;
+
+	return 0;
+}
+EXPORT_SYMBOL(comcerto_eth_register_fpp_ops);
+
+
+void comcerto_eth_unregister_fpp_ops(void)
+{
+	/* FIXME - disable fast path for all interfaces */
+	/* FIXME - prevent fast path from being enabled */
+
+	eth_fpp_ops.write = NULL;
+	eth_fpp_ops.read = NULL;
+	eth_fpp_ops.add_buffer = NULL;
+	eth_fpp_ops.del_buffer = NULL;
+}
+EXPORT_SYMBOL(comcerto_eth_unregister_fpp_ops);
+
+int comcerto_eth_enable_fast_path(struct net_device *dev, unsigned short state)
+{
+	struct eth_priv *priv = netdev_priv(dev);
+	int rc = 0;
+
+	if (priv->fast_path_enabled == state)
+		goto out;
+
+	rtnl_lock();
+	if (dev->flags & IFF_UP) {
+		rc = comcerto_eth_close(dev);
+		if (rc)
+			goto out_unlock;
+
+		priv->fast_path_enabled = state;
+		rc = comcerto_eth_open(dev);
+		if (rc)
+			goto out_unlock;
+
+	} else
+		priv->fast_path_enabled = state;
+
+out_unlock:
+	rtnl_unlock();
+
+out:
+	return rc;
+}
+
+
+__setup("hwaddress=", hwaddress_setup);
+
+
+static int __init comcerto_eth_init(void)
+{
+	int err ;
+
+	err = platform_driver_register(&comcerto_eth_driver);
+	return err;
+}
+
+static void __exit comcerto_eth_exit(void)
+{
+	platform_driver_unregister(&comcerto_eth_driver);
+	comcerto_mdio_exit();
+}
+
+module_init(comcerto_eth_init);
+module_exit(comcerto_eth_exit);
diff -r e137be04dc4d drivers/net/comcerto/comcerto_eth.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/net/comcerto/comcerto_eth.h	Mon Aug 17 16:45:23 2009 -0500
@@ -0,0 +1,200 @@
+/*
+ *  linux/drivers/net/comcerto/comcerto_eth.h
+ *
+ *  Copyright (C) 2006 Mindspeed Technologies, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#ifndef _COMCERTO_VED_H
+#define _COMCERTO_VED_H
+
+#include <linux/netdevice.h>	/* struct device, and other headers */
+#include <linux/mii.h>
+#include <linux/ethtool.h>
+#include "comcerto_gemac.h"
+
+
+#define DEVICE_NAME "%s: Comcerto Ethernet Controller  "
+#define DRV_NAME "comcerto-geth"
+extern const char comcerto_driver_name[];
+extern const char comcerto_driver_version[];
+#define COMCERTO_INFOSTR_LEN	32
+#define COMCERTO_DEV_WEIGHT 16
+
+/* direct EMAC0 control */
+#define DEFAULT_RX_DESC_NT 128
+#define DEFAULT_TX_DESC_NT 128
+#define MAX_RX_DESC_NT 256
+#define MAX_TX_DESC_NT 128
+#define SLOW_PATH_DESC_NT	64
+
+#define TX_FREE_RING_SIZE	128
+
+#define FPP_SKB_SIZE		SZ_4K
+#define FPP_TX_SKB_HEADROOM	64
+#define FPP_TX_SKB_TAILROOM		64
+
+
+#define DEFAULT_ALIGN_PAD	16
+
+#define DEFAULT_PRIORITY	0
+
+#define ETH0	"eth0"
+#define WAN0	"eth2"
+
+#define FAST_PATH_DISABLE	0
+#define FAST_PATH_ENABLE	1
+#define DEFAULT_FAST_PATH_STATE	FAST_PATH_DISABLE
+
+
+#define VDMA0_BASE_VADDR aram_to_virt(0x0A000C00)
+#define VDMA1_BASE_VADDR aram_to_virt(0x0A000D00)
+
+#define TX_FREE_RING0_BASE_VADDR aram_to_virt(0x0A000600)
+#define TX_FREE_RING1_BASE_VADDR aram_to_virt(0x0A000800)
+
+#undef USE_IOREMAP
+
+/*
+ * This structure is private to each device. It is used to pass
+ * packets in and out, so there is place for a packet
+ */
+
+struct eth_priv {
+	struct tFDesc *RxRing[MAX_RX_DESC_NT];
+	u32	RxRingSize;
+	u32  RxMaxRingSize;
+	u32 RxtofillIndex;
+	u32 RxtocleanIndex;
+	u32 Rxmarker;
+	u32	align_pad;
+	u32	default_priority;
+	/* sysfs mapped congestion control */
+	int cng_ctl;
+	u32 cng_state;
+#define CNG_OFF	0
+#define CNG_ON	1
+#if (CNG_OFF != 0)
+#	error "CNG_OFF must be zero"
+#endif
+	u32 fast_filled;
+	u32 cng_on_thr;
+	u32 cng_off_thr;
+	u32 cng_acc;
+	u32 cng_avg;
+	/*
+	 ** defining CNG_DEBUG to 1 allows to monitor instantenious
+	 ** and average values of rx_ring fill
+	 */
+#if	!defined(CNG_DEBUG_FILL)
+#	define CNG_DEBUG_FILL 0
+#endif
+
+#if	(CNG_DEBUG_FILL)
+	u32 cng_fill;
+	u32 cng_fill_avg;
+#endif
+
+	spinlock_t txlock;
+	struct tFDesc *TxRing[MAX_TX_DESC_NT];
+	u32	TxRingSize;
+	u32  TxMaxRingSize;
+	u32 Txtosend;
+	u32 Txdone;
+	int Txavail;
+	struct tFDesc *TxCurrent;
+
+	u32 *tx_free_ring;
+	u32 tx_free_cur;
+	u32 tx_free_avail;
+
+	struct napi_struct napi;
+	struct net_device *dev;
+
+	int id;
+
+	spinlock_t rxlock;
+	struct comcerto_eth_platform_data *einfo;
+
+	/* platform ressources */
+	int		EDMArx_int;
+	int		EDMAtx_int;
+	int		EMAC_int;
+	void		*EMAC_baseaddr;
+	void		*IDMA_baseaddr;
+	void		*ARAM_baseaddr_v;
+	dma_addr_t	ARAM_baseaddr_p;
+	int		ARAM_size;
+	GEM_DEVICE	gemdev;
+
+
+	/* PHY stuff */
+	struct phy_device *phydev;
+	struct mii_bus *mii_bus;
+	int oldspeed;
+	int oldduplex;
+	int oldlink;
+
+	uint32_t msg_enable;
+	uint32_t rx_csum_enable;
+
+	struct work_struct reset_task;
+	struct work_struct watchdog_task;
+	struct timer_list watchdog_timer;
+
+	/* sysfs */
+	u16 Rxpktsz;
+	u16 inbound_fifo_low;
+	u16 inbound_fifo_high;
+	u16 outbound_fifo_low;
+	u16 outbound_fifo_high;
+	u8   rx_lock_size;
+	u8   tx_lock_size;
+	u8 fast_path_enabled;
+
+	int	slow_path_EDMArx_int;
+	int	slow_path_EDMAtx_int;
+	void	*slow_path_IDMA_baseaddr;
+};
+
+typedef struct t_BDesc {
+	u32 BPtr;
+	u32 BControl;
+} BDesc;
+
+typedef struct tFDesc{
+	struct tFDesc *Next;
+	u32 System;
+	u32 FStatus;
+	u32 FControl;
+	BDesc BDesc[2];
+} FDesc, *PFDesc;
+
+#define FDesc_SZ_LOG 5
+
+#if defined(USE_IOREMAP)
+#define phys_desc(priv, v) \
+	(priv->ARAM_baseaddr_p + (dma_addr_t)((unsigned long)(v) - \
+			(unsigned long)(priv->ARAM_baseaddr_v)))
+#define  virt_desc(priv, p) \
+	(void *)((unsigned long)priv->ARAM_baseaddr_v + ((unsigned long)(p) - \
+				(unsigned long)(priv->ARAM_baseaddr_p)))
+#else
+#define phys_desc(priv, v) virt_to_aram(v)
+#define  virt_desc(priv, p) aram_to_virt(p)
+
+#endif
+
+#endif /* _COMCERTO_VED_H */
diff -r e137be04dc4d drivers/net/comcerto/comcerto_ethtool.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/net/comcerto/comcerto_ethtool.c	Mon Aug 17 16:45:23 2009 -0500
@@ -0,0 +1,329 @@
+/*
+  *  linux/drivers/net/comcerto/comcerto_ethtool.c
+  *
+  *  Copyright (C) 2006 Mindspeed Technologies, Inc.
+  *
+  * This program is free software; you can redistribute it and/or modify
+  * it under the terms of the GNU General Public License as published by
+  * the Free Software Foundation; either version 2 of the License, or
+  * (at your option) any later version.
+  *
+  * This 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/kernel.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/spinlock.h>
+#include <linux/mm.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+#include <linux/module.h>
+#include <linux/crc32.h>
+#include <linux/types.h>
+#include <linux/uaccess.h>
+#include <linux/ethtool.h>
+#include <linux/mii.h>
+#include <linux/phy.h>
+
+#include "comcerto_eth.h"
+#include "comcerto_gemac.h"
+
+
+static void comcerto_fill_stats(struct net_device *dev,
+		struct ethtool_stats *dummy, u64 *buf);
+static void  comcerto_gstrings(struct net_device *dev,
+		u32 stringset, u8 *buf);
+static void  comcerto_gringparam(struct net_device *dev,
+		struct ethtool_ringparam *rvals);
+static int  comcerto_sringparam(struct net_device *dev,
+		struct ethtool_ringparam *rvals);
+
+
+extern const char comcerto_eth_driver_name[];
+extern const char comcerto_eth_driver_version[];
+extern int comcerto_eth_start(struct net_device *dev, int phy);
+extern int comcerto_eth_stop(struct net_device *dev, int phy);
+
+
+static char stat_gstrings[][ETH_GSTRING_LEN] = {
+	"tx- octets  (Lower 32-bits)",
+	"tx- octets  (Upper 16-bits)",
+	"tx- packets",
+	"tx- broadcast",
+	"tx- multicast",
+	"tx- pause",
+	"tx- 64 bytes packets",
+	"tx- 64 - 127 bytes packets",
+	"tx- 128 - 255 bytes packets",
+	"tx- 256 - 511 bytes packets",
+	"tx- 512 - 1023 bytes packets",
+	"tx- 1024 - 1518 bytes packets",
+	"tx- > 1518 bytes packets",
+	"tx- underruns  - errors",
+	"tx- single collision",
+	"tx- multi collision",
+	"tx- exces. collision  - errors",
+	"tx- late collision  - errors",
+	"tx- deferred",
+	"tx- carrier sense - errors",
+	"rx- octets (Lower 32-bits)",
+	"rx- octets (Upper 16-bits)",
+	"rx- packets",
+	"rx- broadcast",
+	"rx- multicast",
+	"rx- pause",
+	"rx- 64 bytes packets",
+	"rx- 64 - 127 bytes packets",
+	"rx- 128 - 255 bytes packets",
+	"rx- 256 - 511 bytes packets",
+	"rx- 512 - 1023 bytes packets",
+	"rx- 1024 - 1518 bytes packets",
+	"rx- > 1518 bytes packets",
+	"rx- undersize -errors",
+	"rx- oversize  - errors ",
+	"rx- jabbers - errors",
+	"rx- fcs - errors",
+	"rx- length - errors",
+	"rx- symbol - errors",
+	"rx- align - errors",
+	"rx- ressource - errors",
+	"rx- overrun - errors",
+	"rx- IP cksum - errors",
+	"rx- TCP cksum - errors",
+	"rx- UDP cksum - errors"
+};
+
+/* Fill in a buffer with the strings which correspond to the
+ * stats */
+static void  comcerto_gstrings(struct net_device *dev, u32 stringset, u8 *buf)
+{
+	memcpy(buf, stat_gstrings, GEMAC_RMON_LEN * ETH_GSTRING_LEN);
+}
+
+/* Fill in an array of 64-bit statistics from various sources.
+ * This array will be appended to the end of the ethtool_stats
+ * structure, and returned to user space
+ */
+static void comcerto_fill_stats(struct net_device *dev,
+		struct ethtool_stats *dummy, u64 *buf)
+{
+	struct eth_priv *priv = netdev_priv(dev);
+	u32 *pstat = (u32 *)(priv->gemdev.registers + GEM_OCT_TX_BOT);
+	int i;
+	for (i = 0; i < GEMAC_RMON_LEN; i++)
+		*buf++ = *pstat++;
+}
+
+/* Returns the number of stats (and their corresponding strings) */
+static int comcerto_stats_count(struct net_device *dev)
+{
+	return GEMAC_RMON_LEN;
+}
+
+/* Fills in the drvinfo structure with some basic info */
+static void comcerto_get_drvinfo(struct net_device *dev,
+		struct ethtool_drvinfo *drvinfo)
+{
+	strncpy(drvinfo->driver, DRV_NAME, COMCERTO_INFOSTR_LEN);
+	strncpy(drvinfo->version, comcerto_eth_driver_version,
+			COMCERTO_INFOSTR_LEN);
+	strncpy(drvinfo->fw_version, "N/A", COMCERTO_INFOSTR_LEN);
+	strncpy(drvinfo->bus_info, "N/A", COMCERTO_INFOSTR_LEN);
+	drvinfo->testinfo_len = 0;
+	drvinfo->regdump_len = 0;
+	drvinfo->eedump_len = 0;
+}
+
+
+static int comcerto_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+	struct eth_priv *priv = netdev_priv(dev);
+	struct phy_device *phydev = priv->phydev;
+
+	if (NULL == phydev)
+		return -ENODEV;
+
+	return phy_ethtool_sset(phydev, cmd);
+}
+
+
+/* Return the current settings in the ethtool_cmd structure */
+static int comcerto_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+	struct eth_priv *priv = netdev_priv(dev);
+	struct phy_device *phydev = priv->phydev;
+
+	if (NULL == phydev)
+		return -ENODEV;
+
+	return phy_ethtool_gset(phydev, cmd);
+}
+
+/* Return the length of the register structure */
+static int comcerto_gemac_reglen(struct net_device *dev)
+{
+	return sizeof(struct gem_reg);
+}
+
+static void  comcerto_gemac_get_regs(struct net_device *dev,
+		struct ethtool_regs *regs, void *regbuf)
+{
+	int i;
+	struct eth_priv *priv = netdev_priv(dev);
+	u32 *theregs = (u32 __iomem *) priv->gemdev.registers;
+	u32 *buf = (u32 *) regbuf;
+
+	for (i = 0; i < sizeof(struct gem_reg) / sizeof(u32); i++)
+		buf[i] = theregs[i];
+}
+
+static void comcerto_gringparam(struct net_device *dev, struct ethtool_ringparam *rvals)
+{
+	struct eth_priv *priv = netdev_priv(dev);
+
+	rvals->rx_max_pending = priv->RxRingSize;
+	rvals->rx_mini_max_pending = priv->RxRingSize;
+	rvals->rx_jumbo_max_pending = priv->RxRingSize;
+	rvals->tx_max_pending = priv->TxRingSize;
+
+	/* Values changeable by the user.  The valid values are
+	 * in the range 1 to the "*_max_pending" counterpart above.
+	 */
+	if (priv->RxtocleanIndex >= priv->RxtofillIndex)
+		rvals->rx_pending = (priv->RxtocleanIndex - priv->RxtofillIndex);
+	else
+		rvals->rx_pending = (priv->RxRingSize - 1 - \
+			priv->RxtocleanIndex + priv->RxtofillIndex);
+
+	rvals->rx_mini_pending = rvals->rx_pending;
+	rvals->rx_jumbo_pending = rvals->rx_pending;
+	rvals->tx_pending = priv->TxRingSize - 1 - priv->Txavail;
+}
+
+/* Change the current ring parameters, stopping the controller if
+ * necessary so that we don't mess things up while we're in
+ * motion.  We wait for the ring to be clean before reallocating
+ * the rings. */
+static int comcerto_sringparam(struct net_device *dev, struct ethtool_ringparam *rvals)
+{
+	struct eth_priv *priv = netdev_priv(dev);
+	int err = 0;
+	if (rvals->rx_pending > priv->RxMaxRingSize)
+		return -EINVAL;
+
+	if (!is_power_of_2(rvals->rx_pending)) {
+		printk("%s: Ring sizes must be a power of 2\n",
+				dev->name);
+		return -EINVAL;
+	}
+
+	if (rvals->tx_pending > priv->TxMaxRingSize)
+		return -EINVAL;
+
+	if (!is_power_of_2(rvals->tx_pending)) {
+		printk("%s: Ring sizes must be a power of 2\n",
+				dev->name);
+		return -EINVAL;
+	}
+
+	if (dev->flags & IFF_UP) {
+		netif_stop_queue(dev);
+		comcerto_eth_stop(dev, 0);
+	}
+
+	/* Change the size */
+	priv->RxRingSize = rvals->rx_pending;
+	priv->TxRingSize = rvals->tx_pending;
+
+	/* Rebuild the rings with the new size */
+	if (dev->flags & IFF_UP) {
+
+		err = comcerto_eth_start(dev, 0);
+		if (err == 0)
+			netif_start_queue(dev);
+	}
+	return err;
+}
+
+static int comcerto_set_rx_csum(struct net_device *dev, uint32_t data)
+{
+	struct eth_priv *priv = netdev_priv(dev);
+	int err = 0;
+
+	if (data == priv->rx_csum_enable)
+		return err;
+
+	if (data)
+		gem_enable_checksum_offload(&priv->gemdev);
+	else
+		gem_disable_checksum_offload(&priv->gemdev);
+
+	priv->rx_csum_enable = data;
+	return err;
+}
+
+static uint32_t  comcerto_get_rx_csum(struct net_device *dev)
+{
+	struct eth_priv *priv = netdev_priv(dev);
+	return priv->rx_csum_enable;
+}
+
+static int comcerto_set_tx_csum(struct net_device *dev, uint32_t data)
+{
+	return -EOPNOTSUPP;
+}
+
+static uint32_t comcerto_get_tx_csum(struct net_device *dev)
+{
+	return 0;
+}
+
+static uint32_t comcerto_get_msglevel(struct net_device *dev)
+{
+	struct eth_priv *priv = netdev_priv(dev);
+	return priv->msg_enable;
+}
+
+static void comcerto_set_msglevel(struct net_device *dev, uint32_t data)
+{
+	struct eth_priv *priv = netdev_priv(dev);
+	priv->msg_enable = data;
+}
+
+
+struct ethtool_ops comcerto_ethtool_ops = {
+	.get_settings = comcerto_get_settings,
+	.set_settings = comcerto_set_settings,
+	.get_drvinfo = comcerto_get_drvinfo,
+	.get_regs_len = comcerto_gemac_reglen,
+	.get_regs = comcerto_gemac_get_regs,
+	.get_link = ethtool_op_get_link,
+	.get_ringparam = comcerto_gringparam,
+	.set_ringparam = comcerto_sringparam,
+	.get_strings = comcerto_gstrings,
+	.get_stats_count = comcerto_stats_count,
+	.get_ethtool_stats = comcerto_fill_stats,
+	.get_rx_csum = comcerto_get_rx_csum,
+	.get_tx_csum = comcerto_get_tx_csum,
+	.set_rx_csum = comcerto_set_rx_csum,
+	.set_tx_csum = comcerto_set_tx_csum,
+	.get_msglevel = comcerto_get_msglevel,
+	.set_msglevel = comcerto_set_msglevel,
+};
diff -r e137be04dc4d drivers/net/comcerto/comcerto_fpp.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/net/comcerto/comcerto_fpp.c	Mon Aug 17 16:45:23 2009 -0500
@@ -0,0 +1,980 @@
+ /*
+  *  linux/drivers/net/comcerto/comcerto_fpp.c
+  *
+  *  Copyright (C) 2006 Mindspeed Technologies, Inc.
+  *
+  * This program is free software; you can redistribute it and/or modify
+  * it under the terms of the GNU General Public License as published by
+  * the Free Software Foundation; either version 2 of the License, or
+  * (at your option) any later version.
+  *
+  * This program is distributed in the hope that it will be useful,
+  * but WITHOUT ANY WARRANTY; without even the implied warranty of
+  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  * GNU General Public License for more details.
+  *
+  * You should have received a copy of the GNU General Public License
+  * along with this program; if not, write to the Free Software
+  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+  */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/string.h>
+#include <linux/dma-mapping.h>
+
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/delay.h>
+#include <asm/mach/irq.h>
+#include <asm/arch/hardware.h>
+#include <asm/arch/memory.h>
+#include <asm/arch/debug.h>
+#include <asm/sizes.h>
+#include <asm/uaccess.h>
+
+#include <linux/platform_device.h>
+#include <linux/firmware.h>
+#include <linux/interrupt.h>
+#include <linux/elf.h>
+#include <net/fpp_ops.h>
+
+#include "comcerto_fpp.h"
+#include "comcerto_eth.h"
+
+static unsigned char gVoiceIsRunning = 0;
+
+const char comcerto_fpp_driver_name[] = "Comcerto Fast Path Processor Driver";
+const char comcerto_fpp_driver_version[] = "1.0";
+struct mutex fpp_mutex; 
+
+static struct device ghost_device = {
+	.bus_id = "ghost0",
+};
+
+struct {
+	struct list_head buffer_list;
+	spinlock_t lock;
+} fpp_pool;
+
+
+static int comcerto_fpp_check_ready(struct comcerto_fpp *fpp, u32 timeout);
+static int comcerto_fpp_check_ack(unsigned long timeout);
+extern int comcerto_eth_register_fpp_ops(t_fpp_ops * ops);
+extern void comcerto_eth_unregister_fpp_ops(void);
+extern int comcerto_fpp_register_event_cb(void *cb);
+
+static void fpp_add_buffer(void *buffer)
+{
+	unsigned long flags;
+
+//	printk (KERN_INFO "add_buffer: %lx %lx\n", (unsigned long)buffer, virt_to_phys(buffer));
+
+	spin_lock_irqsave(&fpp_pool.lock, flags);
+	list_add((struct list_head *) buffer, &fpp_pool.buffer_list);
+	spin_unlock_irqrestore(&fpp_pool.lock, flags);
+}
+
+static void fpp_del_buffer(void *buffer) 
+{
+	unsigned long flags;
+
+//	printk (KERN_INFO "del_buffer: %lx %lx\n", (unsigned long)buffer, virt_to_phys(buffer));
+
+	spin_lock_irqsave(&fpp_pool.lock, flags);
+	list_del((struct list_head *)buffer);
+	spin_unlock_irqrestore(&fpp_pool.lock, flags);
+}
+
+/**
+ * comcerto_fpp_register_to_eth -
+ *
+ */
+static int comcerto_fpp_register_to_eth(void)
+{
+	t_fpp_ops fpp_ops;
+	int rc;
+
+	/* set wrapping functions */
+	fpp_ops.write = comcerto_fpp_write;
+	fpp_ops.read = comcerto_fpp_read;
+	fpp_ops.add_buffer = fpp_add_buffer;
+	fpp_ops.del_buffer = fpp_del_buffer;
+	
+	/* register the FPP module to the Ethernet Driver */
+	rc = comcerto_eth_register_fpp_ops(&fpp_ops);
+	if (rc)
+	{
+		printk(KERN_ERR "comcerto_eth_register_fpp_ops() failed !\n");
+		goto err;
+	}
+
+	return 0;
+
+err:
+	return rc;
+}
+
+/**
+ * fpp_register_event_cb -
+ *
+ */
+int comcerto_fpp_register_event_cb(void *cb)
+{
+	struct comcerto_fpp *fpp = ghost_device.driver_data;
+
+	/* register FCI callback used for asynchrounous event */
+	fpp->event_cb = (FPP_EVENT_CB)cb;
+
+	//printk(KERN_INFO "FPP: comcerto_fpp_register_event_cb()\n");
+
+	return 0;
+}
+EXPORT_SYMBOL(comcerto_fpp_register_event_cb);
+
+/**
+ * comcerto_fpp_write - 
+ *
+ *
+ */
+int comcerto_fpp_write(unsigned short fcode, unsigned short length, unsigned short *payload)
+{
+	unsigned short rfcode = 0;
+	unsigned short rlength = 0;
+	unsigned short rpayload[132] = {0};
+
+	/* message length must no be greater than 256 bytes*/
+	if (length > FPP_MAX_MSG_LENGTH) {
+		printk(KERN_ERR "comcerto_fpp_write: msg length(%d) too big\n", length);
+		return -EINVAL;
+	}
+
+	//printk(KERN_INFO "comcerto_fpp_write fcode 0x%x length %d\n", fcode, length);
+
+	/* wait until we can send a new message to the FPP */
+	//while(__raw_readl(CMD_MBOX_0_ADDR) == M0_CMD)
+	if(__raw_readl(CMD_MBOX_0_ADDR) & M0_CMD)
+	{
+		printk(KERN_ERR "comcerto_fpp_write: cannot send command\n");
+		return -EIO;
+		//set_current_state(TASK_UNINTERRUPTIBLE);
+		//schedule_timeout(1);
+	}
+
+	/* write function code and length to mailbox */
+	__raw_writel((fcode << 16 ) | length, CMD_MBOX_1_ADDR);
+
+	/* write message data to fifo */
+	memcpy(CMD_DATA_ADDR, (void*)payload, length);
+		
+	/* new message sent raise busy bit */
+	__raw_writel(M0_CMD, CMD_MBOX_0_ADDR);
+
+	/* new message raise from host irq */
+	__raw_writel((1UL << (FPP_IRQ_FROMHOST)), COMCERTO_INTC_SET_STATUS_REG_1);
+	
+	//printk(KERN_INFO "comcerto_fpp_write...done\n");
+
+	/* read ack from FPP */
+	if(comcerto_fpp_check_ack(1000) == 0)
+	{
+		/* ack has been posted by FPP read data */
+		comcerto_fpp_read(&rfcode, &rlength, &rpayload[0]);
+		if((rfcode == fcode) && (rlength == 2) && (rpayload[0] == 0))
+		{
+			return 0;
+		}
+		else
+		{
+			printk(KERN_ERR "wrong ack rfcode=0x%x rlentgh=%d rpayload=0x%x\n", rfcode, rlength, rpayload[0]);
+			return rpayload[0];
+		}
+	}
+	else
+		return -EIO;
+}
+EXPORT_SYMBOL(comcerto_fpp_write);
+
+int
+comcerto_fpp_cmd(unsigned short fcode, 
+		 unsigned short length, 
+		 unsigned short *payload, 
+		 unsigned short *rsp_len, 
+		 unsigned short *rsp)
+{
+	unsigned short rfcode = 0;
+
+	if (rsp_len)
+	    *rsp_len = 0;
+	if ((rsp_len == NULL) || (rsp == NULL)) {
+	  return comcerto_fpp_write( fcode, length, payload);
+	}
+
+	/* message length must no be greater than 256 bytes*/
+	if (length > FPP_MAX_MSG_LENGTH) {
+		printk(KERN_ERR "comcerto_fpp_cmd: msg length(%d) too big\n", length);
+		return -EINVAL;
+	}
+	//printk(KERN_INFO "comcerto_fpp_write fcode 0x%x length %d\n", fcode, length);
+
+	/* wait until we can send a new  message to the FPP */
+	//while(__raw_readl(CMD_MBOX_0_ADDR) == M0_CMD)
+	if(__raw_readl(CMD_MBOX_0_ADDR) & M0_CMD)
+	{
+		printk(KERN_ERR "comcerto_fpp_cmd: cannot send command\n");
+		return -EIO;
+		//set_current_state(TASK_UNINTERRUPTIBLE);
+		//schedule_timeout(1);
+	}
+
+	/* write function code and length to mailbox */
+	__raw_writel((fcode << 16 ) | length, CMD_MBOX_1_ADDR);
+
+	/* write message data to fifo */
+	memcpy(CMD_DATA_ADDR, (void*)payload, length);
+		
+	/* new message sent raise busy bit */
+	__raw_writel(M0_CMD, CMD_MBOX_0_ADDR);
+
+	/* new message raise from host irq */
+	__raw_writel((1UL << (FPP_IRQ_FROMHOST)), COMCERTO_INTC_SET_STATUS_REG_1);
+	
+	//printk(KERN_INFO "comcerto_fpp_write...done\n");
+
+	/* read ack from FPP */
+	
+	if(comcerto_fpp_check_ack(1000) == 0)
+	{
+	  /*ack has been posted by FPP read data  */
+	  comcerto_fpp_read(&rfcode, rsp_len,(void*)rsp);
+	  if((rfcode == fcode) && (*rsp_len >= 2) && (*rsp == 0)){
+	    //	    printk(KERN_INFO "returning fc:0x%04x l:0x%04x r:0x%04x 0x%04x 0x%04x\n", fcode, *rsp_len, *rsp, *(rsp+1), *(rsp+2)); 
+	    return 0;
+	  } else {
+	    //	    printk(KERN_INFO "bad ack in fpp_cmd returning fc:0x%04x l:0x%04x r:0x%04x 0x%04x 0x%04x\n", fcode, *rsp_len, *rsp, *(rsp+1), *(rsp+2)); 
+	    return rsp[0];
+	  }
+	}
+	else
+	  return -EIO;
+}
+EXPORT_SYMBOL(comcerto_fpp_cmd);
+/**
+ * comcerto_fpp_read - 
+ *
+ *
+ */
+int comcerto_fpp_read(unsigned short *fcode, unsigned short *length, unsigned short *payload)
+{
+
+	//printk(KERN_INFO "comcerto_fpp_read\n");
+
+	/* get function code */
+	*fcode = (__raw_readl(CMD_MBOX_1_ADDR) >> 16);
+
+	/* get message length */
+	*length = (__raw_readl(CMD_MBOX_1_ADDR) & 0x0000FFFF);
+
+	/* copy message data */
+	memcpy((void*)payload, CMD_DATA_ADDR, *length);
+
+	/* new message processed clear busy bit */
+	__raw_writel(0, CMD_MBOX_0_ADDR);
+
+	//printk(KERN_INFO "comcerto_fpp_read done\n");
+
+	return 0;
+}
+EXPORT_SYMBOL(comcerto_fpp_read);
+
+/**
+ * comcerto_fpp_read_event - 
+ *		This function is called from a tasklet 
+ *		and perform handling of the asynchronous event from the FPP.
+ */
+int comcerto_fpp_read_event(unsigned short *fcode, unsigned short *length, unsigned short *payload)
+{
+
+	//printk(KERN_INFO "comcerto_fpp_read_event\n");
+
+	if ((__raw_readl(EVENT_MBOX_0_ADDR) & M0_EVENT) == 0)
+		return -1;
+
+	/* get function code */
+	*fcode = (__raw_readl(EVENT_MBOX_1_ADDR) >> 16);
+
+	/* get message length */
+	*length = (__raw_readl(EVENT_MBOX_1_ADDR) & 0x0000FFFF);
+
+	/* copy message data */
+	memcpy((void*)payload, EVENT_DATA_ADDR, *length);
+
+	/* new message processed clear busy bit */
+	__raw_writel(0, EVENT_MBOX_0_ADDR);
+
+	/* new read from host irq */
+	__raw_writel((1UL << (FPP_IRQ_TOHOST)), COMCERTO_INTC_SET_STATUS_REG_1);
+
+	//printk(KERN_INFO "comcerto_fpp_read done: fcode 0x%x length %d\n", *fcode, *length);
+
+	return 0;
+}
+EXPORT_SYMBOL(comcerto_fpp_read_event);
+
+/**
+ * fpp_command_parser -
+ *
+ *          This function is called by upper layer
+ *          to give message to FPP Forward Engine.
+ *
+ */
+int fpp_command_parser(unsigned short fc, unsigned short length, unsigned short *data, unsigned short *rlen, unsigned short *rdata)
+{
+	int rc;
+
+	mutex_lock(&fpp_mutex);
+	rc = comcerto_fpp_cmd(fc, length, data,rlen,rdata);
+	mutex_unlock(&fpp_mutex);
+
+	return rc;
+}
+EXPORT_SYMBOL(fpp_command_parser);
+
+
+/**
+* comcerto_fpp_check_ack
+* 
+*/
+static int comcerto_fpp_check_ack(unsigned long timeout)
+{
+	unsigned long count = 0;
+	unsigned long j = jiffies + 2;
+
+	//printk(KERN_INFO "comcerto_fpp_check_ack\n");
+
+	/* do busy-wait for up to 2 clock ticks */
+
+	while (time_before(jiffies, j))
+	{
+		if (need_resched())
+			schedule();
+		if ((__raw_readl(CMD_MBOX_0_ADDR) & M0_ACK) != 0)
+			return 0;
+	}
+
+	/* if we get this far, we need to release the cpu to other tasks */
+
+	while (1) {
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		schedule_timeout(1);
+
+		if ((__raw_readl(CMD_MBOX_0_ADDR) & M0_ACK) != 0)
+			return 0;
+
+		/* timeout is passed in ms, increment count by msec per jiffie */
+		count += 1000 / HZ;
+		if (count >= timeout) {
+			printk(KERN_ERR "comcerto_fpp_check_ack: didn't receive ack from FPP\n");
+			goto err;
+		}
+	}
+
+	return 0;
+err:
+	return -1;
+}
+
+
+
+/**
+ * fpp_set_resethandler - 
+ *
+ *
+ */
+static void fpp_set_resethandler(struct comcerto_fpp *fpp, unsigned long base_address)
+{
+	__raw_writel(0xE59FF018, fpp->vectors_base);	/* LDR PC, [PC,#20] */
+	__raw_writel(base_address, fpp->vectors_base + 0x00000020);	/* jump to msp start */
+}
+
+
+/**
+ * download_elf_image - 
+ *
+ *
+ */
+static int download_elf_image(struct _code_info *code_info)
+{
+	int i;
+	int rc = 0;
+	char *section_name;
+	Elf32_Ehdr *this_elf_header = (Elf32_Ehdr *)(code_info->code);
+	Elf32_Half number_of_section = this_elf_header->e_shnum;
+	/* pointer to the Section header.  */
+	Elf32_Shdr *this_section_headers = (Elf32_Shdr *) (code_info->code + this_elf_header->e_shoff);
+	Elf32_Off string_section_offset = this_section_headers[this_elf_header->e_shstrndx].sh_offset;
+	u32 checksum_program_addr=0;
+
+	//printk(KERN_INFO "download_elf_image\n");
+
+	if (!number_of_section)
+	{
+		PDEBUG(MSP_ERR, "Invalid of section = %d ", number_of_section);
+		rc = -EINVAL;
+		goto out;
+	}
+	
+	/* parse all sections */
+	for (i = 0; i < number_of_section; i++)
+	{
+		section_name = code_info->code  + string_section_offset + this_section_headers[i].sh_name;
+		if (!strncmp(section_name, "svc_stack", 8))
+		{
+				code_info->stack_addr = this_section_headers[i].sh_addr;
+				code_info->stack_size = this_section_headers[i].sh_size;
+				PDEBUG (MSP_INIT, "stack_addr at 0x%08x", code_info->stack_addr);
+		} 
+		
+		/* retrieve the section name from the ELF buffer */
+		if (!strncmp(section_name, "CHECKSUM", 8))
+		{
+				checksum_program_addr = *((u32 *) (code_info->code + this_section_headers[i].sh_offset));
+				PDEBUG (MSP_INIT, "checksum prog at 0x%08x", checksum_program_addr);
+		} 
+		else if ((this_section_headers[i].sh_flags != SHF_MIPS_ADDR) && 
+		    (this_section_headers[i].sh_flags != 0)) 
+		{
+			/* retrieve the section name from the ELF buffer */
+			
+			if ((this_section_headers[i].sh_type & 3) == SHT_PROGBITS)
+			{
+				PDEBUG (MSP_INIT, "%s section: %d bytes to load at addr:0x%08x from elf offset: %d",
+					section_name,
+					this_section_headers[i].sh_size,
+					this_section_headers[i].sh_addr,
+					this_section_headers[i].sh_offset);
+				if ((this_section_headers[i].sh_addr >= COMCERTO_ARAM_BASE) && (this_section_headers[i].sh_addr <= (COMCERTO_ARAM_BASE + ARAM_MEMORY_SIZE)))
+				memcpy(
+					aram_to_virt(this_section_headers[i].sh_addr),
+					(void*)(code_info->code + this_section_headers[i].sh_offset),
+					this_section_headers[i].sh_size);
+					
+				else					
+				memcpy(
+					msp_to_virt(this_section_headers[i].sh_addr),
+					(void*)(code_info->code + this_section_headers[i].sh_offset),
+					this_section_headers[i].sh_size);
+			}
+		}
+	}
+	/* everything went OK */
+	code_info->program_addr = this_elf_header->e_entry;
+
+out:
+	return rc;
+
+}
+
+/**
+ * comcerto_fpp_download - 
+ *
+ *
+ */
+static int comcerto_fpp_download(struct comcerto_fpp *fpp)
+{
+	struct _code_info *code_info = &fpp->code_info;
+	int rc;
+
+	//printk(KERN_INFO "comcerto_fpp_download\n");
+
+	rc = download_elf_image(code_info); 
+	if (rc)
+	{
+		printk(KERN_INFO "FPP download done \n");
+		goto err;
+	}
+
+	return 0;
+
+err:
+	return rc;
+}
+
+/**
+ * comcerto_fpp_check_ready - 
+ *
+ *
+ */
+static int comcerto_fpp_check_ready(struct comcerto_fpp *fpp, u32 timeout)
+{
+	u32 count = 0;
+	u8 version[32] = {0};
+	int rc;
+
+	//printk(KERN_INFO "comcerto_fpp_check_ready\n");
+
+	/* timeout is passed in ms, set it in jiffies */
+	timeout = (timeout * HZ) / 1000;
+	
+	while (__raw_readl(CMD_MBOX_0_ADDR) != TX_MAGIC) {
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		schedule_timeout(1);
+
+		if (++count >= timeout) {
+			printk(KERN_ERR "Didn't receive ack from FPP\n");
+			fpp->info = NULL;
+			rc = -EIO;
+			goto err;
+		}
+	}
+
+	/* get firmware version */
+	memcpy(version, CMD_DATA_ADDR, sizeof(version));
+
+	__raw_writel(0, CMD_MBOX_0_ADDR);
+
+	printk(KERN_INFO "FPP is running %s\n", version);
+
+	return 0;
+
+err:
+	return rc;
+}
+
+
+/**
+ *  comcerto_fpp_fill_v2_fifo -
+ *
+ *
+ */
+static void fill_v2_fifo(struct sk_buff *this_fifo_skb, u16 index, u16 cmd_class, u16 cmd_type,
+				u16 func_code, u16 number_of_params, ...)
+{
+	va_list param_list;
+	int i;
+
+	put_fifo_header(this_fifo_skb, index, cmd_class, cmd_type, func_code);	
+
+	((u16 *)this_fifo_skb->tail)[0] += number_of_params * 2;
+
+	va_start(param_list, number_of_params);
+
+	for (i = 0; i < number_of_params; i++)
+	{
+		((u16 *)this_fifo_skb->tail)[i + 4] =  va_arg (param_list, int);
+	}
+
+	va_end(param_list);
+
+	put_fifo_padding(this_fifo_skb);
+}
+
+
+static int comcerto_fpp_SPAWN_TASK(u32 entry_point, u32 stack_ptr, unsigned short stacksize)
+{
+	struct sk_buff *this_skb;
+	unsigned short channel_id;
+	int rc;
+
+//	printk(KERN_INFO "comcerto_fpp_SPAWN_TASK: %x %x %x\n", entry_point, stack_ptr, stacksize);
+
+	this_skb = dev_alloc_skb(1024);
+	if (this_skb == NULL)
+	{
+		printk(KERN_ERR "comcerto_fpp_SPAWN_TASK: skb alloc failed\n");
+		rc = -ENOMEM;
+		goto err0;
+	}
+	skb_reserve(this_skb, 32);
+
+	channel_id = COMCERTO_SUPVSR;
+	memcpy(skb_put(this_skb, 2), &channel_id, 2);
+
+	fill_v2_fifo(this_skb, 0, CMD_CLASS_CONFIGURATION_DEVICE, CMD_TYPE_CONFIGURATION_CHANGE, DEVICE_SPAWN_BGTASK, 5,
+			entry_point & 0xffff, entry_point >> 16,
+			stack_ptr & 0xffff, stack_ptr >> 16,
+			stacksize);
+
+	rc = dci_kioctl(DCI_KIOC_DEV_WRITE_MSG, 1, this_skb);         
+	if (rc)
+	{
+		printk(KERN_ERR "comcerto_fpp_SPAWN_TASK: dci_kioctl() failed\n");
+		
+		goto err1;
+	}
+
+	return 0;
+
+err1:
+	dev_kfree_skb(this_skb);
+
+err0:
+	return rc;
+}
+
+static int comcerto_fpp_KILL_TASK(u32 entry_point, u32 stack_ptr, unsigned short stacksize)
+{
+	struct sk_buff *this_skb;
+	unsigned short channel_id;
+	int rc;
+
+	printk(KERN_INFO "comcerto_fpp_KILL_TASK: %x %x %x\n", entry_point, stack_ptr, stacksize);
+
+	this_skb = dev_alloc_skb(1024);
+	if (this_skb == NULL)
+	{
+		printk(KERN_ERR "comcerto_fpp_KILL_TASK: skb alloc failed\n");
+		rc = -ENOMEM;
+		goto err0;
+	}
+	skb_reserve(this_skb, 32);
+
+	channel_id = COMCERTO_SUPVSR;
+	memcpy(skb_put(this_skb, 2), &channel_id, 2);
+
+	fill_v2_fifo(this_skb, 0, CMD_CLASS_CONFIGURATION_DEVICE, CMD_TYPE_CONFIGURATION_CHANGE, DEVICE_KILL_BGTASK, 0);
+
+	rc = dci_kioctl(DCI_KIOC_DEV_WRITE_MSG, 1, this_skb);
+	if (rc)
+	{
+		printk(KERN_ERR "comcerto_fpp_KILL_TASK: dci_kioctl() failed\n");
+		
+		goto err1;
+	}
+
+	return 0;
+
+err1:
+	dev_kfree_skb(this_skb);
+
+err0:
+	return rc;
+}
+
+/**
+ * comcerto_fpp_start - 
+ *
+ *
+ */
+static int comcerto_fpp_start(struct comcerto_fpp *fpp)
+{
+	int arm1_running;
+	int rc;
+
+	//printk(KERN_INFO "comcerto_fpp_start\n");
+
+	// is ARM1 already running MSP code ?
+	arm1_running = (__raw_readl(COMCERTO_INTC_ARM1_CONTROL_REG) &  0x80000000);
+
+	fpp->state = MSP_STARTING;
+
+	/* clear FPP ready status register */
+	__raw_writel(0, CMD_MBOX_0_ADDR);
+	__raw_writel(0, EVENT_MBOX_0_ADDR);
+
+	if (arm1_running) {
+		rc = comcerto_fpp_SPAWN_TASK(fpp->code_info.program_addr, fpp->code_info.stack_addr, fpp->code_info.stack_size);
+		if (rc)
+			goto err;
+		gVoiceIsRunning = 1;
+	}
+	else
+	{
+		fpp_set_resethandler(fpp, fpp->code_info.program_addr);
+		__raw_writel(0x80000000, COMCERTO_INTC_ARM1_CONTROL_REG);
+	}
+	
+	rc = comcerto_fpp_check_ready(fpp, 8000); 
+	if (rc) {
+		printk(KERN_ERR "comcerto_fpp_start: failed to start FPP\n");
+		goto err;
+	}
+
+	fpp->state = MSP_RUNNING;
+
+	return 0;
+err:
+	return rc;
+
+}
+
+/**
+ * comcerto_fpp_interrupt - 
+ *
+ *
+ */
+irqreturn_t comcerto_fpp_interrupt(int irq, void *dev_id)
+{
+	struct device *dev = (struct device *)dev_id;
+	struct comcerto_fpp *fpp = dev_get_drvdata(dev);
+				
+	tasklet_schedule(&fpp->event_tasklet);
+	//disable_irq(fpp->irq);
+
+	return IRQ_HANDLED;
+}
+
+/**
+ * comcerto_fpp_tasklet - 
+ *
+ *
+ */
+static void comcerto_fpp_tasklet(unsigned long arg)
+{
+	struct comcerto_fpp *fpp =  (struct comcerto_fpp *)arg;
+	struct fpp_event event;
+	
+	if (comcerto_fpp_read_event(&event.fcode, &event.length, &event.payload[0]) == 0)
+	{
+		/* call FCI callback */
+		if(fpp->event_cb != NULL)
+		{	
+			fpp->event_cb(event.fcode, event.length, &event.payload[0]);
+		}
+
+	}
+
+	//enable_irq(fpp->irq);
+}
+
+
+/**
+ * comcerto_fpp_pool_reset - 
+ *
+ *
+ */
+static void comcerto_fpp_pool_reset(void)
+{
+	struct list_head *head, *tmp;
+	unsigned long flags;
+
+	spin_lock_irqsave(&fpp_pool.lock, flags);
+
+	list_for_each_safe(head, tmp, &fpp_pool.buffer_list) {
+//		printk(KERN_INFO "free_buffer: %lx %lx\n", (unsigned long)head, virt_to_phys(head));
+		list_del(head);
+		kfree(head);
+	}
+
+	spin_unlock_irqrestore(&fpp_pool.lock, flags);
+}
+
+/**
+ * comcerto_fpp_pool_init - 
+ *
+ *
+ */
+static int comcerto_fpp_pool_init(void)
+{
+	int total = 0;
+	int n, i;
+	u16 cmd[128];
+	u32 *pool;
+	void *ptr;
+	int rc;
+
+	INIT_LIST_HEAD(&fpp_pool.buffer_list);
+	spin_lock_init(&fpp_pool.lock);
+
+	// populate packets buffer pool
+	do {
+		if (total)
+			cmd[0] = 0;
+		else
+			/* Reset the FPP buffer pool */
+			cmd[0] = 1;
+
+		cmd[1] = 0;
+		pool = (u32 *)&cmd[2];
+		n = min(63, (FPP_PKT_POOL_SIZE - total));
+		for (i = 0; i < n; i++) {
+			ptr = kmalloc(FPP_SKB_SIZE, GFP_KERNEL | GFP_DMA);
+			if (!ptr) {
+				printk(KERN_ERR "comcerto_fpp: unable to allocate FPP's buffer pool\n");
+				rc = -ENOMEM;
+				goto err;
+			}
+
+			consistent_sync(ptr, FPP_SKB_SIZE, DMA_FROM_DEVICE);
+
+//			printk(KERN_INFO "%d %d %lx %lx\n", total, i, (unsigned long)ptr,  virt_to_phys(ptr));
+
+			*pool++ = virt_to_phys(ptr);
+			total++;
+
+			/* add to internal hash table for linux buffer track/release */
+			fpp_add_buffer(ptr);
+		}
+
+		rc = comcerto_fpp_write(CMD_RX_FILL_BUFFERPOOL, 2 * sizeof(u16) + n * sizeof(u32), cmd);
+		if (rc)
+			goto err;
+
+	} while (total < FPP_PKT_POOL_SIZE);
+
+out:
+	return 0;
+
+err:
+	comcerto_fpp_pool_reset();	
+	return rc;
+}
+
+
+/**
+ * comcerto_fpp_init - 
+ *
+ *
+ */
+static int comcerto_fpp_init(struct device *dev)
+{
+	struct comcerto_fpp *fpp;
+	const struct firmware *fw_entry;
+	int rc = 0;
+
+	//printk(KERN_INFO "comcerto_fpp_init\n");
+
+	fpp = (struct comcerto_fpp *)kzalloc(sizeof(struct comcerto_fpp), GFP_KERNEL);
+	if (fpp == NULL) {
+		rc = -ENOMEM;
+		goto err0;
+	}	
+	dev_set_drvdata(dev,fpp);
+
+	if (request_firmware(&fw_entry,"fpp.axf", dev) !=0 ) {
+		printk(KERN_ERR "Error finding FPP firmware\n");
+		rc = -ETIMEDOUT;
+		goto err1;
+	}
+	
+	fpp->code_info.code = fw_entry->data;
+	fpp->code_info.size = fw_entry->size;
+	if (SDRAM_MSP_MEMORY_PHY) // MSP @ address 0x0
+		fpp->vectors_base = ioremap(0x00000000, 0x40);
+	else
+		fpp->vectors_base = (void*)SDRAM_MSP_MEMORY_VADDR;
+
+	if (!fpp->vectors_base) {
+		printk(KERN_ERR "Cannot map fpp vectors, aborting.\n");
+		rc = -EINVAL;
+		goto err2;
+	}
+
+	rc = comcerto_fpp_download(fpp); 
+	if (rc)
+		goto err2;
+
+	rc = comcerto_fpp_start(fpp); 
+	if (rc)
+		goto err2;
+
+	rc = comcerto_fpp_pool_init();
+	if (rc)
+		goto err2;
+
+	fpp->irq= FPP_IRQ_EVENT;
+
+	tasklet_init(&fpp->event_tasklet, comcerto_fpp_tasklet, (unsigned long)fpp);
+	
+	rc = request_irq(fpp->irq , comcerto_fpp_interrupt, SA_SHIRQ, comcerto_fpp_driver_name, dev);
+	if (rc) {
+		printk(KERN_INFO "comcerto_fpp: failed to get the irq: %d\n", fpp->irq);
+		goto err2;
+	}
+
+	release_firmware(fw_entry);
+	return 0;
+
+err2:
+	release_firmware(fw_entry);
+
+err1:
+	kfree(fpp);
+
+err0:
+	return rc;
+}
+
+/**
+ * comcerto_fpp_reset - 
+ *
+ *
+ */
+static int comcerto_fpp_reset(struct device *dev)
+{
+	struct comcerto_fpp *fpp = dev_get_drvdata(dev);
+	
+	//printk(KERN_INFO "comcerto_fpp_reset\n");
+
+	fpp->state = MSP_RESET;
+
+	if(gVoiceIsRunning) {
+		comcerto_fpp_KILL_TASK(fpp->code_info.program_addr, fpp->code_info.stack_addr, fpp->code_info.stack_size);
+	}	
+	else {
+		__raw_writel(0x00000000, COMCERTO_INTC_ARM1_CONTROL_REG);
+	}
+
+	comcerto_fpp_pool_reset();
+
+	free_irq(fpp->irq, dev);
+
+	kfree(fpp);
+
+	return 0;
+}
+
+/**
+ * comcerto_fpp_module_init - 
+ *
+ *
+ */
+static int __init comcerto_fpp_module_init(void)
+{
+	int rc;
+
+	printk(KERN_INFO "comcerto_fpp_module_init\n");
+
+	device_initialize(&ghost_device);
+
+	mutex_init(&fpp_mutex);
+
+	rc = comcerto_fpp_init(&ghost_device); 
+	if (rc)
+		goto err0;
+
+	rc = comcerto_fpp_register_to_eth(); 
+	if (rc)
+		goto err1;
+
+	return 0;
+
+err1:
+	comcerto_fpp_reset(&ghost_device);
+
+err0:
+	return rc;
+}
+
+
+/**
+ * comcerto_fpp_exit - 
+ *
+ *
+ */
+static void __exit comcerto_fpp_module_exit(void)
+{
+	comcerto_eth_unregister_fpp_ops();
+
+	comcerto_fpp_reset(&ghost_device);
+
+	printk(KERN_INFO "comcerto_fpp_module_exit\n");
+}
+
+module_init(comcerto_fpp_module_init);
+module_exit(comcerto_fpp_module_exit);
+
+MODULE_LICENSE("GPL");
diff -r e137be04dc4d drivers/net/comcerto/comcerto_fpp.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/net/comcerto/comcerto_fpp.h	Mon Aug 17 16:45:23 2009 -0500
@@ -0,0 +1,211 @@
+/*
+ *  linux/drivers/net/comcerto/comcerto_msp.h
+ *
+ *  Copyright (C) 2006 Mindspeed Technologies, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef __COMCERTO_FPP_H__
+#define __COMCERTO_FPP_H__
+
+#include <linux/firmware.h>
+#include <linux/elf.h>
+#include <asm/arch/debug.h>
+#include <linux/netdevice.h>
+
+
+int comcerto_fpp_write(unsigned short fcode, unsigned short length, unsigned short *payload);
+int comcerto_fpp_read(unsigned short *fcode, unsigned short *length, unsigned short *payload);
+
+
+/* copied from usr/include/elf.h */
+#ifndef _ELF_H
+#define	_ELF_H 1
+#define EM_ARM		40		/* ARM */
+
+#define SHF_MIPS_ADDR 0x40000000
+#define SHT_PROGBITS 1
+#endif
+
+#define FPP_PKT_POOL_SIZE	768
+
+/* FPP mailboxes and fifos registers */
+
+#define CMD_MBOX_0_ADDR		aram_to_virt(0x0A000000)
+#define CMD_MBOX_1_ADDR		aram_to_virt(0x0A000004)
+#define EVENT_MBOX_0_ADDR	aram_to_virt(0x0A000010) 
+#define EVENT_MBOX_1_ADDR	aram_to_virt(0x0A000014)
+
+#define CMD_DATA_ADDR		aram_to_virt(0x0A000020)
+#define EVENT_DATA_ADDR		aram_to_virt(0x0A000220)
+
+#define M0_CMD	0x00000001	
+#define M0_ACK	0x00000002
+#define M0_EVENT	0x00000004
+
+#define TX_MAGIC	0x4D535044	/* set by FPP when ready */
+
+
+#define FPP_IRQ_FROMHOST	19
+#define FPP_IRQ_TOHOST		20
+#define FPP_IRQ_EVENT		(32+25)
+
+
+#define FPP_MAX_MSG_LENGTH	256 /* expressed in U8 -> 256 bytes*/
+
+
+typedef void (*FPP_EVENT_CB)(u16, u16, u16*);
+
+enum MSP_states {
+	MSP_RESETTING = 0,
+	MSP_RESET,
+	MSP_STARTING,
+	MSP_RUNNING,
+	MSP_CRASHED
+};
+
+struct _code_info {
+	u8 *code;
+	u32 size;
+	u32 checksum_program_addr;
+	u32 program_addr;
+	u32 stack_addr;
+	u32 stack_size;
+	u32 checksum;
+};
+
+struct fpp_event {
+	
+	unsigned short fcode;
+	unsigned short length;
+	unsigned short payload[128];
+};
+
+struct fpp_info {
+	unsigned long ABI_rev;
+	unsigned long Device;
+	unsigned long Revision;
+	char fpp_version[32];
+	unsigned long ARAMsize;
+	unsigned short ARMfreq;
+	unsigned short AMBAfreq;
+	volatile unsigned int ready;
+};
+
+struct comcerto_fpp
+{
+	int state;
+	volatile struct fpp_info *info;
+	struct _code_info code_info;
+	void* __iomem vectors_base;
+	struct tasklet_struct event_tasklet;
+	FPP_EVENT_CB event_cb;
+	int irq;
+};
+
+
+
+/* FPP API definitions */
+//0x0000 -> 0x00FF : RX module
+#define CMD_RX_ENABLE		0x0001
+#define CMD_RX_DISABLE		0x0002
+#define CMD_RX_FILL_BUFFERPOOL	0x0006
+
+//0x0100 -> 0x01FF : Ethernet module
+
+//0x0200 -> 0x02FF : IPv4 module
+
+//0x0300 -> 0x03FF : QM module
+
+//0x0400 -> 0x04FF : Scheduler module
+
+//0x0500 -> 0x05FF : TX module
+#define CMD_TX_ENABLE	0x0501
+#define CMD_TX_DISABLE	0x0502
+
+
+
+
+#define COMCERTO_SUPVSR			0xffff
+#define CMD_CLASS_STATISTICS_CHANNEL		0x01
+#define CMD_CLASS_CONFIGURATION_CHANNEL		0x02
+#define CMD_CLASS_LEGACY_MSG				0x03
+#define CMD_CLASS_ETH_BOOT_LDR				0x04
+#define CMD_CLASS_STATISTICS_DEVICE			0x05
+#define CMD_CLASS_CONFIGURATION_DEVICE		0x06
+
+#define CMD_CLASS_REFERENCE_DIAGNOSTIC		0xc1
+#define CMD_CLASS_OPEN_DIAGNOSTIC			0xc2
+
+/* Command types for Command class 0x02/0x06 */
+#define CMD_TYPE_CONFIGURATION_CHANGE		0x00
+#define CMD_TYPE_CONFIGURATION_QUERY		0x01
+#define CMD_TYPE_ACKNOWLEDGEMENT			0x02
+#define CMD_TYPE_INDICATION					0x03
+#define CMD_TYPE_QUERY_RESPONSE				0x04
+#define CMD_TYPE_INDICATION_RESPONSE		0x05
+
+#define DEVICE_SPAWN_BGTASK		0x04F0	
+#define DEVICE_KILL_BGTASK			0x04F1	
+
+#define DCI_KIOC_SET_CFG		0
+#define DCI_KIOC_DEV_GET_INFO		1
+#define DCI_KIOC_DEV_INIT		2
+#define DCI_KIOC_DEV_RESET		3
+#define DCI_KIOC_DEV_WRITE_MSG		4
+#define DCI_KIOC_DEV_READ_MSG		5
+#define DCI_KIOC_DEV_GET_STATE		6
+
+
+
+/*
+ * put_fifo_header -
+ *
+ * Puts msg header at end of skb. skb->tail is not updated.
+ *
+ */
+static inline void put_fifo_header(struct sk_buff *this_fifo_skb, u16 index, u16 cmd_class, u16 cmd_type, u16 func_code)
+{
+	((u16 *)this_fifo_skb->tail)[0] = ((index & 0xff)  << 8) | 8;
+	((u16 *)this_fifo_skb->tail)[1] = ((cmd_class & 0xff) << 8) | (cmd_type & 0xff);
+	((u16 *)this_fifo_skb->tail)[2] = func_code;
+	((u16 *)this_fifo_skb->tail)[3] = 0x0000;
+}
+
+/**
+ * put_fifo_padding -
+ *
+ * Puts msg padding at end of skb. skb->tail is moved down to match the payload & padding added to the message.
+ * skb->tail should point to beginning of msg header.
+ *
+ */
+static inline void put_fifo_padding(struct sk_buff *this_fifo_skb)
+{
+	int padding;
+	u16 msg_length = ((u16 *)this_fifo_skb->tail)[0] & 0xff;
+
+	skb_put(this_fifo_skb, msg_length);
+
+	if (msg_length & 0x3)
+	{
+		padding = 4 - (msg_length & 0x3);
+
+		memset(this_fifo_skb->tail, 0, padding);
+		skb_put(this_fifo_skb, padding);
+	}
+}
+
+#endif
diff -r e137be04dc4d drivers/net/comcerto/comcerto_gem_AL.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/net/comcerto/comcerto_gem_AL.c	Mon Aug 17 16:45:23 2009 -0500
@@ -0,0 +1,1723 @@
+/*
+ *  linux/drivers/net/comcerto/comcerto_gem_AL.c
+ *
+ *  Copyright (C) 2006 Mindspeed Technologies, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This 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 "comcerto_gemac.h"
+/******************************************************************************/
+
+
+/* Some functions to set/reset and get specific bits in the MAC registers
+ * Note that all functions operate on a read-modify-write basis
+ */
+
+
+/******************************************************************************/
+/*
+ * Function to start transmission on the specified device.  The parameter to
+ * this function is simply a pointer to the GEM_DEVICE structure.
+ * This function should be called after the relevant queues and data has been
+ * set up, however it will check if the number of queue elements is zero first.
+ * Note that this function will also enable tx even if it was previously not set
+ *
+ * Return value:
+ *  0   :   OK
+ *  -1  :   Transmit queue not valid.
+ */
+/******************************************************************************/
+int gem_start_tx(GEM_DEVICE *mac)
+{
+	*(u32 *)(mac->registers + GEM_NET_CONTROL) |= (GEM_TX_START | GEM_TX_EN);
+	return 0;
+}
+/******************************************************************************/
+
+
+/******************************************************************************/
+/*
+ * Halt transmission after current frame has completed.  This is accomplished
+ * simply by writing to the GEM_TX_HALT bit in the network control register,
+ * which should cause the MAC to complete its current frame then stop.
+ *
+ * There is no return value for this function.
+ */
+/******************************************************************************/
+void gem_stop_tx(GEM_DEVICE *mac)
+{
+	*(u32 *)(mac->registers + GEM_NET_CONTROL) |= GEM_TX_HALT;
+}
+/******************************************************************************/
+
+
+/******************************************************************************/
+/*
+ * Abort transmission immediately WITHOUT waiting for completion of any current
+ * frame.
+ * Note that after this operation, the transmit buffer descriptor will be reset
+ * to point to the first buffer in the descriptor list!
+ *
+ * There is no return value.
+ */
+/******************************************************************************/
+void gem_abort_tx(GEM_DEVICE *mac)
+{
+	*(u32 *)(mac->registers + GEM_NET_CONTROL) &= (~GEM_TX_EN);
+}
+/******************************************************************************/
+
+
+/******************************************************************************/
+/*
+ * Obtains status of transmission circuitry, whether it is transmitting or idle.
+ *
+ * Return value:
+ *  0   :   Transmitter is idle.
+ *  1   :   Transmitter active.
+ */
+/******************************************************************************/
+int gem_transmitting(GEM_DEVICE *mac)
+{
+	return (*(u32 *)(mac->registers + GEM_TX_STATUS) & GEM_TX_GO) == GEM_TX_GO;
+}
+/******************************************************************************/
+
+
+/******************************************************************************/
+/*
+ * Enable the receive circuitry.  This should be performed only after the
+ * buffers and the descriptor queues have been set up, otherwise unpredictable
+ * results may occur.
+ *
+ * Return value:
+ *  0   :   OK
+ *  -1  :   Receive queue not valid.
+ */
+/******************************************************************************/
+int gem_enable_rx(GEM_DEVICE *mac)
+{
+	*(u32 *)(mac->registers + GEM_NET_CONTROL) |= GEM_RX_EN;
+	return 0;
+}
+/******************************************************************************/
+
+
+/******************************************************************************/
+/*
+ * Disable the receive circuitry.  This will stop reception of any frame
+ * immediately, note that the descriptor pointer is not changed.
+ *
+ * There is no return value for this function.
+ */
+/******************************************************************************/
+void gem_disable_rx(GEM_DEVICE *mac)
+{
+	*(u32 *)(mac->registers + GEM_NET_CONTROL) &= (~GEM_RX_EN);
+}
+/******************************************************************************/
+
+
+/******************************************************************************/
+/*
+ * Obtain the status of the receive circuitry, whether it is enabled.
+ *
+ * Return value:
+ *  0   :   Receive circuitry disabled.
+ *  -1  :   Receive circuits enabled.
+ */
+/******************************************************************************/
+int gem_receive_on(GEM_DEVICE *mac)
+{
+	return (*(u32 *)(mac->registers + GEM_NET_CONTROL) & GEM_RX_EN) == GEM_RX_EN;
+}
+/******************************************************************************/
+
+
+/******************************************************************************/
+/*
+ * Set the loopback mode of the MAC.  This can be either no loopback for normal
+ * operation, local loopback through MAC internal loopback module or PHY
+ * loopback for external loopback through a PHY.  This asserts the external loop
+ * pin.
+ * The function parameters are a pointer to the device and an enumerated type
+ * specifying the type of loopback required.
+ *
+ * Note: if an invalid loopback mode is specified, loop back will be disabled.
+ *
+ * There is no return value for this function.
+ */
+/******************************************************************************/
+void gem_set_loop(GEM_DEVICE  *mac, MAC_LOOP    gem_loop)
+{
+	switch (gem_loop) {
+	case LB_LOCAL:
+		*(u32 *)(mac->registers + GEM_NET_CONTROL) &= (~GEM_LB_PHY);
+		*(u32 *)(mac->registers + GEM_NET_CONTROL) |= (GEM_LB_MAC);
+		break;
+	case LB_EXT:
+		*(u32 *)(mac->registers + GEM_NET_CONTROL) &= (~GEM_LB_MAC);
+		*(u32 *)(mac->registers + GEM_NET_CONTROL) |= (GEM_LB_PHY);
+		break;
+	default:
+		*(u32 *)(mac->registers + GEM_NET_CONTROL) &= (~(GEM_LB_MAC | GEM_LB_PHY));
+	}
+}
+/******************************************************************************/
+
+
+/******************************************************************************/
+/*
+ * Get the loopback mode of the MAC.  This can be either no loopback for normal
+ * operation, local loopback through MAC internal loopback module or PHY
+ * loopback for external loopback through a PHY.  This asserts the external loop
+ * pin.
+ * The function parameters are a pointer to the device.
+ *
+ * Return value:
+ *  LB_LOCAL    :   Local loop back active.
+ *  LB_EXT      :   External loop back active.
+ *  LB_NONE     :   Loop back disabled.
+ *  -1          :   Unknown mode.
+ */
+/******************************************************************************/
+MAC_LOOP gem_get_loop(GEM_DEVICE  *mac)
+{
+	UINT_32 lb_mode;
+
+	lb_mode = readl(mac->registers + GEM_NET_CONTROL) & \
+			(GEM_LB_PHY | GEM_LB_MAC);
+	switch (lb_mode) {
+	case GEM_LB_MAC:
+		return LB_LOCAL;
+		break;
+	case GEM_LB_PHY:
+		return LB_EXT;
+		break;
+	case 0:
+		return LB_NONE;
+		break;
+	default:
+		return -1;
+	}
+}
+/******************************************************************************/
+
+
+/******************************************************************************/
+/*
+ * Activate the Management interface.  This is required to program the PHY
+ * registers through the MDIO port.
+ *
+ * There is no return value for this function.
+ */
+/******************************************************************************/
+void gem_enable_MDIO(GEM_DEVICE *mac)
+{
+	*(u32 *)(mac->registers + GEM_NET_CONTROL) |= GEM_MDIO_EN;
+}
+/******************************************************************************/
+
+
+/******************************************************************************/
+/*
+ * Disable the Management interface.  In this state, the MDIO is placed in a
+ * high impedance state and the MDC clock is driven low.
+ *
+ * There is no return value for this function.
+ */
+/******************************************************************************/
+void gem_disable_MDIO(GEM_DEVICE *mac)
+{
+	*(u32 *)(mac->registers + GEM_NET_CONTROL) &= (~GEM_MDIO_EN);
+}
+/******************************************************************************/
+
+
+/******************************************************************************/
+/*
+ * Enable writing to the statistic registers.  This is for debug purposes only
+ * and should not be active during normal operation.
+ *
+ * There is no return value for this function.
+ */
+/******************************************************************************/
+void gem_stats_wr_en(GEM_DEVICE *mac)
+{
+	*(u32 *)(mac->registers + GEM_NET_CONTROL) |= GEM_STATS_WR_EN;
+}
+/******************************************************************************/
+
+
+/******************************************************************************/
+/*
+ * Disable writing to the statistic registers.  Under normal operation this is
+ * not necessary as the writing to statistics registers should be off by default
+ *
+ * There is no return value for this function.
+ */
+/******************************************************************************/
+void gem_stats_wr_off(GEM_DEVICE *mac)
+{
+	*(u32 *)(mac->registers + GEM_NET_CONTROL) &= (~GEM_STATS_WR_EN);
+}
+/******************************************************************************/
+
+
+/******************************************************************************/
+/*
+ * Increment all the statistic registers by 1.  This is for debug purposes only.
+ * Note that the statistic registers are automatically cleared on read!
+ *
+ * No return value.
+ */
+/******************************************************************************/
+void gem_stats_inc(GEM_DEVICE *mac)
+{
+	*(u32 *)(mac->registers + GEM_NET_CONTROL) |= GEM_STATS_INC;
+}
+/******************************************************************************/
+
+
+/******************************************************************************/
+/*
+ * Clear all the statistic registers.
+ *
+ * No return value.
+ */
+/******************************************************************************/
+void gem_stats_clr(GEM_DEVICE *mac)
+{
+	*(u32 *)(mac->registers + GEM_NET_CONTROL) |= GEM_STATS_CLR;
+}
+/******************************************************************************/
+
+
+/******************************************************************************/
+/*
+ * Enable pause frame reception.  With this enabled, if a valid pause frame is
+ * received, transmission will halt for the specified time after the current
+ * frame has completed transmission.
+ *
+ * There is no return value for this function.
+ */
+/******************************************************************************/
+void gem_enable_pause_rx(GEM_DEVICE *mac)
+{
+	*(u32 *)(mac->registers + GEM_NET_CONFIG) |= GEM_RX_PAUSE_EN;
+}
+/******************************************************************************/
+
+
+/******************************************************************************/
+/*
+ * Disable pause frame reception.  Incoming pause frames are ignored.
+ *
+ * There is no return value for this function.
+ */
+/******************************************************************************/
+void gem_disable_pause_rx(GEM_DEVICE *mac)
+{
+	*(u32 *)(mac->registers + GEM_NET_CONFIG) &= (~GEM_RX_PAUSE_EN);
+}
+/******************************************************************************/
+
+
+/******************************************************************************/
+/*
+ * Enable Checksum Engine.
+ * With this enabled, Frame with bad IP, TCP or UDP checksums are discarded
+ * There is no return value for this function.
+ */
+/******************************************************************************/
+void gem_enable_checksum_offload(GEM_DEVICE *mac)
+{
+	*(u32 *)(mac->registers + GEM_NET_CONFIG) |= GEM_CKSUM_OFFLOAD;
+}
+
+/******************************************************************************/
+/*
+ * Disable Checksum Engine.
+ *
+ * There is no return value for this function.
+ */
+/******************************************************************************/
+void gem_disable_checksum_offload(GEM_DEVICE *mac)
+{
+	*(u32 *)(mac->registers + GEM_NET_CONFIG) &= (~GEM_CKSUM_OFFLOAD);
+}
+
+/******************************************************************************/
+/*
+ * Enable copy of received pause frame.
+ *
+ * There is no return value for this function.
+ */
+/******************************************************************************/
+void gem_enable_pause_cpy(GEM_DEVICE *mac)
+{
+	*(u32 *)(mac->registers + GEM_NET_CONFIG) &= (~GEM_RX_NO_PAUSE);
+}
+/******************************************************************************/
+
+
+/******************************************************************************/
+/*
+ * Disable copy of received pause frame.
+ *
+ * There is no return value for this function.
+ */
+/******************************************************************************/
+void gem_disable_pause_cpy(GEM_DEVICE *mac)
+{
+	*(u32 *)(mac->registers + GEM_NET_CONTROL) |= GEM_RX_NO_PAUSE;
+}
+/******************************************************************************/
+
+
+/******************************************************************************/
+/*
+ * Send a pause frame with zero quantum.
+ *
+ * There is no return value for this function.
+ */
+/******************************************************************************/
+void gem_send_0q_pause(GEM_DEVICE *mac)
+{
+	*(u32 *)(mac->registers + GEM_NET_CONTROL) |= GEM_TX_0Q_PAUSE;
+}
+/******************************************************************************/
+
+
+/******************************************************************************/
+/*
+ * Send a normal pause frame.
+ *
+ * There is no return value for this function.
+ */
+/******************************************************************************/
+void gem_send_pause(GEM_DEVICE *mac)
+{
+	*(u32 *)(mac->registers + GEM_NET_CONTROL) |= GEM_TX_PAUSE;
+}
+/******************************************************************************/
+
+
+/******************************************************************************/
+/*
+ * Set transmit pause quantum.
+ *
+ * There is no return value for this function.
+ */
+/******************************************************************************/
+void gem_set_tx_pause_q(GEM_DEVICE *mac, UINT_32 gem_pause)
+{
+	*(u32 *)(mac->registers + GEM_TX_PAUSE_QUANT) = gem_pause;
+}
+/******************************************************************************/
+
+
+/******************************************************************************/
+/*
+ * Read transmit pause quantum.
+ *
+ * Return values:
+ * 0-65535: transmit pause quantum.
+ */
+/******************************************************************************/
+UINT_32 gem_get_tx_pause_q(GEM_DEVICE *mac)
+{
+	return readl(mac->registers + GEM_TX_PAUSE_QUANT);
+}
+/******************************************************************************/
+
+
+/******************************************************************************/
+/*
+ * Set retry test bit, this is used for debug purposes only to speed up testing.
+ * This should not be enabled for normal operation.
+ *
+ * There is no return value for this function.
+ */
+/******************************************************************************/
+void gem_en_retry_test(GEM_DEVICE *mac)
+{
+	*(u32 *)(mac->registers + GEM_NET_CONFIG) |= GEM_RETRY_TEST;
+}
+/******************************************************************************/
+
+
+/******************************************************************************/
+/*
+ * Disable retry test bit.  For normal operation this bit should not be set.
+ *
+ * There is no return value for this function.
+ */
+/******************************************************************************/
+void gem_dis_retry_test(GEM_DEVICE *mac)
+{
+	*(u32 *)(mac->registers + GEM_NET_CONFIG) &= (~GEM_RETRY_TEST);
+}
+/******************************************************************************/
+
+
+/******************************************************************************/
+/*
+ * Enable external address match via the eam pin, which when active will copy
+ * the current frame to memory.
+ *
+ * There is no return value for this function.
+ */
+/******************************************************************************/
+void gem_enable_eam(GEM_DEVICE *mac)
+{
+	*(u32 *)(mac->registers + GEM_NET_CONFIG) |= GEM_EAM_EN;
+}
+/******************************************************************************/
+
+
+/******************************************************************************/
+/*
+ * Disable external address match capability.  The MAC will ignore the status of
+ * the eam pin.
+ *
+ * There is no return value for this function.
+ */
+/******************************************************************************/
+void gem_disable_eam(GEM_DEVICE *mac)
+{
+	*(u32 *)(mac->registers + GEM_NET_CONFIG) &= (~GEM_EAM_EN);
+}
+/******************************************************************************/
+
+
+/******************************************************************************/
+/*
+ * Enable storing of the receive frame check sequence into memory.
+ *
+ * There is no return value for this function.
+ */
+/******************************************************************************/
+void gem_enable_fcs_rx(GEM_DEVICE *mac)
+{
+	*(u32 *)(mac->registers + GEM_NET_CONFIG) &= (~GEM_RX_NO_FCS);
+}
+/******************************************************************************/
+
+
+/******************************************************************************/
+/*
+ * Disable storing of the receive frame check sequence into memory.  The last 4
+ * bytes from the incoming frame will be checked for valid CRC, however this
+ * will not be stored into memory.  The frame length will be updated
+ * accordingly.
+ *
+ * There is no return value for this function.
+ */
+/******************************************************************************/
+void gem_disable_fcs_rx(GEM_DEVICE *mac)
+{
+	*(u32 *)(mac->registers + GEM_NET_CONFIG) |= GEM_RX_NO_FCS;
+}
+/******************************************************************************/
+
+
+/******************************************************************************/
+/*
+ * Enable reception of long frames up to 1536 bytes in length.
+ * These are not standard IEEE 802.3 frames.
+ *
+ * There is no return value for this function.
+ */
+/******************************************************************************/
+void gem_enable_1536_rx(GEM_DEVICE *mac)
+{
+	*(u32 *)(mac->registers + GEM_NET_CONFIG) |= GEM_FRAME_1536;
+}
+/******************************************************************************/
+
+
+/******************************************************************************/
+/*
+ * Disable reception of frames greater than 1518 bytes in length.
+ * This is normal operation mode for the MAC for compatibility with IEEE 802.3
+ *
+ * There is no return value for this function.
+ */
+/******************************************************************************/
+void gem_disable_1536_rx(GEM_DEVICE *mac)
+{
+	*(u32 *)(mac->registers + GEM_NET_CONFIG) &= (~GEM_FRAME_1536);
+}
+/******************************************************************************/
+
+
+/******************************************************************************/
+/*
+ * Enable reception of unicast hashed frames.  The frame will be received when
+ * the 6 bit hash function of the frame's destination address points a bit that
+ * is set in the 64-bit hash register and is signalled as a unicast frame.
+ *
+ * There is no return value for this function.
+ */
+/******************************************************************************/
+void gem_enable_unicast(GEM_DEVICE *mac)
+{
+	*(u32 *)(mac->registers + GEM_NET_CONFIG) |= GEM_UNICAST_EN;
+}
+/******************************************************************************/
+
+
+/******************************************************************************/
+/*
+ * Disable reception of unicast hashed frames.
+ *
+ * There is no return value for this function.
+ */
+/******************************************************************************/
+void gem_disable_unicast(GEM_DEVICE *mac)
+{
+	*(u32 *)(mac->registers + GEM_NET_CONFIG) &= (~GEM_UNICAST_EN);
+}
+/******************************************************************************/
+
+
+/******************************************************************************/
+/*
+ * Enable reception of multicast hashed frames.  The frame will be received when
+ * the 6 bit hash function of the frame's destination address points a bit that
+ * is set in the 64-bit hash register and is signalled as a multicast frame.
+ *
+ * There is no return value for this function.
+ */
+/******************************************************************************/
+void gem_enable_multicast(GEM_DEVICE *mac)
+{
+	*(u32 *)(mac->registers + GEM_NET_CONFIG) |= GEM_MULTICAST_EN;
+}
+/******************************************************************************/
+
+
+/******************************************************************************/
+/*
+ * Disable reception of multicast hashed frames.
+ *
+ * There is no return value for this function.
+ */
+/******************************************************************************/
+void gem_disable_multicast(GEM_DEVICE *mac)
+{
+	*(u32 *)(mac->registers + GEM_NET_CONFIG) &= (~GEM_MULTICAST_EN);
+}
+/******************************************************************************/
+
+
+/******************************************************************************/
+/*
+ * Allow reception of broadcast frames (frames with address set to all 1's)
+ * This is normal operating mode for the MAC.
+ *
+ * There is no return value for this function.
+ */
+/******************************************************************************/
+void gem_allow_broadcast(GEM_DEVICE *mac)
+{
+	*(u32 *)(mac->registers + GEM_NET_CONFIG) &= (~GEM_NO_BROADCAST);
+}
+/******************************************************************************/
+
+
+/******************************************************************************/
+/*
+ * Do not allow reception of broadcast frames, such frames will be ignored.
+ *
+ * There is no return value for this function.
+ */
+/******************************************************************************/
+void gem_no_broadcast(GEM_DEVICE *mac)
+{
+	*(u32 *)(mac->registers + GEM_NET_CONFIG) |= GEM_NO_BROADCAST;
+}
+/******************************************************************************/
+
+
+/******************************************************************************/
+/*
+ * Enable copy all frames.  In this mode, the MAC will copy all valid received
+ * frames to memory regardless of the destination address.
+ *
+ * There is no return value for this function.
+ */
+/******************************************************************************/
+void gem_enable_copy_all(GEM_DEVICE *mac)
+{
+	*(u32 *)(mac->registers + GEM_NET_CONFIG) |= GEM_COPY_ALL;
+}
+/******************************************************************************/
+
+
+/******************************************************************************/
+/*
+ * Do not copy all frames.  Normal operating mode for the MAC, frames will only
+ * be copied to memory if it matches one of the specific or hash addresses.
+ *
+ * There is no return value for this function.
+ */
+/******************************************************************************/
+void gem_disable_copy_all(GEM_DEVICE *mac)
+{
+	*(u32 *)(mac->registers + GEM_NET_CONFIG) &= (~GEM_COPY_ALL);
+}
+/******************************************************************************/
+
+
+/******************************************************************************/
+/*
+ * Set MAC into full duplex mode.  The crs and col signals will be ignored in
+ * this mode.
+ *
+ * There is no return value for this function.
+ */
+/******************************************************************************/
+void gem_full_duplex(GEM_DEVICE *mac)
+{
+	*(u32 *)(mac->registers) |= GEM_CONF_DUPLEX_GEM_FULL;
+}
+/******************************************************************************/
+
+
+/******************************************************************************/
+/*
+ * Set MAC into half duplex mode.  The crs and col signals are used to detect
+ * collisions and perform deference where necessary.
+ *
+ * There is no return value for this function.
+ */
+/******************************************************************************/
+void gem_half_duplex(GEM_DEVICE *mac)
+{
+	*(u32 *)(mac->registers) &= ~GEM_CONF_DUPLEX_GEM_FULL;
+}
+/******************************************************************************/
+
+
+/******************************************************************************/
+/*
+ * Set the operating speed of the MAC, for 10 and 100Mb modes, this has no
+ * effect on the MAC functionality, but simply asserts an external speed pin
+ * accordingly.
+ * For 1G modes, this will set the MAC into the appropriate operating mode by
+ * switching to either the GMII or TBI interface depending on required mode.
+ *
+ * There is no return value for this function.
+ */
+/******************************************************************************/
+void gem_set_speed(GEM_DEVICE *mac, MAC_SPEED gem_speed)
+{
+	switch (gem_speed) {
+	case SPEED_10M:
+		writel((readl(mac->gemac_baseaddr + GEM_CFG) & \
+				~GEM_CONF_SPEED_MASK) | \
+				GEM_CONF_SPEED_SEL_GEM | \
+				GEM_CONF_SPEED_GEM_10M,
+				mac->gemac_baseaddr + GEM_CFG);
+		writel(readl(mac->registers + GEM_NET_CONFIG) & (~GEM_PCS_SEL),
+				mac->registers + GEM_NET_CONFIG);
+		break;
+	case SPEED_100M:
+		writel((readl(mac->gemac_baseaddr + GEM_CFG) & \
+			 ~GEM_CONF_SPEED_MASK) | \
+			GEM_CONF_SPEED_SEL_GEM | \
+			GEM_CONF_SPEED_GEM_100M,
+			mac->gemac_baseaddr + GEM_CFG);
+		writel(readl(mac->registers + GEM_NET_CONFIG) & ~GEM_PCS_SEL,
+				mac->registers + GEM_NET_CONFIG);
+		break;
+	case SPEED_1000M:
+		writel((readl(mac->gemac_baseaddr + GEM_CFG) & \
+			 ~GEM_CONF_SPEED_MASK) | \
+			GEM_CONF_SPEED_SEL_GEM | \
+			GEM_CONF_SPEED_GEM_1G,
+			mac->gemac_baseaddr + GEM_CFG);
+		writel(readl(mac->registers + GEM_NET_CONFIG) & ~GEM_PCS_SEL,
+				mac->registers + GEM_NET_CONFIG);
+		break;
+	case SPEED_1000M_PCS:
+		writel((readl(mac->gemac_baseaddr + GEM_CFG) & \
+			 ~GEM_CONF_SPEED_MASK) | \
+			GEM_CONF_SPEED_SEL_GEM | \
+			GEM_CONF_SPEED_GEM_1G,
+			mac->gemac_baseaddr + GEM_CFG);
+		writel(readl(mac->registers + GEM_NET_CONFIG) | GEM_PCS_SEL,
+				mac->registers + GEM_NET_CONFIG);
+		break;
+	default:
+		writel((readl(mac->gemac_baseaddr + GEM_CFG) & \
+			 ~GEM_CONF_SPEED_MASK) | \
+			GEM_CONF_SPEED_SEL_GEM | \
+			GEM_CONF_SPEED_GEM_100M,
+			mac->gemac_baseaddr + GEM_CFG);
+		writel(readl(mac->registers + GEM_NET_CONFIG) & ~GEM_PCS_SEL,
+				mac->registers + GEM_NET_CONFIG);
+	}
+}
+/******************************************************************************/
+
+
+/******************************************************************************/
+/*
+ * Get the operating speed of the MAC, currently this has no functional effect
+ * on the MAC.
+ *
+ * This function returns an enumerated value cast into an int.  This is for
+ * backward compatibility with the macb driver.
+ *
+ * Return value:
+ *  SPEED_10M   :   MAC in 10Mb/s mode.
+ *  SPEED_100M  :   MAC in 100Mb/s mode.
+ *  SPEED_1000M :   MAC in 1G mode with GMII interface.
+ *  SPEED_1000M_PCS :   MAC in 1G mode with PCS interface.
+ */
+/******************************************************************************/
+MAC_SPEED gem_get_speed(GEM_DEVICE *mac)
+{
+
+	if (readl(mac->gemac_baseaddr + GEM_CFG) & GEM_CONF_SPEED_SEL_GEM) {
+		if (readl(mac->gemac_baseaddr + GEM_CFG) & GEM_CONF_SPEED_GEM_1G) {
+			if (readl(mac->registers + GEM_NET_CONFIG) & GEM_PCS_SEL)
+				return SPEED_1000M_PCS;
+			else
+				return SPEED_1000M;
+		} else {
+			if (readl(mac->gemac_baseaddr + GEM_CFG) & GEM_CONF_SPEED_GEM_100M)
+				return SPEED_100M;
+			else
+				return SPEED_10M;
+		}
+	} else {
+		if (readl(mac->gemac_baseaddr + GEM_CFG) & GEM_CONF_SPEED_PHY_1G) {
+			if (readl(mac->registers + GEM_NET_CONFIG) & GEM_PCS_SEL)
+				return SPEED_1000M_PCS;
+			else
+				return SPEED_1000M;
+		} else {
+			if (readl(mac->gemac_baseaddr + GEM_CFG) & GEM_CONF_SPEED_PHY_100M)
+				return SPEED_100M;
+			else
+				return SPEED_10M;
+		}
+	}
+}
+/******************************************************************************/
+
+
+/******************************************************************************/
+/*
+ * Set AMBA AHB bus width.
+ * AMBA_AHB_32:
+ * AMBA_AHB_64:
+ * AMBA_AHB_128:
+ * There is no return value for this function.
+ */
+/******************************************************************************/
+void gem_set_ahb_width(GEM_DEVICE *mac, MAC_AHB_WIDTH gem_buswidth)
+{
+	switch(gem_buswidth) {
+	case AMBA_AHB_128:
+		writel(readl(mac->registers + GEM_NET_CONFIG) | GEM_AHB_WIDTH1,
+				mac->registers + GEM_NET_CONFIG);
+		break;
+	case AMBA_AHB_64:
+		writel(readl(mac->registers + GEM_NET_CONFIG) & \
+				~GEM_AHB_WIDTH1,
+				mac->registers + GEM_NET_CONFIG);
+		writel(readl(mac->registers + GEM_NET_CONFIG) | GEM_AHB_WIDTH0,
+				mac->registers + GEM_NET_CONFIG);
+		break;
+	case AMBA_AHB_32:
+	default:
+		writel(readl(mac->registers + GEM_NET_CONFIG) &	\
+				((~GEM_AHB_WIDTH1) & (~GEM_AHB_WIDTH0)),
+				mac->registers + GEM_NET_CONFIG);
+	}
+}
+/******************************************************************************/
+
+
+/******************************************************************************/
+/*
+ * Get AMBA AHB bus width.
+ * It returns one of the following values:
+ * AMBA_AHB_32, AMBA_AHB_64, AMBA_AHB_128,
+ */
+/******************************************************************************/
+MAC_AHB_WIDTH gem_get_ahb_width(GEM_DEVICE *mac)
+{
+	if (readl(mac->registers + GEM_NET_CONFIG) & GEM_AHB_WIDTH1)
+		return AMBA_AHB_128;
+	else
+		if (readl(mac->registers + GEM_NET_CONFIG) & GEM_AHB_WIDTH0)
+			return AMBA_AHB_64;
+		else
+			return AMBA_AHB_32;
+}
+/******************************************************************************/
+
+
+/******************************************************************************/
+/*
+ * Set MDC clock division.
+ * MDC_DIV_8:
+ * MDC_DIV_16:
+ * MDC_DIV_32:
+ * MDC_DIV_48:
+ * MDC_DIV_64:
+ * MDC_DIV_96:
+ * MDC_DIV_128:
+ * MDC_DIV_224:
+ * There is no return value for this function.
+ */
+/******************************************************************************/
+void gem_set_mdc_div(GEM_DEVICE *mac, MAC_MDC_DIV gem_mdcdiv)
+{
+	switch(gem_mdcdiv) {
+	case MDC_DIV_8:
+		writel(readl(mac->registers + GEM_NET_CONFIG) & \
+			((~GEM_MDC_DIV2) & (~GEM_MDC_DIV1) & (~GEM_MDC_DIV0)),
+			mac->registers + GEM_NET_CONFIG);
+		break;
+	case MDC_DIV_16:
+		writel(readl(mac->registers + GEM_NET_CONFIG) & \
+				((~GEM_MDC_DIV2) & (~GEM_MDC_DIV1)),
+				mac->registers + GEM_NET_CONFIG);
+		writel(readl(mac->registers + GEM_NET_CONFIG) | GEM_MDC_DIV0,
+				mac->registers + GEM_NET_CONFIG);
+		break;
+	case MDC_DIV_32:
+		writel(readl(mac->registers + GEM_NET_CONFIG) & ((~GEM_MDC_DIV2) & (~GEM_MDC_DIV0)),
+				mac->registers + GEM_NET_CONFIG);
+		writel(readl(mac->registers + GEM_NET_CONFIG) | GEM_MDC_DIV1,
+				mac->registers + GEM_NET_CONFIG);
+		break;
+	case MDC_DIV_48:
+		writel(readl(mac->registers + GEM_NET_CONFIG) | (GEM_MDC_DIV1 | GEM_MDC_DIV0),
+				mac->registers + GEM_NET_CONFIG);
+		writel(readl(mac->registers + GEM_NET_CONFIG) & (~GEM_MDC_DIV2),
+				mac->registers + GEM_NET_CONFIG);
+		break;
+	case MDC_DIV_64:
+		writel(readl(mac->registers + GEM_NET_CONFIG) & ((~GEM_MDC_DIV1) & (~GEM_MDC_DIV0)),
+				mac->registers + GEM_NET_CONFIG);
+		writel(readl(mac->registers + GEM_NET_CONFIG) | GEM_MDC_DIV2,
+				mac->registers + GEM_NET_CONFIG);
+		break;
+	case MDC_DIV_96:
+		writel(readl(mac->registers + GEM_NET_CONFIG) | (GEM_MDC_DIV2 | GEM_MDC_DIV0),
+				mac->registers + GEM_NET_CONFIG);
+		writel(readl(mac->registers + GEM_NET_CONFIG) & (~GEM_MDC_DIV1),
+				mac->registers + GEM_NET_CONFIG);
+		break;
+	case MDC_DIV_128:
+		writel(readl(mac->registers + GEM_NET_CONFIG) | (GEM_MDC_DIV2 | GEM_MDC_DIV1),
+				mac->registers + GEM_NET_CONFIG);
+		writel(readl(mac->registers + GEM_NET_CONFIG) & ~GEM_MDC_DIV0,
+					mac->registers + GEM_NET_CONFIG);
+		break;
+	case MDC_DIV_224:
+		writel(readl(mac->registers + GEM_NET_CONFIG) |
+			(GEM_MDC_DIV2 | GEM_MDC_DIV1 | GEM_MDC_DIV0),
+			mac->registers + GEM_NET_CONFIG);
+		break;
+	}
+}
+/******************************************************************************/
+
+
+/******************************************************************************/
+/*
+ * Get MDC clock division.
+ * It returns one of this values:
+ * MDC_DIV_8, MDC_DIV_16, MDC_DIV_32, MDC_DIV_48, MDC_DIV_64, MDC_DIV_96,
+ * MDC_DIV_128, MDC_DIV_224.
+ */
+/******************************************************************************/
+MAC_MDC_DIV gem_get_mdc_div(GEM_DEVICE *mac)
+{
+	if (readl(mac->registers + GEM_NET_CONFIG) & GEM_MDC_DIV2)
+		if (readl(mac->registers + GEM_NET_CONFIG) & GEM_MDC_DIV1)
+			if (readl(mac->registers + GEM_NET_CONFIG) & GEM_MDC_DIV0)
+				return MDC_DIV_224;
+			else
+				return MDC_DIV_128;
+		else
+			if (readl(mac->registers + GEM_NET_CONFIG) & GEM_MDC_DIV0)
+				return MDC_DIV_96;
+			else
+				return MDC_DIV_64;
+	else
+		if (readl(mac->registers + GEM_NET_CONFIG) & GEM_MDC_DIV1)
+			if (readl(mac->registers + GEM_NET_CONFIG) & GEM_MDC_DIV0)
+				return MDC_DIV_48;
+			else
+				return MDC_DIV_32;
+		else
+			if (readl(mac->registers + GEM_NET_CONFIG) & GEM_MDC_DIV0)
+				return MDC_DIV_16;
+			else
+				return MDC_DIV_8;
+}
+/******************************************************************************/
+
+
+/******************************************************************************/
+/*
+ * Enable to read snapshot values of statistic registers.
+ *
+ * There is no return value for this function.
+ */
+/******************************************************************************/
+void gem_enable_rd_snap(GEM_DEVICE *mac)
+{
+	writel(readl(mac->registers + GEM_NET_CONTROL) | GEM_READ_SNAP,
+			mac->registers + GEM_NET_CONTROL);
+}
+
+
+/******************************************************************************/
+/*
+ * Disable to read snapshot values of statistic registers.
+ *
+ * There is no return value for this function.
+ */
+/******************************************************************************/
+void gem_disable_rd_snap(GEM_DEVICE *mac)
+{
+	writel(readl(mac->registers + GEM_NET_CONTROL) & (~GEM_READ_SNAP),
+			mac->registers + GEM_NET_CONTROL);
+}
+
+
+/******************************************************************************/
+/*
+ * Take snapshot of statistic registers. Writing a one will record the current
+ * value of all statistics registers in the snapshot registers and clear the
+ * statistics registers.
+ *
+ * There is no return value for this function.
+ */
+/******************************************************************************/
+void gem_take_snap(GEM_DEVICE *mac)
+{
+	writel(readl(mac->registers + GEM_NET_CONTROL) | GEM_TAKE_SNAP,
+			mac->registers + GEM_NET_CONTROL);
+}
+
+
+/******************************************************************************/
+/*
+ * Get the current link status as returned by the PHY
+ *
+ * Return value:
+ *  0   :   Link is down.
+ *  1   :   Link active.
+ */
+/******************************************************************************/
+int gem_link_status(GEM_DEVICE *mac)
+{
+	return (readl(mac->registers + GEM_NET_STATUS) & GEM_LINK_STATUS) == \
+								GEM_LINK_STATUS;
+}
+/******************************************************************************/
+
+
+
+/******************************************************************************/
+/*
+ * Get the value of the transmit status register.
+ * The return value is an unsigned 32-bit integer containing the contents of the
+ * register.  This should be masked appropriately to obtain the relevant status.
+ *
+ * Return value:
+ * Returns current value of transmit status register.
+ */
+/******************************************************************************/
+UINT_32 gem_get_tx_stat(GEM_DEVICE *mac)
+{
+	return readl(mac->registers + GEM_TX_STATUS);
+}
+
+/*
+ * Reset the specified bits of the transmit status register.
+ *
+ * mac :	Pointer to device structure.
+ * rst_status : Status to reset.
+ * There is no return value.
+ */
+void gem_reset_tx_stat(GEM_DEVICE  *mac, UINT_32 rst_status)
+{
+	writel(readl(mac->registers + GEM_TX_STATUS) | rst_status,
+			mac->registers + GEM_TX_STATUS);
+}
+
+
+/*
+ * Get the value of the receive status register.
+ * The return value is an unsigned 32-bit integer containing the contents of the
+ * register.  This should be masked appropriately to obtain the relevant status.
+ *
+ * Returns current receive status.
+ */
+UINT_32 gem_get_rx_stat(GEM_DEVICE *mac)
+{
+	return readl(mac->registers + GEM_RX_STATUS);
+}
+
+/*
+ * Reset the specified bits of the receive status register.
+ *
+ * There is no return value.
+ */
+void gem_reset_rx_stat(GEM_DEVICE  *mac, UINT_32 rst_status)
+{
+	*(u32 *)(mac->registers + GEM_RX_STATUS) |= rst_status;
+}
+
+/*
+ * Enable jumbo frames to be accepted.
+ *
+ * There is no return value.
+ */
+void gem_enable_rx_jmb(GEM_DEVICE  *mac)
+{
+	*(u32 *)(mac->registers + GEM_NET_CONFIG) |= GEM_RX_JUMBO;
+}
+
+/*
+ * Disable jumbo frames to be accepted.
+ *
+ * There is no return value.
+ */
+void gem_disable_rx_jmb(GEM_DEVICE  *mac)
+{
+	*(u32 *)(mac->registers + GEM_NET_CONFIG) &= (~GEM_RX_JUMBO);
+}
+
+/*
+ * Enable only VLAN frames to be accepted, all other frames will be discarded.
+ *
+ * There is no return value.
+ */
+void gem_enable_vlan_only(GEM_DEVICE  *mac)
+{
+	*(u32 *)(mac->registers + GEM_NET_CONFIG) |= GEM_VLAN_ONLY;
+}
+
+
+/*
+ * Disable VLAN frame only mode. All frames will be accepted.
+ *
+ * There is no return value.
+ */
+void gem_disable_vlan_only(GEM_DEVICE  *mac)
+{
+	*(u32 *)(mac->registers + GEM_NET_CONFIG) &= (~GEM_VLAN_ONLY);
+}
+
+
+
+/******************************************************************************/
+/*
+ * Read the interrupt status register.
+ * This returns an unsigned 32-bit integer with the current interrupt status,
+ * this should be masked appropriately to get the required status.
+ * Note that the interrupt status register is automatically reset on read, so
+ * the returned value should be stored if further processing required.
+ *
+ * Returns the current interrupt status.
+ */
+/******************************************************************************/
+UINT_32 gem_get_irq_stat(GEM_DEVICE *mac)
+{
+	return *(u32 *)(mac->registers + GEM_IRQ_STATUS);
+}
+/******************************************************************************/
+
+
+/******************************************************************************/
+/*
+ * Set specified bits in the interrupt status register.
+ * This can be used for debug purposes to manually activate an interrupt.
+ *
+ * There is no return value.
+ */
+/******************************************************************************/
+void gem_set_irq_stat(GEM_DEVICE *mac, UINT_32 irq_status)
+{
+	*(u32 *)(mac->registers + GEM_IRQ_STATUS) |= irq_status;
+}
+/******************************************************************************/
+
+
+/******************************************************************************/
+/*
+ * Enable specified interrupts.
+ * The specified interrupt bits are enabled by unmasking them.
+ * Note that this appends to the existing interrupt enable list.
+ *
+ * There is no return value.
+ */
+/******************************************************************************/
+void gem_enable_irq(GEM_DEVICE *mac, UINT_32 irq_en)
+{
+	writel(readl(mac->registers + GEM_IRQ_ENABLE) | irq_en,
+			mac->registers + GEM_IRQ_ENABLE);
+}
+/******************************************************************************/
+
+
+/******************************************************************************/
+/*
+ * Disable specified interrupts.
+ * The specified interrupts are masked out so that they do not generate an
+ * interrupt.
+ * Note that this appends to the existing interrupt mask list.
+ *
+ * There is no return value.
+ */
+/******************************************************************************/
+void gem_mask_irq(GEM_DEVICE *mac, UINT_32 irq_mask)
+{
+	writel(readl(mac->registers + GEM_IRQ_DISABLE) | irq_mask,
+			mac->registers + GEM_IRQ_DISABLE);
+}
+/******************************************************************************/
+
+
+/******************************************************************************/
+/*
+ * Obtain the current interrupt mask value.
+ * The return value indicates which interrupts are currently masked out i.e. do
+ * not generate an interrupt.
+ *
+ * Returns the interrupt mask status.
+ */
+/******************************************************************************/
+UINT_32 gem_get_irq_mask(GEM_DEVICE *mac)
+{
+	return readl(mac->registers + GEM_IRQ_MASK);
+}
+/******************************************************************************/
+
+
+/******************************************************************************/
+/*
+ * Read the pause time register.
+ *
+ * Returns the current value in the pause time register which will
+ * decrement when the MAC has gone into pause mode.
+ */
+/******************************************************************************/
+UINT_32 gem_pause_time(GEM_DEVICE *mac)
+{
+	return readl(mac->registers + GEM_RX_PAUSE_TIME);
+}
+/******************************************************************************/
+
+
+/******************************************************************************/
+/*
+ * Set the id-check registers of the MAC.
+ * These registers are used to check the type-id field of the incoming frames,
+ * if matched, the appropriate status bit will be set in word 1 of the receive
+ * descriptor for that frame.
+ * The input parameter is truncated to 16-bits.
+ *
+ * There is no return value.
+ */
+/******************************************************************************/
+void gem_set_id_check1(GEM_DEVICE  *mac, UINT_32 id_check)
+{
+	writel((id_check & 0xFFFF) | 0x80000000,
+			mac->registers + GEM_ID_CHECK1);
+}
+void gem_set_id_check2(GEM_DEVICE *mac, UINT_32 id_check)
+{
+	writel((id_check & 0xFFFF) | 0x80000000,
+			mac->registers + GEM_ID_CHECK2);
+}
+void gem_set_id_check3(GEM_DEVICE *mac, UINT_32 id_check)
+{
+	writel((id_check & 0xFFFF) | 0x80000000,
+			mac->registers + GEM_ID_CHECK3);
+}
+void gem_set_id_check4(GEM_DEVICE  *mac, UINT_32 id_check)
+{
+	writel((id_check & 0xFFFF) | 0x80000000,
+			mac->registers + GEM_ID_CHECK4);
+}
+/******************************************************************************/
+
+
+/******************************************************************************/
+/*
+ * Get the value of the id-check registers in the MAC.
+ *
+ * Return value:
+ *  Value of ID check register.
+ */
+/******************************************************************************/
+UINT_32 gem_get_id_check1(GEM_DEVICE *mac)
+{
+	return readl(mac->registers + GEM_ID_CHECK1);
+}
+UINT_32 gem_get_id_check2(GEM_DEVICE *mac)
+{
+	return readl(mac->registers + GEM_ID_CHECK2);
+}
+UINT_32 gem_get_id_check3(GEM_DEVICE *mac)
+{
+	return readl(mac->registers + GEM_ID_CHECK3);
+}
+UINT_32 gem_get_id_check4(GEM_DEVICE *mac)
+{
+	return readl(mac->registers + GEM_ID_CHECK4);
+}
+/******************************************************************************/
+
+
+/******************************************************************************/
+/*
+ * Set the hash register of the MAC.
+ * This register is used for matching unicast and multicast frames.
+ * The parameter of this function should be a pointer to type MAC_ADDR as
+ * defined in the header file.
+ *
+ * There is no return value.
+ */
+/******************************************************************************/
+void gem_set_hash(GEM_DEVICE  *mac, MAC_ADDR *hash_addr)
+{
+	writel(hash_addr->bottom, mac->registers + GEM_HASH_BOT);
+	writel(hash_addr->top, mac->registers + GEM_HASH_TOP);
+}
+/******************************************************************************/
+
+
+/******************************************************************************/
+/*
+ * Get the current value of the hash registers of the MAC.
+ *
+ * This function returns a value of type MAC_ADDR
+ */
+/******************************************************************************/
+MAC_ADDR gem_get_hash(GEM_DEVICE *mac)
+{
+	MAC_ADDR addr;
+	addr.bottom = readl(mac->registers + GEM_HASH_BOT);
+	addr.top = readl(mac->registers + GEM_HASH_TOP);
+	return addr;
+}
+/******************************************************************************/
+
+
+/******************************************************************************/
+/*
+ * Setup all the specific address registers for the MAC.
+ * These registers are matched against incoming frames to determine whether the
+ * frame should be copied to memory.
+ * The input parameter to this function should be a pointer to type SPEC_ADDR
+ * as defined in the header file.
+ *
+ * There is no return value.
+ */
+/******************************************************************************/
+void gem_set_address(GEM_DEVICE *mac, SPEC_ADDR *spec_addr)
+{
+
+	*(u32 *)(mac->registers + GEM_LADDR1_BOT) = spec_addr->one.bottom;
+	*(u32 *)(mac->registers + GEM_LADDR1_TOP) = spec_addr->one.top;
+	*(u32 *)(mac->registers + GEM_LADDR2_BOT) = spec_addr->two.bottom;
+	*(u32 *)(mac->registers + GEM_LADDR2_TOP) = spec_addr->two.top;
+	*(u32 *)(mac->registers + GEM_LADDR3_BOT) = spec_addr->three.bottom;
+	*(u32 *)(mac->registers + GEM_LADDR3_TOP) = spec_addr->three.top;
+	*(u32 *)(mac->registers + GEM_LADDR4_BOT) = spec_addr->four.bottom;
+	*(u32 *)(mac->registers + GEM_LADDR4_TOP) = spec_addr->four.top;
+}
+/******************************************************************************/
+
+
+/******************************************************************************/
+/*
+ * Get the current set of specific match addresses for the MAC.
+ * Note that a pointer is not returned as this would give direct access to the
+ * MAC address space which may cause unpredictable behaviour if wrongly used.
+ *
+ * Return type is of type SPEC_ADDR as defined in the header file.
+ */
+/******************************************************************************/
+SPEC_ADDR gem_get_address(GEM_DEVICE *mac)
+{
+	SPEC_ADDR spec_addr;
+	spec_addr.one.bottom = readl(mac->registers + GEM_LADDR1_BOT) ;
+	spec_addr.one.top = readl(mac->registers + GEM_LADDR1_TOP) ;
+	spec_addr.two.bottom = readl(mac->registers + GEM_LADDR2_BOT) ;
+	spec_addr.two.top = readl(mac->registers + GEM_LADDR2_TOP) ;
+	spec_addr.three.bottom = readl(mac->registers + GEM_LADDR3_BOT) ;
+	spec_addr.three.top = readl(mac->registers + GEM_LADDR3_TOP) ;
+	spec_addr.four.bottom = readl(mac->registers + GEM_LADDR4_BOT) ;
+	spec_addr.four.top = readl(mac->registers + GEM_LADDR4_TOP) ;
+	return spec_addr;
+}
+/******************************************************************************/
+
+
+/******************************************************************************/
+/*
+ * Set specific local addresses of the MAC.
+ * Rather than setting up all four specific addresses, this function sets them
+ * up individually.  The input parameter should be a pointer to type MAC_ADDR.
+ *
+ * There are no return values.
+ */
+/******************************************************************************/
+void gem_set_laddr1(GEM_DEVICE *mac, MAC_ADDR *address)
+{
+	*(u32 *)(mac->registers + GEM_LADDR1_BOT) = address->bottom;
+	*(u32 *)(mac->registers + GEM_LADDR1_TOP) = address->top;
+}
+void gem_set_laddr2(GEM_DEVICE *mac, MAC_ADDR *address)
+{
+	*(u32 *)(mac->registers + GEM_LADDR2_BOT) = address->bottom;
+	*(u32 *)(mac->registers + GEM_LADDR2_TOP) = address->top;
+}
+void gem_set_laddr3(GEM_DEVICE *mac, MAC_ADDR *address)
+{
+	*(u32 *)(mac->registers + GEM_LADDR3_BOT) = address->bottom;
+	*(u32 *)(mac->registers + GEM_LADDR3_TOP) = address->top;
+}
+void gem_set_laddr4(GEM_DEVICE *mac, MAC_ADDR *address)
+{
+	*(u32 *)(mac->registers + GEM_LADDR4_BOT) = address->bottom;
+	*(u32 *)(mac->registers + GEM_LADDR4_TOP) = address->top;
+}
+/******************************************************************************/
+
+/******************************************************************************/
+/*
+ * Disable specific local addresses of the MAC.
+ */
+/******************************************************************************/
+void gem_clear_laddr1(GEM_DEVICE *mac)
+{
+	*(u32 *)(mac->registers + GEM_LADDR1_BOT) = 0;
+}
+void gem_clear_laddr2(GEM_DEVICE *mac)
+{
+	*(u32 *)(mac->registers + GEM_LADDR2_BOT)  = 0;
+}
+void gem_clear_laddr3(GEM_DEVICE *mac)
+{
+	*(u32 *)(mac->registers + GEM_LADDR3_BOT) = 0;
+}
+void gem_clear_laddr4(GEM_DEVICE *mac)
+{
+	*(u32 *)(mac->registers + GEM_LADDR4_BOT) = 0;
+}
+/******************************************************************************/
+
+/******************************************************************************/
+/*
+ * Get specific local addresses of the MAC.
+ * This allows returning of a single specific address stored in the MAC.
+ *
+ * Return value if of type MAC_ADDR as defined in the header file.
+ */
+/******************************************************************************/
+MAC_ADDR gem_get_laddr1(GEM_DEVICE *mac)
+{
+	MAC_ADDR addr;
+	addr.bottom = readl(mac->registers + GEM_LADDR1_BOT) ;
+	addr.top = readl(mac->registers + GEM_LADDR1_TOP) ;
+	return addr;
+}
+MAC_ADDR gem_get_laddr2(GEM_DEVICE *mac)
+{
+	MAC_ADDR addr;
+	addr.bottom = readl(mac->registers + GEM_LADDR2_BOT) ;
+	addr.top = readl(mac->registers + GEM_LADDR2_TOP) ;
+	return addr;
+}
+MAC_ADDR gem_get_laddr3(GEM_DEVICE *mac)
+{
+	MAC_ADDR addr;
+	addr.bottom = readl(mac->registers + GEM_LADDR3_BOT) ;
+	addr.top = readl(mac->registers + GEM_LADDR3_TOP) ;
+	return addr;
+}
+MAC_ADDR gem_get_laddr4(GEM_DEVICE *mac)
+{
+	MAC_ADDR addr;
+	addr.bottom = readl(mac->registers + GEM_LADDR3_BOT) ;
+	addr.top = readl(mac->registers + GEM_LADDR3_TOP) ;
+	return addr;
+}
+/******************************************************************************/
+
+
+/******************************************************************************/
+/*
+ * Obtain the statistics registers structure.
+ * type GEM_STATS as defined in the header file.
+ * Note that this operation is relatively slow as it is copying all the
+ * statistics register values rather than providing a pointer reference to them.
+ * Note also that the statistics registers will all be automatically cleared
+ * after this operation.
+ *
+ * Returns the entire statistics register block for the MAC in a structure of
+ * type GEM_STATS
+ */
+/******************************************************************************/
+GEM_STATS gem_get_stats(GEM_DEVICE *mac)
+{
+	return *(GEM_STATS *)(mac->registers + GEM_OCT_TX_BOT);
+}
+/******************************************************************************/
+
+
+/******************************************************************************/
+/*
+ * Set the values of the statistics registers.
+ * This is for debug only and allows reading and writing to the statistic
+ * registers to verify functionality.
+ *
+ * There is no return value.
+ */
+/******************************************************************************/
+void gem_set_stats(GEM_DEVICE *mac, GEM_STATS *stats)
+{
+}
+/******************************************************************************/
+
+
+/******************************************************************************/
+/*
+ * Write to a specific MAC memory address.  The defines in the header file
+ * should be used for this.
+ * Note: care should be taken when using this function so as not to pass null
+ * pointers or write to read only registers etc.
+ *
+ * Return value:
+ *  0   :   OK
+ *  -1  :   Invalid input range.
+ */
+/******************************************************************************/
+int gem_register_wr(GEM_DEVICE  *mac, UINT_32 reg_addr, UINT_32 data)
+{
+	if (reg_addr > GEM_REG_TOP)
+		return -1;
+	else {
+		writel(data, mac->registers + reg_addr);
+		return 0;
+	}
+}
+/******************************************************************************/
+
+
+/******************************************************************************/
+/*
+ * Read from a specific MAC memory address. The defines in the header file
+ * should be used for this.
+ * Note that the range of the address requested is not checked.
+ *
+ * Returns register contents.
+ */
+/******************************************************************************/
+UINT_32 gem_register_rd(GEM_DEVICE *mac, UINT_32 reg_addr)
+{
+	return readl(mac->registers + reg_addr);
+}
+/******************************************************************************/
+
+
+/******************************************************************************/
+/*
+ * Reset the MAC device to its default value and load up the MAC address stored
+ * in the header file into specific address 1.  The MAC will be held in
+ * quiescent state.
+ * This function should be called to initialise and check the device prior to
+ * setting up the buffer queues and enabling the MAC.  If it is called mid way
+ * through operation, the MAC is reset to default value and any pending frames
+ * will be lost.
+ * Note that the values in the GEM_DEVICE software structure are not reset, only
+ * the MAC registers are reset.  This is to allow, if necessary to recover the
+ * buffers and reload them into the MAC, however prior to doing this, they
+ * should be cleared first.
+ *
+ * Return value:
+ *  0   :   OK
+ *  -1  :   Error in write/read check on initialisation.
+ */
+/******************************************************************************/
+int gem_reset(GEM_DEVICE *mac)
+{
+	MAC_ADDR zero_address = {0x00000000, 0x00000000};
+	MAC_ADDR enet_address = zero_address;
+
+	/* Write to registers and set default values. */
+	writel(GEM_STATS_CLR | GEM_MDIO_ENABLED,
+			mac->registers + GEM_NET_CONTROL);
+	writel(GEM_DEF_DUPLEX, mac->registers + GEM_NET_CONFIG);
+	gem_set_loop(mac, GEM_DEF_LOOP);
+	gem_set_speed(mac, GEM_DEF_SPEED);
+	gem_set_ahb_width(mac, GEM_DEF_AHB_WIDTH);
+
+	writel(0xFFFFFFFF, mac->registers + GEM_TX_STATUS);
+	writel(0x00000000, mac->registers + GEM_RX_QPTR);
+	writel(0x00000000, mac->registers + GEM_TX_QPTR);
+	writel(0xFFFFFFFF, mac->registers + GEM_RX_STATUS);
+	writel(0xFFFFFFFF, mac->registers + GEM_IRQ_DISABLE);
+	writel(0x00000000, mac->registers + GEM_IRQ_STATUS);
+	gem_set_hash(mac, &zero_address);
+	gem_set_laddr1(mac, &enet_address);
+	gem_set_laddr2(mac, &zero_address);
+	gem_set_laddr3(mac, &zero_address);
+	gem_set_laddr4(mac, &zero_address);
+
+	/* Now read back values and return if not correct. */
+	if (
+			(readl(mac->registers + GEM_LADDR4_BOT) != zero_address.bottom) ||
+			(readl(mac->registers + GEM_LADDR4_TOP) != zero_address.top) ||
+			(readl(mac->registers + GEM_LADDR3_BOT) != zero_address.bottom) ||
+			(readl(mac->registers + GEM_LADDR3_TOP) != zero_address.top) ||
+			(readl(mac->registers + GEM_LADDR2_BOT) != zero_address.bottom) ||
+			(readl(mac->registers + GEM_LADDR2_TOP)  != zero_address.top) ||
+			(readl(mac->registers + GEM_LADDR1_BOT)  != enet_address.bottom) ||
+			(readl(mac->registers + GEM_LADDR1_TOP)  != enet_address.top) ||
+			(readl(mac->registers + GEM_HASH_BOT) != zero_address.bottom) ||
+			(readl(mac->registers + GEM_HASH_TOP) != zero_address.top) ||
+			(readl(mac->registers + GEM_IRQ_STATUS) != 0x00000000) ||
+			(readl(mac->registers + GEM_IRQ_MASK) != 0x0003FFFF) ||
+			(readl(mac->registers + GEM_RX_STATUS) != 0x00000000) ||
+			(readl(mac->registers + GEM_TX_QPTR) != 0x00000000) ||
+			(readl(mac->registers + GEM_RX_QPTR) != 0x00000000) ||
+			(readl(mac->registers + GEM_TX_STATUS) != 0x00000000)
+	   )
+		return -1;
+	else if (((readl(mac->registers + GEM_NET_CONTROL) & GEM_MDIO_EN) !=
+				(0x00000000 | GEM_MDIO_ENABLED)) ||
+			((readl(mac->registers + GEM_NET_CONFIG) & GEM_FULL_DUPLEX) !=
+			 (0x00000000 | GEM_DEF_DUPLEX)) ||
+			(gem_get_loop(mac) != GEM_DEF_LOOP)   ||
+			(gem_get_ahb_width(mac) != GEM_DEF_AHB_WIDTH)
+		)
+		return -1;
+	else
+		return 0;
+}
+/******************************************************************************/
+
+
+/******************************************************************************/
+/*
+ * Enable length field checking feature.
+ * The length field check feature automatically discards frames that has a frame
+ * length smaller than that reported in the length field of the header.
+ *
+ * Note that in accordance with the IEEE spec, frames that are longer than that
+ * reported in length field is still accepted as a valid frame.
+ *
+ * This function has no return value.
+ */
+/******************************************************************************/
+void gem_enable_len_check(GEM_DEVICE *mac)
+{
+	writel(readl(mac->registers + GEM_NET_CONFIG) | GEM_RX_LEN_CHK,
+			mac->registers + GEM_NET_CONFIG);
+}
+/******************************************************************************/
+
+
+/******************************************************************************/
+/*
+ * Disable length field checking feature.
+ *
+ * This function has no return value.
+ */
+/******************************************************************************/
+void gem_disable_len_check(GEM_DEVICE *mac)
+{
+	writel(readl(mac->registers + GEM_NET_CONFIG) & (~GEM_RX_LEN_CHK),
+			mac->registers + GEM_NET_CONFIG);
+}
+/******************************************************************************/
+
+
+/******************************************************************************/
+/*
+ * Convert standard byte style ethernet address to format compatible with MAC.
+ *
+ * Input    :   Pointer to beginning of 6 byte address.
+ *              Pointer to MAC_ADDR structure.
+ * Return values:
+ *  0   :   OK
+ *  -1  :   Invalid inputs.
+ */
+/******************************************************************************/
+int gem_enet_addr_byte_mac(BYTE *enet_byte_addr, MAC_ADDR *enet_addr)
+{
+	if ((enet_byte_addr == NULL) || (enet_addr == NULL))
+		return -1;
+	else {
+		enet_addr->bottom = enet_byte_addr[0] |
+			(enet_byte_addr[1] << 8) |
+			(enet_byte_addr[2] << 16) |
+			(enet_byte_addr[3] << 24);
+		enet_addr->top = enet_byte_addr[4] |
+			(enet_byte_addr[5] << 8);
+		return 0;
+	}
+}
+/******************************************************************************/
+
+
+/******************************************************************************/
+/*
+ * Convert MAC type ethernet address to standard byte style ethernet address.
+ *
+ * Input    :   Pointer to beginning of free space for 6 byte address.
+ *              Pointer to MAC_ADDR structure.
+ * Return values:
+ *  0   :   OK
+ *  -1  :   Invalid inputs.
+ */
+/******************************************************************************/
+int gem_enet_addr_mac_byte(BYTE *enet_byte_addr, MAC_ADDR *enet_addr)
+{
+	if ((enet_byte_addr == NULL) || (enet_addr == NULL))
+		return -1;
+	else {
+		enet_byte_addr[0] = enet_addr->bottom & 0xFF;
+		enet_byte_addr[1] = (enet_addr->bottom >> 8) & 0xFF;
+		enet_byte_addr[2] = (enet_addr->bottom >> 16) & 0xFF;
+		enet_byte_addr[3] = (enet_addr->bottom >> 24) & 0xFF;
+
+		enet_byte_addr[4] = enet_addr->top & 0xFF;
+		enet_byte_addr[5] = (enet_addr->top >> 8) & 0xFF;
+
+		return 0;
+	}
+}
+/******************************************************************************/
diff -r e137be04dc4d drivers/net/comcerto/comcerto_gemac.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/net/comcerto/comcerto_gemac.c	Mon Aug 17 16:45:23 2009 -0500
@@ -0,0 +1,485 @@
+/*
+ *  linux/drivers/net/comcerto/comcerto_gemac.c
+ *
+ *  Copyright (C) 2006 Mindspeed Technologies, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+#include <asm/delay.h>
+#include <asm/io.h>
+#include <mach/comcerto-devices.h>
+
+#include "comcerto_idma.h"
+#include "comcerto_eth.h"
+#include "comcerto_gemac.h"
+
+
+static int gemt_debug = DRV_DBG_LEVEL;
+
+int gem_add_arc_entry(void *priv, char *MAC_address);
+int gem_phy_link_init(GEM_DEVICE *gemdev, int phy_addr);
+int gemt_PHY_timeout(GEM_DEVICE *gemdev, int timeout);
+static void gemt_reset_gem(GEM_DEVICE *gemdev);
+int gemt_reinit(GEM_DEVICE *gemdev, int phy_addr);
+int gemt_config_PHY(GEM_DEVICE *gemdev, int phy_addr,
+		MAC_SPEED speed, u8 duplex_mode);
+int gemac_halt(struct eth_priv *priv);
+int gemac_init(struct eth_priv *priv);
+void comcerto_emac_restart(struct eth_priv *priv);
+void comcerto_emac_restart_tx(struct eth_priv *priv);
+
+
+
+int gem_add_arc_entry(void *priv, char *MAC_address)
+{
+	MAC_ADDR enet_addr;
+	gem_enet_addr_byte_mac(MAC_address, &enet_addr);
+	gem_set_laddr1(priv, &enet_addr);
+	return 0;
+}
+
+
+/*=============================================================================
+ *
+ * NAME: gemt_reset_mac
+ *
+ * PARAMETERS:
+ *   net_device *dev    -INOUT
+ *
+ * DESCRIPTION
+ *   Reset MAC hardware
+ *   This function will reset MAC hardware after stop the MAC for both
+ *   transmission and reception.
+ *
+ * ASSUMPTIONS
+ *   None
+ *
+ * SIDE EFFECTS / STATIC DATA USE
+ *   None
+ *
+ * RETURNS:
+ *   None
+ *
+ *===========================================================================*/
+static void gemt_reset_gem(GEM_DEVICE *gemdev)
+{
+	LOG(DRV_DEBUG_TRACE, "gemt_reset_gem\n");
+
+	LOG(DRV_DEBUG_LOAD, "Aborting transmit and receive.\n");
+	gem_abort_tx(gemdev);
+	gem_disable_rx(gemdev);
+
+	LOG(DRV_DEBUG_LOAD, "Masking all irq.\n");
+	gem_enable_irq(gemdev, GEM_IRQ_ALL);
+	gem_get_irq_stat(gemdev);
+
+	LOG(DRV_DEBUG_LOAD, "Resetting mac to default state.\n");
+
+	if (gem_reset(gemdev) != 0)
+		LOG(DRV_DEBUG_FATAL, "Failed to reset device!\n");
+}
+
+
+int gemac_halt(struct eth_priv *priv)
+{
+	GEM_DEVICE *gemdev = &priv->gemdev;
+
+	gem_stop_tx(gemdev);
+	gem_disable_rx(gemdev);
+	return 0;
+}
+/* Initializes data structures and registers for the controller,
+ * and brings the interface up.	 Returns the link status, meaning
+ * that it returns success if the link is up, failure otherwise.
+ * This allows u-boot to find the first active controller. */
+int gemac_init(struct eth_priv *priv)
+{
+	GEM_DEVICE *gemdev = &priv->gemdev;
+	struct comcerto_eth_platform_data *einfo = priv->einfo ;
+
+#if defined(CONFIG_ARCH_M821XX)
+	writel(readl(COMCERTO_BLOCK_RESET_REG) | GEMAC0_RST << einfo->gem_id,
+			COMCERTO_BLOCK_RESET_REG);
+	udelay(1);
+#endif
+
+	/* software config */
+	switch (einfo->mii_config) {
+	case CONFIG_COMCERTO_USE_GMII:
+		writel(einfo->gemac_mode | GEM_CONF_MODE_SEL_GEM | \
+				GEM_CONF_MODE_GEM_GMII,
+				gemdev->gemac_baseaddr + GEM_CFG);
+		printk(KERN_DEBUG "comcerto gemac%d software config using GMII\n",
+				einfo->gem_id);
+		break;
+	case CONFIG_COMCERTO_USE_RGMII:
+		writel(einfo->gemac_mode | GEM_CONF_MODE_SEL_GEM | \
+				GEM_CONF_MODE_GEM_RGMII,
+				gemdev->gemac_baseaddr + GEM_CFG);
+		printk(KERN_DEBUG "comcerto gemac%d software config using RGMII\n",
+				einfo->gem_id);
+		break;
+	case CONFIG_COMCERTO_USE_RMII:
+		writel(einfo->gemac_mode | GEM_CONF_MODE_SEL_GEM | \
+				GEM_CONF_MODE_GEM_RMII,
+				gemdev->gemac_baseaddr + GEM_CFG);
+		printk(KERN_DEBUG "comcerto gemac%d software config using RMII\n",
+				einfo->gem_id);
+		break;
+	case CONFIG_COMCERTO_USE_MII:
+		writel(einfo->gemac_mode | GEM_CONF_MODE_SEL_GEM | \
+				GEM_CONF_MODE_GEM_MII,
+				gemdev->gemac_baseaddr + GEM_CFG);
+		printk(KERN_DEBUG "comcerto gemac%d software config using MII\n",
+				einfo->gem_id);
+		break;
+	default:
+		if (einfo->gemac_mode & (GEMAC_SW_CONF)) {
+			printk(KERN_DEBUG \
+				"comcerto gemac software config requires one \
+				MII mode defined \n");
+			BUG();
+		} else {
+			writel(einfo->gemac_mode | GEM_CONF_MODE_SEL_GEM | \
+					GEM_CONF_MODE_GEM_MII,
+					gemdev->gemac_baseaddr + GEM_CFG);
+			printk(KERN_DEBUG \
+				"comcerto gemac%d hardware MII config \n",
+				einfo->gem_id);
+		}
+		break;
+	}
+
+	writel(GEM_TXCTRL_DMAIF_EN | GEM_TXCTRL_CRC_EN | GEM_TXCTRL_RETR_EN,
+			gemdev->gemac_baseaddr + GEM_TX_CTRL);
+	writel(GEM_RXCTRL_DMAIF_EN, gemdev->gemac_baseaddr + GEM_RX_CTRL);
+	writel(priv->Rxpktsz, gemdev->gemac_baseaddr + GEM_RX_STAT_PKTSIZE);
+	writel(ARM_FIFO_RXDREQWE | ARM_FIFO_TXDREQRE,
+			gemdev->gemac_baseaddr + GEM_ARM_FIFO_CTRL);
+	writel(priv->inbound_fifo_high,
+			gemdev->gemac_baseaddr + GEM_ARM_RX_FIFO_HIGH);
+	writel(priv->inbound_fifo_low,
+			gemdev->gemac_baseaddr + GEM_ARM_RX_FIFO_LOW);
+	writel(priv->outbound_fifo_high,
+			gemdev->gemac_baseaddr + GEM_RX_FIFO_HIGH);
+	writel(priv->outbound_fifo_low,
+			gemdev->gemac_baseaddr + GEM_RX_FIFO_LOW);
+	writel(GEM_FIFO_CTRL_TXFF_EN | GEM_FIFO_CTRL_HBTXRQ_EN | \
+			GEM_FIFO_CTRL_RXFF_EN | GEM_FIFO_CTRL_HBRXRQ_EN,
+			gemdev->gemac_baseaddr + GEM_FIFO_CTRL);
+
+	/* Reset the MAC */
+	gemt_reset_gem(gemdev);
+
+	gem_disable_copy_all(gemdev);
+	gem_allow_broadcast(gemdev);
+	gem_enable_unicast(gemdev);
+	gem_enable_multicast(gemdev);
+	gem_disable_fcs_rx(gemdev);
+	gem_set_mdc_div(gemdev, MDC_DIV_64);
+
+	/*GEM will perform checksum verifications*/
+	gem_enable_checksum_offload(gemdev);
+	/* enable Pause frame reception */
+	gem_enable_pause_rx(gemdev);
+	priv->rx_csum_enable = 1;
+
+	return 1;
+}
+
+
+irqreturn_t comcerto_gemac_interrupt(int irq, void *dev_id)
+{
+	struct net_device *dev = (struct net_device *)dev_id;
+	struct eth_priv *priv = netdev_priv(dev);
+	GEM_DEVICE *gem = &priv->gemdev;
+	unsigned long statusword;
+
+	gem_mask_irq(gem, GEM_IRQ_RX_ORUN);
+
+	statusword = gem_get_irq_stat(gem);
+	if (statusword & GEM_IRQ_RX_ORUN)
+		if (readl(EMMM_START(priv->IDMA_baseaddr))) {
+			writel(1, EMMM_SOFT_RESET(priv->IDMA_baseaddr));
+			/* generate interrupt to wake up NAPI if needed */
+			__raw_writel((1UL << priv->EDMArx_int),
+					COMCERTO_INTC_SET_STATUS_REG_0);
+
+		}
+	return IRQ_HANDLED;
+}
+
+void comcerto_gemac_setduplex(struct net_device *dev, int duplex)
+{
+	struct eth_priv *priv = netdev_priv(dev);
+	GEM_DEVICE *gemdev = &priv->gemdev;
+
+	if (duplex == DUPLEX_HALF)
+		gem_half_duplex(gemdev);
+	else
+		gem_full_duplex(gemdev);
+
+}
+
+void comcerto_gemac_setspeed(struct net_device *dev, int speed)
+{
+	struct eth_priv *priv = netdev_priv(dev);
+	GEM_DEVICE *gemdev = &priv->gemdev;
+
+	switch (speed) {
+	case 10:
+		priv->inbound_fifo_high = 0x1C0;
+		writel(priv->inbound_fifo_high,
+				gemdev->gemac_baseaddr + GEM_ARM_RX_FIFO_HIGH);
+		writel(readl(gemdev->registers + GEM_NET_CONFIG) | \
+				GEM_RX_BAD_PREAMBLE,
+				gemdev->registers + GEM_NET_CONFIG);
+
+		priv->outbound_fifo_high = 0x40;
+		writel(priv->outbound_fifo_high,
+				gemdev->gemac_baseaddr + GEM_RX_FIFO_HIGH);
+		gem_set_speed(gemdev, SPEED_10M);
+		break;
+	case 100:
+		priv->inbound_fifo_high = 0x1D0;
+		writel(priv->inbound_fifo_high,
+				gemdev->gemac_baseaddr + GEM_ARM_RX_FIFO_HIGH);
+		writel(readl(gemdev->registers + GEM_NET_CONFIG) & \
+				~GEM_RX_BAD_PREAMBLE,
+				gemdev->registers + GEM_NET_CONFIG);
+
+		priv->outbound_fifo_high = 0x40;
+		writel(priv->outbound_fifo_high,
+				gemdev->gemac_baseaddr + GEM_RX_FIFO_HIGH);
+		gem_set_speed(gemdev, SPEED_100M);
+		comcerto_emac_restart_tx(priv);
+		break;
+	case 1000:
+		priv->inbound_fifo_high = 0x1D0;
+		writel(priv->inbound_fifo_high,
+				gemdev->gemac_baseaddr + GEM_ARM_RX_FIFO_HIGH);
+		writel(readl(gemdev->registers + GEM_NET_CONFIG) & \
+				~GEM_RX_BAD_PREAMBLE,
+				gemdev->registers + GEM_NET_CONFIG);
+
+		priv->outbound_fifo_high = DEFAULT_TX_GEM_THR_HI;
+		writel(priv->outbound_fifo_high,
+				gemdev->gemac_baseaddr + GEM_RX_FIFO_HIGH);
+		gem_set_speed(gemdev, SPEED_1000M);
+		comcerto_emac_restart_tx(priv);
+		break;
+	}
+}
+
+
+int comcerto_emac_init(struct net_device *dev)
+{
+	struct eth_priv *priv = netdev_priv(dev);
+	GEM_DEVICE *gemdev = &priv->gemdev;
+
+	gemdev->gemac_baseaddr = priv->EMAC_baseaddr;
+	gemdev->registers = (u32)((u32)gemdev->gemac_baseaddr + GEM_IP);
+	/* Make sure the controller is stopped */
+	gemac_halt(priv);
+
+	gemac_init(priv);
+
+
+	/* Ready the device for tx/rx */
+	gem_start_tx(gemdev);
+	gem_enable_rx(gemdev);
+
+	gem_enable_irq(gemdev, GEM_IRQ_RX_ORUN);
+
+	return 0;
+
+}
+
+
+void comcerto_emac_restart_tx(struct eth_priv *priv)
+{
+	GEM_DEVICE *gem = &priv->gemdev;
+	u32 txhead = 0;
+	u32 restart_tx = 0;
+	unsigned long flags;
+	int i;
+
+
+
+	local_irq_save(flags);
+
+	gem_abort_tx(gem);
+	if (readl(MMEM_START(priv->IDMA_baseaddr))) {
+		restart_tx = 1;
+		*(unsigned int *)MMEM_SOFT_RESET(priv->IDMA_baseaddr) = 1;
+		i = priv->Txdone;
+		while (priv->TxRing[i]->FStatus & IDMA_FSTATUS_FRAME_DONE_MASK) {
+			if (++i == priv->TxRingSize)
+				i = 0;
+		}
+		txhead = phys_desc(priv, priv->TxRing[i]);
+
+	}
+
+	writel(0, gem->gemac_baseaddr + GEM_TX_CTRL);
+	writel(readl(gem->gemac_baseaddr + GEM_ARM_FIFO_CTRL) | \
+			ARM_FIFO_RXFF_RES,
+			gem->gemac_baseaddr + GEM_ARM_FIFO_CTRL);
+	udelay(1);
+
+	writel(readl(gem->gemac_baseaddr + GEM_ARM_FIFO_CTRL) & \
+			~(ARM_FIFO_RXFF_RES),
+			gem->gemac_baseaddr + GEM_ARM_FIFO_CTRL);
+	writel(GEM_TXCTRL_DMAIF_EN | GEM_TXCTRL_CRC_EN | GEM_TXCTRL_RETR_EN,
+			gem->gemac_baseaddr + GEM_TX_CTRL);
+	gem_start_tx(gem);
+
+	writel(priv->tx_lock_size, MMEM_BURST(priv->IDMA_baseaddr));
+	if (restart_tx) {
+		writel(txhead, MMEM_HEAD(priv->IDMA_baseaddr));
+		writel(readl(MMEM_START(priv->IDMA_baseaddr)) | IDMA_START,
+				MMEM_START(priv->IDMA_baseaddr));
+	}
+
+	local_irq_restore(flags);
+
+
+
+}
+
+
+void comcerto_emac_restart(struct eth_priv *priv)
+{
+	GEM_DEVICE *gem = (GEM_DEVICE *)&priv->gemdev;
+	unsigned int tmp;
+	unsigned long flags;
+	u32 net_cfg, addr1_b, addr1_t, hash_b, hash_t;
+	u32 data_fifo_depth;
+	PFDesc ThisFdesc ;
+
+
+	local_irq_save(flags);
+	net_cfg = readl((gem->registers + GEM_NET_CONFIG));
+	writel((net_cfg & 0xffffff0f), gem->registers + GEM_NET_CONFIG);
+	writel(readl(gem->registers + GEM_NET_CONFIG) | 0x800020,
+			gem->registers + GEM_NET_CONFIG);
+
+	addr1_b = readl(gem->registers + GEM_LADDR1_BOT) ;
+	writel(addr1_b, gem->registers + GEM_LADDR1_BOT);
+
+	hash_b = readl(gem->registers + GEM_HASH_BOT);
+	writel(hash_b, gem->registers + GEM_HASH_BOT);
+
+	data_fifo_depth = readl(gem->gemac_baseaddr + GEM_ARM_TX_FIFO_SIZE);
+	udelay(1);
+	while (readl(gem->gemac_baseaddr + GEM_ARM_TX_FIFO_SIZE) != \
+			data_fifo_depth) {
+		data_fifo_depth = \
+			readl(gem->gemac_baseaddr + GEM_ARM_TX_FIFO_SIZE);
+		udelay(1);
+	}
+
+	gem_disable_rx(gem);
+
+
+
+	addr1_t = readl(gem->registers + GEM_LADDR1_TOP);
+	writel(addr1_t, gem->registers + GEM_LADDR1_TOP);
+
+	hash_t = readl(gem->registers + GEM_HASH_TOP);
+	writel(hash_t, gem->registers + GEM_HASH_TOP);
+
+	writel(0xf, gem->registers + GEM_RX_STATUS);
+	writel(net_cfg, gem->registers + GEM_NET_CONFIG);
+
+	writel(0, gem->gemac_baseaddr + GEM_RX_CTRL);
+	writel(readl(gem->gemac_baseaddr + GEM_ARM_FIFO_CTRL) | \
+			ARM_FIFO_TXFF_RES,
+			gem->gemac_baseaddr + GEM_ARM_FIFO_CTRL);
+
+
+	tmp = readl(EMMM_HEAD(priv->IDMA_baseaddr));
+	ThisFdesc = virt_desc(priv, tmp);
+	if ((ThisFdesc->FControl & IDMA_FCONTROL_FREADY) == 0)
+		tmp = (unsigned int)ThisFdesc->Next;
+	writel(1, EMMM_SOFT_RESET(priv->IDMA_baseaddr));
+	writel(priv->rx_lock_size, EMMM_BURST(priv->IDMA_baseaddr));
+	writel(tmp, EMMM_HEAD(priv->IDMA_baseaddr));
+	writel(readl(EMMM_START(priv->IDMA_baseaddr) | IDMA_START),
+			EMMM_START(priv->IDMA_baseaddr));
+
+	writel(readl(gem->gemac_baseaddr + GEM_ARM_FIFO_CTRL) & \
+			~(ARM_FIFO_TXFF_RES),
+			gem->gemac_baseaddr + GEM_ARM_FIFO_CTRL);
+
+	writel(GEM_RXCTRL_DMAIF_EN, gem->gemac_baseaddr + GEM_RX_CTRL);
+	gem_enable_rx(gem);
+
+	gem_enable_irq(gem, GEM_IRQ_RX_ORUN);
+	local_irq_restore(flags);
+}
+
+
+/* Stop the interface */
+void comcerto_emac_halt(struct net_device *dev)
+{
+	struct eth_priv *priv = netdev_priv(dev);
+
+	gemac_halt(priv);
+}
+
+int comcerto_emac_add_ARC_entry(struct net_device *dev, char *MAC_address)
+{
+	struct eth_priv *priv = netdev_priv(dev);
+	GEM_DEVICE *gem = (GEM_DEVICE *)&priv->gemdev;
+
+	return gem_add_arc_entry(gem, MAC_address);
+}
+
+int comcerto_emac_check_frame_status(u32 status)
+{
+	return (status & RX_CHECK_ERROR) ? 0 : 1;
+}
+void comcerto_emac_checksum(u32 status, struct sk_buff *skb)
+{
+	/*Have IP Checksum been validated ?*/
+	if (status & RX_STA_IP) {
+		/*
+		 * If UDP Checksum is OK (in case of a UDP packet)
+		 * Linux don't need to verify checksums
+		 */
+		if (status & RX_STA_UDP)
+			skb->ip_summed = CHECKSUM_UNNECESSARY;
+
+		/*
+		 * If TCP Checksum is OK (in case of a TCP packet)
+		 * Linux don't need to verify checksums
+		 */
+		else if (status & RX_STA_TCP)
+			skb->ip_summed = CHECKSUM_UNNECESSARY;
+
+		/*
+		 * Only IP checksum have been validated
+		 * Linux supports this case (CHECKSUM_HW)
+		 * But it needs to have the hadware calculated value
+		 * GEM doesn't provide it, so we consider that
+		 * no validation have been done
+		 */
+		else
+			skb->ip_summed = CHECKSUM_NONE;
+	} else
+		skb->ip_summed = CHECKSUM_NONE;
+}
diff -r e137be04dc4d drivers/net/comcerto/comcerto_gemac.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/net/comcerto/comcerto_gemac.h	Mon Aug 17 16:45:23 2009 -0500
@@ -0,0 +1,834 @@
+/*
+ *  linux/drivers/net/comcerto/comcerto_gemac.h
+ *
+ *  Copyright (C) 2006 Mindspeed Technologies, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef _COMCERTO_GEMAC_H
+#define _COMCERTO_GEMAC_H
+
+#include <linux/io.h>
+#include <mach/hardware.h>
+#include "comcerto_idma.h"
+
+#define CONFIG_COMCERTO_GEMAC	1
+
+
+/* Some simple definitions to make things easier to read */
+#ifndef TRUE
+    #define TRUE   (0x01)
+#endif
+#ifndef FALSE
+    #define FALSE  (0x00)
+#endif
+
+#ifndef NULL
+    #define NULL (0)
+#endif
+
+#define DRV_DEBUG_OFF       0x0000
+#define DRV_DEBUG_LOAD      0x0001
+#define DRV_DEBUG_OPEN      0x0002
+#define DRV_DEBUG_STOP      0x0004
+#define DRV_DEBUG_CLOSE     0x0004
+#define DRV_DEBUG_UNLOAD    0x0008
+#define DRV_DEBUG_IOCTL     0x0010
+#define DRV_DEBUG_SEND      0x0020
+#define DRV_DEBUG_MCAST_ADD 0x0040
+#define DRV_DEBUG_MCAST_DEL 0x0080
+#define DRV_DEBUG_MCAST_GET 0x0100
+#define DRV_DEBUG_INT       0x0800
+#define DRV_DEBUG_RX        0x1000
+#define DRV_DEBUG_TX        0x2000
+#define DRV_DEBUG_FATAL     0x4000
+#define DRV_DEBUG_CRITICAL  0x8000
+#define DRV_DEBUG_TRACE     0x10000000
+
+#define DRV_DEBUG_RX_BUF       0x00010000
+#define DRV_DEBUG_TX_BUF       0x00020000
+
+#define DRV_DEBUG_RX_ORUN      0x00040000
+#define DRV_DEBUG_TX_URUN      0x00080000
+#define DRV_DEBUG_TX_MID_ERR   0x00100000
+
+#define DRV_DEBUG_ALL          0x1000ffff
+
+#define DRV_DBG_LEVEL	DRV_DEBUG_OFF
+
+/* Default debug level.. */
+#if !defined(DRV_DBG_LEVEL)
+#define DRV_DBG_LEVEL  (DRV_DEBUG_FATAL | DRV_DEBUG_CRITICAL)
+#endif
+
+
+
+#define LOG(flg, fmt, args...)    \
+	{ if (gemt_debug & flg) printk("gem: " fmt, ## args); }
+#define LOG_DATA(flg, fmt, args...)    \
+	{ if (gemt_debug & flg) printk(fmt, ## args); }
+
+
+/* An enumerated type for loopback values.  This can be one of three values, no
+ * loopback -normal operation, local loopback with internal loopback module of
+ * MAC or PHY loopback which is through the external PHY.
+ */
+#ifndef __MAC_LOOP_ENUM__
+#define __MAC_LOOP_ENUM__
+typedef enum {LB_NONE, LB_EXT, LB_LOCAL} MAC_LOOP;
+#endif
+
+/* The possible operating speeds of the MAC, currently supporting 10, 100 and
+ * 1000Mb modes.
+ */
+#ifndef __MAC_SPEED_ENUM__
+#define __MAC_SPEED_ENUM__
+typedef enum {SPEED_10M, SPEED_100M, SPEED_1000M, SPEED_1000M_PCS} MAC_SPEED;
+#endif
+
+/* The possible AMBA AHB bus width of the MAC, currently supporting 32, 64 and
+ * 128 bits.
+ */
+#ifndef __MAC_AHB_ENUM__
+#define __MAC_AHB_ENUM__
+typedef enum {AMBA_AHB_32, AMBA_AHB_64, AMBA_AHB_128} MAC_AHB_WIDTH;
+#endif
+
+/* The possible MDC clock division of the MAC, currently supporting 8, 16 , 32,
+ * 48, 64, 96, 128, 224.
+ */
+#ifndef __MAC_DMCDIV_ENUM__
+#define __MAC_DMCDIV_ENUM__
+typedef enum {MDC_DIV_8, MDC_DIV_16, MDC_DIV_32, MDC_DIV_48, MDC_DIV_64,
+		MDC_DIV_96, MDC_DIV_128, MDC_DIV_224
+	} MAC_MDC_DIV;
+#endif
+
+#define MDIO_TIMEOUT            5000            /* instruction cycles? */
+#define GEM_PHY_ADDR           3
+/* the following PHY related thing should be standard no need to change */
+#define PHY_SPEED_1000M         ((1<<9) | (1<<8))
+#define PHY_DUPLEX_FULL_1000M   (1<<9)
+
+#define PHY_SPEED_100M          ((1<<8) | (1<<7))
+#define PHY_SPEED_10M           ((1<<6) | (1<<5))
+#define PHY_DUPLEX_FULL_100M    (1<<8)
+#define PHY_DUPLEX_FULL_10M     (1<<6)
+
+
+#define GEM_HASH_REG_BITS	64
+/* Specify whether the MDIO should be available, this is set so that for reset
+ * function, appropriate options are setup.  To disable, use 0.
+ */
+#define GEM_MDIO_ENABLED (GEM_MDIO_EN)
+
+
+/* Specify the default PCLK divisor for generating MDC.  This simply defines
+ * which of the divisor control bits are active.  By default, the clock
+ * division is 32.
+ */
+#define GEM_DEF_PCLK_DIV (MDC_DIV_32)
+
+
+/* Specify the default AMBA AHB bus width.  This simply defines
+ * which of the bus width control bits are active.  By default, the bus
+ * width is 32.
+ */
+#define GEM_DEF_AHB_WIDTH (AMBA_AHB_32)
+
+
+/* Specify default duplex mode, for half duplex - specify 0. */
+#ifndef GEM_DEF_DUPLEX
+/* Allow the value to be specified as compiler option
+   0 - half-duplex,
+   GEM_FULL_DUPLEX - full-duplex
+*/
+#define GEM_DEF_DUPLEX (GEM_FULL_DUPLEX)
+#endif
+
+/* Specify default operating speed, 1 for 100Mb.  Note that this is left
+ * shifted.  Also note that this simply asserts a signal to the PHY and has no
+ * effect on the operation of the MAC.
+ * For 10Mb/s mode, specify         SPEED_10M
+ * For 100Mb/s mode, specify        SPEED_100M
+ * For 1Gb/s mode, specify          SPEED_1000M
+ * For 1Gb/s with PCS mode, specify SPEED_1000M_PCS
+ */
+#ifndef GEM_DEF_SPEED
+/* Allow the value to be specified as compiler option */
+#define GEM_DEF_SPEED (SPEED_1000M)
+#endif
+
+/* Specify default loopback mode.  LB_NONE for no loopback, other values are LB_MAC
+ * and LB_PHY
+ */
+#define GEM_DEF_LOOP (LB_NONE)
+
+/******************************
+ *  GEMAC IP wrapper
+ */
+#define GEM_ARM_FIFO_CTRL			0x0000
+#define GEM_ARM_TX_FIFO_SIZE		0x0014
+#define GEM_ARM_RX_FIFO_SIZE		0x0024
+#define GEM_ARM_RX_FIFO_HIGH		0x0028
+#define GEM_ARM_RX_FIFO_LOW		0x002C
+
+#define GEM_FIFO_CTRL				0xD000
+#define GEM_RX_FIFO_HIGH			0xD024
+#define GEM_RX_FIFO_LOW			0xD028
+#define GEM_IP						0xE000
+#define GEM_CFG						0xF000
+#define GEM_TX_CTRL					0xF004
+#define GEM_TX_COLL				0xF008
+#define GEM_RX_CTRL				0xF010
+#define GEM_RX_STAT_PKTSIZE		0xF014
+#define GEM_RX_STAT_FIFODEPTH		0xF018
+#define GEM_RX_STAT_FIFODATA		0xF01C
+
+
+#define DEFAULT_RX_STAT_PKTSIZE		0x100
+#define DEFAULT_TX_GEM_THR_LO		0x00D
+#define DEFAULT_TX_GEM_THR_HI		0x100
+#define DEFAULT_RX_DMA_THR_LO	0x180
+#define DEFAULT_RX_DMA_THR_HI		0x1D0
+
+
+
+#define	GEM_FIFO_CTRL_TXFF_EN				(1 << 0)
+#define	GEM_FIFO_CTRL_HBTXRQ_EN				(1 << 1)
+#define	GEM_FIFO_CTRL_RXFF_EN				(1 << 3)
+#define	GEM_FIFO_CTRL_HBRXRQ_EN				(1 << 4)
+#define	GEM_FIFO_CTRL_TXCP_INH				(1 << 5)
+#define	GEM_FIFO_CTRL_RXCMPLTIE				(1 << 11)
+
+#define GEM_CONF_MODE_SEL_PIN				(0 << 0)
+#define GEM_CONF_MODE_SEL_GEM				(1 << 0)
+#define GEM_CONF_MODE_GEM_MASK				(7 << 1)
+#define GEM_CONF_MODE_GEM_MII				(0 << 1)
+#define GEM_CONF_MODE_GEM_GMII				(1 << 1)
+#define GEM_CONF_MODE_GEM_RMII				(2 << 1)
+#define GEM_CONF_MODE_GEM_RGMII				(3 << 1)
+#define GEM_CONF_MODE_GEM_SMII				(6 << 1)
+#define GEM_CONF_MODE_PIN_MASK				(7 << 4)
+#define GEM_CONF_MODE_PIN_MII				(0 << 4)
+#define GEM_CONF_MODE_PIN_GMII				(1 << 4)
+#define GEM_CONF_MODE_PIN_RMII				(2 << 4)
+#define GEM_CONF_MODE_PIN_RGMII				(3 << 4)
+#define GEM_CONF_MODE_PIN_SMII				(6 << 4)
+#define GEM_CONF_DUPLEX_SEL_PHY				(0 << 8)
+#define GEM_CONF_DUPLEX_SEL_GEM				(1 << 8)
+#define GEM_CONF_DUPLEX_GEM_HALF			(0 << 9)
+#define GEM_CONF_DUPLEX_GEM_FULL			(1 << 9)
+#define GEM_CONF_DUPLEX_PHY_HALF			(0 << 10)
+#define GEM_CONF_DUPLEX_PHY_FULL			(1 << 10)
+#define GEM_CONF_SPEED_SEL_PHY				(0 << 11)
+#define GEM_CONF_SPEED_SEL_GEM				(1 << 11)
+#define GEM_CONF_SPEED_MASK					(3 << 12)
+#define GEM_CONF_SPEED_GEM_10M				(0 << 12)
+#define GEM_CONF_SPEED_GEM_100M				(1 << 12)
+#define GEM_CONF_SPEED_GEM_1G				(2 << 12)
+#define GEM_CONF_SPEED_PHY_10M				(0 << 14)
+#define GEM_CONF_SPEED_PHY_100M				(1 << 14)
+#define GEM_CONF_SPEED_PHY_1G				(2 << 14)
+#define GEM_CONF_PHY_LINK_DOWN				(0 << 16)
+#define GEM_CONF_PHY_LINK_UP				(1 << 16)
+#define GEM_CONF_GEM_LOOPBACK				(1 << 17)
+
+#define GEM_TXCTRL_DMAIF_EN					(1 << 0)
+#define GEM_TXCTRL_CRC_EN					(1 << 1)
+#define GEM_TXCTRL_RETR_EN					(1 << 2)
+#define GEM_TXCTRL_TX_STATE					0xf0000
+
+
+#define GEM_RXCTRL_DMAIF_EN					(1 << 0)
+#define GEM_RXCTRL_RX_STATE					0xf0000
+
+
+/* Host fifo control bits */
+#define ARM_FIFO_RXDREQWE					(1 << 2)
+#define ARM_FIFO_TXDREQRE					(1 << 3)
+#define ARM_FIFO_TXFF_RES					(1 << 12)
+#define ARM_FIFO_RXFF_RES					(1 << 13)
+#define ARM_FIFO_RXCP_INH					(1 << 15)
+
+/* Define some bit positions for registers. */
+
+/* Bit positions for network control register */
+#define GEM_READ_SNAP       (1<<14)     /* Read snapshot register */
+#define GEM_TAKE_SNAP       (1<<13)     /* Take a snapshot */
+#define GEM_TX_0Q_PAUSE     (1<<12)     /* Transmit zero quantum pause frame */
+#define GEM_TX_PAUSE        (1<<11)     /* Transmit pause frame */
+#define GEM_TX_HALT         (1<<10)     /* Halt transmission after curr frame */
+#define GEM_TX_START        (1<<9)      /* Start tx (tx_go) */
+#define GEM_STATS_WR_EN     (1<<7)      /* Enable writing to stat registers */
+#define GEM_STATS_INC       (1<<6)      /* Increment statistic registers */
+#define GEM_STATS_CLR       (1<<5)      /* Clear statistic registers */
+#define GEM_MDIO_EN         (1<<4)      /* Enable MDIO port */
+#define GEM_TX_EN           (1<<3)      /* Enable transmit circuits */
+#define GEM_RX_EN           (1<<2)      /* Enable receive circuits */
+#define GEM_LB_MAC          (1<<1)      /* Perform local loopback at MAC */
+#define GEM_LB_PHY          (1<<0)      /* Perform ext loopback through PHY */
+
+/* Bit positions for network configuration register */
+#define GEM_RX_BAD_PREAMBLE (1<<29)     /* Receive frames with bad preamble */
+#define GEM_CKSUM_OFFLOAD   (1<<24)     /* Enable Checksum Engine*/
+#define GEM_RX_NO_PAUSE     (1<<23)     /* Do not copy pause frames to memory */
+#define GEM_AHB_WIDTH1      (1<<22)     /* Bit 1 for defining AHB width */
+#define GEM_AHB_WIDTH0      (1<<21)     /* Bit 0 for defining AHB width */
+#define GEM_MDC_DIV2        (1<<20)     /* PCLK divisor for MDC, bit 2 */
+#define GEM_MDC_DIV1        (1<<19)     /* PCLK divisor for MDC, bit 1 */
+#define GEM_MDC_DIV0        (1<<18)     /* PCLK divisor for MDC, bit 0 */
+#define GEM_RX_NO_FCS       (1<<17)     /* Discard FCS from received frames. */
+#define GEM_RX_LEN_CHK      (1<<16)     /* Receive length check. */
+#define GEM_RX_OFFSET_BASE  14          /* Pos of LSB for rx buffer offsets. */
+#define GEM_RX_OFFSET1      (1<<(GEM_RX_OFFSET_BASE + 1)) /* RX offset bit 1 */
+#define GEM_RX_OFFSET0      (1<<GEM_RX_OFFSET_BASE)       /* RX offset bit 0 */
+#define GEM_RX_PAUSE_EN     (1<<13)     /* Enable pause reception */
+#define GEM_RETRY_TEST      (1<<12)     /* Retry test for speeding up debug */
+#define GEM_PCS_SEL         (1<<11)     /* Select PCS */
+#define GEM_GIG_MODE        (1<<10)     /* Gigabit mode enable */
+#define GEM_EAM_EN          (1<<9)      /* External address match enable */
+#define GEM_FRAME_1536      (1<<8)      /* Enable 1536 byte frames reception */
+#define GEM_UNICAST_EN      (1<<7)      /* Receive unicast hash frames */
+#define GEM_MULTICAST_EN    (1<<6)      /* Receive multicast hash frames */
+#define GEM_NO_BROADCAST    (1<<5)      /* Do not receive broadcast frames */
+#define GEM_COPY_ALL        (1<<4)      /* Copy all frames */
+#define GEM_RX_JUMBO        (1<<3)      /* Allow jumbo frame reception */
+#define GEM_VLAN_ONLY       (1<<2)      /* Receive only VLAN frames */
+#define GEM_FULL_DUPLEX     (1<<1)      /* Enable full duplex */
+#define GEM_SPEED_100       (1<<0)      /* Set to 100Mb mode */
+
+/* Bit positions for network status register */
+#define GEM_PHY_IDLE        (1<<2)      /* PHY management is idle */
+#define GEM_MDIO_IN         (1<<1)      /* Status of mdio_in pin */
+#define GEM_LINK_STATUS     (1<<0)      /* Status of link pin */
+
+/* Bit positions for transmit status register */
+#define GEM_TX_HRESP        (1<<8)      /* Transmit hresp not OK */
+#define GEM_LATE_COL        (1<<7)      /* Late collision */
+#define GEM_TX_URUN         (1<<6)      /* Transmit underrun occurred */
+#define GEM_TX_COMPLETE     (1<<5)      /* Transmit completed OK */
+#define GEM_TX_BUF_EXH      (1<<4)      /* Transmit buffs exhausted mid frame */
+#define GEM_TX_GO           (1<<3)      /* Status of tx_go internal variable */
+#define GEM_TX_RETRY_EXC    (1<<2)      /* Retry limit exceeded */
+#define GEM_TX_COL          (1<<1)      /* Collision occurred during frame tx */
+#define GEM_TX_USED         (1<<0)      /* Used bit read in tx buffer */
+
+/* Bit positions for receive status register */
+#define GEM_RX_HRESP        (1<<3)      /* Receive hresp not OK */
+#define GEM_RX_ORUN         (1<<2)      /* Receive overrun occurred */
+#define GEM_RX_DONE         (1<<1)      /* Frame successfully received */
+#define GEM_RX_BUF_USED     (1<<0)      /* Receive buffer used bit read */
+
+/* Bit positions for interrupts */
+#define GEM_IRQ_PCS_AN      (1<<16)     /* PCS autonegotiation complete */
+#define GEM_IRQ_EXT_INT     (1<<15)     /* External interrupt pin triggered */
+#define GEM_IRQ_PAUSE_TX    (1<<14)     /* Pause frame transmitted */
+#define GEM_IRQ_PAUSE_0     (1<<13)     /* Pause time has reached zero */
+#define GEM_IRQ_PAUSE_RX    (1<<12)     /* Pause frame received */
+#define GEM_IRQ_HRESP       (1<<11)     /* hresp not ok */
+#define GEM_IRQ_RX_ORUN     (1<<10)     /* Receive overrun occurred */
+#define GEM_IRQ_PCS_LINK    (1<<9)      /* Status of PCS link changed */
+#define GEM_IRQ_TX_DONE     (1<<7)      /* Frame transmitted ok */
+#define GEM_IRQ_TX_ERROR    (1<<6)      /* Transmit err occurred or no buffers*/
+#define GEM_IRQ_RETRY_EXC   (1<<5)      /* Retry limit exceeded */
+#define GEM_IRQ_TX_URUN     (1<<4)      /* Transmit underrun occurred */
+#define GEM_IRQ_TX_USED     (1<<3)      /* Tx buffer used bit read */
+#define GEM_IRQ_RX_USED     (1<<2)      /* Rx buffer used bit read */
+#define GEM_IRQ_RX_DONE     (1<<1)      /* Frame received ok */
+#define GEM_IRQ_MAN_DONE    (1<<0)      /* PHY management operation complete */
+#define GEM_IRQ_ALL         (0xFFFFFFFF)/* Everything! */
+
+/* Transmit buffer descriptor status words bit positions. */
+#define GEM_TBQE_USED       (1<<31)     /* Used bit. */
+#define GEM_TBQE_WRAP       (1<<30)     /* Wrap bit */
+#define GEM_TBQE_RETRY_EXC  (1<<29)     /* Retry limit exceeded. */
+#define GEM_TBQE_URUN       (1<<28)     /* Transmit underrun occurred. */
+#define GEM_TBQE_BUF_EXH    (1<<27)     /* Buffers exhausted mid frame. */
+#define GEM_TBQE_LATE_COL   (1<<26)     /* Late collision. */
+#define GEM_TBQE_NO_CRC     (1<<16)     /* No CRC */
+#define GEM_TBQE_LAST_BUF   (1<<15)     /* Last buffer */
+#define GEM_TBQE_LEN_MASK   (0x3FFF)    /* Mask for length field */
+#define GEM_TX_MAX_LEN      (0x3FFF)    /* Maximum transmit length value */
+#define GEM_TBQE_DUMMY      (0x8000BFFF)/* Dummy value to check for free buffer*/
+/* Receive buffer descriptor status words bit positions. */
+#define GEM_RBQE_BROADCAST  (1<<31)     /* Broadcast frame */
+#define GEM_RBQE_MULTICAST  (1<<30)     /* Multicast hashed frame */
+#define GEM_RBQE_UNICAST    (1<<29)     /* Unicast hashed frame */
+#define GEM_RBQE_EXT_ADDR   (1<<28)     /* External address match */
+#define GEM_RBQE_SPEC_MATCH (1<<27)     /* Specific address matched */
+#define GEM_RBQE_SPEC_BASE  (25)        /* Pos for base of specific match */
+#define GEM_RBQE_SPEC_MAT1  (1<<(RBQE_SPEC_BASE + 1))
+#define GEM_RBQE_SPEC_MAT0  (1<<RBQE_SPEC_BASE)
+#define GEM_RBQE_TYPE_MATCH (1<<24)     /* Type ID matched */
+#define GEM_RBQE_TYPE_BASE  (22)        /* Position for base of type id match */
+#define GEM_RBQE_TYPE_MAT1  (1<<(RBQE_TYPE_BASE + 1))
+#define GEM_RBQE_TYPE_MAT0  (1<<RBQE_TYPE_BASE)
+#define GEM_RBQE_VLAN       (1<<21)     /* VLAN tagged */
+#define GEM_RBQE_PRIORITY   (1<<20)     /* Priority tagged */
+#define GEM_RBQE_VLAN_BASE  (17)        /* Position for base of VLAN priority */
+#define GEM_RBQE_VLAN_P2    (1<<(RBQE_VLAN_BASE+2))
+#define GEM_RBQE_VLAN_P1    (1<<(RBQE_VLAN_BASE+1))
+#define GEM_RBQE_VLAN_P0    (1<<RBQE_VLAN_BASE)
+#define GEM_RBQE_CFI        (1<<16)     /* CFI frame */
+#define GEM_RBQE_EOF        (1<<15)     /* End of frame. */
+#define GEM_RBQE_SOF        (1<<14)     /* Start of frame. */
+#define GEM_RBQE_LEN_MASK   (0x3FFF)    /* Mask for the length field. */
+#define GEM_RBQE_WRAP       (1<<1)      /* Wrap bit.. */
+#define GEM_RBQE_USED       (1<<0)      /* Used bit.. */
+#define GEM_RBQE_ADD_MASK   (0xFFFFFFFC)/* Mask for address */
+
+/* Revision ID Register */
+#define GEM_REV_ID_MODEL_MASK   (0x000F0000)    /* Model ID */
+#define GEM_REV_ID_MODEL_BASE   (16)            /* For Shifting */
+#define GEM_REV_ID_REG_MODEL    (0x00020000)    /* GEM module ID */
+#define GEM_REV_ID_REV_MASK     (0x0000FFFF)    /* Revision ID */
+
+/* Define some memory offsets for easier direct access to memory map. */
+#define GEM_NET_CONTROL         (0x00)
+#define GEM_NET_CONFIG          (0x04)
+#define GEM_NET_STATUS          (0x08)
+#define GEM_USER_IO             (0x0C)
+#define GEM_TX_STATUS           (0x14)
+#define GEM_RX_QPTR             (0x18)
+#define GEM_TX_QPTR             (0x1C)
+#define GEM_RX_STATUS           (0x20)
+#define GEM_IRQ_STATUS          (0x24)
+#define GEM_IRQ_ENABLE          (0x28)
+#define GEM_IRQ_DISABLE         (0x2C)
+#define GEM_IRQ_MASK            (0x30)
+#define GEM_PHY_MAN             (0x34)
+#define GEM_RX_PAUSE_TIME       (0x38)
+#define GEM_TX_PAUSE_QUANT      (0x3C)
+
+#define GEM_HASH_BOT            (0x80)
+#define GEM_HASH_TOP            (0x84)
+#define GEM_LADDR1_BOT          (0x88)
+#define GEM_LADDR1_TOP          (0x8C)
+#define GEM_LADDR2_BOT          (0x90)
+#define GEM_LADDR2_TOP          (0x94)
+#define GEM_LADDR3_BOT          (0x98)
+#define GEM_LADDR3_TOP          (0x9C)
+#define GEM_LADDR4_BOT          (0xA0)
+#define GEM_LADDR4_TOP          (0xA4)
+#define GEM_ID_CHECK1           (0xA8)
+#define GEM_ID_CHECK2           (0xAC)
+#define GEM_ID_CHECK3           (0xB0)
+#define GEM_ID_CHECK4           (0xB4)
+#define GEM_REV_ID              (0xFC)
+
+#define GEM_OCT_TX_BOT          (0x100)
+#define GEM_OCT_TX_TOP          (0x104)
+#define GEM_STATS_FRAMES_TX     (0x108)
+#define GEM_BROADCAST_TX        (0x10C)
+#define GEM_MULTICAST_TX        (0x110)
+#define GEM_STATS_PAUSE_TX      (0x114)
+#define GEM_FRAME64_TX          (0x118)
+#define GEM_FRAME65_TX          (0x11C)
+#define GEM_FRAME128_TX         (0x120)
+#define GEM_FRAME256_TX         (0x124)
+#define GEM_FRAME512_TX         (0x128)
+#define GEM_FRAME1024_TX        (0x12C)
+#define GEM_FRAME1519_TX        (0x130)
+#define GEM_STATS_TX_URUN       (0x134)
+#define GEM_STATS_SINGLE_COL    (0x138)
+#define GEM_STATS_MULTI_COL     (0x13C)
+#define GEM_STATS_EXCESS_COL    (0x140)
+#define GEM_STATS_LATE_COL      (0x144)
+#define GEM_STATS_DEF_TX        (0x148)
+#define GEM_STATS_CRS_ERRORS    (0x14C)
+#define GEM_OCT_RX_BOT          (0x150)
+#define GEM_OCT_RX_TOP          (0x154)
+#define GEM_STATS_FRAMES_RX     (0x158)
+#define GEM_BROADCAST_RX        (0x15C)
+#define GEM_MULTICAST_RX        (0x160)
+#define GEM_STATS_PAUSE_RX      (0x164)
+#define GEM_FRAME64_RX          (0x168)
+#define GEM_FRAME65_RX          (0x16C)
+#define GEM_FRAME128_RX         (0x170)
+#define GEM_FRAME256_RX         (0x174)
+#define GEM_FRAME512_RX         (0x178)
+#define GEM_FRAME1024_RX        (0x17C)
+#define GEM_FRAME1519_RX        (0x180)
+#define GEM_STATS_USIZE_FRAMES  (0x184)
+#define GEM_STATS_EXCESS_LEN    (0x188)
+#define GEM_STATS_JABBERS       (0x18C)
+#define GEM_STATS_FCS_ERRORS    (0x190)
+#define GEM_STATS_LENGTH_ERRORS (0x194)
+#define GEM_STATS_RX_SYM_ERR    (0x198)
+#define GEM_STATS_ALIGN_ERRORS  (0x19C)
+#define GEM_STATS_RX_RES_ERR    (0x1a0)
+#define GEM_STATS_RX_ORUN       (0x1a4)
+
+#define GEM_REG_TOP             (0x23C)
+
+
+/* Define a new type to use that should be unsigned and 32-bits in length.
+ * This is currently supported with 16 and 32-bit architectures of ANSI C, this
+ * may need to be adjusted for other architectures.
+ */
+typedef unsigned long int  UINT_32;
+
+
+/* A new type for a byte definition.  This is an unsigned 8-bit 'char' value. */
+typedef unsigned char BYTE;
+
+
+/* Define some types for using with the HAL.  These types correspond to the
+ * memory map and programming structure of the MAC device.
+ * All structures are 'volatile' to indicate they can be changed by some non-
+ * programming means - i.e. by the hardware itself.  This prevents the compiler
+ * from making false assumptions on how to optimise the code.  Some elements
+ * are also defined as 'const' to enforce some checks on the programmer.  These
+ * are only for register fields that can only be changed by the hardware and are
+ * not writable.
+ */
+
+
+/* The Address organisation for the MAC device.  All addresses are split into
+ * two 32-bit register fields.  The first one (bottom) is the lower 32-bits of
+ * the address and the other field are the high order bits - this may be 16-bits
+ * in the case of MAC addresses, or 32-bits for the hash address.
+ * In terms of memory storage, the first item (bottom) is assumed to be at a
+ * lower address location than 'top'. i.e. top should be at address location of
+ * 'bottom' + 4 bytes.
+ */
+#ifndef __MAC_ADDR_DEF__
+#define __MAC_ADDR_DEF__
+typedef struct {
+   UINT_32  bottom;     /* Lower 32-bits of address. */
+   UINT_32  top;        /* Upper 32-bits of address. */
+} MAC_ADDR;
+#endif
+
+#define MAC_ADDR_LEN 6
+
+
+/* The following is the organisation of the address filters section of the MAC
+ * registers.  The Cadence MAC contains four possible specific address match
+ * addresses, if an incoming frame corresponds to any one of these four
+ * addresses then the frame will be copied to memory.
+ * It is not necessary for all four of the address match registers to be
+ * programmed, this is application dependant.
+ */
+#ifndef __SPEC_ADDR_DEF__
+#define __SPEC_ADDR_DEF__
+typedef struct {
+    MAC_ADDR    one;        /* Specific address register 1. */
+    MAC_ADDR    two;        /* Specific address register 2. */
+    MAC_ADDR    three;      /* Specific address register 3. */
+    MAC_ADDR    four;       /* Specific address register 4. */
+} SPEC_ADDR;
+#endif
+
+/* The set of statistics registers implemented in the Cadence MAC.
+ * The statistics registers implemented are a subset of all the statistics
+ * available, but contains all the compulsory ones.
+ * For full descriptions on the registers, refer to the Cadence MAC programmers
+ * guide or the IEEE 802.3 specifications.
+ */
+typedef struct gem_stats{
+	u32 octets_tx_bot;      /* Lower 32-bits for number of octets tx'd */
+	u32 octets_tx_top;      /* Upper 16-bits for number of octets tx'd */
+	u32 frames_tx;          /* Number of frames transmitted OK */
+	u32 broadcast_tx;       /* Number of broadcast frames transmitted */
+	u32 multicast_tx;       /* Number of multicast frames transmitted */
+	u32 pause_tx;           /* Number of pause frames transmitted. */
+	u32 frame64_tx;         /* Number of 64byte frames transmitted */
+	u32 frame65_127_tx;     /* Number of 65-127 byte frames transmitted */
+	u32 frame128_255_tx;    /* Number of 128-255 byte frames transmitted */
+	u32 frame256_511_tx;    /* Number of 256-511 byte frames transmitted */
+	u32 frame512_1023_tx;   /* Number of 512-1023 byte frames transmitted */
+	u32 frame1024_1518_tx;  /* Number of 1024-1518 byte frames transmitted*/
+	u32 frame1519_tx;       /* Number of frames greater than 1518 bytes tx*/
+	u32 tx_urun;            /* Transmit underrun errors due to DMA */
+	u32 single_col;         /* Number of single collision frames */
+	u32 multi_col;          /* Number of multi collision frames */
+	u32 excess_col;         /* Number of excessive collision frames. */
+	u32 late_col;           /* Collisions occuring after slot time */
+	u32 def_tx;             /* Frames deferred due to crs */
+	u32 crs_errors;         /* Errors caused by crs not being asserted. */
+	u32 octets_rx_bot;      /* Lower 32-bits for number of octets rx'd */
+	u32 octets_rx_top;      /* Upper 16-bits for number of octets rx'd */
+	u32 frames_rx;          /* Number of frames received OK */
+	u32 broadcast_rx;       /* Number of broadcast frames received */
+	u32 multicast_rx;       /* Number of multicast frames received */
+	u32 pause_rx;           /* Number of pause frames received. */
+	u32 frame64_rx;         /* Number of 64byte frames received */
+	u32 frame65_127_rx;     /* Number of 65-127 byte frames received */
+	u32 frame128_255_rx;    /* Number of 128-255 byte frames received */
+	u32 frame256_511_rx;    /* Number of 256-511 byte frames received */
+	u32 frame512_1023_rx;   /* Number of 512-1023 byte frames received */
+	u32 frame1024_1518_rx;  /* Number of 1024-1518 byte frames received*/
+	u32 frame1519_rx;       /* Number of frames greater than 1518 bytes rx*/
+	u32 usize_frames;       /* Frames received less than min of 64 bytes */
+	u32 excess_length;      /* Number of excessive length frames rx */
+	u32 jabbers;            /* Excessive length + crc or align errors. */
+	u32 fcs_errors;         /* Number of frames received with crc errors */
+	u32 length_check_errors;/* Number of frames with incorrect length */
+	u32 rx_symbol_errors;   /* Number of times rx_er asserted during rx */
+	u32 align_errors;       /* Frames received without integer no. bytes */
+	u32 rx_res_errors;      /* Number of times buffers ran out during rx */
+	u32 rx_orun;            /* Receive overrun errors due to DMA */
+	u32 ip_cksum;           /* IP header checksum errors */
+	u32 tcp_cksum;           /* TCP checksum errors */
+	u32 udp_cksum;           /* UDP checksum errors */
+} GEM_STATS; ;
+
+
+/* This is the memory map for the Cadence Enhanced MAC device.
+ * For full descriptions on the registers, refer to the Cadence MAC programmers
+ * guide or the IEEE 802.3 specifications.
+ */
+
+typedef struct gem_reg{
+	u32 net_control;            /* Network control 0x00 */
+	u32 net_config;             /* Network config 0x04 */
+	const u32 net_status; /* Network status, RO, 0x08 */
+	u32 user_io;         /* User IO 0x0C*/
+	const u32 rsvd1;      /* reserved 0x10*/
+	u32 tx_status;              /* Transmit status 0x14 */
+	u32 rx_qptr;                /* Receive queue pointer 0x18 */
+	u32 tx_qptr;                /* Transmit queue pointer 0x1C */
+	u32 rx_status;              /* Receive status 0x20 */
+	u32 irq_status;             /* Interrupt status 0x24 */
+	u32 irq_enable;             /* Interrupt enable 0x28 */
+	u32 irq_disable;            /* Interrupt disable 0x2C */
+	const u32 irq_mask;   /* Interrupt mask, RO, 0x30 */
+	u32 phy_man;                /* PHY management 0x34 */
+	const u32 pause_time; /* Pause time register 0x38 */
+	u32 tx_pause_quant;         /* Transmit pause quantum 0x3C */
+	u32 reserved[16];           /* Reserved */
+	MAC_ADDR hash_addr;             /* Hash address 0x80 - 0x84 */
+	SPEC_ADDR address;              /* Specific addresses 0x88 - 0xA4 */
+	u32 id_check1;              /* Type ID check1 0xA8 */
+	u32 id_check2;              /* Type ID check2 0xAC */
+	u32 id_check3;              /* Type ID check3 0xB0 */
+	u32 id_check4;              /* Type ID check4 0xB4 */
+	u32 rsvd2[17];              /* Reserved */
+	u32 rev_id;                 /* Device Revision ID 0xFC*/
+	struct gem_stats stats;                /* MAC statistics 0x100 - 0x1A4 */
+} GEM_REG;
+
+#define GEMAC_REG_SPACE	sizeof(struct gem_reg)
+#define GEMAC_RMON_LEN (sizeof(struct gem_stats)/sizeof(u32))
+
+
+
+struct gemac_info_struct {
+	unsigned int gemacbaseaddr;
+	unsigned int idmaaddr;
+	unsigned int phyaddr;
+	u32 flags;
+	/*to indicate if gigabit supported or not */
+	u32 phyflags;
+	unsigned int phyregidx;
+};
+
+
+/* This is a structure that will be passed and used for all HAL operations, it
+ * consists of pointers to the various MAC structures such as the MAC register
+ * block and the first descriptor element for the rx and tx buffer queues.
+ * Other internal variables declared for use in function calls and to keep track
+ * of where things are.
+ */
+typedef struct {
+	u32	registers;
+	void	*gemac_baseaddr;
+} GEM_DEVICE;
+
+
+/******************************************************************************/
+/*
+ * Prototypes for functions of HAL
+ */
+/******************************************************************************/
+
+
+/* Re-initialise device and check reset values. */
+int gem_reset(GEM_DEVICE *mac);
+
+/* Device setup. */
+
+void gem_set_loop(GEM_DEVICE *mac, MAC_LOOP gem_loop);
+MAC_LOOP gem_get_loop(GEM_DEVICE *mac);
+
+
+void gem_enable_eam(GEM_DEVICE *mac);
+void gem_disable_eam(GEM_DEVICE *mac);
+
+void gem_enable_fcs_rx(GEM_DEVICE *mac);
+void gem_disable_fcs_rx(GEM_DEVICE *mac);
+
+void gem_enable_1536_rx(GEM_DEVICE *mac);
+void gem_disable_1536_rx(GEM_DEVICE *mac);
+
+void gem_full_duplex(GEM_DEVICE *mac);
+void gem_half_duplex(GEM_DEVICE *mac);
+
+void gem_set_speed(GEM_DEVICE *mac, MAC_SPEED gem_speed);
+MAC_SPEED gem_get_speed(GEM_DEVICE *mac);
+
+void gem_set_ahb_width(GEM_DEVICE *mac, MAC_AHB_WIDTH gem_buswidth);
+MAC_AHB_WIDTH gem_get_ahb_width(GEM_DEVICE *mac);
+
+void gem_set_mdc_div(GEM_DEVICE *mac, MAC_MDC_DIV gem_mdcdiv);
+MAC_MDC_DIV gem_get_mdc_div(GEM_DEVICE *mac);
+
+/* Pause control. */
+void gem_enable_pause_rx(GEM_DEVICE *mac);
+void gem_disable_pause_rx(GEM_DEVICE *mac);
+
+void gem_enable_checksum_offload(GEM_DEVICE *mac);
+void gem_disable_checksum_offload(GEM_DEVICE *mac);
+
+UINT_32 gem_pause_time(GEM_DEVICE *mac);
+
+void gem_enable_pause_cpy(GEM_DEVICE *mac);
+void gem_disable_pause_cpy(GEM_DEVICE *mac);
+
+void gem_send_0q_pause(GEM_DEVICE *mac);
+void gem_send_pause(GEM_DEVICE *mac);
+
+void gem_set_tx_pause_q(GEM_DEVICE *mac, UINT_32 gem_pause);
+UINT_32 gem_get_tx_pause_q(GEM_DEVICE *mac);
+
+
+/* PHY management control. */
+void gem_enable_MDIO(GEM_DEVICE *mac);
+void gem_disable_MDIO(GEM_DEVICE *mac);
+
+int gem_link_status(GEM_DEVICE *mac);
+
+/* Address setup and control. */
+void gem_enable_unicast(GEM_DEVICE *mac);
+void gem_disable_unicast(GEM_DEVICE *mac);
+
+void gem_enable_multicast(GEM_DEVICE *mac);
+void gem_disable_multicast(GEM_DEVICE *mac);
+
+void gem_allow_broadcast(GEM_DEVICE *mac);
+void gem_no_broadcast(GEM_DEVICE *mac);
+
+void gem_enable_copy_all(GEM_DEVICE *mac);
+void gem_disable_copy_all(GEM_DEVICE *mac);
+
+void gem_set_hash(GEM_DEVICE *mac, MAC_ADDR *hash_addr);
+MAC_ADDR gem_get_hash(GEM_DEVICE *mac);
+
+void gem_set_address(GEM_DEVICE *mac, SPEC_ADDR *spec_addr);
+SPEC_ADDR gem_get_address(GEM_DEVICE *mac);
+
+/* Functions to convert between address formats. */
+int gem_enet_addr_byte_mac(BYTE *enet_byte_addr, MAC_ADDR *enet_addr);
+int gem_enet_addr_mac_byte(BYTE *enet_byte_addr, MAC_ADDR *enet_addr);
+
+void gem_set_laddr1(GEM_DEVICE *mac, MAC_ADDR *address);
+void gem_set_laddr2(GEM_DEVICE *mac, MAC_ADDR *address);
+void gem_set_laddr3(GEM_DEVICE *mac, MAC_ADDR *address);
+void gem_set_laddr4(GEM_DEVICE *mac, MAC_ADDR *address);
+void gem_clear_laddr1(GEM_DEVICE *mac);
+void gem_clear_laddr2(GEM_DEVICE *mac);
+void gem_clear_laddr3(GEM_DEVICE *mac);
+void gem_clear_laddr4(GEM_DEVICE *mac);
+
+MAC_ADDR gem_get_laddr1(GEM_DEVICE *mac);
+MAC_ADDR gem_get_laddr2(GEM_DEVICE *mac);
+MAC_ADDR gem_get_laddr3(GEM_DEVICE *mac);
+MAC_ADDR gem_get_laddr4(GEM_DEVICE *mac);
+
+void gem_set_id_check1(GEM_DEVICE *mac, UINT_32 id_check);
+void gem_set_id_check2(GEM_DEVICE *mac, UINT_32 id_check);
+void gem_set_id_check3(GEM_DEVICE *mac, UINT_32 id_check);
+void gem_set_id_check4(GEM_DEVICE *mac, UINT_32 id_check);
+UINT_32 gem_get_id_check1(GEM_DEVICE *mac);
+UINT_32 gem_get_id_check2(GEM_DEVICE *mac);
+UINT_32 gem_get_id_check3(GEM_DEVICE *mac);
+UINT_32 gem_get_id_check4(GEM_DEVICE *mac);
+
+void gem_enable_len_check(GEM_DEVICE *mac);
+void gem_disable_len_check(GEM_DEVICE *mac);
+
+/* Interrupt handling and masking. */
+void gem_set_irq_stat(GEM_DEVICE *mac, UINT_32 irq_status);
+UINT_32 gem_get_irq_stat(GEM_DEVICE *mac);
+
+void gem_enable_irq(GEM_DEVICE *mac, UINT_32 irq_en);
+void gem_mask_irq(GEM_DEVICE *mac, UINT_32 irq_mask);
+UINT_32 gem_get_irq_mask(GEM_DEVICE *mac);
+
+/* Transmit control. */
+int gem_start_tx (GEM_DEVICE *mac);
+void gem_stop_tx(GEM_DEVICE *mac);
+void gem_abort_tx(GEM_DEVICE *mac);
+int gem_restart_tx(GEM_DEVICE *mac);
+int gem_transmitting(GEM_DEVICE *mac);
+UINT_32 gem_get_tx_stat(GEM_DEVICE *mac);
+void gem_reset_tx_stat(GEM_DEVICE *mac, UINT_32 rst_status);
+void gem_reset_tx_q(GEM_DEVICE *mac);
+
+/* Receive control. */
+int gem_enable_rx(GEM_DEVICE *mac);
+void gem_disable_rx(GEM_DEVICE *mac);
+void gem_reset_rx_q(GEM_DEVICE *mac);
+
+int gem_receive_on(GEM_DEVICE *mac);
+UINT_32 gem_get_rx_stat(GEM_DEVICE *mac);
+void gem_reset_rx_stat(GEM_DEVICE *mac, UINT_32 rst_status);
+
+void gem_enable_rx_jmb(GEM_DEVICE *mac);
+void gem_disable_rx_jmb(GEM_DEVICE *mac);
+
+void gem_enable_vlan_only(GEM_DEVICE *mac);
+void gem_disable_vlan_only(GEM_DEVICE *mac);
+
+/* Snapshot of statistic registers */
+void gem_enable_rd_snap(GEM_DEVICE *mac);
+void gem_disable_rd_snap(GEM_DEVICE *mac);
+void gem_take_snap(GEM_DEVICE *mac);
+
+/* Debug options. */
+void gem_stats_wr_en(GEM_DEVICE *mac);
+void gem_stats_wr_off(GEM_DEVICE *mac);
+void gem_stats_inc(GEM_DEVICE *mac);
+void gem_stats_clr(GEM_DEVICE *mac);
+
+void gem_enable_bp(GEM_DEVICE *mac);
+void gem_disable_bp(GEM_DEVICE *mac);
+
+void gem_en_retry_test(GEM_DEVICE *mac);
+void gem_dis_retry_test(GEM_DEVICE *mac);
+
+GEM_STATS gem_get_stats(GEM_DEVICE *mac);
+void gem_set_stats(GEM_DEVICE *mac, GEM_STATS *stats);
+
+/* Generic register access interface. */
+UINT_32 gem_register_rd(GEM_DEVICE *mac, UINT_32 reg_addr);
+int gem_register_wr(GEM_DEVICE *mac, UINT_32 reg_addr, UINT_32 data);
+
+/******************************************************************************/
+
+#define RX_STA_BAD			(1<<0)
+#define RX_STA_VLAN			(1<<1)
+#define RX_STA_BCAST			(1<<7)
+#define RX_STA_MCAST			(1<<8)
+#define RX_STA_IP			(1<<22)
+#define RX_STA_TCP			(1<<23)
+#define RX_STA_UDP			(1<<24)
+#define RX_STA_ERR			(1<<26)
+
+#define RX_CHECK_ERROR		(RX_STA_BAD | RX_STA_ERR)
+#endif /* __GEMAC_H__ */
diff -r e137be04dc4d drivers/net/comcerto/comcerto_idma.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/net/comcerto/comcerto_idma.h	Mon Aug 17 16:45:23 2009 -0500
@@ -0,0 +1,51 @@
+/*
+ *  linux/drivers/net/comcerto/comcerto_idma.h
+ *
+ *  Copyright (C) 2006 Mindspeed Technologies, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef _COMCERTO_IDMA_H
+#define _COMCERTO_IDMA_H
+
+#include <mach/hardware.h>
+
+//************ IDMA registers and masks *****************
+#define EDMA_BASE                               0x010000
+
+
+#define MMEM_START(base)			((u32)base + 0x0000)
+#define MMEM_HEAD(base)				((u32)base + 0x0004)
+#define MMEM_BURST(base)			((u32)base + 0x0008)
+#define MMEM_Control(base)			((u32)base + 0x0010)
+#define MMEM_IRQ_Status(base)			((u32)base + 0x0014)
+#define MMEM_SOFT_RESET(base)			((u32)base + 0x0020)
+
+
+#define EMMM_START(base)			((u32)base + 0x0080)
+#define EMMM_HEAD(base)				((u32)base + 0x0084)
+#define EMMM_BURST(base)			((u32)base + 0x0088)
+#define EMMM_Control(base)			((u32)base + 0x0090)
+#define EMMM_IRQ_Status(base)			((u32)base + 0x0094)
+#define EMMM_SOFT_RESET(base)			((u32)base + 0x00A0)
+
+
+#define	FDESC_ALIGN_BYTES		0x10
+
+
+#define DEFAULT_RX_LOCK			0x8
+#define DEFAULT_TX_LOCK			0x8
+#endif
diff -r e137be04dc4d drivers/net/comcerto/comcerto_mii.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/net/comcerto/comcerto_mii.c	Mon Aug 17 16:45:23 2009 -0500
@@ -0,0 +1,260 @@
+/*
+  *  linux/drivers/net/comcerto/comcerto_mii.c
+  *
+  *  Copyright (C) 2006 Mindspeed Technologies, Inc.
+  *
+  * This program is free software; you can redistribute it and/or modify
+  * it under the terms of the GNU General Public License as published by
+  * the Free Software Foundation; either version 2 of the License, or
+  * (at your option) any later version.
+  *
+  * This 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/kernel.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/unistd.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/spinlock.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/crc32.h>
+#include <linux/mii.h>
+#include <linux/phy.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/uaccess.h>
+#include <mach/comcerto-devices.h>
+
+#include "comcerto_gemac.h"
+#include "comcerto_mii.h"
+
+void comcerto_gem_set_mdc_div(struct comcerto_gmii __iomem *regs, MAC_MDC_DIV gem_mdcdiv)
+{
+	switch (gem_mdcdiv) {
+	case MDC_DIV_8:
+		__raw_writel(__raw_readl(&regs->control) & (~GEM_MDC_DIV2) \
+			& (~GEM_MDC_DIV1) & (~GEM_MDC_DIV0), &regs->control);
+		break;
+	case MDC_DIV_16:
+		__raw_writel((__raw_readl(&regs->control) & (~GEM_MDC_DIV2) & \
+			(~GEM_MDC_DIV1)) | (GEM_MDC_DIV0), &regs->control);
+		break;
+	case MDC_DIV_32:
+		__raw_writel((__raw_readl(&regs->control) & (~GEM_MDC_DIV2) & \
+			(~GEM_MDC_DIV0)) | (GEM_MDC_DIV1), &regs->control);
+		break;
+	case MDC_DIV_48:
+		__raw_writel((__raw_readl(&regs->control) & (~GEM_MDC_DIV2))  | \
+			(GEM_MDC_DIV1) | (GEM_MDC_DIV0) , &regs->control);
+		break;
+	case MDC_DIV_64:
+		__raw_writel((__raw_readl(&regs->control) & (~GEM_MDC_DIV1) & \
+			(~GEM_MDC_DIV0)) | (GEM_MDC_DIV2), &regs->control);
+		break;
+	case MDC_DIV_96:
+		__raw_writel((__raw_readl(&regs->control) & (~GEM_MDC_DIV1)) | \
+			(GEM_MDC_DIV2) | (GEM_MDC_DIV0) , &regs->control);
+		break;
+	case MDC_DIV_128:
+		__raw_writel((__raw_readl(&regs->control) & (~GEM_MDC_DIV0)) | \
+			(GEM_MDC_DIV2) | (GEM_MDC_DIV1), &regs->control);
+		break;
+	case MDC_DIV_224:
+		__raw_writel(__raw_readl(&regs->control) | (GEM_MDC_DIV2) | \
+			(GEM_MDC_DIV1) | (GEM_MDC_DIV0), &regs->control);
+		break;
+	}
+}
+
+
+int comcerto_mdio_write(struct mii_bus *bus, int mii_id, int regnum, u16 value)
+{
+	struct comcerto_gmii __iomem *regs = (void __iomem *)bus->priv;
+	u32 write_data;
+
+	write_data = 0x50020000;
+	write_data |= ((mii_id << 23) | (regnum << 18) | value);
+	__raw_writel(write_data, &regs->phy_man);
+
+	while (!(__raw_readl(&regs->status) & GEM_PHY_IDLE))
+		;
+
+	return 0;
+}
+
+
+int comcerto_mdio_read(struct mii_bus *bus, int mii_id, int regnum)
+{
+	struct comcerto_gmii __iomem *regs = (void __iomem *)bus->priv;
+	u16 value;
+	u32 write_data;
+
+	write_data = 0x60020000;
+	write_data |= ((mii_id << 23) | (regnum << 18));
+	__raw_writel(write_data, &regs->phy_man);
+
+	while (!(__raw_readl(&regs->status) & GEM_PHY_IDLE))
+		;
+
+	value = __raw_readl(&regs->phy_man) & 0xFFFF;
+
+	return value;
+}
+
+
+int comcerto_mdio_reset(struct mii_bus *bus)
+{
+	struct comcerto_gmii __iomem *regs = (void __iomem *)bus->priv;
+	unsigned long bus_id;
+	int res;
+
+	res = strict_strtoul(bus->id, 10, &bus_id);
+	if (res)
+		return res;
+
+	spin_lock_bh(&bus->mdio_lock);
+	*(u32 *)(COMCERTO_BLOCK_RESET_REG) |= GEMAC0_RST << bus_id;
+	udelay(1);
+
+	/* Setup the MII Mgmt clock speed */
+	comcerto_gem_set_mdc_div(regs, MDC_DIV_8);
+
+	/* Reset the management interface */
+	__raw_writel(__raw_readl(&regs->control) | GEM_MDIO_EN, &regs->control);
+
+	/* Wait until the bus is free */
+	while (!(__raw_readl(&regs->status) & GEM_PHY_IDLE))
+		;
+
+	spin_unlock_bh(&bus->mdio_lock);
+
+	return 0;
+}
+
+
+static int comcerto_mdio_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+
+	struct comcerto_mdio_data *pdata = NULL;
+	struct comcerto_gmii __iomem *regs;
+	struct mii_bus *new_bus;
+	struct resource *r;
+	int err = 0;
+
+	if (NULL == dev)
+		return -EINVAL;
+
+	new_bus = mdiobus_alloc();
+	if (!new_bus)
+		return -ENOMEM;
+
+	new_bus->name = "Comcerto MDIO Bus";
+	new_bus->read = &comcerto_mdio_read;
+	new_bus->write = &comcerto_mdio_write;
+	new_bus->reset = &comcerto_mdio_reset;
+	snprintf(new_bus->id, MII_BUS_ID_SIZE, "%x", pdev->id);
+
+	pdata = (struct comcerto_mdio_data *)pdev->dev.platform_data;
+	if (NULL == pdata) {
+		printk(KERN_ERR "comcerto mdio %d: Missing platform data!\n", pdev->id);
+		return -ENODEV;
+	}
+
+	new_bus->phy_mask = pdata->phy_mask;
+	new_bus->irq = pdata->irq;
+	/* we don't have specific mdio irqs */
+	memset(new_bus->irq, 0, 32 * sizeof(int));
+
+	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+	/* Set the PHY base address */
+#if defined(USE_IOREMAP)
+	regs = ioremap(r->start, sizeof(struct comcerto_gmii));
+#else
+	regs  = (void *)APB_VADDR(r->start);
+#endif
+
+	if (NULL == regs) {
+		err = -ENOMEM;
+		goto reg_map_fail;
+	}
+
+	new_bus->priv = (void __force *)regs;
+
+	dev_set_drvdata(dev, new_bus);
+
+	err = mdiobus_register(new_bus);
+
+	if (0 != err) {
+		printk(KERN_ERR "%s: Cannot register as MDIO bus\n",
+				new_bus->name);
+		goto bus_register_fail;
+	}
+
+	return 0;
+
+bus_register_fail:
+	iounmap(regs);
+reg_map_fail:
+	kfree(new_bus);
+
+	return err;
+}
+
+
+int comcerto_mdio_remove(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct mii_bus *bus = dev_get_drvdata(dev);
+
+	mdiobus_unregister(bus);
+
+	dev_set_drvdata(dev, NULL);
+#if defined(USE_IOREMAP)
+	iounmap((void __iomem *)bus->priv);
+#endif
+	bus->priv = NULL;
+	kfree(bus);
+
+	return 0;
+}
+
+/* Structure for a device driver */
+static struct platform_driver comcerto_mdio_driver = {
+	.probe = comcerto_mdio_probe,
+	.remove = comcerto_mdio_remove,
+	.driver	= {
+		.name = "comcerto-mdio",
+	},
+};
+
+int __init comcerto_mdio_init(void)
+{
+	return platform_driver_register(&comcerto_mdio_driver);
+}
+
+void  __exit comcerto_mdio_exit(void)
+{
+	platform_driver_unregister(&comcerto_mdio_driver);
+}
+
+module_init(comcerto_mdio_init);
+module_exit(comcerto_mdio_exit);
diff -r e137be04dc4d drivers/net/comcerto/comcerto_mii.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/net/comcerto/comcerto_mii.h	Mon Aug 17 16:45:23 2009 -0500
@@ -0,0 +1,44 @@
+/*
+  *  linux/drivers/net/comcerto/comcerto_mii.h
+  *
+  *  Copyright (C) 2006 Mindspeed Technologies, Inc.
+  *
+  * This program is free software; you can redistribute it and/or modify
+  * it under the terms of the GNU General Public License as published by
+  * the Free Software Foundation; either version 2 of the License, or
+  * (at your option) any later version.
+  *
+  * This program is distributed in the hope that it will be useful,
+  * but WITHOUT ANY WARRANTY; without even the implied warranty of
+  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  * GNU General Public License for more details.
+  *
+  * You should have received a copy of the GNU General Public License
+  * along with this program; if not, write to the Free Software
+  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+  */
+#ifndef __COMCERTO_MII_H
+#define __COMCERTO_MII_H
+
+
+#define COMCERTO_SUPPORTED (SUPPORTED_10baseT_Half \
+		| SUPPORTED_10baseT_Full \
+		| SUPPORTED_100baseT_Half \
+		| SUPPORTED_100baseT_Full \
+		| SUPPORTED_Autoneg \
+		| SUPPORTED_MII)
+
+/* same registers as GEMAC */
+struct comcerto_gmii {
+	u32 control;            /* Network control 0x00 */
+	u32 config;             /* Network config 0x04 */
+	u32 status; /* Network status, RO, 0x08 */
+	u32 dummy[10];
+	u32 phy_man;                /* PHY management 0x34 */
+};
+
+int comcerto_mdio_read(struct mii_bus *bus, int mii_id, int regnum);
+int comcerto_mdio_write(struct mii_bus *bus, int mii_id, int regnum, u16 value);
+int __init comcerto_mdio_init(void);
+void __exit comcerto_mdio_exit(void);
+#endif
diff -r e137be04dc4d drivers/net/comcerto/comcerto_msp.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/net/comcerto/comcerto_msp.c	Mon Aug 17 16:45:23 2009 -0500
@@ -0,0 +1,446 @@
+/*
+ *  linux/driver/net/comcerto/comcerto_msp.c
+ *
+ *  Copyright (C) 2004,2005 Mindspeed Technologies, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/vmalloc.h>
+#include <linux/interrupt.h>
+#include <linux/sysctl.h>
+#include <linux/proc_fs.h>
+#include <linux/timer.h>
+
+#include <asm/irq.h>
+#include <asm/sizes.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <asm/delay.h>
+
+#include <mach/hardware.h>
+#include <mach/debug.h>
+#include <mach/memory.h>
+
+#include "comcerto_msp.h"
+
+/* Export msp_info address */
+unsigned long SPDRV_ACP_MSP_Phyaddr;
+EXPORT_SYMBOL(SPDRV_ACP_MSP_Phyaddr);
+
+/**
+ * dump_elf_headers -
+ *
+ *
+ */
+static void dump_elf_headers(Elf32_Ehdr *this_elf_header)
+{
+	PDEBUG (MSP_INIT, "ELF_HEADER (%#x)", sizeof(Elf32_Ehdr));
+
+	PDEBUG (MSP_INIT, "File header information (ELF)");
+	PDEBUG (MSP_INIT, "Machine class : %d", this_elf_header->e_ident[EI_CLASS]);
+	PDEBUG (MSP_INIT, "Data encoding: %d", this_elf_header->e_ident[EI_DATA]);
+	PDEBUG (MSP_INIT, "Machine type: %d", this_elf_header->e_machine);
+	PDEBUG (MSP_INIT, "File type: %d", this_elf_header->e_type);
+	PDEBUG (MSP_INIT, "Image Entry point: 0x%08X", this_elf_header->e_entry);
+	PDEBUG (MSP_INIT, "Program header offset: 0x%08X", this_elf_header->e_phoff);
+	PDEBUG (MSP_INIT, "Section header offset: 0x%08X", this_elf_header->e_shoff);
+	PDEBUG (MSP_INIT, "Flags: 0x%08X", this_elf_header->e_flags);
+	PDEBUG (MSP_INIT, "Header size: 0x%04X", this_elf_header->e_ehsize);
+	PDEBUG (MSP_INIT, "Program header entry size: 0x%04X", this_elf_header->e_phentsize);
+	PDEBUG (MSP_INIT, "Program header entries: 0x%04X", this_elf_header->e_phnum);
+	PDEBUG (MSP_INIT, "Section header entry size: 0x%04X", this_elf_header->e_shentsize);
+	PDEBUG (MSP_INIT, "Section header entries: 0x%04X", this_elf_header->e_shnum);
+	PDEBUG (MSP_INIT, "String table section index: 0x%04X", this_elf_header->e_shstrndx);
+}
+
+/**
+ * comcerto_download_elf_image - 
+ *
+ *
+ */
+static int download_elf_image(struct _code_info *code_info)
+{
+	int i;
+	int rc = 0;
+	const char *section_name;
+	Elf32_Ehdr *this_elf_header = (Elf32_Ehdr *)(code_info->code);
+	Elf32_Half number_of_section = this_elf_header->e_shnum;
+	/* pointer to the Section header.  */
+	Elf32_Shdr *this_section_headers = (Elf32_Shdr *) (code_info->code + this_elf_header->e_shoff);
+	Elf32_Off string_section_offset = this_section_headers[this_elf_header->e_shstrndx].sh_offset;
+	u32 checksum_program_addr=0;
+	if (!number_of_section)
+	{
+		PDEBUG(MSP_ERR, "Invalid of section = %d ", number_of_section);
+		rc = -1;
+		goto out;
+	}
+	dump_elf_headers(this_elf_header);
+
+	/* parse all sections */
+	for (i = 0; i < number_of_section; i++)
+	{
+		section_name = code_info->code  + string_section_offset + this_section_headers[i].sh_name;
+		if (!strncmp(section_name, "msp_proc", 8))
+		{
+				code_info->proc_addr = this_section_headers[i].sh_addr;
+				PDEBUG (MSP_INIT, "proc_addr at 0x%08x", code_info->proc_addr);
+				//clean the memory
+				_memset_io(msp_to_virt(this_section_headers[i].sh_addr), 0, this_section_headers[i].sh_size);
+		} 
+		
+		/* retrieve the section name from the ELF buffer */
+		if (!strncmp(section_name, "CHECKSUM", 8))
+		{
+				checksum_program_addr = *((u32 *) (code_info->code + this_section_headers[i].sh_offset));
+				PDEBUG (MSP_INIT, "checksum prog at 0x%08x", checksum_program_addr);
+		} 
+		else if ((this_section_headers[i].sh_flags != SHF_MIPS_ADDR) && 
+		    (this_section_headers[i].sh_flags != 0)) 
+		{
+			/* retrieve the section name from the ELF buffer */
+			
+			if ((this_section_headers[i].sh_type & 3) == SHT_PROGBITS)
+			{
+				PDEBUG (MSP_INIT, "%s section: %d bytes to load at addr:0x%08x from elf offset: %d",
+					section_name,
+					this_section_headers[i].sh_size,
+					this_section_headers[i].sh_addr,
+					this_section_headers[i].sh_offset);
+				
+				memcpy(
+					msp_to_virt(this_section_headers[i].sh_addr),
+					(void*)(code_info->code + this_section_headers[i].sh_offset),
+					this_section_headers[i].sh_size);
+			}
+		}
+	}
+	// every think weent OK
+	code_info->program_addr = this_elf_header->e_entry;
+	
+	
+out:
+	return rc;
+}
+
+void msp_set_resethandler(struct comcerto_msp *msp, unsigned long base_address)
+{
+	__raw_writel(0xE59FF018, msp->vectors_base);	/* LDR PC, [PC,#20] */
+	__raw_writel(base_address, msp->vectors_base + 0x00000020);	/* jump to msp start */
+}
+
+
+int msp_ready(struct comcerto_msp *msp, u32 timeout)
+{
+	u32 count = 0;
+
+	PDEBUG(MSP_FUNC, "msp_ready()");
+
+	/* timeout is passed in ms, set it in jiffies */
+	timeout = (timeout * HZ) / 1000;
+	
+	while (!msp->info || !msp->info->ready) {
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		schedule_timeout(1);
+
+		if (++count >= timeout) {
+			printk(KERN_ERR "Didn't receive ack from MSP\n");
+			msp->info = NULL;
+			goto err;
+		}
+	}
+
+	printk(KERN_INFO "MSP is running\n");
+
+	return 1;
+
+ err:
+	return 0;
+}
+
+
+int msp_start(struct comcerto_msp *msp)
+{
+	PDEBUG(MSP_FUNC, "msp_start()");
+
+	msp->state = MSP_STARTING;
+	msp->alert_seen = 0;
+#if (!defined(CONFIG_ARCH_M821XX) && !defined(CONFIG_ARCH_M822XX))
+	__raw_writel(__raw_readl(COMCERTO_ASA_TC_CR_REG) | ASA_TC_REQARM1EN, COMCERTO_ASA_TC_CR_REG);
+	__raw_writel(__raw_readl(COMCERTO_ASA_ARAM_TC_CR_REG) | ASA_TC_REQARM1EN, COMCERTO_ASA_ARAM_TC_CR_REG);
+#endif	
+	__raw_writel(0x80000000, COMCERTO_INTC_ARM1_CONTROL_REG);
+
+	if (!msp_ready(msp, 8000)) {
+		printk(KERN_ERR "start_ved: failed to start the MSP\n");
+		goto err;
+	}
+
+	//start timer
+	init_timer(&msp->timer_expire);
+	msp->timer_expire.function = msp_poll;
+	msp->timer_expire.expires = jiffies+((10*HZ)/10); // 1second
+	msp->timer_expire.data = (unsigned long) msp;
+	add_timer(&msp->timer_expire);
+	msp->state = MSP_RUNNING;
+
+	// Copy MSP/ACP shared mem location for sp_driver
+	SPDRV_ACP_MSP_Phyaddr = msp->info->SPDRV_ACP_MSP_Phyaddr;
+
+	return 0;
+ err:
+ 	return -1;
+}
+
+void msp_alert(struct comcerto_msp *msp)
+{
+	struct AlertType *alert;
+	struct MSP_STACK_FRAME *frame;
+	unsigned int *sp;
+	
+	if (msp->info) {
+		while (msp->info->AlertNumber != msp->alert_seen) {
+			alert = (struct AlertType *) msp_to_virt(msp->info->saveAlert) + msp->alert_seen;
+			msp->alert_seen++;
+			printk(KERN_CRIT "MSP alert : type : 0x%x, channel=%d \n", alert->type & 0xff, alert->channel);
+			printk(KERN_CRIT "MSP alert : link register : 0x%X, ID =0x%X \n", alert->abort_lr, alert->UniqueID);
+			if (alert->type & 0x8000) {
+				frame = (struct MSP_STACK_FRAME *)msp_to_virt(msp->info->AlertFrame);
+				sp = (unsigned int *)msp_to_virt(frame->sp);
+				sp++;
+				printk(KERN_CRIT "MSP alert : \n");
+				printk(KERN_CRIT "r0 = 0x%08X, r1 = 0x%08X, r2 = 0x%08X, r3 = 0x%08X \n", frame->r0, frame->r1, frame->r2, frame->r3);
+				printk(KERN_CRIT "r4 = 0x%08X, r5 = 0x%08X, r6 = 0x%08X, r7 = 0x%08X \n", frame->r4, frame->r5, frame->r6, frame->r7);
+				printk(KERN_CRIT "r8 = 0x%08X, r9 = 0x%08X, r10 = 0x%08X, r11 = 0x%08X \n", frame->r8, frame->r9, frame->r10,
+				       frame->r11);
+				printk(KERN_CRIT "r12 = 0x%08X, sp = 0x%08X, lr = 0x%08X, \n", frame->r12, frame->sp, frame->lr);
+				printk(KERN_CRIT "sp dump : \n");
+				printk(KERN_CRIT "0x%08X, 0x%08X, 0x%08X, 0x%08X \n", *sp, *(sp + 1), *(sp + 2), *(sp + 3));
+				sp += 4;
+				printk(KERN_CRIT "0x%08X, 0x%08X, 0x%08X, 0x%08X \n", *sp, *(sp + 1), *(sp + 2), *(sp + 3));
+				sp += 4;
+				printk(KERN_CRIT "0x%08X, 0x%08X, 0x%08X, 0x%08X \n", *sp, *(sp + 1), *(sp + 2), *(sp + 3));
+				sp += 4;
+				printk(KERN_CRIT "0x%08X, 0x%08X, 0x%08X, 0x%08X \n ", *sp, *(sp + 1), *(sp + 2), *(sp + 3));
+				sp += 4;
+				printk(KERN_CRIT "0x%08X, 0x%08X, 0x%08X, 0x%08X \n", *sp, *(sp + 1), *(sp + 2), *(sp + 3));
+				sp += 4;
+				printk(KERN_CRIT "0x%08X, 0x%08X, 0x%08X, 0x%08X \n", *sp, *(sp + 1), *(sp + 2), *(sp + 3));
+				sp += 4;
+				printk(KERN_CRIT "0x%08X, 0x%08X, 0x%08X, 0x%08X \n", *sp, *(sp + 1), *(sp + 2), *(sp + 3));
+				sp += 4;
+				printk(KERN_CRIT "0x%08X, 0x%08X, 0x%08X, 0x%08X \n", *sp, *(sp + 1), *(sp + 2), *(sp + 3));
+				sp += 4;
+			}
+		}
+	}
+}
+void msp_poll(unsigned long arg)
+{
+	struct comcerto_msp *msp = (struct comcerto_msp *) arg;
+
+	//check for Alerts
+	msp_alert(msp);
+
+	switch (msp->state)
+	{
+		case MSP_RESETTING:
+		case MSP_RESET:
+		case MSP_STARTING:
+		case MSP_CRASHED:
+			break;
+		case MSP_RUNNING:
+			{
+				if(msp->info->Heartbeat == 0)
+				{
+					printk(KERN_CRIT "MSP Heart beat Failure \n");
+					msp_alert(msp);
+					msp->state = MSP_CRASHED;
+				}
+				msp->info->Heartbeat= 0;
+			}
+			break;
+	}
+	msp->timer_expire.expires = jiffies+((10*HZ)/10); // 1second
+	add_timer(&msp->timer_expire);
+}
+
+int comcerto_download_to_msp(struct comcerto_msp *msp)
+{
+	struct _code_info *code_info = &msp->code_info;
+#if defined(CONFIG_ARCH_M829XX) || defined(CONFIG_ARCH_M821XX) || defined(CONFIG_ARCH_M828XX) || defined(CONFIG_ARCH_M822XX)
+	if(download_elf_image(code_info)==0)
+	{
+		//download went OK retrieve information
+		msp->info = msp_to_virt(msp->code_info.proc_addr);
+		return 0;
+	}
+	return -1;
+#else
+#error "not supported yet!!"
+#endif
+}
+
+int comcerto_start_msp(struct comcerto_msp *msp)
+{
+	struct _code_info *code_info = &msp->code_info;
+	msp_set_resethandler(msp, code_info->program_addr);
+	return msp_start(msp);
+}
+
+void comcerto_stop_msp(struct comcerto_msp *msp)
+{
+	__raw_writel(0, COMCERTO_INTC_ARM1_CONTROL_REG);
+	/* reset all dma peripherals */
+#if 0
+	/* TDM */
+	__raw_writel(0, IO_ADDRESS(COMCERTO_TDMA_BASE) + 0x0004);
+	__raw_writel(0, IO_ADDRESS(COMCERTO_TDMA_BASE) + 0x0008);
+	__raw_writel(0, IO_ADDRESS(COMCERTO_TDMA_BASE) + 0x2004);
+	__raw_writel(0, IO_ADDRESS(COMCERTO_TDMA_BASE) + 0x2008);
+	__raw_writel(0, IO_ADDRESS(COMCERTO_TDMA_BASE) + 0x4004);
+	__raw_writel(0, IO_ADDRESS(COMCERTO_TDMA_BASE) + 0x4008);
+	__raw_writel(0, IO_ADDRESS(COMCERTO_TDMA_BASE) + 0x8004);
+	__raw_writel(0, IO_ADDRESS(COMCERTO_TDMA_BASE) + 0x8008);
+
+	/* SPU */
+	__raw_writel(0, IO_ADDRESS(COMCERTO_SMC_BASE) + 0x10);
+	__raw_writel(1, IO_ADDRESS(COMCERTO_SMC_BASE) + 0x64);
+	__raw_writel(1, IO_ADDRESS(COMCERTO_SMC_BASE) + 0x64);
+#endif
+	msp->state = MSP_RESET;
+	del_timer(&msp->timer_expire);
+}
+
+/*
+*
+*	proc filesystem
+*/
+#if 0
+static char *RevName[] = {
+	"RevA",
+	"RevB",
+	"RevD",
+	"RevE",
+	"RevC"
+};
+
+static char *DashName[] = {
+	"-11",
+	"-12",
+	"-15",
+	"-16",
+	"-14"
+};
+
+static char *DeviceName[] = {
+	"M82803",
+	"M82801",
+	"M82805",
+	"M82810",
+	"M82815",
+	"M82820"
+};
+
+static int msp_proc_info(char *page, char **start, off_t off, int count, int *eof, void *data);
+static int msp_sysctl_ipoffload_enable(ctl_table * ctl, int write, struct file *filp, void __user * buffer, size_t * lenp, loff_t *ppos);
+
+static ctl_table msp_conf_table[] = {
+	{
+	 .ctl_name = 1,
+	 .procname = "msp_state",
+	 .data = &msp.state,
+	 .maxlen = sizeof(int),
+	 .mode = 0444,
+	 .proc_handler = &proc_dointvec},
+	{ .ctl_name = 0 }
+};
+
+static ctl_table msp_root_table[] = {
+	{
+	 .ctl_name = 254,
+	 .procname = "msp",
+	 .maxlen = 0,
+	 .mode = 0555,
+	 .child = msp_conf_table,
+	 },
+	{ .ctl_name = 0 }
+};
+
+
+static int msp_proc_info(char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+	int len = 0;
+	struct comcerto_msp *msp = (comcerto_msp *) data;
+	struct msp_info *info=msp->info;
+	
+	if (info == NULL) {
+		sprintf(page + len, "no MSP info available !\n");
+		return 0;
+	}
+
+	if (info->Device >= Monet_data)
+		len += sprintf(page + len, "Device : %s%s\n", DeviceName[info->Device - Monet_data], DashName[info->Revision]);
+	else if (info->Device <= Chagall_8)
+		len += sprintf(page + len, "Device : M825xx\n");
+
+	if (info->Revision < 5)
+		len += sprintf(page + len, "Revision : %s\n", RevName[info->Revision]);
+
+	len += sprintf(page + len, "MSP version: %s\n", info->msp_version);
+	len += sprintf(page + len, "SPU version: %s\n", info->spu_version);
+	len += sprintf(page + len, "ERAM size: %ld\n", info->ERAMsize);
+	len += sprintf(page + len, "IRAM size: %ld\n", info->IRAMsize);
+	len += sprintf(page + len, "ARAM size: %ld\n", info->ARAMsize);
+
+	len += sprintf(page + len, "MSP freq : %d Mhz \n", info->ARMfreq);
+	len += sprintf(page + len, "AMBA bus freq : %d Mhz \n", info->AMBAfreq);
+	len += sprintf(page + len, "SPU freq : %d Mhz \n", info->SPUfreq);
+
+	return len;
+}
+
+int __init msp_init_proc(struct comcerto_msp *msp)
+{
+	msp->sysctl_header = register_sysctl_table(msp_root_table, 0);
+	if (!msp->sysctl_header) {
+		printk(KERN_ERR "MSP: unable to register sysctl table\n");
+		goto err0;
+	}
+	
+	if (!create_proc_read_entry("msp", 0, 0, msp_proc_info, msp)) {
+		printk(KERN_ERR "MSP: unable to create proc entry\n");
+		goto err1;
+	}
+	
+	return 0;
+
+   err1:
+	unregister_sysctl_table(msp->sysctl_header);
+
+   err0:
+	return -1;
+}
+
+void msp_cleanup_proc(struct comcerto_msp *msp)
+{
+	remove_proc_entry("msp", NULL);
+
+	unregister_sysctl_table(msp->sysctl_header);
+}
+#endif
diff -r e137be04dc4d drivers/net/comcerto/comcerto_msp.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/net/comcerto/comcerto_msp.h	Mon Aug 17 16:45:23 2009 -0500
@@ -0,0 +1,204 @@
+/*
+ *  linux/drivers/net/comcerto/comcerto_msp.h
+ *
+ *  Copyright (C) 2006 Mindspeed Technologies, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef __COMCERTO_MSP_H__
+#define __COMCERTO_MSP_H__
+
+#include <linux/firmware.h>
+#include <linux/elf.h>
+#include <mach/debug.h>
+#include <linux/netdevice.h>
+
+/* copied from usr/include/elf.h */
+#ifndef _ELF_H
+#define	_ELF_H 1
+#define EM_ARM		40		/* ARM */
+
+#define SHF_MIPS_ADDR 0x40000000
+#define SHT_PROGBITS 1
+#endif
+
+enum MSP_states {
+	MSP_RESETTING = 0,
+	MSP_RESET,
+	MSP_STARTING,
+	MSP_RUNNING,
+	MSP_CRASHED
+};
+
+#if 0
+struct _AIF_HEADER {
+	u32 BL_DecompressCode;	/*00    */
+	u32 BL_SelfRelocCode;	/*04    */
+	u32 BL_DbgInitZeroInit;	/*08    */
+	u32 EntryPointOffset;	/*0C    */
+	u32 ProgramExitInstr;	/*10    */
+	u32 ImageReadOnlySize;	/*14    in bytes */
+	u32 ImageReadWriteSize;	/*18    in bytes */
+	u32 ImageDebugSize;	/*1C    */
+	u32 ImageZeroInitSize;	/*20    */
+	u32 ImageDebugType;	/*24    */
+	u32 ImageBase;	/*28    32 bit address */
+	u32 WorkSpace;	/*2C    */
+	u32 AddressMode;	/*30    */
+	u32 DataBase;		/*34    32 bit address */
+	u32 FirstFatOffset;	/*38    byte offset in file */
+	u32 Reserved2;	/*3C    */
+	u32 DebugInitInstr;	/*40    */
+	u32 ZeroInitCode[15];	/*44...80 */
+};
+
+struct _FAT_AIF_HEADER {
+	u32 NextFatOffset;	/*byte offset in file */
+	u32 LoadAddress;	/*32 bit address */
+	u32 Size;		/*in bytes */
+	u8 region_name[32];
+};
+#endif
+
+enum DevName {
+	Chagall_64 = 0,		// Chagall 64 channels (M82530-xx)
+	Chagall_32,		// Chagall 32 channels (M82520-xx)
+	Chagall_16,		// Chagall 16 channels (M82510-xx)
+	Chagall_8,		// Chagall 8 channels (M82505-xx)
+	Miro_HP,		// Miro Communications Convergence Processor (HP Process) (M82610-16P, -14R, -14)
+	Miro_Anyport,		// Miro (RAS/Voice) (M82600-xx)
+	Miro_Wireless,		// Miro Wireless Access Processor (M82620-xx)
+	Miro_LV,		// Miro Communications Convergence Processor (1st version assembled) (LV Process) (HP prototypes) (M82610-11P15P)
+	Miro_Mini_64,		// This is not a real bonding option
+	Miro_Mini_32,		// This is not a real bonding option
+	Miro_Mini_16,		// This is not a real bonding option
+	Miro_Mini_8,		// This is not a real bonding option
+	Picasso,		// Picasso ===> 12
+	Chagall2_32,		// Chagall2_32 - M82515 (monet chip, but functions like a chagall device)
+	Chagall2_16,		// Chagall2_16 - M82511 (monet chip, but functions like a chagall device)
+	Chagall2_8,		// Chagall2_8  - M82506  (monet chip, but functions like a chagall device)
+	Chagall2_4,		// Chagall2_4  - M82501  (monet chip, but functions like a chagall device)
+	Slave_Chagall2_32,	// This is not a real bonding option   ===> 17
+	Slave_Chagall2_16,	// This is not a real bonding option
+	Slave_Chagall2_8,	// This is not a real bonding option
+	Slave_Chagall2_4,	// This is not a real bonding option
+	Chagall2_24,		// Chagall2_24 - M82514 (monet chip, but functions like a chagall device) ====> 21
+	Slave_Chagall2_24,	// This is not a real bonding option
+	Chagall_48,		//  Chagall 48 channels (M82524 -xx)   === > 23
+	Miro_Mini_48,		// This is not a real bonding option
+	//
+	//device types from 25 to 56 currently free
+	//
+	Monet_data = 57,	// Monet data only (M82803-xx)
+	Monet_16,		// Monet 16 channels (M82801-xx)
+	Monet_32,		// Monet 32 channels (M82805-xx)
+	Monet_48,		// Monet 48 channels (M82810-xx)
+	Monet_64,		// Monet 64 channels (M82815-xx)
+	Monet_64HP,		// Monet 64 high performace channels (M82820-xx)
+};
+
+struct MSP_STACK_FRAME {
+	unsigned int r0;
+	unsigned int r1;
+	unsigned int r2;
+	unsigned int r3;
+	unsigned int r4;
+	unsigned int r5;
+	unsigned int r6;
+	unsigned int r7;
+	unsigned int r8;
+	unsigned int r9;
+	unsigned int r10;
+	unsigned int r11;
+	unsigned int r12;
+	unsigned int sp;
+	unsigned int lr;
+	unsigned int pc;
+};
+
+struct AlertType {
+	unsigned short type;
+	unsigned short channel;
+	unsigned short UniqueID;
+	unsigned short filler1;
+	unsigned int abort_lr;
+	unsigned int filler2;
+};
+
+struct _code_info {
+	const u8 *code;
+	u32 size;
+
+	u32 checksum_program_addr;
+	u32 program_addr;
+	u32 proc_addr;
+	u32 checksum;
+};
+
+struct msp_info {
+	unsigned long ABI_rev;
+	volatile unsigned long lock;
+	unsigned long Device;
+	unsigned long Revision;
+	char msp_version[32];
+	char spu_version[16];
+//
+	unsigned long CSPtoMSPQueuePhyaddr;
+	unsigned long MSPtoCSPQueuePhyaddr;
+	unsigned long SMRXCSPhyaddr;
+	unsigned long SMTXCSPhyaddr;
+	unsigned long SPDRV_ACP_MSP_Phyaddr;
+//
+	unsigned long ERAMsize;
+	unsigned long ARAMsize;
+	unsigned long IRAMsize;
+	unsigned short ARMfreq;
+	unsigned short AMBAfreq;
+	unsigned short SPUfreq;
+	unsigned long VOIP_ipaddr;
+	volatile unsigned int IPoffload;
+	volatile unsigned int ready;
+	volatile unsigned int Heartbeat;
+	volatile unsigned int AlertNumber;
+	volatile unsigned long AlertFrame;
+	volatile unsigned long saveAlert;
+};
+
+
+struct comcerto_msp
+{
+	int alert_seen;
+	unsigned long last_tick;
+
+	int watchdog_disable;
+	int ipoffload_enable;
+	int ipoffload_suspend;
+
+	int state;
+
+	volatile struct msp_info *info;
+	struct _code_info code_info;
+	struct sk_buff_head MSP_list;
+	struct timer_list timer_expire;
+	struct ctl_table_header *sysctl_header;
+	void* __iomem vectors_base;
+};
+
+int comcerto_download_to_msp(struct comcerto_msp *msp);
+int comcerto_start_msp(struct comcerto_msp *msp);
+void comcerto_stop_msp(struct comcerto_msp *msp);
+void msp_poll(unsigned long arg);
+#endif
diff -r e137be04dc4d drivers/net/comcerto/comcerto_smi_lock.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/net/comcerto/comcerto_smi_lock.h	Mon Aug 17 16:45:23 2009 -0500
@@ -0,0 +1,65 @@
+/*
+ *  linux/drivers/net/comcerto/comcerto_smi_lock.h
+ *
+ *  Copyright (C) 2006 Mindspeed Technologies, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef __COMCERTO_SMI_LOCK_H__
+#define __COMCERTO_SMI_LOCK_H__
+
+/*
+ *	SWPB() for locking.
+ *	*bytep must be NCNB.
+ *	On a non-ARM, you'll need to do something else.
+ */
+static inline unsigned char SWPB(u8 v, volatile u8 * bytep)
+{
+	unsigned char ret;
+	__asm__ __volatile__("swpb %0, %1, [%2]":"=&r"(ret)
+			     :"r"(v), "r"(bytep)
+			     :"memory");
+	return (ret);
+}
+
+/*
+ *	SFL_lock()
+ *	Spin to lock. Always succeeds.
+ */
+static inline unsigned long SFL_lock(volatile void *lockp)
+{
+	unsigned char t;
+
+	do {
+		t = SWPB(0xFF, (volatile unsigned char *)lockp);
+	} while (t == 0xff);
+
+	return t;
+}
+
+/*
+ *	SFL_unlock()
+ *	Unlock. Always succeeds.
+ */
+static inline void SFL_unlock(volatile void *lockp)
+{
+	unsigned char t;
+
+	t = SWPB(0x00, (volatile unsigned char *)lockp);
+
+}
+
+#endif /* __COMCERTO_SMI_LOCK_H__ */
diff -r e137be04dc4d drivers/net/comcerto/comcerto_smi_part.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/net/comcerto/comcerto_smi_part.c	Mon Aug 17 16:45:23 2009 -0500
@@ -0,0 +1,56 @@
+/*
+ *  linux/drivers/net/comcerto/comcerto_smi_part.c
+ *
+ *  Copyright (C) 2006 Mindspeed Technologies, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <asm/io.h>
+#include <mach/hardware.h>
+#include <mach/debug.h>
+
+#include "comcerto_smi_part.h"
+#include "comcerto_smi_lock.h"
+
+void *SFL_alloc_part(struct FASTPART *fp)
+{
+	void *v;
+//	PDEBUG(SMI_PART, "SFL_alloc_part: partition=%x\n", (unsigned long) fp);
+
+	SFL_lock(&fp->lock);
+
+	if (fp->freeblk) {
+		v = msp_to_virt(fp->freeblk);
+		fp->freeblk = __raw_readl(v);
+	} else
+		v = NULL;
+
+	SFL_unlock(&fp->lock);
+
+	return v;
+}
+
+void SFL_free_part(struct FASTPART *fp, void *v)
+{
+//	PDEBUG(SMI_PART, "SFL_free_part: partition=%x, %x\n", (unsigned long) fp, (unsigned long)v);
+
+	SFL_lock(&fp->lock);
+
+	__raw_writel(fp->freeblk, v);
+	fp->freeblk = virt_to_msp(v);
+
+	SFL_unlock(&fp->lock);
+}
diff -r e137be04dc4d drivers/net/comcerto/comcerto_smi_part.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/net/comcerto/comcerto_smi_part.h	Mon Aug 17 16:45:23 2009 -0500
@@ -0,0 +1,39 @@
+/*
+ *  linux/drivers/net/comcerto/comcerto_smi_part.h
+ *
+ *  Copyright (C) 2006 Mindspeed Technologies, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef __COMCERTO_SMI_PART_H
+#define __COMCERTO_SMI_PART_H
+
+struct FASTPART {
+	volatile unsigned long freeblk;
+	unsigned long storage;
+	u32 blksz;
+	u32 blkcnt;
+	u32 *end_of_storage;
+	volatile u8 lock;
+	u8 reserved1;
+	u16 reserved2;
+	u32 freecnt;
+};
+
+void *SFL_alloc_part(struct FASTPART *fp);
+void SFL_free_part(struct FASTPART *fp, void *v);
+
+#endif /* __COMCERTO_SMI_PART_H */
diff -r e137be04dc4d drivers/net/comcerto/comcerto_smi_queue.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/net/comcerto/comcerto_smi_queue.c	Mon Aug 17 16:45:23 2009 -0500
@@ -0,0 +1,45 @@
+/*
+ *  linux/drivers/net/comcerto/comcerto_smi_queue.c
+ *
+ *  Copyright (C) 2006 Mindspeed Technologies, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This 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/kernel.h>
+#include <asm/io.h>
+#include <mach/hardware.h>
+#include <mach/debug.h>
+
+#include "comcerto_smi_queue.h"
+
+struct FASTQUEUE *smi_queue_init(struct SMIQUEUE *psmiq, u32 physaddr, void (*genint_cpu0) (void))
+{
+	struct FASTQUEUE *fpq;
+
+	//fpq = (struct FASTQUEUE *) msp_to_virt(physaddr);
+	fpq = (struct FASTQUEUE *) aram_to_virt(physaddr);
+
+	PDEBUG(SMI_PART, "Comcerto SMI: fpq(PA): %#lx", (unsigned long)physaddr);
+	PDEBUG(SMI_PART, "Comcerto SMI: fpq(VA): %#lx", (unsigned long)fpq);
+
+	if (fpq) {
+		psmiq->fpq = fpq;
+		psmiq->storage_virt = msp_to_virt(fpq->storage);
+		psmiq->genint_cpu0 = genint_cpu0;
+	}
+
+	return (fpq);
+}
diff -r e137be04dc4d drivers/net/comcerto/comcerto_smi_queue.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/net/comcerto/comcerto_smi_queue.h	Mon Aug 17 16:45:23 2009 -0500
@@ -0,0 +1,108 @@
+/*
+ *  linux/drivers/net/comcerto/comcerto_smi_queue.h
+ *
+ *  Copyright (C) 2006 Mindspeed Technologies, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef __COMCERTO_SMI_QUEUE_H
+#define __COMCERTO_SMI_QUEUE_H
+
+#include <linux/types.h>	/* size_t */
+
+#include <asm/io.h>
+#include <mach/hardware.h>
+
+#include "comcerto_smi_lock.h"
+
+/* shared structure (can't be modified without MSP modification) */
+struct FASTQUEUE {
+	unsigned long storage;
+	u32 sema;
+	volatile u16 get;
+	volatile u16 put;
+	u16 size;
+	u16 lock;
+};
+
+/* private structure (CSP only) */
+struct SMIQUEUE {
+	u32 PtrOffset;			/* IRAM ptr offset to Queue pointer */
+	unsigned long *storage_virt;	/* Virtual Address of fpq->storage */
+	struct FASTQUEUE *fpq;			/* queue pointer */
+	void (*genint_cpu0) (void);	/* CSP to MSP generate interrupt function */
+};
+
+struct FASTQUEUE *smi_queue_init(struct SMIQUEUE *psmiq, u32 PtrOffset, void (*genint_cpu0) (void));
+
+static inline void SFL_genint_cpu0(void)
+{
+	__raw_writel((1 << IRQ_PTP1), COMCERTO_INTC_SET_STATUS_REG_0);
+}
+
+static inline int SFL_enqueue(struct SMIQUEUE *psmiq, void *vaddr)
+{
+	u16 put;
+	struct FASTQUEUE *fpq = psmiq->fpq;
+	int rc = 0;
+
+	SFL_lock(&fpq->lock);
+	put = fpq->put;
+
+	if (++put >= fpq->size)
+		put = 0;
+
+	if (put != fpq->get) {
+		rc = 1;
+		psmiq->storage_virt[fpq->put] = (unsigned long)virt_to_msp(vaddr);
+		fpq->put = put;
+		if (psmiq->genint_cpu0)
+			psmiq->genint_cpu0();
+	}
+
+	SFL_unlock(&fpq->lock);
+
+	return rc;
+}
+
+static inline void *SFL_dequeue(struct SMIQUEUE *psmiq)
+{
+	struct FASTQUEUE *fpq = psmiq->fpq;
+	u32 get;
+	void *v;
+
+	SFL_lock(&fpq->lock);
+	get = fpq->get;
+
+	if (fpq->put != get) {
+		v = msp_to_virt(psmiq->storage_virt[get++]);
+		if (get == fpq->size)
+			get = 0;
+		fpq->get = get;
+	} else
+		v = NULL;
+
+	SFL_unlock(&fpq->lock);
+
+	return v;
+}
+
+static inline int SFL_queue_empty(struct FASTQUEUE *fpq)
+{
+	return (fpq->get == fpq->put);
+}
+
+#endif /* __COMCERTO_SMI_QUEUE_H */
diff -r e137be04dc4d drivers/net/comcerto/comcerto_sysfs.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/net/comcerto/comcerto_sysfs.c	Mon Aug 17 16:45:23 2009 -0500
@@ -0,0 +1,613 @@
+/*
+ * drivers/net/comcerto/ comcerto_sysfs.c
+ *
+  *  Copyright (C) 2006 Mindspeed Technologies, Inc.
+  *
+  * This program is free software; you can redistribute it and/or modify
+  * it under the terms of the GNU General Public License as published by
+  * the Free Software Foundation; either version 2 of the License, or
+  * (at your option) any later version.
+  *
+  * This 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/kernel.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/unistd.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/etherdevice.h>
+#include <linux/spinlock.h>
+#include <linux/mm.h>
+#include <linux/device.h>
+
+#include "comcerto_eth.h"
+#include "comcerto_gemac.h"
+
+extern void comcerto_emac_restart(struct eth_priv *priv);
+extern void comcerto_emac_restart_tx(struct eth_priv *priv);
+extern int comcerto_eth_open(struct net_device *dev);
+extern int comcerto_eth_close(struct net_device *dev);
+extern void comcerto_eth_enable_fast_path(struct net_device *dev,
+		unsigned short state);
+
+static int align_count;
+
+#define COMCERTO_ATTR(_name) \
+static ssize_t comcerto_show_##_name(struct device *dev, \
+	 struct device_attribute *attr, char *buf); \
+static ssize_t comcerto_set_##_name(struct device *dev, \
+		struct device_attribute *attr, \
+		const char *buf, size_t count); \
+static DEVICE_ATTR(_name, 0644, comcerto_show_##_name, comcerto_set_##_name)
+
+#define COMCERTO_CREATE_FILE(_dev, _name) \
+	device_create_file(&_dev->dev, &dev_attr_##_name)
+
+#if 0
+#define COMCERTO_ATTR(_name) \
+static ssize_t comcerto_show_##_name(struct class_device *cdev, char *buf); \
+static ssize_t comcerto_set_##_name(struct class_device *cdev, \
+		const char *buf, size_t count); \
+static CLASS_DEVICE_ATTR(_name, 0644, comcerto_show_##_name, \
+		comcerto_set_##_name)
+
+#define COMCERTO_CREATE_FILE(_dev, _name) \
+	class_device_create_file(&_dev->class_dev, &class_device_attr_##_name)
+#endif
+
+COMCERTO_ATTR(rx_lock_size);
+COMCERTO_ATTR(tx_lock_size);
+COMCERTO_ATTR(align_pad);
+COMCERTO_ATTR(default_priority);
+COMCERTO_ATTR(Rxpktsz);
+COMCERTO_ATTR(inbound_fifo_low);
+COMCERTO_ATTR(inbound_fifo_high);
+COMCERTO_ATTR(outbound_fifo_low);
+COMCERTO_ATTR(outbound_fifo_high);
+COMCERTO_ATTR(cng_ctl);
+COMCERTO_ATTR(cng_on_thr);
+COMCERTO_ATTR(cng_off_thr);
+COMCERTO_ATTR(cng_acc);
+COMCERTO_ATTR(fast_path_enable);
+
+static int  no_aligntrap_setup(void)
+{
+	cr_alignment &= ~CR_A;
+	set_cr(cr_alignment);
+	return 1;
+}
+
+static int  aligntrap_setup(void)
+{
+	cr_alignment |= CR_A;
+	set_cr(cr_alignment);
+	return 1;
+}
+
+static ssize_t comcerto_show_rx_lock_size(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct eth_priv *priv = netdev_priv(to_net_dev(dev));
+
+	return sprintf(buf, "0x%X\n", priv->rx_lock_size);
+}
+
+
+static ssize_t comcerto_set_rx_lock_size(struct device *dev,
+		struct device_attribute *attr,
+		const char *buf, size_t count)
+{
+	struct eth_priv *priv = netdev_priv(to_net_dev(dev));
+	unsigned long lock_sz;
+	unsigned long flags;
+	int res;
+
+	res = strict_strtoul(buf, 0, &lock_sz);
+	if (res)
+		return res;
+
+	spin_lock_irqsave(&priv->rxlock, flags);
+	if ((lock_sz > 0xFF) || (lock_sz == priv->rx_lock_size)) {
+		spin_unlock_irqrestore(&priv->rxlock, flags);
+		return count;
+	}
+
+	priv->rx_lock_size = lock_sz;
+	comcerto_emac_restart(priv);
+	spin_unlock_irqrestore(&priv->rxlock, flags);
+	return count;
+}
+
+
+static ssize_t comcerto_show_tx_lock_size(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct eth_priv *priv = netdev_priv(to_net_dev(dev));
+
+	return sprintf(buf, "0x%X\n", priv->tx_lock_size);
+}
+
+
+static ssize_t comcerto_set_tx_lock_size(struct device *dev,
+		struct device_attribute *attr,
+		const char *buf, size_t count)
+{
+	struct eth_priv *priv = netdev_priv(to_net_dev(dev));
+	unsigned long lock_sz;
+	unsigned long flags;
+	int res;
+
+	res = strict_strtoul(buf, 0, &lock_sz);
+	if (res)
+		return res;
+
+	spin_lock_irqsave(&priv->rxlock, flags);
+	if ((lock_sz > 0xFF) || (lock_sz == priv->tx_lock_size)) {
+		spin_unlock_irqrestore(&priv->rxlock, flags);
+		return count;
+	}
+
+	priv->tx_lock_size = lock_sz;
+	comcerto_emac_restart_tx(priv);
+	spin_unlock_irqrestore(&priv->rxlock, flags);
+	return count;
+}
+
+
+
+static ssize_t comcerto_show_align_pad(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct eth_priv *priv = netdev_priv(to_net_dev(dev));
+
+	return sprintf(buf, "0x%X\n", priv->align_pad);
+}
+
+
+static ssize_t comcerto_set_align_pad(struct device *dev,
+		struct device_attribute *attr,
+		const char *buf, size_t count)
+{
+	struct net_device *netdev = to_net_dev(dev);
+	struct eth_priv *priv = netdev_priv(to_net_dev(dev));
+	unsigned long pad;
+	unsigned long flags;
+	int res;
+
+	res = strict_strtoul(buf, 0, &pad);
+	if (res)
+		return res;
+
+	spin_lock_irqsave(&priv->rxlock, flags);
+	if (pad == priv->align_pad) {
+		spin_unlock_irqrestore(&priv->rxlock, flags);
+		return count;
+	}
+
+	if (netdev->flags & IFF_UP)
+		comcerto_eth_close(netdev);
+
+	if (((pad & 0x3) != 2) && ((priv->align_pad & 0x3) == 2)) {
+		no_aligntrap_setup();
+		align_count++;
+	} else if (((pad & 0x3) == 2) && ((priv->align_pad & 0x3) != 2)) {
+			if (--align_count == 0)
+				aligntrap_setup();
+		}
+	priv->align_pad = pad;
+
+	if (netdev->flags & IFF_UP)
+		comcerto_eth_open(netdev);
+
+	spin_unlock_irqrestore(&priv->rxlock, flags);
+	return count;
+}
+
+
+static ssize_t comcerto_show_default_priority(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct eth_priv *priv = netdev_priv(to_net_dev(dev));
+
+	return sprintf(buf, "%d\n", priv->default_priority);
+}
+
+
+static ssize_t comcerto_set_default_priority(struct device *dev,
+		struct device_attribute *attr,
+		const char *buf, size_t count)
+{
+	struct eth_priv *priv = netdev_priv(to_net_dev(dev));
+	int res;
+
+	res = strict_strtoul(buf, 0, &(priv->default_priority));
+	if (res)
+		return res;
+
+	return count;
+}
+
+
+static ssize_t comcerto_show_Rxpktsz(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct eth_priv *priv = netdev_priv(to_net_dev(dev));
+
+	return sprintf(buf, "0x%X\n", priv->Rxpktsz);
+}
+
+
+static ssize_t comcerto_set_Rxpktsz(struct device *dev,
+		struct device_attribute *attr,
+		const char *buf, size_t count)
+{
+	struct eth_priv *priv = netdev_priv(to_net_dev(dev));
+	GEM_DEVICE *gemdev = &priv->gemdev;
+	unsigned long pkt_sz;
+	unsigned long flags;
+	int res;
+
+	res = strict_strtoul(buf, 0, &pkt_sz);
+	if (res)
+		return res;
+
+	spin_lock_irqsave(&priv->rxlock, flags);
+	if (pkt_sz > 512) {
+		spin_unlock_irqrestore(&priv->rxlock, flags);
+		return count;
+	}
+
+	priv->Rxpktsz = pkt_sz;
+	*(u32 *)(gemdev->gemac_baseaddr + GEM_RX_STAT_PKTSIZE) = priv->Rxpktsz;
+	comcerto_emac_restart(priv);
+
+	spin_unlock_irqrestore(&priv->rxlock, flags);
+	return count;
+}
+
+
+static ssize_t comcerto_show_inbound_fifo_low(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct eth_priv *priv = netdev_priv(to_net_dev(dev));
+
+	return sprintf(buf, "0x%x\n", priv->inbound_fifo_low);
+}
+
+
+static ssize_t comcerto_set_inbound_fifo_low(struct device *dev,
+		struct device_attribute *attr,
+		const char *buf, size_t count)
+{
+	struct eth_priv *priv = netdev_priv(to_net_dev(dev));
+	GEM_DEVICE *gemdev = &priv->gemdev;
+	unsigned long threshold;
+	unsigned long flags;
+	int res;
+
+	res = strict_strtoul(buf, 0, &threshold);
+	if (res)
+		return res;
+
+	spin_lock_irqsave(&priv->rxlock, flags);
+	if (threshold > priv->inbound_fifo_high) {
+		spin_unlock_irqrestore(&priv->rxlock, flags);
+		return count;
+	}
+
+	priv->inbound_fifo_low = threshold;
+	*(u32 *)(gemdev->gemac_baseaddr + GEM_ARM_RX_FIFO_LOW) = \
+						priv->inbound_fifo_low;
+	comcerto_emac_restart(priv);
+	spin_unlock_irqrestore(&priv->rxlock, flags);
+	return count;
+}
+
+
+static ssize_t comcerto_show_inbound_fifo_high(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct eth_priv *priv = netdev_priv(to_net_dev(dev));
+
+	return sprintf(buf, "0x%X\n", priv->inbound_fifo_high);
+}
+
+
+static ssize_t comcerto_set_inbound_fifo_high(struct device *dev,
+		struct device_attribute *attr,
+		const char *buf, size_t count)
+{
+	struct eth_priv *priv = netdev_priv(to_net_dev(dev));
+	GEM_DEVICE *gemdev = &priv->gemdev;
+	unsigned long threshold;
+	unsigned long flags;
+	int res;
+
+	res = strict_strtoul(buf, 0, &threshold);
+	if (res)
+		return res;
+
+	spin_lock_irqsave(&priv->rxlock, flags);
+	if (threshold < priv->inbound_fifo_low) {
+		spin_unlock_irqrestore(&priv->rxlock, flags);
+		return count;
+	}
+
+	priv->inbound_fifo_high = threshold;
+	*(u32 *)(gemdev->gemac_baseaddr + GEM_ARM_RX_FIFO_HIGH) = \
+						priv->inbound_fifo_high;
+	comcerto_emac_restart(priv);
+	spin_unlock_irqrestore(&priv->rxlock, flags);
+	return count;
+}
+
+
+static ssize_t comcerto_show_outbound_fifo_low(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct eth_priv *priv = netdev_priv(to_net_dev(dev));
+
+	return sprintf(buf, "0x%X\n", priv->outbound_fifo_low);
+}
+
+
+static ssize_t comcerto_set_outbound_fifo_low(struct device *dev,
+		struct device_attribute *attr,
+		const char *buf, size_t count)
+{
+	struct eth_priv *priv = netdev_priv(to_net_dev(dev));
+	GEM_DEVICE *gemdev = &priv->gemdev;
+	unsigned long threshold;
+	unsigned long flags;
+	int res;
+
+	res = strict_strtoul(buf, 0, &threshold);
+	if (res)
+		return res;
+
+	spin_lock_irqsave(&priv->txlock, flags);
+	if (threshold > priv->outbound_fifo_high) {
+		spin_unlock_irqrestore(&priv->txlock, flags);
+		return count;
+	}
+
+	priv->outbound_fifo_low = threshold;
+	*(u32 *)(gemdev->gemac_baseaddr + GEM_RX_FIFO_LOW) = \
+						priv->outbound_fifo_low;
+	comcerto_emac_restart_tx(priv);
+	spin_unlock_irqrestore(&priv->txlock, flags);
+	return count;
+}
+
+
+static ssize_t comcerto_show_outbound_fifo_high(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct eth_priv *priv = netdev_priv(to_net_dev(dev));
+
+	return sprintf(buf, "0x%X\n", priv->outbound_fifo_high);
+}
+
+
+static ssize_t comcerto_set_outbound_fifo_high(struct device *dev,
+		struct device_attribute *attr,
+		const char *buf, size_t count)
+{
+	struct eth_priv *priv = netdev_priv(to_net_dev(dev));
+	GEM_DEVICE *gemdev = &priv->gemdev;
+	unsigned long threshold;
+	unsigned long flags;
+	int res;
+
+	res = strict_strtoul(buf, 0, &threshold);
+	if (res)
+		return res;
+
+	spin_lock_irqsave(&priv->txlock, flags);
+	if (threshold < priv->outbound_fifo_low) {
+		spin_unlock_irqrestore(&priv->txlock, flags);
+		return count;
+	}
+
+	priv->outbound_fifo_high = threshold;
+	*(u32 *)(gemdev->gemac_baseaddr + GEM_RX_FIFO_HIGH) = \
+						priv->outbound_fifo_high;
+	comcerto_emac_restart_tx(priv);
+	spin_unlock_irqrestore(&priv->txlock, flags);
+	return count;
+}
+
+
+static ssize_t comcerto_show_cng_ctl(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct eth_priv *priv = netdev_priv(to_net_dev(dev));
+#if (CNG_DEBUG_FILL)
+	return sprintf(buf, "%s: f:%08X af:%08X\n", \
+		to_net_dev(dev)->name, priv->cng_fill, priv->cng_fill_avg);
+#else
+	return sprintf(buf, "%s: CongCtl:%s\n", \
+		to_net_dev(dev)->name, (priv->cng_ctl >= 0) ?  "On" : "Off");
+#endif
+}
+
+
+static ssize_t comcerto_set_cng_ctl(struct device *dev,
+		struct device_attribute *attr,
+		const char *buf, size_t count)
+{
+	struct eth_priv *priv = netdev_priv(to_net_dev(dev));
+	unsigned long tmp;
+	int res;
+
+	res = strict_strtoul(buf, 0, &tmp);
+	if (res)
+		return res;
+
+	if (tmp >= 0) {
+		priv->cng_ctl = tmp;
+	} else if (tmp == -1) {
+		priv->cng_state = CNG_OFF;
+		priv->cng_avg = 0;
+		priv->cng_ctl = -1;
+	}
+	return count;
+	/*	return comcerto_show_cng_ctl(dev, attr, buf); */
+}
+
+static ssize_t comcerto_show_cng_off_thr(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct eth_priv *priv = netdev_priv(to_net_dev(dev));
+	return sprintf(buf, "0x%X\n", priv->cng_off_thr/sizeof(struct tFDesc));
+}
+
+static ssize_t comcerto_set_cng_off_thr(struct device *dev,
+		struct device_attribute *attr,
+		const char *buf, size_t count)
+{
+	struct eth_priv *priv = netdev_priv(to_net_dev(dev));
+	unsigned int threshold;
+	unsigned long tmp;
+	int res;
+
+	res = strict_strtoul(buf, 0, &tmp);
+	if (res)
+		return res;
+
+	threshold = tmp * sizeof(struct tFDesc);
+	if (threshold !=  priv->cng_off_thr)
+		priv->cng_off_thr = threshold;
+	return count;
+}
+
+static ssize_t comcerto_show_cng_on_thr(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct eth_priv *priv = netdev_priv(to_net_dev(dev));
+	return sprintf(buf, "0x%X\n", priv->cng_on_thr/sizeof(struct tFDesc));
+}
+
+static ssize_t comcerto_show_cng_acc(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct eth_priv *priv = netdev_priv(to_net_dev(dev));
+	return sprintf(buf, "0x%X\n", priv->cng_acc);
+}
+
+static ssize_t comcerto_set_cng_acc(struct device *dev,
+		struct device_attribute *attr,
+		const char *buf, size_t count)
+{
+	struct eth_priv *priv = netdev_priv(to_net_dev(dev));
+	unsigned long acc;
+	int res;
+
+	res = strict_strtoul(buf, 0, &acc);
+	if (res)
+		return res;
+
+	if ((acc > 0) && (acc !=  priv->cng_acc))
+		priv->cng_acc = acc;
+	return count;
+}
+
+static ssize_t comcerto_set_cng_on_thr(struct device *dev,
+		struct device_attribute *attr,
+		const char *buf, size_t count)
+{
+	struct eth_priv *priv = netdev_priv(to_net_dev(dev));
+	unsigned long tmp, threshold;
+	int res;
+
+	res = strict_strtoul(buf, 0, &tmp);
+	if (res)
+		return res;
+
+	threshold = tmp * sizeof(struct tFDesc);
+	if (threshold !=  priv->cng_on_thr)
+		priv->cng_on_thr = threshold;
+	return count;
+}
+
+static ssize_t comcerto_show_fast_path_enable(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct eth_priv *priv = netdev_priv(to_net_dev(dev));
+	printk(KERN_INFO "comcerto_show_fast_path_enable\n");
+	return sprintf(buf, "%d\n", priv->fast_path_enabled);
+}
+
+
+static ssize_t comcerto_set_fast_path_enable(struct device *dev,
+		struct device_attribute *attr,
+		const char *buf, size_t count)
+{
+	unsigned long state;
+	int res;
+
+	res = strict_strtoul(buf, 0, &state);
+	if (res)
+		return res;
+
+	printk(KERN_INFO "comcerto_set_fast_path_enable %lu\n", state);
+	comcerto_eth_enable_fast_path(to_net_dev(dev), state);
+
+	return count;
+}
+
+
+void comcerto_init_sysfs(struct net_device *dev)
+{
+	struct eth_priv *priv = netdev_priv(dev);
+
+	/* Initialize the default values */
+	priv->align_pad = DEFAULT_ALIGN_PAD;
+	priv->default_priority = DEFAULT_PRIORITY;
+	priv->Rxpktsz = DEFAULT_RX_STAT_PKTSIZE ;
+	priv->outbound_fifo_low = DEFAULT_TX_GEM_THR_LO ;
+	priv->outbound_fifo_high = DEFAULT_TX_GEM_THR_HI ;
+	priv->inbound_fifo_low = DEFAULT_RX_DMA_THR_LO ;
+	priv->inbound_fifo_high = DEFAULT_RX_DMA_THR_HI ;
+	priv->rx_lock_size = DEFAULT_RX_LOCK;
+	priv->tx_lock_size = DEFAULT_TX_LOCK;
+	priv->fast_path_enabled = DEFAULT_FAST_PATH_STATE;
+
+	priv->cng_ctl = -1;
+	priv->cng_off_thr = 12 * sizeof(struct tFDesc) ;
+	priv->cng_on_thr =  32 * sizeof(struct tFDesc) ;
+	priv->cng_state = CNG_OFF;
+	priv->fast_filled = 0;
+	priv->cng_acc = 5;
+	priv->cng_avg = 0;
+	/* Create our sysfs files */
+	COMCERTO_CREATE_FILE(dev, rx_lock_size);
+	COMCERTO_CREATE_FILE(dev, tx_lock_size);
+	COMCERTO_CREATE_FILE(dev, align_pad);
+	COMCERTO_CREATE_FILE(dev, default_priority);
+	COMCERTO_CREATE_FILE(dev, Rxpktsz);
+	COMCERTO_CREATE_FILE(dev, outbound_fifo_low);
+	COMCERTO_CREATE_FILE(dev, outbound_fifo_high);
+	COMCERTO_CREATE_FILE(dev, inbound_fifo_low);
+	COMCERTO_CREATE_FILE(dev, inbound_fifo_high);
+	COMCERTO_CREATE_FILE(dev, cng_ctl);
+	COMCERTO_CREATE_FILE(dev, cng_on_thr);
+	COMCERTO_CREATE_FILE(dev, cng_off_thr);
+	COMCERTO_CREATE_FILE(dev, cng_acc);
+	COMCERTO_CREATE_FILE(dev, fast_path_enable);
+
+	if ((priv->align_pad & 0x3) != 2) { /* 32 bits  aligned */
+		no_aligntrap_setup();
+		align_count++;
+	}
+}
diff -r e137be04dc4d drivers/net/comcerto/comcerto_ved.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/net/comcerto/comcerto_ved.c	Mon Aug 17 16:45:23 2009 -0500
@@ -0,0 +1,601 @@
+ /*
+  *  linux/drivers/net/comcerto/comcerto_ved.c
+  *
+  *  Copyright (C) 2006 Mindspeed Technologies, Inc.
+  *
+  * This program is free software; you can redistribute it and/or modify
+  * it under the terms of the GNU General Public License as published by
+  * the Free Software Foundation; either version 2 of the License, or
+  * (at your option) any later version.
+  *
+  * This 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/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/dma-mapping.h>
+
+#include <net/ip.h>
+#include <net/sock.h>
+
+#include <asm/irq.h>
+#include <asm/delay.h>
+#include <asm/mach/irq.h>
+#include <mach/hardware.h>
+#include <mach/memory.h>
+#include <mach/debug.h>
+
+#include <linux/platform_device.h>
+#include <linux/firmware.h>
+
+#include "comcerto_ved.h"
+#include "comcerto_smi_part.h"
+#include "comcerto_smi_queue.h"
+#include "comcerto_msp.h"
+
+char ctrl_mac[6] = { 0x00, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE };
+
+#define IP_SEC_HEADROOM	40
+#define PKT_BUF_SZ (1540+IP_SEC_HEADROOM)	/* Size of each rx buffer */
+
+#define VED_STATE_RESET		0
+#define VED_STATE_DIRECT	1
+#define VED_STATE_MSP		2
+#define VED_STATE_CHANGING	3
+
+#define NAPI_WA 1
+
+int ved_state = VED_STATE_RESET;
+
+static int ved_xmit(struct sk_buff *skb, struct net_device *dev);
+static struct net_device_stats *ved_get_stats(struct net_device *dev);
+void ved_rx(struct net_device *dev, int len, char *buf);
+irqreturn_t ved_interrupt(int irq, void *dev_id);
+int device_open(struct net_device *dev);
+int device_release(struct net_device *dev);
+void ved_tx_timeout(struct net_device *dev);
+int ved_rebuild_header(struct sk_buff *skb);
+
+int ved_header(struct sk_buff *skb, struct net_device *dev, unsigned short type, void *daddr, void *saddr, unsigned int len);
+
+int ved_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
+static int ved_write_packet(struct sk_buff *skb, struct net_device *dev);
+static int ved_read_packet(struct net_device *dev, struct FDesc * ThisFdesc);
+static int ved_poll(struct net_device *dev, int *budget);
+
+static int __init ctrl_init(struct net_device *dev);
+
+void ved_set_eth_header(char *set_eth);
+
+
+static int start_ved(struct net_device *dev);
+static int stop_ved(void);
+
+struct net_device ctrl_dev[1] = {
+      {init:ctrl_init,}
+};
+
+static struct platform_device *msp_coprocessor;
+
+/* fake multicast ability */
+static void set_multicast_list(struct net_device *dev)
+{
+
+}
+
+static int __init ctrl_init(struct net_device *dev)
+{
+	struct ved_priv *priv;
+
+	/* Initialize the device structure. */
+	priv = kmalloc(sizeof(struct ved_priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	memset(priv, 0, sizeof(struct ved_priv));
+
+	spin_lock_init(&priv->lock);
+	// init private section
+	priv->default_packet_type = PROTID_ETH;
+	priv->state = 0; /* closed */
+
+	/* Fill in device structure with ethernet-generic values. */
+	ether_setup(dev);
+	
+	//dev->do_ioctl = ved_ioctl;
+	dev->priv = priv;
+	dev->open = device_open;
+	dev->stop = device_release;
+	dev->get_stats = ved_get_stats;
+	dev->hard_start_xmit = ved_xmit;
+	dev->rebuild_header = ved_rebuild_header;
+	dev->hard_header = ved_header;
+	dev->set_multicast_list = set_multicast_list;
+	dev->irq = IRQ_CTRL;
+	
+	dev->poll = ved_poll;
+	dev->weight = 32;
+
+	dev->flags &= ~IFF_MULTICAST;
+	dev->flags |= IFF_NOARP;
+
+	skb_queue_head_init(&priv->msp.MSP_list);
+
+	netif_stop_queue(dev);
+	printk(KERN_DEBUG "%s init\n", CTRL);
+	return 0;
+}
+
+static int ved_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+	struct ved_priv *priv = (struct ved_priv *)dev->priv;
+	unsigned long flags;
+	int rc;
+
+	spin_lock_irqsave(&priv->lock, flags);
+
+	rc = ved_write_packet(skb, dev);
+
+	if (rc) {
+		priv->stats.tx_dropped++;
+	} else {
+		priv->stats.tx_packets++;
+		priv->stats.tx_bytes += skb->len;
+		dev->trans_start = jiffies;	/* save the timestamp */
+	}
+
+	spin_unlock_irqrestore(&priv->lock, flags);
+
+	return 0;
+}
+
+static inline void ved_ack_MSP(void)
+{
+	__raw_writel((1 << IRQ_PTP1), COMCERTO_INTC_SET_STATUS_REG_0);
+}
+
+static inline void ved_disable_int(unsigned int irq)
+{
+	if (irq < 32)
+		__raw_writel(__raw_readl(COMCERTO_INTC_CSP_IRQMASK_0) & ~(1UL << irq), COMCERTO_INTC_CSP_IRQMASK_0);
+	else
+		__raw_writel(__raw_readl(COMCERTO_INTC_CSP_IRQMASK_1) & ~(1UL << (irq - 32)), COMCERTO_INTC_CSP_IRQMASK_1);
+
+}
+
+static inline void ved_enable_int(unsigned int irq)
+{
+	if (irq < 32)
+		__raw_writel(__raw_readl(COMCERTO_INTC_CSP_IRQMASK_0) | (1UL << irq), COMCERTO_INTC_CSP_IRQMASK_0);
+	else
+		__raw_writel(__raw_readl(COMCERTO_INTC_CSP_IRQMASK_1) | (1UL << (irq - 32)), COMCERTO_INTC_CSP_IRQMASK_1);
+
+}
+
+static inline void ved_ack_int(unsigned int irq)
+{
+	if (irq < 32)
+		__raw_writel(__raw_readl(COMCERTO_INTC_STATUS_REG_0) & (1UL << irq), COMCERTO_INTC_STATUS_REG_0);
+	else
+		__raw_writel(__raw_readl(COMCERTO_INTC_STATUS_REG_1) & (1UL << (irq - 32)), COMCERTO_INTC_STATUS_REG_1);
+}
+
+static inline int ved_get_int_status(unsigned int irq)
+{
+	if (irq < 32)
+		return (__raw_readl(COMCERTO_INTC_STATUS_REG_0) & (1UL << irq));
+	else
+		return (__raw_readl(COMCERTO_INTC_STATUS_REG_1) & (1UL << (irq - 32)));
+}
+
+static inline void ved_generate_int(unsigned int irq)
+{
+	if (irq < 32)
+		__raw_writel((1UL << irq), COMCERTO_INTC_SET_STATUS_REG_0);
+	else
+		__raw_writel((1UL << (irq - 32)), COMCERTO_INTC_SET_STATUS_REG_1);
+
+}
+
+irqreturn_t ved_interrupt(int irq, void *dev_id)
+{
+	struct net_device *dev = (struct net_device *)dev_id;
+	struct ved_priv *priv = dev->priv;
+
+	spin_lock(&priv->lock);
+
+	if (netif_rx_schedule_prep(dev)) {
+
+		ved_generate_int(irq);
+		PDEBUG(VED_RX_FUNC, "%s  ved_interruptRX : schedule poll\n", dev->name);
+		disable_irq(irq);
+		__netif_rx_schedule(dev);
+	} else {
+		PDEBUG(VED_RX_FUNC, "%s ved_interruptRX bug! interrupt while in poll\n", dev->name);
+		/* FIX by disabling interrupts  */
+		//disable_irq(irq);
+	}
+
+	/* Unlock the device and we are done */
+	spin_unlock(&priv->lock);
+
+	return IRQ_HANDLED;
+}
+
+int ved_rebuild_header(struct sk_buff *skb)
+{
+	struct ethhdr *eth = (struct ethhdr *)skb->data;
+	struct net_device *dev = skb->dev;
+
+	memcpy(eth->h_source, dev->dev_addr, dev->addr_len);
+	memcpy(eth->h_dest, dev->dev_addr, dev->addr_len);
+	eth->h_dest[ETH_ALEN - 1] ^= 0x01;	/* dest is us xor 1 */
+
+	return 0;
+}
+
+int ved_header(struct sk_buff *skb, struct net_device *dev, unsigned short type, void *daddr, void *saddr, unsigned int len)
+{
+	struct ethhdr *eth = (struct ethhdr *)skb_push(skb, ETH_HLEN);
+
+	eth->h_proto = htons(type);
+	memcpy(eth->h_source, saddr ? saddr : dev->dev_addr, dev->addr_len);
+	memcpy(eth->h_dest, daddr ? daddr : dev->dev_addr, dev->addr_len);
+
+	eth->h_dest[ETH_ALEN - 1] ^= 0x01;	/* dest is us xor 1 */
+
+	return (dev->hard_header_len);
+}
+
+int device_open(struct net_device *dev)
+{
+	struct ved_priv *priv = dev->priv;
+	const struct firmware *fw_entry;
+	int rc = 0;
+
+	/* Check if the interface is alredy open (MSP already download)*/
+	if(priv->state == 1)
+		return rc;
+
+	comcerto_stop_msp(&priv->msp);
+
+	might_sleep();
+
+	if(request_firmware(&fw_entry,"msp.axf",&msp_coprocessor->dev) !=0 ) {
+		printk(KERN_ERR "Error finding the Firmware\n");
+		rc = -ETIMEDOUT;
+		goto out;
+	}
+	
+	priv->msp.code_info.code = fw_entry->data;
+	priv->msp.code_info.size = fw_entry->size;
+	if (SDRAM_MSP_MEMORY_PHY) // MSP @ address 0x0
+		priv->msp.vectors_base = ioremap(0x00000000, 0x40);
+	else
+		priv->msp.vectors_base = (void *)SDRAM_MSP_MEMORY_VADDR;
+
+	if(!priv->msp.vectors_base) {
+		printk(KERN_ERR "Cannot map msp vectors, aborting.\n");
+		goto out;
+	}
+
+	comcerto_download_to_msp(&priv->msp);
+	
+	if(comcerto_start_msp(&priv->msp) < 0)
+		goto out;
+	
+	start_ved(dev);
+
+	rc = request_irq(dev->irq, ved_interrupt, SA_SHIRQ, "comcerto_ved", dev);
+	if (rc) {
+		printk(KERN_ERR "Failed to get the IRQ = %d\n", dev->irq);
+		goto out;
+	}
+
+	netif_start_queue(dev);
+	priv->state = 1; /* open */
+	
+	
+     out:
+	release_firmware(fw_entry);
+	return rc;
+}
+
+int device_release(struct net_device *dev)
+{
+	struct ved_priv *priv = dev->priv;
+
+	PDEBUG(VED_STATE,"%s device_release state %d", CTRL, priv->state);
+
+	/* do nothing if interface is already down */
+	if(priv->state == 1)
+	{
+		netif_stop_queue(dev);	/* can't transmit any more */
+		
+		/* disable irq */
+		free_irq(dev->irq, dev);
+
+		/* reset MSP device */
+		comcerto_stop_msp(&priv->msp);
+		if (SDRAM_MSP_MEMORY_PHY) // MSP @ address 0x0
+			iounmap(priv->msp.vectors_base );
+
+		stop_ved();
+		priv->state = 0;
+	}
+
+	return 0;
+}
+
+static struct net_device_stats *ved_get_stats(struct net_device *dev)
+{
+	return &(((struct ved_priv *)dev->priv)->stats);
+}
+
+int __init ved_init_module(void)
+{
+	int rc;
+//	PDEBUG(VED_INIT_FUNC,"ved_init_module");
+
+	/* Find a name for this unit */
+	rc = dev_alloc_name(&ctrl_dev[0], CTRL);
+	if (rc < 0) {
+		printk(KERN_ERR "ved_init_module: failed to alloc device name %s\n", CTRL);
+		goto err0;
+	}
+
+	rc = register_netdev(&ctrl_dev[0]);
+	if (rc) {
+		printk(KERN_ERR "ved_init_module: failed to register dev %s\n", CTRL);
+		goto err1;
+	}
+
+	/* assign the MAC address for second virtual device */
+	memcpy_fromio(ctrl_dev[0].dev_addr, ctrl_mac, ETH_ALEN);
+	msp_coprocessor = platform_device_register_simple("MSP_Copro", -1, NULL, 0);
+
+	return 0;
+
+      err1:
+	kfree(ctrl_dev[0].priv);
+
+      err0:
+	return rc;
+}
+
+static void __exit ved_cleanup_module(void)
+{
+	unregister_netdev(&ctrl_dev[0]);
+	kfree(ctrl_dev[0].priv);
+}
+
+/**
+ *	ved_read_packet - read and process an REALPACKET (Ethernet) frame 
+ *	@dev: device id
+ *	@ThisFdesc: Frame descriptor to parse
+ *
+ *	This function read and process received frame descriptor non pre-processed by MSP . (ethernet frames)
+ */
+static int ved_read_packet(struct net_device *dev, struct FDesc *ThisFdesc)
+{
+	struct ved_priv *priv = (struct ved_priv *)dev->priv;
+	char *data_addr;
+	int length, offset, reason;
+	struct sk_buff *skb;
+
+	PDEBUG(VED_RX_FUNC, "%s : ved_read_packet: entry\n", dev->name);
+
+	skb = dev_alloc_skb(PKT_BUF_SZ);
+
+	if (skb) {
+		length = ThisFdesc->Length;
+		offset = ThisFdesc->Offset;
+
+		ThisFdesc->FStatus = 0;
+		data_addr = (char *)msp_to_virt(ThisFdesc->Payload + offset);
+
+		skb_reserve(skb, NET_IP_ALIGN);
+		memcpy(skb_put(skb, length), data_addr, length);
+		skb->dev = dev;
+		skb->protocol = eth_type_trans(skb, dev);
+
+		if (unlikely(skb->tail > skb->end))
+			skb_over_panic(skb, length, current_text_addr());
+
+		if((reason = netif_receive_skb(skb)))
+		{
+			priv->stats.rx_dropped++;
+			PDEBUG(VED_RX_FUNC, "WARN: skb not delivered - reason %lx - proto %lx\n", (unsigned long)reason, (unsigned long)skb->protocol);
+		}
+		
+		priv->stats.rx_packets++;
+		priv->stats.rx_bytes += length;
+		dev->last_rx = jiffies;
+		
+	} else {
+		PDEBUG(VED_RX_FUNC, "%s ved_read_packet: low on mem - packet dropped\n", dev->name);
+		priv->stats.rx_dropped++;
+		return 0;
+	}
+	PDEBUG(VED_RX_FUNC, "%s : ved_read_packet: exit\n", dev->name);
+
+	return 1;
+}
+
+static int ved_poll(struct net_device *dev, int *budget)
+{
+
+	struct ved_priv *priv = (struct ved_priv *)dev->priv;
+	struct FDesc * ThisFdesc = NULL;
+	int done;
+	int rx_work_limit = dev->quota;
+	int received = 0;
+
+	PDEBUG(VED_RX_FUNC, "%s : ved_poll: entry\n", dev->name);
+
+restart_poll:
+	do {
+		ved_ack_int(dev->irq);
+
+		while (!SFL_queue_empty(priv->rx_smiq.fpq)) {
+
+			if (--rx_work_limit < 0) {
+				goto not_done;
+			}
+
+			ThisFdesc = SFL_dequeue(&priv->rx_smiq);
+
+			done = ved_read_packet(dev, ThisFdesc);
+			//SFL_free_part(msp_to_virt(ThisFdesc->fpart), ThisFdesc);
+			SFL_free_part(aram_to_virt(ThisFdesc->fpart), ThisFdesc);
+			if (!done)
+				goto not_done;
+			else
+				received++;
+			break;
+			
+		}
+
+	}
+	while (ved_get_int_status(dev->irq));
+
+//	PDEBUG(VED_RX_FUNC, "%s ved_poll : done %d packets \n", dev->name, received);
+
+	dev->quota -= received;
+	*budget -= received;
+	/* we are happy/done, no more packets on ring; put us back
+	   to where we can start processing interrupts again */
+	netif_rx_complete(dev);
+	//enable_irq(dev->irq);
+
+	/* The last op happens after poll completion. Which means the following:
+	 * 1. it can race with disabling irqs in irq handler (which are done to
+	 * schedule polls)
+	 * 2. it can race with dis/enabling irqs in other poll threads
+	 * 3. if an irq raised after the begining of the outer  beginning
+	 * loop(marked in the code above), it will be immediately
+	 * triggered here.
+	 *
+	 * Summarizing: the logic may results in some redundant irqs both
+	 * due to races in masking and due to too late acking of already
+	 * processed irqs. The good news: no events are ever lost.
+	 */
+
+	/* Let's have a last chance to process any missing interrupts we may 
+	* we may have missed while the IRQs line was masqued. Before leaving
+	* poll mode, we check if data have been posted in the queue from MSP.
+	* If true, then the IRQ line is disabled again and a new loop of polling
+	* is scheduled. This double check work arround is well known in NAPI 
+	* based implementation (see documentations/NAPI_HOWTO.txt - appendix2)
+	*/
+#if NAPI_WA
+	if(!SFL_queue_empty(priv->rx_smiq.fpq) && netif_rx_reschedule(dev, received)) {
+		//disable_irq(dev->irq);
+		goto restart_poll;
+	}
+#endif
+	enable_irq(dev->irq);
+	return 0;		/* done */
+
+      not_done:
+
+	PDEBUG(VED_RX_FUNC, "%s ved_poll : not done %d packets \n", dev->name, received);
+
+	if (!received) {
+		received = 1;
+	}
+	dev->quota -= received;
+	*budget -= received;
+
+	return 1;		/* not_done */
+}
+
+static int ved_write_packet(struct sk_buff *skb, struct net_device *dev)
+{
+	struct ved_priv *priv = (struct ved_priv *)dev->priv;
+	struct FDesc *ThisFdesc;
+	struct u8 *buf;
+	u32 offset;
+
+	PDEBUG(VED_TX_FUNC, "%s ved_write_packet : entry \n", dev->name);
+	PDEBUG(VED_TX_FUNC, "%s : ved_write_packet: packet protocol %x \n", dev->name, skb->protocol);
+
+	
+	ThisFdesc = SFL_alloc_part(priv->tx_smipart);
+	if (!ThisFdesc) {
+		dev_kfree_skb(skb);
+		return -ENOMEM;
+	}
+
+	offset = NET_IP_ALIGN;
+	buf = msp_to_virt(ThisFdesc->Payload) + offset;
+	
+	memcpy(buf, skb->data, skb->len);
+
+	ThisFdesc->Offset = offset;
+
+	ThisFdesc->Next = (unsigned long) NULL;
+	ThisFdesc->Length = (u32) (skb->len);
+	ThisFdesc->FStatus = 0;
+	ThisFdesc->protocol = priv->default_packet_type;
+
+	// free the original skb (local generation)
+	dev_kfree_skb(skb);
+
+	if (SFL_enqueue(&priv->tx_smiq, ThisFdesc) == 0) {
+		PDEBUG(VED_TX_FUNC, "ved_write_packet QUEUE FULL !!!! %lx \n", (unsigned long) ThisFdesc);
+		SFL_free_part(priv->tx_smipart, ThisFdesc);
+		return -ENOMEM;
+	}
+	PDEBUG(VED_TX_FUNC, "%s ved_write_packet : exit \n", dev->name);
+
+	return 0;
+
+}
+
+static int stop_ved(void)
+{
+	struct net_device *dev;
+	struct ved_priv *priv;
+	unsigned long flags;
+
+	dev = &ctrl_dev[0];
+	priv = (struct ved_priv *)dev->priv;
+	
+	return 0;
+}
+
+static int start_ved(struct net_device *dev)
+{
+	struct ved_priv *priv= (struct ved_priv *)dev->priv;
+	struct msp_info *info= (struct msp_info *)priv->msp.info;
+	
+	if(info)
+	{
+		PDEBUG(VED_INIT_FUNC, "info \n\tDevice=%lx\n\tRevision=%lx\n\tspu_version=%s\n\tCSPtoMSPQueuePhyaddr=%lx\n\tMSPtoCSPQueuePhyaddr=%lx\n\tSMRXCSPhyaddr=%lx\n\tSMTXCSPhyaddr=%lx\n\t",(unsigned long) info->Device,(unsigned long) info->Revision, info->spu_version,(unsigned long) info->CSPtoMSPQueuePhyaddr,(unsigned long) info->MSPtoCSPQueuePhyaddr,(unsigned long) info->SMRXCSPhyaddr,(unsigned long) info->SMTXCSPhyaddr);
+		printk(KERN_INFO "MSP version is : %s\n", info->msp_version);
+
+//		priv->tx_smipart =  (struct FASTPART *)  msp_to_virt(info->SMRXCSPhyaddr);
+		priv->tx_smipart =  (struct FASTPART *)  aram_to_virt(info->SMRXCSPhyaddr);
+//		priv->rx_smipart =  (struct FASTPART *)  msp_to_virt(info->SMRXCSPhyaddr);
+		priv->rx_smipart =  (struct FASTPART *)  aram_to_virt(info->SMRXCSPhyaddr);
+
+		smi_queue_init(&priv->tx_smiq, info->CSPtoMSPQueuePhyaddr, SFL_genint_cpu0);
+		smi_queue_init(&priv->rx_smiq, info->MSPtoCSPQueuePhyaddr, NULL);
+		ved_ack_MSP();
+		return 0;
+	}
+	return -1;
+}
+
+module_init(ved_init_module);
+module_exit(ved_cleanup_module);
diff -r e137be04dc4d drivers/net/comcerto/comcerto_ved.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/net/comcerto/comcerto_ved.h	Mon Aug 17 16:45:23 2009 -0500
@@ -0,0 +1,105 @@
+/*
+ *  linux/drivers/net/comcerto/comcerto_ved.h
+ *
+ *  Copyright (C) 2006 Mindspeed Technologies, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef _COMCERTO_VED_H
+#define _COMCERTO_VED_H
+
+#include <linux/netdevice.h>	/* struct device, and other headers */
+
+#include "comcerto_smi_part.h"
+#include "comcerto_smi_queue.h"
+#include "comcerto_msp.h"
+
+#define VED_SKB_POOL_SIZE	512
+
+/* Default timeout period */
+#define VED_TIMEOUT 5		/* In jiffies */
+
+// Protocol index definition
+typedef enum {
+	PROTID_RAW,
+	PROTID_ETH,
+	PROTID_PPP,
+	PROTID_IPV4,
+	PROTID_IPV6,
+	PROTID_CSME,
+	PROTID_ARP,
+	PROTID_VLAN,
+	PROTID_UDP,
+	PROTID_TCP,
+	PROTID_ICMP,
+	PROTID_CSM_API,
+	MAX_PROTOCOL,
+	PROTO_INVALID
+} ProtocolIndex;
+
+#define IRQ_CTRL	IRQ_PTP0
+
+
+#define CTRL	"eth1"
+
+
+/*
+ * This structure is private to each device. It is used to pass
+ * packets in and out, so there is place for a packet
+ */
+
+struct ved_priv {
+	struct net_device_stats stats;
+
+	spinlock_t lock;
+
+	struct _SKB_POOL *skbpool;	// skb pool for MSP to CSP buffer (max MTU size)
+
+	// smi (share memory interface)
+	struct FASTPART *tx_smipart;	// CSP to MSP Fdesc fast part
+	struct FASTPART *rx_smipart;	// MSP to CSP Fdesc fast part
+	struct SMIQUEUE tx_smiq;
+	struct SMIQUEUE rx_smiq;
+	u32 default_packet_type;
+	struct comcerto_msp msp;
+	int state;
+};
+
+struct BDesc {
+	unsigned long BPtr;
+	volatile u32 BControl;
+};
+
+struct FDesc {
+	unsigned long Next;
+	volatile u32 System;
+	volatile u32 FStatus;
+	volatile u32 FControl;
+	struct BDesc BDesc;
+	u32 Dummy[6];
+	u16 Length;
+	u16 Offset;
+	u16 protocol;
+	u16 proto_length;
+	struct sk_buff *skb;
+	unsigned long fpart;
+	u32 Dummy1;		// Tail
+	u32 DMA_addr;		// nFdesc used by MSP or local phy addr of FDESC (only used in direct EMAC control mode)
+	u32 pSFdesc;		// CSP musn't touch this value
+	unsigned long Payload;
+};
+
+#endif /* _COMCERTO_VED_H */
