[RFT] skge: fiber carrier handling

From: Stephen Hemminger
Date: Thu Jul 12 2007 - 17:56:51 EST


Does this fix your problems? I don't have dual port boards but have an old SK-9843 fiber board.
====

The XM PHY can give IRQ on lost carrier, which is better than polling.
This version also solves an number of bonding/carrier related bugs.

Signed-off-by: Stephen Hemminger <shemminger@xxxxxxxxxxxxxxxxxxxx>

--- a/drivers/net/skge.c 2007-07-12 14:19:55.000000000 -0700
+++ b/drivers/net/skge.c 2007-07-12 14:53:39.000000000 -0700
@@ -1091,13 +1091,7 @@ 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;
-
- 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);
- }
+ u16 cmd;

cmd = xm_read16(hw, port, XM_MMU_CMD);
cmd &= ~(XM_MMU_ENA_RX | XM_MMU_ENA_TX);
@@ -1107,6 +1101,10 @@ static void xm_link_down(struct skge_hw

if (netif_carrier_ok(dev))
skge_link_down(skge);
+
+ /* If needed start polling for link to come up */
+ if (netif_running(dev) && hw->phy_type == SK_PHY_XMAC)
+ mod_timer(&skge->link_timer, jiffies + LINK_HZ);
}

static int __xm_phy_read(struct skge_hw *hw, int port, u16 reg, u16 *val)
@@ -1434,30 +1432,25 @@ static void xm_phy_init(struct skge_port

xm_phy_write(hw, port, PHY_XMAC_CTRL, ctrl);

- /* Poll PHY for status changes */
- mod_timer(&skge->link_timer, jiffies + LINK_HZ);
+ /* Poll for link coming up */
+ mod_timer(&skge->link_timer, jiffies);
}

-static void xm_check_link(struct net_device *dev)
+/* Check status of link and change state */
+static void xm_link_up(struct skge_port *skge)
{
- struct skge_port *skge = netdev_priv(dev);
+ struct net_device *dev = skge->netdev;
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);
+ u16 isrc = xm_read16(hw, port, XM_ISRC);

- if ((status & PHY_ST_LSYNC) == 0) {
- xm_link_down(hw, port);
- return;
- }
+ if (netif_msg_intr(skge))
+ printk(KERN_DEBUG PFX "%s: fiber status %#x\n", dev->name, isrc);

if (skge->autoneg == AUTONEG_ENABLE) {
u16 lpa, res;

- if (!(status & PHY_ST_AN_OVER))
+ if (!(isrc & XM_IS_AND))
return;

lpa = xm_phy_read(hw, port, PHY_XMAC_AUNE_LP);
@@ -1506,10 +1499,7 @@ static void xm_check_link(struct net_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.
- */
+/* Poll to check for link coming up. */
static void xm_link_timer(unsigned long arg)
{
struct skge_port *skge = (struct skge_port *) arg;
@@ -1520,23 +1510,18 @@ static void xm_link_timer(unsigned long
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;
- }
+ if (xm_read32(hw, port, XM_GP_PORT) & XM_GP_INP_ASS)
+ goto resync;

spin_lock(&hw->phy_lock);
- xm_check_link(dev);
+ xm_link_up(skge);
spin_unlock(&hw->phy_lock);

-nochange:
+ /* Link up, timer no longer needed */
+ if (netif_carrier_ok(dev))
+ return;
+
+resync:
if (netif_running(dev))
mod_timer(&skge->link_timer, jiffies + LINK_HZ);
}
@@ -1593,6 +1578,9 @@ static void genesis_mac_init(struct skge
bcom_check_link(hw, port);
}

+ /* Clear any irq */
+ xm_read16(hw, port, XM_ISRC);
+
/* Set Station Address */
xm_outaddr(hw, port, XM_SA, dev->dev_addr);

@@ -1782,8 +1770,7 @@ 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)))
+ if (hw->phy_type == SK_PHY_XMAC && (status & XM_IS_INP_ASS))
xm_link_down(hw, port);

if (status & XM_IS_TXF_UR) {
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/