1/*
2 * Copyright 2017, Data61
3 * Commonwealth Scientific and Industrial Research Organisation (CSIRO)
4 * ABN 41 687 119 230.
5 *
6 * This software may be distributed and modified according to the terms of
7 * the BSD 2-Clause license. Note that NO WARRANTY is provided.
8 * See "LICENSE_BSD2.txt" for details.
9 *
10 * @TAG(DATA61_BSD)
11 */
12
13#include <platsupport/arch/tsc.h>
14#include <utils/time.h>
15#include <stdio.h>
16
17#define WAIT_SECONDS 2ull
18#define WAIT_NS (NS_IN_S * WAIT_SECONDS) /* 2 seconds in nano seconds to wait for */
19
20uint64_t tsc_freq_hint = 0;
21
22uint64_t tsc_calculate_frequency_hpet(const hpet_t *hpet)
23{
24    if (tsc_freq_hint) {
25        return tsc_freq_hint;
26    }
27    uint64_t tsc_start = rdtsc_pure();
28    uint64_t hpet_start = hpet_get_time(hpet);
29    /* spin until WAIT_NS has passed */
30    while (hpet_get_time(hpet) - hpet_start < WAIT_NS);
31    uint64_t tsc_end = rdtsc_pure();
32    return (tsc_end - tsc_start) / WAIT_SECONDS;
33}
34
35uint64_t tsc_calculate_frequency_pit(pit_t *pit)
36{
37    if (tsc_freq_hint) {
38        return tsc_freq_hint;
39    }
40    /* the PIT should be able to set a timeout for 50 ms */
41    uint64_t wait_ns = 50 * NS_IN_MS;
42
43    int UNUSED error = pit_set_timeout(pit, wait_ns, true);
44    assert(error == 0);
45
46    uint64_t start_time = rdtsc_pure();
47    uint64_t last_absolute = 0;
48    uint64_t total_observed = 0;
49    uint64_t time_offset = pit_get_time(pit);
50    uint64_t last_time = time_offset;
51
52    while (total_observed + last_absolute < WAIT_NS) {
53        uint64_t current_time = pit_get_time(pit);
54        if (current_time > last_time) {
55            total_observed += wait_ns;
56        }
57        last_absolute = wait_ns - current_time + time_offset;
58        last_time = current_time;
59    }
60    uint64_t end_time = rdtsc_pure();
61    /* well that was a fucking trial. Now hopefully we got something sane */
62    return (end_time - start_time) / WAIT_SECONDS;
63}
64