summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPalmer Dabbelt <palmer@rivosinc.com>2022-08-11 14:41:52 -0700
committerPalmer Dabbelt <palmer@rivosinc.com>2022-08-11 14:41:52 -0700
commit7ab52f75a9cf7fed7ba85802b986825dd72df641 (patch)
tree7925addedc2d883212d80f000d16a683c0984681
parent3dbe5829408bc1586f75b4667ef60e5aab0209c7 (diff)
parent9f7a8ff6391fd5363363b8e5c8b1462a07922368 (diff)
RISC-V: Add Sstc extension support
This series implements Sstc extension support which was ratified recently. Before the Sstc extension, an SBI call is necessary to generate timer interrupts as only M-mode have access to the timecompare registers. Thus, there is significant latency to generate timer interrupts at kernel. For virtualized enviornments, its even worse as the KVM handles the SBI call and uses a software timer to emulate the timecomapre register. Sstc extension solves both these problems by defining a stimecmp/vstimecmp at supervisor (host/guest) level. It allows kernel to program a timer and recieve interrupt without supervisor execution enviornment (M-mode/HS mode) intervention. * palmer/riscv-sstc: RISC-V: Prefer sstc extension if available RISC-V: Enable sstc extension parsing from DT RISC-V: Add SSTC extension CSR details
-rw-r--r--arch/riscv/include/asm/csr.h5
-rw-r--r--arch/riscv/include/asm/hwcap.h1
-rw-r--r--arch/riscv/kernel/cpu.c1
-rw-r--r--arch/riscv/kernel/cpufeature.c1
-rw-r--r--drivers/clocksource/timer-riscv.c25
5 files changed, 32 insertions, 1 deletions
diff --git a/arch/riscv/include/asm/csr.h b/arch/riscv/include/asm/csr.h
index 17516afc389a..0e571f6483d9 100644
--- a/arch/riscv/include/asm/csr.h
+++ b/arch/riscv/include/asm/csr.h
@@ -247,6 +247,9 @@
#define CSR_SIP 0x144
#define CSR_SATP 0x180
+#define CSR_STIMECMP 0x14D
+#define CSR_STIMECMPH 0x15D
+
#define CSR_VSSTATUS 0x200
#define CSR_VSIE 0x204
#define CSR_VSTVEC 0x205
@@ -256,6 +259,8 @@
#define CSR_VSTVAL 0x243
#define CSR_VSIP 0x244
#define CSR_VSATP 0x280
+#define CSR_VSTIMECMP 0x24D
+#define CSR_VSTIMECMPH 0x25D
#define CSR_HSTATUS 0x600
#define CSR_HEDELEG 0x602
diff --git a/arch/riscv/include/asm/hwcap.h b/arch/riscv/include/asm/hwcap.h
index 3c8a5ca95c72..6f59ec64175e 100644
--- a/arch/riscv/include/asm/hwcap.h
+++ b/arch/riscv/include/asm/hwcap.h
@@ -57,6 +57,7 @@ enum riscv_isa_ext_id {
RISCV_ISA_EXT_SVPBMT,
RISCV_ISA_EXT_ZICBOM,
RISCV_ISA_EXT_ZIHINTPAUSE,
+ RISCV_ISA_EXT_SSTC,
RISCV_ISA_EXT_ID_MAX = RISCV_ISA_EXT_MAX,
};
diff --git a/arch/riscv/kernel/cpu.c b/arch/riscv/kernel/cpu.c
index a77c380703c5..0be8a2403212 100644
--- a/arch/riscv/kernel/cpu.c
+++ b/arch/riscv/kernel/cpu.c
@@ -95,6 +95,7 @@ static struct riscv_isa_ext_data isa_ext_arr[] = {
__RISCV_ISA_EXT_DATA(svpbmt, RISCV_ISA_EXT_SVPBMT),
__RISCV_ISA_EXT_DATA(zicbom, RISCV_ISA_EXT_ZICBOM),
__RISCV_ISA_EXT_DATA(zihintpause, RISCV_ISA_EXT_ZIHINTPAUSE),
+ __RISCV_ISA_EXT_DATA(sstc, RISCV_ISA_EXT_SSTC),
__RISCV_ISA_EXT_DATA("", RISCV_ISA_EXT_MAX),
};
diff --git a/arch/riscv/kernel/cpufeature.c b/arch/riscv/kernel/cpufeature.c
index c233fbc5b873..553d755483ed 100644
--- a/arch/riscv/kernel/cpufeature.c
+++ b/arch/riscv/kernel/cpufeature.c
@@ -203,6 +203,7 @@ void __init riscv_fill_hwcap(void)
SET_ISA_EXT_MAP("svpbmt", RISCV_ISA_EXT_SVPBMT);
SET_ISA_EXT_MAP("zicbom", RISCV_ISA_EXT_ZICBOM);
SET_ISA_EXT_MAP("zihintpause", RISCV_ISA_EXT_ZIHINTPAUSE);
+ SET_ISA_EXT_MAP("sstc", RISCV_ISA_EXT_SSTC);
}
#undef SET_ISA_EXT_MAP
}
diff --git a/drivers/clocksource/timer-riscv.c b/drivers/clocksource/timer-riscv.c
index e460df7ed799..969a552da8d2 100644
--- a/drivers/clocksource/timer-riscv.c
+++ b/drivers/clocksource/timer-riscv.c
@@ -7,6 +7,9 @@
* either be read from the "time" and "timeh" CSRs, and can use the SBI to
* setup events, or directly accessed using MMIO registers.
*/
+
+#define pr_fmt(fmt) "riscv-timer: " fmt
+
#include <linux/clocksource.h>
#include <linux/clockchips.h>
#include <linux/cpu.h>
@@ -20,14 +23,28 @@
#include <linux/of_irq.h>
#include <clocksource/timer-riscv.h>
#include <asm/smp.h>
+#include <asm/hwcap.h>
#include <asm/sbi.h>
#include <asm/timex.h>
+static DEFINE_STATIC_KEY_FALSE(riscv_sstc_available);
+
static int riscv_clock_next_event(unsigned long delta,
struct clock_event_device *ce)
{
+ u64 next_tval = get_cycles64() + delta;
+
csr_set(CSR_IE, IE_TIE);
- sbi_set_timer(get_cycles64() + delta);
+ if (static_branch_likely(&riscv_sstc_available)) {
+#if defined(CONFIG_32BIT)
+ csr_write(CSR_STIMECMP, next_tval & 0xFFFFFFFF);
+ csr_write(CSR_STIMECMPH, next_tval >> 32);
+#else
+ csr_write(CSR_STIMECMP, next_tval);
+#endif
+ } else
+ sbi_set_timer(next_tval);
+
return 0;
}
@@ -166,6 +183,12 @@ static int __init riscv_timer_init_dt(struct device_node *n)
if (error)
pr_err("cpu hp setup state failed for RISCV timer [%d]\n",
error);
+
+ if (riscv_isa_extension_available(NULL, SSTC)) {
+ pr_info("Timer interrupt in S-mode is available via sstc extension\n");
+ static_branch_enable(&riscv_sstc_available);
+ }
+
return error;
}