[linux-yocto] [PATCH 02/17] axxia: Clean Up the MDIO Access Code

Daniel Dragomir daniel.dragomir at windriver.com
Tue May 16 11:38:54 PDT 2017


From: John Jacques <john.jacques at intel.com>

Removes unused code and adds the second MDIO bus
available on 6700.

Signed-off-by: John Jacques <john.jacques at intel.com>
---
 arch/arm64/boot/dts/intel/axc6732-waco.dts |    7 +
 arch/arm64/boot/dts/intel/axc67xx.dtsi     |    4 +-
 arch/arm64/boot/dts/intel/axm56xx.dtsi     |    2 +-
 drivers/misc/Kconfig                       |    6 +
 drivers/misc/Makefile                      |    1 +
 drivers/misc/axxia-mdio.c                  |  228 ++++++
 drivers/net/ethernet/lsi/Kconfig           |   34 -
 drivers/net/ethernet/lsi/Makefile          |    2 -
 drivers/net/ethernet/lsi/lsi-femac.c       | 1198 ----------------------------
 drivers/net/ethernet/lsi/lsi-mdio.c        |  205 -----
 include/linux/axxia-mdio.h                 |   21 +
 11 files changed, 266 insertions(+), 1442 deletions(-)
 create mode 100644 drivers/misc/axxia-mdio.c
 delete mode 100644 drivers/net/ethernet/lsi/lsi-femac.c
 delete mode 100644 drivers/net/ethernet/lsi/lsi-mdio.c
 create mode 100644 include/linux/axxia-mdio.h

diff --git a/arch/arm64/boot/dts/intel/axc6732-waco.dts b/arch/arm64/boot/dts/intel/axc6732-waco.dts
index 056efc4..c600dbe 100644
--- a/arch/arm64/boot/dts/intel/axc6732-waco.dts
+++ b/arch/arm64/boot/dts/intel/axc6732-waco.dts
@@ -55,6 +55,13 @@
 	};
 };
 
+&mdio1 {
+	status = "okay";
+	lsi,mdio-clk-offset = <0x1c>;
+	lsi,mdio-clk-period = <0xf0>;
+	max-speed = <10>;
+};
+
 &spi0 {
 	status = "okay";
 
diff --git a/arch/arm64/boot/dts/intel/axc67xx.dtsi b/arch/arm64/boot/dts/intel/axc67xx.dtsi
index 3554dd5..f6712fb 100644
--- a/arch/arm64/boot/dts/intel/axc67xx.dtsi
+++ b/arch/arm64/boot/dts/intel/axc67xx.dtsi
@@ -120,7 +120,7 @@
 		};
 
 		mdio0: mdio at 8080260000 {
-			compatible = "lsi,axm-mdio";
+			compatible = "lsi,axm-mdio", "intel,axxia-mdio0";
 			#address-cells = <1>;
 			#size-cells = <0>;
 			reg = <0x80 0x80260000 0 0x1000>;
@@ -128,7 +128,7 @@
 		};
 
 		mdio1: mdio at 8080270000 {
-			compatible = "lsi,axm-mdio";
+			compatible = "intel,axxia-mdio1";
 			#address-cells = <1>;
 			#size-cells = <0>;
 			reg = <0x80 0x80270000 0 0x1000>;
diff --git a/arch/arm64/boot/dts/intel/axm56xx.dtsi b/arch/arm64/boot/dts/intel/axm56xx.dtsi
index ff140b7..08ebbe9 100644
--- a/arch/arm64/boot/dts/intel/axm56xx.dtsi
+++ b/arch/arm64/boot/dts/intel/axm56xx.dtsi
@@ -130,7 +130,7 @@
 		};
 
 		mdio: mdio at 8080200000 {
-			compatible = "lsi,axm-mdio";
+			compatible = "lsi,axm-mdio", "intel,axxia-mdio0";
 			#address-cells = <1>;
 			#size-cells = <0>;
 			reg = <0x80 0x80200000 0 0x1000>;
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index c7be89f..13f8e17 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -530,6 +530,12 @@ config AXXIA_PEI
        help
 	 Set up the PEI controllers in Linux instead of the boot loader.
 
+config AXXIA_MDIO
+       bool "Axxia MDIO Driver"
+       depends on ARCH_AXXIA
+       help
+	 Provide access to the Axxia MDIO bus.
+
 config VEXPRESS_SYSCFG
 	bool "Versatile Express System Configuration driver"
 	depends on VEXPRESS_CONFIG
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index 00cdb96..438adf2 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -54,6 +54,7 @@ obj-$(CONFIG_LSI_MTC)		+= lsi-mtc.o
 obj-$(CONFIG_LSI_SMMON)         += lsi-smmon.o
 obj-$(CONFIG_AXXIA_OEM)         += axxia-oem.o
 obj-$(CONFIG_AXXIA_PEI)         += axxia-pei.o
+obj-$(CONFIG_AXXIA_MDIO)        += axxia-mdio.o
 obj-$(CONFIG_ECHO)		+= echo/
 obj-$(CONFIG_VEXPRESS_SYSCFG)	+= vexpress-syscfg.o
 obj-$(CONFIG_CXL_BASE)		+= cxl/
diff --git a/drivers/misc/axxia-mdio.c b/drivers/misc/axxia-mdio.c
new file mode 100644
index 0000000..acaca53
--- /dev/null
+++ b/drivers/misc/axxia-mdio.c
@@ -0,0 +1,228 @@
+/*
+ * Copyright (C) 2017 Intel <john.jacques at intel.com>
+ *
+ * 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.
+ */
+
+#include <linux/module.h>
+#include <linux/mii.h>
+#include <linux/phy.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_mdio.h>
+#include <linux/of_platform.h>
+#include <linux/io.h>
+
+/* MDIO Registers */
+#define MDIO_CONTROL		0x00
+#define   CONTROL_BUSY		(1<<31) /* MDIO cycle in progress (RO) */
+#define   CONTROL_NOPRE		(1<<30) /* Suppress preamble */
+#define   CONTROL_CL22		(0<<29) /* Clause-22 */
+#define   CONTROL_CL45		(1<<29) /* Clause-45 */
+#define   CONTROL_READ		(2<<27) /* Read operation */
+#define   CONTROL_WRITE		(1<<27) /* Write operation */
+#define   CONTROL_IFSEL		(1<<26) /* Interface select */
+#define   CONTROL_PHYREG(_n)	(((_n) & 0x1F) << 21)
+#define   CONTROL_PHYID(_n)	(((_n) & 0x1F) << 16)
+#define   CONTROL_DATA(_n)	(((_n) & 0xFFFF) << 0)
+#define MDIO_STATUS		0x04
+#define   STATUS_BUSY		(1<<31)
+#define   STATUS_DONE		(1<<30)
+#define MDIO_CLK_OFFSET		0x08
+#define MDIO_CLK_PERIOD		0x0c
+
+/* MDIO bus driver private data */
+struct axxia_mdio_priv {
+	void __iomem *base;
+	struct mii_bus *bus;
+};
+
+static inline void __iomem *
+bus_to_regs(struct mii_bus *bus)
+{
+	return ((struct axxia_mdio_priv *)bus->priv)->base;
+}
+
+static int
+axxia_mdio_read(struct mii_bus *bus, int mii_id, int regnum)
+{
+	void __iomem *base = bus_to_regs(bus);
+	u32 ctrl;
+	u32 data;
+
+	/* Set the mdio_done (status) bit. */
+	writel(STATUS_DONE | readl(base + MDIO_STATUS), base + MDIO_STATUS);
+
+	/* Write the command. */
+	ctrl = (CONTROL_READ |
+		CONTROL_PHYID(mii_id) |
+		CONTROL_PHYREG(regnum));
+
+	if (regnum & MII_ADDR_C45)
+		ctrl |= CONTROL_CL45;
+
+	writel(ctrl, base + MDIO_CONTROL);
+
+	/* Wait for the mdio_done (status) bit to clear. */
+	while ((readl(base + MDIO_STATUS) & STATUS_DONE) != 0)
+		cpu_relax();
+
+	/* Wait for the mdio_busy (control) bit to clear. */
+	do {
+		data = readl(base + MDIO_CONTROL);
+	} while ((data & CONTROL_BUSY) != 0);
+
+	return data & 0xFFFF;
+}
+
+static int
+axxia_mdio_write(struct mii_bus *bus, int mii_id, int regnum, u16 value)
+{
+	void __iomem *base = bus_to_regs(bus);
+	u32 ctrl;
+
+	printk("%s:%d - base=0x%p\n", __FILE__, __LINE__, base);
+
+	/* Wait for mdio_busy (control) to be clear. */
+	while ((readl(base + MDIO_CONTROL) & CONTROL_BUSY) != 0)
+		cpu_relax();
+
+	/* Set the mdio_busy (status) bit. */
+	writel(STATUS_DONE | readl(base + MDIO_STATUS), base + MDIO_STATUS);
+
+	/* Write the command. */
+	ctrl = (CONTROL_WRITE |
+		CONTROL_PHYID(mii_id) |
+		CONTROL_PHYREG(regnum) |
+		CONTROL_DATA(value));
+
+	if (regnum & MII_ADDR_C45)
+		ctrl |= CONTROL_CL45;
+
+	writel(ctrl, base + MDIO_CONTROL);
+
+	/* Wait for the mdio_done (status) bit to clear. */
+	while ((readl(base + MDIO_STATUS) & STATUS_DONE) != 0)
+		cpu_relax();
+
+	/* Wait for the mdio_busy (control) bit to clear. */
+	while ((readl(base + MDIO_CONTROL) & CONTROL_BUSY) != 0)
+		cpu_relax();
+
+	return 0;
+}
+
+static int
+axxia_mdio_probe(struct platform_device *pdev)
+{
+	struct device_node     *np = pdev->dev.of_node;
+	struct axxia_mdio_priv *priv = NULL;
+	struct resource        *res;
+	int                     err;
+	u32                     clk_offset = 0x10;
+	u32                     clk_period = 0x2c;
+
+	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+
+	if (!priv)
+		return -ENOMEM;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+	if (!res)
+		return -ENODEV;
+
+	priv->bus = mdiobus_alloc();
+
+	if (!priv->bus)
+		return -ENOMEM;
+
+	priv->bus->name  = "Axxia MDIO",
+	priv->bus->read  = axxia_mdio_read,
+	priv->bus->write = axxia_mdio_write,
+	priv->bus->priv  = priv;
+	snprintf(priv->bus->id, MII_BUS_ID_SIZE, pdev->name);
+	printk("%s:%d - pdev->name=%s\n", __FILE__, __LINE__, pdev->name);
+
+	priv->base = devm_ioremap_resource(&pdev->dev, res);
+
+	if (!priv->base) {
+		dev_err(&pdev->dev, "Failed to map registers\n");
+		err = -ENODEV;
+		goto err_ret;
+	}
+
+	priv->bus->parent = &pdev->dev;
+	dev_set_drvdata(&pdev->dev, priv->bus);
+
+	of_property_read_u32(np, "lsi,mdio-clk-offset", &clk_offset);
+	of_property_read_u32(np, "lsi,mdio-clk-period", &clk_period);
+
+	writel(clk_offset, priv->base + MDIO_CLK_OFFSET);
+	writel(clk_period, priv->base + MDIO_CLK_PERIOD);
+	writel(0, priv->base + MDIO_CONTROL);
+
+	err = of_mdiobus_register(priv->bus, np);
+
+	if (err) {
+		dev_err(&pdev->dev, "Failed to register MDIO bus\n");
+		goto err_ret;
+	}
+
+	return 0;
+
+err_ret:
+
+	if (priv && priv->bus)
+		kfree(priv->bus);
+
+	return err;
+}
+
+static int
+axxia_mdio_remove(struct platform_device *pdev)
+{
+	struct mii_bus *bus = dev_get_drvdata(&pdev->dev);
+
+	mdiobus_unregister(bus);
+	dev_set_drvdata(&pdev->dev, NULL);
+	mdiobus_free(bus);
+
+	return 0;
+}
+
+static struct of_device_id axxia_mdio_match[] = {
+	{ .compatible = "lsi,axm-mdio", },
+	{ .compatible = "intel,axxia-mdio0", },
+	{ .compatible = "intel,axxia-mdio1", },
+	{},
+};
+
+MODULE_DEVICE_TABLE(of, axxia_mdio_match);
+
+static struct platform_driver axxia_mdio_driver = {
+	.driver = {
+		.name           = "axxia-mdio",
+		.owner          = THIS_MODULE,
+		.of_match_table = axxia_mdio_match,
+	},
+	.probe  = axxia_mdio_probe,
+	.remove = axxia_mdio_remove,
+};
+
+module_platform_driver(axxia_mdio_driver);
+
+MODULE_AUTHOR("John Jacques");
+MODULE_DESCRIPTION("Axxia MDIO Bus Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/net/ethernet/lsi/Kconfig b/drivers/net/ethernet/lsi/Kconfig
index 408e643..a78867d 100644
--- a/drivers/net/ethernet/lsi/Kconfig
+++ b/drivers/net/ethernet/lsi/Kconfig
@@ -1,37 +1,3 @@
-config NET_VENDOR_LSI
-	bool "LSI AXM55xx Ethernet support"
-	select MII
-	select PHYLIB
-	default y if ARCH_AXXIA
-	---help---
-	If you have a network interface driver for LSI AXXIA series, 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
-	the questions about LSI devices. If you say Y, you will be
-	asked for your specific card in the following questions.
-
-if NET_VENDOR_LSI
-
-config NET_LSI_MDIO
-	bool "LSI AXM55xx MDIO bus driver"
-	default y
-	---help---
-	  The MDIO controller in AXM55xx devices.
-
-	  If your board uses an external PHY connected to FEMAC, say Y.
-
-config NET_LSI_FEMAC
-	tristate "LSI FEMAC Ethernet controller"
-	select LSI_MDIO
-	default y
-	---help---
-	  Say Y here if you want to use the built-in 10/100 Fast ethernet
-	  controller (FEMAC) on the AXM55xx devices.
-
-endif # NET_VENDOR_LSI
-
-
 config LSI_NET
 	bool "LSI ACP34XX Ethernet support"
 	select MII
diff --git a/drivers/net/ethernet/lsi/Makefile b/drivers/net/ethernet/lsi/Makefile
index 5ebc246..a48a239 100644
--- a/drivers/net/ethernet/lsi/Makefile
+++ b/drivers/net/ethernet/lsi/Makefile
@@ -1,6 +1,4 @@
 # Makefile for the LSI FEMAC network interface.
 
-obj-$(CONFIG_NET_LSI_MDIO) += lsi-mdio.o
-obj-$(CONFIG_NET_LSI_FEMAC) += lsi-femac.o
 obj-$(CONFIG_LSI_NET) += lsi_acp_mdio.o
 obj-$(CONFIG_LSI_NET) += lsi_acp_net.o
diff --git a/drivers/net/ethernet/lsi/lsi-femac.c b/drivers/net/ethernet/lsi/lsi-femac.c
deleted file mode 100644
index 734ea03..0000000
--- a/drivers/net/ethernet/lsi/lsi-femac.c
+++ /dev/null
@@ -1,1198 +0,0 @@
-/* drivers/net/ethernet/lsi/lsi-femac.c
- *
- * Network device driver for LSI Fast-Ethernet controller (FEMAC).
- *
- * Copyright (C) 2013 LSI
- *
- * 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/kernel.h>
-#include <linux/version.h>
-#include <linux/interrupt.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/errno.h>
-#include <linux/platform_device.h>
-#include <linux/of.h>
-#include <linux/of_address.h>
-#include <linux/of_irq.h>
-#include <linux/of_mdio.h>
-#include <linux/dmapool.h>
-
-#define DRVNAME          "lsi-femac"
-#define DESCRIPTOR_GRANULARITY   64
-#define MAX_FRAME_SIZE         1600
-#define NAPI_WEIGHT              64
-
-static unsigned char macaddr[ETH_ALEN];
-module_param_array(macaddr, byte, NULL, S_IRUSR);
-MODULE_PARM_DESC(macaddr, "Ethernet address");
-
-static int rx_num_desc = 128; /* Must be multiple of DESCRIPTOR_GRANULARITY */
-module_param(rx_num_desc, int, S_IRUSR);
-MODULE_PARM_DESC(rx_num_desc, "Number of receive descriptors");
-
-static int tx_num_desc = 128; /* Must be multiple of DESCRIPTOR_GRANULARITY */
-module_param(tx_num_desc, int, S_IRUSR);
-MODULE_PARM_DESC(tx_num_desc, "Number of transmit descriptors");
-
-/**
- * struct dma_desc - Hardware DMA descriptor
- */
-struct dma_desc {
-	__le32 flags;
-#define DMADESC_FILL    (0 << 0)
-#define DMADESC_BLOCK   (1 << 0)
-#define DMADESC_SCATTER (2 << 0)
-#define DMADESC_READ    (0 << 2)
-#define DMADESC_WRITE   (1 << 2)
-#define DMADESC_SOP     (1 << 3)
-#define DMADESC_EOP     (1 << 4)
-#define DMADESC_INTR    (1 << 5)
-#define DMADESC_ERROR   (1 << 6)
-#define DMADESC_SWAP    (1 << 7)
-	__le16 pdu_len;
-	__le16 buf_len;
-	__le32 cookie;
-	__le32 buf_ptr;
-};
-
-/**
- * struct queue_ptr - Holds the state of the RX or TX queue
- * @hw_tail: Tail pointer (written by hardware, pointer to this field is
- *           programmed into the DMAREG_(RX|TX)_TAIL_ADDR). Points to the next
- *           descriptor to be used for reception or transmission.
- * @tail:    Driver tail pointer. Follows hw_tail and points to next descriptor
- *           to be completed.
- * @head:    Head pointer where the drivers puts the new buffers queued for
- *           transmission, and the where fresh RX buffers are added.
- * @size:    Size in bytes of the descriptor ring.
- * @phys:    Physical address of descriptor ring.
- */
-struct queue_ptr {
-	__le32      hw_tail;
-	u32         tail;
-	u32         head;
-	size_t      size;
-	dma_addr_t  phys;
-};
-
-struct dbg_counters {
-	unsigned long tx_interrupt;
-	unsigned long rx_interrupt;
-	unsigned long tx_nodesc;
-	unsigned long tx_nobuf;
-};
-
-#define DBG_INC(_priv, _member) (++(_priv)->counters._member)
-
-/* Device private data */
-struct femac_dev {
-	struct net_device      *ndev;
-	struct device          *dev;
-	struct napi_struct	napi;
-	void __iomem		*base;
-	/* MAC address (from parameter, device-tree or randomized) */
-	unsigned char		mac_addr[ETH_ALEN] __aligned(2);
-	/* PHY */
-	struct phy_device	*phy_dev;
-	int			link;
-	int			speed;
-	int			duplex;
-	/* RX/TX ring */
-	size_t                  rx_ring_size;
-	dma_addr_t		rx_ring_phys;
-	unsigned		rx_num_desc;
-	struct dma_desc		*rx_ring;
-	struct queue_ptr       *rxq;
-	/* TX ring */
-	size_t                  tx_ring_size;
-	dma_addr_t		tx_ring_phys;
-	unsigned		tx_num_desc;
-	struct dma_desc		*tx_ring;
-	struct queue_ptr       *txq;
-	/* Lock protecting the TX ring */
-	spinlock_t		lock;
-	/* DMA pool for tx buffers */
-	struct dma_pool        *tx_pool;
-	/* Debug counters */
-	struct dbg_counters     counters;
-};
-
-#define napi_to_priv(_napi) container_of(napi, struct femac_dev, napi)
-
-/* FEMAC Registers
- */
-
-/* SMII Status */
-#define RXREG_SMII_STATUS		0x0010
-#define   RX_SMII_STATUS_SPEED		0x01
-#define   RX_SMII_STATUS_DUPLEX		0x02
-#define   RX_SMII_STATUS_LINK		0x04
-#define   RX_SMII_STATUS_JABBER		0x08
-#define   RX_SMII_STATUS_FCD		0x10 /* False Carrier Detect */
-/* Receive Configuration */
-#define RXREG_CONF			0x004c
-#define   RX_CONF_ENABLE		0x0001
-#define   RX_CONF_PAP			0x0002 /* Pass Any Packet */
-#define   RX_CONF_JUMBO9K		0x0008
-#define   RX_CONF_STRIPCRC		0x0010
-#define   RX_CONF_AMT			0x0020 /* Accept All MAC Types */
-#define   RX_CONF_AFC			0x0040 /* Accept Flow Control */
-#define   RX_CONF_VLAN			0x0200 /* Enable VLAN */
-#define   RX_CONF_SPEED			0x0800 /* RX MAC Speed, 0=10M, 1=100M */
-#define   RX_CONF_DUPLEX		0x1000 /* 1=Full-duplex */
-#define   RX_CONF_LINK			0x2000 /* 1=Enable */
-#define   RX_CONF_RXFCE			0x4000 /* RX flow-control */
-#define   RX_CONF_TXFCE			0x8000 /* TX flow-control */
-/* Receive Statistics */
-#define RXREG_STAT_OVERFLOW		0x0278
-#define RXREG_STAT_UNDERSIZE		0x00280
-#define RXREG_STAT_OVERSIZE		0x002b8
-#define RXREG_STAT_PACKET_OK		0x002c0
-#define RXREG_STAT_CRC_ERR		0x002c8
-#define RXREG_STAT_MULTICAST		0x002d0
-#define RXREG_STAT_BROADCAST		0x002d8
-#define RXREG_STAT_MACTYPE		0x002e0
-#define RXREG_STAT_ALIGN_ERR		0x002e8
-#define RXREG_STAT_BYTES_LO		0x002f0
-#define RXREG_STAT_BYTES_HI		0x002f8
-/* Receive Ethernet Mode */
-#define RXREG_MODE			0x0800
-#define   RX_MODE_ETHERNET_ENABLE	0x01
-/* Receive Soft Reset */
-#define RXREG_SOFT_RESET		0x0808
-#define   RX_SOFT_RESET_MAC_0		0x01
-/* Transmit Watermark */
-#define TXREG_WATERMARK			0x1018
-#define   TX_WATERMARK_DTPA_ASSERT	0x8000
-#define   TX_WATERMARK_DTPA_DISABLE	0x4000
-#define   TX_WATERMARK_DTPA_HIGH(_x)	(((_x) & 0x7f) << 7)
-#define   TX_WATERMARK_DTPA_LOW(_x)	(((_x) & 0x7f) << 0)
-/* Swap Source Address Registers */
-#define TXREG_SOURCE_ADDRESS_2		0x1020
-#define TXREG_SOURCE_ADDRESS_1		0x1024
-#define TXREG_SOURCE_ADDRESS_0		0x1028
-/* Transmit Extended Configuration */
-#define TXREG_EXTENDED_CONF		0x1030
-#define   TX_EXTCONF_TXCOLL_WATERMARK	0xe000
-#define   TX_EXTCONF_EX_DEFFERED_DROP	0x0200
-#define   TX_EXTCONF_JUMBO9K		0x0100
-#define   TX_EXTCONF_LATE_COLL_WDW	0x00ff
-/* Transmit Configuration */
-#define TXREG_CONF			0x1050
-#define   TX_CONF_ENABLE_SWAP_SA	0x8000
-#define   TX_CONF_LINK			0x2000
-#define   TX_CONF_DUPLEX		0x1000
-#define   TX_CONF_SPEED			0x0800
-#define   TX_CONF_XBK_RST_RX_NTX	0x0600
-#define   TX_CONF_IFG_MASK		0x01f0
-#define   TX_CONF_IFG(_x)		(((_x) & 0x1f) << 4)
-#define   TX_CONF_APP_CRC_ENABLE	0x0004
-#define   TX_CONF_PAD_ENABLE		0x0002
-#define   TX_CONF_ENABLE		0x0001
-/* Transmit Statistics */
-#define TXREG_STAT_UNDERRUN		0x1300
-#define TXREG_STAT_DEFERRED		0x1308
-#define TXREG_STAT_PAUSE		0x1310
-#define TXREG_STAT_PACKET_OK		0x1318
-#define TXREG_STAT_UNDERSIZE		0x1350
-#define TXREG_STAT_BYTES_LO		0x1358
-#define TXREG_STAT_BYTES_HI		0x1360
-#define TXREG_STAT_LATECOLL		0x1368
-#define TXREG_STAT_EXCECOLL		0x1370
-#define TXREG_STAT_EXCEDEFERRED		0x1378
-#define TXREG_STAT_COLLISION_LIMIT	0x1380
-/* Transmit Mode */
-#define TXREG_MODE			0x1800
-#define   TX_MODE_ETHERNET_ENABLE	0x01
-/* Transmit Soft Reset */
-#define TXREG_SOFT_RESET		0x1808
-#define   TX_SOFT_RESET_MAC_0		0x01
-/* DMA Control */
-#define DMAREG_CONTROL			0x2000
-#define   DMA_CTRL_RST			0x80000000
-#define   DMA_CTRL_ERR_CLEAR		0x40000000
-#define   DMA_CTRL_ENABLE		0x00010000
-/* DMA Enable */
-#define DMAREG_ENABLE			0x2008
-#define   DMA_TX_ENABLE			0x00010000
-#define   DMA_RX_ENABLE			0x00020000
-/* DMA Interrupt Enable/Status */
-#define DMAREG_INT_STATUS		0x2018
-#define DMAREG_INT_ENABLE		0x201c
-#define   DMA_INT_TX			0x01
-#define   DMA_INT_RX			0x02
-/* DMA RX/TX Queue Base/Size */
-#define DMAREG_RX_QUEUE_BASE		0x2030
-#define DMAREG_RX_QUEUE_SIZE		0x2034
-#define DMAREG_TX_QUEUE_BASE		0x2038
-#define DMAREG_TX_QUEUE_SIZE		0x203c
-/* DMA Tail Pointer Address */
-#define DMAREG_RX_TAIL_ADDR		0x2048
-#define DMAREG_TX_TAIL_ADDR		0x204c
-/* DMA Head/Tail Pointers */
-#define DMAREG_RX_HEAD			0x2050
-#define DMAREG_RX_TAIL			0x2054
-#define DMAREG_TX_HEAD			0x2058
-#define DMAREG_TX_TAIL			0x205c
-#define   DMA_POINTER_GEN		0x100000
-#define   DMA_POINTER_MASK		0x0fffff
-#define DMAREG_DTPA_LOW			0x2060
-#define   DTPA_LOW_MARK(_x)		(((_x) & 0x1ff) << 0)
-#define   DTPA_BP_COUNT(_x)		(((_x) & 0xff) << 16)
-#define DMAREG_DTPA_HIGH		0x2064
-#define   DTPA_HIGH_MARK(_x)		(((_x) & 0x1ff) << 0)
-#define   DTPA_START_THRES(_x)		(((_x) & 0x3) << 16)
-
-#define dmaptr_idx(_val) (((_val) & DMA_POINTER_MASK) / sizeof(struct dma_desc))
-#define dmaptr_gen(_val) (!!((_val) & DMA_POINTER_GEN))
-
-/* RX/TX-ring
- *
- * tail - Oldest descriptor, i.e. the next descriptor to be processed by RX/TX
- * interrupt. This pointer is only used by the driver (no corresponding
- * hardware register). The interrupt handler will process descriptors from tail
- * to hw_tail.
- *
- * hw_tail - Next descriptor to be processed by hardware. The memory location
- * is updated by the hardware when it switches descriptor (via DMA). A copy of
- * this value is also available in the DMAREG_[RX|TX]_TAIL register.
- *
- * head - Newest descriptor. This is where the driver adds new descriptors
- * (either fresh rx buffers or tx buffers queued for transmission) and the
- * pointer is updated in hardware via the DMAREG_[RX|TX]_HEAD register. The
- * hardware will process descriptors from hw_tail to head. When hw_tail ==
- * head, the ring is empty.
- *
- *		tail	hw_tail		head
- *		|	|		|
- *		V	V		V
- *      +-----+ +-----+ +-----+ +-----+ +-----+ +-----+
- *      |     | |     | |     | |     | |     | |     |
- *      +-----+ +-----+ +-----+ +-----+ +-----+ +-----+
- *
- */
-
-/**
- * queue_get_head - Return next DMA descriptor from head of queue.
- */
-static inline struct dma_desc *
-queue_get_head(struct dma_desc *ring, const struct queue_ptr *q)
-{
-	if ((q->head ^ q->tail) == DMA_POINTER_GEN)
-		return NULL;
-	return &ring[dmaptr_idx(q->head)];
-}
-
-/**
- * queue_get_tail - Return next DMA descriptor from tail of queue.
- */
-static inline struct dma_desc *
-queue_get_tail(struct dma_desc *ring, const struct queue_ptr *q)
-{
-	if (q->tail == le32_to_cpu(q->hw_tail))
-		return NULL;
-	return &ring[dmaptr_idx(q->tail)];
-}
-
-/**
- * inc_pointer - Helper function to increment a DMA pointer. The counter is in
- * the lower bits and is incremented modulo the size of the ring. The bit
- * DMA_POINTER_GEN is toggled when the counter wraps.
- */
-static inline u32
-inc_pointer(u32 ptr, u32 size)
-{
-	u32 newptr = (ptr & DMA_POINTER_MASK) + sizeof(struct dma_desc);
-
-	/* When counter wraps (on size), reset and toggle generation bit.
-	 * Otherwise preserve generation bit
-	 */
-	if (newptr >= size)
-		newptr = (ptr & DMA_POINTER_GEN) ^ DMA_POINTER_GEN;
-	else
-		newptr |= ptr & DMA_POINTER_GEN;
-
-	return newptr;
-}
-
-static inline u32
-queue_inc_head(struct queue_ptr *q)
-{
-	q->head = inc_pointer(q->head, q->size);
-	return q->head;
-}
-
-static inline u32
-queue_inc_tail(struct queue_ptr *q)
-{
-	q->tail = inc_pointer(q->tail, q->size);
-	return q->tail;
-}
-
-static inline void
-pr_queue(const char *tag, const struct queue_ptr *q)
-{
-	pr_debug("%s tail=%d.%d hw_tail=%d.%d head=%d.%d\n",
-		 tag,
-		 dmaptr_gen(q->tail), dmaptr_idx(q->tail),
-		 dmaptr_gen(q->hw_tail), dmaptr_idx(q->hw_tail),
-		 dmaptr_gen(q->head), dmaptr_idx(q->head));
-}
-
-/**
- * clear_statistics - Counters are cleared on read.
- */
-static void
-clear_statistics(const struct femac_dev *priv)
-{
-	int waste;
-
-	waste = readl(priv->base + RXREG_STAT_OVERFLOW);
-	waste = readl(priv->base + RXREG_STAT_UNDERSIZE);
-	waste = readl(priv->base + RXREG_STAT_OVERSIZE);
-	waste = readl(priv->base + RXREG_STAT_PACKET_OK);
-	waste = readl(priv->base + RXREG_STAT_CRC_ERR);
-	waste = readl(priv->base + RXREG_STAT_MULTICAST);
-	waste = readl(priv->base + RXREG_STAT_BROADCAST);
-	waste = readl(priv->base + RXREG_STAT_MACTYPE);
-	waste = readl(priv->base + RXREG_STAT_ALIGN_ERR);
-	waste = readl(priv->base + RXREG_STAT_BYTES_LO);
-	waste = readl(priv->base + RXREG_STAT_BYTES_HI);
-
-	waste = readl(priv->base + TXREG_STAT_UNDERRUN);
-	waste = readl(priv->base + TXREG_STAT_DEFERRED);
-	waste = readl(priv->base + TXREG_STAT_PAUSE);
-	waste = readl(priv->base + TXREG_STAT_PACKET_OK);
-	waste = readl(priv->base + TXREG_STAT_UNDERSIZE);
-	waste = readl(priv->base + TXREG_STAT_BYTES_LO);
-	waste = readl(priv->base + TXREG_STAT_BYTES_HI);
-	waste = readl(priv->base + TXREG_STAT_LATECOLL);
-	waste = readl(priv->base + TXREG_STAT_EXCECOLL);
-	waste = readl(priv->base + TXREG_STAT_EXCEDEFERRED);
-	waste = readl(priv->base + TXREG_STAT_COLLISION_LIMIT);
-}
-
-static int
-enable_rx_tx(struct net_device *device)
-{
-	struct femac_dev *priv = netdev_priv(device);
-	unsigned long rxcfg;
-	unsigned long txcfg;
-
-	rxcfg = (RX_CONF_STRIPCRC |
-		 RX_CONF_RXFCE    |
-		 RX_CONF_TXFCE);
-
-	txcfg = (TX_CONF_ENABLE_SWAP_SA |
-		 TX_CONF_APP_CRC_ENABLE |
-		 TX_CONF_IFG(0xf)       |
-		 TX_CONF_PAD_ENABLE);
-
-	/* Setup the receive and transmit configuration registers according to
-	 * status from PHY.
-	 */
-	if (priv->phy_dev->speed == SPEED_100) {
-		rxcfg |= RX_CONF_SPEED;
-		txcfg |= TX_CONF_SPEED;
-	}
-	if (priv->phy_dev->duplex == DUPLEX_FULL) {
-		rxcfg |= RX_CONF_DUPLEX;
-		txcfg |= TX_CONF_DUPLEX;
-	}
-	if (priv->phy_dev->link) {
-		rxcfg |= (RX_CONF_ENABLE | RX_CONF_LINK);
-		txcfg |= (TX_CONF_LINK | TX_CONF_ENABLE);
-	}
-
-	writel(rxcfg, priv->base + RXREG_CONF);
-	writel(txcfg, priv->base + TXREG_CONF);
-
-	if (priv->phy_dev->link) {
-		netif_start_queue(device);
-		netif_carrier_on(device);
-	} else {
-		netif_carrier_off(device);
-		netif_stop_queue(device);
-	}
-
-	return 0;
-}
-
-static void
-disable_rx_tx(struct femac_dev *priv)
-{
-	unsigned long txcfg;
-	unsigned long rxcfg;
-
-	rxcfg = readl(priv->base + RXREG_CONF);
-	rxcfg &= ~RX_CONF_ENABLE;
-	writel(rxcfg, priv->base + RXREG_CONF);
-
-	txcfg = readl(priv->base + TXREG_CONF);
-	txcfg &= ~TX_CONF_ENABLE;
-	writel(txcfg, priv->base + TXREG_CONF);
-}
-
-static ssize_t
-femac_show_counters(struct device *dev,
-		    struct device_attribute *attr,
-		    char *buf)
-{
-	struct net_device *ndev = container_of(dev, struct net_device, dev);
-	struct femac_dev *priv = netdev_priv(ndev);
-	ssize_t n = 0;
-
-	n += snprintf(&buf[n], PAGE_SIZE,
-			"tx_interrupt: %lu\n"
-			"rx_interrupt: %lu\n"
-			"tx_nodesc: %lu\n"
-			"tx_nobuf: %lu\n",
-			priv->counters.tx_interrupt,
-			priv->counters.rx_interrupt,
-			priv->counters.tx_nodesc,
-			priv->counters.tx_nobuf);
-
-	n += snprintf(&buf[n], PAGE_SIZE,
-		      "rx_queue: %u.%u / %u.%u / %u.%u\n",
-		      dmaptr_gen(priv->rxq->tail),
-		      dmaptr_idx(priv->rxq->tail),
-		      dmaptr_gen(le32_to_cpu(priv->rxq->hw_tail)),
-		      dmaptr_idx(le32_to_cpu(priv->rxq->hw_tail)),
-		      dmaptr_gen(priv->rxq->head),
-		      dmaptr_idx(priv->rxq->head));
-
-	n += snprintf(&buf[n], PAGE_SIZE,
-		      "tx_queue: %u.%u / %u.%u / %u.%u\n",
-		      dmaptr_gen(priv->txq->tail),
-		      dmaptr_idx(priv->txq->tail),
-		      dmaptr_gen(le32_to_cpu(priv->txq->hw_tail)),
-		      dmaptr_idx(le32_to_cpu(priv->txq->hw_tail)),
-		      dmaptr_gen(priv->txq->head),
-		      dmaptr_idx(priv->txq->head));
-
-	return n;
-}
-static DEVICE_ATTR(counters, S_IRUSR, femac_show_counters, NULL);
-
-static void
-set_macaddr(struct femac_dev *priv, u8 *addr)
-{
-	writel((addr[4] << 8) | addr[5], priv->base + TXREG_SOURCE_ADDRESS_2);
-	writel((addr[2] << 8) | addr[3], priv->base + TXREG_SOURCE_ADDRESS_1);
-	writel((addr[0] << 8) | addr[1], priv->base + TXREG_SOURCE_ADDRESS_0);
-}
-
-/**
- * femac_adjust_link - Called by the PHY driver to update MAC with changes in
- * link state.
- */
-static void
-femac_adjust_link(struct net_device *ndev)
-{
-	struct femac_dev *priv = netdev_priv(ndev);
-	struct phy_device *phy_dev = priv->phy_dev;
-	int status_change = 0;
-
-	/* Link on or off change */
-	if (phy_dev->link != priv->link) {
-		priv->link = phy_dev->link;
-		if (phy_dev->link)
-			enable_rx_tx(ndev);
-		else
-			disable_rx_tx(priv);
-		status_change = 1;
-	}
-
-	if (status_change)
-		phy_print_status(phy_dev);
-}
-
-/**
- * alloc_rx_buf - Initialize a dma descritor with a new rx buffer.
- */
-static int
-alloc_rx_buf(struct femac_dev *priv, struct dma_desc *d)
-{
-	struct sk_buff *skb;
-	dma_addr_t dma_addr;
-
-	skb = netdev_alloc_skb(priv->ndev, MAX_FRAME_SIZE);
-	if (!skb)
-		return -ENOMEM;
-	dma_addr = dma_map_single(priv->dev, skb->data,
-				  MAX_FRAME_SIZE, DMA_FROM_DEVICE);
-	if (dma_mapping_error(priv->dev, dma_addr)) {
-		dev_kfree_skb_any(skb);
-		return -ENOMEM;
-	}
-	d->flags   = cpu_to_le32(DMADESC_WRITE | DMADESC_INTR);
-	d->buf_len = cpu_to_le16(MAX_FRAME_SIZE);
-	d->pdu_len = d->buf_len;
-	d->buf_ptr = cpu_to_le32((u32)dma_addr);
-	d->cookie  = (u32)skb;
-	return 0;
-}
-
-static void
-femac_tx_complete(struct femac_dev *priv)
-{
-	struct dma_desc *desc;
-	int complete = 0;
-	unsigned long flags;
-
-	spin_lock_irqsave(&priv->lock, flags);
-	while ((desc = queue_get_tail(priv->tx_ring, priv->txq)) != NULL) {
-		void *buf = (void *)desc->cookie;
-
-		dma_pool_free(priv->tx_pool, buf, le32_to_cpu(desc->buf_ptr));
-		queue_inc_tail(priv->txq);
-		pr_queue("femac: TX complete", priv->txq);
-		++complete;
-	}
-	spin_unlock_irqrestore(&priv->lock, flags);
-
-	if (complete)
-		netif_wake_queue(priv->ndev);
-}
-
-static inline unsigned compare_ether_addr(const u8 *addr1, const u8 *addr2)
-{
-	const u16 *a = (const u16 *)addr1;
-	const u16 *b = (const u16 *)addr2;
-
-	BUILD_BUG_ON(ETH_ALEN != 6);
-	return ((a[0] ^ b[0]) | (a[1] ^ b[1]) | (a[2] ^ b[2])) != 0;
-}
-
-static int
-femac_rx_packets(struct femac_dev *priv, int max)
-{
-	struct sk_buff *skb;
-	struct dma_desc *desc;
-	int num_rx = 0;
-
-	while (num_rx < max) {
-		desc = queue_get_tail(priv->rx_ring, priv->rxq);
-		if (!desc)
-			break;
-		queue_inc_tail(priv->rxq);
-
-		pr_debug(DRVNAME " (RX) desc=%p flags=%#x len=%u/%u buf=%#x cookie=%#x\n",
-			 desc,
-			 le32_to_cpu(desc->flags),
-			 le16_to_cpu(desc->buf_len),
-			 le16_to_cpu(desc->pdu_len),
-			 le32_to_cpu(desc->buf_ptr),
-			 desc->cookie);
-
-		dma_unmap_single(priv->dev, le32_to_cpu(desc->buf_ptr),
-				 MAX_FRAME_SIZE, DMA_FROM_DEVICE);
-		skb = (struct sk_buff *)desc->cookie;
-
-		if (!(le32_to_cpu(desc->flags) & DMADESC_ERROR)) {
-			struct ethhdr *ethhdr = (struct ethhdr *)skb->data;
-
-			if (is_multicast_ether_addr(&ethhdr->h_dest[0]) ||
-			    is_broadcast_ether_addr(&ethhdr->h_dest[0]) ||
-			    compare_ether_addr(&ethhdr->h_dest[0],
-					       &priv->mac_addr[0]) == 0) {
-				/* No error, pass sk_buff to upper layer */
-				skb_put(skb, le16_to_cpu(desc->buf_len));
-				skb->protocol = eth_type_trans(skb, priv->ndev);
-				netif_receive_skb(skb);
-			} else {
-				dev_kfree_skb_any(skb);
-			}
-		} else {
-			struct net_device_stats *s = &priv->ndev->stats;
-
-			/* Error, free skb and update counters */
-			dev_kfree_skb_any(skb);
-
-			s->rx_fifo_errors +=
-				readl(priv->base + RXREG_STAT_OVERFLOW);
-			s->rx_crc_errors +=
-				readl(priv->base + RXREG_STAT_CRC_ERR);
-			s->rx_frame_errors +=
-				readl(priv->base + RXREG_STAT_ALIGN_ERR);
-		}
-
-		/* Add new RX buffers */
-		desc = queue_get_head(priv->rx_ring, priv->rxq);
-		if (alloc_rx_buf(priv, desc)) {
-			dev_warn(priv->dev, "femac: Failed to alloc RX buffer\n");
-			break;
-		}
-		/* Writes to desc must complete before head is advanced */
-		wmb();
-		writel(queue_inc_head(priv->rxq), priv->base + DMAREG_RX_HEAD);
-
-		++num_rx;
-	}
-
-	return num_rx;
-}
-
-static irqreturn_t
-femac_isr(int irq, void *device_id)
-{
-	struct femac_dev *priv = (struct femac_dev *)device_id;
-	u32 int_status, int_enable;
-
-	/* Read interrupt status */
-	int_status = readl(priv->base + DMAREG_INT_STATUS);
-	int_enable = readl(priv->base + DMAREG_INT_ENABLE);
-	int_status &= int_enable;
-
-	if ((int_status & (DMA_INT_TX | DMA_INT_RX)) == 0)
-		return IRQ_NONE;
-
-	if (int_status & DMA_INT_TX)
-		DBG_INC(priv, tx_interrupt);
-	else
-		DBG_INC(priv, rx_interrupt);
-
-	if (napi_schedule_prep(&priv->napi)) {
-		/* Disable interrupts */
-		writel(0, priv->base + DMAREG_INT_ENABLE);
-		__napi_schedule(&priv->napi);
-	} else {
-		/* Clear interrupt status */
-		writel(0, priv->base + DMAREG_INT_STATUS);
-	}
-
-	return IRQ_HANDLED;
-}
-
-static int
-femac_poll(struct napi_struct *napi, int budget)
-{
-	struct femac_dev *priv = napi_to_priv(napi);
-	int rcvd;
-
-	/* Clear interrupt status */
-	writel(0, priv->base + DMAREG_INT_STATUS);
-
-	WARN_ON(priv->rxq->head != readl(priv->base + DMAREG_RX_HEAD));
-
-	/* Clean TX ring */
-	femac_tx_complete(priv);
-
-	/* Process rx_ring */
-	rcvd = femac_rx_packets(priv, budget);
-	if (rcvd < budget) {
-		/* Exit polling mode */
-		napi_complete(napi);
-		/* Re-enable receive interrupts */
-		writel(DMA_INT_RX | DMA_INT_TX, priv->base + DMAREG_INT_ENABLE);
-	}
-
-	return rcvd;
-}
-
-/**
- * femac_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
-femac_open(struct net_device *ndev)
-{
-	struct femac_dev *priv = netdev_priv(ndev);
-	struct device_node *phy_np;
-	struct phy_device *phy_dev;
-	int rc;
-
-	phy_np = of_parse_phandle(priv->dev->of_node, "phy-handle", 0);
-	if (!phy_np) {
-		dev_err(&ndev->dev, "Missing phy-handle\n");
-		return -ENODEV;
-	}
-
-	phy_dev = of_phy_connect(ndev, phy_np, femac_adjust_link,
-				 0, PHY_INTERFACE_MODE_MII);
-	if (IS_ERR_OR_NULL(phy_dev)) {
-		dev_err(&ndev->dev, "Could not attach to PHY\n");
-		return -ENODEV;
-	}
-
-	phy_dev->advertising = phy_dev->supported;
-	priv->link = 0;
-	priv->phy_dev = phy_dev;
-
-	phy_attached_info(phy_dev);
-
-	napi_enable(&priv->napi);
-
-	/* Install the interrupt handlers. */
-	rc = request_irq(ndev->irq, femac_isr, 0, DRVNAME, priv);
-	if (rc) {
-		dev_err(&ndev->dev, "Request IRQ%d failed\n", ndev->irq);
-		return rc;
-	}
-
-	/* enable interrupts */
-	writel(DMA_INT_RX | DMA_INT_TX, priv->base + DMAREG_INT_ENABLE);
-
-	phy_start(priv->phy_dev);
-
-	return 0;
-}
-
-/**
- * femac_stop - Stops the interface.
- *
- * The interface is stopped when it is brought down; operations performed at
- * open time should be reversed.
- */
-static int
-femac_stop(struct net_device *device)
-{
-	struct femac_dev *priv = netdev_priv(device);
-
-	/* Indicate to the OS that no more packets should be sent.  */
-	netif_stop_queue(device);
-
-	phy_disconnect(priv->phy_dev);
-
-	/* Stop the receiver and transmitter.  */
-	disable_rx_tx(priv);
-
-	/* Disable NAPI. */
-	napi_disable(&priv->napi);
-
-	/* Free the interrupts.  */
-	free_irq(device->irq, priv);
-
-	return 0;
-}
-
-/**
- * femac_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.
- *
- * Since the FEMAC DMA engine needs 32-bit aligned data, we allocate a new TX
- * buffer from a dma_pool and copy the payload before passing it on to the
- * hardware.
- */
-static int
-femac_hard_start_xmit(struct sk_buff *skb, struct net_device *ndev)
-{
-	struct femac_dev *priv = netdev_priv(ndev);
-	struct dma_desc *desc;
-	void *tx_buf;
-	dma_addr_t dma_addr;
-	unsigned long flags;
-	int length;
-
-	if (skb->len > MAX_FRAME_SIZE) {
-		++ndev->stats.tx_dropped;
-		goto drop;
-	}
-
-	tx_buf = dma_pool_alloc(priv->tx_pool, GFP_ATOMIC, &dma_addr);
-	if (!tx_buf) {
-		netif_stop_queue(ndev);
-		DBG_INC(priv, tx_nobuf);
-		++ndev->stats.tx_dropped;
-		dev_err_ratelimited(&ndev->dev, "No TX buffers!\n");
-		goto drop;
-	}
-
-	length = skb->len < ETH_ZLEN ? ETH_ZLEN : skb->len;
-	skb_copy_from_linear_data(skb, tx_buf, length);
-
-	spin_lock_irqsave(&priv->lock, flags);
-
-	desc = queue_get_head(priv->tx_ring, priv->txq);
-	pr_debug(DRVNAME " (TX) desc=%p len=%u\n", desc, length);
-	if (!desc) {
-		DBG_INC(priv, tx_nodesc);
-		spin_unlock_irqrestore(&priv->lock, flags);
-		dma_pool_free(priv->tx_pool, tx_buf, dma_addr);
-		netif_stop_queue(ndev);
-		dev_kfree_skb_any(skb);
-		++ndev->stats.tx_dropped;
-		dev_err_ratelimited(&ndev->dev, "No TX descriptors!\n");
-		return NETDEV_TX_BUSY;
-	}
-
-	desc->flags = cpu_to_le32(DMADESC_WRITE | DMADESC_INTR |
-				  DMADESC_SOP | DMADESC_EOP);
-	desc->buf_ptr = cpu_to_le32((u32)dma_addr);
-	desc->buf_len = cpu_to_le16(length);
-	desc->pdu_len = desc->buf_len;
-	desc->cookie  = (u32)tx_buf;
-	/* Make sure writes to descriptor completed before starting TX */
-	wmb();
-	WARN_ON(priv->txq->head != readl(priv->base + DMAREG_TX_HEAD));
-	writel(queue_inc_head(priv->txq), priv->base + DMAREG_TX_HEAD);
-	netif_trans_update(ndev);	/* prevent tx timeout */
-	pr_queue("XMIT", priv->txq);
-
-	spin_unlock_irqrestore(&priv->lock, flags);
-
-drop:
-	dev_kfree_skb_any(skb);
-	return NETDEV_TX_OK;
-}
-
-/**
- * femac_get_stats - Read hardware counters.
- *
- * Whenever an application needs to get statistics for the interface, this
- * method is called.
- */
-static struct net_device_stats *
-femac_get_stats(struct net_device *ndev)
-{
-	struct femac_dev *priv = netdev_priv(ndev);
-	struct net_device_stats	*s = &ndev->stats;
-
-	s->rx_packets       += readl(priv->base + RXREG_STAT_PACKET_OK);
-	s->tx_packets       += readl(priv->base + TXREG_STAT_PACKET_OK);
-	s->rx_bytes         += readl(priv->base + RXREG_STAT_BYTES_LO);
-	s->tx_bytes         += readl(priv->base + TXREG_STAT_BYTES_LO);
-	s->multicast        += readl(priv->base + RXREG_STAT_MULTICAST);
-	s->multicast        += readl(priv->base + RXREG_STAT_BROADCAST);
-	s->collisions       += readl(priv->base + TXREG_STAT_LATECOLL);
-	s->collisions       += readl(priv->base + TXREG_STAT_EXCECOLL);
-	s->rx_length_errors += readl(priv->base + RXREG_STAT_UNDERSIZE);
-	s->rx_length_errors += readl(priv->base + RXREG_STAT_OVERSIZE);
-	s->tx_fifo_errors   += readl(priv->base + TXREG_STAT_UNDERRUN);
-
-	s->rx_errors =
-		(s->rx_length_errors +
-		 s->rx_fifo_errors +
-		 s->rx_crc_errors +
-		 s->rx_frame_errors);
-
-	s->tx_errors =
-		(s->tx_fifo_errors +
-		 s->tx_aborted_errors);
-
-	return &ndev->stats;
-}
-
-/**
- * femac_set_mac_address
- */
-static int
-femac_set_mac_address(struct net_device *ndev, void *data)
-{
-	struct femac_dev *priv = netdev_priv(ndev);
-	struct sockaddr *addr = data;
-
-	if (netif_running(ndev))
-		return -EBUSY;
-
-	memcpy(ndev->dev_addr, addr->sa_data, ndev->addr_len);
-	set_macaddr(priv, addr->sa_data);
-
-	return 0;
-}
-
-static const struct net_device_ops femac_netdev_ops = {
-	.ndo_open            = femac_open,
-	.ndo_stop            = femac_stop,
-	.ndo_get_stats       = femac_get_stats,
-	.ndo_set_mac_address = femac_set_mac_address,
-	.ndo_start_xmit      = femac_hard_start_xmit,
-};
-
-/* Ethtool operations */
-
-static int
-femac_get_settings(struct net_device *ndev, struct ethtool_cmd *cmd)
-{
-	struct femac_dev *priv = netdev_priv(ndev);
-
-	if (!priv->phy_dev)
-		return -ENODEV;
-
-	return phy_ethtool_gset(priv->phy_dev, cmd);
-}
-
-static int
-femac_set_settings(struct net_device *ndev, struct ethtool_cmd *cmd)
-{
-	struct femac_dev *priv = netdev_priv(ndev);
-
-	if (!priv->phy_dev)
-		return -ENODEV;
-
-	return phy_ethtool_sset(priv->phy_dev, cmd);
-}
-
-static const struct ethtool_ops femac_ethtool_ops = {
-	.get_settings = femac_get_settings,
-	.set_settings = femac_set_settings
-};
-
-/**
- * femac_init - Allocate memory and initialize the hardware
- */
-static int
-femac_init(struct net_device *ndev)
-{
-	struct femac_dev *priv = netdev_priv(ndev);
-	dma_addr_t dma_phys;
-	int i;
-
-	/* Reset the MAC */
-	writel(0x80000000, priv->base + DMAREG_CONTROL);
-
-	/* The number of rx and tx descriptors must be an even multiple of
-	 * DESCRIPTOR_GRANULARITY.
-	 */
-	priv->rx_num_desc = ALIGN(rx_num_desc, DESCRIPTOR_GRANULARITY);
-	priv->tx_num_desc = ALIGN(tx_num_desc, DESCRIPTOR_GRANULARITY);
-
-	/* This needs to be set to something sane for dma_alloc_coherent() */
-	ndev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
-	ndev->dev.dma_mask = &ndev->dev.coherent_dma_mask;
-
-	priv->tx_pool = dma_pool_create("femac_dma", priv->dev,
-					   MAX_FRAME_SIZE, 4, 0);
-	if (!priv->tx_pool) {
-		dev_err(&ndev->dev, "Failed to allocate DMA buffer pool\n");
-		return -ENOMEM;
-	}
-
-	spin_lock_init(&priv->lock);
-
-	/* Take MAC out of reset */
-	writel(0x0, priv->base + RXREG_SOFT_RESET);
-	writel(RX_MODE_ETHERNET_ENABLE, priv->base + RXREG_MODE);
-	writel(0x0, priv->base + TXREG_SOFT_RESET);
-	writel(TX_MODE_ETHERNET_ENABLE, priv->base + TXREG_MODE);
-	writel(TX_WATERMARK_DTPA_HIGH(96) | TX_WATERMARK_DTPA_LOW(10),
-	       priv->base + TXREG_WATERMARK);
-
-	writel(DMA_CTRL_ERR_CLEAR | DMA_CTRL_ENABLE,
-	       priv->base + DMAREG_CONTROL);
-	writel(DMA_TX_ENABLE | DMA_RX_ENABLE, priv->base + DMAREG_ENABLE);
-	writel(DTPA_BP_COUNT(0x28) | DTPA_LOW_MARK(0x44),
-	       priv->base + DMAREG_DTPA_LOW);
-	writel(DTPA_HIGH_MARK(0xc0) | DTPA_START_THRES(0),
-	       priv->base + DMAREG_DTPA_HIGH);
-
-	set_macaddr(priv, ndev->dev_addr);
-
-	/* Initialize RX queue */
-	priv->rx_ring_size = priv->rx_num_desc * sizeof(struct dma_desc);
-	priv->rx_ring = dma_alloc_coherent(&ndev->dev, priv->rx_ring_size,
-					   &priv->rx_ring_phys, GFP_KERNEL);
-	priv->rxq = dma_alloc_coherent(&ndev->dev, 2 * sizeof(struct queue_ptr),
-				       &dma_phys, GFP_KERNEL);
-	priv->rxq->phys = dma_phys;
-	writel(priv->rx_ring_phys, priv->base + DMAREG_RX_QUEUE_BASE);
-	writel(priv->rx_ring_size / 1024, priv->base + DMAREG_RX_QUEUE_SIZE);
-	writel(priv->rxq->phys, priv->base + DMAREG_RX_TAIL_ADDR);
-	priv->rxq->size = priv->rx_ring_size;
-	priv->rxq->hw_tail = readl(priv->base + DMAREG_RX_TAIL);
-	priv->rxq->tail    = priv->rxq->hw_tail;
-	priv->rxq->head    = priv->rxq->hw_tail;
-	writel(priv->rxq->head, priv->base + DMAREG_RX_HEAD);
-	pr_debug("femac: rx_ring %p rxq %p\n", priv->rx_ring, priv->rxq);
-
-	/* Initialize the descriptors */
-	for (i = 0; i < priv->rx_num_desc - 1; ++i) {
-		struct dma_desc *desc  = &priv->rx_ring[i];
-
-		alloc_rx_buf(priv, desc);
-		writel(queue_inc_head(priv->rxq), priv->base + DMAREG_RX_HEAD);
-	}
-
-	/* Initialize TX queue */
-	priv->tx_ring_size = priv->tx_num_desc * sizeof(struct dma_desc);
-	priv->tx_ring = dma_alloc_coherent(&ndev->dev, priv->tx_ring_size,
-					   &priv->tx_ring_phys, GFP_KERNEL);
-	priv->txq = &priv->rxq[1];
-	priv->txq->phys = dma_phys + sizeof(struct queue_ptr);
-	writel(priv->tx_ring_phys, priv->base + DMAREG_TX_QUEUE_BASE);
-	writel(priv->tx_ring_size / 1024, priv->base + DMAREG_TX_QUEUE_SIZE);
-	writel(priv->txq->phys, priv->base + DMAREG_TX_TAIL_ADDR);
-	priv->txq->size    = priv->tx_ring_size;
-	priv->txq->hw_tail = readl(priv->base + DMAREG_RX_TAIL);
-	priv->txq->head    = priv->txq->hw_tail;
-	priv->txq->tail    = priv->txq->hw_tail;
-	writel(priv->txq->head, priv->base + DMAREG_TX_HEAD);
-	pr_debug("femac: tx_ring %p txq %p\n", priv->tx_ring, priv->txq);
-
-	/* Clear statistics */
-	clear_statistics(priv);
-
-	ether_setup(ndev);
-	ndev->netdev_ops = &femac_netdev_ops;
-	ndev->ethtool_ops = &femac_ethtool_ops;
-	ndev->watchdog_timeo = msecs_to_jiffies(1000);
-	memset(&priv->napi, 0, sizeof(struct napi_struct));
-	netif_napi_add(ndev, &priv->napi, femac_poll, NAPI_WEIGHT);
-
-	return 0;
-}
-
-/**
- * femac_probe - Create, initialize and register the net_device.
- */
-static int
-femac_probe(struct platform_device *pdev)
-{
-	struct device_node *np = pdev->dev.of_node;
-	struct net_device *ndev = NULL;
-	struct femac_dev *priv = NULL;
-	struct resource *res;
-	const u32 *field;
-	int length;
-	int rc = 0;
-
-	/* Allocate space for the net_device. */
-	ndev = alloc_etherdev(sizeof(*priv));
-	if (!ndev) {
-		rc = -ENOMEM;
-		goto out;
-	}
-
-	priv = netdev_priv(ndev);
-	priv->ndev = ndev;
-	priv->dev = &pdev->dev;
-	strcpy(ndev->name, "eth%d");
-
-	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	priv->base  = devm_ioremap_resource(&pdev->dev, res);
-	if (IS_ERR(priv->base)) {
-		rc = PTR_ERR(priv->base);
-		goto out;
-	}
-
-	ndev->irq = platform_get_irq(pdev, 0);
-	if (ndev->irq < 0) {
-		rc = ndev->irq;
-		goto out;
-	}
-
-	/* Check for mac address property in device-tree */
-	field = of_get_property(np, "mac-address", &length);
-	if (!field)
-		field = of_get_property(np, "local-mac-address", &length);
-	if (field && length == ETH_ALEN)
-		ether_addr_copy(priv->mac_addr, (const u8 *)field);
-	/* MAC address may be overridden via module/cmdline parameter */
-	if (is_valid_ether_addr(macaddr))
-		ether_addr_copy(priv->mac_addr, macaddr);
-	/* Still no valid MAC address, randomize it */
-	if (!is_valid_ether_addr(priv->mac_addr))
-		random_ether_addr(priv->mac_addr);
-
-	ether_addr_copy(ndev->dev_addr, &priv->mac_addr[0]);
-	ether_addr_copy(ndev->perm_addr, &priv->mac_addr[0]);
-	ndev->addr_len = ETH_ALEN;
-
-	/* Initialize the device. */
-	rc = femac_init(ndev);
-	if (rc != 0)
-		goto out;
-
-	/* Register the device. */
-	rc = register_netdev(ndev);
-	if (rc != 0)
-		goto out;
-
-	device_create_file(&ndev->dev, &dev_attr_counters);
-
-	netif_carrier_off(ndev);
-
-out:
-	if (rc) {
-		dev_err(&pdev->dev, "Failed to initialize, error %d\n", rc);
-		if (ndev)
-			free_netdev(ndev);
-	}
-	return rc;
-}
-
-/**
- * femac_remove - Handle device removal.
- */
-static int
-femac_remove(struct platform_device *pdev)
-{
-	struct net_device *ndev = platform_get_drvdata(pdev);
-	struct femac_dev *priv = netdev_priv(ndev);
-
-	device_remove_file(&ndev->dev, &dev_attr_counters);
-	dma_pool_destroy(priv->tx_pool);
-	dma_free_coherent(&ndev->dev,
-			  priv->rx_ring_size,
-			  priv->rx_ring,
-			  priv->rx_ring_phys);
-	dma_free_coherent(&ndev->dev,
-			  priv->tx_ring_size,
-			  priv->tx_ring,
-			  priv->tx_ring_phys);
-	dma_free_coherent(&ndev->dev,
-			  2 * sizeof(struct queue_ptr),
-			  priv->rxq,
-			  priv->rxq->phys);
-	unregister_netdev(ndev);
-	free_netdev(ndev);
-	platform_set_drvdata(pdev, NULL);
-
-	return 0;
-}
-
-#ifdef CONFIG_PM
-static int
-femac_suspend(struct device *dev)
-{
-	return -ENOSYS;
-}
-
-static int
-femac_resume(struct device *dev)
-{
-	return -ENOSYS;
-}
-
-static const struct dev_pm_ops femac_pm_ops = {
-	.suspend = femac_suspend,
-	.resume  = femac_resume,
-};
-#endif
-
-static const struct of_device_id femac_id_table[] = {
-	{ .compatible = "lsi,femac" },
-	{ }
-};
-MODULE_DEVICE_TABLE(of, femac_id_table);
-
-static struct platform_driver femac_driver = {
-	.driver	= {
-		.name  = DRVNAME,
-		.owner = THIS_MODULE,
-#ifdef CONFIG_PM
-		.pm = &femac_pm_ops,
-#endif
-		.of_match_table = femac_id_table,
-	},
-	.probe = femac_probe,
-	.remove	= femac_remove,
-};
-
-module_platform_driver(femac_driver);
-
-MODULE_AUTHOR("LSI Corporation");
-MODULE_DESCRIPTION("LSI FEMAC Ethernet Driver");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/net/ethernet/lsi/lsi-mdio.c b/drivers/net/ethernet/lsi/lsi-mdio.c
deleted file mode 100644
index 56decf6..0000000
--- a/drivers/net/ethernet/lsi/lsi-mdio.c
+++ /dev/null
@@ -1,205 +0,0 @@
-/*
- * Driver for MDIO controller found in LSI Axxia devices.
- *
- * 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/mii.h>
-#include <linux/phy.h>
-#include <linux/of.h>
-#include <linux/of_address.h>
-#include <linux/of_mdio.h>
-#include <linux/of_platform.h>
-#include <linux/io.h>
-
-/* MDIO Registers */
-#define MDIO_CONTROL		0x00
-#define   CONTROL_BUSY		(1<<31) /* MDIO cycle in progress (RO) */
-#define   CONTROL_NOPRE		(1<<30) /* Suppress preamble */
-#define   CONTROL_CL22		(0<<29) /* Clause-22 */
-#define   CONTROL_CL45		(1<<29) /* Clause-45 */
-#define   CONTROL_READ		(2<<27) /* Read operation */
-#define   CONTROL_WRITE		(1<<27) /* Write operation */
-#define   CONTROL_IFSEL		(1<<26) /* Interface select */
-#define   CONTROL_PHYREG(_n)	(((_n) & 0x1F) << 21)
-#define   CONTROL_PHYID(_n)	(((_n) & 0x1F) << 16)
-#define   CONTROL_DATA(_n)	(((_n) & 0xFFFF) << 0)
-#define MDIO_STATUS		0x04
-#define   STATUS_BUSY		(1<<31)
-#define   STATUS_DONE		(1<<30)
-#define MDIO_CLK_OFFSET		0x08
-#define MDIO_CLK_PERIOD		0x0c
-
-/* MDIO bus driver private data */
-struct lsi_mdio_priv {
-	void __iomem *base;
-	struct mii_bus *bus;
-};
-
-static inline void __iomem *
-bus_to_regs(struct mii_bus *bus)
-{
-	return ((struct lsi_mdio_priv *)bus->priv)->base;
-}
-
-static int
-lsi_mdio_read(struct mii_bus *bus, int mii_id, int regnum)
-{
-	void __iomem *base = bus_to_regs(bus);
-	u32 ctrl;
-	u32 data;
-
-	/* Set the mdio_done (status) bit. */
-	writel(STATUS_DONE | readl(base + MDIO_STATUS), base + MDIO_STATUS);
-
-	/* Write the command. */
-	ctrl = (CONTROL_READ |
-		CONTROL_PHYID(mii_id) |
-		CONTROL_PHYREG(regnum));
-	if (regnum & MII_ADDR_C45)
-		ctrl |= CONTROL_CL45;
-	writel(ctrl, base + MDIO_CONTROL);
-
-	/* Wait for the mdio_done (status) bit to clear. */
-	while ((readl(base + MDIO_STATUS) & STATUS_DONE) != 0)
-		cpu_relax();
-
-	/* Wait for the mdio_busy (control) bit to clear. */
-	do {
-		data = readl(base + MDIO_CONTROL);
-	} while ((data & CONTROL_BUSY) != 0);
-
-	return data & 0xFFFF;
-}
-
-static int
-lsi_mdio_write(struct mii_bus *bus, int mii_id, int regnum, u16 value)
-{
-	void __iomem *base = bus_to_regs(bus);
-	u32 ctrl;
-
-	/* Wait for mdio_busy (control) to be clear. */
-	while ((readl(base + MDIO_CONTROL) & CONTROL_BUSY) != 0)
-		cpu_relax();
-
-	/* Set the mdio_busy (status) bit. */
-	writel(STATUS_DONE | readl(base + MDIO_STATUS), base + MDIO_STATUS);
-
-	/* Write the command. */
-	ctrl = (CONTROL_WRITE |
-		CONTROL_PHYID(mii_id) |
-		CONTROL_PHYREG(regnum) |
-		CONTROL_DATA(value));
-	if (regnum & MII_ADDR_C45)
-		ctrl |= CONTROL_CL45;
-	writel(ctrl, base + MDIO_CONTROL);
-
-	/* Wait for the mdio_done (status) bit to clear. */
-	while ((readl(base + MDIO_STATUS) & STATUS_DONE) != 0)
-		cpu_relax();
-
-	/* Wait for the mdio_busy (control) bit to clear. */
-	while ((readl(base + MDIO_CONTROL) & CONTROL_BUSY) != 0)
-		cpu_relax();
-
-	return 0;
-}
-
-static int
-lsi_mdio_probe(struct platform_device *pdev)
-{
-	struct device_node   *np = pdev->dev.of_node;
-	struct lsi_mdio_priv *priv = NULL;
-	struct resource      *res;
-	int                   err;
-	u32                   clk_offset = 0x10;
-	u32                   clk_period = 0x2c;
-
-	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
-	if (!priv)
-		return -ENOMEM;
-
-	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (!res)
-		return -ENODEV;
-
-	priv->bus = mdiobus_alloc();
-	if (!priv->bus)
-		return -ENOMEM;
-
-	priv->bus->name  = "Axxia MDIO",
-	priv->bus->read  = lsi_mdio_read,
-	priv->bus->write = lsi_mdio_write,
-	priv->bus->priv  = priv;
-	snprintf(priv->bus->id, MII_BUS_ID_SIZE, pdev->name);
-
-	priv->base = devm_ioremap_resource(&pdev->dev, res);
-	if (!priv->base) {
-		dev_err(&pdev->dev, "Failed to map registers\n");
-		err = -ENODEV;
-		goto err_ret;
-	}
-
-	priv->bus->parent = &pdev->dev;
-	dev_set_drvdata(&pdev->dev, priv->bus);
-
-	of_property_read_u32(np, "lsi,mdio-clk-offset", &clk_offset);
-	of_property_read_u32(np, "lsi,mdio-clk-period", &clk_period);
-
-	writel(clk_offset, priv->base + MDIO_CLK_OFFSET);
-	writel(clk_period, priv->base + MDIO_CLK_PERIOD);
-	writel(0, priv->base + MDIO_CONTROL);
-
-	err = of_mdiobus_register(priv->bus, np);
-	if (err) {
-		dev_err(&pdev->dev, "Failed to register MDIO bus\n");
-		goto err_ret;
-	}
-
-	return 0;
-
-err_ret:
-	if (priv && priv->bus)
-		kfree(priv->bus);
-	return err;
-}
-
-static int
-lsi_mdio_remove(struct platform_device *pdev)
-{
-	struct mii_bus *bus = dev_get_drvdata(&pdev->dev);
-
-	mdiobus_unregister(bus);
-	dev_set_drvdata(&pdev->dev, NULL);
-	mdiobus_free(bus);
-
-	return 0;
-}
-
-static struct of_device_id lsi_mdio_match[] = {
-	{ .compatible = "lsi,axm-mdio", },
-	{},
-};
-MODULE_DEVICE_TABLE(of, lsi_mdio_match);
-
-static struct platform_driver lsi_mdio_driver = {
-	.driver = {
-		.name           = "lsi-mdio",
-		.owner          = THIS_MODULE,
-		.of_match_table = lsi_mdio_match,
-	},
-	.probe  = lsi_mdio_probe,
-	.remove = lsi_mdio_remove,
-};
-
-module_platform_driver(lsi_mdio_driver);
-
-MODULE_AUTHOR("LSI Corporation");
-MODULE_DESCRIPTION("LSI MDIO Bus Driver");
-MODULE_LICENSE("GPL v2");
diff --git a/include/linux/axxia-mdio.h b/include/linux/axxia-mdio.h
new file mode 100644
index 0000000..3550349
--- /dev/null
+++ b/include/linux/axxia-mdio.h
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2016 Intel <john.jacques at intel.com>
+ *
+ * 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.
+ */
+
+#ifndef __DRIVERS_MISC_AXXIA_MDIO_H
+#define __DRIVERS_MISC_AXXIA_MDIO_H
+
+#endif /* __DRIVERS_MISC_AXXIA_MDIO_H */
-- 
2.7.4



More information about the linux-yocto mailing list