aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStephen Hemminger <shemminger@linux-foundation.org>2007-10-16 15:15:51 -0400
committerJeff Garzik <jeff@garzik.org>2007-10-16 21:10:28 -0400
commit501fb72d052d2a302b423bef7dec98d9d98c8a36 (patch)
treea7e2f58a981c8e35cf8c0297a3d9a90cb6987669
parent60b24b51799cc23313eed85fb874b70a6d02e2b7 (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>
-rw-r--r--drivers/net/skge.c88
-rw-r--r--drivers/net/skge.h6
2 files changed, 50 insertions, 44 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
62MODULE_DESCRIPTION("SysKonnect Gigabit Ethernet driver"); 62MODULE_DESCRIPTION("SysKonnect Gigabit Ethernet driver");
63MODULE_AUTHOR("Stephen Hemminger <shemminger@linux-foundation.org>"); 63MODULE_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
1345static void xm_check_link(struct net_device *dev) 1341static 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 */
1417static void xm_link_timer(unsigned long arg) 1416static 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) 1446link_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
1443nochange:
1444 if (netif_running(dev))
1445 mod_timer(&skge->link_timer, jiffies + LINK_HZ);
1446} 1451}
1447 1452
1448static void genesis_mac_init(struct skge_hw *hw, int port) 1453static 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. */
diff --git a/drivers/net/skge.h b/drivers/net/skge.h
index 1a57bdd1ddf1..b944738a4a0e 100644
--- a/drivers/net/skge.h
+++ b/drivers/net/skge.h
@@ -2191,11 +2191,9 @@ enum {
2191 XM_IS_TXF_UR = 1<<2, /* Bit 2: Transmit FIFO Underrun */ 2191 XM_IS_TXF_UR = 1<<2, /* Bit 2: Transmit FIFO Underrun */
2192 XM_IS_TX_COMP = 1<<1, /* Bit 1: Frame Tx Complete */ 2192 XM_IS_TX_COMP = 1<<1, /* Bit 1: Frame Tx Complete */
2193 XM_IS_RX_COMP = 1<<0, /* Bit 0: Frame Rx Complete */ 2193 XM_IS_RX_COMP = 1<<0, /* Bit 0: Frame Rx Complete */
2194};
2195
2196#define XM_DEF_MSK (~(XM_IS_INP_ASS | XM_IS_LIPA_RC | \
2197 XM_IS_RXF_OV | XM_IS_TXF_UR))
2198 2194
2195 XM_IMSK_DISABLE = 0xffff,
2196};
2199 2197
2200/* XM_HW_CFG 16 bit r/w Hardware Config Register */ 2198/* XM_HW_CFG 16 bit r/w Hardware Config Register */
2201enum { 2199enum {