Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753968AbcDVLJI (ORCPT ); Fri, 22 Apr 2016 07:09:08 -0400 Received: from mx2.suse.de ([195.135.220.15]:43987 "EHLO mx2.suse.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753846AbcDVLGh (ORCPT ); Fri, 22 Apr 2016 07:06:37 -0400 X-Amavis-Alert: BAD HEADER SECTION, Duplicate header field: "References" From: Jiri Slaby To: stable@vger.kernel.org Cc: linux-kernel@vger.kernel.org, =?UTF-8?q?Bj=C3=B8rn=20Mork?= , "David S . Miller" , Jiri Slaby Subject: [PATCH 3.12 61/78] net: qmi_wwan: MDM9x30 specific power management Date: Fri, 22 Apr 2016 13:05:44 +0200 Message-Id: <9c186cff6026b5f54083647005b5247bfba0d43c.1461323133.git.jslaby@suse.cz> X-Mailer: git-send-email 2.8.1 In-Reply-To: References: In-Reply-To: References: MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 3457 Lines: 97 From: Bjørn Mork 3.12-stable review patch. If anyone has any objections, please let me know. =============== commit 93725149794d3d418cf1eddcae60c7b536c5faa1 upstream. MDM9x30 based modems appear to go into a deeper sleep when suspended without "Remote Wakeup" enabled. The QMI interface will not respond unless a "set DTR" control request is sent on resume. The effect is similar to a QMI_CTL SYNC request, resetting (some of) the firmware state. We allow userspace sessions to span multiple character device open/close sequences. This means that userspace can depend on firmware state while both the netdev and the character device are closed. We have disabled "needs_remote_wakeup" at this point to allow devices without remote wakeup support to be auto-suspended. To make sure the MDM9x30 keeps firmware state, we need to keep "needs_remote_wakeup" always set. We also need to issue a "set DTR" request to enable the QMI interface. Signed-off-by: Bjørn Mork Signed-off-by: David S. Miller Signed-off-by: Jiri Slaby --- drivers/net/usb/qmi_wwan.c | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c index 18101e3fcd04..415bbe0365c6 100644 --- a/drivers/net/usb/qmi_wwan.c +++ b/drivers/net/usb/qmi_wwan.c @@ -216,6 +216,20 @@ err: return rv; } +/* Send CDC SetControlLineState request, setting or clearing the DTR. + * "Required for Autoconnect and 9x30 to wake up" according to the + * GobiNet driver. The requirement has been verified on an MDM9230 + * based Sierra Wireless MC7455 + */ +static int qmi_wwan_change_dtr(struct usbnet *dev, bool on) +{ + u8 intf = dev->intf->cur_altsetting->desc.bInterfaceNumber; + + return usbnet_write_cmd(dev, USB_CDC_REQ_SET_CONTROL_LINE_STATE, + USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE, + on ? 0x01 : 0x00, intf, NULL, 0); +} + static int qmi_wwan_bind(struct usbnet *dev, struct usb_interface *intf) { int status = -1; @@ -320,6 +334,24 @@ next_desc: usb_driver_release_interface(driver, info->data); } + /* disabling remote wakeup on MDM9x30 devices has the same + * effect as clearing DTR. The device will not respond to QMI + * requests until we set DTR again. This is similar to a + * QMI_CTL SYNC request, clearing a lot of firmware state + * including the client ID allocations. + * + * Our usage model allows a session to span multiple + * open/close events, so we must prevent the firmware from + * clearing out state the clients might need. + * + * MDM9x30 is the first QMI chipset with USB3 support. Abuse + * this fact to enable the quirk. + */ + if (le16_to_cpu(dev->udev->descriptor.bcdUSB) >= 0x0201) { + qmi_wwan_manage_power(dev, 1); + qmi_wwan_change_dtr(dev, true); + } + /* Never use the same address on both ends of the link, even * if the buggy firmware told us to. */ @@ -345,6 +377,12 @@ static void qmi_wwan_unbind(struct usbnet *dev, struct usb_interface *intf) if (info->subdriver && info->subdriver->disconnect) info->subdriver->disconnect(info->control); + /* disable MDM9x30 quirk */ + if (le16_to_cpu(dev->udev->descriptor.bcdUSB) >= 0x0201) { + qmi_wwan_change_dtr(dev, false); + qmi_wwan_manage_power(dev, 0); + } + /* allow user to unbind using either control or data */ if (intf == info->control) other = info->data; -- 2.8.1