Commit | Line | Data |
---|---|---|
0f4f0672 JI |
1 | /* |
2 | * linux/arch/arm/include/asm/pmu.h | |
3 | * | |
4 | * Copyright (C) 2009 picoChip Designs Ltd, Jamie Iles | |
5 | * | |
6 | * This program is free software; you can redistribute it and/or modify | |
7 | * it under the terms of the GNU General Public License version 2 as | |
8 | * published by the Free Software Foundation. | |
9 | * | |
10 | */ | |
11 | ||
12 | #ifndef __ARM_PMU_H__ | |
13 | #define __ARM_PMU_H__ | |
14 | ||
0e25a5c9 | 15 | #include <linux/interrupt.h> |
0ce47080 | 16 | #include <linux/perf_event.h> |
0e25a5c9 | 17 | |
b0e89590 WD |
18 | /* |
19 | * Types of PMUs that can be accessed directly and require mutual | |
20 | * exclusion between profiling tools. | |
21 | */ | |
28d7f4ec WD |
22 | enum arm_pmu_type { |
23 | ARM_PMU_DEVICE_CPU = 0, | |
24 | ARM_NUM_PMU_DEVICES, | |
25 | }; | |
26 | ||
0e25a5c9 RV |
27 | /* |
28 | * struct arm_pmu_platdata - ARM PMU platform data | |
29 | * | |
30 | * @handle_irq: an optional handler which will be called from the interrupt and | |
31 | * passed the address of the low level handler, and can be used to implement | |
32 | * any platform specific handling before or after calling it. | |
33 | */ | |
34 | struct arm_pmu_platdata { | |
35 | irqreturn_t (*handle_irq)(int irq, void *dev, | |
36 | irq_handler_t pmu_handler); | |
37 | }; | |
38 | ||
0f4f0672 JI |
39 | #ifdef CONFIG_CPU_HAS_PMU |
40 | ||
0f4f0672 JI |
41 | /** |
42 | * reserve_pmu() - reserve the hardware performance counters | |
43 | * | |
44 | * Reserve the hardware performance counters in the system for exclusive use. | |
b0e89590 | 45 | * Returns 0 on success or -EBUSY if the lock is already held. |
0f4f0672 | 46 | */ |
b0e89590 | 47 | extern int |
7fdd3c49 | 48 | reserve_pmu(enum arm_pmu_type type); |
0f4f0672 JI |
49 | |
50 | /** | |
51 | * release_pmu() - Relinquish control of the performance counters | |
52 | * | |
53 | * Release the performance counters and allow someone else to use them. | |
0f4f0672 | 54 | */ |
b0e89590 | 55 | extern void |
f12482c9 | 56 | release_pmu(enum arm_pmu_type type); |
0f4f0672 | 57 | |
0f4f0672 JI |
58 | #else /* CONFIG_CPU_HAS_PMU */ |
59 | ||
49c006b9 WD |
60 | #include <linux/err.h> |
61 | ||
0f4f0672 | 62 | static inline int |
b0e89590 | 63 | reserve_pmu(enum arm_pmu_type type) |
0f4f0672 JI |
64 | { |
65 | return -ENODEV; | |
66 | } | |
67 | ||
b0e89590 WD |
68 | static inline void |
69 | release_pmu(enum arm_pmu_type type) { } | |
0f4f0672 JI |
70 | |
71 | #endif /* CONFIG_CPU_HAS_PMU */ | |
72 | ||
0ce47080 MR |
73 | #ifdef CONFIG_HW_PERF_EVENTS |
74 | ||
75 | /* The events for a given PMU register set. */ | |
76 | struct pmu_hw_events { | |
77 | /* | |
78 | * The events that are active on the PMU for the given index. | |
79 | */ | |
80 | struct perf_event **events; | |
81 | ||
82 | /* | |
83 | * A 1 bit for an index indicates that the counter is being used for | |
84 | * an event. A 0 means that the counter can be used. | |
85 | */ | |
86 | unsigned long *used_mask; | |
87 | ||
88 | /* | |
89 | * Hardware lock to serialize accesses to PMU registers. Needed for the | |
90 | * read/modify/write sequences. | |
91 | */ | |
92 | raw_spinlock_t pmu_lock; | |
93 | }; | |
94 | ||
95 | struct arm_pmu { | |
96 | struct pmu pmu; | |
97 | enum arm_perf_pmu_ids id; | |
98 | enum arm_pmu_type type; | |
99 | cpumask_t active_irqs; | |
100 | const char *name; | |
101 | irqreturn_t (*handle_irq)(int irq_num, void *dev); | |
102 | void (*enable)(struct hw_perf_event *evt, int idx); | |
103 | void (*disable)(struct hw_perf_event *evt, int idx); | |
104 | int (*get_event_idx)(struct pmu_hw_events *hw_events, | |
105 | struct hw_perf_event *hwc); | |
106 | int (*set_event_filter)(struct hw_perf_event *evt, | |
107 | struct perf_event_attr *attr); | |
108 | u32 (*read_counter)(int idx); | |
109 | void (*write_counter)(int idx, u32 val); | |
110 | void (*start)(void); | |
111 | void (*stop)(void); | |
112 | void (*reset)(void *); | |
113 | int (*map_event)(struct perf_event *event); | |
114 | int num_events; | |
115 | atomic_t active_events; | |
116 | struct mutex reserve_mutex; | |
117 | u64 max_period; | |
118 | struct platform_device *plat_device; | |
119 | struct pmu_hw_events *(*get_hw_events)(void); | |
120 | }; | |
121 | ||
122 | #define to_arm_pmu(p) (container_of(p, struct arm_pmu, pmu)) | |
123 | ||
124 | int __init armpmu_register(struct arm_pmu *armpmu, char *name, int type); | |
125 | ||
126 | u64 armpmu_event_update(struct perf_event *event, | |
127 | struct hw_perf_event *hwc, | |
128 | int idx, int overflow); | |
129 | ||
130 | int armpmu_event_set_period(struct perf_event *event, | |
131 | struct hw_perf_event *hwc, | |
132 | int idx); | |
133 | ||
134 | #endif /* CONFIG_HW_PERF_EVENTS */ | |
135 | ||
0f4f0672 | 136 | #endif /* __ARM_PMU_H__ */ |