1 /*
2 * Copyright (C) 2021 Intel Corporation.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7 #include <types.h>
8 #include <util.h>
9 #include <asm/cpuid.h>
10 #include <asm/cpu_caps.h>
11 #include <asm/io.h>
12 #include <asm/tsc.h>
13 #include <asm/cpu.h>
14 #include <logmsg.h>
15 #include <acpi.h>
16
17 #define CAL_MS 10U
18
19 #define HPET_PERIOD 0x004U
20 #define HPET_CFG 0x010U
21 #define HPET_COUNTER 0x0F0U
22
23 #define HPET_CFG_ENABLE 0x001UL
24
25 static uint32_t tsc_khz;
26 static void *hpet_hva;
27
pit_calibrate_tsc(uint32_t cal_ms_arg)28 static uint64_t pit_calibrate_tsc(uint32_t cal_ms_arg)
29 {
30 #define PIT_TICK_RATE 1193182U
31 #define PIT_TARGET 0x3FFFU
32 #define PIT_MAX_COUNT 0xFFFFU
33
34 uint32_t cal_ms = cal_ms_arg;
35 uint32_t initial_pit;
36 uint16_t current_pit;
37 uint32_t max_cal_ms;
38 uint64_t current_tsc;
39 uint8_t initial_pit_high, initial_pit_low;
40
41 max_cal_ms = ((PIT_MAX_COUNT - PIT_TARGET) * 1000U) / PIT_TICK_RATE;
42 cal_ms = min(cal_ms, max_cal_ms);
43
44 /* Assume the 8254 delivers 18.2 ticks per second when 16 bits fully
45 * wrap. This is about 1.193MHz or a clock period of 0.8384uSec
46 */
47 initial_pit = (cal_ms * PIT_TICK_RATE) / 1000U;
48 initial_pit += PIT_TARGET;
49 initial_pit_high = (uint8_t)(initial_pit >> 8U);
50 initial_pit_low = (uint8_t)initial_pit;
51
52 /* Port 0x43 ==> Control word write; Data 0x30 ==> Select Counter 0,
53 * Read/Write least significant byte first, mode 0, 16 bits.
54 */
55
56 pio_write8(0x30U, 0x43U);
57 pio_write8(initial_pit_low, 0x40U); /* Write LSB */
58 pio_write8(initial_pit_high, 0x40U); /* Write MSB */
59
60 current_tsc = rdtsc();
61
62 do {
63 /* Port 0x43 ==> Control word write; 0x00 ==> Select
64 * Counter 0, Counter Latch Command, Mode 0; 16 bits
65 */
66 pio_write8(0x00U, 0x43U);
67
68 current_pit = (uint16_t)pio_read8(0x40U); /* Read LSB */
69 current_pit |= (uint16_t)pio_read8(0x40U) << 8U; /* Read MSB */
70 /* Let the counter count down to PIT_TARGET */
71 } while (current_pit > PIT_TARGET);
72
73 current_tsc = rdtsc() - current_tsc;
74
75 return (current_tsc / cal_ms) * 1000U;
76 }
77
hpet_init(void)78 void hpet_init(void)
79 {
80 uint64_t cfg;
81
82 hpet_hva = parse_hpet();
83 if (hpet_hva != NULL) {
84 cfg = mmio_read64(hpet_hva + HPET_CFG);
85 if ((cfg & HPET_CFG_ENABLE) == 0UL) {
86 cfg |= HPET_CFG_ENABLE;
87 mmio_write64(cfg, hpet_hva + HPET_CFG);
88 }
89 }
90 }
91
is_hpet_capable(void)92 static inline bool is_hpet_capable(void)
93 {
94 return (hpet_hva != NULL);
95 }
96
hpet_read(uint32_t offset)97 static inline uint32_t hpet_read(uint32_t offset)
98 {
99 return mmio_read32(hpet_hva + offset);
100 }
101
tsc_read_hpet(uint64_t * p)102 static inline uint64_t tsc_read_hpet(uint64_t *p)
103 {
104 uint64_t current_tsc;
105
106 /* read hpet first */
107 *p = hpet_read(HPET_COUNTER);
108 current_tsc = rdtsc();
109
110 return current_tsc;
111 }
112
hpet_calibrate_tsc(uint32_t cal_ms_arg)113 static uint64_t hpet_calibrate_tsc(uint32_t cal_ms_arg)
114 {
115 uint64_t tsc1, tsc2, hpet1, hpet2;
116 uint64_t delta_tsc, delta_fs;
117 uint64_t rflags, tsc_khz;
118
119 CPU_INT_ALL_DISABLE(&rflags);
120 tsc1 = tsc_read_hpet(&hpet1);
121 pit_calibrate_tsc(cal_ms_arg);
122 tsc2 = tsc_read_hpet(&hpet2);
123 CPU_INT_ALL_RESTORE(rflags);
124
125 /* in case counter wrap happened in the low 32 bits */
126 if (hpet2 <= hpet1) {
127 hpet2 |= (1UL << 32U);
128 }
129 delta_fs = (hpet2 - hpet1) * hpet_read(HPET_PERIOD);
130 delta_tsc = tsc2 - tsc1;
131 /*
132 * FS_PER_S = 10 ^ 15
133 *
134 * tsc_khz = delta_tsc / (delta_fs / FS_PER_S) / 1000UL;
135 * = delta_tsc / delta_fs * (10 ^ 12)
136 * = (delta_tsc * (10 ^ 6)) / (delta_fs / (10 ^ 6))
137 */
138 tsc_khz = (delta_tsc * 1000000UL) / (delta_fs / 1000000UL);
139 return tsc_khz * 1000U;
140 }
141
pit_hpet_calibrate_tsc(uint32_t cal_ms_arg,uint64_t tsc_ref_hz)142 static uint64_t pit_hpet_calibrate_tsc(uint32_t cal_ms_arg, uint64_t tsc_ref_hz)
143 {
144 uint64_t tsc_hz, delta;
145
146 if (is_hpet_capable()) {
147 tsc_hz = hpet_calibrate_tsc(cal_ms_arg);
148 } else {
149 tsc_hz = pit_calibrate_tsc(cal_ms_arg);
150 }
151
152 if (tsc_ref_hz != 0UL) {
153 delta = (tsc_hz * 100UL) / tsc_ref_hz;
154 if ((delta < 95UL) || (delta > 105UL)) {
155 tsc_hz = tsc_ref_hz;
156 }
157 }
158
159 return tsc_hz;
160 }
161
162 /*
163 * Determine TSC frequency via CPUID 0x15.
164 */
native_calculate_tsc_cpuid_0x15(void)165 static uint64_t native_calculate_tsc_cpuid_0x15(void)
166 {
167 uint64_t tsc_hz = 0UL;
168 const struct cpuinfo_x86 *cpu_info = get_pcpu_info();
169
170 if (cpu_info->cpuid_level >= 0x15U) {
171 uint32_t eax_denominator, ebx_numerator, ecx_hz, reserved;
172
173 cpuid_subleaf(0x15U, 0x0U, &eax_denominator, &ebx_numerator,
174 &ecx_hz, &reserved);
175
176 if ((eax_denominator != 0U) && (ebx_numerator != 0U)) {
177 tsc_hz = ((uint64_t) ecx_hz *
178 ebx_numerator) / eax_denominator;
179 }
180 }
181
182 return tsc_hz;
183 }
184
185 /*
186 * Determine TSC frequency via CPUID 0x16.
187 */
native_calculate_tsc_cpuid_0x16(void)188 static uint64_t native_calculate_tsc_cpuid_0x16(void)
189 {
190 uint64_t tsc_hz = 0UL;
191 const struct cpuinfo_x86 *cpu_info = get_pcpu_info();
192
193 if (cpu_info->cpuid_level >= 0x16U) {
194 uint32_t eax_base_mhz, ebx_max_mhz, ecx_bus_mhz, edx;
195
196 cpuid_subleaf(0x16U, 0x0U, &eax_base_mhz, &ebx_max_mhz, &ecx_bus_mhz, &edx);
197 tsc_hz = (uint64_t) eax_base_mhz * 1000000U;
198 }
199
200 return tsc_hz;
201 }
202
calibrate_tsc(void)203 void calibrate_tsc(void)
204 {
205 uint64_t tsc_hz;
206
207 tsc_hz = native_calculate_tsc_cpuid_0x15();
208 if (tsc_hz == 0UL) {
209 tsc_hz = pit_hpet_calibrate_tsc(CAL_MS, native_calculate_tsc_cpuid_0x16());
210 }
211 tsc_khz = (uint32_t)(tsc_hz / 1000UL);
212 pr_acrnlog("%s: tsc_khz = %ld", __func__, tsc_khz);
213 }
214
get_tsc_khz(void)215 uint32_t get_tsc_khz(void)
216 {
217 return tsc_khz;
218 }
219
220 /* external API */
221
cpu_ticks(void)222 uint64_t cpu_ticks(void)
223 {
224 return rdtsc();
225 }
226
cpu_tickrate(void)227 uint32_t cpu_tickrate(void)
228 {
229 return tsc_khz;
230 }
231