1e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include <stdbool.h>
2e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include <errno.h>
3e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
4e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include <linux/perf_event.h>
5e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
6e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include "../../perf.h"
7e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include "../../util/types.h"
8e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include "../../util/debug.h"
9e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include "tsc.h"
10e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
11e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengu64 perf_time_to_tsc(u64 ns, struct perf_tsc_conversion *tc)
12e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
13e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	u64 t, quot, rem;
14e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
15e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	t = ns - tc->time_zero;
16e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	quot = t / tc->time_mult;
17e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	rem  = t % tc->time_mult;
18e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	return (quot << tc->time_shift) +
19e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	       (rem << tc->time_shift) / tc->time_mult;
20e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
21e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
22e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengu64 tsc_to_perf_time(u64 cyc, struct perf_tsc_conversion *tc)
23e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
24e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	u64 quot, rem;
25e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
26e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	quot = cyc >> tc->time_shift;
27e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	rem  = cyc & ((1 << tc->time_shift) - 1);
28e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	return tc->time_zero + quot * tc->time_mult +
29e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	       ((rem * tc->time_mult) >> tc->time_shift);
30e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
31e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
32e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengint perf_read_tsc_conversion(const struct perf_event_mmap_page *pc,
33e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			     struct perf_tsc_conversion *tc)
34e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
35e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	bool cap_user_time_zero;
36e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	u32 seq;
37e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	int i = 0;
38e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
39e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	while (1) {
40e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		seq = pc->lock;
41e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		rmb();
42e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		tc->time_mult = pc->time_mult;
43e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		tc->time_shift = pc->time_shift;
44e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		tc->time_zero = pc->time_zero;
45e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		cap_user_time_zero = pc->cap_user_time_zero;
46e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		rmb();
47e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		if (pc->lock == seq && !(seq & 1))
48e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			break;
49e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		if (++i > 10000) {
50e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			pr_debug("failed to get perf_event_mmap_page lock\n");
51e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			return -EINVAL;
52e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		}
53e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	}
54e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
55e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (!cap_user_time_zero)
56e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		return -EOPNOTSUPP;
57e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
58e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	return 0;
59e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
60