mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 02:30:34 +02:00 
			
		
		
		
	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 <lv.zheng@intel.com> Tested-by: Steffen Weber <steffen.weber@gmail.com> Tested-by: Ortwin Glück <odi@odi.ch> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
This commit is contained in:
		
							parent
							
								
									0c78808f51
								
							
						
					
					
						commit
						01305d4139
					
				
					 1 changed files with 33 additions and 10 deletions
				
			
		| 
						 | 
				
			
			@ -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;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue