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:
parent
4ab408dea0
commit
b88aafd365
@ -285,6 +285,11 @@ struct sis190_private {
|
|||||||
struct list_head first_phy;
|
struct list_head first_phy;
|
||||||
u32 features;
|
u32 features;
|
||||||
u32 negotiated_lpa;
|
u32 negotiated_lpa;
|
||||||
|
enum {
|
||||||
|
LNK_OFF,
|
||||||
|
LNK_ON,
|
||||||
|
LNK_AUTONEG,
|
||||||
|
} link_status;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct sis190_phy {
|
struct sis190_phy {
|
||||||
@ -750,6 +755,7 @@ static irqreturn_t sis190_interrupt(int irq, void *__dev)
|
|||||||
|
|
||||||
if (status & LinkChange) {
|
if (status & LinkChange) {
|
||||||
netif_info(tp, intr, dev, "link change\n");
|
netif_info(tp, intr, dev, "link change\n");
|
||||||
|
del_timer(&tp->timer);
|
||||||
schedule_work(&tp->phy_task);
|
schedule_work(&tp->phy_task);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -922,12 +928,15 @@ static void sis190_phy_task(struct work_struct *work)
|
|||||||
if (val & BMCR_RESET) {
|
if (val & BMCR_RESET) {
|
||||||
// FIXME: needlessly high ? -- FR 02/07/2005
|
// FIXME: needlessly high ? -- FR 02/07/2005
|
||||||
mod_timer(&tp->timer, jiffies + HZ/10);
|
mod_timer(&tp->timer, jiffies + HZ/10);
|
||||||
} else if (!(mdio_read_latched(ioaddr, phy_id, MII_BMSR) &
|
goto out_unlock;
|
||||||
BMSR_ANEGCOMPLETE)) {
|
}
|
||||||
|
|
||||||
|
val = mdio_read_latched(ioaddr, phy_id, MII_BMSR);
|
||||||
|
if (!(val & BMSR_ANEGCOMPLETE) && tp->link_status != LNK_AUTONEG) {
|
||||||
netif_carrier_off(dev);
|
netif_carrier_off(dev);
|
||||||
netif_warn(tp, link, dev, "auto-negotiating...\n");
|
netif_warn(tp, link, dev, "auto-negotiating...\n");
|
||||||
mod_timer(&tp->timer, jiffies + SIS190_PHY_TIMEOUT);
|
tp->link_status = LNK_AUTONEG;
|
||||||
} else {
|
} else if ((val & BMSR_LSTATUS) && tp->link_status != LNK_ON) {
|
||||||
/* Rejoice ! */
|
/* Rejoice ! */
|
||||||
struct {
|
struct {
|
||||||
int val;
|
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_info(tp, link, dev, "link on %s mode\n", p->msg);
|
||||||
netif_carrier_on(dev);
|
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:
|
out_unlock:
|
||||||
rtnl_unlock();
|
rtnl_unlock();
|
||||||
@ -1513,6 +1525,7 @@ static struct net_device * __devinit sis190_init_board(struct pci_dev *pdev)
|
|||||||
|
|
||||||
tp->pci_dev = pdev;
|
tp->pci_dev = pdev;
|
||||||
tp->mmio_addr = ioaddr;
|
tp->mmio_addr = ioaddr;
|
||||||
|
tp->link_status = LNK_OFF;
|
||||||
|
|
||||||
sis190_irq_mask_and_ack(ioaddr);
|
sis190_irq_mask_and_ack(ioaddr);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user