aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--firmware/fw_base.S27
-rw-r--r--include/sbi/sbi_platform.h63
-rw-r--r--lib/sbi/sbi_init.c4
-rw-r--r--lib/sbi/sbi_scratch.c7
-rw-r--r--lib/utils/fdt/fdt_helper.c2
-rw-r--r--platform/sifive/fu540/platform.c14
6 files changed, 89 insertions, 28 deletions
diff --git a/firmware/fw_base.S b/firmware/fw_base.S
index dbe5b10..d2aca98 100644
--- a/firmware/fw_base.S
+++ b/firmware/fw_base.S
@@ -351,6 +351,7 @@ _start_warm:
csrw CSR_MIE, zero
csrw CSR_MIP, zero
+ /* Find HART count and HART stack size */
la a4, platform
#if __riscv_xlen == 64
lwu s7, SBI_PLATFORM_HART_COUNT_OFFSET(a4)
@@ -359,12 +360,29 @@ _start_warm:
lw s7, SBI_PLATFORM_HART_COUNT_OFFSET(a4)
lw s8, SBI_PLATFORM_HART_STACK_SIZE_OFFSET(a4)
#endif
+ REG_L s9, SBI_PLATFORM_HART_INDEX2ID_OFFSET(a4)
- /* HART ID should be within expected limit */
+ /* Find HART id */
csrr s6, CSR_MHARTID
- bge s6, s7, _start_hang
- /* find the scratch space for this hart */
+ /* Find HART index */
+ beqz s9, 3f
+ li a4, 0
+1:
+#if __riscv_xlen == 64
+ lwu a5, (s9)
+#else
+ lw a5, (s9)
+#endif
+ beq a5, s6, 2f
+ add s9, s9, 4
+ add a4, a4, 1
+ blt a4, s7, 1b
+ li a4, -1
+2: add s6, a4, zero
+3: bge s6, s7, _start_hang
+
+ /* Find the scratch space based on HART index */
la tp, _fw_end
mul a5, s7, s8
add tp, tp, a5
@@ -411,6 +429,7 @@ _link_end:
_hartid_to_scratch:
/*
* a0 -> HART ID (passed by caller)
+ * a1 -> HART Index (passed by caller)
* t0 -> HART Stack Size
* t1 -> HART Stack End
* t2 -> Temporary
@@ -423,7 +442,7 @@ _hartid_to_scratch:
lw t0, SBI_PLATFORM_HART_STACK_SIZE_OFFSET(t2)
lw t2, SBI_PLATFORM_HART_COUNT_OFFSET(t2)
#endif
- sub t2, t2, a0
+ sub t2, t2, a1
mul t2, t2, t0
la t1, _fw_end
add t1, t1, t2
diff --git a/include/sbi/sbi_platform.h b/include/sbi/sbi_platform.h
index 0264732..c47ab46 100644
--- a/include/sbi/sbi_platform.h
+++ b/include/sbi/sbi_platform.h
@@ -33,6 +33,8 @@
#define SBI_PLATFORM_OPS_OFFSET (0x58)
/** Offset of firmware_context in struct sbi_platform */
#define SBI_PLATFORM_FIRMWARE_CONTEXT_OFFSET (0x58 + __SIZEOF_POINTER__)
+/** Offset of hart_index2id in struct sbi_platform */
+#define SBI_PLATFORM_HART_INDEX2ID_OFFSET (0x58 + (__SIZEOF_POINTER__ * 2))
#define SBI_PLATFORM_TLB_RANGE_FLUSH_LIMIT_DEFAULT (1UL << 12)
@@ -136,9 +138,6 @@ struct sbi_platform_operations {
/** Exit platform timer for current HART */
void (*timer_exit)(void);
- /** Check whether given hart is disabled */
- bool (*hart_disabled)(u32 hartid);
-
/** Bringup the given hart from previous stage **/
int (*hart_start)(u32 hartid, ulong saddr, ulong priv);
/**
@@ -190,6 +189,22 @@ struct sbi_platform {
unsigned long platform_ops_addr;
/** Pointer to system firmware specific context */
unsigned long firmware_context;
+ /**
+ * HART index to HART id table
+ *
+ * For used HART index <abc>:
+ * hart_index2id[<abc>] = some HART id
+ * For unused HART index <abc>:
+ * hart_index2id[<abc>] = -1U
+ *
+ * If hart_index2id == NULL then we assume identity mapping
+ * hart_index2id[<abc>] = <abc>
+ *
+ * We have only two restrictions:
+ * 1. HART index < sbi_platform hart_count
+ * 2. HART id < SBI_HARTMASK_MAX_BITS
+ */
+ const u32 *hart_index2id;
} __packed;
/** Get pointer to sbi_platform for sbi_scratch pointer */
@@ -282,22 +297,46 @@ static inline u32 sbi_platform_hart_stack_size(const struct sbi_platform *plat)
}
/**
- * Check whether the given HART is disabled
+ * Get HART index for the given HART
*
* @param plat pointer to struct sbi_platform
* @param hartid HART ID
*
- * @return TRUE if HART is disabled and FALSE otherwise
+ * @return 0 <= value < hart_count for valid HART otherwise -1U
*/
-static inline bool sbi_platform_hart_disabled(const struct sbi_platform *plat,
- u32 hartid)
+static inline u32 sbi_platform_hart_index(const struct sbi_platform *plat,
+ u32 hartid)
{
- if (plat) {
- if (sbi_platform_hart_count(plat) <= hartid)
- return TRUE;
- if (sbi_platform_ops(plat)->hart_disabled)
- return sbi_platform_ops(plat)->hart_disabled(hartid);
+ u32 i;
+
+ if (!plat)
+ return -1U;
+ if (plat->hart_index2id) {
+ for (i = 0; i < plat->hart_count; i++) {
+ if (plat->hart_index2id[i] == hartid)
+ return i;
+ }
+ return -1U;
}
+
+ return hartid;
+}
+
+/**
+ * Check whether given HART is invalid
+ *
+ * @param plat pointer to struct sbi_platform
+ * @param hartid HART ID
+ *
+ * @return TRUE if HART is invalid and FALSE otherwise
+ */
+static inline bool sbi_platform_hart_invalid(const struct sbi_platform *plat,
+ u32 hartid)
+{
+ if (!plat)
+ return TRUE;
+ if (plat->hart_count <= sbi_platform_hart_index(plat, hartid))
+ return TRUE;
return FALSE;
}
diff --git a/lib/sbi/sbi_init.c b/lib/sbi/sbi_init.c
index 1c2f6b9..2b9afb7 100644
--- a/lib/sbi/sbi_init.c
+++ b/lib/sbi/sbi_init.c
@@ -279,7 +279,7 @@ void __noreturn sbi_init(struct sbi_scratch *scratch)
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
if ((SBI_HARTMASK_MAX_BITS <= hartid) ||
- sbi_platform_hart_disabled(plat, hartid))
+ sbi_platform_hart_invalid(plat, hartid))
sbi_hart_hang();
if (atomic_add_return(&coldboot_lottery, 1) == 1)
@@ -322,7 +322,7 @@ void __noreturn sbi_exit(struct sbi_scratch *scratch)
u32 hartid = current_hartid();
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
- if (sbi_platform_hart_disabled(plat, hartid))
+ if (sbi_platform_hart_invalid(plat, hartid))
sbi_hart_hang();
sbi_platform_early_exit(plat);
diff --git a/lib/sbi/sbi_scratch.c b/lib/sbi/sbi_scratch.c
index a756fa7..8b63570 100644
--- a/lib/sbi/sbi_scratch.c
+++ b/lib/sbi/sbi_scratch.c
@@ -19,7 +19,7 @@ struct sbi_scratch *hartid_to_scratch_table[SBI_HARTMASK_MAX_BITS] = { 0 };
static spinlock_t extra_lock = SPIN_LOCK_INITIALIZER;
static unsigned long extra_offset = SBI_SCRATCH_EXTRA_SPACE_OFFSET;
-typedef struct sbi_scratch *(*hartid2scratch)(ulong hartid);
+typedef struct sbi_scratch *(*hartid2scratch)(ulong hartid, ulong hartindex);
int sbi_scratch_init(struct sbi_scratch *scratch)
{
@@ -27,10 +27,11 @@ int sbi_scratch_init(struct sbi_scratch *scratch)
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
for (i = 0; i < SBI_HARTMASK_MAX_BITS; i++) {
- if (sbi_platform_hart_disabled(plat, i))
+ if (sbi_platform_hart_invalid(plat, i))
continue;
hartid_to_scratch_table[i] =
- ((hartid2scratch)scratch->hartid_to_scratch)(i);
+ ((hartid2scratch)scratch->hartid_to_scratch)(i,
+ sbi_platform_hart_index(plat, i));
}
return 0;
diff --git a/lib/utils/fdt/fdt_helper.c b/lib/utils/fdt/fdt_helper.c
index 47cd1d3..2ea52ca 100644
--- a/lib/utils/fdt/fdt_helper.c
+++ b/lib/utils/fdt/fdt_helper.c
@@ -30,7 +30,7 @@ void fdt_cpu_fixup(void *fdt)
sbi_sprintf(cpu_node, "/cpus/cpu@%d", i);
cpu_offset = fdt_path_offset(fdt, cpu_node);
- if (sbi_platform_hart_disabled(plat, i))
+ if (sbi_platform_hart_invalid(plat, i))
fdt_setprop_string(fdt, cpu_offset, "status",
"disabled");
diff --git a/platform/sifive/fu540/platform.c b/platform/sifive/fu540/platform.c
index db647ca..6714cd5 100644
--- a/platform/sifive/fu540/platform.c
+++ b/platform/sifive/fu540/platform.c
@@ -165,10 +165,12 @@ static int fu540_timer_init(bool cold_boot)
return clint_warm_timer_init();
}
-static bool fu540_hart_disabled(u32 hartid)
-{
- return (FU540_HARITD_DISABLED & (1UL << hartid)) ? TRUE : FALSE;
-}
+static u32 fu540_hart_index2id[FU540_HART_COUNT - 1] = {
+ [0] = 1,
+ [1] = 2,
+ [2] = 3,
+ [3] = 4,
+};
static int fu540_system_down(u32 type)
{
@@ -192,7 +194,6 @@ const struct sbi_platform_operations platform_ops = {
.timer_event_stop = clint_timer_event_stop,
.timer_event_start = clint_timer_event_start,
.timer_init = fu540_timer_init,
- .hart_disabled = fu540_hart_disabled,
.system_reboot = fu540_system_down,
.system_shutdown = fu540_system_down
};
@@ -202,7 +203,8 @@ const struct sbi_platform platform = {
.platform_version = SBI_PLATFORM_VERSION(0x0, 0x01),
.name = "SiFive Freedom U540",
.features = SBI_PLATFORM_DEFAULT_FEATURES,
- .hart_count = FU540_HART_COUNT,
+ .hart_count = (FU540_HART_COUNT - 1),
+ .hart_index2id = fu540_hart_index2id,
.hart_stack_size = SBI_PLATFORM_DEFAULT_HART_STACK_SIZE,
.platform_ops_addr = (unsigned long)&platform_ops
};