From 98a455d91e7116ca417bc37da6aa2dd633206a6f Mon Sep 17 00:00:00 2001 From: Shunyong Yang Date: Tue, 18 Dec 2018 14:02:45 +0800 Subject: ACPI / tables: table override from built-in initrd In some scenario, we need to build initrd with kernel in a single image. This can simplify system deployment process by downloading the whole system once, such as in IC verification. This patch adds support to override ACPI tables from built-in initrd. Signed-off-by: Shunyong Yang [ rjw: Minor cleanups ] Signed-off-by: Rafael J. Wysocki --- drivers/acpi/Kconfig | 10 ++++++++++ drivers/acpi/tables.c | 12 ++++++++++-- 2 files changed, 20 insertions(+), 2 deletions(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig index 90ff0a47c12e..4e015c77e48e 100644 --- a/drivers/acpi/Kconfig +++ b/drivers/acpi/Kconfig @@ -357,6 +357,16 @@ config ACPI_TABLE_UPGRADE initrd, therefore it's safe to say Y. See Documentation/acpi/initrd_table_override.txt for details +config ACPI_TABLE_OVERRIDE_VIA_BUILTIN_INITRD + bool "Override ACPI tables from built-in initrd" + depends on ACPI_TABLE_UPGRADE + depends on INITRAMFS_SOURCE!="" && INITRAMFS_COMPRESSION="" + help + This option provides functionality to override arbitrary ACPI tables + from built-in uncompressed initrd. + + See Documentation/acpi/initrd_table_override.txt for details + config ACPI_DEBUG bool "Debug Statements" help diff --git a/drivers/acpi/tables.c b/drivers/acpi/tables.c index 48eabb6c2d4f..8fccbe49612a 100644 --- a/drivers/acpi/tables.c +++ b/drivers/acpi/tables.c @@ -473,14 +473,22 @@ static DECLARE_BITMAP(acpi_initrd_installed, NR_ACPI_INITRD_TABLES); void __init acpi_table_upgrade(void) { - void *data = (void *)initrd_start; - size_t size = initrd_end - initrd_start; + void *data; + size_t size; int sig, no, table_nr = 0, total_offset = 0; long offset = 0; struct acpi_table_header *table; char cpio_path[32] = "kernel/firmware/acpi/"; struct cpio_data file; + if (IS_ENABLED(CONFIG_ACPI_TABLE_OVERRIDE_VIA_BUILTIN_INITRD)) { + data = __initramfs_start; + size = __initramfs_size; + } else { + data = (void *)initrd_start; + size = initrd_end - initrd_start; + } + if (data == NULL || size == 0) return; -- cgit v1.2.3 From 9ec6dbfbdc0ade855e6bc1da66e263e0d926697c Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Tue, 22 Jan 2019 16:21:03 +0100 Subject: ACPI: no need to check return value of debugfs_create functions When calling debugfs functions, there is no need to ever check the return value. The function can work or not, but the code logic should never do something different based on this. Signed-off-by: Greg Kroah-Hartman Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpi_dbg.c | 15 ++------ drivers/acpi/apei/einj.c | 86 ++++++++++++-------------------------------- drivers/acpi/custom_method.c | 6 ---- drivers/acpi/ec_sys.c | 36 +++++-------------- 4 files changed, 32 insertions(+), 111 deletions(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/acpi_dbg.c b/drivers/acpi/acpi_dbg.c index a2dcd62ea32f..f3bca448b305 100644 --- a/drivers/acpi/acpi_dbg.c +++ b/drivers/acpi/acpi_dbg.c @@ -752,11 +752,6 @@ int __init acpi_aml_init(void) { int ret = 0; - if (!acpi_debugfs_dir) { - ret = -ENOENT; - goto err_exit; - } - /* Initialize AML IO interface */ mutex_init(&acpi_aml_io.lock); init_waitqueue_head(&acpi_aml_io.wait); @@ -766,10 +761,6 @@ int __init acpi_aml_init(void) S_IFREG | S_IRUGO | S_IWUSR, acpi_debugfs_dir, NULL, &acpi_aml_operations); - if (acpi_aml_dentry == NULL) { - ret = -ENODEV; - goto err_exit; - } ret = acpi_register_debugger(THIS_MODULE, &acpi_aml_debugger); if (ret) goto err_fs; @@ -788,10 +779,8 @@ void __exit acpi_aml_exit(void) { if (acpi_aml_initialized) { acpi_unregister_debugger(&acpi_aml_debugger); - if (acpi_aml_dentry) { - debugfs_remove(acpi_aml_dentry); - acpi_aml_dentry = NULL; - } + debugfs_remove(acpi_aml_dentry); + acpi_aml_dentry = NULL; acpi_aml_initialized = false; } } diff --git a/drivers/acpi/apei/einj.c b/drivers/acpi/apei/einj.c index fcccbfdbdd1a..c42299e048e4 100644 --- a/drivers/acpi/apei/einj.c +++ b/drivers/acpi/apei/einj.c @@ -679,7 +679,6 @@ static int __init einj_init(void) { int rc; acpi_status status; - struct dentry *fentry; struct apei_exec_context ctx; if (acpi_disabled) { @@ -707,25 +706,13 @@ static int __init einj_init(void) rc = -ENOMEM; einj_debug_dir = debugfs_create_dir("einj", apei_get_debugfs_dir()); - if (!einj_debug_dir) { - pr_err("Error creating debugfs node.\n"); - goto err_cleanup; - } - fentry = debugfs_create_file("available_error_type", S_IRUSR, - einj_debug_dir, NULL, - &available_error_type_fops); - if (!fentry) - goto err_cleanup; - - fentry = debugfs_create_file("error_type", S_IRUSR | S_IWUSR, - einj_debug_dir, NULL, &error_type_fops); - if (!fentry) - goto err_cleanup; - fentry = debugfs_create_file("error_inject", S_IWUSR, - einj_debug_dir, NULL, &error_inject_fops); - if (!fentry) - goto err_cleanup; + debugfs_create_file("available_error_type", S_IRUSR, einj_debug_dir, + NULL, &available_error_type_fops); + debugfs_create_file("error_type", S_IRUSR | S_IWUSR, einj_debug_dir, + NULL, &error_type_fops); + debugfs_create_file("error_inject", S_IWUSR, einj_debug_dir, + NULL, &error_inject_fops); apei_resources_init(&einj_resources); einj_exec_ctx_init(&ctx); @@ -750,66 +737,37 @@ static int __init einj_init(void) rc = -ENOMEM; einj_param = einj_get_parameter_address(); if ((param_extension || acpi5) && einj_param) { - fentry = debugfs_create_x32("flags", S_IRUSR | S_IWUSR, - einj_debug_dir, &error_flags); - if (!fentry) - goto err_unmap; - fentry = debugfs_create_x64("param1", S_IRUSR | S_IWUSR, - einj_debug_dir, &error_param1); - if (!fentry) - goto err_unmap; - fentry = debugfs_create_x64("param2", S_IRUSR | S_IWUSR, - einj_debug_dir, &error_param2); - if (!fentry) - goto err_unmap; - fentry = debugfs_create_x64("param3", S_IRUSR | S_IWUSR, - einj_debug_dir, &error_param3); - if (!fentry) - goto err_unmap; - fentry = debugfs_create_x64("param4", S_IRUSR | S_IWUSR, - einj_debug_dir, &error_param4); - if (!fentry) - goto err_unmap; - - fentry = debugfs_create_x32("notrigger", S_IRUSR | S_IWUSR, - einj_debug_dir, ¬rigger); - if (!fentry) - goto err_unmap; + debugfs_create_x32("flags", S_IRUSR | S_IWUSR, einj_debug_dir, + &error_flags); + debugfs_create_x64("param1", S_IRUSR | S_IWUSR, einj_debug_dir, + &error_param1); + debugfs_create_x64("param2", S_IRUSR | S_IWUSR, einj_debug_dir, + &error_param2); + debugfs_create_x64("param3", S_IRUSR | S_IWUSR, einj_debug_dir, + &error_param3); + debugfs_create_x64("param4", S_IRUSR | S_IWUSR, einj_debug_dir, + &error_param4); + debugfs_create_x32("notrigger", S_IRUSR | S_IWUSR, + einj_debug_dir, ¬rigger); } if (vendor_dev[0]) { vendor_blob.data = vendor_dev; vendor_blob.size = strlen(vendor_dev); - fentry = debugfs_create_blob("vendor", S_IRUSR, - einj_debug_dir, &vendor_blob); - if (!fentry) - goto err_unmap; - fentry = debugfs_create_x32("vendor_flags", S_IRUSR | S_IWUSR, - einj_debug_dir, &vendor_flags); - if (!fentry) - goto err_unmap; + debugfs_create_blob("vendor", S_IRUSR, einj_debug_dir, + &vendor_blob); + debugfs_create_x32("vendor_flags", S_IRUSR | S_IWUSR, + einj_debug_dir, &vendor_flags); } pr_info("Error INJection is initialized.\n"); return 0; -err_unmap: - if (einj_param) { - acpi_size size = (acpi5) ? - sizeof(struct set_error_type_with_address) : - sizeof(struct einj_parameter); - - acpi_os_unmap_iomem(einj_param, size); - pr_err("Error creating param extension debugfs nodes.\n"); - } - apei_exec_post_unmap_gars(&ctx); err_release: apei_resources_release(&einj_resources); err_fini: apei_resources_fini(&einj_resources); -err_cleanup: - pr_err("Error creating primary debugfs nodes.\n"); debugfs_remove_recursive(einj_debug_dir); return rc; diff --git a/drivers/acpi/custom_method.c b/drivers/acpi/custom_method.c index 4451877f83b6..aa972dc5cb7e 100644 --- a/drivers/acpi/custom_method.c +++ b/drivers/acpi/custom_method.c @@ -79,14 +79,8 @@ static const struct file_operations cm_fops = { static int __init acpi_custom_method_init(void) { - if (acpi_debugfs_dir == NULL) - return -ENOENT; - cm_dentry = debugfs_create_file("custom_method", S_IWUSR, acpi_debugfs_dir, NULL, &cm_fops); - if (cm_dentry == NULL) - return -ENODEV; - return 0; } diff --git a/drivers/acpi/ec_sys.c b/drivers/acpi/ec_sys.c index dd70d6c2bca0..23faa66ea772 100644 --- a/drivers/acpi/ec_sys.c +++ b/drivers/acpi/ec_sys.c @@ -108,52 +108,32 @@ static const struct file_operations acpi_ec_io_ops = { .llseek = default_llseek, }; -static int acpi_ec_add_debugfs(struct acpi_ec *ec, unsigned int ec_device_count) +static void acpi_ec_add_debugfs(struct acpi_ec *ec, unsigned int ec_device_count) { struct dentry *dev_dir; char name[64]; umode_t mode = 0400; - if (ec_device_count == 0) { + if (ec_device_count == 0) acpi_ec_debugfs_dir = debugfs_create_dir("ec", NULL); - if (!acpi_ec_debugfs_dir) - return -ENOMEM; - } sprintf(name, "ec%u", ec_device_count); dev_dir = debugfs_create_dir(name, acpi_ec_debugfs_dir); - if (!dev_dir) { - if (ec_device_count != 0) - goto error; - return -ENOMEM; - } - if (!debugfs_create_x32("gpe", 0444, dev_dir, &first_ec->gpe)) - goto error; - if (!debugfs_create_bool("use_global_lock", 0444, dev_dir, - &first_ec->global_lock)) - goto error; + debugfs_create_x32("gpe", 0444, dev_dir, &first_ec->gpe); + debugfs_create_bool("use_global_lock", 0444, dev_dir, + &first_ec->global_lock); if (write_support) mode = 0600; - if (!debugfs_create_file("io", mode, dev_dir, ec, &acpi_ec_io_ops)) - goto error; - - return 0; - -error: - debugfs_remove_recursive(acpi_ec_debugfs_dir); - return -ENOMEM; + debugfs_create_file("io", mode, dev_dir, ec, &acpi_ec_io_ops); } static int __init acpi_ec_sys_init(void) { - int err = 0; if (first_ec) - err = acpi_ec_add_debugfs(first_ec, 0); - else - err = -ENODEV; - return err; + acpi_ec_add_debugfs(first_ec, 0); + return 0; } static void __exit acpi_ec_sys_exit(void) -- cgit v1.2.3 From 6010ce3f2e57a4a30327abba528876bd7c8cbd36 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Thu, 24 Jan 2019 11:25:59 +0100 Subject: ACPI: debug: Clean up acpi_aml_init() The err_exit label in acpi_aml_init() is not used any more after commit 9ec6dbfbdc0a ("ACPI: no need to check return value of debugfs_create functions"), but the other label in there is not necessary too, so rearrange the code to get rid of them both. No intentional functional impact. Fixes: 9ec6dbfbdc0a ("ACPI: no need to check return value of debugfs_create functions") Reported-by: Stephen Rothwell Reviewed-by: Greg Kroah-Hartman Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpi_dbg.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/acpi_dbg.c b/drivers/acpi/acpi_dbg.c index f3bca448b305..4a434c23a196 100644 --- a/drivers/acpi/acpi_dbg.c +++ b/drivers/acpi/acpi_dbg.c @@ -750,29 +750,28 @@ static const struct acpi_debugger_ops acpi_aml_debugger = { int __init acpi_aml_init(void) { - int ret = 0; + int ret; /* Initialize AML IO interface */ mutex_init(&acpi_aml_io.lock); init_waitqueue_head(&acpi_aml_io.wait); acpi_aml_io.out_crc.buf = acpi_aml_io.out_buf; acpi_aml_io.in_crc.buf = acpi_aml_io.in_buf; + acpi_aml_dentry = debugfs_create_file("acpidbg", S_IFREG | S_IRUGO | S_IWUSR, acpi_debugfs_dir, NULL, &acpi_aml_operations); - ret = acpi_register_debugger(THIS_MODULE, &acpi_aml_debugger); - if (ret) - goto err_fs; - acpi_aml_initialized = true; -err_fs: + ret = acpi_register_debugger(THIS_MODULE, &acpi_aml_debugger); if (ret) { debugfs_remove(acpi_aml_dentry); acpi_aml_dentry = NULL; + return ret; } -err_exit: - return ret; + + acpi_aml_initialized = true; + return 0; } void __exit acpi_aml_exit(void) -- cgit v1.2.3 From fdb3c177657033bfeff5652891bb67ff6e86b557 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Mon, 21 Jan 2019 13:07:50 +0100 Subject: ACPI: EC: Clean up probing for early EC Both acpi_ec_dsdt_probe() and acpi_ec_ecdt_probe() may be void as their return values are ignored anyway. This allows a couple of gotos and labels to go away from there. Moreover, acpi_ec_ecdt_probe() only needs to allocate the ec object after getting the ECDT pointer and checking it, so the pointless memory allocation and release on systems without the ECDT can be avoided by reordering it. No intentional functional impact. Signed-off-by: Rafael J. Wysocki --- drivers/acpi/ec.c | 47 ++++++++++++++++++++--------------------------- drivers/acpi/internal.h | 4 ++-- 2 files changed, 22 insertions(+), 29 deletions(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index 9d66a47d32fb..b94f92a095fd 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -1730,10 +1730,10 @@ static const struct acpi_device_id ec_device_ids[] = { * namespace EC before the main ACPI device enumeration process. It is * retained for historical reason and will be deprecated in the future. */ -int __init acpi_ec_dsdt_probe(void) +void __init acpi_ec_dsdt_probe(void) { - acpi_status status; struct acpi_ec *ec; + acpi_status status; int ret; /* @@ -1743,21 +1743,22 @@ int __init acpi_ec_dsdt_probe(void) * picking up an invalid EC device. */ if (boot_ec) - return -ENODEV; + return; ec = acpi_ec_alloc(); if (!ec) - return -ENOMEM; + return; + /* * At this point, the namespace is initialized, so start to find * the namespace objects. */ - status = acpi_get_devices(ec_device_ids[0].id, - ec_parse_device, ec, NULL); + status = acpi_get_devices(ec_device_ids[0].id, ec_parse_device, ec, NULL); if (ACPI_FAILURE(status) || !ec->handle) { - ret = -ENODEV; - goto error; + acpi_ec_free(ec); + return; } + /* * When the DSDT EC is available, always re-configure boot EC to * have _REG evaluated. _REG can only be evaluated after the @@ -1766,10 +1767,8 @@ int __init acpi_ec_dsdt_probe(void) * handle the events. */ ret = acpi_config_boot_ec(ec, ec->handle, false, false); -error: if (ret) acpi_ec_free(ec); - return ret; } /* @@ -1872,36 +1871,32 @@ static const struct dmi_system_id ec_dmi_table[] __initconst = { {}, }; -int __init acpi_ec_ecdt_probe(void) +void __init acpi_ec_ecdt_probe(void) { - int ret; - acpi_status status; struct acpi_table_ecdt *ecdt_ptr; struct acpi_ec *ec; + acpi_status status; + int ret; - ec = acpi_ec_alloc(); - if (!ec) - return -ENOMEM; - /* - * Generate a boot ec context - */ + /* Generate a boot ec context. */ dmi_check_system(ec_dmi_table); status = acpi_get_table(ACPI_SIG_ECDT, 1, (struct acpi_table_header **)&ecdt_ptr); - if (ACPI_FAILURE(status)) { - ret = -ENODEV; - goto error; - } + if (ACPI_FAILURE(status)) + return; if (!ecdt_ptr->control.address || !ecdt_ptr->data.address) { /* * Asus X50GL: * https://bugzilla.kernel.org/show_bug.cgi?id=11880 */ - ret = -ENODEV; - goto error; + return; } + ec = acpi_ec_alloc(); + if (!ec) + return; + if (EC_FLAGS_CORRECT_ECDT) { ec->command_addr = ecdt_ptr->data.address; ec->data_addr = ecdt_ptr->control.address; @@ -1916,10 +1911,8 @@ int __init acpi_ec_ecdt_probe(void) * the namespace objects, or handle the events. */ ret = acpi_config_boot_ec(ec, ACPI_ROOT_OBJECT, false, true); -error: if (ret) acpi_ec_free(ec); - return ret; } #ifdef CONFIG_PM_SLEEP diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h index 6a9e1fb8913a..6eaf06db7752 100644 --- a/drivers/acpi/internal.h +++ b/drivers/acpi/internal.h @@ -192,8 +192,8 @@ extern struct acpi_ec *first_ec; typedef int (*acpi_ec_query_func) (void *data); int acpi_ec_init(void); -int acpi_ec_ecdt_probe(void); -int acpi_ec_dsdt_probe(void); +void acpi_ec_ecdt_probe(void); +void acpi_ec_dsdt_probe(void); void acpi_ec_block_transactions(void); void acpi_ec_unblock_transactions(void); void acpi_ec_mark_gpe_for_wake(void); -- cgit v1.2.3 From 580d0382c1cdc7aac9d99babc526d0d4c01e1fca Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Thu, 24 Jan 2019 21:16:03 +0900 Subject: ACPI / DPTF: remove header search path to the parent directory It is too much to add extra header search path for all files in drivers/acpi/dptf/. Fix up one C file, and remove the header search path. Signed-off-by: Masahiro Yamada Signed-off-by: Rafael J. Wysocki --- drivers/acpi/dptf/Makefile | 2 -- drivers/acpi/dptf/int340x_thermal.c | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/dptf/Makefile b/drivers/acpi/dptf/Makefile index 06ea8809583d..e6032e47e83f 100644 --- a/drivers/acpi/dptf/Makefile +++ b/drivers/acpi/dptf/Makefile @@ -1,4 +1,2 @@ obj-$(CONFIG_ACPI) += int340x_thermal.o obj-$(CONFIG_DPTF_POWER) += dptf_power.o - -ccflags-y += -Idrivers/acpi diff --git a/drivers/acpi/dptf/int340x_thermal.c b/drivers/acpi/dptf/int340x_thermal.c index 86364097e236..0aa7c2e62e95 100644 --- a/drivers/acpi/dptf/int340x_thermal.c +++ b/drivers/acpi/dptf/int340x_thermal.c @@ -12,7 +12,7 @@ #include #include -#include "internal.h" +#include "../internal.h" #define INT3401_DEVICE 0X01 static const struct acpi_device_id int340x_thermal_device_ids[] = { -- cgit v1.2.3 From a9c3076846beea073428852753ec54b862a65fe6 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 1 Feb 2019 10:57:01 +0100 Subject: ACPI: EC: Declare boot_ec as static The boot_ec variable is not used outside of the file it is defined in, so declare it as static. No intentional functional impact. Signed-off-by: Rafael J. Wysocki --- drivers/acpi/ec.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index b94f92a095fd..c185666ad05c 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -186,8 +186,10 @@ static void advance_transaction(struct acpi_ec *ec); static void acpi_ec_event_handler(struct work_struct *work); static void acpi_ec_event_processor(struct work_struct *work); -struct acpi_ec *boot_ec, *first_ec; +struct acpi_ec *first_ec; EXPORT_SYMBOL(first_ec); + +static struct acpi_ec *boot_ec; static bool boot_ec_is_ecdt = false; static struct workqueue_struct *ec_query_wq; -- cgit v1.2.3 From 1568426c491ad7e17a8d9e0e4d3397ee107af899 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 1 Feb 2019 10:58:20 +0100 Subject: ACPI: EC: Make acpi_ec_ecdt_probe() more straightforward Since acpi_ec_ecdt_probe() is called when boot_ec is not set, it doesn't neeed to take the other possibility into account. Accordingly, it only needs to set the handle field in the ec object to ACPI_ROOT_OBJECT, call acpi_ec_setup() and (if that is successful) set boot_ec to ec and boot_ec_is_ecdt to 'true'. Make it do so directly, without calling acpi_config_boot_ec(), and avoid some pointless checks in the latter. No intentional functional impact except for a changed message. Signed-off-by: Rafael J. Wysocki --- drivers/acpi/ec.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index c185666ad05c..22b8866aa163 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -1907,14 +1907,22 @@ void __init acpi_ec_ecdt_probe(void) ec->data_addr = ecdt_ptr->data.address; } ec->gpe = ecdt_ptr->gpe; + ec->handle = ACPI_ROOT_OBJECT; /* * At this point, the namespace is not initialized, so do not find * the namespace objects, or handle the events. */ - ret = acpi_config_boot_ec(ec, ACPI_ROOT_OBJECT, false, true); - if (ret) + ret = acpi_ec_setup(ec, false); + if (ret) { acpi_ec_free(ec); + return; + } + + boot_ec = ec; + boot_ec_is_ecdt = true; + + pr_info("Boot ECDT EC used to handle transactions\n"); } #ifdef CONFIG_PM_SLEEP -- cgit v1.2.3 From c746b6b67e168f27b04563b0b429aa3e8be27011 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 1 Feb 2019 10:59:42 +0100 Subject: ACPI: EC: Make acpi_ec_dsdt_probe() more straightforward Since acpi_ec_dsdt_probe() returns early if boot_ec is set, it is always unset when that function calls acpi_config_boot_ec() (passing ec->handle as the handle argument to it). Thus it is not really useful to call acpi_config_boot_ec() at that point. It is sufficient to call acpi_ec_setup() directly and (if that is successful) set boot_ec, so make acpi_ec_dsdt_probe() do that and avoid some pointless checks in acpi_config_boot_ec(). No intentional functional impact except for a changed message. Signed-off-by: Rafael J. Wysocki --- drivers/acpi/ec.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index 22b8866aa163..adddb2e3466d 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -1768,9 +1768,16 @@ void __init acpi_ec_dsdt_probe(void) * At this point, the GPE is not fully initialized, so do not to * handle the events. */ - ret = acpi_config_boot_ec(ec, ec->handle, false, false); - if (ret) + ret = acpi_ec_setup(ec, false); + if (ret) { acpi_ec_free(ec); + return; + } + + boot_ec = ec; + + acpi_handle_info(ec->handle, + "Boot DSDT EC used to handle transactions\n"); } /* -- cgit v1.2.3 From d2c62aef3876353134b2901fcdd91cda09d98131 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 1 Feb 2019 12:55:31 +0100 Subject: ACPI: EC: Eliminate acpi_config_boot_ec() Notice that acpi_ec_add() calls acpi_config_boot_ec() when it finds that the device object passed to it represents a "boot" EC, but in that case the ec pointer passed to acpi_config_boot_ec() is guaranteed to be equal to boot_ec and ec->handle is passed as the handle argument to it, so acpi_config_boot_ec() really only calls acpi_ec_setup() and prints a message. Avoid the pointless checks in acpi_config_boot_ec() by calling acpi_ec_setup() directly and print the message separately. With the above changes in place, there are no users of acpi_config_boot_ec(), so drop it. No intentional functional impact except for a changed message. Signed-off-by: Rafael J. Wysocki --- drivers/acpi/ec.c | 54 ++++++++---------------------------------------------- 1 file changed, 8 insertions(+), 46 deletions(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index adddb2e3466d..e2b8cccd23ab 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -1541,49 +1541,6 @@ static int acpi_ec_setup(struct acpi_ec *ec, bool handle_events) return ret; } -static int acpi_config_boot_ec(struct acpi_ec *ec, acpi_handle handle, - bool handle_events, bool is_ecdt) -{ - int ret; - - /* - * Changing the ACPI handle results in a re-configuration of the - * boot EC. And if it happens after the namespace initialization, - * it causes _REG evaluations. - */ - if (boot_ec && boot_ec->handle != handle) - ec_remove_handlers(boot_ec); - - /* Unset old boot EC */ - if (boot_ec != ec) - acpi_ec_free(boot_ec); - - /* - * ECDT device creation is split into acpi_ec_ecdt_probe() and - * acpi_ec_ecdt_start(). This function takes care of completing the - * ECDT parsing logic as the handle update should be performed - * between the installation/uninstallation of the handlers. - */ - if (ec->handle != handle) - ec->handle = handle; - - ret = acpi_ec_setup(ec, handle_events); - if (ret) - return ret; - - /* Set new boot EC */ - if (!boot_ec) { - boot_ec = ec; - boot_ec_is_ecdt = is_ecdt; - } - - acpi_handle_info(boot_ec->handle, - "Used as boot %s EC to handle transactions%s\n", - is_ecdt ? "ECDT" : "DSDT", - handle_events ? " and events" : ""); - return ret; -} - static bool acpi_ec_ecdt_get_handle(acpi_handle *phandle) { struct acpi_table_ecdt *ecdt_ptr; @@ -1651,12 +1608,17 @@ static int acpi_ec_add(struct acpi_device *device) acpi_ec_free(ec); ec = boot_ec; } - ret = acpi_config_boot_ec(ec, ec->handle, true, is_ecdt); - } else - ret = acpi_ec_setup(ec, true); + } + + ret = acpi_ec_setup(ec, true); if (ret) goto err_query; + if (ec == boot_ec) + acpi_handle_info(boot_ec->handle, + "Boot %s EC used to handle transactions and events\n", + is_ecdt ? "ECDT" : "DSDT"); + device->driver_data = ec; ret = !!request_region(ec->data_addr, 1, "EC data"); -- cgit v1.2.3 From 116f2b348b7454ff377b779076b3ead7d47ccb7b Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 1 Feb 2019 12:56:03 +0100 Subject: ACPI: EC: Simplify boot EC checks in acpi_ec_add() Consolidate boot EC checks in acpi_ec_add(), put the acpi_is_boot_ec() checks directly into it and drop the latter. No intentional functional impact. Signed-off-by: Rafael J. Wysocki --- drivers/acpi/ec.c | 29 ++++++++++------------------- 1 file changed, 10 insertions(+), 19 deletions(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index e2b8cccd23ab..9c40f6715c69 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -1560,43 +1560,34 @@ static bool acpi_ec_ecdt_get_handle(acpi_handle *phandle) return true; } -static bool acpi_is_boot_ec(struct acpi_ec *ec) -{ - if (!boot_ec) - return false; - if (ec->command_addr == boot_ec->command_addr && - ec->data_addr == boot_ec->data_addr) - return true; - return false; -} - static int acpi_ec_add(struct acpi_device *device) { struct acpi_ec *ec = NULL; - int ret; - bool is_ecdt = false; + bool dep_update = true; acpi_status status; + int ret; strcpy(acpi_device_name(device), ACPI_EC_DEVICE_NAME); strcpy(acpi_device_class(device), ACPI_EC_CLASS); if (!strcmp(acpi_device_hid(device), ACPI_ECDT_HID)) { - is_ecdt = true; + boot_ec_is_ecdt = true; ec = boot_ec; + dep_update = false; } else { ec = acpi_ec_alloc(); if (!ec) return -ENOMEM; + status = ec_parse_device(device->handle, 0, ec, NULL); if (status != AE_CTRL_TERMINATE) { ret = -EINVAL; goto err_alloc; } - } - if (acpi_is_boot_ec(ec)) { - boot_ec_is_ecdt = is_ecdt; - if (!is_ecdt) { + if (boot_ec && ec->command_addr == boot_ec->command_addr && + ec->data_addr == boot_ec->data_addr) { + boot_ec_is_ecdt = false; /* * Trust PNP0C09 namespace location rather than * ECDT ID. But trust ECDT GPE rather than _GPE @@ -1617,7 +1608,7 @@ static int acpi_ec_add(struct acpi_device *device) if (ec == boot_ec) acpi_handle_info(boot_ec->handle, "Boot %s EC used to handle transactions and events\n", - is_ecdt ? "ECDT" : "DSDT"); + boot_ec_is_ecdt ? "ECDT" : "DSDT"); device->driver_data = ec; @@ -1626,7 +1617,7 @@ static int acpi_ec_add(struct acpi_device *device) ret = !!request_region(ec->command_addr, 1, "EC cmd"); WARN(!ret, "Could not request EC cmd io port 0x%lx", ec->command_addr); - if (!is_ecdt) { + if (dep_update) { /* Reprobe devices depending on the EC */ acpi_walk_dep_device_list(ec->handle); } -- cgit v1.2.3 From b6a3e1475b0220378ad32bdf4d8692f058b1fc03 Mon Sep 17 00:00:00 2001 From: Zhang Rui Date: Fri, 1 Feb 2019 14:13:41 +0800 Subject: Revert "ACPI / EC: Remove old CLEAR_ON_RESUME quirk" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On some Samsung hardware, it is necessary to clear events accumulated by the EC during sleep. These ECs stop reporting GPEs until they are manually polled, if too many events are accumulated. Thus the CLEAR_ON_RESUME quirk is introduced to send EC query commands unconditionally after resume to clear all the EC query events on those platforms. Later, commit 4c237371f290 ("ACPI / EC: Remove old CLEAR_ON_RESUME quirk") removes the CLEAR_ON_RESUME quirk because we thought the new EC IRQ polling logic should handle this case. Now it has been proved that the EC IRQ Polling logic does not fix the issue actually because we got regression report on these Samsung platforms after removing the quirk. Thus revert commit 4c237371f290 ("ACPI / EC: Remove old CLEAR_ON_RESUME quirk") to introduce back the Samsung quirk in this patch. Link: https://bugzilla.kernel.org/show_bug.cgi?id=44161 Tested-by: Ortwin Glück Tested-by: Francisco Cribari Tested-by: Balazs Varga Signed-off-by: Zhang Rui Signed-off-by: Rafael J. Wysocki --- drivers/acpi/ec.c | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) (limited to 'drivers/acpi') diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index 9c40f6715c69..48d4815603e5 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -196,6 +196,7 @@ static struct workqueue_struct *ec_query_wq; static int EC_FLAGS_QUERY_HANDSHAKE; /* Needs QR_EC issued when SCI_EVT set */ static int EC_FLAGS_CORRECT_ECDT; /* Needs ECDT port address correction */ static int EC_FLAGS_IGNORE_DSDT_GPE; /* Needs ECDT GPE as correction setting */ +static int EC_FLAGS_CLEAR_ON_RESUME; /* Needs acpi_ec_clear() on boot/resume */ /* -------------------------------------------------------------------------- * Logging/Debugging @@ -501,6 +502,26 @@ static inline void __acpi_ec_disable_event(struct acpi_ec *ec) ec_log_drv("event blocked"); } +/* + * Process _Q events that might have accumulated in the EC. + * Run with locked ec mutex. + */ +static void acpi_ec_clear(struct acpi_ec *ec) +{ + int i, status; + u8 value = 0; + + for (i = 0; i < ACPI_EC_CLEAR_MAX; i++) { + status = acpi_ec_query(ec, &value); + if (status || !value) + break; + } + if (unlikely(i == ACPI_EC_CLEAR_MAX)) + pr_warn("Warning: Maximum of %d stale EC events cleared\n", i); + else + pr_info("%d stale EC events cleared\n", i); +} + static void acpi_ec_enable_event(struct acpi_ec *ec) { unsigned long flags; @@ -509,6 +530,10 @@ static void acpi_ec_enable_event(struct acpi_ec *ec) if (acpi_ec_started(ec)) __acpi_ec_enable_event(ec); spin_unlock_irqrestore(&ec->lock, flags); + + /* Drain additional events if hardware requires that */ + if (EC_FLAGS_CLEAR_ON_RESUME) + acpi_ec_clear(ec); } #ifdef CONFIG_PM_SLEEP @@ -1781,6 +1806,31 @@ static int ec_flag_query_handshake(const struct dmi_system_id *id) } #endif +/* + * On some hardware it is necessary to clear events accumulated by the EC during + * sleep. These ECs stop reporting GPEs until they are manually polled, if too + * many events are accumulated. (e.g. Samsung Series 5/9 notebooks) + * + * https://bugzilla.kernel.org/show_bug.cgi?id=44161 + * + * Ideally, the EC should also be instructed NOT to accumulate events during + * sleep (which Windows seems to do somehow), but the interface to control this + * behaviour is not known at this time. + * + * Models known to be affected are Samsung 530Uxx/535Uxx/540Uxx/550Pxx/900Xxx, + * however it is very likely that other Samsung models are affected. + * + * On systems which don't accumulate _Q events during sleep, this extra check + * should be harmless. + */ +static int ec_clear_on_resume(const struct dmi_system_id *id) +{ + pr_debug("Detected system needing EC poll on resume.\n"); + EC_FLAGS_CLEAR_ON_RESUME = 1; + ec_event_clearing = ACPI_EC_EVT_TIMING_STATUS; + return 0; +} + /* * Some ECDTs contain wrong register addresses. * MSI MS-171F @@ -1830,6 +1880,9 @@ static const struct dmi_system_id ec_dmi_table[] __initconst = { ec_honor_ecdt_gpe, "ASUS X580VD", { DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), DMI_MATCH(DMI_PRODUCT_NAME, "X580VD"),}, NULL}, + { + ec_clear_on_resume, "Samsung hardware", { + DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD.")}, NULL}, {}, }; -- cgit v1.2.3 From 6cafe700b08cfd261a279b9e5ed99f3a346fe3b0 Mon Sep 17 00:00:00 2001 From: John Garry Date: Fri, 8 Feb 2019 00:14:21 +0800 Subject: ACPI/PPTT: Add acpi_pptt_warn_missing() to consolidate logs For a system using ACPI-based FW without a PPTT, we may get many warnings about the lack of a PPTT, as shown: root@(none)$ dmesg | grep -i pptt [ 0.010125] ACPI PPTT: No PPTT table found, cpu topology may be inaccurate [ 7.138339] ACPI PPTT: No PPTT table found, cache topology may be inaccurate [ 7.145368] ACPI PPTT: No PPTT table found, cache topology may be inaccurate These logs are generated with pr_warn_once(), so the intention was for a single log, but the logs overlap, so consolidate them. Signed-off-by: John Garry Reviewed-by: Jeremy Linton Signed-off-by: Rafael J. Wysocki --- drivers/acpi/pptt.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/pptt.c b/drivers/acpi/pptt.c index da031b1df6f5..ad31c50de3be 100644 --- a/drivers/acpi/pptt.c +++ b/drivers/acpi/pptt.c @@ -451,6 +451,11 @@ static struct acpi_pptt_processor *acpi_find_processor_package_id(struct acpi_ta return cpu; } +static void acpi_pptt_warn_missing(void) +{ + pr_warn_once("No PPTT table found, cpu and cache topology may be inaccurate\n"); +} + /** * topology_get_acpi_cpu_tag() - Find a unique topology value for a feature * @table: Pointer to the head of the PPTT table @@ -498,7 +503,7 @@ static int find_acpi_cpu_topology_tag(unsigned int cpu, int level, int flag) status = acpi_get_table(ACPI_SIG_PPTT, 0, &table); if (ACPI_FAILURE(status)) { - pr_warn_once("No PPTT table found, cpu topology may be inaccurate\n"); + acpi_pptt_warn_missing(); return -ENOENT; } retval = topology_get_acpi_cpu_tag(table, cpu, level, flag); @@ -531,7 +536,7 @@ int acpi_find_last_cache_level(unsigned int cpu) acpi_cpu_id = get_acpi_id_for_cpu(cpu); status = acpi_get_table(ACPI_SIG_PPTT, 0, &table); if (ACPI_FAILURE(status)) { - pr_warn_once("No PPTT table found, cache topology may be inaccurate\n"); + acpi_pptt_warn_missing(); } else { number_of_levels = acpi_find_cache_levels(table, acpi_cpu_id); acpi_put_table(table); @@ -563,7 +568,7 @@ int cache_setup_acpi(unsigned int cpu) status = acpi_get_table(ACPI_SIG_PPTT, 0, &table); if (ACPI_FAILURE(status)) { - pr_warn_once("No PPTT table found, cache topology may be inaccurate\n"); + acpi_pptt_warn_missing(); return -ENOENT; } @@ -617,7 +622,7 @@ int find_acpi_cpu_cache_topology(unsigned int cpu, int level) status = acpi_get_table(ACPI_SIG_PPTT, 0, &table); if (ACPI_FAILURE(status)) { - pr_warn_once("No PPTT table found, topology may be inaccurate\n"); + acpi_pptt_warn_missing(); return -ENOENT; } -- cgit v1.2.3