summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/sbi/Kconfig9
-rw-r--r--lib/sbi/sbi_dbtr.c166
-rw-r--r--lib/sbi/sbi_domain_context.c3
-rw-r--r--lib/sbi/sbi_ecall.c2
-rw-r--r--lib/sbi/sbi_hart_pmp.c13
-rw-r--r--lib/sbi/sbi_hart_protection.c153
-rw-r--r--lib/sbi/sbi_init.c18
-rw-r--r--lib/sbi/sbi_mpxy.c53
-rw-r--r--lib/sbi/sbi_sse.c13
-rw-r--r--lib/sbi/sbi_timer.c12
-rw-r--r--lib/sbi/sbi_tlb.c46
-rw-r--r--lib/sbi/tests/sbi_ecall_test.c59
-rw-r--r--lib/utils/cache/fdt_andes_llcache.c23
-rw-r--r--lib/utils/cppc/fdt_cppc_rpmi.c44
-rw-r--r--lib/utils/hsm/fdt_hsm_andes_atcsmu.c64
-rw-r--r--lib/utils/mpxy/fdt_mpxy_rpmi_logging.c2
-rw-r--r--lib/utils/mpxy/fdt_mpxy_rpmi_mbox.c2
-rw-r--r--lib/utils/mpxy/fdt_mpxy_rpmi_mm.c9
-rw-r--r--lib/utils/reset/Kconfig4
-rw-r--r--lib/utils/reset/fdt_reset_metanoia.c72
-rw-r--r--lib/utils/reset/objects.mk3
-rw-r--r--lib/utils/suspend/fdt_suspend_andes_atcsmu.c70
22 files changed, 695 insertions, 145 deletions
diff --git a/lib/sbi/Kconfig b/lib/sbi/Kconfig
index e76aecca..24132eaa 100644
--- a/lib/sbi/Kconfig
+++ b/lib/sbi/Kconfig
@@ -2,6 +2,15 @@
menu "Generic SBI Support"
+config HARTMASK_MAX_BITS
+ int "Maximum number of hart mask bits (32-512)"
+ range 32 512
+ default 256
+ help
+ The hartmask is indexed using physical hart IDs so this setting
+ also represents the maximum number of hart IDs generic OpenSBI
+ can handle.
+
config DEFAULT_HART_STACK_SIZE
int "Default per-HART stack size (bytes)"
range 8192 1048576
diff --git a/lib/sbi/sbi_dbtr.c b/lib/sbi/sbi_dbtr.c
index 01047969..4fd7fb5e 100644
--- a/lib/sbi/sbi_dbtr.c
+++ b/lib/sbi/sbi_dbtr.c
@@ -24,6 +24,22 @@
/** Offset of pointer to HART's debug triggers info in scratch space */
static unsigned long hart_state_ptr_offset;
+/** Device specific debug trigger operations */
+static const struct sbi_dbtr_device *dbtr_dev = NULL;
+
+const struct sbi_dbtr_device *sbi_dbtr_get_device(void)
+{
+ return dbtr_dev;
+}
+
+void sbi_dbtr_set_device(const struct sbi_dbtr_device *dev)
+{
+ if (!dev || dbtr_dev)
+ return;
+
+ dbtr_dev = dev;
+}
+
#define dbtr_get_hart_state_ptr(__scratch) \
sbi_scratch_read_type((__scratch), void *, hart_state_ptr_offset)
@@ -105,10 +121,75 @@ static void sbi_trigger_init(struct sbi_dbtr_trigger *trig,
trig->index = idx;
}
-static inline struct sbi_dbtr_trigger *sbi_alloc_trigger(void)
+static bool dbtr_trigger_hw_supported(unsigned long idx, unsigned long tdata1,
+ unsigned long tdata2,
+ unsigned long tdata3)
+{
+ if (dbtr_dev && dbtr_dev->trigger_supported)
+ return dbtr_dev->trigger_supported(idx, tdata1, tdata2,
+ tdata3);
+
+ return true;
+}
+
+static bool dbtr_trigger_any_hw_supported(
+ struct sbi_dbtr_hart_triggers_state *hs,
+ unsigned long tdata1, unsigned long tdata2,
+ unsigned long tdata3)
+{
+ unsigned long type = TDATA1_GET_TYPE(tdata1);
+ struct sbi_dbtr_trigger *trig;
+ int i;
+
+ for (i = 0; i < hs->total_trigs; i++) {
+ trig = INDEX_TO_TRIGGER(i);
+ if (__test_bit(type, &trig->type_mask) &&
+ dbtr_trigger_hw_supported(trig->index, tdata1, tdata2,
+ tdata3))
+ return true;
+ }
+
+ return false;
+}
+
+/*
+ * Find the first free hardware trigger slot supporting the configuration.
+ * Slots set in claimed_mask are treated as taken, which allows the caller
+ * to track slot availability. A 32-bit mask covers RV_MAX_TRIGGERS (32);
+ * for a larger number of triggers, this function needs to be updated.
+ */
+static int dbtr_find_free_slot(struct sbi_dbtr_hart_triggers_state *hs,
+ u32 claimed_mask,
+ unsigned long tdata1, unsigned long tdata2,
+ unsigned long tdata3)
+{
+ unsigned long type = TDATA1_GET_TYPE(tdata1);
+ struct sbi_dbtr_trigger *trig;
+ int i;
+
+ for (i = 0; i < hs->total_trigs; i++) {
+ trig = INDEX_TO_TRIGGER(i);
+ if (trig->state & RV_DBTR_BIT_MASK(TS, MAPPED))
+ continue;
+ if (claimed_mask & BIT(i))
+ continue;
+ if (!__test_bit(type, &trig->type_mask))
+ continue;
+ if (!dbtr_trigger_hw_supported(trig->index, tdata1,
+ tdata2, tdata3))
+ continue;
+ return i;
+ }
+
+ return SBI_ENOENT;
+}
+
+static inline struct sbi_dbtr_trigger *sbi_alloc_trigger(unsigned long tdata1,
+ unsigned long tdata2,
+ unsigned long tdata3)
{
int i;
- struct sbi_dbtr_trigger *f_trig = NULL;
+ struct sbi_dbtr_trigger *f_trig;
struct sbi_dbtr_hart_triggers_state *hart_state;
hart_state = dbtr_thishart_state_ptr();
@@ -118,17 +199,12 @@ static inline struct sbi_dbtr_trigger *sbi_alloc_trigger(void)
if (hart_state->available_trigs <= 0)
return NULL;
- for (i = 0; i < hart_state->total_trigs; i++) {
- f_trig = INDEX_TO_TRIGGER(i);
- if (f_trig->state & RV_DBTR_BIT_MASK(TS, MAPPED))
- continue;
- hart_state->available_trigs--;
- break;
- }
-
- if (i == hart_state->total_trigs)
+ i = dbtr_find_free_slot(hart_state, 0, tdata1, tdata2, tdata3);
+ if (i < 0)
return NULL;
+ f_trig = INDEX_TO_TRIGGER(i);
+ hart_state->available_trigs--;
__set_bit(RV_DBTR_BIT(TS, MAPPED), &f_trig->state);
return f_trig;
@@ -547,7 +623,8 @@ int sbi_dbtr_num_trig(unsigned long data, unsigned long *out)
for (i = 0; i < hs->total_trigs; i++) {
trig = INDEX_TO_TRIGGER(i);
- if (__test_bit(type, &trig->type_mask))
+ if (__test_bit(type, &trig->type_mask) &&
+ dbtr_trigger_hw_supported(trig->index, data, 0, 0))
total++;
}
@@ -573,7 +650,7 @@ int sbi_dbtr_read_trig(unsigned long smode,
if (trig_idx_base >= hs->total_trigs ||
trig_idx_base + trig_count >= hs->total_trigs)
- return SBI_ERR_INVALID_PARAM;
+ return SBI_ERR_BAD_RANGE;
if (sbi_dbtr_shmem_disabled(hs))
return SBI_ERR_NO_SHMEM;
@@ -608,6 +685,8 @@ int sbi_dbtr_install_trig(unsigned long smode,
struct sbi_dbtr_data_msg *recv;
struct sbi_dbtr_id_msg *xmit;
unsigned long ctrl;
+ u32 claimed = 0;
+ int slot;
struct sbi_dbtr_trigger *trig;
struct sbi_dbtr_hart_triggers_state *hs = NULL;
bool tdata2_impl, tdata3_impl;
@@ -626,8 +705,10 @@ int sbi_dbtr_install_trig(unsigned long smode,
/*
* SBI v3.0 sec 19.4 requires SBI_ERR_NOT_SUPPORTED when a trigger
* programs a non-zero value into an unimplemented optional CSR. Only
- * the "whole CSR unimplemented" case is caught; WARL bits tied off
- * inside an otherwise-implemented CSR are not.
+ * the "whole CSR unimplemented" case is caught here; WARL bits tied
+ * off inside an otherwise-implemented CSR are delegated to the
+ * device-specific trigger_supported() callback via
+ * dbtr_trigger_any_hw_supported().
*/
tdata2_impl = tdata_implemented(CSR_TDATA2);
tdata3_impl = tdata_implemented(CSR_TDATA3);
@@ -648,7 +729,7 @@ int sbi_dbtr_install_trig(unsigned long smode,
*out = _idx;
sbi_hart_protection_unmap_range((unsigned long)shmem_base,
trig_count * sizeof(*entry));
- return SBI_ERR_FAILED;
+ return SBI_ERR_INVALID_PARAM;
}
if ((recv->tdata2 && !tdata2_impl) ||
@@ -658,6 +739,16 @@ int sbi_dbtr_install_trig(unsigned long smode,
trig_count * sizeof(*entry));
return SBI_ERR_NOT_SUPPORTED;
}
+
+ if (!dbtr_trigger_any_hw_supported(hs,
+ lle_to_cpu(recv->tdata1),
+ lle_to_cpu(recv->tdata2),
+ lle_to_cpu(recv->tdata3))) {
+ *out = _idx;
+ sbi_hart_protection_unmap_range((unsigned long)shmem_base,
+ trig_count * sizeof(*entry));
+ return SBI_ERR_NOT_SUPPORTED;
+ }
}
if (hs->available_trigs < trig_count) {
@@ -667,17 +758,40 @@ int sbi_dbtr_install_trig(unsigned long smode,
return SBI_ERR_FAILED;
}
- /* Install triggers */
+ /*
+ * Dry-run the allocation of the whole batch so that no trigger
+ * is installed if any of the requested configurations cannot be
+ * matched to a free hardware trigger slot.
+ */
for_each_trig_entry(shmem_base, trig_count, typeof(*entry), entry) {
- /*
- * Since we have already checked if enough triggers are
- * available, trigger allocation must succeed.
- */
- trig = sbi_alloc_trigger();
+ recv = (struct sbi_dbtr_data_msg *)(&entry->data);
+ slot = dbtr_find_free_slot(hs, claimed,
+ lle_to_cpu(recv->tdata1),
+ lle_to_cpu(recv->tdata2),
+ lle_to_cpu(recv->tdata3));
+ if (slot < 0) {
+ *out = _idx;
+ sbi_hart_protection_unmap_range((unsigned long)shmem_base,
+ trig_count * sizeof(*entry));
+ return SBI_ERR_FAILED;
+ }
+ claimed |= BIT(slot);
+ }
+ /* Install triggers */
+ for_each_trig_entry(shmem_base, trig_count, typeof(*entry), entry) {
recv = (struct sbi_dbtr_data_msg *)(&entry->data);
xmit = (struct sbi_dbtr_id_msg *)(&entry->id);
+ /*
+ * The dry-run above matched every requested configuration
+ * to a free hardware trigger slot, so allocation must
+ * succeed.
+ */
+ trig = sbi_alloc_trigger(lle_to_cpu(recv->tdata1),
+ lle_to_cpu(recv->tdata2),
+ lle_to_cpu(recv->tdata3));
+
dbtr_trigger_setup(trig, recv);
dbtr_trigger_enable(trig);
xmit->idx = cpu_to_lle(trig->index);
@@ -789,6 +903,14 @@ int sbi_dbtr_update_trig(unsigned long smode,
return SBI_ERR_NOT_SUPPORTED;
}
+ if (!dbtr_trigger_hw_supported(trig->index,
+ lle_to_cpu(entry->data.tdata1),
+ lle_to_cpu(entry->data.tdata2),
+ lle_to_cpu(entry->data.tdata3))) {
+ sbi_hart_protection_unmap_range((unsigned long)entry, sizeof(*entry));
+ return SBI_ERR_NOT_SUPPORTED;
+ }
+
dbtr_trigger_setup(trig, &entry->data);
sbi_hart_protection_unmap_range((unsigned long)entry, sizeof(*entry));
dbtr_trigger_enable(trig);
diff --git a/lib/sbi/sbi_domain_context.c b/lib/sbi/sbi_domain_context.c
index cc4cc04d..0861d541 100644
--- a/lib/sbi/sbi_domain_context.c
+++ b/lib/sbi/sbi_domain_context.c
@@ -171,8 +171,7 @@ static int switch_to_next_domain_context(struct hart_context *ctx,
* is also required for some of the above CSR updates (such
* as satp CSR).
*/
- sbi_hart_protection_unconfigure(scratch);
- sbi_hart_protection_configure(scratch);
+ sbi_hart_protection_reconfigure(scratch, current_dom, target_dom);
/* Mark current context structure initialized because context saved */
ctx->initialized = true;
diff --git a/lib/sbi/sbi_ecall.c b/lib/sbi/sbi_ecall.c
index 745fa313..65c5a55a 100644
--- a/lib/sbi/sbi_ecall.c
+++ b/lib/sbi/sbi_ecall.c
@@ -66,6 +66,8 @@ void sbi_ecall_get_extensions_str(char *exts_str, int exts_str_size, bool experi
sbi_list_for_each_entry(t, &ecall_exts_list, head) {
if (experimental != t->experimental)
continue;
+ if (offset + sbi_strlen(t->name) + 1 > exts_str_size)
+ break;
sbi_snprintf(exts_str + offset, exts_str_size - offset,
"%s,", t->name);
offset = offset + sbi_strlen(t->name) + 1;
diff --git a/lib/sbi/sbi_hart_pmp.c b/lib/sbi/sbi_hart_pmp.c
index 4528258d..c0a4ce1b 100644
--- a/lib/sbi/sbi_hart_pmp.c
+++ b/lib/sbi/sbi_hart_pmp.c
@@ -228,10 +228,10 @@ static bool is_valid_pmp_idx(unsigned int pmp_count, unsigned int pmp_idx)
return false;
}
-static int sbi_hart_smepmp_configure(struct sbi_scratch *scratch)
+static int sbi_hart_smepmp_configure(struct sbi_scratch *scratch,
+ struct sbi_domain *dom)
{
struct sbi_domain_memregion *reg;
- struct sbi_domain *dom = sbi_domain_thishart_ptr();
unsigned int pmp_log2gran, pmp_bits;
unsigned int pmp_idx, pmp_count;
unsigned long pmp_addr_max;
@@ -366,10 +366,10 @@ static int sbi_hart_smepmp_unmap_range(struct sbi_scratch *scratch,
return sbi_hart_pmp_disable(SBI_SMEPMP_RESV_ENTRY);
}
-static int sbi_hart_oldpmp_configure(struct sbi_scratch *scratch)
+static int sbi_hart_oldpmp_configure(struct sbi_scratch *scratch,
+ struct sbi_domain *dom)
{
struct sbi_domain_memregion *reg;
- struct sbi_domain *dom = sbi_domain_thishart_ptr();
unsigned long pmp_addr, pmp_addr_max;
unsigned int pmp_log2gran, pmp_bits;
unsigned int pmp_idx, pmp_count;
@@ -407,7 +407,8 @@ static int sbi_hart_oldpmp_configure(struct sbi_scratch *scratch)
return 0;
}
-static void sbi_hart_pmp_unconfigure(struct sbi_scratch *scratch)
+static void sbi_hart_pmp_unconfigure(struct sbi_scratch *scratch,
+ struct sbi_domain *dom)
{
int i, pmp_count = sbi_hart_pmp_count(scratch);
@@ -424,6 +425,7 @@ static void sbi_hart_pmp_unconfigure(struct sbi_scratch *scratch)
static struct sbi_hart_protection pmp_protection = {
.name = "pmp",
.rating = 100,
+ .type = SBI_HART_PROTECTION_TYPE_MEMORY,
.configure = sbi_hart_oldpmp_configure,
.unconfigure = sbi_hart_pmp_unconfigure,
};
@@ -431,6 +433,7 @@ static struct sbi_hart_protection pmp_protection = {
static struct sbi_hart_protection epmp_protection = {
.name = "epmp",
.rating = 200,
+ .type = SBI_HART_PROTECTION_TYPE_MEMORY,
.configure = sbi_hart_smepmp_configure,
.unconfigure = sbi_hart_pmp_unconfigure,
.map_range = sbi_hart_smepmp_map_range,
diff --git a/lib/sbi/sbi_hart_protection.c b/lib/sbi/sbi_hart_protection.c
index fbebfd1a..c4c149c8 100644
--- a/lib/sbi/sbi_hart_protection.c
+++ b/lib/sbi/sbi_hart_protection.c
@@ -4,18 +4,50 @@
* Copyright (c) 2025 Ventana Micro Systems Inc.
*/
+#include <sbi/sbi_console.h>
#include <sbi/sbi_error.h>
#include <sbi/sbi_hart_protection.h>
#include <sbi/sbi_scratch.h>
+#include <sbi/sbi_string.h>
static SBI_LIST_HEAD(hart_protection_list);
-struct sbi_hart_protection *sbi_hart_protection_best(void)
+static struct sbi_hart_protection *__hart_memory_protection_best(void)
{
- if (sbi_list_empty(&hart_protection_list))
- return NULL;
+ struct sbi_hart_protection *pos;
- return sbi_list_first_entry(&hart_protection_list, struct sbi_hart_protection, head);
+ sbi_list_for_each_entry(pos, &hart_protection_list, head) {
+ if (pos->type == SBI_HART_PROTECTION_TYPE_MEMORY)
+ return pos;
+ }
+
+ return NULL;
+}
+
+void sbi_hart_protection_get_str(char *out_str, int out_str_size)
+{
+ bool memory_protect_done = false;
+ struct sbi_hart_protection *pos;
+ int offset = 0;
+
+ if (!out_str || out_str_size <= 0)
+ return;
+ sbi_memset(out_str, 0, out_str_size);
+
+ sbi_list_for_each_entry(pos, &hart_protection_list, head) {
+ if (pos->type == SBI_HART_PROTECTION_TYPE_MEMORY) {
+ if (memory_protect_done)
+ continue;
+ memory_protect_done = true;
+ }
+ sbi_snprintf(out_str + offset, out_str_size - offset, "%s,", pos->name);
+ offset = offset + sbi_strlen(pos->name) + 1;
+ }
+
+ if (offset)
+ out_str[offset - 1] = '\0';
+ else
+ sbi_strncpy(out_str, "none", out_str_size);
}
int sbi_hart_protection_register(struct sbi_hart_protection *hprot)
@@ -25,6 +57,8 @@ int sbi_hart_protection_register(struct sbi_hart_protection *hprot)
if (!hprot)
return SBI_EINVAL;
+ if (hprot->type >= SBI_HART_PROTECTION_TYPE_MAX)
+ return SBI_EINVAL;
sbi_list_for_each_entry(pos, &hart_protection_list, head) {
if (hprot->rating > pos->rating) {
@@ -49,31 +83,122 @@ void sbi_hart_protection_unregister(struct sbi_hart_protection *hprot)
sbi_list_del(&hprot->head);
}
-int sbi_hart_protection_configure(struct sbi_scratch *scratch)
+static int __hart_protection_configure(struct sbi_scratch *scratch,
+ struct sbi_hart_protection *hprot,
+ struct sbi_domain *dom)
{
- struct sbi_hart_protection *hprot = sbi_hart_protection_best();
-
if (!hprot)
return 0;
if (!hprot->configure)
return SBI_ENOSYS;
- return hprot->configure(scratch);
+ return hprot->configure(scratch, dom);
}
-void sbi_hart_protection_unconfigure(struct sbi_scratch *scratch)
+static void __hart_protection_unconfigure(struct sbi_scratch *scratch,
+ struct sbi_hart_protection *hprot,
+ struct sbi_domain *dom)
{
- struct sbi_hart_protection *hprot = sbi_hart_protection_best();
-
if (!hprot || !hprot->unconfigure)
return;
- hprot->unconfigure(scratch);
+ hprot->unconfigure(scratch, dom);
+}
+
+int sbi_hart_protection_configure(struct sbi_scratch *scratch,
+ struct sbi_domain *dom)
+{
+ bool do_configure, memory_protect_done = false;
+ struct sbi_hart_protection *hprot;
+ int ret;
+
+ sbi_list_for_each_entry(hprot, &hart_protection_list, head) {
+ do_configure = false;
+ switch (hprot->type) {
+ case SBI_HART_PROTECTION_TYPE_MEMORY:
+ do_configure = !memory_protect_done;
+ memory_protect_done = true;
+ break;
+ case SBI_HART_PROTECTION_TYPE_ID:
+ do_configure = true;
+ break;
+ default:
+ break;
+ }
+ if (!do_configure)
+ continue;
+
+ ret = __hart_protection_configure(scratch, hprot, dom);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+void sbi_hart_protection_unconfigure(struct sbi_scratch *scratch,
+ struct sbi_domain *dom)
+{
+
+ bool do_unconfigure, memory_protect_done = false;
+ struct sbi_hart_protection *hprot;
+
+ sbi_list_for_each_entry(hprot, &hart_protection_list, head) {
+ do_unconfigure = false;
+ switch (hprot->type) {
+ case SBI_HART_PROTECTION_TYPE_MEMORY:
+ do_unconfigure = !memory_protect_done;
+ memory_protect_done = true;
+ break;
+ case SBI_HART_PROTECTION_TYPE_ID:
+ do_unconfigure = true;
+ break;
+ default:
+ break;
+ }
+ if (!do_unconfigure)
+ continue;
+
+ __hart_protection_unconfigure(scratch, hprot, dom);
+ }
+}
+
+int sbi_hart_protection_reconfigure(struct sbi_scratch *scratch,
+ struct sbi_domain *current_dom,
+ struct sbi_domain *next_dom)
+{
+ bool do_reconfigure, memory_protect_done = false;
+ struct sbi_hart_protection *hprot;
+ int ret;
+
+ sbi_list_for_each_entry(hprot, &hart_protection_list, head) {
+ do_reconfigure = false;
+ switch (hprot->type) {
+ case SBI_HART_PROTECTION_TYPE_MEMORY:
+ do_reconfigure = !memory_protect_done;
+ memory_protect_done = true;
+ break;
+ case SBI_HART_PROTECTION_TYPE_ID:
+ do_reconfigure = true;
+ break;
+ default:
+ break;
+ }
+ if (!do_reconfigure)
+ continue;
+
+ __hart_protection_unconfigure(scratch, hprot, current_dom);
+ ret = __hart_protection_configure(scratch, hprot, next_dom);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
}
int sbi_hart_protection_map_range(unsigned long base, unsigned long size)
{
- struct sbi_hart_protection *hprot = sbi_hart_protection_best();
+ struct sbi_hart_protection *hprot = __hart_memory_protection_best();
if (!hprot || !hprot->map_range)
return 0;
@@ -83,7 +208,7 @@ int sbi_hart_protection_map_range(unsigned long base, unsigned long size)
int sbi_hart_protection_unmap_range(unsigned long base, unsigned long size)
{
- struct sbi_hart_protection *hprot = sbi_hart_protection_best();
+ struct sbi_hart_protection *hprot = __hart_memory_protection_best();
if (!hprot || !hprot->unmap_range)
return 0;
diff --git a/lib/sbi/sbi_init.c b/lib/sbi/sbi_init.c
index 9bb1a37e..acd2f8b6 100644
--- a/lib/sbi/sbi_init.c
+++ b/lib/sbi/sbi_init.c
@@ -76,7 +76,6 @@ static void sbi_boot_print_general(struct sbi_scratch *scratch)
const struct sbi_hsm_device *hdev;
const struct sbi_ipi_device *idev;
const struct sbi_timer_device *tdev;
- const struct sbi_hart_protection *hprot;
const struct sbi_console_device *cdev;
const struct sbi_system_reset_device *srdev;
const struct sbi_system_suspend_device *susp_dev;
@@ -93,9 +92,8 @@ static void sbi_boot_print_general(struct sbi_scratch *scratch)
sbi_printf("Platform Features : %s\n", str);
sbi_printf("Platform HART Count : %u\n",
sbi_platform_hart_count(plat));
- hprot = sbi_hart_protection_best();
- sbi_printf("Platform HART Protection : %s\n",
- (hprot) ? hprot->name : "---");
+ sbi_hart_protection_get_str(str, sizeof(str));
+ sbi_printf("Platform HART Protection : %s\n", str);
idev = sbi_ipi_get_device();
sbi_printf("Platform IPI Device : %s\n",
(idev) ? idev->name : "---");
@@ -432,12 +430,12 @@ static void __noreturn init_coldboot(struct sbi_scratch *scratch, u32 hartid)
}
/*
- * Configure hart isolation at last because if SMEPMP is,
+ * Configure hart protection at last because if SMEPMP is
* detected, M-mode access to the S/U space will be rescinded.
*/
- rc = sbi_hart_protection_configure(scratch);
+ rc = sbi_hart_protection_configure(scratch, sbi_domain_thishart_ptr());
if (rc) {
- sbi_printf("%s: hart isolation configure failed (error %d)\n",
+ sbi_printf("%s: hart protection configure failed (error %d)\n",
__func__, rc);
sbi_hart_hang();
}
@@ -515,10 +513,10 @@ static void __noreturn init_warm_startup(struct sbi_scratch *scratch,
sbi_hart_hang();
/*
- * Configure hart isolation at last because if SMEPMP is,
+ * Configure hart protection at last because if SMEPMP is
* detected, M-mode access to the S/U space will be rescinded.
*/
- rc = sbi_hart_protection_configure(scratch);
+ rc = sbi_hart_protection_configure(scratch, sbi_domain_thishart_ptr());
if (rc)
sbi_hart_hang();
@@ -539,7 +537,7 @@ static void __noreturn init_warm_resume(struct sbi_scratch *scratch,
if (rc)
sbi_hart_hang();
- rc = sbi_hart_protection_configure(scratch);
+ rc = sbi_hart_protection_configure(scratch, sbi_domain_thishart_ptr());
if (rc)
sbi_hart_hang();
diff --git a/lib/sbi/sbi_mpxy.c b/lib/sbi/sbi_mpxy.c
index ff5c6ab6..19f59f3a 100644
--- a/lib/sbi/sbi_mpxy.c
+++ b/lib/sbi/sbi_mpxy.c
@@ -145,14 +145,36 @@ static inline bool mpxy_is_std_attr(u32 attr_id)
return (attr_id >> 31) ? false : true;
}
+static inline bool mpxy_channel_visible(struct sbi_mpxy_channel *channel,
+ struct sbi_domain *dom)
+{
+ return channel->owner_domain == dom;
+}
+
+/** Find channel_id in registered channels list for this domain */
+static struct sbi_mpxy_channel *mpxy_find_channel(u32 channel_id,
+ struct sbi_domain *dom)
+{
+ struct sbi_mpxy_channel *channel;
+
+ sbi_list_for_each_entry(channel, &mpxy_channel_list, head) {
+ if (channel->channel_id == channel_id &&
+ mpxy_channel_visible(channel, dom))
+ return channel;
+ }
+
+ return NULL;
+}
+
/** Find channel_id in registered channels list */
-static struct sbi_mpxy_channel *mpxy_find_channel(u32 channel_id)
+struct sbi_mpxy_channel *sbi_mpxy_find_channel_any(u32 channel_id)
{
struct sbi_mpxy_channel *channel;
- sbi_list_for_each_entry(channel, &mpxy_channel_list, head)
+ sbi_list_for_each_entry(channel, &mpxy_channel_list, head) {
if (channel->channel_id == channel_id)
return channel;
+ }
return NULL;
}
@@ -224,7 +246,10 @@ int sbi_mpxy_register_channel(struct sbi_mpxy_channel *channel)
if (!channel)
return SBI_EINVAL;
- if (mpxy_find_channel(channel->channel_id))
+ if (!channel->owner_domain)
+ return SBI_EINVAL;
+
+ if (sbi_mpxy_find_channel_any(channel->channel_id))
return SBI_EALREADY;
/* Initialize channel specific attributes */
@@ -397,12 +422,15 @@ int sbi_mpxy_get_channel_ids(u32 start_index)
struct sbi_mpxy_channel *channel;
u32 channels_count = 0;
u32 *shmem_base;
+ struct sbi_domain *dom = sbi_domain_thishart_ptr();
if (!mpxy_shmem_enabled(ms))
return SBI_ERR_NO_SHMEM;
- sbi_list_for_each_entry(channel, &mpxy_channel_list, head)
- channels_count += 1;
+ sbi_list_for_each_entry(channel, &mpxy_channel_list, head) {
+ if (mpxy_channel_visible(channel, dom))
+ channels_count += 1;
+ }
if (start_index > channels_count)
return SBI_ERR_INVALID_PARAM;
@@ -420,6 +448,9 @@ int sbi_mpxy_get_channel_ids(u32 start_index)
// Iterate over the list of channels to get the channel ids.
sbi_list_for_each_entry(channel, &mpxy_channel_list, head) {
+ if (!mpxy_channel_visible(channel, sbi_domain_thishart_ptr()))
+ continue;
+
if (node_index >= start_index &&
node_index < (start_index + returned)) {
shmem_base[2 + node_ret] = cpu_to_le32(channel->channel_id);
@@ -446,11 +477,12 @@ int sbi_mpxy_read_attrs(u32 channel_id, u32 base_attr_id, u32 attr_count)
int ret = SBI_SUCCESS;
u32 *attr_ptr, end_id;
void *shmem_base;
+ struct sbi_domain *dom = sbi_domain_thishart_ptr();
if (!mpxy_shmem_enabled(ms))
return SBI_ERR_NO_SHMEM;
- struct sbi_mpxy_channel *channel = mpxy_find_channel(channel_id);
+ struct sbi_mpxy_channel *channel = mpxy_find_channel(channel_id, dom);
if (!channel)
return SBI_ERR_NOT_SUPPORTED;
@@ -597,11 +629,12 @@ int sbi_mpxy_write_attrs(u32 channel_id, u32 base_attr_id, u32 attr_count)
struct sbi_mpxy_channel *channel;
int ret, mem_idx;
void *shmem_base;
+ struct sbi_domain *dom = sbi_domain_thishart_ptr();
if (!mpxy_shmem_enabled(ms))
return SBI_ERR_NO_SHMEM;
- channel = mpxy_find_channel(channel_id);
+ channel = mpxy_find_channel(channel_id, dom);
if (!channel)
return SBI_ERR_NOT_SUPPORTED;
@@ -686,12 +719,13 @@ int sbi_mpxy_send_message(u32 channel_id, u8 msg_id,
struct sbi_mpxy_channel *channel;
void *shmem_base, *resp_buf;
u32 resp_bufsize;
+ struct sbi_domain *dom = sbi_domain_thishart_ptr();
int ret;
if (!mpxy_shmem_enabled(ms))
return SBI_ERR_NO_SHMEM;
- channel = mpxy_find_channel(channel_id);
+ channel = mpxy_find_channel(channel_id, dom);
if (!channel)
return SBI_ERR_NOT_SUPPORTED;
@@ -743,12 +777,13 @@ int sbi_mpxy_get_notification_events(u32 channel_id, unsigned long *events_len)
struct mpxy_state *ms = sbi_domain_mpxy_state_thishart_ptr();
struct sbi_mpxy_channel *channel;
void *eventsbuf, *shmem_base;
+ struct sbi_domain *dom = sbi_domain_thishart_ptr();
int ret;
if (!mpxy_shmem_enabled(ms))
return SBI_ERR_NO_SHMEM;
- channel = mpxy_find_channel(channel_id);
+ channel = mpxy_find_channel(channel_id, dom);
if (!channel || !channel->get_notification_events)
return SBI_ERR_NOT_SUPPORTED;
diff --git a/lib/sbi/sbi_sse.c b/lib/sbi/sbi_sse.c
index 818afb87..13d78e7c 100644
--- a/lib/sbi/sbi_sse.c
+++ b/lib/sbi/sbi_sse.c
@@ -563,19 +563,14 @@ static void sse_event_inject(struct sbi_sse_event *e,
if (misa_extension('H')) {
unsigned long hstatus = csr_read(CSR_HSTATUS);
-
-#if __riscv_xlen == 64
- if (regs->mstatus & MSTATUS_MPV)
-#elif __riscv_xlen == 32
- if (regs->mstatusH & MSTATUSH_MPV)
-#else
-#error "Unexpected __riscv_xlen"
-#endif
+ if (sbi_regs_from_virt(regs))
hstatus |= HSTATUS_SPV;
+ else
+ hstatus &= ~HSTATUS_SPV;
hstatus &= ~HSTATUS_SPVP;
if (hstatus & HSTATUS_SPV && regs->mstatus & SSTATUS_SPP)
- hstatus |= HSTATUS_SPVP;
+ hstatus |= HSTATUS_SPVP;
csr_write(CSR_HSTATUS, hstatus);
}
diff --git a/lib/sbi/sbi_timer.c b/lib/sbi/sbi_timer.c
index 4d737d22..8abb5e7b 100644
--- a/lib/sbi/sbi_timer.c
+++ b/lib/sbi/sbi_timer.c
@@ -104,6 +104,18 @@ bool sbi_timer_waitms_until(bool (*predicate)(void *), void *arg,
return true;
}
+unsigned long sbi_timer_frequency(void)
+{
+ const struct sbi_timer_device *timer_dev = sbi_timer_get_device();
+
+ if (!timer_dev) {
+ sbi_printf("%s: called without timer device\n", __func__);
+ return 0;
+ }
+
+ return timer_dev->timer_freq;
+}
+
u64 sbi_timer_value(void)
{
if (get_time_val)
diff --git a/lib/sbi/sbi_tlb.c b/lib/sbi/sbi_tlb.c
index ada60c32..ab1e3a99 100644
--- a/lib/sbi/sbi_tlb.c
+++ b/lib/sbi/sbi_tlb.c
@@ -29,6 +29,38 @@ static unsigned long tlb_fifo_off;
static unsigned long tlb_fifo_mem_off;
static unsigned long tlb_range_flush_limit;
+static void sbi_tlb_local_fence_i(struct sbi_tlb_info *tinfo);
+static void sbi_tlb_local_sfence_vma(struct sbi_tlb_info *tinfo);
+static void sbi_tlb_local_sfence_vma_asid(struct sbi_tlb_info *tinfo);
+static void sbi_tlb_local_hfence_gvma_vmid(struct sbi_tlb_info *tinfo);
+static void sbi_tlb_local_hfence_gvma(struct sbi_tlb_info *tinfo);
+static void sbi_tlb_local_hfence_vvma_asid(struct sbi_tlb_info *tinfo);
+static void sbi_tlb_local_hfence_vvma(struct sbi_tlb_info *tinfo);
+
+static struct sbi_tlb_local_operations default_tlb_local_ops = {
+ .local_fence_i = sbi_tlb_local_fence_i,
+ .local_sfence_vma = sbi_tlb_local_sfence_vma,
+ .local_sfence_vma_asid = sbi_tlb_local_sfence_vma_asid,
+ .local_hfence_gvma_vmid = sbi_tlb_local_hfence_gvma_vmid,
+ .local_hfence_gvma = sbi_tlb_local_hfence_gvma,
+ .local_hfence_vvma_asid = sbi_tlb_local_hfence_vvma_asid,
+ .local_hfence_vvma = sbi_tlb_local_hfence_vvma
+};
+
+static const struct sbi_tlb_local_operations *tlb_local_ops =
+ &default_tlb_local_ops;
+
+const struct sbi_tlb_local_operations *sbi_tlb_get_local_operations(void)
+{
+ return tlb_local_ops;
+}
+
+void sbi_tlb_set_local_operations(
+ const struct sbi_tlb_local_operations *ops)
+{
+ tlb_local_ops = ops;
+}
+
void __sbi_sfence_vma_all(void)
{
__asm__ __volatile("sfence.vma");
@@ -183,25 +215,25 @@ static void tlb_entry_local_process(struct sbi_tlb_info *data)
switch (data->type) {
case SBI_TLB_FENCE_I:
- sbi_tlb_local_fence_i(data);
+ tlb_local_ops->local_fence_i(data);
break;
case SBI_TLB_SFENCE_VMA:
- sbi_tlb_local_sfence_vma(data);
+ tlb_local_ops->local_sfence_vma(data);
break;
case SBI_TLB_SFENCE_VMA_ASID:
- sbi_tlb_local_sfence_vma_asid(data);
+ tlb_local_ops->local_sfence_vma_asid(data);
break;
case SBI_TLB_HFENCE_GVMA_VMID:
- sbi_tlb_local_hfence_gvma_vmid(data);
+ tlb_local_ops->local_hfence_gvma_vmid(data);
break;
case SBI_TLB_HFENCE_GVMA:
- sbi_tlb_local_hfence_gvma(data);
+ tlb_local_ops->local_hfence_gvma(data);
break;
case SBI_TLB_HFENCE_VVMA_ASID:
- sbi_tlb_local_hfence_vvma_asid(data);
+ tlb_local_ops->local_hfence_vvma_asid(data);
break;
case SBI_TLB_HFENCE_VVMA:
- sbi_tlb_local_hfence_vvma(data);
+ tlb_local_ops->local_hfence_vvma(data);
break;
default:
break;
diff --git a/lib/sbi/tests/sbi_ecall_test.c b/lib/sbi/tests/sbi_ecall_test.c
index 5b6ce37c..f5c553e9 100644
--- a/lib/sbi/tests/sbi_ecall_test.c
+++ b/lib/sbi/tests/sbi_ecall_test.c
@@ -40,10 +40,69 @@ static void test_sbi_ecall_register_find_extension(struct sbiunit_test_case *tes
SBIUNIT_EXPECT_EQ(test, sbi_ecall_find_extension(SBI_EXT_EXPERIMENTAL_START), NULL);
}
+static void test_sbi_ecall_get_extensions_str_bounds(struct sbiunit_test_case *test)
+{
+ struct sbi_ecall_extension e1 = {
+ .extid_start = SBI_EXT_EXPERIMENTAL_START,
+ .extid_end = SBI_EXT_EXPERIMENTAL_START,
+ .name = "Alpha",
+ .handle = dummy_handler,
+ .experimental = false,
+ };
+ struct sbi_ecall_extension e2 = {
+ .extid_start = SBI_EXT_EXPERIMENTAL_START + 1,
+ .extid_end = SBI_EXT_EXPERIMENTAL_START + 1,
+ .name = "Bravo",
+ .handle = dummy_handler,
+ .experimental = false,
+ };
+ struct sbi_ecall_extension e3 = {
+ .extid_start = SBI_EXT_EXPERIMENTAL_START + 2,
+ .extid_end = SBI_EXT_EXPERIMENTAL_START + 2,
+ .name = "Charli",
+ .handle = dummy_handler,
+ .experimental = false,
+ };
+ char storage[16 + 16];
+ char *buf = storage;
+ char big[128];
+ int i;
+ int found_alpha = 0;
+
+ SBIUNIT_EXPECT_EQ(test, sbi_ecall_register_extension(&e1), 0);
+ SBIUNIT_EXPECT_EQ(test, sbi_ecall_register_extension(&e2), 0);
+ SBIUNIT_EXPECT_EQ(test, sbi_ecall_register_extension(&e3), 0);
+
+ for (i = 16; i < 32; i++)
+ storage[i] = (char)0xA5;
+
+ /* Undersized buffer must not write past the caller-provided size. */
+ sbi_ecall_get_extensions_str(buf, 16, false);
+ SBIUNIT_EXPECT_EQ(test, buf[15], '\0');
+ for (i = 16; i < 32; i++)
+ SBIUNIT_EXPECT_EQ(test, (unsigned char)storage[i], 0xA5);
+
+ /* Negative control: room for the full list, including registered names. */
+ sbi_ecall_get_extensions_str(big, sizeof(big), false);
+ SBIUNIT_EXPECT_NE(test, sbi_strlen(big), 0);
+ for (i = 0; big[i] != '\0'; i++) {
+ if (sbi_strncmp(&big[i], "Alpha", 5) == 0) {
+ found_alpha = 1;
+ break;
+ }
+ }
+ SBIUNIT_EXPECT_EQ(test, found_alpha, 1);
+
+ sbi_ecall_unregister_extension(&e1);
+ sbi_ecall_unregister_extension(&e2);
+ sbi_ecall_unregister_extension(&e3);
+}
+
static struct sbiunit_test_case ecall_tests[] = {
SBIUNIT_TEST_CASE(test_sbi_ecall_version),
SBIUNIT_TEST_CASE(test_sbi_ecall_impid),
SBIUNIT_TEST_CASE(test_sbi_ecall_register_find_extension),
+ SBIUNIT_TEST_CASE(test_sbi_ecall_get_extensions_str_bounds),
SBIUNIT_END_CASE,
};
diff --git a/lib/utils/cache/fdt_andes_llcache.c b/lib/utils/cache/fdt_andes_llcache.c
index 490503ee..7a61b6ab 100644
--- a/lib/utils/cache/fdt_andes_llcache.c
+++ b/lib/utils/cache/fdt_andes_llcache.c
@@ -5,8 +5,11 @@
*/
#include <sbi/riscv_io.h>
+#include <sbi/sbi_domain.h>
#include <sbi/sbi_error.h>
+#include <sbi/sbi_hart.h>
#include <sbi/sbi_heap.h>
+#include <sbi/sbi_scratch.h>
#include <sbi_utils/cache/fdt_cache.h>
#include <sbi_utils/fdt/fdt_driver.h>
#include <sbi_utils/hsm/fdt_hsm_andes_atcsmu.h>
@@ -102,7 +105,10 @@ static int andes_llcache_enable(struct cache_device *dev, bool enable)
}
llcache_ctrl = readl(ctrl_addr);
- return enable == EXTRACT_FIELD(llcache_ctrl, LLCACHE_REG_CTRL_EN_MASK);
+ if (enable != EXTRACT_FIELD(llcache_ctrl, LLCACHE_REG_CTRL_EN_MASK))
+ return SBI_EFAIL;
+
+ return SBI_OK;
}
static struct cache_ops andes_llcache_ops = {
@@ -113,13 +119,13 @@ static struct cache_ops andes_llcache_ops = {
static int andes_llcache_probe(const void *fdt, int nodeoff, const struct fdt_match *match)
{
int rc;
- u64 llcache_base = 0;
+ u64 llcache_base = 0, size;
struct andes_llcache *llcache;
struct cache_device *dev;
uint32_t llcache_cfg;
- rc = fdt_get_node_addr_size(fdt, nodeoff, 0, &llcache_base, NULL);
- if (rc < 0 || !llcache_base)
+ rc = fdt_get_node_addr_size(fdt, nodeoff, 0, &llcache_base, &size);
+ if (rc < 0 || !llcache_base || !size)
return SBI_ENODEV;
llcache = sbi_zalloc(sizeof(*llcache));
@@ -148,6 +154,15 @@ static int andes_llcache_probe(const void *fdt, int nodeoff, const struct fdt_ma
llcache->status_core_stride = 4;
}
+ if (sbi_hart_has_extension(sbi_scratch_thishart_ptr(), SBI_HART_EXT_SMEPMP)) {
+ rc = sbi_domain_root_add_memrange(
+ (unsigned long)llcache->base, (unsigned long)size, PAGE_SIZE,
+ SBI_DOMAIN_MEMREGION_MMIO |
+ SBI_DOMAIN_MEMREGION_SHARED_SURW_MRW);
+ if (rc)
+ return rc;
+ }
+
/* Wait for the hardware initialization done */
while (!andes_llcache_init_done(llcache))
;
diff --git a/lib/utils/cppc/fdt_cppc_rpmi.c b/lib/utils/cppc/fdt_cppc_rpmi.c
index 7bd3b0f9..15c89351 100644
--- a/lib/utils/cppc/fdt_cppc_rpmi.c
+++ b/lib/utils/cppc/fdt_cppc_rpmi.c
@@ -12,6 +12,7 @@
#include <sbi/sbi_cppc.h>
#include <sbi/sbi_ecall_interface.h>
#include <sbi/sbi_scratch.h>
+#include <sbi/sbi_timer.h>
#include <sbi_utils/fdt/fdt_driver.h>
#include <sbi_utils/fdt/fdt_helper.h>
#include <sbi_utils/mailbox/fdt_mailbox.h>
@@ -39,6 +40,8 @@ struct rpmi_cppc {
ulong fc_db_addr;
u64 fc_db_setmask;
u64 fc_db_preservemask;
+ u64 prev_time_csr;
+ u64 prev_delivered_counter;
};
static unsigned long rpmi_cppc_offset;
@@ -107,6 +110,7 @@ static void rpmi_cppc_fc_db_trigger(struct rpmi_cppc *cppc)
static int rpmi_cppc_read(unsigned long reg, u64 *val)
{
+ u64 curr_freq, curr_time_csr, time_csr_delta, freq;
int rc = SBI_SUCCESS;
struct rpmi_cppc_read_reg_req req;
struct rpmi_cppc_read_reg_resp resp;
@@ -116,12 +120,38 @@ static int rpmi_cppc_read(unsigned long reg, u64 *val)
req.reg_id = reg;
cppc = rpmi_cppc_get_pointer(req.hart_id);
- rc = rpmi_normal_request_with_status(
- cppc->chan, RPMI_CPPC_SRV_READ_REG,
- &req, rpmi_u32_count(req), rpmi_u32_count(req),
- &resp, rpmi_u32_count(resp), rpmi_u32_count(resp));
- if (rc)
- return rc;
+ if ((reg == SBI_CPPC_DELIVERED_CTR) && cppc->fc_supported) {
+#if __riscv_xlen != 32
+ curr_freq = readq((void *)cppc->fc_perf_feedback_addr);
+#else
+ curr_freq = readl((void *)cppc->fc_perf_feedback_addr + 4);
+ curr_freq <<= 32;
+ curr_freq |= readl((void *)cppc->fc_perf_feedback_addr);
+#endif
+ curr_time_csr = sbi_timer_value();
+ time_csr_delta = curr_time_csr - cppc->prev_time_csr;
+ cppc->prev_time_csr = curr_time_csr;
+
+ freq = sbi_timer_frequency();
+ if (freq)
+ cppc->prev_delivered_counter +=
+ curr_freq * (time_csr_delta / freq) +
+ (curr_freq * (time_csr_delta % freq)) / freq;
+
+ resp.data_lo = cpu_to_le32(cppc->prev_delivered_counter & UINT32_MAX);
+ resp.data_hi = cpu_to_le32(cppc->prev_delivered_counter >> 32);
+ } else if (reg == SBI_CPPC_REFERENCE_CTR) {
+ curr_time_csr = sbi_timer_value();
+ resp.data_lo = cpu_to_le32(curr_time_csr & UINT32_MAX);
+ resp.data_hi = cpu_to_le32(curr_time_csr >> 32);
+ } else {
+ rc = rpmi_normal_request_with_status(
+ cppc->chan, RPMI_CPPC_SRV_READ_REG,
+ &req, rpmi_u32_count(req), rpmi_u32_count(req),
+ &resp, rpmi_u32_count(resp), rpmi_u32_count(resp));
+ if (rc)
+ return rc;
+ }
#if __riscv_xlen == 32
*val = resp.data_lo;
@@ -276,6 +306,8 @@ static int rpmi_cppc_update_hart_scratch(struct mbox_chan *chan)
if (!cppc)
return SBI_ENOSYS;
+ cppc->prev_time_csr = 0;
+ cppc->prev_delivered_counter = 0;
cppc->chan = chan;
cppc->mode = cppc_mode;
cppc->fc_supported = fc_supported;
diff --git a/lib/utils/hsm/fdt_hsm_andes_atcsmu.c b/lib/utils/hsm/fdt_hsm_andes_atcsmu.c
index 115916d5..2885a983 100644
--- a/lib/utils/hsm/fdt_hsm_andes_atcsmu.c
+++ b/lib/utils/hsm/fdt_hsm_andes_atcsmu.c
@@ -56,7 +56,7 @@ bool atcsmu_support_sleep_mode(u32 sleep_type, u32 hartid)
void atcsmu_set_command(u32 pcs_ctl, u32 hartid)
{
- writel_relaxed(pcs_ctl, (char *)atcsmu_base + PCSm_CTL_OFFSET(hartid));
+ writel(pcs_ctl, (char *)atcsmu_base + PCSm_CTL_OFFSET(hartid));
}
int atcsmu_set_reset_vector(u64 wakeup_addr, u32 hartid)
@@ -94,42 +94,24 @@ u32 atcsmu_read_scratch(void)
return readl_relaxed((char *)atcsmu_base + SCRATCH_PAD_OFFSET);
}
-bool atcsmu_pcs_is_sleep(u32 hartid, bool deep_sleep)
+bool atcsmu_hart_is_sleep(void *opaque)
{
- u32 pcs_status = readl_relaxed((char *)atcsmu_base + PCSm_STATUS_OFFSET(hartid));
- u32 pd_status = deep_sleep ? PD_STATUS_DEEP_SLEEP : PD_STATUS_LIGHT_SLEEP;
+ struct atcsmu_sleep_arg *arg = opaque;
- if (EXTRACT_FIELD(pcs_status, PD_TYPE_MASK) != PD_TYPE_SLEEP) {
- sbi_printf("ATCSMU: hart%d (PCS%d): failed to sleep\n", hartid, hartid + 3);
- return false;
- }
-
- if (EXTRACT_FIELD(pcs_status, PD_STATUS_MASK) != pd_status) {
- sbi_printf("ATCSMU: hart%d (PCS%d): failed to enter %s sleep\n",
- hartid, hartid + 3, deep_sleep ? "deep" : "light");
- return false;
- }
+ u32 pcs_status = readl_relaxed((char *)atcsmu_base +
+ PCSm_STATUS_OFFSET(arg->hartid));
+ u32 pd_status = arg->deep_sleep ? PD_STATUS_DEEP_SLEEP :
+ PD_STATUS_LIGHT_SLEEP;
- return true;
+ return EXTRACT_FIELD(pcs_status, PD_TYPE_MASK) == PD_TYPE_SLEEP &&
+ EXTRACT_FIELD(pcs_status, PD_STATUS_MASK) == pd_status;
}
static int ae350_hart_start(u32 hartid, ulong saddr)
{
u32 hartindex = sbi_hartid_to_hartindex(hartid);
- u32 sleep_type = atcsmu_get_sleep_type(hartid);
-
- /*
- * Don't send wakeup command when:
- * 1) boot time
- * 2) the target hart is non-sleepable 25-series hart0
- * 3) light sleep
- */
- if (!sbi_init_count(hartindex) || (is_andes(25) && hartid == 0) ||
- sleep_type == SBI_SUSP_AE350_LIGHT_SLEEP)
- return sbi_ipi_raw_send(hartindex, false);
- atcsmu_set_command(WAKEUP_CMD, hartid);
- return 0;
+ return sbi_ipi_raw_send(hartindex, false);
}
static int ae350_hart_stop(void)
@@ -152,18 +134,19 @@ static int ae350_hart_stop(void)
/* Prevent the core leaving the WFI mode unexpectedly */
csr_write(CSR_MIE, 0);
+ atcsmu_set_wakeup_events(PCS_WAKEUP_MSIP_MASK | PCS_WAKEUP_MEIP_MASK, hartid);
if (sleep_type == SBI_SUSP_AE350_LIGHT_SLEEP) {
- csr_write(CSR_MIE, MIP_MSIP);
- atcsmu_set_wakeup_events(PCS_WAKEUP_MSIP_MASK, hartid);
+ /* Clock-gated only: needs MSI or MEI set to resume past the WFI */
+ csr_set(CSR_MIE, MIP_MSIP | MIP_MEIP);
atcsmu_set_command(LIGHT_SLEEP_CMD, hartid);
} else if (sleep_type == SBI_SUSP_SLEEP_TYPE_SUSPEND) {
- atcsmu_set_wakeup_events(0x0, hartid);
- atcsmu_set_command(DEEP_SLEEP_CMD, hartid);
+ /* Power-gated: SMU wakes it via cold reset, interrupts not needed */
rc = atcsmu_set_reset_vector((ulong)ae350_enable_coherency_warmboot, hartid);
if (rc)
return SBI_EFAIL;
ae350_non_ret_save(sbi_scratch_thishart_ptr());
+ atcsmu_set_command(DEEP_SLEEP_CMD, hartid);
}
ae350_disable_coherency();
@@ -184,18 +167,27 @@ static const struct sbi_hsm_device hsm_andes_atcsmu = {
static int hsm_andes_atcsmu_probe(const void *fdt, int nodeoff, const struct fdt_match *match)
{
int poff, rc;
- u64 addr;
+ u64 addr, size;
/* Need to find the parent for the address property */
poff = fdt_parent_offset(fdt, nodeoff);
if (poff < 0)
return SBI_EINVAL;
- rc = fdt_get_node_addr_size(fdt, poff, 0, &addr, NULL);
- if (rc < 0 || !addr)
+ rc = fdt_get_node_addr_size(fdt, poff, 0, &addr, &size);
+ if (rc < 0 || !addr || !size)
return SBI_ENODEV;
- atcsmu_base = addr;
+ if (sbi_hart_has_extension(sbi_scratch_thishart_ptr(), SBI_HART_EXT_SMEPMP)) {
+ rc = sbi_domain_root_add_memrange(
+ (unsigned long)addr, (unsigned long)size, PAGE_SIZE,
+ SBI_DOMAIN_MEMREGION_MMIO |
+ SBI_DOMAIN_MEMREGION_SHARED_SURW_MRW);
+ if (rc)
+ return rc;
+ }
+
+ atcsmu_base = addr;
sbi_hsm_set_device(&hsm_andes_atcsmu);
return 0;
}
diff --git a/lib/utils/mpxy/fdt_mpxy_rpmi_logging.c b/lib/utils/mpxy/fdt_mpxy_rpmi_logging.c
index e8f085eb..1e92053d 100644
--- a/lib/utils/mpxy/fdt_mpxy_rpmi_logging.c
+++ b/lib/utils/mpxy/fdt_mpxy_rpmi_logging.c
@@ -11,7 +11,7 @@
static struct mpxy_rpmi_service_data logging_services[] = {
[0] = {
- .id = RPMI_MM_SRV_ENABLE_NOTIFICATION,
+ .id = RPMI_LOGGING_SRV_ENABLE_NOTIFICATION,
.min_tx_len = sizeof(struct rpmi_enable_notification_req),
.max_tx_len = sizeof(struct rpmi_enable_notification_req),
.min_rx_len = sizeof(struct rpmi_enable_notification_resp),
diff --git a/lib/utils/mpxy/fdt_mpxy_rpmi_mbox.c b/lib/utils/mpxy/fdt_mpxy_rpmi_mbox.c
index 84b7a67d..825ac9b3 100644
--- a/lib/utils/mpxy/fdt_mpxy_rpmi_mbox.c
+++ b/lib/utils/mpxy/fdt_mpxy_rpmi_mbox.c
@@ -299,6 +299,8 @@ int mpxy_rpmi_mbox_init(const void *fdt, int nodeoff, const struct fdt_match *ma
/* Setup MPXY mbox client */
/* Channel ID*/
rmb->channel.channel_id = channel_id;
+ /* Set the owner domain */
+ rmb->channel.owner_domain = &root;
/* Callback for read RPMI attributes */
rmb->channel.read_attributes = mpxy_mbox_read_attributes;
/* Callback for write RPMI attributes */
diff --git a/lib/utils/mpxy/fdt_mpxy_rpmi_mm.c b/lib/utils/mpxy/fdt_mpxy_rpmi_mm.c
index d7176aca..7185f3f3 100644
--- a/lib/utils/mpxy/fdt_mpxy_rpmi_mm.c
+++ b/lib/utils/mpxy/fdt_mpxy_rpmi_mm.c
@@ -15,13 +15,20 @@ static struct rpmi_mm_get_attributes_rsp rsp;
static struct mpxy_rpmi_service_data mm_srvcdata[] = {
[0] = {
+ .id = RPMI_MM_SRV_ENABLE_NOTIFICATION,
+ .min_tx_len = sizeof(struct rpmi_enable_notification_req),
+ .max_tx_len = sizeof(struct rpmi_enable_notification_req),
+ .min_rx_len = sizeof(struct rpmi_enable_notification_resp),
+ .max_rx_len = sizeof(struct rpmi_enable_notification_resp),
+ },
+ [1] = {
.id = RPMI_MM_SRV_GET_ATTRIBUTES,
.min_tx_len = 0,
.max_tx_len = 0,
.min_rx_len = sizeof(struct rpmi_mm_get_attributes_rsp),
.max_rx_len = sizeof(struct rpmi_mm_get_attributes_rsp),
},
- [1] = {
+ [2] = {
.id = RPMI_MM_SRV_COMMUNICATE,
.min_tx_len = sizeof(struct rpmi_mm_communicate_req),
.max_tx_len = sizeof(struct rpmi_mm_communicate_req),
diff --git a/lib/utils/reset/Kconfig b/lib/utils/reset/Kconfig
index b2ac120e..8988548c 100644
--- a/lib/utils/reset/Kconfig
+++ b/lib/utils/reset/Kconfig
@@ -29,6 +29,10 @@ config FDT_RESET_LITEX
depends on FDT_GPIO
default n
+config FDT_RESET_METANOIA
+ bool "Metanoia FDT reset driver"
+ default n
+
config FDT_RESET_RPMI
bool "RPMI FDT reset driver"
depends on FDT_MAILBOX && RPMI_MAILBOX
diff --git a/lib/utils/reset/fdt_reset_metanoia.c b/lib/utils/reset/fdt_reset_metanoia.c
new file mode 100644
index 00000000..6f75a893
--- /dev/null
+++ b/lib/utils/reset/fdt_reset_metanoia.c
@@ -0,0 +1,72 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2026 Metanoia Communications Inc.
+ *
+ */
+
+#include <sbi/riscv_io.h>
+#include <sbi/sbi_platform.h>
+#include <sbi/sbi_system.h>
+#include <sbi_utils/fdt/fdt_helper.h>
+#include <sbi_utils/fdt/fdt_driver.h>
+
+#define SWRSTREQ_CTRL_REG_OFFSET 0x00
+#define SWRSTREQ_REG_OFFSET 0x04
+
+struct reset_metanoia_data {
+ u8 *reg_base;
+};
+
+static struct reset_metanoia_data reset_data;
+
+static int metanoia_system_reset_check(u32 type, u32 reason)
+{
+ switch (type) {
+ case SBI_SRST_RESET_TYPE_WARM_REBOOT:
+ case SBI_SRST_RESET_TYPE_COLD_REBOOT:
+ return 1;
+ case SBI_SRST_RESET_TYPE_SHUTDOWN:
+ default:
+ return 0;
+ }
+}
+
+static void metanoia_system_reset(u32 type, u32 reason)
+{
+ writew(0x1, reset_data.reg_base + SWRSTREQ_CTRL_REG_OFFSET);
+ writew(0x1, reset_data.reg_base + SWRSTREQ_REG_OFFSET);
+}
+
+static struct sbi_system_reset_device metanoia_reset = {
+ .name = "metanoia-mt2824-reboot",
+ .system_reset_check = metanoia_system_reset_check,
+ .system_reset = metanoia_system_reset,
+};
+
+static int metanoia_reset_init(const void *fdt, int nodeoff,
+ const struct fdt_match *match)
+{
+ u64 reg_addr;
+ int rc;
+
+ rc = fdt_get_node_addr_size(fdt, nodeoff, 0, &reg_addr, NULL);
+ if (rc < 0 || !reg_addr)
+ return SBI_ENODEV;
+
+ reset_data.reg_base = (u8 *)(ulong)reg_addr;
+
+ sbi_system_reset_add_device(&metanoia_reset);
+
+ return 0;
+}
+
+static const struct fdt_match metanoia_reset_match[] = {
+ { .compatible = "metanoia,mt2824-reboot" },
+ { /* sentinel */ }
+};
+
+const struct fdt_driver fdt_reset_metanoia = {
+ .match_table = metanoia_reset_match,
+ .init = metanoia_reset_init,
+};
diff --git a/lib/utils/reset/objects.mk b/lib/utils/reset/objects.mk
index 38b4e306..a9b6edad 100644
--- a/lib/utils/reset/objects.mk
+++ b/lib/utils/reset/objects.mk
@@ -20,6 +20,9 @@ libsbiutils-objs-$(CONFIG_FDT_RESET_HTIF) += reset/fdt_reset_htif.o
carray-fdt_early_drivers-$(CONFIG_FDT_RESET_LITEX) += fdt_reset_litex
libsbiutils-objs-$(CONFIG_FDT_RESET_LITEX) += reset/fdt_reset_litex.o
+carray-fdt_early_drivers-$(CONFIG_FDT_RESET_METANOIA) += fdt_reset_metanoia
+libsbiutils-objs-$(CONFIG_FDT_RESET_METANOIA) += reset/fdt_reset_metanoia.o
+
carray-fdt_early_drivers-$(CONFIG_FDT_RESET_SG2042_HWMON_MCU) += fdt_reset_sg2042_mcu
libsbiutils-objs-$(CONFIG_FDT_RESET_SG2042_HWMON_MCU) += reset/fdt_reset_sg2042_hwmon_mcu.o
diff --git a/lib/utils/suspend/fdt_suspend_andes_atcsmu.c b/lib/utils/suspend/fdt_suspend_andes_atcsmu.c
index 072accc0..86cdf955 100644
--- a/lib/utils/suspend/fdt_suspend_andes_atcsmu.c
+++ b/lib/utils/suspend/fdt_suspend_andes_atcsmu.c
@@ -12,22 +12,37 @@
#include <sbi/sbi_ecall_interface.h>
#include <sbi/sbi_hart.h>
#include <sbi/sbi_system.h>
+#include <sbi/sbi_timer.h>
#include <sbi_utils/cache/fdt_cmo_helper.h>
#include <sbi_utils/fdt/fdt_driver.h>
#include <sbi_utils/fdt/fdt_helper.h>
#include <sbi_utils/hsm/fdt_hsm_andes_atcsmu.h>
-static int check_secondary_harts_sleep(u32 hartid, bool deep_sleep)
+#define HART_SLEEP_TIMEOUT_MS 1000
+
+static int wait_secondary_harts_sleep(u32 hartid, bool deep_sleep)
{
const struct sbi_domain *dom = &root;
unsigned long i;
u32 target;
+ struct atcsmu_sleep_arg arg;
+
+ arg.deep_sleep = deep_sleep;
- /* Ensure the secondary harts entering the corresponding sleep state */
+ /* Wait for the secondary harts entering the corresponding sleep state */
sbi_hartmask_for_each_hartindex(i, dom->possible_harts) {
target = sbi_hartindex_to_hartid(i);
- if (target != hartid && !atcsmu_pcs_is_sleep(target, deep_sleep))
- return SBI_EFAIL;
+ if (target == hartid)
+ continue;
+
+ arg.hartid = target;
+ if (!sbi_timer_waitms_until(atcsmu_hart_is_sleep, &arg,
+ HART_SLEEP_TIMEOUT_MS)) {
+ sbi_printf("ATCSMU: hart%u (PCS%u): timed out waiting for %s sleep\n",
+ target, target + 3,
+ deep_sleep ? "deep" : "light");
+ return SBI_ETIMEOUT;
+ }
}
return SBI_OK;
@@ -42,39 +57,45 @@ static int ae350_system_suspend_check(u32 sleep_type)
static int ae350_system_suspend(u32 sleep_type, unsigned long addr)
{
u32 hartid = current_hartid();
+ unsigned long saved_mie;
int rc;
/* Prevent the core leaving the WFI mode unexpectedly */
+ saved_mie = csr_read(CSR_MIE);
csr_write(CSR_MIE, 0);
- /*
- * Only allow the S-mode external interrupts (UART2 and RTC alarm) to
- * wake up the primary hart
- */
- csr_set(CSR_SIE, MIP_SEIP);
+ /* SMU wakes the primary hart on RTC alarm / UART2 */
atcsmu_set_wakeup_events(PCS_WAKEUP_RTC_ALARM_MASK | PCS_WAKEUP_UART2_MASK, hartid);
if (sleep_type == SBI_SUSP_AE350_LIGHT_SLEEP) {
- rc = check_secondary_harts_sleep(hartid, false);
+ rc = wait_secondary_harts_sleep(hartid, false);
if (rc)
- return rc;
+ goto err_restore_mie;
+ /* Clock-gated only: enable SEI to resume past the WFI */
+ csr_set(CSR_MIE, MIP_SEIP);
atcsmu_set_command(LIGHT_SLEEP_CMD, hartid);
} else if (sleep_type == SBI_SUSP_SLEEP_TYPE_SUSPEND) {
- rc = check_secondary_harts_sleep(hartid, true);
+ rc = wait_secondary_harts_sleep(hartid, true);
if (rc)
- return rc;
+ goto err_restore_mie;
- atcsmu_set_command(DEEP_SLEEP_CMD, hartid);
rc = atcsmu_set_reset_vector((ulong)ae350_enable_coherency_warmboot, hartid);
if (rc)
- return rc;
+ goto err_restore_mie;
ae350_non_ret_save(sbi_scratch_thishart_ptr());
- fdt_cmo_llc_enable(false);
+
+ /* No LLC is fine; only fail on real errors */
+ rc = fdt_cmo_llc_enable(false);
+ if (rc && rc != SBI_ENODEV)
+ goto err_discard_save;
+
rc = fdt_cmo_llc_flush_all();
- if (rc)
- return rc;
+ if (rc && rc != SBI_ENODEV)
+ goto err_enable_llc;
+
+ atcsmu_set_command(DEEP_SLEEP_CMD, hartid);
}
ae350_disable_coherency();
@@ -84,6 +105,15 @@ static int ae350_system_suspend(u32 sleep_type, unsigned long addr)
ae350_enable_coherency();
return SBI_OK;
+
+err_enable_llc:
+ fdt_cmo_llc_enable(true);
+err_discard_save:
+ ae350_non_ret_discard(sbi_scratch_thishart_ptr());
+err_restore_mie:
+ csr_write(CSR_MIE, saved_mie);
+
+ return rc;
}
static void ae350_system_resume(void)
@@ -91,8 +121,10 @@ static void ae350_system_resume(void)
u32 hartid = current_hartid();
u32 sleep_type = atcsmu_get_sleep_type(hartid);
- if (sleep_type == SBI_SUSP_SLEEP_TYPE_SUSPEND)
+ if (sleep_type == SBI_SUSP_SLEEP_TYPE_SUSPEND) {
fdt_cmo_llc_enable(true);
+ ae350_non_ret_restore(sbi_scratch_thishart_ptr());
+ }
}
static struct sbi_system_suspend_device suspend_andes_atcsmu = {