diff options
author | Jeff Kirsher <jeffrey.t.kirsher@intel.com> | 2011-05-20 20:18:55 -0700 |
---|---|---|
committer | Jeff Kirsher <jeffrey.t.kirsher@intel.com> | 2011-08-12 00:21:51 -0700 |
commit | 527a626601de6ff89859de90883cc546892bf3ca (patch) | |
tree | 5e30febb8d509e036cee5702676f386a0d4e4ad3 /drivers/net/skge.c | |
parent | 1c1538be1da768fe0209a11e1bdf9dd7ab38905a (diff) |
skge/sky2/mv643xx/pxa168: Move the Marvell Ethernet drivers
Move the Marvell Ethernet drivers into drivers/net/ethernet/marvell/
and make the necessary Kconfig and Makefile changes.
CC: Sachin Sanap <ssanap@marvell.com>
CC: Zhangfei Gao <zgao6@marvell.com>
CC: Philip Rakity <prakity@marvell.com>
CC: Mark Brown <markb@marvell.com>
CC: Lennert Buytenhek <buytenh@marvell.com>
CC: Stephen Hemminger <shemminger@linux-foundation.org>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
Diffstat (limited to 'drivers/net/skge.c')
-rw-r--r-- | drivers/net/skge.c | 4133 |
1 files changed, 0 insertions, 4133 deletions
diff --git a/drivers/net/skge.c b/drivers/net/skge.c deleted file mode 100644 index 98ec614c569..00000000000 --- a/drivers/net/skge.c +++ /dev/null @@ -1,4133 +0,0 @@ -/* - * New driver for Marvell Yukon chipset and SysKonnect Gigabit - * Ethernet adapters. Based on earlier sk98lin, e100 and - * FreeBSD if_sk drivers. - * - * This driver intentionally does not support all the features - * of the original driver such as link fail-over and link management because - * those should be done at higher levels. - * - * Copyright (C) 2004, 2005 Stephen Hemminger <shemminger@osdl.org> - * - * 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. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include <linux/in.h> -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/moduleparam.h> -#include <linux/netdevice.h> -#include <linux/etherdevice.h> -#include <linux/ethtool.h> -#include <linux/pci.h> -#include <linux/if_vlan.h> -#include <linux/ip.h> -#include <linux/delay.h> -#include <linux/crc32.h> -#include <linux/dma-mapping.h> -#include <linux/debugfs.h> -#include <linux/sched.h> -#include <linux/seq_file.h> -#include <linux/mii.h> -#include <linux/slab.h> -#include <linux/dmi.h> -#include <linux/prefetch.h> -#include <asm/irq.h> - -#include "skge.h" - -#define DRV_NAME "skge" -#define DRV_VERSION "1.14" - -#define DEFAULT_TX_RING_SIZE 128 -#define DEFAULT_RX_RING_SIZE 512 -#define MAX_TX_RING_SIZE 1024 -#define TX_LOW_WATER (MAX_SKB_FRAGS + 1) -#define MAX_RX_RING_SIZE 4096 -#define RX_COPY_THRESHOLD 128 -#define RX_BUF_SIZE 1536 -#define PHY_RETRIES 1000 -#define ETH_JUMBO_MTU 9000 -#define TX_WATCHDOG (5 * HZ) -#define NAPI_WEIGHT 64 -#define BLINK_MS 250 -#define LINK_HZ HZ - -#define SKGE_EEPROM_MAGIC 0x9933aabb - - -MODULE_DESCRIPTION("SysKonnect Gigabit Ethernet driver"); -MODULE_AUTHOR("Stephen Hemminger <shemminger@linux-foundation.org>"); -MODULE_LICENSE("GPL"); -MODULE_VERSION(DRV_VERSION); - -static const u32 default_msg = (NETIF_MSG_DRV | NETIF_MSG_PROBE | - NETIF_MSG_LINK | NETIF_MSG_IFUP | - NETIF_MSG_IFDOWN); - -static int debug = -1; /* defaults above */ -module_param(debug, int, 0); -MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)"); - -static DEFINE_PCI_DEVICE_TABLE(skge_id_table) = { - { PCI_DEVICE(PCI_VENDOR_ID_3COM, 0x1700) }, /* 3Com 3C940 */ - { PCI_DEVICE(PCI_VENDOR_ID_3COM, 0x80EB) }, /* 3Com 3C940B */ -#ifdef CONFIG_SKGE_GENESIS - { PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, 0x4300) }, /* SK-9xx */ -#endif - { PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, 0x4320) }, /* SK-98xx V2.0 */ - { PCI_DEVICE(PCI_VENDOR_ID_DLINK, 0x4b01) }, /* D-Link DGE-530T (rev.B) */ - { PCI_DEVICE(PCI_VENDOR_ID_DLINK, 0x4c00) }, /* D-Link DGE-530T */ - { PCI_DEVICE(PCI_VENDOR_ID_DLINK, 0x4302) }, /* D-Link DGE-530T Rev C1 */ - { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4320) }, /* Marvell Yukon 88E8001/8003/8010 */ - { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x5005) }, /* Belkin */ - { PCI_DEVICE(PCI_VENDOR_ID_CNET, 0x434E) }, /* CNet PowerG-2000 */ - { PCI_DEVICE(PCI_VENDOR_ID_LINKSYS, 0x1064) }, /* Linksys EG1064 v2 */ - { PCI_VENDOR_ID_LINKSYS, 0x1032, PCI_ANY_ID, 0x0015 }, /* Linksys EG1032 v2 */ - { 0 } -}; -MODULE_DEVICE_TABLE(pci, skge_id_table); - -static int skge_up(struct net_device *dev); -static int skge_down(struct net_device *dev); -static void skge_phy_reset(struct skge_port *skge); -static void skge_tx_clean(struct net_device *dev); -static int xm_phy_write(struct skge_hw *hw, int port, u16 reg, u16 val); -static int gm_phy_write(struct skge_hw *hw, int port, u16 reg, u16 val); -static void genesis_get_stats(struct skge_port *skge, u64 *data); -static void yukon_get_stats(struct skge_port *skge, u64 *data); -static void yukon_init(struct skge_hw *hw, int port); -static void genesis_mac_init(struct skge_hw *hw, int port); -static void genesis_link_up(struct skge_port *skge); -static void skge_set_multicast(struct net_device *dev); - -/* Avoid conditionals by using array */ -static const int txqaddr[] = { Q_XA1, Q_XA2 }; -static const int rxqaddr[] = { Q_R1, Q_R2 }; -static const u32 rxirqmask[] = { IS_R1_F, IS_R2_F }; -static const u32 txirqmask[] = { IS_XA1_F, IS_XA2_F }; -static const u32 napimask[] = { IS_R1_F|IS_XA1_F, IS_R2_F|IS_XA2_F }; -static const u32 portmask[] = { IS_PORT_1, IS_PORT_2 }; - -static inline bool is_genesis(const struct skge_hw *hw) -{ -#ifdef CONFIG_SKGE_GENESIS - return hw->chip_id == CHIP_ID_GENESIS; -#else - return false; -#endif -} - -static int skge_get_regs_len(struct net_device *dev) -{ - return 0x4000; -} - -/* - * Returns copy of whole control register region - * Note: skip RAM address register because accessing it will - * cause bus hangs! - */ -static void skge_get_regs(struct net_device *dev, struct ethtool_regs *regs, - void *p) -{ - const struct skge_port *skge = netdev_priv(dev); - const void __iomem *io = skge->hw->regs; - - regs->version = 1; - memset(p, 0, regs->len); - memcpy_fromio(p, io, B3_RAM_ADDR); - - memcpy_fromio(p + B3_RI_WTO_R1, io + B3_RI_WTO_R1, - regs->len - B3_RI_WTO_R1); -} - -/* Wake on Lan only supported on Yukon chips with rev 1 or above */ -static u32 wol_supported(const struct skge_hw *hw) -{ - if (is_genesis(hw)) - return 0; - - if (hw->chip_id == CHIP_ID_YUKON && hw->chip_rev == 0) - return 0; - - return WAKE_MAGIC | WAKE_PHY; -} - -static void skge_wol_init(struct skge_port *skge) -{ - struct skge_hw *hw = skge->hw; - int port = skge->port; - u16 ctrl; - - skge_write16(hw, B0_CTST, CS_RST_CLR); - skge_write16(hw, SK_REG(port, GMAC_LINK_CTRL), GMLC_RST_CLR); - - /* Turn on Vaux */ - skge_write8(hw, B0_POWER_CTRL, - PC_VAUX_ENA | PC_VCC_ENA | PC_VAUX_ON | PC_VCC_OFF); - - /* WA code for COMA mode -- clear PHY reset */ - if (hw->chip_id == CHIP_ID_YUKON_LITE && - hw->chip_rev >= CHIP_REV_YU_LITE_A3) { - u32 reg = skge_read32(hw, B2_GP_IO); - reg |= GP_DIR_9; - reg &= ~GP_IO_9; - skge_write32(hw, B2_GP_IO, reg); - } - - skge_write32(hw, SK_REG(port, GPHY_CTRL), - GPC_DIS_SLEEP | - GPC_HWCFG_M_3 | GPC_HWCFG_M_2 | GPC_HWCFG_M_1 | GPC_HWCFG_M_0 | - GPC_ANEG_1 | GPC_RST_SET); - - skge_write32(hw, SK_REG(port, GPHY_CTRL), - GPC_DIS_SLEEP | - GPC_HWCFG_M_3 | GPC_HWCFG_M_2 | GPC_HWCFG_M_1 | GPC_HWCFG_M_0 | - GPC_ANEG_1 | GPC_RST_CLR); - - skge_write32(hw, SK_REG(port, GMAC_CTRL), GMC_RST_CLR); - - /* Force to 10/100 skge_reset will re-enable on resume */ - gm_phy_write(hw, port, PHY_MARV_AUNE_ADV, - (PHY_AN_100FULL | PHY_AN_100HALF | - PHY_AN_10FULL | PHY_AN_10HALF | PHY_AN_CSMA)); - /* no 1000 HD/FD */ - gm_phy_write(hw, port, PHY_MARV_1000T_CTRL, 0); - gm_phy_write(hw, port, PHY_MARV_CTRL, - PHY_CT_RESET | PHY_CT_SPS_LSB | PHY_CT_ANE | - PHY_CT_RE_CFG | PHY_CT_DUP_MD); - - - /* Set GMAC to no flow control and auto update for speed/duplex */ - gma_write16(hw, port, GM_GP_CTRL, - GM_GPCR_FC_TX_DIS|GM_GPCR_TX_ENA|GM_GPCR_RX_ENA| - GM_GPCR_DUP_FULL|GM_GPCR_FC_RX_DIS|GM_GPCR_AU_FCT_DIS); - - /* Set WOL address */ - memcpy_toio(hw->regs + WOL_REGS(port, WOL_MAC_ADDR), - skge->netdev->dev_addr, ETH_ALEN); - - /* Turn on appropriate WOL control bits */ - skge_write16(hw, WOL_REGS(port, WOL_CTRL_STAT), WOL_CTL_CLEAR_RESULT); - ctrl = 0; - if (skge->wol & WAKE_PHY) - ctrl |= WOL_CTL_ENA_PME_ON_LINK_CHG|WOL_CTL_ENA_LINK_CHG_UNIT; - else - ctrl |= WOL_CTL_DIS_PME_ON_LINK_CHG|WOL_CTL_DIS_LINK_CHG_UNIT; - - if (skge->wol & WAKE_MAGIC) - ctrl |= WOL_CTL_ENA_PME_ON_MAGIC_PKT|WOL_CTL_ENA_MAGIC_PKT_UNIT; - else - ctrl |= WOL_CTL_DIS_PME_ON_MAGIC_PKT|WOL_CTL_DIS_MAGIC_PKT_UNIT; - - ctrl |= WOL_CTL_DIS_PME_ON_PATTERN|WOL_CTL_DIS_PATTERN_UNIT; - skge_write16(hw, WOL_REGS(port, WOL_CTRL_STAT), ctrl); - - /* block receiver */ - skge_write8(hw, SK_REG(port, RX_GMF_CTRL_T), GMF_RST_SET); -} - -static void skge_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) -{ - struct skge_port *skge = netdev_priv(dev); - - wol->supported = wol_supported(skge->hw); - wol->wolopts = skge->wol; -} - -static int skge_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) -{ - struct skge_port *skge = netdev_priv(dev); - struct skge_hw *hw = skge->hw; - - if ((wol->wolopts & ~wol_supported(hw)) || - !device_can_wakeup(&hw->pdev->dev)) - return -EOPNOTSUPP; - - skge->wol = wol->wolopts; - - device_set_wakeup_enable(&hw->pdev->dev, skge->wol); - - return 0; -} - -/* Determine supported/advertised modes based on hardware. - * Note: ethtool ADVERTISED_xxx == SUPPORTED_xxx - */ -static u32 skge_supported_modes(const struct skge_hw *hw) -{ - u32 supported; - - if (hw->copper) { - supported = (SUPPORTED_10baseT_Half | - SUPPORTED_10baseT_Full | - SUPPORTED_100baseT_Half | - SUPPORTED_100baseT_Full | - SUPPORTED_1000baseT_Half | - SUPPORTED_1000baseT_Full | - SUPPORTED_Autoneg | - SUPPORTED_TP); - - if (is_genesis(hw)) - supported &= ~(SUPPORTED_10baseT_Half | - SUPPORTED_10baseT_Full | - SUPPORTED_100baseT_Half | - SUPPORTED_100baseT_Full); - - else if (hw->chip_id == CHIP_ID_YUKON) - supported &= ~SUPPORTED_1000baseT_Half; - } else - supported = (SUPPORTED_1000baseT_Full | - SUPPORTED_1000baseT_Half | - SUPPORTED_FIBRE | - SUPPORTED_Autoneg); - - return supported; -} - -static int skge_get_settings(struct net_device *dev, - struct ethtool_cmd *ecmd) -{ - struct skge_port *skge = netdev_priv(dev); - struct skge_hw *hw = skge->hw; - - ecmd->transceiver = XCVR_INTERNAL; - ecmd->supported = skge_supported_modes(hw); - - if (hw->copper) { - ecmd->port = PORT_TP; - ecmd->phy_address = hw->phy_addr; - } else - ecmd->port = PORT_FIBRE; - - ecmd->advertising = skge->advertising; - ecmd->autoneg = skge->autoneg; - ethtool_cmd_speed_set(ecmd, skge->speed); - ecmd->duplex = skge->duplex; - return 0; -} - -static int skge_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd) -{ - struct skge_port *skge = netdev_priv(dev); - const struct skge_hw *hw = skge->hw; - u32 supported = skge_supported_modes(hw); - int err = 0; - - if (ecmd->autoneg == AUTONEG_ENABLE) { - ecmd->advertising = supported; - skge->duplex = -1; - skge->speed = -1; - } else { - u32 setting; - u32 speed = ethtool_cmd_speed(ecmd); - - switch (speed) { - case SPEED_1000: - if (ecmd->duplex == DUPLEX_FULL) - setting = SUPPORTED_1000baseT_Full; - else if (ecmd->duplex == DUPLEX_HALF) - setting = SUPPORTED_1000baseT_Half; - else - return -EINVAL; - break; - case SPEED_100: - if (ecmd->duplex == DUPLEX_FULL) - setting = SUPPORTED_100baseT_Full; - else if (ecmd->duplex == DUPLEX_HALF) - setting = SUPPORTED_100baseT_Half; - else - return -EINVAL; - break; - - case SPEED_10: - if (ecmd->duplex == DUPLEX_FULL) - setting = SUPPORTED_10baseT_Full; - else if (ecmd->duplex == DUPLEX_HALF) - setting = SUPPORTED_10baseT_Half; - else - return -EINVAL; - break; - default: - return -EINVAL; - } - - if ((setting & supported) == 0) - return -EINVAL; - - skge->speed = speed; - skge->duplex = ecmd->duplex; - } - - skge->autoneg = ecmd->autoneg; - skge->advertising = ecmd->advertising; - - if (netif_running(dev)) { - skge_down(dev); - err = skge_up(dev); - if (err) { - dev_close(dev); - return err; - } - } - - return 0; -} - -static void skge_get_drvinfo(struct net_device *dev, - struct ethtool_drvinfo *info) -{ - struct skge_port *skge = netdev_priv(dev); - - strcpy(info->driver, DRV_NAME); - strcpy(info->version, DRV_VERSION); - strcpy(info->fw_version, "N/A"); - strcpy(info->bus_info, pci_name(skge->hw->pdev)); -} - -static const struct skge_stat { - char name[ETH_GSTRING_LEN]; - u16 xmac_offset; - u16 gma_offset; -} skge_stats[] = { - { "tx_bytes", XM_TXO_OK_HI, GM_TXO_OK_HI }, - { "rx_bytes", XM_RXO_OK_HI, GM_RXO_OK_HI }, - - { "tx_broadcast", XM_TXF_BC_OK, GM_TXF_BC_OK }, - { "rx_broadcast", XM_RXF_BC_OK, GM_RXF_BC_OK }, - { "tx_multicast", XM_TXF_MC_OK, GM_TXF_MC_OK }, - { "rx_multicast", XM_RXF_MC_OK, GM_RXF_MC_OK }, - { "tx_unicast", XM_TXF_UC_OK, GM_TXF_UC_OK }, - { "rx_unicast", XM_RXF_UC_OK, GM_RXF_UC_OK }, - { "tx_mac_pause", XM_TXF_MPAUSE, GM_TXF_MPAUSE }, - { "rx_mac_pause", XM_RXF_MPAUSE, GM_RXF_MPAUSE }, - - { "collisions", XM_TXF_SNG_COL, GM_TXF_SNG_COL }, - { "multi_collisions", XM_TXF_MUL_COL, GM_TXF_MUL_COL }, - { "aborted", XM_TXF_ABO_COL, GM_TXF_ABO_COL }, - { "late_collision", XM_TXF_LAT_COL, GM_TXF_LAT_COL }, - { "fifo_underrun", XM_TXE_FIFO_UR, GM_TXE_FIFO_UR }, - { "fifo_overflow", XM_RXE_FIFO_OV, GM_RXE_FIFO_OV }, - - { "rx_toolong", XM_RXF_LNG_ERR, GM_RXF_LNG_ERR }, - { "rx_jabber", XM_RXF_JAB_PKT, GM_RXF_JAB_PKT }, - { "rx_runt", XM_RXE_RUNT, GM_RXE_FRAG }, - { "rx_too_long", XM_RXF_LNG_ERR, GM_RXF_LNG_ERR }, - { "rx_fcs_error", XM_RXF_FCS_ERR, GM_RXF_FCS_ERR }, -}; - -static int skge_get_sset_count(struct net_device *dev, int sset) -{ - switch (sset) { - case ETH_SS_STATS: - return ARRAY_SIZE(skge_stats); - default: - return -EOPNOTSUPP; - } -} - -static void skge_get_ethtool_stats(struct net_device *dev, - struct ethtool_stats *stats, u64 *data) -{ - struct skge_port *skge = netdev_priv(dev); - - if (is_genesis(skge->hw)) - genesis_get_stats(skge, data); - else - yukon_get_stats(skge, data); -} - -/* Use hardware MIB variables for critical path statistics and - * transmit feedback not reported at interrupt. - * Other errors are accounted for in interrupt handler. - */ -static struct net_device_stats *skge_get_stats(struct net_device *dev) -{ - struct skge_port *skge = netdev_priv(dev); - u64 data[ARRAY_SIZE(skge_stats)]; - - if (is_genesis(skge->hw)) - genesis_get_stats(skge, data); - else - yukon_get_stats(skge, data); - - dev->stats.tx_bytes = data[0]; - dev->stats.rx_bytes = data[1]; - dev->stats.tx_packets = data[2] + data[4] + data[6]; - dev->stats.rx_packets = data[3] + data[5] + data[7]; - dev->stats.multicast = data[3] + data[5]; - dev->stats.collisions = data[10]; - dev->stats.tx_aborted_errors = data[12]; - - return &dev->stats; -} - -static void skge_get_strings(struct net_device *dev, u32 stringset, u8 *data) -{ - int i; - - switch (stringset) { - case ETH_SS_STATS: - for (i = 0; i < ARRAY_SIZE(skge_stats); i++) - memcpy(data + i * ETH_GSTRING_LEN, - skge_stats[i].name, ETH_GSTRING_LEN); - break; - } -} - -static void skge_get_ring_param(struct net_device *dev, - struct ethtool_ringparam *p) -{ - struct skge_port *skge = netdev_priv(dev); - - p->rx_max_pending = MAX_RX_RING_SIZE; - p->tx_max_pending = MAX_TX_RING_SIZE; - p->rx_mini_max_pending = 0; - p->rx_jumbo_max_pending = 0; - - p->rx_pending = skge->rx_ring.count; - p->tx_pending = skge->tx_ring.count; - p->rx_mini_pending = 0; - p->rx_jumbo_pending = 0; -} - -static int skge_set_ring_param(struct net_device *dev, - struct ethtool_ringparam *p) -{ - struct skge_port *skge = netdev_priv(dev); - int err = 0; - - if (p->rx_pending == 0 || p->rx_pending > MAX_RX_RING_SIZE || - p->tx_pending < TX_LOW_WATER || p->tx_pending > MAX_TX_RING_SIZE) - return -EINVAL; - - skge->rx_ring.count = p->rx_pending; - skge->tx_ring.count = p->tx_pending; - - if (netif_running(dev)) { - skge_down(dev); - err = skge_up(dev); - if (err) - dev_close(dev); - } - - return err; -} - -static u32 skge_get_msglevel(struct net_device *netdev) -{ - struct skge_port *skge = netdev_priv(netdev); - return skge->msg_enable; -} - -static void skge_set_msglevel(struct net_device *netdev, u32 value) -{ - struct skge_port *skge = netdev_priv(netdev); - skge->msg_enable = value; -} - -static int skge_nway_reset(struct net_device *dev) -{ - struct skge_port *skge = netdev_priv(dev); - - if (skge->autoneg != AUTONEG_ENABLE || !netif_running(dev)) - return -EINVAL; - - skge_phy_reset(skge); - return 0; -} - -static void skge_get_pauseparam(struct net_device *dev, - struct ethtool_pauseparam *ecmd) -{ - struct skge_port *skge = netdev_priv(dev); - - ecmd->rx_pause = ((skge->flow_control == FLOW_MODE_SYMMETRIC) || - (skge->flow_control == FLOW_MODE_SYM_OR_REM)); - ecmd->tx_pause = (ecmd->rx_pause || - (skge->flow_control == FLOW_MODE_LOC_SEND)); - - ecmd->autoneg = ecmd->rx_pause || ecmd->tx_pause; -} - -static int skge_set_pauseparam(struct net_device *dev, - struct ethtool_pauseparam *ecmd) -{ - struct skge_port *skge = netdev_priv(dev); - struct ethtool_pauseparam old; - int err = 0; - - skge_get_pauseparam(dev, &old); - - if (ecmd->autoneg != old.autoneg) - skge->flow_control = ecmd->autoneg ? FLOW_MODE_NONE : FLOW_MODE_SYMMETRIC; - else { - if (ecmd->rx_pause && ecmd->tx_pause) - skge->flow_control = FLOW_MODE_SYMMETRIC; - else if (ecmd->rx_pause && !ecmd->tx_pause) - skge->flow_control = FLOW_MODE_SYM_OR_REM; - else if (!ecmd->rx_pause && ecmd->tx_pause) - skge->flow_control = FLOW_MODE_LOC_SEND; - else - skge->flow_control = FLOW_MODE_NONE; - } - - if (netif_running(dev)) { - skge_down(dev); - err = skge_up(dev); - if (err) { - dev_close(dev); - return err; - } - } - - return 0; -} - -/* Chip internal frequency for clock calculations */ -static inline u32 hwkhz(const struct skge_hw *hw) -{ - return is_genesis(hw) ? 53125 : 78125; -} - -/* Chip HZ to microseconds */ -static inline u32 skge_clk2usec(const struct skge_hw *hw, u32 ticks) -{ - return (ticks * 1000) / hwkhz(hw); -} - -/* Microseconds to chip HZ */ -static inline u32 skge_usecs2clk(const struct skge_hw *hw, u32 usec) -{ - return hwkhz(hw) * usec / 1000; -} - -static int skge_get_coalesce(struct net_device *dev, - struct ethtool_coalesce *ecmd) -{ - struct skge_port *skge = netdev_priv(dev); - struct skge_hw *hw = skge->hw; - int port = skge->port; - - ecmd->rx_coalesce_usecs = 0; - ecmd->tx_coalesce_usecs = 0; - - if (skge_read32(hw, B2_IRQM_CTRL) & TIM_START) { - u32 delay = skge_clk2usec(hw, skge_read32(hw, B2_IRQM_INI)); - u32 msk = skge_read32(hw, B2_IRQM_MSK); - - if (msk & rxirqmask[port]) - ecmd->rx_coalesce_usecs = delay; - if (msk & txirqmask[port]) - ecmd->tx_coalesce_usecs = delay; - } - - return 0; -} - -/* Note: interrupt timer is per board, but can turn on/off per port */ -static int skge_set_coalesce(struct net_device *dev, - struct ethtool_coalesce *ecmd) -{ - struct skge_port *skge = netdev_priv(dev); - struct skge_hw *hw = skge->hw; - int port = skge->port; - u32 msk = skge_read32(hw, B2_IRQM_MSK); - u32 delay = 25; - - if (ecmd->rx_coalesce_usecs == 0) - msk &= ~rxirqmask[port]; - else if (ecmd->rx_coalesce_usecs < 25 || - ecmd->rx_coalesce_usecs > 33333) - return -EINVAL; - else { - msk |= rxirqmask[port]; - delay = ecmd->rx_coalesce_usecs; - } - - if (ecmd->tx_coalesce_usecs == 0) - msk &= ~txirqmask[port]; - else if (ecmd->tx_coalesce_usecs < 25 || - ecmd->tx_coalesce_usecs > 33333) - return -EINVAL; - else { - msk |= txirqmask[port]; - delay = min(delay, ecmd->rx_coalesce_usecs); - } - - skge_write32(hw, B2_IRQM_MSK, msk); - if (msk == 0) - skge_write32(hw, B2_IRQM_CTRL, TIM_STOP); - else { - skge_write32(hw, B2_IRQM_INI, skge_usecs2clk(hw, delay)); - skge_write32(hw, B2_IRQM_CTRL, TIM_START); - } - return 0; -} - -enum led_mode { LED_MODE_OFF, LED_MODE_ON, LED_MODE_TST }; -static void skge_led(struct skge_port *skge, enum led_mode mode) -{ - struct skge_hw *hw = skge->hw; - int port = skge->port; - - spin_lock_bh(&hw->phy_lock); - if (is_genesis(hw)) { - switch (mode) { - case LED_MODE_OFF: - if (hw->phy_type == SK_PHY_BCOM) - xm_phy_write(hw, port, PHY_BCOM_P_EXT_CTRL, PHY_B_PEC_LED_OFF); - else { - skge_write32(hw, SK_REG(port, TX_LED_VAL), 0); - skge_write8(hw, SK_REG(port, TX_LED_CTRL), LED_T_OFF); - } - skge_write8(hw, SK_REG(port, LNK_LED_REG), LINKLED_OFF); - skge_write32(hw, SK_REG(port, RX_LED_VAL), 0); - skge_write8(hw, SK_REG(port, RX_LED_CTRL), LED_T_OFF); - break; - - case LED_MODE_ON: - skge_write8(hw, SK_REG(port, LNK_LED_REG), LINKLED_ON); - skge_write8(hw, SK_REG(port, LNK_LED_REG), LINKLED_LINKSYNC_ON); - - skge_write8(hw, SK_REG(port, RX_LED_CTRL), LED_START); - skge_write8(hw, SK_REG(port, TX_LED_CTRL), LED_START); - - break; - - case LED_MODE_TST: - skge_write8(hw, SK_REG(port, RX_LED_TST), LED_T_ON); - skge_write32(hw, SK_REG(port, RX_LED_VAL), 100); - skge_write8(hw, SK_REG(port, RX_LED_CTRL), LED_START); - - if (hw->phy_type == SK_PHY_BCOM) - xm_phy_write(hw, port, PHY_BCOM_P_EXT_CTRL, PHY_B_PEC_LED_ON); - else { - skge_write8(hw, SK_REG(port, TX_LED_TST), LED_T_ON); - skge_write32(hw, SK_REG(port, TX_LED_VAL), 100); - skge_write8(hw, SK_REG(port, TX_LED_CTRL), LED_START); - } - - } - } else { - switch (mode) { - case LED_MODE_OFF: - gm_phy_write(hw, port, PHY_MARV_LED_CTRL, 0); - gm_phy_write(hw, port, PHY_MARV_LED_OVER, - PHY_M_LED_MO_DUP(MO_LED_OFF) | - PHY_M_LED_MO_10(MO_LED_OFF) | - PHY_M_LED_MO_100(MO_LED_OFF) | - PHY_M_LED_MO_1000(MO_LED_OFF) | - PHY_M_LED_MO_RX(MO_LED_OFF)); - break; - case LED_MODE_ON: - gm_phy_write(hw, port, PHY_MARV_LED_CTRL, - PHY_M_LED_PULS_DUR(PULS_170MS) | - PHY_M_LED_BLINK_RT(BLINK_84MS) | - PHY_M_LEDC_TX_CTRL | - PHY_M_LEDC_DP_CTRL); - - gm_phy_write(hw, port, PHY_MARV_LED_OVER, - PHY_M_LED_MO_RX(MO_LED_OFF) | - (skge->speed == SPEED_100 ? - PHY_M_LED_MO_100(MO_LED_ON) : 0)); - break; - case LED_MODE_TST: - gm_phy_write(hw, port, PHY_MARV_LED_CTRL, 0); - gm_phy_write(hw, port, PHY_MARV_LED_OVER, - PHY_M_LED_MO_DUP(MO_LED_ON) | - PHY_M_LED_MO_10(MO_LED_ON) | - PHY_M_LED_MO_100(MO_LED_ON) | - PHY_M_LED_MO_1000(MO_LED_ON) | - PHY_M_LED_MO_RX(MO_LED_ON)); - } - } - spin_unlock_bh(&hw->phy_lock); -} - -/* blink LED's for finding board */ -static int skge_set_phys_id(struct net_device *dev, - enum ethtool_phys_id_state state) -{ - struct skge_port *skge = netdev_priv(dev); - - switch (state) { - case ETHTOOL_ID_ACTIVE: - return 2; /* cycle on/off twice per second */ - - case ETHTOOL_ID_ON: - skge_led(skge, LED_MODE_TST); - break; - - case ETHTOOL_ID_OFF: - skge_led(skge, LED_MODE_OFF); - break; - - case ETHTOOL_ID_INACTIVE: - /* back to regular LED state */ - skge_led(skge, netif_running(dev) ? LED_MODE_ON : LED_MODE_OFF); - } - - return 0; -} - -static int skge_get_eeprom_len(struct net_device *dev) -{ - struct skge_port *skge = netdev_priv(dev); - u32 reg2; - - pci_read_config_dword(skge->hw->pdev, PCI_DEV_REG2, ®2); - return 1 << (((reg2 & PCI_VPD_ROM_SZ) >> 14) + 8); -} - -static u32 skge_vpd_read(struct pci_dev *pdev, int cap, u16 offset) -{ - u32 val; - - pci_write_config_word(pdev, cap + PCI_VPD_ADDR, offset); - - do { - pci_read_config_word(pdev, cap + PCI_VPD_ADDR, &offset); - } while (!(offset & PCI_VPD_ADDR_F)); - - pci_read_config_dword(pdev, cap + PCI_VPD_DATA, &val); - return val; -} - -static void skge_vpd_write(struct pci_dev *pdev, int cap, u16 offset, u32 val) -{ - pci_write_config_dword(pdev, cap + PCI_VPD_DATA, val); - pci_write_config_word(pdev, cap + PCI_VPD_ADDR, - offset | PCI_VPD_ADDR_F); - - do { - pci_read_config_word(pdev, cap + PCI_VPD_ADDR, &offset); - } while (offset & PCI_VPD_ADDR_F); -} - -static int skge_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom, - u8 *data) -{ - struct skge_port *skge = netdev_priv(dev); - struct pci_dev *pdev = skge->hw->pdev; - int cap = pci_find_capability(pdev, PCI_CAP_ID_VPD); - int length = eeprom->len; - u16 offset = eeprom->offset; - - if (!cap) - return -EINVAL; - - eeprom->magic = SKGE_EEPROM_MAGIC; - - while (length > 0) { - u32 val = skge_vpd_read(pdev, cap, offset); - int n = min_t(int, length, sizeof(val)); - - memcpy(data, &val, n); - length -= n; - data += n; - offset += n; - } - return 0; -} - -static int skge_set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom, - u8 *data) -{ - struct skge_port *skge = netdev_priv(dev); - struct pci_dev *pdev = skge->hw->pdev; - int cap = pci_find_capability(pdev, PCI_CAP_ID_VPD); - int length = eeprom->len; - u16 offset = eeprom->offset; - - if (!cap) - return -EINVAL; - - if (eeprom->magic != SKGE_EEPROM_MAGIC) - return -EINVAL; - - while (length > 0) { - u32 val; - int n = min_t(int, length, sizeof(val)); - - if (n < sizeof(val)) - val = skge_vpd_read(pdev, cap, offset); - memcpy(&val, data, n); - - skge_vpd_write(pdev, cap, offset, val); - - length -= n; - data += n; - offset += n; - } - return 0; -} - -static const struct ethtool_ops skge_ethtool_ops = { - .get_settings = skge_get_settings, - .set_settings = skge_set_settings, - .get_drvinfo = skge_get_drvinfo, - .get_regs_len = skge_get_regs_len, - .get_regs = skge_get_regs, - .get_wol = skge_get_wol, - .set_wol = skge_set_wol, - .get_msglevel = skge_get_msglevel, - .set_msglevel = skge_set_msglevel, - .nway_reset = skge_nway_reset, - .get_link = ethtool_op_get_link, - .get_eeprom_len = skge_get_eeprom_len, - .get_eeprom = skge_get_eeprom, - .set_eeprom = skge_set_eeprom, - .get_ringparam = skge_get_ring_param, - .set_ringparam = skge_set_ring_param, - .get_pauseparam = skge_get_pauseparam, - .set_pauseparam = skge_set_pauseparam, - .get_coalesce = skge_get_coalesce, - .set_coalesce = skge_set_coalesce, - .get_strings = skge_get_strings, - .set_phys_id = skge_set_phys_id, - .get_sset_count = skge_get_sset_count, - .get_ethtool_stats = skge_get_ethtool_stats, -}; - -/* - * Allocate ring elements and chain them together - * One-to-one association of board descriptors with ring elements - */ -static int skge_ring_alloc(struct skge_ring *ring, void *vaddr, u32 base) -{ - struct skge_tx_desc *d; - struct skge_element *e; - int i; - - ring->start = kcalloc(ring->count, sizeof(*e), GFP_KERNEL); - if (!ring->start) - return -ENOMEM; - - for (i = 0, e = ring->start, d = vaddr; i < ring->count; i++, e++, d++) { - e->desc = d; - if (i == ring->count - 1) { - e->next = ring->start; - d->next_offset = base; - } else { - e->next = e + 1; - d->next_offset = base + (i+1) * sizeof(*d); - } - } - ring->to_use = ring->to_clean = ring->start; - - return 0; -} - -/* Allocate and setup a new buffer for receiving */ -static void skge_rx_setup(struct skge_port *skge, struct skge_element *e, - struct sk_buff *skb, unsigned int bufsize) -{ - struct skge_rx_desc *rd = e->desc; - u64 map; - - map = pci_map_single(skge->hw->pdev, skb->data, bufsize, - PCI_DMA_FROMDEVICE); - - rd->dma_lo = map; - rd->dma_hi = map >> 32; - e->skb = skb; - rd->csum1_start = ETH_HLEN; - rd->csum2_start = ETH_HLEN; - rd->csum1 = 0; - rd->csum2 = 0; - - wmb(); - - rd->control = BMU_OWN | BMU_STF | BMU_IRQ_EOF | BMU_TCP_CHECK | bufsize; - dma_unmap_addr_set(e, mapaddr, map); - dma_unmap_len_set(e, maplen, bufsize); -} - -/* Resume receiving using existing skb, - * Note: DMA address is not changed by chip. - * MTU not changed while receiver active. - */ -static inline void skge_rx_reuse(struct skge_element *e, unsigned int size) -{ - struct skge_rx_desc *rd = e->desc; - - rd->csum2 = 0; - rd->csum2_start = ETH_HLEN; - - wmb(); - - rd->control = BMU_OWN | BMU_STF | BMU_IRQ_EOF | BMU_TCP_CHECK | size; -} - - -/* Free all buffers in receive ring, assumes receiver stopped */ -static void skge_rx_clean(struct skge_port *skge) -{ - struct skge_hw *hw = skge->hw; - struct skge_ring *ring = &skge->rx_ring; - struct skge_element *e; - - e = ring->start; - do { - struct skge_rx_desc *rd = e->desc; - rd->control = 0; - if (e->skb) { - pci_unmap_single(hw->pdev, - dma_unmap_addr(e, mapaddr), - dma_unmap_len(e, maplen), - PCI_DMA_FROMDEVICE); - dev_kfree_skb(e->skb); - e->skb = NULL; - } - } while ((e = e->next) != ring->start); -} - - -/* Allocate buffers for receive ring - * For receive: to_clean is next received frame. - */ -static int skge_rx_fill(struct net_device *dev) -{ - struct skge_port *skge = netdev_priv(dev); - struct skge_ring *ring = &skge->rx_ring; - struct skge_element *e; - - e = ring->start; - do { - struct sk_buff *skb; - - skb = __netdev_alloc_skb(dev, skge->rx_buf_size + NET_IP_ALIGN, - GFP_KERNEL); - if (!skb) - return -ENOMEM; - - skb_reserve(skb, NET_IP_ALIGN); - skge_rx_setup(skge, e, skb, skge->rx_buf_size); - } while ((e = e->next) != ring->start); - - ring->to_clean = ring->start; - return 0; -} - -static const char *skge_pause(enum pause_status status) -{ - switch (status) { - case FLOW_STAT_NONE: - return "none"; - case FLOW_STAT_REM_SEND: - return "rx only"; - case FLOW_STAT_LOC_SEND: - return "tx_only"; - case FLOW_STAT_SYMMETRIC: /* Both station may send PAUSE */ - return "both"; - default: - return "indeterminated"; - } -} - - -static void skge_link_up(struct skge_port *skge) -{ - skge_write8(skge->hw, SK_REG(skge->port, LNK_LED_REG), - LED_BLK_OFF|LED_SYNC_OFF|LED_ON); - - netif_carrier_on(skge->netdev); - netif_wake_queue(skge->netdev); - - netif_info(skge, link, skge->netdev, - "Link is up at %d Mbps, %s duplex, flow control %s\n", - skge->speed, - skge->duplex == DUPLEX_FULL ? "full" : "half", - skge_pause(skge->flow_status)); -} - -static void skge_link_down(struct skge_port *skge) -{ - skge_write8(skge->hw, SK_REG(skge->port, LNK_LED_REG), LED_OFF); - netif_carrier_off(skge->netdev); - netif_stop_queue(skge->netdev); - - netif_info(skge, link, skge->netdev, "Link is down\n"); -} - -static void xm_link_down(struct skge_hw *hw, int port) -{ - struct net_device *dev = hw->dev[port]; - struct skge_port *skge = netdev_priv(dev); - - xm_write16(hw, port, XM_IMSK, XM_IMSK_DISABLE); - - if (netif_carrier_ok(dev)) - skge_link_down(skge); -} - -static int __xm_phy_read(struct skge_hw *hw, int port, u16 reg, u16 *val) -{ - int i; - - xm_write16(hw, port, XM_PHY_ADDR, reg | hw->phy_addr); - *val = xm_read16(hw, port, XM_PHY_DATA); - - if (hw->phy_type == SK_PHY_XMAC) - goto ready; - - for (i = 0; i < PHY_RETRIES; i++) { - if (xm_read16(hw, port, XM_MMU_CMD) & XM_MMU_PHY_RDY) - goto ready; - udelay(1); - } - - return -ETIMEDOUT; - ready: - *val = xm_read16(hw, port, XM_PHY_DATA); - - return 0; -} - -static u16 xm_phy_read(struct skge_hw *hw, int port, u16 reg) -{ - u16 v = 0; - if (__xm_phy_read(hw, port, reg, &v)) - pr_warning("%s: phy read timed out\n", hw->dev[port]->name); - return v; -} - -static int xm_phy_write(struct skge_hw *hw, int port, u16 reg, u16 val) -{ - int i; - - xm_write16(hw, port, XM_PHY_ADDR, reg | hw->phy_addr); - for (i = 0; i < PHY_RETRIES; i++) { - if (!(xm_read16(hw, port, XM_MMU_CMD) & XM_MMU_PHY_BUSY)) - goto ready; - udelay(1); - } - return -EIO; - - ready: - xm_write16(hw, port, XM_PHY_DATA, val); - for (i = 0; i < PHY_RETRIES; i++) { - if (!(xm_read16(hw, port, XM_MMU_CMD) & XM_MMU_PHY_BUSY)) - return 0; - udelay(1); - } - return -ETIMEDOUT; -} - -static void genesis_init(struct skge_hw *hw) -{ - /* set blink source counter */ - skge_write32(hw, B2_BSC_INI, (SK_BLK_DUR * SK_FACT_53) / 100); - skge_write8(hw, B2_BSC_CTRL, BSC_START); - - /* configure mac arbiter */ - skge_write16(hw, B3_MA_TO_CTRL, MA_RST_CLR); - - /* configure mac arbiter timeout values */ - skge_write8(hw, B3_MA_TOINI_RX1, SK_MAC_TO_53); - skge_write8(hw, B3_MA_TOINI_RX2, SK_MAC_TO_53); - skge_write8(hw, B3_MA_TOINI_TX1, SK_MAC_TO_53); - skge_write8(hw, B3_MA_TOINI_TX2, SK_MAC_TO_53); - - skge_write8(hw, B3_MA_RCINI_RX1, 0); |