diff options
author | Jeff Kirsher <jeffrey.t.kirsher@intel.com> | 2011-05-12 20:21:07 -0700 |
---|---|---|
committer | Jeff Kirsher <jeffrey.t.kirsher@intel.com> | 2011-08-10 20:04:03 -0700 |
commit | ae150435b59e68de00546330241727f2fec54517 (patch) | |
tree | 29a1cb71053306e8a8e0dff1f927d16a9a396917 /drivers/net/smsc911x.c | |
parent | aa43c2158d5ae1dc76cccb08cd57a3ffd32c3825 (diff) |
smsc: Move the SMC (SMSC) drivers
Moves the SMC (SMSC) drivers into drivers/net/ethernet/smsc/ and the
necessary Kconfig and Makefile changes. Also did some cleanup
of NET_VENDOR_SMC Kconfig tag for the 8390 based drivers.
CC: Nicolas Pitre <nico@fluxnic.net>
CC: Donald Becker <becker@scyld.com>
CC: Erik Stahlman <erik@vt.edu>
CC: Dustin McIntire <dustin@sensoria.com>
CC: Steve Glendinning <steve.glendinning@smsc.com>
CC: David Hinds <dahinds@users.sourceforge.net>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
Diffstat (limited to 'drivers/net/smsc911x.c')
-rw-r--r-- | drivers/net/smsc911x.c | 2404 |
1 files changed, 0 insertions, 2404 deletions
diff --git a/drivers/net/smsc911x.c b/drivers/net/smsc911x.c deleted file mode 100644 index 75c08a55582..00000000000 --- a/drivers/net/smsc911x.c +++ /dev/null @@ -1,2404 +0,0 @@ -/*************************************************************************** - * - * Copyright (C) 2004-2008 SMSC - * Copyright (C) 2005-2008 ARM - * - * 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. - * - *************************************************************************** - * Rewritten, heavily based on smsc911x simple driver by SMSC. - * Partly uses io macros from smc91x.c by Nicolas Pitre - * - * Supported devices: - * LAN9115, LAN9116, LAN9117, LAN9118 - * LAN9215, LAN9216, LAN9217, LAN9218 - * LAN9210, LAN9211 - * LAN9220, LAN9221 - * - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include <linux/crc32.h> -#include <linux/delay.h> -#include <linux/errno.h> -#include <linux/etherdevice.h> -#include <linux/ethtool.h> -#include <linux/init.h> -#include <linux/interrupt.h> -#include <linux/ioport.h> -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/netdevice.h> -#include <linux/platform_device.h> -#include <linux/sched.h> -#include <linux/timer.h> -#include <linux/bug.h> -#include <linux/bitops.h> -#include <linux/irq.h> -#include <linux/io.h> -#include <linux/swab.h> -#include <linux/phy.h> -#include <linux/smsc911x.h> -#include <linux/device.h> -#include <linux/of.h> -#include <linux/of_device.h> -#include <linux/of_gpio.h> -#include <linux/of_net.h> -#include "smsc911x.h" - -#define SMSC_CHIPNAME "smsc911x" -#define SMSC_MDIONAME "smsc911x-mdio" -#define SMSC_DRV_VERSION "2008-10-21" - -MODULE_LICENSE("GPL"); -MODULE_VERSION(SMSC_DRV_VERSION); -MODULE_ALIAS("platform:smsc911x"); - -#if USE_DEBUG > 0 -static int debug = 16; -#else -static int debug = 3; -#endif - -module_param(debug, int, 0); -MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)"); - -struct smsc911x_data; - -struct smsc911x_ops { - u32 (*reg_read)(struct smsc911x_data *pdata, u32 reg); - void (*reg_write)(struct smsc911x_data *pdata, u32 reg, u32 val); - void (*rx_readfifo)(struct smsc911x_data *pdata, - unsigned int *buf, unsigned int wordcount); - void (*tx_writefifo)(struct smsc911x_data *pdata, - unsigned int *buf, unsigned int wordcount); -}; - -struct smsc911x_data { - void __iomem *ioaddr; - - unsigned int idrev; - - /* used to decide which workarounds apply */ - unsigned int generation; - - /* device configuration (copied from platform_data during probe) */ - struct smsc911x_platform_config config; - - /* This needs to be acquired before calling any of below: - * smsc911x_mac_read(), smsc911x_mac_write() - */ - spinlock_t mac_lock; - - /* spinlock to ensure register accesses are serialised */ - spinlock_t dev_lock; - - struct phy_device *phy_dev; - struct mii_bus *mii_bus; - int phy_irq[PHY_MAX_ADDR]; - unsigned int using_extphy; - int last_duplex; - int last_carrier; - - u32 msg_enable; - unsigned int gpio_setting; - unsigned int gpio_orig_setting; - struct net_device *dev; - struct napi_struct napi; - - unsigned int software_irq_signal; - -#ifdef USE_PHY_WORK_AROUND -#define MIN_PACKET_SIZE (64) - char loopback_tx_pkt[MIN_PACKET_SIZE]; - char loopback_rx_pkt[MIN_PACKET_SIZE]; - unsigned int resetcount; -#endif - - /* Members for Multicast filter workaround */ - unsigned int multicast_update_pending; - unsigned int set_bits_mask; - unsigned int clear_bits_mask; - unsigned int hashhi; - unsigned int hashlo; - - /* register access functions */ - const struct smsc911x_ops *ops; -}; - -/* Easy access to information */ -#define __smsc_shift(pdata, reg) ((reg) << ((pdata)->config.shift)) - -static inline u32 __smsc911x_reg_read(struct smsc911x_data *pdata, u32 reg) -{ - if (pdata->config.flags & SMSC911X_USE_32BIT) - return readl(pdata->ioaddr + reg); - - if (pdata->config.flags & SMSC911X_USE_16BIT) - return ((readw(pdata->ioaddr + reg) & 0xFFFF) | - ((readw(pdata->ioaddr + reg + 2) & 0xFFFF) << 16)); - - BUG(); - return 0; -} - -static inline u32 -__smsc911x_reg_read_shift(struct smsc911x_data *pdata, u32 reg) -{ - if (pdata->config.flags & SMSC911X_USE_32BIT) - return readl(pdata->ioaddr + __smsc_shift(pdata, reg)); - - if (pdata->config.flags & SMSC911X_USE_16BIT) - return (readw(pdata->ioaddr + - __smsc_shift(pdata, reg)) & 0xFFFF) | - ((readw(pdata->ioaddr + - __smsc_shift(pdata, reg + 2)) & 0xFFFF) << 16); - - BUG(); - return 0; -} - -static inline u32 smsc911x_reg_read(struct smsc911x_data *pdata, u32 reg) -{ - u32 data; - unsigned long flags; - - spin_lock_irqsave(&pdata->dev_lock, flags); - data = pdata->ops->reg_read(pdata, reg); - spin_unlock_irqrestore(&pdata->dev_lock, flags); - - return data; -} - -static inline void __smsc911x_reg_write(struct smsc911x_data *pdata, u32 reg, - u32 val) -{ - if (pdata->config.flags & SMSC911X_USE_32BIT) { - writel(val, pdata->ioaddr + reg); - return; - } - - if (pdata->config.flags & SMSC911X_USE_16BIT) { - writew(val & 0xFFFF, pdata->ioaddr + reg); - writew((val >> 16) & 0xFFFF, pdata->ioaddr + reg + 2); - return; - } - - BUG(); -} - -static inline void -__smsc911x_reg_write_shift(struct smsc911x_data *pdata, u32 reg, u32 val) -{ - if (pdata->config.flags & SMSC911X_USE_32BIT) { - writel(val, pdata->ioaddr + __smsc_shift(pdata, reg)); - return; - } - - if (pdata->config.flags & SMSC911X_USE_16BIT) { - writew(val & 0xFFFF, - pdata->ioaddr + __smsc_shift(pdata, reg)); - writew((val >> 16) & 0xFFFF, - pdata->ioaddr + __smsc_shift(pdata, reg + 2)); - return; - } - - BUG(); -} - -static inline void smsc911x_reg_write(struct smsc911x_data *pdata, u32 reg, - u32 val) -{ - unsigned long flags; - - spin_lock_irqsave(&pdata->dev_lock, flags); - pdata->ops->reg_write(pdata, reg, val); - spin_unlock_irqrestore(&pdata->dev_lock, flags); -} - -/* Writes a packet to the TX_DATA_FIFO */ -static inline void -smsc911x_tx_writefifo(struct smsc911x_data *pdata, unsigned int *buf, - unsigned int wordcount) -{ - unsigned long flags; - - spin_lock_irqsave(&pdata->dev_lock, flags); - - if (pdata->config.flags & SMSC911X_SWAP_FIFO) { - while (wordcount--) - __smsc911x_reg_write(pdata, TX_DATA_FIFO, - swab32(*buf++)); - goto out; - } - - if (pdata->config.flags & SMSC911X_USE_32BIT) { - writesl(pdata->ioaddr + TX_DATA_FIFO, buf, wordcount); - goto out; - } - - if (pdata->config.flags & SMSC911X_USE_16BIT) { - while (wordcount--) - __smsc911x_reg_write(pdata, TX_DATA_FIFO, *buf++); - goto out; - } - - BUG(); -out: - spin_unlock_irqrestore(&pdata->dev_lock, flags); -} - -/* Writes a packet to the TX_DATA_FIFO - shifted version */ -static inline void -smsc911x_tx_writefifo_shift(struct smsc911x_data *pdata, unsigned int *buf, - unsigned int wordcount) -{ - unsigned long flags; - - spin_lock_irqsave(&pdata->dev_lock, flags); - - if (pdata->config.flags & SMSC911X_SWAP_FIFO) { - while (wordcount--) - __smsc911x_reg_write_shift(pdata, TX_DATA_FIFO, - swab32(*buf++)); - goto out; - } - - if (pdata->config.flags & SMSC911X_USE_32BIT) { - writesl(pdata->ioaddr + __smsc_shift(pdata, - TX_DATA_FIFO), buf, wordcount); - goto out; - } - - if (pdata->config.flags & SMSC911X_USE_16BIT) { - while (wordcount--) - __smsc911x_reg_write_shift(pdata, - TX_DATA_FIFO, *buf++); - goto out; - } - - BUG(); -out: - spin_unlock_irqrestore(&pdata->dev_lock, flags); -} - -/* Reads a packet out of the RX_DATA_FIFO */ -static inline void -smsc911x_rx_readfifo(struct smsc911x_data *pdata, unsigned int *buf, - unsigned int wordcount) -{ - unsigned long flags; - - spin_lock_irqsave(&pdata->dev_lock, flags); - - if (pdata->config.flags & SMSC911X_SWAP_FIFO) { - while (wordcount--) - *buf++ = swab32(__smsc911x_reg_read(pdata, - RX_DATA_FIFO)); - goto out; - } - - if (pdata->config.flags & SMSC911X_USE_32BIT) { - readsl(pdata->ioaddr + RX_DATA_FIFO, buf, wordcount); - goto out; - } - - if (pdata->config.flags & SMSC911X_USE_16BIT) { - while (wordcount--) - *buf++ = __smsc911x_reg_read(pdata, RX_DATA_FIFO); - goto out; - } - - BUG(); -out: - spin_unlock_irqrestore(&pdata->dev_lock, flags); -} - -/* Reads a packet out of the RX_DATA_FIFO - shifted version */ -static inline void -smsc911x_rx_readfifo_shift(struct smsc911x_data *pdata, unsigned int *buf, - unsigned int wordcount) -{ - unsigned long flags; - - spin_lock_irqsave(&pdata->dev_lock, flags); - - if (pdata->config.flags & SMSC911X_SWAP_FIFO) { - while (wordcount--) - *buf++ = swab32(__smsc911x_reg_read_shift(pdata, - RX_DATA_FIFO)); - goto out; - } - - if (pdata->config.flags & SMSC911X_USE_32BIT) { - readsl(pdata->ioaddr + __smsc_shift(pdata, - RX_DATA_FIFO), buf, wordcount); - goto out; - } - - if (pdata->config.flags & SMSC911X_USE_16BIT) { - while (wordcount--) - *buf++ = __smsc911x_reg_read_shift(pdata, - RX_DATA_FIFO); - goto out; - } - - BUG(); -out: - spin_unlock_irqrestore(&pdata->dev_lock, flags); -} - -/* waits for MAC not busy, with timeout. Only called by smsc911x_mac_read - * and smsc911x_mac_write, so assumes mac_lock is held */ -static int smsc911x_mac_complete(struct smsc911x_data *pdata) -{ - int i; - u32 val; - - SMSC_ASSERT_MAC_LOCK(pdata); - - for (i = 0; i < 40; i++) { - val = smsc911x_reg_read(pdata, MAC_CSR_CMD); - if (!(val & MAC_CSR_CMD_CSR_BUSY_)) - return 0; - } - SMSC_WARN(pdata, hw, "Timed out waiting for MAC not BUSY. " - "MAC_CSR_CMD: 0x%08X", val); - return -EIO; -} - -/* Fetches a MAC register value. Assumes mac_lock is acquired */ -static u32 smsc911x_mac_read(struct smsc911x_data *pdata, unsigned int offset) -{ - unsigned int temp; - - SMSC_ASSERT_MAC_LOCK(pdata); - - temp = smsc911x_reg_read(pdata, MAC_CSR_CMD); - if (unlikely(temp & MAC_CSR_CMD_CSR_BUSY_)) { - SMSC_WARN(pdata, hw, "MAC busy at entry"); - return 0xFFFFFFFF; - } - - /* Send the MAC cmd */ - smsc911x_reg_write(pdata, MAC_CSR_CMD, ((offset & 0xFF) | - MAC_CSR_CMD_CSR_BUSY_ | MAC_CSR_CMD_R_NOT_W_)); - - /* Workaround for hardware read-after-write restriction */ - temp = smsc911x_reg_read(pdata, BYTE_TEST); - - /* Wait for the read to complete */ - if (likely(smsc911x_mac_complete(pdata) == 0)) - return smsc911x_reg_read(pdata, MAC_CSR_DATA); - - SMSC_WARN(pdata, hw, "MAC busy after read"); - return 0xFFFFFFFF; -} - -/* Set a mac register, mac_lock must be acquired before calling */ -static void smsc911x_mac_write(struct smsc911x_data *pdata, - unsigned int offset, u32 val) -{ - unsigned int temp; - - SMSC_ASSERT_MAC_LOCK(pdata); - - temp = smsc911x_reg_read(pdata, MAC_CSR_CMD); - if (unlikely(temp & MAC_CSR_CMD_CSR_BUSY_)) { - SMSC_WARN(pdata, hw, - "smsc911x_mac_write failed, MAC busy at entry"); - return; - } - - /* Send data to write */ - smsc911x_reg_write(pdata, MAC_CSR_DATA, val); - - /* Write the actual data */ - smsc911x_reg_write(pdata, MAC_CSR_CMD, ((offset & 0xFF) | - MAC_CSR_CMD_CSR_BUSY_)); - - /* Workaround for hardware read-after-write restriction */ - temp = smsc911x_reg_read(pdata, BYTE_TEST); - - /* Wait for the write to complete */ - if (likely(smsc911x_mac_complete(pdata) == 0)) - return; - - SMSC_WARN(pdata, hw, "smsc911x_mac_write failed, MAC busy after write"); -} - -/* Get a phy register */ -static int smsc911x_mii_read(struct mii_bus *bus, int phyaddr, int regidx) -{ - struct smsc911x_data *pdata = (struct smsc911x_data *)bus->priv; - unsigned long flags; - unsigned int addr; - int i, reg; - - spin_lock_irqsave(&pdata->mac_lock, flags); - - /* Confirm MII not busy */ - if (unlikely(smsc911x_mac_read(pdata, MII_ACC) & MII_ACC_MII_BUSY_)) { - SMSC_WARN(pdata, hw, "MII is busy in smsc911x_mii_read???"); - reg = -EIO; - goto out; - } - - /* Set the address, index & direction (read from PHY) */ - addr = ((phyaddr & 0x1F) << 11) | ((regidx & 0x1F) << 6); - smsc911x_mac_write(pdata, MII_ACC, addr); - - /* Wait for read to complete w/ timeout */ - for (i = 0; i < 100; i++) - if (!(smsc911x_mac_read(pdata, MII_ACC) & MII_ACC_MII_BUSY_)) { - reg = smsc911x_mac_read(pdata, MII_DATA); - goto out; - } - - SMSC_WARN(pdata, hw, "Timed out waiting for MII read to finish"); - reg = -EIO; - -out: - spin_unlock_irqrestore(&pdata->mac_lock, flags); - return reg; -} - -/* Set a phy register */ -static int smsc911x_mii_write(struct mii_bus *bus, int phyaddr, int regidx, - u16 val) -{ - struct smsc911x_data *pdata = (struct smsc911x_data *)bus->priv; - unsigned long flags; - unsigned int addr; - int i, reg; - - spin_lock_irqsave(&pdata->mac_lock, flags); - - /* Confirm MII not busy */ - if (unlikely(smsc911x_mac_read(pdata, MII_ACC) & MII_ACC_MII_BUSY_)) { - SMSC_WARN(pdata, hw, "MII is busy in smsc911x_mii_write???"); - reg = -EIO; - goto out; - } - - /* Put the data to write in the MAC */ - smsc911x_mac_write(pdata, MII_DATA, val); - - /* Set the address, index & direction (write to PHY) */ - addr = ((phyaddr & 0x1F) << 11) | ((regidx & 0x1F) << 6) | - MII_ACC_MII_WRITE_; - smsc911x_mac_write(pdata, MII_ACC, addr); - - /* Wait for write to complete w/ timeout */ - for (i = 0; i < 100; i++) - if (!(smsc911x_mac_read(pdata, MII_ACC) & MII_ACC_MII_BUSY_)) { - reg = 0; - goto out; - } - - SMSC_WARN(pdata, hw, "Timed out waiting for MII write to finish"); - reg = -EIO; - -out: - spin_unlock_irqrestore(&pdata->mac_lock, flags); - return reg; -} - -/* Switch to external phy. Assumes tx and rx are stopped. */ -static void smsc911x_phy_enable_external(struct smsc911x_data *pdata) -{ - unsigned int hwcfg = smsc911x_reg_read(pdata, HW_CFG); - - /* Disable phy clocks to the MAC */ - hwcfg &= (~HW_CFG_PHY_CLK_SEL_); - hwcfg |= HW_CFG_PHY_CLK_SEL_CLK_DIS_; - smsc911x_reg_write(pdata, HW_CFG, hwcfg); - udelay(10); /* Enough time for clocks to stop */ - - /* Switch to external phy */ - hwcfg |= HW_CFG_EXT_PHY_EN_; - smsc911x_reg_write(pdata, HW_CFG, hwcfg); - - /* Enable phy clocks to the MAC */ - hwcfg &= (~HW_CFG_PHY_CLK_SEL_); - hwcfg |= HW_CFG_PHY_CLK_SEL_EXT_PHY_; - smsc911x_reg_write(pdata, HW_CFG, hwcfg); - udelay(10); /* Enough time for clocks to restart */ - - hwcfg |= HW_CFG_SMI_SEL_; - smsc911x_reg_write(pdata, HW_CFG, hwcfg); -} - -/* Autodetects and enables external phy if present on supported chips. - * autodetection can be overridden by specifying SMSC911X_FORCE_INTERNAL_PHY - * or SMSC911X_FORCE_EXTERNAL_PHY in the platform_data flags. */ -static void smsc911x_phy_initialise_external(struct smsc911x_data *pdata) -{ - unsigned int hwcfg = smsc911x_reg_read(pdata, HW_CFG); - - if (pdata->config.flags & SMSC911X_FORCE_INTERNAL_PHY) { - SMSC_TRACE(pdata, hw, "Forcing internal PHY"); - pdata->using_extphy = 0; - } else if (pdata->config.flags & SMSC911X_FORCE_EXTERNAL_PHY) { - SMSC_TRACE(pdata, hw, "Forcing external PHY"); - smsc911x_phy_enable_external(pdata); - pdata->using_extphy = 1; - } else if (hwcfg & HW_CFG_EXT_PHY_DET_) { - SMSC_TRACE(pdata, hw, - "HW_CFG EXT_PHY_DET set, using external PHY"); - smsc911x_phy_enable_external(pdata); - pdata->using_extphy = 1; - } else { - SMSC_TRACE(pdata, hw, - "HW_CFG EXT_PHY_DET clear, using internal PHY"); - pdata->using_extphy = 0; - } -} - -/* Fetches a tx status out of the status fifo */ -static unsigned int smsc911x_tx_get_txstatus(struct smsc911x_data *pdata) -{ - unsigned int result = - smsc911x_reg_read(pdata, TX_FIFO_INF) & TX_FIFO_INF_TSUSED_; - - if (result != 0) - result = smsc911x_reg_read(pdata, TX_STATUS_FIFO); - - return result; -} - -/* Fetches the next rx status */ -static unsigned int smsc911x_rx_get_rxstatus(struct smsc911x_data *pdata) -{ - unsigned int result = - smsc911x_reg_read(pdata, RX_FIFO_INF) & RX_FIFO_INF_RXSUSED_; - - if (result != 0) - result = smsc911x_reg_read(pdata, RX_STATUS_FIFO); - - return result; -} - -#ifdef USE_PHY_WORK_AROUND -static int smsc911x_phy_check_loopbackpkt(struct smsc911x_data *pdata) -{ - unsigned int tries; - u32 wrsz; - u32 rdsz; - ulong bufp; - - for (tries = 0; tries < 10; tries++) { - unsigned int txcmd_a; - unsigned int txcmd_b; - unsigned int status; - unsigned int pktlength; - unsigned int i; - - /* Zero-out rx packet memory */ - memset(pdata->loopback_rx_pkt, 0, MIN_PACKET_SIZE); - - /* Write tx packet to 118 */ - txcmd_a = (u32)((ulong)pdata->loopback_tx_pkt & 0x03) << 16; - txcmd_a |= TX_CMD_A_FIRST_SEG_ | TX_CMD_A_LAST_SEG_; - txcmd_a |= MIN_PACKET_SIZE; - - txcmd_b = MIN_PACKET_SIZE << 16 | MIN_PACKET_SIZE; - - smsc911x_reg_write(pdata, TX_DATA_FIFO, txcmd_a); - smsc911x_reg_write(pdata, TX_DATA_FIFO, txcmd_b); - - bufp = (ulong)pdata->loopback_tx_pkt & (~0x3); - wrsz = MIN_PACKET_SIZE + 3; - wrsz += (u32)((ulong)pdata->loopback_tx_pkt & 0x3); - wrsz >>= 2; - - pdata->ops->tx_writefifo(pdata, (unsigned int *)bufp, wrsz); - - /* Wait till transmit is done */ - i = 60; - do { - udelay(5); - status = smsc911x_tx_get_txstatus(pdata); - } while ((i--) && (!status)); - - if (!status) { - SMSC_WARN(pdata, hw, - "Failed to transmit during loopback test"); - continue; - } - if (status & TX_STS_ES_) { - SMSC_WARN(pdata, hw, - "Transmit encountered errors during loopback test"); - continue; - } - - /* Wait till receive is done */ - i = 60; - do { - udelay(5); - status = smsc911x_rx_get_rxstatus(pdata); - } while ((i--) && (!status)); - - if (!status) { - SMSC_WARN(pdata, hw, - "Failed to receive during loopback test"); - continue; - } - if (status & RX_STS_ES_) { - SMSC_WARN(pdata, hw, - "Receive encountered errors during loopback test"); - continue; - } - - pktlength = ((status & 0x3FFF0000UL) >> 16); - bufp = (ulong)pdata->loopback_rx_pkt; - rdsz = pktlength + 3; - rdsz += (u32)((ulong)pdata->loopback_rx_pkt & 0x3); - rdsz >>= 2; - - pdata->ops->rx_readfifo(pdata, (unsigned int *)bufp, rdsz); - - if (pktlength != (MIN_PACKET_SIZE + 4)) { - SMSC_WARN(pdata, hw, "Unexpected packet size " - "during loop back test, size=%d, will retry", - pktlength); - } else { - unsigned int j; - int mismatch = 0; - for (j = 0; j < MIN_PACKET_SIZE; j++) { - if (pdata->loopback_tx_pkt[j] - != pdata->loopback_rx_pkt[j]) { - mismatch = 1; - break; - } - } - if (!mismatch) { - SMSC_TRACE(pdata, hw, "Successfully verified " - "loopback packet"); - return 0; - } else { - SMSC_WARN(pdata, hw, "Data mismatch " - "during loop back test, will retry"); - } - } - } - - return -EIO; -} - -static int smsc911x_phy_reset(struct smsc911x_data *pdata) -{ - struct phy_device *phy_dev = pdata->phy_dev; - unsigned int temp; - unsigned int i = 100000; - - BUG_ON(!phy_dev); - BUG_ON(!phy_dev->bus); - - SMSC_TRACE(pdata, hw, "Performing PHY BCR Reset"); - smsc911x_mii_write(phy_dev->bus, phy_dev->addr, MII_BMCR, BMCR_RESET); - do { - msleep(1); - temp = smsc911x_mii_read(phy_dev->bus, phy_dev->addr, - MII_BMCR); - } while ((i--) && (temp & BMCR_RESET)); - - if (temp & BMCR_RESET) { - SMSC_WARN(pdata, hw, "PHY reset failed to complete"); - return -EIO; - } - /* Extra delay required because the phy may not be completed with - * its reset when BMCR_RESET is cleared. Specs say 256 uS is - * enough delay but using 1ms here to be safe */ - msleep(1); - - return 0; -} - -static int smsc911x_phy_loopbacktest(struct net_device *dev) -{ - struct smsc911x_data *pdata = netdev_priv(dev); - struct phy_device *phy_dev = pdata->phy_dev; - int result = -EIO; - unsigned int i, val; - unsigned long flags; - - /* Initialise tx packet using broadcast destination address */ - memset(pdata->loopback_tx_pkt, 0xff, ETH_ALEN); - - /* Use incrementing source address */ - for (i = 6; i < 12; i++) - pdata->loopback_tx_pkt[i] = (char)i; - - /* Set length type field */ - pdata->loopback_tx_pkt[12] = 0x00; - pdata->loopback_tx_pkt[13] = 0x00; - - for (i = 14; i < MIN_PACKET_SIZE; i++) - pdata->loopback_tx_pkt[i] = (char)i; - - val = smsc911x_reg_read(pdata, HW_CFG); - val &= HW_CFG_TX_FIF_SZ_; - val |= HW_CFG_SF_; - smsc911x_reg_write(pdata, HW_CFG, val); - - smsc911x_reg_write(pdata, TX_CFG, TX_CFG_TX_ON_); - smsc911x_reg_write(pdata, RX_CFG, - (u32)((ulong)pdata->loopback_rx_pkt & 0x03) << 8); - - for (i = 0; i < 10; i++) { - /* Set PHY to 10/FD, no ANEG, and loopback mode */ - smsc911x_mii_write(phy_dev->bus, phy_dev->addr, MII_BMCR, - BMCR_LOOPBACK | BMCR_FULLDPLX); - - /* Enable MAC tx/rx, FD */ - spin_lock_irqsave(&pdata->mac_lock, flags); - smsc911x_mac_write(pdata, MAC_CR, MAC_CR_FDPX_ - | MAC_CR_TXEN_ | MAC_CR_RXEN_); - spin_unlock_irqrestore(&pdata->mac_lock, flags); - - if (smsc911x_phy_check_loopbackpkt(pdata) == 0) { - result = 0; - break; - } - pdata->resetcount++; - - /* Disable MAC rx */ - spin_lock_irqsave(&pdata->mac_lock, flags); - smsc911x_mac_write(pdata, MAC_CR, 0); - spin_unlock_irqrestore(&pdata->mac_lock, flags); - - smsc911x_phy_reset(pdata); - } - - /* Disable MAC */ - spin_lock_irqsave(&pdata->mac_lock, flags); - smsc911x_mac_write(pdata, MAC_CR, 0); - spin_unlock_irqrestore(&pdata->mac_lock, flags); - - /* Cancel PHY loopback mode */ - smsc911x_mii_write(phy_dev->bus, phy_dev->addr, MII_BMCR, 0); - - smsc911x_reg_write(pdata, TX_CFG, 0); - smsc911x_reg_write(pdata, RX_CFG, 0); - - return result; -} -#endif /* USE_PHY_WORK_AROUND */ - -static void smsc911x_phy_update_flowcontrol(struct smsc911x_data *pdata) -{ - struct phy_device *phy_dev = pdata->phy_dev; - u32 afc = smsc911x_reg_read(pdata, AFC_CFG); - u32 flow; - unsigned long flags; - - if (phy_dev->duplex == DUPLEX_FULL) { - u16 lcladv = phy_read(phy_dev, MII_ADVERTISE); - u16 rmtadv = phy_read(phy_dev, MII_LPA); - u8 cap = mii_resolve_flowctrl_fdx(lcladv, rmtadv); - - if (cap & FLOW_CTRL_RX) - flow = 0xFFFF0002; - else - flow = 0; - - if (cap & FLOW_CTRL_TX) - afc |= 0xF; - else - afc &= ~0xF; - - SMSC_TRACE(pdata, hw, "rx pause %s, tx pause %s", - (cap & FLOW_CTRL_RX ? "enabled" : "disabled"), - (cap & FLOW_CTRL_TX ? "enabled" : "disabled")); - } else { - SMSC_TRACE(pdata, hw, "half duplex"); - flow = 0; - afc |= 0xF; - } - - spin_lock_irqsave(&pdata->mac_lock, flags); - smsc911x_mac_write(pdata, FLOW, flow); - spin_unlock_irqrestore(&pdata->mac_lock, flags); - - smsc911x_reg_write(pdata, AFC_CFG, afc); -} - -/* Update link mode if anything has changed. Called periodically when the - * PHY is in polling mode, even if nothing has changed. */ -static void smsc911x_phy_adjust_link(struct net_device *dev) -{ - struct smsc911x_data *pdata = netdev_priv(dev); - struct phy_device *phy_dev = pdata->phy_dev; - unsigned long flags; - int carrier; - - if (phy_dev->duplex != pdata->last_duplex) { - unsigned int mac_cr; - SMSC_TRACE(pdata, hw, "duplex state has changed"); - - spin_lock_irqsave(&pdata->mac_lock, flags); - mac_cr = smsc911x_mac_read(pdata, MAC_CR); - if (phy_dev->duplex) { - SMSC_TRACE(pdata, hw, - "configuring for full duplex mode"); - mac_cr |= MAC_CR_FDPX_; - } else { - SMSC_TRACE(pdata, hw, - "configuring for half duplex mode"); - mac_cr &= ~MAC_CR_FDPX_; - } - smsc911x_mac_write(pdata, MAC_CR, mac_cr); - spin_unlock_irqrestore(&pdata->mac_lock, flags); - - smsc911x_phy_update_flowcontrol(pdata); - pdata->last_duplex = phy_dev->duplex; - } - - carrier = netif_carrier_ok(dev); - if (carrier != pdata->last_carrier) { - SMSC_TRACE(pdata, hw, "carrier state has changed"); - if (carrier) { - SMSC_TRACE(pdata, hw, "configuring for carrier OK"); - if ((pdata->gpio_orig_setting & GPIO_CFG_LED1_EN_) && - (!pdata->using_extphy)) { - /* Restore original GPIO configuration */ - pdata->gpio_setting = pdata->gpio_orig_setting; - smsc911x_reg_write(pdata, GPIO_CFG, - pdata->gpio_setting); - } - } else { - SMSC_TRACE(pdata, hw, "configuring for no carrier"); - /* Check global setting that LED1 - * usage is 10/100 indicator */ - pdata->gpio_setting = smsc911x_reg_read(pdata, - GPIO_CFG); - if ((pdata->gpio_setting & GPIO_CFG_LED1_EN_) && - (!pdata->using_extphy)) { - /* Force 10/100 LED off, after saving - * original GPIO configuration */ - pdata->gpio_orig_setting = pdata->gpio_setting; - - pdata->gpio_setting &= ~GPIO_CFG_LED1_EN_; - pdata->gpio_setting |= (GPIO_CFG_GPIOBUF0_ - | GPIO_CFG_GPIODIR0_ - | GPIO_CFG_GPIOD0_); - smsc911x_reg_write(pdata, GPIO_CFG, - pdata->gpio_setting); - } - } - pdata->last_carrier = carrier; - } -} - -static int smsc911x_mii_probe(struct net_device *dev) -{ - struct smsc911x_data *pdata = netdev_priv(dev); - struct phy_device *phydev = NULL; - int ret; - - /* find the first phy */ - phydev = phy_find_first(pdata->mii_bus); - if (!phydev) { - netdev_err(dev, "no PHY found\n"); - return -ENODEV; - } - - SMSC_TRACE(pdata, probe, "PHY: addr %d, phy_id 0x%08X", - phydev->addr, phydev->phy_id); - - ret = phy_connect_direct(dev, phydev, - &smsc911x_phy_adjust_link, 0, - pdata->config.phy_interface); - - if (ret) { - netdev_err(dev, "Could not attach to PHY\n"); - return ret; - } - - netdev_info(dev, - "attached PHY driver [%s] (mii_bus:phy_addr=%s, irq=%d)\n", - phydev->drv->name, dev_name(&phydev->dev), phydev->irq); - - /* mask with MAC supported features */ - phydev->supported &= (PHY_BASIC_FEATURES | SUPPORTED_Pause | - SUPPORTED_Asym_Pause); - phydev->advertising = phydev->supported; - - pdata->phy_dev = phydev; - pdata->last_duplex = -1; - pdata->last_carrier = -1; - -#ifdef USE_PHY_WORK_AROUND - if (smsc911x_phy_loopbacktest(dev) < 0) { - SMSC_WARN(pdata, hw, "Failed Loop Back Test"); - return -ENODEV; - } - SMSC_TRACE(pdata, hw, "Passed Loop Back Test"); -#endif /* USE_PHY_WORK_AROUND */ - - SMSC_TRACE(pdata, hw, "phy initialised successfully"); - return 0; -} - -static int __devinit smsc911x_mii_init(struct platform_device *pdev, - struct net_device *dev) -{ - struct smsc911x_data *pdata = netdev_priv(dev); - int err = -ENXIO, i; - - pdata->mii_bus = mdiobus_alloc(); - if (!pdata->mii_bus) { - err = -ENOMEM; - goto err_out_1; - } - - pdata->mii_bus->name = SMSC_MDIONAME; - snprintf(pdata->mii_bus->id, MII_BUS_ID_SIZE, "%x", pdev->id); - pdata->mii_bus->priv = pdata; - pdata->mii_bus->read = smsc911x_mii_read; - pdata->mii_bus->write = smsc911x_mii_write; - pdata->mii_bus->irq = pdata->phy_irq; - for (i = 0; i < PHY_MAX_ADDR; ++i) - pdata->mii_bus->irq[i] = PHY_POLL; - - pdata->mii_bus->parent = &pdev->dev; - - switch (pdata->idrev & 0xFFFF0000) { - case 0x01170000: - case 0x01150000: - case 0x117A0000: - case 0x115A0000: - /* External PHY supported, try to autodetect */ - smsc911x_phy_initialise_external(pdata); - break; - default: - SMSC_TRACE(pdata, hw, "External PHY is not supported, " - "using internal PHY"); - pdata->using_extphy = 0; - break; - } - - if (!pdata->using_extphy) { - /* Mask all PHYs except ID 1 (internal) */ - pdata->mii_bus->phy_mask = ~(1 << 1); - } - - if (mdiobus_register(pdata->mii_bus)) { - SMSC_WARN(pdata, probe, "Error registering mii bus"); - goto err_out_free_bus_2; - } - - if (smsc911x_mii_probe(dev) < 0) { - SMSC_WARN(pdata, probe, "Error registering mii bus"); - goto err_out_unregister_bus_3; - } - - return 0; - -err_out_unregister_bus_3: - mdiobus_unregister(pdata->mii_bus); -err_out_free_bus_2: - mdiobus_free(pdata->mii_bus); -err_out_1: - return err; -} - -/* Gets the number of tx statuses in the fifo */ -static unsigned int smsc911x_tx_get_txstatcount(struct smsc911x_data *pdata) -{ - return (smsc911x_reg_read(pdata, TX_FIFO_INF) - & TX_FIFO_INF_TSUSED_) >> 16; -} - -/* Reads tx statuses and increments counters where necessary */ -static void smsc911x_tx_update_txcounters(struct net_device *dev) -{ - struct smsc911x_data *pdata = netdev_priv(dev); - unsigned int tx_stat; - - while ((tx_stat = smsc911x_tx_get_txstatus(pdata)) != 0) { - if (unlikely(tx_stat & 0x80000000)) { - /* In this driver the packet tag is used as the packet - * length. Since a packet length can never reach the - * size of 0x8000, this bit is reserved. It is worth - * noting that the "reserved bit" in the warning above - * does not reference a hardware defined reserved bit - * but rather a driver defined one. - */ - SMSC_WARN(pdata, hw, "Packet tag reserved bit is high"); - } else { - if (unlikely(tx_stat & TX_STS_ES_)) { - dev->stats.tx_errors++; - } else { - dev->stats.tx_packets++; - dev->stats.tx_bytes += (tx_stat >> 16); - } - if (unlikely(tx_stat & TX_STS_EXCESS_COL_)) { - dev->stats.collisions += 16; - dev->stats.tx_aborted_errors += 1; - } else { - dev->stats.collisions += - ((tx_stat >> 3) & 0xF); - } - if (unlikely(tx_stat & TX_STS_LOST_CARRIER_)) - dev->stats.tx_carrier_errors += 1; - if (unlikely(tx_stat & TX_STS_LATE_COL_)) { - dev->stats.collisions++; - dev->stats.tx_aborted_errors++; - } - } - } -} - -/* Increments the Rx error counters */ -static void -smsc911x_rx_counterrors(struct net_device *dev, unsigned int rxstat) -{ - int crc_err = 0; - - if (unlikely(rxstat & RX_STS_ES_)) { - dev->stats.rx_errors++; - if (unlikely(rxstat & RX_STS_CRC_ERR_)) { - dev->stats.rx_crc_errors++; - crc_err = 1; - } - } - if (likely(!crc_err)) { - if (unlikely((rxstat & RX_STS_FRAME_TYPE_) && - (rxstat & RX_STS_LENGTH_ERR_))) - dev->stats.rx_length_errors++; - if (rxstat & RX_STS_MCAST_) - dev->stats.multicast++; - } -} - -/* Quickly dumps bad packets */ -static void -smsc911x_rx_fastforward(struct smsc911x_data *pdata, unsigned int pktbytes) -{ - unsigned int pktwords = (pktbytes + NET_IP_ALIGN + 3) >> 2; - - if (likely(pktwords >= 4)) { - unsigned int timeout = 500; - unsigned int val; - smsc911x_reg_write(pdata, RX_DP_CTRL, RX_DP_CTRL_RX_FFWD_); - do { - udelay(1); - val = smsc911x_reg_read(pdata, RX_DP_CTRL); - } while ((val & RX_DP_CTRL_RX_FFWD_) && --timeout); - - if (unlikely(timeout == 0)) - SMSC_WARN(pdata, hw, "Timed out waiting for " - "RX FFWD to finish, RX_DP_CTRL: 0x%08X", val); - } else { - unsigned int temp; - while (pktwords--) - temp = smsc911x_reg_read(pdata, RX_DATA_FIFO); - } -} - -/* NAPI poll function */ -static int smsc911x_poll(struct napi_struct *napi, int budget) -{ - struct smsc911x_data *pdata = - container_of(napi, struct smsc911x_data, napi); - struct net_device *dev = pdata->dev; - int npackets = 0; - - while (npackets < budget) { - unsigned int pktlength; - unsigned int pktwords; - struct sk_buff *skb; - unsigned int rxstat = smsc911x_rx_get_rxstatus(pdata); - - if (!rxstat) { - unsigned int temp; - /* We processed all packets available. Tell NAPI it can - * stop polling then re-enable rx interrupts */ - smsc911x_reg_write(pdata, INT_STS, INT_STS_RSFL_); - napi_complete(napi); - temp = smsc911x_reg_read(pdata, INT_EN); - temp |= INT_EN_RSFL_EN_; - smsc911x_reg_write(pdata, INT_EN, temp); - break; - } - - /* Count packet for NAPI scheduling, even if it has an error. - * Error packets still require cycles to discard */ - npackets++; |