diff options
Diffstat (limited to 'drivers/acpi')
55 files changed, 1505 insertions, 327 deletions
diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig index 516d7b3..b533eeb 100644 --- a/drivers/acpi/Kconfig +++ b/drivers/acpi/Kconfig @@ -547,6 +547,9 @@ config ACPI_CONFIGFS if ARM64 source "drivers/acpi/arm64/Kconfig" + +config ACPI_PPTT + bool endif config TPS68470_PMIC_OPREGION diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile index 48e2027..6d59aa1 100644 --- a/drivers/acpi/Makefile +++ b/drivers/acpi/Makefile @@ -88,6 +88,7 @@ obj-$(CONFIG_ACPI_BGRT) += bgrt.o obj-$(CONFIG_ACPI_CPPC_LIB) += cppc_acpi.o obj-$(CONFIG_ACPI_SPCR_TABLE) += spcr.o obj-$(CONFIG_ACPI_DEBUGGER_USER) += acpi_dbg.o +obj-$(CONFIG_ACPI_PPTT) += pptt.o # processor has its own "processor." module_param namespace processor-y := processor_driver.o diff --git a/drivers/acpi/ac.c b/drivers/acpi/ac.c index 2d8de2f..cdd3136 100644 --- a/drivers/acpi/ac.c +++ b/drivers/acpi/ac.c @@ -82,11 +82,11 @@ static SIMPLE_DEV_PM_OPS(acpi_ac_pm, NULL, acpi_ac_resume); #ifdef CONFIG_ACPI_PROCFS_POWER extern struct proc_dir_entry *acpi_lock_ac_dir(void); extern void *acpi_unlock_ac_dir(struct proc_dir_entry *acpi_ac_dir); -static int acpi_ac_open_fs(struct inode *inode, struct file *file); #endif static int ac_sleep_before_get_state_ms; +static int ac_check_pmic = 1; static struct acpi_driver acpi_ac_driver = { .name = "ac", @@ -111,16 +111,6 @@ struct acpi_ac { #define to_acpi_ac(x) power_supply_get_drvdata(x) -#ifdef CONFIG_ACPI_PROCFS_POWER -static const struct file_operations acpi_ac_fops = { - .owner = THIS_MODULE, - .open = acpi_ac_open_fs, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; -#endif - /* -------------------------------------------------------------------------- AC Adapter Management -------------------------------------------------------------------------- */ @@ -209,11 +199,6 @@ static int acpi_ac_seq_show(struct seq_file *seq, void *offset) return 0; } -static int acpi_ac_open_fs(struct inode *inode, struct file *file) -{ - return single_open(file, acpi_ac_seq_show, PDE_DATA(inode)); -} - static int acpi_ac_add_fs(struct acpi_ac *ac) { struct proc_dir_entry *entry = NULL; @@ -228,9 +213,8 @@ static int acpi_ac_add_fs(struct acpi_ac *ac) } /* 'state' [R] */ - entry = proc_create_data(ACPI_AC_FILE_STATE, - S_IRUGO, acpi_device_dir(ac->device), - &acpi_ac_fops, ac); + entry = proc_create_single_data(ACPI_AC_FILE_STATE, S_IRUGO, + acpi_device_dir(ac->device), acpi_ac_seq_show, ac); if (!entry) return -ENODEV; return 0; @@ -310,21 +294,43 @@ static int acpi_ac_battery_notify(struct notifier_block *nb, return NOTIFY_OK; } -static int thinkpad_e530_quirk(const struct dmi_system_id *d) +static int __init thinkpad_e530_quirk(const struct dmi_system_id *d) { ac_sleep_before_get_state_ms = 1000; return 0; } -static const struct dmi_system_id ac_dmi_table[] = { +static int __init ac_do_not_check_pmic_quirk(const struct dmi_system_id *d) +{ + ac_check_pmic = 0; + return 0; +} + +static const struct dmi_system_id ac_dmi_table[] __initconst = { { + /* Thinkpad e530 */ .callback = thinkpad_e530_quirk, - .ident = "thinkpad e530", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), DMI_MATCH(DMI_PRODUCT_NAME, "32597CG"), }, }, + { + /* ECS EF20EA */ + .callback = ac_do_not_check_pmic_quirk, + .matches = { + DMI_MATCH(DMI_PRODUCT_NAME, "EF20EA"), + }, + }, + { + /* Lenovo Ideapad Miix 320 */ + .callback = ac_do_not_check_pmic_quirk, + .matches = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "80XF"), + DMI_EXACT_MATCH(DMI_PRODUCT_VERSION, "Lenovo MIIX 320-10ICR"), + }, + }, {}, }; @@ -384,7 +390,6 @@ end: kfree(ac); } - dmi_check_system(ac_dmi_table); return result; } @@ -442,13 +447,17 @@ static int __init acpi_ac_init(void) if (acpi_disabled) return -ENODEV; - for (i = 0; i < ARRAY_SIZE(acpi_ac_blacklist); i++) - if (acpi_dev_present(acpi_ac_blacklist[i].hid, "1", - acpi_ac_blacklist[i].hrv)) { - pr_info(PREFIX "AC: found native %s PMIC, not loading\n", - acpi_ac_blacklist[i].hid); - return -ENODEV; - } + dmi_check_system(ac_dmi_table); + + if (ac_check_pmic) { + for (i = 0; i < ARRAY_SIZE(acpi_ac_blacklist); i++) + if (acpi_dev_present(acpi_ac_blacklist[i].hid, "1", + acpi_ac_blacklist[i].hrv)) { + pr_info(PREFIX "AC: found native %s PMIC, not loading\n", + acpi_ac_blacklist[i].hid); + return -ENODEV; + } + } #ifdef CONFIG_ACPI_PROCFS_POWER acpi_ac_dir = acpi_lock_ac_dir(); diff --git a/drivers/acpi/acpi_apd.c b/drivers/acpi/acpi_apd.c index d553b00..2664452 100644 --- a/drivers/acpi/acpi_apd.c +++ b/drivers/acpi/acpi_apd.c @@ -11,6 +11,7 @@ */ #include <linux/clk-provider.h> +#include <linux/platform_data/clk-st.h> #include <linux/platform_device.h> #include <linux/pm_domain.h> #include <linux/clkdev.h> @@ -72,6 +73,47 @@ static int acpi_apd_setup(struct apd_private_data *pdata) } #ifdef CONFIG_X86_AMD_PLATFORM_DEVICE + +static int misc_check_res(struct acpi_resource *ares, void *data) +{ + struct resource res; + + return !acpi_dev_resource_memory(ares, &res); +} + +static int st_misc_setup(struct apd_private_data *pdata) +{ + struct acpi_device *adev = pdata->adev; + struct platform_device *clkdev; + struct st_clk_data *clk_data; + struct resource_entry *rentry; + struct list_head resource_list; + int ret; + + clk_data = devm_kzalloc(&adev->dev, sizeof(*clk_data), GFP_KERNEL); + if (!clk_data) + return -ENOMEM; + + INIT_LIST_HEAD(&resource_list); + ret = acpi_dev_get_resources(adev, &resource_list, misc_check_res, + NULL); + if (ret < 0) + return -ENOENT; + + list_for_each_entry(rentry, &resource_list, node) { + clk_data->base = devm_ioremap(&adev->dev, rentry->res->start, + resource_size(rentry->res)); + break; + } + + acpi_dev_free_resource_list(&resource_list); + + clkdev = platform_device_register_data(&adev->dev, "clk-st", + PLATFORM_DEVID_NONE, clk_data, + sizeof(*clk_data)); + return PTR_ERR_OR_ZERO(clkdev); +} + static const struct apd_device_desc cz_i2c_desc = { .setup = acpi_apd_setup, .fixed_clk_rate = 133000000, @@ -94,6 +136,10 @@ static const struct apd_device_desc cz_uart_desc = { .fixed_clk_rate = 48000000, .properties = uart_properties, }; + +static const struct apd_device_desc st_misc_desc = { + .setup = st_misc_setup, +}; #endif #ifdef CONFIG_ARM64 @@ -179,6 +225,7 @@ static const struct acpi_device_id acpi_apd_device_ids[] = { { "AMD0020", APD_ADDR(cz_uart_desc) }, { "AMDI0020", APD_ADDR(cz_uart_desc) }, { "AMD0030", }, + { "AMD0040", APD_ADDR(st_misc_desc)}, #endif #ifdef CONFIG_ARM64 { "APMC0D0F", APD_ADDR(xgene_i2c_desc) }, diff --git a/drivers/acpi/acpi_lpss.c b/drivers/acpi/acpi_lpss.c index c4ba916..38a2869 100644 --- a/drivers/acpi/acpi_lpss.c +++ b/drivers/acpi/acpi_lpss.c @@ -69,6 +69,10 @@ ACPI_MODULE_NAME("acpi_lpss"); #define LPSS_SAVE_CTX BIT(4) #define LPSS_NO_D3_DELAY BIT(5) +/* Crystal Cove PMIC shares same ACPI ID between different platforms */ +#define BYT_CRC_HRV 2 +#define CHT_CRC_HRV 3 + struct lpss_private_data; struct lpss_device_desc { @@ -162,7 +166,7 @@ static void byt_pwm_setup(struct lpss_private_data *pdata) if (!adev->pnp.unique_id || strcmp(adev->pnp.unique_id, "1")) return; - if (!acpi_dev_present("INT33FD", NULL, -1)) + if (!acpi_dev_present("INT33FD", NULL, BYT_CRC_HRV)) pwm_add_table(byt_pwm_lookup, ARRAY_SIZE(byt_pwm_lookup)); } diff --git a/drivers/acpi/acpi_platform.c b/drivers/acpi/acpi_platform.c index 88cd949..eaa60c9 100644 --- a/drivers/acpi/acpi_platform.c +++ b/drivers/acpi/acpi_platform.c @@ -82,7 +82,7 @@ struct platform_device *acpi_create_platform_device(struct acpi_device *adev, if (count < 0) { return NULL; } else if (count > 0) { - resources = kzalloc(count * sizeof(struct resource), + resources = kcalloc(count, sizeof(struct resource), GFP_KERNEL); if (!resources) { dev_err(&adev->dev, "No memory for resources\n"); diff --git a/drivers/acpi/acpi_video.c b/drivers/acpi/acpi_video.c index 76fb969..f0b5226 100644 --- a/drivers/acpi/acpi_video.c +++ b/drivers/acpi/acpi_video.c @@ -832,8 +832,9 @@ int acpi_video_get_levels(struct acpi_device *device, * in order to account for buggy BIOS which don't export the first two * special levels (see below) */ - br->levels = kmalloc((obj->package.count + ACPI_VIDEO_FIRST_LEVEL) * - sizeof(*br->levels), GFP_KERNEL); + br->levels = kmalloc_array(obj->package.count + ACPI_VIDEO_FIRST_LEVEL, + sizeof(*br->levels), + GFP_KERNEL); if (!br->levels) { result = -ENOMEM; goto out_free; @@ -2123,6 +2124,25 @@ static int __init intel_opregion_present(void) return opregion; } +static bool dmi_is_desktop(void) +{ + const char *chassis_type; + + chassis_type = dmi_get_system_info(DMI_CHASSIS_TYPE); + if (!chassis_type) + return false; + + if (!strcmp(chassis_type, "3") || /* 3: Desktop */ + !strcmp(chassis_type, "4") || /* 4: Low Profile Desktop */ + !strcmp(chassis_type, "5") || /* 5: Pizza Box */ + !strcmp(chassis_type, "6") || /* 6: Mini Tower */ + !strcmp(chassis_type, "7") || /* 7: Tower */ + !strcmp(chassis_type, "11")) /* 11: Main Server Chassis */ + return true; + + return false; +} + int acpi_video_register(void) { int ret = 0; @@ -2143,8 +2163,12 @@ int acpi_video_register(void) * win8 ready (where we also prefer the native backlight driver, so * normally the acpi_video code should not register there anyways). */ - if (only_lcd == -1) - only_lcd = acpi_osi_is_win8(); + if (only_lcd == -1) { + if (dmi_is_desktop() && acpi_osi_is_win8()) + only_lcd = true; + else + only_lcd = false; + } dmi_check_system(video_dmi_table); diff --git a/drivers/acpi/acpi_watchdog.c b/drivers/acpi/acpi_watchdog.c index ebb626f..9560030 100644 --- a/drivers/acpi/acpi_watchdog.c +++ b/drivers/acpi/acpi_watchdog.c @@ -17,18 +17,77 @@ #include "internal.h" +#ifdef CONFIG_RTC_MC146818_LIB +#include <linux/mc146818rtc.h> + +/* + * There are several systems where the WDAT table is accessing RTC SRAM to + * store persistent information. This does not work well with the Linux RTC + * driver so on those systems we skip WDAT driver and prefer iTCO_wdt + * instead. + * + * See also https://bugzilla.kernel.org/show_bug.cgi?id=199033. + */ +static bool acpi_watchdog_uses_rtc(const struct acpi_table_wdat *wdat) +{ + const struct acpi_wdat_entry *entries; + int i; + + entries = (struct acpi_wdat_entry *)(wdat + 1); + for (i = 0; i < wdat->entries; i++) { + const struct acpi_generic_address *gas; + + gas = &entries[i].register_region; + if (gas->space_id == ACPI_ADR_SPACE_SYSTEM_IO) { + switch (gas->address) { + case RTC_PORT(0): + case RTC_PORT(1): + case RTC_PORT(2): + case RTC_PORT(3): + return true; + } + } + } + + return false; +} +#else +static bool acpi_watchdog_uses_rtc(const struct acpi_table_wdat *wdat) +{ + return false; +} +#endif + +static const struct acpi_table_wdat *acpi_watchdog_get_wdat(void) +{ + const struct acpi_table_wdat *wdat = NULL; + acpi_status status; + + if (acpi_disabled) + return NULL; + + status = acpi_get_table(ACPI_SIG_WDAT, 0, + (struct acpi_table_header **)&wdat); + if (ACPI_FAILURE(status)) { + /* It is fine if there is no WDAT */ + return NULL; + } + + if (acpi_watchdog_uses_rtc(wdat)) { + pr_info("Skipping WDAT on this system because it uses RTC SRAM\n"); + return NULL; + } + + return wdat; +} + /** * Returns true if this system should prefer ACPI based watchdog instead of * the native one (which are typically the same hardware). */ bool acpi_has_watchdog(void) { - struct acpi_table_header hdr; - - if (acpi_disabled) - return false; - - return ACPI_SUCCESS(acpi_get_table_header(ACPI_SIG_WDAT, 0, &hdr)); + return !!acpi_watchdog_get_wdat(); } EXPORT_SYMBOL_GPL(acpi_has_watchdog); @@ -41,12 +100,10 @@ void __init acpi_watchdog_init(void) struct platform_device *pdev; struct resource *resources; size_t nresources = 0; - acpi_status status; int i; - status = acpi_get_table(ACPI_SIG_WDAT, 0, - (struct acpi_table_header **)&wdat); - if (ACPI_FAILURE(status)) { + wdat = acpi_watchdog_get_wdat(); + if (!wdat) { /* It is fine if there is no WDAT */ return; } diff --git a/drivers/acpi/acpica/acapps.h b/drivers/acpi/acpica/acapps.h index a2a8512..5a9c2fe 100644 --- a/drivers/acpi/acpica/acapps.h +++ b/drivers/acpi/acpica/acapps.h @@ -143,6 +143,8 @@ acpi_status fl_split_input_pathname(char *input_path, char **out_directory_path, char **out_filename); +char *fl_get_file_basename(char *file_pathname); + char *ad_generate_filename(char *prefix, char *table_id); void diff --git a/drivers/acpi/acpica/acglobal.h b/drivers/acpi/acpica/acglobal.h index 0bc5500..1e62045 100644 --- a/drivers/acpi/acpica/acglobal.h +++ b/drivers/acpi/acpica/acglobal.h @@ -82,7 +82,7 @@ ACPI_GLOBAL(u8, acpi_gbl_global_lock_pending); * interrupt level */ ACPI_GLOBAL(acpi_spinlock, acpi_gbl_gpe_lock); /* For GPE data structs and registers */ -ACPI_GLOBAL(acpi_spinlock, acpi_gbl_hardware_lock); /* For ACPI H/W except GPE registers */ +ACPI_GLOBAL(acpi_raw_spinlock, acpi_gbl_hardware_lock); /* For ACPI H/W except GPE registers */ ACPI_GLOBAL(acpi_spinlock, acpi_gbl_reference_count_lock); /* Mutex for _OSI support */ diff --git a/drivers/acpi/acpica/acnamesp.h b/drivers/acpi/acpica/acnamesp.h index 514aaf9..3825df9 100644 --- a/drivers/acpi/acpica/acnamesp.h +++ b/drivers/acpi/acpica/acnamesp.h @@ -56,6 +56,10 @@ acpi_status acpi_ns_initialize_objects(void); acpi_status acpi_ns_initialize_devices(u32 flags); +acpi_status +acpi_ns_init_one_package(acpi_handle obj_handle, + u32 level, void *context, void **return_value); + /* * nsload - Namespace loading */ diff --git a/drivers/acpi/acpica/dbnames.c b/drivers/acpi/acpica/dbnames.c index 170802c..992bd7b 100644 --- a/drivers/acpi/acpica/dbnames.c +++ b/drivers/acpi/acpica/dbnames.c @@ -189,9 +189,15 @@ void acpi_db_dump_namespace(char *start_arg, char *depth_arg) } acpi_db_set_output_destination(ACPI_DB_DUPLICATE_OUTPUT); - acpi_os_printf("ACPI Namespace (from %4.4s (%p) subtree):\n", - ((struct acpi_namespace_node *)subtree_entry)->name. - ascii, subtree_entry); + + if (((struct acpi_namespace_node *)subtree_entry)->parent) { + acpi_os_printf("ACPI Namespace (from %4.4s (%p) subtree):\n", + ((struct acpi_namespace_node *)subtree_entry)-> + name.ascii, subtree_entry); + } else { + acpi_os_printf("ACPI Namespace (from %s):\n", + ACPI_NAMESPACE_ROOT); + } /* Display the subtree */ @@ -316,6 +322,7 @@ acpi_db_walk_and_match_name(acpi_handle obj_handle, acpi_os_printf("Could Not get pathname for object %p\n", obj_handle); } else { + info.count = 0; info.owner_id = ACPI_OWNER_ID_MAX; info.debug_level = ACPI_UINT32_MAX; info.display_type = ACPI_DISPLAY_SUMMARY | ACPI_DISPLAY_SHORT; diff --git a/drivers/acpi/acpica/dbobject.c b/drivers/acpi/acpica/dbobject.c index 58c3253..a1c76bf 100644 --- a/drivers/acpi/acpica/dbobject.c +++ b/drivers/acpi/acpica/dbobject.c @@ -35,6 +35,15 @@ void acpi_db_dump_method_info(acpi_status status, struct acpi_walk_state *walk_state) { struct acpi_thread_state *thread; + struct acpi_namespace_node *node; + + node = walk_state->method_node; + + /* There are no locals or arguments for the module-level code case */ + + if (node == acpi_gbl_root_node) { + return; + } /* Ignore control codes, they are not errors */ @@ -384,8 +393,14 @@ void acpi_db_decode_locals(struct acpi_walk_state *walk_state) struct acpi_namespace_node *node; u8 display_locals = FALSE; - obj_desc = walk_state->method_desc; node = walk_state->method_node; + obj_desc = walk_state->method_desc; + + /* There are no locals for the module-level code case */ + + if (node == acpi_gbl_root_node) { + return; + } if (!node) { acpi_os_printf @@ -452,6 +467,12 @@ void acpi_db_decode_arguments(struct acpi_walk_state *walk_state) node = walk_state->method_node; obj_desc = walk_state->method_desc; + /* There are no arguments for the module-level code case */ + + if (node == acpi_gbl_root_node) { + return; + } + if (!node) { acpi_os_printf ("No method node (Executing subtree for buffer or opregion)\n"); diff --git a/drivers/acpi/acpica/dbtest.c b/drivers/acpi/acpica/dbtest.c index 3892680..8a54624 100644 --- a/drivers/acpi/acpica/dbtest.c +++ b/drivers/acpi/acpica/dbtest.c @@ -30,6 +30,8 @@ acpi_db_test_buffer_type(struct acpi_namespace_node *node, u32 bit_length); static acpi_status acpi_db_test_string_type(struct acpi_namespace_node *node, u32 byte_length); +static acpi_status acpi_db_test_package_type(struct acpi_namespace_node *node); + static acpi_status acpi_db_read_from_object(struct acpi_namespace_node *node, acpi_object_type expected_type, @@ -273,6 +275,11 @@ acpi_db_test_one_object(acpi_handle obj_handle, bit_length = byte_length * 8; break; + case ACPI_TYPE_PACKAGE: + + local_type = ACPI_TYPE_PACKAGE; + break; + case ACPI_TYPE_FIELD_UNIT: case ACPI_TYPE_BUFFER_FIELD: case ACPI_TYPE_LOCAL_REGION_FIELD: @@ -305,6 +312,7 @@ acpi_db_test_one_object(acpi_handle obj_handle, acpi_os_printf("%14s: %4.4s", acpi_ut_get_type_name(node->type), node->name.ascii); + if (!obj_desc) { acpi_os_printf(" Ignoring, no attached object\n"); return (AE_OK); @@ -322,14 +330,13 @@ acpi_db_test_one_object(acpi_handle obj_handle, case ACPI_ADR_SPACE_SYSTEM_MEMORY: case ACPI_ADR_SPACE_SYSTEM_IO: case ACPI_ADR_SPACE_PCI_CONFIG: - case ACPI_ADR_SPACE_EC: break; default: acpi_os_printf - (" %s space is not supported [%4.4s]\n", + (" %s space is not supported in this command [%4.4s]\n", acpi_ut_get_region_name(region_obj->region. space_id), region_obj->region.node->name.ascii); @@ -359,6 +366,11 @@ acpi_db_test_one_object(acpi_handle obj_handle, status = acpi_db_test_buffer_type(node, bit_length); break; + case ACPI_TYPE_PACKAGE: + + status = acpi_db_test_package_type(node); + break; + default: acpi_os_printf(" Ignoring, type not implemented (%2.2X)", @@ -366,6 +378,13 @@ acpi_db_test_one_object(acpi_handle obj_handle, break; } + /* Exit on error, but don't abort the namespace walk */ + + if (ACPI_FAILURE(status)) { + status = AE_OK; + goto exit; + } + switch (node->type) { case ACPI_TYPE_LOCAL_REGION_FIELD: @@ -373,12 +392,14 @@ acpi_db_test_one_object(acpi_handle obj_handle, acpi_os_printf(" (%s)", acpi_ut_get_region_name(region_obj->region. space_id)); + break; default: break; } +exit: acpi_os_printf("\n"); return (status); } @@ -431,7 +452,6 @@ acpi_db_test_integer_type(struct acpi_namespace_node *node, u32 bit_length) if (temp1->integer.value == value_to_write) { value_to_write = 0; } - /* Write a new value */ write_value.type = ACPI_TYPE_INTEGER; @@ -708,6 +728,35 @@ exit: /******************************************************************************* * + * FUNCTION: acpi_db_test_package_type + * + * PARAMETERS: node - Parent NS node for the object + * + * RETURN: Status + * + * DESCRIPTION: Test read for a Package object. + * + ******************************************************************************/ + +static acpi_status acpi_db_test_package_type(struct acpi_namespace_node *node) +{ + union acpi_object *temp1 = NULL; + acpi_status status; + + /* Read the original value */ + + status = acpi_db_read_from_object(node, ACPI_TYPE_PACKAGE, &temp1); + if (ACPI_FAILURE(status)) { + return (status); + } + + acpi_os_printf(" %8.8X Elements", temp1->package.count); + acpi_os_free(temp1); + return (status); +} + +/******************************************************************************* + * * FUNCTION: acpi_db_read_from_object * * PARAMETERS: node - Parent NS node for the object @@ -746,8 +795,8 @@ acpi_db_read_from_object(struct acpi_namespace_node *node, acpi_gbl_method_executing = TRUE; status = acpi_evaluate_object(read_handle, NULL, ¶m_objects, &return_obj); - acpi_gbl_method_executing = FALSE; + acpi_gbl_method_executing = FALSE; if (ACPI_FAILURE(status)) { acpi_os_printf("Could not read from object, %s", acpi_format_exception(status)); @@ -760,6 +809,7 @@ acpi_db_read_from_object(struct acpi_namespace_node *node, case ACPI_TYPE_INTEGER: case ACPI_TYPE_BUFFER: case ACPI_TYPE_STRING: + case ACPI_TYPE_PACKAGE: /* * Did we receive the type we wanted? Most important for the * Integer/Buffer case (when a field is larger than an Integer, @@ -771,6 +821,7 @@ acpi_db_read_from_object(struct acpi_namespace_node *node, acpi_ut_get_type_name(expected_type), acpi_ut_get_type_name(ret_value->type)); + acpi_os_free(return_obj.pointer); return (AE_TYPE); } diff --git a/drivers/acpi/acpica/dsdebug.c b/drivers/acpi/acpica/dsdebug.c index 70a2fca..9d33f0b 100644 --- a/drivers/acpi/acpica/dsdebug.c +++ b/drivers/acpi/acpica/dsdebug.c @@ -162,9 +162,15 @@ acpi_ds_dump_method_stack(acpi_status status, op->common.next = NULL; #ifdef ACPI_DISASSEMBLER - acpi_os_printf("Failed at "); - acpi_dm_disassemble(next_walk_state, op, - ACPI_UINT32_MAX); + if (walk_state->method_node != + acpi_gbl_root_node) { + + /* More verbose if not module-level code */ + + acpi_os_printf("Failed at "); + acpi_dm_disassemble(next_walk_state, op, + ACPI_UINT32_MAX); + } #endif op->common.next = next; } diff --git a/drivers/acpi/acpica/dswscope.c b/drivers/acpi/acpica/dswscope.c index d1422f9..7592176 100644 --- a/drivers/acpi/acpica/dswscope.c +++ b/drivers/acpi/acpica/dswscope.c @@ -115,7 +115,7 @@ acpi_ds_scope_stack_push(struct acpi_namespace_node *node, acpi_ut_get_type_name(old_scope_info-> common.value))); } else { - ACPI_DEBUG_PRINT_RAW((ACPI_DB_EXEC, "[\\___] (%s)", "ROOT")); + ACPI_DEBUG_PRINT_RAW((ACPI_DB_EXEC, ACPI_NAMESPACE_ROOT)); } ACPI_DEBUG_PRINT_RAW((ACPI_DB_EXEC, @@ -166,14 +166,14 @@ acpi_status acpi_ds_scope_stack_pop(struct acpi_walk_state *walk_state) new_scope_info = walk_state->scope_info; if (new_scope_info) { - ACPI_DEBUG_PRINT_RAW((ACPI_DB_EXEC, - "[%4.4s] (%s)\n", + ACPI_DEBUG_PRINT_RAW((ACPI_DB_EXEC, "[%4.4s] (%s)\n", acpi_ut_get_node_name(new_scope_info-> scope.node), acpi_ut_get_type_name(new_scope_info-> common.value))); } else { - ACPI_DEBUG_PRINT_RAW((ACPI_DB_EXEC, "[\\___] (ROOT)\n")); + ACPI_DEBUG_PRINT_RAW((ACPI_DB_EXEC, "%s\n", + ACPI_NAMESPACE_ROOT)); } acpi_ut_delete_generic_state(scope_info); diff --git a/drivers/acpi/acpica/evgpe.c b/drivers/acpi/acpica/evgpe.c index abbd590..e10fec9 100644 --- a/drivers/acpi/acpica/evgpe.c +++ b/drivers/acpi/acpica/evgpe.c @@ -634,6 +634,12 @@ acpi_ev_detect_gpe(struct acpi_namespace_node *gpe_device, flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock); + if (!gpe_event_info) { + gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number); + if (!gpe_event_info) + goto error_exit; + } + /* Get the info block for the entire GPE register */ gpe_register_info = gpe_event_info->register_info; diff --git a/drivers/acpi/acpica/evxfgpe.c b/drivers/acpi/acpica/evxfgpe.c index c80e3bdf..b2d5f66 100644 --- a/drivers/acpi/acpica/evxfgpe.c +++ b/drivers/acpi/acpica/evxfgpe.c @@ -639,6 +639,28 @@ ACPI_EXPORT_SYMBOL(acpi_get_gpe_status) /******************************************************************************* * + * FUNCTION: acpi_gispatch_gpe + * + * PARAMETERS: gpe_device - Parent GPE Device. NULL for GPE0/GPE1 + * gpe_number - GPE level within the GPE block + * + * RETURN: None + * + * DESCRIPTION: Detect and dispatch a General Purpose Event to either a function + * (e.g. EC) or method (e.g. _Lxx/_Exx) handler. + * + ******************************************************************************/ +void acpi_dispatch_gpe(acpi_handle gpe_device, u32 gpe_number) +{ + ACPI_FUNCTION_TRACE(acpi_dispatch_gpe); + + acpi_ev_detect_gpe(gpe_device, NULL, gpe_number); +} + +ACPI_EXPORT_SYMBOL(acpi_dispatch_gpe) + +/******************************************************************************* + * * FUNCTION: acpi_finish_gpe * * PARAMETERS: gpe_device - Namespace node for the GPE Block diff --git a/drivers/acpi/acpica/exconfig.c b/drivers/acpi/acpica/exconfig.c index 99d92cb..2373a74 100644 --- a/drivers/acpi/acpica/exconfig.c +++ b/drivers/acpi/acpica/exconfig.c @@ -174,6 +174,13 @@ acpi_ex_load_table_op(struct acpi_walk_state *walk_state, return_ACPI_STATUS(status); } + /* Complete the initialization/resolution of package objects */ + + status = acpi_ns_walk_namespace(ACPI_TYPE_PACKAGE, ACPI_ROOT_OBJECT, + ACPI_UINT32_MAX, 0, + acpi_ns_init_one_package, NULL, NULL, + NULL); + /* Parameter Data (optional) */ if (parameter_node) { @@ -430,6 +437,13 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc, return_ACPI_STATUS(status); } + /* Complete the initialization/resolution of package objects */ + + status = acpi_ns_walk_namespace(ACPI_TYPE_PACKAGE, ACPI_ROOT_OBJECT, + ACPI_UINT32_MAX, 0, + acpi_ns_init_one_package, NULL, NULL, + NULL); + /* Store the ddb_handle into the Target operand */ status = acpi_ex_store(ddb_handle, target, walk_state); @@ -476,6 +490,17 @@ acpi_status acpi_ex_unload_table(union acpi_operand_object *ddb_handle) ACPI_WARNING((AE_INFO, "Received request to unload an ACPI table")); /* + * May 2018: Unload is no longer supported for the following reasons: + * 1) A correct implementation on some hosts may not be possible. + * 2) Other ACPI implementations do not correctly/fully support it. + * 3) It requires host device driver support which does not exist. + * (To properly support namespace unload out from underneath.) + * 4) This AML operator has never been seen in the field. + */ + ACPI_EXCEPTION((AE_INFO, AE_NOT_IMPLEMENTED, + "AML Unload operator is not supported")); + + /* * Validate the handle * Although the handle is partially validated in acpi_ex_reconfiguration() * when it calls acpi_ex_resolve_operands(), the handle is more completely diff --git a/drivers/acpi/acpica/hwregs.c b/drivers/acpi/acpica/hwregs.c index 27a86ad..3de794b 100644 --- a/drivers/acpi/acpica/hwregs.c +++ b/drivers/acpi/acpica/hwregs.c @@ -390,14 +390,14 @@ acpi_status acpi_hw_clear_acpi_status(void) ACPI_BITMASK_ALL_FIXED_STATUS, ACPI_FORMAT_UINT64(acpi_gbl_xpm1a_status.address))); - lock_flags = acpi_os_acquire_lock(acpi_gbl_hardware_lock); + lock_flags = acpi_os_acquire_raw_lock(acpi_gbl_hardware_lock); /* Clear the fixed events in PM1 A/B */ status = acpi_hw_register_write(ACPI_REGISTER_PM1_STATUS, ACPI_BITMASK_ALL_FIXED_STATUS); - acpi_os_release_lock(acpi_gbl_hardware_lock, lock_flags); + acpi_os_release_raw_lock(acpi_gbl_hardware_lock, lock_flags); if (ACPI_FAILURE(status)) { goto exit; diff --git a/drivers/acpi/acpica/hwxface.c b/drivers/acpi/acpica/hwxface.c index 5d13968..6e39a77 100644 --- a/drivers/acpi/acpica/hwxface.c +++ b/drivers/acpi/acpica/hwxface.c @@ -227,7 +227,7 @@ acpi_status acpi_write_bit_register(u32 register_id, u32 value) return_ACPI_STATUS(AE_BAD_PARAMETER); } - lock_flags = acpi_os_acquire_lock(acpi_gbl_hardware_lock); + lock_flags = acpi_os_acquire_raw_lock(acpi_gbl_hardware_lock); /* * At this point, we know that the parent register is one of the @@ -288,7 +288,7 @@ acpi_status acpi_write_bit_register(u32 register_id, u32 value) unlock_and_exit: - acpi_os_release_lock(acpi_gbl_hardware_lock, lock_flags); + acpi_os_release_raw_lock(acpi_gbl_hardware_lock, lock_flags); return_ACPI_STATUS(status); } diff --git a/drivers/acpi/acpica/nsdump.c b/drivers/acpi/acpica/nsdump.c index 4bdbd1d..90ccffc 100644 --- a/drivers/acpi/acpica/nsdump.c +++ b/drivers/acpi/acpica/nsdump.c @@ -170,6 +170,7 @@ acpi_ns_dump_one_object(acpi_handle obj_handle, } type = this_node->type; + info->count++; /* Check if the owner matches */ @@ -639,6 +640,7 @@ acpi_ns_dump_objects(acpi_object_type type, return; } + info.count = 0; info.debug_level = ACPI_LV_TABLES; info.owner_id = owner_id; info.display_type = display_type; @@ -649,6 +651,7 @@ acpi_ns_dump_objects(acpi_object_type type, acpi_ns_dump_one_object, NULL, (void *)&info, NULL); + acpi_os_printf("\nNamespace node count: %u\n\n", info.count); (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); } diff --git a/drivers/acpi/acpica/nsinit.c b/drivers/acpi/acpica/nsinit.c index 77f2b5f..d77257d 100644 --- a/drivers/acpi/acpica/nsinit.c +++ b/drivers/acpi/acpica/nsinit.c @@ -242,6 +242,58 @@ error_exit: /******************************************************************************* * + * FUNCTION: acpi_ns_init_one_package + * + * PARAMETERS: obj_handle - Node + * level - Current nesting level + * context - Not used + * return_value - Not used + * + * RETURN: Status + * + * DESCRIPTION: Callback from acpi_walk_namespace. Invoked for every package + * within the namespace. Used during dynamic load of an SSDT. + * + ******************************************************************************/ + +acpi_status +acpi_ns_init_one_package(acpi_handle obj_handle, + u32 level, void *context, void **return_value) +{ + acpi_status status; + union acpi_operand_object *obj_desc; + struct acpi_namespace_node *node = + (struct acpi_namespace_node *)obj_handle; + + obj_desc = acpi_ns_get_attached_object(node); + if (!obj_desc) { + return (AE_OK); + } + + /* Exit if package is already initialized */ + + if (obj_desc->package.flags & AOPOBJ_DATA_VALID) { + return (AE_OK); + } + + status = acpi_ds_get_package_arguments(obj_desc); + if (ACPI_FAILURE(status)) { + return (AE_OK); + } + + status = + acpi_ut_walk_package_tree(obj_desc, NULL, + acpi_ds_init_package_element, NULL); + if (ACPI_FAILURE(status)) { + return (AE_OK); + } + + obj_desc->package.flags |= AOPOBJ_DATA_VALID; + return (AE_OK); +} + +/******************************************************************************* + * * FUNCTION: acpi_ns_init_one_object * * PARAMETERS: obj_handle - Node @@ -360,27 +412,11 @@ acpi_ns_init_one_object(acpi_handle obj_handle, case ACPI_TYPE_PACKAGE: - info->package_init++; - status = acpi_ds_get_package_arguments(obj_desc); - if (ACPI_FAILURE(status)) { - break; - } - - ACPI_DEBUG_PRINT_RAW((ACPI_DB_PARSE, - "%s: Completing resolution of Package elements\n", - ACPI_GET_FUNCTION_NAME)); + /* Complete the initialization/resolution of the package object */ - /* - * Resolve all named references in package objects (and all - * sub-packages). This action has been deferred until the entire - * namespace has been loaded, in order to support external and - * forward references from individual package elements (05/2017). - */ - status = acpi_ut_walk_package_tree(obj_desc, NULL, - acpi_ds_init_package_element, - NULL); - - obj_desc->package.flags |= AOPOBJ_DATA_VALID; + info->package_init++; + status = + acpi_ns_init_one_package(obj_handle, level, NULL, NULL); break; default: diff --git a/drivers/acpi/acpica/psloop.c b/drivers/acpi/acpica/psloop.c index 68422af..bc5f059 100644 --- a/drivers/acpi/acpica/psloop.c +++ b/drivers/acpi/acpica/psloop.c @@ -515,6 +515,22 @@ acpi_status acpi_ps_parse_loop(struct acpi_walk_state *walk_state) if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } + if (walk_state->opcode == AML_SCOPE_OP) { + /* + * If the scope op fails to parse, skip the body of the + * scope op because the parse failure indicates that the + * device may not exist. + */ + walk_state->parser_state.aml = + walk_state->aml + 1; + walk_state->parser_state.aml = + acpi_ps_get_next_package_end + (&walk_state->parser_state); + walk_state->aml = + walk_state->parser_state.aml; + ACPI_ERROR((AE_INFO, + "Skipping Scope block")); + } continue; } @@ -557,7 +573,40 @@ acpi_status acpi_ps_parse_loop(struct acpi_walk_state *walk_state) if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } - + if ((walk_state->control_state) && + ((walk_state->control_state->control. + opcode == AML_IF_OP) + || (walk_state->control_state->control. + opcode == AML_WHILE_OP))) { + /* + * If the if/while op fails to parse, we will skip parsing + * the body of the op. + */ + parser_state->aml = + walk_state->control_state->control. + aml_predicate_start + 1; + parser_state->aml = + acpi_ps_get_next_package_end + (parser_state); + walk_state->aml = parser_state->aml; + + ACPI_ERROR((AE_INFO, + "Skipping While/If block")); + if (*walk_state->aml == AML_ELSE_OP) { + ACPI_ERROR((AE_INFO, + "Skipping Else block")); + walk_state->parser_state.aml = + walk_state->aml + 1; + walk_state->parser_state.aml = + acpi_ps_get_next_package_end + (parser_state); + walk_state->aml = + parser_state->aml; + } + ACPI_FREE(acpi_ut_pop_generic_state + (&walk_state->control_state)); + } + op = NULL; continue; } } diff --git a/drivers/acpi/acpica/psobject.c b/drivers/acpi/acpica/psobject.c index 7d9d015..3138e7a 100644 --- a/drivers/acpi/acpica/psobject.c +++ b/drivers/acpi/acpica/psobject.c @@ -12,6 +12,7 @@ #include "acparser.h" #include "amlcode.h" #include "acconvert.h" +#include "acnamesp.h" #define _COMPONENT ACPI_PARSER ACPI_MODULE_NAME("psobject") @@ -549,6 +550,21 @@ acpi_ps_complete_op(struct acpi_walk_state *walk_state, do { if (*op) { + /* + * These Opcodes need to be removed from the namespace because they + * get created even if these opcodes cannot be created due to + * errors. + */ + if (((*op)->common.aml_opcode == AML_REGION_OP) + || ((*op)->common.aml_opcode == + AML_DATA_REGION_OP)) { + acpi_ns_delete_children((*op)->common. + node); + acpi_ns_remove_node((*op)->common.node); + (*op)->common.node = NULL; + acpi_ps_delete_parse_tree(*op); + } + status2 = acpi_ps_complete_this_op(walk_state, *op); if (ACPI_FAILURE(status2)) { @@ -574,6 +590,20 @@ acpi_ps_complete_op(struct acpi_walk_state *walk_state, #endif walk_state->prev_op = NULL; walk_state->prev_arg_types = walk_state->arg_types; + + if (walk_state->parse_flags & ACPI_PARSE_MODULE_LEVEL) { + /* + * There was something that went wrong while executing code at the + * module-level. We need to skip parsing whatever caused the + * error and keep going. One runtime error during the table load + * should not cause the entire table to not be loaded. This is + * because there could be correct AML beyond the parts that caused + * the runtime error. + */ + ACPI_ERROR((AE_INFO, + "Ignore error and continue table load")); + return_ACPI_STATUS(AE_OK); + } return_ACPI_STATUS(status); } diff --git a/drivers/acpi/acpica/pswalk.c b/drivers/acpi/acpica/pswalk.c index e0a442b..bd6af8c 100644 --- a/drivers/acpi/acpica/pswalk.c +++ b/drivers/acpi/acpica/pswalk.c @@ -25,22 +25,48 @@ ACPI_MODULE_NAME("pswalk") * DESCRIPTION: Delete a portion of or an entire parse tree. * ******************************************************************************/ +#include "amlcode.h" void acpi_ps_delete_parse_tree(union acpi_parse_object *subtree_root) { union acpi_parse_object *op = subtree_root; union acpi_parse_object *next = NULL; union acpi_parse_object *parent = NULL; + u32 level = 0; ACPI_FUNCTION_TRACE_PTR(ps_delete_parse_tree, subtree_root); + ACPI_DEBUG_PRINT((ACPI_DB_PARSE_TREES, " root %p\n", subtree_root)); + /* Visit all nodes in the subtree */ while (op) { - - /* Check if we are not ascending */ - if (op != parent) { + /* This is the descending case */ + + if (ACPI_IS_DEBUG_ENABLED + (ACPI_LV_PARSE_TREES, _COMPONENT)) { + + /* This debug option will print the entire parse tree */ + + acpi_os_printf(" %*.s%s %p", (level * 4), + " ", + acpi_ps_get_opcode_name(op-> + common. + aml_opcode), + op); + + if (op->named.aml_opcode == AML_INT_NAMEPATH_OP) { + acpi_os_printf(" %4.4s", + op->common.value.string); + } + if (op->named.aml_opcode == AML_STRING_OP) { + acpi_os_printf(" %s", + op->common.value.string); + } + acpi_os_printf("\n"); + } + /* Look for an argument or child of the current op */ next = acpi_ps_get_arg(op, 0); @@ -49,6 +75,7 @@ void acpi_ps_delete_parse_tree(union acpi_parse_object *subtree_root) /* Still going downward in tree (Op is not completed yet) */ op = next; + level++; continue; } } @@ -69,6 +96,7 @@ void acpi_ps_delete_parse_tree(union acpi_parse_object *subtree_root) if (next) { op = next; } else { + level--; op = parent; } } diff --git a/drivers/acpi/acpica/rsdump.c b/drivers/acpi/acpica/rsdump.c index b12a0b1..6601e71 100644 --- a/drivers/acpi/acpica/rsdump.c +++ b/drivers/acpi/acpica/rsdump.c @@ -539,7 +539,7 @@ static void acpi_rs_out_title(const char *title) static void acpi_rs_dump_byte_list(u16 length, u8 * data) { - u8 i; + u16 i; for (i = 0; i < length; i++) { acpi_os_printf("%25s%2.2X : %2.2X\n", "Byte", i, data[i]); diff --git a/drivers/acpi/acpica/tbinstal.c b/drivers/acpi/acpica/tbinstal.c index c5085b7..5f8e7b5 100644 --- a/drivers/acpi/acpica/tbinstal.c +++ b/drivers/acpi/acpica/tbinstal.c @@ -88,7 +88,7 @@ acpi_tb_install_table_with_override(struct acpi_table_desc *new_table_desc, * DESCRIPTION: This function is called to verify and install an ACPI table. * When this function is called by "Load" or "LoadTable" opcodes, * or by acpi_load_table() API, the "Reload" parameter is set. - * After sucessfully returning from this function, table is + * After successfully returning from this function, table is * "INSTALLED" but not "VALIDATED". * ******************************************************************************/ diff --git a/drivers/acpi/acpica/utbuffer.c b/drivers/acpi/acpica/utbuffer.c index 148aeb8..fffa6f5 100644 --- a/drivers/acpi/acpica/utbuffer.c +++ b/drivers/acpi/acpica/utbuffer.c @@ -53,7 +53,7 @@ void acpi_ut_dump_buffer(u8 *buffer, u32 count, u32 display, u32 base_offset) /* Print current offset */ - acpi_os_printf("%6.4X: ", (base_offset + i)); + acpi_os_printf("%8.4X: ", (base_offset + i)); /* Print 16 hex chars */ @@ -219,7 +219,7 @@ acpi_ut_dump_buffer_to_file(ACPI_FILE file, /* Print current offset */ - fprintf(file, "%6.4X: ", (base_offset + i)); + fprintf(file, "%8.4X: ", (base_offset + i)); /* Print 16 hex chars */ diff --git a/drivers/acpi/acpica/uterror.c b/drivers/acpi/acpica/uterror.c index 12d4a0f..5a64dda 100644 --- a/drivers/acpi/acpica/uterror.c +++ b/drivers/acpi/acpica/uterror.c @@ -182,20 +182,20 @@ acpi_ut_prefixed_namespace_error(const char *module_name, switch (lookup_status) { case AE_ALREADY_EXISTS: - acpi_os_printf(ACPI_MSG_BIOS_ERROR); + acpi_os_printf("\n" ACPI_MSG_BIOS_ERROR); message = "Failure creating"; break; case AE_NOT_FOUND: - acpi_os_printf(ACPI_MSG_BIOS_ERROR); - message = "Failure looking up"; + acpi_os_printf("\n" ACPI_MSG_BIOS_ERROR); + message = "Could not resolve"; break; default: - acpi_os_printf(ACPI_MSG_ERROR); - message = "Failure looking up"; + acpi_os_printf("\n" ACPI_MSG_ERROR); + message = "Failure resolving"; break; } diff --git a/drivers/acpi/acpica/utmutex.c b/drivers/acpi/acpica/utmutex.c index d2d93e3..2e465e6 100644 --- a/drivers/acpi/acpica/utmutex.c +++ b/drivers/acpi/acpica/utmutex.c @@ -52,7 +52,7 @@ acpi_status acpi_ut_mutex_initialize(void) return_ACPI_STATUS (status); } - status = acpi_os_create_lock (&acpi_gbl_hardware_lock); + status = acpi_os_create_raw_lock(&acpi_gbl_hardware_lock); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); } @@ -109,7 +109,7 @@ void acpi_ut_mutex_terminate(void) /* Delete the spinlocks */ acpi_os_delete_lock(acpi_gbl_gpe_lock); - acpi_os_delete_lock(acpi_gbl_hardware_lock); + acpi_os_delete_raw_lock(acpi_gbl_hardware_lock); acpi_os_delete_lock(acpi_gbl_reference_count_lock); /* Delete the reader/writer lock */ diff --git a/drivers/acpi/acpica/utobject.c b/drivers/acpi/acpica/utobject.c index 5b78fe0..ae6d8cc 100644 --- a/drivers/acpi/acpica/utobject.c +++ b/drivers/acpi/acpica/utobject.c @@ -8,6 +8,7 @@ *****************************************************************************/ #include <acpi/acpi.h> +#include <linux/kmemleak.h> #include "accommon.h" #include "acnamesp.h" @@ -70,6 +71,7 @@ union acpi_operand_object *acpi_ut_create_internal_object_dbg(const char if (!object) { return_PTR(NULL); } + kmemleak_not_leak(object); switch (type) { case ACPI_TYPE_REGION: diff --git a/drivers/acpi/acpica/utosi.c b/drivers/acpi/acpica/utosi.c index 1b415fa..64b63c8 100644 --- a/drivers/acpi/acpica/utosi.c +++ b/drivers/acpi/acpica/utosi.c @@ -69,6 +69,7 @@ static struct acpi_interface_info acpi_default_supported_interfaces[] = { {"Windows 2015", NULL, 0, ACPI_OSI_WIN_10}, /* Windows 10 - Added 03/2015 */ {"Windows 2016", NULL, 0, ACPI_OSI_WIN_10_RS1}, /* Windows 10 version 1607 - Added 12/2017 */ {"Windows 2017", NULL, 0, ACPI_OSI_WIN_10_RS2}, /* Windows 10 version 1703 - Added 12/2017 */ + {"Windows 2017.2", NULL, 0, ACPI_OSI_WIN_10_RS3}, /* Windows 10 version 1709 - Added 02/2018 */ /* Feature Group Strings */ diff --git a/drivers/acpi/acpica/utprint.c b/drivers/acpi/acpica/utprint.c index 35ffd8d..a98c334 100644 --- a/drivers/acpi/acpica/utprint.c +++ b/drivers/acpi/acpica/utprint.c @@ -470,6 +470,7 @@ int vsnprintf(char *string, acpi_size size, const char *format, va_list args) case 'X': type |= ACPI_FORMAT_UPPER; + /* FALLTHROUGH */ case 'x': diff --git a/drivers/acpi/acpica/utstring.c b/drivers/acpi/acpica/utstring.c index bd57a77..5bef0b0 100644 --- a/drivers/acpi/acpica/utstring.c +++ b/drivers/acpi/acpica/utstring.c @@ -141,7 +141,7 @@ void acpi_ut_repair_name(char *name) * Special case for the root node. This can happen if we get an * error during the execution of module-level code. */ - if (ACPI_COMPARE_NAME(name, "\\___")) { + if (ACPI_COMPARE_NAME(name, ACPI_ROOT_PATHNAME)) { return; } diff --git a/drivers/acpi/apei/erst.c b/drivers/acpi/apei/erst.c index 9bff853..3c5ea7c 100644 --- a/drivers/acpi/apei/erst.c +++ b/drivers/acpi/apei/erst.c @@ -524,7 +524,8 @@ retry: pr_warn(FW_WARN "too many record IDs!\n"); return 0; } - new_entries = kvmalloc(new_size * sizeof(entries[0]), GFP_KERNEL); + new_entries = kvmalloc_array(new_size, sizeof(entries[0]), + GFP_KERNEL); if (!new_entries) return -ENOMEM; memcpy(new_entries, entries, diff --git a/drivers/acpi/apei/ghes.c b/drivers/acpi/apei/ghes.c index 1efefe9..02c6fd9 100644 --- a/drivers/acpi/apei/ghes.c +++ b/drivers/acpi/apei/ghes.c @@ -481,7 +481,7 @@ static void ghes_do_proc(struct ghes *ghes, if (guid_equal(sec_type, &CPER_SEC_PLATFORM_MEM)) { struct cper_sec_mem_err *mem_err = acpi_hest_get_payload(gdata); - ghes_edac_report_mem_error(ghes, sev, mem_err); + ghes_edac_report_mem_error(sev, mem_err); arch_apei_report_mem_error(sev, mem_err); ghes_handle_memory_failure(gdata, sev); @@ -1087,10 +1087,6 @@ static int ghes_probe(struct platform_device *ghes_dev) goto err; } - rc = ghes_edac_register(ghes, &ghes_dev->dev); - if (rc < 0) - goto err; - switch (generic->notify.type) { case ACPI_HEST_NOTIFY_POLLED: timer_setup(&ghes->timer, ghes_poll_func, TIMER_DEFERRABLE); @@ -1102,14 +1098,14 @@ static int ghes_probe(struct platform_device *ghes_dev) if (rc) { pr_err(GHES_PFX "Failed to map GSI to IRQ for generic hardware error source: %d\n", generic->header.source_id); - goto err_edac_unreg; + goto err; } rc = request_irq(ghes->irq, ghes_irq_func, IRQF_SHARED, "GHES IRQ", ghes); if (rc) { pr_err(GHES_PFX "Failed to register IRQ for generic hardware error source: %d\n", generic->header.source_id); - goto err_edac_unreg; + goto err; } break; @@ -1132,14 +1128,16 @@ static int ghes_probe(struct platform_device *ghes_dev) default: BUG(); } + platform_set_drvdata(ghes_dev, ghes); + ghes_edac_register(ghes, &ghes_dev->dev); + /* Handle any pending errors right away */ ghes_proc(ghes); return 0; -err_edac_unreg: - ghes_edac_unregister(ghes); + err: if (ghes) { ghes_fini(ghes); diff --git a/drivers/acpi/apei/hest.c b/drivers/acpi/apei/hest.c index 9cb7411..b1e9f81 100644 --- a/drivers/acpi/apei/hest.c +++ b/drivers/acpi/apei/hest.c @@ -195,7 +195,8 @@ static int __init hest_ghes_dev_register(unsigned int ghes_count) struct ghes_arr ghes_arr; ghes_arr.count = 0; - ghes_arr.ghes_devs = kmalloc(sizeof(void *) * ghes_count, GFP_KERNEL); + ghes_arr.ghes_devs = kmalloc_array(ghes_count, sizeof(void *), + GFP_KERNEL); if (!ghes_arr.ghes_devs) return -ENOMEM; diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c index bdb24d6..b0113a5 100644 --- a/drivers/acpi/battery.c +++ b/drivers/acpi/battery.c @@ -74,6 +74,8 @@ static async_cookie_t async_cookie; static bool battery_driver_registered; static int battery_bix_broken_package; static int battery_notification_delay_ms; +static int battery_ac_is_broken; +static int battery_check_pmic = 1; static unsigned int cache_time = 1000; module_param(cache_time, uint, 0644); MODULE_PARM_DESC(cache_time, "cache time in milliseconds"); @@ -81,14 +83,6 @@ MODULE_PARM_DESC(cache_time, "cache time in milliseconds"); #ifdef CONFIG_ACPI_PROCFS_POWER extern struct proc_dir_entry *acpi_lock_battery_dir(void); extern void *acpi_unlock_battery_dir(struct proc_dir_entry *acpi_battery_dir); - -enum acpi_battery_files { - info_tag = 0, - state_tag, - alarm_tag, - ACPI_BATTERY_NUMFILES, -}; - #endif static const struct acpi_device_id battery_device_ids[] = { @@ -215,6 +209,20 @@ static bool acpi_battery_is_degraded(struct acpi_battery *battery) battery->full_charge_capacity < battery->design_capacity; } +static int acpi_battery_handle_discharging(struct acpi_battery *battery) +{ + /* + * Some devices wrongly report discharging if the battery's charge level + * was above the device's start charging threshold atm the AC adapter + * was plugged in and the device thus did not start a new charge cycle. + */ + if ((battery_ac_is_broken || power_supply_is_system_supplied()) && + battery->rate_now == 0) + return POWER_SUPPLY_STATUS_NOT_CHARGING; + + return POWER_SUPPLY_STATUS_DISCHARGING; +} + static int acpi_battery_get_property(struct power_supply *psy, enum power_supply_property psp, union power_supply_propval *val) @@ -230,7 +238,7 @@ static int acpi_battery_get_property(struct power_supply *psy, switch (psp) { case POWER_SUPPLY_PROP_STATUS: if (battery->state & ACPI_BATTERY_STATE_DISCHARGING) - val->intval = POWER_SUPPLY_STATUS_DISCHARGING; + val->intval = acpi_battery_handle_discharging(battery); else if (battery->state & ACPI_BATTERY_STATE_CHARGING) val->intval = POWER_SUPPLY_STATUS_CHARGING; else if (acpi_battery_is_charged(battery)) @@ -985,9 +993,10 @@ static const char *acpi_battery_units(const struct acpi_battery *battery) "mA" : "mW"; } -static int acpi_battery_print_info(struct seq_file *seq, int result) +static int acpi_battery_info_proc_show(struct seq_file *seq, void *offset) { struct acpi_battery *battery = seq->private; + int result = acpi_battery_update(battery, false); if (result) goto end; @@ -1041,9 +1050,10 @@ static int acpi_battery_print_info(struct seq_file *seq, int result) return result; } -static int acpi_battery_print_state(struct seq_file *seq, int result) +static int acpi_battery_state_proc_show(struct seq_file *seq, void *offset) { struct acpi_battery *battery = seq->private; + int result = acpi_battery_update(battery, false); if (result) goto end; @@ -1088,9 +1098,10 @@ static int acpi_battery_print_state(struct seq_file *seq, int result) return result; } -static int acpi_battery_print_alarm(struct seq_file *seq, int result) +static int acpi_battery_alarm_proc_show(struct seq_file *seq, void *offset) { struct acpi_battery *battery = seq->private; + int result = acpi_battery_update(battery, false); if (result) goto end; @@ -1142,82 +1153,22 @@ static ssize_t acpi_battery_write_alarm(struct file *file, return result; } -typedef int(*print_func)(struct seq_file *seq, int result); - -static print_func acpi_print_funcs[ACPI_BATTERY_NUMFILES] = { - acpi_battery_print_info, - acpi_battery_print_state, - acpi_battery_print_alarm, -}; - -static int acpi_battery_read(int fid, struct seq_file *seq) +static int acpi_battery_alarm_proc_open(struct inode *inode, struct file *file) { - struct acpi_battery *battery = seq->private; - int result = acpi_battery_update(battery, false); - return acpi_print_funcs[fid](seq, result); -} - -#define DECLARE_FILE_FUNCTIONS(_name) \ -static int acpi_battery_read_##_name(struct seq_file *seq, void *offset) \ -{ \ - return acpi_battery_read(_name##_tag, seq); \ -} \ -static int acpi_battery_##_name##_open_fs(struct inode *inode, struct file *file) \ -{ \ - return single_open(file, acpi_battery_read_##_name, PDE_DATA(inode)); \ + return single_open(file, acpi_battery_alarm_proc_show, PDE_DATA(inode)); } -DECLARE_FILE_FUNCTIONS(info); -DECLARE_FILE_FUNCTIONS(state); -DECLARE_FILE_FUNCTIONS(alarm); - -#undef DECLARE_FILE_FUNCTIONS - -#define FILE_DESCRIPTION_RO(_name) \ - { \ - .name = __stringify(_name), \ - .mode = S_IRUGO, \ - .ops = { \ - .open = acpi_battery_##_name##_open_fs, \ - .read = seq_read, \ - .llseek = seq_lseek, \ - .release = single_release, \ - .owner = THIS_MODULE, \ - }, \ - } - -#define FILE_DESCRIPTION_RW(_name) \ - { \ - .name = __stringify(_name), \ - .mode = S_IFREG | S_IRUGO | S_IWUSR, \ - .ops = { \ - .open = acpi_battery_##_name##_open_fs, \ - .read = seq_read, \ - .llseek = seq_lseek, \ - .write = acpi_battery_write_##_name, \ - .release = single_release, \ - .owner = THIS_MODULE, \ - }, \ - } - -static const struct battery_file { - struct file_operations ops; - umode_t mode; - const char *name; -} acpi_battery_file[] = { - FILE_DESCRIPTION_RO(info), - FILE_DESCRIPTION_RO(state), - FILE_DESCRIPTION_RW(alarm), +static const struct file_operations acpi_battery_alarm_fops = { + .owner = THIS_MODULE, + .open = acpi_battery_alarm_proc_open, + .read = seq_read, + .write = acpi_battery_write_alarm, + .llseek = seq_lseek, + .release = single_release, }; -#undef FILE_DESCRIPTION_RO -#undef FILE_DESCRIPTION_RW - static int acpi_battery_add_fs(struct acpi_device *device) { - struct proc_dir_entry *entry = NULL; - int i; - printk(KERN_WARNING PREFIX "Deprecated procfs I/F for battery is loaded," " please retry with CONFIG_ACPI_PROCFS_POWER cleared\n"); if (!acpi_device_dir(device)) { @@ -1227,28 +1178,24 @@ static int acpi_battery_add_fs(struct acpi_device *device) return -ENODEV; } - for (i = 0; i < ACPI_BATTERY_NUMFILES; ++i) { - entry = proc_create_data(acpi_battery_file[i].name, - acpi_battery_file[i].mode, - acpi_device_dir(device), - &acpi_battery_file[i].ops, - acpi_driver_data(device)); - if (!entry) - return -ENODEV; - } + if (!proc_create_single_data("info", S_IRUGO, acpi_device_dir(device), + acpi_battery_info_proc_show, acpi_driver_data(device))) + return -ENODEV; + if (!proc_create_single_data("state", S_IRUGO, acpi_device_dir(device), + acpi_battery_state_proc_show, acpi_driver_data(device))) + return -ENODEV; + if (!proc_create_data("alarm", S_IFREG | S_IRUGO | S_IWUSR, + acpi_device_dir(device), &acpi_battery_alarm_fops, + acpi_driver_data(device))) + return -ENODEV; return 0; } static void acpi_battery_remove_fs(struct acpi_device *device) { - int i; if (!acpi_device_dir(device)) return; - for (i = 0; i < ACPI_BATTERY_NUMFILES; ++i) - remove_proc_entry(acpi_battery_file[i].name, - acpi_device_dir(device)); - - remove_proc_entry(acpi_device_bid(device), acpi_battery_dir); + remove_proc_subtree(acpi_device_bid(device), acpi_battery_dir); acpi_device_dir(device) = NULL; } @@ -1332,23 +1279,64 @@ battery_notification_delay_quirk(const struct dmi_system_id *d) return 0; } +static int __init +battery_ac_is_broken_quirk(const struct dmi_system_id *d) +{ + battery_ac_is_broken = 1; + return 0; +} + +static int __init +battery_do_not_check_pmic_quirk(const struct dmi_system_id *d) +{ + battery_check_pmic = 0; + return 0; +} + static const struct dmi_system_id bat_dmi_table[] __initconst = { { + /* NEC LZ750/LS */ .callback = battery_bix_broken_package_quirk, - .ident = "NEC LZ750/LS", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "NEC"), DMI_MATCH(DMI_PRODUCT_NAME, "PC-LZ750LS"), }, }, { + /* Acer Aspire V5-573G */ .callback = battery_notification_delay_quirk, - .ident = "Acer Aspire V5-573G", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Acer"), DMI_MATCH(DMI_PRODUCT_NAME, "Aspire V5-573G"), }, }, + { + /* Point of View mobii wintab p800w */ + .callback = battery_ac_is_broken_quirk, + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "AMI Corporation"), + DMI_MATCH(DMI_BOARD_NAME, "Aptio CRB"), + DMI_MATCH(DMI_BIOS_VERSION, "3BAIR1013"), + /* Above matches are too generic, add bios-date match */ + DMI_MATCH(DMI_BIOS_DATE, "08/22/2014"), + }, + }, + { + /* ECS EF20EA */ + .callback = battery_do_not_check_pmic_quirk, + .matches = { + DMI_MATCH(DMI_PRODUCT_NAME, "EF20EA"), + }, + }, + { + /* Lenovo Ideapad Miix 320 */ + .callback = battery_do_not_check_pmic_quirk, + .matches = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "80XF"), + DMI_EXACT_MATCH(DMI_PRODUCT_VERSION, "Lenovo MIIX 320-10ICR"), + }, + }, {}, }; @@ -1488,16 +1476,18 @@ static void __init acpi_battery_init_async(void *unused, async_cookie_t cookie) unsigned int i; int result; - for (i = 0; i < ARRAY_SIZE(acpi_battery_blacklist); i++) - if (acpi_dev_present(acpi_battery_blacklist[i], "1", -1)) { - pr_info(PREFIX ACPI_BATTERY_DEVICE_NAME - ": found native %s PMIC, not loading\n", - acpi_battery_blacklist[i]); - return; - } - dmi_check_system(bat_dmi_table); + if (battery_check_pmic) { + for (i = 0; i < ARRAY_SIZE(acpi_battery_blacklist); i++) + if (acpi_dev_present(acpi_battery_blacklist[i], "1", -1)) { + pr_info(PREFIX ACPI_BATTERY_DEVICE_NAME + ": found native %s PMIC, not loading\n", + acpi_battery_blacklist[i]); + return; + } + } + #ifdef CONFIG_ACPI_PROCFS_POWER acpi_battery_dir = acpi_lock_battery_dir(); if (!acpi_battery_dir) diff --git a/drivers/acpi/button.c b/drivers/acpi/button.c index e1eee7a..2345a5e 100644 --- a/drivers/acpi/button.c +++ b/drivers/acpi/button.c @@ -263,19 +263,6 @@ static int acpi_button_state_seq_show(struct seq_file *seq, void *offset) return 0; } -static int acpi_button_state_open_fs(struct inode *inode, struct file *file) -{ - return single_open(file, acpi_button_state_seq_show, PDE_DATA(inode)); -} - -static const struct file_operations acpi_button_state_fops = { - .owner = THIS_MODULE, - .open = acpi_button_state_open_fs, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - static int acpi_button_add_fs(struct acpi_device *device) { struct acpi_button *button = acpi_driver_data(device); @@ -311,9 +298,9 @@ static int acpi_button_add_fs(struct acpi_device *device) } /* create /proc/acpi/button/lid/LID/state */ - entry = proc_create_data(ACPI_BUTTON_FILE_STATE, - S_IRUGO, acpi_device_dir(device), - &acpi_button_state_fops, device); + entry = proc_create_single_data(ACPI_BUTTON_FILE_STATE, S_IRUGO, + acpi_device_dir(device), acpi_button_state_seq_show, + device); if (!entry) { ret = -ENODEV; goto remove_dev_dir; @@ -635,4 +622,26 @@ module_param_call(lid_init_state, NULL, 0644); MODULE_PARM_DESC(lid_init_state, "Behavior for reporting LID initial state"); -module_acpi_driver(acpi_button_driver); +static int acpi_button_register_driver(struct acpi_driver *driver) +{ + /* + * Modules such as nouveau.ko and i915.ko have a link time dependency + * on acpi_lid_open(), and would therefore not be loadable on ACPI + * capable kernels booted in non-ACPI mode if the return value of + * acpi_bus_register_driver() is returned from here with ACPI disabled + * when this driver is built as a module. + */ + if (acpi_disabled) + return 0; + + return acpi_bus_register_driver(driver); +} + +static void acpi_button_unregister_driver(struct acpi_driver *driver) +{ + if (!acpi_disabled) + acpi_bus_unregister_driver(driver); +} + +module_driver(acpi_button_driver, acpi_button_register_driver, + acpi_button_unregister_driver); diff --git a/drivers/acpi/cppc_acpi.c b/drivers/acpi/cppc_acpi.c index 735c74a..d9ce4b1 100644 --- a/drivers/acpi/cppc_acpi.c +++ b/drivers/acpi/cppc_acpi.c @@ -39,6 +39,7 @@ #include <linux/cpufreq.h> #include <linux/delay.h> +#include <linux/iopoll.h> #include <linux/ktime.h> #include <linux/rwsem.h> #include <linux/wait.h> @@ -49,7 +50,7 @@ struct cppc_pcc_data { struct mbox_chan *pcc_channel; void __iomem *pcc_comm_addr; bool pcc_channel_acquired; - ktime_t deadline; + unsigned int deadline_us; unsigned int pcc_mpar, pcc_mrtt, pcc_nominal; bool pending_pcc_write_cmd; /* Any pending/batched PCC write cmds? */ @@ -156,6 +157,9 @@ show_cppc_data(cppc_get_perf_caps, cppc_perf_caps, highest_perf); show_cppc_data(cppc_get_perf_caps, cppc_perf_caps, lowest_perf); show_cppc_data(cppc_get_perf_caps, cppc_perf_caps, nominal_perf); show_cppc_data(cppc_get_perf_caps, cppc_perf_caps, lowest_nonlinear_perf); +show_cppc_data(cppc_get_perf_caps, cppc_perf_caps, lowest_freq); +show_cppc_data(cppc_get_perf_caps, cppc_perf_caps, nominal_freq); + show_cppc_data(cppc_get_perf_ctrs, cppc_perf_fb_ctrs, reference_perf); show_cppc_data(cppc_get_perf_ctrs, cppc_perf_fb_ctrs, wraparound_time); @@ -183,6 +187,8 @@ static struct attribute *cppc_attrs[] = { &lowest_perf.attr, &lowest_nonlinear_perf.attr, &nominal_perf.attr, + &nominal_freq.attr, + &lowest_freq.attr, NULL }; @@ -193,42 +199,31 @@ static struct kobj_type cppc_ktype = { static int check_pcc_chan(int pcc_ss_id, bool chk_err_bit) { - int ret = -EIO, status = 0; + int ret, status; struct cppc_pcc_data *pcc_ss_data = pcc_data[pcc_ss_id]; struct acpi_pcct_shared_memory __iomem *generic_comm_base = pcc_ss_data->pcc_comm_addr; - ktime_t next_deadline = ktime_add(ktime_get(), - pcc_ss_data->deadline); if (!pcc_ss_data->platform_owns_pcc) return 0; - /* Retry in case the remote processor was too slow to catch up. */ - while (!ktime_after(ktime_get(), next_deadline)) { - /* - * Per spec, prior to boot the PCC space wil be initialized by - * platform and should have set the command completion bit when - * PCC can be used by OSPM - */ - status = readw_relaxed(&generic_comm_base->status); - if (status & PCC_CMD_COMPLETE_MASK) { - ret = 0; - if (chk_err_bit && (status & PCC_ERROR_MASK)) - ret = -EIO; - break; - } - /* - * Reducing the bus traffic in case this loop takes longer than - * a few retries. - */ - udelay(3); - } + /* + * Poll PCC status register every 3us(delay_us) for maximum of + * deadline_us(timeout_us) until PCC command complete bit is set(cond) + */ + ret = readw_relaxed_poll_timeout(&generic_comm_base->status, status, + status & PCC_CMD_COMPLETE_MASK, 3, + pcc_ss_data->deadline_us); - if (likely(!ret)) + if (likely(!ret)) { pcc_ss_data->platform_owns_pcc = false; - else - pr_err("PCC check channel failed for ss: %d. Status=%x\n", - pcc_ss_id, status); + if (chk_err_bit && (status & PCC_ERROR_MASK)) + ret = -EIO; + } + + if (unlikely(ret)) + pr_err("PCC check channel failed for ss: %d. ret=%d\n", + pcc_ss_id, ret); return ret; } @@ -580,7 +575,7 @@ static int register_pcc_channel(int pcc_ss_idx) * So add an arbitrary amount of wait on top of Nominal. */ usecs_lat = NUM_RETRIES * cppc_ss->latency; - pcc_data[pcc_ss_idx]->deadline = ns_to_ktime(usecs_lat * NSEC_PER_USEC); + pcc_data[pcc_ss_idx]->deadline_us = usecs_lat; pcc_data[pcc_ss_idx]->pcc_mrtt = cppc_ss->min_turnaround_time; pcc_data[pcc_ss_idx]->pcc_mpar = cppc_ss->max_access_rate; pcc_data[pcc_ss_idx]->pcc_nominal = cppc_ss->latency; @@ -613,7 +608,6 @@ bool __weak cpc_ffh_supported(void) return false; } - /** * pcc_data_alloc() - Allocate the pcc_data memory for pcc subspace * @@ -641,6 +635,34 @@ int pcc_data_alloc(int pcc_ss_id) return 0; } + +/* Check if CPPC revision + num_ent combination is supported */ +static bool is_cppc_supported(int revision, int num_ent) +{ + int expected_num_ent; + + switch (revision) { + case CPPC_V2_REV: + expected_num_ent = CPPC_V2_NUM_ENT; + break; + case CPPC_V3_REV: + expected_num_ent = CPPC_V3_NUM_ENT; + break; + default: + pr_debug("Firmware exports unsupported CPPC revision: %d\n", + revision); + return false; + } + + if (expected_num_ent != num_ent) { + pr_debug("Firmware exports %d entries. Expected: %d for CPPC rev:%d\n", + num_ent, expected_num_ent, revision); + return false; + } + + return true; +} + /* * An example CPC table looks like the following. * @@ -731,14 +753,6 @@ int acpi_cppc_processor_probe(struct acpi_processor *pr) cpc_obj->type); goto out_free; } - - /* Only support CPPCv2. Bail otherwise. */ - if (num_ent != CPPC_NUM_ENT) { - pr_debug("Firmware exports %d entries. Expected: %d\n", - num_ent, CPPC_NUM_ENT); - goto out_free; - } - cpc_ptr->num_entries = num_ent; /* Second entry should be revision. */ @@ -750,12 +764,10 @@ int acpi_cppc_processor_probe(struct acpi_processor *pr) cpc_obj->type); goto out_free; } + cpc_ptr->version = cpc_rev; - if (cpc_rev != CPPC_REV) { - pr_debug("Firmware exports revision:%d. Expected:%d\n", - cpc_rev, CPPC_REV); + if (!is_cppc_supported(cpc_rev, num_ent)) goto out_free; - } /* Iterate through remaining entries in _CPC */ for (i = 2; i < num_ent; i++) { @@ -808,6 +820,18 @@ int acpi_cppc_processor_probe(struct acpi_processor *pr) } } per_cpu(cpu_pcc_subspace_idx, pr->id) = pcc_subspace_id; + + /* + * Initialize the remaining cpc_regs as unsupported. + * Example: In case FW exposes CPPC v2, the below loop will initialize + * LOWEST_FREQ and NOMINAL_FREQ regs as unsupported + */ + for (i = num_ent - 2; i < MAX_CPC_REG_ENT; i++) { + cpc_ptr->cpc_regs[i].type = ACPI_TYPE_INTEGER; + cpc_ptr->cpc_regs[i].cpc_entry.int_value = 0; + } + + /* Store CPU Logical ID */ cpc_ptr->cpu_id = pr->id; @@ -1037,26 +1061,34 @@ int cppc_get_perf_caps(int cpunum, struct cppc_perf_caps *perf_caps) { struct cpc_desc *cpc_desc = per_cpu(cpc_desc_ptr, cpunum); struct cpc_register_resource *highest_reg, *lowest_reg, - *lowest_non_linear_reg, *nominal_reg; - u64 high, low, nom, min_nonlinear; + *lowest_non_linear_reg, *nominal_reg, + *low_freq_reg = NULL, *nom_freq_reg = NULL; + u64 high, low, nom, min_nonlinear, low_f = 0, nom_f = 0; int pcc_ss_id = per_cpu(cpu_pcc_subspace_idx, cpunum); - struct cppc_pcc_data *pcc_ss_data; + struct cppc_pcc_data *pcc_ss_data = NULL; int ret = 0, regs_in_pcc = 0; - if (!cpc_desc || pcc_ss_id < 0) { + if (!cpc_desc) { pr_debug("No CPC descriptor for CPU:%d\n", cpunum); return -ENODEV; } - pcc_ss_data = pcc_data[pcc_ss_id]; highest_reg = &cpc_desc->cpc_regs[HIGHEST_PERF]; lowest_reg = &cpc_desc->cpc_regs[LOWEST_PERF]; lowest_non_linear_reg = &cpc_desc->cpc_regs[LOW_NON_LINEAR_PERF]; nominal_reg = &cpc_desc->cpc_regs[NOMINAL_PERF]; + low_freq_reg = &cpc_desc->cpc_regs[LOWEST_FREQ]; + nom_freq_reg = &cpc_desc->cpc_regs[NOMINAL_FREQ]; /* Are any of the regs PCC ?*/ if (CPC_IN_PCC(highest_reg) || CPC_IN_PCC(lowest_reg) || - CPC_IN_PCC(lowest_non_linear_reg) || CPC_IN_PCC(nominal_reg)) { + CPC_IN_PCC(lowest_non_linear_reg) || CPC_IN_PCC(nominal_reg) || + CPC_IN_PCC(low_freq_reg) || CPC_IN_PCC(nom_freq_reg)) { + if (pcc_ss_id < 0) { + pr_debug("Invalid pcc_ss_id\n"); + return -ENODEV; + } + pcc_ss_data = pcc_data[pcc_ss_id]; regs_in_pcc = 1; down_write(&pcc_ss_data->pcc_lock); /* Ring doorbell once to update PCC subspace */ @@ -1081,6 +1113,17 @@ int cppc_get_perf_caps(int cpunum, struct cppc_perf_caps *perf_caps) if (!high || !low || !nom || !min_nonlinear) ret = -EFAULT; + /* Read optional lowest and nominal frequencies if present */ + if (CPC_SUPPORTED(low_freq_reg)) + cpc_read(cpunum, low_freq_reg, &low_f); + + if (CPC_SUPPORTED(nom_freq_reg)) + cpc_read(cpunum, nom_freq_reg, &nom_f); + + perf_caps->lowest_freq = low_f; + perf_caps->nominal_freq = nom_f; + + out_err: if (regs_in_pcc) up_write(&pcc_ss_data->pcc_lock); @@ -1101,16 +1144,15 @@ int cppc_get_perf_ctrs(int cpunum, struct cppc_perf_fb_ctrs *perf_fb_ctrs) struct cpc_register_resource *delivered_reg, *reference_reg, *ref_perf_reg, *ctr_wrap_reg; int pcc_ss_id = per_cpu(cpu_pcc_subspace_idx, cpunum); - struct cppc_pcc_data *pcc_ss_data; + struct cppc_pcc_data *pcc_ss_data = NULL; u64 delivered, reference, ref_perf, ctr_wrap_time; int ret = 0, regs_in_pcc = 0; - if (!cpc_desc || pcc_ss_id < 0) { + if (!cpc_desc) { pr_debug("No CPC descriptor for CPU:%d\n", cpunum); return -ENODEV; } - pcc_ss_data = pcc_data[pcc_ss_id]; delivered_reg = &cpc_desc->cpc_regs[DELIVERED_CTR]; reference_reg = &cpc_desc->cpc_regs[REFERENCE_CTR]; ref_perf_reg = &cpc_desc->cpc_regs[REFERENCE_PERF]; @@ -1126,6 +1168,11 @@ int cppc_get_perf_ctrs(int cpunum, struct cppc_perf_fb_ctrs *perf_fb_ctrs) /* Are any of the regs PCC ?*/ if (CPC_IN_PCC(delivered_reg) || CPC_IN_PCC(reference_reg) || CPC_IN_PCC(ctr_wrap_reg) || CPC_IN_PCC(ref_perf_reg)) { + if (pcc_ss_id < 0) { + pr_debug("Invalid pcc_ss_id\n"); + return -ENODEV; + } + pcc_ss_data = pcc_data[pcc_ss_id]; down_write(&pcc_ss_data->pcc_lock); regs_in_pcc = 1; /* Ring doorbell once to update PCC subspace */ @@ -1176,15 +1223,14 @@ int cppc_set_perf(int cpu, struct cppc_perf_ctrls *perf_ctrls) struct cpc_desc *cpc_desc = per_cpu(cpc_desc_ptr, cpu); struct cpc_register_resource *desired_reg; int pcc_ss_id = per_cpu(cpu_pcc_subspace_idx, cpu); - struct cppc_pcc_data *pcc_ss_data; + struct cppc_pcc_data *pcc_ss_data = NULL; int ret = 0; - if (!cpc_desc || pcc_ss_id < 0) { + if (!cpc_desc) { pr_debug("No CPC descriptor for CPU:%d\n", cpu); return -ENODEV; } - pcc_ss_data = pcc_data[pcc_ss_id]; desired_reg = &cpc_desc->cpc_regs[DESIRED_PERF]; /* @@ -1195,6 +1241,11 @@ int cppc_set_perf(int cpu, struct cppc_perf_ctrls *perf_ctrls) * achieve that goal here */ if (CPC_IN_PCC(desired_reg)) { + if (pcc_ss_id < 0) { + pr_debug("Invalid pcc_ss_id\n"); + return -ENODEV; + } + pcc_ss_data = pcc_data[pcc_ss_id]; down_read(&pcc_ss_data->pcc_lock); /* BEGIN Phase-I */ if (pcc_ss_data->platform_owns_pcc) { ret = check_pcc_chan(pcc_ss_id, false); diff --git a/drivers/acpi/device_pm.c b/drivers/acpi/device_pm.c index 3d96e4d..a7c2673 100644 --- a/drivers/acpi/device_pm.c +++ b/drivers/acpi/device_pm.c @@ -1257,10 +1257,7 @@ int acpi_dev_pm_attach(struct device *dev, bool power_on) struct acpi_device *adev = ACPI_COMPANION(dev); if (!adev) - return -ENODEV; - - if (dev->pm_domain) - return -EEXIST; + return 0; /* * Only attach the power domain to the first device if the @@ -1268,7 +1265,7 @@ int acpi_dev_pm_attach(struct device *dev, bool power_on) * management twice. */ if (!acpi_device_is_first_physical_node(adev, dev)) - return -EBUSY; + return 0; acpi_add_pm_notifier(adev, dev, acpi_pm_notify_work_func); dev_pm_domain_set(dev, &acpi_general_pm_domain); @@ -1278,7 +1275,7 @@ int acpi_dev_pm_attach(struct device *dev, bool power_on) } dev->pm_domain->detach = acpi_dev_pm_detach; - return 0; + return 1; } EXPORT_SYMBOL_GPL(acpi_dev_pm_attach); #endif /* CONFIG_PM */ diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index 30a5729..bb94cf0 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -1034,6 +1034,12 @@ void acpi_ec_unblock_transactions(void) acpi_ec_start(first_ec, true); } +void acpi_ec_dispatch_gpe(void) +{ + if (first_ec) + acpi_dispatch_gpe(NULL, first_ec->gpe); +} + /* -------------------------------------------------------------------------- Event Management -------------------------------------------------------------------------- */ diff --git a/drivers/acpi/fan.c b/drivers/acpi/fan.c index 3563103..fe0183d 100644 --- a/drivers/acpi/fan.c +++ b/drivers/acpi/fan.c @@ -298,8 +298,8 @@ static int acpi_fan_get_fps(struct acpi_device *device) } fan->fps_count = obj->package.count - 1; /* minus revision field */ - fan->fps = devm_kzalloc(&device->dev, - fan->fps_count * sizeof(struct acpi_fan_fps), + fan->fps = devm_kcalloc(&device->dev, + fan->fps_count, sizeof(struct acpi_fan_fps), GFP_KERNEL); if (!fan->fps) { dev_err(&device->dev, "Not enough memory\n"); diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h index 1d0a501..530a3f6 100644 --- a/drivers/acpi/internal.h +++ b/drivers/acpi/internal.h @@ -188,6 +188,7 @@ int acpi_ec_ecdt_probe(void); int acpi_ec_dsdt_probe(void); void acpi_ec_block_transactions(void); void acpi_ec_unblock_transactions(void); +void acpi_ec_dispatch_gpe(void); int acpi_ec_add_query_handler(struct acpi_ec *ec, u8 query_bit, acpi_handle handle, acpi_ec_query_func func, void *data); diff --git a/drivers/acpi/nfit/core.c b/drivers/acpi/nfit/core.c index e2235ed..d15814e 100644 --- a/drivers/acpi/nfit/core.c +++ b/drivers/acpi/nfit/core.c @@ -1082,9 +1082,10 @@ static int __nfit_mem_init(struct acpi_nfit_desc *acpi_desc, continue; nfit_mem->nfit_flush = nfit_flush; flush = nfit_flush->flush; - nfit_mem->flush_wpq = devm_kzalloc(acpi_desc->dev, - flush->hint_count - * sizeof(struct resource), GFP_KERNEL); + nfit_mem->flush_wpq = devm_kcalloc(acpi_desc->dev, + flush->hint_count, + sizeof(struct resource), + GFP_KERNEL); if (!nfit_mem->flush_wpq) return -ENOMEM; for (i = 0; i < flush->hint_count; i++) { @@ -1978,19 +1979,8 @@ static ssize_t range_index_show(struct device *dev, } static DEVICE_ATTR_RO(range_index); -static ssize_t ecc_unit_size_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct nd_region *nd_region = to_nd_region(dev); - struct nfit_spa *nfit_spa = nd_region_provider_data(nd_region); - - return sprintf(buf, "%d\n", nfit_spa->clear_err_unit); -} -static DEVICE_ATTR_RO(ecc_unit_size); - static struct attribute *acpi_nfit_region_attributes[] = { &dev_attr_range_index.attr, - &dev_attr_ecc_unit_size.attr, NULL, }; diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c index 0da18bd..7433035 100644 --- a/drivers/acpi/pci_root.c +++ b/drivers/acpi/pci_root.c @@ -153,6 +153,7 @@ static struct pci_osc_bit_struct pci_osc_control_bit[] = { { OSC_PCI_EXPRESS_PME_CONTROL, "PME" }, { OSC_PCI_EXPRESS_AER_CONTROL, "AER" }, { OSC_PCI_EXPRESS_CAPABILITY_CONTROL, "PCIeCapability" }, + { OSC_PCI_EXPRESS_LTR_CONTROL, "LTR" }, }; static void decode_osc_bits(struct acpi_pci_root *root, char *msg, u32 word, @@ -472,9 +473,17 @@ static void negotiate_os_control(struct acpi_pci_root *root, int *no_aspm) } control = OSC_PCI_EXPRESS_CAPABILITY_CONTROL - | OSC_PCI_EXPRESS_NATIVE_HP_CONTROL | OSC_PCI_EXPRESS_PME_CONTROL; + if (IS_ENABLED(CONFIG_PCIEASPM)) + control |= OSC_PCI_EXPRESS_LTR_CONTROL; + + if (IS_ENABLED(CONFIG_HOTPLUG_PCI_PCIE)) + control |= OSC_PCI_EXPRESS_NATIVE_HP_CONTROL; + + if (IS_ENABLED(CONFIG_HOTPLUG_PCI_SHPC)) + control |= OSC_PCI_SHPC_NATIVE_HP_CONTROL; + if (pci_aer_available()) { if (aer_acpi_firmware_first()) dev_info(&device->dev, @@ -900,11 +909,15 @@ struct pci_bus *acpi_pci_root_create(struct acpi_pci_root *root, host_bridge = to_pci_host_bridge(bus->bridge); if (!(root->osc_control_set & OSC_PCI_EXPRESS_NATIVE_HP_CONTROL)) - host_bridge->native_hotplug = 0; + host_bridge->native_pcie_hotplug = 0; + if (!(root->osc_control_set & OSC_PCI_SHPC_NATIVE_HP_CONTROL)) + host_bridge->native_shpc_hotplug = 0; if (!(root->osc_control_set & OSC_PCI_EXPRESS_AER_CONTROL)) host_bridge->native_aer = 0; if (!(root->osc_control_set & OSC_PCI_EXPRESS_PME_CONTROL)) host_bridge->native_pme = 0; + if (!(root->osc_control_set & OSC_PCI_EXPRESS_LTR_CONTROL)) + host_bridge->native_ltr = 0; pci_scan_child_bus(bus); pci_set_host_bridge_release(host_bridge, acpi_pci_root_release_info, diff --git a/drivers/acpi/pptt.c b/drivers/acpi/pptt.c new file mode 100644 index 0000000..e5ea197 --- /dev/null +++ b/drivers/acpi/pptt.c @@ -0,0 +1,655 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * pptt.c - parsing of Processor Properties Topology Table (PPTT) + * + * Copyright (C) 2018, ARM + * + * This file implements parsing of the Processor Properties Topology Table + * which is optionally used to describe the processor and cache topology. + * Due to the relative pointers used throughout the table, this doesn't + * leverage the existing subtable parsing in the kernel. + * + * The PPTT structure is an inverted tree, with each node potentially + * holding one or two inverted tree data structures describing + * the caches available at that level. Each cache structure optionally + * contains properties describing the cache at a given level which can be + * used to override hardware probed values. + */ +#define pr_fmt(fmt) "ACPI PPTT: " fmt + +#include <linux/acpi.h> +#include <linux/cacheinfo.h> +#include <acpi/processor.h> + +static struct acpi_subtable_header *fetch_pptt_subtable(struct acpi_table_header *table_hdr, + u32 pptt_ref) +{ + struct acpi_subtable_header *entry; + + /* there isn't a subtable at reference 0 */ + if (pptt_ref < sizeof(struct acpi_subtable_header)) + return NULL; + + if (pptt_ref + sizeof(struct acpi_subtable_header) > table_hdr->length) + return NULL; + + entry = ACPI_ADD_PTR(struct acpi_subtable_header, table_hdr, pptt_ref); + + if (entry->length == 0) + return NULL; + + if (pptt_ref + entry->length > table_hdr->length) + return NULL; + + return entry; +} + +static struct acpi_pptt_processor *fetch_pptt_node(struct acpi_table_header *table_hdr, + u32 pptt_ref) +{ + return (struct acpi_pptt_processor *)fetch_pptt_subtable(table_hdr, pptt_ref); +} + +static struct acpi_pptt_cache *fetch_pptt_cache(struct acpi_table_header *table_hdr, + u32 pptt_ref) +{ + return (struct acpi_pptt_cache *)fetch_pptt_subtable(table_hdr, pptt_ref); +} + +static struct acpi_subtable_header *acpi_get_pptt_resource(struct acpi_table_header *table_hdr, + struct acpi_pptt_processor *node, + int resource) +{ + u32 *ref; + + if (resource >= node->number_of_priv_resources) + return NULL; + + ref = ACPI_ADD_PTR(u32, node, sizeof(struct acpi_pptt_processor)); + ref += resource; + + return fetch_pptt_subtable(table_hdr, *ref); +} + +static inline bool acpi_pptt_match_type(int table_type, int type) +{ + return ((table_type & ACPI_PPTT_MASK_CACHE_TYPE) == type || + table_type & ACPI_PPTT_CACHE_TYPE_UNIFIED & type); +} + +/** + * acpi_pptt_walk_cache() - Attempt to find the requested acpi_pptt_cache + * @table_hdr: Pointer to the head of the PPTT table + * @local_level: passed res reflects this cache level + * @res: cache resource in the PPTT we want to walk + * @found: returns a pointer to the requested level if found + * @level: the requested cache level + * @type: the requested cache type + * + * Attempt to find a given cache level, while counting the max number + * of cache levels for the cache node. + * + * Given a pptt resource, verify that it is a cache node, then walk + * down each level of caches, counting how many levels are found + * as well as checking the cache type (icache, dcache, unified). If a + * level & type match, then we set found, and continue the search. + * Once the entire cache branch has been walked return its max + * depth. + * + * Return: The cache structure and the level we terminated with. + */ +static int acpi_pptt_walk_cache(struct acpi_table_header *table_hdr, + int local_level, + struct acpi_subtable_header *res, + struct acpi_pptt_cache **found, + int level, int type) +{ + struct acpi_pptt_cache *cache; + + if (res->type != ACPI_PPTT_TYPE_CACHE) + return 0; + + cache = (struct acpi_pptt_cache *) res; + while (cache) { + local_level++; + + if (local_level == level && + cache->flags & ACPI_PPTT_CACHE_TYPE_VALID && + acpi_pptt_match_type(cache->attributes, type)) { + if (*found != NULL && cache != *found) + pr_warn("Found duplicate cache level/type unable to determine uniqueness\n"); + + pr_debug("Found cache @ level %d\n", level); + *found = cache; + /* + * continue looking at this node's resource list + * to verify that we don't find a duplicate + * cache node. + */ + } + cache = fetch_pptt_cache(table_hdr, cache->next_level_of_cache); + } + return local_level; +} + +static struct acpi_pptt_cache *acpi_find_cache_level(struct acpi_table_header *table_hdr, + struct acpi_pptt_processor *cpu_node, + int *starting_level, int level, + int type) +{ + struct acpi_subtable_header *res; + int number_of_levels = *starting_level; + int resource = 0; + struct acpi_pptt_cache *ret = NULL; + int local_level; + + /* walk down from processor node */ + while ((res = acpi_get_pptt_resource(table_hdr, cpu_node, resource))) { + resource++; + + local_level = acpi_pptt_walk_cache(table_hdr, *starting_level, + res, &ret, level, type); + /* + * we are looking for the max depth. Since its potentially + * possible for a given node to have resources with differing + * depths verify that the depth we have found is the largest. + */ + if (number_of_levels < local_level) + number_of_levels = local_level; + } + if (number_of_levels > *starting_level) + *starting_level = number_of_levels; + + return ret; +} + +/** + * acpi_count_levels() - Given a PPTT table, and a cpu node, count the caches + * @table_hdr: Pointer to the head of the PPTT table + * @cpu_node: processor node we wish to count caches for + * + * Given a processor node containing a processing unit, walk into it and count + * how many levels exist solely for it, and then walk up each level until we hit + * the root node (ignore the package level because it may be possible to have + * caches that exist across packages). Count the number of cache levels that + * exist at each level on the way up. + * + * Return: Total number of levels found. + */ +static int acpi_count_levels(struct acpi_table_header *table_hdr, + struct acpi_pptt_processor *cpu_node) +{ + int total_levels = 0; + + do { + acpi_find_cache_level(table_hdr, cpu_node, &total_levels, 0, 0); + cpu_node = fetch_pptt_node(table_hdr, cpu_node->parent); + } while (cpu_node); + + return total_levels; +} + +/** + * acpi_pptt_leaf_node() - Given a processor node, determine if its a leaf + * @table_hdr: Pointer to the head of the PPTT table + * @node: passed node is checked to see if its a leaf + * + * Determine if the *node parameter is a leaf node by iterating the + * PPTT table, looking for nodes which reference it. + * + * Return: 0 if we find a node referencing the passed node (or table error), + * or 1 if we don't. + */ +static int acpi_pptt_leaf_node(struct acpi_table_header *table_hdr, + struct acpi_pptt_processor *node) +{ + struct acpi_subtable_header *entry; + unsigned long table_end; + u32 node_entry; + struct acpi_pptt_processor *cpu_node; + u32 proc_sz; + + table_end = (unsigned long)table_hdr + table_hdr->length; + node_entry = ACPI_PTR_DIFF(node, table_hdr); + entry = ACPI_ADD_PTR(struct acpi_subtable_header, table_hdr, + sizeof(struct acpi_table_pptt)); + proc_sz = sizeof(struct acpi_pptt_processor *); + + while ((unsigned long)entry + proc_sz < table_end) { + cpu_node = (struct acpi_pptt_processor *)entry; + if (entry->type == ACPI_PPTT_TYPE_PROCESSOR && + cpu_node->parent == node_entry) + return 0; + if (entry->length == 0) + return 0; + entry = ACPI_ADD_PTR(struct acpi_subtable_header, entry, + entry->length); + + } + return 1; +} + +/** + * acpi_find_processor_node() - Given a PPTT table find the requested processor + * @table_hdr: Pointer to the head of the PPTT table + * @acpi_cpu_id: cpu we are searching for + * + * Find the subtable entry describing the provided processor. + * This is done by iterating the PPTT table looking for processor nodes + * which have an acpi_processor_id that matches the acpi_cpu_id parameter + * passed into the function. If we find a node that matches this criteria + * we verify that its a leaf node in the topology rather than depending + * on the valid flag, which doesn't need to be set for leaf nodes. + * + * Return: NULL, or the processors acpi_pptt_processor* + */ +static struct acpi_pptt_processor *acpi_find_processor_node(struct acpi_table_header *table_hdr, + u32 acpi_cpu_id) +{ + struct acpi_subtable_header *entry; + unsigned long table_end; + struct acpi_pptt_processor *cpu_node; + u32 proc_sz; + + table_end = (unsigned long)table_hdr + table_hdr->length; + entry = ACPI_ADD_PTR(struct acpi_subtable_header, table_hdr, + sizeof(struct acpi_table_pptt)); + proc_sz = sizeof(struct acpi_pptt_processor *); + + /* find the processor structure associated with this cpuid */ + while ((unsigned long)entry + proc_sz < table_end) { + cpu_node = (struct acpi_pptt_processor *)entry; + + if (entry->length == 0) { + pr_warn("Invalid zero length subtable\n"); + break; + } + if (entry->type == ACPI_PPTT_TYPE_PROCESSOR && + acpi_cpu_id == cpu_node->acpi_processor_id && + acpi_pptt_leaf_node(table_hdr, cpu_node)) { + return (struct acpi_pptt_processor *)entry; + } + + entry = ACPI_ADD_PTR(struct acpi_subtable_header, entry, + entry->length); + } + + return NULL; +} + +static int acpi_find_cache_levels(struct acpi_table_header *table_hdr, + u32 acpi_cpu_id) +{ + int number_of_levels = 0; + struct acpi_pptt_processor *cpu; + + cpu = acpi_find_processor_node(table_hdr, acpi_cpu_id); + if (cpu) + number_of_levels = acpi_count_levels(table_hdr, cpu); + + return number_of_levels; +} + +static u8 acpi_cache_type(enum cache_type type) +{ + switch (type) { + case CACHE_TYPE_DATA: + pr_debug("Looking for data cache\n"); + return ACPI_PPTT_CACHE_TYPE_DATA; + case CACHE_TYPE_INST: + pr_debug("Looking for instruction cache\n"); + return ACPI_PPTT_CACHE_TYPE_INSTR; + default: + case CACHE_TYPE_UNIFIED: + pr_debug("Looking for unified cache\n"); + /* + * It is important that ACPI_PPTT_CACHE_TYPE_UNIFIED + * contains the bit pattern that will match both + * ACPI unified bit patterns because we use it later + * to match both cases. + */ + return ACPI_PPTT_CACHE_TYPE_UNIFIED; + } +} + +static struct acpi_pptt_cache *acpi_find_cache_node(struct acpi_table_header *table_hdr, + u32 acpi_cpu_id, + enum cache_type type, + unsigned int level, + struct acpi_pptt_processor **node) +{ + int total_levels = 0; + struct acpi_pptt_cache *found = NULL; + struct acpi_pptt_processor *cpu_node; + u8 acpi_type = acpi_cache_type(type); + + pr_debug("Looking for CPU %d's level %d cache type %d\n", + acpi_cpu_id, level, acpi_type); + + cpu_node = acpi_find_processor_node(table_hdr, acpi_cpu_id); + + while (cpu_node && !found) { + found = acpi_find_cache_level(table_hdr, cpu_node, + &total_levels, level, acpi_type); + *node = cpu_node; + cpu_node = fetch_pptt_node(table_hdr, cpu_node->parent); + } + + return found; +} + +/* total number of attributes checked by the properties code */ +#define PPTT_CHECKED_ATTRIBUTES 4 + +/** + * update_cache_properties() - Update cacheinfo for the given processor + * @this_leaf: Kernel cache info structure being updated + * @found_cache: The PPTT node describing this cache instance + * @cpu_node: A unique reference to describe this cache instance + * + * The ACPI spec implies that the fields in the cache structures are used to + * extend and correct the information probed from the hardware. Lets only + * set fields that we determine are VALID. + * + * Return: nothing. Side effect of updating the global cacheinfo + */ +static void update_cache_properties(struct cacheinfo *this_leaf, + struct acpi_pptt_cache *found_cache, + struct acpi_pptt_processor *cpu_node) +{ + int valid_flags = 0; + + this_leaf->fw_token = cpu_node; + if (found_cache->flags & ACPI_PPTT_SIZE_PROPERTY_VALID) { + this_leaf->size = found_cache->size; + valid_flags++; + } + if (found_cache->flags & ACPI_PPTT_LINE_SIZE_VALID) { + this_leaf->coherency_line_size = found_cache->line_size; + valid_flags++; + } + if (found_cache->flags & ACPI_PPTT_NUMBER_OF_SETS_VALID) { + this_leaf->number_of_sets = found_cache->number_of_sets; + valid_flags++; + } + if (found_cache->flags & ACPI_PPTT_ASSOCIATIVITY_VALID) { + this_leaf->ways_of_associativity = found_cache->associativity; + valid_flags++; + } + if (found_cache->flags & ACPI_PPTT_WRITE_POLICY_VALID) { + switch (found_cache->attributes & ACPI_PPTT_MASK_WRITE_POLICY) { + case ACPI_PPTT_CACHE_POLICY_WT: + this_leaf->attributes = CACHE_WRITE_THROUGH; + break; + case ACPI_PPTT_CACHE_POLICY_WB: + this_leaf->attributes = CACHE_WRITE_BACK; + break; + } + } + if (found_cache->flags & ACPI_PPTT_ALLOCATION_TYPE_VALID) { + switch (found_cache->attributes & ACPI_PPTT_MASK_ALLOCATION_TYPE) { + case ACPI_PPTT_CACHE_READ_ALLOCATE: + this_leaf->attributes |= CACHE_READ_ALLOCATE; + break; + case ACPI_PPTT_CACHE_WRITE_ALLOCATE: + this_leaf->attributes |= CACHE_WRITE_ALLOCATE; + break; + case ACPI_PPTT_CACHE_RW_ALLOCATE: + case ACPI_PPTT_CACHE_RW_ALLOCATE_ALT: + this_leaf->attributes |= + CACHE_READ_ALLOCATE | CACHE_WRITE_ALLOCATE; + break; + } + } + /* + * If the above flags are valid, and the cache type is NOCACHE + * update the cache type as well. + */ + if (this_leaf->type == CACHE_TYPE_NOCACHE && + valid_flags == PPTT_CHECKED_ATTRIBUTES) + this_leaf->type = CACHE_TYPE_UNIFIED; +} + +static void cache_setup_acpi_cpu(struct acpi_table_header *table, + unsigned int cpu) +{ + struct acpi_pptt_cache *found_cache; + struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu); + u32 acpi_cpu_id = get_acpi_id_for_cpu(cpu); + struct cacheinfo *this_leaf; + unsigned int index = 0; + struct acpi_pptt_processor *cpu_node = NULL; + + while (index < get_cpu_cacheinfo(cpu)->num_leaves) { + this_leaf = this_cpu_ci->info_list + index; + found_cache = acpi_find_cache_node(table, acpi_cpu_id, + this_leaf->type, + this_leaf->level, + &cpu_node); + pr_debug("found = %p %p\n", found_cache, cpu_node); + if (found_cache) + update_cache_properties(this_leaf, + found_cache, + cpu_node); + + index++; + } +} + +/* Passing level values greater than this will result in search termination */ +#define PPTT_ABORT_PACKAGE 0xFF + +static struct acpi_pptt_processor *acpi_find_processor_package_id(struct acpi_table_header *table_hdr, + struct acpi_pptt_processor *cpu, + int level, int flag) +{ + struct acpi_pptt_processor *prev_node; + + while (cpu && level) { + if (cpu->flags & flag) + break; + pr_debug("level %d\n", level); + prev_node = fetch_pptt_node(table_hdr, cpu->parent); + if (prev_node == NULL) + break; + cpu = prev_node; + level--; + } + return cpu; +} + +/** + * topology_get_acpi_cpu_tag() - Find a unique topology value for a feature + * @table: Pointer to the head of the PPTT table + * @cpu: Kernel logical cpu number + * @level: A level that terminates the search + * @flag: A flag which terminates the search + * + * Get a unique value given a cpu, and a topology level, that can be + * matched to determine which cpus share common topological features + * at that level. + * + * Return: Unique value, or -ENOENT if unable to locate cpu + */ +static int topology_get_acpi_cpu_tag(struct acpi_table_header *table, + unsigned int cpu, int level, int flag) +{ + struct acpi_pptt_processor *cpu_node; + u32 acpi_cpu_id = get_acpi_id_for_cpu(cpu); + + cpu_node = acpi_find_processor_node(table, acpi_cpu_id); + if (cpu_node) { + cpu_node = acpi_find_processor_package_id(table, cpu_node, + level, flag); + /* Only the first level has a guaranteed id */ + if (level == 0) + return cpu_node->acpi_processor_id; + return ACPI_PTR_DIFF(cpu_node, table); + } + pr_warn_once("PPTT table found, but unable to locate core %d (%d)\n", + cpu, acpi_cpu_id); + return -ENOENT; +} + +static int find_acpi_cpu_topology_tag(unsigned int cpu, int level, int flag) +{ + struct acpi_table_header *table; + acpi_status status; + int retval; + + status = acpi_get_table(ACPI_SIG_PPTT, 0, &table); + if (ACPI_FAILURE(status)) { + pr_warn_once("No PPTT table found, cpu topology may be inaccurate\n"); + return -ENOENT; + } + retval = topology_get_acpi_cpu_tag(table, cpu, level, flag); + pr_debug("Topology Setup ACPI cpu %d, level %d ret = %d\n", + cpu, level, retval); + acpi_put_table(table); + + return retval; +} + +/** + * acpi_find_last_cache_level() - Determines the number of cache levels for a PE + * @cpu: Kernel logical cpu number + * + * Given a logical cpu number, returns the number of levels of cache represented + * in the PPTT. Errors caused by lack of a PPTT table, or otherwise, return 0 + * indicating we didn't find any cache levels. + * + * Return: Cache levels visible to this core. + */ +int acpi_find_last_cache_level(unsigned int cpu) +{ + u32 acpi_cpu_id; + struct acpi_table_header *table; + int number_of_levels = 0; + acpi_status status; + + pr_debug("Cache Setup find last level cpu=%d\n", cpu); + + acpi_cpu_id = get_acpi_id_for_cpu(cpu); + status = acpi_get_table(ACPI_SIG_PPTT, 0, &table); + if (ACPI_FAILURE(status)) { + pr_warn_once("No PPTT table found, cache topology may be inaccurate\n"); + } else { + number_of_levels = acpi_find_cache_levels(table, acpi_cpu_id); + acpi_put_table(table); + } + pr_debug("Cache Setup find last level level=%d\n", number_of_levels); + + return number_of_levels; +} + +/** + * cache_setup_acpi() - Override CPU cache topology with data from the PPTT + * @cpu: Kernel logical cpu number + * + * Updates the global cache info provided by cpu_get_cacheinfo() + * when there are valid properties in the acpi_pptt_cache nodes. A + * successful parse may not result in any updates if none of the + * cache levels have any valid flags set. Futher, a unique value is + * associated with each known CPU cache entry. This unique value + * can be used to determine whether caches are shared between cpus. + * + * Return: -ENOENT on failure to find table, or 0 on success + */ +int cache_setup_acpi(unsigned int cpu) +{ + struct acpi_table_header *table; + acpi_status status; + + pr_debug("Cache Setup ACPI cpu %d\n", cpu); + + status = acpi_get_table(ACPI_SIG_PPTT, 0, &table); + if (ACPI_FAILURE(status)) { + pr_warn_once("No PPTT table found, cache topology may be inaccurate\n"); + return -ENOENT; + } + + cache_setup_acpi_cpu(table, cpu); + acpi_put_table(table); + + return status; +} + +/** + * find_acpi_cpu_topology() - Determine a unique topology value for a given cpu + * @cpu: Kernel logical cpu number + * @level: The topological level for which we would like a unique ID + * + * Determine a topology unique ID for each thread/core/cluster/mc_grouping + * /socket/etc. This ID can then be used to group peers, which will have + * matching ids. + * + * The search terminates when either the requested level is found or + * we reach a root node. Levels beyond the termination point will return the + * same unique ID. The unique id for level 0 is the acpi processor id. All + * other levels beyond this use a generated value to uniquely identify + * a topological feature. + * + * Return: -ENOENT if the PPTT doesn't exist, or the cpu cannot be found. + * Otherwise returns a value which represents a unique topological feature. + */ +int find_acpi_cpu_topology(unsigned int cpu, int level) +{ + return find_acpi_cpu_topology_tag(cpu, level, 0); +} + +/** + * find_acpi_cpu_cache_topology() - Determine a unique cache topology value + * @cpu: Kernel logical cpu number + * @level: The cache level for which we would like a unique ID + * + * Determine a unique ID for each unified cache in the system + * + * Return: -ENOENT if the PPTT doesn't exist, or the cpu cannot be found. + * Otherwise returns a value which represents a unique topological feature. + */ +int find_acpi_cpu_cache_topology(unsigned int cpu, int level) +{ + struct acpi_table_header *table; + struct acpi_pptt_cache *found_cache; + acpi_status status; + u32 acpi_cpu_id = get_acpi_id_for_cpu(cpu); + struct acpi_pptt_processor *cpu_node = NULL; + int ret = -1; + + status = acpi_get_table(ACPI_SIG_PPTT, 0, &table); + if (ACPI_FAILURE(status)) { + pr_warn_once("No PPTT table found, topology may be inaccurate\n"); + return -ENOENT; + } + + found_cache = acpi_find_cache_node(table, acpi_cpu_id, + CACHE_TYPE_UNIFIED, + level, + &cpu_node); + if (found_cache) + ret = ACPI_PTR_DIFF(cpu_node, table); + + acpi_put_table(table); + + return ret; +} + + +/** + * find_acpi_cpu_topology_package() - Determine a unique cpu package value + * @cpu: Kernel logical cpu number + * + * Determine a topology unique package ID for the given cpu. + * This ID can then be used to group peers, which will have matching ids. + * + * The search terminates when either a level is found with the PHYSICAL_PACKAGE + * flag set or we reach a root node. + * + * Return: -ENOENT if the PPTT doesn't exist, or the cpu cannot be found. + * Otherwise returns a value which represents the package for this cpu. + */ +int find_acpi_cpu_topology_package(unsigned int cpu) +{ + return find_acpi_cpu_topology_tag(cpu, PPTT_ABORT_PACKAGE, + ACPI_PPTT_PHYSICAL_PACKAGE); +} diff --git a/drivers/acpi/processor_perflib.c b/drivers/acpi/processor_perflib.c index a651ab3..a303fd0 100644 --- a/drivers/acpi/processor_perflib.c +++ b/drivers/acpi/processor_perflib.c @@ -343,8 +343,9 @@ static int acpi_processor_get_performance_states(struct acpi_processor *pr) pr->performance->state_count = pss->package.count; pr->performance->states = - kmalloc(sizeof(struct acpi_processor_px) * pss->package.count, - GFP_KERNEL); + kmalloc_array(pss->package.count, + sizeof(struct acpi_processor_px), + GFP_KERNEL); if (!pr->performance->states) { result = -ENOMEM; goto end; diff --git a/drivers/acpi/processor_throttling.c b/drivers/acpi/processor_throttling.c index 7f9aff4..fbc936c 100644 --- a/drivers/acpi/processor_throttling.c +++ b/drivers/acpi/processor_throttling.c @@ -534,8 +534,9 @@ static int acpi_processor_get_throttling_states(struct acpi_processor *pr) pr->throttling.state_count = tss->package.count; pr->throttling.states_tss = - kmalloc(sizeof(struct acpi_processor_tx_tss) * tss->package.count, - GFP_KERNEL); + kmalloc_array(tss->package.count, + sizeof(struct acpi_processor_tx_tss), + GFP_KERNEL); if (!pr->throttling.states_tss) { result = -ENOMEM; goto end; diff --git a/drivers/acpi/reboot.c b/drivers/acpi/reboot.c index 71769fd..6fa9c2a 100644 --- a/drivers/acpi/reboot.c +++ b/drivers/acpi/reboot.c @@ -8,8 +8,8 @@ void acpi_reboot(void) { struct acpi_generic_address *rr; struct pci_bus *bus0; - u8 reset_value; unsigned int devfn; + u8 reset_value; if (acpi_disabled) return; @@ -40,7 +40,7 @@ void acpi_reboot(void) /* Form PCI device/function pair. */ devfn = PCI_DEVFN((rr->address >> 32) & 0xffff, (rr->address >> 16) & 0xffff); - printk(KERN_DEBUG "Resetting with ACPI PCI RESET_REG."); + printk(KERN_DEBUG "Resetting with ACPI PCI RESET_REG.\n"); /* Write the value that resets us. */ pci_bus_write_config_byte(bus0, devfn, (rr->address & 0xffff), reset_value); diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index cc234e6..970dd87 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -2166,10 +2166,10 @@ int __init acpi_scan_init(void) acpi_cmos_rtc_init(); acpi_container_init(); acpi_memory_hotplug_init(); + acpi_watchdog_init(); acpi_pnp_init(); acpi_int340x_thermal_init(); acpi_amba_init(); - acpi_watchdog_init(); acpi_init_lpit(); acpi_scan_add_handler(&generic_device_handler); diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c index 99a1a65..5d0486f 100644 --- a/drivers/acpi/sleep.c +++ b/drivers/acpi/sleep.c @@ -364,6 +364,19 @@ static const struct dmi_system_id acpisleep_dmi_table[] __initconst = { DMI_MATCH(DMI_PRODUCT_NAME, "XPS 13 9360"), }, }, + /* + * ThinkPad X1 Tablet(2016) cannot do suspend-to-idle using + * the Low Power S0 Idle firmware interface (see + * https://bugzilla.kernel.org/show_bug.cgi?id=199057). + */ + { + .callback = init_no_lps0, + .ident = "ThinkPad X1 Tablet(2016)", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_MATCH(DMI_PRODUCT_NAME, "20GGA00L00"), + }, + }, {}, }; @@ -976,6 +989,13 @@ static void acpi_s2idle_wake(void) !irqd_is_wakeup_armed(irq_get_irq_data(acpi_sci_irq))) { pm_system_cancel_wakeup(); s2idle_wakeup = true; + /* + * On some platforms with the LPS0 _DSM device noirq resume + * takes too much time for EC wakeup events to survive, so look + * for them now. + */ + if (lps0_device_handle) + acpi_ec_dispatch_gpe(); } } diff --git a/drivers/acpi/sysfs.c b/drivers/acpi/sysfs.c index 4fc59c3..41324f0 100644 --- a/drivers/acpi/sysfs.c +++ b/drivers/acpi/sysfs.c @@ -857,12 +857,12 @@ void acpi_irq_stats_init(void) num_gpes = acpi_current_gpe_count; num_counters = num_gpes + ACPI_NUM_FIXED_EVENTS + NUM_COUNTERS_EXTRA; - all_attrs = kzalloc(sizeof(struct attribute *) * (num_counters + 1), + all_attrs = kcalloc(num_counters + 1, sizeof(struct attribute *), GFP_KERNEL); if (all_attrs == NULL) return; - all_counters = kzalloc(sizeof(struct event_counter) * (num_counters), + all_counters = kcalloc(num_counters, sizeof(struct event_counter), GFP_KERNEL); if (all_counters == NULL) goto fail; @@ -871,7 +871,7 @@ void acpi_irq_stats_init(void) if (ACPI_FAILURE(status)) goto fail; - counter_attrs = kzalloc(sizeof(struct kobj_attribute) * (num_counters), + counter_attrs = kcalloc(num_counters, sizeof(struct kobj_attribute), GFP_KERNEL); if (counter_attrs == NULL) goto fail; diff --git a/drivers/acpi/tables.c b/drivers/acpi/tables.c index 849c4fb..a3d012b 100644 --- a/drivers/acpi/tables.c +++ b/drivers/acpi/tables.c @@ -222,7 +222,7 @@ void acpi_table_print_madt_entry(struct acpi_subtable_header *header) * acpi_parse_entries_array - for each proc_num find a suitable subtable * * @id: table id (for debugging purposes) - * @table_size: single entry size + * @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 @@ -233,6 +233,11 @@ void acpi_table_print_madt_entry(struct acpi_subtable_header *header) * 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. */ @@ -400,7 +405,7 @@ int __init acpi_table_parse(char *id, acpi_tbl_table_handler handler) return -ENODEV; } -/* +/* * The BIOS is supposed to supply a single APIC/MADT, * but some report two. Provide a knob to use either. * (don't you wish instance 0 and 1 were not the same?) @@ -457,7 +462,7 @@ static const char * const table_sigs[] = { ACPI_SIG_UEFI, ACPI_SIG_WAET, ACPI_SIG_WDAT, ACPI_SIG_WDDT, ACPI_SIG_WDRT, ACPI_SIG_DSDT, ACPI_SIG_FADT, ACPI_SIG_PSDT, ACPI_SIG_RSDT, ACPI_SIG_XSDT, ACPI_SIG_SSDT, ACPI_SIG_IORT, - ACPI_SIG_NFIT, ACPI_SIG_HMAT, NULL }; + ACPI_SIG_NFIT, ACPI_SIG_HMAT, ACPI_SIG_PPTT, NULL }; #define ACPI_HEADER_SIZE sizeof(struct acpi_table_header) |