perf: arm: enable pmuserenr [1/1]
authorHanjie Lin <hanjie.lin@amlogic.com>
Mon, 18 Feb 2019 12:03:16 +0000 (20:03 +0800)
committerJianxin Pan <jianxin.pan@amlogic.com>
Thu, 21 Feb 2019 02:41:56 +0000 (18:41 -0800)
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 <hanjie.lin@amlogic.com>
arch/arm/include/asm/perf_event.h
arch/arm/kernel/cpuidle.c
arch/arm/kernel/perf_event_v7.c

index 2501bd0..6241c4d 100644 (file)
@@ -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__ */
index a3308ad..b802508 100644 (file)
@@ -13,6 +13,9 @@
 #include <linux/of.h>
 #include <linux/of_device.h>
 #include <asm/cpuidle.h>
+#ifdef CONFIG_AMLOGIC_MODIFY
+#include <asm/perf_event.h>
+#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)
 {
index 836efdd..2cfc7f0 100644 (file)
 #include <linux/perf/arm_pmu.h>
 #include <linux/platform_device.h>
 
+#ifdef CONFIG_AMLOGIC_MODIFY
+#include <asm/perf_event.h>
+#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)