From: Lv Zheng Date: Wed, 14 Jan 2015 11:28:28 +0000 (+0800) Subject: ACPI / EC: Add reference counting for query handlers X-Git-Tag: fixes-v4.0-rc1~160^2~10^2~13 X-Git-Url: https://git.openpandora.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=01305d4139cd345aa9f64cecfd7fc7b237e1444e;p=pandora-kernel.git ACPI / EC: Add reference counting for query handlers This patch adds reference counting for query handlers in order to eliminate kmalloc()/kfree() usage. Signed-off-by: Lv Zheng Tested-by: Steffen Weber Tested-by: Ortwin Glück Signed-off-by: Rafael J. Wysocki --- diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index 3e19123bb183..87b9911c9039 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -105,6 +105,7 @@ struct acpi_ec_query_handler { acpi_handle handle; void *data; u8 query_bit; + struct kref kref; }; struct transaction { @@ -580,6 +581,27 @@ static int acpi_ec_query_unlocked(struct acpi_ec *ec, u8 *data) /* -------------------------------------------------------------------------- Event Management -------------------------------------------------------------------------- */ +static struct acpi_ec_query_handler * +acpi_ec_get_query_handler(struct acpi_ec_query_handler *handler) +{ + if (handler) + kref_get(&handler->kref); + return handler; +} + +static void acpi_ec_query_handler_release(struct kref *kref) +{ + struct acpi_ec_query_handler *handler = + container_of(kref, struct acpi_ec_query_handler, kref); + + kfree(handler); +} + +static void acpi_ec_put_query_handler(struct acpi_ec_query_handler *handler) +{ + kref_put(&handler->kref, acpi_ec_query_handler_release); +} + int acpi_ec_add_query_handler(struct acpi_ec *ec, u8 query_bit, acpi_handle handle, acpi_ec_query_func func, void *data) @@ -595,6 +617,7 @@ int acpi_ec_add_query_handler(struct acpi_ec *ec, u8 query_bit, handler->func = func; handler->data = data; mutex_lock(&ec->mutex); + kref_init(&handler->kref); list_add(&handler->node, &ec->list); mutex_unlock(&ec->mutex); return 0; @@ -604,15 +627,18 @@ EXPORT_SYMBOL_GPL(acpi_ec_add_query_handler); void acpi_ec_remove_query_handler(struct acpi_ec *ec, u8 query_bit) { struct acpi_ec_query_handler *handler, *tmp; + LIST_HEAD(free_list); mutex_lock(&ec->mutex); list_for_each_entry_safe(handler, tmp, &ec->list, node) { if (query_bit == handler->query_bit) { - list_del(&handler->node); - kfree(handler); + list_del_init(&handler->node); + list_add(&handler->node, &free_list); } } mutex_unlock(&ec->mutex); + list_for_each_entry(handler, &free_list, node) + acpi_ec_put_query_handler(handler); } EXPORT_SYMBOL_GPL(acpi_ec_remove_query_handler); @@ -628,14 +654,14 @@ static void acpi_ec_run(void *cxt) else if (handler->handle) acpi_evaluate_object(handler->handle, NULL, NULL, NULL); pr_debug("##### Query(0x%02x) stopped #####\n", handler->query_bit); - kfree(handler); + acpi_ec_put_query_handler(handler); } static int acpi_ec_sync_query(struct acpi_ec *ec, u8 *data) { u8 value = 0; int status; - struct acpi_ec_query_handler *handler, *copy; + struct acpi_ec_query_handler *handler; status = acpi_ec_query_unlocked(ec, &value); if (data) @@ -646,15 +672,12 @@ static int acpi_ec_sync_query(struct acpi_ec *ec, u8 *data) list_for_each_entry(handler, &ec->list, node) { if (value == handler->query_bit) { /* have custom handler for this bit */ - copy = kmalloc(sizeof(*handler), GFP_KERNEL); - if (!copy) - return -ENOMEM; - memcpy(copy, handler, sizeof(*copy)); + handler = acpi_ec_get_query_handler(handler); pr_debug("##### Query(0x%02x) scheduled #####\n", handler->query_bit); - return acpi_os_execute((copy->func) ? + return acpi_os_execute((handler->func) ? OSL_NOTIFY_HANDLER : OSL_GPE_HANDLER, - acpi_ec_run, copy); + acpi_ec_run, handler); } } return 0;