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:
parent
392f42735d
commit
e4ace486b1
@ -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
|
||||
|
@ -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
|
||||
|
122
drivers/irqchip/msm_show_resume_irq.c
Normal file
122
drivers/irqchip/msm_show_resume_irq.c
Normal 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");
|
Loading…
Reference in New Issue
Block a user