diff options
Diffstat (limited to 'drivers/net/sis190.c')
-rw-r--r-- | drivers/net/sis190.c | 23 |
1 files changed, 18 insertions, 5 deletions
diff --git a/drivers/net/sis190.c b/drivers/net/sis190.c index 80af4a44580..760d9e83a46 100644 --- a/drivers/net/sis190.c +++ b/drivers/net/sis190.c @@ -285,6 +285,11 @@ struct sis190_private { struct list_head first_phy; u32 features; u32 negotiated_lpa; + enum { + LNK_OFF, + LNK_ON, + LNK_AUTONEG, + } link_status; }; struct sis190_phy { @@ -750,6 +755,7 @@ static irqreturn_t sis190_interrupt(int irq, void *__dev) if (status & LinkChange) { netif_info(tp, intr, dev, "link change\n"); + del_timer(&tp->timer); schedule_work(&tp->phy_task); } @@ -922,12 +928,15 @@ static void sis190_phy_task(struct work_struct *work) if (val & BMCR_RESET) { // FIXME: needlessly high ? -- FR 02/07/2005 mod_timer(&tp->timer, jiffies + HZ/10); - } else if (!(mdio_read_latched(ioaddr, phy_id, MII_BMSR) & - BMSR_ANEGCOMPLETE)) { + goto out_unlock; + } + + val = mdio_read_latched(ioaddr, phy_id, MII_BMSR); + if (!(val & BMSR_ANEGCOMPLETE) && tp->link_status != LNK_AUTONEG) { netif_carrier_off(dev); netif_warn(tp, link, dev, "auto-negotiating...\n"); - mod_timer(&tp->timer, jiffies + SIS190_PHY_TIMEOUT); - } else { + tp->link_status = LNK_AUTONEG; + } else if ((val & BMSR_LSTATUS) && tp->link_status != LNK_ON) { /* Rejoice ! */ struct { int val; @@ -1000,7 +1009,10 @@ static void sis190_phy_task(struct work_struct *work) netif_info(tp, link, dev, "link on %s mode\n", p->msg); netif_carrier_on(dev); - } + tp->link_status = LNK_ON; + } else if (!(val & BMSR_LSTATUS) && tp->link_status != LNK_AUTONEG) + tp->link_status = LNK_OFF; + mod_timer(&tp->timer, jiffies + SIS190_PHY_TIMEOUT); out_unlock: rtnl_unlock(); @@ -1513,6 +1525,7 @@ static struct net_device * __devinit sis190_init_board(struct pci_dev *pdev) tp->pci_dev = pdev; tp->mmio_addr = ioaddr; + tp->link_status = LNK_OFF; sis190_irq_mask_and_ack(ioaddr); |