diff options
author | Herton Ronaldo Krzesinski <herton@mandriva.com.br> | 2010-03-02 06:44:41 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2010-03-02 06:44:41 -0500 |
commit | b88aafd365bc6a2222e2d03ff320adea3a37f628 (patch) | |
tree | 519c4893ca656ff997bdd3e016d6bb4172faeec2 /drivers/net | |
parent | 4ab408dea0f0dba4dec0555f4f35b7ae703f5e91 (diff) |
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>
Diffstat (limited to 'drivers/net')
-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 80af4a44580e..760d9e83a465 100644 --- a/drivers/net/sis190.c +++ b/drivers/net/sis190.c | |||
@@ -285,6 +285,11 @@ struct sis190_private { | |||
285 | struct list_head first_phy; | 285 | struct list_head first_phy; |
286 | u32 features; | 286 | u32 features; |
287 | u32 negotiated_lpa; | 287 | u32 negotiated_lpa; |
288 | enum { | ||
289 | LNK_OFF, | ||
290 | LNK_ON, | ||
291 | LNK_AUTONEG, | ||
292 | } link_status; | ||
288 | }; | 293 | }; |
289 | 294 | ||
290 | struct sis190_phy { | 295 | struct sis190_phy { |
@@ -750,6 +755,7 @@ static irqreturn_t sis190_interrupt(int irq, void *__dev) | |||
750 | 755 | ||
751 | if (status & LinkChange) { | 756 | if (status & LinkChange) { |
752 | netif_info(tp, intr, dev, "link change\n"); | 757 | netif_info(tp, intr, dev, "link change\n"); |
758 | del_timer(&tp->timer); | ||
753 | schedule_work(&tp->phy_task); | 759 | schedule_work(&tp->phy_task); |
754 | } | 760 | } |
755 | 761 | ||
@@ -922,12 +928,15 @@ static void sis190_phy_task(struct work_struct *work) | |||
922 | if (val & BMCR_RESET) { | 928 | if (val & BMCR_RESET) { |
923 | // FIXME: needlessly high ? -- FR 02/07/2005 | 929 | // FIXME: needlessly high ? -- FR 02/07/2005 |
924 | mod_timer(&tp->timer, jiffies + HZ/10); | 930 | mod_timer(&tp->timer, jiffies + HZ/10); |
925 | } else if (!(mdio_read_latched(ioaddr, phy_id, MII_BMSR) & | 931 | goto out_unlock; |
926 | BMSR_ANEGCOMPLETE)) { | 932 | } |
933 | |||
934 | val = mdio_read_latched(ioaddr, phy_id, MII_BMSR); | ||
935 | if (!(val & BMSR_ANEGCOMPLETE) && tp->link_status != LNK_AUTONEG) { | ||
927 | netif_carrier_off(dev); | 936 | netif_carrier_off(dev); |
928 | netif_warn(tp, link, dev, "auto-negotiating...\n"); | 937 | netif_warn(tp, link, dev, "auto-negotiating...\n"); |
929 | mod_timer(&tp->timer, jiffies + SIS190_PHY_TIMEOUT); | 938 | tp->link_status = LNK_AUTONEG; |
930 | } else { | 939 | } else if ((val & BMSR_LSTATUS) && tp->link_status != LNK_ON) { |
931 | /* Rejoice ! */ | 940 | /* Rejoice ! */ |
932 | struct { | 941 | struct { |
933 | int val; | 942 | int val; |
@@ -1000,7 +1009,10 @@ static void sis190_phy_task(struct work_struct *work) | |||
1000 | 1009 | ||
1001 | netif_info(tp, link, dev, "link on %s mode\n", p->msg); | 1010 | netif_info(tp, link, dev, "link on %s mode\n", p->msg); |
1002 | netif_carrier_on(dev); | 1011 | netif_carrier_on(dev); |
1003 | } | 1012 | tp->link_status = LNK_ON; |
1013 | } else if (!(val & BMSR_LSTATUS) && tp->link_status != LNK_AUTONEG) | ||
1014 | tp->link_status = LNK_OFF; | ||
1015 | mod_timer(&tp->timer, jiffies + SIS190_PHY_TIMEOUT); | ||
1004 | 1016 | ||
1005 | out_unlock: | 1017 | out_unlock: |
1006 | rtnl_unlock(); | 1018 | rtnl_unlock(); |
@@ -1513,6 +1525,7 @@ static struct net_device * __devinit sis190_init_board(struct pci_dev *pdev) | |||
1513 | 1525 | ||
1514 | tp->pci_dev = pdev; | 1526 | tp->pci_dev = pdev; |
1515 | tp->mmio_addr = ioaddr; | 1527 | tp->mmio_addr = ioaddr; |
1528 | tp->link_status = LNK_OFF; | ||
1516 | 1529 | ||
1517 | sis190_irq_mask_and_ack(ioaddr); | 1530 | sis190_irq_mask_and_ack(ioaddr); |
1518 | 1531 | ||