Introduce a function pointer for sbi_set_timer(), since different OpenSBI versions may implement the TIME extension with different extension IDs and/or function IDs.
If the TIME extension is not available, fall back to the legacy timer mechanism. This is useful when Xen runs as a guest under another Xen, because the TIME extension is not currently virtualised and therefore will not appear as available. The sbi_set_timer() pointer will be used by reprogram_timer() to program Xen’s physical timer as without SSTC extension there is no any other option except SBI call to do that as only M-timer is available for us. Signed-off-by: Oleksii Kurochko <[email protected]> --- Changes in v2: - Move up defintion of SBI_EXT_TIME_SET_TIMER and use the same padding as defintions around it. - Add an extra comment about stime_value granuality above declaration of sbi_set_timer function pointer. - Refactor implemetation of sbi_set_timer_v02(). - Provide fallback for sbi_set_timer_v01(). - Update the commit message. --- xen/arch/riscv/include/asm/sbi.h | 18 ++++++++++++++ xen/arch/riscv/sbi.c | 40 ++++++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+) diff --git a/xen/arch/riscv/include/asm/sbi.h b/xen/arch/riscv/include/asm/sbi.h index 79f7ff5c5501..e0e31d7afa20 100644 --- a/xen/arch/riscv/include/asm/sbi.h +++ b/xen/arch/riscv/include/asm/sbi.h @@ -29,6 +29,10 @@ #define SBI_EXT_BASE 0x10 #define SBI_EXT_RFENCE 0x52464E43 +#define SBI_EXT_TIME 0x54494D45 + +/* SBI function IDs for TIME extension */ +#define SBI_EXT_TIME_SET_TIMER 0x0 /* SBI function IDs for BASE extension */ #define SBI_EXT_BASE_GET_SPEC_VERSION 0x0 @@ -134,6 +138,20 @@ int sbi_remote_hfence_gvma(const cpumask_t *cpu_mask, vaddr_t start, int sbi_remote_hfence_gvma_vmid(const cpumask_t *cpu_mask, vaddr_t start, size_t size, unsigned long vmid); +/* + * Programs the clock for next event after stime_value time. This function also + * clears the pending timer interrupt bit. + * If the supervisor wishes to clear the timer interrupt without scheduling the + * next timer event, it can either request a timer interrupt infinitely far + * into the future (i.e., (uint64_t)-1), or it can instead mask the timer + * interrupt by clearing sie.STIE CSR bit. + * The stime_value parameter represents absolute time measured in ticks. + * + * This SBI call returns 0 upon success or an implementation specific negative + * error code. + */ +extern int (*sbi_set_timer)(uint64_t stime_value); + /* * Initialize SBI library * diff --git a/xen/arch/riscv/sbi.c b/xen/arch/riscv/sbi.c index 425dce44c679..2c7757c8839f 100644 --- a/xen/arch/riscv/sbi.c +++ b/xen/arch/riscv/sbi.c @@ -249,6 +249,38 @@ static int (* __ro_after_init sbi_rfence)(unsigned long fid, unsigned long arg4, unsigned long arg5); +static int cf_check sbi_set_timer_v02(uint64_t stime_value) +{ + struct sbiret ret; + + ret = sbi_ecall(SBI_EXT_TIME, SBI_EXT_TIME_SET_TIMER, stime_value, +#ifdef CONFIG_RISCV_32 + stime_value >> 32, +#else + 0, +#endif + 0, 0, 0, 0); + + return sbi_err_map_xen_errno(ret.error); +} + +static int cf_check sbi_set_timer_v01(uint64_t stime_value) +{ + struct sbiret ret; + + ret = sbi_ecall(SBI_EXT_0_1_SET_TIMER, 0, stime_value, +#ifdef CONFIG_RISCV_32 + stime_value >> 32, +#else + 0, +#endif + 0, 0, 0, 0); + + return sbi_err_map_xen_errno(ret.error); +} + +int (* __ro_after_init sbi_set_timer)(uint64_t stime_value); + int sbi_remote_sfence_vma(const cpumask_t *cpu_mask, vaddr_t start, size_t size) { @@ -326,6 +358,14 @@ int __init sbi_init(void) sbi_rfence = sbi_rfence_v02; printk("SBI v0.2 RFENCE extension detected\n"); } + + if ( sbi_probe_extension(SBI_EXT_TIME) > 0 ) + { + sbi_set_timer = sbi_set_timer_v02; + printk("SBI v0.2 TIME extension detected\n"); + } + else + sbi_set_timer = sbi_set_timer_v01; } else panic("Ooops. SBI spec version 0.1 detected. Need to add support"); -- 2.52.0
