1 /* Some utility functions around the free running clock on ARM. The clock is 2 * 32-bits wide, but we provide 64-bit wrapper functions to make it look 3 * similar to the read_tsc functions. On hardware we could actually make use 4 * of the timer overflow counter, but emulator doesn't emulate it. */ 5 6 #include <minix/minlib.h> 7 #include <minix/sysutil.h> 8 #include <sys/errno.h> 9 #include <sys/types.h> 10 #include <lib.h> 11 #include <assert.h> 12 13 #define MICROHZ 1000000ULL /* number of micros per second */ 14 #define MICROSPERTICK(h) (MICROHZ/(h)) /* number of micros per HZ tick */ 15 16 static u64_t Hz; 17 18 int 19 micro_delay(u32_t micros) 20 { 21 struct minix_kerninfo *minix_kerninfo; 22 u64_t start, delta, delta_end; 23 24 Hz = sys_hz(); 25 minix_kerninfo = get_minix_kerninfo(); 26 27 /* Start of delay. */ 28 read_frclock_64(&start); 29 assert(minix_kerninfo->arm_frclock); 30 assert(minix_kerninfo->arm_frclock->hz); 31 delta_end = (minix_kerninfo->arm_frclock->hz * micros) / MICROHZ; 32 33 /* If we have to wait for at least one HZ tick, use the regular 34 * tickdelay first. Round downwards on purpose, so the average 35 * half-tick we wait short (depending on where in the current tick 36 * we call tickdelay). We can correct for both overhead of tickdelay 37 * itself and the short wait in the busywait later. 38 */ 39 if (micros >= MICROSPERTICK(Hz)) 40 tickdelay(micros*Hz/MICROHZ); 41 42 /* Wait (the rest) of the delay time using busywait. */ 43 do { 44 read_frclock_64(&delta); 45 } while (delta_frclock_64(start, delta) < delta_end); 46 47 48 return 0; 49 } 50 51 u32_t frclock_64_to_micros(u64_t tsc) 52 { 53 return (u32_t) 54 (tsc / (get_minix_kerninfo()->arm_frclock->hz / MICROHZ)); 55 } 56 57 void 58 read_frclock(u32_t *frclk) 59 { 60 struct minix_kerninfo *minix_kerninfo = get_minix_kerninfo(); 61 62 assert(frclk); 63 assert(minix_kerninfo->arm_frclock); 64 assert(minix_kerninfo->arm_frclock->tcrr); 65 *frclk = *(volatile u32_t *)((u8_t *) 66 minix_kerninfo->arm_frclock->tcrr); 67 } 68 69 u32_t 70 delta_frclock(u32_t base, u32_t cur) 71 { 72 u32_t delta; 73 74 if (cur < base) { 75 /* We have wrapped around, so delta is base to wrapping point 76 * plus starting point (0) to cur. This supports wrapping once 77 * only. */ 78 delta = (UINT_MAX - base) + cur; 79 } else { 80 delta = cur - base; 81 } 82 83 return delta; 84 } 85 86 void 87 read_frclock_64(u64_t *frclk) 88 { 89 read_frclock((u32_t *) frclk); 90 } 91 92 u64_t 93 delta_frclock_64(u64_t base, u64_t cur) 94 { 95 return (u64_t) delta_frclock((u32_t) base, (u32_t) cur); 96 } 97 98