perf_event.c 1.7 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Linux performance counter support for MIPS.
  4. *
  5. * Copyright (C) 2010 MIPS Technologies, Inc.
  6. * Author: Deng-Cheng Zhu
  7. *
  8. * This code is based on the implementation for ARM, which is in turn
  9. * based on the sparc64 perf event code and the x86 code. Performance
  10. * counter access is based on the MIPS Oprofile code. And the callchain
  11. * support references the code of MIPS stacktrace.c.
  12. */
  13. #include <linux/perf_event.h>
  14. #include <linux/sched/task_stack.h>
  15. #include <asm/stacktrace.h>
  16. /* Callchain handling code. */
  17. /*
  18. * Leave userspace callchain empty for now. When we find a way to trace
  19. * the user stack callchains, we will add it here.
  20. */
  21. static void save_raw_perf_callchain(struct perf_callchain_entry_ctx *entry,
  22. unsigned long reg29)
  23. {
  24. unsigned long *sp = (unsigned long *)reg29;
  25. unsigned long addr;
  26. while (!kstack_end(sp)) {
  27. addr = *sp++;
  28. if (__kernel_text_address(addr)) {
  29. perf_callchain_store(entry, addr);
  30. if (entry->nr >= entry->max_stack)
  31. break;
  32. }
  33. }
  34. }
  35. void perf_callchain_kernel(struct perf_callchain_entry_ctx *entry,
  36. struct pt_regs *regs)
  37. {
  38. unsigned long sp = regs->regs[29];
  39. #ifdef CONFIG_KALLSYMS
  40. unsigned long ra = regs->regs[31];
  41. unsigned long pc = regs->cp0_epc;
  42. if (raw_show_trace || !__kernel_text_address(pc)) {
  43. unsigned long stack_page =
  44. (unsigned long)task_stack_page(current);
  45. if (stack_page && sp >= stack_page &&
  46. sp <= stack_page + THREAD_SIZE - 32)
  47. save_raw_perf_callchain(entry, sp);
  48. return;
  49. }
  50. do {
  51. perf_callchain_store(entry, pc);
  52. if (entry->nr >= entry->max_stack)
  53. break;
  54. pc = unwind_stack(current, &sp, pc, &ra);
  55. } while (pc);
  56. #else
  57. save_raw_perf_callchain(entry, sp);
  58. #endif
  59. }