diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index c667de7a879..951a79d9b08 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -171,6 +171,15 @@ config ARCH_MSM8994_V1_TLBI_WA [39:38] bits of VA are tied to zero and due to which TLBI operations with VA or ASID will not work. +config MSM8994_V1_PMUIRQ_WA + bool "Enable MSM8994 v1 PMU-CTI IRQ workaround" + depends on ARCH_MSM8994 && CORESIGHT_CTI + help + This enables support for the MSM8994 v1 PMU-CTI IRQ workaround. + This workaround is required for MSM8994 V1 revision where the + percpu PMU interrupt is incorrectly connected to the corresponding + CPUs in the other cluster. + config ARCH_XGENE bool "AppliedMicro X-Gene SOC Family" help diff --git a/drivers/edac/cortex_arm64_edac.c b/drivers/edac/cortex_arm64_edac.c index e73b7a5cdf9..2070e7dd80e 100644 --- a/drivers/edac/cortex_arm64_edac.c +++ b/drivers/edac/cortex_arm64_edac.c @@ -24,6 +24,7 @@ #include #include #include +#include #include @@ -655,9 +656,11 @@ static irqreturn_t arm64_sbe_handler(int irq, void *drvdata) u32 pmovsr, cntr; struct erp_local_data errdata; unsigned long flags; - int overflow = 0; + int overflow = 0, ret = IRQ_HANDLED; int cpu = raw_smp_processor_id(); + msm_cti_pmu_irq_ack(cpu); + errdata.drv = *((struct erp_drvdata **)drvdata); cntr = errdata.drv->mem_perf_counter; arm64_pmu_lock(NULL, &flags); @@ -672,10 +675,10 @@ static irqreturn_t arm64_sbe_handler(int irq, void *drvdata) arm64_erp_local_handler(&errdata); sbe_enable_event(errdata.drv); } else { - return armv8pmu_handle_irq(irq, NULL); + ret = armv8pmu_handle_irq(irq, NULL); } - return IRQ_HANDLED; + return ret; } static int request_erp_irq(struct platform_device *pdev, const char *propname, @@ -842,6 +845,7 @@ static int arm64_cpu_erp_probe(struct platform_device *pdev) drv->mem_perf_counter = arm64_pmu_get_last_counter(); cpu_pm_register_notifier(&(drv->nb)); arm64_pmu_irq_handled_externally(); + schedule_on_each_cpu(msm_enable_cti_pmu_workaround); on_each_cpu(sbe_enable_event, drv, 1); on_each_cpu(arm64_enable_pmu_irq, &sbe_irq, 1); diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile index c8320d2f2d4..73cb2890176 100644 --- a/drivers/soc/qcom/Makefile +++ b/drivers/soc/qcom/Makefile @@ -57,3 +57,4 @@ endif obj-$(CONFIG_MSM_SYSMON_COMM) += sysmon.o obj-$(CONFIG_CP_ACCESS64) += cpaccess64.o obj-$(CONFIG_MSM_CPU_PWR_CTL) += cpu_pwr_ctl.o +obj-$(CONFIG_MSM8994_V1_PMUIRQ_WA) += cti-pmu-irq.o diff --git a/drivers/soc/qcom/cti-pmu-irq.c b/drivers/soc/qcom/cti-pmu-irq.c new file mode 100644 index 00000000000..af06cc0c3e1 --- /dev/null +++ b/drivers/soc/qcom/cti-pmu-irq.c @@ -0,0 +1,76 @@ +/* Copyright (c) 2014, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include + +static struct coresight_cti *msm_cti_cpux[NR_CPUS]; +static const char * const coresight_cpu_name[] = { + "coresight-cti-cpu0", + "coresight-cti-cpu1", + "coresight-cti-cpu2", + "coresight-cti-cpu3", + "coresight-cti-cpu4", + "coresight-cti-cpu5", + "coresight-cti-cpu6", + "coresight-cti-cpu7", +}; + +struct coresight_cti *msm_get_cpu_cti(int cpu) +{ + return coresight_cti_get(coresight_cpu_name[cpu]); +} + +void msm_cti_pmu_irq_ack(int cpu) +{ + int ret = coresight_cti_ack_trig(msm_cti_cpux[cpu], 2); + if (ret) + pr_err("Failed to Acknowledge CTI-PMU Irq on CPU %d - %d\n", + cpu, ret); +} + +void msm_enable_cti_pmu_workaround(struct work_struct *work) +{ + struct coresight_cti *cti_cpux; + int trigin = 1; + int trigout = 2; + int ch = 2; + int cpu = smp_processor_id(); + int ret; + + cti_cpux = coresight_cti_get(coresight_cpu_name[cpu]); + if (IS_ERR(cti_cpux)) + goto err; + + msm_cti_cpux[cpu] = cti_cpux; + + ret = coresight_cti_map_trigin(cti_cpux, trigin, ch); + if (ret) + goto err_in; + ret = coresight_cti_map_trigout(cti_cpux, trigout, ch); + if (ret) + goto err_out; + coresight_cti_enable_gate(cti_cpux, ch); + pr_info("%s for CPU %d\n", __func__, cpu); + + return; +err_out: + coresight_cti_unmap_trigin(cti_cpux, trigin, ch); +err_in: + coresight_cti_put(cti_cpux); +err: + pr_err("Failed to enable CTI-PMU workaround on CPU %d - %d\n", + cpu, ret); +} diff --git a/include/soc/qcom/cti-pmu-irq.h b/include/soc/qcom/cti-pmu-irq.h new file mode 100644 index 00000000000..0233db17754 --- /dev/null +++ b/include/soc/qcom/cti-pmu-irq.h @@ -0,0 +1,27 @@ +/* Copyright (c) 2014, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef __MSM_CTI_PMU_IRQ_H +#define __MSM_CTI_PMU_IRQ_H + +#include + +#ifdef CONFIG_MSM8994_V1_PMUIRQ_WA +void msm_enable_cti_pmu_workaround(struct work_struct *work); +struct coresight_cti *msm_get_cpu_cti(int cpu); +void msm_cti_pmu_irq_ack(int cpu); +#else +static inline void msm_enable_cti_pmu_workaround(struct work_struct *work) { } +static inline struct coresight_cti *msm_get_cpu_cti(int cpu) { return NULL; } +static inline void msm_cti_pmu_irq_ack(int cpu) { } +#endif +#endif