diff options
| author | Iliyan Malchev <malchev@google.com> | 2015-02-20 11:01:24 -0800 |
|---|---|---|
| committer | Michael Bestas <mkbestas@lineageos.org> | 2019-12-23 23:43:34 +0200 |
| commit | 6edd3f1417d82add8c98d292ba39912b830c3d80 (patch) | |
| tree | 7c030a7289a70a8b8e845b2925105cd0e082d3f3 /include/linux | |
| parent | 2402e1b97f9333cdd985f14810ae764ba7335342 (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.h | 18 | ||||
| -rw-r--r-- | include/linux/irqdesc.h | 4 | ||||
| -rw-r--r-- | include/linux/irqhandler.h | 2 | ||||
| -rw-r--r-- | include/linux/wakeup_reason.h | 69 |
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 */ |
