Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

sierra_net: keep status interrupt URB active

The driver and firmware sync up through SYNC messages, and the
firmware's affirmative reply to these SYNC messages appears to be the
"Reset" indication received via the status interrupt endpoint. Thus the
driver needs the status interrupt endpoint always active so that the
Reset indication can be received even if the netdev is closed, which is
the case right after device insertion.

If the Reset indication is not received by the driver, it continues
sending SYNC messages to the firmware, which crashes about 10 seconds
later and the device stops responding.

Signed-off-by: Dan Williams <dcbw@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Dan Williams and committed by
David S. Miller
7b0c5f21 6eecdc5f

+31 -7
+31 -7
drivers/net/usb/sierra_net.c
··· 426 426 427 427 dev_dbg(&dev->udev->dev, "%s", __func__); 428 428 429 + /* The SIERRA_NET_HIP_MSYNC_ID command appears to request that the 430 + * firmware restart itself. After restarting, the modem will respond 431 + * with the SIERRA_NET_HIP_RESTART_ID indication. The driver continues 432 + * sending MSYNC commands every few seconds until it receives the 433 + * RESTART event from the firmware 434 + */ 435 + 429 436 /* tell modem we are ready */ 430 437 status = sierra_net_send_sync(dev); 431 438 if (status < 0) ··· 711 704 /* set context index initially to 0 - prepares tx hdr template */ 712 705 sierra_net_set_ctx_index(priv, 0); 713 706 707 + /* prepare sync message template */ 708 + memcpy(priv->sync_msg, sync_tmplate, sizeof(priv->sync_msg)); 709 + 714 710 /* decrease the rx_urb_size and max_tx_size to 4k on USB 1.1 */ 715 711 dev->rx_urb_size = SIERRA_NET_RX_URB_SIZE; 716 712 if (dev->udev->speed != USB_SPEED_HIGH) ··· 749 739 kfree(priv); 750 740 return -ENODEV; 751 741 } 752 - /* prepare sync message from template */ 753 - memcpy(priv->sync_msg, sync_tmplate, sizeof(priv->sync_msg)); 754 - 755 - /* initiate the sync sequence */ 756 - sierra_net_dosync(dev); 757 742 758 743 return 0; 759 744 } ··· 771 766 netdev_err(dev->net, 772 767 "usb_control_msg failed, status %d\n", status); 773 768 774 - sierra_net_set_private(dev, NULL); 769 + usbnet_status_stop(dev); 775 770 771 + sierra_net_set_private(dev, NULL); 776 772 kfree(priv); 777 773 } 778 774 ··· 914 908 .tx_fixup = sierra_net_tx_fixup, 915 909 }; 916 910 911 + static int 912 + sierra_net_probe(struct usb_interface *udev, const struct usb_device_id *prod) 913 + { 914 + int ret; 915 + 916 + ret = usbnet_probe(udev, prod); 917 + if (ret == 0) { 918 + struct usbnet *dev = usb_get_intfdata(udev); 919 + 920 + ret = usbnet_status_start(dev, GFP_KERNEL); 921 + if (ret == 0) { 922 + /* Interrupt URB now set up; initiate sync sequence */ 923 + sierra_net_dosync(dev); 924 + } 925 + } 926 + return ret; 927 + } 928 + 917 929 #define DIRECT_IP_DEVICE(vend, prod) \ 918 930 {USB_DEVICE_INTERFACE_NUMBER(vend, prod, 7), \ 919 931 .driver_info = (unsigned long)&sierra_net_info_direct_ip}, \ ··· 954 930 static struct usb_driver sierra_net_driver = { 955 931 .name = "sierra_net", 956 932 .id_table = products, 957 - .probe = usbnet_probe, 933 + .probe = sierra_net_probe, 958 934 .disconnect = usbnet_disconnect, 959 935 .suspend = usbnet_suspend, 960 936 .resume = usbnet_resume,