From 892a012699fc0b91a2ed6309078936191447f480 Mon Sep 17 00:00:00 2001 From: Hui Wang Date: Wed, 15 Sep 2021 21:09:05 +0800 Subject: ACPI: resources: Add DMI-based legacy IRQ override quirk After the commit 0ec4e55e9f57 ("ACPI: resources: Add checks for ACPI IRQ override") is reverted, the keyboard on Medion laptops can't work again. To fix the keyboard issue, add a DMI-based override check that will not affect other machines along the lines of prt_quirks[] in drivers/acpi/pci_irq.c. If similar issues are seen on other platforms, the quirk table could be expanded in the future. BugLink: https://bugzilla.kernel.org/show_bug.cgi?id=213031 BugLink: http://bugs.launchpad.net/bugs/1909814 Suggested-by: Rafael J. Wysocki Reported-by: Manuel Krause Tested-by: Manuel Krause Signed-off-by: Hui Wang [ rjw: Subject and changelog edits ] Signed-off-by: Rafael J. Wysocki --- drivers/acpi/resource.c | 49 +++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 47 insertions(+), 2 deletions(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/resource.c b/drivers/acpi/resource.c index ee78a210c606..7bf38652e6ac 100644 --- a/drivers/acpi/resource.c +++ b/drivers/acpi/resource.c @@ -16,6 +16,7 @@ #include #include #include +#include #ifdef CONFIG_X86 #define valid_IRQ(i) (((i) != 0) && ((i) != 2)) @@ -380,9 +381,51 @@ unsigned int acpi_dev_get_irq_type(int triggering, int polarity) } EXPORT_SYMBOL_GPL(acpi_dev_get_irq_type); +static const struct dmi_system_id medion_laptop[] = { + { + .ident = "MEDION P15651", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "MEDION"), + DMI_MATCH(DMI_BOARD_NAME, "M15T"), + }, + }, + { } +}; + +struct irq_override_cmp { + const struct dmi_system_id *system; + unsigned char irq; + unsigned char triggering; + unsigned char polarity; + unsigned char shareable; +}; + +static const struct irq_override_cmp skip_override_table[] = { + { medion_laptop, 1, ACPI_LEVEL_SENSITIVE, ACPI_ACTIVE_LOW, 0 }, +}; + +static bool acpi_dev_irq_override(u32 gsi, u8 triggering, u8 polarity, + u8 shareable) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(skip_override_table); i++) { + const struct irq_override_cmp *entry = &skip_override_table[i]; + + if (dmi_check_system(entry->system) && + entry->irq == gsi && + entry->triggering == triggering && + entry->polarity == polarity && + entry->shareable == shareable) + return false; + } + + return true; +} + static void acpi_dev_get_irqresource(struct resource *res, u32 gsi, u8 triggering, u8 polarity, u8 shareable, - bool legacy) + bool check_override) { int irq, p, t; @@ -401,7 +444,9 @@ static void acpi_dev_get_irqresource(struct resource *res, u32 gsi, * using extended IRQ descriptors we take the IRQ configuration * from _CRS directly. */ - if (legacy && !acpi_get_override_irq(gsi, &t, &p)) { + if (check_override && + acpi_dev_irq_override(gsi, triggering, polarity, shareable) && + !acpi_get_override_irq(gsi, &t, &p)) { u8 trig = t ? ACPI_LEVEL_SENSITIVE : ACPI_EDGE_SENSITIVE; u8 pol = p ? ACPI_ACTIVE_LOW : ACPI_ACTIVE_HIGH; -- cgit v1.2.3 From 6c7058a38dc4e2dee43cd824067b7610b57463ba Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Thu, 16 Sep 2021 19:00:54 +0200 Subject: ACPI: PNP: remove duplicated BRI0A49 and BDP3336 entries BRI0A49 and BDP3336 are already on the list. Signed-off-by: Krzysztof Kozlowski Reviewed-by: Hans de Goede Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpi_pnp.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/acpi_pnp.c b/drivers/acpi/acpi_pnp.c index 8f2dc176bb41..ffdcfcd4a10d 100644 --- a/drivers/acpi/acpi_pnp.c +++ b/drivers/acpi/acpi_pnp.c @@ -156,8 +156,6 @@ static const struct acpi_device_id acpi_pnp_device_ids[] = { {"BRI0A49"}, /* Boca Complete Ofc Communicator 14.4 Data-FAX */ {"BRI1400"}, /* Boca Research 33,600 ACF Modem */ {"BRI3400"}, /* Boca 33.6 Kbps Internal FD34FSVD */ - {"BRI0A49"}, /* Boca 33.6 Kbps Internal FD34FSVD */ - {"BDP3336"}, /* Best Data Products Inc. Smart One 336F PnP Modem */ {"CPI4050"}, /* Computer Peripherals Inc. EuroViVa CommCenter-33.6 SP PnP */ {"CTL3001"}, /* Creative Labs Phone Blaster 28.8 DSVD PnP Voice */ {"CTL3011"}, /* Creative Labs Modem Blaster 28.8 DSVD PnP Voice */ -- cgit v1.2.3 From c117dffff4320b312f068ef6e64a7a4482d641a0 Mon Sep 17 00:00:00 2001 From: Masanari Iida Date: Tue, 21 Sep 2021 15:21:24 +0900 Subject: ACPI: Kconfig: Fix a typo in Kconfig This patch fixes a spelling typo in acpi/Kconfig Signed-off-by: Masanari Iida Signed-off-by: Rafael J. Wysocki --- drivers/acpi/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig index 1da360c51d66..cdbdf68bd98f 100644 --- a/drivers/acpi/Kconfig +++ b/drivers/acpi/Kconfig @@ -71,7 +71,7 @@ config ACPI_DEBUGGER if ACPI_DEBUGGER config ACPI_DEBUGGER_USER - tristate "Userspace debugger accessiblity" + tristate "Userspace debugger accessibility" depends on DEBUG_FS help Export /sys/kernel/debug/acpi/acpidbg for userspace utilities -- cgit v1.2.3 From d6b88ce2eb9d2698eb24451eb92c0a1649b17bb1 Mon Sep 17 00:00:00 2001 From: Richard Gong Date: Wed, 22 Sep 2021 08:31:16 -0500 Subject: ACPI: processor idle: Allow playing dead in C3 state When some cores are disabled on AMD platforms, the system will no longer be able to enter suspend-to-idle s0ix. Update to allow playing dead in C3 state so that the CPUs can enter the deepest state on AMD platforms. BugLink: https://gitlab.freedesktop.org/drm/amd/-/issues/1708 Suggested-by: Mario Limonciello Signed-off-by: Richard Gong [ rjw: Fixed coding style ] Signed-off-by: Rafael J. Wysocki --- drivers/acpi/processor_idle.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index f37fba9e5ba0..76ef1bcc8848 100644 --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c @@ -789,7 +789,8 @@ static int acpi_processor_setup_cstates(struct acpi_processor *pr) state->enter = acpi_idle_enter; state->flags = 0; - if (cx->type == ACPI_STATE_C1 || cx->type == ACPI_STATE_C2) { + if (cx->type == ACPI_STATE_C1 || cx->type == ACPI_STATE_C2 || + cx->type == ACPI_STATE_C3) { state->enter_dead = acpi_idle_play_dead; drv->safe_state_index = count; } -- cgit v1.2.3 From 4795448117824cc4900d696f17d1516c56371045 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sat, 18 Sep 2021 14:53:44 +0200 Subject: PCI: ACPI: Drop acpi_pci_bus The acpi_pci_bus structure was used primarily for running acpi_pci_find_companion() during PCI device objects registration, but after commit 375553a93201 ("PCI: Setup ACPI fwnode early and at the same time with OF") that function is called by pci_setup_device() via pci_set_acpi_fwnode(), which happens before calling pci_device_add() on the new PCI device object, so its ACPI companion has been set already when acpi_device_notify() runs and it will never call ->find_companion() from acpi_pci_bus. For this reason, modify acpi_device_notify() and acpi_device_notify_remove() to call pci_acpi_setup() and pci_acpi_cleanup(), respectively, directly on PCI device objects and drop acpi_pci_bus altogether. While at it, notice that pci_acpi_setup() and pci_acpi_cleanup() can obtain the ACPI companion pointer, which is guaranteed to not be NULL, from their callers and modify them to work that way so as to reduce the number of redundant checks somewhat. Signed-off-by: Rafael J. Wysocki Tested-by: Ferry Toth --- drivers/acpi/glue.c | 34 ++++++++++++++++++++++------------ 1 file changed, 22 insertions(+), 12 deletions(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c index 7a33a6d985f8..68768d6c8a47 100644 --- a/drivers/acpi/glue.c +++ b/drivers/acpi/glue.c @@ -17,6 +17,8 @@ #include #include #include +#include +#include #include #include "internal.h" @@ -307,13 +309,17 @@ void acpi_device_notify(struct device *dev) } adev = ACPI_COMPANION(dev); - if (dev_is_platform(dev)) - acpi_configure_pmsi_domain(dev); + if (dev_is_pci(dev)) { + pci_acpi_setup(dev, adev); + } else { + if (dev_is_platform(dev)) + acpi_configure_pmsi_domain(dev); - if (type && type->setup) - type->setup(dev); - else if (adev->handler && adev->handler->bind) - adev->handler->bind(dev); + if (type && type->setup) + type->setup(dev); + else if (adev->handler && adev->handler->bind) + adev->handler->bind(dev); + } acpi_handle_debug(ACPI_HANDLE(dev), "Bound to device %s\n", dev_name(dev)); @@ -327,16 +333,20 @@ err: void acpi_device_notify_remove(struct device *dev) { struct acpi_device *adev = ACPI_COMPANION(dev); - struct acpi_bus_type *type; if (!adev) return; - type = acpi_get_bus_type(dev); - if (type && type->cleanup) - type->cleanup(dev); - else if (adev->handler && adev->handler->unbind) - adev->handler->unbind(dev); + if (dev_is_pci(dev)) { + pci_acpi_cleanup(dev, adev); + } else { + struct acpi_bus_type *type = acpi_get_bus_type(dev); + + if (type && type->cleanup) + type->cleanup(dev); + else if (adev->handler && adev->handler->unbind) + adev->handler->unbind(dev); + } acpi_unbind_one(dev); } -- cgit v1.2.3 From c4d19838d8c42828c7e39e4432ea5b33f02dac27 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sat, 18 Sep 2021 14:56:17 +0200 Subject: ACPI: glue: Drop cleanup callback from struct acpi_bus_type Since PCI was the only user of the ->cleanup callback in struct acpi_bus_type and it is not using struct acpi_bus_type any more, drop that callback from there and update acpi_device_notify_remove() accordingly. Signed-off-by: Rafael J. Wysocki Tested-by: Ferry Toth --- drivers/acpi/glue.c | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c index 68768d6c8a47..49aaf18243f6 100644 --- a/drivers/acpi/glue.c +++ b/drivers/acpi/glue.c @@ -337,16 +337,10 @@ void acpi_device_notify_remove(struct device *dev) if (!adev) return; - if (dev_is_pci(dev)) { + if (dev_is_pci(dev)) pci_acpi_cleanup(dev, adev); - } else { - struct acpi_bus_type *type = acpi_get_bus_type(dev); - - if (type && type->cleanup) - type->cleanup(dev); - else if (adev->handler && adev->handler->unbind) - adev->handler->unbind(dev); - } + else if (adev->handler && adev->handler->unbind) + adev->handler->unbind(dev); acpi_unbind_one(dev); } -- cgit v1.2.3 From 2ef5236660b677db15527b6d6235af4ce38ea0e3 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sat, 18 Sep 2021 15:02:23 +0200 Subject: ACPI: glue: Look for ACPI bus type only if ACPI companion is not known Notice that it is not necessary to look for the "ACPI bus type" of the device in acpi_device_notify() if the device's ACPI companion is set upfront, so modify the code to do that lookup only if it is necessary to find the ACPI companion. Also notice that if the device's ACPI companion is not set upfront in acpi_device_notify(), the device cannot be either a PCI one or a platform one, so check for these bus types only if the device's ACPI companion is set. Signed-off-by: Rafael J. Wysocki Tested-by: Ferry Toth --- drivers/acpi/glue.c | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c index 49aaf18243f6..17ec6e57c4b7 100644 --- a/drivers/acpi/glue.c +++ b/drivers/acpi/glue.c @@ -289,12 +289,13 @@ EXPORT_SYMBOL_GPL(acpi_unbind_one); void acpi_device_notify(struct device *dev) { - struct acpi_bus_type *type = acpi_get_bus_type(dev); struct acpi_device *adev; int ret; ret = acpi_bind_one(dev, NULL); if (ret) { + struct acpi_bus_type *type = acpi_get_bus_type(dev); + if (!type) goto err; @@ -306,21 +307,26 @@ void acpi_device_notify(struct device *dev) ret = acpi_bind_one(dev, adev); if (ret) goto err; - } - adev = ACPI_COMPANION(dev); - if (dev_is_pci(dev)) { - pci_acpi_setup(dev, adev); + if (type->setup) { + type->setup(dev); + goto done; + } } else { - if (dev_is_platform(dev)) - acpi_configure_pmsi_domain(dev); + adev = ACPI_COMPANION(dev); - if (type && type->setup) - type->setup(dev); - else if (adev->handler && adev->handler->bind) - adev->handler->bind(dev); + if (dev_is_pci(dev)) { + pci_acpi_setup(dev, adev); + goto done; + } else if (dev_is_platform(dev)) { + acpi_configure_pmsi_domain(dev); + } } + if (adev->handler && adev->handler->bind) + adev->handler->bind(dev); + +done: acpi_handle_debug(ACPI_HANDLE(dev), "Bound to device %s\n", dev_name(dev)); -- cgit v1.2.3 From d3c4b6f64ad356c0d9ddbcf73fa471e6a841cc5c Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Wed, 29 Sep 2021 18:31:25 +0200 Subject: ACPICA: Avoid evaluating methods too early during system resume ACPICA commit 0762982923f95eb652cf7ded27356b247c9774de During wakeup from system-wide sleep states, acpi_get_sleep_type_data() is called and it tries to get memory from the slab allocator in order to evaluate a control method, but if KFENCE is enabled in the kernel, the memory allocation attempt causes an IRQ work to be queued and a self-IPI to be sent to the CPU running the code which requires the memory controller to be ready, so if that happens too early in the wakeup path, it doesn't work. Prevent that from taking place by calling acpi_get_sleep_type_data() for S0 upfront, when preparing to enter a given sleep state, and saving the data obtained by it for later use during system wakeup. BugLink: https://bugzilla.kernel.org/show_bug.cgi?id=214271 Reported-by: Reik Keutterling Tested-by: Reik Keutterling Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/acglobal.h | 2 ++ drivers/acpi/acpica/hwesleep.c | 8 ++------ drivers/acpi/acpica/hwsleep.c | 11 ++++------- drivers/acpi/acpica/hwxfsleep.c | 7 +++++++ 4 files changed, 15 insertions(+), 13 deletions(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/acpica/acglobal.h b/drivers/acpi/acpica/acglobal.h index d41b810e367c..4366d36ef119 100644 --- a/drivers/acpi/acpica/acglobal.h +++ b/drivers/acpi/acpica/acglobal.h @@ -226,6 +226,8 @@ extern struct acpi_bit_register_info acpi_gbl_bit_register_info[ACPI_NUM_BITREG]; ACPI_GLOBAL(u8, acpi_gbl_sleep_type_a); ACPI_GLOBAL(u8, acpi_gbl_sleep_type_b); +ACPI_GLOBAL(u8, acpi_gbl_sleep_type_a_s0); +ACPI_GLOBAL(u8, acpi_gbl_sleep_type_b_s0); /***************************************************************************** * diff --git a/drivers/acpi/acpica/hwesleep.c b/drivers/acpi/acpica/hwesleep.c index 803402aefaeb..808fdf54aeeb 100644 --- a/drivers/acpi/acpica/hwesleep.c +++ b/drivers/acpi/acpica/hwesleep.c @@ -147,17 +147,13 @@ acpi_status acpi_hw_extended_sleep(u8 sleep_state) acpi_status acpi_hw_extended_wake_prep(u8 sleep_state) { - acpi_status status; u8 sleep_type_value; ACPI_FUNCTION_TRACE(hw_extended_wake_prep); - status = acpi_get_sleep_type_data(ACPI_STATE_S0, - &acpi_gbl_sleep_type_a, - &acpi_gbl_sleep_type_b); - if (ACPI_SUCCESS(status)) { + if (acpi_gbl_sleep_type_a_s0 != ACPI_SLEEP_TYPE_INVALID) { sleep_type_value = - ((acpi_gbl_sleep_type_a << ACPI_X_SLEEP_TYPE_POSITION) & + ((acpi_gbl_sleep_type_a_s0 << ACPI_X_SLEEP_TYPE_POSITION) & ACPI_X_SLEEP_TYPE_MASK); (void)acpi_write((u64)(sleep_type_value | ACPI_X_SLEEP_ENABLE), diff --git a/drivers/acpi/acpica/hwsleep.c b/drivers/acpi/acpica/hwsleep.c index 14baa13bf848..34a3825f25d3 100644 --- a/drivers/acpi/acpica/hwsleep.c +++ b/drivers/acpi/acpica/hwsleep.c @@ -179,7 +179,7 @@ acpi_status acpi_hw_legacy_sleep(u8 sleep_state) acpi_status acpi_hw_legacy_wake_prep(u8 sleep_state) { - acpi_status status; + acpi_status status = AE_OK; struct acpi_bit_register_info *sleep_type_reg_info; struct acpi_bit_register_info *sleep_enable_reg_info; u32 pm1a_control; @@ -192,10 +192,7 @@ acpi_status acpi_hw_legacy_wake_prep(u8 sleep_state) * This is unclear from the ACPI Spec, but it is required * by some machines. */ - status = acpi_get_sleep_type_data(ACPI_STATE_S0, - &acpi_gbl_sleep_type_a, - &acpi_gbl_sleep_type_b); - if (ACPI_SUCCESS(status)) { + if (acpi_gbl_sleep_type_a_s0 != ACPI_SLEEP_TYPE_INVALID) { sleep_type_reg_info = acpi_hw_get_bit_register_info(ACPI_BITREG_SLEEP_TYPE); sleep_enable_reg_info = @@ -216,9 +213,9 @@ acpi_status acpi_hw_legacy_wake_prep(u8 sleep_state) /* Insert the SLP_TYP bits */ - pm1a_control |= (acpi_gbl_sleep_type_a << + pm1a_control |= (acpi_gbl_sleep_type_a_s0 << sleep_type_reg_info->bit_position); - pm1b_control |= (acpi_gbl_sleep_type_b << + pm1b_control |= (acpi_gbl_sleep_type_b_s0 << sleep_type_reg_info->bit_position); /* Write the control registers and ignore any errors */ diff --git a/drivers/acpi/acpica/hwxfsleep.c b/drivers/acpi/acpica/hwxfsleep.c index 89b12afed564..e4cde23a2906 100644 --- a/drivers/acpi/acpica/hwxfsleep.c +++ b/drivers/acpi/acpica/hwxfsleep.c @@ -217,6 +217,13 @@ acpi_status acpi_enter_sleep_state_prep(u8 sleep_state) return_ACPI_STATUS(status); } + status = acpi_get_sleep_type_data(ACPI_STATE_S0, + &acpi_gbl_sleep_type_a_s0, + &acpi_gbl_sleep_type_b_s0); + if (ACPI_FAILURE(status)) { + acpi_gbl_sleep_type_a_s0 = ACPI_SLEEP_TYPE_INVALID; + } + /* Execute the _PTS method (Prepare To Sleep) */ arg_list.count = 1; -- cgit v1.2.3 From 3bf70bd2538f0515ce17b1c067889ff0e4fec842 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Fri, 1 Oct 2021 20:14:47 +0200 Subject: ACPICA: Add support for Windows 2020 _OSI string ACPICA commit 2dc55de56d2deac30af0b484dd1d65607eb33a9c Link: https://github.com/microsoft_docs/windows-driver-docs/commit/5164e24985e78ef4870d7a5801a5336104f36366 Link: https://github.com/acpica/acpica/commit/2dc55de5 Signed-off-by: Mario Limonciello Signed-off-by: Bob Moore Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/utosi.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/acpi') diff --git a/drivers/acpi/acpica/utosi.c b/drivers/acpi/acpica/utosi.c index 7b8e8bf1e824..8afa1ccaf12e 100644 --- a/drivers/acpi/acpica/utosi.c +++ b/drivers/acpi/acpica/utosi.c @@ -73,6 +73,7 @@ static struct acpi_interface_info acpi_default_supported_interfaces[] = { {"Windows 2018", NULL, 0, ACPI_OSI_WIN_10_RS4}, /* Windows 10 version 1803 - Added 11/2018 */ {"Windows 2018.2", NULL, 0, ACPI_OSI_WIN_10_RS5}, /* Windows 10 version 1809 - Added 11/2018 */ {"Windows 2019", NULL, 0, ACPI_OSI_WIN_10_19H1}, /* Windows 10 version 1903 - Added 08/2019 */ + {"Windows 2020", NULL, 0, ACPI_OSI_WIN_10_20H1}, /* Windows 10 version 2004 - Added 08/2021 */ /* Feature Group Strings */ -- cgit v1.2.3 From 2835f327bd1240508db2c89fe94a056faa53c49a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Almeida?= Date: Fri, 8 Oct 2021 00:05:29 -0300 Subject: ACPI: battery: Accept charges over the design capacity as full MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some buggy firmware and/or brand new batteries can support a charge that's slightly over the reported design capacity. In such cases, the kernel will report to userspace that the charging state of the battery is "Unknown", when in reality the battery charge is "Full", at least from the design capacity point of view. Make the fallback condition accepts capacities over the designed capacity so userspace knows that is full. Signed-off-by: André Almeida Reviewed-by: Hans de Goede Reviewed-by: Sebastian Reichel Signed-off-by: Rafael J. Wysocki --- drivers/acpi/battery.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c index dae91f906cea..8afa85d6eb6a 100644 --- a/drivers/acpi/battery.c +++ b/drivers/acpi/battery.c @@ -169,7 +169,7 @@ static int acpi_battery_is_charged(struct acpi_battery *battery) return 1; /* fallback to using design values for broken batteries */ - if (battery->design_capacity == battery->capacity_now) + if (battery->design_capacity <= battery->capacity_now) return 1; /* we don't do any sort of metric based on percentages */ -- cgit v1.2.3 From c10383e8ddf4810b9a5c1595404c2724d925a0a6 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sat, 9 Oct 2021 16:22:09 +0200 Subject: ACPI: scan: Release PM resources blocked by unused objects On some systems the ACPI namespace contains device objects that are not used in certain configurations of the system. If they start off in the D0 power state configuration, they will stay in it until the system reboots, because of the lack of any mechanism possibly causing their configuration to change. If that happens, they may prevent some power resources from being turned off or generally they may prevent the platform from getting into the deepest low-power states thus causing some energy to be wasted. Address this issue by changing the configuration of unused ACPI device objects to the D3cold power state one after carrying out the ACPI-based enumeration of devices. BugLink: https://bugzilla.kernel.org/show_bug.cgi?id=214091 Link: https://lore.kernel.org/linux-acpi/20211007205126.11769-1-mario.limonciello@amd.com/ Reported-by: Mario Limonciello Signed-off-by: Rafael J. Wysocki Tested-by: Mario Limonciello --- drivers/acpi/glue.c | 25 +++++++++++++++++++++++++ drivers/acpi/internal.h | 1 + drivers/acpi/scan.c | 6 ++++++ 3 files changed, 32 insertions(+) (limited to 'drivers/acpi') diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c index 7a33a6d985f8..1cfafa254e3d 100644 --- a/drivers/acpi/glue.c +++ b/drivers/acpi/glue.c @@ -340,3 +340,28 @@ void acpi_device_notify_remove(struct device *dev) acpi_unbind_one(dev); } + +int acpi_dev_turn_off_if_unused(struct device *dev, void *not_used) +{ + struct acpi_device *adev = to_acpi_device(dev); + + /* + * Skip device objects with device IDs, because they may be in use even + * if they are not companions of any physical device objects. + */ + if (adev->pnp.type.hardware_id) + return 0; + + mutex_lock(&adev->physical_node_lock); + + /* + * Device objects without device IDs are not in use if they have no + * corresponding physical device objects. + */ + if (list_empty(&adev->physical_node_list)) + acpi_device_set_power(adev, ACPI_STATE_D3_COLD); + + mutex_unlock(&adev->physical_node_lock); + + return 0; +} diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h index d91b560e8867..8fbdc172864b 100644 --- a/drivers/acpi/internal.h +++ b/drivers/acpi/internal.h @@ -117,6 +117,7 @@ bool acpi_device_is_battery(struct acpi_device *adev); bool acpi_device_is_first_physical_node(struct acpi_device *adev, const struct device *dev); int acpi_bus_register_early_device(int type); +int acpi_dev_turn_off_if_unused(struct device *dev, void *not_used); /* -------------------------------------------------------------------------- Device Matching and Notification diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 5b54c80b9d32..770b82483d74 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -2559,6 +2559,12 @@ int __init acpi_scan_init(void) } } + /* + * Make sure that power management resources are not blocked by ACPI + * device objects with no users. + */ + bus_for_each_dev(&acpi_bus_type, NULL, NULL, acpi_dev_turn_off_if_unused); + acpi_turn_off_unused_power_resources(); acpi_scan_initialized = true; -- cgit v1.2.3 From 50861d439b9386d9f2cfafc12f2c0d0d14569df9 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sun, 10 Oct 2021 19:23:01 +0200 Subject: ACPI: LPSS: Use ACPI_COMPANION() directly The ACPI_HANDLE() macro returns the ACPI handle of the ACPI device object returned by the ACPI_COMPANION() macro, so it is more straightforward to call the latter directly instead of passing the handle produced by the former to acpi_bus_get_device(). Modify the code accordingly (no intentional functional impact). Signed-off-by: Rafael J. Wysocki Reviewed-by: Mika Westerberg --- drivers/acpi/acpi_lpss.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/acpi_lpss.c b/drivers/acpi/acpi_lpss.c index 30b1f511c2af..5ecd3a3b5236 100644 --- a/drivers/acpi/acpi_lpss.c +++ b/drivers/acpi/acpi_lpss.c @@ -712,14 +712,13 @@ static void __lpss_reg_write(u32 val, struct lpss_private_data *pdata, static int lpss_reg_read(struct device *dev, unsigned int reg, u32 *val) { - struct acpi_device *adev; + struct acpi_device *adev = ACPI_COMPANION(dev); struct lpss_private_data *pdata; unsigned long flags; int ret; - ret = acpi_bus_get_device(ACPI_HANDLE(dev), &adev); - if (WARN_ON(ret)) - return ret; + if (WARN_ON(!adev)) + return -ENODEV; spin_lock_irqsave(&dev->power.lock, flags); if (pm_runtime_suspended(dev)) { @@ -732,6 +731,7 @@ static int lpss_reg_read(struct device *dev, unsigned int reg, u32 *val) goto out; } *val = __lpss_reg_read(pdata, reg); + ret = 0; out: spin_unlock_irqrestore(&dev->power.lock, flags); @@ -1266,7 +1266,8 @@ static int acpi_lpss_platform_notify(struct notifier_block *nb, if (!id || !id->driver_data) return 0; - if (acpi_bus_get_device(ACPI_HANDLE(&pdev->dev), &adev)) + adev = ACPI_COMPANION(&pdev->dev); + if (!adev) return 0; pdata = acpi_driver_data(adev); -- cgit v1.2.3 From d47e983e4f612856c860ae04db054ebcf4a333c3 Mon Sep 17 00:00:00 2001 From: Qing Wang Date: Tue, 12 Oct 2021 20:24:50 -0700 Subject: ACPI: replace snprintf() in "show" functions with sysfs_emit() coccicheck complains about the use of snprintf() in sysfs "show" functions: Fix the coccicheck warning: WARNING: use scnprintf or sprintf. so use sysfs_emit() instead of it where applicable. Signed-off-by: Qing Wang [ rjw: Subject and changelog edits ] Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpi_lpss.c | 2 +- drivers/acpi/dock.c | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/acpi_lpss.c b/drivers/acpi/acpi_lpss.c index 30b1f511c2af..07447213a752 100644 --- a/drivers/acpi/acpi_lpss.c +++ b/drivers/acpi/acpi_lpss.c @@ -750,7 +750,7 @@ static ssize_t lpss_ltr_show(struct device *dev, struct device_attribute *attr, if (ret) return ret; - return snprintf(buf, PAGE_SIZE, "%08x\n", ltr_value); + return sysfs_emit(buf, "%08x\n", ltr_value); } static ssize_t lpss_ltr_mode_show(struct device *dev, diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c index 7cf92158008f..c8e9b962e18c 100644 --- a/drivers/acpi/dock.c +++ b/drivers/acpi/dock.c @@ -492,7 +492,7 @@ static ssize_t docked_show(struct device *dev, struct acpi_device *adev = NULL; acpi_bus_get_device(dock_station->handle, &adev); - return snprintf(buf, PAGE_SIZE, "%u\n", acpi_device_enumerated(adev)); + return sysfs_emit(buf, "%u\n", acpi_device_enumerated(adev)); } static DEVICE_ATTR_RO(docked); @@ -504,7 +504,7 @@ static ssize_t flags_show(struct device *dev, { struct dock_station *dock_station = dev->platform_data; - return snprintf(buf, PAGE_SIZE, "%d\n", dock_station->flags); + return sysfs_emit(buf, "%d\n", dock_station->flags); } static DEVICE_ATTR_RO(flags); @@ -543,7 +543,7 @@ static ssize_t uid_show(struct device *dev, if (ACPI_FAILURE(status)) return 0; - return snprintf(buf, PAGE_SIZE, "%llx\n", lbuf); + return sysfs_emit(buf, "%llx\n", lbuf); } static DEVICE_ATTR_RO(uid); @@ -562,7 +562,7 @@ static ssize_t type_show(struct device *dev, else type = "unknown"; - return snprintf(buf, PAGE_SIZE, "%s\n", type); + return sysfs_emit(buf, "%s\n", type); } static DEVICE_ATTR_RO(type); -- cgit v1.2.3 From a1224f34d72a103829d6953935d6c6621f135b83 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 15 Oct 2021 19:14:10 +0200 Subject: ACPI: PM: Check states of power resources during initialization To avoid situations in which the actual states of certain ACPI power resources are not known just because they have never been referenced by any device configuration objects, check the initial states of all power resources as soon as they are found in the ACPI namespace (and fall back to turning them on if the state check fails). Signed-off-by: Rafael J. Wysocki Tested-by: Andreas K. Huettel --- drivers/acpi/power.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers/acpi') diff --git a/drivers/acpi/power.c b/drivers/acpi/power.c index f0ed4414edb1..bb03fb0eaa0e 100644 --- a/drivers/acpi/power.c +++ b/drivers/acpi/power.c @@ -943,6 +943,7 @@ struct acpi_device *acpi_add_power_resource(acpi_handle handle) union acpi_object acpi_object; struct acpi_buffer buffer = { sizeof(acpi_object), &acpi_object }; acpi_status status; + u8 state_dummy; int result; acpi_bus_get_device(handle, &device); @@ -971,6 +972,10 @@ struct acpi_device *acpi_add_power_resource(acpi_handle handle) resource->order = acpi_object.power_resource.resource_order; resource->state = ACPI_POWER_RESOURCE_STATE_UNKNOWN; + /* Get the initial state or just flip it on if that fails. */ + if (acpi_power_get_state(resource, &state_dummy)) + __acpi_power_on(resource); + pr_info("%s [%s]\n", acpi_device_name(device), acpi_device_bid(device)); device->flags.match_driver = true; -- cgit v1.2.3 From 7a63296d6f579a02b2675b4b0fe5b1cd3235e8d3 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 15 Oct 2021 19:01:28 +0200 Subject: ACPI: PM: Turn off unused wakeup power resources If an ACPI power resource is found to be "on" during the initialization of the list of wakeup power resources of a device, it is reference counted and its wakeup_enabled flag is set, which is problematic if the deivce in question is the only user of the given power resource, it is never runtime-suspended and it is not allowed to wake up the system from sleep, because in that case the given power resource will stay "on" until the system reboots and energy will be wasted. It is better to simply turn off wakeup power resources that are "on" during the initialization unless their reference counters are not zero, because that may be the only opportunity to prevent them from staying in the "on" state all the time. Fixes: b5d667eb392e ("ACPI / PM: Take unusual configurations of power resources into account") Signed-off-by: Rafael J. Wysocki --- drivers/acpi/power.c | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/power.c b/drivers/acpi/power.c index bb03fb0eaa0e..1b7431fb5fb2 100644 --- a/drivers/acpi/power.c +++ b/drivers/acpi/power.c @@ -615,20 +615,19 @@ int acpi_power_wakeup_list_init(struct list_head *list, int *system_level_p) list_for_each_entry(entry, list, node) { struct acpi_power_resource *resource = entry->resource; - int result; u8 state; mutex_lock(&resource->resource_lock); - result = acpi_power_get_state(resource, &state); - if (result) { - mutex_unlock(&resource->resource_lock); - return result; - } - if (state == ACPI_POWER_RESOURCE_STATE_ON) { - resource->ref_count++; - resource->wakeup_enabled = true; - } + /* + * Make sure that the power resource state and its reference + * counter value are consistent with each other. + */ + if (!resource->ref_count && + !acpi_power_get_state(resource, &state) && + state == ACPI_POWER_RESOURCE_STATE_ON) + __acpi_power_off(resource); + if (system_level > resource->system_level) system_level = resource->system_level; -- cgit v1.2.3 From a2d7b2e004af6b09f21ac3d10f8f4456c16a8ddf Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sat, 16 Oct 2021 12:11:08 +0200 Subject: ACPI: PM: Fix sharing of wakeup power resources If an ACPI wakeup power resource is shared between multiple devices, it may not be managed correctly. Suppose, for example, that two devices, A and B, share a wakeup power resource P whose wakeup_enabled flag is 0 initially. Next, suppose that wakeup power is enabled for A and B, in this order, and disabled for B. When wakeup power is enabled for A, P will be turned on and its wakeup_enabled flag will be set. Next, when wakeup power is enabled for B, P will not be touched, because its wakeup_enabled flag is set. Now, when wakeup power is disabled for B, P will be turned off which is incorrect, because A will still need P in order to signal wakeup. Moreover, if wakeup power is enabled for A and then disabled for B, the latter will cause P to be turned off incorrectly (it will be still needed by A), because acpi_disable_wakeup_device_power() is allowed to manipulate power resources when the wakeup.prepare_count counter of the given device is 0. While the first issue could be addressed by changing the wakeup_enabled power resource flag into a counter, addressing the second one requires modifying acpi_disable_wakeup_device_power() to do nothing when the target device's wakeup.prepare_count reference counter is zero and that would cause the new counter to be redundant. Namely, if acpi_disable_wakeup_device_power() is modified as per the above, every change of the new counter following a wakeup.prepare_count change would be reflected by the analogous change of the main reference counter of the given power resource. Accordingly, modify acpi_disable_wakeup_device_power() to do nothing when the target device's wakeup.prepare_count reference counter is zero and drop the power resource wakeup_enabled flag altogether. While at it, ensure that all of the power resources that can be turned off will be turned off when disabling device wakeup due to a power resource manipulation error, to prevent energy from being wasted. Fixes: b5d667eb392e ("ACPI / PM: Take unusual configurations of power resources into account") Signed-off-by: Rafael J. Wysocki --- drivers/acpi/power.c | 69 ++++++++++++++++++---------------------------------- 1 file changed, 24 insertions(+), 45 deletions(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/power.c b/drivers/acpi/power.c index 1b7431fb5fb2..ba6aaf7224a1 100644 --- a/drivers/acpi/power.c +++ b/drivers/acpi/power.c @@ -52,7 +52,6 @@ struct acpi_power_resource { u32 order; unsigned int ref_count; u8 state; - bool wakeup_enabled; struct mutex resource_lock; struct list_head dependents; }; @@ -710,7 +709,6 @@ int acpi_device_sleep_wake(struct acpi_device *dev, */ int acpi_enable_wakeup_device_power(struct acpi_device *dev, int sleep_state) { - struct acpi_power_resource_entry *entry; int err = 0; if (!dev || !dev->wakeup.flags.valid) @@ -721,26 +719,13 @@ int acpi_enable_wakeup_device_power(struct acpi_device *dev, int sleep_state) if (dev->wakeup.prepare_count++) goto out; - list_for_each_entry(entry, &dev->wakeup.resources, node) { - struct acpi_power_resource *resource = entry->resource; - - mutex_lock(&resource->resource_lock); - - if (!resource->wakeup_enabled) { - err = acpi_power_on_unlocked(resource); - if (!err) - resource->wakeup_enabled = true; - } - - mutex_unlock(&resource->resource_lock); - - if (err) { - dev_err(&dev->dev, - "Cannot turn wakeup power resources on\n"); - dev->wakeup.flags.valid = 0; - goto out; - } + err = acpi_power_on_list(&dev->wakeup.resources); + if (err) { + dev_err(&dev->dev, "Cannot turn on wakeup power resources\n"); + dev->wakeup.flags.valid = 0; + goto out; } + /* * Passing 3 as the third argument below means the device may be * put into arbitrary power state afterward. @@ -770,39 +755,33 @@ int acpi_disable_wakeup_device_power(struct acpi_device *dev) mutex_lock(&acpi_device_lock); - if (--dev->wakeup.prepare_count > 0) + if (dev->wakeup.prepare_count > 1) { + dev->wakeup.prepare_count--; goto out; + } - /* - * Executing the code below even if prepare_count is already zero when - * the function is called may be useful, for example for initialisation. - */ - if (dev->wakeup.prepare_count < 0) - dev->wakeup.prepare_count = 0; + /* Do nothing if wakeup power has not been enabled for this device. */ + if (!dev->wakeup.prepare_count) + goto out; err = acpi_device_sleep_wake(dev, 0, 0, 0); if (err) goto out; + /* + * All of the power resources in the list need to be turned off even if + * there are errors. + */ list_for_each_entry(entry, &dev->wakeup.resources, node) { - struct acpi_power_resource *resource = entry->resource; - - mutex_lock(&resource->resource_lock); - - if (resource->wakeup_enabled) { - err = acpi_power_off_unlocked(resource); - if (!err) - resource->wakeup_enabled = false; - } - - mutex_unlock(&resource->resource_lock); + int ret; - if (err) { - dev_err(&dev->dev, - "Cannot turn wakeup power resources off\n"); - dev->wakeup.flags.valid = 0; - break; - } + ret = acpi_power_off(entry->resource); + if (ret && !err) + err = ret; + } + if (err) { + dev_err(&dev->dev, "Cannot turn off wakeup power resources\n"); + dev->wakeup.flags.valid = 0; } out: -- cgit v1.2.3 From a9a8f827f9e81dc8506d3283d166cd6efe822302 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 15 Oct 2021 19:04:26 +0200 Subject: ACPI: PM: Turn off wakeup power resources on _DSW/_PSW errors If acpi_device_sleep_wake() called by acpi_enable_wakeup_device_power() returns an error which means that the evaluation of either _DWS or _PSW has failed, turn off all of the device's wakeup power resources to be consistent with the clearing of dev->wakeup.prepare_count. Signed-off-by: Rafael J. Wysocki --- drivers/acpi/power.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/power.c b/drivers/acpi/power.c index ba6aaf7224a1..112256154880 100644 --- a/drivers/acpi/power.c +++ b/drivers/acpi/power.c @@ -731,8 +731,10 @@ int acpi_enable_wakeup_device_power(struct acpi_device *dev, int sleep_state) * put into arbitrary power state afterward. */ err = acpi_device_sleep_wake(dev, 1, sleep_state, 3); - if (err) + if (err) { + acpi_power_off_list(&dev->wakeup.resources); dev->wakeup.prepare_count = 0; + } out: mutex_unlock(&acpi_device_lock); -- cgit v1.2.3 From caa2bd07f5c5f09acf62072906daeaa667e2b645 Mon Sep 17 00:00:00 2001 From: Aubrey Li Date: Wed, 20 Oct 2021 11:23:16 +0800 Subject: ACPI: PRM: Remove unnecessary blank lines Just remove unnecessary blank lines, no other code changes Signed-off-by: Aubrey Li Signed-off-by: Rafael J. Wysocki --- drivers/acpi/prmt.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/prmt.c b/drivers/acpi/prmt.c index 89c22bc55057..aa02221f6ade 100644 --- a/drivers/acpi/prmt.c +++ b/drivers/acpi/prmt.c @@ -49,7 +49,6 @@ struct prm_context_buffer { }; #pragma pack() - static LIST_HEAD(prm_module_list); struct prm_handler_info { @@ -73,7 +72,6 @@ struct prm_module_info { struct prm_handler_info handlers[]; }; - static u64 efi_pa_va_lookup(u64 pa) { efi_memory_desc_t *md; @@ -88,7 +86,6 @@ static u64 efi_pa_va_lookup(u64 pa) return 0; } - #define get_first_handler(a) ((struct acpi_prmt_handler_info *) ((char *) (a) + a->handler_info_offset)) #define get_next_handler(a) ((struct acpi_prmt_handler_info *) (sizeof(struct acpi_prmt_handler_info) + (char *) a)) @@ -171,7 +168,6 @@ static void *find_guid_info(const guid_t *guid, u8 mode) return NULL; } - static struct prm_module_info *find_prm_module(const guid_t *guid) { return (struct prm_module_info *)find_guid_info(guid, GET_MODULE); -- cgit v1.2.3 From c52ca713279da78881d36b49acd36288a46bbec8 Mon Sep 17 00:00:00 2001 From: Aubrey Li Date: Wed, 20 Oct 2021 11:23:17 +0800 Subject: ACPI: PRM: Handle memory allocation and memory remap failure Handle memory allocation and memory remap failure in acpi_parse_prmt() when system runs out of memory to avoid the potential NULL pointer dereference errors. Signed-off-by: Aubrey Li Signed-off-by: Rafael J. Wysocki --- drivers/acpi/prmt.c | 31 ++++++++++++++++++++++++++----- 1 file changed, 26 insertions(+), 5 deletions(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/prmt.c b/drivers/acpi/prmt.c index aa02221f6ade..4d3a219c67f8 100644 --- a/drivers/acpi/prmt.c +++ b/drivers/acpi/prmt.c @@ -96,7 +96,7 @@ acpi_parse_prmt(union acpi_subtable_headers *header, const unsigned long end) struct acpi_prmt_handler_info *handler_info; struct prm_handler_info *th; struct prm_module_info *tm; - u64 mmio_count = 0; + u64 *mmio_count; u64 cur_handler = 0; u32 module_info_size = 0; u64 mmio_range_size = 0; @@ -105,6 +105,8 @@ acpi_parse_prmt(union acpi_subtable_headers *header, const unsigned long end) module_info = (struct acpi_prmt_module_info *) header; module_info_size = struct_size(tm, handlers, module_info->handler_info_count); tm = kmalloc(module_info_size, GFP_KERNEL); + if (!tm) + goto parse_prmt_out1; guid_copy(&tm->guid, (guid_t *) module_info->module_guid); tm->major_rev = module_info->major_rev; @@ -117,14 +119,24 @@ acpi_parse_prmt(union acpi_subtable_headers *header, const unsigned long end) * Each module is associated with a list of addr * ranges that it can use during the service */ - mmio_count = *(u64 *) memremap(module_info->mmio_list_pointer, 8, MEMREMAP_WB); - mmio_range_size = struct_size(tm->mmio_info, addr_ranges, mmio_count); + mmio_count = (u64 *) memremap(module_info->mmio_list_pointer, 8, MEMREMAP_WB); + if (!mmio_count) + goto parse_prmt_out2; + + mmio_range_size = struct_size(tm->mmio_info, addr_ranges, *mmio_count); tm->mmio_info = kmalloc(mmio_range_size, GFP_KERNEL); + if (!tm->mmio_info) + goto parse_prmt_out3; + temp_mmio = memremap(module_info->mmio_list_pointer, mmio_range_size, MEMREMAP_WB); + if (!temp_mmio) + goto parse_prmt_out4; memmove(tm->mmio_info, temp_mmio, mmio_range_size); } else { - mmio_range_size = struct_size(tm->mmio_info, addr_ranges, mmio_count); - tm->mmio_info = kmalloc(mmio_range_size, GFP_KERNEL); + tm->mmio_info = kmalloc(sizeof(*tm->mmio_info), GFP_KERNEL); + if (!tm->mmio_info) + goto parse_prmt_out2; + tm->mmio_info->mmio_count = 0; } @@ -142,6 +154,15 @@ acpi_parse_prmt(union acpi_subtable_headers *header, const unsigned long end) } while (++cur_handler < tm->handler_count && (handler_info = get_next_handler(handler_info))); return 0; + +parse_prmt_out4: + kfree(tm->mmio_info); +parse_prmt_out3: + memunmap(mmio_count); +parse_prmt_out2: + kfree(tm); +parse_prmt_out1: + return -ENOMEM; } #define GET_MODULE 0 -- cgit v1.2.3 From d69d1f708093347c085699cc0b547982e48c47b8 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Wed, 20 Oct 2021 21:10:17 +0200 Subject: ACPI: PM: sleep: Do not set suspend_ops unnecessarily If none of the S1 - S3 sleep states is supported, it is not necessary to register suspend_ops, so don't do that then. Signed-off-by: Rafael J. Wysocki --- drivers/acpi/sleep.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c index 3023224515ab..eaa47753b758 100644 --- a/drivers/acpi/sleep.c +++ b/drivers/acpi/sleep.c @@ -815,14 +815,18 @@ void __weak acpi_s2idle_setup(void) static void acpi_sleep_suspend_setup(void) { + bool suspend_ops_needed = false; int i; for (i = ACPI_STATE_S1; i < ACPI_STATE_S4; i++) - if (acpi_sleep_state_supported(i)) + if (acpi_sleep_state_supported(i)) { sleep_states[i] = 1; + suspend_ops_needed = true; + } - suspend_set_ops(old_suspend_ordering ? - &acpi_suspend_ops_old : &acpi_suspend_ops); + if (suspend_ops_needed) + suspend_set_ops(old_suspend_ordering ? + &acpi_suspend_ops_old : &acpi_suspend_ops); acpi_s2idle_setup(); } -- cgit v1.2.3 From 3d730ee686800d71ecc5c3cb8460dcdcdeaf38a3 Mon Sep 17 00:00:00 2001 From: Stefan Schaeckeler Date: Sun, 24 Oct 2021 15:04:45 -0700 Subject: ACPI: AC: Quirk GK45 to skip reading _PSR Let GK45 not go into BIOS for determining the AC power state. The BIOS wrongly returns 0, so hardcode the power state to 1. The mini PC GK45 by Besstar Tech Lld. (aka Kodlix) just runs off AC. It does not include any batteries. Nevertheless BIOS reports AC off: root@kodlix:/usr/src/linux# cat /sys/class/power_supply/ADP1/online 0 root@kodlix:/usr/src/linux# modprobe acpi_dbg root@kodlix:/usr/src/linux# tools/power/acpi/acpidbg - find _PSR \_SB.PCI0.SBRG.H_EC.ADP1._PSR Method 000000009283cee8 001 Args 0 Len 001C Aml 00000000f54e5f67 - execute \_SB.PCI0.SBRG.H_EC.ADP1._PSR Evaluating \_SB.PCI0.SBRG.H_EC.ADP1._PSR Evaluation of \_SB.PCI0.SBRG.H_EC.ADP1._PSR returned object 00000000dc08c187, external buffer length 18 [Integer] = 0000000000000000 that should be [Integer] = 0000000000000001 Signed-off-by: Stefan Schaeckeler Signed-off-by: Rafael J. Wysocki --- drivers/acpi/ac.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) (limited to 'drivers/acpi') diff --git a/drivers/acpi/ac.c b/drivers/acpi/ac.c index b0cb662233f1..81aff651a0d4 100644 --- a/drivers/acpi/ac.c +++ b/drivers/acpi/ac.c @@ -61,6 +61,7 @@ static SIMPLE_DEV_PM_OPS(acpi_ac_pm, NULL, acpi_ac_resume); static int ac_sleep_before_get_state_ms; static int ac_check_pmic = 1; +static int ac_only; static struct acpi_driver acpi_ac_driver = { .name = "ac", @@ -93,6 +94,11 @@ static int acpi_ac_get_state(struct acpi_ac *ac) if (!ac) return -EINVAL; + if (ac_only) { + ac->state = 1; + return 0; + } + status = acpi_evaluate_integer(ac->device->handle, "_PSR", NULL, &ac->state); if (ACPI_FAILURE(status)) { @@ -200,6 +206,12 @@ static int __init ac_do_not_check_pmic_quirk(const struct dmi_system_id *d) return 0; } +static int __init ac_only_quirk(const struct dmi_system_id *d) +{ + ac_only = 1; + return 0; +} + /* Please keep this list alphabetically sorted */ static const struct dmi_system_id ac_dmi_table[] __initconst = { { @@ -209,6 +221,13 @@ static const struct dmi_system_id ac_dmi_table[] __initconst = { DMI_MATCH(DMI_PRODUCT_NAME, "EF20EA"), }, }, + { + /* Kodlix GK45 returning incorrect state */ + .callback = ac_only_quirk, + .matches = { + DMI_MATCH(DMI_PRODUCT_NAME, "GK45"), + }, + }, { /* Lenovo Ideapad Miix 320, AXP288 PMIC, separate fuel-gauge */ .callback = ac_do_not_check_pmic_quirk, -- cgit v1.2.3 From 1b26ae40092b43bb6e9c5df376227382b390b953 Mon Sep 17 00:00:00 2001 From: Hui Wang Date: Mon, 25 Oct 2021 14:16:01 +0800 Subject: ACPI: resources: Add one more Medion model in IRQ override quirk The Medion s17 series laptops have the same issue on the keyboard as the s15 series, if skipping to call acpi_get_override_irq(), the keyboard could work well. So put the DMI info of s17 series in the IRQ override quirk table as well. BugLink: https://bugzilla.kernel.org/show_bug.cgi?id=213031 Tested-by: dirksche Signed-off-by: Hui Wang Signed-off-by: Rafael J. Wysocki --- drivers/acpi/resource.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers/acpi') diff --git a/drivers/acpi/resource.c b/drivers/acpi/resource.c index 7bf38652e6ac..3c25ce8c95ba 100644 --- a/drivers/acpi/resource.c +++ b/drivers/acpi/resource.c @@ -389,6 +389,13 @@ static const struct dmi_system_id medion_laptop[] = { DMI_MATCH(DMI_BOARD_NAME, "M15T"), }, }, + { + .ident = "MEDION S17405", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "MEDION"), + DMI_MATCH(DMI_BOARD_NAME, "M17T"), + }, + }, { } }; -- cgit v1.2.3 From bf7fc0c369585e34652d5666ed590d5cac07c2e2 Mon Sep 17 00:00:00 2001 From: Shuai Xue Date: Tue, 26 Oct 2021 15:28:29 +0800 Subject: ACPI: APEI: EINJ: Relax platform response timeout to 1 second When injecting an error into the platform, the OSPM executes an EXECUTE_OPERATION action to instruct the platform to begin the injection operation. And then, the OSPM busy waits for a while by continually executing CHECK_BUSY_STATUS action until the platform indicates that the operation is complete. More specifically, the platform is limited to respond within 1 millisecond right now. This is too strict for some platforms. For example, in Arm platform, when injecting a Processor Correctable error, the OSPM will warn: Firmware does not respond in time. And a message is printed on the console: echo: write error: Input/output error We observe that the waiting time for DDR error injection is about 10 ms and that for PCIe error injection is about 500 ms in Arm platform. In this patch, we relax the response timeout to 1 second. Signed-off-by: Shuai Xue Reviewed-by: Tony Luck Signed-off-by: Rafael J. Wysocki --- drivers/acpi/apei/einj.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/apei/einj.c b/drivers/acpi/apei/einj.c index 2882450c443e..edb2622fd35f 100644 --- a/drivers/acpi/apei/einj.c +++ b/drivers/acpi/apei/einj.c @@ -28,9 +28,10 @@ #undef pr_fmt #define pr_fmt(fmt) "EINJ: " fmt -#define SPIN_UNIT 100 /* 100ns */ -/* Firmware should respond within 1 milliseconds */ -#define FIRMWARE_TIMEOUT (1 * NSEC_PER_MSEC) +#define SLEEP_UNIT_MIN 1000 /* 1ms */ +#define SLEEP_UNIT_MAX 5000 /* 5ms */ +/* Firmware should respond within 1 seconds */ +#define FIRMWARE_TIMEOUT (1 * USEC_PER_SEC) #define ACPI5_VENDOR_BIT BIT(31) #define MEM_ERROR_MASK (ACPI_EINJ_MEMORY_CORRECTABLE | \ ACPI_EINJ_MEMORY_UNCORRECTABLE | \ @@ -171,13 +172,13 @@ static int einj_get_available_error_type(u32 *type) static int einj_timedout(u64 *t) { - if ((s64)*t < SPIN_UNIT) { + if ((s64)*t < SLEEP_UNIT_MIN) { pr_warn(FW_WARN "Firmware does not respond in time\n"); return 1; } - *t -= SPIN_UNIT; - ndelay(SPIN_UNIT); - touch_nmi_watchdog(); + *t -= SLEEP_UNIT_MIN; + usleep_range(SLEEP_UNIT_MIN, SLEEP_UNIT_MAX); + return 0; } -- cgit v1.2.3 From 06606646af97fa9aa0c36a723f4615157e41400a Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Wed, 27 Oct 2021 08:54:38 +0200 Subject: ACPI: APEI: mark apei_hest_parse() static apei_hest_parse() is only used in hest.c, so mark it static. Signed-off-by: Christoph Hellwig [ rjw: Minor subject and changelog edits ] Signed-off-by: Rafael J. Wysocki --- drivers/acpi/apei/hest.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/apei/hest.c b/drivers/acpi/apei/hest.c index 277f00b288d1..0edc1ed47673 100644 --- a/drivers/acpi/apei/hest.c +++ b/drivers/acpi/apei/hest.c @@ -86,7 +86,9 @@ static int hest_esrc_len(struct acpi_hest_header *hest_hdr) return len; }; -int apei_hest_parse(apei_hest_func_t func, void *data) +typedef int (*apei_hest_func_t)(struct acpi_hest_header *hest_hdr, void *data); + +static int apei_hest_parse(apei_hest_func_t func, void *data) { struct acpi_hest_header *hest_hdr; int i, rc, len; @@ -121,7 +123,6 @@ int apei_hest_parse(apei_hest_func_t func, void *data) return 0; } -EXPORT_SYMBOL_GPL(apei_hest_parse); /* * Check if firmware advertises firmware first mode. We need FF bit to be set -- cgit v1.2.3 From 61a3c78d991c7f5e189e82fa54ddaa9d514544a2 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Wed, 27 Oct 2021 18:59:06 +0200 Subject: ACPI: glue: Use acpi_device_adr() in acpi_find_child_device() Instead of evaluating _ADR in acpi_find_child_device(), use the observation that it has already been evaluated and the value returned by it has been stored in the pnp.type.bus_address field of the ACPI device object at hand. Signed-off-by: Rafael J. Wysocki --- drivers/acpi/glue.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c index 17ec6e57c4b7..ef104809f27b 100644 --- a/drivers/acpi/glue.c +++ b/drivers/acpi/glue.c @@ -113,13 +113,10 @@ struct acpi_device *acpi_find_child_device(struct acpi_device *parent, return NULL; list_for_each_entry(adev, &parent->children, node) { - unsigned long long addr; - acpi_status status; + acpi_bus_address addr = acpi_device_adr(adev); int score; - status = acpi_evaluate_integer(adev->handle, METHOD_NAME__ADR, - NULL, &addr); - if (ACPI_FAILURE(status) || addr != address) + if (!adev->pnp.type.bus_address || addr != address) continue; if (!ret) { -- cgit v1.2.3