/* * include/linux/wakeup_reason.h * * Logs the reason which caused the kernel to resume * from the suspend mode. * * Copyright (C) 2014 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_WAKEUP_REASON_H #define _LINUX_WAKEUP_REASON_H #include #include #define MAX_SUSPEND_ABORT_LEN 256 struct wakeup_irq_node { /* @leaf is a linked list of all leaf nodes in the interrupts trees. */ struct list_head next; /* @irq: IRQ number of this node. */ int irq; struct irq_desc *desc; /* @siblings contains the list of irq nodes at the same depth; at a * depth of zero, this is the list of base wakeup interrupts. */ struct list_head siblings; /* @parent: only one node in a siblings list has a pointer to the * parent; that node is the head of the list of siblings. */ struct wakeup_irq_node *parent; /* @child: any node can have one child */ struct wakeup_irq_node *child; /* @handled: this flag is set to true when the interrupt handler (one of * handle_.*_irq in kernel/irq/handle.c) for this node gets called; it is set * to false otherwise. We use this flag to determine whether a subtree rooted * at a node has been handled. When all trees rooted at * base-wakeup-interrupt nodes have been handled, we stop logging * potential wakeup interrupts, and construct the list of actual * wakeups from the leaves of these trees. */ bool handled; }; #ifdef CONFIG_DEDUCE_WAKEUP_REASONS /* Called in the resume path, with interrupts and nonboot cpus disabled; on * need for a spinlock. */ static inline void start_logging_wakeup_reasons(void) { extern bool log_wakeups; extern struct completion wakeups_completion; ACCESS_ONCE(log_wakeups) = true; init_completion(&wakeups_completion); } static inline bool logging_wakeup_reasons_nosync(void) { extern bool log_wakeups; return ACCESS_ONCE(log_wakeups); } static inline bool logging_wakeup_reasons(void) { smp_rmb(); return logging_wakeup_reasons_nosync(); } bool log_possible_wakeup_reason(int irq, struct irq_desc *desc, bool (*handler)(unsigned int, struct irq_desc *)); #else static inline void start_logging_wakeup_reasons(void) {} static inline bool logging_wakeup_reasons_nosync(void) { return false; } static inline bool logging_wakeup_reasons(void) { return false; } static inline bool log_possible_wakeup_reason(int irq, struct irq_desc *desc, bool (*handler)(unsigned int, struct irq_desc *)) { return true; } #endif const struct list_head* get_wakeup_reasons(unsigned long timeout, struct list_head *unfinished); void log_base_wakeup_reason(int irq); void clear_wakeup_reasons(void); void log_suspend_abort_reason(const char *fmt, ...); int check_wakeup_reason(int irq); #endif /* _LINUX_WAKEUP_REASON_H */