From ba06f0766073168cc42458c6327f6703de21943f Mon Sep 17 00:00:00 2001 From: "Ithamar R. Adema" Date: Tue, 17 Sep 2013 03:03:17 +0200 Subject: [PATCH] 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 ;)) --- src/system/kernel/arch/arm/arch_timer.cpp | 72 +++++++++++++++++------ src/system/kernel/lib/arch/arm/Jamfile | 2 - 2 files changed, 54 insertions(+), 20 deletions(-) diff --git a/src/system/kernel/arch/arm/arch_timer.cpp b/src/system/kernel/arch/arm/arch_timer.cpp index 5cf8574279..6c291ed6bb 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)); + uint32 val = timeout & UINT_MAX; + uint32 res = PXA_RES_US; - 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 + 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 084a552ca8..1bdf0f1501 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