diff options
Diffstat (limited to 'arch/arc/kernel/perf_event.c')
-rw-r--r-- | arch/arc/kernel/perf_event.c | 40 |
1 files changed, 21 insertions, 19 deletions
diff --git a/arch/arc/kernel/perf_event.c b/arch/arc/kernel/perf_event.c index 2ce24e74f879..8aec462d90fb 100644 --- a/arch/arc/kernel/perf_event.c +++ b/arch/arc/kernel/perf_event.c | |||
@@ -336,15 +336,12 @@ static int arc_pmu_add(struct perf_event *event, int flags) | |||
336 | struct hw_perf_event *hwc = &event->hw; | 336 | struct hw_perf_event *hwc = &event->hw; |
337 | int idx = hwc->idx; | 337 | int idx = hwc->idx; |
338 | 338 | ||
339 | if (__test_and_set_bit(idx, pmu_cpu->used_mask)) { | 339 | idx = ffz(pmu_cpu->used_mask[0]); |
340 | idx = find_first_zero_bit(pmu_cpu->used_mask, | 340 | if (idx == arc_pmu->n_counters) |
341 | arc_pmu->n_counters); | 341 | return -EAGAIN; |
342 | if (idx == arc_pmu->n_counters) | 342 | |
343 | return -EAGAIN; | 343 | __set_bit(idx, pmu_cpu->used_mask); |
344 | 344 | hwc->idx = idx; | |
345 | __set_bit(idx, pmu_cpu->used_mask); | ||
346 | hwc->idx = idx; | ||
347 | } | ||
348 | 345 | ||
349 | write_aux_reg(ARC_REG_PCT_INDEX, idx); | 346 | write_aux_reg(ARC_REG_PCT_INDEX, idx); |
350 | 347 | ||
@@ -377,21 +374,22 @@ static irqreturn_t arc_pmu_intr(int irq, void *dev) | |||
377 | struct perf_sample_data data; | 374 | struct perf_sample_data data; |
378 | struct arc_pmu_cpu *pmu_cpu = this_cpu_ptr(&arc_pmu_cpu); | 375 | struct arc_pmu_cpu *pmu_cpu = this_cpu_ptr(&arc_pmu_cpu); |
379 | struct pt_regs *regs; | 376 | struct pt_regs *regs; |
380 | int active_ints; | 377 | unsigned int active_ints; |
381 | int idx; | 378 | int idx; |
382 | 379 | ||
383 | arc_pmu_disable(&arc_pmu->pmu); | 380 | arc_pmu_disable(&arc_pmu->pmu); |
384 | 381 | ||
385 | active_ints = read_aux_reg(ARC_REG_PCT_INT_ACT); | 382 | active_ints = read_aux_reg(ARC_REG_PCT_INT_ACT); |
383 | if (!active_ints) | ||
384 | goto done; | ||
386 | 385 | ||
387 | regs = get_irq_regs(); | 386 | regs = get_irq_regs(); |
388 | 387 | ||
389 | for (idx = 0; idx < arc_pmu->n_counters; idx++) { | 388 | do { |
390 | struct perf_event *event = pmu_cpu->act_counter[idx]; | 389 | struct perf_event *event; |
391 | struct hw_perf_event *hwc; | 390 | struct hw_perf_event *hwc; |
392 | 391 | ||
393 | if (!(active_ints & (1 << idx))) | 392 | idx = __ffs(active_ints); |
394 | continue; | ||
395 | 393 | ||
396 | /* Reset interrupt flag by writing of 1 */ | 394 | /* Reset interrupt flag by writing of 1 */ |
397 | write_aux_reg(ARC_REG_PCT_INT_ACT, 1 << idx); | 395 | write_aux_reg(ARC_REG_PCT_INT_ACT, 1 << idx); |
@@ -404,19 +402,22 @@ static irqreturn_t arc_pmu_intr(int irq, void *dev) | |||
404 | write_aux_reg(ARC_REG_PCT_INT_CTRL, | 402 | write_aux_reg(ARC_REG_PCT_INT_CTRL, |
405 | read_aux_reg(ARC_REG_PCT_INT_CTRL) | (1 << idx)); | 403 | read_aux_reg(ARC_REG_PCT_INT_CTRL) | (1 << idx)); |
406 | 404 | ||
405 | event = pmu_cpu->act_counter[idx]; | ||
407 | hwc = &event->hw; | 406 | hwc = &event->hw; |
408 | 407 | ||
409 | WARN_ON_ONCE(hwc->idx != idx); | 408 | WARN_ON_ONCE(hwc->idx != idx); |
410 | 409 | ||
411 | arc_perf_event_update(event, &event->hw, event->hw.idx); | 410 | arc_perf_event_update(event, &event->hw, event->hw.idx); |
412 | perf_sample_data_init(&data, 0, hwc->last_period); | 411 | perf_sample_data_init(&data, 0, hwc->last_period); |
413 | if (!arc_pmu_event_set_period(event)) | 412 | if (arc_pmu_event_set_period(event)) { |
414 | continue; | 413 | if (perf_event_overflow(event, &data, regs)) |
414 | arc_pmu_stop(event, 0); | ||
415 | } | ||
415 | 416 | ||
416 | if (perf_event_overflow(event, &data, regs)) | 417 | active_ints &= ~(1U << idx); |
417 | arc_pmu_stop(event, 0); | 418 | } while (active_ints); |
418 | } | ||
419 | 419 | ||
420 | done: | ||
420 | arc_pmu_enable(&arc_pmu->pmu); | 421 | arc_pmu_enable(&arc_pmu->pmu); |
421 | 422 | ||
422 | return IRQ_HANDLED; | 423 | return IRQ_HANDLED; |
@@ -461,6 +462,7 @@ static int arc_pmu_device_probe(struct platform_device *pdev) | |||
461 | pr_err("This core does not have performance counters!\n"); | 462 | pr_err("This core does not have performance counters!\n"); |
462 | return -ENODEV; | 463 | return -ENODEV; |
463 | } | 464 | } |
465 | BUILD_BUG_ON(ARC_PERF_MAX_COUNTERS > 32); | ||
464 | BUG_ON(pct_bcr.c > ARC_PERF_MAX_COUNTERS); | 466 | BUG_ON(pct_bcr.c > ARC_PERF_MAX_COUNTERS); |
465 | 467 | ||
466 | READ_BCR(ARC_REG_CC_BUILD, cc_bcr); | 468 | READ_BCR(ARC_REG_CC_BUILD, cc_bcr); |