commit 8c0bca49b849ea8ed5d6081a0f2080070a090ece Author: Herton Ronaldo Krzesinski Date: Wed Jul 23 18:46:20 2008 -0300 sis190: do polling to check link status Some sis190 devices don't report LinkChange, so do polling for link status. Signed-off-by: Herton Ronaldo Krzesinski diff --git a/drivers/net/sis190.c b/drivers/net/sis190.c index 3fe0176..49d0d7e 100644 --- a/drivers/net/sis190.c +++ b/drivers/net/sis190.c @@ -294,6 +294,11 @@ struct sis190_private { struct mii_if_info mii_if; struct list_head first_phy; u32 features; + enum { + LNK_OFF, + LNK_ON, + LNK_AUTONEG, + } link_status; }; struct sis190_phy { @@ -755,6 +760,7 @@ static irqreturn_t sis190_interrupt(int irq, void *__dev) if (status & LinkChange) { net_intr(tp, KERN_INFO "%s: link change.\n", dev->name); + del_timer(&tp->timer); schedule_work(&tp->phy_task); } @@ -929,13 +935,16 @@ 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); net_link(tp, KERN_WARNING "%s: auto-negotiating...\n", dev->name); - 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; @@ -994,7 +1003,10 @@ static void sis190_phy_task(struct work_struct *work) net_link(tp, KERN_INFO "%s: link on %s mode.\n", dev->name, 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(); @@ -1486,6 +1498,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);