diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2013-05-05 14:37:16 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-05-05 14:37:16 -0400 |
commit | 64049d1973c1735f543eb7a55653e291e108b0cb (patch) | |
tree | 1b13645ee288a561feccafd9fa84951220f5f651 | |
parent | f8ce1faf55955de62e0a12e330c6d9a526071f65 (diff) | |
parent | 7cc23cd6c0c7d7f4bee057607e7ce01568925717 (diff) |
Merge branch 'perf-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull perf fixes from Ingo Molnar:
"Misc fixes plus a small hw-enablement patch for Intel IB model 58
uncore events"
* 'perf-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
perf/x86/intel/lbr: Demand proper privileges for PERF_SAMPLE_BRANCH_KERNEL
perf/x86/intel/lbr: Fix LBR filter
perf/x86: Blacklist all MEM_*_RETIRED events for Ivy Bridge
perf: Fix vmalloc ring buffer pages handling
perf/x86/intel: Fix unintended variable name reuse
perf/x86/intel: Add support for IvyBridge model 58 Uncore
perf/x86/intel: Fix typo in perf_event_intel_uncore.c
x86: Eliminate irq_mis_count counted in arch_irq_stat
-rw-r--r-- | arch/x86/kernel/cpu/perf_event_intel.c | 13 | ||||
-rw-r--r-- | arch/x86/kernel/cpu/perf_event_intel_lbr.c | 27 | ||||
-rw-r--r-- | arch/x86/kernel/cpu/perf_event_intel_uncore.c | 19 | ||||
-rw-r--r-- | arch/x86/kernel/irq.c | 4 | ||||
-rw-r--r-- | kernel/events/ring_buffer.c | 14 |
5 files changed, 51 insertions, 26 deletions
diff --git a/arch/x86/kernel/cpu/perf_event_intel.c b/arch/x86/kernel/cpu/perf_event_intel.c index ffd6050a1de4..f60d41ff9a97 100644 --- a/arch/x86/kernel/cpu/perf_event_intel.c +++ b/arch/x86/kernel/cpu/perf_event_intel.c | |||
@@ -128,10 +128,15 @@ static struct event_constraint intel_ivb_event_constraints[] __read_mostly = | |||
128 | INTEL_UEVENT_CONSTRAINT(0x08a3, 0x4), /* CYCLE_ACTIVITY.CYCLES_L1D_PENDING */ | 128 | INTEL_UEVENT_CONSTRAINT(0x08a3, 0x4), /* CYCLE_ACTIVITY.CYCLES_L1D_PENDING */ |
129 | INTEL_UEVENT_CONSTRAINT(0x0ca3, 0x4), /* CYCLE_ACTIVITY.STALLS_L1D_PENDING */ | 129 | INTEL_UEVENT_CONSTRAINT(0x0ca3, 0x4), /* CYCLE_ACTIVITY.STALLS_L1D_PENDING */ |
130 | INTEL_UEVENT_CONSTRAINT(0x01c0, 0x2), /* INST_RETIRED.PREC_DIST */ | 130 | INTEL_UEVENT_CONSTRAINT(0x01c0, 0x2), /* INST_RETIRED.PREC_DIST */ |
131 | INTEL_EVENT_CONSTRAINT(0xd0, 0xf), /* MEM_UOPS_RETIRED.* */ | 131 | /* |
132 | INTEL_EVENT_CONSTRAINT(0xd1, 0xf), /* MEM_LOAD_UOPS_RETIRED.* */ | 132 | * Errata BV98 -- MEM_*_RETIRED events can leak between counters of SMT |
133 | INTEL_EVENT_CONSTRAINT(0xd2, 0xf), /* MEM_LOAD_UOPS_LLC_HIT_RETIRED.* */ | 133 | * siblings; disable these events because they can corrupt unrelated |
134 | INTEL_EVENT_CONSTRAINT(0xd3, 0xf), /* MEM_LOAD_UOPS_LLC_MISS_RETIRED.* */ | 134 | * counters. |
135 | */ | ||
136 | INTEL_EVENT_CONSTRAINT(0xd0, 0x0), /* MEM_UOPS_RETIRED.* */ | ||
137 | INTEL_EVENT_CONSTRAINT(0xd1, 0x0), /* MEM_LOAD_UOPS_RETIRED.* */ | ||
138 | INTEL_EVENT_CONSTRAINT(0xd2, 0x0), /* MEM_LOAD_UOPS_LLC_HIT_RETIRED.* */ | ||
139 | INTEL_EVENT_CONSTRAINT(0xd3, 0x0), /* MEM_LOAD_UOPS_LLC_MISS_RETIRED.* */ | ||
135 | EVENT_CONSTRAINT_END | 140 | EVENT_CONSTRAINT_END |
136 | }; | 141 | }; |
137 | 142 | ||
diff --git a/arch/x86/kernel/cpu/perf_event_intel_lbr.c b/arch/x86/kernel/cpu/perf_event_intel_lbr.c index da02e9cc3754..d978353c939b 100644 --- a/arch/x86/kernel/cpu/perf_event_intel_lbr.c +++ b/arch/x86/kernel/cpu/perf_event_intel_lbr.c | |||
@@ -310,7 +310,7 @@ void intel_pmu_lbr_read(void) | |||
310 | * - in case there is no HW filter | 310 | * - in case there is no HW filter |
311 | * - in case the HW filter has errata or limitations | 311 | * - in case the HW filter has errata or limitations |
312 | */ | 312 | */ |
313 | static void intel_pmu_setup_sw_lbr_filter(struct perf_event *event) | 313 | static int intel_pmu_setup_sw_lbr_filter(struct perf_event *event) |
314 | { | 314 | { |
315 | u64 br_type = event->attr.branch_sample_type; | 315 | u64 br_type = event->attr.branch_sample_type; |
316 | int mask = 0; | 316 | int mask = 0; |
@@ -318,8 +318,11 @@ static void intel_pmu_setup_sw_lbr_filter(struct perf_event *event) | |||
318 | if (br_type & PERF_SAMPLE_BRANCH_USER) | 318 | if (br_type & PERF_SAMPLE_BRANCH_USER) |
319 | mask |= X86_BR_USER; | 319 | mask |= X86_BR_USER; |
320 | 320 | ||
321 | if (br_type & PERF_SAMPLE_BRANCH_KERNEL) | 321 | if (br_type & PERF_SAMPLE_BRANCH_KERNEL) { |
322 | if (perf_paranoid_kernel() && !capable(CAP_SYS_ADMIN)) | ||
323 | return -EACCES; | ||
322 | mask |= X86_BR_KERNEL; | 324 | mask |= X86_BR_KERNEL; |
325 | } | ||
323 | 326 | ||
324 | /* we ignore BRANCH_HV here */ | 327 | /* we ignore BRANCH_HV here */ |
325 | 328 | ||
@@ -339,6 +342,8 @@ static void intel_pmu_setup_sw_lbr_filter(struct perf_event *event) | |||
339 | * be used by fixup code for some CPU | 342 | * be used by fixup code for some CPU |
340 | */ | 343 | */ |
341 | event->hw.branch_reg.reg = mask; | 344 | event->hw.branch_reg.reg = mask; |
345 | |||
346 | return 0; | ||
342 | } | 347 | } |
343 | 348 | ||
344 | /* | 349 | /* |
@@ -386,7 +391,9 @@ int intel_pmu_setup_lbr_filter(struct perf_event *event) | |||
386 | /* | 391 | /* |
387 | * setup SW LBR filter | 392 | * setup SW LBR filter |
388 | */ | 393 | */ |
389 | intel_pmu_setup_sw_lbr_filter(event); | 394 | ret = intel_pmu_setup_sw_lbr_filter(event); |
395 | if (ret) | ||
396 | return ret; | ||
390 | 397 | ||
391 | /* | 398 | /* |
392 | * setup HW LBR filter, if any | 399 | * setup HW LBR filter, if any |
@@ -442,8 +449,18 @@ static int branch_type(unsigned long from, unsigned long to) | |||
442 | return X86_BR_NONE; | 449 | return X86_BR_NONE; |
443 | 450 | ||
444 | addr = buf; | 451 | addr = buf; |
445 | } else | 452 | } else { |
446 | addr = (void *)from; | 453 | /* |
454 | * The LBR logs any address in the IP, even if the IP just | ||
455 | * faulted. This means userspace can control the from address. | ||
456 | * Ensure we don't blindy read any address by validating it is | ||
457 | * a known text address. | ||
458 | */ | ||
459 | if (kernel_text_address(from)) | ||
460 | addr = (void *)from; | ||
461 | else | ||
462 | return X86_BR_NONE; | ||
463 | } | ||
447 | 464 | ||
448 | /* | 465 | /* |
449 | * decoder needs to know the ABI especially | 466 | * decoder needs to know the ABI especially |
diff --git a/arch/x86/kernel/cpu/perf_event_intel_uncore.c b/arch/x86/kernel/cpu/perf_event_intel_uncore.c index d0f9e5aa2151..52441a2af538 100644 --- a/arch/x86/kernel/cpu/perf_event_intel_uncore.c +++ b/arch/x86/kernel/cpu/perf_event_intel_uncore.c | |||
@@ -3093,7 +3093,7 @@ static void __init uncore_types_exit(struct intel_uncore_type **types) | |||
3093 | static int __init uncore_type_init(struct intel_uncore_type *type) | 3093 | static int __init uncore_type_init(struct intel_uncore_type *type) |
3094 | { | 3094 | { |
3095 | struct intel_uncore_pmu *pmus; | 3095 | struct intel_uncore_pmu *pmus; |
3096 | struct attribute_group *events_group; | 3096 | struct attribute_group *attr_group; |
3097 | struct attribute **attrs; | 3097 | struct attribute **attrs; |
3098 | int i, j; | 3098 | int i, j; |
3099 | 3099 | ||
@@ -3120,19 +3120,19 @@ static int __init uncore_type_init(struct intel_uncore_type *type) | |||
3120 | while (type->event_descs[i].attr.attr.name) | 3120 | while (type->event_descs[i].attr.attr.name) |
3121 | i++; | 3121 | i++; |
3122 | 3122 | ||
3123 | events_group = kzalloc(sizeof(struct attribute *) * (i + 1) + | 3123 | attr_group = kzalloc(sizeof(struct attribute *) * (i + 1) + |
3124 | sizeof(*events_group), GFP_KERNEL); | 3124 | sizeof(*attr_group), GFP_KERNEL); |
3125 | if (!events_group) | 3125 | if (!attr_group) |
3126 | goto fail; | 3126 | goto fail; |
3127 | 3127 | ||
3128 | attrs = (struct attribute **)(events_group + 1); | 3128 | attrs = (struct attribute **)(attr_group + 1); |
3129 | events_group->name = "events"; | 3129 | attr_group->name = "events"; |
3130 | events_group->attrs = attrs; | 3130 | attr_group->attrs = attrs; |
3131 | 3131 | ||
3132 | for (j = 0; j < i; j++) | 3132 | for (j = 0; j < i; j++) |
3133 | attrs[j] = &type->event_descs[j].attr.attr; | 3133 | attrs[j] = &type->event_descs[j].attr.attr; |
3134 | 3134 | ||
3135 | type->events_group = events_group; | 3135 | type->events_group = attr_group; |
3136 | } | 3136 | } |
3137 | 3137 | ||
3138 | type->pmu_group = &uncore_pmu_attr_group; | 3138 | type->pmu_group = &uncore_pmu_attr_group; |
@@ -3545,11 +3545,12 @@ static int __init uncore_cpu_init(void) | |||
3545 | msr_uncores = nhm_msr_uncores; | 3545 | msr_uncores = nhm_msr_uncores; |
3546 | break; | 3546 | break; |
3547 | case 42: /* Sandy Bridge */ | 3547 | case 42: /* Sandy Bridge */ |
3548 | case 58: /* Ivy Bridge */ | ||
3548 | if (snb_uncore_cbox.num_boxes > max_cores) | 3549 | if (snb_uncore_cbox.num_boxes > max_cores) |
3549 | snb_uncore_cbox.num_boxes = max_cores; | 3550 | snb_uncore_cbox.num_boxes = max_cores; |
3550 | msr_uncores = snb_msr_uncores; | 3551 | msr_uncores = snb_msr_uncores; |
3551 | break; | 3552 | break; |
3552 | case 45: /* Sandy Birdge-EP */ | 3553 | case 45: /* Sandy Bridge-EP */ |
3553 | if (snbep_uncore_cbox.num_boxes > max_cores) | 3554 | if (snbep_uncore_cbox.num_boxes > max_cores) |
3554 | snbep_uncore_cbox.num_boxes = max_cores; | 3555 | snbep_uncore_cbox.num_boxes = max_cores; |
3555 | msr_uncores = snbep_msr_uncores; | 3556 | msr_uncores = snbep_msr_uncores; |
diff --git a/arch/x86/kernel/irq.c b/arch/x86/kernel/irq.c index e4595f105910..84b778962c66 100644 --- a/arch/x86/kernel/irq.c +++ b/arch/x86/kernel/irq.c | |||
@@ -165,10 +165,6 @@ u64 arch_irq_stat_cpu(unsigned int cpu) | |||
165 | u64 arch_irq_stat(void) | 165 | u64 arch_irq_stat(void) |
166 | { | 166 | { |
167 | u64 sum = atomic_read(&irq_err_count); | 167 | u64 sum = atomic_read(&irq_err_count); |
168 | |||
169 | #ifdef CONFIG_X86_IO_APIC | ||
170 | sum += atomic_read(&irq_mis_count); | ||
171 | #endif | ||
172 | return sum; | 168 | return sum; |
173 | } | 169 | } |
174 | 170 | ||
diff --git a/kernel/events/ring_buffer.c b/kernel/events/ring_buffer.c index 97fddb09762b..cd55144270b5 100644 --- a/kernel/events/ring_buffer.c +++ b/kernel/events/ring_buffer.c | |||
@@ -326,11 +326,16 @@ void rb_free(struct ring_buffer *rb) | |||
326 | } | 326 | } |
327 | 327 | ||
328 | #else | 328 | #else |
329 | static int data_page_nr(struct ring_buffer *rb) | ||
330 | { | ||
331 | return rb->nr_pages << page_order(rb); | ||
332 | } | ||
329 | 333 | ||
330 | struct page * | 334 | struct page * |
331 | perf_mmap_to_page(struct ring_buffer *rb, unsigned long pgoff) | 335 | perf_mmap_to_page(struct ring_buffer *rb, unsigned long pgoff) |
332 | { | 336 | { |
333 | if (pgoff > (1UL << page_order(rb))) | 337 | /* The '>' counts in the user page. */ |
338 | if (pgoff > data_page_nr(rb)) | ||
334 | return NULL; | 339 | return NULL; |
335 | 340 | ||
336 | return vmalloc_to_page((void *)rb->user_page + pgoff * PAGE_SIZE); | 341 | return vmalloc_to_page((void *)rb->user_page + pgoff * PAGE_SIZE); |
@@ -350,10 +355,11 @@ static void rb_free_work(struct work_struct *work) | |||
350 | int i, nr; | 355 | int i, nr; |
351 | 356 | ||
352 | rb = container_of(work, struct ring_buffer, work); | 357 | rb = container_of(work, struct ring_buffer, work); |
353 | nr = 1 << page_order(rb); | 358 | nr = data_page_nr(rb); |
354 | 359 | ||
355 | base = rb->user_page; | 360 | base = rb->user_page; |
356 | for (i = 0; i < nr + 1; i++) | 361 | /* The '<=' counts in the user page. */ |
362 | for (i = 0; i <= nr; i++) | ||
357 | perf_mmap_unmark_page(base + (i * PAGE_SIZE)); | 363 | perf_mmap_unmark_page(base + (i * PAGE_SIZE)); |
358 | 364 | ||
359 | vfree(base); | 365 | vfree(base); |
@@ -387,7 +393,7 @@ struct ring_buffer *rb_alloc(int nr_pages, long watermark, int cpu, int flags) | |||
387 | rb->user_page = all_buf; | 393 | rb->user_page = all_buf; |
388 | rb->data_pages[0] = all_buf + PAGE_SIZE; | 394 | rb->data_pages[0] = all_buf + PAGE_SIZE; |
389 | rb->page_order = ilog2(nr_pages); | 395 | rb->page_order = ilog2(nr_pages); |
390 | rb->nr_pages = 1; | 396 | rb->nr_pages = !!nr_pages; |
391 | 397 | ||
392 | ring_buffer_init(rb, watermark, flags); | 398 | ring_buffer_init(rb, watermark, flags); |
393 | 399 | ||