summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIgor Nabirushkin <inabirushkin@nvidia.com>2015-03-16 19:13:33 +0400
committerWinnie Hsu <whsu@nvidia.com>2015-05-29 14:27:04 -0700
commit7b3154608145006f8f1373ba31b4f0cc9e579054 (patch)
tree350a1a76f7aaf0971ed24079b2c476069afe7474
parente7ee0bf5d1229e6f7d507e8d8929860410f6a854 (diff)
misc: tegra-profiler: add unwind reason codes
Unwinding: store individual URC codes for each method. Bug 1624134 Change-Id: I3b2045f9c9147354f3440e326fd3aeccb5e0458d Signed-off-by: Igor Nabirushkin <inabirushkin@nvidia.com> Reviewed-on: http://git-master/r/717848 (cherry picked from commit e5ceff53d63e668a19d36196823f6c185ce48e88) Reviewed-on: http://git-master/r/748086 GVS: Gerrit_Virtual_Submit Reviewed-by: Andrey Trachenko <atrachenko@nvidia.com> Reviewed-by: Winnie Hsu <whsu@nvidia.com>
-rw-r--r--drivers/misc/tegra-profiler/backtrace.c123
-rw-r--r--drivers/misc/tegra-profiler/backtrace.h15
-rw-r--r--drivers/misc/tegra-profiler/comm.c1
-rw-r--r--drivers/misc/tegra-profiler/dwarf_unwind.c18
-rw-r--r--drivers/misc/tegra-profiler/eh_unwind.c14
-rw-r--r--drivers/misc/tegra-profiler/hrt.c65
-rw-r--r--drivers/misc/tegra-profiler/hrt.h4
-rw-r--r--drivers/misc/tegra-profiler/ma.c2
-rw-r--r--drivers/misc/tegra-profiler/main.c12
-rw-r--r--drivers/misc/tegra-profiler/version.h2
-rw-r--r--include/linux/tegra_profiler.h38
11 files changed, 142 insertions, 152 deletions
diff --git a/drivers/misc/tegra-profiler/backtrace.c b/drivers/misc/tegra-profiler/backtrace.c
index 2dc39b1d018c..2d947615978d 100644
--- a/drivers/misc/tegra-profiler/backtrace.c
+++ b/drivers/misc/tegra-profiler/backtrace.c
@@ -29,6 +29,12 @@
#include "hrt.h"
#include "tegra.h"
+static inline int
+is_table_unwinding(struct quadd_callchain *cc)
+{
+ return cc->um.ut || cc->um.dwarf;
+}
+
unsigned long
quadd_user_stack_pointer(struct pt_regs *regs)
{
@@ -87,12 +93,12 @@ quadd_callchain_store(struct quadd_callchain *cc,
unsigned long low_addr = cc->hrt->low_addr;
if (ip < low_addr || !validate_pc_addr(ip, sizeof(unsigned long))) {
- cc->unw_rc = QUADD_URC_PC_INCORRECT;
+ cc->urc_fp = QUADD_URC_PC_INCORRECT;
return 0;
}
if (cc->nr >= QUADD_MAX_STACK_DEPTH) {
- cc->unw_rc = QUADD_URC_LEVEL_TOO_DEEP;
+ cc->urc_fp = QUADD_URC_LEVEL_TOO_DEEP;
return 0;
}
@@ -130,7 +136,7 @@ user_backtrace(struct pt_regs *regs,
return NULL;
if (__copy_from_user_inatomic(&value, tail, sizeof(unsigned long))) {
- cc->unw_rc = QUADD_URC_EACCESS;
+ cc->urc_fp = QUADD_URC_EACCESS;
return NULL;
}
@@ -144,7 +150,7 @@ user_backtrace(struct pt_regs *regs,
if (__copy_from_user_inatomic(&value_lr, tail + 1,
sizeof(value_lr))) {
- cc->unw_rc = QUADD_URC_EACCESS;
+ cc->urc_fp = QUADD_URC_EACCESS;
return NULL;
}
@@ -155,7 +161,7 @@ user_backtrace(struct pt_regs *regs,
/* gcc arm frame */
if (__copy_from_user_inatomic(&value_fp, tail - 1,
sizeof(value_fp))) {
- cc->unw_rc = QUADD_URC_EACCESS;
+ cc->urc_fp = QUADD_URC_EACCESS;
return NULL;
}
@@ -175,7 +181,7 @@ user_backtrace(struct pt_regs *regs,
if (nr_added == 0)
return NULL;
- if (cc->unw_method == QUADD_UNW_METHOD_MIXED &&
+ if (is_table_unwinding(cc) &&
is_ex_entry_exist(regs, value_lr, task))
return NULL;
@@ -193,10 +199,10 @@ get_user_callchain_fp(struct pt_regs *regs,
struct mm_struct *mm = task->mm;
cc->nr = 0;
- cc->unw_rc = QUADD_URC_FP_INCORRECT;
+ cc->urc_fp = QUADD_URC_FP_INCORRECT;
if (!regs || !mm) {
- cc->unw_rc = QUADD_URC_FAILURE;
+ cc->urc_fp = QUADD_URC_FAILURE;
return 0;
}
@@ -209,7 +215,7 @@ get_user_callchain_fp(struct pt_regs *regs,
vma = find_vma(mm, sp);
if (!vma) {
- cc->unw_rc = QUADD_URC_SP_INCORRECT;
+ cc->urc_fp = QUADD_URC_SP_INCORRECT;
return 0;
}
@@ -218,7 +224,7 @@ get_user_callchain_fp(struct pt_regs *regs,
if (probe_kernel_address(fp, reg)) {
pr_warn_once("%s: failed for address: %#lx\n", __func__, fp);
- cc->unw_rc = QUADD_URC_EACCESS;
+ cc->urc_fp = QUADD_URC_EACCESS;
return 0;
}
@@ -239,7 +245,7 @@ get_user_callchain_fp(struct pt_regs *regs,
&value,
(unsigned long __user *)fp + 1,
sizeof(unsigned long))) {
- cc->unw_rc = QUADD_URC_EACCESS;
+ cc->urc_fp = QUADD_URC_EACCESS;
return 0;
}
@@ -279,16 +285,16 @@ __user_backtrace(struct pt_regs *regs,
struct vm_area_struct *vma;
unsigned long __user *tail;
- cc->unw_rc = QUADD_URC_FP_INCORRECT;
+ cc->urc_fp = QUADD_URC_FP_INCORRECT;
if (!mm) {
- cc->unw_rc = QUADD_URC_FAILURE;
+ cc->urc_fp = QUADD_URC_FAILURE;
return cc->nr;
}
vma = find_vma(mm, cc->curr_sp);
if (!vma) {
- cc->unw_rc = QUADD_URC_SP_INCORRECT;
+ cc->urc_fp = QUADD_URC_SP_INCORRECT;
return cc->nr;
}
@@ -316,7 +322,7 @@ user_backtrace_compat(struct pt_regs *regs,
return NULL;
if (__copy_from_user_inatomic(&value, tail, sizeof(value))) {
- cc->unw_rc = QUADD_URC_EACCESS;
+ cc->urc_fp = QUADD_URC_EACCESS;
return NULL;
}
@@ -330,7 +336,7 @@ user_backtrace_compat(struct pt_regs *regs,
if (__copy_from_user_inatomic(&value_lr, tail + 1,
sizeof(value_lr))) {
- cc->unw_rc = QUADD_URC_EACCESS;
+ cc->urc_fp = QUADD_URC_EACCESS;
return NULL;
}
@@ -341,7 +347,7 @@ user_backtrace_compat(struct pt_regs *regs,
/* gcc arm frame */
if (__copy_from_user_inatomic(&value_fp, tail - 1,
sizeof(value_fp))) {
- cc->unw_rc = QUADD_URC_EACCESS;
+ cc->urc_fp = QUADD_URC_EACCESS;
return NULL;
}
@@ -361,7 +367,7 @@ user_backtrace_compat(struct pt_regs *regs,
if (nr_added == 0)
return NULL;
- if (cc->unw_method == QUADD_UNW_METHOD_MIXED &&
+ if (is_table_unwinding(cc) &&
is_ex_entry_exist(regs, value_lr, task))
return NULL;
@@ -379,10 +385,10 @@ get_user_callchain_fp_compat(struct pt_regs *regs,
struct mm_struct *mm = task->mm;
cc->nr = 0;
- cc->unw_rc = QUADD_URC_FP_INCORRECT;
+ cc->urc_fp = QUADD_URC_FP_INCORRECT;
if (!regs || !mm) {
- cc->unw_rc = QUADD_URC_FAILURE;
+ cc->urc_fp = QUADD_URC_FAILURE;
return 0;
}
@@ -395,7 +401,7 @@ get_user_callchain_fp_compat(struct pt_regs *regs,
vma = find_vma(mm, sp);
if (!vma) {
- cc->unw_rc = QUADD_URC_SP_INCORRECT;
+ cc->urc_fp = QUADD_URC_SP_INCORRECT;
return 0;
}
@@ -404,7 +410,7 @@ get_user_callchain_fp_compat(struct pt_regs *regs,
if (probe_kernel_address((unsigned long)fp, reg)) {
pr_warn_once("%s: failed for address: %#x\n", __func__, fp);
- cc->unw_rc = QUADD_URC_EACCESS;
+ cc->urc_fp = QUADD_URC_EACCESS;
return 0;
}
@@ -425,7 +431,7 @@ get_user_callchain_fp_compat(struct pt_regs *regs,
&value,
(u32 __user *)(fp + sizeof(u32)),
sizeof(value))) {
- cc->unw_rc = QUADD_URC_EACCESS;
+ cc->urc_fp = QUADD_URC_EACCESS;
return 0;
}
@@ -465,16 +471,16 @@ __user_backtrace_compat(struct pt_regs *regs,
struct vm_area_struct *vma;
u32 __user *tail;
- cc->unw_rc = QUADD_URC_FP_INCORRECT;
+ cc->urc_fp = QUADD_URC_FP_INCORRECT;
if (!mm) {
- cc->unw_rc = QUADD_URC_FAILURE;
+ cc->urc_fp = QUADD_URC_FAILURE;
return cc->nr;
}
vma = find_vma(mm, cc->curr_sp);
if (!vma) {
- cc->unw_rc = QUADD_URC_SP_INCORRECT;
+ cc->urc_fp = QUADD_URC_SP_INCORRECT;
return cc->nr;
}
@@ -494,7 +500,7 @@ __get_user_callchain_fp(struct pt_regs *regs,
struct task_struct *task)
{
if (cc->nr > 0) {
- if (cc->unw_rc == QUADD_URC_LEVEL_TOO_DEEP)
+ if (cc->urc_fp == QUADD_URC_LEVEL_TOO_DEEP)
return cc->nr;
#ifdef CONFIG_ARM64
@@ -518,44 +524,22 @@ __get_user_callchain_fp(struct pt_regs *regs,
}
static unsigned int
-get_user_callchain_ut(struct pt_regs *regs,
- struct quadd_callchain *cc,
- struct task_struct *task)
-{
- int nr_prev;
- unsigned long prev_sp;
-
- do {
- nr_prev = cc->nr;
- prev_sp = cc->curr_sp;
-
- quadd_get_user_cc_dwarf(regs, cc, task);
- if (nr_prev > 0 && cc->nr == nr_prev)
- break;
-
- nr_prev = cc->nr;
-
- quadd_get_user_cc_arm32_ehabi(regs, cc, task);
- } while (nr_prev != cc->nr &&
- (cc->nr <= 1 || cc->curr_sp > prev_sp));
-
- return cc->nr;
-}
-
-static unsigned int
get_user_callchain_mixed(struct pt_regs *regs,
struct quadd_callchain *cc,
struct task_struct *task)
{
int nr_prev;
unsigned long prev_sp;
+ struct quadd_unw_methods *um = &cc->um;
do {
nr_prev = cc->nr;
prev_sp = cc->curr_sp;
- quadd_get_user_cc_dwarf(regs, cc, task);
- quadd_get_user_cc_arm32_ehabi(regs, cc, task);
+ if (um->dwarf)
+ quadd_get_user_cc_dwarf(regs, cc, task);
+ if (um->ut)
+ quadd_get_user_cc_arm32_ehabi(regs, cc, task);
if (nr_prev != cc->nr) {
if (cc->nr > 1 &&
@@ -565,7 +549,8 @@ get_user_callchain_mixed(struct pt_regs *regs,
continue;
}
- __get_user_callchain_fp(regs, cc, task);
+ if (um->fp)
+ __get_user_callchain_fp(regs, cc, task);
} while (nr_prev != cc->nr &&
(cc->nr <= 1 || cc->curr_sp > prev_sp));
@@ -578,12 +563,12 @@ quadd_get_user_callchain(struct pt_regs *regs,
struct quadd_ctx *ctx,
struct task_struct *task)
{
- unsigned int method = cc->unw_method;
-
cc->nr = 0;
if (!regs) {
- cc->unw_rc = QUADD_URC_FAILURE;
+ cc->urc_fp = QUADD_URC_FAILURE;
+ cc->urc_ut = QUADD_URC_FAILURE;
+ cc->urc_dwarf = QUADD_URC_FAILURE;
return 0;
}
@@ -598,25 +583,11 @@ quadd_get_user_callchain(struct pt_regs *regs,
cc->cs_64 = 0;
#endif
- cc->unw_rc = 0;
-
- switch (method) {
- case QUADD_UNW_METHOD_FP:
- __get_user_callchain_fp(regs, cc, task);
- break;
+ cc->urc_fp = QUADD_URC_NONE;
+ cc->urc_ut = QUADD_URC_NONE;
+ cc->urc_dwarf = QUADD_URC_NONE;
- case QUADD_UNW_METHOD_EHT:
- get_user_callchain_ut(regs, cc, task);
- break;
-
- case QUADD_UNW_METHOD_MIXED:
- get_user_callchain_mixed(regs, cc, task);
- break;
-
- case QUADD_UNW_METHOD_NONE:
- default:
- break;
- }
+ get_user_callchain_mixed(regs, cc, task);
return cc->nr;
}
diff --git a/drivers/misc/tegra-profiler/backtrace.h b/drivers/misc/tegra-profiler/backtrace.h
index 5ee544cdd496..724c614a9408 100644
--- a/drivers/misc/tegra-profiler/backtrace.h
+++ b/drivers/misc/tegra-profiler/backtrace.h
@@ -27,6 +27,14 @@
struct quadd_hrt_ctx;
+struct quadd_unw_methods {
+ unsigned int
+ fp:1,
+ ut:1,
+ ut_ce:1,
+ dwarf:1;
+};
+
struct quadd_callchain {
int nr;
@@ -39,8 +47,11 @@ struct quadd_callchain {
int cs_64;
- unsigned int unw_method;
- unsigned int unw_rc;
+ struct quadd_unw_methods um;
+
+ unsigned int urc_fp;
+ unsigned int urc_ut;
+ unsigned int urc_dwarf;
unsigned long curr_sp;
unsigned long curr_fp;
diff --git a/drivers/misc/tegra-profiler/comm.c b/drivers/misc/tegra-profiler/comm.c
index 7c4b6fcb1a7a..2d70f6318d3e 100644
--- a/drivers/misc/tegra-profiler/comm.c
+++ b/drivers/misc/tegra-profiler/comm.c
@@ -370,6 +370,7 @@ init_mmap_hdr(struct quadd_mmap_rb_info *mmap_rb,
mmap_hdr->magic = QUADD_MMAP_HEADER_MAGIC;
mmap_hdr->version = QUADD_MMAP_HEADER_VERSION;
mmap_hdr->cpu_id = cpu_id;
+ mmap_hdr->samples_version = QUADD_SAMPLES_VERSION;
rb_hdr = (struct quadd_ring_buffer_hdr *)(mmap_hdr + 1);
rb->rb_hdr = rb_hdr;
diff --git a/drivers/misc/tegra-profiler/dwarf_unwind.c b/drivers/misc/tegra-profiler/dwarf_unwind.c
index ef5c4ad420eb..2e624352c4b7 100644
--- a/drivers/misc/tegra-profiler/dwarf_unwind.c
+++ b/drivers/misc/tegra-profiler/dwarf_unwind.c
@@ -1905,7 +1905,7 @@ unwind_backtrace(struct quadd_callchain *cc,
unsigned int unw_type;
int is_eh = 1, mode = sf->mode;
- cc->unw_rc = QUADD_URC_FAILURE;
+ cc->urc_dwarf = QUADD_URC_FAILURE;
user_reg_size = get_user_reg_size(mode);
while (1) {
@@ -1922,7 +1922,7 @@ unwind_backtrace(struct quadd_callchain *cc,
sp = sf->vregs[regnum_sp(mode)];
if (!validate_stack_addr(sp, vma_sp, user_reg_size)) {
- cc->unw_rc = -QUADD_URC_SP_INCORRECT;
+ cc->urc_dwarf = QUADD_URC_SP_INCORRECT;
break;
}
@@ -1935,7 +1935,7 @@ unwind_backtrace(struct quadd_callchain *cc,
if (!is_vma_addr(addr, vma_pc, user_reg_size)) {
err = quadd_get_dw_frames(vma_pc->vm_start, &ri_new);
if (err) {
- cc->unw_rc = QUADD_URC_TBL_NOT_EXIST;
+ cc->urc_dwarf = QUADD_URC_TBL_NOT_EXIST;
break;
}
@@ -1947,7 +1947,7 @@ unwind_backtrace(struct quadd_callchain *cc,
if (!is_fde_entry_exist(ri, sf->pc, &__is_eh, &__is_debug)) {
pr_debug("eh/debug fde entries are not existed\n");
- cc->unw_rc = QUADD_URC_IDX_NOT_FOUND;
+ cc->urc_dwarf = QUADD_URC_IDX_NOT_FOUND;
break;
}
pr_debug("is_eh: %d, is_debug: %d\n", __is_eh, __is_debug);
@@ -1967,11 +1967,11 @@ unwind_backtrace(struct quadd_callchain *cc,
err = unwind_frame(ri, sf, vma_sp, is_eh);
if (err < 0) {
- cc->unw_rc = -err;
+ cc->urc_dwarf = -err;
break;
}
} else {
- cc->unw_rc = -err;
+ cc->urc_dwarf = -err;
break;
}
}
@@ -2038,10 +2038,10 @@ quadd_get_user_cc_dwarf(struct pt_regs *regs,
if (!regs || !mm)
return 0;
- if (cc->unw_rc == QUADD_URC_LEVEL_TOO_DEEP)
+ if (cc->urc_dwarf == QUADD_URC_LEVEL_TOO_DEEP)
return nr_prev;
- cc->unw_rc = QUADD_URC_FAILURE;
+ cc->urc_dwarf = QUADD_URC_FAILURE;
if (nr_prev > 0) {
ip = cc->curr_pc;
@@ -2109,7 +2109,7 @@ quadd_get_user_cc_dwarf(struct pt_regs *regs,
err = quadd_get_dw_frames(vma->vm_start, &ri);
if (err) {
- cc->unw_rc = QUADD_URC_TBL_NOT_EXIST;
+ cc->urc_dwarf = QUADD_URC_TBL_NOT_EXIST;
return 0;
}
diff --git a/drivers/misc/tegra-profiler/eh_unwind.c b/drivers/misc/tegra-profiler/eh_unwind.c
index bfbcd144822f..b48765678aee 100644
--- a/drivers/misc/tegra-profiler/eh_unwind.c
+++ b/drivers/misc/tegra-profiler/eh_unwind.c
@@ -1060,7 +1060,7 @@ unwind_backtrace(struct quadd_callchain *cc,
{
struct ex_region_info ri_new;
- cc->unw_rc = QUADD_URC_FAILURE;
+ cc->urc_ut = QUADD_URC_FAILURE;
pr_debug("fp_arm: %#lx, fp_thumb: %#lx, sp: %#lx, lr: %#lx, pc: %#lx\n",
frame->fp_arm, frame->fp_thumb,
@@ -1081,7 +1081,7 @@ unwind_backtrace(struct quadd_callchain *cc,
break;
if (!validate_stack_addr(frame->sp, vma_sp, sizeof(u32))) {
- cc->unw_rc = -QUADD_URC_SP_INCORRECT;
+ cc->urc_ut = QUADD_URC_SP_INCORRECT;
break;
}
@@ -1094,7 +1094,7 @@ unwind_backtrace(struct quadd_callchain *cc,
if (!is_vma_addr(ti->addr, vma_pc, sizeof(u32))) {
err = get_extabs_ehabi(vma_pc->vm_start, &ri_new);
if (err) {
- cc->unw_rc = QUADD_URC_TBL_NOT_EXIST;
+ cc->urc_ut = QUADD_URC_TBL_NOT_EXIST;
break;
}
@@ -1104,7 +1104,7 @@ unwind_backtrace(struct quadd_callchain *cc,
err = unwind_frame(ri, frame, vma_sp);
if (err < 0) {
pr_debug("end unwind, urc: %ld\n", err);
- cc->unw_rc = -err;
+ cc->urc_ut = -err;
break;
}
@@ -1144,10 +1144,10 @@ quadd_get_user_cc_arm32_ehabi(struct pt_regs *regs,
return 0;
#endif
- if (cc->unw_rc == QUADD_URC_LEVEL_TOO_DEEP)
+ if (cc->urc_ut == QUADD_URC_LEVEL_TOO_DEEP)
return nr_prev;
- cc->unw_rc = QUADD_URC_FAILURE;
+ cc->urc_ut = QUADD_URC_FAILURE;
if (nr_prev > 0) {
ip = cc->curr_pc;
@@ -1188,7 +1188,7 @@ quadd_get_user_cc_arm32_ehabi(struct pt_regs *regs,
err = get_extabs_ehabi(vma->vm_start, &ri);
if (err) {
- cc->unw_rc = QUADD_URC_TBL_NOT_EXIST;
+ cc->urc_ut = QUADD_URC_TBL_NOT_EXIST;
return 0;
}
diff --git a/drivers/misc/tegra-profiler/hrt.c b/drivers/misc/tegra-profiler/hrt.c
index 88a0d967e096..214b79c56aeb 100644
--- a/drivers/misc/tegra-profiler/hrt.c
+++ b/drivers/misc/tegra-profiler/hrt.c
@@ -62,7 +62,7 @@ static enum hrtimer_restart hrtimer_handler(struct hrtimer *hrtimer)
regs = get_irq_regs();
- if (!hrt.active)
+ if (!atomic_read(&hrt.active))
return HRTIMER_NORESTART;
qm_debug_handler_sample(regs);
@@ -193,7 +193,14 @@ static void put_header(void)
hdr->reserved = 0;
hdr->extra_length = 0;
- hdr->reserved |= hrt.unw_method << QUADD_HDR_UNW_METHOD_SHIFT;
+ if (hdr->backtrace) {
+ struct quadd_unw_methods *um = &hrt.um;
+
+ hdr->reserved |= um->fp ? QUADD_HDR_BT_FP : 0;
+ hdr->reserved |= um->ut ? QUADD_HDR_BT_UT : 0;
+ hdr->reserved |= um->ut_ce ? QUADD_HDR_BT_UT_CE : 0;
+ hdr->reserved |= um->dwarf ? QUADD_HDR_BT_DWARF : 0;
+ }
if (hrt.use_arch_timer)
hdr->reserved |= QUADD_HDR_USE_ARCH_TIMER;
@@ -335,11 +342,11 @@ get_stack_offset(struct task_struct *task,
static void
read_all_sources(struct pt_regs *regs, struct task_struct *task)
{
- u32 state, extra_data = 0;
+ u32 state, extra_data = 0, urcs = 0;
int i, vec_idx = 0, bt_size = 0;
int nr_events = 0, nr_positive_events = 0;
struct pt_regs *user_regs;
- struct quadd_iovec vec[5];
+ struct quadd_iovec vec[6];
struct hrt_event_value events[QUADD_MAX_COUNTERS];
u32 events_extra[QUADD_MAX_COUNTERS];
@@ -401,7 +408,8 @@ read_all_sources(struct pt_regs *regs, struct task_struct *task)
cc->curr_pc = 0;
if (ctx->param.backtrace) {
- cc->unw_method = hrt.unw_method;
+ cc->um = hrt.um;
+
bt_size = quadd_get_user_callchain(user_regs, cc, ctx, task);
if (!bt_size && !user_mode(regs)) {
@@ -434,8 +442,18 @@ read_all_sources(struct pt_regs *regs, struct task_struct *task)
extra_data |= QUADD_SED_IP64;
}
- extra_data |= cc->unw_method << QUADD_SED_UNW_METHOD_SHIFT;
- s->reserved |= cc->unw_rc << QUADD_SAMPLE_URC_SHIFT;
+ urcs |= (cc->urc_fp & QUADD_SAMPLE_URC_MASK) <<
+ QUADD_SAMPLE_URC_SHIFT_FP;
+ urcs |= (cc->urc_ut & QUADD_SAMPLE_URC_MASK) <<
+ QUADD_SAMPLE_URC_SHIFT_UT;
+ urcs |= (cc->urc_dwarf & QUADD_SAMPLE_URC_MASK) <<
+ QUADD_SAMPLE_URC_SHIFT_DWARF;
+
+ s->reserved |= QUADD_SAMPLE_RES_URCS_ENABLED;
+
+ vec[vec_idx].base = &urcs;
+ vec[vec_idx].len = sizeof(urcs);
+ vec_idx++;
}
s->callchain_nr = bt_size;
@@ -540,7 +558,7 @@ void __quadd_task_sched_in(struct task_struct *prev,
struct event_data events[QUADD_MAX_COUNTERS];
/* static DEFINE_RATELIMIT_STATE(ratelimit_state, 5 * HZ, 2); */
- if (likely(!hrt.active))
+ if (likely(!atomic_read(&hrt.active)))
return;
/*
if (__ratelimit(&ratelimit_state))
@@ -578,7 +596,7 @@ void __quadd_task_sched_out(struct task_struct *prev,
struct quadd_ctx *ctx = hrt.quadd_ctx;
/* static DEFINE_RATELIMIT_STATE(ratelimit_state, 5 * HZ, 2); */
- if (likely(!hrt.active))
+ if (likely(!atomic_read(&hrt.active)))
return;
/*
if (__ratelimit(&ratelimit_state))
@@ -612,7 +630,7 @@ void __quadd_event_mmap(struct vm_area_struct *vma)
{
struct quadd_parameters *param;
- if (likely(!hrt.active))
+ if (likely(!atomic_read(&hrt.active)))
return;
if (!is_profile_process(current))
@@ -665,14 +683,17 @@ int quadd_hrt_start(void)
extra = param->reserved[QUADD_PARAM_IDX_EXTRA];
- if (extra & QUADD_PARAM_EXTRA_BT_MIXED)
- hrt.unw_method = QUADD_UNW_METHOD_MIXED;
- else if (extra & QUADD_PARAM_EXTRA_BT_UNWIND_TABLES)
- hrt.unw_method = QUADD_UNW_METHOD_EHT;
- else if (extra & QUADD_PARAM_EXTRA_BT_FP)
- hrt.unw_method = QUADD_UNW_METHOD_FP;
- else
- hrt.unw_method = QUADD_UNW_METHOD_NONE;
+ if (param->backtrace) {
+ struct quadd_unw_methods *um = &hrt.um;
+
+ um->fp = extra & QUADD_PARAM_EXTRA_BT_FP ? 1 : 0;
+ um->ut = extra & QUADD_PARAM_EXTRA_BT_UT ? 1 : 0;
+ um->ut_ce = extra & QUADD_PARAM_EXTRA_BT_UT_CE ? 1 : 0;
+ um->dwarf = extra & QUADD_PARAM_EXTRA_BT_DWARF ? 1 : 0;
+
+ pr_info("unw methods: fp/ut/ut_ce/dwarf: %u/%u/%u/%u\n",
+ um->fp, um->ut, um->ut_ce, um->dwarf);
+ }
if (hrt.tc && (extra & QUADD_PARAM_EXTRA_USE_ARCH_TIMER))
hrt.use_arch_timer = 1;
@@ -699,7 +720,7 @@ int quadd_hrt_start(void)
quadd_ma_start(&hrt);
- hrt.active = 1;
+ atomic_set(&hrt.active, 1);
pr_info("Start hrt: freq/period: %ld/%llu\n", freq, period);
return 0;
@@ -718,7 +739,7 @@ void quadd_hrt_stop(void)
quadd_ma_stop(&hrt);
- hrt.active = 0;
+ atomic_set(&hrt.active, 0);
atomic64_set(&hrt.counter_samples, 0);
atomic64_set(&hrt.skipped_samples, 0);
@@ -728,7 +749,7 @@ void quadd_hrt_stop(void)
void quadd_hrt_deinit(void)
{
- if (hrt.active)
+ if (atomic_read(&hrt.active))
quadd_hrt_stop();
free_percpu(hrt.cpu_ctx);
@@ -758,7 +779,7 @@ struct quadd_hrt_ctx *quadd_hrt_init(struct quadd_ctx *ctx)
struct quadd_cpu_context *cpu_ctx;
hrt.quadd_ctx = ctx;
- hrt.active = 0;
+ atomic_set(&hrt.active, 0);
freq = ctx->param.freq;
freq = max_t(long, QUADD_HRT_MIN_FREQ, freq);
diff --git a/drivers/misc/tegra-profiler/hrt.h b/drivers/misc/tegra-profiler/hrt.h
index 172e2f1719dd..2b5254a52fa6 100644
--- a/drivers/misc/tegra-profiler/hrt.h
+++ b/drivers/misc/tegra-profiler/hrt.h
@@ -49,7 +49,7 @@ struct quadd_hrt_ctx {
struct quadd_ctx *quadd_ctx;
- int active;
+ atomic_t active;
atomic_t nr_active_all_core;
atomic64_t counter_samples;
@@ -64,7 +64,7 @@ struct quadd_hrt_ctx {
struct timecounter *tc;
int use_arch_timer;
- unsigned int unw_method;
+ struct quadd_unw_methods um;
int get_stack_offset;
};
diff --git a/drivers/misc/tegra-profiler/ma.c b/drivers/misc/tegra-profiler/ma.c
index c7ccd82ac1b0..83ae8195f80e 100644
--- a/drivers/misc/tegra-profiler/ma.c
+++ b/drivers/misc/tegra-profiler/ma.c
@@ -85,7 +85,7 @@ static void timer_interrupt(unsigned long data)
struct quadd_hrt_ctx *hrt_ctx = (struct quadd_hrt_ctx *)data;
struct timer_list *timer = &hrt_ctx->ma_timer;
- if (hrt_ctx->active == 0)
+ if (!atomic_read(&hrt_ctx->active))
return;
check_ma(hrt_ctx);
diff --git a/drivers/misc/tegra-profiler/main.c b/drivers/misc/tegra-profiler/main.c
index f9d7d4bcdd9b..d3236970e27a 100644
--- a/drivers/misc/tegra-profiler/main.c
+++ b/drivers/misc/tegra-profiler/main.c
@@ -185,7 +185,6 @@ set_parameters(struct quadd_parameters *p, uid_t *debug_app_uid)
int pl310_events_id;
int nr_pmu = 0, nr_pl310 = 0;
struct task_struct *task;
- unsigned int extra;
u64 *low_addr_p;
if (!validate_freq(p->freq)) {
@@ -293,17 +292,6 @@ set_parameters(struct quadd_parameters *p, uid_t *debug_app_uid)
}
}
- extra = p->reserved[QUADD_PARAM_IDX_EXTRA];
-
- if (extra & QUADD_PARAM_EXTRA_BT_UNWIND_TABLES)
- pr_info("unwinding: exception-handling tables\n");
-
- if (extra & QUADD_PARAM_EXTRA_BT_FP)
- pr_info("unwinding: frame pointers\n");
-
- if (extra & QUADD_PARAM_EXTRA_BT_MIXED)
- pr_info("unwinding: mixed mode\n");
-
low_addr_p = (u64 *)&p->reserved[QUADD_PARAM_IDX_BT_LOWER_BOUND];
ctx.hrt->low_addr = (unsigned long)*low_addr_p;
pr_info("bt lower bound: %#lx\n", ctx.hrt->low_addr);
diff --git a/drivers/misc/tegra-profiler/version.h b/drivers/misc/tegra-profiler/version.h
index f956c1d40861..d3254f99c063 100644
--- a/drivers/misc/tegra-profiler/version.h
+++ b/drivers/misc/tegra-profiler/version.h
@@ -18,7 +18,7 @@
#ifndef __QUADD_VERSION_H
#define __QUADD_VERSION_H
-#define QUADD_MODULE_VERSION "1.96"
+#define QUADD_MODULE_VERSION "1.97"
#define QUADD_MODULE_BRANCH "Dev"
#endif /* __QUADD_VERSION_H */
diff --git a/include/linux/tegra_profiler.h b/include/linux/tegra_profiler.h
index 66d5bf240c74..fffa74a7e7df 100644
--- a/include/linux/tegra_profiler.h
+++ b/include/linux/tegra_profiler.h
@@ -19,8 +19,8 @@
#include <linux/ioctl.h>
-#define QUADD_SAMPLES_VERSION 32
-#define QUADD_IO_VERSION 17
+#define QUADD_SAMPLES_VERSION 33
+#define QUADD_IO_VERSION 18
#define QUADD_IO_VERSION_DYNAMIC_RB 5
#define QUADD_IO_VERSION_RB_MAX_FILL_COUNT 6
@@ -35,6 +35,7 @@
#define QUADD_IO_VERSION_BT_LOWER_BOUND 15
#define QUADD_IO_VERSION_STACK_OFFSET 16
#define QUADD_IO_VERSION_SECTIONS_INFO 17
+#define QUADD_IO_VERSION_UNW_METHODS_OPT 18
#define QUADD_SAMPLE_VERSION_THUMB_MODE_FLAG 17
#define QUADD_SAMPLE_VERSION_GROUP_SAMPLES 18
@@ -50,6 +51,7 @@
#define QUADD_SAMPLE_VERSION_HDR_ARCH_TIMER 30
#define QUADD_SAMPLE_VERSION_STACK_OFFSET 31
#define QUADD_SAMPLE_VERSION_SCHED_TASK_STATE 32
+#define QUADD_SAMPLE_VERSION_URCS 33
#define QUADD_MMAP_HEADER_VERSION 1
@@ -165,18 +167,13 @@ enum quadd_cpu_mode {
#pragma pack(push, 1)
-#define QUADD_SAMPLE_UNW_METHOD_SHIFT 0
-#define QUADD_SAMPLE_UNW_METHOD_MASK (1 << QUADD_SAMPLE_UNW_METHOD_SHIFT)
+#define QUADD_SAMPLE_RES_URCS_ENABLED (1 << 0)
-enum {
- QUADD_UNW_METHOD_FP = 0,
- QUADD_UNW_METHOD_EHT,
- QUADD_UNW_METHOD_MIXED,
- QUADD_UNW_METHOD_NONE,
-};
+#define QUADD_SAMPLE_URC_MASK 0xff
-#define QUADD_SAMPLE_URC_SHIFT 1
-#define QUADD_SAMPLE_URC_MASK (0x0f << QUADD_SAMPLE_URC_SHIFT)
+#define QUADD_SAMPLE_URC_SHIFT_FP 0
+#define QUADD_SAMPLE_URC_SHIFT_UT (1 * 8)
+#define QUADD_SAMPLE_URC_SHIFT_DWARF (2 * 8)
enum {
QUADD_URC_SUCCESS = 0,
@@ -194,15 +191,13 @@ enum {
QUADD_URC_PC_INCORRECT,
QUADD_URC_LEVEL_TOO_DEEP,
QUADD_URC_FP_INCORRECT,
+ QUADD_URC_NONE,
QUADD_URC_MAX,
};
#define QUADD_SED_IP64 (1 << 0)
-#define QUADD_SED_UNW_METHOD_SHIFT 1
-#define QUADD_SED_UNW_METHOD_MASK (0x07 << QUADD_SED_UNW_METHOD_SHIFT)
-
-#define QUADD_SED_STACK_OFFSET_SHIFT 4
+#define QUADD_SED_STACK_OFFSET_SHIFT 1
#define QUADD_SED_STACK_OFFSET_MASK (0xffff << QUADD_SED_STACK_OFFSET_SHIFT)
enum {
@@ -318,11 +313,12 @@ struct quadd_debug_data {
#define QUADD_HEADER_MAGIC 0x1122
-#define QUADD_HDR_UNW_METHOD_SHIFT 0
-#define QUADD_HDR_UNW_METHOD_MASK (0x07 << QUADD_HDR_UNW_METHOD_SHIFT)
-
+#define QUADD_HDR_BT_FP (1 << 0)
+#define QUADD_HDR_BT_UT (1 << 1)
+#define QUADD_HDR_BT_UT_CE (1 << 2)
#define QUADD_HDR_USE_ARCH_TIMER (1 << 3)
#define QUADD_HDR_STACK_OFFSET (1 << 4)
+#define QUADD_HDR_BT_DWARF (1 << 5)
struct quadd_header_data {
u16 magic;
@@ -372,10 +368,12 @@ enum {
#define QUADD_PARAM_EXTRA_GET_MMAP (1 << 0)
#define QUADD_PARAM_EXTRA_BT_FP (1 << 1)
-#define QUADD_PARAM_EXTRA_BT_UNWIND_TABLES (1 << 2)
+#define QUADD_PARAM_EXTRA_BT_UT (1 << 2)
#define QUADD_PARAM_EXTRA_BT_MIXED (1 << 3)
#define QUADD_PARAM_EXTRA_USE_ARCH_TIMER (1 << 4)
#define QUADD_PARAM_EXTRA_STACK_OFFSET (1 << 5)
+#define QUADD_PARAM_EXTRA_BT_UT_CE (1 << 6)
+#define QUADD_PARAM_EXTRA_BT_DWARF (1 << 7)
struct quadd_parameters {
u32 freq;