forked from torvalds/linux
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
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 <[email protected]> Signed-off-by: Jeff Garzik <[email protected]>
- Loading branch information
Stephen Hemminger
authored and
Jeff Garzik
committed
Oct 17, 2007
1 parent
60b24b5
commit 501fb72
Showing
2 changed files
with
50 additions
and
44 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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 <[email protected]>"); | ||
|
@@ -995,19 +995,15 @@ 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; | ||
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); | ||
|
@@ -1103,7 +1099,7 @@ static void genesis_reset(struct skge_hw *hw, int port) | |
|
||
/* 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 */ | ||
|
@@ -1141,7 +1137,7 @@ static void bcom_check_link(struct skge_hw *hw, int port) | |
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) { | ||
|
@@ -1342,33 +1338,33 @@ static void xm_phy_init(struct skge_port *skge) | |
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; | ||
int port = skge->port; | ||
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); | ||
|
@@ -1384,7 +1380,7 @@ static void xm_check_link(struct net_device *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 */ | ||
|
@@ -1408,41 +1404,50 @@ static void xm_check_link(struct net_device *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) | ||
{ | ||
struct skge_port *skge = (struct skge_port *) arg; | ||
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) | ||
|
@@ -1686,14 +1691,16 @@ static void genesis_mac_intr(struct skge_hw *hw, int 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 (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; | ||
|
@@ -1753,11 +1760,12 @@ static void genesis_link_up(struct skge_port *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. */ | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters