aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/mips/kernel/perf_event.c63
1 files changed, 6 insertions, 57 deletions
diff --git a/arch/mips/kernel/perf_event.c b/arch/mips/kernel/perf_event.c
index 3d55761146e5..8f7d2f84d095 100644
--- a/arch/mips/kernel/perf_event.c
+++ b/arch/mips/kernel/perf_event.c
@@ -534,21 +534,13 @@ handle_associated_event(struct cpu_hw_events *cpuc,
534#include "perf_event_mipsxx.c" 534#include "perf_event_mipsxx.c"
535 535
536/* Callchain handling code. */ 536/* Callchain handling code. */
537static inline void
538callchain_store(struct perf_callchain_entry *entry,
539 u64 ip)
540{
541 if (entry->nr < PERF_MAX_STACK_DEPTH)
542 entry->ip[entry->nr++] = ip;
543}
544 537
545/* 538/*
546 * Leave userspace callchain empty for now. When we find a way to trace 539 * Leave userspace callchain empty for now. When we find a way to trace
547 * the user stack callchains, we add here. 540 * the user stack callchains, we add here.
548 */ 541 */
549static void 542void perf_callchain_user(struct perf_callchain_entry *entry,
550perf_callchain_user(struct pt_regs *regs, 543 struct pt_regs *regs)
551 struct perf_callchain_entry *entry)
552{ 544{
553} 545}
554 546
@@ -561,23 +553,21 @@ static void save_raw_perf_callchain(struct perf_callchain_entry *entry,
561 while (!kstack_end(sp)) { 553 while (!kstack_end(sp)) {
562 addr = *sp++; 554 addr = *sp++;
563 if (__kernel_text_address(addr)) { 555 if (__kernel_text_address(addr)) {
564 callchain_store(entry, addr); 556 perf_callchain_store(entry, addr);
565 if (entry->nr >= PERF_MAX_STACK_DEPTH) 557 if (entry->nr >= PERF_MAX_STACK_DEPTH)
566 break; 558 break;
567 } 559 }
568 } 560 }
569} 561}
570 562
571static void 563void perf_callchain_kernel(struct perf_callchain_entry *entry,
572perf_callchain_kernel(struct pt_regs *regs, 564 struct pt_regs *regs)
573 struct perf_callchain_entry *entry)
574{ 565{
575 unsigned long sp = regs->regs[29]; 566 unsigned long sp = regs->regs[29];
576#ifdef CONFIG_KALLSYMS 567#ifdef CONFIG_KALLSYMS
577 unsigned long ra = regs->regs[31]; 568 unsigned long ra = regs->regs[31];
578 unsigned long pc = regs->cp0_epc; 569 unsigned long pc = regs->cp0_epc;
579 570
580 callchain_store(entry, PERF_CONTEXT_KERNEL);
581 if (raw_show_trace || !__kernel_text_address(pc)) { 571 if (raw_show_trace || !__kernel_text_address(pc)) {
582 unsigned long stack_page = 572 unsigned long stack_page =
583 (unsigned long)task_stack_page(current); 573 (unsigned long)task_stack_page(current);
@@ -587,53 +577,12 @@ perf_callchain_kernel(struct pt_regs *regs,
587 return; 577 return;
588 } 578 }
589 do { 579 do {
590 callchain_store(entry, pc); 580 perf_callchain_store(entry, pc);
591 if (entry->nr >= PERF_MAX_STACK_DEPTH) 581 if (entry->nr >= PERF_MAX_STACK_DEPTH)
592 break; 582 break;
593 pc = unwind_stack(current, &sp, pc, &ra); 583 pc = unwind_stack(current, &sp, pc, &ra);
594 } while (pc); 584 } while (pc);
595#else 585#else
596 callchain_store(entry, PERF_CONTEXT_KERNEL);
597 save_raw_perf_callchain(entry, sp); 586 save_raw_perf_callchain(entry, sp);
598#endif 587#endif
599} 588}
600
601static void
602perf_do_callchain(struct pt_regs *regs,
603 struct perf_callchain_entry *entry)
604{
605 int is_user;
606
607 if (!regs)
608 return;
609
610 is_user = user_mode(regs);
611
612 if (!current || !current->pid)
613 return;
614
615 if (is_user && current->state != TASK_RUNNING)
616 return;
617
618 if (!is_user) {
619 perf_callchain_kernel(regs, entry);
620 if (current->mm)
621 regs = task_pt_regs(current);
622 else
623 regs = NULL;
624 }
625 if (regs)
626 perf_callchain_user(regs, entry);
627}
628
629static DEFINE_PER_CPU(struct perf_callchain_entry, pmc_irq_entry);
630
631struct perf_callchain_entry *
632perf_callchain(struct pt_regs *regs)
633{
634 struct perf_callchain_entry *entry = &__get_cpu_var(pmc_irq_entry);
635
636 entry->nr = 0;
637 perf_do_callchain(regs, entry);
638 return entry;
639}