@@ -165,8 +165,16 @@ struct transaction {
165
165
u8 flags ;
166
166
};
167
167
168
+ struct acpi_ec_query {
169
+ struct transaction transaction ;
170
+ struct work_struct work ;
171
+ struct acpi_ec_query_handler * handler ;
172
+ };
173
+
168
174
static int acpi_ec_query (struct acpi_ec * ec , u8 * data );
169
175
static void advance_transaction (struct acpi_ec * ec );
176
+ static void acpi_ec_event_handler (struct work_struct * work );
177
+ static void acpi_ec_event_processor (struct work_struct * work );
170
178
171
179
struct acpi_ec * boot_ec , * first_ec ;
172
180
EXPORT_SYMBOL (first_ec );
@@ -978,60 +986,90 @@ void acpi_ec_remove_query_handler(struct acpi_ec *ec, u8 query_bit)
978
986
}
979
987
EXPORT_SYMBOL_GPL (acpi_ec_remove_query_handler );
980
988
981
- static void acpi_ec_run ( void * cxt )
989
+ static struct acpi_ec_query * acpi_ec_create_query ( u8 * pval )
982
990
{
983
- struct acpi_ec_query_handler * handler = cxt ;
991
+ struct acpi_ec_query * q ;
992
+ struct transaction * t ;
993
+
994
+ q = kzalloc (sizeof (struct acpi_ec_query ), GFP_KERNEL );
995
+ if (!q )
996
+ return NULL ;
997
+ INIT_WORK (& q -> work , acpi_ec_event_processor );
998
+ t = & q -> transaction ;
999
+ t -> command = ACPI_EC_COMMAND_QUERY ;
1000
+ t -> rdata = pval ;
1001
+ t -> rlen = 1 ;
1002
+ return q ;
1003
+ }
1004
+
1005
+ static void acpi_ec_delete_query (struct acpi_ec_query * q )
1006
+ {
1007
+ if (q ) {
1008
+ if (q -> handler )
1009
+ acpi_ec_put_query_handler (q -> handler );
1010
+ kfree (q );
1011
+ }
1012
+ }
1013
+
1014
+ static void acpi_ec_event_processor (struct work_struct * work )
1015
+ {
1016
+ struct acpi_ec_query * q = container_of (work , struct acpi_ec_query , work );
1017
+ struct acpi_ec_query_handler * handler = q -> handler ;
984
1018
985
- if (!handler )
986
- return ;
987
1019
ec_dbg_evt ("Query(0x%02x) started" , handler -> query_bit );
988
1020
if (handler -> func )
989
1021
handler -> func (handler -> data );
990
1022
else if (handler -> handle )
991
1023
acpi_evaluate_object (handler -> handle , NULL , NULL , NULL );
992
1024
ec_dbg_evt ("Query(0x%02x) stopped" , handler -> query_bit );
993
- acpi_ec_put_query_handler ( handler );
1025
+ acpi_ec_delete_query ( q );
994
1026
}
995
1027
996
1028
static int acpi_ec_query (struct acpi_ec * ec , u8 * data )
997
1029
{
998
1030
u8 value = 0 ;
999
1031
int result ;
1000
- acpi_status status ;
1001
1032
struct acpi_ec_query_handler * handler ;
1002
- struct transaction t = {.command = ACPI_EC_COMMAND_QUERY ,
1003
- .wdata = NULL , .rdata = & value ,
1004
- .wlen = 0 , .rlen = 1 };
1033
+ struct acpi_ec_query * q ;
1034
+
1035
+ q = acpi_ec_create_query (& value );
1036
+ if (!q )
1037
+ return - ENOMEM ;
1005
1038
1006
1039
/*
1007
1040
* Query the EC to find out which _Qxx method we need to evaluate.
1008
1041
* Note that successful completion of the query causes the ACPI_EC_SCI
1009
1042
* bit to be cleared (and thus clearing the interrupt source).
1010
1043
*/
1011
- result = acpi_ec_transaction (ec , & t );
1012
- if (result )
1013
- return result ;
1014
- if (data )
1015
- * data = value ;
1044
+ result = acpi_ec_transaction (ec , & q -> transaction );
1016
1045
if (!value )
1017
- return - ENODATA ;
1046
+ result = - ENODATA ;
1047
+ if (result )
1048
+ goto err_exit ;
1018
1049
1019
1050
mutex_lock (& ec -> mutex );
1020
1051
list_for_each_entry (handler , & ec -> list , node ) {
1021
1052
if (value == handler -> query_bit ) {
1022
- /* have custom handler for this bit */
1023
- handler = acpi_ec_get_query_handler (handler );
1053
+ q -> handler = acpi_ec_get_query_handler (handler );
1024
1054
ec_dbg_evt ("Query(0x%02x) scheduled" ,
1025
- handler -> query_bit );
1026
- status = acpi_os_execute ((handler -> func ) ?
1027
- OSL_NOTIFY_HANDLER : OSL_GPE_HANDLER ,
1028
- acpi_ec_run , handler );
1029
- if (ACPI_FAILURE (status ))
1055
+ q -> handler -> query_bit );
1056
+ /*
1057
+ * It is reported that _Qxx are evaluated in a
1058
+ * parallel way on Windows:
1059
+ * https://bugzilla.kernel.org/show_bug.cgi?id=94411
1060
+ */
1061
+ if (!schedule_work (& q -> work ))
1030
1062
result = - EBUSY ;
1031
1063
break ;
1032
1064
}
1033
1065
}
1034
1066
mutex_unlock (& ec -> mutex );
1067
+
1068
+ err_exit :
1069
+ if (result && q )
1070
+ acpi_ec_delete_query (q );
1071
+ if (data )
1072
+ * data = value ;
1035
1073
return result ;
1036
1074
}
1037
1075
0 commit comments