Commit 0700c047 authored by Lv Zheng's avatar Lv Zheng Committed by Rafael J. Wysocki

ACPI / EC: Fix query handler related issues

1. acpi_ec_remove_query_handlers()
This patch refines the query handler removal logic implemented in
acpi_ec_remove_query_handler(), making it to invoke new
acpi_ec_remove_query_handlers() API, and ensuring all other removal code
paths to invoke the new API to honor the reference count of the query
handlers.

2. acpi_ec_get_query_handler_by_value()
This patch also refines the query handler search logic originally
implemented in acpi_ec_query(), collecting it into
acpi_ec_get_query_handler_by_value(). And since schedule_work() can ensure
the serilization of acpi_ec_event_handler(), we needn't put the
mutex_lock() around schedule_work().
Signed-off-by: default avatarLv Zheng <lv.zheng@intel.com>
Signed-off-by: default avatarRafael J. Wysocki <rafael.j.wysocki@intel.com>
parent 15b94fa3
...@@ -929,6 +929,23 @@ acpi_ec_get_query_handler(struct acpi_ec_query_handler *handler) ...@@ -929,6 +929,23 @@ acpi_ec_get_query_handler(struct acpi_ec_query_handler *handler)
return handler; return handler;
} }
static struct acpi_ec_query_handler *
acpi_ec_get_query_handler_by_value(struct acpi_ec *ec, u8 value)
{
struct acpi_ec_query_handler *handler;
bool found = false;
mutex_lock(&ec->mutex);
list_for_each_entry(handler, &ec->list, node) {
if (value == handler->query_bit) {
found = true;
break;
}
}
mutex_unlock(&ec->mutex);
return found ? acpi_ec_get_query_handler(handler) : NULL;
}
static void acpi_ec_query_handler_release(struct kref *kref) static void acpi_ec_query_handler_release(struct kref *kref)
{ {
struct acpi_ec_query_handler *handler = struct acpi_ec_query_handler *handler =
...@@ -964,14 +981,15 @@ int acpi_ec_add_query_handler(struct acpi_ec *ec, u8 query_bit, ...@@ -964,14 +981,15 @@ int acpi_ec_add_query_handler(struct acpi_ec *ec, u8 query_bit,
} }
EXPORT_SYMBOL_GPL(acpi_ec_add_query_handler); EXPORT_SYMBOL_GPL(acpi_ec_add_query_handler);
void acpi_ec_remove_query_handler(struct acpi_ec *ec, u8 query_bit) static void acpi_ec_remove_query_handlers(struct acpi_ec *ec,
bool remove_all, u8 query_bit)
{ {
struct acpi_ec_query_handler *handler, *tmp; struct acpi_ec_query_handler *handler, *tmp;
LIST_HEAD(free_list); LIST_HEAD(free_list);
mutex_lock(&ec->mutex); mutex_lock(&ec->mutex);
list_for_each_entry_safe(handler, tmp, &ec->list, node) { list_for_each_entry_safe(handler, tmp, &ec->list, node) {
if (query_bit == handler->query_bit) { if (remove_all || query_bit == handler->query_bit) {
list_del_init(&handler->node); list_del_init(&handler->node);
list_add(&handler->node, &free_list); list_add(&handler->node, &free_list);
} }
...@@ -980,6 +998,11 @@ void acpi_ec_remove_query_handler(struct acpi_ec *ec, u8 query_bit) ...@@ -980,6 +998,11 @@ void acpi_ec_remove_query_handler(struct acpi_ec *ec, u8 query_bit)
list_for_each_entry_safe(handler, tmp, &free_list, node) list_for_each_entry_safe(handler, tmp, &free_list, node)
acpi_ec_put_query_handler(handler); acpi_ec_put_query_handler(handler);
} }
void acpi_ec_remove_query_handler(struct acpi_ec *ec, u8 query_bit)
{
acpi_ec_remove_query_handlers(ec, false, query_bit);
}
EXPORT_SYMBOL_GPL(acpi_ec_remove_query_handler); EXPORT_SYMBOL_GPL(acpi_ec_remove_query_handler);
static struct acpi_ec_query *acpi_ec_create_query(u8 *pval) static struct acpi_ec_query *acpi_ec_create_query(u8 *pval)
...@@ -1025,7 +1048,6 @@ static int acpi_ec_query(struct acpi_ec *ec, u8 *data) ...@@ -1025,7 +1048,6 @@ static int acpi_ec_query(struct acpi_ec *ec, u8 *data)
{ {
u8 value = 0; u8 value = 0;
int result; int result;
struct acpi_ec_query_handler *handler;
struct acpi_ec_query *q; struct acpi_ec_query *q;
q = acpi_ec_create_query(&value); q = acpi_ec_create_query(&value);
...@@ -1043,25 +1065,26 @@ static int acpi_ec_query(struct acpi_ec *ec, u8 *data) ...@@ -1043,25 +1065,26 @@ static int acpi_ec_query(struct acpi_ec *ec, u8 *data)
if (result) if (result)
goto err_exit; goto err_exit;
mutex_lock(&ec->mutex); q->handler = acpi_ec_get_query_handler_by_value(ec, value);
result = -ENODATA; if (!q->handler) {
list_for_each_entry(handler, &ec->list, node) { result = -ENODATA;
if (value == handler->query_bit) { goto err_exit;
result = 0; }
q->handler = acpi_ec_get_query_handler(handler);
ec_dbg_evt("Query(0x%02x) scheduled", /*
q->handler->query_bit); * It is reported that _Qxx are evaluated in a parallel way on
/* * Windows:
* It is reported that _Qxx are evaluated in a * https://bugzilla.kernel.org/show_bug.cgi?id=94411
* parallel way on Windows: *
* https://bugzilla.kernel.org/show_bug.cgi?id=94411 * Put this log entry before schedule_work() in order to make
*/ * it appearing before any other log entries occurred during the
if (!schedule_work(&q->work)) * work queue execution.
result = -EBUSY; */
break; ec_dbg_evt("Query(0x%02x) scheduled", value);
} if (!schedule_work(&q->work)) {
ec_dbg_evt("Query(0x%02x) overlapped", value);
result = -EBUSY;
} }
mutex_unlock(&ec->mutex);
err_exit: err_exit:
if (result && q) if (result && q)
...@@ -1354,19 +1377,13 @@ static int acpi_ec_add(struct acpi_device *device) ...@@ -1354,19 +1377,13 @@ static int acpi_ec_add(struct acpi_device *device)
static int acpi_ec_remove(struct acpi_device *device) static int acpi_ec_remove(struct acpi_device *device)
{ {
struct acpi_ec *ec; struct acpi_ec *ec;
struct acpi_ec_query_handler *handler, *tmp;
if (!device) if (!device)
return -EINVAL; return -EINVAL;
ec = acpi_driver_data(device); ec = acpi_driver_data(device);
ec_remove_handlers(ec); ec_remove_handlers(ec);
mutex_lock(&ec->mutex); acpi_ec_remove_query_handlers(ec, true, 0);
list_for_each_entry_safe(handler, tmp, &ec->list, node) {
list_del(&handler->node);
kfree(handler);
}
mutex_unlock(&ec->mutex);
release_region(ec->data_addr, 1); release_region(ec->data_addr, 1);
release_region(ec->command_addr, 1); release_region(ec->command_addr, 1);
device->driver_data = NULL; device->driver_data = NULL;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment