From e1563769f7b4494c5f789c689495c1e90a0d4bfc Mon Sep 17 00:00:00 2001 From: Michael Opdenacker Date: Fri, 21 Mar 2014 01:10:28 +0100 Subject: [PATCH 01/18] PNP: remove deprecated IRQF_DISABLED This patch removes the use of the IRQF_DISABLED flag from drivers/pnp/resource.c It's a NOOP since 2.6.35 and it will be removed one day. Signed-off-by: Michael Opdenacker Signed-off-by: Rafael J. Wysocki --- drivers/pnp/resource.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/pnp/resource.c b/drivers/pnp/resource.c index bacddd102ae9..01712cbfd92e 100644 --- a/drivers/pnp/resource.c +++ b/drivers/pnp/resource.c @@ -385,7 +385,7 @@ int pnp_check_irq(struct pnp_dev *dev, struct resource *res) * device is active because it itself may be in use */ if (!dev->active) { if (request_irq(*irq, pnp_test_handler, - IRQF_DISABLED | IRQF_PROBE_SHARED, "pnp", NULL)) + IRQF_PROBE_SHARED, "pnp", NULL)) return 0; free_irq(*irq, NULL); } From e2b8ddcc6b3fbb860e15c5d52455735e128326aa Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Mon, 24 Mar 2014 14:48:45 +0800 Subject: [PATCH 02/18] ACPICA: Remove global option to serialize all control methods. According to the reports, the "acpi_serialize" mechanism is broken as: A. The parallel method calls can still happen when the interpreter lock is released under the following conditions: 1. External callbacks are invoked, for example, by the region handlers, the exception handlers, etc.; 2. Module level execution is performed when Load/LoadTable opcodes are executed, and 3. The _REG control methods are invoked to complete the region registrations. B. For the following situations, the interpreter lock need to be released even for a serialized method while currently, the lock-releasing operation is marked as a no-op by acpi_ex_relinquish/reacquire_interpreter() when this mechanism is enabled: 1. Wait opcode is executed, 2. Acquire opcode is executed, and 3. Sleep opcode is executed. This patch removes this mechanism and the internal acpi_ex_relinquish/reacquire_interpreter() APIs. Lv Zheng. References: https://bugzilla.kernel.org/show_bug.cgi?id=52191 Signed-off-by: Lv Zheng Signed-off-by: Bob Moore Signed-off-by: Rafael J. Wysocki --- Documentation/kernel-parameters.txt | 2 - drivers/acpi/acpica/acglobal.h | 8 --- drivers/acpi/acpica/acinterp.h | 4 -- drivers/acpi/acpica/exsystem.c | 12 ++--- drivers/acpi/acpica/exutils.c | 80 ++++------------------------- drivers/acpi/osl.c | 12 ----- include/acpi/acpixf.h | 1 - 7 files changed, 16 insertions(+), 103 deletions(-) diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index bf0fda0125f0..3eae32f34122 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -306,8 +306,6 @@ bytes respectively. Such letter suffixes can also be entirely omitted. acpi_sci= [HW,ACPI] ACPI System Control Interrupt trigger mode Format: { level | edge | high | low } - acpi_serialize [HW,ACPI] force serialization of AML methods - acpi_skip_timer_override [HW,ACPI] Recognize and ignore IRQ0/pin2 Interrupt Override. For broken nForce2 BIOS resulting in XT-PIC timer. diff --git a/drivers/acpi/acpica/acglobal.h b/drivers/acpi/acpica/acglobal.h index 8f40bb972ae3..767556cb1448 100644 --- a/drivers/acpi/acpica/acglobal.h +++ b/drivers/acpi/acpica/acglobal.h @@ -92,14 +92,6 @@ */ ACPI_INIT_GLOBAL(u8, acpi_gbl_enable_interpreter_slack, FALSE); -/* - * Automatically serialize ALL control methods? Default is FALSE, meaning - * to use the Serialized/not_serialized method flags on a per method basis. - * Only change this if the ASL code is poorly written and cannot handle - * reentrancy even though methods are marked "NotSerialized". - */ -ACPI_INIT_GLOBAL(u8, acpi_gbl_all_methods_serialized, FALSE); - /* * Create the predefined _OSI method in the namespace? Default is TRUE * because ACPI CA is fully compatible with other ACPI implementations. diff --git a/drivers/acpi/acpica/acinterp.h b/drivers/acpi/acpica/acinterp.h index c54267748be5..b01f71ce0523 100644 --- a/drivers/acpi/acpica/acinterp.h +++ b/drivers/acpi/acpica/acinterp.h @@ -458,10 +458,6 @@ void acpi_ex_enter_interpreter(void); void acpi_ex_exit_interpreter(void); -void acpi_ex_reacquire_interpreter(void); - -void acpi_ex_relinquish_interpreter(void); - u8 acpi_ex_truncate_for32bit_table(union acpi_operand_object *obj_desc); void acpi_ex_acquire_global_lock(u32 rule); diff --git a/drivers/acpi/acpica/exsystem.c b/drivers/acpi/acpica/exsystem.c index 841caed11c08..f7da64123ed5 100644 --- a/drivers/acpi/acpica/exsystem.c +++ b/drivers/acpi/acpica/exsystem.c @@ -77,7 +77,7 @@ acpi_status acpi_ex_system_wait_semaphore(acpi_semaphore semaphore, u16 timeout) /* We must wait, so unlock the interpreter */ - acpi_ex_relinquish_interpreter(); + acpi_ex_exit_interpreter(); status = acpi_os_wait_semaphore(semaphore, 1, timeout); @@ -87,7 +87,7 @@ acpi_status acpi_ex_system_wait_semaphore(acpi_semaphore semaphore, u16 timeout) /* Reacquire the interpreter */ - acpi_ex_reacquire_interpreter(); + acpi_ex_enter_interpreter(); } return_ACPI_STATUS(status); @@ -123,7 +123,7 @@ acpi_status acpi_ex_system_wait_mutex(acpi_mutex mutex, u16 timeout) /* We must wait, so unlock the interpreter */ - acpi_ex_relinquish_interpreter(); + acpi_ex_exit_interpreter(); status = acpi_os_acquire_mutex(mutex, timeout); @@ -133,7 +133,7 @@ acpi_status acpi_ex_system_wait_mutex(acpi_mutex mutex, u16 timeout) /* Reacquire the interpreter */ - acpi_ex_reacquire_interpreter(); + acpi_ex_enter_interpreter(); } return_ACPI_STATUS(status); @@ -198,7 +198,7 @@ acpi_status acpi_ex_system_do_sleep(u64 how_long) /* Since this thread will sleep, we must release the interpreter */ - acpi_ex_relinquish_interpreter(); + acpi_ex_exit_interpreter(); /* * For compatibility with other ACPI implementations and to prevent @@ -212,7 +212,7 @@ acpi_status acpi_ex_system_do_sleep(u64 how_long) /* And now we must get the interpreter again */ - acpi_ex_reacquire_interpreter(); + acpi_ex_enter_interpreter(); return (AE_OK); } diff --git a/drivers/acpi/acpica/exutils.c b/drivers/acpi/acpica/exutils.c index 5b16c5484bee..d9d72dff2a76 100644 --- a/drivers/acpi/acpica/exutils.c +++ b/drivers/acpi/acpica/exutils.c @@ -98,37 +98,6 @@ void acpi_ex_enter_interpreter(void) return_VOID; } -/******************************************************************************* - * - * FUNCTION: acpi_ex_reacquire_interpreter - * - * PARAMETERS: None - * - * RETURN: None - * - * DESCRIPTION: Reacquire the interpreter execution region from within the - * interpreter code. Failure to enter the interpreter region is a - * fatal system error. Used in conjunction with - * relinquish_interpreter - * - ******************************************************************************/ - -void acpi_ex_reacquire_interpreter(void) -{ - ACPI_FUNCTION_TRACE(ex_reacquire_interpreter); - - /* - * If the global serialized flag is set, do not release the interpreter, - * since it was not actually released by acpi_ex_relinquish_interpreter. - * This forces the interpreter to be single threaded. - */ - if (!acpi_gbl_all_methods_serialized) { - acpi_ex_enter_interpreter(); - } - - return_VOID; -} - /******************************************************************************* * * FUNCTION: acpi_ex_exit_interpreter @@ -139,7 +108,16 @@ void acpi_ex_reacquire_interpreter(void) * * DESCRIPTION: Exit the interpreter execution region. This is the top level * routine used to exit the interpreter when all processing has - * been completed. + * been completed, or when the method blocks. + * + * Cases where the interpreter is unlocked internally: + * 1) Method will be blocked on a Sleep() AML opcode + * 2) Method will be blocked on an Acquire() AML opcode + * 3) Method will be blocked on a Wait() AML opcode + * 4) Method will be blocked to acquire the global lock + * 5) Method will be blocked waiting to execute a serialized control + * method that is currently executing + * 6) About to invoke a user-installed opregion handler * ******************************************************************************/ @@ -158,44 +136,6 @@ void acpi_ex_exit_interpreter(void) return_VOID; } -/******************************************************************************* - * - * FUNCTION: acpi_ex_relinquish_interpreter - * - * PARAMETERS: None - * - * RETURN: None - * - * DESCRIPTION: Exit the interpreter execution region, from within the - * interpreter - before attempting an operation that will possibly - * block the running thread. - * - * Cases where the interpreter is unlocked internally - * 1) Method to be blocked on a Sleep() AML opcode - * 2) Method to be blocked on an Acquire() AML opcode - * 3) Method to be blocked on a Wait() AML opcode - * 4) Method to be blocked to acquire the global lock - * 5) Method to be blocked waiting to execute a serialized control method - * that is currently executing - * 6) About to invoke a user-installed opregion handler - * - ******************************************************************************/ - -void acpi_ex_relinquish_interpreter(void) -{ - ACPI_FUNCTION_TRACE(ex_relinquish_interpreter); - - /* - * If the global serialized flag is set, do not release the interpreter. - * This forces the interpreter to be single threaded. - */ - if (!acpi_gbl_all_methods_serialized) { - acpi_ex_exit_interpreter(); - } - - return_VOID; -} - /******************************************************************************* * * FUNCTION: acpi_ex_truncate_for32bit_table diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index 0d7b7145399e..b7af3b758f32 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c @@ -1539,18 +1539,6 @@ static int __init osi_setup(char *str) __setup("acpi_osi=", osi_setup); -/* enable serialization to combat AE_ALREADY_EXISTS errors */ -static int __init acpi_serialize_setup(char *str) -{ - printk(KERN_INFO PREFIX "serialize enabled\n"); - - acpi_gbl_all_methods_serialized = TRUE; - - return 1; -} - -__setup("acpi_serialize", acpi_serialize_setup); - /* Check of resource interference between native drivers and ACPI * OperationRegions (SystemIO and System Memory only). * IO ports and memory declared in ACPI might be used by the ACPI subsystem diff --git a/include/acpi/acpixf.h b/include/acpi/acpixf.h index e04f0114283f..a3a8dae1cd61 100644 --- a/include/acpi/acpixf.h +++ b/include/acpi/acpixf.h @@ -71,7 +71,6 @@ extern u32 acpi_dbg_layer; /* ACPICA runtime options */ -extern u8 acpi_gbl_all_methods_serialized; extern u8 acpi_gbl_copy_dsdt_locally; extern u8 acpi_gbl_create_osi_method; extern u8 acpi_gbl_disable_auto_repair; From 22b5afce6a0f29f995b0cce83a5033892dd306d8 Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Mon, 24 Mar 2014 14:49:00 +0800 Subject: [PATCH 03/18] ACPICA: Add auto-serialization support for ill-behaved control methods. This change adds support to automatically mark a control method as "serialized" if the method creates any named objects. This will positively prevent the method from being entered by more than one thread and thus preventing a possible abort when an attempt is made to create an object twice. Implemented by parsing all non-serialize control methods at table load time. This feature is disabled by default and this patch also adds a new Linux kernel parameter "acpi_auto_serialize" to allow this feature to be turned on for a specific boot. References: https://bugzilla.kernel.org/show_bug.cgi?id=52191 Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki --- Documentation/kernel-parameters.txt | 8 ++ drivers/acpi/acpica/acdispat.h | 13 +-- drivers/acpi/acpica/acglobal.h | 9 ++ drivers/acpi/acpica/acstruct.h | 3 + drivers/acpi/acpica/dsinit.c | 59 ++++++++++--- drivers/acpi/acpica/dsmethod.c | 132 +++++++++++++++++++++++++++- drivers/acpi/acpica/dswload.c | 16 ++++ drivers/acpi/acpica/nsinit.c | 5 +- drivers/acpi/acpica/nsload.c | 4 +- drivers/acpi/acpica/psloop.c | 4 + drivers/acpi/acpica/psobject.c | 7 +- drivers/acpi/osl.c | 16 ++++ include/acpi/acpixf.h | 1 + 13 files changed, 252 insertions(+), 25 deletions(-) diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index 3eae32f34122..a159537ea880 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -229,6 +229,14 @@ bytes respectively. Such letter suffixes can also be entirely omitted. use by PCI Format: ,... + acpi_auto_serialize [HW,ACPI] + Enable auto-serialization of AML methods + AML control methods that contain the opcodes to create + named objects will be marked as "Serialized" by the + auto-serialization feature. + This feature is disabled by default. + This option allows to turn on the feature. + acpi_no_auto_ssdt [HW,ACPI] Disable automatic loading of SSDT acpica_no_return_repair [HW, ACPI] diff --git a/drivers/acpi/acpica/acdispat.h b/drivers/acpi/acpica/acdispat.h index 5b472c43c31d..d3e2cc395d7f 100644 --- a/drivers/acpi/acpica/acdispat.h +++ b/drivers/acpi/acpica/acdispat.h @@ -139,20 +139,21 @@ acpi_ds_init_field_objects(union acpi_parse_object *op, struct acpi_walk_state *walk_state); /* - * dsload - Parser/Interpreter interface, pass 1 namespace load callbacks + * dsload - Parser/Interpreter interface */ acpi_status acpi_ds_init_callbacks(struct acpi_walk_state *walk_state, u32 pass_number); +/* dsload - pass 1 namespace load callbacks */ + acpi_status acpi_ds_load1_begin_op(struct acpi_walk_state *walk_state, union acpi_parse_object **out_op); acpi_status acpi_ds_load1_end_op(struct acpi_walk_state *walk_state); -/* - * dsload - Parser/Interpreter interface, pass 2 namespace load callbacks - */ +/* dsload - pass 2 namespace load callbacks */ + acpi_status acpi_ds_load2_begin_op(struct acpi_walk_state *walk_state, union acpi_parse_object **out_op); @@ -200,7 +201,9 @@ void acpi_ds_method_data_init(struct acpi_walk_state *walk_state); /* * dsmethod - Parser/Interpreter interface - control method parsing */ -acpi_status acpi_ds_parse_method(struct acpi_namespace_node *node); +acpi_status +acpi_ds_auto_serialize_method(struct acpi_namespace_node *node, + union acpi_operand_object *obj_desc); acpi_status acpi_ds_call_control_method(struct acpi_thread_state *thread, diff --git a/drivers/acpi/acpica/acglobal.h b/drivers/acpi/acpica/acglobal.h index 767556cb1448..ea0f8389ccde 100644 --- a/drivers/acpi/acpica/acglobal.h +++ b/drivers/acpi/acpica/acglobal.h @@ -92,6 +92,15 @@ */ ACPI_INIT_GLOBAL(u8, acpi_gbl_enable_interpreter_slack, FALSE); +/* + * Automatically serialize all methods that create named objects? Default + * is TRUE, meaning that all non_serialized methods are scanned once at + * table load time to determine those that create named objects. Methods + * that create named objects are marked Serialized in order to prevent + * possible run-time problems if they are entered by more than one thread. + */ +ACPI_INIT_GLOBAL(u8, acpi_gbl_auto_serialize_methods, FALSE); + /* * Create the predefined _OSI method in the namespace? Default is TRUE * because ACPI CA is fully compatible with other ACPI implementations. diff --git a/drivers/acpi/acpica/acstruct.h b/drivers/acpi/acpica/acstruct.h index 5d2989a1b68c..cf7346110bd8 100644 --- a/drivers/acpi/acpica/acstruct.h +++ b/drivers/acpi/acpica/acstruct.h @@ -133,6 +133,9 @@ struct acpi_init_walk_info { u32 table_index; u32 object_count; u32 method_count; + u32 serial_method_count; + u32 non_serial_method_count; + u32 serialized_method_count; u32 device_count; u32 op_region_count; u32 field_count; diff --git a/drivers/acpi/acpica/dsinit.c b/drivers/acpi/acpica/dsinit.c index 96644d5ac0e1..aee5e45f6d35 100644 --- a/drivers/acpi/acpica/dsinit.c +++ b/drivers/acpi/acpica/dsinit.c @@ -83,8 +83,8 @@ acpi_ds_init_one_object(acpi_handle obj_handle, (struct acpi_init_walk_info *)context; struct acpi_namespace_node *node = (struct acpi_namespace_node *)obj_handle; - acpi_object_type type; acpi_status status; + union acpi_operand_object *obj_desc; ACPI_FUNCTION_ENTRY(); @@ -100,9 +100,7 @@ acpi_ds_init_one_object(acpi_handle obj_handle, /* And even then, we are only interested in a few object types */ - type = acpi_ns_get_type(obj_handle); - - switch (type) { + switch (acpi_ns_get_type(obj_handle)) { case ACPI_TYPE_REGION: status = acpi_ds_initialize_region(obj_handle); @@ -117,8 +115,44 @@ acpi_ds_init_one_object(acpi_handle obj_handle, break; case ACPI_TYPE_METHOD: - + /* + * Auto-serialization support. We will examine each method that is + * not_serialized to determine if it creates any Named objects. If + * it does, it will be marked serialized to prevent problems if + * the method is entered by two or more threads and an attempt is + * made to create the same named object twice -- which results in + * an AE_ALREADY_EXISTS exception and method abort. + */ info->method_count++; + obj_desc = acpi_ns_get_attached_object(node); + if (!obj_desc) { + break; + } + + /* Ignore if already serialized */ + + if (obj_desc->method.info_flags & ACPI_METHOD_SERIALIZED) { + info->serial_method_count++; + break; + } + + if (acpi_gbl_auto_serialize_methods) { + + /* Parse/scan method and serialize it if necessary */ + + acpi_ds_auto_serialize_method(node, obj_desc); + if (obj_desc->method. + info_flags & ACPI_METHOD_SERIALIZED) { + + /* Method was just converted to Serialized */ + + info->serial_method_count++; + info->serialized_method_count++; + break; + } + } + + info->non_serial_method_count++; break; case ACPI_TYPE_DEVICE: @@ -170,7 +204,6 @@ acpi_ds_initialize_objects(u32 table_index, ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, "**** Starting initialization of namespace objects ****\n")); - ACPI_DEBUG_PRINT_RAW((ACPI_DB_INIT, "Parsing all Control Methods:")); /* Set all init info to zero */ @@ -205,14 +238,16 @@ acpi_ds_initialize_objects(u32 table_index, } ACPI_DEBUG_PRINT_RAW((ACPI_DB_INIT, - "\nTable [%4.4s](id %4.4X) - %u Objects with %u Devices %u Methods %u Regions\n", + "Table [%4.4s] (id %4.4X) - %4u Objects with %3u Devices, " + "%3u Regions, %3u Methods (%u/%u/%u Serial/Non/Cvt)\n", table->signature, owner_id, info.object_count, - info.device_count, info.method_count, - info.op_region_count)); + info.device_count, info.op_region_count, + info.method_count, info.serial_method_count, + info.non_serial_method_count, + info.serialized_method_count)); - ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, - "%u Methods, %u Regions\n", info.method_count, - info.op_region_count)); + ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, "%u Methods, %u Regions\n", + info.method_count, info.op_region_count)); return_ACPI_STATUS(AE_OK); } diff --git a/drivers/acpi/acpica/dsmethod.c b/drivers/acpi/acpica/dsmethod.c index 2c6d42c2bc01..97ed86aee0dc 100644 --- a/drivers/acpi/acpica/dsmethod.c +++ b/drivers/acpi/acpica/dsmethod.c @@ -49,14 +49,144 @@ #ifdef ACPI_DISASSEMBLER #include "acdisasm.h" #endif +#include "acparser.h" +#include "amlcode.h" #define _COMPONENT ACPI_DISPATCHER ACPI_MODULE_NAME("dsmethod") /* Local prototypes */ +static acpi_status +acpi_ds_detect_named_opcodes(struct acpi_walk_state *walk_state, + union acpi_parse_object **out_op); + static acpi_status acpi_ds_create_method_mutex(union acpi_operand_object *method_desc); +/******************************************************************************* + * + * FUNCTION: acpi_ds_auto_serialize_method + * + * PARAMETERS: node - Namespace Node of the method + * obj_desc - Method object attached to node + * + * RETURN: Status + * + * DESCRIPTION: Parse a control method AML to scan for control methods that + * need serialization due to the creation of named objects. + * + * NOTE: It is a bit of overkill to mark all such methods serialized, since + * there is only a problem if the method actually blocks during execution. + * A blocking operation is, for example, a Sleep() operation, or any access + * to an operation region. However, it is probably not possible to easily + * detect whether a method will block or not, so we simply mark all suspicious + * methods as serialized. + * + * NOTE2: This code is essentially a generic routine for parsing a single + * control method. + * + ******************************************************************************/ + +acpi_status +acpi_ds_auto_serialize_method(struct acpi_namespace_node *node, + union acpi_operand_object *obj_desc) +{ + acpi_status status; + union acpi_parse_object *op = NULL; + struct acpi_walk_state *walk_state; + + ACPI_FUNCTION_TRACE_PTR(ds_auto_serialize_method, node); + + ACPI_DEBUG_PRINT((ACPI_DB_PARSE, + "Method auto-serialization parse [%4.4s] %p\n", + acpi_ut_get_node_name(node), node)); + + /* Create/Init a root op for the method parse tree */ + + op = acpi_ps_alloc_op(AML_METHOD_OP); + if (!op) { + return_ACPI_STATUS(AE_NO_MEMORY); + } + + acpi_ps_set_name(op, node->name.integer); + op->common.node = node; + + /* Create and initialize a new walk state */ + + walk_state = + acpi_ds_create_walk_state(node->owner_id, NULL, NULL, NULL); + if (!walk_state) { + return_ACPI_STATUS(AE_NO_MEMORY); + } + + status = + acpi_ds_init_aml_walk(walk_state, op, node, + obj_desc->method.aml_start, + obj_desc->method.aml_length, NULL, 0); + if (ACPI_FAILURE(status)) { + acpi_ds_delete_walk_state(walk_state); + return_ACPI_STATUS(status); + } + + walk_state->descending_callback = acpi_ds_detect_named_opcodes; + + /* Parse the method, scan for creation of named objects */ + + status = acpi_ps_parse_aml(walk_state); + if (ACPI_FAILURE(status)) { + return_ACPI_STATUS(status); + } + + acpi_ps_delete_parse_tree(op); + return_ACPI_STATUS(status); +} + +/******************************************************************************* + * + * FUNCTION: acpi_ds_detect_named_opcodes + * + * PARAMETERS: walk_state - Current state of the parse tree walk + * out_op - Unused, required for parser interface + * + * RETURN: Status + * + * DESCRIPTION: Descending callback used during the loading of ACPI tables. + * Currently used to detect methods that must be marked serialized + * in order to avoid problems with the creation of named objects. + * + ******************************************************************************/ + +static acpi_status +acpi_ds_detect_named_opcodes(struct acpi_walk_state *walk_state, + union acpi_parse_object **out_op) +{ + + ACPI_FUNCTION_NAME(acpi_ds_detect_named_opcodes); + + /* We are only interested in opcodes that have an associated name */ + + if (!(walk_state->op_info->flags & AML_NAMED)) { + return (AE_OK); + } + + /* + * At this point, we know we have a Named object opcode. + * Mark the method as serialized. Later code will create a mutex for + * this method to enforce serialization. + */ + walk_state->method_desc->method.info_flags |= ACPI_METHOD_SERIALIZED; + + ACPI_DEBUG_PRINT((ACPI_DB_INFO, + "Method serialized [%4.4s] %p - [%s] (%4.4X)\n", + walk_state->method_node->name.ascii, + walk_state->method_node, walk_state->op_info->name, + walk_state->opcode)); + + /* Abort the parse, no need to examine this method any further */ + + return (AE_CTRL_TERMINATE); +} + /******************************************************************************* * * FUNCTION: acpi_ds_method_error @@ -74,7 +204,7 @@ acpi_ds_create_method_mutex(union acpi_operand_object *method_desc); ******************************************************************************/ acpi_status -acpi_ds_method_error(acpi_status status, struct acpi_walk_state *walk_state) +acpi_ds_method_error(acpi_status status, struct acpi_walk_state * walk_state) { ACPI_FUNCTION_ENTRY(); diff --git a/drivers/acpi/acpica/dswload.c b/drivers/acpi/acpica/dswload.c index bd7811c64169..15623da26200 100644 --- a/drivers/acpi/acpica/dswload.c +++ b/drivers/acpi/acpica/dswload.c @@ -73,8 +73,20 @@ acpi_ds_init_callbacks(struct acpi_walk_state *walk_state, u32 pass_number) { switch (pass_number) { + case 0: + + /* Parse only - caller will setup callbacks */ + + walk_state->parse_flags = ACPI_PARSE_LOAD_PASS1 | + ACPI_PARSE_DELETE_TREE | ACPI_PARSE_DISASSEMBLE; + walk_state->descending_callback = NULL; + walk_state->ascending_callback = NULL; + break; + case 1: + /* Load pass 1 */ + walk_state->parse_flags = ACPI_PARSE_LOAD_PASS1 | ACPI_PARSE_DELETE_TREE; walk_state->descending_callback = acpi_ds_load1_begin_op; @@ -83,6 +95,8 @@ acpi_ds_init_callbacks(struct acpi_walk_state *walk_state, u32 pass_number) case 2: + /* Load pass 2 */ + walk_state->parse_flags = ACPI_PARSE_LOAD_PASS1 | ACPI_PARSE_DELETE_TREE; walk_state->descending_callback = acpi_ds_load2_begin_op; @@ -91,6 +105,8 @@ acpi_ds_init_callbacks(struct acpi_walk_state *walk_state, u32 pass_number) case 3: + /* Execution pass */ + #ifndef ACPI_NO_METHOD_EXECUTION walk_state->parse_flags |= ACPI_PARSE_EXECUTE | ACPI_PARSE_DELETE_TREE; diff --git a/drivers/acpi/acpica/nsinit.c b/drivers/acpi/acpica/nsinit.c index 5b74677bf74d..a3fb7e4c0809 100644 --- a/drivers/acpi/acpica/nsinit.c +++ b/drivers/acpi/acpica/nsinit.c @@ -111,9 +111,8 @@ acpi_status acpi_ns_initialize_objects(void) info.object_count)); ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, - "%u Control Methods found\n", info.method_count)); - ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, - "%u Op Regions found\n", info.op_region_count)); + "%u Control Methods found\n%u Op Regions found\n", + info.method_count, info.op_region_count)); return_ACPI_STATUS(AE_OK); } diff --git a/drivers/acpi/acpica/nsload.c b/drivers/acpi/acpica/nsload.c index 7ae521ce8d3f..7c9d0181f341 100644 --- a/drivers/acpi/acpica/nsload.c +++ b/drivers/acpi/acpica/nsload.c @@ -128,12 +128,12 @@ unlock: * parse trees. */ ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "**** Begin Table Method Parsing and Object Initialization\n")); + "**** Begin Table Object Initialization\n")); status = acpi_ds_initialize_objects(table_index, node); ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "**** Completed Table Method Parsing and Object Initialization\n")); + "**** Completed Table Object Initialization\n")); return_ACPI_STATUS(status); } diff --git a/drivers/acpi/acpica/psloop.c b/drivers/acpi/acpica/psloop.c index 646d1a3f6e27..b058e2390fdd 100644 --- a/drivers/acpi/acpica/psloop.c +++ b/drivers/acpi/acpica/psloop.c @@ -480,6 +480,10 @@ acpi_status acpi_ps_parse_loop(struct acpi_walk_state *walk_state) status = AE_OK; } + if (status == AE_CTRL_TERMINATE) { + return_ACPI_STATUS(status); + } + status = acpi_ps_complete_op(walk_state, &op, status); diff --git a/drivers/acpi/acpica/psobject.c b/drivers/acpi/acpica/psobject.c index af1f46cd37a5..a6885077d59e 100644 --- a/drivers/acpi/acpica/psobject.c +++ b/drivers/acpi/acpica/psobject.c @@ -219,7 +219,10 @@ acpi_ps_build_named_op(struct acpi_walk_state *walk_state, status = walk_state->descending_callback(walk_state, op); if (ACPI_FAILURE(status)) { - ACPI_EXCEPTION((AE_INFO, status, "During name lookup/catalog")); + if (status != AE_CTRL_TERMINATE) { + ACPI_EXCEPTION((AE_INFO, status, + "During name lookup/catalog")); + } return_ACPI_STATUS(status); } @@ -230,7 +233,7 @@ acpi_ps_build_named_op(struct acpi_walk_state *walk_state, status = acpi_ps_next_parse_state(walk_state, *op, status); if (ACPI_FAILURE(status)) { if (status == AE_CTRL_PENDING) { - return_ACPI_STATUS(AE_CTRL_PARSE_PENDING); + status = AE_CTRL_PARSE_PENDING; } return_ACPI_STATUS(status); } diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index b7af3b758f32..74a160cf85b9 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c @@ -1539,6 +1539,22 @@ static int __init osi_setup(char *str) __setup("acpi_osi=", osi_setup); +/* + * Enable the auto-serialization of named objects creation methods. + * + * This feature is disabled by default. It marks the AML control methods + * that contain the opcodes to create named objects as "Serialized". + */ +static int __init acpi_auto_serialize_setup(char *str) +{ + acpi_gbl_auto_serialize_methods = TRUE; + pr_info("ACPI: auto-serialization enabled\n"); + + return 1; +} + +__setup("acpi_auto_serialize", acpi_auto_serialize_setup); + /* Check of resource interference between native drivers and ACPI * OperationRegions (SystemIO and System Memory only). * IO ports and memory declared in ACPI might be used by the ACPI subsystem diff --git a/include/acpi/acpixf.h b/include/acpi/acpixf.h index a3a8dae1cd61..fc017dff1ba0 100644 --- a/include/acpi/acpixf.h +++ b/include/acpi/acpixf.h @@ -71,6 +71,7 @@ extern u32 acpi_dbg_layer; /* ACPICA runtime options */ +extern u8 acpi_gbl_auto_serialize_methods; extern u8 acpi_gbl_copy_dsdt_locally; extern u8 acpi_gbl_create_osi_method; extern u8 acpi_gbl_disable_auto_repair; From 21bd7e610ef75ef26387ed4667801080b5b7220a Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Mon, 24 Mar 2014 14:49:07 +0800 Subject: [PATCH 04/18] ACPICA: Add additional named objects for the auto-serialize method scan. This change adds some additional opcodes that are detected and will cause a method to be auto-serialized. These opcodes are the various CreateXField and the FieldUnit opcodes. Lv Zheng. References: https://bugzilla.kernel.org/show_bug.cgi?id=52191 Signed-off-by: Lv Zheng Signed-off-by: Bob Moore Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/dsmethod.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/acpi/acpica/dsmethod.c b/drivers/acpi/acpica/dsmethod.c index 97ed86aee0dc..73764c7d1c5d 100644 --- a/drivers/acpi/acpica/dsmethod.c +++ b/drivers/acpi/acpica/dsmethod.c @@ -163,9 +163,11 @@ acpi_ds_detect_named_opcodes(struct acpi_walk_state *walk_state, ACPI_FUNCTION_NAME(acpi_ds_detect_named_opcodes); - /* We are only interested in opcodes that have an associated name */ + /* We are only interested in opcodes that create a new name */ - if (!(walk_state->op_info->flags & AML_NAMED)) { + if (! + (walk_state->op_info-> + flags & (AML_NAMED | AML_CREATE | AML_FIELD))) { return (AE_OK); } From d18255795bf98b3f25dbc5334b8a615943c3dcca Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Mon, 24 Mar 2014 14:49:13 +0800 Subject: [PATCH 05/18] ACPICA: Ignore sync_level for methods that have been auto-serialized. Cannot use a sync_level for methods that have been serialized at load-time or runtime because this may interfere with any existing use of sync_levels within the ASL code. So, we simply ignore the sync_level for these methods, thus preserving any existing sync_level priorities. Note, the use of sync_levels is actually rather rare within BIOS ASL code. References: http://www.spinics.net/lists/linux-acpi/msg49496.html Reported-by: Valdis Kletnieks Reported-by: Sabrina Dubroka Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/acobject.h | 3 ++- drivers/acpi/acpica/dsmethod.c | 24 +++++++++++++++++++----- 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/drivers/acpi/acpica/acobject.h b/drivers/acpi/acpica/acobject.h index 1a4d61805ebc..22fb6449d3d6 100644 --- a/drivers/acpi/acpica/acobject.h +++ b/drivers/acpi/acpica/acobject.h @@ -193,7 +193,8 @@ struct acpi_object_method { #define ACPI_METHOD_INTERNAL_ONLY 0x02 /* Method is implemented internally (_OSI) */ #define ACPI_METHOD_SERIALIZED 0x04 /* Method is serialized */ #define ACPI_METHOD_SERIALIZED_PENDING 0x08 /* Method is to be marked serialized */ -#define ACPI_METHOD_MODIFIED_NAMESPACE 0x10 /* Method modified the namespace */ +#define ACPI_METHOD_IGNORE_SYNC_LEVEL 0x10 /* Method was auto-serialized at table load time */ +#define ACPI_METHOD_MODIFIED_NAMESPACE 0x20 /* Method modified the namespace */ /****************************************************************************** * diff --git a/drivers/acpi/acpica/dsmethod.c b/drivers/acpi/acpica/dsmethod.c index 73764c7d1c5d..3c7f7378b94d 100644 --- a/drivers/acpi/acpica/dsmethod.c +++ b/drivers/acpi/acpica/dsmethod.c @@ -175,8 +175,15 @@ acpi_ds_detect_named_opcodes(struct acpi_walk_state *walk_state, * At this point, we know we have a Named object opcode. * Mark the method as serialized. Later code will create a mutex for * this method to enforce serialization. + * + * Note, ACPI_METHOD_IGNORE_SYNC_LEVEL flag means that we will ignore the + * Sync Level mechanism for this method, even though it is now serialized. + * Otherwise, there can be conflicts with existing ASL code that actually + * uses sync levels. */ - walk_state->method_desc->method.info_flags |= ACPI_METHOD_SERIALIZED; + walk_state->method_desc->method.sync_level = 0; + walk_state->method_desc->method.info_flags |= + (ACPI_METHOD_SERIALIZED | ACPI_METHOD_IGNORE_SYNC_LEVEL); ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Method serialized [%4.4s] %p - [%s] (%4.4X)\n", @@ -349,13 +356,19 @@ acpi_ds_begin_method_execution(struct acpi_namespace_node *method_node, /* * The current_sync_level (per-thread) must be less than or equal to * the sync level of the method. This mechanism provides some - * deadlock prevention + * deadlock prevention. + * + * If the method was auto-serialized, we just ignore the sync level + * mechanism, because auto-serialization of methods can interfere + * with ASL code that actually uses sync levels. * * Top-level method invocation has no walk state at this point */ if (walk_state && - (walk_state->thread->current_sync_level > - obj_desc->method.mutex->mutex.sync_level)) { + (!(obj_desc->method. + info_flags & ACPI_METHOD_IGNORE_SYNC_LEVEL)) + && (walk_state->thread->current_sync_level > + obj_desc->method.mutex->mutex.sync_level)) { ACPI_ERROR((AE_INFO, "Cannot acquire Mutex for method [%4.4s], current SyncLevel is too large (%u)", acpi_ut_get_node_name(method_node), @@ -800,7 +813,8 @@ acpi_ds_terminate_control_method(union acpi_operand_object *method_desc, method_desc->method.info_flags &= ~ACPI_METHOD_SERIALIZED_PENDING; method_desc->method.info_flags |= - ACPI_METHOD_SERIALIZED; + (ACPI_METHOD_SERIALIZED | + ACPI_METHOD_IGNORE_SYNC_LEVEL); method_desc->method.sync_level = 0; } From 08e1d7c0290aaef6bc6d68be8df753ffec02a6ae Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Mon, 24 Mar 2014 14:49:22 +0800 Subject: [PATCH 06/18] ACPICA: Enable auto-serialization as a default kernel behavior. The previous commit "ACPICA: Add auto-serialization support for ill-behaved control methods" introduced the auto-serialization facility as a workaround that can be enabled by "acpi_auto_serialize": This feature marks control methods that create named objects as "serialized" to avoid unwanted AE_ALREADY_EXISTS control method evaluation failures. Enable method auto-serialization as the default kernel behavior. The new kernel parameter is also changed from "acpi_auto_serialize" to "acpi_no_auto_serialize" to reflect the default behavior. References: https://bugzilla.kernel.org/show_bug.cgi?id=52191 References: http://www.spinics.net/lists/linux-acpi/msg49496.html Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki --- Documentation/kernel-parameters.txt | 8 ++++---- drivers/acpi/acpica/acglobal.h | 2 +- drivers/acpi/osl.c | 12 ++++++------ 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index a159537ea880..91f0be8555f5 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -229,13 +229,13 @@ bytes respectively. Such letter suffixes can also be entirely omitted. use by PCI Format: ,... - acpi_auto_serialize [HW,ACPI] - Enable auto-serialization of AML methods + acpi_no_auto_serialize [HW,ACPI] + Disable auto-serialization of AML methods AML control methods that contain the opcodes to create named objects will be marked as "Serialized" by the auto-serialization feature. - This feature is disabled by default. - This option allows to turn on the feature. + This feature is enabled by default. + This option allows to turn off the feature. acpi_no_auto_ssdt [HW,ACPI] Disable automatic loading of SSDT diff --git a/drivers/acpi/acpica/acglobal.h b/drivers/acpi/acpica/acglobal.h index ea0f8389ccde..49bbc71fad54 100644 --- a/drivers/acpi/acpica/acglobal.h +++ b/drivers/acpi/acpica/acglobal.h @@ -99,7 +99,7 @@ ACPI_INIT_GLOBAL(u8, acpi_gbl_enable_interpreter_slack, FALSE); * that create named objects are marked Serialized in order to prevent * possible run-time problems if they are entered by more than one thread. */ -ACPI_INIT_GLOBAL(u8, acpi_gbl_auto_serialize_methods, FALSE); +ACPI_INIT_GLOBAL(u8, acpi_gbl_auto_serialize_methods, TRUE); /* * Create the predefined _OSI method in the namespace? Default is TRUE diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index 74a160cf85b9..a3109ffcfa98 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c @@ -1540,20 +1540,20 @@ static int __init osi_setup(char *str) __setup("acpi_osi=", osi_setup); /* - * Enable the auto-serialization of named objects creation methods. + * Disable the auto-serialization of named objects creation methods. * - * This feature is disabled by default. It marks the AML control methods + * This feature is enabled by default. It marks the AML control methods * that contain the opcodes to create named objects as "Serialized". */ -static int __init acpi_auto_serialize_setup(char *str) +static int __init acpi_no_auto_serialize_setup(char *str) { - acpi_gbl_auto_serialize_methods = TRUE; - pr_info("ACPI: auto-serialization enabled\n"); + acpi_gbl_auto_serialize_methods = FALSE; + pr_info("ACPI: auto-serialization disabled\n"); return 1; } -__setup("acpi_auto_serialize", acpi_auto_serialize_setup); +__setup("acpi_no_auto_serialize", acpi_no_auto_serialize_setup); /* Check of resource interference between native drivers and ACPI * OperationRegions (SystemIO and System Memory only). From 3e9eac50cdcac71a74ca4a8cb587799f474ca62d Mon Sep 17 00:00:00 2001 From: Hanjun Guo Date: Wed, 26 Mar 2014 08:36:23 +0800 Subject: [PATCH 07/18] Revert "ACPI / processor: Make it possible to get APIC ID via GIC" Revert commit df86f5df79d8 (ACPI / processor: Make it possible to get APIC ID via GIC). APIC ID refers the hardware ID of the CPU, which means MPIDR on ARM/ARM64, but in ACPI 5.0, GIC ID feild in GIC structure have no explicit definition and may not refer to the MPIDR. Commit df86f5df79d8 assumed that gic->gic_id as MPIDR which may not be the case, so revert it until the explicit definition of GIC structure is ready. Signed-off-by: Hanjun Guo [rjw: Changelog] Signed-off-by: Rafael J. Wysocki --- drivers/acpi/processor_core.c | 27 --------------------------- 1 file changed, 27 deletions(-) diff --git a/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c index f1dd404463aa..4d91b32423a9 100644 --- a/drivers/acpi/processor_core.c +++ b/drivers/acpi/processor_core.c @@ -71,28 +71,6 @@ static int map_lsapic_id(struct acpi_subtable_header *entry, return 0; } -static int map_gic_id(struct acpi_subtable_header *entry, - int device_declaration, u32 acpi_id, int *apic_id) -{ - struct acpi_madt_generic_interrupt *gic = - (struct acpi_madt_generic_interrupt *)entry; - - if (!(gic->flags & ACPI_MADT_ENABLED)) - return -ENODEV; - - /* - * In the GIC interrupt model, logical processors are - * required to have a Processor Device object in the DSDT, - * so we should check device_declaration here - */ - if (device_declaration && (gic->uid == acpi_id)) { - *apic_id = gic->gic_id; - return 0; - } - - return -EINVAL; -} - static int map_madt_entry(int type, u32 acpi_id) { unsigned long madt_end, entry; @@ -128,9 +106,6 @@ static int map_madt_entry(int type, u32 acpi_id) } else if (header->type == ACPI_MADT_TYPE_LOCAL_SAPIC) { if (!map_lsapic_id(header, type, acpi_id, &apic_id)) break; - } else if (header->type == ACPI_MADT_TYPE_GENERIC_INTERRUPT) { - if (!map_gic_id(header, type, acpi_id, &apic_id)) - break; } entry += header->length; } @@ -161,8 +136,6 @@ static int map_mat_entry(acpi_handle handle, int type, u32 acpi_id) map_lapic_id(header, acpi_id, &apic_id); } else if (header->type == ACPI_MADT_TYPE_LOCAL_SAPIC) { map_lsapic_id(header, type, acpi_id, &apic_id); - } else if (header->type == ACPI_MADT_TYPE_GENERIC_INTERRUPT) { - map_gic_id(header, type, acpi_id, &apic_id); } exit: From e1a297601102c10579623a43df1c3529fb1f2fc9 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Mon, 24 Mar 2014 21:31:27 +0100 Subject: [PATCH 08/18] PM / Runtime: dev_pm_info.runtime_error is signed dev_pm_info.runtime_error has always been a signed int, to store a signed error code. Correct the documentation. Signed-off-by: Geert Uytterhoeven Signed-off-by: Rafael J. Wysocki --- Documentation/power/runtime_pm.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/power/runtime_pm.txt b/Documentation/power/runtime_pm.txt index b6ce00b2be9a..a5683a5662cb 100644 --- a/Documentation/power/runtime_pm.txt +++ b/Documentation/power/runtime_pm.txt @@ -232,7 +232,7 @@ defined in include/linux/pm.h: equal to zero); the initial value of it is 1 (i.e. runtime PM is initially disabled for all devices) - unsigned int runtime_error; + int runtime_error; - if set, there was a fatal error (one of the callbacks returned error code as described in Section 2), so the helper funtions will not work until this flag is cleared; this is the error code returned by the failing From 91e63cc0352257352a134a242a69f5785e5ae6ee Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Mon, 24 Mar 2014 21:31:28 +0100 Subject: [PATCH 09/18] PM / Runtime: Split line longer than 80 characters Signed-off-by: Geert Uytterhoeven Signed-off-by: Rafael J. Wysocki --- Documentation/power/runtime_pm.txt | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Documentation/power/runtime_pm.txt b/Documentation/power/runtime_pm.txt index a5683a5662cb..f62deb66d5c1 100644 --- a/Documentation/power/runtime_pm.txt +++ b/Documentation/power/runtime_pm.txt @@ -401,11 +401,11 @@ drivers/base/power/runtime.c and include/linux/pm_runtime.h: int pm_runtime_disable(struct device *dev); - increment the device's 'power.disable_depth' field (if the value of that field was previously zero, this prevents subsystem-level runtime PM - callbacks from being run for the device), make sure that all of the pending - runtime PM operations on the device are either completed or canceled; - returns 1 if there was a resume request pending and it was necessary to - execute the subsystem-level resume callback for the device to satisfy that - request, otherwise 0 is returned + callbacks from being run for the device), make sure that all of the + pending runtime PM operations on the device are either completed or + canceled; returns 1 if there was a resume request pending and it was + necessary to execute the subsystem-level resume callback for the device + to satisfy that request, otherwise 0 is returned int pm_runtime_barrier(struct device *dev); - check if there's a resume request pending for the device and resume it From 39c29f3dfc5bd9f40ae72f79e509e6cfbb22a50b Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Mon, 24 Mar 2014 21:31:29 +0100 Subject: [PATCH 10/18] PM / Runtime: Correct documented return values for generic PM callbacks As of commit 05aa55dddb9ee4045c320661068bea78dad6a6e5 ("PM / Runtime: Lenient generic runtime pm callbacks"), the generic power management callbacks pm_generic_runtime_suspend() and pm_generic_runtime_resume() return 0, not -EINVAL, if the device doesn't provide its own callbacks. Signed-off-by: Geert Uytterhoeven Signed-off-by: Rafael J. Wysocki --- Documentation/power/runtime_pm.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Documentation/power/runtime_pm.txt b/Documentation/power/runtime_pm.txt index f62deb66d5c1..8cc48b05939d 100644 --- a/Documentation/power/runtime_pm.txt +++ b/Documentation/power/runtime_pm.txt @@ -667,11 +667,11 @@ driver/base/power/generic_ops.c: int pm_generic_runtime_suspend(struct device *dev); - invoke the ->runtime_suspend() callback provided by the driver of this - device and return its result, or return -EINVAL if not defined + device and return its result, or return 0 if not defined int pm_generic_runtime_resume(struct device *dev); - invoke the ->runtime_resume() callback provided by the driver of this - device and return its result, or return -EINVAL if not defined + device and return its result, or return 0 if not defined int pm_generic_suspend(struct device *dev); - if the device has not been suspended at run time, invoke the ->suspend() From fd6fe82673a87f188283b7fc2bdde4ffa0085f2a Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Mon, 24 Mar 2014 21:31:30 +0100 Subject: [PATCH 11/18] PM / Runtime: GENERIC_SUBSYS_PM_OPS is gone Update the documentation for the removal of GENERIC_SUBSYS_PM_OPS in commit 90363ddf0a1a4dccfbb8d0c10b8f488bc7fa69f8 ("PM: Drop generic_subsys_pm_ops") Signed-off-by: Geert Uytterhoeven Signed-off-by: Rafael J. Wysocki --- Documentation/power/runtime_pm.txt | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/Documentation/power/runtime_pm.txt b/Documentation/power/runtime_pm.txt index 8cc48b05939d..0c1c4124d23a 100644 --- a/Documentation/power/runtime_pm.txt +++ b/Documentation/power/runtime_pm.txt @@ -727,15 +727,12 @@ driver/base/power/generic_ops.c: int pm_generic_restore_noirq(struct device *dev); - invoke the ->restore_noirq() callback provided by the device's driver -These functions can be assigned to the ->runtime_idle(), ->runtime_suspend(), +These functions are the defaults used by the PM core, if a subsystem doesn't +provide its own callbacks for ->runtime_idle(), ->runtime_suspend(), ->runtime_resume(), ->suspend(), ->suspend_noirq(), ->resume(), ->resume_noirq(), ->freeze(), ->freeze_noirq(), ->thaw(), ->thaw_noirq(), -->poweroff(), ->poweroff_noirq(), ->restore(), ->restore_noirq() callback -pointers in the subsystem-level dev_pm_ops structures. - -If a subsystem wishes to use all of them at the same time, it can simply assign -the GENERIC_SUBSYS_PM_OPS macro, defined in include/linux/pm.h, to its -dev_pm_ops structure pointer. +->poweroff(), ->poweroff_noirq(), ->restore(), ->restore_noirq() in the +subsystem-level dev_pm_ops structure. Device drivers that wish to use the same function as a system suspend, freeze, poweroff and runtime suspend callback, and similarly for system resume, thaw, From fe98245073394a86039ad0ac55b240ac5b5db8f1 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Mon, 24 Mar 2014 21:31:31 +0100 Subject: [PATCH 12/18] PM / Runtime: s/foo_process_requests/foo_process_next_request/ The example uses foo_process_next_request() everywhere else. Signed-off-by: Geert Uytterhoeven Signed-off-by: Rafael J. Wysocki --- Documentation/power/runtime_pm.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/power/runtime_pm.txt b/Documentation/power/runtime_pm.txt index 0c1c4124d23a..5f96daf8566a 100644 --- a/Documentation/power/runtime_pm.txt +++ b/Documentation/power/runtime_pm.txt @@ -870,7 +870,7 @@ Here is a schematic pseudo-code example: foo->is_suspended = 0; pm_runtime_mark_last_busy(&foo->dev); if (foo->num_pending_requests > 0) - foo_process_requests(foo); + foo_process_next_request(foo); unlock(&foo->private_lock); return 0; } From 9accff57e050d35f6c84554005b0e7caf0429b19 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Mon, 24 Mar 2014 21:37:03 +0100 Subject: [PATCH 13/18] PM / Runtime: Spelling s/competing/completing/ Signed-off-by: Geert Uytterhoeven Signed-off-by: Rafael J. Wysocki --- drivers/base/power/generic_ops.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/base/power/generic_ops.c b/drivers/base/power/generic_ops.c index a2e55bfdf572..96a92db83cad 100644 --- a/drivers/base/power/generic_ops.c +++ b/drivers/base/power/generic_ops.c @@ -285,7 +285,7 @@ int pm_generic_restore(struct device *dev) EXPORT_SYMBOL_GPL(pm_generic_restore); /** - * pm_generic_complete - Generic routine competing a device power transition. + * pm_generic_complete - Generic routine completing a device power transition. * @dev: Device to handle. * * Complete a device power transition during a system-wide power transition. From 0c5aa405a9437d97e09ec289d4f29bb62e0f01b6 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Mon, 24 Mar 2014 12:30:29 +0530 Subject: [PATCH 14/18] cpufreq: resume drivers before enabling governors During suspend, we first stop governors and then suspend cpufreq drivers and resume must be exactly opposite of that. i.e. resume drivers first and then start governors. But the current code in resume enables governors first and then resume drivers. Fix it be changing code sequence there. Signed-off-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/cpufreq.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 3aa7a7a226b3..d8d6bc9d1815 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -1652,14 +1652,13 @@ void cpufreq_resume(void) cpufreq_suspended = false; list_for_each_entry(policy, &cpufreq_policy_list, policy_list) { - if (__cpufreq_governor(policy, CPUFREQ_GOV_START) + if (cpufreq_driver->resume && cpufreq_driver->resume(policy)) + pr_err("%s: Failed to resume driver: %p\n", __func__, + policy); + else if (__cpufreq_governor(policy, CPUFREQ_GOV_START) || __cpufreq_governor(policy, CPUFREQ_GOV_LIMITS)) pr_err("%s: Failed to start governor for policy: %p\n", __func__, policy); - else if (cpufreq_driver->resume - && cpufreq_driver->resume(policy)) - pr_err("%s: Failed to resume driver: %p\n", __func__, - policy); /* * schedule call cpufreq_update_policy() for boot CPU, i.e. last From c2294a2f7853e6450361d078b65407bdaa6d1d11 Mon Sep 17 00:00:00 2001 From: Dirk Brandewie Date: Mon, 24 Mar 2014 07:41:29 -0700 Subject: [PATCH 15/18] intel_pstate: Use del_timer_sync in intel_pstate_cpu_stop Ensure that no timer callback is running since we are about to free the timer structure. We cannot guarantee that the call back is called on the CPU where the timer is running. Reported-by: Thomas Gleixner Signed-off-by: Dirk Brandewie Reviewed-by: Srivatsa S. Bhat Acked-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/intel_pstate.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/cpufreq/intel_pstate.c b/drivers/cpufreq/intel_pstate.c index bcb9a6d0ae11..099967302bf2 100644 --- a/drivers/cpufreq/intel_pstate.c +++ b/drivers/cpufreq/intel_pstate.c @@ -778,7 +778,7 @@ static void intel_pstate_stop_cpu(struct cpufreq_policy *policy) pr_info("intel_pstate CPU %d exiting\n", cpu_num); - del_timer(&all_cpu_data[cpu_num]->timer); + del_timer_sync(&all_cpu_data[cpu_num]->timer); intel_pstate_set_pstate(cpu, cpu->pstate.min_pstate); kfree(all_cpu_data[cpu_num]); all_cpu_data[cpu_num] = NULL; From 12478cf0c55e5969f740bb38a24b1a0104ae18d8 Mon Sep 17 00:00:00 2001 From: "Srivatsa S. Bhat" Date: Mon, 24 Mar 2014 13:35:44 +0530 Subject: [PATCH 16/18] cpufreq: Make sure frequency transitions are serialized Whenever we change the frequency of a CPU, we call the PRECHANGE and POSTCHANGE notifiers. They must be serialized, i.e. PRECHANGE and POSTCHANGE notifiers should strictly alternate, thereby preventing two different sets of PRECHANGE or POSTCHANGE notifiers from interleaving arbitrarily. The following examples illustrate why this is important: Scenario 1: ----------- A thread reading the value of cpuinfo_cur_freq, will call __cpufreq_cpu_get()->cpufreq_out_of_sync()->cpufreq_notify_transition() The ondemand governor can decide to change the frequency of the CPU at the same time and hence it can end up sending the notifications via ->target(). If the notifiers are not serialized, the following sequence can occur: - PRECHANGE Notification for freq A (from cpuinfo_cur_freq) - PRECHANGE Notification for freq B (from target()) - Freq changed by target() to B - POSTCHANGE Notification for freq B - POSTCHANGE Notification for freq A We can see from the above that the last POSTCHANGE Notification happens for freq A but the hardware is set to run at freq B. Where would we break then?: adjust_jiffies() in cpufreq.c & cpufreq_callback() in arch/arm/kernel/smp.c (which also adjusts the jiffies). All the loops_per_jiffy calculations will get messed up. Scenario 2: ----------- The governor calls __cpufreq_driver_target() to change the frequency. At the same time, if we change scaling_{min|max}_freq from sysfs, it will end up calling the governor's CPUFREQ_GOV_LIMITS notification, which will also call __cpufreq_driver_target(). And hence we end up issuing concurrent calls to ->target(). Typically, platforms have the following logic in their ->target() routines: (Eg: cpufreq-cpu0, omap, exynos, etc) A. If new freq is more than old: Increase voltage B. Change freq C. If new freq is less than old: decrease voltage Now, if the two concurrent calls to ->target() are X and Y, where X is trying to increase the freq and Y is trying to decrease it, we get the following race condition: X.A: voltage gets increased for larger freq Y.A: nothing happens Y.B: freq gets decreased Y.C: voltage gets decreased X.B: freq gets increased X.C: nothing happens Thus we can end up setting a freq which is not supported by the voltage we have set. That will probably make the clock to the CPU unstable and the system might not work properly anymore. This patch introduces a set of synchronization primitives to serialize frequency transitions, which are to be used as shown below: cpufreq_freq_transition_begin(); //Perform the frequency change cpufreq_freq_transition_end(); The _begin() call sends the PRECHANGE notification whereas the _end() call sends the POSTCHANGE notification. Also, all the necessary synchronization is handled within these calls. In particular, even drivers which set the ASYNC_NOTIFICATION flag can also use these APIs for performing frequency transitions (ie., you can call _begin() from one task, and call the corresponding _end() from a different task). The actual synchronization underneath is not that complicated: The key challenge is to allow drivers to begin the transition from one thread and end it in a completely different thread (this is to enable drivers that do asynchronous POSTCHANGE notification from bottom-halves, to also use the same interface). To achieve this, a 'transition_ongoing' flag, a 'transition_lock' spinlock and a wait-queue are added per-policy. The flag and the wait-queue are used in conjunction to create an "uninterrupted flow" from _begin() to _end(). The spinlock is used to ensure that only one such "flow" is in flight at any given time. Put together, this provides us all the necessary synchronization. Signed-off-by: Srivatsa S. Bhat Signed-off-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/cpufreq.c | 37 +++++++++++++++++++++++++++++++++++++ include/linux/cpufreq.h | 10 ++++++++++ 2 files changed, 47 insertions(+) diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index d8d6bc9d1815..d57806a85def 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -353,6 +353,41 @@ void cpufreq_notify_post_transition(struct cpufreq_policy *policy, } EXPORT_SYMBOL_GPL(cpufreq_notify_post_transition); +void cpufreq_freq_transition_begin(struct cpufreq_policy *policy, + struct cpufreq_freqs *freqs) +{ +wait: + wait_event(policy->transition_wait, !policy->transition_ongoing); + + spin_lock(&policy->transition_lock); + + if (unlikely(policy->transition_ongoing)) { + spin_unlock(&policy->transition_lock); + goto wait; + } + + policy->transition_ongoing = true; + + spin_unlock(&policy->transition_lock); + + cpufreq_notify_transition(policy, freqs, CPUFREQ_PRECHANGE); +} +EXPORT_SYMBOL_GPL(cpufreq_freq_transition_begin); + +void cpufreq_freq_transition_end(struct cpufreq_policy *policy, + struct cpufreq_freqs *freqs, int transition_failed) +{ + if (unlikely(WARN_ON(!policy->transition_ongoing))) + return; + + cpufreq_notify_post_transition(policy, freqs, transition_failed); + + policy->transition_ongoing = false; + + wake_up(&policy->transition_wait); +} +EXPORT_SYMBOL_GPL(cpufreq_freq_transition_end); + /********************************************************************* * SYSFS INTERFACE * @@ -985,6 +1020,8 @@ static struct cpufreq_policy *cpufreq_policy_alloc(void) INIT_LIST_HEAD(&policy->policy_list); init_rwsem(&policy->rwsem); + spin_lock_init(&policy->transition_lock); + init_waitqueue_head(&policy->transition_wait); return policy; diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h index 2d2e62c8666a..e33760268a86 100644 --- a/include/linux/cpufreq.h +++ b/include/linux/cpufreq.h @@ -16,6 +16,7 @@ #include #include #include +#include #include /********************************************************************* @@ -104,6 +105,11 @@ struct cpufreq_policy { * __cpufreq_governor(data, CPUFREQ_GOV_POLICY_EXIT); */ struct rw_semaphore rwsem; + + /* Synchronization for frequency transitions */ + bool transition_ongoing; /* Tracks transition status */ + spinlock_t transition_lock; + wait_queue_head_t transition_wait; }; /* Only for ACPI */ @@ -337,6 +343,10 @@ void cpufreq_notify_transition(struct cpufreq_policy *policy, struct cpufreq_freqs *freqs, unsigned int state); void cpufreq_notify_post_transition(struct cpufreq_policy *policy, struct cpufreq_freqs *freqs, int transition_failed); +void cpufreq_freq_transition_begin(struct cpufreq_policy *policy, + struct cpufreq_freqs *freqs); +void cpufreq_freq_transition_end(struct cpufreq_policy *policy, + struct cpufreq_freqs *freqs, int transition_failed); #else /* CONFIG_CPU_FREQ */ static inline int cpufreq_register_notifier(struct notifier_block *nb, From 8fec051eea736ec1d8060a2c8766bf3a6b32c3d2 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Mon, 24 Mar 2014 13:35:45 +0530 Subject: [PATCH 17/18] cpufreq: Convert existing drivers to use cpufreq_freq_transition_{begin|end} CPUFreq core has new infrastructure that would guarantee serialized calls to target() or target_index() callbacks. These are called cpufreq_freq_transition_begin() and cpufreq_freq_transition_end(). This patch converts existing drivers to use these new set of routines. Reviewed-by: Srivatsa S. Bhat Signed-off-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/cpufreq-nforce2.c | 4 ++-- drivers/cpufreq/cpufreq.c | 9 ++++----- drivers/cpufreq/exynos5440-cpufreq.c | 4 ++-- drivers/cpufreq/gx-suspmod.c | 4 ++-- drivers/cpufreq/integrator-cpufreq.c | 4 ++-- drivers/cpufreq/longhaul.c | 4 ++-- drivers/cpufreq/pcc-cpufreq.c | 4 ++-- drivers/cpufreq/powernow-k6.c | 4 ++-- drivers/cpufreq/powernow-k7.c | 4 ++-- drivers/cpufreq/powernow-k8.c | 4 ++-- drivers/cpufreq/s3c24xx-cpufreq.c | 4 ++-- drivers/cpufreq/sh-cpufreq.c | 4 ++-- drivers/cpufreq/unicore2-cpufreq.c | 4 ++-- 13 files changed, 28 insertions(+), 29 deletions(-) diff --git a/drivers/cpufreq/cpufreq-nforce2.c b/drivers/cpufreq/cpufreq-nforce2.c index a05b876f375e..bc447b9003c3 100644 --- a/drivers/cpufreq/cpufreq-nforce2.c +++ b/drivers/cpufreq/cpufreq-nforce2.c @@ -270,7 +270,7 @@ static int nforce2_target(struct cpufreq_policy *policy, pr_debug("Old CPU frequency %d kHz, new %d kHz\n", freqs.old, freqs.new); - cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE); + cpufreq_freq_transition_begin(policy, &freqs); /* Disable IRQs */ /* local_irq_save(flags); */ @@ -285,7 +285,7 @@ static int nforce2_target(struct cpufreq_policy *policy, /* Enable IRQs */ /* local_irq_restore(flags); */ - cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE); + cpufreq_freq_transition_end(policy, &freqs, 0); return 0; } diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index d57806a85def..eb562d043412 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -1507,8 +1507,8 @@ static void cpufreq_out_of_sync(unsigned int cpu, unsigned int old_freq, policy = per_cpu(cpufreq_cpu_data, cpu); read_unlock_irqrestore(&cpufreq_driver_lock, flags); - cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE); - cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE); + cpufreq_freq_transition_begin(policy, &freqs); + cpufreq_freq_transition_end(policy, &freqs, 0); } /** @@ -1868,8 +1868,7 @@ int __cpufreq_driver_target(struct cpufreq_policy *policy, pr_debug("%s: cpu: %d, oldfreq: %u, new freq: %u\n", __func__, policy->cpu, freqs.old, freqs.new); - cpufreq_notify_transition(policy, &freqs, - CPUFREQ_PRECHANGE); + cpufreq_freq_transition_begin(policy, &freqs); } retval = cpufreq_driver->target_index(policy, index); @@ -1878,7 +1877,7 @@ int __cpufreq_driver_target(struct cpufreq_policy *policy, __func__, retval); if (notify) - cpufreq_notify_post_transition(policy, &freqs, retval); + cpufreq_freq_transition_end(policy, &freqs, retval); } out: diff --git a/drivers/cpufreq/exynos5440-cpufreq.c b/drivers/cpufreq/exynos5440-cpufreq.c index 7f776aa91e2f..a6b8214d7b77 100644 --- a/drivers/cpufreq/exynos5440-cpufreq.c +++ b/drivers/cpufreq/exynos5440-cpufreq.c @@ -219,7 +219,7 @@ static int exynos_target(struct cpufreq_policy *policy, unsigned int index) freqs.old = policy->cur; freqs.new = freq_table[index].frequency; - cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE); + cpufreq_freq_transition_begin(policy, &freqs); /* Set the target frequency in all C0_3_PSTATE register */ for_each_cpu(i, policy->cpus) { @@ -258,7 +258,7 @@ static void exynos_cpufreq_work(struct work_struct *work) dev_crit(dvfs_info->dev, "New frequency out of range\n"); freqs.new = freqs.old; } - cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE); + cpufreq_freq_transition_end(policy, &freqs, 0); cpufreq_cpu_put(policy); mutex_unlock(&cpufreq_lock); diff --git a/drivers/cpufreq/gx-suspmod.c b/drivers/cpufreq/gx-suspmod.c index d83e8266a58e..1d723dc8880c 100644 --- a/drivers/cpufreq/gx-suspmod.c +++ b/drivers/cpufreq/gx-suspmod.c @@ -265,7 +265,7 @@ static void gx_set_cpuspeed(struct cpufreq_policy *policy, unsigned int khz) freqs.new = new_khz; - cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE); + cpufreq_freq_transition_begin(policy, &freqs); local_irq_save(flags); if (new_khz != stock_freq) { @@ -314,7 +314,7 @@ static void gx_set_cpuspeed(struct cpufreq_policy *policy, unsigned int khz) gx_params->pci_suscfg = suscfg; - cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE); + cpufreq_freq_transition_end(policy, &freqs, 0); pr_debug("suspend modulation w/ duration of ON:%d us, OFF:%d us\n", gx_params->on_duration * 32, gx_params->off_duration * 32); diff --git a/drivers/cpufreq/integrator-cpufreq.c b/drivers/cpufreq/integrator-cpufreq.c index 0e27844e8c2d..e5122f1bfe78 100644 --- a/drivers/cpufreq/integrator-cpufreq.c +++ b/drivers/cpufreq/integrator-cpufreq.c @@ -122,7 +122,7 @@ static int integrator_set_target(struct cpufreq_policy *policy, return 0; } - cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE); + cpufreq_freq_transition_begin(policy, &freqs); cm_osc = __raw_readl(cm_base + INTEGRATOR_HDR_OSC_OFFSET); @@ -143,7 +143,7 @@ static int integrator_set_target(struct cpufreq_policy *policy, */ set_cpus_allowed(current, cpus_allowed); - cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE); + cpufreq_freq_transition_end(policy, &freqs, 0); return 0; } diff --git a/drivers/cpufreq/longhaul.c b/drivers/cpufreq/longhaul.c index 7b94da3d2d10..5c440f87ba8a 100644 --- a/drivers/cpufreq/longhaul.c +++ b/drivers/cpufreq/longhaul.c @@ -269,7 +269,7 @@ static void longhaul_setstate(struct cpufreq_policy *policy, freqs.old = calc_speed(longhaul_get_cpu_mult()); freqs.new = speed; - cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE); + cpufreq_freq_transition_begin(policy, &freqs); pr_debug("Setting to FSB:%dMHz Mult:%d.%dx (%s)\n", fsb, mult/10, mult%10, print_speed(speed/1000)); @@ -386,7 +386,7 @@ retry_loop: } } /* Report true CPU frequency */ - cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE); + cpufreq_freq_transition_end(policy, &freqs, 0); if (!bm_timeout) printk(KERN_INFO PFX "Warning: Timeout while waiting for " diff --git a/drivers/cpufreq/pcc-cpufreq.c b/drivers/cpufreq/pcc-cpufreq.c index 1c0f1067af73..728a2d879499 100644 --- a/drivers/cpufreq/pcc-cpufreq.c +++ b/drivers/cpufreq/pcc-cpufreq.c @@ -215,7 +215,7 @@ static int pcc_cpufreq_target(struct cpufreq_policy *policy, freqs.old = policy->cur; freqs.new = target_freq; - cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE); + cpufreq_freq_transition_begin(policy, &freqs); input_buffer = 0x1 | (((target_freq * 100) / (ioread32(&pcch_hdr->nominal) * 1000)) << 8); @@ -231,7 +231,7 @@ static int pcc_cpufreq_target(struct cpufreq_policy *policy, status = ioread16(&pcch_hdr->status); iowrite16(0, &pcch_hdr->status); - cpufreq_notify_post_transition(policy, &freqs, status != CMD_COMPLETE); + cpufreq_freq_transition_end(policy, &freqs, status != CMD_COMPLETE); spin_unlock(&pcc_lock); if (status != CMD_COMPLETE) { diff --git a/drivers/cpufreq/powernow-k6.c b/drivers/cpufreq/powernow-k6.c index ce27e6c26c94..62c6f2e5afce 100644 --- a/drivers/cpufreq/powernow-k6.c +++ b/drivers/cpufreq/powernow-k6.c @@ -148,11 +148,11 @@ static int powernow_k6_target(struct cpufreq_policy *policy, freqs.old = busfreq * powernow_k6_get_cpu_multiplier(); freqs.new = busfreq * clock_ratio[best_i].driver_data; - cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE); + cpufreq_freq_transition_begin(policy, &freqs); powernow_k6_set_cpu_multiplier(best_i); - cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE); + cpufreq_freq_transition_end(policy, &freqs, 0); return 0; } diff --git a/drivers/cpufreq/powernow-k7.c b/drivers/cpufreq/powernow-k7.c index 0e68e0275621..f911645c3f6d 100644 --- a/drivers/cpufreq/powernow-k7.c +++ b/drivers/cpufreq/powernow-k7.c @@ -269,7 +269,7 @@ static int powernow_target(struct cpufreq_policy *policy, unsigned int index) freqs.new = powernow_table[index].frequency; - cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE); + cpufreq_freq_transition_begin(policy, &freqs); /* Now do the magic poking into the MSRs. */ @@ -290,7 +290,7 @@ static int powernow_target(struct cpufreq_policy *policy, unsigned int index) if (have_a0 == 1) local_irq_enable(); - cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE); + cpufreq_freq_transition_end(policy, &freqs, 0); return 0; } diff --git a/drivers/cpufreq/powernow-k8.c b/drivers/cpufreq/powernow-k8.c index 27eb2be44de5..770a9e1b3468 100644 --- a/drivers/cpufreq/powernow-k8.c +++ b/drivers/cpufreq/powernow-k8.c @@ -963,9 +963,9 @@ static int transition_frequency_fidvid(struct powernow_k8_data *data, policy = cpufreq_cpu_get(smp_processor_id()); cpufreq_cpu_put(policy); - cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE); + cpufreq_freq_transition_begin(policy, &freqs); res = transition_fid_vid(data, fid, vid); - cpufreq_notify_post_transition(policy, &freqs, res); + cpufreq_freq_transition_end(policy, &freqs, res); return res; } diff --git a/drivers/cpufreq/s3c24xx-cpufreq.c b/drivers/cpufreq/s3c24xx-cpufreq.c index 25069741b507..a3dc192d21f9 100644 --- a/drivers/cpufreq/s3c24xx-cpufreq.c +++ b/drivers/cpufreq/s3c24xx-cpufreq.c @@ -217,7 +217,7 @@ static int s3c_cpufreq_settarget(struct cpufreq_policy *policy, s3c_cpufreq_updateclk(clk_pclk, cpu_new.freq.pclk); /* start the frequency change */ - cpufreq_notify_transition(policy, &freqs.freqs, CPUFREQ_PRECHANGE); + cpufreq_freq_transition_begin(policy, &freqs.freqs); /* If hclk is staying the same, then we do not need to * re-write the IO or the refresh timings whilst we are changing @@ -261,7 +261,7 @@ static int s3c_cpufreq_settarget(struct cpufreq_policy *policy, local_irq_restore(flags); /* notify everyone we've done this */ - cpufreq_notify_transition(policy, &freqs.freqs, CPUFREQ_POSTCHANGE); + cpufreq_freq_transition_end(policy, &freqs.freqs, 0); s3c_freq_dbg("%s: finished\n", __func__); return 0; diff --git a/drivers/cpufreq/sh-cpufreq.c b/drivers/cpufreq/sh-cpufreq.c index 696170ebd3a3..86628e22b2a3 100644 --- a/drivers/cpufreq/sh-cpufreq.c +++ b/drivers/cpufreq/sh-cpufreq.c @@ -68,10 +68,10 @@ static int sh_cpufreq_target(struct cpufreq_policy *policy, freqs.new = (freq + 500) / 1000; freqs.flags = 0; - cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE); + cpufreq_freq_transition_begin(policy, &freqs); set_cpus_allowed_ptr(current, &cpus_allowed); clk_set_rate(cpuclk, freq); - cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE); + cpufreq_freq_transition_end(policy, &freqs, 0); dev_dbg(dev, "set frequency %lu Hz\n", freq); diff --git a/drivers/cpufreq/unicore2-cpufreq.c b/drivers/cpufreq/unicore2-cpufreq.c index 36cc330b8747..13be802b6170 100644 --- a/drivers/cpufreq/unicore2-cpufreq.c +++ b/drivers/cpufreq/unicore2-cpufreq.c @@ -44,9 +44,9 @@ static int ucv2_target(struct cpufreq_policy *policy, freqs.old = policy->cur; freqs.new = target_freq; - cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE); + cpufreq_freq_transition_begin(policy, &freqs); ret = clk_set_rate(policy->mclk, target_freq * 1000); - cpufreq_notify_post_transition(policy, &freqs, ret); + cpufreq_freq_transition_end(policy, &freqs, ret); return ret; } From 236a98005274d8011136aee4aef52241588a9712 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Mon, 24 Mar 2014 13:35:46 +0530 Subject: [PATCH 18/18] cpufreq: Make cpufreq_notify_transition & cpufreq_notify_post_transition static cpufreq_notify_transition() and cpufreq_notify_post_transition() shouldn't be called directly by cpufreq drivers anymore and so these should be marked static. Reviewed-by: Srivatsa S. Bhat Signed-off-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/cpufreq.c | 6 ++---- include/linux/cpufreq.h | 4 ---- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index eb562d043412..abda6609d3e7 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -331,16 +331,15 @@ static void __cpufreq_notify_transition(struct cpufreq_policy *policy, * function. It is called twice on all CPU frequency changes that have * external effects. */ -void cpufreq_notify_transition(struct cpufreq_policy *policy, +static void cpufreq_notify_transition(struct cpufreq_policy *policy, struct cpufreq_freqs *freqs, unsigned int state) { for_each_cpu(freqs->cpu, policy->cpus) __cpufreq_notify_transition(policy, freqs, state); } -EXPORT_SYMBOL_GPL(cpufreq_notify_transition); /* Do post notifications when there are chances that transition has failed */ -void cpufreq_notify_post_transition(struct cpufreq_policy *policy, +static void cpufreq_notify_post_transition(struct cpufreq_policy *policy, struct cpufreq_freqs *freqs, int transition_failed) { cpufreq_notify_transition(policy, freqs, CPUFREQ_POSTCHANGE); @@ -351,7 +350,6 @@ void cpufreq_notify_post_transition(struct cpufreq_policy *policy, cpufreq_notify_transition(policy, freqs, CPUFREQ_PRECHANGE); cpufreq_notify_transition(policy, freqs, CPUFREQ_POSTCHANGE); } -EXPORT_SYMBOL_GPL(cpufreq_notify_post_transition); void cpufreq_freq_transition_begin(struct cpufreq_policy *policy, struct cpufreq_freqs *freqs) diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h index e33760268a86..c48e595f623e 100644 --- a/include/linux/cpufreq.h +++ b/include/linux/cpufreq.h @@ -339,10 +339,6 @@ static inline void cpufreq_resume(void) {} int cpufreq_register_notifier(struct notifier_block *nb, unsigned int list); int cpufreq_unregister_notifier(struct notifier_block *nb, unsigned int list); -void cpufreq_notify_transition(struct cpufreq_policy *policy, - struct cpufreq_freqs *freqs, unsigned int state); -void cpufreq_notify_post_transition(struct cpufreq_policy *policy, - struct cpufreq_freqs *freqs, int transition_failed); void cpufreq_freq_transition_begin(struct cpufreq_policy *policy, struct cpufreq_freqs *freqs); void cpufreq_freq_transition_end(struct cpufreq_policy *policy,