[PATCH 5/5] lib: sbi: add Xtheadsstc support
Xiang W
wxjstz at 126.com
Sun Apr 13 08:06:20 PDT 2025
There is an implementation similar to sstc on thead. The difference
between it and sstc is that stimecmp is a memory-mapped register on
thead.
Signed-off-by: Xiang W <wxjstz at 126.com>
---
include/sbi/sbi_hart.h | 2 ++
lib/sbi/sbi_hart.c | 1 +
lib/sbi/sbi_timer.c | 18 ++++++++++-
lib/utils/timer/aclint_mtimer.c | 55 ++++++++++++++++++---------------
4 files changed, 50 insertions(+), 26 deletions(-)
diff --git a/include/sbi/sbi_hart.h b/include/sbi/sbi_hart.h
index 4c36c778..ba6debb8 100644
--- a/include/sbi/sbi_hart.h
+++ b/include/sbi/sbi_hart.h
@@ -37,6 +37,8 @@ enum sbi_hart_extensions {
SBI_HART_EXT_SSCOFPMF,
/** HART has Sstc extension */
SBI_HART_EXT_SSTC,
+ /** HART has Xtheadsstc extension */
+ SBI_HART_EXT_XTHEADSSTC,
/** HART has Zicntr extension (i.e. HW cycle, time & instret CSRs) */
SBI_HART_EXT_ZICNTR,
/** HART has Zihpm extension */
diff --git a/lib/sbi/sbi_hart.c b/lib/sbi/sbi_hart.c
index 8e2979b5..32726916 100644
--- a/lib/sbi/sbi_hart.c
+++ b/lib/sbi/sbi_hart.c
@@ -669,6 +669,7 @@ const struct sbi_hart_ext_data sbi_hart_ext[] = {
__SBI_HART_EXT_DATA(smstateen, SBI_HART_EXT_SMSTATEEN),
__SBI_HART_EXT_DATA(sscofpmf, SBI_HART_EXT_SSCOFPMF),
__SBI_HART_EXT_DATA(sstc, SBI_HART_EXT_SSTC),
+ __SBI_HART_EXT_DATA(xtheadsstc, SBI_HART_EXT_XTHEADSSTC),
__SBI_HART_EXT_DATA(zicntr, SBI_HART_EXT_ZICNTR),
__SBI_HART_EXT_DATA(zihpm, SBI_HART_EXT_ZIHPM),
__SBI_HART_EXT_DATA(zkr, SBI_HART_EXT_ZKR),
diff --git a/lib/sbi/sbi_timer.c b/lib/sbi/sbi_timer.c
index 5351e9e7..e299721d 100644
--- a/lib/sbi/sbi_timer.c
+++ b/lib/sbi/sbi_timer.c
@@ -146,13 +146,28 @@ void sbi_timer_set_delta_upper(ulong delta_upper)
void sbi_timer_event_start(u64 next_event)
{
+ struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
sbi_pmu_ctr_incr_fw(SBI_PMU_FW_SET_TIMER);
+ /**
+ * xtheadsstc is implemented earlier than sstc. Accessing stimecmp on
+ * thead does not trigger an exception, so opensbi will succeed in
+ * detecting sstc on thead, but the stimecmp csr is not positive and
+ * valid. Therefore, this code needs to be reversed before checking the
+ * sstc extension. */
+ if (sbi_hart_has_extension(scratch, SBI_HART_EXT_XTHEADSSTC)) {
+ if (timer_dev && timer_dev->timer_event_start) {
+ timer_dev->timer_event_start(next_event);
+ return;
+ }
+ goto notfound_device;
+ }
+
/**
* Update the stimecmp directly if available. This allows
* the older software to leverage sstc extension on newer hardware.
*/
- if (sbi_hart_has_extension(sbi_scratch_thishart_ptr(), SBI_HART_EXT_SSTC)) {
+ if (sbi_hart_has_extension(scratch, SBI_HART_EXT_SSTC)) {
#if __riscv_xlen == 32
csr_write(CSR_STIMECMP, next_event & 0xFFFFFFFF);
csr_write(CSR_STIMECMPH, next_event >> 32);
@@ -169,6 +184,7 @@ void sbi_timer_event_start(u64 next_event)
return;
}
+notfound_device:
sbi_printf("%s: called without timer device\n", __func__);
}
diff --git a/lib/utils/timer/aclint_mtimer.c b/lib/utils/timer/aclint_mtimer.c
index 3db3c3be..573b9313 100644
--- a/lib/utils/timer/aclint_mtimer.c
+++ b/lib/utils/timer/aclint_mtimer.c
@@ -13,6 +13,7 @@
#include <sbi/sbi_bitops.h>
#include <sbi/sbi_domain.h>
#include <sbi/sbi_error.h>
+#include <sbi/sbi_hart.h>
#include <sbi/sbi_scratch.h>
#include <sbi/sbi_timer.h>
#include <sbi_utils/timer/aclint_mtimer.h>
@@ -56,7 +57,7 @@ static void mtimer_time_wr32(bool timecmp, u64 value, volatile u64 *addr)
writel_relaxed((u32)value, (void *)(addr));
}
-static u64 mtimer_value(void)
+static u64 timer_value(void)
{
struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
struct aclint_mtimer_data *mt;
@@ -69,7 +70,7 @@ static u64 mtimer_value(void)
return mt->time_rd((void *)mt->mtime_addr);
}
-static void mtimer_event_stop(void)
+static void timercmp_write(bool has_xtheadsstc, u64 val)
{
u32 target_hart = current_hartid();
struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
@@ -80,33 +81,37 @@ static void mtimer_event_stop(void)
if (!mt)
return;
- /* Clear MTIMER Time Compare */
- time_cmp = (void *)mt->mtimecmp_addr;
- mt->time_wr(true, -1ULL, &time_cmp[target_hart - mt->first_hartid]);
+ /*
+ * On xtheadsstc, stimecmp is a memory mapped register like mtimecmp,
+ * and the address of stimecmp is offset from the address of mtimecmp
+ * by 0x9000.
+ */
+ if (has_xtheadsstc)
+ time_cmp = (void *)(mt->mtimecmp_addr + 0x9000);
+ else
+ time_cmp = (void *)mt->mtimecmp_addr;
+
+ mt->time_wr(true, val, &time_cmp[target_hart - mt->first_hartid]);
}
-static void mtimer_event_start(u64 next_event)
+static void timer_event_start(u64 next_event)
{
- u32 target_hart = current_hartid();
struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
- struct aclint_mtimer_data *mt;
- u64 *time_cmp;
-
- mt = mtimer_get_hart_data_ptr(scratch);
- if (!mt)
- return;
+ bool has_xtheadsstc =
+ sbi_hart_has_extension(scratch, SBI_HART_EXT_XTHEADSSTC);
+ timercmp_write(has_xtheadsstc, next_event);
+}
- /* Program MTIMER Time Compare */
- time_cmp = (void *)mt->mtimecmp_addr;
- mt->time_wr(true, next_event,
- &time_cmp[target_hart - mt->first_hartid]);
+static void timer_event_stop(void)
+{
+ timer_event_start(__UINT64_MAX__);
}
-static struct sbi_timer_device mtimer = {
+static struct sbi_timer_device timer_dev = {
.name = "aclint-mtimer",
- .timer_value = mtimer_value,
- .timer_event_start = mtimer_event_start,
- .timer_event_stop = mtimer_event_stop
+ .timer_value = timer_value,
+ .timer_event_start = timer_event_start,
+ .timer_event_stop = timer_event_stop
};
void aclint_mtimer_sync(struct aclint_mtimer_data *mt)
@@ -219,7 +224,7 @@ int aclint_mtimer_cold_init(struct aclint_mtimer_data *mt,
if (!mt->mtime_size) {
/* Disable reading mtime when mtime is not available */
- mtimer.timer_value = NULL;
+ timer_dev.timer_value = NULL;
}
/* Add MTIMER regions to the root domain */
@@ -259,9 +264,9 @@ int aclint_mtimer_cold_init(struct aclint_mtimer_data *mt,
return rc;
}
- mtimer.timer_freq = mt->mtime_freq;
- mtimer.warm_init = aclint_mtimer_warm_init;
- sbi_timer_set_device(&mtimer);
+ timer_dev.timer_freq = mt->mtime_freq;
+ timer_dev.warm_init = aclint_mtimer_warm_init;
+ sbi_timer_set_device(&timer_dev);
return 0;
}
--
2.47.2
More information about the opensbi
mailing list