From a3d9f542060aff7c81bf9e019c5f5f7e64b4e4a2 Mon Sep 17 00:00:00 2001 From: Hanjie Lin Date: Mon, 18 Feb 2019 20:03:16 +0800 Subject: [PATCH] perf: arm: enable pmuserenr [1/1] PD#SWPL-4673 Problem: userspace can't access perf monitor cnt with "mrc ... c9,c13,0" Solution: actually userspace should check perf monitor cnt access permissions first before use, so this is a workround. enable pmuserenr with "mcr ... c9,c14,0" in several places: 1, perf probe 2, cpu idle (state>0) exit 3, cpu online 4, system resume after suspend Verify: u212 Change-Id: Ib09682d1d47545dfef8b088283ddbbf390630d3e Signed-off-by: Hanjie Lin --- arch/arm/include/asm/perf_event.h | 5 ++ arch/arm/kernel/cpuidle.c | 18 ++++++- arch/arm/kernel/perf_event_v7.c | 86 +++++++++++++++++++++++++++++++ 3 files changed, 108 insertions(+), 1 deletion(-) diff --git a/arch/arm/include/asm/perf_event.h b/arch/arm/include/asm/perf_event.h index 2501bd0977e6..6241c4d9de6a 100644 --- a/arch/arm/include/asm/perf_event.h +++ b/arch/arm/include/asm/perf_event.h @@ -29,4 +29,9 @@ extern unsigned long perf_misc_flags(struct pt_regs *regs); (regs)->ARM_sp = current_stack_pointer; \ (regs)->ARM_cpsr = SVC_MODE; \ } + +#ifdef CONFIG_AMLOGIC_MODIFY +void enable_pmuserenr(void); +#endif + #endif /* __ARM_PERF_EVENT_H__ */ diff --git a/arch/arm/kernel/cpuidle.c b/arch/arm/kernel/cpuidle.c index a3308ad1a024..b802508813a2 100644 --- a/arch/arm/kernel/cpuidle.c +++ b/arch/arm/kernel/cpuidle.c @@ -13,6 +13,9 @@ #include #include #include +#ifdef CONFIG_AMLOGIC_MODIFY +#include +#endif extern struct of_cpuidle_method __cpuidle_method_of_table[]; @@ -51,9 +54,22 @@ int arm_cpuidle_simple_enter(struct cpuidle_device *dev, */ int arm_cpuidle_suspend(int index) { +#ifdef CONFIG_AMLOGIC_MODIFY + int ret; + int cpu = smp_processor_id(); + + ret = cpuidle_ops[cpu].suspend(index); + + if (index > 0) { + pr_debug("arm_cpuidle_suspend(%d) exit\n", index); + enable_pmuserenr(); + } + return ret; +#else int cpu = smp_processor_id(); return cpuidle_ops[cpu].suspend(index); +#endif } /** @@ -135,7 +151,7 @@ static int __init arm_cpuidle_read_ops(struct device_node *dn, int cpu) * this cpu, * -ENOENT if it fails to find an 'enable-method' property, * -ENXIO if the HW reports a failure or a misconfiguration, - * -ENOMEM if the HW report an memory allocation failure + * -ENOMEM if the HW report an memory allocation failure */ int __init arm_cpuidle_init(int cpu) { diff --git a/arch/arm/kernel/perf_event_v7.c b/arch/arm/kernel/perf_event_v7.c index 836efdda3d80..2cfc7f030076 100644 --- a/arch/arm/kernel/perf_event_v7.c +++ b/arch/arm/kernel/perf_event_v7.c @@ -28,6 +28,10 @@ #include #include +#ifdef CONFIG_AMLOGIC_MODIFY +#include +#endif + /* * Common ARMv7 event types * @@ -2038,8 +2042,86 @@ static const struct pmu_probe_info armv7_pmu_probe_table[] = { { /* sentinel value */ } }; +#ifdef CONFIG_AMLOGIC_MODIFY +#if 0 +static int read_pmuserenr(void) +{ + int val = -1; + + asm volatile("mrc p15, 0, %0, c9, c14, 0" : "=r" (val):: "memory"); + return val; +} +#endif + +void enable_pmuserenr(void) +{ + //pr_emerg("enable_pmuserenr() start, val = %d\n", read_pmuserenr()); + asm volatile("mcr p15, 0, %0, c9, c14, 0" : : "r" (1) : "memory"); + //pr_emerg("enable_pmuserenr() end, val = %d\n", read_pmuserenr()); +} + +static void enable_pmuserenr_single(void *info) +{ + enable_pmuserenr(); +} + +static void enable_pmuserenr_all(void) +{ + pr_info("enable_pmuserenr_all() start\n"); + + enable_pmuserenr_single(NULL); + smp_call_function_many(cpu_possible_mask, + enable_pmuserenr_single, + NULL, + 1); + + pr_info("enable_pmuserenr_all() end\n"); +} + +static int pmu_user_callback(struct notifier_block *nfb, + unsigned long action, + void *hcpu) +{ + switch (action) { + case CPU_ONLINE: + case CPU_ONLINE_FROZEN: + pr_debug("cpu online callback\n"); + enable_pmuserenr(); + break; + default: + break; + } + return NOTIFY_OK; +} + +static struct notifier_block pmu_user_notify = { + &pmu_user_callback, + NULL, + 0 +}; + +static int armv7_pmu_resume(struct platform_device *pdev) +{ + pr_debug("armv7_pmu_resume()\n"); + enable_pmuserenr(); + return 0; +} + +static int armv7_pmu_suspend(struct platform_device *pdev, + pm_message_t state) +{ + pr_debug("armv7_pmu_suspend()\n"); + return 0; +} +#endif + static int armv7_pmu_device_probe(struct platform_device *pdev) { +#ifdef CONFIG_AMLOGIC_MODIFY + enable_pmuserenr_all(); + __register_cpu_notifier(&pmu_user_notify); +#endif + return arm_pmu_device_probe(pdev, armv7_pmu_of_device_ids, armv7_pmu_probe_table); } @@ -2050,6 +2132,10 @@ static struct platform_driver armv7_pmu_driver = { .of_match_table = armv7_pmu_of_device_ids, }, .probe = armv7_pmu_device_probe, +#ifdef CONFIG_AMLOGIC_MODIFY + .suspend = armv7_pmu_suspend, + .resume = armv7_pmu_resume, +#endif }; static int __init register_armv7_pmu_driver(void)