diff options
Diffstat (limited to 'drivers/acpi')
32 files changed, 1018 insertions, 918 deletions
diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig index cee82b473d..f819e760ff 100644 --- a/drivers/acpi/Kconfig +++ b/drivers/acpi/Kconfig @@ -12,6 +12,7 @@ menuconfig ACPI select PNP select NLS select CRC32 + select FIRMWARE_TABLE default y if X86 help Advanced Configuration and Power Interface (ACPI) support for @@ -257,7 +258,7 @@ config ACPI_CPU_FREQ_PSS config ACPI_PROCESSOR_CSTATE def_bool y depends on ACPI_PROCESSOR - depends on IA64 || X86 + depends on X86 config ACPI_PROCESSOR_IDLE bool @@ -281,9 +282,9 @@ config ACPI_CPPC_LIB config ACPI_PROCESSOR tristate "Processor" - depends on X86 || IA64 || ARM64 || LOONGARCH + depends on X86 || ARM64 || LOONGARCH select ACPI_PROCESSOR_IDLE - select ACPI_CPU_FREQ_PSS if X86 || IA64 || LOONGARCH + select ACPI_CPU_FREQ_PSS if X86 || LOONGARCH select THERMAL default y help diff --git a/drivers/acpi/ac.c b/drivers/acpi/ac.c index 225dc68187..2d4a35e6dd 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_extlog.c b/drivers/acpi/acpi_extlog.c index 71e8d4e7a3..ca87a09391 100644 --- a/drivers/acpi/acpi_extlog.c +++ b/drivers/acpi/acpi_extlog.c @@ -308,9 +308,10 @@ err: static void __exit extlog_exit(void) { mce_unregister_decode_chain(&extlog_mce_dec); - ((struct extlog_l1_head *)extlog_l1_addr)->flags &= ~FLAG_OS_OPTIN; - if (extlog_l1_addr) + if (extlog_l1_addr) { + ((struct extlog_l1_head *)extlog_l1_addr)->flags &= ~FLAG_OS_OPTIN; acpi_os_unmap_iomem(extlog_l1_addr, l1_size); + } if (elog_addr) acpi_os_unmap_iomem(elog_addr, elog_size); release_mem_region(elog_base, elog_size); diff --git a/drivers/acpi/acpi_lpss.c b/drivers/acpi/acpi_lpss.c index a052e0ab19..d48407472d 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) }, @@ -579,6 +575,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")) @@ -592,11 +589,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, @@ -658,10 +658,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 7a453c5ff3..bd1ad07f02 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> @@ -100,7 +101,7 @@ static void round_robin_cpu(unsigned int tsk_index) for_each_cpu(cpu, pad_busy_cpus) cpumask_or(tmp, tmp, topology_sibling_cpumask(cpu)); cpumask_andnot(tmp, cpu_online_mask, tmp); - /* avoid HT sibilings if possible */ + /* avoid HT siblings if possible */ if (cpumask_empty(tmp)) cpumask_andnot(tmp, cpu_online_mask, pad_busy_cpus); if (cpumask_empty(tmp)) { @@ -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_video.c b/drivers/acpi/acpi_video.c index 27a6ae89f1..33ddb44774 100644 --- a/drivers/acpi/acpi_video.c +++ b/drivers/acpi/acpi_video.c @@ -500,6 +500,15 @@ static const struct dmi_system_id video_dmi_table[] = { DMI_MATCH(DMI_PRODUCT_NAME, "Vostro 3350"), }, }, + { + .callback = video_set_report_key_events, + .driver_data = (void *)((uintptr_t)REPORT_BRIGHTNESS_KEY_EVENTS), + .ident = "COLORFUL X15 AT 23", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "COLORFUL"), + DMI_MATCH(DMI_PRODUCT_NAME, "X15 AT 23"), + }, + }, /* * Some machines change the brightness themselves when a brightness * hotkey gets pressed, despite us telling them not to. In this case @@ -2058,7 +2067,7 @@ static int acpi_video_bus_add(struct acpi_device *device) 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; diff --git a/drivers/acpi/apei/erst.c b/drivers/acpi/apei/erst.c index 247989060e..bf65e34615 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 63ad0541db..ab2a82cb1b 100644 --- a/drivers/acpi/apei/ghes.c +++ b/drivers/acpi/apei/ghes.c @@ -102,6 +102,20 @@ static inline bool is_hest_type_generic_v2(struct ghes *ghes) } /* + * A platform may describe one error source for the handling of synchronous + * errors (e.g. MCE or SEA), or for handling asynchronous errors (e.g. SCI + * or External Interrupt). On x86, the HEST notifications are always + * asynchronous, so only SEA on ARM is delivered as a synchronous + * notification. + */ +static inline bool is_hest_sync_notify(struct ghes *ghes) +{ + u8 notify_type = ghes->generic->notify.type; + + return notify_type == ACPI_HEST_NOTIFY_SEA; +} + +/* * This driver isn't really modular, however for the time being, * continuing to use module_param is the easiest way to remain * compatible with existing boot arg use cases. @@ -489,7 +503,7 @@ static bool ghes_do_memory_failure(u64 physical_addr, int flags) } static bool ghes_handle_memory_failure(struct acpi_hest_generic_data *gdata, - int sev) + int sev, bool sync) { int flags = -1; int sec_sev = ghes_severity(gdata->error_severity); @@ -503,7 +517,7 @@ static bool ghes_handle_memory_failure(struct acpi_hest_generic_data *gdata, (gdata->flags & CPER_SEC_ERROR_THRESHOLD_EXCEEDED)) flags = MF_SOFT_OFFLINE; if (sev == GHES_SEV_RECOVERABLE && sec_sev == GHES_SEV_RECOVERABLE) - flags = 0; + flags = sync ? MF_ACTION_REQUIRED : 0; if (flags != -1) return ghes_do_memory_failure(mem_err->physical_addr, flags); @@ -511,9 +525,11 @@ static bool ghes_handle_memory_failure(struct acpi_hest_generic_data *gdata, return false; } -static bool ghes_handle_arm_hw_error(struct acpi_hest_generic_data *gdata, int sev) +static bool ghes_handle_arm_hw_error(struct acpi_hest_generic_data *gdata, + int sev, bool sync) { struct cper_sec_proc_arm *err = acpi_hest_get_payload(gdata); + int flags = sync ? MF_ACTION_REQUIRED : 0; bool queued = false; int sec_sev, i; char *p; @@ -538,7 +554,7 @@ static bool ghes_handle_arm_hw_error(struct acpi_hest_generic_data *gdata, int s * and don't filter out 'corrected' error here. */ if (is_cache && has_pa) { - queued = ghes_do_memory_failure(err_info->physical_fault_addr, 0); + queued = ghes_do_memory_failure(err_info->physical_fault_addr, flags); p += err_info->length; continue; } @@ -666,6 +682,7 @@ static bool ghes_do_proc(struct ghes *ghes, const guid_t *fru_id = &guid_null; char *fru_text = ""; bool queued = false; + bool sync = is_hest_sync_notify(ghes); sev = ghes_severity(estatus->error_severity); apei_estatus_for_each_section(estatus, gdata) { @@ -683,13 +700,13 @@ static bool ghes_do_proc(struct ghes *ghes, atomic_notifier_call_chain(&ghes_report_chain, sev, mem_err); arch_apei_report_mem_error(sev, mem_err); - queued = ghes_handle_memory_failure(gdata, sev); + queued = ghes_handle_memory_failure(gdata, sev, sync); } else if (guid_equal(sec_type, &CPER_SEC_PCIE)) { ghes_handle_aer(gdata); } else if (guid_equal(sec_type, &CPER_SEC_PROC_ARM)) { - queued = ghes_handle_arm_hw_error(gdata, sev); + queued = ghes_handle_arm_hw_error(gdata, sev, sync); } else { void *err = acpi_hest_get_payload(gdata); diff --git a/drivers/acpi/arm64/amba.c b/drivers/acpi/arm64/amba.c index 60be8ee1db..171b5c2c7e 100644 --- a/drivers/acpi/arm64/amba.c +++ b/drivers/acpi/arm64/amba.c @@ -101,7 +101,7 @@ static int amba_handler_attach(struct acpi_device *adev, if (parent) dev->dev.parent = acpi_get_first_physical_node(parent); - ACPI_COMPANION_SET(&dev->dev, adev); + device_set_node(&dev->dev, acpi_fwnode_handle(adev)); ret = amba_device_add(dev, &iomem_resource); if (ret) { diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c index 969bf81e8d..b379401ff1 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 a4aa53b7e2..72e64c0718 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; diff --git a/drivers/acpi/device_sysfs.c b/drivers/acpi/device_sysfs.c index a34d8578b3..23373faa35 100644 --- a/drivers/acpi/device_sysfs.c +++ b/drivers/acpi/device_sysfs.c @@ -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; } @@ -228,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; @@ -237,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; } @@ -412,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); @@ -556,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")) { @@ -637,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/hed.c b/drivers/acpi/hed.c index 46c6f8c35b..7652515a6b 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/nfit/core.c b/drivers/acpi/nfit/core.c index 7d88db451c..9923855377 100644 --- a/drivers/acpi/nfit/core.c +++ b/drivers/acpi/nfit/core.c @@ -3340,7 +3340,7 @@ static int acpi_nfit_add(struct acpi_device *adev) int rc = 0; rc = acpi_dev_install_notify_handler(adev, ACPI_DEVICE_NOTIFY, - acpi_nfit_notify); + acpi_nfit_notify, adev); if (rc) return rc; diff --git a/drivers/acpi/numa/Kconfig b/drivers/acpi/numa/Kconfig index 39b1f34c21..849c2bd820 100644 --- a/drivers/acpi/numa/Kconfig +++ b/drivers/acpi/numa/Kconfig @@ -2,8 +2,8 @@ config ACPI_NUMA bool "NUMA support" depends on NUMA - depends on (X86 || IA64 || ARM64 || LOONGARCH) - default y if IA64 || ARM64 + depends on (X86 || ARM64 || LOONGARCH) + default y if ARM64 config ACPI_HMAT bool "ACPI Heterogeneous Memory Attribute Table Support" diff --git a/drivers/acpi/numa/hmat.c b/drivers/acpi/numa/hmat.c index bba268ecd8..9ef5f1bdcf 100644 --- a/drivers/acpi/numa/hmat.c +++ b/drivers/acpi/numa/hmat.c @@ -24,6 +24,7 @@ #include <linux/node.h> #include <linux/sysfs.h> #include <linux/dax.h> +#include <linux/memory-tiers.h> static u8 hmat_revision; static int hmat_disable __initdata; @@ -582,28 +583,25 @@ static int initiators_to_nodemask(unsigned long *p_nodes) return 0; } -static void hmat_register_target_initiators(struct memory_target *target) +static void hmat_update_target_attrs(struct memory_target *target, + unsigned long *p_nodes, int access) { - static DECLARE_BITMAP(p_nodes, MAX_NUMNODES); struct memory_initiator *initiator; - unsigned int mem_nid, cpu_nid; + unsigned int cpu_nid; struct memory_locality *loc = NULL; u32 best = 0; - bool access0done = false; int i; - mem_nid = pxm_to_node(target->memory_pxm); + bitmap_zero(p_nodes, MAX_NUMNODES); /* - * If the Address Range Structure provides a local processor pxm, link + * If the Address Range Structure provides a local processor pxm, set * only that one. Otherwise, find the best performance attributes and - * register all initiators that match. + * collect all initiators that match. */ if (target->processor_pxm != PXM_INVAL) { cpu_nid = pxm_to_node(target->processor_pxm); - register_memory_node_under_compute_node(mem_nid, cpu_nid, 0); - access0done = true; - if (node_state(cpu_nid, N_CPU)) { - register_memory_node_under_compute_node(mem_nid, cpu_nid, 1); + if (access == 0 || node_state(cpu_nid, N_CPU)) { + set_bit(target->processor_pxm, p_nodes); return; } } @@ -617,47 +615,10 @@ static void hmat_register_target_initiators(struct memory_target *target) * We'll also use the sorting to prime the candidate nodes with known * initiators. */ - bitmap_zero(p_nodes, MAX_NUMNODES); list_sort(NULL, &initiators, initiator_cmp); if (initiators_to_nodemask(p_nodes) < 0) return; - if (!access0done) { - for (i = WRITE_LATENCY; i <= READ_BANDWIDTH; i++) { - loc = localities_types[i]; - if (!loc) - continue; - - best = 0; - list_for_each_entry(initiator, &initiators, node) { - u32 value; - - if (!test_bit(initiator->processor_pxm, p_nodes)) - continue; - - value = hmat_initiator_perf(target, initiator, - loc->hmat_loc); - if (hmat_update_best(loc->hmat_loc->data_type, value, &best)) - bitmap_clear(p_nodes, 0, initiator->processor_pxm); - if (value != best) - clear_bit(initiator->processor_pxm, p_nodes); - } - if (best) - hmat_update_target_access(target, loc->hmat_loc->data_type, - best, 0); - } - - for_each_set_bit(i, p_nodes, MAX_NUMNODES) { - cpu_nid = pxm_to_node(i); - register_memory_node_under_compute_node(mem_nid, cpu_nid, 0); - } - } - - /* Access 1 ignores Generic Initiators */ - bitmap_zero(p_nodes, MAX_NUMNODES); - if (initiators_to_nodemask(p_nodes) < 0) - return; - for (i = WRITE_LATENCY; i <= READ_BANDWIDTH; i++) { loc = localities_types[i]; if (!loc) @@ -667,7 +628,7 @@ static void hmat_register_target_initiators(struct memory_target *target) list_for_each_entry(initiator, &initiators, node) { u32 value; - if (!initiator->has_cpu) { + if (access == 1 && !initiator->has_cpu) { clear_bit(initiator->processor_pxm, p_nodes); continue; } @@ -681,14 +642,33 @@ static void hmat_register_target_initiators(struct memory_target *target) clear_bit(initiator->processor_pxm, p_nodes); } if (best) - hmat_update_target_access(target, loc->hmat_loc->data_type, best, 1); + hmat_update_target_access(target, loc->hmat_loc->data_type, best, access); } +} + +static void __hmat_register_target_initiators(struct memory_target *target, + unsigned long *p_nodes, + int access) +{ + unsigned int mem_nid, cpu_nid; + int i; + + mem_nid = pxm_to_node(target->memory_pxm); + hmat_update_target_attrs(target, p_nodes, access); for_each_set_bit(i, p_nodes, MAX_NUMNODES) { cpu_nid = pxm_to_node(i); - register_memory_node_under_compute_node(mem_nid, cpu_nid, 1); + register_memory_node_under_compute_node(mem_nid, cpu_nid, access); } } +static void hmat_register_target_initiators(struct memory_target *target) +{ + static DECLARE_BITMAP(p_nodes, MAX_NUMNODES); + + __hmat_register_target_initiators(target, p_nodes, 0); + __hmat_register_target_initiators(target, p_nodes, 1); +} + static void hmat_register_target_cache(struct memory_target *target) { unsigned mem_nid = pxm_to_node(target->memory_pxm); @@ -780,6 +760,61 @@ static int hmat_callback(struct notifier_block *self, return NOTIFY_OK; } +static int hmat_set_default_dram_perf(void) +{ + int rc; + int nid, pxm; + struct memory_target *target; + struct node_hmem_attrs *attrs; + + if (!default_dram_type) + return -EIO; + + for_each_node_mask(nid, default_dram_type->nodes) { + pxm = node_to_pxm(nid); + target = find_mem_target(pxm); + if (!target) + continue; + attrs = &target->hmem_attrs[1]; + rc = mt_set_default_dram_perf(nid, attrs, "ACPI HMAT"); + if (rc) + return rc; + } + + return 0; +} + +static int hmat_calculate_adistance(struct notifier_block *self, + unsigned long nid, void *data) +{ + static DECLARE_BITMAP(p_nodes, MAX_NUMNODES); + struct memory_target *target; + struct node_hmem_attrs *perf; + int *adist = data; + int pxm; + + pxm = node_to_pxm(nid); + target = find_mem_target(pxm); + if (!target) + return NOTIFY_OK; + + mutex_lock(&target_lock); + hmat_update_target_attrs(target, p_nodes, 1); + mutex_unlock(&target_lock); + + perf = &target->hmem_attrs[1]; + + if (mt_perf_to_adistance(perf, adist)) + return NOTIFY_OK; + + return NOTIFY_STOP; +} + +static struct notifier_block hmat_adist_nb __meminitdata = { + .notifier_call = hmat_calculate_adistance, + .priority = 100, +}; + static __init void hmat_free_structures(void) { struct memory_target *target, *tnext; @@ -862,8 +897,13 @@ static __init int hmat_init(void) hmat_register_targets(); /* Keep the table and structures if the notifier may use them */ - if (!hotplug_memory_notifier(hmat_callback, HMAT_CALLBACK_PRI)) - return 0; + if (hotplug_memory_notifier(hmat_callback, HMAT_CALLBACK_PRI)) + goto out_put; + + if (!hmat_set_default_dram_perf()) + register_mt_adistance_algorithm(&hmat_adist_nb); + + return 0; out_put: hmat_free_structures(); acpi_put_table(tbl); diff --git a/drivers/acpi/numa/srat.c b/drivers/acpi/numa/srat.c index 12f330b0ea..b57de78fbf 100644 --- a/drivers/acpi/numa/srat.c +++ b/drivers/acpi/numa/srat.c @@ -183,7 +183,7 @@ static int __init slit_valid(struct acpi_table_slit *slit) int i, j; int d = slit->locality_count; for (i = 0; i < d; i++) { - for (j = 0; j < d; j++) { + for (j = 0; j < d; j++) { u8 val = slit->entry[d*i + j]; if (i == j) { if (val != LOCAL_DISTANCE) @@ -532,7 +532,7 @@ int __init acpi_numa_init(void) */ /* fake_pxm is the next unused PXM value after SRAT parsing */ - for (i = 0, fake_pxm = -1; i < MAX_NUMNODES - 1; i++) { + for (i = 0, fake_pxm = -1; i < MAX_NUMNODES; i++) { if (node_to_pxm_map[i] > fake_pxm) fake_pxm = node_to_pxm_map[i]; } diff --git a/drivers/acpi/osi.c b/drivers/acpi/osi.c index d4405e1ca9..df9328c850 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 f725813d0c..c09cc3c686 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]; @@ -276,7 +276,7 @@ acpi_map_lookup_virt(void __iomem *virt, acpi_size size) return NULL; } -#if defined(CONFIG_IA64) || defined(CONFIG_ARM64) || defined(CONFIG_RISCV) +#if defined(CONFIG_ARM64) || defined(CONFIG_RISCV) /* ioremap will take care of cache attributes */ #define should_use_kmap(pfn) 0 #else @@ -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 84030804a7..58b89b8d95 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 7020584096..c78453c74e 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_core.c b/drivers/acpi/processor_core.c index 7dd6dbaa98..b203cfe285 100644 --- a/drivers/acpi/processor_core.c +++ b/drivers/acpi/processor_core.c @@ -90,7 +90,7 @@ static int map_gicc_mpidr(struct acpi_subtable_header *entry, struct acpi_madt_generic_interrupt *gicc = container_of(entry, struct acpi_madt_generic_interrupt, header); - if (!(gicc->flags & ACPI_MADT_ENABLED)) + if (!acpi_gicc_is_usable(gicc)) return -ENODEV; /* device_declaration means Device object in DSDT, in the diff --git a/drivers/acpi/property.c b/drivers/acpi/property.c index 4d958a165d..4d042673d5 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); diff --git a/drivers/acpi/resource.c b/drivers/acpi/resource.c index 85ae394e79..03b52d31a3 100644 --- a/drivers/acpi/resource.c +++ b/drivers/acpi/resource.c @@ -385,62 +385,63 @@ 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 B1402CBA", + /* Asus ExpertBook B1402CBA */ .matches = { DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), DMI_MATCH(DMI_BOARD_NAME, "B1402CBA"), @@ -454,53 +455,75 @@ static const struct dmi_system_id asus_laptop[] = { }, }, { - .ident = "Asus ExpertBook B1502CBA", + /* Asus ExpertBook B1502CBA */ .matches = { DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), DMI_MATCH(DMI_BOARD_NAME, "B1502CBA"), }, }, { - .ident = "Asus ExpertBook B2402CBA", + /* Asus ExpertBook B1502CGA */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), + DMI_MATCH(DMI_BOARD_NAME, "B1502CGA"), + }, + }, + { + /* 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"), }, }, - { } -}; - -static const struct dmi_system_id tongfang_gm_rg[] = { { - .ident = "TongFang GMxRGxx/XMG CORE 15 (M22)/TUXEDO Stellaris 15 Gen4 AMD", + /* Asus Vivobook E1504GA */ .matches = { - DMI_MATCH(DMI_BOARD_NAME, "GMxRGxx"), + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), + DMI_MATCH(DMI_BOARD_NAME, "E1504GA"), + }, + }, + { + /* Asus Vivobook E1504GAB */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), + DMI_MATCH(DMI_BOARD_NAME, "E1504GAB"), + }, + }, + { + /* LG Electronics 17U70P */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LG Electronics"), + DMI_MATCH(DMI_BOARD_NAME, "17U70P"), }, }, { } }; -static const struct dmi_system_id maingear_laptop[] = { +/* + * 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 = "MAINGEAR Vector Pro 2 15", + /* TongFang GMxRGxx/XMG CORE 15 (M22)/TUXEDO Stellaris 15 Gen4 AMD */ .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Micro Electronics Inc"), - DMI_MATCH(DMI_PRODUCT_NAME, "MG-VCP2-15A3070T"), - } + DMI_MATCH(DMI_BOARD_NAME, "GMxRGxx"), + }, }, { /* TongFang GMxXGxx/TUXEDO Polaris 15 Gen5 AMD */ @@ -522,16 +545,19 @@ static const struct dmi_system_id maingear_laptop[] = { }, }, { - .ident = "MAINGEAR Vector Pro 2 17", + /* MAINGEAR Vector Pro 2 15 */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Micro Electronics Inc"), + DMI_MATCH(DMI_PRODUCT_NAME, "MG-VCP2-15A3070T"), + } + }, + { + /* 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[] = { { /* TongFang GM6BGEQ / PCSpecialist Elimina Pro 16 M, RTX 3050 */ .matches = { @@ -553,17 +579,6 @@ static const struct dmi_system_id pcspecialist_laptop[] = { { } }; -static const struct dmi_system_id lg_laptop[] = { - { - .ident = "LG Electronics 17U70P", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "LG Electronics"), - DMI_MATCH(DMI_BOARD_NAME, "17U70P"), - }, - }, - { } -}; - struct irq_override_cmp { const struct dmi_system_id *system; unsigned char irq; @@ -574,12 +589,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/riscv/rhct.c b/drivers/acpi/riscv/rhct.c index b280b3e9c7..caa2c16e16 100644 --- a/drivers/acpi/riscv/rhct.c +++ b/drivers/acpi/riscv/rhct.c @@ -8,8 +8,9 @@ #define pr_fmt(fmt) "ACPI: RHCT: " fmt #include <linux/acpi.h> +#include <linux/bits.h> -static struct acpi_table_header *acpi_get_rhct(void) +static struct acpi_table_rhct *acpi_get_rhct(void) { static struct acpi_table_header *rhct; acpi_status status; @@ -26,7 +27,7 @@ static struct acpi_table_header *acpi_get_rhct(void) } } - return rhct; + return (struct acpi_table_rhct *)rhct; } /* @@ -48,7 +49,7 @@ int acpi_get_riscv_isa(struct acpi_table_header *table, unsigned int cpu, const BUG_ON(acpi_disabled); if (!table) { - rhct = (struct acpi_table_rhct *)acpi_get_rhct(); + rhct = acpi_get_rhct(); if (!rhct) return -ENOENT; } else { @@ -81,3 +82,89 @@ int acpi_get_riscv_isa(struct acpi_table_header *table, unsigned int cpu, const return -1; } + +static void acpi_parse_hart_info_cmo_node(struct acpi_table_rhct *rhct, + struct acpi_rhct_hart_info *hart_info, + u32 *cbom_size, u32 *cboz_size, u32 *cbop_size) +{ + u32 size_hartinfo = sizeof(struct acpi_rhct_hart_info); + u32 size_hdr = sizeof(struct acpi_rhct_node_header); + struct acpi_rhct_node_header *ref_node; + struct acpi_rhct_cmo_node *cmo_node; + u32 *hart_info_node_offset; + + hart_info_node_offset = ACPI_ADD_PTR(u32, hart_info, size_hartinfo); + for (int i = 0; i < hart_info->num_offsets; i++) { + ref_node = ACPI_ADD_PTR(struct acpi_rhct_node_header, + rhct, hart_info_node_offset[i]); + if (ref_node->type == ACPI_RHCT_NODE_TYPE_CMO) { + cmo_node = ACPI_ADD_PTR(struct acpi_rhct_cmo_node, + ref_node, size_hdr); + if (cbom_size && cmo_node->cbom_size <= 30) { + if (!*cbom_size) + *cbom_size = BIT(cmo_node->cbom_size); + else if (*cbom_size != BIT(cmo_node->cbom_size)) + pr_warn("CBOM size is not the same across harts\n"); + } + + if (cboz_size && cmo_node->cboz_size <= 30) { + if (!*cboz_size) + *cboz_size = BIT(cmo_node->cboz_size); + else if (*cboz_size != BIT(cmo_node->cboz_size)) + pr_warn("CBOZ size is not the same across harts\n"); + } + + if (cbop_size && cmo_node->cbop_size <= 30) { + if (!*cbop_size) + *cbop_size = BIT(cmo_node->cbop_size); + else if (*cbop_size != BIT(cmo_node->cbop_size)) + pr_warn("CBOP size is not the same across harts\n"); + } + } + } +} + +/* + * During early boot, the caller should call acpi_get_table() and pass its pointer to + * these functions (and free up later). At run time, since this table can be used + * multiple times, pass NULL so that the table remains in memory. + */ +void acpi_get_cbo_block_size(struct acpi_table_header *table, u32 *cbom_size, + u32 *cboz_size, u32 *cbop_size) +{ + u32 size_hdr = sizeof(struct acpi_rhct_node_header); + struct acpi_rhct_node_header *node, *end; + struct acpi_rhct_hart_info *hart_info; + struct acpi_table_rhct *rhct; + + if (acpi_disabled) + return; + + if (table) { + rhct = (struct acpi_table_rhct *)table; + } else { + rhct = acpi_get_rhct(); + if (!rhct) + return; + } + + if (cbom_size) + *cbom_size = 0; + + if (cboz_size) + *cboz_size = 0; + + if (cbop_size) + *cbop_size = 0; + + end = ACPI_ADD_PTR(struct acpi_rhct_node_header, rhct, rhct->header.length); + for (node = ACPI_ADD_PTR(struct acpi_rhct_node_header, rhct, rhct->node_offset); + node < end; + node = ACPI_ADD_PTR(struct acpi_rhct_node_header, node, node->length)) { + if (node->type == ACPI_RHCT_NODE_TYPE_HART_INFO) { + hart_info = ACPI_ADD_PTR(struct acpi_rhct_hart_info, node, size_hdr); + acpi_parse_hart_info_cmo_node(rhct, hart_info, cbom_size, + cboz_size, cbop_size); + } + } +} diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 1d249d0f61..02bb2cce42 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) @@ -2037,6 +2037,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/tables.c b/drivers/acpi/tables.c index 8ab0a82b4d..c1516337f6 100644 --- a/drivers/acpi/tables.c +++ b/drivers/acpi/tables.c @@ -37,18 +37,6 @@ static struct acpi_table_desc initial_tables[ACPI_MAX_TABLES] __initdata; static int acpi_apic_instance __initdata_or_acpilib; -enum acpi_subtable_type { - ACPI_SUBTABLE_COMMON, - ACPI_SUBTABLE_HMAT, - ACPI_SUBTABLE_PRMT, - ACPI_SUBTABLE_CEDT, -}; - -struct acpi_subtable_entry { - union acpi_subtable_headers *hdr; - enum acpi_subtable_type type; -}; - /* * Disable table checksum verification for the early stage due to the size * limitation of the current x86 early mapping implementation. @@ -237,167 +225,6 @@ void acpi_table_print_madt_entry(struct acpi_subtable_header *header) } } -static unsigned long __init_or_acpilib -acpi_get_entry_type(struct acpi_subtable_entry *entry) -{ - switch (entry->type) { - case ACPI_SUBTABLE_COMMON: - return entry->hdr->common.type; - case ACPI_SUBTABLE_HMAT: - return entry->hdr->hmat.type; - case ACPI_SUBTABLE_PRMT: - return 0; - case ACPI_SUBTABLE_CEDT: - return entry->hdr->cedt.type; - } - return 0; -} - -static unsigned long __init_or_acpilib -acpi_get_entry_length(struct acpi_subtable_entry *entry) -{ - switch (entry->type) { - case ACPI_SUBTABLE_COMMON: - return entry->hdr->common.length; - case ACPI_SUBTABLE_HMAT: - return entry->hdr->hmat.length; - case ACPI_SUBTABLE_PRMT: - return entry->hdr->prmt.length; - case ACPI_SUBTABLE_CEDT: - return entry->hdr->cedt.length; - } - return 0; -} - -static unsigned long __init_or_acpilib -acpi_get_subtable_header_length(struct acpi_subtable_entry *entry) -{ - switch (entry->type) { - case ACPI_SUBTABLE_COMMON: - return sizeof(entry->hdr->common); - case ACPI_SUBTABLE_HMAT: - return sizeof(entry->hdr->hmat); - case ACPI_SUBTABLE_PRMT: - return sizeof(entry->hdr->prmt); - case ACPI_SUBTABLE_CEDT: - return sizeof(entry->hdr->cedt); - } - return 0; -} - -static enum acpi_subtable_type __init_or_acpilib -acpi_get_subtable_type(char *id) -{ - if (strncmp(id, ACPI_SIG_HMAT, 4) == 0) - return ACPI_SUBTABLE_HMAT; - if (strncmp(id, ACPI_SIG_PRMT, 4) == 0) - return ACPI_SUBTABLE_PRMT; - if (strncmp(id, ACPI_SIG_CEDT, 4) == 0) - return ACPI_SUBTABLE_CEDT; - return ACPI_SUBTABLE_COMMON; -} - -static __init_or_acpilib bool has_handler(struct acpi_subtable_proc *proc) -{ - return proc->handler || proc->handler_arg; -} - -static __init_or_acpilib int call_handler(struct acpi_subtable_proc *proc, - union acpi_subtable_headers *hdr, - unsigned long end) -{ - if (proc->handler) - return proc->handler(hdr, end); - if (proc->handler_arg) - return proc->handler_arg(hdr, proc->arg, end); - return -EINVAL; -} - -/** - * acpi_parse_entries_array - for each proc_num find a suitable subtable - * - * @id: table id (for debugging purposes) - * @table_size: size of the root table - * @table_header: where does the table start? - * @proc: array of acpi_subtable_proc struct containing entry id - * and associated handler with it - * @proc_num: how big proc is? - * @max_entries: how many entries can we process? - * - * For each proc_num find a subtable with proc->id and run proc->handler - * on it. Assumption is that there's only single handler for particular - * entry id. - * - * The table_size is not the size of the complete ACPI table (the length - * field in the header struct), but only the size of the root table; i.e., - * the offset from the very first byte of the complete ACPI table, to the - * first byte of the very first subtable. - * - * On success returns sum of all matching entries for all proc handlers. - * Otherwise, -ENODEV or -EINVAL is returned. - */ -static int __init_or_acpilib acpi_parse_entries_array( - char *id, unsigned long table_size, - struct acpi_table_header *table_header, struct acpi_subtable_proc *proc, - int proc_num, unsigned int max_entries) -{ - struct acpi_subtable_entry entry; - unsigned long table_end, subtable_len, entry_len; - int count = 0; - int errs = 0; - int i; - - table_end = (unsigned long)table_header + table_header->length; - - /* Parse all entries looking for a match. */ - - entry.type = acpi_get_subtable_type(id); - entry.hdr = (union acpi_subtable_headers *) - ((unsigned long)table_header + table_size); - subtable_len = acpi_get_subtable_header_length(&entry); - - while (((unsigned long)entry.hdr) + subtable_len < table_end) { - if (max_entries && count >= max_entries) - break; - - for (i = 0; i < proc_num; i++) { - if (acpi_get_entry_type(&entry) != proc[i].id) - continue; - if (!has_handler(&proc[i]) || - (!errs && - call_handler(&proc[i], entry.hdr, table_end))) { - errs++; - continue; - } - - proc[i].count++; - break; - } - if (i != proc_num) - count++; - - /* - * If entry->length is 0, break from this loop to avoid - * infinite loop. - */ - entry_len = acpi_get_entry_length(&entry); - if (entry_len == 0) { - pr_err("[%4.4s:0x%02x] Invalid zero length\n", id, proc->id); - return -EINVAL; - } - - entry.hdr = (union acpi_subtable_headers *) - ((unsigned long)entry.hdr + entry_len); - } - - if (max_entries && count > max_entries) { - pr_warn("[%4.4s:0x%02x] found the maximum %i entries\n", - id, proc->id, count); - } - - return errs ? -EINVAL : count; -} - int __init_or_acpilib acpi_table_parse_entries_array( char *id, unsigned long table_size, struct acpi_subtable_proc *proc, int proc_num, unsigned int max_entries) diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c index 8263508415..f74d81abdb 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,7 +488,7 @@ 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; } @@ -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->trip_table); - 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 2ea14648a6..62944e35fc 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,12 +399,13 @@ acpi_evaluate_reference(acpi_handle handle, acpi_handle_debug(list->handles[i], "Found in reference list\n"); } - end: if (ACPI_FAILURE(status)) { list->count = 0; - //kfree(list->handles); + kfree(list->handles); + list->handles = NULL; } +end: kfree(buffer.pointer); return status; @@ -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 31205fee59..9fdcc620c6 100644 --- a/drivers/acpi/video_detect.c +++ b/drivers/acpi/video_detect.c @@ -239,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, @@ -825,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 08f7c67082..7d64e655f1 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 63d834dd38..bc65ebfcdf 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; } |