diff options
author | Ondrej Zary <linux@rainbow-software.org> | 2012-10-11 18:51:41 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2012-10-12 13:56:52 -0400 |
commit | dabdaf0caa3af520dbc1df87b2fb4e77224037bd (patch) | |
tree | 27de4c1b7c097ab07193e4ba29c6a11a6a08b53c /drivers/net | |
parent | 93ac0ef016a1b223d23fbb5e0397cab75a8f7d34 (diff) |
mcs7830: Fix link state detection
The device had an undocumented "feature": it can provide a sequence of
spurious link-down status data even if the link is up all the time.
A sequence of 10 was seen so update the link state only after the device
reports the same link state 20 times.
Signed-off-by: Ondrej Zary <linux@rainbow-software.org>
Reported-by: Michael Leun <lkml20120218@newton.leun.net>
Tested-by: Michael Leun <lkml20120218@newton.leun.net>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net')
-rw-r--r-- | drivers/net/usb/mcs7830.c | 30 |
1 files changed, 21 insertions, 9 deletions
diff --git a/drivers/net/usb/mcs7830.c b/drivers/net/usb/mcs7830.c index 03c2d8d653df..cc7e72010ac3 100644 --- a/drivers/net/usb/mcs7830.c +++ b/drivers/net/usb/mcs7830.c | |||
@@ -117,6 +117,7 @@ enum { | |||
117 | struct mcs7830_data { | 117 | struct mcs7830_data { |
118 | u8 multi_filter[8]; | 118 | u8 multi_filter[8]; |
119 | u8 config; | 119 | u8 config; |
120 | u8 link_counter; | ||
120 | }; | 121 | }; |
121 | 122 | ||
122 | static const char driver_name[] = "MOSCHIP usb-ethernet driver"; | 123 | static const char driver_name[] = "MOSCHIP usb-ethernet driver"; |
@@ -632,20 +633,31 @@ static int mcs7830_rx_fixup(struct usbnet *dev, struct sk_buff *skb) | |||
632 | static void mcs7830_status(struct usbnet *dev, struct urb *urb) | 633 | static void mcs7830_status(struct usbnet *dev, struct urb *urb) |
633 | { | 634 | { |
634 | u8 *buf = urb->transfer_buffer; | 635 | u8 *buf = urb->transfer_buffer; |
635 | bool link; | 636 | bool link, link_changed; |
637 | struct mcs7830_data *data = mcs7830_get_data(dev); | ||
636 | 638 | ||
637 | if (urb->actual_length < 16) | 639 | if (urb->actual_length < 16) |
638 | return; | 640 | return; |
639 | 641 | ||
640 | link = !(buf[1] & 0x20); | 642 | link = !(buf[1] & 0x20); |
641 | if (netif_carrier_ok(dev->net) != link) { | 643 | link_changed = netif_carrier_ok(dev->net) != link; |
642 | if (link) { | 644 | if (link_changed) { |
643 | netif_carrier_on(dev->net); | 645 | data->link_counter++; |
644 | usbnet_defer_kevent(dev, EVENT_LINK_RESET); | 646 | /* |
645 | } else | 647 | track link state 20 times to guard against erroneous |
646 | netif_carrier_off(dev->net); | 648 | link state changes reported sometimes by the chip |
647 | netdev_dbg(dev->net, "Link Status is: %d\n", link); | 649 | */ |
648 | } | 650 | if (data->link_counter > 20) { |
651 | data->link_counter = 0; | ||
652 | if (link) { | ||
653 | netif_carrier_on(dev->net); | ||
654 | usbnet_defer_kevent(dev, EVENT_LINK_RESET); | ||
655 | } else | ||
656 | netif_carrier_off(dev->net); | ||
657 | netdev_dbg(dev->net, "Link Status is: %d\n", link); | ||
658 | } | ||
659 | } else | ||
660 | data->link_counter = 0; | ||
649 | } | 661 | } |
650 | 662 | ||
651 | static const struct driver_info moschip_info = { | 663 | static const struct driver_info moschip_info = { |