From: David Mercado <david.merc...@windriver.com> Incorporated feedback from Linutronix regarding lsi_acp_net.c FEMAC driver
- Removed unnecessary module parameters in kernel config - Removed outdated GNU public license statement in file headers - Fixed multiline comments for proper kernel style - Removed direct memory access from mdio driver - Removed use of UPPERCASE function names - Removed use of global variables - Minimized use of arch-specific #ifdefs - Replaced use of custom align macros with ALIGN()/PTR_ALIGN() - Added missing ethtool callbacks, updated stats function - Removed un-needed extra spinlock - Removed un-needed pr_info messages that would otherwise spam dmesg - Replaced custom MAC parsing with is_multicast_ether_addr() - Fixed incorrect NAPI handling - Removed /proc handling - Removed magic numbers (e.g., replaced 6 with ETH_ALEN) - Fixed module init/exit routines Signed-off-by: David Mercado <david.merc...@windriver.com> --- drivers/net/ethernet/lsi/Kconfig | 15 - drivers/net/ethernet/lsi/lsi_acp_mdio.c | 201 +++---- drivers/net/ethernet/lsi/lsi_acp_net.c | 871 ++++++++++++++----------------- drivers/net/ethernet/lsi/lsi_acp_net.h | 261 ++++++--- 4 files changed, 693 insertions(+), 655 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..aab609d 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,53 @@ #include <linux/skbuff.h> #include <linux/platform_device.h> +#define BZ33327_WA + /* - ============================================================================== - ============================================================================== - MDIO Access - ============================================================================== - ============================================================================== -*/ + * MDIO Access + */ -#ifndef CONFIG_ACPISS +struct lsi_mdio_priv { + unsigned long base; +}; -#define BZ33327_WA - -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,24 +74,24 @@ 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. */ /* 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 @@ -97,16 +100,16 @@ acp_mdio_read(unsigned long address, unsigned long offset, device) */ command |= (offset & 0xffff); /* addr_or_data (target register) */ - WRITE(MDIO_CONTROL_RD_DATA, command); + 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)); /* @@ -114,30 +117,30 @@ acp_mdio_read(unsigned long address, unsigned long offset, */ /* 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) */ command |= (address & 0x1f) << 16; /* port_addr (target device) */ - 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)); *value = (unsigned short)(command & 0xffff); @@ -148,13 +151,12 @@ 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,30 +166,30 @@ 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. */ /* 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 @@ -196,16 +198,16 @@ acp_mdio_write(unsigned long address, unsigned long offset, device) */ command |= (offset & 0xffff); /* addr_or_data (target register) */ - WRITE(MDIO_CONTROL_RD_DATA, command); + 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)); /* @@ -213,11 +215,11 @@ acp_mdio_write(unsigned long address, unsigned long offset, */ /* 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 @@ -225,19 +227,19 @@ acp_mdio_write(unsigned long address, unsigned long offset, command |= (address & 0x1f) << 16; /* port_addr (target 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); @@ -247,38 +249,26 @@ 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 +276,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 +293,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 5684779..5589619 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,48 +71,28 @@ #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" extern int acp_mdio_read(unsigned long, unsigned long, unsigned short *, int); extern int acp_mdio_write(unsigned long, unsigned long, unsigned short, int); -/* 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 @@ -183,12 +153,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; @@ -287,34 +255,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); @@ -391,9 +331,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)) @@ -441,26 +379,44 @@ 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 - ====================================================================== -*/ + * ---------------------------------------------------------------------- + * mac_addr_valid + * + * If mac address is multicast, broadcast, or matches our mac address, + * it's a valid address. Otherwise, it's not. + */ + +static bool mac_addr_valid(struct net_device *dev, u8 *mac_addr) +{ + bool is_valid = false; + + 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; + + return is_valid; +} + /* - ---------------------------------------------------------------------- - clear_statistics -*/ + * ---------------------------------------------------------------------- + * clear_statistics + * + * NOTE: The hardware clears the statistics registers after a read. + */ static void clear_statistics(struct appnic_device *pdata) { - int waste; - /* * Clear memory. */ @@ -468,62 +424,61 @@ static void clear_statistics(struct appnic_device *pdata) memset((void *) &(pdata->stats), 0, sizeof(struct net_device_stats)); /* - * Clear counters. + * Clear counters by reading them. */ - 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 */ - - /* multicast */ - - waste = read_mac(APPNIC_RX_STAT_MULTICAST); - - /* collisions will be the sum of the three following. */ - - 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); - - /* rx_length_errors will be the sum of the two following. */ + /* stats.rx_packets */ + read_mac(APPNIC_RX_STAT_PACKET_OK); - waste = read_mac(APPNIC_RX_STAT_UNDERSIZE); - waste = read_mac(APPNIC_RX_STAT_OVERSIZE); + /* stats.tx_packets */ + read_mac(APPNIC_TX_STAT_PACKET_OK); - /* rx_over_errors (out of descriptors?) maintained by the driver. */ - /* rx_crc_errors */ + /* + * 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. + */ - waste = read_mac(APPNIC_RX_STAT_CRC_ERROR); + /* stats.multicast */ + read_mac(APPNIC_RX_STAT_MULTICAST); - /* rx_frame_errors */ + /* 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); - waste = read_mac(APPNIC_RX_STAT_ALIGN_ERROR); + /* stats.rx_length_errors - The sum of the following driver stats. */ + read_mac(APPNIC_RX_STAT_UNDERSIZE); + read_mac(APPNIC_RX_STAT_OVERSIZE); - /* rx_fifo_errors */ + /* stats.rx_over_errors - Not maintained by this driver. */ - waste = read_mac(APPNIC_RX_STAT_OVERFLOW); + /* stats.rx_crc_errors */ + read_mac(APPNIC_RX_STAT_CRC_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_frame_errors */ + read_mac(APPNIC_RX_STAT_ALIGN_ERROR); - waste = read_mac(APPNIC_TX_STAT_UNDERRUN); + /* stats.rx_fifo_errors */ + read_mac(APPNIC_RX_STAT_OVERFLOW); - /* tx_heartbeat_errors */ - /* tx_window_errors */ + /* + * 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. + */ - /* rx_compressed will not be maintained. */ - /* tx_compressed will not be maintained. */ + /* stats.tx_fifo_errors */ + read_mac(APPNIC_TX_STAT_UNDERRUN); /* - * That's all. + * 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. */ return; @@ -533,38 +488,31 @@ static void clear_statistics(struct appnic_device *pdata) * ---------------------------------------------------------------------- * 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); /* @@ -591,10 +539,6 @@ static void get_hw_statistics(struct appnic_device *pdata) spin_unlock_irqrestore(&pdata->dev_lock, flags); - /* - * That's all. - */ - return; } @@ -705,13 +649,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); @@ -721,7 +664,6 @@ static void disable_rx_tx(void) write_mac(tx_configuration, APPNIC_TX_CONF); - /* That's all. */ return; } @@ -740,15 +682,18 @@ 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; @@ -768,18 +713,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; } @@ -792,25 +735,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 + @@ -824,6 +760,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) { @@ -835,29 +772,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); } @@ -865,17 +788,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; } @@ -887,32 +807,34 @@ 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)) { + 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 */ @@ -954,37 +876,39 @@ 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; } /* @@ -1012,12 +936,12 @@ static irqreturn_t appnic_isr(int irq, void *device_id) /* 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)) { /* @@ -1124,7 +1048,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) @@ -1153,6 +1077,7 @@ 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; @@ -1161,16 +1086,17 @@ static int appnic_hard_start_xmit(struct sk_buff *skb, * 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; @@ -1204,11 +1130,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; } @@ -1222,22 +1149,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; } /* @@ -1259,10 +1186,6 @@ static struct net_device_stats *appnic_get_stats(struct net_device *dev) get_hw_statistics(pdata); - /* - * That's all. - */ - return &pdata->stats; } @@ -1273,14 +1196,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]; @@ -1297,10 +1224,106 @@ 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; + } +} /* * ---------------------------------------------------------------------- @@ -1312,6 +1335,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)); } /* @@ -1336,16 +1361,19 @@ static int appnic_get_settings(struct net_device *dev, */ 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, @@ -1373,13 +1401,10 @@ 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 @@ -1397,19 +1422,19 @@ int appnic_init(struct net_device *dev) */ 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; @@ -1420,19 +1445,19 @@ int appnic_init(struct net_device *dev) */ 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; @@ -1464,80 +1489,15 @@ int appnic_init(struct net_device *dev) (pdata->tx_buf_sz) + (BUFFER_ALIGNMENT); /* - * This needs to be set to something sane for - * dma_alloc_coherent() + * Allocate the buffers. */ -#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; + 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_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; - } - - pdata->dma_alloc_offset_tx = (int)pdata->dma_alloc_tx - - (int)pdata->dma_alloc_dma_tx; - /* * Initialize the tail pointers */ @@ -1556,7 +1516,6 @@ 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 */ @@ -1634,7 +1593,6 @@ int appnic_init(struct net_device *dev) */ spin_lock_init(&pdata->dev_lock); - spin_lock_init(&pdata->extra_lock); /* * Take MAC out of reset @@ -1665,22 +1623,24 @@ 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]); + 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. @@ -1761,48 +1721,30 @@ int appnic_init(struct net_device *dev) /* 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; -} - -/* - * ---------------------------------------------------------------------- - * appnic_read_proc - */ - -static int -appnic_read_proc(char *page, char **start, off_t offset, - int count, int *eof, void *data) -{ - int length; - - length = sprintf(page, "-- appnic.c -- Profiling is disabled\n"); - /* That's all */ - return length; +err_irq_setup: +err_set_mac_addr: + femac_free_mem_buffers(dev); +err_mem_buffers: +err_param: + return rc; } /* @@ -1816,9 +1758,11 @@ static int __devinit 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 @@ -1827,44 +1771,44 @@ static int __devinit 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; @@ -1922,32 +1866,25 @@ static int __devinit 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 @@ -1979,7 +1916,7 @@ static int __devinit 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); @@ -1996,13 +1933,13 @@ static int __devinit 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. */ @@ -2012,14 +1949,14 @@ static int __devinit 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, ":"); @@ -2028,29 +1965,23 @@ static int __devinit 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 @@ -2065,8 +1996,10 @@ static int __devinit 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; } } @@ -2078,7 +2011,7 @@ static int __devinit 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. */ @@ -2086,7 +2019,7 @@ static int __devinit 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. */ @@ -2094,14 +2027,17 @@ static int __devinit 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; } - /* Create the /proc entry. */ - create_proc_read_entry("driver/appnic", 0, NULL, - appnic_read_proc, NULL); + return 0; -out: +err_mii_init: + unregister_netdev(dev); +err_nodev: +err_inval: + free_netdev(dev); +err_alloc_etherdev: return rc; } @@ -2113,35 +2049,29 @@ out: static int __devexit 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; @@ -2163,17 +2093,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 7b6f2b3..00e02f6 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 @@ -33,14 +33,18 @@ extern int ubootenv_get(const char *, char *); #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; @@ -93,7 +97,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; @@ -107,10 +111,8 @@ union appnic_queue_pointer { } __packed; /* - ============================================================================= - The appnic Device Structure - ============================================================================= -*/ + * The appnic Device Structure + */ struct appnic_device { @@ -118,9 +120,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; @@ -135,8 +140,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; @@ -184,7 +193,6 @@ struct appnic_device { /* Spin Lock */ spinlock_t dev_lock; - spinlock_t extra_lock; /* PHY */ struct mii_bus *mii_bus; @@ -195,6 +203,10 @@ struct appnic_device { unsigned int duplex; }; +/* GPREG FEMAC HPROT Register --------------------------------------- */ + +#define GPREG_HPROT_FEMAC ((unsigned long)pdata->gpreg_base + 0x78) + /* * Overview * -------- @@ -220,7 +232,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 @@ -240,73 +252,75 @@ struct appnic_device { #define APPNIC_RX_CONF_LINK 0x2000 /* * Determines the action taken when the FE MAC - * receives an FC packet in FD mode. + * 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 @@ -314,13 +328,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 @@ -328,12 +342,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 @@ -352,64 +366,66 @@ struct appnic_device { /* 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) \ @@ -419,55 +435,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 @@ -494,11 +514,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)) @@ -532,15 +559,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 -- _______________________________________________ linux-yocto mailing list linux-yocto@yoctoproject.org https://lists.yoctoproject.org/listinfo/linux-yocto