Skip to content

Commit d69d169

Browse files
ch-fdavem330
authored andcommitted
usbnet: smsc95xx: fix link detection for disabled autonegotiation
To detect link status up/down for connections where autonegotiation is explicitly disabled, we don't get an irq but need to poll the status register for link up/down detection. This patch adds a workqueue to poll for link status. Signed-off-by: Christoph Fritz <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent f00e35e commit d69d169

File tree

1 file changed

+51
-0
lines changed

1 file changed

+51
-0
lines changed

drivers/net/usb/smsc95xx.c

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,8 @@
6161
#define SUSPEND_ALLMODES (SUSPEND_SUSPEND0 | SUSPEND_SUSPEND1 | \
6262
SUSPEND_SUSPEND2 | SUSPEND_SUSPEND3)
6363

64+
#define CARRIER_CHECK_DELAY (2 * HZ)
65+
6466
struct smsc95xx_priv {
6567
u32 mac_cr;
6668
u32 hash_hi;
@@ -69,6 +71,9 @@ struct smsc95xx_priv {
6971
spinlock_t mac_cr_lock;
7072
u8 features;
7173
u8 suspend_flags;
74+
bool link_ok;
75+
struct delayed_work carrier_check;
76+
struct usbnet *dev;
7277
};
7378

7479
static bool turbo_mode = true;
@@ -624,6 +629,44 @@ static void smsc95xx_status(struct usbnet *dev, struct urb *urb)
624629
intdata);
625630
}
626631

632+
static void set_carrier(struct usbnet *dev, bool link)
633+
{
634+
struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]);
635+
636+
if (pdata->link_ok == link)
637+
return;
638+
639+
pdata->link_ok = link;
640+
641+
if (link)
642+
usbnet_link_change(dev, 1, 0);
643+
else
644+
usbnet_link_change(dev, 0, 0);
645+
}
646+
647+
static void check_carrier(struct work_struct *work)
648+
{
649+
struct smsc95xx_priv *pdata = container_of(work, struct smsc95xx_priv,
650+
carrier_check.work);
651+
struct usbnet *dev = pdata->dev;
652+
int ret;
653+
654+
if (pdata->suspend_flags != 0)
655+
return;
656+
657+
ret = smsc95xx_mdio_read(dev->net, dev->mii.phy_id, MII_BMSR);
658+
if (ret < 0) {
659+
netdev_warn(dev->net, "Failed to read MII_BMSR\n");
660+
return;
661+
}
662+
if (ret & BMSR_LSTATUS)
663+
set_carrier(dev, 1);
664+
else
665+
set_carrier(dev, 0);
666+
667+
schedule_delayed_work(&pdata->carrier_check, CARRIER_CHECK_DELAY);
668+
}
669+
627670
/* Enable or disable Tx & Rx checksum offload engines */
628671
static int smsc95xx_set_features(struct net_device *netdev,
629672
netdev_features_t features)
@@ -1165,13 +1208,20 @@ static int smsc95xx_bind(struct usbnet *dev, struct usb_interface *intf)
11651208
dev->net->flags |= IFF_MULTICAST;
11661209
dev->net->hard_header_len += SMSC95XX_TX_OVERHEAD_CSUM;
11671210
dev->hard_mtu = dev->net->mtu + dev->net->hard_header_len;
1211+
1212+
pdata->dev = dev;
1213+
INIT_DELAYED_WORK(&pdata->carrier_check, check_carrier);
1214+
schedule_delayed_work(&pdata->carrier_check, CARRIER_CHECK_DELAY);
1215+
11681216
return 0;
11691217
}
11701218

11711219
static void smsc95xx_unbind(struct usbnet *dev, struct usb_interface *intf)
11721220
{
11731221
struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]);
1222+
11741223
if (pdata) {
1224+
cancel_delayed_work(&pdata->carrier_check);
11751225
netif_dbg(dev, ifdown, dev->net, "free pdata\n");
11761226
kfree(pdata);
11771227
pdata = NULL;
@@ -1695,6 +1745,7 @@ static int smsc95xx_resume(struct usb_interface *intf)
16951745

16961746
/* do this first to ensure it's cleared even in error case */
16971747
pdata->suspend_flags = 0;
1748+
schedule_delayed_work(&pdata->carrier_check, CARRIER_CHECK_DELAY);
16981749

16991750
if (suspend_flags & SUSPEND_ALLMODES) {
17001751
/* clear wake-up sources */

0 commit comments

Comments
 (0)