[linux-yocto] [PATCH 19/30] LSI FEMAC Ethernet: Updated for upstream submittal

Charlie Paul cpaul.windriver at gmail.com
Tue May 6 09:36:51 PDT 2014


From: David Mercado <david.mercado at windriver.com>

    Incorporated feedback from Linutronix regarding lsi_acp_net.c FEMAC driver

     - Removed unnecessary module parameters in kernel config
     - Removed outdated GNU public license statement in file headers
     - Fixed multiline comments for proper kernel style
     - Removed direct memory access from mdio driver
     - Removed use of UPPERCASE function names
     - Removed use of global variables
     - Minimized use of arch-specific #ifdefs
     - Replaced use of custom align macros with ALIGN()/PTR_ALIGN()
     - Added missing ethtool callbacks, updated stats function
     - Removed un-needed extra spinlock
     - Removed un-needed pr_info messages that would otherwise spam dmesg
     - Replaced custom MAC parsing with is_multicast_ether_addr()
     - Fixed incorrect NAPI handling
     - Removed /proc handling
     - Removed magic numbers (e.g., replaced 6 with ETH_ALEN)
     - Fixed module init/exit routines

Signed-off-by: David Mercado <david.mercado at windriver.com>
---
 drivers/net/ethernet/lsi/Kconfig        |   15 -
 drivers/net/ethernet/lsi/lsi_acp_mdio.c |  201 +++----
 drivers/net/ethernet/lsi/lsi_acp_net.c  |  871 ++++++++++++++-----------------
 drivers/net/ethernet/lsi/lsi_acp_net.h  |  261 ++++++---
 4 files changed, 693 insertions(+), 655 deletions(-)

diff --git a/drivers/net/ethernet/lsi/Kconfig b/drivers/net/ethernet/lsi/Kconfig
index 1c760e5..a78867d 100644
--- a/drivers/net/ethernet/lsi/Kconfig
+++ b/drivers/net/ethernet/lsi/Kconfig
@@ -35,19 +35,4 @@ config LSI_NET_TX_BUF_SZ
 	help
 	  The size of the transmit buffer.
 
-config DISABLE_TX_INTERRUPTS
-	bool "NIC driver: Disable Tx interrupts"
-	depends on LSI_NET
-	default y
-	help
-	  If set to "yes", disables Transmit interrupts
-
-config PRELOAD_RX_BUFFERS
-	bool "NIC driver: Preload Rx buffers"
-	depends on LSI_NET
-	default n
-	help
-	  If set to "yes", enables preloading of Rx buffer prior to
-	  copying into device
-
 endif # LSI_NET
diff --git a/drivers/net/ethernet/lsi/lsi_acp_mdio.c b/drivers/net/ethernet/lsi/lsi_acp_mdio.c
index 07643fc..aab609d 100644
--- a/drivers/net/ethernet/lsi/lsi_acp_mdio.c
+++ b/drivers/net/ethernet/lsi/lsi_acp_mdio.c
@@ -1,21 +1,13 @@
 /*
  * drivers/net/ethernet/lsi/lsi_acp_mdio.c
  *
- * Copyright (C) 2010 LSI
+ * Copyright (C) 2013 LSI Corporation.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
  * (at your option) any later version.
  *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307	 USA
  */
 
 #include <linux/module.h>
@@ -27,42 +19,53 @@
 #include <linux/skbuff.h>
 #include <linux/platform_device.h>
 
+#define BZ33327_WA
+
 /*
-  ==============================================================================
-  ==============================================================================
-  MDIO Access
-  ==============================================================================
-  ==============================================================================
-*/
+ * MDIO Access
+ */
 
-#ifndef CONFIG_ACPISS
+struct lsi_mdio_priv {
+	unsigned long base;
+};
 
-#define BZ33327_WA
-
-static unsigned long mdio_base;
+static struct lsi_mdio_priv *mdio_priv;
 static DEFINE_SPINLOCK(mdio_lock);
 
-#define MDIO_CONTROL_RD_DATA ((void *)(mdio_base + 0x0))
-#define MDIO_STATUS_RD_DATA  ((void *)(mdio_base + 0x4))
-#define MDIO_CLK_OFFSET      ((void *)(mdio_base + 0x8))
-#define MDIO_CLK_PERIOD      ((void *)(mdio_base + 0xc))
+#define MDIO_CONTROL_RD_DATA ((void *)(mdio_priv->base + 0x0))
+#define MDIO_STATUS_RD_DATA  ((void *)(mdio_priv->base + 0x4))
+#define MDIO_CLK_OFFSET      ((void *)(mdio_priv->base + 0x8))
+#define MDIO_CLK_PERIOD      ((void *)(mdio_priv->base + 0xc))
 
 #ifdef CONFIG_ARM
-#define READ(a) readl((a))
-#define WRITE(a, v) writel((v), (a))
+static u32 read_reg(u32 *addr)
+{
+	return readl((void __iomem *)addr);
+}
+
+static void write_reg(u32 *addr, u32 value)
+{
+	writel(value, (void __iomem *)addr);
+}
 #else
-#define READ(a) in_le32((a))
-#define WRITE(a, v) out_le32((a), (v))
+static u32 read_reg(u32 *addr)
+{
+	return in_le32((unsigned *)addr);
+}
+
+static void write_reg(u32 *addr, u32 value)
+{
+	out_le32((unsigned *)addr, (int)value);
+}
 #endif
 
 /*
-  ------------------------------------------------------------------------------
-  acp_mdio_read
-*/
+ * acp_mdio_read
+ */
 
 int
 acp_mdio_read(unsigned long address, unsigned long offset,
-	      unsigned short *value, int clause45)
+	      unsigned short *value, int clause_45)
 {
 	unsigned long command = 0;
 	unsigned long status;
@@ -71,24 +74,24 @@ acp_mdio_read(unsigned long address, unsigned long offset,
 	spin_lock_irqsave(&mdio_lock, flags);
 #if defined(BZ33327_WA)
 	/* Set the mdio_busy (status) bit. */
-	status = READ(MDIO_STATUS_RD_DATA);
+	status = read_reg(MDIO_STATUS_RD_DATA);
 	status |= 0x40000000;
-	WRITE(MDIO_STATUS_RD_DATA, status);
+	write_reg(MDIO_STATUS_RD_DATA, status);
 #endif /* BZ33327_WA */
 
-	if (clause45 == 0) {
+	if (clause_45 == 0) {
 		/* Write the command. */
 		command = 0x10000000;              /* op_code: read */
 		command |= (address & 0x1f) << 16; /* port_addr (tgt device) */
 		command |= (offset & 0x1f) << 21;  /* device_addr (tgt reg) */
-		WRITE(MDIO_CONTROL_RD_DATA, command);
+		write_reg(MDIO_CONTROL_RD_DATA, command);
 	} else {
 		/*
 		 * Step 1: Write the address.
 		 */
 
 		/* Write the address */
-		command = 0x20000000;                    /* clause_45 = 1 */
+		command = 0x20000000;                    /* Clause 45 = 1 */
 		command |= 0x00000000;                   /* op_code: 0 */
 		command |= 0x04000000;                   /* interface_sel = 1 */
 		command |= ((offset & 0x1f000000) >> 3); /* device_addr (target
@@ -97,16 +100,16 @@ acp_mdio_read(unsigned long address, unsigned long offset,
 							    device) */
 		command |= (offset & 0xffff);            /* addr_or_data (target
 							    register) */
-		WRITE(MDIO_CONTROL_RD_DATA, command);
+		write_reg(MDIO_CONTROL_RD_DATA, command);
 
 		/* Wait for the mdio_busy (status) bit to clear. */
 		do {
-			status = READ(MDIO_STATUS_RD_DATA);
+			status = read_reg(MDIO_STATUS_RD_DATA);
 		} while (0 != (status & 0x40000000));
 
 		/* Wait for the mdio_busy (control) bit to clear. */
 		do {
-			command = READ(MDIO_CONTROL_RD_DATA);
+			command = read_reg(MDIO_CONTROL_RD_DATA);
 		} while (0 != (command & 0x80000000));
 
 		/*
@@ -114,30 +117,30 @@ acp_mdio_read(unsigned long address, unsigned long offset,
 		 */
 
 		/* Set the mdio_busy (status) bit. */
-		status = READ(MDIO_STATUS_RD_DATA);
+		status = read_reg(MDIO_STATUS_RD_DATA);
 		status |= 0x40000000;
-		WRITE(MDIO_STATUS_RD_DATA, status);
+		write_reg(MDIO_STATUS_RD_DATA, status);
 
-		command = 0x20000000;                    /* clause_45 = 1 */
+		command = 0x20000000;                    /* Clause 45 = 1 */
 		command |= 0x10000000;                   /* op_code: read */
 		command |= 0x04000000;                   /* interface_sel = 1 */
 		command |= ((offset & 0x1f000000) >> 3); /* device_addr (target
 							    device_type) */
 		command |= (address & 0x1f) << 16;       /* port_addr (target
 							    device) */
-		WRITE(MDIO_CONTROL_RD_DATA, command);
+		write_reg(MDIO_CONTROL_RD_DATA, command);
 	}
 
 #if defined(BZ33327_WA)
 	/* Wait for the mdio_busy (status) bit to clear. */
 	do {
-		status = READ(MDIO_STATUS_RD_DATA);
+		status = read_reg(MDIO_STATUS_RD_DATA);
 	} while (0 != (status & 0x40000000));
 #endif				/* BZ33327_WA */
 
 	/* Wait for the mdio_busy (control) bit to clear. */
 	do {
-		command = READ(MDIO_CONTROL_RD_DATA);
+		command = read_reg(MDIO_CONTROL_RD_DATA);
 	} while (0 != (command & 0x80000000));
 
 	*value = (unsigned short)(command & 0xffff);
@@ -148,13 +151,12 @@ acp_mdio_read(unsigned long address, unsigned long offset,
 EXPORT_SYMBOL(acp_mdio_read);
 
 /*
-  ------------------------------------------------------------------------------
-  acp_mdio_write
-*/
+ * acp_mdio_write
+ */
 
 int
 acp_mdio_write(unsigned long address, unsigned long offset,
-	       unsigned short value, int clause45)
+	       unsigned short value, int clause_45)
 {
 	unsigned long command = 0;
 	unsigned long status;
@@ -164,30 +166,30 @@ acp_mdio_write(unsigned long address, unsigned long offset,
 
 	/* Wait for mdio_busy (control) to be clear. */
 	do {
-		command = READ(MDIO_CONTROL_RD_DATA);
+		command = read_reg(MDIO_CONTROL_RD_DATA);
 	} while (0 != (command & 0x80000000));
 
 #if defined(BZ33327_WA)
 	/* Set the mdio_busy (status) bit. */
-	status = READ(MDIO_STATUS_RD_DATA);
+	status = read_reg(MDIO_STATUS_RD_DATA);
 	status |= 0x40000000;
-	WRITE(MDIO_STATUS_RD_DATA, status);
+	write_reg(MDIO_STATUS_RD_DATA, status);
 #endif /* BZ33327_WA */
 
-	if (clause45 == 0) {
+	if (clause_45 == 0) {
 		/* Write the command. */
 		command = 0x08000000;              /* op_code: write */
 		command |= (address & 0x1f) << 16; /* port_addr (tgt device) */
 		command |= (offset & 0x1f) << 21;  /* device_addr (tgt reg) */
 		command |= (value & 0xffff);       /* value */
-		WRITE(MDIO_CONTROL_RD_DATA, command);
+		write_reg(MDIO_CONTROL_RD_DATA, command);
 	} else {
 		/*
 		 * Step 1: Write the address.
 		 */
 
 		/* Write the address */
-		command = 0x20000000;                    /* clause_45 = 1 */
+		command = 0x20000000;                    /* Clause 45 = 1 */
 		command |= 0x00000000;                   /* op_code: 0 */
 		command |= 0x04000000;                   /* interface_sel = 1 */
 		command |= ((offset & 0x1f000000) >> 3); /* device_addr (target
@@ -196,16 +198,16 @@ acp_mdio_write(unsigned long address, unsigned long offset,
 							    device) */
 		command |= (offset & 0xffff);            /* addr_or_data (target
 							    register) */
-		WRITE(MDIO_CONTROL_RD_DATA, command);
+		write_reg(MDIO_CONTROL_RD_DATA, command);
 
 		/* Wait for the mdio_busy (status) bit to clear. */
 		do {
-			status = READ(MDIO_STATUS_RD_DATA);
+			status = read_reg(MDIO_STATUS_RD_DATA);
 		} while (0 != (status & 0x40000000));
 
 		/* Wait for the mdio_busy (control) bit to clear. */
 		do {
-			command = READ(MDIO_CONTROL_RD_DATA);
+			command = read_reg(MDIO_CONTROL_RD_DATA);
 		} while (0 != (command & 0x80000000));
 
 		/*
@@ -213,11 +215,11 @@ acp_mdio_write(unsigned long address, unsigned long offset,
 		 */
 
 		/* Set the mdio_busy (status) bit. */
-		status = READ(MDIO_STATUS_RD_DATA);
+		status = read_reg(MDIO_STATUS_RD_DATA);
 		status |= 0x40000000;
-		WRITE(MDIO_STATUS_RD_DATA, status);
+		write_reg(MDIO_STATUS_RD_DATA, status);
 
-		command = 0x20000000;                    /* clause_45 = 1 */
+		command = 0x20000000;                    /* Clause 45 = 1 */
 		command |= 0x08000000;                   /* op_code: write */
 		command |= 0x04000000;                   /* interface_sel = 1 */
 		command |= ((offset & 0x1f000000) >> 3); /* device_addr (target
@@ -225,19 +227,19 @@ acp_mdio_write(unsigned long address, unsigned long offset,
 		command |= (address & 0x1f) << 16;       /* port_addr (target
 							    device) */
 		command |= (value & 0xffff);             /* addr_or_data=value*/
-		WRITE(MDIO_CONTROL_RD_DATA, command);
+		write_reg(MDIO_CONTROL_RD_DATA, command);
 	}
 
 #if defined(BZ33327_WA)
 	/* Wait for the mdio_busy (status) bit to clear. */
 	do {
-		status = READ(MDIO_STATUS_RD_DATA);
+		status = read_reg(MDIO_STATUS_RD_DATA);
 	} while (0 != (status & 0x40000000));
 #endif	/* BZ33327_WA */
 
 	/* Wait for the mdio_busy (control) bit to clear. */
 	do {
-		command = READ(MDIO_CONTROL_RD_DATA);
+		command = read_reg(MDIO_CONTROL_RD_DATA);
 	} while (0 != (command & 0x80000000));
 
 	spin_unlock_irqrestore(&mdio_lock, flags);
@@ -247,38 +249,26 @@ acp_mdio_write(unsigned long address, unsigned long offset,
 EXPORT_SYMBOL(acp_mdio_write);
 
 /*
-  ------------------------------------------------------------------------------
-  acp_mdio_initialize
-*/
+ * acp_mdio_initialize
+ */
 
-static int
+static void
 acp_mdio_initialize(void)
 {
 #ifdef CONFIG_ARM
-	WRITE(MDIO_CLK_OFFSET, 0x1c);
-	WRITE(MDIO_CLK_PERIOD, 0xf0);
+	/* LSI AXM (ARM) Platforms. */
+	write_reg(MDIO_CLK_OFFSET, 0x1c);
+	write_reg(MDIO_CLK_PERIOD, 0xf0);
 #else
-	WRITE(MDIO_CLK_OFFSET, 0x10);
-	WRITE(MDIO_CLK_PERIOD, 0x2c);
+	/* LSI ACP (PPC) Platforms. */
+	write_reg(MDIO_CLK_OFFSET, 0x10);
+	write_reg(MDIO_CLK_PERIOD, 0x2c);
 #endif
-
-	return 0;
 }
 
-#endif /* ! CONFIG_ACPISS */
-
 /*
-  ==============================================================================
-  ==============================================================================
-  Linux Stuff
-  ==============================================================================
-  ==============================================================================
-*/
-
-/*
-  ------------------------------------------------------------------------------
-  acp_wrappers_init
-*/
+ * acp_wrappers_init
+ */
 
 int __init
 acp_mdio_init(void)
@@ -286,12 +276,16 @@ acp_mdio_init(void)
 	int rc = -ENODEV;
 	struct device_node *np = NULL;
 	const u32 *field;
+	void __iomem *map;
 	u64 mdio_address;
 	u32 mdio_size;
 
-	pr_info("Initializing Axxia Wrappers.\n");
+	pr_info("MDIO: Initializing Axxia Wrappers.\n");
+
+	mdio_priv = kzalloc(sizeof(struct lsi_mdio_priv), GFP_KERNEL);
+	if (!mdio_priv)
+		return -ENOMEM;
 
-#ifndef CONFIG_ACPISS
 	np = of_find_node_by_type(np, "network");
 
 	while (np &&
@@ -299,22 +293,37 @@ acp_mdio_init(void)
 	       !of_device_is_compatible(np, "acp-femac"))
 		np = of_find_node_by_type(np, "network");
 
-	if (!np)
+	if (!np) {
+		pr_warn("MDIO: No compatible devices found.\n");
+		rc = -EINVAL;
 		goto error;
+	}
 
 	field = of_get_property(np, "mdio-reg", NULL);
 
-	if (!field)
+	if (!field) {
+		pr_crit("MDIO: Unable to read mdio-reg property!\n");
+		rc = -EINVAL;
 		goto error;
+	}
 
 	mdio_address = of_translate_address(np, field);
+	if (mdio_address == OF_BAD_ADDR) {
+		pr_crit("MDIO: of_translate_address failed!\n");
+		rc = -EINVAL;
+		goto error;
+	}
+
 	mdio_size = field[1];
-	mdio_base = (unsigned long)ioremap(mdio_address, mdio_size);
-	rc = acp_mdio_initialize();
-#else
-	rc = 0;
-#endif
+	map = ioremap(mdio_address, mdio_size);
+	if (!map) {
+		pr_crit("MDIO: Unable to ioremap!\n");
+		rc = -ENOMEM;
+		goto error;
+	}
+	mdio_priv->base = (unsigned long)map;
 
+	acp_mdio_initialize();
 error:
 	return rc;
 }
diff --git a/drivers/net/ethernet/lsi/lsi_acp_net.c b/drivers/net/ethernet/lsi/lsi_acp_net.c
index 5684779..5589619 100644
--- a/drivers/net/ethernet/lsi/lsi_acp_net.c
+++ b/drivers/net/ethernet/lsi/lsi_acp_net.c
@@ -1,23 +1,13 @@
 /*
  * drivers/net/ethernet/lsi/lsi_acp_net.c
  *
- * Copyright (C) 2013 LSI
+ * Copyright (C) 2013 LSI Corporation.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
  * (at your option) any later version.
  *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
- * USA
- *
  * NOTES:
  *
  * 1) This driver is used by both ACP (PPC) and AXM (ARM) platforms.
@@ -81,48 +71,28 @@
 #include <linux/of.h>
 #include <linux/of_address.h>
 #include <linux/of_irq.h>
+#include <linux/of_net.h>
 #include <linux/dma-mapping.h>
 #include <linux/uaccess.h>
 #include <linux/io.h>
 
 #include <asm/dma.h>
 
-#ifdef CONFIG_AXXIA
-#include <mach/ncr.h>
-#else
 #include "../../../misc/lsi-ncr.h"
-#endif
 
 #include "lsi_acp_net.h"
 
 extern int acp_mdio_read(unsigned long, unsigned long, unsigned short *, int);
 extern int acp_mdio_write(unsigned long, unsigned long, unsigned short, int);
 
-/* Define to disable full duplex mode on Amarillo boards */
-#undef AMARILLO_WA
-/*#define AMARILLO_WA*/
-
 #define LSI_DRV_NAME           "acp-femac"
 #define LSI_MDIO_NAME          "acp-femac-mdio"
-#define LSI_DRV_VERSION        "2013-09-10"
+#define LSI_DRV_VERSION        "2014-01-09"
 
 MODULE_AUTHOR("John Jacques");
 MODULE_DESCRIPTION("LSI ACP-FEMAC Ethernet driver");
 MODULE_LICENSE("GPL");
 
-/* Base Addresses of the RX, TX, and DMA Registers. */
-static void *rx_base;
-static void *tx_base;
-static void *dma_base;
-#ifdef CONFIG_ARM
-static void *gpreg_base;
-#define GPREG_BASE 0x002010094000ULL
-#endif
-
-/* BCM5221 registers */
-#define PHY_BCM_TEST_REG	0x1f
-#define PHY_AUXILIARY_MODE3	0x1d
-
 /*
  * ----------------------------------------------------------------------
  * appnic_mii_read
@@ -183,12 +153,10 @@ static void appnic_handle_link_change(struct net_device *dev)
 	if (phydev->link) {
 		if ((pdata->speed != phydev->speed) ||
 		    (pdata->duplex != phydev->duplex)) {
-#ifndef AMARILLO_WA
 			if (phydev->duplex) {
 				rx_configuration |= APPNIC_RX_CONF_DUPLEX;
 				tx_configuration |= APPNIC_TX_CONF_DUPLEX;
 			}
-#endif
 			if (phydev->speed == SPEED_100) {
 				rx_configuration |= APPNIC_RX_CONF_SPEED;
 				tx_configuration |= APPNIC_TX_CONF_SPEED;
@@ -287,34 +255,6 @@ skip_first:
 		return ret;
 	}
 
-#ifdef AMARILLO_WA
-	/*
-	 * For the Amarillo, without the auto-negotiate ecn.
-	 */
-	{
-		u16 val;
-		int rc;
-
-		/* Enable access to shadow register @ 0x1d */
-		rc = acp_mdio_read(phydev->addr, PHY_BCM_TEST_REG, &val, 0);
-		val |= 0x80;
-		rc |= acp_mdio_write(phydev->addr, PHY_BCM_TEST_REG, val, 0);
-
-		/* Set RX FIFO size to 0x7 */
-		rc |= acp_mdio_read(phydev->addr, PHY_AUXILIARY_MODE3, &val, 0);
-		val &= 0xf;
-		val |= 0x7;
-		rc |= acp_mdio_write(phydev->addr, PHY_AUXILIARY_MODE3, val, 0);
-
-		/* Disable access to shadow register @ 0x1d */
-		rc |= acp_mdio_read(phydev->addr, PHY_BCM_TEST_REG, &val, 0);
-		val &= ~0x80;
-		rc |= acp_mdio_write(phydev->addr, PHY_BCM_TEST_REG, val, 0);
-
-		if (0 != rc)
-			return -EIO;
-	}
-#endif
 	netdev_info(dev,
 		    "attached PHY driver [%s] (mii_bus:phy_addr=%s, irq=%d)\n",
 		    phydev->drv->name, dev_name(&phydev->dev), phydev->irq);
@@ -391,9 +331,7 @@ err_out_1:
 #define DESCRIPTOR_GRANULARITY 64
 #define BUFFER_ALIGNMENT 64
 
-#define ALIGN64B(address) \
-	((((unsigned long) (address) + (64UL - 1UL)) & ~(64UL - 1UL)))
-
+#define ALIGN64B(address) (PTR_ALIGN((address), BUFFER_ALIGNMENT))
 #define ALIGN64B_OFFSET(address) \
 	(ALIGN64B(address) - (unsigned long) (address))
 
@@ -441,26 +379,44 @@ int tx_buf_sz = CONFIG_LSI_NET_TX_BUF_SZ;
 module_param(tx_buf_sz, int, 0);
 MODULE_PARM_DESC(tx_buf_sz, "Appnic : Receive buffer size");
 
-static unsigned long dropped_by_stack;
-static unsigned long out_of_tx_descriptors;
-static unsigned long transmit_interrupts;
-static unsigned long receive_interrupts;
+/*
+ * ======================================================================
+ * Utility Functions
+ * ======================================================================
+ */
 
 /*
-  ======================================================================
-  Utility Functions
-  ======================================================================
-*/
+ * ----------------------------------------------------------------------
+ * mac_addr_valid
+ *
+ * If mac address is multicast, broadcast, or matches our mac address,
+ * it's a valid address. Otherwise, it's not.
+ */
+
+static bool mac_addr_valid(struct net_device *dev, u8 *mac_addr)
+{
+	bool is_valid = false;
+
+	if (is_multicast_ether_addr(mac_addr))
+		is_valid = true;
+	else if (is_broadcast_ether_addr(mac_addr))
+		is_valid = true;
+	else if (compare_ether_addr(mac_addr, &dev->dev_addr[0]) == 0)
+		is_valid = true;
+
+	return is_valid;
+}
+
 
 /*
-  ----------------------------------------------------------------------
-  clear_statistics
-*/
+ * ----------------------------------------------------------------------
+ * clear_statistics
+ *
+ * NOTE: The hardware clears the statistics registers after a read.
+ */
 
 static void clear_statistics(struct appnic_device *pdata)
 {
-	int waste;
-
 	/*
 	 * Clear memory.
 	 */
@@ -468,62 +424,61 @@ static void clear_statistics(struct appnic_device *pdata)
 	memset((void *) &(pdata->stats), 0, sizeof(struct net_device_stats));
 
 	/*
-	 * Clear counters.
+	 * Clear counters by reading them.
 	 */
 
-	waste = read_mac(APPNIC_RX_STAT_PACKET_OK); /* rx_packets */
-	waste = read_mac(APPNIC_TX_STAT_PACKET_OK); /* tx_packets */
-
-	/* rx_bytes kept by driver. */
-	/* tx_bytes kept by driver. */
-	/* rx_errors will be the sum of the rx errors available. */
-	/* tx_errors will be the sum of the tx errors available. */
-	/* rx_dropped (unable to allocate skb) will be maintained by driver */
-	/* tx_dropped (unable to allocate skb) will be maintained by driver */
-
-	/* multicast */
-
-	waste = read_mac(APPNIC_RX_STAT_MULTICAST);
-
-	/* collisions will be the sum of the three following. */
-
-	waste = read_mac(APPNIC_TX_STATUS_LATE_COLLISION);
-	waste = read_mac(APPNIC_TX_STATUS_EXCESSIVE_COLLISION);
-	waste = read_mac(APPNIC_TX_STAT_COLLISION_ABOVE_WATERMARK);
-
-	/* rx_length_errors will be the sum of the two following. */
+	/* stats.rx_packets */
+	read_mac(APPNIC_RX_STAT_PACKET_OK);
 
-	waste = read_mac(APPNIC_RX_STAT_UNDERSIZE);
-	waste = read_mac(APPNIC_RX_STAT_OVERSIZE);
+	/* stats.tx_packets */
+	read_mac(APPNIC_TX_STAT_PACKET_OK);
 
-	/* rx_over_errors (out of descriptors?) maintained by the driver. */
-	/* rx_crc_errors */
+	/*
+	 * stats.rx_bytes - Updated by this driver.
+	 * stats.tx_bytes - Updated by this driver.
+	 * stats.rx_errors - The sum of all RX errors available.
+	 * stats.tx_errors - The sum of all TX errors available.
+	 * stats.rx_dropped (unable to allocate skb) - Updated by the stack.
+	 * stats.tx_dropped (unable to allocate skb) - Updated by the stack.
+	 */
 
-	waste = read_mac(APPNIC_RX_STAT_CRC_ERROR);
+	/* stats.multicast */
+	read_mac(APPNIC_RX_STAT_MULTICAST);
 
-	/* rx_frame_errors */
+	/* stats.collisions - The sum of the following driver stats. */
+	read_mac(APPNIC_TX_STATUS_LATE_COLLISION);
+	read_mac(APPNIC_TX_STATUS_EXCESSIVE_COLLISION);
+	read_mac(APPNIC_TX_STAT_COLLISION_ABOVE_WATERMARK);
 
-	waste = read_mac(APPNIC_RX_STAT_ALIGN_ERROR);
+	/* stats.rx_length_errors - The sum of the following driver stats. */
+	read_mac(APPNIC_RX_STAT_UNDERSIZE);
+	read_mac(APPNIC_RX_STAT_OVERSIZE);
 
-	/* rx_fifo_errors */
+	/* stats.rx_over_errors - Not maintained by this driver. */
 
-	waste = read_mac(APPNIC_RX_STAT_OVERFLOW);
+	/* stats.rx_crc_errors */
+	read_mac(APPNIC_RX_STAT_CRC_ERROR);
 
-	/* rx_missed will not be maintained. */
-	/* tx_aborted_errors will be maintained by the driver. */
-	/* tx_carrier_errors will not be maintained. */
-	/* tx_fifo_errors */
+	/* stats.rx_frame_errors */
+	read_mac(APPNIC_RX_STAT_ALIGN_ERROR);
 
-	waste = read_mac(APPNIC_TX_STAT_UNDERRUN);
+	/* stats.rx_fifo_errors */
+	read_mac(APPNIC_RX_STAT_OVERFLOW);
 
-	/* tx_heartbeat_errors */
-	/* tx_window_errors */
+	/*
+	 * stats.rx_missed - Not maintained by this driver.
+	 * stats.tx_aborted_errors - Not maintained by this driver.
+	 * stats.tx_carrier_errors - Not maintained by this driver.
+	 */
 
-	/* rx_compressed will not be maintained. */
-	/* tx_compressed will not be maintained. */
+	/* stats.tx_fifo_errors */
+	read_mac(APPNIC_TX_STAT_UNDERRUN);
 
 	/*
-	 * That's all.
+	 * stats.tx_heartbeat_errors - Not maintained by this driver.
+	 * stats.tx_window_errors - Not mainteaned by this driver.
+	 * stats.rx_compressed - Not maintained by this driver.
+	 * stats.tx_compressed - Not maintained by this driver.
 	 */
 
 	return;
@@ -533,38 +488,31 @@ static void clear_statistics(struct appnic_device *pdata)
  * ----------------------------------------------------------------------
  * get_hw_statistics
  *
- *  -- NOTES --
- *
- *  1) The hardware clears the statistics registers after a read.
+ * NOTE: The hardware clears the statistics registers after a read.
  */
 
 static void get_hw_statistics(struct appnic_device *pdata)
 {
 	unsigned long flags;
 
-	/* tx_packets */
-
+	/* stats.tx_packets */
 	pdata->stats.tx_packets += read_mac(APPNIC_TX_STAT_PACKET_OK);
 
-	/* multicast */
-
+	/* stats.multicast */
 	pdata->stats.multicast += read_mac(APPNIC_RX_STAT_MULTICAST);
 
-	/* collision */
-
+	/* stats.collision */
 	pdata->stats.collisions += read_mac(APPNIC_TX_STATUS_LATE_COLLISION);
 	pdata->stats.collisions +=
 		read_mac(APPNIC_TX_STATUS_EXCESSIVE_COLLISION);
 	pdata->stats.collisions +=
 	read_mac(APPNIC_TX_STAT_COLLISION_ABOVE_WATERMARK);
 
-	/* rx_length_errors */
-
+	/* stats.rx_length_errors */
 	pdata->stats.rx_length_errors += read_mac(APPNIC_RX_STAT_UNDERSIZE);
 	pdata->stats.rx_length_errors += read_mac(APPNIC_RX_STAT_OVERSIZE);
 
-	/* tx_fifo_errors */
-
+	/* stats.tx_fifo_errors */
 	pdata->stats.tx_fifo_errors += read_mac(APPNIC_TX_STAT_UNDERRUN);
 
 	/*
@@ -591,10 +539,6 @@ static void get_hw_statistics(struct appnic_device *pdata)
 
 	spin_unlock_irqrestore(&pdata->dev_lock, flags);
 
-	/*
-	 * That's all.
-	 */
-
 	return;
 }
 
@@ -705,13 +649,12 @@ static void queue_decrement(union appnic_queue_pointer *queue,
  * disable_rx_tx
  */
 
-static void disable_rx_tx(void)
+static void disable_rx_tx(struct net_device *dev)
 {
+	struct appnic_device *pdata = netdev_priv(dev);
 	unsigned long tx_configuration;
 	unsigned long rx_configuration;
 
-	pr_info("%s: Disabling the interface.\n", LSI_DRV_NAME);
-
 	rx_configuration = read_mac(APPNIC_RX_CONF);
 	rx_configuration &= ~APPNIC_RX_CONF_ENABLE;
 	write_mac(rx_configuration, APPNIC_RX_CONF);
@@ -721,7 +664,6 @@ static void disable_rx_tx(void)
 
 	write_mac(tx_configuration, APPNIC_TX_CONF);
 
-	/* That's all. */
 	return;
 }
 
@@ -740,15 +682,18 @@ static void disable_rx_tx(void)
 static void handle_transmit_interrupt(struct net_device *dev)
 {
 	struct appnic_device *pdata = netdev_priv(dev);
+	union appnic_queue_pointer queue;
 
 	/*
 	 * The hardware's tail pointer should be one descriptor (or more)
 	 * ahead of software's copy.
 	 */
 
-	while (0 < queue_initialized(SWAB_QUEUE_POINTER(pdata->tx_tail),
-				     pdata->tx_tail_copy, pdata->tx_num_desc)) {
+	queue = swab_queue_pointer(pdata->tx_tail);
+	while (0 < queue_initialized(queue, pdata->tx_tail_copy,
+				     pdata->tx_num_desc)) {
 		queue_increment(&pdata->tx_tail_copy, pdata->tx_num_desc);
+		queue = swab_queue_pointer(pdata->tx_tail);
 	}
 
 	return;
@@ -768,18 +713,16 @@ static void lsinet_rx_packet(struct net_device *dev)
 	unsigned error_num = 0;
 	unsigned long ok_stat = 0, overflow_stat = 0;
 	unsigned long crc_stat = 0, align_stat = 0;
-
-	spin_lock(&pdata->extra_lock);
+	union appnic_queue_pointer queue;
 
 	readdescriptor(((unsigned long)pdata->rx_desc +
 			pdata->rx_tail_copy.bits.offset), &descriptor);
 
-	sk_buff = dev_alloc_skb(1600);
+	sk_buff = dev_alloc_skb(LSINET_MAX_MTU);
 
 	if ((struct sk_buff *)0 == sk_buff) {
 		pr_err("%s: dev_alloc_skb() failed! Dropping packet.\n",
 		       LSI_DRV_NAME);
-		spin_unlock(&pdata->extra_lock);
 		return;
 	}
 
@@ -792,25 +735,18 @@ static void lsinet_rx_packet(struct net_device *dev)
 	 * Copy the received packet into the skb.
 	 */
 
-	while (0 < queue_initialized(SWAB_QUEUE_POINTER(pdata->rx_tail),
-				pdata->rx_tail_copy, pdata->rx_num_desc)) {
+	queue = swab_queue_pointer(pdata->rx_tail);
+	while (0 < queue_initialized(queue, pdata->rx_tail_copy,
+				     pdata->rx_num_desc)) {
 
-#ifdef CONFIG_PRELOAD_RX_BUFFERS
 		{
 			unsigned char *buffer;
 			buffer = skb_put(sk_buff, descriptor.pdu_length);
-			memcmp(buffer, buffer, descriptor.pdu_length);
 			memcpy((void *)buffer,
 			       (void *)(descriptor.host_data_memory_pointer +
 				 pdata->dma_alloc_offset_rx),
 			       descriptor.pdu_length);
 		}
-#else
-		memcpy((void *)skb_put(sk_buff, descriptor.pdu_length),
-		       (void *)(descriptor.host_data_memory_pointer +
-				pdata->dma_alloc_offset_rx),
-		       descriptor.pdu_length);
-#endif
 		bytes_copied += descriptor.pdu_length;
 		descriptor.data_transfer_length = pdata->rx_buf_per_desc;
 		writedescriptor(((unsigned long)pdata->rx_desc +
@@ -824,6 +760,7 @@ static void lsinet_rx_packet(struct net_device *dev)
 		readdescriptor(((unsigned long)pdata->rx_desc +
 					pdata->rx_tail_copy.bits.offset),
 			       &descriptor);
+		queue = swab_queue_pointer(pdata->rx_tail);
 	}
 
 	if (0 == descriptor.end_of_packet) {
@@ -835,29 +772,15 @@ static void lsinet_rx_packet(struct net_device *dev)
 
 	} else {
 		if (0 == error_num) {
-			struct ethhdr *ethhdr =
-				(struct ethhdr *) sk_buff->data;
-			unsigned char broadcast[] = { 0xff, 0xff, 0xff,
-						      0xff, 0xff, 0xff };
-			unsigned char multicast[] = { 0x01, 0x00 };
-
-			if ((0 == memcmp((const void *)&(ethhdr->h_dest[0]),
-					 (const void *)&(dev->dev_addr[0]),
-					 sizeof(ethhdr->h_dest))) ||
-			    (0 == memcmp((const void *)&(ethhdr->h_dest[0]),
-					 (const void *) &(broadcast[0]),
-					 sizeof(ethhdr->h_dest))) ||
-			    (0 == memcmp((const void *)&(ethhdr->h_dest[0]),
-					 (const void *) &(multicast[0]),
-					 sizeof(multicast)))) {
-
+			struct ethhdr *ethhdr = (struct ethhdr *) sk_buff->data;
+			if (mac_addr_valid(dev, &ethhdr->h_dest[0])) {
 				pdata->stats.rx_bytes += bytes_copied;
-				++pdata->stats.rx_packets;
+				pdata->stats.rx_packets++;
 				sk_buff->dev = dev;
 				sk_buff->protocol = eth_type_trans(sk_buff,
 								   dev);
 				if (netif_receive_skb(sk_buff) == NET_RX_DROP)
-					++dropped_by_stack;
+					pdata->dropped_by_stack++;
 			} else {
 				dev_kfree_skb(sk_buff);
 			}
@@ -865,17 +788,14 @@ static void lsinet_rx_packet(struct net_device *dev)
 			dev_kfree_skb(sk_buff);
 
 			if (0 != overflow_stat)
-				++pdata->stats.rx_fifo_errors;
+				pdata->stats.rx_fifo_errors++;
 			else if (0 != crc_stat)
-				++pdata->stats.rx_crc_errors;
+				pdata->stats.rx_crc_errors++;
 			else if (0 != align_stat)
-				++pdata->stats.rx_frame_errors;
+				pdata->stats.rx_frame_errors++;
 		}
 	}
 
-	spin_unlock(&pdata->extra_lock);
-
-	/* That's all. */
 	return;
 }
 
@@ -887,32 +807,34 @@ static void lsinet_rx_packet(struct net_device *dev)
 static int lsinet_rx_packets(struct net_device *dev, int max)
 {
 	struct appnic_device *pdata = netdev_priv(dev);
-	union appnic_queue_pointer queue;
+	union appnic_queue_pointer orig_queue, new_queue;
 	int updated_head_pointer = 0;
 	int packets = 0;
 
-	queue.raw = pdata->rx_tail_copy.raw;
+	new_queue.raw = pdata->rx_tail_copy.raw;
 
 	/* Receive Packets */
 
-	while (0 < queue_initialized(SWAB_QUEUE_POINTER(pdata->rx_tail),
-				     queue, pdata->rx_num_desc)) {
+	orig_queue = swab_queue_pointer(pdata->rx_tail);
+	while (0 < queue_initialized(orig_queue, new_queue,
+				     pdata->rx_num_desc)) {
 		struct appnic_dma_descriptor descriptor;
 
 		readdescriptor(((unsigned long)pdata->rx_desc +
-				  queue.bits.offset),
+				  new_queue.bits.offset),
 				&descriptor);
 
 		if (0 != descriptor.end_of_packet) {
 			lsinet_rx_packet(dev);
-			++packets;
-			queue.raw = pdata->rx_tail_copy.raw;
+			packets++;
+			new_queue.raw = pdata->rx_tail_copy.raw;
 
 			if ((-1 != max) && (packets == max))
 				break;
 		} else {
-			queue_increment(&queue, pdata->rx_num_desc);
+			queue_increment(&new_queue, pdata->rx_num_desc);
 		}
+		orig_queue = swab_queue_pointer(pdata->rx_tail);
 	}
 
 	/* Update the Head Pointer */
@@ -954,37 +876,39 @@ static int lsinet_poll(struct napi_struct *napi, int budget)
 	struct appnic_device *pdata =
 		container_of(napi, struct appnic_device, napi);
 	struct net_device *dev = pdata->device;
-	union appnic_queue_pointer queue;
 
-	int cur_budget = budget;
+	int work_done = 0;
 	unsigned long dma_interrupt_status;
 
-	queue.raw = pdata->rx_tail_copy.raw;
-
 	do {
 		/* Acknowledge the RX interrupt. */
 		write_mac(~APPNIC_DMA_INTERRUPT_ENABLE_RECEIVE,
 			   APPNIC_DMA_INTERRUPT_STATUS);
 
-		cur_budget -= lsinet_rx_packets(dev, cur_budget);
-		if (0 == cur_budget)
+		/* Get Rx packets. */
+		work_done += lsinet_rx_packets(dev, budget - work_done);
+
+		/* We've hit the budget limit. */
+		if (work_done == budget)
 			break;
 
 		dma_interrupt_status = read_mac(APPNIC_DMA_INTERRUPT_STATUS);
 
-	} while ((RX_INTERRUPT(dma_interrupt_status)) && cur_budget);
+	} while (RX_INTERRUPT(dma_interrupt_status));
 
-	napi_complete(napi);
+	if (work_done < budget) {
+		napi_complete(napi);
 
-	/*
-	 * Re-enable receive interrupts (and preserve
-	 * the already enabled TX interrupt).
-	 */
-	write_mac((APPNIC_DMA_INTERRUPT_ENABLE_RECEIVE |
-		   APPNIC_DMA_INTERRUPT_ENABLE_TRANSMIT),
-		  APPNIC_DMA_INTERRUPT_ENABLE);
+		/*
+		 * Re-enable receive interrupts (and preserve
+		 * the already enabled TX interrupt).
+		 */
+		write_mac((APPNIC_DMA_INTERRUPT_ENABLE_RECEIVE |
+			   APPNIC_DMA_INTERRUPT_ENABLE_TRANSMIT),
+			  APPNIC_DMA_INTERRUPT_ENABLE);
+	}
 
-	return 0;
+	return work_done;
 }
 
 /*
@@ -1012,12 +936,12 @@ static irqreturn_t appnic_isr(int irq, void *device_id)
 	/* Handle interrupts */
 	if (TX_INTERRUPT(dma_interrupt_status)) {
 		/* transmition complete */
-		++transmit_interrupts;
+		pdata->transmit_interrupts++;
 		handle_transmit_interrupt(dev);
 	}
 
 	if (RX_INTERRUPT(dma_interrupt_status)) {
-		++receive_interrupts;
+		pdata->receive_interrupts++;
 		if (napi_schedule_prep(&pdata->napi)) {
 
 			/*
@@ -1124,7 +1048,7 @@ static int appnic_stop(struct net_device *dev)
 	napi_disable(&pdata->napi);
 
 	/* Stop the receiver and transmitter. */
-	disable_rx_tx();
+	disable_rx_tx(dev);
 
 	/* Bring the PHY down. */
 	if (pdata->phy_dev)
@@ -1153,6 +1077,7 @@ static int appnic_hard_start_xmit(struct sk_buff *skb,
 	struct appnic_device *pdata = netdev_priv(dev);
 	int length;
 	int buf_per_desc;
+	union appnic_queue_pointer queue;
 
 	length = skb->len < ETH_ZLEN ? ETH_ZLEN : skb->len;
 	buf_per_desc = pdata->tx_buf_sz / pdata->tx_num_desc;
@@ -1161,16 +1086,17 @@ static int appnic_hard_start_xmit(struct sk_buff *skb,
 	 * If enough transmit descriptors are available, copy and transmit.
 	 */
 
+	queue = swab_queue_pointer(pdata->tx_tail);
 	while (((length / buf_per_desc) + 1) >=
 		queue_uninitialized(pdata->tx_head,
-				    SWAB_QUEUE_POINTER(pdata->tx_tail),
+				    queue,
 				    pdata->tx_num_desc)) {
 		handle_transmit_interrupt(dev);
+		queue = swab_queue_pointer(pdata->tx_tail);
 	}
 
 	if (((length / buf_per_desc) + 1) <
-		queue_uninitialized(pdata->tx_head,
-				    SWAB_QUEUE_POINTER(pdata->tx_tail),
+		queue_uninitialized(pdata->tx_head, queue,
 				    pdata->tx_num_desc)) {
 		int bytes_copied = 0;
 		struct appnic_dma_descriptor descriptor;
@@ -1204,11 +1130,12 @@ static int appnic_hard_start_xmit(struct sk_buff *skb,
 				descriptor.data_transfer_length =
 				 (length - bytes_copied);
 				descriptor.end_of_packet = 1;
-#ifdef CONFIG_DISABLE_TX_INTERRUPTS
+				/*
+				 * Leave TX interrupts disabled. We work
+				 * the same with or w/o them. Set to "1"
+				 * if we ever want to enable them though.
+				 */
 				descriptor.interrupt_on_completion = 0;
-#else
-				descriptor.interrupt_on_completion = 1;
-#endif
 				bytes_copied = length;
 			}
 
@@ -1222,22 +1149,22 @@ static int appnic_hard_start_xmit(struct sk_buff *skb,
 			descriptor.start_of_packet = 0;
 		}
 
-#ifdef CONFIG_ARM
-		/* ARM Data sync barrier */
-		asm volatile ("mcr p15,0,%0,c7,c10,4" : : "r" (0));
-#endif
+		/* Data sync barrier */
+		rmb();
+
 		write_mac(pdata->tx_head.raw, APPNIC_DMA_TX_HEAD_POINTER);
 		dev->trans_start = jiffies;
 	} else {
-		++out_of_tx_descriptors;
+		pdata->out_of_tx_descriptors++;
 		pr_err("%s: No transmit descriptors available!\n",
 		       LSI_DRV_NAME);
+		return NETDEV_TX_BUSY;
 	}
 
 	/* Free the socket buffer */
 	dev_kfree_skb(skb);
 
-	return 0;
+	return NETDEV_TX_OK;
 }
 
 /*
@@ -1259,10 +1186,6 @@ static struct net_device_stats *appnic_get_stats(struct net_device *dev)
 
 	get_hw_statistics(pdata);
 
-	/*
-	 * That's all.
-	 */
-
 	return &pdata->stats;
 }
 
@@ -1273,14 +1196,18 @@ static struct net_device_stats *appnic_get_stats(struct net_device *dev)
 
 static int appnic_set_mac_address(struct net_device *dev, void *data)
 {
+	struct appnic_device *pdata = netdev_priv(dev);
 	struct sockaddr *address = data;
 	unsigned long swap_source_address;
 
 	if (netif_running(dev))
 		return -EBUSY;
 
-	memcpy(dev->dev_addr, address->sa_data, 6);
-	memcpy(dev->perm_addr, address->sa_data, 6);
+	if (!is_valid_ether_addr(address->sa_data))
+		return -EADDRNOTAVAIL;
+
+	memcpy(dev->dev_addr, address->sa_data, ETH_ALEN);
+	memcpy(dev->perm_addr, address->sa_data, ETH_ALEN);
 
 	swap_source_address = ((address->sa_data[4]) << 8) |
 			       address->sa_data[5];
@@ -1297,10 +1224,106 @@ static int appnic_set_mac_address(struct net_device *dev, void *data)
 }
 
 /*
-  ======================================================================
-  ETHTOOL Operations
-  ======================================================================
-*/
+ * ======================================================================
+ * ETHTOOL Operations
+ * ======================================================================
+ */
+
+enum {NETDEV_STATS, APPNIC_STATS};
+
+struct appnic_stats {
+	char stat_string[ETH_GSTRING_LEN];
+	int sizeof_stat;
+	int stat_offset;
+};
+
+#define APPNIC_STAT(str, m) { \
+		.stat_string = str, \
+		.sizeof_stat = sizeof(((struct appnic_device *)0)->m), \
+		.stat_offset = offsetof(struct appnic_device, m) }
+
+static const struct appnic_stats appnic_gstrings_stats[] = {
+	APPNIC_STAT("rx_packets", stats.rx_packets),
+	APPNIC_STAT("tx_packets", stats.tx_packets),
+	APPNIC_STAT("rx_bytes", stats.rx_bytes),
+	APPNIC_STAT("tx_bytes", stats.tx_bytes),
+	APPNIC_STAT("rx_errors", stats.rx_errors),
+	APPNIC_STAT("tx_errors", stats.tx_errors),
+	APPNIC_STAT("rx_dropped", stats.rx_dropped),
+	APPNIC_STAT("tx_dropped", stats.tx_dropped),
+	APPNIC_STAT("multicast", stats.multicast),
+	APPNIC_STAT("collisions", stats.collisions),
+	APPNIC_STAT("rx_length_errors", stats.rx_length_errors),
+	APPNIC_STAT("rx_crc_errors", stats.rx_crc_errors),
+	APPNIC_STAT("rx_frame_errors", stats.rx_frame_errors),
+	APPNIC_STAT("rx_fifo_errors", stats.rx_fifo_errors),
+	APPNIC_STAT("tx_fifo_errors", stats.tx_fifo_errors),
+
+	APPNIC_STAT("dropped_by_stack", dropped_by_stack),
+	APPNIC_STAT("out_of_tx_descriptors", out_of_tx_descriptors),
+	APPNIC_STAT("transmit_interrupts", transmit_interrupts),
+	APPNIC_STAT("receive_interrupts", receive_interrupts),
+};
+#define APPNIC_GLOBAL_STATS_LEN  ARRAY_SIZE(appnic_gstrings_stats)
+#define APPNIC_STATS_LEN (APPNIC_GLOBAL_STATS_LEN)
+
+/*
+ * ----------------------------------------------------------------------
+ * appnic_get_ethtool_stats
+ */
+
+static void appnic_get_ethtool_stats(struct net_device *dev,
+				     struct ethtool_stats *stats,
+				     u64 *data)
+{
+	struct appnic_device *pdata = netdev_priv(dev);
+	int i;
+	char *p = NULL;
+
+	get_hw_statistics(pdata);
+	for (i = 0; i < APPNIC_GLOBAL_STATS_LEN; i++) {
+		p = (char *) pdata + appnic_gstrings_stats[i].stat_offset;
+		data[i] = (appnic_gstrings_stats[i].sizeof_stat ==
+			sizeof(u64)) ? *(u64 *)p : *(u32 *)p;
+	}
+}
+
+/*
+ * ----------------------------------------------------------------------
+ * appnic_get_strings
+ */
+
+static void appnic_get_strings(struct net_device *netdev, u32 stringset,
+			       u8 *data)
+{
+	u8 *p = data;
+	int i;
+
+	switch (stringset) {
+	case ETH_SS_STATS:
+		for (i = 0; i < APPNIC_GLOBAL_STATS_LEN; i++) {
+			memcpy(p, appnic_gstrings_stats[i].stat_string,
+			       ETH_GSTRING_LEN);
+			p += ETH_GSTRING_LEN;
+		}
+		break;
+	}
+}
+
+/*
+ * ----------------------------------------------------------------------
+ * appnic_get_sset_count
+ */
+
+static int appnic_get_sset_count(struct net_device *netdev, int sset)
+{
+	switch (sset) {
+	case ETH_SS_STATS:
+		return APPNIC_STATS_LEN;
+	default:
+		return -EOPNOTSUPP;
+	}
+}
 
 /*
  * ----------------------------------------------------------------------
@@ -1312,6 +1335,8 @@ static void appnic_get_drvinfo(struct net_device *dev,
 {
 	strcpy(info->driver, LSI_DRV_NAME);
 	strcpy(info->version, LSI_DRV_VERSION);
+	strlcpy(info->bus_info, dev_name(dev->dev.parent),
+		sizeof(info->bus_info));
 }
 
 /*
@@ -1336,16 +1361,19 @@ static int appnic_get_settings(struct net_device *dev,
  */
 
 static const struct ethtool_ops appnic_ethtool_ops = {
-	.get_drvinfo = appnic_get_drvinfo,
-	.get_settings = appnic_get_settings
+	.get_drvinfo		= appnic_get_drvinfo,
+	.get_settings		= appnic_get_settings,
+	.get_ethtool_stats	= appnic_get_ethtool_stats,
+	.get_strings		= appnic_get_strings,
+	.get_sset_count		= appnic_get_sset_count,
 };
 
 
 /*
-  ======================================================================
-  Linux Module Interface.
-  ======================================================================
-*/
+ * ======================================================================
+ * Linux Module Interface.
+ * ======================================================================
+ */
 
 static const struct net_device_ops appnic_netdev_ops = {
 	.ndo_open = appnic_open,
@@ -1373,13 +1401,10 @@ int appnic_init(struct net_device *dev)
 	struct appnic_dma_descriptor descriptor;
 	struct sockaddr address;
 	unsigned long node_cfg;
+	int rc = 0;
 
-#ifdef CONFIG_ARM
 	/* Set FEMAC to uncached */
-	gpreg_base = ioremap(GPREG_BASE, 0x1000);
-	writel(0x0, gpreg_base+0x78);
-#endif
-
+	femac_uncache(pdata);
 
 	/*
 	 * Reset the MAC
@@ -1397,19 +1422,19 @@ int appnic_init(struct net_device *dev)
 	 */
 
 	if (0 != (rx_num_desc % DESCRIPTOR_GRANULARITY)) {
-		pr_warn("%s: rx_num_desc was not a multiple of %d.\n",
-			LSI_DRV_NAME, DESCRIPTOR_GRANULARITY);
-		rx_num_desc += DESCRIPTOR_GRANULARITY -
-				(rx_num_desc % DESCRIPTOR_GRANULARITY);
+		pr_err("%s: rx_num_desc was not a multiple of %d.\n",
+		       LSI_DRV_NAME, DESCRIPTOR_GRANULARITY);
+		rc = -EINVAL;
+		goto err_param;
 	}
 
 	pdata->rx_num_desc = rx_num_desc;
 
 	if (0 != (tx_num_desc % DESCRIPTOR_GRANULARITY)) {
-		pr_warn("%s: tx_num_desc was not a multiple of %d.\n",
-			LSI_DRV_NAME, DESCRIPTOR_GRANULARITY);
-		tx_num_desc += DESCRIPTOR_GRANULARITY -
-			(tx_num_desc % DESCRIPTOR_GRANULARITY);
+		pr_err("%s: tx_num_desc was not a multiple of %d.\n",
+		       LSI_DRV_NAME, DESCRIPTOR_GRANULARITY);
+		rc = -EINVAL;
+		goto err_param;
 	}
 
 	pdata->tx_num_desc = tx_num_desc;
@@ -1420,19 +1445,19 @@ int appnic_init(struct net_device *dev)
 	 */
 
 	if (0 != (rx_buf_sz % (BUFFER_ALIGNMENT * rx_num_desc))) {
-		pr_warn("%s: rx_buf_sz was not a multiple of %d.\n",
-			LSI_DRV_NAME, (BUFFER_ALIGNMENT * rx_num_desc));
-		rx_buf_sz += (BUFFER_ALIGNMENT * rx_num_desc) -
-				(rx_buf_sz % (BUFFER_ALIGNMENT * rx_num_desc));
+		pr_err("%s: rx_buf_sz was not a multiple of %d.\n",
+		       LSI_DRV_NAME, (BUFFER_ALIGNMENT * rx_num_desc));
+		rc = -EINVAL;
+		goto err_param;
 	}
 
 	pdata->rx_buf_sz = rx_buf_sz;
 
 	if (0 != (tx_buf_sz % (BUFFER_ALIGNMENT * tx_num_desc))) {
-		pr_warn("%s: tx_buf_sz was not a multiple of %d.\n",
-			LSI_DRV_NAME, (BUFFER_ALIGNMENT * tx_num_desc));
-		tx_buf_sz += (BUFFER_ALIGNMENT * tx_num_desc) -
-			(tx_buf_sz % (BUFFER_ALIGNMENT * tx_num_desc));
+		pr_err("%s: tx_buf_sz was not a multiple of %d.\n",
+		       LSI_DRV_NAME, (BUFFER_ALIGNMENT * tx_num_desc));
+		rc = -EINVAL;
+		goto err_param;
 	}
 
 	pdata->tx_buf_sz = tx_buf_sz;
@@ -1464,80 +1489,15 @@ int appnic_init(struct net_device *dev)
 		(pdata->tx_buf_sz) + (BUFFER_ALIGNMENT);
 
 	/*
-	 * This needs to be set to something sane for
-	 * dma_alloc_coherent()
+	 * Allocate the buffers.
 	 */
 
-#if defined(CONFIG_ARM)
-	pdata->dma_alloc = (void *)
-		dma_alloc_coherent(NULL,
-				   pdata->dma_alloc_size,
-				   &pdata->dma_alloc_dma,
-				   GFP_KERNEL);
-#else
-	dev->dev.archdata.dma_ops = &dma_direct_ops;
-
-	pdata->dma_alloc = (void *)
-		dma_alloc_coherent(&dev->dev,
-				   pdata->dma_alloc_size,
-				   &pdata->dma_alloc_dma,
-				   GFP_KERNEL);
-#endif
-
-	if ((void *)0 == pdata->dma_alloc) {
-		pr_err("%s: Can't allocate %d bytes of DMA-able memory!\n",
-		       LSI_DRV_NAME, pdata->dma_alloc_size);
-		kfree(pdata);
-		return -ENOMEM;
-	}
-
-	pdata->dma_alloc_offset = (int)pdata->dma_alloc -
-					(int)pdata->dma_alloc_dma;
-
-#ifdef CONFIG_ARM
-	pdata->dma_alloc_rx = (void *)dma_alloc_coherent(NULL,
-#else
-	pdata->dma_alloc_rx = (void *)dma_alloc_coherent(&dev->dev,
-#endif
-						    pdata->dma_alloc_size_rx,
-						    &pdata->dma_alloc_dma_rx,
-						    GFP_KERNEL);
-
-	if ((void *)0 == pdata->dma_alloc_rx) {
-		pr_err("%s: Can't allocate %d bytes of RX DMA-able memory!\n",
-		       LSI_DRV_NAME, pdata->dma_alloc_size_rx);
-		dma_free_coherent(&dev->dev, pdata->dma_alloc_size,
-				  pdata->dma_alloc, pdata->dma_alloc_dma);
-		kfree(pdata);
-		return -ENOMEM;
+	rc = femac_alloc_mem_buffers(dev);
+	if (rc != 0) {
+		pr_err("%s: Can't allocate DMA-able memory!\n", LSI_DRV_NAME);
+		goto err_mem_buffers;
 	}
 
-	pdata->dma_alloc_offset_rx = (int)pdata->dma_alloc_rx -
-					(int)pdata->dma_alloc_dma_rx;
-
-#ifdef CONFIG_ARM
-	pdata->dma_alloc_tx = (void *)dma_alloc_coherent(NULL,
-#else
-	pdata->dma_alloc_tx = (void *)dma_alloc_coherent(&dev->dev,
-#endif
-						    pdata->dma_alloc_size_tx,
-						    &pdata->dma_alloc_dma_tx,
-						    GFP_KERNEL);
-
-	if ((void *)0 == pdata->dma_alloc_tx) {
-		pr_err("%s: Can't allocate %d bytes of TX DMA-able memory!\n",
-		       LSI_DRV_NAME, pdata->dma_alloc_size_tx);
-		dma_free_coherent(&dev->dev, pdata->dma_alloc_size,
-				  pdata->dma_alloc, pdata->dma_alloc_dma);
-		dma_free_coherent(&dev->dev, pdata->dma_alloc_size_rx,
-				  pdata->dma_alloc_rx, pdata->dma_alloc_dma_rx);
-		kfree(pdata);
-		return -ENOMEM;
-	}
-
-	pdata->dma_alloc_offset_tx = (int)pdata->dma_alloc_tx -
-					(int)pdata->dma_alloc_dma_tx;
-
 	/*
 	 * Initialize the tail pointers
 	 */
@@ -1556,7 +1516,6 @@ int appnic_init(struct net_device *dev)
 	dma_offset += sizeof(union appnic_queue_pointer);
 	memset((void *)pdata->tx_tail, 0, sizeof(union appnic_queue_pointer));
 
-
 	/*
 	 * Initialize the descriptor pointers
 	 */
@@ -1634,7 +1593,6 @@ int appnic_init(struct net_device *dev)
 	 */
 
 	spin_lock_init(&pdata->dev_lock);
-	spin_lock_init(&pdata->extra_lock);
 
 	/*
 	 * Take MAC out of reset
@@ -1665,22 +1623,24 @@ int appnic_init(struct net_device *dev)
 	write_mac(0x40010000, APPNIC_DMA_PCI_CONTROL);
 	write_mac(0x30000, APPNIC_DMA_CONTROL);
 #ifdef CONFIG_ARM
-	writel(0x280044, dma_base + 0x60);
-	writel(0xc0, dma_base + 0x64);
+	writel(0x280044, (unsigned long)pdata->dma_base + 0x60);
+	writel(0xc0, (unsigned long)pdata->dma_base + 0x64);
 #else
-	out_le32(dma_base + 0x60, 0x280044);
-	out_le32(dma_base + 0x64, 0xc0);
+	out_le32((unsigned *)pdata->dma_base + 0x60, 0x280044);
+	out_le32((unsigned *)pdata->dma_base + 0x64, 0xc0);
 #endif
 
 	/*
 	 * Set the MAC address
 	 */
-	pr_info("%s: MAC %02x:%02x:%02x:%02x:%02x:%02x\n", LSI_DRV_NAME,
-		dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
-		dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);
+	pr_info("%s: MAC %pM\n", LSI_DRV_NAME, dev->dev_addr);
 
-	memcpy(&(address.sa_data[0]), dev->dev_addr, 6);
-	appnic_set_mac_address(dev, &address);
+	memcpy(&(address.sa_data[0]), dev->dev_addr, ETH_ALEN);
+	rc = appnic_set_mac_address(dev, &address);
+	if (rc != 0) {
+		pr_err("%s: Unable to set MAC address!\n", LSI_DRV_NAME);
+		goto err_set_mac_addr;
+	}
 
 	/*
 	 * Initialize the queue pointers.
@@ -1761,48 +1721,30 @@ int appnic_init(struct net_device *dev)
 	/* Fill in the net_device structure */
 
 	ether_setup(dev);
-#ifdef CONFIG_ARM
-	dev->irq = pdata->dma_interrupt;
-#else
-	dev->irq = irq_create_mapping(NULL, pdata->dma_interrupt);
-	if (NO_IRQ == dev->irq) {
-		pr_err("%s: irq_create_mapping() failed\n", LSI_DRV_NAME);
-		return -EBUSY;
-	}
 
-	if (0 != irq_set_irq_type(dev->irq, IRQ_TYPE_LEVEL_HIGH)) {
-		pr_err("%s: set_irq_type() failed\n", LSI_DRV_NAME);
-		return -EBUSY;
+	/* Setup IRQ */
+	rc = femac_irq_setup(dev);
+	if (rc != 0) {
+		pr_err("%s: IRQ setup failed!\n", LSI_DRV_NAME);
+		goto err_irq_setup;
 	}
-#endif
 
 	dev->netdev_ops = &appnic_netdev_ops;
+	dev->ethtool_ops = &appnic_ethtool_ops;
 
-	SET_ETHTOOL_OPS(dev, &appnic_ethtool_ops);
 	memset((void *) &pdata->napi, 0, sizeof(struct napi_struct));
 	netif_napi_add(dev, &pdata->napi,
 		       lsinet_poll, LSINET_NAPI_WEIGHT);
 	pdata->device = dev;
 
-	/* That's all */
 	return 0;
-}
-
-/*
- * ----------------------------------------------------------------------
- * appnic_read_proc
- */
-
-static int
-appnic_read_proc(char *page, char **start, off_t offset,
-		 int count, int *eof, void *data)
-{
-	int length;
-
-	length = sprintf(page, "-- appnic.c -- Profiling is disabled\n");
 
-	/* That's all */
-	return length;
+err_irq_setup:
+err_set_mac_addr:
+	femac_free_mem_buffers(dev);
+err_mem_buffers:
+err_param:
+	return rc;
 }
 
 /*
@@ -1816,9 +1758,11 @@ static int __devinit appnic_probe_config_dt(struct net_device *dev,
 {
 	struct appnic_device *pdata = netdev_priv(dev);
 	const u32 *field;
+	const char *mac;
 	const char *macspeed;
-	int length;
-#ifndef CONFIG_ARM
+#ifdef CONFIG_ARM
+	struct device_node *gp_node;
+#else
 	u64 value64;
 	u32 value32;
 #endif
@@ -1827,44 +1771,44 @@ static int __devinit appnic_probe_config_dt(struct net_device *dev,
 		return -ENODEV;
 
 #ifdef CONFIG_ARM
-	rx_base = of_iomap(np, 0);
-	tx_base = of_iomap(np, 1);
-	dma_base = of_iomap(np, 2);
+	gp_node = of_find_compatible_node(NULL, NULL, "lsi,gpreg");
+	if (!gp_node) {
+		pr_err("%s: DTS is missing mode 'gpreg'\n", LSI_DRV_NAME);
+		return -ENODEV;
+	}
+	pdata->gpreg_base = of_iomap(gp_node, 0);
+
+	pdata->rx_base = of_iomap(np, 0);
+	pdata->tx_base = of_iomap(np, 1);
+	pdata->dma_base = of_iomap(np, 2);
+
+	pdata->tx_interrupt = irq_of_parse_and_map(np, 0);
+	pdata->rx_interrupt = irq_of_parse_and_map(np, 1);
+	pdata->dma_interrupt = irq_of_parse_and_map(np, 2);
 #else
 	field = of_get_property(np, "enabled", NULL);
 
 	if (!field || (field && (0 == *field)))
-		return -EINVAL;
+		goto device_tree_failed;
 
 	field = of_get_property(np, "reg", NULL);
 
-	if (!field) {
-		pr_err("%s: Couldn't get \"reg\" property.", LSI_DRV_NAME);
-		return -EINVAL;
-	}
+	if (!field)
+		goto device_tree_failed;
 
 	value64 = of_translate_address(np, field);
 	value32 = field[1];
 	field += 2;
-	rx_base = ioremap(value64, value32);
+	pdata->rx_base = ioremap(value64, value32);
 	value64 = of_translate_address(np, field);
 	value32 = field[1];
 	field += 2;
-	tx_base = ioremap(value64, value32);
+	pdata->tx_base = ioremap(value64, value32);
 	value64 = of_translate_address(np, field);
 	value32 = field[1];
 	field += 2;
-	dma_base = ioremap(value64, value32);
-#endif
-	pdata->rx_base = (unsigned long)rx_base;
-	pdata->tx_base = (unsigned long)tx_base;
-	pdata->dma_base = (unsigned long)dma_base;
+	pdata->dma_base = ioremap(value64, value32);
 
-#ifdef CONFIG_ARM
-	pdata->tx_interrupt = irq_of_parse_and_map(np, 0);
-	pdata->rx_interrupt = irq_of_parse_and_map(np, 1);
-	pdata->dma_interrupt = irq_of_parse_and_map(np, 2);
-#else
 	field = of_get_property(np, "interrupts", NULL);
 	if (!field)
 		goto device_tree_failed;
@@ -1922,32 +1866,25 @@ static int __devinit appnic_probe_config_dt(struct net_device *dev,
 		pdata->phy_link_auto = 1;
 	}
 
-	field = of_get_property(np, "mac-address", &length);
-	if (!field || 6 != length) {
+	mac = of_get_mac_address(np);
+	if (!mac)
 		goto device_tree_failed;
-	} else {
-		int i;
-		u8 *value;
-
-		value = (u8 *)field;
 
-		for (i = 0; i < 6; ++i)
-			pdata->mac_addr[i] = value[i];
-	}
-
-	memcpy(dev->dev_addr, &pdata->mac_addr[0], 6);
-	memcpy(dev->perm_addr, &pdata->mac_addr[0], 6);
+	memcpy(&pdata->mac_addr[0], mac, ETH_ALEN);
+	memcpy(dev->dev_addr, mac, ETH_ALEN);
+	memcpy(dev->perm_addr, mac, ETH_ALEN);
 
 	return 0;
 
 device_tree_failed:
 	pr_err("%s: Reading Device Tree Failed\n", LSI_DRV_NAME);
-	iounmap(rx_base);
-	iounmap(tx_base);
-	iounmap(dma_base);
 #ifdef CONFIG_ARM
-	iounmap(gpreg_base);
+	iounmap(pdata->gpreg_base);
 #endif
+	iounmap(pdata->rx_base);
+	iounmap(pdata->tx_base);
+	iounmap(pdata->dma_base);
+
 	return -EINVAL;
 }
 #else
@@ -1979,7 +1916,7 @@ static int __devinit appnic_drv_probe(struct platform_device *pdev)
 	if (!dev) {
 		pr_err("%s: Couldn't allocate net device.\n", LSI_DRV_NAME);
 		rc = -ENOMEM;
-		goto out;
+		goto err_alloc_etherdev;
 	}
 
 	SET_NETDEV_DEV(dev, &pdev->dev);
@@ -1996,13 +1933,13 @@ static int __devinit appnic_drv_probe(struct platform_device *pdev)
 	rc = appnic_probe_config_dt(dev, np);
 
 	if (rc == -EINVAL) {
-		goto out;
-	} else if (rc == -ENODEV) {
+		goto err_inval;
+	} else if (rc == -EINVAL) {
 
 #ifdef CONFIG_MTD_NAND_EP501X_UBOOTENV
 
 		/*
-		 * Attempt to get device settings from the DTB failed, so
+		 * The attempt to get device settings from the DTB failed, so
 		 * try to grab the ethernet MAC from the u-boot environment
 		 * and use hard-coded values for device base addresses.
 		 */
@@ -2012,14 +1949,14 @@ static int __devinit appnic_drv_probe(struct platform_device *pdev)
 		if (0 != ubootenv_get("ethaddr", ethaddr_string)) {
 			pr_err("%s: Could not read ethernet address!\n",
 			       LSI_DRV_NAME);
-			return -EFAULT;
+			rc = -EINVAL;
+			goto err_inval;
 		} else {
-
-			u8 mac_address[6];
+			u8 mac_address[ETH_ALEN];
 			int i = 0;
 			char *string = ethaddr_string;
 
-			while ((0 != string) && (6 > i)) {
+			while ((0 != string) && (ETH_ALEN > i)) {
 				char *value;
 				unsigned long res;
 				value = strsep(&string, ":");
@@ -2028,29 +1965,23 @@ static int __devinit appnic_drv_probe(struct platform_device *pdev)
 				mac_address[i++] = (u8)res;
 			}
 
-			memcpy(dev->dev_addr, mac_address, 6);
-			memcpy(dev->perm_addr, mac_address, 6);
-			dev->addr_len = 6;
+			memcpy(dev->dev_addr, mac_address, ETH_ALEN);
+			memcpy(dev->perm_addr, mac_address, ETH_ALEN);
+			dev->addr_len = ETH_ALEN;
 
 			pr_info("%s: Using Static Addresses and Interrupts",
 				LSI_DRV_NAME);
-			rx_base = ioremap(0x002000480000ULL, 0x1000);
-			pdata->rx_base =
-			 (unsigned long)ioremap(0x002000480000ULL, 0x1000);
-			tx_base = ioremap(0x002000481000ULL, 0x1000);
-			pdata->tx_base =
-			(unsigned long)ioremap(0x002000481000ULL, 0x1000);
-			dma_base = ioremap(0x002000482000ULL, 0x1000);
-			pdata->dma_base =
-			 (unsigned long)ioremap(0x002000482000ULL, 0x1000);
+			pdata->rx_base = ioremap(0x002000480000ULL, 0x1000);
+			pdata->tx_base = ioremap(0x002000481000ULL, 0x1000);
+			pdata->dma_base = ioremap(0x002000482000ULL, 0x1000);
 			pdata->dma_interrupt = 33;
 		}
 #else
 		/* Neither dtb info nor ubootenv driver found. */
 		pr_err("%s: Could not read ethernet address!", LSI_DRV_NAME);
-		return -EBUSY;
+		rc = -EINVAL;
+		goto err_inval;
 #endif
-
 	}
 
 #ifdef CONFIG_MTD_NAND_EP501X_UBOOTENV
@@ -2065,8 +1996,10 @@ static int __devinit appnic_drv_probe(struct platform_device *pdev)
 			 * since u-boot defaults this value as hex.
 			 */
 			unsigned long res;
-			if (kstrtoul(uboot_env_string, 16, &res))
-				return -EBUSY;
+			if (kstrtoul(uboot_env_string, 16, &res)) {
+				rc = -EINVAL;
+				goto err_inval;
+			}
 			pdata->ad_value = res;
 		}
 	}
@@ -2078,7 +2011,7 @@ static int __devinit appnic_drv_probe(struct platform_device *pdev)
 	if (0 != rc) {
 		pr_err("%s: appnic_init() failed: %d\n", LSI_DRV_NAME, rc);
 		rc = -ENODEV;
-		goto out;
+		goto err_nodev;
 	}
 
 	/* Register the device. */
@@ -2086,7 +2019,7 @@ static int __devinit appnic_drv_probe(struct platform_device *pdev)
 	if (0 != rc) {
 		pr_err("%s: register_netdev() failed: %d\n", LSI_DRV_NAME, rc);
 		rc = -ENODEV;
-		goto out;
+		goto err_nodev;
 	}
 
 	/* Initialize the PHY. */
@@ -2094,14 +2027,17 @@ static int __devinit appnic_drv_probe(struct platform_device *pdev)
 	if (rc) {
 		pr_warn("%s: Failed to initialize PHY", LSI_DRV_NAME);
 		rc = -ENODEV;
-		goto out;
+		goto err_mii_init;
 	}
 
-	/* Create the /proc entry. */
-	create_proc_read_entry("driver/appnic", 0, NULL,
-				appnic_read_proc, NULL);
+	return 0;
 
-out:
+err_mii_init:
+	unregister_netdev(dev);
+err_nodev:
+err_inval:
+	free_netdev(dev);
+err_alloc_etherdev:
 	return rc;
 }
 
@@ -2113,35 +2049,29 @@ out:
 static int __devexit appnic_drv_remove(struct platform_device *pdev)
 {
 	struct net_device *dev = platform_get_drvdata(pdev);
-	struct appnic_device *pdata;
+	struct appnic_device *pdata = NULL;
 
 	pr_info("%s: Stopping driver", LSI_DRV_NAME);
 
-	remove_proc_entry("driver/appnic", NULL);
-
-	if (dev) {
-		pdata = netdev_priv(dev);
-		if (pdata->phy_dev)
-			phy_disconnect(pdata->phy_dev);
-		mdiobus_unregister(pdata->mii_bus);
-		mdiobus_free(pdata->mii_bus);
-		platform_set_drvdata(pdev, NULL);
-		unregister_netdev(dev);
-		free_irq(dev->irq, dev);
-		dma_free_coherent(&dev->dev, pdata->dma_alloc_size,
-				  pdata->dma_alloc, pdata->dma_alloc_dma);
-		dma_free_coherent(&dev->dev, pdata->dma_alloc_size_rx,
-				  pdata->dma_alloc_rx, pdata->dma_alloc_dma_rx);
-		dma_free_coherent(&dev->dev, pdata->dma_alloc_size_tx,
-				  pdata->dma_alloc_tx, pdata->dma_alloc_dma_tx);
-		free_netdev(dev);
-	}
+	BUG_ON(!dev);
+	pdata = netdev_priv(dev);
+	BUG_ON(!pdata);
+	BUG_ON(!pdata->phy_dev);
+	phy_disconnect(pdata->phy_dev);
+	pdata->phy_dev = NULL;
+	mdiobus_unregister(pdata->mii_bus);
+	mdiobus_free(pdata->mii_bus);
+	platform_set_drvdata(pdev, NULL);
+	unregister_netdev(dev);
+	free_irq(dev->irq, dev);
+	femac_free_mem_buffers(dev);
+	free_netdev(dev);
 
-	iounmap(rx_base);
-	iounmap(tx_base);
-	iounmap(dma_base);
+	iounmap(pdata->rx_base);
+	iounmap(pdata->tx_base);
+	iounmap(pdata->dma_base);
 #ifdef CONFIG_ARM
-	iounmap(gpreg_base);
+	iounmap(pdata->gpreg_base);
 #endif
 
 	return 0;
@@ -2163,17 +2093,4 @@ static struct platform_driver appnic_driver = {
 	},
 };
 
-/* Entry point for loading the module */
-static int __init appnic_init_module(void)
-{
-	return platform_driver_register(&appnic_driver);
-}
-
-/* Entry point for unloading the module */
-static void __exit appnic_cleanup_module(void)
-{
-	platform_driver_unregister(&appnic_driver);
-}
-
-module_init(appnic_init_module);
-module_exit(appnic_cleanup_module);
+module_platform_driver(appnic_driver);
diff --git a/drivers/net/ethernet/lsi/lsi_acp_net.h b/drivers/net/ethernet/lsi/lsi_acp_net.h
index 7b6f2b3..00e02f6 100644
--- a/drivers/net/ethernet/lsi/lsi_acp_net.h
+++ b/drivers/net/ethernet/lsi/lsi_acp_net.h
@@ -1,7 +1,7 @@
 /*
  * drivers/net/ethernet/lsi/lsi_acp_net.h
  *
- * Copyright (C) 2013 LSI
+ * Copyright (C) 2013 LSI Corporation.
  *
  * 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
@@ -33,14 +33,18 @@ extern int ubootenv_get(const char *, char *);
 #define LSINET_NAPI_WEIGHT	64
 
 /*
-  ======================================================================
-  Device Data Structures
-  ======================================================================
-*/
+ * This is the maximum number of bytes that serve to hold
+ * incoming Rx data.
+ */
+#define LSINET_MAX_MTU		(ETH_DATA_LEN + 100) /* MTU + padding */
+
+/*
+ * Device Data Structures
+ */
 
 struct appnic_dma_descriptor {
 
-#ifdef CONFIG_ARM
+#ifdef __LITTLE_ENDIAN
 	/* Word 0 */
 	/* 00=Fill|01=Block|10=Scatter */
 	unsigned long transfer_type:2;
@@ -93,7 +97,7 @@ union appnic_queue_pointer {
 	unsigned long raw;
 
 	struct {
-#ifdef CONFIG_ARM
+#ifdef __LITTLE_ENDIAN
 		unsigned long offset:20;
 		unsigned long generation_bit:1;
 		unsigned long unused:11;
@@ -107,10 +111,8 @@ union appnic_queue_pointer {
 } __packed;
 
 /*
-  =============================================================================
-  The appnic Device Structure
-  =============================================================================
-*/
+ * The appnic Device Structure
+ */
 
 struct appnic_device {
 
@@ -118,9 +120,12 @@ struct appnic_device {
 	struct net_device *device;
 
 	/* Addresses, Interrupt, and PHY stuff. */
-	unsigned long rx_base;
-	unsigned long tx_base;
-	unsigned long dma_base;
+	void __iomem *rx_base;
+	void __iomem *tx_base;
+	void __iomem *dma_base;
+#ifdef CONFIG_ARM
+	void __iomem *gpreg_base;
+#endif
 	unsigned long tx_interrupt;
 	unsigned long rx_interrupt;
 	unsigned long dma_interrupt;
@@ -135,8 +140,12 @@ struct appnic_device {
 	/* NAPI */
 	struct napi_struct napi;
 
-	/* statistics */
+	/* Statistics */
 	struct net_device_stats stats;
+	unsigned long dropped_by_stack;
+	unsigned long out_of_tx_descriptors;
+	unsigned long transmit_interrupts;
+	unsigned long receive_interrupts;
 
 	/* DMA-able memory */
 	int dma_alloc_size;
@@ -184,7 +193,6 @@ struct appnic_device {
 
 	/* Spin Lock */
 	spinlock_t dev_lock;
-	spinlock_t extra_lock;
 
 	/* PHY */
 	struct mii_bus *mii_bus;
@@ -195,6 +203,10 @@ struct appnic_device {
 	unsigned int duplex;
 };
 
+/* GPREG FEMAC HPROT Register --------------------------------------- */
+
+#define GPREG_HPROT_FEMAC	((unsigned long)pdata->gpreg_base + 0x78)
+
 /*
  * Overview
  * --------
@@ -220,7 +232,7 @@ struct appnic_device {
 
 /* Receive Configuration -------------------------------------------- */
 
-#define APPNIC_RX_CONF		(rx_base + 0x004c)
+#define APPNIC_RX_CONF		((unsigned long)pdata->rx_base + 0x004c)
 #define APPNIC_RX_CONF_ENABLE   0x0001
 /* Pass Any Packet */
 #define APPNIC_RX_CONF_PAP	0x0002
@@ -240,73 +252,75 @@ struct appnic_device {
 #define APPNIC_RX_CONF_LINK	0x2000
 /*
  * Determines the action taken when the FE MAC
- * receives an FC packet in FD mode.
+ * receives an Flow Control packet in FD mode.
  */
 #define APPNIC_RX_CONF_RXFCE    0x4000
 /*
- * Controls the insertion of FC packets
+ * Controls the insertion of Flow Control packets
  * by the MAC transmitter.
  */
 #define APPNIC_RX_CONF_TXFCE    0x8000
 
 /* Receive Stat Overflow -------------------------------------------- */
 
-#define APPNIC_RX_STAT_OVERFLOW (rx_base + 0x278)
+#define APPNIC_RX_STAT_OVERFLOW ((unsigned long)pdata->rx_base + 0x278)
 
 /* Receive Stat Undersize ------------------------------------------- */
 
-#define APPNIC_RX_STAT_UNDERSIZE (rx_base + 0x280)
+#define APPNIC_RX_STAT_UNDERSIZE ((unsigned long)pdata->rx_base + 0x280)
 
 /* Receive Stat Oversize -------------------------------------------- */
 
-#define APPNIC_RX_STAT_OVERSIZE (rx_base + 0x2b8)
+#define APPNIC_RX_STAT_OVERSIZE ((unsigned long)pdata->rx_base + 0x2b8)
 
 /* Receive Stat Multicast ------------------------------------------- */
 
-#define APPNIC_RX_STAT_MULTICAST (rx_base + 0x2d0)
+#define APPNIC_RX_STAT_MULTICAST ((unsigned long)pdata->rx_base + 0x2d0)
 
 /* Receive Stat Packet OK ------------------------------------------- */
 
-#define APPNIC_RX_STAT_PACKET_OK (rx_base + 0x2c0)
+#define APPNIC_RX_STAT_PACKET_OK ((unsigned long)pdata->rx_base + 0x2c0)
 
 /* Receive Stat CRC Error ------------------------------------------- */
 
-#define APPNIC_RX_STAT_CRC_ERROR (rx_base + 0x2c8)
+#define APPNIC_RX_STAT_CRC_ERROR ((unsigned long)pdata->rx_base + 0x2c8)
 
 /* Receive Stat Align Error ----------------------------------------- */
 
-#define APPNIC_RX_STAT_ALIGN_ERROR (rx_base + 0x2e8)
+#define APPNIC_RX_STAT_ALIGN_ERROR ((unsigned long)pdata->rx_base + 0x2e8)
 
 /* Receive Ethernet Mode -------------------------------------------- */
 
-#define APPNIC_RX_MODE (rx_base + 0x0800)
+#define APPNIC_RX_MODE ((unsigned long)pdata->rx_base + 0x0800)
 #define APPNIC_RX_MODE_ETHERNET_MODE_ENABLE 0x00001
 
 /* Receive Soft Reset ----------------------------------------------- */
 
-#define APPNIC_RX_SOFT_RESET (rx_base + 0x0808)
+#define APPNIC_RX_SOFT_RESET ((unsigned long)pdata->rx_base + 0x0808)
 #define APPNIC_RX_SOFT_RESET_MAC_0 0x00001
 
 /* Receive Internal Interrupt Control ------------------------------- */
 
-#define APPNIC_RX_INTERNAL_INTERRUPT_CONTROL (rx_base + 0xc00)
+#define APPNIC_RX_INTERNAL_INTERRUPT_CONTROL \
+	((unsigned long)pdata->rx_base + 0xc00)
 #define APPNIC_RX_INTERNAL_INTERRUPT_CONTROL_MAC_0 0x1
 
 /* Receive External Interrupt Control ------------------------------- */
 
-#define APPNIC_RX_EXTERNAL_INTERRUPT_CONTROL (rx_base + 0xc04)
+#define APPNIC_RX_EXTERNAL_INTERRUPT_CONTROL \
+	((unsigned long)pdata->rx_base + 0xc04)
 #define APPNIC_RX_EXTERNAL_INTERRUPT_CONTROL_MAC_0_HIGH_LOW 0x10
 #define APPNIC_RX_EXTERNAL_INTERRUPT_CONTROL_MAC_0 0x1
 
 /* Receive Interrupt Status ----------------------------------------- */
 
-#define APPNIC_RX_INTERRUPT_STATUS (rx_base + 0xc20)
+#define APPNIC_RX_INTERRUPT_STATUS ((unsigned long)pdata->rx_base + 0xc20)
 #define APPNIC_RX_INTERRUPT_EXTERNAL_STATUS_MAC_0 0x10
 #define APPNIC_RX_INTERRUPT_INTERNAL_STATUS_MAC_0 0x1
 
 /* Transmit Watermark ----------------------------------------------- */
 
-#define APPNIC_TX_WATERMARK (tx_base + 0x18)
+#define APPNIC_TX_WATERMARK ((unsigned long)pdata->tx_base + 0x18)
 #define APPNIC_TX_WATERMARK_TXCONFIG_DTPA_ASSERT 0x8000
 #define APPNIC_TX_WATERMARK_TXCONFIG_DTPA_DISABLE 0x4000
 #define APPNIC_TX_WATERMARK_TXCONFIG_DTPA_WATER_MARK_HIGH 0x3f00
@@ -314,13 +328,13 @@ struct appnic_device {
 
 /* Swap Source Address Registers ------------------------------------ */
 
-#define APPNIC_SWAP_SOURCE_ADDRESS_2 (tx_base + 0x20)
-#define APPNIC_SWAP_SOURCE_ADDRESS_1 (tx_base + 0x24)
-#define APPNIC_SWAP_SOURCE_ADDRESS_0 (tx_base + 0x28)
+#define APPNIC_SWAP_SOURCE_ADDRESS_2 ((unsigned long)pdata->tx_base + 0x20)
+#define APPNIC_SWAP_SOURCE_ADDRESS_1 ((unsigned long)pdata->tx_base + 0x24)
+#define APPNIC_SWAP_SOURCE_ADDRESS_0 ((unsigned long)pdata->tx_base + 0x28)
 
 /* Transmit Extended Configuration ---------------------------------- */
 
-#define APPNIC_TX_EXTENDED_CONF (tx_base + 0x30)
+#define APPNIC_TX_EXTENDED_CONF ((unsigned long)pdata->tx_base + 0x30)
 #define APPNIC_TX_EXTENDED_CONF_TRANSMIT_COLLISION_WATERMARK_LEVEL 0xf000
 #define APPNIC_TX_EXTENDED_CONF_EXCESSIVE_DEFFERED_PACKET_DROP 0x200
 #define APPNIC_TX_EXTENDED_CONF_JUMBO9K 0x100
@@ -328,12 +342,12 @@ struct appnic_device {
 
 /* Transmit Half Duplex Configuration ------------------------------- */
 
-#define APPNIC_TX_HALF_DUPLEX_CONF (tx_base + 0x34)
+#define APPNIC_TX_HALF_DUPLEX_CONF ((unsigned long)pdata->tx_base + 0x34)
 #define APPNIC_TX_HALF_DUPLEX_CONF_RANDOM_SEED_VALUE 0xff
 
 /* Transmit Configuration ------------------------------------------- */
 
-#define APPNIC_TX_CONF			(tx_base + 0x0050)
+#define APPNIC_TX_CONF	((unsigned long)pdata->tx_base + 0x0050)
 #define APPNIC_TX_CONF_ENABLE_SWAP_SA	0x8000
 #define APPNIC_TX_CONF_LINK		0x2000
 #define APPNIC_TX_CONF_DUPLEX		0x1000
@@ -352,64 +366,66 @@ struct appnic_device {
 
 /* Transmit Time Value Configuration -------------------------------- */
 
-#define APPNIC_TX_TIME_VALUE_CONF (tx_base + 0x5c)
+#define APPNIC_TX_TIME_VALUE_CONF ((unsigned long)pdata->tx_base + 0x5c)
 #define APPNIC_TX_TIME_VALUE_CONF_PAUSE_VALUE 0xffff
 
 /* Transmit Stat Underrun ------------------------------------------- */
 
-#define APPNIC_TX_STAT_UNDERRUN (tx_base + 0x300)
+#define APPNIC_TX_STAT_UNDERRUN ((unsigned long)pdata->tx_base + 0x300)
 
 /* Transmit Stat Packet OK ------------------------------------------ */
 
-#define APPNIC_TX_STAT_PACKET_OK (tx_base + 0x318)
+#define APPNIC_TX_STAT_PACKET_OK ((unsigned long)pdata->tx_base + 0x318)
 
 /* Transmit Stat Undersize ------------------------------------------ */
 
-#define APPNIC_TX_STAT_UNDERSIZE (tx_base + 0x350)
+#define APPNIC_TX_STAT_UNDERSIZE ((unsigned long)pdata->tx_base + 0x350)
 
 /* Transmit Status Late Collision ----------------------------------- */
 
-#define APPNIC_TX_STATUS_LATE_COLLISION (tx_base + 0x368)
+#define APPNIC_TX_STATUS_LATE_COLLISION ((unsigned long)pdata->tx_base + 0x368)
 
 /* Transmit Status Excessive Collision ------------------------------ */
 
-#define APPNIC_TX_STATUS_EXCESSIVE_COLLISION (tx_base + 0x370)
+#define APPNIC_TX_STATUS_EXCESSIVE_COLLISION \
+	((unsigned long)pdata->tx_base + 0x370)
 
 /* Transmit Stat Collision Above Watermark -------------------------- */
 
-#define APPNIC_TX_STAT_COLLISION_ABOVE_WATERMARK (tx_base + 0x380)
+#define APPNIC_TX_STAT_COLLISION_ABOVE_WATERMARK \
+	((unsigned long)pdata->tx_base + 0x380)
 
 /* Transmit Mode ---------------------------------------------------- */
 
-#define APPNIC_TX_MODE (tx_base + 0x800)
+#define APPNIC_TX_MODE ((unsigned long)pdata->tx_base + 0x800)
 #define APPNIC_TX_MODE_ETHERNET_MODE_ENABLE 0x1
 
 /* Transmit Soft Reset ---------------------------------------------- */
 
-#define APPNIC_TX_SOFT_RESET (tx_base + 0x808)
+#define APPNIC_TX_SOFT_RESET ((unsigned long)pdata->tx_base + 0x808)
 #define APPNIC_TX_SOFT_RESET_MAC_0 0x1
 
 /* Transmit Interrupt Control --------------------------------------- */
 
-#define APPNIC_TX_INTERRUPT_CONTROL (tx_base + 0xc00)
+#define APPNIC_TX_INTERRUPT_CONTROL ((unsigned long)pdata->tx_base + 0xc00)
 #define APPNIC_TX_INTERRUPT_CONTROL_MAC_0 0x1
 
 /* Transmit Interrupt Status ---------------------------------------- */
 
-#define APPNIC_TX_INTERRUPT_STATUS (tx_base + 0xc20)
+#define APPNIC_TX_INTERRUPT_STATUS ((unsigned long)pdata->tx_base + 0xc20)
 #define APPNIC_TX_INTERRUPT_STATUS_MAC_0 0x1
 
 /* */
 
-#define APPNIC_DMA_PCI_CONTROL (dma_base + 0x00)
+#define APPNIC_DMA_PCI_CONTROL ((unsigned long)pdata->dma_base + 0x00)
 
 /* */
 
-#define APPNIC_DMA_CONTROL (dma_base + 0x08)
+#define APPNIC_DMA_CONTROL ((unsigned long)pdata->dma_base + 0x08)
 
 /* DMA Interrupt Status --------------------------------------------- */
 
-#define APPNIC_DMA_INTERRUPT_STATUS (dma_base + 0x18)
+#define APPNIC_DMA_INTERRUPT_STATUS ((unsigned long)pdata->dma_base + 0x18)
 #define APPNIC_DMA_INTERRUPT_STATUS_RX 0x2
 #define APPNIC_DMA_INTERRUPT_STATUS_TX 0x1
 #define RX_INTERRUPT(dma_interrupt_status) \
@@ -419,55 +435,59 @@ struct appnic_device {
 
 /* DMA Interrupt Enable --------------------------------------------- */
 
-#define APPNIC_DMA_INTERRUPT_ENABLE (dma_base + 0x1c)
+#define APPNIC_DMA_INTERRUPT_ENABLE ((unsigned long)pdata->dma_base + 0x1c)
 #define APPNIC_DMA_INTERRUPT_ENABLE_RECEIVE 0x2
 #define APPNIC_DMA_INTERRUPT_ENABLE_TRANSMIT 0x1
 
 /* DMA Receive Queue Base Address ----------------------------------- */
 
-#define APPNIC_DMA_RX_QUEUE_BASE_ADDRESS (dma_base + 0x30)
+#define APPNIC_DMA_RX_QUEUE_BASE_ADDRESS ((unsigned long)pdata->dma_base + 0x30)
 
 /* DMA Receive Queue Size ------------------------------------------- */
 
-#define APPNIC_DMA_RX_QUEUE_SIZE (dma_base + 0x34)
+#define APPNIC_DMA_RX_QUEUE_SIZE ((unsigned long)pdata->dma_base + 0x34)
 
 /* DMA Transmit Queue Base Address ---------------------------------- */
 
-#define APPNIC_DMA_TX_QUEUE_BASE_ADDRESS (dma_base + 0x38)
+#define APPNIC_DMA_TX_QUEUE_BASE_ADDRESS ((unsigned long)pdata->dma_base + 0x38)
 
 /* DMA Transmit Queue Size ------------------------------------------ */
 
-#define APPNIC_DMA_TX_QUEUE_SIZE (dma_base + 0x3c)
+#define APPNIC_DMA_TX_QUEUE_SIZE ((unsigned long)pdata->dma_base + 0x3c)
 
 /* DMA Recevie Tail Pointer Address --------------------------------- */
 
-#define APPNIC_DMA_RX_TAIL_POINTER_ADDRESS (dma_base + 0x48)
+#define APPNIC_DMA_RX_TAIL_POINTER_ADDRESS \
+	((unsigned long)pdata->dma_base + 0x48)
 
 /* DMA Transmit Tail Pointer Address -------------------------------- */
 
-#define APPNIC_DMA_TX_TAIL_POINTER_ADDRESS (dma_base + 0x4c)
+#define APPNIC_DMA_TX_TAIL_POINTER_ADDRESS \
+	((unsigned long)pdata->dma_base + 0x4c)
 
 /* DMA Receive Head Pointer ----------------------------------------- */
 
-#define APPNIC_DMA_RX_HEAD_POINTER			(dma_base + 0x50)
+#define APPNIC_DMA_RX_HEAD_POINTER	((unsigned long)pdata->dma_base + 0x50)
 #define APPNIC_DMA_RX_HEAD_POINTER_GB			0x100000
 #define APPNIC_DMA_RX_HEAD_POINTER_POINTER		0x0fffff
 
 /* DMA Receive Tail Pointer Local Copy ------------------------------ */
 
-#define APPNIC_DMA_RX_TAIL_POINTER_LOCAL_COPY		(dma_base + 0x54)
+#define APPNIC_DMA_RX_TAIL_POINTER_LOCAL_COPY	\
+	((unsigned long)pdata->dma_base + 0x54)
 #define APPNIC_DMA_RX_TAIL_POINTER_LOCAL_COPY_GB	0x100000
 #define APPNIC_DMA_RX_TAIL_POINTER_LOCAL_COPY_POINTER	0x0fffff
 
 /* DMA Transmit Head Pointer ---------------------------------------- */
 
-#define APPNIC_DMA_TX_HEAD_POINTER			(dma_base + 0x58)
+#define APPNIC_DMA_TX_HEAD_POINTER	((unsigned long)pdata->dma_base + 0x58)
 #define APPNIC_DMA_TX_HEAD_POINTER_GB			0x100000
 #define APPNIC_DMA_TX_HEAD_POINTER_POINTER		0x0fffff
 
 /* DMA Transmit Tail Pointer Local Copy ----------------------------- */
 
-#define APPNIC_DMA_TX_TAIL_POINTER_LOCAL_COPY		(dma_base + 0x5c)
+#define APPNIC_DMA_TX_TAIL_POINTER_LOCAL_COPY	\
+	((unsigned long)pdata->dma_base + 0x5c)
 #define APPNIC_DMA_TX_TAIL_POINTER_LOCAL_COPY_GB	0x100000
 #define APPNIC_DMA_TX_TAIL_POINTER_LOCAL_COPY_POINTER	0x0fffff
 
@@ -494,11 +514,18 @@ writedescriptor(unsigned long address,
 }
 
 static inline union appnic_queue_pointer
-swab_queue_pointer(const union appnic_queue_pointer *old_queue)
+_swab_queue_pointer(const union appnic_queue_pointer *old_queue)
 {
 	return *old_queue;
 }
 
+static inline void
+femac_uncache(struct appnic_device *pdata)
+{
+	/* Set FEMAC to uncached */
+	writel(0x0, GPREG_HPROT_FEMAC);
+}
+
 #else
 
 #define read_mac(address)         in_le32((u32 *) (address))
@@ -532,15 +559,115 @@ writedescriptor(unsigned long address,
 }
 
 static inline union appnic_queue_pointer
-swab_queue_pointer(const union appnic_queue_pointer *old_queue)
+_swab_queue_pointer(const union appnic_queue_pointer *old_queue)
 {
 	union appnic_queue_pointer new_queue;
 	new_queue.raw = swab32(old_queue->raw);
 	return new_queue;
 }
+
+static inline void
+femac_uncache(struct appnic_device *pdata) {}
+
 #endif /* ifdef CONFIG_ARM */
 
-#define SWAB_QUEUE_POINTER(pointer) \
-swab_queue_pointer((const union appnic_queue_pointer *) (pointer))
+static int
+femac_irq_setup(struct net_device *dev)
+{
+	struct appnic_device *pdata = netdev_priv(dev);
+
+#ifdef CONFIG_ARM
+	dev->irq = pdata->dma_interrupt;
+#else
+	dev->irq = irq_create_mapping(NULL, pdata->dma_interrupt);
+	if (NO_IRQ == dev->irq)
+		return -EINVAL;
+
+	if (0 != irq_set_irq_type(dev->irq, IRQ_TYPE_LEVEL_HIGH))
+		return -EINVAL;
+#endif
+	return 0;
+}
+
+static inline int
+femac_alloc_mem_buffers(struct net_device *dev)
+{
+	struct appnic_device *pdata = netdev_priv(dev);
+	struct device *device = NULL;
+	int rc;
+
+#ifndef CONFIG_ARM
+	dev->dev.archdata.dma_ops = &dma_direct_ops;
+	device = &dev->dev;
+#endif
+
+	pdata->dma_alloc = (void *)dma_alloc_coherent(device,
+						      pdata->dma_alloc_size,
+						      &pdata->dma_alloc_dma,
+						      GFP_KERNEL);
+	if (pdata->dma_alloc == (void *)0) {
+		rc = -ENOMEM;
+		goto err_dma_alloc;
+	}
+
+	pdata->dma_alloc_offset = (int)pdata->dma_alloc -
+					(int)pdata->dma_alloc_dma;
+
+	pdata->dma_alloc_rx = (void *)dma_alloc_coherent(device,
+						      pdata->dma_alloc_size_rx,
+						      &pdata->dma_alloc_dma_rx,
+						      GFP_KERNEL);
+	if (pdata->dma_alloc_rx == (void *)0) {
+		rc = -ENOMEM;
+		goto err_dma_alloc_rx;
+	}
+
+	pdata->dma_alloc_offset_rx = (int)pdata->dma_alloc_rx -
+					(int)pdata->dma_alloc_dma_rx;
+
+	pdata->dma_alloc_tx = (void *)dma_alloc_coherent(device,
+						      pdata->dma_alloc_size_tx,
+						      &pdata->dma_alloc_dma_tx,
+						      GFP_KERNEL);
+
+	if (pdata->dma_alloc_tx == (void *)0) {
+		rc = -ENOMEM;
+		goto err_dma_alloc_tx;
+	}
+
+	pdata->dma_alloc_offset_tx = (int)pdata->dma_alloc_tx -
+					(int)pdata->dma_alloc_dma_tx;
+
+	return 0;
+
+err_dma_alloc_tx:
+	dma_free_coherent(device, pdata->dma_alloc_size_rx,
+			  pdata->dma_alloc_rx, pdata->dma_alloc_dma_rx);
+err_dma_alloc_rx:
+	dma_free_coherent(device, pdata->dma_alloc_size,
+			  pdata->dma_alloc, pdata->dma_alloc_dma);
+err_dma_alloc:
+	return rc;
+}
+
+static inline void
+femac_free_mem_buffers(struct net_device *dev)
+{
+	struct appnic_device *pdata = netdev_priv(dev);
+	struct device *device = NULL;
+
+#ifndef CONFIG_ARM
+	device = &dev->dev;
+#endif
+	dma_free_coherent(device, pdata->dma_alloc_size,
+			  pdata->dma_alloc, pdata->dma_alloc_dma);
+	dma_free_coherent(device, pdata->dma_alloc_size_rx,
+			  pdata->dma_alloc_rx, pdata->dma_alloc_dma_rx);
+	dma_free_coherent(device, pdata->dma_alloc_size_tx,
+			  pdata->dma_alloc_tx, pdata->dma_alloc_dma_tx);
+}
+
+#define swab_queue_pointer(pointer) \
+	_swab_queue_pointer((const union appnic_queue_pointer *) (pointer))
 
 #endif /* _LSI_ACP_NET_H */
-- 
1.7.9.5



More information about the linux-yocto mailing list