diff options
Diffstat (limited to 'arch/arm/kernel')
-rw-r--r-- | arch/arm/kernel/Makefile | 3 | ||||
-rw-r--r-- | arch/arm/kernel/perf_event.c | 347 | ||||
-rw-r--r-- | arch/arm/kernel/perf_event_cpu.c | 295 | ||||
-rw-r--r-- | arch/arm/kernel/perf_event_v6.c | 12 | ||||
-rw-r--r-- | arch/arm/kernel/perf_event_v7.c | 32 | ||||
-rw-r--r-- | arch/arm/kernel/perf_event_xscale.c | 10 | ||||
-rw-r--r-- | arch/arm/kernel/pmu.c | 36 |
7 files changed, 374 insertions, 361 deletions
diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile index 7ad2d5cf7008..1c4321430737 100644 --- a/arch/arm/kernel/Makefile +++ b/arch/arm/kernel/Makefile | |||
@@ -69,8 +69,7 @@ obj-$(CONFIG_CPU_XSC3) += xscale-cp0.o | |||
69 | obj-$(CONFIG_CPU_MOHAWK) += xscale-cp0.o | 69 | obj-$(CONFIG_CPU_MOHAWK) += xscale-cp0.o |
70 | obj-$(CONFIG_CPU_PJ4) += pj4-cp0.o | 70 | obj-$(CONFIG_CPU_PJ4) += pj4-cp0.o |
71 | obj-$(CONFIG_IWMMXT) += iwmmxt.o | 71 | obj-$(CONFIG_IWMMXT) += iwmmxt.o |
72 | obj-$(CONFIG_CPU_HAS_PMU) += pmu.o | 72 | obj-$(CONFIG_HW_PERF_EVENTS) += perf_event.o perf_event_cpu.o |
73 | obj-$(CONFIG_HW_PERF_EVENTS) += perf_event.o | ||
74 | AFLAGS_iwmmxt.o := -Wa,-mcpu=iwmmxt | 73 | AFLAGS_iwmmxt.o := -Wa,-mcpu=iwmmxt |
75 | obj-$(CONFIG_ARM_CPU_TOPOLOGY) += topology.o | 74 | obj-$(CONFIG_ARM_CPU_TOPOLOGY) += topology.o |
76 | 75 | ||
diff --git a/arch/arm/kernel/perf_event.c b/arch/arm/kernel/perf_event.c index ab243b87118d..93971b1a4f0b 100644 --- a/arch/arm/kernel/perf_event.c +++ b/arch/arm/kernel/perf_event.c | |||
@@ -12,68 +12,15 @@ | |||
12 | */ | 12 | */ |
13 | #define pr_fmt(fmt) "hw perfevents: " fmt | 13 | #define pr_fmt(fmt) "hw perfevents: " fmt |
14 | 14 | ||
15 | #include <linux/bitmap.h> | ||
16 | #include <linux/interrupt.h> | ||
17 | #include <linux/kernel.h> | 15 | #include <linux/kernel.h> |
18 | #include <linux/export.h> | ||
19 | #include <linux/perf_event.h> | ||
20 | #include <linux/platform_device.h> | 16 | #include <linux/platform_device.h> |
21 | #include <linux/spinlock.h> | 17 | #include <linux/pm_runtime.h> |
22 | #include <linux/uaccess.h> | 18 | #include <linux/uaccess.h> |
23 | 19 | ||
24 | #include <asm/cputype.h> | ||
25 | #include <asm/irq.h> | ||
26 | #include <asm/irq_regs.h> | 20 | #include <asm/irq_regs.h> |
27 | #include <asm/pmu.h> | 21 | #include <asm/pmu.h> |
28 | #include <asm/stacktrace.h> | 22 | #include <asm/stacktrace.h> |
29 | 23 | ||
30 | /* | ||
31 | * ARMv6 supports a maximum of 3 events, starting from index 0. If we add | ||
32 | * another platform that supports more, we need to increase this to be the | ||
33 | * largest of all platforms. | ||
34 | * | ||
35 | * ARMv7 supports up to 32 events: | ||
36 | * cycle counter CCNT + 31 events counters CNT0..30. | ||
37 | * Cortex-A8 has 1+4 counters, Cortex-A9 has 1+6 counters. | ||
38 | */ | ||
39 | #define ARMPMU_MAX_HWEVENTS 32 | ||
40 | |||
41 | static DEFINE_PER_CPU(struct perf_event * [ARMPMU_MAX_HWEVENTS], hw_events); | ||
42 | static DEFINE_PER_CPU(unsigned long [BITS_TO_LONGS(ARMPMU_MAX_HWEVENTS)], used_mask); | ||
43 | static DEFINE_PER_CPU(struct pmu_hw_events, cpu_hw_events); | ||
44 | |||
45 | #define to_arm_pmu(p) (container_of(p, struct arm_pmu, pmu)) | ||
46 | |||
47 | /* Set at runtime when we know what CPU type we are. */ | ||
48 | static struct arm_pmu *cpu_pmu; | ||
49 | |||
50 | const char *perf_pmu_name(void) | ||
51 | { | ||
52 | if (!cpu_pmu) | ||
53 | return NULL; | ||
54 | |||
55 | return cpu_pmu->pmu.name; | ||
56 | } | ||
57 | EXPORT_SYMBOL_GPL(perf_pmu_name); | ||
58 | |||
59 | int perf_num_counters(void) | ||
60 | { | ||
61 | int max_events = 0; | ||
62 | |||
63 | if (cpu_pmu != NULL) | ||
64 | max_events = cpu_pmu->num_events; | ||
65 | |||
66 | return max_events; | ||
67 | } | ||
68 | EXPORT_SYMBOL_GPL(perf_num_counters); | ||
69 | |||
70 | #define HW_OP_UNSUPPORTED 0xFFFF | ||
71 | |||
72 | #define C(_x) \ | ||
73 | PERF_COUNT_HW_CACHE_##_x | ||
74 | |||
75 | #define CACHE_OP_UNSUPPORTED 0xFFFF | ||
76 | |||
77 | static int | 24 | static int |
78 | armpmu_map_cache_event(const unsigned (*cache_map) | 25 | armpmu_map_cache_event(const unsigned (*cache_map) |
79 | [PERF_COUNT_HW_CACHE_MAX] | 26 | [PERF_COUNT_HW_CACHE_MAX] |
@@ -104,7 +51,7 @@ armpmu_map_cache_event(const unsigned (*cache_map) | |||
104 | } | 51 | } |
105 | 52 | ||
106 | static int | 53 | static int |
107 | armpmu_map_event(const unsigned (*event_map)[PERF_COUNT_HW_MAX], u64 config) | 54 | armpmu_map_hw_event(const unsigned (*event_map)[PERF_COUNT_HW_MAX], u64 config) |
108 | { | 55 | { |
109 | int mapping = (*event_map)[config]; | 56 | int mapping = (*event_map)[config]; |
110 | return mapping == HW_OP_UNSUPPORTED ? -ENOENT : mapping; | 57 | return mapping == HW_OP_UNSUPPORTED ? -ENOENT : mapping; |
@@ -116,19 +63,20 @@ armpmu_map_raw_event(u32 raw_event_mask, u64 config) | |||
116 | return (int)(config & raw_event_mask); | 63 | return (int)(config & raw_event_mask); |
117 | } | 64 | } |
118 | 65 | ||
119 | static int map_cpu_event(struct perf_event *event, | 66 | int |
120 | const unsigned (*event_map)[PERF_COUNT_HW_MAX], | 67 | armpmu_map_event(struct perf_event *event, |
121 | const unsigned (*cache_map) | 68 | const unsigned (*event_map)[PERF_COUNT_HW_MAX], |
122 | [PERF_COUNT_HW_CACHE_MAX] | 69 | const unsigned (*cache_map) |
123 | [PERF_COUNT_HW_CACHE_OP_MAX] | 70 | [PERF_COUNT_HW_CACHE_MAX] |
124 | [PERF_COUNT_HW_CACHE_RESULT_MAX], | 71 | [PERF_COUNT_HW_CACHE_OP_MAX] |
125 | u32 raw_event_mask) | 72 | [PERF_COUNT_HW_CACHE_RESULT_MAX], |
73 | u32 raw_event_mask) | ||
126 | { | 74 | { |
127 | u64 config = event->attr.config; | 75 | u64 config = event->attr.config; |
128 | 76 | ||
129 | switch (event->attr.type) { | 77 | switch (event->attr.type) { |
130 | case PERF_TYPE_HARDWARE: | 78 | case PERF_TYPE_HARDWARE: |
131 | return armpmu_map_event(event_map, config); | 79 | return armpmu_map_hw_event(event_map, config); |
132 | case PERF_TYPE_HW_CACHE: | 80 | case PERF_TYPE_HW_CACHE: |
133 | return armpmu_map_cache_event(cache_map, config); | 81 | return armpmu_map_cache_event(cache_map, config); |
134 | case PERF_TYPE_RAW: | 82 | case PERF_TYPE_RAW: |
@@ -222,7 +170,6 @@ armpmu_stop(struct perf_event *event, int flags) | |||
222 | */ | 170 | */ |
223 | if (!(hwc->state & PERF_HES_STOPPED)) { | 171 | if (!(hwc->state & PERF_HES_STOPPED)) { |
224 | armpmu->disable(hwc, hwc->idx); | 172 | armpmu->disable(hwc, hwc->idx); |
225 | barrier(); /* why? */ | ||
226 | armpmu_event_update(event, hwc, hwc->idx); | 173 | armpmu_event_update(event, hwc, hwc->idx); |
227 | hwc->state |= PERF_HES_STOPPED | PERF_HES_UPTODATE; | 174 | hwc->state |= PERF_HES_STOPPED | PERF_HES_UPTODATE; |
228 | } | 175 | } |
@@ -350,99 +297,41 @@ validate_group(struct perf_event *event) | |||
350 | return 0; | 297 | return 0; |
351 | } | 298 | } |
352 | 299 | ||
353 | static irqreturn_t armpmu_platform_irq(int irq, void *dev) | 300 | static irqreturn_t armpmu_dispatch_irq(int irq, void *dev) |
354 | { | 301 | { |
355 | struct arm_pmu *armpmu = (struct arm_pmu *) dev; | 302 | struct arm_pmu *armpmu = (struct arm_pmu *) dev; |
356 | struct platform_device *plat_device = armpmu->plat_device; | 303 | struct platform_device *plat_device = armpmu->plat_device; |
357 | struct arm_pmu_platdata *plat = dev_get_platdata(&plat_device->dev); | 304 | struct arm_pmu_platdata *plat = dev_get_platdata(&plat_device->dev); |
358 | 305 | ||
359 | return plat->handle_irq(irq, dev, armpmu->handle_irq); | 306 | if (plat && plat->handle_irq) |
307 | return plat->handle_irq(irq, dev, armpmu->handle_irq); | ||
308 | else | ||
309 | return armpmu->handle_irq(irq, dev); | ||
360 | } | 310 | } |
361 | 311 | ||
362 | static void | 312 | static void |
363 | armpmu_release_hardware(struct arm_pmu *armpmu) | 313 | armpmu_release_hardware(struct arm_pmu *armpmu) |
364 | { | 314 | { |
365 | int i, irq, irqs; | 315 | armpmu->free_irq(); |
366 | struct platform_device *pmu_device = armpmu->plat_device; | 316 | pm_runtime_put_sync(&armpmu->plat_device->dev); |
367 | struct arm_pmu_platdata *plat = | ||
368 | dev_get_platdata(&pmu_device->dev); | ||
369 | |||
370 | irqs = min(pmu_device->num_resources, num_possible_cpus()); | ||
371 | |||
372 | for (i = 0; i < irqs; ++i) { | ||
373 | if (!cpumask_test_and_clear_cpu(i, &armpmu->active_irqs)) | ||
374 | continue; | ||
375 | irq = platform_get_irq(pmu_device, i); | ||
376 | if (irq >= 0) { | ||
377 | if (plat && plat->disable_irq) | ||
378 | plat->disable_irq(irq); | ||
379 | free_irq(irq, armpmu); | ||
380 | } | ||
381 | } | ||
382 | |||
383 | release_pmu(armpmu->type); | ||
384 | } | 317 | } |
385 | 318 | ||
386 | static int | 319 | static int |
387 | armpmu_reserve_hardware(struct arm_pmu *armpmu) | 320 | armpmu_reserve_hardware(struct arm_pmu *armpmu) |
388 | { | 321 | { |
389 | struct arm_pmu_platdata *plat; | 322 | int err; |
390 | irq_handler_t handle_irq; | ||
391 | int i, err, irq, irqs; | ||
392 | struct platform_device *pmu_device = armpmu->plat_device; | 323 | struct platform_device *pmu_device = armpmu->plat_device; |
393 | 324 | ||
394 | if (!pmu_device) | 325 | if (!pmu_device) |
395 | return -ENODEV; | 326 | return -ENODEV; |
396 | 327 | ||
397 | err = reserve_pmu(armpmu->type); | 328 | pm_runtime_get_sync(&pmu_device->dev); |
329 | err = armpmu->request_irq(armpmu_dispatch_irq); | ||
398 | if (err) { | 330 | if (err) { |
399 | pr_warning("unable to reserve pmu\n"); | 331 | armpmu_release_hardware(armpmu); |
400 | return err; | 332 | return err; |
401 | } | 333 | } |
402 | 334 | ||
403 | plat = dev_get_platdata(&pmu_device->dev); | ||
404 | if (plat && plat->handle_irq) | ||
405 | handle_irq = armpmu_platform_irq; | ||
406 | else | ||
407 | handle_irq = armpmu->handle_irq; | ||
408 | |||
409 | irqs = min(pmu_device->num_resources, num_possible_cpus()); | ||
410 | if (irqs < 1) { | ||
411 | pr_err("no irqs for PMUs defined\n"); | ||
412 | return -ENODEV; | ||
413 | } | ||
414 | |||
415 | for (i = 0; i < irqs; ++i) { | ||
416 | err = 0; | ||
417 | irq = platform_get_irq(pmu_device, i); | ||
418 | if (irq < 0) | ||
419 | continue; | ||
420 | |||
421 | /* | ||
422 | * If we have a single PMU interrupt that we can't shift, | ||
423 | * assume that we're running on a uniprocessor machine and | ||
424 | * continue. Otherwise, continue without this interrupt. | ||
425 | */ | ||
426 | if (irq_set_affinity(irq, cpumask_of(i)) && irqs > 1) { | ||
427 | pr_warning("unable to set irq affinity (irq=%d, cpu=%u)\n", | ||
428 | irq, i); | ||
429 | continue; | ||
430 | } | ||
431 | |||
432 | err = request_irq(irq, handle_irq, | ||
433 | IRQF_DISABLED | IRQF_NOBALANCING, | ||
434 | "arm-pmu", armpmu); | ||
435 | if (err) { | ||
436 | pr_err("unable to request IRQ%d for ARM PMU counters\n", | ||
437 | irq); | ||
438 | armpmu_release_hardware(armpmu); | ||
439 | return err; | ||
440 | } else if (plat && plat->enable_irq) | ||
441 | plat->enable_irq(irq); | ||
442 | |||
443 | cpumask_set_cpu(i, &armpmu->active_irqs); | ||
444 | } | ||
445 | |||
446 | return 0; | 335 | return 0; |
447 | } | 336 | } |
448 | 337 | ||
@@ -581,6 +470,32 @@ static void armpmu_disable(struct pmu *pmu) | |||
581 | armpmu->stop(); | 470 | armpmu->stop(); |
582 | } | 471 | } |
583 | 472 | ||
473 | #ifdef CONFIG_PM_RUNTIME | ||
474 | static int armpmu_runtime_resume(struct device *dev) | ||
475 | { | ||
476 | struct arm_pmu_platdata *plat = dev_get_platdata(dev); | ||
477 | |||
478 | if (plat && plat->runtime_resume) | ||
479 | return plat->runtime_resume(dev); | ||
480 | |||
481 | return 0; | ||
482 | } | ||
483 | |||
484 | static int armpmu_runtime_suspend(struct device *dev) | ||
485 | { | ||
486 | struct arm_pmu_platdata *plat = dev_get_platdata(dev); | ||
487 | |||
488 | if (plat && plat->runtime_suspend) | ||
489 | return plat->runtime_suspend(dev); | ||
490 | |||
491 | return 0; | ||
492 | } | ||
493 | #endif | ||
494 | |||
495 | const struct dev_pm_ops armpmu_dev_pm_ops = { | ||
496 | SET_RUNTIME_PM_OPS(armpmu_runtime_suspend, armpmu_runtime_resume, NULL) | ||
497 | }; | ||
498 | |||
584 | static void __init armpmu_init(struct arm_pmu *armpmu) | 499 | static void __init armpmu_init(struct arm_pmu *armpmu) |
585 | { | 500 | { |
586 | atomic_set(&armpmu->active_events, 0); | 501 | atomic_set(&armpmu->active_events, 0); |
@@ -598,174 +513,14 @@ static void __init armpmu_init(struct arm_pmu *armpmu) | |||
598 | }; | 513 | }; |
599 | } | 514 | } |
600 | 515 | ||
601 | int __init armpmu_register(struct arm_pmu *armpmu, char *name, int type) | 516 | int armpmu_register(struct arm_pmu *armpmu, char *name, int type) |
602 | { | 517 | { |
603 | armpmu_init(armpmu); | 518 | armpmu_init(armpmu); |
519 | pr_info("enabled with %s PMU driver, %d counters available\n", | ||
520 | armpmu->name, armpmu->num_events); | ||
604 | return perf_pmu_register(&armpmu->pmu, name, type); | 521 | return perf_pmu_register(&armpmu->pmu, name, type); |
605 | } | 522 | } |
606 | 523 | ||
607 | /* Include the PMU-specific implementations. */ | ||
608 | #include "perf_event_xscale.c" | ||
609 | #include "perf_event_v6.c" | ||
610 | #include "perf_event_v7.c" | ||
611 | |||
612 | /* | ||
613 | * Ensure the PMU has sane values out of reset. | ||
614 | * This requires SMP to be available, so exists as a separate initcall. | ||
615 | */ | ||
616 | static int __init | ||
617 | cpu_pmu_reset(void) | ||
618 | { | ||
619 | if (cpu_pmu && cpu_pmu->reset) | ||
620 | return on_each_cpu(cpu_pmu->reset, NULL, 1); | ||
621 | return 0; | ||
622 | } | ||
623 | arch_initcall(cpu_pmu_reset); | ||
624 | |||
625 | /* | ||
626 | * PMU platform driver and devicetree bindings. | ||
627 | */ | ||
628 | static struct of_device_id armpmu_of_device_ids[] = { | ||
629 | {.compatible = "arm,cortex-a9-pmu"}, | ||
630 | {.compatible = "arm,cortex-a8-pmu"}, | ||
631 | {.compatible = "arm,arm1136-pmu"}, | ||
632 | {.compatible = "arm,arm1176-pmu"}, | ||
633 | {}, | ||
634 | }; | ||
635 | |||
636 | static struct platform_device_id armpmu_plat_device_ids[] = { | ||
637 | {.name = "arm-pmu"}, | ||
638 | {}, | ||
639 | }; | ||
640 | |||
641 | static int __devinit armpmu_device_probe(struct platform_device *pdev) | ||
642 | { | ||
643 | if (!cpu_pmu) | ||
644 | return -ENODEV; | ||
645 | |||
646 | cpu_pmu->plat_device = pdev; | ||
647 | return 0; | ||
648 | } | ||
649 | |||
650 | static struct platform_driver armpmu_driver = { | ||
651 | .driver = { | ||
652 | .name = "arm-pmu", | ||
653 | .of_match_table = armpmu_of_device_ids, | ||
654 | }, | ||
655 | .probe = armpmu_device_probe, | ||
656 | .id_table = armpmu_plat_device_ids, | ||
657 | }; | ||
658 | |||
659 | static int __init register_pmu_driver(void) | ||
660 | { | ||
661 | return platform_driver_register(&armpmu_driver); | ||
662 | } | ||
663 | device_initcall(register_pmu_driver); | ||
664 | |||
665 | static struct pmu_hw_events *armpmu_get_cpu_events(void) | ||
666 | { | ||
667 | return &__get_cpu_var(cpu_hw_events); | ||
668 | } | ||
669 | |||
670 | static void __init cpu_pmu_init(struct arm_pmu *armpmu) | ||
671 | { | ||
672 | int cpu; | ||
673 | for_each_possible_cpu(cpu) { | ||
674 | struct pmu_hw_events *events = &per_cpu(cpu_hw_events, cpu); | ||
675 | events->events = per_cpu(hw_events, cpu); | ||
676 | events->used_mask = per_cpu(used_mask, cpu); | ||
677 | raw_spin_lock_init(&events->pmu_lock); | ||
678 | } | ||
679 | armpmu->get_hw_events = armpmu_get_cpu_events; | ||
680 | armpmu->type = ARM_PMU_DEVICE_CPU; | ||
681 | } | ||
682 | |||
683 | /* | ||
684 | * PMU hardware loses all context when a CPU goes offline. | ||
685 | * When a CPU is hotplugged back in, since some hardware registers are | ||
686 | * UNKNOWN at reset, the PMU must be explicitly reset to avoid reading | ||
687 | * junk values out of them. | ||
688 | */ | ||
689 | static int __cpuinit pmu_cpu_notify(struct notifier_block *b, | ||
690 | unsigned long action, void *hcpu) | ||
691 | { | ||
692 | if ((action & ~CPU_TASKS_FROZEN) != CPU_STARTING) | ||
693 | return NOTIFY_DONE; | ||
694 | |||
695 | if (cpu_pmu && cpu_pmu->reset) | ||
696 | cpu_pmu->reset(NULL); | ||
697 | |||
698 | return NOTIFY_OK; | ||
699 | } | ||
700 | |||
701 | static struct notifier_block __cpuinitdata pmu_cpu_notifier = { | ||
702 | .notifier_call = pmu_cpu_notify, | ||
703 | }; | ||
704 | |||
705 | /* | ||
706 | * CPU PMU identification and registration. | ||
707 | */ | ||
708 | static int __init | ||
709 | init_hw_perf_events(void) | ||
710 | { | ||
711 | unsigned long cpuid = read_cpuid_id(); | ||
712 | unsigned long implementor = (cpuid & 0xFF000000) >> 24; | ||
713 | unsigned long part_number = (cpuid & 0xFFF0); | ||
714 | |||
715 | /* ARM Ltd CPUs. */ | ||
716 | if (0x41 == implementor) { | ||
717 | switch (part_number) { | ||
718 | case 0xB360: /* ARM1136 */ | ||
719 | case 0xB560: /* ARM1156 */ | ||
720 | case 0xB760: /* ARM1176 */ | ||
721 | cpu_pmu = armv6pmu_init(); | ||
722 | break; | ||
723 | case 0xB020: /* ARM11mpcore */ | ||
724 | cpu_pmu = armv6mpcore_pmu_init(); | ||
725 | break; | ||
726 | case 0xC080: /* Cortex-A8 */ | ||
727 | cpu_pmu = armv7_a8_pmu_init(); | ||
728 | break; | ||
729 | case 0xC090: /* Cortex-A9 */ | ||
730 | cpu_pmu = armv7_a9_pmu_init(); | ||
731 | break; | ||
732 | case 0xC050: /* Cortex-A5 */ | ||
733 | cpu_pmu = armv7_a5_pmu_init(); | ||
734 | break; | ||
735 | case 0xC0F0: /* Cortex-A15 */ | ||
736 | cpu_pmu = armv7_a15_pmu_init(); | ||
737 | break; | ||
738 | case 0xC070: /* Cortex-A7 */ | ||
739 | cpu_pmu = armv7_a7_pmu_init(); | ||
740 | break; | ||
741 | } | ||
742 | /* Intel CPUs [xscale]. */ | ||
743 | } else if (0x69 == implementor) { | ||
744 | part_number = (cpuid >> 13) & 0x7; | ||
745 | switch (part_number) { | ||
746 | case 1: | ||
747 | cpu_pmu = xscale1pmu_init(); | ||
748 | break; | ||
749 | case 2: | ||
750 | cpu_pmu = xscale2pmu_init(); | ||
751 | break; | ||
752 | } | ||
753 | } | ||
754 | |||
755 | if (cpu_pmu) { | ||
756 | pr_info("enabled with %s PMU driver, %d counters available\n", | ||
757 | cpu_pmu->name, cpu_pmu->num_events); | ||
758 | cpu_pmu_init(cpu_pmu); | ||
759 | register_cpu_notifier(&pmu_cpu_notifier); | ||
760 | armpmu_register(cpu_pmu, cpu_pmu->name, PERF_TYPE_RAW); | ||
761 | } else { | ||
762 | pr_info("no hardware support available\n"); | ||
763 | } | ||
764 | |||
765 | return 0; | ||
766 | } | ||
767 | early_initcall(init_hw_perf_events); | ||
768 | |||
769 | /* | 524 | /* |
770 | * Callchain handling code. | 525 | * Callchain handling code. |
771 | */ | 526 | */ |
diff --git a/arch/arm/kernel/perf_event_cpu.c b/arch/arm/kernel/perf_event_cpu.c new file mode 100644 index 000000000000..8d7d8d4de9d6 --- /dev/null +++ b/arch/arm/kernel/perf_event_cpu.c | |||
@@ -0,0 +1,295 @@ | |||
1 | /* | ||
2 | * This program is free software; you can redistribute it and/or modify | ||
3 | * it under the terms of the GNU General Public License version 2 as | ||
4 | * published by the Free Software Foundation. | ||
5 | * | ||
6 | * This program is distributed in the hope that it will be useful, | ||
7 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
8 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
9 | * GNU General Public License for more details. | ||
10 | * | ||
11 | * You should have received a copy of the GNU General Public License | ||
12 | * along with this program; if not, write to the Free Software | ||
13 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
14 | * | ||
15 | * Copyright (C) 2012 ARM Limited | ||
16 | * | ||
17 | * Author: Will Deacon <will.deacon@arm.com> | ||
18 | */ | ||
19 | #define pr_fmt(fmt) "CPU PMU: " fmt | ||
20 | |||
21 | #include <linux/bitmap.h> | ||
22 | #include <linux/export.h> | ||
23 | #include <linux/kernel.h> | ||
24 | #include <linux/of.h> | ||
25 | #include <linux/platform_device.h> | ||
26 | #include <linux/spinlock.h> | ||
27 | |||
28 | #include <asm/cputype.h> | ||
29 | #include <asm/irq_regs.h> | ||
30 | #include <asm/pmu.h> | ||
31 | |||
32 | /* Set at runtime when we know what CPU type we are. */ | ||
33 | static struct arm_pmu *cpu_pmu; | ||
34 | |||
35 | static DEFINE_PER_CPU(struct perf_event * [ARMPMU_MAX_HWEVENTS], hw_events); | ||
36 | static DEFINE_PER_CPU(unsigned long [BITS_TO_LONGS(ARMPMU_MAX_HWEVENTS)], used_mask); | ||
37 | static DEFINE_PER_CPU(struct pmu_hw_events, cpu_hw_events); | ||
38 | |||
39 | /* | ||
40 | * Despite the names, these two functions are CPU-specific and are used | ||
41 | * by the OProfile/perf code. | ||
42 | */ | ||
43 | const char *perf_pmu_name(void) | ||
44 | { | ||
45 | if (!cpu_pmu) | ||
46 | return NULL; | ||
47 | |||
48 | return cpu_pmu->pmu.name; | ||
49 | } | ||
50 | EXPORT_SYMBOL_GPL(perf_pmu_name); | ||
51 | |||
52 | int perf_num_counters(void) | ||
53 | { | ||
54 | int max_events = 0; | ||
55 | |||
56 | if (cpu_pmu != NULL) | ||
57 | max_events = cpu_pmu->num_events; | ||
58 | |||
59 | return max_events; | ||
60 | } | ||
61 | EXPORT_SYMBOL_GPL(perf_num_counters); | ||
62 | |||
63 | /* Include the PMU-specific implementations. */ | ||
64 | #include "perf_event_xscale.c" | ||
65 | #include "perf_event_v6.c" | ||
66 | #include "perf_event_v7.c" | ||
67 | |||
68 | static struct pmu_hw_events *cpu_pmu_get_cpu_events(void) | ||
69 | { | ||
70 | return &__get_cpu_var(cpu_hw_events); | ||
71 | } | ||
72 | |||
73 | static void cpu_pmu_free_irq(void) | ||
74 | { | ||
75 | int i, irq, irqs; | ||
76 | struct platform_device *pmu_device = cpu_pmu->plat_device; | ||
77 | |||
78 | irqs = min(pmu_device->num_resources, num_possible_cpus()); | ||
79 | |||
80 | for (i = 0; i < irqs; ++i) { | ||
81 | if (!cpumask_test_and_clear_cpu(i, &cpu_pmu->active_irqs)) | ||
82 | continue; | ||
83 | irq = platform_get_irq(pmu_device, i); | ||
84 | if (irq >= 0) | ||
85 | free_irq(irq, cpu_pmu); | ||
86 | } | ||
87 | } | ||
88 | |||
89 | static int cpu_pmu_request_irq(irq_handler_t handler) | ||
90 | { | ||
91 | int i, err, irq, irqs; | ||
92 | struct platform_device *pmu_device = cpu_pmu->plat_device; | ||
93 | |||
94 | if (!pmu_device) | ||
95 | return -ENODEV; | ||
96 | |||
97 | irqs = min(pmu_device->num_resources, num_possible_cpus()); | ||
98 | if (irqs < 1) { | ||
99 | pr_err("no irqs for PMUs defined\n"); | ||
100 | return -ENODEV; | ||
101 | } | ||
102 | |||
103 | for (i = 0; i < irqs; ++i) { | ||
104 | err = 0; | ||
105 | irq = platform_get_irq(pmu_device, i); | ||
106 | if (irq < 0) | ||
107 | continue; | ||
108 | |||
109 | /* | ||
110 | * If we have a single PMU interrupt that we can't shift, | ||
111 | * assume that we're running on a uniprocessor machine and | ||
112 | * continue. Otherwise, continue without this interrupt. | ||
113 | */ | ||
114 | if (irq_set_affinity(irq, cpumask_of(i)) && irqs > 1) { | ||
115 | pr_warning("unable to set irq affinity (irq=%d, cpu=%u)\n", | ||
116 | irq, i); | ||
117 | continue; | ||
118 | } | ||
119 | |||
120 | err = request_irq(irq, handler, IRQF_NOBALANCING, "arm-pmu", | ||
121 | cpu_pmu); | ||
122 | if (err) { | ||
123 | pr_err("unable to request IRQ%d for ARM PMU counters\n", | ||
124 | irq); | ||
125 | return err; | ||
126 | } | ||
127 | |||
128 | cpumask_set_cpu(i, &cpu_pmu->active_irqs); | ||
129 | } | ||
130 | |||
131 | return 0; | ||
132 | } | ||
133 | |||
134 | static void __devinit cpu_pmu_init(struct arm_pmu *cpu_pmu) | ||
135 | { | ||
136 | int cpu; | ||
137 | for_each_possible_cpu(cpu) { | ||
138 | struct pmu_hw_events *events = &per_cpu(cpu_hw_events, cpu); | ||
139 | events->events = per_cpu(hw_events, cpu); | ||
140 | events->used_mask = per_cpu(used_mask, cpu); | ||
141 | raw_spin_lock_init(&events->pmu_lock); | ||
142 | } | ||
143 | |||
144 | cpu_pmu->get_hw_events = cpu_pmu_get_cpu_events; | ||
145 | cpu_pmu->request_irq = cpu_pmu_request_irq; | ||
146 | cpu_pmu->free_irq = cpu_pmu_free_irq; | ||
147 | |||
148 | /* Ensure the PMU has sane values out of reset. */ | ||
149 | if (cpu_pmu && cpu_pmu->reset) | ||
150 | on_each_cpu(cpu_pmu->reset, NULL, 1); | ||
151 | } | ||
152 | |||
153 | /* | ||
154 | * PMU hardware loses all context when a CPU goes offline. | ||
155 | * When a CPU is hotplugged back in, since some hardware registers are | ||
156 | * UNKNOWN at reset, the PMU must be explicitly reset to avoid reading | ||
157 | * junk values out of them. | ||
158 | */ | ||
159 | static int __cpuinit cpu_pmu_notify(struct notifier_block *b, | ||
160 | unsigned long action, void *hcpu) | ||
161 | { | ||
162 | if ((action & ~CPU_TASKS_FROZEN) != CPU_STARTING) | ||
163 | return NOTIFY_DONE; | ||
164 | |||
165 | if (cpu_pmu && cpu_pmu->reset) | ||
166 | cpu_pmu->reset(NULL); | ||
167 | |||
168 | return NOTIFY_OK; | ||
169 | } | ||
170 | |||
171 | static struct notifier_block __cpuinitdata cpu_pmu_hotplug_notifier = { | ||
172 | .notifier_call = cpu_pmu_notify, | ||
173 | }; | ||
174 | |||
175 | /* | ||
176 | * PMU platform driver and devicetree bindings. | ||
177 | */ | ||
178 | static struct of_device_id __devinitdata cpu_pmu_of_device_ids[] = { | ||
179 | {.compatible = "arm,cortex-a15-pmu", .data = armv7_a15_pmu_init}, | ||
180 | {.compatible = "arm,cortex-a9-pmu", .data = armv7_a9_pmu_init}, | ||
181 | {.compatible = "arm,cortex-a8-pmu", .data = armv7_a8_pmu_init}, | ||
182 | {.compatible = "arm,cortex-a7-pmu", .data = armv7_a7_pmu_init}, | ||
183 | {.compatible = "arm,cortex-a5-pmu", .data = armv7_a5_pmu_init}, | ||
184 | {.compatible = "arm,arm11mpcore-pmu", .data = armv6mpcore_pmu_init}, | ||
185 | {.compatible = "arm,arm1176-pmu", .data = armv6pmu_init}, | ||
186 | {.compatible = "arm,arm1136-pmu", .data = armv6pmu_init}, | ||
187 | {}, | ||
188 | }; | ||
189 | |||
190 | static struct platform_device_id __devinitdata cpu_pmu_plat_device_ids[] = { | ||
191 | {.name = "arm-pmu"}, | ||
192 | {}, | ||
193 | }; | ||
194 | |||
195 | /* | ||
196 | * CPU PMU identification and probing. | ||
197 | */ | ||
198 | static struct arm_pmu *__devinit probe_current_pmu(void) | ||
199 | { | ||
200 | struct arm_pmu *pmu = NULL; | ||
201 | int cpu = get_cpu(); | ||
202 | unsigned long cpuid = read_cpuid_id(); | ||
203 | unsigned long implementor = (cpuid & 0xFF000000) >> 24; | ||
204 | unsigned long part_number = (cpuid & 0xFFF0); | ||
205 | |||
206 | pr_info("probing PMU on CPU %d\n", cpu); | ||
207 | |||
208 | /* ARM Ltd CPUs. */ | ||
209 | if (0x41 == implementor) { | ||
210 | switch (part_number) { | ||
211 | case 0xB360: /* ARM1136 */ | ||
212 | case 0xB560: /* ARM1156 */ | ||
213 | case 0xB760: /* ARM1176 */ | ||
214 | pmu = armv6pmu_init(); | ||
215 | break; | ||
216 | case 0xB020: /* ARM11mpcore */ | ||
217 | pmu = armv6mpcore_pmu_init(); | ||
218 | break; | ||
219 | case 0xC080: /* Cortex-A8 */ | ||
220 | pmu = armv7_a8_pmu_init(); | ||
221 | break; | ||
222 | case 0xC090: /* Cortex-A9 */ | ||
223 | pmu = armv7_a9_pmu_init(); | ||
224 | break; | ||
225 | case 0xC050: /* Cortex-A5 */ | ||
226 | pmu = armv7_a5_pmu_init(); | ||
227 | break; | ||
228 | case 0xC0F0: /* Cortex-A15 */ | ||
229 | pmu = armv7_a15_pmu_init(); | ||
230 | break; | ||
231 | case 0xC070: /* Cortex-A7 */ | ||
232 | pmu = armv7_a7_pmu_init(); | ||
233 | break; | ||
234 | } | ||
235 | /* Intel CPUs [xscale]. */ | ||
236 | } else if (0x69 == implementor) { | ||
237 | part_number = (cpuid >> 13) & 0x7; | ||
238 | switch (part_number) { | ||
239 | case 1: | ||
240 | pmu = xscale1pmu_init(); | ||
241 | break; | ||
242 | case 2: | ||
243 | pmu = xscale2pmu_init(); | ||
244 | break; | ||
245 | } | ||
246 | } | ||
247 | |||
248 | put_cpu(); | ||
249 | return pmu; | ||
250 | } | ||
251 | |||
252 | static int __devinit cpu_pmu_device_probe(struct platform_device *pdev) | ||
253 | { | ||
254 | const struct of_device_id *of_id; | ||
255 | struct arm_pmu *(*init_fn)(void); | ||
256 | struct device_node *node = pdev->dev.of_node; | ||
257 | |||
258 | if (cpu_pmu) { | ||
259 | pr_info("attempt to register multiple PMU devices!"); | ||
260 | return -ENOSPC; | ||
261 | } | ||
262 | |||
263 | if (node && (of_id = of_match_node(cpu_pmu_of_device_ids, pdev->dev.of_node))) { | ||
264 | init_fn = of_id->data; | ||
265 | cpu_pmu = init_fn(); | ||
266 | } else { | ||
267 | cpu_pmu = probe_current_pmu(); | ||
268 | } | ||
269 | |||
270 | if (!cpu_pmu) | ||
271 | return -ENODEV; | ||
272 | |||
273 | cpu_pmu->plat_device = pdev; | ||
274 | cpu_pmu_init(cpu_pmu); | ||
275 | register_cpu_notifier(&cpu_pmu_hotplug_notifier); | ||
276 | armpmu_register(cpu_pmu, cpu_pmu->name, PERF_TYPE_RAW); | ||
277 | |||
278 | return 0; | ||
279 | } | ||
280 | |||
281 | static struct platform_driver cpu_pmu_driver = { | ||
282 | .driver = { | ||
283 | .name = "arm-pmu", | ||
284 | .pm = &armpmu_dev_pm_ops, | ||
285 | .of_match_table = cpu_pmu_of_device_ids, | ||
286 | }, | ||
287 | .probe = cpu_pmu_device_probe, | ||
288 | .id_table = cpu_pmu_plat_device_ids, | ||
289 | }; | ||
290 | |||
291 | static int __init register_pmu_driver(void) | ||
292 | { | ||
293 | return platform_driver_register(&cpu_pmu_driver); | ||
294 | } | ||
295 | device_initcall(register_pmu_driver); | ||
diff --git a/arch/arm/kernel/perf_event_v6.c b/arch/arm/kernel/perf_event_v6.c index c90fcb2b6967..6ccc07971745 100644 --- a/arch/arm/kernel/perf_event_v6.c +++ b/arch/arm/kernel/perf_event_v6.c | |||
@@ -645,7 +645,7 @@ armv6mpcore_pmu_disable_event(struct hw_perf_event *hwc, | |||
645 | 645 | ||
646 | static int armv6_map_event(struct perf_event *event) | 646 | static int armv6_map_event(struct perf_event *event) |
647 | { | 647 | { |
648 | return map_cpu_event(event, &armv6_perf_map, | 648 | return armpmu_map_event(event, &armv6_perf_map, |
649 | &armv6_perf_cache_map, 0xFF); | 649 | &armv6_perf_cache_map, 0xFF); |
650 | } | 650 | } |
651 | 651 | ||
@@ -664,7 +664,7 @@ static struct arm_pmu armv6pmu = { | |||
664 | .max_period = (1LLU << 32) - 1, | 664 | .max_period = (1LLU << 32) - 1, |
665 | }; | 665 | }; |
666 | 666 | ||
667 | static struct arm_pmu *__init armv6pmu_init(void) | 667 | static struct arm_pmu *__devinit armv6pmu_init(void) |
668 | { | 668 | { |
669 | return &armv6pmu; | 669 | return &armv6pmu; |
670 | } | 670 | } |
@@ -679,7 +679,7 @@ static struct arm_pmu *__init armv6pmu_init(void) | |||
679 | 679 | ||
680 | static int armv6mpcore_map_event(struct perf_event *event) | 680 | static int armv6mpcore_map_event(struct perf_event *event) |
681 | { | 681 | { |
682 | return map_cpu_event(event, &armv6mpcore_perf_map, | 682 | return armpmu_map_event(event, &armv6mpcore_perf_map, |
683 | &armv6mpcore_perf_cache_map, 0xFF); | 683 | &armv6mpcore_perf_cache_map, 0xFF); |
684 | } | 684 | } |
685 | 685 | ||
@@ -698,17 +698,17 @@ static struct arm_pmu armv6mpcore_pmu = { | |||
698 | .max_period = (1LLU << 32) - 1, | 698 | .max_period = (1LLU << 32) - 1, |
699 | }; | 699 | }; |
700 | 700 | ||
701 | static struct arm_pmu *__init armv6mpcore_pmu_init(void) | 701 | static struct arm_pmu *__devinit armv6mpcore_pmu_init(void) |
702 | { | 702 | { |
703 | return &armv6mpcore_pmu; | 703 | return &armv6mpcore_pmu; |
704 | } | 704 | } |
705 | #else | 705 | #else |
706 | static struct arm_pmu *__init armv6pmu_init(void) | 706 | static struct arm_pmu *__devinit armv6pmu_init(void) |
707 | { | 707 | { |
708 | return NULL; | 708 | return NULL; |
709 | } | 709 | } |
710 | 710 | ||
711 | static struct arm_pmu *__init armv6mpcore_pmu_init(void) | 711 | static struct arm_pmu *__devinit armv6mpcore_pmu_init(void) |
712 | { | 712 | { |
713 | return NULL; | 713 | return NULL; |
714 | } | 714 | } |
diff --git a/arch/arm/kernel/perf_event_v7.c b/arch/arm/kernel/perf_event_v7.c index f04070bd2183..bd4b090ebcfd 100644 --- a/arch/arm/kernel/perf_event_v7.c +++ b/arch/arm/kernel/perf_event_v7.c | |||
@@ -1204,31 +1204,31 @@ static void armv7pmu_reset(void *info) | |||
1204 | 1204 | ||
1205 | static int armv7_a8_map_event(struct perf_event *event) | 1205 | static int armv7_a8_map_event(struct perf_event *event) |
1206 | { | 1206 | { |
1207 | return map_cpu_event(event, &armv7_a8_perf_map, | 1207 | return armpmu_map_event(event, &armv7_a8_perf_map, |
1208 | &armv7_a8_perf_cache_map, 0xFF); | 1208 | &armv7_a8_perf_cache_map, 0xFF); |
1209 | } | 1209 | } |
1210 | 1210 | ||
1211 | static int armv7_a9_map_event(struct perf_event *event) | 1211 | static int armv7_a9_map_event(struct perf_event *event) |
1212 | { | 1212 | { |
1213 | return map_cpu_event(event, &armv7_a9_perf_map, | 1213 | return armpmu_map_event(event, &armv7_a9_perf_map, |
1214 | &armv7_a9_perf_cache_map, 0xFF); | 1214 | &armv7_a9_perf_cache_map, 0xFF); |
1215 | } | 1215 | } |
1216 | 1216 | ||
1217 | static int armv7_a5_map_event(struct perf_event *event) | 1217 | static int armv7_a5_map_event(struct perf_event *event) |
1218 | { | 1218 | { |
1219 | return map_cpu_event(event, &armv7_a5_perf_map, | 1219 | return armpmu_map_event(event, &armv7_a5_perf_map, |
1220 | &armv7_a5_perf_cache_map, 0xFF); | 1220 | &armv7_a5_perf_cache_map, 0xFF); |
1221 | } | 1221 | } |
1222 | 1222 | ||
1223 | static int armv7_a15_map_event(struct perf_event *event) | 1223 | static int armv7_a15_map_event(struct perf_event *event) |
1224 | { | 1224 | { |
1225 | return map_cpu_event(event, &armv7_a15_perf_map, | 1225 | return armpmu_map_event(event, &armv7_a15_perf_map, |
1226 | &armv7_a15_perf_cache_map, 0xFF); | 1226 | &armv7_a15_perf_cache_map, 0xFF); |
1227 | } | 1227 | } |
1228 | 1228 | ||
1229 | static int armv7_a7_map_event(struct perf_event *event) | 1229 | static int armv7_a7_map_event(struct perf_event *event) |
1230 | { | 1230 | { |
1231 | return map_cpu_event(event, &armv7_a7_perf_map, | 1231 | return armpmu_map_event(event, &armv7_a7_perf_map, |
1232 | &armv7_a7_perf_cache_map, 0xFF); | 1232 | &armv7_a7_perf_cache_map, 0xFF); |
1233 | } | 1233 | } |
1234 | 1234 | ||
@@ -1245,7 +1245,7 @@ static struct arm_pmu armv7pmu = { | |||
1245 | .max_period = (1LLU << 32) - 1, | 1245 | .max_period = (1LLU << 32) - 1, |
1246 | }; | 1246 | }; |
1247 | 1247 | ||
1248 | static u32 __init armv7_read_num_pmnc_events(void) | 1248 | static u32 __devinit armv7_read_num_pmnc_events(void) |
1249 | { | 1249 | { |
1250 | u32 nb_cnt; | 1250 | u32 nb_cnt; |
1251 | 1251 | ||
@@ -1256,7 +1256,7 @@ static u32 __init armv7_read_num_pmnc_events(void) | |||
1256 | return nb_cnt + 1; | 1256 | return nb_cnt + 1; |
1257 | } | 1257 | } |
1258 | 1258 | ||
1259 | static struct arm_pmu *__init armv7_a8_pmu_init(void) | 1259 | static struct arm_pmu *__devinit armv7_a8_pmu_init(void) |
1260 | { | 1260 | { |
1261 | armv7pmu.name = "ARMv7 Cortex-A8"; | 1261 | armv7pmu.name = "ARMv7 Cortex-A8"; |
1262 | armv7pmu.map_event = armv7_a8_map_event; | 1262 | armv7pmu.map_event = armv7_a8_map_event; |
@@ -1264,7 +1264,7 @@ static struct arm_pmu *__init armv7_a8_pmu_init(void) | |||
1264 | return &armv7pmu; | 1264 | return &armv7pmu; |
1265 | } | 1265 | } |
1266 | 1266 | ||
1267 | static struct arm_pmu *__init armv7_a9_pmu_init(void) | 1267 | static struct arm_pmu *__devinit armv7_a9_pmu_init(void) |
1268 | { | 1268 | { |
1269 | armv7pmu.name = "ARMv7 Cortex-A9"; | 1269 | armv7pmu.name = "ARMv7 Cortex-A9"; |
1270 | armv7pmu.map_event = armv7_a9_map_event; | 1270 | armv7pmu.map_event = armv7_a9_map_event; |
@@ -1272,7 +1272,7 @@ static struct arm_pmu *__init armv7_a9_pmu_init(void) | |||
1272 | return &armv7pmu; | 1272 | return &armv7pmu; |
1273 | } | 1273 | } |
1274 | 1274 | ||
1275 | static struct arm_pmu *__init armv7_a5_pmu_init(void) | 1275 | static struct arm_pmu *__devinit armv7_a5_pmu_init(void) |
1276 | { | 1276 | { |
1277 | armv7pmu.name = "ARMv7 Cortex-A5"; | 1277 | armv7pmu.name = "ARMv7 Cortex-A5"; |
1278 | armv7pmu.map_event = armv7_a5_map_event; | 1278 | armv7pmu.map_event = armv7_a5_map_event; |
@@ -1280,7 +1280,7 @@ static struct arm_pmu *__init armv7_a5_pmu_init(void) | |||
1280 | return &armv7pmu; | 1280 | return &armv7pmu; |
1281 | } | 1281 | } |
1282 | 1282 | ||
1283 | static struct arm_pmu *__init armv7_a15_pmu_init(void) | 1283 | static struct arm_pmu *__devinit armv7_a15_pmu_init(void) |
1284 | { | 1284 | { |
1285 | armv7pmu.name = "ARMv7 Cortex-A15"; | 1285 | armv7pmu.name = "ARMv7 Cortex-A15"; |
1286 | armv7pmu.map_event = armv7_a15_map_event; | 1286 | armv7pmu.map_event = armv7_a15_map_event; |
@@ -1289,7 +1289,7 @@ static struct arm_pmu *__init armv7_a15_pmu_init(void) | |||
1289 | return &armv7pmu; | 1289 | return &armv7pmu; |
1290 | } | 1290 | } |
1291 | 1291 | ||
1292 | static struct arm_pmu *__init armv7_a7_pmu_init(void) | 1292 | static struct arm_pmu *__devinit armv7_a7_pmu_init(void) |
1293 | { | 1293 | { |
1294 | armv7pmu.name = "ARMv7 Cortex-A7"; | 1294 | armv7pmu.name = "ARMv7 Cortex-A7"; |
1295 | armv7pmu.map_event = armv7_a7_map_event; | 1295 | armv7pmu.map_event = armv7_a7_map_event; |
@@ -1298,27 +1298,27 @@ static struct arm_pmu *__init armv7_a7_pmu_init(void) | |||
1298 | return &armv7pmu; | 1298 | return &armv7pmu; |
1299 | } | 1299 | } |
1300 | #else | 1300 | #else |
1301 | static struct arm_pmu *__init armv7_a8_pmu_init(void) | 1301 | static struct arm_pmu *__devinit armv7_a8_pmu_init(void) |
1302 | { | 1302 | { |
1303 | return NULL; | 1303 | return NULL; |
1304 | } | 1304 | } |
1305 | 1305 | ||
1306 | static struct arm_pmu *__init armv7_a9_pmu_init(void) | 1306 | static struct arm_pmu *__devinit armv7_a9_pmu_init(void) |
1307 | { | 1307 | { |
1308 | return NULL; | 1308 | return NULL; |
1309 | } | 1309 | } |
1310 | 1310 | ||
1311 | static struct arm_pmu *__init armv7_a5_pmu_init(void) | 1311 | static struct arm_pmu *__devinit armv7_a5_pmu_init(void) |
1312 | { | 1312 | { |
1313 | return NULL; | 1313 | return NULL; |
1314 | } | 1314 | } |
1315 | 1315 | ||
1316 | static struct arm_pmu *__init armv7_a15_pmu_init(void) | 1316 | static struct arm_pmu *__devinit armv7_a15_pmu_init(void) |
1317 | { | 1317 | { |
1318 | return NULL; | 1318 | return NULL; |
1319 | } | 1319 | } |
1320 | 1320 | ||
1321 | static struct arm_pmu *__init armv7_a7_pmu_init(void) | 1321 | static struct arm_pmu *__devinit armv7_a7_pmu_init(void) |
1322 | { | 1322 | { |
1323 | return NULL; | 1323 | return NULL; |
1324 | } | 1324 | } |
diff --git a/arch/arm/kernel/perf_event_xscale.c b/arch/arm/kernel/perf_event_xscale.c index f759fe0bab63..426e19f380a2 100644 --- a/arch/arm/kernel/perf_event_xscale.c +++ b/arch/arm/kernel/perf_event_xscale.c | |||
@@ -430,7 +430,7 @@ xscale1pmu_write_counter(int counter, u32 val) | |||
430 | 430 | ||
431 | static int xscale_map_event(struct perf_event *event) | 431 | static int xscale_map_event(struct perf_event *event) |
432 | { | 432 | { |
433 | return map_cpu_event(event, &xscale_perf_map, | 433 | return armpmu_map_event(event, &xscale_perf_map, |
434 | &xscale_perf_cache_map, 0xFF); | 434 | &xscale_perf_cache_map, 0xFF); |
435 | } | 435 | } |
436 | 436 | ||
@@ -449,7 +449,7 @@ static struct arm_pmu xscale1pmu = { | |||
449 | .max_period = (1LLU << 32) - 1, | 449 | .max_period = (1LLU << 32) - 1, |
450 | }; | 450 | }; |
451 | 451 | ||
452 | static struct arm_pmu *__init xscale1pmu_init(void) | 452 | static struct arm_pmu *__devinit xscale1pmu_init(void) |
453 | { | 453 | { |
454 | return &xscale1pmu; | 454 | return &xscale1pmu; |
455 | } | 455 | } |
@@ -816,17 +816,17 @@ static struct arm_pmu xscale2pmu = { | |||
816 | .max_period = (1LLU << 32) - 1, | 816 | .max_period = (1LLU << 32) - 1, |
817 | }; | 817 | }; |
818 | 818 | ||
819 | static struct arm_pmu *__init xscale2pmu_init(void) | 819 | static struct arm_pmu *__devinit xscale2pmu_init(void) |
820 | { | 820 | { |
821 | return &xscale2pmu; | 821 | return &xscale2pmu; |
822 | } | 822 | } |
823 | #else | 823 | #else |
824 | static struct arm_pmu *__init xscale1pmu_init(void) | 824 | static struct arm_pmu *__devinit xscale1pmu_init(void) |
825 | { | 825 | { |
826 | return NULL; | 826 | return NULL; |
827 | } | 827 | } |
828 | 828 | ||
829 | static struct arm_pmu *__init xscale2pmu_init(void) | 829 | static struct arm_pmu *__devinit xscale2pmu_init(void) |
830 | { | 830 | { |
831 | return NULL; | 831 | return NULL; |
832 | } | 832 | } |
diff --git a/arch/arm/kernel/pmu.c b/arch/arm/kernel/pmu.c deleted file mode 100644 index 2334bf8a650a..000000000000 --- a/arch/arm/kernel/pmu.c +++ /dev/null | |||
@@ -1,36 +0,0 @@ | |||
1 | /* | ||
2 | * linux/arch/arm/kernel/pmu.c | ||
3 | * | ||
4 | * Copyright (C) 2009 picoChip Designs Ltd, Jamie Iles | ||
5 | * Copyright (C) 2010 ARM Ltd, Will Deacon | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License version 2 as | ||
9 | * published by the Free Software Foundation. | ||
10 | * | ||
11 | */ | ||
12 | |||
13 | #include <linux/err.h> | ||
14 | #include <linux/kernel.h> | ||
15 | #include <linux/module.h> | ||
16 | |||
17 | #include <asm/pmu.h> | ||
18 | |||
19 | /* | ||
20 | * PMU locking to ensure mutual exclusion between different subsystems. | ||
21 | */ | ||
22 | static unsigned long pmu_lock[BITS_TO_LONGS(ARM_NUM_PMU_DEVICES)]; | ||
23 | |||
24 | int | ||
25 | reserve_pmu(enum arm_pmu_type type) | ||
26 | { | ||
27 | return test_and_set_bit_lock(type, pmu_lock) ? -EBUSY : 0; | ||
28 | } | ||
29 | EXPORT_SYMBOL_GPL(reserve_pmu); | ||
30 | |||
31 | void | ||
32 | release_pmu(enum arm_pmu_type type) | ||
33 | { | ||
34 | clear_bit_unlock(type, pmu_lock); | ||
35 | } | ||
36 | EXPORT_SYMBOL_GPL(release_pmu); | ||