[linux-yocto] [PATCH 07/78] drivers/net/ethernet: add ACP wrapper support for LSI RTE into kernel

Paul Butler butler.paul at gmail.com
Tue Nov 19 20:22:43 PST 2013


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

adds the LSI ACP wrapper routines into the kernel. These
are needed for the LSI RTE application.

Signed-off-by: David Mercado <david.mercado at windriver.com>
---
 arch/powerpc/include/asm/lsi/acp_ncr.h |   3 +
 arch/powerpc/sysdev/Makefile           |   2 +-
 arch/powerpc/sysdev/lsi_acp_wrappers.c | 325 +++++++++++++++++++++++++++++++++
 drivers/net/ethernet/lsi/lsi_acp_net.c | 117 +-----------
 drivers/net/ethernet/lsi/lsi_acp_net.h |   2 -
 5 files changed, 333 insertions(+), 116 deletions(-)
 create mode 100644 arch/powerpc/sysdev/lsi_acp_wrappers.c

diff --git a/arch/powerpc/include/asm/lsi/acp_ncr.h b/arch/powerpc/include/asm/lsi/acp_ncr.h
index a7399e7..1a08f07 100644
--- a/arch/powerpc/include/asm/lsi/acp_ncr.h
+++ b/arch/powerpc/include/asm/lsi/acp_ncr.h
@@ -39,4 +39,7 @@ int ncr_write(unsigned long, unsigned long, int, void *);
 
 int is_asic(void);
 
+extern int acp_mdio_read(unsigned long, unsigned long, unsigned short *);
+extern int acp_mdio_write(unsigned long, unsigned long, unsigned short);
+
 #endif /*  __DRIVERS_LSI_ACP_NCR_H */
diff --git a/arch/powerpc/sysdev/Makefile b/arch/powerpc/sysdev/Makefile
index 6354d1c..a95b59f 100644
--- a/arch/powerpc/sysdev/Makefile
+++ b/arch/powerpc/sysdev/Makefile
@@ -73,4 +73,4 @@ obj-$(CONFIG_PPC_XICS)		+= xics/
 
 obj-$(CONFIG_GE_FPGA)		+= ge/
 
-obj-$(CONFIG_ACP)		+= lsi_acp_ncr.o
+obj-$(CONFIG_ACP)		+= lsi_acp_ncr.o lsi_acp_wrappers.o
diff --git a/arch/powerpc/sysdev/lsi_acp_wrappers.c b/arch/powerpc/sysdev/lsi_acp_wrappers.c
new file mode 100644
index 0000000..910ed25
--- /dev/null
+++ b/arch/powerpc/sysdev/lsi_acp_wrappers.c
@@ -0,0 +1,325 @@
+/*
+ * arch/powerpc/sysdev/lsi_acp_wrappers.c
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307	 USA
+ */
+
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include <linux/sched.h>
+#include <linux/of.h>
+#include <linux/io.h>
+#include <asm/irq.h>
+#include <asm/lsi/acp_ncr.h>
+
+MODULE_AUTHOR("LSI Corporation");
+MODULE_DESCRIPTION("ACP Wrappers");
+MODULE_LICENSE("GPL");
+
+/*
+  ============================================================================
+  ============================================================================
+  MDIO Access
+  ============================================================================
+  ============================================================================
+*/
+
+
+static unsigned long mdio_base;
+DEFINE_SPINLOCK(mdio_lock);
+
+#define MDIO_CONTROL_RD_DATA ((void *)(mdio_base + 0x0))
+#define MDIO_STATUS_RD_DATA  ((void *)(mdio_base + 0x4))
+#define MDIO_CLK_OFFSET      ((void *)(mdio_base + 0x8))
+#define MDIO_CLK_PERIOD      ((void *)(mdio_base + 0xc))
+
+/*
+ * -------------------------------------------------------------------------
+ * acp_mdio_read
+ */
+
+int acp_mdio_read(unsigned long address, unsigned long offset,
+		  unsigned short *value)
+{
+	unsigned long command = 0;
+	unsigned long status;
+	unsigned long flags;
+
+	spin_lock_irqsave(&mdio_lock, flags);
+
+	/* Set the mdio_busy (status) bit. */
+	status = in_le32(MDIO_STATUS_RD_DATA);
+	status |= 0x40000000;
+	out_le32(MDIO_STATUS_RD_DATA, status);
+
+	/* Write the command.*/
+	command |= 0x10000000;	/* op_code: read */
+	command |= (address & 0x1f) << 16; /* port_addr (target device) */
+	command |= (offset & 0x1f) << 21; /* device_addr (target register) */
+	out_le32(MDIO_CONTROL_RD_DATA, command);
+
+	/* Wait for the mdio_busy (status) bit to clear. */
+	do {
+		status = in_le32(MDIO_STATUS_RD_DATA);
+	} while (0 != (status & 0x40000000));
+
+	/* Wait for the mdio_busy (control) bit to clear. */
+	do {
+		command = in_le32(MDIO_CONTROL_RD_DATA);
+	} while (0 != (command & 0x80000000));
+
+	*value = (unsigned short)(command & 0xffff);
+
+	spin_unlock_irqrestore(&mdio_lock, flags);
+
+	return 0;
+}
+EXPORT_SYMBOL(acp_mdio_read);
+
+/*
+ * -------------------------------------------------------------------------
+ * acp_mdio_write
+ */
+
+int acp_mdio_write(unsigned long address, unsigned long offset,
+		   unsigned short value)
+{
+	unsigned long command = 0;
+	unsigned long status;
+	unsigned long flags;
+
+	spin_lock_irqsave(&mdio_lock, flags);
+
+	/* Wait for mdio_busy (control) to be clear. */
+	do {
+		command = in_le32(MDIO_CONTROL_RD_DATA);
+	} while (0 != (command & 0x80000000));
+
+	/* Set the mdio_busy (status) bit. */
+	status = in_le32(MDIO_STATUS_RD_DATA);
+	status |= 0x40000000;
+	out_le32(MDIO_STATUS_RD_DATA, status);
+
+	/* Write the command. */
+	command = 0x08000000;	/* op_code: write */
+	command |= (address & 0x1f) << 16; /* port_addr (target device) */
+	command |= (offset & 0x1f) << 21; /* device_addr (target register) */
+	command |= (value & 0xffff); /* value */
+	out_le32(MDIO_CONTROL_RD_DATA, command);
+
+	/* Wait for the mdio_busy (status) bit to clear. */
+	do {
+		status = in_le32(MDIO_STATUS_RD_DATA);
+	} while (0 != (status & 0x40000000));
+
+	/* Wait for the mdio_busy (control) bit to clear. */
+	do {
+		command = in_le32(MDIO_CONTROL_RD_DATA);
+	} while (0 != (command & 0x80000000));
+
+	spin_unlock_irqrestore(&mdio_lock, flags);
+
+	return 0;
+}
+EXPORT_SYMBOL(acp_mdio_write);
+
+/*
+ * -------------------------------------------------------------------------
+ * acp_mdio_initialize
+ */
+
+static int acp_mdio_initialize(void)
+{
+	if (is_asic()) {
+		out_le32(MDIO_CLK_OFFSET, 0x10);
+		out_le32(MDIO_CLK_PERIOD, 0x2c);
+	} else {
+		out_le32(MDIO_CLK_OFFSET, 0x05);
+		out_le32(MDIO_CLK_PERIOD, 0x0c);
+	}
+
+	return 0;
+}
+
+
+/*
+  ============================================================================
+  ============================================================================
+  Interrupts
+  ============================================================================
+  ============================================================================
+*/
+
+/*
+ * -------------------------------------------------------------------------
+ * acp_irq_create_mapping
+ */
+unsigned int acp_irq_create_mapping(struct irq_domain *host,
+				    irq_hw_number_t hwirq)
+{
+	unsigned int mapped_irq;
+
+	preempt_disable();
+	mapped_irq = irq_create_mapping(host, hwirq);
+	preempt_enable();
+
+	return mapped_irq;
+}
+EXPORT_SYMBOL(acp_irq_create_mapping);
+
+/*
+  ============================================================================
+  ============================================================================
+  Spin Locks
+  ============================================================================
+  ============================================================================
+*/
+
+/*
+ * -------------------------------------------------------------------------
+ * acp_spin_lock_init
+ */
+
+void acp_spin_lock_init(spinlock_t *lock)
+{
+	spin_lock_init(lock);
+}
+EXPORT_SYMBOL(acp_spin_lock_init);
+
+/*
+ * -------------------------------------------------------------------------
+ * acp_spin_lock
+ */
+
+void acp_spin_lock(spinlock_t *lock)
+{
+	spin_lock(lock);
+}
+EXPORT_SYMBOL(acp_spin_lock);
+
+/*
+ * -------------------------------------------------------------------------
+ * acp_spin_unlock
+ */
+
+void acp_spin_unlock(spinlock_t *lock)
+{
+	spin_unlock(lock);
+}
+EXPORT_SYMBOL(acp_spin_unlock);
+
+/*
+ * -------------------------------------------------------------------------
+ * acp_spin_lock_bh
+ */
+
+void acp_spin_lock_bh(spinlock_t *lock)
+{
+	spin_lock_bh(lock);
+}
+EXPORT_SYMBOL(acp_spin_lock_bh);
+
+/*
+ * -------------------------------------------------------------------------
+ * acp_spin_unlock_bh
+ */
+
+void acp_spin_unlock_bh(spinlock_t *lock)
+{
+	spin_unlock_bh(lock);
+}
+EXPORT_SYMBOL(acp_spin_unlock_bh);
+
+/*
+ * -------------------------------------------------------------------------
+ * acp_spin_lock_irqsave
+ */
+
+void acp_spin_lock_irqsave(spinlock_t *lock, unsigned long flags)
+{
+	spin_lock_irqsave(lock, flags);
+}
+EXPORT_SYMBOL(acp_spin_lock_irqsave);
+
+/*
+ * -------------------------------------------------------------------------
+ * acp_spin_unlock_irqrestore
+ */
+
+void acp_spin_unlock_irqrestore(spinlock_t *lock, unsigned long flags)
+{
+	spin_unlock_irqrestore(lock, flags);
+}
+EXPORT_SYMBOL(acp_spin_unlock_irqrestore);
+
+/*
+ * -------------------------------------------------------------------------
+ * acp_wrappers_init
+ */
+
+int __init acp_wrappers_init(void)
+{
+	int rc = -1;
+	struct device_node *np = NULL;
+	const u32 *field;
+	u64 mdio_phys_address;
+	u32 mdio_size;
+
+	pr_info("Initializing ACP Wrappers.\n");
+
+	np = of_find_node_by_type(np, "network");
+
+	while (np && !of_device_is_compatible(np, "acp-femac"))
+		np = of_find_node_by_type(np, "network");
+
+	if (np) {
+		field = of_get_property(np, "enabled", NULL);
+
+		if (!field || (field && (0 == *field))) {
+			pr_warn("Networking is Not Enabled.\n");
+			goto acp_wrappers_init_done;
+		}
+
+		field = of_get_property(np, "mdio-reg", NULL);
+
+		if (!field) {
+			pr_err("Couldn't get \"mdio-reg\" property.\n");
+		} else {
+			mdio_phys_address = of_translate_address(np, field);
+			mdio_size = field[1];
+			rc = 0;
+		}
+	}
+
+	if (0 != rc) {
+		mdio_phys_address = 0x002000409000ULL;
+		mdio_size = 0x1000;
+		pr_warn("** MDIO Address Not Specified in Device Tree.\n");
+	}
+
+	mdio_base = (unsigned long)ioremap(mdio_phys_address, mdio_size);
+	rc = acp_mdio_initialize();
+
+	if (0 != rc)
+		pr_err("MDIO Initiailzation Failed!\n");
+
+acp_wrappers_init_done:
+
+	return 0;
+}
+
+module_init(acp_wrappers_init);
diff --git a/drivers/net/ethernet/lsi/lsi_acp_net.c b/drivers/net/ethernet/lsi/lsi_acp_net.c
index 21153bf..605a431 100644
--- a/drivers/net/ethernet/lsi/lsi_acp_net.c
+++ b/drivers/net/ethernet/lsi/lsi_acp_net.c
@@ -72,7 +72,6 @@
 #define LSI_MDIO_NAME          "acp-femac-mdio"
 #define LSI_DRV_VERSION        "2013-04-30"
 
-
 MODULE_AUTHOR("John Jacques");
 MODULE_DESCRIPTION("LSI ACP-FEMAC Ethernet driver");
 MODULE_LICENSE("GPL");
@@ -83,37 +82,6 @@ static void *tx_base;
 static void *dma_base;
 
 /*
-  =============================================================================
-  MDIO / PHY
-  =============================================================================
-*/
-
-#define MDIO_CONTROL_RD_DATA ((void *)(pdata->mdio_base + 0x0))
-#define MDIO_STATUS_RD_DATA  ((void *)(pdata->mdio_base + 0x4))
-#define MDIO_CLK_OFFSET      ((void *)(pdata->mdio_base + 0x8))
-#define MDIO_CLK_PERIOD      ((void *)(pdata->mdio_base + 0xc))
-
-/*
- * ----------------------------------------------------------------------
- * appnic_mdio_initialize
- */
-
-static void appnic_mdio_initialize(struct net_device *dev)
-{
-	struct appnic_device *pdata = netdev_priv(dev);
-
-	if (is_asic()) {
-		out_le32(MDIO_CLK_OFFSET, 0x10);
-		out_le32(MDIO_CLK_PERIOD, 0x2c);
-	} else {
-		out_le32(MDIO_CLK_OFFSET, 0x05);
-		out_le32(MDIO_CLK_PERIOD, 0x0c);
-	}
-
-	return;
-}
-
-/*
  * ----------------------------------------------------------------------
  * appnic_mii_read
  *
@@ -122,42 +90,14 @@ static void appnic_mdio_initialize(struct net_device *dev)
 
 static int appnic_mii_read(struct mii_bus *bus, int phy, int reg)
 {
-	struct appnic_device *pdata = (struct appnic_device *)bus->priv;
-	unsigned long flags;
 	unsigned short value;
-	unsigned long command = 0;
-	unsigned long status;
-
-	spin_lock_irqsave(&pdata->mdio_lock, flags);
 
-	/* Set the mdio_busy (status) bit. */
-	status = in_le32(MDIO_STATUS_RD_DATA);
-	status |= 0x40000000;
-	out_le32(MDIO_STATUS_RD_DATA, status);
+	/* Always returns success, so no need to check return status. */
+	acp_mdio_read(phy, reg, &value);
 
-	/* Write the command. */
-	command |= 0x10000000;          /* op_code: read */
-	command |= (phy & 0x1f) << 16;  /* port_addr (target device) */
-	command |= (reg & 0x1f) << 21;  /* device_addr (target register) */
-	out_le32(MDIO_CONTROL_RD_DATA, command);
-
-	/* Wait for the mdio_busy (status) bit to clear. */
-	do {
-		status = in_le32(MDIO_STATUS_RD_DATA);
-	} while (0 != (status & 0x40000000));
-
-	/* Wait for the mdio_busy (control) bit to clear. */
-	do {
-		command = in_le32(MDIO_CONTROL_RD_DATA);
-	} while (0 != (command & 0x80000000));
-
-	value = (unsigned short)(command & 0xffff);
-	spin_unlock_irqrestore(&pdata->mdio_lock, flags);
-
-	return value;
+	return (int)value;
 }
 
-
 /*
  * ----------------------------------------------------------------------
  * appnic_mii_write
@@ -165,43 +105,7 @@ static int appnic_mii_read(struct mii_bus *bus, int phy, int reg)
 
 static int appnic_mii_write(struct mii_bus *bus, int phy, int reg, u16 val)
 {
-	struct appnic_device *pdata = (struct appnic_device *)bus->priv;
-	unsigned long flags;
-	unsigned long command = 0;
-	unsigned long status;
-
-	spin_lock_irqsave(&pdata->mdio_lock, flags);
-
-	/* Wait for mdio_busy (control) to be clear. */
-	do {
-		command = in_le32(MDIO_CONTROL_RD_DATA);
-	} while (0 != (command & 0x80000000));
-
-	/* Set the mdio_busy (status) bit. */
-	status = in_le32(MDIO_STATUS_RD_DATA);
-	status |= 0x40000000;
-	out_le32(MDIO_STATUS_RD_DATA, status);
-
-	/* Write the command. */
-	command = 0x08000000;           /* op_code: write */
-	command |= (phy & 0x1f) << 16;  /* port_addr (target device) */
-	command |= (reg & 0x1f) << 21;  /* device_addr (target register) */
-	command |= (val & 0xffff);      /* value */
-	out_le32(MDIO_CONTROL_RD_DATA, command);
-
-	/* Wait for the mdio_busy (status) bit to clear. */
-	do {
-		status = in_le32(MDIO_STATUS_RD_DATA);
-	} while (0 != (status & 0x40000000));
-
-	/* Wait for the mdio_busy (control) bit to clear. */
-	do {
-		command = in_le32(MDIO_CONTROL_RD_DATA);
-	} while (0 != (command & 0x80000000));
-
-	spin_unlock_irqrestore(&pdata->mdio_lock, flags);
-
-	return 0;
+	return acp_mdio_write(phy, reg, val);
 }
 
 /*
@@ -1596,7 +1500,6 @@ int appnic_init(struct net_device *dev)
 	 * Initialize the spinlocks.
 	 */
 
-	spin_lock_init(&pdata->mdio_lock);
 	spin_lock_init(&pdata->dev_lock);
 	spin_lock_init(&pdata->extra_lock);
 
@@ -1807,15 +1710,6 @@ static int __devinit appnic_probe_config_dt(struct net_device *dev,
 	else
 		pdata->mdio_clock = field[0];
 
-	field = of_get_property(np, "mdio-reg", NULL);
-	if (!field) {
-		goto device_tree_failed;
-	} else {
-		value64 = of_translate_address(np, field);
-		value32 = field[1];
-		pdata->mdio_base = (unsigned long)ioremap(value64, value32);
-	}
-
 	field = of_get_property(np, "phy-address", NULL);
 	if (!field)
 		goto device_tree_failed;
@@ -1998,9 +1892,6 @@ static int __devinit appnic_drv_probe(struct platform_device *pdev)
 		goto out;
 	}
 
-	/* Initialize the MDIO interface. */
-	appnic_mdio_initialize(dev);
-
 	/* Initialize the PHY. */
 	rc = appnic_mii_init(pdev, dev);
 	if (rc) {
diff --git a/drivers/net/ethernet/lsi/lsi_acp_net.h b/drivers/net/ethernet/lsi/lsi_acp_net.h
index db4bfcf..f7de38d 100644
--- a/drivers/net/ethernet/lsi/lsi_acp_net.h
+++ b/drivers/net/ethernet/lsi/lsi_acp_net.h
@@ -93,7 +93,6 @@ struct appnic_device {
 	unsigned long dma_base;
 	unsigned long interrupt;
 	unsigned long mdio_clock;
-	unsigned long mdio_base;
 	unsigned long phy_address;
 	unsigned long ad_value;
 	unsigned char mac_addr[6];
@@ -149,7 +148,6 @@ struct appnic_device {
 	union appnic_queue_pointer tx_head;
 
 	/* Spin Lock */
-	spinlock_t mdio_lock;
 	spinlock_t dev_lock;
 	spinlock_t extra_lock;
 
-- 
1.8.4.3



More information about the linux-yocto mailing list