[linux-yocto] [PATCH 18/39] LSI FEMAC Ethernet Driver
Charlie Paul
cpaul.windriver at gmail.com
Fri Apr 11 14:13:19 PDT 2014
From: David Mercado <david.mercado at windriver.com>
Integrated feedback and suggestions to make driver easier to upstream.
Signed-off-by: David Mercado <david.mercado at windriver.com>
---
drivers/net/ethernet/lsi/Kconfig | 15 -
drivers/net/ethernet/lsi/lsi_acp_mdio.c | 245 ++++-----
drivers/net/ethernet/lsi/lsi_acp_net.c | 877 +++++++++++++++----------------
drivers/net/ethernet/lsi/lsi_acp_net.h | 273 +++++++---
4 files changed, 740 insertions(+), 670 deletions(-)
diff --git a/drivers/net/ethernet/lsi/Kconfig b/drivers/net/ethernet/lsi/Kconfig
index 1c760e5..a78867d 100644
--- a/drivers/net/ethernet/lsi/Kconfig
+++ b/drivers/net/ethernet/lsi/Kconfig
@@ -35,19 +35,4 @@ config LSI_NET_TX_BUF_SZ
help
The size of the transmit buffer.
-config DISABLE_TX_INTERRUPTS
- bool "NIC driver: Disable Tx interrupts"
- depends on LSI_NET
- default y
- help
- If set to "yes", disables Transmit interrupts
-
-config PRELOAD_RX_BUFFERS
- bool "NIC driver: Preload Rx buffers"
- depends on LSI_NET
- default n
- help
- If set to "yes", enables preloading of Rx buffer prior to
- copying into device
-
endif # LSI_NET
diff --git a/drivers/net/ethernet/lsi/lsi_acp_mdio.c b/drivers/net/ethernet/lsi/lsi_acp_mdio.c
index 07643fc..6427ae0 100644
--- a/drivers/net/ethernet/lsi/lsi_acp_mdio.c
+++ b/drivers/net/ethernet/lsi/lsi_acp_mdio.c
@@ -1,21 +1,13 @@
/*
* drivers/net/ethernet/lsi/lsi_acp_mdio.c
*
- * Copyright (C) 2010 LSI
+ * Copyright (C) 2013 LSI Corporation.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/module.h>
@@ -27,42 +19,49 @@
#include <linux/skbuff.h>
#include <linux/platform_device.h>
-/*
- ==============================================================================
- ==============================================================================
- MDIO Access
- ==============================================================================
- ==============================================================================
-*/
+#define BZ33327_WA
-#ifndef CONFIG_ACPISS
+/* MDIO Access */
-#define BZ33327_WA
+struct lsi_mdio_priv {
+ unsigned long base;
+};
-static unsigned long mdio_base;
+static struct lsi_mdio_priv *mdio_priv;
static 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))
+#define MDIO_CONTROL_RD_DATA ((void *)(mdio_priv->base + 0x0))
+#define MDIO_STATUS_RD_DATA ((void *)(mdio_priv->base + 0x4))
+#define MDIO_CLK_OFFSET ((void *)(mdio_priv->base + 0x8))
+#define MDIO_CLK_PERIOD ((void *)(mdio_priv->base + 0xc))
#ifdef CONFIG_ARM
-#define READ(a) readl((a))
-#define WRITE(a, v) writel((v), (a))
+static u32 read_reg(u32 *addr)
+{
+ return readl((void __iomem *)addr);
+}
+
+static void write_reg(u32 *addr, u32 value)
+{
+ writel(value, (void __iomem *)addr);
+}
#else
-#define READ(a) in_le32((a))
-#define WRITE(a, v) out_le32((a), (v))
+static u32 read_reg(u32 *addr)
+{
+ return in_le32((unsigned *)addr);
+}
+
+static void write_reg(u32 *addr, u32 value)
+{
+ out_le32((unsigned *)addr, (int)value);
+}
#endif
-/*
- ------------------------------------------------------------------------------
- acp_mdio_read
-*/
+/* acp_mdio_read */
int
acp_mdio_read(unsigned long address, unsigned long offset,
- unsigned short *value, int clause45)
+ unsigned short *value, int clause_45)
{
unsigned long command = 0;
unsigned long status;
@@ -71,73 +70,74 @@ acp_mdio_read(unsigned long address, unsigned long offset,
spin_lock_irqsave(&mdio_lock, flags);
#if defined(BZ33327_WA)
/* Set the mdio_busy (status) bit. */
- status = READ(MDIO_STATUS_RD_DATA);
+ status = read_reg(MDIO_STATUS_RD_DATA);
status |= 0x40000000;
- WRITE(MDIO_STATUS_RD_DATA, status);
+ write_reg(MDIO_STATUS_RD_DATA, status);
#endif /* BZ33327_WA */
- if (clause45 == 0) {
+ if (clause_45 == 0) {
/* Write the command. */
command = 0x10000000; /* op_code: read */
command |= (address & 0x1f) << 16; /* port_addr (tgt device) */
command |= (offset & 0x1f) << 21; /* device_addr (tgt reg) */
- WRITE(MDIO_CONTROL_RD_DATA, command);
+ write_reg(MDIO_CONTROL_RD_DATA, command);
} else {
- /*
- * Step 1: Write the address.
- */
+ /* Step 1: Write the address. */
/* Write the address */
- command = 0x20000000; /* clause_45 = 1 */
+ command = 0x20000000; /* Clause 45 = 1 */
command |= 0x00000000; /* op_code: 0 */
command |= 0x04000000; /* interface_sel = 1 */
command |= ((offset & 0x1f000000) >> 3); /* device_addr (target
- device_type) */
+ * device_type)
+ */
command |= (address & 0x1f) << 16; /* port_addr (target
- device) */
+ * device)
+ */
command |= (offset & 0xffff); /* addr_or_data (target
- register) */
- WRITE(MDIO_CONTROL_RD_DATA, command);
+ * register)
+ */
+ write_reg(MDIO_CONTROL_RD_DATA, command);
/* Wait for the mdio_busy (status) bit to clear. */
do {
- status = READ(MDIO_STATUS_RD_DATA);
+ status = read_reg(MDIO_STATUS_RD_DATA);
} while (0 != (status & 0x40000000));
/* Wait for the mdio_busy (control) bit to clear. */
do {
- command = READ(MDIO_CONTROL_RD_DATA);
+ command = read_reg(MDIO_CONTROL_RD_DATA);
} while (0 != (command & 0x80000000));
- /*
- * Step 2: Read the value.
- */
+ /* Step 2: Read the value. */
/* Set the mdio_busy (status) bit. */
- status = READ(MDIO_STATUS_RD_DATA);
+ status = read_reg(MDIO_STATUS_RD_DATA);
status |= 0x40000000;
- WRITE(MDIO_STATUS_RD_DATA, status);
+ write_reg(MDIO_STATUS_RD_DATA, status);
- command = 0x20000000; /* clause_45 = 1 */
+ command = 0x20000000; /* Clause 45 = 1 */
command |= 0x10000000; /* op_code: read */
command |= 0x04000000; /* interface_sel = 1 */
command |= ((offset & 0x1f000000) >> 3); /* device_addr (target
- device_type) */
+ * device_type)
+ */
command |= (address & 0x1f) << 16; /* port_addr (target
- device) */
- WRITE(MDIO_CONTROL_RD_DATA, command);
+ * device)
+ */
+ write_reg(MDIO_CONTROL_RD_DATA, command);
}
#if defined(BZ33327_WA)
/* Wait for the mdio_busy (status) bit to clear. */
do {
- status = READ(MDIO_STATUS_RD_DATA);
+ status = read_reg(MDIO_STATUS_RD_DATA);
} while (0 != (status & 0x40000000));
#endif /* BZ33327_WA */
/* Wait for the mdio_busy (control) bit to clear. */
do {
- command = READ(MDIO_CONTROL_RD_DATA);
+ command = read_reg(MDIO_CONTROL_RD_DATA);
} while (0 != (command & 0x80000000));
*value = (unsigned short)(command & 0xffff);
@@ -147,14 +147,11 @@ acp_mdio_read(unsigned long address, unsigned long offset,
}
EXPORT_SYMBOL(acp_mdio_read);
-/*
- ------------------------------------------------------------------------------
- acp_mdio_write
-*/
+/* acp_mdio_write */
int
acp_mdio_write(unsigned long address, unsigned long offset,
- unsigned short value, int clause45)
+ unsigned short value, int clause_45)
{
unsigned long command = 0;
unsigned long status;
@@ -164,80 +161,81 @@ acp_mdio_write(unsigned long address, unsigned long offset,
/* Wait for mdio_busy (control) to be clear. */
do {
- command = READ(MDIO_CONTROL_RD_DATA);
+ command = read_reg(MDIO_CONTROL_RD_DATA);
} while (0 != (command & 0x80000000));
#if defined(BZ33327_WA)
/* Set the mdio_busy (status) bit. */
- status = READ(MDIO_STATUS_RD_DATA);
+ status = read_reg(MDIO_STATUS_RD_DATA);
status |= 0x40000000;
- WRITE(MDIO_STATUS_RD_DATA, status);
+ write_reg(MDIO_STATUS_RD_DATA, status);
#endif /* BZ33327_WA */
- if (clause45 == 0) {
+ if (clause_45 == 0) {
/* Write the command. */
command = 0x08000000; /* op_code: write */
command |= (address & 0x1f) << 16; /* port_addr (tgt device) */
command |= (offset & 0x1f) << 21; /* device_addr (tgt reg) */
command |= (value & 0xffff); /* value */
- WRITE(MDIO_CONTROL_RD_DATA, command);
+ write_reg(MDIO_CONTROL_RD_DATA, command);
} else {
- /*
- * Step 1: Write the address.
- */
+ /* Step 1: Write the address. */
/* Write the address */
- command = 0x20000000; /* clause_45 = 1 */
+ command = 0x20000000; /* Clause 45 = 1 */
command |= 0x00000000; /* op_code: 0 */
command |= 0x04000000; /* interface_sel = 1 */
command |= ((offset & 0x1f000000) >> 3); /* device_addr (target
- device_type) */
+ * device_type)
+ */
command |= (address & 0x1f) << 16; /* port_addr (target
- device) */
+ * device)
+ */
command |= (offset & 0xffff); /* addr_or_data (target
- register) */
- WRITE(MDIO_CONTROL_RD_DATA, command);
+ * register)
+ */
+ write_reg(MDIO_CONTROL_RD_DATA, command);
/* Wait for the mdio_busy (status) bit to clear. */
do {
- status = READ(MDIO_STATUS_RD_DATA);
+ status = read_reg(MDIO_STATUS_RD_DATA);
} while (0 != (status & 0x40000000));
/* Wait for the mdio_busy (control) bit to clear. */
do {
- command = READ(MDIO_CONTROL_RD_DATA);
+ command = read_reg(MDIO_CONTROL_RD_DATA);
} while (0 != (command & 0x80000000));
- /*
- * Step 2: Write the value.
- */
+ /* Step 2: Write the value. */
/* Set the mdio_busy (status) bit. */
- status = READ(MDIO_STATUS_RD_DATA);
+ status = read_reg(MDIO_STATUS_RD_DATA);
status |= 0x40000000;
- WRITE(MDIO_STATUS_RD_DATA, status);
+ write_reg(MDIO_STATUS_RD_DATA, status);
- command = 0x20000000; /* clause_45 = 1 */
+ command = 0x20000000; /* Clause 45 = 1 */
command |= 0x08000000; /* op_code: write */
command |= 0x04000000; /* interface_sel = 1 */
command |= ((offset & 0x1f000000) >> 3); /* device_addr (target
- device_type) */
+ * device_type)
+ */
command |= (address & 0x1f) << 16; /* port_addr (target
- device) */
+ * device)
+ */
command |= (value & 0xffff); /* addr_or_data=value*/
- WRITE(MDIO_CONTROL_RD_DATA, command);
+ write_reg(MDIO_CONTROL_RD_DATA, command);
}
#if defined(BZ33327_WA)
/* Wait for the mdio_busy (status) bit to clear. */
do {
- status = READ(MDIO_STATUS_RD_DATA);
+ status = read_reg(MDIO_STATUS_RD_DATA);
} while (0 != (status & 0x40000000));
#endif /* BZ33327_WA */
/* Wait for the mdio_busy (control) bit to clear. */
do {
- command = READ(MDIO_CONTROL_RD_DATA);
+ command = read_reg(MDIO_CONTROL_RD_DATA);
} while (0 != (command & 0x80000000));
spin_unlock_irqrestore(&mdio_lock, flags);
@@ -246,39 +244,23 @@ acp_mdio_write(unsigned long address, unsigned long offset,
}
EXPORT_SYMBOL(acp_mdio_write);
-/*
- ------------------------------------------------------------------------------
- acp_mdio_initialize
-*/
+/* acp_mdio_initialize */
-static int
+static void
acp_mdio_initialize(void)
{
#ifdef CONFIG_ARM
- WRITE(MDIO_CLK_OFFSET, 0x1c);
- WRITE(MDIO_CLK_PERIOD, 0xf0);
+ /* LSI AXM (ARM) Platforms. */
+ write_reg(MDIO_CLK_OFFSET, 0x1c);
+ write_reg(MDIO_CLK_PERIOD, 0xf0);
#else
- WRITE(MDIO_CLK_OFFSET, 0x10);
- WRITE(MDIO_CLK_PERIOD, 0x2c);
+ /* LSI ACP (PPC) Platforms. */
+ write_reg(MDIO_CLK_OFFSET, 0x10);
+ write_reg(MDIO_CLK_PERIOD, 0x2c);
#endif
-
- return 0;
}
-#endif /* ! CONFIG_ACPISS */
-
-/*
- ==============================================================================
- ==============================================================================
- Linux Stuff
- ==============================================================================
- ==============================================================================
-*/
-
-/*
- ------------------------------------------------------------------------------
- acp_wrappers_init
-*/
+/* acp_wrappers_init */
int __init
acp_mdio_init(void)
@@ -286,12 +268,16 @@ acp_mdio_init(void)
int rc = -ENODEV;
struct device_node *np = NULL;
const u32 *field;
+ void __iomem *map;
u64 mdio_address;
u32 mdio_size;
- pr_info("Initializing Axxia Wrappers.\n");
+ pr_info("MDIO: Initializing Axxia Wrappers.\n");
+
+ mdio_priv = kzalloc(sizeof(struct lsi_mdio_priv), GFP_KERNEL);
+ if (!mdio_priv)
+ return -ENOMEM;
-#ifndef CONFIG_ACPISS
np = of_find_node_by_type(np, "network");
while (np &&
@@ -299,22 +285,37 @@ acp_mdio_init(void)
!of_device_is_compatible(np, "acp-femac"))
np = of_find_node_by_type(np, "network");
- if (!np)
+ if (!np) {
+ pr_warn("MDIO: No compatible devices found.\n");
+ rc = -EINVAL;
goto error;
+ }
field = of_get_property(np, "mdio-reg", NULL);
- if (!field)
+ if (!field) {
+ pr_crit("MDIO: Unable to read mdio-reg property!\n");
+ rc = -EINVAL;
goto error;
+ }
mdio_address = of_translate_address(np, field);
+ if (mdio_address == OF_BAD_ADDR) {
+ pr_crit("MDIO: of_translate_address failed!\n");
+ rc = -EINVAL;
+ goto error;
+ }
+
mdio_size = field[1];
- mdio_base = (unsigned long)ioremap(mdio_address, mdio_size);
- rc = acp_mdio_initialize();
-#else
- rc = 0;
-#endif
+ map = ioremap(mdio_address, mdio_size);
+ if (!map) {
+ pr_crit("MDIO: Unable to ioremap!\n");
+ rc = -ENOMEM;
+ goto error;
+ }
+ mdio_priv->base = (unsigned long)map;
+ acp_mdio_initialize();
error:
return rc;
}
diff --git a/drivers/net/ethernet/lsi/lsi_acp_net.c b/drivers/net/ethernet/lsi/lsi_acp_net.c
index 8924b19..78b7e79 100644
--- a/drivers/net/ethernet/lsi/lsi_acp_net.c
+++ b/drivers/net/ethernet/lsi/lsi_acp_net.c
@@ -1,23 +1,13 @@
/*
* drivers/net/ethernet/lsi/lsi_acp_net.c
*
- * Copyright (C) 2013 LSI
+ * Copyright (C) 2013 LSI Corporation.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
- * USA
- *
* NOTES:
*
* 1) This driver is used by both ACP (PPC) and AXM (ARM) platforms.
@@ -81,45 +71,25 @@
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
+#include <linux/of_net.h>
#include <linux/dma-mapping.h>
#include <linux/uaccess.h>
#include <linux/io.h>
#include <asm/dma.h>
-#ifdef CONFIG_AXXIA
-#include <mach/ncr.h>
-#else
#include "../../../misc/lsi-ncr.h"
-#endif
#include "lsi_acp_net.h"
-/* Define to disable full duplex mode on Amarillo boards */
-#undef AMARILLO_WA
-/*#define AMARILLO_WA*/
-
#define LSI_DRV_NAME "acp-femac"
#define LSI_MDIO_NAME "acp-femac-mdio"
-#define LSI_DRV_VERSION "2013-09-10"
+#define LSI_DRV_VERSION "2014-01-09"
MODULE_AUTHOR("John Jacques");
MODULE_DESCRIPTION("LSI ACP-FEMAC Ethernet driver");
MODULE_LICENSE("GPL");
-/* Base Addresses of the RX, TX, and DMA Registers. */
-static void *rx_base;
-static void *tx_base;
-static void *dma_base;
-#ifdef CONFIG_ARM
-static void *gpreg_base;
-#define GPREG_BASE 0x002010094000ULL
-#endif
-
-/* BCM5221 registers */
-#define PHY_BCM_TEST_REG 0x1f
-#define PHY_AUXILIARY_MODE3 0x1d
-
/* ----------------------------------------------------------------------
* appnic_mii_read
*
@@ -177,12 +147,10 @@ static void appnic_handle_link_change(struct net_device *dev)
if (phydev->link) {
if ((pdata->speed != phydev->speed) ||
(pdata->duplex != phydev->duplex)) {
-#ifndef AMARILLO_WA
if (phydev->duplex) {
rx_configuration |= APPNIC_RX_CONF_DUPLEX;
tx_configuration |= APPNIC_TX_CONF_DUPLEX;
}
-#endif
if (phydev->speed == SPEED_100) {
rx_configuration |= APPNIC_RX_CONF_SPEED;
tx_configuration |= APPNIC_TX_CONF_SPEED;
@@ -279,34 +247,6 @@ skip_first:
return ret;
}
-#ifdef AMARILLO_WA
- /*
- * For the Amarillo, without the auto-negotiate ecn.
- */
- {
- u16 val;
- int rc;
-
- /* Enable access to shadow register @ 0x1d */
- rc = acp_mdio_read(phydev->addr, PHY_BCM_TEST_REG, &val, 0);
- val |= 0x80;
- rc |= acp_mdio_write(phydev->addr, PHY_BCM_TEST_REG, val, 0);
-
- /* Set RX FIFO size to 0x7 */
- rc |= acp_mdio_read(phydev->addr, PHY_AUXILIARY_MODE3, &val, 0);
- val &= 0xf;
- val |= 0x7;
- rc |= acp_mdio_write(phydev->addr, PHY_AUXILIARY_MODE3, val, 0);
-
- /* Disable access to shadow register @ 0x1d */
- rc |= acp_mdio_read(phydev->addr, PHY_BCM_TEST_REG, &val, 0);
- val &= ~0x80;
- rc |= acp_mdio_write(phydev->addr, PHY_BCM_TEST_REG, val, 0);
-
- if (0 != rc)
- return -EIO;
- }
-#endif
netdev_info(dev,
"attached PHY driver [%s] (mii_bus:phy_addr=%s, irq=%d)\n",
phydev->drv->name, dev_name(&phydev->dev), phydev->irq);
@@ -381,9 +321,7 @@ err_out_1:
#define DESCRIPTOR_GRANULARITY 64
#define BUFFER_ALIGNMENT 64
-#define ALIGN64B(address) \
- ((((unsigned long) (address) + (64UL - 1UL)) & ~(64UL - 1UL)))
-
+#define ALIGN64B(address) (PTR_ALIGN((address), BUFFER_ALIGNMENT))
#define ALIGN64B_OFFSET(address) \
(ALIGN64B(address) - (unsigned long) (address))
@@ -426,120 +364,135 @@ int tx_buf_sz = CONFIG_LSI_NET_TX_BUF_SZ;
module_param(tx_buf_sz, int, 0);
MODULE_PARM_DESC(tx_buf_sz, "Appnic : Receive buffer size");
-static unsigned long dropped_by_stack;
-static unsigned long out_of_tx_descriptors;
-static unsigned long transmit_interrupts;
-static unsigned long receive_interrupts;
-
/* ======================================================================
- Utility Functions
- ======================================================================
-*/
+ * Utility Functions
+ * ======================================================================
+ */
/* ----------------------------------------------------------------------
- * clear_statistics
+ * mac_addr_valid
+ *
+ * If mac address is multicast, broadcast, or matches our mac address,
+ * it's a valid address. Otherwise, it's not.
*/
-static void clear_statistics(struct appnic_device *pdata)
+static bool mac_addr_valid(struct net_device *dev, u8 *mac_addr)
{
- int waste;
-
- /* Clear memory. */
+ bool is_valid = false;
- memset((void *) &(pdata->stats), 0, sizeof(struct net_device_stats));
+ if (is_multicast_ether_addr(mac_addr))
+ is_valid = true;
+ else if (is_broadcast_ether_addr(mac_addr))
+ is_valid = true;
+ else if (compare_ether_addr(mac_addr, &dev->dev_addr[0]) == 0)
+ is_valid = true;
- /* Clear counters. */
+ return is_valid;
+}
- waste = read_mac(APPNIC_RX_STAT_PACKET_OK); /* rx_packets */
- waste = read_mac(APPNIC_TX_STAT_PACKET_OK); /* tx_packets */
- /* rx_bytes kept by driver. */
- /* tx_bytes kept by driver. */
- /* rx_errors will be the sum of the rx errors available. */
- /* tx_errors will be the sum of the tx errors available. */
- /* rx_dropped (unable to allocate skb) will be maintained by driver */
- /* tx_dropped (unable to allocate skb) will be maintained by driver */
+/* ----------------------------------------------------------------------
+ * clear_statistics
+ *
+ * NOTE: The hardware clears the statistics registers after a read.
+ */
- /* multicast */
+static void clear_statistics(struct appnic_device *pdata)
+{
+ /* Clear memory. */
- waste = read_mac(APPNIC_RX_STAT_MULTICAST);
+ memset((void *) &(pdata->stats), 0, sizeof(struct net_device_stats));
- /* collisions will be the sum of the three following. */
+ /* Clear counters by reading them. */
- waste = read_mac(APPNIC_TX_STATUS_LATE_COLLISION);
- waste = read_mac(APPNIC_TX_STATUS_EXCESSIVE_COLLISION);
- waste = read_mac(APPNIC_TX_STAT_COLLISION_ABOVE_WATERMARK);
+ /* stats.rx_packets */
+ read_mac(APPNIC_RX_STAT_PACKET_OK);
- /* rx_length_errors will be the sum of the two following. */
+ /* stats.tx_packets */
+ read_mac(APPNIC_TX_STAT_PACKET_OK);
- waste = read_mac(APPNIC_RX_STAT_UNDERSIZE);
- waste = read_mac(APPNIC_RX_STAT_OVERSIZE);
+ /* stats.rx_bytes - Updated by this driver.
+ * stats.tx_bytes - Updated by this driver.
+ * stats.rx_errors - The sum of all RX errors available.
+ * stats.tx_errors - The sum of all TX errors available.
+ * stats.rx_dropped (unable to allocate skb) - Updated by the stack.
+ * stats.tx_dropped (unable to allocate skb) - Updated by the stack.
+ */
- /* rx_over_errors (out of descriptors?) maintained by the driver. */
- /* rx_crc_errors */
+ /* stats.multicast */
+ read_mac(APPNIC_RX_STAT_MULTICAST);
- waste = read_mac(APPNIC_RX_STAT_CRC_ERROR);
+ /* stats.collisions - The sum of the following driver stats. */
+ read_mac(APPNIC_TX_STATUS_LATE_COLLISION);
+ read_mac(APPNIC_TX_STATUS_EXCESSIVE_COLLISION);
+ read_mac(APPNIC_TX_STAT_COLLISION_ABOVE_WATERMARK);
- /* rx_frame_errors */
+ /* stats.rx_length_errors - The sum of the following driver stats. */
+ read_mac(APPNIC_RX_STAT_UNDERSIZE);
+ read_mac(APPNIC_RX_STAT_OVERSIZE);
- waste = read_mac(APPNIC_RX_STAT_ALIGN_ERROR);
+ /* stats.rx_over_errors - Not maintained by this driver. */
- /* rx_fifo_errors */
+ /* stats.rx_crc_errors */
+ read_mac(APPNIC_RX_STAT_CRC_ERROR);
- waste = read_mac(APPNIC_RX_STAT_OVERFLOW);
+ /* stats.rx_frame_errors */
+ read_mac(APPNIC_RX_STAT_ALIGN_ERROR);
- /* rx_missed will not be maintained. */
- /* tx_aborted_errors will be maintained by the driver. */
- /* tx_carrier_errors will not be maintained. */
- /* tx_fifo_errors */
+ /* stats.rx_fifo_errors */
+ read_mac(APPNIC_RX_STAT_OVERFLOW);
- waste = read_mac(APPNIC_TX_STAT_UNDERRUN);
+ /* stats.rx_missed - Not maintained by this driver.
+ * stats.tx_aborted_errors - Not maintained by this driver.
+ * stats.tx_carrier_errors - Not maintained by this driver.
+ */
- /* tx_heartbeat_errors */
- /* tx_window_errors */
+ /* stats.tx_fifo_errors */
+ read_mac(APPNIC_TX_STAT_UNDERRUN);
- /* rx_compressed will not be maintained. */
- /* tx_compressed will not be maintained. */
+ /* stats.tx_heartbeat_errors - Not maintained by this driver.
+ * stats.tx_window_errors - Not mainteaned by this driver.
+ * stats.rx_compressed - Not maintained by this driver.
+ * stats.tx_compressed - Not maintained by this driver.
+ */
- /* That's all. */
return;
}
/* ----------------------------------------------------------------------
* get_hw_statistics
*
- * -- NOTES --
- *
- * 1) The hardware clears the statistics registers after a read.
+ * NOTE: The hardware clears the statistics registers after a read.
*/
static void get_hw_statistics(struct appnic_device *pdata)
{
unsigned long flags;
- /* tx_packets */
+ /* stats.tx_packets */
pdata->stats.tx_packets += read_mac(APPNIC_TX_STAT_PACKET_OK);
- /* multicast */
+ /* stats.multicast */
pdata->stats.multicast += read_mac(APPNIC_RX_STAT_MULTICAST);
- /* collision */
+ /* stats.collision */
pdata->stats.collisions += read_mac(APPNIC_TX_STATUS_LATE_COLLISION);
pdata->stats.collisions +=
read_mac(APPNIC_TX_STATUS_EXCESSIVE_COLLISION);
pdata->stats.collisions +=
read_mac(APPNIC_TX_STAT_COLLISION_ABOVE_WATERMARK);
- /* rx_length_errors */
+ /* stats.rx_length_errors */
pdata->stats.rx_length_errors += read_mac(APPNIC_RX_STAT_UNDERSIZE);
pdata->stats.rx_length_errors += read_mac(APPNIC_RX_STAT_OVERSIZE);
- /* tx_fifo_errors */
+ /* stats.tx_fifo_errors */
pdata->stats.tx_fifo_errors += read_mac(APPNIC_TX_STAT_UNDERRUN);
/* Lock this section out so the statistics maintained by the driver
* don't get clobbered.
*/
+
spin_lock_irqsave(&pdata->dev_lock, flags);
pdata->stats.rx_errors +=
@@ -559,7 +512,6 @@ static void get_hw_statistics(struct appnic_device *pdata)
spin_unlock_irqrestore(&pdata->dev_lock, flags);
- /* That's all. */
return;
}
@@ -665,13 +617,12 @@ static void queue_decrement(union appnic_queue_pointer *queue,
* disable_rx_tx
*/
-static void disable_rx_tx(void)
+static void disable_rx_tx(struct net_device *dev)
{
+ struct appnic_device *pdata = netdev_priv(dev);
unsigned long tx_configuration;
unsigned long rx_configuration;
- pr_info("%s: Disabling the interface.\n", LSI_DRV_NAME);
-
rx_configuration = read_mac(APPNIC_RX_CONF);
rx_configuration &= ~APPNIC_RX_CONF_ENABLE;
write_mac(rx_configuration, APPNIC_RX_CONF);
@@ -681,7 +632,6 @@ static void disable_rx_tx(void)
write_mac(tx_configuration, APPNIC_TX_CONF);
- /* That's all. */
return;
}
@@ -698,14 +648,17 @@ static void disable_rx_tx(void)
static void handle_transmit_interrupt(struct net_device *dev)
{
struct appnic_device *pdata = netdev_priv(dev);
+ union appnic_queue_pointer queue;
/* The hardware's tail pointer should be one descriptor (or more)
* ahead of software's copy.
*/
- while (0 < queue_initialized(SWAB_QUEUE_POINTER(pdata->tx_tail),
- pdata->tx_tail_copy, pdata->tx_num_desc)) {
+ queue = swab_queue_pointer(pdata->tx_tail);
+ while (0 < queue_initialized(queue, pdata->tx_tail_copy,
+ pdata->tx_num_desc)) {
queue_increment(&pdata->tx_tail_copy, pdata->tx_num_desc);
+ queue = swab_queue_pointer(pdata->tx_tail);
}
return;
@@ -724,18 +677,16 @@ static void lsinet_rx_packet(struct net_device *dev)
unsigned error_num = 0;
unsigned long ok_stat = 0, overflow_stat = 0;
unsigned long crc_stat = 0, align_stat = 0;
-
- spin_lock(&pdata->extra_lock);
+ union appnic_queue_pointer queue;
readdescriptor(((unsigned long)pdata->rx_desc +
pdata->rx_tail_copy.bits.offset), &descriptor);
- sk_buff = dev_alloc_skb(1600);
+ sk_buff = dev_alloc_skb(LSINET_MAX_MTU);
if ((struct sk_buff *)0 == sk_buff) {
pr_err("%s: dev_alloc_skb() failed! Dropping packet.\n",
LSI_DRV_NAME);
- spin_unlock(&pdata->extra_lock);
return;
}
@@ -746,25 +697,18 @@ static void lsinet_rx_packet(struct net_device *dev)
/* Copy the received packet into the skb. */
- while (0 < queue_initialized(SWAB_QUEUE_POINTER(pdata->rx_tail),
- pdata->rx_tail_copy, pdata->rx_num_desc)) {
+ queue = swab_queue_pointer(pdata->rx_tail);
+ while (0 < queue_initialized(queue, pdata->rx_tail_copy,
+ pdata->rx_num_desc)) {
-#ifdef CONFIG_PRELOAD_RX_BUFFERS
{
unsigned char *buffer;
buffer = skb_put(sk_buff, descriptor.pdu_length);
- memcmp(buffer, buffer, descriptor.pdu_length);
memcpy((void *)buffer,
(void *)(descriptor.host_data_memory_pointer +
pdata->dma_alloc_offset_rx),
descriptor.pdu_length);
}
-#else
- memcpy((void *)skb_put(sk_buff, descriptor.pdu_length),
- (void *)(descriptor.host_data_memory_pointer +
- pdata->dma_alloc_offset_rx),
- descriptor.pdu_length);
-#endif
bytes_copied += descriptor.pdu_length;
descriptor.data_transfer_length = pdata->rx_buf_per_desc;
writedescriptor(((unsigned long)pdata->rx_desc +
@@ -778,6 +722,7 @@ static void lsinet_rx_packet(struct net_device *dev)
readdescriptor(((unsigned long)pdata->rx_desc +
pdata->rx_tail_copy.bits.offset),
&descriptor);
+ queue = swab_queue_pointer(pdata->rx_tail);
}
if (0 == descriptor.end_of_packet) {
@@ -789,29 +734,15 @@ static void lsinet_rx_packet(struct net_device *dev)
} else {
if (0 == error_num) {
- struct ethhdr *ethhdr =
- (struct ethhdr *) sk_buff->data;
- unsigned char broadcast[] = { 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff };
- unsigned char multicast[] = { 0x01, 0x00 };
-
- if ((0 == memcmp((const void *)&(ethhdr->h_dest[0]),
- (const void *)&(dev->dev_addr[0]),
- sizeof(ethhdr->h_dest))) ||
- (0 == memcmp((const void *)&(ethhdr->h_dest[0]),
- (const void *) &(broadcast[0]),
- sizeof(ethhdr->h_dest))) ||
- (0 == memcmp((const void *)&(ethhdr->h_dest[0]),
- (const void *) &(multicast[0]),
- sizeof(multicast)))) {
-
+ struct ethhdr *ethhdr = (struct ethhdr *) sk_buff->data;
+ if (mac_addr_valid(dev, ðhdr->h_dest[0])) {
pdata->stats.rx_bytes += bytes_copied;
- ++pdata->stats.rx_packets;
+ pdata->stats.rx_packets++;
sk_buff->dev = dev;
sk_buff->protocol = eth_type_trans(sk_buff,
dev);
if (netif_receive_skb(sk_buff) == NET_RX_DROP)
- ++dropped_by_stack;
+ pdata->dropped_by_stack++;
} else {
dev_kfree_skb(sk_buff);
}
@@ -819,17 +750,14 @@ static void lsinet_rx_packet(struct net_device *dev)
dev_kfree_skb(sk_buff);
if (0 != overflow_stat)
- ++pdata->stats.rx_fifo_errors;
+ pdata->stats.rx_fifo_errors++;
else if (0 != crc_stat)
- ++pdata->stats.rx_crc_errors;
+ pdata->stats.rx_crc_errors++;
else if (0 != align_stat)
- ++pdata->stats.rx_frame_errors;
+ pdata->stats.rx_frame_errors++;
}
}
- spin_unlock(&pdata->extra_lock);
-
- /* That's all. */
return;
}
@@ -840,34 +768,38 @@ static void lsinet_rx_packet(struct net_device *dev)
static int lsinet_rx_packets(struct net_device *dev, int max)
{
struct appnic_device *pdata = netdev_priv(dev);
- union appnic_queue_pointer queue;
+ union appnic_queue_pointer orig_queue, new_queue;
int updated_head_pointer = 0;
int packets = 0;
- queue.raw = pdata->rx_tail_copy.raw;
+ new_queue.raw = pdata->rx_tail_copy.raw;
- /* Receive Packets. */
- while (0 < queue_initialized(SWAB_QUEUE_POINTER(pdata->rx_tail),
- queue, pdata->rx_num_desc)) {
+ /* Receive Packets */
+
+ orig_queue = swab_queue_pointer(pdata->rx_tail);
+ while (0 < queue_initialized(orig_queue, new_queue,
+ pdata->rx_num_desc)) {
struct appnic_dma_descriptor descriptor;
readdescriptor(((unsigned long)pdata->rx_desc +
- queue.bits.offset),
+ new_queue.bits.offset),
&descriptor);
if (0 != descriptor.end_of_packet) {
lsinet_rx_packet(dev);
- ++packets;
- queue.raw = pdata->rx_tail_copy.raw;
+ packets++;
+ new_queue.raw = pdata->rx_tail_copy.raw;
if ((-1 != max) && (packets == max))
break;
} else {
- queue_increment(&queue, pdata->rx_num_desc);
+ queue_increment(&new_queue, pdata->rx_num_desc);
}
+ orig_queue = swab_queue_pointer(pdata->rx_tail);
}
- /* Update the Head Pointer. */
+ /* Update the Head Pointer */
+
while (1 < queue_uninitialized(pdata->rx_head,
pdata->rx_tail_copy,
pdata->rx_num_desc)) {
@@ -904,36 +836,38 @@ static int lsinet_poll(struct napi_struct *napi, int budget)
struct appnic_device *pdata =
container_of(napi, struct appnic_device, napi);
struct net_device *dev = pdata->device;
- union appnic_queue_pointer queue;
- int cur_budget = budget;
+ int work_done = 0;
unsigned long dma_interrupt_status;
- queue.raw = pdata->rx_tail_copy.raw;
-
do {
/* Acknowledge the RX interrupt. */
write_mac(~APPNIC_DMA_INTERRUPT_ENABLE_RECEIVE,
APPNIC_DMA_INTERRUPT_STATUS);
- cur_budget -= lsinet_rx_packets(dev, cur_budget);
- if (0 == cur_budget)
+ /* Get Rx packets. */
+ work_done += lsinet_rx_packets(dev, budget - work_done);
+
+ /* We've hit the budget limit. */
+ if (work_done == budget)
break;
dma_interrupt_status = read_mac(APPNIC_DMA_INTERRUPT_STATUS);
- } while ((RX_INTERRUPT(dma_interrupt_status)) && cur_budget);
+ } while (RX_INTERRUPT(dma_interrupt_status));
- napi_complete(napi);
+ if (work_done < budget) {
+ napi_complete(napi);
- /* Re-enable receive interrupts (and preserve
- * the already enabled TX interrupt).
- */
- write_mac((APPNIC_DMA_INTERRUPT_ENABLE_RECEIVE |
- APPNIC_DMA_INTERRUPT_ENABLE_TRANSMIT),
- APPNIC_DMA_INTERRUPT_ENABLE);
+ /* Re-enable receive interrupts (and preserve
+ * the already enabled TX interrupt).
+ */
+ write_mac((APPNIC_DMA_INTERRUPT_ENABLE_RECEIVE |
+ APPNIC_DMA_INTERRUPT_ENABLE_TRANSMIT),
+ APPNIC_DMA_INTERRUPT_ENABLE);
+ }
- return 0;
+ return work_done;
}
/* ----------------------------------------------------------------------
@@ -953,23 +887,23 @@ static irqreturn_t appnic_isr(int irq, void *device_id)
/* Get the status. */
dma_interrupt_status = read_mac(APPNIC_DMA_INTERRUPT_STATUS);
- /* NAPI - don't ack RX interrupt. */
+ /* NAPI - don't ack RX interrupt */
write_mac(APPNIC_DMA_INTERRUPT_ENABLE_RECEIVE,
APPNIC_DMA_INTERRUPT_STATUS);
/* Handle interrupts. */
if (TX_INTERRUPT(dma_interrupt_status)) {
/* transmition complete */
- ++transmit_interrupts;
+ pdata->transmit_interrupts++;
handle_transmit_interrupt(dev);
}
if (RX_INTERRUPT(dma_interrupt_status)) {
- ++receive_interrupts;
+ pdata->receive_interrupts++;
if (napi_schedule_prep(&pdata->napi)) {
/* Disable RX interrupts and tell the
- * system we've got work.
+ * system we've got work
*/
write_mac(APPNIC_DMA_INTERRUPT_ENABLE_TRANSMIT,
APPNIC_DMA_INTERRUPT_ENABLE);
@@ -980,7 +914,7 @@ static irqreturn_t appnic_isr(int irq, void *device_id)
}
}
- /* Release the lock. */
+ /* Release the lock */
spin_unlock_irqrestore(&pdata->dev_lock, flags);
return IRQ_HANDLED;
@@ -1068,7 +1002,7 @@ static int appnic_stop(struct net_device *dev)
napi_disable(&pdata->napi);
/* Stop the receiver and transmitter. */
- disable_rx_tx();
+ disable_rx_tx(dev);
/* Bring the PHY down. */
if (pdata->phy_dev)
@@ -1096,22 +1030,24 @@ static int appnic_hard_start_xmit(struct sk_buff *skb,
struct appnic_device *pdata = netdev_priv(dev);
int length;
int buf_per_desc;
+ union appnic_queue_pointer queue;
length = skb->len < ETH_ZLEN ? ETH_ZLEN : skb->len;
buf_per_desc = pdata->tx_buf_sz / pdata->tx_num_desc;
/* If enough transmit descriptors are available, copy and transmit. */
+ queue = swab_queue_pointer(pdata->tx_tail);
while (((length / buf_per_desc) + 1) >=
queue_uninitialized(pdata->tx_head,
- SWAB_QUEUE_POINTER(pdata->tx_tail),
+ queue,
pdata->tx_num_desc)) {
handle_transmit_interrupt(dev);
+ queue = swab_queue_pointer(pdata->tx_tail);
}
if (((length / buf_per_desc) + 1) <
- queue_uninitialized(pdata->tx_head,
- SWAB_QUEUE_POINTER(pdata->tx_tail),
+ queue_uninitialized(pdata->tx_head, queue,
pdata->tx_num_desc)) {
int bytes_copied = 0;
struct appnic_dma_descriptor descriptor;
@@ -1145,11 +1081,12 @@ static int appnic_hard_start_xmit(struct sk_buff *skb,
descriptor.data_transfer_length =
(length - bytes_copied);
descriptor.end_of_packet = 1;
-#ifdef CONFIG_DISABLE_TX_INTERRUPTS
+ /*
+ * Leave TX interrupts disabled. We work
+ * the same with or w/o them. Set to "1"
+ * if we ever want to enable them though.
+ */
descriptor.interrupt_on_completion = 0;
-#else
- descriptor.interrupt_on_completion = 1;
-#endif
bytes_copied = length;
}
@@ -1163,22 +1100,22 @@ static int appnic_hard_start_xmit(struct sk_buff *skb,
descriptor.start_of_packet = 0;
}
-#ifdef CONFIG_ARM
- /* ARM Data sync barrier. */
- asm volatile ("mcr p15,0,%0,c7,c10,4" : : "r" (0));
-#endif
+ /* Data sync barrier. */
+ rmb();
+
write_mac(pdata->tx_head.raw, APPNIC_DMA_TX_HEAD_POINTER);
dev->trans_start = jiffies;
} else {
- ++out_of_tx_descriptors;
+ pdata->out_of_tx_descriptors++;
pr_err("%s: No transmit descriptors available!\n",
LSI_DRV_NAME);
+ return NETDEV_TX_BUSY;
}
/* Free the socket buffer. */
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
/* ----------------------------------------------------------------------
@@ -1197,8 +1134,6 @@ static struct net_device_stats *appnic_get_stats(struct net_device *dev)
get_hw_statistics(pdata);
- /* That's all. */
-
return &pdata->stats;
}
@@ -1208,14 +1143,18 @@ static struct net_device_stats *appnic_get_stats(struct net_device *dev)
static int appnic_set_mac_address(struct net_device *dev, void *data)
{
+ struct appnic_device *pdata = netdev_priv(dev);
struct sockaddr *address = data;
unsigned long swap_source_address;
if (netif_running(dev))
return -EBUSY;
- memcpy(dev->dev_addr, address->sa_data, 6);
- memcpy(dev->perm_addr, address->sa_data, 6);
+ if (!is_valid_ether_addr(address->sa_data))
+ return -EADDRNOTAVAIL;
+
+ memcpy(dev->dev_addr, address->sa_data, ETH_ALEN);
+ memcpy(dev->perm_addr, address->sa_data, ETH_ALEN);
swap_source_address = ((address->sa_data[4]) << 8) |
address->sa_data[5];
@@ -1232,9 +1171,102 @@ static int appnic_set_mac_address(struct net_device *dev, void *data)
}
/* ======================================================================
- ETHTOOL Operations
- ======================================================================
-*/
+ * ETHTOOL Operations
+ * ======================================================================
+ */
+
+enum {NETDEV_STATS, APPNIC_STATS};
+
+struct appnic_stats {
+ char stat_string[ETH_GSTRING_LEN];
+ int sizeof_stat;
+ int stat_offset;
+};
+
+#define APPNIC_STAT(str, m) { \
+ .stat_string = str, \
+ .sizeof_stat = sizeof(((struct appnic_device *)0)->m), \
+ .stat_offset = offsetof(struct appnic_device, m) }
+
+static const struct appnic_stats appnic_gstrings_stats[] = {
+ APPNIC_STAT("rx_packets", stats.rx_packets),
+ APPNIC_STAT("tx_packets", stats.tx_packets),
+ APPNIC_STAT("rx_bytes", stats.rx_bytes),
+ APPNIC_STAT("tx_bytes", stats.tx_bytes),
+ APPNIC_STAT("rx_errors", stats.rx_errors),
+ APPNIC_STAT("tx_errors", stats.tx_errors),
+ APPNIC_STAT("rx_dropped", stats.rx_dropped),
+ APPNIC_STAT("tx_dropped", stats.tx_dropped),
+ APPNIC_STAT("multicast", stats.multicast),
+ APPNIC_STAT("collisions", stats.collisions),
+ APPNIC_STAT("rx_length_errors", stats.rx_length_errors),
+ APPNIC_STAT("rx_crc_errors", stats.rx_crc_errors),
+ APPNIC_STAT("rx_frame_errors", stats.rx_frame_errors),
+ APPNIC_STAT("rx_fifo_errors", stats.rx_fifo_errors),
+ APPNIC_STAT("tx_fifo_errors", stats.tx_fifo_errors),
+
+ APPNIC_STAT("dropped_by_stack", dropped_by_stack),
+ APPNIC_STAT("out_of_tx_descriptors", out_of_tx_descriptors),
+ APPNIC_STAT("transmit_interrupts", transmit_interrupts),
+ APPNIC_STAT("receive_interrupts", receive_interrupts),
+};
+#define APPNIC_GLOBAL_STATS_LEN ARRAY_SIZE(appnic_gstrings_stats)
+#define APPNIC_STATS_LEN (APPNIC_GLOBAL_STATS_LEN)
+
+/* ----------------------------------------------------------------------
+ * appnic_get_ethtool_stats
+ */
+
+static void appnic_get_ethtool_stats(struct net_device *dev,
+ struct ethtool_stats *stats,
+ u64 *data)
+{
+ struct appnic_device *pdata = netdev_priv(dev);
+ int i;
+ char *p = NULL;
+
+ get_hw_statistics(pdata);
+ for (i = 0; i < APPNIC_GLOBAL_STATS_LEN; i++) {
+ p = (char *) pdata + appnic_gstrings_stats[i].stat_offset;
+ data[i] = (appnic_gstrings_stats[i].sizeof_stat ==
+ sizeof(u64)) ? *(u64 *)p : *(u32 *)p;
+ }
+}
+
+/* ----------------------------------------------------------------------
+ * appnic_get_strings
+ */
+
+static void appnic_get_strings(struct net_device *netdev, u32 stringset,
+ u8 *data)
+{
+ u8 *p = data;
+ int i;
+
+ switch (stringset) {
+ case ETH_SS_STATS:
+ for (i = 0; i < APPNIC_GLOBAL_STATS_LEN; i++) {
+ memcpy(p, appnic_gstrings_stats[i].stat_string,
+ ETH_GSTRING_LEN);
+ p += ETH_GSTRING_LEN;
+ }
+ break;
+ }
+}
+
+/* ----------------------------------------------------------------------
+ * appnic_get_sset_count
+ */
+
+static int appnic_get_sset_count(struct net_device *netdev, int sset)
+{
+ switch (sset) {
+ case ETH_SS_STATS:
+ return APPNIC_STATS_LEN;
+ default:
+ return -EOPNOTSUPP;
+ }
+}
/* ----------------------------------------------------------------------
* appnic_get_drvinfo
@@ -1245,6 +1277,8 @@ static void appnic_get_drvinfo(struct net_device *dev,
{
strcpy(info->driver, LSI_DRV_NAME);
strcpy(info->version, LSI_DRV_VERSION);
+ strlcpy(info->bus_info, dev_name(dev->dev.parent),
+ sizeof(info->bus_info));
}
/* ----------------------------------------------------------------------
@@ -1263,17 +1297,21 @@ static int appnic_get_settings(struct net_device *dev,
return phy_ethtool_gset(phydev, cmd);
}
-/* Fill in the struture... */
+/* Fill in the struture... */
+
static const struct ethtool_ops appnic_ethtool_ops = {
- .get_drvinfo = appnic_get_drvinfo,
- .get_settings = appnic_get_settings
+ .get_drvinfo = appnic_get_drvinfo,
+ .get_settings = appnic_get_settings,
+ .get_ethtool_stats = appnic_get_ethtool_stats,
+ .get_strings = appnic_get_strings,
+ .get_sset_count = appnic_get_sset_count,
};
/* ======================================================================
- Linux Module Interface.
- ======================================================================
-*/
+ * Linux Module Interface.
+ * ======================================================================
+ */
static const struct net_device_ops appnic_netdev_ops = {
.ndo_open = appnic_open,
@@ -1300,33 +1338,33 @@ int appnic_init(struct net_device *dev)
struct appnic_dma_descriptor descriptor;
struct sockaddr address;
unsigned long node_cfg;
+ int rc = 0;
-#ifdef CONFIG_ARM
/* Set FEMAC to uncached */
- gpreg_base = ioremap(GPREG_BASE, 0x1000);
- writel(0x0, gpreg_base+0x78);
-#endif
+ femac_uncache(pdata);
/* Reset the MAC. */
+
write_mac(0x80000000, APPNIC_DMA_PCI_CONTROL);
/* Allocate memory and initialize the descriptors. */
- /* fixup num_[rt]x_desc */
+ /* fixup num_[rt]x_desc. */
+
if (0 != (rx_num_desc % DESCRIPTOR_GRANULARITY)) {
- pr_warn("%s: rx_num_desc was not a multiple of %d.\n",
- LSI_DRV_NAME, DESCRIPTOR_GRANULARITY);
- rx_num_desc += DESCRIPTOR_GRANULARITY -
- (rx_num_desc % DESCRIPTOR_GRANULARITY);
+ pr_err("%s: rx_num_desc was not a multiple of %d.\n",
+ LSI_DRV_NAME, DESCRIPTOR_GRANULARITY);
+ rc = -EINVAL;
+ goto err_param;
}
pdata->rx_num_desc = rx_num_desc;
if (0 != (tx_num_desc % DESCRIPTOR_GRANULARITY)) {
- pr_warn("%s: tx_num_desc was not a multiple of %d.\n",
- LSI_DRV_NAME, DESCRIPTOR_GRANULARITY);
- tx_num_desc += DESCRIPTOR_GRANULARITY -
- (tx_num_desc % DESCRIPTOR_GRANULARITY);
+ pr_err("%s: tx_num_desc was not a multiple of %d.\n",
+ LSI_DRV_NAME, DESCRIPTOR_GRANULARITY);
+ rc = -EINVAL;
+ goto err_param;
}
pdata->tx_num_desc = tx_num_desc;
@@ -1334,20 +1372,21 @@ int appnic_init(struct net_device *dev)
/* up [rt]x_buf_sz. Must be some multiple of 64 bytes
* per descriptor.
*/
+
if (0 != (rx_buf_sz % (BUFFER_ALIGNMENT * rx_num_desc))) {
- pr_warn("%s: rx_buf_sz was not a multiple of %d.\n",
- LSI_DRV_NAME, (BUFFER_ALIGNMENT * rx_num_desc));
- rx_buf_sz += (BUFFER_ALIGNMENT * rx_num_desc) -
- (rx_buf_sz % (BUFFER_ALIGNMENT * rx_num_desc));
+ pr_err("%s: rx_buf_sz was not a multiple of %d.\n",
+ LSI_DRV_NAME, (BUFFER_ALIGNMENT * rx_num_desc));
+ rc = -EINVAL;
+ goto err_param;
}
pdata->rx_buf_sz = rx_buf_sz;
if (0 != (tx_buf_sz % (BUFFER_ALIGNMENT * tx_num_desc))) {
- pr_warn("%s: tx_buf_sz was not a multiple of %d.\n",
- LSI_DRV_NAME, (BUFFER_ALIGNMENT * tx_num_desc));
- tx_buf_sz += (BUFFER_ALIGNMENT * tx_num_desc) -
- (tx_buf_sz % (BUFFER_ALIGNMENT * tx_num_desc));
+ pr_err("%s: tx_buf_sz was not a multiple of %d.\n",
+ LSI_DRV_NAME, (BUFFER_ALIGNMENT * tx_num_desc));
+ rc = -EINVAL;
+ goto err_param;
}
pdata->tx_buf_sz = tx_buf_sz;
@@ -1357,6 +1396,7 @@ int appnic_init(struct net_device *dev)
* small since mappings obtained from dma_alloc_coherent() have
* a minimum size of one page.
*/
+
pdata->dma_alloc_size =
/* The tail pointers (rx and tx) */
(sizeof(union appnic_queue_pointer) * 2) +
@@ -1377,81 +1417,16 @@ int appnic_init(struct net_device *dev)
/* The TX buffer (and padding...) */
(pdata->tx_buf_sz) + (BUFFER_ALIGNMENT);
- /* This needs to be set to something sane for
- * dma_alloc_coherent().
- */
-
-#if defined(CONFIG_ARM)
- pdata->dma_alloc = (void *)
- dma_alloc_coherent(NULL,
- pdata->dma_alloc_size,
- &pdata->dma_alloc_dma,
- GFP_KERNEL);
-#else
- dev->dev.archdata.dma_ops = &dma_direct_ops;
-
- pdata->dma_alloc = (void *)
- dma_alloc_coherent(&dev->dev,
- pdata->dma_alloc_size,
- &pdata->dma_alloc_dma,
- GFP_KERNEL);
-#endif
-
- if ((void *)0 == pdata->dma_alloc) {
- pr_err("%s: Can't allocate %d bytes of DMA-able memory!\n",
- LSI_DRV_NAME, pdata->dma_alloc_size);
- kfree(pdata);
- return -ENOMEM;
- }
-
- pdata->dma_alloc_offset = (int)pdata->dma_alloc -
- (int)pdata->dma_alloc_dma;
-
-#ifdef CONFIG_ARM
- pdata->dma_alloc_rx = (void *)dma_alloc_coherent(NULL,
-#else
- pdata->dma_alloc_rx = (void *)dma_alloc_coherent(&dev->dev,
-#endif
- pdata->dma_alloc_size_rx,
- &pdata->dma_alloc_dma_rx,
- GFP_KERNEL);
-
- if ((void *)0 == pdata->dma_alloc_rx) {
- pr_err("%s: Can't allocate %d bytes of RX DMA-able memory!\n",
- LSI_DRV_NAME, pdata->dma_alloc_size_rx);
- dma_free_coherent(&dev->dev, pdata->dma_alloc_size,
- pdata->dma_alloc, pdata->dma_alloc_dma);
- kfree(pdata);
- return -ENOMEM;
- }
+ /* Allocate the buffers. */
- pdata->dma_alloc_offset_rx = (int)pdata->dma_alloc_rx -
- (int)pdata->dma_alloc_dma_rx;
-
-#ifdef CONFIG_ARM
- pdata->dma_alloc_tx = (void *)dma_alloc_coherent(NULL,
-#else
- pdata->dma_alloc_tx = (void *)dma_alloc_coherent(&dev->dev,
-#endif
- pdata->dma_alloc_size_tx,
- &pdata->dma_alloc_dma_tx,
- GFP_KERNEL);
-
- if ((void *)0 == pdata->dma_alloc_tx) {
- pr_err("%s: Can't allocate %d bytes of TX DMA-able memory!\n",
- LSI_DRV_NAME, pdata->dma_alloc_size_tx);
- dma_free_coherent(&dev->dev, pdata->dma_alloc_size,
- pdata->dma_alloc, pdata->dma_alloc_dma);
- dma_free_coherent(&dev->dev, pdata->dma_alloc_size_rx,
- pdata->dma_alloc_rx, pdata->dma_alloc_dma_rx);
- kfree(pdata);
- return -ENOMEM;
+ rc = femac_alloc_mem_buffers(dev);
+ if (rc != 0) {
+ pr_err("%s: Can't allocate DMA-able memory!\n", LSI_DRV_NAME);
+ goto err_mem_buffers;
}
- pdata->dma_alloc_offset_tx = (int)pdata->dma_alloc_tx -
- (int)pdata->dma_alloc_dma_tx;
-
/* Initialize the tail pointers. */
+
dma_offset = pdata->dma_alloc;
pdata->rx_tail = (union appnic_queue_pointer *)dma_offset;
@@ -1466,8 +1441,8 @@ int appnic_init(struct net_device *dev)
dma_offset += sizeof(union appnic_queue_pointer);
memset((void *)pdata->tx_tail, 0, sizeof(union appnic_queue_pointer));
-
/* Initialize the descriptor pointers. */
+
pdata->rx_desc = (struct appnic_dma_descriptor *)ALIGN64B(dma_offset);
pdata->rx_desc_dma = (int)pdata->rx_desc - (int)pdata->dma_alloc_offset;
dma_offset += (sizeof(struct appnic_dma_descriptor) *
@@ -1483,6 +1458,7 @@ int appnic_init(struct net_device *dev)
(sizeof(struct appnic_dma_descriptor) * pdata->tx_num_desc));
/* Initialize the buffer pointers. */
+
dma_offset = pdata->dma_alloc_rx;
pdata->rx_buf = (void *)ALIGN64B(dma_offset);
@@ -1498,6 +1474,7 @@ int appnic_init(struct net_device *dev)
pdata->tx_buf_per_desc = pdata->tx_buf_sz / pdata->tx_num_desc;
/* Initialize the descriptors. */
+
buf = (unsigned long)pdata->rx_buf_dma;
for (index = 0; index < pdata->rx_num_desc; ++index) {
memset((void *) &descriptor, 0,
@@ -1531,16 +1508,18 @@ int appnic_init(struct net_device *dev)
}
/* Initialize the spinlocks. */
+
spin_lock_init(&pdata->dev_lock);
- spin_lock_init(&pdata->extra_lock);
/* Take MAC out of reset. */
+
write_mac(0x0, APPNIC_RX_SOFT_RESET);
write_mac(0x1, APPNIC_RX_MODE);
write_mac(0x0, APPNIC_TX_SOFT_RESET);
write_mac(0x1, APPNIC_TX_MODE);
/* Set the watermark. */
+
ncr_read(NCP_REGION_ID(0x16, 0xff), 0x10, 4, &node_cfg);
if (0 == (0x80000000 & node_cfg))
@@ -1557,24 +1536,27 @@ int appnic_init(struct net_device *dev)
write_mac(0x40010000, APPNIC_DMA_PCI_CONTROL);
write_mac(0x30000, APPNIC_DMA_CONTROL);
#ifdef CONFIG_ARM
- writel(0x280044, dma_base + 0x60);
- writel(0xc0, dma_base + 0x64);
+ writel(0x280044, (unsigned long)pdata->dma_base + 0x60);
+ writel(0xc0, (unsigned long)pdata->dma_base + 0x64);
#else
- out_le32(dma_base + 0x60, 0x280044);
- out_le32(dma_base + 0x64, 0xc0);
+ out_le32((unsigned *)pdata->dma_base + 0x60, 0x280044);
+ out_le32((unsigned *)pdata->dma_base + 0x64, 0xc0);
#endif
- /* Set the MAC address */
- pr_info("%s: MAC %02x:%02x:%02x:%02x:%02x:%02x\n", LSI_DRV_NAME,
- dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
- dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);
+ /* Set the MAC address. */
+ pr_info("%s: MAC %pM\n", LSI_DRV_NAME, dev->dev_addr);
- memcpy(&(address.sa_data[0]), dev->dev_addr, 6);
- appnic_set_mac_address(dev, &address);
+ memcpy(&(address.sa_data[0]), dev->dev_addr, ETH_ALEN);
+ rc = appnic_set_mac_address(dev, &address);
+ if (rc != 0) {
+ pr_err("%s: Unable to set MAC address!\n", LSI_DRV_NAME);
+ goto err_set_mac_addr;
+ }
/* Initialize the queue pointers. */
- /* Receiver */
+ /* Receiver. */
+
memset((void *)&pdata->rx_tail_copy, 0,
sizeof(union appnic_queue_pointer));
memset((void *)&pdata->rx_head, 0,
@@ -1588,6 +1570,7 @@ int appnic_init(struct net_device *dev)
/* Indicate that all of the receive descriptors
* are ready.
*/
+
pdata->rx_head.bits.offset = (pdata->rx_num_desc - 1) *
sizeof(struct appnic_dma_descriptor);
write_mac(pdata->rx_tail_dma, APPNIC_DMA_RX_TAIL_POINTER_ADDRESS);
@@ -1598,6 +1581,7 @@ int appnic_init(struct net_device *dev)
* tail pointer must be read and the head pointer (and
* local copy of the tail) based on it.
*/
+
pdata->rx_tail->raw =
read_mac(APPNIC_DMA_RX_TAIL_POINTER_LOCAL_COPY);
pdata->rx_tail_copy.raw = pdata->rx_tail->raw;
@@ -1607,7 +1591,8 @@ int appnic_init(struct net_device *dev)
(0 == pdata->rx_head.bits.generation_bit) ? 1 : 0;
write_mac(pdata->rx_head.raw, APPNIC_DMA_RX_HEAD_POINTER);
- /* Transmitter */
+ /* Transmitter. */
+
memset((void *) &pdata->tx_tail_copy, 0,
sizeof(union appnic_queue_pointer));
memset((void *) &pdata->tx_head, 0,
@@ -1625,41 +1610,43 @@ int appnic_init(struct net_device *dev)
* tail pointer must be read and the head pointer (and
* local copy of the tail) based on it.
*/
+
pdata->tx_tail->raw = read_mac(APPNIC_DMA_TX_TAIL_POINTER_LOCAL_COPY);
pdata->tx_tail_copy.raw = pdata->tx_tail->raw;
pdata->tx_head.raw = pdata->tx_tail->raw;
write_mac(pdata->tx_head.raw, APPNIC_DMA_TX_HEAD_POINTER);
- /* Clear statistics */
+ /* Clear statistics. */
+
clear_statistics(pdata);
- /* Fill in the net_device structure */
+ /* Fill in the net_device structure. */
+
ether_setup(dev);
-#ifdef CONFIG_ARM
- dev->irq = pdata->dma_interrupt;
-#else
- dev->irq = irq_create_mapping(NULL, pdata->dma_interrupt);
- if (NO_IRQ == dev->irq) {
- pr_err("%s: irq_create_mapping() failed\n", LSI_DRV_NAME);
- return -EBUSY;
- }
- if (0 != irq_set_irq_type(dev->irq, IRQ_TYPE_LEVEL_HIGH)) {
- pr_err("%s: set_irq_type() failed\n", LSI_DRV_NAME);
- return -EBUSY;
+ /* Setup IRQ. */
+ rc = femac_irq_setup(dev);
+ if (rc != 0) {
+ pr_err("%s: IRQ setup failed!\n", LSI_DRV_NAME);
+ goto err_irq_setup;
}
-#endif
dev->netdev_ops = &appnic_netdev_ops;
+ dev->ethtool_ops = &appnic_ethtool_ops;
- SET_ETHTOOL_OPS(dev, &appnic_ethtool_ops);
memset((void *) &pdata->napi, 0, sizeof(struct napi_struct));
netif_napi_add(dev, &pdata->napi,
lsinet_poll, LSINET_NAPI_WEIGHT);
pdata->device = dev;
- /* That's all */
return 0;
+
+err_irq_setup:
+err_set_mac_addr:
+ femac_free_mem_buffers(dev);
+err_mem_buffers:
+err_param:
+ return rc;
}
/* ----------------------------------------------------------------------
@@ -1672,9 +1659,11 @@ static int appnic_probe_config_dt(struct net_device *dev,
{
struct appnic_device *pdata = netdev_priv(dev);
const u32 *field;
+ const char *mac;
const char *macspeed;
- int length;
-#ifndef CONFIG_ARM
+#ifdef CONFIG_ARM
+ struct device_node *gp_node;
+#else
u64 value64;
u32 value32;
#endif
@@ -1683,44 +1672,44 @@ static int appnic_probe_config_dt(struct net_device *dev,
return -ENODEV;
#ifdef CONFIG_ARM
- rx_base = of_iomap(np, 0);
- tx_base = of_iomap(np, 1);
- dma_base = of_iomap(np, 2);
+ gp_node = of_find_compatible_node(NULL, NULL, "lsi,gpreg");
+ if (!gp_node) {
+ pr_err("%s: DTS is missing mode 'gpreg'\n", LSI_DRV_NAME);
+ return -ENODEV;
+ }
+ pdata->gpreg_base = of_iomap(gp_node, 0);
+
+ pdata->rx_base = of_iomap(np, 0);
+ pdata->tx_base = of_iomap(np, 1);
+ pdata->dma_base = of_iomap(np, 2);
+
+ pdata->tx_interrupt = irq_of_parse_and_map(np, 0);
+ pdata->rx_interrupt = irq_of_parse_and_map(np, 1);
+ pdata->dma_interrupt = irq_of_parse_and_map(np, 2);
#else
field = of_get_property(np, "enabled", NULL);
if (!field || (field && (0 == *field)))
- return -EINVAL;
+ goto device_tree_failed;
field = of_get_property(np, "reg", NULL);
- if (!field) {
- pr_err("%s: Couldn't get \"reg\" property.", LSI_DRV_NAME);
- return -EINVAL;
- }
+ if (!field)
+ goto device_tree_failed;
value64 = of_translate_address(np, field);
value32 = field[1];
field += 2;
- rx_base = ioremap(value64, value32);
+ pdata->rx_base = ioremap(value64, value32);
value64 = of_translate_address(np, field);
value32 = field[1];
field += 2;
- tx_base = ioremap(value64, value32);
+ pdata->tx_base = ioremap(value64, value32);
value64 = of_translate_address(np, field);
value32 = field[1];
field += 2;
- dma_base = ioremap(value64, value32);
-#endif
- pdata->rx_base = (unsigned long)rx_base;
- pdata->tx_base = (unsigned long)tx_base;
- pdata->dma_base = (unsigned long)dma_base;
+ pdata->dma_base = ioremap(value64, value32);
-#ifdef CONFIG_ARM
- pdata->tx_interrupt = irq_of_parse_and_map(np, 0);
- pdata->rx_interrupt = irq_of_parse_and_map(np, 1);
- pdata->dma_interrupt = irq_of_parse_and_map(np, 2);
-#else
field = of_get_property(np, "interrupts", NULL);
if (!field)
goto device_tree_failed;
@@ -1768,9 +1757,8 @@ static int appnic_probe_config_dt(struct net_device *dev,
pdata->phy_link_speed = 0;
pdata->phy_link_duplex = 0;
} else {
- pr_err(
- "Invalid phy-link value \"%s\" in DTS. Defaulting to \"auto\".\n",
- macspeed);
+ pr_err("Invalid phy-link value \"%s\" in DTS. Defaulting to \"auto\".\n",
+ macspeed);
pdata->phy_link_auto = 1;
}
} else {
@@ -1778,32 +1766,25 @@ static int appnic_probe_config_dt(struct net_device *dev,
pdata->phy_link_auto = 1;
}
- field = of_get_property(np, "mac-address", &length);
- if (!field || 6 != length) {
+ mac = of_get_mac_address(np);
+ if (!mac)
goto device_tree_failed;
- } else {
- int i;
- u8 *value;
- value = (u8 *)field;
-
- for (i = 0; i < 6; ++i)
- pdata->mac_addr[i] = value[i];
- }
-
- memcpy(dev->dev_addr, &pdata->mac_addr[0], 6);
- memcpy(dev->perm_addr, &pdata->mac_addr[0], 6);
+ memcpy(&pdata->mac_addr[0], mac, ETH_ALEN);
+ memcpy(dev->dev_addr, mac, ETH_ALEN);
+ memcpy(dev->perm_addr, mac, ETH_ALEN);
return 0;
device_tree_failed:
pr_err("%s: Reading Device Tree Failed\n", LSI_DRV_NAME);
- iounmap(rx_base);
- iounmap(tx_base);
- iounmap(dma_base);
#ifdef CONFIG_ARM
- iounmap(gpreg_base);
+ iounmap(pdata->gpreg_base);
#endif
+ iounmap(pdata->rx_base);
+ iounmap(pdata->tx_base);
+ iounmap(pdata->dma_base);
+
return -EINVAL;
}
#else
@@ -1834,7 +1815,7 @@ static int appnic_drv_probe(struct platform_device *pdev)
if (!dev) {
pr_err("%s: Couldn't allocate net device.\n", LSI_DRV_NAME);
rc = -ENOMEM;
- goto out;
+ goto err_alloc_etherdev;
}
SET_NETDEV_DEV(dev, &pdev->dev);
@@ -1850,12 +1831,12 @@ static int appnic_drv_probe(struct platform_device *pdev)
rc = appnic_probe_config_dt(dev, np);
if (rc == -EINVAL) {
- goto out;
- } else if (rc == -ENODEV) {
+ goto err_inval;
+ } else if (rc == -EINVAL) {
#ifdef CONFIG_MTD_NAND_EP501X_UBOOTENV
- /* Attempt to get device settings from the DTB failed, so
+ /* The attempt to get device settings from the DTB failed, so
* try to grab the ethernet MAC from the u-boot environment
* and use hard-coded values for device base addresses.
*/
@@ -1865,14 +1846,14 @@ static int appnic_drv_probe(struct platform_device *pdev)
if (0 != ubootenv_get("ethaddr", ethaddr_string)) {
pr_err("%s: Could not read ethernet address!\n",
LSI_DRV_NAME);
- return -EFAULT;
+ rc = -EINVAL;
+ goto err_inval;
} else {
-
- u8 mac_address[6];
+ u8 mac_address[ETH_ALEN];
int i = 0;
char *string = ethaddr_string;
- while ((0 != string) && (6 > i)) {
+ while ((0 != string) && (ETH_ALEN > i)) {
char *value;
unsigned long res;
value = strsep(&string, ":");
@@ -1881,29 +1862,23 @@ static int appnic_drv_probe(struct platform_device *pdev)
mac_address[i++] = (u8)res;
}
- memcpy(dev->dev_addr, mac_address, 6);
- memcpy(dev->perm_addr, mac_address, 6);
- dev->addr_len = 6;
+ memcpy(dev->dev_addr, mac_address, ETH_ALEN);
+ memcpy(dev->perm_addr, mac_address, ETH_ALEN);
+ dev->addr_len = ETH_ALEN;
pr_info("%s: Using Static Addresses and Interrupts",
LSI_DRV_NAME);
- rx_base = ioremap(0x002000480000ULL, 0x1000);
- pdata->rx_base =
- (unsigned long)ioremap(0x002000480000ULL, 0x1000);
- tx_base = ioremap(0x002000481000ULL, 0x1000);
- pdata->tx_base =
- (unsigned long)ioremap(0x002000481000ULL, 0x1000);
- dma_base = ioremap(0x002000482000ULL, 0x1000);
- pdata->dma_base =
- (unsigned long)ioremap(0x002000482000ULL, 0x1000);
+ pdata->rx_base = ioremap(0x002000480000ULL, 0x1000);
+ pdata->tx_base = ioremap(0x002000481000ULL, 0x1000);
+ pdata->dma_base = ioremap(0x002000482000ULL, 0x1000);
pdata->dma_interrupt = 33;
}
#else
/* Neither dtb info nor ubootenv driver found. */
pr_err("%s: Could not read ethernet address!", LSI_DRV_NAME);
- return -EBUSY;
+ rc = -EINVAL;
+ goto err_inval;
#endif
-
}
#ifdef CONFIG_MTD_NAND_EP501X_UBOOTENV
@@ -1918,8 +1893,10 @@ static int appnic_drv_probe(struct platform_device *pdev)
* since u-boot defaults this value as hex.
*/
unsigned long res;
- if (kstrtoul(uboot_env_string, 16, &res))
- return -EBUSY;
+ if (kstrtoul(uboot_env_string, 16, &res)) {
+ rc = -EINVAL;
+ goto err_inval;
+ }
pdata->ad_value = res;
}
}
@@ -1931,7 +1908,7 @@ static int appnic_drv_probe(struct platform_device *pdev)
if (0 != rc) {
pr_err("%s: appnic_init() failed: %d\n", LSI_DRV_NAME, rc);
rc = -ENODEV;
- goto out;
+ goto err_nodev;
}
/* Register the device. */
@@ -1939,7 +1916,7 @@ static int appnic_drv_probe(struct platform_device *pdev)
if (0 != rc) {
pr_err("%s: register_netdev() failed: %d\n", LSI_DRV_NAME, rc);
rc = -ENODEV;
- goto out;
+ goto err_nodev;
}
/* Initialize the PHY. */
@@ -1947,9 +1924,17 @@ static int appnic_drv_probe(struct platform_device *pdev)
if (rc) {
pr_warn("%s: Failed to initialize PHY", LSI_DRV_NAME);
rc = -ENODEV;
- goto out;
+ goto err_mii_init;
}
-out:
+
+ return 0;
+
+err_mii_init:
+ unregister_netdev(dev);
+err_nodev:
+err_inval:
+ free_netdev(dev);
+err_alloc_etherdev:
return rc;
}
@@ -1960,35 +1945,29 @@ out:
static int appnic_drv_remove(struct platform_device *pdev)
{
struct net_device *dev = platform_get_drvdata(pdev);
- struct appnic_device *pdata;
+ struct appnic_device *pdata = NULL;
pr_info("%s: Stopping driver", LSI_DRV_NAME);
- remove_proc_entry("driver/appnic", NULL);
-
- if (dev) {
- pdata = netdev_priv(dev);
- if (pdata->phy_dev)
- phy_disconnect(pdata->phy_dev);
- mdiobus_unregister(pdata->mii_bus);
- mdiobus_free(pdata->mii_bus);
- platform_set_drvdata(pdev, NULL);
- unregister_netdev(dev);
- free_irq(dev->irq, dev);
- dma_free_coherent(&dev->dev, pdata->dma_alloc_size,
- pdata->dma_alloc, pdata->dma_alloc_dma);
- dma_free_coherent(&dev->dev, pdata->dma_alloc_size_rx,
- pdata->dma_alloc_rx, pdata->dma_alloc_dma_rx);
- dma_free_coherent(&dev->dev, pdata->dma_alloc_size_tx,
- pdata->dma_alloc_tx, pdata->dma_alloc_dma_tx);
- free_netdev(dev);
- }
+ BUG_ON(!dev);
+ pdata = netdev_priv(dev);
+ BUG_ON(!pdata);
+ BUG_ON(!pdata->phy_dev);
+ phy_disconnect(pdata->phy_dev);
+ pdata->phy_dev = NULL;
+ mdiobus_unregister(pdata->mii_bus);
+ mdiobus_free(pdata->mii_bus);
+ platform_set_drvdata(pdev, NULL);
+ unregister_netdev(dev);
+ free_irq(dev->irq, dev);
+ femac_free_mem_buffers(dev);
+ free_netdev(dev);
- iounmap(rx_base);
- iounmap(tx_base);
- iounmap(dma_base);
+ iounmap(pdata->rx_base);
+ iounmap(pdata->tx_base);
+ iounmap(pdata->dma_base);
#ifdef CONFIG_ARM
- iounmap(gpreg_base);
+ iounmap(pdata->gpreg_base);
#endif
return 0;
@@ -1998,7 +1977,6 @@ static const struct of_device_id appnic_dt_ids[] = {
{ .compatible = "lsi,acp-femac", },
{ .compatible = "acp-femac", },
{ /* end of list */ },
-
};
MODULE_DEVICE_TABLE(of, appnic_dt_ids);
@@ -2013,17 +1991,4 @@ static struct platform_driver appnic_driver = {
},
};
-/* Entry point for loading the module */
-static int __init appnic_init_module(void)
-{
- return platform_driver_register(&appnic_driver);
-}
-
-/* Entry point for unloading the module */
-static void __exit appnic_cleanup_module(void)
-{
- platform_driver_unregister(&appnic_driver);
-}
-
-module_init(appnic_init_module);
-module_exit(appnic_cleanup_module);
+module_platform_driver(appnic_driver);
diff --git a/drivers/net/ethernet/lsi/lsi_acp_net.h b/drivers/net/ethernet/lsi/lsi_acp_net.h
index 238af6e..c1f4311 100644
--- a/drivers/net/ethernet/lsi/lsi_acp_net.h
+++ b/drivers/net/ethernet/lsi/lsi_acp_net.h
@@ -1,7 +1,7 @@
/*
* drivers/net/ethernet/lsi/lsi_acp_net.h
*
- * Copyright (C) 2013 LSI
+ * 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
@@ -29,21 +29,21 @@ extern int ubootenv_get(const char *, char *);
extern int acp_mdio_read(unsigned long, unsigned long, unsigned short *, int);
extern int acp_mdio_write(unsigned long, unsigned long, unsigned short, int);
-/*
- * This is the maximum number of packets to be received every
+/* This is the maximum number of packets to be received every
* NAPI poll
*/
#define LSINET_NAPI_WEIGHT 64
-/*
- ======================================================================
- Device Data Structures
- ======================================================================
-*/
+/* This is the maximum number of bytes that serve to hold
+ * incoming Rx data.
+ */
+#define LSINET_MAX_MTU (ETH_DATA_LEN + 100) /* MTU + padding */
+
+/* Device Data Structures */
struct appnic_dma_descriptor {
-#ifdef CONFIG_ARM
+#ifdef __LITTLE_ENDIAN
/* Word 0 */
/* 00=Fill|01=Block|10=Scatter */
unsigned long transfer_type:2;
@@ -96,7 +96,7 @@ union appnic_queue_pointer {
unsigned long raw;
struct {
-#ifdef CONFIG_ARM
+#ifdef __LITTLE_ENDIAN
unsigned long offset:20;
unsigned long generation_bit:1;
unsigned long unused:11;
@@ -109,11 +109,7 @@ union appnic_queue_pointer {
} __packed;
-/*
- =============================================================================
- The appnic Device Structure
- =============================================================================
-*/
+/* The appnic Device Structure */
struct appnic_device {
@@ -121,9 +117,12 @@ struct appnic_device {
struct net_device *device;
/* Addresses, Interrupt, and PHY stuff. */
- unsigned long rx_base;
- unsigned long tx_base;
- unsigned long dma_base;
+ void __iomem *rx_base;
+ void __iomem *tx_base;
+ void __iomem *dma_base;
+#ifdef CONFIG_ARM
+ void __iomem *gpreg_base;
+#endif
unsigned long tx_interrupt;
unsigned long rx_interrupt;
unsigned long dma_interrupt;
@@ -138,8 +137,12 @@ struct appnic_device {
/* NAPI */
struct napi_struct napi;
- /* statistics */
+ /* Statistics */
struct net_device_stats stats;
+ unsigned long dropped_by_stack;
+ unsigned long out_of_tx_descriptors;
+ unsigned long transmit_interrupts;
+ unsigned long receive_interrupts;
/* DMA-able memory */
int dma_alloc_size;
@@ -187,7 +190,6 @@ struct appnic_device {
/* Spin Lock */
spinlock_t dev_lock;
- spinlock_t extra_lock;
/* PHY */
struct mii_bus *mii_bus;
@@ -198,8 +200,11 @@ struct appnic_device {
unsigned int duplex;
};
-/*
- * Overview
+/* GPREG FEMAC HPROT Register --------------------------------------- */
+
+#define GPREG_HPROT_FEMAC ((unsigned long)pdata->gpreg_base + 0x78)
+
+/* Overview
* --------
*
* Register offset decoding is as follows:
@@ -223,7 +228,7 @@ struct appnic_device {
/* Receive Configuration -------------------------------------------- */
-#define APPNIC_RX_CONF (rx_base + 0x004c)
+#define APPNIC_RX_CONF ((unsigned long)pdata->rx_base + 0x004c)
#define APPNIC_RX_CONF_ENABLE 0x0001
/* Pass Any Packet */
#define APPNIC_RX_CONF_PAP 0x0002
@@ -241,75 +246,76 @@ struct appnic_device {
#define APPNIC_RX_CONF_DUPLEX 0x1000
/* 1=Enable */
#define APPNIC_RX_CONF_LINK 0x2000
-/*
- * Determines the action taken when the FE MAC
- * receives an FC packet in FD mode.
+/* Determines the action taken when the FE MAC
+ * receives an Flow Control packet in FD mode.
*/
#define APPNIC_RX_CONF_RXFCE 0x4000
-/*
- * Controls the insertion of FC packets
+
+/* Controls the insertion of Flow Control packets
* by the MAC transmitter.
*/
#define APPNIC_RX_CONF_TXFCE 0x8000
/* Receive Stat Overflow -------------------------------------------- */
-#define APPNIC_RX_STAT_OVERFLOW (rx_base + 0x278)
+#define APPNIC_RX_STAT_OVERFLOW ((unsigned long)pdata->rx_base + 0x278)
/* Receive Stat Undersize ------------------------------------------- */
-#define APPNIC_RX_STAT_UNDERSIZE (rx_base + 0x280)
+#define APPNIC_RX_STAT_UNDERSIZE ((unsigned long)pdata->rx_base + 0x280)
/* Receive Stat Oversize -------------------------------------------- */
-#define APPNIC_RX_STAT_OVERSIZE (rx_base + 0x2b8)
+#define APPNIC_RX_STAT_OVERSIZE ((unsigned long)pdata->rx_base + 0x2b8)
/* Receive Stat Multicast ------------------------------------------- */
-#define APPNIC_RX_STAT_MULTICAST (rx_base + 0x2d0)
+#define APPNIC_RX_STAT_MULTICAST ((unsigned long)pdata->rx_base + 0x2d0)
/* Receive Stat Packet OK ------------------------------------------- */
-#define APPNIC_RX_STAT_PACKET_OK (rx_base + 0x2c0)
+#define APPNIC_RX_STAT_PACKET_OK ((unsigned long)pdata->rx_base + 0x2c0)
/* Receive Stat CRC Error ------------------------------------------- */
-#define APPNIC_RX_STAT_CRC_ERROR (rx_base + 0x2c8)
+#define APPNIC_RX_STAT_CRC_ERROR ((unsigned long)pdata->rx_base + 0x2c8)
/* Receive Stat Align Error ----------------------------------------- */
-#define APPNIC_RX_STAT_ALIGN_ERROR (rx_base + 0x2e8)
+#define APPNIC_RX_STAT_ALIGN_ERROR ((unsigned long)pdata->rx_base + 0x2e8)
/* Receive Ethernet Mode -------------------------------------------- */
-#define APPNIC_RX_MODE (rx_base + 0x0800)
+#define APPNIC_RX_MODE ((unsigned long)pdata->rx_base + 0x0800)
#define APPNIC_RX_MODE_ETHERNET_MODE_ENABLE 0x00001
/* Receive Soft Reset ----------------------------------------------- */
-#define APPNIC_RX_SOFT_RESET (rx_base + 0x0808)
+#define APPNIC_RX_SOFT_RESET ((unsigned long)pdata->rx_base + 0x0808)
#define APPNIC_RX_SOFT_RESET_MAC_0 0x00001
/* Receive Internal Interrupt Control ------------------------------- */
-#define APPNIC_RX_INTERNAL_INTERRUPT_CONTROL (rx_base + 0xc00)
+#define APPNIC_RX_INTERNAL_INTERRUPT_CONTROL \
+ ((unsigned long)pdata->rx_base + 0xc00)
#define APPNIC_RX_INTERNAL_INTERRUPT_CONTROL_MAC_0 0x1
/* Receive External Interrupt Control ------------------------------- */
-#define APPNIC_RX_EXTERNAL_INTERRUPT_CONTROL (rx_base + 0xc04)
+#define APPNIC_RX_EXTERNAL_INTERRUPT_CONTROL \
+ ((unsigned long)pdata->rx_base + 0xc04)
#define APPNIC_RX_EXTERNAL_INTERRUPT_CONTROL_MAC_0_HIGH_LOW 0x10
#define APPNIC_RX_EXTERNAL_INTERRUPT_CONTROL_MAC_0 0x1
/* Receive Interrupt Status ----------------------------------------- */
-#define APPNIC_RX_INTERRUPT_STATUS (rx_base + 0xc20)
+#define APPNIC_RX_INTERRUPT_STATUS ((unsigned long)pdata->rx_base + 0xc20)
#define APPNIC_RX_INTERRUPT_EXTERNAL_STATUS_MAC_0 0x10
#define APPNIC_RX_INTERRUPT_INTERNAL_STATUS_MAC_0 0x1
/* Transmit Watermark ----------------------------------------------- */
-#define APPNIC_TX_WATERMARK (tx_base + 0x18)
+#define APPNIC_TX_WATERMARK ((unsigned long)pdata->tx_base + 0x18)
#define APPNIC_TX_WATERMARK_TXCONFIG_DTPA_ASSERT 0x8000
#define APPNIC_TX_WATERMARK_TXCONFIG_DTPA_DISABLE 0x4000
#define APPNIC_TX_WATERMARK_TXCONFIG_DTPA_WATER_MARK_HIGH 0x3f00
@@ -317,13 +323,13 @@ struct appnic_device {
/* Swap Source Address Registers ------------------------------------ */
-#define APPNIC_SWAP_SOURCE_ADDRESS_2 (tx_base + 0x20)
-#define APPNIC_SWAP_SOURCE_ADDRESS_1 (tx_base + 0x24)
-#define APPNIC_SWAP_SOURCE_ADDRESS_0 (tx_base + 0x28)
+#define APPNIC_SWAP_SOURCE_ADDRESS_2 ((unsigned long)pdata->tx_base + 0x20)
+#define APPNIC_SWAP_SOURCE_ADDRESS_1 ((unsigned long)pdata->tx_base + 0x24)
+#define APPNIC_SWAP_SOURCE_ADDRESS_0 ((unsigned long)pdata->tx_base + 0x28)
/* Transmit Extended Configuration ---------------------------------- */
-#define APPNIC_TX_EXTENDED_CONF (tx_base + 0x30)
+#define APPNIC_TX_EXTENDED_CONF ((unsigned long)pdata->tx_base + 0x30)
#define APPNIC_TX_EXTENDED_CONF_TRANSMIT_COLLISION_WATERMARK_LEVEL 0xf000
#define APPNIC_TX_EXTENDED_CONF_EXCESSIVE_DEFFERED_PACKET_DROP 0x200
#define APPNIC_TX_EXTENDED_CONF_JUMBO9K 0x100
@@ -331,12 +337,12 @@ struct appnic_device {
/* Transmit Half Duplex Configuration ------------------------------- */
-#define APPNIC_TX_HALF_DUPLEX_CONF (tx_base + 0x34)
+#define APPNIC_TX_HALF_DUPLEX_CONF ((unsigned long)pdata->tx_base + 0x34)
#define APPNIC_TX_HALF_DUPLEX_CONF_RANDOM_SEED_VALUE 0xff
/* Transmit Configuration ------------------------------------------- */
-#define APPNIC_TX_CONF (tx_base + 0x0050)
+#define APPNIC_TX_CONF ((unsigned long)pdata->tx_base + 0x0050)
#define APPNIC_TX_CONF_ENABLE_SWAP_SA 0x8000
#define APPNIC_TX_CONF_LINK 0x2000
#define APPNIC_TX_CONF_DUPLEX 0x1000
@@ -351,68 +357,70 @@ struct appnic_device {
do { \
(tx_configuration) &= ~APPNIC_TX_CONF_IFG; \
(tx_configuration) |= ((ifg & 0x1f) << 4); \
- } while (0);
+ } while (0)
/* Transmit Time Value Configuration -------------------------------- */
-#define APPNIC_TX_TIME_VALUE_CONF (tx_base + 0x5c)
+#define APPNIC_TX_TIME_VALUE_CONF ((unsigned long)pdata->tx_base + 0x5c)
#define APPNIC_TX_TIME_VALUE_CONF_PAUSE_VALUE 0xffff
/* Transmit Stat Underrun ------------------------------------------- */
-#define APPNIC_TX_STAT_UNDERRUN (tx_base + 0x300)
+#define APPNIC_TX_STAT_UNDERRUN ((unsigned long)pdata->tx_base + 0x300)
/* Transmit Stat Packet OK ------------------------------------------ */
-#define APPNIC_TX_STAT_PACKET_OK (tx_base + 0x318)
+#define APPNIC_TX_STAT_PACKET_OK ((unsigned long)pdata->tx_base + 0x318)
/* Transmit Stat Undersize ------------------------------------------ */
-#define APPNIC_TX_STAT_UNDERSIZE (tx_base + 0x350)
+#define APPNIC_TX_STAT_UNDERSIZE ((unsigned long)pdata->tx_base + 0x350)
/* Transmit Status Late Collision ----------------------------------- */
-#define APPNIC_TX_STATUS_LATE_COLLISION (tx_base + 0x368)
+#define APPNIC_TX_STATUS_LATE_COLLISION ((unsigned long)pdata->tx_base + 0x368)
/* Transmit Status Excessive Collision ------------------------------ */
-#define APPNIC_TX_STATUS_EXCESSIVE_COLLISION (tx_base + 0x370)
+#define APPNIC_TX_STATUS_EXCESSIVE_COLLISION \
+ ((unsigned long)pdata->tx_base + 0x370)
/* Transmit Stat Collision Above Watermark -------------------------- */
-#define APPNIC_TX_STAT_COLLISION_ABOVE_WATERMARK (tx_base + 0x380)
+#define APPNIC_TX_STAT_COLLISION_ABOVE_WATERMARK \
+ ((unsigned long)pdata->tx_base + 0x380)
/* Transmit Mode ---------------------------------------------------- */
-#define APPNIC_TX_MODE (tx_base + 0x800)
+#define APPNIC_TX_MODE ((unsigned long)pdata->tx_base + 0x800)
#define APPNIC_TX_MODE_ETHERNET_MODE_ENABLE 0x1
/* Transmit Soft Reset ---------------------------------------------- */
-#define APPNIC_TX_SOFT_RESET (tx_base + 0x808)
+#define APPNIC_TX_SOFT_RESET ((unsigned long)pdata->tx_base + 0x808)
#define APPNIC_TX_SOFT_RESET_MAC_0 0x1
/* Transmit Interrupt Control --------------------------------------- */
-#define APPNIC_TX_INTERRUPT_CONTROL (tx_base + 0xc00)
+#define APPNIC_TX_INTERRUPT_CONTROL ((unsigned long)pdata->tx_base + 0xc00)
#define APPNIC_TX_INTERRUPT_CONTROL_MAC_0 0x1
/* Transmit Interrupt Status ---------------------------------------- */
-#define APPNIC_TX_INTERRUPT_STATUS (tx_base + 0xc20)
+#define APPNIC_TX_INTERRUPT_STATUS ((unsigned long)pdata->tx_base + 0xc20)
#define APPNIC_TX_INTERRUPT_STATUS_MAC_0 0x1
/* */
-#define APPNIC_DMA_PCI_CONTROL (dma_base + 0x00)
+#define APPNIC_DMA_PCI_CONTROL ((unsigned long)pdata->dma_base + 0x00)
/* */
-#define APPNIC_DMA_CONTROL (dma_base + 0x08)
+#define APPNIC_DMA_CONTROL ((unsigned long)pdata->dma_base + 0x08)
/* DMA Interrupt Status --------------------------------------------- */
-#define APPNIC_DMA_INTERRUPT_STATUS (dma_base + 0x18)
+#define APPNIC_DMA_INTERRUPT_STATUS ((unsigned long)pdata->dma_base + 0x18)
#define APPNIC_DMA_INTERRUPT_STATUS_RX 0x2
#define APPNIC_DMA_INTERRUPT_STATUS_TX 0x1
#define RX_INTERRUPT(dma_interrupt_status) \
@@ -422,55 +430,59 @@ struct appnic_device {
/* DMA Interrupt Enable --------------------------------------------- */
-#define APPNIC_DMA_INTERRUPT_ENABLE (dma_base + 0x1c)
+#define APPNIC_DMA_INTERRUPT_ENABLE ((unsigned long)pdata->dma_base + 0x1c)
#define APPNIC_DMA_INTERRUPT_ENABLE_RECEIVE 0x2
#define APPNIC_DMA_INTERRUPT_ENABLE_TRANSMIT 0x1
/* DMA Receive Queue Base Address ----------------------------------- */
-#define APPNIC_DMA_RX_QUEUE_BASE_ADDRESS (dma_base + 0x30)
+#define APPNIC_DMA_RX_QUEUE_BASE_ADDRESS ((unsigned long)pdata->dma_base + 0x30)
/* DMA Receive Queue Size ------------------------------------------- */
-#define APPNIC_DMA_RX_QUEUE_SIZE (dma_base + 0x34)
+#define APPNIC_DMA_RX_QUEUE_SIZE ((unsigned long)pdata->dma_base + 0x34)
/* DMA Transmit Queue Base Address ---------------------------------- */
-#define APPNIC_DMA_TX_QUEUE_BASE_ADDRESS (dma_base + 0x38)
+#define APPNIC_DMA_TX_QUEUE_BASE_ADDRESS ((unsigned long)pdata->dma_base + 0x38)
/* DMA Transmit Queue Size ------------------------------------------ */
-#define APPNIC_DMA_TX_QUEUE_SIZE (dma_base + 0x3c)
+#define APPNIC_DMA_TX_QUEUE_SIZE ((unsigned long)pdata->dma_base + 0x3c)
/* DMA Recevie Tail Pointer Address --------------------------------- */
-#define APPNIC_DMA_RX_TAIL_POINTER_ADDRESS (dma_base + 0x48)
+#define APPNIC_DMA_RX_TAIL_POINTER_ADDRESS \
+ ((unsigned long)pdata->dma_base + 0x48)
/* DMA Transmit Tail Pointer Address -------------------------------- */
-#define APPNIC_DMA_TX_TAIL_POINTER_ADDRESS (dma_base + 0x4c)
+#define APPNIC_DMA_TX_TAIL_POINTER_ADDRESS \
+ ((unsigned long)pdata->dma_base + 0x4c)
/* DMA Receive Head Pointer ----------------------------------------- */
-#define APPNIC_DMA_RX_HEAD_POINTER (dma_base + 0x50)
+#define APPNIC_DMA_RX_HEAD_POINTER ((unsigned long)pdata->dma_base + 0x50)
#define APPNIC_DMA_RX_HEAD_POINTER_GB 0x100000
#define APPNIC_DMA_RX_HEAD_POINTER_POINTER 0x0fffff
/* DMA Receive Tail Pointer Local Copy ------------------------------ */
-#define APPNIC_DMA_RX_TAIL_POINTER_LOCAL_COPY (dma_base + 0x54)
+#define APPNIC_DMA_RX_TAIL_POINTER_LOCAL_COPY \
+ ((unsigned long)pdata->dma_base + 0x54)
#define APPNIC_DMA_RX_TAIL_POINTER_LOCAL_COPY_GB 0x100000
#define APPNIC_DMA_RX_TAIL_POINTER_LOCAL_COPY_POINTER 0x0fffff
/* DMA Transmit Head Pointer ---------------------------------------- */
-#define APPNIC_DMA_TX_HEAD_POINTER (dma_base + 0x58)
+#define APPNIC_DMA_TX_HEAD_POINTER ((unsigned long)pdata->dma_base + 0x58)
#define APPNIC_DMA_TX_HEAD_POINTER_GB 0x100000
#define APPNIC_DMA_TX_HEAD_POINTER_POINTER 0x0fffff
/* DMA Transmit Tail Pointer Local Copy ----------------------------- */
-#define APPNIC_DMA_TX_TAIL_POINTER_LOCAL_COPY (dma_base + 0x5c)
+#define APPNIC_DMA_TX_TAIL_POINTER_LOCAL_COPY \
+ ((unsigned long)pdata->dma_base + 0x5c)
#define APPNIC_DMA_TX_TAIL_POINTER_LOCAL_COPY_GB 0x100000
#define APPNIC_DMA_TX_TAIL_POINTER_LOCAL_COPY_POINTER 0x0fffff
@@ -497,11 +509,18 @@ writedescriptor(unsigned long address,
}
static inline union appnic_queue_pointer
-swab_queue_pointer(const union appnic_queue_pointer *old_queue)
+_swab_queue_pointer(const union appnic_queue_pointer *old_queue)
{
return *old_queue;
}
+static inline void
+femac_uncache(struct appnic_device *pdata)
+{
+ /* Set FEMAC to uncached */
+ writel(0x0, GPREG_HPROT_FEMAC);
+}
+
#else
#define read_mac(address) in_le32((u32 *) (address))
@@ -535,15 +554,115 @@ writedescriptor(unsigned long address,
}
static inline union appnic_queue_pointer
-swab_queue_pointer(const union appnic_queue_pointer *old_queue)
+_swab_queue_pointer(const union appnic_queue_pointer *old_queue)
{
union appnic_queue_pointer new_queue;
new_queue.raw = swab32(old_queue->raw);
return new_queue;
}
+
+static inline void
+femac_uncache(struct appnic_device *pdata) {}
+
#endif /* ifdef CONFIG_ARM */
-#define SWAB_QUEUE_POINTER(pointer) \
-swab_queue_pointer((const union appnic_queue_pointer *) (pointer))
+static int
+femac_irq_setup(struct net_device *dev)
+{
+ struct appnic_device *pdata = netdev_priv(dev);
+
+#ifdef CONFIG_ARM
+ dev->irq = pdata->dma_interrupt;
+#else
+ dev->irq = irq_create_mapping(NULL, pdata->dma_interrupt);
+ if (NO_IRQ == dev->irq)
+ return -EINVAL;
+
+ if (0 != irq_set_irq_type(dev->irq, IRQ_TYPE_LEVEL_HIGH))
+ return -EINVAL;
+#endif
+ return 0;
+}
+
+static inline int
+femac_alloc_mem_buffers(struct net_device *dev)
+{
+ struct appnic_device *pdata = netdev_priv(dev);
+ struct device *device = NULL;
+ int rc;
+
+#ifndef CONFIG_ARM
+ dev->dev.archdata.dma_ops = &dma_direct_ops;
+ device = &dev->dev;
+#endif
+
+ pdata->dma_alloc = (void *)dma_alloc_coherent(device,
+ pdata->dma_alloc_size,
+ &pdata->dma_alloc_dma,
+ GFP_KERNEL);
+ if (pdata->dma_alloc == (void *)0) {
+ rc = -ENOMEM;
+ goto err_dma_alloc;
+ }
+
+ pdata->dma_alloc_offset = (int)pdata->dma_alloc -
+ (int)pdata->dma_alloc_dma;
+
+ pdata->dma_alloc_rx = (void *)dma_alloc_coherent(device,
+ pdata->dma_alloc_size_rx,
+ &pdata->dma_alloc_dma_rx,
+ GFP_KERNEL);
+ if (pdata->dma_alloc_rx == (void *)0) {
+ rc = -ENOMEM;
+ goto err_dma_alloc_rx;
+ }
+
+ pdata->dma_alloc_offset_rx = (int)pdata->dma_alloc_rx -
+ (int)pdata->dma_alloc_dma_rx;
+
+ pdata->dma_alloc_tx = (void *)dma_alloc_coherent(device,
+ pdata->dma_alloc_size_tx,
+ &pdata->dma_alloc_dma_tx,
+ GFP_KERNEL);
+
+ if (pdata->dma_alloc_tx == (void *)0) {
+ rc = -ENOMEM;
+ goto err_dma_alloc_tx;
+ }
+
+ pdata->dma_alloc_offset_tx = (int)pdata->dma_alloc_tx -
+ (int)pdata->dma_alloc_dma_tx;
+
+ return 0;
+
+err_dma_alloc_tx:
+ dma_free_coherent(device, pdata->dma_alloc_size_rx,
+ pdata->dma_alloc_rx, pdata->dma_alloc_dma_rx);
+err_dma_alloc_rx:
+ dma_free_coherent(device, pdata->dma_alloc_size,
+ pdata->dma_alloc, pdata->dma_alloc_dma);
+err_dma_alloc:
+ return rc;
+}
+
+static inline void
+femac_free_mem_buffers(struct net_device *dev)
+{
+ struct appnic_device *pdata = netdev_priv(dev);
+ struct device *device = NULL;
+
+#ifndef CONFIG_ARM
+ device = &dev->dev;
+#endif
+ dma_free_coherent(device, pdata->dma_alloc_size,
+ pdata->dma_alloc, pdata->dma_alloc_dma);
+ dma_free_coherent(device, pdata->dma_alloc_size_rx,
+ pdata->dma_alloc_rx, pdata->dma_alloc_dma_rx);
+ dma_free_coherent(device, pdata->dma_alloc_size_tx,
+ pdata->dma_alloc_tx, pdata->dma_alloc_dma_tx);
+}
+
+#define swab_queue_pointer(pointer) \
+ _swab_queue_pointer((const union appnic_queue_pointer *) (pointer))
#endif /* _LSI_ACP_NET_H */
--
1.7.9.5
More information about the linux-yocto
mailing list