From e4ace486b10ae0ec8bcd5df404a7c382d5533fef Mon Sep 17 00:00:00 2001 From: Rashid Zafar Date: Wed, 12 Oct 2022 13:12:35 -0700 Subject: [PATCH] drivers: irqchip: Add snapshot of msm_show_resume_irq Add a snapshot of the show resume IRQ driver from msm-5.15 'commit 12ba2ebcde0b ("irqchip: add snapshot of msm_show_resume_irq")'. Updates: - Remove upstream dependency with irq-gic-v3.c where it registers for syscore ops and handle on our side instead - Get GICD base address per device and print HW IRQ when resuming from suspend. - Change GPL v2 license to GPL Change-Id: I4c0ffd433e995305459f37cad24b9cbf8b8c4ee0 Signed-off-by: Rashid Zafar --- drivers/irqchip/Kconfig | 10 +++ drivers/irqchip/Makefile | 1 + drivers/irqchip/msm_show_resume_irq.c | 122 ++++++++++++++++++++++++++ 3 files changed, 133 insertions(+) create mode 100644 drivers/irqchip/msm_show_resume_irq.c diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig index 66b9fa408bf2..6bd604534235 100644 --- a/drivers/irqchip/Kconfig +++ b/drivers/irqchip/Kconfig @@ -440,6 +440,16 @@ config QCOM_PDC Power Domain Controller driver to manage and configure wakeup IRQs for Qualcomm Technologies Inc (QTI) mobile chips. +config QCOM_SHOW_RESUME_IRQ + tristate "Enable logging of interrupts that could have caused resume" + depends on PM + depends on ARM_GIC_V2 || ARM_GIC_V3 + help + This option logs wake up interrupts that have triggered just before + the resume loop unrolls. It helps to debug to know any unnecessary + wake up interrupts that causes system to come out of low power modes. + Say Y if you want to debug why the system resumed. + config QCOM_MPM tristate "QCOM MPM" depends on ARCH_QCOM diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile index b6acbca2248b..e344e0a3eae3 100644 --- a/drivers/irqchip/Makefile +++ b/drivers/irqchip/Makefile @@ -120,3 +120,4 @@ obj-$(CONFIG_IRQ_IDT3243X) += irq-idt3243x.o obj-$(CONFIG_APPLE_AIC) += irq-apple-aic.o obj-$(CONFIG_MCHP_EIC) += irq-mchp-eic.o obj-$(CONFIG_SUNPLUS_SP7021_INTC) += irq-sp7021-intc.o +obj-$(CONFIG_QCOM_SHOW_RESUME_IRQ) += msm_show_resume_irq.o diff --git a/drivers/irqchip/msm_show_resume_irq.c b/drivers/irqchip/msm_show_resume_irq.c new file mode 100644 index 000000000000..2417a84438e1 --- /dev/null +++ b/drivers/irqchip/msm_show_resume_irq.c @@ -0,0 +1,122 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2011, 2014-2016, 2018, 2020-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static void __iomem *base; +static int msm_show_resume_irq_mask; +module_param_named(debug_mask, msm_show_resume_irq_mask, int, 0664); + +static void msm_show_resume_irqs(void) +{ + unsigned int i; + u32 enabled; + u32 pending[32]; + u32 gic_line_nr; + u32 typer; + + if (!msm_show_resume_irq_mask) + return; + + typer = readl_relaxed(base + GICD_TYPER); + gic_line_nr = min(GICD_TYPER_SPIS(typer), 1023u); + + for (i = 0; i * 32 < gic_line_nr; i++) { + enabled = readl_relaxed(base + GICD_ICENABLER + i * 4); + pending[i] = readl_relaxed(base + GICD_ISPENDR + i * 4); + pending[i] &= enabled; + } + + for (i = find_first_bit((unsigned long *)pending, gic_line_nr); + i < gic_line_nr; + i = find_next_bit((unsigned long *)pending, gic_line_nr, i + 1)) { + + if (i < 32) + continue; + + pr_warn("%s: HWIRQ %u\n", __func__, i); + } +} + +static atomic_t cpus_in_s2idle; + +static void gic_s2idle_enter(void *unused, struct cpuidle_device *dev, bool s2idle) +{ + if (!s2idle) + return; + + atomic_inc(&cpus_in_s2idle); +} + +static void gic_s2idle_exit(void *unused, struct cpuidle_device *dev, bool s2idle) +{ + if (!s2idle) + return; + + if (atomic_read(&cpus_in_s2idle) == num_online_cpus()) + msm_show_resume_irqs(); + + atomic_dec(&cpus_in_s2idle); +} + +static struct syscore_ops gic_syscore_ops = { + .resume = msm_show_resume_irqs, +}; + +static int msm_show_resume_probe(struct platform_device *pdev) +{ + base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL); + if (IS_ERR(base)) { + pr_err("%pOF: unable to map GICD registers\n", pdev->dev.of_node); + return -ENXIO; + } + + register_syscore_ops(&gic_syscore_ops); + return 0; +} + +static const struct of_device_id msm_show_resume_match_table[] = { + { .compatible = "qcom,show-resume-irqs" }, + { } +}; +MODULE_DEVICE_TABLE(of, msm_show_resume_match_table); + +static struct platform_driver msm_show_resume_dev_driver = { + .probe = msm_show_resume_probe, + .driver = { + .name = "show-resume-irqs", + .of_match_table = msm_show_resume_match_table, + }, +}; + +static int __init msm_show_resume_init(void) +{ + register_trace_prio_android_vh_cpuidle_psci_enter(gic_s2idle_enter, NULL, INT_MAX); + register_trace_prio_android_vh_cpuidle_psci_exit(gic_s2idle_exit, NULL, INT_MAX); + + return platform_driver_register(&msm_show_resume_dev_driver); +} + + +#if IS_MODULE(CONFIG_QCOM_SHOW_RESUME_IRQ) +module_init(msm_show_resume_init); +#else +pure_initcall(msm_show_resume_init); +#endif + +MODULE_DESCRIPTION("Qualcomm Technologies, Inc. MSM Show resume IRQ"); +MODULE_LICENSE("GPL");