lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [day] [month] [year] [list]
Message-Id: <200801242128.21569.asalnikov@ru.mvista.com>
Date:	Thu, 24 Jan 2008 21:28:20 +0300
From:	Anton Salnikov <asalnikov@...mvista.com>
To:	netdev@...r.kernel.org
Cc:	jgarzik@...ox.com
Subject: [PATCH] TI DaVinci ethernet support for DM6446

This is support for DaVinci DM6446 ethernet onchip controller for kernel
version 2.6.24-rc8

Signed-off-by: Anton Salnikov <asalnikov@...mvista.com>
---

 drivers/net/arm/Kconfig              |    9 
 drivers/net/arm/Makefile             |    4 
 drivers/net/arm/davinci_emac.c       | 4766 +++++++++++++++++++++++++++++++++++
 drivers/net/arm/davinci_emac.h       | 1560 +++++++++++
 drivers/net/arm/davinci_emac_debug.c |  658 ++++
 drivers/net/arm/davinci_emac_phy.c   |  723 +++++
 drivers/net/arm/davinci_emac_phy.h   |  106 
 7 files changed, 7826 insertions(+)

Index: 2.6.24-rc8.ether/drivers/net/arm/Kconfig
===================================================================
--- 2.6.24-rc8.ether.orig/drivers/net/arm/Kconfig
+++ 2.6.24-rc8.ether/drivers/net/arm/Kconfig
@@ -2,6 +2,7 @@
 # Acorn Network device configuration
 #  These are for Acorn's Expansion card network interfaces
 #
+
 config ARM_AM79C961A
 	bool "ARM EBSA110 AM79C961A support"
 	depends on ARM && ARCH_EBSA110
@@ -47,3 +48,11 @@ config EP93XX_ETH
 	help
 	  This is a driver for the ethernet hardware included in EP93xx CPUs.
 	  Say Y if you are building a kernel for EP93xx based devices.
+
+config TI_DAVINCI_EMAC
+	tristate "TI DaVinci EMAC Support"
+	depends on NETDEVICES && MACH_DAVINCI_EVM
+	help
+	  This driver supports TI's DaVinci Ethernet .
+	  To compile this driver as a module, choose M here: the module
+	  will be called ti_davinci_emac.  This is recommended.
Index: 2.6.24-rc8.ether/drivers/net/arm/Makefile
===================================================================
--- 2.6.24-rc8.ether.orig/drivers/net/arm/Makefile
+++ 2.6.24-rc8.ether/drivers/net/arm/Makefile
@@ -9,3 +9,7 @@ obj-$(CONFIG_ARM_ETHER3)	+= ether3.o
 obj-$(CONFIG_ARM_ETHER1)	+= ether1.o
 obj-$(CONFIG_ARM_AT91_ETHER)	+= at91_ether.o
 obj-$(CONFIG_EP93XX_ETH)	+= ep93xx_eth.o
+
+obj-$(CONFIG_TI_DAVINCI_EMAC) += davinci_emac_driver.o
+davinci_emac_driver-objs := davinci_emac.o davinci_emac_phy.o 
davinci_emac_debug.o
+
Index: 2.6.24-rc8.ether/drivers/net/arm/davinci_emac.c
===================================================================
--- /dev/null
+++ 2.6.24-rc8.ether/drivers/net/arm/davinci_emac.c
@@ -0,0 +1,4766 @@
+/*
+ * linux/drivers/net/davinci_emac.c
+ *
+ * Copyright (C) 2006 Texas Instruments.
+ * Copyright (C) 2008 MontaVista Software, Inc. <source@...sta.com>
+ *
+ * This file is licensed under the terms of the
+ * GNU General Public License version 2. This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *----------------------------------------------------------------------------
+ * Modifications:
+ * ver.	0.0 Suraj Iyer - Original Linux drive
+ *	0.1 Anant Gole - Recoded as per TI PSPF architecture (converted to DDA)
+ *	2.0 Suraj Iyer, Sharath Kumar, Ajay Singh - Completed for TI BCG
+ *	3.0 Anant Gole - Modified and ported for DaVinci
+ *	4.0 Kevin Hilman, Anant Gole - Linuxification of the driver
+ *	4.? Paul Bartholomew -	Use PHY_DUPLEX_* constants instead
+ *				of hard-coded numbers.  Also, fixed
+ *				EMAC_IOCTL_READ_PHY_REG in emac_control() -
+ *				the phy_num and reg_addr args were swapped
+ *				in call to emac_mdio_read().
+ */
+
+/*
+ *   Driver Features:
+ *
+ *    The following flags should be defined by the make file for support
+ *   of the features:
+ *
+ *   (1) EMAC_CACHE_WRITEBACK_MODE to support write back cache mode.
+ *
+ *   (2) EMAC_MULTIPACKET_TX_COMPLETE_NOTIFY - to support of multiple
+ *	Tx complete notifications. If this is defined the Tx complete
+ *	DDA callback function contains multiple packet Tx complete
+ *	events.  Note: BY DEFAULT THIS DRIVER HANDLES MULTIPLE TX
+ *	COMPLETE VIA ITS CALLBACK IN THE SAME FUNCTION FOR SINGLE
+ *	PACKET COMPLETE NOTIFY.
+ *
+ *
+ *   (3) CONFIG_EMAC_INIT_BUF_MALLOC - Not required for DaVinci driver
+ *	- feature was added for another TI platform
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/errno.h>
+#include <linux/in.h>
+#include <linux/ioport.h>
+#include <linux/slab.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/ethtool.h>
+#include <linux/highmem.h>
+#include <linux/proc_fs.h>
+#include <linux/ctype.h>
+#include <linux/version.h>
+#include <linux/spinlock.h>
+#include <linux/dma-mapping.h>
+#include <linux/clk.h>
+#include <linux/platform_device.h>
+#include <asm/arch/hardware.h>
+
+#include "davinci_emac.h"
+
+/*
+ * linux module options
+ */
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Davinci EMAC Maintainer: Anant Gole <anantgole@...com>");
+MODULE_DESCRIPTION("DaVinci Ethernet driver - EMAC (EMAC)");
+MODULE_VERSION(EMAC_MODULE_VERSION);
+
+static int cfg_link_speed ;
+module_param(cfg_link_speed, int, 0);
+MODULE_PARM_DESC(cfg_link_speed, "Fixed speed of the Link: <100/10>");
+
+static char *cfg_link_mode = "auto";
+module_param(cfg_link_mode, charp, 0);
+MODULE_PARM_DESC(cfg_link_mode, "Fixed mode of the Link: <fd/hd>");
+
+static int debug_mode;
+module_param(debug_mode, int, 0);
+MODULE_PARM_DESC(debug_mode,
+		 "Turn on the debug info: <0/1>. Default is 0 (off)");
+
+const char emac_version_string[] = "TI DaVinci EMAC Linux version updated 4.0";
+
+/*
+ * L3 Alignment mechanism: The below given macro returns the number of
+ * bytes required to align the given size to a L3 frame 4 byte
+ * boundry. This is typically required to add 2 bytes to the ethernet
+ * frame start to make sure the IP header (L3) is aligned on a 4 byte
+ * boundry
+ */
+static char emac_L3_align[] = { 0x02, 0x01, 0x00, 0x03 };
+
+/* 4 Byte alignment for skb's:
+ *
+ * Currently Skb's dont need to be on a 4 byte boundry, but other OS's
+ * have such requirements Just to make sure we comply if there is any
+ * such requirement on SKB's in future, we align it on a 4 byte
+ * boundry.
+ */
+static char emac_4byte_align[] = { 0x0, 0x03, 0x02, 0x1 };
+
+/* debug tracing */
+static int emac_link_status = 1;
+static int emac_debug_mode;
+
+/* global variables required during initialization */
+static int g_link_speed;	/* 0=auto negotiate, 100=100mbps, 10=10mbps */
+static int g_link_mode;	/* 0=Auto Negotiate, Full Duplex = 3;
+				 *Half Duplex = 2 Unknown = 1 */
+static int g_init_enable_flag;
+
+/* global device array */
+static struct net_device *emac_net_dev[EMAC_MAX_INSTANCES];
+struct net_device *last_emac_device;
+int emac_devices_installed;	/* number of EMAC instances */
+static struct proc_dir_entry *gp_stats_file;	/* proc entries */
+static char emac_cfg[EMAC_MAX_INSTANCES][200];
+
+/* clock frequency for EMAC */
+static struct clk *emac_clk;
+static unsigned long emac_bus_frequency;
+
+/* MAC ethernet address string in 00:00:00:00:00:00 format */
+static unsigned char emac_eth_string[20] = "deadbeaf";
+
+static const char emac_ddcversion_string[] = "EMAC DDC version 0.5";
+static u32 emac_debug;	/* no debug flags by default */
+static u32 emac_wrapper_ptr = EMAC_WRAPPER_RAM_ADDR;
+
+static int emac_dev_tx(struct sk_buff *skb, struct net_device *netdev);
+static irqreturn_t emac_hal_isr(int irq, void *dev_id);
+static void *emac_net_alloc_rx_buf(struct emac_dev_s *dev, int buf_size,
+				   void **data_token,
+				   u32 channel, void *alloc_args);
+static int emac_net_free_rx_buf(struct emac_dev_s *dev, void *buffer,
+				void *data_token,
+				u32 channel, void *free_args);
+static int emac_net_tx_complete(struct emac_dev_s *dev,
+				void **net_data_tokens,
+				int num_tokens, u32 channel);
+static int emac_net_rx_cb(struct emac_dev_s *dev,
+				struct net_pkt_obj *net_pkt_list,
+				void *rx_args);
+static int emac_poll(struct napi_struct *napi, int budget);
+#ifdef CONFIG_NET_POLL_CONTROLLER
+static void emac_poll_controller(struct net_device *dev);
+#endif
+
+/* net device related private function prototypes */
+static int emac_dev_init(struct net_device *netdev);
+static int emac_dev_open(struct net_device *dev);
+static int emac_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd);
+static int emac_dev_close(struct net_device *netdev);
+static void emac_dev_mcast_set(struct net_device *netdev);
+static void emac_tx_timeout(struct net_device *netdev);
+static struct net_device_stats *emac_dev_get_net_stats(struct net_device
+						       *dev);
+
+/* internal function prototypes */
+static int __init emac_p_detect_manual_cfg(int, char *, int);
+int emac_p_get_version(char *buf, char **start, off_t offset,
+			      int count, int *eof, void *data);
+int emac_p_update_statistics(struct net_device *netdev);
+int emac_p_reset_statistics(struct net_device *netdev);
+static int emac_p_dev_enable(struct emac_dev_s *dev);
+static int emac_p_dev_disable(struct emac_dev_s *dev);
+static void emac_p_tick_timer_expiry(struct emac_dev_s *dev);
+static int emac_dev_set_mac_addr(struct net_device *netdev, void *addr);
+
+/* function prototype for emac_p_tick_timer_expiry() function as per
+ * linux timer API */
+typedef void (*timer_tick_func) (unsigned long);
+
+/* DDA function table */
+static int emac_control_cb(struct emac_dev_s *dev, int cmd,
+			   void *cmd_arg, void *param);
+
+/* function prototypes */
+static int emac_send(struct emac_dev_s *dev, struct net_pkt_obj *pkt,
+		     int channel, bool send_args);
+
+static int emac_tick(struct emac_dev_s *dev, void *tick_args);
+static int emac_pkt_process(struct emac_dev_s *dev, int *pkts_pending,
+			    void *pkt_args);
+static int emac_pkt_process_end(struct emac_dev_s *dev, void *proc_args);
+static int emac_tx_bdproc(struct emac_dev_s *dev, u32 channel, u32 *more_pkts,
+			  bool *is_eoq);
+static int emac_rx_bdproc(struct emac_dev_s *dev, u32 channel,
+				int *more_pkts);
+
+#ifdef EMAC_MULTIFRAGMENT
+static void emac_add_bdto_rx_queue(struct emac_dev_s *dev,
+				struct emac_rx_cppi_ch_t *rx_cppi,
+				struct emac_rx_bd *sop_bd,
+				struct emac_rx_bd *eop_bd,
+				u32 *buffer,
+				void **buf_token, u32 num_bd);
+#else
+static void emac_add_bdto_rx_queue(struct emac_dev_s *dev,
+				struct emac_rx_cppi_ch_t *rx_cppi,
+				struct emac_rx_bd *curr_bd, char *buffer,
+				void *buf_token);
+#endif
+
+static int emac_update_phy_status(struct emac_dev_s *dev);
+static int emac_init(struct emac_dev_s *dev, struct emac_init_config 
*init_cfg);
+static int emac_de_init(struct emac_dev_s *dev, void *param);
+static int emac_open(struct emac_dev_s *dev, void *param);
+static int emac_close(struct emac_dev_s *dev, void *param);
+int emac_control(struct emac_dev_s *dev, int cmd, void *cmd_arg,
+			void *param);
+static int emac_ch_open(struct emac_dev_s *dev, struct emac_ch_info *ch_info,
+			void *ch_open_args);
+static int emac_ch_close(struct emac_dev_s *dev, int channel,
+			 int direction, void *ch_close_args);
+static int emac_wait_for_teardown_complete(struct emac_dev_s *dev,
+					u32 channel,
+					enum net_ch_dir direction,
+					bool blocking);
+static int emac_enable_channel(struct emac_dev_s *dev, u32 channel,
+				u32 direction);
+static int emac_disable_channel(struct emac_dev_s *dev, u32 channel,
+				enum net_ch_dir direction);
+static int emac_init_tx_channel(struct emac_dev_s *dev,
+				struct emac_ch_info *ch_info,
+				void *ch_open_args);
+static int emac_init_rx_channel(struct emac_dev_s *dev,
+				struct emac_ch_info *ch_info,
+				void *ch_open_args);
+static int emac_un_init_tx_channel(struct emac_dev_s *dev, u32 channel,
+				   void *ch_close_args);
+static int emac_un_init_rx_channel(struct emac_dev_s *dev, u32 channel,
+				   void *ch_close_args);
+static void emac_set_mac_address(struct emac_dev_s *dev, u32 channel,
+				char *mac_addr);
+static void emac_ddcifcnt_clear(struct emac_dev_s *dev);
+static void emac_ddcifcnt_updt(struct emac_dev_s *dev);
+static void emac_ddcphycnt(struct emac_dev_s *dev, u32 *cmd_arg);
+
+/* string to ethernet address conversion */
+static void emac_str_to_ethaddr(unsigned char *ea, unsigned char *str)
+{
+	int i;
+	unsigned char num;
+
+	for (i = 0; i < 6; i++) {
+		if ((*str == '.') || (*str == ':'))
+			str++;
+		num = emac_str_to_hexnum(*str) << 4;
+		++str;
+		num |= (emac_str_to_hexnum(*str));
+		++str;
+		ea[i] = num;
+	}
+}
+
+static int emac_cfg_build(void)
+{
+	static int cfg_instance;
+	sprintf(emac_cfg[cfg_instance],
+		"%d:%x:%d:%d:%u:%d:%d:%d:%d:%d:%d:%d:%d:%d"
+		":%d:%d:%x:%d:%d:%u:%u:%x:%d",
+		cfg_instance, EMAC_BASE_ADDR,
+		EMAC_INTERRUPT, 0, EMAC_BUS_FREQUENCY,
+		g_link_speed, g_link_mode, EMAC_DEFAULT_PROMISCOUS_ENABLE,
+		EMAC_DEFAULT_BROADCAST_ENABLE,
+		EMAC_DEFAULT_MULTICAST_ENABLE,
+		EMAC_DEFAULT_MAX_FRAME_SIZE,
+		EMAC_DEFAULT_TX_NUM_BD,
+		EMAC_DEFAULT_TX_MAX_SERVICE, EMAC_DEFAULT_RX_NUM_BD,
+		EMAC_DEFAULT_RX_MAX_SERVICE, 0,
+		EMAC_MDIO_BASE_ADDR, 0, 0,
+		EMAC_BUS_FREQUENCY, EMAC_MDIO_FREQUENCY, EMAC_PHY_MASK, 10);
+
+	DBG("Driver Config:\n%s\n", emac_cfg[cfg_instance]);
+
+	cfg_instance++;
+
+	return 0;
+}
+
+/*
+ * cmdline param format: dm6446eth=mac:00.11.22.33.44.55
+ */
+static int emac_cmdline_mac_setup(char *str)
+{
+	/* The first char passed from the bootloader is '=', so ignore it */
+	strcpy(&emac_eth_string[0], &str[1]);
+
+	printk(KERN_INFO"TI DaVinci EMAC: Kernel Boot params Eth address: %s\n",
+	       emac_eth_string);
+
+	return (1);
+}
+__setup("eth", emac_cmdline_mac_setup);
+
+static int emac_cfg_probe(void)
+{
+	/* for DaVinci there is only 1 EMAC instance */
+	if (emac_cfg_build())
+		return -1;
+
+	return 0;
+}
+
+/*
+ * DDA Callback functions
+ */
+
+/* emac_control_cb - ioctl function to be called by the DDC */
+static int emac_control_cb(struct emac_dev_s *dev, int cmd,
+			   void *cmd_arg, void *param)
+{
+	switch (cmd) {
+	case EMAC_IOCTL_TIMER_START:
+	/*
+	 * cmd will directly have the timer period
+	 * of the periodic timer, param not used
+	 * asks for milliSecs. So calculate ticks
+	 * from ticks per 1000 mSec
+	 */
+	{
+		struct timer_list *p_timer = &dev->periodic_timer;
+		dev->periodic_ticks =
+			(EMAC_TICKS_PER_SEC * (int)cmd_arg) / 1000;
+		p_timer->expires = jiffies + dev->periodic_ticks;
+		add_timer(&dev->periodic_timer);
+		dev->timer_active = TRUE;
+	}
+		break;
+	case EMAC_IOCTL_TIMER_STOP:
+		/* cmd and param not used */
+		if (dev->timer_active == TRUE) {
+			del_timer_sync(&dev->periodic_timer);
+			dev->timer_active = FALSE;
+		}
+		break;
+	case EMAC_IOCTL_STATUS_UPDATE:
+	/* cmd_arg will point to status structure,
+	 *param not used  */
+	{
+		struct net_device *netdev = dev->owner;
+
+		struct emac_status *status = &dev->ddc_status;
+		dev->ddc_status = *((struct emac_status *) cmd_arg);
+		if ((status->hw_status & EMAC_TX_HOST_ERROR) ==
+			EMAC_TX_HOST_ERROR)
+				ERR("TX Host Error. Transmit Stopped %s\n",
+					netdev->name);
+
+		if ((status->hw_status & EMAC_RX_HOST_ERROR) ==
+			EMAC_RX_HOST_ERROR)
+				ERR("RX Host Error. Receive Stopped %s\n",
+					netdev->name);
+
+		if (status->phy_linked) {
+			/* link ON */
+			if (!netif_carrier_ok(netdev))
+				netif_carrier_on(netdev);
+			dev->link_speed =
+				((status->phy_speed == 100) ?
+					100000000 : 10000000);
+			dev->link_mode =
+				((status->
+				phy_duplex == PHY_DUPLEX_FULL) ?
+					PHY_DUPLEX_FULL :
+					PHY_DUPLEX_HALF);
+
+			/* reactivate the transmit queue if it
+			 *is stopped */
+			if (netif_running(netdev) &&
+				netif_queue_stopped(netdev))
+				netif_wake_queue(netdev);
+		} else {
+				/* link OFF */
+				if (netif_carrier_ok(netdev)) {
+						/* do we need to register
+						 *synchronization issues with
+						 *stats here. */
+					dev->link_speed = 100000000;
+					dev->link_mode = 1;
+					netif_carrier_off(netdev);
+				}
+				if (!netif_queue_stopped(netdev))
+						/* so that kernel does not
+						 *keep on xmiting pkts. */
+					netif_stop_queue(netdev);
+		}
+
+		if (emac_link_status)
+			DBG("%s, PhyNum %d,  %s, %s, %s\n",
+				((struct net_device *)dev->owner)->name,
+				status->phy_num,
+				((status->phy_duplex == PHY_DUPLEX_FULL) ?
+				 "Full Duplex" : "Half Duplex"),
+				((status->phy_speed == 100) ?
+				 "100 Mbps" : "10 Mbps"),
+				((status->phy_linked) ?
+				 "Linked" : "NO LINK"));
+	}
+		break;
+	case EMAC_IOCTL_MIB64_CNT_TIMER_START:
+	/*
+	 * cmd will directly have the timer period of the
+	 * periodic timer, param not used
+	 * asks for milli_secs. so calculate ticks
+	 * from ticks per 1000 m_sec
+	 */
+	{
+		struct timer_list *p_timer = &dev->mib_timer;
+
+		dev->mib_ticks =
+			(EMAC_TICKS_PER_SEC * (int)cmd_arg) / 1000;
+		p_timer->expires = jiffies + dev->mib_ticks;
+		add_timer(p_timer);
+		dev->mib_timer_active = TRUE;
+	}
+	break;
+	case EMAC_IOCTL_MIB64_CNT_TIMER_STOP:
+		/* cmd_arg and param not used */
+		if (dev->mib_timer_active == TRUE) {
+			del_timer_sync(&dev->mib_timer);
+			dev->mib_timer_active = FALSE;
+		}
+		break;
+	default:
+		DBG("Unhandled ioctl code %d\n", cmd);
+		break;
+	}
+
+	return EMAC_SUCCESS;
+}
+
+/**
+ *
+ * emacEndGetConfig - Extract configuration for given unit number/instance
+ *
+ * This function gets the configuration information from the
+ * configuration service or by some means for the given unit
+ * number/emac instance
+ *
+ * Note: For debug/default, static information is obtained from the
+ * header file
+ *
+ * RETURNS: OK or ERROR.
+ */
+static int emac_net_get_config(struct emac_dev_s *dev)
+{
+	struct emac_init_config *i_cfg = &dev->init_cfg;
+	struct emac_ch_info *tx_ch_cfg = &dev->tx_ch_info[0];
+	struct emac_ch_info *rx_ch_cfg = &dev->rx_ch_info[0];
+	int speed, duplex, extra;
+	char local_string_val[200];
+	char *local_string = NULL;
+	char *tok;
+	char *p_holder = NULL;
+
+	local_string = emac_cfg[(dev->instance_num < EMAC_MAX_INSTANCES)?
+					dev->instance_num : 0];
+
+	strcpy(local_string_val, local_string);
+	local_string = local_string_val;
+	p_holder = NULL;
+	tok = (char *)strsep(&local_string, ":");
+	if (tok == NULL)
+		return -1;
+
+	i_cfg->inst_id = EMAC_TOKEN_GET_INTEGER;
+	EMAC_TOKEN_PARSE(&local_string);
+	DBG("i_cfg->instId=%d", i_cfg->inst_id);
+
+	i_cfg->base_address = EMAC_TOKEN_GET_HEX;
+	EMAC_TOKEN_PARSE(&local_string);
+	DBG("\ni_cfg->baseAddress=%08X", i_cfg->base_address);
+
+	i_cfg->intr_line = EMAC_TOKEN_GET_INTEGER;
+	EMAC_TOKEN_PARSE(&local_string);
+	DBG("\ni_cfg->intrLine=%d", i_cfg->intr_line);
+
+	i_cfg->reset_line = EMAC_TOKEN_GET_INTEGER;
+	EMAC_TOKEN_PARSE(&local_string);
+	DBG("\ni_cfg->resetLine=%d", i_cfg->reset_line);
+
+	i_cfg->emac_bus_frequency = EMAC_TOKEN_GET_INTEGER;
+	EMAC_TOKEN_PARSE(&local_string);
+	DBG("\ni_cfg->emacBusFrequency=%d", i_cfg->emac_bus_frequency);
+
+	speed = EMAC_TOKEN_GET_INTEGER;
+	EMAC_TOKEN_PARSE(&local_string);
+	DBG("\nspeed=%d", speed);
+
+	duplex = EMAC_TOKEN_GET_INTEGER;
+	EMAC_TOKEN_PARSE(&local_string);
+	DBG("\nduplex=%d", duplex);
+
+	i_cfg->rx_cfg.promiscous_enable = EMAC_TOKEN_GET_INTEGER;
+	EMAC_TOKEN_PARSE(&local_string);
+	DBG("\ni_cfg->rxCfg.promiscousEnable=%d",
+	    i_cfg->rx_cfg.promiscous_enable);
+
+	i_cfg->rx_cfg.broadcast_enable = EMAC_TOKEN_GET_INTEGER;
+	EMAC_TOKEN_PARSE(&local_string);
+	DBG("\ni_cfg->rxCfg.broadcastEnable=%d",
+	    i_cfg->rx_cfg.broadcast_enable);
+
+	i_cfg->rx_cfg.multicast_enable = EMAC_TOKEN_GET_INTEGER;
+	EMAC_TOKEN_PARSE(&local_string);
+	DBG("\ni_cfg->rxCfg.multicastEnable=%d",
+	    i_cfg->rx_cfg.multicast_enable);
+
+	i_cfg->rx_cfg.max_rx_pkt_length = EMAC_TOKEN_GET_INTEGER;
+	EMAC_TOKEN_PARSE(&local_string);
+	DBG("\ni_cfg->rxCfg.maxRxPktLength=%d",
+	    i_cfg->rx_cfg.max_rx_pkt_length);
+
+	tx_ch_cfg->num_bd = EMAC_TOKEN_GET_INTEGER;
+	EMAC_TOKEN_PARSE(&local_string);
+	DBG("\ntx_ch_cfg->num_bd=%d", tx_ch_cfg->num_bd);
+
+	tx_ch_cfg->service_max = EMAC_TOKEN_GET_INTEGER;
+	EMAC_TOKEN_PARSE(&local_string);
+	DBG("\ntx_ch_cfg->service_max=%d", tx_ch_cfg->service_max);
+
+	rx_ch_cfg->num_bd = EMAC_TOKEN_GET_INTEGER;
+	EMAC_TOKEN_PARSE(&local_string);
+	DBG("\nrx_ch_cfg->num_bd=%d", rx_ch_cfg->num_bd);
+
+	rx_ch_cfg->service_max = EMAC_TOKEN_GET_INTEGER;
+	EMAC_TOKEN_PARSE(&local_string);
+	DBG("\nrx_ch_cfg->service_max=%d", rx_ch_cfg->service_max);
+
+	extra = EMAC_TOKEN_GET_INTEGER;
+	EMAC_TOKEN_PARSE(&local_string);
+	DBG("\nextra=%d", extra);
+
+	i_cfg->mdio_base_address = EMAC_TOKEN_GET_HEX;
+	EMAC_TOKEN_PARSE(&local_string);
+	DBG("\ni_cfg->mdioBaseAddress=%08X", i_cfg->mdio_base_address);
+
+	i_cfg->mdio_intr_line = EMAC_TOKEN_GET_INTEGER;
+	EMAC_TOKEN_PARSE(&local_string);
+	DBG("\ni_cfg->mdioIntrLine=%d", i_cfg->mdio_intr_line);
+
+	i_cfg->mdio_reset_line = EMAC_TOKEN_GET_INTEGER;
+	EMAC_TOKEN_PARSE(&local_string);
+	DBG("\ni_cfg->mdioResetLine=%d", i_cfg->mdio_reset_line);
+
+	i_cfg->mdio_bus_frequency = EMAC_TOKEN_GET_INTEGER;
+	EMAC_TOKEN_PARSE(&local_string);
+	DBG("\ni_cfg->MdioBusFrequency=%d", i_cfg->mdio_bus_frequency);
+
+	i_cfg->mdio_clock_frequency = EMAC_TOKEN_GET_INTEGER;
+	EMAC_TOKEN_PARSE(&local_string);
+	DBG("\ni_cfg->MdioClockFrequency=%d", i_cfg->mdio_clock_frequency);
+
+	i_cfg->phy_mask = EMAC_TOKEN_GET_HEX;
+	EMAC_TOKEN_PARSE(&local_string);
+	DBG("\ni_cfg->PhyMask=%08X", i_cfg->phy_mask);
+
+	i_cfg->mdio_tick_msec = EMAC_TOKEN_GET_INTEGER;
+	DBG("\ni_cfg->MdioTickMSec=%d", i_cfg->mdio_tick_msec);
+	DBG("\n");
+
+	i_cfg->mib64cnt_msec = CONFIG_EMAC_MIB_TIMER_TIMEOUT;
+	rx_ch_cfg->buf_size = i_cfg->rx_cfg.max_rx_pkt_length;
+	dev->rx_buf_offset =
+	    EMAC_L3_ALIGN(extra) + EMAC_DEFAULT_EXTRA_RXBUF_SIZE;
+	dev->rx_buf_size = (rx_ch_cfg->buf_size + dev->rx_buf_offset);
+
+	/* align skb's on 4 byte boundry - no hard requirement currently - done
+	 * for future use
+	 */
+	dev->rx_buf_size += EMAC_4BYTE_ALIGN(dev->rx_buf_size);
+
+	/* determine phy speed/duplex mode - to be built as per MDIO
+	 *module requirements */
+	if (speed == CONFIG_EMAC_NOPHY) {
+		i_cfg->phy_mode = SNWAY_NOPHY;
+	} else {
+		if ((speed == 0) && (duplex == PHY_DUPLEX_AUTO)) {
+			i_cfg->phy_mode = SNWAY_AUTOALL;
+		} else if (speed == 10) {
+			if (duplex == PHY_DUPLEX_HALF)
+				i_cfg->phy_mode = SNWAY_HD10;
+			else if (duplex == PHY_DUPLEX_FULL)
+				i_cfg->phy_mode = SNWAY_FD10;
+			else
+				i_cfg->phy_mode = SNWAY_HD10 | SNWAY_FD10;
+		} else if (speed == 100) {
+			if (duplex == PHY_DUPLEX_HALF)
+				i_cfg->phy_mode = SNWAY_HD100;
+			else if (duplex == PHY_DUPLEX_FULL)
+				i_cfg->phy_mode = SNWAY_FD100;
+			else
+				i_cfg->phy_mode = SNWAY_HD100 | SNWAY_FD100;
+		} else {
+			if (duplex == PHY_DUPLEX_FULL)
+				i_cfg->phy_mode = SNWAY_FD10 | SNWAY_FD100;
+			else
+				i_cfg->phy_mode = SNWAY_HD10 | SNWAY_HD100;
+		}
+	}
+
+	dev->vlan_enable = EMAC_DEFAULT_VLAN_ENABLE;
+	i_cfg->num_tx_channels = EMAC_DEFAULT_NUM_TX_CHANNELS;
+	i_cfg->num_rx_channels = EMAC_DEFAULT_NUM_RX_CHANNELS;
+	i_cfg->MLink_mask = EMAC_DEFAULT_MLINK_MASK;
+	i_cfg->rx_cfg.pass_crc = EMAC_DEFAULT_PASS_CRC;
+	i_cfg->rx_cfg.qos_enable = EMAC_DEFAULT_QOS_ENABLE;
+	i_cfg->rx_cfg.no_buffer_chaining = EMAC_DEFAULT_NO_BUFFER_CHAINING;
+	i_cfg->rx_cfg.copy_maccontrol_frames_enable =
+			EMAC_DEFAULT_COPY_MAC_CONTROL_FRAMES_ENABLE;
+	i_cfg->rx_cfg.copy_short_frames_enable =
+			EMAC_DEFAULT_COPY_SHORT_FRAMES_ENABLE;
+	i_cfg->rx_cfg.copy_error_frames_enable =
+			EMAC_DEFAULT_COPY_ERROR_FRAMES_ENABLE;
+	i_cfg->rx_cfg.promiscous_channel = EMAC_DEFAULT_PROMISCOUS_CHANNEL;
+	i_cfg->rx_cfg.broadcast_channel = EMAC_DEFAULT_BROADCAST_CHANNEL;
+	i_cfg->rx_cfg.multicast_channel = EMAC_DEFAULT_MULTICAST_CHANNEL;
+	i_cfg->rx_cfg.buffer_offset = EMAC_DEFAULT_BUFFER_OFFSET;
+	i_cfg->mac_cfg.p_type = EMAC_TXPRIO_FIXED;
+	i_cfg->mac_cfg.tx_short_gap_enable = FALSE;
+
+	if (speed == 1000)
+		i_cfg->mac_cfg.giga_bit_enable = TRUE;
+	else
+		i_cfg->mac_cfg.giga_bit_enable = FALSE;
+
+	i_cfg->mac_cfg.tx_pacing_enable = EMAC_DEFAULT_TX_PACING_ENABLE;
+	i_cfg->mac_cfg.mii_enable = EMAC_DEFAULT_MII_ENABLE;
+	i_cfg->mac_cfg.tx_flow_enable = EMAC_DEFAULT_TX_FLOW_ENABLE;
+	i_cfg->mac_cfg.rx_flow_enable = EMAC_DEFAULT_RX_FLOW_ENABLE;
+	i_cfg->mac_cfg.loopback_enable = EMAC_DEFAULT_LOOPBACK_ENABLE;
+	i_cfg->mac_cfg.full_duplex_enable = EMAC_DEFAULT_FULL_DUPLEX_ENABLE;
+	i_cfg->mac_cfg.tx_interrupt_disable = EMAC_DEFAULT_TX_INTERRUPT_DISABLE;
+	tx_ch_cfg->ch_num = EMAC_DEFAULT_TX_CHANNEL;
+	tx_ch_cfg->ch_dir = NET_CH_DIR_TX;
+	tx_ch_cfg->ch_state = NET_CH_UNINITIALIZED;
+	rx_ch_cfg->ch_num = EMAC_DEFAULT_RX_CHANNEL;
+	rx_ch_cfg->ch_dir = NET_CH_DIR_RX;
+	rx_ch_cfg->ch_state = NET_CH_UNINITIALIZED;
+
+	/* module control EWrap base address for DaVinci */
+	i_cfg->e_wrap_base_address = EMAC_WRAPPER_REGS_ADDR;
+
+	DBG("\n");
+	return 0;
+}
+
+/* detect manual config */
+static int __init emac_p_detect_manual_cfg(int link_speed, char *link_mode,
+					   int debug)
+{
+	if (debug == 1) {
+		emac_debug_mode = 1;
+		DBG("Enabled debug print.\n");
+	}
+
+	if ((link_speed == 0) && (!strcmp(link_mode, "auto"))) {
+		/* Auto negotiation */
+		g_link_speed = 0;
+		g_link_mode = 0;
+		DBG("auto negotiation selected\n");
+	}
+
+	if (!link_speed || (link_speed != 10 && link_speed != 100)) {
+		g_link_speed = 0;
+		g_link_mode = 0;
+		DBG("Invalid or No value of link speed specified,"
+		    "defaulting to auto negotiation .\n");
+	}
+
+	if (!link_mode
+	    || (!strcmp(link_mode, "fd") && !strcmp(link_mode, "hd"))) {
+		g_link_speed = 0;
+		g_link_mode = 0;
+		DBG("Invalid or No value of link mode specified,"
+		    "defaulting to auto mode.\n");
+	}
+
+	if ((link_speed == 10) && (!strcmp(link_mode, "fd"))) {
+		g_link_speed = 10;
+		g_link_mode = 3;
+	} else if ((link_speed == 10) && (!strcmp(link_mode, "hd"))) {
+		g_link_speed = 10;
+		g_link_mode = 2;
+	} else if ((link_speed == 100) && (!strcmp(link_mode, "fd"))) {
+		g_link_speed = 100;
+		g_link_mode = 3;
+	} else if ((link_speed == 100) && (!strcmp(link_mode, "hd"))) {
+		g_link_speed = 100;
+		g_link_mode = 2;
+	} else {
+		g_link_speed = 0;
+		g_link_mode = 0;
+	}
+
+	DBG("Link is set to the speed of"
+	    "%s speed and %s mode.\n",
+	    ((g_link_speed ==
+	      0) ? "auto" : ((g_link_speed == 100) ? "100" : "10")),
+	    ((g_link_mode ==
+	      0) ? "auto" : ((g_link_mode == 2) ? "half" : "full")));
+
+	return 0;
+}
+
+int emac_p_reset_statistics(struct net_device *netdev)
+{
+	struct emac_dev_s *dev = NETDEV_PRIV(netdev);
+
+	memset(&dev->device_mib, 0, sizeof(struct emac_hw_statistics));
+	memset(&dev->device_stats, 0, sizeof(struct emac_drv_stats));
+	memset(&dev->net_dev_stats, 0, sizeof(struct net_device_stats));
+
+	/* clear statistics */
+	if (emac_control(dev, EMAC_IOCTL_CLR_STATISTICS, NULL, NULL)
+	    != EMAC_SUCCESS) {
+		ERR("Error clearing statistics in DDC for %s\n", netdev->name);
+		return -1;
+	}
+
+	return 0;
+}
+
+int emac_p_update_statistics(struct net_device *netdev)
+{
+	unsigned long rx_hal_errors = 0;
+	unsigned long rx_hal_discards = 0;
+	unsigned long tx_hal_errors = 0;
+	unsigned long if_out_discards = 0;
+	unsigned long if_in_discards = 0;
+	unsigned long if_out_errors = 0;
+	unsigned long if_in_errors = 0;
+	struct emac_dev_s *dev = NETDEV_PRIV(netdev);
+	struct emac_hw_statistics *p_device_mib = &dev->device_mib;
+	struct emac_hw_statistics local_mib;
+	struct emac_hw_statistics *p_local_mib = &local_mib;
+	struct net_device_stats *p_net_dev_stats = &dev->net_dev_stats;
+	int dev_mib_elem_count = 0;
+
+	/* do not access the hardware if it is in the reset state. */
+	if (!test_bit(0, &dev->set_to_close)) {
+		/* get hardware statistics from DDC */
+		if (emac_control(dev, EMAC_IOCTL_GET_STATISTICS,
+			(void *)p_local_mib, NULL)
+				!= EMAC_SUCCESS) {
+			ERR("Error getting statistics for %s\n", netdev->name);
+
+			return -1;
+		}
+
+		dev_mib_elem_count =
+		sizeof(struct emac_hw_statistics) / sizeof(unsigned long);
+
+		/*
+		 * Update the history of the stats. This takes care of
+		 * any reset of the device and stats that might have
+		 * taken place during the life time of the driver.
+		 */
+		while (dev_mib_elem_count--)
+			*((unsigned long *)p_device_mib + dev_mib_elem_count) =
+					*((unsigned long *)p_local_mib +
+					dev_mib_elem_count);
+	}
+
+	/* RFC2665, section 3.2.7, page 9 */
+	rx_hal_errors =
+			p_device_mib->if_in_fragments +
+			p_device_mib->if_in_crcerrors +
+			p_device_mib->if_in_align_code_errors +
+			p_device_mib->if_in_jabber_frames;
+
+	/* RFC2233 */
+	rx_hal_discards = p_device_mib->if_rx_dmaoverruns;
+
+	/* RFC2665, section 3.2.7, page 9 */
+	tx_hal_errors =
+			p_device_mib->if_excessive_collision_frames +
+			p_device_mib->if_late_collisions +
+			p_device_mib->if_carrier_sense_errors +
+			p_device_mib->if_out_underrun;
+
+	/* if not set, the short frames (< 64 bytes) are considered as
+	errors */
+	if (dev->init_cfg.rx_cfg.copy_short_frames_enable == FALSE)
+		rx_hal_errors += p_device_mib->if_in_undersized_frames;
+
+	/* All frames greater than max rx frame length set in hardware
+	*should be considered error frames RFC2665, section 3.2.7,
+	*page 9. */
+	rx_hal_errors += p_device_mib->if_in_oversized_frames;
+
+	/* if not in promiscous, then non addr matching frames are discarded */
+	/* EMAC 2.0 manual section 2.8.1.14 */
+	if (dev->init_cfg.rx_cfg.promiscous_enable == FALSE)
+		if_in_discards += p_device_mib->if_in_filtered_frames;
+
+	/* total rx discards = hal discards */
+	if_in_discards = rx_hal_discards;
+	p_net_dev_stats->rx_dropped = rx_hal_discards;
+	p_net_dev_stats->rx_crc_errors = p_device_mib->if_in_crcerrors;
+	p_net_dev_stats->rx_frame_errors =
+			p_device_mib->if_in_align_code_errors;
+	p_net_dev_stats->multicast = p_device_mib->if_in_multicasts;
+	if_in_errors = rx_hal_errors;
+	if_out_errors = tx_hal_errors;
+	if_out_discards = p_net_dev_stats->tx_dropped;
+
+	/* let us update the net device stats struct. to be updated in
+	the later releases. */
+	dev->net_dev_stats.rx_errors = if_in_errors;
+	dev->net_dev_stats.collisions = p_device_mib->if_collision_frames;
+	dev->net_dev_stats.tx_carrier_errors =
+			p_device_mib->if_carrier_sense_errors;
+
+	return 0;
+}
+
+int emac_p_get_version(char *buf, char **start, off_t offset, int count,
+			      int *eof, void *data)
+{
+	int len = 0;
+
+	len += sprintf(buf + len, "Texas Instruments : %s\n",
+		       emac_version_string);
+	return len;
+}
+
+/* tick timer */
+static void emac_p_tick_timer_expiry(struct emac_dev_s *dev)
+{
+	struct timer_list *p_timer = &dev->periodic_timer;
+
+	if (test_bit(0, &dev->set_to_close))
+		return;
+
+	if (dev->timer_active == TRUE) {
+		emac_tick(dev, NULL);
+		/* restart the timer */
+		p_timer->expires = jiffies + dev->periodic_ticks;
+		add_timer(p_timer);
+	}
+}
+
+/* mib timer */
+static void emac_p_mib_timer_expiry(struct emac_dev_s *dev)
+{
+	struct timer_list *p_timer = &dev->mib_timer;
+
+	if (test_bit(0, &dev->set_to_close))
+		return;
+
+	if (dev->mib_timer_active == TRUE) {
+		emac_control(dev, EMAC_IOCTL_IF_PARAMS_UPDT, NULL, NULL);
+		/* restart the timer */
+		p_timer->expires = jiffies + dev->mib_ticks;
+		add_timer(p_timer);
+	}
+}
+
+/*
+ * Device enable/disable functions
+ */
+
+/**
+ * enable the device - init TX/RX channels and open DDC
+ */
+static int emac_p_dev_enable(struct emac_dev_s *dev)
+{
+	int ret_code;
+	struct net_device *netdev = dev->owner;
+
+	dev->set_to_close = 0;
+
+	/* create a TX channel */
+	ret_code = emac_ch_open(dev, &dev->tx_ch_info[0], NULL);
+
+	if (ret_code != EMAC_SUCCESS) {
+		ERR("%s error: Error %08X from EMAC TX Channel Open()\n",
+		    netdev->name, ret_code);
+		return (-1);
+	}
+
+	/* create a RX channel - note that last param contains mac address */
+	ret_code =
+	    emac_ch_open(dev, &dev->rx_ch_info[0], (void *)&dev->mac_addr[0]);
+	if (ret_code != EMAC_SUCCESS) {
+		ERR("%s error: Error %08X from EMAC RX Channel Open()\n",
+		    netdev->name, ret_code);
+		return -1;
+	}
+	/* open DDC instance */
+	ret_code = emac_open(dev, NULL);
+	if (ret_code != EMAC_SUCCESS) {
+		ERR("%s error: Error %08X from EMAC Open()\n",
+		    netdev->name, ret_code);
+		return -1;
+	}
+
+	return 0;
+}
+
+/* disable the device - teardown chanels and close DDC */
+static int emac_p_dev_disable(struct emac_dev_s *dev)
+{
+	int ret_code;
+	struct net_device *netdev = dev->owner;
+
+	/* inform the upper layers. */
+	netif_stop_queue(dev->owner);
+
+	/* prepare to close */
+	set_bit(0, &dev->set_to_close);
+
+	/* closing the DDC instance will close all channels also */
+	ret_code = emac_close(dev, NULL);
+
+	if (ret_code != EMAC_SUCCESS) {
+		ERR("%s error: Error %08X from EMAC Close()\n",
+		    netdev->name, ret_code);
+		return -1;
+	} else {
+		/* DDC should turn off the timer, but just in case */
+		if (dev->timer_active != FALSE) {
+			del_timer_sync(&dev->periodic_timer);
+			dev->timer_active = FALSE;
+		}
+
+		DBG("Device %s Closed.\n", netdev->name);
+		dev->device_stats.start_tick = jiffies;
+		dev->link_speed = 100000000;
+		dev->link_mode = 1;
+		netif_carrier_off(netdev);
+	}
+	return 0;
+}
+
+/*
+ * Net Device functions
+ */
+
+/* get statistics */
+static struct net_device_stats *emac_dev_get_net_stats(struct net_device
+						       *netdev)
+{
+	struct emac_dev_s *dev = NETDEV_PRIV(netdev);
+	emac_p_update_statistics(netdev);
+	return &dev->net_dev_stats;
+}
+
+/* set multicast address in the driver */
+static void emac_dev_mcast_set(struct net_device *netdev)
+{
+	struct emac_dev_s *dev = NETDEV_PRIV(netdev);
+
+	if (netdev->flags & IFF_PROMISC) {
+		/* enable promiscous mode */
+		dev->init_cfg.rx_cfg.promiscous_enable = TRUE;
+
+		emac_control(dev,
+			     EMAC_IOCTL_SET_RXCFG,
+			     (void *)&dev->init_cfg.rx_cfg, NULL);
+	} else if ((netdev->flags & IFF_ALLMULTI) ||
+		   (netdev->mc_count > EMAC_DEFAULT_MAX_MULTICAST_ADDRESSES)) {
+		/* enable multicast - disable promiscous */
+		dev->init_cfg.rx_cfg.promiscous_enable = FALSE;
+		dev->init_cfg.rx_cfg.multicast_enable = TRUE;
+		emac_control(dev,
+			     EMAC_IOCTL_SET_RXCFG,
+			     (void *)&dev->init_cfg.rx_cfg, NULL);
+
+		/* enable all multicast addresses */
+		emac_control(dev, EMAC_IOCTL_ALL_MULTI, (void *)
+			     EMAC_ALL_MULTI_SET, NULL);
+	} else if (netdev->mc_count == 0) {
+		/* only unicast mode to be set - clear promiscous and
+		   clear multicast modes */
+		emac_control(dev, EMAC_IOCTL_ALL_MULTI, (void *)
+			     EMAC_ALL_MULTI_CLR, NULL);
+
+		/* disable promiscous and multicast modes */
+		dev->init_cfg.rx_cfg.promiscous_enable = FALSE;
+		dev->init_cfg.rx_cfg.multicast_enable = FALSE;
+		emac_control(dev,
+			     EMAC_IOCTL_SET_RXCFG,
+			     (void *)&dev->init_cfg.rx_cfg, NULL);
+	} else if (netdev->mc_count) {
+		struct dev_mc_list *mc_ptr;
+
+		/* clear multicast list first */
+		emac_control(dev, EMAC_IOCTL_ALL_MULTI, (void *)
+			     EMAC_ALL_MULTI_CLR, NULL);
+
+		/* enable multicast - disable promiscous */
+		dev->init_cfg.rx_cfg.promiscous_enable = FALSE;
+		dev->init_cfg.rx_cfg.multicast_enable = TRUE;
+		emac_control(dev,
+			     EMAC_IOCTL_SET_RXCFG,
+			     (void *)&dev->init_cfg.rx_cfg, NULL);
+
+		/* program multicast address list into EMAC hardware */
+		for (mc_ptr = netdev->mc_list; mc_ptr; mc_ptr = mc_ptr->next)
+			emac_control(dev, EMAC_IOCTL_MULTICAST_ADDR, (void *)
+				     EMAC_MULTICAST_ADD, (void *)
+				     mc_ptr->dmi_addr);
+	} else
+		DBG("%s:No Multicast address to set.\n", netdev->name);
+}
+
+static int emac_dev_set_mac_addr(struct net_device *netdev, void *addr)
+{
+	int ret_code;
+	struct emac_address_params address_params;
+	struct sockaddr *sa = addr;
+	struct emac_dev_s *dev = NETDEV_PRIV(netdev);
+
+	address_params.channel = EMAC_DEFAULT_RX_CHANNEL;
+	address_params.mac_address = sa->sa_data;
+
+	ret_code = emac_control(dev, EMAC_IOCTL_SET_MAC_ADDRESS,
+			(struct emac_address_params *) &address_params, NULL);
+
+	if (ret_code != EMAC_SUCCESS) {
+		ERR("%s error: Error %08X from EMAC TX Channel Open()\n",
+		    netdev->name, ret_code);
+
+		return -EIO;
+	}
+	memcpy(dev->mac_addr, sa->sa_data, netdev->addr_len);
+	memcpy(netdev->dev_addr, sa->sa_data, netdev->addr_len);
+	return 0;
+}
+
+static void emac_tx_timeout(struct net_device *netdev)
+{
+	int ret_code;
+	struct emac_dev_s *dev = NETDEV_PRIV(netdev);
+
+	printk(KERN_NOTICE"EMAC Tx Timeout: Closing TX channel\n");
+	emac_ch_close(dev, dev->tx_ch_info[0].ch_num,
+		dev->tx_ch_info[0].ch_dir, 0);
+
+	printk(KERN_NOTICE"EMAC Tx Timeout: Opening TX channel\n");
+	ret_code = emac_ch_open(dev, &dev->tx_ch_info[0], NULL);
+
+	if (ret_code != EMAC_SUCCESS)
+		ERR("%s error: Error %08X from EMAC TX Channel Open()\n",
+		    netdev->name, ret_code);
+	else
+		ERR("EMAC Tx Timeout: "
+		    "successfully closed and opened channels\n");
+
+	/* update interface statistics */
+	dev->net_dev_stats.tx_errors++;
+}
+
+/**
+ * emac_dev_init
+ *
+ * Returns:
+ *     0 on success, error code otherwise.
+ * Parms:
+ *     dev The structure of the device to be
+ *         init'ed.
+ *
+ * This function completes the initialization of the
+ * device structure and driver.  It reserves the IO
+ * addresses and assignes the device's methods.
+ *
+ */
+static int emac_dev_init(struct net_device *netdev)
+{
+	int cnt, init_status = 0;
+	int ret_code;
+	char *mac_name = NULL;
+	char *mac_string = NULL;
+	char *default_mac_string = NULL;
+	struct emac_dev_s *dev = NETDEV_PRIV(netdev);
+	int instance_num = dev->instance_num;
+
+	/* create mac name */
+	switch (instance_num) {
+	case 0:
+		mac_name = EMAC_MAC_ADDR_A;
+
+		/* we are getting default MAC address from bootloader */
+		if (strcmp(emac_eth_string, "deadbeaf") == 0)
+			default_mac_string = "08:00:28:32:06:08";
+		else
+			default_mac_string = &emac_eth_string[0];
+		break;
+	default:
+		mac_name = "";
+		default_mac_string = "08:00:28:32:06:08";
+		break;
+	}
+	printk(KERN_INFO "TI DaVinci EMAC: MAC address is %s\n",
+	       default_mac_string);
+
+	mac_string = default_mac_string;
+	emac_str_to_ethaddr(dev->mac_addr, mac_string);
+	for (cnt = 0; cnt <= ETH_ALEN; cnt++)
+		netdev->dev_addr[cnt] = dev->mac_addr[cnt];
+
+	dev->set_to_close = 1;
+
+	/* get configuration information for this instance */
+	/* when config service is available, use it */
+	if (emac_net_get_config(dev) != 0) {
+		ERR("Could not fetch configuration information\n");
+		goto emac_dev_init_exit;
+	}
+
+	dev->init_cfg.inst_id = instance_num;
+	dev->drv_state = DRV_CREATED;
+	init_status = 1;	/* instance created */
+
+	/* initialize instance by passing initial configuration struct */
+	ret_code = emac_init(dev, &dev->init_cfg);
+
+	if (ret_code != EMAC_SUCCESS) {
+		ERR("Error %08X from Init()\n", ret_code);
+		goto emac_dev_init_exit;
+	}
+
+	init_status = 2;	/* instance initialized */
+
+	/* init spin lock */
+	spin_lock_init(&dev->tx_lock);
+	spin_lock_init(&dev->rx_lock);
+
+	/* set as per RFC 2665 */
+	dev->link_speed = 100000000;
+	dev->link_mode = 1;
+
+	/* initialize the timers for the net device - the timer will
+	   be started by DDC calling the ioctl on DDA */
+	init_timer(&dev->periodic_timer);
+	dev->periodic_ticks = 0;
+	dev->periodic_timer.expires = 0;
+	dev->timer_active = FALSE;
+	dev->periodic_timer.data = (unsigned long)dev;
+	dev->periodic_timer.function =
+	    (timer_tick_func) emac_p_tick_timer_expiry;
+	init_timer(&dev->mib_timer);
+	dev->mib_timer_active = FALSE;
+	dev->mib_timer.data = (unsigned long)dev;
+	dev->mib_timer.function = (timer_tick_func) emac_p_mib_timer_expiry;
+
+	/* populate the device structure */
+	netdev->addr_len = 6;
+	netdev->open = emac_dev_open;	/*  i.e. start device  */
+	netdev->do_ioctl = emac_ioctl;
+	netdev->hard_start_xmit = emac_dev_tx;
+	netdev->stop = emac_dev_close;
+	netdev->get_stats = emac_dev_get_net_stats;
+	netdev->set_multicast_list = emac_dev_mcast_set;
+	netdev->tx_timeout = emac_tx_timeout;
+	netdev->set_mac_address = emac_dev_set_mac_addr;
+#ifdef CONFIG_NET_POLL_CONTROLLER
+	netdev->poll_controller = emac_poll_controller;
+#endif
+
+	/* reset the broadcast and multicast flags and enable them
+	   based upon configuration of driver */
+	netdev->flags &= ~(IFF_PROMISC | IFF_BROADCAST | IFF_MULTICAST);
+	if (dev->init_cfg.rx_cfg.broadcast_enable == TRUE)
+		netdev->flags |= IFF_BROADCAST;
+	if (dev->init_cfg.rx_cfg.multicast_enable == TRUE)
+		netdev->flags |= IFF_MULTICAST;
+
+	netif_carrier_off(netdev);
+	netdev->irq = dev->init_cfg.intr_line;
+
+	/* request memory region from the kernel */
+	netdev->base_addr = dev->init_cfg.base_address;
+	request_mem_region(netdev->base_addr, EMAC_DEFAULT_EMAC_SIZE,
+			   netdev->name);
+
+	/* if following flag ON then open DDC */
+	if (g_init_enable_flag) {
+		if (emac_p_dev_enable(dev)) {
+			ERR("device could not OPEN\n");
+			goto emac_dev_init_exit;
+		}
+	}
+
+	return 0;
+
+emac_dev_init_exit:
+	/* all resources allocated are freed - call the un-init
+	   sequence on DDC */
+	switch (init_status) {
+	case 2:
+		ret_code = emac_de_init(dev, NULL);
+
+		if (ret_code != EMAC_SUCCESS)
+			ERR("%s: Error %08X from Deinit()\n",
+			    netdev->name, ret_code);
+	default:
+		break;
+	}
+
+	return -1;
+}
+
+/*
+ * Device Open/Close functions
+ */
+
+#if !defined(SA_INTERRUPT)
+#define SA_INTERRUPT	0
+#endif
+
+static int emac_dev_open(struct net_device *netdev)
+{
+	struct emac_dev_s *dev = NETDEV_PRIV(netdev);
+
+	if (!g_init_enable_flag) {
+		if (emac_p_dev_enable(dev)) {
+			ERR("%s error: device could not OPEN\n", netdev->name);
+			return -1;
+		}
+	}
+
+	if (request_irq(dev->irq_line, emac_hal_isr, SA_INTERRUPT,
+			"EMAC", dev)) {
+		printk(KERN_NOTICE"EMAC: Failed to register the irq %d"
+			" for EMAC %s.\n", dev->init_cfg.intr_line,
+			netdev->name);
+		return -1;
+	}
+	if (netif_carrier_ok(netdev))
+		netif_start_queue(netdev);
+	else
+		netif_stop_queue(netdev);
+
+	dev->device_stats.start_tick = jiffies;
+	napi_enable(&dev->napi);
+	printk(KERN_INFO"Started the network queue for %s.\n", netdev->name);
+	return 0;
+}
+
+static int emac_dev_close(struct net_device *netdev)
+{
+	struct emac_dev_s *dev = NETDEV_PRIV(netdev);
+
+	napi_disable(&dev->napi);
+
+	if (!g_init_enable_flag)
+		emac_p_dev_disable(dev);
+
+	/* free ISR */
+	free_irq(dev->init_cfg.intr_line, dev);
+
+	return 0;
+}
+
+static int emac_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd)
+{
+	struct emac_drv_priv_ioctl priv_ioctl;
+	struct emac_dev_s *dev = NETDEV_PRIV(netdev);
+
+	if (cmd == SIOCDEVPRIVATE) {
+		/* copy user data */
+		if (copy_from_user
+		    ((char *)&priv_ioctl, (char *)rq->ifr_data,
+		     sizeof(struct emac_drv_priv_ioctl)))
+			return -EFAULT;
+
+		switch (priv_ioctl.cmd) {
+			/* program type 2/3 address filter */
+		case EMAC_PRIV_FILTERING:
+		{
+			struct emac_type2_3_addr_filter_params filter_params;
+
+			if (copy_from_user
+				((char *)&filter_params,
+				(char *)priv_ioctl.data,
+				sizeof(struct emac_type2_3_addr_filter_params)))
+
+				return -EFAULT;
+
+			if (emac_control(dev,
+					EMAC_IOCTL_TYPE2_3_FILTERING,
+					(struct emac_type2_3_addr_filter_params
+					*) &filter_params, NULL)
+				!= EMAC_SUCCESS) {
+				ERR("Failed to read params");
+				return -EFAULT;
+			}
+			break;
+		}
+		/* read PHY register via MII interface */
+		case EMAC_PRIV_MII_READ:
+		{
+			struct emac_phy_params phy_params;
+			unsigned long irq_flags;
+
+			/* copy user data into local variable */
+			if (copy_from_user((char *)&phy_params,
+				(char *)priv_ioctl.data,
+				sizeof(struct emac_phy_params)))
+				return -EFAULT;
+
+			/* make sure this function does not
+			 *clash with mii access during tick
+			 *function */
+			local_irq_save(irq_flags);
+
+			if (emac_control(dev, EMAC_IOCTL_READ_PHY_REG,
+				(void *)&phy_params,
+				NULL) != EMAC_SUCCESS) {
+				ERR("Failed to read params");
+				return -EFAULT;
+			}
+
+			/* copy the local data to user space */
+			if (copy_to_user((char *)priv_ioctl.data,
+				(char *)&phy_params,
+				sizeof(struct emac_phy_params)))
+				return -EFAULT;
+
+			/* enable tick timer to access phy now
+			   if required */
+			local_irq_restore(irq_flags);
+		}
+		break;
+			/* write PHY register via MII interface */
+		case EMAC_PRIV_MII_WRITE:
+		{
+			struct emac_phy_params phy_params;
+			unsigned long irq_flags;
+
+			/* copy user data into local variable */
+			if (copy_from_user((char *)&phy_params,
+				(char *)priv_ioctl.data,
+				sizeof(struct emac_phy_params)))
+				return -EFAULT;
+
+			/* make sure this function does not
+			   clash with mii access during tick
+			   function */
+			local_irq_save(irq_flags);
+
+			if (emac_control(dev, EMAC_IOCTL_WRITE_PHY_REG,
+						(void *)&phy_params,
+						NULL) != EMAC_SUCCESS) {
+				ERR("Failed to read params");
+				return -EFAULT;
+			}
+
+			/* enable tick timer to access phy now
+			   if required */
+			local_irq_restore(irq_flags);
+		}
+		break;
+			/* get statistics */
+		case EMAC_PRIV_GET_STATS:
+		{
+			struct emac_hw_statistics stats;
+
+			/* Caller provides memory for HW stats
+			   structure via "data" pointer */
+			if (emac_control(dev, EMAC_IOCTL_GET_STATISTICS,
+				(void *)&stats, NULL) != EMAC_SUCCESS) {
+				ERR("Failed to get statistics");
+				return EMAC_INTERNAL_FAILURE;
+			}
+
+			/* copy the local data to user space */
+			if (copy_to_user
+			    ((char *)priv_ioctl.data, (char *)&stats,
+			     sizeof(struct emac_hw_statistics)))
+				return -EFAULT;
+			break;
+		}
+			/* clear statistics */
+		case EMAC_PRIV_CLR_STATS:
+			if (emac_control(dev,
+					 EMAC_IOCTL_CLR_STATISTICS,
+					 NULL, NULL)
+				!= EMAC_SUCCESS) {
+				ERR("Failed to clear statistics");
+				return EMAC_INTERNAL_FAILURE;
+			}
+			break;
+		default:
+			return -EFAULT;
+			break;
+		}
+	}
+
+	else if (cmd == SIOTIMIB2) {
+		struct ti_snmp_cmd_t ti_snmp_cmd;
+
+		/* now copy the user data */
+		if (copy_from_user
+		    ((char *)&ti_snmp_cmd, (char *)rq->ifr_data,
+		     sizeof(struct ti_snmp_cmd_t)))
+			return -EFAULT;
+
+		switch (ti_snmp_cmd.cmd) {
+		case TI_SIOCGINTFCOUNTERS:
+		{
+			struct mib2_if_counters mib_counter;
+
+			/* Caller provides memory for HW stats
+				structure via "data" pointer */
+			if (emac_control(dev,
+						EMAC_IOCTL_IF_COUNTERS,
+						(void *)&mib_counter, NULL)
+				!= EMAC_SUCCESS) {
+				ERR("Failed to get statistics");
+				return EMAC_INTERNAL_FAILURE;
+			}
+
+			/* copy the local data to user space */
+			if (copy_to_user
+				((char *)ti_snmp_cmd.data,
+				(char *)&mib_counter,
+				sizeof(struct mib2_if_counters)))
+				return -EFAULT;
+			break;
+		}
+		case TI_SIOCGINTFPARAMS:
+		{
+			struct mib2_if_params local_params;
+
+			local_params.if_speed = dev->link_speed;
+			local_params.if_high_speed =
+				(local_params.if_speed) / 1000000;
+			local_params.if_oper_status =
+				((netdev->
+				flags & IFF_UP) ? MIB2_STATUS_UP :
+				MIB2_STATUS_DOWN);
+			local_params.if_promiscuous_mode =
+				((netdev->
+				flags & IFF_PROMISC) ? TRUE : FALSE);
+
+			/* now copy the counters to the user data */
+			if (copy_to_user
+				((char *)ti_snmp_cmd.data,
+				(char *)&local_params,
+				sizeof(struct mib2_if_params)))
+				return -EFAULT;
+		}
+			break;
+
+		case TI_SIOCGETHERCOUNTERS:
+		{
+			struct mib2_phy_counters phy_counter;
+
+			/* Caller provides memory for HW stats
+				structure via "data" pointer */
+			if (emac_control(dev,
+						EMAC_IOCTL_ETHER_COUNTERS,
+						(void *)&phy_counter, NULL)
+				!= EMAC_SUCCESS) {
+				ERR("Failed to get statistics");
+
+				return EMAC_INTERNAL_FAILURE;
+			}
+
+			/* copy the local data to user space */
+			if (copy_to_user
+				((char *)ti_snmp_cmd.data,
+				(char *)&phy_counter,
+				sizeof(struct mib2_phy_counters)))
+				return -EFAULT;
+			break;
+		}
+		case TI_SIOCGETHERPARAMS:
+		{
+			struct mib2_eth_params local_params;
+
+			local_params.eth_duplex_status =
+				((dev->link_mode ==
+				PHY_DUPLEX_FULL) ?
+				MIB2_FULL_DUPLEX : MIB2_HALF_DUPLEX);
+
+			/* now copy the counters to the user data */
+			if (copy_to_user
+				((char *)ti_snmp_cmd.data,
+				(char *)&local_params,
+				sizeof(struct mib2_eth_params)))
+				return -EFAULT;
+			break;
+		}
+		default:
+			return -EFAULT;
+		}
+	} else
+		return -EFAULT;
+
+	return 0;
+}
+
+/*
+ * HASH SUPPORT FUNCTIONS
+ */
+
+/* get hash value using mechainsm in specs */
+static u32 hash_get(u8 *addr)
+{
+	register u8 tmpval;
+	register int cnt;
+	register u32 hash = 0;
+
+	for (cnt = 0; cnt < 2; cnt++) {
+		tmpval = *addr++;
+		hash ^= (tmpval >> 2) ^ (tmpval << 4);
+		tmpval = *addr++;
+		hash ^= (tmpval >> 4) ^ (tmpval << 2);
+		tmpval = *addr++;
+		hash ^= (tmpval >> 6) ^ (tmpval);
+	}
+
+	return (hash & 0x3F);
+}
+
+/**
+ * Hash Table Add
+ *- Adds mac address to hash table and upates hash bits in hardware
+ *- Returns negative if error, 0 if no change to registers, >0 if
+ *  hash registers need to change
+ */
+static int hash_add(struct emac_dev_s *_dev, u8 *mac_address)
+{
+	struct emac_dev_s *dev = (struct emac_dev_s *) _dev;
+	u32 hash_value;
+	u32 hash_bit;
+	u32 status = 0;
+	hash_value = hash_get(mac_address);
+
+	if (hash_value >= EMAC_NUM_MULTICAST_BITS) {
+		LOGERR("Invalid Hash Value=%d. Should not be greater than %d",
+		       hash_value, (EMAC_NUM_MULTICAST_BITS - 1));
+		return EMAC_INVALID_PARAM;
+	}
+
+	/* set the hash bit only if not previously set */
+	if (dev->multicast_hash_cnt[hash_value] == 0) {
+		status = 1;
+		if (hash_value < 32) {
+			hash_bit = (1 << hash_value);
+			dev->mac_hash1 |= hash_bit;
+		} else {
+			hash_bit = (1 << (hash_value - 32));
+			dev->mac_hash2 |= hash_bit;
+		}
+	}
+
+	/* increment counter to maintain number of multicast address
+	   that map to this hash bit  */
+	++dev->multicast_hash_cnt[hash_value];
+
+	return status;
+}
+
+/**
+ * Hash Table Del
+ *- Deletes a mac address from hash table and updates hash register bits
+ *- Returns negative if error, 0 if no change to registers, >0 if
+ *  hash registers need to change
+ */
+static int hash_del(struct emac_dev_s *_dev, u8 *mac_address)
+{
+	struct emac_dev_s *dev = (struct emac_dev_s *) _dev;
+	u32 hash_value;
+	u32 hash_bit;
+
+	hash_value = hash_get(mac_address);
+	if (dev->multicast_hash_cnt[hash_value] > 0)
+		/* decrement counter to reduce number of multicast
+		 *address that map to this hash bit  */
+		--dev->multicast_hash_cnt[hash_value];
+
+	/* if counter still > 0, at least one multicast address refers
+	 *to this hash bit. so return 0 */
+	if (dev->multicast_hash_cnt[hash_value] > 0)
+		return 0;
+
+	if (hash_value < 32) {
+		hash_bit = (1 << hash_value);
+		dev->mac_hash1 &= ~hash_bit;
+	} else {
+		hash_bit = (1 << (hash_value - 32));
+		dev->mac_hash2 &= ~hash_bit;
+	}
+
+	/* return 1 to indicate change in mac_hash registers reqd */
+	return 1;
+}
+
+/**
+ * updates hash register bits with single multicast address add/delete
+ * operation
+ */
+static void emac_single_multi(struct emac_dev_s *_dev,
+			enum emac_single_multi_oper oper, u8 *addr)
+{
+	struct emac_dev_s *dev = (struct emac_dev_s *) _dev;
+	int status = -1;
+
+	switch (oper) {
+	case EMAC_MULTICAST_ADD:
+		status = hash_add(_dev, addr);
+		break;
+	case EMAC_MULTICAST_DEL:
+		status = hash_del(_dev, addr);
+		break;
+	default:
+		LOGERR("Unhandled Single Multicast operation %d", oper);
+		break;
+	}
+
+	/* write to the hardware only if the register status chances */
+	if (status > 0) {
+		davinci_writel(dev->mac_hash1, dev->emac_regs_base
+				+ EMAC_MAC_HASH1_REG);
+		davinci_writel(dev->mac_hash2, dev->emac_regs_base
+				+ EMAC_MAC_HASH2_REG);
+	}
+}
+
+/**
+ * updates hash register bits for all multi operation (set/clear)
+ */
+static void emac_all_multi(struct emac_dev_s *_dev,
+				enum emac_all_multi_oper oper)
+{
+	struct emac_dev_s *dev = (struct emac_dev_s *) _dev;
+
+	switch (oper) {
+	case EMAC_ALL_MULTI_SET:
+		dev->mac_hash1 = EMAC_ALL_MULTI_REG_VALUE;
+		dev->mac_hash2 = EMAC_ALL_MULTI_REG_VALUE;
+		break;
+	case EMAC_ALL_MULTI_CLR:
+		dev->mac_hash1 = 0;
+		dev->mac_hash2 = 0;
+		memset(&(dev->multicast_hash_cnt[0]), 0,
+		sizeof(dev->multicast_hash_cnt[0]) * EMAC_NUM_MULTICAST_BITS);
+		break;
+	default:
+		LOGERR("Unhandled All multi operation %d", oper);
+		break;
+	}
+
+	davinci_writel(dev->mac_hash1, dev->emac_regs_base
+					+ EMAC_MAC_HASH1_REG);
+	davinci_writel(dev->mac_hash2, dev->emac_regs_base
+					+ EMAC_MAC_HASH2_REG);
+}
+
+/*
+ * PHY related functions
+ */
+
+/**
+ * Cpmac Update Phy Status - updates phy status variables in
+ * hDDC->status "CpmacDDCStatus" structure
+ */
+static int emac_update_phy_status(struct emac_dev_s *_dev)
+{
+	struct emac_dev_s *dev = (struct emac_dev_s *) _dev;
+	u32 set_phy_mode;
+
+	LOGMSG(EMAC_DEBUG_BUSY_FUNCTION_ENTRY, "");
+
+	/* verify proper device state */
+	if (dev->drv_state != DRV_OPENED) {
+		LOGERR("Device NOT Open");
+		return EMAC_ERR_DEV_NOT_OPEN;
+	}
+
+	set_phy_mode = dev->init_cfg.phy_mode;
+
+	/* no phy condition */
+	if (set_phy_mode & SNWAY_NOPHY) {
+		/*  no phy condition, always linked */
+		dev->status.phy_linked = 1;
+		dev->status.phy_speed = 100;
+		dev->status.phy_duplex = PHY_DUPLEX_FULL;
+		dev->status.phy_num = 0xFFFFFFFF;	/* no phy */
+		dev->mac_control |= (1 << EMAC_MACCONTROL_FULLDUPLEXEN_SHIFT);
+
+		/* write mac control register from stored value */
+		davinci_writel(dev->mac_control, dev->emac_regs_base
+						+ EMAC_MAC_CONTROL_REG);
+		goto emac_update_phy_status_exit;
+	}
+
+	/* if loopback set in hardware, set link to ON */
+	if (dev->mac_control & EMAC_MACCONTROL_LOOPBKEN_MASK) {
+		dev->status.phy_linked = 1;
+		goto emac_update_phy_status_exit;
+	}
+	if (set_phy_mode & SNWAY_LPBK)
+		dev->status.phy_linked = emac_mdio_is_loopback();
+	else
+		dev->status.phy_linked = emac_mdio_is_linked();
+
+	if (dev->status.phy_linked) {
+		/*  retreive duplex and speed and the phy number  */
+		if (set_phy_mode & SNWAY_LPBK)
+			dev->status.phy_duplex = PHY_DUPLEX_FULL;
+		else
+			dev->status.phy_duplex = emac_mdio_get_duplex();
+		dev->status.phy_speed = emac_mdio_get_speed();
+		dev->status.phy_num = emac_mdio_get_phy_num();
+
+		/* set the duplex bit in maccontrol */
+		if (dev->status.phy_duplex == PHY_DUPLEX_FULL)
+			dev->mac_control |=
+			    (1 << EMAC_MACCONTROL_FULLDUPLEXEN_SHIFT);
+		else
+			dev->mac_control &=
+			    ~(1 << EMAC_MACCONTROL_FULLDUPLEXEN_SHIFT);
+
+	}
+
+	/* write mac control register from stored value */
+	davinci_writel(dev->mac_control, dev->emac_regs_base
+					+ EMAC_MAC_CONTROL_REG);
+
+emac_update_phy_status_exit:
+	LOGMSG(EMAC_DEBUG_PORT_UPDATE,
+	       "MacControl=%08X, Status: Phy=%d, Speed=%s, Duplex=%s",
+	       dev->mac_control, dev->status.phy_num,
+	       (dev->status.phy_speed == 100) ? "100" : "10",
+	       (dev->status.phy_duplex == PHY_DUPLEX_FULL) ? "Full" : "Half");
+	LOGMSG(EMAC_DEBUG_BUSY_FUNCTION_EXIT, "");
+
+	return EMAC_SUCCESS;
+}
+
+/**
+ * set phy mode
+ */
+static int emac_set_phy_mode(struct emac_dev_s *_dev)
+{
+	struct emac_dev_s *dev = (struct emac_dev_s *) _dev;
+	u32 set_phy_mode;
+	u32 phy_mode;
+
+	LOGMSG(EMAC_DEBUG_BUSY_FUNCTION_ENTRY, "");
+
+	/* verify proper device state */
+	if (dev->drv_state != DRV_OPENED) {
+		LOGERR("Device NOT Open");
+		return EMAC_ERR_DEV_NOT_OPEN;
+	}
+
+	set_phy_mode = dev->init_cfg.phy_mode;
+	phy_mode = 0;
+	if (set_phy_mode & SNWAY_AUTO)
+		phy_mode |= NWAY_AUTO;
+	if (set_phy_mode & SNWAY_FD10)
+		phy_mode |= NWAY_FD10;
+	if (set_phy_mode & SNWAY_FD100)
+		phy_mode |= NWAY_FD100;
+	if (set_phy_mode & SNWAY_HD10)
+		phy_mode |= NWAY_HD10;
+	if (set_phy_mode & SNWAY_HD100)
+		phy_mode |= NWAY_HD100;
+	if (set_phy_mode & SNWAY_LPBK)
+		phy_mode |= NWAY_LPBK;
+	if (set_phy_mode & SNWAY_AUTOMDIX)
+		phy_mode |= NWAY_AUTOMDIX;
+	/* check for EMAC bus frequency for correct speed operation */
+	if ((set_phy_mode & SNWAY_FD10) || (set_phy_mode & SNWAY_HD10)) {
+		if (dev->init_cfg.emac_bus_frequency <=
+		    EMAC_MIN_FREQUENCY_FOR_10MBPS)
+			LOGERR("Bus speedemacSetPhyMode: CpmacFreq(%d) "
+			       "is less than required %d freq for "
+			       "10Mbps support. CANNOT SUPPORT 10Mbps",
+			       dev->init_cfg.emac_bus_frequency,
+			       EMAC_MIN_FREQUENCY_FOR_10MBPS);
+	}
+
+	else if ((set_phy_mode & SNWAY_FD100) || (set_phy_mode & SNWAY_HD100)) {
+		if (dev->init_cfg.emac_bus_frequency <=
+		    EMAC_MIN_FREQUENCY_FOR_100MBPS)
+
+			LOGERR("freq(%d) is less than required %d freq for "
+			       "100Mbps support. CANNOT SUPPORT 100Mbps",
+			       dev->init_cfg.emac_bus_frequency,
+			       EMAC_MIN_FREQUENCY_FOR_100MBPS);
+	}
+
+	/* TODO: check for gigabit mode when PHY mode defines for
+	 *gigabit are available */
+	LOGMSG(EMAC_DEBUG_PORT_UPDATE,
+	       "MdioPhyMode=%08X, PhyMode=%08d, Auto:%d, FD10:%d, "
+	       "HD10:%d, FD100:%d, HD100:%d",
+	       set_phy_mode, phy_mode,
+	       (phy_mode & NWAY_AUTO), (phy_mode & NWAY_FD10),
+	       (phy_mode & NWAY_HD10),
+	       (phy_mode & NWAY_FD100), (phy_mode & NWAY_HD100));
+	emac_mdio_set_phy_mode(phy_mode);
+	emac_update_phy_status(_dev);
+	LOGMSG(EMAC_DEBUG_BUSY_FUNCTION_EXIT, "");
+
+	return EMAC_SUCCESS;
+}
+
+/*
+ * MAC ADDRESSING MODE SUPPORT FUNCTIONS
+ */
+
+/**
+ * this function sets / clears the unicast flag in hardware
+ */
+static void emac_rx_uni_cast(struct emac_dev_s *_dev, u32 channel, bool enable)
+{
+	struct emac_dev_s *dev = (struct emac_dev_s *) _dev;
+
+	/* update local copy of register to save cycles in reading the
+	 *register */
+	if (enable == TRUE) {
+		dev->rx_unicast_set |= (1 << channel);
+		dev->rx_unicast_clear &= ~(1 << channel);
+	} else {
+		/* disable unicast channel setting */
+		dev->rx_unicast_clear |= (1 << channel);
+		dev->rx_unicast_set &= ~(1 << channel);
+	}
+
+	/* write to hardware if device is open */
+	if (dev->drv_state == DRV_OPENED) {
+		davinci_writel(dev->rx_unicast_set, dev->emac_regs_base
+						+ EMAC_RX_UNICAST_SET_REG);
+		davinci_writel(dev->rx_unicast_clear,
+		dev->emac_regs_base + EMAC_RX_UNICAST_CLEAR_REG);
+	}
+}
+
+/**
+ * EMAC Add Type 0 Address
+ * - set mac address for type 0 addressing (EMAC)
+ *
+ * This is an internal function of the DDC called from channel
+ * enable API which does channel number range checking and hence its
+ * not required.  It is assumed that this function will get the
+ * correct channel number always
+ */
+static void emac_add_type0addr(struct emac_dev_s *dev, u32 channel,
+			       char *mac_address)
+{
+	davinci_writel((mac_address[0] << 8) | (mac_address[1]),
+	dev->emac_regs_base + EMAC_MAC_SRC_ADDR_LO_REG);
+	davinci_writel((mac_address[2] << 24) |
+		(mac_address[3] << 16) | (mac_address[4] << 8) |
+		(mac_address[5]),
+		dev->emac_regs_base + EMAC_MAC_SRC_ADDR_HI_REG);
+	/* enable unicast */
+	emac_rx_uni_cast(dev, channel, TRUE);
+}
+
+/**
+ * EMAC Add Type 1 Address
+ * - set mac address for type 1 addressing (EMAC)
+ *
+ * This is an internal function of the DDC called from channel enable
+ * API which does channel number range checking and hence its not required.
+ * It is assumed that this function will get the correct channel number always
+ */
+static void emac_add_type1addr(struct emac_dev_s *dev, u32 channel,
+			       char *mac_address)
+{
+	/* set mac_index register with channel number */
+	davinci_writel(channel, dev->emac_regs_base + EMAC_MAC_INDEX_REG);
+
+	/* set mac_addr_hi register */
+	davinci_writel((mac_address[3] << 24) | (mac_address[2] << 16) |
+	    (mac_address[1] << 8) | (mac_address[0]),
+	    dev->emac_regs_base + EMAC_MAC_ADDR_HI_REG);
+
+	/* set mac_addr_lo register */
+	davinci_writel(((mac_address[5] << 8) | mac_address[4]),
+	dev->emac_regs_base + EMAC_MAC_ADDR_LO_REG);
+
+	/* set mac hash */
+	davinci_writel(0, dev->emac_regs_base + EMAC_MAC_HASH1_REG);
+	davinci_writel(0, dev->emac_regs_base + EMAC_MAC_HASH2_REG);
+
+	/* As per discussion with hardware folks, it is mandatory to
+	   set the source address of the mac, else correct behaviour
+	   is not guaranteed */
+	emac_add_type0addr(dev, channel, mac_address);
+
+	/* enable unicast */
+	emac_rx_uni_cast(dev, channel, TRUE);
+}
+
+/**
+ * CPGMAC CFIG 2/3 type addressing - filtering
+ */
+static void emac_add_type2addr(struct emac_dev_s *_dev, u32 channel,
+			       char *mac_address,
+			       int index, bool valid, int match)
+{
+	/* not supported in DaVinci */
+}
+
+/*
+ * HARDWARE CONFIGURATION SUPPORT FUNCTIONS
+ */
+
+/**
+ * set RX hardware configuration
+ */
+void emac_set_rx_hw_cfg(struct emac_dev_s *_dev)
+{
+	struct emac_dev_s *dev = (struct emac_dev_s *) _dev;
+	struct emac_rx_config *rx_cfg;
+	u32 rx_mbp_enable;
+
+	if (dev->drv_state != DRV_OPENED) {
+		LOGERR("Function called when device is NOT in open state");
+		return;
+	}
+
+	rx_cfg = &dev->init_cfg.rx_cfg;
+
+	/* set RX MBP enable register */
+	rx_mbp_enable =
+	    ((rx_cfg->pass_crc & 0x1) << EMAC_RXMBP_PASSCRC_SHIFT) |
+	    ((rx_cfg->qos_enable & 0x1) << EMAC_RXMBP_QOSEN_SHIFT) |
+	    ((rx_cfg->no_buffer_chaining & 0x1) << EMAC_RXMBP_NOCHAIN_SHIFT) |
+	    ((rx_cfg->
+	      copy_maccontrol_frames_enable & 0x1) << EMAC_RXMBP_CMFEN_SHIFT) |
+	    ((rx_cfg->
+	      copy_short_frames_enable & 0x1) << EMAC_RXMBP_CSFEN_SHIFT) |
+	    ((rx_cfg->
+	      copy_error_frames_enable & 0x1) << EMAC_RXMBP_CEFEN_SHIFT) |
+	    ((rx_cfg->
+	      promiscous_enable & 0x1) << EMAC_RXMBP_CAFEN_SHIFT) |
+		((rx_cfg->promiscous_channel & EMAC_RXMBP_CHMASK)
+		 << EMAC_RXMBP_PROMCH_SHIFT) |
+		((rx_cfg->broadcast_enable & 0x1) << EMAC_RXMBP_BROADEN_SHIFT)|
+		((rx_cfg->broadcast_channel & EMAC_RXMBP_CHMASK) <<
+		 EMAC_RXMBP_BROADCH_SHIFT) |
+		((rx_cfg->multicast_enable & 0x1) << EMAC_RXMBP_MULTIEN_SHIFT)|
+		((rx_cfg->multicast_channel & EMAC_RXMBP_CHMASK) <<
+		 EMAC_RXMBP_MULTICH_SHIFT);
+
+	if (rx_cfg->promiscous_enable) {
+		/* disable mcast bcast and unicast:  H/W limitation */
+		rx_mbp_enable &= ~(0x1 << EMAC_RXMBP_BROADEN_SHIFT);
+		rx_mbp_enable &= ~(0x1 << EMAC_RXMBP_MULTIEN_SHIFT);
+
+		/* disable unicast - warning!! assuming only one
+		 *channel open */
+		emac_rx_uni_cast(_dev, (dev->rx_cppi[0])->ch_info.ch_num,
+				 FALSE);
+	} else {
+		/* enable unicast - warning!! assuming only one
+		 *channel open */
+		emac_rx_uni_cast(_dev, (dev->rx_cppi[0])->ch_info.ch_num, TRUE);
+	}
+
+	if (dev->rx_MBP_enable != rx_mbp_enable) {
+		dev->rx_MBP_enable = rx_mbp_enable;
+		davinci_writel(rx_mbp_enable, dev->emac_regs_base
+						+ EMAC_RX_MBP_ENABLE_REG);
+	}
+
+	/* set max rx packet length */
+	davinci_writel((rx_cfg->max_rx_pkt_length & EMAC_RX_MAX_LEN_MASK),
+	dev->emac_regs_base + EMAC_RX_MAXLEN_REG);
+
+	/* set rx buffer offset */
+	davinci_writel((rx_cfg->buffer_offset & EMAC_RX_BUFFER_OFFSET_MASK),
+	dev->emac_regs_base + EMAC_RX_BUFFER_OFFSET_REG);
+
+	LOGMSG(EMAC_DEBUG_FUNCTION_EXIT,
+	       "Rx_MBP_Enable = 0x%08x\n", rx_mbp_enable);
+}
+
+/**
+ * set MAC configuration - MACControl register
+ */
+static void emac_set_mac_hw_cfg(struct emac_dev_s *_dev)
+{
+	struct emac_dev_s *dev = (struct emac_dev_s *) _dev;
+	struct emac_mac_config *mac_cfg;
+	u32 mac_control;
+
+	if (dev->drv_state != DRV_OPENED) {
+		LOGERR("Function called when device is NOT in open state");
+		return;
+	}
+
+	mac_cfg = &dev->init_cfg.mac_cfg;
+	mac_control =
+	    ((mac_cfg->
+	      tx_short_gap_enable & 0x1) << EMAC_MACCONTROL_TXSHORTGAPEN_SHIFT)
+	    | (((mac_cfg->p_type == EMAC_TXPRIO_FIXED) ? 0x1 : 0) <<
+	       EMAC_MACCONTROL_TXPTYPE_SHIFT)
+	    | ((mac_cfg->giga_bit_enable & 0x1) <<
+	       EMAC_MACCONTROL_GIGABITEN_SHIFT) | ((mac_cfg->
+						    tx_pacing_enable & 0x1) <<
+						 EMAC_MACCONTROL_TXPACEEN_SHIFT)
+	    |
+	    /* THIS LINE FOR REFERENCE ONLY ((mac_cfg->mii_enable & 0x1)
+			 << EMAC_MACCONTROL_MIIEN_SHIFT) | */
+	    (dev->mac_control & EMAC_MACCONTROL_MIIEN_MASK) |
+	    ((mac_cfg->
+	      tx_flow_enable & 0x1) << EMAC_MACCONTROL_TXFLOWEN_SHIFT) |
+	    ((mac_cfg->
+	      rx_flow_enable & 0x1) << EMAC_MACCONTROL_RXFLOWEN_SHIFT) |
+	    ((mac_cfg->
+	      loopback_enable & 0x1) << EMAC_MACCONTROL_LOOPBKEN_SHIFT) |
+	    (dev->mac_control & EMAC_MACCONTROL_FULLDUPLEXEN_MASK);
+
+	if (dev->mac_control != mac_control) {
+		dev->mac_control = mac_control;
+		davinci_writel(mac_control, dev->emac_regs_base
+						+ EMAC_MAC_CONTROL_REG);
+	}
+}
+
+/**
+ * EMAC Init
+ * - validates max TX/RX channels and stores initial configuration
+ *
+ * Initial configuration passed by via the "init_cfg" parameter
+ */
+static int emac_init(struct emac_dev_s *_dev, struct emac_init_config 
*init_cfg)
+{
+	struct emac_dev_s *dev = (struct emac_dev_s *) _dev;
+
+	LOGMSG(EMAC_DEBUG_FUNCTION_ENTRY, "");
+
+	/* validate num_tx and num_rx channels */
+	if ((init_cfg->num_tx_channels > EMAC_MAX_TX_CHANNELS) ||
+	    (init_cfg->num_rx_channels > EMAC_MAX_RX_CHANNELS)) {
+		LOGERR("Invalid number of TX/RX channels");
+		return EMAC_INVALID_PARAM;
+	}
+
+	/* save config info for later use */
+	dev->init_cfg = *init_cfg;	/* structure copy */
+
+	LOGMSG(EMAC_DEBUG_FUNCTION_EXIT, "");
+	return EMAC_SUCCESS;
+}
+
+/**
+ * EMAC DDC DeInit
+ * Stub function - no functionality required as per this implementation
+ */
+static int emac_de_init(struct emac_dev_s *dev, void *param)
+{
+	LOGMSG(EMAC_DEBUG_FUNCTION_ENTRY, "");
+	LOGMSG(EMAC_DEBUG_FUNCTION_EXIT, "");
+
+	return EMAC_SUCCESS;
+}
+
+
+/**
+ * EMAC DDC Open
+ * - Brings module out of reset
+ * - Open's CSL, programs mandatory hardware init registers
+ * - Open's MII_MDIO module and enable poll timer via DDA
+ * - Enables earlier created TX/RX channels
+ * - Enables TX/RX operation in hardware
+ *
+ *"param" not used in this implementation
+ */
+static int emac_open(struct emac_dev_s *_dev, void *param)
+{
+	struct emac_dev_s *dev = (struct emac_dev_s *) _dev;
+	u32 channel;
+	u32 mii_mod_id, mii_rev_maj, mii_rev_min;
+	int ret_val;
+	struct emac_init_config *init_cfg;
+
+	LOGMSG(EMAC_DEBUG_FUNCTION_ENTRY, "");
+
+	/* NOTE: what about synchronization? */
+	/* NOTE: what about multiinstance? */
+	if (dev->drv_state == DRV_OPENED) {
+		LOGERR("Device already open");
+		return EMAC_ERR_DEV_ALREADY_OPEN;
+	}
+
+	/* get init config info structure pointer for easy access */
+	init_cfg = &dev->init_cfg;
+
+	/* set the BD memory pointer */
+	emac_wrapper_ptr = EMAC_WRAPPER_RAM_ADDR;
+
+	/* bring EMAC out of reset - for clean implementation, reset
+	 *and then unreset the module */
+	/* for EMAC 2.6 and beyond, reset is internal to the module */
+	davinci_writel(1, dev->emac_regs_base + EMAC_SOFT_RESET_REG);
+
+	/* wait for reset to complete - do nothing */
+	while (davinci_readl(dev->emac_regs_base + EMAC_SOFT_RESET_REG));
+
+	for (channel = 0; channel < EMAC_MAX_TX_CHANNELS; channel++) {
+		/* program TX/RX HDP's to 0 */
+		davinci_writel(0, dev->emac_regs_base +
+					EMAC_TX_HDP_REG(channel));
+
+		/* initialize the completion pointers to 0 */
+		davinci_writel(0, dev->emac_regs_base
+					+ EMAC_TX_CP_REG(channel));
+	}
+
+	for (channel = 0; channel < EMAC_MAX_RX_CHANNELS; channel++) {
+		davinci_writel(0, dev->emac_regs_base
+					+ EMAC_RX_HDP_REG(channel));
+
+		/* initialize the completion pointers to 0 */
+		davinci_writel(0, dev->emac_regs_base
+					+ EMAC_RX_CP_REG(channel));
+	}
+
+	/* enable TX/RX DMA */
+	davinci_orl(EMAC_TX_CONTROL_TX_ENABLE_VAL,
+		dev->emac_regs_base + EMAC_TX_CONTROL_REG);
+	davinci_orl(EMAC_RX_CONTROL_RX_ENABLE_VAL,
+		dev->emac_regs_base + EMAC_RX_CONTROL_REG);
+
+	/* enable adapter check interrupts - disable stats interupt */
+	davinci_writel(EMAC_MAC_HOST_ERR_INTMASK_VAL,
+	dev->emac_regs_base + EMAC_MAC_INT_MASK_SET_REG);
+	/* set device state - opened - useful when opening channels */
+	dev->drv_state = DRV_OPENED;
+
+	/* set the mac_control register */
+	emac_set_mac_hw_cfg(_dev);
+
+	/* start MDIO autonegotiation and set phy mode */
+	emac_mdio_get_ver(init_cfg->mdio_base_address,
+			  &mii_mod_id, &mii_rev_maj, &mii_rev_min);
+
+	LOGMSG(EMAC_DEBUG_PORT_UPDATE,
+	       "MII Module Id=%d, MII Base Address=%08X, Major Rev=%d, "
+	       "Minor Rev=%d",
+	       mii_mod_id, init_cfg->mdio_base_address,
+	       mii_rev_maj, mii_rev_min);
+
+	/* no failure code returned from this function */
+	emac_mdio_init(init_cfg->mdio_base_address,
+		       dev->init_cfg.inst_id,
+		       init_cfg->phy_mask,
+		       init_cfg->MLink_mask,
+		       init_cfg->mdio_bus_frequency,
+		       init_cfg->mdio_clock_frequency,
+		       (emac_debug & EMAC_DEBUG_MII));
+
+	/* set the PHY to a given mode - as per config parameters and
+	 *update DDA layer */
+	emac_set_phy_mode(_dev);
+
+	emac_control_cb(dev,
+			EMAC_IOCTL_STATUS_UPDATE, (void *)&dev->status, NULL);
+
+	/* start the tick timer via DDA */
+	emac_control_cb(dev,
+			EMAC_IOCTL_TIMER_START,
+			(void *)init_cfg->mdio_tick_msec, NULL);
+
+	/* enable opened TX channels */
+	for (channel = 0; channel < EMAC_MAX_TX_CHANNELS; channel++) {
+		if (dev->tx_cppi[channel] != NULL) {
+			ret_val =
+			    emac_enable_channel(_dev, channel, NET_CH_DIR_TX);
+			if (ret_val != EMAC_SUCCESS) {
+				LOGERR("Error enabling TX channel %d", channel);
+
+				/* TODECIDE: should we return from
+				 *here or continue enabling other
+				 *channels */
+				return ret_val;
+			}
+		}
+	}
+
+	/* set filter low threshold - not supported, hence set to 0 */
+	davinci_writel(0, dev->emac_regs_base + EMAC_RX_FILTER_LOW_THRESH_REG);
+
+	/* disable unicast on all channels first - enabled if channel
+	 *is configured & enabled below */
+	davinci_writel(EMAC_RX_UNICAST_CLEAR_ALL,
+		dev->emac_regs_base + EMAC_RX_UNICAST_CLEAR_REG);
+
+	/* set MAC hash register */
+	davinci_writel(dev->mac_hash1,
+		dev->emac_regs_base + EMAC_MAC_HASH1_REG);
+	davinci_writel(dev->mac_hash2,
+		dev->emac_regs_base + EMAC_MAC_HASH2_REG);
+
+	/* RX MBP, RX pkt length and RX buffer offset registers taken
+	 *care by this function */
+	emac_set_rx_hw_cfg(_dev);
+
+	/* read RX address matching/filtering type (0/1/2) */
+	dev->rx_addr_type =
+	(davinci_readl(dev->emac_regs_base + EMAC_MAC_CFIG_REG) >> 8) & 0xFF;
+
+	/* enable opened RX channels */
+	for (channel = 0; channel < EMAC_MAX_RX_CHANNELS; channel++) {
+		if (dev->rx_cppi[channel] != NULL) {
+			ret_val =
+			    emac_enable_channel(_dev, channel, NET_CH_DIR_RX);
+			if (ret_val != EMAC_SUCCESS) {
+				LOGERR("Error enabling RX channel %d", channel);
+
+				/* TODECIDE: should we return from
+				 *here or continue enabling other
+				 *channels */
+				return ret_val;
+			}
+		}
+
+		/* since flow threshold and free buffer feature is not
+		 *supported, set it to 0 */
+		davinci_writel(0,
+			dev->emac_regs_base + EMAC_RX_FLOW_THRESH_REG(channel));
+		davinci_writel(0,
+			dev->emac_regs_base + EMAC_RX_FREE_BUFFER_REG(channel));
+	}
+
+	/* finally set MAC control register, enable MII */
+	dev->mac_control |= (1 << EMAC_MACCONTROL_MIIEN_SHIFT);
+	davinci_writel(dev->mac_control,
+		dev->emac_regs_base + EMAC_MAC_CONTROL_REG);
+
+	/* start the MIB cnt tick timer via DDA */
+	emac_control_cb(dev,
+			EMAC_IOCTL_MIB64_CNT_TIMER_START,
+			(void *)init_cfg->mib64cnt_msec, NULL);
+
+	/* enable interrupts via module control (wrapper) */
+	davinci_writel(1, dev->emac_wrap_regs_base + EMAC_WRAP_EWCTL_REG);
+
+	LOGMSG(EMAC_DEBUG_FUNCTION_EXIT, "");
+	return EMAC_SUCCESS;
+}
+
+/**
+ * EMAC DDC Close
+ * - Disables poll timer via DDA
+ * - Disable and Close all open TX/RX channels
+ * - Closes CSL
+ * - Puts module in reset
+ *
+ *"param" not used in this implementation
+ */
+static int emac_close(struct emac_dev_s *_dev, void *param)
+{
+	struct emac_dev_s *dev = (struct emac_dev_s *) _dev;
+	int ret_val;
+	int err_val = EMAC_SUCCESS;
+	u32 channel;
+
+	LOGMSG(EMAC_DEBUG_FUNCTION_ENTRY, "");
+
+	if (dev->drv_state == DRV_CLOSED) {
+		LOGERR("Device already closed");
+		return EMAC_ERR_DEV_ALREADY_CLOSED;
+	}
+
+	/* stop the tick timer via DDA */
+	emac_control_cb(dev, EMAC_IOCTL_TIMER_STOP, NULL, NULL);
+
+	/* stop the mib timer via DDA */
+	emac_control_cb(dev, EMAC_IOCTL_MIB64_CNT_TIMER_STOP, NULL, NULL);
+	/* close TX channels */
+	for (channel = 0; channel < EMAC_MAX_TX_CHANNELS; channel++) {
+		if (dev->tx_cppi[channel] != NULL) {
+			ret_val =
+			    emac_ch_close(_dev, channel, NET_CH_DIR_TX, NULL);
+			if (ret_val != EMAC_SUCCESS) {
+				LOGERR("Error closing TX channel %d", channel);
+
+				/* instead of returning immediatley on
+				 *error, we close all possible
+				 *channels */
+				err_val = ret_val;
+			}
+		}
+	}
+
+	/* close RX channels */
+	for (channel = 0; channel < EMAC_MAX_RX_CHANNELS; channel++) {
+		if (dev->rx_cppi[channel] != NULL) {
+			ret_val =
+			    emac_ch_close(_dev, channel, NET_CH_DIR_RX, NULL);
+
+			if (ret_val != EMAC_SUCCESS) {
+				LOGERR("Error closing RX channel %d", channel);
+
+				/* instead of returning immediatley on
+				 *error, we close all possible
+				 *channels */
+				err_val = ret_val;	/* return ret_val; */
+			}
+		}
+	}
+
+	/* disable interrupts via module control (wrapper) */
+	davinci_writel(0, dev->emac_wrap_regs_base + EMAC_WRAP_EWCTL_REG);
+
+	/* put EMAC in reset */
+	davinci_writel(1, dev->emac_regs_base + EMAC_SOFT_RESET_REG);
+	/* NOTE: we really do not need to wait for soft reset? */
+
+	/* put MDIO in reset - not required for davinci */
+
+	LOGMSG(EMAC_DEBUG_FUNCTION_EXIT, "");
+
+	/* closed all channels successfully. mark the DDC as closed */
+	if (err_val == EMAC_SUCCESS)
+		dev->drv_state = DRV_CLOSED;
+
+	return err_val;
+}
+
+/**
+ * EMAC DDC Ioctl
+ * - Get Software (DDC) and Hardware Versions
+ * - Set/Modify RX and MAC configuration
+ * - Get DDC/module status
+ * - Read/Write MII registers (via PHY)
+ * - Get/Clr Statistics (hardware counters)
+ * - Add/Del/ Multicast operations AllMulti Set/Clear operations
+ * - Type2/3 Filtering operation
+ *
+ *"param" not used in this implementation
+ */
+int emac_control(struct emac_dev_s *_dev, int cmd, void *cmd_arg,
+				void *param)
+{
+	struct emac_dev_s *dev = (struct emac_dev_s *) _dev;
+
+	/* sanity check */
+	if (dev->drv_state != DRV_OPENED) {
+		LOGERR("ioctl called when device is NOT open");
+		return EMAC_ERR_DEV_NOT_OPEN;
+	}
+
+	switch (cmd) {
+	case EMAC_IOCTL_GET_HWVER:
+		/* read hardware versions only if device is in open state
+		 * cmd is a ptr to an integer that will contain Tx Id
+		 * ver and param is a pointer to an integer that will
+		 * contain rx id ver after this call
+		 */
+		if (dev->drv_state == DRV_OPENED) {
+			*((u32 *) cmd_arg) = davinci_readl(dev->emac_regs_base
+						+ EMAC_TX_IDVER_REG);
+			*((u32 *) param) = davinci_readl(dev->emac_regs_base
+						+ EMAC_TX_IDVER_REG);
+		} else
+			return EMAC_ERR_DEV_NOT_OPEN;
+		break;
+	case EMAC_IOCTL_SET_RXCFG:
+		/*
+		 * rx configuration structure passed in structure
+		 * pointed by cmd_arg, params not used
+		 */
+		if (cmd_arg != NULL) {
+			dev->init_cfg.rx_cfg =
+				*((struct emac_rx_config *) cmd_arg);
+			emac_set_rx_hw_cfg(_dev);
+		} else
+			return EMAC_INVALID_PARAM;
+		break;
+	case EMAC_IOCTL_SET_MACCFG:
+		/*
+		 * mac configuration structure passed in a structure
+		 * pointed by cmd_arg, params not used
+		 */
+		if (cmd_arg != NULL) {
+			dev->init_cfg.mac_cfg =
+				*((struct emac_mac_config *) cmd_arg);
+			emac_set_mac_hw_cfg(_dev);
+		} else
+			return EMAC_INVALID_PARAM;
+		break;
+	case EMAC_IOCTL_GET_STATUS:
+	/*
+	 * returns struct emac_status structure back in cmd_arg
+	 * pointer pointed structur
+	 */
+	{
+		struct emac_status *status =
+			(struct emac_status *) cmd_arg;
+		*status = dev->status;	/* structure copy */
+	}
+		break;
+	case EMAC_IOCTL_READ_PHY_REG:
+	/*
+	 * cmd = pointer to CpmacPhyParams struct. data read
+	 * back into "data" parameter in the structure
+	 */
+	{
+		/* \warning: Read to the phy registers - Note
+		   that this code loops on a completion bit in
+		   the phy so there are chances of hanging" */
+		struct emac_phy_params *phy_params =
+		    (struct emac_phy_params *) cmd_arg;
+
+		phy_params->data = emac_mdio_read(phy_params->phy_num,
+						  phy_params->reg_addr);
+	}
+		break;
+	case EMAC_IOCTL_WRITE_PHY_REG:
+	/*
+	 * cmd = pointer to CpmacPhyParams struct. data to be
+	 * written is in "data" parameter in the structure
+	 */
+	{
+		struct emac_phy_params *phy_params =
+		    (struct emac_phy_params *) cmd_arg;
+
+		/*
+		 * \warning: Write to the phy registers - Note
+		 * that this code loops on a completion bit in
+		 * the phy so there are chances of hanging"
+		 */
+		emac_mdio_write(phy_params->reg_addr,
+				phy_params->phy_num, phy_params->data);
+	}
+		break;
+	case EMAC_IOCTL_GET_STATISTICS:
+	/*
+	 * cmd_arg points to the user provided structure for
+	 * statistics which match with hardware 36 regs, param
+	 * is not used
+	 */
+	{
+		u32 cnt;
+		u32 *user_stats = (u32 *) cmd_arg;
+
+		for (cnt = 0; cnt < EMAC_NUM_STAT_REGS;
+			cnt++, user_stats++)
+			* user_stats = davinci_readl(dev->emac_regs_base
+				+ EMAC_RX_GOOD_FRAMES_REG + cnt * 4);
+	}
+
+		break;
+	case EMAC_IOCTL_CLR_STATISTICS:
+	/*
+	 * cmd_arg or param is not used
+	 */
+	{
+		u32 cnt;
+		for (cnt = 0; cnt < EMAC_NUM_STAT_REGS; cnt++) {
+			davinci_writel(EMAC_STAT_CLEAR,
+				dev->emac_regs_base
+				+ EMAC_RX_GOOD_FRAMES_REG + cnt * 4);
+			/*addr = EMAC_STAT_CLEAR; */
+			/* 0xFFFFFFFF value */
+		}
+		emac_ddcifcnt_clear(_dev);
+	}
+		break;
+	case EMAC_IOCTL_MULTICAST_ADDR:
+	/*
+	 * cmd_arg= emac_multicast_oper enum, param = pointer
+	 * to multicast address - u8
+	 */
+	{
+		u8 *addr = (u8 *) param;
+		emac_single_multi(_dev,
+				  (enum emac_single_multi_oper) cmd_arg,
+				  addr);
+	}
+		break;
+	case EMAC_IOCTL_ALL_MULTI:
+		/*
+		 * cmd_arg= enum emac_all_multi_oper enum, param=not used
+		 */
+		emac_all_multi(_dev, (enum emac_all_multi_oper) cmd_arg);
+		break;
+	case EMAC_IOCTL_TYPE2_3_FILTERING:
+	{
+		/*
+		 * cmd_arg = pointer to
+		 * struct emac_type2_3_addr_filter_params structure,
+		 * param=not used
+		 */
+		struct emac_type2_3_addr_filter_params *addr_params;
+
+		addr_params =
+		    (struct emac_type2_3_addr_filter_params *) cmd_arg;
+		emac_add_type2addr(_dev, addr_params->channel,
+				   addr_params->mac_address,
+				   addr_params->index,
+				   addr_params->valid,
+				   addr_params->match);
+	}
+		break;
+	case EMAC_IOCTL_SET_MAC_ADDRESS:
+	{
+		/*
+		 * cmd_arg = pointer to
+		 * struct emac_type2_3_addr_filter_params structure,
+		 * param=not used
+		 */
+		struct emac_address_params *addr_params;
+		struct emac_rx_cppi_ch_t *rx_cppi;
+		int cnt;
+
+		if (dev->drv_state != DRV_OPENED) {
+			LOGERR("EMAC_IOCTL_TYPE2_3_FILTERING Ioctl"
+				" called when device is NOT in open"
+				" state");
+			return EMAC_ERR_DEV_NOT_OPEN;
+		}
+
+		addr_params = (struct emac_address_params *) cmd_arg;
+		rx_cppi = dev->rx_cppi[addr_params->channel];
+		if (rx_cppi == NULL) {
+			LOGERR
+			  ("Invalid Channel %d. RX CPPI structure NULL",
+			     addr_params->channel);
+			return EMAC_ERR_RX_CH_INVALID;
+		}
+
+		for (cnt = 0; cnt < 6; cnt++)
+			rx_cppi->mac_addr[cnt] =
+			    addr_params->mac_address[cnt];
+
+		/* set interface MAC address */
+		emac_set_mac_address(_dev, addr_params->channel,
+				     addr_params->mac_address);
+	}
+		break;
+	case EMAC_IOCTL_IF_COUNTERS:
+		emac_ddcifcnt_updt(_dev);
+		memcpy(cmd_arg, &dev->mib2if_hccounter.mib2if_counter,
+		       sizeof(struct mib2_if_counters));
+		break;
+	case EMAC_IOCTL_ETHER_COUNTERS:
+		emac_ddcphycnt(_dev, cmd_arg);
+		break;
+	case EMAC_IOCTL_IF_PARAMS_UPDT:
+		emac_ddcifcnt_updt(_dev);
+		break;
+	default:
+		LOGERR("Unhandled ioctl code %d", cmd);
+		break;
+	}
+
+	return EMAC_SUCCESS;
+}
+
+/**
+ * EMAC DDC Channel Open
+ * - Verify channel info (range checking etc)
+ * - Allocate memory for the channel
+ * - Book-keep operations for the channel - ready to be enabled in hardware
+ *
+ * 1. If DDC instance is in "Opened" state, the channel is enabled in hardware
+ *      2. "chOpenArgs" is used only for opening RX channel
+ */
+static int emac_ch_open(struct emac_dev_s *_dev, struct emac_ch_info *ch_info,
+			void *ch_open_args)
+{
+	struct emac_dev_s *dev = (struct emac_dev_s *) _dev;
+	int ret_val;
+
+	LOGMSG(EMAC_DEBUG_FUNCTION_ENTRY,
+	       "ChannelNo=%d, Dir=%s",
+	       ch_info->ch_num,
+	       ((ch_info->ch_dir == NET_CH_DIR_TX) ? "TX" : "RX"));
+
+	/* if the channel state is not NET_CH_UNINITIALIZED, return error */
+	if (ch_info->ch_state != NET_CH_UNINITIALIZED) {
+		LOGERR
+		    ("%s channel %d  should be in NET_CH_UNINITIALIZED state",
+		     ((ch_info->ch_dir == NET_CH_DIR_TX) ? "TX" : "RX"),
+		     ch_info->ch_num);
+		return EMAC_INVALID_PARAM;
+	}
+
+	/* init channel */
+	if (ch_info->ch_dir == NET_CH_DIR_TX) {
+		if (ch_info->ch_num >= dev->init_cfg.num_tx_channels) {
+			LOGERR
+			    ("Invalid TX Channel=%d specified",
+			     ch_info->ch_num);
+			return EMAC_ERR_TX_CH_INVALID;
+		}
+
+		if (dev->tx_is_created[ch_info->ch_num] == TRUE) {
+			LOGERR("TX Channel %d already open", ch_info->ch_num);
+			return EMAC_ERR_TX_CH_ALREADY_INIT;
+		}
+
+		/*
+		 * allocate channel memory and perform other book-keep
+		 *functions for the channel
+		 */
+		ret_val = emac_init_tx_channel(_dev, ch_info, ch_open_args);
+		if (ret_val != EMAC_SUCCESS) {
+			LOGERR
+			    ("Error in initializing TX channel %d",
+			     ch_info->ch_num);
+			return ret_val;
+		}
+	} else if (ch_info->ch_dir == NET_CH_DIR_RX) {
+		if (ch_info->ch_num >= dev->init_cfg.num_rx_channels) {
+			LOGERR
+			    ("Invalid RX Channel=%d specified",
+			     ch_info->ch_num);
+			return EMAC_ERR_RX_CH_INVALID;
+		}
+
+		if (dev->rx_is_created[ch_info->ch_num] == TRUE) {
+			LOGERR("RX Channel %d already open", ch_info->ch_num);
+			return EMAC_ERR_RX_CH_ALREADY_INIT;
+		}
+
+		/*
+		 * allocate channel memory and perform other book-keep
+		 * functions for the channel
+		 */
+		ret_val = emac_init_rx_channel(_dev, ch_info, ch_open_args);
+
+		if (ret_val != EMAC_SUCCESS) {
+			LOGERR
+			    ("Error in initializing RX channel %d",
+			     ch_info->ch_num);
+			return ret_val;
+		}
+	}
+
+	/* if device is opened already, enable this channel for use */
+	if (dev->drv_state == DRV_OPENED) {
+		ret_val =
+		    emac_enable_channel(_dev, ch_info->ch_num, ch_info->ch_dir);
+		if (ret_val != EMAC_SUCCESS) {
+			LOGERR
+			    ("Error enabling channel %d in %d direction",
+			     ch_info->ch_num, ch_info->ch_dir);
+			return ret_val;
+		}
+	}
+
+	LOGMSG(EMAC_DEBUG_FUNCTION_EXIT,
+	       "ChannelNo=%d, Dir=%s",
+	       ch_info->ch_num,
+	       ((ch_info->ch_dir == NET_CH_DIR_TX) ? "TX" : "RX"));
+
+	return EMAC_SUCCESS;
+}
+
+/**
+ * EMAC DDC Channel Close
+ * - If DDC instance is in "Opened" state, disable the channel in hardware
+ * - Un-initialize the channel (free memory previously allocated)
+ */
+static int emac_ch_close(struct emac_dev_s *_dev, int channel,
+			 int direction, void *ch_close_args)
+{
+	struct emac_dev_s *dev = (struct emac_dev_s *) _dev;
+	int ret_val;
+
+	LOGMSG(EMAC_DEBUG_FUNCTION_ENTRY,
+	       "ChannelNo=%d, Dir=%s",
+	       channel, ((direction == NET_CH_DIR_TX) ? "TX" : "RX"));
+
+	/* disable this channel */
+	if (dev->drv_state == DRV_OPENED) {
+		ret_val = emac_disable_channel(_dev, channel, direction);
+		if (ret_val != EMAC_SUCCESS) {
+			LOGERR
+			    ("Error disabling channel %d in %s direction",
+			     channel,
+			     ((direction == NET_CH_DIR_TX) ? "TX" : "RX"));
+			return ret_val;
+		}
+	}
+
+	/* un_init channel */
+	if (direction == NET_CH_DIR_TX) {
+		ret_val = emac_un_init_tx_channel(_dev, channel, ch_close_args);
+		if (ret_val != EMAC_SUCCESS) {
+			LOGERR("Error in UnInit of TX channel %d", channel);
+			return ret_val;
+		}
+	}
+
+	else if (direction == NET_CH_DIR_RX) {
+		ret_val = emac_un_init_rx_channel(_dev, channel, ch_close_args);
+		if (ret_val != EMAC_SUCCESS) {
+			LOGERR("Error in UnInit of TX channel %d", channel);
+			return ret_val;
+		}
+	}
+
+	LOGMSG(EMAC_DEBUG_FUNCTION_EXIT,
+	       "ChannelNo=%d, Dir=%s",
+	       channel, ((direction == NET_CH_DIR_TX) ? "TX" : "RX"));
+
+	return EMAC_SUCCESS;
+}
+
+/**
+ * Init Tx Channel
+ * - Allocates memory for TX Ch Control structure, Buffer descriptors
+ * - Initialize the above data structures as per channel configuration
+ * - Chain the TX BD list ready to be given to hardware
+ *
+ * 1. "chOpenArgs" not used in this implementation
+ *
+ * 2. This function assumes that the channel number passed is valid
+ * and the hDDC->txCppi[channel] pointer is NULL. This function will
+ * not do any error check on these parameters to avoid duplicate error
+ * checks (done in caller function).
+ */
+static int emac_init_tx_channel(struct emac_dev_s *_dev,
+				struct emac_ch_info *ch_info,
+				void *ch_open_args)
+{
+	struct emac_dev_s *dev = (struct emac_dev_s *) _dev;
+	u32 cnt, bd_size;
+	char *alloc_mem;
+	struct emac_tx_bd *curr_bd;
+	struct emac_tx_cppi_ch *tx_cppi = NULL;
+
+	LOGMSG(EMAC_DEBUG_FUNCTION_ENTRY, "ChannelNo=%d", ch_info->ch_num);
+
+	/* allocate memory for TX CPPI channel and set to 0 */
+	emac_malloc(sizeof(struct emac_tx_cppi_ch), (void **)&tx_cppi);
+
+	/* update the channel control structure in DDC */
+	dev->tx_cppi[ch_info->ch_num] = tx_cppi;
+
+	/* populate channel info */
+	tx_cppi->ch_info = *ch_info;	/* structure copy */
+	tx_cppi->ch_info.ch_state = NET_CH_INITIALIZED;
+	tx_cppi->active_queue_head = 0;
+	tx_cppi->active_queue_tail = 0;
+	tx_cppi->queue_active = FALSE;
+	dev->tx_teardown_pending[ch_info->ch_num] = FALSE;
+
+#ifdef EMAC_MULTIPACKET_TX_COMPLETE_NOTIFY
+	/* allocate memory for TX CPPI channel on a 4 byte boundry */
+	emac_malloc((ch_info->service_max * sizeof(u32)),
+		    (void **)&tx_cppi->tx_complete);
+#endif
+
+	/*
+	 * allocate buffer descriptor pool align every BD on four word
+	 * boundry for future requirements
+	 */
+	bd_size = (sizeof(struct emac_tx_bd) + 0xF) & ~0xF;
+	tx_cppi->alloc_size = (((bd_size * ch_info->num_bd) + 0xF) & ~0xF);
+
+	/* alloc TX BD memory */
+	tx_cppi->bd_mem = (char *)EMAC_TX_BD_MEM;
+	memzero(tx_cppi->bd_mem, tx_cppi->alloc_size);
+
+	/* initialize the BD linked list */
+	alloc_mem = (char *)(((u32) tx_cppi->bd_mem + 0xF) & ~0xF);
+
+	tx_cppi->bd_pool_head = 0;
+	for (cnt = 0; cnt < ch_info->num_bd; cnt++) {
+		curr_bd = (struct emac_tx_bd *) (alloc_mem + (cnt * bd_size));
+		curr_bd->next = tx_cppi->bd_pool_head;
+		tx_cppi->bd_pool_head = curr_bd;
+	}
+
+	/* reset statistics counters */
+	tx_cppi->out_of_tx_bd = 0;
+	tx_cppi->no_active_pkts = 0;
+	tx_cppi->active_queue_count = 0;
+	dev->tx_is_created[ch_info->ch_num] = TRUE;
+	LOGMSG(EMAC_DEBUG_FUNCTION_EXIT, "ChannelNo=%d", ch_info->ch_num);
+
+	return EMAC_SUCCESS;
+}
+
+/**
+ * Un-Init Tx Channel
+ *
+ *- Frees memory previously allocated for Ch Control structure,
+ *    Buffer descriptors
+ *
+ * 1. "chCloseArgs" not used in this implementation
+ * 2. This function assumes that the channel number passed is valid
+ * and this function will not do any error check to avoid duplicate
+ * error checks (done in caller function).
+ */
+static int emac_un_init_tx_channel(struct emac_dev_s *_dev, u32 channel,
+				   void *ch_close_args)
+{
+	struct emac_dev_s *dev = (struct emac_dev_s *) _dev;
+	struct emac_tx_cppi_ch *tx_cppi;
+
+	LOGMSG(EMAC_DEBUG_FUNCTION_ENTRY, "ChannelNo=%d", channel);
+
+	/* check if channel structure is already de-allocated */
+	if (dev->tx_is_created[channel] == FALSE) {
+		LOGERR("TX CPPI Channel %d structure already freed", channel);
+		return EMAC_ERR_TX_CH_ALREADY_CLOSED;
+	}
+
+	tx_cppi = dev->tx_cppi[channel];
+
+	/* free the buffer descriptors memory */
+	if (tx_cppi->bd_mem != NULL)
+		tx_cppi->bd_mem = NULL;
+
+#ifdef EMAC_MULTIPACKET_TX_COMPLETE_NOTIFY
+	/* free the TX complete queue */
+	emac_free(tx_cppi->tx_complete);
+#endif
+
+	/* free the TX channel structure */
+	emac_free(tx_cppi);
+	dev->tx_cppi[channel] = NULL;
+	dev->tx_is_created[channel] = FALSE;
+	LOGMSG(EMAC_DEBUG_FUNCTION_EXIT, "ChannelNo=%d", channel);
+
+	return EMAC_SUCCESS;
+}
+
+/**
+ * Init Rx Channel
+ * - Allocates memory for RX Ch Control structure, Buffer descriptors
+ * - Initialize the above data structures as per channel configuration
+ *- Allocate receive buffers from DDA and chain the RX BD list ready
+ *    to be given to hardware
+ *
+ * 1. "chOpenArgs" Points to MAC address for this channel
+ * 2. This function assumes that the channel number passed is valid
+ * and the hDDC->rxCppi[channel] pointer is NULL. This function will
+ * not do any error check on these parameters to avoid duplicate error
+ * checks (done in caller function).
+ */
+static int emac_init_rx_channel(struct emac_dev_s *_dev,
+				struct emac_ch_info *ch_info,
+				void *ch_open_args)
+{
+	struct emac_dev_s *dev = (struct emac_dev_s *) _dev;
+	u32 cnt, bd_size;
+	char *alloc_mem;
+	struct emac_rx_bd *curr_bd;
+	struct emac_rx_cppi_ch_t *rx_cppi = NULL;
+
+	LOGMSG(EMAC_DEBUG_FUNCTION_ENTRY, "ChannelNo=%d", ch_info->ch_num);
+	/* allocate memory for RX CPPI channel */
+	emac_malloc(sizeof(struct emac_rx_cppi_ch_t), (void **)&rx_cppi);
+	/* update the channel control structure in DDC */
+	dev->rx_cppi[ch_info->ch_num] = rx_cppi;
+
+	rx_cppi->ch_info = *ch_info;	/* structure copy */
+	rx_cppi->ch_info.ch_state = NET_CH_INITIALIZED;
+	dev->rx_teardown_pending[ch_info->ch_num] = FALSE;
+
+	/* save mac address */
+	alloc_mem = (char *)ch_open_args;
+	for (cnt = 0; cnt < 6; cnt++)
+		rx_cppi->mac_addr[cnt] = alloc_mem[cnt];
+
+	/*
+	 * allocate buffer descriptor pool align every BD on four word
+	 * boundry for future requirements
+	 */
+	bd_size = (sizeof(struct emac_rx_bd) + 0xF) & ~0xF;
+	rx_cppi->alloc_size = (((bd_size * ch_info->num_bd) + 0xF) & ~0xF);
+
+	/* alloc RX BD memory */
+	rx_cppi->bd_mem = (char *) EMAC_RX_BD_MEM;
+	memzero(rx_cppi->bd_mem, rx_cppi->alloc_size);
+
+	rx_cppi->pkt_queue.buf_list = &rx_cppi->buf_queue[0];
+
+	/* allocate RX buffer and initialize the BD linked list */
+	alloc_mem = (char *)(((u32) rx_cppi->bd_mem + 0xF) & ~0xF);
+	rx_cppi->active_queue_head = 0;
+	rx_cppi->active_queue_tail = (struct emac_rx_bd *) alloc_mem;
+	for (cnt = 0; cnt < ch_info->num_bd; cnt++) {
+		curr_bd = (struct emac_rx_bd *) (alloc_mem + (cnt * bd_size));
+
+		/*
+		 * for potential future use the last parameter
+		 * contains the BD ptr
+		 */
+		curr_bd->data_ptr =
+		    (void *)(emac_net_alloc_rx_buf(dev,
+						   ch_info->buf_size,
+						   (void **) &
+						   curr_bd->buf_token, 0,
+						   (void *)curr_bd));
+		if (curr_bd->data_ptr == NULL) {
+			LOGERR
+			    ("Error in RX Buffer allocation for channel %d",
+			     ch_info->ch_num);
+			return EMAC_ERR_RX_BUFFER_ALLOC_FAIL;
+		}
+
+		/* populate the hardware descriptor */
+		curr_bd->h_next = EMAC_VIRT_TO_PHYS(rx_cppi->active_queue_head);
+		curr_bd->buff_ptr = EMAC_VIRT_TO_PHYS(curr_bd->data_ptr);
+		curr_bd->off_b_len = ch_info->buf_size;
+		curr_bd->mode = EMAC_CPPI_OWNERSHIP_BIT;
+
+		/* write back to hardware memory */
+		BD_CACHE_WRITEBACK_INVALIDATE((u32) curr_bd,
+					      EMAC_BD_LENGTH_FOR_CACHE);
+		curr_bd->next = (void *)rx_cppi->active_queue_head;
+		rx_cppi->active_queue_head = curr_bd;
+	}
+
+	/*
+	 * At this point rxCppi->activeQueueHead points to the first
+	 * RX BD ready to be given to RX HDP and
+	 * rx_cppi->active_queue_tail points to the last RX BD
+	 */
+	dev->rx_is_created[ch_info->ch_num] = TRUE;
+
+	LOGMSG(EMAC_DEBUG_FUNCTION_EXIT, "ChannelNo=%d", ch_info->ch_num);
+	return EMAC_SUCCESS;
+}
+
+/**
+ * Un-Init Rx Channel
+ *- Frees memory previously allocated for Ch Control structure,
+ *    Buffer descriptors
+ *- Returns (Frees) back receive buffers to DDA layer
+ *
+ * 1. "chCloseArgs" not used in this implementation
+ * 2. This function assumes that the channel number passed is valid
+ * and this function will not do any error check to avoid duplicate
+ * error checks (done in caller function).
+ */
+static int emac_un_init_rx_channel(struct emac_dev_s *_dev, u32 channel,
+				   void *ch_close_args)
+{
+	struct emac_dev_s *dev = (struct emac_dev_s *) _dev;
+	struct emac_rx_cppi_ch_t *rx_cppi;
+	struct emac_rx_bd *curr_bd;
+
+	LOGMSG(EMAC_DEBUG_FUNCTION_ENTRY, "ChannelNo=%d", channel);
+
+	/* check if channel structure is already de-allocated */
+	if (dev->rx_is_created[channel] == FALSE) {
+		LOGERR("RX CPPI Channel %d structure already freed", channel);
+		return EMAC_ERR_RX_CH_ALREADY_CLOSED;
+	}
+
+	rx_cppi = dev->rx_cppi[channel];
+
+	/* free the receive buffers previously allocated */
+	curr_bd = rx_cppi->active_queue_head;
+	while (curr_bd) {
+		if (emac_net_free_rx_buf(dev,
+					 curr_bd->data_ptr,
+					 (void *) curr_bd->
+					 buf_token, 0, NULL) != EMAC_SUCCESS)
+			LOGERR("Failed to free RX buffer Ch %d", channel);
+		curr_bd = curr_bd->next;
+	}
+
+	/* free the buffer descriptors memory */
+	if (rx_cppi->bd_mem != NULL)
+		rx_cppi->bd_mem = NULL;
+
+	/* free the RX channel structure */
+	emac_free(rx_cppi);
+	dev->rx_cppi[channel] = NULL;
+	dev->rx_is_created[channel] = FALSE;
+	LOGMSG(EMAC_DEBUG_FUNCTION_EXIT, "ChannelNo=%d", channel);
+
+	return EMAC_SUCCESS;
+}
+
+/**
+ * Set EMAC Mac address
+ * Functionality provided:
+ * - EMAC address is set in the hardware based on the address type
+ *
+ * 1. It is assumed that the channel is already "initialized"
+ */
+static void emac_set_mac_address(struct emac_dev_s *_dev, u32 channel,
+				char *mac_addr)
+{
+	struct emac_dev_s *dev = (struct emac_dev_s *) _dev;
+
+	/* enable unicast on this channel */
+	davinci_writel((1 << channel), dev->emac_regs_base
+		+ EMAC_RX_UNICAST_SET_REG);
+
+	/* program MAC address for the channel depending upon emac/cpgmac */
+	if (dev->rx_addr_type == RX_ADDR_TYPE0)
+		emac_add_type0addr(_dev, channel, mac_addr);
+	else if (dev->rx_addr_type == RX_ADDR_TYPE1)
+		emac_add_type1addr(_dev, channel, mac_addr);
+	else if (dev->rx_addr_type == RX_ADDR_TYPE2)
+		emac_add_type2addr(_dev, channel, mac_addr, 0, 1, 1);
+	else
+		LOGERR
+		    ("Wrong Rx Addressing Type - (Type2) detected in hardware");
+}
+
+/**
+ * Enable TX/RX Channel
+ * Functionality provided:
+ *- Channel is enabled in hardware. Data transfer can occur on this
+ *    channel after this.
+ *
+ * 1. It is assumed that the channel is already "initialized"
+ * 2. To enable a channel after its disabled, it needs to be initialized again
+ */
+static int emac_enable_channel(struct emac_dev_s *_dev, u32 channel,
+				u32 direction)
+{
+	struct emac_dev_s *dev = (struct emac_dev_s *) _dev;
+
+	LOGMSG(EMAC_DEBUG_FUNCTION_ENTRY,
+	       "ChannelNo=%d, Direction=%s",
+	       channel, ((direction == NET_CH_DIR_TX) ? "TX" : "RX"));
+
+	if (direction == NET_CH_DIR_TX) {
+		struct emac_tx_cppi_ch *tx_cppi;
+
+		tx_cppi = dev->tx_cppi[channel];
+		if (tx_cppi == NULL) {
+			LOGERR("Invalid Channel %d. TX CPPI structure NULL",
+			     channel);
+
+			return EMAC_ERR_TX_CH_INVALID;
+		}
+
+		/* init head descriptor pointer */
+		davinci_writel(0, dev->emac_regs_base
+				+ EMAC_TX_HDP_REG(channel));
+		{
+			struct emac_mac_config *mac_cfg;
+
+			mac_cfg = &dev->init_cfg.mac_cfg;
+			if (mac_cfg->tx_interrupt_disable == TRUE) {
+				/* disable channel interrupt */
+				davinci_writel((1 << channel),
+						dev->emac_regs_base
+					+ EMAC_TX_INT_MASK_CLEAR_REG);
+				dev->tx_interrupt_disable = TRUE;
+				dev->tx_int_threshold[channel] =
+				    dev->tx_cppi[channel]->ch_info.service_max;
+			} else {
+				/* enable channel interrupt */
+				davinci_writel((1 << channel),
+						dev->emac_regs_base
+						+ EMAC_TX_INT_MASK_SET_REG);
+				dev->tx_interrupt_disable = FALSE;
+			}
+		}
+
+		/* mark channel open */
+		dev->tx_is_open[channel] = TRUE;
+		tx_cppi->ch_info.ch_state = NET_CH_OPENED;
+	}
+
+	else if (direction == NET_CH_DIR_RX) {
+		struct emac_rx_cppi_ch_t *rx_cppi;
+
+		rx_cppi = dev->rx_cppi[channel];
+		if (rx_cppi == NULL) {
+			LOGERR
+			    ("Invalid Channel %d. RX CPPI structure NULL",
+			     channel);
+
+			return EMAC_ERR_RX_CH_INVALID;
+		}
+
+		/* set interface MAC address */
+		emac_set_mac_address(_dev, channel, rx_cppi->mac_addr);
+
+		/* enable channel interrupt */
+		davinci_writel((1 << channel),
+			dev->emac_regs_base + EMAC_RX_INT_MASK_SET_REG);
+
+		/* mark queue active */
+		rx_cppi->queue_active = TRUE;
+
+		/* enable DMA */
+		davinci_writel(EMAC_VIRT_TO_PHYS(rx_cppi->active_queue_head),
+		dev->emac_regs_base + EMAC_RX_HDP_REG(channel));
+
+		/* mark channel open */
+		dev->rx_is_open[channel] = TRUE;
+
+		rx_cppi->ch_info.ch_state = NET_CH_OPENED;
+
+	}
+
+	LOGMSG(EMAC_DEBUG_FUNCTION_EXIT,
+	       "ChannelNo=%d, Direction=%s",
+	       channel, ((direction == NET_CH_DIR_TX) ? "TX" : "RX"));
+
+	return EMAC_SUCCESS;
+}
+
+/**
+ * Disable TX/RX Channel
+ * Functionality provided:
+ *- Channel is disabled in hardware. No data transfer can occur on
+ *   this channel after this.
+ *
+ * 1. It is assumed that the channel number passed is valid
+ * 2. Resources for the channel will be released only when its closed
+ */
+static int emac_disable_channel(struct emac_dev_s *_dev, u32 channel,
+				enum net_ch_dir direction)
+{
+	struct emac_dev_s *dev = (struct emac_dev_s *) _dev;
+
+	LOGMSG(EMAC_DEBUG_FUNCTION_ENTRY,
+	       "ChannelNo=%d, Direction=%s",
+	       channel, ((direction == NET_CH_DIR_TX) ? "TX" : "RX"));
+
+	if (direction == NET_CH_DIR_TX) {
+
+		/* set the TX teardown pending flag */
+		dev->tx_teardown_pending[channel] = TRUE;
+
+		/* initiate teardown of TX channel */
+		davinci_writel(channel,
+				dev->emac_regs_base + EMAC_TX_TEARDOWN_REG);
+
+		/* wait for teardown complete */
+		if (emac_wait_for_teardown_complete
+		    (_dev, channel, direction, TRUE) != EMAC_SUCCESS) {
+
+			LOGERR("Failed to teardown TX channel %d", channel);
+
+			/* instead of quitting on error immediately,
+			 *we continue so as to cleanup the channel */
+		}
+
+		dev->tx_teardown_pending[channel] = FALSE;
+
+		/* disable interrupt */
+		davinci_writel((1 << channel),
+			dev->emac_regs_base + EMAC_TX_INT_MASK_CLEAR_REG);
+
+		/* disable DMA */
+
+		/* mark channel closed */
+		dev->tx_is_open[channel] = FALSE;
+	}
+
+	else if (direction == NET_CH_DIR_RX) {
+		dev->rx_teardown_pending[channel] = TRUE;
+
+		/* initiate teardown of TX channel */
+		davinci_writel(channel,
+			dev->emac_regs_base + EMAC_RX_TEARDOWN_REG);
+
+		/* wait for teardown complete */
+		if (emac_wait_for_teardown_complete
+		    (_dev, channel, direction, TRUE) != EMAC_SUCCESS)
+			LOGERR("Failed to teardown RX channel %d", channel);
+
+		dev->rx_teardown_pending[channel] = FALSE;
+
+		/* disable interrupt */
+		davinci_writel((1 << channel),
+			dev->emac_regs_base + EMAC_RX_INT_MASK_CLEAR_REG);
+
+		/* mark channel closed */
+		dev->rx_is_open[channel] = FALSE;
+	}
+
+	LOGMSG(EMAC_DEBUG_FUNCTION_EXIT,
+	       "ChannelNo=%d, Direction=%s",
+	       channel, ((direction == NET_CH_DIR_TX) ? "TX" : "RX"));
+
+	return EMAC_SUCCESS;
+}
+
+/**
+ * Wait for Teardown Complete
+ * - This function waits (blocking mode) for teardown completion.
+ * - blocking = TRUE(waits on OS timer wait untill teardown complete),
+ *            = FALSE (returns immediately) - NOT SUPPORTED
+ * As of now this function supports blocking mode in polled mode only
+ */
+static int emac_wait_for_teardown_complete(struct emac_dev_s *_dev,
+					u32 channel,
+					enum net_ch_dir direction,
+					bool blocking)
+{
+	struct emac_dev_s *dev = (struct emac_dev_s *) _dev;
+	static unsigned int teardown_cnt = 0xFFFFFFF0;
+
+	if (direction == NET_CH_DIR_TX) {
+		struct emac_tx_bd *curr_bd;
+		struct emac_tx_cppi_ch *tx_cppi;
+
+		LOGMSG(EMAC_DEBUG_FUNCTION_ENTRY,
+		       "ChannelNo=%d, Direction=%s",
+		       channel, ((direction == NET_CH_DIR_TX) ? "TX" : "RX"));
+
+		while ((davinci_readl(dev->emac_regs_base +
+			EMAC_TX_CP_REG(channel)) & EMAC_TEARDOWN_VALUE) !=
+							EMAC_TEARDOWN_VALUE) {
+			/*
+			 * wait here for tx teardown completion
+			 * interrupt to occur
+			 */
+
+			/*
+			 * A task delay can be called here to pend
+			 * rather than occupying CPU cycles - anyway
+			 * it has been found that the teardown takes
+			 * very few cpu cycles and does not affect
+			 * functionality
+			 */
+			--teardown_cnt;
+			if (teardown_cnt) {
+				printk(KERN_NOTICE "Tx teardown aborted\n");
+				break;
+			}
+		}
+
+		/* write to the completion pointer */
+		davinci_writel(EMAC_TEARDOWN_VALUE,
+			dev->emac_regs_base + EMAC_TX_CP_REG(channel));
+
+		/*
+		 * TX teardown complete - process sent packets and
+		 * return sent packets to DDA
+		 */
+		tx_cppi = dev->tx_cppi[channel];
+		if (tx_cppi->queue_active == TRUE) {
+			curr_bd = tx_cppi->active_queue_head;
+			while (curr_bd != NULL) {
+				emac_net_tx_complete(dev,
+						     &(curr_bd->buf_token),
+						     1, channel);
+
+				if (curr_bd != tx_cppi->active_queue_tail)
+					curr_bd = curr_bd->next;
+				else
+					break;
+			}
+			tx_cppi->bd_pool_head = tx_cppi->active_queue_head;
+			tx_cppi->active_queue_head =
+			    tx_cppi->active_queue_tail = 0;
+		}
+
+		/* At this stage all TX BD's are available linked with
+		 *"bdPoolHead" and can be freed */
+		LOGMSG(EMAC_DEBUG_FUNCTION_EXIT,
+		       "ChannelNo=%d, Direction=%s",
+		       channel, ((direction == NET_CH_DIR_TX) ? "TX" : "RX"));
+	} else if (direction == NET_CH_DIR_RX) {
+		LOGMSG(EMAC_DEBUG_FUNCTION_ENTRY,
+		       "ChannelNo=%d, Direction=%s",
+		       channel, ((direction == NET_CH_DIR_TX) ? "TX" : "RX"));
+
+		while ((davinci_readl(dev->emac_regs_base +
+			EMAC_RX_CP_REG(channel)) & EMAC_TEARDOWN_VALUE) !=
+							EMAC_TEARDOWN_VALUE) {
+
+			/*
+			 * wait here for rx teardown completion
+			 * interrupt to occur
+			 */
+
+			/*
+			 * A task delay can be called here to pend
+			 * rather than occupying CPU cycles - anyway
+			 * it has been found that the teardown takes
+			 * very few cpu cycles and does not affect
+			 * functionality
+			 */
+			--teardown_cnt;
+			if (teardown_cnt) {
+				printk(KERN_NOTICE"Rx teardown aborted\n");
+				break;
+			}
+		}
+
+		/* write to the completion pointer */
+		davinci_writel(EMAC_TEARDOWN_VALUE,
+			dev->emac_regs_base + EMAC_RX_CP_REG(channel));
+
+		/* At this stage all TX BD's are available linked with
+		 *"activeQueueHead" and can be freed */
+		LOGMSG(EMAC_DEBUG_FUNCTION_EXIT,
+		       "ChannelNo=%d, Direction=%s",
+		       channel, ((direction == NET_CH_DIR_TX) ? "TX" : "RX"));
+
+	}
+
+	return EMAC_SUCCESS;
+}
+
+static void emac_ddcphycnt(struct emac_dev_s *dev, u32 *cmd_arg)
+{
+	int result;
+	struct emac_hw_statistics stats;
+	struct mib2_phy_counters *mib2phy_counters =
+	    (struct mib2_phy_counters *)cmd_arg;
+
+	result =
+	    emac_control(dev, EMAC_IOCTL_GET_STATISTICS, (u32 *) &stats, NULL);
+
+	if (result != 0) {
+		LOGERR("Error from ioctl for EMAC_IOCTL_GET_STATISTICS \n");
+		return;
+	}
+
+	mib2phy_counters->eth_alignment_errors = stats.if_in_align_code_errors;
+	mib2phy_counters->eth_fcserrors = stats.if_in_crcerrors;
+	mib2phy_counters->eth_single_collisions =
+	    stats.if_single_collision_frames;
+	mib2phy_counters->eth_multiple_collisions =
+	    stats.if_multiple_collision_frames;
+	mib2phy_counters->eth_sqetest_errors = 0;
+	mib2phy_counters->eth_deferred_tx_frames =
+	    stats.if_deferred_transmissions;
+	mib2phy_counters->eth_late_collisions = stats.if_late_collisions;
+	mib2phy_counters->eth_excessive_collisions =
+	    stats.if_excessive_collision_frames;
+	mib2phy_counters->eth_internal_mac_tx_errors = 0;
+	mib2phy_counters->eth_carrier_sense_errors =
+	    stats.if_carrier_sense_errors;
+	mib2phy_counters->eth_too_long_rx_frames = stats.if_in_oversized_frames;
+	mib2phy_counters->eth_internal_mac_rx_errors = 0;
+	mib2phy_counters->eth_symbol_errors = 0;
+}
+
+static void emac_ddcifcnt_clear(struct emac_dev_s *_dev)
+{
+	struct emac_dev_s *dev = (struct emac_dev_s *) _dev;
+
+	memzero((char *)&dev->mib2if_hccounter, sizeof(dev->mib2if_hccounter));
+}
+
+static void emac_ddcifcnt_updt(struct emac_dev_s *_dev)
+{
+	struct emac_dev_s *dev = (struct emac_dev_s *) _dev;
+	int result;
+	struct emac_hw_statistics stats;
+
+	result =
+	    emac_control(_dev, EMAC_IOCTL_GET_STATISTICS,
+			 (u32 *) &stats, NULL);
+
+	if (result != 0) {
+		LOGERR("Error from ioctl for DDC EMAC_IOCTL_GET_STATISTICS \n");
+		return;
+	}
+
+	if (stats.if_in_octets >= dev->mib2if_hccounter.in_bytes) {
+		dev->mib2if_hccounter.in_bytes_hc +=
+		    (stats.if_in_octets - dev->mib2if_hccounter.in_bytes);
+	} else {
+		dev->mib2if_hccounter.in_bytes_hc +=
+		    0xffffffff - (dev->mib2if_hccounter.in_bytes -
+				  stats.if_in_octets);
+	}
+
+	dev->mib2if_hccounter.in_bytes = stats.if_in_octets;
+	if (stats.if_in_good_frames >=
+	    dev->mib2if_hccounter.in_multicast_pkts +
+	    dev->mib2if_hccounter.in_broadcast_pkts +
+	    dev->mib2if_hccounter.in_unicast_pkts) {
+		dev->mib2if_hccounter.in_unicast_pkts_hc +=
+		    ((stats.if_in_good_frames -
+		      (stats.if_in_broadcasts + stats.if_in_multicasts))
+		     - dev->mib2if_hccounter.in_unicast_pkts);
+	} else {
+		dev->mib2if_hccounter.in_unicast_pkts_hc +=
+		    0xffffffff - (dev->mib2if_hccounter.in_unicast_pkts -
+				  (stats.if_in_good_frames -
+				   (stats.if_in_broadcasts +
+				    stats.if_in_multicasts)));
+	}
+	dev->mib2if_hccounter.in_unicast_pkts = (stats.if_in_good_frames -
+						 (stats.if_in_broadcasts +
+						  stats.if_in_multicasts));
+	if (stats.if_in_multicasts >= dev->mib2if_hccounter.in_multicast_pkts) {
+		dev->mib2if_hccounter.in_multicast_pkts_hc +=
+		    (stats.if_in_multicasts -
+		     dev->mib2if_hccounter.in_multicast_pkts);
+	} else {
+		dev->mib2if_hccounter.in_multicast_pkts_hc +=
+		    0xffffffff - (dev->mib2if_hccounter.in_multicast_pkts -
+				  stats.if_in_multicasts);
+	}
+
+	dev->mib2if_hccounter.in_multicast_pkts = stats.if_in_multicasts;
+	if (stats.if_in_broadcasts >= dev->mib2if_hccounter.in_broadcast_pkts) {
+		dev->mib2if_hccounter.in_broadcast_pkts_hc +=
+		    (stats.if_in_broadcasts -
+		     dev->mib2if_hccounter.in_broadcast_pkts);
+
+	} else {
+		dev->mib2if_hccounter.in_broadcast_pkts_hc +=
+		    0xffffffff - (dev->mib2if_hccounter.in_broadcast_pkts -
+				  stats.if_in_broadcasts);
+	}
+
+	dev->mib2if_hccounter.in_broadcast_pkts = stats.if_in_broadcasts;
+	if (stats.if_out_octets >= dev->mib2if_hccounter.out_bytes) {
+		dev->mib2if_hccounter.out_bytes_hc +=
+		    (stats.if_out_octets - dev->mib2if_hccounter.out_bytes);
+	} else {
+		dev->mib2if_hccounter.out_bytes_hc +=
+		    0xffffffff - (dev->mib2if_hccounter.out_bytes -
+				  stats.if_out_octets);
+	}
+
+	dev->mib2if_hccounter.out_bytes = stats.if_out_octets;
+	if (stats.if_out_good_frames >=
+	    dev->mib2if_hccounter.out_multicast_pkts +
+	    dev->mib2if_hccounter.out_broadcast_pkts +
+	    dev->mib2if_hccounter.out_unicast_pkts)
+		dev->mib2if_hccounter.out_unicast_pkts_hc +=
+		    ((stats.if_out_good_frames -
+		      (stats.if_out_broadcasts + stats.if_out_multicasts))
+		     - dev->mib2if_hccounter.out_unicast_pkts);
+	else
+		dev->mib2if_hccounter.out_unicast_pkts_hc +=
+		    0xffffffff - (dev->mib2if_hccounter.out_unicast_pkts -
+				  (stats.if_out_good_frames -
+				   (stats.if_out_broadcasts +
+				    stats.if_out_multicasts)));
+
+	dev->mib2if_hccounter.out_unicast_pkts = (stats.if_out_good_frames -
+						  (stats.if_out_broadcasts +
+						   stats.if_out_multicasts));
+
+	if (stats.if_out_multicasts >=
+		dev->mib2if_hccounter.out_multicast_pkts)
+		dev->mib2if_hccounter.out_multicast_pkts_hc +=
+			(stats.if_out_multicasts -
+		dev->mib2if_hccounter.out_multicast_pkts);
+	else
+		dev->mib2if_hccounter.out_multicast_pkts_hc +=
+			0xffffffff - (dev->mib2if_hccounter.out_multicast_pkts -
+			stats.if_out_multicasts);
+
+	dev->mib2if_hccounter.out_multicast_pkts = stats.if_out_multicasts;
+	if (stats.if_out_broadcasts >=
+		dev->mib2if_hccounter.out_broadcast_pkts)
+
+		dev->mib2if_hccounter.out_broadcast_pkts_hc +=
+			(stats.if_out_broadcasts -
+		dev->mib2if_hccounter.out_broadcast_pkts);
+	else
+		dev->mib2if_hccounter.out_broadcast_pkts_hc +=
+		    0xffffffff - (dev->mib2if_hccounter.out_broadcast_pkts -
+				  stats.if_out_broadcasts);
+	dev->mib2if_hccounter.out_broadcast_pkts = stats.if_out_broadcasts;
+
+	/* low 32-bit of total octets received from media */
+	dev->mib2if_hccounter.mib2if_counter.in_bytes_low =
+	    (unsigned long)dev->mib2if_hccounter.in_bytes_hc;
+
+	/* high 32-bit of total octets received from media */
+	dev->mib2if_hccounter.mib2if_counter.in_bytes_high =
+	    (dev->mib2if_hccounter.in_bytes_hc >> 32);
+
+	/* low 32-bit of total octets received from media */
+	dev->mib2if_hccounter.mib2if_counter.in_unicast_pkts_low =
+	    (unsigned long)dev->mib2if_hccounter.in_unicast_pkts_hc;
+
+	/* high 32-bit of total octets received from media */
+	dev->mib2if_hccounter.mib2if_counter.in_unicast_pkts_high =
+	    (dev->mib2if_hccounter.in_unicast_pkts_hc >> 32);
+
+	/* low 32-bit of total octets received from media */
+	dev->mib2if_hccounter.mib2if_counter.in_multicast_pkts_low =
+	    (unsigned long)dev->mib2if_hccounter.in_multicast_pkts_hc;
+
+	/* high 32-bit of total octets received from media */
+	dev->mib2if_hccounter.mib2if_counter.in_multicast_pkts_high =
+	    dev->mib2if_hccounter.in_multicast_pkts_hc >> 32;
+
+	/* low 32-bit of total octets received from media */
+	dev->mib2if_hccounter.mib2if_counter.in_broadcast_pkts_low =
+	    (unsigned long)dev->mib2if_hccounter.in_broadcast_pkts_hc;
+
+	/* high 32-bit of total octets received from media */
+	dev->mib2if_hccounter.mib2if_counter.in_broadcast_pkts_high =
+	    dev->mib2if_hccounter.in_broadcast_pkts_hc >> 32;
+
+	/* packets discarded due to resource limit */
+	dev->mib2if_hccounter.mib2if_counter.in_discard_pkts =
+	    stats.if_rx_dmaoverruns
+	    + stats.if_rx_mof_overruns
+	    + stats.
+	    if_rx_sof_overruns
+	    + stats.if_in_crcerrors
+	    + stats.
+	    if_in_align_code_errors
+	    + stats.if_in_jabber_frames
+	    + stats.
+	    if_in_fragments
+	    + stats.if_in_oversized_frames
+	    + stats.
+	    if_in_undersized_frames
+	    + stats.if_in_filtered_frames + stats.if_in_qos_filtered_frames;
+
+	/* packets discarded due to format errors */
+	dev->mib2if_hccounter.mib2if_counter.in_error_pkts =
+	    stats.if_in_crcerrors
+	    + stats.if_in_align_code_errors
+	    + stats.if_in_jabber_frames + stats.if_in_fragments;
+
+	dev->mib2if_hccounter.mib2if_counter.in_unknown_prot_pkts = 0;
+
+	/* low 32-bit of total octets received from media */
+	dev->mib2if_hccounter.mib2if_counter.out_bytes_low =
+	    (unsigned long)dev->mib2if_hccounter.out_bytes_hc;
+
+	/* high 32-bit of total octets received from media */
+	dev->mib2if_hccounter.mib2if_counter.out_bytes_high =
+	    dev->mib2if_hccounter.out_bytes_hc >> 32;
+
+	/* low 32-bit of total octets received from media */
+	dev->mib2if_hccounter.mib2if_counter.out_unicast_pkts_low =
+	    (unsigned long)dev->mib2if_hccounter.out_unicast_pkts_hc;
+
+	/* high 32-bit of total octets received from media */
+	dev->mib2if_hccounter.mib2if_counter.out_unicast_pkts_high =
+	    dev->mib2if_hccounter.out_unicast_pkts_hc >> 32;
+
+	/* low 32-bit of total octets received from media */
+	dev->mib2if_hccounter.mib2if_counter.out_multicast_pkts_low =
+	    (unsigned long)dev->mib2if_hccounter.out_multicast_pkts_hc;
+
+	/* high 32-bit of total octets received from media */
+	dev->mib2if_hccounter.mib2if_counter.out_multicast_pkts_high =
+	    dev->mib2if_hccounter.out_multicast_pkts_hc >> 32;
+
+	/* low 32-bit of total octets received from media */
+	dev->mib2if_hccounter.mib2if_counter.out_broadcast_pkts_low =
+	    (unsigned long)dev->mib2if_hccounter.out_broadcast_pkts_hc;
+
+	/* high 32-bit of total octets received from media */
+	dev->mib2if_hccounter.mib2if_counter.out_broadcast_pkts_high =
+	    dev->mib2if_hccounter.out_broadcast_pkts_hc >> 32;
+
+	/* packets discarded due to format errors */
+	dev->mib2if_hccounter.mib2if_counter.out_error_pkts =
+	    (stats.if_excessive_collision_frames
+	     + stats.if_late_collisions + stats.if_carrier_sense_errors);
+
+	/* packets discarded due to resource limit */
+	dev->mib2if_hccounter.mib2if_counter.out_discard_pkts =
+	    stats.if_out_underrun +
+	    dev->mib2if_hccounter.mib2if_counter.out_error_pkts;
+}
+
+#define emac_min_val(a, b)	((a > b) ? b : a)
+
+#ifdef EMAC_DEBUG		/*  used only for debug printing  */
+/* static global strings */
+static char *emac_tx_host_error_codes[16] = {
+	/* 0000 */ "No error",
+	/* 0001 */ "SOP error",
+	/* 0010 */ "Ownership bit not set in SOP buffer",
+	/* 0011 */ "Zero Next Buffer Descriptor Pointer Without EOP",
+	/* 0100 */ "Zero Buffer Pointer",
+	/* 0101 */ "Zero Buffer Length",
+	/* 0110 */ "Packet Length Error",
+	/* 0111 */ "Reserved",
+	/* 1000 */ "Reserved",
+	/* 1001 */ "Reserved",
+	/* 1010 */ "Reserved",
+	/* 1011 */ "Reserved",
+	/* 1100 */ "Reserved",
+	/* 1101 */ "Reserved",
+	/* 1110 */ "Reserved",
+	/* 1111 */ "Reserved"
+};
+
+static char *emac_rx_host_error_codes[16] = {
+	/* 0000 */ "No error",
+	/* 0001 */ "Reserved",
+	/* 0010 */ "Ownership bit not set in input buffer",
+	/* 0011 */ "Reserved",
+	/* 0100 */ "Zero Buffer Pointer",
+	/* 0101 */ "Reserved",
+	/* 0110 */ "Reserved",
+	/* 0111 */ "Reserved",
+	/* 1000 */ "Reserved",
+	/* 1001 */ "Reserved",
+	/* 1010 */ "Reserved",
+	/* 1011 */ "Reserved",
+	/* 1100 */ "Reserved",
+	/* 1101 */ "Reserved",
+	/* 1110 */ "Reserved",
+	/* 1111 */ "Reserved"
+};
+
+#endif				/* EMAC_DEBUG */
+
+/**
+ * EMAC DDC Periodic Timer (Tick) Function
+ * - calls PHY polling function
+ * - If status changed, invokes DDA callback to propogate PHY / Devicestatus
+ *
+ *"tickArgs" is not used in this implementation
+ */
+static int emac_tick(struct emac_dev_s *_dev, void *tick_args)
+{
+	struct emac_dev_s *dev = (struct emac_dev_s *) _dev;
+
+	/* verify proper device state */
+	if (dev->drv_state != DRV_OPENED)
+		return EMAC_ERR_DEV_NOT_OPEN;
+
+	if (!(dev->init_cfg.phy_mode & SNWAY_NOPHY)) {
+		/* opened and phy available */
+		int tick_change;
+
+		tick_change = emac_mdio_tick();
+		if (tick_change == 1) {
+			/*  MDIO indicated a change  */
+			emac_update_phy_status((struct emac_dev_s *) dev);
+			emac_control_cb(dev,
+					EMAC_IOCTL_STATUS_UPDATE,
+					(void *)&dev->status, NULL);
+		}
+	}
+
+	return EMAC_SUCCESS;
+}
+
+/**
+ * EMAC DDC Packet processing function
+ * - Detects if there are host errors and invokes the DDA callback to inform
+ *   the DDA layer about the hardware error.
+ *
+ */
+static void emac_process_host_error(struct emac_dev_s *_dev)
+{
+	struct emac_dev_s *dev = (struct emac_dev_s *) _dev;
+	u32 channel = 0;
+	u32 vector = 0;
+	u32 status = 0;
+
+	/*
+	 * the mac_status register bits starting from rx error channel
+	 * have been mapped to hw_err_info LSB 16 bits
+	 */
+	status = davinci_readl(dev->emac_regs_base + EMAC_MAC_STATUS_REG);
+
+	/* TX: reading the channel and cause */
+	channel =
+	    ((status & EMAC_MACSTATUS_TXERRCH_MASK) >>
+	     EMAC_MACSTATUS_TXERRCH_SHIFT);
+
+	dev->status.hw_err_info = channel << 16;
+
+	vector =
+	    (status & EMAC_MACSTATUS_TXERRCODE_MASK) >>
+	    EMAC_MACSTATUS_TXERRCODE_SHIFT;
+
+	if (vector) {
+		dev->status.hw_status = EMAC_TX_HOST_ERROR;
+		LOGERR
+		    ("Ch=%d, EMAC_TX_HOST_ERROR. Cause=%s",
+		     dev->status.hw_err_info,
+		     &emac_tx_host_error_codes[vector][0]);
+	}
+
+	/* RX: reading the channel and cause (vector variable being
+	 *re-used) */
+	channel =
+	    ((status & EMAC_MACSTATUS_RXERRCH_MASK) >>
+	     EMAC_MACSTATUS_RXERRCH_SHIFT);
+
+	dev->status.hw_err_info |= channel;
+	vector =
+	    (status & EMAC_MACSTATUS_RXERRCODE_MASK) >>
+	    EMAC_MACSTATUS_RXERRCODE_SHIFT;
+	if (vector) {
+		dev->status.hw_status = EMAC_RX_HOST_ERROR;
+		LOGERR
+		    ("Ch=%d, EMAC_RX_HOST_ERROR. Cause=%s",
+		     dev->status.hw_err_info,
+		     &emac_rx_host_error_codes[vector][0]);
+	}
+
+	/* inform DDA layer about this critical failure */
+	emac_control_cb(dev,
+			EMAC_IOCTL_STATUS_UPDATE, (void *)&dev->status, NULL);
+}
+
+/**
+ * EMAC DDC Packet processing function
+
+ *- Reads the device interrupt status and invokes TX/RX BD processing
+ *  function
+ *- Also detects if there are host errors and invokes the
+ *  callback to inform  about the hardware error.
+ *
+ *"pkts_pending" will contain number of packets still to be processed
+ * (TX + RX)
+ */
+static int emac_pkt_process(struct emac_dev_s *_dev, int *pkts_pending,
+			    void *pkt_args)
+{
+	struct emac_dev_s *dev = (struct emac_dev_s *) _dev;
+	u32 channel = 0;
+	u32 vector = 0;
+	u32 handle_pkts_and_status = 0;
+	u32 vector_channel = 0;
+	int pkts_processed = 0;
+
+	/* disable interrupts via module control (wrapper) */
+	davinci_writel(0, dev->emac_wrap_regs_base + EMAC_WRAP_EWCTL_REG);
+	vector = davinci_readl(dev->emac_regs_base + EMAC_MAC_IN_VECTOR_REG);
+
+	/* handle packet transmit completion */
+	if (vector & EMAC_MAC_IN_VECTOR_TX_INT_VEC) {
+		bool is_eoq;
+
+		vector_channel = (vector & EMAC_MAC_IN_VECTOR_TX_INT_VEC);
+		for (channel = 0; channel < 8; channel++) {
+			if (vector_channel & 0x1)
+				break;
+
+			vector_channel >>= 1;
+		}
+
+		handle_pkts_and_status =
+		    dev->tx_cppi[channel]->ch_info.service_max;
+		if (pkt_args)
+			handle_pkts_and_status =
+			    emac_min_val(((struct rx_tx_params *) pkt_args)->
+				tx_pkts, handle_pkts_and_status);
+
+		pkts_processed =
+		    emac_tx_bdproc(_dev, channel, &handle_pkts_and_status,
+				   &is_eoq);
+		if (pkt_args)
+			((struct rx_tx_params *) pkt_args)->ret_tx_pkts =
+			    pkts_processed;
+
+		if (dev->tx_interrupt_disable == TRUE) {
+			/* status */
+			if (!handle_pkts_and_status && is_eoq)
+				/* disable channel interrupt */
+				davinci_writel((1 << channel),
+			dev->emac_regs_base + EMAC_TX_INT_MASK_CLEAR_REG);
+		}
+		*pkts_pending = handle_pkts_and_status;	/* status. */
+	}
+
+	/*
+	 * Handle RX packets first - the thought process in this is
+	 * that the received packets will be handled immediately
+	 * reducing the latency (- but an equally opposite argument
+	 * can also be made)
+	 */
+	if (vector & EMAC_MAC_IN_VECTOR_RX_INT_VEC) {
+		vector_channel = (vector & EMAC_MAC_IN_VECTOR_RX_INT_VEC);
+		vector_channel >>= 8;
+		for (channel = 0; channel < 8; channel++) {
+			if (vector_channel & 0x1)
+				break;
+			vector_channel >>= 1;
+		}
+
+		handle_pkts_and_status =
+		    dev->rx_cppi[channel]->ch_info.service_max;
+		if (pkt_args)
+			handle_pkts_and_status =
+			    emac_min_val(((struct rx_tx_params *) pkt_args)->
+				rx_pkts, handle_pkts_and_status);
+
+		pkts_processed =
+		    emac_rx_bdproc(_dev, channel,
+			&handle_pkts_and_status);
+
+		if (pkt_args)
+			((struct rx_tx_params *) pkt_args)->ret_rx_pkts =
+			    pkts_processed;
+
+		*pkts_pending |= handle_pkts_and_status;	/* status */
+	}
+
+	/*
+	 * handle host errors - being handled last does not mean its
+	 * of least priority
+	 */
+	if (vector & EMAC_MAC_IN_VECTOR_HOST_INT)
+		emac_process_host_error(_dev);
+
+	return EMAC_SUCCESS;
+}
+
+/**
+ * EMAC DDC Signal Packet processing end to hardware
+ *- programs the EOI vector register so that if there are pending
+ *  packets in hardware queue *an interrupt can be generated by the
+ *  hardware
+ */
+static int emac_pkt_process_end(struct emac_dev_s *dev, void *proc_args)
+{
+	/* enable interrupts via module control (wrapper) */
+	davinci_writel(1, dev->emac_wrap_regs_base + EMAC_WRAP_EWCTL_REG);
+
+	return EMAC_SUCCESS;
+}
+
+#ifdef EMAC_MULTIFRAGMENT
+#error "EMAC Multi fragment Not supported"
+#else
+
+/*
+ * SINGLE-FRAGMENT SUPPORT HERE
+ */
+
+/**
+ * EMAC DDC Send/Transmit function
+ * - Queues the packet provided by DDA into hardware queue
+ * - If the queue is stalled due to sync issues, re-trigger the hardware
+ *
+ * If "sendArgs" is TRUE (non zero) CRC is calculated by DDA or upper
+ * layer and not by hardware and is part of the packet data send to
+ * this function
+ */
+static int emac_send(struct emac_dev_s *_dev, struct net_pkt_obj *pkt,
+		     int channel, bool send_args)
+{
+	unsigned long flags;
+	struct emac_dev_s *dev = (struct emac_dev_s *) _dev;
+	int ret_val = EMAC_SUCCESS;
+	struct emac_tx_bd *curr_bd;
+	struct emac_tx_cppi_ch *tx_cppi;
+	struct net_buf_obj *buf_list;
+
+	/* verify proper device state */
+	if (dev->drv_state != DRV_OPENED)
+		return EMAC_ERR_DEV_NOT_OPEN;
+
+	/* validate channel number and get channel control structure */
+	if (channel > EMAC_MAX_TX_CHANNELS)
+		return EMAC_ERR_TX_CH_INVALID;
+
+	if (dev->tx_is_open[channel] != TRUE)
+		return EMAC_ERR_TX_CH_NOT_OPEN;
+
+	/* check ethernet link state. if not linked, return error */
+	if (!dev->status.phy_linked)
+		return EMAC_ERR_TX_NO_LINK;
+
+	tx_cppi = dev->tx_cppi[channel];
+	buf_list = pkt->buf_list;	/* get handle to the buffer array */
+
+	/* check packet size and if < EMAC_MIN_ETHERNET_PKT_SIZE, pad it up */
+	if (pkt->pkt_length < EMAC_MIN_ETHERNET_PKT_SIZE) {
+		buf_list->length +=
+		    (EMAC_MIN_ETHERNET_PKT_SIZE - pkt->pkt_length);
+		pkt->pkt_length = EMAC_MIN_ETHERNET_PKT_SIZE;
+	}
+	spin_lock_irqsave(&dev->tx_lock, flags);
+
+	/* only one tx BD for the packet to be sent */
+	curr_bd = tx_cppi->bd_pool_head;
+	if (curr_bd == NULL) {
+#ifdef EMAC_GETSTATS
+		tx_cppi->out_of_tx_bd++;
+#endif
+		ret_val = EMAC_ERR_TX_OUT_OF_BD;
+		goto exit_emac_send;
+	}
+
+	tx_cppi->bd_pool_head = curr_bd->next;
+
+	/* populate the BD contents to be added to the TX list */
+	curr_bd->buf_token = buf_list->buf_token;
+	curr_bd->buff_ptr = EMAC_VIRT_TO_PHYS((int *)buf_list->data_ptr);
+	curr_bd->off_b_len = buf_list->length;
+	curr_bd->h_next = 0;
+	curr_bd->next = 0;
+	curr_bd->mode =
+	    (EMAC_CPPI_SOP_BIT | EMAC_CPPI_OWNERSHIP_BIT | EMAC_CPPI_EOP_BIT
+	     | pkt->pkt_length);
+
+	if ((bool) send_args == TRUE)
+		curr_bd->mode |= EMAC_CPPI_PASS_CRC_BIT;
+
+	/* flush the packet from cache if write back cache is present */
+	BD_CACHE_WRITEBACK_INVALIDATE(curr_bd, EMAC_BD_LENGTH_FOR_CACHE);
+
+	/* send the packet */
+	if (tx_cppi->active_queue_head == 0) {
+		tx_cppi->active_queue_head = curr_bd;
+		tx_cppi->active_queue_tail = curr_bd;
+		if (tx_cppi->queue_active != TRUE) {
+			davinci_writel(EMAC_VIRT_TO_PHYS(curr_bd),
+			dev->emac_regs_base + EMAC_TX_HDP_REG(channel));
+			tx_cppi->queue_active = TRUE;
+		}
+#ifdef EMAC_GETSTATS
+		++tx_cppi->queue_reinit;
+#endif
+	} else {
+		register struct emac_tx_bd *tail_bd;
+		register u32 frame_status;
+
+		tail_bd = tx_cppi->active_queue_tail;
+		tail_bd->next = curr_bd;
+		tx_cppi->active_queue_tail = curr_bd;
+		tail_bd = EMAC_VIRT_NOCACHE(tail_bd);
+		tail_bd->h_next = (int)EMAC_VIRT_TO_PHYS(curr_bd);
+		frame_status = tail_bd->mode;
+		if (frame_status & EMAC_CPPI_EOQ_BIT) {
+			davinci_writel(EMAC_VIRT_TO_PHYS(curr_bd),
+			dev->emac_regs_base + EMAC_TX_HDP_REG(channel));
+			frame_status &= ~(EMAC_CPPI_EOQ_BIT);
+			tail_bd->mode = frame_status;
+#ifdef EMAC_GETSTATS
+			++tx_cppi->end_of_queue_add;
+#endif
+		} else {
+			if (dev->tx_interrupt_disable == TRUE) {
+				/* enable channel interrupt */
+				davinci_writel((1 << channel),
+				dev->emac_regs_base + EMAC_TX_INT_MASK_SET_REG);
+			}
+		}
+	}
+#ifdef EMAC_GETSTATS
+	tx_cppi->active_queue_count++;
+#endif
+
+exit_emac_send:
+	spin_unlock_irqrestore(&dev->tx_lock, flags);
+
+	if (dev->tx_interrupt_disable == TRUE) {
+		if (--dev->tx_int_threshold[channel] <= 0) {
+			bool is_eoq;
+			u32 handle_pkts_and_status;
+
+			handle_pkts_and_status =
+			    dev->tx_cppi[channel]->ch_info.service_max;
+			emac_tx_bdproc(_dev, channel, &handle_pkts_and_status,
+				       &is_eoq);
+			dev->tx_int_threshold[channel] =
+			    dev->tx_cppi[channel]->ch_info.service_max;
+		}
+	}
+
+	return ret_val;
+}
+
+/**
+ * EMAC DDC TX Buffer Descriptor processing
+ * - processes transmit completed packets and returns the handles to DDA layer
+ * - If the queue is stalled due to sync issues, re-trigger the hardware
+ *
+ * returns number of pkts processed and 1 in morePkts if pkt
+ * completion processing pending
+ */
+static int emac_tx_bdproc(struct emac_dev_s *_dev, u32 channel,
+			  u32 *handle_pkts_and_status, bool *is_eoq)
+{
+	unsigned long flags;
+	struct emac_dev_s *dev = (struct emac_dev_s *) _dev;
+	struct emac_tx_bd *curr_bd;
+	struct emac_tx_cppi_ch *tx_cppi;
+	u32 frame_status;
+	u32 pkts_processed = 0;
+	u32 pkts_to_process = *handle_pkts_and_status;
+#ifdef EMAC_MULTIPACKET_TX_COMPLETE_NOTIFY
+	u32 tx_complete_cnt = 0;
+	u32 *tx_complete_ptr;
+#endif
+
+	*handle_pkts_and_status = 0;	/* status. */
+	*is_eoq = TRUE;
+
+	/* Here no need to validate channel number, since it is taken
+	   from the interrupt register instead channel structure
+	   should be validated */
+	if (dev->tx_is_open[channel] == FALSE)
+		return EMAC_ERR_TX_CH_NOT_OPEN;
+
+	if (dev->tx_teardown_pending[channel] == TRUE)
+		return EMAC_SUCCESS;	/* dont handle any pkt completions */
+
+	tx_cppi = dev->tx_cppi[channel];
+#ifdef EMAC_MULTIPACKET_TX_COMPLETE_NOTIFY
+	tx_complete_ptr = &tx_cppi->tx_complete[0];
+#endif
+#ifdef EMAC_GETSTATS
+	++tx_cppi->proc_count;
+#endif
+	spin_lock_irqsave(&dev->tx_lock, flags);
+
+	/* get first BD to process */
+	curr_bd = tx_cppi->active_queue_head;
+	if (curr_bd == 0) {
+		davinci_writel(EMAC_VIRT_TO_PHYS(tx_cppi->last_hw_bdprocessed),
+		dev->emac_regs_base + EMAC_TX_CP_REG(channel));
+
+#ifdef EMAC_GETSTATS
+		tx_cppi->no_active_pkts++;
+#endif
+
+		spin_unlock_irqrestore(&dev->tx_lock, flags);
+
+		return EMAC_SUCCESS;
+	}
+
+	/* invalidate BD */
+	BD_CACHE_INVALIDATE(curr_bd, EMAC_BD_LENGTH_FOR_CACHE);
+
+	frame_status = curr_bd->mode;
+	while ((curr_bd) &&
+	       ((frame_status & EMAC_CPPI_OWNERSHIP_BIT) == 0) &&
+	       (pkts_processed < pkts_to_process)) {
+
+		davinci_writel(EMAC_VIRT_TO_PHYS(curr_bd),
+		dev->emac_regs_base + EMAC_TX_CP_REG(channel));
+		tx_cppi->active_queue_head = curr_bd->next;
+		if (frame_status & EMAC_CPPI_EOQ_BIT) {
+			if (curr_bd->next) {
+				/* misqueued packet */
+				davinci_writel(curr_bd->h_next,
+				dev->emac_regs_base + EMAC_TX_HDP_REG(channel));
+#ifdef EMAC_GETSTATS
+				++tx_cppi->mis_queued_packets;
+#endif
+			} else
+				/* end of queue */
+				tx_cppi->queue_active = FALSE;
+		}
+#ifdef EMAC_MULTIPACKET_TX_COMPLETE_NOTIFY
+		*tx_complete_ptr = (u32) curr_bd->buf_token;
+		++tx_complete_ptr;
+		++tx_complete_cnt;
+#else
+		/* single packet TX complete notify - this function is
+		 *called in the send critical section context */
+		emac_net_tx_complete(dev,
+				     &curr_bd->buf_token, 1, (void *)channel);
+#endif
+		curr_bd->next = tx_cppi->bd_pool_head;
+		tx_cppi->bd_pool_head = curr_bd;
+#ifdef EMAC_GETSTATS
+		--tx_cppi->active_queue_count;
+#endif
+		pkts_processed++;
+		tx_cppi->last_hw_bdprocessed = curr_bd;
+		curr_bd = tx_cppi->active_queue_head;
+		if (curr_bd) {
+			BD_CACHE_INVALIDATE(curr_bd, EMAC_BD_LENGTH_FOR_CACHE);
+			frame_status = curr_bd->mode;
+		}
+	}			/* end of while loop */
+
+	if ((curr_bd) && ((frame_status & EMAC_CPPI_OWNERSHIP_BIT) == 0))
+		*handle_pkts_and_status = 1;
+
+	/*
+	 * This check is same as check for EOQ i.e framestatus and
+	 * EMAC_CPPI_EOQ_BIT
+	 */
+	if (curr_bd)
+		*is_eoq = FALSE;
+
+#ifdef EMAC_MULTIPACKET_TX_COMPLETE_NOTIFY
+	/*
+	 * multiple packet TX complete notify - this function is NOT
+	 * called in the send critical section context
+	 */
+	emac_net_tx_complete(dev, (void **) &tx_cppi->tx_complete[0],
+				tx_complete_cnt, channel);
+#endif
+	spin_unlock_irqrestore(&dev->tx_lock, flags);
+
+	return pkts_processed;
+}
+
+/**
+ * EMAC DDC Add Buffer to RX queue function
+ * - returns the BD to the Receive queue
+ * - If the queue is stalled due to sync issues, re-trigger the hardware
+ */
+static void emac_add_bdto_rx_queue(struct emac_dev_s *dev,
+				struct emac_rx_cppi_ch_t *rx_cppi,
+				struct emac_rx_bd *curr_bd, char *buffer,
+				void *buf_token)
+{
+	/* populate the hardware descriptor */
+	curr_bd->h_next = 0;
+	curr_bd->buff_ptr = EMAC_VIRT_TO_PHYS(buffer);
+	curr_bd->off_b_len = rx_cppi->ch_info.buf_size;
+	curr_bd->mode = EMAC_CPPI_OWNERSHIP_BIT;
+	curr_bd->next = 0;
+	curr_bd->data_ptr = buffer;
+	curr_bd->buf_token = buf_token;
+
+	/* write back  */
+	/* BD_CACHE_WRITEBACK_INVALIDATE(curr_bd, EMAC_BD_LENGTH_FOR_CACHE); */
+	if (rx_cppi->active_queue_head == 0) {
+		rx_cppi->active_queue_head = curr_bd;
+		rx_cppi->active_queue_tail = curr_bd;
+		if (rx_cppi->queue_active != FALSE) {
+			davinci_writel(
+				EMAC_VIRT_TO_PHYS(rx_cppi->active_queue_head),
+				dev->emac_regs_base
+				+ EMAC_RX_HDP_REG(rx_cppi->ch_info.ch_num));
+			rx_cppi->queue_active = TRUE;
+		}
+	} else {
+		struct emac_rx_bd *tail_bd;
+		u32 frame_status;
+
+		tail_bd = rx_cppi->active_queue_tail;
+		rx_cppi->active_queue_tail = curr_bd;
+		tail_bd->next = (void *)curr_bd;
+		tail_bd = EMAC_VIRT_NOCACHE(tail_bd);
+		tail_bd->h_next = EMAC_VIRT_TO_PHYS(curr_bd);
+		frame_status = tail_bd->mode;
+		if (frame_status & EMAC_CPPI_EOQ_BIT) {
+			davinci_writel(EMAC_VIRT_TO_PHYS(curr_bd),
+				dev->emac_regs_base
+			+ EMAC_RX_HDP_REG(rx_cppi->ch_info.ch_num));
+			frame_status &= ~(EMAC_CPPI_EOQ_BIT);
+			tail_bd->mode = frame_status;
+#ifdef EMAC_GETSTATS
+			++rx_cppi->end_of_queue_add;
+#endif
+		}
+
+	}
+
+#ifdef EMAC_GETSTATS
+	++rx_cppi->recycled_bd;	/* maintain statistics of how many BD's were
+	 queued back - recycled */
+#endif
+}
+
+/**
+ * EMAC DDC RX Buffer Descriptor processing
+ * - processes received packets and passes them to DDA layer
+ * - requeues the buffer descriptor to the receive pool
+ * - If the queue is stalled due to sync issues, re-trigger the hardware
+ */
+static int emac_rx_bdproc(struct emac_dev_s *_dev, u32 channel,
+			  int *handle_pkts_and_status)
+{
+	unsigned long flags;
+	struct emac_dev_s *dev = (struct emac_dev_s *) _dev;
+	struct emac_rx_cppi_ch_t *rx_cppi;
+	struct emac_rx_bd *curr_bd, *last_bd;
+	u32 frame_status;
+	char *new_buffer;
+	void *new_buf_token;
+	struct net_buf_obj *rx_buf_obj;
+	u32 pkts_processed;
+	struct net_pkt_obj *curr_pkt, pkt_obj;
+	struct net_buf_obj buf_obj;
+	u32 pkts_to_be_processed = *handle_pkts_and_status;
+
+	/* Here no need to validate channel number, since it is taken
+	   from the interrupt register instead channel structure
+	   should be validated */
+	if (dev->rx_is_open[channel] == FALSE) {
+		*handle_pkts_and_status = 0;
+		return EMAC_ERR_RX_CH_NOT_OPEN;
+	}
+
+	/* check if channel teardown pending */
+	rx_cppi = dev->rx_cppi[channel];
+	if (dev->rx_teardown_pending[channel] == TRUE) {
+		*handle_pkts_and_status = 0;
+		return 0;
+	}
+#ifdef EMAC_GETSTATS
+	++rx_cppi->proc_count;
+#endif
+	*handle_pkts_and_status = 0;
+	pkts_processed = 0;
+
+	spin_lock_irqsave(&dev->rx_lock, flags);
+
+	pkt_obj.buf_list = &buf_obj;
+	curr_pkt = &pkt_obj;
+	curr_bd = rx_cppi->active_queue_head;
+	BD_CACHE_INVALIDATE(curr_bd, EMAC_BD_LENGTH_FOR_CACHE);
+	frame_status = curr_bd->mode;
+
+	while ((curr_bd) &&
+	       ((frame_status & EMAC_CPPI_OWNERSHIP_BIT) == 0) &&
+	       (pkts_processed < pkts_to_be_processed)) {
+
+		/* allocate new buffer */
+		new_buffer =
+		    (void *)(emac_net_alloc_rx_buf(dev,
+						   rx_cppi->ch_info.buf_size,
+						   &new_buf_token, 0, NULL));
+		if (new_buffer == NULL) {
+			/* no buffer available. return error with packets
+			pending */
+#ifdef EMAC_GETSTATS
+			++rx_cppi->out_of_rx_buffers;
+#endif
+			goto end_emac_rx_bdproc;
+		}
+
+		/* populate received packet data structure */
+		rx_buf_obj = &curr_pkt->buf_list[0];
+		rx_buf_obj->data_ptr = (char *)curr_bd->data_ptr;
+		rx_buf_obj->length =
+			curr_bd->off_b_len & EMAC_RX_BD_BUF_SIZE;
+		rx_buf_obj->buf_token = curr_bd->buf_token;
+		curr_pkt->pkt_token = curr_pkt->buf_list->buf_token;
+		curr_pkt->num_bufs = 1;
+		curr_pkt->pkt_length =
+		    (frame_status & EMAC_RX_BD_PKT_LENGTH_MASK);
+		/* acknowledge RX interrupt for the channel */
+		davinci_writel(EMAC_VIRT_TO_PHYS(curr_bd),
+		dev->emac_regs_base + EMAC_RX_CP_REG(channel));
+
+#ifdef EMAC_GETSTATS
+		++rx_cppi->processed_bd;
+#endif
+		last_bd = curr_bd;
+		curr_bd = last_bd->next;
+		rx_cppi->active_queue_head = curr_bd;
+
+		/* check if end of RX queue ? */
+		if (frame_status & EMAC_CPPI_EOQ_BIT) {
+			if (curr_bd) {
+				/* misqueued packet */
+#ifdef EMAC_GETSTATS
+				++rx_cppi->mis_queued_packets;
+#endif
+				davinci_writel(EMAC_VIRT_TO_PHYS(curr_bd),
+						dev->emac_regs_base
+						+ EMAC_RX_HDP_REG(channel));
+
+			} else {
+				/* end of queue */
+#ifdef EMAC_GETSTATS
+				++rx_cppi->end_of_queue;
+#endif
+				rx_cppi->queue_active = FALSE;	/* clear
+							software RX queue */
+			}
+		}
+
+		/* recycle BD */
+		emac_add_bdto_rx_queue(_dev, rx_cppi, last_bd, new_buffer,
+				       new_buf_token);
+
+		/* return the packet to the user - BD ptr passed in
+		 *last parameter for potential *future* use */
+		spin_unlock_irqrestore(&dev->rx_lock, flags);
+		emac_net_rx_cb(dev, curr_pkt, (void *)channel);
+		spin_lock_irqsave(&dev->rx_lock, flags);
+
+		curr_bd = rx_cppi->active_queue_head;
+		if (curr_bd) {
+			BD_CACHE_INVALIDATE(curr_bd, EMAC_BD_LENGTH_FOR_CACHE);
+			frame_status = curr_bd->mode;
+		}
+		++pkts_processed;
+	}
+
+	if ((curr_bd) && ((frame_status & EMAC_CPPI_OWNERSHIP_BIT) == 0))
+		*handle_pkts_and_status = 1;
+
+end_emac_rx_bdproc:
+	spin_unlock_irqrestore(&dev->rx_lock, flags);
+	return pkts_processed;
+}
+
+#endif				/* !EMAC_MULTIFRAGMENT */
+
+/**
+ * Linux 2.6 Kernel Ethernet Poll function Call only RX processing in
+ * the poll function - TX is taken care of in interrupt context
+ */
+static int emac_poll(struct napi_struct *napi, int budget)
+{
+	struct emac_dev_s *dev = container_of(napi, struct emac_dev_s, napi);
+	struct net_device *netdev = dev->owner;
+
+	unsigned int pkts_pending = 0;
+	/* this is used to pass the rx packets to be processed and
+	 *return the number of rx packets processed */
+	struct rx_tx_params *napi_params = &dev->napi_rx_tx;
+
+	if (!dev->set_to_close) {
+		napi_params->rx_pkts = budget;
+		napi_params->tx_pkts = EMAC_DEFAULT_TX_MAX_SERVICE;
+
+		/* process packets - call the DDC packet processing function */
+		emac_pkt_process(dev, &pkts_pending, napi_params);
+
+		/* if more packets reschedule the tasklet or call
+		 *pkt_process_end */
+		if (!pkts_pending) {
+			if (test_bit(NAPI_STATE_SCHED, &napi->state))
+				netif_rx_complete(netdev, napi);
+			emac_pkt_process_end(dev, NULL);
+		}
+	}
+
+	/* we are closing down, so dont process anything */
+	return napi_params->ret_rx_pkts;
+}
+
+#ifdef CONFIG_NET_POLL_CONTROLLER
+
+/**
+ * Polling receive - used by netconsole and other diagnostic tools
+ * to allow network i/o with interrupts disabled.
+ */
+void emac_poll_controller(struct net_device *netdev)
+{
+	struct emac_dev_s *dev = NETDEV_PRIV(netdev);
+
+	disable_irq(netdev->irq);
+	emac_hal_isr(netdev->irq, dev);
+	enable_irq(netdev->irq);
+}
+#endif
+
+/* allocate RX buffer */
+void *emac_net_alloc_rx_buf(struct emac_dev_s *dev, int buf_size,
+			    void **data_token,
+			    u32 channel, void *alloc_args)
+{
+	struct net_device *netdev = dev->owner;
+	struct sk_buff *p_skb;
+
+	p_skb = dev_alloc_skb(dev->rx_buf_size);
+	if (p_skb == NULL) {
+#ifdef EMAC_DEBUG
+		ERR("emac_net_alloc_rx_buf:Failed to allocate skb for %s.\n",
+		    netdev->name);
+#endif
+		return NULL;
+	}
+
+	/* set device pointer in skb and reserve space for extra bytes */
+	p_skb->dev = netdev;
+	skb_reserve(p_skb, dev->rx_buf_offset);
+
+	/* set the data token */
+	*data_token = (void *) p_skb;
+#ifdef EMAC_CACHE_INVALIDATE_FIX
+	/* invalidate buffer */
+	EMAC_CACHE_INVALIDATE((unsigned long)p_skb->data, buf_size);
+#endif
+
+	return p_skb->data;
+}
+
+/* free RX buffer */
+static int emac_net_free_rx_buf(struct emac_dev_s *dev, void *buffer,
+				void *data_token,
+				u32 channel, void *free_args)
+{
+	dev_kfree_skb_any((struct sk_buff *)data_token);
+	return EMAC_SUCCESS;
+}
+
+
+/**
+ * Packet receive notification
+ *
+ * This function gets received packet via the netPktList and
+ * it queues the packet into the higher layer queue
+ *
+ * Note that rxArgs contains "channel" and is ignored for this
+ * implementation
+ */
+static int emac_net_rx_cb(struct emac_dev_s *dev,
+			struct net_pkt_obj *net_pkt_list,
+			void *rx_args)
+{
+	struct sk_buff *p_skb;
+
+	p_skb = (struct sk_buff *)net_pkt_list->pkt_token;
+
+	/* set length of packet */
+	skb_put(p_skb, net_pkt_list->pkt_length);
+#ifndef EMAC_CACHE_INVALIDATE_FIX
+	/* invalidate cache */
+	EMAC_CACHE_INVALIDATE((unsigned long)p_skb->data, p_skb->len);
+#endif
+	p_skb->protocol = eth_type_trans(p_skb, dev->owner);
+	p_skb->dev->last_rx = jiffies;
+	netif_receive_skb(p_skb);
+	dev->net_dev_stats.rx_bytes += net_pkt_list->pkt_length;
+	dev->net_dev_stats.rx_packets++;
+
+	return 0;
+}
+
+
+/* transmit complete callback */
+static int emac_net_tx_complete(struct emac_dev_s *dev,
+				void **net_data_tokens,
+				int num_tokens, u32 channel)
+{
+	u32 cnt;
+
+	if (num_tokens && netif_queue_stopped(dev->owner))
+		netif_start_queue(dev->owner);
+
+	for (cnt = 0; cnt < num_tokens; cnt++) {
+		struct sk_buff *skb = (struct sk_buff *)net_data_tokens[cnt];
+		if (skb != NULL) {
+		    dev->net_dev_stats.tx_packets++;
+		    dev->net_dev_stats.tx_bytes += skb->len;
+		    dev_kfree_skb_any(skb);
+		}
+	}
+
+	return 0;
+}
+
+/*
+ * Interrupt functions
+ */
+
+irqreturn_t emac_hal_isr(int irq, void *dev_id)
+{
+	struct emac_dev_s *dev = (struct emac_dev_s *) dev_id;
+
+	++dev->isr_count;
+	if (!dev->set_to_close) /* NAPI support */
+		netif_rx_schedule(dev->owner, &dev->napi);
+
+	return IRQ_HANDLED;
+}
+
+/**
+ * transmit function - only single fragment supported
+ */
+static int emac_dev_tx(struct sk_buff *skb, struct net_device *netdev)
+{
+	int ret_code;
+	/* buffer object - only single frame support */
+	struct net_buf_obj tx_buf;
+	struct net_pkt_obj tx_packet;	/* packet object */
+	struct emac_dev_s *dev = NETDEV_PRIV(netdev);
+	/* ANANT HACK: unsigned long flags; */
+
+	/* Build the buffer and packet objects - Since only single fragment is
+	 *supported, need not set length and token in both packet & object.
+	 *Doing so for completeness sake & to show that this needs to be done
+	 *in multifragment case
+	 */
+	tx_packet.buf_list = &tx_buf;
+	tx_packet.num_bufs = 1;	/* only single fragment supported */
+	tx_packet.pkt_length = skb->len;
+	tx_packet.pkt_token = (void *) skb;
+	tx_buf.length = skb->len;
+	tx_buf.buf_token = (void *) skb;
+	tx_buf.data_ptr = skb->data;
+
+	/* flush data buffer if write back mode */
+	EMAC_CACHE_WRITEBACK((unsigned long)skb->data, skb->len);
+	netdev->trans_start = jiffies;
+
+	/* ANANT_HACK: Need to lock TX so that there is no contention
+	   spin_lock_irqsave(&hDDA->lock, flags);
+	 */
+
+	/* DDC send : last param FALSE so that hardware calculates CRC */
+	ret_code = emac_send(dev, &tx_packet, EMAC_DEFAULT_TX_CHANNEL, FALSE);
+
+	/* ANANT_HACK: Need to un-lock TX so that there is no contention
+	   between two processes
+	   spin_unlock_irqrestore(&hDDA->lock, flags);
+	 */
+
+	if (ret_code == EMAC_SUCCESS)
+	    return 0;
+	if (ret_code == EMAC_ERR_TX_OUT_OF_BD) {
+		ERR("WARN: emac_dev_tx: Out of TX BD's\n");
+		netif_stop_queue(dev->owner);
+	}
+	dev->net_dev_stats.tx_dropped++;
+	return -1;
+}
+
+/*
+ * Linux Driver Model
+ */
+
+
+static ssize_t emac_show_version(struct device_driver *drv, char *buf)
+{
+	return emac_p_get_version(buf, NULL, 0, 4096, NULL, NULL);
+}
+
+static DRIVER_ATTR(version, S_IRUGO, emac_show_version, NULL);
+
+
+
+/**
+ * probe number of EMAC instances and register net_device structure
+ */
+static int __devinit emac_dev_probe(struct device *ddev)
+{
+	struct platform_device *pdev = to_platform_device(ddev);
+	int ret_val = 0;
+	int unit;
+	/*int instance_count = EMAC_MAX_INSTANCES;*/
+
+	/* obtain clock rate from kernel clock API's */
+	struct resource *dev_res =
+		platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	struct resource *wrap_res =
+		platform_get_resource(pdev, IORESOURCE_MEM, 1);
+	int irq_res = platform_get_irq(pdev, 0);
+
+	if (!dev_res) {
+	    printk(KERN_NOTICE "TI DAVINCI EMAC: fail to get resource\n");
+	    return -EINVAL;
+	}
+
+	if (!wrap_res) {
+	    printk(KERN_NOTICE "TI DAVINCI EMAC: fail to get resource"
+			" for wrap regs\n");
+	    return -EINVAL;
+	}
+
+	if (!irq_res) {
+	    printk(KERN_NOTICE "TI DAVINCI EMAC: fail to get resource"
+			" for irq\n");
+	    return -EINVAL;
+	}
+
+	emac_clk = clk_get(0, "EMACCLK");
+	if (IS_ERR(emac_clk)) {
+		printk("TI DAVINCI EMAC: Failed to get clock. Exiting\n");
+		return -EINVAL;
+	}
+
+	clk_enable(emac_clk);
+	emac_bus_frequency = clk_get_rate(emac_clk);
+
+	for (unit = 0; unit < EMAC_MAX_INSTANCES; unit++) {
+		struct emac_dev_s *dev;
+		int failed;
+		struct net_device *netdev =
+			alloc_etherdev(sizeof(struct emac_dev_s));
+		if (!netdev) {
+			printk(KERN_NOTICE
+	"TI DaVinci EMAC: Etherdev alloc failed for device inst %d.\n", unit);
+
+			ret_val = -ENOMEM;
+			/* if error, free EMAC clock */
+			clk_disable(emac_clk);
+			break;
+		}
+		dev = NETDEV_PRIV(netdev);
+		dev->owner = netdev;
+		dev->instance_num = unit;
+		dev->emac_regs_base = dev_res->start;
+		dev->emac_wrap_regs_base = wrap_res->start;
+		dev->irq_line = irq_res;
+		netdev->init = emac_dev_init;
+		SET_NETDEV_DEV(netdev, &pdev->dev);
+		emac_net_dev[dev->instance_num] = netdev;
+#if defined CONFIG_EMAC_INIT_BUF_MALLOC
+		g_init_enable_flag = 1;
+#endif
+		emac_p_detect_manual_cfg(cfg_link_speed, cfg_link_mode,
+					 debug_mode);
+		if (emac_cfg_probe()) {
+			printk("TI DAVINCI EMAC: Error in configuration.\n");
+			return (-1);
+		}
+		netif_napi_add(netdev, &dev->napi, emac_poll,
+			EMAC_DEFAULT_RX_MAX_SERVICE);
+
+		/* register the network device with linux */
+		failed = register_netdev(netdev);
+
+		if (failed) {
+			ERR("Could not register device: %d\n", failed);
+
+			ret_val = -1;
+
+			clk_disable(emac_clk);
+
+			FREE_NETDEV(netdev);
+			break;
+		} else {
+			dev->next_device = last_emac_device;
+			last_emac_device = netdev;
+			DBG("%s irq=%2d io=%04x\n",
+			    netdev->name, (int)netdev->irq,
+			    (int)netdev->base_addr);
+#ifdef EMAC_DEBUG
+			create_proc_read_entry("net/emac_rfc2665_stats", 0,
+					       NULL, emac_p_read_rfc2665_stats,
+					       netdev);
+#endif
+		}
+	}
+
+	if (ret_val == 0) {
+		/* to maintain backward compatibility with NSP. */
+#ifdef EMAC_DEBUG
+		gp_stats_file = create_proc_entry("net/emac_stats", 0644, NULL);
+		if (gp_stats_file) {
+			gp_stats_file->read_proc = emac_p_read_stats;
+			gp_stats_file->write_proc = emac_p_write_stats;
+		}
+
+		create_proc_read_entry("net/emac_ver", 0, NULL,
+				       emac_p_get_version, NULL);
+
+		create_proc_read_entry("net/emac_config", 0, NULL,
+				       emac_dump_config, NULL);
+		create_proc_read_entry("net/emac_link", 0, NULL,
+				       emac_p_read_link, NULL);
+#endif
+	}
+	emac_devices_installed = unit;
+
+	printk(KERN_INFO"%s\n", emac_version_string);
+	printk(KERN_INFO"TI DaVinci EMAC: Installed %d instances.\n", unit);
+#if defined CONFIG_EMAC_INIT_BUF_MALLOC
+	printk
+	("TI DAVINCI EMAC driver is allocating buffer memory at init time.\n");
+#endif
+
+	return ((unit >= 0) ? 0 : -ENODEV);
+}
+
+/* structure describing the EMAC driver */
+static struct device_driver emac_driver = {
+	.name = "ti_davinci_emac",
+	.bus = &platform_bus_type,
+	.probe = emac_dev_probe,
+	.remove = NULL,		/* TODO: findout when probe would be called. */
+	.suspend = NULL,
+	.resume = NULL,
+};
+
+
+/*
+ * Linux Module Init/Exit
+ */
+
+static int __init emac_driver_init(void)
+{
+    register int rs = driver_register(&emac_driver);
+    if (rs)
+	    return rs;
+
+    if (driver_create_file(&emac_driver, &driver_attr_version))
+	    printk(KERN_NOTICE "TI DaVinci EMAC: fail to create sysfs node\n");
+    return 0;
+}
+
+static void emac_exit(void)
+{
+	struct net_device *netdev;
+	struct emac_dev_s *dev;
+	int ret_code;
+
+	while (emac_devices_installed) {
+		char proc_name[100];
+		int proc_category_name_len = 0;
+
+		netdev = last_emac_device;
+		dev = NETDEV_PRIV(netdev);
+
+		DBG("Unloading %s irq=%2d io=%04x\n",
+		    netdev->name, (int)netdev->irq, (int)netdev->base_addr);
+
+		/* free EMAC clock */
+		clk_disable(emac_clk);
+
+		if (g_init_enable_flag)
+			emac_p_dev_disable(dev);
+
+		/* deinit DDC */
+		ret_code = emac_de_init(dev, NULL);
+
+		if (ret_code != EMAC_SUCCESS)
+			ERR("Error %08X from Deinit()\n", ret_code);
+			/*
+			 * we dont want to quit from here, lets delete
+			 * the instance also
+			 */
+
+		/* delete the proc entry */
+		strcpy(proc_name, "davinci/");
+		strcat(proc_name, netdev->name);
+		proc_category_name_len = strlen(proc_name);
+		strcpy(proc_name + proc_category_name_len, "_rfc2665_stats");
+		remove_proc_entry(proc_name, NULL);
+
+		/* release memory region and unregister the device */
+		release_mem_region(netdev->base_addr, EMAC_DEFAULT_EMAC_SIZE);
+		unregister_netdev(netdev);
+
+		last_emac_device = dev->next_device;
+		if (netdev)
+			FREE_NETDEV(netdev);
+
+		emac_devices_installed--;
+	}
+
+#ifdef EMAC_DEBUG
+	if (gp_stats_file)
+		remove_proc_entry("net/emac_stats", NULL);
+
+	remove_proc_entry("net/emac_link", NULL);
+	remove_proc_entry("net/emac_ver", NULL);
+	remove_proc_entry("net/emac_config", NULL);
+#endif
+
+}
+
+module_init(emac_driver_init);
+module_exit(emac_exit);
Index: 2.6.24-rc8.ether/drivers/net/arm/davinci_emac.h
===================================================================
--- /dev/null
+++ 2.6.24-rc8.ether/drivers/net/arm/davinci_emac.h
@@ -0,0 +1,1560 @@
+/**
+ * Copyright (C) 2008 MontaVista Software, Inc. <source@...sta.com>
+ *
+ * This file is licensed under the terms of the
+ * GNU General Public License version 2. This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ *
+ */
+
+#include "davinci_emac_phy.h"
+#include <asm/arch/hardware.h>
+
+/* version info */
+#define EMAC_MAJOR_VERSION		4
+#define EMAC_MINOR_VERSION		0
+#define EMAC_MODULE_VERSION		"4.0"
+
+/* Debug options */
+#define EMAC_DEBUG
+
+#define EMAC_CACHE_WRITEBACK_MODE
+#define EMAC_CACHE_INVALIDATE_FIX
+
+#define TRUE		((bool) 1)
+#define FALSE		((bool) 0)
+
+#define EMAC_MULTIPACKET_TX_COMPLETE_NOTIFY
+
+/* NO PHY used in case of external ethernet switches */
+#define CONFIG_EMAC_NOPHY		9999
+
+/* DaVinci specific configuration */
+#define EMAC_BASE_ADDR		IO_ADDRESS(DAVINCI_EMAC_CNTRL_REGS_BASE)
+#define EMAC_WRAPPER_REGS_ADDR	IO_ADDRESS(DAVINCI_EMAC_WRAPPER_CNTRL_REGS_BASE)
+#define EMAC_WRAPPER_RAM_ADDR	IO_ADDRESS(DAVINCI_EMAC_WRAPPER_RAM_BASE)
+#define EMAC_WRAPPER_RAM_SIZE	(8 << 10)
+#define EMAC_MDIO_BASE_ADDR	IO_ADDRESS(DAVINCI_MDIO_CNTRL_REGS_BASE)
+
+#define EMAC_INTERRUPT		13
+#define EMAC_BUS_FREQUENCY	76500000	/* PLL/6 i.e 76.5 MHz */
+#define EMAC_MDIO_FREQUENCY	2200000	/* PHY bus frequency */
+#define EMAC_PHY_MASK		0x2	/* PHY chip is located at address 1 */
+
+/*
+ * Note: For DaVinci, Buffer Descriptors are located in Wrapper RAM
+ * (4K).  Half of the Wrapper memory is for RX BD's and other half for
+ * TX BD's
+ */
+#define EMAC_TX_BD_MEM	EMAC_WRAPPER_RAM_ADDR
+#define EMAC_RX_BD_MEM	\
+	(EMAC_WRAPPER_RAM_ADDR + (EMAC_WRAPPER_RAM_SIZE >> 1))
+
+/*
+ * If multi packet Tx complete notifications is enabled (via
+ * EMAC_MULTIPACKET_TX_COMPLETE_NOTIFY), Max number of Tx packets that
+ * can be notified - the actual number will depend upon user
+ * configuration for parameter "maxPktsToProcess"
+ */
+/* feature macros here */
+#define EMAC_MAX_TX_COMPLETE_PKTS_TO_NOTIFY		8
+
+/* config macros */
+#define EMAC_MAX_INSTANCES			1
+#define EMAC_MIN_ETHERNET_PKT_SIZE		60
+
+/**
+ * max RX fragments calculation - 1500 byte packet and 64 byte
+ * buffer. fragments=1500/64=24
+ */
+#define EMAC_MAX_RX_FRAGMENTS			24
+
+/* theoratically TX max fragments are equal to 24 */
+#define EMAC_MAX_TX_FRAGMENTS			8
+
+/* EMAC hardware specific */
+#define EMAC_RESET_CLOCKS_WAIT			64
+#define EMAC_MAX_TX_CHANNELS			8
+#define EMAC_MAX_RX_CHANNELS			8
+#define EMAC_MIN_FREQUENCY_FOR_10MBPS		5500000
+#define EMAC_MIN_FREQUENCY_FOR_100MBPS		55000000
+#define EMAC_MIN_FREQUENCY_FOR_1000MBPS		125000000
+
+/*
+ * The following are EMAC registers which have been removed from the
+ * CPGMAC register map. Thus we access them using macros to avoid
+ * having more CSL register overlay structures for older EMAC register
+ * map.
+ */
+
+/* statistics clear value */
+#define EMAC_NUM_STAT_REGS			36
+#define EMAC_STAT_CLEAR				0xFFFFFFFF
+
+/* EMAC all multicast set register value */
+#define EMAC_ALL_MULTI_REG_VALUE		0xFFFFFFFF
+
+/* EMAC number of multicast bits that can be set/cleared - currently
+   64 bits - hash1/2 regs */
+#define EMAC_NUM_MULTICAST_BITS			64
+
+/* EMAC teardown value */
+#define EMAC_TEARDOWN_VALUE			0xFFFFFFFC
+
+/* TX / RX control bits */
+#define EMAC_TX_CONTROL_TX_ENABLE_VAL		0x1
+#define EMAC_RX_CONTROL_RX_ENABLE_VAL 		0x1
+
+/* host interrupt bits */
+#define EMAC_MAC_HOST_ERR_INTMASK_VAL		0x2
+#define EMAC_MAC_STAT_INT_INTMASK_VAL		0x1
+
+/* rx config masks */
+#define EMAC_RX_UNICAST_CLEAR_ALL		0xFF
+
+/* type 0 address filtering macros */
+#define EMAC_TYPE_0_MACSRCADDR0_MASK		0xFF
+#define EMAC_TYPE_0_MACSRCADDR0_SHIFT		0
+#define EMAC_TYPE_0_MACSRCADDR1_MASK		0xFF
+#define EMAC_TYPE_0_MACSRCADDR1_SHIFT		0
+
+#define EMAC_TYPE_0_MACSRCADDR2_MASK		(0xFF<<24)
+#define EMAC_TYPE_0_MACSRCADDR2_SHIFT		24
+#define EMAC_TYPE_0_MACSRCADDR3_MASK		(0xFF<<16)
+#define EMAC_TYPE_0_MACSRCADDR3_SHIFT		16
+#define EMAC_TYPE_0_MACSRCADDR4_MASK		(0xFF<<8)
+#define EMAC_TYPE_0_MACSRCADDR4_SHIFT		8
+#define EMAC_TYPE_0_MACSRCADDR5_MASK		0xFF
+#define EMAC_TYPE_0_MACSRCADDR5_SHIFT		0
+
+/* type 1 address filtering macros */
+#define EMAC_TYPE_1_MACSRCADDR0_MASK		(0xFF<<8)
+#define EMAC_TYPE_1_MACSRCADDR0_SHIFT		8
+#define EMAC_TYPE_1_MACSRCADDR1_MASK		0xFF
+#define EMAC_TYPE_1_MACSRCADDR1_SHIFT		0
+
+#define EMAC_TYPE_1_MACSRCADDR2_MASK		(0xFF<<24)
+#define EMAC_TYPE_1_MACSRCADDR2_SHIFT		24
+#define EMAC_TYPE_1_MACSRCADDR3_MASK		(0xFF<<16)
+#define EMAC_TYPE_1_MACSRCADDR3_SHIFT		16
+#define EMAC_TYPE_1_MACSRCADDR4_MASK		(0xFF<<8)
+#define EMAC_TYPE_1_MACSRCADDR4_SHIFT		8
+#define EMAC_TYPE_1_MACSRCADDR5_MASK		0xFF
+#define EMAC_TYPE_1_MACSRCADDR5_SHIFT		0
+
+/* CP(G)MAC address filtering bit macros */
+#define CPGMAC_VALID_MASK			(0x1<<20)
+#define CPGMAC_VALID_SHIFT			20
+#define CPGMAC_MATCH_FILTER_MASK		(0x1<<19)
+#define CPGMAC_MATCH_FILTER_SHIFT		19
+#define CPGMAC_CHANNEL_MASK			(0x7<<16)
+#define CPGMAC_CHANNEL_SHIFT			16
+#define CPGMAC_TYPE_2_3_MACSRCADDR0_MASK	(0xFF<<8)
+#define CPGMAC_TYPE_2_3_MACSRCADDR0_SHIFT	8
+#define CPGMAC_TYPE_2_3_MACSRCADDR1_MASK	0xFF
+#define CPGMAC_TYPE_2_3_MACSRCADDR1_SHIFT	0
+
+#define CPGMAC_TYPE_2_3_MACSRCADDR2_MASK	(0xFF<<24)
+#define CPGMAC_TYPE_2_3_MACSRCADDR2_SHIFT	24
+#define CPGMAC_TYPE_2_3_MACSRCADDR3_MASK	(0xFF<<16)
+#define CPGMAC_TYPE_2_3_MACSRCADDR3_SHIFT	16
+#define CPGMAC_TYPE_2_3_MACSRCADDR4_MASK	(0xFF<<8)
+#define CPGMAC_TYPE_2_3_MACSRCADDR4_SHIFT	8
+#define CPGMAC_TYPE_2_3_MACSRCADDR5_MASK	0xFF
+#define CPGMAC_TYPE_2_3_MACSRCADDR5_SHIFT	0
+
+/* RX MBP register bit positions */
+#define EMAC_RXMBP_PASSCRC_SHIFT		30
+#define EMAC_RXMBP_PASSCRC_MASK			(0x1 << 30)
+#define EMAC_RXMBP_QOSEN_SHIFT			29
+#define EMAC_RXMBP_QOSEN_MASK			(0x1 << 29)
+#define EMAC_RXMBP_NOCHAIN_SHIFT		28
+#define EMAC_RXMBP_NOCHAIN_MASK			(0x1 << 28)
+#define EMAC_RXMBP_CMFEN_SHIFT			24
+#define EMAC_RXMBP_CMFEN_MASK			(0x1 << 24)
+#define EMAC_RXMBP_CSFEN_SHIFT			23
+#define EMAC_RXMBP_CSFEN_MASK			(0x1 << 23)
+#define EMAC_RXMBP_CEFEN_SHIFT			22
+#define EMAC_RXMBP_CEFEN_MASK			(0x1 << 22)
+#define EMAC_RXMBP_CAFEN_SHIFT			21
+#define EMAC_RXMBP_CAFEN_MASK			(0x1 << 21)
+#define EMAC_RXMBP_PROMCH_SHIFT			16
+#define EMAC_RXMBP_PROMCH_MASK			(0x7 << 16)
+#define EMAC_RXMBP_BROADEN_SHIFT		13
+#define EMAC_RXMBP_BROADEN_MASK			(0x1 << 13)
+#define EMAC_RXMBP_BROADCH_SHIFT		8
+#define EMAC_RXMBP_BROADCH_MASK			(0x7 << 8)
+#define EMAC_RXMBP_MULTIEN_SHIFT		5
+#define EMAC_RXMBP_MULTIEN_MASK			(0x1 << 5)
+#define EMAC_RXMBP_MULTICH_SHIFT		0
+#define EMAC_RXMBP_MULTICH_MASK			0x7
+
+#define EMAC_RXMBP_CHMASK			0x7
+
+/* mac control register bit fields */
+#define EMAC_MACCONTROL_TXSHORTGAPEN_SHIFT	10
+#define EMAC_MACCONTROL_TXSHORTGAPEN_MASK	(0x1 << 10)
+#define EMAC_MACCONTROL_TXPTYPE_SHIFT		9
+#define EMAC_MACCONTROL_TXPTYPE_MASK		(0x1 << 9)
+#define EMAC_MACCONTROL_GIGABITEN_SHIFT		7
+#define EMAC_MACCONTROL_GIGABITEN_MASK		(0x1 << 7)
+#define EMAC_MACCONTROL_TXPACEEN_SHIFT		6
+#define EMAC_MACCONTROL_TXPACEEN_MASK		(0x1 << 6)
+#define EMAC_MACCONTROL_MIIEN_SHIFT		5
+#define EMAC_MACCONTROL_MIIEN_MASK		(0x1 << 5)
+#define EMAC_MACCONTROL_TXFLOWEN_SHIFT		4
+#define EMAC_MACCONTROL_TXFLOWEN_MASK		(0x1 << 4)
+#define EMAC_MACCONTROL_RXFLOWEN_SHIFT		3
+#define EMAC_MACCONTROL_RXFLOWEN_MASK		(0x1 << 3)
+#define EMAC_MACCONTROL_LOOPBKEN_SHIFT		1
+#define EMAC_MACCONTROL_LOOPBKEN_MASK		(0x1 << 1)
+#define EMAC_MACCONTROL_FULLDUPLEXEN_SHIFT	0
+#define EMAC_MACCONTROL_FULLDUPLEXEN_MASK	0x1
+
+/* mac_status register */
+#define EMAC_MACSTATUS_TXERRCODE_MASK		0xF00000
+#define EMAC_MACSTATUS_TXERRCODE_SHIFT		20
+#define EMAC_MACSTATUS_TXERRCH_MASK		0x7
+#define EMAC_MACSTATUS_TXERRCH_SHIFT		16
+#define EMAC_MACSTATUS_RXERRCODE_MASK		0xF000
+#define EMAC_MACSTATUS_RXERRCODE_SHIFT		12
+#define EMAC_MACSTATUS_RXERRCH_MASK		0x7
+#define EMAC_MACSTATUS_RXERRCH_SHIFT		8
+
+/* EMAC RX max packet length mask */
+#define EMAC_RX_MAX_LEN_SHIFT			0
+#define EMAC_RX_MAX_LEN_MASK			0xFFFF
+
+/* EMAC RX max packet length mask */
+#define EMAC_RX_BUFFER_OFFSET_SHIFT		0
+#define EMAC_RX_BUFFER_OFFSET_MASK		0xFFFF
+
+/* MAC_IN_VECTOR (0x180) register bit fields */
+#define EMAC_MAC_IN_VECTOR_HOST_INT		0x20000
+#define EMAC_MAC_IN_VECTOR_STATPEND_INT		0x10000
+#define EMAC_MAC_IN_VECTOR_RX_INT_VEC		0xFF00
+#define EMAC_MAC_IN_VECTOR_TX_INT_VEC		0xFF
+
+/* CPPI bit positions */
+#define EMAC_CPPI_SOP_BIT			(1 << 31)
+#define EMAC_CPPI_EOP_BIT			(1 << 30)
+#define EMAC_CPPI_OWNERSHIP_BIT			(1 << 29)
+#define EMAC_CPPI_EOQ_BIT			(1 << 28)
+#define EMAC_CPPI_TEARDOWN_COMPLETE_BIT		(1 << 27)
+#define EMAC_CPPI_PASS_CRC_BIT			(1 << 26)
+
+/* defining the macro EMAC_INSTANCE_CODE to 0 so that it can be usable in DDA*/
+#define EMAC_INSTANCE_CODE			0
+#define EMAC_ERROR_CODE				(EMAC_INSTANCE_CODE << 16)
+#define EMAC_ERROR_INFO				EMAC_ERROR_CODE
+#define EMAC_ERROR_WARNING			(EMAC_ERROR_CODE | 0x10000000)
+#define EMAC_ERROR_MINOR			(EMAC_ERROR_CODE | 0x20000000)
+#define EMAC_ERROR_MAJOR			(EMAC_ERROR_CODE | 0x30000000)
+#define EMAC_ERROR_CRITICAL			(EMAC_ERROR_CODE | 0x40000000)
+
+/* EMAC success code */
+#define EMAC_SUCCESS				0
+
+/* EMAC error codes */
+#define EMAC_ERR_DEV_ALREADY_INSTANTIATED(inst_id) \
+						(0x30000000 + ((inst_id) << 16))
+#define EMAC_ERR_DEV_NOT_INSTANTIATED		(EMAC_ERROR_MAJOR + 1)
+#define EMAC_INVALID_PARAM			(EMAC_ERROR_MAJOR + 2)
+#define EMAC_ERR_TX_CH_INVALID			(EMAC_ERROR_CRITICAL + 3)
+#define EMAC_ERR_TX_CH_ALREADY_INIT		(EMAC_ERROR_MAJOR + 4)
+#define EMAC_ERR_TX_CH_ALREADY_CLOSED		(EMAC_ERROR_MAJOR + 5)
+#define EMAC_ERR_TX_CH_NOT_OPEN			(EMAC_ERROR_MAJOR + 6)
+#define EMAC_ERR_TX_NO_LINK			(EMAC_ERROR_MAJOR + 7)
+#define EMAC_ERR_TX_OUT_OF_BD			(EMAC_ERROR_MAJOR + 8)
+#define EMAC_ERR_RX_CH_INVALID			(EMAC_ERROR_CRITICAL + 9)
+#define EMAC_ERR_RX_CH_ALREADY_INIT		(EMAC_ERROR_MAJOR + 10)
+#define EMAC_ERR_RX_CH_ALREADY_CLOSED		(EMAC_ERROR_MAJOR + 11)
+#define EMAC_ERR_RX_CH_NOT_OPEN			(EMAC_ERROR_MAJOR + 12)
+#define EMAC_ERR_DEV_ALREADY_CREATED		(EMAC_ERROR_MAJOR + 13)
+#define EMAC_ERR_DEV_NOT_OPEN			(EMAC_ERROR_MAJOR + 14)
+#define EMAC_ERR_DEV_ALREADY_CLOSED		(EMAC_ERROR_MAJOR + 15)
+#define EMAC_ERR_DEV_ALREADY_OPEN		(EMAC_ERROR_MAJOR + 16)
+#define EMAC_ERR_RX_BUFFER_ALLOC_FAIL		(EMAC_ERROR_CRITICAL + 17)
+
+/*
+ * ioctls
+ */
+#define EMAC_IOCTL_BASE		0
+
+#define EMAC_IOCTL_GET_STATISTICS		(EMAC_IOCTL_BASE + 0)
+#define EMAC_IOCTL_CLR_STATISTICS		(EMAC_IOCTL_BASE + 1)
+#define EMAC_IOCTL_GET_SWVER			(EMAC_IOCTL_BASE + 2)
+#define EMAC_IOCTL_GET_HWVER			(EMAC_IOCTL_BASE + 3)
+#define EMAC_IOCTL_SET_RXCFG			(EMAC_IOCTL_BASE + 4)
+#define EMAC_IOCTL_SET_MACCFG			(EMAC_IOCTL_BASE + 5)
+#define EMAC_IOCTL_GET_STATUS			(EMAC_IOCTL_BASE + 6)
+#define EMAC_IOCTL_READ_PHY_REG			(EMAC_IOCTL_BASE + 7)
+#define EMAC_IOCTL_WRITE_PHY_REG		(EMAC_IOCTL_BASE + 8)
+#define EMAC_IOCTL_MULTICAST_ADDR		(EMAC_IOCTL_BASE + 9)
+#define EMAC_IOCTL_ALL_MULTI			(EMAC_IOCTL_BASE + 10)
+#define EMAC_IOCTL_TYPE2_3_FILTERING		(EMAC_IOCTL_BASE + 11)
+#define EMAC_IOCTL_SET_MAC_ADDRESS		(EMAC_IOCTL_BASE + 12)
+#define EMAC_IOCTL_IF_COUNTERS			(EMAC_IOCTL_BASE + 13)
+#define EMAC_IOCTL_ETHER_COUNTERS		(EMAC_IOCTL_BASE + 14)
+#define EMAC_IOCTL_IF_PARAMS_UPDT		(EMAC_IOCTL_BASE + 15)
+
+#define EMAC_IOCTL_TIMER_START			(EMAC_IOCTL_BASE + 16)
+#define EMAC_IOCTL_TIMER_STOP			(EMAC_IOCTL_BASE + 17)
+#define EMAC_IOCTL_STATUS_UPDATE		(EMAC_IOCTL_BASE + 18)
+#define EMAC_IOCTL_MIB64_CNT_TIMER_START	(EMAC_IOCTL_BASE + 19)
+#define EMAC_IOCTL_MIB64_CNT_TIMER_STOP		(EMAC_IOCTL_BASE + 20)
+
+#define EMAC_PRIV_FILTERING			(EMAC_IOCTL_BASE + 21)
+#define EMAC_PRIV_MII_READ			(EMAC_IOCTL_BASE + 22)
+#define EMAC_PRIV_MII_WRITE			(EMAC_IOCTL_BASE + 23)
+#define EMAC_PRIV_GET_STATS			(EMAC_IOCTL_BASE + 24)
+#define EMAC_PRIV_CLR_STATS			(EMAC_IOCTL_BASE + 25)
+#define EMAC_EXTERNAL_SWITCH			(EMAC_IOCTL_BASE + 26)
+
+/*
+ * MII module port settings
+ *
+ * DDA sets the Phy mode as a combination of the following in "phyMode"
+ * parameter in the init configuration structure
+ */
+
+/* bit 16 and above unused by MII register*/
+#define SNWAY_AUTOMDIX		(1<<16)
+#define SNWAY_FD1000		(1<<13)
+#define SNWAY_HD1000		(1<<12)
+#define SNWAY_NOPHY		(1<<10)
+#define SNWAY_LPBK		(1<<9)
+#define SNWAY_FD100		(1<<8)
+#define SNWAY_HD100		(1<<7)
+#define SNWAY_FD10		(1<<6)
+#define SNWAY_HD10		(1<<5)
+#define SNWAY_AUTO		(1<<0)
+#define SNWAY_AUTOALL (SNWAY_AUTO|SNWAY_FD100|SNWAY_FD10|SNWAY_HD100|
SNWAY_HD10)
+
+/**
+ * DDC Status Ioctl - Error status
+ *
+ * Note that each error code is a bit position so that multiple
+ * errors can be clubbed together and passed in a integer value
+ */
+#define EMAC_NO_ERROR		0
+#define EMAC_TX_HOST_ERROR	0x1	/* MSB 8 bits: err code, channel no */
+#define EMAC_RX_HOST_ERROR	0x8	/* LSB 8 bits: err code, channel no */
+
+#define EGRESS_TRAILOR_LEN			0
+
+#define CFG_START_LINK_SPEED			SNWAY_AUTOALL	/* auto nego */
+
+/* defaut configuration values required for passing on to DDC */
+#define EMAC_DEFAULT_MLINK_MASK				0
+#define EMAC_DEFAULT_PASS_CRC				FALSE
+#define EMAC_DEFAULT_QOS_ENABLE				FALSE
+#define EMAC_DEFAULT_NO_BUFFER_CHAINING			FALSE
+#define EMAC_DEFAULT_COPY_MAC_CONTROL_FRAMES_ENABLE	FALSE
+#define EMAC_DEFAULT_COPY_SHORT_FRAMES_ENABLE		FALSE
+#define EMAC_DEFAULT_COPY_ERROR_FRAMES_ENABLE		FALSE
+#define EMAC_DEFAULT_PROMISCOUS_CHANNEL			0
+#define EMAC_DEFAULT_BROADCAST_CHANNEL			0
+#define EMAC_DEFAULT_MULTICAST_CHANNEL			0
+#define EMAC_DEFAULT_BUFFER_OFFSET			0
+#define EMAC_DEFAULT_TX_PRIO_TYPE			EMAC_TXPRIO_FIXED
+#define EMAC_DEFAULT_TX_SHORT_GAP_ENABLE		FALSE
+#define EMAC_DEFAULT_TX_PACING_ENABLE			FALSE
+#define EMAC_DEFAULT_MII_ENABLE				TRUE
+#define EMAC_DEFAULT_TX_FLOW_ENABLE			FALSE
+#define EMAC_DEFAULT_RX_FLOW_ENABLE			FALSE
+#define EMAC_DEFAULT_LOOPBACK_ENABLE			FALSE
+#define EMAC_DEFAULT_FULL_DUPLEX_ENABLE			TRUE
+#define EMAC_DEFAULT_TX_INTERRUPT_DISABLE		TRUE
+#define CONFIG_EMAC_MIB_TIMER_TIMEOUT			5000	/* 5 seconds */
+
+#define EMAC_DEFAULT_PROMISCOUS_ENABLE			0
+#define EMAC_DEFAULT_BROADCAST_ENABLE			1
+#define EMAC_DEFAULT_MULTICAST_ENABLE			1
+
+/* NOT EXPLICIT SUPPORT PROVIDED AS OF NOW - vlan support in the driver */
+#define EMAC_DEFAULT_VLAN_ENABLE			FALSE
+
+/* system value for ticks per seconds */
+#define EMAC_TICKS_PER_SEC				HZ
+
+/**
+ * Extra bytes for Cache alignment of skbuf - should be equal to
+ * processor cache line size - in case of ARM926 its 32 bytes
+ */
+#define EMAC_DEFAULT_EXTRA_RXBUF_SIZE			32
+
+/*
+ * default max frame size = 1522 = 1500 byte data + 14 byte eth header
+ * + 4 byte checksum + 4 byte vlan tag + 32 bytes for cache
+ * alignment
+ */
+#define EMAC_DEFAULT_MAX_FRAME_SIZE    \
+(1500 + 14 + 4 + 4 + EGRESS_TRAILOR_LEN + EMAC_DEFAULT_EXTRA_RXBUF_SIZE)
+
+/* default number of TX channels */
+#define EMAC_DEFAULT_NUM_TX_CHANNELS		1
+
+/* default TX channel number */
+#define EMAC_DEFAULT_TX_CHANNEL			0
+
+/* default TX number of BD's/buffers */
+#define EMAC_DEFAULT_TX_NUM_BD			128
+
+/* default TX max service BD's */
+#define EMAC_DEFAULT_TX_MAX_SERVICE		32
+
+/* default number of RX channels */
+#define EMAC_DEFAULT_NUM_RX_CHANNELS		1
+
+/* default RX channel number */
+#define EMAC_DEFAULT_RX_CHANNEL			0
+
+#define EMAC_DEFAULT_RX_NUM_BD			128
+
+/* default RX max service BD's */
+#define EMAC_DEFAULT_RX_MAX_SERVICE		32 /* should = netdev->weight */
+
+#if ((EMAC_DEFAULT_TX_NUM_BD + EMAC_DEFAULT_RX_NUM_BD)  > 256)
+#error "Error. DaVinci has space for no more than 256 TX+RX BD's"
+#endif
+
+/*
+ * Size of EMAC peripheral footprint in memory that needs to be
+ * reserved in Linux Note that this value is actually a hardware
+ * memory footprint value taken from the specs and ideally should have
+ * been in the csl files. Keeping it for convinience since EMAC
+ * peripheral footprint will not change unless the peripheral itself
+ * changes drastically and it will be called with a different name and
+ * will have a different driver anyway
+ *
+ * For Davinci size = control regs (4k) + wrapper regs (4k) + wrapper
+ * RAM (8k) + mdio regs (2k)
+ */
+#define EMAC_DEFAULT_EMAC_SIZE        0x4800
+
+/* ENV variable names for obtaining MAC addresses */
+#define EMAC_MAC_ADDR_A		"maca"
+#define EMAC_MAC_ADDR_B		"macb"
+#define EMAC_MAC_ADDR_C		"macc"
+#define EMAC_MAC_ADDR_D		"macd"
+#define EMAC_MAC_ADDR_E		"mace"
+#define EMAC_MAC_ADDR_F		"macf"
+
+/**
+ * Maximum multicast addresses list to be handled by the driver - If
+ * this is not restricted then the driver will spend considerable time
+ * in handling multicast lists
+ */
+#define EMAC_DEFAULT_MAX_MULTICAST_ADDRESSES		64
+
+#define NETDEV_PRIV(net_dev)		netdev_priv(net_dev)
+#define FREE_NETDEV(net_dev)		free_netdev(net_dev)
+
+#define dbg_print	{ if (emac_debug_mode) \
+				printk }
+#define err_print printk
+
+/* misc error codes */
+#define EMAC_INTERNAL_FAILURE		(-1)
+
+/* LED codes required for controlling LED's */
+#define EMAC_LINK_OFF		0
+#define EMAC_LINK_ON		1
+#define EMAC_SPEED_100		2
+#define EMAC_SPEED_10		3
+#define EMAC_FULL_DPLX		4
+#define EMAC_HALF_DPLX		5
+#define EMAC_TX_ACTIVITY	6
+#define EMAC_RX_ACTIVITY	7
+
+
+#define EMAC_L3_ALIGN(size)	emac_L3_align[(size) & 3]
+
+
+#define EMAC_4BYTE_ALIGN(size) emac_4byte_align[(size) & 0x3]
+
+#define EMAC_DEBUG_FUNCTION_ENTRY		(0x1 << 1)
+#define EMAC_DEBUG_FUNCTION_EXIT		(0x1 << 2)
+#define EMAC_DEBUG_BUSY_FUNCTION_ENTRY		(0x1 << 3)
+#define EMAC_DEBUG_BUSY_FUNCTION_EXIT		(0x1 << 4)
+#define EMAC_DEBUG_TX				(0x1 << 6)
+#define EMAC_DEBUG_RX				(0x1 << 7)
+#define EMAC_DEBUG_PORT_UPDATE			(0x1 << 8)
+#define EMAC_DEBUG_MII				(0x1 << 9)
+#define EMAC_DEBUG_TEARDOWN			(0x1 << 10)
+
+/*
+ * Debug flags
+ *
+ * IMPORTANT NOTE: The debug flags need to be enabled carefully as it
+ * could flood the console/sink point of the debug traces and also
+ * affect the functionality of the overall system
+ */
+#ifdef EMAC_DEBUG
+#define LOG(lvl, format, args...) \
+	printk(lvl "%s:%d[%d]" format, __FUNCTION__, __LINE__, \
+	dev->init_cfg.inst_id, ##args)
+#define LOGERR(format, args...) LOG(KERN_ERR, format, ##args)
+#define LOGMSG(flag, format, args...)	\
+  do { if (flag & emac_debug) LOG(KERN_DEBUG, #flag format, ##args); } while 
(0)
+#define DBG(format, args...) \
+  do { if (emac_debug_mode) printk(KERN_DEBUG "davinci_emac: " format, ##args);
\
+  } while (0)
+#define ERR(format, args...) \
+  printk(KERN_ERR "ERROR: davinci_emac: " format, ##args)
+#else
+#define DBG(format, args...)
+#define ERR(format, args...)
+#define LOGERR(format, args...)
+#define LOGMSG(flag, format, args...)
+#endif
+
+/* DDC internal macros */
+#define EMAC_RX_BD_BUF_SIZE		0xFFFF;
+#define EMAC_BD_LENGTH_FOR_CACHE	16	/* only CPPI bytes */
+#define EMAC_RX_BD_PKT_LENGTH_MASK	0xFFFF
+
+#define CFG_START_LINK_SPEED		SNWAY_AUTOALL	/* auto nego */
+
+/* defaut configuration values required for passing on to DDC */
+#define EMAC_DEFAULT_MLINK_MASK				0
+#define EMAC_DEFAULT_PASS_CRC				FALSE
+#define EMAC_DEFAULT_QOS_ENABLE				FALSE
+#define EMAC_DEFAULT_NO_BUFFER_CHAINING			FALSE
+#define EMAC_DEFAULT_COPY_MAC_CONTROL_FRAMES_ENABLE	FALSE
+#define EMAC_DEFAULT_COPY_SHORT_FRAMES_ENABLE		FALSE
+#define EMAC_DEFAULT_COPY_ERROR_FRAMES_ENABLE		FALSE
+#define EMAC_DEFAULT_PROMISCOUS_CHANNEL			0
+#define EMAC_DEFAULT_BROADCAST_CHANNEL			0
+#define EMAC_DEFAULT_MULTICAST_CHANNEL			0
+#define EMAC_DEFAULT_BUFFER_OFFSET			0
+#define EMAC_DEFAULT_TX_PRIO_TYPE			EMAC_TXPRIO_FIXED
+#define EMAC_DEFAULT_TX_SHORT_GAP_ENABLE		FALSE
+#define EMAC_DEFAULT_TX_PACING_ENABLE			FALSE
+#define EMAC_DEFAULT_MII_ENABLE				TRUE
+#define EMAC_DEFAULT_TX_FLOW_ENABLE			FALSE
+#define EMAC_DEFAULT_RX_FLOW_ENABLE			FALSE
+#define EMAC_DEFAULT_LOOPBACK_ENABLE			FALSE
+#define EMAC_DEFAULT_FULL_DUPLEX_ENABLE			TRUE
+#define EMAC_DEFAULT_TX_INTERRUPT_DISABLE		TRUE
+#define CONFIG_EMAC_MIB_TIMER_TIMEOUT			5000	/* 5 sec */
+
+#define EMAC_DEFAULT_PROMISCOUS_ENABLE			0
+#define EMAC_DEFAULT_BROADCAST_ENABLE			1
+#define EMAC_DEFAULT_MULTICAST_ENABLE			1
+
+/**
+ * structs, enums
+ */
+enum emac_drv_state {
+	DRV_CREATED,
+	DRV_INITIALIZED,
+	DRV_OPENED,
+	DRV_CLOSED,
+	DRV_DEINITIALIZED,
+	DRV_POWERED_DOWN,
+};
+
+/**
+ * Network Buffer Object
+ *
+ * Holds attributes of a buffer/fragment
+ *
+ * Send: Usually when the buffers are allocated by DDA, the
+ * Start of Packet token will be the handle to the whole packet. This
+ * token/handle should be good enough to free the packet or return to
+ * its pool. When the buffers are allocated by DDC, typically token
+ * for each buffer needs to be indicated (TxComplete) rather than
+ * only the Start of Packet token.
+ *
+ * Receive: For each buffer the token will be a handle to the buffer
+ * that can be used by the allocater (DDA or DDC) of the buffer to
+ * free it or return to a pool.
+ */
+struct net_buf_obj {
+	void *buf_token;
+	char *data_ptr;
+	int length;
+};
+
+/**
+ * Network Packet Object
+ *
+ * Holds attributes of a network packet (NetBufObjs and packet size).
+ */
+struct net_pkt_obj {
+	void *pkt_token;	/* data token may hold tx/rx chan id */
+	struct net_buf_obj *buf_list;	/* array of network buffer objects */
+	int num_bufs;		/* number of network buffer objects */
+	int pkt_length;		/* packet length (number of bytes) */
+};
+
+/**
+ * Net Channel State
+ *
+ * State of the channel (initialized, about to be closed, closed etc
+ */
+enum net_ch_dir {
+	NET_CH_DIR_TX = 0,	/* transmit only */
+	NET_CH_DIR_RX,		/* receive only */
+	NET_CH_DIR_BIDIRECTIONAL,	/* bidirectonaly - TX/RX  */
+	NET_CH_DIR_UNDEFINED	/* not defined */
+};
+
+/**
+ * Net Channel State
+ *
+ * State of the channel (initialized, about to be closed, closed etc
+ */
+enum net_ch_state {
+	NET_CH_UNINITIALIZED = 0,
+	NET_CH_INITIALIZED,
+	NET_CH_OPENED,
+	NET_CH_CLOSE_IN_PROGRESS,
+	NET_CH_CLOSED
+};
+
+/**
+ * EMAC Peripheral Device Register Memory Layout structure
+ *
+ * The structure instance variable points to CP(G)MAC register space in
+ * SOC memory map directly.
+ * This is a template only, no memory is ever allocated for this!
+ */
+
+#define EMAC_WRAP_REGS_BASE		0
+#define EMAC_WRAP_RSVD0_REG		EMAC_WRAP_REGS_BASE
+#define EMAC_WRAP_EWCTL_REG		(EMAC_WRAP_REGS_BASE + 4)
+#define EMAC_WRAP_EWINTTCNT_REG		(EMAC_WRAP_REGS_BASE + 8)
+
+#define EMAC_REGS_BASE			0
+#define EMAC_TX_IDVER_REG		(EMAC_REGS_BASE + 0x00)
+#define EMAC_TX_CONTROL_REG		(EMAC_REGS_BASE + 0x04)
+#define EMAC_TX_TEARDOWN_REG		(EMAC_REGS_BASE + 0x08)
+#define EMAC_RESERVED1_REG		(EMAC_REGS_BASE + 0x0c)
+#define EMAC_RX_IDVER_REG		(EMAC_REGS_BASE + 0x10)
+#define EMAC_RX_CONTROL_REG		(EMAC_REGS_BASE + 0x14)
+#define EMAC_RX_TEARDOWN_REG		(EMAC_REGS_BASE + 0x18)
+#define EMAC_PAD2_REG			(EMAC_REGS_BASE + 0x1c)
+#define EMAC_TX_INTSTAT_RAW_REG		(EMAC_REGS_BASE + 0x80)
+#define EMAC_TX_INTSTAT_MASKED		(EMAC_REGS_BASE + 0x84)
+#define EMAC_TX_INT_MASK_SET_REG	(EMAC_REGS_BASE + 0x88)
+#define EMAC_TX_INT_MASK_CLEAR_REG	(EMAC_REGS_BASE + 0x8c)
+#define EMAC_MAC_IN_VECTOR_REG		(EMAC_REGS_BASE + 0x90)
+#define EMAC_MAC_EOI_VECTOR		(EMAC_REGS_BASE + 0x94)
+#define EMAC_PAD3_REG			(EMAC_REGS_BASE + 0x98)
+#define EMAC_RX_INT_STAT_RAW_REG	(EMAC_REGS_BASE + 0xa0)
+#define EMAC_RX_INT_STAT_MASKED_REG	(EMAC_REGS_BASE + 0xa4)
+#define EMAC_RX_INT_MASK_SET_REG	(EMAC_REGS_BASE + 0xa8)
+#define EMAC_RX_INT_MASK_CLEAR_REG	(EMAC_REGS_BASE + 0xac)
+#define EMAC_MAC_INT_STAT_RAW_REG	(EMAC_REGS_BASE + 0xb0)
+#define EMAC_MAC_INT_STAT_MASKED_REG	(EMAC_REGS_BASE + 0xb4)
+#define EMAC_MAC_INT_MASK_SET_REG	(EMAC_REGS_BASE + 0xb8)
+#define EMAC_MAC_INT_MASK_CLEAR_REG	(EMAC_REGS_BASE + 0xbc)
+#define EMAC_PAD4_REG			(EMAC_REGS_BASE + 0xc0)
+#define EMAC_RX_MBP_ENABLE_REG		(EMAC_REGS_BASE + 0x100)
+#define EMAC_RX_UNICAST_SET_REG		(EMAC_REGS_BASE + 0x104)
+#define EMAC_RX_UNICAST_CLEAR_REG	(EMAC_REGS_BASE + 0x108)
+#define EMAC_RX_MAXLEN_REG		(EMAC_REGS_BASE + 0x10c)
+#define EMAC_RX_BUFFER_OFFSET_REG	(EMAC_REGS_BASE + 0x110)
+#define EMAC_RX_FILTER_LOW_THRESH_REG	(EMAC_REGS_BASE + 0x114)
+#define EMAC_PAD5_REG			(EMAC_REGS_BASE + 0x118)
+#define EMAC_RX_FLOW_THRESH_REG(i)	(EMAC_REGS_BASE + 0x120 + (i<<2))
+#define EMAC_RX_FREE_BUFFER_REG(i)	(EMAC_REGS_BASE + 0x140 + (i<<2))
+#define EMAC_MAC_CONTROL_REG		(EMAC_REGS_BASE + 0x160)
+#define EMAC_MAC_STATUS_REG		(EMAC_REGS_BASE + 0x164)
+#define EMAC_EMCONTROL_REG		(EMAC_REGS_BASE + 0x168)
+#define EMAC_FIFO_CONTROL_REG		(EMAC_REGS_BASE + 0x16c)
+#define EMAC_MAC_CFIG_REG		(EMAC_REGS_BASE + 0x170)
+#define EMAC_SOFT_RESET_REG		(EMAC_REGS_BASE + 0x174)
+#define EMAC_PAD6			(EMAC_REGS_BASE + 0x178)
+#define EMAC_MAC_SRC_ADDR_LO_REG	(EMAC_REGS_BASE + 0x1d0)
+#define EMAC_MAC_SRC_ADDR_HI_REG	(EMAC_REGS_BASE + 0x1d4)
+#define EMAC_MAC_HASH1_REG		(EMAC_REGS_BASE + 0x1d8)
+#define EMAC_MAC_HASH2_REG		(EMAC_REGS_BASE + 0x1dc)
+#define EMAC_BOFF_TEST_REG		(EMAC_REGS_BASE + 0x1e0)
+#define EMAC_TPACE_TEST_REG		(EMAC_REGS_BASE + 0x1e4)
+#define EMAC_RX_PAUSE_REG		(EMAC_REGS_BASE + 0x1e8)
+#define EMAC_TX_PAUSE_REG		(EMAC_REGS_BASE + 0x1ec)
+#define EMAC_PAD7			(EMAC_REGS_BASE + 0x1f0)
+#define EMAC_RX_GOOD_FRAMES_REG		(EMAC_REGS_BASE + 0x200)
+#define EMAC_RX_BROADCAST_FRAMES_REG	(EMAC_REGS_BASE + 0x204)
+#define EMAC_RX_MULTICAST_FRAMES_REG	(EMAC_REGS_BASE + 0x208)
+#define EMAC_RX_PAUSE_FRAMES_REG	(EMAC_REGS_BASE + 0x20c)
+#define EMAC_RX_CRCERROR_REG		(EMAC_REGS_BASE + 0x210)
+#define EMAC_RX_ALIGN_CODE_ERRORS_REG	(EMAC_REGS_BASE + 0x214)
+#define EMAC_RX_OVERSIZED_FRAMES_REG	(EMAC_REGS_BASE + 0x218)
+#define EMAC_RX_JABBER_FRAME_REG	(EMAC_REGS_BASE + 0x21c)
+#define EMAC_RX_UNDERSIZED_FRAMES	(EMAC_REGS_BASE + 0x220)
+#define EMAC_RX_FRAGMENTS_REG 		(EMAC_REGS_BASE + 0x224)
+#define EMAC_RX_FILTERED_FRAMES_REG	(EMAC_REGS_BASE + 0x228)
+#define EMAC_RX_QOS_FILTERED_FRAMES_REG	(EMAC_REGS_BASE + 0x22c)
+#define EMAC_RX_OCTETS_REG		(EMAC_REGS_BASE + 0x230)
+#define EMAC_TX_GOOD_FRAMES_REG		(EMAC_REGS_BASE + 0x234)
+#define EMAC_TX_BROADCAST_FRAMES_REG	(EMAC_REGS_BASE + 0x238)
+#define EMAC_TX_MULTICAST_FRAMES_REG	(EMAC_REGS_BASE + 0x23c)
+#define EMAC_TX_PAUSE_FRAMES_REG	(EMAC_REGS_BASE + 0x240)
+#define EMAC_TX_DEFERED_FRAMES_REG	(EMAC_REGS_BASE + 0x244)
+#define EMAC_TX_COLLISION_FRAMES_REG	(EMAC_REGS_BASE + 0x248)
+#define EMAC_TX_SINGLE_COLL_FRAMES_REG	(EMAC_REGS_BASE + 0x24c)
+#define EMAC_TX_MULT_COLL_FRAMES_REG	(EMAC_REGS_BASE + 0x250)
+#define EMAC_TX_EXCESSIVE_COLLISIONS_REG (EMAC_REGS_BASE + 0x254)
+#define EMAC_TX_LATE_COLLITIONS_REG	(EMAC_REGS_BASE + 0x258)
+#define EMAC_TX_UNDERRUN_REG		(EMAC_REGS_BASE + 0x25c)
+#define EMAC_TX_CARRIER_SENSE_ERRORS_REG	(EMAC_REGS_BASE + 0x260)
+#define EMAC_TX_OCTETS_REG		(EMAC_REGS_BASE + 0x264)
+#define EMAC_REG64OCTET_FRAMES_REG	(EMAC_REGS_BASE + 0x268)
+#define EMAC_65_TO_127_OCTET_REG	(EMAC_REGS_BASE + 0x26c)
+#define EMAC_128_TO_255_OCTET_REG	(EMAC_REGS_BASE + 0x270)
+#define EMAC_256_TO_511_OCTET_REG	(EMAC_REGS_BASE + 0x274)
+#define EMAC_512_TO_1023_OCTET_REG	(EMAC_REGS_BASE + 0x278)
+#define EMAC_1024_UPOCTET_REG		(EMAC_REGS_BASE + 0x27c)
+#define EMAC_NET_OCTETS_REG		(EMAC_REGS_BASE + 0x280)
+#define EMAC_RX_SOF_OVERRUNS_REG	(EMAC_REGS_BASE + 0x284)
+#define EMAC_RX_MOF_OVERRUNS_REG	(EMAC_REGS_BASE + 0x288)
+#define EMAC_RX_DMA_OVERRUNS_REG	(EMAC_REGS_BASE + 0x28c)
+#define EMAC_PAD8			(EMAC_REGS_BASE + 0x290)
+#define EMAC_MAC_ADDR_LO_REG		(EMAC_REGS_BASE + 0x500)
+#define EMAC_MAC_ADDR_HI_REG		(EMAC_REGS_BASE + 0x504)
+#define EMAC_MAC_INDEX_REG		(EMAC_REGS_BASE + 0x508)
+#define EMAC_PAD9			(EMAC_REGS_BASE + 0x50c)
+#define EMAC_TX_HDP_REG(i)		(EMAC_REGS_BASE + 0x600 + (i<<2))
+#define EMAC_RX_HDP_REG(i)		(EMAC_REGS_BASE + 0x620 + (i<<2))
+#define EMAC_TX_CP_REG(i)		(EMAC_REGS_BASE + 0x640 + (i<<2))
+#define EMAC_RX_CP_REG(i)		(EMAC_REGS_BASE + 0x660 + (i<<2))
+
+
+/**
+ * EMAC Peripheral Device Register Enumerations
+ */
+enum emac_reg_ids {
+	tx_id_ver = 0,
+	tx_control,
+	tx_teardown,
+	rx_id_ver = 4,
+	rx_control,
+	rx_teardown,
+	rx_MBP_enable = 64,
+	rx_unicast_set,
+	rx_unicast_clear,
+	rx_maxlen,
+	rx_buffer_offset,
+
+	rx_filter_low_thresh,
+	rx0_flow_thresh = 72,
+	rx1_flow_thresh,
+	rx2_flow_thresh,
+	rx3_flow_thresh,
+	rx4_flow_thresh,
+
+	rx5_flow_thresh,
+	rx6_flow_thresh,
+	rx7_flow_thresh,
+	rx0_free_buffer,
+
+	rx1_free_buffer,
+	rx2_free_buffer,
+	rx3_free_buffer,
+	rx4_free_buffer,
+
+	rx5_free_buffer,
+	rx6_free_buffer,
+	rx7_free_buffer,
+	mac_control,
+	mac_status,
+
+	EMControl,
+	tx_fifo_control,
+	tx_int_stat_raw,
+	tx_int_stat_masked,
+
+	tx_int_mask_set,
+	tx_int_mask_clear,
+	mac_in_vector,
+	mac_EOI_vector,
+	mac_cfig,
+
+	rx_int_stat_raw = 100,
+	rx_int_stat_masked,
+	rx_int_mask_set,
+	rx_int_mask_clear,
+	mac_int_stat_raw,
+
+	mac_int_stat_masked,
+	mac_int_mask_set,
+	mac_int_mask_clear,
+	mac_src_addr_lo = 116,
+	mac_src_addr_hi,
+	mac_hash1,
+	mac_hash2,
+	boff_test,
+	tpace_test,
+	rx_pause,
+
+	tx_pause,
+	rx_good_frames = 128,
+	rx_broadcast_frames,
+	rx_multicast_frames,
+	rx_pause_frames,
+	rx_crcerrors,
+
+	rx_align_code_errors,
+	rx_oversized_frames,
+	rx_jabber_frames,
+	rx_undersized_frames,
+
+	rx_fragments,
+	rx_filtered_frames,
+	rx_qos_filtered_frames,
+	rx_octets,
+
+	tx_good_frames,
+	tx_broadcast_frames,
+	tx_multicast_frames,
+	tx_pause_frames,
+
+	tx_deferred_frames,
+	tx_collision_frames,
+	tx_single_coll_frames,
+	tx_mult_coll_frames,
+
+	tx_excessive_collisions,
+	tx_late_collisions,
+	tx_underrun,
+	tx_carrier_sense_errors,
+
+	tx_octets,
+	reg64octet_frames,
+	reg65t127octet_frames,
+	reg128t255octet_frames,
+
+	reg256t511octet_frames,
+	reg512t1023octet_frames,
+	reg1024t_upoctet_frames,
+
+	net_octets,
+	rx_sof_overruns,
+	rx_mof_overruns,
+	rx_dma_overruns,
+
+	RX_FIFO_processor_test_access = 192,	/* first word of RX FIFO */
+	TX_FIFO_processor_test_access = 256,	/* first word of TX FIFO */
+	mac_addr_lo = 320,
+	mac_addr_hi,
+	mac_index,
+	tx0_HDP = 384,
+	tx1_HDP,
+	tx2_HDP,
+	tx3_HDP,
+	tx4_HDP,
+	tx5_HDP,
+	tx6_HDP,
+
+	tx7_HDP,
+	rx0_HDP,
+	rx1_HDP,
+	rx2_HDP,
+	rx3_HDP,
+	rx4_HDP,
+
+	rx5_HDP,
+	rx6_HDP,
+	rx7_HDP,
+	tx0_CP,
+	tx1_CP,
+	tx2_CP,
+	tx3_CP,
+
+	tx4_CP,
+	tx5_CP,
+	tx6_CP,
+	tx7_CP,
+	rx0_CP,
+	rx1_CP,
+	rx2_CP,
+
+	rx3_CP,
+	rx4_CP,
+	rx5_CP,
+	rx6_CP,
+	rx7_CP,
+	stateram_test_access = 448	/* first word of state RAM */
+};
+
+/**
+ * EMAC Addressing Type
+ *
+ * Addressing type based upon cfig register. For EMAC peripheral cfig
+ * register reads a value of 0 i.e Type 0 addressing
+ */
+enum emac_rx_addr_type {
+	RX_ADDR_TYPE0 = 0,	/* old style used in (EMAC) */
+	RX_ADDR_TYPE1 = 1,	/* new CPGMAC style */
+	RX_ADDR_TYPE2 = 2,	/* new CPGMAC "filtering" style */
+	RX_ADDR_TYPE3 = 3	/* new CPGMAC "filtering" style */
+};
+
+/**
+ * EMAC Single Multicast Ioctl - EMAC_IOCTL_MULTICAST_ADDR operations
+ *
+ * Add/Del operations for adding/deleting a single multicast address
+ */
+enum emac_single_multi_oper {
+	EMAC_MULTICAST_ADD = 0,
+	EMAC_MULTICAST_DEL
+};
+
+/**
+ * EMAC All Multicast Ioctl - EMAC_IOCTL_ALL_MULTI operations
+ *
+ * Set/Clear all multicast operation
+ */
+enum emac_all_multi_oper {
+	EMAC_ALL_MULTI_SET = 0,
+	EMAC_ALL_MULTI_CLR
+};
+
+/**
+ * MII Read/Write PHY register
+ *
+ * Parameters to read/write a PHY register via MII interface
+ */
+struct emac_phy_params {
+	u32 phy_num;		/* phy number to be read/written */
+	u32 reg_addr;		/* register to be read/written */
+	u32 data;		/* data to be read/written */
+};
+
+/**
+ * MAC  Address params
+ *
+ * Parameters for Configuring Mac address
+ */
+struct emac_address_params {
+	u32 channel;
+	char *mac_address;
+};
+
+/**
+ * Type 2/3 Addressing
+ *
+ * Parameters for programming CFIG 2/3 addressing mode
+ *
+ */
+struct emac_type2_3_addr_filter_params {
+	u32 channel;	/* channel to which this filtering params apply */
+	char *mac_address;	/* mac address for filtering */
+	int index;		/* index of filtering list to update */
+	bool valid;		/* entry valid */
+	int match;		/* entry matching  */
+};
+
+/**
+ * EMAC Hardware Statistics
+ *
+ * Statistics counters provided by EMAC Hardware. The names of the
+ * counters in this structure are of "MIB style" and corrospond
+ * directly to the hardware counters provided by EMAC
+ */
+struct emac_hw_statistics {
+	u32 if_in_good_frames;
+	u32 if_in_broadcasts;
+	u32 if_in_multicasts;
+	u32 if_in_pause_frames;
+	u32 if_in_crcerrors;
+	u32 if_in_align_code_errors;
+	u32 if_in_oversized_frames;
+	u32 if_in_jabber_frames;
+	u32 if_in_undersized_frames;
+	u32 if_in_fragments;
+	u32 if_in_filtered_frames;
+	u32 if_in_qos_filtered_frames;
+	u32 if_in_octets;
+	u32 if_out_good_frames;
+	u32 if_out_broadcasts;
+	u32 if_out_multicasts;
+	u32 if_out_pause_frames;
+	u32 if_deferred_transmissions;
+	u32 if_collision_frames;
+	u32 if_single_collision_frames;
+	u32 if_multiple_collision_frames;
+	u32 if_excessive_collision_frames;
+	u32 if_late_collisions;
+	u32 if_out_underrun;
+	u32 if_carrier_sense_errors;
+	u32 if_out_octets;
+	u32 if64octet_frames;
+	u32 if65to127octet_frames;
+	u32 if128to255octet_frames;
+	u32 if256to511octet_frames;
+	u32 if512to1023octet_frames;
+	u32 if1024to_upoctet_frames;
+	u32 if_net_octets;
+	u32 if_rx_sof_overruns;
+	u32 if_rx_mof_overruns;
+	u32 if_rx_dmaoverruns;
+};
+
+
+
+/*
+ * MIB-2 Common MIB Constants
+ */
+#define MIB2_TRUTH_VALUE_TRUE  		1
+#define MIB2_TRUTH_VALUE_FALSE  	2
+
+/* MIB-2 interface admin/oper status values  */
+/* device is in operational status unless status is down. */
+#define MIB2_STATUS_UP		1
+#define MIB2_STATUS_DOWN	2
+#define MIB2_STATUS_TEST	3
+#define MIB2_STATUS_UNKNOWN	4
+#define MIB2_STATUS_DORMANT	5
+
+#define TI_SIOC_OFFSET		0
+
+/* definitions for interface group MIB variables: GET */
+#define TI_SIOCGINTFCOUNTERS		(TI_SIOC_OFFSET + 0x01)
+#define TI_SIOCGINTFPARAMS		(TI_SIOC_OFFSET + 0x02)
+
+/* SET command definitions */
+#define TI_SIOCSINTFADMINSTATUS		(TI_SIOC_OFFSET + 0x03)
+
+/* definitions for ether-like group MIB variables: GET  */
+#define TI_SIOCGETHERCOUNTERS		(TI_SIOC_OFFSET + 0x04)
+#define TI_SIOCGETHERPARAMS		(TI_SIOC_OFFSET + 0x05)
+
+/* defines MIB II INTERFACE objects */
+struct mib2_if_counters {
+	unsigned long in_bytes_low;
+	unsigned long in_bytes_high;
+	unsigned long in_unicast_pkts_low;
+	unsigned long in_unicast_pkts_high;
+	unsigned long in_multicast_pkts_low;
+	unsigned long in_multicast_pkts_high;
+	unsigned long in_broadcast_pkts_low;
+	unsigned long in_broadcast_pkts_high;
+	unsigned long in_discard_pkts;
+	unsigned long in_error_pkts;
+	unsigned long in_unknown_prot_pkts;
+	unsigned long out_bytes_low;
+	unsigned long out_bytes_high;
+	unsigned long out_unicast_pkts_low;
+	unsigned long out_unicast_pkts_high;
+	unsigned long out_multicast_pkts_low;
+	unsigned long out_multicast_pkts_high;
+	unsigned long out_broadcast_pkts_low;
+	unsigned long out_broadcast_pkts_high;
+	unsigned long out_discard_pkts;
+	unsigned long out_error_pkts;
+};
+
+struct mib2_if_hccounters {
+	struct mib2_if_counters mib2if_counter;
+	unsigned long long in_bytes_hc;
+	unsigned long long in_unicast_pkts_hc;
+	unsigned long long in_multicast_pkts_hc;
+	unsigned long long in_broadcast_pkts_hc;
+	unsigned long long out_bytes_hc;
+	unsigned long long out_unicast_pkts_hc;
+	unsigned long long out_multicast_pkts_hc;
+	unsigned long long out_broadcast_pkts_hc;
+	unsigned long long in_bytes;
+	unsigned long long in_unicast_pkts;
+	unsigned long long in_multicast_pkts;
+	unsigned long long in_broadcast_pkts;
+	unsigned long long out_bytes;
+	unsigned long long out_unicast_pkts;
+	unsigned long long out_multicast_pkts;
+	unsigned long long out_broadcast_pkts;
+};
+
+struct mib2_if_params {
+	unsigned long if_speed;		/* speed in bits per second */
+	unsigned long if_high_speed;	/* speed in mega-bits per second */
+	long if_oper_status;
+	long if_promiscuous_mode;
+};
+
+struct mib2_if_command {
+	long if_admin_status;		/* desired interface state */
+};
+
+/* ether_like-MIB constants */
+#define	MIB2_UNKNOWN_DUPLEX	1
+#define	MIB2_HALF_DUPLEX	2
+#define	MIB2_FULL_DUPLEX	3
+
+/* ioctl/cmd value to be used by snmpd like applications */
+#define SIOTIMIB2	SIOCDEVPRIVATE + 1
+
+/* defines MIB II ether_like-MIB  objects */
+struct mib2_phy_counters {
+	unsigned long eth_alignment_errors;
+	unsigned long eth_fcserrors;
+	unsigned long eth_single_collisions;
+	unsigned long eth_multiple_collisions;
+	unsigned long eth_sqetest_errors;
+	unsigned long eth_deferred_tx_frames;
+	unsigned long eth_late_collisions;
+	unsigned long eth_excessive_collisions;
+	unsigned long eth_internal_mac_tx_errors;
+	unsigned long eth_carrier_sense_errors;
+	unsigned long eth_too_long_rx_frames;
+	unsigned long eth_internal_mac_rx_errors;
+	unsigned long eth_symbol_errors;
+};
+
+struct mib2_eth_params {
+	long eth_duplex_status;	/* current emac duplex status */
+};
+
+struct ti_snmp_cmd_t {
+	unsigned long cmd;
+	unsigned long port;
+	void *data;
+};
+
+/**
+ * DDC Status values
+ *
+ * Provides status of the device - error status, phy status etc
+ *
+ */
+struct emac_status {
+	u32 hw_status;
+	u32 hw_err_info;
+	u32 phy_linked;		/* link status: 1=linked, 0=no link */
+	u32 phy_duplex;		/* duplex status:
+				 * 3=full duplex,
+				 * 2=half duplex */
+
+	u32 phy_speed;		/* link speed = 10, 100, 1000 */
+	u32 phy_num;		/* phy number - useful if phy number is
+				* discovered */
+};
+
+/**
+ * EMAC Channel Config Info
+ *
+ * Common to both TX/RX
+ * Used to pass channel config info from DDA to DDC for EMAC channels
+ */
+struct emac_ch_info {
+	int ch_num;		/* DDC_net_ch_info: channel number */
+	enum net_ch_dir ch_dir;	/* DDC_net_ch_info: channel direction */
+	enum net_ch_state ch_state;	/* DDC_net_ch_info: channel state */
+	int num_bd;		/* number of BD (& buffers for RX) */
+	int service_max;	/* maximum BD's processed in one go */
+	int buf_size;		/* buffer size (applicable for RX only) */
+};
+
+/**
+ * EMAC RX configuration
+ *
+ * This data structure configures the RX module of the device
+ */
+struct emac_rx_config {
+	bool pass_crc;		/* pass CRC bytes to packet memory */
+	bool qos_enable;	/* receive qo_s enable ? */
+	bool no_buffer_chaining;	/* DEBUG ONLY - ALWAYS SET TO FALSE */
+	bool copy_maccontrol_frames_enable;
+	bool copy_short_frames_enable;
+	bool copy_error_frames_enable;
+	bool promiscous_enable;
+	u32 promiscous_channel;	/* promiscous receive channel */
+	bool broadcast_enable;	/* receive broadcast frames ? */
+	u32 broadcast_channel;	/* broadcast receive channel */
+	bool multicast_enable;	/* receive multicast frames ? */
+	u32 multicast_channel;	/* multicast receive channel */
+	u32 max_rx_pkt_length;	/* max receive packet length */
+	u32 buffer_offset;	/* buffer offset for all RX channels */
+};
+
+/**
+ * Transmit Queue priority type
+ *
+ * Enums for transmit queue priority type - fixed/round robin
+ * available in hardware
+ */
+enum emac_tx_queue_priority_type {
+	EMAC_TXPRIO_ROUND_ROBIN = 0,
+	EMAC_TXPRIO_FIXED = 1
+};
+
+/**
+ * EMAC MAC configuration
+ *
+ * This data structure configures the MAC module parameters of the device
+ */
+struct emac_mac_config {
+	enum emac_tx_queue_priority_type p_type;
+	bool tx_short_gap_enable;
+	bool giga_bit_enable;
+	bool tx_pacing_enable;
+	bool mii_enable;		/* DEBUG ONLY - ALWAYS SET TO TRUE */
+	bool tx_flow_enable;
+	bool rx_flow_enable;
+	bool loopback_enable;
+	bool full_duplex_enable;	/* DEBUG ONLY - based upon phy_mode */
+	bool tx_interrupt_disable;
+};
+
+/**
+ * EMAC Init Configuration
+ *
+ * Configuration information provided to DDC layer during
+ * initialization.  DDA gets the config information from the OS/PAL
+ * layer and passes the relevant config to the DDC during
+ * initialization. The config info can come from various sources -
+ * static compiled in info, boot time (ENV, Flash) info etc.
+ */
+struct emac_init_config {
+	u32 inst_id;
+	u32 num_tx_channels;
+	u32 num_rx_channels;
+	u32 emac_bus_frequency;
+	u32 base_address;
+	u32 e_wrap_base_address;
+	u32 intr_line;
+	u32 reset_line;
+	u32 mdio_base_address;
+	u32 mdio_reset_line;
+	u32 mdio_intr_line;
+	u32 phy_mask;
+	u32 MLink_mask;
+	u32 mdio_bus_frequency;
+	u32 mdio_clock_frequency;
+	u32 mdio_tick_msec;
+	u32 mib64cnt_msec;
+	u32 phy_mode;
+	struct emac_rx_config rx_cfg;
+	struct emac_mac_config mac_cfg;
+};
+
+struct rx_tx_params {
+	u32 rx_pkts;		/* number of rx pkts to be processed */
+	u32 tx_pkts;		/* number of tx pkts to be processed */
+	u32 ret_rx_pkts;	/* number of rx pkts processed */
+	u32 ret_tx_pkts;	/* number of tx pkts processed */
+};
+
+/*
+ * EMAC Private Ioctl Structure
+ *
+ * Private Ioctl commands provided by the EMAC Linux Driver use this
+ * structure
+ */
+struct emac_drv_priv_ioctl {
+	unsigned int cmd;
+	void *data;
+};
+
+/*
+ * EMAC DDA maintained statistics
+ *
+ * Driver maintained statistics (apart from Hardware statistics)
+ */
+struct emac_drv_stats {
+	unsigned long tx_discards;
+	unsigned long rx_discards;
+	unsigned long start_tick;
+};
+
+/*
+ * TX Buffer Descriptor
+ *
+ * CPPI 3.0 TX BD structure specific to EMAC.
+ */
+struct emac_tx_bd {
+	int h_next;		/* next buffer descriptor pointer */
+	int buff_ptr;		/* data buffer pointer */
+	int off_b_len;		/* (buffer_offset_16)(buffer_length_16) */
+	int mode;		/* SOP, EOP, ownership, EOQ, teardown,
+				 *Qstarv, length */
+	void *next;		/* next TX buffer descriptor (linked list) */
+	void *buf_token;
+	void *eop_bd;		/* pointer to end of packet BD */
+};
+
+/* forward declaration */
+struct emac_rx_cppi_ch_t;
+
+/**
+ * RX Buffer Descriptor
+ *
+ * CPPI 3.0 RX BD structure specific to EMAC.
+ */
+struct emac_rx_bd {
+	int h_next;		/* next (hardware) buffer descriptor pointer */
+	int buff_ptr;		/* data buffer pointer */
+	int off_b_len;		/* (buffer_offset_16)(buffer_length_16) */
+	int mode;		/* SOP, EOP, ownership, EOQ, teardown,
+				 *Q starv, length */
+	void *next;		/* pointer to the next RX buffer in BD queue */
+	void *data_ptr;		/* virtual address of the buffer allocated */
+	void *buf_token;
+	struct emac_rx_cppi_ch_t *rx_cppi;
+};
+
+/**
+ * TX Channel Control Structure
+ *
+ * Used by EMAC DDC code to process TX Buffer Descriptors
+ */
+struct emac_tx_cppi_ch {
+	/** configuration info */
+	struct emac_ch_info ch_info;	/* channel config/info */
+
+	/* CPPI specific */
+	u32 alloc_size;		/* BD pool allocated memory size */
+	char *bd_mem;		/* buffer descriptor memory pointer */
+	struct emac_tx_bd *bd_pool_head;	/* free BD pool head */
+	struct emac_tx_bd *active_queue_head; /* head of active packet queue */
+	struct emac_tx_bd *active_queue_tail;	/* last hardware BD written */
+
+	struct emac_tx_bd *last_hw_bdprocessed;	/* last HW BD processed */
+	bool queue_active;	/* queue active ? TRUE/FALSE */
+#ifdef EMAC_MULTIPACKET_TX_COMPLETE_NOTIFY
+	u32 *tx_complete;	/* tx complete notification queue */
+#endif
+	/** statistics */
+	u32 proc_count;		/* TX: # of times emac_tx_bdproc is called */
+	u32 mis_queued_packets;	/* misqueued packets */
+	u32 queue_reinit;	/* queue reinit - head ptr reinit */
+	u32 end_of_queue_add;	/* packet added to end of queue in send */
+	u32 out_of_tx_bd;	/* out of tx bd errors */
+	u32 no_active_pkts;	/* IRQ when there were no packets to process */
+	u32 active_queue_count;	/* active tx bd count */
+	u32 num_multi_frag_pkts;
+};
+
+/**
+ * RX Channel Control Structure
+ *
+ * Used by EMAC DDC code to process RX Buffer Descriptors
+ */
+struct emac_rx_cppi_ch_t {
+	/* configuration info */
+	struct emac_ch_info ch_info;	/* channel config/info */
+
+	/* EMAC (ethernet) specific configuration info */
+	char mac_addr[6];	/* ethernet MAC address */
+
+	/** CPPI specific */
+	u32 alloc_size;		/* BD pool allocated memory size */
+	char *bd_mem;		/* buffer descriptor memory pointer */
+	struct emac_rx_bd *bd_pool_head;
+	struct emac_rx_bd *active_queue_head;
+	struct emac_rx_bd *active_queue_tail;
+	bool queue_active;
+
+	/* packet and buffer objects required for passing up to DDA
+	 *layer for the given instance */
+	struct net_pkt_obj pkt_queue;
+	struct net_buf_obj buf_queue[EMAC_MAX_RX_FRAGMENTS];
+#ifdef EMAC_MULTIFRAGMENT
+	u32 rx_buffer_ptr[EMAC_MAX_RX_FRAGMENTS];
+	u32 rx_data_token[EMAC_MAX_RX_FRAGMENTS];
+#endif
+	/** statistics */
+	u32 proc_count;		/* number of times struct emac_rx_bdproc
+				 * is called */
+	u32 processed_bd;	/* number of BD's processed */
+	u32 recycled_bd;	/* number of recycled BD's */
+	u32 out_of_rx_bd;	/* NO BD's available */
+	u32 out_of_rx_buffers;	/* NO buffers available */
+	u32 queue_reinit;	/* condition when recycling buffers */
+	u32 end_of_queue_add;	/* when adding BD at end */
+	u32 end_of_queue;	/* end of queue condition */
+	u32 mis_queued_packets;	/* mis-queued packet condition */
+	u32 num_multi_frag_pkts;
+};
+
+/* data structures and header files required for MII-MDIO module  */
+
+/**
+ * EMAC Private data structure
+ *
+ * Each EMAC device maintains its own private data structure and has a
+ * pointer to the net_device data structure representing the instance
+ * with the kernel.  The private data structure contains a "owner"
+ * member pointing to the net_device structure and the net_device data
+ * structure's "priv" member points back to this data structure.
+ */
+struct emac_dev_s {
+	void *owner;		/* pointer to the net_device struct */
+	unsigned int instance_num;	/* instance number of the device */
+	struct net_device *next_device;
+	unsigned int link_speed;
+	unsigned int link_mode;
+	unsigned long set_to_close;
+	void *led_handle;
+
+	/* DDC related parameters */
+	struct emac_status ddc_status;
+
+	/* configuration parameters */
+	unsigned char mac_addr[6];
+	struct emac_init_config init_cfg;
+	unsigned int rx_buf_size;
+	unsigned int rx_buf_offset;
+
+	/* TODO: VLAN TX not supported as of now */
+	bool vlan_enable;
+
+	/* channel configuration - though only 1 TX/RX channel is
+	 *supported, provision is made for max */
+	struct emac_ch_info tx_ch_info[EMAC_MAX_TX_CHANNELS];
+	struct emac_ch_info rx_ch_info[EMAC_MAX_RX_CHANNELS];
+
+	/* periodic timer required for MDIO polling */
+	struct timer_list periodic_timer;
+	u32 periodic_ticks;	/* ticks for this timer */
+	bool timer_active;	/* periodic timer active ??? */
+	struct timer_list mib_timer;	/* for 64 bit MIB counter  */
+	u32 mib_ticks;		/* ticks for this timer */
+	bool mib_timer_active;	/* periodic timer active ??? */
+
+	/* statistics */
+	struct emac_hw_statistics device_mib; /* hardware statistics counters */
+	struct emac_drv_stats device_stats;	/* device statstics */
+	struct net_device_stats net_dev_stats;
+
+	/* statistics counters for debugging */
+	u32 isr_count;
+
+	/* tx_rx_param struct added */
+	struct rx_tx_params napi_rx_tx;
+
+	/* TX/RX locks */
+	spinlock_t tx_lock;
+	spinlock_t rx_lock;
+
+	enum emac_drv_state drv_state;
+
+	/** EMAC specific parameters - DDC device specifics */
+	struct emac_tx_cppi_ch *tx_cppi[EMAC_MAX_TX_CHANNELS];
+	struct emac_rx_cppi_ch_t *rx_cppi[EMAC_MAX_RX_CHANNELS];
+	bool tx_is_created[EMAC_MAX_TX_CHANNELS];
+	bool rx_is_created[EMAC_MAX_RX_CHANNELS];
+	bool tx_is_open[EMAC_MAX_TX_CHANNELS];
+	bool rx_is_open[EMAC_MAX_RX_CHANNELS];
+	bool tx_teardown_pending[EMAC_MAX_TX_CHANNELS];
+	bool rx_teardown_pending[EMAC_MAX_RX_CHANNELS];
+	int tx_int_threshold[EMAC_MAX_TX_CHANNELS];
+	bool tx_interrupt_disable;
+
+	/* register mirror values - maintained to avoid costly
+	 *register access for reads */
+	u32 rx_unicast_set;
+	u32 rx_unicast_clear;
+	u32 rx_MBP_enable;
+	u32 mac_hash1;
+	u32 mac_hash2;
+	u32 mac_control;
+	struct emac_status status;
+
+	/* number of multicast hash bits used in hardware */
+	u32 multicast_hash_cnt[EMAC_NUM_MULTICAST_BITS];
+
+	u32 emac_regs_base;
+	u32 emac_wrap_regs_base;
+	/* EMAC/CPGMAC addressing mechanism */
+	u32 rx_addr_type;	/* 0 (EMAC), 1 or 2 (CPGMAC) */
+	u32 irq_line;
+	struct napi_struct napi;
+
+	struct mib2_if_hccounters mib2if_hccounter;
+};
+
+#define davinci_orl(v, a)	davinci_writel((davinci_readl(a) | v), a)
+
+#define EMAC_TOKEN_PARSE(str) \
+  { if ((tok = (char *)strsep((str), ":")) == NULL) return -1; }
+#define EMAC_TOKEN_GET_INTEGER simple_strtoul (tok, NULL, 10)
+#define EMAC_TOKEN_GET_HEX     simple_strtoul (tok, NULL, 16)
+
+/*
+ * internal utility functions
+ */
+static inline u32 emac_virt_to_phys(u32 addr)
+{
+	/* NOTE: must handle memory and IO addresses */
+	return ((addr & 0xFFFF0000) == EMAC_BASE_ADDR)?
+			io_v2p(addr) : virt_to_phys((void *)addr);
+}
+
+#define EMAC_VIRT_TO_PHYS(x) emac_virt_to_phys((u32)x)
+#define EMAC_VIRT_NOCACHE(addr)(addr)
+
+/* alloc and zero memoy */
+static inline int emac_malloc(u32 n, void **buf)
+{
+	void *tmp = kcalloc(n, 1, GFP_KERNEL);
+
+	if (!tmp) {
+		printk(KERN_ERR "emac_malloc(): kmalloc() failed.\n");
+		dump_stack();
+		return -1;
+	}
+
+	*buf = tmp;
+	return 0;
+}
+
+static inline void emac_free(void *ptr)
+{
+	kfree(ptr);
+}
+
+#define EMAC_CACHE_INVALIDATE(addr, size) \
+	dma_cache_maint((void *)addr, size, DMA_FROM_DEVICE)
+#define EMAC_CACHE_WRITEBACK(addr, size) \
+	dma_cache_maint((void *)addr, size, DMA_TO_DEVICE)
+#define EMAC_CACHE_WRITEBACK_INVALIDATE(addr, size) \
+	dma_cache_maint((void *)addr, size, DMA_BIDIRECTIONAL)
+
+/* buffer-descriptors in IO space.  No cache invalidation needed */
+#define BD_CACHE_INVALIDATE(addr, size)
+#define BD_CACHE_WRITEBACK(addr, size)
+#define BD_CACHE_WRITEBACK_INVALIDATE(addr, size)
+
+/* string to hex conversion */
+static inline unsigned char emac_str_to_hexnum(unsigned char c)
+{
+	if (c >= '0' && c <= '9')
+		return c - '0';
+	if (c >= 'a' && c <= 'f')
+		return c - 'a' + 10;
+	if (c >= 'A' && c <= 'F')
+		return c - 'A' + 10;
+	return 0;
+}
+
+extern int davinci_get_macaddr(char *ptr);
+
+#ifdef EMAC_DEBUG
+
+extern int emac_p_read_link(char *buf, char **start, off_t offset, int count,
+			    int *eof, void *data);
+extern int emac_dump_config(char *buf, char **start, off_t offset, int count,
+			    int *eof, void *data);
+extern int emac_p_update_statistics_debug(struct net_device *netdev, char *buf,
+				    int limit, int *p_len);
+extern int emac_p_read_rfc2665_stats(char *buf, char **start, off_t offset,
+				     int count, int *eof, void *data);
+extern int emac_p_read_stats(char *buf, char **start, off_t offset, int count,
+			     int *eof, void *data);
+extern int emac_p_write_stats(struct file *fp, const char *buf,
+			      unsigned long count, void *data);
+extern int emac_devices_installed;
+extern struct net_device *last_emac_device;
+extern int emac_control(struct emac_dev_s *dev, int cmd, void *cmd_arg,
+			void *param);
+extern int emac_p_reset_statistics(struct net_device *netdev);
+extern int emac_p_update_statistics(struct net_device *netdev);
+
+#endif
Index: 2.6.24-rc8.ether/drivers/net/arm/davinci_emac_debug.c
===================================================================
--- /dev/null
+++ 2.6.24-rc8.ether/drivers/net/arm/davinci_emac_debug.c
@@ -0,0 +1,658 @@
+/*
+ * Copyright (C) 2008 MontaVista Software, Inc. <source@...sta.com>
+ *
+ * This file is licensed under the terms of the
+ * GNU General Public License version 2. This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/netdevice.h>
+#include "davinci_emac.h"
+
+/* dump configuration information for debug purposes */
+int emac_dump_config(char *buf, char **start, off_t offset, int count,
+			    int *eof, void *data)
+{
+	int len = 0;
+	struct net_device *netdev;
+	struct net_device *emac_dev_list[emac_devices_installed];
+	int i;
+	struct emac_dev_s *dev;
+
+	len +=
+	sprintf(buf + len, "EMAC devices = %d\n", emac_devices_installed);
+
+	netdev = last_emac_device;
+
+	/*
+	 * reverse the the device link list to list eth0,eth1...in
+	 * correct order
+	 */
+	for (i = 0; i < emac_devices_installed; i++) {
+		emac_dev_list[emac_devices_installed - (i + 1)] = netdev;
+		dev = NETDEV_PRIV(netdev);
+		netdev = dev->next_device;
+	}
+
+	for (i = 0; i < emac_devices_installed; i++) {
+		netdev = emac_dev_list[i];
+		dev = NETDEV_PRIV(netdev);
+
+		len +=
+		sprintf(buf + len,
+			"\nEMAC Driver Internal Config Info for Unit %d\n",
+     dev->instance_num);
+		len += sprintf(buf + len, "vlanEnable         = %d\n",
+			       dev->vlan_enable);
+		len += sprintf(buf + len, "rxBufSize          = %d\n",
+			       dev->rx_buf_size);
+		len += sprintf(buf + len, "rxBufOffset        = %d\n",
+			       dev->rx_buf_offset);
+		len += sprintf(buf + len, "instId             = %d\n",
+			       dev->init_cfg.inst_id);
+		len += sprintf(buf + len, "numTxChannels      = %d\n",
+			       dev->init_cfg.num_tx_channels);
+		len += sprintf(buf + len, "numRxChannels      = %d\n",
+			       dev->init_cfg.num_rx_channels);
+		len += sprintf(buf + len, "emacBusFrequency  = %d\n",
+			       dev->init_cfg.emac_bus_frequency);
+		len += sprintf(buf + len, "baseAddress        = %08X\n",
+			       dev->init_cfg.base_address);
+		len += sprintf(buf + len, "intrLine           = %d\n",
+			       dev->init_cfg.intr_line);
+		len += sprintf(buf + len, "resetLine          = %d\n",
+			       dev->init_cfg.reset_line);
+		len += sprintf(buf + len, "mdioBaseAddress    = %08X\n",
+			       dev->init_cfg.mdio_base_address);
+		len += sprintf(buf + len, "mdioResetLine      = %d\n",
+			       dev->init_cfg.mdio_reset_line);
+		len += sprintf(buf + len, "mdioIntrLine       = %d\n",
+			       dev->init_cfg.mdio_intr_line);
+		len += sprintf(buf + len, "PhyMask            = %08X\n",
+			       dev->init_cfg.phy_mask);
+		len += sprintf(buf + len, "MLinkMask          = %08X\n",
+			       dev->init_cfg.MLink_mask);
+		len += sprintf(buf + len, "MdioBusFrequency   = %d\n",
+			       dev->init_cfg.mdio_bus_frequency);
+		len += sprintf(buf + len, "MdioClockFrequency = %d\n",
+			       dev->init_cfg.mdio_clock_frequency);
+		len += sprintf(buf + len, "MdioTickMSec       = %d\n",
+			       dev->init_cfg.mdio_tick_msec);
+		len += sprintf(buf + len, "phyMode            = %d\n",
+			       dev->init_cfg.phy_mode);
+		len += sprintf(buf + len, "passCRC            = %d\n",
+			       dev->init_cfg.rx_cfg.pass_crc);
+		len += sprintf(buf + len, "qosEnable          = %d\n",
+			       dev->init_cfg.rx_cfg.qos_enable);
+		len += sprintf(buf + len, "noBufferChaining   = %d\n",
+			       dev->init_cfg.rx_cfg.no_buffer_chaining);
+		len += sprintf(buf + len, "copyMACCntrlFrsEne = %d\n",
+			dev->init_cfg.rx_cfg.copy_maccontrol_frames_enable);
+		len += sprintf(buf + len, "copyShortFramesEn  = %d\n",
+			       dev->init_cfg.rx_cfg.copy_short_frames_enable);
+		len += sprintf(buf + len, "copyErrorFramesEn  = %d\n",
+			       dev->init_cfg.rx_cfg.copy_error_frames_enable);
+		len += sprintf(buf + len, "promiscousEnable   = %d\n",
+			       dev->init_cfg.rx_cfg.promiscous_enable);
+		len += sprintf(buf + len, "promiscousChannel  = %d\n",
+			       dev->init_cfg.rx_cfg.promiscous_channel);
+		len += sprintf(buf + len, "broadcastEnable    = %d\n",
+			       dev->init_cfg.rx_cfg.broadcast_enable);
+		len += sprintf(buf + len, "broadcastChannel   = %d\n",
+			       dev->init_cfg.rx_cfg.broadcast_channel);
+		len += sprintf(buf + len, "multicastEnable    = %d\n",
+			       dev->init_cfg.rx_cfg.multicast_enable);
+		len += sprintf(buf + len, "multicastChannel   = %d\n",
+			       dev->init_cfg.rx_cfg.multicast_channel);
+		len += sprintf(buf + len, "maxRxPktLength     = %d\n",
+			       dev->init_cfg.rx_cfg.max_rx_pkt_length);
+		len += sprintf(buf + len, "bufferOffset       = %d\n",
+			       dev->init_cfg.rx_cfg.buffer_offset);
+		len += sprintf(buf + len, "pType              = %d\n",
+			       dev->init_cfg.mac_cfg.p_type);
+		len += sprintf(buf + len, "txShortGapEnable   = %d\n",
+			       dev->init_cfg.mac_cfg.tx_short_gap_enable);
+		len += sprintf(buf + len, "gigaBitEnable      = %d\n",
+			       dev->init_cfg.mac_cfg.giga_bit_enable);
+		len += sprintf(buf + len, "txPacingEnable     = %d\n",
+			       dev->init_cfg.mac_cfg.tx_pacing_enable);
+		len += sprintf(buf + len, "miiEnable          = %d\n",
+			       dev->init_cfg.mac_cfg.mii_enable);
+		len += sprintf(buf + len, "txFlowEnable       = %d\n",
+			       dev->init_cfg.mac_cfg.tx_flow_enable);
+		len += sprintf(buf + len, "rxFlowEnable       = %d\n",
+			       dev->init_cfg.mac_cfg.rx_flow_enable);
+		len += sprintf(buf + len, "loopbackEnable     = %d\n",
+			       dev->init_cfg.mac_cfg.loopback_enable);
+		len += sprintf(buf + len, "fullDuplexEnable   = %d\n",
+			       dev->init_cfg.mac_cfg.full_duplex_enable);
+		netdev = dev->next_device;
+	}
+
+	return len;
+}
+
+
+/* link read support */
+int emac_p_read_link(char *buf, char **start, off_t offset, int count,
+			    int *eof, void *data)
+{
+	int len = 0;
+	struct net_device *netdev;
+	struct emac_dev_s *dev;
+	struct net_device *emac_dev_list[emac_devices_installed];
+	int i;
+
+	len +=
+	sprintf(buf + len, "EMAC devices = %d\n", emac_devices_installed);
+	netdev = last_emac_device;
+
+	/* reverse the the device link list to list eth0,eth1...in correct
+	*order */
+	for (i = 0; i < emac_devices_installed; i++) {
+		emac_dev_list[emac_devices_installed - (i + 1)] = netdev;
+		dev = NETDEV_PRIV(netdev);
+		netdev = dev->next_device;
+	}
+
+	for (i = 0; i < emac_devices_installed; i++) {
+		netdev = emac_dev_list[i];
+		dev = NETDEV_PRIV(netdev);
+
+		/*  this prints them out from high to low because of
+		how the devices are linked */
+		if (netif_carrier_ok(netdev)) {
+			len +=
+			sprintf(buf + len,
+			"eth%d: Link State: %s    "
+			"Phy %d, Speed = %s, Duplex = %s\n",
+			dev->instance_num, "UP",
+			dev->ddc_status.phy_num,
+			(dev->link_speed == 100000000) ? "100" : "10",
+			(dev->link_mode == 2) ? "Half" : "Full");
+		} else {
+			len += sprintf(buf + len, "eth%d: Link State: DOWN\n",
+				       dev->instance_num);
+		}
+		netdev = dev->next_device;
+	}
+
+	return len;
+}
+
+/* update RFC2665 statistics */
+int emac_p_read_rfc2665_stats(char *buf, char **start, off_t offset,
+				     int count, int *eof, void *data)
+{
+	int limit = count - 80;
+	int len = 0;
+	struct net_device *netdev = (struct net_device *)data;
+
+	emac_p_update_statistics_debug(netdev, buf, limit, &len);
+	*eof = 1;
+
+	return len;
+}
+
+int emac_p_update_statistics_debug(struct net_device *netdev, char *buf,
+				    int limit, int *p_len)
+{
+	unsigned long rx_hal_errors = 0;
+	unsigned long rx_hal_discards = 0;
+	unsigned long tx_hal_errors = 0;
+	unsigned long if_out_discards = 0;
+	unsigned long if_in_discards = 0;
+	unsigned long if_out_errors = 0;
+	unsigned long if_in_errors = 0;
+	struct emac_dev_s *dev = NETDEV_PRIV(netdev);
+	struct emac_hw_statistics *p_device_mib = &dev->device_mib;
+	struct emac_drv_stats *p_stats = &dev->device_stats;
+	struct emac_hw_statistics local_mib;
+	struct emac_hw_statistics *p_local_mib = &local_mib;
+	struct net_device_stats *p_net_dev_stats = &dev->net_dev_stats;
+	int len = 0;
+	int dev_mib_elem_count = 0;
+
+	/* do not access the hardware if it is in the reset state. */
+	if (!test_bit(0, &dev->set_to_close)) {
+		/* get hardware statistics from DDC */
+		if (emac_control(dev, EMAC_IOCTL_GET_STATISTICS,
+		    (void *)p_local_mib, NULL)
+				  != EMAC_SUCCESS) {
+			ERR("Error getting statistics for %s\n", netdev->name);
+
+			return -1;
+		}
+
+		dev_mib_elem_count = sizeof(struct emac_hw_statistics) /
+				sizeof(unsigned long);
+
+		/*
+		 * Update the history of the stats. This takes care of
+		 * any reset of the device and stats that might have
+		 * taken place during the life time of the driver.
+		 */
+		while (dev_mib_elem_count--)
+			*((unsigned long *)p_device_mib + dev_mib_elem_count) =
+					*((unsigned long *)p_local_mib +
+					dev_mib_elem_count);
+	}
+
+	/* RFC2665, section 3.2.7, page 9 */
+	rx_hal_errors =	p_device_mib->if_in_fragments +
+			p_device_mib->if_in_crcerrors +
+			p_device_mib->if_in_align_code_errors +
+			p_device_mib->if_in_jabber_frames;
+
+	/* RFC2233 */
+	rx_hal_discards = p_device_mib->if_rx_dmaoverruns;
+
+	/* RFC2665, section 3.2.7, page 9 */
+	tx_hal_errors =	p_device_mib->if_excessive_collision_frames +
+			p_device_mib->if_late_collisions +
+			p_device_mib->if_carrier_sense_errors +
+			p_device_mib->if_out_underrun;
+
+	/* if not set, the short frames (< 64 bytes) are considered as
+	errors */
+	if (dev->init_cfg.rx_cfg.copy_short_frames_enable == FALSE)
+		rx_hal_errors += p_device_mib->if_in_undersized_frames;
+
+	/* All frames greater than max rx frame length set in hardware
+	*should be considered error frames RFC2665, section 3.2.7,
+	*page 9. */
+	rx_hal_errors += p_device_mib->if_in_oversized_frames;
+
+	/* if not in promiscous, then non addr matching frames are discarded */
+	/* EMAC 2.0 manual section 2.8.1.14 */
+	if (dev->init_cfg.rx_cfg.promiscous_enable == FALSE)
+		if_in_discards += p_device_mib->if_in_filtered_frames;
+
+	/* total rx discards = hal discards */
+	if_in_discards = rx_hal_discards;
+	p_net_dev_stats->rx_dropped = rx_hal_discards;
+	p_net_dev_stats->rx_crc_errors = p_device_mib->if_in_crcerrors;
+	p_net_dev_stats->rx_frame_errors =
+			p_device_mib->if_in_align_code_errors;
+	p_net_dev_stats->multicast = p_device_mib->if_in_multicasts;
+	if_in_errors = rx_hal_errors;
+	if_out_errors = tx_hal_errors;
+	if_out_discards = p_net_dev_stats->tx_dropped;
+
+	/* let us update the net device stats struct. to be updated in
+	the later releases. */
+	dev->net_dev_stats.rx_errors = if_in_errors;
+	dev->net_dev_stats.collisions = p_device_mib->if_collision_frames;
+	dev->net_dev_stats.tx_carrier_errors =
+			p_device_mib->if_carrier_sense_errors;
+
+	if (buf == NULL || limit == 0)
+		return 0;
+
+	if (len <= limit)
+		len += sprintf(buf + len, "%-35s: %u\n", "ifSpeed",
+			       dev->link_speed);
+	if (len <= limit)
+		len += sprintf(buf + len, "%-35s: %u\n",
+			       "dot3StatsDuplexStatus",	dev->link_mode);
+	if (len <= limit)
+		len += sprintf(buf + len, "%-35s: %u\n", "ifAdminStatus",
+			       (netdev->flags & IFF_UP ? 1 : 2));
+	if (len <= limit)
+		len += sprintf(buf + len, "%-35s: %u\n", "ifOperStatus",
+			       (((netdev->flags & IFF_UP) &&
+				netif_carrier_ok(netdev)) ? 1 : 2));
+	if (len <= limit)
+		len += sprintf(buf + len, "%-35s: %lu\n", "ifLastChange",
+			       p_stats->start_tick);
+	if (len <= limit)
+		len += sprintf(buf + len, "%-35s: %lu\n", "ifInDiscards",
+			       if_in_discards);
+	if (len <= limit)
+		len += sprintf(buf + len, "%-35s: %lu\n", "ifInErrors",
+			       if_in_errors);
+	if (len <= limit)
+		len += sprintf(buf + len, "%-35s: %lu\n", "ifOutDiscards",
+			       if_out_discards);
+	if (len <= limit)
+		len += sprintf(buf + len, "%-35s: %lu\n", "ifOutErrors",
+			       if_out_errors);
+	if (len <= limit)
+		len += sprintf(buf + len, "%-35s: %u\n", "ifInGoodFrames",
+			       p_device_mib->if_in_good_frames);
+	if (len <= limit)
+		len += sprintf(buf + len, "%-35s: %u\n", "ifInBroadcasts",
+			       p_device_mib->if_in_broadcasts);
+	if (len <= limit)
+		len += sprintf(buf + len, "%-35s: %u\n", "ifInMulticasts",
+			       p_device_mib->if_in_multicasts);
+	if (len <= limit)
+		len += sprintf(buf + len, "%-35s: %u\n", "ifInPauseFrames",
+			       p_device_mib->if_in_pause_frames);
+	if (len <= limit)
+		len += sprintf(buf + len, "%-35s: %u\n", "ifInCRCErrors",
+			       p_device_mib->if_in_crcerrors);
+	if (len <= limit)
+		len += sprintf(buf + len, "%-35s: %u\n", "ifInAlignCodeErrors",
+			       p_device_mib->if_in_align_code_errors);
+	if (len <= limit)
+		len += sprintf(buf + len, "%-35s: %u\n", "ifInOversizedFrames",
+			       p_device_mib->if_in_oversized_frames);
+	if (len <= limit)
+		len += sprintf(buf + len, "%-35s: %u\n", "ifInJabberFrames",
+			       p_device_mib->if_in_jabber_frames);
+	if (len <= limit)
+		len += sprintf(buf + len, "%-35s: %u\n",
+			       "ifInUndersizedFrames",
+			       p_device_mib->if_in_undersized_frames);
+	if (len <= limit)
+		len += sprintf(buf + len, "%-35s: %u\n", "ifInFragments",
+			       p_device_mib->if_in_fragments);
+	if (len <= limit)
+		len += sprintf(buf + len, "%-35s: %u\n", "ifInFilteredFrames",
+			       p_device_mib->if_in_filtered_frames);
+	if (len <= limit)
+		len += sprintf(buf + len, "%-35s: %u\n",
+			       "ifInQosFilteredFrames",
+			       p_device_mib->if_in_qos_filtered_frames);
+	if (len <= limit)
+		len += sprintf(buf + len, "%-35s: %u\n", "ifInOctets",
+			       p_device_mib->if_in_octets);
+	if (len <= limit)
+		len += sprintf(buf + len, "%-35s: %u\n", "ifOutGoodFrames",
+			       p_device_mib->if_out_good_frames);
+	if (len <= limit)
+		len += sprintf(buf + len, "%-35s: %u\n", "ifOutBroadcasts",
+			       p_device_mib->if_out_broadcasts);
+	if (len <= limit)
+		len += sprintf(buf + len, "%-35s: %u\n", "ifOutMulticasts",
+			       p_device_mib->if_out_multicasts);
+	if (len <= limit)
+		len += sprintf(buf + len, "%-35s: %u\n", "ifOutPauseFrames",
+			       p_device_mib->if_out_pause_frames);
+	if (len <= limit)
+		len += sprintf(buf + len, "%-35s: %u\n",
+			       "ifDeferredTransmissions",
+			       p_device_mib->if_deferred_transmissions);
+	if (len <= limit)
+		len += sprintf(buf + len, "%-35s: %u\n", "ifCollisionFrames",
+			       p_device_mib->if_collision_frames);
+	if (len <= limit)
+		len += sprintf(buf + len, "%-35s: %u\n",
+			       "ifSingleCollisionFrames",
+			       p_device_mib->if_single_collision_frames);
+	if (len <= limit)
+		len += sprintf(buf + len, "%-35s: %u\n",
+			       "ifMultipleCollisionFrames",
+			       p_device_mib->if_multiple_collision_frames);
+	if (len <= limit)
+		len += sprintf(buf + len, "%-35s: %u\n",
+			       "ifExcessiveCollisionFrames",
+			       p_device_mib->if_excessive_collision_frames);
+	if (len <= limit)
+		len += sprintf(buf + len, "%-35s: %u\n", "ifLateCollisions",
+			       p_device_mib->if_late_collisions);
+	if (len <= limit)
+		len += sprintf(buf + len, "%-35s: %u\n", "ifOutUnderrun",
+			       p_device_mib->if_out_underrun);
+	if (len <= limit)
+		len += sprintf(buf + len, "%-35s: %u\n",
+			       "ifCarrierSenseErrors",
+			       p_device_mib->if_carrier_sense_errors);
+	if (len <= limit)
+		len += sprintf(buf + len, "%-35s: %u\n", "ifOutOctets",
+			       p_device_mib->if_out_octets);
+	if (len <= limit)
+		len += sprintf(buf + len, "%-35s: %u\n", "if64OctetFrames",
+			       p_device_mib->if64octet_frames);
+	if (len <= limit)
+		len += sprintf(buf + len, "%-35s: %u\n",
+			       "if65To127POctetFrames",
+			       p_device_mib->if65to127octet_frames);
+	if (len <= limit)
+		len += sprintf(buf + len, "%-35s: %u\n",
+			       "if128To255OctetFrames",
+			       p_device_mib->if128to255octet_frames);
+	if (len <= limit)
+		len += sprintf(buf + len, "%-35s: %u\n",
+			       "if256To511OctetFrames",
+			       p_device_mib->if256to511octet_frames);
+	if (len <= limit)
+		len += sprintf(buf + len, "%-35s: %u\n",
+			       "if512To1023OctetFrames",
+			       p_device_mib->if512to1023octet_frames);
+	if (len <= limit)
+		len += sprintf(buf + len, "%-35s: %u\n",
+			       "if1024ToUpOctetFrames",
+			       p_device_mib->if1024to_upoctet_frames);
+	if (len <= limit)
+		len += sprintf(buf + len, "%-35s: %u\n", "ifNetOctets",
+			       p_device_mib->if_net_octets);
+	if (len <= limit)
+		len += sprintf(buf + len, "%-35s: %u\n", "ifRxSofOverruns",
+			       p_device_mib->if_rx_sof_overruns);
+	if (len <= limit)
+		len += sprintf(buf + len, "%-35s: %u\n", "ifRxMofOverruns",
+			       p_device_mib->if_rx_mof_overruns);
+	if (len <= limit)
+		len += sprintf(buf + len, "%-35s: %u\n", "ifRxDMAOverruns",
+			       p_device_mib->if_rx_dmaoverruns);
+	*p_len = len;
+
+	return 0;
+}
+
+int emac_p_read_stats(char *buf, char **start, off_t offset, int count,
+			     int *eof, void *data)
+{
+	struct net_device *netdev = last_emac_device;
+	int len = 0;
+	int limit = count - 80;
+	int i;
+	struct net_device *emac_dev_list[emac_devices_installed];
+	struct emac_dev_s *dev;
+	struct emac_hw_statistics *p_device_mib;
+
+	/* reverse the the device link list to list eth0,eth1...in
+	correct order */
+	for (i = 0; i < emac_devices_installed; i++) {
+		emac_dev_list[emac_devices_installed - (i + 1)] = netdev;
+		dev = NETDEV_PRIV(netdev);
+		netdev = dev->next_device;
+	}
+
+	for (i = 0; i < emac_devices_installed; i++) {
+		netdev = emac_dev_list[i];
+		if (!netdev)
+			goto proc_error;
+
+		/* get stats */
+		emac_p_update_statistics(netdev);
+		dev = NETDEV_PRIV(netdev);
+		p_device_mib = &dev->device_mib;
+
+		/* transmit stats */
+		if (len <= limit)
+			len += sprintf(buf + len, "\nCpmac %d, Address %lx\n",
+				       i + 1, netdev->base_addr);
+		if (len <= limit)
+			len += sprintf(buf + len, " Transmit Stats\n");
+		if (len <= limit)
+			len += sprintf(buf + len,
+				       "   Tx Valid Bytes Sent        :%u\n",
+				       p_device_mib->if_out_octets);
+		if (len <= limit)
+			len += sprintf(buf + len,
+				       "   Good Tx Frames (Hardware)  :%u\n",
+				       p_device_mib->if_out_good_frames);
+		if (len <= limit)
+			len += sprintf(buf + len,
+				       "   Good Tx Frames (Software)  :%lu\n",
+				       dev->net_dev_stats.tx_packets);
+		if (len <= limit)
+			len += sprintf(buf + len,
+				       "   Good Tx Broadcast Frames   :%u\n",
+				       p_device_mib->if_out_broadcasts);
+		if (len <= limit)
+			len += sprintf(buf + len,
+				       "   Good Tx Multicast Frames   :%u\n",
+				       p_device_mib->if_out_multicasts);
+		if (len <= limit)
+			len += sprintf(buf + len,
+				       "   Pause Frames Sent          :%u\n",
+				       p_device_mib->if_out_pause_frames);
+		if (len <= limit)
+			len += sprintf(buf + len,
+				       "   Collisions                 :%u\n",
+				       p_device_mib->if_collision_frames);
+		if (len <= limit)
+			len += sprintf(buf + len,
+				       "   Tx Error Frames            :%lu\n",
+				       dev->net_dev_stats.tx_errors);
+		if (len <= limit)
+			len += sprintf(buf + len,
+				       "   Carrier Sense Errors       :%u\n",
+				       p_device_mib->if_carrier_sense_errors);
+		if (len <= limit)
+			len += sprintf(buf + len, "\n");
+
+		/* receive stats */
+		if (len <= limit)
+			len += sprintf(buf + len, "\nCpmac %d, Address %lx\n",
+				       i + 1, netdev->base_addr);
+		if (len <= limit)
+			len += sprintf(buf + len, " Receive Stats\n");
+		if (len <= limit)
+			len += sprintf(buf + len,
+				       "   Rx Valid Bytes Received    :%u\n",
+				       p_device_mib->if_in_octets);
+		if (len <= limit)
+			len += sprintf(buf + len,
+				       "   Good Rx Frames (Hardware)  :%u\n",
+				       p_device_mib->if_in_good_frames);
+		if (len <= limit)
+			len += sprintf(buf + len,
+				       "   Good Rx Frames (Software)  :%lu\n",
+				       dev->net_dev_stats.rx_packets);
+		if (len <= limit)
+			len += sprintf(buf + len,
+				       "   Good Rx Broadcast Frames   :%u\n",
+				       p_device_mib->if_in_broadcasts);
+		if (len <= limit)
+			len += sprintf(buf + len,
+				       "   Good Rx Multicast Frames   :%u\n",
+				       p_device_mib->if_in_multicasts);
+		if (len <= limit)
+			len += sprintf(buf + len,
+				       "   Pause Frames Received      :%u\n",
+				       p_device_mib->if_in_pause_frames);
+		if (len <= limit)
+			len += sprintf(buf + len,
+				       "   Rx CRC Errors              :%u\n",
+				       p_device_mib->if_in_crcerrors);
+		if (len <= limit)
+			len += sprintf(buf + len,
+				       "   Rx Align/Code Errors       :%u\n",
+				       p_device_mib->if_in_align_code_errors);
+		if (len <= limit)
+			len += sprintf(buf + len,
+				       "   Rx Jabbers                 :%u\n",
+				       p_device_mib->if_in_oversized_frames);
+		if (len <= limit)
+			len += sprintf(buf + len,
+				       "   Rx Filtered Frames         :%u\n",
+				       p_device_mib->if_in_filtered_frames);
+		if (len <= limit)
+			len += sprintf(buf + len,
+				       "   Rx Fragments               :%u\n",
+				       p_device_mib->if_in_fragments);
+		if (len <= limit)
+			len += sprintf(buf + len,
+				       "   Rx Undersized Frames       :%u\n",
+				       p_device_mib->if_in_undersized_frames);
+		if (len <= limit)
+			len += sprintf(buf + len,
+				       "   Rx Overruns                :%u\n",
+				       p_device_mib->if_rx_dmaoverruns);
+	}
+
+	return len;
+
+proc_error:
+		*eof = 1;
+
+	return len;
+}
+
+int emac_p_write_stats(struct file *fp, const char *buf,
+			      unsigned long count, void *data)
+{
+	char local_buf[31];
+	int ret_val = 0;
+
+	if (count > 30) {
+		printk(KERN_NOTICE"Error : Buffer Overflow\n");
+		printk(KERN_NOTICE"Use \"echo 0 > emac_stat\" to reset"
+				" the statistics\n");
+		return -EFAULT;
+	}
+
+	count -= copy_from_user(local_buf, buf, count);
+	local_buf[(count)? (count - 1) : 0] = '\0'; /* ignoring last \n char */
+	ret_val = count;
+	if (strcmp("0", local_buf) == 0) {
+		struct net_device *netdev = last_emac_device;
+		int i;
+		struct net_device *emac_dev_list[emac_devices_installed];
+		struct emac_dev_s *dev;
+
+		/* valid command */
+		printk(KERN_INFO"Resetting statistics for EMAC interface.\n");
+
+		/*
+		 * reverse the the device link list to list
+		 * eth0,eth1...in correct order
+		 */
+		for (i = 0; i < emac_devices_installed; i++) {
+			emac_dev_list[emac_devices_installed - (i + 1)] =
+					netdev;
+			dev = NETDEV_PRIV(netdev);
+			netdev = dev->next_device;
+		}
+
+		for (i = 0; i < emac_devices_installed; i++) {
+			netdev = emac_dev_list[i];
+			if (!netdev) {
+				ret_val = -EFAULT;
+				break;
+			}
+			emac_p_reset_statistics(netdev);
+		}
+	} else {
+		printk(KERN_NOTICE"Error: Unknown operation on"
+				"emac statistics\n");
+		printk(KERN_NOTICE"Use \"echo 0 > emac_stats\" to"
+				" reset the statistics\n");
+		return -EFAULT;
+	}
+
+	return ret_val;
+}
Index: 2.6.24-rc8.ether/drivers/net/arm/davinci_emac_phy.c
===================================================================
--- /dev/null
+++ 2.6.24-rc8.ether/drivers/net/arm/davinci_emac_phy.c
@@ -0,0 +1,723 @@
+/*
+ * linux/drivers/net/davinci_emac_phy.c
+ *
+ * EMAC MII-MDIO Module - Polling State Machine.
+ *
+ * Copyright (C) 2006 Texas Instruments.
+ * Copyright (C) 2008 MontaVista Software, Inc. <source@...sta.com>
+ *
+ * This file is licensed under the terms of the
+ * GNU General Public License version 2. This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * ----------------------------------------------------------------------------
+ Modifications:
+ *  HISTORY:
+ *  Date      	Modifier         		Notes
+ *  2001/02 	Denis, Bill, Michael		Original
+ *  14Feb2006	Anant Gole 			Re-written for linux
+ *  07Dec2006	Paul Bartholomew		Fix half-duplex,
+ *           					use PHY_DUPLEX_* constants
+ */
+#include <linux/kernel.h>
+
+#include <asm/io.h>
+
+#include "davinci_emac_phy.h"
+
+#define EMAC_PHY_DEBUG 0
+
+#if EMAC_PHY_DEBUG
+#define DPRINTK(fmt, args...)	\
+			do { if (emac_phy->debug_mode) \
+			printk(KERN_ERR "\n%s: " fmt, __FUNCTION__ , ## args) \
+			} while (0)
+#else
+#define DPRINTK(fmt, args...)
+#endif
+
+/* Phy Registers */
+#define PHY_CONTROL_REG       	0
+#define MII_PHY_RESET           (1<<15)
+#define MII_PHY_LOOP            (1<<14)
+#define MII_PHY_100             (1<<13)
+#define MII_AUTO_NEGOTIATE_EN   (1<<12)
+#define MII_PHY_PDOWN           (1<<11)
+#define MII_PHY_ISOLATE         (1<<10)
+#define MII_RENEGOTIATE         (1<<9)
+#define MII_PHY_FD              (1<<8)
+
+#define PHY_STATUS_REG        	1
+#define MII_NWAY_COMPLETE       (1<<5)
+#define MII_NWAY_CAPABLE        (1<<3)
+#define MII_PHY_LINKED          (1<<2)
+
+#define NWAY_ADVERTIZE_REG    	4
+#define NWAY_REMADVERTISE_REG 	5
+#define MII_NWAY_FD100          (1<<8)
+#define MII_NWAY_HD100          (1<<7)
+#define MII_NWAY_FD10           (1<<6)
+#define MII_NWAY_HD10           (1<<5)
+#define MII_NWAY_SEL            (1<<0)
+
+/*
+ * Timeout values - since timer tikc is expected to be 10 mSecs fixed these
+ * values are in (value * 10 mSecs)
+ */
+#define PHY_FIND_TIMEOUT (2)
+#define PHY_RECK_TIMEOUT (200)
+#define PHY_LINK_TIMEOUT (500)
+#define PHY_NWST_TIMEOUT (500)
+#define PHY_NWDN_TIMEOUT (800)
+#define PHY_MDIX_TIMEOUT (274)	/* 2.74 Seconds <--Spec and empirical */
+
+/* Mask & Control defines */
+#define MDIO_CONTROL_CLKDIV           	(0xFF)
+#define MDIO_CONTROL_ENABLE           	(1 << 30)
+#define MDIO_USERACCESS_GO     			(1 << 31)
+#define MDIO_USERACCESS_WRITE  			(1 << 30)
+#define MDIO_USERACCESS_READ   			(0 << 30)
+#define MDIO_USERACCESS_WRITE  			(1 << 30)
+#define MDIO_USERACCESS_REGADR 			(0x1F << 21)
+#define MDIO_USERACCESS_PHYADR 			(0x1F << 16)
+#define MDIO_USERACCESS_DATA   			(0xFFFF)
+#define MDIO_USERPHYSEL_LINKSEL         (1 << 7)
+#define MDIO_VER_MODID         			(0xFFFF << 16)
+#define MDIO_VER_REVMAJ        			(0xFF   << 8)
+#define MDIO_VER_REVMIN        			(0xFF)
+
+/* PHY Registers */
+#define MDIO_VER						(0x00)
+#define MDIO_CONTROL					(0x04)
+#define MDIO_ALIVE						(0x08)
+#define MDIO_LINK						(0x0C)
+#define MDIO_LINKINTRAW					(0x10)
+#define MDIO_LINKINTMASKED				(0x14)
+#define MDIO_USERINTRAW					(0x20)
+#define MDIO_USERINTMASKED				(0x24)
+#define MDIO_USERINTMASKED_SET			(0x28)
+#define MDIO_USERINTMASKED_CLR			(0x2C)
+#define MDIO_USERACCESS(inst)			(0x80+(inst*8))
+#define MDIO_USERPHYSEL(inst) 			(0x84+(inst*8))
+
+#define MDIO_USERACCESS_INST	MDIO_USERACCESS(emac_phy->inst)
+#define MDIO_USERPHYSEL_INST	MDIO_USERPHYSEL(emac_phy->inst)
+
+#define MDIO_REG_READ(reg)		(__raw_readl(emac_phy->base + (reg)))
+#define MDIO_REG_WRITE(reg, val)	(__raw_writel(val,	\
+						emac_phy->base + (reg)))
+
+/* Phy State */
+#define PHY_NULL       0
+#define PHY_INIT       1
+#define PHY_FINDING    2
+#define PHY_FOUND      3
+#define PHY_NWAY_START 4
+#define PHY_NWAY_WAIT  5
+#define PHY_LINK_WAIT  6
+#define PHY_LINKED     7
+#define PHY_LOOPBACK   8
+
+static char *phy_state_str[] = {
+	"NULL", "INIT", "FINDING", "FOUND", "NWAY_START", "NWAY_WAIT",
+	"LINK_WAIT", "LINKED", "LOOPBACK"
+};
+
+#define PHY_NOT_FOUND  0xFFFF	/*  Used in Phy Detection */
+
+struct phy_info {
+	int inst;		/* Instance of PHY - for user sel register */
+	unsigned int base;	/* Base address of mdio module */
+	int state;		/* state of phy */
+	int state_change;	/* phy state change ? */
+	unsigned int timeout;	/* Timeout counter */
+	unsigned int phy_mode;	/* requested phy mode */
+	unsigned int speed;	/* current Speed - 10 / 100 */
+	unsigned int duplex;	/* 0=Auto Negotiate,
+				 * 3=Full,
+				 * 2=Half,
+				 * 1=Unknown
+				 */
+	unsigned int phy_addr;	/* phy address */
+	unsigned int phy_mask;	/* phy mask */
+	unsigned int mlink_mask;/* mlink mask */
+	int debug_mode;		/* debug mode */
+};
+
+/* Global phy structure instance */
+struct phy_info emac_phy_info;
+struct phy_info *emac_phy = &emac_phy_info;
+
+void emac_mdio_get_ver(unsigned int mdio_base, unsigned int *module_id,
+		       unsigned int *rev_major, unsigned int *rev_minor)
+{
+	unsigned int ver;
+
+	emac_phy->base = mdio_base;
+	ver = MDIO_REG_READ(MDIO_VER);
+
+	*module_id = (ver & MDIO_VER_MODID) >> 16;
+	*rev_major = (ver & MDIO_VER_REVMAJ) >> 8;
+	*rev_minor = (ver & MDIO_VER_REVMIN);
+}
+
+/* Initialize mdio module */
+int emac_mdio_init(unsigned int mdio_base,
+		   unsigned int inst,
+		   unsigned int phy_mask,
+		   unsigned int mlink_mask,
+		   unsigned int mdio_bus_freq,
+		   unsigned int mdio_clock_freq, unsigned int verbose)
+{
+	unsigned int clk_div;
+
+	/* Set base addr and init phy state */
+	emac_phy->inst = inst;
+	emac_phy->base = mdio_base;
+	emac_phy->phy_mask = phy_mask;
+	emac_phy->mlink_mask = mlink_mask;
+	emac_phy->state = PHY_INIT;
+	emac_phy->debug_mode = verbose;
+	emac_phy->speed = 10;
+	emac_phy->duplex = PHY_DUPLEX_HALF;	/* Half duplex */
+
+	clk_div = ((mdio_clock_freq & mdio_bus_freq)?
+		((mdio_bus_freq / mdio_clock_freq) - 1) : 0xff)
+		& MDIO_CONTROL_CLKDIV;
+
+	/* Set enable and clock divider in MDIOControl */
+	MDIO_REG_WRITE(MDIO_CONTROL, clk_div | MDIO_CONTROL_ENABLE);
+
+	return 0;
+}
+
+/* Set PHY mode - autonegotiation or any other */
+void emac_mdio_set_phy_mode(unsigned int phy_mode)
+{
+	emac_phy->phy_mode = phy_mode;
+
+	if ((emac_phy->state == PHY_NWAY_START) ||
+	    (emac_phy->state == PHY_NWAY_WAIT) ||
+	    (emac_phy->state == PHY_LINK_WAIT) ||
+	    (emac_phy->state == PHY_LINKED) ||
+	    (emac_phy->state == PHY_LOOPBACK)) {
+		emac_phy->state = PHY_FOUND;
+		emac_phy->state_change = 1;
+	}
+
+	DPRINTK("PhyMode:%08X Auto:%d, FD10:%d, HD10:%d, FD100:%d, HD100:%d\n",
+		phy_mode,
+		phy_mode & NWAY_AUTO, phy_mode & MII_NWAY_FD10,
+		phy_mode & MII_NWAY_HD10, phy_mode & MII_NWAY_FD100,
+		phy_mode & MII_NWAY_HD100);
+}
+
+/* Get linked status - check if link is on - 1=link on, 0=link off */
+inline int emac_mdio_is_linked(void)
+{
+	return ((emac_phy->state == PHY_LINKED) ? 1 : 0);
+}
+
+/* Get speed - 10 / 100 Mbps */
+inline int emac_mdio_get_speed(void)
+{
+	return emac_phy->speed;
+}
+
+/*
+ * Get duplex - 0=Auto Negotiate, Full Duplex = 3; Half Duplex = 2 Unknown = 1
+ */
+inline int emac_mdio_get_duplex(void)
+{
+	return emac_phy->duplex;
+}
+
+/* Get Phy number/address */
+inline int emac_mdio_get_phy_num(void)
+{
+	return emac_phy->phy_addr;
+}
+
+/* Check if loopback enabled on phy */
+inline int emac_mdio_is_loopback(void)
+{
+	return ((emac_phy->state == PHY_LOOPBACK) ? 1 : 0);
+}
+
+/* Wait until mdio is ready for next command */
+#define MDIO_WAIT_FOR_USER_ACCESS \
+	while ((MDIO_REG_READ(MDIO_USERACCESS_INST) & MDIO_USERACCESS_GO) != 0);
+
+/* Read from a phy register via mdio interface */
+unsigned int emac_mdio_read(unsigned int phy_addr, unsigned int phy_reg)
+{
+	unsigned int phy_data = 0;
+
+	/* Wait until mdio is ready for next command */
+	MDIO_WAIT_FOR_USER_ACCESS;
+
+	MDIO_REG_WRITE(MDIO_USERACCESS_INST,
+		       (MDIO_USERACCESS_GO |
+		       MDIO_USERACCESS_READ |
+		       ((phy_reg << 21) & MDIO_USERACCESS_REGADR) |
+		       ((phy_addr << 16) & MDIO_USERACCESS_PHYADR) |
+		       (phy_data & MDIO_USERACCESS_DATA)));
+
+	/* Wait until mdio is ready for next command */
+	MDIO_WAIT_FOR_USER_ACCESS;
+
+	return (MDIO_REG_READ(MDIO_USERACCESS_INST) & MDIO_USERACCESS_DATA);
+}
+
+/* Write to a phy register via mdio interface */
+void emac_mdio_write(unsigned int phy_addr, unsigned int phy_reg,
+		     unsigned int phy_data)
+{
+	/* Wait until mdio is ready for next command */
+	MDIO_WAIT_FOR_USER_ACCESS;
+
+	MDIO_REG_WRITE(MDIO_USERACCESS_INST,
+		       (MDIO_USERACCESS_GO |
+		       MDIO_USERACCESS_WRITE |
+		       ((phy_reg << 21) & MDIO_USERACCESS_REGADR) |
+		       ((phy_addr << 16) & MDIO_USERACCESS_PHYADR) |
+		       (phy_data & MDIO_USERACCESS_DATA)));
+}
+
+/* Reset the selected phy */
+static void emac_mdio_phy_reset(unsigned int phy_addr)
+{
+	emac_mdio_write(phy_addr, PHY_CONTROL_REG, MII_PHY_RESET);
+	while (emac_mdio_read(phy_addr, PHY_CONTROL_REG) & MII_PHY_RESET);
+	/*
+	 * CRITICAL: Fix for increasing PHY signal drive strength for
+	 * TX lockup issue. On DaVinci EVM, the Intel LXT971 PHY
+	 * signal strength was low causing  TX to fail randomly. The
+	 * fix is to Set bit 11 (Increased MII drive strength) of PHY
+	 * register 26 (Digital Config register) on this phy.
+	 */
+	emac_mdio_write(phy_addr, 26, ((emac_mdio_read(phy_addr, 26)) | 0x800));
+	emac_mdio_read(phy_addr, 26);
+}
+
+/* Timeout condition handler in PHY state machine */
+static void emac_mdio_phy_timeout(void)
+{
+	emac_phy->state = PHY_FOUND;
+	emac_phy->state_change = 1;
+}
+
+/* PHY state machine : Init state handler */
+static void emac_mdio_init_state(void)
+{
+	emac_phy->state = PHY_FINDING;
+	emac_phy->state_change = 1;
+	emac_phy->timeout = PHY_FIND_TIMEOUT;
+}
+
+/* PHY state machine : Finding state handler */
+static void emac_mdio_finding_state(void)
+{
+	unsigned int phy_alive_status;
+	int i;
+
+	emac_phy->phy_addr = PHY_NOT_FOUND;
+
+	/* Find if timeout complete */
+	if (emac_phy->timeout)
+		/* Allow some time for phy to show up in alive register */
+		--emac_phy->timeout;
+	else {
+		phy_alive_status = MDIO_REG_READ(MDIO_LINK);
+		/* Check phys based upon user mask */
+		phy_alive_status &= emac_phy->phy_mask;
+
+		/* Find the first interesting alive phy */
+		i = ffs(phy_alive_status) - 1;
+
+		if ((phy_alive_status) && (i < 32))
+			emac_phy->phy_addr = i;
+
+		if (emac_phy->phy_addr != PHY_NOT_FOUND) {
+			DPRINTK("PHY Found. Phy Number=%d\n",
+				emac_phy->phy_addr);
+			emac_phy->state = PHY_FOUND;
+			emac_phy->state_change = 1;
+		} else {
+			/* Set Timer for finding timeout */
+			DPRINTK("PHY NOT Found. Starting timeout\n");
+			emac_phy->timeout = PHY_RECK_TIMEOUT;
+		}
+	}
+}
+
+/* PHY state machine : Found state handler */
+static void emac_mdio_found_state(void)
+{
+	unsigned int phy_status;
+	unsigned int phy_num;
+	unsigned int cnt;
+	unsigned int nway_advertise;
+
+	/* Check if there is any phy mode requested by the user */
+	if (emac_phy->phy_mode == 0)
+		return;
+
+	/* Check alive phy's */
+	phy_status = MDIO_REG_READ(MDIO_LINK);
+	phy_status &= emac_phy->phy_mask; /* Check phys based upon user mask */
+
+	/*
+	 * we will now isolate all our phys, except the one we have
+	 * decided to use
+	 */
+	for (phy_num = 0, cnt = 1; phy_num < 32; phy_num++, cnt <<= 1) {
+		if ((phy_status & cnt) && (phy_num != emac_phy->phy_addr)) {
+			/*
+			 * Disable a phy that we are not using
+			 *
+			 * CRITICAL: Note that this code assums that there is
+			 * only 1 phy connected if this is not the case then
+			 * the next statement should be commented.
+			 */
+			emac_mdio_write(emac_phy->phy_addr,
+					PHY_CONTROL_REG,
+					(MII_PHY_ISOLATE |
+					 MII_PHY_PDOWN));
+		}
+	}
+
+	/*  Reset the Phy and proceed with auto-negotiation */
+	emac_mdio_phy_reset(emac_phy->phy_addr);
+
+	/*
+	 * Set the way Link will be Monitored, Check the Link Selection Method
+	 */
+	if ((1 << emac_phy->phy_addr) & emac_phy->mlink_mask)
+		MDIO_REG_WRITE(MDIO_USERPHYSEL_INST,
+			       (emac_phy->phy_addr | MDIO_USERPHYSEL_LINKSEL));
+
+	/* For Phy Internal loopback , need to wait until Phy found */
+	if (emac_phy->phy_mode & NWAY_LPBK) {
+		/* Set Phy in Loopback and read mdio to confirm */
+		emac_mdio_write(emac_phy->phy_addr, PHY_CONTROL_REG,
+				(MII_PHY_LOOP | MII_PHY_FD));
+		emac_mdio_read(emac_phy->phy_addr, PHY_STATUS_REG);
+		emac_phy->state = PHY_LOOPBACK;
+		emac_phy->state_change = 1;
+		return;
+	}
+
+	/* Start negotiation */
+	nway_advertise = MII_NWAY_SEL;
+	if (emac_phy->phy_mode & NWAY_FD100)
+		nway_advertise |= MII_NWAY_FD100;
+	if (emac_phy->phy_mode & NWAY_HD100)
+		nway_advertise |= MII_NWAY_HD100;
+	if (emac_phy->phy_mode & NWAY_FD10)
+		nway_advertise |= MII_NWAY_FD10;
+	if (emac_phy->phy_mode & NWAY_HD10)
+		nway_advertise |= MII_NWAY_HD10;
+
+	phy_status = emac_mdio_read(emac_phy->phy_addr, PHY_STATUS_REG);
+
+	if ((phy_status & MII_NWAY_CAPABLE)
+		&& (emac_phy->phy_mode & NWAY_AUTO)) {
+		/*
+		 * NWAY Phy Detected - following procedure for NWAY
+		 * compliant Phys
+		 */
+		emac_mdio_write(emac_phy->phy_addr, NWAY_ADVERTIZE_REG,
+				nway_advertise);
+		if (emac_phy->debug_mode) {
+			DPRINTK("NWAY Advertising: ");
+			if (nway_advertise & MII_NWAY_FD100)
+				DPRINTK("100 Mbps FullDuplex");
+			if (nway_advertise & MII_NWAY_HD100)
+				DPRINTK("100 Mbps HalfDuplex");
+			if (nway_advertise & MII_NWAY_FD10)
+				DPRINTK("10 Mbps FullDuplex");
+			if (nway_advertise & MII_NWAY_HD10)
+				DPRINTK("10 Mbps HalfDuplex");
+			DPRINTK("\n");
+		}
+
+		/* Start/Restart autonegotiation */
+		emac_mdio_write(emac_phy->phy_addr, PHY_CONTROL_REG,
+				MII_AUTO_NEGOTIATE_EN);
+		emac_mdio_write(emac_phy->phy_addr, PHY_CONTROL_REG,
+				(MII_AUTO_NEGOTIATE_EN | MII_RENEGOTIATE));
+		emac_phy->state = PHY_NWAY_START;
+		emac_phy->state_change = 1;
+		emac_phy->timeout = PHY_NWST_TIMEOUT;
+	} else {
+		/* Phy cannot do auto negotiation */
+		emac_phy->phy_mode &= ~NWAY_AUTO;
+		nway_advertise &= ~MII_NWAY_SEL;
+		phy_status = 0;
+
+		if (nway_advertise & (MII_NWAY_FD100 | MII_NWAY_HD100)) {
+			phy_status = MII_PHY_100;/* Set 100 Mbps if requested */
+			nway_advertise &= (MII_NWAY_FD100 | MII_NWAY_HD100);
+		} else
+			nway_advertise &= (MII_NWAY_FD10 | MII_NWAY_HD10);
+
+		/* Set Full duplex if requested */
+		if (nway_advertise & (MII_NWAY_FD100 | MII_NWAY_FD10))
+			phy_status |= MII_PHY_FD;
+
+		/* Set requested speed and duplex mode on phy */
+		emac_mdio_write(emac_phy->phy_addr, PHY_CONTROL_REG,
+				phy_status);
+
+		/* Set the phy speed and duplex mode */
+		emac_phy->speed = (phy_status & MII_PHY_100) ? 100 : 10;
+		emac_phy->duplex = (phy_status & MII_PHY_FD) ? 3 : 2;
+
+		emac_phy->state = PHY_LINK_WAIT;
+		emac_phy->state_change = 1;
+		emac_phy->timeout = PHY_LINK_TIMEOUT;
+	}
+}
+
+/* PHY state machine : NWAY Start state handler */
+static void emac_mdio_nwaystart_state(void)
+{
+	unsigned int status;
+
+	status = emac_mdio_read(emac_phy->phy_addr, PHY_CONTROL_REG);
+	if ((status & MII_RENEGOTIATE) == 0) {
+		/* Flush pending latched bits */
+		status = emac_mdio_read(emac_phy->phy_addr, PHY_STATUS_REG);
+		emac_phy->state = PHY_NWAY_WAIT;
+		emac_phy->state_change = 1;
+		emac_phy->timeout = PHY_NWDN_TIMEOUT;
+	} else {
+		if (emac_phy->timeout)
+			--emac_phy->timeout;
+		else
+		    /*
+		     * Timed Out for NWAY to start - very unlikely condition,
+		     * back to Found
+		     */
+			emac_mdio_phy_timeout();
+	}
+}
+
+/* PHY state machine : NWAY Wait state handler */
+static void emac_mdio_nwaywait_state(void)
+{
+	unsigned int status;
+	unsigned int my_cap, partner_cap, neg_mode;
+
+	/* Check if nway negotiation complete */
+	status = emac_mdio_read(emac_phy->phy_addr, PHY_STATUS_REG);
+
+	if (status & MII_NWAY_COMPLETE) {
+		/* negotiation complete, check for partner capabilities */
+		emac_phy->state_change = 1;
+		my_cap = emac_mdio_read(emac_phy->phy_addr, NWAY_ADVERTIZE_REG);
+		partner_cap =
+		    emac_mdio_read(emac_phy->phy_addr, NWAY_REMADVERTISE_REG);
+
+		/* Negotiated mode is what we and partnet have in common */
+		neg_mode = my_cap & partner_cap;
+		if (emac_phy->debug_mode)
+			DPRINTK("Phy %d, neg_mode %04X, my_cap %04X,"
+				" partner_cap %04X\n", emac_phy->phy_addr,
+				neg_mode, my_cap, partner_cap);
+
+		/* Limit negotiation to fields below */
+		neg_mode &=
+		    (MII_NWAY_FD100 | MII_NWAY_HD100 | MII_NWAY_FD10 |
+		     MII_NWAY_HD10);
+		if (neg_mode == 0)
+			DPRINTK("WARNING: Negotiation complete but NO"
+				" agreement, default is 10HD\n");
+
+		if (neg_mode & MII_NWAY_FD100)
+			DPRINTK("100 Mbps FullDuplex");
+		if (neg_mode & MII_NWAY_HD100)
+			DPRINTK("100 Mbps HalfDuplex");
+		if (neg_mode & MII_NWAY_FD10)
+			DPRINTK("10 Mbps FullDuplex");
+		if (neg_mode & MII_NWAY_HD10)
+			DPRINTK("10 Mbps HalfDuplex");
+		DPRINTK("\n");
+
+		if (neg_mode != 0) {
+			if (status & MII_PHY_LINKED)
+				emac_phy->state = PHY_LINKED;
+			else
+				emac_phy->state = PHY_LINK_WAIT;
+		}
+
+		/* Set the phy speed and duplex mode */
+		emac_phy->speed =
+		    (neg_mode & (MII_NWAY_FD100 | MII_NWAY_HD100)) ? 100 : 10;
+		emac_phy->duplex =
+		    (neg_mode & (MII_NWAY_FD100 | MII_NWAY_FD10)) ?
+				PHY_DUPLEX_FULL : PHY_DUPLEX_HALF;
+	} else {
+
+		if (emac_phy->timeout)
+			--emac_phy->timeout;
+		else
+			/*
+			 * Timed Out for NWAY to start - very unlikely
+			 * condition, back to Found
+			 */
+			emac_mdio_phy_timeout();
+	}
+}
+
+/* PHY state machine : Link Wait state handler */
+static void emac_mdio_linkwait_state(void)
+{
+	unsigned int status;
+
+	/* Check if nway negotiation complete */
+	status = emac_mdio_read(emac_phy->phy_addr, PHY_STATUS_REG);
+	if (status & MII_PHY_LINKED) {
+		emac_phy->state = PHY_LINKED;
+		emac_phy->state_change = 1;
+	} else {
+		if (emac_phy->timeout)
+			--emac_phy->timeout;
+		else
+			/*
+			 * Timed Out for link - very unlikely condition,
+			 * back to Found
+			 */
+			emac_mdio_phy_timeout();
+	}
+}
+
+/* PHY state machine : Linked handler */
+static void emac_mdio_linked_state(void)
+{
+	if (MDIO_REG_READ(MDIO_LINK) & (1 << emac_phy->phy_addr))
+		return;		/* do nothing if already linked */
+
+	/* If not linked, move mode to nway down or waiting for link */
+	emac_phy->state_change = 1;
+	if (emac_phy->phy_mode & NWAY_AUTO) {
+		emac_phy->state = PHY_NWAY_WAIT;
+		emac_phy->timeout = PHY_NWDN_TIMEOUT;
+	} else {
+		emac_phy->state = PHY_LINK_WAIT;
+		emac_phy->timeout = PHY_LINK_TIMEOUT;
+	}
+}
+
+/* PHY state machine : Loopback handler */
+static void emac_mdio_loopback_state(void)
+{
+}
+
+/* PHY state machine : Default handler */
+static void emac_mdio_default_state(void)
+{
+	/* Awaiting a init call */
+	emac_phy->state_change = 1;
+}
+
+/* Detailed PHY dump for debug */
+static void emac_mdio_phy_dump(void)
+{
+	unsigned int status;
+
+	DPRINTK("\n");
+	DPRINTK("PHY Addr/Num=%d, PHY State=%s, Speed=%d, Duplex=%d\n",
+		emac_phy->phy_addr, phy_state_str[emac_phy->state],
+		emac_phy->speed, emac_phy->duplex);
+
+	/* 0: Control register */
+	status = emac_mdio_read(emac_phy->phy_addr, PHY_CONTROL_REG);
+	DPRINTK("PhyControl: %04X, Loopback=%s, Speed=%s, Duplex=%s\n",
+		status,
+		status & MII_PHY_LOOP ? "On" : "Off",
+		status & MII_PHY_100 ? "100" : "10",
+		status & MII_PHY_FD ? "Full" : "Half");
+
+	/* 1: Status register */
+	status = emac_mdio_read(emac_phy->phy_addr, PHY_STATUS_REG);
+	DPRINTK("PhyStatus: %04X, AutoNeg=%s, Link=%s\n",
+		status,
+		status & MII_NWAY_COMPLETE ? "Complete" : "NotComplete",
+		status & MII_PHY_LINKED ? "Up" : "Down");
+
+	/* 4: Auto Negotiation Advertisement register */
+	status = emac_mdio_read(emac_phy->phy_addr, NWAY_ADVERTIZE_REG);
+	DPRINTK("PhyMyCapability: %04X, 100FD=%s, 100HD=%s, 10FD=%s, 10HD=%s\n",
+		status,
+		status & MII_NWAY_FD100 ? "Yes" : "No",
+		status & MII_NWAY_HD100 ? "Yes" : "No",
+		status & MII_NWAY_FD10 ? "Yes" : "No",
+		status & MII_NWAY_HD10 ? "Yes" : "No");
+
+	/* 5: Auto Negotiation Advertisement register */
+	status = emac_mdio_read(emac_phy->phy_addr, NWAY_REMADVERTISE_REG);
+	DPRINTK("PhyPartnerCapability: %04X, 100FD=%s,"
+		" 100HD=%s, 10FD=%s, 10HD=%s\n",
+	     status, status & MII_NWAY_FD100 ? "Yes" : "No",
+	     status & MII_NWAY_HD100 ? "Yes" : "No",
+	     status & MII_NWAY_FD10 ? "Yes" : "No",
+	     status & MII_NWAY_HD10 ? "Yes" : "No");
+}
+
+/* emac_mdio_tick is called every 10 mili seconds to process Phy states */
+int emac_mdio_tick(void)
+{
+	switch (emac_phy->state) {
+	case PHY_INIT:
+		emac_mdio_init_state();
+		break;
+	case PHY_FINDING:
+		emac_mdio_finding_state();
+		break;
+	case PHY_FOUND:
+		emac_mdio_found_state();
+		break;
+	case PHY_NWAY_START:
+		emac_mdio_nwaystart_state();
+		break;
+	case PHY_NWAY_WAIT:
+		emac_mdio_nwaywait_state();
+		break;
+	case PHY_LINK_WAIT:
+		emac_mdio_linkwait_state();
+		break;
+	case PHY_LINKED:
+		emac_mdio_linked_state();
+		break;
+	case PHY_LOOPBACK:
+		emac_mdio_loopback_state();
+		break;
+	default:
+		emac_mdio_default_state();
+		break;
+	}
+
+	/* Return state change to user */
+	if (emac_phy->state_change) {
+		emac_mdio_phy_dump();
+		emac_phy->state_change = 0;
+		return 1;
+	}
+	return 0;
+}
Index: 2.6.24-rc8.ether/drivers/net/arm/davinci_emac_phy.h
===================================================================
--- /dev/null
+++ 2.6.24-rc8.ether/drivers/net/arm/davinci_emac_phy.h
@@ -0,0 +1,106 @@
+/*
+ * linux/drivers/net/davinci_emac_phy.h
+ *
+ * Copyright (C) 2006 Texas Instruments.
+ * Copyright (C) MontaVista Software, Inc. <source@...sta.com>
+ *
+ * This file is licensed under the terms of the
+ * GNU General Public License version 2. This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ *
+ * ----------------------------------------------------------------------------
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * ----------------------------------------------------------------------------
+ * Modifications:
+ *  HISTORY:
+ *  Date      Modifier         Ver    Notes
+ *  01Jan01 Denis, Bill             Original
+ *  27Mar02 Michael Hanrahan Original (modified from emacmdio.h)
+ *  04Apr02 Michael Hanrahan Added Interrupt Support
+ *  07Dec06 Paul Bartholomew Added PHY_DUPLEX_* defines
+ */
+#ifndef _DAVINCI_EMAC_PHY_H_
+#define _DAVINCI_EMAC_PHY_H_
+
+/* phy mode values  */
+#define NWAY_AUTOMDIX       (1<<16)
+#define NWAY_FD1000         (1<<13)
+#define NWAY_HD1000         (1<<12)
+#define NWAY_NOPHY          (1<<10)
+#define NWAY_LPBK           (1<<9)
+#define NWAY_FD100          (1<<8)
+#define NWAY_HD100          (1<<7)
+#define NWAY_FD10           (1<<6)
+#define NWAY_HD10           (1<<5)
+#define NWAY_AUTO           (1<<0)
+
+/* phy duplex values */
+#define	PHY_DUPLEX_AUTO		0	/* Auto Negotiate */
+#define	PHY_DUPLEX_UNKNOWN	1	/* Unknown */
+#define	PHY_DUPLEX_HALF		2	/* Half Duplex */
+#define	PHY_DUPLEX_FULL		3	/* Full Duplex */
+
+/*
+ * Tic() return values
+ */
+
+#define _MIIMDIO_MDIXFLIP (1<<28)
+
+#define _AUTOMDIX_DELAY_MIN  80	/* milli-seconds */
+#define _AUTOMDIX_DELAY_MAX 200	/* milli-seconds */
+
+/* Get module version */
+void emac_mdio_get_ver(unsigned int mdio_base, unsigned int *module_id,
+		       unsigned int *rev_major, unsigned int *rev_minor);
+
+/* Initialize mdio module */
+int emac_mdio_init(unsigned int mdio_base,
+		   unsigned int inst,
+		   unsigned int phy_mask,
+		   unsigned int mlink_mask,
+		   unsigned int mdio_bus_freq,
+		   unsigned int mdio_clock_freq, unsigned int verbose);
+
+/* Set PHY mode - autonegotiation or any other */
+void emac_mdio_set_phy_mode(unsigned int phy_mode);
+
+/* Get linked status - check if link is on - 1=link on, 0=link off */
+int emac_mdio_is_linked(void);
+
+/* Get speed - 10 / 100 Mbps */
+int emac_mdio_get_speed(void);
+
+/* Get duplex - 2=full duplex, 1=half duplex */
+int emac_mdio_get_duplex(void);
+
+/* Get Phy number/address */
+int emac_mdio_get_phy_num(void);
+
+/* Check if loopback enabled on phy */
+int emac_mdio_is_loopback(void);
+
+/* Read from a phy register via mdio interface */
+unsigned int emac_mdio_read(unsigned int phy_addr, unsigned int phy_reg);
+
+/* Write to a phy register via mdio interface */
+void emac_mdio_write(unsigned int phy_addr, unsigned int phy_reg,
+		     unsigned int phy_data);
+
+/* MDIO tick function - to be called every 10 mSecs */
+int emac_mdio_tick(void);
+
+#endif				/* _DAVINIC_EMAC_PHY_H_ */
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ