From eb8d374abcbb5418512ba73bba305c2ebe5161fd Mon Sep 17 00:00:00 2001 From: Andy Gospodarek Date: Thu, 3 Apr 2008 15:20:32 -0400 Subject: [PATCH] Update skge driver to upstream version 1.10. RHBZ 406051 --- drivers/net/skge.c | 914 +++++++++++++++++++++++++++++++++++----------------- drivers/net/skge.h | 64 +++- 2 files changed, 675 insertions(+), 303 deletions(-) diff --git a/drivers/net/skge.c b/drivers/net/skge.c index ad878df..39a394d 100644 --- a/drivers/net/skge.c +++ b/drivers/net/skge.c @@ -43,7 +43,7 @@ #include "skge.h" #define DRV_NAME "skge" -#define DRV_VERSION "1.6" +#define DRV_VERSION "1.10" #define PFX DRV_NAME " " #define DEFAULT_TX_RING_SIZE 128 @@ -58,6 +58,7 @@ #define TX_WATCHDOG (5 * HZ) #define NAPI_WEIGHT 64 #define BLINK_MS 250 +#define LINK_HZ (HZ/2) MODULE_DESCRIPTION("SysKonnect Gigabit Ethernet driver"); MODULE_AUTHOR("Stephen Hemminger "); @@ -77,13 +78,13 @@ static const struct pci_device_id skge_id_table[] = { { PCI_DEVICE(PCI_VENDOR_ID_3COM, PCI_DEVICE_ID_3COM_3C940B) }, { PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, PCI_DEVICE_ID_SYSKONNECT_GE) }, { PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, PCI_DEVICE_ID_SYSKONNECT_YU) }, - { PCI_DEVICE(PCI_VENDOR_ID_DLINK, PCI_DEVICE_ID_DLINK_DGE510T), }, + { PCI_DEVICE(PCI_VENDOR_ID_DLINK, PCI_DEVICE_ID_DLINK_DGE510T) }, { PCI_DEVICE(PCI_VENDOR_ID_DLINK, 0x4b01) }, /* DGE-530T */ { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4320) }, { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x5005) }, /* Belkin */ { PCI_DEVICE(PCI_VENDOR_ID_CNET, PCI_DEVICE_ID_CNET_GIGACARD) }, { PCI_DEVICE(PCI_VENDOR_ID_LINKSYS, PCI_DEVICE_ID_LINKSYS_EG1064) }, - { PCI_VENDOR_ID_LINKSYS, 0x1032, PCI_ANY_ID, 0x0015, }, + { PCI_VENDOR_ID_LINKSYS, 0x1032, PCI_ANY_ID, 0x0015 }, { 0 } }; MODULE_DEVICE_TABLE(pci, skge_id_table); @@ -91,7 +92,7 @@ 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 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); @@ -105,6 +106,7 @@ 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 irqmask[] = { IS_R1_F|IS_XA1_F, IS_R2_F|IS_XA2_F }; static int skge_get_regs_len(struct net_device *dev) { @@ -131,18 +133,93 @@ static void skge_get_regs(struct net_device *dev, struct ethtool_regs *regs, } /* Wake on Lan only supported on Yukon chips with rev 1 or above */ -static int wol_supported(const struct skge_hw *hw) +static u32 wol_supported(const struct skge_hw *hw) { - return !((hw->chip_id == CHIP_ID_GENESIS || - (hw->chip_id == CHIP_ID_YUKON && hw->chip_rev == 0))); + if (hw->chip_id == CHIP_ID_YUKON && hw->chip_rev != 0) + return WAKE_MAGIC | WAKE_PHY; + else + return 0; +} + +static u32 pci_wake_enabled(struct pci_dev *dev) +{ + int pm = pci_find_capability(dev, PCI_CAP_ID_PM); + u16 value; + + /* If device doesn't support PM Capabilities, but request is to disable + * wake events, it's a nop; otherwise fail */ + if (!pm) + return 0; + + pci_read_config_word(dev, pm + PCI_PM_PMC, &value); + + value &= PCI_PM_CAP_PME_MASK; + value >>= ffs(PCI_PM_CAP_PME_MASK) - 1; /* First bit of mask */ + + return value != 0; +} + +static void skge_wol_init(struct skge_port *skge) +{ + struct skge_hw *hw = skge->hw; + int port = skge->port; + enum pause_control save_mode; + u32 ctrl; + + /* Bring hardware out of reset */ + skge_write16(hw, B0_CTST, CS_RST_CLR); + skge_write16(hw, SK_REG(port, GMAC_LINK_CTRL), GMLC_RST_CLR); + + skge_write8(hw, SK_REG(port, GPHY_CTRL), GPC_RST_CLR); + skge_write8(hw, SK_REG(port, GMAC_CTRL), GMC_RST_CLR); + + /* Force to 10/100 skge_reset will re-enable on resume */ + save_mode = skge->flow_control; + skge->flow_control = FLOW_MODE_SYMMETRIC; + + ctrl = skge->advertising; + skge->advertising &= ~(ADVERTISED_1000baseT_Half|ADVERTISED_1000baseT_Full); + + skge_phy_reset(skge); + + skge->flow_control = save_mode; + skge->advertising = ctrl; + + /* 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) ? WAKE_MAGIC : 0; - wol->wolopts = skge->wol ? WAKE_MAGIC : 0; + wol->supported = wol_supported(skge->hw); + wol->wolopts = skge->wol; } static int skge_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) @@ -150,23 +227,12 @@ 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 != WAKE_MAGIC && wol->wolopts != 0) + if (wol->wolopts & wol_supported(hw)) return -EOPNOTSUPP; - if (wol->wolopts == WAKE_MAGIC && !wol_supported(hw)) - return -EOPNOTSUPP; - - skge->wol = wol->wolopts == WAKE_MAGIC; - - if (skge->wol) { - memcpy_toio(hw->regs + WOL_MAC_ADDR, dev->dev_addr, ETH_ALEN); - - skge_write16(hw, WOL_CTRL_STAT, - WOL_CTL_ENA_PME_ON_MAGIC_PKT | - WOL_CTL_ENA_MAGIC_PKT_UNIT); - } else - skge_write16(hw, WOL_CTRL_STAT, WOL_CTL_DEFAULT); - + skge->wol = wol->wolopts; + if (!netif_running(dev)) + skge_wol_init(skge); return 0; } @@ -195,8 +261,8 @@ static u32 skge_supported_modes(const struct skge_hw *hw) else if (hw->chip_id == CHIP_ID_YUKON) supported &= ~SUPPORTED_1000baseT_Half; } else - supported = SUPPORTED_1000baseT_Full | SUPPORTED_FIBRE - | SUPPORTED_Autoneg; + supported = SUPPORTED_1000baseT_Full | SUPPORTED_1000baseT_Half + | SUPPORTED_FIBRE | SUPPORTED_Autoneg; return supported; } @@ -485,31 +551,37 @@ static void skge_get_pauseparam(struct net_device *dev, { struct skge_port *skge = netdev_priv(dev); - ecmd->tx_pause = (skge->flow_control == FLOW_MODE_LOC_SEND) - || (skge->flow_control == FLOW_MODE_SYMMETRIC); - ecmd->rx_pause = (skge->flow_control == FLOW_MODE_REM_SEND) - || (skge->flow_control == FLOW_MODE_SYMMETRIC); + 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 = skge->autoneg; + 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; - skge->autoneg = ecmd->autoneg; - 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_REM_SEND; - else if (!ecmd->rx_pause && ecmd->tx_pause) - skge->flow_control = FLOW_MODE_LOC_SEND; - else - skge->flow_control = FLOW_MODE_NONE; + 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_phy_reset(skge); + return 0; } @@ -604,7 +676,12 @@ static void skge_led(struct skge_port *skge, enum led_mode mode) if (hw->chip_id == CHIP_ID_GENESIS) { switch (mode) { case LED_MODE_OFF: - xm_phy_write(hw, port, PHY_BCOM_P_EXT_CTRL, PHY_B_PEC_LED_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); @@ -624,8 +701,14 @@ static void skge_led(struct skge_port *skge, enum led_mode mode) skge_write32(hw, SK_REG(port, RX_LED_VAL), 100); skge_write8(hw, SK_REG(port, RX_LED_CTRL), LED_START); - xm_phy_write(hw, port, PHY_BCOM_P_EXT_CTRL, PHY_B_PEC_LED_ON); - break; + 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) { @@ -818,8 +901,9 @@ static void skge_rx_clean(struct skge_port *skge) /* Allocate buffers for receive ring * For receive: to_clean is next received frame. */ -static int skge_rx_fill(struct skge_port *skge) +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; @@ -827,7 +911,8 @@ static int skge_rx_fill(struct skge_port *skge) do { struct sk_buff *skb; - skb = alloc_skb(skge->rx_buf_size + NET_IP_ALIGN, GFP_KERNEL); + skb = __netdev_alloc_skb(dev, skge->rx_buf_size + NET_IP_ALIGN, + GFP_KERNEL); if (!skb) return -ENOMEM; @@ -839,6 +924,23 @@ static int skge_rx_fill(struct skge_port *skge) 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), @@ -847,16 +949,13 @@ static void skge_link_up(struct skge_port *skge) netif_carrier_on(skge->netdev); netif_wake_queue(skge->netdev); - if (netif_msg_link(skge)) + if (netif_msg_link(skge)) { printk(KERN_INFO PFX "%s: Link is up at %d Mbps, %s duplex, flow control %s\n", skge->netdev->name, skge->speed, skge->duplex == DUPLEX_FULL ? "full" : "half", - (skge->flow_control == FLOW_MODE_NONE) ? "none" : - (skge->flow_control == FLOW_MODE_LOC_SEND) ? "tx only" : - (skge->flow_control == FLOW_MODE_REM_SEND) ? "rx only" : - (skge->flow_control == FLOW_MODE_SYMMETRIC) ? "tx and rx" : - "unknown"); + skge_pause(skge->flow_status)); + } } static void skge_link_down(struct skge_port *skge) @@ -869,6 +968,29 @@ static void skge_link_down(struct skge_port *skge) printk(KERN_INFO PFX "%s: Link is down.\n", skge->netdev->name); } + +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); + u16 cmd, msk; + + if (hw->phy_type == SK_PHY_XMAC) { + msk = xm_read16(hw, port, XM_IMSK); + msk |= XM_IS_INP_ASS | XM_IS_LIPA_RC | XM_IS_RX_PAGE | XM_IS_AND; + xm_write16(hw, port, XM_IMSK, msk); + } + + cmd = xm_read16(hw, port, XM_MMU_CMD); + cmd &= ~(XM_MMU_ENA_RX | XM_MMU_ENA_TX); + xm_write16(hw, port, XM_MMU_CMD, cmd); + /* dummy read to ensure writing */ + (void) xm_read16(hw, port, XM_MMU_CMD); + + 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; @@ -876,6 +998,9 @@ static int __xm_phy_read(struct skge_hw *hw, int port, u16 reg, u16 *val) 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; @@ -962,7 +1087,8 @@ static void genesis_reset(struct skge_hw *hw, int port) xm_write16(hw, port, XM_RX_CMD, 0); /* reset RX CMD Reg */ /* disable Broadcom PHY IRQ */ - xm_write16(hw, port, PHY_BCOM_INT_MASK, 0xffff); + if (hw->phy_type == SK_PHY_BCOM) + xm_write16(hw, port, PHY_BCOM_INT_MASK, 0xffff); xm_outhash(hw, port, XM_HSM, zero); } @@ -973,7 +1099,15 @@ static const u16 phy_pause_map[] = { [FLOW_MODE_NONE] = 0, [FLOW_MODE_LOC_SEND] = PHY_AN_PAUSE_ASYM, [FLOW_MODE_SYMMETRIC] = PHY_AN_PAUSE_CAP, - [FLOW_MODE_REM_SEND] = PHY_AN_PAUSE_CAP | PHY_AN_PAUSE_ASYM, + [FLOW_MODE_SYM_OR_REM] = PHY_AN_PAUSE_CAP | PHY_AN_PAUSE_ASYM, +}; + +/* special defines for FIBER (88E1011S only) */ +static const u16 fiber_pause_map[] = { + [FLOW_MODE_NONE] = PHY_X_P_NO_PAUSE, + [FLOW_MODE_LOC_SEND] = PHY_X_P_ASYM_MD, + [FLOW_MODE_SYMMETRIC] = PHY_X_P_SYM_MD, + [FLOW_MODE_SYM_OR_REM] = PHY_X_P_BOTH_MD, }; @@ -989,68 +1123,64 @@ static void bcom_check_link(struct skge_hw *hw, int port) status = xm_phy_read(hw, port, PHY_BCOM_STAT); if ((status & PHY_ST_LSYNC) == 0) { - u16 cmd = xm_read16(hw, port, XM_MMU_CMD); - cmd &= ~(XM_MMU_ENA_RX | XM_MMU_ENA_TX); - xm_write16(hw, port, XM_MMU_CMD, cmd); - /* dummy read to ensure writing */ - (void) xm_read16(hw, port, XM_MMU_CMD); - - if (netif_carrier_ok(dev)) - skge_link_down(skge); - } else { - if (skge->autoneg == AUTONEG_ENABLE && - (status & PHY_ST_AN_OVER)) { - u16 lpa = xm_phy_read(hw, port, PHY_BCOM_AUNE_LP); - u16 aux = xm_phy_read(hw, port, PHY_BCOM_AUX_STAT); - - if (lpa & PHY_B_AN_RF) { - printk(KERN_NOTICE PFX "%s: remote fault\n", - dev->name); - return; - } + xm_link_down(hw, port); + return; + } - /* Check Duplex mismatch */ - switch (aux & PHY_B_AS_AN_RES_MSK) { - case PHY_B_RES_1000FD: - skge->duplex = DUPLEX_FULL; - break; - case PHY_B_RES_1000HD: - skge->duplex = DUPLEX_HALF; - break; - default: - printk(KERN_NOTICE PFX "%s: duplex mismatch\n", - dev->name); - return; - } + if (skge->autoneg == AUTONEG_ENABLE) { + u16 lpa, aux; + if (!(status & PHY_ST_AN_OVER)) + return; - /* We are using IEEE 802.3z/D5.0 Table 37-4 */ - switch (aux & PHY_B_AS_PAUSE_MSK) { - case PHY_B_AS_PAUSE_MSK: - skge->flow_control = FLOW_MODE_SYMMETRIC; - break; - case PHY_B_AS_PRR: - skge->flow_control = FLOW_MODE_REM_SEND; - break; - case PHY_B_AS_PRT: - skge->flow_control = FLOW_MODE_LOC_SEND; - break; - default: - skge->flow_control = FLOW_MODE_NONE; - } + lpa = xm_phy_read(hw, port, PHY_XMAC_AUNE_LP); + if (lpa & PHY_B_AN_RF) { + printk(KERN_NOTICE PFX "%s: remote fault\n", + dev->name); + return; + } + + aux = xm_phy_read(hw, port, PHY_BCOM_AUX_STAT); - skge->speed = SPEED_1000; + /* Check Duplex mismatch */ + switch (aux & PHY_B_AS_AN_RES_MSK) { + case PHY_B_RES_1000FD: + skge->duplex = DUPLEX_FULL; + break; + case PHY_B_RES_1000HD: + skge->duplex = DUPLEX_HALF; + break; + default: + printk(KERN_NOTICE PFX "%s: duplex mismatch\n", + dev->name); + return; } - if (!netif_carrier_ok(dev)) - genesis_link_up(skge); + /* We are using IEEE 802.3z/D5.0 Table 37-4 */ + switch (aux & PHY_B_AS_PAUSE_MSK) { + case PHY_B_AS_PAUSE_MSK: + skge->flow_status = FLOW_STAT_SYMMETRIC; + break; + case PHY_B_AS_PRR: + skge->flow_status = FLOW_STAT_REM_SEND; + break; + case PHY_B_AS_PRT: + skge->flow_status = FLOW_STAT_LOC_SEND; + break; + default: + skge->flow_status = FLOW_STAT_NONE; + } + skge->speed = SPEED_1000; } + + if (!netif_carrier_ok(dev)) + genesis_link_up(skge); } /* Broadcom 5400 only supports giagabit! SysKonnect did not put an additional * Phy on for 100 or 10Mbit operation */ -static void bcom_phy_init(struct skge_port *skge, int jumbo) +static void bcom_phy_init(struct skge_port *skge) { struct skge_hw *hw = skge->hw; int port = skge->port; @@ -1141,7 +1271,7 @@ static void bcom_phy_init(struct skge_port *skge, int jumbo) phy_pause_map[skge->flow_control] | PHY_AN_CSMA); /* Handle Jumbo frames */ - if (jumbo) { + if (hw->dev[port]->mtu > ETH_DATA_LEN) { xm_phy_write(hw, port, PHY_BCOM_AUX_CTRL, PHY_B_AC_TX_TST | PHY_B_AC_LONG_PACK); @@ -1154,8 +1284,143 @@ static void bcom_phy_init(struct skge_port *skge, int jumbo) /* Use link status change interrupt */ xm_phy_write(hw, port, PHY_BCOM_INT_MASK, PHY_B_DEF_MSK); +} + +static void xm_phy_init(struct skge_port *skge) +{ + struct skge_hw *hw = skge->hw; + int port = skge->port; + u16 ctrl = 0; + + if (skge->autoneg == AUTONEG_ENABLE) { + if (skge->advertising & ADVERTISED_1000baseT_Half) + ctrl |= PHY_X_AN_HD; + if (skge->advertising & ADVERTISED_1000baseT_Full) + ctrl |= PHY_X_AN_FD; + + ctrl |= fiber_pause_map[skge->flow_control]; + + xm_phy_write(hw, port, PHY_XMAC_AUNE_ADV, ctrl); + + /* Restart Auto-negotiation */ + ctrl = PHY_CT_ANE | PHY_CT_RE_CFG; + } else { + /* Set DuplexMode in Config register */ + if (skge->duplex == DUPLEX_FULL) + ctrl |= PHY_CT_DUP_MD; + /* + * Do NOT enable Auto-negotiation here. This would hold + * the link down because no IDLEs are transmitted + */ + } + + xm_phy_write(hw, port, PHY_XMAC_CTRL, ctrl); + + /* Poll PHY for status changes */ + schedule_delayed_work(&skge->link_thread, LINK_HZ); +} + +static void xm_check_link(struct net_device *dev) +{ + struct skge_port *skge = netdev_priv(dev); + struct skge_hw *hw = skge->hw; + int port = skge->port; + u16 status; + + /* read twice because of latch */ + (void) xm_phy_read(hw, port, PHY_XMAC_STAT); + status = xm_phy_read(hw, port, PHY_XMAC_STAT); + + if ((status & PHY_ST_LSYNC) == 0) { + xm_link_down(hw, port); + return; + } + + if (skge->autoneg == AUTONEG_ENABLE) { + u16 lpa, res; + + if (!(status & PHY_ST_AN_OVER)) + return; + + lpa = xm_phy_read(hw, port, PHY_XMAC_AUNE_LP); + if (lpa & PHY_B_AN_RF) { + printk(KERN_NOTICE PFX "%s: remote fault\n", + dev->name); + return; + } + + res = xm_phy_read(hw, port, PHY_XMAC_RES_ABI); + + /* Check Duplex mismatch */ + switch (res & (PHY_X_RS_HD | PHY_X_RS_FD)) { + case PHY_X_RS_FD: + skge->duplex = DUPLEX_FULL; + break; + case PHY_X_RS_HD: + skge->duplex = DUPLEX_HALF; + break; + default: + printk(KERN_NOTICE PFX "%s: duplex mismatch\n", + dev->name); + return; + } - bcom_check_link(hw, port); + /* We are using IEEE 802.3z/D5.0 Table 37-4 */ + if ((skge->flow_control == FLOW_MODE_SYMMETRIC || + skge->flow_control == FLOW_MODE_SYM_OR_REM) && + (lpa & PHY_X_P_SYM_MD)) + skge->flow_status = FLOW_STAT_SYMMETRIC; + else if (skge->flow_control == FLOW_MODE_SYM_OR_REM && + (lpa & PHY_X_RS_PAUSE) == PHY_X_P_ASYM_MD) + /* Enable PAUSE receive, disable PAUSE transmit */ + skge->flow_status = FLOW_STAT_REM_SEND; + else if (skge->flow_control == FLOW_MODE_LOC_SEND && + (lpa & PHY_X_RS_PAUSE) == PHY_X_P_BOTH_MD) + /* Disable PAUSE receive, enable PAUSE transmit */ + skge->flow_status = FLOW_STAT_LOC_SEND; + else + skge->flow_status = FLOW_STAT_NONE; + + skge->speed = SPEED_1000; + } + + if (!netif_carrier_ok(dev)) + genesis_link_up(skge); +} + +/* Poll to check for link coming up. + * Since internal PHY is wired to a level triggered pin, can't + * get an interrupt when carrier is detected. + */ +static void xm_link_timer(void *arg) +{ + struct net_device *dev = arg; + struct skge_port *skge = netdev_priv(arg); + struct skge_hw *hw = skge->hw; + int port = skge->port; + + if (!netif_running(dev)) + return; + + if (netif_carrier_ok(dev)) { + xm_read16(hw, port, XM_ISRC); + if (!(xm_read16(hw, port, XM_ISRC) & XM_IS_INP_ASS)) + goto nochange; + } else { + if (xm_read32(hw, port, XM_GP_PORT) & XM_GP_INP_ASS) + goto nochange; + xm_read16(hw, port, XM_ISRC); + if (xm_read16(hw, port, XM_ISRC) & XM_IS_INP_ASS) + goto nochange; + } + + mutex_lock(&hw->phy_mutex); + xm_check_link(dev); + mutex_unlock(&hw->phy_mutex); + +nochange: + if (netif_running(dev)) + schedule_delayed_work(&skge->link_thread, LINK_HZ); } static void genesis_mac_init(struct skge_hw *hw, int port) @@ -1186,20 +1451,29 @@ static void genesis_mac_init(struct skge_hw *hw, int port) * namely for the 1000baseTX cards that use the XMAC's * GMII mode. */ - /* Take external Phy out of reset */ - r = skge_read32(hw, B2_GP_IO); - if (port == 0) - r |= GP_DIR_0|GP_IO_0; - else - r |= GP_DIR_2|GP_IO_2; + if (hw->phy_type != SK_PHY_XMAC) { + /* Take external Phy out of reset */ + r = skge_read32(hw, B2_GP_IO); + if (port == 0) + r |= GP_DIR_0|GP_IO_0; + else + r |= GP_DIR_2|GP_IO_2; - skge_write32(hw, B2_GP_IO, r); + skge_write32(hw, B2_GP_IO, r); + /* Enable GMII interface */ + xm_write16(hw, port, XM_HW_CFG, XM_HW_GMII_MD); + } - /* Enable GMII interface */ - xm_write16(hw, port, XM_HW_CFG, XM_HW_GMII_MD); - bcom_phy_init(skge, jumbo); + switch(hw->phy_type) { + case SK_PHY_XMAC: + xm_phy_init(skge); + break; + case SK_PHY_BCOM: + bcom_phy_init(skge); + bcom_check_link(hw, port); + } /* Set Station Address */ xm_outaddr(hw, port, XM_SA, dev->dev_addr); @@ -1332,16 +1606,18 @@ static void genesis_stop(struct skge_port *skge) skge_write16(hw, SK_REG(port, TX_MFF_CTRL1), MFF_SET_MAC_RST); /* For external PHYs there must be special handling */ - reg = skge_read32(hw, B2_GP_IO); - if (port == 0) { - reg |= GP_DIR_0; - reg &= ~GP_IO_0; - } else { - reg |= GP_DIR_2; - reg &= ~GP_IO_2; + if (hw->phy_type != SK_PHY_XMAC) { + reg = skge_read32(hw, B2_GP_IO); + if (port == 0) { + reg |= GP_DIR_0; + reg &= ~GP_IO_0; + } else { + reg |= GP_DIR_2; + reg &= ~GP_IO_2; + } + skge_write32(hw, B2_GP_IO, reg); + skge_read32(hw, B2_GP_IO); } - skge_write32(hw, B2_GP_IO, reg); - skge_read32(hw, B2_GP_IO); xm_write16(hw, port, XM_MMU_CMD, xm_read16(hw, port, XM_MMU_CMD) @@ -1388,6 +1664,10 @@ static void genesis_mac_intr(struct skge_hw *hw, int port) printk(KERN_DEBUG PFX "%s: mac interrupt status 0x%x\n", skge->netdev->name, status); + if (hw->phy_type == SK_PHY_XMAC && + (status & (XM_IS_INP_ASS | XM_IS_LIPA_RC))) + xm_link_down(hw, port); + if (status & XM_IS_TXF_UR) { xm_write32(hw, port, XM_MODE, XM_MD_FTF); ++skge->net_stats.tx_fifo_errors; @@ -1402,8 +1682,8 @@ static void genesis_link_up(struct skge_port *skge) { struct skge_hw *hw = skge->hw; int port = skge->port; - u16 cmd; - u32 mode, msk; + u16 cmd, msk; + u32 mode; cmd = xm_read16(hw, port, XM_MMU_CMD); @@ -1411,8 +1691,8 @@ static void genesis_link_up(struct skge_port *skge) * enabling pause frame reception is required for 1000BT * because the XMAC is not reset if the link is going down */ - if (skge->flow_control == FLOW_MODE_NONE || - skge->flow_control == FLOW_MODE_LOC_SEND) + if (skge->flow_status == FLOW_STAT_NONE || + skge->flow_status == FLOW_STAT_LOC_SEND) /* Disable Pause Frame Reception */ cmd |= XM_MMU_IGN_PF; else @@ -1422,8 +1702,8 @@ static void genesis_link_up(struct skge_port *skge) xm_write16(hw, port, XM_MMU_CMD, cmd); mode = xm_read32(hw, port, XM_MODE); - if (skge->flow_control == FLOW_MODE_SYMMETRIC || - skge->flow_control == FLOW_MODE_LOC_SEND) { + if (skge->flow_status== FLOW_STAT_SYMMETRIC || + skge->flow_status == FLOW_STAT_LOC_SEND) { /* * Configure Pause Frame Generation * Use internal and external Pause Frame Generation. @@ -1451,27 +1731,28 @@ static void genesis_link_up(struct skge_port *skge) } xm_write32(hw, port, XM_MODE, mode); - msk = XM_DEF_MSK; - /* disable GP0 interrupt bit for external Phy */ - msk |= XM_IS_INP_ASS; + if (hw->phy_type != SK_PHY_XMAC) + msk |= XM_IS_INP_ASS; /* disable GP0 interrupt bit */ xm_write16(hw, port, XM_IMSK, msk); xm_read16(hw, port, XM_ISRC); /* get MMU Command Reg. */ cmd = xm_read16(hw, port, XM_MMU_CMD); - if (skge->duplex == DUPLEX_FULL) + if (hw->phy_type != SK_PHY_XMAC && skge->duplex == DUPLEX_FULL) cmd |= XM_MMU_GMII_FD; /* * Workaround BCOM Errata (#10523) for all BCom Phys * Enable Power Management after link up */ - xm_phy_write(hw, port, PHY_BCOM_AUX_CTRL, - xm_phy_read(hw, port, PHY_BCOM_AUX_CTRL) - & ~PHY_B_AC_DIS_PM); - xm_phy_write(hw, port, PHY_BCOM_INT_MASK, PHY_B_DEF_MSK); + if (hw->phy_type == SK_PHY_BCOM) { + xm_phy_write(hw, port, PHY_BCOM_AUX_CTRL, + xm_phy_read(hw, port, PHY_BCOM_AUX_CTRL) + & ~PHY_B_AC_DIS_PM); + xm_phy_write(hw, port, PHY_BCOM_INT_MASK, PHY_B_DEF_MSK); + } /* enable Rx/Tx */ xm_write16(hw, port, XM_MMU_CMD, @@ -1602,11 +1883,17 @@ static void yukon_init(struct skge_hw *hw, int port) adv |= PHY_M_AN_10_FD; if (skge->advertising & ADVERTISED_10baseT_Half) adv |= PHY_M_AN_10_HD; - } else /* special defines for FIBER (88E1011S only) */ - adv |= PHY_M_AN_1000X_AHD | PHY_M_AN_1000X_AFD; - /* Set Flow-control capabilities */ - adv |= phy_pause_map[skge->flow_control]; + /* Set Flow-control capabilities */ + adv |= phy_pause_map[skge->flow_control]; + } else { + if (skge->advertising & ADVERTISED_1000baseT_Full) + adv |= PHY_M_AN_1000X_AFD; + if (skge->advertising & ADVERTISED_1000baseT_Half) + adv |= PHY_M_AN_1000X_AHD; + + adv |= fiber_pause_map[skge->flow_control]; + } /* Restart Auto-negotiation */ ctrl |= PHY_CT_ANE | PHY_CT_RE_CFG; @@ -1740,6 +2027,11 @@ static void yukon_mac_init(struct skge_hw *hw, int port) case FLOW_MODE_LOC_SEND: /* disable Rx flow-control */ reg |= GM_GPCR_FC_RX_DIS | GM_GPCR_AU_FCT_DIS; + break; + case FLOW_MODE_SYMMETRIC: + case FLOW_MODE_SYM_OR_REM: + /* enable Tx & Rx flow-control */ + break; } gma_write16(hw, port, GM_GP_CTRL, reg); @@ -1928,22 +2220,17 @@ static void yukon_link_down(struct skge_port *skge) int port = skge->port; u16 ctrl; - gm_phy_write(hw, port, PHY_MARV_INT_MASK, 0); - ctrl = gma_read16(hw, port, GM_GP_CTRL); ctrl &= ~(GM_GPCR_RX_ENA | GM_GPCR_TX_ENA); gma_write16(hw, port, GM_GP_CTRL, ctrl); - if (skge->flow_control == FLOW_MODE_REM_SEND) { + if (skge->flow_status == FLOW_STAT_REM_SEND) { + ctrl = gm_phy_read(hw, port, PHY_MARV_AUNE_ADV); + ctrl |= PHY_M_AN_ASP; /* restore Asymmetric Pause bit */ - gm_phy_write(hw, port, PHY_MARV_AUNE_ADV, - gm_phy_read(hw, port, - PHY_MARV_AUNE_ADV) - | PHY_M_AN_ASP); - + gm_phy_write(hw, port, PHY_MARV_AUNE_ADV, ctrl); } - yukon_reset(hw, port); skge_link_down(skge); yukon_init(hw, port); @@ -1987,19 +2274,19 @@ static void yukon_phy_intr(struct skge_port *skge) /* We are using IEEE 802.3z/D5.0 Table 37-4 */ switch (phystat & PHY_M_PS_PAUSE_MSK) { case PHY_M_PS_PAUSE_MSK: - skge->flow_control = FLOW_MODE_SYMMETRIC; + skge->flow_status = FLOW_STAT_SYMMETRIC; break; case PHY_M_PS_RX_P_EN: - skge->flow_control = FLOW_MODE_REM_SEND; + skge->flow_status = FLOW_STAT_REM_SEND; break; case PHY_M_PS_TX_P_EN: - skge->flow_control = FLOW_MODE_LOC_SEND; + skge->flow_status = FLOW_STAT_LOC_SEND; break; default: - skge->flow_control = FLOW_MODE_NONE; + skge->flow_status = FLOW_STAT_NONE; } - if (skge->flow_control == FLOW_MODE_NONE || + if (skge->flow_status == FLOW_STAT_NONE || (skge->speed < SPEED_1000 && skge->duplex == DUPLEX_HALF)) skge_write8(hw, SK_REG(port, GMAC_CTRL), GMC_PAUSE_OFF); else @@ -2031,6 +2318,7 @@ static void skge_phy_reset(struct skge_port *skge) { struct skge_hw *hw = skge->hw; int port = skge->port; + struct net_device *dev = hw->dev[port]; netif_stop_queue(skge->netdev); netif_carrier_off(skge->netdev); @@ -2044,6 +2332,8 @@ static void skge_phy_reset(struct skge_port *skge) yukon_init(hw, port); } mutex_unlock(&hw->phy_mutex); + + dev->set_multicast_list(dev); } /* Basic MII support */ @@ -2148,6 +2438,9 @@ static int skge_up(struct net_device *dev) size_t rx_size, tx_size; int err; + if (!is_valid_ether_addr(dev->dev_addr)) + return -EINVAL; + if (netif_msg_ifup(skge)) printk(KERN_INFO PFX "%s: enabling interface\n", dev->name); @@ -2178,7 +2471,7 @@ static int skge_up(struct net_device *dev) if (err) goto free_pci_mem; - err = skge_rx_fill(skge); + err = skge_rx_fill(dev); if (err) goto free_rx_ring; @@ -2237,6 +2530,8 @@ static int skge_down(struct net_device *dev) printk(KERN_INFO PFX "%s: disabling interface\n", dev->name); netif_stop_queue(dev); + if (hw->chip_id == CHIP_ID_GENESIS && hw->phy_type == SK_PHY_XMAC) + cancel_delayed_work(&skge->link_thread); skge_write8(skge->hw, SK_REG(skge->port, LNK_LED_REG), LED_OFF); if (hw->chip_id == CHIP_ID_GENESIS) @@ -2281,7 +2576,7 @@ static int skge_down(struct net_device *dev) skge_led(skge, LED_MODE_OFF); netif_poll_disable(dev); - skge_tx_clean(skge); + skge_tx_clean(dev); skge_rx_clean(skge); kfree(skge->rx_ring.start); @@ -2306,25 +2601,12 @@ static int skge_xmit_frame(struct sk_buff *skb, struct net_device *dev) int i; u32 control, len; u64 map; - unsigned long flags; if (skb_padto(skb, ETH_ZLEN)) return NETDEV_TX_OK; - if (!spin_trylock_irqsave(&skge->tx_lock, flags)) - /* Collision - tell upper layer to requeue */ - return NETDEV_TX_LOCKED; - - if (unlikely(skge_avail(&skge->tx_ring) < skb_shinfo(skb)->nr_frags + 1)) { - if (!netif_queue_stopped(dev)) { - netif_stop_queue(dev); - - printk(KERN_WARNING PFX "%s: ring full when queue awake!\n", - dev->name); - } - spin_unlock_irqrestore(&skge->tx_lock, flags); + if (unlikely(skge_avail(&skge->tx_ring) < skb_shinfo(skb)->nr_frags + 1)) return NETDEV_TX_BUSY; - } e = skge->tx_ring.to_use; td = e->desc; @@ -2399,8 +2681,6 @@ static int skge_xmit_frame(struct sk_buff *skb, struct net_device *dev) netif_stop_queue(dev); } - spin_unlock_irqrestore(&skge->tx_lock, flags); - dev->trans_start = jiffies; return NETDEV_TX_OK; @@ -2430,18 +2710,18 @@ static void skge_tx_free(struct skge_port *skge, struct skge_element *e, printk(KERN_DEBUG PFX "%s: tx done slot %td\n", skge->netdev->name, e - skge->tx_ring.start); - dev_kfree_skb_any(e->skb); + dev_kfree_skb(e->skb); } e->skb = NULL; } /* Free all buffers in transmit ring */ -static void skge_tx_clean(struct skge_port *skge) +static void skge_tx_clean(struct net_device *dev) { + struct skge_port *skge = netdev_priv(dev); struct skge_element *e; - unsigned long flags; - spin_lock_irqsave(&skge->tx_lock, flags); + netif_tx_lock_bh(dev); for (e = skge->tx_ring.to_clean; e != skge->tx_ring.to_use; e = e->next) { struct skge_tx_desc *td = e->desc; skge_tx_free(skge, e, td->control); @@ -2449,8 +2729,8 @@ static void skge_tx_clean(struct skge_port *skge) } skge->tx_ring.to_clean = e; - netif_wake_queue(skge->netdev); - spin_unlock_irqrestore(&skge->tx_lock, flags); + netif_wake_queue(dev); + netif_tx_unlock_bh(dev); } static void skge_tx_timeout(struct net_device *dev) @@ -2461,7 +2741,7 @@ static void skge_tx_timeout(struct net_device *dev) printk(KERN_DEBUG PFX "%s: tx timeout\n", dev->name); skge_write8(skge->hw, Q_ADDR(txqaddr[skge->port], Q_CSR), CSR_STOP); - skge_tx_clean(skge); + skge_tx_clean(dev); } static int skge_change_mtu(struct net_device *dev, int new_mtu) @@ -2487,6 +2767,17 @@ static int skge_change_mtu(struct net_device *dev, int new_mtu) return err; } +static const u8 pause_mc_addr[ETH_ALEN] = { 0x1, 0x80, 0xc2, 0x0, 0x0, 0x1 }; + +static void genesis_add_filter(u8 filter[8], const u8 *addr) +{ + u32 crc, bit; + + crc = ether_crc_le(ETH_ALEN, addr); + bit = ~crc & 0x3f; + filter[bit/8] |= 1 << (bit%8); +} + static void genesis_set_multicast(struct net_device *dev) { struct skge_port *skge = netdev_priv(dev); @@ -2508,24 +2799,33 @@ static void genesis_set_multicast(struct net_device *dev) memset(filter, 0xff, sizeof(filter)); else { memset(filter, 0, sizeof(filter)); - for (i = 0; list && i < count; i++, list = list->next) { - u32 crc, bit; - crc = ether_crc_le(ETH_ALEN, list->dmi_addr); - bit = ~crc & 0x3f; - filter[bit/8] |= 1 << (bit%8); - } + + if (skge->flow_status == FLOW_STAT_REM_SEND + || skge->flow_status == FLOW_STAT_SYMMETRIC) + genesis_add_filter(filter, pause_mc_addr); + + for (i = 0; list && i < count; i++, list = list->next) + genesis_add_filter(filter, list->dmi_addr); } xm_write32(hw, port, XM_MODE, mode); xm_outhash(hw, port, XM_HSM, filter); } +static void yukon_add_filter(u8 filter[8], const u8 *addr) +{ + u32 bit = ether_crc(ETH_ALEN, addr) & 0x3f; + filter[bit/8] |= 1 << (bit%8); +} + static void yukon_set_multicast(struct net_device *dev) { struct skge_port *skge = netdev_priv(dev); struct skge_hw *hw = skge->hw; int port = skge->port; struct dev_mc_list *list = dev->mc_list; + int rx_pause = (skge->flow_status == FLOW_STAT_REM_SEND + || skge->flow_status == FLOW_STAT_SYMMETRIC); u16 reg; u8 filter[8]; @@ -2538,16 +2838,17 @@ static void yukon_set_multicast(struct net_device *dev) reg &= ~(GM_RXCR_UCF_ENA | GM_RXCR_MCF_ENA); else if (dev->flags & IFF_ALLMULTI) /* all multicast */ memset(filter, 0xff, sizeof(filter)); - else if (dev->mc_count == 0) /* no multicast */ + else if (dev->mc_count == 0 && !rx_pause)/* no multicast */ reg &= ~GM_RXCR_MCF_ENA; else { int i; reg |= GM_RXCR_MCF_ENA; - for (i = 0; list && i < dev->mc_count; i++, list = list->next) { - u32 bit = ether_crc(ETH_ALEN, list->dmi_addr) & 0x3f; - filter[bit/8] |= 1 << (bit%8); - } + if (rx_pause) + yukon_add_filter(filter, pause_mc_addr); + + for (i = 0; list && i < dev->mc_count; i++, list = list->next) + yukon_add_filter(filter, list->dmi_addr); } @@ -2584,16 +2885,17 @@ static inline int bad_phy_status(const struct skge_hw *hw, u32 status) /* Get receive buffer from descriptor. * Handles copy of small buffers and reallocation failures */ -static inline struct sk_buff *skge_rx_get(struct skge_port *skge, - struct skge_element *e, - u32 control, u32 status, u16 csum) +static struct sk_buff *skge_rx_get(struct net_device *dev, + struct skge_element *e, + u32 control, u32 status, u16 csum) { + struct skge_port *skge = netdev_priv(dev); struct sk_buff *skb; u16 len = control & BMU_BBC; if (unlikely(netif_msg_rx_status(skge))) printk(KERN_DEBUG PFX "%s: rx slot %td status 0x%x len %d\n", - skge->netdev->name, e - skge->rx_ring.start, + dev->name, e - skge->rx_ring.start, status, len); if (len > skge->rx_buf_size) @@ -2609,7 +2911,7 @@ static inline struct sk_buff *skge_rx_get(struct skge_port *skge, goto error; if (len < RX_COPY_THRESHOLD) { - skb = alloc_skb(len + 2, GFP_ATOMIC); + skb = netdev_alloc_skb(dev, len + 2); if (!skb) goto resubmit; @@ -2624,7 +2926,7 @@ static inline struct sk_buff *skge_rx_get(struct skge_port *skge, skge_rx_reuse(e, skge->rx_buf_size); } else { struct sk_buff *nskb; - nskb = alloc_skb(skge->rx_buf_size + NET_IP_ALIGN, GFP_ATOMIC); + nskb = netdev_alloc_skb(dev, skge->rx_buf_size + NET_IP_ALIGN); if (!nskb) goto resubmit; @@ -2639,20 +2941,19 @@ static inline struct sk_buff *skge_rx_get(struct skge_port *skge, } skb_put(skb, len); - skb->dev = skge->netdev; if (skge->rx_csum) { skb->csum = csum; skb->ip_summed = CHECKSUM_HW; } - skb->protocol = eth_type_trans(skb, skge->netdev); + skb->protocol = eth_type_trans(skb, dev); return skb; error: if (netif_msg_rx_err(skge)) printk(KERN_DEBUG PFX "%s: rx err, slot %td control 0x%x status 0x%x\n", - skge->netdev->name, e - skge->rx_ring.start, + dev->name, e - skge->rx_ring.start, control, status); if (skge->hw->chip_id == CHIP_ID_GENESIS) { @@ -2677,15 +2978,15 @@ resubmit: } /* Free all buffers in Tx ring which are no longer owned by device */ -static void skge_txirq(struct net_device *dev) +static void skge_tx_done(struct net_device *dev) { struct skge_port *skge = netdev_priv(dev); struct skge_ring *ring = &skge->tx_ring; struct skge_element *e; - rmb(); + skge_write8(skge->hw, Q_ADDR(txqaddr[skge->port], Q_CSR), CSR_IRQ_CL_F); - spin_lock(&skge->tx_lock); + netif_tx_lock(dev); for (e = ring->to_clean; e != ring->to_use; e = e->next) { struct skge_tx_desc *td = e->desc; @@ -2696,11 +2997,10 @@ static void skge_txirq(struct net_device *dev) } skge->tx_ring.to_clean = e; - if (netif_queue_stopped(skge->netdev) - && skge_avail(&skge->tx_ring) > TX_LOW_WATER) - netif_wake_queue(skge->netdev); + if (skge_avail(&skge->tx_ring) > TX_LOW_WATER) + netif_wake_queue(dev); - spin_unlock(&skge->tx_lock); + netif_tx_unlock(dev); } static int skge_poll(struct net_device *dev, int *budget) @@ -2709,9 +3009,14 @@ static int skge_poll(struct net_device *dev, int *budget) struct skge_hw *hw = skge->hw; struct skge_ring *ring = &skge->rx_ring; struct skge_element *e; + unsigned long flags; int to_do = min(dev->quota, *budget); int work_done = 0; + skge_tx_done(dev); + + skge_write8(hw, Q_ADDR(rxqaddr[skge->port], Q_CSR), CSR_IRQ_CL_F); + for (e = ring->to_clean; prefetch(e->next), work_done < to_do; e = e->next) { struct skge_rx_desc *rd = e->desc; struct sk_buff *skb; @@ -2722,7 +3027,7 @@ static int skge_poll(struct net_device *dev, int *budget) if (control & BMU_OWN) break; - skb = skge_rx_get(skge, e, control, rd->status, rd->csum2); + skb = skge_rx_get(dev, e, control, rd->status, rd->csum2); if (likely(skb)) { dev->last_rx = jiffies; netif_receive_skb(skb); @@ -2742,13 +3047,12 @@ static int skge_poll(struct net_device *dev, int *budget) if (work_done >= to_do) return 1; /* not done */ - netif_rx_complete(dev); - - spin_lock_irq(&hw->hw_lock); - hw->intr_mask |= rxirqmask[skge->port]; + spin_lock_irqsave(&hw->hw_lock, flags); + __netif_rx_complete(dev); + hw->intr_mask |= irqmask[skge->port]; skge_write32(hw, B0_IMSK, hw->intr_mask); - mmiowb(); - spin_unlock_irq(&hw->hw_lock); + skge_read32(hw, B0_IMSK); + spin_unlock_irqrestore(&hw->hw_lock, flags); return 0; } @@ -2872,7 +3176,7 @@ static void skge_extirq(void *arg) if (netif_running(dev)) { if (hw->chip_id != CHIP_ID_GENESIS) yukon_phy_intr(skge); - else + else if (hw->phy_type == SK_PHY_BCOM) bcom_phy_intr(skge); } } @@ -2881,6 +3185,7 @@ static void skge_extirq(void *arg) spin_lock_irq(&hw->hw_lock); hw->intr_mask |= IS_EXT_REG; skge_write32(hw, B0_IMSK, hw->intr_mask); + skge_read32(hw, B0_IMSK); spin_unlock_irq(&hw->hw_lock); } @@ -2888,27 +3193,23 @@ static irqreturn_t skge_intr(int irq, void *dev_id, struct pt_regs *regs) { struct skge_hw *hw = dev_id; u32 status; + int handled = 0; + spin_lock(&hw->hw_lock); /* Reading this register masks IRQ */ status = skge_read32(hw, B0_SP_ISRC); - if (status == 0) - return IRQ_NONE; + if (status == 0 || status == ~0) + goto out; - spin_lock(&hw->hw_lock); + handled = 1; status &= hw->intr_mask; if (status & IS_EXT_REG) { hw->intr_mask &= ~IS_EXT_REG; schedule_work(&hw->phy_work); } - if (status & IS_XA1_F) { - skge_write8(hw, Q_ADDR(Q_XA1, Q_CSR), CSR_IRQ_CL_F); - skge_txirq(hw->dev[0]); - } - - if (status & IS_R1_F) { - skge_write8(hw, Q_ADDR(Q_R1, Q_CSR), CSR_IRQ_CL_F); - hw->intr_mask &= ~IS_R1_F; + if (status & (IS_XA1_F|IS_R1_F)) { + hw->intr_mask &= ~(IS_XA1_F|IS_R1_F); netif_rx_schedule(hw->dev[0]); } @@ -2927,14 +3228,8 @@ static irqreturn_t skge_intr(int irq, void *dev_id, struct pt_regs *regs) skge_mac_intr(hw, 0); if (hw->dev[1]) { - if (status & IS_XA2_F) { - skge_write8(hw, Q_ADDR(Q_XA2, Q_CSR), CSR_IRQ_CL_F); - skge_txirq(hw->dev[1]); - } - - if (status & IS_R2_F) { - skge_write8(hw, Q_ADDR(Q_R2, Q_CSR), CSR_IRQ_CL_F); - hw->intr_mask &= ~IS_R2_F; + if (status & (IS_XA2_F|IS_R2_F)) { + hw->intr_mask &= ~(IS_XA2_F|IS_R2_F); netif_rx_schedule(hw->dev[1]); } @@ -2955,9 +3250,11 @@ static irqreturn_t skge_intr(int irq, void *dev_id, struct pt_regs *regs) skge_error_irq(hw); skge_write32(hw, B0_IMSK, hw->intr_mask); + skge_read32(hw, B0_IMSK); +out: spin_unlock(&hw->hw_lock); - return IRQ_HANDLED; + return IRQ_RETVAL(handled); } #ifdef CONFIG_NET_POLL_CONTROLLER @@ -3031,7 +3328,7 @@ static int skge_reset(struct skge_hw *hw) { u32 reg; u16 ctst, pci_status; - u8 t8, mac_cfg, pmd_type, phy_type; + u8 t8, mac_cfg, pmd_type; int i; ctst = skge_read16(hw, B0_CTST); @@ -3055,19 +3352,22 @@ static int skge_reset(struct skge_hw *hw) ctst & (CS_CLK_RUN_HOT|CS_CLK_RUN_RST|CS_CLK_RUN_ENA)); hw->chip_id = skge_read8(hw, B2_CHIP_ID); - phy_type = skge_read8(hw, B2_E_1) & 0xf; + hw->phy_type = skge_read8(hw, B2_E_1) & 0xf; pmd_type = skge_read8(hw, B2_PMD_TYP); hw->copper = (pmd_type == 'T' || pmd_type == '1'); switch (hw->chip_id) { case CHIP_ID_GENESIS: - switch (phy_type) { + switch (hw->phy_type) { + case SK_PHY_XMAC: + hw->phy_addr = PHY_ADDR_XMAC; + break; case SK_PHY_BCOM: hw->phy_addr = PHY_ADDR_BCOM; break; default: printk(KERN_ERR PFX "%s: unsupported phy type 0x%x\n", - pci_name(hw->pdev), phy_type); + pci_name(hw->pdev), hw->phy_type); return -EOPNOTSUPP; } break; @@ -3075,7 +3375,7 @@ static int skge_reset(struct skge_hw *hw) case CHIP_ID_YUKON: case CHIP_ID_YUKON_LITE: case CHIP_ID_YUKON_LP: - if (phy_type < SK_PHY_MARV_COPPER && pmd_type != 'S') + if (hw->phy_type < SK_PHY_MARV_COPPER && pmd_type != 'S') hw->copper = 1; hw->phy_addr = PHY_ADDR_MARV; @@ -3106,11 +3406,13 @@ static int skge_reset(struct skge_hw *hw) else hw->ram_size = t8 * 4096; - spin_lock_init(&hw->hw_lock); - hw->intr_mask = IS_HW_ERR | IS_EXT_REG | IS_PORT_1; + hw->intr_mask = IS_HW_ERR | IS_PORT_1; if (hw->ports > 1) hw->intr_mask |= IS_PORT_2; + if (!(hw->chip_id == CHIP_ID_GENESIS && hw->phy_type == SK_PHY_XMAC)) + hw->intr_mask |= IS_EXT_REG; + if (hw->chip_id == CHIP_ID_GENESIS) genesis_init(hw); else { @@ -3222,7 +3524,7 @@ static struct net_device *skge_devinit(struct skge_hw *hw, int port, dev->poll_controller = skge_netpoll; #endif dev->irq = hw->pdev->irq; - dev->features = NETIF_F_LLTX; + if (highmem) dev->features |= NETIF_F_HIGHDMA; @@ -3235,16 +3537,18 @@ static struct net_device *skge_devinit(struct skge_hw *hw, int port, /* Auto speed and flow control */ skge->autoneg = AUTONEG_ENABLE; - skge->flow_control = FLOW_MODE_SYMMETRIC; + skge->flow_control = FLOW_MODE_SYM_OR_REM; skge->duplex = -1; skge->speed = -1; skge->advertising = skge_supported_modes(hw); + skge->wol = pci_wake_enabled(hw->pdev) ? wol_supported(hw) : 0; hw->dev[port] = dev; skge->port = port; - spin_lock_init(&skge->tx_lock); + /* Only used for Genesis XMAC */ + INIT_WORK(&skge->link_thread, xm_link_timer, dev); if (hw->chip_id != CHIP_ID_GENESIS) { dev->features |= NETIF_F_IP_CSUM | NETIF_F_SG; @@ -3332,6 +3636,7 @@ static int __devinit skge_probe(struct pci_dev *pdev, hw->pdev = pdev; mutex_init(&hw->phy_mutex); INIT_WORK(&hw->phy_work, skge_extirq, hw); + spin_lock_init(&hw->hw_lock); hw->regs = ioremap_nocache(pci_resource_start(pdev, 0), 0x4000); if (!hw->regs) { @@ -3340,33 +3645,24 @@ static int __devinit skge_probe(struct pci_dev *pdev, goto err_out_free_hw; } - err = request_irq(pdev->irq, skge_intr, IRQF_SHARED, DRV_NAME, hw); - if (err) { - printk(KERN_ERR PFX "%s: cannot assign irq %d\n", - pci_name(pdev), pdev->irq); - goto err_out_iounmap; - } - pci_set_drvdata(pdev, hw); - err = skge_reset(hw); if (err) - goto err_out_free_irq; + goto err_out_iounmap; printk(KERN_INFO PFX DRV_VERSION " addr 0x%llx irq %d chip %s rev %d\n", (unsigned long long)pci_resource_start(pdev, 0), pdev->irq, skge_board_name(hw), hw->chip_rev); - if ((dev = skge_devinit(hw, 0, using_dac)) == NULL) + dev = skge_devinit(hw, 0, using_dac); + if (!dev) goto err_out_led_off; + /* Some motherboards are broken and has zero in ROM. */ if (!is_valid_ether_addr(dev->dev_addr)) { - printk(KERN_ERR PFX "%s: bad (zero?) ethernet address in rom\n", + printk(KERN_WARNING PFX "%s: bad (zero?) ethernet address in rom\n", pci_name(pdev)); - err = -EIO; - goto err_out_free_netdev; } - err = register_netdev(dev); if (err) { printk(KERN_ERR PFX "%s: cannot register net device\n", @@ -3374,6 +3670,12 @@ static int __devinit skge_probe(struct pci_dev *pdev, goto err_out_free_netdev; } + err = request_irq(pdev->irq, skge_intr, IRQF_SHARED, dev->name, hw); + if (err) { + printk(KERN_ERR PFX "%s: cannot assign irq %d\n", + dev->name, pdev->irq); + goto err_out_unregister; + } skge_show_addr(dev); if (hw->ports > 1 && (dev1 = skge_devinit(hw, 1, using_dac))) { @@ -3386,15 +3688,16 @@ static int __devinit skge_probe(struct pci_dev *pdev, free_netdev(dev1); } } + pci_set_drvdata(pdev, hw); return 0; +err_out_unregister: + unregister_netdev(dev); err_out_free_netdev: free_netdev(dev); err_out_led_off: skge_write16(hw, B0_LED, LED_STAT_OFF); -err_out_free_irq: - free_irq(pdev->irq, hw); err_out_iounmap: iounmap(hw->regs); err_out_free_hw: @@ -3416,6 +3719,8 @@ static void __devexit skge_remove(struct pci_dev *pdev) if (!hw) return; + flush_scheduled_work(); + if ((dev1 = hw->dev[1])) unregister_netdev(dev1); dev0 = hw->dev[0]; @@ -3424,13 +3729,12 @@ static void __devexit skge_remove(struct pci_dev *pdev) spin_lock_irq(&hw->hw_lock); hw->intr_mask = 0; skge_write32(hw, B0_IMSK, 0); + skge_read32(hw, B0_IMSK); spin_unlock_irq(&hw->hw_lock); skge_write16(hw, B0_LED, LED_STAT_OFF); skge_write8(hw, B0_CTST, CS_RST_SET); - flush_scheduled_work(); - free_irq(pdev->irq, hw); pci_release_regions(pdev); pci_disable_device(pdev); @@ -3444,31 +3748,48 @@ static void __devexit skge_remove(struct pci_dev *pdev) } #ifdef CONFIG_PM +static int vaux_avail(struct pci_dev *pdev) +{ + int pm_cap; + + pm_cap = pci_find_capability(pdev, PCI_CAP_ID_PM); + if (pm_cap) { + u16 ctl; + pci_read_config_word(pdev, pm_cap + PCI_PM_PMC, &ctl); + if (ctl & PCI_PM_CAP_AUX_POWER) + return 1; + } + return 0; +} + + static int skge_suspend(struct pci_dev *pdev, pm_message_t state) { struct skge_hw *hw = pci_get_drvdata(pdev); - int i, wol = 0; + int i, err, wol = 0; - for (i = 0; i < 2; i++) { + err = pci_save_state(pdev); + if (err) + return err; + + for (i = 0; i < hw->ports; i++) { struct net_device *dev = hw->dev[i]; + struct skge_port *skge = netdev_priv(dev); - if (dev) { - struct skge_port *skge = netdev_priv(dev); - if (netif_running(dev)) { - netif_carrier_off(dev); - if (skge->wol) - netif_stop_queue(dev); - else - skge_down(dev); - } - netif_device_detach(dev); - wol |= skge->wol; - } + if (netif_running(dev)) + skge_down(dev); + if (skge->wol) + skge_wol_init(skge); + + wol |= skge->wol; } - pci_save_state(pdev); + if (wol && vaux_avail(pdev)) + skge_write8(hw, B0_POWER_CTRL, + PC_VAUX_ENA | PC_VCC_ENA | PC_VAUX_ON | PC_VCC_OFF); + + skge_write32(hw, B0_IMSK, 0); pci_enable_wake(pdev, pci_choose_state(pdev, state), wol); - pci_disable_device(pdev); pci_set_power_state(pdev, pci_choose_state(pdev, state)); return 0; @@ -3477,23 +3798,38 @@ static int skge_suspend(struct pci_dev *pdev, pm_message_t state) static int skge_resume(struct pci_dev *pdev) { struct skge_hw *hw = pci_get_drvdata(pdev); - int i; + int i, err; + + err = pci_set_power_state(pdev, PCI_D0); + if (err) + goto out; + + err = pci_restore_state(pdev); + if (err) + goto out; - pci_set_power_state(pdev, PCI_D0); - pci_restore_state(pdev); pci_enable_wake(pdev, PCI_D0, 0); - skge_reset(hw); + err = skge_reset(hw); + if (err) + goto out; - for (i = 0; i < 2; i++) { + for (i = 0; i < hw->ports; i++) { struct net_device *dev = hw->dev[i]; - if (dev) { - netif_device_attach(dev); - if (netif_running(dev) && skge_up(dev)) + + if (netif_running(dev)) { + err = skge_up(dev); + + if (err) { + printk(KERN_ERR PFX "%s: could not up: %d\n", + dev->name, err); dev_close(dev); + goto out; + } } } - return 0; +out: + return err; } #endif diff --git a/drivers/net/skge.h b/drivers/net/skge.h index 593387b..467a7d7 100644 --- a/drivers/net/skge.h +++ b/drivers/net/skge.h @@ -875,11 +875,13 @@ enum { WOL_PATT_CNT_0 = 0x0f38,/* 32 bit WOL Pattern Counter 3..0 */ WOL_PATT_CNT_4 = 0x0f3c,/* 24 bit WOL Pattern Counter 6..4 */ }; +#define WOL_REGS(port, x) (x + (port)*0x80) enum { WOL_PATT_RAM_1 = 0x1000,/* WOL Pattern RAM Link 1 */ WOL_PATT_RAM_2 = 0x1400,/* WOL Pattern RAM Link 2 */ }; +#define WOL_PATT_RAM_BASE(port) (WOL_PATT_RAM_1 + (port)*0x400) enum { BASE_XMAC_1 = 0x2000,/* XMAC 1 registers */ @@ -934,7 +936,7 @@ enum { PHY_XMAC_AUNE_ADV = 0x04,/* 16 bit r/w Auto-Neg. Advertisement */ PHY_XMAC_AUNE_LP = 0x05,/* 16 bit r/o Link Partner Abi Reg */ PHY_XMAC_AUNE_EXP = 0x06,/* 16 bit r/o Auto-Neg. Expansion Reg */ - PHY_XMAC_NEPG = 0x07,/* 16 bit r/w Next Page Register */ + PHY_XMAC_NEPG = 0x07,/* 16 bit r/w Next Page Register */ PHY_XMAC_NEPG_LP = 0x08,/* 16 bit r/o Next Page Link Partner */ PHY_XMAC_EXT_STAT = 0x0f,/* 16 bit r/o Ext Status Register */ @@ -1097,13 +1099,36 @@ enum { /* Pause Bits (PHY_X_AN_PAUSE and PHY_X_RS_PAUSE) encoding */ enum { - PHY_X_P_NO_PAUSE = 0<<7,/* Bit 8..7: no Pause Mode */ + PHY_X_P_NO_PAUSE= 0<<7,/* Bit 8..7: no Pause Mode */ PHY_X_P_SYM_MD = 1<<7, /* Bit 8..7: symmetric Pause Mode */ PHY_X_P_ASYM_MD = 2<<7,/* Bit 8..7: asymmetric Pause Mode */ PHY_X_P_BOTH_MD = 3<<7,/* Bit 8..7: both Pause Mode */ }; +/***** PHY_XMAC_EXT_STAT 16 bit r/w Extended Status Register *****/ +enum { + PHY_X_EX_FD = 1<<15, /* Bit 15: Device Supports Full Duplex */ + PHY_X_EX_HD = 1<<14, /* Bit 14: Device Supports Half Duplex */ +}; + +/***** PHY_XMAC_RES_ABI 16 bit r/o PHY Resolved Ability *****/ +enum { + PHY_X_RS_PAUSE = 3<<7, /* Bit 8..7: selected Pause Mode */ + PHY_X_RS_HD = 1<<6, /* Bit 6: Half Duplex Mode selected */ + PHY_X_RS_FD = 1<<5, /* Bit 5: Full Duplex Mode selected */ + PHY_X_RS_ABLMIS = 1<<4, /* Bit 4: duplex or pause cap mismatch */ + PHY_X_RS_PAUMIS = 1<<3, /* Bit 3: pause capability mismatch */ +}; + +/* Remote Fault Bits (PHY_X_AN_RFB) encoding */ +enum { + X_RFB_OK = 0<<12,/* Bit 13..12 No errors, Link OK */ + X_RFB_LF = 1<<12,/* Bit 13..12 Link Failure */ + X_RFB_OFF = 2<<12,/* Bit 13..12 Offline */ + X_RFB_AN_ERR = 3<<12,/* Bit 13..12 Auto-Negotiation Error */ +}; + /* Broadcom-Specific */ /***** PHY_BCOM_1000T_CTRL 16 bit r/w 1000Base-T Control Reg *****/ enum { @@ -1824,8 +1849,7 @@ enum { GMR_FS_JABBER, /* Rx GMAC FIFO Flush Mask (default) */ RX_FF_FL_DEF_MSK = GMR_FS_CRC_ERR | GMR_FS_RX_FF_OV |GMR_FS_MII_ERR | - GMR_FS_BAD_FC | GMR_FS_GOOD_FC | GMR_FS_UN_SIZE | - GMR_FS_JABBER, + GMR_FS_BAD_FC | GMR_FS_UN_SIZE | GMR_FS_JABBER, }; /* RX_GMF_CTRL_T 32 bit Rx GMAC FIFO Control/Test */ @@ -2158,8 +2182,8 @@ enum { XM_IS_LNK_AE = 1<<14, /* Bit 14: Link Asynchronous Event */ XM_IS_TX_ABORT = 1<<13, /* Bit 13: Transmit Abort, late Col. etc */ XM_IS_FRC_INT = 1<<12, /* Bit 12: Force INT bit set in GP */ - XM_IS_INP_ASS = 1<<11, /* Bit 11: Input Asserted, GP bit 0 set */ - XM_IS_LIPA_RC = 1<<10, /* Bit 10: Link Partner requests config */ + XM_IS_INP_ASS = 1<<11, /* Bit 11: Input Asserted, GP bit 0 set */ + XM_IS_LIPA_RC = 1<<10, /* Bit 10: Link Partner requests config */ XM_IS_RX_PAGE = 1<<9, /* Bit 9: Page Received */ XM_IS_TX_PAGE = 1<<8, /* Bit 8: Next Page Loaded for Transmit */ XM_IS_AND = 1<<7, /* Bit 7: Auto-Negotiation Done */ @@ -2172,8 +2196,7 @@ enum { XM_IS_RX_COMP = 1<<0, /* Bit 0: Frame Rx Complete */ }; -#define XM_DEF_MSK (~(XM_IS_INP_ASS | XM_IS_LIPA_RC | XM_IS_RX_PAGE | \ - XM_IS_AND | XM_IS_RXC_OV | XM_IS_TXC_OV | \ +#define XM_DEF_MSK (~(XM_IS_INP_ASS | XM_IS_LIPA_RC | \ XM_IS_RXF_OV | XM_IS_TXF_UR)) @@ -2396,6 +2419,7 @@ struct skge_hw { u8 chip_rev; u8 copper; u8 ports; + u8 phy_type; u32 ram_size; u32 ram_offset; @@ -2404,28 +2428,40 @@ struct skge_hw { struct mutex phy_mutex; }; -enum { - FLOW_MODE_NONE = 0, /* No Flow-Control */ - FLOW_MODE_LOC_SEND = 1, /* Local station sends PAUSE */ - FLOW_MODE_REM_SEND = 2, /* Symmetric or just remote */ +enum pause_control { + FLOW_MODE_NONE = 1, /* No Flow-Control */ + FLOW_MODE_LOC_SEND = 2, /* Local station sends PAUSE */ FLOW_MODE_SYMMETRIC = 3, /* Both stations may send PAUSE */ + FLOW_MODE_SYM_OR_REM = 4, /* Both stations may send PAUSE or + * just the remote station may send PAUSE + */ }; +enum pause_status { + FLOW_STAT_INDETERMINATED=0, /* indeterminated */ + FLOW_STAT_NONE, /* No Flow Control */ + FLOW_STAT_REM_SEND, /* Remote Station sends PAUSE */ + FLOW_STAT_LOC_SEND, /* Local station sends PAUSE */ + FLOW_STAT_SYMMETRIC, /* Both station may send PAUSE */ +}; + + struct skge_port { u32 msg_enable; struct skge_hw *hw; struct net_device *netdev; int port; - spinlock_t tx_lock; struct skge_ring tx_ring; struct skge_ring rx_ring; struct net_device_stats net_stats; + struct work_struct link_thread; + enum pause_control flow_control; + enum pause_status flow_status; u8 rx_csum; u8 blink_on; - u8 flow_control; u8 wol; u8 autoneg; /* AUTONEG_ENABLE, AUTONEG_DISABLE */ u8 duplex; /* DUPLEX_HALF, DUPLEX_FULL */ -- 1.5.2.1