VM: full munmap
[minix.git] / lib / libsys / tsc_util.c
blobd6dc1aff8d01d7654b2fe4fe6bf94045c45b7a7a
2 #include <stdio.h>
3 #include <time.h>
4 #include <sys/times.h>
5 #include <sys/types.h>
6 #include <minix/u64.h>
7 #include <minix/config.h>
8 #include <minix/const.h>
9 #include <minix/minlib.h>
10 #include <machine/archtypes.h>
12 #include "sysutil.h"
14 #ifndef CONFIG_MAX_CPUS
15 #define CONFIG_MAX_CPUS 1
16 #endif
18 #define MICROHZ 1000000 /* number of micros per second */
19 #define MICROSPERTICK(h) (MICROHZ/(h)) /* number of micros per HZ tick */
21 #define CALIBRATE \
22 if(!calibrated) { \
23 int r; \
24 if((r=tsc_calibrate()) != OK) \
25 panic("calibrate failed: %d", r); \
28 static u32_t calib_mhz, Hz = 0;
29 static int calibrated = 0;
31 int
32 tsc_calibrate(void)
34 struct cpu_info cpu_info[CONFIG_MAX_CPUS];
36 /* Get HZ. */
37 Hz = sys_hz();
39 /* Obtain CPU frequency from kernel */
40 if (sys_getcpuinfo(&cpu_info)) {
41 printf("tsc_calibrate: cannot get cpu info\n");
42 return -1;
45 /* For now, use the frequency of the first CPU; everything here will
46 * break down in case we get scheduled on multiple CPUs with different
47 * frequencies regardless
49 calib_mhz = cpu_info[0].freq;
50 calibrated = 1;
52 return OK;
55 int
56 micro_delay(u32_t micros)
58 u64_t now, end;
60 /* Start of delay. */
61 read_tsc_64(&now);
63 CALIBRATE;
65 /* We have to know when to end the delay. */
66 end = add64(now, mul64u(micros, calib_mhz));
68 /* If we have to wait for at least one HZ tick, use the regular
69 * tickdelay first. Round downwards on purpose, so the average
70 * half-tick we wait short (depending on where in the current tick
71 * we call tickdelay). We can correct for both overhead of tickdelay
72 * itself and the short wait in the busywait later.
74 if(micros >= MICROSPERTICK(Hz))
75 tickdelay(micros*Hz/MICROHZ);
77 /* Wait (the rest) of the delay time using busywait. */
78 while(cmp64(now, end) < 0)
79 read_tsc_64(&now);
81 return OK;
84 u32_t tsc_64_to_micros(u64_t tsc)
86 u64_t tmp;
88 CALIBRATE;
90 tmp = div64u64(tsc, calib_mhz);
91 if (ex64hi(tmp)) {
92 printf("tsc_64_to_micros: more than 2^32ms\n");
93 return ~0UL;
94 } else {
95 return ex64lo(tmp);
99 u32_t tsc_to_micros(u32_t low, u32_t high)
101 return tsc_64_to_micros(make64(low, high));
104 u32_t tsc_get_khz(void)
106 CALIBRATE;
108 return calib_mhz * 1000;