Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/drivers/base/syscore.c
49051 views
1
// SPDX-License-Identifier: GPL-2.0
2
/*
3
* syscore.c - Execution of system core operations.
4
*
5
* Copyright (C) 2011 Rafael J. Wysocki <[email protected]>, Novell Inc.
6
*/
7
8
#include <linux/syscore_ops.h>
9
#include <linux/mutex.h>
10
#include <linux/module.h>
11
#include <linux/suspend.h>
12
#include <trace/events/power.h>
13
14
static LIST_HEAD(syscore_list);
15
static DEFINE_MUTEX(syscore_lock);
16
17
/**
18
* register_syscore - Register a set of system core operations.
19
* @syscore: System core operations to register.
20
*/
21
void register_syscore(struct syscore *syscore)
22
{
23
mutex_lock(&syscore_lock);
24
list_add_tail(&syscore->node, &syscore_list);
25
mutex_unlock(&syscore_lock);
26
}
27
EXPORT_SYMBOL_GPL(register_syscore);
28
29
/**
30
* unregister_syscore - Unregister a set of system core operations.
31
* @syscore: System core operations to unregister.
32
*/
33
void unregister_syscore(struct syscore *syscore)
34
{
35
mutex_lock(&syscore_lock);
36
list_del(&syscore->node);
37
mutex_unlock(&syscore_lock);
38
}
39
EXPORT_SYMBOL_GPL(unregister_syscore);
40
41
#ifdef CONFIG_PM_SLEEP
42
/**
43
* syscore_suspend - Execute all the registered system core suspend callbacks.
44
*
45
* This function is executed with one CPU on-line and disabled interrupts.
46
*/
47
int syscore_suspend(void)
48
{
49
struct syscore *syscore;
50
int ret = 0;
51
52
trace_suspend_resume(TPS("syscore_suspend"), 0, true);
53
pm_pr_dbg("Checking wakeup interrupts\n");
54
55
/* Return error code if there are any wakeup interrupts pending. */
56
if (pm_wakeup_pending())
57
return -EBUSY;
58
59
WARN_ONCE(!irqs_disabled(),
60
"Interrupts enabled before system core suspend.\n");
61
62
list_for_each_entry_reverse(syscore, &syscore_list, node)
63
if (syscore->ops->suspend) {
64
pm_pr_dbg("Calling %pS\n", syscore->ops->suspend);
65
ret = syscore->ops->suspend(syscore->data);
66
if (ret)
67
goto err_out;
68
WARN_ONCE(!irqs_disabled(),
69
"Interrupts enabled after %pS\n",
70
syscore->ops->suspend);
71
}
72
73
trace_suspend_resume(TPS("syscore_suspend"), 0, false);
74
return 0;
75
76
err_out:
77
pr_err("PM: System core suspend callback %pS failed.\n",
78
syscore->ops->suspend);
79
80
list_for_each_entry_continue(syscore, &syscore_list, node)
81
if (syscore->ops->resume)
82
syscore->ops->resume(syscore->data);
83
84
return ret;
85
}
86
EXPORT_SYMBOL_GPL(syscore_suspend);
87
88
/**
89
* syscore_resume - Execute all the registered system core resume callbacks.
90
*
91
* This function is executed with one CPU on-line and disabled interrupts.
92
*/
93
void syscore_resume(void)
94
{
95
struct syscore *syscore;
96
97
trace_suspend_resume(TPS("syscore_resume"), 0, true);
98
WARN_ONCE(!irqs_disabled(),
99
"Interrupts enabled before system core resume.\n");
100
101
list_for_each_entry(syscore, &syscore_list, node)
102
if (syscore->ops->resume) {
103
pm_pr_dbg("Calling %pS\n", syscore->ops->resume);
104
syscore->ops->resume(syscore->data);
105
WARN_ONCE(!irqs_disabled(),
106
"Interrupts enabled after %pS\n",
107
syscore->ops->resume);
108
}
109
trace_suspend_resume(TPS("syscore_resume"), 0, false);
110
}
111
EXPORT_SYMBOL_GPL(syscore_resume);
112
#endif /* CONFIG_PM_SLEEP */
113
114
/**
115
* syscore_shutdown - Execute all the registered system core shutdown callbacks.
116
*/
117
void syscore_shutdown(void)
118
{
119
struct syscore *syscore;
120
121
mutex_lock(&syscore_lock);
122
123
list_for_each_entry_reverse(syscore, &syscore_list, node)
124
if (syscore->ops->shutdown) {
125
if (initcall_debug)
126
pr_info("PM: Calling %pS\n",
127
syscore->ops->shutdown);
128
syscore->ops->shutdown(syscore->data);
129
}
130
131
mutex_unlock(&syscore_lock);
132
}
133
134