diff options
author | Stephen Hemminger <shemminger@linux-foundation.org> | 2007-10-16 15:15:51 -0400 |
---|---|---|
committer | Jeff Garzik <jeff@garzik.org> | 2007-10-16 21:10:28 -0400 |
commit | 501fb72d052d2a302b423bef7dec98d9d98c8a36 (patch) | |
tree | a7e2f58a981c8e35cf8c0297a3d9a90cb6987669 /drivers/net/skge.c | |
parent | 60b24b51799cc23313eed85fb874b70a6d02e2b7 (diff) |
skge: XM PHY handling fixes
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 <shemminger@linux-foundation.org>
Signed-off-by: Jeff Garzik <jeff@garzik.org>
Diffstat (limited to 'drivers/net/skge.c')
-rw-r--r-- | drivers/net/skge.c | 88 |
1 files changed, 48 insertions, 40 deletions
diff --git a/drivers/net/skge.c b/drivers/net/skge.c index d5c10fd93bf4..180e82f85ac8 100644 --- a/drivers/net/skge.c +++ b/drivers/net/skge.c | |||
@@ -57,7 +57,7 @@ | |||
57 | #define TX_WATCHDOG (5 * HZ) | 57 | #define TX_WATCHDOG (5 * HZ) |
58 | #define NAPI_WEIGHT 64 | 58 | #define NAPI_WEIGHT 64 |
59 | #define BLINK_MS 250 | 59 | #define BLINK_MS 250 |
60 | #define LINK_HZ (HZ/2) | 60 | #define LINK_HZ HZ |
61 | 61 | ||
62 | MODULE_DESCRIPTION("SysKonnect Gigabit Ethernet driver"); | 62 | MODULE_DESCRIPTION("SysKonnect Gigabit Ethernet driver"); |
63 | MODULE_AUTHOR("Stephen Hemminger <shemminger@linux-foundation.org>"); | 63 | MODULE_AUTHOR("Stephen Hemminger <shemminger@linux-foundation.org>"); |
@@ -995,19 +995,15 @@ static void xm_link_down(struct skge_hw *hw, int port) | |||
995 | { | 995 | { |
996 | struct net_device *dev = hw->dev[port]; | 996 | struct net_device *dev = hw->dev[port]; |
997 | struct skge_port *skge = netdev_priv(dev); | 997 | struct skge_port *skge = netdev_priv(dev); |
998 | u16 cmd, msk; | 998 | u16 cmd = xm_read16(hw, port, XM_MMU_CMD); |
999 | 999 | ||
1000 | if (hw->phy_type == SK_PHY_XMAC) { | 1000 | xm_write16(hw, port, XM_IMSK, XM_IMSK_DISABLE); |
1001 | msk = xm_read16(hw, port, XM_IMSK); | ||
1002 | msk |= XM_IS_INP_ASS | XM_IS_LIPA_RC | XM_IS_RX_PAGE | XM_IS_AND; | ||
1003 | xm_write16(hw, port, XM_IMSK, msk); | ||
1004 | } | ||
1005 | 1001 | ||
1006 | cmd = xm_read16(hw, port, XM_MMU_CMD); | ||
1007 | cmd &= ~(XM_MMU_ENA_RX | XM_MMU_ENA_TX); | 1002 | cmd &= ~(XM_MMU_ENA_RX | XM_MMU_ENA_TX); |
1008 | xm_write16(hw, port, XM_MMU_CMD, cmd); | 1003 | xm_write16(hw, port, XM_MMU_CMD, cmd); |
1004 | |||
1009 | /* dummy read to ensure writing */ | 1005 | /* dummy read to ensure writing */ |
1010 | (void) xm_read16(hw, port, XM_MMU_CMD); | 1006 | xm_read16(hw, port, XM_MMU_CMD); |
1011 | 1007 | ||
1012 | if (netif_carrier_ok(dev)) | 1008 | if (netif_carrier_ok(dev)) |
1013 | skge_link_down(skge); | 1009 | skge_link_down(skge); |
@@ -1103,7 +1099,7 @@ static void genesis_reset(struct skge_hw *hw, int port) | |||
1103 | 1099 | ||
1104 | /* reset the statistics module */ | 1100 | /* reset the statistics module */ |
1105 | xm_write32(hw, port, XM_GP_PORT, XM_GP_RES_STAT); | 1101 | xm_write32(hw, port, XM_GP_PORT, XM_GP_RES_STAT); |
1106 | xm_write16(hw, port, XM_IMSK, 0xffff); /* disable XMAC IRQs */ | 1102 | xm_write16(hw, port, XM_IMSK, XM_IMSK_DISABLE); |
1107 | xm_write32(hw, port, XM_MODE, 0); /* clear Mode Reg */ | 1103 | xm_write32(hw, port, XM_MODE, 0); /* clear Mode Reg */ |
1108 | xm_write16(hw, port, XM_TX_CMD, 0); /* reset TX CMD Reg */ | 1104 | xm_write16(hw, port, XM_TX_CMD, 0); /* reset TX CMD Reg */ |
1109 | xm_write16(hw, port, XM_RX_CMD, 0); /* reset RX CMD Reg */ | 1105 | xm_write16(hw, port, XM_RX_CMD, 0); /* reset RX CMD Reg */ |
@@ -1141,7 +1137,7 @@ static void bcom_check_link(struct skge_hw *hw, int port) | |||
1141 | u16 status; | 1137 | u16 status; |
1142 | 1138 | ||
1143 | /* read twice because of latch */ | 1139 | /* read twice because of latch */ |
1144 | (void) xm_phy_read(hw, port, PHY_BCOM_STAT); | 1140 | xm_phy_read(hw, port, PHY_BCOM_STAT); |
1145 | status = xm_phy_read(hw, port, PHY_BCOM_STAT); | 1141 | status = xm_phy_read(hw, port, PHY_BCOM_STAT); |
1146 | 1142 | ||
1147 | if ((status & PHY_ST_LSYNC) == 0) { | 1143 | if ((status & PHY_ST_LSYNC) == 0) { |
@@ -1342,7 +1338,7 @@ static void xm_phy_init(struct skge_port *skge) | |||
1342 | mod_timer(&skge->link_timer, jiffies + LINK_HZ); | 1338 | mod_timer(&skge->link_timer, jiffies + LINK_HZ); |
1343 | } | 1339 | } |
1344 | 1340 | ||
1345 | static void xm_check_link(struct net_device *dev) | 1341 | static int xm_check_link(struct net_device *dev) |
1346 | { | 1342 | { |
1347 | struct skge_port *skge = netdev_priv(dev); | 1343 | struct skge_port *skge = netdev_priv(dev); |
1348 | struct skge_hw *hw = skge->hw; | 1344 | struct skge_hw *hw = skge->hw; |
@@ -1350,25 +1346,25 @@ static void xm_check_link(struct net_device *dev) | |||
1350 | u16 status; | 1346 | u16 status; |
1351 | 1347 | ||
1352 | /* read twice because of latch */ | 1348 | /* read twice because of latch */ |
1353 | (void) xm_phy_read(hw, port, PHY_XMAC_STAT); | 1349 | xm_phy_read(hw, port, PHY_XMAC_STAT); |
1354 | status = xm_phy_read(hw, port, PHY_XMAC_STAT); | 1350 | status = xm_phy_read(hw, port, PHY_XMAC_STAT); |
1355 | 1351 | ||
1356 | if ((status & PHY_ST_LSYNC) == 0) { | 1352 | if ((status & PHY_ST_LSYNC) == 0) { |
1357 | xm_link_down(hw, port); | 1353 | xm_link_down(hw, port); |
1358 | return; | 1354 | return 0; |
1359 | } | 1355 | } |
1360 | 1356 | ||
1361 | if (skge->autoneg == AUTONEG_ENABLE) { | 1357 | if (skge->autoneg == AUTONEG_ENABLE) { |
1362 | u16 lpa, res; | 1358 | u16 lpa, res; |
1363 | 1359 | ||
1364 | if (!(status & PHY_ST_AN_OVER)) | 1360 | if (!(status & PHY_ST_AN_OVER)) |
1365 | return; | 1361 | return 0; |
1366 | 1362 | ||
1367 | lpa = xm_phy_read(hw, port, PHY_XMAC_AUNE_LP); | 1363 | lpa = xm_phy_read(hw, port, PHY_XMAC_AUNE_LP); |
1368 | if (lpa & PHY_B_AN_RF) { | 1364 | if (lpa & PHY_B_AN_RF) { |
1369 | printk(KERN_NOTICE PFX "%s: remote fault\n", | 1365 | printk(KERN_NOTICE PFX "%s: remote fault\n", |
1370 | dev->name); | 1366 | dev->name); |
1371 | return; | 1367 | return 0; |
1372 | } | 1368 | } |
1373 | 1369 | ||
1374 | res = xm_phy_read(hw, port, PHY_XMAC_RES_ABI); | 1370 | res = xm_phy_read(hw, port, PHY_XMAC_RES_ABI); |
@@ -1384,7 +1380,7 @@ static void xm_check_link(struct net_device *dev) | |||
1384 | default: | 1380 | default: |
1385 | printk(KERN_NOTICE PFX "%s: duplex mismatch\n", | 1381 | printk(KERN_NOTICE PFX "%s: duplex mismatch\n", |
1386 | dev->name); | 1382 | dev->name); |
1387 | return; | 1383 | return 0; |
1388 | } | 1384 | } |
1389 | 1385 | ||
1390 | /* We are using IEEE 802.3z/D5.0 Table 37-4 */ | 1386 | /* We are using IEEE 802.3z/D5.0 Table 37-4 */ |
@@ -1408,11 +1404,14 @@ static void xm_check_link(struct net_device *dev) | |||
1408 | 1404 | ||
1409 | if (!netif_carrier_ok(dev)) | 1405 | if (!netif_carrier_ok(dev)) |
1410 | genesis_link_up(skge); | 1406 | genesis_link_up(skge); |
1407 | return 1; | ||
1411 | } | 1408 | } |
1412 | 1409 | ||
1413 | /* Poll to check for link coming up. | 1410 | /* Poll to check for link coming up. |
1411 | * | ||
1414 | * Since internal PHY is wired to a level triggered pin, can't | 1412 | * Since internal PHY is wired to a level triggered pin, can't |
1415 | * get an interrupt when carrier is detected. | 1413 | * get an interrupt when carrier is detected, need to poll for |
1414 | * link coming up. | ||
1416 | */ | 1415 | */ |
1417 | static void xm_link_timer(unsigned long arg) | 1416 | static void xm_link_timer(unsigned long arg) |
1418 | { | 1417 | { |
@@ -1420,29 +1419,35 @@ static void xm_link_timer(unsigned long arg) | |||
1420 | struct net_device *dev = skge->netdev; | 1419 | struct net_device *dev = skge->netdev; |
1421 | struct skge_hw *hw = skge->hw; | 1420 | struct skge_hw *hw = skge->hw; |
1422 | int port = skge->port; | 1421 | int port = skge->port; |
1422 | int i; | ||
1423 | unsigned long flags; | ||
1423 | 1424 | ||
1424 | if (!netif_running(dev)) | 1425 | if (!netif_running(dev)) |
1425 | return; | 1426 | return; |
1426 | 1427 | ||
1427 | if (netif_carrier_ok(dev)) { | 1428 | spin_lock_irqsave(&hw->phy_lock, flags); |
1429 | |||
1430 | /* | ||
1431 | * Verify that the link by checking GPIO register three times. | ||
1432 | * This pin has the signal from the link_sync pin connected to it. | ||
1433 | */ | ||
1434 | for (i = 0; i < 3; i++) { | ||
1435 | if (xm_read16(hw, port, XM_GP_PORT) & XM_GP_INP_ASS) | ||
1436 | goto link_down; | ||
1437 | } | ||
1438 | |||
1439 | /* Re-enable interrupt to detect link down */ | ||
1440 | if (xm_check_link(dev)) { | ||
1441 | u16 msk = xm_read16(hw, port, XM_IMSK); | ||
1442 | msk &= ~XM_IS_INP_ASS; | ||
1443 | xm_write16(hw, port, XM_IMSK, msk); | ||
1428 | xm_read16(hw, port, XM_ISRC); | 1444 | xm_read16(hw, port, XM_ISRC); |
1429 | if (!(xm_read16(hw, port, XM_ISRC) & XM_IS_INP_ASS)) | ||
1430 | goto nochange; | ||
1431 | } else { | 1445 | } else { |
1432 | if (xm_read32(hw, port, XM_GP_PORT) & XM_GP_INP_ASS) | 1446 | link_down: |
1433 | goto nochange; | 1447 | mod_timer(&skge->link_timer, |
1434 | xm_read16(hw, port, XM_ISRC); | 1448 | round_jiffies(jiffies + LINK_HZ)); |
1435 | if (xm_read16(hw, port, XM_ISRC) & XM_IS_INP_ASS) | ||
1436 | goto nochange; | ||
1437 | } | 1449 | } |
1438 | 1450 | spin_unlock_irqrestore(&hw->phy_lock, flags); | |
1439 | spin_lock(&hw->phy_lock); | ||
1440 | xm_check_link(dev); | ||
1441 | spin_unlock(&hw->phy_lock); | ||
1442 | |||
1443 | nochange: | ||
1444 | if (netif_running(dev)) | ||
1445 | mod_timer(&skge->link_timer, jiffies + LINK_HZ); | ||
1446 | } | 1451 | } |
1447 | 1452 | ||
1448 | static void genesis_mac_init(struct skge_hw *hw, int port) | 1453 | static void genesis_mac_init(struct skge_hw *hw, int port) |
@@ -1686,14 +1691,16 @@ static void genesis_mac_intr(struct skge_hw *hw, int port) | |||
1686 | printk(KERN_DEBUG PFX "%s: mac interrupt status 0x%x\n", | 1691 | printk(KERN_DEBUG PFX "%s: mac interrupt status 0x%x\n", |
1687 | skge->netdev->name, status); | 1692 | skge->netdev->name, status); |
1688 | 1693 | ||
1689 | if (hw->phy_type == SK_PHY_XMAC && | 1694 | if (hw->phy_type == SK_PHY_XMAC && (status & XM_IS_INP_ASS)) { |
1690 | (status & (XM_IS_INP_ASS | XM_IS_LIPA_RC))) | 1695 | xm_link_down(hw, port); |
1691 | xm_link_down(hw, port); | 1696 | mod_timer(&skge->link_timer, jiffies + 1); |
1697 | } | ||
1692 | 1698 | ||
1693 | if (status & XM_IS_TXF_UR) { | 1699 | if (status & XM_IS_TXF_UR) { |
1694 | xm_write32(hw, port, XM_MODE, XM_MD_FTF); | 1700 | xm_write32(hw, port, XM_MODE, XM_MD_FTF); |
1695 | ++skge->net_stats.tx_fifo_errors; | 1701 | ++skge->net_stats.tx_fifo_errors; |
1696 | } | 1702 | } |
1703 | |||
1697 | if (status & XM_IS_RXF_OV) { | 1704 | if (status & XM_IS_RXF_OV) { |
1698 | xm_write32(hw, port, XM_MODE, XM_MD_FRF); | 1705 | xm_write32(hw, port, XM_MODE, XM_MD_FRF); |
1699 | ++skge->net_stats.rx_fifo_errors; | 1706 | ++skge->net_stats.rx_fifo_errors; |
@@ -1753,11 +1760,12 @@ static void genesis_link_up(struct skge_port *skge) | |||
1753 | } | 1760 | } |
1754 | 1761 | ||
1755 | xm_write32(hw, port, XM_MODE, mode); | 1762 | xm_write32(hw, port, XM_MODE, mode); |
1756 | msk = XM_DEF_MSK; | ||
1757 | if (hw->phy_type != SK_PHY_XMAC) | ||
1758 | msk |= XM_IS_INP_ASS; /* disable GP0 interrupt bit */ | ||
1759 | 1763 | ||
1764 | /* Turn on detection of Tx underrun, Rx overrun */ | ||
1765 | msk = xm_read16(hw, port, XM_IMSK); | ||
1766 | msk &= ~(XM_IS_RXF_OV | XM_IS_TXF_UR); | ||
1760 | xm_write16(hw, port, XM_IMSK, msk); | 1767 | xm_write16(hw, port, XM_IMSK, msk); |
1768 | |||
1761 | xm_read16(hw, port, XM_ISRC); | 1769 | xm_read16(hw, port, XM_ISRC); |
1762 | 1770 | ||
1763 | /* get MMU Command Reg. */ | 1771 | /* get MMU Command Reg. */ |