From patchwork Fri May 24 14:52:30 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Nicolas Saenz Julienne X-Patchwork-Id: 10960001 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 00EB9933 for ; Fri, 24 May 2019 14:52:38 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id E125928686 for ; Fri, 24 May 2019 14:52:37 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id D4CBC2877E; Fri, 24 May 2019 14:52:37 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.9 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI, RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id C77D828686 for ; Fri, 24 May 2019 14:52:36 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2404040AbfEXOwg (ORCPT ); Fri, 24 May 2019 10:52:36 -0400 Received: from mx2.suse.de ([195.135.220.15]:52908 "EHLO mx1.suse.de" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S2403860AbfEXOwg (ORCPT ); Fri, 24 May 2019 10:52:36 -0400 X-Virus-Scanned: by amavisd-new at test-mx.suse.de Received: from relay2.suse.de (unknown [195.135.220.254]) by mx1.suse.de (Postfix) with ESMTP id E02AFAF7F; Fri, 24 May 2019 14:52:34 +0000 (UTC) From: Nicolas Saenz Julienne To: Mathias Nyman Cc: oneukum@suse.com, Nicolas Saenz Julienne , Greg Kroah-Hartman , linux-usb@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH] xhci: clear port_remote_wakeup after resume failure Date: Fri, 24 May 2019 16:52:30 +0200 Message-Id: <20190524145231.6605-1-nsaenzjulienne@suse.de> X-Mailer: git-send-email 2.21.0 MIME-Version: 1.0 Sender: linux-usb-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-usb@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP This was seen on a Dell Precision 5520 using it's WD15 dock. The dock's Ethernet device interfaces with the laptop through one of it's USB3 ports. While idle, the Ethernet device and HCD are suspended by runtime PM, being the only device connected on the bus. Then, both are resumed on behalf of the Ethernet device, which has remote wake-up capabilities. The Ethernet device was observed to randomly disconnect from the USB port shortly after submitting it's remote wake-up request. Probably a weird timing issue yet to be investigated. This causes runtime PM to busyloop causing some tangible CPU load. The reason is the port gets stuck in the middle of a remote wake-up operation, waiting for the device to switch to U0. This never happens, leaving "port_remote_wakeup" enabled, and automatically triggering a failure on any further suspend operation. This patch clears "port_remote_wakeup" upon detecting a device with a wrong resuming port state (see Table 4-9 in 4.15.2.3). Making sure the above mentioned situation doesn't trigger a PM busyloop. Signed-off-by: Nicolas Saenz Julienne --- drivers/usb/host/xhci-hub.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c index 3abe70ff1b1e..53f5ee50ef8c 100644 --- a/drivers/usb/host/xhci-hub.c +++ b/drivers/usb/host/xhci-hub.c @@ -1047,8 +1047,8 @@ static u32 xhci_get_port_status(struct usb_hcd *hcd, xhci_get_usb2_port_status(port, &status, raw_port_status, flags); /* - * Clear stale usb2 resume signalling variables in case port changed - * state during resume signalling. For example on error + * Clear stale resume signalling variables in case port changed + * state during resume signalling. For example on error. */ if ((bus_state->resume_done[wIndex] || test_bit(wIndex, &bus_state->resuming_ports)) && @@ -1057,6 +1057,12 @@ static u32 xhci_get_port_status(struct usb_hcd *hcd, bus_state->resume_done[wIndex] = 0; clear_bit(wIndex, &bus_state->resuming_ports); usb_hcd_end_port_resume(&hcd->self, wIndex); + } else if (bus_state->port_remote_wakeup & (1 << port->hcd_portnum) && + ((raw_port_status & PORT_PLS_MASK) != XDEV_RESUME || + !(raw_port_status & PORT_CONNECT) || + !(raw_port_status & PORT_PE) || + raw_port_status & PORT_OC)) { + bus_state->port_remote_wakeup &= ~(1 << port->hcd_portnum); } if (bus_state->port_c_suspend & (1 << wIndex))