ARM: perf: Set ARMv7 SDER SUNIDEN bit
authorMartin Fuzzey <mfuzzey@parkeon.com>
Thu, 14 Jan 2016 04:36:26 +0000 (23:36 -0500)
committerWill Deacon <will.deacon@arm.com>
Mon, 25 Jan 2016 18:37:44 +0000 (18:37 +0000)
ARMv7 counters other than the CPU cycle counter only work if the Secure
Debug Enable Register (SDER) SUNIDEN bit is set.

Since access to the SDER is only possible in secure state, it will
only be done if the device tree property "secure-reg-access" is set.

Without this:

 Performance counter stats for 'sleep 1':

          14606094 cycles                    #    0.000 GHz
                 0 instructions              #    0.00  insns per cycle

After applying:

 Performance counter stats for 'sleep 1':

           5843809 cycles
           2566484 instructions              #    0.44  insns per cycle

       1.020144000 seconds time elapsed

Some platforms (eg i.MX53) may also need additional platform specific
setup.

Acked-by: Rob Herring <robh@kernel.org>
Signed-off-by: Martin Fuzzey <mfuzzey@parkeon.com>
Signed-off-by: Pooya Keshavarzi <Pooya.Keshavarzi@de.bosch.com>
Signed-off-by: George G. Davis <george_davis@mentor.com>
[will: add warning if property is found on arm64]
Signed-off-by: Will Deacon <will.deacon@arm.com>
Documentation/devicetree/bindings/arm/pmu.txt
arch/arm/kernel/perf_event_v7.c
drivers/perf/arm_pmu.c
include/linux/perf/arm_pmu.h

index 56518839f52a7908922aa9a88d60575be57cdbe3..b6056d3bca06a17421dbbc0ec17f12b6addf7b0e 100644 (file)
@@ -46,6 +46,16 @@ Optional properties:
 - qcom,no-pc-write : Indicates that this PMU doesn't support the 0xc and 0xd
                      events.
 
+- secure-reg-access : Indicates that the ARMv7 Secure Debug Enable Register
+                     (SDER) is accessible. This will cause the driver to do
+                     any setup required that is only possible in ARMv7 secure
+                     state. If not present the ARMv7 SDER will not be touched,
+                     which means the PMU may fail to operate unless external
+                     code (bootloader or security monitor) has performed the
+                     appropriate initialisation. Note that this property is
+                     not valid for non-ARMv7 CPUs or ARMv7 CPUs booting Linux
+                     in Non-secure state.
+
 Example:
 
 pmu {
index 4152158f6e6a527eca033e0235ee5a54f0ab2d69..15063851cd10825d08468b03e88411310beb68a3 100644 (file)
@@ -712,6 +712,11 @@ static const struct attribute_group *armv7_pmuv2_attr_groups[] = {
 #define        ARMV7_EXCLUDE_USER      (1 << 30)
 #define        ARMV7_INCLUDE_HYP       (1 << 27)
 
+/*
+ * Secure debug enable reg
+ */
+#define ARMV7_SDER_SUNIDEN     BIT(1) /* Permit non-invasive debug */
+
 static inline u32 armv7_pmnc_read(void)
 {
        u32 val;
@@ -1094,7 +1099,13 @@ static int armv7pmu_set_event_filter(struct hw_perf_event *event,
 static void armv7pmu_reset(void *info)
 {
        struct arm_pmu *cpu_pmu = (struct arm_pmu *)info;
-       u32 idx, nb_cnt = cpu_pmu->num_events;
+       u32 idx, nb_cnt = cpu_pmu->num_events, val;
+
+       if (cpu_pmu->secure_access) {
+               asm volatile("mrc p15, 0, %0, c1, c1, 1" : "=r" (val));
+               val |= ARMV7_SDER_SUNIDEN;
+               asm volatile("mcr p15, 0, %0, c1, c1, 1" : : "r" (val));
+       }
 
        /* The counter and interrupt enable registers are unknown at reset. */
        for (idx = ARMV7_IDX_CYCLE_COUNTER; idx < nb_cnt; ++idx) {
index 166637f2917cc563d8a0acc34da2dc6ab22319f1..eb5bee07526b58435f4c9d7bbcad7ea89848472d 100644 (file)
@@ -889,6 +889,15 @@ int arm_pmu_device_probe(struct platform_device *pdev,
        if (node && (of_id = of_match_node(of_table, pdev->dev.of_node))) {
                init_fn = of_id->data;
 
+               pmu->secure_access = of_property_read_bool(pdev->dev.of_node,
+                                                          "secure-reg-access");
+
+               /* arm64 systems boot only as non-secure */
+               if (IS_ENABLED(CONFIG_ARM64) && pmu->secure_access) {
+                       pr_warn("ignoring \"secure-reg-access\" property for arm64\n");
+                       pmu->secure_access = false;
+               }
+
                ret = of_pmu_irq_cfg(pmu);
                if (!ret)
                        ret = init_fn(pmu);
index 83b5e34c6580345fb47b648fb98fc8892583d8b9..2d5eaaa900780c1870f68fdde956ebc36218c541 100644 (file)
@@ -104,6 +104,7 @@ struct arm_pmu {
        atomic_t        active_events;
        struct mutex    reserve_mutex;
        u64             max_period;
+       bool            secure_access; /* 32-bit ARM only */
        struct platform_device  *plat_device;
        struct pmu_hw_events    __percpu *hw_events;
        struct notifier_block   hotplug_nb;