diff options
| -rw-r--r-- | arch/x86/kernel/cpu/perf_event.c | 71 | ||||
| -rw-r--r-- | arch/x86/kernel/cpu/perf_event.h | 4 | ||||
| -rw-r--r-- | arch/x86/kernel/cpu/perf_event_intel.c | 14 | ||||
| -rw-r--r-- | arch/x86/kernel/cpu/perf_event_intel_bts.c | 9 | ||||
| -rw-r--r-- | kernel/events/core.c | 14 | ||||
| -rw-r--r-- | tools/build/Makefile.build | 8 |
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 | ||
| 137 | static atomic_t active_events; | 137 | static atomic_t active_events; |
| 138 | static atomic_t pmc_refcount; | ||
| 138 | static DEFINE_MUTEX(pmc_reserve_mutex); | 139 | static 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 | ||
| 271 | static void hw_perf_event_destroy(struct perf_event *event) | 272 | static 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 | ||
| 280 | void hw_perf_lbr_event_destroy(struct perf_event *event) | 278 | void 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 | ||
| 325 | int 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 | |||
| 345 | void 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 | ||
| 346 | out: | 374 | out: |
| 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 | ||
| 351 | void x86_del_exclusive(unsigned int what) | 390 | void 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 | ||
| 356 | int x86_setup_perfctr(struct perf_event *event) | 396 | int 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 | ||
| 717 | void x86_del_exclusive(unsigned int what); | 717 | void x86_del_exclusive(unsigned int what); |
| 718 | 718 | ||
| 719 | int x86_reserve_hardware(void); | ||
| 720 | |||
| 721 | void x86_release_hardware(void); | ||
| 722 | |||
| 719 | void hw_perf_lbr_event_destroy(struct perf_event *event); | 723 | void hw_perf_lbr_event_destroy(struct perf_event *event); |
| 720 | 724 | ||
| 721 | int x86_setup_perfctr(struct perf_event *event); | 725 | int 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 | ||
| 484 | static void bts_event_destroy(struct perf_event *event) | 484 | static 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 | ||
| 489 | static int bts_event_init(struct perf_event *event) | 490 | static 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)) | |||
| 94 | subdir-obj-y := $(filter %/$(obj)-in.o, $(obj-y)) | 94 | subdir-obj-y := $(filter %/$(obj)-in.o, $(obj-y)) |
| 95 | 95 | ||
| 96 | # '$(OUTPUT)/dir' prefix to all objects | 96 | # '$(OUTPUT)/dir' prefix to all objects |
| 97 | prefix := $(subst ./,,$(OUTPUT)$(dir)/) | 97 | objprefix := $(subst ./,,$(OUTPUT)$(dir)/) |
| 98 | obj-y := $(addprefix $(prefix),$(obj-y)) | 98 | obj-y := $(addprefix $(objprefix),$(obj-y)) |
| 99 | subdir-obj-y := $(addprefix $(prefix),$(subdir-obj-y)) | 99 | subdir-obj-y := $(addprefix $(objprefix),$(subdir-obj-y)) |
| 100 | 100 | ||
| 101 | # Final '$(obj)-in.o' object | 101 | # Final '$(obj)-in.o' object |
| 102 | in-target := $(prefix)$(obj)-in.o | 102 | in-target := $(objprefix)$(obj)-in.o |
| 103 | 103 | ||
| 104 | PHONY += $(subdir-y) | 104 | PHONY += $(subdir-y) |
| 105 | 105 | ||
