This adds a driver for the Aurora VLSI NB8800 Ethernet controller.
It is an almost complete rewrite of a driver originally found in
a Sigma Designs 2.6.22 tree.

Signed-off-by: Mans Rullgard <m...@mansr.com>
---
Changes:
- remove check for wake on lan irq as it is never requested
- prettify mac address setting
- use ethtool_op_get_link()
- use hardware statistics counters
- check for dma mapping errors
- drop bogus netdev_mc_count(dev) > 64 check
- move request_irq to ndo_open callback
- drop tx_queue_len override
- remove batched tx descriptor cleanup
- use bool type as appropriate
- set the IC_THRESHOLD register correctly according to documentation
- set the RX_ITR and TX_ITR registers to better values improving performance
- move phy_connect to ndo_open callback
- get phy information from devicetree
- move dma buffer allocation to ndo_open callback
- anything I forgot to mention
---
 drivers/net/ethernet/Kconfig         |    1 +
 drivers/net/ethernet/Makefile        |    1 +
 drivers/net/ethernet/aurora/Kconfig  |   20 +
 drivers/net/ethernet/aurora/Makefile |    1 +
 drivers/net/ethernet/aurora/nb8800.c | 1118 ++++++++++++++++++++++++++++++++++
 drivers/net/ethernet/aurora/nb8800.h |  229 +++++++
 6 files changed, 1370 insertions(+)
 create mode 100644 drivers/net/ethernet/aurora/Kconfig
 create mode 100644 drivers/net/ethernet/aurora/Makefile
 create mode 100644 drivers/net/ethernet/aurora/nb8800.c
 create mode 100644 drivers/net/ethernet/aurora/nb8800.h

diff --git a/drivers/net/ethernet/Kconfig b/drivers/net/ethernet/Kconfig
index 05aa759..8310163 100644
--- a/drivers/net/ethernet/Kconfig
+++ b/drivers/net/ethernet/Kconfig
@@ -29,6 +29,7 @@ source "drivers/net/ethernet/apm/Kconfig"
 source "drivers/net/ethernet/apple/Kconfig"
 source "drivers/net/ethernet/arc/Kconfig"
 source "drivers/net/ethernet/atheros/Kconfig"
+source "drivers/net/ethernet/aurora/Kconfig"
 source "drivers/net/ethernet/cadence/Kconfig"
 source "drivers/net/ethernet/adi/Kconfig"
 source "drivers/net/ethernet/broadcom/Kconfig"
diff --git a/drivers/net/ethernet/Makefile b/drivers/net/ethernet/Makefile
index ddfc808..b435fb0 100644
--- a/drivers/net/ethernet/Makefile
+++ b/drivers/net/ethernet/Makefile
@@ -15,6 +15,7 @@ obj-$(CONFIG_NET_XGENE) += apm/
 obj-$(CONFIG_NET_VENDOR_APPLE) += apple/
 obj-$(CONFIG_NET_VENDOR_ARC) += arc/
 obj-$(CONFIG_NET_VENDOR_ATHEROS) += atheros/
+obj-$(CONFIG_NET_VENDOR_AURORA) += aurora/
 obj-$(CONFIG_NET_CADENCE) += cadence/
 obj-$(CONFIG_NET_BFIN) += adi/
 obj-$(CONFIG_NET_VENDOR_BROADCOM) += broadcom/
diff --git a/drivers/net/ethernet/aurora/Kconfig 
b/drivers/net/ethernet/aurora/Kconfig
new file mode 100644
index 0000000..a3c7106
--- /dev/null
+++ b/drivers/net/ethernet/aurora/Kconfig
@@ -0,0 +1,20 @@
+config NET_VENDOR_AURORA
+       bool "Aurora VLSI devices"
+       help
+         If you have a network (Ethernet) device belonging to this class,
+         say Y.
+
+         Note that the answer to this question doesn't directly affect the
+         kernel: saying N will just cause the configurator to skip all
+         questions about Aurora devices. If you say Y, you will be asked
+         for your specific device in the following questions.
+
+if NET_VENDOR_AURORA
+
+config AURORA_NB8800
+       tristate "Aurora AU-NB8800 support"
+       select PHYLIB
+       help
+        Support for the AU-NB8800 gigabit Ethernet controller.
+
+endif
diff --git a/drivers/net/ethernet/aurora/Makefile 
b/drivers/net/ethernet/aurora/Makefile
new file mode 100644
index 0000000..6cb528a
--- /dev/null
+++ b/drivers/net/ethernet/aurora/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_AURORA_NB8800) += nb8800.o
diff --git a/drivers/net/ethernet/aurora/nb8800.c 
b/drivers/net/ethernet/aurora/nb8800.c
new file mode 100644
index 0000000..b546b67
--- /dev/null
+++ b/drivers/net/ethernet/aurora/nb8800.c
@@ -0,0 +1,1118 @@
+/*
+ * Copyright (C) 2015 Mans Rullgard <m...@mansr.com>
+ *
+ * Mostly rewritten, based on driver from Sigma Designs.  Original
+ * copyright notice below.
+ *
+ *
+ * Driver for tangox SMP864x/SMP865x/SMP867x/SMP868x builtin Ethernet Mac.
+ *
+ * Copyright (C) 2005 Maxime Bizon <mbi...@freebox.fr>
+ *
+ * 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.
+ */
+
+#include <linux/module.h>
+#include <linux/etherdevice.h>
+#include <linux/delay.h>
+#include <linux/ethtool.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/of_device.h>
+#include <linux/of_mdio.h>
+#include <linux/of_net.h>
+#include <linux/dma-mapping.h>
+#include <linux/phy.h>
+#include <linux/cache.h>
+#include <linux/jiffies.h>
+#include <linux/io.h>
+#include <asm/barrier.h>
+
+#include "nb8800.h"
+
+static inline u8 nb8800_readb(struct nb8800_priv *priv, int reg)
+{
+       return readb(priv->base + reg);
+}
+
+static inline u32 nb8800_readl(struct nb8800_priv *priv, int reg)
+{
+       return readl(priv->base + reg);
+}
+
+static inline void nb8800_writeb(struct nb8800_priv *priv, int reg, u8 val)
+{
+       writeb(val, priv->base + reg);
+}
+
+static inline void nb8800_writew(struct nb8800_priv *priv, int reg, u16 val)
+{
+       writew(val, priv->base + reg);
+}
+
+static inline void nb8800_writel(struct nb8800_priv *priv, int reg, u32 val)
+{
+       writel(val, priv->base + reg);
+}
+
+#define nb8800_set_bits(sz, priv, reg, bits) do {                      \
+               u32 __o = nb8800_read##sz(priv, reg);                   \
+               u32 __n = __o | (bits);                                 \
+               if (__n != __o)                                         \
+                       nb8800_write##sz(priv, reg, __n);               \
+       } while (0)
+
+#define nb8800_clear_bits(sz, priv, reg, bits) do {                    \
+               u32 __o = nb8800_read##sz(priv, reg);                   \
+               u32 __n = __o & ~(bits);                                \
+               if (__n != __o)                                         \
+                       nb8800_write##sz(priv, reg, __n);               \
+       } while (0)
+
+#define MDIO_TIMEOUT   1000
+
+static int nb8800_mdio_wait(struct mii_bus *bus)
+{
+       struct nb8800_priv *priv = bus->priv;
+       int tmo = MDIO_TIMEOUT;
+
+       while (--tmo) {
+               if (!(nb8800_readl(priv, NB8800_MDIO_CMD) & MDIO_CMD_GO))
+                       break;
+               udelay(1);
+       }
+
+       return tmo;
+}
+
+static int nb8800_mdio_read(struct mii_bus *bus, int phy_id, int reg)
+{
+       struct nb8800_priv *priv = bus->priv;
+       int val;
+
+       if (!nb8800_mdio_wait(bus))
+               return -ETIMEDOUT;
+
+       val = MIIAR_ADDR(phy_id) | MIIAR_REG(reg);
+
+       nb8800_writel(priv, NB8800_MDIO_CMD, val);
+       udelay(10);
+       nb8800_writel(priv, NB8800_MDIO_CMD, val | MDIO_CMD_GO);
+
+       if (!nb8800_mdio_wait(bus))
+               return -ETIMEDOUT;
+
+       val = nb8800_readl(priv, NB8800_MDIO_STS);
+       if (val & MDIO_STS_ERR)
+               return 0xffff;
+
+       return val & 0xffff;
+}
+
+static int nb8800_mdio_write(struct mii_bus *bus, int phy_id, int reg, u16 val)
+{
+       struct nb8800_priv *priv = bus->priv;
+       int tmp;
+
+       if (!nb8800_mdio_wait(bus))
+               return -ETIMEDOUT;
+
+       tmp = MIIAR_DATA(val) | MIIAR_ADDR(phy_id) | MIIAR_REG(reg) |
+               MDIO_CMD_WR;
+
+       nb8800_writel(priv, NB8800_MDIO_CMD, tmp);
+       udelay(10);
+       nb8800_writel(priv, NB8800_MDIO_CMD, tmp | MDIO_CMD_GO);
+
+       if (!nb8800_mdio_wait(bus))
+               return -ETIMEDOUT;
+
+       return 0;
+}
+
+static void nb8800_mac_tx(struct net_device *dev, bool enable)
+{
+       struct nb8800_priv *priv = netdev_priv(dev);
+
+       while (nb8800_readl(priv, NB8800_TXC_CR) & TCR_EN)
+               cpu_relax();
+
+       if (enable)
+               nb8800_set_bits(b, priv, NB8800_TX_CTL1, TX_EN);
+       else
+               nb8800_clear_bits(b, priv, NB8800_TX_CTL1, TX_EN);
+}
+
+static void nb8800_mac_rx(struct net_device *dev, bool enable)
+{
+       struct nb8800_priv *priv = netdev_priv(dev);
+
+       if (enable)
+               nb8800_set_bits(b, priv, NB8800_RX_CTL, RX_EN);
+       else
+               nb8800_clear_bits(b, priv, NB8800_RX_CTL, RX_EN);
+}
+
+static void nb8800_mac_af(struct net_device *dev, bool enable)
+{
+       struct nb8800_priv *priv = netdev_priv(dev);
+
+       if (enable)
+               nb8800_set_bits(b, priv, NB8800_RX_CTL, RX_AF_EN);
+       else
+               nb8800_clear_bits(b, priv, NB8800_RX_CTL, RX_AF_EN);
+}
+
+static void nb8800_stop_rx(struct net_device *dev)
+{
+       struct nb8800_priv *priv = netdev_priv(dev);
+       int i;
+
+       for (i = 0; i < RX_DESC_COUNT; i++)
+               priv->rx_descs[i].config |= DESC_EOC;
+
+       while (nb8800_readl(priv, NB8800_RXC_CR) & RCR_EN)
+               usleep_range(1000, 10000);
+}
+
+static void nb8800_start_rx(struct net_device *dev)
+{
+       struct nb8800_priv *priv = netdev_priv(dev);
+
+       nb8800_set_bits(l, priv, NB8800_RXC_CR, RCR_EN);
+}
+
+static int nb8800_alloc_rx(struct net_device *dev, int i, bool napi)
+{
+       struct nb8800_priv *priv = netdev_priv(dev);
+       struct nb8800_dma_desc *rx = &priv->rx_descs[i];
+       struct rx_buf *buf = &priv->rx_bufs[i];
+       int size = L1_CACHE_ALIGN(RX_BUF_SIZE);
+       void *data;
+
+       data = napi ? napi_alloc_frag(size) : netdev_alloc_frag(size);
+       if (!data) {
+               buf->page = NULL;
+               rx->config = DESC_EOF;
+               return -ENOMEM;
+       }
+
+       buf->page = virt_to_head_page(data);
+       buf->offset = data - page_address(buf->page);
+
+       rx->config = RX_BUF_SIZE | DESC_BTS(2) | DESC_DS | DESC_EOF;
+       rx->s_addr = dma_map_page(&dev->dev, buf->page, buf->offset,
+                                 RX_BUF_SIZE, DMA_FROM_DEVICE);
+
+       if (dma_mapping_error(&dev->dev, rx->s_addr)) {
+               skb_free_frag(data);
+               buf->page = NULL;
+               rx->config = DESC_EOF;
+               return -ENOMEM;
+       }
+
+       return 0;
+}
+
+static void nb8800_receive(struct net_device *dev, int i, int len)
+{
+       struct nb8800_priv *priv = netdev_priv(dev);
+       struct nb8800_dma_desc *rx = &priv->rx_descs[i];
+       struct page *page = priv->rx_bufs[i].page;
+       int offset = priv->rx_bufs[i].offset;
+       void *data = page_address(page) + offset;
+       dma_addr_t dma = rx->s_addr;
+       struct sk_buff *skb;
+
+       skb = napi_alloc_skb(&priv->napi, RX_COPYBREAK);
+       if (!skb) {
+               netdev_err(dev, "rx skb allocation failed\n");
+               return;
+       }
+
+       if (len <= RX_COPYBREAK) {
+               dma_sync_single_for_cpu(&dev->dev, dma, len, DMA_FROM_DEVICE);
+               memcpy(skb_put(skb, len), data, len);
+               dma_sync_single_for_device(&dev->dev, dma, len,
+                                          DMA_FROM_DEVICE);
+       } else {
+               dma_unmap_page(&dev->dev, dma, RX_BUF_SIZE, DMA_FROM_DEVICE);
+               memcpy(skb_put(skb, 128), data, 128);
+               skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags, page,
+                               offset + 128, len - 128, RX_BUF_SIZE);
+               priv->rx_bufs[i].page = NULL;
+       }
+
+       skb->protocol = eth_type_trans(skb, dev);
+       netif_receive_skb(skb);
+}
+
+static void nb8800_rx_error(struct net_device *dev, u32 report)
+{
+       int len = RX_BYTES_TRANSFERRED(report);
+
+       if (report & RX_FCS_ERR)
+               dev->stats.rx_crc_errors++;
+
+       if ((report & (RX_FRAME_LEN_ERROR | RX_LENGTH_ERR)) ||
+           (len > RX_BUF_SIZE))
+               dev->stats.rx_length_errors++;
+
+       dev->stats.rx_errors++;
+}
+
+static int nb8800_poll(struct napi_struct *napi, int budget)
+{
+       struct net_device *dev = napi->dev;
+       struct nb8800_priv *priv = netdev_priv(dev);
+       struct nb8800_dma_desc *rx;
+       int work = 0;
+       int last = priv->rx_eoc;
+       int next;
+
+       while (work < budget) {
+               struct rx_buf *rx_buf;
+               u32 report;
+               int len;
+
+               next = (last + 1) & (RX_DESC_COUNT - 1);
+
+               rx_buf = &priv->rx_bufs[next];
+               rx = &priv->rx_descs[next];
+               report = rx->report;
+
+               if (!report)
+                       break;
+
+               if (IS_RX_ERROR(report)) {
+                       nb8800_rx_error(dev, report);
+               } else if (likely(rx_buf->page)) {
+                       len = RX_BYTES_TRANSFERRED(report);
+                       nb8800_receive(dev, next, len);
+               }
+
+               rx->report = 0;
+               if (!rx_buf->page)
+                       nb8800_alloc_rx(dev, next, true);
+
+               last = next;
+               work++;
+       }
+
+       if (work) {
+               priv->rx_descs[last].config |= DESC_EOC;
+               wmb();  /* ensure new EOC is written before clearing old */
+               priv->rx_descs[priv->rx_eoc].config &= ~DESC_EOC;
+               priv->rx_eoc = last;
+               nb8800_start_rx(dev);
+       }
+
+       if (work < budget) {
+               nb8800_writel(priv, NB8800_RX_ITR, 1);
+               napi_complete_done(napi, work);
+       }
+
+       return work;
+}
+
+static void nb8800_tx_dma_queue(struct net_device *dev, dma_addr_t data,
+                               int len, int flags)
+{
+       struct nb8800_priv *priv = netdev_priv(dev);
+       int next = priv->tx_next;
+       struct nb8800_dma_desc *tx = &priv->tx_descs[next];
+
+       tx->s_addr = data;
+       tx->config = DESC_BTS(2) | DESC_DS | flags | len;
+       tx->report = 0;
+
+       priv->tx_next = (next + 1) & (TX_DESC_COUNT - 1);
+}
+
+static void nb8800_tx_dma_start(struct net_device *dev, int new)
+{
+       struct nb8800_priv *priv = netdev_priv(dev);
+       struct nb8800_dma_desc *tx;
+       struct tx_buf *tx_buf;
+       u32 txc_cr;
+       int next;
+
+       next = xchg(&priv->tx_pending, -1);
+       if (next < 0)
+               next = new;
+       if (next < 0)
+               goto end;
+
+       txc_cr = nb8800_readl(priv, NB8800_TXC_CR) & 0xffff;
+       if (txc_cr & TCR_EN)
+               goto end;
+
+       tx = &priv->tx_descs[next];
+       tx_buf = &priv->tx_bufs[next];
+
+       next = (next + tx_buf->frags) & (TX_DESC_COUNT - 1);
+
+       nb8800_writel(priv, NB8800_TX_DESC_ADDR, tx_buf->desc_dma);
+       wmb();          /* ensure desc addr is written before starting DMA */
+       nb8800_writel(priv, NB8800_TXC_CR, txc_cr | TCR_EN);
+
+       if (!priv->tx_bufs[next].frags)
+               next = -1;
+
+end:
+       priv->tx_pending = next;
+}
+
+static int nb8800_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+       struct nb8800_priv *priv = netdev_priv(dev);
+       struct tx_skb_data *skb_data;
+       struct tx_buf *tx_buf;
+       dma_addr_t dma_addr;
+       unsigned int dma_len;
+       int cpsz, next;
+       int frags;
+
+       if (atomic_read(&priv->tx_free) <= NB8800_DESC_LOW) {
+               netif_stop_queue(dev);
+               return NETDEV_TX_BUSY;
+       }
+
+       cpsz = (8 - (uintptr_t)skb->data) & 7;
+
+       dma_len = skb->len - cpsz;
+       dma_addr = dma_map_single(&dev->dev, skb->data + cpsz,
+                                 dma_len, DMA_TO_DEVICE);
+
+       if (dma_mapping_error(&dev->dev, dma_addr)) {
+               kfree_skb(skb);
+               return NETDEV_TX_OK;
+       }
+
+       frags = cpsz ? 2 : 1;
+       atomic_sub(frags, &priv->tx_free);
+
+       next = priv->tx_next;
+       tx_buf = &priv->tx_bufs[next];
+
+       if (cpsz) {
+               dma_addr_t dma = tx_buf->desc_dma +
+                       offsetof(struct nb8800_dma_desc, buf);
+               memcpy(priv->tx_descs[next].buf, skb->data, cpsz);
+               nb8800_tx_dma_queue(dev, dma, cpsz, 0);
+       }
+
+       nb8800_tx_dma_queue(dev, dma_addr, dma_len, DESC_EOF | DESC_EOC);
+       netdev_sent_queue(dev, skb->len);
+
+       tx_buf->skb = skb;
+       tx_buf->frags = frags;
+
+       skb_data = (struct tx_skb_data *)skb->cb;
+       skb_data->dma_addr = dma_addr;
+       skb_data->dma_len = dma_len;
+
+       nb8800_tx_dma_start(dev, next);
+
+       if (atomic_read(&priv->tx_free) <= NB8800_DESC_LOW)
+               netif_stop_queue(dev);
+
+       return NETDEV_TX_OK;
+}
+
+static void nb8800_tx_done(struct net_device *dev)
+{
+       struct nb8800_priv *priv = netdev_priv(dev);
+       struct tx_buf *tx_buf = &priv->tx_bufs[priv->tx_done];
+       struct sk_buff *skb = tx_buf->skb;
+       struct tx_skb_data *skb_data = (struct tx_skb_data *)skb->cb;
+
+       priv->tx_done = (priv->tx_done + tx_buf->frags) & (TX_DESC_COUNT - 1);
+
+       netdev_completed_queue(dev, 1, skb->len);
+       dma_unmap_single(&dev->dev, skb_data->dma_addr, skb_data->dma_len,
+                        DMA_TO_DEVICE);
+       dev_consume_skb_irq(tx_buf->skb);
+
+       atomic_add(tx_buf->frags, &priv->tx_free);
+
+       tx_buf->skb = NULL;
+       tx_buf->frags = 0;
+
+       nb8800_tx_dma_start(dev, -1);
+       netif_wake_queue(dev);
+}
+
+static irqreturn_t nb8800_isr(int irq, void *dev_id)
+{
+       struct net_device *dev = dev_id;
+       struct nb8800_priv *priv = netdev_priv(dev);
+       u32 val;
+
+       /* tx interrupt */
+       val = nb8800_readl(priv, NB8800_TXC_SR);
+       if (val) {
+               nb8800_writel(priv, NB8800_TXC_SR, val);
+
+               if (likely(val & TSR_TI))
+                       nb8800_tx_done(dev);
+
+               if (unlikely(val & TSR_DE))
+                       netdev_err(dev, "TX DMA error\n");
+
+               if (unlikely(val & TSR_TO))
+                       netdev_err(dev, "TX Status FIFO overflow\n");
+       }
+
+       /* rx interrupt */
+       val = nb8800_readl(priv, NB8800_RXC_SR);
+       if (val) {
+               nb8800_writel(priv, NB8800_RXC_SR, val);
+
+               if (likely(val & RSR_RI)) {
+                       nb8800_writel(priv, NB8800_RX_ITR, priv->rx_poll_itr);
+                       napi_schedule_irqoff(&priv->napi);
+               }
+
+               if (unlikely(val & RSR_DE))
+                       netdev_err(dev, "RX DMA error\n");
+
+               if (unlikely(val & RSR_RO)) {
+                       int i;
+
+                       netdev_err(dev, "RX Status FIFO overflow\n");
+
+                       for (i = 0; i < 4; i++)
+                               nb8800_readl(priv, NB8800_RX_FIFO_SR);
+               }
+       }
+
+       return IRQ_HANDLED;
+}
+
+static void nb8800_mac_config(struct net_device *dev)
+{
+       struct nb8800_priv *priv = netdev_priv(dev);
+       unsigned phy_clk;
+       unsigned ict;
+
+       if (priv->duplex)
+               nb8800_clear_bits(b, priv, NB8800_MAC_MODE, HALF_DUPLEX);
+       else
+               nb8800_set_bits(b, priv, NB8800_MAC_MODE, HALF_DUPLEX);
+
+       if (priv->speed == SPEED_1000) {
+               nb8800_set_bits(b, priv, NB8800_MAC_MODE,
+                               RGMII_MODE | GMAC_MODE);
+               nb8800_writeb(priv, NB8800_SLOT_TIME, 255);
+               phy_clk = 125000000;
+       } else {
+               nb8800_clear_bits(b, priv, NB8800_MAC_MODE,
+                                 RGMII_MODE | GMAC_MODE);
+               nb8800_writeb(priv, NB8800_SLOT_TIME, 127);
+               phy_clk = 25000000;
+       }
+
+       ict = DIV_ROUND_UP(phy_clk, clk_get_rate(priv->clk));
+       nb8800_writeb(priv, NB8800_IC_THRESHOLD, ict);
+}
+
+static void nb8800_link_reconfigure(struct net_device *dev)
+{
+       struct nb8800_priv *priv = netdev_priv(dev);
+       struct phy_device *phydev = priv->phydev;
+
+       if (phydev->speed == priv->speed && phydev->duplex == priv->duplex &&
+           phydev->link == priv->link)
+               return;
+
+       if (phydev->link != priv->link || phydev->link)
+               phy_print_status(priv->phydev);
+
+       priv->speed = phydev->speed;
+       priv->duplex = phydev->duplex;
+       priv->link = phydev->link;
+
+       if (priv->link)
+               nb8800_mac_config(dev);
+}
+
+static void nb8800_update_mac_addr(struct net_device *dev)
+{
+       struct nb8800_priv *priv = netdev_priv(dev);
+       int i;
+
+       for (i = 0; i < 6; i++)
+               nb8800_writeb(priv, NB8800_SRC_ADDR(i), dev->dev_addr[i]);
+
+       for (i = 0; i < 6; i++)
+               nb8800_writeb(priv, NB8800_UC_ADDR(i), dev->dev_addr[i]);
+}
+
+static int nb8800_set_mac_address(struct net_device *dev, void *addr)
+{
+       struct sockaddr *sock = addr;
+
+       if (netif_running(dev))
+               return -EBUSY;
+
+       ether_addr_copy(dev->dev_addr, sock->sa_data);
+       nb8800_update_mac_addr(dev);
+
+       return 0;
+}
+
+static void nb8800_mc_init(struct net_device *dev, int val)
+{
+       struct nb8800_priv *priv = netdev_priv(dev);
+
+       nb8800_writeb(priv, NB8800_MC_INIT, val);
+       while (nb8800_readb(priv, NB8800_MC_INIT))
+               cpu_relax();
+}
+
+static void nb8800_set_rx_mode(struct net_device *dev)
+{
+       struct nb8800_priv *priv = netdev_priv(dev);
+       struct netdev_hw_addr *ha;
+       bool af_en;
+       int i;
+
+       if (dev->flags & (IFF_PROMISC | IFF_ALLMULTI))
+               af_en = false;
+       else
+               af_en = true;
+
+       nb8800_mac_af(dev, af_en);
+
+       if (!af_en)
+               return;
+
+       nb8800_mc_init(dev, 0);
+
+       netdev_for_each_mc_addr(ha, dev) {
+               char *addr = ha->addr;
+
+               for (i = 0; i < 6; i++)
+                       nb8800_writeb(priv, NB8800_MC_ADDR(i), addr[i]);
+
+               nb8800_mc_init(dev, 0xff);
+       }
+}
+
+#define RX_DESC_SIZE (RX_DESC_COUNT * sizeof(struct nb8800_dma_desc))
+#define TX_DESC_SIZE (TX_DESC_COUNT * sizeof(struct nb8800_dma_desc))
+
+static void nb8800_dma_free(struct net_device *dev)
+{
+       struct nb8800_priv *priv = netdev_priv(dev);
+       int i;
+
+       if (priv->rx_bufs) {
+               for (i = 0; i < RX_DESC_COUNT; i++)
+                       if (priv->rx_bufs[i].page)
+                               put_page(priv->rx_bufs[i].page);
+
+               kfree(priv->rx_bufs);
+               priv->rx_bufs = NULL;
+       }
+
+       if (priv->tx_bufs) {
+               for (i = 0; i < TX_DESC_COUNT; i++)
+                       kfree_skb(priv->tx_bufs[i].skb);
+
+               kfree(priv->tx_bufs);
+               priv->tx_bufs = NULL;
+       }
+
+       if (priv->rx_descs) {
+               dma_free_coherent(dev->dev.parent, RX_DESC_SIZE, priv->rx_descs,
+                                 priv->rx_desc_dma);
+               priv->rx_descs = NULL;
+       }
+
+       if (priv->tx_descs) {
+               dma_free_coherent(dev->dev.parent, TX_DESC_SIZE, priv->tx_descs,
+                                 priv->tx_desc_dma);
+               priv->tx_descs = NULL;
+       }
+}
+
+static int nb8800_dma_init(struct net_device *dev)
+{
+       struct nb8800_priv *priv = netdev_priv(dev);
+       int n_rx = RX_DESC_COUNT;
+       int n_tx = TX_DESC_COUNT;
+       int i;
+
+       priv->rx_descs = dma_alloc_coherent(dev->dev.parent, RX_DESC_SIZE,
+                                           &priv->rx_desc_dma, GFP_KERNEL);
+       if (!priv->rx_descs)
+               goto err_out;
+
+       priv->rx_bufs = kcalloc(n_rx, sizeof(*priv->rx_bufs), GFP_KERNEL);
+       if (!priv->rx_bufs)
+               goto err_out;
+
+       for (i = 0; i < n_rx; i++) {
+               struct nb8800_dma_desc *rx = &priv->rx_descs[i];
+               dma_addr_t rx_dma;
+               int err;
+
+               rx_dma = priv->rx_desc_dma + i * sizeof(struct nb8800_dma_desc);
+               rx->n_addr = rx_dma + sizeof(struct nb8800_dma_desc);
+               rx->r_addr = rx_dma + offsetof(struct nb8800_dma_desc, report);
+               rx->report = 0;
+
+               err = nb8800_alloc_rx(dev, i, false);
+               if (err)
+                       goto err_out;
+       }
+
+       priv->rx_descs[n_rx - 1].n_addr = priv->rx_desc_dma;
+       priv->rx_descs[n_rx - 1].config |= DESC_EOC;
+
+       priv->rx_eoc = RX_DESC_COUNT - 1;
+
+       priv->tx_descs = dma_alloc_coherent(dev->dev.parent, TX_DESC_SIZE,
+                                           &priv->tx_desc_dma, GFP_KERNEL);
+       if (!priv->tx_descs)
+               goto err_out;
+
+       priv->tx_bufs = kcalloc(n_tx, sizeof(*priv->tx_bufs), GFP_KERNEL);
+       if (!priv->tx_bufs)
+               goto err_out;
+
+       for (i = 0; i < n_tx; i++) {
+               struct nb8800_dma_desc *tx = &priv->tx_descs[i];
+               dma_addr_t tx_dma;
+
+               tx_dma = priv->tx_desc_dma + i * sizeof(struct nb8800_dma_desc);
+               tx->n_addr = tx_dma + sizeof(struct nb8800_dma_desc);
+               tx->r_addr = tx_dma + offsetof(struct nb8800_dma_desc, report);
+
+               priv->tx_bufs[i].desc_dma = tx_dma;
+       }
+
+       priv->tx_descs[n_tx - 1].n_addr = priv->tx_desc_dma;
+
+       priv->tx_pending = -1;
+       priv->tx_next = 0;
+       priv->tx_done = 0;
+       atomic_set(&priv->tx_free, TX_DESC_COUNT);
+
+       nb8800_writel(priv, NB8800_TX_DESC_ADDR, priv->tx_desc_dma);
+       nb8800_writel(priv, NB8800_RX_DESC_ADDR, priv->rx_desc_dma);
+
+       wmb();          /* ensure all setup is written before starting */
+
+       return 0;
+
+err_out:
+       nb8800_dma_free(dev);
+
+       return -ENOMEM;
+}
+
+static int nb8800_open(struct net_device *dev)
+{
+       struct nb8800_priv *priv = netdev_priv(dev);
+       int err;
+
+       nb8800_writel(priv, NB8800_RXC_SR, 0xf);
+       nb8800_writel(priv, NB8800_TXC_SR, 0xf);
+
+       err = nb8800_dma_init(dev);
+       if (err)
+               return err;
+
+       err = request_irq(dev->irq, nb8800_isr, 0, dev_name(&dev->dev), dev);
+       if (err)
+               goto err_free_dma;
+
+       nb8800_mac_rx(dev, true);
+       nb8800_mac_tx(dev, true);
+
+       priv->phydev = of_phy_connect(dev, priv->phy_node,
+                                     nb8800_link_reconfigure, 0,
+                                     priv->phy_mode);
+       if (!priv->phydev)
+               goto err_free_irq;
+
+       napi_enable(&priv->napi);
+       netif_start_queue(dev);
+
+       nb8800_start_rx(dev);
+       phy_start(priv->phydev);
+
+       return 0;
+
+err_free_irq:
+       free_irq(dev->irq, dev);
+err_free_dma:
+       nb8800_dma_free(dev);
+
+       return err;
+}
+
+static int nb8800_stop(struct net_device *dev)
+{
+       struct nb8800_priv *priv = netdev_priv(dev);
+
+       netif_stop_queue(dev);
+       napi_disable(&priv->napi);
+
+       nb8800_stop_rx(dev);
+
+       nb8800_mac_rx(dev, false);
+       nb8800_mac_tx(dev, false);
+
+       free_irq(dev->irq, dev);
+
+       phy_stop(priv->phydev);
+       phy_disconnect(priv->phydev);
+
+       nb8800_dma_free(dev);
+
+       return 0;
+}
+
+static u32 nb8800_read_stat(struct net_device *dev, int index)
+{
+       struct nb8800_priv *priv = netdev_priv(dev);
+
+       nb8800_writeb(priv, NB8800_STAT_INDEX, index);
+
+       return nb8800_readl(priv, NB8800_STAT_DATA);
+}
+
+static struct net_device_stats *nb8800_get_stats(struct net_device *dev)
+{
+       dev->stats.rx_bytes     = nb8800_read_stat(dev, 0x00);
+       dev->stats.rx_packets   = nb8800_read_stat(dev, 0x01);
+       dev->stats.multicast    = nb8800_read_stat(dev, 0x0d);
+       dev->stats.tx_bytes     = nb8800_read_stat(dev, 0x80);
+       dev->stats.tx_packets   = nb8800_read_stat(dev, 0x81);
+
+       return &dev->stats;
+}
+
+static int nb8800_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+{
+       struct nb8800_priv *priv = netdev_priv(dev);
+
+       return phy_mii_ioctl(priv->phydev, rq, cmd);
+}
+
+static const struct net_device_ops nb8800_netdev_ops = {
+       .ndo_open               = nb8800_open,
+       .ndo_stop               = nb8800_stop,
+       .ndo_start_xmit         = nb8800_xmit,
+       .ndo_set_mac_address    = nb8800_set_mac_address,
+       .ndo_set_rx_mode        = nb8800_set_rx_mode,
+       .ndo_do_ioctl           = nb8800_ioctl,
+       .ndo_get_stats          = nb8800_get_stats,
+       .ndo_change_mtu         = eth_change_mtu,
+       .ndo_validate_addr      = eth_validate_addr,
+};
+
+static int nb8800_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+       struct nb8800_priv *priv = netdev_priv(dev);
+
+       return phy_ethtool_gset(priv->phydev, cmd);
+}
+
+static int nb8800_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+       struct nb8800_priv *priv = netdev_priv(dev);
+
+       return phy_ethtool_sset(priv->phydev, cmd);
+}
+
+static int nb8800_nway_reset(struct net_device *dev)
+{
+       struct nb8800_priv *priv = netdev_priv(dev);
+
+       return genphy_restart_aneg(priv->phydev);
+}
+
+static struct ethtool_ops nb8800_ethtool_ops = {
+       .get_settings           = nb8800_get_settings,
+       .set_settings           = nb8800_set_settings,
+       .nway_reset             = nb8800_nway_reset,
+       .get_link               = ethtool_op_get_link,
+};
+
+static void nb8800_tangox_init(struct net_device *dev)
+{
+       struct nb8800_priv *priv = netdev_priv(dev);
+       u32 val;
+
+       val = nb8800_readb(priv, NB8800_TANGOX_PAD_MODE) & 0x78;
+       if (priv->phy_mode == PHY_INTERFACE_MODE_RGMII)
+               val |= 1;
+       nb8800_writeb(priv, NB8800_TANGOX_PAD_MODE, val);
+}
+
+static void nb8800_tangox_reset(struct net_device *dev)
+{
+       struct nb8800_priv *priv = netdev_priv(dev);
+       int clk_div;
+
+       nb8800_writeb(priv, NB8800_TANGOX_RESET, 0);
+       usleep_range(1000, 10000);
+       nb8800_writeb(priv, NB8800_TANGOX_RESET, 1);
+
+       wmb();          /* ensure reset is cleared before proceeding */
+
+       clk_div = DIV_ROUND_UP(clk_get_rate(priv->clk), 2 * MAX_MDC_CLOCK);
+       nb8800_writew(priv, NB8800_TANGOX_MDIO_CLKDIV, clk_div);
+}
+
+static const struct nb8800_ops nb8800_tangox_ops = {
+       .init   = nb8800_tangox_init,
+       .reset  = nb8800_tangox_reset,
+};
+
+static int nb8800_hw_init(struct net_device *dev)
+{
+       struct nb8800_priv *priv = netdev_priv(dev);
+       unsigned int val = 0;
+
+       nb8800_writeb(priv, NB8800_RANDOM_SEED, 0x08);
+
+       /* TX single deferral params */
+       nb8800_writeb(priv, NB8800_TX_SDP, 0xc);
+
+       /* Threshold for partial full */
+       nb8800_writeb(priv, NB8800_PF_THRESHOLD, 0xff);
+
+       /* Pause Quanta */
+       nb8800_writeb(priv, NB8800_PQ1, 0xff);
+       nb8800_writeb(priv, NB8800_PQ2, 0xff);
+
+       /* configure TX DMA Channels */
+       val = nb8800_readl(priv, NB8800_TXC_CR);
+       val &= TCR_LE;
+       val |= TCR_DM | TCR_RS | TCR_TFI(1) | TCR_BTS(2);
+       nb8800_writel(priv, NB8800_TXC_CR, val);
+
+       /* TX Interrupt Time Register */
+       nb8800_writel(priv, NB8800_TX_ITR, 1);
+
+       /* configure RX DMA Channels */
+       val = nb8800_readl(priv, NB8800_RXC_CR);
+       val &= RCR_LE;
+       val |= RCR_DM | RCR_RS | RCR_RFI(7) | RCR_BTS(2) | RCR_FL;
+       nb8800_writel(priv, NB8800_RXC_CR, val);
+
+       /* RX Interrupt Time Register */
+       nb8800_writel(priv, NB8800_RX_ITR, 1);
+
+       val = TX_RETRY_EN | TX_PAD_EN | TX_APPEND_FCS;
+       nb8800_writeb(priv, NB8800_TX_CTL1, val);
+
+       /* collision retry count */
+       nb8800_writeb(priv, NB8800_TX_CTL2, 5);
+
+       val = RX_PAD_STRIP | RX_PAUSE_EN | RX_AF_EN | RX_RUNT;
+       nb8800_writeb(priv, NB8800_RX_CTL, val);
+
+       nb8800_mc_init(dev, 0);
+
+       nb8800_writeb(priv, NB8800_TX_BUFSIZE, 0xff);
+
+       return 0;
+}
+
+static const struct of_device_id nb8800_dt_ids[] = {
+       {
+               .compatible = "aurora,nb8800",
+       },
+       {
+               .compatible = "sigma,smp8642-ethernet",
+               .data = &nb8800_tangox_ops,
+       },
+       { }
+};
+
+static int nb8800_probe(struct platform_device *pdev)
+{
+       const struct of_device_id *match;
+       const struct nb8800_ops *ops = NULL;
+       struct nb8800_priv *priv;
+       struct resource *res;
+       struct net_device *dev;
+       struct mii_bus *bus;
+       const unsigned char *mac;
+       void __iomem *base;
+       int irq;
+       int ret;
+
+       match = of_match_device(nb8800_dt_ids, &pdev->dev);
+       if (match)
+               ops = match->data;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res) {
+               dev_err(&pdev->dev, "No MMIO base\n");
+               return -EINVAL;
+       }
+
+       irq = platform_get_irq(pdev, 0);
+       if (irq <= 0) {
+               dev_err(&pdev->dev, "No IRQ\n");
+               return -EINVAL;
+       }
+
+       base = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(base))
+               return PTR_ERR(base);
+
+       dev_info(&pdev->dev, "AU-NB8800 Ethernet at %pa\n", &res->start);
+
+       dev = alloc_etherdev(sizeof(*priv));
+       if (!dev)
+               return -ENOMEM;
+
+       platform_set_drvdata(pdev, dev);
+       SET_NETDEV_DEV(dev, &pdev->dev);
+
+       priv = netdev_priv(dev);
+       priv->base = base;
+
+       priv->phy_mode = of_get_phy_mode(pdev->dev.of_node);
+       if (priv->phy_mode < 0)
+               priv->phy_mode = PHY_INTERFACE_MODE_RGMII;
+
+       priv->clk = devm_clk_get(&pdev->dev, NULL);
+       if (IS_ERR(priv->clk)) {
+               dev_err(&pdev->dev, "failed to get clock\n");
+               ret = PTR_ERR(priv->clk);
+               goto err_free_dev;
+       }
+
+       ret = clk_prepare_enable(priv->clk);
+       if (ret)
+               goto err_free_dev;
+
+       priv->rx_poll_itr = clk_get_rate(priv->clk) / 1000;
+
+       if (ops && ops->reset)
+               ops->reset(dev);
+
+       bus = devm_mdiobus_alloc(&pdev->dev);
+       if (!bus) {
+               ret = -ENOMEM;
+               goto err_disable_clk;
+       }
+
+       bus->name = "nb8800-mii";
+       bus->read = nb8800_mdio_read;
+       bus->write = nb8800_mdio_write;
+       bus->parent = &pdev->dev;
+       snprintf(bus->id, MII_BUS_ID_SIZE, "%.*s-mii", MII_BUS_ID_SIZE - 5,
+                pdev->name);
+       bus->priv = priv;
+
+       ret = of_mdiobus_register(bus, pdev->dev.of_node);
+       if (ret) {
+               dev_err(&pdev->dev, "failed to register MII bus\n");
+               goto err_disable_clk;
+       }
+
+       priv->phy_node = of_parse_phandle(pdev->dev.of_node, "phy-handle", 0);
+       if (!priv->phy_node) {
+               dev_err(&pdev->dev, "no PHY specified\n");
+               ret = -ENODEV;
+               goto err_free_bus;
+       }
+
+       priv->mii_bus = bus;
+
+       if (ops && ops->init)
+               ops->init(dev);
+
+       ret = nb8800_hw_init(dev);
+       if (ret)
+               goto err_free_bus;
+
+       dev->netdev_ops = &nb8800_netdev_ops;
+       dev->ethtool_ops = &nb8800_ethtool_ops;
+       dev->flags |= IFF_MULTICAST;
+       dev->irq = irq;
+
+       mac = of_get_mac_address(pdev->dev.of_node);
+       if (mac)
+               ether_addr_copy(dev->dev_addr, mac);
+
+       if (!is_valid_ether_addr(dev->dev_addr))
+               eth_hw_addr_random(dev);
+
+       nb8800_update_mac_addr(dev);
+
+       netif_carrier_off(dev);
+
+       ret = register_netdev(dev);
+       if (ret) {
+               netdev_err(dev, "failed to register netdev\n");
+               goto err_free_dma;
+       }
+
+       netif_napi_add(dev, &priv->napi, nb8800_poll, NAPI_POLL_WEIGHT);
+
+       netdev_info(dev, "MAC address %pM\n", dev->dev_addr);
+
+       return 0;
+
+err_free_dma:
+       nb8800_dma_free(dev);
+err_free_bus:
+       mdiobus_unregister(bus);
+err_disable_clk:
+       clk_disable_unprepare(priv->clk);
+err_free_dev:
+       free_netdev(dev);
+
+       return ret;
+}
+
+static int nb8800_remove(struct platform_device *pdev)
+{
+       struct net_device *ndev = platform_get_drvdata(pdev);
+       struct nb8800_priv *priv = netdev_priv(ndev);
+
+       unregister_netdev(ndev);
+
+       mdiobus_unregister(priv->mii_bus);
+
+       clk_disable_unprepare(priv->clk);
+
+       nb8800_dma_free(ndev);
+       free_netdev(ndev);
+
+       return 0;
+}
+
+static struct platform_driver nb8800_driver = {
+       .driver = {
+               .name           = "nb8800",
+               .of_match_table = nb8800_dt_ids,
+       },
+       .probe  = nb8800_probe,
+       .remove = nb8800_remove,
+};
+
+module_platform_driver(nb8800_driver);
+
+MODULE_DESCRIPTION("Aurora AU-NB8800 Ethernet driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/ethernet/aurora/nb8800.h 
b/drivers/net/ethernet/aurora/nb8800.h
new file mode 100644
index 0000000..5cf8222
--- /dev/null
+++ b/drivers/net/ethernet/aurora/nb8800.h
@@ -0,0 +1,229 @@
+#ifndef _NB8800_H_
+#define _NB8800_H_
+
+#include <linux/types.h>
+#include <linux/skbuff.h>
+#include <linux/phy.h>
+#include <linux/clk.h>
+#include <linux/timer.h>
+#include <linux/bitops.h>
+
+#define RX_DESC_COUNT                  256
+#define TX_DESC_COUNT                  256
+
+#define NB8800_DESC_LOW                        4
+
+#define RX_BUF_SIZE                    1552
+#define TX_BUF_SIZE                    1552
+
+#define RX_COPYBREAK                   256
+
+#define MAX_MDC_CLOCK                  2500000
+
+/* register offsets */
+#define NB8800_TX_CTL1                 0x00
+#define TX_TPD                         BIT(5)
+#define TX_APPEND_FCS                  BIT(4)
+#define TX_PAD_EN                      BIT(3)
+#define TX_RETRY_EN                    BIT(2)
+#define TX_EN                          BIT(0)
+
+#define NB8800_TX_CTL2                 0x01
+
+#define NB8800_RX_CTL                  0x04
+#define RX_BC_DISABLE                  BIT(7)
+#define RX_RUNT                                BIT(6)
+#define RX_AF_EN                       BIT(5)
+#define RX_PAUSE_EN                    BIT(3)
+#define RX_SEND_CRC                    BIT(2)
+#define RX_PAD_STRIP                   BIT(1)
+#define RX_EN                          BIT(0)
+
+#define NB8800_RANDOM_SEED             0x8
+#define NB8800_TX_SDP                  0x14
+#define NB8800_TX_TPDP1                        0x18
+#define NB8800_TX_TPDP2                        0x19
+#define NB8800_SLOT_TIME               0x1c
+
+#define NB8800_MDIO_CMD                        0x20
+#define MIIAR_ADDR(x)                  ((x) << 21)
+#define MIIAR_REG(x)                   ((x) << 16)
+#define MIIAR_DATA(x)                  ((x) <<  0)
+#define MDIO_CMD_GO                    BIT(31)
+#define MDIO_CMD_WR                    BIT(26)
+
+#define NB8800_MDIO_STS                        0x24
+#define MDIO_STS_ERR                   BIT(31)
+
+#define NB8800_MC_ADDR(i)              (0x28 + (i))
+#define NB8800_MC_INIT                 0x2e
+#define NB8800_UC_ADDR(i)              (0x3c + (i))
+
+#define NB8800_MAC_MODE                        0x44
+#define RGMII_MODE                     BIT(7)
+#define HALF_DUPLEX                    BIT(4)
+#define BURST_EN                       BIT(3)
+#define LOOPBACK_EN                    BIT(2)
+#define GMAC_MODE                      BIT(0)
+
+#define NB8800_IC_THRESHOLD            0x50
+#define NB8800_PE_THRESHOLD            0x51
+#define NB8800_PF_THRESHOLD            0x52
+#define NB8800_TX_BUFSIZE              0x54
+#define NB8800_FIFO_CTL                        0x56
+#define NB8800_PQ1                     0x60
+#define NB8800_PQ2                     0x61
+#define NB8800_SRC_ADDR(i)             (0x6a + (i))
+#define NB8800_STAT_DATA               0x78
+#define NB8800_STAT_INDEX              0x7c
+#define NB8800_STAT_CLEAR              0x7d
+
+#define NB8800_SLEEP_MODE              0x7e
+#define SLEEP_MODE                     BIT(0)
+
+#define NB8800_WAKEUP                  0x7f
+#define WAKEUP                         BIT(0)
+
+#define NB8800_TXC_CR                  0x100
+#define TCR_LK                         BIT(12)
+#define TCR_DS                         BIT(11)
+#define TCR_BTS(x)                     (((x) & 0x7) << 8)
+#define TCR_DIE                                BIT(7)
+#define TCR_TFI(x)                     (((x) & 0x7) << 4)
+#define TCR_LE                         BIT(3)
+#define TCR_RS                         BIT(2)
+#define TCR_DM                         BIT(1)
+#define TCR_EN                         BIT(0)
+
+#define NB8800_TXC_SR                  0x104
+#define TSR_DE                         BIT(3)
+#define TSR_DI                         BIT(2)
+#define TSR_TO                         BIT(1)
+#define TSR_TI                         BIT(0)
+
+#define NB8800_TX_SAR                  0x108
+#define NB8800_TX_DESC_ADDR            0x10c
+
+#define NB8800_TX_REPORT_ADDR          0x110
+#define TX_BYTES_TRASFERRED(x)         (((x) >> 16) & 0xffff)
+#define TX_FIRST_DEFERRAL              BIT(7)
+#define TX_EARLY_COLLISIONS(x)         (((x) >> 3) & 0xf)
+#define TX_LATE_COLLISION              BIT(2)
+#define TX_PACKET_DROPPED              BIT(1)
+#define TX_FIFO_UNDERRUN               BIT(0)
+#define IS_TX_ERROR(r)                 ((r) & 0x87)
+
+#define NB8800_TX_FIFO_SR              0x114
+#define NB8800_TX_ITR                  0x118
+
+#define NB8800_RXC_CR                  0x200
+#define RCR_FL                         BIT(13)
+#define RCR_LK                         BIT(12)
+#define RCR_DS                         BIT(11)
+#define RCR_BTS(x)                     (((x) & 7) << 8)
+#define RCR_DIE                                BIT(7)
+#define RCR_RFI(x)                     (((x) & 7) << 4)
+#define RCR_LE                         BIT(3)
+#define RCR_RS                         BIT(2)
+#define RCR_DM                         BIT(1)
+#define RCR_EN                         BIT(0)
+
+#define NB8800_RXC_SR                  0x204
+#define RSR_DE                         BIT(3)
+#define RSR_DI                         BIT(2)
+#define RSR_RO                         BIT(1)
+#define RSR_RI                         BIT(0)
+
+#define NB8800_RX_SAR                  0x208
+#define NB8800_RX_DESC_ADDR            0x20c
+
+#define NB8800_RX_REPORT_ADDR          0x210
+#define RX_BYTES_TRANSFERRED(x)                (((x) >> 16) & 0xFFFF)
+#define RX_MULTICAST_PKT               BIT(9)
+#define RX_BROADCAST_PKT               BIT(8)
+#define RX_LENGTH_ERR                  BIT(7)
+#define RX_FCS_ERR                     BIT(6)
+#define RX_RUNT_PKT                    BIT(5)
+#define RX_FIFO_OVERRUN                        BIT(4)
+#define RX_LATE_COLLISION              BIT(3)
+#define RX_FRAME_LEN_ERROR             BIT(2)
+#define RX_ERROR_MASK                  0xfc
+#define IS_RX_ERROR(r)                 ((r) & RX_ERROR_MASK)
+
+#define NB8800_RX_FIFO_SR              0x214
+#define NB8800_RX_ITR                  0x218
+
+/* Sigma Designs SMP86xx additional registers */
+#define NB8800_TANGOX_PAD_MODE         0x400
+#define NB8800_TANGOX_MDIO_CLKDIV      0x420
+#define NB8800_TANGOX_RESET            0x424
+
+struct nb8800_dma_desc {
+       u32 s_addr;
+       u32 n_addr;
+       u32 r_addr;
+       u32 config;
+       u8  buf[12];
+       u32 report;
+};
+
+#define DESC_ID                                BIT(23)
+#define DESC_EOC                       BIT(22)
+#define DESC_EOF                       BIT(21)
+#define DESC_LK                                BIT(20)
+#define DESC_DS                                BIT(19)
+#define DESC_BTS(x)                    (((x) & 0x7) << 16)
+
+struct rx_buf {
+       struct page *page;
+       int offset;
+};
+
+struct tx_buf {
+       struct sk_buff *skb;
+       dma_addr_t desc_dma;
+       int frags;
+};
+
+struct tx_skb_data {
+       dma_addr_t dma_addr;
+       unsigned int dma_len;
+};
+
+struct nb8800_priv {
+       struct napi_struct              napi;
+
+       void __iomem                    *base;
+
+       struct nb8800_dma_desc          *rx_descs;
+       struct rx_buf                   *rx_bufs;
+       u16                             rx_eoc;
+       u32                             rx_poll_itr;
+
+       struct nb8800_dma_desc          *tx_descs;
+       struct tx_buf                   *tx_bufs;
+       atomic_t                        tx_free;
+       u32                             tx_pending;
+       u16                             tx_next;
+       u16                             tx_done;
+
+       struct mii_bus                  *mii_bus;
+       struct device_node              *phy_node;
+       struct phy_device               *phydev;
+       int                             phy_mode;
+       int                             speed;
+       int                             duplex;
+       int                             link;
+
+       dma_addr_t                      rx_desc_dma;
+       dma_addr_t                      tx_desc_dma;
+
+       struct clk                      *clk;
+};
+
+struct nb8800_ops {
+       void (*init)(struct net_device *dev);
+       void (*reset)(struct net_device *dev);
+};
+
+#endif /* _NB8800_H_ */
-- 
2.6.2

--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to