From patchwork Thu Dec 3 18:24:18 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Bj=C3=B8rn_Mork?= X-Patchwork-Id: 552406 X-Patchwork-Delegate: davem@davemloft.net Return-Path: X-Original-To: patchwork-incoming@ozlabs.org Delivered-To: patchwork-incoming@ozlabs.org Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id A7BB31402C0 for ; Fri, 4 Dec 2015 05:25:17 +1100 (AEDT) Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; secure) header.d=mork.no header.i=@mork.no header.b=o5MIGiiM; dkim-atps=neutral Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752543AbbLCSZL (ORCPT ); Thu, 3 Dec 2015 13:25:11 -0500 Received: from canardo.mork.no ([148.122.252.1]:55648 "EHLO canardo.mork.no" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752049AbbLCSZI (ORCPT ); Thu, 3 Dec 2015 13:25:08 -0500 Received: from nemi.mork.no (nemi.mork.no [IPv6:2001:4641:0:2:e8b:fdff:fe08:971]) (authenticated bits=0) by canardo.mork.no (8.14.4/8.14.4) with ESMTP id tB3IOnOd006634 (version=TLSv1/SSLv3 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128 verify=OK); Thu, 3 Dec 2015 19:24:50 +0100 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=mork.no; s=a; t=1449167093; bh=fz+YwTRu8+wjc8vuZiFiZnsj0/Eh4TN00JYMRRZnZuc=; h=From:To:Cc:Date:Message-Id:References:From; b=o5MIGiiM99VXPx6JMxNXQk0UCefsxEI4U1o+dfx8cNDqyo/BIvzKftr+JwYgImQa/ mxnWwL85XdULLae8XXZmXm8C/iP4Oi6nux6wvG65f2Hbi97CSFQPj4LaDLHSk3Fljy AWpjXkdpKsnQTJWapKs3kXX0i1pSG8uzS+Us/Z6W/1BKDYfpnLyQzJb57OcL5oz3rn zhOdK/E5obU27c9pMrjNDIMPzxqWB1psJ6oYnJpc3f7/w+fkZ1ua+Z8kCQ9802/5Kq zG2UxIsz62ipyEz5C7Zo8LtV9Ojnpet7ykNy5xo8c+jrESuJiJlgC67voz8UvZlRiL 36RSWrt9OQksA== Received: from bjorn by nemi.mork.no with local (Exim 4.84) (envelope-from ) id 1a4YYj-0005ut-8X; Thu, 03 Dec 2015 19:24:49 +0100 From: =?UTF-8?q?Bj=C3=B8rn=20Mork?= To: netdev@vger.kernel.org Cc: linux-usb@vger.kernel.org, Marcel Holtmann , Oliver Neukum , Aleksander Morgado , Dan Williams , =?UTF-8?q?Bj=C3=B8rn=20Mork?= Subject: [PATCH 1/6] net: qmi_wwan: MDM9x30 specific power management Date: Thu, 3 Dec 2015 19:24:18 +0100 Message-Id: <1449167063-22703-2-git-send-email-bjorn@mork.no> X-Mailer: git-send-email 2.1.4 In-Reply-To: <1449167063-22703-1-git-send-email-bjorn@mork.no> References: <1449167063-22703-1-git-send-email-bjorn@mork.no> MIME-Version: 1.0 X-Virus-Scanned: clamav-milter 0.98.7 at canardo X-Virus-Status: Clean Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org 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 --- 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 9a5be8b85186..fc9dd452a3b5 100644 --- a/drivers/net/usb/qmi_wwan.c +++ b/drivers/net/usb/qmi_wwan.c @@ -223,6 +223,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; @@ -280,6 +294,24 @@ static int qmi_wwan_bind(struct usbnet *dev, struct usb_interface *intf) 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. Or, if device is assigned the well-known * buggy firmware MAC address, replace it with a random address, @@ -307,6 +339,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;