diff --git a/include/minix/sysutil.h b/include/minix/sysutil.h index 56a6d7952..426e5a1b8 100644 --- a/include/minix/sysutil.h +++ b/include/minix/sysutil.h @@ -62,11 +62,12 @@ u32_t tsc_to_micros(u32_t low, u32_t high); u32_t tsc_get_khz(void); u32_t micros_to_ticks(u32_t micros); #if defined(__arm__) -u32_t read_frclock(void); +void read_frclock(u32_t *frclk); u32_t delta_frclock(u32_t base, u32_t cur); -u64_t read_frclock_64(void); -u64_t delta_frclock_64(u64_t base, u64_t cur); #endif +void read_frclock_64(u64_t *frclk); +u64_t delta_frclock_64(u64_t base, u64_t cur); +u32_t frclock_64_to_micros(u64_t tsc); void ser_putc(char c); void get_randomness(struct k_randomness *, int); u32_t sqrt_approx(u32_t); diff --git a/lib/libsys/arch/earm/frclock_util.c b/lib/libsys/arch/earm/frclock_util.c index 8d81e7857..574bb029a 100644 --- a/lib/libsys/arch/earm/frclock_util.c +++ b/lib/libsys/arch/earm/frclock_util.c @@ -9,7 +9,7 @@ #include #include #include - +#include static u64_t calib_hz = 1625000, Hz; #define MICROHZ 1000000ULL /* number of micros per second */ @@ -23,7 +23,7 @@ micro_delay(u32_t micros) Hz = sys_hz(); /* Start of delay. */ - start = read_frclock_64(); + read_frclock_64(&start); delta_end = (calib_hz * micros) / MICROHZ; /* If we have to wait for at least one HZ tick, use the regular @@ -37,7 +37,7 @@ micro_delay(u32_t micros) /* Wait (the rest) of the delay time using busywait. */ do { - delta = read_frclock_64(); + read_frclock_64(&delta); } while (delta_frclock_64(start, delta) < delta_end); @@ -46,16 +46,18 @@ micro_delay(u32_t micros) u32_t frclock_64_to_micros(u64_t tsc) { - return (u32_t) tsc / calib_hz; + return (u32_t) tsc / (calib_hz / MICROHZ); } -u32_t -read_frclock(void) +void +read_frclock(u32_t *frclk) { extern struct minix_kerninfo *_minix_kerninfo; volatile u32_t *frclock; + + assert(frclk); frclock = (u32_t *)((u8_t *) _minix_kerninfo->minix_frclock+OMAP3_TCRR); - return (u64_t) *frclock; + *frclk = *frclock; } u32_t @@ -75,15 +77,15 @@ delta_frclock(u32_t base, u32_t cur) return delta; } -u64_t -read_frclock_64(void) +void +read_frclock_64(u64_t *frclk) { - return (u64_t) read_frclock(); + read_frclock((u32_t *) frclk); } u64_t delta_frclock_64(u64_t base, u64_t cur) { - return delta_frclock((u32_t) base, (u32_t) cur); + return (u64_t) delta_frclock((u32_t) base, (u32_t) cur); } diff --git a/lib/libsys/arch/earm/spin.c b/lib/libsys/arch/earm/spin.c index 1033a2f8f..3e2115f03 100644 --- a/lib/libsys/arch/earm/spin.c +++ b/lib/libsys/arch/earm/spin.c @@ -55,11 +55,11 @@ int spin_check(spin_t *s) case STATE_BASE_TS: s->s_state = STATE_TS; - s->s_base_tsc = read_frclock_64(); + read_frclock_64(&s->s_base_tsc); break; case STATE_TS: - cur_tsc = read_frclock_64(); + read_frclock_64(&cur_tsc); tsc_delta = delta_frclock_64(s->s_base_tsc, cur_tsc); micro_delta = frclock_64_to_micros(tsc_delta); diff --git a/lib/libsys/arch/i386/frclock_util.c b/lib/libsys/arch/i386/frclock_util.c new file mode 100644 index 000000000..8d81e7857 --- /dev/null +++ b/lib/libsys/arch/i386/frclock_util.c @@ -0,0 +1,89 @@ +/* Some utility functions around the free running clock on ARM. The clock is + * 32-bits wide, but we provide 64-bit wrapper functions to make it look + * similar to the read_tsc functions. On hardware we could actually make use + * of the timer overflow counter, but emulator doesn't emulate it. */ + +#include "omap_timer_registers.h" +#include +#include +#include +#include +#include + + +static u64_t calib_hz = 1625000, Hz; +#define MICROHZ 1000000ULL /* number of micros per second */ +#define MICROSPERTICK(h) (MICROHZ/(h)) /* number of micros per HZ tick */ + +int +micro_delay(u32_t micros) +{ + u64_t start, delta, delta_end; + + Hz = sys_hz(); + + /* Start of delay. */ + start = read_frclock_64(); + delta_end = (calib_hz * micros) / MICROHZ; + + /* If we have to wait for at least one HZ tick, use the regular + * tickdelay first. Round downwards on purpose, so the average + * half-tick we wait short (depending on where in the current tick + * we call tickdelay). We can correct for both overhead of tickdelay + * itself and the short wait in the busywait later. + */ + if (micros >= MICROSPERTICK(Hz)) + tickdelay(micros*Hz/MICROHZ); + + /* Wait (the rest) of the delay time using busywait. */ + do { + delta = read_frclock_64(); + } while (delta_frclock_64(start, delta) < delta_end); + + + return 0; +} + +u32_t frclock_64_to_micros(u64_t tsc) +{ + return (u32_t) tsc / calib_hz; +} + +u32_t +read_frclock(void) +{ + extern struct minix_kerninfo *_minix_kerninfo; + volatile u32_t *frclock; + frclock = (u32_t *)((u8_t *) _minix_kerninfo->minix_frclock+OMAP3_TCRR); + return (u64_t) *frclock; +} + +u32_t +delta_frclock(u32_t base, u32_t cur) +{ + u32_t delta; + + if (cur < base) { + /* We have wrapped around, so delta is base to wrapping point + * plus starting point (0) to cur. This supports wrapping once + * only. */ + delta = (UINT_MAX - base) + cur; + } else { + delta = cur - base; + } + + return delta; +} + +u64_t +read_frclock_64(void) +{ + return (u64_t) read_frclock(); +} + +u64_t +delta_frclock_64(u64_t base, u64_t cur) +{ + return delta_frclock((u32_t) base, (u32_t) cur); +} + diff --git a/lib/libsys/arch/i386/tsc_util.c b/lib/libsys/arch/i386/tsc_util.c index d6dc1aff8..87b2b8c1c 100644 --- a/lib/libsys/arch/i386/tsc_util.c +++ b/lib/libsys/arch/i386/tsc_util.c @@ -107,3 +107,12 @@ u32_t tsc_get_khz(void) return calib_mhz * 1000; } + +#define frclock_64_to_micros tsc_64_to_micros +#define read_frclock_64 read_tsc_64 + +u64_t delta_frclock_64(u64_t base, u64_t cur) +{ + return cur - base; +} +