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'
This commit is contained in:
@@ -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,
|
||||
|
@@ -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;
|
||||
|
@@ -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[] = {
|
||||
|
@@ -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);\
|
||||
}
|
||||
|
||||
/*
|
||||
|
Reference in New Issue
Block a user