mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git
synced 2025-01-08 15:04:45 +00:00
More ACPI updates for 5.15-rc1
- 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). -----BEGIN PGP SIGNATURE----- iQJGBAABCAAwFiEE4fcc61cGeeHD/fCwgsRv/nhiVHEFAmE41EgSHHJqd0Byand5 c29ja2kubmV0AAoJEILEb/54YlRxZrgP/iStcM1PdEkzW9KInTbI7MDiQl8Iaem2 4AcbrsQmJxAEfJ+kzUuoArjj+y4T8sf49AA9Akg/q3zwf0oBix8JdtPDEx823oG8 7/0zjPJMigmcmGfGIlnQaSYqE30hatsthqF0iyH9AZjRzM1m9MavAtxrwDOD0Chq m6kMObNorm/C0mjdPy71DAbiPbrcsMTFjw27hXHWnfsQFhZeVAoyhh2aFvk790pG QRxpArI8r3dLb9vORQWo0q4jezPrRU6HzfvULVZEtv5+F8VUAby+qi1oGUSNx6CX OB20Z1MFPSolsJvyRkfE8HEq0x1Es37doBROolhmliaKUQezwKPMZKJGgEYyUaSJ bnWmN2wuE39VB6rIWXIaw6bHX3RwWnUJgoMvTZZIexp4kmmy9nsPB119na2odFVW D06yMPZwx9lCDVWNkIbpcCGHkBWvQSZ+X/tROVOgyutJ2Rgph0PTVxQxVZmTnTWm Pq6Tp8lSeatL16vEY75EX5pXbmKiGDIFrGv28Jxou2Arf31hcagY+rxu6YYORefu NdkC2GD4TlQMGm2Ukfo5D/svFzJ/MQvP75ytVP3Oqi7ZFLkU2RzYOun8oOcZjUk6 76CH5/fmSvV2NbZRCDzhxiDXVhBFPaGm0KFnYYKs1V7AskdhnzOkd03z2bseTC0V XNk0fHL1R38J =8lPe -----END PGP SIGNATURE----- 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
This commit is contained in:
commit
9c566611ac
@ -30,22 +30,21 @@ following ASL code can be used::
|
|||||||
{
|
{
|
||||||
Device (STAC)
|
Device (STAC)
|
||||||
{
|
{
|
||||||
Name (_ADR, Zero)
|
|
||||||
Name (_HID, "BMA222E")
|
Name (_HID, "BMA222E")
|
||||||
|
Name (RBUF, ResourceTemplate ()
|
||||||
|
{
|
||||||
|
I2cSerialBus (0x0018, ControllerInitiated, 0x00061A80,
|
||||||
|
AddressingMode7Bit, "\\_SB.I2C6", 0x00,
|
||||||
|
ResourceConsumer, ,)
|
||||||
|
GpioInt (Edge, ActiveHigh, Exclusive, PullDown, 0x0000,
|
||||||
|
"\\_SB.GPO2", 0x00, ResourceConsumer, , )
|
||||||
|
{ // Pin list
|
||||||
|
0
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
Method (_CRS, 0, Serialized)
|
Method (_CRS, 0, Serialized)
|
||||||
{
|
{
|
||||||
Name (RBUF, ResourceTemplate ()
|
|
||||||
{
|
|
||||||
I2cSerialBus (0x0018, ControllerInitiated, 0x00061A80,
|
|
||||||
AddressingMode7Bit, "\\_SB.I2C6", 0x00,
|
|
||||||
ResourceConsumer, ,)
|
|
||||||
GpioInt (Edge, ActiveHigh, Exclusive, PullDown, 0x0000,
|
|
||||||
"\\_SB.GPO2", 0x00, ResourceConsumer, , )
|
|
||||||
{ // Pin list
|
|
||||||
0
|
|
||||||
}
|
|
||||||
})
|
|
||||||
Return (RBUF)
|
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.
|
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
|
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
|
"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
|
in loading multiple tables. Only SSDT and OEM tables are allowed. See
|
||||||
initrd_table_override.txt for more details.
|
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
|
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
|
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
|
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
|
In order to load SSDTs from an EFI variable the ``"efivar_ssdt=..."`` kernel
|
||||||
parameter can be used. The argument for the option is the variable name to
|
command line parameter can be used (the name has a limitation of 16 characters).
|
||||||
use. If there are multiple variables with the same name but with different
|
The argument for the option is the variable name to use. If there are multiple
|
||||||
vendor GUIDs, all of them will be loaded.
|
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
|
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
|
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
|
#!/bin/sh -e
|
||||||
|
|
||||||
while ! [ -z "$1" ]; do
|
while [ -n "$1" ]; do
|
||||||
case "$1" in
|
case "$1" in
|
||||||
"-f") filename="$2"; shift;;
|
"-f") filename="$2"; shift;;
|
||||||
"-g") guid="$2"; shift;;
|
"-g") guid="$2"; shift;;
|
||||||
@ -167,14 +168,14 @@ variable with the content from a given file::
|
|||||||
Loading ACPI SSDTs from configfs
|
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
|
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
|
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
|
New tables can be loading by creating new directories in /sys/kernel/config/acpi/table
|
||||||
writing the SSDT aml code in the aml attribute::
|
and writing the SSDT AML code in the aml attribute::
|
||||||
|
|
||||||
cd /config/acpi/table
|
cd /sys/kernel/config/acpi/table
|
||||||
mkdir my_ssdt
|
mkdir my_ssdt
|
||||||
cat ~/ssdt.aml > my_ssdt/aml
|
cat ~/ssdt.aml > my_ssdt/aml
|
||||||
|
@ -449,25 +449,30 @@ int acpi_s2idle_prepare_late(void)
|
|||||||
if (pm_debug_messages_on)
|
if (pm_debug_messages_on)
|
||||||
lpi_check_constraints();
|
lpi_check_constraints();
|
||||||
|
|
||||||
if (lps0_dsm_func_mask_microsoft > 0) {
|
/* 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);
|
||||||
|
|
||||||
|
if (lps0_dsm_func_mask_microsoft > 0)
|
||||||
acpi_sleep_run_lps0_dsm(ACPI_LPS0_SCREEN_OFF,
|
acpi_sleep_run_lps0_dsm(ACPI_LPS0_SCREEN_OFF,
|
||||||
lps0_dsm_func_mask_microsoft, lps0_dsm_guid_microsoft);
|
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_microsoft, lps0_dsm_guid_microsoft);
|
||||||
|
/* modern standby entry */
|
||||||
acpi_sleep_run_lps0_dsm(ACPI_LPS0_MS_ENTRY,
|
acpi_sleep_run_lps0_dsm(ACPI_LPS0_MS_ENTRY,
|
||||||
lps0_dsm_func_mask_microsoft, lps0_dsm_guid_microsoft);
|
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,
|
|
||||||
lps0_dsm_func_mask, lps0_dsm_guid);
|
|
||||||
} else {
|
|
||||||
acpi_sleep_run_lps0_dsm(ACPI_LPS0_SCREEN_OFF,
|
|
||||||
lps0_dsm_func_mask, lps0_dsm_guid);
|
|
||||||
acpi_sleep_run_lps0_dsm(ACPI_LPS0_ENTRY,
|
|
||||||
lps0_dsm_func_mask, lps0_dsm_guid);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -476,24 +481,30 @@ void acpi_s2idle_restore_early(void)
|
|||||||
if (!lps0_device_handle || sleep_no_lps0)
|
if (!lps0_device_handle || sleep_no_lps0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (lps0_dsm_func_mask_microsoft > 0) {
|
/* Modern standby exit */
|
||||||
acpi_sleep_run_lps0_dsm(ACPI_LPS0_EXIT,
|
if (lps0_dsm_func_mask_microsoft > 0)
|
||||||
lps0_dsm_func_mask_microsoft, lps0_dsm_guid_microsoft);
|
|
||||||
acpi_sleep_run_lps0_dsm(ACPI_LPS0_MS_EXIT,
|
acpi_sleep_run_lps0_dsm(ACPI_LPS0_MS_EXIT,
|
||||||
lps0_dsm_func_mask_microsoft, lps0_dsm_guid_microsoft);
|
lps0_dsm_func_mask_microsoft, lps0_dsm_guid_microsoft);
|
||||||
|
|
||||||
|
/* 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);
|
||||||
|
if (lps0_dsm_func_mask_microsoft > 0)
|
||||||
|
acpi_sleep_run_lps0_dsm(ACPI_LPS0_EXIT,
|
||||||
|
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,
|
acpi_sleep_run_lps0_dsm(ACPI_LPS0_SCREEN_ON,
|
||||||
lps0_dsm_func_mask_microsoft, lps0_dsm_guid_microsoft);
|
lps0_dsm_func_mask_microsoft, lps0_dsm_guid_microsoft);
|
||||||
} else if (acpi_s2idle_vendor_amd()) {
|
if (lps0_dsm_func_mask > 0)
|
||||||
acpi_sleep_run_lps0_dsm(ACPI_LPS0_EXIT_AMD,
|
acpi_sleep_run_lps0_dsm(acpi_s2idle_vendor_amd() ?
|
||||||
lps0_dsm_func_mask, lps0_dsm_guid);
|
ACPI_LPS0_SCREEN_ON_AMD :
|
||||||
acpi_sleep_run_lps0_dsm(ACPI_LPS0_SCREEN_ON_AMD,
|
ACPI_LPS0_SCREEN_ON,
|
||||||
lps0_dsm_func_mask, lps0_dsm_guid);
|
lps0_dsm_func_mask, lps0_dsm_guid);
|
||||||
} else {
|
|
||||||
acpi_sleep_run_lps0_dsm(ACPI_LPS0_EXIT,
|
|
||||||
lps0_dsm_func_mask, lps0_dsm_guid);
|
|
||||||
acpi_sleep_run_lps0_dsm(ACPI_LPS0_SCREEN_ON,
|
|
||||||
lps0_dsm_func_mask, lps0_dsm_guid);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct platform_s2idle_ops acpi_s2idle_ops_lps0 = {
|
static const struct platform_s2idle_ops acpi_s2idle_ops_lps0 = {
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/msi.h>
|
#include <linux/msi.h>
|
||||||
#include <linux/pci.h>
|
#include <linux/pci.h>
|
||||||
|
#include <linux/pci-acpi.h>
|
||||||
#include <linux/pci-ecam.h>
|
#include <linux/pci-ecam.h>
|
||||||
#include <linux/srcu.h>
|
#include <linux/srcu.h>
|
||||||
#include <linux/rculist.h>
|
#include <linux/rculist.h>
|
||||||
@ -447,6 +448,56 @@ static struct pci_ops vmd_ops = {
|
|||||||
.write = vmd_pci_write,
|
.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)
|
static void vmd_attach_resources(struct vmd_dev *vmd)
|
||||||
{
|
{
|
||||||
vmd->dev->resource[VMD_MEMBAR1].child = &vmd->resources[1];
|
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)
|
if (vmd->irq_domain)
|
||||||
dev_set_msi_domain(&vmd->bus->dev, vmd->irq_domain);
|
dev_set_msi_domain(&vmd->bus->dev, vmd->irq_domain);
|
||||||
|
|
||||||
|
vmd_acpi_begin();
|
||||||
|
|
||||||
pci_scan_child_bus(vmd->bus);
|
pci_scan_child_bus(vmd->bus);
|
||||||
pci_assign_unassigned_bus_resources(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);
|
pci_bus_add_devices(vmd->bus);
|
||||||
|
|
||||||
|
vmd_acpi_end();
|
||||||
|
|
||||||
WARN(sysfs_create_link(&vmd->dev->dev.kobj, &vmd->bus->dev.kobj,
|
WARN(sysfs_create_link(&vmd->dev->dev.kobj, &vmd->bus->dev.kobj,
|
||||||
"domain"), "Can't create symlink to domain\n");
|
"domain"), "Can't create symlink to domain\n");
|
||||||
return 0;
|
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);
|
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)
|
struct device *pci_get_host_bridge_device(struct pci_dev *dev)
|
||||||
{
|
{
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
#include <linux/pci-acpi.h>
|
#include <linux/pci-acpi.h>
|
||||||
#include <linux/pm_runtime.h>
|
#include <linux/pm_runtime.h>
|
||||||
#include <linux/pm_qos.h>
|
#include <linux/pm_qos.h>
|
||||||
|
#include <linux/rwsem.h>
|
||||||
#include "pci.h"
|
#include "pci.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -1178,6 +1179,69 @@ void acpi_pci_remove_bus(struct pci_bus *bus)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* ACPI bus type */
|
/* 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)
|
static struct acpi_device *acpi_pci_find_companion(struct device *dev)
|
||||||
{
|
{
|
||||||
struct pci_dev *pci_dev = to_pci_dev(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;
|
bool check_children;
|
||||||
u64 addr;
|
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);
|
check_children = pci_is_bridge(pci_dev);
|
||||||
/* Please ref to ACPI spec for the syntax of _ADR */
|
/* Please ref to ACPI spec for the syntax of _ADR */
|
||||||
addr = (PCI_SLOT(pci_dev->devfn) << 16) | PCI_FUNC(pci_dev->devfn);
|
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) { }
|
static inline void pci_acpi_remove_edr_notifier(struct pci_dev *pdev) { }
|
||||||
#endif /* CONFIG_PCIE_EDR */
|
#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 */
|
#else /* CONFIG_ACPI */
|
||||||
static inline void acpi_pci_add_bus(struct pci_bus *bus) { }
|
static inline void acpi_pci_add_bus(struct pci_bus *bus) { }
|
||||||
static inline void acpi_pci_remove_bus(struct pci_bus *bus) { }
|
static inline void acpi_pci_remove_bus(struct pci_bus *bus) { }
|
||||||
|
Loading…
Reference in New Issue
Block a user