Received: by 2002:a05:6a10:1d13:0:0:0:0 with SMTP id pp19csp1598579pxb; Fri, 20 Aug 2021 09:13:49 -0700 (PDT) X-Google-Smtp-Source: ABdhPJwRDUYK14ik5tsbtAow6PQdt/G1TocEJLv2UCxY7O5uF6tVxg1DGzWGJZjdu7tiGAu/BtVf X-Received: by 2002:a5d:9eda:: with SMTP id a26mr16733725ioe.166.1629476029415; Fri, 20 Aug 2021 09:13:49 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1629476029; cv=none; d=google.com; s=arc-20160816; b=J9XCj2qAdzeyAXa/yezCOF/lLh9Ok6N44yb6D4fIyFwJesEovlhMDSzzqhq9AtvZOY PcH1a1aqO+dC8exivmrFSl+gny4maorfXun9hjER5wJDak3TL1oUGf3x2MLr4V4YVdWl s7cjT2BHKl/p0ki+rIkb31GNteE4zdFfAO51vgysSsSbLEhV3xYhBKJ0slFd+1rEEd4H GkUhOcOZj2zwVwRgovZw6TwkJCRq93fj1A7u9BJr+mTgzbyuR3jYl8NTDXEIIsP/dI/A N8Z91cNJZeqQdUGWa57v2meaGQLCjO5JEWCVCxlFSM5N9Ui89I1vt9iVWITsgu4fcjEH i28Q== 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=Zyl/qgUx8j4VHohs1gIQrFPlo8ObIlbRv3CRUIyyfJs=; b=HLErL5yPR3wOgwfbY72mU+35YaURhREqI3CKLl4cFlqmsUdTJvuHqei50daxuBLEKL 5u/IcalXR7d+RddJl+og2A5kYq7LyR4XmrLq+3IrOXJfNnwp5hvCTcg1c4aUD0M+Ien4 Q3NsFxOXPxR4p8sI8diOfKplVTGh3z6UxXIVa0yMZhMWqG5abDiYVjg5NcYwVbcllgKh KXHI/l/RVqiOQgnGDjzk+n1cFswyqT2+ciEHqtmdGz8p8MjMyERC3fKbJ3n9Nn0oNrJF wbzmM0SFOxvbpbu2AOcF2165YQaO2gGVstCGY+w2Fh9zoT7m04OIM9wNv9Mo00WX6aUh EOYg== 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 i5si3488960jam.97.2021.08.20.09.13.36; Fri, 20 Aug 2021 09:13: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 S230052AbhHTQNY (ORCPT + 99 others); Fri, 20 Aug 2021 12:13:24 -0400 Received: from cloudserver094114.home.pl ([79.96.170.134]:58168 "EHLO cloudserver094114.home.pl" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232233AbhHTQNV (ORCPT ); Fri, 20 Aug 2021 12:13:21 -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 3.0.0) id bd9c341d9aad94d5; Fri, 20 Aug 2021 18:12:41 +0200 Received: from kreacher.localnet (unknown [213.134.175.112]) (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 3E08D66A221; Fri, 20 Aug 2021 18:12:40 +0200 (CEST) From: "Rafael J. Wysocki" To: Linux PCI , Jonathan Derrick Cc: Wendy Wang , Linux ACPI , LKML , Mika Westerberg , Bjorn Helgaas , David Box Subject: [PATCH] PCI: VMD: ACPI: Make ACPI companion lookup work for VMD bus Date: Fri, 20 Aug 2021 18:12:39 +0200 Message-ID: <11834551.O9o76ZdvQC@kreacher> MIME-Version: 1.0 Content-Transfer-Encoding: 7Bit Content-Type: text/plain; charset="UTF-8" X-CLIENT-IP: 213.134.175.112 X-CLIENT-HOSTNAME: 213.134.175.112 X-VADE-SPAMSTATE: clean X-VADE-SPAMCAUSE: gggruggvucftvghtrhhoucdtuddrgedvtddrleelgdeliecutefuodetggdotefrodftvfcurfhrohhfihhlvgemucfjqffogffrnfdpggftiffpkfenuceurghilhhouhhtmecuudehtdenucesvcftvggtihhpihgvnhhtshculddquddttddmnecujfgurhephffvufffkfgggfgtsehtufertddttdejnecuhfhrohhmpedftfgrfhgrvghlucflrdcuhgihshhotghkihdfuceorhhjfiesrhhjfiihshhotghkihdrnhgvtheqnecuggftrfgrthhtvghrnhephfegtdffjeehkeegleejveevtdeugfffieeijeduuddtkefgjedvheeujeejtedvnecukfhppedvudefrddufeegrddujeehrdduuddvnecuvehluhhsthgvrhfuihiivgeptdenucfrrghrrghmpehinhgvthepvddufedrudefgedrudejhedrudduvddphhgvlhhopehkrhgvrggthhgvrhdrlhhotggrlhhnvghtpdhmrghilhhfrhhomhepfdftrghfrggvlhculfdrucghhihsohgtkhhifdcuoehrjhifsehrjhifhihsohgtkhhirdhnvghtqedprhgtphhtthhopehlihhnuhigqdhptghisehvghgvrhdrkhgvrhhnvghlrdhorhhgpdhrtghpthhtohepjhhonhgrthhhrghnrdguvghrrhhitghksehinhhtvghlrdgtohhmpdhrtghpthhtohepfigvnhguhidrfigrnhhgsehinhhtvghlrdgtohhmpdhrtghpthhtoheplhhinhhugidqrggtphhisehvghgvrhdrkhgvrhhnvghlrdhorhhgpdhrtghpthhtoheplhhinhhugidqkhgvrhhnvghlsehv ghgvrhdrkhgvrhhnvghlrdhorhhgpdhrtghpthhtohepmhhikhgrrdifvghsthgvrhgsvghrgheslhhinhhugidrihhnthgvlhdrtghomhdprhgtphhtthhopehhvghlghgrrghssehkvghrnhgvlhdrohhrghdprhgtphhtthhopegurghvihgurdgvrdgsohigsehlihhnuhigrdhinhhtvghlrdgtohhm X-DCC--Metrics: v370.home.net.pl 1024; Body=16 Fuz1=16 Fuz2=16 Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: Rafael J. Wysocki On some systems, in order to get to the deepest low-power state of the platform (which may be necessary to save significant enough amounts of energy while suspended to idle. for example), devices on the PCI bus exposed by the VMD driver need to be power-managed via ACPI. However, the layout of the ACPI namespace below the VMD controller device object does not reflect the layout of the PCI bus under the VMD host bridge, so in order to identify the ACPI companion objects for the devices on that bus, it is necessary to use a special _ADR encoding on the ACPI side. In other words, acpi_pci_find_companion() does not work for these devices, so it needs to be amended with a special lookup logic specific to the VMD bus. Address this issue by allowing the VMD driver to temporarily install an ACPI companion lookup hook containing the code matching the devices on the VMD PCI bus with the corresponding objects in the ACPI namespace. Signed-off-by: Rafael J. Wysocki Tested-by: Wendy Wang --- drivers/pci/controller/vmd.c | 48 ++++++++++++++++++++++++++ drivers/pci/host-bridge.c | 1 drivers/pci/pci-acpi.c | 78 +++++++++++++++++++++++++++++++++++++++++++ include/linux/pci-acpi.h | 3 + 4 files changed, 130 insertions(+) Index: linux-pm/drivers/pci/controller/vmd.c =================================================================== --- linux-pm.orig/drivers/pci/controller/vmd.c +++ linux-pm/drivers/pci/controller/vmd.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -447,6 +448,49 @@ static struct pci_ops vmd_ops = { .write = vmd_pci_write, }; +#ifdef CONFIG_ACPI +static struct acpi_device *vmd_acpi_find_companion(struct pci_dev *pci_dev) +{ + struct pci_host_bridge *bridge; + u32 busnr, addr; + + if (pci_dev->bus->ops != &vmd_ops) + return NULL; + + bridge = pci_find_host_bridge(pci_dev->bus); + busnr = pci_dev->bus->number - bridge->bus->number; + addr = (busnr << 24) | ((u32)pci_dev->devfn << 16) | 0x8000FFFFU; + + dev_dbg(&pci_dev->dev, "Looking for ACPI companion (address 0x%x)\n", + addr); + + return acpi_find_child_device(ACPI_COMPANION(bridge->dev.parent), addr, + false); +} + +static bool hook_installed; + +static void vmd_acpi_begin(void) +{ + if (pci_acpi_set_companion_lookup_hook(vmd_acpi_find_companion)) + return; + + hook_installed = true; +} + +static void vmd_acpi_end(void) +{ + if (!hook_installed) + return; + + pci_acpi_clear_companion_lookup_hook(); + hook_installed = false; +} +#else +static inline void vmd_acpi_begin(void) { } +static inline void vmd_acpi_end(void) { } +#endif /* CONFIG_ACPI */ + static void vmd_attach_resources(struct vmd_dev *vmd) { vmd->dev->resource[VMD_MEMBAR1].child = &vmd->resources[1]; @@ -747,6 +791,8 @@ static int vmd_enable_domain(struct vmd_ if (vmd->irq_domain) dev_set_msi_domain(&vmd->bus->dev, vmd->irq_domain); + vmd_acpi_begin(); + pci_scan_child_bus(vmd->bus); pci_assign_unassigned_bus_resources(vmd->bus); @@ -760,6 +806,8 @@ static int vmd_enable_domain(struct vmd_ pci_bus_add_devices(vmd->bus); + vmd_acpi_end(); + WARN(sysfs_create_link(&vmd->dev->dev.kobj, &vmd->bus->dev.kobj, "domain"), "Can't create symlink to domain\n"); return 0; Index: linux-pm/drivers/pci/host-bridge.c =================================================================== --- linux-pm.orig/drivers/pci/host-bridge.c +++ linux-pm/drivers/pci/host-bridge.c @@ -23,6 +23,7 @@ struct pci_host_bridge *pci_find_host_br return to_pci_host_bridge(root_bus->bridge); } +EXPORT_SYMBOL_GPL(pci_find_host_bridge); struct device *pci_get_host_bridge_device(struct pci_dev *dev) { Index: linux-pm/drivers/pci/pci-acpi.c =================================================================== --- linux-pm.orig/drivers/pci/pci-acpi.c +++ linux-pm/drivers/pci/pci-acpi.c @@ -1159,6 +1159,72 @@ void acpi_pci_remove_bus(struct pci_bus } /* ACPI bus type */ + + +DEFINE_STATIC_KEY_FALSE(pci_acpi_companion_lookup_key); +static DEFINE_MUTEX(pci_acpi_companion_lookup_mtx); +static struct acpi_device *(*pci_acpi_find_companion_hook)(struct pci_dev *); + +/** + * pci_acpi_set_companion_lookup_hook - Set ACPI companion lookup callback. + * @func: ACPI companion lookup callback pointer or NULL. + * + * Set a special ACPI companion lookup callback for PCI devices whose companion + * objects in the ACPI namespace have _ADR with non-standard bus-device-function + * encodings. + * + * Return 0 on success or a negative error code on failure (in which case no + * changes are made). + * + * The caller is responsible for the appropriate ordering of the invocations of + * this function with respect to the enumeration of the PCI devices needing the + * callback installed by it. + */ +int pci_acpi_set_companion_lookup_hook(struct acpi_device *(*func)(struct pci_dev *)) +{ + int ret; + + if (!func) + return -EINVAL; + + mutex_lock(&pci_acpi_companion_lookup_mtx); + + if (pci_acpi_find_companion_hook) { + ret = -EBUSY; + } else { + pci_acpi_find_companion_hook = func; + static_branch_enable(&pci_acpi_companion_lookup_key); + ret = 0; + } + + mutex_unlock(&pci_acpi_companion_lookup_mtx); + + return ret; +} +EXPORT_SYMBOL_GPL(pci_acpi_set_companion_lookup_hook); + +/** + * pci_acpi_clear_companion_lookup_hook - Clear ACPI companion lookup callback. + * + * Clear the special ACPI companion lookup callback previously set by + * pci_acpi_set_companion_lookup_hook(). Block until the last running instance + * of the callback returns before clearing it. + * + * The caller is responsible for the appropriate ordering of the invocations of + * this function with respect to the enumeration of the PCI devices needing the + * callback cleared by it. + */ +void pci_acpi_clear_companion_lookup_hook(void) +{ + mutex_lock(&pci_acpi_companion_lookup_mtx); + + pci_acpi_find_companion_hook = NULL; + static_branch_disable(&pci_acpi_companion_lookup_key); + + mutex_unlock(&pci_acpi_companion_lookup_mtx); +} +EXPORT_SYMBOL_GPL(pci_acpi_clear_companion_lookup_hook); + static struct acpi_device *acpi_pci_find_companion(struct device *dev) { struct pci_dev *pci_dev = to_pci_dev(dev); @@ -1166,6 +1232,18 @@ static struct acpi_device *acpi_pci_find bool check_children; u64 addr; + if (static_branch_unlikely(&pci_acpi_companion_lookup_key)) { + mutex_lock(&pci_acpi_companion_lookup_mtx); + + adev = pci_acpi_find_companion_hook ? + pci_acpi_find_companion_hook(pci_dev) : NULL; + + mutex_unlock(&pci_acpi_companion_lookup_mtx); + + if (adev) + return adev; + } + check_children = pci_is_bridge(pci_dev); /* Please ref to ACPI spec for the syntax of _ADR */ addr = (PCI_SLOT(pci_dev->devfn) << 16) | PCI_FUNC(pci_dev->devfn); Index: linux-pm/include/linux/pci-acpi.h =================================================================== --- linux-pm.orig/include/linux/pci-acpi.h +++ linux-pm/include/linux/pci-acpi.h @@ -122,6 +122,9 @@ static inline void pci_acpi_add_edr_noti static inline void pci_acpi_remove_edr_notifier(struct pci_dev *pdev) { } #endif /* CONFIG_PCIE_EDR */ +int pci_acpi_set_companion_lookup_hook(struct acpi_device *(*func)(struct pci_dev *)); +void pci_acpi_clear_companion_lookup_hook(void); + #else /* CONFIG_ACPI */ static inline void acpi_pci_add_bus(struct pci_bus *bus) { } static inline void acpi_pci_remove_bus(struct pci_bus *bus) { }