diff options
Diffstat (limited to 'drivers/acpi')
30 files changed, 947 insertions, 710 deletions
diff --git a/drivers/acpi/ac.c b/drivers/acpi/ac.c index 225dc6818751..2d4a35e6dd18 100644 --- a/drivers/acpi/ac.c +++ b/drivers/acpi/ac.c @@ -17,6 +17,7 @@ #include <linux/delay.h> #include <linux/platform_device.h> #include <linux/power_supply.h> +#include <linux/string_choices.h> #include <linux/acpi.h> #include <acpi/battery.h> @@ -32,8 +33,9 @@ MODULE_AUTHOR("Paul Diefenbaugh"); MODULE_DESCRIPTION("ACPI AC Adapter Driver"); MODULE_LICENSE("GPL"); -static int acpi_ac_add(struct acpi_device *device); -static void acpi_ac_remove(struct acpi_device *device); +static int acpi_ac_probe(struct platform_device *pdev); +static void acpi_ac_remove(struct platform_device *pdev); + static void acpi_ac_notify(acpi_handle handle, u32 event, void *data); static const struct acpi_device_id ac_device_ids[] = { @@ -50,17 +52,6 @@ static SIMPLE_DEV_PM_OPS(acpi_ac_pm, NULL, acpi_ac_resume); static int ac_sleep_before_get_state_ms; static int ac_only; -static struct acpi_driver acpi_ac_driver = { - .name = "ac", - .class = ACPI_AC_CLASS, - .ids = ac_device_ids, - .ops = { - .add = acpi_ac_add, - .remove = acpi_ac_remove, - }, - .drv.pm = &acpi_ac_pm, -}; - struct acpi_ac { struct power_supply *charger; struct power_supply_desc charger_desc; @@ -128,15 +119,12 @@ static enum power_supply_property ac_props[] = { /* Driver Model */ static void acpi_ac_notify(acpi_handle handle, u32 event, void *data) { - struct acpi_device *device = data; - struct acpi_ac *ac = acpi_driver_data(device); - - if (!ac) - return; + struct acpi_ac *ac = data; + struct acpi_device *adev = ac->device; switch (event) { default: - acpi_handle_debug(device->handle, "Unsupported event [0x%x]\n", + acpi_handle_debug(adev->handle, "Unsupported event [0x%x]\n", event); fallthrough; case ACPI_AC_NOTIFY_STATUS: @@ -153,10 +141,10 @@ static void acpi_ac_notify(acpi_handle handle, u32 event, void *data) msleep(ac_sleep_before_get_state_ms); acpi_ac_get_state(ac); - acpi_bus_generate_netlink_event(device->pnp.device_class, - dev_name(&device->dev), event, + acpi_bus_generate_netlink_event(adev->pnp.device_class, + dev_name(&adev->dev), event, (u32) ac->state); - acpi_notifier_call_chain(device, event, (u32) ac->state); + acpi_notifier_call_chain(adev, event, (u32) ac->state); kobject_uevent(&ac->charger->dev.kobj, KOBJ_CHANGE); } } @@ -213,24 +201,22 @@ static const struct dmi_system_id ac_dmi_table[] __initconst = { {}, }; -static int acpi_ac_add(struct acpi_device *device) +static int acpi_ac_probe(struct platform_device *pdev) { + struct acpi_device *adev = ACPI_COMPANION(&pdev->dev); struct power_supply_config psy_cfg = {}; - int result = 0; - struct acpi_ac *ac = NULL; - - - if (!device) - return -EINVAL; + struct acpi_ac *ac; + int result; ac = kzalloc(sizeof(struct acpi_ac), GFP_KERNEL); if (!ac) return -ENOMEM; - ac->device = device; - strcpy(acpi_device_name(device), ACPI_AC_DEVICE_NAME); - strcpy(acpi_device_class(device), ACPI_AC_CLASS); - device->driver_data = ac; + ac->device = adev; + strcpy(acpi_device_name(adev), ACPI_AC_DEVICE_NAME); + strcpy(acpi_device_class(adev), ACPI_AC_CLASS); + + platform_set_drvdata(pdev, ac); result = acpi_ac_get_state(ac); if (result) @@ -238,26 +224,26 @@ static int acpi_ac_add(struct acpi_device *device) psy_cfg.drv_data = ac; - ac->charger_desc.name = acpi_device_bid(device); + ac->charger_desc.name = acpi_device_bid(adev); ac->charger_desc.type = POWER_SUPPLY_TYPE_MAINS; ac->charger_desc.properties = ac_props; ac->charger_desc.num_properties = ARRAY_SIZE(ac_props); ac->charger_desc.get_property = get_ac_property; - ac->charger = power_supply_register(&ac->device->dev, + ac->charger = power_supply_register(&pdev->dev, &ac->charger_desc, &psy_cfg); if (IS_ERR(ac->charger)) { result = PTR_ERR(ac->charger); goto err_release_ac; } - pr_info("%s [%s] (%s)\n", acpi_device_name(device), - acpi_device_bid(device), ac->state ? "on-line" : "off-line"); + pr_info("%s [%s] (%s-line)\n", acpi_device_name(adev), + acpi_device_bid(adev), str_on_off(ac->state)); ac->battery_nb.notifier_call = acpi_ac_battery_notify; register_acpi_notifier(&ac->battery_nb); - result = acpi_dev_install_notify_handler(device, ACPI_ALL_NOTIFY, - acpi_ac_notify); + result = acpi_dev_install_notify_handler(adev, ACPI_ALL_NOTIFY, + acpi_ac_notify, ac); if (result) goto err_unregister; @@ -275,16 +261,9 @@ err_release_ac: #ifdef CONFIG_PM_SLEEP static int acpi_ac_resume(struct device *dev) { - struct acpi_ac *ac; + struct acpi_ac *ac = dev_get_drvdata(dev); unsigned int old_state; - if (!dev) - return -EINVAL; - - ac = acpi_driver_data(to_acpi_device(dev)); - if (!ac) - return -EINVAL; - old_state = ac->state; if (acpi_ac_get_state(ac)) return 0; @@ -297,16 +276,11 @@ static int acpi_ac_resume(struct device *dev) #define acpi_ac_resume NULL #endif -static void acpi_ac_remove(struct acpi_device *device) +static void acpi_ac_remove(struct platform_device *pdev) { - struct acpi_ac *ac = NULL; + struct acpi_ac *ac = platform_get_drvdata(pdev); - if (!device || !acpi_driver_data(device)) - return; - - ac = acpi_driver_data(device); - - acpi_dev_remove_notify_handler(device, ACPI_ALL_NOTIFY, + acpi_dev_remove_notify_handler(ac->device, ACPI_ALL_NOTIFY, acpi_ac_notify); power_supply_unregister(ac->charger); unregister_acpi_notifier(&ac->battery_nb); @@ -314,6 +288,16 @@ static void acpi_ac_remove(struct acpi_device *device) kfree(ac); } +static struct platform_driver acpi_ac_driver = { + .probe = acpi_ac_probe, + .remove_new = acpi_ac_remove, + .driver = { + .name = "ac", + .acpi_match_table = ac_device_ids, + .pm = &acpi_ac_pm, + }, +}; + static int __init acpi_ac_init(void) { int result; @@ -326,7 +310,7 @@ static int __init acpi_ac_init(void) dmi_check_system(ac_dmi_table); - result = acpi_bus_register_driver(&acpi_ac_driver); + result = platform_driver_register(&acpi_ac_driver); if (result < 0) return -ENODEV; @@ -335,7 +319,7 @@ static int __init acpi_ac_init(void) static void __exit acpi_ac_exit(void) { - acpi_bus_unregister_driver(&acpi_ac_driver); + platform_driver_unregister(&acpi_ac_driver); } module_init(acpi_ac_init); module_exit(acpi_ac_exit); diff --git a/drivers/acpi/acpi_fpdt.c b/drivers/acpi/acpi_fpdt.c index a2056c4c8cb7..271092f2700a 100644 --- a/drivers/acpi/acpi_fpdt.c +++ b/drivers/acpi/acpi_fpdt.c @@ -194,12 +194,19 @@ static int fpdt_process_subtable(u64 address, u32 subtable_type) record_header = (void *)subtable_header + offset; offset += record_header->length; + if (!record_header->length) { + pr_err(FW_BUG "Zero-length record found in FPTD.\n"); + result = -EINVAL; + goto err; + } + switch (record_header->type) { case RECORD_S3_RESUME: if (subtable_type != SUBTABLE_S3PT) { pr_err(FW_BUG "Invalid record %d for subtable %s\n", record_header->type, signature); - return -EINVAL; + result = -EINVAL; + goto err; } if (record_resume) { pr_err("Duplicate resume performance record found.\n"); @@ -208,7 +215,7 @@ static int fpdt_process_subtable(u64 address, u32 subtable_type) record_resume = (struct resume_performance_record *)record_header; result = sysfs_create_group(fpdt_kobj, &resume_attr_group); if (result) - return result; + goto err; break; case RECORD_S3_SUSPEND: if (subtable_type != SUBTABLE_S3PT) { @@ -223,13 +230,14 @@ static int fpdt_process_subtable(u64 address, u32 subtable_type) record_suspend = (struct suspend_performance_record *)record_header; result = sysfs_create_group(fpdt_kobj, &suspend_attr_group); if (result) - return result; + goto err; break; case RECORD_BOOT: if (subtable_type != SUBTABLE_FBPT) { pr_err(FW_BUG "Invalid %d for subtable %s\n", record_header->type, signature); - return -EINVAL; + result = -EINVAL; + goto err; } if (record_boot) { pr_err("Duplicate boot performance record found.\n"); @@ -238,7 +246,7 @@ static int fpdt_process_subtable(u64 address, u32 subtable_type) record_boot = (struct boot_performance_record *)record_header; result = sysfs_create_group(fpdt_kobj, &boot_attr_group); if (result) - return result; + goto err; break; default: @@ -247,6 +255,18 @@ static int fpdt_process_subtable(u64 address, u32 subtable_type) } } return 0; + +err: + if (record_boot) + sysfs_remove_group(fpdt_kobj, &boot_attr_group); + + if (record_suspend) + sysfs_remove_group(fpdt_kobj, &suspend_attr_group); + + if (record_resume) + sysfs_remove_group(fpdt_kobj, &resume_attr_group); + + return result; } static int __init acpi_init_fpdt(void) @@ -255,6 +275,7 @@ static int __init acpi_init_fpdt(void) struct acpi_table_header *header; struct fpdt_subtable_entry *subtable; u32 offset = sizeof(*header); + int result; status = acpi_get_table(ACPI_SIG_FPDT, 0, &header); @@ -263,8 +284,8 @@ static int __init acpi_init_fpdt(void) fpdt_kobj = kobject_create_and_add("fpdt", acpi_kobj); if (!fpdt_kobj) { - acpi_put_table(header); - return -ENOMEM; + result = -ENOMEM; + goto err_nomem; } while (offset < header->length) { @@ -272,8 +293,10 @@ static int __init acpi_init_fpdt(void) switch (subtable->type) { case SUBTABLE_FBPT: case SUBTABLE_S3PT: - fpdt_process_subtable(subtable->address, + result = fpdt_process_subtable(subtable->address, subtable->type); + if (result) + goto err_subtable; break; default: /* Other types are reserved in ACPI 6.4 spec. */ @@ -282,6 +305,12 @@ static int __init acpi_init_fpdt(void) offset += sizeof(*subtable); } return 0; +err_subtable: + kobject_put(fpdt_kobj); + +err_nomem: + acpi_put_table(header); + return result; } fs_initcall(acpi_init_fpdt); diff --git a/drivers/acpi/acpi_lpss.c b/drivers/acpi/acpi_lpss.c index 539e700de4d2..875de44961bf 100644 --- a/drivers/acpi/acpi_lpss.c +++ b/drivers/acpi/acpi_lpss.c @@ -368,7 +368,6 @@ static const struct acpi_device_id acpi_lpss_device_ids[] = { { "INT33C4", LPSS_ADDR(lpt_uart_dev_desc) }, { "INT33C5", LPSS_ADDR(lpt_uart_dev_desc) }, { "INT33C6", LPSS_ADDR(lpt_sdio_dev_desc) }, - { "INT33C7", }, /* BayTrail LPSS devices */ { "80860F09", LPSS_ADDR(byt_pwm_dev_desc) }, @@ -376,8 +375,6 @@ static const struct acpi_device_id acpi_lpss_device_ids[] = { { "80860F0E", LPSS_ADDR(byt_spi_dev_desc) }, { "80860F14", LPSS_ADDR(byt_sdio_dev_desc) }, { "80860F41", LPSS_ADDR(byt_i2c_dev_desc) }, - { "INT33B2", }, - { "INT33FC", }, /* Braswell LPSS devices */ { "80862286", LPSS_ADDR(lpss_dma_desc) }, @@ -396,7 +393,6 @@ static const struct acpi_device_id acpi_lpss_device_ids[] = { { "INT3434", LPSS_ADDR(lpt_uart_dev_desc) }, { "INT3435", LPSS_ADDR(lpt_uart_dev_desc) }, { "INT3436", LPSS_ADDR(lpt_sdio_dev_desc) }, - { "INT3437", }, /* Wildcat Point LPSS devices */ { "INT3438", LPSS_ADDR(lpt_spi_dev_desc) }, @@ -578,6 +574,7 @@ static bool acpi_lpss_dep(struct acpi_device *adev, acpi_handle handle) { struct acpi_handle_list dep_devices; acpi_status status; + bool ret = false; int i; if (!acpi_has_method(adev->handle, "_DEP")) @@ -591,11 +588,14 @@ static bool acpi_lpss_dep(struct acpi_device *adev, acpi_handle handle) } for (i = 0; i < dep_devices.count; i++) { - if (dep_devices.handles[i] == handle) - return true; + if (dep_devices.handles[i] == handle) { + ret = true; + break; + } } - return false; + acpi_handle_list_free(&dep_devices); + return ret; } static void acpi_lpss_link_consumer(struct device *dev1, @@ -657,10 +657,9 @@ static int acpi_lpss_create_device(struct acpi_device *adev, int ret; dev_desc = (const struct lpss_device_desc *)id->driver_data; - if (!dev_desc) { - pdev = acpi_create_platform_device(adev, NULL); - return IS_ERR_OR_NULL(pdev) ? PTR_ERR(pdev) : 1; - } + if (!dev_desc) + return -EINVAL; + pdata = kzalloc(sizeof(*pdata), GFP_KERNEL); if (!pdata) return -ENOMEM; diff --git a/drivers/acpi/acpi_pad.c b/drivers/acpi/acpi_pad.c index 7a453c5ff303..32a2c006908b 100644 --- a/drivers/acpi/acpi_pad.c +++ b/drivers/acpi/acpi_pad.c @@ -18,6 +18,7 @@ #include <linux/slab.h> #include <linux/acpi.h> #include <linux/perf_event.h> +#include <linux/platform_device.h> #include <asm/mwait.h> #include <xen/xen.h> @@ -336,33 +337,14 @@ static ssize_t idlecpus_show(struct device *dev, static DEVICE_ATTR_RW(idlecpus); -static int acpi_pad_add_sysfs(struct acpi_device *device) -{ - int result; - - result = device_create_file(&device->dev, &dev_attr_idlecpus); - if (result) - return -ENODEV; - result = device_create_file(&device->dev, &dev_attr_idlepct); - if (result) { - device_remove_file(&device->dev, &dev_attr_idlecpus); - return -ENODEV; - } - result = device_create_file(&device->dev, &dev_attr_rrtime); - if (result) { - device_remove_file(&device->dev, &dev_attr_idlecpus); - device_remove_file(&device->dev, &dev_attr_idlepct); - return -ENODEV; - } - return 0; -} +static struct attribute *acpi_pad_attrs[] = { + &dev_attr_idlecpus.attr, + &dev_attr_idlepct.attr, + &dev_attr_rrtime.attr, + NULL +}; -static void acpi_pad_remove_sysfs(struct acpi_device *device) -{ - device_remove_file(&device->dev, &dev_attr_idlecpus); - device_remove_file(&device->dev, &dev_attr_idlepct); - device_remove_file(&device->dev, &dev_attr_rrtime); -} +ATTRIBUTE_GROUPS(acpi_pad); /* * Query firmware how many CPUs should be idle @@ -416,13 +398,13 @@ static void acpi_pad_handle_notify(acpi_handle handle) static void acpi_pad_notify(acpi_handle handle, u32 event, void *data) { - struct acpi_device *device = data; + struct acpi_device *adev = data; switch (event) { case ACPI_PROCESSOR_AGGREGATOR_NOTIFY: acpi_pad_handle_notify(handle); - acpi_bus_generate_netlink_event(device->pnp.device_class, - dev_name(&device->dev), event, 0); + acpi_bus_generate_netlink_event(adev->pnp.device_class, + dev_name(&adev->dev), event, 0); break; default: pr_warn("Unsupported event [0x%x]\n", event); @@ -430,35 +412,33 @@ static void acpi_pad_notify(acpi_handle handle, u32 event, } } -static int acpi_pad_add(struct acpi_device *device) +static int acpi_pad_probe(struct platform_device *pdev) { + struct acpi_device *adev = ACPI_COMPANION(&pdev->dev); acpi_status status; - strcpy(acpi_device_name(device), ACPI_PROCESSOR_AGGREGATOR_DEVICE_NAME); - strcpy(acpi_device_class(device), ACPI_PROCESSOR_AGGREGATOR_CLASS); + strcpy(acpi_device_name(adev), ACPI_PROCESSOR_AGGREGATOR_DEVICE_NAME); + strcpy(acpi_device_class(adev), ACPI_PROCESSOR_AGGREGATOR_CLASS); - if (acpi_pad_add_sysfs(device)) - return -ENODEV; + status = acpi_install_notify_handler(adev->handle, + ACPI_DEVICE_NOTIFY, acpi_pad_notify, adev); - status = acpi_install_notify_handler(device->handle, - ACPI_DEVICE_NOTIFY, acpi_pad_notify, device); - if (ACPI_FAILURE(status)) { - acpi_pad_remove_sysfs(device); + if (ACPI_FAILURE(status)) return -ENODEV; - } return 0; } -static void acpi_pad_remove(struct acpi_device *device) +static void acpi_pad_remove(struct platform_device *pdev) { + struct acpi_device *adev = ACPI_COMPANION(&pdev->dev); + mutex_lock(&isolated_cpus_lock); acpi_pad_idle_cpus(0); mutex_unlock(&isolated_cpus_lock); - acpi_remove_notify_handler(device->handle, + acpi_remove_notify_handler(adev->handle, ACPI_DEVICE_NOTIFY, acpi_pad_notify); - acpi_pad_remove_sysfs(device); } static const struct acpi_device_id pad_device_ids[] = { @@ -467,13 +447,13 @@ static const struct acpi_device_id pad_device_ids[] = { }; MODULE_DEVICE_TABLE(acpi, pad_device_ids); -static struct acpi_driver acpi_pad_driver = { - .name = "processor_aggregator", - .class = ACPI_PROCESSOR_AGGREGATOR_CLASS, - .ids = pad_device_ids, - .ops = { - .add = acpi_pad_add, - .remove = acpi_pad_remove, +static struct platform_driver acpi_pad_driver = { + .probe = acpi_pad_probe, + .remove_new = acpi_pad_remove, + .driver = { + .dev_groups = acpi_pad_groups, + .name = "processor_aggregator", + .acpi_match_table = pad_device_ids, }, }; @@ -487,12 +467,12 @@ static int __init acpi_pad_init(void) if (power_saving_mwait_eax == 0) return -EINVAL; - return acpi_bus_register_driver(&acpi_pad_driver); + return platform_driver_register(&acpi_pad_driver); } static void __exit acpi_pad_exit(void) { - acpi_bus_unregister_driver(&acpi_pad_driver); + platform_driver_unregister(&acpi_pad_driver); } module_init(acpi_pad_init); diff --git a/drivers/acpi/acpi_processor.c b/drivers/acpi/acpi_processor.c index c711db8a9c33..0f5218e361df 100644 --- a/drivers/acpi/acpi_processor.c +++ b/drivers/acpi/acpi_processor.c @@ -12,6 +12,7 @@ #define pr_fmt(fmt) "ACPI: " fmt #include <linux/acpi.h> +#include <linux/cpu.h> #include <linux/device.h> #include <linux/dmi.h> #include <linux/kernel.h> diff --git a/drivers/acpi/acpi_video.c b/drivers/acpi/acpi_video.c index 948e31f7ce6e..0b7a01f38b65 100644 --- a/drivers/acpi/acpi_video.c +++ b/drivers/acpi/acpi_video.c @@ -2057,20 +2057,23 @@ static int acpi_video_bus_add(struct acpi_device *device) !auto_detect) acpi_video_bus_register_backlight(video); - acpi_video_bus_add_notify_handler(video); + error = acpi_video_bus_add_notify_handler(video); + if (error) + goto err_del; error = acpi_dev_install_notify_handler(device, ACPI_DEVICE_NOTIFY, - acpi_video_bus_notify); + acpi_video_bus_notify, device); if (error) goto err_remove; return 0; err_remove: + acpi_video_bus_remove_notify_handler(video); +err_del: mutex_lock(&video_list_lock); list_del(&video->entry); mutex_unlock(&video_list_lock); - acpi_video_bus_remove_notify_handler(video); acpi_video_bus_unregister_backlight(video); err_put_video: acpi_video_bus_put_devices(video); diff --git a/drivers/acpi/apei/erst.c b/drivers/acpi/apei/erst.c index 247989060e29..bf65e3461531 100644 --- a/drivers/acpi/apei/erst.c +++ b/drivers/acpi/apei/erst.c @@ -59,6 +59,10 @@ static struct acpi_table_erst *erst_tab; #define ERST_RANGE_NVRAM 0x0002 #define ERST_RANGE_SLOW 0x0004 +/* ERST Exec max timings */ +#define ERST_EXEC_TIMING_MAX_MASK 0xFFFFFFFF00000000 +#define ERST_EXEC_TIMING_MAX_SHIFT 32 + /* * ERST Error Log Address Range, used as buffer for reading/writing * error records. @@ -68,6 +72,7 @@ static struct erst_erange { u64 size; void __iomem *vaddr; u32 attr; + u64 timings; } erst_erange; /* @@ -97,6 +102,19 @@ static inline int erst_errno(int command_status) } } +static inline u64 erst_get_timeout(void) +{ + u64 timeout = FIRMWARE_TIMEOUT; + + if (erst_erange.attr & ERST_RANGE_SLOW) { + timeout = ((erst_erange.timings & ERST_EXEC_TIMING_MAX_MASK) >> + ERST_EXEC_TIMING_MAX_SHIFT) * NSEC_PER_MSEC; + if (timeout < FIRMWARE_TIMEOUT) + timeout = FIRMWARE_TIMEOUT; + } + return timeout; +} + static int erst_timedout(u64 *t, u64 spin_unit) { if ((s64)*t < spin_unit) { @@ -191,9 +209,11 @@ static int erst_exec_stall_while_true(struct apei_exec_context *ctx, { int rc; u64 val; - u64 timeout = FIRMWARE_TIMEOUT; + u64 timeout; u64 stall_time; + timeout = erst_get_timeout(); + if (ctx->var1 > FIRMWARE_MAX_STALL) { if (!in_nmi()) pr_warn(FW_WARN @@ -389,6 +409,13 @@ static int erst_get_erange(struct erst_erange *range) if (rc) return rc; range->attr = apei_exec_ctx_get_output(&ctx); + rc = apei_exec_run(&ctx, ACPI_ERST_EXECUTE_TIMINGS); + if (rc == 0) + range->timings = apei_exec_ctx_get_output(&ctx); + else if (rc == -ENOENT) + range->timings = 0; + else + return rc; return 0; } @@ -621,10 +648,12 @@ EXPORT_SYMBOL_GPL(erst_get_record_id_end); static int __erst_write_to_storage(u64 offset) { struct apei_exec_context ctx; - u64 timeout = FIRMWARE_TIMEOUT; + u64 timeout; u64 val; int rc; + timeout = erst_get_timeout(); + erst_exec_ctx_init(&ctx); rc = apei_exec_run_optional(&ctx, ACPI_ERST_BEGIN_WRITE); if (rc) @@ -660,10 +689,12 @@ static int __erst_write_to_storage(u64 offset) static int __erst_read_from_storage(u64 record_id, u64 offset) { struct apei_exec_context ctx; - u64 timeout = FIRMWARE_TIMEOUT; + u64 timeout; u64 val; int rc; + timeout = erst_get_timeout(); + erst_exec_ctx_init(&ctx); rc = apei_exec_run_optional(&ctx, ACPI_ERST_BEGIN_READ); if (rc) @@ -703,10 +734,12 @@ static int __erst_read_from_storage(u64 record_id, u64 offset) static int __erst_clear_from_storage(u64 record_id) { struct apei_exec_context ctx; - u64 timeout = FIRMWARE_TIMEOUT; + u64 timeout; u64 val; int rc; + timeout = erst_get_timeout(); + erst_exec_ctx_init(&ctx); rc = apei_exec_run_optional(&ctx, ACPI_ERST_BEGIN_CLEAR); if (rc) diff --git a/drivers/acpi/apei/ghes.c b/drivers/acpi/apei/ghes.c index ef59d6ea16da..63ad0541db38 100644 --- a/drivers/acpi/apei/ghes.c +++ b/drivers/acpi/apei/ghes.c @@ -209,6 +209,20 @@ err_pool_alloc: return -ENOMEM; } +/** + * ghes_estatus_pool_region_free - free previously allocated memory + * from the ghes_estatus_pool. + * @addr: address of memory to free. + * @size: size of memory to free. + * + * Returns none. + */ +void ghes_estatus_pool_region_free(unsigned long addr, u32 size) +{ + gen_pool_free(ghes_estatus_pool, addr, size); +} +EXPORT_SYMBOL_GPL(ghes_estatus_pool_region_free); + static int map_gen_v2(struct ghes *ghes) { return apei_map_generic_address(&ghes->generic_v2->read_ack_register); @@ -564,6 +578,7 @@ static void ghes_handle_aer(struct acpi_hest_generic_data *gdata) pcie_err->validation_bits & CPER_PCIE_VALID_AER_INFO) { unsigned int devfn; int aer_severity; + u8 *aer_info; devfn = PCI_DEVFN(pcie_err->device_id.device, pcie_err->device_id.function); @@ -577,11 +592,17 @@ static void ghes_handle_aer(struct acpi_hest_generic_data *gdata) if (gdata->flags & CPER_SEC_RESET) aer_severity = AER_FATAL; + aer_info = (void *)gen_pool_alloc(ghes_estatus_pool, + sizeof(struct aer_capability_regs)); + if (!aer_info) + return; + memcpy(aer_info, pcie_err->aer_info, sizeof(struct aer_capability_regs)); + aer_recover_queue(pcie_err->device_id.segment, pcie_err->device_id.bus, devfn, aer_severity, (struct aer_capability_regs *) - pcie_err->aer_info); + aer_info); } #endif } diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c index 969bf81e8d54..b379401ff1c2 100644 --- a/drivers/acpi/battery.c +++ b/drivers/acpi/battery.c @@ -1214,7 +1214,7 @@ static int acpi_battery_add(struct acpi_device *device) device_init_wakeup(&device->dev, 1); result = acpi_dev_install_notify_handler(device, ACPI_ALL_NOTIFY, - acpi_battery_notify); + acpi_battery_notify, device); if (result) goto fail_pm; diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index f41dda2d3493..72e64c0718c9 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -556,12 +556,12 @@ static void acpi_device_remove_notify_handler(struct acpi_device *device, int acpi_dev_install_notify_handler(struct acpi_device *adev, u32 handler_type, - acpi_notify_handler handler) + acpi_notify_handler handler, void *context) { acpi_status status; status = acpi_install_notify_handler(adev->handle, handler_type, - handler, adev); + handler, context); if (ACPI_FAILURE(status)) return -ENODEV; @@ -1410,10 +1410,10 @@ static int __init acpi_init(void) acpi_init_ffh(); pci_mmcfg_late_init(); - acpi_arm_init(); acpi_viot_early_init(); acpi_hest_init(); acpi_ghes_init(); + acpi_arm_init(); acpi_scan_init(); acpi_ec_init(); acpi_debugfs_init(); diff --git a/drivers/acpi/device_sysfs.c b/drivers/acpi/device_sysfs.c index b9bbf0746199..23373faa35ec 100644 --- a/drivers/acpi/device_sysfs.c +++ b/drivers/acpi/device_sysfs.c @@ -158,8 +158,8 @@ static int create_pnp_modalias(const struct acpi_device *acpi_dev, char *modalia return 0; len = snprintf(modalias, size, "acpi:"); - if (len <= 0) - return len; + if (len >= size) + return -ENOMEM; size -= len; @@ -168,8 +168,6 @@ static int create_pnp_modalias(const struct acpi_device *acpi_dev, char *modalia continue; count = snprintf(&modalias[len], size, "%s:", id->id); - if (count < 0) - return -EINVAL; if (count >= size) return -ENOMEM; @@ -177,7 +175,7 @@ static int create_pnp_modalias(const struct acpi_device *acpi_dev, char *modalia len += count; size -= count; } - modalias[len] = '\0'; + return len; } @@ -212,8 +210,10 @@ static int create_of_modalias(const struct acpi_device *acpi_dev, char *modalias len = snprintf(modalias, size, "of:N%sT", (char *)buf.pointer); ACPI_FREE(buf.pointer); - if (len <= 0) - return len; + if (len >= size) + return -ENOMEM; + + size -= len; of_compatible = acpi_dev->data.of_compatible; if (of_compatible->type == ACPI_TYPE_PACKAGE) { @@ -226,8 +226,6 @@ static int create_of_modalias(const struct acpi_device *acpi_dev, char *modalias for (i = 0; i < nval; i++, obj++) { count = snprintf(&modalias[len], size, "C%s", obj->string.pointer); - if (count < 0) - return -EINVAL; if (count >= size) return -ENOMEM; @@ -235,7 +233,7 @@ static int create_of_modalias(const struct acpi_device *acpi_dev, char *modalias len += count; size -= count; } - modalias[len] = '\0'; + return len; } @@ -410,7 +408,7 @@ static ssize_t uid_show(struct device *dev, { struct acpi_device *acpi_dev = to_acpi_device(dev); - return sprintf(buf, "%s\n", acpi_dev->pnp.unique_id); + return sprintf(buf, "%s\n", acpi_device_uid(acpi_dev)); } static DEVICE_ATTR_RO(uid); @@ -554,7 +552,7 @@ int acpi_device_setup_files(struct acpi_device *dev) if (dev->pnp.type.bus_address) result = device_create_file(&dev->dev, &dev_attr_adr); - if (dev->pnp.unique_id) + if (acpi_device_uid(dev)) result = device_create_file(&dev->dev, &dev_attr_uid); if (acpi_has_method(dev->handle, "_SUN")) { @@ -635,7 +633,7 @@ void acpi_device_remove_files(struct acpi_device *dev) if (acpi_has_method(dev->handle, "_HRV")) device_remove_file(&dev->dev, &dev_attr_hrv); - if (dev->pnp.unique_id) + if (acpi_device_uid(dev)) device_remove_file(&dev->dev, &dev_attr_uid); if (dev->pnp.type.bus_address) device_remove_file(&dev->dev, &dev_attr_adr); diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index 660834a49c1f..a59c11df7375 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -1915,6 +1915,27 @@ static const struct dmi_system_id ec_dmi_table[] __initconst = { }, { /* + * HP Pavilion Gaming Laptop 15-dk1xxx + * https://github.com/systemd/systemd/issues/28942 + */ + .callback = ec_honor_dsdt_gpe, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "HP"), + DMI_MATCH(DMI_PRODUCT_NAME, "HP Pavilion Gaming Laptop 15-dk1xxx"), + }, + }, + { + /* + * HP 250 G7 Notebook PC + */ + .callback = ec_honor_dsdt_gpe, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "HP"), + DMI_MATCH(DMI_PRODUCT_NAME, "HP 250 G7 Notebook PC"), + }, + }, + { + /* * Samsung hardware * https://bugzilla.kernel.org/show_bug.cgi?id=44161 */ diff --git a/drivers/acpi/hed.c b/drivers/acpi/hed.c index 46c6f8c35b43..7652515a6be1 100644 --- a/drivers/acpi/hed.c +++ b/drivers/acpi/hed.c @@ -57,7 +57,7 @@ static int acpi_hed_add(struct acpi_device *device) hed_handle = device->handle; err = acpi_dev_install_notify_handler(device, ACPI_DEVICE_NOTIFY, - acpi_hed_notify); + acpi_hed_notify, device); if (err) hed_handle = NULL; diff --git a/drivers/acpi/irq.c b/drivers/acpi/irq.c index c2c786eb95ab..1687483ff319 100644 --- a/drivers/acpi/irq.c +++ b/drivers/acpi/irq.c @@ -57,6 +57,7 @@ int acpi_register_gsi(struct device *dev, u32 gsi, int trigger, int polarity) { struct irq_fwspec fwspec; + unsigned int irq; fwspec.fwnode = acpi_get_gsi_domain_id(gsi); if (WARN_ON(!fwspec.fwnode)) { @@ -68,7 +69,11 @@ int acpi_register_gsi(struct device *dev, u32 gsi, int trigger, fwspec.param[1] = acpi_dev_get_irq_type(trigger, polarity); fwspec.param_count = 2; - return irq_create_fwspec_mapping(&fwspec); + irq = irq_create_fwspec_mapping(&fwspec); + if (!irq) + return -EINVAL; + + return irq; } EXPORT_SYMBOL_GPL(acpi_register_gsi); diff --git a/drivers/acpi/nfit/core.c b/drivers/acpi/nfit/core.c index f0e6738ae3c9..992385537757 100644 --- a/drivers/acpi/nfit/core.c +++ b/drivers/acpi/nfit/core.c @@ -855,7 +855,7 @@ static size_t sizeof_idt(struct acpi_nfit_interleave *idt) { if (idt->header.length < sizeof(*idt)) return 0; - return sizeof(*idt) + sizeof(u32) * (idt->line_count - 1); + return sizeof(*idt) + sizeof(u32) * idt->line_count; } static bool add_idt(struct acpi_nfit_desc *acpi_desc, @@ -3339,6 +3339,16 @@ static int acpi_nfit_add(struct acpi_device *adev) acpi_size sz; int rc = 0; + rc = acpi_dev_install_notify_handler(adev, ACPI_DEVICE_NOTIFY, + acpi_nfit_notify, adev); + if (rc) + return rc; + + rc = devm_add_action_or_reset(dev, acpi_nfit_remove_notify_handler, + adev); + if (rc) + return rc; + status = acpi_get_table(ACPI_SIG_NFIT, 0, &tbl); if (ACPI_FAILURE(status)) { /* The NVDIMM root device allows OS to trigger enumeration of @@ -3386,17 +3396,7 @@ static int acpi_nfit_add(struct acpi_device *adev) if (rc) return rc; - rc = devm_add_action_or_reset(dev, acpi_nfit_shutdown, acpi_desc); - if (rc) - return rc; - - rc = acpi_dev_install_notify_handler(adev, ACPI_DEVICE_NOTIFY, - acpi_nfit_notify); - if (rc) - return rc; - - return devm_add_action_or_reset(dev, acpi_nfit_remove_notify_handler, - adev); + return devm_add_action_or_reset(dev, acpi_nfit_shutdown, acpi_desc); } static void acpi_nfit_update_notify(struct device *dev, acpi_handle handle) diff --git a/drivers/acpi/numa/srat.c b/drivers/acpi/numa/srat.c index 1f4fc5f8a819..12f330b0eac0 100644 --- a/drivers/acpi/numa/srat.c +++ b/drivers/acpi/numa/srat.c @@ -310,11 +310,16 @@ static int __init acpi_parse_cfmws(union acpi_subtable_headers *header, start = cfmws->base_hpa; end = cfmws->base_hpa + cfmws->window_size; - /* Skip if the SRAT already described the NUMA details for this HPA */ - node = phys_to_target_node(start); - if (node != NUMA_NO_NODE) + /* + * The SRAT may have already described NUMA details for all, + * or a portion of, this CFMWS HPA range. Extend the memblks + * found for any portion of the window to cover the entire + * window. + */ + if (!numa_fill_memblks(start, end)) return 0; + /* No SRAT description. Create a new node. */ node = acpi_map_pxm_to_node(*fake_pxm); if (node == NUMA_NO_NODE) { diff --git a/drivers/acpi/osi.c b/drivers/acpi/osi.c index d4405e1ca9b9..df9328c850bd 100644 --- a/drivers/acpi/osi.c +++ b/drivers/acpi/osi.c @@ -110,7 +110,7 @@ void __init acpi_osi_setup(char *str) break; } else if (osi->string[0] == '\0') { osi->enable = enable; - strncpy(osi->string, str, OSI_STRING_LENGTH_MAX); + strscpy(osi->string, str, OSI_STRING_LENGTH_MAX); break; } } diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index f725813d0cce..e154ad0be263 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c @@ -149,7 +149,7 @@ void acpi_os_printf(const char *fmt, ...) } EXPORT_SYMBOL(acpi_os_printf); -void acpi_os_vprintf(const char *fmt, va_list args) +void __printf(1, 0) acpi_os_vprintf(const char *fmt, va_list args) { static char buffer[512]; @@ -493,7 +493,7 @@ EXPORT_SYMBOL(acpi_os_unmap_generic_address); #ifdef ACPI_FUTURE_USAGE acpi_status -acpi_os_get_physical_address(void *virt, acpi_physical_address * phys) +acpi_os_get_physical_address(void *virt, acpi_physical_address *phys) { if (!phys || !virt) return AE_BAD_PARAMETER; @@ -784,7 +784,7 @@ acpi_os_write_memory(acpi_physical_address phys_addr, u64 value, u32 width) #ifdef CONFIG_PCI acpi_status -acpi_os_read_pci_configuration(struct acpi_pci_id * pci_id, u32 reg, +acpi_os_read_pci_configuration(struct acpi_pci_id *pci_id, u32 reg, u64 *value, u32 width) { int result, size; @@ -816,7 +816,7 @@ acpi_os_read_pci_configuration(struct acpi_pci_id * pci_id, u32 reg, } acpi_status -acpi_os_write_pci_configuration(struct acpi_pci_id * pci_id, u32 reg, +acpi_os_write_pci_configuration(struct acpi_pci_id *pci_id, u32 reg, u64 value, u32 width) { int result, size; @@ -1067,6 +1067,7 @@ acpi_status acpi_os_execute(acpi_execute_type type, struct acpi_os_dpc *dpc; struct workqueue_struct *queue; int ret; + ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Scheduling function [%p(%p)] for deferred execution.\n", function, context)); @@ -1197,7 +1198,7 @@ bool acpi_queue_hotplug_work(struct work_struct *work) } acpi_status -acpi_os_create_semaphore(u32 max_units, u32 initial_units, acpi_handle * handle) +acpi_os_create_semaphore(u32 max_units, u32 initial_units, acpi_handle *handle) { struct semaphore *sem = NULL; @@ -1522,6 +1523,7 @@ acpi_cpu_flags acpi_os_acquire_lock(acpi_spinlock lockp) __acquires(lockp) { acpi_cpu_flags flags; + spin_lock_irqsave(lockp, flags); return flags; } @@ -1554,7 +1556,7 @@ void acpi_os_release_lock(acpi_spinlock lockp, acpi_cpu_flags flags) ******************************************************************************/ acpi_status -acpi_os_create_cache(char *name, u16 size, u16 depth, acpi_cache_t ** cache) +acpi_os_create_cache(char *name, u16 size, u16 depth, acpi_cache_t **cache) { *cache = kmem_cache_create(name, size, 0, 0, NULL); if (*cache == NULL) @@ -1575,10 +1577,10 @@ acpi_os_create_cache(char *name, u16 size, u16 depth, acpi_cache_t ** cache) * ******************************************************************************/ -acpi_status acpi_os_purge_cache(acpi_cache_t * cache) +acpi_status acpi_os_purge_cache(acpi_cache_t *cache) { kmem_cache_shrink(cache); - return (AE_OK); + return AE_OK; } /******************************************************************************* @@ -1594,10 +1596,10 @@ acpi_status acpi_os_purge_cache(acpi_cache_t * cache) * ******************************************************************************/ -acpi_status acpi_os_delete_cache(acpi_cache_t * cache) +acpi_status acpi_os_delete_cache(acpi_cache_t *cache) { kmem_cache_destroy(cache); - return (AE_OK); + return AE_OK; } /******************************************************************************* @@ -1614,10 +1616,10 @@ acpi_status acpi_os_delete_cache(acpi_cache_t * cache) * ******************************************************************************/ -acpi_status acpi_os_release_object(acpi_cache_t * cache, void *object) +acpi_status acpi_os_release_object(acpi_cache_t *cache, void *object) { kmem_cache_free(cache, object); - return (AE_OK); + return AE_OK; } #endif @@ -1708,6 +1710,7 @@ acpi_status acpi_os_prepare_sleep(u8 sleep_state, u32 pm1a_control, u32 pm1b_control) { int rc = 0; + if (__acpi_os_prepare_sleep) rc = __acpi_os_prepare_sleep(sleep_state, pm1a_control, pm1b_control); @@ -1730,6 +1733,7 @@ acpi_status acpi_os_prepare_extended_sleep(u8 sleep_state, u32 val_a, u32 val_b) { int rc = 0; + if (__acpi_os_prepare_extended_sleep) rc = __acpi_os_prepare_extended_sleep(sleep_state, val_a, val_b); diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c index 84030804a763..58b89b8d950e 100644 --- a/drivers/acpi/pci_root.c +++ b/drivers/acpi/pci_root.c @@ -1055,9 +1055,9 @@ struct pci_bus *acpi_pci_root_create(struct acpi_pci_root *root, * exists and returns 0, we must preserve any PCI resource * assignments made by firmware for this host bridge. */ - obj = acpi_evaluate_dsm(ACPI_HANDLE(bus->bridge), &pci_acpi_dsm_guid, 1, - DSM_PCI_PRESERVE_BOOT_CONFIG, NULL); - if (obj && obj->type == ACPI_TYPE_INTEGER && obj->integer.value == 0) + obj = acpi_evaluate_dsm_typed(ACPI_HANDLE(bus->bridge), &pci_acpi_dsm_guid, 1, + DSM_PCI_PRESERVE_BOOT_CONFIG, NULL, ACPI_TYPE_INTEGER); + if (obj && obj->integer.value == 0) host_bridge->preserve_config = 1; ACPI_FREE(obj); diff --git a/drivers/acpi/prmt.c b/drivers/acpi/prmt.c index 7020584096bf..c78453c74ef5 100644 --- a/drivers/acpi/prmt.c +++ b/drivers/acpi/prmt.c @@ -69,7 +69,7 @@ struct prm_module_info { bool updatable; struct list_head module_list; - struct prm_handler_info handlers[]; + struct prm_handler_info handlers[] __counted_by(handler_count); }; static u64 efi_pa_va_lookup(u64 pa) diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index dc615ef6550a..3a34a8c425fe 100644 --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c @@ -1217,8 +1217,7 @@ static int acpi_processor_setup_lpi_states(struct acpi_processor *pr) strscpy(state->desc, lpi->desc, CPUIDLE_DESC_LEN); state->exit_latency = lpi->wake_latency; state->target_residency = lpi->min_residency; - if (lpi->arch_flags) - state->flags |= CPUIDLE_FLAG_TIMER_STOP; + state->flags |= arch_get_idle_state_flags(lpi->arch_flags); if (i != 0 && lpi->entry_method == ACPI_CSTATE_FFH) state->flags |= CPUIDLE_FLAG_RCU_IDLE; state->enter = acpi_idle_lpi_enter; diff --git a/drivers/acpi/processor_pdc.c b/drivers/acpi/processor_pdc.c index 1a8591e9a9bf..994091bd52de 100644 --- a/drivers/acpi/processor_pdc.c +++ b/drivers/acpi/processor_pdc.c @@ -19,6 +19,7 @@ static void acpi_set_pdc_bits(u32 *buf) { buf[0] = ACPI_PDC_REVISION_ID; buf[1] = 1; + buf[2] = 0; /* Twiddle arch-specific bits needed for _PDC */ arch_acpi_set_proc_cap_bits(&buf[2]); diff --git a/drivers/acpi/property.c b/drivers/acpi/property.c index 413e4fcadcaf..6979a3f9f90a 100644 --- a/drivers/acpi/property.c +++ b/drivers/acpi/property.c @@ -55,6 +55,7 @@ static const guid_t ads_guid = GUID_INIT(0xdbb8e3e6, 0x5886, 0x4ba6, 0x87, 0x95, 0x13, 0x19, 0xf5, 0x2a, 0x96, 0x6b); +/* ACPI _DSD data buffer GUID: edb12dd0-363d-4085-a3d2-49522ca160c4 */ static const guid_t buffer_prop_guid = GUID_INIT(0xedb12dd0, 0x363d, 0x4085, 0xa3, 0xd2, 0x49, 0x52, 0x2c, 0xa1, 0x60, 0xc4); @@ -1102,25 +1103,26 @@ static int acpi_data_prop_read(const struct acpi_device_data *data, switch (proptype) { case DEV_PROP_STRING: break; - case DEV_PROP_U8 ... DEV_PROP_U64: + default: if (obj->type == ACPI_TYPE_BUFFER) { if (nval > obj->buffer.length) return -EOVERFLOW; - break; + } else { + if (nval > obj->package.count) + return -EOVERFLOW; } - fallthrough; - default: - if (nval > obj->package.count) - return -EOVERFLOW; break; } if (nval == 0) return -EINVAL; - if (obj->type != ACPI_TYPE_BUFFER) - items = obj->package.elements; - else + if (obj->type == ACPI_TYPE_BUFFER) { + if (proptype != DEV_PROP_U8) + return -EPROTO; items = obj; + } else { + items = obj->package.elements; + } switch (proptype) { case DEV_PROP_U8: diff --git a/drivers/acpi/resource.c b/drivers/acpi/resource.c index 32cfa3f4efd3..15a3bdbd0755 100644 --- a/drivers/acpi/resource.c +++ b/drivers/acpi/resource.c @@ -385,140 +385,160 @@ 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[] = { +/* + * DMI matches for boards where the DSDT specifies the kbd IRQ as + * level active-low and using the override changes this to rising edge, + * stopping the keyboard from working. + */ +static const struct dmi_system_id irq1_level_low_skip_override[] = { { - .ident = "MEDION P15651", + /* MEDION P15651 */ .matches = { DMI_MATCH(DMI_SYS_VENDOR, "MEDION"), DMI_MATCH(DMI_BOARD_NAME, "M15T"), }, }, { - .ident = "MEDION S17405", + /* MEDION S17405 */ .matches = { DMI_MATCH(DMI_SYS_VENDOR, "MEDION"), DMI_MATCH(DMI_BOARD_NAME, "M17T"), }, }, { - .ident = "MEDION S17413", + /* MEDION S17413 */ .matches = { DMI_MATCH(DMI_SYS_VENDOR, "MEDION"), DMI_MATCH(DMI_BOARD_NAME, "M1xA"), }, }, - { } -}; - -static const struct dmi_system_id asus_laptop[] = { { - .ident = "Asus Vivobook K3402ZA", + /* Asus Vivobook K3402ZA */ .matches = { DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), DMI_MATCH(DMI_BOARD_NAME, "K3402ZA"), }, }, { - .ident = "Asus Vivobook K3502ZA", + /* Asus Vivobook K3502ZA */ .matches = { DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), DMI_MATCH(DMI_BOARD_NAME, "K3502ZA"), }, }, { - .ident = "Asus Vivobook S5402ZA", + /* Asus Vivobook S5402ZA */ .matches = { DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), DMI_MATCH(DMI_BOARD_NAME, "S5402ZA"), }, }, { - .ident = "Asus Vivobook S5602ZA", + /* Asus Vivobook S5602ZA */ .matches = { DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), DMI_MATCH(DMI_BOARD_NAME, "S5602ZA"), }, }, { - .ident = "Asus ExpertBook B1502CBA", + /* Asus ExpertBook B1402CBA */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), + DMI_MATCH(DMI_BOARD_NAME, "B1402CBA"), + }, + }, + { + /* Asus ExpertBook B1502CBA */ .matches = { DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), DMI_MATCH(DMI_BOARD_NAME, "B1502CBA"), }, }, { - .ident = "Asus ExpertBook B2402CBA", + /* Asus ExpertBook B2402CBA */ .matches = { DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), DMI_MATCH(DMI_BOARD_NAME, "B2402CBA"), }, }, { - .ident = "Asus ExpertBook B2402FBA", + /* Asus ExpertBook B2402FBA */ .matches = { DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), DMI_MATCH(DMI_BOARD_NAME, "B2402FBA"), }, }, { - .ident = "Asus ExpertBook B2502", + /* Asus ExpertBook B2502 */ .matches = { DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), DMI_MATCH(DMI_BOARD_NAME, "B2502CBA"), }, }, + { + /* LG Electronics 17U70P */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LG Electronics"), + DMI_MATCH(DMI_BOARD_NAME, "17U70P"), + }, + }, { } }; -static const struct dmi_system_id tongfang_gm_rg[] = { +/* + * DMI matches for AMD Zen boards where the DSDT specifies the kbd IRQ + * as falling edge and this must be overridden to rising edge, + * to have a working keyboard. + */ +static const struct dmi_system_id irq1_edge_low_force_override[] = { { - .ident = "TongFang GMxRGxx/XMG CORE 15 (M22)/TUXEDO Stellaris 15 Gen4 AMD", + /* TongFang GMxRGxx/XMG CORE 15 (M22)/TUXEDO Stellaris 15 Gen4 AMD */ .matches = { DMI_MATCH(DMI_BOARD_NAME, "GMxRGxx"), }, }, - { } -}; - -static const struct dmi_system_id maingear_laptop[] = { { - .ident = "MAINGEAR Vector Pro 2 15", + /* TongFang GMxXGxx/TUXEDO Polaris 15 Gen5 AMD */ + .matches = { + DMI_MATCH(DMI_BOARD_NAME, "GMxXGxx"), + }, + }, + { + /* TongFang GM6XGxX/TUXEDO Stellaris 16 Gen5 AMD */ + .matches = { + DMI_MATCH(DMI_BOARD_NAME, "GM6XGxX"), + }, + }, + { + /* MAINGEAR Vector Pro 2 15 */ .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Micro Electronics Inc"), DMI_MATCH(DMI_PRODUCT_NAME, "MG-VCP2-15A3070T"), } }, { - .ident = "MAINGEAR Vector Pro 2 17", + /* MAINGEAR Vector Pro 2 17 */ .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Micro Electronics Inc"), DMI_MATCH(DMI_PRODUCT_NAME, "MG-VCP2-17A3070T"), }, }, - { } -}; - -static const struct dmi_system_id pcspecialist_laptop[] = { { - .ident = "PCSpecialist Elimina Pro 16 M", - /* - * Some models have product-name "Elimina Pro 16 M", - * others "GM6BGEQ". Match on board-name to match both. - */ + /* TongFang GM6BGEQ / PCSpecialist Elimina Pro 16 M, RTX 3050 */ .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "PCSpecialist"), DMI_MATCH(DMI_BOARD_NAME, "GM6BGEQ"), }, }, - { } -}; - -static const struct dmi_system_id lg_laptop[] = { { - .ident = "LG Electronics 17U70P", + /* TongFang GM6BG5Q, RTX 4050 */ .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "LG Electronics"), - DMI_MATCH(DMI_BOARD_NAME, "17U70P"), + DMI_MATCH(DMI_BOARD_NAME, "GM6BG5Q"), + }, + }, + { + /* TongFang GM6BG0Q / PCSpecialist Elimina Pro 16 M, RTX 4060 */ + .matches = { + DMI_MATCH(DMI_BOARD_NAME, "GM6BG0Q"), }, }, { } @@ -534,12 +554,8 @@ struct irq_override_cmp { }; static const struct irq_override_cmp override_table[] = { - { medion_laptop, 1, ACPI_LEVEL_SENSITIVE, ACPI_ACTIVE_LOW, 0, false }, - { asus_laptop, 1, ACPI_LEVEL_SENSITIVE, ACPI_ACTIVE_LOW, 0, false }, - { tongfang_gm_rg, 1, ACPI_EDGE_SENSITIVE, ACPI_ACTIVE_LOW, 1, true }, - { maingear_laptop, 1, ACPI_EDGE_SENSITIVE, ACPI_ACTIVE_LOW, 1, true }, - { pcspecialist_laptop, 1, ACPI_EDGE_SENSITIVE, ACPI_ACTIVE_LOW, 1, true }, - { lg_laptop, 1, ACPI_LEVEL_SENSITIVE, ACPI_ACTIVE_LOW, 0, false }, + { irq1_level_low_skip_override, 1, ACPI_LEVEL_SENSITIVE, ACPI_ACTIVE_LOW, 0, false }, + { irq1_edge_low_force_override, 1, ACPI_EDGE_SENSITIVE, ACPI_ACTIVE_LOW, 1, true }, }; static bool acpi_dev_irq_override(u32 gsi, u8 triggering, u8 polarity, diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 691d4b7686ee..fa5dd71a80fa 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -289,10 +289,10 @@ static int acpi_scan_hot_remove(struct acpi_device *device) return 0; } -static int acpi_scan_device_not_present(struct acpi_device *adev) +static int acpi_scan_device_not_enumerated(struct acpi_device *adev) { if (!acpi_device_enumerated(adev)) { - dev_warn(&adev->dev, "Still not present\n"); + dev_warn(&adev->dev, "Still not enumerated\n"); return -EALREADY; } acpi_bus_trim(adev); @@ -304,7 +304,7 @@ static int acpi_scan_device_check(struct acpi_device *adev) int error; acpi_bus_get_status(adev); - if (adev->status.present || adev->status.functional) { + if (acpi_device_is_present(adev)) { /* * This function is only called for device objects for which * matching scan handlers exist. The only situation in which @@ -327,7 +327,7 @@ static int acpi_scan_device_check(struct acpi_device *adev) error = -ENODEV; } } else { - error = acpi_scan_device_not_present(adev); + error = acpi_scan_device_not_enumerated(adev); } return error; } @@ -338,8 +338,8 @@ static int acpi_scan_bus_check(struct acpi_device *adev, void *not_used) int error; acpi_bus_get_status(adev); - if (!(adev->status.present || adev->status.functional)) { - acpi_scan_device_not_present(adev); + if (!acpi_device_is_present(adev)) { + acpi_scan_device_not_enumerated(adev); return 0; } if (handler && handler->hotplug.scan_dependent) @@ -2032,6 +2032,7 @@ static u32 acpi_scan_check_dep(acpi_handle handle, bool check_dep) mutex_unlock(&acpi_dep_list_lock); } + acpi_handle_list_free(&dep_devices); return count; } diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c index f14e68266ccd..d98ff69303b3 100644 --- a/drivers/acpi/thermal.c +++ b/drivers/acpi/thermal.c @@ -43,17 +43,7 @@ #define ACPI_THERMAL_MAX_ACTIVE 10 #define ACPI_THERMAL_MAX_LIMIT_STR_LEN 65 -#define ACPI_TRIPS_CRITICAL BIT(0) -#define ACPI_TRIPS_HOT BIT(1) -#define ACPI_TRIPS_PASSIVE BIT(2) -#define ACPI_TRIPS_ACTIVE BIT(3) -#define ACPI_TRIPS_DEVICES BIT(4) - -#define ACPI_TRIPS_THRESHOLDS (ACPI_TRIPS_PASSIVE | ACPI_TRIPS_ACTIVE) - -#define ACPI_TRIPS_INIT (ACPI_TRIPS_CRITICAL | ACPI_TRIPS_HOT | \ - ACPI_TRIPS_PASSIVE | ACPI_TRIPS_ACTIVE | \ - ACPI_TRIPS_DEVICES) +#define ACPI_THERMAL_TRIP_PASSIVE (-1) /* * This exception is thrown out in two cases: @@ -62,12 +52,11 @@ * 2.TODO: Devices listed in _PSL, _ALx, _TZD may change. * We need to re-bind the cooling devices of a thermal zone when this occurs. */ -#define ACPI_THERMAL_TRIPS_EXCEPTION(flags, tz, str) \ +#define ACPI_THERMAL_TRIPS_EXCEPTION(tz, str) \ do { \ - if (flags != ACPI_TRIPS_INIT) \ - acpi_handle_info(tz->device->handle, \ - "ACPI thermal trip point %s changed\n" \ - "Please report to linux-acpi@vger.kernel.org\n", str); \ + acpi_handle_info(tz->device->handle, \ + "ACPI thermal trip point %s changed\n" \ + "Please report to linux-acpi@vger.kernel.org\n", str); \ } while (0) static int act; @@ -93,13 +82,12 @@ MODULE_PARM_DESC(psv, "Disable or override all passive trip points."); static struct workqueue_struct *acpi_thermal_pm_queue; struct acpi_thermal_trip { - unsigned long temperature; - bool valid; + unsigned long temp_dk; + struct acpi_handle_list devices; }; struct acpi_thermal_passive { struct acpi_thermal_trip trip; - struct acpi_handle_list devices; unsigned long tc1; unsigned long tc2; unsigned long tsp; @@ -107,12 +95,9 @@ struct acpi_thermal_passive { struct acpi_thermal_active { struct acpi_thermal_trip trip; - struct acpi_handle_list devices; }; struct acpi_thermal_trips { - struct acpi_thermal_trip critical; - struct acpi_thermal_trip hot; struct acpi_thermal_passive passive; struct acpi_thermal_active active[ACPI_THERMAL_MAX_ACTIVE]; }; @@ -120,13 +105,12 @@ struct acpi_thermal_trips { struct acpi_thermal { struct acpi_device *device; acpi_bus_id name; - unsigned long temperature; - unsigned long last_temperature; + unsigned long temp_dk; + unsigned long last_temp_dk; unsigned long polling_frequency; volatile u8 zombie; struct acpi_thermal_trips trips; struct thermal_trip *trip_table; - struct acpi_handle_list devices; struct thermal_zone_device *thermal_zone; int kelvin_offset; /* in millidegrees */ struct work_struct thermal_check_work; @@ -146,16 +130,16 @@ static int acpi_thermal_get_temperature(struct acpi_thermal *tz) if (!tz) return -EINVAL; - tz->last_temperature = tz->temperature; + tz->last_temp_dk = tz->temp_dk; status = acpi_evaluate_integer(tz->device->handle, "_TMP", NULL, &tmp); if (ACPI_FAILURE(status)) return -ENODEV; - tz->temperature = tmp; + tz->temp_dk = tmp; acpi_handle_debug(tz->device->handle, "Temperature is %lu dK\n", - tz->temperature); + tz->temp_dk); return 0; } @@ -188,245 +172,148 @@ static int acpi_thermal_temp(struct acpi_thermal *tz, int temp_deci_k) tz->kelvin_offset); } -static void __acpi_thermal_trips_update(struct acpi_thermal *tz, int flag) +static bool acpi_thermal_trip_valid(struct acpi_thermal_trip *acpi_trip) +{ + return acpi_trip->temp_dk != THERMAL_TEMP_INVALID; +} + +static int active_trip_index(struct acpi_thermal *tz, + struct acpi_thermal_trip *acpi_trip) +{ + struct acpi_thermal_active *active; + + active = container_of(acpi_trip, struct acpi_thermal_active, trip); + return active - tz->trips.active; +} + +static long get_passive_temp(struct acpi_thermal *tz) { + unsigned long long tmp; acpi_status status; + + status = acpi_evaluate_integer(tz->device->handle, "_PSV", NULL, &tmp); + if (ACPI_FAILURE(status)) + return THERMAL_TEMP_INVALID; + + return tmp; +} + +static long get_active_temp(struct acpi_thermal *tz, int index) +{ + char method[] = { '_', 'A', 'C', '0' + index, '\0' }; unsigned long long tmp; - struct acpi_handle_list devices; - bool valid = false; - int i; + acpi_status status; - /* Critical Shutdown */ - if (flag & ACPI_TRIPS_CRITICAL) { - status = acpi_evaluate_integer(tz->device->handle, "_CRT", NULL, &tmp); - tz->trips.critical.temperature = tmp; - /* - * Treat freezing temperatures as invalid as well; some - * BIOSes return really low values and cause reboots at startup. - * Below zero (Celsius) values clearly aren't right for sure.. - * ... so lets discard those as invalid. - */ - if (ACPI_FAILURE(status)) { - tz->trips.critical.valid = false; - acpi_handle_debug(tz->device->handle, - "No critical threshold\n"); - } else if (tmp <= 2732) { - pr_info(FW_BUG "Invalid critical threshold (%llu)\n", tmp); - tz->trips.critical.valid = false; - } else { - tz->trips.critical.valid = true; - acpi_handle_debug(tz->device->handle, - "Found critical threshold [%lu]\n", - tz->trips.critical.temperature); - } - if (tz->trips.critical.valid) { - if (crt == -1) { - tz->trips.critical.valid = false; - } else if (crt > 0) { - unsigned long crt_k = celsius_to_deci_kelvin(crt); - - /* - * Allow override critical threshold - */ - if (crt_k > tz->trips.critical.temperature) - pr_info("Critical threshold %d C\n", crt); - - tz->trips.critical.temperature = crt_k; - } - } + status = acpi_evaluate_integer(tz->device->handle, method, NULL, &tmp); + if (ACPI_FAILURE(status)) + return THERMAL_TEMP_INVALID; + + /* + * If an override has been provided, apply it so there are no active + * trips with thresholds greater than the override. + */ + if (act > 0) { + unsigned long long override = celsius_to_deci_kelvin(act); + + if (tmp > override) + tmp = override; } + return tmp; +} - /* Critical Sleep (optional) */ - if (flag & ACPI_TRIPS_HOT) { - status = acpi_evaluate_integer(tz->device->handle, "_HOT", NULL, &tmp); - if (ACPI_FAILURE(status)) { - tz->trips.hot.valid = false; - acpi_handle_debug(tz->device->handle, - "No hot threshold\n"); - } else { - tz->trips.hot.temperature = tmp; - tz->trips.hot.valid = true; - acpi_handle_debug(tz->device->handle, - "Found hot threshold [%lu]\n", - tz->trips.hot.temperature); - } +static void acpi_thermal_update_trip(struct acpi_thermal *tz, + const struct thermal_trip *trip) +{ + struct acpi_thermal_trip *acpi_trip = trip->priv; + + if (trip->type == THERMAL_TRIP_PASSIVE) { + if (psv > 0) + return; + + acpi_trip->temp_dk = get_passive_temp(tz); + } else { + int index = active_trip_index(tz, acpi_trip); + + acpi_trip->temp_dk = get_active_temp(tz, index); } - /* Passive (optional) */ - if (((flag & ACPI_TRIPS_PASSIVE) && tz->trips.passive.trip.valid) || - flag == ACPI_TRIPS_INIT) { - valid = tz->trips.passive.trip.valid; - if (psv == -1) { - status = AE_SUPPORT; - } else if (psv > 0) { - tmp = celsius_to_deci_kelvin(psv); - status = AE_OK; - } else { - status = acpi_evaluate_integer(tz->device->handle, - "_PSV", NULL, &tmp); - } + if (!acpi_thermal_trip_valid(acpi_trip)) + ACPI_THERMAL_TRIPS_EXCEPTION(tz, "state"); +} - if (ACPI_FAILURE(status)) { - tz->trips.passive.trip.valid = false; - } else { - tz->trips.passive.trip.temperature = tmp; - tz->trips.passive.trip.valid = true; - if (flag == ACPI_TRIPS_INIT) { - status = acpi_evaluate_integer(tz->device->handle, - "_TC1", NULL, &tmp); - if (ACPI_FAILURE(status)) - tz->trips.passive.trip.valid = false; - else - tz->trips.passive.tc1 = tmp; - - status = acpi_evaluate_integer(tz->device->handle, - "_TC2", NULL, &tmp); - if (ACPI_FAILURE(status)) - tz->trips.passive.trip.valid = false; - else - tz->trips.passive.tc2 = tmp; - - status = acpi_evaluate_integer(tz->device->handle, - "_TSP", NULL, &tmp); - if (ACPI_FAILURE(status)) - tz->trips.passive.trip.valid = false; - else - tz->trips.passive.tsp = tmp; - } - } +static bool update_trip_devices(struct acpi_thermal *tz, + struct acpi_thermal_trip *acpi_trip, + int index, bool compare) +{ + struct acpi_handle_list devices = { 0 }; + char method[] = "_PSL"; + acpi_status status; + + if (index != ACPI_THERMAL_TRIP_PASSIVE) { + method[1] = 'A'; + method[2] = 'L'; + method[3] = '0' + index; } - if ((flag & ACPI_TRIPS_DEVICES) && tz->trips.passive.trip.valid) { - memset(&devices, 0, sizeof(struct acpi_handle_list)); - status = acpi_evaluate_reference(tz->device->handle, "_PSL", - NULL, &devices); - if (ACPI_FAILURE(status)) { - acpi_handle_info(tz->device->handle, - "Invalid passive threshold\n"); - tz->trips.passive.trip.valid = false; - } else { - tz->trips.passive.trip.valid = true; - } - if (memcmp(&tz->trips.passive.devices, &devices, - sizeof(struct acpi_handle_list))) { - memcpy(&tz->trips.passive.devices, &devices, - sizeof(struct acpi_handle_list)); - ACPI_THERMAL_TRIPS_EXCEPTION(flag, tz, "device"); - } + status = acpi_evaluate_reference(tz->device->handle, method, NULL, &devices); + if (ACPI_FAILURE(status)) { + acpi_handle_info(tz->device->handle, "%s evaluation failure\n", method); + return false; } - if ((flag & ACPI_TRIPS_PASSIVE) || (flag & ACPI_TRIPS_DEVICES)) { - if (valid != tz->trips.passive.trip.valid) - ACPI_THERMAL_TRIPS_EXCEPTION(flag, tz, "state"); + + if (acpi_handle_list_equal(&acpi_trip->devices, &devices)) { + acpi_handle_list_free(&devices); + return true; } - /* Active (optional) */ - for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE; i++) { - char name[5] = { '_', 'A', 'C', ('0' + i), '\0' }; - valid = tz->trips.active[i].trip.valid; + if (compare) + ACPI_THERMAL_TRIPS_EXCEPTION(tz, "device"); - if (act == -1) - break; /* disable all active trip points */ - - if (flag == ACPI_TRIPS_INIT || ((flag & ACPI_TRIPS_ACTIVE) && - tz->trips.active[i].trip.valid)) { - status = acpi_evaluate_integer(tz->device->handle, - name, NULL, &tmp); - if (ACPI_FAILURE(status)) { - tz->trips.active[i].trip.valid = false; - if (i == 0) - break; - - if (act <= 0) - break; - - if (i == 1) - tz->trips.active[0].trip.temperature = - celsius_to_deci_kelvin(act); - else - /* - * Don't allow override higher than - * the next higher trip point - */ - tz->trips.active[i-1].trip.temperature = - min_t(unsigned long, - tz->trips.active[i-2].trip.temperature, - celsius_to_deci_kelvin(act)); - - break; - } else { - tz->trips.active[i].trip.temperature = tmp; - tz->trips.active[i].trip.valid = true; - } - } + acpi_handle_list_replace(&acpi_trip->devices, &devices); + return true; +} - name[2] = 'L'; - if ((flag & ACPI_TRIPS_DEVICES) && tz->trips.active[i].trip.valid) { - memset(&devices, 0, sizeof(struct acpi_handle_list)); - status = acpi_evaluate_reference(tz->device->handle, - name, NULL, &devices); - if (ACPI_FAILURE(status)) { - acpi_handle_info(tz->device->handle, - "Invalid active%d threshold\n", i); - tz->trips.active[i].trip.valid = false; - } else { - tz->trips.active[i].trip.valid = true; - } - - if (memcmp(&tz->trips.active[i].devices, &devices, - sizeof(struct acpi_handle_list))) { - memcpy(&tz->trips.active[i].devices, &devices, - sizeof(struct acpi_handle_list)); - ACPI_THERMAL_TRIPS_EXCEPTION(flag, tz, "device"); - } - } - if ((flag & ACPI_TRIPS_ACTIVE) || (flag & ACPI_TRIPS_DEVICES)) - if (valid != tz->trips.active[i].trip.valid) - ACPI_THERMAL_TRIPS_EXCEPTION(flag, tz, "state"); +static void acpi_thermal_update_trip_devices(struct acpi_thermal *tz, + const struct thermal_trip *trip) +{ + struct acpi_thermal_trip *acpi_trip = trip->priv; + int index = trip->type == THERMAL_TRIP_PASSIVE ? + ACPI_THERMAL_TRIP_PASSIVE : active_trip_index(tz, acpi_trip); - if (!tz->trips.active[i].trip.valid) - break; - } + if (update_trip_devices(tz, acpi_trip, index, true)) + return; - if (flag & ACPI_TRIPS_DEVICES) { - memset(&devices, 0, sizeof(devices)); - status = acpi_evaluate_reference(tz->device->handle, "_TZD", - NULL, &devices); - if (ACPI_SUCCESS(status) && - memcmp(&tz->devices, &devices, sizeof(devices))) { - tz->devices = devices; - ACPI_THERMAL_TRIPS_EXCEPTION(flag, tz, "device"); - } - } + acpi_trip->temp_dk = THERMAL_TEMP_INVALID; + ACPI_THERMAL_TRIPS_EXCEPTION(tz, "state"); } +struct adjust_trip_data { + struct acpi_thermal *tz; + u32 event; +}; + static int acpi_thermal_adjust_trip(struct thermal_trip *trip, void *data) { struct acpi_thermal_trip *acpi_trip = trip->priv; - struct acpi_thermal *tz = data; + struct adjust_trip_data *atd = data; + struct acpi_thermal *tz = atd->tz; - if (!acpi_trip) + if (!acpi_trip || !acpi_thermal_trip_valid(acpi_trip)) return 0; - if (acpi_trip->valid) - trip->temperature = acpi_thermal_temp(tz, acpi_trip->temperature); + if (atd->event == ACPI_THERMAL_NOTIFY_THRESHOLDS) + acpi_thermal_update_trip(tz, trip); + else + acpi_thermal_update_trip_devices(tz, trip); + + if (acpi_thermal_trip_valid(acpi_trip)) + trip->temperature = acpi_thermal_temp(tz, acpi_trip->temp_dk); else trip->temperature = THERMAL_TEMP_INVALID; return 0; } -static void acpi_thermal_adjust_thermal_zone(struct thermal_zone_device *thermal, - unsigned long data) -{ - struct acpi_thermal *tz = thermal_zone_device_priv(thermal); - int flag = data == ACPI_THERMAL_NOTIFY_THRESHOLDS ? - ACPI_TRIPS_THRESHOLDS : ACPI_TRIPS_DEVICES; - - __acpi_thermal_trips_update(tz, flag); - - for_each_thermal_trip(tz->thermal_zone, acpi_thermal_adjust_trip, tz); -} - static void acpi_queue_thermal_check(struct acpi_thermal *tz) { if (!work_pending(&tz->thermal_check_work)) @@ -435,41 +322,156 @@ static void acpi_queue_thermal_check(struct acpi_thermal *tz) static void acpi_thermal_trips_update(struct acpi_thermal *tz, u32 event) { + struct adjust_trip_data atd = { .tz = tz, .event = event }; struct acpi_device *adev = tz->device; /* - * Use thermal_zone_device_exec() to carry out the trip points + * Use thermal_zone_for_each_trip() to carry out the trip points * update, so as to protect thermal_get_trend() from getting stale * trip point temperatures and to prevent thermal_zone_device_update() * invoked from acpi_thermal_check_fn() from producing inconsistent * results. */ - thermal_zone_device_exec(tz->thermal_zone, - acpi_thermal_adjust_thermal_zone, event); + thermal_zone_for_each_trip(tz->thermal_zone, + acpi_thermal_adjust_trip, &atd); acpi_queue_thermal_check(tz); acpi_bus_generate_netlink_event(adev->pnp.device_class, dev_name(&adev->dev), event, 0); } +static long acpi_thermal_get_critical_trip(struct acpi_thermal *tz) +{ + unsigned long long tmp; + acpi_status status; + + if (crt > 0) { + tmp = celsius_to_deci_kelvin(crt); + goto set; + } + if (crt == -1) { + acpi_handle_debug(tz->device->handle, "Critical threshold disabled\n"); + return THERMAL_TEMP_INVALID; + } + + status = acpi_evaluate_integer(tz->device->handle, "_CRT", NULL, &tmp); + if (ACPI_FAILURE(status)) { + acpi_handle_debug(tz->device->handle, "No critical threshold\n"); + return THERMAL_TEMP_INVALID; + } + if (tmp <= 2732) { + /* + * Below zero (Celsius) values clearly aren't right for sure, + * so discard them as invalid. + */ + pr_info(FW_BUG "Invalid critical threshold (%llu)\n", tmp); + return THERMAL_TEMP_INVALID; + } + +set: + acpi_handle_debug(tz->device->handle, "Critical threshold [%llu]\n", tmp); + return tmp; +} + +static long acpi_thermal_get_hot_trip(struct acpi_thermal *tz) +{ + unsigned long long tmp; + acpi_status status; + + status = acpi_evaluate_integer(tz->device->handle, "_HOT", NULL, &tmp); + if (ACPI_FAILURE(status)) { + acpi_handle_debug(tz->device->handle, "No hot threshold\n"); + return THERMAL_TEMP_INVALID; + } + + acpi_handle_debug(tz->device->handle, "Hot threshold [%llu]\n", tmp); + return tmp; +} + +static bool passive_trip_params_init(struct acpi_thermal *tz) +{ + unsigned long long tmp; + acpi_status status; + + status = acpi_evaluate_integer(tz->device->handle, "_TC1", NULL, &tmp); + if (ACPI_FAILURE(status)) + return false; + + tz->trips.passive.tc1 = tmp; + + status = acpi_evaluate_integer(tz->device->handle, "_TC2", NULL, &tmp); + if (ACPI_FAILURE(status)) + return false; + + tz->trips.passive.tc2 = tmp; + + status = acpi_evaluate_integer(tz->device->handle, "_TSP", NULL, &tmp); + if (ACPI_FAILURE(status)) + return false; + + tz->trips.passive.tsp = tmp; + + return true; +} + +static bool acpi_thermal_init_trip(struct acpi_thermal *tz, int index) +{ + struct acpi_thermal_trip *acpi_trip; + long temp; + + if (index == ACPI_THERMAL_TRIP_PASSIVE) { + acpi_trip = &tz->trips.passive.trip; + + if (psv == -1) + goto fail; + + if (!passive_trip_params_init(tz)) + goto fail; + + temp = psv > 0 ? celsius_to_deci_kelvin(psv) : + get_passive_temp(tz); + } else { + acpi_trip = &tz->trips.active[index].trip; + + if (act == -1) + goto fail; + + temp = get_active_temp(tz, index); + } + + if (temp == THERMAL_TEMP_INVALID) + goto fail; + + if (!update_trip_devices(tz, acpi_trip, index, false)) + goto fail; + + acpi_trip->temp_dk = temp; + return true; + +fail: + acpi_trip->temp_dk = THERMAL_TEMP_INVALID; + return false; +} + static int acpi_thermal_get_trip_points(struct acpi_thermal *tz) { - bool valid; + unsigned int count = 0; int i; - __acpi_thermal_trips_update(tz, ACPI_TRIPS_INIT); + if (acpi_thermal_init_trip(tz, ACPI_THERMAL_TRIP_PASSIVE)) + count++; - valid = tz->trips.critical.valid | - tz->trips.hot.valid | - tz->trips.passive.trip.valid; - - for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE; i++) - valid = valid || tz->trips.active[i].trip.valid; + for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE; i++) { + if (acpi_thermal_init_trip(tz, i)) + count++; + else + break; - if (!valid) { - pr_warn(FW_BUG "No valid trip found\n"); - return -ENODEV; } - return 0; + + while (++i < ACPI_THERMAL_MAX_ACTIVE) + tz->trips.active[i].trip.temp_dk = THERMAL_TEMP_INVALID; + + return count; } /* sys I/F for generic thermal sysfs support */ @@ -486,13 +488,13 @@ static int thermal_get_temp(struct thermal_zone_device *thermal, int *temp) if (result) return result; - *temp = deci_kelvin_to_millicelsius_with_offset(tz->temperature, + *temp = deci_kelvin_to_millicelsius_with_offset(tz->temp_dk, tz->kelvin_offset); return 0; } static int thermal_get_trend(struct thermal_zone_device *thermal, - struct thermal_trip *trip, + const struct thermal_trip *trip, enum thermal_trend *trend) { struct acpi_thermal *tz = thermal_zone_device_priv(thermal); @@ -503,15 +505,15 @@ static int thermal_get_trend(struct thermal_zone_device *thermal, return -EINVAL; acpi_trip = trip->priv; - if (!acpi_trip || !acpi_trip->valid) + if (!acpi_trip || !acpi_thermal_trip_valid(acpi_trip)) return -EINVAL; switch (trip->type) { case THERMAL_TRIP_PASSIVE: - t = tz->trips.passive.tc1 * (tz->temperature - - tz->last_temperature) + - tz->trips.passive.tc2 * (tz->temperature - - acpi_trip->temperature); + t = tz->trips.passive.tc1 * (tz->temp_dk - + tz->last_temp_dk) + + tz->trips.passive.tc2 * (tz->temp_dk - + acpi_trip->temp_dk); if (t > 0) *trend = THERMAL_TREND_RAISING; else if (t < 0) @@ -522,7 +524,7 @@ static int thermal_get_trend(struct thermal_zone_device *thermal, return 0; case THERMAL_TRIP_ACTIVE: - t = acpi_thermal_temp(tz, tz->temperature); + t = acpi_thermal_temp(tz, tz->temp_dk); if (t <= trip->temperature) break; @@ -557,91 +559,72 @@ static void acpi_thermal_zone_device_critical(struct thermal_zone_device *therma thermal_zone_device_critical(thermal); } -static int acpi_thermal_cooling_device_cb(struct thermal_zone_device *thermal, - struct thermal_cooling_device *cdev, - bool bind) +struct acpi_thermal_bind_data { + struct thermal_zone_device *thermal; + struct thermal_cooling_device *cdev; + bool bind; +}; + +static int bind_unbind_cdev_cb(struct thermal_trip *trip, void *arg) { - struct acpi_device *device = cdev->devdata; - struct acpi_thermal *tz = thermal_zone_device_priv(thermal); - struct acpi_device *dev; - acpi_handle handle; + struct acpi_thermal_trip *acpi_trip = trip->priv; + struct acpi_thermal_bind_data *bd = arg; + struct thermal_zone_device *thermal = bd->thermal; + struct thermal_cooling_device *cdev = bd->cdev; + struct acpi_device *cdev_adev = cdev->devdata; int i; - int j; - int trip = -1; - int result = 0; - if (tz->trips.critical.valid) - trip++; + /* Skip critical and hot trips. */ + if (!acpi_trip) + return 0; - if (tz->trips.hot.valid) - trip++; + for (i = 0; i < acpi_trip->devices.count; i++) { + acpi_handle handle = acpi_trip->devices.handles[i]; + struct acpi_device *adev = acpi_fetch_acpi_dev(handle); - if (tz->trips.passive.trip.valid) { - trip++; - for (i = 0; i < tz->trips.passive.devices.count; i++) { - handle = tz->trips.passive.devices.handles[i]; - dev = acpi_fetch_acpi_dev(handle); - if (dev != device) - continue; - - if (bind) - result = thermal_zone_bind_cooling_device( - thermal, trip, cdev, - THERMAL_NO_LIMIT, - THERMAL_NO_LIMIT, - THERMAL_WEIGHT_DEFAULT); - else - result = - thermal_zone_unbind_cooling_device( - thermal, trip, cdev); - - if (result) - goto failed; - } - } + if (adev != cdev_adev) + continue; - for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE; i++) { - if (!tz->trips.active[i].trip.valid) - break; + if (bd->bind) { + int ret; - trip++; - for (j = 0; j < tz->trips.active[i].devices.count; j++) { - handle = tz->trips.active[i].devices.handles[j]; - dev = acpi_fetch_acpi_dev(handle); - if (dev != device) - continue; - - if (bind) - result = thermal_zone_bind_cooling_device( - thermal, trip, cdev, - THERMAL_NO_LIMIT, - THERMAL_NO_LIMIT, - THERMAL_WEIGHT_DEFAULT); - else - result = thermal_zone_unbind_cooling_device( - thermal, trip, cdev); - - if (result) - goto failed; + ret = thermal_bind_cdev_to_trip(thermal, trip, cdev, + THERMAL_NO_LIMIT, + THERMAL_NO_LIMIT, + THERMAL_WEIGHT_DEFAULT); + if (ret) + return ret; + } else { + thermal_unbind_cdev_from_trip(thermal, trip, cdev); } } -failed: - return result; + return 0; +} + +static int acpi_thermal_bind_unbind_cdev(struct thermal_zone_device *thermal, + struct thermal_cooling_device *cdev, + bool bind) +{ + struct acpi_thermal_bind_data bd = { + .thermal = thermal, .cdev = cdev, .bind = bind + }; + + return for_each_thermal_trip(thermal, bind_unbind_cdev_cb, &bd); } static int acpi_thermal_bind_cooling_device(struct thermal_zone_device *thermal, struct thermal_cooling_device *cdev) { - return acpi_thermal_cooling_device_cb(thermal, cdev, true); + return acpi_thermal_bind_unbind_cdev(thermal, cdev, true); } static int acpi_thermal_unbind_cooling_device(struct thermal_zone_device *thermal, struct thermal_cooling_device *cdev) { - return acpi_thermal_cooling_device_cb(thermal, cdev, false); + return acpi_thermal_bind_unbind_cdev(thermal, cdev, false); } static struct thermal_zone_device_ops acpi_thermal_zone_ops = { @@ -679,66 +662,11 @@ static void acpi_thermal_zone_sysfs_remove(struct acpi_thermal *tz) sysfs_remove_link(&tzdev->kobj, "device"); } -static int acpi_thermal_register_thermal_zone(struct acpi_thermal *tz) +static int acpi_thermal_register_thermal_zone(struct acpi_thermal *tz, + unsigned int trip_count, + int passive_delay) { - struct acpi_thermal_trip *acpi_trip; - struct thermal_trip *trip; - int passive_delay = 0; - int trip_count = 0; int result; - int i; - - if (tz->trips.critical.valid) - trip_count++; - - if (tz->trips.hot.valid) - trip_count++; - - if (tz->trips.passive.trip.valid) { - trip_count++; - passive_delay = tz->trips.passive.tsp * 100; - } - - for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE && tz->trips.active[i].trip.valid; i++) - trip_count++; - - trip = kcalloc(trip_count, sizeof(*trip), GFP_KERNEL); - if (!trip) - return -ENOMEM; - - tz->trip_table = trip; - - if (tz->trips.critical.valid) { - trip->type = THERMAL_TRIP_CRITICAL; - trip->temperature = acpi_thermal_temp(tz, tz->trips.critical.temperature); - trip++; - } - - if (tz->trips.hot.valid) { - trip->type = THERMAL_TRIP_HOT; - trip->temperature = acpi_thermal_temp(tz, tz->trips.hot.temperature); - trip++; - } - - acpi_trip = &tz->trips.passive.trip; - if (acpi_trip->valid) { - trip->type = THERMAL_TRIP_PASSIVE; - trip->temperature = acpi_thermal_temp(tz, acpi_trip->temperature); - trip->priv = acpi_trip; - trip++; - } - - for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE; i++) { - acpi_trip = &tz->trips.active[i].trip; - - if (!acpi_trip->valid) - break; - - trip->type = THERMAL_TRIP_ACTIVE; - trip->temperature = acpi_thermal_temp(tz, acpi_trip->temperature); - trip->priv = acpi_trip; - trip++; - } tz->thermal_zone = thermal_zone_device_register_with_trips("acpitz", tz->trip_table, @@ -748,10 +676,8 @@ static int acpi_thermal_register_thermal_zone(struct acpi_thermal *tz) NULL, passive_delay, tz->polling_frequency * 100); - if (IS_ERR(tz->thermal_zone)) { - result = PTR_ERR(tz->thermal_zone); - goto free_trip_table; - } + if (IS_ERR(tz->thermal_zone)) + return PTR_ERR(tz->thermal_zone); result = acpi_thermal_zone_sysfs_add(tz); if (result) @@ -770,8 +696,6 @@ remove_links: acpi_thermal_zone_sysfs_remove(tz); unregister_tzd: thermal_zone_device_unregister(tz->thermal_zone); -free_trip_table: - kfree(tz->trip_table); return result; } @@ -844,38 +768,6 @@ static void acpi_thermal_aml_dependency_fix(struct acpi_thermal *tz) acpi_evaluate_integer(handle, "_TMP", NULL, &value); } -static int acpi_thermal_get_info(struct acpi_thermal *tz) -{ - int result; - - if (!tz) - return -EINVAL; - - acpi_thermal_aml_dependency_fix(tz); - - /* Get trip points [_CRT, _PSV, etc.] (required) */ - result = acpi_thermal_get_trip_points(tz); - if (result) - return result; - - /* Get temperature [_TMP] (required) */ - result = acpi_thermal_get_temperature(tz); - if (result) - return result; - - /* Set the cooling mode [_SCP] to active cooling (default) */ - acpi_execute_simple_method(tz->device->handle, "_SCP", - ACPI_THERMAL_MODE_ACTIVE); - - /* Get default polling frequency [_TZP] (optional) */ - if (tzp) - tz->polling_frequency = tzp; - else - acpi_thermal_get_polling_frequency(tz); - - return 0; -} - /* * The exact offset between Kelvin and degree Celsius is 273.15. However ACPI * handles temperature values with a single decimal place. As a consequence, @@ -886,10 +778,9 @@ static int acpi_thermal_get_info(struct acpi_thermal *tz) * The heuristic below should work for all ACPI thermal zones which have a * critical trip point with a value being a multiple of 0.5 degree Celsius. */ -static void acpi_thermal_guess_offset(struct acpi_thermal *tz) +static void acpi_thermal_guess_offset(struct acpi_thermal *tz, long crit_temp) { - if (tz->trips.critical.valid && - (tz->trips.critical.temperature % 5) == 1) + if (crit_temp != THERMAL_TEMP_INVALID && crit_temp % 5 == 1) tz->kelvin_offset = 273100; else tz->kelvin_offset = 273200; @@ -920,10 +811,27 @@ static void acpi_thermal_check_fn(struct work_struct *work) mutex_unlock(&tz->thermal_check_lock); } +static void acpi_thermal_free_thermal_zone(struct acpi_thermal *tz) +{ + int i; + + acpi_handle_list_free(&tz->trips.passive.trip.devices); + for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE; i++) + acpi_handle_list_free(&tz->trips.active[i].trip.devices); + + kfree(tz); +} + static int acpi_thermal_add(struct acpi_device *device) { + struct acpi_thermal_trip *acpi_trip; + struct thermal_trip *trip; struct acpi_thermal *tz; + unsigned int trip_count; + int crit_temp, hot_temp; + int passive_delay = 0; int result; + int i; if (!device) return -EINVAL; @@ -938,25 +846,97 @@ static int acpi_thermal_add(struct acpi_device *device) strcpy(acpi_device_class(device), ACPI_THERMAL_CLASS); device->driver_data = tz; - result = acpi_thermal_get_info(tz); + acpi_thermal_aml_dependency_fix(tz); + + /* Get trip points [_CRT, _PSV, etc.] (required). */ + trip_count = acpi_thermal_get_trip_points(tz); + + crit_temp = acpi_thermal_get_critical_trip(tz); + if (crit_temp != THERMAL_TEMP_INVALID) + trip_count++; + + hot_temp = acpi_thermal_get_hot_trip(tz); + if (hot_temp != THERMAL_TEMP_INVALID) + trip_count++; + + if (!trip_count) { + pr_warn(FW_BUG "No valid trip points!\n"); + result = -ENODEV; + goto free_memory; + } + + /* Get temperature [_TMP] (required). */ + result = acpi_thermal_get_temperature(tz); if (result) goto free_memory; - acpi_thermal_guess_offset(tz); + /* Set the cooling mode [_SCP] to active cooling. */ + acpi_execute_simple_method(tz->device->handle, "_SCP", + ACPI_THERMAL_MODE_ACTIVE); - result = acpi_thermal_register_thermal_zone(tz); - if (result) + /* Determine the default polling frequency [_TZP]. */ + if (tzp) + tz->polling_frequency = tzp; + else + acpi_thermal_get_polling_frequency(tz); + + acpi_thermal_guess_offset(tz, crit_temp); + + trip = kcalloc(trip_count, sizeof(*trip), GFP_KERNEL); + if (!trip) { + result = -ENOMEM; goto free_memory; + } + + tz->trip_table = trip; + + if (crit_temp != THERMAL_TEMP_INVALID) { + trip->type = THERMAL_TRIP_CRITICAL; + trip->temperature = acpi_thermal_temp(tz, crit_temp); + trip++; + } + + if (hot_temp != THERMAL_TEMP_INVALID) { + trip->type = THERMAL_TRIP_HOT; + trip->temperature = acpi_thermal_temp(tz, hot_temp); + trip++; + } + + acpi_trip = &tz->trips.passive.trip; + if (acpi_thermal_trip_valid(acpi_trip)) { + passive_delay = tz->trips.passive.tsp * 100; + + trip->type = THERMAL_TRIP_PASSIVE; + trip->temperature = acpi_thermal_temp(tz, acpi_trip->temp_dk); + trip->priv = acpi_trip; + trip++; + } + + for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE; i++) { + acpi_trip = &tz->trips.active[i].trip; + + if (!acpi_thermal_trip_valid(acpi_trip)) + break; + + trip->type = THERMAL_TRIP_ACTIVE; + trip->temperature = acpi_thermal_temp(tz, acpi_trip->temp_dk); + trip->priv = acpi_trip; + trip++; + } + + result = acpi_thermal_register_thermal_zone(tz, trip_count, passive_delay); + if (result) + goto free_trips; refcount_set(&tz->thermal_check_count, 3); mutex_init(&tz->thermal_check_lock); INIT_WORK(&tz->thermal_check_work, acpi_thermal_check_fn); pr_info("%s [%s] (%ld C)\n", acpi_device_name(device), - acpi_device_bid(device), deci_kelvin_to_celsius(tz->temperature)); + acpi_device_bid(device), deci_kelvin_to_celsius(tz->temp_dk)); result = acpi_dev_install_notify_handler(device, ACPI_DEVICE_NOTIFY, - acpi_thermal_notify); + acpi_thermal_notify, device); if (result) goto flush_wq; @@ -965,8 +945,10 @@ static int acpi_thermal_add(struct acpi_device *device) flush_wq: flush_workqueue(acpi_thermal_pm_queue); acpi_thermal_unregister_thermal_zone(tz); +free_trips: + kfree(tz->trip_table); free_memory: - kfree(tz); + acpi_thermal_free_thermal_zone(tz); return result; } @@ -986,7 +968,7 @@ static void acpi_thermal_remove(struct acpi_device *device) flush_workqueue(acpi_thermal_pm_queue); acpi_thermal_unregister_thermal_zone(tz); - kfree(tz); + acpi_thermal_free_thermal_zone(tz); } #ifdef CONFIG_PM_SLEEP @@ -1010,11 +992,13 @@ static int acpi_thermal_resume(struct device *dev) return -EINVAL; for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE; i++) { - if (!tz->trips.active[i].trip.valid) + struct acpi_thermal_trip *acpi_trip = &tz->trips.active[i].trip; + + if (!acpi_thermal_trip_valid(acpi_trip)) break; - for (j = 0; j < tz->trips.active[i].devices.count; j++) { - acpi_bus_update_power(tz->trips.active[i].devices.handles[j], + for (j = 0; j < acpi_trip->devices.count; j++) { + acpi_bus_update_power(acpi_trip->devices.handles[j], &power_state); } } @@ -1046,7 +1030,8 @@ static struct acpi_driver acpi_thermal_driver = { .drv.pm = &acpi_thermal_pm, }; -static int thermal_act(const struct dmi_system_id *d) { +static int thermal_act(const struct dmi_system_id *d) +{ if (act == 0) { pr_notice("%s detected: disabling all active thermal trip points\n", d->ident); @@ -1054,13 +1039,17 @@ static int thermal_act(const struct dmi_system_id *d) { } return 0; } -static int thermal_nocrt(const struct dmi_system_id *d) { + +static int thermal_nocrt(const struct dmi_system_id *d) +{ pr_notice("%s detected: disabling all critical thermal trip point actions.\n", d->ident); crt = -1; return 0; } -static int thermal_tzp(const struct dmi_system_id *d) { + +static int thermal_tzp(const struct dmi_system_id *d) +{ if (tzp == 0) { pr_notice("%s detected: enabling thermal zone polling\n", d->ident); @@ -1068,7 +1057,9 @@ static int thermal_tzp(const struct dmi_system_id *d) { } return 0; } -static int thermal_psv(const struct dmi_system_id *d) { + +static int thermal_psv(const struct dmi_system_id *d) +{ if (psv == 0) { pr_notice("%s detected: disabling all passive thermal trip points\n", d->ident); diff --git a/drivers/acpi/utils.c b/drivers/acpi/utils.c index 2ea14648a661..28c75242fca9 100644 --- a/drivers/acpi/utils.c +++ b/drivers/acpi/utils.c @@ -342,9 +342,8 @@ acpi_evaluate_reference(acpi_handle handle, u32 i = 0; - if (!list) { + if (!list) return AE_BAD_PARAMETER; - } /* Evaluate object. */ @@ -370,7 +369,8 @@ acpi_evaluate_reference(acpi_handle handle, goto end; } - if (package->package.count > ACPI_MAX_HANDLES) { + list->handles = kcalloc(package->package.count, sizeof(*list->handles), GFP_KERNEL); + if (!list->handles) { kfree(package); return AE_NO_MEMORY; } @@ -399,10 +399,11 @@ acpi_evaluate_reference(acpi_handle handle, acpi_handle_debug(list->handles[i], "Found in reference list\n"); } - end: +end: if (ACPI_FAILURE(status)) { list->count = 0; - //kfree(list->handles); + kfree(list->handles); + list->handles = NULL; } kfree(buffer.pointer); @@ -412,6 +413,61 @@ acpi_evaluate_reference(acpi_handle handle, EXPORT_SYMBOL(acpi_evaluate_reference); +/** + * acpi_handle_list_equal - Check if two ACPI handle lists are the same + * @list1: First list to compare. + * @list2: Second list to compare. + * + * Return true if the given ACPI handle lists are of the same size and + * contain the same ACPI handles in the same order. Otherwise, return false. + */ +bool acpi_handle_list_equal(struct acpi_handle_list *list1, + struct acpi_handle_list *list2) +{ + return list1->count == list2->count && + !memcmp(list1->handles, list2->handles, + list1->count * sizeof(acpi_handle)); +} +EXPORT_SYMBOL_GPL(acpi_handle_list_equal); + +/** + * acpi_handle_list_replace - Replace one ACPI handle list with another + * @dst: ACPI handle list to replace. + * @src: Source ACPI handle list. + * + * Free the handles table in @dst, move the handles table from @src to @dst, + * copy count from @src to @dst and clear @src. + */ +void acpi_handle_list_replace(struct acpi_handle_list *dst, + struct acpi_handle_list *src) +{ + if (dst->count) + kfree(dst->handles); + + dst->count = src->count; + dst->handles = src->handles; + + src->handles = NULL; + src->count = 0; +} +EXPORT_SYMBOL_GPL(acpi_handle_list_replace); + +/** + * acpi_handle_list_free - Free the handles table in an ACPI handle list + * @list: ACPI handle list to free. + * + * Free the handles table in @list and clear its count field. + */ +void acpi_handle_list_free(struct acpi_handle_list *list) +{ + if (!list->count) + return; + + kfree(list->handles); + list->count = 0; +} +EXPORT_SYMBOL_GPL(acpi_handle_list_free); + acpi_status acpi_get_physical_device_location(acpi_handle handle, struct acpi_pld_info **pld) { @@ -523,7 +579,7 @@ acpi_handle_printk(const char *level, acpi_handle handle, const char *fmt, ...) vaf.va = &args; path = acpi_handle_path(handle); - printk("%sACPI: %s: %pV", level, path ? path : "<n/a>" , &vaf); + printk("%sACPI: %s: %pV", level, path ? path : "<n/a>", &vaf); va_end(args); kfree(path); @@ -769,19 +825,42 @@ bool acpi_check_dsm(acpi_handle handle, const guid_t *guid, u64 rev, u64 funcs) EXPORT_SYMBOL(acpi_check_dsm); /** + * acpi_dev_uid_match - Match device by supplied UID + * @adev: ACPI device to match. + * @uid2: Unique ID of the device. + * + * Matches UID in @adev with given @uid2. + * + * Returns: + * - %true if matches. + * - %false otherwise. + */ +bool acpi_dev_uid_match(struct acpi_device *adev, const char *uid2) +{ + const char *uid1 = acpi_device_uid(adev); + + return uid1 && uid2 && !strcmp(uid1, uid2); +} +EXPORT_SYMBOL_GPL(acpi_dev_uid_match); + +/** * acpi_dev_hid_uid_match - Match device by supplied HID and UID * @adev: ACPI device to match. * @hid2: Hardware ID of the device. * @uid2: Unique ID of the device, pass NULL to not check _UID. * - * Matches HID and UID in @adev with given @hid2 and @uid2. - * Returns true if matches. + * Matches HID and UID in @adev with given @hid2 and @uid2. Absence of @uid2 + * will be treated as a match. If user wants to validate @uid2, it should be + * done before calling this function. + * + * Returns: + * - %true if matches or @uid2 is NULL. + * - %false otherwise. */ bool acpi_dev_hid_uid_match(struct acpi_device *adev, const char *hid2, const char *uid2) { const char *hid1 = acpi_device_hid(adev); - const char *uid1 = acpi_device_uid(adev); if (strcmp(hid1, hid2)) return false; @@ -789,7 +868,7 @@ bool acpi_dev_hid_uid_match(struct acpi_device *adev, if (!uid2) return true; - return uid1 && !strcmp(uid1, uid2); + return acpi_dev_uid_match(adev, uid2); } EXPORT_SYMBOL(acpi_dev_hid_uid_match); @@ -863,8 +942,7 @@ static int acpi_dev_match_cb(struct device *dev, const void *data) if (acpi_match_device_ids(adev, match->hid)) return 0; - if (match->uid && (!adev->pnp.unique_id || - strcmp(adev->pnp.unique_id, match->uid))) + if (match->uid && !acpi_dev_uid_match(adev, match->uid)) return 0; if (match->hrv == -1) diff --git a/drivers/acpi/video_detect.c b/drivers/acpi/video_detect.c index 442396f6ed1f..9fdcc620c652 100644 --- a/drivers/acpi/video_detect.c +++ b/drivers/acpi/video_detect.c @@ -130,6 +130,16 @@ static int video_detect_force_native(const struct dmi_system_id *d) return 0; } +static int video_detect_portege_r100(const struct dmi_system_id *d) +{ + struct pci_dev *dev; + /* Search for Trident CyberBlade XP4m32 to confirm Portégé R100 */ + dev = pci_get_device(PCI_VENDOR_ID_TRIDENT, 0x2100, NULL); + if (dev) + acpi_backlight_dmi = acpi_backlight_vendor; + return 0; +} + static const struct dmi_system_id video_detect_dmi_table[] = { /* * Models which should use the vendor backlight interface, @@ -229,14 +239,6 @@ static const struct dmi_system_id video_detect_dmi_table[] = { DMI_MATCH(DMI_BOARD_NAME, "NC210/NC110"), }, }, - { - .callback = video_detect_force_vendor, - /* Xiaomi Mi Pad 2 */ - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Xiaomi Inc"), - DMI_MATCH(DMI_PRODUCT_NAME, "Mipad2"), - }, - }, /* * Models which should use the vendor backlight interface, @@ -271,6 +273,22 @@ static const struct dmi_system_id video_detect_dmi_table[] = { }, /* + * Toshiba Portégé R100 has working both acpi_video and toshiba_acpi + * vendor driver. But none of them gets activated as it has a VGA with + * no kernel driver (Trident CyberBlade XP4m32). + * The DMI strings are generic so check for the VGA chip in callback. + */ + { + .callback = video_detect_portege_r100, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), + DMI_MATCH(DMI_PRODUCT_NAME, "Portable PC"), + DMI_MATCH(DMI_PRODUCT_VERSION, "Version 1.0"), + DMI_MATCH(DMI_BOARD_NAME, "Portable PC") + }, + }, + + /* * Models which need acpi_video backlight control where the GPU drivers * do not call acpi_video_register_backlight() because no internal panel * is detected. Typically these are all-in-ones (monitors with builtin @@ -799,6 +817,56 @@ static const struct dmi_system_id video_detect_dmi_table[] = { DMI_MATCH(DMI_PRODUCT_NAME, "Vostro 15 3535"), }, }, + + /* + * x86 android tablets which directly control the backlight through + * an external backlight controller, typically TI's LP8557. + * The backlight is directly controlled by the lp855x driver on these. + * This setup means that neither i915's native nor acpi_video backlight + * control works. Add a "vendor" quirk to disable both. Note these + * devices do not use vendor control in the typical meaning of + * vendor specific SMBIOS or ACPI calls being used. + */ + { + .callback = video_detect_force_vendor, + /* Lenovo Yoga Book X90F / X90L */ + .matches = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Intel Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "CHERRYVIEW D1 PLATFORM"), + DMI_EXACT_MATCH(DMI_PRODUCT_VERSION, "YETI-11"), + }, + }, + { + .callback = video_detect_force_vendor, + /* + * Lenovo Yoga Tablet 2 830F/L or 1050F/L (The 8" and 10" + * Lenovo Yoga Tablet 2 use the same mainboard) + */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Intel Corp."), + DMI_MATCH(DMI_PRODUCT_NAME, "VALLEYVIEW C0 PLATFORM"), + DMI_MATCH(DMI_BOARD_NAME, "BYT-T FFD8"), + /* Partial match on beginning of BIOS version */ + DMI_MATCH(DMI_BIOS_VERSION, "BLADE_21"), + }, + }, + { + .callback = video_detect_force_vendor, + /* Lenovo Yoga Tab 3 Pro YT3-X90F */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"), + DMI_MATCH(DMI_PRODUCT_NAME, "CHERRYVIEW D1 PLATFORM"), + DMI_MATCH(DMI_PRODUCT_VERSION, "Blade3-10A-001"), + }, + }, + { + .callback = video_detect_force_vendor, + /* Xiaomi Mi Pad 2 */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Xiaomi Inc"), + DMI_MATCH(DMI_PRODUCT_NAME, "Mipad2"), + }, + }, { }, }; diff --git a/drivers/acpi/x86/s2idle.c b/drivers/acpi/x86/s2idle.c index 08f7c6708206..7d64e655f1b8 100644 --- a/drivers/acpi/x86/s2idle.c +++ b/drivers/acpi/x86/s2idle.c @@ -417,11 +417,10 @@ static int validate_dsm(acpi_handle handle, const char *uuid, int rev, guid_t *d int ret = -EINVAL; guid_parse(uuid, dsm_guid); - obj = acpi_evaluate_dsm(handle, dsm_guid, rev, 0, NULL); /* Check if the _DSM is present and as expected. */ - if (!obj || obj->type != ACPI_TYPE_BUFFER || obj->buffer.length == 0 || - obj->buffer.length > sizeof(u32)) { + obj = acpi_evaluate_dsm_typed(handle, dsm_guid, rev, 0, NULL, ACPI_TYPE_BUFFER); + if (!obj || obj->buffer.length == 0 || obj->buffer.length > sizeof(u32)) { acpi_handle_debug(handle, "_DSM UUID %s rev %d function 0 evaluation failed\n", uuid, rev); goto out; diff --git a/drivers/acpi/x86/utils.c b/drivers/acpi/x86/utils.c index 63d834dd3811..bc65ebfcdf76 100644 --- a/drivers/acpi/x86/utils.c +++ b/drivers/acpi/x86/utils.c @@ -184,8 +184,7 @@ bool acpi_device_override_status(struct acpi_device *adev, unsigned long long *s if (acpi_match_device_ids(adev, override_status_ids[i].hid)) continue; - if (!adev->pnp.unique_id || - strcmp(adev->pnp.unique_id, override_status_ids[i].uid)) + if (!acpi_dev_uid_match(adev, override_status_ids[i].uid)) continue; } |