8 Commits

Author SHA1 Message Date
Chao Wei
15c8ab7701 SG2044: add t-head c9xx jtlb errta
Signed-off-by: Chao Wei <chao.wei@sophgo.com>
2026-01-06 16:44:47 +08:00
haijiao.liu
78f021d248 lib: Add SG2044 CPPC support
Signed-off-by: haijiao.liu <haijiao.liu@sophgo.com>
2025-04-25 06:30:33 +08:00
Xiaoguang Xing
df02b2f353 github: Do not use upstream review
Signed-off-by: Xiaoguang Xing <xiaoguang.xing@sophgo.com>
2025-03-31 15:09:32 +08:00
Xiaoguang Xing
7f6a748be6 makefile: Remove linker garbage collection print
See commmit 0171cfc("Makefile: enable --gc-sections").

Signed-off-by: Xiaoguang Xing <xiaoguang.xing@sophgo.com>
2025-03-31 15:09:24 +08:00
haijiao.liu
da2348b161 lib: Fix warning message of timer in boot phase
Optimize the reset driver to prevent the use of the timer function
before the timer driver initialization is completed, which resloves
the following warning messages:

sbi_timer_delay_loop: called without timer device

Signed-off-by: haijiao.liu <haijiao.liu@sophgo.com>
2025-03-31 15:09:17 +08:00
Xiaoguang Xing
999ec3b2e7 platform: Fix when no serial node in dtb
SOPHGO BM1690 SoC TP dtb has not serial node.

Signed-off-by: bowen.pang <bowen.pang@sophgo.com>
2025-03-31 15:09:17 +08:00
Xiaoguang Xing
e285bad3c3 lib: Add mtimer and mswi support for BM1690 AP and TP
mswi and mtimer' address of bm1690 ap and tp is not contiguous,
so make them separately.

Signed-off-by: Xiaoguang Xing <xiaoguang.xing@sophgo.com>
2025-03-31 15:08:44 +08:00
Inochi Amaoto
7225632021 platform: generic: thead: Add Sophgo SG2044
The Sophgo SG2044 is a new version of C920, although it supports
sscofpmf, it still needs this pmu quirks its cores.

Signed-off-by: Inochi Amaoto <inochiama@gmail.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2025-03-31 15:08:18 +08:00
167 changed files with 2615 additions and 3943 deletions

View File

@@ -94,26 +94,20 @@ OPENSBI_VERSION_MINOR=`grep "define OPENSBI_VERSION_MINOR" $(include_dir)/sbi/sb
OPENSBI_VERSION_GIT=
# Detect 'git' presence before issuing 'git' commands
GIT_AVAIL := $(shell command -v git 2> /dev/null)
GIT_AVAIL=$(shell command -v git 2> /dev/null)
ifneq ($(GIT_AVAIL),)
GIT_DIR := $(shell git rev-parse --git-dir 2> /dev/null)
GIT_DIR=$(shell git rev-parse --git-dir 2> /dev/null)
ifneq ($(GIT_DIR),)
OPENSBI_VERSION_GIT := $(shell if [ -d $(GIT_DIR) ]; then git describe 2> /dev/null; fi)
OPENSBI_VERSION_GIT=$(shell if [ -d $(GIT_DIR) ]; then git describe 2> /dev/null; fi)
endif
endif
# Setup compilation commands
ifneq ($(LLVM),)
ifneq ($(filter %/,$(LLVM)),)
LLVM_PREFIX := $(LLVM)
else ifneq ($(filter -%,$(LLVM)),)
LLVM_SUFFIX := $(LLVM)
endif
CC = $(LLVM_PREFIX)clang$(LLVM_SUFFIX)
AR = $(LLVM_PREFIX)llvm-ar$(LLVM_SUFFIX)
LD = $(LLVM_PREFIX)ld.lld$(LLVM_SUFFIX)
OBJCOPY = $(LLVM_PREFIX)llvm-objcopy$(LLVM_SUFFIX)
CC = clang
AR = llvm-ar
LD = ld.lld
OBJCOPY = llvm-objcopy
else
ifdef CROSS_COMPILE
CC = $(CROSS_COMPILE)gcc
@@ -180,11 +174,6 @@ else
USE_LD_FLAG = -fuse-ld=bfd
endif
REPRODUCIBLE ?= n
ifeq ($(REPRODUCIBLE),y)
REPRODUCIBLE_FLAGS += -ffile-prefix-map=$(src_dir)=
endif
# Check whether the linker supports creating PIEs
OPENSBI_LD_PIE := $(shell $(CC) $(CLANG_TARGET) $(RELAX_FLAG) $(USE_LD_FLAG) -fPIE -nostdlib -Wl,-pie -x c /dev/null -o /dev/null >/dev/null 2>&1 && echo y || echo n)
@@ -213,18 +202,16 @@ endif
BUILD_INFO ?= n
ifeq ($(BUILD_INFO),y)
OPENSBI_BUILD_DATE_FMT = +%Y-%m-%d %H:%M:%S %z
ifndef OPENSBI_BUILD_TIME_STAMP
ifdef SOURCE_DATE_EPOCH
OPENSBI_BUILD_TIME_STAMP := $(shell date -u -d "@$(SOURCE_DATE_EPOCH)" \
OPENSBI_BUILD_TIME_STAMP ?= $(shell date -u -d "@$(SOURCE_DATE_EPOCH)" \
"$(OPENSBI_BUILD_DATE_FMT)" 2>/dev/null || \
date -u -r "$(SOURCE_DATE_EPOCH)" \
"$(OPENSBI_BUILD_DATE_FMT)" 2>/dev/null || \
date -u "$(OPENSBI_BUILD_DATE_FMT)")
else
OPENSBI_BUILD_TIME_STAMP := $(shell date "$(OPENSBI_BUILD_DATE_FMT)")
OPENSBI_BUILD_TIME_STAMP ?= $(shell date "$(OPENSBI_BUILD_DATE_FMT)")
endif
endif
OPENSBI_BUILD_COMPILER_VERSION := $(shell $(CC) -v 2>&1 | grep ' version ' | \
OPENSBI_BUILD_COMPILER_VERSION=$(shell $(CC) -v 2>&1 | grep ' version ' | \
sed 's/[[:space:]]*$$//')
endif
@@ -363,7 +350,6 @@ ifeq ($(BUILD_INFO),y)
GENFLAGS += -DOPENSBI_BUILD_TIME_STAMP="\"$(OPENSBI_BUILD_TIME_STAMP)\""
GENFLAGS += -DOPENSBI_BUILD_COMPILER_VERSION="\"$(OPENSBI_BUILD_COMPILER_VERSION)\""
endif
GENFLAGS += -include $(include_dir)/sbi/sbi_visibility.h
ifdef PLATFORM
GENFLAGS += -include $(KCONFIG_AUTOHEADER)
endif
@@ -373,8 +359,6 @@ GENFLAGS += $(firmware-genflags-y)
CFLAGS = -g -Wall -Werror -ffreestanding -nostdlib -fno-stack-protector -fno-strict-aliasing -ffunction-sections -fdata-sections
CFLAGS += -fno-omit-frame-pointer -fno-optimize-sibling-calls
CFLAGS += -fno-asynchronous-unwind-tables -fno-unwind-tables
CFLAGS += $(REPRODUCIBLE_FLAGS)
# Optionally supported flags
ifeq ($(CC_SUPPORT_VECTOR),y)
CFLAGS += -DOPENSBI_CC_SUPPORT_VECTOR
@@ -400,7 +384,6 @@ CPPFLAGS += $(firmware-cppflags-y)
ASFLAGS = -g -Wall -nostdlib
ASFLAGS += -fno-omit-frame-pointer -fno-optimize-sibling-calls
ASFLAGS += -fPIE
ASFLAGS += $(REPRODUCIBLE_FLAGS)
# Optionally supported flags
ifeq ($(CC_SUPPORT_SAVE_RESTORE),y)
ASFLAGS += -mno-save-restore
@@ -444,7 +427,6 @@ DTSCPPFLAGS = $(CPPFLAGS) -nostdinc -nostdlib -fno-builtin -D__DTS__ -x assemble
ifneq ($(DEBUG),)
CFLAGS += -O0
ELFFLAGS += -Wl,--print-gc-sections
else
CFLAGS += -O2
endif

View File

@@ -99,7 +99,7 @@ capable enough to bring up all other non-booting harts using HSM extension.
Required Toolchain and Packages
-------------------------------
OpenSBI can be compiled natively or cross-compiled on a host machine. For
OpenSBI can be compiled natively or cross-compiled on a x86 host. For
cross-compilation, you can build your own toolchain, download a prebuilt one
from the [Bootlin toolchain repository] or install a distribution-provided
toolchain; if you opt to use LLVM/Clang, most distribution toolchains will
@@ -108,12 +108,16 @@ LLVM/Clang toolchain due to LLVM's ability to support multiple backends in the
same binary, so is often an easy way to obtain a working cross-compilation
toolchain.
Toolchains with Position Independent Executable (PIE) support like
*riscv64-linux-gnu-gcc*, *riscv64-unknown-freebsd-gcc*, or *Clang/LLVM* are
required in order to generate PIE firmware images that can run at arbitrary
address with appropriate alignment. Bare-metal GNU toolchains (e.g.
*riscv64-unknown-elf-gcc*) cannot be used. *Clang/LLVM* can still generate PIE
images if a bare-metal triple is used (e.g. *-target riscv64-unknown-elf*).
Basically, we prefer toolchains with Position Independent Executable (PIE)
support like *riscv64-linux-gnu-gcc*, *riscv64-unknown-freebsd-gcc*, or
*Clang/LLVM* as they generate PIE firmware images that can run at arbitrary
address with appropriate alignment. If a bare-metal GNU toolchain (e.g.
*riscv64-unknown-elf-gcc*) is used, static linked firmware images are
generated instead. *Clang/LLVM* can still generate PIE images if a bare-metal
triple is used (e.g. *-target riscv64-unknown-elf*).
Please note that only a 64-bit version of the toolchain is available in
the Bootlin toolchain repository for now.
In addition to a toolchain, OpenSBI also requires the following packages on
the host:
@@ -252,18 +256,6 @@ option with:
make LLVM=1
```
To build with a specific version of LLVM, a path to a directory containing the
LLVM tools can be provided:
```
make LLVM=/path/to/llvm/
```
If you have versioned llvm tools you would like to use, such as `clang-17`, the LLVM variable can
be set as:
```
make LLVM=-17
```
When using Clang, *CROSS_COMPILE* often does not need to be defined unless
using GNU binutils with prefixed binary names. *PLATFORM_RISCV_XLEN* will be
used to infer a default triple to pass to Clang, so if *PLATFORM_RISCV_XLEN*

View File

@@ -19,10 +19,6 @@ Base Platform Requirements
The base RISC-V platform requirements for OpenSBI are as follows:
1. At least rv32ima_zicsr or rv64ima_zicsr required on all HARTs
* Users may restrict the usage of atomic instructions to lr/sc
via rv32im_zalrsc_zicsr or rv64im_zalrsc_zicsr if preferred
2. At least one HART should have S-mode support because:
* SBI calls are meant for RISC-V S-mode (Supervisor mode)

View File

@@ -74,10 +74,10 @@ pmu {
<0x10000 0x10033 0x000ff000>;
/* For event ID 0x0002 */
riscv,raw-event-to-mhpmcounters = <0x0000 0x0002 0xffffffff 0xffffffff 0x00000f8>,
/* For event ID 0-15 */
/* For event ID 0-4 */
<0x0 0x0 0xffffffff 0xfffffff0 0x00000ff0>,
/* For event ID 0xffffffff0000000f - 0xffffffff000000ff */
<0xffffffff 0xf 0xffffffff 0xffffff0f 0x00000ff0>;
<0xffffffff 0x0 0xffffffff 0xffffff0f 0x00000ff0>;
};
```

View File

@@ -59,18 +59,8 @@ _try_lottery:
/* Jump to relocation wait loop if we don't get relocation lottery */
lla a6, _boot_lottery
li a7, BOOT_LOTTERY_ACQUIRED
#ifdef __riscv_atomic
amoswap.w a6, a7, (a6)
bnez a6, _wait_for_boot_hart
#elif __riscv_zalrsc
_sc_fail:
lr.w t0, (a6)
sc.w t1, a7, (a6)
bnez t1, _sc_fail
bnez t0, _wait_for_boot_hart
#else
#error "need a or zalrsc"
#endif
/* relocate the global table content */
li t0, FW_TEXT_START /* link start */
@@ -302,7 +292,7 @@ _fdt_reloc_done:
REG_S t0, 0(t1)
j _start_warm
/* waiting for boot hart to be done (_boot_status == BOOT_STATUS_BOOT_HART_DONE) */
/* waiting for boot hart to be done (_boot_status == 2) */
_wait_for_boot_hart:
li t0, BOOT_STATUS_BOOT_HART_DONE
lla t1, _boot_status

View File

@@ -30,18 +30,7 @@ _start:
/* Pick one hart to run the main boot sequence */
lla a3, _hart_lottery
li a2, 1
#ifdef __riscv_atomic
amoadd.w a3, a2, (a3)
#elif __riscv_zalrsc
_sc_fail:
lr.w t0, (a3)
addw t1, t0, a2
sc.w t1, t1, (a3)
bnez t1, _sc_fail
move a3, t0
#else
#error "need a or zalrsc"
#endif
bnez a3, _start_hang
/* Save a0 and a1 */

View File

@@ -79,12 +79,36 @@ struct fw_dynamic_info {
* Prevent modification of struct fw_dynamic_info from affecting
* FW_DYNAMIC_INFO_xxx_OFFSET
*/
assert_member_offset(struct fw_dynamic_info, magic, FW_DYNAMIC_INFO_MAGIC_OFFSET);
assert_member_offset(struct fw_dynamic_info, version, FW_DYNAMIC_INFO_VERSION_OFFSET);
assert_member_offset(struct fw_dynamic_info, next_addr, FW_DYNAMIC_INFO_NEXT_ADDR_OFFSET);
assert_member_offset(struct fw_dynamic_info, next_mode, FW_DYNAMIC_INFO_NEXT_MODE_OFFSET);
assert_member_offset(struct fw_dynamic_info, options, FW_DYNAMIC_INFO_OPTIONS_OFFSET);
assert_member_offset(struct fw_dynamic_info, boot_hart, FW_DYNAMIC_INFO_BOOT_HART_OFFSET);
_Static_assert(
offsetof(struct fw_dynamic_info, magic)
== FW_DYNAMIC_INFO_MAGIC_OFFSET,
"struct fw_dynamic_info definition has changed, please redefine "
"FW_DYNAMIC_INFO_MAGIC_OFFSET");
_Static_assert(
offsetof(struct fw_dynamic_info, version)
== FW_DYNAMIC_INFO_VERSION_OFFSET,
"struct fw_dynamic_info definition has changed, please redefine "
"FW_DYNAMIC_INFO_VERSION_OFFSET");
_Static_assert(
offsetof(struct fw_dynamic_info, next_addr)
== FW_DYNAMIC_INFO_NEXT_ADDR_OFFSET,
"struct fw_dynamic_info definition has changed, please redefine "
"FW_DYNAMIC_INFO_NEXT_ADDR_OFFSET");
_Static_assert(
offsetof(struct fw_dynamic_info, next_mode)
== FW_DYNAMIC_INFO_NEXT_MODE_OFFSET,
"struct fw_dynamic_info definition has changed, please redefine "
"FW_DYNAMIC_INFO_NEXT_MODE_OFFSET");
_Static_assert(
offsetof(struct fw_dynamic_info, options)
== FW_DYNAMIC_INFO_OPTIONS_OFFSET,
"struct fw_dynamic_info definition has changed, please redefine "
"FW_DYNAMIC_INFO_OPTIONS_OFFSET");
_Static_assert(
offsetof(struct fw_dynamic_info, boot_hart)
== FW_DYNAMIC_INFO_BOOT_HART_OFFSET,
"struct fw_dynamic_info definition has changed, please redefine "
"FW_DYNAMIC_INFO_BOOT_HART_OFFSET");
#endif

View File

@@ -156,26 +156,6 @@
: "memory"); \
})
#if __riscv_xlen == 64
#define __csrrw64(op, csr, csrh, val) (true ? op(csr, val) : (uint64_t)csrh)
#define __csrr64( op, csr, csrh) (true ? op(csr) : (uint64_t)csrh)
#define __csrw64( op, csr, csrh, val) (true ? op(csr, val) : (uint64_t)csrh)
#elif __riscv_xlen == 32
#define __csrrw64(op, csr, csrh, val) ( op(csr, val) | (uint64_t)op(csrh, val >> 32) << 32)
#define __csrr64( op, csr, csrh) ( op(csr) | (uint64_t)op(csrh) << 32)
#define __csrw64( op, csr, csrh, val) ({ op(csr, val); op(csrh, val >> 32); })
#endif
#define csr_swap64( csr, val) __csrrw64(csr_swap, csr, csr ## H, val)
#define csr_read64( csr) __csrr64 (csr_read, csr, csr ## H)
#define csr_read_relaxed64(csr) __csrr64 (csr_read_relaxed, csr, csr ## H)
#define csr_write64( csr, val) __csrw64 (csr_write, csr, csr ## H, val)
#define csr_read_set64( csr, val) __csrrw64(csr_read_set, csr, csr ## H, val)
#define csr_set64( csr, val) __csrw64 (csr_set, csr, csr ## H, val)
#define csr_clear64( csr, val) __csrw64 (csr_clear, csr, csr ## H, val)
#define csr_read_clear64( csr, val) __csrrw64(csr_read_clear, csr, csr ## H, val)
#define csr_clear64( csr, val) __csrw64 (csr_clear, csr, csr ## H, val)
unsigned long csr_read_num(int csr_num);
void csr_write_num(int csr_num, unsigned long val);

View File

@@ -32,8 +32,7 @@
#define MSTATUS_TVM _UL(0x00100000)
#define MSTATUS_TW _UL(0x00200000)
#define MSTATUS_TSR _UL(0x00400000)
#define MSTATUS_SPELP _UL(0x00800000)
#define MSTATUS_SDT _UL(0x01000000)
#define MSTATUS_SPELP _UL(0x00800000)
#define MSTATUS32_SD _UL(0x80000000)
#if __riscv_xlen == 64
#define MSTATUS_UXL _ULL(0x0000000300000000)
@@ -86,8 +85,6 @@
#define HSTATUS_GVA _UL(0x00000040)
#define HSTATUS_VSBE _UL(0x00000020)
#define MTVEC_MODE _UL(0x00000003)
#define MCAUSE_IRQ_MASK (_UL(1) << (__riscv_xlen - 1))
#define IRQ_S_SOFT 1
@@ -378,17 +375,6 @@
#define CSR_SSTATEEN2 0x10E
#define CSR_SSTATEEN3 0x10F
/* Machine-Level Control transfer records CSRs */
#define CSR_MCTRCTL 0x34e
/* Supervisor-Level Control transfer records CSRs */
#define CSR_SCTRCTL 0x14e
#define CSR_SCTRSTATUS 0x14f
#define CSR_SCTRDEPTH 0x15f
/* VS-Level Control transfer records CSRs */
#define CSR_VSCTRCTL 0x24e
/* ===== Hypervisor-level CSRs ===== */
/* Hypervisor Trap Setup (H-extension) */
@@ -813,8 +799,6 @@
#define SMSTATEEN0_CS (_ULL(1) << SMSTATEEN0_CS_SHIFT)
#define SMSTATEEN0_FCSR_SHIFT 1
#define SMSTATEEN0_FCSR (_ULL(1) << SMSTATEEN0_FCSR_SHIFT)
#define SMSTATEEN0_CTR_SHIFT 54
#define SMSTATEEN0_CTR (_ULL(1) << SMSTATEEN0_CTR_SHIFT)
#define SMSTATEEN0_CONTEXT_SHIFT 57
#define SMSTATEEN0_CONTEXT (_ULL(1) << SMSTATEEN0_CONTEXT_SHIFT)
#define SMSTATEEN0_IMSIC_SHIFT 58
@@ -986,14 +970,13 @@
#define INSN_MATCH_VS4RV 0x62800027
#define INSN_MATCH_VS8RV 0xe2800027
#define INSN_OPCODE_MASK 0x7f
#define INSN_OPCODE_VECTOR_LOAD 0x07
#define INSN_OPCODE_VECTOR_STORE 0x27
#define INSN_OPCODE_AMO 0x2f
#define INSN_MASK_VECTOR_LOAD_STORE 0x7f
#define INSN_MATCH_VECTOR_LOAD 0x07
#define INSN_MATCH_VECTOR_STORE 0x27
#define IS_VECTOR_LOAD_STORE(insn) \
((((insn) & INSN_OPCODE_MASK) == INSN_OPCODE_VECTOR_LOAD) || \
(((insn) & INSN_OPCODE_MASK) == INSN_OPCODE_VECTOR_STORE))
((((insn) & INSN_MASK_VECTOR_LOAD_STORE) == INSN_MATCH_VECTOR_LOAD) || \
(((insn) & INSN_MASK_VECTOR_LOAD_STORE) == INSN_MATCH_VECTOR_STORE))
#define IS_VECTOR_INSN_MATCH(insn, match, mask) \
(((insn) & (mask)) == ((match) & (mask)))
@@ -1287,17 +1270,6 @@
#error "Unexpected __riscv_xlen"
#endif
#define MASK_FUNCT3 0x7000
#define SHIFT_FUNCT3 12
#define MASK_RS1 0xf8000
#define MASK_CSR 0xfff00000
#define SHIFT_CSR 20
#define MASK_AQRL 0x06000000
#define SHIFT_AQRL 25
#define VM_MASK 0x1
#define VIEW_MASK 0x3
#define VSEW_MASK 0x3
@@ -1365,11 +1337,10 @@
#define REG_PTR(insn, pos, regs) \
(ulong *)((ulong)(regs) + REG_OFFSET(insn, pos))
#define GET_FUNC3(insn) ((insn & MASK_FUNCT3) >> SHIFT_FUNCT3)
#define GET_RM(insn) GET_FUNC3(insn)
#define GET_RM(insn) ((insn & MASK_FUNCT3) >> SHIFT_FUNCT3)
#define GET_RS1_NUM(insn) ((insn & MASK_RS1) >> 15)
#define GET_CSR_NUM(insn) ((insn & MASK_CSR) >> SHIFT_CSR)
#define GET_AQRL(insn) ((insn & MASK_AQRL) >> SHIFT_AQRL)
#define GET_RS1(insn, regs) (*REG_PTR(insn, SH_RS1, regs))
#define GET_RS2(insn, regs) (*REG_PTR(insn, SH_RS2, regs))
@@ -1394,6 +1365,13 @@
#define GET_VEMUL(vlmul, view, vsew) ((vlmul + view - vsew) & 7)
#define GET_EMUL(vemul) (1UL << ((vemul) >= 4 ? 0 : (vemul)))
#define MASK_FUNCT3 0x7000
#define MASK_RS1 0xf8000
#define MASK_CSR 0xfff00000
#define SHIFT_FUNCT3 12
#define SHIFT_CSR 20
#define CSRRW 1
#define CSRRS 2
#define CSRRC 3

View File

@@ -130,17 +130,4 @@ static inline void bitmap_xor(unsigned long *dst, const unsigned long *src1,
__bitmap_xor(dst, src1, src2, nbits);
}
static inline int bitmap_weight(const unsigned long *src, int nbits)
{
int i, res = 0;
for (i = 0; i < nbits / BITS_PER_LONG; i++)
res += sbi_popcount(src[i]);
if (nbits % BITS_PER_LONG)
res += sbi_popcount(src[i] & BITMAP_LAST_WORD_MASK(nbits));
return res;
}
#endif

View File

@@ -125,22 +125,14 @@ static inline unsigned long sbi_fls(unsigned long word)
*/
static inline unsigned long sbi_popcount(unsigned long word)
{
unsigned long count;
unsigned long count = 0;
#if BITS_PER_LONG == 64
count = word - ((word >> 1) & 0x5555555555555555ul);
count = (count & 0x3333333333333333ul) + ((count >> 2) & 0x3333333333333333ul);
count = (count + (count >> 4)) & 0x0F0F0F0F0F0F0F0Ful;
count = count + (count >> 8);
count = count + (count >> 16);
return (count + (count >> 32)) & 0x00000000000000FFul;
#else
count = word - ((word >> 1) & 0x55555555);
count = (count & 0x33333333) + ((count >> 2) & 0x33333333);
count = (count + (count >> 4)) & 0x0F0F0F0F;
count = count + (count >> 8);
return (count + (count >> 16)) & 0x000000FF;
#endif
while (word) {
word &= word - 1;
count++;
}
return count;
}
#define for_each_set_bit(bit, addr, size) \

32
include/sbi/sbi_clk.h Normal file
View File

@@ -0,0 +1,32 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2025 Sophgo Inc.
*
* Authors:
* Haijiao Liu <haijiao.liu@sophgo.com>
*/
#ifndef __SBI_CLK_H__
#define __SBI_CLK_H__
#include <sbi/sbi_types.h>
/* clock device */
struct sbi_clk_device {
char name[32];
int (*clk_set_rate)(const char *name, uint64_t rate);
uint64_t (*clk_get_rate)(const char *name);
int (*clk_enable)(const char *name);
int (*clk_disable)(const char *name);
};
int sbi_clk_set_rate(const char *name, uint64_t rate);
uint64_t sbi_clk_get_rate(const char *name);
int sbi_clk_enable(const char *name);
int sbi_clk_disable(const char *name);
const struct sbi_clk_device *sbi_clk_get_device(const void *fdt);
void sbi_clk_set_device(const struct sbi_clk_device *dev);
#endif

View File

@@ -90,7 +90,7 @@ struct sbi_dbtr_hart_triggers_state {
}while (0);
/** SBI shared mem messages layout */
union sbi_dbtr_shmem_entry {
struct sbi_dbtr_shmem_entry {
struct sbi_dbtr_data_msg data;
struct sbi_dbtr_id_msg id;
};
@@ -115,7 +115,8 @@ int sbi_dbtr_uninstall_trig(unsigned long trig_idx_base,
int sbi_dbtr_enable_trig(unsigned long trig_idx_base,
unsigned long trig_idx_mask);
int sbi_dbtr_update_trig(unsigned long smode,
unsigned long trig_count);
unsigned long trig_idx_base,
unsigned long trig_idx_mask);
int sbi_dbtr_disable_trig(unsigned long trig_idx_base,
unsigned long trig_idx_mask);

View File

@@ -307,11 +307,8 @@ int sbi_domain_register(struct sbi_domain *dom,
int sbi_domain_root_add_memrange(unsigned long addr, unsigned long size,
unsigned long align, unsigned long region_flags);
/** Startup non-root domains */
int sbi_domain_startup(struct sbi_scratch *scratch, u32 cold_hartid);
/** Finalize domain tables */
int sbi_domain_finalize(struct sbi_scratch *scratch);
/** Finalize domain tables and startup non-root domains */
int sbi_domain_finalize(struct sbi_scratch *scratch, u32 cold_hartid);
/** Initialize domains */
int sbi_domain_init(struct sbi_scratch *scratch, u32 cold_hartid);

View File

@@ -1,20 +0,0 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2025 Rivos Inc.
*
* Authors:
* Clément Léger <cleger@rivosinc.com>
*/
#ifndef __SBI_DOUBLE_TRAP_H__
#define __SBI_DOUBLE_TRAP_H__
#include <sbi/sbi_types.h>
#include <sbi/sbi_trap.h>
int sbi_double_trap_handler(struct sbi_trap_context *tcntx);
void sbi_double_trap_init(struct sbi_scratch *scratch);
#endif

View File

@@ -13,7 +13,7 @@
#include <sbi/sbi_types.h>
#include <sbi/sbi_list.h>
#define SBI_ECALL_VERSION_MAJOR 3
#define SBI_ECALL_VERSION_MAJOR 2
#define SBI_ECALL_VERSION_MINOR 0
#define SBI_OPENSBI_IMPID 1

View File

@@ -380,12 +380,10 @@ enum sbi_sse_attr_id {
#define SBI_SSE_ATTR_CONFIG_ONESHOT (1 << 0)
#define SBI_SSE_ATTR_INTERRUPTED_FLAGS_SSTATUS_SPP BIT(0)
#define SBI_SSE_ATTR_INTERRUPTED_FLAGS_SSTATUS_SPIE BIT(1)
#define SBI_SSE_ATTR_INTERRUPTED_FLAGS_STATUS_SPP BIT(0)
#define SBI_SSE_ATTR_INTERRUPTED_FLAGS_STATUS_SPIE BIT(1)
#define SBI_SSE_ATTR_INTERRUPTED_FLAGS_HSTATUS_SPV BIT(2)
#define SBI_SSE_ATTR_INTERRUPTED_FLAGS_HSTATUS_SPVP BIT(3)
#define SBI_SSE_ATTR_INTERRUPTED_FLAGS_SSTATUS_SPELP BIT(4)
#define SBI_SSE_ATTR_INTERRUPTED_FLAGS_SSTATUS_SDT BIT(5)
enum sbi_sse_state {
SBI_SSE_STATE_UNUSED = 0,
@@ -395,77 +393,48 @@ enum sbi_sse_state {
};
/* SBI SSE Event IDs. */
/* Range 0x00000000 - 0x0000ffff */
#define SBI_SSE_EVENT_LOCAL_HIGH_PRIO_RAS 0x00000000
#define SBI_SSE_EVENT_LOCAL_RAS 0x00000000
#define SBI_SSE_EVENT_LOCAL_DOUBLE_TRAP 0x00000001
#define SBI_SSE_EVENT_LOCAL_RESERVED_0_START 0x00000002
#define SBI_SSE_EVENT_LOCAL_RESERVED_0_END 0x00003fff
#define SBI_SSE_EVENT_LOCAL_PLAT_0_START 0x00004000
#define SBI_SSE_EVENT_LOCAL_PLAT_0_END 0x00007fff
#define SBI_SSE_EVENT_GLOBAL_HIGH_PRIO_RAS 0x00008000
#define SBI_SSE_EVENT_GLOBAL_RESERVED_0_START 0x00008001
#define SBI_SSE_EVENT_GLOBAL_RESERVED_0_END 0x0000bfff
#define SBI_SSE_EVENT_GLOBAL_RAS 0x00008000
#define SBI_SSE_EVENT_GLOBAL_PLAT_0_START 0x0000c000
#define SBI_SSE_EVENT_GLOBAL_PLAT_0_END 0x0000ffff
/* Range 0x00010000 - 0x0001ffff */
#define SBI_SSE_EVENT_LOCAL_PMU_OVERFLOW 0x00010000
#define SBI_SSE_EVENT_LOCAL_RESERVED_1_START 0x00010001
#define SBI_SSE_EVENT_LOCAL_RESERVED_1_END 0x00013fff
#define SBI_SSE_EVENT_LOCAL_PMU 0x00010000
#define SBI_SSE_EVENT_LOCAL_PLAT_1_START 0x00014000
#define SBI_SSE_EVENT_LOCAL_PLAT_1_END 0x00017fff
#define SBI_SSE_EVENT_GLOBAL_RESERVED_1_START 0x00018000
#define SBI_SSE_EVENT_GLOBAL_RESERVED_1_END 0x0001bfff
#define SBI_SSE_EVENT_GLOBAL_PLAT_1_START 0x0001c000
#define SBI_SSE_EVENT_GLOBAL_PLAT_1_END 0x0001ffff
/* Range 0x00100000 - 0x0010ffff */
#define SBI_SSE_EVENT_LOCAL_LOW_PRIO_RAS 0x00100000
#define SBI_SSE_EVENT_LOCAL_RESERVED_2_START 0x00100001
#define SBI_SSE_EVENT_LOCAL_RESERVED_2_END 0x00103fff
#define SBI_SSE_EVENT_LOCAL_PLAT_2_START 0x00104000
#define SBI_SSE_EVENT_LOCAL_PLAT_2_END 0x00107fff
#define SBI_SSE_EVENT_LOCAL_PLAT_2_START 0x00024000
#define SBI_SSE_EVENT_LOCAL_PLAT_2_END 0x00027fff
#define SBI_SSE_EVENT_GLOBAL_PLAT_2_START 0x0002c000
#define SBI_SSE_EVENT_GLOBAL_PLAT_2_END 0x0002ffff
#define SBI_SSE_EVENT_GLOBAL_LOW_PRIO_RAS 0x00108000
#define SBI_SSE_EVENT_GLOBAL_RESERVED_2_START 0x00108001
#define SBI_SSE_EVENT_GLOBAL_RESERVED_2_END 0x0010bfff
#define SBI_SSE_EVENT_GLOBAL_PLAT_2_START 0x0010c000
#define SBI_SSE_EVENT_GLOBAL_PLAT_2_END 0x0010ffff
/* Range 0xffff0000 - 0xffffffff */
#define SBI_SSE_EVENT_LOCAL_SOFTWARE 0xffff0000
#define SBI_SSE_EVENT_LOCAL_RESERVED_3_START 0xffff0001
#define SBI_SSE_EVENT_LOCAL_RESERVED_3_END 0xffff3fff
#define SBI_SSE_EVENT_LOCAL_PLAT_3_START 0xffff4000
#define SBI_SSE_EVENT_LOCAL_PLAT_3_END 0xffff7fff
#define SBI_SSE_EVENT_GLOBAL_SOFTWARE 0xffff8000
#define SBI_SSE_EVENT_GLOBAL_RESERVED_3_START 0xffff8001
#define SBI_SSE_EVENT_GLOBAL_RESERVED_3_END 0xffffbfff
#define SBI_SSE_EVENT_GLOBAL_PLAT_3_START 0xffffc000
#define SBI_SSE_EVENT_GLOBAL_PLAT_3_END 0xffffffff
#define SBI_SSE_EVENT_GLOBAL_BIT BIT(15)
#define SBI_SSE_EVENT_PLATFORM_BIT BIT(14)
#define SBI_SSE_EVENT_GLOBAL_BIT (1 << 15)
#define SBI_SSE_EVENT_PLATFORM_BIT (1 << 14)
/* SBI function IDs for MPXY extension */
#define SBI_EXT_MPXY_GET_SHMEM_SIZE 0x0
#define SBI_EXT_MPXY_SET_SHMEM 0x1
#define SBI_EXT_MPXY_GET_CHANNEL_IDS 0x2
#define SBI_EXT_MPXY_READ_ATTRS 0x3
#define SBI_EXT_MPXY_WRITE_ATTRS 0x4
#define SBI_EXT_MPXY_SEND_MSG_WITH_RESP 0x5
#define SBI_EXT_MPXY_SEND_MSG_WITHOUT_RESP 0x6
#define SBI_EXT_MPXY_GET_NOTIFICATION_EVENTS 0x7
#define SBI_EXT_MPXY_SET_SHMEM 0x0
#define SBI_EXT_MPXY_GET_CHANNEL_IDS 0x1
#define SBI_EXT_MPXY_READ_ATTRS 0x2
#define SBI_EXT_MPXY_WRITE_ATTRS 0x3
#define SBI_EXT_MPXY_SEND_MSG_WITH_RESP 0x4
#define SBI_EXT_MPXY_SEND_MSG_NO_RESP 0x5
#define SBI_EXT_MPXY_GET_NOTIFICATION_EVENTS 0x6
/* SBI base specification related macros */
#define SBI_SPEC_VERSION_MAJOR_OFFSET 24
#define SBI_SPEC_VERSION_MAJOR_MASK 0x7f
#define SBI_SPEC_VERSION_MINOR_MASK 0xffffff
#define SBI_EXT_EXPERIMENTAL_START 0x08000000
#define SBI_EXT_EXPERIMENTAL_END 0x08FFFFFF
#define SBI_EXT_VENDOR_START 0x09000000
#define SBI_EXT_VENDOR_END 0x09FFFFFF
#define SBI_EXT_FIRMWARE_START 0x0A000000
@@ -486,9 +455,8 @@ enum sbi_sse_state {
#define SBI_ERR_BAD_RANGE -11
#define SBI_ERR_TIMEOUT -12
#define SBI_ERR_IO -13
#define SBI_ERR_DENIED_LOCKED -14
#define SBI_LAST_ERR SBI_ERR_DENIED_LOCKED
#define SBI_LAST_ERR SBI_ERR_BAD_RANGE
/* clang-format on */

View File

@@ -29,7 +29,6 @@
#define SBI_ETIMEOUT SBI_ERR_TIMEOUT
#define SBI_ETIMEDOUT SBI_ERR_TIMEOUT
#define SBI_EIO SBI_ERR_IO
#define SBI_EDENIED_LOCKED SBI_ERR_DENIED_LOCKED
#define SBI_ENODEV -1000
#define SBI_ENOSYS -1001

View File

@@ -31,7 +31,7 @@ enum sbi_hart_extensions {
SBI_HART_EXT_SMAIA = 0,
/** HART has Smepmp */
SBI_HART_EXT_SMEPMP,
/** HART has Smstateen extension **/
/** HART has Smstateen CSR **/
SBI_HART_EXT_SMSTATEEN,
/** Hart has Sscofpmt extension */
SBI_HART_EXT_SSCOFPMF,
@@ -75,12 +75,6 @@ enum sbi_hart_extensions {
SBI_HART_EXT_ZICFISS,
/** Hart has Ssdbltrp extension */
SBI_HART_EXT_SSDBLTRP,
/** HART has CTR M-mode CSRs */
SBI_HART_EXT_SMCTR,
/** HART has CTR S-mode CSRs */
SBI_HART_EXT_SSCTR,
/** HART has Ssstateen extension **/
SBI_HART_EXT_SSSTATEEN,
/** Maximum index of Hart extension */
SBI_HART_EXT_MAX,
@@ -93,14 +87,6 @@ struct sbi_hart_ext_data {
extern const struct sbi_hart_ext_data sbi_hart_ext[];
/** CSRs should be detected by access and trapping */
enum sbi_hart_csrs {
SBI_HART_CSR_CYCLE = 0,
SBI_HART_CSR_TIME,
SBI_HART_CSR_INSTRET,
SBI_HART_CSR_MAX,
};
/*
* Smepmp enforces access boundaries between M-mode and
* S/U-mode. When it is enabled, the PMPs are programmed
@@ -120,7 +106,6 @@ struct sbi_hart_features {
bool detected;
int priv_version;
unsigned long extensions[BITS_TO_LONGS(SBI_HART_EXT_MAX)];
unsigned long csrs[BITS_TO_LONGS(SBI_HART_CSR_MAX)];
unsigned int pmp_count;
unsigned int pmp_addr_bits;
unsigned int pmp_log2gran;
@@ -159,7 +144,6 @@ bool sbi_hart_has_extension(struct sbi_scratch *scratch,
enum sbi_hart_extensions ext);
void sbi_hart_get_extensions_str(struct sbi_scratch *scratch,
char *extension_str, int nestr);
bool sbi_hart_has_csr(struct sbi_scratch *scratch, enum sbi_hart_csrs csr);
void __attribute__((noreturn)) sbi_hart_hang(void);

View File

@@ -181,17 +181,6 @@ static inline void sbi_hartmask_xor(struct sbi_hartmask *dstp,
sbi_hartmask_bits(src2p), SBI_HARTMASK_MAX_BITS);
}
/**
* Count of bits in *srcp
* @param srcp the hartmask to count bits in
*
* Return: count of bits set in *srcp
*/
static inline int sbi_hartmask_weight(const struct sbi_hartmask *srcp)
{
return bitmap_weight(sbi_hartmask_bits(srcp), SBI_HARTMASK_MAX_BITS);
}
/**
* Iterate over each HART index in hartmask
* __i hart index

View File

@@ -1,17 +0,0 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2025 MIPS
*
*/
#ifndef __SBI_ILLEGAL_ATOMIC_H__
#define __SBI_ILLEGAL_ATOMIC_H__
#include <sbi/sbi_types.h>
struct sbi_trap_regs;
int sbi_illegal_atomic(ulong insn, struct sbi_trap_regs *regs);
#endif

View File

@@ -14,10 +14,6 @@
struct sbi_trap_context;
typedef int (*illegal_insn_func)(ulong insn, struct sbi_trap_regs *regs);
int truly_illegal_insn(ulong insn, struct sbi_trap_regs *regs);
int sbi_illegal_insn_handler(struct sbi_trap_context *tcntx);
#endif

View File

@@ -16,8 +16,6 @@ struct sbi_scratch;
void __noreturn sbi_init(struct sbi_scratch *scratch);
void sbi_revert_entry_count(struct sbi_scratch *scratch);
unsigned long sbi_entry_count(u32 hartindex);
unsigned long sbi_init_count(u32 hartindex);

View File

@@ -153,13 +153,11 @@ int sbi_mpxy_init(struct sbi_scratch *scratch);
/** Check if some Message proxy channel is available */
bool sbi_mpxy_channel_available(void);
/** Get message proxy shared memory size */
unsigned long sbi_mpxy_get_shmem_size(void);
/** Set message proxy shared memory on the calling HART */
int sbi_mpxy_set_shmem(unsigned long shmem_phys_lo,
unsigned long shmem_phys_hi,
unsigned long flags);
/** Set Message proxy shared memory on the calling HART */
int sbi_mpxy_set_shmem(unsigned long shmem_size,
unsigned long shmem_phys_lo,
unsigned long shmem_phys_hi,
unsigned long flags);
/** Get channel IDs list */
int sbi_mpxy_get_channel_ids(u32 start_index);

View File

@@ -39,8 +39,6 @@
#define SBI_PLATFORM_FIRMWARE_CONTEXT_OFFSET (0x60 + __SIZEOF_POINTER__)
/** Offset of hart_index2id in struct sbi_platform */
#define SBI_PLATFORM_HART_INDEX2ID_OFFSET (0x60 + (__SIZEOF_POINTER__ * 2))
/** Offset of cbom_block_size in struct sbi_platform */
#define SBI_PLATFORM_CBOM_BLOCK_SIZE_OFFSET (0x60 + (__SIZEOF_POINTER__ * 3))
#define SBI_PLATFORM_TLB_RANGE_FLUSH_LIMIT_DEFAULT (1UL << 12)
@@ -131,6 +129,8 @@ struct sbi_platform_operations {
/** Initialize the platform Message Proxy(MPXY) driver */
int (*mpxy_init)(void);
/** Check if SBI vendor extension is implemented or not */
bool (*vendor_ext_check)(void);
/** platform specific SBI extension implementation provider */
int (*vendor_ext_provider)(long funcid,
struct sbi_trap_regs *regs,
@@ -142,13 +142,6 @@ struct sbi_platform_operations {
/** platform specific handler to fixup store fault */
int (*emulate_store)(int wlen, unsigned long addr,
union sbi_ldst_data in_val);
/** platform specific pmp setup on current HART */
void (*pmp_set)(unsigned int n, unsigned long flags,
unsigned long prot, unsigned long addr,
unsigned long log2len);
/** platform specific pmp disable on current HART */
void (*pmp_disable)(unsigned int n);
};
/** Platform default per-HART stack size for exception/interrupt handling */
@@ -176,7 +169,7 @@ struct sbi_platform {
char name[64];
/** Supported features */
u64 features;
/** Total number of HARTs (at most SBI_HARTMASK_MAX_BITS) */
/** Total number of HARTs */
u32 hart_count;
/** Per-HART stack size for exception/interrupt handling */
u32 hart_stack_size;
@@ -191,34 +184,70 @@ struct sbi_platform {
/**
* HART index to HART id table
*
* If hart_index2id != NULL then the table must contain a mapping
* for each HART index 0 <= <abc> < hart_count:
* 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;
/** Allocation alignment for Scratch */
unsigned long cbom_block_size;
};
/**
* Prevent modification of struct sbi_platform from affecting
* SBI_PLATFORM_xxx_OFFSET
*/
assert_member_offset(struct sbi_platform, opensbi_version, SBI_PLATFORM_OPENSBI_VERSION_OFFSET);
assert_member_offset(struct sbi_platform, platform_version, SBI_PLATFORM_VERSION_OFFSET);
assert_member_offset(struct sbi_platform, name, SBI_PLATFORM_NAME_OFFSET);
assert_member_offset(struct sbi_platform, features, SBI_PLATFORM_FEATURES_OFFSET);
assert_member_offset(struct sbi_platform, hart_count, SBI_PLATFORM_HART_COUNT_OFFSET);
assert_member_offset(struct sbi_platform, hart_stack_size, SBI_PLATFORM_HART_STACK_SIZE_OFFSET);
assert_member_offset(struct sbi_platform, heap_size, SBI_PLATFORM_HEAP_SIZE_OFFSET);
assert_member_offset(struct sbi_platform, reserved, SBI_PLATFORM_RESERVED_OFFSET);
assert_member_offset(struct sbi_platform, platform_ops_addr, SBI_PLATFORM_OPS_OFFSET);
assert_member_offset(struct sbi_platform, firmware_context, SBI_PLATFORM_FIRMWARE_CONTEXT_OFFSET);
assert_member_offset(struct sbi_platform, hart_index2id, SBI_PLATFORM_HART_INDEX2ID_OFFSET);
assert_member_offset(struct sbi_platform, cbom_block_size, SBI_PLATFORM_CBOM_BLOCK_SIZE_OFFSET);
_Static_assert(
offsetof(struct sbi_platform, opensbi_version)
== SBI_PLATFORM_OPENSBI_VERSION_OFFSET,
"struct sbi_platform definition has changed, please redefine "
"SBI_PLATFORM_OPENSBI_VERSION_OFFSET");
_Static_assert(
offsetof(struct sbi_platform, platform_version)
== SBI_PLATFORM_VERSION_OFFSET,
"struct sbi_platform definition has changed, please redefine "
"SBI_PLATFORM_VERSION_OFFSET");
_Static_assert(
offsetof(struct sbi_platform, name)
== SBI_PLATFORM_NAME_OFFSET,
"struct sbi_platform definition has changed, please redefine "
"SBI_PLATFORM_NAME_OFFSET");
_Static_assert(
offsetof(struct sbi_platform, features)
== SBI_PLATFORM_FEATURES_OFFSET,
"struct sbi_platform definition has changed, please redefine "
"SBI_PLATFORM_FEATURES_OFFSET");
_Static_assert(
offsetof(struct sbi_platform, hart_count)
== SBI_PLATFORM_HART_COUNT_OFFSET,
"struct sbi_platform definition has changed, please redefine "
"SBI_PLATFORM_HART_COUNT_OFFSET");
_Static_assert(
offsetof(struct sbi_platform, hart_stack_size)
== SBI_PLATFORM_HART_STACK_SIZE_OFFSET,
"struct sbi_platform definition has changed, please redefine "
"SBI_PLATFORM_HART_STACK_SIZE_OFFSET");
_Static_assert(
offsetof(struct sbi_platform, platform_ops_addr)
== SBI_PLATFORM_OPS_OFFSET,
"struct sbi_platform definition has changed, please redefine "
"SBI_PLATFORM_OPS_OFFSET");
_Static_assert(
offsetof(struct sbi_platform, firmware_context)
== SBI_PLATFORM_FIRMWARE_CONTEXT_OFFSET,
"struct sbi_platform definition has changed, please redefine "
"SBI_PLATFORM_FIRMWARE_CONTEXT_OFFSET");
_Static_assert(
offsetof(struct sbi_platform, hart_index2id)
== SBI_PLATFORM_HART_INDEX2ID_OFFSET,
"struct sbi_platform definition has changed, please redefine "
"SBI_PLATFORM_HART_INDEX2ID_OFFSET");
/** Get pointer to sbi_platform for sbi_scratch pointer */
#define sbi_platform_ptr(__s) \
@@ -302,7 +331,7 @@ static inline u32 sbi_platform_tlb_fifo_num_entries(const struct sbi_platform *p
{
if (plat && sbi_platform_ops(plat)->get_tlb_num_entries)
return sbi_platform_ops(plat)->get_tlb_num_entries();
return sbi_hart_count();
return sbi_scratch_last_hartindex() + 1;
}
/**
@@ -580,7 +609,10 @@ static inline int sbi_platform_mpxy_init(const struct sbi_platform *plat)
static inline bool sbi_platform_vendor_ext_check(
const struct sbi_platform *plat)
{
return plat && sbi_platform_ops(plat)->vendor_ext_provider;
if (plat && sbi_platform_ops(plat)->vendor_ext_check)
return sbi_platform_ops(plat)->vendor_ext_check();
return false;
}
/**
@@ -651,38 +683,6 @@ static inline int sbi_platform_emulate_store(const struct sbi_platform *plat,
return SBI_ENOTSUPP;
}
/**
* Platform specific PMP setup on current HART
*
* @param plat pointer to struct sbi_platform
* @param n index of the pmp entry
* @param flags domain memregion flags
* @param prot attribute of the pmp entry
* @param addr address of the pmp entry
* @param log2len size of the pmp entry as power-of-2
*/
static inline void sbi_platform_pmp_set(const struct sbi_platform *plat,
unsigned int n, unsigned long flags,
unsigned long prot, unsigned long addr,
unsigned long log2len)
{
if (plat && sbi_platform_ops(plat)->pmp_set)
sbi_platform_ops(plat)->pmp_set(n, flags, prot, addr, log2len);
}
/**
* Platform specific PMP disable on current HART
*
* @param plat pointer to struct sbi_platform
* @param n index of the pmp entry
*/
static inline void sbi_platform_pmp_disable(const struct sbi_platform *plat,
unsigned int n)
{
if (plat && sbi_platform_ops(plat)->pmp_disable)
sbi_platform_ops(plat)->pmp_disable(n);
}
#endif
#endif

View File

@@ -114,9 +114,6 @@ void sbi_pmu_exit(struct sbi_scratch *scratch);
/** Return the pmu irq bit depending on extension existence */
int sbi_pmu_irq_bit(void);
/** Return the pmu irq mask or 0 if the pmu overflow irq is not supported */
unsigned long sbi_pmu_irq_mask(void);
/**
* Add the hardware event to counter mapping information. This should be called
* from the platform code to update the mapping table.

View File

@@ -93,21 +93,61 @@ struct sbi_scratch {
* Prevent modification of struct sbi_scratch from affecting
* SBI_SCRATCH_xxx_OFFSET
*/
assert_member_offset(struct sbi_scratch, fw_start, SBI_SCRATCH_FW_START_OFFSET);
assert_member_offset(struct sbi_scratch, fw_size, SBI_SCRATCH_FW_SIZE_OFFSET);
assert_member_offset(struct sbi_scratch, fw_rw_offset, SBI_SCRATCH_FW_RW_OFFSET);
assert_member_offset(struct sbi_scratch, fw_heap_offset, SBI_SCRATCH_FW_HEAP_OFFSET);
assert_member_offset(struct sbi_scratch, fw_heap_size, SBI_SCRATCH_FW_HEAP_SIZE_OFFSET);
assert_member_offset(struct sbi_scratch, next_arg1, SBI_SCRATCH_NEXT_ARG1_OFFSET);
assert_member_offset(struct sbi_scratch, next_addr, SBI_SCRATCH_NEXT_ADDR_OFFSET);
assert_member_offset(struct sbi_scratch, next_mode, SBI_SCRATCH_NEXT_MODE_OFFSET);
assert_member_offset(struct sbi_scratch, warmboot_addr, SBI_SCRATCH_WARMBOOT_ADDR_OFFSET);
assert_member_offset(struct sbi_scratch, platform_addr, SBI_SCRATCH_PLATFORM_ADDR_OFFSET);
assert_member_offset(struct sbi_scratch, hartid_to_scratch, SBI_SCRATCH_HARTID_TO_SCRATCH_OFFSET);
assert_member_offset(struct sbi_scratch, trap_context, SBI_SCRATCH_TRAP_CONTEXT_OFFSET);
assert_member_offset(struct sbi_scratch, tmp0, SBI_SCRATCH_TMP0_OFFSET);
assert_member_offset(struct sbi_scratch, options, SBI_SCRATCH_OPTIONS_OFFSET);
assert_member_offset(struct sbi_scratch, hartindex, SBI_SCRATCH_HARTINDEX_OFFSET);
_Static_assert(
offsetof(struct sbi_scratch, fw_start)
== SBI_SCRATCH_FW_START_OFFSET,
"struct sbi_scratch definition has changed, please redefine "
"SBI_SCRATCH_FW_START_OFFSET");
_Static_assert(
offsetof(struct sbi_scratch, fw_size)
== SBI_SCRATCH_FW_SIZE_OFFSET,
"struct sbi_scratch definition has changed, please redefine "
"SBI_SCRATCH_FW_SIZE_OFFSET");
_Static_assert(
offsetof(struct sbi_scratch, next_arg1)
== SBI_SCRATCH_NEXT_ARG1_OFFSET,
"struct sbi_scratch definition has changed, please redefine "
"SBI_SCRATCH_NEXT_ARG1_OFFSET");
_Static_assert(
offsetof(struct sbi_scratch, next_addr)
== SBI_SCRATCH_NEXT_ADDR_OFFSET,
"struct sbi_scratch definition has changed, please redefine "
"SBI_SCRATCH_NEXT_ADDR_OFFSET");
_Static_assert(
offsetof(struct sbi_scratch, next_mode)
== SBI_SCRATCH_NEXT_MODE_OFFSET,
"struct sbi_scratch definition has changed, please redefine "
"SBI_SCRATCH_NEXT_MODE_OFFSET");
_Static_assert(
offsetof(struct sbi_scratch, warmboot_addr)
== SBI_SCRATCH_WARMBOOT_ADDR_OFFSET,
"struct sbi_scratch definition has changed, please redefine "
"SBI_SCRATCH_WARMBOOT_ADDR_OFFSET");
_Static_assert(
offsetof(struct sbi_scratch, platform_addr)
== SBI_SCRATCH_PLATFORM_ADDR_OFFSET,
"struct sbi_scratch definition has changed, please redefine "
"SBI_SCRATCH_PLATFORM_ADDR_OFFSET");
_Static_assert(
offsetof(struct sbi_scratch, hartid_to_scratch)
== SBI_SCRATCH_HARTID_TO_SCRATCH_OFFSET,
"struct sbi_scratch definition has changed, please redefine "
"SBI_SCRATCH_HARTID_TO_SCRATCH_OFFSET");
_Static_assert(
offsetof(struct sbi_scratch, trap_context)
== SBI_SCRATCH_TRAP_CONTEXT_OFFSET,
"struct sbi_scratch definition has changed, please redefine "
"SBI_SCRATCH_TRAP_CONTEXT_OFFSET");
_Static_assert(
offsetof(struct sbi_scratch, tmp0)
== SBI_SCRATCH_TMP0_OFFSET,
"struct sbi_scratch definition has changed, please redefine "
"SBI_SCRATCH_TMP0_OFFSET");
_Static_assert(
offsetof(struct sbi_scratch, options)
== SBI_SCRATCH_OPTIONS_OFFSET,
"struct sbi_scratch definition has changed, please redefine "
"SBI_SCRATCH_OPTIONS_OFFSET");
/** Possible options for OpenSBI library */
enum sbi_scratch_options {
@@ -170,18 +210,15 @@ do { \
#define current_hartindex() \
(sbi_scratch_thishart_ptr()->hartindex)
/** Number of harts managed by this OpenSBI instance */
extern u32 sbi_scratch_hart_count;
/** Last HART index having a sbi_scratch pointer */
extern u32 last_hartindex_having_scratch;
/** Get the number of harts managed by this OpenSBI instance */
#define sbi_hart_count() sbi_scratch_hart_count
/** Iterate over the harts managed by this OpenSBI instance */
#define sbi_for_each_hartindex(__var) \
for (u32 __var = 0; __var < sbi_hart_count(); ++__var)
/** Get last HART index having a sbi_scratch pointer */
#define sbi_scratch_last_hartindex() last_hartindex_having_scratch
/** Check whether a particular HART index is valid or not */
#define sbi_hartindex_valid(__hartindex) ((__hartindex) < sbi_hart_count())
#define sbi_hartindex_valid(__hartindex) \
(((__hartindex) <= sbi_scratch_last_hartindex()) ? true : false)
/** HART index to HART id table */
extern u32 hartindex_to_hartid_table[];
@@ -189,7 +226,7 @@ extern u32 hartindex_to_hartid_table[];
/** Get sbi_scratch from HART index */
#define sbi_hartindex_to_hartid(__hartindex) \
({ \
((__hartindex) < SBI_HARTMASK_MAX_BITS) ? \
((__hartindex) <= sbi_scratch_last_hartindex()) ?\
hartindex_to_hartid_table[__hartindex] : -1U; \
})
@@ -199,8 +236,8 @@ extern struct sbi_scratch *hartindex_to_scratch_table[];
/** Get sbi_scratch from HART index */
#define sbi_hartindex_to_scratch(__hartindex) \
({ \
((__hartindex) < SBI_HARTMASK_MAX_BITS) ? \
hartindex_to_scratch_table[__hartindex] : NULL; \
((__hartindex) <= sbi_scratch_last_hartindex()) ?\
hartindex_to_scratch_table[__hartindex] : NULL;\
})
/**

View File

@@ -1,33 +0,0 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Simple simply-linked list library.
*
* Copyright (c) 2025 Rivos Inc.
*
* Authors:
* Clément Léger <cleger@rivosinc.com>
*/
#ifndef __SBI_SLIST_H__
#define __SBI_SLIST_H__
#include <sbi/sbi_types.h>
#define SBI_SLIST_HEAD_INIT(_ptr) (_ptr)
#define SBI_SLIST_HEAD(_lname, _stype) struct _stype *_lname
#define SBI_SLIST_NODE(_stype) SBI_SLIST_HEAD(next, _stype)
#define SBI_SLIST_NODE_INIT(_ptr) .next = _ptr
#define SBI_INIT_SLIST_HEAD(_head) (_head) = NULL
#define SBI_SLIST_ADD(_ptr, _head) \
do { \
(_ptr)->next = _head; \
(_head) = _ptr; \
} while (0)
#define SBI_SLIST_FOR_EACH_ENTRY(_ptr, _head) \
for (_ptr = _head; _ptr; _ptr = _ptr->next)
#endif

View File

@@ -54,12 +54,12 @@ struct sbi_sse_cb_ops {
void (*disable_cb)(uint32_t event_id);
};
/* Add a supported event with associated callback operations
* @param event_id Event identifier (SBI_SSE_EVENT_* or a custom platform one)
* @param cb_ops Callback operations (Can be NULL if any)
/* Set the callback operations for an event
* @param event_id Event identifier (SBI_SSE_EVENT_*)
* @param cb_ops Callback operations
* @return 0 on success, error otherwise
*/
int sbi_sse_add_event(uint32_t event_id, const struct sbi_sse_cb_ops *cb_ops);
int sbi_sse_set_cb_ops(uint32_t event_id, const struct sbi_sse_cb_ops *cb_ops);
/* Inject an event to the current hard
* @param event_id Event identifier (SBI_SSE_EVENT_*)

View File

@@ -112,13 +112,10 @@
/** Size (in bytes) of sbi_trap_info */
#define SBI_TRAP_INFO_SIZE SBI_TRAP_INFO_OFFSET(last)
#define STACK_BOUNDARY 16
#define ALIGN_TO_BOUNDARY(x, a) (((x) + (a) - 1) & ~((a) - 1))
/** Size (in bytes) of sbi_trap_context */
#define SBI_TRAP_CONTEXT_SIZE ALIGN_TO_BOUNDARY((SBI_TRAP_REGS_SIZE + \
#define SBI_TRAP_CONTEXT_SIZE (SBI_TRAP_REGS_SIZE + \
SBI_TRAP_INFO_SIZE + \
__SIZEOF_POINTER__), STACK_BOUNDARY)
__SIZEOF_POINTER__)
#ifndef __ASSEMBLER__

View File

@@ -28,6 +28,8 @@ int sbi_load_access_handler(struct sbi_trap_context *tcntx);
int sbi_store_access_handler(struct sbi_trap_context *tcntx);
int sbi_double_trap_handler(struct sbi_trap_context *tcntx);
ulong sbi_misaligned_tinst_fixup(ulong orig_tinst, ulong new_tinst,
ulong addr_offset);

View File

@@ -96,13 +96,6 @@ typedef uint64_t be64_t;
const typeof(((type *)0)->member) * __mptr = (ptr); \
(type *)((char *)__mptr - offsetof(type, member)); })
#define assert_member_offset(type, member, offset) \
_Static_assert( \
(offsetof(type, member)) == (offset ), \
"The offset " #offset " of " #member " in " #type \
"is not correct, please redefine it.")
#define array_size(x) (sizeof(x) / sizeof((x)[0]))
#define MAX(a, b) ((a) > (b) ? (a) : (b))

View File

@@ -11,7 +11,7 @@
#define __SBI_VERSION_H__
#define OPENSBI_VERSION_MAJOR 1
#define OPENSBI_VERSION_MINOR 7
#define OPENSBI_VERSION_MINOR 6
/**
* OpenSBI 32-bit version with:

View File

@@ -1,16 +0,0 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2025 SiFive
*/
#ifndef __SBI_VISIBILITY_H__
#define __SBI_VISIBILITY_H__
/*
* Declare all global objects with hidden visibility so access is PC-relative
* instead of going through the GOT.
*/
#pragma GCC visibility push(hidden)
#endif

View File

@@ -0,0 +1,26 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2025 Sophgo Inc.
*
* Authors:
* Haijiao Liu <haijiao.liu@sophgo.com>
*/
#ifndef __FDT_CLK_H__
#define __FDT_CLK_H__
#include <sbi/sbi_types.h>
#include <sbi_utils/fdt/fdt_driver.h>
#ifdef CONFIG_FDT_CLK
void fdt_clk_init(const void *fdt);
#else
static inline void fdt_clk_init(const void *fdt) { }
#endif
#endif

View File

@@ -0,0 +1,104 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2025 Sophgo Inc.
*
* Authors:
* Haijiao Liu <haijiao.liu@sophgo.com>
*/
#ifndef _SG2044_CLK_H_
#define _SG2044_CLK_H_
#include <sbi/sbi_string.h>
#include <sbi/sbi_bitops.h>
#define KHZ 1000UL
#define MHZ (KHZ * KHZ)
#define SG2044_CLK_USE_INIT_VAL BIT(0) /* use default value */
#define SG2044_CLK_USE_REG_VAL BIT(1) /* use reg divider value */
#define SG2044_CLK_RO BIT(2) /* use reg divider value */
#define CLK_PLL BIT(0)
#define CLK_MUX BIT(1)
#define PLL_CTRL_OFFSET 0xC4
#define PLL_STAT_LOCK_OFFSET 0x10
#define PLL_SELECT_OFFSET 0x2020
#define CLK_MODE 0x4
#define CLK_MODE_MASK 0x3
#define FBDIV_SHIFT 0
#define FBDIV_WIDTH 12
#define REFDIV_SHIFT 12
#define REFDIV_WIDTH 6
#define POSTDIV1_SHIFT 18
#define POSTDIV1_WIDTH 3
#define POSTDIV2_SHIFT 21
#define POSTDIV2_WIDTH 3
#define REFDIV_MIN 1
#define REFDIV_MAX 63
#define FBDIV_MIN 8
#define FBDIV_MAX 1066
#define PLL_FREQ_MIN (1600 * MHZ)
#define PLL_FREQ_MAX (3200 * MHZ)
#define div_mask(width) ((1 << (width)) - 1)
#define TOP_PLL_CTRL(fbdiv, p1, p2, refdiv) \
(BIT(30) | (0x2 << 27) | BIT(24) | (((p2 - 1) & 0x7) << 21) | \
(((p1 - 1) & 0x7) << 18) | ((refdiv & 0x3f) << 12) | (fbdiv & 0xfff))
#define MPLL0_CLK 0
#define MPLL1_CLK 1
#define MPLL2_CLK 2
#define MPLL3_CLK 3
#define MPLL4_CLK 4
#define MPLL5_CLK 5
#define FPLL0_CLK 6
#define FPLL1_CLK 7
#define DPLL0_CLK 8
#define DPLL1_CLK 9
#define DPLL2_CLK 10
#define DPLL3_CLK 11
#define DPLL4_CLK 12
#define DPLL5_CLK 13
#define DPLL6_CLK 14
#define DPLL7_CLK 15
static inline char is_power_of_2(unsigned long n)
{
return (n != 0 && ((n & (n - 1)) == 0));
}
#define do_div(n, base) ({ \
uint32_t __base = (base); \
uint32_t __rem; \
__rem = (uint32_t)(n) % __base; \
(n) = (uint32_t)(n) / __base; \
__rem; \
})
struct sg2044_pll_ctrl {
unsigned int mode;
unsigned long freq;
unsigned int fbdiv;
unsigned int postdiv1;
unsigned int postdiv2;
unsigned int refdiv;
};
struct sg2044_pll_clock {
unsigned int id;
char *name;
unsigned int status_offset;
unsigned int enable_offset;
uint64_t default_rate;
struct sg2044_pll_ctrl pctrl_table[4];
};
#endif

View File

@@ -0,0 +1,26 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2024 Ventana Micro Systems Inc.
*
* Authors:
* Anup Patel <apatel@ventanamicro.com>
*/
#ifndef __FDT_CPPC_H__
#define __FDT_CPPC_H__
#include <sbi/sbi_types.h>
#include <sbi_utils/fdt/fdt_driver.h>
#ifdef CONFIG_FDT_CPPC
void fdt_cppc_init(const void *fdt);
#else
static inline void fdt_cppc_init(const void *fdt) { }
#endif
#endif

View File

@@ -18,9 +18,6 @@ struct fdt_driver {
bool experimental;
};
/* List of early FDT drivers generated at compile time */
extern const struct fdt_driver *const fdt_early_drivers[];
/**
* Initialize a driver instance for a specific DT node
*

View File

@@ -34,6 +34,13 @@ struct platform_uart_data {
unsigned long reg_offset;
};
const struct fdt_match *fdt_match_node(const void *fdt, int nodeoff,
const struct fdt_match *match_table);
int fdt_find_match(const void *fdt, int startoff,
const struct fdt_match *match_table,
const struct fdt_match **out_match);
int fdt_parse_phandle_with_args(const void *fdt, int nodeoff,
const char *prop, const char *cells_prop,
int index, struct fdt_phandle_args *out_args);
@@ -50,11 +57,9 @@ int fdt_parse_hart_id(const void *fdt, int cpu_offset, u32 *hartid);
int fdt_parse_max_enabled_hart_id(const void *fdt, u32 *max_hartid);
int fdt_parse_cbom_block_size(const void *fdt, int cpu_offset, unsigned long *cbom_block_size);
int fdt_parse_timebase_frequency(const void *fdt, unsigned long *freq);
int fdt_parse_isa_extensions(const void *fdt, unsigned int hartid,
int fdt_parse_isa_extensions(const void *fdt, unsigned int hard_id,
unsigned long *extensions);
int fdt_parse_gaisler_uart_node(const void *fdt, int nodeoffset,

View File

@@ -62,6 +62,11 @@ int fdt_pmu_setup(const void *fdt);
*/
uint64_t fdt_pmu_get_select_value(uint32_t event_idx);
/** The event index to selector value table instance */
extern struct fdt_pmu_hw_event_select_map fdt_pmu_evt_select[];
/** The number of valid entries in fdt_pmu_evt_select[] */
extern uint32_t hw_event_count;
#else
static inline void fdt_pmu_fixup(void *fdt) { }

View File

@@ -0,0 +1,26 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2024 Ventana Micro Systems Inc.
*
* Authors:
* Anup Patel <apatel@ventanamicro.com>
*/
#ifndef __FDT_HSM_H__
#define __FDT_HSM_H__
#include <sbi/sbi_types.h>
#include <sbi_utils/fdt/fdt_driver.h>
#ifdef CONFIG_FDT_HSM
void fdt_hsm_init(const void *fdt);
#else
static inline void fdt_hsm_init(const void *fdt) { }
#endif
#endif

View File

@@ -11,10 +11,14 @@
#define __FDT_IRQCHIP_H__
#include <sbi/sbi_types.h>
#include <sbi_utils/fdt/fdt_driver.h>
#ifdef CONFIG_FDT_IRQCHIP
struct fdt_irqchip {
const struct fdt_match *match_table;
int (*cold_init)(const void *fdt, int nodeoff, const struct fdt_match *match);
};
int fdt_irqchip_init(void);
#else

View File

@@ -11,7 +11,6 @@
#define __RPMI_MAILBOX_H__
#include <sbi/sbi_error.h>
#include <sbi_utils/mailbox/mailbox.h>
#include <sbi_utils/mailbox/rpmi_msgprot.h>
#define rpmi_u32_count(__var) (sizeof(__var) / sizeof(u32))

View File

@@ -175,7 +175,7 @@ enum rpmi_error {
RPMI_ERR_VENDOR_START = -128,
};
/** RPMI Mailbox Message Arguments */
/** RPMI Message Arguments */
struct rpmi_message_args {
u32 flags;
#define RPMI_MSG_FLAGS_NO_TX (1U << 0)
@@ -189,20 +189,6 @@ struct rpmi_message_args {
u32 rx_data_len;
};
/** RPMI Mailbox Channel Attribute IDs */
enum rpmi_channel_attribute_id {
RPMI_CHANNEL_ATTR_PROTOCOL_VERSION = 0,
RPMI_CHANNEL_ATTR_MAX_DATA_LEN,
RPMI_CHANNEL_ATTR_P2A_DOORBELL_SYSMSI_INDEX,
RPMI_CHANNEL_ATTR_TX_TIMEOUT,
RPMI_CHANNEL_ATTR_RX_TIMEOUT,
RPMI_CHANNEL_ATTR_SERVICEGROUP_ID,
RPMI_CHANNEL_ATTR_SERVICEGROUP_VERSION,
RPMI_CHANNEL_ATTR_IMPL_ID,
RPMI_CHANNEL_ATTR_IMPL_VERSION,
RPMI_CHANNEL_ATTR_MAX,
};
/*
* RPMI SERVICEGROUPS AND SERVICES
*/
@@ -211,12 +197,11 @@ enum rpmi_channel_attribute_id {
enum rpmi_servicegroup_id {
RPMI_SRVGRP_ID_MIN = 0,
RPMI_SRVGRP_BASE = 0x0001,
RPMI_SRVGRP_SYSTEM_MSI = 0x0002,
RPMI_SRVGRP_SYSTEM_RESET = 0x0003,
RPMI_SRVGRP_SYSTEM_SUSPEND = 0x0004,
RPMI_SRVGRP_HSM = 0x0005,
RPMI_SRVGRP_CPPC = 0x0006,
RPMI_SRVGRP_CLOCK = 0x0008,
RPMI_SRVGRP_SYSTEM_RESET = 0x0002,
RPMI_SRVGRP_SYSTEM_SUSPEND = 0x0003,
RPMI_SRVGRP_HSM = 0x0004,
RPMI_SRVGRP_CPPC = 0x0005,
RPMI_SRVGRP_CLOCK = 0x0007,
RPMI_SRVGRP_ID_MAX_COUNT,
/* Reserved range for service groups */
@@ -247,10 +232,12 @@ enum rpmi_base_service_id {
RPMI_BASE_SRV_GET_PLATFORM_INFO = 0x05,
RPMI_BASE_SRV_PROBE_SERVICE_GROUP = 0x06,
RPMI_BASE_SRV_GET_ATTRIBUTES = 0x07,
RPMI_BASE_SRV_SET_MSI = 0x08,
};
#define RPMI_BASE_FLAGS_F0_PRIVILEGE (1U << 1)
#define RPMI_BASE_FLAGS_F0_EV_NOTIFY (1U << 0)
#define RPMI_BASE_FLAGS_F0_PRIVILEGE (1U << 2)
#define RPMI_BASE_FLAGS_F0_EV_NOTIFY (1U << 1)
#define RPMI_BASE_FLAGS_F0_MSI_EN (1U)
enum rpmi_base_context_priv_level {
RPMI_BASE_CONTEXT_PRIV_S_MODE,
@@ -271,92 +258,6 @@ struct rpmi_base_get_platform_info_resp {
char plat_info[];
};
/** RPMI System MSI ServiceGroup Service IDs */
enum rpmi_sysmsi_service_id {
RPMI_SYSMSI_SRV_ENABLE_NOTIFICATION = 0x01,
RPMI_SYSMSI_SRV_GET_ATTRIBUTES = 0x2,
RPMI_SYSMSI_SRV_GET_MSI_ATTRIBUTES = 0x3,
RPMI_SYSMSI_SRV_SET_MSI_STATE = 0x4,
RPMI_SYSMSI_SRV_GET_MSI_STATE = 0x5,
RPMI_SYSMSI_SRV_SET_MSI_TARGET = 0x6,
RPMI_SYSMSI_SRV_GET_MSI_TARGET = 0x7,
RPMI_SYSMSI_SRV_ID_MAX_COUNT,
};
/** Response for system MSI service group attributes */
struct rpmi_sysmsi_get_attributes_resp {
s32 status;
u32 sys_num_msi;
u32 flag0;
u32 flag1;
};
/** Request for system MSI attributes */
struct rpmi_sysmsi_get_msi_attributes_req {
u32 sys_msi_index;
};
/** Response for system MSI attributes */
struct rpmi_sysmsi_get_msi_attributes_resp {
s32 status;
u32 flag0;
u32 flag1;
u8 name[16];
};
#define RPMI_SYSMSI_MSI_ATTRIBUTES_FLAG0_PREF_PRIV (1U << 0)
/** Request for system MSI set state */
struct rpmi_sysmsi_set_msi_state_req {
u32 sys_msi_index;
u32 sys_msi_state;
};
#define RPMI_SYSMSI_MSI_STATE_ENABLE (1U << 0)
#define RPMI_SYSMSI_MSI_STATE_PENDING (1U << 1)
/** Response for system MSI set state */
struct rpmi_sysmsi_set_msi_state_resp {
s32 status;
};
/** Request for system MSI get state */
struct rpmi_sysmsi_get_msi_state_req {
u32 sys_msi_index;
};
/** Response for system MSI get state */
struct rpmi_sysmsi_get_msi_state_resp {
s32 status;
u32 sys_msi_state;
};
/** Request for system MSI set target */
struct rpmi_sysmsi_set_msi_target_req {
u32 sys_msi_index;
u32 sys_msi_address_low;
u32 sys_msi_address_high;
u32 sys_msi_data;
};
/** Response for system MSI set target */
struct rpmi_sysmsi_set_msi_target_resp {
s32 status;
};
/** Request for system MSI get target */
struct rpmi_sysmsi_get_msi_target_req {
u32 sys_msi_index;
};
/** Response for system MSI get target */
struct rpmi_sysmsi_get_msi_target_resp {
s32 status;
u32 sys_msi_address_low;
u32 sys_msi_address_high;
u32 sys_msi_data;
};
/** RPMI System Reset ServiceGroup Service IDs */
enum rpmi_system_reset_service_id {
RPMI_SYSRST_SRV_ENABLE_NOTIFICATION = 0x01,

View File

@@ -15,11 +15,11 @@
#ifdef CONFIG_FDT_MPXY
int fdt_mpxy_init(const void *fdt);
void fdt_mpxy_init(const void *fdt);
#else
static inline int fdt_mpxy_init(const void *fdt) { return 0; }
static inline void fdt_mpxy_init(const void *fdt) { }
#endif

View File

@@ -1,85 +0,0 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2024 Ventana Micro Systems Inc.
*
* Authors:
* Anup Patel <apatel@ventanamicro.com>
*/
#ifndef __FDT_MPXY_RPMI_MBOX_H__
#define __FDT_MPXY_RPMI_MBOX_H__
#include <sbi/sbi_types.h>
#include <sbi/sbi_mpxy.h>
#include <sbi_utils/mailbox/fdt_mailbox.h>
#include <sbi_utils/mailbox/rpmi_msgprot.h>
#include <sbi_utils/mpxy/fdt_mpxy.h>
/** Convert the mpxy attribute ID to attribute array index */
#define attr_id2index(attr_id) (attr_id - SBI_MPXY_ATTR_MSGPROTO_ATTR_START)
enum mpxy_msgprot_rpmi_attr_id {
MPXY_MSGPROT_RPMI_ATTR_SERVICEGROUP_ID = SBI_MPXY_ATTR_MSGPROTO_ATTR_START,
MPXY_MSGPROT_RPMI_ATTR_SERVICEGROUP_VERSION,
MPXY_MSGPROT_RPMI_ATTR_IMPL_ID,
MPXY_MSGPROT_RPMI_ATTR_IMPL_VERSION,
MPXY_MSGPROT_RPMI_ATTR_MAX_ID
};
/**
* MPXY message protocol attributes for RPMI
* Order of attribute fields must follow the
* attribute IDs in `enum mpxy_msgprot_rpmi_attr_id`
*/
struct mpxy_rpmi_channel_attrs {
u32 servicegrp_id;
u32 servicegrp_ver;
u32 impl_id;
u32 impl_ver;
};
/** Make sure all attributes are packed for direct memcpy */
#define assert_field_offset(field, attr_offset) \
_Static_assert( \
((offsetof(struct mpxy_rpmi_channel_attrs, field)) / \
sizeof(u32)) == (attr_offset - SBI_MPXY_ATTR_MSGPROTO_ATTR_START),\
"field " #field \
" from struct mpxy_rpmi_channel_attrs invalid offset, expected " #attr_offset)
assert_field_offset(servicegrp_id, MPXY_MSGPROT_RPMI_ATTR_SERVICEGROUP_ID);
assert_field_offset(servicegrp_ver, MPXY_MSGPROT_RPMI_ATTR_SERVICEGROUP_VERSION);
assert_field_offset(impl_id, MPXY_MSGPROT_RPMI_ATTR_IMPL_ID);
assert_field_offset(impl_ver, MPXY_MSGPROT_RPMI_ATTR_IMPL_VERSION);
/** MPXY RPMI service data for each service group */
struct mpxy_rpmi_service_data {
u8 id;
u32 min_tx_len;
u32 max_tx_len;
u32 min_rx_len;
u32 max_rx_len;
};
/** MPXY RPMI mbox data for each service group */
struct mpxy_rpmi_mbox_data {
u32 servicegrp_id;
u32 num_services;
struct mpxy_rpmi_service_data *service_data;
/** Transfer RPMI service group message */
int (*xfer_group)(void *context, struct mbox_chan *chan,
struct mbox_xfer *xfer);
/** Setup RPMI service group context for MPXY */
int (*setup_group)(void **context, struct mbox_chan *chan,
const struct mpxy_rpmi_mbox_data *data);
/** Cleanup RPMI service group context for MPXY */
void (*cleanup_group)(void *context);
};
/** Common probe function for MPXY RPMI drivers */
int mpxy_rpmi_mbox_init(const void *fdt, int nodeoff, const struct fdt_match *match);
#endif

View File

@@ -0,0 +1,31 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2020 Western Digital Corporation or its affiliates.
*
* Authors:
* Anup Patel <anup.patel@wdc.com>
*/
#ifndef __FDT_RESET_H__
#define __FDT_RESET_H__
#include <sbi/sbi_types.h>
#include <sbi_utils/fdt/fdt_driver.h>
#ifdef CONFIG_FDT_RESET
/**
* fdt_reset_init() - initialize reset drivers based on the device-tree
*
* This function shall be invoked in final init.
*/
void fdt_reset_init(const void *fdt);
#else
static inline void fdt_reset_init(const void *fdt) { }
#endif
#endif

View File

@@ -12,9 +12,7 @@
#include <sbi/sbi_types.h>
#define UART_CAP_UUE BIT(0) /* Check UUE capability for XScale PXA UARTs */
int uart8250_init(unsigned long base, u32 in_freq, u32 baudrate, u32 reg_shift,
u32 reg_width, u32 reg_offset, u32 caps);
u32 reg_width, u32 reg_offset);
#endif

View File

@@ -0,0 +1,26 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2024 Ventana Micro Systems Inc.
*
* Authors:
* Anup Patel <apatel@ventanamicro.com>
*/
#ifndef __FDT_SUSPEND_H__
#define __FDT_SUSPEND_H__
#include <sbi/sbi_types.h>
#include <sbi_utils/fdt/fdt_driver.h>
#ifdef CONFIG_FDT_SUSPEND
void fdt_suspend_init(const void *fdt);
#else
static inline void fdt_suspend_init(const void *fdt) { }
#endif
#endif

View File

@@ -79,7 +79,6 @@ libsbi-objs-y += sbi_heap.o
libsbi-objs-y += sbi_math.o
libsbi-objs-y += sbi_hfence.o
libsbi-objs-y += sbi_hsm.o
libsbi-objs-y += sbi_illegal_atomic.o
libsbi-objs-y += sbi_illegal_insn.o
libsbi-objs-y += sbi_init.o
libsbi-objs-y += sbi_ipi.o
@@ -100,3 +99,4 @@ libsbi-objs-y += sbi_trap_v_ldst.o
libsbi-objs-y += sbi_unpriv.o
libsbi-objs-y += sbi_expected_trap.o
libsbi-objs-y += sbi_cppc.o
libsbi-objs-y += sbi_clk.o

View File

@@ -12,7 +12,7 @@
#include <sbi/riscv_atomic.h>
#include <sbi/riscv_barrier.h>
#if !defined(__riscv_atomic) && !defined(__riscv_zalrsc)
#ifndef __riscv_atomic
#error "opensbi strongly relies on the A extension of RISC-V"
#endif
@@ -31,7 +31,6 @@ void atomic_write(atomic_t *atom, long value)
long atomic_add_return(atomic_t *atom, long value)
{
#ifdef __riscv_atomic
long ret;
#if __SIZEOF_LONG__ == 4
__asm__ __volatile__(" amoadd.w.aqrl %1, %2, %0"
@@ -44,29 +43,6 @@ long atomic_add_return(atomic_t *atom, long value)
: "r"(value)
: "memory");
#endif
#elif __riscv_zalrsc
long ret, temp;
#if __SIZEOF_LONG__ == 4
__asm__ __volatile__("1:lr.w.aqrl %1,%0\n"
" addw %2,%1,%3\n"
" sc.w.aqrl %2,%2,%0\n"
" bnez %2,1b"
: "+A"(atom->counter), "=&r"(ret), "=&r"(temp)
: "r"(value)
: "memory");
#elif __SIZEOF_LONG__ == 8
__asm__ __volatile__("1:lr.d.aqrl %1,%0\n"
" add %2,%1,%3\n"
" sc.d.aqrl %2,%2,%0\n"
" bnez %2,1b"
: "+A"(atom->counter), "=&r"(ret), "=&r"(temp)
: "r"(value)
: "memory");
#endif
#else
#error "need a or zalrsc"
#endif
return ret + value;
}
@@ -75,7 +51,6 @@ long atomic_sub_return(atomic_t *atom, long value)
return atomic_add_return(atom, -value);
}
#ifdef __riscv_atomic
#define __axchg(ptr, new, size) \
({ \
__typeof__(ptr) __ptr = (ptr); \
@@ -101,39 +76,6 @@ long atomic_sub_return(atomic_t *atom, long value)
} \
__ret; \
})
#elif __riscv_zalrsc
#define __axchg(ptr, new, size) \
({ \
__typeof__(ptr) __ptr = (ptr); \
__typeof__(new) __new = (new); \
__typeof__(*(ptr)) __ret, __temp; \
switch (size) { \
case 4: \
__asm__ __volatile__ ( \
"1: lr.w.aqrl %0, %1\n" \
" sc.w.aqrl %2, %3, %1\n" \
" bnez %2, 1b\n" \
: "=&r" (__ret), "+A" (*__ptr), "=&r" (__temp) \
: "r" (__new) \
: "memory"); \
break; \
case 8: \
__asm__ __volatile__ ( \
"1: lr.d.aqrl %0, %1\n" \
" sc.d.aqrl %2, %3, %1\n" \
" bnez %2, 1b\n" \
: "=&r" (__ret), "+A" (*__ptr), "=&r" (__temp) \
: "r" (__new) \
: "memory"); \
break; \
default: \
break; \
} \
__ret; \
})
#else
#error "need a or zalrsc"
#endif
#define axchg(ptr, x) \
({ \

View File

@@ -53,16 +53,7 @@ void spin_lock(spinlock_t *lock)
__asm__ __volatile__(
/* Atomically increment the next ticket. */
#ifdef __riscv_atomic
" amoadd.w.aqrl %0, %4, %3\n"
#elif __riscv_zalrsc
"3: lr.w.aqrl %0, %3\n"
" addw %1, %0, %4\n"
" sc.w.aqrl %1, %1, %3\n"
" bnez %1, 3b\n"
#else
#error "need a or zalrsc"
#endif
/* Did we get the lock? */
" srli %1, %0, %6\n"

64
lib/sbi/sbi_clk.c Normal file
View File

@@ -0,0 +1,64 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2025 Sophgo Inc.
*
* Authors:
* Haijiao Liu <haijiao.liu@sophgo.com>
*/
#include <sbi/sbi_error.h>
#include <sbi/sbi_clk.h>
#include <sbi_utils/clk/fdt_clk.h>
static const struct sbi_clk_device *clk_dev = NULL;
const struct sbi_clk_device *sbi_clk_get_device(const void *fdt)
{
if (!clk_dev)
fdt_clk_init(fdt);
return clk_dev ? clk_dev : NULL;
}
void sbi_clk_set_device(const struct sbi_clk_device *dev)
{
if (!dev || clk_dev)
return;
clk_dev = dev;
}
int sbi_clk_set_rate(const char *name, uint64_t rate)
{
if (!clk_dev || !clk_dev->clk_set_rate)
return SBI_EFAIL;
clk_dev->clk_set_rate(name, rate);
return 0;
}
uint64_t sbi_clk_get_rate(const char *name)
{
if (!clk_dev || !clk_dev->clk_get_rate)
return SBI_EFAIL;
return clk_dev->clk_get_rate(name);
}
int sbi_clk_enable(const char *name)
{
if (!clk_dev || !clk_dev->clk_enable)
return SBI_EFAIL;
return clk_dev->clk_enable(name);
}
int sbi_clk_disable(const char *name)
{
if (!clk_dev || !clk_dev->clk_disable)
return SBI_EFAIL;
return clk_dev->clk_disable(name);
}

View File

@@ -506,7 +506,7 @@ int sbi_dbtr_read_trig(unsigned long smode,
{
struct sbi_dbtr_data_msg *xmit;
struct sbi_dbtr_trigger *trig;
union sbi_dbtr_shmem_entry *entry;
struct sbi_dbtr_shmem_entry *entry;
void *shmem_base = NULL;
struct sbi_dbtr_hart_triggers_state *hs = NULL;
@@ -523,17 +523,16 @@ int sbi_dbtr_read_trig(unsigned long smode,
shmem_base = hart_shmem_base(hs);
sbi_hart_map_saddr((unsigned long)shmem_base,
trig_count * sizeof(*entry));
for_each_trig_entry(shmem_base, trig_count, typeof(*entry), entry) {
sbi_hart_map_saddr((unsigned long)entry, sizeof(*entry));
xmit = &entry->data;
trig = INDEX_TO_TRIGGER((_idx + trig_idx_base));
xmit->tstate = cpu_to_lle(trig->state);
xmit->tdata1 = cpu_to_lle(trig->tdata1);
xmit->tdata2 = cpu_to_lle(trig->tdata2);
xmit->tdata3 = cpu_to_lle(trig->tdata3);
sbi_hart_unmap_saddr();
}
sbi_hart_unmap_saddr();
return SBI_SUCCESS;
}
@@ -542,7 +541,7 @@ int sbi_dbtr_install_trig(unsigned long smode,
unsigned long trig_count, unsigned long *out)
{
void *shmem_base = NULL;
union sbi_dbtr_shmem_entry *entry;
struct sbi_dbtr_shmem_entry *entry;
struct sbi_dbtr_data_msg *recv;
struct sbi_dbtr_id_msg *xmit;
unsigned long ctrl;
@@ -557,11 +556,10 @@ int sbi_dbtr_install_trig(unsigned long smode,
return SBI_ERR_NO_SHMEM;
shmem_base = hart_shmem_base(hs);
sbi_hart_map_saddr((unsigned long)shmem_base,
trig_count * sizeof(*entry));
/* Check requested triggers configuration */
for_each_trig_entry(shmem_base, trig_count, typeof(*entry), entry) {
sbi_hart_map_saddr((unsigned long)entry, sizeof(*entry));
recv = (struct sbi_dbtr_data_msg *)(&entry->data);
ctrl = recv->tdata1;
@@ -576,11 +574,11 @@ int sbi_dbtr_install_trig(unsigned long smode,
sbi_hart_unmap_saddr();
return SBI_ERR_FAILED;
}
sbi_hart_unmap_saddr();
}
if (hs->available_trigs < trig_count) {
*out = hs->available_trigs;
sbi_hart_unmap_saddr();
return SBI_ERR_FAILED;
}
@@ -592,15 +590,16 @@ int sbi_dbtr_install_trig(unsigned long smode,
*/
trig = sbi_alloc_trigger();
sbi_hart_map_saddr((unsigned long)entry, sizeof(*entry));
recv = (struct sbi_dbtr_data_msg *)(&entry->data);
xmit = (struct sbi_dbtr_id_msg *)(&entry->id);
dbtr_trigger_setup(trig, recv);
dbtr_trigger_enable(trig);
xmit->idx = cpu_to_lle(trig->index);
sbi_hart_unmap_saddr();
}
sbi_hart_unmap_saddr();
return SBI_SUCCESS;
}
@@ -652,11 +651,15 @@ int sbi_dbtr_enable_trig(unsigned long trig_idx_base,
}
int sbi_dbtr_update_trig(unsigned long smode,
unsigned long trig_count)
unsigned long trig_idx_base,
unsigned long trig_idx_mask)
{
unsigned long trig_idx;
unsigned long trig_mask = trig_idx_mask << trig_idx_base;
unsigned long idx = trig_idx_base;
struct sbi_dbtr_data_msg *recv;
unsigned long uidx = 0;
struct sbi_dbtr_trigger *trig;
union sbi_dbtr_shmem_entry *entry;
struct sbi_dbtr_shmem_entry *entry;
void *shmem_base = NULL;
struct sbi_dbtr_hart_triggers_state *hs = NULL;
@@ -669,28 +672,18 @@ int sbi_dbtr_update_trig(unsigned long smode,
shmem_base = hart_shmem_base(hs);
if (trig_count >= hs->total_trigs)
return SBI_ERR_BAD_RANGE;
for_each_set_bit_from(idx, &trig_mask, hs->total_trigs) {
trig = INDEX_TO_TRIGGER(idx);
for_each_trig_entry(shmem_base, trig_count, typeof(*entry), entry) {
sbi_hart_map_saddr((unsigned long)entry, sizeof(*entry));
trig_idx = entry->id.idx;
if (trig_idx >= hs->total_trigs) {
sbi_hart_unmap_saddr();
if (!(trig->state & RV_DBTR_BIT_MASK(TS, MAPPED)))
return SBI_ERR_INVALID_PARAM;
}
trig = INDEX_TO_TRIGGER(trig_idx);
entry = (shmem_base + uidx * sizeof(*entry));
recv = &entry->data;
if (!(trig->state & RV_DBTR_BIT_MASK(TS, MAPPED))) {
sbi_hart_unmap_saddr();
return SBI_ERR_FAILED;
}
dbtr_trigger_setup(trig, &entry->data);
sbi_hart_unmap_saddr();
trig->tdata2 = lle_to_cpu(recv->tdata2);
dbtr_trigger_enable(trig);
uidx++;
}
return SBI_SUCCESS;

View File

@@ -685,15 +685,20 @@ int sbi_domain_root_add_memrange(unsigned long addr, unsigned long size,
return 0;
}
int sbi_domain_startup(struct sbi_scratch *scratch, u32 cold_hartid)
int sbi_domain_finalize(struct sbi_scratch *scratch, u32 cold_hartid)
{
int rc;
u32 dhart;
struct sbi_domain *dom;
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
/* Sanity checks */
if (!domain_finalized)
return SBI_EINVAL;
/* Initialize and populate domains for the platform */
rc = sbi_platform_domains_init(plat);
if (rc) {
sbi_printf("%s: platform domains_init() failed (error %d)\n",
__func__, rc);
return rc;
}
/* Startup boot HART of domains */
sbi_domain_for_each(dom) {
@@ -739,26 +744,6 @@ int sbi_domain_startup(struct sbi_scratch *scratch, u32 cold_hartid)
}
}
return 0;
}
int sbi_domain_finalize(struct sbi_scratch *scratch)
{
int rc;
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
/* Sanity checks */
if (domain_finalized)
return SBI_EINVAL;
/* Initialize and populate domains for the platform */
rc = sbi_platform_domains_init(plat);
if (rc) {
sbi_printf("%s: platform domains_init() failed (error %d)\n",
__func__, rc);
return rc;
}
/*
* Set the finalized flag so that the root domain
* regions can't be changed.
@@ -770,9 +755,11 @@ int sbi_domain_finalize(struct sbi_scratch *scratch)
int sbi_domain_init(struct sbi_scratch *scratch, u32 cold_hartid)
{
u32 i;
int rc;
struct sbi_hartmask *root_hmask;
struct sbi_domain_memregion *root_memregs;
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
SBI_INIT_LIST_HEAD(&domain_list);
@@ -853,7 +840,7 @@ int sbi_domain_init(struct sbi_scratch *scratch, u32 cold_hartid)
root.next_mode = scratch->next_mode;
/* Root domain possible and assigned HARTs */
sbi_for_each_hartindex(i)
for (i = 0; i < plat->hart_count; i++)
sbi_hartmask_set_hartindex(i, root_hmask);
/* Finally register the root domain */

View File

@@ -15,7 +15,6 @@
#include <sbi/sbi_string.h>
#include <sbi/sbi_domain.h>
#include <sbi/sbi_domain_context.h>
#include <sbi/sbi_platform.h>
#include <sbi/sbi_trap.h>
/** Context representation for a hart within a domain */
@@ -54,30 +53,31 @@ struct hart_context {
bool initialized;
};
static struct sbi_domain_data dcpriv;
struct domain_context_priv {
/** Contexts for possible HARTs indexed by hartindex */
struct hart_context *hartindex_to_context_table[SBI_HARTMASK_MAX_BITS];
};
static struct sbi_domain_data dcpriv = {
.data_size = sizeof(struct domain_context_priv),
};
static inline struct hart_context *hart_context_get(struct sbi_domain *dom,
u32 hartindex)
{
struct hart_context **dom_hartindex_to_context_table;
struct domain_context_priv *dcp = sbi_domain_data_ptr(dom, &dcpriv);
dom_hartindex_to_context_table = sbi_domain_data_ptr(dom, &dcpriv);
if (!dom_hartindex_to_context_table || !sbi_hartindex_valid(hartindex))
return NULL;
return dom_hartindex_to_context_table[hartindex];
return (dcp && hartindex < SBI_HARTMASK_MAX_BITS) ?
dcp->hartindex_to_context_table[hartindex] : NULL;
}
static void hart_context_set(struct sbi_domain *dom, u32 hartindex,
struct hart_context *hc)
{
struct hart_context **dom_hartindex_to_context_table;
struct domain_context_priv *dcp = sbi_domain_data_ptr(dom, &dcpriv);
dom_hartindex_to_context_table = sbi_domain_data_ptr(dom, &dcpriv);
if (!dom_hartindex_to_context_table || !sbi_hartindex_valid(hartindex))
return;
dom_hartindex_to_context_table[hartindex] = hc;
if (dcp && hartindex < SBI_HARTMASK_MAX_BITS)
dcp->hartindex_to_context_table[hartindex] = hc;
}
/** Macro to obtain the current hart's context pointer */
@@ -116,7 +116,6 @@ static void switch_to_next_domain_context(struct hart_context *ctx,
/* Reconfigure PMP settings for the new domain */
for (int i = 0; i < pmp_count; i++) {
sbi_platform_pmp_disable(sbi_platform_thishart_ptr(), i);
pmp_disable(i);
}
sbi_hart_pmp_configure(scratch);
@@ -233,14 +232,6 @@ int sbi_domain_context_exit(void)
int sbi_domain_context_init(void)
{
/**
* Allocate per-domain and per-hart context data.
* The data type is "struct hart_context **" whose memory space will be
* dynamically allocated by domain_setup_data_one(). Calculate needed
* size of memory space here.
*/
dcpriv.data_size = sizeof(struct hart_context *) * sbi_hart_count();
return sbi_domain_register_data(&dcpriv);
}

View File

@@ -10,7 +10,6 @@
#include <sbi/sbi_console.h>
#include <sbi/sbi_ecall_interface.h>
#include <sbi/sbi_error.h>
#include <sbi/sbi_hart.h>
#include <sbi/sbi_sse.h>
#include <sbi/sbi_trap.h>
@@ -29,9 +28,3 @@ int sbi_double_trap_handler(struct sbi_trap_context *tcntx)
return sbi_sse_inject_event(SBI_SSE_EVENT_LOCAL_DOUBLE_TRAP);
}
void sbi_double_trap_init(struct sbi_scratch *scratch)
{
if (sbi_hart_has_extension(scratch, SBI_HART_EXT_SSDBLTRP))
sbi_sse_add_event(SBI_SSE_EVENT_LOCAL_DOUBLE_TRAP, NULL);
}

View File

@@ -93,6 +93,7 @@ int sbi_ecall_register_extension(struct sbi_ecall_extension *ext)
return SBI_EINVAL;
}
SBI_INIT_LIST_HEAD(&ext->head);
sbi_list_add_tail(&ext->head, &ecall_exts_list);
return 0;

View File

@@ -43,7 +43,7 @@ static int sbi_ecall_dbtr_handler(unsigned long extid, unsigned long funcid,
ret = sbi_dbtr_enable_trig(regs->a0, regs->a1);
break;
case SBI_EXT_DBTR_TRIGGER_UPDATE:
ret = sbi_dbtr_update_trig(smode, regs->a0);
ret = sbi_dbtr_update_trig(smode, regs->a0, regs->a1);
break;
case SBI_EXT_DBTR_TRIGGER_DISABLE:
ret = sbi_dbtr_disable_trig(regs->a0, regs->a1);
@@ -69,6 +69,7 @@ struct sbi_ecall_extension ecall_dbtr = {
.name = "dbtr",
.extid_start = SBI_EXT_DBTR,
.extid_end = SBI_EXT_DBTR,
.experimental = true,
.handle = sbi_ecall_dbtr_handler,
.register_extensions = sbi_ecall_dbtr_register_extensions,
};

View File

@@ -45,6 +45,7 @@ struct sbi_ecall_extension ecall_fwft = {
.name = "fwft",
.extid_start = SBI_EXT_FWFT,
.extid_end = SBI_EXT_FWFT,
.experimental = true,
.register_extensions = sbi_ecall_fwft_register_extensions,
.handle = sbi_ecall_fwft_handler,
};

View File

@@ -20,11 +20,8 @@ static int sbi_ecall_mpxy_handler(unsigned long extid, unsigned long funcid,
int ret = 0;
switch (funcid) {
case SBI_EXT_MPXY_GET_SHMEM_SIZE:
out->value = sbi_mpxy_get_shmem_size();
break;
case SBI_EXT_MPXY_SET_SHMEM:
ret = sbi_mpxy_set_shmem(regs->a0, regs->a1, regs->a2);
ret = sbi_mpxy_set_shmem(regs->a0, regs->a1, regs->a2, regs->a3);
break;
case SBI_EXT_MPXY_GET_CHANNEL_IDS:
ret = sbi_mpxy_get_channel_ids(regs->a0);
@@ -39,7 +36,7 @@ static int sbi_ecall_mpxy_handler(unsigned long extid, unsigned long funcid,
ret = sbi_mpxy_send_message(regs->a0, regs->a1,
regs->a2, &out->value);
break;
case SBI_EXT_MPXY_SEND_MSG_WITHOUT_RESP:
case SBI_EXT_MPXY_SEND_MSG_NO_RESP:
ret = sbi_mpxy_send_message(regs->a0, regs->a1, regs->a2,
NULL);
break;
@@ -67,6 +64,7 @@ struct sbi_ecall_extension ecall_mpxy = {
.name = "mpxy",
.extid_start = SBI_EXT_MPXY,
.extid_end = SBI_EXT_MPXY,
.experimental = true,
.register_extensions = sbi_ecall_mpxy_register_extensions,
.handle = sbi_ecall_mpxy_handler,
};

View File

@@ -59,6 +59,7 @@ struct sbi_ecall_extension ecall_sse = {
.name = "sse",
.extid_start = SBI_EXT_SSE,
.extid_end = SBI_EXT_SSE,
.experimental = true,
.register_extensions = sbi_ecall_sse_register_extensions,
.handle = sbi_ecall_sse_handler,
};

View File

@@ -223,32 +223,32 @@ static int fwft_pmlen_supported(struct fwft_config *conf)
return SBI_OK;
}
static bool fwft_try_to_set_pmm(unsigned long pmm)
{
csr_set(CSR_MENVCFG, pmm);
return (csr_read(CSR_MENVCFG) & ENVCFG_PMM) == pmm;
}
static int fwft_set_pmlen(struct fwft_config *conf, unsigned long value)
{
unsigned long pmm, prev;
unsigned long prev;
switch (value) {
case 0:
pmm = ENVCFG_PMM_PMLEN_0;
break;
case 7:
pmm = ENVCFG_PMM_PMLEN_7;
break;
case 16:
pmm = ENVCFG_PMM_PMLEN_16;
break;
default:
if (value > 16)
return SBI_EINVAL;
}
prev = csr_read_clear(CSR_MENVCFG, ENVCFG_PMM);
csr_set(CSR_MENVCFG, pmm);
if ((csr_read(CSR_MENVCFG) & ENVCFG_PMM) != pmm) {
csr_write(CSR_MENVCFG, prev);
return SBI_EINVAL;
if (value == 0)
return SBI_OK;
if (value <= 7) {
if (fwft_try_to_set_pmm(ENVCFG_PMM_PMLEN_7))
return SBI_OK;
csr_clear(CSR_MENVCFG, ENVCFG_PMM);
}
if (fwft_try_to_set_pmm(ENVCFG_PMM_PMLEN_16))
return SBI_OK;
csr_write(CSR_MENVCFG, prev);
return SBI_OK;
return SBI_EINVAL;
}
static int fwft_get_pmlen(struct fwft_config *conf, unsigned long *value)
@@ -337,7 +337,7 @@ int sbi_fwft_set(enum sbi_fwft_feature_t feature, unsigned long value,
return SBI_EINVAL;
if (conf->flags & SBI_FWFT_SET_FLAG_LOCK)
return SBI_EDENIED_LOCKED;
return SBI_EDENIED;
ret = conf->feature->set(conf, value);
if (ret)

View File

@@ -85,11 +85,11 @@ static void mstatus_init(struct sbi_scratch *scratch)
#endif
}
if (misa_extension('H'))
csr_write(CSR_HSTATUS, 0);
if (sbi_hart_has_extension(scratch, SBI_HART_EXT_SMSTATEEN)) {
mstateen_val = 0;
mstateen_val = csr_read(CSR_MSTATEEN0);
#if __riscv_xlen == 32
mstateen_val |= ((uint64_t)csr_read(CSR_MSTATEEN0H)) << 32;
#endif
mstateen_val |= SMSTATEEN_STATEN;
mstateen_val |= SMSTATEEN0_CONTEXT;
mstateen_val |= SMSTATEEN0_HSENVCFG;
@@ -105,34 +105,17 @@ static void mstatus_init(struct sbi_scratch *scratch)
else
mstateen_val &= ~(SMSTATEEN0_SVSLCT);
if (sbi_hart_has_extension(scratch, SBI_HART_EXT_SSCTR))
mstateen_val |= SMSTATEEN0_CTR;
else
mstateen_val &= ~SMSTATEEN0_CTR;
csr_write64(CSR_MSTATEEN0, mstateen_val);
csr_write64(CSR_MSTATEEN1, SMSTATEEN_STATEN);
csr_write64(CSR_MSTATEEN2, SMSTATEEN_STATEN);
csr_write64(CSR_MSTATEEN3, SMSTATEEN_STATEN);
}
if (sbi_hart_has_extension(scratch, SBI_HART_EXT_SSSTATEEN)) {
if (misa_extension('S')) {
csr_write(CSR_SSTATEEN0, 0);
csr_write(CSR_SSTATEEN1, 0);
csr_write(CSR_SSTATEEN2, 0);
csr_write(CSR_SSTATEEN3, 0);
}
if (misa_extension('H')) {
csr_write64(CSR_HSTATEEN0, (uint64_t)0);
csr_write64(CSR_HSTATEEN1, (uint64_t)0);
csr_write64(CSR_HSTATEEN2, (uint64_t)0);
csr_write64(CSR_HSTATEEN3, (uint64_t)0);
}
csr_write(CSR_MSTATEEN0, mstateen_val);
#if __riscv_xlen == 32
csr_write(CSR_MSTATEEN0H, mstateen_val >> 32);
#endif
}
if (sbi_hart_priv_version(scratch) >= SBI_HART_PRIV_VER_1_12) {
menvcfg_val = csr_read64(CSR_MENVCFG);
menvcfg_val = csr_read(CSR_MENVCFG);
#if __riscv_xlen == 32
menvcfg_val |= ((uint64_t)csr_read(CSR_MENVCFGH)) << 32;
#endif
/* Disable double trap by default */
menvcfg_val &= ~ENVCFG_DTE;
@@ -168,7 +151,10 @@ static void mstatus_init(struct sbi_scratch *scratch)
if (sbi_hart_has_extension(scratch, SBI_HART_EXT_SVADE))
menvcfg_val &= ~ENVCFG_ADUE;
csr_write64(CSR_MENVCFG, menvcfg_val);
csr_write(CSR_MENVCFG, menvcfg_val);
#if __riscv_xlen == 32
csr_write(CSR_MENVCFGH, menvcfg_val >> 32);
#endif
/* Enable S-mode access to seed CSR */
if (sbi_hart_has_extension(scratch, SBI_HART_EXT_ZKR)) {
@@ -217,7 +203,7 @@ static int delegate_traps(struct sbi_scratch *scratch)
/* Send M-mode interrupts and most exceptions to S-mode */
interrupts = MIP_SSIP | MIP_STIP | MIP_SEIP;
interrupts |= sbi_pmu_irq_mask();
interrupts |= sbi_pmu_irq_bit();
exceptions = (1U << CAUSE_MISALIGNED_FETCH) | (1U << CAUSE_BREAKPOINT) |
(1U << CAUSE_USER_ECALL);
@@ -375,9 +361,6 @@ static void sbi_hart_smepmp_set(struct sbi_scratch *scratch,
unsigned long pmp_addr = reg->base >> PMP_SHIFT;
if (pmp_log2gran <= reg->order && pmp_addr < pmp_addr_max) {
sbi_platform_pmp_set(sbi_platform_ptr(scratch),
pmp_idx, reg->flags, pmp_flags,
reg->base, reg->order);
pmp_set(pmp_idx, pmp_flags, reg->base, reg->order);
} else {
sbi_printf("Can not configure pmp for domain %s because"
@@ -495,9 +478,6 @@ static int sbi_hart_oldpmp_configure(struct sbi_scratch *scratch,
pmp_addr = reg->base >> PMP_SHIFT;
if (pmp_log2gran <= reg->order && pmp_addr < pmp_addr_max) {
sbi_platform_pmp_set(sbi_platform_ptr(scratch),
pmp_idx, reg->flags, pmp_flags,
reg->base, reg->order);
pmp_set(pmp_idx++, pmp_flags, reg->base, reg->order);
} else {
sbi_printf("Can not configure pmp for domain %s because"
@@ -538,9 +518,6 @@ int sbi_hart_map_saddr(unsigned long addr, unsigned long size)
}
}
sbi_platform_pmp_set(sbi_platform_ptr(scratch), SBI_SMEPMP_RESV_ENTRY,
SBI_DOMAIN_MEMREGION_SHARED_SURW_MRW,
pmp_flags, base, order);
pmp_set(SBI_SMEPMP_RESV_ENTRY, pmp_flags, base, order);
return SBI_OK;
@@ -553,7 +530,6 @@ int sbi_hart_unmap_saddr(void)
if (!sbi_hart_has_extension(scratch, SBI_HART_EXT_SMEPMP))
return SBI_OK;
sbi_platform_pmp_disable(sbi_platform_ptr(scratch), SBI_SMEPMP_RESV_ENTRY);
return pmp_disable(SBI_SMEPMP_RESV_ENTRY);
}
@@ -712,9 +688,6 @@ const struct sbi_hart_ext_data sbi_hart_ext[] = {
__SBI_HART_EXT_DATA(zicfilp, SBI_HART_EXT_ZICFILP),
__SBI_HART_EXT_DATA(zicfiss, SBI_HART_EXT_ZICFISS),
__SBI_HART_EXT_DATA(ssdbltrp, SBI_HART_EXT_SSDBLTRP),
__SBI_HART_EXT_DATA(smctr, SBI_HART_EXT_SMCTR),
__SBI_HART_EXT_DATA(ssctr, SBI_HART_EXT_SSCTR),
__SBI_HART_EXT_DATA(ssstateen, SBI_HART_EXT_SSSTATEEN),
};
_Static_assert(SBI_HART_EXT_MAX == array_size(sbi_hart_ext),
@@ -741,10 +714,6 @@ void sbi_hart_get_extensions_str(struct sbi_scratch *scratch,
sbi_memset(extensions_str, 0, nestr);
for_each_set_bit(ext, hfeatures->extensions, SBI_HART_EXT_MAX) {
if (offset + sbi_strlen(sbi_hart_ext[ext].name) + 1 > nestr) {
sbi_printf("%s:extension name is longer than buffer (error)\n", __func__);
break;
}
sbi_snprintf(extensions_str + offset,
nestr - offset,
"%s,", sbi_hart_ext[ext].name);
@@ -757,20 +726,6 @@ void sbi_hart_get_extensions_str(struct sbi_scratch *scratch,
sbi_strncpy(extensions_str, "none", nestr);
}
/**
* Check whether a particular CSR is present on the HART
*
* @param scratch pointer to the HART scratch space
* @param csr the CSR number to check
*/
bool sbi_hart_has_csr(struct sbi_scratch *scratch, enum sbi_hart_csrs csr)
{
struct sbi_hart_features *hfeatures =
sbi_scratch_offset_ptr(scratch, hart_features_offset);
return __test_bit(csr, hfeatures->csrs);
}
static unsigned long hart_pmp_get_allowed_addr(void)
{
unsigned long val = 0;
@@ -827,6 +782,7 @@ static int hart_detect_features(struct sbi_scratch *scratch)
struct sbi_hart_features *hfeatures =
sbi_scratch_offset_ptr(scratch, hart_features_offset);
unsigned long val, oldval;
bool has_zicntr = false;
int rc;
/* If hart features already detected then do nothing */
@@ -835,7 +791,6 @@ static int hart_detect_features(struct sbi_scratch *scratch)
/* Clear hart features */
sbi_memset(hfeatures->extensions, 0, sizeof(hfeatures->extensions));
sbi_memset(hfeatures->csrs, 0, sizeof(hfeatures->csrs));
hfeatures->pmp_count = 0;
hfeatures->mhpm_mask = 0;
hfeatures->priv_version = SBI_HART_PRIV_VER_UNKNOWN;
@@ -962,6 +917,9 @@ __pmp_skip:
/* Detect if hart supports sscofpmf */
__check_ext_csr(SBI_HART_PRIV_VER_1_11,
CSR_SCOUNTOVF, SBI_HART_EXT_SSCOFPMF);
/* Detect if hart supports time CSR */
__check_ext_csr(SBI_HART_PRIV_VER_UNKNOWN,
CSR_TIME, SBI_HART_EXT_ZICNTR);
/* Detect if hart has AIA local interrupt CSRs */
__check_ext_csr(SBI_HART_PRIV_VER_UNKNOWN,
CSR_MTOPI, SBI_HART_EXT_SMAIA);
@@ -971,9 +929,6 @@ __pmp_skip:
/* Detect if hart supports mstateen CSRs */
__check_ext_csr(SBI_HART_PRIV_VER_1_12,
CSR_MSTATEEN0, SBI_HART_EXT_SMSTATEEN);
/* Detect if hart supports sstateen CSRs */
__check_ext_csr(SBI_HART_PRIV_VER_1_12,
CSR_SSTATEEN0, SBI_HART_EXT_SSSTATEEN);
/* Detect if hart supports smcntrpmf */
__check_ext_csr(SBI_HART_PRIV_VER_1_12,
CSR_MCYCLECFG, SBI_HART_EXT_SMCNTRPMF);
@@ -983,16 +938,8 @@ __pmp_skip:
#undef __check_ext_csr
#define __check_csr_existence(__csr, __csr_id) \
csr_read_allowed(__csr, &trap); \
if (!trap.cause) \
__set_bit(__csr_id, hfeatures->csrs);
__check_csr_existence(CSR_CYCLE, SBI_HART_CSR_CYCLE);
__check_csr_existence(CSR_TIME, SBI_HART_CSR_TIME);
__check_csr_existence(CSR_INSTRET, SBI_HART_CSR_INSTRET);
#undef __check_csr_existence
/* Save trap based detection of Zicntr */
has_zicntr = sbi_hart_has_extension(scratch, SBI_HART_EXT_ZICNTR);
/* Let platform populate extensions */
rc = sbi_platform_extensions_init(sbi_platform_thishart_ptr(),
@@ -1002,9 +949,7 @@ __pmp_skip:
/* Zicntr should only be detected using traps */
__sbi_hart_update_extension(hfeatures, SBI_HART_EXT_ZICNTR,
sbi_hart_has_csr(scratch, SBI_HART_CSR_CYCLE) &&
sbi_hart_has_csr(scratch, SBI_HART_CSR_TIME) &&
sbi_hart_has_csr(scratch, SBI_HART_CSR_INSTRET));
has_zicntr);
/* Extensions implied by other extensions and features */
if (hfeatures->mhpm_mask)

View File

@@ -244,6 +244,7 @@ int sbi_heap_init_new(struct sbi_heap_control *hpctrl, unsigned long base,
/* Prepare free node list */
for (i = 0; i < (hpctrl->hksize / sizeof(*n)); i++) {
n = (struct heap_node *)(hpctrl->hkbase + (sizeof(*n) * i));
SBI_INIT_LIST_HEAD(&n->head);
n->addr = n->size = 0;
sbi_list_add_tail(&n->head, &hpctrl->free_node_list);
}

View File

@@ -37,8 +37,6 @@
static const struct sbi_hsm_device *hsm_dev = NULL;
static unsigned long hart_data_offset;
static bool hsm_device_has_hart_hotplug(void);
static int hsm_device_hart_stop(void);
/** Per hart specific data to manage state transition **/
struct sbi_hsm_data {
@@ -172,15 +170,6 @@ static void sbi_hsm_hart_wait(struct sbi_scratch *scratch)
/* Wait for state transition requested by sbi_hsm_hart_start() */
while (atomic_read(&hdata->state) != SBI_HSM_STATE_START_PENDING) {
/*
* If the hsm_dev is ready and it support the hotplug, we can
* use the hsm stop for more power saving
*/
if (hsm_device_has_hart_hotplug()) {
sbi_revert_entry_count(scratch);
hsm_device_hart_stop();
}
wfi();
}
@@ -249,6 +238,7 @@ static void hsm_device_hart_resume(void)
int sbi_hsm_init(struct sbi_scratch *scratch, bool cold_boot)
{
u32 i;
struct sbi_scratch *rscratch;
struct sbi_hsm_data *hdata;
@@ -258,7 +248,7 @@ int sbi_hsm_init(struct sbi_scratch *scratch, bool cold_boot)
return SBI_ENOMEM;
/* Initialize hart state data for every hart */
sbi_for_each_hartindex(i) {
for (i = 0; i <= sbi_scratch_last_hartindex(); i++) {
rscratch = sbi_hartindex_to_scratch(i);
if (!rscratch)
continue;

View File

@@ -1,664 +0,0 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2025 MIPS
*
*/
#include <sbi/riscv_asm.h>
#include <sbi/sbi_hart.h>
#include <sbi/sbi_trap.h>
#include <sbi/sbi_illegal_atomic.h>
#include <sbi/sbi_illegal_insn.h>
#if !defined(__riscv_atomic) && !defined(__riscv_zalrsc)
#error "opensbi strongly relies on the A extension of RISC-V"
#endif
#ifdef __riscv_atomic
int sbi_illegal_atomic(ulong insn, struct sbi_trap_regs *regs)
{
return truly_illegal_insn(insn, regs);
}
#elif __riscv_zalrsc
#define DEFINE_UNPRIVILEGED_LR_FUNCTION(type, aqrl, insn) \
static type lr_##type##aqrl(const type *addr, \
struct sbi_trap_info *trap) \
{ \
register ulong tinfo asm("a3"); \
register ulong mstatus = 0; \
register ulong mtvec = sbi_hart_expected_trap_addr(); \
type ret = 0; \
trap->cause = 0; \
asm volatile( \
"add %[tinfo], %[taddr], zero\n" \
"csrrw %[mtvec], " STR(CSR_MTVEC) ", %[mtvec]\n" \
"csrrs %[mstatus], " STR(CSR_MSTATUS) ", %[mprv]\n" \
".option push\n" \
".option norvc\n" \
#insn " %[ret], %[addr]\n" \
".option pop\n" \
"csrw " STR(CSR_MSTATUS) ", %[mstatus]\n" \
"csrw " STR(CSR_MTVEC) ", %[mtvec]" \
: [mstatus] "+&r"(mstatus), [mtvec] "+&r"(mtvec), \
[tinfo] "+&r"(tinfo), [ret] "=&r"(ret) \
: [addr] "m"(*addr), [mprv] "r"(MSTATUS_MPRV), \
[taddr] "r"((ulong)trap) \
: "a4", "memory"); \
return ret; \
}
#define DEFINE_UNPRIVILEGED_SC_FUNCTION(type, aqrl, insn) \
static type sc_##type##aqrl(type *addr, type val, \
struct sbi_trap_info *trap) \
{ \
register ulong tinfo asm("a3"); \
register ulong mstatus = 0; \
register ulong mtvec = sbi_hart_expected_trap_addr(); \
type ret = 0; \
trap->cause = 0; \
asm volatile( \
"add %[tinfo], %[taddr], zero\n" \
"csrrw %[mtvec], " STR(CSR_MTVEC) ", %[mtvec]\n" \
"csrrs %[mstatus], " STR(CSR_MSTATUS) ", %[mprv]\n" \
".option push\n" \
".option norvc\n" \
#insn " %[ret], %[val], %[addr]\n" \
".option pop\n" \
"csrw " STR(CSR_MSTATUS) ", %[mstatus]\n" \
"csrw " STR(CSR_MTVEC) ", %[mtvec]" \
: [mstatus] "+&r"(mstatus), [mtvec] "+&r"(mtvec), \
[tinfo] "+&r"(tinfo), [ret] "=&r"(ret) \
: [addr] "m"(*addr), [mprv] "r"(MSTATUS_MPRV), \
[val] "r"(val), [taddr] "r"((ulong)trap) \
: "a4", "memory"); \
return ret; \
}
DEFINE_UNPRIVILEGED_LR_FUNCTION(s32, , lr.w);
DEFINE_UNPRIVILEGED_LR_FUNCTION(s32, _aq, lr.w.aq);
DEFINE_UNPRIVILEGED_LR_FUNCTION(s32, _rl, lr.w.rl);
DEFINE_UNPRIVILEGED_LR_FUNCTION(s32, _aqrl, lr.w.aqrl);
DEFINE_UNPRIVILEGED_SC_FUNCTION(s32, , sc.w);
DEFINE_UNPRIVILEGED_SC_FUNCTION(s32, _aq, sc.w.aq);
DEFINE_UNPRIVILEGED_SC_FUNCTION(s32, _rl, sc.w.rl);
DEFINE_UNPRIVILEGED_SC_FUNCTION(s32, _aqrl, sc.w.aqrl);
#if __riscv_xlen == 64
DEFINE_UNPRIVILEGED_LR_FUNCTION(s64, , lr.d);
DEFINE_UNPRIVILEGED_LR_FUNCTION(s64, _aq, lr.d.aq);
DEFINE_UNPRIVILEGED_LR_FUNCTION(s64, _rl, lr.d.rl);
DEFINE_UNPRIVILEGED_LR_FUNCTION(s64, _aqrl, lr.d.aqrl);
DEFINE_UNPRIVILEGED_SC_FUNCTION(s64, , sc.d);
DEFINE_UNPRIVILEGED_SC_FUNCTION(s64, _aq, sc.d.aq);
DEFINE_UNPRIVILEGED_SC_FUNCTION(s64, _rl, sc.d.rl);
DEFINE_UNPRIVILEGED_SC_FUNCTION(s64, _aqrl, sc.d.aqrl);
#endif
#define DEFINE_ATOMIC_FUNCTION(name, type, func) \
static int atomic_##name(ulong insn, struct sbi_trap_regs *regs) \
{ \
struct sbi_trap_info uptrap; \
ulong addr = GET_RS1(insn, regs); \
ulong val = GET_RS2(insn, regs); \
ulong rd_val = 0; \
ulong fail = 1; \
while (fail) { \
rd_val = lr_##type((void *)addr, &uptrap); \
if (uptrap.cause) { \
return sbi_trap_redirect(regs, &uptrap); \
} \
fail = sc_##type((void *)addr, func, &uptrap); \
if (uptrap.cause) { \
return sbi_trap_redirect(regs, &uptrap); \
} \
} \
SET_RD(insn, regs, rd_val); \
regs->mepc += 4; \
return 0; \
}
DEFINE_ATOMIC_FUNCTION(add_w, s32, rd_val + val);
DEFINE_ATOMIC_FUNCTION(add_w_aq, s32_aq, rd_val + val);
DEFINE_ATOMIC_FUNCTION(add_w_rl, s32_rl, rd_val + val);
DEFINE_ATOMIC_FUNCTION(add_w_aqrl, s32_aqrl, rd_val + val);
DEFINE_ATOMIC_FUNCTION(and_w, s32, rd_val & val);
DEFINE_ATOMIC_FUNCTION(and_w_aq, s32_aq, rd_val & val);
DEFINE_ATOMIC_FUNCTION(and_w_rl, s32_rl, rd_val & val);
DEFINE_ATOMIC_FUNCTION(and_w_aqrl, s32_aqrl, rd_val & val);
DEFINE_ATOMIC_FUNCTION(or_w, s32, rd_val | val);
DEFINE_ATOMIC_FUNCTION(or_w_aq, s32_aq, rd_val | val);
DEFINE_ATOMIC_FUNCTION(or_w_rl, s32_rl, rd_val | val);
DEFINE_ATOMIC_FUNCTION(or_w_aqrl, s32_aqrl, rd_val | val);
DEFINE_ATOMIC_FUNCTION(xor_w, s32, rd_val ^ val);
DEFINE_ATOMIC_FUNCTION(xor_w_aq, s32_aq, rd_val ^ val);
DEFINE_ATOMIC_FUNCTION(xor_w_rl, s32_rl, rd_val ^ val);
DEFINE_ATOMIC_FUNCTION(xor_w_aqrl, s32_aqrl, rd_val ^ val);
DEFINE_ATOMIC_FUNCTION(swap_w, s32, val);
DEFINE_ATOMIC_FUNCTION(swap_w_aq, s32_aq, val);
DEFINE_ATOMIC_FUNCTION(swap_w_rl, s32_rl, val);
DEFINE_ATOMIC_FUNCTION(swap_w_aqrl, s32_aqrl, val);
DEFINE_ATOMIC_FUNCTION(max_w, s32, (s32)rd_val > (s32)val ? rd_val : val);
DEFINE_ATOMIC_FUNCTION(max_w_aq, s32_aq, (s32)rd_val > (s32)val ? rd_val : val);
DEFINE_ATOMIC_FUNCTION(max_w_rl, s32_rl, (s32)rd_val > (s32)val ? rd_val : val);
DEFINE_ATOMIC_FUNCTION(max_w_aqrl, s32_aqrl, (s32)rd_val > (s32)val ? rd_val : val);
DEFINE_ATOMIC_FUNCTION(maxu_w, s32, (u32)rd_val > (u32)val ? rd_val : val);
DEFINE_ATOMIC_FUNCTION(maxu_w_aq, s32_aq, (u32)rd_val > (u32)val ? rd_val : val);
DEFINE_ATOMIC_FUNCTION(maxu_w_rl, s32_rl, (u32)rd_val > (u32)val ? rd_val : val);
DEFINE_ATOMIC_FUNCTION(maxu_w_aqrl, s32_aqrl, (u32)rd_val > (u32)val ? rd_val : val);
DEFINE_ATOMIC_FUNCTION(min_w, s32, (s32)rd_val < (s32)val ? rd_val : val);
DEFINE_ATOMIC_FUNCTION(min_w_aq, s32_aq, (s32)rd_val < (s32)val ? rd_val : val);
DEFINE_ATOMIC_FUNCTION(min_w_rl, s32_rl, (s32)rd_val < (s32)val ? rd_val : val);
DEFINE_ATOMIC_FUNCTION(min_w_aqrl, s32_aqrl, (s32)rd_val < (s32)val ? rd_val : val);
DEFINE_ATOMIC_FUNCTION(minu_w, s32, (u32)rd_val < (u32)val ? rd_val : val);
DEFINE_ATOMIC_FUNCTION(minu_w_aq, s32_aq, (u32)rd_val < (u32)val ? rd_val : val);
DEFINE_ATOMIC_FUNCTION(minu_w_rl, s32_rl, (u32)rd_val < (u32)val ? rd_val : val);
DEFINE_ATOMIC_FUNCTION(minu_w_aqrl, s32_aqrl, (u32)rd_val < (u32)val ? rd_val : val);
#if __riscv_xlen == 64
DEFINE_ATOMIC_FUNCTION(add_d, s64, rd_val + val);
DEFINE_ATOMIC_FUNCTION(add_d_aq, s64_aq, rd_val + val);
DEFINE_ATOMIC_FUNCTION(add_d_rl, s64_rl, rd_val + val);
DEFINE_ATOMIC_FUNCTION(add_d_aqrl, s64_aqrl, rd_val + val);
DEFINE_ATOMIC_FUNCTION(and_d, s64, rd_val & val);
DEFINE_ATOMIC_FUNCTION(and_d_aq, s64_aq, rd_val & val);
DEFINE_ATOMIC_FUNCTION(and_d_rl, s64_rl, rd_val & val);
DEFINE_ATOMIC_FUNCTION(and_d_aqrl, s64_aqrl, rd_val & val);
DEFINE_ATOMIC_FUNCTION(or_d, s64, rd_val | val);
DEFINE_ATOMIC_FUNCTION(or_d_aq, s64_aq, rd_val | val);
DEFINE_ATOMIC_FUNCTION(or_d_rl, s64_rl, rd_val | val);
DEFINE_ATOMIC_FUNCTION(or_d_aqrl, s64_aqrl, rd_val | val);
DEFINE_ATOMIC_FUNCTION(xor_d, s64, rd_val ^ val);
DEFINE_ATOMIC_FUNCTION(xor_d_aq, s64_aq, rd_val ^ val);
DEFINE_ATOMIC_FUNCTION(xor_d_rl, s64_rl, rd_val ^ val);
DEFINE_ATOMIC_FUNCTION(xor_d_aqrl, s64_aqrl, rd_val ^ val);
DEFINE_ATOMIC_FUNCTION(swap_d, s64, val);
DEFINE_ATOMIC_FUNCTION(swap_d_aq, s64_aq, val);
DEFINE_ATOMIC_FUNCTION(swap_d_rl, s64_rl, val);
DEFINE_ATOMIC_FUNCTION(swap_d_aqrl, s64_aqrl, val);
DEFINE_ATOMIC_FUNCTION(max_d, s64, (s64)rd_val > (s64)val ? rd_val : val);
DEFINE_ATOMIC_FUNCTION(max_d_aq, s64_aq, (s64)rd_val > (s64)val ? rd_val : val);
DEFINE_ATOMIC_FUNCTION(max_d_rl, s64_rl, (s64)rd_val > (s64)val ? rd_val : val);
DEFINE_ATOMIC_FUNCTION(max_d_aqrl, s64_aqrl, (s64)rd_val > (s64)val ? rd_val : val);
DEFINE_ATOMIC_FUNCTION(maxu_d, s64, (u64)rd_val > (u64)val ? rd_val : val);
DEFINE_ATOMIC_FUNCTION(maxu_d_aq, s64_aq, (u64)rd_val > (u64)val ? rd_val : val);
DEFINE_ATOMIC_FUNCTION(maxu_d_rl, s64_rl, (u64)rd_val > (u64)val ? rd_val : val);
DEFINE_ATOMIC_FUNCTION(maxu_d_aqrl, s64_aqrl, (u64)rd_val > (u64)val ? rd_val : val);
DEFINE_ATOMIC_FUNCTION(min_d, s64, (s64)rd_val < (s64)val ? rd_val : val);
DEFINE_ATOMIC_FUNCTION(min_d_aq, s64_aq, (s64)rd_val < (s64)val ? rd_val : val);
DEFINE_ATOMIC_FUNCTION(min_d_rl, s64_rl, (s64)rd_val < (s64)val ? rd_val : val);
DEFINE_ATOMIC_FUNCTION(min_d_aqrl, s64_aqrl, (s64)rd_val < (s64)val ? rd_val : val);
DEFINE_ATOMIC_FUNCTION(minu_d, s64, (u64)rd_val < (u64)val ? rd_val : val);
DEFINE_ATOMIC_FUNCTION(minu_d_aq, s64_aq, (u64)rd_val < (u64)val ? rd_val : val);
DEFINE_ATOMIC_FUNCTION(minu_d_rl, s64_rl, (u64)rd_val < (u64)val ? rd_val : val);
DEFINE_ATOMIC_FUNCTION(minu_d_aqrl, s64_aqrl, (u64)rd_val < (u64)val ? rd_val : val);
#endif
static const illegal_insn_func amoadd_table[32] = {
truly_illegal_insn, /* 0 */
truly_illegal_insn, /* 1 */
truly_illegal_insn, /* 2 */
truly_illegal_insn, /* 3 */
truly_illegal_insn, /* 4 */
truly_illegal_insn, /* 5 */
truly_illegal_insn, /* 6 */
truly_illegal_insn, /* 7 */
atomic_add_w, /* 8 */
atomic_add_w_rl, /* 9 */
atomic_add_w_aq, /* 10 */
atomic_add_w_aqrl, /* 11 */
#if __riscv_xlen == 64
atomic_add_d, /* 12 */
atomic_add_d_rl, /* 13 */
atomic_add_d_aq, /* 14 */
atomic_add_d_aqrl, /* 15 */
#else
truly_illegal_insn, /* 12 */
truly_illegal_insn, /* 13 */
truly_illegal_insn, /* 14 */
truly_illegal_insn, /* 15 */
#endif
truly_illegal_insn, /* 16 */
truly_illegal_insn, /* 17 */
truly_illegal_insn, /* 18 */
truly_illegal_insn, /* 19 */
truly_illegal_insn, /* 20 */
truly_illegal_insn, /* 21 */
truly_illegal_insn, /* 22 */
truly_illegal_insn, /* 23 */
truly_illegal_insn, /* 24 */
truly_illegal_insn, /* 25 */
truly_illegal_insn, /* 26 */
truly_illegal_insn, /* 27 */
truly_illegal_insn, /* 28 */
truly_illegal_insn, /* 29 */
truly_illegal_insn, /* 30 */
truly_illegal_insn, /* 31 */
};
static const illegal_insn_func amoswap_table[32] = {
truly_illegal_insn, /* 0 */
truly_illegal_insn, /* 1 */
truly_illegal_insn, /* 2 */
truly_illegal_insn, /* 3 */
truly_illegal_insn, /* 4 */
truly_illegal_insn, /* 5 */
truly_illegal_insn, /* 6 */
truly_illegal_insn, /* 7 */
atomic_swap_w, /* 8 */
atomic_swap_w_rl, /* 9 */
atomic_swap_w_aq, /* 10 */
atomic_swap_w_aqrl, /* 11 */
#if __riscv_xlen == 64
atomic_swap_d, /* 12 */
atomic_swap_d_rl, /* 13 */
atomic_swap_d_aq, /* 14 */
atomic_swap_d_aqrl, /* 15 */
#else
truly_illegal_insn, /* 12 */
truly_illegal_insn, /* 13 */
truly_illegal_insn, /* 14 */
truly_illegal_insn, /* 15 */
#endif
truly_illegal_insn, /* 16 */
truly_illegal_insn, /* 17 */
truly_illegal_insn, /* 18 */
truly_illegal_insn, /* 19 */
truly_illegal_insn, /* 20 */
truly_illegal_insn, /* 21 */
truly_illegal_insn, /* 22 */
truly_illegal_insn, /* 23 */
truly_illegal_insn, /* 24 */
truly_illegal_insn, /* 25 */
truly_illegal_insn, /* 26 */
truly_illegal_insn, /* 27 */
truly_illegal_insn, /* 28 */
truly_illegal_insn, /* 29 */
truly_illegal_insn, /* 30 */
truly_illegal_insn, /* 31 */
};
static const illegal_insn_func amoxor_table[32] = {
truly_illegal_insn, /* 0 */
truly_illegal_insn, /* 1 */
truly_illegal_insn, /* 2 */
truly_illegal_insn, /* 3 */
truly_illegal_insn, /* 4 */
truly_illegal_insn, /* 5 */
truly_illegal_insn, /* 6 */
truly_illegal_insn, /* 7 */
atomic_xor_w, /* 8 */
atomic_xor_w_rl, /* 9 */
atomic_xor_w_aq, /* 10 */
atomic_xor_w_aqrl, /* 11 */
#if __riscv_xlen == 64
atomic_xor_d, /* 12 */
atomic_xor_d_rl, /* 13 */
atomic_xor_d_aq, /* 14 */
atomic_xor_d_aqrl, /* 15 */
#else
truly_illegal_insn, /* 12 */
truly_illegal_insn, /* 13 */
truly_illegal_insn, /* 14 */
truly_illegal_insn, /* 15 */
#endif
truly_illegal_insn, /* 16 */
truly_illegal_insn, /* 17 */
truly_illegal_insn, /* 18 */
truly_illegal_insn, /* 19 */
truly_illegal_insn, /* 20 */
truly_illegal_insn, /* 21 */
truly_illegal_insn, /* 22 */
truly_illegal_insn, /* 23 */
truly_illegal_insn, /* 24 */
truly_illegal_insn, /* 25 */
truly_illegal_insn, /* 26 */
truly_illegal_insn, /* 27 */
truly_illegal_insn, /* 28 */
truly_illegal_insn, /* 29 */
truly_illegal_insn, /* 30 */
truly_illegal_insn, /* 31 */
};
static const illegal_insn_func amoor_table[32] = {
truly_illegal_insn, /* 0 */
truly_illegal_insn, /* 1 */
truly_illegal_insn, /* 2 */
truly_illegal_insn, /* 3 */
truly_illegal_insn, /* 4 */
truly_illegal_insn, /* 5 */
truly_illegal_insn, /* 6 */
truly_illegal_insn, /* 7 */
atomic_or_w, /* 8 */
atomic_or_w_rl, /* 9 */
atomic_or_w_aq, /* 10 */
atomic_or_w_aqrl, /* 11 */
#if __riscv_xlen == 64
atomic_or_d, /* 12 */
atomic_or_d_rl, /* 13 */
atomic_or_d_aq, /* 14 */
atomic_or_d_aqrl, /* 15 */
#else
truly_illegal_insn, /* 12 */
truly_illegal_insn, /* 13 */
truly_illegal_insn, /* 14 */
truly_illegal_insn, /* 15 */
#endif
truly_illegal_insn, /* 16 */
truly_illegal_insn, /* 17 */
truly_illegal_insn, /* 18 */
truly_illegal_insn, /* 19 */
truly_illegal_insn, /* 20 */
truly_illegal_insn, /* 21 */
truly_illegal_insn, /* 22 */
truly_illegal_insn, /* 23 */
truly_illegal_insn, /* 24 */
truly_illegal_insn, /* 25 */
truly_illegal_insn, /* 26 */
truly_illegal_insn, /* 27 */
truly_illegal_insn, /* 28 */
truly_illegal_insn, /* 29 */
truly_illegal_insn, /* 30 */
truly_illegal_insn, /* 31 */
};
static const illegal_insn_func amoand_table[32] = {
truly_illegal_insn, /* 0 */
truly_illegal_insn, /* 1 */
truly_illegal_insn, /* 2 */
truly_illegal_insn, /* 3 */
truly_illegal_insn, /* 4 */
truly_illegal_insn, /* 5 */
truly_illegal_insn, /* 6 */
truly_illegal_insn, /* 7 */
atomic_and_w, /* 8 */
atomic_and_w_rl, /* 9 */
atomic_and_w_aq, /* 10 */
atomic_and_w_aqrl, /* 11 */
#if __riscv_xlen == 64
atomic_and_d, /* 12 */
atomic_and_d_rl, /* 13 */
atomic_and_d_aq, /* 14 */
atomic_and_d_aqrl, /* 15 */
#else
truly_illegal_insn, /* 12 */
truly_illegal_insn, /* 13 */
truly_illegal_insn, /* 14 */
truly_illegal_insn, /* 15 */
#endif
truly_illegal_insn, /* 16 */
truly_illegal_insn, /* 17 */
truly_illegal_insn, /* 18 */
truly_illegal_insn, /* 19 */
truly_illegal_insn, /* 20 */
truly_illegal_insn, /* 21 */
truly_illegal_insn, /* 22 */
truly_illegal_insn, /* 23 */
truly_illegal_insn, /* 24 */
truly_illegal_insn, /* 25 */
truly_illegal_insn, /* 26 */
truly_illegal_insn, /* 27 */
truly_illegal_insn, /* 28 */
truly_illegal_insn, /* 29 */
truly_illegal_insn, /* 30 */
truly_illegal_insn, /* 31 */
};
static const illegal_insn_func amomin_table[32] = {
truly_illegal_insn, /* 0 */
truly_illegal_insn, /* 1 */
truly_illegal_insn, /* 2 */
truly_illegal_insn, /* 3 */
truly_illegal_insn, /* 4 */
truly_illegal_insn, /* 5 */
truly_illegal_insn, /* 6 */
truly_illegal_insn, /* 7 */
atomic_min_w, /* 8 */
atomic_min_w_rl, /* 9 */
atomic_min_w_aq, /* 10 */
atomic_min_w_aqrl, /* 11 */
#if __riscv_xlen == 64
atomic_min_d, /* 12 */
atomic_min_d_rl, /* 13 */
atomic_min_d_aq, /* 14 */
atomic_min_d_aqrl, /* 15 */
#else
truly_illegal_insn, /* 12 */
truly_illegal_insn, /* 13 */
truly_illegal_insn, /* 14 */
truly_illegal_insn, /* 15 */
#endif
truly_illegal_insn, /* 16 */
truly_illegal_insn, /* 17 */
truly_illegal_insn, /* 18 */
truly_illegal_insn, /* 19 */
truly_illegal_insn, /* 20 */
truly_illegal_insn, /* 21 */
truly_illegal_insn, /* 22 */
truly_illegal_insn, /* 23 */
truly_illegal_insn, /* 24 */
truly_illegal_insn, /* 25 */
truly_illegal_insn, /* 26 */
truly_illegal_insn, /* 27 */
truly_illegal_insn, /* 28 */
truly_illegal_insn, /* 29 */
truly_illegal_insn, /* 30 */
truly_illegal_insn, /* 31 */
};
static const illegal_insn_func amomax_table[32] = {
truly_illegal_insn, /* 0 */
truly_illegal_insn, /* 1 */
truly_illegal_insn, /* 2 */
truly_illegal_insn, /* 3 */
truly_illegal_insn, /* 4 */
truly_illegal_insn, /* 5 */
truly_illegal_insn, /* 6 */
truly_illegal_insn, /* 7 */
atomic_max_w, /* 8 */
atomic_max_w_rl, /* 9 */
atomic_max_w_aq, /* 10 */
atomic_max_w_aqrl, /* 11 */
#if __riscv_xlen == 64
atomic_max_d, /* 12 */
atomic_max_d_rl, /* 13 */
atomic_max_d_aq, /* 14 */
atomic_max_d_aqrl, /* 15 */
#else
truly_illegal_insn, /* 12 */
truly_illegal_insn, /* 13 */
truly_illegal_insn, /* 14 */
truly_illegal_insn, /* 15 */
#endif
truly_illegal_insn, /* 16 */
truly_illegal_insn, /* 17 */
truly_illegal_insn, /* 18 */
truly_illegal_insn, /* 19 */
truly_illegal_insn, /* 20 */
truly_illegal_insn, /* 21 */
truly_illegal_insn, /* 22 */
truly_illegal_insn, /* 23 */
truly_illegal_insn, /* 24 */
truly_illegal_insn, /* 25 */
truly_illegal_insn, /* 26 */
truly_illegal_insn, /* 27 */
truly_illegal_insn, /* 28 */
truly_illegal_insn, /* 29 */
truly_illegal_insn, /* 30 */
truly_illegal_insn, /* 31 */
};
static const illegal_insn_func amominu_table[32] = {
truly_illegal_insn, /* 0 */
truly_illegal_insn, /* 1 */
truly_illegal_insn, /* 2 */
truly_illegal_insn, /* 3 */
truly_illegal_insn, /* 4 */
truly_illegal_insn, /* 5 */
truly_illegal_insn, /* 6 */
truly_illegal_insn, /* 7 */
atomic_minu_w, /* 8 */
atomic_minu_w_rl, /* 9 */
atomic_minu_w_aq, /* 10 */
atomic_minu_w_aqrl, /* 11 */
#if __riscv_xlen == 64
atomic_minu_d, /* 12 */
atomic_minu_d_rl, /* 13 */
atomic_minu_d_aq, /* 14 */
atomic_minu_d_aqrl, /* 15 */
#else
truly_illegal_insn, /* 12 */
truly_illegal_insn, /* 13 */
truly_illegal_insn, /* 14 */
truly_illegal_insn, /* 15 */
#endif
truly_illegal_insn, /* 16 */
truly_illegal_insn, /* 17 */
truly_illegal_insn, /* 18 */
truly_illegal_insn, /* 19 */
truly_illegal_insn, /* 20 */
truly_illegal_insn, /* 21 */
truly_illegal_insn, /* 22 */
truly_illegal_insn, /* 23 */
truly_illegal_insn, /* 24 */
truly_illegal_insn, /* 25 */
truly_illegal_insn, /* 26 */
truly_illegal_insn, /* 27 */
truly_illegal_insn, /* 28 */
truly_illegal_insn, /* 29 */
truly_illegal_insn, /* 30 */
truly_illegal_insn, /* 31 */
};
static const illegal_insn_func amomaxu_table[32] = {
truly_illegal_insn, /* 0 */
truly_illegal_insn, /* 1 */
truly_illegal_insn, /* 2 */
truly_illegal_insn, /* 3 */
truly_illegal_insn, /* 4 */
truly_illegal_insn, /* 5 */
truly_illegal_insn, /* 6 */
truly_illegal_insn, /* 7 */
atomic_maxu_w, /* 8 */
atomic_maxu_w_rl, /* 9 */
atomic_maxu_w_aq, /* 10 */
atomic_maxu_w_aqrl, /* 11 */
#if __riscv_xlen == 64
atomic_maxu_d, /* 12 */
atomic_maxu_d_rl, /* 13 */
atomic_maxu_d_aq, /* 14 */
atomic_maxu_d_aqrl, /* 15 */
#else
truly_illegal_insn, /* 12 */
truly_illegal_insn, /* 13 */
truly_illegal_insn, /* 14 */
truly_illegal_insn, /* 15 */
#endif
truly_illegal_insn, /* 16 */
truly_illegal_insn, /* 17 */
truly_illegal_insn, /* 18 */
truly_illegal_insn, /* 19 */
truly_illegal_insn, /* 20 */
truly_illegal_insn, /* 21 */
truly_illegal_insn, /* 22 */
truly_illegal_insn, /* 23 */
truly_illegal_insn, /* 24 */
truly_illegal_insn, /* 25 */
truly_illegal_insn, /* 26 */
truly_illegal_insn, /* 27 */
truly_illegal_insn, /* 28 */
truly_illegal_insn, /* 29 */
truly_illegal_insn, /* 30 */
truly_illegal_insn, /* 31 */
};
static int amoadd_insn(ulong insn, struct sbi_trap_regs *regs)
{
return amoadd_table[(GET_FUNC3(insn) << 2) + GET_AQRL(insn)](insn, regs);
}
static int amoswap_insn(ulong insn, struct sbi_trap_regs *regs)
{
return amoswap_table[(GET_FUNC3(insn) << 2) + GET_AQRL(insn)](insn, regs);
}
static int amoxor_insn(ulong insn, struct sbi_trap_regs *regs)
{
return amoxor_table[(GET_FUNC3(insn) << 2) + GET_AQRL(insn)](insn, regs);
}
static int amoor_insn(ulong insn, struct sbi_trap_regs *regs)
{
return amoor_table[(GET_FUNC3(insn) << 2) + GET_AQRL(insn)](insn, regs);
}
static int amoand_insn(ulong insn, struct sbi_trap_regs *regs)
{
return amoand_table[(GET_FUNC3(insn) << 2) + GET_AQRL(insn)](insn, regs);
}
static int amomin_insn(ulong insn, struct sbi_trap_regs *regs)
{
return amomin_table[(GET_FUNC3(insn) << 2) + GET_AQRL(insn)](insn, regs);
}
static int amomax_insn(ulong insn, struct sbi_trap_regs *regs)
{
return amomax_table[(GET_FUNC3(insn) << 2) + GET_AQRL(insn)](insn, regs);
}
static int amominu_insn(ulong insn, struct sbi_trap_regs *regs)
{
return amominu_table[(GET_FUNC3(insn) << 2) + GET_AQRL(insn)](insn, regs);
}
static int amomaxu_insn(ulong insn, struct sbi_trap_regs *regs)
{
return amomaxu_table[(GET_FUNC3(insn) << 2) + GET_AQRL(insn)](insn, regs);
}
static const illegal_insn_func amo_insn_table[32] = {
amoadd_insn, /* 0 */
amoswap_insn, /* 1 */
truly_illegal_insn, /* 2 */
truly_illegal_insn, /* 3 */
amoxor_insn, /* 4 */
truly_illegal_insn, /* 5 */
truly_illegal_insn, /* 6 */
truly_illegal_insn, /* 7 */
amoor_insn, /* 8 */
truly_illegal_insn, /* 9 */
truly_illegal_insn, /* 10 */
truly_illegal_insn, /* 11 */
amoand_insn, /* 12 */
truly_illegal_insn, /* 13 */
truly_illegal_insn, /* 14 */
truly_illegal_insn, /* 15 */
amomin_insn, /* 16 */
truly_illegal_insn, /* 17 */
truly_illegal_insn, /* 18 */
truly_illegal_insn, /* 19 */
amomax_insn, /* 20 */
truly_illegal_insn, /* 21 */
truly_illegal_insn, /* 22 */
truly_illegal_insn, /* 23 */
amominu_insn, /* 24 */
truly_illegal_insn, /* 25 */
truly_illegal_insn, /* 26 */
truly_illegal_insn, /* 27 */
amomaxu_insn, /* 28 */
truly_illegal_insn, /* 29 */
truly_illegal_insn, /* 30 */
truly_illegal_insn /* 31 */
};
int sbi_illegal_atomic(ulong insn, struct sbi_trap_regs *regs)
{
return amo_insn_table[(insn >> 27) & 0x1f](insn, regs);
}
#else
#error "need a or zalrsc"
#endif

View File

@@ -13,14 +13,15 @@
#include <sbi/sbi_bitops.h>
#include <sbi/sbi_emulate_csr.h>
#include <sbi/sbi_error.h>
#include <sbi/sbi_illegal_atomic.h>
#include <sbi/sbi_illegal_insn.h>
#include <sbi/sbi_pmu.h>
#include <sbi/sbi_trap.h>
#include <sbi/sbi_unpriv.h>
#include <sbi/sbi_console.h>
int truly_illegal_insn(ulong insn, struct sbi_trap_regs *regs)
typedef int (*illegal_insn_func)(ulong insn, struct sbi_trap_regs *regs);
static int truly_illegal_insn(ulong insn, struct sbi_trap_regs *regs)
{
struct sbi_trap_info trap;
@@ -122,7 +123,7 @@ static const illegal_insn_func illegal_insn_table[32] = {
truly_illegal_insn, /* 8 */
truly_illegal_insn, /* 9 */
truly_illegal_insn, /* 10 */
sbi_illegal_atomic, /* 11 */
truly_illegal_insn, /* 11 */
truly_illegal_insn, /* 12 */
truly_illegal_insn, /* 13 */
truly_illegal_insn, /* 14 */

View File

@@ -13,7 +13,6 @@
#include <sbi/sbi_console.h>
#include <sbi/sbi_cppc.h>
#include <sbi/sbi_domain.h>
#include <sbi/sbi_double_trap.h>
#include <sbi/sbi_ecall.h>
#include <sbi/sbi_fwft.h>
#include <sbi/sbi_hart.h>
@@ -161,7 +160,7 @@ static void sbi_boot_print_domains(struct sbi_scratch *scratch)
static void sbi_boot_print_hart(struct sbi_scratch *scratch, u32 hartid)
{
int xlen;
char str[256];
char str[128];
const struct sbi_domain *dom = sbi_domain_thishart_ptr();
if (scratch->options & SBI_SCRATCH_NO_BOOT_PRINTS)
@@ -267,6 +266,12 @@ static void __noreturn init_coldboot(struct sbi_scratch *scratch, u32 hartid)
if (rc)
sbi_hart_hang();
rc = sbi_sse_init(scratch, true);
if (rc) {
sbi_printf("%s: sse init failed (error %d)\n", __func__, rc);
sbi_hart_hang();
}
rc = sbi_pmu_init(scratch, true);
if (rc) {
sbi_printf("%s: pmu init failed (error %d)\n",
@@ -280,8 +285,6 @@ static void __noreturn init_coldboot(struct sbi_scratch *scratch, u32 hartid)
sbi_boot_print_banner(scratch);
sbi_double_trap_init(scratch);
rc = sbi_irqchip_init(scratch, true);
if (rc) {
sbi_printf("%s: irqchip init failed (error %d)\n",
@@ -318,13 +321,13 @@ static void __noreturn init_coldboot(struct sbi_scratch *scratch, u32 hartid)
sbi_printf("%s: mpxy init failed (error %d)\n", __func__, rc);
sbi_hart_hang();
}
/*
* Note: Finalize domains after HSM initialization
* Note: Finalize domains after HSM initialization so that we
* can startup non-root domains.
* Note: Finalize domains before HART PMP configuration so
* that we use correct domain for configuring PMP.
*/
rc = sbi_domain_finalize(scratch);
rc = sbi_domain_finalize(scratch, hartid);
if (rc) {
sbi_printf("%s: domain finalize failed (error %d)\n",
__func__, rc);
@@ -343,16 +346,6 @@ static void __noreturn init_coldboot(struct sbi_scratch *scratch, u32 hartid)
sbi_hart_hang();
}
/*
* Note: SSE events callbacks can be registered by other drivers so
* sbi_sse_init() needs to be called after all drivers have been probed.
*/
rc = sbi_sse_init(scratch, true);
if (rc) {
sbi_printf("%s: sse init failed (error %d)\n", __func__, rc);
sbi_hart_hang();
}
/*
* Note: Ecall initialization should be after platform final
* initialization so that all available platform devices are
@@ -372,17 +365,6 @@ static void __noreturn init_coldboot(struct sbi_scratch *scratch, u32 hartid)
run_all_tests();
/*
* Note: Startup domains after all initialization are done
* otherwise boot HART of non-root domain can crash.
*/
rc = sbi_domain_startup(scratch, hartid);
if (rc) {
sbi_printf("%s: domain startup failed (error %d)\n",
__func__, rc);
sbi_hart_hang();
}
/*
* Configure PMP at last because if SMEPMP is detected,
* M-mode access to the S/U space will be rescinded.
@@ -426,6 +408,10 @@ static void __noreturn init_warm_startup(struct sbi_scratch *scratch,
if (rc)
sbi_hart_hang();
rc = sbi_sse_init(scratch, false);
if (rc)
sbi_hart_hang();
rc = sbi_pmu_init(scratch, false);
if (rc)
sbi_hart_hang();
@@ -458,10 +444,6 @@ static void __noreturn init_warm_startup(struct sbi_scratch *scratch,
if (rc)
sbi_hart_hang();
rc = sbi_sse_init(scratch, false);
if (rc)
sbi_hart_hang();
/*
* Configure PMP at last because if SMEPMP is detected,
* M-mode access to the S/U space will be rescinded.
@@ -579,19 +561,6 @@ void __noreturn sbi_init(struct sbi_scratch *scratch)
init_warmboot(scratch, hartid);
}
void sbi_revert_entry_count(struct sbi_scratch *scratch)
{
unsigned long *entry_count, *init_count;
if (!entry_count_offset || !init_count_offset)
sbi_hart_hang();
entry_count = sbi_scratch_offset_ptr(scratch, entry_count_offset);
init_count = sbi_scratch_offset_ptr(scratch, init_count_offset);
*entry_count = *init_count;
}
unsigned long sbi_entry_count(u32 hartindex)
{
struct sbi_scratch *scratch;

View File

@@ -116,11 +116,6 @@ int sbi_ipi_send_many(ulong hmask, ulong hbase, u32 event, void *data)
struct sbi_domain *dom = sbi_domain_thishart_ptr();
struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
if (hmask == 0 && hbase != -1UL) {
/* Nothing to do, but it's not an error either. */
return 0;
}
/* Find the target harts */
rc = sbi_hsm_hart_interruptible_mask(dom, &target_mask);
if (rc)
@@ -128,7 +123,6 @@ int sbi_ipi_send_many(ulong hmask, ulong hbase, u32 event, void *data)
if (hbase != -1UL) {
struct sbi_hartmask tmp_mask = { 0 };
int count = sbi_popcount(hmask);
for (i = hbase; hmask; i++, hmask >>= 1) {
if (hmask & 1UL)
@@ -136,9 +130,6 @@ int sbi_ipi_send_many(ulong hmask, ulong hbase, u32 event, void *data)
}
sbi_hartmask_and(&target_mask, &target_mask, &tmp_mask);
if (sbi_hartmask_weight(&target_mask) != count)
return SBI_EINVAL;
}
/* Send IPIs */

View File

@@ -11,7 +11,6 @@
#include <sbi/sbi_domain.h>
#include <sbi/sbi_error.h>
#include <sbi/sbi_hart.h>
#include <sbi/sbi_heap.h>
#include <sbi/sbi_platform.h>
#include <sbi/sbi_mpxy.h>
#include <sbi/sbi_scratch.h>
@@ -20,8 +19,8 @@
#include <sbi/sbi_console.h>
#include <sbi/sbi_byteorder.h>
/** Shared memory size across all harts */
static unsigned long mpxy_shmem_size = PAGE_SIZE;
/** Offset of pointer to MPXY state in scratch space */
static unsigned long mpxy_state_offset;
/** List of MPXY proxy channels */
static SBI_LIST_HEAD(mpxy_channel_list);
@@ -44,17 +43,17 @@ static SBI_LIST_HEAD(mpxy_channel_list);
#define CAP_EVENTSSTATE_POS 2
#define CAP_EVENTSSTATE_MASK (1U << CAP_EVENTSSTATE_POS)
/** Channel Capability - Send Message With Response function support */
#define CAP_SEND_MSG_WITH_RESP_POS 3
#define CAP_SEND_MSG_WITH_RESP_MASK (1U << CAP_SEND_MSG_WITH_RESP_POS)
/** Channel Capability - Get Notification function support */
#define CAP_GET_NOTIFICATIONS_POS 3
#define CAP_GET_NOTIFICATIONS_MASK (1U << CAP_GET_NOTIFICATIONS_POS)
/** Channel Capability - Send Message Without Response function support */
#define CAP_SEND_MSG_WITHOUT_RESP_POS 4
#define CAP_SEND_MSG_WITHOUT_RESP_MASK (1U << CAP_SEND_MSG_WITHOUT_RESP_POS)
/** Channel Capability - Get Notification function support */
#define CAP_GET_NOTIFICATIONS_POS 5
#define CAP_GET_NOTIFICATIONS_MASK (1U << CAP_GET_NOTIFICATIONS_POS)
/** Channel Capability - Send Message With Response function support */
#define CAP_SEND_MSG_WITH_RESP_POS 5
#define CAP_SEND_MSG_WITH_RESP_MASK (1U << CAP_SEND_MSG_WITH_RESP_POS)
/** Helpers to enable/disable channel capability bits
* _c: capability variable
@@ -64,10 +63,17 @@ static SBI_LIST_HEAD(mpxy_channel_list);
#define CAP_DISABLE(_c, _m) INSERT_FIELD(_c, _m, 0)
#define CAP_GET(_c, _m) EXTRACT_FIELD(_c, _m)
#if __riscv_xlen == 64
#define SHMEM_PHYS_ADDR(_hi, _lo) (_lo)
#elif __riscv_xlen == 32
#define SHMEM_PHYS_ADDR(_hi, _lo) (((u64)(_hi) << 32) | (_lo))
#else
#error "Undefined XLEN"
#endif
/** Per hart shared memory */
struct mpxy_shmem {
unsigned long shmem_size;
unsigned long shmem_addr_lo;
unsigned long shmem_addr_hi;
};
@@ -81,17 +87,10 @@ struct mpxy_state {
struct mpxy_shmem shmem;
};
static struct mpxy_state *sbi_domain_get_mpxy_state(struct sbi_domain *dom,
u32 hartindex);
/** Macro to obtain the current hart's MPXY state pointer in current domain */
#define sbi_domain_mpxy_state_thishart_ptr() \
sbi_domain_get_mpxy_state(sbi_domain_thishart_ptr(), \
current_hartindex())
/** Disable hart shared memory */
static inline void sbi_mpxy_shmem_disable(struct mpxy_state *ms)
{
ms->shmem.shmem_size = 0;
ms->shmem.shmem_addr_lo = INVALID_ADDR;
ms->shmem.shmem_addr_hi = INVALID_ADDR;
}
@@ -171,8 +170,9 @@ bool sbi_mpxy_channel_available(void)
static void mpxy_std_attrs_init(struct sbi_mpxy_channel *channel)
{
struct mpxy_state *ms = sbi_domain_mpxy_state_thishart_ptr();
u32 capability = 0;
struct mpxy_state *ms =
sbi_scratch_thishart_offset_ptr(mpxy_state_offset);
/* Reset values */
channel->attrs.msi_control = 0;
@@ -228,113 +228,37 @@ int sbi_mpxy_register_channel(struct sbi_mpxy_channel *channel)
/* Initialize channel specific attributes */
mpxy_std_attrs_init(channel);
/* Update shared memory size if required */
if (mpxy_shmem_size < channel->attrs.msg_data_maxlen) {
mpxy_shmem_size = channel->attrs.msg_data_maxlen;
mpxy_shmem_size = (mpxy_shmem_size + (PAGE_SIZE - 1)) / PAGE_SIZE;
}
SBI_INIT_LIST_HEAD(&channel->head);
sbi_list_add_tail(&channel->head, &mpxy_channel_list);
return SBI_OK;
}
/** Setup per domain MPXY state data */
static int domain_mpxy_state_data_setup(struct sbi_domain *dom,
struct sbi_domain_data *data,
void *data_ptr)
{
struct mpxy_state **dom_hartindex_to_mpxy_state_table = data_ptr;
struct mpxy_state *ms;
u32 i;
sbi_hartmask_for_each_hartindex(i, dom->possible_harts) {
ms = sbi_zalloc(sizeof(*ms));
if (!ms)
return SBI_ENOMEM;
/*
* TODO: Proper support for checking msi support from
* platform. Currently disable msi and sse and use
* polling
*/
ms->msi_avail = false;
ms->sse_avail = false;
sbi_mpxy_shmem_disable(ms);
dom_hartindex_to_mpxy_state_table[i] = ms;
}
return 0;
}
/** Cleanup per domain MPXY state data */
static void domain_mpxy_state_data_cleanup(struct sbi_domain *dom,
struct sbi_domain_data *data,
void *data_ptr)
{
struct mpxy_state **dom_hartindex_to_mpxy_state_table = data_ptr;
u32 i;
sbi_hartmask_for_each_hartindex(i, dom->possible_harts)
sbi_free(dom_hartindex_to_mpxy_state_table[i]);
}
static struct sbi_domain_data dmspriv = {
.data_setup = domain_mpxy_state_data_setup,
.data_cleanup = domain_mpxy_state_data_cleanup,
};
/**
* Get per-domain MPXY state pointer for a given domain and HART index
* @param dom pointer to domain
* @param hartindex the HART index
*
* @return per-domain MPXY state pointer for given HART index
*/
static struct mpxy_state *sbi_domain_get_mpxy_state(struct sbi_domain *dom,
u32 hartindex)
{
struct mpxy_state **dom_hartindex_to_mpxy_state_table;
dom_hartindex_to_mpxy_state_table = sbi_domain_data_ptr(dom, &dmspriv);
if (!dom_hartindex_to_mpxy_state_table ||
!sbi_hartindex_valid(hartindex))
return NULL;
return dom_hartindex_to_mpxy_state_table[hartindex];
}
int sbi_mpxy_init(struct sbi_scratch *scratch)
{
int ret;
mpxy_state_offset = sbi_scratch_alloc_type_offset(struct mpxy_state);
if (!mpxy_state_offset)
return SBI_ENOMEM;
/**
* Allocate per-domain and per-hart MPXY state data.
* The data type is "struct mpxy_state **" whose memory space will be
* dynamically allocated by domain_setup_data_one() and
* domain_mpxy_state_data_setup(). Calculate needed size of memory space
* here.
* TODO: Proper support for checking msi support from platform.
* Currently disable msi and sse and use polling
*/
dmspriv.data_size = sizeof(struct mpxy_state *) * sbi_hart_count();
ret = sbi_domain_register_data(&dmspriv);
if (ret)
return ret;
struct mpxy_state *ms =
sbi_scratch_thishart_offset_ptr(mpxy_state_offset);
ms->msi_avail = false;
ms->sse_avail = false;
sbi_mpxy_shmem_disable(ms);
return sbi_platform_mpxy_init(sbi_platform_ptr(scratch));
}
unsigned long sbi_mpxy_get_shmem_size(void)
int sbi_mpxy_set_shmem(unsigned long shmem_size, unsigned long shmem_phys_lo,
unsigned long shmem_phys_hi, unsigned long flags)
{
return mpxy_shmem_size;
}
int sbi_mpxy_set_shmem(unsigned long shmem_phys_lo,
unsigned long shmem_phys_hi,
unsigned long flags)
{
struct mpxy_state *ms = sbi_domain_mpxy_state_thishart_ptr();
struct mpxy_state *ms =
sbi_scratch_thishart_offset_ptr(mpxy_state_offset);
unsigned long *ret_buf;
/** Disable shared memory if both hi and lo have all bit 1s */
@@ -348,26 +272,13 @@ int sbi_mpxy_set_shmem(unsigned long shmem_phys_lo,
return SBI_ERR_INVALID_PARAM;
/** Check shared memory size and address aligned to 4K Page */
if (shmem_phys_lo & ~PAGE_MASK)
if (!shmem_size || (shmem_size & ~PAGE_MASK) ||
(shmem_phys_lo & ~PAGE_MASK))
return SBI_ERR_INVALID_PARAM;
/*
* On RV32, the M-mode can only access the first 4GB of
* the physical address space because M-mode does not have
* MMU to access full 34-bit physical address space.
* So fail if the upper 32 bits of the physical address
* is non-zero on RV32.
*
* On RV64, kernel sets upper 64bit address part to zero.
* So fail if the upper 64bit of the physical address
* is non-zero on RV64.
*/
if (shmem_phys_hi)
return SBI_ERR_INVALID_ADDRESS;
if (!sbi_domain_check_addr_range(sbi_domain_thishart_ptr(),
SHMEM_PHYS_ADDR(shmem_phys_hi, shmem_phys_lo),
mpxy_shmem_size, PRV_S,
shmem_size, PRV_S,
SBI_DOMAIN_READ | SBI_DOMAIN_WRITE))
return SBI_ERR_INVALID_ADDRESS;
@@ -375,13 +286,15 @@ int sbi_mpxy_set_shmem(unsigned long shmem_phys_lo,
if (flags == SBI_EXT_MPXY_SHMEM_FLAG_OVERWRITE_RETURN) {
ret_buf = (unsigned long *)(ulong)SHMEM_PHYS_ADDR(shmem_phys_hi,
shmem_phys_lo);
sbi_hart_map_saddr((unsigned long)ret_buf, mpxy_shmem_size);
ret_buf[0] = cpu_to_lle(ms->shmem.shmem_addr_lo);
ret_buf[1] = cpu_to_lle(ms->shmem.shmem_addr_hi);
sbi_hart_map_saddr((unsigned long)ret_buf, shmem_size);
ret_buf[0] = cpu_to_lle(ms->shmem.shmem_size);
ret_buf[1] = cpu_to_lle(ms->shmem.shmem_addr_lo);
ret_buf[2] = cpu_to_lle(ms->shmem.shmem_addr_hi);
sbi_hart_unmap_saddr();
}
/** Setup the new shared memory */
ms->shmem.shmem_size = shmem_size;
ms->shmem.shmem_addr_lo = shmem_phys_lo;
ms->shmem.shmem_addr_hi = shmem_phys_hi;
@@ -390,12 +303,15 @@ int sbi_mpxy_set_shmem(unsigned long shmem_phys_lo,
int sbi_mpxy_get_channel_ids(u32 start_index)
{
struct mpxy_state *ms = sbi_domain_mpxy_state_thishart_ptr();
u32 remaining, returned, max_channelids;
u32 node_index = 0, node_ret = 0;
struct sbi_mpxy_channel *channel;
u32 remaining, returned, max_channelids;
u32 channels_count = 0;
u32 *shmem_base;
struct sbi_mpxy_channel *channel;
/* Check if the shared memory is being setup or not. */
struct mpxy_state *ms =
sbi_scratch_thishart_offset_ptr(mpxy_state_offset);
if (!mpxy_shmem_enabled(ms))
return SBI_ERR_NO_SHMEM;
@@ -407,11 +323,12 @@ int sbi_mpxy_get_channel_ids(u32 start_index)
return SBI_ERR_INVALID_PARAM;
shmem_base = hart_shmem_base(ms);
sbi_hart_map_saddr((unsigned long)hart_shmem_base(ms), mpxy_shmem_size);
sbi_hart_map_saddr((unsigned long)hart_shmem_base(ms),
ms->shmem.shmem_size);
/** number of channel ids which can be stored in shmem adjusting
* for remaining and returned fields */
max_channelids = (mpxy_shmem_size / sizeof(u32)) - 2;
max_channelids = (ms->shmem.shmem_size / sizeof(u32)) - 2;
/* total remaining from the start index */
remaining = channels_count - start_index;
/* how many can be returned */
@@ -441,11 +358,13 @@ int sbi_mpxy_get_channel_ids(u32 start_index)
int sbi_mpxy_read_attrs(u32 channel_id, u32 base_attr_id, u32 attr_count)
{
struct mpxy_state *ms = sbi_domain_mpxy_state_thishart_ptr();
int ret = SBI_SUCCESS;
u32 *attr_ptr, end_id;
void *shmem_base;
struct mpxy_state *ms =
sbi_scratch_thishart_offset_ptr(mpxy_state_offset);
if (!mpxy_shmem_enabled(ms))
return SBI_ERR_NO_SHMEM;
@@ -459,13 +378,14 @@ int sbi_mpxy_read_attrs(u32 channel_id, u32 base_attr_id, u32 attr_count)
return SBI_ERR_INVALID_PARAM;
/* Sanity check for base_attr_id and attr_count */
if (!attr_count || (attr_count > (mpxy_shmem_size / ATTR_SIZE)))
if (!attr_count || (attr_count > (ms->shmem.shmem_size / ATTR_SIZE)))
return SBI_ERR_INVALID_PARAM;
shmem_base = hart_shmem_base(ms);
end_id = base_attr_id + attr_count - 1;
sbi_hart_map_saddr((unsigned long)hart_shmem_base(ms), mpxy_shmem_size);
sbi_hart_map_saddr((unsigned long)hart_shmem_base(ms),
ms->shmem.shmem_size);
/* Standard attributes range check */
if (mpxy_is_std_attr(base_attr_id)) {
@@ -522,8 +442,8 @@ out:
static int mpxy_check_write_std_attr(struct sbi_mpxy_channel *channel,
u32 attr_id, u32 attr_val)
{
struct sbi_mpxy_channel_attrs *attrs = &channel->attrs;
int ret = SBI_SUCCESS;
struct sbi_mpxy_channel_attrs *attrs = &channel->attrs;
switch(attr_id) {
case SBI_MPXY_ATTR_MSI_CONTROL:
@@ -555,9 +475,11 @@ static int mpxy_check_write_std_attr(struct sbi_mpxy_channel *channel,
* Write the attribute value
*/
static void mpxy_write_std_attr(struct sbi_mpxy_channel *channel, u32 attr_id,
u32 attr_val)
u32 attr_val)
{
struct mpxy_state *ms = sbi_domain_mpxy_state_thishart_ptr();
struct mpxy_state *ms =
sbi_scratch_thishart_offset_ptr(mpxy_state_offset);
struct sbi_mpxy_channel_attrs *attrs = &channel->attrs;
switch(attr_id) {
@@ -591,16 +513,17 @@ static void mpxy_write_std_attr(struct sbi_mpxy_channel *channel, u32 attr_id,
int sbi_mpxy_write_attrs(u32 channel_id, u32 base_attr_id, u32 attr_count)
{
struct mpxy_state *ms = sbi_domain_mpxy_state_thishart_ptr();
u32 *mem_ptr, attr_id, end_id, attr_val;
struct sbi_mpxy_channel *channel;
int ret, mem_idx;
void *shmem_base;
u32 *mem_ptr, attr_id, end_id, attr_val;
struct mpxy_state *ms =
sbi_scratch_thishart_offset_ptr(mpxy_state_offset);
if (!mpxy_shmem_enabled(ms))
return SBI_ERR_NO_SHMEM;
channel = mpxy_find_channel(channel_id);
struct sbi_mpxy_channel *channel = mpxy_find_channel(channel_id);
if (!channel)
return SBI_ERR_NOT_SUPPORTED;
@@ -610,13 +533,13 @@ int sbi_mpxy_write_attrs(u32 channel_id, u32 base_attr_id, u32 attr_count)
return SBI_ERR_INVALID_PARAM;
/* Sanity check for base_attr_id and attr_count */
if (!attr_count || (attr_count > (mpxy_shmem_size / ATTR_SIZE)))
if (!attr_count || (attr_count > (ms->shmem.shmem_size / ATTR_SIZE)))
return SBI_ERR_INVALID_PARAM;
shmem_base = hart_shmem_base(ms);
end_id = base_attr_id + attr_count - 1;
sbi_hart_map_saddr((unsigned long)shmem_base, mpxy_shmem_size);
sbi_hart_map_saddr((unsigned long)shmem_base, ms->shmem.shmem_size);
mem_ptr = (u32 *)shmem_base;
@@ -681,16 +604,17 @@ int sbi_mpxy_send_message(u32 channel_id, u8 msg_id,
unsigned long msg_data_len,
unsigned long *resp_data_len)
{
struct mpxy_state *ms = sbi_domain_mpxy_state_thishart_ptr();
struct sbi_mpxy_channel *channel;
int ret;
void *shmem_base, *resp_buf;
u32 resp_bufsize;
int ret;
struct mpxy_state *ms =
sbi_scratch_thishart_offset_ptr(mpxy_state_offset);
if (!mpxy_shmem_enabled(ms))
return SBI_ERR_NO_SHMEM;
channel = mpxy_find_channel(channel_id);
struct sbi_mpxy_channel *channel = mpxy_find_channel(channel_id);
if (!channel)
return SBI_ERR_NOT_SUPPORTED;
@@ -700,23 +624,24 @@ int sbi_mpxy_send_message(u32 channel_id, u8 msg_id,
if (!resp_data_len && !channel->send_message_without_response)
return SBI_ERR_NOT_SUPPORTED;
if (msg_data_len > mpxy_shmem_size ||
if (msg_data_len > ms->shmem.shmem_size ||
msg_data_len > channel->attrs.msg_data_maxlen)
return SBI_ERR_INVALID_PARAM;
shmem_base = hart_shmem_base(ms);
sbi_hart_map_saddr((unsigned long)shmem_base, mpxy_shmem_size);
sbi_hart_map_saddr((unsigned long)shmem_base, ms->shmem.shmem_size);
if (resp_data_len) {
resp_buf = shmem_base;
resp_bufsize = mpxy_shmem_size;
resp_bufsize = ms->shmem.shmem_size;
ret = channel->send_message_with_response(channel, msg_id,
shmem_base,
msg_data_len,
resp_buf,
resp_bufsize,
resp_data_len);
} else {
}
else {
ret = channel->send_message_without_response(channel, msg_id,
shmem_base,
msg_data_len);
@@ -730,7 +655,7 @@ int sbi_mpxy_send_message(u32 channel_id, u8 msg_id,
return SBI_ERR_FAILED;
if (resp_data_len &&
(*resp_data_len > mpxy_shmem_size ||
(*resp_data_len > ms->shmem.shmem_size ||
*resp_data_len > channel->attrs.msg_data_maxlen))
return SBI_ERR_FAILED;
@@ -739,30 +664,34 @@ int sbi_mpxy_send_message(u32 channel_id, u8 msg_id,
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;
int ret;
void *eventsbuf, *shmem_base;
struct mpxy_state *ms =
sbi_scratch_thishart_offset_ptr(mpxy_state_offset);
if (!mpxy_shmem_enabled(ms))
return SBI_ERR_NO_SHMEM;
channel = mpxy_find_channel(channel_id);
if (!channel || !channel->get_notification_events)
struct sbi_mpxy_channel *channel = mpxy_find_channel(channel_id);
if (!channel)
return SBI_ERR_NOT_SUPPORTED;
if (!channel->get_notification_events)
return SBI_ERR_NOT_SUPPORTED;
shmem_base = hart_shmem_base(ms);
sbi_hart_map_saddr((unsigned long)shmem_base, mpxy_shmem_size);
sbi_hart_map_saddr((unsigned long)shmem_base, ms->shmem.shmem_size);
eventsbuf = shmem_base;
ret = channel->get_notification_events(channel, eventsbuf,
mpxy_shmem_size,
ms->shmem.shmem_size,
events_len);
sbi_hart_unmap_saddr();
if (ret)
return ret;
if (*events_len > (mpxy_shmem_size - 16))
if (*events_len > ms->shmem.shmem_size)
return SBI_ERR_FAILED;
return SBI_SUCCESS;

View File

@@ -206,12 +206,6 @@ static int pmu_ctr_validate(struct sbi_pmu_hart_state *phs,
return event_idx_type;
}
static bool pmu_ctr_idx_validate(unsigned long cbase, unsigned long cmask)
{
/* Do a basic sanity check of counter base & mask */
return cmask && cbase + sbi_fls(cmask) < total_ctrs;
}
int sbi_pmu_ctr_fw_read(uint32_t cidx, uint64_t *cval)
{
int event_idx_type;
@@ -315,11 +309,11 @@ int sbi_pmu_add_raw_event_counter_map(uint64_t select, uint64_t select_mask, u32
void sbi_pmu_ovf_irq()
{
/*
* We need to disable the overflow irq before returning to S-mode or we will loop
* on an irq being triggered
* We need to disable LCOFIP before returning to S-mode or we will loop
* on LCOFIP being triggered
*/
csr_clear(CSR_MIE, sbi_pmu_irq_mask());
sbi_sse_inject_event(SBI_SSE_EVENT_LOCAL_PMU_OVERFLOW);
csr_clear(CSR_MIE, MIP_LCOFIP);
sbi_sse_inject_event(SBI_SSE_EVENT_LOCAL_PMU);
}
static int pmu_ctr_enable_irq_hw(int ctr_idx)
@@ -350,7 +344,7 @@ static int pmu_ctr_enable_irq_hw(int ctr_idx)
* Otherwise, there will be race conditions where we may clear the bit
* the software is yet to handle the interrupt.
*/
if (!(mip_val & sbi_pmu_irq_mask())) {
if (!(mip_val & MIP_LCOFIP)) {
mhpmevent_curr &= of_mask;
csr_write_num(mhpmevent_csr, mhpmevent_curr);
}
@@ -411,21 +405,11 @@ int sbi_pmu_irq_bit(void)
struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
if (sbi_hart_has_extension(scratch, SBI_HART_EXT_SSCOFPMF))
return IRQ_PMU_OVF;
return MIP_LCOFIP;
if (pmu_dev && pmu_dev->hw_counter_irq_bit)
return pmu_dev->hw_counter_irq_bit();
return -1;
}
unsigned long sbi_pmu_irq_mask(void)
{
int irq_bit = sbi_pmu_irq_bit();
if (irq_bit < 0)
return 0;
return BIT(irq_bit);
return 0;
}
static int pmu_ctr_start_fw(struct sbi_pmu_hart_state *phs,
@@ -478,7 +462,7 @@ int sbi_pmu_ctr_start(unsigned long cbase, unsigned long cmask,
int i, cidx;
uint64_t edata;
if (!pmu_ctr_idx_validate(cbase, cmask))
if ((cbase + sbi_fls(cmask)) >= total_ctrs)
return ret;
if (flags & SBI_PMU_STOP_FLAG_TAKE_SNAPSHOT)
@@ -583,8 +567,8 @@ int sbi_pmu_ctr_stop(unsigned long cbase, unsigned long cmask,
uint32_t event_code;
int i, cidx;
if (!pmu_ctr_idx_validate(cbase, cmask))
return ret;
if ((cbase + sbi_fls(cmask)) >= total_ctrs)
return SBI_EINVAL;
if (flag & SBI_PMU_STOP_FLAG_TAKE_SNAPSHOT)
return SBI_ENO_SHMEM;
@@ -607,9 +591,9 @@ int sbi_pmu_ctr_stop(unsigned long cbase, unsigned long cmask,
}
}
/* Clear PMU overflow interrupt to avoid spurious ones */
/* Clear MIP_LCOFIP to avoid spurious interrupts */
if (phs->sse_enabled)
csr_clear(CSR_MIP, sbi_pmu_irq_mask());
csr_clear(CSR_MIP, MIP_LCOFIP);
return ret;
}
@@ -738,13 +722,12 @@ static int pmu_ctr_find_hw(struct sbi_pmu_hart_state *phs,
return SBI_EINVAL;
/**
* If Sscofpmf or Andes PMU is present, try to find
* the programmable counter for cycle/instret as well.
* If Sscof is present try to find the programmable counter for
* cycle/instret as well.
*/
fixed_ctr = pmu_ctr_find_fixed_hw(event_idx);
if (fixed_ctr >= 0 &&
!sbi_hart_has_extension(scratch, SBI_HART_EXT_SSCOFPMF) &&
!sbi_hart_has_extension(scratch, SBI_HART_EXT_XANDESPMU))
!sbi_hart_has_extension(scratch, SBI_HART_EXT_SSCOFPMF))
return pmu_fixed_ctr_update_inhibit_bits(fixed_ctr, flags);
if (sbi_hart_priv_version(scratch) >= SBI_HART_PRIV_VER_1_11)
@@ -845,7 +828,8 @@ int sbi_pmu_ctr_cfg_match(unsigned long cidx_base, unsigned long cidx_mask,
int ret, event_type, ctr_idx = SBI_ENOTSUPP;
u32 event_code;
if (!pmu_ctr_idx_validate(cidx_base, cidx_mask))
/* Do a basic sanity check of counter base & mask */
if ((cidx_base + sbi_fls(cidx_mask)) >= total_ctrs)
return SBI_EINVAL;
event_type = pmu_event_validate(phs, event_idx, event_data);
@@ -1102,43 +1086,30 @@ void sbi_pmu_exit(struct sbi_scratch *scratch)
static void pmu_sse_enable(uint32_t event_id)
{
unsigned long irq_mask = sbi_pmu_irq_mask();
struct sbi_pmu_hart_state *phs = pmu_thishart_state_ptr();
csr_set(CSR_MIE, irq_mask);
phs->sse_enabled = true;
csr_clear(CSR_MIDELEG, sbi_pmu_irq_bit());
csr_clear(CSR_MIP, MIP_LCOFIP);
csr_set(CSR_MIE, MIP_LCOFIP);
}
static void pmu_sse_disable(uint32_t event_id)
{
unsigned long irq_mask = sbi_pmu_irq_mask();
struct sbi_pmu_hart_state *phs = pmu_thishart_state_ptr();
csr_clear(CSR_MIE, irq_mask);
csr_clear(CSR_MIP, irq_mask);
csr_clear(CSR_MIE, MIP_LCOFIP);
csr_clear(CSR_MIP, MIP_LCOFIP);
csr_set(CSR_MIDELEG, sbi_pmu_irq_bit());
phs->sse_enabled = false;
}
static void pmu_sse_complete(uint32_t event_id)
{
csr_set(CSR_MIE, sbi_pmu_irq_mask());
}
static void pmu_sse_register(uint32_t event_id)
{
struct sbi_pmu_hart_state *phs = pmu_thishart_state_ptr();
phs->sse_enabled = true;
csr_clear(CSR_MIDELEG, sbi_pmu_irq_mask());
}
static void pmu_sse_unregister(uint32_t event_id)
{
struct sbi_pmu_hart_state *phs = pmu_thishart_state_ptr();
phs->sse_enabled = false;
csr_set(CSR_MIDELEG, sbi_pmu_irq_mask());
csr_set(CSR_MIE, MIP_LCOFIP);
}
static const struct sbi_sse_cb_ops pmu_sse_cb_ops = {
.register_cb = pmu_sse_register,
.unregister_cb = pmu_sse_unregister,
.enable_cb = pmu_sse_enable,
.disable_cb = pmu_sse_disable,
.complete_cb = pmu_sse_complete,
@@ -1181,11 +1152,10 @@ int sbi_pmu_init(struct sbi_scratch *scratch, bool cold_boot)
return SBI_EINVAL;
total_ctrs = num_hw_ctrs + SBI_PMU_FW_CTR_MAX;
if (sbi_pmu_irq_bit() >= 0)
sbi_sse_add_event(SBI_SSE_EVENT_LOCAL_PMU_OVERFLOW, &pmu_sse_cb_ops);
}
sbi_sse_set_cb_ops(SBI_SSE_EVENT_LOCAL_PMU, &pmu_sse_cb_ops);
phs = pmu_get_hart_state_ptr(scratch);
if (!phs) {
phs = sbi_zalloc(sizeof(*phs));

View File

@@ -14,31 +14,18 @@
#include <sbi/sbi_scratch.h>
#include <sbi/sbi_string.h>
#define DEFAULT_SCRATCH_ALLOC_ALIGN __SIZEOF_POINTER__
u32 sbi_scratch_hart_count;
u32 hartindex_to_hartid_table[SBI_HARTMASK_MAX_BITS] = { [0 ... SBI_HARTMASK_MAX_BITS-1] = -1U };
struct sbi_scratch *hartindex_to_scratch_table[SBI_HARTMASK_MAX_BITS];
u32 last_hartindex_having_scratch = 0;
u32 hartindex_to_hartid_table[SBI_HARTMASK_MAX_BITS + 1] = { -1U };
struct sbi_scratch *hartindex_to_scratch_table[SBI_HARTMASK_MAX_BITS + 1] = { 0 };
static spinlock_t extra_lock = SPIN_LOCK_INITIALIZER;
static unsigned long extra_offset = SBI_SCRATCH_EXTRA_SPACE_OFFSET;
/*
* Get the alignment size.
* Return DEFAULT_SCRATCH_ALLOC_ALIGNMENT or riscv,cbom_block_size
*/
static unsigned long sbi_get_scratch_alloc_align(void)
{
const struct sbi_platform *plat = sbi_platform_thishart_ptr();
if (!plat || !plat->cbom_block_size)
return DEFAULT_SCRATCH_ALLOC_ALIGN;
return plat->cbom_block_size;
}
u32 sbi_hartid_to_hartindex(u32 hartid)
{
sbi_for_each_hartindex(i)
u32 i;
for (i = 0; i <= last_hartindex_having_scratch; i++)
if (hartindex_to_hartid_table[i] == hartid)
return i;
@@ -49,30 +36,27 @@ typedef struct sbi_scratch *(*hartid2scratch)(ulong hartid, ulong hartindex);
int sbi_scratch_init(struct sbi_scratch *scratch)
{
u32 h, hart_count;
u32 i, h;
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
hart_count = plat->hart_count;
if (hart_count > SBI_HARTMASK_MAX_BITS)
hart_count = SBI_HARTMASK_MAX_BITS;
sbi_scratch_hart_count = hart_count;
sbi_for_each_hartindex(i) {
for (i = 0; i < plat->hart_count; i++) {
h = (plat->hart_index2id) ? plat->hart_index2id[i] : i;
hartindex_to_hartid_table[i] = h;
hartindex_to_scratch_table[i] =
((hartid2scratch)scratch->hartid_to_scratch)(h, i);
}
last_hartindex_having_scratch = plat->hart_count - 1;
return 0;
}
unsigned long sbi_scratch_alloc_offset(unsigned long size)
{
u32 i;
void *ptr;
unsigned long ret = 0;
struct sbi_scratch *rscratch;
unsigned long scratch_alloc_align = 0;
/*
* We have a simple brain-dead allocator which never expects
@@ -86,14 +70,8 @@ unsigned long sbi_scratch_alloc_offset(unsigned long size)
if (!size)
return 0;
scratch_alloc_align = sbi_get_scratch_alloc_align();
/*
* We let the allocation align to cacheline bytes to avoid livelock on
* certain platforms due to atomic variables from the same cache line.
*/
size += scratch_alloc_align - 1;
size &= ~(scratch_alloc_align - 1);
size += __SIZEOF_POINTER__ - 1;
size &= ~((unsigned long)__SIZEOF_POINTER__ - 1);
spin_lock(&extra_lock);
@@ -107,7 +85,7 @@ done:
spin_unlock(&extra_lock);
if (ret) {
sbi_for_each_hartindex(i) {
for (i = 0; i <= sbi_scratch_last_hartindex(); i++) {
rscratch = sbi_hartindex_to_scratch(i);
if (!rscratch)
continue;

View File

@@ -23,7 +23,6 @@
#include <sbi/sbi_pmu.h>
#include <sbi/sbi_sse.h>
#include <sbi/sbi_scratch.h>
#include <sbi/sbi_slist.h>
#include <sbi/sbi_string.h>
#include <sbi/sbi_trap.h>
@@ -40,11 +39,21 @@
#define EVENT_IS_GLOBAL(__event_id) ((__event_id) & SBI_SSE_EVENT_GLOBAL_BIT)
static const uint32_t supported_events[] = {
SBI_SSE_EVENT_LOCAL_RAS,
SBI_SSE_EVENT_LOCAL_DOUBLE_TRAP,
SBI_SSE_EVENT_GLOBAL_RAS,
SBI_SSE_EVENT_LOCAL_PMU,
SBI_SSE_EVENT_LOCAL_SOFTWARE,
SBI_SSE_EVENT_GLOBAL_SOFTWARE,
};
#define EVENT_COUNT array_size(supported_events)
#define sse_event_invoke_cb(_event, _cb, ...) \
{ \
const struct sbi_sse_cb_ops *__ops = _event->info->cb_ops; \
if (__ops && __ops->_cb) \
__ops->_cb(_event->event_id, ##__VA_ARGS__); \
if (_event->cb_ops && _event->cb_ops->_cb) \
_event->cb_ops->_cb(_event->event_id, ##__VA_ARGS__); \
}
struct sse_entry_state {
@@ -101,7 +110,7 @@ struct sbi_sse_event {
struct sbi_sse_event_attrs attrs;
uint32_t event_id;
u32 hartindex;
struct sse_event_info *info;
const struct sbi_sse_cb_ops *cb_ops;
struct sbi_dlist node;
};
@@ -158,12 +167,6 @@ struct sse_global_event {
spinlock_t lock;
};
struct sse_event_info {
uint32_t event_id;
const struct sbi_sse_cb_ops *cb_ops;
SBI_SLIST_NODE(sse_event_info);
};
static unsigned int local_event_count;
static unsigned int global_event_count;
static struct sse_global_event *global_events;
@@ -177,58 +180,6 @@ static u32 sse_ipi_inject_event = SBI_IPI_EVENT_MAX;
static int sse_ipi_inject_send(unsigned long hartid, uint32_t event_id);
struct sse_event_info global_software_event = {
.event_id = SBI_SSE_EVENT_GLOBAL_SOFTWARE,
SBI_SLIST_NODE_INIT(NULL),
};
struct sse_event_info local_software_event = {
.event_id = SBI_SSE_EVENT_LOCAL_SOFTWARE,
SBI_SLIST_NODE_INIT(&global_software_event),
};
static SBI_SLIST_HEAD(supported_events, sse_event_info) =
SBI_SLIST_HEAD_INIT(&local_software_event);
/*
* This array is used to distinguish between standard event and platform
* events in order to return SBI_ERR_NOT_SUPPORTED for them.
*/
static const uint32_t standard_events[] = {
SBI_SSE_EVENT_LOCAL_HIGH_PRIO_RAS,
SBI_SSE_EVENT_LOCAL_DOUBLE_TRAP,
SBI_SSE_EVENT_GLOBAL_HIGH_PRIO_RAS,
SBI_SSE_EVENT_LOCAL_PMU_OVERFLOW,
SBI_SSE_EVENT_LOCAL_LOW_PRIO_RAS,
SBI_SSE_EVENT_GLOBAL_LOW_PRIO_RAS,
SBI_SSE_EVENT_LOCAL_SOFTWARE,
SBI_SSE_EVENT_GLOBAL_SOFTWARE,
};
static bool sse_is_standard_event(uint32_t event_id)
{
int i;
for (i = 0; i < array_size(standard_events); i++) {
if (event_id == standard_events[i])
return true;
}
return false;
}
static struct sse_event_info *sse_event_info_get(uint32_t event_id)
{
struct sse_event_info *info;
SBI_SLIST_FOR_EACH_ENTRY(info, supported_events) {
if (info->event_id == event_id)
return info;
}
return NULL;
}
static unsigned long sse_event_state(struct sbi_sse_event *e)
{
return e->attrs.status & SBI_SSE_ATTR_STATUS_STATE_MASK;
@@ -293,41 +244,30 @@ static void sse_event_set_state(struct sbi_sse_event *e,
e->attrs.status |= new_state;
}
static int sse_event_get(uint32_t event_id, struct sbi_sse_event **eret)
static struct sbi_sse_event *sse_event_get(uint32_t event_id)
{
unsigned int i;
struct sbi_sse_event *e;
struct sse_hart_state *shs;
if (!eret)
return SBI_EINVAL;
if (EVENT_IS_GLOBAL(event_id)) {
for (i = 0; i < global_event_count; i++) {
e = &global_events[i].event;
if (e->event_id == event_id) {
spin_lock(&global_events[i].lock);
*eret = e;
return SBI_SUCCESS;
return e;
}
}
} else {
shs = sse_thishart_state_ptr();
for (i = 0; i < local_event_count; i++) {
e = &shs->local_events[i];
if (e->event_id == event_id) {
*eret = e;
return SBI_SUCCESS;
}
if (e->event_id == event_id)
return e;
}
}
/* Check if the event is a standard one but not supported */
if (sse_is_standard_event(event_id))
return SBI_ENOTSUPP;
/* If not supported nor a standard event, it is invalid */
return SBI_EINVAL;
return NULL;
}
static void sse_event_put(struct sbi_sse_event *e)
@@ -388,7 +328,7 @@ static int sse_event_set_hart_id_check(struct sbi_sse_event *e,
struct sbi_domain *hd = sbi_domain_thishart_ptr();
if (!sse_event_is_global(e))
return SBI_EDENIED;
return SBI_EBAD_RANGE;
if (!sbi_domain_is_assigned_hart(hd, sbi_hartid_to_hartindex(hartid)))
return SBI_EINVAL;
@@ -427,12 +367,10 @@ static int sse_event_set_attr_check(struct sbi_sse_event *e, uint32_t attr_id,
return sse_event_set_hart_id_check(e, val);
case SBI_SSE_ATTR_INTERRUPTED_FLAGS:
if (val & ~(SBI_SSE_ATTR_INTERRUPTED_FLAGS_SSTATUS_SPP |
SBI_SSE_ATTR_INTERRUPTED_FLAGS_SSTATUS_SPIE |
if (val & ~(SBI_SSE_ATTR_INTERRUPTED_FLAGS_STATUS_SPP |
SBI_SSE_ATTR_INTERRUPTED_FLAGS_STATUS_SPIE |
SBI_SSE_ATTR_INTERRUPTED_FLAGS_HSTATUS_SPV |
SBI_SSE_ATTR_INTERRUPTED_FLAGS_HSTATUS_SPVP |
SBI_SSE_ATTR_INTERRUPTED_FLAGS_SSTATUS_SPELP |
SBI_SSE_ATTR_INTERRUPTED_FLAGS_SSTATUS_SDT))
SBI_SSE_ATTR_INTERRUPTED_FLAGS_HSTATUS_SPVP))
return SBI_EINVAL;
__attribute__((__fallthrough__));
case SBI_SSE_ATTR_INTERRUPTED_SEPC:
@@ -446,13 +384,7 @@ static int sse_event_set_attr_check(struct sbi_sse_event *e, uint32_t attr_id,
return SBI_OK;
default:
/*
* Attribute range validity was already checked by
* sbi_sse_attr_check(). If we end up here, attribute was not
* handled by the above 'case' statements and thus it is
* read-only.
*/
return SBI_EDENIED;
return SBI_EBAD_RANGE;
}
}
@@ -520,14 +452,10 @@ static unsigned long sse_interrupted_flags(unsigned long mstatus)
{
unsigned long hstatus, flags = 0;
if (mstatus & MSTATUS_SPIE)
flags |= SBI_SSE_ATTR_INTERRUPTED_FLAGS_SSTATUS_SPIE;
if (mstatus & MSTATUS_SPP)
flags |= SBI_SSE_ATTR_INTERRUPTED_FLAGS_SSTATUS_SPP;
if (mstatus & MSTATUS_SPELP)
flags |= SBI_SSE_ATTR_INTERRUPTED_FLAGS_SSTATUS_SPELP;
if (mstatus & MSTATUS_SDT)
flags |= SBI_SSE_ATTR_INTERRUPTED_FLAGS_SSTATUS_SDT;
if (mstatus & (MSTATUS_SPIE))
flags |= SBI_SSE_ATTR_INTERRUPTED_FLAGS_STATUS_SPIE;
if (mstatus & (MSTATUS_SPP))
flags |= SBI_SSE_ATTR_INTERRUPTED_FLAGS_STATUS_SPP;
if (misa_extension('H')) {
hstatus = csr_read(CSR_HSTATUS);
@@ -585,13 +513,9 @@ static void sse_event_inject(struct sbi_sse_event *e,
regs->a7 = e->attrs.entry.arg;
regs->mepc = e->attrs.entry.pc;
/*
* Return to S-mode with virtualization disabled, not expected landing
* pad, supervisor trap disabled.
*/
regs->mstatus &= ~(MSTATUS_MPP | MSTATUS_SIE | MSTATUS_SPELP);
/* Return to S-mode with virtualization disabled */
regs->mstatus &= ~(MSTATUS_MPP | MSTATUS_SIE);
regs->mstatus |= (PRV_S << MSTATUS_MPP_SHIFT);
regs->mstatus |= MSTATUS_SDT;
#if __riscv_xlen == 64
regs->mstatus &= ~MSTATUS_MPV;
@@ -642,21 +566,13 @@ static void sse_event_resume(struct sbi_sse_event *e,
regs->mstatus |= MSTATUS_SIE;
regs->mstatus &= ~MSTATUS_SPIE;
if (i_ctx->flags & SBI_SSE_ATTR_INTERRUPTED_FLAGS_SSTATUS_SPIE)
if (i_ctx->flags & SBI_SSE_ATTR_INTERRUPTED_FLAGS_STATUS_SPIE)
regs->mstatus |= MSTATUS_SPIE;
regs->mstatus &= ~MSTATUS_SPP;
if (i_ctx->flags & SBI_SSE_ATTR_INTERRUPTED_FLAGS_SSTATUS_SPP)
if (i_ctx->flags & SBI_SSE_ATTR_INTERRUPTED_FLAGS_STATUS_SPP)
regs->mstatus |= MSTATUS_SPP;
regs->mstatus &= ~MSTATUS_SPELP;
if (i_ctx->flags & SBI_SSE_ATTR_INTERRUPTED_FLAGS_SSTATUS_SPELP)
regs->mstatus |= MSTATUS_SPELP;
regs->mstatus &= ~MSTATUS_SDT;
if (i_ctx->flags & SBI_SSE_ATTR_INTERRUPTED_FLAGS_SSTATUS_SDT)
regs->mstatus |= MSTATUS_SDT;
regs->a7 = i_ctx->a7;
regs->a6 = i_ctx->a6;
csr_write(CSR_SEPC, i_ctx->sepc);
@@ -737,7 +653,8 @@ static void sse_ipi_inject_process(struct sbi_scratch *scratch)
/* Mark all queued events as pending */
while (!sbi_fifo_dequeue(sse_inject_fifo_r, &evt)) {
if (sse_event_get(evt.event_id, &e))
e = sse_event_get(evt.event_id);
if (!e)
continue;
sse_event_set_pending(e);
@@ -779,9 +696,10 @@ static int sse_inject_event(uint32_t event_id, unsigned long hartid)
int ret;
struct sbi_sse_event *e;
ret = sse_event_get(event_id, &e);
if (ret)
return ret;
e = sse_event_get(event_id);
if (!e)
return SBI_EINVAL;
/* In case of global event, provided hart_id is ignored */
if (sse_event_is_global(e))
@@ -870,9 +788,9 @@ int sbi_sse_enable(uint32_t event_id)
int ret;
struct sbi_sse_event *e;
ret = sse_event_get(event_id, &e);
if (ret)
return ret;
e = sse_event_get(event_id);
if (!e)
return SBI_EINVAL;
sse_enabled_event_lock(e);
ret = sse_event_enable(e);
@@ -887,9 +805,9 @@ int sbi_sse_disable(uint32_t event_id)
int ret;
struct sbi_sse_event *e;
ret = sse_event_get(event_id, &e);
if (ret)
return ret;
e = sse_event_get(event_id);
if (!e)
return SBI_EINVAL;
sse_enabled_event_lock(e);
ret = sse_event_disable(e);
@@ -908,7 +826,7 @@ int sbi_sse_hart_mask(void)
return SBI_EFAIL;
if (state->masked)
return SBI_EALREADY_STOPPED;
return SBI_EALREADY_STARTED;
state->masked = true;
@@ -923,7 +841,7 @@ int sbi_sse_hart_unmask(void)
return SBI_EFAIL;
if (!state->masked)
return SBI_EALREADY_STARTED;
return SBI_EALREADY_STOPPED;
state->masked = false;
@@ -945,26 +863,19 @@ int sbi_sse_inject_event(uint32_t event_id)
return sse_inject_event(event_id, current_hartid());
}
int sbi_sse_add_event(uint32_t event_id, const struct sbi_sse_cb_ops *cb_ops)
int sbi_sse_set_cb_ops(uint32_t event_id, const struct sbi_sse_cb_ops *cb_ops)
{
struct sse_event_info *info;
struct sbi_sse_event *e;
/* Do not allow adding an event twice */
info = sse_event_info_get(event_id);
if (info)
return SBI_EALREADY;
if (cb_ops && cb_ops->set_hartid_cb && !EVENT_IS_GLOBAL(event_id))
if (cb_ops->set_hartid_cb && !EVENT_IS_GLOBAL(event_id))
return SBI_EINVAL;
info = sbi_zalloc(sizeof(*info));
if (!info)
return SBI_ENOMEM;
e = sse_event_get(event_id);
if (!e)
return SBI_EINVAL;
info->cb_ops = cb_ops;
info->event_id = event_id;
SBI_SLIST_ADD(info, supported_events);
e->cb_ops = cb_ops;
sse_event_put(e);
return SBI_OK;
}
@@ -1032,9 +943,9 @@ int sbi_sse_read_attrs(uint32_t event_id, uint32_t base_attr_id,
if (ret)
return ret;
ret = sse_event_get(event_id, &e);
if (ret)
return ret;
e = sse_event_get(event_id);
if (!e)
return SBI_EINVAL;
sbi_hart_map_saddr(output_phys_lo, sizeof(unsigned long) * attr_count);
@@ -1097,9 +1008,9 @@ int sbi_sse_write_attrs(uint32_t event_id, uint32_t base_attr_id,
if (ret)
return ret;
ret = sse_event_get(event_id, &e);
if (ret)
return ret;
e = sse_event_get(event_id);
if (!e)
return SBI_EINVAL;
ret = sse_write_attrs(e, base_attr_id, attr_count, input_phys_lo);
sse_event_put(e);
@@ -1122,9 +1033,9 @@ int sbi_sse_register(uint32_t event_id, unsigned long handler_entry_pc,
SBI_DOMAIN_EXECUTE))
return SBI_EINVALID_ADDR;
ret = sse_event_get(event_id, &e);
if (ret)
return ret;
e = sse_event_get(event_id);
if (!e)
return SBI_EINVAL;
ret = sse_event_register(e, handler_entry_pc, handler_entry_arg);
sse_event_put(e);
@@ -1137,9 +1048,9 @@ int sbi_sse_unregister(uint32_t event_id)
int ret;
struct sbi_sse_event *e;
ret = sse_event_get(event_id, &e);
if (ret)
return ret;
e = sse_event_get(event_id);
if (!e)
return SBI_EINVAL;
ret = sse_event_unregister(e);
sse_event_put(e);
@@ -1147,10 +1058,9 @@ int sbi_sse_unregister(uint32_t event_id)
return ret;
}
static void sse_event_init(struct sbi_sse_event *e, struct sse_event_info *info)
static void sse_event_init(struct sbi_sse_event *e, uint32_t event_id)
{
e->event_id = info->event_id;
e->info = info;
e->event_id = event_id;
e->hartindex = current_hartindex();
e->attrs.hartid = current_hartid();
/* Declare all events as injectable */
@@ -1159,10 +1069,10 @@ static void sse_event_init(struct sbi_sse_event *e, struct sse_event_info *info)
static void sse_event_count_init()
{
struct sse_event_info *info;
unsigned int i;
SBI_SLIST_FOR_EACH_ENTRY(info, supported_events) {
if (EVENT_IS_GLOBAL(info->event_id))
for (i = 0; i < EVENT_COUNT; i++) {
if (EVENT_IS_GLOBAL(supported_events[i]))
global_event_count++;
else
local_event_count++;
@@ -1172,19 +1082,18 @@ static void sse_event_count_init()
static int sse_global_init()
{
struct sbi_sse_event *e;
unsigned int ev = 0;
struct sse_event_info *info;
unsigned int i, ev = 0;
global_events = sbi_zalloc(sizeof(*global_events) * global_event_count);
if (!global_events)
return SBI_ENOMEM;
SBI_SLIST_FOR_EACH_ENTRY(info, supported_events) {
if (!EVENT_IS_GLOBAL(info->event_id))
for (i = 0; i < EVENT_COUNT; i++) {
if (!EVENT_IS_GLOBAL(supported_events[i]))
continue;
e = &global_events[ev].event;
sse_event_init(e, info);
sse_event_init(e, supported_events[i]);
SPIN_LOCK_INIT(global_events[ev].lock);
ev++;
@@ -1195,16 +1104,16 @@ static int sse_global_init()
static void sse_local_init(struct sse_hart_state *shs)
{
unsigned int ev = 0;
struct sse_event_info *info;
unsigned int i, ev = 0;
SBI_INIT_LIST_HEAD(&shs->enabled_event_list);
SPIN_LOCK_INIT(shs->enabled_event_lock);
SBI_SLIST_FOR_EACH_ENTRY(info, supported_events) {
if (EVENT_IS_GLOBAL(info->event_id))
for (i = 0; i < EVENT_COUNT; i++) {
if (EVENT_IS_GLOBAL(supported_events[i]))
continue;
sse_event_init(&shs->local_events[ev++], info);
sse_event_init(&shs->local_events[ev++], supported_events[i]);
}
}
@@ -1234,8 +1143,7 @@ int sbi_sse_init(struct sbi_scratch *scratch, bool cold_boot)
}
sse_inject_fifo_mem_off = sbi_scratch_alloc_offset(
(global_event_count + local_event_count) *
sizeof(struct sse_ipi_inject_data));
EVENT_COUNT * sizeof(struct sse_ipi_inject_data));
if (!sse_inject_fifo_mem_off) {
sbi_scratch_free_offset(sse_inject_fifo_off);
sbi_scratch_free_offset(shs_ptr_off);
@@ -1272,8 +1180,7 @@ int sbi_sse_init(struct sbi_scratch *scratch, bool cold_boot)
sse_inject_mem =
sbi_scratch_offset_ptr(scratch, sse_inject_fifo_mem_off);
sbi_fifo_init(sse_inject_q, sse_inject_mem,
(global_event_count + local_event_count),
sbi_fifo_init(sse_inject_q, sse_inject_mem, EVENT_COUNT,
sizeof(struct sse_ipi_inject_data));
return 0;
@@ -1281,18 +1188,21 @@ int sbi_sse_init(struct sbi_scratch *scratch, bool cold_boot)
void sbi_sse_exit(struct sbi_scratch *scratch)
{
int i;
struct sbi_sse_event *e;
struct sse_event_info *info;
SBI_SLIST_FOR_EACH_ENTRY(info, supported_events) {
if (sse_event_get(info->event_id, &e))
for (i = 0; i < EVENT_COUNT; i++) {
e = sse_event_get(supported_events[i]);
if (!e)
continue;
if (e->attrs.hartid != current_hartid())
goto skip;
if (sse_event_state(e) > SBI_SSE_STATE_REGISTERED)
if (sse_event_state(e) > SBI_SSE_STATE_REGISTERED) {
sbi_printf("Event %d in invalid state at exit", i);
sse_event_set_state(e, SBI_SSE_STATE_UNUSED);
}
skip:
sse_event_put(e);

View File

@@ -68,22 +68,22 @@ char *sbi_strcpy(char *dest, const char *src)
{
char *ret = dest;
while ((*dest++ = *src++) != '\0') {
while (*src != '\0') {
*dest++ = *src++;
}
return ret;
}
char *sbi_strncpy(char *dest, const char *src, size_t count)
{
char *tmp = dest;
char *ret = dest;
while (count) {
if ((*tmp = *src) != 0)
src++;
tmp++;
count--;
while (count-- && *src != '\0') {
*dest++ = *src++;
}
return dest;
return ret;
}
char *sbi_strchr(const char *s, int c)

View File

@@ -139,7 +139,12 @@ void sbi_timer_event_start(u64 next_event)
* the older software to leverage sstc extension on newer hardware.
*/
if (sbi_hart_has_extension(sbi_scratch_thishart_ptr(), SBI_HART_EXT_SSTC)) {
csr_write64(CSR_STIMECMP, next_event);
#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);
@@ -185,7 +190,7 @@ int sbi_timer_init(struct sbi_scratch *scratch, bool cold_boot)
if (!time_delta_off)
return SBI_ENOMEM;
if (sbi_hart_has_csr(scratch, SBI_HART_CSR_TIME))
if (sbi_hart_has_extension(scratch, SBI_HART_EXT_ZICNTR))
get_time_val = get_ticks;
ret = sbi_platform_timer_init(plat);

View File

@@ -79,12 +79,15 @@ static void sbi_tlb_local_hfence_gvma(struct sbi_tlb_info *tinfo)
static void sbi_tlb_local_sfence_vma(struct sbi_tlb_info *tinfo)
{
#ifndef CONFIG_THEAD_C9XX_ERRATA_JTLB
unsigned long start = tinfo->start;
unsigned long size = tinfo->size;
unsigned long i;
#endif
sbi_pmu_ctr_incr_fw(SBI_PMU_FW_SFENCE_VMA_RCVD);
#ifndef CONFIG_THEAD_C9XX_ERRATA_JTLB
if ((start == 0 && size == 0) || (size == SBI_TLB_FLUSH_ALL)) {
tlb_flush_all();
return;
@@ -96,6 +99,10 @@ static void sbi_tlb_local_sfence_vma(struct sbi_tlb_info *tinfo)
: "r"(start + i)
: "memory");
}
#else
tlb_flush_all();
return;
#endif
}
static void sbi_tlb_local_hfence_vvma_asid(struct sbi_tlb_info *tinfo)
@@ -148,7 +155,9 @@ static void sbi_tlb_local_sfence_vma_asid(struct sbi_tlb_info *tinfo)
unsigned long start = tinfo->start;
unsigned long size = tinfo->size;
unsigned long asid = tinfo->asid;
#ifndef CONFIG_THEAD_C9XX_ERRATA_JTLB
unsigned long i;
#endif
sbi_pmu_ctr_incr_fw(SBI_PMU_FW_SFENCE_VMA_ASID_RCVD);
@@ -161,12 +170,20 @@ static void sbi_tlb_local_sfence_vma_asid(struct sbi_tlb_info *tinfo)
return;
}
#ifndef CONFIG_THEAD_C9XX_ERRATA_JTLB
for (i = 0; i < size; i += PAGE_SIZE) {
__asm__ __volatile__("sfence.vma %0, %1"
:
: "r"(start + i), "r"(asid)
: "memory");
}
#else
__asm__ __volatile__("sfence.vma x0, %0"
:
: "r"(asid)
: "memory");
#endif
}
static void sbi_tlb_local_fence_i(struct sbi_tlb_info *tinfo)

View File

@@ -11,7 +11,6 @@
#include <sbi/riscv_encoding.h>
#include <sbi/sbi_bitops.h>
#include <sbi/sbi_console.h>
#include <sbi/sbi_double_trap.h>
#include <sbi/sbi_ecall.h>
#include <sbi/sbi_error.h>
#include <sbi/sbi_hart.h>
@@ -169,7 +168,7 @@ int sbi_trap_redirect(struct sbi_trap_regs *regs,
csr_write(CSR_VSCAUSE, trap->cause);
/* Set MEPC to VS-mode exception vector base */
regs->mepc = csr_read(CSR_VSTVEC) & ~MTVEC_MODE;
regs->mepc = csr_read(CSR_VSTVEC);
/* Set MPP to VS-mode */
regs->mstatus &= ~MSTATUS_MPP;
@@ -204,7 +203,7 @@ int sbi_trap_redirect(struct sbi_trap_regs *regs,
csr_write(CSR_SCAUSE, trap->cause);
/* Set MEPC to S-mode exception vector base */
regs->mepc = csr_read(CSR_STVEC) & ~MTVEC_MODE;
regs->mepc = csr_read(CSR_STVEC);
/* Set MPP to S-mode */
regs->mstatus &= ~MSTATUS_MPP;
@@ -240,13 +239,12 @@ static int sbi_trap_nonaia_irq(unsigned long irq)
case IRQ_M_SOFT:
sbi_ipi_process();
break;
case IRQ_PMU_OVF:
sbi_pmu_ovf_irq();
break;
case IRQ_M_EXT:
return sbi_irqchip_process();
default:
if (irq == sbi_pmu_irq_bit()) {
sbi_pmu_ovf_irq();
return 0;
}
return SBI_ENOENT;
}
@@ -267,17 +265,15 @@ static int sbi_trap_aia_irq(void)
case IRQ_M_SOFT:
sbi_ipi_process();
break;
case IRQ_PMU_OVF:
sbi_pmu_ovf_irq();
break;
case IRQ_M_EXT:
rc = sbi_irqchip_process();
if (rc)
return rc;
break;
default:
if (mtopi == sbi_pmu_irq_bit()) {
sbi_pmu_ovf_irq();
break;
}
return SBI_ENOENT;
}
}

View File

@@ -14,10 +14,4 @@ carray-sbi_unit_tests-$(CONFIG_SBIUNIT) += locks_test_suite
libsbi-objs-$(CONFIG_SBIUNIT) += tests/riscv_locks_test.o
carray-sbi_unit_tests-$(CONFIG_SBIUNIT) += math_test_suite
libsbi-objs-$(CONFIG_SBIUNIT) += tests/sbi_math_test.o
carray-sbi_unit_tests-$(CONFIG_SBIUNIT) += ecall_test_suite
libsbi-objs-$(CONFIG_SBIUNIT) += tests/sbi_ecall_test.o
carray-sbi_unit_tests-$(CONFIG_SBIUNIT) += bitops_test_suite
libsbi-objs-$(CONFIG_SBIUNIT) += tests/sbi_bitops_test.o
libsbi-objs-$(CONFIG_SBIUNIT) += tests/sbi_math_test.o

View File

@@ -1,135 +0,0 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright 2025 Beijing ESWIN Computing Technology Co., Ltd.
*
* Author: Dongdong Zhang <zhangdongdong@eswincomputing.com>
*/
#include <sbi/sbi_bitops.h>
#include <sbi/sbi_unit_test.h>
#define BPL BITS_PER_LONG
unsigned long bits_to_search = 64;
static unsigned long ffb1[] = {};
static unsigned long ffb2[] = { 0 };
static unsigned long ffb3[] = { 1 };
static unsigned long ffb4[] = { 1UL << (BPL - 1) };
static unsigned long ffb5[] = { 0, 0x10 };
static unsigned long ffb6[] = { 0, 0, 1UL << (BPL - 1) };
static unsigned long ffb7[] = { 0, 0, 0, 0x01 };
static void find_first_bit_test(struct sbiunit_test_case *test)
{
SBIUNIT_EXPECT_EQ(test, find_first_bit(ffb1, 0), 0);
SBIUNIT_EXPECT_EQ(test, find_first_bit(ffb2, BPL), BPL);
SBIUNIT_EXPECT_EQ(test, find_first_bit(ffb3, BPL), 0);
SBIUNIT_EXPECT_EQ(test, find_first_bit(ffb4, BPL), BPL - 1);
SBIUNIT_EXPECT_EQ(test, find_first_bit(ffb5, 2 * BPL), BPL + 4);
SBIUNIT_EXPECT_EQ(test, find_first_bit(ffb6, 3 * BPL),
2 * BPL + BPL - 1);
SBIUNIT_EXPECT_EQ(test, find_first_bit(ffb7, 4 * BPL), 3 * BPL);
}
static unsigned long ffzb1[] = {};
static unsigned long ffzb2[] = { ~0UL };
static unsigned long ffzb3[] = { ~1UL };
static unsigned long ffzb4[] = { ~(1UL << (BPL - 1)) };
static unsigned long ffzb5[] = { ~0UL, ~0x10UL };
static unsigned long ffzb6[] = { ~0UL, ~0UL, ~(1UL << (BPL - 1)) };
static unsigned long ffzb7[] = { ~0UL, ~0UL, ~0UL, ~0x01UL };
static void find_first_zero_bit_test(struct sbiunit_test_case *test)
{
SBIUNIT_ASSERT_EQ(test, find_first_zero_bit(ffzb1, 0), 0);
SBIUNIT_ASSERT_EQ(test, find_first_zero_bit(ffzb2, BPL), BPL);
SBIUNIT_ASSERT_EQ(test, find_first_zero_bit(ffzb3, BPL), 0);
SBIUNIT_ASSERT_EQ(test, find_first_zero_bit(ffzb4, BPL), BPL - 1);
SBIUNIT_ASSERT_EQ(test, find_first_zero_bit(ffzb5, 2 * BPL), BPL + 4);
SBIUNIT_ASSERT_EQ(test, find_first_zero_bit(ffzb6, 3 * BPL),
2 * BPL + BPL - 1);
SBIUNIT_ASSERT_EQ(test, find_first_zero_bit(ffzb7, 4 * BPL), 3 * BPL);
}
static unsigned long flb1[] = {};
static unsigned long flb2[] = { 0 };
static unsigned long flb3[] = { 1 };
static unsigned long flb4[] = { 1UL << (BPL - 1) };
static unsigned long flb5[] = { 0, 0x10 };
static unsigned long flb6[] = { 0, 0, 1UL << (BPL - 1) };
static unsigned long flb7[] = { 0, 0, 0, 0x01 };
static void find_last_bit_test(struct sbiunit_test_case *test)
{
SBIUNIT_EXPECT_EQ(test, find_last_bit(flb1, 0), 0);
SBIUNIT_EXPECT_EQ(test, find_last_bit(flb2, BPL), BPL);
SBIUNIT_EXPECT_EQ(test, find_last_bit(flb3, BPL), 0);
SBIUNIT_EXPECT_EQ(test, find_last_bit(flb4, BPL), BPL - 1);
SBIUNIT_EXPECT_EQ(test, find_last_bit(flb5, 2 * BPL), BPL + 4);
SBIUNIT_EXPECT_EQ(test, find_last_bit(flb6, 3 * BPL),
2 * BPL + BPL - 1);
SBIUNIT_EXPECT_EQ(test, find_last_bit(flb7, 4 * BPL), 3 * BPL);
}
static unsigned long fnb1[] = {};
static unsigned long fnb2[] = { 0 };
static unsigned long fnb3[] = { 1 };
static unsigned long fnb4[] = { 1UL << (BPL - 1) };
static unsigned long fnb5[] = { 0, 0x10 };
static unsigned long fnb6[] = { 0, 0, 1UL << (BPL - 1) };
static unsigned long fnb7[] = { 0, 0, 0, 0x01 };
static void find_next_bit_test(struct sbiunit_test_case *test)
{
SBIUNIT_EXPECT_EQ(test, find_next_bit(fnb1, 0, 0), 0);
SBIUNIT_EXPECT_EQ(test, find_next_bit(fnb2, BPL, 0), BPL);
SBIUNIT_EXPECT_EQ(test, find_next_bit(fnb3, BPL, 0), 0);
SBIUNIT_EXPECT_EQ(test, find_next_bit(fnb4, BPL, 0), BPL - 1);
SBIUNIT_EXPECT_EQ(test, find_next_bit(fnb5, 2 * BPL, 0), BPL + 4);
SBIUNIT_EXPECT_EQ(test, find_next_bit(fnb6, 3 * BPL, 0),
2 * BPL + BPL - 1);
SBIUNIT_EXPECT_EQ(test, find_next_bit(fnb7, 4 * BPL, 0), 3 * BPL);
SBIUNIT_EXPECT_EQ(test, find_next_bit(fnb5, 2 * BPL, BPL), BPL + 4);
SBIUNIT_EXPECT_EQ(test, find_next_bit(fnb7, 4 * BPL, 3 * BPL), 3 * BPL);
SBIUNIT_EXPECT_EQ(test, find_next_bit(fnb6, 3 * BPL, BPL),
2 * BPL + BPL - 1);
}
static unsigned long fnzb1[] = {};
static unsigned long fnzb2[] = { ~0UL };
static unsigned long fnzb3[] = { ~1UL };
static unsigned long fnzb4[] = { ~(1UL << (BPL - 1)) };
static unsigned long fnzb5[] = { ~0UL, ~0x10UL };
static unsigned long fnzb6[] = { ~0UL, ~0UL, ~(1UL << (BPL - 1)) };
static unsigned long fnzb7[] = { ~0UL, ~0UL, ~0UL, ~0x01UL };
static void find_next_zero_bit_test(struct sbiunit_test_case *test)
{
SBIUNIT_EXPECT_EQ(test, find_next_zero_bit(fnzb1, 0, 0), 0);
SBIUNIT_EXPECT_EQ(test, find_next_zero_bit(fnzb2, BPL, 0), BPL);
SBIUNIT_EXPECT_EQ(test, find_next_zero_bit(fnzb3, BPL, 0), 0);
SBIUNIT_EXPECT_EQ(test, find_next_zero_bit(fnzb4, BPL, 0), BPL - 1);
SBIUNIT_EXPECT_EQ(test, find_next_zero_bit(fnzb5, 2 * BPL, 0), BPL + 4);
SBIUNIT_EXPECT_EQ(test, find_next_zero_bit(fnzb6, 3 * BPL, 0),
2 * BPL + BPL - 1);
SBIUNIT_EXPECT_EQ(test, find_next_zero_bit(fnzb7, 4 * BPL, 0), 3 * BPL);
SBIUNIT_EXPECT_EQ(test, find_next_zero_bit(fnzb5, 2 * BPL, BPL),
BPL + 4);
SBIUNIT_EXPECT_EQ(test, find_next_zero_bit(fnzb7, 4 * BPL, 3 * BPL),
3 * BPL);
SBIUNIT_EXPECT_EQ(test, find_next_zero_bit(fnzb6, 3 * BPL, BPL),
2 * BPL + BPL - 1);
}
static struct sbiunit_test_case bitops_test_cases[] = {
SBIUNIT_TEST_CASE(find_first_bit_test),
SBIUNIT_TEST_CASE(find_first_zero_bit_test),
SBIUNIT_TEST_CASE(find_last_bit_test),
SBIUNIT_TEST_CASE(find_next_bit_test),
SBIUNIT_TEST_CASE(find_next_zero_bit_test),
SBIUNIT_END_CASE,
};
SBIUNIT_TEST_SUITE(bitops_test_suite, bitops_test_cases);

View File

@@ -1,50 +0,0 @@
#include <sbi/sbi_unit_test.h>
#include <sbi/sbi_ecall.h>
#include <sbi/sbi_ecall_interface.h>
static void test_sbi_ecall_version(struct sbiunit_test_case *test)
{
SBIUNIT_EXPECT_EQ(test, sbi_ecall_version_major(), SBI_ECALL_VERSION_MAJOR);
SBIUNIT_EXPECT_EQ(test, sbi_ecall_version_minor(), SBI_ECALL_VERSION_MINOR);
}
static void test_sbi_ecall_impid(struct sbiunit_test_case *test)
{
unsigned long old_impid = sbi_ecall_get_impid();
sbi_ecall_set_impid(42);
SBIUNIT_EXPECT_EQ(test, sbi_ecall_get_impid(), 42);
sbi_ecall_set_impid(old_impid);
}
static int dummy_handler(unsigned long extid, unsigned long funcid,
struct sbi_trap_regs *regs,
struct sbi_ecall_return *out)
{
return 0;
}
static void test_sbi_ecall_register_find_extension(struct sbiunit_test_case *test)
{
struct sbi_ecall_extension test_ext = {
/* Use experimental extension space for no overlap */
.extid_start = SBI_EXT_EXPERIMENTAL_START,
.extid_end = SBI_EXT_EXPERIMENTAL_START,
.name = "TestExt",
.handle = dummy_handler,
};
SBIUNIT_EXPECT_EQ(test, sbi_ecall_register_extension(&test_ext), 0);
SBIUNIT_EXPECT_EQ(test, sbi_ecall_find_extension(SBI_EXT_EXPERIMENTAL_START), &test_ext);
sbi_ecall_unregister_extension(&test_ext);
SBIUNIT_EXPECT_EQ(test, sbi_ecall_find_extension(SBI_EXT_EXPERIMENTAL_START), NULL);
}
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_END_CASE,
};
SBIUNIT_TEST_SUITE(ecall_test_suite, ecall_tests);

View File

@@ -34,4 +34,6 @@ source "$(OPENSBI_SRC_DIR)/lib/utils/timer/Kconfig"
source "$(OPENSBI_SRC_DIR)/lib/utils/mpxy/Kconfig"
source "$(OPENSBI_SRC_DIR)/lib/utils/clk/Kconfig"
endmenu

18
lib/utils/clk/Kconfig Normal file
View File

@@ -0,0 +1,18 @@
# SPDX-License-Identifier: BSD-2-Clause
menu "Clock Support"
config FDT_CLK
bool "FDT based CLK drivers"
depends on FDT
default n
if FDT_CLK
config FDT_CLK_SG2044
bool "SG2044 clock drivers"
default n
endif
endmenu

18
lib/utils/clk/fdt_clk.c Normal file
View File

@@ -0,0 +1,18 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2025 Sophgo Inc.
*
* Authors:
* Haijiao Liu <haijiao.liu@sophgo.com>
*/
#include <sbi_utils/clk/fdt_clk.h>
/* List of FDT clock drivers generated at compile time */
extern const struct fdt_driver *const fdt_clk_drivers[];
void fdt_clk_init(const void *fdt)
{
fdt_driver_init_all(fdt, fdt_clk_drivers);
}

View File

@@ -0,0 +1,3 @@
HEADER: sbi_utils/clk/fdt_clk.h
TYPE: const struct fdt_driver
NAME: fdt_clk_drivers

14
lib/utils/clk/objects.mk Normal file
View File

@@ -0,0 +1,14 @@
#
# SPDX-License-Identifier: BSD-2-Clause
#
# Copyright (C) 2025 Sophgo Inc
#
# Authors:
# Haijiao Liu <haijiao.liu@sophgo.com>
#
libsbiutils-objs-$(CONFIG_FDT_CLK) += clk/fdt_clk.o
libsbiutils-objs-$(CONFIG_FDT_CLK) += clk/fdt_clk_drivers.carray.o
carray-fdt_clk_drivers-$(CONFIG_FDT_CLK_SG2044) += fdt_clk_sg2044
libsbiutils-objs-$(CONFIG_FDT_CLK_SG2044) += clk/sg2044_clk.o

553
lib/utils/clk/sg2044_clk.c Normal file
View File

@@ -0,0 +1,553 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2025 Sophgo Inc.
*
* Authors:
* Haijiao Liu <haijiao.liu@sophgo.com>
*/
#include <libfdt.h>
#include <sbi/sbi_error.h>
#include <sbi/sbi_string.h>
#include <sbi/sbi_console.h>
#include <sbi/sbi_timer.h>
#include <sbi/sbi_clk.h>
#include <sbi/riscv_io.h>
#include <sbi_utils/fdt/fdt_driver.h>
#include <sbi_utils/clk/sg2044_clk.h>
#define POSTDIV_RESULT_INDEX 2
static u64 top_base_addr;
static int sg2044_pll_mux[][2] = {
{MPLL0_CLK, 0}, {MPLL1_CLK, 1}, {MPLL2_CLK, 2}, {MPLL3_CLK, 3},
{MPLL4_CLK, 4}, {MPLL5_CLK, 5}, {FPLL1_CLK, 6}, {DPLL0_CLK, 7},
{DPLL1_CLK, 8}, {DPLL2_CLK, 9}, {DPLL3_CLK, 10}, {DPLL4_CLK, 11},
{DPLL5_CLK, 12}, {DPLL6_CLK, 13}, {DPLL7_CLK, 14}
};
static int postdiv1_2[][3] = {
{2, 4, 8}, {3, 3, 9}, {2, 5, 10}, {2, 6, 12},
{2, 7, 14}, {3, 5, 15}, {4, 4, 16}, {3, 6, 18},
{4, 5, 20}, {3, 7, 21}, {4, 6, 24}, {5, 5, 25},
{4, 7, 28}, {5, 6, 30}, {5, 7, 35}, {6, 6, 36},
{6, 7, 42}, {7, 7, 49}
};
static inline unsigned long abs_diff(unsigned long a, unsigned long b)
{
return (a > b) ? (a - b) : (b - a);
}
static struct sg2044_pll_clock sg2044_root_pll_clks[] = {
{
.id = MPLL0_CLK,
.name = "mpll0-clock",
.default_rate = 2000 * MHZ,
.status_offset = 0x98,
.enable_offset = 0x9c,
}, {
.id = MPLL1_CLK,
.name = "mpll1-clock",
.default_rate = 2000 * MHZ,
.status_offset = 0x98,
.enable_offset = 0x9c,
}, {
.id = MPLL2_CLK,
.name = "mpll2-clock",
.default_rate = 1000 * MHZ,
.status_offset = 0x98,
.enable_offset = 0x9c,
}, {
.id = MPLL3_CLK,
.name = "mpll3-clock",
.default_rate = 2000 * MHZ,
.status_offset = 0x98,
.enable_offset = 0x9c,
}, {
.id = MPLL4_CLK,
.name = "mpll4-clock",
.default_rate = 1050 * MHZ,
.status_offset = 0x98,
.enable_offset = 0x9c,
}, {
.id = MPLL5_CLK,
.name = "mpll5-clock",
.default_rate = 900 * MHZ,
.status_offset = 0x98,
.enable_offset = 0x9c,
}, {
.id = FPLL0_CLK,
.name = "fpll0-clock",
}, {
.id = FPLL1_CLK,
.name = "fpll1-clock",
}, {
.id = DPLL0_CLK,
.name = "dpll0-clock",
.status_offset = 0x98,
.enable_offset = 0x9c,
}, {
.id = DPLL1_CLK,
.name = "dpll1-clock",
.status_offset = 0x98,
.enable_offset = 0x9c,
}, {
.id = DPLL2_CLK,
.name = "dpll2-clock",
.status_offset = 0x98,
.enable_offset = 0x9c,
}, {
.id = DPLL3_CLK,
.name = "dpll3-clock",
.status_offset = 0x98,
.enable_offset = 0x9c,
}, {
.id = DPLL4_CLK,
.name = "dpll4-clock",
.status_offset = 0x98,
.enable_offset = 0x9c,
}, {
.id = DPLL5_CLK,
.name = "dpll5-clock",
.status_offset = 0x98,
.enable_offset = 0x9c,
}, {
.id = DPLL6_CLK,
.name = "dpll6-clock",
.status_offset = 0x98,
.enable_offset = 0x9c,
}, {
.id = DPLL7_CLK,
.name = "dpll7-clock",
.status_offset = 0x98,
.enable_offset = 0x9c,
}
};
static inline void top_misc_read(uintptr_t offset, uint32_t *value)
{
*value = readl((const volatile void *)top_base_addr + offset);
}
static inline void top_misc_write(uintptr_t offset, uint32_t value)
{
writel(value, (volatile void *)(top_base_addr + offset));
}
static void sg2044_pll_write_h(int id, int value)
{
top_misc_write(PLL_CTRL_OFFSET + (id << 3), value);
}
static void sg2044_pll_read_h(int id, uint32_t *pvalue)
{
top_misc_read(PLL_CTRL_OFFSET + (id << 3), pvalue);
}
static void sg2044_pll_write_l(int id, int value)
{
top_misc_write(PLL_CTRL_OFFSET + (id << 3) - 4, value);
}
static void sg2044_pll_read_l(int id, uint32_t *pvalue)
{
top_misc_read(PLL_CTRL_OFFSET + (id << 3) - 4, pvalue);
}
static int __pll_get_postdiv_1_2(uint64_t rate, uint64_t prate,
uint32_t fbdiv, uint32_t refdiv,
uint32_t *postdiv1, uint32_t *postdiv2)
{
int index = 0;
int ret = 0;
uint64_t tmp0;
/*
* calculate (parent_rate/refdiv)
* and result save to tmp0
*/
tmp0 = prate;
do_div(tmp0, refdiv);
/*
* calcuate ((parent_rate/REFDIV) x FBDIV)
* and result save to prate
*/
tmp0 *= fbdiv;
/*
* calcuate (((parent_rate/REFDIV) x FBDIV)/input_rate)
* and result save to tmp0
* here tmp0 is (POSTDIV1*POSTDIV2)
*/
do_div(tmp0, rate);
/* calculate div1 and div2 value */
if (tmp0 <= 7) {
/* (div1 * div2) <= 7, no need to use array search */
*postdiv1 = tmp0;
*postdiv2 = 1;
} else {
/* (div1 * div2) > 7, use array search */
for (index = 0; index < array_size(postdiv1_2); index++) {
if (tmp0 > postdiv1_2[index][POSTDIV_RESULT_INDEX]) {
continue;
} else {
/* found it */
break;
}
}
if (index < array_size(postdiv1_2)) {
*postdiv1 = postdiv1_2[index][1];
*postdiv2 = postdiv1_2[index][0];
} else {
sbi_printf("%s out of postdiv array range!\n", __func__);
ret = -1;
}
}
return ret;
}
/*
* The function uses the following mapping for frequency range selection:
* - 2'd2 (bit[17:16] = 0b10): for frequencies from 1.6 GHz to 2.4 GHz.
* - 2'd3 (bit[17:16] = 0b11): for frequencies from 2.4 GHz to 3.2 GHz.
*/
static void __set_pll_vcosel(struct sg2044_pll_clock *sg2044_pll, uint64_t foutvco)
{
int vcosel;
uint32_t value;
if (foutvco < (2400 * MHZ))
vcosel = 0x2;
else
vcosel = 0x3;
sg2044_pll_read_l(sg2044_pll->id, &value);
value &= ~(0x3 << 16);
value |= (vcosel << 16);
sg2044_pll_write_l(sg2044_pll->id, value);
}
static inline int sg2044_pll_id2shift(uint32_t id)
{
for (int i = 0; i < 15; i++) {
if (sg2044_pll_mux[i][0] == id)
return sg2044_pll_mux[i][1];
}
return -1;
}
static inline int sg2044_pll_switch_mux(struct sg2044_pll_clock *pll, char en)
{
uint32_t value;
uint32_t id = pll->id;
int shift;
shift = sg2044_pll_id2shift(id);
if (shift == -1) {
sbi_printf("%s Unable to find a suitable shift!\n", __func__);
return -1;
}
top_misc_read(PLL_SELECT_OFFSET, &value);
if (en)
top_misc_write(PLL_SELECT_OFFSET, value & (~(1 << shift)));
else
top_misc_write(PLL_SELECT_OFFSET, value | (1 << shift));
return 0;
}
static inline int sg2044_pll_enable(struct sg2044_pll_clock *pll, char en)
{
uint32_t value;
uint64_t wait = 0;
uint32_t id = pll->id;
if (en) {
/* wait pll lock */
top_misc_read(pll->status_offset, &value);
while (!((value >> (PLL_STAT_LOCK_OFFSET + id)) & 0x1)) {
top_misc_read(pll->status_offset, &value);
wait++;
sbi_timer_udelay(10);
if (wait > 10000)
sbi_printf("%s not locked\n", pll->name);
}
/* wait pll updating */
wait = 0;
top_misc_read(pll->status_offset, &value);
while (((value >> id) & 0x1)) {
top_misc_read(pll->status_offset, &value);
wait++;
sbi_timer_udelay(10);
if (wait > 10000)
sbi_printf("%s still updating\n", pll->name);
}
/* enable pll */
top_misc_read(pll->enable_offset, &value);
top_misc_write(pll->enable_offset, value | (1 << id));
} else {
/* disable pll */
top_misc_read(pll->enable_offset, &value);
top_misc_write(pll->enable_offset, value & (~(1 << id)));
}
return 0;
}
/**
* The PLL output frequency calculation is based on the formula:
* FOUTPOSTDIV = FREF * FBDIV / REFDIV / (POSTDIV1 + 1) * (POSTDIV2 + 1)
* where:
* - FREF: Reference Clock Input (12MHz to 1600MHz).
* - FOUTPOSTDIV: Output Clock (25MHz to 3200MHz).
* - REFDIV: Reference divide value (1 to 63).
* - FBDIV: Feedback divide value (8 to 1066).
* - POSTDIV1: Post Divide 1 setting (0 to 7).
* - POSTDIV2: Post Divide 2 setting (0 to 7).
*
* Additionally, other check points inside PLL are listed here:
* 1.FOUTVCO = FREF * FBDIV / REFDIV 1600MHz to 3200MHz
* - VCOSEL = 2'd2, FOUTVCO 1.6G~2.4G;
* - VCOSEL = 2'd3, FOUTVCO 2.4G~3.2G
* 2.POSTDIV1 >= POSTDIV2
*/
static int __get_pll_ctl_setting(struct sg2044_pll_ctrl *best,
uint64_t req_rate, uint64_t parent_rate)
{
int ret;
uint32_t fbdiv, refdiv, fref, postdiv1, postdiv2;
uint64_t tmp = 0, foutvco;
fref = parent_rate;
for (refdiv = REFDIV_MIN; refdiv < REFDIV_MAX + 1; refdiv++) {
for (fbdiv = FBDIV_MIN; fbdiv < FBDIV_MAX + 1; fbdiv++) {
foutvco = fref * fbdiv / refdiv;
/* check fpostdiv pfd */
if (foutvco < PLL_FREQ_MIN || foutvco > PLL_FREQ_MAX
|| (fref / refdiv) < 10)
continue;
ret = __pll_get_postdiv_1_2(req_rate, fref, fbdiv,
refdiv, &postdiv1, &postdiv2);
if (ret)
continue;
tmp = foutvco / (postdiv1 * postdiv2);
if (abs_diff(tmp, req_rate) < abs_diff(best->freq, req_rate)) {
best->freq = tmp;
best->refdiv = refdiv;
best->fbdiv = fbdiv;
best->postdiv1 = postdiv1;
best->postdiv2 = postdiv2;
if (tmp == req_rate)
return 0;
}
continue;
}
}
return -1;
}
/**
* The function performs the following steps:
* 1. Switch the PLL source to fpll before modifying settings.
* 2. Disable the MPLL to allow safe modifications to its configuration.
* 3. Calculate the new PLL settings based on the desired rate and the parent rate.
* 5. Set the frequency range based on the foutvco .
* 6. Write the new settings to the PLL control register.
* 7. Re-enable the PLL.
* 8. Switch back the PLL source to mpll after modifications.
*/
static int sg2044_clk_pll_set_rate(struct sg2044_pll_clock *sg2044_pll,
uint64_t rate, uint64_t parent_rate)
{
int ret = 0;
uint32_t value;
uint64_t foutvco;
struct sg2044_pll_ctrl pctrl_table;
sbi_memset(&pctrl_table, 0, sizeof(struct sg2044_pll_ctrl));
/* switch to fpll before modify mpll */
ret = sg2044_pll_switch_mux(sg2044_pll, 1);
if (ret == -1) {
sbi_printf("switch to fpll fail!\n");
goto out;
}
if (sg2044_pll_enable(sg2044_pll, 0)) {
sbi_printf("Can't disable pll(%s), status error\n", sg2044_pll->name);
ret = -1;
goto out;
}
sg2044_pll_read_h(sg2044_pll->id, &value);
__get_pll_ctl_setting(&pctrl_table, rate, parent_rate);
if (!pctrl_table.freq) {
sbi_printf("%s: Can't find a proper pll setting\n", sg2044_pll->name);
ret = -1;
goto out;
}
value = TOP_PLL_CTRL(pctrl_table.fbdiv, pctrl_table.postdiv1,
pctrl_table.postdiv2, pctrl_table.refdiv);
foutvco = parent_rate * pctrl_table.fbdiv / pctrl_table.refdiv;
__set_pll_vcosel(sg2044_pll, foutvco);
/* write the value to top register */
sg2044_pll_write_h(sg2044_pll->id, value);
sg2044_pll_enable(sg2044_pll, 1);
/* switch back to mpll after modify mpll */
ret = sg2044_pll_switch_mux(sg2044_pll, 0);
if (ret == -1) {
sbi_printf("switch back to mpll fail!\n");
goto out;
}
out:
return ret;
}
static uint64_t sg2044_clk_pll_get_rate(struct sg2044_pll_clock *sg2044_pll,
uint64_t parent_rate)
{
uint32_t value;
uint64_t fref;
int refdiv, fbdiv;
int postdiv1, postdiv2;
sg2044_pll_read_h(sg2044_pll->id, &value);
fref = parent_rate;
fbdiv = (value >> FBDIV_SHIFT) & div_mask(FBDIV_WIDTH);
refdiv = (value >> REFDIV_SHIFT) & div_mask(REFDIV_WIDTH);
postdiv1 = (value >> POSTDIV1_SHIFT) & div_mask(POSTDIV1_WIDTH);
postdiv2 = (value >> POSTDIV2_SHIFT) & div_mask(POSTDIV2_WIDTH);
return fref * fbdiv / refdiv / (postdiv1 + 1) * (postdiv2 + 1);
}
static struct sg2044_pll_clock *sg2044_get_clk_by_name(const char *name)
{
int index;
for (index = 0; index < array_size(sg2044_root_pll_clks); index++) {
if (!sbi_strcmp(name, sg2044_root_pll_clks[index].name))
return &sg2044_root_pll_clks[index];
}
return 0;
}
static int sg2044_clk_set_rate(const char *name, uint64_t rate)
{
int ret;
struct sg2044_pll_clock *clk;
clk = sg2044_get_clk_by_name(name);
if (!clk)
return SBI_EINVAL;
ret = sg2044_clk_pll_set_rate(clk, rate, 25 * MHZ);
if (ret != 0)
sbi_printf("%s set rate fail, ret = %d\n", name, ret);
return ret;
}
static uint64_t sg2044_clk_get_rate(const char *name)
{
struct sg2044_pll_clock *clk;
clk = sg2044_get_clk_by_name(name);
if (!clk)
return SBI_EINVAL;
return sg2044_clk_pll_get_rate(clk, 25 * MHZ);
}
static int sg2044_clk_enable(const char *name)
{
struct sg2044_pll_clock *clk;
clk = sg2044_get_clk_by_name(name);
if (!clk)
return SBI_EINVAL;
sg2044_pll_enable(clk, 1);
return 0;
}
static int sg2044_clk_disable(const char *name)
{
struct sg2044_pll_clock *clk;
clk = sg2044_get_clk_by_name(name);
if (!clk)
return SBI_EINVAL;
sg2044_pll_enable(clk, 0);
return 0;
}
static struct sbi_clk_device sbi_sg2044_clk = {
.name = "sg2044-clk",
.clk_set_rate = sg2044_clk_set_rate,
.clk_get_rate = sg2044_clk_get_rate,
.clk_enable = sg2044_clk_enable,
.clk_disable = sg2044_clk_disable,
};
static int sg2044_clk_init(const void *fdt, int nodeoff,
const struct fdt_match *match)
{
int top_offset, len;
const fdt32_t *phandle;
const fdt32_t *reg;
if (top_base_addr)
return 0;
phandle = fdt_getprop(fdt, nodeoff, "subctrl-syscon", &len);
if (!phandle)
return SBI_EINVAL;
top_offset = fdt_node_offset_by_phandle(fdt, fdt32_to_cpu(*phandle));
if (top_offset < 0)
return top_offset;
reg = fdt_getprop(fdt, top_offset, "reg", &len);
if (!reg || len <= 0)
return SBI_EINVAL;
top_base_addr = fdt32_to_cpu(reg[0]);
top_base_addr = (top_base_addr << 32) | fdt32_to_cpu(reg[1]);
sbi_clk_set_device(&sbi_sg2044_clk);
return 0;
}
static const struct fdt_match sg2044_clk_match[] = {
{ .compatible = "sg2044, pll-clock" },
{},
};
struct fdt_driver fdt_clk_sg2044 = {
.match_table = sg2044_clk_match,
.init = sg2044_clk_init,
};

View File

@@ -14,6 +14,11 @@ config FDT_CPPC_RPMI
depends on FDT_MAILBOX && RPMI_MAILBOX
default n
config FDT_CPPC_SG2044
bool "FDT SG2044 CPPC driver"
select FDT_CLK_SG2044
default n
endif
endmenu

22
lib/utils/cppc/fdt_cppc.c Normal file
View File

@@ -0,0 +1,22 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2024 Ventana Micro Systems Inc.
*
* Authors:
* Anup Patel <apatel@ventanamicro.com>
*/
#include <sbi_utils/cppc/fdt_cppc.h>
/* List of FDT CPPC drivers generated at compile time */
extern const struct fdt_driver *const fdt_cppc_drivers[];
void fdt_cppc_init(const void *fdt)
{
/*
* Platforms might have multiple CPPC devices or might
* not have any so probe all and don't fail.
*/
fdt_driver_init_all(fdt, fdt_cppc_drivers);
}

View File

@@ -0,0 +1,3 @@
HEADER: sbi_utils/cppc/fdt_cppc.h
TYPE: const struct fdt_driver
NAME: fdt_cppc_drivers

View File

@@ -12,7 +12,7 @@
#include <sbi/sbi_cppc.h>
#include <sbi/sbi_ecall_interface.h>
#include <sbi/sbi_scratch.h>
#include <sbi_utils/fdt/fdt_driver.h>
#include <sbi_utils/cppc/fdt_cppc.h>
#include <sbi_utils/fdt/fdt_helper.h>
#include <sbi_utils/mailbox/fdt_mailbox.h>
#include <sbi_utils/mailbox/rpmi_mailbox.h>
@@ -367,7 +367,8 @@ static const struct fdt_match rpmi_cppc_match[] = {
{},
};
const struct fdt_driver fdt_cppc_rpmi = {
struct fdt_driver fdt_cppc_rpmi = {
.match_table = rpmi_cppc_match,
.init = rpmi_cppc_cold_init,
.experimental = true,
};

View File

@@ -0,0 +1,115 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2025 Sophgo Inc.
*
* Authors:
* Haijiao Liu <haijiao.liu@sophgo.com>
*/
#include <libfdt.h>
#include <sbi/sbi_error.h>
#include <sbi/sbi_string.h>
#include <sbi/sbi_console.h>
#include <sbi/sbi_ecall_interface.h>
#include <sbi/sbi_clk.h>
#include <sbi/sbi_cppc.h>
#include <sbi_utils/cppc/fdt_cppc.h>
#define CPPC_REGISTER_WIDTH 64
#define CPPC_REGISTER_NOT_IMPLEMENTED 0
static char clock_names[64];
static uint64_t clk_granularity;
static int sg2044_cppc_read(unsigned long reg, u64 *val)
{
int rc = SBI_SUCCESS;
switch (reg) {
case SBI_CPPC_DESIRED_PERF:
*val = sbi_clk_get_rate(clock_names) / clk_granularity;
break;
default:
rc = SBI_ERR_NOT_SUPPORTED;
}
return rc;
}
static int sg2044_cppc_write(unsigned long reg, u64 val)
{
int rc = SBI_SUCCESS;
switch (reg) {
case SBI_CPPC_DESIRED_PERF:
rc = sbi_clk_set_rate(clock_names, val * clk_granularity);
break;
default:
rc = SBI_ERR_NOT_SUPPORTED;
}
return rc;
}
static int sg2044_cppc_probe(unsigned long reg)
{
int rc;
switch (reg) {
case SBI_CPPC_DESIRED_PERF:
rc = CPPC_REGISTER_WIDTH;
break;
default:
rc = CPPC_REGISTER_NOT_IMPLEMENTED;
}
return rc;
}
static struct sbi_cppc_device sbi_sg2044_cppc = {
.name = "sg2044-cppc",
.cppc_read = sg2044_cppc_read,
.cppc_write = sg2044_cppc_write,
.cppc_probe = sg2044_cppc_probe,
};
static int sg2044_cppc_cold_init(const void *fdt, int nodeoff,
const struct fdt_match *match)
{
const struct sbi_clk_device *clk;
const fdt32_t *val;
const char *name;
int len;
clk = sbi_clk_get_device(fdt);
if (!clk)
return SBI_ENODEV;
val = fdt_getprop(fdt, nodeoff, "step", &len);
if (!val)
return SBI_EINVAL;
clk_granularity = fdt32_to_cpu(val[0]);
clk_granularity = (clk_granularity << 32) | fdt32_to_cpu(val[1]);
name = fdt_getprop(fdt, nodeoff, "clock-names", &len);
if (!name)
return SBI_EINVAL;
sbi_strncpy(clock_names, name, MIN(sizeof(clock_names), len));
sbi_cppc_set_device(&sbi_sg2044_cppc);
return 0;
}
static const struct fdt_match sg2044_cppc_match[] = {
{ .compatible = "sophgo,sg2044-cppc" },
{},
};
struct fdt_driver fdt_cppc_sg2044 = {
.match_table = sg2044_cppc_match,
.init = sg2044_cppc_cold_init,
};

View File

@@ -7,5 +7,11 @@
# Anup Patel <apatel@ventanamicro.com>
#
carray-fdt_early_drivers-$(CONFIG_FDT_CPPC_RPMI) += fdt_cppc_rpmi
libsbiutils-objs-$(CONFIG_FDT_CPPC) += cppc/fdt_cppc.o
libsbiutils-objs-$(CONFIG_FDT_CPPC) += cppc/fdt_cppc_drivers.carray.o
carray-fdt_cppc_drivers-$(CONFIG_FDT_CPPC_RPMI) += fdt_cppc_rpmi
libsbiutils-objs-$(CONFIG_FDT_CPPC_RPMI) += cppc/fdt_cppc_rpmi.o
carray-fdt_cppc_drivers-$(CONFIG_FDT_CPPC_SG2044) += fdt_cppc_sg2044
libsbiutils-objs-$(CONFIG_FDT_CPPC_SG2044) += cppc/fdt_cppc_sg2044.o

View File

@@ -289,10 +289,8 @@ static int __fdt_parse_region(const void *fdt, int domain_offset,
return SBI_EINVAL;
order = val32;
flags = region_access & (SBI_DOMAIN_MEMREGION_ACCESS_MASK
| SBI_DOMAIN_MEMREGION_ENF_PERMISSIONS);
/* Read "mmio" DT property */
flags = region_access & SBI_DOMAIN_MEMREGION_ACCESS_MASK;
if (fdt_get_property(fdt, region_offset, "mmio", NULL))
flags |= SBI_DOMAIN_MEMREGION_MMIO;
@@ -473,7 +471,7 @@ static int __fdt_parse_domain(const void *fdt, int domain_offset, void *opaque)
if (err)
continue;
if (SBI_HARTMASK_MAX_BITS <= sbi_hartid_to_hartindex(val32))
if (SBI_HARTMASK_MAX_BITS <= val32)
continue;
if (!fdt_node_is_enabled(fdt, cpu_offset))

View File

@@ -15,43 +15,39 @@ int fdt_driver_init_by_offset(const void *fdt, int nodeoff,
{
const struct fdt_driver *driver;
const struct fdt_match *match;
int compat_len, prop_len, rc;
const char *compat_str;
const void *prop;
int len, rc;
if (!fdt_node_is_enabled(fdt, nodeoff))
return SBI_ENODEV;
compat_str = fdt_getprop(fdt, nodeoff, "compatible", &prop_len);
if (!compat_str)
prop = fdt_getprop(fdt, nodeoff, "compatible", &len);
if (!prop)
return SBI_ENODEV;
while ((compat_len = strnlen(compat_str, prop_len) + 1) <= prop_len) {
for (int i = 0; (driver = drivers[i]); i++)
for (match = driver->match_table; match->compatible; match++)
if (!memcmp(match->compatible, compat_str, compat_len))
goto found;
while ((driver = *drivers++)) {
for (match = driver->match_table; match->compatible; match++) {
if (!fdt_stringlist_contains(prop, len, match->compatible))
continue;
compat_str += compat_len;
prop_len -= compat_len;
if (driver->experimental)
sbi_printf("WARNING: %s driver is experimental and may change\n",
match->compatible);
rc = driver->init(fdt, nodeoff, match);
if (rc < 0) {
const char *name;
name = fdt_get_name(fdt, nodeoff, NULL);
sbi_printf("%s: %s (%s) init failed: %d\n",
__func__, name, match->compatible, rc);
}
return rc;
}
}
return SBI_ENODEV;
found:
if (driver->experimental)
sbi_printf("WARNING: %s driver is experimental and may change\n",
match->compatible);
rc = driver->init(fdt, nodeoff, match);
if (rc < 0) {
const char *name;
name = fdt_get_name(fdt, nodeoff, NULL);
sbi_printf("%s: %s (%s) init failed: %d\n",
__func__, name, match->compatible, rc);
}
return rc;
}
static int fdt_driver_init_scan(const void *fdt,

View File

@@ -1,3 +0,0 @@
HEADER: sbi_utils/fdt/fdt_driver.h
TYPE: const struct fdt_driver
NAME: fdt_early_drivers

View File

@@ -16,7 +16,6 @@
#include <sbi/sbi_scratch.h>
#include <sbi/sbi_string.h>
#include <sbi/sbi_error.h>
#include <sbi/sbi_timer.h>
#include <sbi_utils/fdt/fdt_fixup.h>
#include <sbi_utils/fdt/fdt_pmu.h>
#include <sbi_utils/fdt/fdt_helper.h>
@@ -108,21 +107,10 @@ int fdt_add_cpu_idle_states(void *fdt, const struct sbi_cpu_idle_state *state)
void fdt_cpu_fixup(void *fdt)
{
struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
struct sbi_domain *dom = sbi_domain_thishart_ptr();
int err, cpu_offset, cpus_offset, len;
const char *mmu_type, *extensions;
const char *mmu_type;
u32 hartid, hartindex;
bool emulated_zicntr;
/*
* Claim Zicntr extension in riscv,isa-extensions if
* 1. OpenSBI can emulate time CSR with a timer
* 2. The other two CSRs specified by Zicntr are available
*/
emulated_zicntr = sbi_timer_get_device() != NULL &&
sbi_hart_has_csr(scratch, SBI_HART_CSR_CYCLE) &&
sbi_hart_has_csr(scratch, SBI_HART_CSR_INSTRET);
err = fdt_open_into(fdt, fdt, fdt_totalsize(fdt) + 32);
if (err < 0)
@@ -152,25 +140,6 @@ void fdt_cpu_fixup(void *fdt)
!mmu_type || !len)
fdt_setprop_string(fdt, cpu_offset, "status",
"disabled");
if (!emulated_zicntr)
continue;
extensions = fdt_getprop(fdt, cpu_offset,
"riscv,isa-extensions", &len);
/*
* For legacy devicetrees, don't create riscv,isa-extensions
* property if there hasn't been already one.
*/
if (extensions &&
!fdt_stringlist_contains(extensions, len, "zicntr")) {
err = fdt_open_into(fdt, fdt, fdt_totalsize(fdt) + 16);
if (err)
continue;
fdt_appendprop_string(fdt, cpu_offset,
"riscv,isa-extensions", "zicntr");
}
}
}
@@ -446,6 +415,7 @@ int fdt_register_general_fixup(struct fdt_general_fixup *fixup)
return SBI_EALREADY;
}
SBI_INIT_LIST_HEAD(&fixup->head);
sbi_list_add_tail(&fixup->head, &fixup_list);
return 0;

View File

@@ -33,6 +33,48 @@
#define DEFAULT_SHAKTI_UART_FREQ 50000000
#define DEFAULT_SHAKTI_UART_BAUD 115200
const struct fdt_match *fdt_match_node(const void *fdt, int nodeoff,
const struct fdt_match *match_table)
{
int ret;
if (!fdt || nodeoff < 0 || !match_table)
return NULL;
while (match_table->compatible) {
ret = fdt_node_check_compatible(fdt, nodeoff,
match_table->compatible);
if (!ret)
return match_table;
match_table++;
}
return NULL;
}
int fdt_find_match(const void *fdt, int startoff,
const struct fdt_match *match_table,
const struct fdt_match **out_match)
{
int nodeoff;
if (!fdt || !match_table)
return SBI_ENODEV;
while (match_table->compatible) {
nodeoff = fdt_node_offset_by_compatible(fdt, startoff,
match_table->compatible);
if (nodeoff >= 0) {
if (out_match)
*out_match = match_table;
return nodeoff;
}
match_table++;
}
return SBI_ENODEV;
}
int fdt_parse_phandle_with_args(const void *fdt, int nodeoff,
const char *prop, const char *cells_prop,
int index, struct fdt_phandle_args *out_args)
@@ -246,30 +288,6 @@ int fdt_parse_hart_id(const void *fdt, int cpu_offset, u32 *hartid)
return 0;
}
int fdt_parse_cbom_block_size(const void *fdt, int cpu_offset, unsigned long *cbom_block_size)
{
int len;
const void *prop;
const fdt32_t *val;
if (!fdt || cpu_offset < 0)
return SBI_EINVAL;
prop = fdt_getprop(fdt, cpu_offset, "device_type", &len);
if (!prop || !len)
return SBI_EINVAL;
if (strncmp (prop, "cpu", strlen ("cpu")))
return SBI_EINVAL;
val = fdt_getprop(fdt, cpu_offset, "riscv,cbom-block-size", &len);
if (!val || len < sizeof(fdt32_t))
return SBI_EINVAL;
if (cbom_block_size)
*cbom_block_size = fdt32_to_cpu(*val);
return 0;
}
int fdt_parse_max_enabled_hart_id(const void *fdt, u32 *max_hartid)
{
u32 hartid;
@@ -607,64 +625,19 @@ int fdt_parse_xlnx_uartlite_node(const void *fdt, int nodeoffset,
return fdt_parse_uart_node_common(fdt, nodeoffset, uart, 0, 0);
}
static int fdt_aplic_find_imsic_node(const void *fdt, int nodeoff,
struct imsic_data *imsic, bool mmode)
{
const fdt32_t *val;
int i, len, noff, rc;
val = fdt_getprop(fdt, nodeoff, "msi-parent", &len);
if (val && len >= sizeof(fdt32_t)) {
noff = fdt_node_offset_by_phandle(fdt, fdt32_to_cpu(*val));
if (noff < 0)
return noff;
rc = fdt_parse_imsic_node(fdt, noff, imsic);
if (rc)
return rc;
rc = imsic_data_check(imsic);
if (rc)
return rc;
if (imsic->targets_mmode == mmode) {
return 0;
}
} else {
return SBI_ENODEV;
}
val = fdt_getprop(fdt, nodeoff, "riscv,children", &len);
if (!val || len < sizeof(fdt32_t))
return SBI_ENODEV;
len /= sizeof(fdt32_t);
for (i = 0; i < len; i++) {
noff = fdt_node_offset_by_phandle(fdt, fdt32_to_cpu(val[i]));
if (noff < 0)
return noff;
rc = fdt_aplic_find_imsic_node(fdt, noff, imsic, mmode);
if (!rc)
break;
}
return rc;
}
int fdt_parse_aplic_node(const void *fdt, int nodeoff, struct aplic_data *aplic)
{
bool child_found;
const fdt32_t *val;
const fdt32_t *del;
struct imsic_data imsic = { 0 };
int i, j, d, dcnt, len, rc;
struct imsic_data imsic;
int i, j, d, dcnt, len, noff, rc;
uint64_t reg_addr, reg_size;
struct aplic_delegate_data *deleg;
if (nodeoff < 0 || !aplic || !fdt)
return SBI_ENODEV;
memset(aplic, 0, sizeof(*aplic));
rc = fdt_get_node_addr_size(fdt, nodeoff, 0, &reg_addr, &reg_size);
if (rc < 0 || !reg_addr || !reg_size)
@@ -686,34 +659,78 @@ int fdt_parse_aplic_node(const void *fdt, int nodeoff, struct aplic_data *aplic)
}
}
aplic->num_idc = len / 2;
goto aplic_msi_parent_done;
}
rc = fdt_aplic_find_imsic_node(fdt, nodeoff, &imsic, true);
if (!rc) {
aplic->targets_mmode = true;
aplic->has_msicfg_mmode = true;
aplic->msicfg_mmode.lhxs = imsic.guest_index_bits;
aplic->msicfg_mmode.lhxw = imsic.hart_index_bits;
aplic->msicfg_mmode.hhxw = imsic.group_index_bits;
aplic->msicfg_mmode.hhxs = imsic.group_index_shift;
if (aplic->msicfg_mmode.hhxs < (2 * IMSIC_MMIO_PAGE_SHIFT))
return SBI_EINVAL;
aplic->msicfg_mmode.hhxs -= 24;
aplic->msicfg_mmode.base_addr = imsic.regs[0].addr;
}
val = fdt_getprop(fdt, nodeoff, "msi-parent", &len);
if (val && len >= sizeof(fdt32_t)) {
noff = fdt_node_offset_by_phandle(fdt, fdt32_to_cpu(*val));
if (noff < 0)
return noff;
rc = fdt_aplic_find_imsic_node(fdt, nodeoff, &imsic, false);
if (!rc) {
aplic->has_msicfg_smode = true;
aplic->msicfg_smode.lhxs = imsic.guest_index_bits;
aplic->msicfg_smode.lhxw = imsic.hart_index_bits;
aplic->msicfg_smode.hhxw = imsic.group_index_bits;
aplic->msicfg_smode.hhxs = imsic.group_index_shift;
if (aplic->msicfg_smode.hhxs < (2 * IMSIC_MMIO_PAGE_SHIFT))
return SBI_EINVAL;
aplic->msicfg_smode.hhxs -= 24;
aplic->msicfg_smode.base_addr = imsic.regs[0].addr;
rc = fdt_parse_imsic_node(fdt, noff, &imsic);
if (rc)
return rc;
rc = imsic_data_check(&imsic);
if (rc)
return rc;
aplic->targets_mmode = imsic.targets_mmode;
if (imsic.targets_mmode) {
aplic->has_msicfg_mmode = true;
aplic->msicfg_mmode.lhxs = imsic.guest_index_bits;
aplic->msicfg_mmode.lhxw = imsic.hart_index_bits;
aplic->msicfg_mmode.hhxw = imsic.group_index_bits;
aplic->msicfg_mmode.hhxs = imsic.group_index_shift;
if (aplic->msicfg_mmode.hhxs <
(2 * IMSIC_MMIO_PAGE_SHIFT))
return SBI_EINVAL;
aplic->msicfg_mmode.hhxs -= 24;
aplic->msicfg_mmode.base_addr = imsic.regs[0].addr;
} else {
goto aplic_msi_parent_done;
}
val = fdt_getprop(fdt, nodeoff, "riscv,children", &len);
if (!val || len < sizeof(fdt32_t))
goto aplic_msi_parent_done;
noff = fdt_node_offset_by_phandle(fdt, fdt32_to_cpu(*val));
if (noff < 0)
return noff;
val = fdt_getprop(fdt, noff, "msi-parent", &len);
if (!val || len < sizeof(fdt32_t))
goto aplic_msi_parent_done;
noff = fdt_node_offset_by_phandle(fdt, fdt32_to_cpu(*val));
if (noff < 0)
return noff;
rc = fdt_parse_imsic_node(fdt, noff, &imsic);
if (rc)
return rc;
rc = imsic_data_check(&imsic);
if (rc)
return rc;
if (!imsic.targets_mmode) {
aplic->has_msicfg_smode = true;
aplic->msicfg_smode.lhxs = imsic.guest_index_bits;
aplic->msicfg_smode.lhxw = imsic.hart_index_bits;
aplic->msicfg_smode.hhxw = imsic.group_index_bits;
aplic->msicfg_smode.hhxs = imsic.group_index_shift;
if (aplic->msicfg_smode.hhxs <
(2 * IMSIC_MMIO_PAGE_SHIFT))
return SBI_EINVAL;
aplic->msicfg_smode.hhxs -= 24;
aplic->msicfg_smode.base_addr = imsic.regs[0].addr;
}
}
aplic_msi_parent_done:
for (d = 0; d < APLIC_MAX_DELEGATE; d++) {
deleg = &aplic->delegate[d];
@@ -969,7 +986,7 @@ int fdt_parse_aclint_node(const void *fdt, int nodeoffset,
{
const fdt32_t *val;
int i, rc, count, cpu_offset, cpu_intc_offset;
u32 phandle, hwirq, hartid, first_hartid, last_hartid;
u32 phandle, hwirq, hartid, first_hartid, last_hartid, hart_count;
u32 match_hwirq = (for_timer) ? IRQ_M_TIMER : IRQ_M_SOFT;
if (nodeoffset < 0 || !fdt ||
@@ -998,7 +1015,7 @@ int fdt_parse_aclint_node(const void *fdt, int nodeoffset,
count = count / sizeof(fdt32_t);
first_hartid = -1U;
last_hartid = 0;
hart_count = last_hartid = 0;
for (i = 0; i < (count / 2); i++) {
phandle = fdt32_to_cpu(val[2 * i]);
hwirq = fdt32_to_cpu(val[(2 * i) + 1]);
@@ -1015,18 +1032,24 @@ int fdt_parse_aclint_node(const void *fdt, int nodeoffset,
if (rc)
continue;
if (SBI_HARTMASK_MAX_BITS <= hartid)
continue;
if (match_hwirq == hwirq) {
if (hartid < first_hartid)
first_hartid = hartid;
if (hartid > last_hartid)
last_hartid = hartid;
hart_count++;
}
}
if ((last_hartid >= first_hartid) && first_hartid != -1U) {
*out_first_hartid = first_hartid;
*out_hart_count = last_hartid - first_hartid + 1;
count = last_hartid - first_hartid + 1;
*out_hart_count = (hart_count < count) ? hart_count : count;
}
return 0;
}
@@ -1074,7 +1097,7 @@ int fdt_parse_plmt_node(const void *fdt, int nodeoffset, unsigned long *plmt_bas
if (rc)
continue;
if (SBI_HARTMASK_MAX_BITS <= sbi_hartid_to_hartindex(hartid))
if (SBI_HARTMASK_MAX_BITS <= hartid)
continue;
if (hwirq == IRQ_M_TIMER)
@@ -1130,7 +1153,7 @@ int fdt_parse_plicsw_node(const void *fdt, int nodeoffset, unsigned long *plicsw
if (rc)
continue;
if (SBI_HARTMASK_MAX_BITS <= sbi_hartid_to_hartindex(hartid))
if (SBI_HARTMASK_MAX_BITS <= hartid)
continue;
if (hwirq == IRQ_M_SOFT)

View File

@@ -11,14 +11,15 @@
#include <libfdt.h>
#include <sbi/sbi_hart.h>
#include <sbi/sbi_error.h>
#include <sbi/sbi_heap.h>
#include <sbi/sbi_pmu.h>
#include <sbi/sbi_scratch.h>
#include <sbi_utils/fdt/fdt_helper.h>
#include <sbi_utils/fdt/fdt_pmu.h>
static struct fdt_pmu_hw_event_select_map *fdt_pmu_evt_select;
static uint32_t hw_event_count;
#define FDT_PMU_HW_EVENT_MAX (SBI_PMU_HW_EVENT_MAX * 2)
struct fdt_pmu_hw_event_select_map fdt_pmu_evt_select[FDT_PMU_HW_EVENT_MAX] = {0};
uint32_t hw_event_count;
uint64_t fdt_pmu_get_select_value(uint32_t event_idx)
{
@@ -73,7 +74,7 @@ int fdt_pmu_setup(const void *fdt)
event_ctr_map = fdt_getprop(fdt, pmu_offset,
"riscv,event-to-mhpmcounters", &len);
if (event_ctr_map) {
if (event_ctr_map && len >= 8) {
len = len / (sizeof(u32) * 3);
for (i = 0; i < len; i++) {
event_idx_start = fdt32_to_cpu(event_ctr_map[3 * i]);
@@ -88,27 +89,21 @@ int fdt_pmu_setup(const void *fdt)
event_val = fdt_getprop(fdt, pmu_offset,
"riscv,event-to-mhpmevent", &len);
if (event_val) {
if (event_val && len >= 8) {
len = len / (sizeof(u32) * 3);
hw_event_count = len;
fdt_pmu_evt_select = sbi_calloc(hw_event_count,
sizeof(*fdt_pmu_evt_select));
if (!fdt_pmu_evt_select)
return SBI_ENOMEM;
for (i = 0; i < len; i++) {
event = &fdt_pmu_evt_select[i];
event = &fdt_pmu_evt_select[hw_event_count];
event->eidx = fdt32_to_cpu(event_val[3 * i]);
event->select = fdt32_to_cpu(event_val[3 * i + 1]);
event->select = (event->select << 32) |
fdt32_to_cpu(event_val[3 * i + 2]);
hw_event_count++;
}
}
event_val = fdt_getprop(fdt, pmu_offset,
"riscv,raw-event-to-mhpmcounters", &len);
if (event_val) {
if (event_val && len >= 20) {
len = len / (sizeof(u32) * 5);
for (i = 0; i < len; i++) {
raw_selector = fdt32_to_cpu(event_val[5 * i]);

Some files were not shown because too many files have changed in this diff Show More