Re: [PATCH V2 2/4] introduce the device async action mechanism

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Friday 24 July 2009, Zhang Rui wrote:
> Introduce Device Async Action Mechanism
> 
> In order to speed up Linux suspend/resume/shutdown process,
> we introduce the device async action mechanism that allow devices
> to suspend/resume/shutdown asynchronously.
> 
> The basic idea is that,
> if the suspend/resume/shutdown process of a device group,
> including a root device and its child devices, are independent of
> other devices, we create an async domain for this device group,
> and make them suspend/resume/shutdown asynchronously.    
> 
> Note that DEV_ASYNC_RESUME is different from DEV_ASYNC_SUSPEND and
> DEV_ASYNC_SHUTDOWN.
> In resume case, all the parents are resumed first.
> deferred resuming of the child devices won't break anything.
> So it's easy to find out a device group that supports DEV_ASYNC_RESUME.
> 
> In suspend/shutdown case, child devices should be suspended/shutdown
> before the parents. But deferred suspend/shutdown may break this rule.
> so for a device groups that supports DEV_ASYNC_SUSPEND&DEV_ASYNC_SHUTDOWN,
> the root device of this device async group must NOT depend on its parents.
> i.e. it's fully functional without its parents.
> e.g. I create a device async group for i8042 controller in patch 4,
> and the parent of i8042 controller device is the "platform" device under
> sysfs root device.

For general comments, please refer to my reply to the [0/4] message.  Some
coding-related remarks are below.

> Signed-off-by: Zhang Rui <rui.zhang@xxxxxxxxx>
> ---
>  drivers/base/Makefile     |    3 
>  drivers/base/async_dev.c  |  199 ++++++++++++++++++++++++++++++++++++++++++++++
>  drivers/base/core.c       |   35 ++++++--
>  drivers/base/power/main.c |   24 +++++
>  include/linux/async_dev.h |   47 ++++++++++
>  include/linux/device.h    |    2 
>  6 files changed, 298 insertions(+), 12 deletions(-)
> 
> Index: linux-2.6/drivers/base/Makefile
> ===================================================================
> --- linux-2.6.orig/drivers/base/Makefile
> +++ linux-2.6/drivers/base/Makefile
> @@ -3,7 +3,8 @@
>  obj-y			:= core.o sys.o bus.o dd.o \
>  			   driver.o class.o platform.o \
>  			   cpu.o firmware.o init.o map.o devres.o \
> -			   attribute_container.o transport_class.o
> +			   attribute_container.o transport_class.o \
> +			   async_dev.o
>  obj-y			+= power/
>  obj-$(CONFIG_HAS_DMA)	+= dma-mapping.o
>  obj-$(CONFIG_ISA)	+= isa.o
> Index: linux-2.6/drivers/base/async_dev.c
> ===================================================================
> --- /dev/null
> +++ linux-2.6/drivers/base/async_dev.c
> @@ -0,0 +1,199 @@
> +/*
> + * async_dev.c: Device asynchronous functions
> + *
> + * (C) Copyright 2009 Intel Corporation
> + * Author: Zhang Rui <rui.zhang@xxxxxxxxx>
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License
> + * as published by the Free Software Foundation; version 2
> + * of the License.
> + */
> +
> +#include <linux/device.h>
> +#include <linux/async.h>
> +#include <linux/async_dev.h>
> +
> +static LIST_HEAD(dev_async_list);
> +static int dev_async_enabled;
> +
> +struct dev_async_context {
> +	struct device *dev;
> +	void *data;
> +	void *func;
> +};

Please, _please_ don't use (void * ) for passing function pointers.  IMO doing
that is fundamentally wrong.

> +static int dev_action(struct device *dev, dev_async_func func,
> +			void *data)
> +{
> +	int error = 0;
> +
> +	if (!func || !dev)
> +		return -EINVAL;
> +
> +	error = func(dev, data);
> +
> +	return error;
> +}

Hmm, what about:

+		return func && dev ? func(dev, data) : -EINVAL;

That gives you a one-liner, doesn't it?

> +static void dev_async_action(void *data, async_cookie_t cookie)
> +{
> +	int error;
> +	struct dev_async_context *context = data;
> +
> +	context->dev->dev_async->cookie = cookie;
> +	async_synchronize_cookie_domain(cookie,
> +					 &context->dev->dev_async->domain);
> +
> +	error =	dev_action(context->dev, context->func, context->data);
> +	if (error)
> +		printk(KERN_ERR "PM: Device %s async action failed: error %d\n",
> +			dev_name(context->dev), error);
> +
> +	kfree(context);
> +}
> +
> +/**
> + * dev_async_schedule - async execution of device actions.
> + * @dev: Device.
> + * @func: device callback function.
> + * @data: data.
> + * @type: the type of device async actions.
> + */
> +int dev_async_schedule(struct device *dev, dev_async_func func,
> +			void *data, int type)
> +{
> +	struct dev_async_context *context;
> +
> +	if (!func || !dev)
> +		return -EINVAL;
> +
> +	if (!(type & DEV_ASYNC_ACTIONS_ALL))
> +		return -EINVAL;
> +
> +	if (!dev_async_enabled || !dev->dev_async)
> +		return dev_action(dev, func, data);
> +
> +	/* device doesn't support the current async action */
> +	if (!(dev->dev_async->type & type))
> +		return dev_action(dev, func, data);
> +
> +	context = kzalloc(sizeof(struct dev_async_context), GFP_KERNEL);
> +	if (!data)
> +		return -ENOMEM;
> +
> +	context->dev = dev;
> +	context->data = data;
> +	context->func = func;
> +	async_schedule_domain(dev_async_action, context,
> +			       &dev->dev_async->domain);
> +	return 0;
> +}
> +
> +/**
> + * device_async_synchronization - sync point for all the async actions
> + * @dev: Device.
> + *
> + * wait until all the async actions are done.
> + */
> +void dev_async_synchronization(void)
> +{
> +	struct dev_async_struct *pos;
> +
> +	list_for_each_entry(pos, &dev_async_list, node)
> +	    async_synchronize_full_domain(&pos->domain);
> +
> +	return;

What the return statement is for?

> +}
> +
> +static int dev_match(struct device *dev, void *data)
> +{
> +	dev_err(dev->parent, "Child device %s is registered before "
> +		"dev->dev_async being initialized", dev_name(dev));
> +	return 1;
> +}
> +
> +/**
> + * device_async_register - register a device that supports async actions
> + * @dev: Device.
> + * @type: the kind of dev async actions that supported
> + *
> + * Register a device that supports a certain kind of dev async actions.
> + * Create a synchrolization Domain for this device and share with all its
> + * child devices.
> + */
> +int dev_async_register(struct device *dev, int type)
> +{
> +	if (!dev_async_enabled)
> +		return 0;
> +
> +	if (!dev)
> +		return -EINVAL;
> +
> +	if (dev->dev_async) {
> +		/* multiple async domains for a single device not supported */
> +		dev_err(dev, "async domain already registered\n");
> +		return -EEXIST;
> +	}
> +
> +	/*
> +	 * dev_async_register must be called before any of its child devices
> +	 * being registered to the driver model.
> +	 */
> +	if (dev->p)
> +		if (device_find_child(dev, NULL, dev_match)) {
> +			dev_err(dev, "Can not register device async domain\n");
> +			return -EINVAL;
> +		}
> +
> +	/* check for unsupported async actions */
> +	if (!(type & DEV_ASYNC_ACTIONS_ALL)) {
> +		dev_err(dev, "unsupported async action %x registered\n", type);
> +		return -EINVAL;
> +	}
> +
> +	dev->dev_async = kzalloc(sizeof(struct dev_async_struct), GFP_KERNEL);
> +	if (!dev->dev_async)
> +		return -ENOMEM;
> +
> +	INIT_LIST_HEAD(&dev->dev_async->domain);
> +	dev->dev_async->dev = dev;
> +	dev->dev_async->type = type;
> +	list_add_tail(&dev->dev_async->node, &dev_async_list);
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(dev_async_register);
> +
> +/**
> + * device_async_unregister - unregister a device that supports async actions
> + * @dev: Device.
> + *
> + * Unregister a device that supports async actions.
> + * And delete async action Domain at the same time.
> + */
> +void dev_async_unregister(struct device *dev)
> +{
> +	if (!dev_async_enabled)
> +		return;
> +
> +	if (!dev->dev_async)
> +		return;
> +
> +	if (dev->dev_async->dev != dev)
> +		return;
> +
> +	list_del(&dev->dev_async->node);
> +	kfree(dev->dev_async);
> +	dev->dev_async = NULL;
> +	return;

And here?

Well, it looks like my comments to the previous version of the patch were
silently ignored. :-(

Best,
Rafael
--
To unsubscribe from this list: send the line "unsubscribe linux-acpi" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux IBM ACPI]     [Linux Power Management]     [Linux Kernel]     [Linux Laptop]     [Kernel Newbies]     [Share Photos]     [Security]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Samba]     [Video 4 Linux]     [Device Mapper]     [Linux Resources]

  Powered by Linux