Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  *  syscore.c - Execution of system core operations.
0004  *
0005  *  Copyright (C) 2011 Rafael J. Wysocki <rjw@sisk.pl>, Novell Inc.
0006  */
0007 
0008 #include <linux/syscore_ops.h>
0009 #include <linux/mutex.h>
0010 #include <linux/module.h>
0011 #include <linux/suspend.h>
0012 #include <trace/events/power.h>
0013 
0014 static LIST_HEAD(syscore_ops_list);
0015 static DEFINE_MUTEX(syscore_ops_lock);
0016 
0017 /**
0018  * register_syscore_ops - Register a set of system core operations.
0019  * @ops: System core operations to register.
0020  */
0021 void register_syscore_ops(struct syscore_ops *ops)
0022 {
0023     mutex_lock(&syscore_ops_lock);
0024     list_add_tail(&ops->node, &syscore_ops_list);
0025     mutex_unlock(&syscore_ops_lock);
0026 }
0027 EXPORT_SYMBOL_GPL(register_syscore_ops);
0028 
0029 /**
0030  * unregister_syscore_ops - Unregister a set of system core operations.
0031  * @ops: System core operations to unregister.
0032  */
0033 void unregister_syscore_ops(struct syscore_ops *ops)
0034 {
0035     mutex_lock(&syscore_ops_lock);
0036     list_del(&ops->node);
0037     mutex_unlock(&syscore_ops_lock);
0038 }
0039 EXPORT_SYMBOL_GPL(unregister_syscore_ops);
0040 
0041 #ifdef CONFIG_PM_SLEEP
0042 /**
0043  * syscore_suspend - Execute all the registered system core suspend callbacks.
0044  *
0045  * This function is executed with one CPU on-line and disabled interrupts.
0046  */
0047 int syscore_suspend(void)
0048 {
0049     struct syscore_ops *ops;
0050     int ret = 0;
0051 
0052     trace_suspend_resume(TPS("syscore_suspend"), 0, true);
0053     pm_pr_dbg("Checking wakeup interrupts\n");
0054 
0055     /* Return error code if there are any wakeup interrupts pending. */
0056     if (pm_wakeup_pending())
0057         return -EBUSY;
0058 
0059     WARN_ONCE(!irqs_disabled(),
0060         "Interrupts enabled before system core suspend.\n");
0061 
0062     list_for_each_entry_reverse(ops, &syscore_ops_list, node)
0063         if (ops->suspend) {
0064             pm_pr_dbg("Calling %pS\n", ops->suspend);
0065             ret = ops->suspend();
0066             if (ret)
0067                 goto err_out;
0068             WARN_ONCE(!irqs_disabled(),
0069                 "Interrupts enabled after %pS\n", ops->suspend);
0070         }
0071 
0072     trace_suspend_resume(TPS("syscore_suspend"), 0, false);
0073     return 0;
0074 
0075  err_out:
0076     pr_err("PM: System core suspend callback %pS failed.\n", ops->suspend);
0077 
0078     list_for_each_entry_continue(ops, &syscore_ops_list, node)
0079         if (ops->resume)
0080             ops->resume();
0081 
0082     return ret;
0083 }
0084 EXPORT_SYMBOL_GPL(syscore_suspend);
0085 
0086 /**
0087  * syscore_resume - Execute all the registered system core resume callbacks.
0088  *
0089  * This function is executed with one CPU on-line and disabled interrupts.
0090  */
0091 void syscore_resume(void)
0092 {
0093     struct syscore_ops *ops;
0094 
0095     trace_suspend_resume(TPS("syscore_resume"), 0, true);
0096     WARN_ONCE(!irqs_disabled(),
0097         "Interrupts enabled before system core resume.\n");
0098 
0099     list_for_each_entry(ops, &syscore_ops_list, node)
0100         if (ops->resume) {
0101             pm_pr_dbg("Calling %pS\n", ops->resume);
0102             ops->resume();
0103             WARN_ONCE(!irqs_disabled(),
0104                 "Interrupts enabled after %pS\n", ops->resume);
0105         }
0106     trace_suspend_resume(TPS("syscore_resume"), 0, false);
0107 }
0108 EXPORT_SYMBOL_GPL(syscore_resume);
0109 #endif /* CONFIG_PM_SLEEP */
0110 
0111 /**
0112  * syscore_shutdown - Execute all the registered system core shutdown callbacks.
0113  */
0114 void syscore_shutdown(void)
0115 {
0116     struct syscore_ops *ops;
0117 
0118     mutex_lock(&syscore_ops_lock);
0119 
0120     list_for_each_entry_reverse(ops, &syscore_ops_list, node)
0121         if (ops->shutdown) {
0122             if (initcall_debug)
0123                 pr_info("PM: Calling %pS\n", ops->shutdown);
0124             ops->shutdown();
0125         }
0126 
0127     mutex_unlock(&syscore_ops_lock);
0128 }