[U-Boot] [PATCH v3] Gbe Controller driver support for kirkwood SOCs

Prafulla Wadaskar prafulla at marvell.com
Tue May 19 00:00:58 CEST 2009


Contributors:
Yotam Admon <yotam at marvell.com>
Michael Blostein <michaelbl at marvell.com

Reviewed by: Ronen Shitrit <rshitrit at marvell.com>
Signed-off-by: Prafulla Wadaskar <prafulla at marvell.com>
---
Change log:
v2: entire rewrite/restructure of v1
used small names for variable/function names
readl/writel used to access SoC registers
Soc registers accssed using pointers through net device struct
miiphy registration done for external smi read/write access
miiphy_link used to detect phy link presence
cleaned for cosmetic changes

v3: asm/arch/kirkwood.h included in c file
 
 cpu/arm926ejs/kirkwood/cpu.c |    8 +
 drivers/net/Makefile         |    1 +
 drivers/net/kirkwood_egiga.c | 1669 ++++++++++++++++++++++++++++++++++++++++++
 drivers/net/kirkwood_egiga.h |  828 +++++++++++++++++++++
 include/netdev.h             |    1 +
 5 files changed, 2507 insertions(+), 0 deletions(-)
 create mode 100644 drivers/net/kirkwood_egiga.c
 create mode 100644 drivers/net/kirkwood_egiga.h

diff --git a/cpu/arm926ejs/kirkwood/cpu.c b/cpu/arm926ejs/kirkwood/cpu.c
index c1e9146..b440008 100644
--- a/cpu/arm926ejs/kirkwood/cpu.c
+++ b/cpu/arm926ejs/kirkwood/cpu.c
@@ -295,3 +295,11 @@ int arch_misc_init(void)
 	return 0;
 }
 #endif /* CONFIG_ARCH_MISC_INIT */
+
+#ifdef CONFIG_KIRKWOOD_EGIGA
+int cpu_eth_init(bd_t *bis)
+{
+	kirkwood_egiga_initialize(bis);
+	return 0;
+}
+#endif
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index a360a50..f0c5654 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -40,6 +40,7 @@ COBJS-$(CONFIG_ENC28J60) += enc28j60.o
 COBJS-$(CONFIG_FSLDMAFEC) += fsl_mcdmafec.o mcfmii.o
 COBJS-$(CONFIG_GRETH) += greth.o
 COBJS-$(CONFIG_INCA_IP_SWITCH) += inca-ip_sw.o
+COBJS-$(CONFIG_KIRKWOOD_EGIGA) += kirkwood_egiga.o
 COBJS-$(CONFIG_DRIVER_KS8695ETH) += ks8695eth.o
 COBJS-$(CONFIG_DRIVER_LAN91C96) += lan91c96.o
 COBJS-$(CONFIG_MACB) += macb.o
diff --git a/drivers/net/kirkwood_egiga.c b/drivers/net/kirkwood_egiga.c
new file mode 100644
index 0000000..d9b295a
--- /dev/null
+++ b/drivers/net/kirkwood_egiga.c
@@ -0,0 +1,1669 @@
+/*
+ * (C) Copyright 2009
+ * Marvell Semiconductor <www.marvell.com>
+ * Prafulla Wadaskar <prafulla at marvell.com>
+ *
+ * (C) Copyright 2003
+ * Ingo Assmus <ingo.assmus at keymile.com>
+ *
+ * based on - Driver for MV64360X ethernet ports
+ * Copyright (C) 2002 rabeeh at galileo.co.il
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ */
+
+#include <common.h>
+#include <net.h>
+#include <malloc.h>
+#include <miiphy.h>
+#include <asm/errno.h>
+#include <asm/types.h>
+#include <asm/byteorder.h>
+
+/* In case SRAM is cache coherent or non-cacheable */
+#define CONFIG_NOT_COHERENT_CACHE
+#define D_CACHE_FLUSH_LINE(addr, offset) ;
+#define CPU_PIPE_FLUSH	{ __asm__ __volatile__ ("nop;nop;nop;nop;nop;nop;nop");}
+
+#include "kirkwood_egiga.h"
+
+/*
+ * smi_reg_read - Read from ethernet phy register.
+ *
+ * INPUT:
+ * @phy_adr - Phy address.
+ * @reg_ofs - Phy register offset.
+ *
+ * This function reads ethernet phy register.
+ * REturns 16bit phy register value, or 0xffff on error
+ */
+int smi_reg_read(char *devname, u8 phy_adr, u8 reg_ofs, u16 * data)
+{
+	struct eth_device *dev = eth_get_dev_by_name(devname);
+	struct kwgbe_device *dkwgbe = to_dkwgbe(dev);
+	struct kwgbe_registers *regs = dkwgbe->regs;
+	u32 smi_reg;
+	volatile u32 timeout;
+
+	/* check to read parameters */
+	if (phy_adr == 0xEE && reg_ofs == 0xEE) {
+		data = (void *)(0x00ff & KWGBEREG_RD(regs->phyadr));
+		return 0;
+	}
+	/* check parameters */
+	if ((phy_adr << KWGBE_PHY_SMI_DEV_ADDR_OFFS) &
+	    ~KWGBE_PHY_SMI_DEV_ADDR_MASK) {
+		printf("Illegal PHY device address %d\n", phy_adr);
+		return -EFAULT;
+	}
+	if ((reg_ofs << KWGBE_SMI_REG_ADDR_OFFS) & ~KWGBE_SMI_REG_ADDR_MASK) {
+		printf("Illegal PHY register offset %d\n", reg_ofs);
+		return -EFAULT;
+	}
+
+	timeout = KWGBE_PHY_SMI_TIMEOUT;
+	/* wait till the SMI is not busy */
+	do {
+		/* read smi register */
+		smi_reg = KWGBEREG_RD(regs->smi);
+		if (timeout-- == 0) {
+			printf("SMI busy timeout\n");
+			return -EFAULT;
+		}
+	} while (smi_reg & KWGBE_PHY_SMI_BUSY_MASK);
+
+	/* fill the phy address and regiser offset and read opcode */
+	smi_reg =
+	    (phy_adr << KWGBE_PHY_SMI_DEV_ADDR_OFFS) | (reg_ofs <<
+							KWGBE_SMI_REG_ADDR_OFFS)
+	    | KWGBE_PHY_SMI_OPCODE_READ;
+
+	/* write the smi register */
+	KWGBEREG_WR(regs->smi, smi_reg);
+
+	/*wait till readed value is ready */
+	timeout = KWGBE_PHY_SMI_TIMEOUT;
+	do {
+		/* read smi register */
+		smi_reg = KWGBEREG_RD(regs->smi);
+		if (timeout-- == 0) {
+			printf("SMI read-valid timeout\n");
+			return -EFAULT;
+		}
+	} while (!(smi_reg & KWGBE_PHY_SMI_READ_VALID_MASK));
+
+	/* Wait for the data to update in the SMI register */
+	for (timeout = 0; timeout < KWGBE_PHY_SMI_TIMEOUT; timeout++) ;
+
+	*data = (u16) (KWGBEREG_RD(regs->smi) & KWGBE_PHY_SMI_DATA_MASK);
+
+	debug("Reg(phyadr %d, off %d) Phy-value = %04x\n", phy_adr,
+	      reg_ofs, *data);
+
+	return 0;
+}
+
+/*
+ * smi_reg_write - Write to ethernet phy register.
+ *
+ * @phy_adr - Phy address.
+ * @reg_ofs - Phy register offset.
+ * @data    - 16bit data.
+ *
+ * This function write to ethernet phy register.
+ * Returns 0 if write succeed, -EINVAL on bad parameters , MV_ERROR on error .
+ * -ETIME on timeout
+ */
+int smi_reg_write(char *devname, u8 phy_adr, u8 reg_ofs, u16 data)
+{
+	struct eth_device *dev = eth_get_dev_by_name(devname);
+	struct kwgbe_device *dkwgbe = to_dkwgbe(dev);
+	struct kwgbe_registers *regs = dkwgbe->regs;
+	u32 smi_reg;
+	volatile u32 timeout;
+
+	/* check parameters */
+	if ((phy_adr << KWGBE_PHY_SMI_DEV_ADDR_OFFS) &
+	    ~KWGBE_PHY_SMI_DEV_ADDR_MASK) {
+		printf("Illegal phy address\n");
+		return -EINVAL;
+	}
+	if ((reg_ofs << KWGBE_SMI_REG_ADDR_OFFS) & ~KWGBE_SMI_REG_ADDR_MASK) {
+		printf("Illegal register offset\n");
+		return -EINVAL;
+	}
+
+	/* wait till the SMI is not busy */
+	timeout = KWGBE_PHY_SMI_TIMEOUT;
+	do {
+		/* read smi register */
+		smi_reg = KWGBEREG_RD(regs->smi);
+		if (timeout-- == 0) {
+			printf("SMI busy timeout\n");
+			return -ETIME;
+		}
+	} while (smi_reg & KWGBE_PHY_SMI_BUSY_MASK);
+
+	/* fill the phy address and regiser offset and write opcode and data */
+	smi_reg = (data << KWGBE_PHY_SMI_DATA_OFFS);
+	smi_reg |=
+	    (phy_adr << KWGBE_PHY_SMI_DEV_ADDR_OFFS) | (reg_ofs <<
+							KWGBE_SMI_REG_ADDR_OFFS);
+	smi_reg &= ~KWGBE_PHY_SMI_OPCODE_READ;
+
+	/* write the smi register */
+	KWGBEREG_WR(regs->smi, smi_reg);
+
+	return 0;
+}
+
+static int egiga_free_tx_rings(struct eth_device *dev)
+{
+	struct kwgbe_device *dkwgbe = to_dkwgbe(dev);
+	struct kwgbe_portinfo *portinfo = &dkwgbe->portinfo;
+	struct kwgbe_registers *regs = dkwgbe->regs;
+
+	u32 queue;
+	volatile struct kwgbe_tx_dscr *p_tx_curr_desc;
+
+	/* Stop Tx Queues */
+	KWGBEREG_WR(regs->tqc, 0x0000ff00);
+
+	/* Free TX rings */
+	debug("Clearing previously allocated TX queues... \n");
+	for (queue = 0; queue < KW_TXQ_NO; queue++) {
+		/* Free on TX rings */
+		for (p_tx_curr_desc = portinfo->p_tx_desc_area_base[queue];
+		     ((u32) p_tx_curr_desc <=
+		      (u32) portinfo->p_tx_desc_area_base[queue] +
+		      portinfo->tx_desc_area_size[queue]);
+		     p_tx_curr_desc =
+		     (struct kwgbe_tx_dscr *)((u32) p_tx_curr_desc +
+					      TX_DESC_ALIGNED_SIZE)) {
+			/* this is inside for loop */
+			if (p_tx_curr_desc->retinfo != 0) {
+				p_tx_curr_desc->retinfo = 0;
+				debug("freed\n");
+			}
+		}
+		debug("Done\n");
+	}
+	return 0;
+}
+
+static int egiga_free_rx_rings(struct eth_device *dev)
+{
+	struct kwgbe_device *dkwgbe = to_dkwgbe(dev);
+	struct kwgbe_portinfo *portinfo = &dkwgbe->portinfo;
+	struct kwgbe_registers *regs = dkwgbe->regs;
+
+	u32 queue;
+	volatile struct kwgbe_rx_dscr *p_rx_curr_desc;
+
+	/* Stop RX Queues */
+	KWGBEREG_WR(regs->rqc, 0x0000ff00);
+
+	/* Free RX rings */
+	debug("Clearing previously allocated RX queues...\n");
+	for (queue = 0; queue < KW_RXQ_NO; queue++) {
+		/* Free preallocated skb's on RX rings */
+		for (p_rx_curr_desc = portinfo->p_rx_desc_area_base[queue];
+		     (((u32) p_rx_curr_desc <
+		       ((u32) portinfo->p_rx_desc_area_base[queue] +
+			portinfo->rx_desc_area_size[queue])));
+		     p_rx_curr_desc =
+		     (struct kwgbe_rx_dscr *)((u32) p_rx_curr_desc +
+					      RX_DESC_ALIGNED_SIZE)) {
+			if (p_rx_curr_desc->retinfo != 0) {
+				p_rx_curr_desc->retinfo = 0;
+				debug("freed\n");
+			}
+		}
+		debug("Done\n");
+	}
+	return 0;
+}
+
+static void phy_set_addr(struct kwgbe_registers *regs, int phy_addr)
+{
+	KWGBEREG_WR(regs->phyadr, phy_addr);
+}
+
+#ifdef  UPDATE_STATS_BY_SOFTWARE
+/*
+ * egiga_print_stat
+ *
+ * Update the statistics structure in the private data structure
+ *
+ * Input : pointer to ethernet interface network device structure
+ * Output : N/A
+ */
+static void egiga_print_stat(struct eth_device *dev)
+{
+	struct kwgbe_device *dkwgbe = to_dkwgbe(dev);
+	struct egiga_priv *portpriv = &dkwgbe->portpriv;
+	struct net_device_stats *stats = &portpriv->stats;
+
+	/* These are false updates */
+	printf("\n### Network statistics: ###\n");
+	printf("--------------------------\n");
+	printf(" Packets received:		%d\n", stats->rx_packets);
+	printf(" Packets send:			%d\n", stats->tx_packets);
+	printf(" Received bytes:		%lld\n", stats->rx_bytes);
+	printf(" Send bytes:			%lld\n", stats->tx_bytes);
+	if (stats->rx_errors != 0)
+		printf(" Rx Errors:			%d\n",
+		       stats->rx_errors);
+	if (stats->rx_dropped != 0)
+		printf(" Rx dropped (CRC Errors):	%d\n",
+		       stats->rx_dropped);
+	if (stats->multicast != 0)
+		printf(" Rx mulicast frames:		%d\n",
+		       stats->multicast);
+	if (stats->collisions != 0)
+		printf(" No. of collisions:		%d\n",
+		       stats->collisions);
+	if (stats->rx_length_errors != 0)
+		printf(" Rx length errors:		%d\n",
+		       stats->rx_length_errors);
+}
+#endif
+
+/*
+ * kwgbe_stop
+ *
+ * This function is used when closing the network device.
+ * It updates the hardware,
+ * release all memory that holds buffers and descriptors and release the IRQ.
+ * Input : a pointer to the device structure
+ * Output : zero if success , nonzero if fails
+ */
+int kwgbe_stop(struct eth_device *dev)
+{
+	struct kwgbe_device *dkwgbe = to_dkwgbe(dev);
+	struct kwgbe_registers *regs = dkwgbe->regs;
+
+	/* Disable all gigE address decoder */
+	KWGBEREG_WR(regs->bare, 0x3f);
+
+	egiga_free_tx_rings(dev);
+	egiga_free_rx_rings(dev);
+
+	port_reset(regs);
+	/* Disable ethernet port interrupts */
+	KWGBEREG_WR(regs->ic, 0);
+	KWGBEREG_WR(regs->ice, 0);
+	/* Mask RX buffer and TX end interrupt */
+	KWGBEREG_WR(regs->pim, 0);
+	/* Mask phy and link status changes interrupts */
+	KWGBEREG_WR(regs->peim, 0);
+
+	/* Print Network statistics */
+#ifdef  UPDATE_STATS_BY_SOFTWARE
+	/*
+	 * Print statistics (only if ethernet is running),
+	 * then zero all the stats fields in memory
+	 */
+	if (portpriv->running == MAGIC_KWGBE_RUNNING) {
+		portpriv->running = 0;
+		egiga_print_stat(dev);
+	}
+	memset(&portpriv->stats, 0, sizeof(struct net_device_stats));
+#endif
+	debug("Ethernet stopped ...\n");
+	return 0;
+}
+
+/*
+ * clear_mib_counters - Clear all MIB counters
+ *
+ * This function clears all MIB counters of a specific ethernet port.
+ * A read from the MIB counter will reset the counter.
+ *
+ * OUTPUT: After reading all MIB counters, the counters resets.
+ * RETURN: MIB counter value.
+ */
+static void clear_mib_counters(u32 mibc)
+{
+	u32 i = mibc + 0x80;
+	u32 dummy;
+
+	/* Perform dummy reads from MIB counters */
+	for (; mibc < i; mibc += 4) {
+		dummy = readl(mibc);
+	}
+}
+
+/*
+ * egiga_update_stat
+ *
+ * Update the statistics structure in the private data structure
+ *
+ * Input : pointer to ethernet interface network device structure
+ * Output : N/A
+ */
+static void egiga_update_stat(struct eth_device *dev)
+{
+	struct kwgbe_device *dkwgbe = to_dkwgbe(dev);
+	struct egiga_priv *portpriv = &dkwgbe->portpriv;
+	struct net_device_stats *stats = &portpriv->stats;
+	struct mib_counters *mibc = &dkwgbe->regs->mibc;
+
+	/* These are false updates */
+	stats->rx_packets += KWGBEREG_RD(mibc->good_frames_received);
+	stats->tx_packets += KWGBEREG_RD(mibc->good_frames_sent);
+	stats->rx_bytes += KWGBEREG_RD(mibc->good_octets_received);
+	stats->tx_bytes += KWGBEREG_RD(mibc->good_octets_sent);
+	stats->rx_errors += KWGBEREG_RD(mibc->mac_receive_error);
+	/* Rx dropped is for received packet with CRC error */
+	stats->rx_dropped += KWGBEREG_RD(mibc->bad_crc_event);
+	stats->multicast += KWGBEREG_RD(mibc->multicast_frames_received);
+	stats->collisions +=
+	    KWGBEREG_RD(mibc->collision) + KWGBEREG_RD(mibc->late_collision);
+	stats->rx_length_errors +=
+	    KWGBEREG_RD(mibc->undersize_received) +
+	    KWGBEREG_RD(mibc->oversize_received);
+}
+
+/*
+ * egiga_get_stats
+ *
+ * Returns a pointer to the interface statistics.
+ *
+ * Input : dev - a pointer to the required interface
+ * Output : a pointer to the interface's statistics
+ */
+static struct net_device_stats *egiga_get_stats(struct eth_device *dev)
+{
+	struct kwgbe_device *dkwgbe = to_dkwgbe(dev);
+	struct egiga_priv *portpriv = &dkwgbe->portpriv;
+
+	egiga_update_stat(dev);
+	return &portpriv->stats;
+}
+
+/*
+ * set_access_control - Config address decode parameters for Ethernet unit
+ *
+ * This function configures the address decode parameters for the Gigabit
+ * Ethernet Controller according the given parameters struct.
+ *
+ * @regs	Register struct pointer.
+ * @param	Address decode parameter struct.
+ */
+static void set_access_control(struct kwgbe_registers *regs,
+			       struct kwgbe_winparam *param)
+{
+	u32 access_prot_reg;
+
+	/* Set access control register */
+	access_prot_reg = KWGBEREG_RD(regs->epap);
+	access_prot_reg &= (~(3 << (param->win * 2)));	/* clear window permission */
+	access_prot_reg |= (param->access_ctrl << (param->win * 2));
+	KWGBEREG_WR(regs->epap, access_prot_reg);
+
+	/* Set window Size reg (SR) */
+	KWGBEREG_WR(regs->barsz[param->win].size,
+		    (((param->size / 0x10000) - 1) << 16));
+
+	/* Set window Base address reg (BA) */
+	KWGBEREG_WR(regs->barsz[param->win].bar,
+		    (param->target | param->attrib | param->base_addr));
+	/* High address remap reg (HARR) */
+	if (param->win < 4)
+		KWGBEREG_WR(regs->ha_remap[param->win], param->high_addr);
+
+	/* Base address enable reg (BARER) */
+	if (param->enable == 1)
+		KWGBEREG_BITS_RESET(regs->bare, (1 << param->win));
+	else
+		KWGBEREG_BITS_SET(regs->bare, (1 << param->win));
+}
+
+static void set_dram_access(struct kwgbe_registers *regs)
+{
+	struct kwgbe_winparam win_param;
+	int i;
+
+	for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) {
+		/* Set access parameters for DRAM bank i */
+		win_param.win = i;	/* Use Ethernet window i */
+		win_param.target = KWGBE_TARGET_DRAM;	/* Window target - DDR  */
+		win_param.access_ctrl = EWIN_ACCESS_FULL;	/* Enable full access */
+		win_param.high_addr = 0;
+		/* Get bank base */
+		win_param.base_addr = kw_sdram_bar(i);
+		win_param.size = kw_sdram_bs(i);	/* Get bank size */
+		if (win_param.size == 0)
+			win_param.enable = 0;
+		else
+			win_param.enable = 1;	/* Enable the access */
+		switch (i) {
+		case 0:
+			/* Enable DRAM bank 0  */
+			win_param.attrib = EBAR_ATTR_DRAM_CS0;
+			break;
+		case 1:
+			/* Enable DRAM bank 1  */
+			win_param.attrib = EBAR_ATTR_DRAM_CS1;
+			break;
+		case 2:
+			/* Enable DRAM bank 2  */
+			win_param.attrib = EBAR_ATTR_DRAM_CS2;
+			break;
+		case 3:
+			/* Enable DRAM bank 3  */
+			win_param.attrib = EBAR_ATTR_DRAM_CS3;
+			break;
+		default:
+			/* invalide bank, disable access */
+			win_param.enable = 0;
+			win_param.attrib = 0;
+			break;
+		}
+#ifndef CONFIG_NOT_COHERENT_CACHE
+		win_param.attrib |= EBAR_ATTR_DRAM_CACHE_COHERENCY_WB;
+#endif
+		/* Set the access control for address window (EPAPR) READ & WRITE */
+		set_access_control(regs, &win_param);
+	}
+}
+
+/*
+ * port_init_mac_tables - Clear all entrance in the UC, SMC and OMC tables
+ *
+ * Go through all the DA filter tables (Unicast, Special Multicast & Other
+ * Multicast) and set each entry to 0.
+ *
+ */
+static void port_init_mac_tables(struct kwgbe_registers *regs)
+{
+	int table_index;
+
+	/* Clear DA filter unicast table (Ex_dFUT) */
+	for (table_index = 0; table_index < 4; ++table_index)
+		KWGBEREG_WR(regs->dfut[table_index], 0);
+
+	for (table_index = 0; table_index < 64; ++table_index) {
+		/* Clear DA filter special multicast table (Ex_dFSMT) */
+		KWGBEREG_WR(regs->dfsmt[table_index], 0);
+		/* Clear DA filter other multicast table (Ex_dFOMT) */
+		KWGBEREG_WR(regs->dfomt[table_index], 0);
+	}
+}
+
+/*
+ * port_init - Initialize the Ethernet port driver
+ *
+ * @p_gbe_pctrl - ptr to Ethernet port control struct
+ *
+ * This function prepares the ethernet port to start its activity:
+ * 1) Completes the ethernet port driver struct initialization toward port
+ *     start routine.
+ * 2) Resets the device to a quiescent state in case of warm reboot.
+ * 3) Enable SDMA access to all four DRAM banks as well as internal SRAM.
+ * 4) Clean MAC tables. The reset status of those tables is unknown.
+ * 5) Set PHY address.
+ * Note: Call this routine prior to port_start routine and after setting
+ *  user values in the user fields of Ethernet port control struct (i.e.
+ *  port_phy_addr).
+ *
+ */
+static void port_init(struct kwgbe_device *dkwgbe)
+{
+	struct kwgbe_portinfo *p_gbe_pctrl = &dkwgbe->portinfo;
+	struct kwgbe_registers *regs = dkwgbe->regs;
+	int queue;
+
+	p_gbe_pctrl->port_config = PRT_CFG_VAL;
+	p_gbe_pctrl->port_config_extend = PORT_CFG_EXTEND_VALUE;
+	p_gbe_pctrl->port_sdma_config = PORT_SDMA_CFG_VALUE;
+	p_gbe_pctrl->port_serial_control = PORT_SERIAL_CONTROL_VALUE;
+
+	p_gbe_pctrl->port_rx_queue_command = 0;
+	p_gbe_pctrl->port_tx_queue_command = 0;
+
+	/* Stop RX Queues */
+	KWGBEREG_WR(regs->rqc, 0x0000ff00);
+
+	/* Clear the ethernet port interrupts */
+	KWGBEREG_WR(regs->ic, 0);
+	KWGBEREG_WR(regs->ice, 0);
+
+	/* Unmask RX buffer and TX end interrupt */
+	KWGBEREG_WR(regs->pim, INT_CAUSE_UNMASK_ALL);
+
+	/* Unmask phy and link status changes interrupts */
+	KWGBEREG_WR(regs->peim, INT_CAUSE_UNMASK_ALL_EXT);
+
+	/* Zero out SW structs */
+	for (queue = 0; queue < MAX_RXQ_NO; queue++) {
+		CURR_RFD_SET((struct kwgbe_rx_dscr *)0x00000000, queue);
+		USED_RFD_SET((struct kwgbe_rx_dscr *)0x00000000, queue);
+		p_gbe_pctrl->rx_resource_err[queue] = 0;
+	}
+
+	for (queue = 0; queue < MAX_TXQ_NO; queue++) {
+		CURR_TFD_SET((struct kwgbe_tx_dscr *)0x00000000, queue);
+		USED_TFD_SET((struct kwgbe_tx_dscr *)0x00000000, queue);
+		FIRST_TFD_SET((struct kwgbe_tx_dscr *)0x00000000, queue);
+		p_gbe_pctrl->tx_resource_err[queue] = 0;
+	}
+
+	port_reset(regs);
+	set_dram_access(regs);
+	port_init_mac_tables(regs);
+}
+
+/*
+ * port_start - Start the Ethernet port activity.
+ *
+ * This routine prepares the Ethernet port for Rx and Tx activity:
+ * 1. Initialize Tx and Rx Current Descriptor Pointer for each queue that
+ *     has been initialized a descriptor's ring (using kwgbe_init_tx_desc_ring
+ *     for Tx and kwgbe_init_rx_desc_ring for Rx)
+ * 2. Initialize and enable the Ethernet configuration port by writing to
+ *     the port's configuration and command registers.
+ * 3. Initialize and enable the SDMA by writing to the SDMA's
+ * configuration and command registers.
+ * After completing these steps, the ethernet port SDMA can starts to
+ * perform Rx and Tx activities.
+ *
+ * Note: Each Rx and Tx queue descriptor's list must be initialized prior
+ * to calling this function (use kwgbe_init_tx_desc_ring for Tx queues and
+ * kwgbe_init_rx_desc_ring for Rx queues).
+ *
+ * OUTPUT: Ethernet port is ready to receive and transmit.
+ *
+ * RETURN: 0 if the port PHY is not up. 1 otherwise.
+ */
+static void port_start(struct kwgbe_device *dkwgbe)
+{
+	struct kwgbe_portinfo *p_gbe_pctrl = &dkwgbe->portinfo;
+	struct kwgbe_registers *regs = dkwgbe->regs;
+	int queue;
+	volatile struct kwgbe_tx_dscr *p_tx_curr_desc;
+	volatile struct kwgbe_rx_dscr *p_rx_curr_desc;
+
+	/* Assignment of Tx CTRP of given queue */
+	for (queue = 0; queue < MAX_TXQ_NO; queue++) {
+		CURR_TFD_GET(p_tx_curr_desc, queue);
+		KWGBEREG_WR(regs->tcqdp[queue], (u32) p_tx_curr_desc);
+	}
+
+	/* Assignment of Rx CRDB of given queue */
+	for (queue = 0; queue < MAX_RXQ_NO; queue++) {
+		CURR_RFD_GET(p_rx_curr_desc, queue);
+		KWGBEREG_WR(regs->crdp[queue], (u32) p_rx_curr_desc);
+
+		if (p_rx_curr_desc != NULL)
+			/* Add the assigned Ethernet address to the port's address table */
+			port_uc_addr_set(regs, p_gbe_pctrl->port_mac_addr,
+					 queue);
+	}
+
+	/* Assign port configuration and command. */
+	KWGBEREG_WR(regs->pxc, p_gbe_pctrl->port_config);
+	KWGBEREG_WR(regs->pxcx, p_gbe_pctrl->port_config_extend);
+	KWGBEREG_WR(regs->psc0, p_gbe_pctrl->port_serial_control);
+	KWGBEREG_BITS_SET(regs->psc0, KWGBE_SERIAL_PORT_EN);
+
+	/* Assign port SDMA configuration */
+	KWGBEREG_WR(regs->sdc, p_gbe_pctrl->port_sdma_config);
+	KWGBEREG_WR(regs->tqx[0].qxttbc, 0x3fffffff);
+	KWGBEREG_WR(regs->tqx[0].tqxtbc, 0x03fffcff);
+	/* Turn off the port/queue bandwidth limitation */
+	KWGBEREG_WR(regs->pmtu, 0x0);
+
+	/* Enable port Rx. */
+	KWGBEREG_WR(regs->rqc, p_gbe_pctrl->port_rx_queue_command);
+
+	/* Set maximum receive buffer to 9700 bytes */
+	KWGBEREG_WR(regs->psc0,
+		    (0x5 << 17) | (KWGBEREG_RD(regs->psc0) & 0xfff1ffff));
+
+	/*
+	 * Set ethernet MTU for leaky bucket mechanism to 0 - this will
+	 * disable the leaky bucket mechanism .
+	 */
+	KWGBEREG_WR(regs->pmtu, 0);
+}
+
+/*
+ * port_uc_addr - This function Set the port unicast address table
+ *
+ * This function locates the proper entry in the Unicast table for the
+ * specified MAC nibble and sets its properties according to function
+ * parameters.
+ * This function add/removes MAC addresses from the port unicast address
+ * table.
+ *
+ * @uc_nibble	Unicast MAC Address last nibble.
+ * @queue	Rx queue number for this MAC address.
+ * @option      0 = Add, 1 = remove address.
+ *
+ * RETURN: 1 if output succeeded. 0 if option parameter is invalid.
+ */
+static int port_uc_addr(struct kwgbe_registers *regs, u8 uc_nibble,
+			enum kwgbe_q queue, int option)
+{
+	u32 unicast_reg;
+	u32 tbl_offset;
+	u32 reg_offset;
+
+	/* Locate the Unicast table entry */
+	uc_nibble = (0xf & uc_nibble);
+	tbl_offset = (uc_nibble / 4);	/* Register offset from unicast table base */
+	reg_offset = uc_nibble % 4;	/* Entry offset within the above register */
+
+	switch (option) {
+	case REJECT_MAC_ADDR:
+		/* Clear accepts frame bit at specified unicast DA table entry */
+		unicast_reg = KWGBEREG_RD(regs->dfut[tbl_offset]);
+		unicast_reg &= (0xFF << (8 * reg_offset));
+		KWGBEREG_WR(regs->dfut[tbl_offset], unicast_reg);
+		break;
+	case ACCEPT_MAC_ADDR:
+		/* Set accepts frame bit at unicast DA filter table entry */
+		unicast_reg = KWGBEREG_RD(regs->dfut[tbl_offset]);
+		unicast_reg &= (0xFF << (8 * reg_offset));
+		unicast_reg |= ((0x01 | (queue << 1)) << (8 * reg_offset));
+		KWGBEREG_WR(regs->dfut[tbl_offset], unicast_reg);
+		break;
+	default:
+		return 0;
+	}
+	return 1;
+}
+
+/*
+ * port_uc_addr_set - This function Set the port Unicast address.
+ *
+ * This function Set the port Ethernet MAC address.
+ *
+ * @p_addr	Address to be set
+ * @queue	Rx queue number for this MAC address.
+ *
+ * OUTPUT: Set MAC address low and high registers. also calls
+ * port_uc_addr() To set the unicast table with the proper info.
+ */
+static void port_uc_addr_set(struct kwgbe_registers *regs, u8 * p_addr,
+			     enum kwgbe_q queue)
+{
+	u32 mac_h;
+	u32 mac_l;
+
+	mac_l = (p_addr[4] << 8) | (p_addr[5]);
+	mac_h =
+	    (p_addr[0] << 24) | (p_addr[1] << 16) | (p_addr[2] << 8) |
+	    (p_addr[3] << 0);
+
+	KWGBEREG_WR(regs->macal, mac_l);
+	KWGBEREG_WR(regs->macah, mac_h);
+
+	/* Accept frames of this address */
+	port_uc_addr(regs, p_addr[5], queue, ACCEPT_MAC_ADDR);
+}
+
+/*
+ * port_reset - Reset Ethernet port
+ *
+ * This routine resets the chip by aborting any SDMA engine activity and
+ * clearing the MIB counters. The Receiver and the Transmit unit are in
+ * idle state after this command is performed and the port is disabled.
+ *
+ */
+static void port_reset(struct kwgbe_registers *regs)
+{
+	u32 reg_data, i;
+
+	/* Stop Tx port activity. Check port Tx activity. */
+	reg_data = KWGBEREG_RD(regs->tqc);
+
+	if (reg_data & 0xFF) {
+		/* Issue stop command for active channels only */
+		KWGBEREG_WR(regs->tqc, (reg_data << 8));
+
+		/* Wait for all Tx activity to terminate. */
+		do {
+			/* Check port cause register that all Tx queues are stopped */
+			reg_data = KWGBEREG_RD(regs->tqc);
+		}
+		while (reg_data & 0xFF);
+	}
+
+	/* Stop Rx port activity. Check port Rx activity. */
+	reg_data = KWGBEREG_RD(regs->rqc);
+
+	if (reg_data & 0xFF) {
+		/* Issue stop command for active channels only */
+		KWGBEREG_WR(regs->rqc, (reg_data << 8));
+
+		/* Wait for all Rx activity to terminate. */
+		do {
+			/* Check port cause register that all Rx queues are stopped */
+			reg_data = KWGBEREG_RD(regs->rqc);
+		}
+		while (reg_data & 0xFF);
+	}
+
+	/* Clear all MIB counters */
+	clear_mib_counters((u32) & regs->mibc);
+
+	/* Enable port in the Configuration Register */
+	KWGBEREG_BITS_RESET(regs->psc0, KWGBE_SERIAL_PORT_EN);
+	/* Set port of active in the Configuration Register */
+	KWGBEREG_BITS_RESET(regs->psc1, 1 << 4);
+#ifdef CONFIG_SYS_MII_MODE
+	/* Set MMI interface up */
+	KWGBEREG_BITS_RESET(regs->psc1, 1 << 3);
+#endif
+	for (i = 0; i < 4000; i++) ;
+	return;
+}
+
+/*
+ * kwgbe_init_rx_desc_ring - Curve a Rx chain desc list and buffer in memory.
+ *
+ * This function prepares a Rx chained list of descriptors and packet
+ * buffers in a form of a ring. The routine must be called after port
+ * initialization routine and before port start routine.
+ * The Ethernet SDMA engine uses CPU bus addresses to access the various
+ * devices in the system (i.e. DRAM). This function uses the ethernet
+ * struct 'virtual to physical' routine (set by the user) to set the ring
+ * with physical addresses.
+ *
+ * @rx_queue		Number of Rx queue.
+ * @rx_desc_num		Number of Rx descriptors
+ * @rx_buff_size	Size of Rx buffer
+ * @rx_desc_base_addr	Rx descriptors memory area base addr.
+ * @rx_buff_base_addr	Rx buffer memory area base addr.
+ *
+ * The routine updates the Ethernet port control struct with information
+ * regarding the Rx descriptors and buffers.
+ *
+ * RETURN:
+ * 0 if the given descriptors memory area is not aligned according to
+ * Ethernet SDMA specifications.
+ * 1 otherwise.
+ */
+static int kwgbe_init_rx_desc_ring(struct kwgbe_device *dkwgbe,
+				   enum kwgbe_q rx_queue,
+				   int rx_desc_num,
+				   int rx_buff_size,
+				   u32 rx_desc_base_addr, u32 rx_buff_base_addr)
+{
+	struct kwgbe_portinfo *p_gbe_pctrl = &dkwgbe->portinfo;
+	struct kwgbe_rx_dscr *p_rx_desc;
+	/* pointer to link with the last descriptor */
+	struct kwgbe_rx_dscr *p_rx_prev_desc;
+	u32 buffer_addr;
+	int ix;			/* a counter */
+
+	p_rx_desc = (struct kwgbe_rx_dscr *)rx_desc_base_addr;
+	p_rx_prev_desc = p_rx_desc;
+	buffer_addr = rx_buff_base_addr;
+
+	/* Rx desc Must be 4LW aligned (i.e. Descriptor_Address[3:0]=0000). */
+	if (rx_buff_base_addr & 0xF)
+		return 0;
+
+	/* Rx buffers are limited to 64K bytes and Minimum size is 8 bytes  */
+	if ((rx_buff_size < 8) || (rx_buff_size > RX_BUF_MXSZ))
+		return 0;
+
+	/* Rx buffers must be 64-bit aligned.       */
+	if ((rx_buff_base_addr + rx_buff_size) & 0x7)
+		return 0;
+
+	/* initialize the Rx descriptors ring */
+	for (ix = 0; ix < rx_desc_num; ix++) {
+		p_rx_desc->buf_size = rx_buff_size;
+		p_rx_desc->byte_cnt = 0x0000;
+		p_rx_desc->cmd_sts =
+		    KWGBE_BUFFER_OWNED_BY_DMA | KWGBE_RX_EN_INTERRUPT;
+		p_rx_desc->nxtdesc_p = ((u32) p_rx_desc) + RX_DESC_ALIGNED_SIZE;
+		p_rx_desc->buf_ptr = buffer_addr;
+		p_rx_desc->retinfo = 0x00000000;
+		D_CACHE_FLUSH_LINE(p_rx_desc, 0);
+		buffer_addr += rx_buff_size;
+		p_rx_prev_desc = p_rx_desc;
+		p_rx_desc = (struct kwgbe_rx_dscr *)
+		    ((u32) p_rx_desc + RX_DESC_ALIGNED_SIZE);
+	}
+
+	/* Closing Rx descriptors ring */
+	p_rx_prev_desc->nxtdesc_p = (rx_desc_base_addr);
+	D_CACHE_FLUSH_LINE(p_rx_prev_desc, 0);
+
+	/* Save Rx desc pointer to driver struct. */
+	CURR_RFD_SET((struct kwgbe_rx_dscr *)rx_desc_base_addr, rx_queue);
+	USED_RFD_SET((struct kwgbe_rx_dscr *)rx_desc_base_addr, rx_queue);
+
+	p_gbe_pctrl->p_rx_desc_area_base[rx_queue] =
+	    (struct kwgbe_rx_dscr *)rx_desc_base_addr;
+	p_gbe_pctrl->rx_desc_area_size[rx_queue] =
+	    rx_desc_num * RX_DESC_ALIGNED_SIZE;
+
+	p_gbe_pctrl->port_rx_queue_command |= (1 << rx_queue);
+
+	return 1;
+}
+
+/*
+ * kwgbe_init_tx_desc_ring - Curve a Tx chain desc list and buffer in memory.
+ *
+ * This function prepares a Tx chained list of descriptors and packet
+ * buffers in a form of a ring. The routine must be called after port
+ * initialization routine and before port start routine.
+ * The Ethernet SDMA engine uses CPU bus addresses to access the various
+ * devices in the system (i.e. DRAM). This function uses the ethernet
+ * struct 'virtual to physical' routine (set by the user) to set the ring
+ * with physical addresses.
+ *
+ * @p_gbe_pctrl		Ethernet Port Control srtuct ptr.
+ * @tx_queue		Number of Tx queue.
+ * @tx_desc_num		Number of Tx descriptors
+ * @tx_buff_size	Size of Tx buffer
+ * @tx_desc_base_addr	Tx descriptors memory area base addr.
+ * @tx_buff_base_addr	Tx buffer memory area base addr.
+ *
+ * The routine updates the Ethernet port control struct with information
+ * regarding the Tx descriptors and buffers.
+ *
+ * RETURN:
+ * 0 if the given descriptors memory area is not aligned according to
+ * Ethernet SDMA specifications.
+ * 1 otherwise.
+ */
+static int kwgbe_init_tx_desc_ring(struct kwgbe_device *dkwgbe,
+				   enum kwgbe_q tx_queue,
+				   int tx_desc_num,
+				   int tx_buff_size,
+				   u32 tx_desc_base_addr, u32 tx_buff_base_addr)
+{
+	struct kwgbe_portinfo *p_gbe_pctrl = &dkwgbe->portinfo;
+	struct kwgbe_tx_dscr *p_tx_desc;
+	struct kwgbe_tx_dscr *p_tx_prev_desc;
+	u32 buffer_addr;
+	int ix;			/* a counter */
+
+	/* save the first desc pointer to link with the last descriptor */
+	p_tx_desc = (struct kwgbe_tx_dscr *)tx_desc_base_addr;
+	p_tx_prev_desc = p_tx_desc;
+	buffer_addr = tx_buff_base_addr;
+
+	/* Tx desc Must be 4LW aligned (i.e. Descriptor_Address[3:0]=0000). */
+	if (tx_buff_base_addr & 0xF)
+		return 0;
+
+	/* Tx buffers are limited to 64K bytes and Minimum size is 8 bytes  */
+	if ((tx_buff_size > TX_BUF_MXSZ)
+	    || (tx_buff_size < TX_BUF_MNSZ))
+		return 0;
+
+	/* Initialize the Tx descriptors ring */
+	for (ix = 0; ix < tx_desc_num; ix++) {
+		p_tx_desc->byte_cnt = 0x0000;
+		p_tx_desc->l4i_chk = 0x0000;
+		p_tx_desc->cmd_sts = 0x00000000;
+		p_tx_desc->nxtdesc_p = ((u32) p_tx_desc) + TX_DESC_ALIGNED_SIZE;
+
+		p_tx_desc->buf_ptr = buffer_addr;
+		p_tx_desc->retinfo = 0x00000000;
+		D_CACHE_FLUSH_LINE(p_tx_desc, 0);
+		buffer_addr += tx_buff_size;
+		p_tx_prev_desc = p_tx_desc;
+		p_tx_desc = (struct kwgbe_tx_dscr *)
+		    ((u32) p_tx_desc + TX_DESC_ALIGNED_SIZE);
+
+	}
+	/* Closing Tx descriptors ring */
+	p_tx_prev_desc->nxtdesc_p = tx_desc_base_addr;
+	D_CACHE_FLUSH_LINE(p_tx_prev_desc, 0);
+	/* Set Tx desc pointer in driver struct. */
+	CURR_TFD_SET((struct kwgbe_tx_dscr *)tx_desc_base_addr, tx_queue);
+	USED_TFD_SET((struct kwgbe_tx_dscr *)tx_desc_base_addr, tx_queue);
+
+	/* Init Tx ring base and size parameters */
+	p_gbe_pctrl->p_tx_desc_area_base[tx_queue] =
+	    (struct kwgbe_tx_dscr *)tx_desc_base_addr;
+	p_gbe_pctrl->tx_desc_area_size[tx_queue] =
+	    (tx_desc_num * TX_DESC_ALIGNED_SIZE);
+
+	/* Add the queue to the list of Tx queues of this port */
+	p_gbe_pctrl->port_tx_queue_command |= (1 << tx_queue);
+
+	return 1;
+}
+
+/*
+ * b_copy - Copy bytes from source to destination
+ *
+ * This function supports the eight bytes limitation on Tx buffer size.
+ * The routine will zero eight bytes starting from the destination address
+ * followed by copying bytes from the source address to the destination.
+ *
+ * @src_addr		32 bit source address.
+ * @dst_add		32 bit destination address.
+ * @byte_count		Number of bytes to copy.
+ */
+static void b_copy(u32 src_addr, u32 dst_addr, int byte_count)
+{
+	/* Zero the dst_addr area */
+	*(u32 *) dst_addr = 0x0;
+
+	while (byte_count != 0) {
+		*(char *)dst_addr = *(char *)src_addr;
+		dst_addr++;
+		src_addr++;
+		byte_count--;
+	}
+}
+
+/*
+ * port_send - Send an Ethernet packet
+ *
+ * This routine send a given packet described by p_pktinfo parameter. It
+ * supports transmitting of a packet spaned over multiple buffers. The
+ * routine updates 'curr' and 'first' indexes according to the packet
+ * segment passed to the routine. In case the packet segment is first,
+ * the 'first' index is update. In any case, the 'curr' index is updated.
+ * If the routine get into Tx resource error it assigns 'curr' index as
+ * 'first'. This way the function can abort Tx process of multiple
+ * descriptors per packet.
+ *
+ * @tx_queue		Number of Tx queue.
+ * @p_pkt_info		User packet buffer ptr.
+ *
+ * OUTPUT: Tx ring 'curr' and 'first' indexes are updated.
+ *
+ * RETURN:
+ * KWGBE_QFULL in case of Tx resource error.
+ * KWGBE_ERROR in case the routine can not access Tx desc ring.
+ * KWGBE_QLAST_RESO if the routine uses the last Tx resource.
+ * KWGBE_OK otherwise.
+ */
+static enum kwgbe_fret_sts port_send(struct kwgbe_device *dkwgbe,
+				     enum kwgbe_q tx_queue,
+				     struct kwgbe_pktinf *p_pkt_info)
+{
+	struct kwgbe_portinfo *p_gbe_pctrl = &dkwgbe->portinfo;
+	struct kwgbe_registers *regs = dkwgbe->regs;
+	volatile struct kwgbe_tx_dscr *p_tx_desc_first;
+	volatile struct kwgbe_tx_dscr *p_tx_desc_curr;
+	volatile struct kwgbe_tx_dscr *p_tx_next_desc_curr;
+	volatile struct kwgbe_tx_dscr *p_tx_desc_used;
+	u32 command_status;
+
+#ifdef CONFIG_TX_PKT_DISPLAY
+	{
+		u16 pcnt = p_pkt_info->byte_cnt;
+		u8 *prnt = (u8 *) p_pkt_info->buf_ptr;
+		printf("cnt=%d,", pcnt);
+		while (pcnt) {
+			printf("%02x,", prnt[0]);
+			prnt++;
+			pcnt--;
+		}
+		printf(" pckend\n");
+	}
+#endif
+	/* Do not process Tx ring in case of Tx ring resource error */
+	if (p_gbe_pctrl->tx_resource_err[tx_queue] == 1)
+		return KWGBE_QFULL;
+
+	/* Get the Tx Desc ring indexes */
+	CURR_TFD_GET(p_tx_desc_curr, tx_queue);
+	USED_TFD_GET(p_tx_desc_used, tx_queue);
+
+	if (p_tx_desc_curr == NULL)
+		return KWGBE_ERROR;
+
+	/* The following parameters are used to save readings from memory */
+	p_tx_next_desc_curr = TX_NEXT_DESC_PTR(p_tx_desc_curr, tx_queue);
+	command_status =
+	    p_pkt_info->cmd_sts | KWGBE_ZERO_PADDING | KWGBE_GEN_CRC;
+
+	if (command_status & (KWGBE_TX_FIRST_DESC)) {
+		/* Update first desc */
+		FIRST_TFD_SET(p_tx_desc_curr, tx_queue);
+		p_tx_desc_first = p_tx_desc_curr;
+	} else {
+		FIRST_TFD_GET(p_tx_desc_first, tx_queue);
+		command_status |= KWGBE_BUFFER_OWNED_BY_DMA;
+	}
+
+	/*
+	 * Buffers with a payload smaller than 8 bytes must be aligned to 64-bit
+	 * boundary. We use the memory allocated for Tx descriptor. This memory
+	 * located in TX_BUF_OFFSET_IN_DESC offset within the Tx descriptor.
+	 */
+	if (p_pkt_info->byte_cnt <= 8) {
+		printf("You have failed in the < 8 bytes errata - fixme\n");
+		return KWGBE_ERROR;
+
+		p_tx_desc_curr->buf_ptr =
+		    (u32) p_tx_desc_curr + TX_BUF_OFFSET_IN_DESC;
+		b_copy(p_pkt_info->buf_ptr, p_tx_desc_curr->buf_ptr,
+		       p_pkt_info->byte_cnt);
+	} else
+		p_tx_desc_curr->buf_ptr = p_pkt_info->buf_ptr;
+
+	p_tx_desc_curr->byte_cnt = p_pkt_info->byte_cnt;
+	p_tx_desc_curr->retinfo = p_pkt_info->retinfo;
+
+	if (p_pkt_info->cmd_sts & (KWGBE_TX_LAST_DESC)) {
+		/* Set last desc with DMA ownership and interrupt enable. */
+		p_tx_desc_curr->cmd_sts = command_status |
+		    KWGBE_BUFFER_OWNED_BY_DMA | KWGBE_TX_EN_INTERRUPT;
+
+		if (p_tx_desc_curr != p_tx_desc_first)
+			p_tx_desc_first->cmd_sts |= KWGBE_BUFFER_OWNED_BY_DMA;
+
+		/* Flush CPU pipe */
+		D_CACHE_FLUSH_LINE((u32) p_tx_desc_curr, 0);
+		D_CACHE_FLUSH_LINE((u32) p_tx_desc_first, 0);
+		CPU_PIPE_FLUSH;
+
+		/* Apply send command */
+		KWGBEREG_WR(regs->tqc, (1 << tx_queue));
+		debug("packet xmitted\n");
+
+		/*
+		 * Finish Tx packet.
+		 * Update first desc in case of Tx resource error
+		 */
+		p_tx_desc_first = p_tx_next_desc_curr;
+		FIRST_TFD_SET(p_tx_desc_first, tx_queue);
+
+	} else {
+		p_tx_desc_curr->cmd_sts = command_status;
+		D_CACHE_FLUSH_LINE((u32) p_tx_desc_curr, 0);
+	}
+
+	/* Check for ring index overlap in the Tx desc ring */
+	if (p_tx_next_desc_curr == p_tx_desc_used) {
+		/* Update the current descriptor */
+		CURR_TFD_SET(p_tx_desc_first, tx_queue);
+
+		p_gbe_pctrl->tx_resource_err[tx_queue] = 1;
+		return KWGBE_QLAST_RESO;
+	} else {
+		/* Update the current descriptor */
+		CURR_TFD_SET(p_tx_next_desc_curr, tx_queue);
+		return KWGBE_OK;
+	}
+}
+
+/*
+ * tx_return_desc - Free all used Tx descriptors
+ *
+ * This routine returns the transmitted packet information to the caller.
+ * It uses the 'first' index to support Tx desc return in case a transmit
+ * of a packet spanned over multiple buffer still in process.
+ * In case the Tx queue was in "resource error" condition, where there are
+ * no available Tx resources, the function resets the resource error flag.
+ *
+ * @p_gbe_pctrl		Ethernet Port Control srtuct ptr.
+ * @tx_queue		Number of Tx queue.
+ * @p_pkt_info		User packet buffer ptr.
+ *
+ * OUTPUT:Tx ring 'first' and 'used' indexes are updated.
+ *
+ * RETURN:
+ * KWGBE_ERROR in case the routine can not access Tx desc ring.
+ * KWGBE_RETRY in case there is transmission in process.
+ * KWGBE_END_OF_JOB if the routine has nothing to release.
+ * KWGBE_OK otherwise.
+ */
+static enum kwgbe_fret_sts tx_return_desc(struct kwgbe_device *dkwgbe,
+					  enum kwgbe_q tx_queue,
+					  struct kwgbe_pktinf *p_pkt_info)
+{
+	struct kwgbe_portinfo *p_gbe_pctrl = &dkwgbe->portinfo;
+	volatile struct kwgbe_tx_dscr *p_tx_desc_used = NULL;
+	volatile struct kwgbe_tx_dscr *p_tx_desc_first = NULL;
+	u32 command_status;
+
+	/* Get the Tx Desc ring indexes */
+	USED_TFD_GET(p_tx_desc_used, tx_queue);
+	FIRST_TFD_GET(p_tx_desc_first, tx_queue);
+
+	/* Sanity check */
+	if (p_tx_desc_used == NULL)
+		return KWGBE_ERROR;
+
+	command_status = p_tx_desc_used->cmd_sts;
+
+	/* Still transmitting... */
+	if (command_status & (KWGBE_BUFFER_OWNED_BY_DMA)) {
+		D_CACHE_FLUSH_LINE((u32) p_tx_desc_used, 0);
+		return KWGBE_RETRY;
+	}
+
+	/* Stop release. About to overlap the current available Tx descriptor */
+	if ((p_tx_desc_used == p_tx_desc_first) &&
+	    (p_gbe_pctrl->tx_resource_err[tx_queue] == 0)) {
+		D_CACHE_FLUSH_LINE((u32) p_tx_desc_used, 0);
+		return KWGBE_END_OF_JOB;
+	}
+
+	/* Pass the packet information to the caller */
+	p_pkt_info->cmd_sts = command_status;
+	p_pkt_info->retinfo = p_tx_desc_used->retinfo;
+	p_tx_desc_used->retinfo = 0;
+
+	/* Update the next descriptor to release. */
+	USED_TFD_SET(TX_NEXT_DESC_PTR(p_tx_desc_used, tx_queue), tx_queue);
+
+	/* Any Tx return cancels the Tx resource error status */
+	if (p_gbe_pctrl->tx_resource_err[tx_queue] == 1)
+		p_gbe_pctrl->tx_resource_err[tx_queue] = 0;
+
+	D_CACHE_FLUSH_LINE((u32) p_tx_desc_used, 0);
+
+	return KWGBE_OK;
+}
+
+/*
+ * port_receive - Get received information from Rx ring.
+ *
+ * This routine returns the received data to the caller. There is no
+ * data copying during routine operation. All information is returned
+ * using pointer to packet information struct passed from the caller.
+ * If the routine exhausts	Rx ring resources then the resource error flag
+ * is set.
+ *
+ * @p_gbe_pctrl		Ethernet Port Control srtuct ptr.
+ * @rx_queue		Number of Rx queue.
+ * @p_pkt_info		User packet buffer.
+ *
+ * OUTPUT: Rx ring current and used indexes are updated.
+ *
+ * RETURN:
+ * KWGBE_ERROR in case the routine can not access Rx desc ring.
+ * KWGBE_QFULL if Rx ring resources are exhausted.
+ * KWGBE_END_OF_JOB if there is no received data.
+ * KWGBE_OK otherwise.
+ */
+static enum kwgbe_fret_sts port_receive(struct kwgbe_device *dkwgbe,
+					enum kwgbe_q rx_queue,
+					struct kwgbe_pktinf *p_pkt_info)
+{
+	struct kwgbe_portinfo *p_gbe_pctrl = &dkwgbe->portinfo;
+	volatile struct kwgbe_rx_dscr *p_rx_curr_desc;
+	volatile struct kwgbe_rx_dscr *p_rx_next_curr_desc;
+	volatile struct kwgbe_rx_dscr *p_rx_used_desc;
+	u32 command_status;
+
+	/* Do not process Rx ring in case of Rx ring resource error */
+	if (p_gbe_pctrl->rx_resource_err[rx_queue] == 1) {
+		printf("Rx Queue is full ...\n");
+		return KWGBE_QFULL;
+	}
+
+	/* Get the Rx Desc ring 'curr and 'used' indexes */
+	CURR_RFD_GET(p_rx_curr_desc, rx_queue);
+	USED_RFD_GET(p_rx_used_desc, rx_queue);
+
+	/* Sanity check */
+	if (p_rx_curr_desc == NULL)
+		return KWGBE_ERROR;
+
+	/* The following parameters are used to save readings from memory */
+	p_rx_next_curr_desc = RX_NEXT_DESC_PTR(p_rx_curr_desc, rx_queue);
+	command_status = p_rx_curr_desc->cmd_sts;
+
+	/* Nothing to receive... */
+	if (command_status & (KWGBE_BUFFER_OWNED_BY_DMA)) {
+		/*debug("Rx: command_status: %08x\n", command_status); */
+		D_CACHE_FLUSH_LINE((u32) p_rx_curr_desc, 0);
+		/*debug("KWGBE_END_OF_JOB ...\n"); */
+		return KWGBE_END_OF_JOB;
+	}
+
+	p_pkt_info->byte_cnt = (p_rx_curr_desc->byte_cnt) - RX_BUF_OFFSET;
+	p_pkt_info->cmd_sts = command_status;
+	p_pkt_info->buf_ptr = (p_rx_curr_desc->buf_ptr) + RX_BUF_OFFSET;
+	p_pkt_info->retinfo = p_rx_curr_desc->retinfo;
+	p_pkt_info->l4i_chk = p_rx_curr_desc->buf_size;	/* IP fragment indicator */
+
+	/* Clean the return info field to indicate that the packet has been */
+	/* moved to the upper layers                                        */
+	p_rx_curr_desc->retinfo = 0;
+
+	/* Update 'curr' in data structure */
+	CURR_RFD_SET(p_rx_next_curr_desc, rx_queue);
+
+	/* Rx descriptors resource exhausted. Set the Rx ring resource error flag */
+	if (p_rx_next_curr_desc == p_rx_used_desc)
+		p_gbe_pctrl->rx_resource_err[rx_queue] = 1;
+
+	D_CACHE_FLUSH_LINE((u32) p_rx_curr_desc, 0);
+	CPU_PIPE_FLUSH;
+	return KWGBE_OK;
+}
+
+/*
+ * rx_return_buff - Returns a Rx buffer back to the Rx ring.
+ *
+ * This routine returns a Rx buffer back to the Rx ring. It retrieves the
+ * next 'used' descriptor and attached the returned buffer to it.
+ * In case the Rx ring was in "resource error" condition, where there are
+ * no available Rx resources, the function resets the resource error flag.
+ *
+ * @p_gbe_pctrl		Ethernet Port Control srtuct ptr.
+ * @rx_queue		Number of Rx queue.
+ * @p_pkt_info		Information on the returned buffer ptr.
+ *
+ * OUTPUT: New available Rx resource in Rx descriptor ring.
+ *
+ * RETURN:
+ * KWGBE_ERROR in case the routine can not access Rx desc ring.
+ * KWGBE_OK otherwise.
+ */
+static enum kwgbe_fret_sts rx_return_buff(struct kwgbe_device *dkwgbe,
+					  enum kwgbe_q rx_queue,
+					  struct kwgbe_pktinf *p_pkt_info)
+{
+	struct kwgbe_portinfo *p_gbe_pctrl = &dkwgbe->portinfo;
+	volatile struct kwgbe_rx_dscr *p_used_rx_desc;	/* Where to return Rx resource */
+
+	/* Get 'used' Rx descriptor */
+	USED_RFD_GET(p_used_rx_desc, rx_queue);
+
+	/* Sanity check */
+	if (p_used_rx_desc == NULL)
+		return KWGBE_ERROR;
+
+	p_used_rx_desc->buf_ptr = p_pkt_info->buf_ptr;
+	p_used_rx_desc->retinfo = p_pkt_info->retinfo;
+	p_used_rx_desc->byte_cnt = p_pkt_info->byte_cnt;
+	p_used_rx_desc->buf_size = KW_RX_BUF_SZ;	/* Reset Buffer size */
+
+	/* Flush the write pipe */
+	CPU_PIPE_FLUSH;
+
+	/* Return the descriptor to DMA ownership */
+	p_used_rx_desc->cmd_sts =
+	    KWGBE_BUFFER_OWNED_BY_DMA | KWGBE_RX_EN_INTERRUPT;
+
+	/* Flush descriptor and CPU pipe */
+	D_CACHE_FLUSH_LINE((u32) p_used_rx_desc, 0);
+	CPU_PIPE_FLUSH;
+
+	/* Move the used descriptor pointer to the next descriptor */
+	USED_RFD_SET(RX_NEXT_DESC_PTR(p_used_rx_desc, rx_queue), rx_queue);
+
+	/* Any Rx return cancels the Rx resource error status */
+	if (p_gbe_pctrl->rx_resource_err[rx_queue] == 1)
+		p_gbe_pctrl->rx_resource_err[rx_queue] = 0;
+
+	return KWGBE_OK;
+}
+
+/*
+ * init function
+ */
+static int kwgbe_init(struct eth_device *dev)
+{
+	struct kwgbe_device *dkwgbe = to_dkwgbe(dev);
+	struct kwgbe_portinfo *portinfo = &dkwgbe->portinfo;
+	struct egiga_priv *portpriv = &dkwgbe->portpriv;
+
+	u32 queue;
+
+	/*
+	 * ronen - when we update the MAC env params we only update dev->enetaddr
+	 * see ./net/eth.c set_enetaddr()
+	 */
+	memcpy(portinfo->port_mac_addr, dev->enetaddr, 6);
+
+	/* Activate the DMA channels etc */
+	port_init(dkwgbe);
+
+	/* "Allocate" setup TX rings */
+	for (queue = 0; queue < KW_TXQ_NO; queue++) {
+		u32 size;
+
+		portpriv->tx_ring_size[queue] = KW_TXQ_SZ;
+		/*size = no of DESCs times DESC-size */
+		size = (portpriv->tx_ring_size[queue] * TX_DESC_ALIGNED_SIZE);
+		portinfo->tx_desc_area_size[queue] = size;
+
+		/* first clear desc area completely */
+		memset((void *)portinfo->p_tx_desc_area_base[queue],
+		       0, portinfo->tx_desc_area_size[queue]);
+
+		/* initialize tx desc ring with low level driver */
+		if (kwgbe_init_tx_desc_ring
+		    (dkwgbe, KWGBE_Q0,
+		     portpriv->tx_ring_size[queue],
+		     KW_TX_BUF_SZ /* Each Buffer is 1600 Byte */ ,
+		     (u32) portinfo->
+		     p_tx_desc_area_base[queue],
+		     (u32) portinfo->p_tx_buffer_base[queue]) == 0)
+			printf("### initializing TX Ring\n");
+	}
+
+	/* "Allocate" setup RX rings */
+	for (queue = 0; queue < KW_RXQ_NO; queue++) {
+		u32 size;
+
+		/* Meantime RX Ring are fixed - but must be configurable by user */
+		portpriv->rx_ring_size[queue] = KW_RXQ_SZ;
+		size = (portpriv->rx_ring_size[queue] * RX_DESC_ALIGNED_SIZE);
+		portinfo->rx_desc_area_size[queue] = size;
+
+		/* first clear desc area completely */
+		memset((void *)portinfo->p_rx_desc_area_base[queue],
+		       0, portinfo->rx_desc_area_size[queue]);
+		if ((kwgbe_init_rx_desc_ring
+		     (dkwgbe, KWGBE_Q0,
+		      portpriv->rx_ring_size[queue],
+		      KW_RX_BUF_SZ /* Each Buffer is 1600 Byte */ ,
+		      (u32) portinfo->
+		      p_rx_desc_area_base[queue],
+		      (u32) portinfo->p_rx_buffer_base[queue])) == 0)
+			printf("### initializing RX Ring\n");
+	}
+
+	port_start(dkwgbe);
+
+#if (defined (CONFIG_MII) || defined (CONFIG_CMD_MII)) \
+	 && defined (CONFIG_SYS_FAULT_ECHO_LINK_DOWN)
+	if (!miiphy_link(dev->name, portinfo->port_phy_addr)) {
+		printf("No link on %s\n", dev->name);
+		return 0;
+	}
+#endif
+	portpriv->running = MAGIC_KWGBE_RUNNING;
+	return 1;
+}
+
+/*
+ * egiga_start_xmit
+ *
+ * This function is queues a packet in the Tx descriptor for
+ * required port.
+ *
+ * Output : zero upon success
+ */
+int kwgbe_xmit(struct eth_device *dev, volatile void *dataPtr, int dataSize)
+{
+	struct kwgbe_device *dkwgbe = to_dkwgbe(dev);
+	struct egiga_priv *portpriv = &dkwgbe->portpriv;
+	struct net_device_stats *stats = &portpriv->stats;
+
+	struct kwgbe_pktinf pkt_info;
+	enum kwgbe_fret_sts status;
+	enum kwgbe_fret_sts release_result;
+
+	/* Update packet info data structure */
+	pkt_info.cmd_sts = KWGBE_TX_FIRST_DESC | KWGBE_TX_LAST_DESC;	/* first last */
+	pkt_info.cmd_sts |= KWGBE_BUFFER_OWNED_BY_DMA;	/* DMA owned */
+
+	pkt_info.byte_cnt = dataSize;
+	pkt_info.buf_ptr = (u32) dataPtr;
+	pkt_info.retinfo = 0;
+
+	status = port_send(dkwgbe, KWGBE_Q0, &pkt_info);
+	if ((status == KWGBE_ERROR) || (status == KWGBE_QFULL)) {
+		printf("On transmitting packet ..\n");
+		if (status == KWGBE_QFULL)
+			printf("ETH Queue is full.\n");
+		if (status == KWGBE_QLAST_RESO)
+			printf("ETH Queue: using last available resource.\n");
+		goto error;
+	}
+
+	/* Update statistics and start of transmittion time */
+	stats->tx_bytes += dataSize;
+	stats->tx_packets++;
+
+	/* Check if packet(s) is(are) transmitted correctly (release everything) */
+	do {
+		release_result = tx_return_desc(dkwgbe, KWGBE_Q0, &pkt_info);
+		switch (release_result) {
+		case KWGBE_OK:
+			debug("descriptor released\n");
+			if (pkt_info.cmd_sts & 1) {
+				printf("in TX\n");
+				stats->tx_errors++;
+			}
+			break;
+		case KWGBE_RETRY:
+			debug("transmission still in process\n");
+			break;
+		case KWGBE_ERROR:
+			printf("routine can not access Tx desc ring\n");
+			break;
+		case KWGBE_END_OF_JOB:
+			debug("the routine has nothing to release\n");
+			break;
+		default:	/* should not happen */
+			break;
+		}
+	} while (release_result == KWGBE_OK);
+
+	return 0;		/* success */
+      error:
+	return 1;		/* Failed - higher layers will free the skb */
+}
+
+/*
+ * kwgbe_receive
+ *
+ * This function is forward packets that are received from the port's
+ * queues toward kernel core or FastRoute them to another interface.
+ *
+ * @dev		a pointer to the required interface
+ *
+ * Output : number of served packets
+ */
+int kwgbe_receive(struct eth_device *dev)
+{
+	struct kwgbe_device *dkwgbe = to_dkwgbe(dev);
+	struct egiga_priv *portpriv = &dkwgbe->portpriv;
+	struct net_device_stats *stats = &portpriv->stats;
+	struct kwgbe_pktinf pkt_info;
+
+	while ((port_receive(dkwgbe, KWGBE_Q0, &pkt_info) == KWGBE_OK)) {
+
+		if (pkt_info.byte_cnt != 0) {
+			debug("%s: Received %d byte Packet @ 0x%x",
+			      __FUNCTION__, pkt_info.byte_cnt,
+			      pkt_info.buf_ptr);
+		}
+		/* Update statistics. Note byte count includes 4 byte CRC count */
+		stats->rx_packets++;
+		stats->rx_bytes += pkt_info.byte_cnt;
+
+		/*
+		 * In case received a packet without first / last bits on OR the error
+		 * summary bit is on, the packets needs to be dropeed.
+		 */
+		if (((pkt_info.
+		      cmd_sts & (KWGBE_RX_FIRST_DESC | KWGBE_RX_LAST_DESC)) !=
+		     (KWGBE_RX_FIRST_DESC | KWGBE_RX_LAST_DESC))
+		    || (pkt_info.cmd_sts & KWGBE_ERROR_SUMMARY)) {
+			stats->rx_dropped++;
+
+			printf
+			    ("Received packet spread on multiple descriptors\n");
+
+			/* Is this caused by an error ? */
+			if (pkt_info.cmd_sts & KWGBE_ERROR_SUMMARY) {
+				stats->rx_errors++;
+			}
+
+			/* free these descriptors again without forwarding them to the higher layers */
+			pkt_info.buf_ptr &= ~0x7;	/* realign buffer again */
+			pkt_info.byte_cnt = 0x0000;	/* Reset Byte count */
+
+			if (rx_return_buff(dkwgbe, KWGBE_Q0, &pkt_info) !=
+			    KWGBE_OK) {
+				printf
+				    ("Error while returning the RX Desc to Ring\n");
+			} else {
+				debug("RX Desc returned to Ring");
+			}
+			/* /free these descriptors again */
+		} else {
+
+			/* !!! call higher layer processing */
+			debug
+			    ("\nNow send it to upper layer protocols (NetReceive) ...");
+
+			/* let the upper layer handle the packet */
+			NetReceive((uchar *) pkt_info.buf_ptr,
+				   (int)pkt_info.byte_cnt);
+
+			/* free descriptor  */
+			pkt_info.buf_ptr &= ~0x7;	/* realign buffer again */
+			pkt_info.byte_cnt = 0x0000;	/* Reset Byte count */
+			debug("RX: pkt_info.buf_ptr = %x", pkt_info.buf_ptr);
+			if (rx_return_buff(dkwgbe, KWGBE_Q0, &pkt_info) !=
+			    KWGBE_OK) {
+				printf("while returning the RX Desc to Ring");
+			} else {
+				debug("RX Desc returned to Ring");
+			}
+			/* free descriptor code end  */
+		}
+	}
+	egiga_get_stats(dev);	/* update statistics */
+	return 1;
+}
+
+/*
+ * Called from net/eth.c
+ */
+int kirkwood_egiga_initialize(bd_t * bis)
+{
+	struct kwgbe_device *dkwgbe;
+	struct eth_device *dev;
+	struct kwgbe_portinfo *portinfo;
+	struct egiga_priv *portpriv;
+	int devnum, x, temp;
+	char *s, *e, buf[64];
+	u8 used_ports[MAX_KWGBE_DEVS] = CONFIG_KIRKWOOD_EGIGA_PORTS;
+
+	for (devnum = 0; devnum < MAX_KWGBE_DEVS; devnum++) {
+		/*skip if port is configured not to use */
+		if (used_ports[devnum] == 0)
+			continue;
+
+		dkwgbe = malloc(sizeof(struct kwgbe_device));
+		if (!dkwgbe) {
+			printf("Error: Failed to allocate memory for kwgbe%d\n",
+			       devnum);
+			return -1;
+		}
+		memset(dkwgbe, 0, sizeof(struct kwgbe_device));
+
+		dev = &dkwgbe->dev;
+		portinfo = &dkwgbe->portinfo;
+		portpriv = &dkwgbe->portpriv;
+
+		/* must be less than NAMESIZE (16) */
+		sprintf(dev->name, "egiga%d", devnum);
+		debug("Initializing %s", dev->name);
+
+		/* Extract the MAC address from the environment */
+		switch (devnum) {
+		case 0:
+			dkwgbe->regs = (void *)KW_EGIGA0_BASE;
+			s = "ethaddr";
+			break;
+		case 1:
+			dkwgbe->regs = (void *)KW_EGIGA1_BASE;
+			s = "eth1addr";
+			break;
+		default:	/* this should never happen */
+			printf("%s: Invalid device number %d\n",
+			       __FUNCTION__, devnum);
+			return -1;
+		}
+
+		e = getenv(s);
+		if (!e) {
+			/* Generate Ramdom MAC addresses if not set */
+			sprintf(buf, "00:50:43:%02x:%02x:%02x",
+				get_random_hex(), get_random_hex(),
+				get_random_hex());
+			setenv(s, buf);
+		}
+
+		temp = getenv_r(s, buf, sizeof(buf));
+		s = (temp > 0) ? buf : NULL;
+
+		debug("Setting MAC %d to %s", devnum, s);
+		/* on POR port is pre-powered up, so assume it is up */
+
+		for (x = 0; x < 6; ++x) {
+			dev->enetaddr[x] = s ? simple_strtoul(s, &e, 16) : 0;
+			if (s)
+				s = (*e) ? e + 1 : e;
+		}
+		/* set the MAC addr in the HW */
+		memcpy(portinfo->port_mac_addr, dev->enetaddr, 6);
+		port_uc_addr_set(dkwgbe->regs, dev->enetaddr, 0);
+
+		dev->init = (void *)kwgbe_init;
+		dev->halt = (void *)kwgbe_stop;
+		dev->send = (void *)kwgbe_xmit;
+		dev->recv = (void *)kwgbe_receive;
+
+		/*
+		 * Read MIB counter on the GT in order to reset them,
+		 * then zero all the stats fields in memory
+		 */
+		egiga_update_stat(dev);
+		memset(&portpriv->stats, 0, sizeof(struct net_device_stats));
+
+		debug("Allocating descriptor and buffer rings");
+
+		portinfo->p_rx_desc_area_base[0] =
+		    (struct kwgbe_rx_dscr *)memalign(16,
+						     RX_DESC_ALIGNED_SIZE *
+						     KW_RXQ_SZ + 1);
+		portinfo->p_tx_desc_area_base[0] =
+		    (struct kwgbe_tx_dscr *)memalign(16,
+						     TX_DESC_ALIGNED_SIZE *
+						     KW_TXQ_SZ + 1);
+
+		portinfo->p_rx_buffer_base[0] =
+		    (char *)memalign(16, KW_RXQ_SZ * KW_TX_BUF_SZ + 1);
+		portinfo->p_tx_buffer_base[0] =
+		    (char *)memalign(16, KW_RXQ_SZ * KW_TX_BUF_SZ + 1);
+
+		eth_register(dev);
+
+		/* Set phy address of the port */
+		portinfo->port_phy_addr = PHY_BASE_ADR + devnum;
+		phy_set_addr(dkwgbe->regs, portinfo->port_phy_addr);
+
+#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
+		miiphy_register(dev->name, smi_reg_read, smi_reg_write);
+#endif
+	}
+	return 0;
+}
diff --git a/drivers/net/kirkwood_egiga.h b/drivers/net/kirkwood_egiga.h
new file mode 100644
index 0000000..3a5a306
--- /dev/null
+++ b/drivers/net/kirkwood_egiga.h
@@ -0,0 +1,828 @@
+/*
+ * (C) Copyright 2009
+ * Marvell Semiconductor <www.marvell.com>
+ * Prafulla Wadaskar <prafulla at marvell.com>
+ *
+ * based on - Driver for MV64360X ethernet ports
+ * Copyright (C) 2002 rabeeh at galileo.co.il
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ */
+
+#ifndef __EGIGA_H__
+#define __EGIGA_H__
+
+#define MAX_KWGBE_DEVS	2	/*controller has two ports */
+
+/* PHY_BASE_ADR is board specific and can be configured */
+#if defined (CONFIG_PHY_BASE_ADR)
+#define PHY_BASE_ADR		CONFIG_PHY_BASE_ADR
+#else
+#define PHY_BASE_ADR		0x08	/* default phy base addr */
+#endif
+
+/* Egiga driver statistics can be displayed optionally */
+#ifdef CONFIG_EGIGA_STATS_BY_SOFTWARE
+#define UPDATE_STATS_BY_SOFTWARE
+#else
+#undef UPDATE_STATS_BY_SOFTWARE
+#endif
+
+/* Constants */
+#define MAGIC_KWGBE_RUNNING		8031971
+#define INT_CAUSE_UNMASK_ALL		0x0007ffff
+#define INT_CAUSE_UNMASK_ALL_EXT	0x0011ffff
+
+/* Port attrib */
+/* Max queue number is 8 for controller but here configured 1 */
+#define MAX_RXQ_NO	1
+#define MAX_TXQ_NO	1
+/* Use one TX queue and one RX queue */
+#define KW_TXQ_NO 	1
+#define KW_RXQ_NO 	1
+
+/*
+ * Number of RX / TX descriptors on RX / TX rings.
+ * Note that allocating RX descriptors is done by allocating the RX
+ * ring AND a preallocated RX buffers (skb's) for each descriptor.
+ * The TX descriptors only allocates the TX descriptors ring,
+ * with no pre allocated TX buffers (skb's are allocated by higher layers.
+ */
+
+/* TX/RX parameters can be passed externally */
+#ifdef CONFIG_KWGBE_TXQ_SZ
+#define KW_TXQ_SZ CONFIG_KWGBE_TXQ_SZ
+#else
+#define KW_TXQ_SZ 4
+#endif
+
+#ifdef	CONFIG_KWGBE_RXQ_SZ
+#define KW_RXQ_SZ CONFIG_KWGBE_RXQ_SZ
+#else
+#define KW_RXQ_SZ 4
+#endif
+
+#ifdef CONFIG_KWGBE_RXBUF_SZ
+#define KW_RX_BUF_SZ CONFIG_KWGBE_RXBUF_SZ
+#else
+#define KW_RX_BUF_SZ 1600
+#endif
+
+#ifdef CONFIG_KWGBE_TXBUF_SZ
+#define KW_TX_BUF_SZ CONFIG_KWGBE_TXBUF_SZ
+#else
+#define KW_TX_BUF_SZ 1600
+#endif
+
+#define RX_BUF_MXSZ  0xFFFF
+#define TX_BUF_MXSZ  0xFFFF	/* Buffers are limited to 64k */
+#define RX_BUF_MNSZ  0x8
+#define TX_BUF_MNSZ  0x8
+
+/*
+ *	Network device statistics. Akin to the 2.0 ether stats but
+ *	with byte counters.
+ */
+struct net_device_stats {
+	u32 rx_packets;		/* total packets received       */
+	u32 tx_packets;		/* total packets transmitted    */
+	u64 rx_bytes;		/* total bytes received         */
+	u64 tx_bytes;		/* total bytes transmitted      */
+	u32 rx_errors;		/* bad packets received         */
+	u32 tx_errors;		/* packet transmit problems     */
+	u32 rx_dropped;		/* no space in linux buffers    */
+	u32 tx_dropped;		/* no space available in linux  */
+	u32 multicast;		/* multicast packets received   */
+	u32 collisions;
+	/* detailed rx_errors: */
+	u32 rx_length_errors;
+	u32 rx_over_errors;	/* receiver ring buff overflow  */
+	u32 rx_crc_errors;	/* recved pkt with crc error    */
+	u32 rx_frame_errors;	/* recv'd frame alignment error */
+	u32 rx_fifo_errors;	/* recv'r fifo overrun          */
+	u32 rx_missed_errors;	/* receiver missed packet       */
+	/* detailed tx_errors */
+	u32 tx_aborted_errors;
+	u32 tx_carrier_errors;
+	u32 tx_fifo_errors;
+	u32 tx_heartbeat_errors;
+	u32 tx_window_errors;
+	/* for cslip etc */
+	u32 rx_compressed;
+	u32 tx_compressed;
+};
+
+/* Private data structure used for ethernet device */
+struct egiga_priv {
+	struct net_device_stats stats;
+	/* to buffer area aligned */
+	char *p_tx_buffer[KW_TXQ_SZ + 1];
+	char *p_rx_buffer[KW_RXQ_SZ + 1];
+	/* Size of Tx Ring per queue */
+	u32 tx_ring_size[MAX_TXQ_NO];
+	/* Size of Rx Ring per queue */
+	u32 rx_ring_size[MAX_RXQ_NO];
+	/* Magic Number for Ethernet running */
+	u32 running;
+};
+
+/* Chip Registers Structures */
+struct mib_counters {
+	u64 good_octets_received;
+	u32 bad_octets_received;
+	u32 internal_mac_transmit_err;
+	u32 good_frames_received;
+	u32 bad_frames_received;
+	u32 broadcast_frames_received;
+	u32 multicast_frames_received;
+	u32 frames_64_octets;
+	u32 frames_65_to_127_octets;
+	u32 frames_128_to_255_octets;
+	u32 frames_256_to_511_octets;
+	u32 frames_512_to_1023_octets;
+	u32 frames_1024_to_max_octets;
+	u64 good_octets_sent;
+	u32 good_frames_sent;
+	u32 excessive_collision;
+	u32 multicast_frames_sent;
+	u32 broadcast_frames_sent;
+	u32 unrec_mac_control_received;
+	u32 fc_sent;
+	u32 good_fc_received;
+	u32 bad_fc_received;
+	u32 undersize_received;
+	u32 fragments_received;
+	u32 oversize_received;
+	u32 jabber_received;
+	u32 mac_receive_error;
+	u32 bad_crc_event;
+	u32 collision;
+	u32 late_collision;
+};
+
+struct kwgbe_barsz {
+	u32 bar;
+	u32 size;
+};
+
+struct kwgbe_crdp {
+	u32 crdp;
+	u32 crdp_pad[3];
+};
+
+struct kwgbe_tqx {
+	u32 qxttbc;
+	u32 tqxtbc;
+	u32 tqxac;
+	u32 tqxpad;
+};
+
+struct kwgbe_registers {
+	u32 phyadr;
+	u32 smi;
+	u32 euda;
+	u32 eudid;
+	u8 pad1[0x080 - 0x00c - 4];
+	u32 euic;
+	u32 euim;
+	u8 pad2[0x094 - 0x084 - 4];
+	u32 euea;
+	u32 euiae;
+	u8 pad3[0x0b0 - 0x098 - 4];
+	u32 euc;
+	u8 pad3a[0x200 - 0x0b0 - 4];
+	struct kwgbe_barsz barsz[6];
+	u8 pad4[0x280 - 0x22c - 4];
+	u32 ha_remap[4];
+	u32 bare;
+	u32 epap;
+	u8 pad5[0x400 - 0x294 - 4];
+	u32 pxc;
+	u32 pxcx;
+	u32 mii_ser_params;
+	u8 pad6[0x410 - 0x408 - 4];
+	u32 evlane;
+	u32 macal;
+	u32 macah;
+	u32 sdc;
+	u32 dscp[7];
+	u32 psc0;
+	u32 vpt2p;
+	u32 ps0;
+	u32 tqc;
+	u32 psc1;
+	u32 ps1;
+	u32 mrvl_header;
+	u8 pad7[0x460 - 0x454 - 4];
+	u32 ic;
+	u32 ice;
+	u32 pim;
+	u32 peim;
+	u8 pad8[0x474 - 0x46c - 4];
+	u32 pxtfut;
+	u32 pad9;
+	u32 pxmfs;
+	u32 pad10;
+	u32 pxdfc;
+	u32 pxofc;
+	u8 pad11[0x494 - 0x488 - 4];
+	u32 peuiae;
+	u8 pad12[0x4bc - 0x494 - 4];
+	u32 eth_type_prio;
+	u8 pad13[0x4dc - 0x4bc - 4];
+	u32 tqfpc;
+	u32 pttbrc;
+	u32 tqc1;
+	u32 pmtu;
+	u32 pmtbs;
+	u8 pad14[0x60c - 0x4ec - 4];
+	struct kwgbe_crdp crdp[7];
+	u32 crdp7;
+	u32 rqc;
+	u32 cur_servd_dscr_ptr;
+	u8 pad15[0x6c0 - 0x684 - 4];
+	u32 tcqdp[8];
+	u8 pad16[0x700 - 0x6dc - 4];
+	struct kwgbe_tqx tqx[8];
+	u32 pttbc;
+	u8 pad17[0x7a8 - 0x780 - 4];
+	u32 tqxipg0;
+	u32 pad18[3];
+	u32 tqxipg1;
+	u8 pad19[0x7c0 - 0x7b8 - 4];
+	u32 hitkninlopkt;
+	u32 hitkninasyncpkt;
+	u32 lotkninasyncpkt;
+	u32 pad20;
+	u32 ts;
+	u8 pad21[0x3000 - 0x27d0 - 4];
+	struct mib_counters mibc;
+	u8 pad22[0x3400 - 0x3000 - sizeof(struct mib_counters)];
+	u32 dfsmt[64];
+	u32 dfomt[64];
+	u32 dfut[4];
+	u8 pad23[0xe20c0 - 0x7360c - 4];
+	u32 pmbus_top_arbiter;
+};
+
+#define to_dkwgbe(_kd) container_of(_kd, struct kwgbe_device, dev)
+#define KWGBEREG_WR(adr, val)		writel(val, (u32)&adr)
+#define KWGBEREG_RD(adr)		readl((u32)&adr)
+#define KWGBEREG_BITS_RESET(adr, val)	writel(readl((u32)&adr) & ~(val), (u32)&adr)
+#define KWGBEREG_BITS_SET(adr, val)	writel(readl((u32)&adr) | val, (u32)&adr)
+
+/* Default port configuration value */
+#define PRT_CFG_VAL			\
+	KWGBE_UCAST_MOD_NRML		| \
+	KWGBE_DFLT_RX_Q0		| \
+	KWGBE_DFLT_RX_ARPQ0		| \
+	KWGBE_RX_BC_IF_NOT_IP_OR_ARP	| \
+	KWGBE_RX_BC_IF_IP		| \
+	KWGBE_RX_BC_IF_ARP		| \
+	KWGBE_CPTR_TCP_FRMS_DIS		| \
+	KWGBE_CPTR_UDP_FRMS_DIS		| \
+	KWGBE_DFLT_RX_TCPQ0		| \
+	KWGBE_DFLT_RX_UDPQ0		| \
+	KWGBE_DFLT_RX_BPDU_Q_0
+
+/* Default port extend configuration value */
+#define PORT_CFG_EXTEND_VALUE		\
+     KWGBE_SPAN_BPDU_PACKETS_AS_NORMAL	| \
+     KWGBE_PARTITION_DIS		| \
+	KWGBE_TX_CRC_GENERATION_EN
+
+/* Default sdma control value */
+#ifdef CONFIG_NOT_COHERENT_CACHE
+#define PORT_SDMA_CFG_VALUE		\
+	KWGBE_RX_BURST_SIZE_16_64BIT	| \
+	KWGBE_BLM_RX_NO_SWAP		| \
+	KWGBE_BLM_TX_NO_SWAP		| \
+	GT_KWGBE_IPG_INT_RX(0)		| \
+	KWGBE_TX_BURST_SIZE_16_64BIT;
+#else
+#define PORT_SDMA_CFG_VALUE		\
+	KWGBE_RX_BURST_SIZE_4_64BIT	| \
+	GT_KWGBE_IPG_INT_RX(0)		| \
+	KWGBE_TX_BURST_SIZE_4_64BIT;
+#endif
+
+#define GT_KWGBE_IPG_INT_RX(value)	((value & 0x3fff) << 8)
+
+/* Default port serial control value */
+#define PORT_SERIAL_CONTROL_VALUE_TMP		  \
+	KWGBE_FORCE_LINK_PASS			| \
+	KWGBE_DIS_AUTO_NEG_FOR_DUPLX		| \
+	KWGBE_DIS_AUTO_NEG_FOR_FLOW_CTRL	| \
+	KWGBE_ADV_NO_FLOW_CTRL			| \
+	KWGBE_FORCE_FC_MODE_NO_PAUSE_DIS_TX	| \
+	KWGBE_FORCE_BP_MODE_NO_JAM		| \
+	(1 << 9)					| \
+	KWGBE_DO_NOT_FORCE_LINK_FAIL		| \
+	KWGBE_DIS_AUTO_NEG_SPEED_GMII		| \
+	KWGBE_DTE_ADV_0				| \
+	KWGBE_MIIPHY_MAC_MODE			| \
+	KWGBE_AUTO_NEG_NO_CHANGE			| \
+	KWGBE_MAX_RX_PACKET_1552BYTE		| \
+	KWGBE_CLR_EXT_LOOPBACK			| \
+	KWGBE_SET_FULL_DUPLEX_MODE		| \
+	KWGBE_DIS_FLOW_CTRL_TX_RX_IN_FULL_DUPLEX | \
+	KWGBE_SET_MII_SPEED_TO_100
+
+#ifdef CONFIG_SYS_MII_MODE
+#define PORT_SERIAL_CONTROL_VALUE	\
+	PORT_SERIAL_CONTROL_VALUE_TMP |	\
+	KWGBE_SET_GMII_SPEED_TO_10_100
+#else
+#define PORT_SERIAL_CONTROL_VALUE	\
+	PORT_SERIAL_CONTROL_VALUE_TMP |	\
+	KWGBE_SET_GMII_SPEED_TO_1000
+#endif
+
+/* Tx WRR confoguration macros */
+#define PORT_MAX_TRAN_UNIT	0x24	/* MTU register (default) 9KByte */
+#define PORT_MAX_TOKEN_BUCKET_SIZE	0x_fFFF	/* PMTBS reg (default) */
+#define PORT_TOKEN_RATE		    1023	/* PTTBRC reg (default) */
+/* MAC accepet/reject macros */
+#define ACCEPT_MAC_ADDR		0
+#define REJECT_MAC_ADDR		1
+/* Size of a Tx/Rx descriptor used in chain list data structure */
+#define RX_DESC_ALIGNED_SIZE	0x20
+#define TX_DESC_ALIGNED_SIZE	0x20
+/* An offest in Tx descriptors to store data for buffers less than 8 Bytes */
+#define TX_BUF_OFFSET_IN_DESC	0x18
+/* Buffer offset from buffer pointer */
+#define RX_BUF_OFFSET		0x2
+
+/* Port serial status reg (PSR) */
+#define KWGBE_INTERFACE_GMII_MII	0
+#define KWGBE_INTERFACE_PCM		1
+#define KWGBE_LINK_IS_DOWN		0
+#define KWGBE_LINK_IS_UP		(1 << 1)
+#define KWGBE_PORT_AT_HALF_DUPLEX	0
+#define KWGBE_PORT_AT_FULL_DUPLEX	(1 << 2)
+#define KWGBE_RX_FLOW_CTRL_DISD		0
+#define KWGBE_RX_FLOW_CTRL_ENBALED	(1 << 3)
+#define KWGBE_GMII_SPEED_100_10		0
+#define KWGBE_GMII_SPEED_1000		(1 << 4)
+#define KWGBE_MII_SPEED_10		0
+#define KWGBE_MII_SPEED_100		(1 << 5)
+#define KWGBE_NO_TX			0
+#define KWGBE_TX_IN_PROGRESS		(1 << 7)
+#define KWGBE_BYPASS_NO_ACTIVE		0
+#define KWGBE_BYPASS_ACTIVE		(1 << 8)
+#define KWGBE_PORT_NOT_AT_PARTN_STT	0
+#define KWGBE_PORT_AT_PARTN_STT		(1 << 9)
+#define KWGBE_PORT_TX_FIFO_NOT_EMPTY	0
+#define KWGBE_PORT_TX_FIFO_EMPTY	(1 << 10)
+
+/* These macros describes the Port configuration reg (Px_cR) bits */
+#define KWGBE_UCAST_MOD_NRML		0
+#define KWGBE_UNICAST_PROMISCUOUS_MODE	1
+#define KWGBE_DFLT_RX_Q0		0
+#define KWGBE_DFLT_RX_Q1		(1 << 1)
+#define KWGBE_DFLT_RX_Q2		(1 << 2)
+#define KWGBE_DFLT_RX_Q3		((1 << 2) | (1 << 1))
+#define KWGBE_DFLT_RX_Q4		(1 << 3)
+#define KWGBE_DFLT_RX_Q5		((1 << 3) | (1 << 1))
+#define KWGBE_DFLT_RX_Q6		((1 << 3) | (1 << 2))
+#define KWGBE_DFLT_RX_Q7		((1 << 3) | (1 << 2) | (1 << 1))
+#define KWGBE_DFLT_RX_ARPQ0		0
+#define KWGBE_DFLT_RX_ARPQ1		(1 << 4)
+#define KWGBE_DFLT_RX_ARPQ2		(1 << 5)
+#define KWGBE_DFLT_RX_ARPQ3		((1 << 5) | (1 << 4))
+#define KWGBE_DFLT_RX_ARPQ4		(1 << 6)
+#define KWGBE_DFLT_RX_ARPQ5		((1 << 6) | (1 << 4))
+#define KWGBE_DFLT_RX_ARPQ6		((1 << 6) | (1 << 5))
+#define KWGBE_DFLT_RX_ARPQ7		((1 << 6) | (1 << 5) | (1 << 4))
+#define KWGBE_RX_BC_IF_NOT_IP_OR_ARP	0
+#define KWGBE_REJECT_BC_IF_NOT_IP_OR_ARP (1 << 7)
+#define KWGBE_RX_BC_IF_IP		0
+#define KWGBE_REJECT_BC_IF_IP		(1 << 8)
+#define KWGBE_RX_BC_IF_ARP		0
+#define KWGBE_REJECT_BC_IF_ARP		(1 << 9)
+#define KWGBE_TX_AM_NO_UPDATE_ERR_SMRY	(1 << 12)
+#define KWGBE_CPTR_TCP_FRMS_DIS		0
+#define KWGBE_CPTR_TCP_FRMS_EN		(1 << 14)
+#define KWGBE_CPTR_UDP_FRMS_DIS		0
+#define KWGBE_CPTR_UDP_FRMS_EN		(1 << 15)
+#define KWGBE_DFLT_RX_TCPQ0		0
+#define KWGBE_DFLT_RX_TCPQ1		(1 << 16)
+#define KWGBE_DFLT_RX_TCPQ2		(1 << 17)
+#define KWGBE_DFLT_RX_TCPQ3		((1 << 17) | (1 << 16))
+#define KWGBE_DFLT_RX_TCPQ4		(1 << 18)
+#define KWGBE_DFLT_RX_TCPQ5		((1 << 18) | (1 << 16))
+#define KWGBE_DFLT_RX_TCPQ6		((1 << 18) | (1 << 17))
+#define KWGBE_DFLT_RX_TCPQ7		((1 << 18) | (1 << 17) | (1 << 16))
+#define KWGBE_DFLT_RX_UDPQ0		0
+#define KWGBE_DFLT_RX_UDPQ1		(1 << 19)
+#define KWGBE_DFLT_RX_UDPQ2		(1 << 20)
+#define KWGBE_DFLT_RX_UDPQ3		((1 << 20) | (1 << 19))
+#define KWGBE_DFLT_RX_UDPQ4		(1 << 21)
+#define KWGBE_DFLT_RX_UDPQ5		((1 << 21) | (1 << 19))
+#define KWGBE_DFLT_RX_UDPQ6		((1 << 21) | (1 << 20))
+#define KWGBE_DFLT_RX_UDPQ7		((1 << 21) | (1 << 20) | (1 << 19))
+#define KWGBE_DFLT_RX_BPDU_Q_0		 0
+#define KWGBE_DFLT_RX_BPDU_Q_1		(1 << 22)
+#define KWGBE_DFLT_RX_BPDU_Q_2		(1 << 23)
+#define KWGBE_DFLT_RX_BPDU_Q_3		((1 << 23) | (1 << 22))
+#define KWGBE_DFLT_RX_BPDU_Q_4		(1 << 24)
+#define KWGBE_DFLT_RX_BPDU_Q_5		((1 << 24) | (1 << 22))
+#define KWGBE_DFLT_RX_BPDU_Q_6		((1 << 24) | (1 << 23))
+#define KWGBE_DFLT_RX_BPDU_Q_7		((1 << 24) | (1 << 23) | (1 << 22))
+#define KWGBE_DFLT_RX_TCP_CHKSUM_MODE	(1 << 25)
+
+/* These macros describes the Port configuration extend reg (Px_cXR) bits*/
+#define KWGBE_CLASSIFY_EN			1
+#define KWGBE_SPAN_BPDU_PACKETS_AS_NORMAL	0
+#define KWGBE_SPAN_BPDU_PACKETS_TO_RX_Q7	(1 << 1)
+#define KWGBE_PARTITION_DIS			0
+#define KWGBE_PARTITION_EN			(1 << 2)
+#define KWGBE_TX_CRC_GENERATION_EN		0
+#define KWGBE_TX_CRC_GENERATION_DIS		(1 << 3)
+
+/* Tx/Rx queue command reg (RQCR/TQCR)*/
+#define KWGBE_Q_0_EN				1
+#define KWGBE_Q_1_EN				(1 << 1)
+#define KWGBE_Q_2_EN				(1 << 2)
+#define KWGBE_Q_3_EN				(1 << 3)
+#define KWGBE_Q_4_EN				(1 << 4)
+#define KWGBE_Q_5_EN				(1 << 5)
+#define KWGBE_Q_6_EN				(1 << 6)
+#define KWGBE_Q_7_EN				(1 << 7)
+#define KWGBE_Q_0_DIS				(1 << 8)
+#define KWGBE_Q_1_DIS				(1 << 9)
+#define KWGBE_Q_2_DIS				(1 << 10)
+#define KWGBE_Q_3_DIS				(1 << 11)
+#define KWGBE_Q_4_DIS				(1 << 12)
+#define KWGBE_Q_5_DIS				(1 << 13)
+#define KWGBE_Q_6_DIS				(1 << 14)
+#define KWGBE_Q_7_DIS				(1 << 15)
+
+/* These macros describes the Port Sdma configuration reg (SDCR) bits */
+#define KWGBE_RIFB				1
+#define KWGBE_RX_BURST_SIZE_1_64BIT		0
+#define KWGBE_RX_BURST_SIZE_2_64BIT		(1 << 1)
+#define KWGBE_RX_BURST_SIZE_4_64BIT		(1 << 2)
+#define KWGBE_RX_BURST_SIZE_8_64BIT		((1 << 2) | (1 << 1))
+#define KWGBE_RX_BURST_SIZE_16_64BIT		(1 << 3)
+#define KWGBE_BLM_RX_NO_SWAP			(1 << 4)
+#define KWGBE_BLM_RX_BYTE_SWAP			0
+#define KWGBE_BLM_TX_NO_SWAP			(1 << 5)
+#define KWGBE_BLM_TX_BYTE_SWAP			0
+#define KWGBE_DESCRIPTORS_BYTE_SWAP		(1 << 6)
+#define KWGBE_DESCRIPTORS_NO_SWAP		0
+#define KWGBE_TX_BURST_SIZE_1_64BIT		0
+#define KWGBE_TX_BURST_SIZE_2_64BIT		(1 << 22)
+#define KWGBE_TX_BURST_SIZE_4_64BIT		(1 << 23)
+#define KWGBE_TX_BURST_SIZE_8_64BIT		((1 << 23) | (1 << 22))
+#define KWGBE_TX_BURST_SIZE_16_64BIT		(1 << 24)
+
+/* These macros describes the Port serial control reg (PSCR) bits */
+#define KWGBE_SERIAL_PORT_DIS			0
+#define KWGBE_SERIAL_PORT_EN			1
+#define KWGBE_FORCE_LINK_PASS			(1 << 1)
+#define KWGBE_DO_NOT_FORCE_LINK_PASS		0
+#define KWGBE_EN_AUTO_NEG_FOR_DUPLX		0
+#define KWGBE_DIS_AUTO_NEG_FOR_DUPLX		(1 << 2)
+#define KWGBE_EN_AUTO_NEG_FOR_FLOW_CTRL		0
+#define KWGBE_DIS_AUTO_NEG_FOR_FLOW_CTRL	(1 << 3)
+#define KWGBE_ADV_NO_FLOW_CTRL			0
+#define KWGBE_ADV_SYMMETRIC_FLOW_CTRL		(1 << 4)
+#define KWGBE_FORCE_FC_MODE_NO_PAUSE_DIS_TX	0
+#define KWGBE_FORCE_FC_MODE_TX_PAUSE_DIS	(1 << 5)
+#define KWGBE_FORCE_BP_MODE_NO_JAM		0
+#define KWGBE_FORCE_BP_MODE_JAM_TX		(1 << 7)
+#define KWGBE_FORCE_BP_MODE_JAM_TX_ON_RX_ERR	(1 << 8)
+#define KWGBE_FORCE_LINK_FAIL			0
+#define KWGBE_DO_NOT_FORCE_LINK_FAIL		(1 << 10)
+#define KWGBE_DIS_AUTO_NEG_SPEED_GMII		(1 << 13)
+#define KWGBE_EN_AUTO_NEG_SPEED_GMII		0
+#define KWGBE_DTE_ADV_0				0
+#define KWGBE_DTE_ADV_1				(1 << 14)
+#define KWGBE_MIIPHY_MAC_MODE			0
+#define KWGBE_MIIPHY_PHY_MODE			(1 << 15)
+#define KWGBE_AUTO_NEG_NO_CHANGE		0
+#define KWGBE_RESTART_AUTO_NEG			(1 << 16)
+#define KWGBE_MAX_RX_PACKET_1518BYTE		0
+#define KWGBE_MAX_RX_PACKET_1522BYTE		(1 << 17)
+#define KWGBE_MAX_RX_PACKET_1552BYTE		(1 << 18)
+#define KWGBE_MAX_RX_PACKET_9022BYTE		((1 << 18) | (1 << 17))
+#define KWGBE_MAX_RX_PACKET_9192BYTE		(1 << 19)
+#define KWGBE_MAX_RX_PACKET_9700BYTE		((1 << 19) | (1 << 17))
+#define KWGBE_SET_EXT_LOOPBACK			(1 << 20)
+#define KWGBE_CLR_EXT_LOOPBACK			0
+#define KWGBE_SET_FULL_DUPLEX_MODE		(1 << 21)
+#define KWGBE_SET_HALF_DUPLEX_MODE		0
+#define KWGBE_EN_FLOW_CTRL_TX_RX_IN_FULL_DUPLEX	(1 << 22)
+#define KWGBE_DIS_FLOW_CTRL_TX_RX_IN_FULL_DUPLEX 0
+#define KWGBE_SET_GMII_SPEED_TO_10_100		0
+#define KWGBE_SET_GMII_SPEED_TO_1000		(1 << 23)
+#define KWGBE_SET_MII_SPEED_TO_10		0
+#define KWGBE_SET_MII_SPEED_TO_100		(1 << 24)
+
+/* SMI register fields (KWGBE_SMI_REG) */
+#define KWGBE_PHY_SMI_TIMEOUT		10000
+#define KWGBE_PHY_SMI_DATA_OFFS        	0	/* Data */
+#define KWGBE_PHY_SMI_DATA_MASK	       	(0xffff << KWGBE_PHY_SMI_DATA_OFFS)
+#define KWGBE_PHY_SMI_DEV_ADDR_OFFS	16	/* PHY device address */
+#define KWGBE_PHY_SMI_DEV_ADDR_MASK    	(0x1f << KWGBE_PHY_SMI_DEV_ADDR_OFFS)
+#define KWGBE_SMI_REG_ADDR_OFFS		21	/* PHY device register address */
+#define KWGBE_SMI_REG_ADDR_MASK		(0x1f << KWGBE_SMI_REG_ADDR_OFFS)
+#define KWGBE_PHY_SMI_OPCODE_OFFS	26	/* Write/Read opcode */
+#define KWGBE_PHY_SMI_OPCODE_MASK	(3 << KWGBE_PHY_SMI_OPCODE_OFFS)
+#define KWGBE_PHY_SMI_OPCODE_WRITE	(0 << KWGBE_PHY_SMI_OPCODE_OFFS)
+#define KWGBE_PHY_SMI_OPCODE_READ	(1 << KWGBE_PHY_SMI_OPCODE_OFFS)
+#define KWGBE_PHY_SMI_READ_VALID_MASK	(1 << 27)	/* Read Valid  */
+#define KWGBE_PHY_SMI_BUSY_MASK		(1 << 28)	/* Busy */
+
+/* SDMA command status fields macros */
+/* Tx & Rx descriptors status */
+#define KWGBE_ERROR_SUMMARY		1
+
+/* Tx & Rx descriptors command */
+#define KWGBE_BUFFER_OWNED_BY_DMA	(1 << 31)
+
+/* Tx descriptors status */
+#define KWGBE_LC_ERROR			0
+#define KWGBE_UR_ERROR			(1 << 1)
+#define KWGBE_RL_ERROR			(1 << 2)
+#define KWGBE_LLC_SNAP_FORMAT		(1 << 9)
+
+/* Rx descriptors status */
+#define KWGBE_CRC_ERROR			0
+#define KWGBE_OVERRUN_ERROR		(1 << 1)
+#define KWGBE_MAX_FRAME_LENGTH_ERROR	(1 << 2)
+#define KWGBE_RESOURCE_ERROR		((1 << 2) | (1 << 1))
+#define KWGBE_VLAN_TAGGED		(1 << 19)
+#define KWGBE_BPDU_FRAME		(1 << 20)
+#define KWGBE_TCP_FRAME_OVER_IP_V_4	0
+#define KWGBE_UDP_FRAME_OVER_IP_V_4	(1 << 21)
+#define KWGBE_OTHER_FRAME_TYPE		(1 << 22)
+#define KWGBE_LAYER_2_IS_KWGBE_V_2	(1 << 23)
+#define KWGBE_FRAME_TYPE_IP_V_4		(1 << 24)
+#define KWGBE_FRAME_HEADER_OK		(1 << 25)
+#define KWGBE_RX_LAST_DESC		(1 << 26)
+#define KWGBE_RX_FIRST_DESC		(1 << 27)
+#define KWGBE_UNKNOWN_DESTINATION_ADDR	(1 << 28)
+#define KWGBE_RX_EN_INTERRUPT		(1 << 29)
+#define KWGBE_LAYER_4_CHECKSUM_OK	(1 << 30)
+
+/* Rx descriptors byte count */
+#define KWGBE_FRAME_FRAGMENTED		(1 << 2)
+
+/* Tx descriptors command */
+#define KWGBE_LAYER_4_CHECKSUM_FIRST_DESC	(1 << 10)
+#define KWGBE_FRAME_SET_TO_VLAN			(1 << 15)
+#define KWGBE_TCP_FRAME				0
+#define KWGBE_UDP_FRAME				(1 << 16)
+#define KWGBE_GEN_TCP_UDP_CHECKSUM		(1 << 17)
+#define KWGBE_GEN_IP_V_4_CHECKSUM		(1 << 18)
+#define KWGBE_ZERO_PADDING			(1 << 19)
+#define KWGBE_TX_LAST_DESC			(1 << 20)
+#define KWGBE_TX_FIRST_DESC			(1 << 21)
+#define KWGBE_GEN_CRC				(1 << 22)
+#define KWGBE_TX_EN_INTERRUPT			(1 << 23)
+#define KWGBE_AUTO_MODE				(1 << 30)
+
+/* Address decode parameters */
+/* Ethernet Base Address Register bits */
+#define EBAR_TARGET_DRAM			0x00000000
+#define EBAR_TARGET_DEVICE			0x00000001
+#define EBAR_TARGET_CBS				0x00000002
+#define EBAR_TARGET_PCI0			0x00000003
+#define EBAR_TARGET_PCI1			0x00000004
+#define EBAR_TARGET_CUNIT			0x00000005
+#define EBAR_TARGET_AUNIT			0x00000006
+#define EBAR_TARGET_GUNIT			0x00000007
+
+/* Window attrib */
+#define EBAR_ATTR_DRAM_CS0			0x00000E00
+#define EBAR_ATTR_DRAM_CS1			0x00000D00
+#define EBAR_ATTR_DRAM_CS2			0x00000B00
+#define EBAR_ATTR_DRAM_CS3			0x00000700
+
+/* DRAM Target interface */
+#define EBAR_ATTR_DRAM_NO_CACHE_COHERENCY	0x00000000
+#define EBAR_ATTR_DRAM_CACHE_COHERENCY_WT	0x00001000
+#define EBAR_ATTR_DRAM_CACHE_COHERENCY_WB	0x00002000
+
+/* Device Bus Target interface */
+#define EBAR_ATTR_DEVICE_DEVCS0			0x00001E00
+#define EBAR_ATTR_DEVICE_DEVCS1			0x00001D00
+#define EBAR_ATTR_DEVICE_DEVCS2			0x00001B00
+#define EBAR_ATTR_DEVICE_DEVCS3			0x00001700
+#define EBAR_ATTR_DEVICE_BOOTCS3		0x00000F00
+
+/* PCI Target interface */
+#define EBAR_ATTR_PCI_BYTE_SWAP			0x00000000
+#define EBAR_ATTR_PCI_NO_SWAP			0x00000100
+#define EBAR_ATTR_PCI_BYTE_WORD_SWAP		0x00000200
+#define EBAR_ATTR_PCI_WORD_SWAP			0x00000300
+#define EBAR_ATTR_PCI_NO_SNOOP_NOT_ASSERT	0x00000000
+#define EBAR_ATTR_PCI_NO_SNOOP_ASSERT		0x00000400
+#define EBAR_ATTR_PCI_IO_SPACE			0x00000000
+#define EBAR_ATTR_PCI_MEMORY_SPACE		0x00000800
+#define EBAR_ATTR_PCI_REQ64_FORCE		0x00000000
+#define EBAR_ATTR_PCI_REQ64_SIZE		0x00001000
+
+/* Window access control */
+#define EWIN_ACCESS_NOT_ALLOWED 0
+#define EWIN_ACCESS_READ_ONLY	1
+#define EWIN_ACCESS_FULL	((1 << 1) | 1)
+
+/* SDMA command macros */
+#define CURR_RFD_GET(p_curr_desc, queue) \
+ ((p_curr_desc) = p_gbe_pctrl->p_rx_curr_desc_q[queue])
+
+#define CURR_RFD_SET(p_curr_desc, queue) \
+ (p_gbe_pctrl->p_rx_curr_desc_q[queue] = (p_curr_desc))
+
+#define USED_RFD_GET(p_used_desc, queue) \
+ ((p_used_desc) = p_gbe_pctrl->p_rx_used_desc_q[queue])
+
+#define USED_RFD_SET(p_used_desc, queue)\
+(p_gbe_pctrl->p_rx_used_desc_q[queue] = (p_used_desc))
+
+#define CURR_TFD_GET(p_curr_desc, queue) \
+ ((p_curr_desc) = p_gbe_pctrl->p_tx_curr_desc_q[queue])
+
+#define CURR_TFD_SET(p_curr_desc, queue) \
+ (p_gbe_pctrl->p_tx_curr_desc_q[queue] = (p_curr_desc))
+
+#define USED_TFD_GET(p_used_desc, queue) \
+ ((p_used_desc) = p_gbe_pctrl->p_tx_used_desc_q[queue])
+
+#define USED_TFD_SET(p_used_desc, queue) \
+ (p_gbe_pctrl->p_tx_used_desc_q[queue] = (p_used_desc))
+
+#define FIRST_TFD_GET(p_first_desc, queue) \
+ ((p_first_desc) = p_gbe_pctrl->p_tx_first_desc_q[queue])
+
+#define FIRST_TFD_SET(p_first_desc, queue) \
+ (p_gbe_pctrl->p_tx_first_desc_q[queue] = (p_first_desc))
+
+/* Macros that save access to desc in order to find next desc pointer  */
+#define RX_NEXT_DESC_PTR(p_rx_desc, queue) 	( \
+	struct kwgbe_rx_dscr*)(((((u32)p_rx_desc - \
+	(u32)p_gbe_pctrl->p_rx_desc_area_base[queue]) + \
+	RX_DESC_ALIGNED_SIZE) % p_gbe_pctrl->rx_desc_area_size[queue]) + \
+	(u32)p_gbe_pctrl->p_rx_desc_area_base[queue])
+
+#define TX_NEXT_DESC_PTR(p_tx_desc, queue) 	( \
+	struct kwgbe_tx_dscr*)(((((u32)p_tx_desc - \
+	(u32)p_gbe_pctrl->p_tx_desc_area_base[queue]) + \
+	TX_DESC_ALIGNED_SIZE) % p_gbe_pctrl->tx_desc_area_size[queue]) + \
+	(u32)p_gbe_pctrl->p_tx_desc_area_base[queue])
+
+enum kwgbe_fret_sts {
+	KWGBE_OK,		/* Returned as expected. */
+	KWGBE_ERROR,		/* Fundamental error. */
+	KWGBE_RETRY,		/* Could not process request. Try later. */
+	KWGBE_END_OF_JOB,	/* Ring has nothing to process. */
+	KWGBE_QFULL,		/* Ring resource error. */
+	KWGBE_QLAST_RESO	/* Ring resources about to exhaust. */
+};
+
+enum kwgbe_q {
+	KWGBE_Q0 = 0,
+	KWGBE_Q1 = 1,
+	KWGBE_Q2 = 2,
+	KWGBE_Q3 = 3,
+	KWGBE_Q4 = 4,
+	KWGBE_Q5 = 5,
+	KWGBE_Q6 = 6,
+	KWGBE_Q7 = 7
+};
+
+enum kwgbe_adrwin {
+	KWGBE_WIN0,
+	KWGBE_WIN1,
+	KWGBE_WIN2,
+	KWGBE_WIN3,
+	KWGBE_WIN4,
+	KWGBE_WIN5
+};
+
+enum kwgbe_target {
+	KWGBE_TARGET_DRAM,
+	KWGBE_TARGET_DEV,
+	KWGBE_TARGET_CBS,
+	KWGBE_TARGET_PCI0,
+	KWGBE_TARGET_PCI1
+};
+
+struct kwgbe_rx_dscr {
+	u32 cmd_sts;		/* Descriptor command status */
+	u16 buf_size;		/* Buffer size */
+	u16 byte_cnt;		/* Descriptor buffer byte count */
+	u32 buf_ptr;		/* Descriptor buffer pointer */
+	u32 nxtdesc_p;		/* Next descriptor pointer */
+	u32 retinfo;		/* User resource return information */
+};
+
+struct kwgbe_tx_dscr {
+	u32 cmd_sts;		/* Descriptor command status */
+	u16 l4i_chk;		/* CPU provided TCP Checksum */
+	u16 byte_cnt;		/* Descriptor buffer byte count */
+	u32 buf_ptr;		/* Descriptor buffer pointer */
+	u32 nxtdesc_p;		/* Next descriptor pointer */
+	u32 retinfo;		/* User resource return information */
+};
+
+/*
+ * Unified struct for Rx and Tx operations. The user is not required to
+ * be familier with neither Tx nor Rx descriptors.
+ */
+struct kwgbe_pktinf {
+	u32 cmd_sts;		/* Descriptor command status */
+	u16 byte_cnt;		/* Descriptor buffer byte count */
+	u16 l4i_chk;		/* Tx CPU provided TCP Checksum */
+	u32 buf_ptr;		/* Descriptor buffer pointer */
+	u32 retinfo;		/* User resource return information */
+};
+
+struct kwgbe_winparam {
+	enum kwgbe_adrwin win;	/* Window number */
+	enum kwgbe_target target;	/* System targets */
+	u16 attrib;		/* BAR attrib. See above macros */
+	u32 base_addr;		/* Window base address in u32 form */
+	u32 high_addr;		/* Window high address in u32 form */
+	u32 size;		/* Size in MBytes. Must be % 64Kbyte. */
+	int enable;		/* Enable/disable access to the window. */
+	u16 access_ctrl;	/*Access ctrl register. see above macros */
+};
+
+/* Ethernet port specific infomation */
+struct kwgbe_portinfo {
+	int port_phy_addr;	/* User phy address of Ethrnet port */
+	u8 port_mac_addr[6];	/* User defined port MAC address. */
+	u32 port_config;	/* User port configuration value */
+	u32 port_config_extend;	/* User port config extend value */
+	u32 port_sdma_config;	/* User port SDMA config value */
+	u32 port_serial_control;	/* User port serial control value */
+	u32 port_tx_queue_command;	/* Port active Tx queues summary */
+	u32 port_rx_queue_command;	/* Port active Rx queues summary */
+
+	/* User function to cast virtual address to CPU bus address */
+	 u32(*port_virt_to_phys) (u32 addr);
+	/* User scratch pad for user specific data structures */
+	void *port_private;
+
+	int rx_resource_err[MAX_RXQ_NO];	/* Rx ring resource err flag */
+	int tx_resource_err[MAX_TXQ_NO];	/* Tx ring resource err flag */
+
+	/* Tx/Rx rings managment indexes fields. For driver use */
+
+	/* Next available Rx resource */
+	volatile struct kwgbe_rx_dscr *p_rx_curr_desc_q[MAX_RXQ_NO];
+	/* Returning Rx resource */
+	volatile struct kwgbe_rx_dscr *p_rx_used_desc_q[MAX_RXQ_NO];
+
+	/* Next available Tx resource */
+	volatile struct kwgbe_tx_dscr *p_tx_curr_desc_q[MAX_TXQ_NO];
+	/* Returning Tx resource */
+	volatile struct kwgbe_tx_dscr *p_tx_used_desc_q[MAX_TXQ_NO];
+	/* An extra Tx index to support txmt of multiple buffs per packet */
+	volatile struct kwgbe_tx_dscr *p_tx_first_desc_q[MAX_TXQ_NO];
+
+	/* Tx/Rx rings size and base variables fields. For driver use */
+
+	volatile struct kwgbe_rx_dscr *p_rx_desc_area_base[MAX_RXQ_NO];
+	u32 rx_desc_area_size[MAX_RXQ_NO];
+	char *p_rx_buffer_base[MAX_RXQ_NO];
+
+	volatile struct kwgbe_tx_dscr *p_tx_desc_area_base[MAX_TXQ_NO];
+	u32 tx_desc_area_size[MAX_TXQ_NO];
+	char *p_tx_buffer_base[MAX_TXQ_NO];
+};
+
+/* port device data struct */
+struct kwgbe_device {
+	struct eth_device dev;
+	struct kwgbe_portinfo portinfo;
+	struct egiga_priv portpriv;
+	struct kwgbe_registers *regs;
+};
+
+/* functions */
+static void port_uc_addr_set(struct kwgbe_registers *regs, u8 * p_addr,
+			     enum kwgbe_q queue);
+static void port_reset(struct kwgbe_registers *regs);
+
+#endif /* __EGIGA_H__ */
diff --git a/include/netdev.h b/include/netdev.h
index 4f2b23a..3f2dc83 100644
--- a/include/netdev.h
+++ b/include/netdev.h
@@ -52,6 +52,7 @@ int fec_initialize (bd_t *bis);
 int greth_initialize(bd_t *bis);
 void gt6426x_eth_initialize(bd_t *bis);
 int inca_switch_initialize(bd_t *bis);
+int kirkwood_egiga_initialize(bd_t *bis);
 int macb_eth_initialize(int id, void *regs, unsigned int phy_addr);
 int mcdmafec_initialize(bd_t *bis);
 int mcffec_initialize(bd_t *bis);
-- 
1.5.3.3



More information about the U-Boot mailing list