*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
+ * 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
#include "skge.h"
#define DRV_NAME "skge"
-#define DRV_VERSION "1.8"
+#define DRV_VERSION "1.10"
#define PFX DRV_NAME " "
#define DEFAULT_TX_RING_SIZE 128
#define LINK_HZ (HZ/2)
MODULE_DESCRIPTION("SysKonnect Gigabit Ethernet driver");
-MODULE_AUTHOR("Stephen Hemminger <shemminger@osdl.org>");
+MODULE_AUTHOR("Stephen Hemminger <shemminger@linux-foundation.org>");
MODULE_LICENSE("GPL");
MODULE_VERSION(DRV_VERSION);
}
/* 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)
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;
}
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;
}
{
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;
}
struct skge_element *e;
int i;
- ring->start = kcalloc(sizeof(*e), ring->count, GFP_KERNEL);
+ ring->start = kcalloc(ring->count, sizeof(*e), GFP_KERNEL);
if (!ring->start)
return -ENOMEM;
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),
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)
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;
[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,
};
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);
+ xm_link_down(hw, port);
return;
}
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;
+ skge->flow_status = FLOW_STAT_SYMMETRIC;
break;
case PHY_B_AS_PRR:
- skge->flow_control = FLOW_MODE_REM_SEND;
+ skge->flow_status = FLOW_STAT_REM_SEND;
break;
case PHY_B_AS_PRT:
- 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;
}
skge->speed = SPEED_1000;
}
if (skge->advertising & ADVERTISED_1000baseT_Full)
ctrl |= PHY_X_AN_FD;
- switch(skge->flow_control) {
- case FLOW_MODE_NONE:
- ctrl |= PHY_X_P_NO_PAUSE;
- break;
- case FLOW_MODE_LOC_SEND:
- ctrl |= PHY_X_P_ASYM_MD;
- break;
- case FLOW_MODE_SYMMETRIC:
- ctrl |= PHY_X_P_BOTH_MD;
- break;
- }
+ ctrl |= fiber_pause_map[skge->flow_control];
xm_phy_write(hw, port, PHY_XMAC_AUNE_ADV, ctrl);
status = xm_phy_read(hw, port, PHY_XMAC_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);
+ xm_link_down(hw, port);
return;
}
}
/* We are using IEEE 802.3z/D5.0 Table 37-4 */
- if (lpa & PHY_X_P_SYM_MD)
- skge->flow_control = FLOW_MODE_SYMMETRIC;
- else if ((lpa & PHY_X_RS_PAUSE) == PHY_X_P_ASYM_MD)
- skge->flow_control = FLOW_MODE_REM_SEND;
- else if ((lpa & PHY_X_RS_PAUSE) == PHY_X_P_BOTH_MD)
- skge->flow_control = FLOW_MODE_LOC_SEND;
+ 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_control = FLOW_MODE_NONE;
-
+ skge->flow_status = FLOW_STAT_NONE;
skge->speed = SPEED_1000;
}
* 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)
+static void xm_link_timer(struct work_struct *work)
{
- struct net_device *dev = arg;
- struct skge_port *skge = netdev_priv(arg);
+ struct skge_port *skge =
+ container_of(work, struct skge_port, link_thread.work);
+ struct net_device *dev = skge->netdev;
struct skge_hw *hw = skge->hw;
int port = skge->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;
{
struct skge_hw *hw = skge->hw;
int port = skge->port;
- u16 cmd;
+ u16 cmd, msk;
u32 mode;
cmd = xm_read16(hw, port, XM_MMU_CMD);
* 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
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.
}
xm_write32(hw, port, XM_MODE, mode);
- xm_write16(hw, port, XM_IMSK, XM_DEF_MSK);
+ msk = XM_DEF_MSK;
+ 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. */
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;
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);
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);
/* 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
{
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);
yukon_init(hw, port);
}
mutex_unlock(&hw->phy_mutex);
+
+ dev->set_multicast_list(dev);
}
/* Basic MII support */
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);
BUG_ON(skge->dma & 7);
if ((u64)skge->dma >> 32 != ((u64) skge->dma + skge->mem_size) >> 32) {
- printk(KERN_ERR PFX "pci_alloc_consistent region crosses 4G boundary\n");
+ dev_err(&hw->pdev->dev, "pci_alloc_consistent region crosses 4G boundary\n");
err = -EINVAL;
goto free_pci_mem;
}
td->csum_offs = 0;
td->csum_start = offset;
- td->csum_write = offset + skb->csum;
+ td->csum_write = offset + skb->csum_offset;
} else
control = BMU_CHECK;
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;
if (work_done >= to_do)
return 1; /* not done */
- spin_lock_irq(&hw->hw_lock);
+ 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);
skge_read32(hw, B0_IMSK);
- spin_unlock_irq(&hw->hw_lock);
+ spin_unlock_irqrestore(&hw->hw_lock, flags);
return 0;
}
/* Handle device specific framing and timeout interrupts */
static void skge_error_irq(struct skge_hw *hw)
{
+ struct pci_dev *pdev = hw->pdev;
u32 hwstatus = skge_read32(hw, B0_HWE_ISRC);
if (hw->chip_id == CHIP_ID_GENESIS) {
}
if (hwstatus & IS_RAM_RD_PAR) {
- printk(KERN_ERR PFX "Ram read data parity error\n");
+ dev_err(&pdev->dev, "Ram read data parity error\n");
skge_write16(hw, B3_RI_CTRL, RI_CLR_RD_PERR);
}
if (hwstatus & IS_RAM_WR_PAR) {
- printk(KERN_ERR PFX "Ram write data parity error\n");
+ dev_err(&pdev->dev, "Ram write data parity error\n");
skge_write16(hw, B3_RI_CTRL, RI_CLR_WR_PERR);
}
skge_mac_parity(hw, 1);
if (hwstatus & IS_R1_PAR_ERR) {
- printk(KERN_ERR PFX "%s: receive queue parity error\n",
- hw->dev[0]->name);
+ dev_err(&pdev->dev, "%s: receive queue parity error\n",
+ hw->dev[0]->name);
skge_write32(hw, B0_R1_CSR, CSR_IRQ_CL_P);
}
if (hwstatus & IS_R2_PAR_ERR) {
- printk(KERN_ERR PFX "%s: receive queue parity error\n",
- hw->dev[1]->name);
+ dev_err(&pdev->dev, "%s: receive queue parity error\n",
+ hw->dev[1]->name);
skge_write32(hw, B0_R2_CSR, CSR_IRQ_CL_P);
}
if (hwstatus & (IS_IRQ_MST_ERR|IS_IRQ_STAT)) {
u16 pci_status, pci_cmd;
- pci_read_config_word(hw->pdev, PCI_COMMAND, &pci_cmd);
- pci_read_config_word(hw->pdev, PCI_STATUS, &pci_status);
+ pci_read_config_word(pdev, PCI_COMMAND, &pci_cmd);
+ pci_read_config_word(pdev, PCI_STATUS, &pci_status);
- printk(KERN_ERR PFX "%s: PCI error cmd=%#x status=%#x\n",
- pci_name(hw->pdev), pci_cmd, pci_status);
+ dev_err(&pdev->dev, "PCI error cmd=%#x status=%#x\n",
+ pci_cmd, pci_status);
/* Write the error bits back to clear them. */
pci_status &= PCI_STATUS_ERROR_BITS;
skge_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_ON);
- pci_write_config_word(hw->pdev, PCI_COMMAND,
+ pci_write_config_word(pdev, PCI_COMMAND,
pci_cmd | PCI_COMMAND_SERR | PCI_COMMAND_PARITY);
- pci_write_config_word(hw->pdev, PCI_STATUS, pci_status);
+ pci_write_config_word(pdev, PCI_STATUS, pci_status);
skge_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_OFF);
/* if error still set then just ignore it */
hwstatus = skge_read32(hw, B0_HWE_ISRC);
if (hwstatus & IS_IRQ_STAT) {
- printk(KERN_INFO PFX "unable to clear error (so ignoring them)\n");
+ dev_warn(&hw->pdev->dev, "unable to clear error (so ignoring them)\n");
hw->intr_mask &= ~IS_HW_ERR;
}
}
* because accessing phy registers requires spin wait which might
* cause excess interrupt latency.
*/
-static void skge_extirq(void *arg)
+static void skge_extirq(struct work_struct *work)
{
- struct skge_hw *hw = arg;
+ struct skge_hw *hw = container_of(work, struct skge_hw, phy_work);
int port;
mutex_lock(&hw->phy_mutex);
hw->phy_addr = PHY_ADDR_BCOM;
break;
default:
- printk(KERN_ERR PFX "%s: unsupported phy type 0x%x\n",
- pci_name(hw->pdev), hw->phy_type);
+ dev_err(&hw->pdev->dev, "unsupported phy type 0x%x\n",
+ hw->phy_type);
return -EOPNOTSUPP;
}
break;
break;
default:
- printk(KERN_ERR PFX "%s: unsupported chip type 0x%x\n",
- pci_name(hw->pdev), hw->chip_id);
+ dev_err(&hw->pdev->dev, "unsupported chip type 0x%x\n",
+ hw->chip_id);
return -EOPNOTSUPP;
}
/* avoid boards with stuck Hardware error bits */
if ((skge_read32(hw, B0_ISRC) & IS_HW_ERR) &&
(skge_read32(hw, B0_HWE_ISRC) & IS_IRQ_SENSOR)) {
- printk(KERN_WARNING PFX "stuck hardware sensor bit\n");
+ dev_warn(&hw->pdev->dev, "stuck hardware sensor bit\n");
hw->intr_mask &= ~IS_HW_ERR;
}
struct net_device *dev = alloc_etherdev(sizeof(*skge));
if (!dev) {
- printk(KERN_ERR "skge etherdev alloc failed");
+ dev_err(&hw->pdev->dev, "etherdev alloc failed\n");
return NULL;
}
/* 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;
/* Only used for Genesis XMAC */
- INIT_WORK(&skge->link_thread, xm_link_timer, dev);
+ INIT_DELAYED_WORK(&skge->link_thread, xm_link_timer);
if (hw->chip_id != CHIP_ID_GENESIS) {
dev->features |= NETIF_F_IP_CSUM | NETIF_F_SG;
err = pci_enable_device(pdev);
if (err) {
- printk(KERN_ERR PFX "%s cannot enable PCI device\n",
- pci_name(pdev));
+ dev_err(&pdev->dev, "cannot enable PCI device\n");
goto err_out;
}
err = pci_request_regions(pdev, DRV_NAME);
if (err) {
- printk(KERN_ERR PFX "%s cannot obtain PCI resources\n",
- pci_name(pdev));
+ dev_err(&pdev->dev, "cannot obtain PCI resources\n");
goto err_out_disable_pdev;
}
}
if (err) {
- printk(KERN_ERR PFX "%s no usable DMA configuration\n",
- pci_name(pdev));
+ dev_err(&pdev->dev, "no usable DMA configuration\n");
goto err_out_free_regions;
}
err = -ENOMEM;
hw = kzalloc(sizeof(*hw), GFP_KERNEL);
if (!hw) {
- printk(KERN_ERR PFX "%s: cannot allocate hardware struct\n",
- pci_name(pdev));
+ dev_err(&pdev->dev, "cannot allocate hardware struct\n");
goto err_out_free_regions;
}
hw->pdev = pdev;
mutex_init(&hw->phy_mutex);
- INIT_WORK(&hw->phy_work, skge_extirq, hw);
+ INIT_WORK(&hw->phy_work, skge_extirq);
spin_lock_init(&hw->hw_lock);
hw->regs = ioremap_nocache(pci_resource_start(pdev, 0), 0x4000);
if (!hw->regs) {
- printk(KERN_ERR PFX "%s: cannot map device registers\n",
- pci_name(pdev));
+ dev_err(&pdev->dev, "cannot map device registers\n");
goto err_out_free_hw;
}
if (!dev)
goto err_out_led_off;
- if (!is_valid_ether_addr(dev->dev_addr)) {
- printk(KERN_ERR PFX "%s: bad (zero?) ethernet address in rom\n",
- pci_name(pdev));
- err = -EIO;
- goto err_out_free_netdev;
- }
+ /* Some motherboards are broken and has zero in ROM. */
+ if (!is_valid_ether_addr(dev->dev_addr))
+ dev_warn(&pdev->dev, "bad (zero?) ethernet address in rom\n");
err = register_netdev(dev);
if (err) {
- printk(KERN_ERR PFX "%s: cannot register net device\n",
- pci_name(pdev));
+ dev_err(&pdev->dev, "cannot register net device\n");
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_err(&pdev->dev, "%s: cannot assign irq %d\n",
dev->name, pdev->irq);
goto err_out_unregister;
}
skge_show_addr(dev1);
else {
/* Failure to register second port need not be fatal */
- printk(KERN_WARNING PFX "register of second port failed\n");
+ dev_warn(&pdev->dev, "register of second port failed\n");
hw->dev[1] = NULL;
free_netdev(dev1);
}
}
#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;
+
+ err = pci_save_state(pdev);
+ if (err)
+ return err;
- pci_save_state(pdev);
for (i = 0; i < hw->ports; i++) {
struct net_device *dev = hw->dev[i];
+ struct skge_port *skge = netdev_priv(dev);
- if (netif_running(dev)) {
- struct skge_port *skge = netdev_priv(dev);
+ if (netif_running(dev))
+ skge_down(dev);
+ if (skge->wol)
+ skge_wol_init(skge);
- netif_carrier_off(dev);
- if (skge->wol)
- netif_stop_queue(dev);
- else
- skge_down(dev);
- wol |= skge->wol;
- }
- netif_device_detach(dev);
+ wol |= skge->wol;
}
+ 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_set_power_state(pdev, pci_choose_state(pdev, state));
struct skge_hw *hw = pci_get_drvdata(pdev);
int i, err;
- pci_set_power_state(pdev, PCI_D0);
- pci_restore_state(pdev);
+ err = pci_set_power_state(pdev, PCI_D0);
+ if (err)
+ goto out;
+
+ err = pci_restore_state(pdev);
+ if (err)
+ goto out;
+
pci_enable_wake(pdev, PCI_D0, 0);
err = skge_reset(hw);
for (i = 0; i < hw->ports; i++) {
struct net_device *dev = hw->dev[i];
- netif_device_attach(dev);
if (netif_running(dev)) {
err = skge_up(dev);