0038146de997883aa883a3f8a70cfacc5c54dd56
[akaros.git] / kern / arch / x86 / perfmon.c
1 /* Copyright (c) 2015 Google Inc
2  * Davide Libenzi <dlibenzi@google.com>
3  * Barret Rhoden <brho@cs.berkeley.edu>
4  * See LICENSE for details.
5  *
6  * Manages the setting and reading of hardware perf counters across all cores,
7  * including generating samples in response to counter overflow interrupts.
8  *
9  * The hardware interface is pretty straightforward - it's mostly setting and
10  * unsetting fixed and unfixed events, sometimes with interrupts and trigger
11  * counts.
12  *
13  * The 'command' to the cores is a struct perfmon_alloc.  This tells the core
14  * which event to set up (this is the perfmon_event).  The cores respond in
15  * counters[], saying which of their counters it is using for that event.  If
16  * the cores are given different alloc requests, it is possible that they might
17  * choose different counters[] for the same event.
18  *
19  * These perfmon_allocs are collected in a perfmon_session.  The session is just
20  * a bunch of allocs, which are referred to by index (the 'ped').  Currently,
21  * the session is grabbed by whoever opens the perf FD in devarch, and closed
22  * when that FD is closed.  They are 1:1 with devarch's perf_contexts.
23  *
24  * The values for the counters are extracted with perfmon_get_event_status(),
25  * which uses a struct perfmon_status to collect the results.  We pass the
26  * perfmon_alloc as part of the perfmon_status_env, since we need to tell the
27  * core which counter we're talking about.
28  *
29  * You can have multiple sessions, but if you try to install the same counter in
30  * multiple, concurrent sessions, the hardware might complain (it definitely
31  * will if it is a fixed event). */
32
33 #include <sys/types.h>
34 #include <arch/ros/msr-index.h>
35 #include <arch/ros/membar.h>
36 #include <arch/x86.h>
37 #include <arch/msr.h>
38 #include <arch/uaccess.h>
39 #include <ros/errno.h>
40 #include <assert.h>
41 #include <trap.h>
42 #include <smp.h>
43 #include <atomic.h>
44 #include <core_set.h>
45 #include <percpu.h>
46 #include <kmalloc.h>
47 #include <err.h>
48 #include <string.h>
49 #include <profiler.h>
50 #include <arch/perfmon.h>
51
52 #define FIXCNTR_NBITS 4
53 #define FIXCNTR_MASK (((uint64_t) 1 << FIXCNTR_NBITS) - 1)
54
55 struct perfmon_cpu_context {
56         spinlock_t lock;
57         struct perfmon_event counters[MAX_VAR_COUNTERS];
58         struct perfmon_event fixed_counters[MAX_FIX_COUNTERS];
59 };
60
61 struct perfmon_status_env {
62         struct perfmon_alloc *pa;
63         struct perfmon_status *pef;
64 };
65
66 static struct perfmon_cpu_caps cpu_caps;
67 static DEFINE_PERCPU(struct perfmon_cpu_context, counters_env);
68 DEFINE_PERCPU_INIT(perfmon_counters_env_init);
69
70 static void perfmon_counters_env_init(void)
71 {
72         for (int i = 0; i < num_cores; i++) {
73                 struct perfmon_cpu_context *cctx = _PERCPU_VARPTR(counters_env, i);
74
75                 spinlock_init_irqsave(&cctx->lock);
76         }
77 }
78
79 static void perfmon_read_cpu_caps(struct perfmon_cpu_caps *pcc)
80 {
81         uint32_t a, b, c, d;
82
83         cpuid(0x0a, 0, &a, &b, &c, &d);
84
85         pcc->proc_arch_events = a >> 24;
86         pcc->bits_x_counter = (a >> 16) & 0xff;
87         pcc->counters_x_proc = (a >> 8) & 0xff;
88         pcc->bits_x_fix_counter = (d >> 5) & 0xff;
89         pcc->fix_counters_x_proc = d & 0x1f;
90         pcc->perfmon_version = a & 0xff;
91 }
92
93 static void perfmon_enable_event(int idx, uint64_t event)
94 {
95         uint64_t gctrl;
96
97         /* Events need to be enabled in both MSRs */
98         write_msr(MSR_ARCH_PERFMON_EVENTSEL0 + idx, event);
99         gctrl = read_msr(MSR_CORE_PERF_GLOBAL_CTRL);
100         write_msr(MSR_CORE_PERF_GLOBAL_CTRL, gctrl | (1 << idx));
101 }
102
103 static void perfmon_disable_event(int idx)
104 {
105         uint64_t gctrl;
106
107         /* Events can be disabled in either location.  We could just clear the
108          * global ctrl, but we use the contents of EVENTSEL to say if the counter is
109          * available or not. */
110         write_msr(MSR_ARCH_PERFMON_EVENTSEL0 + idx, 0);
111         gctrl = read_msr(MSR_CORE_PERF_GLOBAL_CTRL);
112         write_msr(MSR_CORE_PERF_GLOBAL_CTRL, gctrl & ~(1 << idx));
113 }
114
115 static bool perfmon_event_available(uint32_t idx)
116 {
117         return read_msr(MSR_ARCH_PERFMON_EVENTSEL0 + idx) == 0;
118 }
119
120 /* Helper.  Given an event, a fixed counter index, and the contents of the fixed
121  * counter ctl MSR, output the value for the fixed counter ctl that will enable
122  * the event at idx. */
123 static uint64_t perfmon_apply_fixevent_mask(uint64_t event, int idx,
124                                             uint64_t base)
125 {
126         uint64_t m = 0;
127
128         if (PMEV_GET_OS(event))
129                 m |= (1 << 0);
130         if (PMEV_GET_USR(event))
131                 m |= (1 << 1);
132         if (PMEV_GET_ANYTH(event) && (cpu_caps.perfmon_version >= 3))
133                 m |= (1 << 2);
134         if (PMEV_GET_INTEN(event))
135                 m |= (1 << 3);
136         /* Enable enforcement: we need at least one bit set so that this fixed
137          * counter appears to be in use. */
138         if (PMEV_GET_EN(event) && !PMEV_GET_OS(event) && !PMEV_GET_USR(event))
139                 m |= (1 << 0) | (1 << 1);
140
141         m <<= idx * FIXCNTR_NBITS;
142         m |= base & ~(FIXCNTR_MASK << (idx * FIXCNTR_NBITS));
143
144         return m;
145 }
146
147 /* These helpers take the fxctrl_value to save on a rdmsr. */
148 static void perfmon_enable_fix_event(int idx, uint64_t event,
149                                      uint64_t fxctrl_value)
150 {
151         uint64_t gctrl, fx;
152
153         /* Enable in both locations: the bits in FIXED and the bit in GLOBAL. */
154         fx = perfmon_apply_fixevent_mask(event, idx, fxctrl_value);
155         write_msr(MSR_CORE_PERF_FIXED_CTR_CTRL, fx);
156         gctrl = read_msr(MSR_CORE_PERF_GLOBAL_CTRL);
157         write_msr(MSR_CORE_PERF_GLOBAL_CTRL, gctrl | ((uint64_t) 1 << (32 + idx)));
158 }
159
160 static void perfmon_disable_fix_event(int idx, uint64_t fxctrl_value)
161 {
162         uint64_t gctrl;
163
164         /* Events can be disabled in either location.  We could just clear the
165          * global ctrl, but we use the bits of fxctlr to say if the counter is
166          * available or not. */
167         write_msr(MSR_CORE_PERF_FIXED_CTR_CTRL,
168                   fxctrl_value & ~(FIXCNTR_MASK << (idx * FIXCNTR_NBITS)));
169         gctrl = read_msr(MSR_CORE_PERF_GLOBAL_CTRL);
170         write_msr(MSR_CORE_PERF_GLOBAL_CTRL, gctrl & ~((uint64_t) 1 << (32 + idx)));
171 }
172
173 static bool perfmon_fix_event_available(uint32_t idx, uint64_t fxctrl_value)
174 {
175         return (fxctrl_value & (FIXCNTR_MASK << (idx * FIXCNTR_NBITS))) == 0;
176 }
177
178 /* Helper to set a fixed perfcounter to trigger/overflow after count events.
179  * Anytime you set a perfcounter to something non-zero, you need to use this
180  * helper. */
181 static void perfmon_set_fixed_trigger(unsigned int idx, uint64_t count)
182 {
183         int64_t write_val = -(int64_t)count;
184
185         write_val &= (1ULL << cpu_caps.bits_x_fix_counter) - 1;
186         write_msr(MSR_CORE_PERF_FIXED_CTR0 + idx, write_val);
187 }
188
189 /* Helper to set a regular perfcounter to trigger/overflow after count events.
190  * Anytime you set a perfcounter to something non-zero, you ought to use this
191  * helper. */
192 static void perfmon_set_unfixed_trigger(unsigned int idx, uint64_t count)
193 {
194         int64_t write_val = -(int64_t)count;
195
196         write_val &= (1ULL << cpu_caps.bits_x_counter) - 1;
197         write_msr(MSR_IA32_PERFCTR0 + idx, write_val);
198 }
199
200 /* Helper: sets errno/errstr based on the error code returned from the core.  We
201  * don't have a great way to get errors back from smp_do_in_cores() commands.
202  * We use negative counter values (e.g. i = -EBUSY) to signal an error of a
203  * certain type.  This converts that to something useful for userspace. */
204 static void perfmon_convert_error(int err_code, int core_id)
205 {
206         switch (err_code) {
207         case EBUSY:
208                 set_error(err_code, "Fixed perf counter is busy on core %d", core_id);
209                 break;
210         case ENOSPC:
211                 set_error(err_code, "Perf counter idx out of range on core %d",
212                           core_id);
213                 break;
214         case ENOENT:
215                 set_error(err_code, "Perf counter not set on core %d", core_id);
216                 break;
217         default:
218                 set_error(err_code, "Unknown perf counter error on core %d", core_id);
219                 break;
220         };
221 }
222
223 static void perfmon_do_cores_alloc(void *opaque)
224 {
225         struct perfmon_alloc *pa = (struct perfmon_alloc *) opaque;
226         struct perfmon_cpu_context *cctx = PERCPU_VARPTR(counters_env);
227         int i;
228         struct perfmon_event *pev;
229
230         spin_lock_irqsave(&cctx->lock);
231         if (perfmon_is_fixed_event(&pa->ev)) {
232                 uint64_t fxctrl_value = read_msr(MSR_CORE_PERF_FIXED_CTR_CTRL);
233
234                 i = PMEV_GET_EVENT(pa->ev.event);
235                 if (i >= (int) cpu_caps.fix_counters_x_proc) {
236                         i = -ENOSPC;
237                 } else if (!perfmon_fix_event_available(i, fxctrl_value)) {
238                         i = -EBUSY;
239                 } else {
240                         /* Keep a copy of pa->ev for later.  pa is read-only and shared. */
241                         cctx->fixed_counters[i] = pa->ev;
242                         pev = &cctx->fixed_counters[i];
243                         if (PMEV_GET_INTEN(pev->event))
244                                 perfmon_set_fixed_trigger(i, pev->trigger_count);
245                         else
246                                 write_msr(MSR_CORE_PERF_FIXED_CTR0 + i, 0);
247                         write_msr(MSR_CORE_PERF_GLOBAL_OVF_CTRL, 1ULL << (32 + i));
248                         perfmon_enable_fix_event(i, pev->event, fxctrl_value);
249                 }
250         } else {
251                 for (i = 0; i < (int) cpu_caps.counters_x_proc; i++) {
252                         if (cctx->counters[i].event == 0) {
253                                 /* kernel bug if the MSRs don't agree with our bookkeeping */
254                                 assert(perfmon_event_available(i));
255                                 break;
256                         }
257                 }
258                 if (i < (int) cpu_caps.counters_x_proc) {
259                         cctx->counters[i] = pa->ev;
260                         pev = &cctx->counters[i];
261                         if (PMEV_GET_INTEN(pev->event))
262                                 perfmon_set_unfixed_trigger(i, pev->trigger_count);
263                         else
264                                 write_msr(MSR_IA32_PERFCTR0 + i, 0);
265                         write_msr(MSR_CORE_PERF_GLOBAL_OVF_CTRL, 1ULL << i);
266                         perfmon_enable_event(i, pev->event);
267                 } else {
268                         i = -ENOSPC;
269                 }
270         }
271         spin_unlock_irqsave(&cctx->lock);
272
273         pa->cores_counters[core_id()] = (counter_t) i;
274 }
275
276 static void perfmon_do_cores_free(void *opaque)
277 {
278         struct perfmon_alloc *pa = (struct perfmon_alloc *) opaque;
279         struct perfmon_cpu_context *cctx = PERCPU_VARPTR(counters_env);
280         int err = 0, coreno = core_id();
281         counter_t ccno = pa->cores_counters[coreno];
282
283         spin_lock_irqsave(&cctx->lock);
284         if (perfmon_is_fixed_event(&pa->ev)) {
285                 uint64_t fxctrl_value = read_msr(MSR_CORE_PERF_FIXED_CTR_CTRL);
286
287                 if ((ccno >= cpu_caps.fix_counters_x_proc) ||
288                     perfmon_fix_event_available(ccno, fxctrl_value)) {
289                         err = -ENOENT;
290                 } else {
291                         perfmon_init_event(&cctx->fixed_counters[ccno]);
292                         perfmon_disable_fix_event((int) ccno, fxctrl_value);
293                         write_msr(MSR_CORE_PERF_FIXED_CTR0 + ccno, 0);
294                 }
295         } else {
296                 if (ccno < (int) cpu_caps.counters_x_proc) {
297                         perfmon_init_event(&cctx->counters[ccno]);
298                         perfmon_disable_event((int) ccno);
299                         write_msr(MSR_IA32_PERFCTR0 + ccno, 0);
300                 } else {
301                         err = -ENOENT;
302                 }
303         }
304         spin_unlock_irqsave(&cctx->lock);
305
306         pa->cores_counters[coreno] = (counter_t) err;
307 }
308
309 /* Helper: Reads a fixed counter's value.  Returns the max amount possible if
310  * the counter overflowed. */
311 static uint64_t perfmon_read_fixed_counter(int ccno)
312 {
313         uint64_t overflow_status = read_msr(MSR_CORE_PERF_GLOBAL_STATUS);
314
315         if (overflow_status & (1ULL << (32 + ccno)))
316                 return (1ULL << cpu_caps.bits_x_fix_counter) - 1;
317         else
318                 return read_msr(MSR_CORE_PERF_FIXED_CTR0 + ccno);
319 }
320
321 /* Helper: Reads an unfixed counter's value.  Returns the max amount possible if
322  * the counter overflowed. */
323 static uint64_t perfmon_read_unfixed_counter(int ccno)
324 {
325         uint64_t overflow_status = read_msr(MSR_CORE_PERF_GLOBAL_STATUS);
326
327         if (overflow_status & (1ULL << ccno))
328                 return (1ULL << cpu_caps.bits_x_counter) - 1;
329         else
330                 return read_msr(MSR_IA32_PERFCTR0 + ccno);
331 }
332
333 static void perfmon_do_cores_status(void *opaque)
334 {
335         struct perfmon_status_env *env = (struct perfmon_status_env *) opaque;
336         struct perfmon_cpu_context *cctx = PERCPU_VARPTR(counters_env);
337         int coreno = core_id();
338         counter_t ccno = env->pa->cores_counters[coreno];
339
340         spin_lock_irqsave(&cctx->lock);
341         if (perfmon_is_fixed_event(&env->pa->ev))
342                 env->pef->cores_values[coreno] = perfmon_read_fixed_counter(ccno);
343         else
344                 env->pef->cores_values[coreno] = perfmon_read_unfixed_counter(ccno);
345         spin_unlock_irqsave(&cctx->lock);
346 }
347
348 static void perfmon_setup_alloc_core_set(const struct perfmon_alloc *pa,
349                                          struct core_set *cset)
350 {
351         int i;
352
353         core_set_init(cset);
354         for (i = 0; i < num_cores; i++) {
355                 if (pa->cores_counters[i] >= 0)
356                         core_set_setcpu(cset, i);
357         }
358 }
359
360 static void perfmon_cleanup_cores_alloc(struct perfmon_alloc *pa)
361 {
362         struct core_set cset;
363
364         perfmon_setup_alloc_core_set(pa, &cset);
365         smp_do_in_cores(&cset, perfmon_do_cores_free, pa);
366 }
367
368 static void perfmon_free_alloc(struct perfmon_alloc *pa)
369 {
370         kfree(pa);
371 }
372
373 static void perfmon_destroy_alloc(struct perfmon_alloc *pa)
374 {
375         perfmon_cleanup_cores_alloc(pa);
376         perfmon_free_alloc(pa);
377 }
378
379 static struct perfmon_alloc *perfmon_create_alloc(const struct perfmon_event *pev)
380 {
381         int i;
382         struct perfmon_alloc *pa = kzmalloc(sizeof(struct perfmon_alloc) +
383                                                 num_cores * sizeof(counter_t),
384                                             MEM_WAIT);
385
386         pa->ev = *pev;
387         for (i = 0; i < num_cores; i++)
388                 pa->cores_counters[i] = INVALID_COUNTER;
389
390         return pa;
391 }
392
393 static struct perfmon_status *perfmon_status_alloc(void)
394 {
395         struct perfmon_status *pef = kzmalloc(sizeof(struct perfmon_status) +
396                                                   num_cores * sizeof(uint64_t),
397                                               MEM_WAIT);
398
399         return pef;
400 }
401
402 static void perfmon_arm_irq(void)
403 {
404         apicrput(MSR_LAPIC_LVT_PERFMON, IdtLAPIC_PCINT);
405 }
406
407 bool perfmon_supported(void)
408 {
409         return cpu_caps.perfmon_version >= 2;
410 }
411
412 void perfmon_global_init(void)
413 {
414         perfmon_read_cpu_caps(&cpu_caps);
415 }
416
417 void perfmon_pcpu_init(void)
418 {
419         int i;
420
421         if (!perfmon_supported())
422                 return;
423         /* Enable user level access to the performance counters */
424         lcr4(rcr4() | CR4_PCE);
425
426         /* Reset all the counters and selectors to zero.
427          */
428         write_msr(MSR_CORE_PERF_GLOBAL_CTRL, 0);
429         for (i = 0; i < (int) cpu_caps.counters_x_proc; i++) {
430                 write_msr(MSR_ARCH_PERFMON_EVENTSEL0 + i, 0);
431                 write_msr(MSR_IA32_PERFCTR0 + i, 0);
432         }
433         write_msr(MSR_CORE_PERF_FIXED_CTR_CTRL, 0);
434         for (i = 0; i < (int) cpu_caps.fix_counters_x_proc; i++)
435                 write_msr(MSR_CORE_PERF_FIXED_CTR0 + i, 0);
436
437         perfmon_arm_irq();
438 }
439
440 static uint64_t perfmon_make_sample_event(const struct perfmon_event *pev)
441 {
442         return pev->user_data;
443 }
444
445 static void profiler_add_hw_sample(struct hw_trapframe *hw_tf, uint64_t info)
446 {
447         #define PROFILER_BT_DEPTH 16
448         uintptr_t pc_list[PROFILER_BT_DEPTH];
449         size_t n;
450         uintptr_t pc = get_hwtf_pc(hw_tf);
451         uintptr_t fp = get_hwtf_fp(hw_tf);
452
453         if (in_kernel(hw_tf)) {
454                 n = backtrace_list(pc, fp, pc_list, PROFILER_BT_DEPTH);
455                 profiler_push_kernel_backtrace(pc_list, n, info);
456         } else {
457                 n = backtrace_user_list(pc, fp, pc_list, PROFILER_BT_DEPTH);
458                 profiler_push_user_backtrace(pc_list, n, info);
459         }
460 }
461
462 void perfmon_interrupt(struct hw_trapframe *hw_tf, void *data)
463 {
464         int i;
465         struct perfmon_cpu_context *cctx = PERCPU_VARPTR(counters_env);
466         uint64_t gctrl, status;
467
468         spin_lock_irqsave(&cctx->lock);
469         /* We need to save the global control status, because we need to disable
470          * counters in order to be able to reset their values.
471          * We will restore the global control status on exit.
472          */
473         status = read_msr(MSR_CORE_PERF_GLOBAL_STATUS);
474         gctrl = read_msr(MSR_CORE_PERF_GLOBAL_CTRL);
475         write_msr(MSR_CORE_PERF_GLOBAL_CTRL, 0);
476         for (i = 0; i < (int) cpu_caps.counters_x_proc; i++) {
477                 if (status & ((uint64_t) 1 << i)) {
478                         if (cctx->counters[i].event) {
479                                 profiler_add_hw_sample(
480                                     hw_tf, perfmon_make_sample_event(cctx->counters + i));
481                                 perfmon_set_unfixed_trigger(i, cctx->counters[i].trigger_count);
482                         }
483                 }
484         }
485         for (i = 0; i < (int) cpu_caps.fix_counters_x_proc; i++) {
486                 if (status & ((uint64_t) 1 << (32 + i))) {
487                         if (cctx->fixed_counters[i].event) {
488                                 profiler_add_hw_sample(
489                                     hw_tf, perfmon_make_sample_event(cctx->fixed_counters + i));
490                                 perfmon_set_fixed_trigger(i,
491                                         cctx->fixed_counters[i].trigger_count);
492                         }
493                 }
494         }
495         write_msr(MSR_CORE_PERF_GLOBAL_OVF_CTRL, status);
496         write_msr(MSR_CORE_PERF_GLOBAL_CTRL, gctrl);
497         spin_unlock_irqsave(&cctx->lock);
498
499         /* We need to re-arm the IRQ as the PFM IRQ gets masked on trigger.
500          * Note that KVM and real HW seems to be doing two different things WRT
501          * re-arming the IRQ. KVM re-arms does not mask the IRQ, while real HW does.
502          */
503         perfmon_arm_irq();
504 }
505
506 void perfmon_get_cpu_caps(struct perfmon_cpu_caps *pcc)
507 {
508         memcpy(pcc, &cpu_caps, sizeof(*pcc));
509 }
510
511 static int perfmon_install_session_alloc(struct perfmon_session *ps,
512                                          struct perfmon_alloc *pa)
513 {
514         qlock(&ps->qlock);
515         for (int i = 0; i < ARRAY_SIZE(ps->allocs); i++) {
516                 if (!ps->allocs[i]) {
517                         ps->allocs[i] = pa;
518                         qunlock(&ps->qlock);
519                         return i;
520                 }
521         }
522         qunlock(&ps->qlock);
523         error(ENFILE, "Too many perf allocs in the session");
524 }
525
526 int perfmon_open_event(const struct core_set *cset, struct perfmon_session *ps,
527                        const struct perfmon_event *pev)
528 {
529         ERRSTACK(1);
530         int i;
531         struct perfmon_alloc *pa = perfmon_create_alloc(pev);
532
533         if (waserror()) {
534                 perfmon_destroy_alloc(pa);
535                 nexterror();
536         }
537         /* Ensure we're turning on the event.  The user could have forgotten to set
538          * it.  Our tracking of whether or not a counter is in use depends on it
539          * being enabled, or at least that some bit is set. */
540         PMEV_SET_EN(pa->ev.event, 1);
541         smp_do_in_cores(cset, perfmon_do_cores_alloc, pa);
542
543         for (i = 0; i < num_cores; i++) {
544                 if (core_set_getcpu(cset, i)) {
545                         counter_t ccno = pa->cores_counters[i];
546
547                         if (unlikely(ccno < 0)) {
548                                 perfmon_destroy_alloc(pa);
549                                 perfmon_convert_error(-(int)ccno, i);
550                                 return -1;
551                         }
552                 }
553         }
554         /* The perfmon_alloc data structure will not be visible to userspace,
555          * until the perfmon_install_session_alloc() completes, and at that
556          * time the smp_do_in_cores(perfmon_do_cores_alloc) will have run on
557          * all cores.
558          * The perfmon_alloc data structure will never be changed once published.
559          */
560         i = perfmon_install_session_alloc(ps, pa);
561         poperror();
562
563         return i;
564 }
565
566 /* Helper, looks up a pa, given ped.  Hold the qlock. */
567 static struct perfmon_alloc *__lookup_pa(struct perfmon_session *ps, int ped)
568 {
569         struct perfmon_alloc *pa;
570
571         if (unlikely((ped < 0) || (ped >= ARRAY_SIZE(ps->allocs))))
572                 error(EBADFD, "Perf event %d out of range", ped);
573         pa = ps->allocs[ped];
574         if (!pa)
575                 error(ENOENT, "No perf alloc for event %d", ped);
576         return pa;
577 }
578
579 void perfmon_close_event(struct perfmon_session *ps, int ped)
580 {
581         ERRSTACK(1);
582         struct perfmon_alloc *pa;
583
584         qlock(&ps->qlock);
585         if (waserror()) {
586                 qunlock(&ps->qlock);
587                 nexterror();
588         };
589         /* lookup does the error checking */
590         pa = __lookup_pa(ps, ped);
591         ps->allocs[ped] = NULL;
592         poperror();
593         qunlock(&ps->qlock);
594         perfmon_destroy_alloc(pa);
595 }
596
597 /* Fetches the status (i.e. PMU counters) of event ped from all applicable
598  * cores.  Returns a perfmon_status, which the caller should free. */
599 struct perfmon_status *perfmon_get_event_status(struct perfmon_session *ps,
600                                                 int ped)
601 {
602         ERRSTACK(1);
603         struct core_set cset;
604         struct perfmon_status_env env;
605
606         /* qlock keeps the PA alive.  We don't want to spin, since the spinners
607          * might prevent the smp_do_in_cores(), resulting in a deadlock. */
608         qlock(&ps->qlock);
609         if (waserror()) {
610                 qunlock(&ps->qlock);
611                 nexterror();
612         };
613         env.pa = __lookup_pa(ps, ped);
614         env.pef = perfmon_status_alloc();
615
616         perfmon_setup_alloc_core_set(env.pa, &cset);
617         smp_do_in_cores(&cset, perfmon_do_cores_status, &env);
618
619         poperror();
620         qunlock(&ps->qlock);
621
622         return env.pef;
623 }
624
625 void perfmon_free_event_status(struct perfmon_status *pef)
626 {
627         kfree(pef);
628 }
629
630 struct perfmon_session *perfmon_create_session(void)
631 {
632         struct perfmon_session *ps = kzmalloc(sizeof(struct perfmon_session),
633                                               MEM_WAIT);
634
635         qlock_init(&ps->qlock);
636         return ps;
637 }
638
639 void perfmon_close_session(struct perfmon_session *ps)
640 {
641         struct perfmon_alloc *pa;
642
643         for (int i = 0; i < ARRAY_SIZE(ps->allocs); i++) {
644                 pa = ps->allocs[i];
645                 if (pa)
646                         perfmon_destroy_alloc(pa);
647         }
648         kfree(ps);
649 }