arm64: edac: Add workaround for using cti to trigger pmu irq

In MSM8994-V1, for unknown reasons the pmu percpu interrupt was
incorrectly connected to the corresponding CPU in the other cluster.
To workaround this problem, it was decided that the cti could be used
to trigger the percpu pmu interrupt to the right cpu which actually
caused the event and can handle it.
This patch implements this workaround.

Change-Id: I732ad77ed2529a54b85c51b3fadcc53d93d70279
Signed-off-by: Rohit Vaswani <rvaswani@codeaurora.org>
This commit is contained in:
Rohit Vaswani 2014-05-23 20:41:58 -07:00
parent 4e4cb0e35a
commit 1b1d3e9fbb
5 changed files with 120 additions and 3 deletions

View File

@ -171,6 +171,15 @@ config ARCH_MSM8994_V1_TLBI_WA
[39:38] bits of VA are tied to zero and due to which TLBI [39:38] bits of VA are tied to zero and due to which TLBI
operations with VA or ASID will not work. 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 config ARCH_XGENE
bool "AppliedMicro X-Gene SOC Family" bool "AppliedMicro X-Gene SOC Family"
help help

View File

@ -24,6 +24,7 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/workqueue.h> #include <linux/workqueue.h>
#include <linux/percpu.h> #include <linux/percpu.h>
#include <soc/qcom/cti-pmu-irq.h>
#include <asm/cputype.h> #include <asm/cputype.h>
@ -655,9 +656,11 @@ static irqreturn_t arm64_sbe_handler(int irq, void *drvdata)
u32 pmovsr, cntr; u32 pmovsr, cntr;
struct erp_local_data errdata; struct erp_local_data errdata;
unsigned long flags; unsigned long flags;
int overflow = 0; int overflow = 0, ret = IRQ_HANDLED;
int cpu = raw_smp_processor_id(); int cpu = raw_smp_processor_id();
msm_cti_pmu_irq_ack(cpu);
errdata.drv = *((struct erp_drvdata **)drvdata); errdata.drv = *((struct erp_drvdata **)drvdata);
cntr = errdata.drv->mem_perf_counter; cntr = errdata.drv->mem_perf_counter;
arm64_pmu_lock(NULL, &flags); arm64_pmu_lock(NULL, &flags);
@ -672,10 +675,10 @@ static irqreturn_t arm64_sbe_handler(int irq, void *drvdata)
arm64_erp_local_handler(&errdata); arm64_erp_local_handler(&errdata);
sbe_enable_event(errdata.drv); sbe_enable_event(errdata.drv);
} else { } 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, 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(); drv->mem_perf_counter = arm64_pmu_get_last_counter();
cpu_pm_register_notifier(&(drv->nb)); cpu_pm_register_notifier(&(drv->nb));
arm64_pmu_irq_handled_externally(); 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(sbe_enable_event, drv, 1);
on_each_cpu(arm64_enable_pmu_irq, &sbe_irq, 1); on_each_cpu(arm64_enable_pmu_irq, &sbe_irq, 1);

View File

@ -57,3 +57,4 @@ endif
obj-$(CONFIG_MSM_SYSMON_COMM) += sysmon.o obj-$(CONFIG_MSM_SYSMON_COMM) += sysmon.o
obj-$(CONFIG_CP_ACCESS64) += cpaccess64.o obj-$(CONFIG_CP_ACCESS64) += cpaccess64.o
obj-$(CONFIG_MSM_CPU_PWR_CTL) += cpu_pwr_ctl.o obj-$(CONFIG_MSM_CPU_PWR_CTL) += cpu_pwr_ctl.o
obj-$(CONFIG_MSM8994_V1_PMUIRQ_WA) += cti-pmu-irq.o

View File

@ -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 <linux/coresight-cti.h>
#include <linux/err.h>
#include <linux/kernel.h>
#include <linux/smp.h>
#include <soc/qcom/cti-pmu-irq.h>
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);
}

View File

@ -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 <linux/workqueue.h>
#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