struct list_head first_phy;
        u32 features;
        u32 negotiated_lpa;
+       enum {
+               LNK_OFF,
+               LNK_ON,
+               LNK_AUTONEG,
+       } link_status;
 };
 
 struct sis190_phy {
 
        if (status & LinkChange) {
                netif_info(tp, intr, dev, "link change\n");
+               del_timer(&tp->timer);
                schedule_work(&tp->phy_task);
        }
 
        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;
 
                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();
 
        tp->pci_dev = pdev;
        tp->mmio_addr = ioaddr;
+       tp->link_status = LNK_OFF;
 
        sis190_irq_mask_and_ack(ioaddr);