diff options
Diffstat (limited to 'tools/perf/arch/powerpc')
20 files changed, 132 insertions, 1229 deletions
diff --git a/tools/perf/arch/powerpc/Makefile b/tools/perf/arch/powerpc/Makefile index a295a80ea078..44cc3f023318 100644 --- a/tools/perf/arch/powerpc/Makefile +++ b/tools/perf/arch/powerpc/Makefile @@ -1,3 +1,2 @@ # SPDX-License-Identifier: GPL-2.0 -HAVE_KVM_STAT_SUPPORT := 1 PERF_HAVE_JITDUMP := 1 diff --git a/tools/perf/arch/powerpc/annotate/instructions.c b/tools/perf/arch/powerpc/annotate/instructions.c deleted file mode 100644 index ca567cfdcbdb..000000000000 --- a/tools/perf/arch/powerpc/annotate/instructions.c +++ /dev/null @@ -1,317 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -#include <linux/compiler.h> - -static struct ins_ops *powerpc__associate_instruction_ops(struct arch *arch, const char *name) -{ - int i; - struct ins_ops *ops; - - /* - * - Interested only if instruction starts with 'b'. - * - Few start with 'b', but aren't branch instructions. - */ - if (name[0] != 'b' || - !strncmp(name, "bcd", 3) || - !strncmp(name, "brinc", 5) || - !strncmp(name, "bper", 4)) - return NULL; - - ops = &jump_ops; - - i = strlen(name) - 1; - if (i < 0) - return NULL; - - /* ignore optional hints at the end of the instructions */ - if (name[i] == '+' || name[i] == '-') - i--; - - if (name[i] == 'l' || (name[i] == 'a' && name[i-1] == 'l')) { - /* - * if the instruction ends up with 'l' or 'la', then - * those are considered 'calls' since they update LR. - * ... except for 'bnl' which is branch if not less than - * and the absolute form of the same. - */ - if (strcmp(name, "bnl") && strcmp(name, "bnl+") && - strcmp(name, "bnl-") && strcmp(name, "bnla") && - strcmp(name, "bnla+") && strcmp(name, "bnla-")) - ops = &call_ops; - } - if (name[i] == 'r' && name[i-1] == 'l') - /* - * instructions ending with 'lr' are considered to be - * return instructions - */ - ops = &ret_ops; - - arch__associate_ins_ops(arch, name, ops); - return ops; -} - -#define PPC_OP(op) (((op) >> 26) & 0x3F) -#define PPC_21_30(R) (((R) >> 1) & 0x3ff) -#define PPC_22_30(R) (((R) >> 1) & 0x1ff) - -struct insn_offset { - const char *name; - int value; -}; - -/* - * There are memory instructions with opcode 31 which are - * of X Form, Example: - * ldx RT,RA,RB - * ______________________________________ - * | 31 | RT | RA | RB | 21 |/| - * -------------------------------------- - * 0 6 11 16 21 30 31 - * - * But all instructions with opcode 31 are not memory. - * Example: add RT,RA,RB - * - * Use bits 21 to 30 to check memory insns with 31 as opcode. - * In ins_array below, for ldx instruction: - * name => OP_31_XOP_LDX - * value => 21 - */ - -static struct insn_offset ins_array[] = { - { .name = "OP_31_XOP_LXSIWZX", .value = 12, }, - { .name = "OP_31_XOP_LWARX", .value = 20, }, - { .name = "OP_31_XOP_LDX", .value = 21, }, - { .name = "OP_31_XOP_LWZX", .value = 23, }, - { .name = "OP_31_XOP_LDUX", .value = 53, }, - { .name = "OP_31_XOP_LWZUX", .value = 55, }, - { .name = "OP_31_XOP_LXSIWAX", .value = 76, }, - { .name = "OP_31_XOP_LDARX", .value = 84, }, - { .name = "OP_31_XOP_LBZX", .value = 87, }, - { .name = "OP_31_XOP_LVX", .value = 103, }, - { .name = "OP_31_XOP_LBZUX", .value = 119, }, - { .name = "OP_31_XOP_STXSIWX", .value = 140, }, - { .name = "OP_31_XOP_STDX", .value = 149, }, - { .name = "OP_31_XOP_STWX", .value = 151, }, - { .name = "OP_31_XOP_STDUX", .value = 181, }, - { .name = "OP_31_XOP_STWUX", .value = 183, }, - { .name = "OP_31_XOP_STBX", .value = 215, }, - { .name = "OP_31_XOP_STVX", .value = 231, }, - { .name = "OP_31_XOP_STBUX", .value = 247, }, - { .name = "OP_31_XOP_LHZX", .value = 279, }, - { .name = "OP_31_XOP_LHZUX", .value = 311, }, - { .name = "OP_31_XOP_LXVDSX", .value = 332, }, - { .name = "OP_31_XOP_LWAX", .value = 341, }, - { .name = "OP_31_XOP_LHAX", .value = 343, }, - { .name = "OP_31_XOP_LWAUX", .value = 373, }, - { .name = "OP_31_XOP_LHAUX", .value = 375, }, - { .name = "OP_31_XOP_STHX", .value = 407, }, - { .name = "OP_31_XOP_STHUX", .value = 439, }, - { .name = "OP_31_XOP_LXSSPX", .value = 524, }, - { .name = "OP_31_XOP_LDBRX", .value = 532, }, - { .name = "OP_31_XOP_LSWX", .value = 533, }, - { .name = "OP_31_XOP_LWBRX", .value = 534, }, - { .name = "OP_31_XOP_LFSUX", .value = 567, }, - { .name = "OP_31_XOP_LXSDX", .value = 588, }, - { .name = "OP_31_XOP_LSWI", .value = 597, }, - { .name = "OP_31_XOP_LFDX", .value = 599, }, - { .name = "OP_31_XOP_LFDUX", .value = 631, }, - { .name = "OP_31_XOP_STXSSPX", .value = 652, }, - { .name = "OP_31_XOP_STDBRX", .value = 660, }, - { .name = "OP_31_XOP_STXWX", .value = 661, }, - { .name = "OP_31_XOP_STWBRX", .value = 662, }, - { .name = "OP_31_XOP_STFSX", .value = 663, }, - { .name = "OP_31_XOP_STFSUX", .value = 695, }, - { .name = "OP_31_XOP_STXSDX", .value = 716, }, - { .name = "OP_31_XOP_STSWI", .value = 725, }, - { .name = "OP_31_XOP_STFDX", .value = 727, }, - { .name = "OP_31_XOP_STFDUX", .value = 759, }, - { .name = "OP_31_XOP_LXVW4X", .value = 780, }, - { .name = "OP_31_XOP_LHBRX", .value = 790, }, - { .name = "OP_31_XOP_LXVD2X", .value = 844, }, - { .name = "OP_31_XOP_LFIWAX", .value = 855, }, - { .name = "OP_31_XOP_LFIWZX", .value = 887, }, - { .name = "OP_31_XOP_STXVW4X", .value = 908, }, - { .name = "OP_31_XOP_STHBRX", .value = 918, }, - { .name = "OP_31_XOP_STXVD2X", .value = 972, }, - { .name = "OP_31_XOP_STFIWX", .value = 983, }, -}; - -/* - * Arithmetic instructions which are having opcode as 31. - * These instructions are tracked to save the register state - * changes. Example: - * - * lwz r10,264(r3) - * add r31, r3, r3 - * lwz r9, 0(r31) - * - * Here instruction tracking needs to identify the "add" - * instruction and save data type of r3 to r31. If a sample - * is hit at next "lwz r9, 0(r31)", by this instruction tracking, - * data type of r31 can be resolved. - */ -static struct insn_offset arithmetic_ins_op_31[] = { - { .name = "SUB_CARRY_XO_FORM", .value = 8, }, - { .name = "MUL_HDW_XO_FORM1", .value = 9, }, - { .name = "ADD_CARRY_XO_FORM", .value = 10, }, - { .name = "MUL_HW_XO_FORM1", .value = 11, }, - { .name = "SUB_XO_FORM", .value = 40, }, - { .name = "MUL_HDW_XO_FORM", .value = 73, }, - { .name = "MUL_HW_XO_FORM", .value = 75, }, - { .name = "SUB_EXT_XO_FORM", .value = 136, }, - { .name = "ADD_EXT_XO_FORM", .value = 138, }, - { .name = "SUB_ZERO_EXT_XO_FORM", .value = 200, }, - { .name = "ADD_ZERO_EXT_XO_FORM", .value = 202, }, - { .name = "SUB_EXT_XO_FORM2", .value = 232, }, - { .name = "MUL_DW_XO_FORM", .value = 233, }, - { .name = "ADD_EXT_XO_FORM2", .value = 234, }, - { .name = "MUL_W_XO_FORM", .value = 235, }, - { .name = "ADD_XO_FORM", .value = 266, }, - { .name = "DIV_DW_XO_FORM1", .value = 457, }, - { .name = "DIV_W_XO_FORM1", .value = 459, }, - { .name = "DIV_DW_XO_FORM", .value = 489, }, - { .name = "DIV_W_XO_FORM", .value = 491, }, -}; - -static struct insn_offset arithmetic_two_ops[] = { - { .name = "mulli", .value = 7, }, - { .name = "subfic", .value = 8, }, - { .name = "addic", .value = 12, }, - { .name = "addic.", .value = 13, }, - { .name = "addi", .value = 14, }, - { .name = "addis", .value = 15, }, -}; - -static int cmp_offset(const void *a, const void *b) -{ - const struct insn_offset *val1 = a; - const struct insn_offset *val2 = b; - - return (val1->value - val2->value); -} - -static struct ins_ops *check_ppc_insn(struct disasm_line *dl) -{ - int raw_insn = dl->raw.raw_insn; - int opcode = PPC_OP(raw_insn); - int mem_insn_31 = PPC_21_30(raw_insn); - struct insn_offset *ret; - struct insn_offset mem_insns_31_opcode = { - "OP_31_INSN", - mem_insn_31 - }; - char name_insn[32]; - - /* - * Instructions with opcode 32 to 63 are memory - * instructions in powerpc - */ - if ((opcode & 0x20)) { - /* - * Set name in case of raw instruction to - * opcode to be used in insn-stat - */ - if (!strlen(dl->ins.name)) { - sprintf(name_insn, "%d", opcode); - dl->ins.name = strdup(name_insn); - } - return &load_store_ops; - } else if (opcode == 31) { - /* Check for memory instructions with opcode 31 */ - ret = bsearch(&mem_insns_31_opcode, ins_array, ARRAY_SIZE(ins_array), sizeof(ins_array[0]), cmp_offset); - if (ret) { - if (!strlen(dl->ins.name)) - dl->ins.name = strdup(ret->name); - return &load_store_ops; - } else { - mem_insns_31_opcode.value = PPC_22_30(raw_insn); - ret = bsearch(&mem_insns_31_opcode, arithmetic_ins_op_31, ARRAY_SIZE(arithmetic_ins_op_31), - sizeof(arithmetic_ins_op_31[0]), cmp_offset); - if (ret != NULL) - return &arithmetic_ops; - /* Bits 21 to 30 has value 444 for "mr" insn ie, OR X form */ - if (PPC_21_30(raw_insn) == 444) - return &arithmetic_ops; - } - } else { - mem_insns_31_opcode.value = opcode; - ret = bsearch(&mem_insns_31_opcode, arithmetic_two_ops, ARRAY_SIZE(arithmetic_two_ops), - sizeof(arithmetic_two_ops[0]), cmp_offset); - if (ret != NULL) - return &arithmetic_ops; - } - - return NULL; -} - -/* - * Instruction tracking function to track register state moves. - * Example sequence: - * ld r10,264(r3) - * mr r31,r3 - * <<after some sequence> - * ld r9,312(r31) - * - * Previous instruction sequence shows that register state of r3 - * is moved to r31. update_insn_state_powerpc tracks these state - * changes - */ -#ifdef HAVE_LIBDW_SUPPORT -static void update_insn_state_powerpc(struct type_state *state, - struct data_loc_info *dloc, Dwarf_Die * cu_die __maybe_unused, - struct disasm_line *dl) -{ - struct annotated_insn_loc loc; - struct annotated_op_loc *src = &loc.ops[INSN_OP_SOURCE]; - struct annotated_op_loc *dst = &loc.ops[INSN_OP_TARGET]; - struct type_state_reg *tsr; - u32 insn_offset = dl->al.offset; - - if (annotate_get_insn_location(dloc->arch, dl, &loc) < 0) - return; - - /* - * Value 444 for bits 21:30 is for "mr" - * instruction. "mr" is extended OR. So set the - * source and destination reg correctly - */ - if (PPC_21_30(dl->raw.raw_insn) == 444) { - int src_reg = src->reg1; - - src->reg1 = dst->reg1; - dst->reg1 = src_reg; - } - - if (!has_reg_type(state, dst->reg1)) - return; - - tsr = &state->regs[dst->reg1]; - - if (!has_reg_type(state, src->reg1) || - !state->regs[src->reg1].ok) { - tsr->ok = false; - return; - } - - tsr->type = state->regs[src->reg1].type; - tsr->kind = state->regs[src->reg1].kind; - tsr->ok = true; - - pr_debug_dtp("mov [%x] reg%d -> reg%d", - insn_offset, src->reg1, dst->reg1); - pr_debug_type_name(&tsr->type, tsr->kind); -} -#endif /* HAVE_LIBDW_SUPPORT */ - -static int powerpc__annotate_init(struct arch *arch, char *cpuid __maybe_unused) -{ - if (!arch->initialized) { - arch->initialized = true; - arch->associate_instruction_ops = powerpc__associate_instruction_ops; - arch->objdump.comment_char = '#'; - annotate_opts.show_asm_raw = true; - arch->e_machine = EM_PPC; - arch->e_flags = 0; - } - - return 0; -} diff --git a/tools/perf/arch/powerpc/entry/syscalls/Kbuild b/tools/perf/arch/powerpc/entry/syscalls/Kbuild deleted file mode 100644 index 84c6599b4ea6..000000000000 --- a/tools/perf/arch/powerpc/entry/syscalls/Kbuild +++ /dev/null @@ -1,3 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -syscall-y += syscalls_32.h -syscall-y += syscalls_64.h diff --git a/tools/perf/arch/powerpc/entry/syscalls/Makefile.syscalls b/tools/perf/arch/powerpc/entry/syscalls/Makefile.syscalls deleted file mode 100644 index e35afbc57c79..000000000000 --- a/tools/perf/arch/powerpc/entry/syscalls/Makefile.syscalls +++ /dev/null @@ -1,6 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 - -syscall_abis_32 += nospu -syscall_abis_64 += nospu - -syscalltbl = $(srctree)/tools/perf/arch/powerpc/entry/syscalls/syscall.tbl diff --git a/tools/perf/arch/powerpc/entry/syscalls/syscall.tbl b/tools/perf/arch/powerpc/entry/syscalls/syscall.tbl index d8b4ab78bef0..4fcc7c58a105 100644 --- a/tools/perf/arch/powerpc/entry/syscalls/syscall.tbl +++ b/tools/perf/arch/powerpc/entry/syscalls/syscall.tbl @@ -557,3 +557,8 @@ 464 common getxattrat sys_getxattrat 465 common listxattrat sys_listxattrat 466 common removexattrat sys_removexattrat +467 common open_tree_attr sys_open_tree_attr +468 common file_getattr sys_file_getattr +469 common file_setattr sys_file_setattr +470 common listns sys_listns +471 nospu rseq_slice_yield sys_rseq_slice_yield diff --git a/tools/perf/arch/powerpc/include/dwarf-regs-table.h b/tools/perf/arch/powerpc/include/dwarf-regs-table.h index 66dc015a733d..7e746cb31b66 100644 --- a/tools/perf/arch/powerpc/include/dwarf-regs-table.h +++ b/tools/perf/arch/powerpc/include/dwarf-regs-table.h @@ -7,6 +7,7 @@ * http://refspecs.linuxfoundation.org/ELF/ppc64/PPC-elf64abi-1.9.html * http://refspecs.linux-foundation.org/elf/elfspec_ppc.pdf */ +#undef REG_DWARFNUM_NAME #define REG_DWARFNUM_NAME(reg, idx) [idx] = "%" #reg static const char * const powerpc_regstr_tbl[] = { diff --git a/tools/perf/arch/powerpc/include/perf_regs.h b/tools/perf/arch/powerpc/include/perf_regs.h index 1c66f6ba6773..22b492a3dd58 100644 --- a/tools/perf/arch/powerpc/include/perf_regs.h +++ b/tools/perf/arch/powerpc/include/perf_regs.h @@ -4,7 +4,7 @@ #include <stdlib.h> #include <linux/types.h> -#include <asm/perf_regs.h> +#include "../../../../arch/powerpc/include/uapi/asm/perf_regs.h" void perf_regs_load(u64 *regs); diff --git a/tools/perf/arch/powerpc/include/syscall_table.h b/tools/perf/arch/powerpc/include/syscall_table.h deleted file mode 100644 index 7ff51b783000..000000000000 --- a/tools/perf/arch/powerpc/include/syscall_table.h +++ /dev/null @@ -1,8 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#include <asm/bitsperlong.h> - -#if __BITS_PER_LONG == 64 -#include <asm/syscalls_64.h> -#else -#include <asm/syscalls_32.h> -#endif diff --git a/tools/perf/arch/powerpc/tests/dwarf-unwind.c b/tools/perf/arch/powerpc/tests/dwarf-unwind.c index 5ecf82893b84..66af884baa66 100644 --- a/tools/perf/arch/powerpc/tests/dwarf-unwind.c +++ b/tools/perf/arch/powerpc/tests/dwarf-unwind.c @@ -45,7 +45,7 @@ static int sample_ustack(struct perf_sample *sample, int test__arch_unwind_sample(struct perf_sample *sample, struct thread *thread) { - struct regs_dump *regs = &sample->user_regs; + struct regs_dump *regs = perf_sample__user_regs(sample); u64 *buf; buf = calloc(1, sizeof(u64) * PERF_REGS_MAX); diff --git a/tools/perf/arch/powerpc/util/Build b/tools/perf/arch/powerpc/util/Build index ed82715080f9..ae928050e07a 100644 --- a/tools/perf/arch/powerpc/util/Build +++ b/tools/perf/arch/powerpc/util/Build @@ -1,13 +1,9 @@ perf-util-y += header.o -perf-util-$(CONFIG_LIBTRACEEVENT) += kvm-stat.o -perf-util-y += perf_regs.o perf-util-y += mem-events.o perf-util-y += pmu.o perf-util-y += sym-handling.o perf-util-y += evsel.o -perf-util-y += event.o perf-util-$(CONFIG_LIBDW) += skip-callchain-idx.o -perf-util-$(CONFIG_LIBUNWIND) += unwind-libunwind.o -perf-util-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o +perf-util-y += auxtrace.o diff --git a/tools/perf/arch/powerpc/util/auxtrace.c b/tools/perf/arch/powerpc/util/auxtrace.c new file mode 100644 index 000000000000..4600a1661b4f --- /dev/null +++ b/tools/perf/arch/powerpc/util/auxtrace.c @@ -0,0 +1,110 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * VPA support + */ +#include <errno.h> +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/string.h> +#include <linux/zalloc.h> + +#include "../../util/evlist.h" +#include "../../util/debug.h" +#include "../../util/auxtrace.h" +#include "../../util/powerpc-vpadtl.h" +#include "../../util/record.h" +#include <internal/lib.h> // page_size + +#define KiB(x) ((x) * 1024) + +static int +powerpc_vpadtl_recording_options(struct auxtrace_record *ar __maybe_unused, + struct evlist *evlist __maybe_unused, + struct record_opts *opts) +{ + opts->full_auxtrace = true; + + /* + * Set auxtrace_mmap_pages to minimum + * two pages + */ + if (!opts->auxtrace_mmap_pages) { + opts->auxtrace_mmap_pages = KiB(128) / page_size; + if (opts->mmap_pages == UINT_MAX) + opts->mmap_pages = KiB(256) / page_size; + } + + return 0; +} + +static size_t powerpc_vpadtl_info_priv_size(struct auxtrace_record *itr __maybe_unused, + struct evlist *evlist __maybe_unused) +{ + return VPADTL_AUXTRACE_PRIV_SIZE; +} + +static int +powerpc_vpadtl_info_fill(struct auxtrace_record *itr __maybe_unused, + struct perf_session *session __maybe_unused, + struct perf_record_auxtrace_info *auxtrace_info, + size_t priv_size __maybe_unused) +{ + auxtrace_info->type = PERF_AUXTRACE_VPA_DTL; + + return 0; +} + +static void powerpc_vpadtl_free(struct auxtrace_record *itr) +{ + free(itr); +} + +static u64 powerpc_vpadtl_reference(struct auxtrace_record *itr __maybe_unused) +{ + return 0; +} + +struct auxtrace_record *auxtrace_record__init(struct evlist *evlist, + int *err) +{ + struct auxtrace_record *aux; + struct evsel *pos; + int found = 0; + + /* + * Set err value to zero here. Any fail later + * will set appropriate return code to err. + */ + *err = 0; + + evlist__for_each_entry(evlist, pos) { + if (strstarts(pos->name, "vpa_dtl")) { + found = 1; + pos->needs_auxtrace_mmap = true; + break; + } + } + + if (!found) + return NULL; + + /* + * To obtain the auxtrace buffer file descriptor, the auxtrace event + * must come first. + */ + evlist__to_front(pos->evlist, pos); + + aux = zalloc(sizeof(*aux)); + if (aux == NULL) { + pr_debug("aux record is NULL\n"); + *err = -ENOMEM; + return NULL; + } + + aux->recording_options = powerpc_vpadtl_recording_options; + aux->info_priv_size = powerpc_vpadtl_info_priv_size; + aux->info_fill = powerpc_vpadtl_info_fill; + aux->free = powerpc_vpadtl_free; + aux->reference = powerpc_vpadtl_reference; + return aux; +} diff --git a/tools/perf/arch/powerpc/util/book3s_hcalls.h b/tools/perf/arch/powerpc/util/book3s_hcalls.h deleted file mode 100644 index 488f4339b83c..000000000000 --- a/tools/perf/arch/powerpc/util/book3s_hcalls.h +++ /dev/null @@ -1,124 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef ARCH_PERF_BOOK3S_HV_HCALLS_H -#define ARCH_PERF_BOOK3S_HV_HCALLS_H - -/* - * PowerPC HCALL codes : hcall code to name mapping - */ -#define kvm_trace_symbol_hcall \ - {0x4, "H_REMOVE"}, \ - {0x8, "H_ENTER"}, \ - {0xc, "H_READ"}, \ - {0x10, "H_CLEAR_MOD"}, \ - {0x14, "H_CLEAR_REF"}, \ - {0x18, "H_PROTECT"}, \ - {0x1c, "H_GET_TCE"}, \ - {0x20, "H_PUT_TCE"}, \ - {0x24, "H_SET_SPRG0"}, \ - {0x28, "H_SET_DABR"}, \ - {0x2c, "H_PAGE_INIT"}, \ - {0x30, "H_SET_ASR"}, \ - {0x34, "H_ASR_ON"}, \ - {0x38, "H_ASR_OFF"}, \ - {0x3c, "H_LOGICAL_CI_LOAD"}, \ - {0x40, "H_LOGICAL_CI_STORE"}, \ - {0x44, "H_LOGICAL_CACHE_LOAD"}, \ - {0x48, "H_LOGICAL_CACHE_STORE"}, \ - {0x4c, "H_LOGICAL_ICBI"}, \ - {0x50, "H_LOGICAL_DCBF"}, \ - {0x54, "H_GET_TERM_CHAR"}, \ - {0x58, "H_PUT_TERM_CHAR"}, \ - {0x5c, "H_REAL_TO_LOGICAL"}, \ - {0x60, "H_HYPERVISOR_DATA"}, \ - {0x64, "H_EOI"}, \ - {0x68, "H_CPPR"}, \ - {0x6c, "H_IPI"}, \ - {0x70, "H_IPOLL"}, \ - {0x74, "H_XIRR"}, \ - {0x78, "H_MIGRATE_DMA"}, \ - {0x7c, "H_PERFMON"}, \ - {0xdc, "H_REGISTER_VPA"}, \ - {0xe0, "H_CEDE"}, \ - {0xe4, "H_CONFER"}, \ - {0xe8, "H_PROD"}, \ - {0xec, "H_GET_PPP"}, \ - {0xf0, "H_SET_PPP"}, \ - {0xf4, "H_PURR"}, \ - {0xf8, "H_PIC"}, \ - {0xfc, "H_REG_CRQ"}, \ - {0x100, "H_FREE_CRQ"}, \ - {0x104, "H_VIO_SIGNAL"}, \ - {0x108, "H_SEND_CRQ"}, \ - {0x110, "H_COPY_RDMA"}, \ - {0x114, "H_REGISTER_LOGICAL_LAN"}, \ - {0x118, "H_FREE_LOGICAL_LAN"}, \ - {0x11c, "H_ADD_LOGICAL_LAN_BUFFER"}, \ - {0x120, "H_SEND_LOGICAL_LAN"}, \ - {0x124, "H_BULK_REMOVE"}, \ - {0x130, "H_MULTICAST_CTRL"}, \ - {0x134, "H_SET_XDABR"}, \ - {0x138, "H_STUFF_TCE"}, \ - {0x13c, "H_PUT_TCE_INDIRECT"}, \ - {0x14c, "H_CHANGE_LOGICAL_LAN_MAC"}, \ - {0x150, "H_VTERM_PARTNER_INFO"}, \ - {0x154, "H_REGISTER_VTERM"}, \ - {0x158, "H_FREE_VTERM"}, \ - {0x15c, "H_RESET_EVENTS"}, \ - {0x160, "H_ALLOC_RESOURCE"}, \ - {0x164, "H_FREE_RESOURCE"}, \ - {0x168, "H_MODIFY_QP"}, \ - {0x16c, "H_QUERY_QP"}, \ - {0x170, "H_REREGISTER_PMR"}, \ - {0x174, "H_REGISTER_SMR"}, \ - {0x178, "H_QUERY_MR"}, \ - {0x17c, "H_QUERY_MW"}, \ - {0x180, "H_QUERY_HCA"}, \ - {0x184, "H_QUERY_PORT"}, \ - {0x188, "H_MODIFY_PORT"}, \ - {0x18c, "H_DEFINE_AQP1"}, \ - {0x190, "H_GET_TRACE_BUFFER"}, \ - {0x194, "H_DEFINE_AQP0"}, \ - {0x198, "H_RESIZE_MR"}, \ - {0x19c, "H_ATTACH_MCQP"}, \ - {0x1a0, "H_DETACH_MCQP"}, \ - {0x1a4, "H_CREATE_RPT"}, \ - {0x1a8, "H_REMOVE_RPT"}, \ - {0x1ac, "H_REGISTER_RPAGES"}, \ - {0x1b0, "H_DISABLE_AND_GET"}, \ - {0x1b4, "H_ERROR_DATA"}, \ - {0x1b8, "H_GET_HCA_INFO"}, \ - {0x1bc, "H_GET_PERF_COUNT"}, \ - {0x1c0, "H_MANAGE_TRACE"}, \ - {0x1d4, "H_FREE_LOGICAL_LAN_BUFFER"}, \ - {0x1d8, "H_POLL_PENDING"}, \ - {0x1e4, "H_QUERY_INT_STATE"}, \ - {0x244, "H_ILLAN_ATTRIBUTES"}, \ - {0x250, "H_MODIFY_HEA_QP"}, \ - {0x254, "H_QUERY_HEA_QP"}, \ - {0x258, "H_QUERY_HEA"}, \ - {0x25c, "H_QUERY_HEA_PORT"}, \ - {0x260, "H_MODIFY_HEA_PORT"}, \ - {0x264, "H_REG_BCMC"}, \ - {0x268, "H_DEREG_BCMC"}, \ - {0x26c, "H_REGISTER_HEA_RPAGES"}, \ - {0x270, "H_DISABLE_AND_GET_HEA"}, \ - {0x274, "H_GET_HEA_INFO"}, \ - {0x278, "H_ALLOC_HEA_RESOURCE"}, \ - {0x284, "H_ADD_CONN"}, \ - {0x288, "H_DEL_CONN"}, \ - {0x298, "H_JOIN"}, \ - {0x2a4, "H_VASI_STATE"}, \ - {0x2b0, "H_ENABLE_CRQ"}, \ - {0x2b8, "H_GET_EM_PARMS"}, \ - {0x2d0, "H_SET_MPP"}, \ - {0x2d4, "H_GET_MPP"}, \ - {0x2ec, "H_HOME_NODE_ASSOCIATIVITY"}, \ - {0x2f4, "H_BEST_ENERGY"}, \ - {0x2fc, "H_XIRR_X"}, \ - {0x300, "H_RANDOM"}, \ - {0x304, "H_COP"}, \ - {0x314, "H_GET_MPP_X"}, \ - {0x31c, "H_SET_MODE"}, \ - {0xf000, "H_RTAS"} \ - -#endif diff --git a/tools/perf/arch/powerpc/util/book3s_hv_exits.h b/tools/perf/arch/powerpc/util/book3s_hv_exits.h deleted file mode 100644 index 2011376c7ab5..000000000000 --- a/tools/perf/arch/powerpc/util/book3s_hv_exits.h +++ /dev/null @@ -1,33 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef ARCH_PERF_BOOK3S_HV_EXITS_H -#define ARCH_PERF_BOOK3S_HV_EXITS_H - -/* - * PowerPC Interrupt vectors : exit code to name mapping - */ - -#define kvm_trace_symbol_exit \ - {0x0, "RETURN_TO_HOST"}, \ - {0x100, "SYSTEM_RESET"}, \ - {0x200, "MACHINE_CHECK"}, \ - {0x300, "DATA_STORAGE"}, \ - {0x380, "DATA_SEGMENT"}, \ - {0x400, "INST_STORAGE"}, \ - {0x480, "INST_SEGMENT"}, \ - {0x500, "EXTERNAL"}, \ - {0x502, "EXTERNAL_HV"}, \ - {0x600, "ALIGNMENT"}, \ - {0x700, "PROGRAM"}, \ - {0x800, "FP_UNAVAIL"}, \ - {0x900, "DECREMENTER"}, \ - {0x980, "HV_DECREMENTER"}, \ - {0xc00, "SYSCALL"}, \ - {0xd00, "TRACE"}, \ - {0xe00, "H_DATA_STORAGE"}, \ - {0xe20, "H_INST_STORAGE"}, \ - {0xe40, "H_EMUL_ASSIST"}, \ - {0xf00, "PERFMON"}, \ - {0xf20, "ALTIVEC"}, \ - {0xf40, "VSX"} - -#endif diff --git a/tools/perf/arch/powerpc/util/event.c b/tools/perf/arch/powerpc/util/event.c deleted file mode 100644 index 77d8cc2b5691..000000000000 --- a/tools/perf/arch/powerpc/util/event.c +++ /dev/null @@ -1,60 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -#include <linux/types.h> -#include <linux/string.h> -#include <linux/zalloc.h> - -#include "../../../util/event.h" -#include "../../../util/synthetic-events.h" -#include "../../../util/machine.h" -#include "../../../util/tool.h" -#include "../../../util/map.h" -#include "../../../util/debug.h" -#include "../../../util/sample.h" - -void arch_perf_parse_sample_weight(struct perf_sample *data, - const __u64 *array, u64 type) -{ - union perf_sample_weight weight; - - weight.full = *array; - if (type & PERF_SAMPLE_WEIGHT) - data->weight = weight.full; - else { - data->weight = weight.var1_dw; - data->ins_lat = weight.var2_w; - data->p_stage_cyc = weight.var3_w; - } -} - -void arch_perf_synthesize_sample_weight(const struct perf_sample *data, - __u64 *array, u64 type) -{ - *array = data->weight; - - if (type & PERF_SAMPLE_WEIGHT_STRUCT) { - *array &= 0xffffffff; - *array |= ((u64)data->ins_lat << 32); - } -} - -const char *arch_perf_header_entry(const char *se_header) -{ - if (!strcmp(se_header, "Local INSTR Latency")) - return "Finish Cyc"; - else if (!strcmp(se_header, "INSTR Latency")) - return "Global Finish_cyc"; - else if (!strcmp(se_header, "Local Pipeline Stage Cycle")) - return "Dispatch Cyc"; - else if (!strcmp(se_header, "Pipeline Stage Cycle")) - return "Global Dispatch_cyc"; - return se_header; -} - -int arch_support_sort_key(const char *sort_key) -{ - if (!strcmp(sort_key, "p_stage_cyc")) - return 1; - if (!strcmp(sort_key, "local_p_stage_cyc")) - return 1; - return 0; -} diff --git a/tools/perf/arch/powerpc/util/header.c b/tools/perf/arch/powerpc/util/header.c index c7df534dbf8f..0be74f048f96 100644 --- a/tools/perf/arch/powerpc/util/header.c +++ b/tools/perf/arch/powerpc/util/header.c @@ -14,8 +14,8 @@ static bool is_compat_mode(void) { - u64 base_platform = getauxval(AT_BASE_PLATFORM); - u64 platform = getauxval(AT_PLATFORM); + unsigned long base_platform = getauxval(AT_BASE_PLATFORM); + unsigned long platform = getauxval(AT_PLATFORM); if (!strcmp((char *)platform, (char *)base_platform)) return false; diff --git a/tools/perf/arch/powerpc/util/kvm-stat.c b/tools/perf/arch/powerpc/util/kvm-stat.c deleted file mode 100644 index c8357b571ccf..000000000000 --- a/tools/perf/arch/powerpc/util/kvm-stat.c +++ /dev/null @@ -1,219 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -#include <errno.h> -#include "util/kvm-stat.h" -#include "util/parse-events.h" -#include "util/debug.h" -#include "util/evsel.h" -#include "util/evlist.h" -#include "util/pmus.h" - -#include "book3s_hv_exits.h" -#include "book3s_hcalls.h" -#include <subcmd/parse-options.h> - -#define NR_TPS 4 - -const char *vcpu_id_str = "vcpu_id"; -const char *kvm_entry_trace = "kvm_hv:kvm_guest_enter"; -const char *kvm_exit_trace = "kvm_hv:kvm_guest_exit"; - -define_exit_reasons_table(hv_exit_reasons, kvm_trace_symbol_exit); -define_exit_reasons_table(hcall_reasons, kvm_trace_symbol_hcall); - -/* Tracepoints specific to ppc_book3s_hv */ -const char *ppc_book3s_hv_kvm_tp[] = { - "kvm_hv:kvm_guest_enter", - "kvm_hv:kvm_guest_exit", - "kvm_hv:kvm_hcall_enter", - "kvm_hv:kvm_hcall_exit", - NULL, -}; - -/* 1 extra placeholder for NULL */ -const char *kvm_events_tp[NR_TPS + 1]; -const char *kvm_exit_reason; - -static void hcall_event_get_key(struct evsel *evsel, - struct perf_sample *sample, - struct event_key *key) -{ - key->info = 0; - key->key = evsel__intval(evsel, sample, "req"); -} - -static const char *get_hcall_exit_reason(u64 exit_code) -{ - struct exit_reasons_table *tbl = hcall_reasons; - - while (tbl->reason != NULL) { - if (tbl->exit_code == exit_code) - return tbl->reason; - tbl++; - } - - pr_debug("Unknown hcall code: %lld\n", - (unsigned long long)exit_code); - return "UNKNOWN"; -} - -static bool hcall_event_end(struct evsel *evsel, - struct perf_sample *sample __maybe_unused, - struct event_key *key __maybe_unused) -{ - return (evsel__name_is(evsel, kvm_events_tp[3])); -} - -static bool hcall_event_begin(struct evsel *evsel, - struct perf_sample *sample, struct event_key *key) -{ - if (evsel__name_is(evsel, kvm_events_tp[2])) { - hcall_event_get_key(evsel, sample, key); - return true; - } - - return false; -} -static void hcall_event_decode_key(struct perf_kvm_stat *kvm __maybe_unused, - struct event_key *key, - char *decode) -{ - const char *hcall_reason = get_hcall_exit_reason(key->key); - - scnprintf(decode, KVM_EVENT_NAME_LEN, "%s", hcall_reason); -} - -static struct kvm_events_ops hcall_events = { - .is_begin_event = hcall_event_begin, - .is_end_event = hcall_event_end, - .decode_key = hcall_event_decode_key, - .name = "HCALL-EVENT", -}; - -static struct kvm_events_ops exit_events = { - .is_begin_event = exit_event_begin, - .is_end_event = exit_event_end, - .decode_key = exit_event_decode_key, - .name = "VM-EXIT" -}; - -struct kvm_reg_events_ops kvm_reg_events_ops[] = { - { .name = "vmexit", .ops = &exit_events }, - { .name = "hcall", .ops = &hcall_events }, - { NULL, NULL }, -}; - -const char * const kvm_skip_events[] = { - NULL, -}; - - -static int is_tracepoint_available(const char *str, struct evlist *evlist) -{ - struct parse_events_error err; - int ret; - - parse_events_error__init(&err); - ret = parse_events(evlist, str, &err); - if (ret) - parse_events_error__print(&err, "tracepoint"); - parse_events_error__exit(&err); - return ret; -} - -static int ppc__setup_book3s_hv(struct perf_kvm_stat *kvm, - struct evlist *evlist) -{ - const char **events_ptr; - int i, nr_tp = 0, err = -1; - - /* Check for book3s_hv tracepoints */ - for (events_ptr = ppc_book3s_hv_kvm_tp; *events_ptr; events_ptr++) { - err = is_tracepoint_available(*events_ptr, evlist); - if (err) - return -1; - nr_tp++; - } - - for (i = 0; i < nr_tp; i++) - kvm_events_tp[i] = ppc_book3s_hv_kvm_tp[i]; - - kvm_events_tp[i] = NULL; - kvm_exit_reason = "trap"; - kvm->exit_reasons = hv_exit_reasons; - kvm->exit_reasons_isa = "HV"; - - return 0; -} - -/* Wrapper to setup kvm tracepoints */ -static int ppc__setup_kvm_tp(struct perf_kvm_stat *kvm) -{ - struct evlist *evlist = evlist__new(); - - if (evlist == NULL) - return -ENOMEM; - - /* Right now, only supported on book3s_hv */ - return ppc__setup_book3s_hv(kvm, evlist); -} - -int setup_kvm_events_tp(struct perf_kvm_stat *kvm) -{ - return ppc__setup_kvm_tp(kvm); -} - -int cpu_isa_init(struct perf_kvm_stat *kvm, const char *cpuid __maybe_unused) -{ - int ret; - - ret = ppc__setup_kvm_tp(kvm); - if (ret) { - kvm->exit_reasons = NULL; - kvm->exit_reasons_isa = NULL; - } - - return ret; -} - -/* - * In case of powerpc architecture, pmu registers are programmable - * by guest kernel. So monitoring guest via host may not provide - * valid samples with default 'cycles' event. It is better to use - * 'trace_imc/trace_cycles' event for guest profiling, since it - * can track the guest instruction pointer in the trace-record. - * - * Function to parse the arguments and return appropriate values. - */ -int kvm_add_default_arch_event(int *argc, const char **argv) -{ - const char **tmp; - bool event = false; - int i, j = *argc; - - const struct option event_options[] = { - OPT_BOOLEAN('e', "event", &event, NULL), - OPT_END() - }; - - tmp = calloc(j + 1, sizeof(char *)); - if (!tmp) - return -EINVAL; - - for (i = 0; i < j; i++) - tmp[i] = argv[i]; - - parse_options(j, tmp, event_options, NULL, PARSE_OPT_KEEP_UNKNOWN); - if (!event) { - if (perf_pmus__have_event("trace_imc", "trace_cycles")) { - argv[j++] = strdup("-e"); - argv[j++] = strdup("trace_imc/trace_cycles/"); - *argc += 2; - } else { - free(tmp); - return -EINVAL; - } - } - - free(tmp); - return 0; -} diff --git a/tools/perf/arch/powerpc/util/perf_regs.c b/tools/perf/arch/powerpc/util/perf_regs.c deleted file mode 100644 index bd36cfd420a2..000000000000 --- a/tools/perf/arch/powerpc/util/perf_regs.c +++ /dev/null @@ -1,240 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -#include <errno.h> -#include <string.h> -#include <regex.h> -#include <linux/zalloc.h> - -#include "perf_regs.h" -#include "../../../util/perf_regs.h" -#include "../../../util/debug.h" -#include "../../../util/event.h" -#include "../../../util/header.h" -#include "../../../perf-sys.h" -#include "utils_header.h" - -#include <linux/kernel.h> - -#define PVR_POWER9 0x004E -#define PVR_POWER10 0x0080 -#define PVR_POWER11 0x0082 - -static const struct sample_reg sample_reg_masks[] = { - SMPL_REG(r0, PERF_REG_POWERPC_R0), - SMPL_REG(r1, PERF_REG_POWERPC_R1), - SMPL_REG(r2, PERF_REG_POWERPC_R2), - SMPL_REG(r3, PERF_REG_POWERPC_R3), - SMPL_REG(r4, PERF_REG_POWERPC_R4), - SMPL_REG(r5, PERF_REG_POWERPC_R5), - SMPL_REG(r6, PERF_REG_POWERPC_R6), - SMPL_REG(r7, PERF_REG_POWERPC_R7), - SMPL_REG(r8, PERF_REG_POWERPC_R8), - SMPL_REG(r9, PERF_REG_POWERPC_R9), - SMPL_REG(r10, PERF_REG_POWERPC_R10), - SMPL_REG(r11, PERF_REG_POWERPC_R11), - SMPL_REG(r12, PERF_REG_POWERPC_R12), - SMPL_REG(r13, PERF_REG_POWERPC_R13), - SMPL_REG(r14, PERF_REG_POWERPC_R14), - SMPL_REG(r15, PERF_REG_POWERPC_R15), - SMPL_REG(r16, PERF_REG_POWERPC_R16), - SMPL_REG(r17, PERF_REG_POWERPC_R17), - SMPL_REG(r18, PERF_REG_POWERPC_R18), - SMPL_REG(r19, PERF_REG_POWERPC_R19), - SMPL_REG(r20, PERF_REG_POWERPC_R20), - SMPL_REG(r21, PERF_REG_POWERPC_R21), - SMPL_REG(r22, PERF_REG_POWERPC_R22), - SMPL_REG(r23, PERF_REG_POWERPC_R23), - SMPL_REG(r24, PERF_REG_POWERPC_R24), - SMPL_REG(r25, PERF_REG_POWERPC_R25), - SMPL_REG(r26, PERF_REG_POWERPC_R26), - SMPL_REG(r27, PERF_REG_POWERPC_R27), - SMPL_REG(r28, PERF_REG_POWERPC_R28), - SMPL_REG(r29, PERF_REG_POWERPC_R29), - SMPL_REG(r30, PERF_REG_POWERPC_R30), - SMPL_REG(r31, PERF_REG_POWERPC_R31), - SMPL_REG(nip, PERF_REG_POWERPC_NIP), - SMPL_REG(msr, PERF_REG_POWERPC_MSR), - SMPL_REG(orig_r3, PERF_REG_POWERPC_ORIG_R3), - SMPL_REG(ctr, PERF_REG_POWERPC_CTR), - SMPL_REG(link, PERF_REG_POWERPC_LINK), - SMPL_REG(xer, PERF_REG_POWERPC_XER), - SMPL_REG(ccr, PERF_REG_POWERPC_CCR), - SMPL_REG(softe, PERF_REG_POWERPC_SOFTE), - SMPL_REG(trap, PERF_REG_POWERPC_TRAP), - SMPL_REG(dar, PERF_REG_POWERPC_DAR), - SMPL_REG(dsisr, PERF_REG_POWERPC_DSISR), - SMPL_REG(sier, PERF_REG_POWERPC_SIER), - SMPL_REG(mmcra, PERF_REG_POWERPC_MMCRA), - SMPL_REG(mmcr0, PERF_REG_POWERPC_MMCR0), - SMPL_REG(mmcr1, PERF_REG_POWERPC_MMCR1), - SMPL_REG(mmcr2, PERF_REG_POWERPC_MMCR2), - SMPL_REG(mmcr3, PERF_REG_POWERPC_MMCR3), - SMPL_REG(sier2, PERF_REG_POWERPC_SIER2), - SMPL_REG(sier3, PERF_REG_POWERPC_SIER3), - SMPL_REG(pmc1, PERF_REG_POWERPC_PMC1), - SMPL_REG(pmc2, PERF_REG_POWERPC_PMC2), - SMPL_REG(pmc3, PERF_REG_POWERPC_PMC3), - SMPL_REG(pmc4, PERF_REG_POWERPC_PMC4), - SMPL_REG(pmc5, PERF_REG_POWERPC_PMC5), - SMPL_REG(pmc6, PERF_REG_POWERPC_PMC6), - SMPL_REG(sdar, PERF_REG_POWERPC_SDAR), - SMPL_REG(siar, PERF_REG_POWERPC_SIAR), - SMPL_REG_END -}; - -/* REG or %rREG */ -#define SDT_OP_REGEX1 "^(%r)?([1-2]?[0-9]|3[0-1])$" - -/* -NUM(REG) or NUM(REG) or -NUM(%rREG) or NUM(%rREG) */ -#define SDT_OP_REGEX2 "^(\\-)?([0-9]+)\\((%r)?([1-2]?[0-9]|3[0-1])\\)$" - -static regex_t sdt_op_regex1, sdt_op_regex2; - -static int sdt_init_op_regex(void) -{ - static int initialized; - int ret = 0; - - if (initialized) - return 0; - - ret = regcomp(&sdt_op_regex1, SDT_OP_REGEX1, REG_EXTENDED); - if (ret) - goto error; - - ret = regcomp(&sdt_op_regex2, SDT_OP_REGEX2, REG_EXTENDED); - if (ret) - goto free_regex1; - - initialized = 1; - return 0; - -free_regex1: - regfree(&sdt_op_regex1); -error: - pr_debug4("Regex compilation error.\n"); - return ret; -} - -/* - * Parse OP and convert it into uprobe format, which is, +/-NUM(%gprREG). - * Possible variants of OP are: - * Format Example - * ------------------------- - * NUM(REG) 48(18) - * -NUM(REG) -48(18) - * NUM(%rREG) 48(%r18) - * -NUM(%rREG) -48(%r18) - * REG 18 - * %rREG %r18 - * iNUM i0 - * i-NUM i-1 - * - * SDT marker arguments on Powerpc uses %rREG form with -mregnames flag - * and REG form with -mno-regnames. Here REG is general purpose register, - * which is in 0 to 31 range. - */ -int arch_sdt_arg_parse_op(char *old_op, char **new_op) -{ - int ret, new_len; - regmatch_t rm[5]; - char prefix; - - /* Constant argument. Uprobe does not support it */ - if (old_op[0] == 'i') { - pr_debug4("Skipping unsupported SDT argument: %s\n", old_op); - return SDT_ARG_SKIP; - } - - ret = sdt_init_op_regex(); - if (ret < 0) - return ret; - - if (!regexec(&sdt_op_regex1, old_op, 3, rm, 0)) { - /* REG or %rREG --> %gprREG */ - - new_len = 5; /* % g p r NULL */ - new_len += (int)(rm[2].rm_eo - rm[2].rm_so); - - *new_op = zalloc(new_len); - if (!*new_op) - return -ENOMEM; - - scnprintf(*new_op, new_len, "%%gpr%.*s", - (int)(rm[2].rm_eo - rm[2].rm_so), old_op + rm[2].rm_so); - } else if (!regexec(&sdt_op_regex2, old_op, 5, rm, 0)) { - /* - * -NUM(REG) or NUM(REG) or -NUM(%rREG) or NUM(%rREG) --> - * +/-NUM(%gprREG) - */ - prefix = (rm[1].rm_so == -1) ? '+' : '-'; - - new_len = 8; /* +/- ( % g p r ) NULL */ - new_len += (int)(rm[2].rm_eo - rm[2].rm_so); - new_len += (int)(rm[4].rm_eo - rm[4].rm_so); - - *new_op = zalloc(new_len); - if (!*new_op) - return -ENOMEM; - - scnprintf(*new_op, new_len, "%c%.*s(%%gpr%.*s)", prefix, - (int)(rm[2].rm_eo - rm[2].rm_so), old_op + rm[2].rm_so, - (int)(rm[4].rm_eo - rm[4].rm_so), old_op + rm[4].rm_so); - } else { - pr_debug4("Skipping unsupported SDT argument: %s\n", old_op); - return SDT_ARG_SKIP; - } - - return SDT_ARG_VALID; -} - -uint64_t arch__intr_reg_mask(void) -{ - struct perf_event_attr attr = { - .type = PERF_TYPE_HARDWARE, - .config = PERF_COUNT_HW_CPU_CYCLES, - .sample_type = PERF_SAMPLE_REGS_INTR, - .precise_ip = 1, - .disabled = 1, - .exclude_kernel = 1, - }; - int fd; - u32 version; - u64 extended_mask = 0, mask = PERF_REGS_MASK; - - /* - * Get the PVR value to set the extended - * mask specific to platform. - */ - version = (((mfspr(SPRN_PVR)) >> 16) & 0xFFFF); - if (version == PVR_POWER9) - extended_mask = PERF_REG_PMU_MASK_300; - else if ((version == PVR_POWER10) || (version == PVR_POWER11)) - extended_mask = PERF_REG_PMU_MASK_31; - else - return mask; - - attr.sample_regs_intr = extended_mask; - attr.sample_period = 1; - event_attr_init(&attr); - - /* - * check if the pmu supports perf extended regs, before - * returning the register mask to sample. - */ - fd = sys_perf_event_open(&attr, 0, -1, -1, 0); - if (fd != -1) { - close(fd); - mask |= extended_mask; - } - return mask; -} - -uint64_t arch__user_reg_mask(void) -{ - return PERF_REGS_MASK; -} - -const struct sample_reg *arch__sample_reg_masks(void) -{ - return sample_reg_masks; -} diff --git a/tools/perf/arch/powerpc/util/skip-callchain-idx.c b/tools/perf/arch/powerpc/util/skip-callchain-idx.c index 356786432fd3..e57f10798fa6 100644 --- a/tools/perf/arch/powerpc/util/skip-callchain-idx.c +++ b/tools/perf/arch/powerpc/util/skip-callchain-idx.c @@ -30,14 +30,6 @@ * The libdwfl code in this file is based on code from elfutils * (libdwfl/argp-std.c, libdwfl/tests/addrcfi.c, etc). */ -static char *debuginfo_path; - -static const Dwfl_Callbacks offline_callbacks = { - .debuginfo_path = &debuginfo_path, - .find_debuginfo = dwfl_standard_find_debuginfo, - .section_address = dwfl_offline_section_address, -}; - /* * Use the DWARF expression for the Call-frame-address and determine @@ -149,44 +141,22 @@ static Dwarf_Frame *get_dwarf_frame(Dwfl_Module *mod, Dwarf_Addr pc) * yet used) * -1 in case of errors */ -static int check_return_addr(struct dso *dso, u64 map_start, Dwarf_Addr pc) +static int check_return_addr(struct dso *dso, Dwarf_Addr mapped_pc) { int rc = -1; Dwfl *dwfl; Dwfl_Module *mod; Dwarf_Frame *frame; int ra_regno; - Dwarf_Addr start = pc; - Dwarf_Addr end = pc; + Dwarf_Addr start = mapped_pc; + Dwarf_Addr end = mapped_pc; bool signalp; - const char *exec_file = dso__long_name(dso); - - dwfl = RC_CHK_ACCESS(dso)->dwfl; - - if (!dwfl) { - dwfl = dwfl_begin(&offline_callbacks); - if (!dwfl) { - pr_debug("dwfl_begin() failed: %s\n", dwarf_errmsg(-1)); - return -1; - } - - mod = dwfl_report_elf(dwfl, exec_file, exec_file, -1, - map_start, false); - if (!mod) { - pr_debug("dwfl_report_elf() failed %s\n", - dwarf_errmsg(-1)); - /* - * We normally cache the DWARF debug info and never - * call dwfl_end(). But to prevent fd leak, free in - * case of error. - */ - dwfl_end(dwfl); - goto out; - } - RC_CHK_ACCESS(dso)->dwfl = dwfl; - } - mod = dwfl_addrmodule(dwfl, pc); + dwfl = dso__libdw_dwfl(dso); + if (!dwfl) + return -1; + + mod = dwfl_addrmodule(dwfl, mapped_pc); if (!mod) { pr_debug("dwfl_addrmodule() failed, %s\n", dwarf_errmsg(-1)); goto out; @@ -196,9 +166,9 @@ static int check_return_addr(struct dso *dso, u64 map_start, Dwarf_Addr pc) * To work with split debug info files (eg: glibc), check both * .eh_frame and .debug_frame sections of the ELF header. */ - frame = get_eh_frame(mod, pc); + frame = get_eh_frame(mod, mapped_pc); if (!frame) { - frame = get_dwarf_frame(mod, pc); + frame = get_dwarf_frame(mod, mapped_pc); if (!frame) goto out; } @@ -264,7 +234,7 @@ int arch_skip_callchain_idx(struct thread *thread, struct ip_callchain *chain) return skip_slot; } - rc = check_return_addr(dso, map__start(al.map), ip); + rc = check_return_addr(dso, map__map_ip(al.map, ip)); pr_debug("[DSO %s, sym %s, ip 0x%" PRIx64 "] rc %d\n", dso__long_name(dso), al.sym->name, ip, rc); diff --git a/tools/perf/arch/powerpc/util/unwind-libdw.c b/tools/perf/arch/powerpc/util/unwind-libdw.c deleted file mode 100644 index e9a5a8bb67d9..000000000000 --- a/tools/perf/arch/powerpc/util/unwind-libdw.c +++ /dev/null @@ -1,76 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -#include <elfutils/libdwfl.h> -#include <linux/kernel.h> -#include "perf_regs.h" -#include "../../../util/unwind-libdw.h" -#include "../../../util/perf_regs.h" -#include "../../../util/sample.h" - -/* See backends/ppc_initreg.c and backends/ppc_regs.c in elfutils. */ -static const int special_regs[3][2] = { - { 65, PERF_REG_POWERPC_LINK }, - { 101, PERF_REG_POWERPC_XER }, - { 109, PERF_REG_POWERPC_CTR }, -}; - -bool libdw__arch_set_initial_registers(Dwfl_Thread *thread, void *arg) -{ - struct unwind_info *ui = arg; - struct regs_dump *user_regs = &ui->sample->user_regs; - Dwarf_Word dwarf_regs[32], dwarf_nip; - size_t i; - -#define REG(r) ({ \ - Dwarf_Word val = 0; \ - perf_reg_value(&val, user_regs, PERF_REG_POWERPC_##r); \ - val; \ -}) - - dwarf_regs[0] = REG(R0); - dwarf_regs[1] = REG(R1); - dwarf_regs[2] = REG(R2); - dwarf_regs[3] = REG(R3); - dwarf_regs[4] = REG(R4); - dwarf_regs[5] = REG(R5); - dwarf_regs[6] = REG(R6); - dwarf_regs[7] = REG(R7); - dwarf_regs[8] = REG(R8); - dwarf_regs[9] = REG(R9); - dwarf_regs[10] = REG(R10); - dwarf_regs[11] = REG(R11); - dwarf_regs[12] = REG(R12); - dwarf_regs[13] = REG(R13); - dwarf_regs[14] = REG(R14); - dwarf_regs[15] = REG(R15); - dwarf_regs[16] = REG(R16); - dwarf_regs[17] = REG(R17); - dwarf_regs[18] = REG(R18); - dwarf_regs[19] = REG(R19); - dwarf_regs[20] = REG(R20); - dwarf_regs[21] = REG(R21); - dwarf_regs[22] = REG(R22); - dwarf_regs[23] = REG(R23); - dwarf_regs[24] = REG(R24); - dwarf_regs[25] = REG(R25); - dwarf_regs[26] = REG(R26); - dwarf_regs[27] = REG(R27); - dwarf_regs[28] = REG(R28); - dwarf_regs[29] = REG(R29); - dwarf_regs[30] = REG(R30); - dwarf_regs[31] = REG(R31); - if (!dwfl_thread_state_registers(thread, 0, 32, dwarf_regs)) - return false; - - dwarf_nip = REG(NIP); - dwfl_thread_state_register_pc(thread, dwarf_nip); - for (i = 0; i < ARRAY_SIZE(special_regs); i++) { - Dwarf_Word val = 0; - perf_reg_value(&val, user_regs, special_regs[i][1]); - if (!dwfl_thread_state_registers(thread, - special_regs[i][0], 1, - &val)) - return false; - } - - return true; -} diff --git a/tools/perf/arch/powerpc/util/unwind-libunwind.c b/tools/perf/arch/powerpc/util/unwind-libunwind.c deleted file mode 100644 index 90a6beda20de..000000000000 --- a/tools/perf/arch/powerpc/util/unwind-libunwind.c +++ /dev/null @@ -1,92 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Copyright 2016 Chandan Kumar, IBM Corporation. - */ - -#include <errno.h> -#include <libunwind.h> -#include <asm/perf_regs.h> -#include "../../util/unwind.h" -#include "../../util/debug.h" - -int libunwind__arch_reg_id(int regnum) -{ - switch (regnum) { - case UNW_PPC64_R0: - return PERF_REG_POWERPC_R0; - case UNW_PPC64_R1: - return PERF_REG_POWERPC_R1; - case UNW_PPC64_R2: - return PERF_REG_POWERPC_R2; - case UNW_PPC64_R3: - return PERF_REG_POWERPC_R3; - case UNW_PPC64_R4: - return PERF_REG_POWERPC_R4; - case UNW_PPC64_R5: - return PERF_REG_POWERPC_R5; - case UNW_PPC64_R6: - return PERF_REG_POWERPC_R6; - case UNW_PPC64_R7: - return PERF_REG_POWERPC_R7; - case UNW_PPC64_R8: - return PERF_REG_POWERPC_R8; - case UNW_PPC64_R9: - return PERF_REG_POWERPC_R9; - case UNW_PPC64_R10: - return PERF_REG_POWERPC_R10; - case UNW_PPC64_R11: - return PERF_REG_POWERPC_R11; - case UNW_PPC64_R12: - return PERF_REG_POWERPC_R12; - case UNW_PPC64_R13: - return PERF_REG_POWERPC_R13; - case UNW_PPC64_R14: - return PERF_REG_POWERPC_R14; - case UNW_PPC64_R15: - return PERF_REG_POWERPC_R15; - case UNW_PPC64_R16: - return PERF_REG_POWERPC_R16; - case UNW_PPC64_R17: - return PERF_REG_POWERPC_R17; - case UNW_PPC64_R18: - return PERF_REG_POWERPC_R18; - case UNW_PPC64_R19: - return PERF_REG_POWERPC_R19; - case UNW_PPC64_R20: - return PERF_REG_POWERPC_R20; - case UNW_PPC64_R21: - return PERF_REG_POWERPC_R21; - case UNW_PPC64_R22: - return PERF_REG_POWERPC_R22; - case UNW_PPC64_R23: - return PERF_REG_POWERPC_R23; - case UNW_PPC64_R24: - return PERF_REG_POWERPC_R24; - case UNW_PPC64_R25: - return PERF_REG_POWERPC_R25; - case UNW_PPC64_R26: - return PERF_REG_POWERPC_R26; - case UNW_PPC64_R27: - return PERF_REG_POWERPC_R27; - case UNW_PPC64_R28: - return PERF_REG_POWERPC_R28; - case UNW_PPC64_R29: - return PERF_REG_POWERPC_R29; - case UNW_PPC64_R30: - return PERF_REG_POWERPC_R30; - case UNW_PPC64_R31: - return PERF_REG_POWERPC_R31; - case UNW_PPC64_LR: - return PERF_REG_POWERPC_LINK; - case UNW_PPC64_CTR: - return PERF_REG_POWERPC_CTR; - case UNW_PPC64_XER: - return PERF_REG_POWERPC_XER; - case UNW_PPC64_NIP: - return PERF_REG_POWERPC_NIP; - default: - pr_err("unwind: invalid reg id %d\n", regnum); - return -EINVAL; - } - return -EINVAL; -} |
