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

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

 



On Mon, 2013-11-04 at 14:27 -0600, Dan Williams wrote:
> 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?

Bjorn, did you have a chance to try this patch out on your devices?

Dan

> 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


--
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