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 <quic_rzafar@quicinc.com>
This commit is contained in:
Rashid Zafar 2022-10-12 13:12:35 -07:00
parent 392f42735d
commit e4ace486b1
3 changed files with 133 additions and 0 deletions

View File

@ -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

View File

@ -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

View File

@ -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 <linux/cpuidle.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/platform_device.h>
#include <linux/syscore_ops.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/irqchip/arm-gic-v3.h>
#include <trace/hooks/cpuidle_psci.h>
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");