diff --git a/include/minix/sysutil.h b/include/minix/sysutil.h index cd32e953c..56a6d7952 100644 --- a/include/minix/sysutil.h +++ b/include/minix/sysutil.h @@ -61,6 +61,12 @@ u32_t tsc_64_to_micros(u64_t tsc); 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); +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 ser_putc(char c); void get_randomness(struct k_randomness *, int); u32_t sqrt_approx(u32_t); diff --git a/include/minix/type.h b/include/minix/type.h index 7dc11f161..29e59bcba 100644 --- a/include/minix/type.h +++ b/include/minix/type.h @@ -168,7 +168,7 @@ struct minix_kerninfo { u32_t kerninfo_magic; u32_t minix_feature_flags; /* features in minix kernel */ u32_t ki_flags; /* what is present in this struct */ - u32_t flags_unused2; + u32_t minix_frclock; u32_t flags_unused3; u32_t flags_unused4; struct kinfo *kinfo; diff --git a/kernel/arch/earm/arch_clock.c b/kernel/arch/earm/arch_clock.c index 5a5144140..96d8811b2 100644 --- a/kernel/arch/earm/arch_clock.c +++ b/kernel/arch/earm/arch_clock.c @@ -25,6 +25,7 @@ static unsigned tsc_per_ms[CONFIG_MAX_CPUS]; int init_local_timer(unsigned freq) { omap3_timer_init(freq); + omap3_frclock_init(); /* always only 1 cpu in the system */ tsc_per_ms[0] = 1; diff --git a/kernel/arch/earm/memory.c b/kernel/arch/earm/memory.c index 2f22bb5b7..f422d43be 100644 --- a/kernel/arch/earm/memory.c +++ b/kernel/arch/earm/memory.c @@ -18,6 +18,7 @@ #include "arch_proto.h" #include "kernel/proto.h" #include "kernel/debug.h" +#include "omap_timer.h" phys_bytes device_mem_vaddr = 0; @@ -667,6 +668,7 @@ void arch_proc_init(struct proc *pr, const u32_t ip, const u32_t sp, char *name) } static int device_mem_mapping_index = -1, + frclock_index = -1, usermapped_glo_index = -1, usermapped_index = -1, first_um_idx = -1; @@ -685,7 +687,9 @@ int arch_phys_map(const int index, (u32_t) &usermapped_start; if(first) { + memset(&minix_kerninfo, 0, sizeof(minix_kerninfo)); device_mem_mapping_index = freeidx++; + frclock_index = freeidx++; if(glo_len > 0) { usermapped_glo_index = freeidx++; } @@ -717,6 +721,12 @@ int arch_phys_map(const int index, *flags = VMMF_UNCACHED | VMMF_WRITE; return OK; } + else if (index == frclock_index) { + *addr = OMAP3_GPTIMER10_BASE; + *len = ARM_PAGE_SIZE; + *flags = VMMF_USER; + return OK; + } return EINVAL; } @@ -727,7 +737,6 @@ int arch_phys_map_reply(const int index, const vir_bytes addr) u32_t usermapped_offset; assert(addr > (u32_t) &usermapped_start); usermapped_offset = addr - (u32_t) &usermapped_start; - memset(&minix_kerninfo, 0, sizeof(minix_kerninfo)); #define FIXEDPTR(ptr) (void *) ((u32_t)ptr + usermapped_offset) #define FIXPTR(ptr) ptr = FIXEDPTR(ptr) #define ASSIGN(minixstruct) minix_kerninfo.minixstruct = FIXEDPTR(&minixstruct) @@ -746,10 +755,15 @@ int arch_phys_map_reply(const int index, const vir_bytes addr) return OK; } - if(index == usermapped_index) return OK; - - if (index == device_mem_mapping_index) { - device_mem_vaddr = addr; + if (index == usermapped_index) { + return OK; + } + else if (index == device_mem_mapping_index) { + device_mem_vaddr = addr; + return OK; + } + else if (index == frclock_index) { + minix_kerninfo.minix_frclock = addr; return OK; } diff --git a/kernel/arch/earm/omap_timer.c b/kernel/arch/earm/omap_timer.c index f106dc092..a5bac65a9 100644 --- a/kernel/arch/earm/omap_timer.c +++ b/kernel/arch/earm/omap_timer.c @@ -21,6 +21,42 @@ int omap3_register_timer_handler(const irq_handler_t handler) return 0; } +void omap3_frclock_init(void) +{ + u32_t tisr; + + /* Stop timer */ + mmio_clear(OMAP3_GPTIMER10_TCLR, OMAP3_TCLR_ST); + + /* Use functional clock source for GPTIMER10 */ + mmio_set(OMAP3_CM_CLKSEL_CORE, OMAP3_CLKSEL_GPT10); + + /* Scale timer down to 13/8 = 1.625 Mhz to roughly get microsecond ticks */ + /* The scale is computed as 2^(PTV+1). So if PTV == 2, we get 2^3 = 8. + */ + mmio_set(OMAP3_GPTIMER10_TCLR, (2 << OMAP3_TCLR_PTV)); + + /* Start and auto-reload at 0 */ + mmio_write(OMAP3_GPTIMER10_TLDR, 0x0); + mmio_write(OMAP3_GPTIMER10_TCRR, 0x0); + + /* Set up overflow interrupt */ + tisr = OMAP3_TISR_MAT_IT_FLAG | OMAP3_TISR_OVF_IT_FLAG | + OMAP3_TISR_TCAR_IT_FLAG; + mmio_write(OMAP3_GPTIMER10_TISR, tisr); /* Clear interrupt status */ + mmio_write(OMAP3_GPTIMER10_TIER, OMAP3_TIER_OVF_IT_ENA); + + /* Start timer */ + mmio_set(OMAP3_GPTIMER10_TCLR, + OMAP3_TCLR_OVF_TRG|OMAP3_TCLR_AR|OMAP3_TCLR_ST|OMAP3_TCLR_PRE); +} + +void omap3_frclock_stop() +{ + mmio_clear(OMAP3_GPTIMER10_TCLR, OMAP3_TCLR_ST); +} + + void omap3_timer_init(unsigned freq) { u32_t tisr; @@ -63,6 +99,7 @@ void omap3_timer_int_handler() OMAP3_TISR_TCAR_IT_FLAG; mmio_write(OMAP3_GPTIMER1_TISR, tisr); tsc++; + } /* Don't use libminlib's read_tsc_64, but our own version instead. We emulate diff --git a/kernel/arch/earm/omap_timer.h b/kernel/arch/earm/omap_timer.h index 5317b0e28..948139bfb 100644 --- a/kernel/arch/earm/omap_timer.h +++ b/kernel/arch/earm/omap_timer.h @@ -1,92 +1,14 @@ #ifndef _OMAP_TIMER_H #define _OMAP_TIMER_H -/* General-purpose timer register map */ -#define OMAP3_GPTIMER1_BASE 0x48318000 /* GPTIMER1 physical address */ -#define OMAP3_GPTIMER2_BASE 0x49032000 /* GPTIMER2 physical address */ -#define OMAP3_GPTIMER3_BASE 0x49034000 /* GPTIMER3 physical address */ -#define OMAP3_GPTIMER4_BASE 0x49036000 /* GPTIMER4 physical address */ -#define OMAP3_GPTIMER5_BASE 0x49038000 /* GPTIMER5 physical address */ -#define OMAP3_GPTIMER6_BASE 0x4903A000 /* GPTIMER6 physical address */ -#define OMAP3_GPTIMER7_BASE 0x4903C000 /* GPTIMER7 physical address */ -#define OMAP3_GPTIMER8_BASE 0x4903E000 /* GPTIMER8 physical address */ -#define OMAP3_GPTIMER9_BASE 0x49040000 /* GPTIMER9 physical address */ -#define OMAP3_GPTIMER10_BASE 0x48086000 /* GPTIMER10 physical address */ -#define OMAP3_GPTIMER11_BASE 0x48088000 /* GPTIMER11 physical address */ - -/* General-purpose timer registers */ -#define OMAP3_TIDR 0x000 /* IP revision code */ -#define OMAP3_TIOCP_CFG 0x010 /* Controls params for GP timer L4 interface */ -#define OMAP3_TISTAT 0x014 /* Status (excl. interrupt status) */ -#define OMAP3_TISR 0x018 /* Pending interrupt status */ -#define OMAP3_TIER 0x01C /* Interrupt enable */ -#define OMAP3_TWER 0x020 /* Wakeup enable */ -#define OMAP3_TCLR 0x024 /* Controls optional features */ -#define OMAP3_TCRR 0x028 /* Internal counter value */ -#define OMAP3_TLDR 0x02C /* Timer load value */ -#define OMAP3_TTGR 0x030 /* Triggers counter reload */ -#define OMAP3_TWPS 0x034 /* Indicates if Write-Posted pending */ -#define OMAP3_TMAR 0x038 /* Value to be compared with counter */ -#define OMAP3_TCAR1 0x03C /* First captured value of counter register */ -#define OMAP3_TSICR 0x040 /* Control posted mode and functional SW reset */ -#define OMAP3_TCAR2 0x044 /* Second captured value of counter register */ -#define OMAP3_TPIR 0x048 /* Positive increment (1 ms tick) */ -#define OMAP3_TNIR 0x04C /* Negative increment (1 ms tick) */ -#define OMAP3_TCVR 0x050 /* Defines TCRR is sub/over-period (1 ms tick) */ -#define OMAP3_TOCR 0x054 /* Masks tick interrupt */ -#define OMAP3_TOWR 0x058 /* Number of masked overflow interrupts */ - -/* Interrupt status register fields */ -#define OMAP3_TISR_MAT_IT_FLAG (1 << 0) /* Pending match interrupt status */ -#define OMAP3_TISR_OVF_IT_FLAG (1 << 1) /* Pending overflow interrupt status */ -#define OMAP3_TISR_TCAR_IT_FLAG (1 << 2) /* Pending capture interrupt status */ - -/* Interrupt enable register fields */ -#define OMAP3_TIER_MAT_IT_ENA (1 << 0) /* Enable match interrupt */ -#define OMAP3_TIER_OVF_IT_ENA (1 << 1) /* Enable overflow interrupt */ -#define OMAP3_TIER_TCAR_IT_ENA (1 << 2) /* Enable capture interrupt */ - -/* Timer control fields */ -#define OMAP3_TCLR_ST (1 << 0) /* Start/stop timer */ -#define OMAP3_TCLR_AR (1 << 1) /* Autoreload or one-shot mode */ -#define OMAP3_TCLR_OVF_TRG (1 << 10) /* Overflow trigger */ - -#define OMAP3_GPTIMER1_TIDR (OMAP3_GPTIMER1_BASE + OMAP3_TIDR) -#define OMAP3_GPTIMER1_TIOCP_CFG (OMAP3_GPTIMER1_BASE + OMAP3_TIOCP_CFG) -#define OMAP3_GPTIMER1_TISTAT (OMAP3_GPTIMER1_BASE + OMAP3_TISTAT) -#define OMAP3_GPTIMER1_TISR (OMAP3_GPTIMER1_BASE + OMAP3_TISR) -#define OMAP3_GPTIMER1_TIER (OMAP3_GPTIMER1_BASE + OMAP3_TIER) -#define OMAP3_GPTIMER1_TWER (OMAP3_GPTIMER1_BASE + OMAP3_TWER) -#define OMAP3_GPTIMER1_TCLR (OMAP3_GPTIMER1_BASE + OMAP3_TCLR) -#define OMAP3_GPTIMER1_TCRR (OMAP3_GPTIMER1_BASE + OMAP3_TCRR) -#define OMAP3_GPTIMER1_TLDR (OMAP3_GPTIMER1_BASE + OMAP3_TLDR) -#define OMAP3_GPTIMER1_TTGR (OMAP3_GPTIMER1_BASE + OMAP3_TTGR) -#define OMAP3_GPTIMER1_TWPS (OMAP3_GPTIMER1_BASE + OMAP3_TWPS) -#define OMAP3_GPTIMER1_TMAR (OMAP3_GPTIMER1_BASE + OMAP3_TMAR) -#define OMAP3_GPTIMER1_TCAR1 (OMAP3_GPTIMER1_BASE + OMAP3_TCAR1) -#define OMAP3_GPTIMER1_TSICR (OMAP3_GPTIMER1_BASE + OMAP3_TSICR) -#define OMAP3_GPTIMER1_TCAR2 (OMAP3_GPTIMER1_BASE + OMAP3_TCAR2) -#define OMAP3_GPTIMER1_TPIR (OMAP3_GPTIMER1_BASE + OMAP3_TPIR) -#define OMAP3_GPTIMER1_TNIR (OMAP3_GPTIMER1_BASE + OMAP3_TNIR) -#define OMAP3_GPTIMER1_TCVR (OMAP3_GPTIMER1_BASE + OMAP3_TCVR) -#define OMAP3_GPTIMER1_TOCR (OMAP3_GPTIMER1_BASE + OMAP3_TOCR) -#define OMAP3_GPTIMER1_TOWR (OMAP3_GPTIMER1_BASE + OMAP3_TOWR) - -#define OMAP3_CM_CLKSEL_WKUP 0x48004c40 /* source clock selection */ -#define OMAP3_CLKSEL_GPT1 (1 << 0) /* Selects GPTIMER 1 source - * clock: - * - * 0: use 32KHz clock - * 1: sys clock) - */ - -#define TIMER_FREQ 1000 /* clock frequency for OMAP timer (1ms) */ -#define TIMER_COUNT(freq) (TIMER_FREQ/(freq)) /* initial value for counter*/ +#include "omap_timer_registers.h" #ifndef __ASSEMBLY__ void omap3_timer_init(unsigned freq); void omap3_timer_stop(void); +void omap3_frclock_init(void); +void omap3_frclock_stop(void); int omap3_register_timer_handler(const irq_handler_t handler); void omap3_timer_int_handler(void); diff --git a/kernel/arch/earm/omap_timer_registers.h b/kernel/arch/earm/omap_timer_registers.h new file mode 100644 index 000000000..21e8b9d95 --- /dev/null +++ b/kernel/arch/earm/omap_timer_registers.h @@ -0,0 +1,119 @@ +#ifndef _OMAP_TIMER_REGISTERS_H +#define _OMAP_TIMER_REGISTERS_H + +/* General-purpose timer register map */ +#define OMAP3_GPTIMER1_BASE 0x48318000 /* GPTIMER1 physical address */ +#define OMAP3_GPTIMER2_BASE 0x49032000 /* GPTIMER2 physical address */ +#define OMAP3_GPTIMER3_BASE 0x49034000 /* GPTIMER3 physical address */ +#define OMAP3_GPTIMER4_BASE 0x49036000 /* GPTIMER4 physical address */ +#define OMAP3_GPTIMER5_BASE 0x49038000 /* GPTIMER5 physical address */ +#define OMAP3_GPTIMER6_BASE 0x4903A000 /* GPTIMER6 physical address */ +#define OMAP3_GPTIMER7_BASE 0x4903C000 /* GPTIMER7 physical address */ +#define OMAP3_GPTIMER8_BASE 0x4903E000 /* GPTIMER8 physical address */ +#define OMAP3_GPTIMER9_BASE 0x49040000 /* GPTIMER9 physical address */ +#define OMAP3_GPTIMER10_BASE 0x48086000 /* GPTIMER10 physical address */ +#define OMAP3_GPTIMER11_BASE 0x48088000 /* GPTIMER11 physical address */ + +/* General-purpose timer registers */ +#define OMAP3_TIDR 0x000 /* IP revision code */ +#define OMAP3_TIOCP_CFG 0x010 /* Controls params for GP timer L4 interface */ +#define OMAP3_TISTAT 0x014 /* Status (excl. interrupt status) */ +#define OMAP3_TISR 0x018 /* Pending interrupt status */ +#define OMAP3_TIER 0x01C /* Interrupt enable */ +#define OMAP3_TWER 0x020 /* Wakeup enable */ +#define OMAP3_TCLR 0x024 /* Controls optional features */ +#define OMAP3_TCRR 0x028 /* Internal counter value */ +#define OMAP3_TLDR 0x02C /* Timer load value */ +#define OMAP3_TTGR 0x030 /* Triggers counter reload */ +#define OMAP3_TWPS 0x034 /* Indicates if Write-Posted pending */ +#define OMAP3_TMAR 0x038 /* Value to be compared with counter */ +#define OMAP3_TCAR1 0x03C /* First captured value of counter register */ +#define OMAP3_TSICR 0x040 /* Control posted mode and functional SW reset */ +#define OMAP3_TCAR2 0x044 /* Second captured value of counter register */ +#define OMAP3_TPIR 0x048 /* Positive increment (1 ms tick) */ +#define OMAP3_TNIR 0x04C /* Negative increment (1 ms tick) */ +#define OMAP3_TCVR 0x050 /* Defines TCRR is sub/over-period (1 ms tick) */ +#define OMAP3_TOCR 0x054 /* Masks tick interrupt */ +#define OMAP3_TOWR 0x058 /* Number of masked overflow interrupts */ + +/* Interrupt status register fields */ +#define OMAP3_TISR_MAT_IT_FLAG (1 << 0) /* Pending match interrupt status */ +#define OMAP3_TISR_OVF_IT_FLAG (1 << 1) /* Pending overflow interrupt status */ +#define OMAP3_TISR_TCAR_IT_FLAG (1 << 2) /* Pending capture interrupt status */ + +/* Interrupt enable register fields */ +#define OMAP3_TIER_MAT_IT_ENA (1 << 0) /* Enable match interrupt */ +#define OMAP3_TIER_OVF_IT_ENA (1 << 1) /* Enable overflow interrupt */ +#define OMAP3_TIER_TCAR_IT_ENA (1 << 2) /* Enable capture interrupt */ + +/* Timer control fields */ +#define OMAP3_TCLR_ST (1 << 0) /* Start/stop timer */ +#define OMAP3_TCLR_AR (1 << 1) /* Autoreload or one-shot mode */ +#define OMAP3_TCLR_PRE (1 << 5) /* Prescaler on */ +#define OMAP3_TCLR_PTV 2 +#define OMAP3_TCLR_OVF_TRG (1 << 10) /* Overflow trigger */ + +#define OMAP3_GPTIMER1_TIDR (OMAP3_GPTIMER1_BASE + OMAP3_TIDR) +#define OMAP3_GPTIMER1_TIOCP_CFG (OMAP3_GPTIMER1_BASE + OMAP3_TIOCP_CFG) +#define OMAP3_GPTIMER1_TISTAT (OMAP3_GPTIMER1_BASE + OMAP3_TISTAT) +#define OMAP3_GPTIMER1_TISR (OMAP3_GPTIMER1_BASE + OMAP3_TISR) +#define OMAP3_GPTIMER1_TIER (OMAP3_GPTIMER1_BASE + OMAP3_TIER) +#define OMAP3_GPTIMER1_TWER (OMAP3_GPTIMER1_BASE + OMAP3_TWER) +#define OMAP3_GPTIMER1_TCLR (OMAP3_GPTIMER1_BASE + OMAP3_TCLR) +#define OMAP3_GPTIMER1_TCRR (OMAP3_GPTIMER1_BASE + OMAP3_TCRR) +#define OMAP3_GPTIMER1_TLDR (OMAP3_GPTIMER1_BASE + OMAP3_TLDR) +#define OMAP3_GPTIMER1_TTGR (OMAP3_GPTIMER1_BASE + OMAP3_TTGR) +#define OMAP3_GPTIMER1_TWPS (OMAP3_GPTIMER1_BASE + OMAP3_TWPS) +#define OMAP3_GPTIMER1_TMAR (OMAP3_GPTIMER1_BASE + OMAP3_TMAR) +#define OMAP3_GPTIMER1_TCAR1 (OMAP3_GPTIMER1_BASE + OMAP3_TCAR1) +#define OMAP3_GPTIMER1_TSICR (OMAP3_GPTIMER1_BASE + OMAP3_TSICR) +#define OMAP3_GPTIMER1_TCAR2 (OMAP3_GPTIMER1_BASE + OMAP3_TCAR2) +#define OMAP3_GPTIMER1_TPIR (OMAP3_GPTIMER1_BASE + OMAP3_TPIR) +#define OMAP3_GPTIMER1_TNIR (OMAP3_GPTIMER1_BASE + OMAP3_TNIR) +#define OMAP3_GPTIMER1_TCVR (OMAP3_GPTIMER1_BASE + OMAP3_TCVR) +#define OMAP3_GPTIMER1_TOCR (OMAP3_GPTIMER1_BASE + OMAP3_TOCR) +#define OMAP3_GPTIMER1_TOWR (OMAP3_GPTIMER1_BASE + OMAP3_TOWR) + +#define OMAP3_GPTIMER10_TIDR (OMAP3_GPTIMER10_BASE + OMAP3_TIDR) +#define OMAP3_GPTIMER10_TIOCP_CFG (OMAP3_GPTIMER10_BASE + OMAP3_TIOCP_CFG) +#define OMAP3_GPTIMER10_TISTAT (OMAP3_GPTIMER10_BASE + OMAP3_TISTAT) +#define OMAP3_GPTIMER10_TISR (OMAP3_GPTIMER10_BASE + OMAP3_TISR) +#define OMAP3_GPTIMER10_TIER (OMAP3_GPTIMER10_BASE + OMAP3_TIER) +#define OMAP3_GPTIMER10_TWER (OMAP3_GPTIMER10_BASE + OMAP3_TWER) +#define OMAP3_GPTIMER10_TCLR (OMAP3_GPTIMER10_BASE + OMAP3_TCLR) +#define OMAP3_GPTIMER10_TCRR (OMAP3_GPTIMER10_BASE + OMAP3_TCRR) +#define OMAP3_GPTIMER10_TLDR (OMAP3_GPTIMER10_BASE + OMAP3_TLDR) +#define OMAP3_GPTIMER10_TTGR (OMAP3_GPTIMER10_BASE + OMAP3_TTGR) +#define OMAP3_GPTIMER10_TWPS (OMAP3_GPTIMER10_BASE + OMAP3_TWPS) +#define OMAP3_GPTIMER10_TMAR (OMAP3_GPTIMER10_BASE + OMAP3_TMAR) +#define OMAP3_GPTIMER10_TCAR1 (OMAP3_GPTIMER10_BASE + OMAP3_TCAR1) +#define OMAP3_GPTIMER10_TSICR (OMAP3_GPTIMER10_BASE + OMAP3_TSICR) +#define OMAP3_GPTIMER10_TCAR2 (OMAP3_GPTIMER10_BASE + OMAP3_TCAR2) +#define OMAP3_GPTIMER10_TPIR (OMAP3_GPTIMER10_BASE + OMAP3_TPIR) +#define OMAP3_GPTIMER10_TNIR (OMAP3_GPTIMER10_BASE + OMAP3_TNIR) +#define OMAP3_GPTIMER10_TCVR (OMAP3_GPTIMER10_BASE + OMAP3_TCVR) +#define OMAP3_GPTIMER10_TOCR (OMAP3_GPTIMER10_BASE + OMAP3_TOCR) +#define OMAP3_GPTIMER10_TOWR (OMAP3_GPTIMER10_BASE + OMAP3_TOWR) + +#define OMAP3_CM_CLKSEL_GFX 0x48004b40 +#define OMAP3_CM_CLKEN_PLL 0x48004d00 +#define OMAP3_CM_FCLKEN1_CORE 0x48004A00 +#define OMAP3_CM_CLKSEL_CORE 0x48004A40 /* GPT10 src clock sel. */ +#define OMAP3_CM_FCLKEN_PER 0x48005000 +#define OMAP3_CM_CLKSEL_PER 0x48005040 +#define OMAP3_CM_CLKSEL_WKUP 0x48004c40 /* GPT1 source clock selection */ + +#define OMAP3_CLKSEL_GPT1 (1 << 0) /* Selects GPTIMER 1 source + * clock: + * + * 0: use 32KHz clock + * 1: sys clock) + */ +#define OMAP3_CLKSEL_GPT10 (1 << 6) +#define OMAP3_CLKSEL_GPT11 (1 << 7) + + +#define TIMER_FREQ 1000 /* clock frequency for OMAP timer (1ms) */ +#define TIMER_COUNT(freq) (TIMER_FREQ/(freq)) /* initial value for counter*/ + +#endif /* _OMAP_TIMER_REGISTERS_H */ diff --git a/kernel/arch/i386/memory.c b/kernel/arch/i386/memory.c index eb87a9d92..3eca8bbba 100644 --- a/kernel/arch/i386/memory.c +++ b/kernel/arch/i386/memory.c @@ -804,6 +804,7 @@ int arch_phys_map(const int index, (u32_t) &usermapped_start; if(first) { + memset(&minix_kerninfo, 0, sizeof(minix_kerninfo)); video_mem_mapping_index = freeidx++; if(glo_len > 0) { usermapped_glo_index = freeidx++; @@ -921,7 +922,6 @@ int arch_phys_map_reply(const int index, const vir_bytes addr) extern u32_t usermapped_offset; assert(addr > (u32_t) &usermapped_start); usermapped_offset = addr - (u32_t) &usermapped_start; - memset(&minix_kerninfo, 0, sizeof(minix_kerninfo)); #define FIXEDPTR(ptr) (void *) ((u32_t)ptr + usermapped_offset) #define FIXPTR(ptr) ptr = FIXEDPTR(ptr) #define ASSIGN(minixstruct) minix_kerninfo.minixstruct = FIXEDPTR(&minixstruct) diff --git a/lib/libsys/arch/earm/Makefile.inc b/lib/libsys/arch/earm/Makefile.inc index 8a9981774..55fd2bced 100644 --- a/lib/libsys/arch/earm/Makefile.inc +++ b/lib/libsys/arch/earm/Makefile.inc @@ -5,8 +5,11 @@ HERE=${.CURDIR}/arch/${MACHINE_ARCH} .PATH: ${HERE} SRCS+= \ + frclock_util.c \ + spin.c \ tsc_util.c -CPPFLAGS+= -I${HERE}/../../ +CPPFLAGS+= -I${HERE}/../../ +CPPFLAGS+= -I${NETBSDSRCDIR} -I${NETBSDSRCDIR}/kernel/arch/${MACHINE_ARCH}/ diff --git a/lib/libsys/arch/earm/frclock_util.c b/lib/libsys/arch/earm/frclock_util.c new file mode 100644 index 000000000..8d81e7857 --- /dev/null +++ b/lib/libsys/arch/earm/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/earm/spin.c b/lib/libsys/arch/earm/spin.c new file mode 100644 index 000000000..1033a2f8f --- /dev/null +++ b/lib/libsys/arch/earm/spin.c @@ -0,0 +1,98 @@ +/* Helper functions that allow driver writers to easily busy-wait (spin) for a + * condition to become satisfied within a certain maximum time span. + */ +/* This implementation first spins without making any system calls for a + * while, and then starts using system calls (specifically, the system call to + * obtain the current time) while spinning. The reason for this is that in + * many cases, the condition to be checked will become satisfied rather + * quickly, and we want to avoid getting descheduled in that case. However, + * after a while, running out of scheduling quantum will cause our priority to + * be lowered, and we can avoid this by voluntarily giving up the CPU, by + * making a system call. + */ +#include "sysutil.h" +#include +#include + +/* Number of microseconds to keep spinning initially, without performing a + * system call. We pick a value somewhat smaller than a typical clock tick. + * Note that for the above reasons, we want to avoid using sys_hz() here. + */ +#define TSC_SPIN 1000 /* in microseconds */ + +/* Internal spin states. */ +enum { + STATE_INIT, /* simply check the condition (once) */ + STATE_BASE_TS, /* get the initial TSC value (once) */ + STATE_TS, /* use the TSC to spin (up to TSC_SPIN us) */ + STATE_UPTIME /* use the clock to spin */ +}; + +void spin_init(spin_t *s, u32_t usecs) +{ + /* Initialize the given spin state structure, set to spin at most the + * given number of microseconds. + */ + s->s_state = STATE_INIT; + s->s_usecs = usecs; + s->s_timeout = FALSE; +} + +int spin_check(spin_t *s) +{ + /* Check whether a timeout has taken place. Return TRUE if the caller + * should continue spinning, and FALSE if a timeout has occurred. The + * implementation assumes that it is okay to spin a little bit too long + * (up to a full clock tick extra). + */ + u64_t cur_tsc, tsc_delta; + clock_t now, micro_delta; + + switch (s->s_state) { + case STATE_INIT: + s->s_state = STATE_BASE_TS; + break; + + case STATE_BASE_TS: + s->s_state = STATE_TS; + s->s_base_tsc = read_frclock_64(); + break; + + case STATE_TS: + cur_tsc = read_frclock_64(); + tsc_delta = delta_frclock_64(s->s_base_tsc, cur_tsc); + micro_delta = frclock_64_to_micros(tsc_delta); + + if (micro_delta >= s->s_usecs) { + s->s_timeout = TRUE; + return FALSE; + } + + if (micro_delta >= TSC_SPIN) { + s->s_usecs -= micro_delta; + getuptime(&s->s_base_uptime); + s->s_state = STATE_UPTIME; + } + + break; + + case STATE_UPTIME: + getuptime(&now); + + /* We assume that sys_hz() caches its return value. */ + micro_delta = ((now - s->s_base_uptime) * 1000 / sys_hz()) * + 1000; + + if (micro_delta >= s->s_usecs) { + s->s_timeout = TRUE; + return FALSE; + } + + break; + + default: + panic("spin_check: invalid state %d", s->s_state); + } + + return TRUE; +} diff --git a/lib/libsys/arch/earm/tsc_util.c b/lib/libsys/arch/earm/tsc_util.c index 045d079cb..4f973e9a1 100644 --- a/lib/libsys/arch/earm/tsc_util.c +++ b/lib/libsys/arch/earm/tsc_util.c @@ -18,25 +18,14 @@ #define MICROHZ 1000000 /* number of micros per second */ #define MICROSPERTICK(h) (MICROHZ/(h)) /* number of micros per HZ tick */ -static u32_t calib_mhz = 1000, Hz = 1000; - -int -micro_delay(u32_t micros) -{ - return OK; -} +static u32_t calib_hz = 600000000; u32_t tsc_64_to_micros(u64_t tsc) { u64_t tmp; - tmp = div64u64(tsc, calib_mhz); - if (ex64hi(tmp)) { - printf("tsc_64_to_micros: more than 2^32ms\n"); - return ~0UL; - } else { - return ex64lo(tmp); - } + tmp = tsc / calib_hz; + return (u32_t) tmp; } u32_t tsc_to_micros(u32_t low, u32_t high)