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. Despite of the fact that sbi_set_timer_v01 is introduced and used as fall back, SBI v0.1 still isn't fully supported (with the current SBI calls usage, sbi_rfence_v01 should be introduced too), so panic() in sbi_init() isn't removed. 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. Use dprintk() for all the cases to print that a speicifc SBI extension is available as it isn't really necessary in case of release builds. Signed-off-by: Oleksii Kurochko <[email protected]> --- Changes in v3: - Init sbi_set_timer with sbi_set_timer_v01 as fallback value. - Sort SBI IDs in the same way as SBI EXT IDs are declared. - Add __ro_after_init for sbi_set_timer variable. - use dprintk instead of printk to print information if SBI ext is available. --- 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, 57 insertions(+), 1 deletion(-) diff --git a/xen/arch/riscv/include/asm/sbi.h b/xen/arch/riscv/include/asm/sbi.h index 79f7ff5c5501..a237f8b1393c 100644 --- a/xen/arch/riscv/include/asm/sbi.h +++ b/xen/arch/riscv/include/asm/sbi.h @@ -29,6 +29,7 @@ #define SBI_EXT_BASE 0x10 #define SBI_EXT_RFENCE 0x52464E43 +#define SBI_EXT_TIME 0x54494D45 /* SBI function IDs for BASE extension */ #define SBI_EXT_BASE_GET_SPEC_VERSION 0x0 @@ -48,6 +49,9 @@ #define SBI_EXT_RFENCE_REMOTE_HFENCE_VVMA 0x5 #define SBI_EXT_RFENCE_REMOTE_HFENCE_VVMA_ASID 0x6 +/* SBI function IDs for TIME extension */ +#define SBI_EXT_TIME_SET_TIMER 0x0 + #define SBI_SPEC_VERSION_MAJOR_MASK 0x7f000000 #define SBI_SPEC_VERSION_MINOR_MASK 0x00ffffff @@ -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 (* __ro_after_init 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..b4a7ae6940c1 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) = sbi_set_timer_v01; + int sbi_remote_sfence_vma(const cpumask_t *cpu_mask, vaddr_t start, size_t size) { @@ -324,7 +356,13 @@ int __init sbi_init(void) if ( sbi_probe_extension(SBI_EXT_RFENCE) > 0 ) { sbi_rfence = sbi_rfence_v02; - printk("SBI v0.2 RFENCE extension detected\n"); + dprintk(XENLOG_INFO, "SBI v0.2 RFENCE extension detected\n"); + } + + if ( sbi_probe_extension(SBI_EXT_TIME) > 0 ) + { + sbi_set_timer = sbi_set_timer_v02; + dprintk(XENLOG_INFO, "SBI v0.2 TIME extension detected\n"); } } else -- 2.52.0
