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 majord...@vger.kernel.org
> 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 majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to