sis190: fix cable detect via link status poll

Some sis190 devices don't report LinkChange, so do polling for
link status.

Fixes http://bugzilla.kernel.org/show_bug.cgi?id=11926

Signed-off-by: Herton Ronaldo Krzesinski <herton@mandriva.com.br>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Herton Ronaldo Krzesinski 2010-03-02 03:44:41 -08:00 committed by David S. Miller
parent 4ab408dea0
commit b88aafd365

View file

@ -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);