ACPI updates for 5.20-rc1
- Use facilities provided by the driver core and some additional helpers to handle the children of a given ACPI device object in multiple places instead of using the children and node list heads in struct acpi_device which is error prone (Rafael Wysocki). - Fix ACPI-related device reference counting issue in the hisi_lpc bus driver (Yang Yingliang). - Drop the children and node list heads that are not needed any more from struct acpi_device (Rafael Wysocki). - Drop driver member from struct acpi_device (Uwe Kleine-König). - Drop redundant check from acpi_device_remove() (Uwe Kleine-König). - Prepare the CPPC library for handling backwards-compatible future _CPC return package formats gracefully (Rafael Wysocki). - Clean up the ACPI EC driver after previous changes in it (Hans de Goede). - Drop leftover acpi_processor_get_limit_info() declaration (Riwen Lu). - Split out thermal initialization from ACPI PSS (Riwen Lu). - Annotate more functions in the ACPI CPU idle driver to live in the cpuidle section (Guilherme G. Piccoli). - Fix _EINJ vs "special purpose" EFI memory regions (Dan Williams). - Implement a better fix to avoid spamming the console with old error logs (Tony Luck). - Fix typo in a comment in the APEI code (Xiang wangx). - Save NVS memory during transitions into S3 on Lenovo G40-45 (Manyi Li). - Add support for upcoming AMD uPEP device ID AMDI008 to the ACPI suspend-to-idle driver for x86 platforms (Shyam Sundar S K). - Clean up checks related to the ACPI_FADT_LOW_POWER_S0 platform flag in the LPIT table driver and the suspend-to-idle driver for x86 platforms (Rafael Wysocki). - Print information messages regarding declared LPS0 idle support in the platform firmware (Rafael Wysocki). - Fix missing check in register_device_clock() in the ACPI driver for Intel SoCs (huhai). - Fix ACS setup in the VIOT table parser (Eric Auger). - Skip IRQ override on AMD Zen platforms where it's harmful (Chuanhong Guo). - Use native backlight on Dell Inspiron N4010 (Hans de Goede). - Use native backlight on some TongFang devices (Werner Sembach). - Drop X86 dependency from the ACPI backlight driver Kconfig (Riwen Lu). - Shorten the quirk list in the ACPI backlight driver by identifying Clevo by board_name only (Werner Sembach). - Remove useless NULL pointer checks from 2 ACPI PCI link management functions (Andrey Strachuk). - Fix obsolete example in the ACPI EINJ documentation (Qifu Zhang). - Update links and references to _DSD-related documents (Sudeep Holla). -----BEGIN PGP SIGNATURE----- iQJGBAABCAAwFiEE4fcc61cGeeHD/fCwgsRv/nhiVHEFAmLoKr8SHHJqd0Byand5 c29ja2kubmV0AAoJEILEb/54YlRxOIoP/3mM3FKIXzHE0P3L9sY6vV470yeW8pA7 /9SeZsswN872MuCO9J/EAINmgAk+HKOzJK4QUgYREwObagS5vPMAdYBRpGaNgBYg RPqoZIAaop6KZzhnzS3kE4luAEuIvTECSELLB5sRgcnLK16gf00RhOd/4jLW3Vdc LFUeh0Dubz+ZX9sD8jUh6+Z70nl0mJWQitT5JddqfiUxnMYAYmEqXA77NfVFSCLa UTQVBBAspdfT5tp0h4yUGYE3+cNXWRcZ/yx2UDIAcy4qjzzOZwYIOjzPJhkT8dE+ 7XTG2NpAqmsnEW9UCC9eJAG1X3c7X0yGJGj8XE2iqLBRqVvJcL7d/VNybFyj9odz zI3NLEBYsZP2d4wDGi1p2OwcmpftxQqfY62fe8yUEjsFA5HL0qu9iM+Xh9VgmiFA vPkT/7Fjx0chpMLwMXiSn/Olm79vVBu/tnjt64/BSsWDUlxQ5Hwx871Uq0nSJVoY gZazgbG/SFoPvDqe6n4UfOKtodgpvkVU1J6VFHGuLUEXquH7WdsypJMEvq3VQ8C0 hgc3nDENx7on8iK+jyJOTbc5rNd8MZDDuAapst5BxPWFXZ/G9Td0jDzh0oea489I UTq0epp7oUhHpZMH0h+szIPMLxo+AnMKv8j7qWoy0qPpjer4B98h4szceFzHBbVZ uc8vA3EcO9UM =2/wJ -----END PGP SIGNATURE----- Merge tag 'acpi-5.20-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm Pull ACPI updates from Rafael Wysocki: "These rework the handling of ACPI device objects to use the driver core facilities for managing child ones instead of some questionable home-grown ways without the requisite locking and reference counting, clean up the EC driver, improve suspend-to-idle handling on x86, add some systems to the ACPI backlight quirk list, fix some assorted issues, clean up code and improve documentation. Specifics: - Use facilities provided by the driver core and some additional helpers to handle the children of a given ACPI device object in multiple places instead of using the children and node list heads in struct acpi_device which is error prone (Rafael Wysocki). - Fix ACPI-related device reference counting issue in the hisi_lpc bus driver (Yang Yingliang). - Drop the children and node list heads that are not needed any more from struct acpi_device (Rafael Wysocki). - Drop driver member from struct acpi_device (Uwe Kleine-König). - Drop redundant check from acpi_device_remove() (Uwe Kleine-König). - Prepare the CPPC library for handling backwards-compatible future _CPC return package formats gracefully (Rafael Wysocki). - Clean up the ACPI EC driver after previous changes in it (Hans de Goede). - Drop leftover acpi_processor_get_limit_info() declaration (Riwen Lu). - Split out thermal initialization from ACPI PSS (Riwen Lu). - Annotate more functions in the ACPI CPU idle driver to live in the cpuidle section (Guilherme G. Piccoli). - Fix _EINJ vs "special purpose" EFI memory regions (Dan Williams). - Implement a better fix to avoid spamming the console with old error logs (Tony Luck). - Fix typo in a comment in the APEI code (Xiang wangx). - Save NVS memory during transitions into S3 on Lenovo G40-45 (Manyi Li). - Add support for upcoming AMD uPEP device ID AMDI008 to the ACPI suspend-to-idle driver for x86 platforms (Shyam Sundar S K). - Clean up checks related to the ACPI_FADT_LOW_POWER_S0 platform flag in the LPIT table driver and the suspend-to-idle driver for x86 platforms (Rafael Wysocki). - Print information messages regarding declared LPS0 idle support in the platform firmware (Rafael Wysocki). - Fix missing check in register_device_clock() in the ACPI driver for Intel SoCs (huhai). - Fix ACS setup in the VIOT table parser (Eric Auger). - Skip IRQ override on AMD Zen platforms where it's harmful (Chuanhong Guo). - Use native backlight on Dell Inspiron N4010 (Hans de Goede). - Use native backlight on some TongFang devices (Werner Sembach). - Drop X86 dependency from the ACPI backlight driver Kconfig (Riwen Lu). - Shorten the quirk list in the ACPI backlight driver by identifying Clevo by board_name only (Werner Sembach). - Remove useless NULL pointer checks from 2 ACPI PCI link management functions (Andrey Strachuk). - Fix obsolete example in the ACPI EINJ documentation (Qifu Zhang). - Update links and references to _DSD-related documents (Sudeep Holla)" * tag 'acpi-5.20-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm: (46 commits) ACPI/PCI: Remove useless NULL pointer checks ACPI: CPPC: Do not prevent CPPC from working in the future ACPI: PM: x86: Print messages regarding LPS0 idle support ACPI: resource: skip IRQ override on AMD Zen platforms Documentation: ACPI: EINJ: Fix obsolete example ACPI: video: Use native backlight on Dell Inspiron N4010 ACPI: PM: s2idle: Use LPS0 idle if ACPI_FADT_LOW_POWER_S0 is unset Revert "ACPI / PM: LPIT: Register sysfs attributes based on FADT" ACPI: video: Shortening quirk list by identifying Clevo by board_name only ACPI: video: Force backlight native for some TongFang devices ACPI: PM: s2idle: Add support for upcoming AMD uPEP HID AMDI008 ACPI: VIOT: Fix ACS setup ACPI: bus: Drop unused list heads from struct acpi_device hisi_lpc: Use acpi_dev_for_each_child() bus: hisi_lpc: fix missing platform_device_put() in hisi_lpc_acpi_probe() ACPI: bus: Drop driver member of struct acpi_device ACPI: bus: Drop redundant check in acpi_device_remove() ACPI: APEI: Fix _EINJ vs EFI_MEMORY_SP ACPI: LPSS: Fix missing check in register_device_clock() ACPI: APEI: Better fix to avoid spamming the console with old error logs ...
This commit is contained in:
commit
8fa0db3a9b
@ -21,7 +21,9 @@ specific type) associated with it.
|
||||
|
||||
In the ACPI _DSD context it is an element of the sub-package following the
|
||||
generic Device Properties UUID in the _DSD return package as specified in the
|
||||
Device Properties UUID definition document [1]_.
|
||||
section titled "Well-Known _DSD UUIDs and Data Structure Formats" sub-section
|
||||
"Device Properties UUID" in _DSD (Device Specific Data) Implementation Guide
|
||||
document [1]_.
|
||||
|
||||
It also may be regarded as the definition of a key and the associated data type
|
||||
that can be returned by _DSD in the Device Properties UUID sub-package for a
|
||||
@ -36,7 +38,9 @@ Property subsets are nested collections of properties. Each of them is
|
||||
associated with an additional key (name) allowing the subset to be referred
|
||||
to as a whole (and to be treated as a separate entity). The canonical
|
||||
representation of property subsets is via the mechanism specified in the
|
||||
Hierarchical Properties Extension UUID definition document [2]_.
|
||||
section titled "Well-Known _DSD UUIDs and Data Structure Formats" sub-section
|
||||
"Hierarchical Data Extension UUID" in _DSD (Device Specific Data)
|
||||
Implementation Guide document [1]_.
|
||||
|
||||
Property sets may be hierarchical. That is, a property set may contain
|
||||
multiple property subsets that each may contain property subsets of its
|
||||
@ -96,5 +100,4 @@ contents.
|
||||
References
|
||||
==========
|
||||
|
||||
.. [1] https://www.uefi.org/sites/default/files/resources/_DSD-device-properties-UUID.pdf
|
||||
.. [2] https://www.uefi.org/sites/default/files/resources/_DSD-hierarchical-data-extension-UUID-v1.1.pdf
|
||||
.. [1] https://github.com/UEFI/DSD-Guide
|
||||
|
@ -168,7 +168,7 @@ An error injection example::
|
||||
0x00000008 Memory Correctable
|
||||
0x00000010 Memory Uncorrectable non-fatal
|
||||
# echo 0x12345000 > param1 # Set memory address for injection
|
||||
# echo $((-1 << 12)) > param2 # Mask 0xfffffffffffff000 - anywhere in this page
|
||||
# echo 0xfffffffffffff000 > param2 # Mask - anywhere in this page
|
||||
# echo 0x8 > error_type # Choose correctable memory error
|
||||
# echo 1 > error_inject # Inject now
|
||||
|
||||
|
@ -210,7 +210,7 @@ config ACPI_TINY_POWER_BUTTON_SIGNAL
|
||||
|
||||
config ACPI_VIDEO
|
||||
tristate "Video"
|
||||
depends on X86 && BACKLIGHT_CLASS_DEVICE
|
||||
depends on BACKLIGHT_CLASS_DEVICE
|
||||
depends on INPUT
|
||||
select THERMAL
|
||||
help
|
||||
@ -255,7 +255,6 @@ config ACPI_DOCK
|
||||
|
||||
config ACPI_CPU_FREQ_PSS
|
||||
bool
|
||||
select THERMAL
|
||||
|
||||
config ACPI_PROCESSOR_CSTATE
|
||||
def_bool y
|
||||
@ -287,6 +286,7 @@ config ACPI_PROCESSOR
|
||||
depends on X86 || IA64 || ARM64 || LOONGARCH
|
||||
select ACPI_PROCESSOR_IDLE
|
||||
select ACPI_CPU_FREQ_PSS if X86 || IA64 || LOONGARCH
|
||||
select THERMAL
|
||||
default y
|
||||
help
|
||||
This driver adds support for the ACPI Processor package. It is required
|
||||
|
@ -109,10 +109,9 @@ obj-$(CONFIG_ACPI_PPTT) += pptt.o
|
||||
obj-$(CONFIG_ACPI_PFRUT) += pfr_update.o pfr_telemetry.o
|
||||
|
||||
# processor has its own "processor." module_param namespace
|
||||
processor-y := processor_driver.o
|
||||
processor-y := processor_driver.o processor_thermal.o
|
||||
processor-$(CONFIG_ACPI_PROCESSOR_IDLE) += processor_idle.o
|
||||
processor-$(CONFIG_ACPI_CPU_FREQ_PSS) += processor_throttling.o \
|
||||
processor_thermal.o
|
||||
processor-$(CONFIG_ACPI_CPU_FREQ_PSS) += processor_throttling.o
|
||||
processor-$(CONFIG_CPU_FREQ) += processor_perflib.o
|
||||
|
||||
obj-$(CONFIG_ACPI_PROCESSOR_AGGREGATOR) += acpi_pad.o
|
||||
|
@ -109,17 +109,11 @@ static void lpit_update_residency(struct lpit_residency_info *info,
|
||||
if (!info->iomem_addr)
|
||||
return;
|
||||
|
||||
if (!(acpi_gbl_FADT.flags & ACPI_FADT_LOW_POWER_S0))
|
||||
return;
|
||||
|
||||
/* Silently fail, if cpuidle attribute group is not present */
|
||||
sysfs_add_file_to_group(&cpu_subsys.dev_root->kobj,
|
||||
&dev_attr_low_power_idle_system_residency_us.attr,
|
||||
"cpuidle");
|
||||
} else if (info->gaddr.space_id == ACPI_ADR_SPACE_FIXED_HARDWARE) {
|
||||
if (!(acpi_gbl_FADT.flags & ACPI_FADT_LOW_POWER_S0))
|
||||
return;
|
||||
|
||||
/* Silently fail, if cpuidle attribute group is not present */
|
||||
sysfs_add_file_to_group(&cpu_subsys.dev_root->kobj,
|
||||
&dev_attr_low_power_idle_cpu_residency_us.attr,
|
||||
|
@ -422,6 +422,9 @@ static int register_device_clock(struct acpi_device *adev,
|
||||
if (!lpss_clk_dev)
|
||||
lpt_register_clock_device();
|
||||
|
||||
if (IS_ERR(lpss_clk_dev))
|
||||
return PTR_ERR(lpss_clk_dev);
|
||||
|
||||
clk_data = platform_get_drvdata(lpss_clk_dev);
|
||||
if (!clk_data)
|
||||
return -ENODEV;
|
||||
|
@ -1150,24 +1150,25 @@ acpi_video_get_device_type(struct acpi_video_bus *video,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
acpi_video_bus_get_one_device(struct acpi_device *device,
|
||||
struct acpi_video_bus *video)
|
||||
static int acpi_video_bus_get_one_device(struct acpi_device *device, void *arg)
|
||||
{
|
||||
unsigned long long device_id;
|
||||
int status, device_type;
|
||||
struct acpi_video_device *data;
|
||||
struct acpi_video_bus *video = arg;
|
||||
struct acpi_video_device_attrib *attribute;
|
||||
struct acpi_video_device *data;
|
||||
unsigned long long device_id;
|
||||
acpi_status status;
|
||||
int device_type;
|
||||
|
||||
status =
|
||||
acpi_evaluate_integer(device->handle, "_ADR", NULL, &device_id);
|
||||
/* Some device omits _ADR, we skip them instead of fail */
|
||||
status = acpi_evaluate_integer(device->handle, "_ADR", NULL, &device_id);
|
||||
/* Skip devices without _ADR instead of failing. */
|
||||
if (ACPI_FAILURE(status))
|
||||
return 0;
|
||||
goto exit;
|
||||
|
||||
data = kzalloc(sizeof(struct acpi_video_device), GFP_KERNEL);
|
||||
if (!data)
|
||||
if (!data) {
|
||||
dev_dbg(&device->dev, "Cannot attach\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
strcpy(acpi_device_name(device), ACPI_VIDEO_DEVICE_NAME);
|
||||
strcpy(acpi_device_class(device), ACPI_VIDEO_CLASS);
|
||||
@ -1230,7 +1231,9 @@ acpi_video_bus_get_one_device(struct acpi_device *device,
|
||||
list_add_tail(&data->entry, &video->video_device_list);
|
||||
mutex_unlock(&video->device_list_lock);
|
||||
|
||||
return status;
|
||||
exit:
|
||||
video->child_count++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1542,9 +1545,6 @@ static int
|
||||
acpi_video_bus_get_devices(struct acpi_video_bus *video,
|
||||
struct acpi_device *device)
|
||||
{
|
||||
int status = 0;
|
||||
struct acpi_device *dev;
|
||||
|
||||
/*
|
||||
* There are systems where video module known to work fine regardless
|
||||
* of broken _DOD and ignoring returned value here doesn't cause
|
||||
@ -1552,16 +1552,7 @@ acpi_video_bus_get_devices(struct acpi_video_bus *video,
|
||||
*/
|
||||
acpi_video_device_enumerate(video);
|
||||
|
||||
list_for_each_entry(dev, &device->children, node) {
|
||||
|
||||
status = acpi_video_bus_get_one_device(dev, video);
|
||||
if (status) {
|
||||
dev_err(&dev->dev, "Can't attach device\n");
|
||||
break;
|
||||
}
|
||||
video->child_count++;
|
||||
}
|
||||
return status;
|
||||
return acpi_dev_for_each_child(device, acpi_video_bus_get_one_device, video);
|
||||
}
|
||||
|
||||
/* acpi_video interface */
|
||||
|
@ -3,7 +3,7 @@
|
||||
* apei-base.c - ACPI Platform Error Interface (APEI) supporting
|
||||
* infrastructure
|
||||
*
|
||||
* APEI allows to report errors (for example from the chipset) to the
|
||||
* APEI allows to report errors (for example from the chipset) to
|
||||
* the operating system. This improves NMI handling especially. In
|
||||
* addition it supports error serialization and error injection.
|
||||
*
|
||||
|
@ -29,16 +29,26 @@
|
||||
|
||||
#undef pr_fmt
|
||||
#define pr_fmt(fmt) "BERT: " fmt
|
||||
|
||||
#define ACPI_BERT_PRINT_MAX_RECORDS 5
|
||||
#define ACPI_BERT_PRINT_MAX_LEN 1024
|
||||
|
||||
static int bert_disable;
|
||||
|
||||
/*
|
||||
* Print "all" the error records in the BERT table, but avoid huge spam to
|
||||
* the console if the BIOS included oversize records, or too many records.
|
||||
* Skipping some records here does not lose anything because the full
|
||||
* data is available to user tools in:
|
||||
* /sys/firmware/acpi/tables/data/BERT
|
||||
*/
|
||||
static void __init bert_print_all(struct acpi_bert_region *region,
|
||||
unsigned int region_len)
|
||||
{
|
||||
struct acpi_hest_generic_status *estatus =
|
||||
(struct acpi_hest_generic_status *)region;
|
||||
int remain = region_len;
|
||||
int printed = 0, skipped = 0;
|
||||
u32 estatus_len;
|
||||
|
||||
while (remain >= sizeof(struct acpi_bert_region)) {
|
||||
@ -46,24 +56,26 @@ static void __init bert_print_all(struct acpi_bert_region *region,
|
||||
if (remain < estatus_len) {
|
||||
pr_err(FW_BUG "Truncated status block (length: %u).\n",
|
||||
estatus_len);
|
||||
return;
|
||||
break;
|
||||
}
|
||||
|
||||
/* No more error records. */
|
||||
if (!estatus->block_status)
|
||||
return;
|
||||
break;
|
||||
|
||||
if (cper_estatus_check(estatus)) {
|
||||
pr_err(FW_BUG "Invalid error record.\n");
|
||||
return;
|
||||
break;
|
||||
}
|
||||
|
||||
pr_info_once("Error records from previous boot:\n");
|
||||
if (region_len < ACPI_BERT_PRINT_MAX_LEN)
|
||||
if (estatus_len < ACPI_BERT_PRINT_MAX_LEN &&
|
||||
printed < ACPI_BERT_PRINT_MAX_RECORDS) {
|
||||
pr_info_once("Error records from previous boot:\n");
|
||||
cper_estatus_print(KERN_INFO HW_ERR, estatus);
|
||||
else
|
||||
pr_info_once("Max print length exceeded, table data is available at:\n"
|
||||
"/sys/firmware/acpi/tables/data/BERT");
|
||||
printed++;
|
||||
} else {
|
||||
skipped++;
|
||||
}
|
||||
|
||||
/*
|
||||
* Because the boot error source is "one-time polled" type,
|
||||
@ -75,6 +87,9 @@ static void __init bert_print_all(struct acpi_bert_region *region,
|
||||
estatus = (void *)estatus + estatus_len;
|
||||
remain -= estatus_len;
|
||||
}
|
||||
|
||||
if (skipped)
|
||||
pr_info(HW_ERR "Skipped %d error records\n", skipped);
|
||||
}
|
||||
|
||||
static int __init setup_bert_disable(char *str)
|
||||
|
@ -546,6 +546,8 @@ static int einj_error_inject(u32 type, u32 flags, u64 param1, u64 param2,
|
||||
!= REGION_INTERSECTS) &&
|
||||
(region_intersects(base_addr, size, IORESOURCE_MEM, IORES_DESC_PERSISTENT_MEMORY)
|
||||
!= REGION_INTERSECTS) &&
|
||||
(region_intersects(base_addr, size, IORESOURCE_MEM, IORES_DESC_SOFT_RESERVED)
|
||||
!= REGION_INTERSECTS) &&
|
||||
!arch_is_platform_page(base_addr)))
|
||||
return -EINVAL;
|
||||
|
||||
|
@ -464,7 +464,6 @@ out_free:
|
||||
static void acpi_bus_notify(acpi_handle handle, u32 type, void *data)
|
||||
{
|
||||
struct acpi_device *adev;
|
||||
struct acpi_driver *driver;
|
||||
u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE;
|
||||
bool hotplug_event = false;
|
||||
|
||||
@ -516,10 +515,13 @@ static void acpi_bus_notify(acpi_handle handle, u32 type, void *data)
|
||||
if (!adev)
|
||||
goto err;
|
||||
|
||||
driver = adev->driver;
|
||||
if (driver && driver->ops.notify &&
|
||||
(driver->flags & ACPI_DRIVER_ALL_NOTIFY_EVENTS))
|
||||
driver->ops.notify(adev, type);
|
||||
if (adev->dev.driver) {
|
||||
struct acpi_driver *driver = to_acpi_driver(adev->dev.driver);
|
||||
|
||||
if (driver && driver->ops.notify &&
|
||||
(driver->flags & ACPI_DRIVER_ALL_NOTIFY_EVENTS))
|
||||
driver->ops.notify(adev, type);
|
||||
}
|
||||
|
||||
if (!hotplug_event) {
|
||||
acpi_bus_put_acpi_device(adev);
|
||||
@ -538,8 +540,9 @@ static void acpi_bus_notify(acpi_handle handle, u32 type, void *data)
|
||||
static void acpi_notify_device(acpi_handle handle, u32 event, void *data)
|
||||
{
|
||||
struct acpi_device *device = data;
|
||||
struct acpi_driver *acpi_drv = to_acpi_driver(device->dev.driver);
|
||||
|
||||
device->driver->ops.notify(device, event);
|
||||
acpi_drv->ops.notify(device, event);
|
||||
}
|
||||
|
||||
static void acpi_notify_device_fixed(void *data)
|
||||
@ -1032,8 +1035,6 @@ static int acpi_device_probe(struct device *dev)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
acpi_dev->driver = acpi_drv;
|
||||
|
||||
pr_debug("Driver [%s] successfully bound to device [%s]\n",
|
||||
acpi_drv->name, acpi_dev->pnp.bus_id);
|
||||
|
||||
@ -1043,7 +1044,6 @@ static int acpi_device_probe(struct device *dev)
|
||||
if (acpi_drv->ops.remove)
|
||||
acpi_drv->ops.remove(acpi_dev);
|
||||
|
||||
acpi_dev->driver = NULL;
|
||||
acpi_dev->driver_data = NULL;
|
||||
return ret;
|
||||
}
|
||||
@ -1059,15 +1059,14 @@ static int acpi_device_probe(struct device *dev)
|
||||
static void acpi_device_remove(struct device *dev)
|
||||
{
|
||||
struct acpi_device *acpi_dev = to_acpi_device(dev);
|
||||
struct acpi_driver *acpi_drv = acpi_dev->driver;
|
||||
struct acpi_driver *acpi_drv = to_acpi_driver(dev->driver);
|
||||
|
||||
if (acpi_drv->ops.notify)
|
||||
acpi_device_remove_notify_handler(acpi_dev);
|
||||
|
||||
if (acpi_drv->ops.remove)
|
||||
acpi_drv->ops.remove(acpi_dev);
|
||||
|
||||
if (acpi_drv) {
|
||||
if (acpi_drv->ops.notify)
|
||||
acpi_device_remove_notify_handler(acpi_dev);
|
||||
if (acpi_drv->ops.remove)
|
||||
acpi_drv->ops.remove(acpi_dev);
|
||||
}
|
||||
acpi_dev->driver = NULL;
|
||||
acpi_dev->driver_data = NULL;
|
||||
|
||||
put_device(dev);
|
||||
@ -1101,6 +1100,7 @@ static int acpi_dev_for_one_check(struct device *dev, void *context)
|
||||
|
||||
return adwc->fn(to_acpi_device(dev), adwc->data);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(acpi_dev_for_each_child);
|
||||
|
||||
int acpi_dev_for_each_child(struct acpi_device *adev,
|
||||
int (*fn)(struct acpi_device *, void *), void *data)
|
||||
@ -1113,6 +1113,18 @@ int acpi_dev_for_each_child(struct acpi_device *adev,
|
||||
return device_for_each_child(&adev->dev, &adwc, acpi_dev_for_one_check);
|
||||
}
|
||||
|
||||
int acpi_dev_for_each_child_reverse(struct acpi_device *adev,
|
||||
int (*fn)(struct acpi_device *, void *),
|
||||
void *data)
|
||||
{
|
||||
struct acpi_dev_walk_context adwc = {
|
||||
.fn = fn,
|
||||
.data = data,
|
||||
};
|
||||
|
||||
return device_for_each_child_reverse(&adev->dev, &adwc, acpi_dev_for_one_check);
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
Initialization/Cleanup
|
||||
-------------------------------------------------------------------------- */
|
||||
@ -1402,6 +1414,7 @@ static int __init acpi_init(void)
|
||||
|
||||
pci_mmcfg_late_init();
|
||||
acpi_iort_init();
|
||||
acpi_viot_early_init();
|
||||
acpi_hest_init();
|
||||
acpi_ghes_init();
|
||||
acpi_scan_init();
|
||||
|
@ -23,17 +23,18 @@ static const struct acpi_device_id container_device_ids[] = {
|
||||
|
||||
#ifdef CONFIG_ACPI_CONTAINER
|
||||
|
||||
static int check_offline(struct acpi_device *adev, void *not_used)
|
||||
{
|
||||
if (acpi_scan_is_offline(adev, false))
|
||||
return 0;
|
||||
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
static int acpi_container_offline(struct container_dev *cdev)
|
||||
{
|
||||
struct acpi_device *adev = ACPI_COMPANION(&cdev->dev);
|
||||
struct acpi_device *child;
|
||||
|
||||
/* Check all of the dependent devices' physical companions. */
|
||||
list_for_each_entry(child, &adev->children, node)
|
||||
if (!acpi_scan_is_offline(child, false))
|
||||
return -EBUSY;
|
||||
|
||||
return 0;
|
||||
return acpi_dev_for_each_child(ACPI_COMPANION(&cdev->dev), check_offline, NULL);
|
||||
}
|
||||
|
||||
static void acpi_container_release(struct device *dev)
|
||||
|
@ -618,33 +618,6 @@ static int pcc_data_alloc(int pcc_ss_id)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Check if CPPC revision + num_ent combination is supported */
|
||||
static bool is_cppc_supported(int revision, int num_ent)
|
||||
{
|
||||
int expected_num_ent;
|
||||
|
||||
switch (revision) {
|
||||
case CPPC_V2_REV:
|
||||
expected_num_ent = CPPC_V2_NUM_ENT;
|
||||
break;
|
||||
case CPPC_V3_REV:
|
||||
expected_num_ent = CPPC_V3_NUM_ENT;
|
||||
break;
|
||||
default:
|
||||
pr_debug("Firmware exports unsupported CPPC revision: %d\n",
|
||||
revision);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (expected_num_ent != num_ent) {
|
||||
pr_debug("Firmware exports %d entries. Expected: %d for CPPC rev:%d\n",
|
||||
num_ent, expected_num_ent, revision);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* An example CPC table looks like the following.
|
||||
*
|
||||
@ -733,7 +706,6 @@ int acpi_cppc_processor_probe(struct acpi_processor *pr)
|
||||
cpc_obj->type, pr->id);
|
||||
goto out_free;
|
||||
}
|
||||
cpc_ptr->num_entries = num_ent;
|
||||
|
||||
/* Second entry should be revision. */
|
||||
cpc_obj = &out_obj->package.elements[1];
|
||||
@ -744,10 +716,32 @@ int acpi_cppc_processor_probe(struct acpi_processor *pr)
|
||||
cpc_obj->type, pr->id);
|
||||
goto out_free;
|
||||
}
|
||||
cpc_ptr->version = cpc_rev;
|
||||
|
||||
if (!is_cppc_supported(cpc_rev, num_ent))
|
||||
if (cpc_rev < CPPC_V2_REV) {
|
||||
pr_debug("Unsupported _CPC Revision (%d) for CPU:%d\n", cpc_rev,
|
||||
pr->id);
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
/*
|
||||
* Disregard _CPC if the number of entries in the return pachage is not
|
||||
* as expected, but support future revisions being proper supersets of
|
||||
* the v3 and only causing more entries to be returned by _CPC.
|
||||
*/
|
||||
if ((cpc_rev == CPPC_V2_REV && num_ent != CPPC_V2_NUM_ENT) ||
|
||||
(cpc_rev == CPPC_V3_REV && num_ent != CPPC_V3_NUM_ENT) ||
|
||||
(cpc_rev > CPPC_V3_REV && num_ent <= CPPC_V3_NUM_ENT)) {
|
||||
pr_debug("Unexpected number of _CPC return package entries (%d) for CPU:%d\n",
|
||||
num_ent, pr->id);
|
||||
goto out_free;
|
||||
}
|
||||
if (cpc_rev > CPPC_V3_REV) {
|
||||
num_ent = CPPC_V3_NUM_ENT;
|
||||
cpc_rev = CPPC_V3_REV;
|
||||
}
|
||||
|
||||
cpc_ptr->num_entries = num_ent;
|
||||
cpc_ptr->version = cpc_rev;
|
||||
|
||||
/* Iterate through remaining entries in _CPC */
|
||||
for (i = 2; i < num_ent; i++) {
|
||||
|
@ -369,6 +369,28 @@ int acpi_device_fix_up_power(struct acpi_device *device)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(acpi_device_fix_up_power);
|
||||
|
||||
static int fix_up_power_if_applicable(struct acpi_device *adev, void *not_used)
|
||||
{
|
||||
if (adev->status.present && adev->status.enabled)
|
||||
acpi_device_fix_up_power(adev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* acpi_device_fix_up_power_extended - Force device and its children into D0.
|
||||
* @adev: Parent device object whose power state is to be fixed up.
|
||||
*
|
||||
* Call acpi_device_fix_up_power() for @adev and its children so long as they
|
||||
* are reported as present and enabled.
|
||||
*/
|
||||
void acpi_device_fix_up_power_extended(struct acpi_device *adev)
|
||||
{
|
||||
acpi_device_fix_up_power(adev);
|
||||
acpi_dev_for_each_child(adev, fix_up_power_if_applicable, NULL);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(acpi_device_fix_up_power_extended);
|
||||
|
||||
int acpi_device_update_power(struct acpi_device *device, int *state_p)
|
||||
{
|
||||
int state;
|
||||
|
@ -376,7 +376,7 @@ eject_store(struct device *d, struct device_attribute *attr,
|
||||
return -EINVAL;
|
||||
|
||||
if ((!acpi_device->handler || !acpi_device->handler->hotplug.enabled)
|
||||
&& !acpi_device->driver)
|
||||
&& !d->driver)
|
||||
return -ENODEV;
|
||||
|
||||
status = acpi_get_type(acpi_device->handle, ¬_used);
|
||||
|
@ -180,7 +180,6 @@ static struct workqueue_struct *ec_wq;
|
||||
static struct workqueue_struct *ec_query_wq;
|
||||
|
||||
static int EC_FLAGS_CORRECT_ECDT; /* Needs ECDT port address correction */
|
||||
static int EC_FLAGS_IGNORE_DSDT_GPE; /* Needs ECDT GPE as correction setting */
|
||||
static int EC_FLAGS_TRUST_DSDT_GPE; /* Needs DSDT GPE as correction setting */
|
||||
static int EC_FLAGS_CLEAR_ON_RESUME; /* Needs acpi_ec_clear() on boot/resume */
|
||||
|
||||
@ -1407,24 +1406,16 @@ ec_parse_device(acpi_handle handle, u32 Level, void *context, void **retval)
|
||||
if (ec->data_addr == 0 || ec->command_addr == 0)
|
||||
return AE_OK;
|
||||
|
||||
if (boot_ec && boot_ec_is_ecdt && EC_FLAGS_IGNORE_DSDT_GPE) {
|
||||
/*
|
||||
* Always inherit the GPE number setting from the ECDT
|
||||
* EC.
|
||||
*/
|
||||
ec->gpe = boot_ec->gpe;
|
||||
} else {
|
||||
/* Get GPE bit assignment (EC events). */
|
||||
/* TODO: Add support for _GPE returning a package */
|
||||
status = acpi_evaluate_integer(handle, "_GPE", NULL, &tmp);
|
||||
if (ACPI_SUCCESS(status))
|
||||
ec->gpe = tmp;
|
||||
/* Get GPE bit assignment (EC events). */
|
||||
/* TODO: Add support for _GPE returning a package */
|
||||
status = acpi_evaluate_integer(handle, "_GPE", NULL, &tmp);
|
||||
if (ACPI_SUCCESS(status))
|
||||
ec->gpe = tmp;
|
||||
/*
|
||||
* Errors are non-fatal, allowing for ACPI Reduced Hardware
|
||||
* platforms which use GpioInt instead of GPE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Errors are non-fatal, allowing for ACPI Reduced Hardware
|
||||
* platforms which use GpioInt instead of GPE.
|
||||
*/
|
||||
}
|
||||
/* Use the global lock for all EC transactions? */
|
||||
tmp = 0;
|
||||
acpi_evaluate_integer(handle, "_GLK", NULL, &tmp);
|
||||
@ -1626,15 +1617,18 @@ static int acpi_ec_add(struct acpi_device *device)
|
||||
}
|
||||
|
||||
if (boot_ec && ec->command_addr == boot_ec->command_addr &&
|
||||
ec->data_addr == boot_ec->data_addr &&
|
||||
!EC_FLAGS_TRUST_DSDT_GPE) {
|
||||
ec->data_addr == boot_ec->data_addr) {
|
||||
/*
|
||||
* Trust PNP0C09 namespace location rather than
|
||||
* ECDT ID. But trust ECDT GPE rather than _GPE
|
||||
* because of ASUS quirks, so do not change
|
||||
* boot_ec->gpe to ec->gpe.
|
||||
* Trust PNP0C09 namespace location rather than ECDT ID.
|
||||
* But trust ECDT GPE rather than _GPE because of ASUS
|
||||
* quirks. So do not change boot_ec->gpe to ec->gpe,
|
||||
* except when the TRUST_DSDT_GPE quirk is set.
|
||||
*/
|
||||
boot_ec->handle = ec->handle;
|
||||
|
||||
if (EC_FLAGS_TRUST_DSDT_GPE)
|
||||
boot_ec->gpe = ec->gpe;
|
||||
|
||||
acpi_handle_debug(ec->handle, "duplicated.\n");
|
||||
acpi_ec_free(ec);
|
||||
ec = boot_ec;
|
||||
@ -1862,68 +1856,40 @@ static int ec_honor_dsdt_gpe(const struct dmi_system_id *id)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Some DSDTs contain wrong GPE setting.
|
||||
* Asus FX502VD/VE, GL702VMK, X550VXK, X580VD
|
||||
* https://bugzilla.kernel.org/show_bug.cgi?id=195651
|
||||
*/
|
||||
static int ec_honor_ecdt_gpe(const struct dmi_system_id *id)
|
||||
{
|
||||
pr_debug("Detected system needing ignore DSDT GPE setting.\n");
|
||||
EC_FLAGS_IGNORE_DSDT_GPE = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dmi_system_id ec_dmi_table[] __initconst = {
|
||||
{
|
||||
ec_correct_ecdt, "MSI MS-171F", {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star"),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "MS-171F"),}, NULL},
|
||||
/*
|
||||
* MSI MS-171F
|
||||
* https://bugzilla.kernel.org/show_bug.cgi?id=12461
|
||||
*/
|
||||
.callback = ec_correct_ecdt,
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star"),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "MS-171F"),
|
||||
},
|
||||
},
|
||||
{
|
||||
ec_honor_ecdt_gpe, "ASUS FX502VD", {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "FX502VD"),}, NULL},
|
||||
/*
|
||||
* HP Pavilion Gaming Laptop 15-cx0xxx
|
||||
* https://bugzilla.kernel.org/show_bug.cgi?id=209989
|
||||
*/
|
||||
.callback = ec_honor_dsdt_gpe,
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "HP"),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "HP Pavilion Gaming Laptop 15-cx0xxx"),
|
||||
},
|
||||
},
|
||||
{
|
||||
ec_honor_ecdt_gpe, "ASUS FX502VE", {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "FX502VE"),}, NULL},
|
||||
{
|
||||
ec_honor_ecdt_gpe, "ASUS GL702VMK", {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "GL702VMK"),}, NULL},
|
||||
{
|
||||
ec_honor_ecdt_gpe, "ASUSTeK COMPUTER INC. X505BA", {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "X505BA"),}, NULL},
|
||||
{
|
||||
ec_honor_ecdt_gpe, "ASUSTeK COMPUTER INC. X505BP", {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "X505BP"),}, NULL},
|
||||
{
|
||||
ec_honor_ecdt_gpe, "ASUSTeK COMPUTER INC. X542BA", {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "X542BA"),}, NULL},
|
||||
{
|
||||
ec_honor_ecdt_gpe, "ASUSTeK COMPUTER INC. X542BP", {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "X542BP"),}, NULL},
|
||||
{
|
||||
ec_honor_ecdt_gpe, "ASUS X550VXK", {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "X550VXK"),}, NULL},
|
||||
{
|
||||
ec_honor_ecdt_gpe, "ASUS X580VD", {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "X580VD"),}, NULL},
|
||||
{
|
||||
/* https://bugzilla.kernel.org/show_bug.cgi?id=209989 */
|
||||
ec_honor_dsdt_gpe, "HP Pavilion Gaming Laptop 15-cx0xxx", {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "HP"),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "HP Pavilion Gaming Laptop 15-cx0xxx"),}, NULL},
|
||||
{
|
||||
ec_clear_on_resume, "Samsung hardware", {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD.")}, NULL},
|
||||
{},
|
||||
/*
|
||||
* Samsung hardware
|
||||
* https://bugzilla.kernel.org/show_bug.cgi?id=44161
|
||||
*/
|
||||
.callback = ec_clear_on_resume,
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
|
||||
},
|
||||
},
|
||||
{}
|
||||
};
|
||||
|
||||
void __init acpi_ec_ecdt_probe(void)
|
||||
@ -2201,28 +2167,18 @@ static int acpi_ec_init_workqueues(void)
|
||||
|
||||
static const struct dmi_system_id acpi_ec_no_wakeup[] = {
|
||||
{
|
||||
.ident = "Thinkpad X1 Carbon 6th",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
|
||||
DMI_MATCH(DMI_PRODUCT_FAMILY, "Thinkpad X1 Carbon 6th"),
|
||||
},
|
||||
},
|
||||
{
|
||||
.ident = "ThinkPad X1 Carbon 6th",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
|
||||
DMI_MATCH(DMI_PRODUCT_FAMILY, "ThinkPad X1 Carbon 6th"),
|
||||
},
|
||||
},
|
||||
{
|
||||
.ident = "ThinkPad X1 Yoga 3rd",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
|
||||
DMI_MATCH(DMI_PRODUCT_FAMILY, "ThinkPad X1 Yoga 3rd"),
|
||||
},
|
||||
},
|
||||
{
|
||||
.ident = "HP ZHAN 66 Pro",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "HP"),
|
||||
DMI_MATCH(DMI_PRODUCT_FAMILY, "103C_5336AN HP ZHAN 66 Pro"),
|
||||
|
@ -77,12 +77,22 @@ static struct acpi_bus_type *acpi_get_bus_type(struct device *dev)
|
||||
#define FIND_CHILD_MIN_SCORE 1
|
||||
#define FIND_CHILD_MAX_SCORE 2
|
||||
|
||||
static int match_any(struct acpi_device *adev, void *not_used)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
static bool acpi_dev_has_children(struct acpi_device *adev)
|
||||
{
|
||||
return acpi_dev_for_each_child(adev, match_any, NULL) > 0;
|
||||
}
|
||||
|
||||
static int find_child_checks(struct acpi_device *adev, bool check_children)
|
||||
{
|
||||
unsigned long long sta;
|
||||
acpi_status status;
|
||||
|
||||
if (check_children && list_empty(&adev->children))
|
||||
if (check_children && !acpi_dev_has_children(adev))
|
||||
return -ENODEV;
|
||||
|
||||
status = acpi_evaluate_integer(adev->handle, "_STA", NULL, &sta);
|
||||
@ -105,54 +115,97 @@ static int find_child_checks(struct acpi_device *adev, bool check_children)
|
||||
return FIND_CHILD_MAX_SCORE;
|
||||
}
|
||||
|
||||
struct find_child_walk_data {
|
||||
struct acpi_device *adev;
|
||||
u64 address;
|
||||
int score;
|
||||
bool check_sta;
|
||||
bool check_children;
|
||||
};
|
||||
|
||||
static int check_one_child(struct acpi_device *adev, void *data)
|
||||
{
|
||||
struct find_child_walk_data *wd = data;
|
||||
int score;
|
||||
|
||||
if (!adev->pnp.type.bus_address || acpi_device_adr(adev) != wd->address)
|
||||
return 0;
|
||||
|
||||
if (!wd->adev) {
|
||||
/*
|
||||
* This is the first matching object, so save it. If it is not
|
||||
* necessary to look for any other matching objects, stop the
|
||||
* search.
|
||||
*/
|
||||
wd->adev = adev;
|
||||
return !(wd->check_sta || wd->check_children);
|
||||
}
|
||||
|
||||
/*
|
||||
* There is more than one matching device object with the same _ADR
|
||||
* value. That really is unexpected, so we are kind of beyond the scope
|
||||
* of the spec here. We have to choose which one to return, though.
|
||||
*
|
||||
* First, get the score for the previously found object and terminate
|
||||
* the walk if it is maximum.
|
||||
*/
|
||||
if (!wd->score) {
|
||||
score = find_child_checks(wd->adev, wd->check_children);
|
||||
if (score == FIND_CHILD_MAX_SCORE)
|
||||
return 1;
|
||||
|
||||
wd->score = score;
|
||||
}
|
||||
/*
|
||||
* Second, if the object that has just been found has a better score,
|
||||
* replace the previously found one with it and terminate the walk if
|
||||
* the new score is maximum.
|
||||
*/
|
||||
score = find_child_checks(adev, wd->check_children);
|
||||
if (score > wd->score) {
|
||||
wd->adev = adev;
|
||||
if (score == FIND_CHILD_MAX_SCORE)
|
||||
return 1;
|
||||
|
||||
wd->score = score;
|
||||
}
|
||||
|
||||
/* Continue, because there may be better matches. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct acpi_device *acpi_find_child(struct acpi_device *parent,
|
||||
u64 address, bool check_children,
|
||||
bool check_sta)
|
||||
{
|
||||
struct find_child_walk_data wd = {
|
||||
.address = address,
|
||||
.check_children = check_children,
|
||||
.check_sta = check_sta,
|
||||
.adev = NULL,
|
||||
.score = 0,
|
||||
};
|
||||
|
||||
if (parent)
|
||||
acpi_dev_for_each_child(parent, check_one_child, &wd);
|
||||
|
||||
return wd.adev;
|
||||
}
|
||||
|
||||
struct acpi_device *acpi_find_child_device(struct acpi_device *parent,
|
||||
u64 address, bool check_children)
|
||||
{
|
||||
struct acpi_device *adev, *ret = NULL;
|
||||
int ret_score = 0;
|
||||
|
||||
if (!parent)
|
||||
return NULL;
|
||||
|
||||
list_for_each_entry(adev, &parent->children, node) {
|
||||
acpi_bus_address addr = acpi_device_adr(adev);
|
||||
int score;
|
||||
|
||||
if (!adev->pnp.type.bus_address || addr != address)
|
||||
continue;
|
||||
|
||||
if (!ret) {
|
||||
/* This is the first matching object. Save it. */
|
||||
ret = adev;
|
||||
continue;
|
||||
}
|
||||
/*
|
||||
* There is more than one matching device object with the same
|
||||
* _ADR value. That really is unexpected, so we are kind of
|
||||
* beyond the scope of the spec here. We have to choose which
|
||||
* one to return, though.
|
||||
*
|
||||
* First, check if the previously found object is good enough
|
||||
* and return it if so. Second, do the same for the object that
|
||||
* we've just found.
|
||||
*/
|
||||
if (!ret_score) {
|
||||
ret_score = find_child_checks(ret, check_children);
|
||||
if (ret_score == FIND_CHILD_MAX_SCORE)
|
||||
return ret;
|
||||
}
|
||||
score = find_child_checks(adev, check_children);
|
||||
if (score == FIND_CHILD_MAX_SCORE) {
|
||||
return adev;
|
||||
} else if (score > ret_score) {
|
||||
ret = adev;
|
||||
ret_score = score;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
return acpi_find_child(parent, address, check_children, true);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(acpi_find_child_device);
|
||||
|
||||
struct acpi_device *acpi_find_child_by_adr(struct acpi_device *adev,
|
||||
acpi_bus_address adr)
|
||||
{
|
||||
return acpi_find_child(adev, adr, false, false);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(acpi_find_child_by_adr);
|
||||
|
||||
static void acpi_physnode_link_name(char *buf, unsigned int node_id)
|
||||
{
|
||||
if (node_id > 0)
|
||||
|
@ -95,7 +95,7 @@ static acpi_status acpi_pci_link_check_possible(struct acpi_resource *resource,
|
||||
case ACPI_RESOURCE_TYPE_IRQ:
|
||||
{
|
||||
struct acpi_resource_irq *p = &resource->data.irq;
|
||||
if (!p || !p->interrupt_count) {
|
||||
if (!p->interrupt_count) {
|
||||
acpi_handle_debug(handle,
|
||||
"Blank _PRS IRQ resource\n");
|
||||
return AE_OK;
|
||||
@ -121,7 +121,7 @@ static acpi_status acpi_pci_link_check_possible(struct acpi_resource *resource,
|
||||
{
|
||||
struct acpi_resource_extended_irq *p =
|
||||
&resource->data.extended_irq;
|
||||
if (!p || !p->interrupt_count) {
|
||||
if (!p->interrupt_count) {
|
||||
acpi_handle_debug(handle,
|
||||
"Blank _PRS EXT IRQ resource\n");
|
||||
return AE_OK;
|
||||
@ -182,7 +182,7 @@ static acpi_status acpi_pci_link_check_current(struct acpi_resource *resource,
|
||||
case ACPI_RESOURCE_TYPE_IRQ:
|
||||
{
|
||||
struct acpi_resource_irq *p = &resource->data.irq;
|
||||
if (!p || !p->interrupt_count) {
|
||||
if (!p->interrupt_count) {
|
||||
/*
|
||||
* IRQ descriptors may have no IRQ# bits set,
|
||||
* particularly those w/ _STA disabled
|
||||
@ -197,7 +197,7 @@ static acpi_status acpi_pci_link_check_current(struct acpi_resource *resource,
|
||||
{
|
||||
struct acpi_resource_extended_irq *p =
|
||||
&resource->data.extended_irq;
|
||||
if (!p || !p->interrupt_count) {
|
||||
if (!p->interrupt_count) {
|
||||
/*
|
||||
* extended IRQ descriptors must
|
||||
* return at least 1 IRQ
|
||||
|
@ -139,75 +139,17 @@ static int acpi_soft_cpu_dead(unsigned int cpu)
|
||||
}
|
||||
|
||||
#ifdef CONFIG_ACPI_CPU_FREQ_PSS
|
||||
static int acpi_pss_perf_init(struct acpi_processor *pr,
|
||||
struct acpi_device *device)
|
||||
static void acpi_pss_perf_init(struct acpi_processor *pr)
|
||||
{
|
||||
int result = 0;
|
||||
|
||||
acpi_processor_ppc_has_changed(pr, 0);
|
||||
|
||||
acpi_processor_get_throttling_info(pr);
|
||||
|
||||
if (pr->flags.throttling)
|
||||
pr->flags.limit = 1;
|
||||
|
||||
pr->cdev = thermal_cooling_device_register("Processor", device,
|
||||
&processor_cooling_ops);
|
||||
if (IS_ERR(pr->cdev)) {
|
||||
result = PTR_ERR(pr->cdev);
|
||||
return result;
|
||||
}
|
||||
|
||||
dev_dbg(&device->dev, "registered as cooling_device%d\n",
|
||||
pr->cdev->id);
|
||||
|
||||
result = sysfs_create_link(&device->dev.kobj,
|
||||
&pr->cdev->device.kobj,
|
||||
"thermal_cooling");
|
||||
if (result) {
|
||||
dev_err(&device->dev,
|
||||
"Failed to create sysfs link 'thermal_cooling'\n");
|
||||
goto err_thermal_unregister;
|
||||
}
|
||||
|
||||
result = sysfs_create_link(&pr->cdev->device.kobj,
|
||||
&device->dev.kobj,
|
||||
"device");
|
||||
if (result) {
|
||||
dev_err(&pr->cdev->device,
|
||||
"Failed to create sysfs link 'device'\n");
|
||||
goto err_remove_sysfs_thermal;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_remove_sysfs_thermal:
|
||||
sysfs_remove_link(&device->dev.kobj, "thermal_cooling");
|
||||
err_thermal_unregister:
|
||||
thermal_cooling_device_unregister(pr->cdev);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static void acpi_pss_perf_exit(struct acpi_processor *pr,
|
||||
struct acpi_device *device)
|
||||
{
|
||||
if (pr->cdev) {
|
||||
sysfs_remove_link(&device->dev.kobj, "thermal_cooling");
|
||||
sysfs_remove_link(&pr->cdev->device.kobj, "device");
|
||||
thermal_cooling_device_unregister(pr->cdev);
|
||||
pr->cdev = NULL;
|
||||
}
|
||||
}
|
||||
#else
|
||||
static inline int acpi_pss_perf_init(struct acpi_processor *pr,
|
||||
struct acpi_device *device)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void acpi_pss_perf_exit(struct acpi_processor *pr,
|
||||
struct acpi_device *device) {}
|
||||
static inline void acpi_pss_perf_init(struct acpi_processor *pr) {}
|
||||
#endif /* CONFIG_ACPI_CPU_FREQ_PSS */
|
||||
|
||||
static int __acpi_processor_start(struct acpi_device *device)
|
||||
@ -229,7 +171,9 @@ static int __acpi_processor_start(struct acpi_device *device)
|
||||
if (!cpuidle_get_driver() || cpuidle_get_driver() == &acpi_idle_driver)
|
||||
acpi_processor_power_init(pr);
|
||||
|
||||
result = acpi_pss_perf_init(pr, device);
|
||||
acpi_pss_perf_init(pr);
|
||||
|
||||
result = acpi_processor_thermal_init(pr, device);
|
||||
if (result)
|
||||
goto err_power_exit;
|
||||
|
||||
@ -239,7 +183,7 @@ static int __acpi_processor_start(struct acpi_device *device)
|
||||
return 0;
|
||||
|
||||
result = -ENODEV;
|
||||
acpi_pss_perf_exit(pr, device);
|
||||
acpi_processor_thermal_exit(pr, device);
|
||||
|
||||
err_power_exit:
|
||||
acpi_processor_power_exit(pr);
|
||||
@ -277,10 +221,10 @@ static int acpi_processor_stop(struct device *dev)
|
||||
return 0;
|
||||
acpi_processor_power_exit(pr);
|
||||
|
||||
acpi_pss_perf_exit(pr, device);
|
||||
|
||||
acpi_cppc_processor_exit(pr);
|
||||
|
||||
acpi_processor_thermal_exit(pr, device);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -607,7 +607,7 @@ static DEFINE_RAW_SPINLOCK(c3_lock);
|
||||
* @cx: Target state context
|
||||
* @index: index of target state
|
||||
*/
|
||||
static int acpi_idle_enter_bm(struct cpuidle_driver *drv,
|
||||
static int __cpuidle acpi_idle_enter_bm(struct cpuidle_driver *drv,
|
||||
struct acpi_processor *pr,
|
||||
struct acpi_processor_cx *cx,
|
||||
int index)
|
||||
@ -664,7 +664,7 @@ static int acpi_idle_enter_bm(struct cpuidle_driver *drv,
|
||||
return index;
|
||||
}
|
||||
|
||||
static int acpi_idle_enter(struct cpuidle_device *dev,
|
||||
static int __cpuidle acpi_idle_enter(struct cpuidle_device *dev,
|
||||
struct cpuidle_driver *drv, int index)
|
||||
{
|
||||
struct acpi_processor_cx *cx = per_cpu(acpi_cstate[index], dev->cpu);
|
||||
@ -693,7 +693,7 @@ static int acpi_idle_enter(struct cpuidle_device *dev,
|
||||
return index;
|
||||
}
|
||||
|
||||
static int acpi_idle_enter_s2idle(struct cpuidle_device *dev,
|
||||
static int __cpuidle acpi_idle_enter_s2idle(struct cpuidle_device *dev,
|
||||
struct cpuidle_driver *drv, int index)
|
||||
{
|
||||
struct acpi_processor_cx *cx = per_cpu(acpi_cstate[index], dev->cpu);
|
||||
|
@ -266,3 +266,57 @@ const struct thermal_cooling_device_ops processor_cooling_ops = {
|
||||
.get_cur_state = processor_get_cur_state,
|
||||
.set_cur_state = processor_set_cur_state,
|
||||
};
|
||||
|
||||
int acpi_processor_thermal_init(struct acpi_processor *pr,
|
||||
struct acpi_device *device)
|
||||
{
|
||||
int result = 0;
|
||||
|
||||
pr->cdev = thermal_cooling_device_register("Processor", device,
|
||||
&processor_cooling_ops);
|
||||
if (IS_ERR(pr->cdev)) {
|
||||
result = PTR_ERR(pr->cdev);
|
||||
return result;
|
||||
}
|
||||
|
||||
dev_dbg(&device->dev, "registered as cooling_device%d\n",
|
||||
pr->cdev->id);
|
||||
|
||||
result = sysfs_create_link(&device->dev.kobj,
|
||||
&pr->cdev->device.kobj,
|
||||
"thermal_cooling");
|
||||
if (result) {
|
||||
dev_err(&device->dev,
|
||||
"Failed to create sysfs link 'thermal_cooling'\n");
|
||||
goto err_thermal_unregister;
|
||||
}
|
||||
|
||||
result = sysfs_create_link(&pr->cdev->device.kobj,
|
||||
&device->dev.kobj,
|
||||
"device");
|
||||
if (result) {
|
||||
dev_err(&pr->cdev->device,
|
||||
"Failed to create sysfs link 'device'\n");
|
||||
goto err_remove_sysfs_thermal;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_remove_sysfs_thermal:
|
||||
sysfs_remove_link(&device->dev.kobj, "thermal_cooling");
|
||||
err_thermal_unregister:
|
||||
thermal_cooling_device_unregister(pr->cdev);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void acpi_processor_thermal_exit(struct acpi_processor *pr,
|
||||
struct acpi_device *device)
|
||||
{
|
||||
if (pr->cdev) {
|
||||
sysfs_remove_link(&device->dev.kobj, "thermal_cooling");
|
||||
sysfs_remove_link(&pr->cdev->device.kobj, "device");
|
||||
thermal_cooling_device_unregister(pr->cdev);
|
||||
pr->cdev = NULL;
|
||||
}
|
||||
}
|
||||
|
@ -1012,6 +1012,22 @@ static int acpi_node_prop_read(const struct fwnode_handle *fwnode,
|
||||
propname, proptype, val, nval);
|
||||
}
|
||||
|
||||
static int stop_on_next(struct acpi_device *adev, void *data)
|
||||
{
|
||||
struct acpi_device **ret_p = data;
|
||||
|
||||
if (!*ret_p) {
|
||||
*ret_p = adev;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Skip until the "previous" object is found. */
|
||||
if (*ret_p == adev)
|
||||
*ret_p = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* acpi_get_next_subnode - Return the next child node handle for a fwnode
|
||||
* @fwnode: Firmware node to find the next child node for.
|
||||
@ -1020,35 +1036,22 @@ static int acpi_node_prop_read(const struct fwnode_handle *fwnode,
|
||||
struct fwnode_handle *acpi_get_next_subnode(const struct fwnode_handle *fwnode,
|
||||
struct fwnode_handle *child)
|
||||
{
|
||||
const struct acpi_device *adev = to_acpi_device_node(fwnode);
|
||||
const struct list_head *head;
|
||||
struct list_head *next;
|
||||
struct acpi_device *adev = to_acpi_device_node(fwnode);
|
||||
|
||||
if ((!child || is_acpi_device_node(child)) && adev) {
|
||||
struct acpi_device *child_adev;
|
||||
struct acpi_device *child_adev = to_acpi_device_node(child);
|
||||
|
||||
head = &adev->children;
|
||||
if (list_empty(head))
|
||||
goto nondev;
|
||||
acpi_dev_for_each_child(adev, stop_on_next, &child_adev);
|
||||
if (child_adev)
|
||||
return acpi_fwnode_handle(child_adev);
|
||||
|
||||
if (child) {
|
||||
adev = to_acpi_device_node(child);
|
||||
next = adev->node.next;
|
||||
if (next == head) {
|
||||
child = NULL;
|
||||
goto nondev;
|
||||
}
|
||||
child_adev = list_entry(next, struct acpi_device, node);
|
||||
} else {
|
||||
child_adev = list_first_entry(head, struct acpi_device,
|
||||
node);
|
||||
}
|
||||
return acpi_fwnode_handle(child_adev);
|
||||
child = NULL;
|
||||
}
|
||||
|
||||
nondev:
|
||||
if (!child || is_acpi_data_node(child)) {
|
||||
const struct acpi_data_node *data = to_acpi_data_node(fwnode);
|
||||
const struct list_head *head;
|
||||
struct list_head *next;
|
||||
struct acpi_data_node *dn;
|
||||
|
||||
/*
|
||||
|
@ -416,6 +416,16 @@ static bool acpi_dev_irq_override(u32 gsi, u8 triggering, u8 polarity,
|
||||
{
|
||||
int i;
|
||||
|
||||
#ifdef CONFIG_X86
|
||||
/*
|
||||
* IRQ override isn't needed on modern AMD Zen systems and
|
||||
* this override breaks active low IRQs on AMD Ryzen 6000 and
|
||||
* newer systems. Skip it.
|
||||
*/
|
||||
if (boot_cpu_has(X86_FEATURE_ZEN))
|
||||
return false;
|
||||
#endif
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(skip_override_table); i++) {
|
||||
const struct irq_override_cmp *entry = &skip_override_table[i];
|
||||
|
||||
|
@ -334,10 +334,9 @@ static int acpi_scan_device_check(struct acpi_device *adev)
|
||||
return error;
|
||||
}
|
||||
|
||||
static int acpi_scan_bus_check(struct acpi_device *adev)
|
||||
static int acpi_scan_bus_check(struct acpi_device *adev, void *not_used)
|
||||
{
|
||||
struct acpi_scan_handler *handler = adev->handler;
|
||||
struct acpi_device *child;
|
||||
int error;
|
||||
|
||||
acpi_bus_get_status(adev);
|
||||
@ -353,19 +352,14 @@ static int acpi_scan_bus_check(struct acpi_device *adev)
|
||||
dev_warn(&adev->dev, "Namespace scan failure\n");
|
||||
return error;
|
||||
}
|
||||
list_for_each_entry(child, &adev->children, node) {
|
||||
error = acpi_scan_bus_check(child);
|
||||
if (error)
|
||||
return error;
|
||||
}
|
||||
return 0;
|
||||
return acpi_dev_for_each_child(adev, acpi_scan_bus_check, NULL);
|
||||
}
|
||||
|
||||
static int acpi_generic_hotplug_event(struct acpi_device *adev, u32 type)
|
||||
{
|
||||
switch (type) {
|
||||
case ACPI_NOTIFY_BUS_CHECK:
|
||||
return acpi_scan_bus_check(adev);
|
||||
return acpi_scan_bus_check(adev, NULL);
|
||||
case ACPI_NOTIFY_DEVICE_CHECK:
|
||||
return acpi_scan_device_check(adev);
|
||||
case ACPI_NOTIFY_EJECT_REQUEST:
|
||||
@ -471,8 +465,6 @@ static void acpi_device_del(struct acpi_device *device)
|
||||
struct acpi_device_bus_id *acpi_device_bus_id;
|
||||
|
||||
mutex_lock(&acpi_device_lock);
|
||||
if (device->parent)
|
||||
list_del(&device->node);
|
||||
|
||||
list_for_each_entry(acpi_device_bus_id, &acpi_bus_id_list, node)
|
||||
if (!strcmp(acpi_device_bus_id->bus_id,
|
||||
@ -488,6 +480,7 @@ static void acpi_device_del(struct acpi_device *device)
|
||||
}
|
||||
|
||||
list_del(&device->wakeup_list);
|
||||
|
||||
mutex_unlock(&acpi_device_lock);
|
||||
|
||||
acpi_power_add_remove_device(device, false);
|
||||
@ -680,8 +673,6 @@ static int __acpi_device_add(struct acpi_device *device,
|
||||
* -------
|
||||
* Link this device to its parent and siblings.
|
||||
*/
|
||||
INIT_LIST_HEAD(&device->children);
|
||||
INIT_LIST_HEAD(&device->node);
|
||||
INIT_LIST_HEAD(&device->wakeup_list);
|
||||
INIT_LIST_HEAD(&device->physical_node_list);
|
||||
INIT_LIST_HEAD(&device->del_list);
|
||||
@ -721,9 +712,6 @@ static int __acpi_device_add(struct acpi_device *device,
|
||||
list_add_tail(&acpi_device_bus_id->node, &acpi_bus_id_list);
|
||||
}
|
||||
|
||||
if (device->parent)
|
||||
list_add_tail(&device->node, &device->parent->children);
|
||||
|
||||
if (device->wakeup.flags.valid)
|
||||
list_add_tail(&device->wakeup_list, &acpi_wakeup_device_list);
|
||||
|
||||
@ -752,9 +740,6 @@ static int __acpi_device_add(struct acpi_device *device,
|
||||
err:
|
||||
mutex_lock(&acpi_device_lock);
|
||||
|
||||
if (device->parent)
|
||||
list_del(&device->node);
|
||||
|
||||
list_del(&device->wakeup_list);
|
||||
|
||||
err_unlock:
|
||||
@ -2187,9 +2172,8 @@ static int acpi_scan_attach_handler(struct acpi_device *device)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void acpi_bus_attach(struct acpi_device *device, bool first_pass)
|
||||
static int acpi_bus_attach(struct acpi_device *device, void *first_pass)
|
||||
{
|
||||
struct acpi_device *child;
|
||||
bool skip = !first_pass && device->flags.visited;
|
||||
acpi_handle ejd;
|
||||
int ret;
|
||||
@ -2206,7 +2190,7 @@ static void acpi_bus_attach(struct acpi_device *device, bool first_pass)
|
||||
device->flags.initialized = false;
|
||||
acpi_device_clear_enumerated(device);
|
||||
device->flags.power_manageable = 0;
|
||||
return;
|
||||
return 0;
|
||||
}
|
||||
if (device->handler)
|
||||
goto ok;
|
||||
@ -2224,7 +2208,7 @@ static void acpi_bus_attach(struct acpi_device *device, bool first_pass)
|
||||
|
||||
ret = acpi_scan_attach_handler(device);
|
||||
if (ret < 0)
|
||||
return;
|
||||
return 0;
|
||||
|
||||
device->flags.match_driver = true;
|
||||
if (ret > 0 && !device->flags.enumeration_by_parent) {
|
||||
@ -2234,19 +2218,20 @@ static void acpi_bus_attach(struct acpi_device *device, bool first_pass)
|
||||
|
||||
ret = device_attach(&device->dev);
|
||||
if (ret < 0)
|
||||
return;
|
||||
return 0;
|
||||
|
||||
if (device->pnp.type.platform_id || device->flags.enumeration_by_parent)
|
||||
acpi_default_enumeration(device);
|
||||
else
|
||||
acpi_device_set_enumerated(device);
|
||||
|
||||
ok:
|
||||
list_for_each_entry(child, &device->children, node)
|
||||
acpi_bus_attach(child, first_pass);
|
||||
ok:
|
||||
acpi_dev_for_each_child(device, acpi_bus_attach, first_pass);
|
||||
|
||||
if (!skip && device->handler && device->handler->hotplug.notify_online)
|
||||
device->handler->hotplug.notify_online(device);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int acpi_dev_get_first_consumer_dev_cb(struct acpi_dep_data *dep, void *data)
|
||||
@ -2274,7 +2259,7 @@ static void acpi_scan_clear_dep_fn(struct work_struct *work)
|
||||
cdw = container_of(work, struct acpi_scan_clear_dep_work, work);
|
||||
|
||||
acpi_scan_lock_acquire();
|
||||
acpi_bus_attach(cdw->adev, true);
|
||||
acpi_bus_attach(cdw->adev, (void *)true);
|
||||
acpi_scan_lock_release();
|
||||
|
||||
acpi_dev_put(cdw->adev);
|
||||
@ -2432,7 +2417,7 @@ int acpi_bus_scan(acpi_handle handle)
|
||||
if (!device)
|
||||
return -ENODEV;
|
||||
|
||||
acpi_bus_attach(device, true);
|
||||
acpi_bus_attach(device, (void *)true);
|
||||
|
||||
if (!acpi_bus_scan_second_pass)
|
||||
return 0;
|
||||
@ -2446,25 +2431,17 @@ int acpi_bus_scan(acpi_handle handle)
|
||||
acpi_bus_check_add_2, NULL, NULL,
|
||||
(void **)&device);
|
||||
|
||||
acpi_bus_attach(device, false);
|
||||
acpi_bus_attach(device, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(acpi_bus_scan);
|
||||
|
||||
/**
|
||||
* acpi_bus_trim - Detach scan handlers and drivers from ACPI device objects.
|
||||
* @adev: Root of the ACPI namespace scope to walk.
|
||||
*
|
||||
* Must be called under acpi_scan_lock.
|
||||
*/
|
||||
void acpi_bus_trim(struct acpi_device *adev)
|
||||
static int acpi_bus_trim_one(struct acpi_device *adev, void *not_used)
|
||||
{
|
||||
struct acpi_scan_handler *handler = adev->handler;
|
||||
struct acpi_device *child;
|
||||
|
||||
list_for_each_entry_reverse(child, &adev->children, node)
|
||||
acpi_bus_trim(child);
|
||||
acpi_dev_for_each_child_reverse(adev, acpi_bus_trim_one, NULL);
|
||||
|
||||
adev->flags.match_driver = false;
|
||||
if (handler) {
|
||||
@ -2482,6 +2459,19 @@ void acpi_bus_trim(struct acpi_device *adev)
|
||||
acpi_device_set_power(adev, ACPI_STATE_D3_COLD);
|
||||
adev->flags.initialized = false;
|
||||
acpi_device_clear_enumerated(adev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* acpi_bus_trim - Detach scan handlers and drivers from ACPI device objects.
|
||||
* @adev: Root of the ACPI namespace scope to walk.
|
||||
*
|
||||
* Must be called under acpi_scan_lock.
|
||||
*/
|
||||
void acpi_bus_trim(struct acpi_device *adev)
|
||||
{
|
||||
acpi_bus_trim_one(adev, NULL);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(acpi_bus_trim);
|
||||
|
||||
|
@ -360,6 +360,14 @@ static const struct dmi_system_id acpisleep_dmi_table[] __initconst = {
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "80E3"),
|
||||
},
|
||||
},
|
||||
{
|
||||
.callback = init_nvs_save_s3,
|
||||
.ident = "Lenovo G40-45",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "80E1"),
|
||||
},
|
||||
},
|
||||
/*
|
||||
* ThinkPad X1 Tablet(2016) cannot do suspend-to-idle using
|
||||
* the Low Power S0 Idle firmware interface (see
|
||||
@ -816,6 +824,9 @@ static const struct platform_s2idle_ops acpi_s2idle_ops = {
|
||||
|
||||
void __weak acpi_s2idle_setup(void)
|
||||
{
|
||||
if (acpi_gbl_FADT.flags & ACPI_FADT_LOW_POWER_S0)
|
||||
pr_info("Efficient low-power S0 idle declared\n");
|
||||
|
||||
s2idle_set_ops(&acpi_s2idle_ops);
|
||||
}
|
||||
|
||||
|
@ -347,6 +347,14 @@ static const struct dmi_system_id video_detect_dmi_table[] = {
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro12,1"),
|
||||
},
|
||||
},
|
||||
{
|
||||
.callback = video_detect_force_native,
|
||||
/* Dell Inspiron N4010 */
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron N4010"),
|
||||
},
|
||||
},
|
||||
{
|
||||
.callback = video_detect_force_native,
|
||||
/* Dell Vostro V131 */
|
||||
@ -430,23 +438,6 @@ static const struct dmi_system_id video_detect_dmi_table[] = {
|
||||
.callback = video_detect_force_native,
|
||||
.ident = "Clevo NL5xRU",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
|
||||
DMI_MATCH(DMI_BOARD_NAME, "NL5xRU"),
|
||||
},
|
||||
},
|
||||
{
|
||||
.callback = video_detect_force_native,
|
||||
.ident = "Clevo NL5xRU",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "SchenkerTechnologiesGmbH"),
|
||||
DMI_MATCH(DMI_BOARD_NAME, "NL5xRU"),
|
||||
},
|
||||
},
|
||||
{
|
||||
.callback = video_detect_force_native,
|
||||
.ident = "Clevo NL5xRU",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "Notebook"),
|
||||
DMI_MATCH(DMI_BOARD_NAME, "NL5xRU"),
|
||||
},
|
||||
},
|
||||
@ -469,28 +460,60 @@ static const struct dmi_system_id video_detect_dmi_table[] = {
|
||||
{
|
||||
.callback = video_detect_force_native,
|
||||
.ident = "Clevo NL5xNU",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_BOARD_NAME, "NL5xNU"),
|
||||
},
|
||||
},
|
||||
/*
|
||||
* The TongFang PF5PU1G, PF4NU1F, PF5NU1G, and PF5LUXG/TUXEDO BA15 Gen10,
|
||||
* Pulse 14/15 Gen1, and Pulse 15 Gen2 have the same problem as the Clevo
|
||||
* NL5xRU and NL5xNU/TUXEDO Aura 15 Gen1 and Gen2. See the description
|
||||
* above.
|
||||
*/
|
||||
{
|
||||
.callback = video_detect_force_native,
|
||||
.ident = "TongFang PF5PU1G",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_BOARD_NAME, "PF5PU1G"),
|
||||
},
|
||||
},
|
||||
{
|
||||
.callback = video_detect_force_native,
|
||||
.ident = "TongFang PF4NU1F",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_BOARD_NAME, "PF4NU1F"),
|
||||
},
|
||||
},
|
||||
{
|
||||
.callback = video_detect_force_native,
|
||||
.ident = "TongFang PF4NU1F",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
|
||||
DMI_MATCH(DMI_BOARD_NAME, "NL5xNU"),
|
||||
DMI_MATCH(DMI_BOARD_NAME, "PULSE1401"),
|
||||
},
|
||||
},
|
||||
{
|
||||
.callback = video_detect_force_native,
|
||||
.ident = "Clevo NL5xNU",
|
||||
.ident = "TongFang PF5NU1G",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "SchenkerTechnologiesGmbH"),
|
||||
DMI_MATCH(DMI_BOARD_NAME, "NL5xNU"),
|
||||
DMI_MATCH(DMI_BOARD_NAME, "PF5NU1G"),
|
||||
},
|
||||
},
|
||||
{
|
||||
.callback = video_detect_force_native,
|
||||
.ident = "Clevo NL5xNU",
|
||||
.ident = "TongFang PF5NU1G",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "Notebook"),
|
||||
DMI_MATCH(DMI_BOARD_NAME, "NL5xNU"),
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
|
||||
DMI_MATCH(DMI_BOARD_NAME, "PULSE1501"),
|
||||
},
|
||||
},
|
||||
{
|
||||
.callback = video_detect_force_native,
|
||||
.ident = "TongFang PF5LUXG",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_BOARD_NAME, "PF5LUXG"),
|
||||
},
|
||||
},
|
||||
|
||||
/*
|
||||
* Desktops which falsely report a backlight and which our heuristics
|
||||
* for this do not catch.
|
||||
|
@ -248,6 +248,26 @@ err_free:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* acpi_viot_early_init - Test the presence of VIOT and enable ACS
|
||||
*
|
||||
* If the VIOT does exist, ACS must be enabled. This cannot be
|
||||
* done in acpi_viot_init() which is called after the bus scan
|
||||
*/
|
||||
void __init acpi_viot_early_init(void)
|
||||
{
|
||||
#ifdef CONFIG_PCI
|
||||
acpi_status status;
|
||||
struct acpi_table_header *hdr;
|
||||
|
||||
status = acpi_get_table(ACPI_SIG_VIOT, 0, &hdr);
|
||||
if (ACPI_FAILURE(status))
|
||||
return;
|
||||
pci_request_acs();
|
||||
acpi_put_table(hdr);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* acpi_viot_init - Parse the VIOT table
|
||||
*
|
||||
@ -319,12 +339,6 @@ static int viot_pci_dev_iommu_init(struct pci_dev *pdev, u16 dev_id, void *data)
|
||||
epid = ((domain_nr - ep->segment_start) << 16) +
|
||||
dev_id - ep->bdf_start + ep->endpoint_id;
|
||||
|
||||
/*
|
||||
* If we found a PCI range managed by the viommu, we're
|
||||
* the one that has to request ACS.
|
||||
*/
|
||||
pci_request_acs();
|
||||
|
||||
return viot_dev_iommu_init(&pdev->dev, ep->viommu,
|
||||
epid);
|
||||
}
|
||||
|
@ -369,9 +369,6 @@ static int lps0_device_attach(struct acpi_device *adev,
|
||||
if (lps0_device_handle)
|
||||
return 0;
|
||||
|
||||
if (!(acpi_gbl_FADT.flags & ACPI_FADT_LOW_POWER_S0))
|
||||
return 0;
|
||||
|
||||
if (acpi_s2idle_vendor_amd()) {
|
||||
/* AMD0004, AMD0005, AMDI0005:
|
||||
* - Should use rev_id 0x0
|
||||
@ -397,7 +394,9 @@ static int lps0_device_attach(struct acpi_device *adev,
|
||||
lps0_dsm_func_mask = (lps0_dsm_func_mask << 1) | 0x1;
|
||||
acpi_handle_debug(adev->handle, "_DSM UUID %s: Adjusted function mask: 0x%x\n",
|
||||
ACPI_LPS0_DSM_UUID_AMD, lps0_dsm_func_mask);
|
||||
} else if (lps0_dsm_func_mask_microsoft > 0 && !strcmp(hid, "AMDI0007")) {
|
||||
} else if (lps0_dsm_func_mask_microsoft > 0 &&
|
||||
(!strcmp(hid, "AMDI0007") ||
|
||||
!strcmp(hid, "AMDI0008"))) {
|
||||
lps0_dsm_func_mask_microsoft = -EINVAL;
|
||||
acpi_handle_debug(adev->handle, "_DSM Using AMD method\n");
|
||||
}
|
||||
@ -419,11 +418,15 @@ static int lps0_device_attach(struct acpi_device *adev,
|
||||
lpi_device_get_constraints();
|
||||
|
||||
/*
|
||||
* Use suspend-to-idle by default if the default suspend mode was not
|
||||
* set from the command line.
|
||||
* Use suspend-to-idle by default if ACPI_FADT_LOW_POWER_S0 is set in
|
||||
* the FADT and the default suspend mode was not set from the command
|
||||
* line.
|
||||
*/
|
||||
if (mem_sleep_default > PM_SUSPEND_MEM && !acpi_sleep_default_s3)
|
||||
if ((acpi_gbl_FADT.flags & ACPI_FADT_LOW_POWER_S0) &&
|
||||
mem_sleep_default > PM_SUSPEND_MEM && !acpi_sleep_default_s3) {
|
||||
mem_sleep_current = PM_SUSPEND_TO_IDLE;
|
||||
pr_info("Low-power S0 idle used by default for system suspend\n");
|
||||
}
|
||||
|
||||
/*
|
||||
* Some LPS0 systems, like ASUS Zenbook UX430UNR/i7-8550U, require the
|
||||
|
@ -379,7 +379,7 @@ static void hisi_lpc_acpi_fixup_child_resource(struct device *hostdev,
|
||||
|
||||
/*
|
||||
* hisi_lpc_acpi_set_io_res - set the resources for a child
|
||||
* @child: the device node to be updated the I/O resource
|
||||
* @adev: ACPI companion of the device node to be updated the I/O resource
|
||||
* @hostdev: the device node associated with host controller
|
||||
* @res: double pointer to be set to the address of translated resources
|
||||
* @num_res: pointer to variable to hold the number of translated resources
|
||||
@ -390,31 +390,24 @@ static void hisi_lpc_acpi_fixup_child_resource(struct device *hostdev,
|
||||
* host-relative address resource. This function will return the translated
|
||||
* logical PIO addresses for each child devices resources.
|
||||
*/
|
||||
static int hisi_lpc_acpi_set_io_res(struct device *child,
|
||||
static int hisi_lpc_acpi_set_io_res(struct acpi_device *adev,
|
||||
struct device *hostdev,
|
||||
const struct resource **res, int *num_res)
|
||||
{
|
||||
struct acpi_device *adev;
|
||||
struct acpi_device *host;
|
||||
struct acpi_device *host = to_acpi_device(adev->dev.parent);
|
||||
struct resource_entry *rentry;
|
||||
LIST_HEAD(resource_list);
|
||||
struct resource *resources;
|
||||
int count;
|
||||
int i;
|
||||
|
||||
if (!child || !hostdev)
|
||||
return -EINVAL;
|
||||
|
||||
host = to_acpi_device(hostdev);
|
||||
adev = to_acpi_device(child);
|
||||
|
||||
if (!adev->status.present) {
|
||||
dev_dbg(child, "device is not present\n");
|
||||
dev_dbg(&adev->dev, "device is not present\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (acpi_device_enumerated(adev)) {
|
||||
dev_dbg(child, "has been enumerated\n");
|
||||
dev_dbg(&adev->dev, "has been enumerated\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
@ -425,7 +418,7 @@ static int hisi_lpc_acpi_set_io_res(struct device *child,
|
||||
*/
|
||||
count = acpi_dev_get_resources(adev, &resource_list, NULL, NULL);
|
||||
if (count <= 0) {
|
||||
dev_dbg(child, "failed to get resources\n");
|
||||
dev_dbg(&adev->dev, "failed to get resources\n");
|
||||
return count ? count : -EIO;
|
||||
}
|
||||
|
||||
@ -454,7 +447,7 @@ static int hisi_lpc_acpi_set_io_res(struct device *child,
|
||||
continue;
|
||||
ret = hisi_lpc_acpi_xlat_io_res(adev, host, &resources[i]);
|
||||
if (ret) {
|
||||
dev_err(child, "translate IO range %pR failed (%d)\n",
|
||||
dev_err(&adev->dev, "translate IO range %pR failed (%d)\n",
|
||||
&resources[i], ret);
|
||||
return ret;
|
||||
}
|
||||
@ -471,6 +464,12 @@ static int hisi_lpc_acpi_remove_subdev(struct device *dev, void *unused)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int hisi_lpc_acpi_clear_enumerated(struct acpi_device *adev, void *not_used)
|
||||
{
|
||||
acpi_device_clear_enumerated(adev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct hisi_lpc_acpi_cell {
|
||||
const char *hid;
|
||||
const char *name;
|
||||
@ -480,13 +479,92 @@ struct hisi_lpc_acpi_cell {
|
||||
|
||||
static void hisi_lpc_acpi_remove(struct device *hostdev)
|
||||
{
|
||||
struct acpi_device *adev = ACPI_COMPANION(hostdev);
|
||||
struct acpi_device *child;
|
||||
|
||||
device_for_each_child(hostdev, NULL, hisi_lpc_acpi_remove_subdev);
|
||||
acpi_dev_for_each_child(ACPI_COMPANION(hostdev),
|
||||
hisi_lpc_acpi_clear_enumerated, NULL);
|
||||
}
|
||||
|
||||
list_for_each_entry(child, &adev->children, node)
|
||||
acpi_device_clear_enumerated(child);
|
||||
static int hisi_lpc_acpi_add_child(struct acpi_device *child, void *data)
|
||||
{
|
||||
const char *hid = acpi_device_hid(child);
|
||||
struct device *hostdev = data;
|
||||
const struct hisi_lpc_acpi_cell *cell;
|
||||
struct platform_device *pdev;
|
||||
const struct resource *res;
|
||||
bool found = false;
|
||||
int num_res;
|
||||
int ret;
|
||||
|
||||
ret = hisi_lpc_acpi_set_io_res(child, hostdev, &res, &num_res);
|
||||
if (ret) {
|
||||
dev_warn(hostdev, "set resource fail (%d)\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
cell = (struct hisi_lpc_acpi_cell []){
|
||||
/* ipmi */
|
||||
{
|
||||
.hid = "IPI0001",
|
||||
.name = "hisi-lpc-ipmi",
|
||||
},
|
||||
/* 8250-compatible uart */
|
||||
{
|
||||
.hid = "HISI1031",
|
||||
.name = "serial8250",
|
||||
.pdata = (struct plat_serial8250_port []) {
|
||||
{
|
||||
.iobase = res->start,
|
||||
.uartclk = 1843200,
|
||||
.iotype = UPIO_PORT,
|
||||
.flags = UPF_BOOT_AUTOCONF,
|
||||
},
|
||||
{}
|
||||
},
|
||||
.pdata_size = 2 *
|
||||
sizeof(struct plat_serial8250_port),
|
||||
},
|
||||
{}
|
||||
};
|
||||
|
||||
for (; cell && cell->name; cell++) {
|
||||
if (!strcmp(cell->hid, hid)) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
dev_warn(hostdev,
|
||||
"could not find cell for child device (%s), discarding\n",
|
||||
hid);
|
||||
return 0;
|
||||
}
|
||||
|
||||
pdev = platform_device_alloc(cell->name, PLATFORM_DEVID_AUTO);
|
||||
if (!pdev)
|
||||
return -ENOMEM;
|
||||
|
||||
pdev->dev.parent = hostdev;
|
||||
ACPI_COMPANION_SET(&pdev->dev, child);
|
||||
|
||||
ret = platform_device_add_resources(pdev, res, num_res);
|
||||
if (ret)
|
||||
goto fail;
|
||||
|
||||
ret = platform_device_add_data(pdev, cell->pdata, cell->pdata_size);
|
||||
if (ret)
|
||||
goto fail;
|
||||
|
||||
ret = platform_device_add(pdev);
|
||||
if (ret)
|
||||
goto fail;
|
||||
|
||||
acpi_device_set_enumerated(child);
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
platform_device_put(pdev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -501,94 +579,14 @@ static void hisi_lpc_acpi_remove(struct device *hostdev)
|
||||
*/
|
||||
static int hisi_lpc_acpi_probe(struct device *hostdev)
|
||||
{
|
||||
struct acpi_device *adev = ACPI_COMPANION(hostdev);
|
||||
struct acpi_device *child;
|
||||
int ret;
|
||||
|
||||
/* Only consider the children of the host */
|
||||
list_for_each_entry(child, &adev->children, node) {
|
||||
const char *hid = acpi_device_hid(child);
|
||||
const struct hisi_lpc_acpi_cell *cell;
|
||||
struct platform_device *pdev;
|
||||
const struct resource *res;
|
||||
bool found = false;
|
||||
int num_res;
|
||||
ret = acpi_dev_for_each_child(ACPI_COMPANION(hostdev),
|
||||
hisi_lpc_acpi_add_child, hostdev);
|
||||
if (ret)
|
||||
hisi_lpc_acpi_remove(hostdev);
|
||||
|
||||
ret = hisi_lpc_acpi_set_io_res(&child->dev, &adev->dev, &res,
|
||||
&num_res);
|
||||
if (ret) {
|
||||
dev_warn(hostdev, "set resource fail (%d)\n", ret);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
cell = (struct hisi_lpc_acpi_cell []){
|
||||
/* ipmi */
|
||||
{
|
||||
.hid = "IPI0001",
|
||||
.name = "hisi-lpc-ipmi",
|
||||
},
|
||||
/* 8250-compatible uart */
|
||||
{
|
||||
.hid = "HISI1031",
|
||||
.name = "serial8250",
|
||||
.pdata = (struct plat_serial8250_port []) {
|
||||
{
|
||||
.iobase = res->start,
|
||||
.uartclk = 1843200,
|
||||
.iotype = UPIO_PORT,
|
||||
.flags = UPF_BOOT_AUTOCONF,
|
||||
},
|
||||
{}
|
||||
},
|
||||
.pdata_size = 2 *
|
||||
sizeof(struct plat_serial8250_port),
|
||||
},
|
||||
{}
|
||||
};
|
||||
|
||||
for (; cell && cell->name; cell++) {
|
||||
if (!strcmp(cell->hid, hid)) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
dev_warn(hostdev,
|
||||
"could not find cell for child device (%s), discarding\n",
|
||||
hid);
|
||||
continue;
|
||||
}
|
||||
|
||||
pdev = platform_device_alloc(cell->name, PLATFORM_DEVID_AUTO);
|
||||
if (!pdev) {
|
||||
ret = -ENOMEM;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
pdev->dev.parent = hostdev;
|
||||
ACPI_COMPANION_SET(&pdev->dev, child);
|
||||
|
||||
ret = platform_device_add_resources(pdev, res, num_res);
|
||||
if (ret)
|
||||
goto fail;
|
||||
|
||||
ret = platform_device_add_data(pdev, cell->pdata,
|
||||
cell->pdata_size);
|
||||
if (ret)
|
||||
goto fail;
|
||||
|
||||
ret = platform_device_add(pdev);
|
||||
if (ret)
|
||||
goto fail;
|
||||
|
||||
acpi_device_set_enumerated(child);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
hisi_lpc_acpi_remove(hostdev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -60,12 +60,29 @@ int mfd_cell_disable(struct platform_device *pdev)
|
||||
EXPORT_SYMBOL(mfd_cell_disable);
|
||||
|
||||
#if IS_ENABLED(CONFIG_ACPI)
|
||||
struct match_ids_walk_data {
|
||||
struct acpi_device_id *ids;
|
||||
struct acpi_device *adev;
|
||||
};
|
||||
|
||||
static int match_device_ids(struct acpi_device *adev, void *data)
|
||||
{
|
||||
struct match_ids_walk_data *wd = data;
|
||||
|
||||
if (!acpi_match_device_ids(adev, wd->ids)) {
|
||||
wd->adev = adev;
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void mfd_acpi_add_device(const struct mfd_cell *cell,
|
||||
struct platform_device *pdev)
|
||||
{
|
||||
const struct mfd_cell_acpi_match *match = cell->acpi_match;
|
||||
struct acpi_device *parent, *child;
|
||||
struct acpi_device *adev = NULL;
|
||||
struct acpi_device *parent;
|
||||
|
||||
parent = ACPI_COMPANION(pdev->dev.parent);
|
||||
if (!parent)
|
||||
@ -83,14 +100,14 @@ static void mfd_acpi_add_device(const struct mfd_cell *cell,
|
||||
if (match) {
|
||||
if (match->pnpid) {
|
||||
struct acpi_device_id ids[2] = {};
|
||||
struct match_ids_walk_data wd = {
|
||||
.adev = NULL,
|
||||
.ids = ids,
|
||||
};
|
||||
|
||||
strlcpy(ids[0].id, match->pnpid, sizeof(ids[0].id));
|
||||
list_for_each_entry(child, &parent->children, node) {
|
||||
if (!acpi_match_device_ids(child, ids)) {
|
||||
adev = child;
|
||||
break;
|
||||
}
|
||||
}
|
||||
acpi_dev_for_each_child(parent, match_device_ids, &wd);
|
||||
adev = wd.adev;
|
||||
} else {
|
||||
adev = acpi_find_child_device(parent, match->adr, false);
|
||||
}
|
||||
|
@ -775,8 +775,8 @@ static int sdhci_acpi_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
const struct sdhci_acpi_slot *slot;
|
||||
struct acpi_device *device, *child;
|
||||
const struct dmi_system_id *id;
|
||||
struct acpi_device *device;
|
||||
struct sdhci_acpi_host *c;
|
||||
struct sdhci_host *host;
|
||||
struct resource *iomem;
|
||||
@ -796,10 +796,7 @@ static int sdhci_acpi_probe(struct platform_device *pdev)
|
||||
slot = sdhci_acpi_get_slot(device);
|
||||
|
||||
/* Power on the SDHCI controller and its children */
|
||||
acpi_device_fix_up_power(device);
|
||||
list_for_each_entry(child, &device->children, node)
|
||||
if (child->status.present && child->status.enabled)
|
||||
acpi_device_fix_up_power(child);
|
||||
acpi_device_fix_up_power_extended(device);
|
||||
|
||||
if (sdhci_acpi_byt_defer(dev))
|
||||
return -EPROBE_DEFER;
|
||||
|
@ -1240,16 +1240,11 @@ static const struct sdhci_pci_fixes sdhci_intel_byt_sd = {
|
||||
#ifdef CONFIG_ACPI
|
||||
static void intel_mrfld_mmc_fix_up_power_slot(struct sdhci_pci_slot *slot)
|
||||
{
|
||||
struct acpi_device *device, *child;
|
||||
struct acpi_device *device;
|
||||
|
||||
device = ACPI_COMPANION(&slot->chip->pdev->dev);
|
||||
if (!device)
|
||||
return;
|
||||
|
||||
acpi_device_fix_up_power(device);
|
||||
list_for_each_entry(child, &device->children, node)
|
||||
if (child->status.present && child->status.enabled)
|
||||
acpi_device_fix_up_power(child);
|
||||
if (device)
|
||||
acpi_device_fix_up_power_extended(device);
|
||||
}
|
||||
#else
|
||||
static inline void intel_mrfld_mmc_fix_up_power_slot(struct sdhci_pci_slot *slot) {}
|
||||
|
@ -6842,6 +6842,31 @@ static const struct backlight_ops ibm_backlight_data = {
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
static int __init tpacpi_evaluate_bcl(struct acpi_device *adev, void *not_used)
|
||||
{
|
||||
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
|
||||
union acpi_object *obj;
|
||||
acpi_status status;
|
||||
int rc;
|
||||
|
||||
status = acpi_evaluate_object(adev->handle, "_BCL", NULL, &buffer);
|
||||
if (ACPI_FAILURE(status))
|
||||
return 0;
|
||||
|
||||
obj = buffer.pointer;
|
||||
if (!obj || obj->type != ACPI_TYPE_PACKAGE) {
|
||||
acpi_handle_info(adev->handle,
|
||||
"Unknown _BCL data, please report this to %s\n",
|
||||
TPACPI_MAIL);
|
||||
rc = 0;
|
||||
} else {
|
||||
rc = obj->package.count;
|
||||
}
|
||||
kfree(obj);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* Call _BCL method of video device. On some ThinkPads this will
|
||||
* switch the firmware to the ACPI brightness control mode.
|
||||
@ -6849,37 +6874,13 @@ static const struct backlight_ops ibm_backlight_data = {
|
||||
|
||||
static int __init tpacpi_query_bcl_levels(acpi_handle handle)
|
||||
{
|
||||
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
|
||||
union acpi_object *obj;
|
||||
struct acpi_device *device, *child;
|
||||
int rc;
|
||||
struct acpi_device *device;
|
||||
|
||||
device = acpi_fetch_acpi_dev(handle);
|
||||
if (!device)
|
||||
return 0;
|
||||
|
||||
rc = 0;
|
||||
list_for_each_entry(child, &device->children, node) {
|
||||
acpi_status status = acpi_evaluate_object(child->handle, "_BCL",
|
||||
NULL, &buffer);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
buffer.length = ACPI_ALLOCATE_BUFFER;
|
||||
continue;
|
||||
}
|
||||
|
||||
obj = (union acpi_object *)buffer.pointer;
|
||||
if (!obj || (obj->type != ACPI_TYPE_PACKAGE)) {
|
||||
pr_err("Unknown _BCL data, please report this to %s\n",
|
||||
TPACPI_MAIL);
|
||||
rc = 0;
|
||||
} else {
|
||||
rc = obj->package.count;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
kfree(buffer.pointer);
|
||||
return rc;
|
||||
return acpi_dev_for_each_child(device, tpacpi_evaluate_bcl, NULL);
|
||||
}
|
||||
|
||||
|
||||
|
@ -127,6 +127,71 @@ static bool find_slave(struct sdw_bus *bus,
|
||||
return true;
|
||||
}
|
||||
|
||||
struct sdw_acpi_child_walk_data {
|
||||
struct sdw_bus *bus;
|
||||
struct acpi_device *adev;
|
||||
struct sdw_slave_id id;
|
||||
bool ignore_unique_id;
|
||||
};
|
||||
|
||||
static int sdw_acpi_check_duplicate(struct acpi_device *adev, void *data)
|
||||
{
|
||||
struct sdw_acpi_child_walk_data *cwd = data;
|
||||
struct sdw_bus *bus = cwd->bus;
|
||||
struct sdw_slave_id id;
|
||||
|
||||
if (adev == cwd->adev)
|
||||
return 0;
|
||||
|
||||
if (!find_slave(bus, adev, &id))
|
||||
return 0;
|
||||
|
||||
if (cwd->id.sdw_version != id.sdw_version || cwd->id.mfg_id != id.mfg_id ||
|
||||
cwd->id.part_id != id.part_id || cwd->id.class_id != id.class_id)
|
||||
return 0;
|
||||
|
||||
if (cwd->id.unique_id != id.unique_id) {
|
||||
dev_dbg(bus->dev,
|
||||
"Valid unique IDs 0x%x 0x%x for Slave mfg_id 0x%04x, part_id 0x%04x\n",
|
||||
cwd->id.unique_id, id.unique_id, cwd->id.mfg_id,
|
||||
cwd->id.part_id);
|
||||
cwd->ignore_unique_id = false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
dev_err(bus->dev,
|
||||
"Invalid unique IDs 0x%x 0x%x for Slave mfg_id 0x%04x, part_id 0x%04x\n",
|
||||
cwd->id.unique_id, id.unique_id, cwd->id.mfg_id, cwd->id.part_id);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
static int sdw_acpi_find_one(struct acpi_device *adev, void *data)
|
||||
{
|
||||
struct sdw_bus *bus = data;
|
||||
struct sdw_acpi_child_walk_data cwd = {
|
||||
.bus = bus,
|
||||
.adev = adev,
|
||||
.ignore_unique_id = true,
|
||||
};
|
||||
int ret;
|
||||
|
||||
if (!find_slave(bus, adev, &cwd.id))
|
||||
return 0;
|
||||
|
||||
/* Brute-force O(N^2) search for duplicates. */
|
||||
ret = acpi_dev_for_each_child(ACPI_COMPANION(bus->dev),
|
||||
sdw_acpi_check_duplicate, &cwd);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (cwd.ignore_unique_id)
|
||||
cwd.id.unique_id = SDW_IGNORED_UNIQUE_ID;
|
||||
|
||||
/* Ignore errors and continue. */
|
||||
sdw_slave_add(bus, &cwd.id, acpi_fwnode_handle(adev));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* sdw_acpi_find_slaves() - Find Slave devices in Master ACPI node
|
||||
* @bus: SDW bus instance
|
||||
@ -135,8 +200,7 @@ static bool find_slave(struct sdw_bus *bus,
|
||||
*/
|
||||
int sdw_acpi_find_slaves(struct sdw_bus *bus)
|
||||
{
|
||||
struct acpi_device *adev, *parent;
|
||||
struct acpi_device *adev2, *parent2;
|
||||
struct acpi_device *parent;
|
||||
|
||||
parent = ACPI_COMPANION(bus->dev);
|
||||
if (!parent) {
|
||||
@ -144,54 +208,7 @@ int sdw_acpi_find_slaves(struct sdw_bus *bus)
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
list_for_each_entry(adev, &parent->children, node) {
|
||||
struct sdw_slave_id id;
|
||||
struct sdw_slave_id id2;
|
||||
bool ignore_unique_id = true;
|
||||
|
||||
if (!find_slave(bus, adev, &id))
|
||||
continue;
|
||||
|
||||
/* brute-force O(N^2) search for duplicates */
|
||||
parent2 = parent;
|
||||
list_for_each_entry(adev2, &parent2->children, node) {
|
||||
|
||||
if (adev == adev2)
|
||||
continue;
|
||||
|
||||
if (!find_slave(bus, adev2, &id2))
|
||||
continue;
|
||||
|
||||
if (id.sdw_version != id2.sdw_version ||
|
||||
id.mfg_id != id2.mfg_id ||
|
||||
id.part_id != id2.part_id ||
|
||||
id.class_id != id2.class_id)
|
||||
continue;
|
||||
|
||||
if (id.unique_id != id2.unique_id) {
|
||||
dev_dbg(bus->dev,
|
||||
"Valid unique IDs 0x%x 0x%x for Slave mfg_id 0x%04x, part_id 0x%04x\n",
|
||||
id.unique_id, id2.unique_id, id.mfg_id, id.part_id);
|
||||
ignore_unique_id = false;
|
||||
} else {
|
||||
dev_err(bus->dev,
|
||||
"Invalid unique IDs 0x%x 0x%x for Slave mfg_id 0x%04x, part_id 0x%04x\n",
|
||||
id.unique_id, id2.unique_id, id.mfg_id, id.part_id);
|
||||
return -ENODEV;
|
||||
}
|
||||
}
|
||||
|
||||
if (ignore_unique_id)
|
||||
id.unique_id = SDW_IGNORED_UNIQUE_ID;
|
||||
|
||||
/*
|
||||
* don't error check for sdw_slave_add as we want to continue
|
||||
* adding Slaves
|
||||
*/
|
||||
sdw_slave_add(bus, &id, acpi_fwnode_handle(adev));
|
||||
}
|
||||
|
||||
return 0;
|
||||
return acpi_dev_for_each_child(parent, sdw_acpi_find_one, bus);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -301,37 +301,22 @@ static bool tb_acpi_bus_match(struct device *dev)
|
||||
return tb_is_switch(dev) || tb_is_usb4_port_device(dev);
|
||||
}
|
||||
|
||||
static struct acpi_device *tb_acpi_find_port(struct acpi_device *adev,
|
||||
const struct tb_port *port)
|
||||
{
|
||||
struct acpi_device *port_adev;
|
||||
|
||||
if (!adev)
|
||||
return NULL;
|
||||
|
||||
/*
|
||||
* Device routers exists under the downstream facing USB4 port
|
||||
* of the parent router. Their _ADR is always 0.
|
||||
*/
|
||||
list_for_each_entry(port_adev, &adev->children, node) {
|
||||
if (acpi_device_adr(port_adev) == port->port)
|
||||
return port_adev;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct acpi_device *tb_acpi_switch_find_companion(struct tb_switch *sw)
|
||||
{
|
||||
struct acpi_device *adev = NULL;
|
||||
struct tb_switch *parent_sw;
|
||||
|
||||
/*
|
||||
* Device routers exists under the downstream facing USB4 port
|
||||
* of the parent router. Their _ADR is always 0.
|
||||
*/
|
||||
parent_sw = tb_switch_parent(sw);
|
||||
if (parent_sw) {
|
||||
struct tb_port *port = tb_port_at(tb_route(sw), parent_sw);
|
||||
struct acpi_device *port_adev;
|
||||
|
||||
port_adev = tb_acpi_find_port(ACPI_COMPANION(&parent_sw->dev), port);
|
||||
port_adev = acpi_find_child_by_adr(ACPI_COMPANION(&parent_sw->dev),
|
||||
port->port);
|
||||
if (port_adev)
|
||||
adev = acpi_find_child_device(port_adev, 0, false);
|
||||
} else {
|
||||
@ -364,8 +349,8 @@ static struct acpi_device *tb_acpi_find_companion(struct device *dev)
|
||||
if (tb_is_switch(dev))
|
||||
return tb_acpi_switch_find_companion(tb_to_switch(dev));
|
||||
else if (tb_is_usb4_port_device(dev))
|
||||
return tb_acpi_find_port(ACPI_COMPANION(dev->parent),
|
||||
tb_to_usb4_port_device(dev)->port);
|
||||
return acpi_find_child_by_adr(ACPI_COMPANION(dev->parent),
|
||||
tb_to_usb4_port_device(dev)->port->port);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -124,22 +124,6 @@ out:
|
||||
*/
|
||||
#define USB_ACPI_LOCATION_VALID (1 << 31)
|
||||
|
||||
static struct acpi_device *usb_acpi_find_port(struct acpi_device *parent,
|
||||
int raw)
|
||||
{
|
||||
struct acpi_device *adev;
|
||||
|
||||
if (!parent)
|
||||
return NULL;
|
||||
|
||||
list_for_each_entry(adev, &parent->children, node) {
|
||||
if (acpi_device_adr(adev) == raw)
|
||||
return adev;
|
||||
}
|
||||
|
||||
return acpi_find_child_device(parent, raw, false);
|
||||
}
|
||||
|
||||
static struct acpi_device *
|
||||
usb_acpi_get_companion_for_port(struct usb_port *port_dev)
|
||||
{
|
||||
@ -170,7 +154,7 @@ usb_acpi_get_companion_for_port(struct usb_port *port_dev)
|
||||
port1 = port_dev->portnum;
|
||||
}
|
||||
|
||||
return usb_acpi_find_port(adev, port1);
|
||||
return acpi_find_child_by_adr(adev, port1);
|
||||
}
|
||||
|
||||
static struct acpi_device *
|
||||
|
@ -365,8 +365,6 @@ struct acpi_device {
|
||||
acpi_handle handle; /* no handle for fixed hardware */
|
||||
struct fwnode_handle fwnode;
|
||||
struct acpi_device *parent;
|
||||
struct list_head children;
|
||||
struct list_head node;
|
||||
struct list_head wakeup_list;
|
||||
struct list_head del_list;
|
||||
struct acpi_device_status status;
|
||||
@ -379,7 +377,6 @@ struct acpi_device {
|
||||
struct acpi_device_data data;
|
||||
struct acpi_scan_handler *handler;
|
||||
struct acpi_hotplug_context *hp;
|
||||
struct acpi_driver *driver;
|
||||
const struct acpi_gpio_mapping *driver_gpios;
|
||||
void *driver_data;
|
||||
struct device dev;
|
||||
@ -483,6 +480,9 @@ extern struct bus_type acpi_bus_type;
|
||||
int acpi_bus_for_each_dev(int (*fn)(struct device *, void *), void *data);
|
||||
int acpi_dev_for_each_child(struct acpi_device *adev,
|
||||
int (*fn)(struct acpi_device *, void *), void *data);
|
||||
int acpi_dev_for_each_child_reverse(struct acpi_device *adev,
|
||||
int (*fn)(struct acpi_device *, void *),
|
||||
void *data);
|
||||
|
||||
/*
|
||||
* Events
|
||||
@ -521,6 +521,7 @@ const char *acpi_power_state_string(int state);
|
||||
int acpi_device_set_power(struct acpi_device *device, int state);
|
||||
int acpi_bus_init_power(struct acpi_device *device);
|
||||
int acpi_device_fix_up_power(struct acpi_device *device);
|
||||
void acpi_device_fix_up_power_extended(struct acpi_device *adev);
|
||||
int acpi_bus_update_power(acpi_handle handle, int *state_p);
|
||||
int acpi_device_update_power(struct acpi_device *device, int *state_p);
|
||||
bool acpi_bus_power_manageable(acpi_handle handle);
|
||||
@ -622,6 +623,8 @@ static inline int acpi_dma_configure(struct device *dev,
|
||||
}
|
||||
struct acpi_device *acpi_find_child_device(struct acpi_device *parent,
|
||||
u64 address, bool check_children);
|
||||
struct acpi_device *acpi_find_child_by_adr(struct acpi_device *adev,
|
||||
acpi_bus_address adr);
|
||||
int acpi_is_root_bridge(acpi_handle);
|
||||
struct acpi_pci_root *acpi_pci_find_root(acpi_handle handle);
|
||||
|
||||
|
@ -17,7 +17,7 @@
|
||||
#include <acpi/pcc.h>
|
||||
#include <acpi/processor.h>
|
||||
|
||||
/* Support CPPCv2 and CPPCv3 */
|
||||
/* CPPCv2 and CPPCv3 support */
|
||||
#define CPPC_V2_REV 2
|
||||
#define CPPC_V3_REV 3
|
||||
#define CPPC_V2_NUM_ENT 21
|
||||
|
@ -441,9 +441,12 @@ static inline int acpi_processor_hotplug(struct acpi_processor *pr)
|
||||
#endif /* CONFIG_ACPI_PROCESSOR_IDLE */
|
||||
|
||||
/* in processor_thermal.c */
|
||||
int acpi_processor_get_limit_info(struct acpi_processor *pr);
|
||||
int acpi_processor_thermal_init(struct acpi_processor *pr,
|
||||
struct acpi_device *device);
|
||||
void acpi_processor_thermal_exit(struct acpi_processor *pr,
|
||||
struct acpi_device *device);
|
||||
extern const struct thermal_cooling_device_ops processor_cooling_ops;
|
||||
#if defined(CONFIG_ACPI_CPU_FREQ_PSS) & defined(CONFIG_CPU_FREQ)
|
||||
#ifdef CONFIG_CPU_FREQ
|
||||
void acpi_thermal_cpufreq_init(struct cpufreq_policy *policy);
|
||||
void acpi_thermal_cpufreq_exit(struct cpufreq_policy *policy);
|
||||
#else
|
||||
@ -455,6 +458,6 @@ static inline void acpi_thermal_cpufreq_exit(struct cpufreq_policy *policy)
|
||||
{
|
||||
return;
|
||||
}
|
||||
#endif /* CONFIG_ACPI_CPU_FREQ_PSS */
|
||||
#endif /* CONFIG_CPU_FREQ */
|
||||
|
||||
#endif
|
||||
|
@ -6,9 +6,11 @@
|
||||
#include <linux/acpi.h>
|
||||
|
||||
#ifdef CONFIG_ACPI_VIOT
|
||||
void __init acpi_viot_early_init(void);
|
||||
void __init acpi_viot_init(void);
|
||||
int viot_iommu_configure(struct device *dev);
|
||||
#else
|
||||
static inline void acpi_viot_early_init(void) {}
|
||||
static inline void acpi_viot_init(void) {}
|
||||
static inline int viot_iommu_configure(struct device *dev)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user