[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <2925475.Mzl99EToV0@vostro.rjw.lan>
Date: Wed, 20 May 2015 01:01:33 +0200
From: "Rafael J. Wysocki" <rjw@...ysocki.net>
To: Tony Lindgren <tony@...mide.com>
Cc: Felipe Balbi <balbi@...com>,
"Rafael J. Wysocki" <rafael.j.wysocki@...el.com>,
Alan Stern <stern@...land.harvard.edu>,
Andreas Fenkart <afenkart@...il.com>,
Greg Kroah-Hartman <gregkh@...uxfoundation.org>,
Huiquan Zhong <huiquan.zhong@...el.com>,
Kevin Hilman <khilman@...nel.org>, NeilBrown <neilb@...e.de>,
Mika Westerberg <mika.westerberg@...ux.intel.com>,
Nishanth Menon <nm@...com>,
Peter Hurley <peter@...leysoftware.com>,
Sebastian Andrzej Siewior <bigeasy@...utronix.de>,
Ulf Hansson <ulf.hansson@...aro.org>,
Thomas Gleixner <tglx@...utronix.de>, linux-pm@...r.kernel.org,
linux-kernel@...r.kernel.org, linux-serial@...r.kernel.org,
linux-omap@...r.kernel.org
Subject: Re: [PATCH 2/5] PM / Wakeirq: Add automated device wake IRQ handling
On Tuesday, May 19, 2015 11:18:42 AM Tony Lindgren wrote:
> * Tony Lindgren <tony@...mide.com> [150519 08:21]:
> > * Rafael J. Wysocki <rjw@...ysocki.net> [150519 07:02]:
> > > On Tuesday, May 19, 2015 04:04:43 PM Rafael J. Wysocki wrote:
> > > > On Monday, May 18, 2015 04:44:01 PM Tony Lindgren wrote:
> > > > >
> > > > > We can replace it with just the following init and exit
> > > > > time code:
> > > > >
> > > > > ...
> > > > > device_init_wakeup(dev, true);
> > > > > dev_pm_set_wake_irq(dev, irq);
> > > > > ...
> > > > > dev_pm_clear_wake_irq(dev);
> > > > > device_init_wakeup(dev, false);
> > > > > ...
> > > > >
> > > > > And for hardware with dedicated wake-up interrupts:
> > > > >
> > > > > ...
> > > > > device_init_wakeup(dev, true);
> > > > > dev_pm_set_dedicated_wake_irq(dev, irq);
> > > > > ...
> > > > > dev_pm_clear_wake_irq(dev);
> > > > > device_init_wakeup(dev, false);
> > > > > ...
> > > > >
> > > > > For now, let's only enable it for select PM_WAKEIRQ.
> > > >
> > > > Why? What would be wrong with doing that unconditionally?
> >
> > No reason to make it conditional any longer. it's there from
> > the earlier version that only handled the dedicated wake IRQS.
> >
> > > I mean, what about making it depend on CONFIG_PM directly?
> >
> > OK let's do that.
>
> Here's the patch updated and now using just CONFIG_PM.
This one looks really good. :-)
If it doesn't depend on anything, I can apply it right away, so please let me
know.
> 8< ---------------------------
> From: Tony Lindgren <tony@...mide.com>
> Date: Mon, 18 May 2015 15:40:29 -0700
> Subject: [PATCH] PM / Wakeirq: Add automated device wake IRQ handling
>
> Turns out we can automate the handling for the device_may_wakeup()
> quite a bit by using the kernel wakeup source list as suggested
> by Rafael J. Wysocki <rjw@...ysocki.net>.
>
> And as some hardware has separate dedicated wake-up interrupt
> in addition to the IO interrupt, we can automate the handling by
> adding a generic threaded interrupt handler that just calls the
> device PM runtime to wake up the device.
>
> This allows dropping code from device drivers as we currently
> are doing it in multiple ways, and often wrong.
>
> For most drivers, we should be able to drop the following
> boilerplate code from runtime_suspend and runtime_resume
> functions:
>
> ...
> device_init_wakeup(dev, true);
> ...
> if (device_may_wakeup(dev))
> enable_irq_wake(irq);
> ...
> if (device_may_wakeup(dev))
> disable_irq_wake(irq);
> ...
> device_init_wakeup(dev, false);
> ...
>
> We can replace it with just the following init and exit
> time code:
>
> ...
> device_init_wakeup(dev, true);
> dev_pm_set_wake_irq(dev, irq);
> ...
> dev_pm_clear_wake_irq(dev);
> device_init_wakeup(dev, false);
> ...
>
> And for hardware with dedicated wake-up interrupts:
>
> ...
> device_init_wakeup(dev, true);
> dev_pm_set_dedicated_wake_irq(dev, irq);
> ...
> dev_pm_clear_wake_irq(dev);
> device_init_wakeup(dev, false);
> ...
>
> Signed-off-by: Tony Lindgren <tony@...mide.com>
>
> diff --git a/drivers/base/power/Makefile b/drivers/base/power/Makefile
> index 1cb8544..f94a6cc 100644
> --- a/drivers/base/power/Makefile
> +++ b/drivers/base/power/Makefile
> @@ -1,4 +1,4 @@
> -obj-$(CONFIG_PM) += sysfs.o generic_ops.o common.o qos.o runtime.o
> +obj-$(CONFIG_PM) += sysfs.o generic_ops.o common.o qos.o runtime.o wakeirq.o
> obj-$(CONFIG_PM_SLEEP) += main.o wakeup.o
> obj-$(CONFIG_PM_TRACE_RTC) += trace.o
> obj-$(CONFIG_PM_OPP) += opp.o
> diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c
> index 3d874ec..6f2515c 100644
> --- a/drivers/base/power/main.c
> +++ b/drivers/base/power/main.c
> @@ -24,6 +24,7 @@
> #include <linux/pm.h>
> #include <linux/pm_runtime.h>
> #include <linux/pm-trace.h>
> +#include <linux/pm_wakeirq.h>
> #include <linux/interrupt.h>
> #include <linux/sched.h>
> #include <linux/async.h>
> @@ -587,6 +588,7 @@ void dpm_resume_noirq(pm_message_t state)
> async_synchronize_full();
> dpm_show_time(starttime, state, "noirq");
> resume_device_irqs();
> + device_wakeup_disarm_wake_irqs();
> cpuidle_resume();
> trace_suspend_resume(TPS("dpm_resume_noirq"), state.event, false);
> }
> @@ -1104,6 +1106,7 @@ int dpm_suspend_noirq(pm_message_t state)
>
> trace_suspend_resume(TPS("dpm_suspend_noirq"), state.event, true);
> cpuidle_pause();
> + device_wakeup_arm_wake_irqs();
> suspend_device_irqs();
> mutex_lock(&dpm_list_mtx);
> pm_transition = state;
> diff --git a/drivers/base/power/power.h b/drivers/base/power/power.h
> index b6b8a27..f1a5d95 100644
> --- a/drivers/base/power/power.h
> +++ b/drivers/base/power/power.h
> @@ -20,6 +20,46 @@ static inline void pm_runtime_early_init(struct device *dev)
> extern void pm_runtime_init(struct device *dev);
> extern void pm_runtime_remove(struct device *dev);
>
> +struct wake_irq {
> + struct device *dev;
> + int irq;
> + bool dedicated_irq:1;
> +};
> +
> +extern void dev_pm_arm_wake_irq(struct wake_irq *wirq);
> +extern void dev_pm_disarm_wake_irq(struct wake_irq *wirq);
> +
> +#ifdef CONFIG_PM_SLEEP
> +
> +extern int device_wakeup_attach_irq(struct device *dev,
> + struct wake_irq *wakeirq);
> +extern void device_wakeup_detach_irq(struct device *dev);
> +extern void device_wakeup_arm_wake_irqs(void);
> +extern void device_wakeup_disarm_wake_irqs(void);
> +
> +#else
> +
> +static inline int
> +device_wakeup_attach_irq(struct device *dev,
> + struct wake_irq *wakeirq)
> +{
> + return 0;
> +}
> +
> +static inline void device_wakeup_detach_irq(struct device *dev)
> +{
> +}
> +
> +static inline void device_wakeup_arm_wake_irqs(void)
> +{
> +}
> +
> +static inline void device_wakeup_disarm_wake_irqs(void)
> +{
> +}
> +
> +#endif /* CONFIG_PM_SLEEP */
> +
> /*
> * sysfs.c
> */
> @@ -52,6 +92,14 @@ static inline void wakeup_sysfs_remove(struct device *dev) {}
> static inline int pm_qos_sysfs_add(struct device *dev) { return 0; }
> static inline void pm_qos_sysfs_remove(struct device *dev) {}
>
> +static inline void dev_pm_arm_wake_irq(struct wake_irq *wirq)
> +{
> +}
> +
> +static inline void dev_pm_disarm_wake_irq(struct wake_irq *wirq)
> +{
> +}
> +
> #endif
>
> #ifdef CONFIG_PM_SLEEP
> diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c
> index 4ffe4a2..e1a10a0 100644
> --- a/drivers/base/power/runtime.c
> +++ b/drivers/base/power/runtime.c
> @@ -10,6 +10,7 @@
> #include <linux/sched.h>
> #include <linux/export.h>
> #include <linux/pm_runtime.h>
> +#include <linux/pm_wakeirq.h>
> #include <trace/events/rpm.h>
> #include "power.h"
>
> @@ -514,6 +515,7 @@ static int rpm_suspend(struct device *dev, int rpmflags)
>
> callback = RPM_GET_CALLBACK(dev, runtime_suspend);
>
> + dev_pm_enable_wake_irq(dev);
> retval = rpm_callback(callback, dev);
> if (retval)
> goto fail;
> @@ -552,6 +554,7 @@ static int rpm_suspend(struct device *dev, int rpmflags)
> return retval;
>
> fail:
> + dev_pm_disable_wake_irq(dev);
> __update_runtime_status(dev, RPM_ACTIVE);
> dev->power.deferred_resume = false;
> wake_up_all(&dev->power.wait_queue);
> @@ -734,10 +737,12 @@ static int rpm_resume(struct device *dev, int rpmflags)
>
> callback = RPM_GET_CALLBACK(dev, runtime_resume);
>
> + dev_pm_disable_wake_irq(dev);
> retval = rpm_callback(callback, dev);
> if (retval) {
> __update_runtime_status(dev, RPM_SUSPENDED);
> pm_runtime_cancel_pending(dev);
> + dev_pm_enable_wake_irq(dev);
> } else {
> no_callback:
> __update_runtime_status(dev, RPM_ACTIVE);
> diff --git a/drivers/base/power/wakeirq.c b/drivers/base/power/wakeirq.c
> new file mode 100644
> index 0000000..7470004
> --- /dev/null
> +++ b/drivers/base/power/wakeirq.c
> @@ -0,0 +1,273 @@
> +/*
> + * wakeirq.c - Device wakeirq helper functions
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + * This program is distributed "as is" WITHOUT ANY WARRANTY of any
> + * kind, whether express or implied; without even the implied warranty
> + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + */
> +
> +#include <linux/device.h>
> +#include <linux/interrupt.h>
> +#include <linux/irq.h>
> +#include <linux/slab.h>
> +#include <linux/pm_runtime.h>
> +#include <linux/pm_wakeirq.h>
> +
> +#include "power.h"
> +
> +/**
> + * dev_pm_attach_wake_irq - Attach device interrupt as a wake IRQ
> + * @dev: Device entry
> + * @irq: Device wake-up capable interrupt
> + * @wirq: Wake irq specific data
> + *
> + * Internal function to attach either a device IO interrupt or a
> + * dedicated wake-up interrupt as a wake IRQ.
> + */
> +static int dev_pm_attach_wake_irq(struct device *dev, int irq,
> + struct wake_irq *wirq)
> +{
> + unsigned long flags;
> + int err;
> +
> + if (!dev || !wirq)
> + return -EINVAL;
> +
> + spin_lock_irqsave(&dev->power.lock, flags);
> + if (dev_WARN_ONCE(dev, dev->power.wakeirq,
> + "wake irq already initialized\n")) {
> + spin_unlock_irqrestore(&dev->power.lock, flags);
> + return -EEXIST;
> + }
> +
> + dev->power.wakeirq = wirq;
> + spin_unlock_irqrestore(&dev->power.lock, flags);
> +
> + err = device_wakeup_attach_irq(dev, wirq);
> + if (err)
> + return err;
> +
> + return 0;
> +}
> +
> +/**
> + * dev_pm_set_wake_irq - Attach device IO interrupt as wake IRQ
> + * @dev: Device entry
> + * @irq: Device IO interrupt
> + *
> + * Attach a device IO interrupt as a wake IRQ. The wake IRQ gets
> + * automatically configured for wake-up from suspend based
> + * on the device specific sysfs wakeup entry. Typically called
> + * during driver probe after calling device_init_wakeup().
> + */
> +int dev_pm_set_wake_irq(struct device *dev, int irq)
> +{
> + struct wake_irq *wirq;
> + int err;
> +
> + wirq = kzalloc(sizeof(*wirq), GFP_KERNEL);
> + if (!wirq)
> + return -ENOMEM;
> +
> + wirq->dev = dev;
> + wirq->irq = irq;
> +
> + err = dev_pm_attach_wake_irq(dev, irq, wirq);
> + if (err)
> + kfree(wirq);
> +
> + return err;
> +}
> +EXPORT_SYMBOL_GPL(dev_pm_set_wake_irq);
> +
> +/**
> + * dev_pm_clear_wake_irq - Detach a device IO interrupt wake IRQ
> + * @dev: Device entry
> + *
> + * Detach a device wake IRQ and free resources.
> + *
> + * Note that it's OK for drivers to call this without calling
> + * dev_pm_set_wake_irq() as all the driver instances may not have
> + * a wake IRQ configured. This avoid adding wake IRQ specific
> + * checks into the drivers.
> + */
> +void dev_pm_clear_wake_irq(struct device *dev)
> +{
> + struct wake_irq *wirq = dev->power.wakeirq;
> + unsigned long flags;
> +
> + if (!wirq)
> + return;
> +
> + spin_lock_irqsave(&dev->power.lock, flags);
> + dev->power.wakeirq = NULL;
> + spin_unlock_irqrestore(&dev->power.lock, flags);
> +
> + device_wakeup_detach_irq(dev);
> + if (wirq->dedicated_irq)
> + free_irq(wirq->irq, wirq);
> + kfree(wirq);
> +}
> +EXPORT_SYMBOL_GPL(dev_pm_clear_wake_irq);
> +
> +/**
> + * handle_threaded_wake_irq - Handler for dedicated wake-up interrupts
> + * @irq: Device specific dedicated wake-up interrupt
> + * @_wirq: Wake IRQ data
> + *
> + * Some devices have a separate wake-up interrupt in addition to the
> + * device IO interrupt. The wake-up interrupt signals that a device
> + * should be woken up from it's idle state. This handler uses device
> + * specific pm_runtime functions to wake the device, and then it's
> + * up to the device to do whatever it needs to. Note that as the
> + * device may need to restore context and start up regulators, we
> + * use a threaded IRQ.
> + *
> + * Also note that we are not resending the lost device interrupts.
> + * We assume that the wake-up interrupt just needs to wake-up the
> + * device, and then device's pm_runtime_resume() can deal with the
> + * situation.
> + */
> +static irqreturn_t handle_threaded_wake_irq(int irq, void *_wirq)
> +{
> + struct wake_irq *wirq = _wirq;
> + int res;
> +
> + /* We don't want RPM_ASYNC or RPM_NOWAIT here */
> + res = pm_runtime_resume(wirq->dev);
> + if (res < 0)
> + dev_warn(wirq->dev,
> + "wake IRQ with no resume: %i\n", res);
> +
> + return IRQ_HANDLED;
> +}
> +
> +/**
> + * dev_pm_set_dedicated_wake_irq - Request a dedicated wake-up interrupt
> + * @dev: Device entry
> + * @irq: Device wake-up interrupt
> + *
> + * Unless your hardware has separate wake-up interrupts in addition
> + * to the device IO interrupts, you don't need this.
> + *
> + * Sets up a threaded interrupt handler for a device that has
> + * a dedicated wake-up interrupt in addition to the device IO
> + * interrupt.
> + *
> + * The interrupt starts disabled, and needs to be managed for
> + * the device by the bus code or the device driver using
> + * dev_pm_enable_wake_irq() and dev_pm_disable_wake_irq()
> + * functions.
> + */
> +int dev_pm_set_dedicated_wake_irq(struct device *dev, int irq)
> +{
> + struct wake_irq *wirq;
> + int err;
> +
> + wirq = kzalloc(sizeof(*wirq), GFP_KERNEL);
> + if (!wirq)
> + return -ENOMEM;
> +
> + wirq->dev = dev;
> + wirq->irq = irq;
> + wirq->dedicated_irq = true;
> + irq_set_status_flags(irq, IRQ_NOAUTOEN);
> +
> + /*
> + * Consumer device may need to power up and restore state
> + * so we use a threaded irq.
> + */
> + err = request_threaded_irq(irq, NULL, handle_threaded_wake_irq,
> + IRQF_ONESHOT, dev_name(dev), wirq);
> + if (err)
> + goto err_free;
> +
> + err = dev_pm_attach_wake_irq(dev, irq, wirq);
> + if (err)
> + goto err_free_irq;
> +
> + return err;
> +
> +err_free_irq:
> + free_irq(irq, wirq);
> +err_free:
> + kfree(wirq);
> +
> + return err;
> +}
> +EXPORT_SYMBOL_GPL(dev_pm_set_dedicated_wake_irq);
> +
> +/**
> + * dev_pm_enable_wake_irq - Enable device wake-up interrupt
> + * @dev: Device
> + *
> + * Called from the bus code or the device driver for
> + * runtime_suspend() to enable the wake-up interrupt while
> + * the device is running.
> + *
> + * Note that for runtime_suspend()) the wake-up interrupts
> + * should be unconditionally enabled unlike for suspend()
> + * that is conditional.
> + */
> +void dev_pm_enable_wake_irq(struct device *dev)
> +{
> + struct wake_irq *wirq = dev->power.wakeirq;
> +
> + if (wirq && wirq->dedicated_irq)
> + enable_irq(wirq->irq);
> +}
> +EXPORT_SYMBOL_GPL(dev_pm_enable_wake_irq);
> +
> +/**
> + * dev_pm_disable_wake_irq - Disable device wake-up interrupt
> + * @dev: Device
> + *
> + * Called from the bus code or the device driver for
> + * runtime_resume() to disable the wake-up interrupt while
> + * the device is running.
> + */
> +void dev_pm_disable_wake_irq(struct device *dev)
> +{
> + struct wake_irq *wirq = dev->power.wakeirq;
> +
> + if (wirq && wirq->dedicated_irq)
> + disable_irq_nosync(wirq->irq);
> +}
> +EXPORT_SYMBOL_GPL(dev_pm_disable_wake_irq);
> +
> +/**
> + * dev_pm_arm_wake_irq - Arm device wake-up
> + * @wirq: Device wake-up interrupt
> + *
> + * Sets up the wake-up event conditionally based on the
> + * device_may_wake().
> + */
> +void dev_pm_arm_wake_irq(struct wake_irq *wirq)
> +{
> + if (!wirq)
> + return;
> +
> + if (device_may_wakeup(wirq->dev))
> + enable_irq_wake(wirq->irq);
> +}
> +
> +/**
> + * dev_pm_disarm_wake_irq - Disarm device wake-up
> + * @wirq: Device wake-up interrupt
> + *
> + * Clears up the wake-up event conditionally based on the
> + * device_may_wake().
> + */
> +void dev_pm_disarm_wake_irq(struct wake_irq *wirq)
> +{
> + if (!wirq)
> + return;
> +
> + if (device_may_wakeup(wirq->dev))
> + disable_irq_wake(wirq->irq);
> +}
> diff --git a/drivers/base/power/wakeup.c b/drivers/base/power/wakeup.c
> index 7726200..7332ebc 100644
> --- a/drivers/base/power/wakeup.c
> +++ b/drivers/base/power/wakeup.c
> @@ -14,6 +14,7 @@
> #include <linux/suspend.h>
> #include <linux/seq_file.h>
> #include <linux/debugfs.h>
> +#include <linux/pm_wakeirq.h>
> #include <trace/events/power.h>
>
> #include "power.h"
> @@ -239,6 +240,97 @@ int device_wakeup_enable(struct device *dev)
> EXPORT_SYMBOL_GPL(device_wakeup_enable);
>
> /**
> + * device_wakeup_attach_irq - Attach a wakeirq to a wakeup source
> + * @dev: Device to handle
> + * @wakeirq: Device specific wakeirq entry
> + *
> + * Attach a device wakeirq to the wakeup source so the device
> + * wake IRQ can be configured automatically for suspend and
> + * resume.
> + */
> +int device_wakeup_attach_irq(struct device *dev,
> + struct wake_irq *wakeirq)
> +{
> + struct wakeup_source *ws;
> + int ret = 0;
> +
> + spin_lock_irq(&dev->power.lock);
> + ws = dev->power.wakeup;
> + if (!ws) {
> + dev_err(dev, "forgot to call call device_init_wakeup?\n");
> + ret = -EINVAL;
> + goto unlock;
> + }
> +
> + if (ws->wakeirq) {
> + ret = -EEXIST;
> + goto unlock;
> + }
> +
> + ws->wakeirq = wakeirq;
> +
> +unlock:
> + spin_unlock_irq(&dev->power.lock);
> +
> + return ret;
> +}
> +
> +/**
> + * device_wakeup_detach_irq - Detach a wakeirq from a wakeup source
> + * @dev: Device to handle
> + *
> + * Removes a device wakeirq from the wakeup source.
> + */
> +void device_wakeup_detach_irq(struct device *dev)
> +{
> + struct wakeup_source *ws;
> +
> + spin_lock_irq(&dev->power.lock);
> + ws = dev->power.wakeup;
> + if (!ws)
> + goto unlock;
> +
> + ws->wakeirq = NULL;
> +
> +unlock:
> + spin_unlock_irq(&dev->power.lock);
> +}
> +
> +/**
> + * device_wakeup_arm_wake_irqs(void)
> + *
> + * Itereates over the list of device wakeirqs to arm them.
> + */
> +void device_wakeup_arm_wake_irqs(void)
> +{
> + struct wakeup_source *ws;
> +
> + rcu_read_lock();
> + list_for_each_entry_rcu(ws, &wakeup_sources, entry) {
> + if (ws->wakeirq)
> + dev_pm_arm_wake_irq(ws->wakeirq);
> + }
> + rcu_read_unlock();
> +}
> +
> +/**
> + * device_wakeup_disarm_wake_irqs(void)
> + *
> + * Itereates over the list of device wakeirqs to disarm them.
> + */
> +void device_wakeup_disarm_wake_irqs(void)
> +{
> + struct wakeup_source *ws;
> +
> + rcu_read_lock();
> + list_for_each_entry_rcu(ws, &wakeup_sources, entry) {
> + if (ws->wakeirq)
> + dev_pm_disarm_wake_irq(ws->wakeirq);
> + }
> + rcu_read_unlock();
> +}
> +
> +/**
> * device_wakeup_detach - Detach a device's wakeup source object from it.
> * @dev: Device to detach the wakeup source object from.
> *
> diff --git a/include/linux/pm.h b/include/linux/pm.h
> index 2d29c64..1c4ed0c 100644
> --- a/include/linux/pm.h
> +++ b/include/linux/pm.h
> @@ -529,6 +529,7 @@ enum rpm_request {
> };
>
> struct wakeup_source;
> +struct wake_irq;
> struct pm_domain_data;
>
> struct pm_subsys_data {
> @@ -568,6 +569,7 @@ struct dev_pm_info {
> unsigned long timer_expires;
> struct work_struct work;
> wait_queue_head_t wait_queue;
> + struct wake_irq *wakeirq;
> atomic_t usage_count;
> atomic_t child_count;
> unsigned int disable_depth:3;
> diff --git a/include/linux/pm_wakeirq.h b/include/linux/pm_wakeirq.h
> new file mode 100644
> index 0000000..4046fa1
> --- /dev/null
> +++ b/include/linux/pm_wakeirq.h
> @@ -0,0 +1,52 @@
> +/*
> + * pm_wakeirq.h - Device wakeirq helper functions
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + * This program is distributed "as is" WITHOUT ANY WARRANTY of any
> + * kind, whether express or implied; without even the implied warranty
> + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + */
> +
> +#ifndef _LINUX_PM_WAKEIRQ_H
> +#define _LINUX_PM_WAKEIRQ_H
> +
> +#ifdef CONFIG_PM
> +
> +extern int dev_pm_set_wake_irq(struct device *dev, int irq);
> +extern int dev_pm_set_dedicated_wake_irq(struct device *dev,
> + int irq);
> +extern void dev_pm_clear_wake_irq(struct device *dev);
> +extern void dev_pm_enable_wake_irq(struct device *dev);
> +extern void dev_pm_disable_wake_irq(struct device *dev);
> +
> +#else /* !CONFIG_PM */
> +
> +static inline int dev_pm_set_wake_irq(struct device *dev, int irq)
> +{
> + return 0;
> +}
> +
> +static inline int dev_pm_set_dedicated__wake_irq(struct device *dev,
> + int irq)
> +{
> + return 0;
> +}
> +
> +static inline void dev_pm_clear_wake_irq(struct device *dev)
> +{
> +}
> +
> +static inline void dev_pm_enable_wake_irq(struct device *dev)
> +{
> +}
> +
> +static inline void dev_pm_disable_wake_irq(struct device *dev)
> +{
> +}
> +
> +#endif /* CONFIG_PM */
> +#endif /* _LINUX_PM_WAKEIRQ_H */
> diff --git a/include/linux/pm_wakeup.h b/include/linux/pm_wakeup.h
> index a0f7080..a344793 100644
> --- a/include/linux/pm_wakeup.h
> +++ b/include/linux/pm_wakeup.h
> @@ -28,9 +28,17 @@
>
> #include <linux/types.h>
>
> +struct wake_irq;
> +
> /**
> * struct wakeup_source - Representation of wakeup sources
> *
> + * @name: Name of the wakeup source
> + * @entry: Wakeup source list entry
> + * @lock: Wakeup source lock
> + * @wakeirq: Optional device specific wakeirq
> + * @timer: Wakeup timer list
> + * @timer_expires: Wakeup timer expiration
> * @total_time: Total time this wakeup source has been active.
> * @max_time: Maximum time this wakeup source has been continuously active.
> * @last_time: Monotonic clock when the wakeup source's was touched last time.
> @@ -47,6 +55,7 @@ struct wakeup_source {
> const char *name;
> struct list_head entry;
> spinlock_t lock;
> + struct wake_irq *wakeirq;
> struct timer_list timer;
> unsigned long timer_expires;
> ktime_t total_time;
--
I speak only for myself.
Rafael J. Wysocki, Intel Open Source Technology Center.
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
Powered by blists - more mailing lists