Skip to content

Commit 9c56661

Browse files
committed
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
2 parents 0f4b928 + e543b10 commit 9c56661

File tree

6 files changed

+197
-52
lines changed

6 files changed

+197
-52
lines changed

Documentation/admin-guide/acpi/ssdt-overlays.rst

Lines changed: 25 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -30,22 +30,21 @@ following ASL code can be used::
3030
{
3131
Device (STAC)
3232
{
33-
Name (_ADR, Zero)
3433
Name (_HID, "BMA222E")
34+
Name (RBUF, ResourceTemplate ()
35+
{
36+
I2cSerialBus (0x0018, ControllerInitiated, 0x00061A80,
37+
AddressingMode7Bit, "\\_SB.I2C6", 0x00,
38+
ResourceConsumer, ,)
39+
GpioInt (Edge, ActiveHigh, Exclusive, PullDown, 0x0000,
40+
"\\_SB.GPO2", 0x00, ResourceConsumer, , )
41+
{ // Pin list
42+
0
43+
}
44+
})
3545

3646
Method (_CRS, 0, Serialized)
3747
{
38-
Name (RBUF, ResourceTemplate ()
39-
{
40-
I2cSerialBus (0x0018, ControllerInitiated, 0x00061A80,
41-
AddressingMode7Bit, "\\_SB.I2C6", 0x00,
42-
ResourceConsumer, ,)
43-
GpioInt (Edge, ActiveHigh, Exclusive, PullDown, 0x0000,
44-
"\\_SB.GPO2", 0x00, ResourceConsumer, , )
45-
{ // Pin list
46-
0
47-
}
48-
})
4948
Return (RBUF)
5049
}
5150
}
@@ -75,7 +74,7 @@ This option allows loading of user defined SSDTs from initrd and it is useful
7574
when the system does not support EFI or when there is not enough EFI storage.
7675

7776
It works in a similar way with initrd based ACPI tables override/upgrade: SSDT
78-
aml code must be placed in the first, uncompressed, initrd under the
77+
AML code must be placed in the first, uncompressed, initrd under the
7978
"kernel/firmware/acpi" path. Multiple files can be used and this will translate
8079
in loading multiple tables. Only SSDT and OEM tables are allowed. See
8180
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
103102
allows a persistent, OS independent way of storing the user defined SSDTs. There
104103
is also work underway to implement EFI support for loading user defined SSDTs
105104
and using this method will make it easier to convert to the EFI loading
106-
mechanism when that will arrive.
105+
mechanism when that will arrive. To enable it, the
106+
CONFIG_EFI_CUSTOM_SSDT_OVERLAYS shoyld be chosen to y.
107107

108-
In order to load SSDTs from an EFI variable the efivar_ssdt kernel command line
109-
parameter can be used. The argument for the option is the variable name to
110-
use. If there are multiple variables with the same name but with different
111-
vendor GUIDs, all of them will be loaded.
108+
In order to load SSDTs from an EFI variable the ``"efivar_ssdt=..."`` kernel
109+
command line parameter can be used (the name has a limitation of 16 characters).
110+
The argument for the option is the variable name to use. If there are multiple
111+
variables with the same name but with different vendor GUIDs, all of them will
112+
be loaded.
112113

113114
In order to store the AML code in an EFI variable the efivarfs filesystem can be
114115
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::
127128

128129
#!/bin/sh -e
129130

130-
while ! [ -z "$1" ]; do
131+
while [ -n "$1" ]; do
131132
case "$1" in
132133
"-f") filename="$2"; shift;;
133134
"-g") guid="$2"; shift;;
@@ -167,14 +168,14 @@ variable with the content from a given file::
167168
Loading ACPI SSDTs from configfs
168169
================================
169170

170-
This option allows loading of user defined SSDTs from userspace via the configfs
171+
This option allows loading of user defined SSDTs from user space via the configfs
171172
interface. The CONFIG_ACPI_CONFIGFS option must be select and configfs must be
172173
mounted. In the following examples, we assume that configfs has been mounted in
173-
/config.
174+
/sys/kernel/config.
174175

175-
New tables can be loading by creating new directories in /config/acpi/table/ and
176-
writing the SSDT aml code in the aml attribute::
176+
New tables can be loading by creating new directories in /sys/kernel/config/acpi/table
177+
and writing the SSDT AML code in the aml attribute::
177178

178-
cd /config/acpi/table
179+
cd /sys/kernel/config/acpi/table
179180
mkdir my_ssdt
180181
cat ~/ssdt.aml > my_ssdt/aml

drivers/acpi/x86/s2idle.c

Lines changed: 39 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -449,25 +449,30 @@ int acpi_s2idle_prepare_late(void)
449449
if (pm_debug_messages_on)
450450
lpi_check_constraints();
451451

452-
if (lps0_dsm_func_mask_microsoft > 0) {
452+
/* Screen off */
453+
if (lps0_dsm_func_mask > 0)
454+
acpi_sleep_run_lps0_dsm(acpi_s2idle_vendor_amd() ?
455+
ACPI_LPS0_SCREEN_OFF_AMD :
456+
ACPI_LPS0_SCREEN_OFF,
457+
lps0_dsm_func_mask, lps0_dsm_guid);
458+
459+
if (lps0_dsm_func_mask_microsoft > 0)
453460
acpi_sleep_run_lps0_dsm(ACPI_LPS0_SCREEN_OFF,
454461
lps0_dsm_func_mask_microsoft, lps0_dsm_guid_microsoft);
455-
acpi_sleep_run_lps0_dsm(ACPI_LPS0_MS_ENTRY,
456-
lps0_dsm_func_mask_microsoft, lps0_dsm_guid_microsoft);
462+
463+
/* LPS0 entry */
464+
if (lps0_dsm_func_mask > 0)
465+
acpi_sleep_run_lps0_dsm(acpi_s2idle_vendor_amd() ?
466+
ACPI_LPS0_ENTRY_AMD :
467+
ACPI_LPS0_ENTRY,
468+
lps0_dsm_func_mask, lps0_dsm_guid);
469+
if (lps0_dsm_func_mask_microsoft > 0) {
457470
acpi_sleep_run_lps0_dsm(ACPI_LPS0_ENTRY,
458471
lps0_dsm_func_mask_microsoft, lps0_dsm_guid_microsoft);
459-
} else if (acpi_s2idle_vendor_amd()) {
460-
acpi_sleep_run_lps0_dsm(ACPI_LPS0_SCREEN_OFF_AMD,
461-
lps0_dsm_func_mask, lps0_dsm_guid);
462-
acpi_sleep_run_lps0_dsm(ACPI_LPS0_ENTRY_AMD,
463-
lps0_dsm_func_mask, lps0_dsm_guid);
464-
} else {
465-
acpi_sleep_run_lps0_dsm(ACPI_LPS0_SCREEN_OFF,
466-
lps0_dsm_func_mask, lps0_dsm_guid);
467-
acpi_sleep_run_lps0_dsm(ACPI_LPS0_ENTRY,
468-
lps0_dsm_func_mask, lps0_dsm_guid);
472+
/* modern standby entry */
473+
acpi_sleep_run_lps0_dsm(ACPI_LPS0_MS_ENTRY,
474+
lps0_dsm_func_mask_microsoft, lps0_dsm_guid_microsoft);
469475
}
470-
471476
return 0;
472477
}
473478

@@ -476,24 +481,30 @@ void acpi_s2idle_restore_early(void)
476481
if (!lps0_device_handle || sleep_no_lps0)
477482
return;
478483

479-
if (lps0_dsm_func_mask_microsoft > 0) {
480-
acpi_sleep_run_lps0_dsm(ACPI_LPS0_EXIT,
481-
lps0_dsm_func_mask_microsoft, lps0_dsm_guid_microsoft);
484+
/* Modern standby exit */
485+
if (lps0_dsm_func_mask_microsoft > 0)
482486
acpi_sleep_run_lps0_dsm(ACPI_LPS0_MS_EXIT,
483487
lps0_dsm_func_mask_microsoft, lps0_dsm_guid_microsoft);
484-
acpi_sleep_run_lps0_dsm(ACPI_LPS0_SCREEN_ON,
485-
lps0_dsm_func_mask_microsoft, lps0_dsm_guid_microsoft);
486-
} else if (acpi_s2idle_vendor_amd()) {
487-
acpi_sleep_run_lps0_dsm(ACPI_LPS0_EXIT_AMD,
488-
lps0_dsm_func_mask, lps0_dsm_guid);
489-
acpi_sleep_run_lps0_dsm(ACPI_LPS0_SCREEN_ON_AMD,
490-
lps0_dsm_func_mask, lps0_dsm_guid);
491-
} else {
488+
489+
/* LPS0 exit */
490+
if (lps0_dsm_func_mask > 0)
491+
acpi_sleep_run_lps0_dsm(acpi_s2idle_vendor_amd() ?
492+
ACPI_LPS0_EXIT_AMD :
493+
ACPI_LPS0_EXIT,
494+
lps0_dsm_func_mask, lps0_dsm_guid);
495+
if (lps0_dsm_func_mask_microsoft > 0)
492496
acpi_sleep_run_lps0_dsm(ACPI_LPS0_EXIT,
493-
lps0_dsm_func_mask, lps0_dsm_guid);
497+
lps0_dsm_func_mask_microsoft, lps0_dsm_guid_microsoft);
498+
499+
/* Screen on */
500+
if (lps0_dsm_func_mask_microsoft > 0)
494501
acpi_sleep_run_lps0_dsm(ACPI_LPS0_SCREEN_ON,
495-
lps0_dsm_func_mask, lps0_dsm_guid);
496-
}
502+
lps0_dsm_func_mask_microsoft, lps0_dsm_guid_microsoft);
503+
if (lps0_dsm_func_mask > 0)
504+
acpi_sleep_run_lps0_dsm(acpi_s2idle_vendor_amd() ?
505+
ACPI_LPS0_SCREEN_ON_AMD :
506+
ACPI_LPS0_SCREEN_ON,
507+
lps0_dsm_func_mask, lps0_dsm_guid);
497508
}
498509

499510
static const struct platform_s2idle_ops acpi_s2idle_ops_lps0 = {

drivers/pci/controller/vmd.c

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include <linux/module.h>
1212
#include <linux/msi.h>
1313
#include <linux/pci.h>
14+
#include <linux/pci-acpi.h>
1415
#include <linux/pci-ecam.h>
1516
#include <linux/srcu.h>
1617
#include <linux/rculist.h>
@@ -447,6 +448,56 @@ static struct pci_ops vmd_ops = {
447448
.write = vmd_pci_write,
448449
};
449450

451+
#ifdef CONFIG_ACPI
452+
static struct acpi_device *vmd_acpi_find_companion(struct pci_dev *pci_dev)
453+
{
454+
struct pci_host_bridge *bridge;
455+
u32 busnr, addr;
456+
457+
if (pci_dev->bus->ops != &vmd_ops)
458+
return NULL;
459+
460+
bridge = pci_find_host_bridge(pci_dev->bus);
461+
busnr = pci_dev->bus->number - bridge->bus->number;
462+
/*
463+
* The address computation below is only applicable to relative bus
464+
* numbers below 32.
465+
*/
466+
if (busnr > 31)
467+
return NULL;
468+
469+
addr = (busnr << 24) | ((u32)pci_dev->devfn << 16) | 0x8000FFFFU;
470+
471+
dev_dbg(&pci_dev->dev, "Looking for ACPI companion (address 0x%x)\n",
472+
addr);
473+
474+
return acpi_find_child_device(ACPI_COMPANION(bridge->dev.parent), addr,
475+
false);
476+
}
477+
478+
static bool hook_installed;
479+
480+
static void vmd_acpi_begin(void)
481+
{
482+
if (pci_acpi_set_companion_lookup_hook(vmd_acpi_find_companion))
483+
return;
484+
485+
hook_installed = true;
486+
}
487+
488+
static void vmd_acpi_end(void)
489+
{
490+
if (!hook_installed)
491+
return;
492+
493+
pci_acpi_clear_companion_lookup_hook();
494+
hook_installed = false;
495+
}
496+
#else
497+
static inline void vmd_acpi_begin(void) { }
498+
static inline void vmd_acpi_end(void) { }
499+
#endif /* CONFIG_ACPI */
500+
450501
static void vmd_attach_resources(struct vmd_dev *vmd)
451502
{
452503
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)
747798
if (vmd->irq_domain)
748799
dev_set_msi_domain(&vmd->bus->dev, vmd->irq_domain);
749800

801+
vmd_acpi_begin();
802+
750803
pci_scan_child_bus(vmd->bus);
751804
pci_assign_unassigned_bus_resources(vmd->bus);
752805

@@ -760,6 +813,8 @@ static int vmd_enable_domain(struct vmd_dev *vmd, unsigned long features)
760813

761814
pci_bus_add_devices(vmd->bus);
762815

816+
vmd_acpi_end();
817+
763818
WARN(sysfs_create_link(&vmd->dev->dev.kobj, &vmd->bus->dev.kobj,
764819
"domain"), "Can't create symlink to domain\n");
765820
return 0;

drivers/pci/host-bridge.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ struct pci_host_bridge *pci_find_host_bridge(struct pci_bus *bus)
2323

2424
return to_pci_host_bridge(root_bus->bridge);
2525
}
26+
EXPORT_SYMBOL_GPL(pci_find_host_bridge);
2627

2728
struct device *pci_get_host_bridge_device(struct pci_dev *dev)
2829
{

drivers/pci/pci-acpi.c

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include <linux/pci-acpi.h>
1818
#include <linux/pm_runtime.h>
1919
#include <linux/pm_qos.h>
20+
#include <linux/rwsem.h>
2021
#include "pci.h"
2122

2223
/*
@@ -1178,13 +1179,86 @@ void acpi_pci_remove_bus(struct pci_bus *bus)
11781179
}
11791180

11801181
/* ACPI bus type */
1182+
1183+
1184+
static DECLARE_RWSEM(pci_acpi_companion_lookup_sem);
1185+
static struct acpi_device *(*pci_acpi_find_companion_hook)(struct pci_dev *);
1186+
1187+
/**
1188+
* pci_acpi_set_companion_lookup_hook - Set ACPI companion lookup callback.
1189+
* @func: ACPI companion lookup callback pointer or NULL.
1190+
*
1191+
* Set a special ACPI companion lookup callback for PCI devices whose companion
1192+
* objects in the ACPI namespace have _ADR with non-standard bus-device-function
1193+
* encodings.
1194+
*
1195+
* Return 0 on success or a negative error code on failure (in which case no
1196+
* changes are made).
1197+
*
1198+
* The caller is responsible for the appropriate ordering of the invocations of
1199+
* this function with respect to the enumeration of the PCI devices needing the
1200+
* callback installed by it.
1201+
*/
1202+
int pci_acpi_set_companion_lookup_hook(struct acpi_device *(*func)(struct pci_dev *))
1203+
{
1204+
int ret;
1205+
1206+
if (!func)
1207+
return -EINVAL;
1208+
1209+
down_write(&pci_acpi_companion_lookup_sem);
1210+
1211+
if (pci_acpi_find_companion_hook) {
1212+
ret = -EBUSY;
1213+
} else {
1214+
pci_acpi_find_companion_hook = func;
1215+
ret = 0;
1216+
}
1217+
1218+
up_write(&pci_acpi_companion_lookup_sem);
1219+
1220+
return ret;
1221+
}
1222+
EXPORT_SYMBOL_GPL(pci_acpi_set_companion_lookup_hook);
1223+
1224+
/**
1225+
* pci_acpi_clear_companion_lookup_hook - Clear ACPI companion lookup callback.
1226+
*
1227+
* Clear the special ACPI companion lookup callback previously set by
1228+
* pci_acpi_set_companion_lookup_hook(). Block until the last running instance
1229+
* of the callback returns before clearing it.
1230+
*
1231+
* The caller is responsible for the appropriate ordering of the invocations of
1232+
* this function with respect to the enumeration of the PCI devices needing the
1233+
* callback cleared by it.
1234+
*/
1235+
void pci_acpi_clear_companion_lookup_hook(void)
1236+
{
1237+
down_write(&pci_acpi_companion_lookup_sem);
1238+
1239+
pci_acpi_find_companion_hook = NULL;
1240+
1241+
up_write(&pci_acpi_companion_lookup_sem);
1242+
}
1243+
EXPORT_SYMBOL_GPL(pci_acpi_clear_companion_lookup_hook);
1244+
11811245
static struct acpi_device *acpi_pci_find_companion(struct device *dev)
11821246
{
11831247
struct pci_dev *pci_dev = to_pci_dev(dev);
11841248
struct acpi_device *adev;
11851249
bool check_children;
11861250
u64 addr;
11871251

1252+
down_read(&pci_acpi_companion_lookup_sem);
1253+
1254+
adev = pci_acpi_find_companion_hook ?
1255+
pci_acpi_find_companion_hook(pci_dev) : NULL;
1256+
1257+
up_read(&pci_acpi_companion_lookup_sem);
1258+
1259+
if (adev)
1260+
return adev;
1261+
11881262
check_children = pci_is_bridge(pci_dev);
11891263
/* Please ref to ACPI spec for the syntax of _ADR */
11901264
addr = (PCI_SLOT(pci_dev->devfn) << 16) | PCI_FUNC(pci_dev->devfn);

include/linux/pci-acpi.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,9 @@ static inline void pci_acpi_add_edr_notifier(struct pci_dev *pdev) { }
122122
static inline void pci_acpi_remove_edr_notifier(struct pci_dev *pdev) { }
123123
#endif /* CONFIG_PCIE_EDR */
124124

125+
int pci_acpi_set_companion_lookup_hook(struct acpi_device *(*func)(struct pci_dev *));
126+
void pci_acpi_clear_companion_lookup_hook(void);
127+
125128
#else /* CONFIG_ACPI */
126129
static inline void acpi_pci_add_bus(struct pci_bus *bus) { }
127130
static inline void acpi_pci_remove_bus(struct pci_bus *bus) { }

0 commit comments

Comments
 (0)