perf/arch/arm64: Implement hw_breakpoint_arch_parse()
authorFrederic Weisbecker <frederic@kernel.org>
Tue, 26 Jun 2018 02:58:53 +0000 (04:58 +0200)
committerIngo Molnar <mingo@kernel.org>
Tue, 26 Jun 2018 07:07:56 +0000 (09:07 +0200)
Migrate to the new API in order to remove arch_validate_hwbkpt_settings()
that clumsily mixes up architecture validation and commit.

Signed-off-by: Frederic Weisbecker <frederic@kernel.org>
Acked-by: Will Deacon <will.deacon@arm.com>
Acked-by: Mark Rutland <mark.rutland@arm.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Andy Lutomirski <luto@kernel.org>
Cc: Arnaldo Carvalho de Melo <acme@kernel.org>
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Chris Zankel <chris@zankel.net>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Joel Fernandes <joel.opensrc@gmail.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Max Filippov <jcmvbkbc@gmail.com>
Cc: Michael Ellerman <mpe@ellerman.id.au>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Rich Felker <dalias@libc.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Yoshinori Sato <ysato@users.sourceforge.jp>
Link: http://lkml.kernel.org/r/1529981939-8231-7-git-send-email-frederic@kernel.org
Signed-off-by: Ingo Molnar <mingo@kernel.org>
arch/arm64/include/asm/hw_breakpoint.h
arch/arm64/kernel/hw_breakpoint.c

index 9f4a3d48762e8ad9fcc91b84289f1bc4e1c89109..bf9c305daa624a953bf8c18f5202180c6ca394b5 100644 (file)
@@ -119,13 +119,17 @@ static inline void decode_ctrl_reg(u32 reg,
 
 struct task_struct;
 struct notifier_block;
+struct perf_event_attr;
 struct perf_event;
 struct pmu;
 
 extern int arch_bp_generic_fields(struct arch_hw_breakpoint_ctrl ctrl,
                                  int *gen_len, int *gen_type, int *offset);
 extern int arch_check_bp_in_kernelspace(struct arch_hw_breakpoint *hw);
-extern int arch_validate_hwbkpt_settings(struct perf_event *bp);
+extern int hw_breakpoint_arch_parse(struct perf_event *bp,
+                                   const struct perf_event_attr *attr,
+                                   struct arch_hw_breakpoint *hw);
+#define hw_breakpoint_arch_parse hw_breakpoint_arch_parse
 extern int hw_breakpoint_exceptions_notify(struct notifier_block *unused,
                                           unsigned long val, void *data);
 
index 6a90d12e4ff2c319eab3a00f3d0624ee013e31a0..8c9644376326fe96f05645d298c1b4fcd383d652 100644 (file)
@@ -420,53 +420,53 @@ int arch_bp_generic_fields(struct arch_hw_breakpoint_ctrl ctrl,
 /*
  * Construct an arch_hw_breakpoint from a perf_event.
  */
-static int arch_build_bp_info(struct perf_event *bp)
+static int arch_build_bp_info(struct perf_event *bp,
+                             const struct perf_event_attr *attr,
+                             struct arch_hw_breakpoint *hw)
 {
-       struct arch_hw_breakpoint *info = counter_arch_bp(bp);
-
        /* Type */
-       switch (bp->attr.bp_type) {
+       switch (attr->bp_type) {
        case HW_BREAKPOINT_X:
-               info->ctrl.type = ARM_BREAKPOINT_EXECUTE;
+               hw->ctrl.type = ARM_BREAKPOINT_EXECUTE;
                break;
        case HW_BREAKPOINT_R:
-               info->ctrl.type = ARM_BREAKPOINT_LOAD;
+               hw->ctrl.type = ARM_BREAKPOINT_LOAD;
                break;
        case HW_BREAKPOINT_W:
-               info->ctrl.type = ARM_BREAKPOINT_STORE;
+               hw->ctrl.type = ARM_BREAKPOINT_STORE;
                break;
        case HW_BREAKPOINT_RW:
-               info->ctrl.type = ARM_BREAKPOINT_LOAD | ARM_BREAKPOINT_STORE;
+               hw->ctrl.type = ARM_BREAKPOINT_LOAD | ARM_BREAKPOINT_STORE;
                break;
        default:
                return -EINVAL;
        }
 
        /* Len */
-       switch (bp->attr.bp_len) {
+       switch (attr->bp_len) {
        case HW_BREAKPOINT_LEN_1:
-               info->ctrl.len = ARM_BREAKPOINT_LEN_1;
+               hw->ctrl.len = ARM_BREAKPOINT_LEN_1;
                break;
        case HW_BREAKPOINT_LEN_2:
-               info->ctrl.len = ARM_BREAKPOINT_LEN_2;
+               hw->ctrl.len = ARM_BREAKPOINT_LEN_2;
                break;
        case HW_BREAKPOINT_LEN_3:
-               info->ctrl.len = ARM_BREAKPOINT_LEN_3;
+               hw->ctrl.len = ARM_BREAKPOINT_LEN_3;
                break;
        case HW_BREAKPOINT_LEN_4:
-               info->ctrl.len = ARM_BREAKPOINT_LEN_4;
+               hw->ctrl.len = ARM_BREAKPOINT_LEN_4;
                break;
        case HW_BREAKPOINT_LEN_5:
-               info->ctrl.len = ARM_BREAKPOINT_LEN_5;
+               hw->ctrl.len = ARM_BREAKPOINT_LEN_5;
                break;
        case HW_BREAKPOINT_LEN_6:
-               info->ctrl.len = ARM_BREAKPOINT_LEN_6;
+               hw->ctrl.len = ARM_BREAKPOINT_LEN_6;
                break;
        case HW_BREAKPOINT_LEN_7:
-               info->ctrl.len = ARM_BREAKPOINT_LEN_7;
+               hw->ctrl.len = ARM_BREAKPOINT_LEN_7;
                break;
        case HW_BREAKPOINT_LEN_8:
-               info->ctrl.len = ARM_BREAKPOINT_LEN_8;
+               hw->ctrl.len = ARM_BREAKPOINT_LEN_8;
                break;
        default:
                return -EINVAL;
@@ -477,37 +477,37 @@ static int arch_build_bp_info(struct perf_event *bp)
         * AArch32 also requires breakpoints of length 2 for Thumb.
         * Watchpoints can be of length 1, 2, 4 or 8 bytes.
         */
-       if (info->ctrl.type == ARM_BREAKPOINT_EXECUTE) {
+       if (hw->ctrl.type == ARM_BREAKPOINT_EXECUTE) {
                if (is_compat_bp(bp)) {
-                       if (info->ctrl.len != ARM_BREAKPOINT_LEN_2 &&
-                           info->ctrl.len != ARM_BREAKPOINT_LEN_4)
+                       if (hw->ctrl.len != ARM_BREAKPOINT_LEN_2 &&
+                           hw->ctrl.len != ARM_BREAKPOINT_LEN_4)
                                return -EINVAL;
-               } else if (info->ctrl.len != ARM_BREAKPOINT_LEN_4) {
+               } else if (hw->ctrl.len != ARM_BREAKPOINT_LEN_4) {
                        /*
                         * FIXME: Some tools (I'm looking at you perf) assume
                         *        that breakpoints should be sizeof(long). This
                         *        is nonsense. For now, we fix up the parameter
                         *        but we should probably return -EINVAL instead.
                         */
-                       info->ctrl.len = ARM_BREAKPOINT_LEN_4;
+                       hw->ctrl.len = ARM_BREAKPOINT_LEN_4;
                }
        }
 
        /* Address */
-       info->address = bp->attr.bp_addr;
+       hw->address = attr->bp_addr;
 
        /*
         * Privilege
         * Note that we disallow combined EL0/EL1 breakpoints because
         * that would complicate the stepping code.
         */
-       if (arch_check_bp_in_kernelspace(info))
-               info->ctrl.privilege = AARCH64_BREAKPOINT_EL1;
+       if (arch_check_bp_in_kernelspace(hw))
+               hw->ctrl.privilege = AARCH64_BREAKPOINT_EL1;
        else
-               info->ctrl.privilege = AARCH64_BREAKPOINT_EL0;
+               hw->ctrl.privilege = AARCH64_BREAKPOINT_EL0;
 
        /* Enabled? */
-       info->ctrl.enabled = !bp->attr.disabled;
+       hw->ctrl.enabled = !attr->disabled;
 
        return 0;
 }
@@ -515,14 +515,15 @@ static int arch_build_bp_info(struct perf_event *bp)
 /*
  * Validate the arch-specific HW Breakpoint register settings.
  */
-int arch_validate_hwbkpt_settings(struct perf_event *bp)
+int hw_breakpoint_arch_parse(struct perf_event *bp,
+                            const struct perf_event_attr *attr,
+                            struct arch_hw_breakpoint *hw)
 {
-       struct arch_hw_breakpoint *info = counter_arch_bp(bp);
        int ret;
        u64 alignment_mask, offset;
 
        /* Build the arch_hw_breakpoint. */
-       ret = arch_build_bp_info(bp);
+       ret = arch_build_bp_info(bp, attr, hw);
        if (ret)
                return ret;
 
@@ -536,42 +537,42 @@ int arch_validate_hwbkpt_settings(struct perf_event *bp)
         * that here.
         */
        if (is_compat_bp(bp)) {
-               if (info->ctrl.len == ARM_BREAKPOINT_LEN_8)
+               if (hw->ctrl.len == ARM_BREAKPOINT_LEN_8)
                        alignment_mask = 0x7;
                else
                        alignment_mask = 0x3;
-               offset = info->address & alignment_mask;
+               offset = hw->address & alignment_mask;
                switch (offset) {
                case 0:
                        /* Aligned */
                        break;
                case 1:
                        /* Allow single byte watchpoint. */
-                       if (info->ctrl.len == ARM_BREAKPOINT_LEN_1)
+                       if (hw->ctrl.len == ARM_BREAKPOINT_LEN_1)
                                break;
                case 2:
                        /* Allow halfword watchpoints and breakpoints. */
-                       if (info->ctrl.len == ARM_BREAKPOINT_LEN_2)
+                       if (hw->ctrl.len == ARM_BREAKPOINT_LEN_2)
                                break;
                default:
                        return -EINVAL;
                }
        } else {
-               if (info->ctrl.type == ARM_BREAKPOINT_EXECUTE)
+               if (hw->ctrl.type == ARM_BREAKPOINT_EXECUTE)
                        alignment_mask = 0x3;
                else
                        alignment_mask = 0x7;
-               offset = info->address & alignment_mask;
+               offset = hw->address & alignment_mask;
        }
 
-       info->address &= ~alignment_mask;
-       info->ctrl.len <<= offset;
+       hw->address &= ~alignment_mask;
+       hw->ctrl.len <<= offset;
 
        /*
         * Disallow per-task kernel breakpoints since these would
         * complicate the stepping code.
         */
-       if (info->ctrl.privilege == AARCH64_BREAKPOINT_EL1 && bp->hw.target)
+       if (hw->ctrl.privilege == AARCH64_BREAKPOINT_EL1 && bp->hw.target)
                return -EINVAL;
 
        return 0;