diff options
Diffstat (limited to 'drivers/acpi')
-rw-r--r-- | drivers/acpi/ac.c | 48 | ||||
-rw-r--r-- | drivers/acpi/acpi_watchdog.c | 72 | ||||
-rw-r--r-- | drivers/acpi/acpica/acapps.h | 2 | ||||
-rw-r--r-- | drivers/acpi/acpica/acglobal.h | 2 | ||||
-rw-r--r-- | drivers/acpi/acpica/acnamesp.h | 4 | ||||
-rw-r--r-- | drivers/acpi/acpica/dbnames.c | 12 | ||||
-rw-r--r-- | drivers/acpi/acpica/dbtest.c | 59 | ||||
-rw-r--r-- | drivers/acpi/acpica/dswscope.c | 8 | ||||
-rw-r--r-- | drivers/acpi/acpica/exconfig.c | 14 | ||||
-rw-r--r-- | drivers/acpi/acpica/hwregs.c | 4 | ||||
-rw-r--r-- | drivers/acpi/acpica/hwxface.c | 4 | ||||
-rw-r--r-- | drivers/acpi/acpica/nsinit.c | 76 | ||||
-rw-r--r-- | drivers/acpi/acpica/rsdump.c | 2 | ||||
-rw-r--r-- | drivers/acpi/acpica/tbinstal.c | 2 | ||||
-rw-r--r-- | drivers/acpi/acpica/utbuffer.c | 4 | ||||
-rw-r--r-- | drivers/acpi/acpica/utmutex.c | 4 | ||||
-rw-r--r-- | drivers/acpi/acpica/utobject.c | 2 | ||||
-rw-r--r-- | drivers/acpi/acpica/utprint.c | 1 | ||||
-rw-r--r-- | drivers/acpi/acpica/utstring.c | 2 | ||||
-rw-r--r-- | drivers/acpi/battery.c | 81 | ||||
-rw-r--r-- | drivers/acpi/cppc_acpi.c | 159 |
21 files changed, 416 insertions, 146 deletions
diff --git a/drivers/acpi/ac.c b/drivers/acpi/ac.c index 2d8de2f8c1ed..b823a86c166d 100644 --- a/drivers/acpi/ac.c +++ b/drivers/acpi/ac.c @@ -87,6 +87,7 @@ static int acpi_ac_open_fs(struct inode *inode, struct file *file); static int ac_sleep_before_get_state_ms; +static int ac_check_pmic = 1; static struct acpi_driver acpi_ac_driver = { .name = "ac", @@ -310,21 +311,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 +407,6 @@ end: kfree(ac); } - dmi_check_system(ac_dmi_table); return result; } @@ -442,13 +464,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_watchdog.c b/drivers/acpi/acpi_watchdog.c index 4bde16fb97d8..95600309ce42 100644 --- a/drivers/acpi/acpi_watchdog.c +++ b/drivers/acpi/acpi_watchdog.c @@ -12,35 +12,51 @@ #define pr_fmt(fmt) "ACPI: watchdog: " fmt #include <linux/acpi.h> -#include <linux/dmi.h> #include <linux/ioport.h> #include <linux/platform_device.h> #include "internal.h" -static const struct dmi_system_id acpi_watchdog_skip[] = { - { - /* - * On Lenovo Z50-70 there are two issues with the WDAT - * table. First some of the instructions use RTC SRAM - * to store persistent information. This does not work well - * with Linux RTC driver. Second, more important thing is - * that the instructions do not actually reset the system. - * - * On this particular system iTCO_wdt seems to work just - * fine so we prefer that over WDAT for now. - * - * See also https://bugzilla.kernel.org/show_bug.cgi?id=199033. - */ - .ident = "Lenovo Z50-70", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), - DMI_MATCH(DMI_PRODUCT_NAME, "20354"), - DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo Z50-70"), - }, - }, - {} -}; +#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) { @@ -50,9 +66,6 @@ static const struct acpi_table_wdat *acpi_watchdog_get_wdat(void) if (acpi_disabled) return NULL; - if (dmi_check_system(acpi_watchdog_skip)) - return NULL; - status = acpi_get_table(ACPI_SIG_WDAT, 0, (struct acpi_table_header **)&wdat); if (ACPI_FAILURE(status)) { @@ -60,6 +73,11 @@ static const struct acpi_table_wdat *acpi_watchdog_get_wdat(void) 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; } diff --git a/drivers/acpi/acpica/acapps.h b/drivers/acpi/acpica/acapps.h index a2a85122fafe..5a9c2febc0fb 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 0bc550072a21..1e6204518496 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 514aaf948ea9..3825df923480 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 170802c62179..dc94de91033e 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 */ diff --git a/drivers/acpi/acpica/dbtest.c b/drivers/acpi/acpica/dbtest.c index 3892680a5258..8a5462439a97 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/dswscope.c b/drivers/acpi/acpica/dswscope.c index d1422f984f6e..7592176a8fa2 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/exconfig.c b/drivers/acpi/acpica/exconfig.c index 99d92cb32803..f85c6f3271f6 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); diff --git a/drivers/acpi/acpica/hwregs.c b/drivers/acpi/acpica/hwregs.c index 27a86ad55b58..3de794bcf8fa 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 5d1396870bd0..6e39a771a56e 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/nsinit.c b/drivers/acpi/acpica/nsinit.c index 77f2b5f4948a..d77257d1c827 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/rsdump.c b/drivers/acpi/acpica/rsdump.c index b12a0b1cd9ce..6601e71b45e3 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 c5085b7ae8c9..5f8e7b561c90 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 148aeb84e561..fffa6f5ae59e 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/utmutex.c b/drivers/acpi/acpica/utmutex.c index d2d93e388f40..2e465e6a0ab6 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 5b78fe08d7d7..ae6d8cc18cec 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/utprint.c b/drivers/acpi/acpica/utprint.c index 35ffd8d51c65..a98c334c3bb7 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 bd57a77bbcb2..5bef0b059406 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/battery.c b/drivers/acpi/battery.c index bdb24d636d9a..572845fafb00 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"); @@ -215,6 +217,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 +246,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)) @@ -1332,23 +1348,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 +1545,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/cppc_acpi.c b/drivers/acpi/cppc_acpi.c index 735c74a4cbdb..d9ce4b162e2c 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); |