summaryrefslogtreecommitdiff
path: root/include/linux
diff options
context:
space:
mode:
authorIliyan Malchev <malchev@google.com>2015-02-20 11:01:24 -0800
committerMichael Bestas <mkbestas@lineageos.org>2019-12-23 23:43:34 +0200
commit6edd3f1417d82add8c98d292ba39912b830c3d80 (patch)
tree7c030a7289a70a8b8e845b2925105cd0e082d3f3 /include/linux
parent2402e1b97f9333cdd985f14810ae764ba7335342 (diff)
BACKPORT: PM: wakeup_reason: add functions to query and clear wakeup reasons
The query results are valid until the next PM_SUSPEND_PREPARE. (cherry picked from commit 76543de14f860ab713114621cb62e8006b7ca952) Change-Id: I6bc2bd47c830262319576a001d39ac9a994916cf Signed-off-by: Iliyan Malchev <malchev@google.com>
Diffstat (limited to 'include/linux')
-rw-r--r--include/linux/irq.h18
-rw-r--r--include/linux/irqdesc.h4
-rw-r--r--include/linux/irqhandler.h2
-rw-r--r--include/linux/wakeup_reason.h69
4 files changed, 75 insertions, 18 deletions
diff --git a/include/linux/irq.h b/include/linux/irq.h
index f653225a896d..8da001eb82aa 100644
--- a/include/linux/irq.h
+++ b/include/linux/irq.h
@@ -473,15 +473,15 @@ static inline int irq_set_parent(int irq, int parent_irq)
* Built-in IRQ handlers for various IRQ types,
* callable via desc->handle_irq()
*/
-extern void handle_level_irq(struct irq_desc *desc);
-extern void handle_fasteoi_irq(struct irq_desc *desc);
-extern void handle_edge_irq(struct irq_desc *desc);
-extern void handle_edge_eoi_irq(struct irq_desc *desc);
-extern void handle_simple_irq(struct irq_desc *desc);
-extern void handle_percpu_irq(struct irq_desc *desc);
-extern void handle_percpu_devid_irq(struct irq_desc *desc);
-extern void handle_bad_irq(struct irq_desc *desc);
-extern void handle_nested_irq(unsigned int irq);
+extern bool handle_level_irq(struct irq_desc *desc);
+extern bool handle_fasteoi_irq(struct irq_desc *desc);
+extern bool handle_edge_irq(struct irq_desc *desc);
+extern bool handle_edge_eoi_irq(struct irq_desc *desc);
+extern bool handle_simple_irq(struct irq_desc *desc);
+extern bool handle_percpu_irq(struct irq_desc *desc);
+extern bool handle_percpu_devid_irq(struct irq_desc *desc);
+extern bool handle_bad_irq(struct irq_desc *desc);
+extern bool handle_nested_irq(unsigned int irq);
extern int irq_chip_compose_msi_msg(struct irq_data *data, struct msi_msg *msg);
#ifdef CONFIG_IRQ_DOMAIN_HIERARCHY
diff --git a/include/linux/irqdesc.h b/include/linux/irqdesc.h
index a587a33363c7..50b55bdfe0bd 100644
--- a/include/linux/irqdesc.h
+++ b/include/linux/irqdesc.h
@@ -135,9 +135,9 @@ static inline struct msi_desc *irq_desc_get_msi_desc(struct irq_desc *desc)
* Architectures call this to let the generic IRQ layer
* handle an interrupt.
*/
-static inline void generic_handle_irq_desc(struct irq_desc *desc)
+static inline bool generic_handle_irq_desc(struct irq_desc *desc)
{
- desc->handle_irq(desc);
+ return desc->handle_irq(desc);
}
int generic_handle_irq(unsigned int irq);
diff --git a/include/linux/irqhandler.h b/include/linux/irqhandler.h
index 661bed0ed1f3..b31ab4b59c16 100644
--- a/include/linux/irqhandler.h
+++ b/include/linux/irqhandler.h
@@ -8,7 +8,7 @@
struct irq_desc;
struct irq_data;
-typedef void (*irq_flow_handler_t)(struct irq_desc *desc);
+typedef bool (*irq_flow_handler_t)(struct irq_desc *desc);
typedef void (*irq_preflow_handler_t)(struct irq_data *data);
#endif
diff --git a/include/linux/wakeup_reason.h b/include/linux/wakeup_reason.h
index d84d8c301546..a26b1c998139 100644
--- a/include/linux/wakeup_reason.h
+++ b/include/linux/wakeup_reason.h
@@ -18,15 +18,72 @@
#ifndef _LINUX_WAKEUP_REASON_H
#define _LINUX_WAKEUP_REASON_H
+#include <linux/types.h>
+#include <linux/completion.h>
+
#define MAX_SUSPEND_ABORT_LEN 256
-void log_wakeup_reason(int irq);
-int check_wakeup_reason(int irq);
+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;
+};
+
+/* 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;
+ log_wakeups = true;
+ init_completion(&wakeups_completion);
+}
+
+static inline bool logging_wakeup_reasons(void)
+{
+ extern bool log_wakeups;
+ return ACCESS_ONCE(log_wakeups);
+}
+
+void log_base_wakeup_reason(int irq);
-#ifdef CONFIG_SUSPEND
void log_suspend_abort_reason(const char *fmt, ...);
-#else
-static inline void log_suspend_abort_reason(const char *fmt, ...) { }
-#endif
+
+bool log_possible_wakeup_reason(int irq,
+ struct irq_desc *desc,
+ bool (*handler)(struct irq_desc *));
+
+int check_wakeup_reason(int irq);
+
+const struct list_head*
+get_wakeup_reasons(unsigned long timeout, struct list_head *unfinished);
+
+void clear_wakeup_reasons(void);
#endif /* _LINUX_WAKEUP_REASON_H */