Received: by 2002:a05:6a10:9848:0:0:0:0 with SMTP id x8csp3527731pxf; Mon, 15 Mar 2021 11:33:03 -0700 (PDT) X-Google-Smtp-Source: ABdhPJwU0q9Vu8EnZtp47qebd+Ki2RlB5yqg5EXYL2IwPE8qZyepydFXitNHBFPufi8JI7bGd87f X-Received: by 2002:a17:906:5203:: with SMTP id g3mr8697726ejm.95.1615833183027; Mon, 15 Mar 2021 11:33:03 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1615833183; cv=none; d=google.com; s=arc-20160816; b=rSKbXld3UBocSlGBbFcTrXGj5Ydvc9M23QHcc7x25RbT3PeZrFG+t5qMTEEE2H7ZNo S+kUrHVyBrR2j2yZET3bW7HZ/5VgBuw9/jc7EaqlyBA7p/5Sjuxv2rfPckaLv3frYMFN CokZnelp/eQHhVTekOM7xlqC6dai5HlFjYco8enhvtRY+0oYmizVIcwG/l4RLAbhbQCW T45dTQnozjyjfeLQ5LWyqMAD6qX9MYG9+s4Z1be5a/CG0LBUUJuP+3s1r/7qAKv/1gfJ DAGpcS0W4eIxEjHBC+8bjxQtGRM3R/Alx0I+AgqSPmUiv9tYK8GwzHuhS8sGOFl6OBWF ruWg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :user-agent:references:in-reply-to:message-id:date:subject:cc:to :from:dkim-signature; bh=UTA0wZ3qIla//nCNk1faSsINjpSE+fzeHbPBgNkWRZQ=; b=ftStpa9UrdWGAKL/qB8csrvSeaY3AvHjlIfI0tBoULpJ4evXCJQQK5mY9KnExfj3Z1 zF0vP4RJTGdm84KFD9CY0yuUHvksKDHiCVXVY7oh24TeB+J/uXhwmD9ACGaVG9MTFWt8 QWXpnI+APnKY+jtitmtr3XgXRoLpHVHIJ7KUGIVabFM/ovWO1cTi3PZMyLTRm1sZ7k/Q xiCvbmIoRMkkKBfbRm3zzojT0Zecj41LPRUnSPyTXjL0KXhlnKmUzUVzrqzsfNDo1OB1 BzcJhdLzoL9j10XQJwkkrLEvD56KZ9C8+BSuiMBLFYtk8sN2lNV+6RTij3vMkDUCdSY1 H/QQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linuxfoundation.org header.s=korg header.b=CoiZIGDq; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linuxfoundation.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [23.128.96.18]) by mx.google.com with ESMTP id t6si11509613edw.202.2021.03.15.11.32.39; Mon, 15 Mar 2021 11:33:03 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) client-ip=23.128.96.18; Authentication-Results: mx.google.com; dkim=pass header.i=@linuxfoundation.org header.s=korg header.b=CoiZIGDq; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linuxfoundation.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S236213AbhCOOiv (ORCPT + 99 others); Mon, 15 Mar 2021 10:38:51 -0400 Received: from mail.kernel.org ([198.145.29.99]:48766 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S233658AbhCOOCR (ORCPT ); Mon, 15 Mar 2021 10:02:17 -0400 Received: by mail.kernel.org (Postfix) with ESMTPSA id C8FEB64E89; Mon, 15 Mar 2021 14:02:05 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=linuxfoundation.org; s=korg; t=1615816926; bh=UnvoTaee++uQmgZBcbDloBQf3a1K2DhIcoEylFd3FLI=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=CoiZIGDqydG8hfQcDx8+fuvbBP9AJtMl0HzNgA17qS9jRcAjiYuGRzlvwbGPlyRYv mGeUKYJaezmmQEGm4QoECfyBUgLhWnrlZ7S2JzI79RD2wubEPXcDcY/Zj6ej8lok+o oiEuVVdTfyN2DiagyQ9SqXicXcE5DkCO6mg0KxUY= From: gregkh@linuxfoundation.org To: linux-kernel@vger.kernel.org Cc: Greg Kroah-Hartman , stable@vger.kernel.org, Mika Westerberg , Mathias Nyman Subject: [PATCH 5.11 207/306] xhci: Fix repeated xhci wake after suspend due to uncleared internal wake state Date: Mon, 15 Mar 2021 14:54:30 +0100 Message-Id: <20210315135514.629705304@linuxfoundation.org> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20210315135507.611436477@linuxfoundation.org> References: <20210315135507.611436477@linuxfoundation.org> User-Agent: quilt/0.66 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: Greg Kroah-Hartman From: Mathias Nyman commit d26c00e7276fc92b18c253d69e872f6b03832bad upstream. If port terminations are detected in suspend, but link never reaches U0 then xHCI may have an internal uncleared wake state that will cause an immediate wake after suspend. This wake state is normally cleared when driver clears the PORT_CSC bit, which is set after a device is enabled and in U0. Write 1 to clear PORT_CSC for ports that don't have anything connected when suspending. This makes sure any pending internal wake states in xHCI are cleared. Cc: stable@vger.kernel.org Tested-by: Mika Westerberg Signed-off-by: Mathias Nyman Link: https://lore.kernel.org/r/20210311115353.2137560-5-mathias.nyman@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci.c | 62 +++++++++++++++++++++++------------------------- 1 file changed, 30 insertions(+), 32 deletions(-) --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -883,44 +883,42 @@ static void xhci_clear_command_ring(stru xhci_set_cmd_ring_deq(xhci); } -static void xhci_disable_port_wake_on_bits(struct xhci_hcd *xhci) +/* + * Disable port wake bits if do_wakeup is not set. + * + * Also clear a possible internal port wake state left hanging for ports that + * detected termination but never successfully enumerated (trained to 0U). + * Internal wake causes immediate xHCI wake after suspend. PORT_CSC write done + * at enumeration clears this wake, force one here as well for unconnected ports + */ + +static void xhci_disable_hub_port_wake(struct xhci_hcd *xhci, + struct xhci_hub *rhub, + bool do_wakeup) { - struct xhci_port **ports; - int port_index; unsigned long flags; u32 t1, t2, portsc; + int i; spin_lock_irqsave(&xhci->lock, flags); - /* disable usb3 ports Wake bits */ - port_index = xhci->usb3_rhub.num_ports; - ports = xhci->usb3_rhub.ports; - while (port_index--) { - t1 = readl(ports[port_index]->addr); - portsc = t1; - t1 = xhci_port_state_to_neutral(t1); - t2 = t1 & ~PORT_WAKE_BITS; - if (t1 != t2) { - writel(t2, ports[port_index]->addr); - xhci_dbg(xhci, "disable wake bits port %d-%d, portsc: 0x%x, write: 0x%x\n", - xhci->usb3_rhub.hcd->self.busnum, - port_index + 1, portsc, t2); - } - } + for (i = 0; i < rhub->num_ports; i++) { + portsc = readl(rhub->ports[i]->addr); + t1 = xhci_port_state_to_neutral(portsc); + t2 = t1; + + /* clear wake bits if do_wake is not set */ + if (!do_wakeup) + t2 &= ~PORT_WAKE_BITS; + + /* Don't touch csc bit if connected or connect change is set */ + if (!(portsc & (PORT_CSC | PORT_CONNECT))) + t2 |= PORT_CSC; - /* disable usb2 ports Wake bits */ - port_index = xhci->usb2_rhub.num_ports; - ports = xhci->usb2_rhub.ports; - while (port_index--) { - t1 = readl(ports[port_index]->addr); - portsc = t1; - t1 = xhci_port_state_to_neutral(t1); - t2 = t1 & ~PORT_WAKE_BITS; if (t1 != t2) { - writel(t2, ports[port_index]->addr); - xhci_dbg(xhci, "disable wake bits port %d-%d, portsc: 0x%x, write: 0x%x\n", - xhci->usb2_rhub.hcd->self.busnum, - port_index + 1, portsc, t2); + writel(t2, rhub->ports[i]->addr); + xhci_dbg(xhci, "config port %d-%d wake bits, portsc: 0x%x, write: 0x%x\n", + rhub->hcd->self.busnum, i + 1, portsc, t2); } } spin_unlock_irqrestore(&xhci->lock, flags); @@ -983,8 +981,8 @@ int xhci_suspend(struct xhci_hcd *xhci, return -EINVAL; /* Clear root port wake on bits if wakeup not allowed. */ - if (!do_wakeup) - xhci_disable_port_wake_on_bits(xhci); + xhci_disable_hub_port_wake(xhci, &xhci->usb3_rhub, do_wakeup); + xhci_disable_hub_port_wake(xhci, &xhci->usb2_rhub, do_wakeup); if (!HCD_HW_ACCESSIBLE(hcd)) return 0;