099-0006-net-qmi_wwan-MDM9x30-specific-power-management.patch 3.4 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192
  1. From 93725149794d3d418cf1eddcae60c7b536c5faa1 Mon Sep 17 00:00:00 2001
  2. From: =?UTF-8?q?Bj=C3=B8rn=20Mork?= <bjorn@mork.no>
  3. Date: Thu, 3 Dec 2015 19:24:18 +0100
  4. Subject: [PATCH] net: qmi_wwan: MDM9x30 specific power management
  5. MIME-Version: 1.0
  6. Content-Type: text/plain; charset=UTF-8
  7. Content-Transfer-Encoding: 8bit
  8. MDM9x30 based modems appear to go into a deeper sleep when
  9. suspended without "Remote Wakeup" enabled. The QMI interface
  10. will not respond unless a "set DTR" control request is sent
  11. on resume. The effect is similar to a QMI_CTL SYNC request,
  12. resetting (some of) the firmware state.
  13. We allow userspace sessions to span multiple character device
  14. open/close sequences. This means that userspace can depend
  15. on firmware state while both the netdev and the character
  16. device are closed. We have disabled "needs_remote_wakeup" at
  17. this point to allow devices without remote wakeup support to
  18. be auto-suspended.
  19. To make sure the MDM9x30 keeps firmware state, we need to
  20. keep "needs_remote_wakeup" always set. We also need to
  21. issue a "set DTR" request to enable the QMI interface.
  22. Signed-off-by: Bjørn Mork <bjorn@mork.no>
  23. Signed-off-by: David S. Miller <davem@davemloft.net>
  24. ---
  25. drivers/net/usb/qmi_wwan.c | 38 ++++++++++++++++++++++++++++++++++++++
  26. 1 file changed, 38 insertions(+)
  27. --- a/drivers/net/usb/qmi_wwan.c
  28. +++ b/drivers/net/usb/qmi_wwan.c
  29. @@ -329,6 +329,20 @@ err:
  30. return rv;
  31. }
  32. +/* Send CDC SetControlLineState request, setting or clearing the DTR.
  33. + * "Required for Autoconnect and 9x30 to wake up" according to the
  34. + * GobiNet driver. The requirement has been verified on an MDM9230
  35. + * based Sierra Wireless MC7455
  36. + */
  37. +static int qmi_wwan_change_dtr(struct usbnet *dev, bool on)
  38. +{
  39. + u8 intf = dev->intf->cur_altsetting->desc.bInterfaceNumber;
  40. +
  41. + return usbnet_write_cmd(dev, USB_CDC_REQ_SET_CONTROL_LINE_STATE,
  42. + USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
  43. + on ? 0x01 : 0x00, intf, NULL, 0);
  44. +}
  45. +
  46. static int qmi_wwan_bind(struct usbnet *dev, struct usb_interface *intf)
  47. {
  48. int status = -1;
  49. @@ -386,6 +400,24 @@ static int qmi_wwan_bind(struct usbnet *
  50. usb_driver_release_interface(driver, info->data);
  51. }
  52. + /* disabling remote wakeup on MDM9x30 devices has the same
  53. + * effect as clearing DTR. The device will not respond to QMI
  54. + * requests until we set DTR again. This is similar to a
  55. + * QMI_CTL SYNC request, clearing a lot of firmware state
  56. + * including the client ID allocations.
  57. + *
  58. + * Our usage model allows a session to span multiple
  59. + * open/close events, so we must prevent the firmware from
  60. + * clearing out state the clients might need.
  61. + *
  62. + * MDM9x30 is the first QMI chipset with USB3 support. Abuse
  63. + * this fact to enable the quirk.
  64. + */
  65. + if (le16_to_cpu(dev->udev->descriptor.bcdUSB) >= 0x0201) {
  66. + qmi_wwan_manage_power(dev, 1);
  67. + qmi_wwan_change_dtr(dev, true);
  68. + }
  69. +
  70. /* Never use the same address on both ends of the link, even if the
  71. * buggy firmware told us to. Or, if device is assigned the well-known
  72. * buggy firmware MAC address, replace it with a random address,
  73. @@ -414,6 +446,12 @@ static void qmi_wwan_unbind(struct usbne
  74. if (info->subdriver && info->subdriver->disconnect)
  75. info->subdriver->disconnect(info->control);
  76. + /* disable MDM9x30 quirk */
  77. + if (le16_to_cpu(dev->udev->descriptor.bcdUSB) >= 0x0201) {
  78. + qmi_wwan_change_dtr(dev, false);
  79. + qmi_wwan_manage_power(dev, 0);
  80. + }
  81. +
  82. /* allow user to unbind using either control or data */
  83. if (intf == info->control)
  84. other = info->data;