|
@@ -57,7 +57,7 @@
|
|
#define TX_WATCHDOG (5 * HZ)
|
|
#define TX_WATCHDOG (5 * HZ)
|
|
#define NAPI_WEIGHT 64
|
|
#define NAPI_WEIGHT 64
|
|
#define BLINK_MS 250
|
|
#define BLINK_MS 250
|
|
-#define LINK_HZ (HZ/2)
|
|
|
|
|
|
+#define LINK_HZ HZ
|
|
|
|
|
|
MODULE_DESCRIPTION("SysKonnect Gigabit Ethernet driver");
|
|
MODULE_DESCRIPTION("SysKonnect Gigabit Ethernet driver");
|
|
MODULE_AUTHOR("Stephen Hemminger <shemminger@linux-foundation.org>");
|
|
MODULE_AUTHOR("Stephen Hemminger <shemminger@linux-foundation.org>");
|
|
@@ -995,19 +995,15 @@ static void xm_link_down(struct skge_hw *hw, int port)
|
|
{
|
|
{
|
|
struct net_device *dev = hw->dev[port];
|
|
struct net_device *dev = hw->dev[port];
|
|
struct skge_port *skge = netdev_priv(dev);
|
|
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);
|
|
cmd &= ~(XM_MMU_ENA_RX | XM_MMU_ENA_TX);
|
|
xm_write16(hw, port, XM_MMU_CMD, cmd);
|
|
xm_write16(hw, port, XM_MMU_CMD, cmd);
|
|
|
|
+
|
|
/* dummy read to ensure writing */
|
|
/* 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))
|
|
if (netif_carrier_ok(dev))
|
|
skge_link_down(skge);
|
|
skge_link_down(skge);
|
|
@@ -1103,7 +1099,7 @@ static void genesis_reset(struct skge_hw *hw, int port)
|
|
|
|
|
|
/* reset the statistics module */
|
|
/* reset the statistics module */
|
|
xm_write32(hw, port, XM_GP_PORT, XM_GP_RES_STAT);
|
|
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_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_TX_CMD, 0); /* reset TX CMD Reg */
|
|
xm_write16(hw, port, XM_RX_CMD, 0); /* reset RX 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;
|
|
u16 status;
|
|
|
|
|
|
/* read twice because of latch */
|
|
/* 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);
|
|
status = xm_phy_read(hw, port, PHY_BCOM_STAT);
|
|
|
|
|
|
if ((status & PHY_ST_LSYNC) == 0) {
|
|
if ((status & PHY_ST_LSYNC) == 0) {
|
|
@@ -1342,7 +1338,7 @@ static void xm_phy_init(struct skge_port *skge)
|
|
mod_timer(&skge->link_timer, jiffies + LINK_HZ);
|
|
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_port *skge = netdev_priv(dev);
|
|
struct skge_hw *hw = skge->hw;
|
|
struct skge_hw *hw = skge->hw;
|
|
@@ -1350,25 +1346,25 @@ static void xm_check_link(struct net_device *dev)
|
|
u16 status;
|
|
u16 status;
|
|
|
|
|
|
/* read twice because of latch */
|
|
/* 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);
|
|
status = xm_phy_read(hw, port, PHY_XMAC_STAT);
|
|
|
|
|
|
if ((status & PHY_ST_LSYNC) == 0) {
|
|
if ((status & PHY_ST_LSYNC) == 0) {
|
|
xm_link_down(hw, port);
|
|
xm_link_down(hw, port);
|
|
- return;
|
|
|
|
|
|
+ return 0;
|
|
}
|
|
}
|
|
|
|
|
|
if (skge->autoneg == AUTONEG_ENABLE) {
|
|
if (skge->autoneg == AUTONEG_ENABLE) {
|
|
u16 lpa, res;
|
|
u16 lpa, res;
|
|
|
|
|
|
if (!(status & PHY_ST_AN_OVER))
|
|
if (!(status & PHY_ST_AN_OVER))
|
|
- return;
|
|
|
|
|
|
+ return 0;
|
|
|
|
|
|
lpa = xm_phy_read(hw, port, PHY_XMAC_AUNE_LP);
|
|
lpa = xm_phy_read(hw, port, PHY_XMAC_AUNE_LP);
|
|
if (lpa & PHY_B_AN_RF) {
|
|
if (lpa & PHY_B_AN_RF) {
|
|
printk(KERN_NOTICE PFX "%s: remote fault\n",
|
|
printk(KERN_NOTICE PFX "%s: remote fault\n",
|
|
dev->name);
|
|
dev->name);
|
|
- return;
|
|
|
|
|
|
+ return 0;
|
|
}
|
|
}
|
|
|
|
|
|
res = xm_phy_read(hw, port, PHY_XMAC_RES_ABI);
|
|
res = xm_phy_read(hw, port, PHY_XMAC_RES_ABI);
|
|
@@ -1384,7 +1380,7 @@ static void xm_check_link(struct net_device *dev)
|
|
default:
|
|
default:
|
|
printk(KERN_NOTICE PFX "%s: duplex mismatch\n",
|
|
printk(KERN_NOTICE PFX "%s: duplex mismatch\n",
|
|
dev->name);
|
|
dev->name);
|
|
- return;
|
|
|
|
|
|
+ return 0;
|
|
}
|
|
}
|
|
|
|
|
|
/* We are using IEEE 802.3z/D5.0 Table 37-4 */
|
|
/* We are using IEEE 802.3z/D5.0 Table 37-4 */
|
|
@@ -1408,11 +1404,14 @@ static void xm_check_link(struct net_device *dev)
|
|
|
|
|
|
if (!netif_carrier_ok(dev))
|
|
if (!netif_carrier_ok(dev))
|
|
genesis_link_up(skge);
|
|
genesis_link_up(skge);
|
|
|
|
+ return 1;
|
|
}
|
|
}
|
|
|
|
|
|
/* Poll to check for link coming up.
|
|
/* Poll to check for link coming up.
|
|
|
|
+ *
|
|
* Since internal PHY is wired to a level triggered pin, can't
|
|
* 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)
|
|
static void xm_link_timer(unsigned long arg)
|
|
{
|
|
{
|
|
@@ -1420,29 +1419,35 @@ static void xm_link_timer(unsigned long arg)
|
|
struct net_device *dev = skge->netdev;
|
|
struct net_device *dev = skge->netdev;
|
|
struct skge_hw *hw = skge->hw;
|
|
struct skge_hw *hw = skge->hw;
|
|
int port = skge->port;
|
|
int port = skge->port;
|
|
|
|
+ int i;
|
|
|
|
+ unsigned long flags;
|
|
|
|
|
|
if (!netif_running(dev))
|
|
if (!netif_running(dev))
|
|
return;
|
|
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);
|
|
xm_read16(hw, port, XM_ISRC);
|
|
- if (!(xm_read16(hw, port, XM_ISRC) & XM_IS_INP_ASS))
|
|
|
|
- goto nochange;
|
|
|
|
} else {
|
|
} 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)
|
|
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",
|
|
printk(KERN_DEBUG PFX "%s: mac interrupt status 0x%x\n",
|
|
skge->netdev->name, status);
|
|
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) {
|
|
if (status & XM_IS_TXF_UR) {
|
|
xm_write32(hw, port, XM_MODE, XM_MD_FTF);
|
|
xm_write32(hw, port, XM_MODE, XM_MD_FTF);
|
|
++skge->net_stats.tx_fifo_errors;
|
|
++skge->net_stats.tx_fifo_errors;
|
|
}
|
|
}
|
|
|
|
+
|
|
if (status & XM_IS_RXF_OV) {
|
|
if (status & XM_IS_RXF_OV) {
|
|
xm_write32(hw, port, XM_MODE, XM_MD_FRF);
|
|
xm_write32(hw, port, XM_MODE, XM_MD_FRF);
|
|
++skge->net_stats.rx_fifo_errors;
|
|
++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);
|
|
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_write16(hw, port, XM_IMSK, msk);
|
|
|
|
+
|
|
xm_read16(hw, port, XM_ISRC);
|
|
xm_read16(hw, port, XM_ISRC);
|
|
|
|
|
|
/* get MMU Command Reg. */
|
|
/* get MMU Command Reg. */
|