From 5d389afc1f8fea707225bc2ee64e00d85dab623a Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Thu, 1 Feb 2024 16:11:15 -0600 Subject: ACPI: video: Handle fetching EDID that is longer than 256 bytes The ACPI specification allows for an EDID to be up to 512 bytes but the _DDC EDID fetching code will only try up to 256 bytes. Modify the code to instead start at 512 bytes and work it's way down instead. As _DDC is now called up to 4 times on a machine debugging messages are noisier than necessary. Decrease from info to debug. Link: https://uefi.org/htmlspecs/ACPI_Spec_6_4_html/Apx_B_Video_Extensions/output-device-specific-methods.html#ddc-return-the-edid-for-this-device Signed-off-by: Mario Limonciello [ rjw: Type mismatch fix, minor whitespace adjustment ] Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpi_video.c | 28 +++++++++++----------------- 1 file changed, 11 insertions(+), 17 deletions(-) diff --git a/drivers/acpi/acpi_video.c b/drivers/acpi/acpi_video.c index 4afdda9db019..1fda30388297 100644 --- a/drivers/acpi/acpi_video.c +++ b/drivers/acpi/acpi_video.c @@ -612,7 +612,7 @@ acpi_video_device_lcd_get_level_current(struct acpi_video_device *device, static int acpi_video_device_EDID(struct acpi_video_device *device, - union acpi_object **edid, ssize_t length) + union acpi_object **edid, int length) { int status; struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; @@ -625,13 +625,11 @@ acpi_video_device_EDID(struct acpi_video_device *device, if (!device) return -ENODEV; - if (length == 128) - arg0.integer.value = 1; - else if (length == 256) - arg0.integer.value = 2; - else + if (!length || (length % 128)) return -EINVAL; + arg0.integer.value = length / 128; + status = acpi_evaluate_object(device->dev->handle, "_DDC", &args, &buffer); if (ACPI_FAILURE(status)) return -ENODEV; @@ -641,7 +639,8 @@ acpi_video_device_EDID(struct acpi_video_device *device, if (obj && obj->type == ACPI_TYPE_BUFFER) *edid = obj; else { - acpi_handle_info(device->dev->handle, "Invalid _DDC data\n"); + acpi_handle_debug(device->dev->handle, + "Invalid _DDC data for length %d\n", length); status = -EFAULT; kfree(obj); } @@ -1447,7 +1446,6 @@ int acpi_video_get_edid(struct acpi_device *device, int type, int device_id, for (i = 0; i < video->attached_count; i++) { video_device = video->attached_array[i].bind_info; - length = 256; if (!video_device) continue; @@ -1478,18 +1476,14 @@ int acpi_video_get_edid(struct acpi_device *device, int type, int device_id, continue; } - status = acpi_video_device_EDID(video_device, &buffer, length); - - if (ACPI_FAILURE(status) || !buffer || - buffer->type != ACPI_TYPE_BUFFER) { - length = 128; + for (length = 512; length > 0; length -= 128) { status = acpi_video_device_EDID(video_device, &buffer, length); - if (ACPI_FAILURE(status) || !buffer || - buffer->type != ACPI_TYPE_BUFFER) { - continue; - } + if (ACPI_SUCCESS(status)) + break; } + if (!length) + continue; *edid = buffer->buffer.pointer; return length; -- cgit v1.2.3 From c763aefeeb3ebeb05efff3d204ffe8fa7872da8f Mon Sep 17 00:00:00 2001 From: Onkarnath Date: Tue, 13 Feb 2024 13:14:15 +0530 Subject: ACPI: use %pe for better readability of errors while printing As %pe is already introduced, it's better to use it in place of (%ld) for printing errors in logs. It would enhance readability of logs. Co-developed-by: Maninder Singh Signed-off-by: Maninder Singh Signed-off-by: Onkarnath Reviewed-by: Stanislaw Gruszka Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpi_processor.c | 2 +- drivers/acpi/acpi_watchdog.c | 2 +- drivers/acpi/pci_slot.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/acpi/acpi_processor.c b/drivers/acpi/acpi_processor.c index 4fe2ef54088c..2ddd36a21850 100644 --- a/drivers/acpi/acpi_processor.c +++ b/drivers/acpi/acpi_processor.c @@ -161,7 +161,7 @@ static void cpufreq_add_device(const char *name) pdev = platform_device_register_simple(name, PLATFORM_DEVID_NONE, NULL, 0); if (IS_ERR(pdev)) - pr_info("%s device creation failed: %ld\n", name, PTR_ERR(pdev)); + pr_info("%s device creation failed: %pe\n", name, pdev); } #ifdef CONFIG_X86 diff --git a/drivers/acpi/acpi_watchdog.c b/drivers/acpi/acpi_watchdog.c index 8e9e001da38f..14b24157799c 100644 --- a/drivers/acpi/acpi_watchdog.c +++ b/drivers/acpi/acpi_watchdog.c @@ -179,7 +179,7 @@ void __init acpi_watchdog_init(void) pdev = platform_device_register_simple("wdat_wdt", PLATFORM_DEVID_NONE, resources, nresources); if (IS_ERR(pdev)) - pr_err("Device creation failed: %ld\n", PTR_ERR(pdev)); + pr_err("Device creation failed: %pe\n", pdev); kfree(resources); diff --git a/drivers/acpi/pci_slot.c b/drivers/acpi/pci_slot.c index d6cb2c27a23b..741bcc9d6d6a 100644 --- a/drivers/acpi/pci_slot.c +++ b/drivers/acpi/pci_slot.c @@ -111,7 +111,7 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv) snprintf(name, sizeof(name), "%llu", sun); pci_slot = pci_create_slot(pci_bus, device, name, NULL); if (IS_ERR(pci_slot)) { - pr_err("pci_create_slot returned %ld\n", PTR_ERR(pci_slot)); + pr_err("pci_create_slot returned %pe\n", pci_slot); kfree(slot); return AE_OK; } -- cgit v1.2.3 From 7c86e17455de1a442ec906d3449148b5e9a218a4 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 18 Feb 2024 16:15:32 +0100 Subject: ACPI: x86: Move acpi_quirk_skip_serdev_enumeration() out of CONFIG_X86_ANDROID_TABLETS Some recent(ish) Dell AIO devices have a backlight controller board connected to an UART. This UART has a DELL0501 HID with CID set to PNP0501 so that the UART is still handled by 8250_pnp.c. Unfortunately there is no separate ACPI device with an UartSerialBusV2() resource to model the backlight-controller. The next patch in this series will use acpi_quirk_skip_serdev_enumeration() to still create a serdev for this for a backlight driver to bind to instead of creating a /dev/ttyS0. This new acpi_quirk_skip_serdev_enumeration() use is not limited to Android X86 tablets, so move it out of the ifdef CONFIG_X86_ANDROID_TABLETS block. Signed-off-by: Hans de Goede Signed-off-by: Rafael J. Wysocki --- drivers/acpi/x86/utils.c | 18 ++++++++++++++---- include/acpi/acpi_bus.h | 14 +++++++------- 2 files changed, 21 insertions(+), 11 deletions(-) diff --git a/drivers/acpi/x86/utils.c b/drivers/acpi/x86/utils.c index bc65ebfcdf76..8829a907eee0 100644 --- a/drivers/acpi/x86/utils.c +++ b/drivers/acpi/x86/utils.c @@ -428,7 +428,7 @@ bool acpi_quirk_skip_i2c_client_enumeration(struct acpi_device *adev) } EXPORT_SYMBOL_GPL(acpi_quirk_skip_i2c_client_enumeration); -int acpi_quirk_skip_serdev_enumeration(struct device *controller_parent, bool *skip) +static int acpi_dmi_skip_serdev_enumeration(struct device *controller_parent, bool *skip) { struct acpi_device *adev = ACPI_COMPANION(controller_parent); const struct dmi_system_id *dmi_id; @@ -436,8 +436,6 @@ int acpi_quirk_skip_serdev_enumeration(struct device *controller_parent, bool *s u64 uid; int ret; - *skip = false; - ret = acpi_dev_uid_to_integer(adev, &uid); if (ret) return 0; @@ -463,7 +461,6 @@ int acpi_quirk_skip_serdev_enumeration(struct device *controller_parent, bool *s return 0; } -EXPORT_SYMBOL_GPL(acpi_quirk_skip_serdev_enumeration); bool acpi_quirk_skip_gpio_event_handlers(void) { @@ -478,8 +475,21 @@ bool acpi_quirk_skip_gpio_event_handlers(void) return (quirks & ACPI_QUIRK_SKIP_GPIO_EVENT_HANDLERS); } EXPORT_SYMBOL_GPL(acpi_quirk_skip_gpio_event_handlers); +#else +static int acpi_dmi_skip_serdev_enumeration(struct device *controller_parent, bool *skip) +{ + return 0; +} #endif +int acpi_quirk_skip_serdev_enumeration(struct device *controller_parent, bool *skip) +{ + *skip = false; + + return acpi_dmi_skip_serdev_enumeration(controller_parent, skip); +} +EXPORT_SYMBOL_GPL(acpi_quirk_skip_serdev_enumeration); + /* Lists of PMIC ACPI HIDs with an (often better) native charger driver */ static const struct { const char *hid; diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index e4d24d3f9abb..446225aada50 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -749,6 +749,7 @@ bool acpi_device_override_status(struct acpi_device *adev, unsigned long long *s bool acpi_quirk_skip_acpi_ac_and_battery(void); int acpi_install_cmos_rtc_space_handler(acpi_handle handle); void acpi_remove_cmos_rtc_space_handler(acpi_handle handle); +int acpi_quirk_skip_serdev_enumeration(struct device *controller_parent, bool *skip); #else static inline bool acpi_device_override_status(struct acpi_device *adev, unsigned long long *status) @@ -766,23 +767,22 @@ static inline int acpi_install_cmos_rtc_space_handler(acpi_handle handle) static inline void acpi_remove_cmos_rtc_space_handler(acpi_handle handle) { } +static inline int +acpi_quirk_skip_serdev_enumeration(struct device *controller_parent, bool *skip) +{ + *skip = false; + return 0; +} #endif #if IS_ENABLED(CONFIG_X86_ANDROID_TABLETS) bool acpi_quirk_skip_i2c_client_enumeration(struct acpi_device *adev); -int acpi_quirk_skip_serdev_enumeration(struct device *controller_parent, bool *skip); bool acpi_quirk_skip_gpio_event_handlers(void); #else static inline bool acpi_quirk_skip_i2c_client_enumeration(struct acpi_device *adev) { return false; } -static inline int -acpi_quirk_skip_serdev_enumeration(struct device *controller_parent, bool *skip) -{ - *skip = false; - return 0; -} static inline bool acpi_quirk_skip_gpio_event_handlers(void) { return false; -- cgit v1.2.3 From 99b572e6136eab69a8c91d72cf8595b256e304b5 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 18 Feb 2024 16:15:33 +0100 Subject: ACPI: x86: Add DELL0501 handling to acpi_quirk_skip_serdev_enumeration() Some recent(ish) Dell AIO devices have a backlight controller board connected to an UART. This UART has a DELL0501 HID with CID set to PNP0501 so that the UART is still handled by 8250_pnp.c. Unfortunately there is no separate ACPI device with an UartSerialBusV2() resource to model the backlight-controller. This causes the kernel to create a /dev/ttyS0 char-device for the UART instead of creating an in kernel serdev-controller + serdev-device pair for a kernel backlight driver. Use the existing acpi_quirk_skip_serdev_enumeration() mechanism to work around this by returning skip=true for tty-ctrl parents with a HID of DELL0501. Like other cases where the UartSerialBusV2() resource is missing or broken this will only create the serdev-controller device and the serdev-device itself will need to be instantiated by platform code. Unfortunately in this case there is no device for the platform-code instantiating the serdev-device to bind to. So also create a platform_device for this. Signed-off-by: Hans de Goede Signed-off-by: Rafael J. Wysocki --- drivers/acpi/x86/utils.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/drivers/acpi/x86/utils.c b/drivers/acpi/x86/utils.c index 8829a907eee0..90c3d2eab9e9 100644 --- a/drivers/acpi/x86/utils.c +++ b/drivers/acpi/x86/utils.c @@ -484,8 +484,28 @@ static int acpi_dmi_skip_serdev_enumeration(struct device *controller_parent, bo int acpi_quirk_skip_serdev_enumeration(struct device *controller_parent, bool *skip) { + struct acpi_device *adev = ACPI_COMPANION(controller_parent); + *skip = false; + /* + * The DELL0501 ACPI HID represents an UART (CID is set to PNP0501) with + * a backlight-controller attached. There is no separate ACPI device with + * an UartSerialBusV2() resource to model the backlight-controller. + * Set skip to true so that the tty core creates a serdev ctrl device. + * The backlight driver will manually create the serdev client device. + */ + if (acpi_dev_hid_match(adev, "DELL0501")) { + *skip = true; + /* + * Create a platform dev for dell-uart-backlight to bind to. + * This is a static device, so no need to store the result. + */ + platform_device_register_simple("dell-uart-backlight", PLATFORM_DEVID_NONE, + NULL, 0); + return 0; + } + return acpi_dmi_skip_serdev_enumeration(controller_parent, skip); } EXPORT_SYMBOL_GPL(acpi_quirk_skip_serdev_enumeration); -- cgit v1.2.3 From 0cc46f1a52b4220ec11d98a01575909ca820a7b4 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 16 Feb 2024 17:38:55 +0100 Subject: ACPI: Drop the custom_method debugfs interface The ACPI custom_method debugfs interface is security-sensitive and concurrent access to it is broken [1]. Moreover, the recipe for preparing a customized version of a given control method has changed at one point due to ACPICA changes, which has not been reflected in its documentation, so whoever used it before has had to adapt and it had gone unnoticed for a long time. This interface was a bad idea to start with and its implementation is fragile at the design level. It's been always conceptually questionable, problematic from the security standpoint and implemented poorly. Patches fixing its most apparent functional issues (for example, [2]) don't actually address much of the above. Granted, at the time it was introduced, there was no alternative, but there is the AML debugger in the kernel now and there is the configfs interface allowing custom ACPI tables to be loaded. The former can be used for extensive AML debugging and the latter can be use for testing new AML. [3] Accordingly, drop custom_method along with its (outdated anyway) documentation. Link: https://lore.kernel.org/linux-acpi/20221227063335.61474-1-zh.nvgt@gmail.com/ # [1] Link: https://lore.kernel.org/linux-acpi/20231111132402.4142-1-shiqiang.deng213@gmail.com/ [2] Link: https://stackoverflow.com/questions/62849113/how-to-unload-an-overlay-loaded-using-acpi-config-sysfs # [3] Reported-by: Hang Zhang Signed-off-by: Rafael J. Wysocki Reviewed-by: Zhang Rui Reviewed-by: Kees Cook --- Documentation/firmware-guide/acpi/index.rst | 1 - .../firmware-guide/acpi/method-customizing.rst | 89 ------------------ drivers/acpi/Kconfig | 14 --- drivers/acpi/Makefile | 1 - drivers/acpi/custom_method.c | 103 --------------------- 5 files changed, 208 deletions(-) delete mode 100644 Documentation/firmware-guide/acpi/method-customizing.rst delete mode 100644 drivers/acpi/custom_method.c diff --git a/Documentation/firmware-guide/acpi/index.rst b/Documentation/firmware-guide/acpi/index.rst index b6a42f4ffe03..b246902f523f 100644 --- a/Documentation/firmware-guide/acpi/index.rst +++ b/Documentation/firmware-guide/acpi/index.rst @@ -14,7 +14,6 @@ ACPI Support dsd/phy enumeration osi - method-customizing method-tracing DSD-properties-rules debug diff --git a/Documentation/firmware-guide/acpi/method-customizing.rst b/Documentation/firmware-guide/acpi/method-customizing.rst deleted file mode 100644 index de3ebcaed4cf..000000000000 --- a/Documentation/firmware-guide/acpi/method-customizing.rst +++ /dev/null @@ -1,89 +0,0 @@ -.. SPDX-License-Identifier: GPL-2.0 - -======================================= -Linux ACPI Custom Control Method How To -======================================= - -:Author: Zhang Rui - - -Linux supports customizing ACPI control methods at runtime. - -Users can use this to: - -1. override an existing method which may not work correctly, - or just for debugging purposes. -2. insert a completely new method in order to create a missing - method such as _OFF, _ON, _STA, _INI, etc. - -For these cases, it is far simpler to dynamically install a single -control method rather than override the entire DSDT, because kernel -rebuild/reboot is not needed and test result can be got in minutes. - -.. note:: - - - Only ACPI METHOD can be overridden, any other object types like - "Device", "OperationRegion", are not recognized. Methods - declared inside scope operators are also not supported. - - - The same ACPI control method can be overridden for many times, - and it's always the latest one that used by Linux/kernel. - - - To get the ACPI debug object output (Store (AAAA, Debug)), - please run:: - - echo 1 > /sys/module/acpi/parameters/aml_debug_output - - -1. override an existing method -============================== -a) get the ACPI table via ACPI sysfs I/F. e.g. to get the DSDT, - just run "cat /sys/firmware/acpi/tables/DSDT > /tmp/dsdt.dat" -b) disassemble the table by running "iasl -d dsdt.dat". -c) rewrite the ASL code of the method and save it in a new file, -d) package the new file (psr.asl) to an ACPI table format. - Here is an example of a customized \_SB._AC._PSR method:: - - DefinitionBlock ("", "SSDT", 1, "", "", 0x20080715) - { - Method (\_SB_.AC._PSR, 0, NotSerialized) - { - Store ("In AC _PSR", Debug) - Return (ACON) - } - } - - Note that the full pathname of the method in ACPI namespace - should be used. -e) assemble the file to generate the AML code of the method. - e.g. "iasl -vw 6084 psr.asl" (psr.aml is generated as a result) - If parameter "-vw 6084" is not supported by your iASL compiler, - please try a newer version. -f) mount debugfs by "mount -t debugfs none /sys/kernel/debug" -g) override the old method via the debugfs by running - "cat /tmp/psr.aml > /sys/kernel/debug/acpi/custom_method" - -2. insert a new method -====================== -This is easier than overriding an existing method. -We just need to create the ASL code of the method we want to -insert and then follow the step c) ~ g) in section 1. - -3. undo your changes -==================== -The "undo" operation is not supported for a new inserted method -right now, i.e. we can not remove a method currently. -For an overridden method, in order to undo your changes, please -save a copy of the method original ASL code in step c) section 1, -and redo step c) ~ g) to override the method with the original one. - - -.. note:: We can use a kernel with multiple custom ACPI method running, - But each individual write to debugfs can implement a SINGLE - method override. i.e. if we want to insert/override multiple - ACPI methods, we need to redo step c) ~ g) for multiple times. - -.. note:: Be aware that root can mis-use this driver to modify arbitrary - memory and gain additional rights, if root's privileges got - restricted (for example if root is not allowed to load additional - modules after boot). diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig index 3c3f8037ebed..c645bb453f3b 100644 --- a/drivers/acpi/Kconfig +++ b/drivers/acpi/Kconfig @@ -449,20 +449,6 @@ config ACPI_HED which is used to report some hardware errors notified via SCI, mainly the corrected errors. -config ACPI_CUSTOM_METHOD - tristate "Allow ACPI methods to be inserted/replaced at run time" - depends on DEBUG_FS - help - This debug facility allows ACPI AML methods to be inserted and/or - replaced without rebooting the system. For details refer to: - Documentation/firmware-guide/acpi/method-customizing.rst. - - NOTE: This option is security sensitive, because it allows arbitrary - kernel memory to be written to by root (uid=0) users, allowing them - to bypass certain security measures (e.g. if root is not allowed to - load additional kernel modules after boot, this feature may be used - to override that restriction). - config ACPI_BGRT bool "Boottime Graphics Resource Table support" depends on EFI && (X86 || ARM64) diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile index 12ef8180d272..8cc8c0d9c873 100644 --- a/drivers/acpi/Makefile +++ b/drivers/acpi/Makefile @@ -101,7 +101,6 @@ obj-$(CONFIG_ACPI_SBS) += sbshc.o obj-$(CONFIG_ACPI_SBS) += sbs.o obj-$(CONFIG_ACPI_HED) += hed.o obj-$(CONFIG_ACPI_EC_DEBUGFS) += ec_sys.o -obj-$(CONFIG_ACPI_CUSTOM_METHOD)+= custom_method.o obj-$(CONFIG_ACPI_BGRT) += bgrt.o obj-$(CONFIG_ACPI_CPPC_LIB) += cppc_acpi.o obj-$(CONFIG_ACPI_SPCR_TABLE) += spcr.o diff --git a/drivers/acpi/custom_method.c b/drivers/acpi/custom_method.c deleted file mode 100644 index d39a9b474727..000000000000 --- a/drivers/acpi/custom_method.c +++ /dev/null @@ -1,103 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * custom_method.c - debugfs interface for customizing ACPI control method - */ - -#include -#include -#include -#include -#include -#include -#include - -#include "internal.h" - -MODULE_LICENSE("GPL"); - -static struct dentry *cm_dentry; - -/* /sys/kernel/debug/acpi/custom_method */ - -static ssize_t cm_write(struct file *file, const char __user *user_buf, - size_t count, loff_t *ppos) -{ - static char *buf; - static u32 max_size; - static u32 uncopied_bytes; - - struct acpi_table_header table; - acpi_status status; - int ret; - - ret = security_locked_down(LOCKDOWN_ACPI_TABLES); - if (ret) - return ret; - - if (!(*ppos)) { - /* parse the table header to get the table length */ - if (count <= sizeof(struct acpi_table_header)) - return -EINVAL; - if (copy_from_user(&table, user_buf, - sizeof(struct acpi_table_header))) - return -EFAULT; - uncopied_bytes = max_size = table.length; - /* make sure the buf is not allocated */ - kfree(buf); - buf = kzalloc(max_size, GFP_KERNEL); - if (!buf) - return -ENOMEM; - } - - if (buf == NULL) - return -EINVAL; - - if ((*ppos > max_size) || - (*ppos + count > max_size) || - (*ppos + count < count) || - (count > uncopied_bytes)) { - kfree(buf); - buf = NULL; - return -EINVAL; - } - - if (copy_from_user(buf + (*ppos), user_buf, count)) { - kfree(buf); - buf = NULL; - return -EFAULT; - } - - uncopied_bytes -= count; - *ppos += count; - - if (!uncopied_bytes) { - status = acpi_install_method(buf); - kfree(buf); - buf = NULL; - if (ACPI_FAILURE(status)) - return -EINVAL; - add_taint(TAINT_OVERRIDDEN_ACPI_TABLE, LOCKDEP_NOW_UNRELIABLE); - } - - return count; -} - -static const struct file_operations cm_fops = { - .write = cm_write, - .llseek = default_llseek, -}; - -static int __init acpi_custom_method_init(void) -{ - cm_dentry = debugfs_create_file("custom_method", S_IWUSR, - acpi_debugfs_dir, NULL, &cm_fops); - return 0; -} - -static void __exit acpi_custom_method_exit(void) -{ - debugfs_remove(cm_dentry); -} - -module_init(acpi_custom_method_init); -module_exit(acpi_custom_method_exit); -- cgit v1.2.3 From f2f212f36a8cd3cd6763a19611d0edd2a19df51a Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Mon, 20 Nov 2023 18:30:54 +0100 Subject: ACPI: APEI: GHES: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new(), which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Instead of returning an error code, emit a better error message than the core. Apart from the improved error message this patch has no effects for the driver. Signed-off-by: Uwe Kleine-König Signed-off-by: Rafael J. Wysocki --- drivers/acpi/apei/ghes.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/drivers/acpi/apei/ghes.c b/drivers/acpi/apei/ghes.c index ab2a82cb1b0b..512067cac170 100644 --- a/drivers/acpi/apei/ghes.c +++ b/drivers/acpi/apei/ghes.c @@ -1455,7 +1455,7 @@ err: return rc; } -static int ghes_remove(struct platform_device *ghes_dev) +static void ghes_remove(struct platform_device *ghes_dev) { int rc; struct ghes *ghes; @@ -1492,8 +1492,15 @@ static int ghes_remove(struct platform_device *ghes_dev) break; case ACPI_HEST_NOTIFY_SOFTWARE_DELEGATED: rc = apei_sdei_unregister_ghes(ghes); - if (rc) - return rc; + if (rc) { + /* + * Returning early results in a resource leak, but we're + * only here if stopping the hardware failed. + */ + dev_err(&ghes_dev->dev, "Failed to unregister ghes (%pe)\n", + ERR_PTR(rc)); + return; + } break; default: BUG(); @@ -1507,8 +1514,6 @@ static int ghes_remove(struct platform_device *ghes_dev) mutex_unlock(&ghes_devs_mutex); kfree(ghes); - - return 0; } static struct platform_driver ghes_platform_driver = { @@ -1516,7 +1521,7 @@ static struct platform_driver ghes_platform_driver = { .name = "GHES", }, .probe = ghes_probe, - .remove = ghes_remove, + .remove_new = ghes_remove, }; void __init acpi_ghes_init(void) -- cgit v1.2.3 From 9a7897a2b03183f15ea4c7645416daf3ae1f634e Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Thu, 22 Feb 2024 19:52:33 +0100 Subject: ACPI: TAD: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new(), which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpi_tad.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/acpi/acpi_tad.c b/drivers/acpi/acpi_tad.c index 33c3b16af556..1d670dbe4d1d 100644 --- a/drivers/acpi/acpi_tad.c +++ b/drivers/acpi/acpi_tad.c @@ -554,7 +554,7 @@ static int acpi_tad_disable_timer(struct device *dev, u32 timer_id) return acpi_tad_wake_set(dev, "_STV", timer_id, ACPI_TAD_WAKE_DISABLED); } -static int acpi_tad_remove(struct platform_device *pdev) +static void acpi_tad_remove(struct platform_device *pdev) { struct device *dev = &pdev->dev; acpi_handle handle = ACPI_HANDLE(dev); @@ -579,7 +579,6 @@ static int acpi_tad_remove(struct platform_device *pdev) pm_runtime_put_sync(dev); pm_runtime_disable(dev); acpi_remove_cmos_rtc_space_handler(handle); - return 0; } static int acpi_tad_probe(struct platform_device *pdev) @@ -684,7 +683,7 @@ static struct platform_driver acpi_tad_driver = { .acpi_match_table = acpi_tad_ids, }, .probe = acpi_tad_probe, - .remove = acpi_tad_remove, + .remove_new = acpi_tad_remove, }; MODULE_DEVICE_TABLE(acpi, acpi_tad_ids); -- cgit v1.2.3 From 10ff709a68ccd985cbbbdd04beac468724ca3c18 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Thu, 22 Feb 2024 19:52:34 +0100 Subject: ACPI: AGDI: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new(), which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Acked-by: Hanjun Guo Signed-off-by: Rafael J. Wysocki --- drivers/acpi/arm64/agdi.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/acpi/arm64/agdi.c b/drivers/acpi/arm64/agdi.c index 8b3c7d42b41b..f5f21dd0d277 100644 --- a/drivers/acpi/arm64/agdi.c +++ b/drivers/acpi/arm64/agdi.c @@ -58,7 +58,7 @@ static int agdi_probe(struct platform_device *pdev) return agdi_sdei_probe(pdev, adata); } -static int agdi_remove(struct platform_device *pdev) +static void agdi_remove(struct platform_device *pdev) { struct agdi_data *adata = dev_get_platdata(&pdev->dev); int err, i; @@ -67,7 +67,7 @@ static int agdi_remove(struct platform_device *pdev) if (err) { dev_err(&pdev->dev, "Failed to disable sdei-event #%d (%pe)\n", adata->sdei_event, ERR_PTR(err)); - return 0; + return; } for (i = 0; i < 3; i++) { @@ -81,8 +81,6 @@ static int agdi_remove(struct platform_device *pdev) if (err) dev_err(&pdev->dev, "Failed to unregister sdei-event #%d (%pe)\n", adata->sdei_event, ERR_PTR(err)); - - return 0; } static struct platform_driver agdi_driver = { @@ -90,7 +88,7 @@ static struct platform_driver agdi_driver = { .name = "agdi", }, .probe = agdi_probe, - .remove = agdi_remove, + .remove_new = agdi_remove, }; void __init acpi_agdi_init(void) -- cgit v1.2.3 From da22084d586670fa5cfdc92fd7e350cf1fc737de Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Thu, 22 Feb 2024 19:52:35 +0100 Subject: ACPI: DPTF: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new(), which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert these two drivers from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Signed-off-by: Rafael J. Wysocki --- drivers/acpi/dptf/dptf_pch_fivr.c | 6 ++---- drivers/acpi/dptf/dptf_power.c | 6 ++---- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/drivers/acpi/dptf/dptf_pch_fivr.c b/drivers/acpi/dptf/dptf_pch_fivr.c index 4919e7abe93f..654aaa53c67f 100644 --- a/drivers/acpi/dptf/dptf_pch_fivr.c +++ b/drivers/acpi/dptf/dptf_pch_fivr.c @@ -141,11 +141,9 @@ static int pch_fivr_add(struct platform_device *pdev) return 0; } -static int pch_fivr_remove(struct platform_device *pdev) +static void pch_fivr_remove(struct platform_device *pdev) { sysfs_remove_group(&pdev->dev.kobj, &pch_fivr_attribute_group); - - return 0; } static const struct acpi_device_id pch_fivr_device_ids[] = { @@ -159,7 +157,7 @@ MODULE_DEVICE_TABLE(acpi, pch_fivr_device_ids); static struct platform_driver pch_fivr_driver = { .probe = pch_fivr_add, - .remove = pch_fivr_remove, + .remove_new = pch_fivr_remove, .driver = { .name = "dptf_pch_fivr", .acpi_match_table = pch_fivr_device_ids, diff --git a/drivers/acpi/dptf/dptf_power.c b/drivers/acpi/dptf/dptf_power.c index 86561eda939f..b8187babbbbb 100644 --- a/drivers/acpi/dptf/dptf_power.c +++ b/drivers/acpi/dptf/dptf_power.c @@ -209,7 +209,7 @@ static int dptf_power_add(struct platform_device *pdev) return 0; } -static int dptf_power_remove(struct platform_device *pdev) +static void dptf_power_remove(struct platform_device *pdev) { struct acpi_device *acpi_dev = platform_get_drvdata(pdev); @@ -221,8 +221,6 @@ static int dptf_power_remove(struct platform_device *pdev) sysfs_remove_group(&pdev->dev.kobj, &dptf_battery_attribute_group); else sysfs_remove_group(&pdev->dev.kobj, &dptf_power_attribute_group); - - return 0; } static const struct acpi_device_id int3407_device_ids[] = { @@ -242,7 +240,7 @@ MODULE_DEVICE_TABLE(acpi, int3407_device_ids); static struct platform_driver dptf_power_driver = { .probe = dptf_power_add, - .remove = dptf_power_remove, + .remove_new = dptf_power_remove, .driver = { .name = "dptf_power", .acpi_match_table = int3407_device_ids, -- cgit v1.2.3 From c21f50e1f39408d43b0fd034764ea63985db2d18 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Thu, 22 Feb 2024 19:52:36 +0100 Subject: ACPI: GED: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new(), which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Signed-off-by: Rafael J. Wysocki --- drivers/acpi/evged.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/acpi/evged.c b/drivers/acpi/evged.c index fe6b6792c8bb..11778c93254b 100644 --- a/drivers/acpi/evged.c +++ b/drivers/acpi/evged.c @@ -173,10 +173,9 @@ static void ged_shutdown(struct platform_device *pdev) } } -static int ged_remove(struct platform_device *pdev) +static void ged_remove(struct platform_device *pdev) { ged_shutdown(pdev); - return 0; } static const struct acpi_device_id ged_acpi_ids[] = { @@ -186,7 +185,7 @@ static const struct acpi_device_id ged_acpi_ids[] = { static struct platform_driver ged_driver = { .probe = ged_probe, - .remove = ged_remove, + .remove_new = ged_remove, .shutdown = ged_shutdown, .driver = { .name = MODULE_NAME, -- cgit v1.2.3 From 24fd13c0824f1fc3cb2db0f96d8ac78302b5beb7 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Thu, 22 Feb 2024 19:52:37 +0100 Subject: ACPI: fan: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new(), which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Signed-off-by: Rafael J. Wysocki --- drivers/acpi/fan_core.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/acpi/fan_core.c b/drivers/acpi/fan_core.c index 9dccbae9e8ea..ff72e4ef8738 100644 --- a/drivers/acpi/fan_core.c +++ b/drivers/acpi/fan_core.c @@ -387,7 +387,7 @@ err_end: return result; } -static int acpi_fan_remove(struct platform_device *pdev) +static void acpi_fan_remove(struct platform_device *pdev) { struct acpi_fan *fan = platform_get_drvdata(pdev); @@ -399,8 +399,6 @@ static int acpi_fan_remove(struct platform_device *pdev) sysfs_remove_link(&pdev->dev.kobj, "thermal_cooling"); sysfs_remove_link(&fan->cdev->device.kobj, "device"); thermal_cooling_device_unregister(fan->cdev); - - return 0; } #ifdef CONFIG_PM_SLEEP @@ -446,7 +444,7 @@ static const struct dev_pm_ops acpi_fan_pm = { static struct platform_driver acpi_fan_driver = { .probe = acpi_fan_probe, - .remove = acpi_fan_remove, + .remove_new = acpi_fan_remove, .driver = { .name = "acpi-fan", .acpi_match_table = fan_device_ids, -- cgit v1.2.3 From b4a48c50589e4096d4cc5fefbcea4ebc9a7f31ef Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Thu, 22 Feb 2024 19:52:38 +0100 Subject: ACPI: pfr_telemetry: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new(), which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Signed-off-by: Rafael J. Wysocki --- drivers/acpi/pfr_telemetry.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/acpi/pfr_telemetry.c b/drivers/acpi/pfr_telemetry.c index 843f678ade0c..998264a7333d 100644 --- a/drivers/acpi/pfr_telemetry.c +++ b/drivers/acpi/pfr_telemetry.c @@ -347,13 +347,11 @@ static const struct file_operations acpi_pfrt_log_fops = { .llseek = noop_llseek, }; -static int acpi_pfrt_log_remove(struct platform_device *pdev) +static void acpi_pfrt_log_remove(struct platform_device *pdev) { struct pfrt_log_device *pfrt_log_dev = platform_get_drvdata(pdev); misc_deregister(&pfrt_log_dev->miscdev); - - return 0; } static void pfrt_log_put_idx(void *data) @@ -427,7 +425,7 @@ static struct platform_driver acpi_pfrt_log_driver = { .acpi_match_table = acpi_pfrt_log_ids, }, .probe = acpi_pfrt_log_probe, - .remove = acpi_pfrt_log_remove, + .remove_new = acpi_pfrt_log_remove, }; module_platform_driver(acpi_pfrt_log_driver); -- cgit v1.2.3 From 74550b070d0b40f5b9aaa8c1161e7b587e391289 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Thu, 22 Feb 2024 19:52:39 +0100 Subject: ACPI: pfr_update: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new(), which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Signed-off-by: Rafael J. Wysocki --- drivers/acpi/pfr_update.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/acpi/pfr_update.c b/drivers/acpi/pfr_update.c index 98267f163e2b..8b2910995fc1 100644 --- a/drivers/acpi/pfr_update.c +++ b/drivers/acpi/pfr_update.c @@ -489,13 +489,11 @@ static const struct file_operations acpi_pfru_fops = { .llseek = noop_llseek, }; -static int acpi_pfru_remove(struct platform_device *pdev) +static void acpi_pfru_remove(struct platform_device *pdev) { struct pfru_device *pfru_dev = platform_get_drvdata(pdev); misc_deregister(&pfru_dev->miscdev); - - return 0; } static void pfru_put_idx(void *data) @@ -567,7 +565,7 @@ static struct platform_driver acpi_pfru_driver = { .acpi_match_table = acpi_pfru_ids, }, .probe = acpi_pfru_probe, - .remove = acpi_pfru_remove, + .remove_new = acpi_pfru_remove, }; module_platform_driver(acpi_pfru_driver); -- cgit v1.2.3 From 8ec7071385508822892cabc2c0cb74333859407a Mon Sep 17 00:00:00 2001 From: Avadhut Naik Date: Thu, 29 Feb 2024 00:22:45 -0600 Subject: ACPI: APEI: Skip initialization of GHES_ASSIST structures for Machine Check Architecture To support GHES_ASSIST on Machine Check Architecture (MCA) error sources, a set of GHES structures is provided by the system firmware for each MCA error source. Each of these sets consists of a GHES structure for each MCA bank on each logical CPU, with all structures of a set sharing a common Related Source ID, equal to the Source ID of one of the MCA error source structures.[1] On SOCs with large core counts, this typically equates to tens of thousands of GHES_ASSIST structures for MCA under "/sys/bus/platform/drivers/GHES". Support for GHES_ASSIST however, hasn't been implemented in the kernel. As such, the information provided through these structures is not consumed by Linux. Moreover, these GHES_ASSIST structures for MCA, which are supposed to provide supplemental information in context of an error reported by hardware, are setup as independent error sources by the kernel during HEST initialization. Additionally, if the Type field of the Notification structure, associated with these GHES_ASSIST structures for MCA, is set to Polled, the kernel sets up a timer for each individual structure. The duration of the timer is derived from the Poll Interval field of the Notification structure. On SOCs with high core counts, this will result in tens of thousands of timers expiring periodically causing unnecessary preemptions and wastage of CPU cycles. The problem will particularly intensify if Poll Interval duration is not sufficiently high. Since GHES_ASSIST support is not present in kernel, skip initialization of GHES_ASSIST structures for MCA to eliminate their performance impact. [1] ACPI specification 6.5, section 18.7 Signed-off-by: Avadhut Naik Reviewed-by: Yazen Ghannam Reviewed-by: Tony Luck Signed-off-by: Rafael J. Wysocki --- drivers/acpi/apei/hest.c | 51 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/drivers/acpi/apei/hest.c b/drivers/acpi/apei/hest.c index 6aef1ee5e1bd..20d757687e3d 100644 --- a/drivers/acpi/apei/hest.c +++ b/drivers/acpi/apei/hest.c @@ -37,6 +37,20 @@ EXPORT_SYMBOL_GPL(hest_disable); static struct acpi_table_hest *__read_mostly hest_tab; +/* + * Since GHES_ASSIST is not supported, skip initialization of GHES_ASSIST + * structures for MCA. + * During HEST parsing, detected MCA error sources are cached from early + * table entries so that the Flags and Source Id fields from these cached + * values are then referred to in later table entries to determine if the + * encountered GHES_ASSIST structure should be initialized. + */ +static struct { + struct acpi_hest_ia_corrected *cmc; + struct acpi_hest_ia_machine_check *mc; + struct acpi_hest_ia_deferred_check *dmc; +} mces; + static const int hest_esrc_len_tab[ACPI_HEST_TYPE_RESERVED] = { [ACPI_HEST_TYPE_IA32_CHECK] = -1, /* need further calculation */ [ACPI_HEST_TYPE_IA32_CORRECTED_CHECK] = -1, @@ -70,22 +84,54 @@ static int hest_esrc_len(struct acpi_hest_header *hest_hdr) cmc = (struct acpi_hest_ia_corrected *)hest_hdr; len = sizeof(*cmc) + cmc->num_hardware_banks * sizeof(struct acpi_hest_ia_error_bank); + mces.cmc = cmc; } else if (hest_type == ACPI_HEST_TYPE_IA32_CHECK) { struct acpi_hest_ia_machine_check *mc; mc = (struct acpi_hest_ia_machine_check *)hest_hdr; len = sizeof(*mc) + mc->num_hardware_banks * sizeof(struct acpi_hest_ia_error_bank); + mces.mc = mc; } else if (hest_type == ACPI_HEST_TYPE_IA32_DEFERRED_CHECK) { struct acpi_hest_ia_deferred_check *mc; mc = (struct acpi_hest_ia_deferred_check *)hest_hdr; len = sizeof(*mc) + mc->num_hardware_banks * sizeof(struct acpi_hest_ia_error_bank); + mces.dmc = mc; } BUG_ON(len == -1); return len; }; +/* + * GHES and GHESv2 structures share the same format, starting from + * Source Id and ending in Error Status Block Length (inclusive). + */ +static bool is_ghes_assist_struct(struct acpi_hest_header *hest_hdr) +{ + struct acpi_hest_generic *ghes; + u16 related_source_id; + + if (hest_hdr->type != ACPI_HEST_TYPE_GENERIC_ERROR && + hest_hdr->type != ACPI_HEST_TYPE_GENERIC_ERROR_V2) + return false; + + ghes = (struct acpi_hest_generic *)hest_hdr; + related_source_id = ghes->related_source_id; + + if (mces.cmc && mces.cmc->flags & ACPI_HEST_GHES_ASSIST && + related_source_id == mces.cmc->header.source_id) + return true; + if (mces.mc && mces.mc->flags & ACPI_HEST_GHES_ASSIST && + related_source_id == mces.mc->header.source_id) + return true; + if (mces.dmc && mces.dmc->flags & ACPI_HEST_GHES_ASSIST && + related_source_id == mces.dmc->header.source_id) + return true; + + return false; +} + 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) @@ -114,6 +160,11 @@ static int apei_hest_parse(apei_hest_func_t func, void *data) return -EINVAL; } + if (is_ghes_assist_struct(hest_hdr)) { + hest_hdr = (void *)hest_hdr + len; + continue; + } + rc = func(hest_hdr, data); if (rc) return rc; -- cgit v1.2.3