diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig index d039126411beb..6c4d8619c4e1b 100644 --- a/drivers/irqchip/Kconfig +++ b/drivers/irqchip/Kconfig @@ -37,6 +37,7 @@ config ARM_GIC_V3 select IRQ_DOMAIN_HIERARCHY select PARTITION_PERCPU select GENERIC_IRQ_EFFECTIVE_AFF_MASK + select QGKI_SHOW_S2IDLE_WAKE_IRQ if QGKI config ARM_GIC_V3_ITS bool @@ -516,4 +517,11 @@ config SIFIVE_PLIC If you don't know what to do here, say Y. +config QGKI_SHOW_S2IDLE_WAKE_IRQ + bool "Qualcomm Technologies, Inc. (QTI) SHOW S2IDLE WAKE IRQ" + depends on ARM_GIC_V3 + help + When this option is selected, first cpu waking up from s2idle + prints the interrupts pending and enabled at GIC. + endmenu diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c index dcaa003b9417e..19ddb4c52bd6c 100644 --- a/drivers/irqchip/irq-gic-v3.c +++ b/drivers/irqchip/irq-gic-v3.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include @@ -1244,6 +1245,13 @@ static int gic_set_affinity(struct irq_data *d, const struct cpumask *mask_val, #define gic_smp_init() do { } while(0) #endif +#ifdef CONFIG_QGKI_SHOW_S2IDLE_WAKE_IRQ +void gic_s2idle_wake(void) +{ + gic_resume_one(&gic_data); +} +#endif /* CONFIG_QGKI_SHOW_S2IDLE_WAKE_IRQ */ + #ifdef CONFIG_CPU_PM static int gic_cpu_pm_notifier(struct notifier_block *self, unsigned long cmd, void *v) diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h index 5cc10cf7cb3e6..2f349fb5f1965 100644 --- a/include/linux/irqchip/arm-gic-v3.h +++ b/include/linux/irqchip/arm-gic-v3.h @@ -638,6 +638,10 @@ static inline bool gic_enable_sre(void) return !!(val & ICC_SRE_EL1_SRE); } +#ifdef CONFIG_QGKI_SHOW_S2IDLE_WAKE_IRQ +void gic_s2idle_wake(void); +#endif /* CONFIG_QGKI_SHOW_S2IDLE_WAKE_IRQ */ + #endif #endif diff --git a/kernel/sched/idle.c b/kernel/sched/idle.c index 251a7df055d6b..93b3195bfd971 100644 --- a/kernel/sched/idle.c +++ b/kernel/sched/idle.c @@ -8,6 +8,9 @@ */ #include "sched.h" +#ifdef CONFIG_QGKI_SHOW_S2IDLE_WAKE_IRQ +#include +#endif /* CONFIG_QGKI_SHOW_S2IDLE_WAKE_IRQ */ #include /* Linker adds these: start and end of __cpuidle functions */ @@ -128,6 +131,11 @@ static int call_cpuidle(struct cpuidle_driver *drv, struct cpuidle_device *dev, * set, and it returns with polling set. If it ever stops polling, it * must clear the polling bit. */ + +#ifdef CONFIG_QGKI_SHOW_S2IDLE_WAKE_IRQ +static cpumask_t cpu_state; +#endif /* CONFIG_QGKI_SHOW_S2IDLE_WAKE_IRQ */ + static void cpuidle_idle_call(void) { struct cpuidle_device *dev = cpuidle_get_device(); @@ -169,9 +177,26 @@ static void cpuidle_idle_call(void) if (idle_should_enter_s2idle() || dev->use_deepest_state) { if (idle_should_enter_s2idle()) { + +#ifdef CONFIG_QGKI_SHOW_S2IDLE_WAKE_IRQ + bool print_wake_irq; + + cpumask_set_cpu(dev->cpu, &cpu_state); +#endif /* CONFIG_QGKI_SHOW_S2IDLE_WAKE_IRQ */ + rcu_idle_enter(); entered_state = cpuidle_enter_s2idle(drv, dev); + +#ifdef CONFIG_QGKI_SHOW_S2IDLE_WAKE_IRQ + print_wake_irq = cpumask_weight(&cpu_state) == + cpumask_weight(cpu_online_mask) ? + true : false; + cpumask_clear_cpu(dev->cpu, &cpu_state); + if (print_wake_irq) + gic_s2idle_wake(); +#endif /* CONFIG_QGKI_SHOW_S2IDLE_WAKE_IRQ */ + if (entered_state > 0) { local_irq_enable(); goto exit_idle;