Commit 9c566611 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'acpi-5.15-rc1-2' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm

Pull more ACPI updates from Rafael Wysocki:
 "These add ACPI support to the PCI VMD driver, improve suspend-to-idle
  support for AMD platforms and update documentation.

  Specifics:

   - Add ACPI support to the PCI VMD driver (Rafael Wysocki)

   - Rearrange suspend-to-idle support code to reflect the platform
     firmware expectations on some AMD platforms (Mario Limonciello)

   - Make SSDT overlays documentation follow the code documented by it
     more closely (Andy Shevchenko)"

* tag 'acpi-5.15-rc1-2' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm:
  ACPI: PM: s2idle: Run both AMD and Microsoft methods if both are supported
  Documentation: ACPI: Align the SSDT overlays file with the code
  PCI: VMD: ACPI: Make ACPI companion lookup work for VMD bus
parents 0f4b9289 e543b10c
......@@ -30,11 +30,7 @@ following ASL code can be used::
{
Device (STAC)
{
Name (_ADR, Zero)
Name (_HID, "BMA222E")
Method (_CRS, 0, Serialized)
{
Name (RBUF, ResourceTemplate ()
{
I2cSerialBus (0x0018, ControllerInitiated, 0x00061A80,
......@@ -46,6 +42,9 @@ following ASL code can be used::
0
}
})
Method (_CRS, 0, Serialized)
{
Return (RBUF)
}
}
......@@ -75,7 +74,7 @@ This option allows loading of user defined SSDTs from initrd and it is useful
when the system does not support EFI or when there is not enough EFI storage.
It works in a similar way with initrd based ACPI tables override/upgrade: SSDT
aml code must be placed in the first, uncompressed, initrd under the
AML code must be placed in the first, uncompressed, initrd under the
"kernel/firmware/acpi" path. Multiple files can be used and this will translate
in loading multiple tables. Only SSDT and OEM tables are allowed. See
initrd_table_override.txt for more details.
......@@ -103,12 +102,14 @@ This is the preferred method, when EFI is supported on the platform, because it
allows a persistent, OS independent way of storing the user defined SSDTs. There
is also work underway to implement EFI support for loading user defined SSDTs
and using this method will make it easier to convert to the EFI loading
mechanism when that will arrive.
mechanism when that will arrive. To enable it, the
CONFIG_EFI_CUSTOM_SSDT_OVERLAYS shoyld be chosen to y.
In order to load SSDTs from an EFI variable the efivar_ssdt kernel command line
parameter can be used. The argument for the option is the variable name to
use. If there are multiple variables with the same name but with different
vendor GUIDs, all of them will be loaded.
In order to load SSDTs from an EFI variable the ``"efivar_ssdt=..."`` kernel
command line parameter can be used (the name has a limitation of 16 characters).
The argument for the option is the variable name to use. If there are multiple
variables with the same name but with different vendor GUIDs, all of them will
be loaded.
In order to store the AML code in an EFI variable the efivarfs filesystem can be
used. It is enabled and mounted by default in /sys/firmware/efi/efivars in all
......@@ -127,7 +128,7 @@ variable with the content from a given file::
#!/bin/sh -e
while ! [ -z "$1" ]; do
while [ -n "$1" ]; do
case "$1" in
"-f") filename="$2"; shift;;
"-g") guid="$2"; shift;;
......@@ -167,14 +168,14 @@ variable with the content from a given file::
Loading ACPI SSDTs from configfs
================================
This option allows loading of user defined SSDTs from userspace via the configfs
This option allows loading of user defined SSDTs from user space via the configfs
interface. The CONFIG_ACPI_CONFIGFS option must be select and configfs must be
mounted. In the following examples, we assume that configfs has been mounted in
/config.
/sys/kernel/config.
New tables can be loading by creating new directories in /config/acpi/table/ and
writing the SSDT aml code in the aml attribute::
New tables can be loading by creating new directories in /sys/kernel/config/acpi/table
and writing the SSDT AML code in the aml attribute::
cd /config/acpi/table
cd /sys/kernel/config/acpi/table
mkdir my_ssdt
cat ~/ssdt.aml > my_ssdt/aml
......@@ -449,25 +449,30 @@ int acpi_s2idle_prepare_late(void)
if (pm_debug_messages_on)
lpi_check_constraints();
if (lps0_dsm_func_mask_microsoft > 0) {
acpi_sleep_run_lps0_dsm(ACPI_LPS0_SCREEN_OFF,
lps0_dsm_func_mask_microsoft, lps0_dsm_guid_microsoft);
acpi_sleep_run_lps0_dsm(ACPI_LPS0_MS_ENTRY,
lps0_dsm_func_mask_microsoft, lps0_dsm_guid_microsoft);
acpi_sleep_run_lps0_dsm(ACPI_LPS0_ENTRY,
lps0_dsm_func_mask_microsoft, lps0_dsm_guid_microsoft);
} else if (acpi_s2idle_vendor_amd()) {
acpi_sleep_run_lps0_dsm(ACPI_LPS0_SCREEN_OFF_AMD,
lps0_dsm_func_mask, lps0_dsm_guid);
acpi_sleep_run_lps0_dsm(ACPI_LPS0_ENTRY_AMD,
/* Screen off */
if (lps0_dsm_func_mask > 0)
acpi_sleep_run_lps0_dsm(acpi_s2idle_vendor_amd() ?
ACPI_LPS0_SCREEN_OFF_AMD :
ACPI_LPS0_SCREEN_OFF,
lps0_dsm_func_mask, lps0_dsm_guid);
} else {
if (lps0_dsm_func_mask_microsoft > 0)
acpi_sleep_run_lps0_dsm(ACPI_LPS0_SCREEN_OFF,
lps0_dsm_func_mask_microsoft, lps0_dsm_guid_microsoft);
/* LPS0 entry */
if (lps0_dsm_func_mask > 0)
acpi_sleep_run_lps0_dsm(acpi_s2idle_vendor_amd() ?
ACPI_LPS0_ENTRY_AMD :
ACPI_LPS0_ENTRY,
lps0_dsm_func_mask, lps0_dsm_guid);
if (lps0_dsm_func_mask_microsoft > 0) {
acpi_sleep_run_lps0_dsm(ACPI_LPS0_ENTRY,
lps0_dsm_func_mask, lps0_dsm_guid);
lps0_dsm_func_mask_microsoft, lps0_dsm_guid_microsoft);
/* modern standby entry */
acpi_sleep_run_lps0_dsm(ACPI_LPS0_MS_ENTRY,
lps0_dsm_func_mask_microsoft, lps0_dsm_guid_microsoft);
}
return 0;
}
......@@ -476,24 +481,30 @@ void acpi_s2idle_restore_early(void)
if (!lps0_device_handle || sleep_no_lps0)
return;
if (lps0_dsm_func_mask_microsoft > 0) {
acpi_sleep_run_lps0_dsm(ACPI_LPS0_EXIT,
lps0_dsm_func_mask_microsoft, lps0_dsm_guid_microsoft);
/* Modern standby exit */
if (lps0_dsm_func_mask_microsoft > 0)
acpi_sleep_run_lps0_dsm(ACPI_LPS0_MS_EXIT,
lps0_dsm_func_mask_microsoft, lps0_dsm_guid_microsoft);
acpi_sleep_run_lps0_dsm(ACPI_LPS0_SCREEN_ON,
lps0_dsm_func_mask_microsoft, lps0_dsm_guid_microsoft);
} else if (acpi_s2idle_vendor_amd()) {
acpi_sleep_run_lps0_dsm(ACPI_LPS0_EXIT_AMD,
lps0_dsm_func_mask, lps0_dsm_guid);
acpi_sleep_run_lps0_dsm(ACPI_LPS0_SCREEN_ON_AMD,
/* LPS0 exit */
if (lps0_dsm_func_mask > 0)
acpi_sleep_run_lps0_dsm(acpi_s2idle_vendor_amd() ?
ACPI_LPS0_EXIT_AMD :
ACPI_LPS0_EXIT,
lps0_dsm_func_mask, lps0_dsm_guid);
} else {
if (lps0_dsm_func_mask_microsoft > 0)
acpi_sleep_run_lps0_dsm(ACPI_LPS0_EXIT,
lps0_dsm_func_mask, lps0_dsm_guid);
lps0_dsm_func_mask_microsoft, lps0_dsm_guid_microsoft);
/* Screen on */
if (lps0_dsm_func_mask_microsoft > 0)
acpi_sleep_run_lps0_dsm(ACPI_LPS0_SCREEN_ON,
lps0_dsm_func_mask_microsoft, lps0_dsm_guid_microsoft);
if (lps0_dsm_func_mask > 0)
acpi_sleep_run_lps0_dsm(acpi_s2idle_vendor_amd() ?
ACPI_LPS0_SCREEN_ON_AMD :
ACPI_LPS0_SCREEN_ON,
lps0_dsm_func_mask, lps0_dsm_guid);
}
}
static const struct platform_s2idle_ops acpi_s2idle_ops_lps0 = {
......
......@@ -11,6 +11,7 @@
#include <linux/module.h>
#include <linux/msi.h>
#include <linux/pci.h>
#include <linux/pci-acpi.h>
#include <linux/pci-ecam.h>
#include <linux/srcu.h>
#include <linux/rculist.h>
......@@ -447,6 +448,56 @@ 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;
/*
* The address computation below is only applicable to relative bus
* numbers below 32.
*/
if (busnr > 31)
return NULL;
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 +798,8 @@ static int vmd_enable_domain(struct vmd_dev *vmd, unsigned long features)
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 +813,8 @@ static int vmd_enable_domain(struct vmd_dev *vmd, unsigned long features)
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;
......
......@@ -23,6 +23,7 @@ struct pci_host_bridge *pci_find_host_bridge(struct pci_bus *bus)
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)
{
......
......@@ -17,6 +17,7 @@
#include <linux/pci-acpi.h>
#include <linux/pm_runtime.h>
#include <linux/pm_qos.h>
#include <linux/rwsem.h>
#include "pci.h"
/*
......@@ -1178,6 +1179,69 @@ void acpi_pci_remove_bus(struct pci_bus *bus)
}
/* ACPI bus type */
static DECLARE_RWSEM(pci_acpi_companion_lookup_sem);
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;
down_write(&pci_acpi_companion_lookup_sem);
if (pci_acpi_find_companion_hook) {
ret = -EBUSY;
} else {
pci_acpi_find_companion_hook = func;
ret = 0;
}
up_write(&pci_acpi_companion_lookup_sem);
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)
{
down_write(&pci_acpi_companion_lookup_sem);
pci_acpi_find_companion_hook = NULL;
up_write(&pci_acpi_companion_lookup_sem);
}
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);
......@@ -1185,6 +1249,16 @@ static struct acpi_device *acpi_pci_find_companion(struct device *dev)
bool check_children;
u64 addr;
down_read(&pci_acpi_companion_lookup_sem);
adev = pci_acpi_find_companion_hook ?
pci_acpi_find_companion_hook(pci_dev) : NULL;
up_read(&pci_acpi_companion_lookup_sem);
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);
......
......@@ -122,6 +122,9 @@ static inline void pci_acpi_add_edr_notifier(struct pci_dev *pdev) { }
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) { }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment