From: Charlie Paul <cpaul.windri...@gmail.com>

Driver changes to the ethernet to support the AXXIA
5500 board.

Signed-off-by: Charlie Paul <cpaul.windri...@gmail.com>
---
 drivers/net/ethernet/Kconfig            |    3 +
 drivers/net/ethernet/Makefile           |    1 +
 drivers/net/ethernet/lsi/Kconfig        |   38 +
 drivers/net/ethernet/lsi/Makefile       |    4 +
 drivers/net/ethernet/lsi/lsi_acp_mdio.c |  338 ++++++
 drivers/net/ethernet/lsi/lsi_acp_net.c  | 2009 +++++++++++++++++++++++++++++++
 drivers/net/ethernet/lsi/lsi_acp_net.h  |  670 +++++++++++
 7 files changed, 3063 insertions(+)
 create mode 100644 drivers/net/ethernet/lsi/Kconfig
 create mode 100644 drivers/net/ethernet/lsi/Makefile
 create mode 100644 drivers/net/ethernet/lsi/lsi_acp_mdio.c
 create mode 100644 drivers/net/ethernet/lsi/lsi_acp_net.c
 create mode 100644 drivers/net/ethernet/lsi/lsi_acp_net.h

diff --git a/drivers/net/ethernet/Kconfig b/drivers/net/ethernet/Kconfig
index 506b024..d168c75 100644
--- a/drivers/net/ethernet/Kconfig
+++ b/drivers/net/ethernet/Kconfig
@@ -35,6 +35,7 @@ source "drivers/net/ethernet/chelsio/Kconfig"
 source "drivers/net/ethernet/cirrus/Kconfig"
 source "drivers/net/ethernet/cisco/Kconfig"
 source "drivers/net/ethernet/davicom/Kconfig"
+source "drivers/net/ethernet/lsi/Kconfig"
 
 config DNET
        tristate "Dave ethernet support (DNET)"
@@ -166,5 +167,7 @@ source "drivers/net/ethernet/via/Kconfig"
 source "drivers/net/ethernet/wiznet/Kconfig"
 source "drivers/net/ethernet/xilinx/Kconfig"
 source "drivers/net/ethernet/xircom/Kconfig"
+source "drivers/net/ethernet/lsi/Kconfig"
+
 
 endif # ETHERNET
diff --git a/drivers/net/ethernet/Makefile b/drivers/net/ethernet/Makefile
index c0b8789..168b1ac 100644
--- a/drivers/net/ethernet/Makefile
+++ b/drivers/net/ethernet/Makefile
@@ -77,3 +77,4 @@ obj-$(CONFIG_NET_VENDOR_VIA) += via/
 obj-$(CONFIG_NET_VENDOR_WIZNET) += wiznet/
 obj-$(CONFIG_NET_VENDOR_XILINX) += xilinx/
 obj-$(CONFIG_NET_VENDOR_XIRCOM) += xircom/
+obj-$(CONFIG_LSI_NET) += lsi/
diff --git a/drivers/net/ethernet/lsi/Kconfig b/drivers/net/ethernet/lsi/Kconfig
new file mode 100644
index 0000000..a78867d
--- /dev/null
+++ b/drivers/net/ethernet/lsi/Kconfig
@@ -0,0 +1,38 @@
+config LSI_NET
+       bool "LSI ACP34XX Ethernet support"
+       select MII
+       select PHYLIB
+       help
+         Network interface driver for LSI's APP and AXXIA series boards.
+
+if LSI_NET
+
+config LSI_NET_NUM_RX_DESC
+       int "LSI Axxia Network Driver: Number of receive descriptors"
+       depends on LSI_NET
+       default "4"
+       help
+          The number of receive descriptors to allocate.
+
+config LSI_NET_RX_BUF_SZ
+       int "NIC driver: Size of the receive buffer"
+       depends on LSI_NET
+       default "32768"
+       help
+          The size of the receive buffer.
+
+config LSI_NET_NUM_TX_DESC
+       int "NIC driver: Number of transmit descriptors"
+       depends on LSI_NET
+       default "4"
+       help
+         The number of transmit descriptors to allocate.
+
+config LSI_NET_TX_BUF_SZ
+       int "NIC driver: Size of the transmit buffer"
+       depends on LSI_NET
+       default "32768"
+       help
+         The size of the transmit buffer.
+
+endif # LSI_NET
diff --git a/drivers/net/ethernet/lsi/Makefile 
b/drivers/net/ethernet/lsi/Makefile
new file mode 100644
index 0000000..a48a239
--- /dev/null
+++ b/drivers/net/ethernet/lsi/Makefile
@@ -0,0 +1,4 @@
+# Makefile for the LSI FEMAC network interface.
+
+obj-$(CONFIG_LSI_NET) += lsi_acp_mdio.o
+obj-$(CONFIG_LSI_NET) += lsi_acp_net.o
diff --git a/drivers/net/ethernet/lsi/lsi_acp_mdio.c 
b/drivers/net/ethernet/lsi/lsi_acp_mdio.c
new file mode 100644
index 0000000..7bde921
--- /dev/null
+++ b/drivers/net/ethernet/lsi/lsi_acp_mdio.c
@@ -0,0 +1,338 @@
+/*
+ * drivers/net/ethernet/lsi/lsi_acp_mdio.c
+ *
+ * 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.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/of.h>
+#include <asm/irq.h>
+#include <linux/io.h>
+#include <linux/of_address.h>
+#include <linux/irqdomain.h>
+#include <linux/skbuff.h>
+#include <linux/platform_device.h>
+
+#define BZ33327_WA
+
+/* MDIO Access */
+
+struct lsi_mdio_priv {
+       unsigned long base;
+};
+
+static struct lsi_mdio_priv *mdio_priv;
+static DEFINE_SPINLOCK(mdio_lock);
+
+#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
+static u32 read_reg(u32 *addr)
+{
+       return readl_relaxed((void __iomem *)addr);
+}
+
+static void write_reg(u32 *addr, u32 value)
+{
+       writel_relaxed(value, (void __iomem *)addr);
+}
+#else
+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 */
+
+int
+acp_mdio_read(unsigned long address, unsigned long offset,
+             unsigned short *value, int clause_45)
+{
+       unsigned long command = 0;
+       unsigned long status;
+       unsigned long flags;
+
+       spin_lock_irqsave(&mdio_lock, flags);
+#if defined(BZ33327_WA)
+       /* Set the mdio_busy (status) bit. */
+       status = read_reg(MDIO_STATUS_RD_DATA);
+       status |= 0x40000000;
+       write_reg(MDIO_STATUS_RD_DATA, status);
+#endif /* BZ33327_WA */
+
+       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_reg(MDIO_CONTROL_RD_DATA, command);
+       } else {
+               /* Step 1: Write the address. */
+
+               /* Write the address */
+               command = 0x20000000;                    /* Clause 45 = 1 */
+               command |= 0x00000000;                   /* op_code: 0 */
+               command |= 0x04000000;                   /* interface_sel = 1 */
+               command |= ((offset & 0x1f000000) >> 3); /* device_addr (target
+                                                         * device_type)
+                                                         */
+               command |= (address & 0x1f) << 16;       /* port_addr (target
+                                                         * device)
+                                                         */
+               command |= (offset & 0xffff);            /* addr_or_data (target
+                                                         * register)
+                                                         */
+               write_reg(MDIO_CONTROL_RD_DATA, command);
+
+               /* Wait for the mdio_busy (status) bit to clear. */
+               do {
+                       status = read_reg(MDIO_STATUS_RD_DATA);
+               } while (0 != (status & 0x40000000));
+
+               /* Wait for the mdio_busy (control) bit to clear. */
+               do {
+                       command = read_reg(MDIO_CONTROL_RD_DATA);
+               } while (0 != (command & 0x80000000));
+
+               /* Step 2: Read the value. */
+
+               /* Set the mdio_busy (status) bit. */
+               status = read_reg(MDIO_STATUS_RD_DATA);
+               status |= 0x40000000;
+               write_reg(MDIO_STATUS_RD_DATA, status);
+
+               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_reg(MDIO_CONTROL_RD_DATA, command);
+       }
+
+#if defined(BZ33327_WA)
+       /* Wait for the mdio_busy (status) bit to clear. */
+       do {
+               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_reg(MDIO_CONTROL_RD_DATA);
+       } while (0 != (command & 0x80000000));
+
+       *value = (unsigned short)(command & 0xffff);
+       spin_unlock_irqrestore(&mdio_lock, flags);
+
+       return 0;
+}
+EXPORT_SYMBOL(acp_mdio_read);
+
+/* acp_mdio_write */
+
+int
+acp_mdio_write(unsigned long address, unsigned long offset,
+              unsigned short value, int clause_45)
+{
+       unsigned long command = 0;
+       unsigned long status;
+       unsigned long flags;
+
+       spin_lock_irqsave(&mdio_lock, flags);
+
+       /* Wait for mdio_busy (control) to be clear. */
+       do {
+               command = read_reg(MDIO_CONTROL_RD_DATA);
+       } while (0 != (command & 0x80000000));
+
+#if defined(BZ33327_WA)
+       /* Set the mdio_busy (status) bit. */
+       status = read_reg(MDIO_STATUS_RD_DATA);
+       status |= 0x40000000;
+       write_reg(MDIO_STATUS_RD_DATA, status);
+#endif /* BZ33327_WA */
+
+       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_reg(MDIO_CONTROL_RD_DATA, command);
+       } else {
+               /* Step 1: Write the address. */
+
+               /* Write the address */
+               command = 0x20000000;                    /* Clause 45 = 1 */
+               command |= 0x00000000;                   /* op_code: 0 */
+               command |= 0x04000000;                   /* interface_sel = 1 */
+               command |= ((offset & 0x1f000000) >> 3); /* device_addr (target
+                                                         * device_type)
+                                                         */
+               command |= (address & 0x1f) << 16;       /* port_addr (target
+                                                         * device)
+                                                         */
+               command |= (offset & 0xffff);            /* addr_or_data (target
+                                                         * register)
+                                                         */
+               write_reg(MDIO_CONTROL_RD_DATA, command);
+
+               /* Wait for the mdio_busy (status) bit to clear. */
+               do {
+                       status = read_reg(MDIO_STATUS_RD_DATA);
+               } while (0 != (status & 0x40000000));
+
+               /* Wait for the mdio_busy (control) bit to clear. */
+               do {
+                       command = read_reg(MDIO_CONTROL_RD_DATA);
+               } while (0 != (command & 0x80000000));
+
+               /* Step 2: Write the value. */
+
+               /* Set the mdio_busy (status) bit. */
+               status = read_reg(MDIO_STATUS_RD_DATA);
+               status |= 0x40000000;
+               write_reg(MDIO_STATUS_RD_DATA, status);
+
+               command = 0x20000000;                    /* Clause 45 = 1 */
+               command |= 0x08000000;                   /* op_code: write */
+               command |= 0x04000000;                   /* interface_sel = 1 */
+               command |= ((offset & 0x1f000000) >> 3); /* device_addr (target
+                                                         * device_type)
+                                                         */
+               command |= (address & 0x1f) << 16;       /* port_addr (target
+                                                         * device)
+                                                         */
+               command |= (value & 0xffff);             /* addr_or_data=value*/
+               write_reg(MDIO_CONTROL_RD_DATA, command);
+       }
+
+#if defined(BZ33327_WA)
+       /* Wait for the mdio_busy (status) bit to clear. */
+       do {
+               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_reg(MDIO_CONTROL_RD_DATA);
+       } while (0 != (command & 0x80000000));
+
+       spin_unlock_irqrestore(&mdio_lock, flags);
+
+       return 0;
+}
+EXPORT_SYMBOL(acp_mdio_write);
+
+/* acp_mdio_initialize */
+
+static void
+acp_mdio_initialize(int offset, int period)
+{
+       write_reg(MDIO_CLK_OFFSET, offset);
+       write_reg(MDIO_CLK_PERIOD, period);
+
+       return;
+}
+
+/* acp_wrappers_init */
+
+int __init
+acp_mdio_init(void)
+{
+       int rc = -ENODEV;
+       struct device_node *np = NULL;
+       const u32 *field;
+       void __iomem *map;
+       u64 mdio_address;
+       u32 mdio_size;
+       u32 mdio_offset = 0;
+       u32 mdio_period = 0;
+
+       pr_info("MDIO: Initializing Axxia Wrappers.\n");
+
+       mdio_priv = kzalloc(sizeof(struct lsi_mdio_priv), GFP_KERNEL);
+       if (!mdio_priv)
+               return -ENOMEM;
+
+       np = of_find_node_by_type(np, "network");
+
+       while (np &&
+              !of_device_is_compatible(np, "lsi,acp-femac") &&
+              !of_device_is_compatible(np, "acp-femac"))
+               np = of_find_node_by_type(np, "network");
+
+       if (!np) {
+               pr_warn("MDIO: No compatible devices found.\n");
+               rc = -EINVAL;
+               goto error;
+       }
+
+       field = of_get_property(np, "mdio-reg", NULL);
+
+       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[3];
+       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;
+       field = of_get_property(np, "mdio-clock-offset", NULL);
+
+       if (field)
+               mdio_offset = ntohl(field[0]);
+
+       field = of_get_property(np, "mdio-clock-period", NULL);
+
+       if (field)
+               mdio_period = ntohl(field[0]);
+
+       if (0 != mdio_offset && 0 != mdio_period)
+               acp_mdio_initialize(mdio_offset, mdio_period);
+
+error:
+       return rc;
+}
+
+module_init(acp_mdio_init);
+
+MODULE_AUTHOR("LSI Corporation");
+MODULE_DESCRIPTION("Timing Test");
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/ethernet/lsi/lsi_acp_net.c 
b/drivers/net/ethernet/lsi/lsi_acp_net.c
new file mode 100644
index 0000000..e079294
--- /dev/null
+++ b/drivers/net/ethernet/lsi/lsi_acp_net.c
@@ -0,0 +1,2009 @@
+/*
+ * drivers/net/ethernet/lsi/lsi_acp_net.c
+ *
+ * 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.
+ *
+ * NOTES:
+ *
+ * 1) This driver is used by both ACP (PPC) and AXM (ARM) platforms.
+ *
+ * 2) This driver parses the DTB for driver specific settings. A few of
+ *    them can be overriden by setting environment variables in U-boot:
+ *
+ *    ethaddr - MAC address of interface, in xx:xx:xx:xx:xx:xx format
+ *
+ *    phy-addr - Specific address of PHY (0 - 0x20). If not specified,
+ *               the driver will scan the bus and will attach to the first
+ *               PHY it finds.
+ *
+ *    ad-value - PHY advertise value. Can be set to one of these or they
+ *               be OR'ed together. If not set, the driver sets the
+ *               advertised value equal to what the driver supports.
+ *
+ *               0x101 - 100/Full
+ *               0x81  - 100/Half
+ *               0x41  - 10/Full
+ *               0x21  - 10/Half
+ *
+ * 3) This driver allows the option to disable auto negotiation and manually
+ *    specify the speed and duplex setting, with the use of the device tree
+ *    variable "phy-link". Legal values for this variable are:
+ *
+ *    "auto"  - auto negotiation enabled
+ *    "100MF" - auto negotation disabled, set to 100MB Full Duplex
+ *    "10MH"  - auto negotation disabled, set to 100MB Half Duplex
+ *    "10MF"  - auto negotation disabled, set to 10MB Full Duplex
+ *    "10MH"  - auto negotation disabled, set to 10MB Half Duplex
+ *
+ *    NOTE: If the phy-link variable is not present in the device tree, or
+ *    if an invalid value is used, the driver defaults to auto negotiation
+ *    mode.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/version.h>
+#include <linux/string.h>
+#include <linux/interrupt.h>
+#include <linux/errno.h>
+#include <linux/in.h>
+#include <linux/slab.h>
+#include <linux/ioport.h>
+#include <linux/spinlock.h>
+#include <linux/delay.h>
+#include <linux/bitops.h>
+#include <linux/proc_fs.h>
+#include <linux/platform_device.h>
+#include <linux/netdevice.h>
+#include <linux/mii.h>
+#include <linux/phy.h>
+#include <linux/etherdevice.h>
+#include <linux/ethtool.h>
+#include <linux/skbuff.h>
+#include <linux/init.h>
+#include <linux/irq.h>
+#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>
+
+#include "../../../misc/lsi-ncr.h"
+
+#include "lsi_acp_net.h"
+
+#define LSI_DRV_NAME           "acp-femac"
+#define LSI_MDIO_NAME          "acp-femac-mdio"
+#define LSI_DRV_VERSION        "2014-01-09"
+
+MODULE_AUTHOR("John Jacques");
+MODULE_DESCRIPTION("LSI ACP-FEMAC Ethernet driver");
+MODULE_LICENSE("GPL");
+
+/* ----------------------------------------------------------------------
+ * appnic_mii_read
+ *
+ * Returns -EBUSY if unsuccessful, the (short) value otherwise.
+ */
+
+static int appnic_mii_read(struct mii_bus *bus, int phy, int reg)
+{
+       unsigned short value;
+
+       /* Always returns success, so no need to check return status. */
+       acp_mdio_read(phy, reg, &value, 0);
+
+       return (int)value;
+}
+
+/* ----------------------------------------------------------------------
+ * appnic_mii_write
+ */
+
+static int appnic_mii_write(struct mii_bus *bus, int phy, int reg, u16 val)
+{
+       return acp_mdio_write(phy, reg, val, 0);
+}
+
+/* ----------------------------------------------------------------------
+ * appnic_handle_link_change
+ *
+ * Called periodically when PHY is in polling mode.
+ */
+
+static void appnic_handle_link_change(struct net_device *dev)
+{
+       struct appnic_device *pdata = netdev_priv(dev);
+       struct phy_device *phydev = pdata->phy_dev;
+       int status_change = 0;
+       unsigned long rx_configuration;
+       unsigned long tx_configuration = 0;
+
+       rx_configuration =
+#ifdef CONFIG_ARM
+               APPNIC_RX_CONF_STRIPCRC;
+#else
+               (APPNIC_RX_CONF_STRIPCRC |
+                APPNIC_RX_CONF_RXFCE |
+                APPNIC_RX_CONF_TXFCE);
+#endif
+       tx_configuration =
+               (APPNIC_TX_CONF_ENABLE_SWAP_SA |
+                APPNIC_TX_CONF_APP_CRC_ENABLE |
+                APPNIC_TX_CONF_PAD_ENABLE);
+
+       TX_CONF_SET_IFG(tx_configuration, 0xf);
+
+       if (phydev->link) {
+               if ((pdata->speed != phydev->speed) ||
+                   (pdata->duplex != phydev->duplex)) {
+                       if (phydev->duplex) {
+                               rx_configuration |= APPNIC_RX_CONF_DUPLEX;
+                               tx_configuration |= APPNIC_TX_CONF_DUPLEX;
+                       }
+                       if (phydev->speed == SPEED_100) {
+                               rx_configuration |= APPNIC_RX_CONF_SPEED;
+                               tx_configuration |= APPNIC_TX_CONF_SPEED;
+                       }
+
+                       rx_configuration |= (APPNIC_RX_CONF_ENABLE |
+                                            APPNIC_RX_CONF_LINK);
+                       tx_configuration |= (APPNIC_TX_CONF_LINK |
+                                            APPNIC_TX_CONF_ENABLE);
+
+                       pdata->speed = phydev->speed;
+                       pdata->duplex = phydev->duplex;
+                       status_change = 1;
+               }
+       }
+       if (phydev->link != pdata->link) {
+               if (!phydev->link) {
+                       pdata->speed = 0;
+                       pdata->duplex = -1;
+               }
+               pdata->link = phydev->link;
+               status_change = 1;
+       }
+
+       if (status_change) {
+               if (phydev->link) {
+                       netif_carrier_on(dev);
+                       netdev_info(dev, "link up (%d/%s)\n",
+                                   phydev->speed,
+                                   phydev->duplex == DUPLEX_FULL ?
+                                   "Full" : "Half");
+               } else {
+                       netif_carrier_off(dev);
+                       netdev_info(dev, "link down\n");
+               }
+
+               if (rx_configuration != read_mac(APPNIC_RX_CONF))
+                       write_mac(rx_configuration, APPNIC_RX_CONF);
+
+               if (tx_configuration != read_mac(APPNIC_TX_CONF))
+                       write_mac(tx_configuration, APPNIC_TX_CONF);
+       }
+
+       return;
+}
+
+/* ----------------------------------------------------------------------
+ * appnic_mii_probe
+ */
+
+static int appnic_mii_probe(struct net_device *dev)
+{
+       struct appnic_device *pdata = netdev_priv(dev);
+       struct phy_device *phydev = NULL;
+       int ret;
+
+       if (pdata->phy_address && (pdata->phy_address < PHY_MAX_ADDR)) {
+               phydev = pdata->mii_bus->phy_map[pdata->phy_address];
+               if (phydev)
+                       goto skip_first;
+       }
+
+       /* Find the first phy */
+       phydev = phy_find_first(pdata->mii_bus);
+       if (!phydev) {
+               pr_crit("!!! no PHY found !!!\n");
+               netdev_err(dev, " no PHY found\n");
+               return -ENODEV;
+       }
+
+skip_first:
+
+       /* Allow the option to disable auto negotiation and manually specify
+        * the link speed and duplex setting with the use of a environment
+        * setting.
+        */
+
+       if (0 == pdata->phy_link_auto) {
+               phydev->autoneg = AUTONEG_DISABLE;
+               phydev->speed =
+                       0 == pdata->phy_link_speed ? SPEED_10 : SPEED_100;
+               phydev->duplex =
+                       0 == pdata->phy_link_duplex ? DUPLEX_HALF : DUPLEX_FULL;
+       } else {
+               phydev->autoneg = AUTONEG_ENABLE;
+       }
+
+       ret = phy_connect_direct(dev, phydev,
+                                &appnic_handle_link_change,
+                                PHY_INTERFACE_MODE_MII);
+
+       if (ret) {
+               netdev_err(dev, "Could not attach to PHY\n");
+               return ret;
+       }
+
+       netdev_info(dev,
+                   "attached PHY driver [%s] (mii_bus:phy_addr=%s, irq=%d)\n",
+                   phydev->drv->name, dev_name(&phydev->dev), phydev->irq);
+
+       /* Mask with MAC supported features */
+       phydev->supported &= PHY_BASIC_FEATURES;
+       if (pdata->ad_value)
+               phydev->advertising = mii_adv_to_ethtool_adv_t(pdata->ad_value);
+       else
+               phydev->advertising = phydev->supported;
+
+       pdata->link = 0;
+       pdata->speed = 0;
+       pdata->duplex = -1;
+       pdata->phy_dev = phydev;
+
+       pr_info("%s: PHY initialized successfully", LSI_DRV_NAME);
+       return 0;
+}
+
+/* ----------------------------------------------------------------------
+ * appnic_mii_init
+ */
+
+static int appnic_mii_init(struct platform_device *pdev,
+                          struct net_device *dev)
+{
+       struct appnic_device *pdata = netdev_priv(dev);
+       int i, err = -ENXIO;
+
+       pdata->mii_bus = mdiobus_alloc();
+       if (!pdata->mii_bus) {
+               err = -ENOMEM;
+               goto err_out_1;
+       }
+
+       pdata->mii_bus->name = LSI_MDIO_NAME;
+       snprintf(pdata->mii_bus->id, MII_BUS_ID_SIZE, "%s-%x",
+                pdev->name, pdev->id);
+       pdata->mii_bus->priv = pdata;
+       pdata->mii_bus->read = appnic_mii_read;
+       pdata->mii_bus->write = appnic_mii_write;
+       pdata->mii_bus->irq = pdata->phy_irq;
+       for (i = 0; i < PHY_MAX_ADDR; ++i)
+               pdata->mii_bus->irq[i] = PHY_POLL;
+
+       if (mdiobus_register(pdata->mii_bus)) {
+               pr_warn("%s: Error registering mii bus", LSI_DRV_NAME);
+               goto err_out_free_bus_2;
+       }
+
+       if (appnic_mii_probe(dev) < 0) {
+               pr_warn("%s: Error registering mii bus", LSI_DRV_NAME);
+               goto err_out_unregister_bus_3;
+       }
+
+       return 0;
+
+err_out_unregister_bus_3:
+       mdiobus_unregister(pdata->mii_bus);
+err_out_free_bus_2:
+       mdiobus_free(pdata->mii_bus);
+err_out_1:
+       return err;
+}
+
+/* ======================================================================
+ * NIC Interface
+ * ======================================================================
+*/
+
+#define DESCRIPTOR_GRANULARITY 64
+#define BUFFER_ALIGNMENT 64
+
+#define ALIGN64B(address) (PTR_ALIGN((address), BUFFER_ALIGNMENT))
+#define ALIGN64B_OFFSET(address) \
+       (ALIGN64B(address) - (unsigned long) (address))
+
+/*  ----- Note On Buffer Space -----
+ *
+ *  Minimum number of descriptors is 64 for the receiver and 64 for the
+ *  transmitter; therefore, 2048 bytes (16 bytes each).
+ *  This driver uses the following parameters, all of which may be set on
+ *  the command line if this drivers is used as a module.
+ *
+ *  - rx_num_desc : Number of receive descriptors. This  must be a multiple
+ *                  of 64.
+ *  - tx_num_desc : Number of transmit descriptors. This must be a multiple
+ *                  of 64.
+ *
+ *  The scheme used will be as follows:
+ *
+ *  - num_[rt]x_desc will be adjusted to be a multiple of 64 (if necessary).
+ *  - An skb (with the data area 64 byte aligned) will be allocated for each rx
+ *    descriptor.
+ */
+
+/* Receiver */
+
+int rx_num_desc = (CONFIG_LSI_NET_NUM_RX_DESC * DESCRIPTOR_GRANULARITY);
+module_param(rx_num_desc, int, 0);
+MODULE_PARM_DESC(rx_num_desc, "appnic : Number of receive descriptors");
+
+int rx_buf_sz = CONFIG_LSI_NET_RX_BUF_SZ;
+module_param(rx_buf_sz, int, 0);
+MODULE_PARM_DESC(rx_buf_sz, "appnic : Receive buffer size");
+
+/* Transmitter */
+
+int tx_num_desc = (CONFIG_LSI_NET_NUM_TX_DESC * DESCRIPTOR_GRANULARITY);
+module_param(tx_num_desc, int, 0);
+MODULE_PARM_DESC(tx_num_desc, "appnic : Number of receive descriptors");
+
+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");
+
+/* ======================================================================
+ * 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 (ether_addr_equal(mac_addr, &dev->dev_addr[0]))
+               is_valid = true;
+
+       return is_valid;
+}
+
+
+/* ----------------------------------------------------------------------
+ * clear_statistics
+ *
+ * NOTE: The hardware clears the statistics registers after a read.
+ */
+
+static void clear_statistics(struct appnic_device *pdata)
+{
+       /* Clear memory. */
+
+       memset((void *) &(pdata->stats), 0, sizeof(struct net_device_stats));
+
+       /* Clear counters by reading them. */
+
+       /* stats.rx_packets */
+       read_mac(APPNIC_RX_STAT_PACKET_OK);
+
+       /* stats.tx_packets */
+       read_mac(APPNIC_TX_STAT_PACKET_OK);
+
+       /* 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.
+        */
+
+       /* stats.multicast */
+       read_mac(APPNIC_RX_STAT_MULTICAST);
+
+       /* 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);
+
+       /* stats.rx_length_errors - The sum of the following driver stats. */
+       read_mac(APPNIC_RX_STAT_UNDERSIZE);
+       read_mac(APPNIC_RX_STAT_OVERSIZE);
+
+       /* stats.rx_over_errors - Not maintained by this driver. */
+
+       /* stats.rx_crc_errors */
+       read_mac(APPNIC_RX_STAT_CRC_ERROR);
+
+       /* stats.rx_frame_errors */
+       read_mac(APPNIC_RX_STAT_ALIGN_ERROR);
+
+       /* stats.rx_fifo_errors */
+       read_mac(APPNIC_RX_STAT_OVERFLOW);
+
+       /* 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.
+        */
+
+       /* stats.tx_fifo_errors */
+       read_mac(APPNIC_TX_STAT_UNDERRUN);
+
+       /* 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;
+}
+
+/* ----------------------------------------------------------------------
+ * get_hw_statistics
+ *
+ * NOTE: The hardware clears the statistics registers after a read.
+ */
+
+static void get_hw_statistics(struct appnic_device *pdata)
+{
+       unsigned long flags;
+
+       /* stats.tx_packets */
+       pdata->stats.tx_packets += read_mac(APPNIC_TX_STAT_PACKET_OK);
+
+       /* stats.multicast */
+       pdata->stats.multicast += read_mac(APPNIC_RX_STAT_MULTICAST);
+
+       /* 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);
+
+       /* 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);
+
+       /* stats.tx_fifo_errors */
+       pdata->stats.tx_fifo_errors += read_mac(APPNIC_TX_STAT_UNDERRUN);
+
+       /* Lock this section out so the statistics maintained by the driver
+        * don't get clobbered.
+        */
+
+       spin_lock_irqsave(&pdata->dev_lock, flags);
+
+       pdata->stats.rx_errors +=
+               (pdata->stats.rx_length_errors +
+                pdata->stats.rx_crc_errors +
+                pdata->stats.rx_frame_errors +
+                pdata->stats.rx_fifo_errors +
+                pdata->stats.rx_dropped +
+                pdata->stats.rx_over_errors);
+
+       pdata->stats.rx_dropped = 0;
+       pdata->stats.rx_over_errors = 0;
+
+       pdata->stats.tx_errors += (pdata->stats.tx_fifo_errors +
+                                  pdata->stats.tx_aborted_errors);
+       pdata->stats.tx_aborted_errors = 0;
+
+       spin_unlock_irqrestore(&pdata->dev_lock, flags);
+
+       return;
+}
+
+/* ----------------------------------------------------------------------
+ * queue_initialized
+ *
+ * Returns the number of descriptors that are ready to receive packets
+ * or are waiting to transmit packets.  (from tail to head).
+ */
+
+static int queue_initialized(union appnic_queue_pointer head,
+                            union appnic_queue_pointer tail,
+                            int size)
+{
+       int initialized;
+
+       /* Calculate the number of descriptors currently initialized. */
+       if (head.bits.generation_bit == tail.bits.generation_bit) {
+               /* same generation */
+               initialized = (head.bits.offset - tail.bits.offset);
+       } else {
+               /* different generation */
+               initialized = head.bits.offset +
+                       (size * sizeof(struct appnic_dma_descriptor) -
+                        tail.bits.offset);
+       }
+
+       /* Number of descriptors is offset / sizeof(a descriptor). */
+       initialized /= sizeof(struct appnic_dma_descriptor);
+
+       return initialized;
+}
+
+/* ----------------------------------------------------------------------
+ * queue_uninitialzed
+ *
+ * Returns the number of unused/uninitialized descriptors. (from head to tail).
+*/
+
+static int queue_uninitialized(union appnic_queue_pointer head,
+                              union appnic_queue_pointer tail,
+                              int size)
+{
+       int allocated;
+
+       /* Calculate the number of descriptors currently unused/uninitialized */
+       if (head.bits.generation_bit == tail.bits.generation_bit)
+               /* Same generation. */
+               allocated = ((size * sizeof(struct appnic_dma_descriptor)) -
+                        head.bits.offset) + tail.bits.offset;
+       else
+               /* Different generation. */
+               allocated = tail.bits.offset - head.bits.offset;
+
+       /* Number of descriptors is offset / sizeof(a descriptor). */
+       allocated /= sizeof(struct appnic_dma_descriptor);
+
+       /* That's all. */
+       return allocated;
+}
+
+/* ----------------------------------------------------------------------
+ * queue_increment
+ */
+
+static void queue_increment(union appnic_queue_pointer *queue,
+                           int number_of_descriptors)
+{
+       queue->bits.offset += sizeof(struct appnic_dma_descriptor);
+
+       if ((number_of_descriptors * sizeof(struct appnic_dma_descriptor)) ==
+               queue->bits.offset) {
+
+               queue->bits.offset = 0;
+               queue->bits.generation_bit =
+                       (0 == queue->bits.generation_bit) ? 1 : 0;
+       }
+
+       return;
+}
+
+/* ----------------------------------------------------------------------
+ * queue_decrement
+ */
+
+static void queue_decrement(union appnic_queue_pointer *queue,
+                           int number_of_descriptors)
+{
+       if (0 == queue->bits.offset) {
+               queue->bits.offset =
+                       ((number_of_descriptors - 1) *
+                        sizeof(struct appnic_dma_descriptor));
+               queue->bits.generation_bit =
+                       (0 == queue->bits.generation_bit) ? 1 : 0;
+       } else {
+               queue->bits.offset -= sizeof(struct appnic_dma_descriptor);
+       }
+
+       return;
+}
+
+/* ----------------------------------------------------------------------
+ * disable_rx_tx
+ */
+
+static void disable_rx_tx(struct net_device *dev)
+{
+       struct appnic_device *pdata = netdev_priv(dev);
+       unsigned long tx_configuration;
+       unsigned long rx_configuration;
+
+       rx_configuration = read_mac(APPNIC_RX_CONF);
+       rx_configuration &= ~APPNIC_RX_CONF_ENABLE;
+       write_mac(rx_configuration, APPNIC_RX_CONF);
+
+       tx_configuration = read_mac(APPNIC_TX_CONF);
+       tx_configuration &= ~APPNIC_TX_CONF_ENABLE;
+
+       write_mac(tx_configuration, APPNIC_TX_CONF);
+
+       return;
+}
+
+
+/* ======================================================================
+ *Linux Network Driver Interface
+ * ======================================================================
+*/
+
+/* ----------------------------------------------------------------------
+ * handle_transmit_interrupt
+ */
+
+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.
+        */
+
+       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;
+}
+
+/* ----------------------------------------------------------------------
+ * lsinet_rx_packet
+ */
+
+static void lsinet_rx_packet(struct net_device *dev)
+{
+       struct appnic_device *pdata = netdev_priv(dev);
+       struct appnic_dma_descriptor descriptor;
+       struct sk_buff *sk_buff;
+       unsigned bytes_copied = 0;
+       unsigned error_num = 0;
+       unsigned long ok_stat = 0, overflow_stat = 0;
+       unsigned long crc_stat = 0, align_stat = 0;
+       union appnic_queue_pointer queue;
+
+       readdescriptor(((unsigned long)pdata->rx_desc +
+                       pdata->rx_tail_copy.bits.offset), &descriptor);
+
+       sk_buff = netdev_alloc_skb(NULL, LSINET_MAX_MTU);
+
+       if ((struct sk_buff *)0 == sk_buff) {
+               pr_info_ratelimited("%s: No buffer, packet dropped.\n",
+                                   LSI_DRV_NAME);
+               pdata->stats.rx_dropped++;
+               return;
+       } else {
+               /* Needs to be reviewed.  This fixed an aligment
+                * exception when pinging to the target from a host.
+               */
+
+               /* Align IP on 16 byte boundaries */
+               skb_reserve(sk_buff, 2);
+       }
+
+       ok_stat = read_mac(APPNIC_RX_STAT_PACKET_OK);
+       overflow_stat = read_mac(APPNIC_RX_STAT_OVERFLOW);
+       crc_stat = read_mac(APPNIC_RX_STAT_CRC_ERROR);
+       align_stat = read_mac(APPNIC_RX_STAT_ALIGN_ERROR);
+
+       /* Copy the received packet into the skb. */
+
+       queue = swab_queue_pointer(pdata->rx_tail);
+       while (0 < queue_initialized(queue, pdata->rx_tail_copy,
+                                    pdata->rx_num_desc)) {
+
+               if (skb_tailroom(sk_buff) >= descriptor.pdu_length) {
+                       unsigned char *buffer;
+                       buffer = skb_put(sk_buff, descriptor.pdu_length);
+                       memcpy((void *)buffer,
+                              (void *)(descriptor.host_data_memory_pointer +
+                                pdata->dma_alloc_offset_rx),
+                              descriptor.pdu_length);
+               } else {
+                       pr_err_ratelimited("%s: PDU overrun (%u/%u, %d)\n",
+                                          LSI_DRV_NAME,
+                                          descriptor.pdu_length,
+                                          bytes_copied,
+                                          descriptor.error);
+               }
+               bytes_copied += descriptor.pdu_length;
+               descriptor.data_transfer_length = pdata->rx_buf_per_desc;
+               writedescriptor(((unsigned long)pdata->rx_desc +
+                                       pdata->rx_tail_copy.bits.offset),
+                               &descriptor);
+               if (0 != descriptor.error)
+                       error_num = 1;
+               queue_increment(&pdata->rx_tail_copy, pdata->rx_num_desc);
+               if (0 != descriptor.end_of_packet)
+                       break;
+               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) {
+               pr_err("%s: No end of packet! %lu/%lu/%lu/%lu\n",
+                      LSI_DRV_NAME, ok_stat, overflow_stat,
+                      crc_stat, align_stat);
+               BUG();
+               dev_kfree_skb(sk_buff);
+
+       } else {
+               if (0 == error_num) {
+                       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++;
+                               sk_buff->dev = dev;
+                               sk_buff->protocol = eth_type_trans(sk_buff,
+                                                                  dev);
+                               if (netif_receive_skb(sk_buff) == NET_RX_DROP)
+                                       pdata->dropped_by_stack++;
+                       } else {
+                               dev_kfree_skb(sk_buff);
+                       }
+               } else {
+                       dev_kfree_skb(sk_buff);
+
+                       if (0 != overflow_stat)
+                               pdata->stats.rx_fifo_errors++;
+                       else if (0 != crc_stat)
+                               pdata->stats.rx_crc_errors++;
+                       else if (0 != align_stat)
+                               pdata->stats.rx_frame_errors++;
+               }
+       }
+
+       return;
+}
+
+/* ----------------------------------------------------------------------
+ * lsinet_rx_packets
+ */
+
+static int lsinet_rx_packets(struct net_device *dev, int max)
+{
+       struct appnic_device *pdata = netdev_priv(dev);
+       union appnic_queue_pointer orig_queue, new_queue;
+       int updated_head_pointer = 0;
+       int packets = 0;
+
+       new_queue.raw = pdata->rx_tail_copy.raw;
+
+       /* Receive Packets */
+
+       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 +
+                                 new_queue.bits.offset),
+                               &descriptor);
+
+               if (0 != descriptor.end_of_packet) {
+                       lsinet_rx_packet(dev);
+                       packets++;
+                       new_queue.raw = pdata->rx_tail_copy.raw;
+
+                       if ((-1 != max) && (packets == max))
+                               break;
+               } else {
+                       queue_increment(&new_queue, pdata->rx_num_desc);
+               }
+               orig_queue = swab_queue_pointer(pdata->rx_tail);
+       }
+
+       /* Update the Head Pointer */
+
+       while (1 < queue_uninitialized(pdata->rx_head,
+                                      pdata->rx_tail_copy,
+                                      pdata->rx_num_desc)) {
+
+               struct appnic_dma_descriptor descriptor;
+
+               readdescriptor(((unsigned long)pdata->rx_desc +
+                                 pdata->rx_head.bits.offset), &descriptor);
+               descriptor.data_transfer_length = pdata->rx_buf_per_desc;
+               descriptor.write = 1;
+               descriptor.pdu_length = 0;
+               descriptor.start_of_packet = 0;
+               descriptor.end_of_packet = 0;
+               descriptor.interrupt_on_completion = 1;
+               writedescriptor(((unsigned long)pdata->rx_desc +
+                                  pdata->rx_head.bits.offset),
+                                &descriptor);
+               queue_increment(&pdata->rx_head, pdata->rx_num_desc);
+               updated_head_pointer = 1;
+       }
+
+       if (0 != updated_head_pointer)
+               write_mac(pdata->rx_head.raw, APPNIC_DMA_RX_HEAD_POINTER);
+
+       return packets;
+}
+
+/* ----------------------------------------------------------------------
+ * lsinet_poll
+ */
+
+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;
+
+       int work_done = 0;
+       unsigned long dma_interrupt_status;
+
+       do {
+               /* Acknowledge the RX interrupt. */
+               write_mac(~APPNIC_DMA_INTERRUPT_ENABLE_RECEIVE,
+                          APPNIC_DMA_INTERRUPT_STATUS);
+
+               /* 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));
+
+       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);
+       }
+
+       return work_done;
+}
+
+/* ----------------------------------------------------------------------
+ * appnic_isr
+ */
+
+static irqreturn_t appnic_isr(int irq, void *device_id)
+{
+       struct net_device *dev = (struct net_device *)device_id;
+       struct appnic_device *pdata = netdev_priv(dev);
+       unsigned long dma_interrupt_status;
+       unsigned long flags;
+
+       /* Acquire the lock. */
+       spin_lock_irqsave(&pdata->dev_lock, flags);
+
+       /* Get the status. */
+       dma_interrupt_status = read_mac(APPNIC_DMA_INTERRUPT_STATUS);
+
+       /* NAPI - don't ack RX interrupt */
+       write_mac(APPNIC_DMA_INTERRUPT_ENABLE_RECEIVE,
+                 APPNIC_DMA_INTERRUPT_STATUS);
+
+       /* Handle interrupts. */
+       if (TX_INTERRUPT(dma_interrupt_status)) {
+               /* transmition complete */
+               pdata->transmit_interrupts++;
+               handle_transmit_interrupt(dev);
+       }
+
+       if (RX_INTERRUPT(dma_interrupt_status)) {
+               pdata->receive_interrupts++;
+               if (napi_schedule_prep(&pdata->napi)) {
+
+                       /* Disable RX interrupts and tell the
+                        * system we've got work
+                        */
+                       write_mac(APPNIC_DMA_INTERRUPT_ENABLE_TRANSMIT,
+                                 APPNIC_DMA_INTERRUPT_ENABLE);
+                       __napi_schedule(&pdata->napi);
+               } else {
+                       write_mac(APPNIC_DMA_INTERRUPT_ENABLE_TRANSMIT,
+                                 APPNIC_DMA_INTERRUPT_ENABLE);
+               }
+       }
+
+       /* Release the lock */
+       spin_unlock_irqrestore(&pdata->dev_lock, flags);
+
+       return IRQ_HANDLED;
+}
+
+#ifdef CONFIG_NET_POLL_CONTROLLER
+
+/* ----------------------------------------------------------------------
+ * appnic_poll_controller
+ *
+ * Polling receive - used by netconsole and other diagnostic tools
+ * to allow network i/o with interrupts disabled.
+ */
+
+static void appnic_poll_controller(struct net_device *dev)
+{
+       disable_irq(dev->irq);
+       appnic_isr(dev->irq, dev);
+       enable_irq(dev->irq);
+}
+
+#endif
+
+
+/* ----------------------------------------------------------------------
+ * appnic_open
+ *
+ * Opens the interface.  The interface is opened whenever ifconfig
+ * activates it.  The open method should register any system resource
+ * it needs (I/O ports, IRQ, DMA, etc.) turn on the hardware, and
+ * increment the module usage count.
+ */
+
+static int appnic_open(struct net_device *dev)
+{
+       struct appnic_device *pdata = netdev_priv(dev);
+       int return_code = 0;
+
+       /* Bring the PHY up. */
+       phy_start(pdata->phy_dev);
+
+       /* Enable NAPI. */
+       napi_enable(&pdata->napi);
+
+       /* Install the interrupt handlers. */
+       return_code = request_irq(dev->irq, appnic_isr, IRQF_DISABLED,
+                                  LSI_DRV_NAME, dev);
+       if (0 != return_code) {
+               pr_err("%s: request_irq() failed, returned 0x%x/%d\n",
+                      LSI_DRV_NAME, return_code, return_code);
+               return return_code;
+       }
+
+       /* Enable interrupts. */
+       write_mac((APPNIC_DMA_INTERRUPT_ENABLE_RECEIVE |
+                  APPNIC_DMA_INTERRUPT_ENABLE_TRANSMIT),
+                  APPNIC_DMA_INTERRUPT_ENABLE);
+
+       /* Let the OS know we are ready to send packets. */
+       netif_start_queue(dev);
+
+       /* That's all. */
+       return 0;
+}
+
+/* ----------------------------------------------------------------------
+ * appnic_stop
+ *
+ * Stops the interface.  The interface is stopped when it is brought
+ * down; operations performed at open time should be reversed.
+ */
+
+static int appnic_stop(struct net_device *dev)
+{
+       struct appnic_device *pdata = netdev_priv(dev);
+
+       pr_info("%s: Stopping the interface.\n", LSI_DRV_NAME);
+
+       /* Disable all device interrupts. */
+       write_mac(0, APPNIC_DMA_INTERRUPT_ENABLE);
+       free_irq(dev->irq, dev);
+
+       /* Indicate to the OS that no more packets should be sent.  */
+       netif_stop_queue(dev);
+       napi_disable(&pdata->napi);
+
+       /* Stop the receiver and transmitter. */
+       disable_rx_tx(dev);
+
+       /* Bring the PHY down. */
+       if (pdata->phy_dev)
+               phy_stop(pdata->phy_dev);
+
+       /* That's all. */
+       return 0;
+}
+
+/* ----------------------------------------------------------------------
+ * appnic_hard_start_xmit
+ *
+ * The method initiates the transmission of a packet.  The full packet
+ * (protocol headers and all) is contained in a socket buffer (sk_buff)
+ * structure.
+ *
+ * ----- NOTES -----
+ *
+ * 1) This will not get called again by the kernel until it returns.
+ */
+
+static int appnic_hard_start_xmit(struct sk_buff *skb,
+                      struct net_device *dev)
+{
+       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;
+
+       /* 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,
+                                   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, queue,
+                                   pdata->tx_num_desc)) {
+               int bytes_copied = 0;
+               struct appnic_dma_descriptor descriptor;
+
+               readdescriptor(((unsigned long)pdata->tx_desc +
+                               pdata->tx_head.bits.offset), &descriptor);
+               descriptor.start_of_packet = 1;
+
+               while (bytes_copied < length) {
+                       descriptor.write = 1;
+                       descriptor.pdu_length = length;
+
+                       if ((length - bytes_copied) > buf_per_desc) {
+                               memcpy((void *)
+                                       (descriptor.host_data_memory_pointer +
+                                        pdata->dma_alloc_offset_tx),
+                                      (void *) ((unsigned long) skb->data +
+                                       bytes_copied),
+                                       buf_per_desc);
+                               descriptor.data_transfer_length = buf_per_desc;
+                               descriptor.end_of_packet = 0;
+                               descriptor.interrupt_on_completion = 0;
+                               bytes_copied += buf_per_desc;
+                       } else {
+                               memcpy((void *)
+                                       (descriptor.host_data_memory_pointer +
+                                        pdata->dma_alloc_offset_tx),
+                                      (void *) ((unsigned long) skb->data +
+                                       bytes_copied),
+                                       (length - bytes_copied));
+                               descriptor.data_transfer_length =
+                                (length - bytes_copied);
+                               descriptor.end_of_packet = 1;
+                               /* 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;
+                               bytes_copied = length;
+                       }
+
+                       pdata->stats.tx_bytes += bytes_copied;
+                       writedescriptor(((unsigned long) pdata->tx_desc +
+                               pdata->tx_head.bits.offset), &descriptor);
+                       queue_increment(&pdata->tx_head, pdata->tx_num_desc);
+                       readdescriptor(((unsigned long)pdata->tx_desc +
+                                        pdata->tx_head.bits.offset),
+                                       &descriptor);
+                       descriptor.start_of_packet = 0;
+               }
+
+               /* Data sync barrier. */
+               rmb();
+
+               write_mac(pdata->tx_head.raw, APPNIC_DMA_TX_HEAD_POINTER);
+               dev->trans_start = jiffies;
+
+       } else {
+               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 NETDEV_TX_OK;
+}
+
+/* ----------------------------------------------------------------------
+ * appnic_net_device_stats
+ *
+ * Whenever an application needs to get statistics for the interface,
+ * this method is called.  This happens, for example, when ifconfig or
+ * nstat -i is run.
+ */
+
+static struct net_device_stats *appnic_get_stats(struct net_device *dev)
+{
+       struct appnic_device *pdata = netdev_priv(dev);
+
+       /* Update the statistics structure. */
+
+       get_hw_statistics(pdata);
+
+       return &pdata->stats;
+}
+
+/* ----------------------------------------------------------------------
+ * appnic_set_mac_address
+ */
+
+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;
+
+       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];
+       write_mac(swap_source_address, APPNIC_SWAP_SOURCE_ADDRESS_2);
+       swap_source_address = ((address->sa_data[2]) << 8) |
+                       address->sa_data[3];
+       write_mac(swap_source_address, APPNIC_SWAP_SOURCE_ADDRESS_1);
+       swap_source_address = ((address->sa_data[0]) << 8) |
+                              address->sa_data[1];
+       write_mac(swap_source_address, APPNIC_SWAP_SOURCE_ADDRESS_0);
+       memcpy(dev->dev_addr, address->sa_data, dev->addr_len);
+
+       return 0;
+}
+
+/* ======================================================================
+ * 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;
+       }
+}
+
+/* ----------------------------------------------------------------------
+ * appnic_get_drvinfo
+ */
+
+static void appnic_get_drvinfo(struct net_device *dev,
+                              struct ethtool_drvinfo *info)
+{
+       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));
+}
+
+/* ----------------------------------------------------------------------
+ * appnic_get_settings
+ */
+
+static int appnic_get_settings(struct net_device *dev,
+                              struct ethtool_cmd *cmd)
+{
+       struct appnic_device *pdata = netdev_priv(dev);
+       struct phy_device *phydev = pdata->phy_dev;
+
+       if (!phydev)
+               return -ENODEV;
+
+       return phy_ethtool_gset(phydev, cmd);
+}
+
+/* Fill in the struture...  */
+
+static const struct ethtool_ops appnic_ethtool_ops = {
+       .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.
+ * ======================================================================
+ */
+
+static const struct net_device_ops appnic_netdev_ops = {
+       .ndo_open = appnic_open,
+       .ndo_stop = appnic_stop,
+       .ndo_get_stats = appnic_get_stats,
+       .ndo_set_mac_address = appnic_set_mac_address,
+       .ndo_start_xmit = appnic_hard_start_xmit,
+#ifdef CONFIG_NET_POLL_CONTROLLER
+       .ndo_poll_controller = appnic_poll_controller,
+#endif
+
+};
+
+/* ----------------------------------------------------------------------
+ * appnic_init
+ */
+
+int appnic_init(struct net_device *dev)
+{
+       struct appnic_device *pdata = netdev_priv(dev);
+       void *dma_offset;
+       int index;
+       unsigned long buf;
+       struct appnic_dma_descriptor descriptor;
+       struct sockaddr address;
+       unsigned long node_cfg;
+       int rc = 0;
+
+       /* Set FEMAC to uncached */
+       femac_uncache(pdata);
+
+       /* Reset the MAC. */
+
+       write_mac(0x80000000, APPNIC_DMA_PCI_CONTROL);
+
+       /* Allocate memory and initialize the descriptors. */
+
+       /* fixup num_[rt]x_desc. */
+
+       if (0 != (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_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;
+
+       /* up [rt]x_buf_sz. Must be some multiple of 64 bytes
+        * per descriptor.
+        */
+
+       if (0 != (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_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;
+
+       /* Allocate dma-able memory. Broken into smaller parts to keep
+        * from allocating a single large chunk of memory, but not too
+        * small since mappings obtained from dma_alloc_coherent() have
+        * a minimum size of one page.
+        */
+
+       pdata->dma_alloc_size =
+               /* The tail pointers (rx and tx) */
+               (sizeof(union appnic_queue_pointer) * 2) +
+               /* The RX descriptor ring (and padding to allow
+                * 64 byte alignment)
+                */
+               (sizeof(struct appnic_dma_descriptor) * pdata->rx_num_desc) +
+               (DESCRIPTOR_GRANULARITY) +
+               /* The TX descriptor ring (and padding...) */
+               (sizeof(struct appnic_dma_descriptor) * pdata->tx_num_desc) +
+               (DESCRIPTOR_GRANULARITY);
+
+       pdata->dma_alloc_size_rx =
+               /* The RX buffer (and padding...) */
+               (pdata->rx_buf_sz) + (BUFFER_ALIGNMENT);
+
+       pdata->dma_alloc_size_tx =
+               /* The TX buffer (and padding...) */
+               (pdata->tx_buf_sz) + (BUFFER_ALIGNMENT);
+
+       /* Allocate the buffers. */
+
+       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;
+       }
+
+       /* Initialize the tail pointers. */
+
+       dma_offset = pdata->dma_alloc;
+
+       pdata->rx_tail = (union appnic_queue_pointer *)dma_offset;
+       pdata->rx_tail_dma = (int)pdata->rx_tail - (int)pdata->dma_alloc_offset;
+       dma_offset += sizeof(union appnic_queue_pointer);
+       memset((void *)pdata->rx_tail, 0,
+              sizeof(union appnic_queue_pointer));
+
+
+       pdata->tx_tail = (union appnic_queue_pointer *)dma_offset;
+       pdata->tx_tail_dma = (int)pdata->tx_tail - (int)pdata->dma_alloc_offset;
+       dma_offset += sizeof(union appnic_queue_pointer);
+       memset((void *)pdata->tx_tail, 0, sizeof(union appnic_queue_pointer));
+
+       /* Initialize the descriptor pointers. */
+
+       pdata->rx_desc = (struct appnic_dma_descriptor *)ALIGN64B(dma_offset);
+       pdata->rx_desc_dma = (int)pdata->rx_desc - (int)pdata->dma_alloc_offset;
+       dma_offset += (sizeof(struct appnic_dma_descriptor) *
+                       pdata->rx_num_desc) + (DESCRIPTOR_GRANULARITY);
+       memset((void *)pdata->rx_desc, 0,
+              (sizeof(struct appnic_dma_descriptor) * pdata->rx_num_desc));
+
+       pdata->tx_desc = (struct appnic_dma_descriptor *)ALIGN64B(dma_offset);
+       pdata->tx_desc_dma = (int)pdata->tx_desc - (int)pdata->dma_alloc_offset;
+       dma_offset += (sizeof(struct appnic_dma_descriptor) *
+                       pdata->tx_num_desc) + (DESCRIPTOR_GRANULARITY);
+       memset((void *)pdata->tx_desc, 0,
+              (sizeof(struct appnic_dma_descriptor) * pdata->tx_num_desc));
+
+       /* Initialize the buffer pointers. */
+
+       dma_offset = pdata->dma_alloc_rx;
+
+       pdata->rx_buf = (void *)ALIGN64B(dma_offset);
+       pdata->rx_buf_dma = (int)pdata->rx_buf -
+                               (int)pdata->dma_alloc_offset_rx;
+       pdata->rx_buf_per_desc = pdata->rx_buf_sz / pdata->rx_num_desc;
+
+       dma_offset = pdata->dma_alloc_tx;
+
+       pdata->tx_buf = (void *)ALIGN64B(dma_offset);
+       pdata->tx_buf_dma = (int)pdata->tx_buf -
+                               (int)pdata->dma_alloc_offset_tx;
+       pdata->tx_buf_per_desc = pdata->tx_buf_sz / pdata->tx_num_desc;
+
+       /* Initialize the descriptors. */
+
+       buf = (unsigned long)pdata->rx_buf_dma;
+       for (index = 0; index < pdata->rx_num_desc; ++index) {
+               memset((void *) &descriptor, 0,
+                      sizeof(struct appnic_dma_descriptor));
+               descriptor.write = 1;
+               descriptor.interrupt_on_completion = 1;
+               descriptor.host_data_memory_pointer = buf;
+               descriptor.data_transfer_length = pdata->rx_buf_per_desc;
+
+               writedescriptor(((unsigned long)pdata->rx_desc + (index *
+                               sizeof(struct appnic_dma_descriptor))),
+                               &descriptor);
+
+               buf += pdata->rx_buf_per_desc;
+       }
+
+       buf = (unsigned long)pdata->tx_buf_dma;
+
+       for (index = 0; index < pdata->tx_num_desc; ++index) {
+               memset((void *) &descriptor, 0,
+                      sizeof(struct appnic_dma_descriptor));
+               descriptor.write = 1;
+               descriptor.interrupt_on_completion = 1;
+               descriptor.host_data_memory_pointer = buf;
+
+               writedescriptor(((unsigned long)pdata->tx_desc + (index *
+                                sizeof(struct appnic_dma_descriptor))),
+                               &descriptor);
+
+               buf += pdata->tx_buf_per_desc;
+       }
+
+       /* Initialize the spinlocks. */
+
+       spin_lock_init(&pdata->dev_lock);
+
+       /* Take MAC out of reset. */
+
+       write_mac(0x0, APPNIC_RX_SOFT_RESET);
+       write_mac(0x1, APPNIC_RX_MODE);
+       write_mac(0x0, APPNIC_TX_SOFT_RESET);
+       write_mac(0x1, APPNIC_TX_MODE);
+
+       /* Set the watermark. */
+
+       ncr_read(NCP_REGION_ID(0x16, 0xff), 0x10, 4, &node_cfg);
+
+       if (0 == (0x80000000 & node_cfg))
+               write_mac(0x300a, APPNIC_TX_WATERMARK);
+       else
+               write_mac(0xc00096, APPNIC_TX_WATERMARK);
+
+       write_mac(0x1, APPNIC_TX_HALF_DUPLEX_CONF);
+       write_mac(0xffff, APPNIC_TX_TIME_VALUE_CONF);
+       write_mac(0x1, APPNIC_TX_INTERRUPT_CONTROL);
+       write_mac(0x5275, APPNIC_TX_EXTENDED_CONF);
+       write_mac(0x1, APPNIC_RX_INTERNAL_INTERRUPT_CONTROL);
+       write_mac(0x1, APPNIC_RX_EXTERNAL_INTERRUPT_CONTROL);
+       write_mac(0x40010000, APPNIC_DMA_PCI_CONTROL);
+       write_mac(0x30000, APPNIC_DMA_CONTROL);
+#ifdef CONFIG_ARM
+       writel(0x280044,
+              (void __iomem *)((unsigned long)pdata->dma_base + 0x60));
+       writel(0xc0,
+              (void __iomem *)((unsigned long)pdata->dma_base + 0x64));
+#else
+       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 %pM\n", LSI_DRV_NAME, dev->dev_addr);
+
+       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. */
+
+       /* Receiver. */
+
+       memset((void *)&pdata->rx_tail_copy, 0,
+              sizeof(union appnic_queue_pointer));
+       memset((void *)&pdata->rx_head, 0,
+              sizeof(union appnic_queue_pointer));
+
+       write_mac(pdata->rx_desc_dma, APPNIC_DMA_RX_QUEUE_BASE_ADDRESS);
+       write_mac((pdata->rx_num_desc *
+                  sizeof(struct appnic_dma_descriptor)) / 1024,
+                 APPNIC_DMA_RX_QUEUE_SIZE);
+
+       /* Indicate that all of the receive descriptors
+        * are ready.
+        */
+
+       pdata->rx_head.bits.offset = (pdata->rx_num_desc - 1) *
+                                       sizeof(struct appnic_dma_descriptor);
+       write_mac(pdata->rx_tail_dma, APPNIC_DMA_RX_TAIL_POINTER_ADDRESS);
+
+       /* N.B.
+        *
+        * The boot loader may have used the NIC.  If so, the
+        * tail pointer must be read and the head pointer (and
+        * local copy of the tail) based on it.
+        */
+
+       pdata->rx_tail->raw =
+                 read_mac(APPNIC_DMA_RX_TAIL_POINTER_LOCAL_COPY);
+       pdata->rx_tail_copy.raw = pdata->rx_tail->raw;
+       pdata->rx_head.raw = pdata->rx_tail->raw;
+       queue_decrement(&pdata->rx_head, pdata->rx_num_desc);
+       pdata->rx_head.bits.generation_bit =
+                 (0 == pdata->rx_head.bits.generation_bit) ? 1 : 0;
+       write_mac(pdata->rx_head.raw, APPNIC_DMA_RX_HEAD_POINTER);
+
+       /* Transmitter. */
+
+       memset((void *) &pdata->tx_tail_copy, 0,
+              sizeof(union appnic_queue_pointer));
+       memset((void *) &pdata->tx_head, 0,
+              sizeof(union appnic_queue_pointer));
+
+       write_mac(pdata->tx_desc_dma, APPNIC_DMA_TX_QUEUE_BASE_ADDRESS);
+       write_mac((pdata->tx_num_desc *
+                  sizeof(struct appnic_dma_descriptor)) / 1024,
+                 APPNIC_DMA_TX_QUEUE_SIZE);
+       write_mac(pdata->tx_tail_dma, APPNIC_DMA_TX_TAIL_POINTER_ADDRESS);
+
+       /* N.B.
+        *
+        * The boot loader may have used the NIC.  If so, the
+        * tail pointer must be read and the head pointer (and
+        * local copy of the tail) based on it.
+        */
+
+       pdata->tx_tail->raw = read_mac(APPNIC_DMA_TX_TAIL_POINTER_LOCAL_COPY);
+       pdata->tx_tail_copy.raw = pdata->tx_tail->raw;
+       pdata->tx_head.raw = pdata->tx_tail->raw;
+       write_mac(pdata->tx_head.raw, APPNIC_DMA_TX_HEAD_POINTER);
+
+       /* Clear statistics. */
+
+       clear_statistics(pdata);
+
+       /* Fill in the net_device structure. */
+
+       ether_setup(dev);
+
+       /* Setup IRQ. */
+       rc = femac_irq_setup(dev);
+       if (rc != 0) {
+               pr_err("%s: IRQ setup failed!\n", LSI_DRV_NAME);
+               goto err_irq_setup;
+       }
+
+       dev->netdev_ops = &appnic_netdev_ops;
+       dev->ethtool_ops = &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;
+
+       return 0;
+
+err_irq_setup:
+err_set_mac_addr:
+       femac_free_mem_buffers(dev);
+err_mem_buffers:
+err_param:
+       return rc;
+}
+
+/* ----------------------------------------------------------------------
+ * appnic_probe_config_dt
+ */
+
+#ifdef CONFIG_OF
+static int appnic_probe_config_dt(struct net_device *dev,
+                                 struct device_node *np)
+{
+       struct appnic_device *pdata = netdev_priv(dev);
+       const u32 *field;
+       const char *mac;
+       const char *macspeed;
+#ifdef CONFIG_ARM
+       struct device_node *gp_node;
+#else
+       u64 value64;
+       u32 value32;
+#endif
+
+       if (!np)
+               return -ENODEV;
+
+#ifdef CONFIG_ARM
+       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)))
+               goto device_tree_failed;
+
+       field = of_get_property(np, "reg", NULL);
+
+       if (!field)
+               goto device_tree_failed;
+
+       value64 = of_translate_address(np, field);
+       value32 = field[3];
+       field += 2;
+       pdata->rx_base = ioremap(value64, value32);
+       value64 = of_translate_address(np, field);
+       value32 = field[3];
+       field += 2;
+       pdata->tx_base = ioremap(value64, value32);
+       value64 = of_translate_address(np, field);
+       value32 = field[3];
+       field += 2;
+       pdata->dma_base = ioremap(value64, value32);
+
+       field = of_get_property(np, "interrupts", NULL);
+       if (!field)
+               goto device_tree_failed;
+       else
+               pdata->dma_interrupt = field[0];
+#endif
+
+       field = of_get_property(np, "mdio-clock", NULL);
+       if (!field)
+               goto device_tree_failed;
+       else
+               pdata->mdio_clock = ntohl(field[0]);
+
+       field = of_get_property(np, "phy-address", NULL);
+       if (!field)
+               goto device_tree_failed;
+       else
+               pdata->phy_address = ntohl(field[0]);
+
+       field = of_get_property(np, "ad-value", NULL);
+       if (!field)
+               goto device_tree_failed;
+       else
+               pdata->ad_value = ntohl(field[0]);
+
+       macspeed = of_get_property(np, "phy-link", NULL);
+
+       if (macspeed) {
+               if (0 == strncmp(macspeed, "auto", strlen("auto"))) {
+                       pdata->phy_link_auto = 1;
+               } else if (0 == strncmp(macspeed, "100MF", strlen("100MF"))) {
+                       pdata->phy_link_auto = 0;
+                       pdata->phy_link_speed = 1;
+                       pdata->phy_link_duplex = 1;
+               } else if (0 == strncmp(macspeed, "100MH", strlen("100MH"))) {
+                       pdata->phy_link_auto = 0;
+                       pdata->phy_link_speed = 1;
+                       pdata->phy_link_duplex = 0;
+               } else if (0 == strncmp(macspeed, "10MF", strlen("10MF"))) {
+                       pdata->phy_link_auto = 0;
+                       pdata->phy_link_speed = 0;
+                       pdata->phy_link_duplex = 1;
+               } else if (0 == strncmp(macspeed, "10MH", strlen("10MH"))) {
+                       pdata->phy_link_auto = 0;
+                       pdata->phy_link_speed = 0;
+                       pdata->phy_link_duplex = 0;
+               } else {
+                       pr_err("Invalid phy-link value \"%s\" in DTS. 
Defaulting to \"auto\".\n",
+                                       macspeed);
+                       pdata->phy_link_auto = 1;
+               }
+       } else {
+               /* Auto is the default. */
+               pdata->phy_link_auto = 1;
+       }
+
+       mac = of_get_mac_address(np);
+       if (!mac)
+               goto device_tree_failed;
+
+       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);
+#ifdef CONFIG_ARM
+       iounmap(pdata->gpreg_base);
+#endif
+       iounmap(pdata->rx_base);
+       iounmap(pdata->tx_base);
+       iounmap(pdata->dma_base);
+
+       return -EINVAL;
+}
+#else
+static inline int appnic_probe_config_dt(struct net_device *dev,
+                                        struct device_node *np)
+{
+       return -ENODEV;
+}
+#endif /* CONFIG_OF */
+
+/* ----------------------------------------------------------------------
+ * appnic_drv_probe
+ */
+
+static int appnic_drv_probe(struct platform_device *pdev)
+{
+       int rc = 0;
+       struct device_node *np = pdev->dev.of_node;
+       struct net_device *dev;
+       struct appnic_device *pdata;
+
+       pr_info("%s: LSI(R) 10/100 Network Driver - version %s\n",
+               LSI_DRV_NAME, LSI_DRV_VERSION);
+
+       /* Allocate space for the device. */
+
+       dev = alloc_etherdev(sizeof(struct appnic_device));
+       if (!dev) {
+               pr_err("%s: Couldn't allocate net device.\n", LSI_DRV_NAME);
+               rc = -ENOMEM;
+               goto err_alloc_etherdev;
+       }
+
+       SET_NETDEV_DEV(dev, &pdev->dev);
+       platform_set_drvdata(pdev, dev);
+
+       pdata = netdev_priv(dev);
+
+       /* Get the physical addresses, interrupt number, etc. from the
+        * device tree.  If no entry exists (older boot loader...) just
+        * use the pre-devicetree method.
+        */
+
+       rc = appnic_probe_config_dt(dev, np);
+
+       if (rc == -EINVAL) {
+               goto err_inval;
+       } else if (rc == -EINVAL) {
+
+#ifdef CONFIG_MTD_NAND_EP501X_UBOOTENV
+
+               /* 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.
+                */
+
+               unsigned char ethaddr_string[20];
+
+               if (0 != ubootenv_get("ethaddr", ethaddr_string)) {
+                       pr_err("%s: Could not read ethernet address!\n",
+                              LSI_DRV_NAME);
+                       rc = -EINVAL;
+                       goto err_inval;
+               } else {
+                       u8 mac_address[ETH_ALEN];
+                       int i = 0;
+                       char *string = ethaddr_string;
+
+                       while ((0 != string) && (ETH_ALEN > i)) {
+                               char *value;
+                               unsigned long res;
+                               value = strsep(&string, ":");
+                               if (kstrtoul(value, 16, &res))
+                                       return -EBUSY;
+                               mac_address[i++] = (u8)res;
+                       }
+
+                       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);
+                       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);
+               rc = -EINVAL;
+               goto err_inval;
+#endif
+       }
+
+#ifdef CONFIG_MTD_NAND_EP501X_UBOOTENV
+
+       {
+               unsigned char uboot_env_string[20];
+
+               /* Override ad_value with u-boot environment variable if set. */
+               if (0 == ubootenv_get("ad_value", uboot_env_string)) {
+                       /* Assume ad_value is always entered as a hex value,
+                        * since u-boot defaults this value as hex.
+                        */
+                       unsigned long res;
+                       if (kstrtoul(uboot_env_string, 16, &res)) {
+                               rc = -EINVAL;
+                               goto err_inval;
+                       }
+                       pdata->ad_value = res;
+               }
+       }
+
+#endif
+
+       /* Initialize the device. */
+       rc = appnic_init(dev);
+       if (0 != rc) {
+               pr_err("%s: appnic_init() failed: %d\n", LSI_DRV_NAME, rc);
+               rc = -ENODEV;
+               goto err_nodev;
+       }
+
+       /* Register the device. */
+       rc = register_netdev(dev);
+       if (0 != rc) {
+               pr_err("%s: register_netdev() failed: %d\n", LSI_DRV_NAME, rc);
+               rc = -ENODEV;
+               goto err_nodev;
+       }
+
+       /* Initialize the PHY. */
+       rc = appnic_mii_init(pdev, dev);
+       if (rc) {
+               pr_warn("%s: Failed to initialize PHY", LSI_DRV_NAME);
+               rc = -ENODEV;
+               goto err_mii_init;
+       }
+
+       return 0;
+
+err_mii_init:
+       unregister_netdev(dev);
+err_nodev:
+err_inval:
+       free_netdev(dev);
+err_alloc_etherdev:
+       return rc;
+}
+
+/* ----------------------------------------------------------------------
+ * appnic_drv_remove
+ */
+
+static int appnic_drv_remove(struct platform_device *pdev)
+{
+       struct net_device *dev = platform_get_drvdata(pdev);
+       struct appnic_device *pdata = NULL;
+
+       pr_info("%s: Stopping driver", LSI_DRV_NAME);
+
+       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(pdata->rx_base);
+       iounmap(pdata->tx_base);
+       iounmap(pdata->dma_base);
+#ifdef CONFIG_ARM
+       iounmap(pdata->gpreg_base);
+#endif
+
+       return 0;
+}
+
+static const struct of_device_id appnic_dt_ids[] = {
+       { .compatible = "lsi,acp-femac", },
+       { .compatible = "acp-femac", },
+       { /* end of list */ },
+};
+MODULE_DEVICE_TABLE(of, appnic_dt_ids);
+
+static struct platform_driver appnic_driver = {
+       .probe = appnic_drv_probe,
+       .remove = appnic_drv_remove,
+       .driver = {
+               .name   = LSI_DRV_NAME,
+               .owner  = THIS_MODULE,
+               .pm     = NULL,
+               .of_match_table = appnic_dt_ids,
+       },
+};
+
+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
new file mode 100644
index 0000000..ac891cf
--- /dev/null
+++ b/drivers/net/ethernet/lsi/lsi_acp_net.h
@@ -0,0 +1,670 @@
+/*
+ * drivers/net/ethernet/lsi/lsi_acp_net.h
+ *
+ * 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
+ */
+
+#ifndef _LSI_ACP_NET_H
+#define _LSI_ACP_NET_H
+
+#ifdef CONFIG_MTD_NAND_EP501X_UBOOTENV
+extern int ubootenv_get(const char *, char *);
+#endif
+
+extern int acp_mdio_read(unsigned long, unsigned long, unsigned short *, int);
+extern int acp_mdio_write(unsigned long, unsigned long, unsigned short, int);
+
+/* This is the maximum number of packets to be received every
+ * NAPI poll
+ */
+#define LSINET_NAPI_WEIGHT     64
+
+/* 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 __LITTLE_ENDIAN
+       /* Word 0 */
+       /* 00=Fill|01=Block|10=Scatter */
+       unsigned long transfer_type:2;
+       unsigned long write:1;
+       unsigned long start_of_packet:1;
+       unsigned long end_of_packet:1;
+       unsigned long interrupt_on_completion:1;
+       unsigned long error:1;
+       /* big endian to little endian */
+       unsigned long byte_swapping_on:1;
+       unsigned long unused:24;
+
+       /* Word 1 */
+       unsigned long data_transfer_length:16;
+       unsigned long pdu_length:16;
+
+       /* Word 2 */
+       unsigned long target_memory_address;
+
+       /* Word 3 */
+       unsigned long host_data_memory_pointer;
+#else
+       /* Word 0 */
+       unsigned long unused:24;
+       /* big endian to little endian */
+       unsigned long byte_swapping_on:1;
+       unsigned long error:1;
+       unsigned long interrupt_on_completion:1;
+       unsigned long end_of_packet:1;
+       unsigned long start_of_packet:1;
+       unsigned long write:1;
+       /* 00=Fill|01=Block|10=Scatter */
+       unsigned long transfer_type:2;
+
+       /* Word 1 */
+       unsigned long pdu_length:16;
+       unsigned long data_transfer_length:16;
+
+       /* Word 2 */
+       unsigned long target_memory_address;
+
+       /* Word 3 */
+       unsigned long host_data_memory_pointer;
+#endif
+
+} __packed;
+
+union appnic_queue_pointer {
+
+       unsigned long raw;
+
+       struct {
+#ifdef __LITTLE_ENDIAN
+               unsigned long offset:20;
+               unsigned long generation_bit:1;
+               unsigned long unused:11;
+#else
+               unsigned long unused:11;
+               unsigned long generation_bit:1;
+               unsigned long offset:20;
+#endif
+       } __packed bits;
+
+} __packed;
+
+/* The appnic Device Structure */
+
+struct appnic_device {
+
+       /* net_device */
+       struct net_device *device;
+
+       /* Addresses, Interrupt, and PHY stuff. */
+       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;
+       unsigned long mdio_clock;
+       unsigned long phy_address;
+       unsigned long ad_value;
+       unsigned long phy_link_auto;
+       unsigned long phy_link_speed;
+       unsigned long phy_link_duplex;
+       unsigned char mac_addr[6];
+
+       /* NAPI */
+       struct napi_struct napi;
+
+       /* 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;
+       int dma_alloc_size_rx;
+       int dma_alloc_size_tx;
+       void *dma_alloc;
+       void *dma_alloc_rx;
+       void *dma_alloc_tx;
+       dma_addr_t dma_alloc_dma;
+       dma_addr_t dma_alloc_dma_rx;
+       dma_addr_t dma_alloc_dma_tx;
+       int dma_alloc_offset;
+       int dma_alloc_offset_rx;
+       int dma_alloc_offset_tx;
+
+       /* tail pointers */
+       volatile union appnic_queue_pointer *rx_tail;
+       dma_addr_t rx_tail_dma;
+       volatile union appnic_queue_pointer *tx_tail;
+       dma_addr_t tx_tail_dma;
+
+       /* descriptors */
+       struct appnic_dma_descriptor *rx_desc;
+       dma_addr_t rx_desc_dma;
+       unsigned rx_num_desc;
+       struct appnic_dma_descriptor *tx_desc;
+       dma_addr_t tx_desc_dma;
+       unsigned tx_num_desc;
+
+       /* buffers */
+       unsigned rx_buf_sz;
+       unsigned rx_buf_per_desc;
+       void *rx_buf;
+       dma_addr_t rx_buf_dma;
+       unsigned tx_buf_sz;
+       unsigned tx_buf_per_desc;
+       void *tx_buf;
+       dma_addr_t tx_buf_dma;
+
+       /* The local pointers */
+       union appnic_queue_pointer rx_tail_copy;
+       union appnic_queue_pointer rx_head;
+       union appnic_queue_pointer tx_tail_copy;
+       union appnic_queue_pointer tx_head;
+
+       /* Spin Lock */
+       spinlock_t dev_lock;
+
+       /* PHY */
+       struct mii_bus *mii_bus;
+       struct phy_device *phy_dev;
+       int phy_irq[PHY_MAX_ADDR];
+       unsigned int link;
+       unsigned int speed;
+       unsigned int duplex;
+};
+
+/* GPREG FEMAC HPROT Register --------------------------------------- */
+
+#define GPREG_HPROT_FEMAC      ((unsigned long)pdata->gpreg_base + 0x78)
+
+/* Overview
+ * --------
+ *
+ * Register offset decoding is as follows:
+ *
+ * Bit(s) Description
+ *
+ * 16:15  define the Channel.  There is only one; therefore, 00.
+ * 14:12  define the MAC within the channel.  Only one so 000.
+ * 11:10  define the register "space" as follows:
+ * 00 = fast ethernet MACmw.l 06000000 ffffffff 3200000
+ * 10 = global
+ * 11 = interrupt
+ * 9: 2  register
+ * 1: 0  always 00, 32 bit registers only.
+ *
+ * Receive registers start at the base address.  Transmit registers start
+ * at 0x20000 above the base address.  DMA start at a completely different
+ * base address (in this case 0x8000000 above the base).
+ *
+*/
+
+/* Receive Configuration -------------------------------------------- */
+
+#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
+#define APPNIC_RX_CONF_JUMBO9K  0x0008
+#define APPNIC_RX_CONF_STRIPCRC 0x0010
+/* Accept All MAC Types */
+#define APPNIC_RX_CONF_AMT     0x0020
+/* Accept Flow Control */
+#define APPNIC_RX_CONF_AFC     0x0040
+/* Enable VLAN */
+#define APPNIC_RX_CONF_VLAN    0x0200
+/* RX MAC Speed, 1=100MBS */
+#define APPNIC_RX_CONF_SPEED    0x0800
+/* 1=Duplex Mode */
+#define APPNIC_RX_CONF_DUPLEX   0x1000
+/* 1=Enable */
+#define APPNIC_RX_CONF_LINK    0x2000
+/* Determines the action taken when the FE MAC
+ * receives an Flow Control packet in FD mode.
+ */
+#define APPNIC_RX_CONF_RXFCE    0x4000
+
+/* 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 ((unsigned long)pdata->rx_base + 0x278)
+
+/* Receive Stat Undersize ------------------------------------------- */
+
+#define APPNIC_RX_STAT_UNDERSIZE ((unsigned long)pdata->rx_base + 0x280)
+
+/* Receive Stat Oversize -------------------------------------------- */
+
+#define APPNIC_RX_STAT_OVERSIZE ((unsigned long)pdata->rx_base + 0x2b8)
+
+/* Receive Stat Multicast ------------------------------------------- */
+
+#define APPNIC_RX_STAT_MULTICAST ((unsigned long)pdata->rx_base + 0x2d0)
+
+/* Receive Stat Packet OK ------------------------------------------- */
+
+#define APPNIC_RX_STAT_PACKET_OK ((unsigned long)pdata->rx_base + 0x2c0)
+
+/* Receive Stat CRC Error ------------------------------------------- */
+
+#define APPNIC_RX_STAT_CRC_ERROR ((unsigned long)pdata->rx_base + 0x2c8)
+
+/* Receive Stat Align Error ----------------------------------------- */
+
+#define APPNIC_RX_STAT_ALIGN_ERROR ((unsigned long)pdata->rx_base + 0x2e8)
+
+/* Receive Ethernet Mode -------------------------------------------- */
+
+#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 ((unsigned long)pdata->rx_base + 0x0808)
+#define APPNIC_RX_SOFT_RESET_MAC_0 0x00001
+
+/* Receive Internal Interrupt Control ------------------------------- */
+
+#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 \
+       ((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 ((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 ((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
+#define APPNIC_TX_WATERMARK_TXCONFIG_DTPA_WATER_MARK_LOW 0x3f
+
+/* Swap Source Address Registers ------------------------------------ */
+
+#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 ((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
+#define APPNIC_TX_EXTENDED_CONF_LATE_COLLISION_WINDOW_COUNT 0xff
+
+/* Transmit Half Duplex Configuration ------------------------------- */
+
+#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 ((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
+#define APPNIC_TX_CONF_SPEED           0x0800
+#define APPNIC_TX_CONF_XBK_RST_RX_NTX  0x0600
+#define APPNIC_TX_CONF_IFG             0x01f0
+#define APPNIC_TX_CONF_APP_CRC_ENABLE  0x0004
+#define APPNIC_TX_CONF_PAD_ENABLE      0x0002
+#define APPNIC_TX_CONF_ENABLE          0x0001
+
+#define TX_CONF_SET_IFG(tx_configuration, ifg)                 \
+       do {                                                    \
+               (tx_configuration) &= ~APPNIC_TX_CONF_IFG;      \
+               (tx_configuration) |= ((ifg & 0x1f) << 4);      \
+       } while (0)
+
+/* Transmit Time Value Configuration -------------------------------- */
+
+#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 ((unsigned long)pdata->tx_base + 0x300)
+
+/* Transmit Stat Packet OK ------------------------------------------ */
+
+#define APPNIC_TX_STAT_PACKET_OK ((unsigned long)pdata->tx_base + 0x318)
+
+/* Transmit Stat Undersize ------------------------------------------ */
+
+#define APPNIC_TX_STAT_UNDERSIZE ((unsigned long)pdata->tx_base + 0x350)
+
+/* Transmit Status Late Collision ----------------------------------- */
+
+#define APPNIC_TX_STATUS_LATE_COLLISION ((unsigned long)pdata->tx_base + 0x368)
+
+/* Transmit Status Excessive Collision ------------------------------ */
+
+#define APPNIC_TX_STATUS_EXCESSIVE_COLLISION \
+       ((unsigned long)pdata->tx_base + 0x370)
+
+/* Transmit Stat Collision Above Watermark -------------------------- */
+
+#define APPNIC_TX_STAT_COLLISION_ABOVE_WATERMARK \
+       ((unsigned long)pdata->tx_base + 0x380)
+
+/* Transmit Mode ---------------------------------------------------- */
+
+#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 ((unsigned long)pdata->tx_base + 0x808)
+#define APPNIC_TX_SOFT_RESET_MAC_0 0x1
+
+/* Transmit Interrupt Control --------------------------------------- */
+
+#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 ((unsigned long)pdata->tx_base + 0xc20)
+#define APPNIC_TX_INTERRUPT_STATUS_MAC_0 0x1
+
+/* */
+
+#define APPNIC_DMA_PCI_CONTROL ((unsigned long)pdata->dma_base + 0x00)
+
+/* */
+
+#define APPNIC_DMA_CONTROL ((unsigned long)pdata->dma_base + 0x08)
+
+/* DMA Interrupt Status --------------------------------------------- */
+
+#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) \
+       (0 != (dma_interrupt_status & APPNIC_DMA_INTERRUPT_STATUS_RX))
+#define TX_INTERRUPT(dma_interrupt_status) \
+       (0 != (dma_interrupt_status & APPNIC_DMA_INTERRUPT_STATUS_TX))
+
+/* DMA Interrupt Enable --------------------------------------------- */
+
+#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 ((unsigned long)pdata->dma_base + 
0x30)
+
+/* DMA Receive Queue Size ------------------------------------------- */
+
+#define APPNIC_DMA_RX_QUEUE_SIZE ((unsigned long)pdata->dma_base + 0x34)
+
+/* DMA Transmit Queue Base Address ---------------------------------- */
+
+#define APPNIC_DMA_TX_QUEUE_BASE_ADDRESS ((unsigned long)pdata->dma_base + 
0x38)
+
+/* DMA Transmit Queue Size ------------------------------------------ */
+
+#define APPNIC_DMA_TX_QUEUE_SIZE ((unsigned long)pdata->dma_base + 0x3c)
+
+/* DMA Recevie Tail Pointer Address --------------------------------- */
+
+#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 \
+       ((unsigned long)pdata->dma_base + 0x4c)
+
+/* DMA Receive Head Pointer ----------------------------------------- */
+
+#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  \
+       ((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     ((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  \
+       ((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
+
+#ifdef CONFIG_ARM
+
+#define read_mac(address)         readl((void __iomem *)(address))
+#define write_mac(value, address) writel((value), (void __iomem *)(address))
+#else
+#define read_mac(address)         in_le32((u32 *) (address))
+#define write_mac(value, address) out_le32((u32 *) (address), (value))
+#endif /* CONFIG_ARM */
+
+#ifdef __LITTLE_ENDIAN
+static inline void
+readdescriptor(unsigned long address, struct appnic_dma_descriptor *descriptor)
+{
+       memcpy(descriptor, (void *)address,
+              sizeof(struct appnic_dma_descriptor));
+       return;
+}
+
+static inline void
+writedescriptor(unsigned long address,
+               const struct appnic_dma_descriptor *descriptor)
+{
+       memcpy((void *)address, descriptor,
+                  sizeof(struct appnic_dma_descriptor));
+       return;
+}
+
+static inline union appnic_queue_pointer
+_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, (void __iomem *)GPREG_HPROT_FEMAC);
+}
+
+#else
+
+static inline void
+readdescriptor(unsigned long address, struct appnic_dma_descriptor *descriptor)
+{
+       unsigned long *from = (unsigned long *) address;
+       unsigned long *to = (unsigned long *) descriptor;
+
+       *to++ = swab32(*from++);
+       *to++ = swab32(*from++);
+       *to++ = swab32(*from++);
+       *to++ = swab32(*from++);
+       return;
+}
+
+static inline void
+writedescriptor(unsigned long address,
+               const struct appnic_dma_descriptor *descriptor)
+{
+       unsigned long *to = (unsigned long *) address;
+       unsigned long *from = (unsigned long *) descriptor;
+
+       *to++ = swab32(*from++);
+       *to++ = swab32(*from++);
+       *to++ = swab32(*from++);
+       *to++ = swab32(*from++);
+       return;
+}
+
+static inline union appnic_queue_pointer
+_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 __LITTLE_ENDIAN */
+
+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

-- 
_______________________________________________
linux-yocto mailing list
linux-yocto@yoctoproject.org
https://lists.yoctoproject.org/listinfo/linux-yocto

Reply via email to