1 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> 11 12 #include "sysutil.h" 13 14 #ifndef CONFIG_MAX_CPUS 15 #define CONFIG_MAX_CPUS 1 16 #endif 17 18 #define MICROHZ 1000000 /* number of micros per second */ 19 #define MICROSPERTICK(h) (MICROHZ/(h)) /* number of micros per HZ tick */ 20 21 #define CALIBRATE \ 22 if(!calibrated) { \ 23 int r; \ 24 if((r=tsc_calibrate()) != OK) \ 25 panic("calibrate failed: %d", r); \ 26 } 27 28 static u32_t calib_mhz, Hz = 0; 29 static int calibrated = 0; 30 31 int 32 tsc_calibrate(void) 33 { 34 struct cpu_info cpu_info[CONFIG_MAX_CPUS]; 35 36 /* Get HZ. */ 37 Hz = sys_hz(); 38 39 /* Obtain CPU frequency from kernel */ 40 if (sys_getcpuinfo(&cpu_info)) { 41 printf("tsc_calibrate: cannot get cpu info\n"); 42 return -1; 43 } 44 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 48 */ 49 calib_mhz = cpu_info[0].freq; 50 calibrated = 1; 51 52 return OK; 53 } 54 55 int 56 micro_delay(u32_t micros) 57 { 58 u64_t now, end; 59 60 /* Start of delay. */ 61 read_tsc_64(&now); 62 63 CALIBRATE; 64 65 /* We have to know when to end the delay. */ 66 end = now + ((u64_t)micros * calib_mhz); 67 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. 73 */ 74 if(micros >= MICROSPERTICK(Hz)) 75 tickdelay(micros*Hz/MICROHZ); 76 77 /* Wait (the rest) of the delay time using busywait. */ 78 while(now < end) 79 read_tsc_64(&now); 80 81 return OK; 82 } 83 84 u32_t tsc_64_to_micros(u64_t tsc) 85 { 86 u64_t tmp; 87 88 CALIBRATE; 89 90 tmp = 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); 96 } 97 } 98 99 u32_t tsc_to_micros(u32_t low, u32_t high) 100 { 101 return tsc_64_to_micros(make64(low, high)); 102 } 103 104 u32_t tsc_get_khz(void) 105 { 106 CALIBRATE; 107 108 return calib_mhz * 1000; 109 } 110 111 #define frclock_64_to_micros tsc_64_to_micros 112 #define read_frclock_64 read_tsc_64 113 114 u64_t delta_frclock_64(u64_t base, u64_t cur) 115 { 116 return cur - base; 117 } 118 119