aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
Diffstat (limited to 'arch')
-rw-r--r--arch/x86/kernel/cpu/perf_event.c52
-rw-r--r--arch/x86/kernel/cpu/perf_event.h4
-rw-r--r--arch/x86/kernel/cpu/perf_event_intel_bts.c9
3 files changed, 46 insertions, 19 deletions
diff --git a/arch/x86/kernel/cpu/perf_event.c b/arch/x86/kernel/cpu/perf_event.c
index 4f7001f28936..aa4e3a74e541 100644
--- a/arch/x86/kernel/cpu/perf_event.c
+++ b/arch/x86/kernel/cpu/perf_event.c
@@ -270,11 +270,7 @@ msr_fail:
270 270
271static void hw_perf_event_destroy(struct perf_event *event) 271static void hw_perf_event_destroy(struct perf_event *event)
272{ 272{
273 if (atomic_dec_and_mutex_lock(&active_events, &pmc_reserve_mutex)) { 273 x86_release_hardware();
274 release_pmc_hardware();
275 release_ds_buffers();
276 mutex_unlock(&pmc_reserve_mutex);
277 }
278} 274}
279 275
280void hw_perf_lbr_event_destroy(struct perf_event *event) 276void hw_perf_lbr_event_destroy(struct perf_event *event)
@@ -324,6 +320,35 @@ set_ext_hw_attr(struct hw_perf_event *hwc, struct perf_event *event)
324 return x86_pmu_extra_regs(val, event); 320 return x86_pmu_extra_regs(val, event);
325} 321}
326 322
323int x86_reserve_hardware(void)
324{
325 int err = 0;
326
327 if (!atomic_inc_not_zero(&active_events)) {
328 mutex_lock(&pmc_reserve_mutex);
329 if (atomic_read(&active_events) == 0) {
330 if (!reserve_pmc_hardware())
331 err = -EBUSY;
332 else
333 reserve_ds_buffers();
334 }
335 if (!err)
336 atomic_inc(&active_events);
337 mutex_unlock(&pmc_reserve_mutex);
338 }
339
340 return err;
341}
342
343void x86_release_hardware(void)
344{
345 if (atomic_dec_and_mutex_lock(&active_events, &pmc_reserve_mutex)) {
346 release_pmc_hardware();
347 release_ds_buffers();
348 mutex_unlock(&pmc_reserve_mutex);
349 }
350}
351
327/* 352/*
328 * Check if we can create event of a certain type (that no conflicting events 353 * Check if we can create event of a certain type (that no conflicting events
329 * are present). 354 * are present).
@@ -336,9 +361,10 @@ int x86_add_exclusive(unsigned int what)
336 return 0; 361 return 0;
337 362
338 mutex_lock(&pmc_reserve_mutex); 363 mutex_lock(&pmc_reserve_mutex);
339 for (i = 0; i < ARRAY_SIZE(x86_pmu.lbr_exclusive); i++) 364 for (i = 0; i < ARRAY_SIZE(x86_pmu.lbr_exclusive); i++) {
340 if (i != what && atomic_read(&x86_pmu.lbr_exclusive[i])) 365 if (i != what && atomic_read(&x86_pmu.lbr_exclusive[i]))
341 goto out; 366 goto out;
367 }
342 368
343 atomic_inc(&x86_pmu.lbr_exclusive[what]); 369 atomic_inc(&x86_pmu.lbr_exclusive[what]);
344 ret = 0; 370 ret = 0;
@@ -527,19 +553,7 @@ static int __x86_pmu_event_init(struct perf_event *event)
527 if (!x86_pmu_initialized()) 553 if (!x86_pmu_initialized())
528 return -ENODEV; 554 return -ENODEV;
529 555
530 err = 0; 556 err = x86_reserve_hardware();
531 if (!atomic_inc_not_zero(&active_events)) {
532 mutex_lock(&pmc_reserve_mutex);
533 if (atomic_read(&active_events) == 0) {
534 if (!reserve_pmc_hardware())
535 err = -EBUSY;
536 else
537 reserve_ds_buffers();
538 }
539 if (!err)
540 atomic_inc(&active_events);
541 mutex_unlock(&pmc_reserve_mutex);
542 }
543 if (err) 557 if (err)
544 return err; 558 return err;
545 559
diff --git a/arch/x86/kernel/cpu/perf_event.h b/arch/x86/kernel/cpu/perf_event.h
index ef78516850fb..f068695eaca0 100644
--- a/arch/x86/kernel/cpu/perf_event.h
+++ b/arch/x86/kernel/cpu/perf_event.h
@@ -703,6 +703,10 @@ int x86_add_exclusive(unsigned int what);
703 703
704void x86_del_exclusive(unsigned int what); 704void x86_del_exclusive(unsigned int what);
705 705
706int x86_reserve_hardware(void);
707
708void x86_release_hardware(void);
709
706void hw_perf_lbr_event_destroy(struct perf_event *event); 710void hw_perf_lbr_event_destroy(struct perf_event *event);
707 711
708int x86_setup_perfctr(struct perf_event *event); 712int x86_setup_perfctr(struct perf_event *event);
diff --git a/arch/x86/kernel/cpu/perf_event_intel_bts.c b/arch/x86/kernel/cpu/perf_event_intel_bts.c
index ac1f0c55f379..7795f3f8b1d5 100644
--- a/arch/x86/kernel/cpu/perf_event_intel_bts.c
+++ b/arch/x86/kernel/cpu/perf_event_intel_bts.c
@@ -483,17 +483,26 @@ static int bts_event_add(struct perf_event *event, int mode)
483 483
484static void bts_event_destroy(struct perf_event *event) 484static void bts_event_destroy(struct perf_event *event)
485{ 485{
486 x86_release_hardware();
486 x86_del_exclusive(x86_lbr_exclusive_bts); 487 x86_del_exclusive(x86_lbr_exclusive_bts);
487} 488}
488 489
489static int bts_event_init(struct perf_event *event) 490static int bts_event_init(struct perf_event *event)
490{ 491{
492 int ret;
493
491 if (event->attr.type != bts_pmu.type) 494 if (event->attr.type != bts_pmu.type)
492 return -ENOENT; 495 return -ENOENT;
493 496
494 if (x86_add_exclusive(x86_lbr_exclusive_bts)) 497 if (x86_add_exclusive(x86_lbr_exclusive_bts))
495 return -EBUSY; 498 return -EBUSY;
496 499
500 ret = x86_reserve_hardware();
501 if (ret) {
502 x86_del_exclusive(x86_lbr_exclusive_bts);
503 return ret;
504 }
505
497 event->destroy = bts_event_destroy; 506 event->destroy = bts_event_destroy;
498 507
499 return 0; 508 return 0;