diff options
26 files changed, 2767 insertions, 118 deletions
diff --git a/arch/x86/kernel/cpu/Makefile b/arch/x86/kernel/cpu/Makefile index 6ab6aa2fdfdd..bac4c3804cc7 100644 --- a/arch/x86/kernel/cpu/Makefile +++ b/arch/x86/kernel/cpu/Makefile | |||
@@ -32,7 +32,9 @@ obj-$(CONFIG_PERF_EVENTS) += perf_event.o | |||
32 | 32 | ||
33 | ifdef CONFIG_PERF_EVENTS | 33 | ifdef CONFIG_PERF_EVENTS |
34 | obj-$(CONFIG_CPU_SUP_AMD) += perf_event_amd.o | 34 | obj-$(CONFIG_CPU_SUP_AMD) += perf_event_amd.o |
35 | obj-$(CONFIG_CPU_SUP_INTEL) += perf_event_p6.o perf_event_p4.o perf_event_intel_lbr.o perf_event_intel_ds.o perf_event_intel.o | 35 | obj-$(CONFIG_CPU_SUP_INTEL) += perf_event_p6.o perf_event_p4.o |
36 | obj-$(CONFIG_CPU_SUP_INTEL) += perf_event_intel_lbr.o perf_event_intel_ds.o perf_event_intel.o | ||
37 | obj-$(CONFIG_CPU_SUP_INTEL) += perf_event_intel_uncore.o | ||
36 | endif | 38 | endif |
37 | 39 | ||
38 | obj-$(CONFIG_X86_MCE) += mcheck/ | 40 | obj-$(CONFIG_X86_MCE) += mcheck/ |
diff --git a/arch/x86/kernel/cpu/perf_event.c b/arch/x86/kernel/cpu/perf_event.c index 766c76d5ec4c..6d32aefc9dbd 100644 --- a/arch/x86/kernel/cpu/perf_event.c +++ b/arch/x86/kernel/cpu/perf_event.c | |||
@@ -626,7 +626,7 @@ static bool __perf_sched_find_counter(struct perf_sched *sched) | |||
626 | c = sched->constraints[sched->state.event]; | 626 | c = sched->constraints[sched->state.event]; |
627 | 627 | ||
628 | /* Prefer fixed purpose counters */ | 628 | /* Prefer fixed purpose counters */ |
629 | if (x86_pmu.num_counters_fixed) { | 629 | if (c->idxmsk64 & (~0ULL << X86_PMC_IDX_FIXED)) { |
630 | idx = X86_PMC_IDX_FIXED; | 630 | idx = X86_PMC_IDX_FIXED; |
631 | for_each_set_bit_from(idx, c->idxmsk, X86_PMC_IDX_MAX) { | 631 | for_each_set_bit_from(idx, c->idxmsk, X86_PMC_IDX_MAX) { |
632 | if (!__test_and_set_bit(idx, sched->state.used)) | 632 | if (!__test_and_set_bit(idx, sched->state.used)) |
@@ -693,8 +693,8 @@ static bool perf_sched_next_event(struct perf_sched *sched) | |||
693 | /* | 693 | /* |
694 | * Assign a counter for each event. | 694 | * Assign a counter for each event. |
695 | */ | 695 | */ |
696 | static int perf_assign_events(struct event_constraint **constraints, int n, | 696 | int perf_assign_events(struct event_constraint **constraints, int n, |
697 | int wmin, int wmax, int *assign) | 697 | int wmin, int wmax, int *assign) |
698 | { | 698 | { |
699 | struct perf_sched sched; | 699 | struct perf_sched sched; |
700 | 700 | ||
@@ -823,7 +823,7 @@ static inline void x86_assign_hw_event(struct perf_event *event, | |||
823 | } else { | 823 | } else { |
824 | hwc->config_base = x86_pmu_config_addr(hwc->idx); | 824 | hwc->config_base = x86_pmu_config_addr(hwc->idx); |
825 | hwc->event_base = x86_pmu_event_addr(hwc->idx); | 825 | hwc->event_base = x86_pmu_event_addr(hwc->idx); |
826 | hwc->event_base_rdpmc = x86_pmu_addr_offset(hwc->idx); | 826 | hwc->event_base_rdpmc = hwc->idx; |
827 | } | 827 | } |
828 | } | 828 | } |
829 | 829 | ||
diff --git a/arch/x86/kernel/cpu/perf_event.h b/arch/x86/kernel/cpu/perf_event.h index 3df3de9452a9..83238f2a12b2 100644 --- a/arch/x86/kernel/cpu/perf_event.h +++ b/arch/x86/kernel/cpu/perf_event.h | |||
@@ -481,6 +481,8 @@ static inline void __x86_pmu_enable_event(struct hw_perf_event *hwc, | |||
481 | 481 | ||
482 | void x86_pmu_enable_all(int added); | 482 | void x86_pmu_enable_all(int added); |
483 | 483 | ||
484 | int perf_assign_events(struct event_constraint **constraints, int n, | ||
485 | int wmin, int wmax, int *assign); | ||
484 | int x86_schedule_events(struct cpu_hw_events *cpuc, int n, int *assign); | 486 | int x86_schedule_events(struct cpu_hw_events *cpuc, int n, int *assign); |
485 | 487 | ||
486 | void x86_pmu_stop(struct perf_event *event, int flags); | 488 | void x86_pmu_stop(struct perf_event *event, int flags); |
diff --git a/arch/x86/kernel/cpu/perf_event_intel_uncore.c b/arch/x86/kernel/cpu/perf_event_intel_uncore.c new file mode 100644 index 000000000000..28a8413ca199 --- /dev/null +++ b/arch/x86/kernel/cpu/perf_event_intel_uncore.c | |||
@@ -0,0 +1,1703 @@ | |||
1 | #include "perf_event_intel_uncore.h" | ||
2 | |||
3 | static struct intel_uncore_type *empty_uncore[] = { NULL, }; | ||
4 | static struct intel_uncore_type **msr_uncores = empty_uncore; | ||
5 | static struct intel_uncore_type **pci_uncores = empty_uncore; | ||
6 | /* pci bus to socket mapping */ | ||
7 | static int pcibus_to_physid[256] = { [0 ... 255] = -1, }; | ||
8 | |||
9 | static DEFINE_RAW_SPINLOCK(uncore_box_lock); | ||
10 | |||
11 | /* mask of cpus that collect uncore events */ | ||
12 | static cpumask_t uncore_cpu_mask; | ||
13 | |||
14 | /* constraint for the fixed counter */ | ||
15 | static struct event_constraint constraint_fixed = | ||
16 | EVENT_CONSTRAINT(~0ULL, 1 << UNCORE_PMC_IDX_FIXED, ~0ULL); | ||
17 | |||
18 | DEFINE_UNCORE_FORMAT_ATTR(event, event, "config:0-7"); | ||
19 | DEFINE_UNCORE_FORMAT_ATTR(umask, umask, "config:8-15"); | ||
20 | DEFINE_UNCORE_FORMAT_ATTR(edge, edge, "config:18"); | ||
21 | DEFINE_UNCORE_FORMAT_ATTR(inv, inv, "config:23"); | ||
22 | DEFINE_UNCORE_FORMAT_ATTR(cmask5, cmask, "config:24-28"); | ||
23 | DEFINE_UNCORE_FORMAT_ATTR(cmask8, cmask, "config:24-31"); | ||
24 | DEFINE_UNCORE_FORMAT_ATTR(thresh8, thresh, "config:24-31"); | ||
25 | DEFINE_UNCORE_FORMAT_ATTR(thresh5, thresh, "config:24-28"); | ||
26 | DEFINE_UNCORE_FORMAT_ATTR(occ_sel, occ_sel, "config:14-15"); | ||
27 | DEFINE_UNCORE_FORMAT_ATTR(occ_invert, occ_invert, "config:30"); | ||
28 | DEFINE_UNCORE_FORMAT_ATTR(occ_edge, occ_edge, "config:14-51"); | ||
29 | |||
30 | /* Sandy Bridge-EP uncore support */ | ||
31 | static void snbep_uncore_pci_disable_box(struct intel_uncore_box *box) | ||
32 | { | ||
33 | struct pci_dev *pdev = box->pci_dev; | ||
34 | int box_ctl = uncore_pci_box_ctl(box); | ||
35 | u32 config; | ||
36 | |||
37 | pci_read_config_dword(pdev, box_ctl, &config); | ||
38 | config |= SNBEP_PMON_BOX_CTL_FRZ; | ||
39 | pci_write_config_dword(pdev, box_ctl, config); | ||
40 | } | ||
41 | |||
42 | static void snbep_uncore_pci_enable_box(struct intel_uncore_box *box) | ||
43 | { | ||
44 | struct pci_dev *pdev = box->pci_dev; | ||
45 | int box_ctl = uncore_pci_box_ctl(box); | ||
46 | u32 config; | ||
47 | |||
48 | pci_read_config_dword(pdev, box_ctl, &config); | ||
49 | config &= ~SNBEP_PMON_BOX_CTL_FRZ; | ||
50 | pci_write_config_dword(pdev, box_ctl, config); | ||
51 | } | ||
52 | |||
53 | static void snbep_uncore_pci_enable_event(struct intel_uncore_box *box, | ||
54 | struct perf_event *event) | ||
55 | { | ||
56 | struct pci_dev *pdev = box->pci_dev; | ||
57 | struct hw_perf_event *hwc = &event->hw; | ||
58 | |||
59 | pci_write_config_dword(pdev, hwc->config_base, hwc->config | | ||
60 | SNBEP_PMON_CTL_EN); | ||
61 | } | ||
62 | |||
63 | static void snbep_uncore_pci_disable_event(struct intel_uncore_box *box, | ||
64 | struct perf_event *event) | ||
65 | { | ||
66 | struct pci_dev *pdev = box->pci_dev; | ||
67 | struct hw_perf_event *hwc = &event->hw; | ||
68 | |||
69 | pci_write_config_dword(pdev, hwc->config_base, hwc->config); | ||
70 | } | ||
71 | |||
72 | static u64 snbep_uncore_pci_read_counter(struct intel_uncore_box *box, | ||
73 | struct perf_event *event) | ||
74 | { | ||
75 | struct pci_dev *pdev = box->pci_dev; | ||
76 | struct hw_perf_event *hwc = &event->hw; | ||
77 | u64 count; | ||
78 | |||
79 | pci_read_config_dword(pdev, hwc->event_base, (u32 *)&count); | ||
80 | pci_read_config_dword(pdev, hwc->event_base + 4, (u32 *)&count + 1); | ||
81 | return count; | ||
82 | } | ||
83 | |||
84 | static void snbep_uncore_pci_init_box(struct intel_uncore_box *box) | ||
85 | { | ||
86 | struct pci_dev *pdev = box->pci_dev; | ||
87 | pci_write_config_dword(pdev, SNBEP_PCI_PMON_BOX_CTL, | ||
88 | SNBEP_PMON_BOX_CTL_INT); | ||
89 | } | ||
90 | |||
91 | static void snbep_uncore_msr_disable_box(struct intel_uncore_box *box) | ||
92 | { | ||
93 | u64 config; | ||
94 | unsigned msr; | ||
95 | |||
96 | msr = uncore_msr_box_ctl(box); | ||
97 | if (msr) { | ||
98 | rdmsrl(msr, config); | ||
99 | config |= SNBEP_PMON_BOX_CTL_FRZ; | ||
100 | wrmsrl(msr, config); | ||
101 | return; | ||
102 | } | ||
103 | } | ||
104 | |||
105 | static void snbep_uncore_msr_enable_box(struct intel_uncore_box *box) | ||
106 | { | ||
107 | u64 config; | ||
108 | unsigned msr; | ||
109 | |||
110 | msr = uncore_msr_box_ctl(box); | ||
111 | if (msr) { | ||
112 | rdmsrl(msr, config); | ||
113 | config &= ~SNBEP_PMON_BOX_CTL_FRZ; | ||
114 | wrmsrl(msr, config); | ||
115 | return; | ||
116 | } | ||
117 | } | ||
118 | |||
119 | static void snbep_uncore_msr_enable_event(struct intel_uncore_box *box, | ||
120 | struct perf_event *event) | ||
121 | { | ||
122 | struct hw_perf_event *hwc = &event->hw; | ||
123 | |||
124 | wrmsrl(hwc->config_base, hwc->config | SNBEP_PMON_CTL_EN); | ||
125 | } | ||
126 | |||
127 | static void snbep_uncore_msr_disable_event(struct intel_uncore_box *box, | ||
128 | struct perf_event *event) | ||
129 | { | ||
130 | struct hw_perf_event *hwc = &event->hw; | ||
131 | |||
132 | wrmsrl(hwc->config_base, hwc->config); | ||
133 | } | ||
134 | |||
135 | static u64 snbep_uncore_msr_read_counter(struct intel_uncore_box *box, | ||
136 | struct perf_event *event) | ||
137 | { | ||
138 | struct hw_perf_event *hwc = &event->hw; | ||
139 | u64 count; | ||
140 | |||
141 | rdmsrl(hwc->event_base, count); | ||
142 | return count; | ||
143 | } | ||
144 | |||
145 | static void snbep_uncore_msr_init_box(struct intel_uncore_box *box) | ||
146 | { | ||
147 | unsigned msr = uncore_msr_box_ctl(box); | ||
148 | if (msr) | ||
149 | wrmsrl(msr, SNBEP_PMON_BOX_CTL_INT); | ||
150 | } | ||
151 | |||
152 | static struct attribute *snbep_uncore_formats_attr[] = { | ||
153 | &format_attr_event.attr, | ||
154 | &format_attr_umask.attr, | ||
155 | &format_attr_edge.attr, | ||
156 | &format_attr_inv.attr, | ||
157 | &format_attr_thresh8.attr, | ||
158 | NULL, | ||
159 | }; | ||
160 | |||
161 | static struct attribute *snbep_uncore_ubox_formats_attr[] = { | ||
162 | &format_attr_event.attr, | ||
163 | &format_attr_umask.attr, | ||
164 | &format_attr_edge.attr, | ||
165 | &format_attr_inv.attr, | ||
166 | &format_attr_thresh5.attr, | ||
167 | NULL, | ||
168 | }; | ||
169 | |||
170 | static struct attribute *snbep_uncore_pcu_formats_attr[] = { | ||
171 | &format_attr_event.attr, | ||
172 | &format_attr_occ_sel.attr, | ||
173 | &format_attr_edge.attr, | ||
174 | &format_attr_inv.attr, | ||
175 | &format_attr_thresh5.attr, | ||
176 | &format_attr_occ_invert.attr, | ||
177 | &format_attr_occ_edge.attr, | ||
178 | NULL, | ||
179 | }; | ||
180 | |||
181 | static struct uncore_event_desc snbep_uncore_imc_events[] = { | ||
182 | INTEL_UNCORE_EVENT_DESC(clockticks, "event=0xff,umask=0xff"), | ||
183 | INTEL_UNCORE_EVENT_DESC(cas_count_read, "event=0x04,umask=0x03"), | ||
184 | INTEL_UNCORE_EVENT_DESC(cas_count_write, "event=0x04,umask=0x0c"), | ||
185 | { /* end: all zeroes */ }, | ||
186 | }; | ||
187 | |||
188 | static struct uncore_event_desc snbep_uncore_qpi_events[] = { | ||
189 | INTEL_UNCORE_EVENT_DESC(clockticks, "event=0x14"), | ||
190 | INTEL_UNCORE_EVENT_DESC(txl_flits_active, "event=0x00,umask=0x06"), | ||
191 | INTEL_UNCORE_EVENT_DESC(drs_data, "event=0x02,umask=0x08"), | ||
192 | INTEL_UNCORE_EVENT_DESC(ncb_data, "event=0x03,umask=0x04"), | ||
193 | { /* end: all zeroes */ }, | ||
194 | }; | ||
195 | |||
196 | static struct attribute_group snbep_uncore_format_group = { | ||
197 | .name = "format", | ||
198 | .attrs = snbep_uncore_formats_attr, | ||
199 | }; | ||
200 | |||
201 | static struct attribute_group snbep_uncore_ubox_format_group = { | ||
202 | .name = "format", | ||
203 | .attrs = snbep_uncore_ubox_formats_attr, | ||
204 | }; | ||
205 | |||
206 | static struct attribute_group snbep_uncore_pcu_format_group = { | ||
207 | .name = "format", | ||
208 | .attrs = snbep_uncore_pcu_formats_attr, | ||
209 | }; | ||
210 | |||
211 | static struct intel_uncore_ops snbep_uncore_msr_ops = { | ||
212 | .init_box = snbep_uncore_msr_init_box, | ||
213 | .disable_box = snbep_uncore_msr_disable_box, | ||
214 | .enable_box = snbep_uncore_msr_enable_box, | ||
215 | .disable_event = snbep_uncore_msr_disable_event, | ||
216 | .enable_event = snbep_uncore_msr_enable_event, | ||
217 | .read_counter = snbep_uncore_msr_read_counter, | ||
218 | }; | ||
219 | |||
220 | static struct intel_uncore_ops snbep_uncore_pci_ops = { | ||
221 | .init_box = snbep_uncore_pci_init_box, | ||
222 | .disable_box = snbep_uncore_pci_disable_box, | ||
223 | .enable_box = snbep_uncore_pci_enable_box, | ||
224 | .disable_event = snbep_uncore_pci_disable_event, | ||
225 | .enable_event = snbep_uncore_pci_enable_event, | ||
226 | .read_counter = snbep_uncore_pci_read_counter, | ||
227 | }; | ||
228 | |||
229 | static struct event_constraint snbep_uncore_cbox_constraints[] = { | ||
230 | UNCORE_EVENT_CONSTRAINT(0x01, 0x1), | ||
231 | UNCORE_EVENT_CONSTRAINT(0x02, 0x3), | ||
232 | UNCORE_EVENT_CONSTRAINT(0x04, 0x3), | ||
233 | UNCORE_EVENT_CONSTRAINT(0x05, 0x3), | ||
234 | UNCORE_EVENT_CONSTRAINT(0x07, 0x3), | ||
235 | UNCORE_EVENT_CONSTRAINT(0x11, 0x1), | ||
236 | UNCORE_EVENT_CONSTRAINT(0x12, 0x3), | ||
237 | UNCORE_EVENT_CONSTRAINT(0x13, 0x3), | ||
238 | UNCORE_EVENT_CONSTRAINT(0x1b, 0xc), | ||
239 | UNCORE_EVENT_CONSTRAINT(0x1c, 0xc), | ||
240 | UNCORE_EVENT_CONSTRAINT(0x1d, 0xc), | ||
241 | UNCORE_EVENT_CONSTRAINT(0x1e, 0xc), | ||
242 | UNCORE_EVENT_CONSTRAINT(0x1f, 0xe), | ||
243 | UNCORE_EVENT_CONSTRAINT(0x21, 0x3), | ||
244 | UNCORE_EVENT_CONSTRAINT(0x23, 0x3), | ||
245 | UNCORE_EVENT_CONSTRAINT(0x31, 0x3), | ||
246 | UNCORE_EVENT_CONSTRAINT(0x32, 0x3), | ||
247 | UNCORE_EVENT_CONSTRAINT(0x33, 0x3), | ||
248 | UNCORE_EVENT_CONSTRAINT(0x34, 0x3), | ||
249 | UNCORE_EVENT_CONSTRAINT(0x35, 0x3), | ||
250 | UNCORE_EVENT_CONSTRAINT(0x36, 0x1), | ||
251 | UNCORE_EVENT_CONSTRAINT(0x37, 0x3), | ||
252 | UNCORE_EVENT_CONSTRAINT(0x38, 0x3), | ||
253 | UNCORE_EVENT_CONSTRAINT(0x39, 0x3), | ||
254 | UNCORE_EVENT_CONSTRAINT(0x3b, 0x1), | ||
255 | EVENT_CONSTRAINT_END | ||
256 | }; | ||
257 | |||
258 | static struct event_constraint snbep_uncore_r2pcie_constraints[] = { | ||
259 | UNCORE_EVENT_CONSTRAINT(0x10, 0x3), | ||
260 | UNCORE_EVENT_CONSTRAINT(0x11, 0x3), | ||
261 | UNCORE_EVENT_CONSTRAINT(0x12, 0x1), | ||
262 | UNCORE_EVENT_CONSTRAINT(0x23, 0x3), | ||
263 | UNCORE_EVENT_CONSTRAINT(0x24, 0x3), | ||
264 | UNCORE_EVENT_CONSTRAINT(0x25, 0x3), | ||
265 | UNCORE_EVENT_CONSTRAINT(0x26, 0x3), | ||
266 | UNCORE_EVENT_CONSTRAINT(0x32, 0x3), | ||
267 | UNCORE_EVENT_CONSTRAINT(0x33, 0x3), | ||
268 | UNCORE_EVENT_CONSTRAINT(0x34, 0x3), | ||
269 | EVENT_CONSTRAINT_END | ||
270 | }; | ||
271 | |||
272 | static struct event_constraint snbep_uncore_r3qpi_constraints[] = { | ||
273 | UNCORE_EVENT_CONSTRAINT(0x10, 0x3), | ||
274 | UNCORE_EVENT_CONSTRAINT(0x11, 0x3), | ||
275 | UNCORE_EVENT_CONSTRAINT(0x12, 0x3), | ||
276 | UNCORE_EVENT_CONSTRAINT(0x13, 0x1), | ||
277 | UNCORE_EVENT_CONSTRAINT(0x20, 0x3), | ||
278 | UNCORE_EVENT_CONSTRAINT(0x21, 0x3), | ||
279 | UNCORE_EVENT_CONSTRAINT(0x22, 0x3), | ||
280 | UNCORE_EVENT_CONSTRAINT(0x23, 0x3), | ||
281 | UNCORE_EVENT_CONSTRAINT(0x24, 0x3), | ||
282 | UNCORE_EVENT_CONSTRAINT(0x25, 0x3), | ||
283 | UNCORE_EVENT_CONSTRAINT(0x26, 0x3), | ||
284 | UNCORE_EVENT_CONSTRAINT(0x30, 0x3), | ||
285 | UNCORE_EVENT_CONSTRAINT(0x31, 0x3), | ||
286 | UNCORE_EVENT_CONSTRAINT(0x32, 0x3), | ||
287 | UNCORE_EVENT_CONSTRAINT(0x33, 0x3), | ||
288 | UNCORE_EVENT_CONSTRAINT(0x34, 0x3), | ||
289 | UNCORE_EVENT_CONSTRAINT(0x36, 0x3), | ||
290 | UNCORE_EVENT_CONSTRAINT(0x37, 0x3), | ||
291 | EVENT_CONSTRAINT_END | ||
292 | }; | ||
293 | |||
294 | static struct intel_uncore_type snbep_uncore_ubox = { | ||
295 | .name = "ubox", | ||
296 | .num_counters = 2, | ||
297 | .num_boxes = 1, | ||
298 | .perf_ctr_bits = 44, | ||
299 | .fixed_ctr_bits = 48, | ||
300 | .perf_ctr = SNBEP_U_MSR_PMON_CTR0, | ||
301 | .event_ctl = SNBEP_U_MSR_PMON_CTL0, | ||
302 | .event_mask = SNBEP_U_MSR_PMON_RAW_EVENT_MASK, | ||
303 | .fixed_ctr = SNBEP_U_MSR_PMON_UCLK_FIXED_CTR, | ||
304 | .fixed_ctl = SNBEP_U_MSR_PMON_UCLK_FIXED_CTL, | ||
305 | .ops = &snbep_uncore_msr_ops, | ||
306 | .format_group = &snbep_uncore_ubox_format_group, | ||
307 | }; | ||
308 | |||
309 | static struct intel_uncore_type snbep_uncore_cbox = { | ||
310 | .name = "cbox", | ||
311 | .num_counters = 4, | ||
312 | .num_boxes = 8, | ||
313 | .perf_ctr_bits = 44, | ||
314 | .event_ctl = SNBEP_C0_MSR_PMON_CTL0, | ||
315 | .perf_ctr = SNBEP_C0_MSR_PMON_CTR0, | ||
316 | .event_mask = SNBEP_PMON_RAW_EVENT_MASK, | ||
317 | .box_ctl = SNBEP_C0_MSR_PMON_BOX_CTL, | ||
318 | .msr_offset = SNBEP_CBO_MSR_OFFSET, | ||
319 | .constraints = snbep_uncore_cbox_constraints, | ||
320 | .ops = &snbep_uncore_msr_ops, | ||
321 | .format_group = &snbep_uncore_format_group, | ||
322 | }; | ||
323 | |||
324 | static struct intel_uncore_type snbep_uncore_pcu = { | ||
325 | .name = "pcu", | ||
326 | .num_counters = 4, | ||
327 | .num_boxes = 1, | ||
328 | .perf_ctr_bits = 48, | ||
329 | .perf_ctr = SNBEP_PCU_MSR_PMON_CTR0, | ||
330 | .event_ctl = SNBEP_PCU_MSR_PMON_CTL0, | ||
331 | .event_mask = SNBEP_PCU_MSR_PMON_RAW_EVENT_MASK, | ||
332 | .box_ctl = SNBEP_PCU_MSR_PMON_BOX_CTL, | ||
333 | .ops = &snbep_uncore_msr_ops, | ||
334 | .format_group = &snbep_uncore_pcu_format_group, | ||
335 | }; | ||
336 | |||
337 | static struct intel_uncore_type *snbep_msr_uncores[] = { | ||
338 | &snbep_uncore_ubox, | ||
339 | &snbep_uncore_cbox, | ||
340 | &snbep_uncore_pcu, | ||
341 | NULL, | ||
342 | }; | ||
343 | |||
344 | #define SNBEP_UNCORE_PCI_COMMON_INIT() \ | ||
345 | .perf_ctr = SNBEP_PCI_PMON_CTR0, \ | ||
346 | .event_ctl = SNBEP_PCI_PMON_CTL0, \ | ||
347 | .event_mask = SNBEP_PMON_RAW_EVENT_MASK, \ | ||
348 | .box_ctl = SNBEP_PCI_PMON_BOX_CTL, \ | ||
349 | .ops = &snbep_uncore_pci_ops, \ | ||
350 | .format_group = &snbep_uncore_format_group | ||
351 | |||
352 | static struct intel_uncore_type snbep_uncore_ha = { | ||
353 | .name = "ha", | ||
354 | .num_counters = 4, | ||
355 | .num_boxes = 1, | ||
356 | .perf_ctr_bits = 48, | ||
357 | SNBEP_UNCORE_PCI_COMMON_INIT(), | ||
358 | }; | ||
359 | |||
360 | static struct intel_uncore_type snbep_uncore_imc = { | ||
361 | .name = "imc", | ||
362 | .num_counters = 4, | ||
363 | .num_boxes = 4, | ||
364 | .perf_ctr_bits = 48, | ||
365 | .fixed_ctr_bits = 48, | ||
366 | .fixed_ctr = SNBEP_MC_CHy_PCI_PMON_FIXED_CTR, | ||
367 | .fixed_ctl = SNBEP_MC_CHy_PCI_PMON_FIXED_CTL, | ||
368 | .event_descs = snbep_uncore_imc_events, | ||
369 | SNBEP_UNCORE_PCI_COMMON_INIT(), | ||
370 | }; | ||
371 | |||
372 | static struct intel_uncore_type snbep_uncore_qpi = { | ||
373 | .name = "qpi", | ||
374 | .num_counters = 4, | ||
375 | .num_boxes = 2, | ||
376 | .perf_ctr_bits = 48, | ||
377 | .event_descs = snbep_uncore_qpi_events, | ||
378 | SNBEP_UNCORE_PCI_COMMON_INIT(), | ||
379 | }; | ||
380 | |||
381 | |||
382 | static struct intel_uncore_type snbep_uncore_r2pcie = { | ||
383 | .name = "r2pcie", | ||
384 | .num_counters = 4, | ||
385 | .num_boxes = 1, | ||
386 | .perf_ctr_bits = 44, | ||
387 | .constraints = snbep_uncore_r2pcie_constraints, | ||
388 | SNBEP_UNCORE_PCI_COMMON_INIT(), | ||
389 | }; | ||
390 | |||
391 | static struct intel_uncore_type snbep_uncore_r3qpi = { | ||
392 | .name = "r3qpi", | ||
393 | .num_counters = 3, | ||
394 | .num_boxes = 2, | ||
395 | .perf_ctr_bits = 44, | ||
396 | .constraints = snbep_uncore_r3qpi_constraints, | ||
397 | SNBEP_UNCORE_PCI_COMMON_INIT(), | ||
398 | }; | ||
399 | |||
400 | static struct intel_uncore_type *snbep_pci_uncores[] = { | ||
401 | &snbep_uncore_ha, | ||
402 | &snbep_uncore_imc, | ||
403 | &snbep_uncore_qpi, | ||
404 | &snbep_uncore_r2pcie, | ||
405 | &snbep_uncore_r3qpi, | ||
406 | NULL, | ||
407 | }; | ||
408 | |||
409 | static DEFINE_PCI_DEVICE_TABLE(snbep_uncore_pci_ids) = { | ||
410 | { /* Home Agent */ | ||
411 | PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_UNC_HA), | ||
412 | .driver_data = (unsigned long)&snbep_uncore_ha, | ||
413 | }, | ||
414 | { /* MC Channel 0 */ | ||
415 | PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_UNC_IMC0), | ||
416 | .driver_data = (unsigned long)&snbep_uncore_imc, | ||
417 | }, | ||
418 | { /* MC Channel 1 */ | ||
419 | PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_UNC_IMC1), | ||
420 | .driver_data = (unsigned long)&snbep_uncore_imc, | ||
421 | }, | ||
422 | { /* MC Channel 2 */ | ||
423 | PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_UNC_IMC2), | ||
424 | .driver_data = (unsigned long)&snbep_uncore_imc, | ||
425 | }, | ||
426 | { /* MC Channel 3 */ | ||
427 | PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_UNC_IMC3), | ||
428 | .driver_data = (unsigned long)&snbep_uncore_imc, | ||
429 | }, | ||
430 | { /* QPI Port 0 */ | ||
431 | PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_UNC_QPI0), | ||
432 | .driver_data = (unsigned long)&snbep_uncore_qpi, | ||
433 | }, | ||
434 | { /* QPI Port 1 */ | ||
435 | PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_UNC_QPI1), | ||
436 | .driver_data = (unsigned long)&snbep_uncore_qpi, | ||
437 | }, | ||
438 | { /* P2PCIe */ | ||
439 | PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_UNC_R2PCIE), | ||
440 | .driver_data = (unsigned long)&snbep_uncore_r2pcie, | ||
441 | }, | ||
442 | { /* R3QPI Link 0 */ | ||
443 | PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_UNC_R3QPI0), | ||
444 | .driver_data = (unsigned long)&snbep_uncore_r3qpi, | ||
445 | }, | ||
446 | { /* R3QPI Link 1 */ | ||
447 | PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_UNC_R3QPI1), | ||
448 | .driver_data = (unsigned long)&snbep_uncore_r3qpi, | ||
449 | }, | ||
450 | { /* end: all zeroes */ } | ||
451 | }; | ||
452 | |||
453 | static struct pci_driver snbep_uncore_pci_driver = { | ||
454 | .name = "snbep_uncore", | ||
455 | .id_table = snbep_uncore_pci_ids, | ||
456 | }; | ||
457 | |||
458 | /* | ||
459 | * build pci bus to socket mapping | ||
460 | */ | ||
461 | static void snbep_pci2phy_map_init(void) | ||
462 | { | ||
463 | struct pci_dev *ubox_dev = NULL; | ||
464 | int i, bus, nodeid; | ||
465 | u32 config; | ||
466 | |||
467 | while (1) { | ||
468 | /* find the UBOX device */ | ||
469 | ubox_dev = pci_get_device(PCI_VENDOR_ID_INTEL, | ||
470 | PCI_DEVICE_ID_INTEL_JAKETOWN_UBOX, | ||
471 | ubox_dev); | ||
472 | if (!ubox_dev) | ||
473 | break; | ||
474 | bus = ubox_dev->bus->number; | ||
475 | /* get the Node ID of the local register */ | ||
476 | pci_read_config_dword(ubox_dev, 0x40, &config); | ||
477 | nodeid = config; | ||
478 | /* get the Node ID mapping */ | ||
479 | pci_read_config_dword(ubox_dev, 0x54, &config); | ||
480 | /* | ||
481 | * every three bits in the Node ID mapping register maps | ||
482 | * to a particular node. | ||
483 | */ | ||
484 | for (i = 0; i < 8; i++) { | ||
485 | if (nodeid == ((config >> (3 * i)) & 0x7)) { | ||
486 | pcibus_to_physid[bus] = i; | ||
487 | break; | ||
488 | } | ||
489 | } | ||
490 | }; | ||
491 | return; | ||
492 | } | ||
493 | /* end of Sandy Bridge-EP uncore support */ | ||
494 | |||
495 | |||
496 | /* Sandy Bridge uncore support */ | ||
497 | static void snb_uncore_msr_enable_event(struct intel_uncore_box *box, | ||
498 | struct perf_event *event) | ||
499 | { | ||
500 | struct hw_perf_event *hwc = &event->hw; | ||
501 | |||
502 | if (hwc->idx < UNCORE_PMC_IDX_FIXED) | ||
503 | wrmsrl(hwc->config_base, hwc->config | SNB_UNC_CTL_EN); | ||
504 | else | ||
505 | wrmsrl(hwc->config_base, SNB_UNC_CTL_EN); | ||
506 | } | ||
507 | |||
508 | static void snb_uncore_msr_disable_event(struct intel_uncore_box *box, | ||
509 | struct perf_event *event) | ||
510 | { | ||
511 | wrmsrl(event->hw.config_base, 0); | ||
512 | } | ||
513 | |||
514 | static u64 snb_uncore_msr_read_counter(struct intel_uncore_box *box, | ||
515 | struct perf_event *event) | ||
516 | { | ||
517 | u64 count; | ||
518 | rdmsrl(event->hw.event_base, count); | ||
519 | return count; | ||
520 | } | ||
521 | |||
522 | static void snb_uncore_msr_init_box(struct intel_uncore_box *box) | ||
523 | { | ||
524 | if (box->pmu->pmu_idx == 0) { | ||
525 | wrmsrl(SNB_UNC_PERF_GLOBAL_CTL, | ||
526 | SNB_UNC_GLOBAL_CTL_EN | SNB_UNC_GLOBAL_CTL_CORE_ALL); | ||
527 | } | ||
528 | } | ||
529 | |||
530 | static struct attribute *snb_uncore_formats_attr[] = { | ||
531 | &format_attr_event.attr, | ||
532 | &format_attr_umask.attr, | ||
533 | &format_attr_edge.attr, | ||
534 | &format_attr_inv.attr, | ||
535 | &format_attr_cmask5.attr, | ||
536 | NULL, | ||
537 | }; | ||
538 | |||
539 | static struct attribute_group snb_uncore_format_group = { | ||
540 | .name = "format", | ||
541 | .attrs = snb_uncore_formats_attr, | ||
542 | }; | ||
543 | |||
544 | static struct intel_uncore_ops snb_uncore_msr_ops = { | ||
545 | .init_box = snb_uncore_msr_init_box, | ||
546 | .disable_event = snb_uncore_msr_disable_event, | ||
547 | .enable_event = snb_uncore_msr_enable_event, | ||
548 | .read_counter = snb_uncore_msr_read_counter, | ||
549 | }; | ||
550 | |||
551 | static struct event_constraint snb_uncore_cbox_constraints[] = { | ||
552 | UNCORE_EVENT_CONSTRAINT(0x80, 0x1), | ||
553 | UNCORE_EVENT_CONSTRAINT(0x83, 0x1), | ||
554 | EVENT_CONSTRAINT_END | ||
555 | }; | ||
556 | |||
557 | static struct intel_uncore_type snb_uncore_cbox = { | ||
558 | .name = "cbox", | ||
559 | .num_counters = 2, | ||
560 | .num_boxes = 4, | ||
561 | .perf_ctr_bits = 44, | ||
562 | .fixed_ctr_bits = 48, | ||
563 | .perf_ctr = SNB_UNC_CBO_0_PER_CTR0, | ||
564 | .event_ctl = SNB_UNC_CBO_0_PERFEVTSEL0, | ||
565 | .fixed_ctr = SNB_UNC_FIXED_CTR, | ||
566 | .fixed_ctl = SNB_UNC_FIXED_CTR_CTRL, | ||
567 | .single_fixed = 1, | ||
568 | .event_mask = SNB_UNC_RAW_EVENT_MASK, | ||
569 | .msr_offset = SNB_UNC_CBO_MSR_OFFSET, | ||
570 | .constraints = snb_uncore_cbox_constraints, | ||
571 | .ops = &snb_uncore_msr_ops, | ||
572 | .format_group = &snb_uncore_format_group, | ||
573 | }; | ||
574 | |||
575 | static struct intel_uncore_type *snb_msr_uncores[] = { | ||
576 | &snb_uncore_cbox, | ||
577 | NULL, | ||
578 | }; | ||
579 | /* end of Sandy Bridge uncore support */ | ||
580 | |||
581 | /* Nehalem uncore support */ | ||
582 | static void nhm_uncore_msr_disable_box(struct intel_uncore_box *box) | ||
583 | { | ||
584 | wrmsrl(NHM_UNC_PERF_GLOBAL_CTL, 0); | ||
585 | } | ||
586 | |||
587 | static void nhm_uncore_msr_enable_box(struct intel_uncore_box *box) | ||
588 | { | ||
589 | wrmsrl(NHM_UNC_PERF_GLOBAL_CTL, | ||
590 | NHM_UNC_GLOBAL_CTL_EN_PC_ALL | NHM_UNC_GLOBAL_CTL_EN_FC); | ||
591 | } | ||
592 | |||
593 | static void nhm_uncore_msr_enable_event(struct intel_uncore_box *box, | ||
594 | struct perf_event *event) | ||
595 | { | ||
596 | struct hw_perf_event *hwc = &event->hw; | ||
597 | |||
598 | if (hwc->idx < UNCORE_PMC_IDX_FIXED) | ||
599 | wrmsrl(hwc->config_base, hwc->config | SNB_UNC_CTL_EN); | ||
600 | else | ||
601 | wrmsrl(hwc->config_base, NHM_UNC_FIXED_CTR_CTL_EN); | ||
602 | } | ||
603 | |||
604 | static struct attribute *nhm_uncore_formats_attr[] = { | ||
605 | &format_attr_event.attr, | ||
606 | &format_attr_umask.attr, | ||
607 | &format_attr_edge.attr, | ||
608 | &format_attr_inv.attr, | ||
609 | &format_attr_cmask8.attr, | ||
610 | NULL, | ||
611 | }; | ||
612 | |||
613 | static struct attribute_group nhm_uncore_format_group = { | ||
614 | .name = "format", | ||
615 | .attrs = nhm_uncore_formats_attr, | ||
616 | }; | ||
617 | |||
618 | static struct uncore_event_desc nhm_uncore_events[] = { | ||
619 | INTEL_UNCORE_EVENT_DESC(clockticks, "event=0xff,umask=0xff"), | ||
620 | INTEL_UNCORE_EVENT_DESC(qmc_writes_full_any, "event=0x2f,umask=0x0f"), | ||
621 | INTEL_UNCORE_EVENT_DESC(qmc_normal_reads_any, "event=0x2c,umask=0x0f"), | ||
622 | INTEL_UNCORE_EVENT_DESC(qhl_request_ioh_reads, "event=0x20,umask=0x01"), | ||
623 | INTEL_UNCORE_EVENT_DESC(qhl_request_ioh_writes, "event=0x20,umask=0x02"), | ||
624 | INTEL_UNCORE_EVENT_DESC(qhl_request_remote_reads, "event=0x20,umask=0x04"), | ||
625 | INTEL_UNCORE_EVENT_DESC(qhl_request_remote_writes, "event=0x20,umask=0x08"), | ||
626 | INTEL_UNCORE_EVENT_DESC(qhl_request_local_reads, "event=0x20,umask=0x10"), | ||
627 | INTEL_UNCORE_EVENT_DESC(qhl_request_local_writes, "event=0x20,umask=0x20"), | ||
628 | { /* end: all zeroes */ }, | ||
629 | }; | ||
630 | |||
631 | static struct intel_uncore_ops nhm_uncore_msr_ops = { | ||
632 | .disable_box = nhm_uncore_msr_disable_box, | ||
633 | .enable_box = nhm_uncore_msr_enable_box, | ||
634 | .disable_event = snb_uncore_msr_disable_event, | ||
635 | .enable_event = nhm_uncore_msr_enable_event, | ||
636 | .read_counter = snb_uncore_msr_read_counter, | ||
637 | }; | ||
638 | |||
639 | static struct intel_uncore_type nhm_uncore = { | ||
640 | .name = "", | ||
641 | .num_counters = 8, | ||
642 | .num_boxes = 1, | ||
643 | .perf_ctr_bits = 48, | ||
644 | .fixed_ctr_bits = 48, | ||
645 | .event_ctl = NHM_UNC_PERFEVTSEL0, | ||
646 | .perf_ctr = NHM_UNC_UNCORE_PMC0, | ||
647 | .fixed_ctr = NHM_UNC_FIXED_CTR, | ||
648 | .fixed_ctl = NHM_UNC_FIXED_CTR_CTRL, | ||
649 | .event_mask = NHM_UNC_RAW_EVENT_MASK, | ||
650 | .event_descs = nhm_uncore_events, | ||
651 | .ops = &nhm_uncore_msr_ops, | ||
652 | .format_group = &nhm_uncore_format_group, | ||
653 | }; | ||
654 | |||
655 | static struct intel_uncore_type *nhm_msr_uncores[] = { | ||
656 | &nhm_uncore, | ||
657 | NULL, | ||
658 | }; | ||
659 | /* end of Nehalem uncore support */ | ||
660 | |||
661 | static void uncore_assign_hw_event(struct intel_uncore_box *box, | ||
662 | struct perf_event *event, int idx) | ||
663 | { | ||
664 | struct hw_perf_event *hwc = &event->hw; | ||
665 | |||
666 | hwc->idx = idx; | ||
667 | hwc->last_tag = ++box->tags[idx]; | ||
668 | |||
669 | if (hwc->idx == UNCORE_PMC_IDX_FIXED) { | ||
670 | hwc->event_base = uncore_fixed_ctr(box); | ||
671 | hwc->config_base = uncore_fixed_ctl(box); | ||
672 | return; | ||
673 | } | ||
674 | |||
675 | hwc->config_base = uncore_event_ctl(box, hwc->idx); | ||
676 | hwc->event_base = uncore_perf_ctr(box, hwc->idx); | ||
677 | } | ||
678 | |||
679 | static void uncore_perf_event_update(struct intel_uncore_box *box, | ||
680 | struct perf_event *event) | ||
681 | { | ||
682 | u64 prev_count, new_count, delta; | ||
683 | int shift; | ||
684 | |||
685 | if (event->hw.idx >= UNCORE_PMC_IDX_FIXED) | ||
686 | shift = 64 - uncore_fixed_ctr_bits(box); | ||
687 | else | ||
688 | shift = 64 - uncore_perf_ctr_bits(box); | ||
689 | |||
690 | /* the hrtimer might modify the previous event value */ | ||
691 | again: | ||
692 | prev_count = local64_read(&event->hw.prev_count); | ||
693 | new_count = uncore_read_counter(box, event); | ||
694 | if (local64_xchg(&event->hw.prev_count, new_count) != prev_count) | ||
695 | goto again; | ||
696 | |||
697 | delta = (new_count << shift) - (prev_count << shift); | ||
698 | delta >>= shift; | ||
699 | |||
700 | local64_add(delta, &event->count); | ||
701 | } | ||
702 | |||
703 | /* | ||
704 | * The overflow interrupt is unavailable for SandyBridge-EP, is broken | ||
705 | * for SandyBridge. So we use hrtimer to periodically poll the counter | ||
706 | * to avoid overflow. | ||
707 | */ | ||
708 | static enum hrtimer_restart uncore_pmu_hrtimer(struct hrtimer *hrtimer) | ||
709 | { | ||
710 | struct intel_uncore_box *box; | ||
711 | unsigned long flags; | ||
712 | int bit; | ||
713 | |||
714 | box = container_of(hrtimer, struct intel_uncore_box, hrtimer); | ||
715 | if (!box->n_active || box->cpu != smp_processor_id()) | ||
716 | return HRTIMER_NORESTART; | ||
717 | /* | ||
718 | * disable local interrupt to prevent uncore_pmu_event_start/stop | ||
719 | * to interrupt the update process | ||
720 | */ | ||
721 | local_irq_save(flags); | ||
722 | |||
723 | for_each_set_bit(bit, box->active_mask, UNCORE_PMC_IDX_MAX) | ||
724 | uncore_perf_event_update(box, box->events[bit]); | ||
725 | |||
726 | local_irq_restore(flags); | ||
727 | |||
728 | hrtimer_forward_now(hrtimer, ns_to_ktime(UNCORE_PMU_HRTIMER_INTERVAL)); | ||
729 | return HRTIMER_RESTART; | ||
730 | } | ||
731 | |||
732 | static void uncore_pmu_start_hrtimer(struct intel_uncore_box *box) | ||
733 | { | ||
734 | __hrtimer_start_range_ns(&box->hrtimer, | ||
735 | ns_to_ktime(UNCORE_PMU_HRTIMER_INTERVAL), 0, | ||
736 | HRTIMER_MODE_REL_PINNED, 0); | ||
737 | } | ||
738 | |||
739 | static void uncore_pmu_cancel_hrtimer(struct intel_uncore_box *box) | ||
740 | { | ||
741 | hrtimer_cancel(&box->hrtimer); | ||
742 | } | ||
743 | |||
744 | static void uncore_pmu_init_hrtimer(struct intel_uncore_box *box) | ||
745 | { | ||
746 | hrtimer_init(&box->hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); | ||
747 | box->hrtimer.function = uncore_pmu_hrtimer; | ||
748 | } | ||
749 | |||
750 | struct intel_uncore_box *uncore_alloc_box(int cpu) | ||
751 | { | ||
752 | struct intel_uncore_box *box; | ||
753 | |||
754 | box = kmalloc_node(sizeof(*box), GFP_KERNEL | __GFP_ZERO, | ||
755 | cpu_to_node(cpu)); | ||
756 | if (!box) | ||
757 | return NULL; | ||
758 | |||
759 | uncore_pmu_init_hrtimer(box); | ||
760 | atomic_set(&box->refcnt, 1); | ||
761 | box->cpu = -1; | ||
762 | box->phys_id = -1; | ||
763 | |||
764 | return box; | ||
765 | } | ||
766 | |||
767 | static struct intel_uncore_box * | ||
768 | uncore_pmu_to_box(struct intel_uncore_pmu *pmu, int cpu) | ||
769 | { | ||
770 | static struct intel_uncore_box *box; | ||
771 | |||
772 | box = *per_cpu_ptr(pmu->box, cpu); | ||
773 | if (box) | ||
774 | return box; | ||
775 | |||
776 | raw_spin_lock(&uncore_box_lock); | ||
777 | list_for_each_entry(box, &pmu->box_list, list) { | ||
778 | if (box->phys_id == topology_physical_package_id(cpu)) { | ||
779 | atomic_inc(&box->refcnt); | ||
780 | *per_cpu_ptr(pmu->box, cpu) = box; | ||
781 | break; | ||
782 | } | ||
783 | } | ||
784 | raw_spin_unlock(&uncore_box_lock); | ||
785 | |||
786 | return *per_cpu_ptr(pmu->box, cpu); | ||
787 | } | ||
788 | |||
789 | static struct intel_uncore_pmu *uncore_event_to_pmu(struct perf_event *event) | ||
790 | { | ||
791 | return container_of(event->pmu, struct intel_uncore_pmu, pmu); | ||
792 | } | ||
793 | |||
794 | static struct intel_uncore_box *uncore_event_to_box(struct perf_event *event) | ||
795 | { | ||
796 | /* | ||
797 | * perf core schedules event on the basis of cpu, uncore events are | ||
798 | * collected by one of the cpus inside a physical package. | ||
799 | */ | ||
800 | return uncore_pmu_to_box(uncore_event_to_pmu(event), | ||
801 | smp_processor_id()); | ||
802 | } | ||
803 | |||
804 | static int uncore_collect_events(struct intel_uncore_box *box, | ||
805 | struct perf_event *leader, bool dogrp) | ||
806 | { | ||
807 | struct perf_event *event; | ||
808 | int n, max_count; | ||
809 | |||
810 | max_count = box->pmu->type->num_counters; | ||
811 | if (box->pmu->type->fixed_ctl) | ||
812 | max_count++; | ||
813 | |||
814 | if (box->n_events >= max_count) | ||
815 | return -EINVAL; | ||
816 | |||
817 | n = box->n_events; | ||
818 | box->event_list[n] = leader; | ||
819 | n++; | ||
820 | if (!dogrp) | ||
821 | return n; | ||
822 | |||
823 | list_for_each_entry(event, &leader->sibling_list, group_entry) { | ||
824 | if (event->state <= PERF_EVENT_STATE_OFF) | ||
825 | continue; | ||
826 | |||
827 | if (n >= max_count) | ||
828 | return -EINVAL; | ||
829 | |||
830 | box->event_list[n] = event; | ||
831 | n++; | ||
832 | } | ||
833 | return n; | ||
834 | } | ||
835 | |||
836 | static struct event_constraint * | ||
837 | uncore_event_constraint(struct intel_uncore_type *type, | ||
838 | struct perf_event *event) | ||
839 | { | ||
840 | struct event_constraint *c; | ||
841 | |||
842 | if (event->hw.config == ~0ULL) | ||
843 | return &constraint_fixed; | ||
844 | |||
845 | if (type->constraints) { | ||
846 | for_each_event_constraint(c, type->constraints) { | ||
847 | if ((event->hw.config & c->cmask) == c->code) | ||
848 | return c; | ||
849 | } | ||
850 | } | ||
851 | |||
852 | return &type->unconstrainted; | ||
853 | } | ||
854 | |||
855 | static int uncore_assign_events(struct intel_uncore_box *box, | ||
856 | int assign[], int n) | ||
857 | { | ||
858 | unsigned long used_mask[BITS_TO_LONGS(UNCORE_PMC_IDX_MAX)]; | ||
859 | struct event_constraint *c, *constraints[UNCORE_PMC_IDX_MAX]; | ||
860 | int i, ret, wmin, wmax; | ||
861 | struct hw_perf_event *hwc; | ||
862 | |||
863 | bitmap_zero(used_mask, UNCORE_PMC_IDX_MAX); | ||
864 | |||
865 | for (i = 0, wmin = UNCORE_PMC_IDX_MAX, wmax = 0; i < n; i++) { | ||
866 | c = uncore_event_constraint(box->pmu->type, | ||
867 | box->event_list[i]); | ||
868 | constraints[i] = c; | ||
869 | wmin = min(wmin, c->weight); | ||
870 | wmax = max(wmax, c->weight); | ||
871 | } | ||
872 | |||
873 | /* fastpath, try to reuse previous register */ | ||
874 | for (i = 0; i < n; i++) { | ||
875 | hwc = &box->event_list[i]->hw; | ||
876 | c = constraints[i]; | ||
877 | |||
878 | /* never assigned */ | ||
879 | if (hwc->idx == -1) | ||
880 | break; | ||
881 | |||
882 | /* constraint still honored */ | ||
883 | if (!test_bit(hwc->idx, c->idxmsk)) | ||
884 | break; | ||
885 | |||
886 | /* not already used */ | ||
887 | if (test_bit(hwc->idx, used_mask)) | ||
888 | break; | ||
889 | |||
890 | __set_bit(hwc->idx, used_mask); | ||
891 | assign[i] = hwc->idx; | ||
892 | } | ||
893 | if (i == n) | ||
894 | return 0; | ||
895 | |||
896 | /* slow path */ | ||
897 | ret = perf_assign_events(constraints, n, wmin, wmax, assign); | ||
898 | return ret ? -EINVAL : 0; | ||
899 | } | ||
900 | |||
901 | static void uncore_pmu_event_start(struct perf_event *event, int flags) | ||
902 | { | ||
903 | struct intel_uncore_box *box = uncore_event_to_box(event); | ||
904 | int idx = event->hw.idx; | ||
905 | |||
906 | if (WARN_ON_ONCE(!(event->hw.state & PERF_HES_STOPPED))) | ||
907 | return; | ||
908 | |||
909 | if (WARN_ON_ONCE(idx == -1 || idx >= UNCORE_PMC_IDX_MAX)) | ||
910 | return; | ||
911 | |||
912 | event->hw.state = 0; | ||
913 | box->events[idx] = event; | ||
914 | box->n_active++; | ||
915 | __set_bit(idx, box->active_mask); | ||
916 | |||
917 | local64_set(&event->hw.prev_count, uncore_read_counter(box, event)); | ||
918 | uncore_enable_event(box, event); | ||
919 | |||
920 | if (box->n_active == 1) { | ||
921 | uncore_enable_box(box); | ||
922 | uncore_pmu_start_hrtimer(box); | ||
923 | } | ||
924 | } | ||
925 | |||
926 | static void uncore_pmu_event_stop(struct perf_event *event, int flags) | ||
927 | { | ||
928 | struct intel_uncore_box *box = uncore_event_to_box(event); | ||
929 | struct hw_perf_event *hwc = &event->hw; | ||
930 | |||
931 | if (__test_and_clear_bit(hwc->idx, box->active_mask)) { | ||
932 | uncore_disable_event(box, event); | ||
933 | box->n_active--; | ||
934 | box->events[hwc->idx] = NULL; | ||
935 | WARN_ON_ONCE(hwc->state & PERF_HES_STOPPED); | ||
936 | hwc->state |= PERF_HES_STOPPED; | ||
937 | |||
938 | if (box->n_active == 0) { | ||
939 | uncore_disable_box(box); | ||
940 | uncore_pmu_cancel_hrtimer(box); | ||
941 | } | ||
942 | } | ||
943 | |||
944 | if ((flags & PERF_EF_UPDATE) && !(hwc->state & PERF_HES_UPTODATE)) { | ||
945 | /* | ||
946 | * Drain the remaining delta count out of a event | ||
947 | * that we are disabling: | ||
948 | */ | ||
949 | uncore_perf_event_update(box, event); | ||
950 | hwc->state |= PERF_HES_UPTODATE; | ||
951 | } | ||
952 | } | ||
953 | |||
954 | static int uncore_pmu_event_add(struct perf_event *event, int flags) | ||
955 | { | ||
956 | struct intel_uncore_box *box = uncore_event_to_box(event); | ||
957 | struct hw_perf_event *hwc = &event->hw; | ||
958 | int assign[UNCORE_PMC_IDX_MAX]; | ||
959 | int i, n, ret; | ||
960 | |||
961 | if (!box) | ||
962 | return -ENODEV; | ||
963 | |||
964 | ret = n = uncore_collect_events(box, event, false); | ||
965 | if (ret < 0) | ||
966 | return ret; | ||
967 | |||
968 | hwc->state = PERF_HES_UPTODATE | PERF_HES_STOPPED; | ||
969 | if (!(flags & PERF_EF_START)) | ||
970 | hwc->state |= PERF_HES_ARCH; | ||
971 | |||
972 | ret = uncore_assign_events(box, assign, n); | ||
973 | if (ret) | ||
974 | return ret; | ||
975 | |||
976 | /* save events moving to new counters */ | ||
977 | for (i = 0; i < box->n_events; i++) { | ||
978 | event = box->event_list[i]; | ||
979 | hwc = &event->hw; | ||
980 | |||
981 | if (hwc->idx == assign[i] && | ||
982 | hwc->last_tag == box->tags[assign[i]]) | ||
983 | continue; | ||
984 | /* | ||
985 | * Ensure we don't accidentally enable a stopped | ||
986 | * counter simply because we rescheduled. | ||
987 | */ | ||
988 | if (hwc->state & PERF_HES_STOPPED) | ||
989 | hwc->state |= PERF_HES_ARCH; | ||
990 | |||
991 | uncore_pmu_event_stop(event, PERF_EF_UPDATE); | ||
992 | } | ||
993 | |||
994 | /* reprogram moved events into new counters */ | ||
995 | for (i = 0; i < n; i++) { | ||
996 | event = box->event_list[i]; | ||
997 | hwc = &event->hw; | ||
998 | |||
999 | if (hwc->idx != assign[i] || | ||
1000 | hwc->last_tag != box->tags[assign[i]]) | ||
1001 | uncore_assign_hw_event(box, event, assign[i]); | ||
1002 | else if (i < box->n_events) | ||
1003 | continue; | ||
1004 | |||
1005 | if (hwc->state & PERF_HES_ARCH) | ||
1006 | continue; | ||
1007 | |||
1008 | uncore_pmu_event_start(event, 0); | ||
1009 | } | ||
1010 | box->n_events = n; | ||
1011 | |||
1012 | return 0; | ||
1013 | } | ||
1014 | |||
1015 | static void uncore_pmu_event_del(struct perf_event *event, int flags) | ||
1016 | { | ||
1017 | struct intel_uncore_box *box = uncore_event_to_box(event); | ||
1018 | int i; | ||
1019 | |||
1020 | uncore_pmu_event_stop(event, PERF_EF_UPDATE); | ||
1021 | |||
1022 | for (i = 0; i < box->n_events; i++) { | ||
1023 | if (event == box->event_list[i]) { | ||
1024 | while (++i < box->n_events) | ||
1025 | box->event_list[i - 1] = box->event_list[i]; | ||
1026 | |||
1027 | --box->n_events; | ||
1028 | break; | ||
1029 | } | ||
1030 | } | ||
1031 | |||
1032 | event->hw.idx = -1; | ||
1033 | event->hw.last_tag = ~0ULL; | ||
1034 | } | ||
1035 | |||
1036 | static void uncore_pmu_event_read(struct perf_event *event) | ||
1037 | { | ||
1038 | struct intel_uncore_box *box = uncore_event_to_box(event); | ||
1039 | uncore_perf_event_update(box, event); | ||
1040 | } | ||
1041 | |||
1042 | /* | ||
1043 | * validation ensures the group can be loaded onto the | ||
1044 | * PMU if it was the only group available. | ||
1045 | */ | ||
1046 | static int uncore_validate_group(struct intel_uncore_pmu *pmu, | ||
1047 | struct perf_event *event) | ||
1048 | { | ||
1049 | struct perf_event *leader = event->group_leader; | ||
1050 | struct intel_uncore_box *fake_box; | ||
1051 | int assign[UNCORE_PMC_IDX_MAX]; | ||
1052 | int ret = -EINVAL, n; | ||
1053 | |||
1054 | fake_box = uncore_alloc_box(smp_processor_id()); | ||
1055 | if (!fake_box) | ||
1056 | return -ENOMEM; | ||
1057 | |||
1058 | fake_box->pmu = pmu; | ||
1059 | /* | ||
1060 | * the event is not yet connected with its | ||
1061 | * siblings therefore we must first collect | ||
1062 | * existing siblings, then add the new event | ||
1063 | * before we can simulate the scheduling | ||
1064 | */ | ||
1065 | n = uncore_collect_events(fake_box, leader, true); | ||
1066 | if (n < 0) | ||
1067 | goto out; | ||
1068 | |||
1069 | fake_box->n_events = n; | ||
1070 | n = uncore_collect_events(fake_box, event, false); | ||
1071 | if (n < 0) | ||
1072 | goto out; | ||
1073 | |||
1074 | fake_box->n_events = n; | ||
1075 | |||
1076 | ret = uncore_assign_events(fake_box, assign, n); | ||
1077 | out: | ||
1078 | kfree(fake_box); | ||
1079 | return ret; | ||
1080 | } | ||
1081 | |||
1082 | int uncore_pmu_event_init(struct perf_event *event) | ||
1083 | { | ||
1084 | struct intel_uncore_pmu *pmu; | ||
1085 | struct intel_uncore_box *box; | ||
1086 | struct hw_perf_event *hwc = &event->hw; | ||
1087 | int ret; | ||
1088 | |||
1089 | if (event->attr.type != event->pmu->type) | ||
1090 | return -ENOENT; | ||
1091 | |||
1092 | pmu = uncore_event_to_pmu(event); | ||
1093 | /* no device found for this pmu */ | ||
1094 | if (pmu->func_id < 0) | ||
1095 | return -ENOENT; | ||
1096 | |||
1097 | /* | ||
1098 | * Uncore PMU does measure at all privilege level all the time. | ||
1099 | * So it doesn't make sense to specify any exclude bits. | ||
1100 | */ | ||
1101 | if (event->attr.exclude_user || event->attr.exclude_kernel || | ||
1102 | event->attr.exclude_hv || event->attr.exclude_idle) | ||
1103 | return -EINVAL; | ||
1104 | |||
1105 | /* Sampling not supported yet */ | ||
1106 | if (hwc->sample_period) | ||
1107 | return -EINVAL; | ||
1108 | |||
1109 | /* | ||
1110 | * Place all uncore events for a particular physical package | ||
1111 | * onto a single cpu | ||
1112 | */ | ||
1113 | if (event->cpu < 0) | ||
1114 | return -EINVAL; | ||
1115 | box = uncore_pmu_to_box(pmu, event->cpu); | ||
1116 | if (!box || box->cpu < 0) | ||
1117 | return -EINVAL; | ||
1118 | event->cpu = box->cpu; | ||
1119 | |||
1120 | if (event->attr.config == UNCORE_FIXED_EVENT) { | ||
1121 | /* no fixed counter */ | ||
1122 | if (!pmu->type->fixed_ctl) | ||
1123 | return -EINVAL; | ||
1124 | /* | ||
1125 | * if there is only one fixed counter, only the first pmu | ||
1126 | * can access the fixed counter | ||
1127 | */ | ||
1128 | if (pmu->type->single_fixed && pmu->pmu_idx > 0) | ||
1129 | return -EINVAL; | ||
1130 | hwc->config = ~0ULL; | ||
1131 | } else { | ||
1132 | hwc->config = event->attr.config & pmu->type->event_mask; | ||
1133 | } | ||
1134 | |||
1135 | event->hw.idx = -1; | ||
1136 | event->hw.last_tag = ~0ULL; | ||
1137 | |||
1138 | if (event->group_leader != event) | ||
1139 | ret = uncore_validate_group(pmu, event); | ||
1140 | else | ||
1141 | ret = 0; | ||
1142 | |||
1143 | return ret; | ||
1144 | } | ||
1145 | |||
1146 | static int __init uncore_pmu_register(struct intel_uncore_pmu *pmu) | ||
1147 | { | ||
1148 | int ret; | ||
1149 | |||
1150 | pmu->pmu = (struct pmu) { | ||
1151 | .attr_groups = pmu->type->attr_groups, | ||
1152 | .task_ctx_nr = perf_invalid_context, | ||
1153 | .event_init = uncore_pmu_event_init, | ||
1154 | .add = uncore_pmu_event_add, | ||
1155 | .del = uncore_pmu_event_del, | ||
1156 | .start = uncore_pmu_event_start, | ||
1157 | .stop = uncore_pmu_event_stop, | ||
1158 | .read = uncore_pmu_event_read, | ||
1159 | }; | ||
1160 | |||
1161 | if (pmu->type->num_boxes == 1) { | ||
1162 | if (strlen(pmu->type->name) > 0) | ||
1163 | sprintf(pmu->name, "uncore_%s", pmu->type->name); | ||
1164 | else | ||
1165 | sprintf(pmu->name, "uncore"); | ||
1166 | } else { | ||
1167 | sprintf(pmu->name, "uncore_%s_%d", pmu->type->name, | ||
1168 | pmu->pmu_idx); | ||
1169 | } | ||
1170 | |||
1171 | ret = perf_pmu_register(&pmu->pmu, pmu->name, -1); | ||
1172 | return ret; | ||
1173 | } | ||
1174 | |||
1175 | static void __init uncore_type_exit(struct intel_uncore_type *type) | ||
1176 | { | ||
1177 | int i; | ||
1178 | |||
1179 | for (i = 0; i < type->num_boxes; i++) | ||
1180 | free_percpu(type->pmus[i].box); | ||
1181 | kfree(type->pmus); | ||
1182 | type->pmus = NULL; | ||
1183 | kfree(type->attr_groups[1]); | ||
1184 | type->attr_groups[1] = NULL; | ||
1185 | } | ||
1186 | |||
1187 | static void uncore_types_exit(struct intel_uncore_type **types) | ||
1188 | { | ||
1189 | int i; | ||
1190 | for (i = 0; types[i]; i++) | ||
1191 | uncore_type_exit(types[i]); | ||
1192 | } | ||
1193 | |||
1194 | static int __init uncore_type_init(struct intel_uncore_type *type) | ||
1195 | { | ||
1196 | struct intel_uncore_pmu *pmus; | ||
1197 | struct attribute_group *events_group; | ||
1198 | struct attribute **attrs; | ||
1199 | int i, j; | ||
1200 | |||
1201 | pmus = kzalloc(sizeof(*pmus) * type->num_boxes, GFP_KERNEL); | ||
1202 | if (!pmus) | ||
1203 | return -ENOMEM; | ||
1204 | |||
1205 | type->unconstrainted = (struct event_constraint) | ||
1206 | __EVENT_CONSTRAINT(0, (1ULL << type->num_counters) - 1, | ||
1207 | 0, type->num_counters, 0); | ||
1208 | |||
1209 | for (i = 0; i < type->num_boxes; i++) { | ||
1210 | pmus[i].func_id = -1; | ||
1211 | pmus[i].pmu_idx = i; | ||
1212 | pmus[i].type = type; | ||
1213 | INIT_LIST_HEAD(&pmus[i].box_list); | ||
1214 | pmus[i].box = alloc_percpu(struct intel_uncore_box *); | ||
1215 | if (!pmus[i].box) | ||
1216 | goto fail; | ||
1217 | } | ||
1218 | |||
1219 | if (type->event_descs) { | ||
1220 | i = 0; | ||
1221 | while (type->event_descs[i].attr.attr.name) | ||
1222 | i++; | ||
1223 | |||
1224 | events_group = kzalloc(sizeof(struct attribute *) * (i + 1) + | ||
1225 | sizeof(*events_group), GFP_KERNEL); | ||
1226 | if (!events_group) | ||
1227 | goto fail; | ||
1228 | |||
1229 | attrs = (struct attribute **)(events_group + 1); | ||
1230 | events_group->name = "events"; | ||
1231 | events_group->attrs = attrs; | ||
1232 | |||
1233 | for (j = 0; j < i; j++) | ||
1234 | attrs[j] = &type->event_descs[j].attr.attr; | ||
1235 | |||
1236 | type->attr_groups[1] = events_group; | ||
1237 | } | ||
1238 | |||
1239 | type->pmus = pmus; | ||
1240 | return 0; | ||
1241 | fail: | ||
1242 | uncore_type_exit(type); | ||
1243 | return -ENOMEM; | ||
1244 | } | ||
1245 | |||
1246 | static int __init uncore_types_init(struct intel_uncore_type **types) | ||
1247 | { | ||
1248 | int i, ret; | ||
1249 | |||
1250 | for (i = 0; types[i]; i++) { | ||
1251 | ret = uncore_type_init(types[i]); | ||
1252 | if (ret) | ||
1253 | goto fail; | ||
1254 | } | ||
1255 | return 0; | ||
1256 | fail: | ||
1257 | while (--i >= 0) | ||
1258 | uncore_type_exit(types[i]); | ||
1259 | return ret; | ||
1260 | } | ||
1261 | |||
1262 | static struct pci_driver *uncore_pci_driver; | ||
1263 | static bool pcidrv_registered; | ||
1264 | |||
1265 | /* | ||
1266 | * add a pci uncore device | ||
1267 | */ | ||
1268 | static int __devinit uncore_pci_add(struct intel_uncore_type *type, | ||
1269 | struct pci_dev *pdev) | ||
1270 | { | ||
1271 | struct intel_uncore_pmu *pmu; | ||
1272 | struct intel_uncore_box *box; | ||
1273 | int i, phys_id; | ||
1274 | |||
1275 | phys_id = pcibus_to_physid[pdev->bus->number]; | ||
1276 | if (phys_id < 0) | ||
1277 | return -ENODEV; | ||
1278 | |||
1279 | box = uncore_alloc_box(0); | ||
1280 | if (!box) | ||
1281 | return -ENOMEM; | ||
1282 | |||
1283 | /* | ||
1284 | * for performance monitoring unit with multiple boxes, | ||
1285 | * each box has a different function id. | ||
1286 | */ | ||
1287 | for (i = 0; i < type->num_boxes; i++) { | ||
1288 | pmu = &type->pmus[i]; | ||
1289 | if (pmu->func_id == pdev->devfn) | ||
1290 | break; | ||
1291 | if (pmu->func_id < 0) { | ||
1292 | pmu->func_id = pdev->devfn; | ||
1293 | break; | ||
1294 | } | ||
1295 | pmu = NULL; | ||
1296 | } | ||
1297 | |||
1298 | if (!pmu) { | ||
1299 | kfree(box); | ||
1300 | return -EINVAL; | ||
1301 | } | ||
1302 | |||
1303 | box->phys_id = phys_id; | ||
1304 | box->pci_dev = pdev; | ||
1305 | box->pmu = pmu; | ||
1306 | uncore_box_init(box); | ||
1307 | pci_set_drvdata(pdev, box); | ||
1308 | |||
1309 | raw_spin_lock(&uncore_box_lock); | ||
1310 | list_add_tail(&box->list, &pmu->box_list); | ||
1311 | raw_spin_unlock(&uncore_box_lock); | ||
1312 | |||
1313 | return 0; | ||
1314 | } | ||
1315 | |||
1316 | static void __devexit uncore_pci_remove(struct pci_dev *pdev) | ||
1317 | { | ||
1318 | struct intel_uncore_box *box = pci_get_drvdata(pdev); | ||
1319 | struct intel_uncore_pmu *pmu = box->pmu; | ||
1320 | int cpu, phys_id = pcibus_to_physid[pdev->bus->number]; | ||
1321 | |||
1322 | if (WARN_ON_ONCE(phys_id != box->phys_id)) | ||
1323 | return; | ||
1324 | |||
1325 | raw_spin_lock(&uncore_box_lock); | ||
1326 | list_del(&box->list); | ||
1327 | raw_spin_unlock(&uncore_box_lock); | ||
1328 | |||
1329 | for_each_possible_cpu(cpu) { | ||
1330 | if (*per_cpu_ptr(pmu->box, cpu) == box) { | ||
1331 | *per_cpu_ptr(pmu->box, cpu) = NULL; | ||
1332 | atomic_dec(&box->refcnt); | ||
1333 | } | ||
1334 | } | ||
1335 | |||
1336 | WARN_ON_ONCE(atomic_read(&box->refcnt) != 1); | ||
1337 | kfree(box); | ||
1338 | } | ||
1339 | |||
1340 | static int __devinit uncore_pci_probe(struct pci_dev *pdev, | ||
1341 | const struct pci_device_id *id) | ||
1342 | { | ||
1343 | struct intel_uncore_type *type; | ||
1344 | |||
1345 | type = (struct intel_uncore_type *)id->driver_data; | ||
1346 | return uncore_pci_add(type, pdev); | ||
1347 | } | ||
1348 | |||
1349 | static int __init uncore_pci_init(void) | ||
1350 | { | ||
1351 | int ret; | ||
1352 | |||
1353 | switch (boot_cpu_data.x86_model) { | ||
1354 | case 45: /* Sandy Bridge-EP */ | ||
1355 | pci_uncores = snbep_pci_uncores; | ||
1356 | uncore_pci_driver = &snbep_uncore_pci_driver; | ||
1357 | snbep_pci2phy_map_init(); | ||
1358 | break; | ||
1359 | default: | ||
1360 | return 0; | ||
1361 | } | ||
1362 | |||
1363 | ret = uncore_types_init(pci_uncores); | ||
1364 | if (ret) | ||
1365 | return ret; | ||
1366 | |||
1367 | uncore_pci_driver->probe = uncore_pci_probe; | ||
1368 | uncore_pci_driver->remove = uncore_pci_remove; | ||
1369 | |||
1370 | ret = pci_register_driver(uncore_pci_driver); | ||
1371 | if (ret == 0) | ||
1372 | pcidrv_registered = true; | ||
1373 | else | ||
1374 | uncore_types_exit(pci_uncores); | ||
1375 | |||
1376 | return ret; | ||
1377 | } | ||
1378 | |||
1379 | static void __init uncore_pci_exit(void) | ||
1380 | { | ||
1381 | if (pcidrv_registered) { | ||
1382 | pcidrv_registered = false; | ||
1383 | pci_unregister_driver(uncore_pci_driver); | ||
1384 | uncore_types_exit(pci_uncores); | ||
1385 | } | ||
1386 | } | ||
1387 | |||
1388 | static void __cpuinit uncore_cpu_dying(int cpu) | ||
1389 | { | ||
1390 | struct intel_uncore_type *type; | ||
1391 | struct intel_uncore_pmu *pmu; | ||
1392 | struct intel_uncore_box *box; | ||
1393 | int i, j; | ||
1394 | |||
1395 | for (i = 0; msr_uncores[i]; i++) { | ||
1396 | type = msr_uncores[i]; | ||
1397 | for (j = 0; j < type->num_boxes; j++) { | ||
1398 | pmu = &type->pmus[j]; | ||
1399 | box = *per_cpu_ptr(pmu->box, cpu); | ||
1400 | *per_cpu_ptr(pmu->box, cpu) = NULL; | ||
1401 | if (box && atomic_dec_and_test(&box->refcnt)) | ||
1402 | kfree(box); | ||
1403 | } | ||
1404 | } | ||
1405 | } | ||
1406 | |||
1407 | static int __cpuinit uncore_cpu_starting(int cpu) | ||
1408 | { | ||
1409 | struct intel_uncore_type *type; | ||
1410 | struct intel_uncore_pmu *pmu; | ||
1411 | struct intel_uncore_box *box, *exist; | ||
1412 | int i, j, k, phys_id; | ||
1413 | |||
1414 | phys_id = topology_physical_package_id(cpu); | ||
1415 | |||
1416 | for (i = 0; msr_uncores[i]; i++) { | ||
1417 | type = msr_uncores[i]; | ||
1418 | for (j = 0; j < type->num_boxes; j++) { | ||
1419 | pmu = &type->pmus[j]; | ||
1420 | box = *per_cpu_ptr(pmu->box, cpu); | ||
1421 | /* called by uncore_cpu_init? */ | ||
1422 | if (box && box->phys_id >= 0) { | ||
1423 | uncore_box_init(box); | ||
1424 | continue; | ||
1425 | } | ||
1426 | |||
1427 | for_each_online_cpu(k) { | ||
1428 | exist = *per_cpu_ptr(pmu->box, k); | ||
1429 | if (exist && exist->phys_id == phys_id) { | ||
1430 | atomic_inc(&exist->refcnt); | ||
1431 | *per_cpu_ptr(pmu->box, cpu) = exist; | ||
1432 | kfree(box); | ||
1433 | box = NULL; | ||
1434 | break; | ||
1435 | } | ||
1436 | } | ||
1437 | |||
1438 | if (box) { | ||
1439 | box->phys_id = phys_id; | ||
1440 | uncore_box_init(box); | ||
1441 | } | ||
1442 | } | ||
1443 | } | ||
1444 | return 0; | ||
1445 | } | ||
1446 | |||
1447 | static int __cpuinit uncore_cpu_prepare(int cpu, int phys_id) | ||
1448 | { | ||
1449 | struct intel_uncore_type *type; | ||
1450 | struct intel_uncore_pmu *pmu; | ||
1451 | struct intel_uncore_box *box; | ||
1452 | int i, j; | ||
1453 | |||
1454 | for (i = 0; msr_uncores[i]; i++) { | ||
1455 | type = msr_uncores[i]; | ||
1456 | for (j = 0; j < type->num_boxes; j++) { | ||
1457 | pmu = &type->pmus[j]; | ||
1458 | if (pmu->func_id < 0) | ||
1459 | pmu->func_id = j; | ||
1460 | |||
1461 | box = uncore_alloc_box(cpu); | ||
1462 | if (!box) | ||
1463 | return -ENOMEM; | ||
1464 | |||
1465 | box->pmu = pmu; | ||
1466 | box->phys_id = phys_id; | ||
1467 | *per_cpu_ptr(pmu->box, cpu) = box; | ||
1468 | } | ||
1469 | } | ||
1470 | return 0; | ||
1471 | } | ||
1472 | |||
1473 | static void __cpuinit uncore_change_context(struct intel_uncore_type **uncores, | ||
1474 | int old_cpu, int new_cpu) | ||
1475 | { | ||
1476 | struct intel_uncore_type *type; | ||
1477 | struct intel_uncore_pmu *pmu; | ||
1478 | struct intel_uncore_box *box; | ||
1479 | int i, j; | ||
1480 | |||
1481 | for (i = 0; uncores[i]; i++) { | ||
1482 | type = uncores[i]; | ||
1483 | for (j = 0; j < type->num_boxes; j++) { | ||
1484 | pmu = &type->pmus[j]; | ||
1485 | if (old_cpu < 0) | ||
1486 | box = uncore_pmu_to_box(pmu, new_cpu); | ||
1487 | else | ||
1488 | box = uncore_pmu_to_box(pmu, old_cpu); | ||
1489 | if (!box) | ||
1490 | continue; | ||
1491 | |||
1492 | if (old_cpu < 0) { | ||
1493 | WARN_ON_ONCE(box->cpu != -1); | ||
1494 | box->cpu = new_cpu; | ||
1495 | continue; | ||
1496 | } | ||
1497 | |||
1498 | WARN_ON_ONCE(box->cpu != old_cpu); | ||
1499 | if (new_cpu >= 0) { | ||
1500 | uncore_pmu_cancel_hrtimer(box); | ||
1501 | perf_pmu_migrate_context(&pmu->pmu, | ||
1502 | old_cpu, new_cpu); | ||
1503 | box->cpu = new_cpu; | ||
1504 | } else { | ||
1505 | box->cpu = -1; | ||
1506 | } | ||
1507 | } | ||
1508 | } | ||
1509 | } | ||
1510 | |||
1511 | static void __cpuinit uncore_event_exit_cpu(int cpu) | ||
1512 | { | ||
1513 | int i, phys_id, target; | ||
1514 | |||
1515 | /* if exiting cpu is used for collecting uncore events */ | ||
1516 | if (!cpumask_test_and_clear_cpu(cpu, &uncore_cpu_mask)) | ||
1517 | return; | ||
1518 | |||
1519 | /* find a new cpu to collect uncore events */ | ||
1520 | phys_id = topology_physical_package_id(cpu); | ||
1521 | target = -1; | ||
1522 | for_each_online_cpu(i) { | ||
1523 | if (i == cpu) | ||
1524 | continue; | ||
1525 | if (phys_id == topology_physical_package_id(i)) { | ||
1526 | target = i; | ||
1527 | break; | ||
1528 | } | ||
1529 | } | ||
1530 | |||
1531 | /* migrate uncore events to the new cpu */ | ||
1532 | if (target >= 0) | ||
1533 | cpumask_set_cpu(target, &uncore_cpu_mask); | ||
1534 | |||
1535 | uncore_change_context(msr_uncores, cpu, target); | ||
1536 | uncore_change_context(pci_uncores, cpu, target); | ||
1537 | } | ||
1538 | |||
1539 | static void __cpuinit uncore_event_init_cpu(int cpu) | ||
1540 | { | ||
1541 | int i, phys_id; | ||
1542 | |||
1543 | phys_id = topology_physical_package_id(cpu); | ||
1544 | for_each_cpu(i, &uncore_cpu_mask) { | ||
1545 | if (phys_id == topology_physical_package_id(i)) | ||
1546 | return; | ||
1547 | } | ||
1548 | |||
1549 | cpumask_set_cpu(cpu, &uncore_cpu_mask); | ||
1550 | |||
1551 | uncore_change_context(msr_uncores, -1, cpu); | ||
1552 | uncore_change_context(pci_uncores, -1, cpu); | ||
1553 | } | ||
1554 | |||
1555 | static int __cpuinit uncore_cpu_notifier(struct notifier_block *self, | ||
1556 | unsigned long action, void *hcpu) | ||
1557 | { | ||
1558 | unsigned int cpu = (long)hcpu; | ||
1559 | |||
1560 | /* allocate/free data structure for uncore box */ | ||
1561 | switch (action & ~CPU_TASKS_FROZEN) { | ||
1562 | case CPU_UP_PREPARE: | ||
1563 | uncore_cpu_prepare(cpu, -1); | ||
1564 | break; | ||
1565 | case CPU_STARTING: | ||
1566 | uncore_cpu_starting(cpu); | ||
1567 | break; | ||
1568 | case CPU_UP_CANCELED: | ||
1569 | case CPU_DYING: | ||
1570 | uncore_cpu_dying(cpu); | ||
1571 | break; | ||
1572 | default: | ||
1573 | break; | ||
1574 | } | ||
1575 | |||
1576 | /* select the cpu that collects uncore events */ | ||
1577 | switch (action & ~CPU_TASKS_FROZEN) { | ||
1578 | case CPU_DOWN_FAILED: | ||
1579 | case CPU_STARTING: | ||
1580 | uncore_event_init_cpu(cpu); | ||
1581 | break; | ||
1582 | case CPU_DOWN_PREPARE: | ||
1583 | uncore_event_exit_cpu(cpu); | ||
1584 | break; | ||
1585 | default: | ||
1586 | break; | ||
1587 | } | ||
1588 | |||
1589 | return NOTIFY_OK; | ||
1590 | } | ||
1591 | |||
1592 | static struct notifier_block uncore_cpu_nb __cpuinitdata = { | ||
1593 | .notifier_call = uncore_cpu_notifier, | ||
1594 | /* | ||
1595 | * to migrate uncore events, our notifier should be executed | ||
1596 | * before perf core's notifier. | ||
1597 | */ | ||
1598 | .priority = CPU_PRI_PERF + 1, | ||
1599 | }; | ||
1600 | |||
1601 | static void __init uncore_cpu_setup(void *dummy) | ||
1602 | { | ||
1603 | uncore_cpu_starting(smp_processor_id()); | ||
1604 | } | ||
1605 | |||
1606 | static int __init uncore_cpu_init(void) | ||
1607 | { | ||
1608 | int ret, cpu; | ||
1609 | |||
1610 | switch (boot_cpu_data.x86_model) { | ||
1611 | case 26: /* Nehalem */ | ||
1612 | case 30: | ||
1613 | case 37: /* Westmere */ | ||
1614 | case 44: | ||
1615 | msr_uncores = nhm_msr_uncores; | ||
1616 | break; | ||
1617 | case 42: /* Sandy Bridge */ | ||
1618 | msr_uncores = snb_msr_uncores; | ||
1619 | break; | ||
1620 | case 45: /* Sandy Birdge-EP */ | ||
1621 | msr_uncores = snbep_msr_uncores; | ||
1622 | break; | ||
1623 | default: | ||
1624 | return 0; | ||
1625 | } | ||
1626 | |||
1627 | ret = uncore_types_init(msr_uncores); | ||
1628 | if (ret) | ||
1629 | return ret; | ||
1630 | |||
1631 | get_online_cpus(); | ||
1632 | |||
1633 | for_each_online_cpu(cpu) { | ||
1634 | int i, phys_id = topology_physical_package_id(cpu); | ||
1635 | |||
1636 | for_each_cpu(i, &uncore_cpu_mask) { | ||
1637 | if (phys_id == topology_physical_package_id(i)) { | ||
1638 | phys_id = -1; | ||
1639 | break; | ||
1640 | } | ||
1641 | } | ||
1642 | if (phys_id < 0) | ||
1643 | continue; | ||
1644 | |||
1645 | uncore_cpu_prepare(cpu, phys_id); | ||
1646 | uncore_event_init_cpu(cpu); | ||
1647 | } | ||
1648 | on_each_cpu(uncore_cpu_setup, NULL, 1); | ||
1649 | |||
1650 | register_cpu_notifier(&uncore_cpu_nb); | ||
1651 | |||
1652 | put_online_cpus(); | ||
1653 | |||
1654 | return 0; | ||
1655 | } | ||
1656 | |||
1657 | static int __init uncore_pmus_register(void) | ||
1658 | { | ||
1659 | struct intel_uncore_pmu *pmu; | ||
1660 | struct intel_uncore_type *type; | ||
1661 | int i, j; | ||
1662 | |||
1663 | for (i = 0; msr_uncores[i]; i++) { | ||
1664 | type = msr_uncores[i]; | ||
1665 | for (j = 0; j < type->num_boxes; j++) { | ||
1666 | pmu = &type->pmus[j]; | ||
1667 | uncore_pmu_register(pmu); | ||
1668 | } | ||
1669 | } | ||
1670 | |||
1671 | for (i = 0; pci_uncores[i]; i++) { | ||
1672 | type = pci_uncores[i]; | ||
1673 | for (j = 0; j < type->num_boxes; j++) { | ||
1674 | pmu = &type->pmus[j]; | ||
1675 | uncore_pmu_register(pmu); | ||
1676 | } | ||
1677 | } | ||
1678 | |||
1679 | return 0; | ||
1680 | } | ||
1681 | |||
1682 | static int __init intel_uncore_init(void) | ||
1683 | { | ||
1684 | int ret; | ||
1685 | |||
1686 | if (boot_cpu_data.x86_vendor != X86_VENDOR_INTEL) | ||
1687 | return -ENODEV; | ||
1688 | |||
1689 | ret = uncore_pci_init(); | ||
1690 | if (ret) | ||
1691 | goto fail; | ||
1692 | ret = uncore_cpu_init(); | ||
1693 | if (ret) { | ||
1694 | uncore_pci_exit(); | ||
1695 | goto fail; | ||
1696 | } | ||
1697 | |||
1698 | uncore_pmus_register(); | ||
1699 | return 0; | ||
1700 | fail: | ||
1701 | return ret; | ||
1702 | } | ||
1703 | device_initcall(intel_uncore_init); | ||
diff --git a/arch/x86/kernel/cpu/perf_event_intel_uncore.h b/arch/x86/kernel/cpu/perf_event_intel_uncore.h new file mode 100644 index 000000000000..4d52db0d1dfe --- /dev/null +++ b/arch/x86/kernel/cpu/perf_event_intel_uncore.h | |||
@@ -0,0 +1,406 @@ | |||
1 | #include <linux/module.h> | ||
2 | #include <linux/slab.h> | ||
3 | #include <linux/pci.h> | ||
4 | #include <linux/perf_event.h> | ||
5 | #include "perf_event.h" | ||
6 | |||
7 | #define UNCORE_PMU_NAME_LEN 32 | ||
8 | #define UNCORE_BOX_HASH_SIZE 8 | ||
9 | |||
10 | #define UNCORE_PMU_HRTIMER_INTERVAL (60 * NSEC_PER_SEC) | ||
11 | |||
12 | #define UNCORE_FIXED_EVENT 0xffff | ||
13 | #define UNCORE_PMC_IDX_MAX_GENERIC 8 | ||
14 | #define UNCORE_PMC_IDX_FIXED UNCORE_PMC_IDX_MAX_GENERIC | ||
15 | #define UNCORE_PMC_IDX_MAX (UNCORE_PMC_IDX_FIXED + 1) | ||
16 | |||
17 | #define UNCORE_EVENT_CONSTRAINT(c, n) EVENT_CONSTRAINT(c, n, 0xff) | ||
18 | |||
19 | /* SNB event control */ | ||
20 | #define SNB_UNC_CTL_EV_SEL_MASK 0x000000ff | ||
21 | #define SNB_UNC_CTL_UMASK_MASK 0x0000ff00 | ||
22 | #define SNB_UNC_CTL_EDGE_DET (1 << 18) | ||
23 | #define SNB_UNC_CTL_EN (1 << 22) | ||
24 | #define SNB_UNC_CTL_INVERT (1 << 23) | ||
25 | #define SNB_UNC_CTL_CMASK_MASK 0x1f000000 | ||
26 | #define NHM_UNC_CTL_CMASK_MASK 0xff000000 | ||
27 | #define NHM_UNC_FIXED_CTR_CTL_EN (1 << 0) | ||
28 | |||
29 | #define SNB_UNC_RAW_EVENT_MASK (SNB_UNC_CTL_EV_SEL_MASK | \ | ||
30 | SNB_UNC_CTL_UMASK_MASK | \ | ||
31 | SNB_UNC_CTL_EDGE_DET | \ | ||
32 | SNB_UNC_CTL_INVERT | \ | ||
33 | SNB_UNC_CTL_CMASK_MASK) | ||
34 | |||
35 | #define NHM_UNC_RAW_EVENT_MASK (SNB_UNC_CTL_EV_SEL_MASK | \ | ||
36 | SNB_UNC_CTL_UMASK_MASK | \ | ||
37 | SNB_UNC_CTL_EDGE_DET | \ | ||
38 | SNB_UNC_CTL_INVERT | \ | ||
39 | NHM_UNC_CTL_CMASK_MASK) | ||
40 | |||
41 | /* SNB global control register */ | ||
42 | #define SNB_UNC_PERF_GLOBAL_CTL 0x391 | ||
43 | #define SNB_UNC_FIXED_CTR_CTRL 0x394 | ||
44 | #define SNB_UNC_FIXED_CTR 0x395 | ||
45 | |||
46 | /* SNB uncore global control */ | ||
47 | #define SNB_UNC_GLOBAL_CTL_CORE_ALL ((1 << 4) - 1) | ||
48 | #define SNB_UNC_GLOBAL_CTL_EN (1 << 29) | ||
49 | |||
50 | /* SNB Cbo register */ | ||
51 | #define SNB_UNC_CBO_0_PERFEVTSEL0 0x700 | ||
52 | #define SNB_UNC_CBO_0_PER_CTR0 0x706 | ||
53 | #define SNB_UNC_CBO_MSR_OFFSET 0x10 | ||
54 | |||
55 | /* NHM global control register */ | ||
56 | #define NHM_UNC_PERF_GLOBAL_CTL 0x391 | ||
57 | #define NHM_UNC_FIXED_CTR 0x394 | ||
58 | #define NHM_UNC_FIXED_CTR_CTRL 0x395 | ||
59 | |||
60 | /* NHM uncore global control */ | ||
61 | #define NHM_UNC_GLOBAL_CTL_EN_PC_ALL ((1ULL << 8) - 1) | ||
62 | #define NHM_UNC_GLOBAL_CTL_EN_FC (1ULL << 32) | ||
63 | |||
64 | /* NHM uncore register */ | ||
65 | #define NHM_UNC_PERFEVTSEL0 0x3c0 | ||
66 | #define NHM_UNC_UNCORE_PMC0 0x3b0 | ||
67 | |||
68 | /* SNB-EP Box level control */ | ||
69 | #define SNBEP_PMON_BOX_CTL_RST_CTRL (1 << 0) | ||
70 | #define SNBEP_PMON_BOX_CTL_RST_CTRS (1 << 1) | ||
71 | #define SNBEP_PMON_BOX_CTL_FRZ (1 << 8) | ||
72 | #define SNBEP_PMON_BOX_CTL_FRZ_EN (1 << 16) | ||
73 | #define SNBEP_PMON_BOX_CTL_INT (SNBEP_PMON_BOX_CTL_RST_CTRL | \ | ||
74 | SNBEP_PMON_BOX_CTL_RST_CTRS | \ | ||
75 | SNBEP_PMON_BOX_CTL_FRZ_EN) | ||
76 | /* SNB-EP event control */ | ||
77 | #define SNBEP_PMON_CTL_EV_SEL_MASK 0x000000ff | ||
78 | #define SNBEP_PMON_CTL_UMASK_MASK 0x0000ff00 | ||
79 | #define SNBEP_PMON_CTL_RST (1 << 17) | ||
80 | #define SNBEP_PMON_CTL_EDGE_DET (1 << 18) | ||
81 | #define SNBEP_PMON_CTL_EV_SEL_EXT (1 << 21) /* only for QPI */ | ||
82 | #define SNBEP_PMON_CTL_EN (1 << 22) | ||
83 | #define SNBEP_PMON_CTL_INVERT (1 << 23) | ||
84 | #define SNBEP_PMON_CTL_TRESH_MASK 0xff000000 | ||
85 | #define SNBEP_PMON_RAW_EVENT_MASK (SNBEP_PMON_CTL_EV_SEL_MASK | \ | ||
86 | SNBEP_PMON_CTL_UMASK_MASK | \ | ||
87 | SNBEP_PMON_CTL_EDGE_DET | \ | ||
88 | SNBEP_PMON_CTL_INVERT | \ | ||
89 | SNBEP_PMON_CTL_TRESH_MASK) | ||
90 | |||
91 | /* SNB-EP Ubox event control */ | ||
92 | #define SNBEP_U_MSR_PMON_CTL_TRESH_MASK 0x1f000000 | ||
93 | #define SNBEP_U_MSR_PMON_RAW_EVENT_MASK \ | ||
94 | (SNBEP_PMON_CTL_EV_SEL_MASK | \ | ||
95 | SNBEP_PMON_CTL_UMASK_MASK | \ | ||
96 | SNBEP_PMON_CTL_EDGE_DET | \ | ||
97 | SNBEP_PMON_CTL_INVERT | \ | ||
98 | SNBEP_U_MSR_PMON_CTL_TRESH_MASK) | ||
99 | |||
100 | /* SNB-EP PCU event control */ | ||
101 | #define SNBEP_PCU_MSR_PMON_CTL_OCC_SEL_MASK 0x0000c000 | ||
102 | #define SNBEP_PCU_MSR_PMON_CTL_TRESH_MASK 0x1f000000 | ||
103 | #define SNBEP_PCU_MSR_PMON_CTL_OCC_INVERT (1 << 30) | ||
104 | #define SNBEP_PCU_MSR_PMON_CTL_OCC_EDGE_DET (1 << 31) | ||
105 | #define SNBEP_PCU_MSR_PMON_RAW_EVENT_MASK \ | ||
106 | (SNBEP_PMON_CTL_EV_SEL_MASK | \ | ||
107 | SNBEP_PCU_MSR_PMON_CTL_OCC_SEL_MASK | \ | ||
108 | SNBEP_PMON_CTL_EDGE_DET | \ | ||
109 | SNBEP_PMON_CTL_INVERT | \ | ||
110 | SNBEP_PCU_MSR_PMON_CTL_TRESH_MASK | \ | ||
111 | SNBEP_PCU_MSR_PMON_CTL_OCC_INVERT | \ | ||
112 | SNBEP_PCU_MSR_PMON_CTL_OCC_EDGE_DET) | ||
113 | |||
114 | /* SNB-EP pci control register */ | ||
115 | #define SNBEP_PCI_PMON_BOX_CTL 0xf4 | ||
116 | #define SNBEP_PCI_PMON_CTL0 0xd8 | ||
117 | /* SNB-EP pci counter register */ | ||
118 | #define SNBEP_PCI_PMON_CTR0 0xa0 | ||
119 | |||
120 | /* SNB-EP home agent register */ | ||
121 | #define SNBEP_HA_PCI_PMON_BOX_ADDRMATCH0 0x40 | ||
122 | #define SNBEP_HA_PCI_PMON_BOX_ADDRMATCH1 0x44 | ||
123 | #define SNBEP_HA_PCI_PMON_BOX_OPCODEMATCH 0x48 | ||
124 | /* SNB-EP memory controller register */ | ||
125 | #define SNBEP_MC_CHy_PCI_PMON_FIXED_CTL 0xf0 | ||
126 | #define SNBEP_MC_CHy_PCI_PMON_FIXED_CTR 0xd0 | ||
127 | /* SNB-EP QPI register */ | ||
128 | #define SNBEP_Q_Py_PCI_PMON_PKT_MATCH0 0x228 | ||
129 | #define SNBEP_Q_Py_PCI_PMON_PKT_MATCH1 0x22c | ||
130 | #define SNBEP_Q_Py_PCI_PMON_PKT_MASK0 0x238 | ||
131 | #define SNBEP_Q_Py_PCI_PMON_PKT_MASK1 0x23c | ||
132 | |||
133 | /* SNB-EP Ubox register */ | ||
134 | #define SNBEP_U_MSR_PMON_CTR0 0xc16 | ||
135 | #define SNBEP_U_MSR_PMON_CTL0 0xc10 | ||
136 | |||
137 | #define SNBEP_U_MSR_PMON_UCLK_FIXED_CTL 0xc08 | ||
138 | #define SNBEP_U_MSR_PMON_UCLK_FIXED_CTR 0xc09 | ||
139 | |||
140 | /* SNB-EP Cbo register */ | ||
141 | #define SNBEP_C0_MSR_PMON_CTR0 0xd16 | ||
142 | #define SNBEP_C0_MSR_PMON_CTL0 0xd10 | ||
143 | #define SNBEP_C0_MSR_PMON_BOX_FILTER 0xd14 | ||
144 | #define SNBEP_C0_MSR_PMON_BOX_CTL 0xd04 | ||
145 | #define SNBEP_CBO_MSR_OFFSET 0x20 | ||
146 | |||
147 | /* SNB-EP PCU register */ | ||
148 | #define SNBEP_PCU_MSR_PMON_CTR0 0xc36 | ||
149 | #define SNBEP_PCU_MSR_PMON_CTL0 0xc30 | ||
150 | #define SNBEP_PCU_MSR_PMON_BOX_FILTER 0xc34 | ||
151 | #define SNBEP_PCU_MSR_PMON_BOX_CTL 0xc24 | ||
152 | #define SNBEP_PCU_MSR_CORE_C3_CTR 0x3fc | ||
153 | #define SNBEP_PCU_MSR_CORE_C6_CTR 0x3fd | ||
154 | |||
155 | struct intel_uncore_ops; | ||
156 | struct intel_uncore_pmu; | ||
157 | struct intel_uncore_box; | ||
158 | struct uncore_event_desc; | ||
159 | |||
160 | struct intel_uncore_type { | ||
161 | const char *name; | ||
162 | int num_counters; | ||
163 | int num_boxes; | ||
164 | int perf_ctr_bits; | ||
165 | int fixed_ctr_bits; | ||
166 | int single_fixed; | ||
167 | unsigned perf_ctr; | ||
168 | unsigned event_ctl; | ||
169 | unsigned event_mask; | ||
170 | unsigned fixed_ctr; | ||
171 | unsigned fixed_ctl; | ||
172 | unsigned box_ctl; | ||
173 | unsigned msr_offset; | ||
174 | struct event_constraint unconstrainted; | ||
175 | struct event_constraint *constraints; | ||
176 | struct intel_uncore_pmu *pmus; | ||
177 | struct intel_uncore_ops *ops; | ||
178 | struct uncore_event_desc *event_descs; | ||
179 | const struct attribute_group *attr_groups[3]; | ||
180 | }; | ||
181 | |||
182 | #define format_group attr_groups[0] | ||
183 | |||
184 | struct intel_uncore_ops { | ||
185 | void (*init_box)(struct intel_uncore_box *); | ||
186 | void (*disable_box)(struct intel_uncore_box *); | ||
187 | void (*enable_box)(struct intel_uncore_box *); | ||
188 | void (*disable_event)(struct intel_uncore_box *, struct perf_event *); | ||
189 | void (*enable_event)(struct intel_uncore_box *, struct perf_event *); | ||
190 | u64 (*read_counter)(struct intel_uncore_box *, struct perf_event *); | ||
191 | }; | ||
192 | |||
193 | struct intel_uncore_pmu { | ||
194 | struct pmu pmu; | ||
195 | char name[UNCORE_PMU_NAME_LEN]; | ||
196 | int pmu_idx; | ||
197 | int func_id; | ||
198 | struct intel_uncore_type *type; | ||
199 | struct intel_uncore_box ** __percpu box; | ||
200 | struct list_head box_list; | ||
201 | }; | ||
202 | |||
203 | struct intel_uncore_box { | ||
204 | int phys_id; | ||
205 | int n_active; /* number of active events */ | ||
206 | int n_events; | ||
207 | int cpu; /* cpu to collect events */ | ||
208 | unsigned long flags; | ||
209 | atomic_t refcnt; | ||
210 | struct perf_event *events[UNCORE_PMC_IDX_MAX]; | ||
211 | struct perf_event *event_list[UNCORE_PMC_IDX_MAX]; | ||
212 | unsigned long active_mask[BITS_TO_LONGS(UNCORE_PMC_IDX_MAX)]; | ||
213 | u64 tags[UNCORE_PMC_IDX_MAX]; | ||
214 | struct pci_dev *pci_dev; | ||
215 | struct intel_uncore_pmu *pmu; | ||
216 | struct hrtimer hrtimer; | ||
217 | struct list_head list; | ||
218 | }; | ||
219 | |||
220 | #define UNCORE_BOX_FLAG_INITIATED 0 | ||
221 | |||
222 | struct uncore_event_desc { | ||
223 | struct kobj_attribute attr; | ||
224 | const char *config; | ||
225 | }; | ||
226 | |||
227 | #define INTEL_UNCORE_EVENT_DESC(_name, _config) \ | ||
228 | { \ | ||
229 | .attr = __ATTR(_name, 0444, uncore_event_show, NULL), \ | ||
230 | .config = _config, \ | ||
231 | } | ||
232 | |||
233 | #define DEFINE_UNCORE_FORMAT_ATTR(_var, _name, _format) \ | ||
234 | static ssize_t __uncore_##_var##_show(struct kobject *kobj, \ | ||
235 | struct kobj_attribute *attr, \ | ||
236 | char *page) \ | ||
237 | { \ | ||
238 | BUILD_BUG_ON(sizeof(_format) >= PAGE_SIZE); \ | ||
239 | return sprintf(page, _format "\n"); \ | ||
240 | } \ | ||
241 | static struct kobj_attribute format_attr_##_var = \ | ||
242 | __ATTR(_name, 0444, __uncore_##_var##_show, NULL) | ||
243 | |||
244 | |||
245 | static ssize_t uncore_event_show(struct kobject *kobj, | ||
246 | struct kobj_attribute *attr, char *buf) | ||
247 | { | ||
248 | struct uncore_event_desc *event = | ||
249 | container_of(attr, struct uncore_event_desc, attr); | ||
250 | return sprintf(buf, "%s", event->config); | ||
251 | } | ||
252 | |||
253 | static inline unsigned uncore_pci_box_ctl(struct intel_uncore_box *box) | ||
254 | { | ||
255 | return box->pmu->type->box_ctl; | ||
256 | } | ||
257 | |||
258 | static inline unsigned uncore_pci_fixed_ctl(struct intel_uncore_box *box) | ||
259 | { | ||
260 | return box->pmu->type->fixed_ctl; | ||
261 | } | ||
262 | |||
263 | static inline unsigned uncore_pci_fixed_ctr(struct intel_uncore_box *box) | ||
264 | { | ||
265 | return box->pmu->type->fixed_ctr; | ||
266 | } | ||
267 | |||
268 | static inline | ||
269 | unsigned uncore_pci_event_ctl(struct intel_uncore_box *box, int idx) | ||
270 | { | ||
271 | return idx * 4 + box->pmu->type->event_ctl; | ||
272 | } | ||
273 | |||
274 | static inline | ||
275 | unsigned uncore_pci_perf_ctr(struct intel_uncore_box *box, int idx) | ||
276 | { | ||
277 | return idx * 8 + box->pmu->type->perf_ctr; | ||
278 | } | ||
279 | |||
280 | static inline | ||
281 | unsigned uncore_msr_box_ctl(struct intel_uncore_box *box) | ||
282 | { | ||
283 | if (!box->pmu->type->box_ctl) | ||
284 | return 0; | ||
285 | return box->pmu->type->box_ctl + | ||
286 | box->pmu->type->msr_offset * box->pmu->pmu_idx; | ||
287 | } | ||
288 | |||
289 | static inline | ||
290 | unsigned uncore_msr_fixed_ctl(struct intel_uncore_box *box) | ||
291 | { | ||
292 | if (!box->pmu->type->fixed_ctl) | ||
293 | return 0; | ||
294 | return box->pmu->type->fixed_ctl + | ||
295 | box->pmu->type->msr_offset * box->pmu->pmu_idx; | ||
296 | } | ||
297 | |||
298 | static inline | ||
299 | unsigned uncore_msr_fixed_ctr(struct intel_uncore_box *box) | ||
300 | { | ||
301 | return box->pmu->type->fixed_ctr + | ||
302 | box->pmu->type->msr_offset * box->pmu->pmu_idx; | ||
303 | } | ||
304 | |||
305 | static inline | ||
306 | unsigned uncore_msr_event_ctl(struct intel_uncore_box *box, int idx) | ||
307 | { | ||
308 | return idx + box->pmu->type->event_ctl + | ||
309 | box->pmu->type->msr_offset * box->pmu->pmu_idx; | ||
310 | } | ||
311 | |||
312 | static inline | ||
313 | unsigned uncore_msr_perf_ctr(struct intel_uncore_box *box, int idx) | ||
314 | { | ||
315 | return idx + box->pmu->type->perf_ctr + | ||
316 | box->pmu->type->msr_offset * box->pmu->pmu_idx; | ||
317 | } | ||
318 | |||
319 | static inline | ||
320 | unsigned uncore_fixed_ctl(struct intel_uncore_box *box) | ||
321 | { | ||
322 | if (box->pci_dev) | ||
323 | return uncore_pci_fixed_ctl(box); | ||
324 | else | ||
325 | return uncore_msr_fixed_ctl(box); | ||
326 | } | ||
327 | |||
328 | static inline | ||
329 | unsigned uncore_fixed_ctr(struct intel_uncore_box *box) | ||
330 | { | ||
331 | if (box->pci_dev) | ||
332 | return uncore_pci_fixed_ctr(box); | ||
333 | else | ||
334 | return uncore_msr_fixed_ctr(box); | ||
335 | } | ||
336 | |||
337 | static inline | ||
338 | unsigned uncore_event_ctl(struct intel_uncore_box *box, int idx) | ||
339 | { | ||
340 | if (box->pci_dev) | ||
341 | return uncore_pci_event_ctl(box, idx); | ||
342 | else | ||
343 | return uncore_msr_event_ctl(box, idx); | ||
344 | } | ||
345 | |||
346 | static inline | ||
347 | unsigned uncore_perf_ctr(struct intel_uncore_box *box, int idx) | ||
348 | { | ||
349 | if (box->pci_dev) | ||
350 | return uncore_pci_perf_ctr(box, idx); | ||
351 | else | ||
352 | return uncore_msr_perf_ctr(box, idx); | ||
353 | } | ||
354 | |||
355 | static inline int uncore_perf_ctr_bits(struct intel_uncore_box *box) | ||
356 | { | ||
357 | return box->pmu->type->perf_ctr_bits; | ||
358 | } | ||
359 | |||
360 | static inline int uncore_fixed_ctr_bits(struct intel_uncore_box *box) | ||
361 | { | ||
362 | return box->pmu->type->fixed_ctr_bits; | ||
363 | } | ||
364 | |||
365 | static inline int uncore_num_counters(struct intel_uncore_box *box) | ||
366 | { | ||
367 | return box->pmu->type->num_counters; | ||
368 | } | ||
369 | |||
370 | static inline void uncore_disable_box(struct intel_uncore_box *box) | ||
371 | { | ||
372 | if (box->pmu->type->ops->disable_box) | ||
373 | box->pmu->type->ops->disable_box(box); | ||
374 | } | ||
375 | |||
376 | static inline void uncore_enable_box(struct intel_uncore_box *box) | ||
377 | { | ||
378 | if (box->pmu->type->ops->enable_box) | ||
379 | box->pmu->type->ops->enable_box(box); | ||
380 | } | ||
381 | |||
382 | static inline void uncore_disable_event(struct intel_uncore_box *box, | ||
383 | struct perf_event *event) | ||
384 | { | ||
385 | box->pmu->type->ops->disable_event(box, event); | ||
386 | } | ||
387 | |||
388 | static inline void uncore_enable_event(struct intel_uncore_box *box, | ||
389 | struct perf_event *event) | ||
390 | { | ||
391 | box->pmu->type->ops->enable_event(box, event); | ||
392 | } | ||
393 | |||
394 | static inline u64 uncore_read_counter(struct intel_uncore_box *box, | ||
395 | struct perf_event *event) | ||
396 | { | ||
397 | return box->pmu->type->ops->read_counter(box, event); | ||
398 | } | ||
399 | |||
400 | static inline void uncore_box_init(struct intel_uncore_box *box) | ||
401 | { | ||
402 | if (!test_and_set_bit(UNCORE_BOX_FLAG_INITIATED, &box->flags)) { | ||
403 | if (box->pmu->type->ops->init_box) | ||
404 | box->pmu->type->ops->init_box(box); | ||
405 | } | ||
406 | } | ||
diff --git a/arch/x86/lib/usercopy.c b/arch/x86/lib/usercopy.c index 677b1ed184c9..4f74d94c8d97 100644 --- a/arch/x86/lib/usercopy.c +++ b/arch/x86/lib/usercopy.c | |||
@@ -22,7 +22,7 @@ copy_from_user_nmi(void *to, const void __user *from, unsigned long n) | |||
22 | void *map; | 22 | void *map; |
23 | int ret; | 23 | int ret; |
24 | 24 | ||
25 | if (__range_not_ok(from, n, TASK_SIZE) == 0) | 25 | if (__range_not_ok(from, n, TASK_SIZE)) |
26 | return len; | 26 | return len; |
27 | 27 | ||
28 | do { | 28 | do { |
diff --git a/include/linux/ftrace_event.h b/include/linux/ftrace_event.h index 176a939d1547..1aff18346c71 100644 --- a/include/linux/ftrace_event.h +++ b/include/linux/ftrace_event.h | |||
@@ -207,6 +207,9 @@ struct ftrace_event_call { | |||
207 | * bit 1: enabled | 207 | * bit 1: enabled |
208 | * bit 2: filter_active | 208 | * bit 2: filter_active |
209 | * bit 3: enabled cmd record | 209 | * bit 3: enabled cmd record |
210 | * bit 4: allow trace by non root (cap any) | ||
211 | * bit 5: failed to apply filter | ||
212 | * bit 6: ftrace internal event (do not enable) | ||
210 | * | 213 | * |
211 | * Changes to flags must hold the event_mutex. | 214 | * Changes to flags must hold the event_mutex. |
212 | * | 215 | * |
diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index ab741b0d0074..5f187026b812 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h | |||
@@ -2755,6 +2755,17 @@ | |||
2755 | #define PCI_DEVICE_ID_INTEL_IOAT_SNB7 0x3c27 | 2755 | #define PCI_DEVICE_ID_INTEL_IOAT_SNB7 0x3c27 |
2756 | #define PCI_DEVICE_ID_INTEL_IOAT_SNB8 0x3c2e | 2756 | #define PCI_DEVICE_ID_INTEL_IOAT_SNB8 0x3c2e |
2757 | #define PCI_DEVICE_ID_INTEL_IOAT_SNB9 0x3c2f | 2757 | #define PCI_DEVICE_ID_INTEL_IOAT_SNB9 0x3c2f |
2758 | #define PCI_DEVICE_ID_INTEL_UNC_HA 0x3c46 | ||
2759 | #define PCI_DEVICE_ID_INTEL_UNC_IMC0 0x3cb0 | ||
2760 | #define PCI_DEVICE_ID_INTEL_UNC_IMC1 0x3cb1 | ||
2761 | #define PCI_DEVICE_ID_INTEL_UNC_IMC2 0x3cb4 | ||
2762 | #define PCI_DEVICE_ID_INTEL_UNC_IMC3 0x3cb5 | ||
2763 | #define PCI_DEVICE_ID_INTEL_UNC_QPI0 0x3c41 | ||
2764 | #define PCI_DEVICE_ID_INTEL_UNC_QPI1 0x3c42 | ||
2765 | #define PCI_DEVICE_ID_INTEL_UNC_R2PCIE 0x3c43 | ||
2766 | #define PCI_DEVICE_ID_INTEL_UNC_R3QPI0 0x3c44 | ||
2767 | #define PCI_DEVICE_ID_INTEL_UNC_R3QPI1 0x3c45 | ||
2768 | #define PCI_DEVICE_ID_INTEL_JAKETOWN_UBOX 0x3ce0 | ||
2758 | #define PCI_DEVICE_ID_INTEL_IOAT_SNB 0x402f | 2769 | #define PCI_DEVICE_ID_INTEL_IOAT_SNB 0x402f |
2759 | #define PCI_DEVICE_ID_INTEL_5100_16 0x65f0 | 2770 | #define PCI_DEVICE_ID_INTEL_5100_16 0x65f0 |
2760 | #define PCI_DEVICE_ID_INTEL_5100_21 0x65f5 | 2771 | #define PCI_DEVICE_ID_INTEL_5100_21 0x65f5 |
diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h index 1ce887abcc5c..76c5c8b724a7 100644 --- a/include/linux/perf_event.h +++ b/include/linux/perf_event.h | |||
@@ -1107,6 +1107,8 @@ perf_event_create_kernel_counter(struct perf_event_attr *attr, | |||
1107 | struct task_struct *task, | 1107 | struct task_struct *task, |
1108 | perf_overflow_handler_t callback, | 1108 | perf_overflow_handler_t callback, |
1109 | void *context); | 1109 | void *context); |
1110 | extern void perf_pmu_migrate_context(struct pmu *pmu, | ||
1111 | int src_cpu, int dst_cpu); | ||
1110 | extern u64 perf_event_read_value(struct perf_event *event, | 1112 | extern u64 perf_event_read_value(struct perf_event *event, |
1111 | u64 *enabled, u64 *running); | 1113 | u64 *enabled, u64 *running); |
1112 | 1114 | ||
diff --git a/kernel/events/core.c b/kernel/events/core.c index f85c0154b333..f1cf0edeb39a 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c | |||
@@ -253,9 +253,9 @@ perf_cgroup_match(struct perf_event *event) | |||
253 | return !event->cgrp || event->cgrp == cpuctx->cgrp; | 253 | return !event->cgrp || event->cgrp == cpuctx->cgrp; |
254 | } | 254 | } |
255 | 255 | ||
256 | static inline void perf_get_cgroup(struct perf_event *event) | 256 | static inline bool perf_tryget_cgroup(struct perf_event *event) |
257 | { | 257 | { |
258 | css_get(&event->cgrp->css); | 258 | return css_tryget(&event->cgrp->css); |
259 | } | 259 | } |
260 | 260 | ||
261 | static inline void perf_put_cgroup(struct perf_event *event) | 261 | static inline void perf_put_cgroup(struct perf_event *event) |
@@ -484,7 +484,11 @@ static inline int perf_cgroup_connect(int fd, struct perf_event *event, | |||
484 | event->cgrp = cgrp; | 484 | event->cgrp = cgrp; |
485 | 485 | ||
486 | /* must be done before we fput() the file */ | 486 | /* must be done before we fput() the file */ |
487 | perf_get_cgroup(event); | 487 | if (!perf_tryget_cgroup(event)) { |
488 | event->cgrp = NULL; | ||
489 | ret = -ENOENT; | ||
490 | goto out; | ||
491 | } | ||
488 | 492 | ||
489 | /* | 493 | /* |
490 | * all events in a group must monitor | 494 | * all events in a group must monitor |
@@ -1641,6 +1645,8 @@ perf_install_in_context(struct perf_event_context *ctx, | |||
1641 | lockdep_assert_held(&ctx->mutex); | 1645 | lockdep_assert_held(&ctx->mutex); |
1642 | 1646 | ||
1643 | event->ctx = ctx; | 1647 | event->ctx = ctx; |
1648 | if (event->cpu != -1) | ||
1649 | event->cpu = cpu; | ||
1644 | 1650 | ||
1645 | if (!task) { | 1651 | if (!task) { |
1646 | /* | 1652 | /* |
@@ -6248,6 +6254,8 @@ SYSCALL_DEFINE5(perf_event_open, | |||
6248 | } | 6254 | } |
6249 | } | 6255 | } |
6250 | 6256 | ||
6257 | get_online_cpus(); | ||
6258 | |||
6251 | event = perf_event_alloc(&attr, cpu, task, group_leader, NULL, | 6259 | event = perf_event_alloc(&attr, cpu, task, group_leader, NULL, |
6252 | NULL, NULL); | 6260 | NULL, NULL); |
6253 | if (IS_ERR(event)) { | 6261 | if (IS_ERR(event)) { |
@@ -6300,7 +6308,7 @@ SYSCALL_DEFINE5(perf_event_open, | |||
6300 | /* | 6308 | /* |
6301 | * Get the target context (task or percpu): | 6309 | * Get the target context (task or percpu): |
6302 | */ | 6310 | */ |
6303 | ctx = find_get_context(pmu, task, cpu); | 6311 | ctx = find_get_context(pmu, task, event->cpu); |
6304 | if (IS_ERR(ctx)) { | 6312 | if (IS_ERR(ctx)) { |
6305 | err = PTR_ERR(ctx); | 6313 | err = PTR_ERR(ctx); |
6306 | goto err_alloc; | 6314 | goto err_alloc; |
@@ -6373,20 +6381,23 @@ SYSCALL_DEFINE5(perf_event_open, | |||
6373 | mutex_lock(&ctx->mutex); | 6381 | mutex_lock(&ctx->mutex); |
6374 | 6382 | ||
6375 | if (move_group) { | 6383 | if (move_group) { |
6376 | perf_install_in_context(ctx, group_leader, cpu); | 6384 | synchronize_rcu(); |
6385 | perf_install_in_context(ctx, group_leader, event->cpu); | ||
6377 | get_ctx(ctx); | 6386 | get_ctx(ctx); |
6378 | list_for_each_entry(sibling, &group_leader->sibling_list, | 6387 | list_for_each_entry(sibling, &group_leader->sibling_list, |
6379 | group_entry) { | 6388 | group_entry) { |
6380 | perf_install_in_context(ctx, sibling, cpu); | 6389 | perf_install_in_context(ctx, sibling, event->cpu); |
6381 | get_ctx(ctx); | 6390 | get_ctx(ctx); |
6382 | } | 6391 | } |
6383 | } | 6392 | } |
6384 | 6393 | ||
6385 | perf_install_in_context(ctx, event, cpu); | 6394 | perf_install_in_context(ctx, event, event->cpu); |
6386 | ++ctx->generation; | 6395 | ++ctx->generation; |
6387 | perf_unpin_context(ctx); | 6396 | perf_unpin_context(ctx); |
6388 | mutex_unlock(&ctx->mutex); | 6397 | mutex_unlock(&ctx->mutex); |
6389 | 6398 | ||
6399 | put_online_cpus(); | ||
6400 | |||
6390 | event->owner = current; | 6401 | event->owner = current; |
6391 | 6402 | ||
6392 | mutex_lock(¤t->perf_event_mutex); | 6403 | mutex_lock(¤t->perf_event_mutex); |
@@ -6415,6 +6426,7 @@ err_context: | |||
6415 | err_alloc: | 6426 | err_alloc: |
6416 | free_event(event); | 6427 | free_event(event); |
6417 | err_task: | 6428 | err_task: |
6429 | put_online_cpus(); | ||
6418 | if (task) | 6430 | if (task) |
6419 | put_task_struct(task); | 6431 | put_task_struct(task); |
6420 | err_group_fd: | 6432 | err_group_fd: |
@@ -6475,6 +6487,39 @@ err: | |||
6475 | } | 6487 | } |
6476 | EXPORT_SYMBOL_GPL(perf_event_create_kernel_counter); | 6488 | EXPORT_SYMBOL_GPL(perf_event_create_kernel_counter); |
6477 | 6489 | ||
6490 | void perf_pmu_migrate_context(struct pmu *pmu, int src_cpu, int dst_cpu) | ||
6491 | { | ||
6492 | struct perf_event_context *src_ctx; | ||
6493 | struct perf_event_context *dst_ctx; | ||
6494 | struct perf_event *event, *tmp; | ||
6495 | LIST_HEAD(events); | ||
6496 | |||
6497 | src_ctx = &per_cpu_ptr(pmu->pmu_cpu_context, src_cpu)->ctx; | ||
6498 | dst_ctx = &per_cpu_ptr(pmu->pmu_cpu_context, dst_cpu)->ctx; | ||
6499 | |||
6500 | mutex_lock(&src_ctx->mutex); | ||
6501 | list_for_each_entry_safe(event, tmp, &src_ctx->event_list, | ||
6502 | event_entry) { | ||
6503 | perf_remove_from_context(event); | ||
6504 | put_ctx(src_ctx); | ||
6505 | list_add(&event->event_entry, &events); | ||
6506 | } | ||
6507 | mutex_unlock(&src_ctx->mutex); | ||
6508 | |||
6509 | synchronize_rcu(); | ||
6510 | |||
6511 | mutex_lock(&dst_ctx->mutex); | ||
6512 | list_for_each_entry_safe(event, tmp, &events, event_entry) { | ||
6513 | list_del(&event->event_entry); | ||
6514 | if (event->state >= PERF_EVENT_STATE_OFF) | ||
6515 | event->state = PERF_EVENT_STATE_INACTIVE; | ||
6516 | perf_install_in_context(dst_ctx, event, dst_cpu); | ||
6517 | get_ctx(dst_ctx); | ||
6518 | } | ||
6519 | mutex_unlock(&dst_ctx->mutex); | ||
6520 | } | ||
6521 | EXPORT_SYMBOL_GPL(perf_pmu_migrate_context); | ||
6522 | |||
6478 | static void sync_child_event(struct perf_event *child_event, | 6523 | static void sync_child_event(struct perf_event *child_event, |
6479 | struct task_struct *child) | 6524 | struct task_struct *child) |
6480 | { | 6525 | { |
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c index a008663d86c8..b4f20fba09fc 100644 --- a/kernel/trace/ftrace.c +++ b/kernel/trace/ftrace.c | |||
@@ -312,7 +312,7 @@ static int remove_ftrace_list_ops(struct ftrace_ops **list, | |||
312 | 312 | ||
313 | static int __register_ftrace_function(struct ftrace_ops *ops) | 313 | static int __register_ftrace_function(struct ftrace_ops *ops) |
314 | { | 314 | { |
315 | if (ftrace_disabled) | 315 | if (unlikely(ftrace_disabled)) |
316 | return -ENODEV; | 316 | return -ENODEV; |
317 | 317 | ||
318 | if (FTRACE_WARN_ON(ops == &global_ops)) | 318 | if (FTRACE_WARN_ON(ops == &global_ops)) |
@@ -4299,16 +4299,12 @@ int register_ftrace_function(struct ftrace_ops *ops) | |||
4299 | 4299 | ||
4300 | mutex_lock(&ftrace_lock); | 4300 | mutex_lock(&ftrace_lock); |
4301 | 4301 | ||
4302 | if (unlikely(ftrace_disabled)) | ||
4303 | goto out_unlock; | ||
4304 | |||
4305 | ret = __register_ftrace_function(ops); | 4302 | ret = __register_ftrace_function(ops); |
4306 | if (!ret) | 4303 | if (!ret) |
4307 | ret = ftrace_startup(ops, 0); | 4304 | ret = ftrace_startup(ops, 0); |
4308 | 4305 | ||
4309 | |||
4310 | out_unlock: | ||
4311 | mutex_unlock(&ftrace_lock); | 4306 | mutex_unlock(&ftrace_lock); |
4307 | |||
4312 | return ret; | 4308 | return ret; |
4313 | } | 4309 | } |
4314 | EXPORT_SYMBOL_GPL(register_ftrace_function); | 4310 | EXPORT_SYMBOL_GPL(register_ftrace_function); |
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index 68032c6177db..49249c28690d 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c | |||
@@ -371,7 +371,7 @@ EXPORT_SYMBOL_GPL(tracing_on); | |||
371 | void tracing_off(void) | 371 | void tracing_off(void) |
372 | { | 372 | { |
373 | if (global_trace.buffer) | 373 | if (global_trace.buffer) |
374 | ring_buffer_record_on(global_trace.buffer); | 374 | ring_buffer_record_off(global_trace.buffer); |
375 | /* | 375 | /* |
376 | * This flag is only looked at when buffers haven't been | 376 | * This flag is only looked at when buffers haven't been |
377 | * allocated yet. We don't really care about the race | 377 | * allocated yet. We don't really care about the race |
diff --git a/kernel/trace/trace_output.c b/kernel/trace/trace_output.c index df611a0e76c5..123b189c732c 100644 --- a/kernel/trace/trace_output.c +++ b/kernel/trace/trace_output.c | |||
@@ -1325,4 +1325,4 @@ __init static int init_events(void) | |||
1325 | 1325 | ||
1326 | return 0; | 1326 | return 0; |
1327 | } | 1327 | } |
1328 | device_initcall(init_events); | 1328 | early_initcall(init_events); |
diff --git a/kernel/watchdog.c b/kernel/watchdog.c index e5e1d85b8c7c..4b1dfba70f7c 100644 --- a/kernel/watchdog.c +++ b/kernel/watchdog.c | |||
@@ -372,6 +372,13 @@ static int watchdog(void *unused) | |||
372 | 372 | ||
373 | 373 | ||
374 | #ifdef CONFIG_HARDLOCKUP_DETECTOR | 374 | #ifdef CONFIG_HARDLOCKUP_DETECTOR |
375 | /* | ||
376 | * People like the simple clean cpu node info on boot. | ||
377 | * Reduce the watchdog noise by only printing messages | ||
378 | * that are different from what cpu0 displayed. | ||
379 | */ | ||
380 | static unsigned long cpu0_err; | ||
381 | |||
375 | static int watchdog_nmi_enable(int cpu) | 382 | static int watchdog_nmi_enable(int cpu) |
376 | { | 383 | { |
377 | struct perf_event_attr *wd_attr; | 384 | struct perf_event_attr *wd_attr; |
@@ -390,11 +397,21 @@ static int watchdog_nmi_enable(int cpu) | |||
390 | 397 | ||
391 | /* Try to register using hardware perf events */ | 398 | /* Try to register using hardware perf events */ |
392 | event = perf_event_create_kernel_counter(wd_attr, cpu, NULL, watchdog_overflow_callback, NULL); | 399 | event = perf_event_create_kernel_counter(wd_attr, cpu, NULL, watchdog_overflow_callback, NULL); |
400 | |||
401 | /* save cpu0 error for future comparision */ | ||
402 | if (cpu == 0 && IS_ERR(event)) | ||
403 | cpu0_err = PTR_ERR(event); | ||
404 | |||
393 | if (!IS_ERR(event)) { | 405 | if (!IS_ERR(event)) { |
394 | pr_info("enabled, takes one hw-pmu counter.\n"); | 406 | /* only print for cpu0 or different than cpu0 */ |
407 | if (cpu == 0 || cpu0_err) | ||
408 | pr_info("enabled on all CPUs, permanently consumes one hw-PMU counter.\n"); | ||
395 | goto out_save; | 409 | goto out_save; |
396 | } | 410 | } |
397 | 411 | ||
412 | /* skip displaying the same error again */ | ||
413 | if (cpu > 0 && (PTR_ERR(event) == cpu0_err)) | ||
414 | return PTR_ERR(event); | ||
398 | 415 | ||
399 | /* vary the KERN level based on the returned errno */ | 416 | /* vary the KERN level based on the returned errno */ |
400 | if (PTR_ERR(event) == -EOPNOTSUPP) | 417 | if (PTR_ERR(event) == -EOPNOTSUPP) |
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index 875bf2675326..861f0aec77ae 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c | |||
@@ -1179,6 +1179,12 @@ int cmd_stat(int argc, const char **argv, const char *prefix __used) | |||
1179 | fprintf(stderr, "cannot use both --output and --log-fd\n"); | 1179 | fprintf(stderr, "cannot use both --output and --log-fd\n"); |
1180 | usage_with_options(stat_usage, options); | 1180 | usage_with_options(stat_usage, options); |
1181 | } | 1181 | } |
1182 | |||
1183 | if (output_fd < 0) { | ||
1184 | fprintf(stderr, "argument to --log-fd must be a > 0\n"); | ||
1185 | usage_with_options(stat_usage, options); | ||
1186 | } | ||
1187 | |||
1182 | if (!output) { | 1188 | if (!output) { |
1183 | struct timespec tm; | 1189 | struct timespec tm; |
1184 | mode = append_file ? "a" : "w"; | 1190 | mode = append_file ? "a" : "w"; |
@@ -1190,7 +1196,7 @@ int cmd_stat(int argc, const char **argv, const char *prefix __used) | |||
1190 | } | 1196 | } |
1191 | clock_gettime(CLOCK_REALTIME, &tm); | 1197 | clock_gettime(CLOCK_REALTIME, &tm); |
1192 | fprintf(output, "# started on %s\n", ctime(&tm.tv_sec)); | 1198 | fprintf(output, "# started on %s\n", ctime(&tm.tv_sec)); |
1193 | } else if (output_fd != 2) { | 1199 | } else if (output_fd > 0) { |
1194 | mode = append_file ? "a" : "w"; | 1200 | mode = append_file ? "a" : "w"; |
1195 | output = fdopen(output_fd, mode); | 1201 | output = fdopen(output_fd, mode); |
1196 | if (!output) { | 1202 | if (!output) { |
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index 07c8f3792954..a5e2015319ee 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c | |||
@@ -1942,7 +1942,6 @@ int perf_file_header__read(struct perf_file_header *header, | |||
1942 | else | 1942 | else |
1943 | return -1; | 1943 | return -1; |
1944 | } else if (ph->needs_swap) { | 1944 | } else if (ph->needs_swap) { |
1945 | unsigned int i; | ||
1946 | /* | 1945 | /* |
1947 | * feature bitmap is declared as an array of unsigned longs -- | 1946 | * feature bitmap is declared as an array of unsigned longs -- |
1948 | * not good since its size can differ between the host that | 1947 | * not good since its size can differ between the host that |
@@ -1958,14 +1957,17 @@ int perf_file_header__read(struct perf_file_header *header, | |||
1958 | * file), punt and fallback to the original behavior -- | 1957 | * file), punt and fallback to the original behavior -- |
1959 | * clearing all feature bits and setting buildid. | 1958 | * clearing all feature bits and setting buildid. |
1960 | */ | 1959 | */ |
1961 | for (i = 0; i < BITS_TO_LONGS(HEADER_FEAT_BITS); ++i) | 1960 | mem_bswap_64(&header->adds_features, |
1962 | header->adds_features[i] = bswap_64(header->adds_features[i]); | 1961 | BITS_TO_U64(HEADER_FEAT_BITS)); |
1963 | 1962 | ||
1964 | if (!test_bit(HEADER_HOSTNAME, header->adds_features)) { | 1963 | if (!test_bit(HEADER_HOSTNAME, header->adds_features)) { |
1965 | for (i = 0; i < BITS_TO_LONGS(HEADER_FEAT_BITS); ++i) { | 1964 | /* unswap as u64 */ |
1966 | header->adds_features[i] = bswap_64(header->adds_features[i]); | 1965 | mem_bswap_64(&header->adds_features, |
1967 | header->adds_features[i] = bswap_32(header->adds_features[i]); | 1966 | BITS_TO_U64(HEADER_FEAT_BITS)); |
1968 | } | 1967 | |
1968 | /* unswap as u32 */ | ||
1969 | mem_bswap_32(&header->adds_features, | ||
1970 | BITS_TO_U32(HEADER_FEAT_BITS)); | ||
1969 | } | 1971 | } |
1970 | 1972 | ||
1971 | if (!test_bit(HEADER_HOSTNAME, header->adds_features)) { | 1973 | if (!test_bit(HEADER_HOSTNAME, header->adds_features)) { |
@@ -2091,6 +2093,35 @@ static int read_attr(int fd, struct perf_header *ph, | |||
2091 | return ret <= 0 ? -1 : 0; | 2093 | return ret <= 0 ? -1 : 0; |
2092 | } | 2094 | } |
2093 | 2095 | ||
2096 | static int perf_evsel__set_tracepoint_name(struct perf_evsel *evsel) | ||
2097 | { | ||
2098 | struct event_format *event = trace_find_event(evsel->attr.config); | ||
2099 | char bf[128]; | ||
2100 | |||
2101 | if (event == NULL) | ||
2102 | return -1; | ||
2103 | |||
2104 | snprintf(bf, sizeof(bf), "%s:%s", event->system, event->name); | ||
2105 | evsel->name = strdup(bf); | ||
2106 | if (event->name == NULL) | ||
2107 | return -1; | ||
2108 | |||
2109 | return 0; | ||
2110 | } | ||
2111 | |||
2112 | static int perf_evlist__set_tracepoint_names(struct perf_evlist *evlist) | ||
2113 | { | ||
2114 | struct perf_evsel *pos; | ||
2115 | |||
2116 | list_for_each_entry(pos, &evlist->entries, node) { | ||
2117 | if (pos->attr.type == PERF_TYPE_TRACEPOINT && | ||
2118 | perf_evsel__set_tracepoint_name(pos)) | ||
2119 | return -1; | ||
2120 | } | ||
2121 | |||
2122 | return 0; | ||
2123 | } | ||
2124 | |||
2094 | int perf_session__read_header(struct perf_session *session, int fd) | 2125 | int perf_session__read_header(struct perf_session *session, int fd) |
2095 | { | 2126 | { |
2096 | struct perf_header *header = &session->header; | 2127 | struct perf_header *header = &session->header; |
@@ -2172,6 +2203,9 @@ int perf_session__read_header(struct perf_session *session, int fd) | |||
2172 | 2203 | ||
2173 | lseek(fd, header->data_offset, SEEK_SET); | 2204 | lseek(fd, header->data_offset, SEEK_SET); |
2174 | 2205 | ||
2206 | if (perf_evlist__set_tracepoint_names(session->evlist)) | ||
2207 | goto out_delete_evlist; | ||
2208 | |||
2175 | header->frozen = 1; | 2209 | header->frozen = 1; |
2176 | return 0; | 2210 | return 0; |
2177 | out_errno: | 2211 | out_errno: |
diff --git a/tools/perf/util/include/linux/bitops.h b/tools/perf/util/include/linux/bitops.h index f1584833bd22..587a230d2075 100644 --- a/tools/perf/util/include/linux/bitops.h +++ b/tools/perf/util/include/linux/bitops.h | |||
@@ -8,6 +8,8 @@ | |||
8 | #define BITS_PER_LONG __WORDSIZE | 8 | #define BITS_PER_LONG __WORDSIZE |
9 | #define BITS_PER_BYTE 8 | 9 | #define BITS_PER_BYTE 8 |
10 | #define BITS_TO_LONGS(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(long)) | 10 | #define BITS_TO_LONGS(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(long)) |
11 | #define BITS_TO_U64(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(u64)) | ||
12 | #define BITS_TO_U32(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(u32)) | ||
11 | 13 | ||
12 | #define for_each_set_bit(bit, addr, size) \ | 14 | #define for_each_set_bit(bit, addr, size) \ |
13 | for ((bit) = find_first_bit((addr), (size)); \ | 15 | for ((bit) = find_first_bit((addr), (size)); \ |
diff --git a/tools/perf/util/parse-events-test.c b/tools/perf/util/parse-events-test.c index d0cf7c1ed068..229af6da33a2 100644 --- a/tools/perf/util/parse-events-test.c +++ b/tools/perf/util/parse-events-test.c | |||
@@ -430,6 +430,49 @@ static int test__checkevent_pmu_name(struct perf_evlist *evlist) | |||
430 | return 0; | 430 | return 0; |
431 | } | 431 | } |
432 | 432 | ||
433 | static int test__checkterms_simple(struct list_head *terms) | ||
434 | { | ||
435 | struct parse_events__term *term; | ||
436 | |||
437 | /* config=10 */ | ||
438 | term = list_entry(terms->next, struct parse_events__term, list); | ||
439 | TEST_ASSERT_VAL("wrong type term", | ||
440 | term->type_term == PARSE_EVENTS__TERM_TYPE_CONFIG); | ||
441 | TEST_ASSERT_VAL("wrong type val", | ||
442 | term->type_val == PARSE_EVENTS__TERM_TYPE_NUM); | ||
443 | TEST_ASSERT_VAL("wrong val", term->val.num == 10); | ||
444 | TEST_ASSERT_VAL("wrong config", !term->config); | ||
445 | |||
446 | /* config1 */ | ||
447 | term = list_entry(term->list.next, struct parse_events__term, list); | ||
448 | TEST_ASSERT_VAL("wrong type term", | ||
449 | term->type_term == PARSE_EVENTS__TERM_TYPE_CONFIG1); | ||
450 | TEST_ASSERT_VAL("wrong type val", | ||
451 | term->type_val == PARSE_EVENTS__TERM_TYPE_NUM); | ||
452 | TEST_ASSERT_VAL("wrong val", term->val.num == 1); | ||
453 | TEST_ASSERT_VAL("wrong config", !term->config); | ||
454 | |||
455 | /* config2=3 */ | ||
456 | term = list_entry(term->list.next, struct parse_events__term, list); | ||
457 | TEST_ASSERT_VAL("wrong type term", | ||
458 | term->type_term == PARSE_EVENTS__TERM_TYPE_CONFIG2); | ||
459 | TEST_ASSERT_VAL("wrong type val", | ||
460 | term->type_val == PARSE_EVENTS__TERM_TYPE_NUM); | ||
461 | TEST_ASSERT_VAL("wrong val", term->val.num == 3); | ||
462 | TEST_ASSERT_VAL("wrong config", !term->config); | ||
463 | |||
464 | /* umask=1*/ | ||
465 | term = list_entry(term->list.next, struct parse_events__term, list); | ||
466 | TEST_ASSERT_VAL("wrong type term", | ||
467 | term->type_term == PARSE_EVENTS__TERM_TYPE_USER); | ||
468 | TEST_ASSERT_VAL("wrong type val", | ||
469 | term->type_val == PARSE_EVENTS__TERM_TYPE_NUM); | ||
470 | TEST_ASSERT_VAL("wrong val", term->val.num == 1); | ||
471 | TEST_ASSERT_VAL("wrong config", !strcmp(term->config, "umask")); | ||
472 | |||
473 | return 0; | ||
474 | } | ||
475 | |||
433 | struct test__event_st { | 476 | struct test__event_st { |
434 | const char *name; | 477 | const char *name; |
435 | __u32 type; | 478 | __u32 type; |
@@ -559,7 +602,23 @@ static struct test__event_st test__events_pmu[] = { | |||
559 | #define TEST__EVENTS_PMU_CNT (sizeof(test__events_pmu) / \ | 602 | #define TEST__EVENTS_PMU_CNT (sizeof(test__events_pmu) / \ |
560 | sizeof(struct test__event_st)) | 603 | sizeof(struct test__event_st)) |
561 | 604 | ||
562 | static int test(struct test__event_st *e) | 605 | struct test__term { |
606 | const char *str; | ||
607 | __u32 type; | ||
608 | int (*check)(struct list_head *terms); | ||
609 | }; | ||
610 | |||
611 | static struct test__term test__terms[] = { | ||
612 | [0] = { | ||
613 | .str = "config=10,config1,config2=3,umask=1", | ||
614 | .check = test__checkterms_simple, | ||
615 | }, | ||
616 | }; | ||
617 | |||
618 | #define TEST__TERMS_CNT (sizeof(test__terms) / \ | ||
619 | sizeof(struct test__term)) | ||
620 | |||
621 | static int test_event(struct test__event_st *e) | ||
563 | { | 622 | { |
564 | struct perf_evlist *evlist; | 623 | struct perf_evlist *evlist; |
565 | int ret; | 624 | int ret; |
@@ -590,7 +649,48 @@ static int test_events(struct test__event_st *events, unsigned cnt) | |||
590 | struct test__event_st *e = &events[i]; | 649 | struct test__event_st *e = &events[i]; |
591 | 650 | ||
592 | pr_debug("running test %d '%s'\n", i, e->name); | 651 | pr_debug("running test %d '%s'\n", i, e->name); |
593 | ret = test(e); | 652 | ret = test_event(e); |
653 | if (ret) | ||
654 | break; | ||
655 | } | ||
656 | |||
657 | return ret; | ||
658 | } | ||
659 | |||
660 | static int test_term(struct test__term *t) | ||
661 | { | ||
662 | struct list_head *terms; | ||
663 | int ret; | ||
664 | |||
665 | terms = malloc(sizeof(*terms)); | ||
666 | if (!terms) | ||
667 | return -ENOMEM; | ||
668 | |||
669 | INIT_LIST_HEAD(terms); | ||
670 | |||
671 | ret = parse_events_terms(terms, t->str); | ||
672 | if (ret) { | ||
673 | pr_debug("failed to parse terms '%s', err %d\n", | ||
674 | t->str , ret); | ||
675 | return ret; | ||
676 | } | ||
677 | |||
678 | ret = t->check(terms); | ||
679 | parse_events__free_terms(terms); | ||
680 | |||
681 | return ret; | ||
682 | } | ||
683 | |||
684 | static int test_terms(struct test__term *terms, unsigned cnt) | ||
685 | { | ||
686 | int ret = 0; | ||
687 | unsigned i; | ||
688 | |||
689 | for (i = 0; i < cnt; i++) { | ||
690 | struct test__term *t = &terms[i]; | ||
691 | |||
692 | pr_debug("running test %d '%s'\n", i, t->str); | ||
693 | ret = test_term(t); | ||
594 | if (ret) | 694 | if (ret) |
595 | break; | 695 | break; |
596 | } | 696 | } |
@@ -617,9 +717,21 @@ int parse_events__test(void) | |||
617 | { | 717 | { |
618 | int ret; | 718 | int ret; |
619 | 719 | ||
620 | ret = test_events(test__events, TEST__EVENTS_CNT); | 720 | do { |
621 | if (!ret && test_pmu()) | 721 | ret = test_events(test__events, TEST__EVENTS_CNT); |
622 | ret = test_events(test__events_pmu, TEST__EVENTS_PMU_CNT); | 722 | if (ret) |
723 | break; | ||
724 | |||
725 | if (test_pmu()) { | ||
726 | ret = test_events(test__events_pmu, | ||
727 | TEST__EVENTS_PMU_CNT); | ||
728 | if (ret) | ||
729 | break; | ||
730 | } | ||
731 | |||
732 | ret = test_terms(test__terms, TEST__TERMS_CNT); | ||
733 | |||
734 | } while (0); | ||
623 | 735 | ||
624 | return ret; | 736 | return ret; |
625 | } | 737 | } |
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index eacf932a36a0..0cc27da30ddb 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c | |||
@@ -11,6 +11,8 @@ | |||
11 | #include "cache.h" | 11 | #include "cache.h" |
12 | #include "header.h" | 12 | #include "header.h" |
13 | #include "debugfs.h" | 13 | #include "debugfs.h" |
14 | #include "parse-events-bison.h" | ||
15 | #define YY_EXTRA_TYPE int | ||
14 | #include "parse-events-flex.h" | 16 | #include "parse-events-flex.h" |
15 | #include "pmu.h" | 17 | #include "pmu.h" |
16 | 18 | ||
@@ -26,7 +28,7 @@ struct event_symbol { | |||
26 | #ifdef PARSER_DEBUG | 28 | #ifdef PARSER_DEBUG |
27 | extern int parse_events_debug; | 29 | extern int parse_events_debug; |
28 | #endif | 30 | #endif |
29 | int parse_events_parse(struct list_head *list, int *idx); | 31 | int parse_events_parse(void *data, void *scanner); |
30 | 32 | ||
31 | #define CHW(x) .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_##x | 33 | #define CHW(x) .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_##x |
32 | #define CSW(x) .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_##x | 34 | #define CSW(x) .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_##x |
@@ -529,6 +531,9 @@ int parse_events_add_pmu(struct list_head **list, int *idx, | |||
529 | 531 | ||
530 | memset(&attr, 0, sizeof(attr)); | 532 | memset(&attr, 0, sizeof(attr)); |
531 | 533 | ||
534 | if (perf_pmu__check_alias(pmu, head_config)) | ||
535 | return -EINVAL; | ||
536 | |||
532 | /* | 537 | /* |
533 | * Configure hardcoded terms first, no need to check | 538 | * Configure hardcoded terms first, no need to check |
534 | * return value when called with fail == 0 ;) | 539 | * return value when called with fail == 0 ;) |
@@ -617,27 +622,62 @@ int parse_events_modifier(struct list_head *list, char *str) | |||
617 | return 0; | 622 | return 0; |
618 | } | 623 | } |
619 | 624 | ||
620 | int parse_events(struct perf_evlist *evlist, const char *str, int unset __used) | 625 | static int parse_events__scanner(const char *str, void *data, int start_token) |
621 | { | 626 | { |
622 | LIST_HEAD(list); | ||
623 | LIST_HEAD(list_tmp); | ||
624 | YY_BUFFER_STATE buffer; | 627 | YY_BUFFER_STATE buffer; |
625 | int ret, idx = evlist->nr_entries; | 628 | void *scanner; |
629 | int ret; | ||
630 | |||
631 | ret = parse_events_lex_init_extra(start_token, &scanner); | ||
632 | if (ret) | ||
633 | return ret; | ||
626 | 634 | ||
627 | buffer = parse_events__scan_string(str); | 635 | buffer = parse_events__scan_string(str, scanner); |
628 | 636 | ||
629 | #ifdef PARSER_DEBUG | 637 | #ifdef PARSER_DEBUG |
630 | parse_events_debug = 1; | 638 | parse_events_debug = 1; |
631 | #endif | 639 | #endif |
632 | ret = parse_events_parse(&list, &idx); | 640 | ret = parse_events_parse(data, scanner); |
641 | |||
642 | parse_events__flush_buffer(buffer, scanner); | ||
643 | parse_events__delete_buffer(buffer, scanner); | ||
644 | parse_events_lex_destroy(scanner); | ||
645 | return ret; | ||
646 | } | ||
647 | |||
648 | /* | ||
649 | * parse event config string, return a list of event terms. | ||
650 | */ | ||
651 | int parse_events_terms(struct list_head *terms, const char *str) | ||
652 | { | ||
653 | struct parse_events_data__terms data = { | ||
654 | .terms = NULL, | ||
655 | }; | ||
656 | int ret; | ||
657 | |||
658 | ret = parse_events__scanner(str, &data, PE_START_TERMS); | ||
659 | if (!ret) { | ||
660 | list_splice(data.terms, terms); | ||
661 | free(data.terms); | ||
662 | return 0; | ||
663 | } | ||
664 | |||
665 | parse_events__free_terms(data.terms); | ||
666 | return ret; | ||
667 | } | ||
633 | 668 | ||
634 | parse_events__flush_buffer(buffer); | 669 | int parse_events(struct perf_evlist *evlist, const char *str, int unset __used) |
635 | parse_events__delete_buffer(buffer); | 670 | { |
636 | parse_events_lex_destroy(); | 671 | struct parse_events_data__events data = { |
672 | .list = LIST_HEAD_INIT(data.list), | ||
673 | .idx = evlist->nr_entries, | ||
674 | }; | ||
675 | int ret; | ||
637 | 676 | ||
677 | ret = parse_events__scanner(str, &data, PE_START_EVENTS); | ||
638 | if (!ret) { | 678 | if (!ret) { |
639 | int entries = idx - evlist->nr_entries; | 679 | int entries = data.idx - evlist->nr_entries; |
640 | perf_evlist__splice_list_tail(evlist, &list, entries); | 680 | perf_evlist__splice_list_tail(evlist, &data.list, entries); |
641 | return 0; | 681 | return 0; |
642 | } | 682 | } |
643 | 683 | ||
@@ -937,6 +977,13 @@ int parse_events__term_str(struct parse_events__term **term, | |||
937 | config, str, 0); | 977 | config, str, 0); |
938 | } | 978 | } |
939 | 979 | ||
980 | int parse_events__term_clone(struct parse_events__term **new, | ||
981 | struct parse_events__term *term) | ||
982 | { | ||
983 | return new_term(new, term->type_val, term->type_term, term->config, | ||
984 | term->val.str, term->val.num); | ||
985 | } | ||
986 | |||
940 | void parse_events__free_terms(struct list_head *terms) | 987 | void parse_events__free_terms(struct list_head *terms) |
941 | { | 988 | { |
942 | struct parse_events__term *term, *h; | 989 | struct parse_events__term *term, *h; |
diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h index 1784f06e3a6a..ee9c218a193c 100644 --- a/tools/perf/util/parse-events.h +++ b/tools/perf/util/parse-events.h | |||
@@ -31,6 +31,7 @@ extern int parse_events_option(const struct option *opt, const char *str, | |||
31 | int unset); | 31 | int unset); |
32 | extern int parse_events(struct perf_evlist *evlist, const char *str, | 32 | extern int parse_events(struct perf_evlist *evlist, const char *str, |
33 | int unset); | 33 | int unset); |
34 | extern int parse_events_terms(struct list_head *terms, const char *str); | ||
34 | extern int parse_filter(const struct option *opt, const char *str, int unset); | 35 | extern int parse_filter(const struct option *opt, const char *str, int unset); |
35 | 36 | ||
36 | #define EVENTS_HELP_MAX (128*1024) | 37 | #define EVENTS_HELP_MAX (128*1024) |
@@ -61,11 +62,22 @@ struct parse_events__term { | |||
61 | struct list_head list; | 62 | struct list_head list; |
62 | }; | 63 | }; |
63 | 64 | ||
65 | struct parse_events_data__events { | ||
66 | struct list_head list; | ||
67 | int idx; | ||
68 | }; | ||
69 | |||
70 | struct parse_events_data__terms { | ||
71 | struct list_head *terms; | ||
72 | }; | ||
73 | |||
64 | int parse_events__is_hardcoded_term(struct parse_events__term *term); | 74 | int parse_events__is_hardcoded_term(struct parse_events__term *term); |
65 | int parse_events__term_num(struct parse_events__term **_term, | 75 | int parse_events__term_num(struct parse_events__term **_term, |
66 | int type_term, char *config, long num); | 76 | int type_term, char *config, long num); |
67 | int parse_events__term_str(struct parse_events__term **_term, | 77 | int parse_events__term_str(struct parse_events__term **_term, |
68 | int type_term, char *config, char *str); | 78 | int type_term, char *config, char *str); |
79 | int parse_events__term_clone(struct parse_events__term **new, | ||
80 | struct parse_events__term *term); | ||
69 | void parse_events__free_terms(struct list_head *terms); | 81 | void parse_events__free_terms(struct list_head *terms); |
70 | int parse_events_modifier(struct list_head *list, char *str); | 82 | int parse_events_modifier(struct list_head *list, char *str); |
71 | int parse_events_add_tracepoint(struct list_head **list, int *idx, | 83 | int parse_events_add_tracepoint(struct list_head **list, int *idx, |
@@ -81,8 +93,7 @@ int parse_events_add_pmu(struct list_head **list, int *idx, | |||
81 | char *pmu , struct list_head *head_config); | 93 | char *pmu , struct list_head *head_config); |
82 | void parse_events_update_lists(struct list_head *list_event, | 94 | void parse_events_update_lists(struct list_head *list_event, |
83 | struct list_head *list_all); | 95 | struct list_head *list_all); |
84 | void parse_events_error(struct list_head *list_all, | 96 | void parse_events_error(void *data, void *scanner, char const *msg); |
85 | int *idx, char const *msg); | ||
86 | int parse_events__test(void); | 97 | int parse_events__test(void); |
87 | 98 | ||
88 | void print_events(const char *event_glob); | 99 | void print_events(const char *event_glob); |
diff --git a/tools/perf/util/parse-events.l b/tools/perf/util/parse-events.l index 618a8e788399..488362e14133 100644 --- a/tools/perf/util/parse-events.l +++ b/tools/perf/util/parse-events.l | |||
@@ -1,4 +1,6 @@ | |||
1 | 1 | ||
2 | %option reentrant | ||
3 | %option bison-bridge | ||
2 | %option prefix="parse_events_" | 4 | %option prefix="parse_events_" |
3 | %option stack | 5 | %option stack |
4 | 6 | ||
@@ -8,7 +10,10 @@ | |||
8 | #include "parse-events-bison.h" | 10 | #include "parse-events-bison.h" |
9 | #include "parse-events.h" | 11 | #include "parse-events.h" |
10 | 12 | ||
11 | static int __value(char *str, int base, int token) | 13 | char *parse_events_get_text(yyscan_t yyscanner); |
14 | YYSTYPE *parse_events_get_lval(yyscan_t yyscanner); | ||
15 | |||
16 | static int __value(YYSTYPE *yylval, char *str, int base, int token) | ||
12 | { | 17 | { |
13 | long num; | 18 | long num; |
14 | 19 | ||
@@ -17,35 +22,48 @@ static int __value(char *str, int base, int token) | |||
17 | if (errno) | 22 | if (errno) |
18 | return PE_ERROR; | 23 | return PE_ERROR; |
19 | 24 | ||
20 | parse_events_lval.num = num; | 25 | yylval->num = num; |
21 | return token; | 26 | return token; |
22 | } | 27 | } |
23 | 28 | ||
24 | static int value(int base) | 29 | static int value(yyscan_t scanner, int base) |
25 | { | 30 | { |
26 | return __value(parse_events_text, base, PE_VALUE); | 31 | YYSTYPE *yylval = parse_events_get_lval(scanner); |
32 | char *text = parse_events_get_text(scanner); | ||
33 | |||
34 | return __value(yylval, text, base, PE_VALUE); | ||
27 | } | 35 | } |
28 | 36 | ||
29 | static int raw(void) | 37 | static int raw(yyscan_t scanner) |
30 | { | 38 | { |
31 | return __value(parse_events_text + 1, 16, PE_RAW); | 39 | YYSTYPE *yylval = parse_events_get_lval(scanner); |
40 | char *text = parse_events_get_text(scanner); | ||
41 | |||
42 | return __value(yylval, text + 1, 16, PE_RAW); | ||
32 | } | 43 | } |
33 | 44 | ||
34 | static int str(int token) | 45 | static int str(yyscan_t scanner, int token) |
35 | { | 46 | { |
36 | parse_events_lval.str = strdup(parse_events_text); | 47 | YYSTYPE *yylval = parse_events_get_lval(scanner); |
48 | char *text = parse_events_get_text(scanner); | ||
49 | |||
50 | yylval->str = strdup(text); | ||
37 | return token; | 51 | return token; |
38 | } | 52 | } |
39 | 53 | ||
40 | static int sym(int type, int config) | 54 | static int sym(yyscan_t scanner, int type, int config) |
41 | { | 55 | { |
42 | parse_events_lval.num = (type << 16) + config; | 56 | YYSTYPE *yylval = parse_events_get_lval(scanner); |
57 | |||
58 | yylval->num = (type << 16) + config; | ||
43 | return PE_VALUE_SYM; | 59 | return PE_VALUE_SYM; |
44 | } | 60 | } |
45 | 61 | ||
46 | static int term(int type) | 62 | static int term(yyscan_t scanner, int type) |
47 | { | 63 | { |
48 | parse_events_lval.num = type; | 64 | YYSTYPE *yylval = parse_events_get_lval(scanner); |
65 | |||
66 | yylval->num = type; | ||
49 | return PE_TERM; | 67 | return PE_TERM; |
50 | } | 68 | } |
51 | 69 | ||
@@ -61,25 +79,38 @@ modifier_event [ukhpGH]{1,8} | |||
61 | modifier_bp [rwx] | 79 | modifier_bp [rwx] |
62 | 80 | ||
63 | %% | 81 | %% |
64 | cpu-cycles|cycles { return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_CPU_CYCLES); } | 82 | |
65 | stalled-cycles-frontend|idle-cycles-frontend { return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_STALLED_CYCLES_FRONTEND); } | 83 | %{ |
66 | stalled-cycles-backend|idle-cycles-backend { return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_STALLED_CYCLES_BACKEND); } | 84 | { |
67 | instructions { return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_INSTRUCTIONS); } | 85 | int start_token; |
68 | cache-references { return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_CACHE_REFERENCES); } | 86 | |
69 | cache-misses { return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_CACHE_MISSES); } | 87 | start_token = (int) parse_events_get_extra(yyscanner); |
70 | branch-instructions|branches { return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_BRANCH_INSTRUCTIONS); } | 88 | if (start_token) { |
71 | branch-misses { return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_BRANCH_MISSES); } | 89 | parse_events_set_extra(NULL, yyscanner); |
72 | bus-cycles { return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_BUS_CYCLES); } | 90 | return start_token; |
73 | ref-cycles { return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_REF_CPU_CYCLES); } | 91 | } |
74 | cpu-clock { return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_CPU_CLOCK); } | 92 | } |
75 | task-clock { return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_TASK_CLOCK); } | 93 | %} |
76 | page-faults|faults { return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_PAGE_FAULTS); } | 94 | |
77 | minor-faults { return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_PAGE_FAULTS_MIN); } | 95 | cpu-cycles|cycles { return sym(yyscanner, PERF_TYPE_HARDWARE, PERF_COUNT_HW_CPU_CYCLES); } |
78 | major-faults { return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_PAGE_FAULTS_MAJ); } | 96 | stalled-cycles-frontend|idle-cycles-frontend { return sym(yyscanner, PERF_TYPE_HARDWARE, PERF_COUNT_HW_STALLED_CYCLES_FRONTEND); } |
79 | context-switches|cs { return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_CONTEXT_SWITCHES); } | 97 | stalled-cycles-backend|idle-cycles-backend { return sym(yyscanner, PERF_TYPE_HARDWARE, PERF_COUNT_HW_STALLED_CYCLES_BACKEND); } |
80 | cpu-migrations|migrations { return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_CPU_MIGRATIONS); } | 98 | instructions { return sym(yyscanner, PERF_TYPE_HARDWARE, PERF_COUNT_HW_INSTRUCTIONS); } |
81 | alignment-faults { return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_ALIGNMENT_FAULTS); } | 99 | cache-references { return sym(yyscanner, PERF_TYPE_HARDWARE, PERF_COUNT_HW_CACHE_REFERENCES); } |
82 | emulation-faults { return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_EMULATION_FAULTS); } | 100 | cache-misses { return sym(yyscanner, PERF_TYPE_HARDWARE, PERF_COUNT_HW_CACHE_MISSES); } |
101 | branch-instructions|branches { return sym(yyscanner, PERF_TYPE_HARDWARE, PERF_COUNT_HW_BRANCH_INSTRUCTIONS); } | ||
102 | branch-misses { return sym(yyscanner, PERF_TYPE_HARDWARE, PERF_COUNT_HW_BRANCH_MISSES); } | ||
103 | bus-cycles { return sym(yyscanner, PERF_TYPE_HARDWARE, PERF_COUNT_HW_BUS_CYCLES); } | ||
104 | ref-cycles { return sym(yyscanner, PERF_TYPE_HARDWARE, PERF_COUNT_HW_REF_CPU_CYCLES); } | ||
105 | cpu-clock { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_CPU_CLOCK); } | ||
106 | task-clock { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_TASK_CLOCK); } | ||
107 | page-faults|faults { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_PAGE_FAULTS); } | ||
108 | minor-faults { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_PAGE_FAULTS_MIN); } | ||
109 | major-faults { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_PAGE_FAULTS_MAJ); } | ||
110 | context-switches|cs { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_CONTEXT_SWITCHES); } | ||
111 | cpu-migrations|migrations { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_CPU_MIGRATIONS); } | ||
112 | alignment-faults { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_ALIGNMENT_FAULTS); } | ||
113 | emulation-faults { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_EMULATION_FAULTS); } | ||
83 | 114 | ||
84 | L1-dcache|l1-d|l1d|L1-data | | 115 | L1-dcache|l1-d|l1d|L1-data | |
85 | L1-icache|l1-i|l1i|L1-instruction | | 116 | L1-icache|l1-i|l1i|L1-instruction | |
@@ -87,14 +118,14 @@ LLC|L2 | | |||
87 | dTLB|d-tlb|Data-TLB | | 118 | dTLB|d-tlb|Data-TLB | |
88 | iTLB|i-tlb|Instruction-TLB | | 119 | iTLB|i-tlb|Instruction-TLB | |
89 | branch|branches|bpu|btb|bpc | | 120 | branch|branches|bpu|btb|bpc | |
90 | node { return str(PE_NAME_CACHE_TYPE); } | 121 | node { return str(yyscanner, PE_NAME_CACHE_TYPE); } |
91 | 122 | ||
92 | load|loads|read | | 123 | load|loads|read | |
93 | store|stores|write | | 124 | store|stores|write | |
94 | prefetch|prefetches | | 125 | prefetch|prefetches | |
95 | speculative-read|speculative-load | | 126 | speculative-read|speculative-load | |
96 | refs|Reference|ops|access | | 127 | refs|Reference|ops|access | |
97 | misses|miss { return str(PE_NAME_CACHE_OP_RESULT); } | 128 | misses|miss { return str(yyscanner, PE_NAME_CACHE_OP_RESULT); } |
98 | 129 | ||
99 | /* | 130 | /* |
100 | * These are event config hardcoded term names to be specified | 131 | * These are event config hardcoded term names to be specified |
@@ -102,20 +133,20 @@ misses|miss { return str(PE_NAME_CACHE_OP_RESULT); } | |||
102 | * so we can put them here directly. In case the we have a conflict | 133 | * so we can put them here directly. In case the we have a conflict |
103 | * in future, this needs to go into '//' condition block. | 134 | * in future, this needs to go into '//' condition block. |
104 | */ | 135 | */ |
105 | config { return term(PARSE_EVENTS__TERM_TYPE_CONFIG); } | 136 | config { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_CONFIG); } |
106 | config1 { return term(PARSE_EVENTS__TERM_TYPE_CONFIG1); } | 137 | config1 { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_CONFIG1); } |
107 | config2 { return term(PARSE_EVENTS__TERM_TYPE_CONFIG2); } | 138 | config2 { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_CONFIG2); } |
108 | name { return term(PARSE_EVENTS__TERM_TYPE_NAME); } | 139 | name { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_NAME); } |
109 | period { return term(PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD); } | 140 | period { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD); } |
110 | branch_type { return term(PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE); } | 141 | branch_type { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE); } |
111 | 142 | ||
112 | mem: { BEGIN(mem); return PE_PREFIX_MEM; } | 143 | mem: { BEGIN(mem); return PE_PREFIX_MEM; } |
113 | r{num_raw_hex} { return raw(); } | 144 | r{num_raw_hex} { return raw(yyscanner); } |
114 | {num_dec} { return value(10); } | 145 | {num_dec} { return value(yyscanner, 10); } |
115 | {num_hex} { return value(16); } | 146 | {num_hex} { return value(yyscanner, 16); } |
116 | 147 | ||
117 | {modifier_event} { return str(PE_MODIFIER_EVENT); } | 148 | {modifier_event} { return str(yyscanner, PE_MODIFIER_EVENT); } |
118 | {name} { return str(PE_NAME); } | 149 | {name} { return str(yyscanner, PE_NAME); } |
119 | "/" { return '/'; } | 150 | "/" { return '/'; } |
120 | - { return '-'; } | 151 | - { return '-'; } |
121 | , { return ','; } | 152 | , { return ','; } |
@@ -123,17 +154,17 @@ r{num_raw_hex} { return raw(); } | |||
123 | = { return '='; } | 154 | = { return '='; } |
124 | 155 | ||
125 | <mem>{ | 156 | <mem>{ |
126 | {modifier_bp} { return str(PE_MODIFIER_BP); } | 157 | {modifier_bp} { return str(yyscanner, PE_MODIFIER_BP); } |
127 | : { return ':'; } | 158 | : { return ':'; } |
128 | {num_dec} { return value(10); } | 159 | {num_dec} { return value(yyscanner, 10); } |
129 | {num_hex} { return value(16); } | 160 | {num_hex} { return value(yyscanner, 16); } |
130 | /* | 161 | /* |
131 | * We need to separate 'mem:' scanner part, in order to get specific | 162 | * We need to separate 'mem:' scanner part, in order to get specific |
132 | * modifier bits parsed out. Otherwise we would need to handle PE_NAME | 163 | * modifier bits parsed out. Otherwise we would need to handle PE_NAME |
133 | * and we'd need to parse it manually. During the escape from <mem> | 164 | * and we'd need to parse it manually. During the escape from <mem> |
134 | * state we need to put the escaping char back, so we dont miss it. | 165 | * state we need to put the escaping char back, so we dont miss it. |
135 | */ | 166 | */ |
136 | . { unput(*parse_events_text); BEGIN(INITIAL); } | 167 | . { unput(*yytext); BEGIN(INITIAL); } |
137 | /* | 168 | /* |
138 | * We destroy the scanner after reaching EOF, | 169 | * We destroy the scanner after reaching EOF, |
139 | * but anyway just to be sure get back to INIT state. | 170 | * but anyway just to be sure get back to INIT state. |
@@ -143,7 +174,7 @@ r{num_raw_hex} { return raw(); } | |||
143 | 174 | ||
144 | %% | 175 | %% |
145 | 176 | ||
146 | int parse_events_wrap(void) | 177 | int parse_events_wrap(void *scanner __used) |
147 | { | 178 | { |
148 | return 1; | 179 | return 1; |
149 | } | 180 | } |
diff --git a/tools/perf/util/parse-events.y b/tools/perf/util/parse-events.y index 362cc59332ae..9525c455d27f 100644 --- a/tools/perf/util/parse-events.y +++ b/tools/perf/util/parse-events.y | |||
@@ -1,7 +1,8 @@ | |||
1 | 1 | %pure-parser | |
2 | %name-prefix "parse_events_" | 2 | %name-prefix "parse_events_" |
3 | %parse-param {struct list_head *list_all} | 3 | %parse-param {void *_data} |
4 | %parse-param {int *idx} | 4 | %parse-param {void *scanner} |
5 | %lex-param {void* scanner} | ||
5 | 6 | ||
6 | %{ | 7 | %{ |
7 | 8 | ||
@@ -12,8 +13,9 @@ | |||
12 | #include "types.h" | 13 | #include "types.h" |
13 | #include "util.h" | 14 | #include "util.h" |
14 | #include "parse-events.h" | 15 | #include "parse-events.h" |
16 | #include "parse-events-bison.h" | ||
15 | 17 | ||
16 | extern int parse_events_lex (void); | 18 | extern int parse_events_lex (YYSTYPE* lvalp, void* scanner); |
17 | 19 | ||
18 | #define ABORT_ON(val) \ | 20 | #define ABORT_ON(val) \ |
19 | do { \ | 21 | do { \ |
@@ -23,6 +25,7 @@ do { \ | |||
23 | 25 | ||
24 | %} | 26 | %} |
25 | 27 | ||
28 | %token PE_START_EVENTS PE_START_TERMS | ||
26 | %token PE_VALUE PE_VALUE_SYM PE_RAW PE_TERM | 29 | %token PE_VALUE PE_VALUE_SYM PE_RAW PE_TERM |
27 | %token PE_NAME | 30 | %token PE_NAME |
28 | %token PE_MODIFIER_EVENT PE_MODIFIER_BP | 31 | %token PE_MODIFIER_EVENT PE_MODIFIER_BP |
@@ -58,24 +61,33 @@ do { \ | |||
58 | } | 61 | } |
59 | %% | 62 | %% |
60 | 63 | ||
64 | start: | ||
65 | PE_START_EVENTS events | ||
66 | | | ||
67 | PE_START_TERMS terms | ||
68 | |||
61 | events: | 69 | events: |
62 | events ',' event | event | 70 | events ',' event | event |
63 | 71 | ||
64 | event: | 72 | event: |
65 | event_def PE_MODIFIER_EVENT | 73 | event_def PE_MODIFIER_EVENT |
66 | { | 74 | { |
75 | struct parse_events_data__events *data = _data; | ||
76 | |||
67 | /* | 77 | /* |
68 | * Apply modifier on all events added by single event definition | 78 | * Apply modifier on all events added by single event definition |
69 | * (there could be more events added for multiple tracepoint | 79 | * (there could be more events added for multiple tracepoint |
70 | * definitions via '*?'. | 80 | * definitions via '*?'. |
71 | */ | 81 | */ |
72 | ABORT_ON(parse_events_modifier($1, $2)); | 82 | ABORT_ON(parse_events_modifier($1, $2)); |
73 | parse_events_update_lists($1, list_all); | 83 | parse_events_update_lists($1, &data->list); |
74 | } | 84 | } |
75 | | | 85 | | |
76 | event_def | 86 | event_def |
77 | { | 87 | { |
78 | parse_events_update_lists($1, list_all); | 88 | struct parse_events_data__events *data = _data; |
89 | |||
90 | parse_events_update_lists($1, &data->list); | ||
79 | } | 91 | } |
80 | 92 | ||
81 | event_def: event_pmu | | 93 | event_def: event_pmu | |
@@ -89,9 +101,10 @@ event_def: event_pmu | | |||
89 | event_pmu: | 101 | event_pmu: |
90 | PE_NAME '/' event_config '/' | 102 | PE_NAME '/' event_config '/' |
91 | { | 103 | { |
104 | struct parse_events_data__events *data = _data; | ||
92 | struct list_head *list = NULL; | 105 | struct list_head *list = NULL; |
93 | 106 | ||
94 | ABORT_ON(parse_events_add_pmu(&list, idx, $1, $3)); | 107 | ABORT_ON(parse_events_add_pmu(&list, &data->idx, $1, $3)); |
95 | parse_events__free_terms($3); | 108 | parse_events__free_terms($3); |
96 | $$ = list; | 109 | $$ = list; |
97 | } | 110 | } |
@@ -99,94 +112,115 @@ PE_NAME '/' event_config '/' | |||
99 | event_legacy_symbol: | 112 | event_legacy_symbol: |
100 | PE_VALUE_SYM '/' event_config '/' | 113 | PE_VALUE_SYM '/' event_config '/' |
101 | { | 114 | { |
115 | struct parse_events_data__events *data = _data; | ||
102 | struct list_head *list = NULL; | 116 | struct list_head *list = NULL; |
103 | int type = $1 >> 16; | 117 | int type = $1 >> 16; |
104 | int config = $1 & 255; | 118 | int config = $1 & 255; |
105 | 119 | ||
106 | ABORT_ON(parse_events_add_numeric(&list, idx, type, config, $3)); | 120 | ABORT_ON(parse_events_add_numeric(&list, &data->idx, |
121 | type, config, $3)); | ||
107 | parse_events__free_terms($3); | 122 | parse_events__free_terms($3); |
108 | $$ = list; | 123 | $$ = list; |
109 | } | 124 | } |
110 | | | 125 | | |
111 | PE_VALUE_SYM sep_slash_dc | 126 | PE_VALUE_SYM sep_slash_dc |
112 | { | 127 | { |
128 | struct parse_events_data__events *data = _data; | ||
113 | struct list_head *list = NULL; | 129 | struct list_head *list = NULL; |
114 | int type = $1 >> 16; | 130 | int type = $1 >> 16; |
115 | int config = $1 & 255; | 131 | int config = $1 & 255; |
116 | 132 | ||
117 | ABORT_ON(parse_events_add_numeric(&list, idx, type, config, NULL)); | 133 | ABORT_ON(parse_events_add_numeric(&list, &data->idx, |
134 | type, config, NULL)); | ||
118 | $$ = list; | 135 | $$ = list; |
119 | } | 136 | } |
120 | 137 | ||
121 | event_legacy_cache: | 138 | event_legacy_cache: |
122 | PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT '-' PE_NAME_CACHE_OP_RESULT | 139 | PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT '-' PE_NAME_CACHE_OP_RESULT |
123 | { | 140 | { |
141 | struct parse_events_data__events *data = _data; | ||
124 | struct list_head *list = NULL; | 142 | struct list_head *list = NULL; |
125 | 143 | ||
126 | ABORT_ON(parse_events_add_cache(&list, idx, $1, $3, $5)); | 144 | ABORT_ON(parse_events_add_cache(&list, &data->idx, $1, $3, $5)); |
127 | $$ = list; | 145 | $$ = list; |
128 | } | 146 | } |
129 | | | 147 | | |
130 | PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT | 148 | PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT |
131 | { | 149 | { |
150 | struct parse_events_data__events *data = _data; | ||
132 | struct list_head *list = NULL; | 151 | struct list_head *list = NULL; |
133 | 152 | ||
134 | ABORT_ON(parse_events_add_cache(&list, idx, $1, $3, NULL)); | 153 | ABORT_ON(parse_events_add_cache(&list, &data->idx, $1, $3, NULL)); |
135 | $$ = list; | 154 | $$ = list; |
136 | } | 155 | } |
137 | | | 156 | | |
138 | PE_NAME_CACHE_TYPE | 157 | PE_NAME_CACHE_TYPE |
139 | { | 158 | { |
159 | struct parse_events_data__events *data = _data; | ||
140 | struct list_head *list = NULL; | 160 | struct list_head *list = NULL; |
141 | 161 | ||
142 | ABORT_ON(parse_events_add_cache(&list, idx, $1, NULL, NULL)); | 162 | ABORT_ON(parse_events_add_cache(&list, &data->idx, $1, NULL, NULL)); |
143 | $$ = list; | 163 | $$ = list; |
144 | } | 164 | } |
145 | 165 | ||
146 | event_legacy_mem: | 166 | event_legacy_mem: |
147 | PE_PREFIX_MEM PE_VALUE ':' PE_MODIFIER_BP sep_dc | 167 | PE_PREFIX_MEM PE_VALUE ':' PE_MODIFIER_BP sep_dc |
148 | { | 168 | { |
169 | struct parse_events_data__events *data = _data; | ||
149 | struct list_head *list = NULL; | 170 | struct list_head *list = NULL; |
150 | 171 | ||
151 | ABORT_ON(parse_events_add_breakpoint(&list, idx, (void *) $2, $4)); | 172 | ABORT_ON(parse_events_add_breakpoint(&list, &data->idx, |
173 | (void *) $2, $4)); | ||
152 | $$ = list; | 174 | $$ = list; |
153 | } | 175 | } |
154 | | | 176 | | |
155 | PE_PREFIX_MEM PE_VALUE sep_dc | 177 | PE_PREFIX_MEM PE_VALUE sep_dc |
156 | { | 178 | { |
179 | struct parse_events_data__events *data = _data; | ||
157 | struct list_head *list = NULL; | 180 | struct list_head *list = NULL; |
158 | 181 | ||
159 | ABORT_ON(parse_events_add_breakpoint(&list, idx, (void *) $2, NULL)); | 182 | ABORT_ON(parse_events_add_breakpoint(&list, &data->idx, |
183 | (void *) $2, NULL)); | ||
160 | $$ = list; | 184 | $$ = list; |
161 | } | 185 | } |
162 | 186 | ||
163 | event_legacy_tracepoint: | 187 | event_legacy_tracepoint: |
164 | PE_NAME ':' PE_NAME | 188 | PE_NAME ':' PE_NAME |
165 | { | 189 | { |
190 | struct parse_events_data__events *data = _data; | ||
166 | struct list_head *list = NULL; | 191 | struct list_head *list = NULL; |
167 | 192 | ||
168 | ABORT_ON(parse_events_add_tracepoint(&list, idx, $1, $3)); | 193 | ABORT_ON(parse_events_add_tracepoint(&list, &data->idx, $1, $3)); |
169 | $$ = list; | 194 | $$ = list; |
170 | } | 195 | } |
171 | 196 | ||
172 | event_legacy_numeric: | 197 | event_legacy_numeric: |
173 | PE_VALUE ':' PE_VALUE | 198 | PE_VALUE ':' PE_VALUE |
174 | { | 199 | { |
200 | struct parse_events_data__events *data = _data; | ||
175 | struct list_head *list = NULL; | 201 | struct list_head *list = NULL; |
176 | 202 | ||
177 | ABORT_ON(parse_events_add_numeric(&list, idx, $1, $3, NULL)); | 203 | ABORT_ON(parse_events_add_numeric(&list, &data->idx, $1, $3, NULL)); |
178 | $$ = list; | 204 | $$ = list; |
179 | } | 205 | } |
180 | 206 | ||
181 | event_legacy_raw: | 207 | event_legacy_raw: |
182 | PE_RAW | 208 | PE_RAW |
183 | { | 209 | { |
210 | struct parse_events_data__events *data = _data; | ||
184 | struct list_head *list = NULL; | 211 | struct list_head *list = NULL; |
185 | 212 | ||
186 | ABORT_ON(parse_events_add_numeric(&list, idx, PERF_TYPE_RAW, $1, NULL)); | 213 | ABORT_ON(parse_events_add_numeric(&list, &data->idx, |
214 | PERF_TYPE_RAW, $1, NULL)); | ||
187 | $$ = list; | 215 | $$ = list; |
188 | } | 216 | } |
189 | 217 | ||
218 | terms: event_config | ||
219 | { | ||
220 | struct parse_events_data__terms *data = _data; | ||
221 | data->terms = $1; | ||
222 | } | ||
223 | |||
190 | event_config: | 224 | event_config: |
191 | event_config ',' event_term | 225 | event_config ',' event_term |
192 | { | 226 | { |
@@ -267,8 +301,7 @@ sep_slash_dc: '/' | ':' | | |||
267 | 301 | ||
268 | %% | 302 | %% |
269 | 303 | ||
270 | void parse_events_error(struct list_head *list_all __used, | 304 | void parse_events_error(void *data __used, void *scanner __used, |
271 | int *idx __used, | ||
272 | char const *msg __used) | 305 | char const *msg __used) |
273 | { | 306 | { |
274 | } | 307 | } |
diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c index a119a5371699..74d0948ec368 100644 --- a/tools/perf/util/pmu.c +++ b/tools/perf/util/pmu.c | |||
@@ -80,6 +80,114 @@ static int pmu_format(char *name, struct list_head *format) | |||
80 | return 0; | 80 | return 0; |
81 | } | 81 | } |
82 | 82 | ||
83 | static int perf_pmu__new_alias(struct list_head *list, char *name, FILE *file) | ||
84 | { | ||
85 | struct perf_pmu__alias *alias; | ||
86 | char buf[256]; | ||
87 | int ret; | ||
88 | |||
89 | ret = fread(buf, 1, sizeof(buf), file); | ||
90 | if (ret == 0) | ||
91 | return -EINVAL; | ||
92 | buf[ret] = 0; | ||
93 | |||
94 | alias = malloc(sizeof(*alias)); | ||
95 | if (!alias) | ||
96 | return -ENOMEM; | ||
97 | |||
98 | INIT_LIST_HEAD(&alias->terms); | ||
99 | ret = parse_events_terms(&alias->terms, buf); | ||
100 | if (ret) { | ||
101 | free(alias); | ||
102 | return ret; | ||
103 | } | ||
104 | |||
105 | alias->name = strdup(name); | ||
106 | list_add_tail(&alias->list, list); | ||
107 | return 0; | ||
108 | } | ||
109 | |||
110 | /* | ||
111 | * Process all the sysfs attributes located under the directory | ||
112 | * specified in 'dir' parameter. | ||
113 | */ | ||
114 | static int pmu_aliases_parse(char *dir, struct list_head *head) | ||
115 | { | ||
116 | struct dirent *evt_ent; | ||
117 | DIR *event_dir; | ||
118 | int ret = 0; | ||
119 | |||
120 | event_dir = opendir(dir); | ||
121 | if (!event_dir) | ||
122 | return -EINVAL; | ||
123 | |||
124 | while (!ret && (evt_ent = readdir(event_dir))) { | ||
125 | char path[PATH_MAX]; | ||
126 | char *name = evt_ent->d_name; | ||
127 | FILE *file; | ||
128 | |||
129 | if (!strcmp(name, ".") || !strcmp(name, "..")) | ||
130 | continue; | ||
131 | |||
132 | snprintf(path, PATH_MAX, "%s/%s", dir, name); | ||
133 | |||
134 | ret = -EINVAL; | ||
135 | file = fopen(path, "r"); | ||
136 | if (!file) | ||
137 | break; | ||
138 | ret = perf_pmu__new_alias(head, name, file); | ||
139 | fclose(file); | ||
140 | } | ||
141 | |||
142 | closedir(event_dir); | ||
143 | return ret; | ||
144 | } | ||
145 | |||
146 | /* | ||
147 | * Reading the pmu event aliases definition, which should be located at: | ||
148 | * /sys/bus/event_source/devices/<dev>/events as sysfs group attributes. | ||
149 | */ | ||
150 | static int pmu_aliases(char *name, struct list_head *head) | ||
151 | { | ||
152 | struct stat st; | ||
153 | char path[PATH_MAX]; | ||
154 | const char *sysfs; | ||
155 | |||
156 | sysfs = sysfs_find_mountpoint(); | ||
157 | if (!sysfs) | ||
158 | return -1; | ||
159 | |||
160 | snprintf(path, PATH_MAX, | ||
161 | "%s/bus/event_source/devices/%s/events", sysfs, name); | ||
162 | |||
163 | if (stat(path, &st) < 0) | ||
164 | return -1; | ||
165 | |||
166 | if (pmu_aliases_parse(path, head)) | ||
167 | return -1; | ||
168 | |||
169 | return 0; | ||
170 | } | ||
171 | |||
172 | static int pmu_alias_terms(struct perf_pmu__alias *alias, | ||
173 | struct list_head *terms) | ||
174 | { | ||
175 | struct parse_events__term *term, *clone; | ||
176 | LIST_HEAD(list); | ||
177 | int ret; | ||
178 | |||
179 | list_for_each_entry(term, &alias->terms, list) { | ||
180 | ret = parse_events__term_clone(&clone, term); | ||
181 | if (ret) { | ||
182 | parse_events__free_terms(&list); | ||
183 | return ret; | ||
184 | } | ||
185 | list_add_tail(&clone->list, &list); | ||
186 | } | ||
187 | list_splice(&list, terms); | ||
188 | return 0; | ||
189 | } | ||
190 | |||
83 | /* | 191 | /* |
84 | * Reading/parsing the default pmu type value, which should be | 192 | * Reading/parsing the default pmu type value, which should be |
85 | * located at: | 193 | * located at: |
@@ -118,6 +226,7 @@ static struct perf_pmu *pmu_lookup(char *name) | |||
118 | { | 226 | { |
119 | struct perf_pmu *pmu; | 227 | struct perf_pmu *pmu; |
120 | LIST_HEAD(format); | 228 | LIST_HEAD(format); |
229 | LIST_HEAD(aliases); | ||
121 | __u32 type; | 230 | __u32 type; |
122 | 231 | ||
123 | /* | 232 | /* |
@@ -135,8 +244,12 @@ static struct perf_pmu *pmu_lookup(char *name) | |||
135 | if (!pmu) | 244 | if (!pmu) |
136 | return NULL; | 245 | return NULL; |
137 | 246 | ||
247 | pmu_aliases(name, &aliases); | ||
248 | |||
138 | INIT_LIST_HEAD(&pmu->format); | 249 | INIT_LIST_HEAD(&pmu->format); |
250 | INIT_LIST_HEAD(&pmu->aliases); | ||
139 | list_splice(&format, &pmu->format); | 251 | list_splice(&format, &pmu->format); |
252 | list_splice(&aliases, &pmu->aliases); | ||
140 | pmu->name = strdup(name); | 253 | pmu->name = strdup(name); |
141 | pmu->type = type; | 254 | pmu->type = type; |
142 | return pmu; | 255 | return pmu; |
@@ -279,6 +392,59 @@ int perf_pmu__config(struct perf_pmu *pmu, struct perf_event_attr *attr, | |||
279 | return pmu_config(&pmu->format, attr, head_terms); | 392 | return pmu_config(&pmu->format, attr, head_terms); |
280 | } | 393 | } |
281 | 394 | ||
395 | static struct perf_pmu__alias *pmu_find_alias(struct perf_pmu *pmu, | ||
396 | struct parse_events__term *term) | ||
397 | { | ||
398 | struct perf_pmu__alias *alias; | ||
399 | char *name; | ||
400 | |||
401 | if (parse_events__is_hardcoded_term(term)) | ||
402 | return NULL; | ||
403 | |||
404 | if (term->type_val == PARSE_EVENTS__TERM_TYPE_NUM) { | ||
405 | if (term->val.num != 1) | ||
406 | return NULL; | ||
407 | if (pmu_find_format(&pmu->format, term->config)) | ||
408 | return NULL; | ||
409 | name = term->config; | ||
410 | } else if (term->type_val == PARSE_EVENTS__TERM_TYPE_STR) { | ||
411 | if (strcasecmp(term->config, "event")) | ||
412 | return NULL; | ||
413 | name = term->val.str; | ||
414 | } else { | ||
415 | return NULL; | ||
416 | } | ||
417 | |||
418 | list_for_each_entry(alias, &pmu->aliases, list) { | ||
419 | if (!strcasecmp(alias->name, name)) | ||
420 | return alias; | ||
421 | } | ||
422 | return NULL; | ||
423 | } | ||
424 | |||
425 | /* | ||
426 | * Find alias in the terms list and replace it with the terms | ||
427 | * defined for the alias | ||
428 | */ | ||
429 | int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms) | ||
430 | { | ||
431 | struct parse_events__term *term, *h; | ||
432 | struct perf_pmu__alias *alias; | ||
433 | int ret; | ||
434 | |||
435 | list_for_each_entry_safe(term, h, head_terms, list) { | ||
436 | alias = pmu_find_alias(pmu, term); | ||
437 | if (!alias) | ||
438 | continue; | ||
439 | ret = pmu_alias_terms(alias, &term->list); | ||
440 | if (ret) | ||
441 | return ret; | ||
442 | list_del(&term->list); | ||
443 | free(term); | ||
444 | } | ||
445 | return 0; | ||
446 | } | ||
447 | |||
282 | int perf_pmu__new_format(struct list_head *list, char *name, | 448 | int perf_pmu__new_format(struct list_head *list, char *name, |
283 | int config, unsigned long *bits) | 449 | int config, unsigned long *bits) |
284 | { | 450 | { |
diff --git a/tools/perf/util/pmu.h b/tools/perf/util/pmu.h index 68c0db965e1f..535f2c5258ab 100644 --- a/tools/perf/util/pmu.h +++ b/tools/perf/util/pmu.h | |||
@@ -19,17 +19,26 @@ struct perf_pmu__format { | |||
19 | struct list_head list; | 19 | struct list_head list; |
20 | }; | 20 | }; |
21 | 21 | ||
22 | struct perf_pmu__alias { | ||
23 | char *name; | ||
24 | struct list_head terms; | ||
25 | struct list_head list; | ||
26 | }; | ||
27 | |||
22 | struct perf_pmu { | 28 | struct perf_pmu { |
23 | char *name; | 29 | char *name; |
24 | __u32 type; | 30 | __u32 type; |
25 | struct list_head format; | 31 | struct list_head format; |
32 | struct list_head aliases; | ||
26 | struct list_head list; | 33 | struct list_head list; |
27 | }; | 34 | }; |
28 | 35 | ||
29 | struct perf_pmu *perf_pmu__find(char *name); | 36 | struct perf_pmu *perf_pmu__find(char *name); |
30 | int perf_pmu__config(struct perf_pmu *pmu, struct perf_event_attr *attr, | 37 | int perf_pmu__config(struct perf_pmu *pmu, struct perf_event_attr *attr, |
31 | struct list_head *head_terms); | 38 | struct list_head *head_terms); |
32 | 39 | int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms); | |
40 | struct list_head *perf_pmu__alias(struct perf_pmu *pmu, | ||
41 | struct list_head *head_terms); | ||
33 | int perf_pmu_wrap(void); | 42 | int perf_pmu_wrap(void); |
34 | void perf_pmu_error(struct list_head *list, char *name, char const *msg); | 43 | void perf_pmu_error(struct list_head *list, char *name, char const *msg); |
35 | 44 | ||
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index febc0aeb3c66..6b305fbcc986 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c | |||
@@ -441,6 +441,16 @@ static void perf_tool__fill_defaults(struct perf_tool *tool) | |||
441 | tool->finished_round = process_finished_round_stub; | 441 | tool->finished_round = process_finished_round_stub; |
442 | } | 442 | } |
443 | } | 443 | } |
444 | |||
445 | void mem_bswap_32(void *src, int byte_size) | ||
446 | { | ||
447 | u32 *m = src; | ||
448 | while (byte_size > 0) { | ||
449 | *m = bswap_32(*m); | ||
450 | byte_size -= sizeof(u32); | ||
451 | ++m; | ||
452 | } | ||
453 | } | ||
444 | 454 | ||
445 | void mem_bswap_64(void *src, int byte_size) | 455 | void mem_bswap_64(void *src, int byte_size) |
446 | { | 456 | { |
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h index 877d78186f2c..c71a1a7b05ed 100644 --- a/tools/perf/util/session.h +++ b/tools/perf/util/session.h | |||
@@ -80,6 +80,7 @@ struct branch_info *machine__resolve_bstack(struct machine *self, | |||
80 | bool perf_session__has_traces(struct perf_session *self, const char *msg); | 80 | bool perf_session__has_traces(struct perf_session *self, const char *msg); |
81 | 81 | ||
82 | void mem_bswap_64(void *src, int byte_size); | 82 | void mem_bswap_64(void *src, int byte_size); |
83 | void mem_bswap_32(void *src, int byte_size); | ||
83 | void perf_event__attr_swap(struct perf_event_attr *attr); | 84 | void perf_event__attr_swap(struct perf_event_attr *attr); |
84 | 85 | ||
85 | int perf_session__create_kernel_maps(struct perf_session *self); | 86 | int perf_session__create_kernel_maps(struct perf_session *self); |