aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/x86/kernel/cpu/perf_event.c71
-rw-r--r--arch/x86/kernel/cpu/perf_event.h4
-rw-r--r--arch/x86/kernel/cpu/perf_event_intel.c14
-rw-r--r--arch/x86/kernel/cpu/perf_event_intel_bts.c9
-rw-r--r--kernel/events/core.c14
-rw-r--r--tools/build/Makefile.build8
6 files changed, 84 insertions, 36 deletions
diff --git a/arch/x86/kernel/cpu/perf_event.c b/arch/x86/kernel/cpu/perf_event.c
index 9560d0fc6fa6..5801a14f7524 100644
--- a/arch/x86/kernel/cpu/perf_event.c
+++ b/arch/x86/kernel/cpu/perf_event.c
@@ -135,6 +135,7 @@ static int x86_pmu_extra_regs(u64 config, struct perf_event *event)
135} 135}
136 136
137static atomic_t active_events; 137static atomic_t active_events;
138static atomic_t pmc_refcount;
138static DEFINE_MUTEX(pmc_reserve_mutex); 139static DEFINE_MUTEX(pmc_reserve_mutex);
139 140
140#ifdef CONFIG_X86_LOCAL_APIC 141#ifdef CONFIG_X86_LOCAL_APIC
@@ -270,11 +271,8 @@ msr_fail:
270 271
271static void hw_perf_event_destroy(struct perf_event *event) 272static void hw_perf_event_destroy(struct perf_event *event)
272{ 273{
273 if (atomic_dec_and_mutex_lock(&active_events, &pmc_reserve_mutex)) { 274 x86_release_hardware();
274 release_pmc_hardware(); 275 atomic_dec(&active_events);
275 release_ds_buffers();
276 mutex_unlock(&pmc_reserve_mutex);
277 }
278} 276}
279 277
280void hw_perf_lbr_event_destroy(struct perf_event *event) 278void hw_perf_lbr_event_destroy(struct perf_event *event)
@@ -324,6 +322,35 @@ set_ext_hw_attr(struct hw_perf_event *hwc, struct perf_event *event)
324 return x86_pmu_extra_regs(val, event); 322 return x86_pmu_extra_regs(val, event);
325} 323}
326 324
325int x86_reserve_hardware(void)
326{
327 int err = 0;
328
329 if (!atomic_inc_not_zero(&pmc_refcount)) {
330 mutex_lock(&pmc_reserve_mutex);
331 if (atomic_read(&pmc_refcount) == 0) {
332 if (!reserve_pmc_hardware())
333 err = -EBUSY;
334 else
335 reserve_ds_buffers();
336 }
337 if (!err)
338 atomic_inc(&pmc_refcount);
339 mutex_unlock(&pmc_reserve_mutex);
340 }
341
342 return err;
343}
344
345void x86_release_hardware(void)
346{
347 if (atomic_dec_and_mutex_lock(&pmc_refcount, &pmc_reserve_mutex)) {
348 release_pmc_hardware();
349 release_ds_buffers();
350 mutex_unlock(&pmc_reserve_mutex);
351 }
352}
353
327/* 354/*
328 * Check if we can create event of a certain type (that no conflicting events 355 * Check if we can create event of a certain type (that no conflicting events
329 * are present). 356 * are present).
@@ -336,21 +363,34 @@ int x86_add_exclusive(unsigned int what)
336 return 0; 363 return 0;
337 364
338 mutex_lock(&pmc_reserve_mutex); 365 mutex_lock(&pmc_reserve_mutex);
339 for (i = 0; i < ARRAY_SIZE(x86_pmu.lbr_exclusive); i++) 366 for (i = 0; i < ARRAY_SIZE(x86_pmu.lbr_exclusive); i++) {
340 if (i != what && atomic_read(&x86_pmu.lbr_exclusive[i])) 367 if (i != what && atomic_read(&x86_pmu.lbr_exclusive[i]))
341 goto out; 368 goto out;
369 }
342 370
343 atomic_inc(&x86_pmu.lbr_exclusive[what]); 371 atomic_inc(&x86_pmu.lbr_exclusive[what]);
344 ret = 0; 372 ret = 0;
345 373
346out: 374out:
347 mutex_unlock(&pmc_reserve_mutex); 375 mutex_unlock(&pmc_reserve_mutex);
376
377 /*
378 * Assuming that all exclusive events will share the PMI handler
379 * (which checks active_events for whether there is work to do),
380 * we can bump active_events counter right here, except for
381 * x86_lbr_exclusive_lbr events that go through x86_pmu_event_init()
382 * path, which already bumps active_events for them.
383 */
384 if (!ret && what != x86_lbr_exclusive_lbr)
385 atomic_inc(&active_events);
386
348 return ret; 387 return ret;
349} 388}
350 389
351void x86_del_exclusive(unsigned int what) 390void x86_del_exclusive(unsigned int what)
352{ 391{
353 atomic_dec(&x86_pmu.lbr_exclusive[what]); 392 atomic_dec(&x86_pmu.lbr_exclusive[what]);
393 atomic_dec(&active_events);
354} 394}
355 395
356int x86_setup_perfctr(struct perf_event *event) 396int x86_setup_perfctr(struct perf_event *event)
@@ -527,22 +567,11 @@ static int __x86_pmu_event_init(struct perf_event *event)
527 if (!x86_pmu_initialized()) 567 if (!x86_pmu_initialized())
528 return -ENODEV; 568 return -ENODEV;
529 569
530 err = 0; 570 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) 571 if (err)
544 return err; 572 return err;
545 573
574 atomic_inc(&active_events);
546 event->destroy = hw_perf_event_destroy; 575 event->destroy = hw_perf_event_destroy;
547 576
548 event->hw.idx = -1; 577 event->hw.idx = -1;
@@ -1415,6 +1444,10 @@ perf_event_nmi_handler(unsigned int cmd, struct pt_regs *regs)
1415 u64 finish_clock; 1444 u64 finish_clock;
1416 int ret; 1445 int ret;
1417 1446
1447 /*
1448 * All PMUs/events that share this PMI handler should make sure to
1449 * increment active_events for their events.
1450 */
1418 if (!atomic_read(&active_events)) 1451 if (!atomic_read(&active_events))
1419 return NMI_DONE; 1452 return NMI_DONE;
1420 1453
diff --git a/arch/x86/kernel/cpu/perf_event.h b/arch/x86/kernel/cpu/perf_event.h
index 74089bcb6d74..3e7fd27dfe20 100644
--- a/arch/x86/kernel/cpu/perf_event.h
+++ b/arch/x86/kernel/cpu/perf_event.h
@@ -716,6 +716,10 @@ int x86_add_exclusive(unsigned int what);
716 716
717void x86_del_exclusive(unsigned int what); 717void x86_del_exclusive(unsigned int what);
718 718
719int x86_reserve_hardware(void);
720
721void x86_release_hardware(void);
722
719void hw_perf_lbr_event_destroy(struct perf_event *event); 723void hw_perf_lbr_event_destroy(struct perf_event *event);
720 724
721int x86_setup_perfctr(struct perf_event *event); 725int x86_setup_perfctr(struct perf_event *event);
diff --git a/arch/x86/kernel/cpu/perf_event_intel.c b/arch/x86/kernel/cpu/perf_event_intel.c
index d455e2a61287..19980d9a6cc9 100644
--- a/arch/x86/kernel/cpu/perf_event_intel.c
+++ b/arch/x86/kernel/cpu/perf_event_intel.c
@@ -3227,6 +3227,8 @@ __init int intel_pmu_init(void)
3227 3227
3228 case 61: /* 14nm Broadwell Core-M */ 3228 case 61: /* 14nm Broadwell Core-M */
3229 case 86: /* 14nm Broadwell Xeon D */ 3229 case 86: /* 14nm Broadwell Xeon D */
3230 case 71: /* 14nm Broadwell + GT3e (Intel Iris Pro graphics) */
3231 case 79: /* 14nm Broadwell Server */
3230 x86_pmu.late_ack = true; 3232 x86_pmu.late_ack = true;
3231 memcpy(hw_cache_event_ids, hsw_hw_cache_event_ids, sizeof(hw_cache_event_ids)); 3233 memcpy(hw_cache_event_ids, hsw_hw_cache_event_ids, sizeof(hw_cache_event_ids));
3232 memcpy(hw_cache_extra_regs, hsw_hw_cache_extra_regs, sizeof(hw_cache_extra_regs)); 3234 memcpy(hw_cache_extra_regs, hsw_hw_cache_extra_regs, sizeof(hw_cache_extra_regs));
@@ -3296,13 +3298,13 @@ __init int intel_pmu_init(void)
3296 * counter, so do not extend mask to generic counters 3298 * counter, so do not extend mask to generic counters
3297 */ 3299 */
3298 for_each_event_constraint(c, x86_pmu.event_constraints) { 3300 for_each_event_constraint(c, x86_pmu.event_constraints) {
3299 if (c->cmask != FIXED_EVENT_FLAGS 3301 if (c->cmask == FIXED_EVENT_FLAGS
3300 || c->idxmsk64 == INTEL_PMC_MSK_FIXED_REF_CYCLES) { 3302 && c->idxmsk64 != INTEL_PMC_MSK_FIXED_REF_CYCLES) {
3301 continue; 3303 c->idxmsk64 |= (1ULL << x86_pmu.num_counters) - 1;
3302 } 3304 }
3303 3305 c->idxmsk64 &=
3304 c->idxmsk64 |= (1ULL << x86_pmu.num_counters) - 1; 3306 ~(~0UL << (INTEL_PMC_IDX_FIXED + x86_pmu.num_counters_fixed));
3305 c->weight += x86_pmu.num_counters; 3307 c->weight = hweight64(c->idxmsk64);
3306 } 3308 }
3307 } 3309 }
3308 3310
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;
diff --git a/kernel/events/core.c b/kernel/events/core.c
index 9e0773d5d110..f2003b97ddc9 100644
--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -4331,20 +4331,20 @@ static void ring_buffer_attach(struct perf_event *event,
4331 WARN_ON_ONCE(event->rcu_pending); 4331 WARN_ON_ONCE(event->rcu_pending);
4332 4332
4333 old_rb = event->rb; 4333 old_rb = event->rb;
4334 event->rcu_batches = get_state_synchronize_rcu();
4335 event->rcu_pending = 1;
4336
4337 spin_lock_irqsave(&old_rb->event_lock, flags); 4334 spin_lock_irqsave(&old_rb->event_lock, flags);
4338 list_del_rcu(&event->rb_entry); 4335 list_del_rcu(&event->rb_entry);
4339 spin_unlock_irqrestore(&old_rb->event_lock, flags); 4336 spin_unlock_irqrestore(&old_rb->event_lock, flags);
4340 }
4341 4337
4342 if (event->rcu_pending && rb) { 4338 event->rcu_batches = get_state_synchronize_rcu();
4343 cond_synchronize_rcu(event->rcu_batches); 4339 event->rcu_pending = 1;
4344 event->rcu_pending = 0;
4345 } 4340 }
4346 4341
4347 if (rb) { 4342 if (rb) {
4343 if (event->rcu_pending) {
4344 cond_synchronize_rcu(event->rcu_batches);
4345 event->rcu_pending = 0;
4346 }
4347
4348 spin_lock_irqsave(&rb->event_lock, flags); 4348 spin_lock_irqsave(&rb->event_lock, flags);
4349 list_add_rcu(&event->rb_entry, &rb->event_list); 4349 list_add_rcu(&event->rb_entry, &rb->event_list);
4350 spin_unlock_irqrestore(&rb->event_lock, flags); 4350 spin_unlock_irqrestore(&rb->event_lock, flags);
diff --git a/tools/build/Makefile.build b/tools/build/Makefile.build
index 69c35cf09cad..a51244a8022f 100644
--- a/tools/build/Makefile.build
+++ b/tools/build/Makefile.build
@@ -94,12 +94,12 @@ obj-y := $(patsubst %/, %/$(obj)-in.o, $(obj-y))
94subdir-obj-y := $(filter %/$(obj)-in.o, $(obj-y)) 94subdir-obj-y := $(filter %/$(obj)-in.o, $(obj-y))
95 95
96# '$(OUTPUT)/dir' prefix to all objects 96# '$(OUTPUT)/dir' prefix to all objects
97prefix := $(subst ./,,$(OUTPUT)$(dir)/) 97objprefix := $(subst ./,,$(OUTPUT)$(dir)/)
98obj-y := $(addprefix $(prefix),$(obj-y)) 98obj-y := $(addprefix $(objprefix),$(obj-y))
99subdir-obj-y := $(addprefix $(prefix),$(subdir-obj-y)) 99subdir-obj-y := $(addprefix $(objprefix),$(subdir-obj-y))
100 100
101# Final '$(obj)-in.o' object 101# Final '$(obj)-in.o' object
102in-target := $(prefix)$(obj)-in.o 102in-target := $(objprefix)$(obj)-in.o
103 103
104PHONY += $(subdir-y) 104PHONY += $(subdir-y)
105 105