18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * drivers/base/power/wakeup.c - System wakeup events framework
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (c) 2010 Rafael J. Wysocki <rjw@sisk.pl>, Novell Inc.
68c2ecf20Sopenharmony_ci */
78c2ecf20Sopenharmony_ci#define pr_fmt(fmt) "PM: " fmt
88c2ecf20Sopenharmony_ci
98c2ecf20Sopenharmony_ci#include <linux/device.h>
108c2ecf20Sopenharmony_ci#include <linux/slab.h>
118c2ecf20Sopenharmony_ci#include <linux/sched/signal.h>
128c2ecf20Sopenharmony_ci#include <linux/capability.h>
138c2ecf20Sopenharmony_ci#include <linux/export.h>
148c2ecf20Sopenharmony_ci#include <linux/suspend.h>
158c2ecf20Sopenharmony_ci#include <linux/seq_file.h>
168c2ecf20Sopenharmony_ci#include <linux/debugfs.h>
178c2ecf20Sopenharmony_ci#include <linux/pm_wakeirq.h>
188c2ecf20Sopenharmony_ci#include <trace/events/power.h>
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_ci#include "power.h"
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_ci#ifndef CONFIG_SUSPEND
238c2ecf20Sopenharmony_cisuspend_state_t pm_suspend_target_state;
248c2ecf20Sopenharmony_ci#define pm_suspend_target_state	(PM_SUSPEND_ON)
258c2ecf20Sopenharmony_ci#endif
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_ci#define list_for_each_entry_rcu_locked(pos, head, member) \
288c2ecf20Sopenharmony_ci	list_for_each_entry_rcu(pos, head, member, \
298c2ecf20Sopenharmony_ci		srcu_read_lock_held(&wakeup_srcu))
308c2ecf20Sopenharmony_ci/*
318c2ecf20Sopenharmony_ci * If set, the suspend/hibernate code will abort transitions to a sleep state
328c2ecf20Sopenharmony_ci * if wakeup events are registered during or immediately before the transition.
338c2ecf20Sopenharmony_ci */
348c2ecf20Sopenharmony_cibool events_check_enabled __read_mostly;
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_ci/* First wakeup IRQ seen by the kernel in the last cycle. */
378c2ecf20Sopenharmony_cistatic unsigned int wakeup_irq[2] __read_mostly;
388c2ecf20Sopenharmony_cistatic DEFINE_RAW_SPINLOCK(wakeup_irq_lock);
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_ci/* If greater than 0 and the system is suspending, terminate the suspend. */
418c2ecf20Sopenharmony_cistatic atomic_t pm_abort_suspend __read_mostly;
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_ci/*
448c2ecf20Sopenharmony_ci * Combined counters of registered wakeup events and wakeup events in progress.
458c2ecf20Sopenharmony_ci * They need to be modified together atomically, so it's better to use one
468c2ecf20Sopenharmony_ci * atomic variable to hold them both.
478c2ecf20Sopenharmony_ci */
488c2ecf20Sopenharmony_cistatic atomic_t combined_event_count = ATOMIC_INIT(0);
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_ci#define IN_PROGRESS_BITS	(sizeof(int) * 4)
518c2ecf20Sopenharmony_ci#define MAX_IN_PROGRESS		((1 << IN_PROGRESS_BITS) - 1)
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_cistatic void split_counters(unsigned int *cnt, unsigned int *inpr)
548c2ecf20Sopenharmony_ci{
558c2ecf20Sopenharmony_ci	unsigned int comb = atomic_read(&combined_event_count);
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_ci	*cnt = (comb >> IN_PROGRESS_BITS);
588c2ecf20Sopenharmony_ci	*inpr = comb & MAX_IN_PROGRESS;
598c2ecf20Sopenharmony_ci}
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_ci/* A preserved old value of the events counter. */
628c2ecf20Sopenharmony_cistatic unsigned int saved_count;
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_cistatic DEFINE_RAW_SPINLOCK(events_lock);
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_cistatic void pm_wakeup_timer_fn(struct timer_list *t);
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_cistatic LIST_HEAD(wakeup_sources);
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_cistatic DECLARE_WAIT_QUEUE_HEAD(wakeup_count_wait_queue);
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_ciDEFINE_STATIC_SRCU(wakeup_srcu);
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_cistatic struct wakeup_source deleted_ws = {
758c2ecf20Sopenharmony_ci	.name = "deleted",
768c2ecf20Sopenharmony_ci	.lock =  __SPIN_LOCK_UNLOCKED(deleted_ws.lock),
778c2ecf20Sopenharmony_ci};
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_cistatic DEFINE_IDA(wakeup_ida);
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_ci/**
828c2ecf20Sopenharmony_ci * wakeup_source_create - Create a struct wakeup_source object.
838c2ecf20Sopenharmony_ci * @name: Name of the new wakeup source.
848c2ecf20Sopenharmony_ci */
858c2ecf20Sopenharmony_cistruct wakeup_source *wakeup_source_create(const char *name)
868c2ecf20Sopenharmony_ci{
878c2ecf20Sopenharmony_ci	struct wakeup_source *ws;
888c2ecf20Sopenharmony_ci	const char *ws_name;
898c2ecf20Sopenharmony_ci	int id;
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_ci	ws = kzalloc(sizeof(*ws), GFP_KERNEL);
928c2ecf20Sopenharmony_ci	if (!ws)
938c2ecf20Sopenharmony_ci		goto err_ws;
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_ci	ws_name = kstrdup_const(name, GFP_KERNEL);
968c2ecf20Sopenharmony_ci	if (!ws_name)
978c2ecf20Sopenharmony_ci		goto err_name;
988c2ecf20Sopenharmony_ci	ws->name = ws_name;
998c2ecf20Sopenharmony_ci
1008c2ecf20Sopenharmony_ci	id = ida_alloc(&wakeup_ida, GFP_KERNEL);
1018c2ecf20Sopenharmony_ci	if (id < 0)
1028c2ecf20Sopenharmony_ci		goto err_id;
1038c2ecf20Sopenharmony_ci	ws->id = id;
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_ci	return ws;
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_cierr_id:
1088c2ecf20Sopenharmony_ci	kfree_const(ws->name);
1098c2ecf20Sopenharmony_cierr_name:
1108c2ecf20Sopenharmony_ci	kfree(ws);
1118c2ecf20Sopenharmony_cierr_ws:
1128c2ecf20Sopenharmony_ci	return NULL;
1138c2ecf20Sopenharmony_ci}
1148c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(wakeup_source_create);
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_ci/*
1178c2ecf20Sopenharmony_ci * Record wakeup_source statistics being deleted into a dummy wakeup_source.
1188c2ecf20Sopenharmony_ci */
1198c2ecf20Sopenharmony_cistatic void wakeup_source_record(struct wakeup_source *ws)
1208c2ecf20Sopenharmony_ci{
1218c2ecf20Sopenharmony_ci	unsigned long flags;
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_ci	spin_lock_irqsave(&deleted_ws.lock, flags);
1248c2ecf20Sopenharmony_ci
1258c2ecf20Sopenharmony_ci	if (ws->event_count) {
1268c2ecf20Sopenharmony_ci		deleted_ws.total_time =
1278c2ecf20Sopenharmony_ci			ktime_add(deleted_ws.total_time, ws->total_time);
1288c2ecf20Sopenharmony_ci		deleted_ws.prevent_sleep_time =
1298c2ecf20Sopenharmony_ci			ktime_add(deleted_ws.prevent_sleep_time,
1308c2ecf20Sopenharmony_ci				  ws->prevent_sleep_time);
1318c2ecf20Sopenharmony_ci		deleted_ws.max_time =
1328c2ecf20Sopenharmony_ci			ktime_compare(deleted_ws.max_time, ws->max_time) > 0 ?
1338c2ecf20Sopenharmony_ci				deleted_ws.max_time : ws->max_time;
1348c2ecf20Sopenharmony_ci		deleted_ws.event_count += ws->event_count;
1358c2ecf20Sopenharmony_ci		deleted_ws.active_count += ws->active_count;
1368c2ecf20Sopenharmony_ci		deleted_ws.relax_count += ws->relax_count;
1378c2ecf20Sopenharmony_ci		deleted_ws.expire_count += ws->expire_count;
1388c2ecf20Sopenharmony_ci		deleted_ws.wakeup_count += ws->wakeup_count;
1398c2ecf20Sopenharmony_ci	}
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&deleted_ws.lock, flags);
1428c2ecf20Sopenharmony_ci}
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_cistatic void wakeup_source_free(struct wakeup_source *ws)
1458c2ecf20Sopenharmony_ci{
1468c2ecf20Sopenharmony_ci	ida_free(&wakeup_ida, ws->id);
1478c2ecf20Sopenharmony_ci	kfree_const(ws->name);
1488c2ecf20Sopenharmony_ci	kfree(ws);
1498c2ecf20Sopenharmony_ci}
1508c2ecf20Sopenharmony_ci
1518c2ecf20Sopenharmony_ci/**
1528c2ecf20Sopenharmony_ci * wakeup_source_destroy - Destroy a struct wakeup_source object.
1538c2ecf20Sopenharmony_ci * @ws: Wakeup source to destroy.
1548c2ecf20Sopenharmony_ci *
1558c2ecf20Sopenharmony_ci * Use only for wakeup source objects created with wakeup_source_create().
1568c2ecf20Sopenharmony_ci */
1578c2ecf20Sopenharmony_civoid wakeup_source_destroy(struct wakeup_source *ws)
1588c2ecf20Sopenharmony_ci{
1598c2ecf20Sopenharmony_ci	if (!ws)
1608c2ecf20Sopenharmony_ci		return;
1618c2ecf20Sopenharmony_ci
1628c2ecf20Sopenharmony_ci	__pm_relax(ws);
1638c2ecf20Sopenharmony_ci	wakeup_source_record(ws);
1648c2ecf20Sopenharmony_ci	wakeup_source_free(ws);
1658c2ecf20Sopenharmony_ci}
1668c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(wakeup_source_destroy);
1678c2ecf20Sopenharmony_ci
1688c2ecf20Sopenharmony_ci/**
1698c2ecf20Sopenharmony_ci * wakeup_source_add - Add given object to the list of wakeup sources.
1708c2ecf20Sopenharmony_ci * @ws: Wakeup source object to add to the list.
1718c2ecf20Sopenharmony_ci */
1728c2ecf20Sopenharmony_civoid wakeup_source_add(struct wakeup_source *ws)
1738c2ecf20Sopenharmony_ci{
1748c2ecf20Sopenharmony_ci	unsigned long flags;
1758c2ecf20Sopenharmony_ci
1768c2ecf20Sopenharmony_ci	if (WARN_ON(!ws))
1778c2ecf20Sopenharmony_ci		return;
1788c2ecf20Sopenharmony_ci
1798c2ecf20Sopenharmony_ci	spin_lock_init(&ws->lock);
1808c2ecf20Sopenharmony_ci	timer_setup(&ws->timer, pm_wakeup_timer_fn, 0);
1818c2ecf20Sopenharmony_ci	ws->active = false;
1828c2ecf20Sopenharmony_ci
1838c2ecf20Sopenharmony_ci	raw_spin_lock_irqsave(&events_lock, flags);
1848c2ecf20Sopenharmony_ci	list_add_rcu(&ws->entry, &wakeup_sources);
1858c2ecf20Sopenharmony_ci	raw_spin_unlock_irqrestore(&events_lock, flags);
1868c2ecf20Sopenharmony_ci}
1878c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(wakeup_source_add);
1888c2ecf20Sopenharmony_ci
1898c2ecf20Sopenharmony_ci/**
1908c2ecf20Sopenharmony_ci * wakeup_source_remove - Remove given object from the wakeup sources list.
1918c2ecf20Sopenharmony_ci * @ws: Wakeup source object to remove from the list.
1928c2ecf20Sopenharmony_ci */
1938c2ecf20Sopenharmony_civoid wakeup_source_remove(struct wakeup_source *ws)
1948c2ecf20Sopenharmony_ci{
1958c2ecf20Sopenharmony_ci	unsigned long flags;
1968c2ecf20Sopenharmony_ci
1978c2ecf20Sopenharmony_ci	if (WARN_ON(!ws))
1988c2ecf20Sopenharmony_ci		return;
1998c2ecf20Sopenharmony_ci
2008c2ecf20Sopenharmony_ci	raw_spin_lock_irqsave(&events_lock, flags);
2018c2ecf20Sopenharmony_ci	list_del_rcu(&ws->entry);
2028c2ecf20Sopenharmony_ci	raw_spin_unlock_irqrestore(&events_lock, flags);
2038c2ecf20Sopenharmony_ci	synchronize_srcu(&wakeup_srcu);
2048c2ecf20Sopenharmony_ci
2058c2ecf20Sopenharmony_ci	del_timer_sync(&ws->timer);
2068c2ecf20Sopenharmony_ci	/*
2078c2ecf20Sopenharmony_ci	 * Clear timer.function to make wakeup_source_not_registered() treat
2088c2ecf20Sopenharmony_ci	 * this wakeup source as not registered.
2098c2ecf20Sopenharmony_ci	 */
2108c2ecf20Sopenharmony_ci	ws->timer.function = NULL;
2118c2ecf20Sopenharmony_ci}
2128c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(wakeup_source_remove);
2138c2ecf20Sopenharmony_ci
2148c2ecf20Sopenharmony_ci/**
2158c2ecf20Sopenharmony_ci * wakeup_source_register - Create wakeup source and add it to the list.
2168c2ecf20Sopenharmony_ci * @dev: Device this wakeup source is associated with (or NULL if virtual).
2178c2ecf20Sopenharmony_ci * @name: Name of the wakeup source to register.
2188c2ecf20Sopenharmony_ci */
2198c2ecf20Sopenharmony_cistruct wakeup_source *wakeup_source_register(struct device *dev,
2208c2ecf20Sopenharmony_ci					     const char *name)
2218c2ecf20Sopenharmony_ci{
2228c2ecf20Sopenharmony_ci	struct wakeup_source *ws;
2238c2ecf20Sopenharmony_ci	int ret;
2248c2ecf20Sopenharmony_ci
2258c2ecf20Sopenharmony_ci	ws = wakeup_source_create(name);
2268c2ecf20Sopenharmony_ci	if (ws) {
2278c2ecf20Sopenharmony_ci		if (!dev || device_is_registered(dev)) {
2288c2ecf20Sopenharmony_ci			ret = wakeup_source_sysfs_add(dev, ws);
2298c2ecf20Sopenharmony_ci			if (ret) {
2308c2ecf20Sopenharmony_ci				wakeup_source_free(ws);
2318c2ecf20Sopenharmony_ci				return NULL;
2328c2ecf20Sopenharmony_ci			}
2338c2ecf20Sopenharmony_ci		}
2348c2ecf20Sopenharmony_ci		wakeup_source_add(ws);
2358c2ecf20Sopenharmony_ci	}
2368c2ecf20Sopenharmony_ci	return ws;
2378c2ecf20Sopenharmony_ci}
2388c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(wakeup_source_register);
2398c2ecf20Sopenharmony_ci
2408c2ecf20Sopenharmony_ci/**
2418c2ecf20Sopenharmony_ci * wakeup_source_unregister - Remove wakeup source from the list and remove it.
2428c2ecf20Sopenharmony_ci * @ws: Wakeup source object to unregister.
2438c2ecf20Sopenharmony_ci */
2448c2ecf20Sopenharmony_civoid wakeup_source_unregister(struct wakeup_source *ws)
2458c2ecf20Sopenharmony_ci{
2468c2ecf20Sopenharmony_ci	if (ws) {
2478c2ecf20Sopenharmony_ci		wakeup_source_remove(ws);
2488c2ecf20Sopenharmony_ci		if (ws->dev)
2498c2ecf20Sopenharmony_ci			wakeup_source_sysfs_remove(ws);
2508c2ecf20Sopenharmony_ci
2518c2ecf20Sopenharmony_ci		wakeup_source_destroy(ws);
2528c2ecf20Sopenharmony_ci	}
2538c2ecf20Sopenharmony_ci}
2548c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(wakeup_source_unregister);
2558c2ecf20Sopenharmony_ci
2568c2ecf20Sopenharmony_ci/**
2578c2ecf20Sopenharmony_ci * wakeup_sources_read_lock - Lock wakeup source list for read.
2588c2ecf20Sopenharmony_ci *
2598c2ecf20Sopenharmony_ci * Returns an index of srcu lock for struct wakeup_srcu.
2608c2ecf20Sopenharmony_ci * This index must be passed to the matching wakeup_sources_read_unlock().
2618c2ecf20Sopenharmony_ci */
2628c2ecf20Sopenharmony_ciint wakeup_sources_read_lock(void)
2638c2ecf20Sopenharmony_ci{
2648c2ecf20Sopenharmony_ci	return srcu_read_lock(&wakeup_srcu);
2658c2ecf20Sopenharmony_ci}
2668c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(wakeup_sources_read_lock);
2678c2ecf20Sopenharmony_ci
2688c2ecf20Sopenharmony_ci/**
2698c2ecf20Sopenharmony_ci * wakeup_sources_read_unlock - Unlock wakeup source list.
2708c2ecf20Sopenharmony_ci * @idx: return value from corresponding wakeup_sources_read_lock()
2718c2ecf20Sopenharmony_ci */
2728c2ecf20Sopenharmony_civoid wakeup_sources_read_unlock(int idx)
2738c2ecf20Sopenharmony_ci{
2748c2ecf20Sopenharmony_ci	srcu_read_unlock(&wakeup_srcu, idx);
2758c2ecf20Sopenharmony_ci}
2768c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(wakeup_sources_read_unlock);
2778c2ecf20Sopenharmony_ci
2788c2ecf20Sopenharmony_ci/**
2798c2ecf20Sopenharmony_ci * wakeup_sources_walk_start - Begin a walk on wakeup source list
2808c2ecf20Sopenharmony_ci *
2818c2ecf20Sopenharmony_ci * Returns first object of the list of wakeup sources.
2828c2ecf20Sopenharmony_ci *
2838c2ecf20Sopenharmony_ci * Note that to be safe, wakeup sources list needs to be locked by calling
2848c2ecf20Sopenharmony_ci * wakeup_source_read_lock() for this.
2858c2ecf20Sopenharmony_ci */
2868c2ecf20Sopenharmony_cistruct wakeup_source *wakeup_sources_walk_start(void)
2878c2ecf20Sopenharmony_ci{
2888c2ecf20Sopenharmony_ci	struct list_head *ws_head = &wakeup_sources;
2898c2ecf20Sopenharmony_ci
2908c2ecf20Sopenharmony_ci	return list_entry_rcu(ws_head->next, struct wakeup_source, entry);
2918c2ecf20Sopenharmony_ci}
2928c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(wakeup_sources_walk_start);
2938c2ecf20Sopenharmony_ci
2948c2ecf20Sopenharmony_ci/**
2958c2ecf20Sopenharmony_ci * wakeup_sources_walk_next - Get next wakeup source from the list
2968c2ecf20Sopenharmony_ci * @ws: Previous wakeup source object
2978c2ecf20Sopenharmony_ci *
2988c2ecf20Sopenharmony_ci * Note that to be safe, wakeup sources list needs to be locked by calling
2998c2ecf20Sopenharmony_ci * wakeup_source_read_lock() for this.
3008c2ecf20Sopenharmony_ci */
3018c2ecf20Sopenharmony_cistruct wakeup_source *wakeup_sources_walk_next(struct wakeup_source *ws)
3028c2ecf20Sopenharmony_ci{
3038c2ecf20Sopenharmony_ci	struct list_head *ws_head = &wakeup_sources;
3048c2ecf20Sopenharmony_ci
3058c2ecf20Sopenharmony_ci	return list_next_or_null_rcu(ws_head, &ws->entry,
3068c2ecf20Sopenharmony_ci				struct wakeup_source, entry);
3078c2ecf20Sopenharmony_ci}
3088c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(wakeup_sources_walk_next);
3098c2ecf20Sopenharmony_ci
3108c2ecf20Sopenharmony_ci/**
3118c2ecf20Sopenharmony_ci * device_wakeup_attach - Attach a wakeup source object to a device object.
3128c2ecf20Sopenharmony_ci * @dev: Device to handle.
3138c2ecf20Sopenharmony_ci * @ws: Wakeup source object to attach to @dev.
3148c2ecf20Sopenharmony_ci *
3158c2ecf20Sopenharmony_ci * This causes @dev to be treated as a wakeup device.
3168c2ecf20Sopenharmony_ci */
3178c2ecf20Sopenharmony_cistatic int device_wakeup_attach(struct device *dev, struct wakeup_source *ws)
3188c2ecf20Sopenharmony_ci{
3198c2ecf20Sopenharmony_ci	spin_lock_irq(&dev->power.lock);
3208c2ecf20Sopenharmony_ci	if (dev->power.wakeup) {
3218c2ecf20Sopenharmony_ci		spin_unlock_irq(&dev->power.lock);
3228c2ecf20Sopenharmony_ci		return -EEXIST;
3238c2ecf20Sopenharmony_ci	}
3248c2ecf20Sopenharmony_ci	dev->power.wakeup = ws;
3258c2ecf20Sopenharmony_ci	if (dev->power.wakeirq)
3268c2ecf20Sopenharmony_ci		device_wakeup_attach_irq(dev, dev->power.wakeirq);
3278c2ecf20Sopenharmony_ci	spin_unlock_irq(&dev->power.lock);
3288c2ecf20Sopenharmony_ci	return 0;
3298c2ecf20Sopenharmony_ci}
3308c2ecf20Sopenharmony_ci
3318c2ecf20Sopenharmony_ci/**
3328c2ecf20Sopenharmony_ci * device_wakeup_enable - Enable given device to be a wakeup source.
3338c2ecf20Sopenharmony_ci * @dev: Device to handle.
3348c2ecf20Sopenharmony_ci *
3358c2ecf20Sopenharmony_ci * Create a wakeup source object, register it and attach it to @dev.
3368c2ecf20Sopenharmony_ci */
3378c2ecf20Sopenharmony_ciint device_wakeup_enable(struct device *dev)
3388c2ecf20Sopenharmony_ci{
3398c2ecf20Sopenharmony_ci	struct wakeup_source *ws;
3408c2ecf20Sopenharmony_ci	int ret;
3418c2ecf20Sopenharmony_ci
3428c2ecf20Sopenharmony_ci	if (!dev || !dev->power.can_wakeup)
3438c2ecf20Sopenharmony_ci		return -EINVAL;
3448c2ecf20Sopenharmony_ci
3458c2ecf20Sopenharmony_ci	if (pm_suspend_target_state != PM_SUSPEND_ON)
3468c2ecf20Sopenharmony_ci		dev_dbg(dev, "Suspicious %s() during system transition!\n", __func__);
3478c2ecf20Sopenharmony_ci
3488c2ecf20Sopenharmony_ci	ws = wakeup_source_register(dev, dev_name(dev));
3498c2ecf20Sopenharmony_ci	if (!ws)
3508c2ecf20Sopenharmony_ci		return -ENOMEM;
3518c2ecf20Sopenharmony_ci
3528c2ecf20Sopenharmony_ci	ret = device_wakeup_attach(dev, ws);
3538c2ecf20Sopenharmony_ci	if (ret)
3548c2ecf20Sopenharmony_ci		wakeup_source_unregister(ws);
3558c2ecf20Sopenharmony_ci
3568c2ecf20Sopenharmony_ci	return ret;
3578c2ecf20Sopenharmony_ci}
3588c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(device_wakeup_enable);
3598c2ecf20Sopenharmony_ci
3608c2ecf20Sopenharmony_ci/**
3618c2ecf20Sopenharmony_ci * device_wakeup_attach_irq - Attach a wakeirq to a wakeup source
3628c2ecf20Sopenharmony_ci * @dev: Device to handle
3638c2ecf20Sopenharmony_ci * @wakeirq: Device specific wakeirq entry
3648c2ecf20Sopenharmony_ci *
3658c2ecf20Sopenharmony_ci * Attach a device wakeirq to the wakeup source so the device
3668c2ecf20Sopenharmony_ci * wake IRQ can be configured automatically for suspend and
3678c2ecf20Sopenharmony_ci * resume.
3688c2ecf20Sopenharmony_ci *
3698c2ecf20Sopenharmony_ci * Call under the device's power.lock lock.
3708c2ecf20Sopenharmony_ci */
3718c2ecf20Sopenharmony_civoid device_wakeup_attach_irq(struct device *dev,
3728c2ecf20Sopenharmony_ci			     struct wake_irq *wakeirq)
3738c2ecf20Sopenharmony_ci{
3748c2ecf20Sopenharmony_ci	struct wakeup_source *ws;
3758c2ecf20Sopenharmony_ci
3768c2ecf20Sopenharmony_ci	ws = dev->power.wakeup;
3778c2ecf20Sopenharmony_ci	if (!ws)
3788c2ecf20Sopenharmony_ci		return;
3798c2ecf20Sopenharmony_ci
3808c2ecf20Sopenharmony_ci	if (ws->wakeirq)
3818c2ecf20Sopenharmony_ci		dev_err(dev, "Leftover wakeup IRQ found, overriding\n");
3828c2ecf20Sopenharmony_ci
3838c2ecf20Sopenharmony_ci	ws->wakeirq = wakeirq;
3848c2ecf20Sopenharmony_ci}
3858c2ecf20Sopenharmony_ci
3868c2ecf20Sopenharmony_ci/**
3878c2ecf20Sopenharmony_ci * device_wakeup_detach_irq - Detach a wakeirq from a wakeup source
3888c2ecf20Sopenharmony_ci * @dev: Device to handle
3898c2ecf20Sopenharmony_ci *
3908c2ecf20Sopenharmony_ci * Removes a device wakeirq from the wakeup source.
3918c2ecf20Sopenharmony_ci *
3928c2ecf20Sopenharmony_ci * Call under the device's power.lock lock.
3938c2ecf20Sopenharmony_ci */
3948c2ecf20Sopenharmony_civoid device_wakeup_detach_irq(struct device *dev)
3958c2ecf20Sopenharmony_ci{
3968c2ecf20Sopenharmony_ci	struct wakeup_source *ws;
3978c2ecf20Sopenharmony_ci
3988c2ecf20Sopenharmony_ci	ws = dev->power.wakeup;
3998c2ecf20Sopenharmony_ci	if (ws)
4008c2ecf20Sopenharmony_ci		ws->wakeirq = NULL;
4018c2ecf20Sopenharmony_ci}
4028c2ecf20Sopenharmony_ci
4038c2ecf20Sopenharmony_ci/**
4048c2ecf20Sopenharmony_ci * device_wakeup_arm_wake_irqs(void)
4058c2ecf20Sopenharmony_ci *
4068c2ecf20Sopenharmony_ci * Itereates over the list of device wakeirqs to arm them.
4078c2ecf20Sopenharmony_ci */
4088c2ecf20Sopenharmony_civoid device_wakeup_arm_wake_irqs(void)
4098c2ecf20Sopenharmony_ci{
4108c2ecf20Sopenharmony_ci	struct wakeup_source *ws;
4118c2ecf20Sopenharmony_ci	int srcuidx;
4128c2ecf20Sopenharmony_ci
4138c2ecf20Sopenharmony_ci	srcuidx = srcu_read_lock(&wakeup_srcu);
4148c2ecf20Sopenharmony_ci	list_for_each_entry_rcu_locked(ws, &wakeup_sources, entry)
4158c2ecf20Sopenharmony_ci		dev_pm_arm_wake_irq(ws->wakeirq);
4168c2ecf20Sopenharmony_ci	srcu_read_unlock(&wakeup_srcu, srcuidx);
4178c2ecf20Sopenharmony_ci}
4188c2ecf20Sopenharmony_ci
4198c2ecf20Sopenharmony_ci/**
4208c2ecf20Sopenharmony_ci * device_wakeup_disarm_wake_irqs(void)
4218c2ecf20Sopenharmony_ci *
4228c2ecf20Sopenharmony_ci * Itereates over the list of device wakeirqs to disarm them.
4238c2ecf20Sopenharmony_ci */
4248c2ecf20Sopenharmony_civoid device_wakeup_disarm_wake_irqs(void)
4258c2ecf20Sopenharmony_ci{
4268c2ecf20Sopenharmony_ci	struct wakeup_source *ws;
4278c2ecf20Sopenharmony_ci	int srcuidx;
4288c2ecf20Sopenharmony_ci
4298c2ecf20Sopenharmony_ci	srcuidx = srcu_read_lock(&wakeup_srcu);
4308c2ecf20Sopenharmony_ci	list_for_each_entry_rcu_locked(ws, &wakeup_sources, entry)
4318c2ecf20Sopenharmony_ci		dev_pm_disarm_wake_irq(ws->wakeirq);
4328c2ecf20Sopenharmony_ci	srcu_read_unlock(&wakeup_srcu, srcuidx);
4338c2ecf20Sopenharmony_ci}
4348c2ecf20Sopenharmony_ci
4358c2ecf20Sopenharmony_ci/**
4368c2ecf20Sopenharmony_ci * device_wakeup_detach - Detach a device's wakeup source object from it.
4378c2ecf20Sopenharmony_ci * @dev: Device to detach the wakeup source object from.
4388c2ecf20Sopenharmony_ci *
4398c2ecf20Sopenharmony_ci * After it returns, @dev will not be treated as a wakeup device any more.
4408c2ecf20Sopenharmony_ci */
4418c2ecf20Sopenharmony_cistatic struct wakeup_source *device_wakeup_detach(struct device *dev)
4428c2ecf20Sopenharmony_ci{
4438c2ecf20Sopenharmony_ci	struct wakeup_source *ws;
4448c2ecf20Sopenharmony_ci
4458c2ecf20Sopenharmony_ci	spin_lock_irq(&dev->power.lock);
4468c2ecf20Sopenharmony_ci	ws = dev->power.wakeup;
4478c2ecf20Sopenharmony_ci	dev->power.wakeup = NULL;
4488c2ecf20Sopenharmony_ci	spin_unlock_irq(&dev->power.lock);
4498c2ecf20Sopenharmony_ci	return ws;
4508c2ecf20Sopenharmony_ci}
4518c2ecf20Sopenharmony_ci
4528c2ecf20Sopenharmony_ci/**
4538c2ecf20Sopenharmony_ci * device_wakeup_disable - Do not regard a device as a wakeup source any more.
4548c2ecf20Sopenharmony_ci * @dev: Device to handle.
4558c2ecf20Sopenharmony_ci *
4568c2ecf20Sopenharmony_ci * Detach the @dev's wakeup source object from it, unregister this wakeup source
4578c2ecf20Sopenharmony_ci * object and destroy it.
4588c2ecf20Sopenharmony_ci */
4598c2ecf20Sopenharmony_ciint device_wakeup_disable(struct device *dev)
4608c2ecf20Sopenharmony_ci{
4618c2ecf20Sopenharmony_ci	struct wakeup_source *ws;
4628c2ecf20Sopenharmony_ci
4638c2ecf20Sopenharmony_ci	if (!dev || !dev->power.can_wakeup)
4648c2ecf20Sopenharmony_ci		return -EINVAL;
4658c2ecf20Sopenharmony_ci
4668c2ecf20Sopenharmony_ci	ws = device_wakeup_detach(dev);
4678c2ecf20Sopenharmony_ci	wakeup_source_unregister(ws);
4688c2ecf20Sopenharmony_ci	return 0;
4698c2ecf20Sopenharmony_ci}
4708c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(device_wakeup_disable);
4718c2ecf20Sopenharmony_ci
4728c2ecf20Sopenharmony_ci/**
4738c2ecf20Sopenharmony_ci * device_set_wakeup_capable - Set/reset device wakeup capability flag.
4748c2ecf20Sopenharmony_ci * @dev: Device to handle.
4758c2ecf20Sopenharmony_ci * @capable: Whether or not @dev is capable of waking up the system from sleep.
4768c2ecf20Sopenharmony_ci *
4778c2ecf20Sopenharmony_ci * If @capable is set, set the @dev's power.can_wakeup flag and add its
4788c2ecf20Sopenharmony_ci * wakeup-related attributes to sysfs.  Otherwise, unset the @dev's
4798c2ecf20Sopenharmony_ci * power.can_wakeup flag and remove its wakeup-related attributes from sysfs.
4808c2ecf20Sopenharmony_ci *
4818c2ecf20Sopenharmony_ci * This function may sleep and it can't be called from any context where
4828c2ecf20Sopenharmony_ci * sleeping is not allowed.
4838c2ecf20Sopenharmony_ci */
4848c2ecf20Sopenharmony_civoid device_set_wakeup_capable(struct device *dev, bool capable)
4858c2ecf20Sopenharmony_ci{
4868c2ecf20Sopenharmony_ci	if (!!dev->power.can_wakeup == !!capable)
4878c2ecf20Sopenharmony_ci		return;
4888c2ecf20Sopenharmony_ci
4898c2ecf20Sopenharmony_ci	dev->power.can_wakeup = capable;
4908c2ecf20Sopenharmony_ci	if (device_is_registered(dev) && !list_empty(&dev->power.entry)) {
4918c2ecf20Sopenharmony_ci		if (capable) {
4928c2ecf20Sopenharmony_ci			int ret = wakeup_sysfs_add(dev);
4938c2ecf20Sopenharmony_ci
4948c2ecf20Sopenharmony_ci			if (ret)
4958c2ecf20Sopenharmony_ci				dev_info(dev, "Wakeup sysfs attributes not added\n");
4968c2ecf20Sopenharmony_ci		} else {
4978c2ecf20Sopenharmony_ci			wakeup_sysfs_remove(dev);
4988c2ecf20Sopenharmony_ci		}
4998c2ecf20Sopenharmony_ci	}
5008c2ecf20Sopenharmony_ci}
5018c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(device_set_wakeup_capable);
5028c2ecf20Sopenharmony_ci
5038c2ecf20Sopenharmony_ci/**
5048c2ecf20Sopenharmony_ci * device_init_wakeup - Device wakeup initialization.
5058c2ecf20Sopenharmony_ci * @dev: Device to handle.
5068c2ecf20Sopenharmony_ci * @enable: Whether or not to enable @dev as a wakeup device.
5078c2ecf20Sopenharmony_ci *
5088c2ecf20Sopenharmony_ci * By default, most devices should leave wakeup disabled.  The exceptions are
5098c2ecf20Sopenharmony_ci * devices that everyone expects to be wakeup sources: keyboards, power buttons,
5108c2ecf20Sopenharmony_ci * possibly network interfaces, etc.  Also, devices that don't generate their
5118c2ecf20Sopenharmony_ci * own wakeup requests but merely forward requests from one bus to another
5128c2ecf20Sopenharmony_ci * (like PCI bridges) should have wakeup enabled by default.
5138c2ecf20Sopenharmony_ci */
5148c2ecf20Sopenharmony_ciint device_init_wakeup(struct device *dev, bool enable)
5158c2ecf20Sopenharmony_ci{
5168c2ecf20Sopenharmony_ci	int ret = 0;
5178c2ecf20Sopenharmony_ci
5188c2ecf20Sopenharmony_ci	if (!dev)
5198c2ecf20Sopenharmony_ci		return -EINVAL;
5208c2ecf20Sopenharmony_ci
5218c2ecf20Sopenharmony_ci	if (enable) {
5228c2ecf20Sopenharmony_ci		device_set_wakeup_capable(dev, true);
5238c2ecf20Sopenharmony_ci		ret = device_wakeup_enable(dev);
5248c2ecf20Sopenharmony_ci	} else {
5258c2ecf20Sopenharmony_ci		device_wakeup_disable(dev);
5268c2ecf20Sopenharmony_ci		device_set_wakeup_capable(dev, false);
5278c2ecf20Sopenharmony_ci	}
5288c2ecf20Sopenharmony_ci
5298c2ecf20Sopenharmony_ci	return ret;
5308c2ecf20Sopenharmony_ci}
5318c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(device_init_wakeup);
5328c2ecf20Sopenharmony_ci
5338c2ecf20Sopenharmony_ci/**
5348c2ecf20Sopenharmony_ci * device_set_wakeup_enable - Enable or disable a device to wake up the system.
5358c2ecf20Sopenharmony_ci * @dev: Device to handle.
5368c2ecf20Sopenharmony_ci */
5378c2ecf20Sopenharmony_ciint device_set_wakeup_enable(struct device *dev, bool enable)
5388c2ecf20Sopenharmony_ci{
5398c2ecf20Sopenharmony_ci	return enable ? device_wakeup_enable(dev) : device_wakeup_disable(dev);
5408c2ecf20Sopenharmony_ci}
5418c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(device_set_wakeup_enable);
5428c2ecf20Sopenharmony_ci
5438c2ecf20Sopenharmony_ci/**
5448c2ecf20Sopenharmony_ci * wakeup_source_not_registered - validate the given wakeup source.
5458c2ecf20Sopenharmony_ci * @ws: Wakeup source to be validated.
5468c2ecf20Sopenharmony_ci */
5478c2ecf20Sopenharmony_cistatic bool wakeup_source_not_registered(struct wakeup_source *ws)
5488c2ecf20Sopenharmony_ci{
5498c2ecf20Sopenharmony_ci	/*
5508c2ecf20Sopenharmony_ci	 * Use timer struct to check if the given source is initialized
5518c2ecf20Sopenharmony_ci	 * by wakeup_source_add.
5528c2ecf20Sopenharmony_ci	 */
5538c2ecf20Sopenharmony_ci	return ws->timer.function != pm_wakeup_timer_fn;
5548c2ecf20Sopenharmony_ci}
5558c2ecf20Sopenharmony_ci
5568c2ecf20Sopenharmony_ci/*
5578c2ecf20Sopenharmony_ci * The functions below use the observation that each wakeup event starts a
5588c2ecf20Sopenharmony_ci * period in which the system should not be suspended.  The moment this period
5598c2ecf20Sopenharmony_ci * will end depends on how the wakeup event is going to be processed after being
5608c2ecf20Sopenharmony_ci * detected and all of the possible cases can be divided into two distinct
5618c2ecf20Sopenharmony_ci * groups.
5628c2ecf20Sopenharmony_ci *
5638c2ecf20Sopenharmony_ci * First, a wakeup event may be detected by the same functional unit that will
5648c2ecf20Sopenharmony_ci * carry out the entire processing of it and possibly will pass it to user space
5658c2ecf20Sopenharmony_ci * for further processing.  In that case the functional unit that has detected
5668c2ecf20Sopenharmony_ci * the event may later "close" the "no suspend" period associated with it
5678c2ecf20Sopenharmony_ci * directly as soon as it has been dealt with.  The pair of pm_stay_awake() and
5688c2ecf20Sopenharmony_ci * pm_relax(), balanced with each other, is supposed to be used in such
5698c2ecf20Sopenharmony_ci * situations.
5708c2ecf20Sopenharmony_ci *
5718c2ecf20Sopenharmony_ci * Second, a wakeup event may be detected by one functional unit and processed
5728c2ecf20Sopenharmony_ci * by another one.  In that case the unit that has detected it cannot really
5738c2ecf20Sopenharmony_ci * "close" the "no suspend" period associated with it, unless it knows in
5748c2ecf20Sopenharmony_ci * advance what's going to happen to the event during processing.  This
5758c2ecf20Sopenharmony_ci * knowledge, however, may not be available to it, so it can simply specify time
5768c2ecf20Sopenharmony_ci * to wait before the system can be suspended and pass it as the second
5778c2ecf20Sopenharmony_ci * argument of pm_wakeup_event().
5788c2ecf20Sopenharmony_ci *
5798c2ecf20Sopenharmony_ci * It is valid to call pm_relax() after pm_wakeup_event(), in which case the
5808c2ecf20Sopenharmony_ci * "no suspend" period will be ended either by the pm_relax(), or by the timer
5818c2ecf20Sopenharmony_ci * function executed when the timer expires, whichever comes first.
5828c2ecf20Sopenharmony_ci */
5838c2ecf20Sopenharmony_ci
5848c2ecf20Sopenharmony_ci/**
5858c2ecf20Sopenharmony_ci * wakup_source_activate - Mark given wakeup source as active.
5868c2ecf20Sopenharmony_ci * @ws: Wakeup source to handle.
5878c2ecf20Sopenharmony_ci *
5888c2ecf20Sopenharmony_ci * Update the @ws' statistics and, if @ws has just been activated, notify the PM
5898c2ecf20Sopenharmony_ci * core of the event by incrementing the counter of of wakeup events being
5908c2ecf20Sopenharmony_ci * processed.
5918c2ecf20Sopenharmony_ci */
5928c2ecf20Sopenharmony_cistatic void wakeup_source_activate(struct wakeup_source *ws)
5938c2ecf20Sopenharmony_ci{
5948c2ecf20Sopenharmony_ci	unsigned int cec;
5958c2ecf20Sopenharmony_ci
5968c2ecf20Sopenharmony_ci	if (WARN_ONCE(wakeup_source_not_registered(ws),
5978c2ecf20Sopenharmony_ci			"unregistered wakeup source\n"))
5988c2ecf20Sopenharmony_ci		return;
5998c2ecf20Sopenharmony_ci
6008c2ecf20Sopenharmony_ci	ws->active = true;
6018c2ecf20Sopenharmony_ci	ws->active_count++;
6028c2ecf20Sopenharmony_ci	ws->last_time = ktime_get();
6038c2ecf20Sopenharmony_ci	if (ws->autosleep_enabled)
6048c2ecf20Sopenharmony_ci		ws->start_prevent_time = ws->last_time;
6058c2ecf20Sopenharmony_ci
6068c2ecf20Sopenharmony_ci	/* Increment the counter of events in progress. */
6078c2ecf20Sopenharmony_ci	cec = atomic_inc_return(&combined_event_count);
6088c2ecf20Sopenharmony_ci
6098c2ecf20Sopenharmony_ci	trace_wakeup_source_activate(ws->name, cec);
6108c2ecf20Sopenharmony_ci}
6118c2ecf20Sopenharmony_ci
6128c2ecf20Sopenharmony_ci/**
6138c2ecf20Sopenharmony_ci * wakeup_source_report_event - Report wakeup event using the given source.
6148c2ecf20Sopenharmony_ci * @ws: Wakeup source to report the event for.
6158c2ecf20Sopenharmony_ci * @hard: If set, abort suspends in progress and wake up from suspend-to-idle.
6168c2ecf20Sopenharmony_ci */
6178c2ecf20Sopenharmony_cistatic void wakeup_source_report_event(struct wakeup_source *ws, bool hard)
6188c2ecf20Sopenharmony_ci{
6198c2ecf20Sopenharmony_ci	ws->event_count++;
6208c2ecf20Sopenharmony_ci	/* This is racy, but the counter is approximate anyway. */
6218c2ecf20Sopenharmony_ci	if (events_check_enabled)
6228c2ecf20Sopenharmony_ci		ws->wakeup_count++;
6238c2ecf20Sopenharmony_ci
6248c2ecf20Sopenharmony_ci	if (!ws->active)
6258c2ecf20Sopenharmony_ci		wakeup_source_activate(ws);
6268c2ecf20Sopenharmony_ci
6278c2ecf20Sopenharmony_ci	if (hard)
6288c2ecf20Sopenharmony_ci		pm_system_wakeup();
6298c2ecf20Sopenharmony_ci}
6308c2ecf20Sopenharmony_ci
6318c2ecf20Sopenharmony_ci/**
6328c2ecf20Sopenharmony_ci * __pm_stay_awake - Notify the PM core of a wakeup event.
6338c2ecf20Sopenharmony_ci * @ws: Wakeup source object associated with the source of the event.
6348c2ecf20Sopenharmony_ci *
6358c2ecf20Sopenharmony_ci * It is safe to call this function from interrupt context.
6368c2ecf20Sopenharmony_ci */
6378c2ecf20Sopenharmony_civoid __pm_stay_awake(struct wakeup_source *ws)
6388c2ecf20Sopenharmony_ci{
6398c2ecf20Sopenharmony_ci	unsigned long flags;
6408c2ecf20Sopenharmony_ci
6418c2ecf20Sopenharmony_ci	if (!ws)
6428c2ecf20Sopenharmony_ci		return;
6438c2ecf20Sopenharmony_ci
6448c2ecf20Sopenharmony_ci	spin_lock_irqsave(&ws->lock, flags);
6458c2ecf20Sopenharmony_ci
6468c2ecf20Sopenharmony_ci	wakeup_source_report_event(ws, false);
6478c2ecf20Sopenharmony_ci	del_timer(&ws->timer);
6488c2ecf20Sopenharmony_ci	ws->timer_expires = 0;
6498c2ecf20Sopenharmony_ci
6508c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&ws->lock, flags);
6518c2ecf20Sopenharmony_ci}
6528c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(__pm_stay_awake);
6538c2ecf20Sopenharmony_ci
6548c2ecf20Sopenharmony_ci/**
6558c2ecf20Sopenharmony_ci * pm_stay_awake - Notify the PM core that a wakeup event is being processed.
6568c2ecf20Sopenharmony_ci * @dev: Device the wakeup event is related to.
6578c2ecf20Sopenharmony_ci *
6588c2ecf20Sopenharmony_ci * Notify the PM core of a wakeup event (signaled by @dev) by calling
6598c2ecf20Sopenharmony_ci * __pm_stay_awake for the @dev's wakeup source object.
6608c2ecf20Sopenharmony_ci *
6618c2ecf20Sopenharmony_ci * Call this function after detecting of a wakeup event if pm_relax() is going
6628c2ecf20Sopenharmony_ci * to be called directly after processing the event (and possibly passing it to
6638c2ecf20Sopenharmony_ci * user space for further processing).
6648c2ecf20Sopenharmony_ci */
6658c2ecf20Sopenharmony_civoid pm_stay_awake(struct device *dev)
6668c2ecf20Sopenharmony_ci{
6678c2ecf20Sopenharmony_ci	unsigned long flags;
6688c2ecf20Sopenharmony_ci
6698c2ecf20Sopenharmony_ci	if (!dev)
6708c2ecf20Sopenharmony_ci		return;
6718c2ecf20Sopenharmony_ci
6728c2ecf20Sopenharmony_ci	spin_lock_irqsave(&dev->power.lock, flags);
6738c2ecf20Sopenharmony_ci	__pm_stay_awake(dev->power.wakeup);
6748c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&dev->power.lock, flags);
6758c2ecf20Sopenharmony_ci}
6768c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(pm_stay_awake);
6778c2ecf20Sopenharmony_ci
6788c2ecf20Sopenharmony_ci#ifdef CONFIG_PM_AUTOSLEEP
6798c2ecf20Sopenharmony_cistatic void update_prevent_sleep_time(struct wakeup_source *ws, ktime_t now)
6808c2ecf20Sopenharmony_ci{
6818c2ecf20Sopenharmony_ci	ktime_t delta = ktime_sub(now, ws->start_prevent_time);
6828c2ecf20Sopenharmony_ci	ws->prevent_sleep_time = ktime_add(ws->prevent_sleep_time, delta);
6838c2ecf20Sopenharmony_ci}
6848c2ecf20Sopenharmony_ci#else
6858c2ecf20Sopenharmony_cistatic inline void update_prevent_sleep_time(struct wakeup_source *ws,
6868c2ecf20Sopenharmony_ci					     ktime_t now) {}
6878c2ecf20Sopenharmony_ci#endif
6888c2ecf20Sopenharmony_ci
6898c2ecf20Sopenharmony_ci/**
6908c2ecf20Sopenharmony_ci * wakup_source_deactivate - Mark given wakeup source as inactive.
6918c2ecf20Sopenharmony_ci * @ws: Wakeup source to handle.
6928c2ecf20Sopenharmony_ci *
6938c2ecf20Sopenharmony_ci * Update the @ws' statistics and notify the PM core that the wakeup source has
6948c2ecf20Sopenharmony_ci * become inactive by decrementing the counter of wakeup events being processed
6958c2ecf20Sopenharmony_ci * and incrementing the counter of registered wakeup events.
6968c2ecf20Sopenharmony_ci */
6978c2ecf20Sopenharmony_cistatic void wakeup_source_deactivate(struct wakeup_source *ws)
6988c2ecf20Sopenharmony_ci{
6998c2ecf20Sopenharmony_ci	unsigned int cnt, inpr, cec;
7008c2ecf20Sopenharmony_ci	ktime_t duration;
7018c2ecf20Sopenharmony_ci	ktime_t now;
7028c2ecf20Sopenharmony_ci
7038c2ecf20Sopenharmony_ci	ws->relax_count++;
7048c2ecf20Sopenharmony_ci	/*
7058c2ecf20Sopenharmony_ci	 * __pm_relax() may be called directly or from a timer function.
7068c2ecf20Sopenharmony_ci	 * If it is called directly right after the timer function has been
7078c2ecf20Sopenharmony_ci	 * started, but before the timer function calls __pm_relax(), it is
7088c2ecf20Sopenharmony_ci	 * possible that __pm_stay_awake() will be called in the meantime and
7098c2ecf20Sopenharmony_ci	 * will set ws->active.  Then, ws->active may be cleared immediately
7108c2ecf20Sopenharmony_ci	 * by the __pm_relax() called from the timer function, but in such a
7118c2ecf20Sopenharmony_ci	 * case ws->relax_count will be different from ws->active_count.
7128c2ecf20Sopenharmony_ci	 */
7138c2ecf20Sopenharmony_ci	if (ws->relax_count != ws->active_count) {
7148c2ecf20Sopenharmony_ci		ws->relax_count--;
7158c2ecf20Sopenharmony_ci		return;
7168c2ecf20Sopenharmony_ci	}
7178c2ecf20Sopenharmony_ci
7188c2ecf20Sopenharmony_ci	ws->active = false;
7198c2ecf20Sopenharmony_ci
7208c2ecf20Sopenharmony_ci	now = ktime_get();
7218c2ecf20Sopenharmony_ci	duration = ktime_sub(now, ws->last_time);
7228c2ecf20Sopenharmony_ci	ws->total_time = ktime_add(ws->total_time, duration);
7238c2ecf20Sopenharmony_ci	if (ktime_to_ns(duration) > ktime_to_ns(ws->max_time))
7248c2ecf20Sopenharmony_ci		ws->max_time = duration;
7258c2ecf20Sopenharmony_ci
7268c2ecf20Sopenharmony_ci	ws->last_time = now;
7278c2ecf20Sopenharmony_ci	del_timer(&ws->timer);
7288c2ecf20Sopenharmony_ci	ws->timer_expires = 0;
7298c2ecf20Sopenharmony_ci
7308c2ecf20Sopenharmony_ci	if (ws->autosleep_enabled)
7318c2ecf20Sopenharmony_ci		update_prevent_sleep_time(ws, now);
7328c2ecf20Sopenharmony_ci
7338c2ecf20Sopenharmony_ci	/*
7348c2ecf20Sopenharmony_ci	 * Increment the counter of registered wakeup events and decrement the
7358c2ecf20Sopenharmony_ci	 * couter of wakeup events in progress simultaneously.
7368c2ecf20Sopenharmony_ci	 */
7378c2ecf20Sopenharmony_ci	cec = atomic_add_return(MAX_IN_PROGRESS, &combined_event_count);
7388c2ecf20Sopenharmony_ci	trace_wakeup_source_deactivate(ws->name, cec);
7398c2ecf20Sopenharmony_ci
7408c2ecf20Sopenharmony_ci	split_counters(&cnt, &inpr);
7418c2ecf20Sopenharmony_ci	if (!inpr && waitqueue_active(&wakeup_count_wait_queue))
7428c2ecf20Sopenharmony_ci		wake_up(&wakeup_count_wait_queue);
7438c2ecf20Sopenharmony_ci}
7448c2ecf20Sopenharmony_ci
7458c2ecf20Sopenharmony_ci/**
7468c2ecf20Sopenharmony_ci * __pm_relax - Notify the PM core that processing of a wakeup event has ended.
7478c2ecf20Sopenharmony_ci * @ws: Wakeup source object associated with the source of the event.
7488c2ecf20Sopenharmony_ci *
7498c2ecf20Sopenharmony_ci * Call this function for wakeup events whose processing started with calling
7508c2ecf20Sopenharmony_ci * __pm_stay_awake().
7518c2ecf20Sopenharmony_ci *
7528c2ecf20Sopenharmony_ci * It is safe to call it from interrupt context.
7538c2ecf20Sopenharmony_ci */
7548c2ecf20Sopenharmony_civoid __pm_relax(struct wakeup_source *ws)
7558c2ecf20Sopenharmony_ci{
7568c2ecf20Sopenharmony_ci	unsigned long flags;
7578c2ecf20Sopenharmony_ci
7588c2ecf20Sopenharmony_ci	if (!ws)
7598c2ecf20Sopenharmony_ci		return;
7608c2ecf20Sopenharmony_ci
7618c2ecf20Sopenharmony_ci	spin_lock_irqsave(&ws->lock, flags);
7628c2ecf20Sopenharmony_ci	if (ws->active)
7638c2ecf20Sopenharmony_ci		wakeup_source_deactivate(ws);
7648c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&ws->lock, flags);
7658c2ecf20Sopenharmony_ci}
7668c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(__pm_relax);
7678c2ecf20Sopenharmony_ci
7688c2ecf20Sopenharmony_ci/**
7698c2ecf20Sopenharmony_ci * pm_relax - Notify the PM core that processing of a wakeup event has ended.
7708c2ecf20Sopenharmony_ci * @dev: Device that signaled the event.
7718c2ecf20Sopenharmony_ci *
7728c2ecf20Sopenharmony_ci * Execute __pm_relax() for the @dev's wakeup source object.
7738c2ecf20Sopenharmony_ci */
7748c2ecf20Sopenharmony_civoid pm_relax(struct device *dev)
7758c2ecf20Sopenharmony_ci{
7768c2ecf20Sopenharmony_ci	unsigned long flags;
7778c2ecf20Sopenharmony_ci
7788c2ecf20Sopenharmony_ci	if (!dev)
7798c2ecf20Sopenharmony_ci		return;
7808c2ecf20Sopenharmony_ci
7818c2ecf20Sopenharmony_ci	spin_lock_irqsave(&dev->power.lock, flags);
7828c2ecf20Sopenharmony_ci	__pm_relax(dev->power.wakeup);
7838c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&dev->power.lock, flags);
7848c2ecf20Sopenharmony_ci}
7858c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(pm_relax);
7868c2ecf20Sopenharmony_ci
7878c2ecf20Sopenharmony_ci/**
7888c2ecf20Sopenharmony_ci * pm_wakeup_timer_fn - Delayed finalization of a wakeup event.
7898c2ecf20Sopenharmony_ci * @data: Address of the wakeup source object associated with the event source.
7908c2ecf20Sopenharmony_ci *
7918c2ecf20Sopenharmony_ci * Call wakeup_source_deactivate() for the wakeup source whose address is stored
7928c2ecf20Sopenharmony_ci * in @data if it is currently active and its timer has not been canceled and
7938c2ecf20Sopenharmony_ci * the expiration time of the timer is not in future.
7948c2ecf20Sopenharmony_ci */
7958c2ecf20Sopenharmony_cistatic void pm_wakeup_timer_fn(struct timer_list *t)
7968c2ecf20Sopenharmony_ci{
7978c2ecf20Sopenharmony_ci	struct wakeup_source *ws = from_timer(ws, t, timer);
7988c2ecf20Sopenharmony_ci	unsigned long flags;
7998c2ecf20Sopenharmony_ci
8008c2ecf20Sopenharmony_ci	spin_lock_irqsave(&ws->lock, flags);
8018c2ecf20Sopenharmony_ci
8028c2ecf20Sopenharmony_ci	if (ws->active && ws->timer_expires
8038c2ecf20Sopenharmony_ci	    && time_after_eq(jiffies, ws->timer_expires)) {
8048c2ecf20Sopenharmony_ci		wakeup_source_deactivate(ws);
8058c2ecf20Sopenharmony_ci		ws->expire_count++;
8068c2ecf20Sopenharmony_ci	}
8078c2ecf20Sopenharmony_ci
8088c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&ws->lock, flags);
8098c2ecf20Sopenharmony_ci}
8108c2ecf20Sopenharmony_ci
8118c2ecf20Sopenharmony_ci/**
8128c2ecf20Sopenharmony_ci * pm_wakeup_ws_event - Notify the PM core of a wakeup event.
8138c2ecf20Sopenharmony_ci * @ws: Wakeup source object associated with the event source.
8148c2ecf20Sopenharmony_ci * @msec: Anticipated event processing time (in milliseconds).
8158c2ecf20Sopenharmony_ci * @hard: If set, abort suspends in progress and wake up from suspend-to-idle.
8168c2ecf20Sopenharmony_ci *
8178c2ecf20Sopenharmony_ci * Notify the PM core of a wakeup event whose source is @ws that will take
8188c2ecf20Sopenharmony_ci * approximately @msec milliseconds to be processed by the kernel.  If @ws is
8198c2ecf20Sopenharmony_ci * not active, activate it.  If @msec is nonzero, set up the @ws' timer to
8208c2ecf20Sopenharmony_ci * execute pm_wakeup_timer_fn() in future.
8218c2ecf20Sopenharmony_ci *
8228c2ecf20Sopenharmony_ci * It is safe to call this function from interrupt context.
8238c2ecf20Sopenharmony_ci */
8248c2ecf20Sopenharmony_civoid pm_wakeup_ws_event(struct wakeup_source *ws, unsigned int msec, bool hard)
8258c2ecf20Sopenharmony_ci{
8268c2ecf20Sopenharmony_ci	unsigned long flags;
8278c2ecf20Sopenharmony_ci	unsigned long expires;
8288c2ecf20Sopenharmony_ci
8298c2ecf20Sopenharmony_ci	if (!ws)
8308c2ecf20Sopenharmony_ci		return;
8318c2ecf20Sopenharmony_ci
8328c2ecf20Sopenharmony_ci	spin_lock_irqsave(&ws->lock, flags);
8338c2ecf20Sopenharmony_ci
8348c2ecf20Sopenharmony_ci	wakeup_source_report_event(ws, hard);
8358c2ecf20Sopenharmony_ci
8368c2ecf20Sopenharmony_ci	if (!msec) {
8378c2ecf20Sopenharmony_ci		wakeup_source_deactivate(ws);
8388c2ecf20Sopenharmony_ci		goto unlock;
8398c2ecf20Sopenharmony_ci	}
8408c2ecf20Sopenharmony_ci
8418c2ecf20Sopenharmony_ci	expires = jiffies + msecs_to_jiffies(msec);
8428c2ecf20Sopenharmony_ci	if (!expires)
8438c2ecf20Sopenharmony_ci		expires = 1;
8448c2ecf20Sopenharmony_ci
8458c2ecf20Sopenharmony_ci	if (!ws->timer_expires || time_after(expires, ws->timer_expires)) {
8468c2ecf20Sopenharmony_ci		mod_timer(&ws->timer, expires);
8478c2ecf20Sopenharmony_ci		ws->timer_expires = expires;
8488c2ecf20Sopenharmony_ci	}
8498c2ecf20Sopenharmony_ci
8508c2ecf20Sopenharmony_ci unlock:
8518c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&ws->lock, flags);
8528c2ecf20Sopenharmony_ci}
8538c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(pm_wakeup_ws_event);
8548c2ecf20Sopenharmony_ci
8558c2ecf20Sopenharmony_ci/**
8568c2ecf20Sopenharmony_ci * pm_wakeup_dev_event - Notify the PM core of a wakeup event.
8578c2ecf20Sopenharmony_ci * @dev: Device the wakeup event is related to.
8588c2ecf20Sopenharmony_ci * @msec: Anticipated event processing time (in milliseconds).
8598c2ecf20Sopenharmony_ci * @hard: If set, abort suspends in progress and wake up from suspend-to-idle.
8608c2ecf20Sopenharmony_ci *
8618c2ecf20Sopenharmony_ci * Call pm_wakeup_ws_event() for the @dev's wakeup source object.
8628c2ecf20Sopenharmony_ci */
8638c2ecf20Sopenharmony_civoid pm_wakeup_dev_event(struct device *dev, unsigned int msec, bool hard)
8648c2ecf20Sopenharmony_ci{
8658c2ecf20Sopenharmony_ci	unsigned long flags;
8668c2ecf20Sopenharmony_ci
8678c2ecf20Sopenharmony_ci	if (!dev)
8688c2ecf20Sopenharmony_ci		return;
8698c2ecf20Sopenharmony_ci
8708c2ecf20Sopenharmony_ci	spin_lock_irqsave(&dev->power.lock, flags);
8718c2ecf20Sopenharmony_ci	pm_wakeup_ws_event(dev->power.wakeup, msec, hard);
8728c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&dev->power.lock, flags);
8738c2ecf20Sopenharmony_ci}
8748c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(pm_wakeup_dev_event);
8758c2ecf20Sopenharmony_ci
8768c2ecf20Sopenharmony_civoid pm_print_active_wakeup_sources(void)
8778c2ecf20Sopenharmony_ci{
8788c2ecf20Sopenharmony_ci	struct wakeup_source *ws;
8798c2ecf20Sopenharmony_ci	int srcuidx, active = 0;
8808c2ecf20Sopenharmony_ci	struct wakeup_source *last_activity_ws = NULL;
8818c2ecf20Sopenharmony_ci
8828c2ecf20Sopenharmony_ci	srcuidx = srcu_read_lock(&wakeup_srcu);
8838c2ecf20Sopenharmony_ci	list_for_each_entry_rcu_locked(ws, &wakeup_sources, entry) {
8848c2ecf20Sopenharmony_ci		if (ws->active) {
8858c2ecf20Sopenharmony_ci			pm_pr_dbg("active wakeup source: %s\n", ws->name);
8868c2ecf20Sopenharmony_ci			active = 1;
8878c2ecf20Sopenharmony_ci		} else if (!active &&
8888c2ecf20Sopenharmony_ci			   (!last_activity_ws ||
8898c2ecf20Sopenharmony_ci			    ktime_to_ns(ws->last_time) >
8908c2ecf20Sopenharmony_ci			    ktime_to_ns(last_activity_ws->last_time))) {
8918c2ecf20Sopenharmony_ci			last_activity_ws = ws;
8928c2ecf20Sopenharmony_ci		}
8938c2ecf20Sopenharmony_ci	}
8948c2ecf20Sopenharmony_ci
8958c2ecf20Sopenharmony_ci	if (!active && last_activity_ws)
8968c2ecf20Sopenharmony_ci		pm_pr_dbg("last active wakeup source: %s\n",
8978c2ecf20Sopenharmony_ci			last_activity_ws->name);
8988c2ecf20Sopenharmony_ci	srcu_read_unlock(&wakeup_srcu, srcuidx);
8998c2ecf20Sopenharmony_ci}
9008c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(pm_print_active_wakeup_sources);
9018c2ecf20Sopenharmony_ci
9028c2ecf20Sopenharmony_ci/**
9038c2ecf20Sopenharmony_ci * pm_wakeup_pending - Check if power transition in progress should be aborted.
9048c2ecf20Sopenharmony_ci *
9058c2ecf20Sopenharmony_ci * Compare the current number of registered wakeup events with its preserved
9068c2ecf20Sopenharmony_ci * value from the past and return true if new wakeup events have been registered
9078c2ecf20Sopenharmony_ci * since the old value was stored.  Also return true if the current number of
9088c2ecf20Sopenharmony_ci * wakeup events being processed is different from zero.
9098c2ecf20Sopenharmony_ci */
9108c2ecf20Sopenharmony_cibool pm_wakeup_pending(void)
9118c2ecf20Sopenharmony_ci{
9128c2ecf20Sopenharmony_ci	unsigned long flags;
9138c2ecf20Sopenharmony_ci	bool ret = false;
9148c2ecf20Sopenharmony_ci
9158c2ecf20Sopenharmony_ci	raw_spin_lock_irqsave(&events_lock, flags);
9168c2ecf20Sopenharmony_ci	if (events_check_enabled) {
9178c2ecf20Sopenharmony_ci		unsigned int cnt, inpr;
9188c2ecf20Sopenharmony_ci
9198c2ecf20Sopenharmony_ci		split_counters(&cnt, &inpr);
9208c2ecf20Sopenharmony_ci		ret = (cnt != saved_count || inpr > 0);
9218c2ecf20Sopenharmony_ci		events_check_enabled = !ret;
9228c2ecf20Sopenharmony_ci	}
9238c2ecf20Sopenharmony_ci	raw_spin_unlock_irqrestore(&events_lock, flags);
9248c2ecf20Sopenharmony_ci
9258c2ecf20Sopenharmony_ci	if (ret) {
9268c2ecf20Sopenharmony_ci		pm_pr_dbg("Wakeup pending, aborting suspend\n");
9278c2ecf20Sopenharmony_ci		pm_print_active_wakeup_sources();
9288c2ecf20Sopenharmony_ci	}
9298c2ecf20Sopenharmony_ci
9308c2ecf20Sopenharmony_ci	return ret || atomic_read(&pm_abort_suspend) > 0;
9318c2ecf20Sopenharmony_ci}
9328c2ecf20Sopenharmony_ci
9338c2ecf20Sopenharmony_civoid pm_system_wakeup(void)
9348c2ecf20Sopenharmony_ci{
9358c2ecf20Sopenharmony_ci	atomic_inc(&pm_abort_suspend);
9368c2ecf20Sopenharmony_ci	s2idle_wake();
9378c2ecf20Sopenharmony_ci}
9388c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(pm_system_wakeup);
9398c2ecf20Sopenharmony_ci
9408c2ecf20Sopenharmony_civoid pm_system_cancel_wakeup(void)
9418c2ecf20Sopenharmony_ci{
9428c2ecf20Sopenharmony_ci	atomic_dec_if_positive(&pm_abort_suspend);
9438c2ecf20Sopenharmony_ci}
9448c2ecf20Sopenharmony_ci
9458c2ecf20Sopenharmony_civoid pm_wakeup_clear(unsigned int irq_number)
9468c2ecf20Sopenharmony_ci{
9478c2ecf20Sopenharmony_ci	raw_spin_lock_irq(&wakeup_irq_lock);
9488c2ecf20Sopenharmony_ci
9498c2ecf20Sopenharmony_ci	if (irq_number && wakeup_irq[0] == irq_number)
9508c2ecf20Sopenharmony_ci		wakeup_irq[0] = wakeup_irq[1];
9518c2ecf20Sopenharmony_ci	else
9528c2ecf20Sopenharmony_ci		wakeup_irq[0] = 0;
9538c2ecf20Sopenharmony_ci
9548c2ecf20Sopenharmony_ci	wakeup_irq[1] = 0;
9558c2ecf20Sopenharmony_ci
9568c2ecf20Sopenharmony_ci	raw_spin_unlock_irq(&wakeup_irq_lock);
9578c2ecf20Sopenharmony_ci
9588c2ecf20Sopenharmony_ci	if (!irq_number)
9598c2ecf20Sopenharmony_ci		atomic_set(&pm_abort_suspend, 0);
9608c2ecf20Sopenharmony_ci}
9618c2ecf20Sopenharmony_ci
9628c2ecf20Sopenharmony_civoid pm_system_irq_wakeup(unsigned int irq_number)
9638c2ecf20Sopenharmony_ci{
9648c2ecf20Sopenharmony_ci	unsigned long flags;
9658c2ecf20Sopenharmony_ci
9668c2ecf20Sopenharmony_ci	raw_spin_lock_irqsave(&wakeup_irq_lock, flags);
9678c2ecf20Sopenharmony_ci
9688c2ecf20Sopenharmony_ci	if (wakeup_irq[0] == 0)
9698c2ecf20Sopenharmony_ci		wakeup_irq[0] = irq_number;
9708c2ecf20Sopenharmony_ci	else if (wakeup_irq[1] == 0)
9718c2ecf20Sopenharmony_ci		wakeup_irq[1] = irq_number;
9728c2ecf20Sopenharmony_ci	else
9738c2ecf20Sopenharmony_ci		irq_number = 0;
9748c2ecf20Sopenharmony_ci
9758c2ecf20Sopenharmony_ci	raw_spin_unlock_irqrestore(&wakeup_irq_lock, flags);
9768c2ecf20Sopenharmony_ci
9778c2ecf20Sopenharmony_ci	if (irq_number)
9788c2ecf20Sopenharmony_ci		pm_system_wakeup();
9798c2ecf20Sopenharmony_ci}
9808c2ecf20Sopenharmony_ci
9818c2ecf20Sopenharmony_ciunsigned int pm_wakeup_irq(void)
9828c2ecf20Sopenharmony_ci{
9838c2ecf20Sopenharmony_ci	return wakeup_irq[0];
9848c2ecf20Sopenharmony_ci}
9858c2ecf20Sopenharmony_ci
9868c2ecf20Sopenharmony_ci/**
9878c2ecf20Sopenharmony_ci * pm_get_wakeup_count - Read the number of registered wakeup events.
9888c2ecf20Sopenharmony_ci * @count: Address to store the value at.
9898c2ecf20Sopenharmony_ci * @block: Whether or not to block.
9908c2ecf20Sopenharmony_ci *
9918c2ecf20Sopenharmony_ci * Store the number of registered wakeup events at the address in @count.  If
9928c2ecf20Sopenharmony_ci * @block is set, block until the current number of wakeup events being
9938c2ecf20Sopenharmony_ci * processed is zero.
9948c2ecf20Sopenharmony_ci *
9958c2ecf20Sopenharmony_ci * Return 'false' if the current number of wakeup events being processed is
9968c2ecf20Sopenharmony_ci * nonzero.  Otherwise return 'true'.
9978c2ecf20Sopenharmony_ci */
9988c2ecf20Sopenharmony_cibool pm_get_wakeup_count(unsigned int *count, bool block)
9998c2ecf20Sopenharmony_ci{
10008c2ecf20Sopenharmony_ci	unsigned int cnt, inpr;
10018c2ecf20Sopenharmony_ci
10028c2ecf20Sopenharmony_ci	if (block) {
10038c2ecf20Sopenharmony_ci		DEFINE_WAIT(wait);
10048c2ecf20Sopenharmony_ci
10058c2ecf20Sopenharmony_ci		for (;;) {
10068c2ecf20Sopenharmony_ci			prepare_to_wait(&wakeup_count_wait_queue, &wait,
10078c2ecf20Sopenharmony_ci					TASK_INTERRUPTIBLE);
10088c2ecf20Sopenharmony_ci			split_counters(&cnt, &inpr);
10098c2ecf20Sopenharmony_ci			if (inpr == 0 || signal_pending(current))
10108c2ecf20Sopenharmony_ci				break;
10118c2ecf20Sopenharmony_ci			pm_print_active_wakeup_sources();
10128c2ecf20Sopenharmony_ci			schedule();
10138c2ecf20Sopenharmony_ci		}
10148c2ecf20Sopenharmony_ci		finish_wait(&wakeup_count_wait_queue, &wait);
10158c2ecf20Sopenharmony_ci	}
10168c2ecf20Sopenharmony_ci
10178c2ecf20Sopenharmony_ci	split_counters(&cnt, &inpr);
10188c2ecf20Sopenharmony_ci	*count = cnt;
10198c2ecf20Sopenharmony_ci	return !inpr;
10208c2ecf20Sopenharmony_ci}
10218c2ecf20Sopenharmony_ci
10228c2ecf20Sopenharmony_ci/**
10238c2ecf20Sopenharmony_ci * pm_save_wakeup_count - Save the current number of registered wakeup events.
10248c2ecf20Sopenharmony_ci * @count: Value to compare with the current number of registered wakeup events.
10258c2ecf20Sopenharmony_ci *
10268c2ecf20Sopenharmony_ci * If @count is equal to the current number of registered wakeup events and the
10278c2ecf20Sopenharmony_ci * current number of wakeup events being processed is zero, store @count as the
10288c2ecf20Sopenharmony_ci * old number of registered wakeup events for pm_check_wakeup_events(), enable
10298c2ecf20Sopenharmony_ci * wakeup events detection and return 'true'.  Otherwise disable wakeup events
10308c2ecf20Sopenharmony_ci * detection and return 'false'.
10318c2ecf20Sopenharmony_ci */
10328c2ecf20Sopenharmony_cibool pm_save_wakeup_count(unsigned int count)
10338c2ecf20Sopenharmony_ci{
10348c2ecf20Sopenharmony_ci	unsigned int cnt, inpr;
10358c2ecf20Sopenharmony_ci	unsigned long flags;
10368c2ecf20Sopenharmony_ci
10378c2ecf20Sopenharmony_ci	events_check_enabled = false;
10388c2ecf20Sopenharmony_ci	raw_spin_lock_irqsave(&events_lock, flags);
10398c2ecf20Sopenharmony_ci	split_counters(&cnt, &inpr);
10408c2ecf20Sopenharmony_ci	if (cnt == count && inpr == 0) {
10418c2ecf20Sopenharmony_ci		saved_count = count;
10428c2ecf20Sopenharmony_ci		events_check_enabled = true;
10438c2ecf20Sopenharmony_ci	}
10448c2ecf20Sopenharmony_ci	raw_spin_unlock_irqrestore(&events_lock, flags);
10458c2ecf20Sopenharmony_ci	return events_check_enabled;
10468c2ecf20Sopenharmony_ci}
10478c2ecf20Sopenharmony_ci
10488c2ecf20Sopenharmony_ci#ifdef CONFIG_PM_AUTOSLEEP
10498c2ecf20Sopenharmony_ci/**
10508c2ecf20Sopenharmony_ci * pm_wakep_autosleep_enabled - Modify autosleep_enabled for all wakeup sources.
10518c2ecf20Sopenharmony_ci * @enabled: Whether to set or to clear the autosleep_enabled flags.
10528c2ecf20Sopenharmony_ci */
10538c2ecf20Sopenharmony_civoid pm_wakep_autosleep_enabled(bool set)
10548c2ecf20Sopenharmony_ci{
10558c2ecf20Sopenharmony_ci	struct wakeup_source *ws;
10568c2ecf20Sopenharmony_ci	ktime_t now = ktime_get();
10578c2ecf20Sopenharmony_ci	int srcuidx;
10588c2ecf20Sopenharmony_ci
10598c2ecf20Sopenharmony_ci	srcuidx = srcu_read_lock(&wakeup_srcu);
10608c2ecf20Sopenharmony_ci	list_for_each_entry_rcu_locked(ws, &wakeup_sources, entry) {
10618c2ecf20Sopenharmony_ci		spin_lock_irq(&ws->lock);
10628c2ecf20Sopenharmony_ci		if (ws->autosleep_enabled != set) {
10638c2ecf20Sopenharmony_ci			ws->autosleep_enabled = set;
10648c2ecf20Sopenharmony_ci			if (ws->active) {
10658c2ecf20Sopenharmony_ci				if (set)
10668c2ecf20Sopenharmony_ci					ws->start_prevent_time = now;
10678c2ecf20Sopenharmony_ci				else
10688c2ecf20Sopenharmony_ci					update_prevent_sleep_time(ws, now);
10698c2ecf20Sopenharmony_ci			}
10708c2ecf20Sopenharmony_ci		}
10718c2ecf20Sopenharmony_ci		spin_unlock_irq(&ws->lock);
10728c2ecf20Sopenharmony_ci	}
10738c2ecf20Sopenharmony_ci	srcu_read_unlock(&wakeup_srcu, srcuidx);
10748c2ecf20Sopenharmony_ci}
10758c2ecf20Sopenharmony_ci#endif /* CONFIG_PM_AUTOSLEEP */
10768c2ecf20Sopenharmony_ci
10778c2ecf20Sopenharmony_ci/**
10788c2ecf20Sopenharmony_ci * print_wakeup_source_stats - Print wakeup source statistics information.
10798c2ecf20Sopenharmony_ci * @m: seq_file to print the statistics into.
10808c2ecf20Sopenharmony_ci * @ws: Wakeup source object to print the statistics for.
10818c2ecf20Sopenharmony_ci */
10828c2ecf20Sopenharmony_cistatic int print_wakeup_source_stats(struct seq_file *m,
10838c2ecf20Sopenharmony_ci				     struct wakeup_source *ws)
10848c2ecf20Sopenharmony_ci{
10858c2ecf20Sopenharmony_ci	unsigned long flags;
10868c2ecf20Sopenharmony_ci	ktime_t total_time;
10878c2ecf20Sopenharmony_ci	ktime_t max_time;
10888c2ecf20Sopenharmony_ci	unsigned long active_count;
10898c2ecf20Sopenharmony_ci	ktime_t active_time;
10908c2ecf20Sopenharmony_ci	ktime_t prevent_sleep_time;
10918c2ecf20Sopenharmony_ci
10928c2ecf20Sopenharmony_ci	spin_lock_irqsave(&ws->lock, flags);
10938c2ecf20Sopenharmony_ci
10948c2ecf20Sopenharmony_ci	total_time = ws->total_time;
10958c2ecf20Sopenharmony_ci	max_time = ws->max_time;
10968c2ecf20Sopenharmony_ci	prevent_sleep_time = ws->prevent_sleep_time;
10978c2ecf20Sopenharmony_ci	active_count = ws->active_count;
10988c2ecf20Sopenharmony_ci	if (ws->active) {
10998c2ecf20Sopenharmony_ci		ktime_t now = ktime_get();
11008c2ecf20Sopenharmony_ci
11018c2ecf20Sopenharmony_ci		active_time = ktime_sub(now, ws->last_time);
11028c2ecf20Sopenharmony_ci		total_time = ktime_add(total_time, active_time);
11038c2ecf20Sopenharmony_ci		if (active_time > max_time)
11048c2ecf20Sopenharmony_ci			max_time = active_time;
11058c2ecf20Sopenharmony_ci
11068c2ecf20Sopenharmony_ci		if (ws->autosleep_enabled)
11078c2ecf20Sopenharmony_ci			prevent_sleep_time = ktime_add(prevent_sleep_time,
11088c2ecf20Sopenharmony_ci				ktime_sub(now, ws->start_prevent_time));
11098c2ecf20Sopenharmony_ci	} else {
11108c2ecf20Sopenharmony_ci		active_time = 0;
11118c2ecf20Sopenharmony_ci	}
11128c2ecf20Sopenharmony_ci
11138c2ecf20Sopenharmony_ci	seq_printf(m, "%-12s\t%lu\t\t%lu\t\t%lu\t\t%lu\t\t%lld\t\t%lld\t\t%lld\t\t%lld\t\t%lld\n",
11148c2ecf20Sopenharmony_ci		   ws->name, active_count, ws->event_count,
11158c2ecf20Sopenharmony_ci		   ws->wakeup_count, ws->expire_count,
11168c2ecf20Sopenharmony_ci		   ktime_to_ms(active_time), ktime_to_ms(total_time),
11178c2ecf20Sopenharmony_ci		   ktime_to_ms(max_time), ktime_to_ms(ws->last_time),
11188c2ecf20Sopenharmony_ci		   ktime_to_ms(prevent_sleep_time));
11198c2ecf20Sopenharmony_ci
11208c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&ws->lock, flags);
11218c2ecf20Sopenharmony_ci
11228c2ecf20Sopenharmony_ci	return 0;
11238c2ecf20Sopenharmony_ci}
11248c2ecf20Sopenharmony_ci
11258c2ecf20Sopenharmony_cistatic void *wakeup_sources_stats_seq_start(struct seq_file *m,
11268c2ecf20Sopenharmony_ci					loff_t *pos)
11278c2ecf20Sopenharmony_ci{
11288c2ecf20Sopenharmony_ci	struct wakeup_source *ws;
11298c2ecf20Sopenharmony_ci	loff_t n = *pos;
11308c2ecf20Sopenharmony_ci	int *srcuidx = m->private;
11318c2ecf20Sopenharmony_ci
11328c2ecf20Sopenharmony_ci	if (n == 0) {
11338c2ecf20Sopenharmony_ci		seq_puts(m, "name\t\tactive_count\tevent_count\twakeup_count\t"
11348c2ecf20Sopenharmony_ci			"expire_count\tactive_since\ttotal_time\tmax_time\t"
11358c2ecf20Sopenharmony_ci			"last_change\tprevent_suspend_time\n");
11368c2ecf20Sopenharmony_ci	}
11378c2ecf20Sopenharmony_ci
11388c2ecf20Sopenharmony_ci	*srcuidx = srcu_read_lock(&wakeup_srcu);
11398c2ecf20Sopenharmony_ci	list_for_each_entry_rcu_locked(ws, &wakeup_sources, entry) {
11408c2ecf20Sopenharmony_ci		if (n-- <= 0)
11418c2ecf20Sopenharmony_ci			return ws;
11428c2ecf20Sopenharmony_ci	}
11438c2ecf20Sopenharmony_ci
11448c2ecf20Sopenharmony_ci	return NULL;
11458c2ecf20Sopenharmony_ci}
11468c2ecf20Sopenharmony_ci
11478c2ecf20Sopenharmony_cistatic void *wakeup_sources_stats_seq_next(struct seq_file *m,
11488c2ecf20Sopenharmony_ci					void *v, loff_t *pos)
11498c2ecf20Sopenharmony_ci{
11508c2ecf20Sopenharmony_ci	struct wakeup_source *ws = v;
11518c2ecf20Sopenharmony_ci	struct wakeup_source *next_ws = NULL;
11528c2ecf20Sopenharmony_ci
11538c2ecf20Sopenharmony_ci	++(*pos);
11548c2ecf20Sopenharmony_ci
11558c2ecf20Sopenharmony_ci	list_for_each_entry_continue_rcu(ws, &wakeup_sources, entry) {
11568c2ecf20Sopenharmony_ci		next_ws = ws;
11578c2ecf20Sopenharmony_ci		break;
11588c2ecf20Sopenharmony_ci	}
11598c2ecf20Sopenharmony_ci
11608c2ecf20Sopenharmony_ci	if (!next_ws)
11618c2ecf20Sopenharmony_ci		print_wakeup_source_stats(m, &deleted_ws);
11628c2ecf20Sopenharmony_ci
11638c2ecf20Sopenharmony_ci	return next_ws;
11648c2ecf20Sopenharmony_ci}
11658c2ecf20Sopenharmony_ci
11668c2ecf20Sopenharmony_cistatic void wakeup_sources_stats_seq_stop(struct seq_file *m, void *v)
11678c2ecf20Sopenharmony_ci{
11688c2ecf20Sopenharmony_ci	int *srcuidx = m->private;
11698c2ecf20Sopenharmony_ci
11708c2ecf20Sopenharmony_ci	srcu_read_unlock(&wakeup_srcu, *srcuidx);
11718c2ecf20Sopenharmony_ci}
11728c2ecf20Sopenharmony_ci
11738c2ecf20Sopenharmony_ci/**
11748c2ecf20Sopenharmony_ci * wakeup_sources_stats_seq_show - Print wakeup sources statistics information.
11758c2ecf20Sopenharmony_ci * @m: seq_file to print the statistics into.
11768c2ecf20Sopenharmony_ci * @v: wakeup_source of each iteration
11778c2ecf20Sopenharmony_ci */
11788c2ecf20Sopenharmony_cistatic int wakeup_sources_stats_seq_show(struct seq_file *m, void *v)
11798c2ecf20Sopenharmony_ci{
11808c2ecf20Sopenharmony_ci	struct wakeup_source *ws = v;
11818c2ecf20Sopenharmony_ci
11828c2ecf20Sopenharmony_ci	print_wakeup_source_stats(m, ws);
11838c2ecf20Sopenharmony_ci
11848c2ecf20Sopenharmony_ci	return 0;
11858c2ecf20Sopenharmony_ci}
11868c2ecf20Sopenharmony_ci
11878c2ecf20Sopenharmony_cistatic const struct seq_operations wakeup_sources_stats_seq_ops = {
11888c2ecf20Sopenharmony_ci	.start = wakeup_sources_stats_seq_start,
11898c2ecf20Sopenharmony_ci	.next  = wakeup_sources_stats_seq_next,
11908c2ecf20Sopenharmony_ci	.stop  = wakeup_sources_stats_seq_stop,
11918c2ecf20Sopenharmony_ci	.show  = wakeup_sources_stats_seq_show,
11928c2ecf20Sopenharmony_ci};
11938c2ecf20Sopenharmony_ci
11948c2ecf20Sopenharmony_cistatic int wakeup_sources_stats_open(struct inode *inode, struct file *file)
11958c2ecf20Sopenharmony_ci{
11968c2ecf20Sopenharmony_ci	return seq_open_private(file, &wakeup_sources_stats_seq_ops, sizeof(int));
11978c2ecf20Sopenharmony_ci}
11988c2ecf20Sopenharmony_ci
11998c2ecf20Sopenharmony_cistatic const struct file_operations wakeup_sources_stats_fops = {
12008c2ecf20Sopenharmony_ci	.owner = THIS_MODULE,
12018c2ecf20Sopenharmony_ci	.open = wakeup_sources_stats_open,
12028c2ecf20Sopenharmony_ci	.read = seq_read,
12038c2ecf20Sopenharmony_ci	.llseek = seq_lseek,
12048c2ecf20Sopenharmony_ci	.release = seq_release_private,
12058c2ecf20Sopenharmony_ci};
12068c2ecf20Sopenharmony_ci
12078c2ecf20Sopenharmony_cistatic int __init wakeup_sources_debugfs_init(void)
12088c2ecf20Sopenharmony_ci{
12098c2ecf20Sopenharmony_ci	debugfs_create_file("wakeup_sources", S_IRUGO, NULL, NULL,
12108c2ecf20Sopenharmony_ci			    &wakeup_sources_stats_fops);
12118c2ecf20Sopenharmony_ci	return 0;
12128c2ecf20Sopenharmony_ci}
12138c2ecf20Sopenharmony_ci
12148c2ecf20Sopenharmony_cipostcore_initcall(wakeup_sources_debugfs_init);
1215