aboutsummaryrefslogtreecommitdiff
path: root/drivers/net/skge.c
diff options
context:
space:
mode:
authorJeff Kirsher <jeffrey.t.kirsher@intel.com>2011-05-20 20:18:55 -0700
committerJeff Kirsher <jeffrey.t.kirsher@intel.com>2011-08-12 00:21:51 -0700
commit527a626601de6ff89859de90883cc546892bf3ca (patch)
tree5e30febb8d509e036cee5702676f386a0d4e4ad3 /drivers/net/skge.c
parent1c1538be1da768fe0209a11e1bdf9dd7ab38905a (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.c4133
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, &reg2);
- 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);