summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAtish Patra <atishp@rivosinc.com>2022-04-26 09:29:22 +0300
committerAnup Patel <anup@brainfault.org>2022-04-28 09:15:21 +0300
commitd62f6da062ad0fcc3bdc042a3f3b200d91d18afd (patch)
treec26f03e59440fd15c0b6639633645dcd45114b76
parent4035ae94be802a68f8e8408a84b77f531d59416b (diff)
downloadopensbi-d62f6da062ad0fcc3bdc042a3f3b200d91d18afd.tar.xz
lib: sbi: Implement Sstc extension
Recently, Sstc extension was ratified. It defines stimecmp which allows the supervisor mode to directly update the timecmp value without the need of the SBI call. The hardware also can inject the S-mode timer interrupt direclty to the supervisor without going through the M-mode. To maintain backward compatibility with the older software, SBI call now uses stimecmp directly if the hardware supports. Implement the Sstc extension. Signed-off-by: Atish Patra <atishp@rivosinc.com> Reviewed-by: Anup Patel <anup@brainfault.org>
-rw-r--r--include/sbi/riscv_encoding.h4
-rw-r--r--include/sbi/sbi_hart.h4
-rw-r--r--lib/sbi/sbi_hart.c28
-rw-r--r--lib/sbi/sbi_timer.c25
4 files changed, 57 insertions, 4 deletions
diff --git a/include/sbi/riscv_encoding.h b/include/sbi/riscv_encoding.h
index a9772a6..7cfbace 100644
--- a/include/sbi/riscv_encoding.h
+++ b/include/sbi/riscv_encoding.h
@@ -324,6 +324,10 @@
#define CSR_STVAL 0x143
#define CSR_SIP 0x144
+/* Sstc extension */
+#define CSR_STIMECMP 0x14D
+#define CSR_STIMECMPH 0x15D
+
/* Supervisor Protection and Translation */
#define CSR_SATP 0x180
diff --git a/include/sbi/sbi_hart.h b/include/sbi/sbi_hart.h
index be3ad9f..1d09374 100644
--- a/include/sbi/sbi_hart.h
+++ b/include/sbi/sbi_hart.h
@@ -30,9 +30,11 @@ enum sbi_hart_features {
SBI_HART_HAS_MENVCFG = (1 << 6),
/** HART has mstateen CSR **/
SBI_HART_HAS_SMSTATEEN = (1 << 7),
+ /** HART has SSTC extension implemented in hardware */
+ SBI_HART_HAS_SSTC = (1 << 8),
/** Last index of Hart features*/
- SBI_HART_HAS_LAST_FEATURE = SBI_HART_HAS_SMSTATEEN,
+ SBI_HART_HAS_LAST_FEATURE = SBI_HART_HAS_SSTC,
};
struct sbi_scratch;
diff --git a/lib/sbi/sbi_hart.c b/lib/sbi/sbi_hart.c
index 891fa18..a50b6e4 100644
--- a/lib/sbi/sbi_hart.c
+++ b/lib/sbi/sbi_hart.c
@@ -147,6 +147,22 @@ static void mstatus_init(struct sbi_scratch *scratch)
menvcfg_val |= ENVCFG_PBMTE;
#endif
+ /*
+ * The spec doesn't explicitly describe the reset value of menvcfg.
+ * Enable access to stimecmp if sstc extension is present in the
+ * hardware.
+ */
+ if (sbi_hart_has_feature(scratch, SBI_HART_HAS_SSTC)) {
+#if __riscv_xlen == 32
+ unsigned long menvcfgh_val;
+ menvcfgh_val = csr_read(CSR_MENVCFGH);
+ menvcfgh_val |= ENVCFGH_STCE;
+ csr_write(CSR_MENVCFGH, menvcfgh_val);
+#else
+ menvcfg_val |= ENVCFG_STCE;
+#endif
+ }
+
csr_write(CSR_MENVCFG, menvcfg_val);
}
@@ -367,6 +383,8 @@ static inline char *sbi_hart_feature_id2string(unsigned long feature)
break;
case SBI_HART_HAS_AIA:
fstr = "aia";
+ case SBI_HART_HAS_SSTC:
+ fstr = "sstc";
break;
case SBI_HART_HAS_MENVCFG:
fstr = "menvcfg";
@@ -610,6 +628,16 @@ __aia_skip:
if (!trap.cause)
hfeatures->features |= SBI_HART_HAS_MENVCFG;
+ /**
+ * Detect if hart supports stimecmp CSR(Sstc extension) and menvcfg is
+ * implemented.
+ */
+ if (hfeatures->features & SBI_HART_HAS_MENVCFG) {
+ csr_read_allowed(CSR_STIMECMP, (unsigned long)&trap);
+ if (!trap.cause)
+ hfeatures->features |= SBI_HART_HAS_SSTC;
+ }
+
/* Detect if hart supports mstateen CSRs */
val = csr_read_allowed(CSR_MSTATEEN0, (unsigned long)&trap);
if (!trap.cause)
diff --git a/lib/sbi/sbi_timer.c b/lib/sbi/sbi_timer.c
index acdba92..bf0f375 100644
--- a/lib/sbi/sbi_timer.c
+++ b/lib/sbi/sbi_timer.c
@@ -124,16 +124,35 @@ void sbi_timer_set_delta_upper(ulong delta_upper)
void sbi_timer_event_start(u64 next_event)
{
sbi_pmu_ctr_incr_fw(SBI_PMU_FW_SET_TIMER);
- if (timer_dev && timer_dev->timer_event_start)
+
+ /**
+ * Update the stimecmp directly if available. This allows
+ * the older software to leverage sstc extension on newer hardware.
+ */
+ if (sbi_hart_has_feature(sbi_scratch_thishart_ptr(), SBI_HART_HAS_SSTC)) {
+#if __riscv_xlen == 32
+ csr_write(CSR_STIMECMP, next_event & 0xFFFFFFFF);
+ csr_write(CSR_STIMECMPH, next_event >> 32);
+#else
+ csr_write(CSR_STIMECMP, next_event);
+#endif
+ } else if (timer_dev && timer_dev->timer_event_start) {
timer_dev->timer_event_start(next_event);
- csr_clear(CSR_MIP, MIP_STIP);
+ csr_clear(CSR_MIP, MIP_STIP);
+ }
csr_set(CSR_MIE, MIP_MTIP);
}
void sbi_timer_process(void)
{
csr_clear(CSR_MIE, MIP_MTIP);
- csr_set(CSR_MIP, MIP_STIP);
+ /*
+ * If sstc extension is available, supervisor can receive the timer
+ * directly without M-mode come in between. This function should
+ * only invoked if M-mode programs the timer for its own purpose.
+ */
+ if (!sbi_hart_has_feature(sbi_scratch_thishart_ptr(), SBI_HART_HAS_SSTC))
+ csr_set(CSR_MIP, MIP_STIP);
}
const struct sbi_timer_device *sbi_timer_get_device(void)