blob: b5ab51008e95f5a54b252633e09eefe046f85c6f [file] [log] [blame]
/*
* 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 <linux/types.h>
#include <linux/completion.h>
#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 */