| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * Copyright 2016 Anju T, IBM Corporation. |
|---|
| 3 | | - * |
|---|
| 4 | | - * This program is free software; you can redistribute it and/or |
|---|
| 5 | | - * modify it under the terms of the GNU General Public License |
|---|
| 6 | | - * as published by the Free Software Foundation; either version |
|---|
| 7 | | - * 2 of the License, or (at your option) any later version. |
|---|
| 8 | 4 | */ |
|---|
| 9 | 5 | |
|---|
| 10 | 6 | #include <linux/errno.h> |
|---|
| .. | .. |
|---|
| 17 | 13 | #include <asm/ptrace.h> |
|---|
| 18 | 14 | #include <asm/perf_regs.h> |
|---|
| 19 | 15 | |
|---|
| 16 | +u64 PERF_REG_EXTENDED_MASK; |
|---|
| 17 | + |
|---|
| 20 | 18 | #define PT_REGS_OFFSET(id, r) [id] = offsetof(struct pt_regs, r) |
|---|
| 21 | 19 | |
|---|
| 22 | | -#define REG_RESERVED (~((1ULL << PERF_REG_POWERPC_MAX) - 1)) |
|---|
| 20 | +#define REG_RESERVED (~(PERF_REG_EXTENDED_MASK | PERF_REG_PMU_MASK)) |
|---|
| 23 | 21 | |
|---|
| 24 | 22 | static unsigned int pt_regs_offset[PERF_REG_POWERPC_MAX] = { |
|---|
| 25 | 23 | PT_REGS_OFFSET(PERF_REG_POWERPC_R0, gpr[0]), |
|---|
| .. | .. |
|---|
| 69 | 67 | PT_REGS_OFFSET(PERF_REG_POWERPC_TRAP, trap), |
|---|
| 70 | 68 | PT_REGS_OFFSET(PERF_REG_POWERPC_DAR, dar), |
|---|
| 71 | 69 | PT_REGS_OFFSET(PERF_REG_POWERPC_DSISR, dsisr), |
|---|
| 70 | + PT_REGS_OFFSET(PERF_REG_POWERPC_SIER, dar), |
|---|
| 71 | + PT_REGS_OFFSET(PERF_REG_POWERPC_MMCRA, dsisr), |
|---|
| 72 | 72 | }; |
|---|
| 73 | + |
|---|
| 74 | +/* Function to return the extended register values */ |
|---|
| 75 | +static u64 get_ext_regs_value(int idx) |
|---|
| 76 | +{ |
|---|
| 77 | + switch (idx) { |
|---|
| 78 | + case PERF_REG_POWERPC_MMCR0: |
|---|
| 79 | + return mfspr(SPRN_MMCR0); |
|---|
| 80 | + case PERF_REG_POWERPC_MMCR1: |
|---|
| 81 | + return mfspr(SPRN_MMCR1); |
|---|
| 82 | + case PERF_REG_POWERPC_MMCR2: |
|---|
| 83 | + return mfspr(SPRN_MMCR2); |
|---|
| 84 | +#ifdef CONFIG_PPC64 |
|---|
| 85 | + case PERF_REG_POWERPC_MMCR3: |
|---|
| 86 | + return mfspr(SPRN_MMCR3); |
|---|
| 87 | + case PERF_REG_POWERPC_SIER2: |
|---|
| 88 | + return mfspr(SPRN_SIER2); |
|---|
| 89 | + case PERF_REG_POWERPC_SIER3: |
|---|
| 90 | + return mfspr(SPRN_SIER3); |
|---|
| 91 | +#endif |
|---|
| 92 | + default: return 0; |
|---|
| 93 | + } |
|---|
| 94 | +} |
|---|
| 73 | 95 | |
|---|
| 74 | 96 | u64 perf_reg_value(struct pt_regs *regs, int idx) |
|---|
| 75 | 97 | { |
|---|
| 76 | | - if (WARN_ON_ONCE(idx >= PERF_REG_POWERPC_MAX)) |
|---|
| 98 | + u64 perf_reg_extended_max = PERF_REG_POWERPC_MAX; |
|---|
| 99 | + |
|---|
| 100 | + if (cpu_has_feature(CPU_FTR_ARCH_31)) |
|---|
| 101 | + perf_reg_extended_max = PERF_REG_MAX_ISA_31; |
|---|
| 102 | + else if (cpu_has_feature(CPU_FTR_ARCH_300)) |
|---|
| 103 | + perf_reg_extended_max = PERF_REG_MAX_ISA_300; |
|---|
| 104 | + |
|---|
| 105 | + if (idx == PERF_REG_POWERPC_SIER && |
|---|
| 106 | + (IS_ENABLED(CONFIG_FSL_EMB_PERF_EVENT) || |
|---|
| 107 | + IS_ENABLED(CONFIG_PPC32) || |
|---|
| 108 | + !is_sier_available())) |
|---|
| 109 | + return 0; |
|---|
| 110 | + |
|---|
| 111 | + if (idx == PERF_REG_POWERPC_MMCRA && |
|---|
| 112 | + (IS_ENABLED(CONFIG_FSL_EMB_PERF_EVENT) || |
|---|
| 113 | + IS_ENABLED(CONFIG_PPC32))) |
|---|
| 114 | + return 0; |
|---|
| 115 | + |
|---|
| 116 | + if (idx >= PERF_REG_POWERPC_MAX && idx < perf_reg_extended_max) |
|---|
| 117 | + return get_ext_regs_value(idx); |
|---|
| 118 | + |
|---|
| 119 | + /* |
|---|
| 120 | + * If the idx is referring to value beyond the |
|---|
| 121 | + * supported registers, return 0 with a warning |
|---|
| 122 | + */ |
|---|
| 123 | + if (WARN_ON_ONCE(idx >= perf_reg_extended_max)) |
|---|
| 77 | 124 | return 0; |
|---|
| 78 | 125 | |
|---|
| 79 | 126 | return regs_get_register(regs, pt_regs_offset[idx]); |
|---|
| .. | .. |
|---|
| 97 | 144 | } |
|---|
| 98 | 145 | |
|---|
| 99 | 146 | void perf_get_regs_user(struct perf_regs *regs_user, |
|---|
| 100 | | - struct pt_regs *regs, |
|---|
| 101 | | - struct pt_regs *regs_user_copy) |
|---|
| 147 | + struct pt_regs *regs) |
|---|
| 102 | 148 | { |
|---|
| 103 | 149 | regs_user->regs = task_pt_regs(current); |
|---|
| 104 | 150 | regs_user->abi = (regs_user->regs) ? perf_reg_abi(current) : |
|---|