Re: [RFC] Revert "sierra_net: keep status interrupt URB active"

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Fri, 2013-11-01 at 13:53 +0100, Bjørn Mork wrote:
> This reverts commit 7b0c5f21f348a66de495868b8df0284e8dfd6bbf.
> 
> It's not easy to create a driver for all the various firmware
> bugs out there.
> 
> This change caused regressions for a number of devices, which
> started to fail link detection and therefore became completely
> non-functional. The exact reason is yet unknown, it looks like
> the affected firmwares might actually need all or some of the
> additional SYNC messages the patch got rid of.
> 
> Reverting is not optimal, as it will re-introduce the original
> problem, but it is currently the only alternative known to fix
> this issue.

Instead, how does the following patch work for you?

Dan

---
diff --git a/drivers/net/usb/sierra_net.c b/drivers/net/usb/sierra_net.c
index a79e9d3..dd59d97 100644
--- a/drivers/net/usb/sierra_net.c
+++ b/drivers/net/usb/sierra_net.c
@@ -163,18 +163,19 @@ struct lsi_umts {
 #define SIERRA_NET_LSI_UMTS_LEN        (sizeof(struct lsi_umts))
 #define SIERRA_NET_LSI_UMTS_STATUS_LEN \
 	(SIERRA_NET_LSI_UMTS_LEN - SIERRA_NET_LSI_COMMON_LEN)
 
 /* Forward definitions */
 static void sierra_sync_timer(unsigned long syncdata);
 static int sierra_net_change_mtu(struct net_device *net, int new_mtu);
+static int sierra_net_open (struct net_device *net);
 
 /* Our own net device operations structure */
 static const struct net_device_ops sierra_net_device_ops = {
-	.ndo_open               = usbnet_open,
+	.ndo_open               = sierra_net_open,
 	.ndo_stop               = usbnet_stop,
 	.ndo_start_xmit         = usbnet_start_xmit,
 	.ndo_tx_timeout         = usbnet_tx_timeout,
 	.ndo_change_mtu         = sierra_net_change_mtu,
 	.ndo_set_mac_address    = eth_mac_addr,
 	.ndo_validate_addr      = eth_validate_addr,
 };
@@ -439,14 +440,15 @@ static void sierra_net_dosync(struct usbnet *dev)
 		netdev_err(dev->net,
 			"Send SYNC failed, status %d\n", status);
 	status = sierra_net_send_sync(dev);
 	if (status < 0)
 		netdev_err(dev->net,
 			"Send SYNC failed, status %d\n", status);
 
+printk(KERN_INFO "%s: sent two SYNC messages\n", __func__);
 	/* Now, start a timer and make sure we get the Restart Indication */
 	priv->sync_timer.function = sierra_sync_timer;
 	priv->sync_timer.data = (unsigned long) dev;
 	priv->sync_timer.expires = jiffies + SIERRA_NET_SYNCDELAY;
 	add_timer(&priv->sync_timer);
 }
 
@@ -497,31 +499,34 @@ static void sierra_net_kevent(struct work_struct *work)
 				netdev_err(dev->net, "%s: Bad packet, received"
 					" %d, expected %d\n",	__func__, len,
 					hh.hdrlen + hh.payload_len.word);
 				kfree(buf);
 				return;
 			}
 
+printk(KERN_INFO "%s: received msg 0x%02x len %d\n", __func__, hh.msgid.byte, len);
 			/* Switch on received message types */
 			switch (hh.msgid.byte) {
 			case SIERRA_NET_HIP_LSI_UMTSID:
 				dev_dbg(&dev->udev->dev, "LSI for ctx:%d",
 					hh.msgspecific.byte);
 				sierra_net_handle_lsi(dev, buf, &hh);
 				break;
 			case SIERRA_NET_HIP_RESTART_ID:
+printk(KERN_INFO "%s: RESTART received code 0x%02x\n", __func__, hh.msgspecific.byte);
 				dev_dbg(&dev->udev->dev, "Restart reported: %d,"
 						" stopping sync timer",
 						hh.msgspecific.byte);
 				/* Got sync resp - stop timer & clear mask */
 				del_timer_sync(&priv->sync_timer);
 				clear_bit(SIERRA_NET_TIMER_EXPIRY,
 					  &priv->kevent_flags);
 				break;
 			case SIERRA_NET_HIP_HSYNC_ID:
+printk(KERN_INFO "%s: HSYNC received\n", __func__);
 				dev_dbg(&dev->udev->dev, "SYNC received");
 				err = sierra_net_send_sync(dev);
 				if (err < 0)
 					netdev_err(dev->net,
 						"Send SYNC failed %d\n", err);
 				break;
 			case SIERRA_NET_HIP_EXTENDEDID:
@@ -537,14 +542,15 @@ static void sierra_net_kevent(struct work_struct *work)
 				break;
 			}
 		}
 		kfree(buf);
 	}
 	/* The sync timer bit might be set */
 	if (test_bit(SIERRA_NET_TIMER_EXPIRY, &priv->kevent_flags)) {
+printk(KERN_INFO "%s: re-sending SYNC\n", __func__);
 		clear_bit(SIERRA_NET_TIMER_EXPIRY, &priv->kevent_flags);
 		dev_dbg(&dev->udev->dev, "Deferred sync timer expiry");
 		sierra_net_dosync(priv->usbnet);
 	}
 
 	if (priv->kevent_flags)
 		dev_dbg(&dev->udev->dev, "sierra_net_kevent done, "
@@ -562,14 +568,15 @@ static void sierra_net_defer_kevent(struct usbnet *dev, int work)
 /*
  * Sync Retransmit Timer Handler. On expiry, kick the work queue
  */
 static void sierra_sync_timer(unsigned long syncdata)
 {
 	struct usbnet *dev = (struct usbnet *)syncdata;
 
+printk(KERN_INFO "%s: sync timer expired\n", __func__);
 	dev_dbg(&dev->udev->dev, "%s", __func__);
 	/* Kick the tasklet */
 	sierra_net_defer_kevent(dev, SIERRA_NET_TIMER_EXPIRY);
 }
 
 static void sierra_net_status(struct usbnet *dev, struct urb *urb)
 {
@@ -584,14 +591,15 @@ static void sierra_net_status(struct usbnet *dev, struct urb *urb)
 	event = urb->transfer_buffer;
 	switch (event->bNotificationType) {
 	case USB_CDC_NOTIFY_NETWORK_CONNECTION:
 	case USB_CDC_NOTIFY_SPEED_CHANGE:
 		/* USB 305 sends those */
 		break;
 	case USB_CDC_NOTIFY_RESPONSE_AVAILABLE:
+printk(KERN_INFO "%s: firmware indicates response available\n", __func__);
 		sierra_net_defer_kevent(dev, SIERRA_NET_EVENT_RESP_AVAIL);
 		break;
 	default:
 		netdev_err(dev->net, ": unexpected notification %02x!\n",
 				event->bNotificationType);
 		break;
 	}
@@ -767,20 +775,32 @@ static void sierra_net_unbind(struct usbnet *dev, struct usb_interface *intf)
 	/* tell modem we are going away */
 	status = sierra_net_send_cmd(dev, priv->shdwn_msg,
 			sizeof(priv->shdwn_msg), "Shutdown");
 	if (status < 0)
 		netdev_err(dev->net,
 			"usb_control_msg failed, status %d\n", status);
 
-	usbnet_status_stop(dev);
-
 	sierra_net_set_private(dev, NULL);
 	kfree(priv);
 }
 
+static int sierra_net_open (struct net_device *net)
+{
+	int ret;
+
+	ret = usbnet_open(net);
+	if (ret == 0) {
+		struct usbnet *dev = netdev_priv(net);
+
+		/* Interrupt URB now set up; initiate sync sequence */
+		sierra_net_dosync(dev);
+	}
+	return ret;
+}
+
 static struct sk_buff *sierra_net_skb_clone(struct usbnet *dev,
 		struct sk_buff *skb, int len)
 {
 	struct sk_buff *new_skb;
 
 	/* clone skb */
 	new_skb = skb_clone(skb, GFP_ATOMIC);
@@ -910,14 +930,15 @@ static const struct driver_info sierra_net_info_direct_ip = {
 	.bind = sierra_net_bind,
 	.unbind = sierra_net_unbind,
 	.status = sierra_net_status,
 	.rx_fixup = sierra_net_rx_fixup,
 	.tx_fixup = sierra_net_tx_fixup,
 };
 
+#if 0
 static int
 sierra_net_probe(struct usb_interface *udev, const struct usb_device_id *prod)
 {
 	int ret;
 
 	ret = usbnet_probe(udev, prod);
 	if (ret == 0) {
@@ -927,14 +948,15 @@ sierra_net_probe(struct usb_interface *udev, const struct usb_device_id *prod)
 		if (ret == 0) {
 			/* Interrupt URB now set up; initiate sync sequence */
 			sierra_net_dosync(dev);
 		}
 	}
 	return ret;
 }
+#endif
 
 #define DIRECT_IP_DEVICE(vend, prod) \
 	{USB_DEVICE_INTERFACE_NUMBER(vend, prod, 7), \
 	.driver_info = (unsigned long)&sierra_net_info_direct_ip}, \
 	{USB_DEVICE_INTERFACE_NUMBER(vend, prod, 10), \
 	.driver_info = (unsigned long)&sierra_net_info_direct_ip}, \
 	{USB_DEVICE_INTERFACE_NUMBER(vend, prod, 11), \
@@ -950,15 +972,15 @@ static const struct usb_device_id products[] = {
 };
 MODULE_DEVICE_TABLE(usb, products);
 
 /* We are based on usbnet, so let it handle the USB driver specifics */
 static struct usb_driver sierra_net_driver = {
 	.name = "sierra_net",
 	.id_table = products,
-	.probe = sierra_net_probe,
+	.probe = usbnet_probe,
 	.disconnect = usbnet_disconnect,
 	.suspend = usbnet_suspend,
 	.resume = usbnet_resume,
 	.no_dynamic_id = 1,
 	.disable_hub_initiated_lpm = 1,
 };
 

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux