aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arc/kernel/perf_event.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arc/kernel/perf_event.c')
-rw-r--r--arch/arc/kernel/perf_event.c40
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
420done:
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);