Received: by 2002:a05:6a10:f3d0:0:0:0:0 with SMTP id a16csp3136570pxv; Mon, 12 Jul 2021 10:07:49 -0700 (PDT) X-Google-Smtp-Source: ABdhPJyDWgKsFQCOW4qJaiDK3DPurcsubrdBaxS9nQFXyuqGcd5MqK6VKToSKMymZg6zCrkEeNj5 X-Received: by 2002:a92:ad03:: with SMTP id w3mr35709314ilh.225.1626109669273; Mon, 12 Jul 2021 10:07:49 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1626109669; cv=none; d=google.com; s=arc-20160816; b=FqgjKraC6hKot/eB1QxtjJYc073+ru9RNm5VoiIo93MwSLqqGjq1FtBLC7G1eBr8Oj lhpRn+5Hnrb2s1sS9Cir/WwNwrGloCPTxnPuEjmGh2s8HMHuY8NXxUPtF8ImCmNVIPpx v4FV8X3Ywdm5WNmcIWIR69vwjqLR30554GdQHnZ6o8kzG2a3DSIHXlCdVT8PXAUxLrVz Gph7PA8UhUcjAzuc2qu7cyGH5JD6A4L0M4Ix2csWOgNTyeSd9PYzQDjfsY7Zmm+k4IwJ 8DBgq4sWtmDbtMKhyJxTXu05skkh7fR+hUL2dyTVWGjEbretktw7jRSwvnWkTu4WDsVW D9Kg== 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 :message-id:date:subject:cc:to:from; bh=jHqCGeXF1aGqLSHXUOx/NbQ35QQUHGpwPRG7U3bmvEE=; b=DX2MgaKnAQDzYjeVVgppxqljlmGBlQv1j+EgzuyHjEug4sf9nFbbUMm9SwYh9PeaFn XQEmayf/VAsTD0QMiHqnNdBT9HA/qCfXWfQj3xreqVDM5Iq2IwBR7YwbVjorQjh1Mf2O yUhOPZWCXKBTZGUP7s178p77dkUg+OTogalW5gzS83LMxAtPLf0gez+sq44QXA3XVbfE euTe0MIAk/40Rlnnc6t3sEPI5ZLDp0b8WAMvLZJEr4IBWo175nhAFaWH54SP/ia/y75f /0vO5QUX1UuLdJUR8G0qi9DLNX2xN6cJWXMbXg3UVvMKR0b8E9O1Yxe3YYJ17itNEPz5 7X0Q== ARC-Authentication-Results: i=1; mx.google.com; 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 Return-Path: Received: from vger.kernel.org (vger.kernel.org. [23.128.96.18]) by mx.google.com with ESMTP id s10si17493376iot.35.2021.07.12.10.07.33; Mon, 12 Jul 2021 10:07:49 -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; 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 Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234870AbhGLRJj (ORCPT + 99 others); Mon, 12 Jul 2021 13:09:39 -0400 Received: from cloudserver094114.home.pl ([79.96.170.134]:62342 "EHLO cloudserver094114.home.pl" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S234561AbhGLRJj (ORCPT ); Mon, 12 Jul 2021 13:09:39 -0400 Received: from localhost (127.0.0.1) (HELO v370.home.net.pl) by /usr/run/smtp (/usr/run/postfix/private/idea_relay_lmtp) via UNIX with SMTP (IdeaSmtpServer 2.1.0) id 1126075ed0e12430; Mon, 12 Jul 2021 19:06:48 +0200 Received: from kreacher.localnet (89-64-82-45.dynamic.chello.pl [89.64.82.45]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by v370.home.net.pl (Postfix) with ESMTPSA id 9E3C7669C07; Mon, 12 Jul 2021 19:06:47 +0200 (CEST) From: "Rafael J. Wysocki" To: Linux PCI Cc: Linux ACPI , Linux PM , LKML , Mika Westerberg , Bjorn Helgaas , Kai-Heng Feng , Utkarsh H Patel , Koba Ko Subject: [RFT][PATCH] PCI: PM: Add special case handling for PCIe device wakeup Date: Mon, 12 Jul 2021 19:06:47 +0200 Message-ID: <5475468.DvuYhMxLoT@kreacher> MIME-Version: 1.0 Content-Transfer-Encoding: 7Bit Content-Type: text/plain; charset="UTF-8" X-CLIENT-IP: 89.64.82.45 X-CLIENT-HOSTNAME: 89-64-82-45.dynamic.chello.pl X-VADE-SPAMSTATE: clean X-VADE-SPAMCAUSE: gggruggvucftvghtrhhoucdtuddrgedvtddruddvgddutdeiucetufdoteggodetrfdotffvucfrrhhofhhilhgvmecujffqoffgrffnpdggtffipffknecuuegrihhlohhuthemucduhedtnecusecvtfgvtghiphhivghnthhsucdlqddutddtmdenucfjughrpefhvffufffkggfgtgesthfuredttddtjeenucfhrhhomhepfdftrghfrggvlhculfdrucghhihsohgtkhhifdcuoehrjhifsehrjhifhihsohgtkhhirdhnvghtqeenucggtffrrghtthgvrhhnpedvvefgteeuteehkeduuedvudetleevffdtffdtjeejueekffetieekgfeigfehudenucffohhmrghinhepkhgvrhhnvghlrdhorhhgnecukfhppeekledrieegrdekvddrgeehnecuvehluhhsthgvrhfuihiivgeptdenucfrrghrrghmpehinhgvthepkeelrdeigedrkedvrdeghedphhgvlhhopehkrhgvrggthhgvrhdrlhhotggrlhhnvghtpdhmrghilhhfrhhomhepfdftrghfrggvlhculfdrucghhihsohgtkhhifdcuoehrjhifsehrjhifhihsohgtkhhirdhnvghtqedprhgtphhtthhopehlihhnuhigqdhptghisehvghgvrhdrkhgvrhhnvghlrdhorhhgpdhrtghpthhtoheplhhinhhugidqrggtphhisehvghgvrhdrkhgvrhhnvghlrdhorhhgpdhrtghpthhtoheplhhinhhugidqphhmsehvghgvrhdrkhgvrhhnvghlrdhorhhgpdhrtghpthhtoheplhhinhhugidqkhgvrhhnvghlsehvghgvrhdrkhgvrhhnvghlrdhorhhgpdhrtghp thhtohepmhhikhgrrdifvghsthgvrhgsvghrgheslhhinhhugidrihhnthgvlhdrtghomhdprhgtphhtthhopehhvghlghgrrghssehkvghrnhgvlhdrohhrghdprhgtphhtthhopehkrghirdhhvghnghdrfhgvnhhgsegtrghnohhnihgtrghlrdgtohhmpdhrtghpthhtohepuhhtkhgrrhhshhdrhhdrphgrthgvlhesihhnthgvlhdrtghomhdprhgtphhtthhopehkohgsrgdrkhhosegtrghnohhnihgtrghlrdgtohhm X-DCC--Metrics: v370.home.net.pl 1024; Body=9 Fuz1=9 Fuz2=9 Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: Rafael J. Wysocki Some PCIe devices only support PME (Power Management Event) from D3cold. One example is the ASMedia xHCI controller: 11:00.0 USB controller: ASMedia Technology Inc. ASM1042A USB 3.0 Host Controller (prog-if 30 [XHCI]) ... Capabilities: [78] Power Management version 3 Flags: PMEClk- DSI- D1- D2- AuxCurrent=55mA PME(D0-,D1-,D2-,D3hot-,D3cold+) Status: D0 NoSoftRst+ PME-Enable- DSel=0 DScale=0 PME- In those cases, if the device is expected to generate wakeup events from its final power state, pci_target_state() returns D0, which prevents the PCIe port the device is connected to from entering any low-power states too. However, if the device were allowed to go into D3hot, its parent PCIe port would also be able to go into D3 and if it goes into D3cold, it would cause the endpoint device to end up in D3cold too (as per the PCI PM spec v1.2, Table 6-1), in which case the endpoint would be able to signal PME. This means that the system could be put into a lower-power configuration without sacrificing the the given device's ability to generate PME. In order to avoid missing that opportunity, extend pci_pme_capable() to check the device's parent in the special case when the target state is D3hot and the device can only signal PME from D3cold and update pci_target_state() to return the current target state if pci_pme_capable() returns 'true' for it. Link: https://lore.kernel.org/linux-pm/20210617123653.58640-1-mika.westerberg@linux.intel.com Reported-by: Mika Westerberg Reported-by: Utkarsh H Patel Reported-by: Koba Ko Signed-off-by: Rafael J. Wysocki --- Hi, Anyone who can reproduce the problem described in the changelog, please test the patch and let me know the result. Thanks! --- drivers/pci/pci.c | 38 ++++++++++++++++++++++++++------------ 1 file changed, 26 insertions(+), 12 deletions(-) Index: linux-pm/drivers/pci/pci.c =================================================================== --- linux-pm.orig/drivers/pci/pci.c +++ linux-pm/drivers/pci/pci.c @@ -2298,10 +2298,29 @@ void pci_pme_wakeup_bus(struct pci_bus * */ bool pci_pme_capable(struct pci_dev *dev, pci_power_t state) { + struct pci_dev *parent; + if (!dev->pm_cap) return false; - return !!(dev->pme_support & (1 << state)); + if (dev->pme_support & (1 << state)) + return true; + + /* + * Special case: The target state is D3hot and the device only supports + * signaling PME from D3cold, but it is a PCIe device whose parent port + * can go into D3cold. In that case, if the device is allowed to go + * into D3hot, the parent port can go into D3cold which will cause the + * device to end up in D3cold, so it will be able to signal PME from the + * final state. + */ + if (state != PCI_D3hot || !(dev->pme_support & (1 << PCI_D3cold))) + return false; + + parent = dev->bus->self; + return pci_bridge_d3_possible(parent) && + platform_pci_power_manageable(parent) && + platform_pci_choose_state(parent) == PCI_D3cold; } EXPORT_SYMBOL(pci_pme_capable); @@ -2595,17 +2614,12 @@ static pci_power_t pci_target_state(stru if (dev->current_state == PCI_D3cold) target_state = PCI_D3cold; - if (wakeup) { - /* - * Find the deepest state from which the device can generate - * PME#. - */ - if (dev->pme_support) { - while (target_state - && !(dev->pme_support & (1 << target_state))) - target_state--; - } - } + if (!wakeup || !dev->pme_support || pci_pme_capable(dev, target_state)) + return target_state; + + /* Find the deepest state from which the device can generate PME#. */ + while (target_state && !(dev->pme_support & (1 << target_state))) + target_state--; return target_state; }