diff options
Diffstat (limited to 'include/linux')
-rw-r--r-- | include/linux/suspend.h | 1 | ||||
-rw-r--r-- | include/linux/suspend_blocker.h | 166 | ||||
-rw-r--r-- | include/linux/suspend_ioctls.h | 4 |
3 files changed, 171 insertions, 0 deletions
diff --git a/include/linux/suspend.h b/include/linux/suspend.h index 5e781d824e6d..07023d373e4f 100644 --- a/include/linux/suspend.h +++ b/include/linux/suspend.h @@ -6,6 +6,7 @@ #include <linux/init.h> #include <linux/pm.h> #include <linux/mm.h> +#include <linux/suspend_blocker.h> #include <asm/errno.h> #if defined(CONFIG_PM_SLEEP) && defined(CONFIG_VT) && defined(CONFIG_VT_CONSOLE) diff --git a/include/linux/suspend_blocker.h b/include/linux/suspend_blocker.h new file mode 100644 index 000000000000..bb90b453afcc --- /dev/null +++ b/include/linux/suspend_blocker.h @@ -0,0 +1,166 @@ +/* include/linux/suspend_blocker.h + * + * Copyright (C) 2007-2010 Google, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef _LINUX_SUSPEND_BLOCKER_H +#define _LINUX_SUSPEND_BLOCKER_H + +#include <linux/list.h> +#include <linux/ktime.h> +#include <linux/workqueue.h> + +/** + * struct suspend_blocker_stats - statistics for a suspend blocker + * + * @count: Number of times this blocker has been deacivated. + * @wakeup_count: Number of times this blocker was the first to block suspend + * after resume. + * @total_time: Total time this suspend blocker has prevented suspend. + * @prevent_suspend_time: Time this suspend blocker has prevented suspend while + * user-space requested suspend. + * @max_time: Max time this suspend blocker has been continuously active. + * @last_time: Monotonic clock when the active state last changed. + */ +struct suspend_blocker_stats { +#ifdef CONFIG_SUSPEND_BLOCKER_STATS + unsigned int count; + unsigned int wakeup_count; + ktime_t total_time; + ktime_t prevent_suspend_time; + ktime_t max_time; + ktime_t last_time; +#endif +}; + +/** + * struct suspend_blocker - the basic suspend_blocker structure + * @link: List entry for active or inactive list. + * @flags: Tracks initialized and active state and statistics. + * @name: Suspend blocker name used for debugging. + * + * When a suspend_blocker is active it prevents the system from entering + * opportunistic suspend. + * + * The suspend_blocker structure must be initialized by suspend_blocker_init() + */ +struct suspend_blocker { +#ifdef CONFIG_OPPORTUNISTIC_SUSPEND + struct list_head link; + int flags; + const char *name; + struct suspend_blocker_stats stat; +#endif +}; + +/** + * struct suspend_blocking_work - the basic suspend_blocking_work structure + * @work: Standard work struct. + * @suspend_blocker: Suspend blocker. + * @func: Callback. + * @lock: Spinlock protecting pending and running state. + * @active: Number of cpu workqueues where work is pending or + * callback is running. + * + * When suspend blocking work is pending or its callback is running it prevents + * the system from entering opportunistic suspend. + * + * The suspend_blocking_work structure must be initialized by + * suspend_blocking_work_init(). + */ + +struct suspend_blocking_work { + struct work_struct work; +#ifdef CONFIG_OPPORTUNISTIC_SUSPEND + struct suspend_blocker suspend_blocker; + work_func_t func; + spinlock_t lock; + int active; +#endif +}; + +static inline struct suspend_blocking_work *to_suspend_blocking_work( + struct work_struct *work) +{ + return container_of(work, struct suspend_blocking_work, work); +} + +#ifdef CONFIG_OPPORTUNISTIC_SUSPEND +#define __SUSPEND_BLOCKER_INITIALIZER(blocker_name) \ + { .name = #blocker_name, } + +#define DEFINE_SUSPEND_BLOCKER(blocker, name) \ + struct suspend_blocker blocker = __SUSPEND_BLOCKER_INITIALIZER(name) + +extern void suspend_blocker_register(struct suspend_blocker *blocker); +extern void suspend_blocker_init(struct suspend_blocker *blocker, + const char *name); +extern void suspend_blocker_unregister(struct suspend_blocker *blocker); +extern void suspend_block(struct suspend_blocker *blocker); +extern void suspend_unblock(struct suspend_blocker *blocker); +extern bool suspend_blocker_is_active(struct suspend_blocker *blocker); +extern bool suspend_is_blocked(void); + +void suspend_blocking_work_init(struct suspend_blocking_work *work, + work_func_t func, const char *name); +void suspend_blocking_work_destroy(struct suspend_blocking_work *work); +int queue_suspend_blocking_work(struct workqueue_struct *wq, + struct suspend_blocking_work *work); +int schedule_suspend_blocking_work(struct suspend_blocking_work *work); +int cancel_suspend_blocking_work_sync(struct suspend_blocking_work *work); + +#else + +#define DEFINE_SUSPEND_BLOCKER(blocker, name) \ + struct suspend_blocker blocker + +static inline void suspend_blocker_register(struct suspend_blocker *bl) {} +static inline void suspend_blocker_init(struct suspend_blocker *bl, + const char *n) {} +static inline void suspend_blocker_unregister(struct suspend_blocker *bl) {} +static inline void suspend_block(struct suspend_blocker *bl) {} +static inline void suspend_unblock(struct suspend_blocker *bl) {} +static inline bool suspend_blocker_is_active(struct suspend_blocker *bl) +{ + return false; +} +static inline bool suspend_is_blocked(void) { return false; } + +static inline void suspend_blocking_work_init( + struct suspend_blocking_work *work, work_func_t func, const char *name) +{ + INIT_WORK(&work->work, func); +} +static inline void suspend_blocking_work_destroy( + struct suspend_blocking_work *work) +{ + cancel_work_sync(&work->work); +} +static inline int queue_suspend_blocking_work( + struct workqueue_struct *wq, struct suspend_blocking_work *work) +{ + return queue_work(wq, &work->work); +} +static inline int schedule_suspend_blocking_work( + struct suspend_blocking_work *work) +{ + return schedule_work(&work->work); +} +static inline int cancel_suspend_blocking_work_sync( + struct suspend_blocking_work *work) +{ + return cancel_work_sync(&work->work); +} +#endif + +#endif diff --git a/include/linux/suspend_ioctls.h b/include/linux/suspend_ioctls.h index 0b30382984fe..b95a6b2bd973 100644 --- a/include/linux/suspend_ioctls.h +++ b/include/linux/suspend_ioctls.h @@ -30,4 +30,8 @@ struct resume_swap_area { #define SNAPSHOT_ALLOC_SWAP_PAGE _IOR(SNAPSHOT_IOC_MAGIC, 20, __kernel_loff_t) #define SNAPSHOT_IOC_MAXNR 20 +#define SUSPEND_BLOCKER_IOCTL_SET_NAME(len) _IOC(_IOC_WRITE, 's', 0, len) +#define SUSPEND_BLOCKER_IOCTL_BLOCK _IO('s', 1) +#define SUSPEND_BLOCKER_IOCTL_UNBLOCK _IO('s', 2) + #endif /* _LINUX_SUSPEND_IOCTLS_H */ |