mcs: provide tickless api for arm timers

This does not implement the timers for any platforms, but
provides the generic arm arch, and aarch32/aarch64 infrastructure for
tickless timer drivers.
This commit is contained in:
Anna Lyons
2019-05-23 14:22:20 +10:00
committed by Kent Mcleod
parent fad8781c81
commit 742cabf15b
8 changed files with 133 additions and 1 deletions

View File

@@ -53,3 +53,7 @@ additional_commands:
NUM_PPI: '*'
INTERRUPT_CONTROLLER: '*'
TIMER: '*'
KERNEL_WCET: '*'
CLK_MAGIC: '*'
CLK_SHIFT: '*'
TIMER_PRECISION: '*'

View File

@@ -84,6 +84,9 @@ if(DEFINED CONFIGURE_MAX_IRQ)
math(EXPR BITS "${BITS} + 1")
endif()
set(CONFIGURE_IRQ_SLOT_BITS "${BITS}" CACHE INTERNAL "")
if(NOT DEFINED ${CONFIGURE_TIMER_PRECISION})
set(CONFIGURE_TIMER_PRECISION "0")
endif()
configure_file(
src/arch/${KernelArch}/platform_gen.h.in
${CMAKE_CURRENT_BINARY_DIR}/gen_headers/plat/platform_gen.h @ONLY

View File

@@ -102,13 +102,22 @@ unset(CONFIGURE_NUM_PPI CACHE)
unset(CONFIGURE_INTERRUPT_CONTROLLER CACHE)
unset(CONFIGURE_TIMER CACHE)
unset(CONFIGURE_SMMU CACHE)
unset(CONFIGURE_CLK_SHIFT CACHE)
unset(CONFIGURE_CLK_MAGIC CACHE)
unset(CONFIGURE_KERNEL_WCET CACHE)
unset(CONFIGURE_TIMER_PRECISION CACHE)
# CLK_SHIFT and CLK_MAGIC are generated from tools/reciprocal.py
# based on the TIMER_CLK_HZ to simulate division.
# This could be moved to a cmake function
# in future to build the values on the first build. Note the calculation
# can take a long time though.
function(declare_default_headers)
cmake_parse_arguments(
PARSE_ARGV
0
CONFIGURE
""
"TIMER_FREQUENCY;MAX_IRQ;NUM_PPI;PLIC_MAX_NUM_INT;INTERRUPT_CONTROLLER;TIMER;SMMU"
"TIMER_FREQUENCY;MAX_IRQ;NUM_PPI;PLIC_MAX_NUM_INT;INTERRUPT_CONTROLLER;TIMER;SMMU;CLK_SHIFT;CLK_MAGIC;KERNEL_WCET;TIMER_PRECISION"
""
)
set(CONFIGURE_TIMER_FREQUENCY "${CONFIGURE_TIMER_FREQUENCY}" CACHE INTERNAL "")
@@ -118,6 +127,10 @@ function(declare_default_headers)
set(CONFIGURE_INTERRUPT_CONTROLLER "${CONFIGURE_INTERRUPT_CONTROLLER}" CACHE INTERNAL "")
set(CONFIGURE_TIMER "${CONFIGURE_TIMER}" CACHE INTERNAL "")
set(CONFIGURE_SMMU "${CONFIGURE_SMMU}" CACHE INTERNAL "")
set(CONFIGURE_CLK_SHIFT "${CONFIGURE_CLK_SHIFT}" CACHE INTERNAL "")
set(CONFIGURE_CLK_MAGIC "${CONFIGURE_CLK_MAGIC}" CACHE INTERNAL "")
set(CONFIGURE_KERNEL_WCET "${CONFIGURE_KERNEL_WCET}" CACHE INTERNAL "")
set(CONFIGURE_TIMER_PRECISION "${CONFIGURE_TIMER_PRECISION}" CACHE INTERNAL "")
endfunction()
# For all of the common variables we set a default value here if they haven't

View File

@@ -30,4 +30,32 @@
#define CNT_CVAL CNTV_CVAL
#endif
#ifdef CONFIG_KERNEL_MCS
#include <util.h>
/* timer function definitions that work for all 32bit arm platforms that provide
* CLK_MAGIC and TIMER_CLOCK_MHZ -- these definitions might need to move
* if we come across an arm platform that does not suit this model */
/* get the max value ticksToUs can be passed without overflowing */
static inline CONST ticks_t getMaxTicksToUs(void)
{
#if USE_KHZ
return UINT64_MAX / KHZ_IN_MHZ / CLK_MAGIC;
#else
return UINT64_MAX / CLK_MAGIC;
#endif
}
static inline CONST time_t ticksToUs(ticks_t ticks)
{
/* simulate 64bit division using multiplication by reciprocal */
#if USE_KHZ
return (ticks * KHZ_IN_MHZ) * CLK_MAGIC >> CLK_SHIFT;
#else
return (ticks * CLK_MAGIC) >> CLK_SHIFT;
#endif
}
#endif /* CONFIG_KERNEL_MCS */
#endif /* __ARCH_MODE_MACHINE_TIMER_H_ */

View File

@@ -26,4 +26,27 @@
#endif
#define CNTFRQ "cntfrq_el0"
#ifdef CONFIG_KERNEL_MCS
#include <stdint.h>
#include <util.h>
/* timer function definitions that work for all 64 bit arm platforms */
static inline CONST ticks_t getMaxTicksToUs(void)
{
#if USE_KHZ
return UINT64_MAX / TIMER_CLOCK_KHZ;
#else
return UINT64_MAX;
#endif
}
static inline CONST time_t ticksToUs(ticks_t ticks)
{
#if USE_KHZ
return (ticks * TIMER_CLOCK_KHZ) / TIMER_CLOCK_MHZ;
#else
return ticks / TIMER_CLOCK_MHZ;
#endif
}
#endif /* CONFIG_KERNEL_MCS */
#endif /* __ARCH_MODE_MACHINE_TIMER_H_ */

View File

@@ -15,6 +15,48 @@
#include <config.h>
#include <stdint.h>
#ifdef CONFIG_KERNEL_MCS
#include <types.h>
#include <util.h>
#include <mode/util.h>
#define USE_KHZ (TIMER_CLOCK_HZ % HZ_IN_MHZ > 0)
#define TIMER_CLOCK_KHZ (TIMER_CLOCK_HZ / HZ_IN_KHZ)
#define TIMER_CLOCK_MHZ (TIMER_CLOCK_HZ / HZ_IN_MHZ)
#include <plat/platform_gen.h>
#include <mode/machine/timer.h>
void initTimer(void);
/* get the max value usToTicks can be passed without overflowing */
static inline CONST time_t getMaxUsToTicks(void)
{
#if USE_KHZ
return UINT64_MAX / TIMER_CLOCK_KHZ;
#else
return UINT64_MAX / TIMER_CLOCK_MHZ;
#endif
}
static inline CONST ticks_t usToTicks(time_t us)
{
#if USE_KHZ
/* reciprocal division overflows too quickly for dividing by KHZ_IN_MHZ.
* This operation isn't used frequently or on many platforms, so use manual
* division here */
return div64(us * TIMER_CLOCK_KHZ, KHZ_IN_MHZ);
#else
return us * TIMER_CLOCK_MHZ;
#endif
}
static inline CONST ticks_t getTimerPrecision(void)
{
return usToTicks(TIMER_PRECISION);
}
#else /* CONFIG_KERNEL_MCS */
#include <mode/machine/timer.h>
#include <plat/machine/hardware.h>
@@ -29,5 +71,6 @@
#endif
void initTimer(void);
#endif
#endif /* __ARCH_MACHINE_TIMER_H_ */

View File

@@ -487,6 +487,10 @@ static BOOT_CODE bool_t try_init_kernel(
}
write_it_asid_pool(it_ap_cap, it_pd_cap);
#ifdef CONFIG_KERNEL_MCS
NODE_STATE(ksCurTime) = getCurrentTime();
#endif
/* create the idle thread */
if (!create_idle_thread()) {
return false;

View File

@@ -13,7 +13,13 @@
#ifndef __ARM_PLAT_H
#define __ARM_PLAT_H
#include <autoconf.h>
#define TIMER_CLOCK_HZ @CONFIGURE_TIMER_FREQUENCY@
#define CLK_MAGIC @CONFIGURE_CLK_MAGIC@
#define CLK_SHIFT @CONFIGURE_CLK_SHIFT@
#define TIMER_PRECISION @CONFIGURE_TIMER_PRECISION@
enum IRQConstants {
maxIRQ = @CONFIGURE_MAX_IRQ@
} platform_interrupt_t;
@@ -27,4 +33,12 @@ enum IRQConstants {
#if (defined(CONFIGURE_SMMU) && defined(CONFIG_ARM_SMMU))
#include CONFIGURE_SMMU
#endif
#ifdef CONFIG_KERNEL_MCS
static inline CONST time_t getKernelWcetUs(void)
{
return @CONFIGURE_KERNEL_WCET@;
}
#endif
#endif /* !__ARM_PLAT_H */