hrev46081 adds 1 changeset to branch 'master' old head: 7418443d1246959a5d89dad67d56b749a6708c6a new head: af1c0b55ca4c6303ce2c2d8789442421ddda2bc8 overview: http://cgit.haiku-os.org/haiku/log/?qt=range&q=af1c0b5+%5E7418443 ---------------------------------------------------------------------------- af1c0b5: ARM: kernel: fix timer resolution and implement basic timekeeping. The previously used method for programming the timer did not take into account that our timespec is 64bit while the register we poke it into is 32 bit. Since the PXA (SoC in Verdex target) has a limited scale of resolution (us,ms,second) we dynamicly determine the one that we can most closely match, and set that. For f.ex. snooze to work however, we also need system_time to work. The current implementation uses a system timer at microsecond resolution to keep track of time. Although the code is far from perfect, committing it now before it gets lost, since I'm working on the infrastructure code to properly factor out the SoC specific code out of the core ARM architecture code (so the kernel can support more then our poor old Verdex QEMU target ;)) [ Ithamar R. Adema <ithamar@xxxxxxxxxxxxxxxxxxx> ] ---------------------------------------------------------------------------- Revision: hrev46081 Commit: af1c0b55ca4c6303ce2c2d8789442421ddda2bc8 URL: http://cgit.haiku-os.org/haiku/commit/?id=af1c0b5 Author: Ithamar R. Adema <ithamar@xxxxxxxxxxxxxxxxxxx> Date: Tue Sep 17 01:03:17 2013 UTC ---------------------------------------------------------------------------- 2 files changed, 55 insertions(+), 21 deletions(-) src/system/kernel/arch/arm/arch_timer.cpp | 74 ++++++++++++++++++++------- src/system/kernel/lib/arch/arm/Jamfile | 2 - ---------------------------------------------------------------------------- diff --git a/src/system/kernel/arch/arm/arch_timer.cpp b/src/system/kernel/arch/arm/arch_timer.cpp index 5cf8574..6c291ed 100644 --- a/src/system/kernel/arch/arm/arch_timer.cpp +++ b/src/system/kernel/arch/arm/arch_timer.cpp @@ -35,35 +35,63 @@ #define PXA_OSSR 0x05 #define PXA_OIER 0x07 #define PXA_OSCR4 0x10 +#define PXA_OSCR5 0x11 #define PXA_OSMR4 0x20 +#define PXA_OSMR5 0x21 #define PXA_OMCR4 0x30 +#define PXA_OMCR5 0x31 +#define PXA_RES_S (3 << 0) +#define PXA_RES_MS (1 << 1) +#define PXA_RES_US (1 << 2) -static area_id sPxaTimersArea; -static uint32 *sPxaTimersBase; +#define US2S(bt) ((bt) / 1000000ULL) +#define US2MS(bt) ((bt) / 1000ULL) +static area_id sPxaTimersArea = B_ERROR; +static uint32 *sPxaTimersBase = NULL; +static bigtime_t sSystemTime = 0; static int32 pxa_timer_interrupt(void *data) { - int32 ret = timer_interrupt(); - sPxaTimersBase[PXA_OSSR] |= (1 << 4); + if (sPxaTimersBase[PXA_OSSR] & (1 << 4)) { + sPxaTimersBase[PXA_OSSR] |= (1 << 4); + return timer_interrupt(); + } - return ret; -} + if (sPxaTimersBase[PXA_OSSR] & (1 << 5)) { + sPxaTimersBase[PXA_OSSR] |= (1 << 5); + sSystemTime += UINT_MAX + 1ULL; + } + return B_HANDLED_INTERRUPT; +} void arch_timer_set_hardware_timer(bigtime_t timeout) { - TRACE(("arch_timer_set_hardware_timer(%lld)\n", timeout)); - - if (sPxaTimersBase) { - sPxaTimersBase[PXA_OIER] |= (1 << 4); - sPxaTimersBase[PXA_OMCR4] = 4; // set to exactly single milisecond resolution - sPxaTimersBase[PXA_OSMR4] = timeout; - sPxaTimersBase[PXA_OSCR4] = 0; // start counting from 0 again + uint32 val = timeout & UINT_MAX; + uint32 res = PXA_RES_US; + + if (timeout & ~UINT_MAX) { + // Does not fit, so scale resolution down to milliseconds + if (US2MS(timeout) & ~UINT_MAX) { + // Still does not fit, scale down to seconds as last ditch attempt + val = US2S(timeout) & UINT_MAX; + res = PXA_RES_S; + } else { + // Fits in millisecond resolution + val = US2MS(timeout) & UINT_MAX; + res = PXA_RES_MS; + } } + + TRACE(("arch_timer_set_hardware_timer(val=%lu, res=%lu)\n", val, res)); + sPxaTimersBase[PXA_OIER] |= (1 << 4); + sPxaTimersBase[PXA_OMCR4] = res; + sPxaTimersBase[PXA_OSMR4] = val; + sPxaTimersBase[PXA_OSCR4] = 0; // start counting from 0 again } @@ -72,13 +100,10 @@ arch_timer_clear_hardware_timer() { TRACE(("arch_timer_clear_hardware_timer\n")); - if (sPxaTimersBase) { - sPxaTimersBase[PXA_OMCR4] = 0; // disable our timer - sPxaTimersBase[PXA_OIER] &= ~(4 << 1); - } + sPxaTimersBase[PXA_OMCR4] = 0; // disable our timer + sPxaTimersBase[PXA_OIER] &= ~(1 << 4); } - int arch_init_timer(kernel_args *args) { @@ -88,9 +113,20 @@ arch_init_timer(kernel_args *args) if (sPxaTimersArea < 0) return sPxaTimersArea; - sPxaTimersBase[PXA_OMCR4] = 0; // disable our timer + sPxaTimersBase[PXA_OIER] |= (1 << 5); // enable timekeeping timer + sPxaTimersBase[PXA_OMCR5] = PXA_RES_US | (1 << 7); + sPxaTimersBase[PXA_OSMR5] = UINT_MAX; + sPxaTimersBase[PXA_OSCR5] = 0; install_io_interrupt_handler(PXA_TIMERS_INTERRUPT, &pxa_timer_interrupt, NULL, 0); return B_OK; } + +bigtime_t +system_time(void) +{ + return (sPxaTimersBase != NULL) ? + sSystemTime + sPxaTimersBase[PXA_OSCR5] : + 0ULL; +} diff --git a/src/system/kernel/lib/arch/arm/Jamfile b/src/system/kernel/lib/arch/arm/Jamfile index 084a552..1bdf0f1 100644 --- a/src/system/kernel/lib/arch/arm/Jamfile +++ b/src/system/kernel/lib/arch/arm/Jamfile @@ -11,8 +11,6 @@ SEARCH_SOURCE += [ FDirName $(librootSources) os arch generic ] ; KernelMergeObject kernel_os_arch_$(TARGET_ARCH).o : atomic.S byteorder.S -# system_time_asm.S - system_time.c generic_system_time_nsecs.cpp