summaryrefslogtreecommitdiff
path: root/include/linux/wakeup_reason.h
blob: a015ce5c830f24b588ad4d1cd7e00e2e17f78b09 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
/*
 * 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)(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)(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 */