diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2015-04-24 07:55:54 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2015-04-24 07:55:54 -0700 |
commit | c76397e9303f2c9ac3c2b9d94834ff241d2b2bd4 (patch) | |
tree | 5d8aa13edd611fc2ae29e36678b5cef02408b8d6 /arch/arc/kernel | |
parent | 860448cf76c0878b83d3cf343a0436188b396b8e (diff) | |
parent | d8f6ad85cbb740b7e8ca5275b12838fab685540c (diff) |
Merge tag 'arc-4.1-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/vgupta/arc
Pull ARC updates from Vineet Gupta:
- perf fixes/improvements
- misc cleanups
* tag 'arc-4.1-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/vgupta/arc:
ARC: perf: don't add code for impossible case
ARC: perf: Rename DT binding to not confuse with power mgmt
ARC: perf: add user space attribution in callchains
ARC: perf: Add kernel callchain support
ARC: perf: support cache hit/miss ratio
ARC: perf: Add some comments/debug stuff
ARC: perf: make @arc_pmu static global
ARC: mem init spring cleaning - No functional changes
ARC: Fix RTT boot printing
ARC: fold __builtin_constant_p() into test_bit()
ARC: rename unhandled exception handler
ARC: cosmetic: Remove unused ECR bitfield masks
ARC: Fix WRITE_BCR
ARC: [nsimosci] Update defconfig
arc: copy_thread(): rename 'arg' argument to 'kthread_arg'
Diffstat (limited to 'arch/arc/kernel')
-rw-r--r-- | arch/arc/kernel/perf_event.c | 73 | ||||
-rw-r--r-- | arch/arc/kernel/process.c | 9 | ||||
-rw-r--r-- | arch/arc/kernel/setup.c | 5 | ||||
-rw-r--r-- | arch/arc/kernel/traps.c | 4 |
4 files changed, 69 insertions, 22 deletions
diff --git a/arch/arc/kernel/perf_event.c b/arch/arc/kernel/perf_event.c index ae1c485cbc68..fd2ec50102f2 100644 --- a/arch/arc/kernel/perf_event.c +++ b/arch/arc/kernel/perf_event.c @@ -16,6 +16,7 @@ #include <linux/perf_event.h> #include <linux/platform_device.h> #include <asm/arcregs.h> +#include <asm/stacktrace.h> struct arc_pmu { struct pmu pmu; @@ -25,6 +26,46 @@ struct arc_pmu { int ev_hw_idx[PERF_COUNT_ARC_HW_MAX]; }; +struct arc_callchain_trace { + int depth; + void *perf_stuff; +}; + +static int callchain_trace(unsigned int addr, void *data) +{ + struct arc_callchain_trace *ctrl = data; + struct perf_callchain_entry *entry = ctrl->perf_stuff; + perf_callchain_store(entry, addr); + + if (ctrl->depth++ < 3) + return 0; + + return -1; +} + +void +perf_callchain_kernel(struct perf_callchain_entry *entry, struct pt_regs *regs) +{ + struct arc_callchain_trace ctrl = { + .depth = 0, + .perf_stuff = entry, + }; + + arc_unwind_core(NULL, regs, callchain_trace, &ctrl); +} + +void +perf_callchain_user(struct perf_callchain_entry *entry, struct pt_regs *regs) +{ + /* + * User stack can't be unwound trivially with kernel dwarf unwinder + * So for now just record the user PC + */ + perf_callchain_store(entry, instruction_pointer(regs)); +} + +static struct arc_pmu *arc_pmu; + /* read counter #idx; note that counter# != event# on ARC! */ static uint64_t arc_pmu_read_counter(int idx) { @@ -47,7 +88,6 @@ static uint64_t arc_pmu_read_counter(int idx) static void arc_perf_event_update(struct perf_event *event, struct hw_perf_event *hwc, int idx) { - struct arc_pmu *arc_pmu = container_of(event->pmu, struct arc_pmu, pmu); uint64_t prev_raw_count, new_raw_count; int64_t delta; @@ -89,13 +129,16 @@ static int arc_pmu_cache_event(u64 config) if (ret == CACHE_OP_UNSUPPORTED) return -ENOENT; + pr_debug("init cache event: type/op/result %d/%d/%d with h/w %d \'%s\'\n", + cache_type, cache_op, cache_result, ret, + arc_pmu_ev_hw_map[ret]); + return ret; } /* initializes hw_perf_event structure if event is supported */ static int arc_pmu_event_init(struct perf_event *event) { - struct arc_pmu *arc_pmu = container_of(event->pmu, struct arc_pmu, pmu); struct hw_perf_event *hwc = &event->hw; int ret; @@ -106,8 +149,9 @@ static int arc_pmu_event_init(struct perf_event *event) if (arc_pmu->ev_hw_idx[event->attr.config] < 0) return -ENOENT; hwc->config = arc_pmu->ev_hw_idx[event->attr.config]; - pr_debug("initializing event %d with cfg %d\n", - (int) event->attr.config, (int) hwc->config); + pr_debug("init event %d with h/w %d \'%s\'\n", + (int) event->attr.config, (int) hwc->config, + arc_pmu_ev_hw_map[event->attr.config]); return 0; case PERF_TYPE_HW_CACHE: ret = arc_pmu_cache_event(event->attr.config); @@ -183,8 +227,6 @@ static void arc_pmu_stop(struct perf_event *event, int flags) static void arc_pmu_del(struct perf_event *event, int flags) { - struct arc_pmu *arc_pmu = container_of(event->pmu, struct arc_pmu, pmu); - arc_pmu_stop(event, PERF_EF_UPDATE); __clear_bit(event->hw.idx, arc_pmu->used_mask); @@ -194,7 +236,6 @@ static void arc_pmu_del(struct perf_event *event, int flags) /* allocate hardware counter and optionally start counting */ static int arc_pmu_add(struct perf_event *event, int flags) { - struct arc_pmu *arc_pmu = container_of(event->pmu, struct arc_pmu, pmu); struct hw_perf_event *hwc = &event->hw; int idx = hwc->idx; @@ -247,10 +288,7 @@ static int arc_pmu_device_probe(struct platform_device *pdev) BUG_ON(pct_bcr.c > ARC_PMU_MAX_HWEVENTS); READ_BCR(ARC_REG_CC_BUILD, cc_bcr); - if (!cc_bcr.v) { - pr_err("Performance counters exist, but no countable conditions?\n"); - return -ENODEV; - } + BUG_ON(!cc_bcr.v); /* Counters exist but No countable conditions ? */ arc_pmu = devm_kzalloc(&pdev->dev, sizeof(struct arc_pmu), GFP_KERNEL); if (!arc_pmu) @@ -263,19 +301,22 @@ static int arc_pmu_device_probe(struct platform_device *pdev) arc_pmu->n_counters, arc_pmu->counter_size, cc_bcr.c); cc_name.str[8] = 0; - for (i = 0; i < PERF_COUNT_HW_MAX; i++) + for (i = 0; i < PERF_COUNT_ARC_HW_MAX; i++) arc_pmu->ev_hw_idx[i] = -1; + /* loop thru all available h/w condition indexes */ for (j = 0; j < cc_bcr.c; j++) { write_aux_reg(ARC_REG_CC_INDEX, j); cc_name.indiv.word0 = read_aux_reg(ARC_REG_CC_NAME0); cc_name.indiv.word1 = read_aux_reg(ARC_REG_CC_NAME1); + + /* See if it has been mapped to a perf event_id */ for (i = 0; i < ARRAY_SIZE(arc_pmu_ev_hw_map); i++) { if (arc_pmu_ev_hw_map[i] && !strcmp(arc_pmu_ev_hw_map[i], cc_name.str) && strlen(arc_pmu_ev_hw_map[i])) { - pr_debug("mapping %d to idx %d with name %s\n", - i, j, cc_name.str); + pr_debug("mapping perf event %2d to h/w event \'%8s\' (idx %d)\n", + i, cc_name.str, j); arc_pmu->ev_hw_idx[i] = j; } } @@ -302,7 +343,7 @@ static int arc_pmu_device_probe(struct platform_device *pdev) #ifdef CONFIG_OF static const struct of_device_id arc_pmu_match[] = { - { .compatible = "snps,arc700-pmu" }, + { .compatible = "snps,arc700-pct" }, {}, }; MODULE_DEVICE_TABLE(of, arc_pmu_match); @@ -310,7 +351,7 @@ MODULE_DEVICE_TABLE(of, arc_pmu_match); static struct platform_driver arc_pmu_driver = { .driver = { - .name = "arc700-pmu", + .name = "arc700-pct", .of_match_table = of_match_ptr(arc_pmu_match), }, .probe = arc_pmu_device_probe, diff --git a/arch/arc/kernel/process.c b/arch/arc/kernel/process.c index f46efd14059d..e095c557afdd 100644 --- a/arch/arc/kernel/process.c +++ b/arch/arc/kernel/process.c @@ -49,7 +49,10 @@ void arch_cpu_idle(void) asmlinkage void ret_from_fork(void); -/* Layout of Child kernel mode stack as setup at the end of this function is +/* + * Copy architecture-specific thread state + * + * Layout of Child kernel mode stack as setup at the end of this function is * * | ... | * | ... | @@ -81,7 +84,7 @@ asmlinkage void ret_from_fork(void); * ------------------ <===== END of PAGE */ int copy_thread(unsigned long clone_flags, - unsigned long usp, unsigned long arg, + unsigned long usp, unsigned long kthread_arg, struct task_struct *p) { struct pt_regs *c_regs; /* child's pt_regs */ @@ -112,7 +115,7 @@ int copy_thread(unsigned long clone_flags, if (unlikely(p->flags & PF_KTHREAD)) { memset(c_regs, 0, sizeof(struct pt_regs)); - c_callee->r13 = arg; /* argument to kernel thread */ + c_callee->r13 = kthread_arg; c_callee->r14 = usp; /* function */ return 0; diff --git a/arch/arc/kernel/setup.c b/arch/arc/kernel/setup.c index 900f68a70088..1d167c6df8ca 100644 --- a/arch/arc/kernel/setup.c +++ b/arch/arc/kernel/setup.c @@ -120,7 +120,10 @@ static void read_arc_build_cfg_regs(void) READ_BCR(ARC_REG_SMART_BCR, bcr); cpu->extn.smart = bcr.ver ? 1 : 0; - cpu->extn.debug = cpu->extn.ap | cpu->extn.smart; + READ_BCR(ARC_REG_RTT_BCR, bcr); + cpu->extn.rtt = bcr.ver ? 1 : 0; + + cpu->extn.debug = cpu->extn.ap | cpu->extn.smart | cpu->extn.rtt; } static const struct cpuinfo_data arc_cpu_tbl[] = { diff --git a/arch/arc/kernel/traps.c b/arch/arc/kernel/traps.c index 3eadfdabc322..c927aa84e652 100644 --- a/arch/arc/kernel/traps.c +++ b/arch/arc/kernel/traps.c @@ -42,7 +42,7 @@ void die(const char *str, struct pt_regs *regs, unsigned long address) * -for kernel, chk if due to copy_(to|from)_user, otherwise die() */ static noinline int -handle_exception(const char *str, struct pt_regs *regs, siginfo_t *info) +unhandled_exception(const char *str, struct pt_regs *regs, siginfo_t *info) { if (user_mode(regs)) { struct task_struct *tsk = current; @@ -71,7 +71,7 @@ int name(unsigned long address, struct pt_regs *regs) \ .si_code = sicode, \ .si_addr = (void __user *)address, \ }; \ - return handle_exception(str, regs, &info);\ + return unhandled_exception(str, regs, &info);\ } /* |