aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net
diff options
context:
space:
mode:
authorOndrej Zary <linux@rainbow-software.org>2012-10-11 18:51:41 -0400
committerDavid S. Miller <davem@davemloft.net>2012-10-12 13:56:52 -0400
commitdabdaf0caa3af520dbc1df87b2fb4e77224037bd (patch)
tree27de4c1b7c097ab07193e4ba29c6a11a6a08b53c /drivers/net
parent93ac0ef016a1b223d23fbb5e0397cab75a8f7d34 (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.c30
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 {
117struct mcs7830_data { 117struct 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
122static const char driver_name[] = "MOSCHIP usb-ethernet driver"; 123static const char driver_name[] = "MOSCHIP usb-ethernet driver";
@@ -632,20 +633,31 @@ static int mcs7830_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
632static void mcs7830_status(struct usbnet *dev, struct urb *urb) 633static 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
651static const struct driver_info moschip_info = { 663static const struct driver_info moschip_info = {