diff --git a/Documentation/devicetree/bindings/net/moxa,moxart-mac.txt b/Documentation/devicetree/bindings/net/moxa,moxart-mac.txt
new file mode 100644
index 0000000..1fc44ff
--- /dev/null
+++ b/Documentation/devicetree/bindings/net/moxa,moxart-mac.txt
@@ -0,0 +1,25 @@
+MOXA ART Ethernet Controller
+
+Required properties:
+
+- compatible : Must be "moxa,moxart-mac"
+- reg : Should contain registers location and length
+ index 0 : main register
+ index 1 : mac address (stored on flash)
+- interrupts : Should contain the mac interrupt number
+
+Example:
+
+ mac0: mac@90900000 {
+ compatible = "moxa,moxart-mac";
+ reg = <0x90900000 0x100>,
+ <0x80000050 0x6>;
+ interrupts = <25 0>;
+ };
+
+ mac1: mac@92000000 {
+ compatible = "moxa,moxart-mac";
+ reg = <0x92000000 0x100>,
+ <0x80000056 0x6>;
+ interrupts = <27 0>;
+ };diff --git a/drivers/net/ethernet/Kconfig b/drivers/net/ethernet/Kconfig
index 2037080..506b024 100644
--- a/drivers/net/ethernet/Kconfig
+++ b/drivers/net/ethernet/Kconfig
@@ -90,6 +90,7 @@ source "drivers/net/ethernet/marvell/Kconfig"
source "drivers/net/ethernet/mellanox/Kconfig"
source "drivers/net/ethernet/micrel/Kconfig"
source "drivers/net/ethernet/microchip/Kconfig"
+source "drivers/net/ethernet/moxa/Kconfig"
source "drivers/net/ethernet/myricom/Kconfig"
config FEALNX
diff --git a/drivers/net/ethernet/Makefile b/drivers/net/ethernet/Makefile
index 390bd0b..c0b8789 100644
--- a/drivers/net/ethernet/Makefile
+++ b/drivers/net/ethernet/Makefile
@@ -42,6 +42,7 @@ obj-$(CONFIG_NET_VENDOR_MARVELL) += marvell/
obj-$(CONFIG_NET_VENDOR_MELLANOX) += mellanox/
obj-$(CONFIG_NET_VENDOR_MICREL) += micrel/
obj-$(CONFIG_NET_VENDOR_MICROCHIP) += microchip/
+obj-$(CONFIG_NET_VENDOR_MOXART) += moxa/
obj-$(CONFIG_NET_VENDOR_MYRI) += myricom/
obj-$(CONFIG_FEALNX) += fealnx.o
obj-$(CONFIG_NET_VENDOR_NATSEMI) += natsemi/
diff --git a/drivers/net/ethernet/moxa/Kconfig b/drivers/net/ethernet/moxa/Kconfig
new file mode 100644
index 0000000..1731e05
--- /dev/null
+++ b/drivers/net/ethernet/moxa/Kconfig
@@ -0,0 +1,30 @@
+#
+# MOXART device configuration
+#
+
+config NET_VENDOR_MOXART
+ bool "MOXA ART devices"
+ default y
+ depends on (ARM && ARCH_MOXART)
+ ---help---
+ If you have a network (Ethernet) card belonging to this class, say Y
+ and read the Ethernet-HOWTO, available from
+ <http://www.tldp.org/docs.html#howto>.
+
+ Note that the answer to this question doesn't directly affect the
+ kernel: saying N will just cause the configurator to skip all
+ the questions about MOXA ART devices. If you say Y, you will be asked
+ for your specific card in the following questions.
+
+if NET_VENDOR_MOXART
+
+config ARM_MOXART_ETHER
+ tristate "MOXART Ethernet support"
+ depends on ARM && ARCH_MOXART
+ select NET_CORE
+ ---help---
+ If you wish to compile a kernel for a hardware with MOXA ART SoC and
+ want to use the internal ethernet then you should answer Y to this.
+
+
+endif # NET_VENDOR_MOXART
diff --git a/drivers/net/ethernet/moxa/Makefile b/drivers/net/ethernet/moxa/Makefile
new file mode 100644
index 0000000..aa3c73e9
--- /dev/null
+++ b/drivers/net/ethernet/moxa/Makefile
@@ -0,0 +1,5 @@
+#
+# Makefile for the MOXART network device drivers.
+#
+
+obj-$(CONFIG_ARM_MOXART_ETHER) += moxart_ether.o
diff --git a/drivers/net/ethernet/moxa/moxart_ether.c b/drivers/net/ethernet/moxa/moxart_ether.c
new file mode 100644
index 0000000..8856f4e
--- /dev/null
+++ b/drivers/net/ethernet/moxa/moxart_ether.c
@@ -0,0 +1,577 @@
+/* MOXA ART Ethernet (RTL8201CP) driver.
+ *
+ * Copyright (C) 2013 Jonas Jensen
+ *
+ * Jonas Jensen <jonas.jensen@gmail.com>
+ *
+ * Based on code from
+ * Moxa Technology Co., Ltd. <www.moxa.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/dma-mapping.h>
+#include <linux/ethtool.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/crc32.h>
+#include <linux/crc32c.h>
+#include <linux/dma-mapping.h>
+
+#include "moxart_ether.h"
+
+static inline unsigned long moxart_emac_read(struct net_device *ndev,
+ unsigned int reg)
+{
+ struct moxart_mac_priv_t *priv = netdev_priv(ndev);
+
+ return readl(priv->base + reg);
+}
+
+static inline void moxart_emac_write(struct net_device *ndev,
+ unsigned int reg, unsigned long value)
+{
+ struct moxart_mac_priv_t *priv = netdev_priv(ndev);
+
+ writel(value, priv->base + reg);
+}
+
+static void moxart_update_mac_address(struct net_device *ndev)
+{
+ moxart_emac_write(ndev, MAC_MADR_REG_OFFSET,
+ ((ndev->dev_addr[0] << 8) | (ndev->dev_addr[1])));
+ moxart_emac_write(ndev, MAC_MADR_REG_OFFSET + 4,
+ ((ndev->dev_addr[2] << 24) |
+ (ndev->dev_addr[3] << 16) |
+ (ndev->dev_addr[4] << 8) |
+ (ndev->dev_addr[5])));
+}
+
+static int moxart_set_mac_address(struct net_device *ndev, void *addr)
+{
+ struct sockaddr *address = addr;
+
+ if (!is_valid_ether_addr(address->sa_data))
+ return -EADDRNOTAVAIL;
+
+ memcpy(ndev->dev_addr, address->sa_data, ndev->addr_len);
+ moxart_update_mac_address(ndev);
+
+ return 0;
+}
+
+static void moxart_mac_free_memory(struct net_device *ndev)
+{
+ struct moxart_mac_priv_t *priv = netdev_priv(ndev);
+ int i;
+
+ for (i = 0; i < RX_DESC_NUM; i++)
+ dma_unmap_single(&ndev->dev, priv->rx_mapping[i],
+ priv->rx_buf_size, DMA_FROM_DEVICE);
+
+ if (priv->tx_desc_base)
+ dma_free_coherent(NULL, sizeof(struct tx_desc_t)*TX_DESC_NUM,
+ priv->tx_desc_base, priv->tx_base);
+ if (priv->rx_desc_base)
+ dma_free_coherent(NULL, sizeof(struct rx_desc_t)*RX_DESC_NUM,
+ priv->rx_desc_base, priv->rx_base);
+
+ kfree(priv->tx_buf_base);
+ kfree(priv->rx_buf_base);
+}
+
+static void moxart_mac_reset(struct net_device *ndev)
+{
+ struct moxart_mac_priv_t *priv = netdev_priv(ndev);
+
+ writel(SW_RST, priv->base + MACCR_REG_OFFSET);
+ while (readl(priv->base + MACCR_REG_OFFSET) & SW_RST)
+ mdelay(10);
+
+ writel(0, priv->base + IMR_REG_OFFSET);
+
+ priv->reg_maccr = RX_BROADPKT | FULLDUP | CRC_APD | RX_FTL;
+}
+
+static void moxart_mac_enable(struct net_device *ndev)
+{
+ struct moxart_mac_priv_t *priv = netdev_priv(ndev);
+
+ writel(0x00001010, priv->base + ITC_REG_OFFSET);
+ writel(0x00000001, priv->base + APTC_REG_OFFSET);
+ writel(0x00000390, priv->base + DBLAC_REG_OFFSET);
+
+ priv->reg_imr |= (RPKT_FINISH_M | XPKT_FINISH_M);
+ writel(priv->reg_imr, priv->base + IMR_REG_OFFSET);
+
+ priv->reg_maccr |= (RCV_EN | XMT_EN | RDMA_EN | XDMA_EN);
+ writel(priv->reg_maccr, priv->base + MACCR_REG_OFFSET);
+}
+
+static void moxart_mac_setup_desc_ring(struct net_device *ndev)
+{
+ struct moxart_mac_priv_t *priv = netdev_priv(ndev);
+ struct tx_desc_t *txdesc;
+ struct rx_desc_t *rxdesc;
+ int i;
+
+ for (i = 0; i < TX_DESC_NUM; i++) {
+ txdesc = &priv->tx_desc_base[i];
+ memset(txdesc, 0, sizeof(struct tx_desc_t));
+
+ priv->tx_buf[i] = priv->tx_buf_base + priv->tx_buf_size * i;
+ }
+ priv->tx_desc_base[TX_DESC_NUM - 1].txdes1.ubit.edotr = 1;
+ priv->tx_head = 0;
+ priv->tx_tail = 0;
+
+ for (i = 0; i < RX_DESC_NUM; i++) {
+ rxdesc = &priv->rx_desc_base[i];
+ memset(rxdesc, 0, sizeof(struct rx_desc_t));
+ rxdesc->rxdes0.ubit.rx_dma_own = 1;
+ rxdesc->rxdes1.ubit.rx_buf_size = RX_BUF_SIZE;
+
+ priv->rx_buf[i] = priv->rx_buf_base + priv->rx_buf_size * i;
+ priv->rx_mapping[i] = dma_map_single(&ndev->dev,
+ priv->rx_buf[i],
+ priv->rx_buf_size,
+ DMA_FROM_DEVICE);
+ if (dma_mapping_error(&ndev->dev, priv->rx_mapping[i]))
+ netdev_err(ndev, "DMA mapping error\n");
+
+ rxdesc->rxdes2.addr_phys = priv->rx_mapping[i];
+ rxdesc->rxdes2.addr_virt = priv->rx_buf[i];
+ }
+ priv->rx_desc_base[RX_DESC_NUM - 1].rxdes1.ubit.edorr = 1;
+ priv->rx_head = 0;
+
+ /* reset the MAC controler TX/RX desciptor base address */
+ writel(priv->tx_base, priv->base + TXR_BADR_REG_OFFSET);
+ writel(priv->rx_base, priv->base + RXR_BADR_REG_OFFSET);
+}
+
+static int moxart_mac_open(struct net_device *ndev)
+{
+ struct moxart_mac_priv_t *priv = netdev_priv(ndev);
+
+ if (!is_valid_ether_addr(ndev->dev_addr))
+ return -EADDRNOTAVAIL;
+
+ napi_enable(&priv->napi);
+
+ moxart_mac_reset(ndev);
+ moxart_update_mac_address(ndev);
+ moxart_mac_setup_desc_ring(ndev);
+ moxart_mac_enable(ndev);
+ netif_start_queue(ndev);
+
+ netdev_dbg(ndev, "%s: IMR=0x%x, MACCR=0x%x\n",
+ __func__, readl(priv->base + IMR_REG_OFFSET),
+ readl(priv->base + MACCR_REG_OFFSET));
+
+ return 0;
+}
+
+static int moxart_mac_stop(struct net_device *ndev)
+{
+ struct moxart_mac_priv_t *priv = netdev_priv(ndev);
+
+ napi_disable(&priv->napi);
+
+ netif_stop_queue(ndev);
+
+ /* disable all interrupts */
+ writel(0, priv->base + IMR_REG_OFFSET);
+
+ /* disable all functions */
+ writel(0, priv->base + MACCR_REG_OFFSET);
+
+ return 0;
+}
+
+static int moxart_rx_poll(struct napi_struct *napi, int budget)
+{
+ struct moxart_mac_priv_t *priv = container_of(napi,
+ struct moxart_mac_priv_t,
+ napi);
+ struct net_device *ndev = priv->ndev;
+ struct rx_desc_t *rxdesc;
+ struct sk_buff *skb;
+ unsigned int ui, len;
+ int rx_head = priv->rx_head;
+ int rx = 0;
+
+ while (1) {
+ rxdesc = &priv->rx_desc_base[rx_head];
+ ui = rxdesc->rxdes0.ui;
+
+ if (ui & RXDMA_OWN)
+ break;
+
+ if (ui & (RX_ERR | CRC_ERR | FTL | RUNT | RX_ODD_NB)) {
+ net_dbg_ratelimited("packet error\n");
+ priv->stats.rx_dropped++;
+ priv->stats.rx_errors++;
+ continue;
+ }
+
+ len = ui & RFL_MASK;
+
+ if (len > RX_BUF_SIZE)
+ len = RX_BUF_SIZE;
+
+ skb = build_skb(priv->rx_buf[rx_head], priv->rx_buf_size);
+ if (unlikely(!skb)) {
+ net_dbg_ratelimited("build_skb failed\n");
+ priv->stats.rx_dropped++;
+ priv->stats.rx_errors++;
+ }
+
+ skb_put(skb, len);
+ skb->protocol = eth_type_trans(skb, ndev);
+ napi_gro_receive(&priv->napi, skb);
+ rx++;
+
+ ndev->last_rx = jiffies;
+ priv->stats.rx_packets++;
+ priv->stats.rx_bytes += len;
+ if (ui & MULTICAST_RXDES0)
+ priv->stats.multicast++;
+
+ rxdesc->rxdes0.ui = RXDMA_OWN;
+
+ rx_head = RX_NEXT(rx_head);
+ priv->rx_head = rx_head;
+
+ if (rx >= budget)
+ break;
+ }
+
+ if (rx < budget) {
+ napi_gro_flush(napi, false);
+ __napi_complete(napi);
+ }
+
+ priv->reg_imr |= RPKT_FINISH_M;
+ writel(priv->reg_imr, priv->base + IMR_REG_OFFSET);
+
+ return rx;
+}
+
+static void moxart_tx_finished(struct net_device *ndev)
+{
+ struct moxart_mac_priv_t *priv = netdev_priv(ndev);
+ unsigned tx_head = priv->tx_head;
+ unsigned tx_tail = priv->tx_tail;
+
+ while (tx_tail != tx_head) {
+ dma_unmap_single(&ndev->dev, priv->tx_mapping[tx_tail],
+ priv->tx_len[tx_tail], DMA_TO_DEVICE);
+
+ priv->stats.tx_packets++;
+ priv->stats.tx_bytes += priv->tx_skb[tx_tail]->len;
+
+ dev_kfree_skb_irq(priv->tx_skb[tx_tail]);
+ priv->tx_skb[tx_tail] = NULL;
+
+ tx_tail = TX_NEXT(tx_tail);
+ }
+ priv->tx_tail = tx_tail;
+}
+
+static irqreturn_t moxart_mac_interrupt(int irq, void *dev_id)
+{
+ struct net_device *ndev = (struct net_device *) dev_id;
+ struct moxart_mac_priv_t *priv = netdev_priv(ndev);
+ unsigned int ists = readl(priv->base + ISR_REG_OFFSET);
+
+ if (ists & XPKT_OK_INT_STS)
+ moxart_tx_finished(ndev);
+
+ if (ists & RPKT_FINISH) {
+ if (napi_schedule_prep(&priv->napi)) {
+ priv->reg_imr &= ~RPKT_FINISH_M;
+ writel(priv->reg_imr, priv->base + IMR_REG_OFFSET);
+ __napi_schedule(&priv->napi);
+ }
+ }
+
+ return IRQ_HANDLED;
+}
+
+static int moxart_mac_start_xmit(struct sk_buff *skb, struct net_device *ndev)
+{
+ struct moxart_mac_priv_t *priv = netdev_priv(ndev);
+ struct tx_desc_t *txdesc;
+ unsigned int len;
+ unsigned int tx_head = priv->tx_head;
+
+ spin_lock_irq(&priv->txlock);
+
+ txdesc = &priv->tx_desc_base[tx_head];
+
+ if (txdesc->txdes0.ubit.tx_dma_own) {
+ net_dbg_ratelimited("no TX space for packet\n");
+ priv->stats.tx_dropped++;
+ return NETDEV_TX_BUSY;
+ }
+
+ len = skb->len > TX_BUF_SIZE ? TX_BUF_SIZE : skb->len;
+
+ priv->tx_mapping[tx_head] = dma_map_single(&ndev->dev, skb->data,
+ len, DMA_TO_DEVICE);
+ if (dma_mapping_error(&ndev->dev, priv->tx_mapping[tx_head])) {
+ netdev_err(ndev, "DMA mapping error\n");
+ return NETDEV_TX_BUSY;
+ }
+
+ priv->tx_len[tx_head] = len;
+ priv->tx_skb[tx_head] = skb;
+
+ txdesc->txdes2.addr_phys = priv->tx_mapping[tx_head];
+ txdesc->txdes2.addr_virt = skb->data;
+
+ if (skb->len < ETH_ZLEN) {
+ memset(&txdesc->txdes2.addr_virt[skb->len],
+ 0, ETH_ZLEN - skb->len);
+ len = ETH_ZLEN;
+ }
+
+ txdesc->txdes1.ubit.lts = 1;
+ txdesc->txdes1.ubit.fts = 1;
+ txdesc->txdes1.ubit.tx2_fic = 0;
+ txdesc->txdes1.ubit.tx_ic = 0;
+ txdesc->txdes1.ubit.tx_buf_size = len;
+ txdesc->txdes0.ui = TXDMA_OWN;
+
+ /* start to send packet */
+ writel(0xffffffff, priv->base + TXPD_REG_OFFSET);
+
+ priv->tx_head = TX_NEXT(tx_head);
+
+ ndev->trans_start = jiffies;
+
+ spin_unlock_irq(&priv->txlock);
+
+ return NETDEV_TX_OK;
+}
+
+static struct net_device_stats *moxart_mac_get_stats(struct net_device *ndev)
+{
+ struct moxart_mac_priv_t *priv = netdev_priv(ndev);
+
+ return &priv->stats;
+}
+
+static void moxart_mac_setmulticast(struct net_device *ndev)
+{
+ struct moxart_mac_priv_t *priv = netdev_priv(ndev);
+ struct netdev_hw_addr *ha;
+ int crc_val;
+
+ netdev_for_each_mc_addr(ha, ndev) {
+ crc_val = crc32_le(~0, ha->addr, ETH_ALEN);
+ crc_val = (crc_val >> 26) & 0x3f;
+ if (crc_val >= 32) {
+ writel(readl(priv->base + MATH1_REG_OFFSET) |
+ (1UL << (crc_val - 32)),
+ priv->base + MATH1_REG_OFFSET);
+ } else {
+ writel(readl(priv->base + MATH0_REG_OFFSET) |
+ (1UL << crc_val),
+ priv->base + MATH0_REG_OFFSET);
+ }
+ }
+}
+
+static void moxart_mac_set_rx_mode(struct net_device *ndev)
+{
+ struct moxart_mac_priv_t *priv = netdev_priv(ndev);
+
+ spin_lock_irq(&priv->txlock);
+
+ (ndev->flags & IFF_PROMISC) ? (priv->reg_maccr |= RCV_ALL) :
+ (priv->reg_maccr &= ~RCV_ALL);
+
+ (ndev->flags & IFF_ALLMULTI) ? (priv->reg_maccr |= RX_MULTIPKT) :
+ (priv->reg_maccr &= ~RX_MULTIPKT);
+
+ if ((ndev->flags & IFF_MULTICAST) && netdev_mc_count(ndev)) {
+ priv->reg_maccr |= HT_MULTI_EN;
+ moxart_mac_setmulticast(ndev);
+ } else {
+ priv->reg_maccr &= ~HT_MULTI_EN;
+ }
+
+ writel(priv->reg_maccr, priv->base + MACCR_REG_OFFSET);
+
+ spin_unlock_irq(&priv->txlock);
+}
+
+static struct net_device_ops moxart_netdev_ops = {
+ .ndo_open = moxart_mac_open,
+ .ndo_stop = moxart_mac_stop,
+ .ndo_start_xmit = moxart_mac_start_xmit,
+ .ndo_get_stats = moxart_mac_get_stats,
+ .ndo_set_rx_mode = moxart_mac_set_rx_mode,
+ .ndo_set_mac_address = moxart_set_mac_address,
+ .ndo_validate_addr = eth_validate_addr,
+ .ndo_change_mtu = eth_change_mtu,
+};
+
+static void moxart_get_mac_address(struct net_device *ndev)
+{
+ struct moxart_mac_priv_t *priv = netdev_priv(ndev);
+ int i;
+
+ for (i = 0; i <= 5; i++)
+ ndev->dev_addr[i] = readb(priv->flash_base + i);
+}
+
+static int moxart_mac_probe(struct platform_device *pdev)
+{
+ struct device *p_dev = &pdev->dev;
+ struct device_node *node = p_dev->of_node;
+ struct net_device *ndev;
+ struct moxart_mac_priv_t *priv;
+ struct resource *res;
+ unsigned int irq;
+ void *tmp;
+
+ ndev = alloc_etherdev(sizeof(struct moxart_mac_priv_t));
+ if (!ndev)
+ return -ENOMEM;
+
+ irq = irq_of_parse_and_map(node, 0);
+
+ priv = netdev_priv(ndev);
+ priv->ndev = ndev;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ ndev->base_addr = res->start;
+ priv->base = devm_ioremap_resource(p_dev, res);
+ if (IS_ERR(priv->base)) {
+ dev_err(p_dev, "devm_ioremap_resource failed\n");
+ goto init_fail;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+
+ /* the flash driver (physmap_of) requests the same region
+ * so use ioremap instead of devm_ioremap_resource
+ */
+ priv->flash_base = ioremap(res->start, resource_size(res));
+ if (IS_ERR(priv->flash_base)) {
+ dev_err(p_dev, "devm_ioremap_resource failed\n");
+ goto init_fail;
+ }
+
+ spin_lock_init(&priv->txlock);
+
+ priv->tx_buf_size = TX_BUF_SIZE;
+ priv->rx_buf_size = RX_BUF_SIZE +
+ SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
+
+ tmp = dma_alloc_coherent(NULL, sizeof(struct tx_desc_t) * TX_DESC_NUM,
+ &priv->tx_base, GFP_DMA | GFP_KERNEL);
+ priv->tx_desc_base = (struct tx_desc_t *) tmp;
+ if (priv->tx_desc_base == NULL)
+ goto init_fail;
+
+ tmp = dma_alloc_coherent(NULL, sizeof(struct rx_desc_t) * RX_DESC_NUM,
+ &priv->rx_base, GFP_DMA | GFP_KERNEL);
+ priv->rx_desc_base = (struct rx_desc_t *) tmp;
+ if (priv->rx_desc_base == NULL)
+ goto init_fail;
+
+ priv->tx_buf_base = kmalloc(priv->tx_buf_size * TX_DESC_NUM,
+ GFP_ATOMIC);
+ if (!priv->tx_buf_base)
+ goto init_fail;
+
+ priv->rx_buf_base = kmalloc(priv->rx_buf_size * RX_DESC_NUM,
+ GFP_ATOMIC);
+ if (!priv->rx_buf_base)
+ goto init_fail;
+
+ platform_set_drvdata(pdev, ndev);
+
+ ether_setup(ndev);
+ ndev->netdev_ops = &moxart_netdev_ops;
+ netif_napi_add(ndev, &priv->napi, moxart_rx_poll, RX_DESC_NUM);
+ ndev->priv_flags |= IFF_UNICAST_FLT;
+
+ SET_NETDEV_DEV(ndev, &pdev->dev);
+
+ moxart_get_mac_address(ndev);
+ moxart_update_mac_address(ndev);
+
+ if (register_netdev(ndev)) {
+ free_netdev(ndev);
+ goto init_fail;
+ }
+
+ ndev->irq = irq;
+
+ if (devm_request_irq(p_dev, irq, moxart_mac_interrupt, 0,
+ pdev->name, ndev)) {
+ netdev_err(ndev, "devm_request_irq failed\n");
+ free_netdev(ndev);
+ return -EBUSY;
+ }
+
+ netdev_dbg(ndev, "%s: IRQ=%d address=%pM\n",
+ __func__, ndev->irq, ndev->dev_addr);
+
+ return 0;
+
+init_fail:
+ netdev_err(ndev, "%s: init failed\n", __func__);
+ moxart_mac_free_memory(ndev);
+
+ return -ENOMEM;
+}
+
+static int moxart_remove(struct platform_device *pdev)
+{
+ struct net_device *ndev = platform_get_drvdata(pdev);
+
+ unregister_netdev(ndev);
+ free_irq(ndev->irq, ndev);
+ moxart_mac_free_memory(ndev);
+ platform_set_drvdata(pdev, NULL);
+ free_netdev(ndev);
+
+ return 0;
+}
+
+static const struct of_device_id moxart_mac_match[] = {
+ { .compatible = "moxa,moxart-mac" },
+ { }
+};
+
+struct __initdata platform_driver moxart_mac_driver = {
+ .probe = moxart_mac_probe,
+ .remove = moxart_remove,
+ .driver = {
+ .name = "moxart-ethernet",
+ .owner = THIS_MODULE,
+ .of_match_table = moxart_mac_match,
+ },
+};
+module_platform_driver(moxart_mac_driver);
+
+MODULE_DESCRIPTION("MOXART RTL8201CP Ethernet driver");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Jonas Jensen <jonas.jensen@gmail.com>");
+diff --git a/drivers/net/ethernet/moxa/moxart_ether.h b/drivers/net/ethernet/moxa/moxart_ether.h
new file mode 100644
index 0000000..790b6a9
--- /dev/null
+++ b/drivers/net/ethernet/moxa/moxart_ether.h
@@ -0,0 +1,513 @@
+/* MOXA ART Ethernet (RTL8201CP) driver.
+ *
+ * Copyright (C) 2013 Jonas Jensen
+ *
+ * Jonas Jensen <jonas.jensen@gmail.com>
+ *
+ * Based on code from
+ * Moxa Technology Co., Ltd. <www.moxa.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#ifndef _MOXART_ETHERNET_H
+#define _MOXART_ETHERNET_H
+
+#define TX_DESC_NUM 64
+#define TX_DESC_NUM_MASK (TX_DESC_NUM-1)
+#define TX_NEXT(N) (((N) + 1) & (TX_DESC_NUM_MASK))
+#define TX_BUF_SIZE 1600
+
+#define RX_DESC_NUM 64
+#define RX_DESC_NUM_MASK (RX_DESC_NUM-1)
+#define RX_NEXT(N) (((N) + 1) & (RX_DESC_NUM_MASK))
+#define RX_BUF_SIZE 1600
+
+struct tx_desc_t {
+ union {
+#define TXDMA_OWN BIT(31)
+#define TXPKT_EXSCOL BIT(1)
+#define TXPKT_LATECOL BIT(0)
+ unsigned int ui;
+
+ struct {
+ /* is aborted due to late collision */
+ unsigned int tx_pkt_late_col:1;
+
+ /* is aborted after 16 collisions */
+ unsigned int rx_pkt_exs_col:1;
+
+ unsigned int reserved1:29;
+
+ /* is owned by the MAC controller */
+ unsigned int tx_dma_own:1;
+ } ubit;
+ } txdes0;
+
+ union {
+#define EDOTR BIT(31)
+#define TXIC BIT(30)
+#define TX2FIC BIT(29)
+#define FTS BIT(28)
+#define LTS BIT(27)
+#define TXBUF_SIZE_MASK 0x7ff
+#define TXBUF_SIZE_MAX (TXBUF_SIZE_MASK+1)
+ unsigned int ui;
+
+ struct {
+ /* transmit buffer size in byte */
+ unsigned int tx_buf_size:11;
+
+ unsigned int reserved2:16;
+
+ /* is the last descriptor of a Tx packet */
+ unsigned int lts:1;
+
+ /* is the first descriptor of a Tx packet */
+ unsigned int fts:1;
+
+ /* transmit to FIFO interrupt on completion */
+ unsigned int tx2_fic:1;
+
+ /* transmit interrupt on completion */
+ unsigned int tx_ic:1;
+
+ /* end descriptor of transmit ring */
+ unsigned int edotr:1;
+ } ubit;
+ } txdes1;
+
+ struct {
+ /* transmit buffer physical base address */
+ unsigned int addr_phys;
+
+ /* transmit buffer virtual base address */
+ unsigned char *addr_virt;
+ } txdes2;
+};
+
+struct rx_desc_t {
+ union {
+#define RXDMA_OWN BIT(31)
+#define FRS BIT(29)
+#define LRS BIT(28)
+#define RX_ODD_NB BIT(22)
+#define RUNT BIT(21)
+#define FTL BIT(20)
+#define CRC_ERR BIT(19)
+#define RX_ERR BIT(18)
+#define BROADCAST_RXDES0 BIT(17)
+#define MULTICAST_RXDES0 BIT(16)
+#define RFL_MASK 0x7ff
+#define RFL_MAX (RFL_MASK+1)
+ unsigned int ui;
+
+ struct {
+ /* receive frame length */
+ unsigned int recv_frame_len:11;
+ unsigned int reserved1:5;
+
+ /* multicast frame */
+ unsigned int multicast:1;
+
+ /* broadcast frame */
+ unsigned int broadcast:1;
+ unsigned int rx_err:1; /* receive error */
+ unsigned int crc_err:1; /* CRC error */
+ unsigned int ftl:1; /* frame too long */
+
+ /* runt packet, less than 64 bytes */
+ unsigned int runt:1;
+
+ /* receive odd nibbles */
+ unsigned int rx_odd_nb:1;
+ unsigned int reserved2:5;
+
+ /* last receive segment descriptor */
+ unsigned int lrs:1;
+
+ /* first receive segment descriptor */
+ unsigned int frs:1;
+
+ unsigned int reserved3:1;
+ unsigned int rx_dma_own:1; /* RXDMA onwership */
+ } ubit;
+ } rxdes0;
+
+ union {
+#define EDORR BIT(31)
+#define RXBUF_SIZE_MASK 0x7ff
+#define RXBUF_SIZE_MAX (RXBUF_SIZE_MASK+1)
+ unsigned int ui;
+
+ struct {
+ /* receive buffer size */
+ unsigned int rx_buf_size:11;
+
+ unsigned int reserved4:20;
+
+ /* end descriptor of receive ring */
+ unsigned int edorr:1;
+ } ubit;
+ } rxdes1;
+
+ struct {
+ /* receive buffer physical base address */
+ unsigned int addr_phys;
+
+ /* receive buffer virtual base address */
+ unsigned char *addr_virt;
+ } rxdes2;
+};
+
+struct mac_control_reg_t {
+
+/* RXDMA has received packets into RX buffer successfully */
+#define RPKT_FINISH BIT(0)
+/* receive buffer unavailable */
+#define NORXBUF BIT(1)
+/* TXDMA has moved data into the TX FIFO */
+#define XPKT_FINISH BIT(2)
+/* transmit buffer unavailable */
+#define NOTXBUF BIT(3)
+/* packets transmitted to ethernet successfully */
+#define XPKT_OK_INT_STS BIT(4)
+/* packets transmitted to ethernet lost due to late
+ * collision or excessive collision
+ */
+#define XPKT_LOST_INT_STS BIT(5)
+/* packets received into RX FIFO successfully */
+#define RPKT_SAV BIT(6)
+/* received packet lost due to RX FIFO full */
+#define RPKT_LOST_INT_STS BIT(7)
+#define AHB_ERR BIT(8) /* AHB error */
+#define PHYSTS_CHG BIT(9) /* PHY link status change */
+ unsigned int isr; /* interrupt status, 0x0 */
+
+#define RPKT_FINISH_M BIT(0) /* interrupt mask of ISR[0] */
+#define NORXBUF_M BIT(1) /* interrupt mask of ISR[1] */
+#define XPKT_FINISH_M BIT(2) /* interrupt mask of ISR[2] */
+#define NOTXBUF_M BIT(3) /* interrupt mask of ISR[3] */
+#define XPKT_OK_M BIT(4) /* interrupt mask of ISR[4] */
+#define XPKT_LOST_M BIT(5) /* interrupt mask of ISR[5] */
+#define RPKT_SAV_M BIT(6) /* interrupt mask of ISR[6] */
+#define RPKT_LOST_M BIT(7) /* interrupt mask of ISR[7] */
+#define AHB_ERR_M BIT(8) /* interrupt mask of ISR[8] */
+#define PHYSTS_CHG_M BIT(9) /* interrupt mask of ISR[9] */
+ unsigned int imr; /* interrupt mask, 0x4 */
+
+/* the most significant 2 bytes of MAC address */
+#define MAC_MADR_MASK 0xffff
+ /* MAC most significant address, 0x8 */
+ unsigned int mac_madr;
+
+ /* MAC least significant address, 0xc */
+ unsigned int mac_ldar;
+
+ /* multicast address hash table 0, 0x10 */
+ unsigned int matht0;
+
+ /* multicast address hash table 1, 0x14 */
+ unsigned int matht1;
+
+ /* transmit poll demand, 0x18 */
+ unsigned int txpd;
+
+ /* receive poll demand, 0x1c */
+ unsigned int rxpd;
+
+ /* transmit ring base address, 0x20 */
+ unsigned int txr_badr;
+
+ /* receive ring base address, 0x24 */
+ unsigned int rxr_badr;
+
+/* defines the period of TX cycle time */
+#define TXINT_TIME_SEL BIT(15)
+#define TXINT_THR_MASK 0x7000
+#define TXINT_CNT_MASK 0xf00
+/* defines the period of RX cycle time */
+#define RXINT_TIME_SEL BIT(7)
+#define RXINT_THR_MASK 0x70
+#define RXINT_CNT_MASK 0xF
+ /* interrupt timer control, 0x28 */
+ unsigned int itc;
+
+/* defines the period of TX poll time */
+#define TXPOLL_TIME_SEL BIT(12)
+#define TXPOLL_CNT_MASK 0xf00
+#define TXPOLL_CNT_SHIFT_BIT 8
+/* defines the period of RX poll time */
+#define RXPOLL_TIME_SEL BIT(4)
+#define RXPOLL_CNT_MASK 0xF
+#define RXPOLL_CNT_SHIFT_BIT 0
+ /* automatic polling timer control, 0x2c */
+ unsigned int aptc;
+
+/* enable RX FIFO threshold arbitration */
+#define RX_THR_EN BIT(9)
+#define RXFIFO_HTHR_MASK 0x1c0
+#define RXFIFO_LTHR_MASK 0x38
+/* use INCR16 burst command in AHB bus */
+#define INCR16_EN BIT(2)
+/* use INCR8 burst command in AHB bus */
+#define INCR8_EN BIT(1)
+/* use INCR4 burst command in AHB bus */
+#define INCR4_EN BIT(0)
+ /* DMA burst length and arbitration control, 0x30 */
+ unsigned int dblac;
+
+ unsigned int reserved1[21]; /* 0x34 - 0x84 */
+
+#define RX_BROADPKT BIT(17) /* receive boradcast packet */
+/* receive all multicast packet */
+#define RX_MULTIPKT BIT(16)
+#define FULLDUP BIT(15) /* full duplex */
+/* append CRC to transmitted packet */
+#define CRC_APD BIT(14)
+/* do not check incoming packet's destination address */
+#define RCV_ALL BIT(12)
+/* store incoming packet even if its length is great than 1518 bytes */
+#define RX_FTL BIT(11)
+/* store incoming packet even if its length is less than 64 bytes */
+#define RX_RUNT BIT(10)
+/* enable storing incoming packet if the packet passes hash table
+ * address filtering and is a multicast packet
+ */
+#define HT_MULTI_EN BIT(9)
+#define RCV_EN BIT(8) /* receiver enable */
+/* enable packet reception when transmitting packet in half duplex mode */
+#define ENRX_IN_HALFTX BIT(6)
+#define XMT_EN BIT(5) /* transmitter enable */
+/* disable CRC check when receiving packets */
+#define CRC_DIS BIT(4)
+#define LOOP_EN BIT(3) /* internal loop-back */
+/* software reset, last 64 AHB bus clocks */
+#define SW_RST BIT(2)
+#define RDMA_EN BIT(1) /* enable receive DMA chan */
+#define XDMA_EN BIT(0) /* enable transmit DMA chan */
+ unsigned int maccr; /* MAC control, 0x88 */
+
+#define COL_EXCEED BIT(11) /* collisions exceeds 16 */
+/* transmitter detects late collision */
+#define LATE_COL BIT(10)
+/* packet transmitted to ethernet lost due to late collision
+ * or excessive collision
+ */
+#define XPKT_LOST BIT(9)
+/* packets transmitted to ethernet successfully */
+#define XPKT_OK BIT(8)
+/* receiver detects a runt packet */
+#define RUNT_MAC_STS BIT(7)
+/* receiver detects a frame that is too long */
+#define FTL_MAC_STS BIT(6)
+#define CRC_ERR_MAC_STS BIT(5)
+/* received packets list due to RX FIFO full */
+#define RPKT_LOST BIT(4)
+/* packets received into RX FIFO successfully */
+#define RPKT_SAVE BIT(3)
+/* incoming packet dropped due to collision */
+#define COL BIT(2)
+#define MCPU_BROADCAST BIT(1)
+#define MCPU_MULTICAST BIT(0)
+ unsigned int macsr; /* MAC status, 0x8c */
+
+/* initialize a write sequence to PHY by setting this bit to 1
+ * this bit would be auto cleared after the write operation is finished.
+ */
+#define MIIWR BIT(27)
+#define MIIRD BIT(26)
+#define REGAD_MASK 0x3e00000
+#define PHYAD_MASK 0x1f0000
+#define MIIRDATA_MASK 0xffff
+ unsigned int phycr; /* PHY control, 0x90 */
+
+#define MIIWDATA_MASK 0xffff
+ unsigned int phywdata; /* PHY write data, 0x94 */
+
+#define PAUSE_TIME_MASK 0xffff0000
+#define FC_HIGH_MASK 0xf000
+#define FC_LOW_MASK 0xf00
+#define RX_PAUSE BIT(4) /* receive pause frame */
+/* packet transmission is paused due to receive */
+#define TXPAUSED BIT(3)
+ /* pause frame */
+/* enable flow control threshold mode. */
+#define FCTHR_EN BIT(2)
+#define TX_PAUSE BIT(1) /* transmit pause frame */
+#define FC_EN BIT(0) /* flow control mode enable */
+ unsigned int fcr; /* flow control, 0x98 */
+
+#define BK_LOW_MASK 0xf00
+#define BKJAM_LEN_MASK 0xf0
+#define BK_MODE BIT(1) /* back pressure address mode */
+#define BK_EN BIT(0) /* back pressure mode enable */
+ unsigned int bpr; /* back pressure, 0x9c */
+
+ unsigned int reserved2[9]; /* 0xa0 - 0xc0 */
+
+#define TEST_SEED_MASK 0x3fff
+ unsigned int ts; /* test seed, 0xc4 */
+
+#define TXD_REQ BIT(31) /* TXDMA request */
+#define RXD_REQ BIT(30) /* RXDMA request */
+#define DARB_TXGNT BIT(29) /* TXDMA grant */
+#define DARB_RXGNT BIT(28) /* RXDMA grant */
+#define TXFIFO_EMPTY BIT(27) /* TX FIFO is empty */
+#define RXFIFO_EMPTY BIT(26) /* RX FIFO is empty */
+#define TXDMA2_SM_MASK 0x7000
+#define TXDMA1_SM_MASK 0xf00
+#define RXDMA2_SM_MASK 0x70
+#define RXDMA1_SM_MASK 0xF
+ unsigned int dmafifos; /* DMA/FIFO state, 0xc8 */
+
+#define SINGLE_PKT BIT(26) /* single packet mode */
+/* automatic polling timer test mode */
+#define PTIMER_TEST BIT(25)
+#define ITIMER_TEST BIT(24) /* interrupt timer test mode */
+#define TEST_SEED_SEL BIT(22) /* test seed select */
+#define SEED_SEL BIT(21) /* seed select */
+#define TEST_MODE BIT(20) /* transmission test mode */
+#define TEST_TIME_MASK 0xffc00
+#define TEST_EXCEL_MASK 0x3e0
+ unsigned int tm; /* test mode, 0xcc */
+
+ unsigned int reserved3; /* 0xd0 */
+
+#define TX_MCOL_MASK 0xffff0000
+#define TX_MCOL_SHIFT_BIT 16
+#define TX_SCOL_MASK 0xffff
+#define TX_SCOL_SHIFT_BIT 0
+ /* TX_MCOL and TX_SCOL counter, 0xd4 */
+ unsigned int txmcol_xscol;
+
+#define RPF_MASK 0xffff0000
+#define RPF_SHIFT_BIT 16
+#define AEP_MASK 0xffff
+#define AEP_SHIFT_BIT 0
+ unsigned int rpf_aep; /* RPF and AEP counter, 0xd8 */
+
+#define XM_MASK 0xffff0000
+#define XM_SHIFT_BIT 16
+#define PG_MASK 0xffff
+#define PG_SHIFT_BIT 0
+ unsigned int xm_pg; /* XM and PG counter, 0xdc */
+
+#define RUNT_CNT_MASK 0xffff0000
+#define RUNT_CNT_SHIFT_BIT 16
+#define TLCC_MASK 0xffff
+#define TLCC_SHIFT_BIT 0
+ /* RUNT_CNT and TLCC counter, 0xe0 */
+ unsigned int runtcnt_tlcc;
+
+#define CRCER_CNT_MASK 0xffff0000
+#define CRCER_CNT_SHIFT_BIT 16
+#define FTL_CNT_MASK 0xffff
+#define FTL_CNT_SHIFT_BIT 0
+ /* CRCER_CNT and FTL_CNT counter, 0xe4 */
+ unsigned int crcercnt_ftlcnt;
+
+#define RLC_MASK 0xffff0000
+#define RLC_SHIFT_BIT 16
+#define RCC_MASK 0xffff
+#define RCC_SHIFT_BIT 0
+ unsigned int rlc_rcc; /* RLC and RCC counter, 0xe8 */
+
+ unsigned int broc; /* BROC counter, 0xec */
+ unsigned int mulca; /* MULCA counter, 0xf0 */
+ unsigned int rp; /* RP counter, 0xf4 */
+ unsigned int xp; /* XP counter, 0xf8 */
+};
+
+#define ISR_REG_OFFSET 0x0
+#define IMR_REG_OFFSET 0x4
+#define MAC_MADR_REG_OFFSET 0x8
+#define MAC_LADR_REG_OFFSET 0xC
+#define MATH0_REG_OFFSET 0x10
+#define MATH1_REG_OFFSET 0x14
+#define TXPD_REG_OFFSET 0x18
+#define RXPD_REG_OFFSET 0x1C
+#define TXR_BADR_REG_OFFSET 0x20
+#define RXR_BADR_REG_OFFSET 0x24
+#define ITC_REG_OFFSET 0x28
+#define APTC_REG_OFFSET 0x2C
+#define DBLAC_REG_OFFSET 0x30
+#define MACCR_REG_OFFSET 0x88
+#define MACSR_REG_OFFSET 0x8C
+#define PHYCR_REG_OFFSET 0x90
+#define PHYWDATA_REG_OFFSET 0x94
+#define FCR_REG_OFFSET 0x98
+#define BPR_REG_OFFSET 0x9C
+#define TS_REG_OFFSET 0xC4
+#define DMAFIFOS_REG_OFFSET 0xC8
+#define TM_REG_OFFSET 0xCC
+#define TX_MCOL_TX_SCOL_REG_OFFSET 0xD4
+#define RPF_AEP_REG_OFFSET 0xD8
+#define XM_PG_REG_OFFSET 0xDC
+#define RUNT_CNT_TLCC_REG_OFFSET 0xE0
+#define CRCER_CNT_FTL_CNT_REG_OFFSET 0xE4
+#define RLC_RCC_REG_OFFSET 0xE8
+#define BROC_REG_OFFSET 0xEC
+#define MULCA_REG_OFFSET 0xF0
+#define RP_REG_OFFSET 0xF4
+#define XP_REG_OFFSET 0xF8
+#define PHY_CNTL_REG 0x0
+#define PHY_STATUS_REG 0x1
+#define PHY_ID_REG1 0x2
+#define PHY_ID_REG2 0x3
+#define PHY_ANA_REG 0x4
+#define PHY_ANLPAR_REG 0x5
+#define PHY_ANE_REG 0x6
+#define PHY_ECNTL_REG1 0x10
+#define PHY_QPDS_REG 0x11
+#define PHY_10BOP_REG 0x12
+#define PHY_ECNTL_REG2 0x13
+#define FTMAC100_REG_PHY_WRITE 0x8000000
+#define FTMAC100_REG_PHY_READ 0x4000000
+
+/* PHY Status register */
+#define AN_COMPLETE 0x20
+
+#define LINK_STATUS 0x4
+
+struct moxart_mac_priv_t {
+ void __iomem *base;
+ void __iomem *flash_base;
+ struct net_device_stats stats;
+ unsigned int reg_maccr;
+ unsigned int reg_imr;
+ struct napi_struct napi;
+ struct net_device *ndev;
+
+ dma_addr_t rx_base;
+ dma_addr_t rx_mapping[RX_DESC_NUM];
+ struct rx_desc_t *rx_desc_base;
+ unsigned char *rx_buf_base;
+ unsigned char *rx_buf[RX_DESC_NUM];
+ unsigned int rx_head;
+ unsigned int rx_buf_size;
+
+ dma_addr_t tx_base;
+ dma_addr_t tx_mapping[TX_DESC_NUM];
+ struct tx_desc_t *tx_desc_base;
+ unsigned char *tx_buf_base;
+ unsigned char *tx_buf[RX_DESC_NUM];
+ unsigned int tx_head;
+ unsigned int tx_buf_size;
+
+ spinlock_t txlock;
+ unsigned int tx_len[TX_DESC_NUM];
+ struct sk_buff *tx_skb[TX_DESC_NUM];
+ unsigned int tx_tail;
+};
+
+#if TX_BUF_SIZE >= TXBUF_SIZE_MAX
+#error MOXA ART Ethernet device driver Tx buffer size too large !
+#endif
+#if RX_BUF_SIZE >= RXBUF_SIZE_MAX
+#error MOXA ART Ethernet device driver Rx buffer size too large !
+#endif
+
+#endif--
1.8.2.1