diff options
-rw-r--r-- | firmware/fw_base.S | 27 | ||||
-rw-r--r-- | include/sbi/sbi_platform.h | 63 | ||||
-rw-r--r-- | lib/sbi/sbi_init.c | 4 | ||||
-rw-r--r-- | lib/sbi/sbi_scratch.c | 7 | ||||
-rw-r--r-- | lib/utils/fdt/fdt_helper.c | 2 | ||||
-rw-r--r-- | platform/sifive/fu540/platform.c | 14 |
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 }; |