-stable review patch. If anyone has any objections, please let us know. ------------------ From: Stephen Hemminger patch 501fb72d052d2a302b423bef7dec98d9d98c8a36 in mainline. Change how PHY is managed on SysKonnect fibre based boards. Poll for PHY coming up 1 per second, but use interrupt to detect loss. Signed-off-by: Stephen Hemminger Signed-off-by: Jeff Garzik Signed-off-by: Greg Kroah-Hartman --- drivers/net/skge.c | 90 ++++++++++++++++++++++++++++------------------------- drivers/net/skge.h | 6 +-- 2 files changed, 51 insertions(+), 45 deletions(-) --- a/drivers/net/skge.c +++ b/drivers/net/skge.c @@ -57,7 +57,7 @@ #define TX_WATCHDOG (5 * HZ) #define NAPI_WEIGHT 64 #define BLINK_MS 250 -#define LINK_HZ (HZ/2) +#define LINK_HZ HZ MODULE_DESCRIPTION("SysKonnect Gigabit Ethernet driver"); MODULE_AUTHOR("Stephen Hemminger "); @@ -992,19 +992,15 @@ static void xm_link_down(struct skge_hw { struct net_device *dev = hw->dev[port]; struct skge_port *skge = netdev_priv(dev); - u16 cmd, msk; + u16 cmd = xm_read16(hw, port, XM_MMU_CMD); - 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); - } + xm_write16(hw, port, XM_IMSK, XM_IMSK_DISABLE); - 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); + xm_read16(hw, port, XM_MMU_CMD); if (netif_carrier_ok(dev)) skge_link_down(skge); @@ -1100,7 +1096,7 @@ static void genesis_reset(struct skge_hw /* reset the statistics module */ xm_write32(hw, port, XM_GP_PORT, XM_GP_RES_STAT); - xm_write16(hw, port, XM_IMSK, 0xffff); /* disable XMAC IRQs */ + xm_write16(hw, port, XM_IMSK, XM_IMSK_DISABLE); xm_write32(hw, port, XM_MODE, 0); /* clear Mode Reg */ xm_write16(hw, port, XM_TX_CMD, 0); /* reset TX CMD Reg */ xm_write16(hw, port, XM_RX_CMD, 0); /* reset RX CMD Reg */ @@ -1138,7 +1134,7 @@ static void bcom_check_link(struct skge_ u16 status; /* read twice because of latch */ - (void) xm_phy_read(hw, port, PHY_BCOM_STAT); + xm_phy_read(hw, port, PHY_BCOM_STAT); status = xm_phy_read(hw, port, PHY_BCOM_STAT); if ((status & PHY_ST_LSYNC) == 0) { @@ -1339,7 +1335,7 @@ static void xm_phy_init(struct skge_port mod_timer(&skge->link_timer, jiffies + LINK_HZ); } -static void xm_check_link(struct net_device *dev) +static int xm_check_link(struct net_device *dev) { struct skge_port *skge = netdev_priv(dev); struct skge_hw *hw = skge->hw; @@ -1347,25 +1343,25 @@ static void xm_check_link(struct net_dev u16 status; /* read twice because of latch */ - (void) xm_phy_read(hw, port, PHY_XMAC_STAT); + 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; + return 0; } if (skge->autoneg == AUTONEG_ENABLE) { u16 lpa, res; if (!(status & PHY_ST_AN_OVER)) - return; + return 0; 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; + return 0; } res = xm_phy_read(hw, port, PHY_XMAC_RES_ABI); @@ -1381,7 +1377,7 @@ static void xm_check_link(struct net_dev default: printk(KERN_NOTICE PFX "%s: duplex mismatch\n", dev->name); - return; + return 0; } /* We are using IEEE 802.3z/D5.0 Table 37-4 */ @@ -1405,11 +1401,14 @@ static void xm_check_link(struct net_dev if (!netif_carrier_ok(dev)) genesis_link_up(skge); + return 1; } /* 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. + * get an interrupt when carrier is detected, need to poll for + * link coming up. */ static void xm_link_timer(unsigned long arg) { @@ -1417,29 +1416,35 @@ static void xm_link_timer(unsigned long struct net_device *dev = skge->netdev; struct skge_hw *hw = skge->hw; int port = skge->port; + int i; + unsigned long flags; if (!netif_running(dev)) return; - if (netif_carrier_ok(dev)) { + spin_lock_irqsave(&hw->phy_lock, flags); + + /* + * Verify that the link by checking GPIO register three times. + * This pin has the signal from the link_sync pin connected to it. + */ + for (i = 0; i < 3; i++) { + if (xm_read16(hw, port, XM_GP_PORT) & XM_GP_INP_ASS) + goto link_down; + } + + /* Re-enable interrupt to detect link down */ + if (xm_check_link(dev)) { + u16 msk = xm_read16(hw, port, XM_IMSK); + msk &= ~XM_IS_INP_ASS; + xm_write16(hw, port, XM_IMSK, msk); 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; +link_down: + mod_timer(&skge->link_timer, + round_jiffies(jiffies + LINK_HZ)); } - - spin_lock(&hw->phy_lock); - xm_check_link(dev); - spin_unlock(&hw->phy_lock); - -nochange: - if (netif_running(dev)) - mod_timer(&skge->link_timer, jiffies + LINK_HZ); + spin_unlock_irqrestore(&hw->phy_lock, flags); } static void genesis_mac_init(struct skge_hw *hw, int port) @@ -1683,14 +1688,16 @@ static void genesis_mac_intr(struct skge 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 (hw->phy_type == SK_PHY_XMAC && (status & XM_IS_INP_ASS)) { + xm_link_down(hw, port); + mod_timer(&skge->link_timer, jiffies + 1); + } if (status & XM_IS_TXF_UR) { xm_write32(hw, port, XM_MODE, XM_MD_FTF); ++skge->net_stats.tx_fifo_errors; } + if (status & XM_IS_RXF_OV) { xm_write32(hw, port, XM_MODE, XM_MD_FRF); ++skge->net_stats.rx_fifo_errors; @@ -1750,11 +1757,12 @@ static void genesis_link_up(struct skge_ } xm_write32(hw, port, XM_MODE, mode); - msk = XM_DEF_MSK; - if (hw->phy_type != SK_PHY_XMAC) - msk |= XM_IS_INP_ASS; /* disable GP0 interrupt bit */ + /* Turn on detection of Tx underrun, Rx overrun */ + msk = xm_read16(hw, port, XM_IMSK); + msk &= ~(XM_IS_RXF_OV | XM_IS_TXF_UR); xm_write16(hw, port, XM_IMSK, msk); + xm_read16(hw, port, XM_ISRC); /* get MMU Command Reg. */ @@ -2185,7 +2193,7 @@ static void yukon_mac_intr(struct skge_h u8 status = skge_read8(hw, SK_REG(port, GMAC_IRQ_SRC)); if (netif_msg_intr(skge)) - printk(KERN_DEBUG PFX "%s: mac interrupt status 0x%x\n", + printk(KERN_DEBUG PFX "%s: yukon mac interrupt status 0x%x\n", dev->name, status); if (status & GM_IS_RX_FF_OR) { --- a/drivers/net/skge.h +++ b/drivers/net/skge.h @@ -2193,11 +2193,9 @@ enum { XM_IS_TXF_UR = 1<<2, /* Bit 2: Transmit FIFO Underrun */ XM_IS_TX_COMP = 1<<1, /* Bit 1: Frame Tx Complete */ 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_RXF_OV | XM_IS_TXF_UR)) + XM_IMSK_DISABLE = 0xffff, +}; /* XM_HW_CFG 16 bit r/w Hardware Config Register */ enum { -- - To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/