13 Commits

Author SHA1 Message Date
f879119605 Обновить platform/generic/cvitek_riscv.c 2026-02-11 02:19:45 +07:00
aedef73d12 Обновить platform/generic/cvitek_riscv.c 2026-02-11 01:41:03 +07:00
92ee61dae4 Обновить platform/generic/cvitek_riscv.c 2026-02-11 01:34:56 +07:00
sophgo-forum-service
6766e9cc96 opensbi: weekly rls 2025.01.24
daa470, [fix](opensbi): add rls_info.txt
b21a54, [test](opensbi): opensbi tailoring (time optimizing)
6ff231, [fix](str): fix riscv suspend section which do not use varivales and functions beyond syspend section.
2025-01-24 14:50:56 +08:00
sophgo-forum-service
3b045ae374 opensbi: weekly rls 2025.01.10
daa470, [fix](opensbi): add rls_info.txt
b21a54, [test](opensbi): opensbi tailoring (time optimizing)
6ff231, [fix](str): fix riscv suspend section which do not use varivales and functions beyond syspend section.

Change-Id: I8c6e7698b475b2d14c02308121f621dafe9b9e36
2025-01-13 16:32:03 +08:00
sophgo-forum-service
fffb4754ee opensbi: weekly rls 2024.10.14
-0f5edb, [fix](str):fix chip id miss and fix suspend bug on rtc
-a068cd, [fix](str): refine rtc suspend/resume process

Change-Id: Ice28701d616192d7d6a6f13621d739dd07424571
2024-10-14 19:27:45 +08:00
sophgo-forum-service
ab9b8f8d10 opensbi: weekly rls 2024.07.20
-0aa741, support cv181x/cv180x suspend to ram.

Change-Id: I64dcb0ff942aa7238a88ef3bd1da2c67f5d089b4
2024-07-20 21:40:47 +08:00
sophgo-forum-service
3fd99912a6 opensbi: weekly rls 2024.06.6
-2da720, Add rst/unrst/reset c906l ecall.

Change-Id: Id1b2de0c5cb4607d46fd4397a78e77109790cc49
2024-06-06 15:17:01 +08:00
sophgo-forum-service
216793f112 (opensbi): Init branch sg200x-dev
Change-Id: If4dd4f7d55a714cff21c4ead4376a4137ee03330
2024-02-14 16:36:52 +08:00
sophgo-forum-service
ba54b0038e note: sync patch from T-Head.
https://github.com/T-head-Semi/opensbi commit: 89182b257c8798e15e4c685c1af0c2862d528d2a
2024-02-14 16:31:42 +08:00
Guo Ren
ba85a8ec52 platform/generic/platform.c: Support qemu poweroff
Signed-off-by: Guo Ren <guoren@linux.alibaba.com>
2024-01-10 17:35:55 +08:00
Guo Ren
885df4577a utils: irqchip: Fixup priority init overwrite zero
Signed-off-by: Guo Ren <guoren@linux.alibaba.com>
2024-01-10 17:35:47 +08:00
Guo Ren
f67338cc74 thead PMU supported
Signed-off-by: Guo Ren <guoren@linux.alibaba.com>
2024-01-10 17:35:39 +08:00
204 changed files with 2149 additions and 9320 deletions

View File

@@ -1,16 +0,0 @@
AlignConsecutiveAssignments: true
AlignEscapedNewlines: Left
AlignTrailingComments: true
AllowShortFunctionsOnASingleLine: None
BraceWrapping:
AfterFunction: true
BreakBeforeBraces: Custom
BreakStringLiterals: false
ContinuationIndentWidth: 8
Cpp11BracedListStyle: false
IndentWidth: 8
ReflowComments: false
SortIncludes: false
SpacesInContainerLiterals: false
TabWidth: 8
UseTab: Always

175
Makefile
View File

@@ -76,54 +76,26 @@ OPENSBI_VERSION_MINOR=`grep "define OPENSBI_VERSION_MINOR" $(include_dir)/sbi/sb
OPENSBI_VERSION_GIT=$(shell if [ -d $(src_dir)/.git ]; then git describe 2> /dev/null; fi)
# Setup compilation commands
ifneq ($(LLVM),)
CC = clang
AR = llvm-ar
LD = ld.lld
OBJCOPY = llvm-objcopy
else
ifdef CROSS_COMPILE
CC = $(CROSS_COMPILE)gcc
CPP = $(CROSS_COMPILE)cpp
AR = $(CROSS_COMPILE)ar
LD = $(CROSS_COMPILE)ld
OBJCOPY = $(CROSS_COMPILE)objcopy
else
CC ?= gcc
CPP ?= cpp
AR ?= ar
LD ?= ld
OBJCOPY ?= objcopy
endif
endif
CPP = $(CC) -E
AS = $(CC)
DTC = dtc
ifneq ($(shell $(CC) --version 2>&1 | head -n 1 | grep clang),)
CC_IS_CLANG = y
else
CC_IS_CLANG = n
endif
ifneq ($(shell $(LD) --version 2>&1 | head -n 1 | grep LLD),)
LD_IS_LLD = y
else
LD_IS_LLD = n
endif
ifeq ($(CC_IS_CLANG),y)
ifneq ($(CROSS_COMPILE),)
CLANG_TARGET = --target=$(notdir $(CROSS_COMPILE:%-=%))
endif
endif
# Guess the compiler's XLEN
OPENSBI_CC_XLEN := $(shell TMP=`$(CC) $(CLANG_TARGET) -dumpmachine | sed 's/riscv\([0-9][0-9]\).*/\1/'`; echo $${TMP})
# Guess the compiler's ABI and ISA
ifneq ($(CC_IS_CLANG),y)
# Guess the compillers xlen
OPENSBI_CC_XLEN := $(shell TMP=`$(CC) -dumpmachine | sed 's/riscv\([0-9][0-9]\).*/\1/'`; echo $${TMP})
OPENSBI_CC_ABI := $(shell TMP=`$(CC) -v 2>&1 | sed -n 's/.*\(with\-abi=\([a-zA-Z0-9]*\)\).*/\2/p'`; echo $${TMP})
OPENSBI_CC_ISA := $(shell TMP=`$(CC) -v 2>&1 | sed -n 's/.*\(with\-arch=\([a-zA-Z0-9]*\)\).*/\2/p'`; echo $${TMP})
endif
# Setup platform XLEN
ifndef PLATFORM_RISCV_XLEN
@@ -134,47 +106,6 @@ ifndef PLATFORM_RISCV_XLEN
endif
endif
ifeq ($(CC_IS_CLANG),y)
ifeq ($(CROSS_COMPILE),)
CLANG_TARGET = --target=riscv$(PLATFORM_RISCV_XLEN)-unknown-elf
endif
endif
ifeq ($(LD_IS_LLD),y)
RELAX_FLAG = -mno-relax
USE_LD_FLAG = -fuse-ld=lld
else
USE_LD_FLAG = -fuse-ld=bfd
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)
# Check whether the compiler supports -m(no-)save-restore
CC_SUPPORT_SAVE_RESTORE := $(shell $(CC) $(CLANG_TARGET) $(RELAX_FLAG) -nostdlib -mno-save-restore -x c /dev/null -o /dev/null 2>&1 | grep "\-save\-restore" >/dev/null && echo n || echo y)
# Check whether the assembler and the compiler support the Zicsr and Zifencei extensions
CC_SUPPORT_ZICSR_ZIFENCEI := $(shell $(CC) $(CLANG_TARGET) $(RELAX_FLAG) -nostdlib -march=rv$(OPENSBI_CC_XLEN)imafd_zicsr_zifencei -x c /dev/null -o /dev/null 2>&1 | grep "zicsr\|zifencei" > /dev/null && echo n || echo y)
# Build Info:
# OPENSBI_BUILD_TIME_STAMP -- the compilation time stamp
# OPENSBI_BUILD_COMPILER_VERSION -- the compiler version info
BUILD_INFO ?= n
ifeq ($(BUILD_INFO),y)
OPENSBI_BUILD_DATE_FMT = +%Y-%m-%d %H:%M:%S %z
ifdef 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)")
endif
OPENSBI_BUILD_COMPILER_VERSION=$(shell $(CC) -v 2>&1 | grep ' version ' | \
sed 's/[[:space:]]*$$//')
endif
# Setup list of objects.mk files
ifdef PLATFORM
platform-object-mks=$(shell if [ -d $(platform_src_dir)/ ]; then find $(platform_src_dir) -iname "objects.mk" | sort -r; fi)
@@ -212,6 +143,20 @@ deps-y+=$(libsbi-objs-path-y:.o=.dep)
deps-y+=$(libsbiutils-objs-path-y:.o=.dep)
deps-y+=$(firmware-objs-path-y:.o=.dep)
ifeq (,$(wildcard ${PM_SRAM_BIN_PATH}))
ifeq (${CHIP_ARCH},CV180X)
PM_SRAM_BIN_PATH=${OPENSBI_PATH}/pm_default_cv180x.bin
endif
ifeq (${CHIP_ARCH},CV181X)
PM_SRAM_BIN_PATH=${OPENSBI_PATH}/pm_default_cv181x.bin
endif
else
ifeq ($(filter clean %clean clean%,$(MAKECMDGOALS)),)
$(shell touch -c platform\generic\cvitek_riscv.c > /dev/null)
endif
endif
$(info PM_SRAM_BIN_PATH is '${PM_SRAM_BIN_PATH}')
# Setup platform ABI, ISA and Code Model
ifndef PLATFORM_RISCV_ABI
ifneq ($(PLATFORM_RISCV_TOOLCHAIN_DEFAULT), 1)
@@ -226,11 +171,7 @@ ifndef PLATFORM_RISCV_ABI
endif
ifndef PLATFORM_RISCV_ISA
ifneq ($(PLATFORM_RISCV_TOOLCHAIN_DEFAULT), 1)
ifeq ($(CC_SUPPORT_ZICSR_ZIFENCEI), y)
PLATFORM_RISCV_ISA = rv$(PLATFORM_RISCV_XLEN)imafdc_zicsr_zifencei
else
PLATFORM_RISCV_ISA = rv$(PLATFORM_RISCV_XLEN)imafdc
endif
PLATFORM_RISCV_ISA = rv$(PLATFORM_RISCV_XLEN)imafdc
else
PLATFORM_RISCV_ISA = $(OPENSBI_CC_ISA)
endif
@@ -267,72 +208,61 @@ else
endif
# Setup compilation commands flags
ifeq ($(CC_IS_CLANG),y)
GENFLAGS += $(CLANG_TARGET)
GENFLAGS += -Wno-unused-command-line-argument
endif
GENFLAGS += -I$(platform_src_dir)/include
GENFLAGS = -I$(platform_src_dir)/include
GENFLAGS += -I$(include_dir)
ifneq ($(OPENSBI_VERSION_GIT),)
GENFLAGS += -DOPENSBI_VERSION_GIT="\"$(OPENSBI_VERSION_GIT)\""
endif
ifeq ($(BUILD_INFO),y)
GENFLAGS += -DOPENSBI_BUILD_TIME_STAMP="\"$(OPENSBI_BUILD_TIME_STAMP)\""
GENFLAGS += -DOPENSBI_BUILD_COMPILER_VERSION="\"$(OPENSBI_BUILD_COMPILER_VERSION)\""
endif
GENFLAGS += $(libsbiutils-genflags-y)
GENFLAGS += $(platform-genflags-y)
GENFLAGS += $(firmware-genflags-y)
CFLAGS = -g -Wall -Werror -ffreestanding -nostdlib -fno-stack-protector -fno-strict-aliasing -O2
CFLAGS += -fno-omit-frame-pointer -fno-optimize-sibling-calls -mstrict-align
# enable -m(no-)save-restore option by CC_SUPPORT_SAVE_RESTORE
ifeq ($(CC_SUPPORT_SAVE_RESTORE),y)
CFLAGS += -mno-save-restore
define add_define
GENFLAGS += -D$(1)$(if $(value $(1)),=$(value $(1)),)
endef
ifeq (${CONFIG_OPENSBI_FASTBOOT},y)
$(eval $(call add_define,CONFIG_OPENSBI_FASTBOOT))
endif
CFLAGS = -g -Wall -Werror -ffreestanding -nostdlib -fno-strict-aliasing -O2
CFLAGS += -fno-omit-frame-pointer -fno-optimize-sibling-calls
CFLAGS += -mno-save-restore -mstrict-align
CFLAGS += -mabi=$(PLATFORM_RISCV_ABI) -march=$(PLATFORM_RISCV_ISA)
CFLAGS += -mcmodel=$(PLATFORM_RISCV_CODE_MODEL)
CFLAGS += $(RELAX_FLAG)
CFLAGS += $(GENFLAGS)
CFLAGS += $(platform-cflags-y)
CFLAGS += -fno-pie -no-pie
CFLAGS += $(firmware-cflags-y)
CFLAGS += -DPM_SRAM_BIN_PATH=$(PM_SRAM_BIN_PATH)
ifeq ($(CHIP_ARCH),CV180X)
CFLAGS += -DCONFIG_CV180X
endif
ifeq (${CHIP_ARCH},CV181X)
CFLAGS += -DCONFIG_CV181X
endif
CPPFLAGS += $(GENFLAGS)
CPPFLAGS += $(platform-cppflags-y)
CPPFLAGS += $(firmware-cppflags-y)
ASFLAGS = -g -Wall -nostdlib
ASFLAGS += -fno-omit-frame-pointer -fno-optimize-sibling-calls -mstrict-align
# enable -m(no-)save-restore option by CC_SUPPORT_SAVE_RESTORE
ifeq ($(CC_SUPPORT_SAVE_RESTORE),y)
ASFLAGS += -mno-save-restore
endif
ASFLAGS += -fno-omit-frame-pointer -fno-optimize-sibling-calls
ASFLAGS += -mno-save-restore -mstrict-align
ASFLAGS += -mabi=$(PLATFORM_RISCV_ABI) -march=$(PLATFORM_RISCV_ISA)
ASFLAGS += -mcmodel=$(PLATFORM_RISCV_CODE_MODEL)
ASFLAGS += $(RELAX_FLAG)
ifneq ($(CC_IS_CLANG),y)
ifneq ($(RELAX_FLAG),)
ASFLAGS += -Wa,$(RELAX_FLAG)
endif
endif
ASFLAGS += $(GENFLAGS)
ASFLAGS += $(platform-asflags-y)
ASFLAGS += $(firmware-asflags-y)
ARFLAGS = rcs
ELFFLAGS += $(USE_LD_FLAG)
ELFFLAGS += -Wl,--build-id=none -Wl,-N
ELFFLAGS += -Wl,--build-id=none -N -static-libgcc -lgcc
ELFFLAGS += $(platform-ldflags-y)
ELFFLAGS += $(firmware-ldflags-y)
MERGEFLAGS += -r
ifeq ($(LD_IS_LLD),y)
MERGEFLAGS += -b elf
else
MERGEFLAGS += -b elf$(PLATFORM_RISCV_XLEN)-littleriscv
endif
MERGEFLAGS += -m elf$(PLATFORM_RISCV_XLEN)lriscv
DTSCPPFLAGS = $(CPPFLAGS) -nostdinc -nostdlib -fno-builtin -D__DTS__ -x assembler-with-cpp
@@ -404,10 +334,6 @@ compile_d2c = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \
$(if $($(2)-varprefix-$(3)),$(eval D2C_NAME_PREFIX := $($(2)-varprefix-$(3))),$(eval D2C_NAME_PREFIX := $(5))) \
$(if $($(2)-padding-$(3)),$(eval D2C_PADDING_BYTES := $($(2)-padding-$(3))),$(eval D2C_PADDING_BYTES := 0)) \
$(src_dir)/scripts/d2c.sh -i $(6) -a $(D2C_ALIGN_BYTES) -p $(D2C_NAME_PREFIX) -t $(D2C_PADDING_BYTES) > $(1)
compile_carray = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \
echo " CARRAY $(subst $(build_dir)/,,$(1))"; \
$(eval CARRAY_VAR_LIST := $(carray-$(subst .c,,$(shell basename $(1)))-y)) \
$(src_dir)/scripts/carray.sh -i $(2) -l "$(CARRAY_VAR_LIST)" > $(1)
compile_gen_dep = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \
echo " GEN-DEP $(subst $(build_dir)/,,$(1))"; \
echo "$(1:.dep=$(2)): $(3)" >> $(1)
@@ -441,27 +367,12 @@ $(build_dir)/%.dep: $(src_dir)/%.c
$(build_dir)/%.o: $(src_dir)/%.c
$(call compile_cc,$@,$<)
$(build_dir)/%.o: $(build_dir)/%.c
$(call compile_cc,$@,$<)
ifeq ($(BUILD_INFO),y)
$(build_dir)/lib/sbi/sbi_init.o: $(libsbi_dir)/sbi_init.c FORCE
$(call compile_cc,$@,$<)
endif
$(build_dir)/%.dep: $(src_dir)/%.S
$(call compile_as_dep,$@,$<)
$(build_dir)/%.o: $(src_dir)/%.S
$(call compile_as,$@,$<)
$(build_dir)/%.dep: $(src_dir)/%.carray
$(call compile_gen_dep,$@,.c,$<)
$(call compile_gen_dep,$@,.o,$(@:.dep=.c))
$(build_dir)/%.c: $(src_dir)/%.carray
$(call compile_carray,$@,$<)
$(platform_build_dir)/%.bin: $(platform_build_dir)/%.elf
$(call compile_objcopy,$@,$<)
@@ -477,6 +388,9 @@ $(platform_build_dir)/%.dep: $(platform_src_dir)/%.c
$(platform_build_dir)/%.o: $(platform_src_dir)/%.c
$(call compile_cc,$@,$<)
$(platform_build_dir)/%.o: $(platform_build_dir)/%.c
$(call compile_cc,$@,$<)
$(platform_build_dir)/%.dep: $(platform_src_dir)/%.S
$(call compile_as_dep,$@,$<)
@@ -606,6 +520,3 @@ ifeq ($(install_root_dir),$(install_root_dir_default)/usr)
$(if $(V), @echo " RM $(install_root_dir_default)")
$(CMD_PREFIX)rm -rf $(install_root_dir_default)
endif
.PHONY: FORCE
FORCE:

View File

@@ -96,21 +96,8 @@ Required Toolchain
------------------
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
support cross-compiling for RISC-V using the same toolchain as your native
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.
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*).
cross-compilation, you can build your own toolchain or just download
a prebuilt one from the [Bootlin toolchain repository].
Please note that only a 64-bit version of the toolchain is available in
the Bootlin toolchain repository for now.
@@ -124,7 +111,7 @@ architecture than RISC-V.
For cross-compiling, the environment variable *CROSS_COMPILE* must be defined
to specify the name prefix of the RISC-V compiler toolchain executables, e.g.
*riscv64-linux-gnu-* if the gcc executable used is *riscv64-linux-gnu-gcc*.
*riscv64-unknown-elf-* if the gcc executable used is *riscv64-unknown-elf-gcc*.
To build *libsbi.a* simply execute:
```
@@ -200,83 +187,21 @@ Building 32-bit / 64-bit OpenSBI Images
---------------------------------------
By default, building OpenSBI generates 32-bit or 64-bit images based on the
supplied RISC-V cross-compile toolchain. For example if *CROSS_COMPILE* is set
to *riscv64-linux-gnu-*, 64-bit OpenSBI images will be generated. If building
to *riscv64-unknown-elf-*, 64-bit OpenSBI images will be generated. If building
32-bit OpenSBI images, *CROSS_COMPILE* should be set to a toolchain that is
pre-configured to generate 32-bit RISC-V codes, like *riscv32-linux-gnu-*.
pre-configured to generate 32-bit RISC-V codes, like *riscv32-unknown-elf-*.
However it's possible to explicitly specify the image bits we want to build with
a given RISC-V toolchain. This can be done by setting the environment variable
*PLATFORM_RISCV_XLEN* to the desired width, for example:
```
export CROSS_COMPILE=riscv64-linux-gnu-
export CROSS_COMPILE=riscv64-unknown-elf-
export PLATFORM_RISCV_XLEN=32
```
will generate 32-bit OpenSBI images. And vice vesa.
Building with Clang/LLVM
------------------------
OpenSBI can also be built with Clang/LLVM. To build with just Clang but keep
the default binutils (which will still use the *CROSS_COMPILE* prefix if
defined), override the *CC* make variable with:
```
make CC=clang
```
To build with a full LLVM-based toolchain, not just Clang, enable the *LLVM*
option with:
```
make LLVM=1
```
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*
itself defaults to an undesired value then prefer setting that rather than the
full triple via *CROSS_COMPILE*. If *CROSS_COMPILE* is nonetheless defined,
rather than being used as a prefix for the executable name, it will instead be
passed via the `--target` option with the trailing `-` removed, so must be a
valid triple.
These can also be mixed; for example using a GCC cross-compiler but LLVM
binutils would be:
```
make CC=riscv64-linux-gnu-gcc LLVM=1
```
These variables must be passed for all the make invocations described in this
document.
NOTE: Using Clang with a `riscv*-linux-gnu` GNU binutils linker has been seen
to produce broken binaries with missing relocations; it is therefore currently
recommended that this combination be avoided or *FW_PIC=n* be used to disable
building OpenSBI as a position-independent binary.
Building with timestamp and compiler info
-----------------------------------------
When doing development, we may want to know the build time and compiler info
for debug purpose. OpenSBI can also be built with timestamp and compiler info.
To build with those info and print it out at boot time, we can just simply add
`BUILD_INFO=y`, like:
```
make BUILD_INFO=y
```
But if you have used `BUILD_INFO=y`, and want to switch back to `BUILD_INFO=n`,
you must do
```
make clean
```
before the next build.
NOTE: Using `BUILD_INFO=y` without specifying SOURCE_DATE_EPOCH will violate
[reproducible builds]. This definition is ONLY for development and debug
purpose, and should NOT be used in a product which follows "reproducible
builds".
Contributing to OpenSBI
-----------------------
@@ -359,4 +284,3 @@ make I=<install_directory> install_docs
[Doxygen manual]: http://www.doxygen.nl/manual/index.html
[Kendryte standalone SDK]: https://github.com/kendryte/kendryte-standalone-sdk
[third party notices]: ThirdPartyNotices.md
[reproducible builds]: https://reproducible-builds.org

View File

@@ -52,6 +52,7 @@ has following details:
* **next_mode** - Privilege mode of the next booting stage for this
domain. This can be either S-mode or U-mode.
* **system_reset_allowed** - Is domain allowed to reset the system?
* **system_suspend_allowed** - Is domain allowed to suspend the system?
The memory regions represented by **regions** in **struct sbi_domain** have
following additional constraints to align with RISC-V PMP requirements:
@@ -91,6 +92,7 @@ following manner:
* **next_mode** - Next booting stage mode in coldboot HART scratch space
is the next mode for the ROOT domain
* **system_reset_allowed** - The ROOT domain is allowed to reset the system
* **system_suspend_allowed** - The ROOT domain is allowed to suspend the system
Domain Effects
--------------
@@ -187,6 +189,8 @@ The DT properties of a domain instance DT node are as follows:
stage mode of coldboot HART** is used as default value.
* **system-reset-allowed** (Optional) - A boolean flag representing
whether the domain instance is allowed to do system reset.
* **system-suspend-allowed** (Optional) - A boolean flag representing
whether the domain instance is allowed to do system suspend.
### Assigning HART To Domain Instance
@@ -252,6 +256,7 @@ be done:
next-addr = <0x0 0x80100000>;
next-mode = <0x0>;
system-reset-allowed;
system-suspend-allowed;
};
udomain: untrusted-domain {

View File

@@ -9,13 +9,6 @@ OpenSBI generic library code. The supported firmwares type will differ in how
the arguments passed by the platform early boot stage are handled, as well as
how the boot stage following the firmware will be handled and executed.
The previous booting stage will pass information via the following registers
of RISC-V CPU:
* hartid via *a0* register
* device tree blob address in memory via *a1* register. The address must
be aligned to 8 bytes.
OpenSBI currently supports three different types of firmwares.
Firmware with Dynamic Information (*FW_DYNAMIC*)
@@ -69,12 +62,6 @@ parameters:
argument by the prior booting stage.
* **FW_FDT_PADDING** - Optional zero bytes padding to the embedded flattened
device tree binary file specified by **FW_FDT_PATH** option.
* **FW_PIC** - "FW_PIC=y" generates position independent executable firmware
images. OpenSBI can run at arbitrary address with appropriate alignment.
Therefore, the original relocation mechanism ("FW_PIC=n") will be skipped.
In other words, OpenSBI will directly run at the load address without any
code movement. This option requires a toolchain with PIE support, and it
is on by default.
Additionally, each firmware type as a set of type specific configuration
parameters. Detailed information for each firmware type can be found in the

View File

@@ -6,9 +6,8 @@ information about next booting stage (e.g. a bootloader or an OS) and runtime
OpenSBI library options from previous booting stage.
The previous booting stage will pass information to *FW_DYNAMIC* by creating
*struct fw_dynamic_info* in memory and passing its address to *FW_DYNAMIC*
via *a2* register of RISC-V CPU. The address must be aligned to 8 bytes on
RV64 and 4 bytes on RV32.
*struct fw_dynamic_info* in memory and passing it's address to *FW_DYNAMIC*
via *a2* register of RISC-V CPU.
A *FW_DYNAMIC* firmware is particularly useful when the booting stage executed
prior to OpenSBI firmware is capable of loading both the OpenSBI firmware and

View File

@@ -1,9 +1,9 @@
Andes AE350 SoC Platform
========================
The AE350 AXI/AHB-based platform N25(F)/NX25(F)/D25F/A25/AX25 CPU with level-one
memories, interrupt controller, debug module, AXI and AHB Bus Matrix Controller,
AXI-to-AHB Bridge and a collection of fundamental AHB/APB bus IP components
pre-integrated together as a system design. The high-quality and configurable
memories,interrupt controller, debug module, AXI and AHB Bus Matrix Controller,
AXI-to-AHB Bridge and a collection of fundamentalAHB/APB bus IP components
pre-integrated together as a system design.The high-quality and configurable
AHB/APB IPs suites a majority embedded systems, and the verified platform serves
as a starting point to jump start SoC designs.

View File

@@ -46,13 +46,11 @@ RISC-V Platforms Using Generic Platform
---------------------------------------
* **QEMU RISC-V Virt Machine** (*[qemu_virt.md]*)
* **Shakti C-class SoC Platform** (*[shakti_cclass.md]*)
* **SiFive HiFive Unleashed** (*[sifive_fu540.md]*)
* **Spike** (*[spike.md]*)
* **Shakti C-class SoC Platform** (*[shakti_cclass.md]*)
* **T-HEAD C9xx series Processors** (*[thead-c9xx.md]*)
[qemu_virt.md]: qemu_virt.md
[shakti_cclass.md]: shakti_cclass.md
[sifive_fu540.md]: sifive_fu540.md
[spike.md]: spike.md
[shakti_cclass.md]: shakti_cclass.md
[thead-c9xx.md]: thead-c9xx.md

View File

@@ -147,27 +147,3 @@ qemu-system-riscv32 -M virt -m 256M -nographic \
-device virtio-blk-device,drive=hd0 \
-append "root=/dev/vda rw console=ttyS0"
```
Debugging with GDB
------------------
In a first console start OpenSBI with QEMU:
```
qemu-system-riscv64 -M virt -m 256M -nographic \
-bios build/platform/generic/firmware/fw_payload.bin \
-gdb tcp::1234 \
-S
```
Parameter *-gdb tcp::1234* specifies 1234 as the debug port.
Parameter *-S* lets QEMU wait at the first instruction.
In a second console start GDB:
```
gdb build/platform/generic/firmware/fw_payload.elf \
-ex 'target remote localhost:1234'
```

View File

@@ -8,7 +8,7 @@ With QEMU v4.2 or above release, the 'sifive_u' machine can be used to test
OpenSBI image built for the real hardware as well.
To build platform specific library and firmwares, provide the
*PLATFORM=generic* parameter to the top level `make` command.
*PLATFORM=sifive/fu540* parameter to the top level `make` command.
Platform Options
----------------
@@ -32,10 +32,10 @@ To use Linux v5.2 (or higher), the pre-built DTB (DT binary) from Linux v5.2
the compile time option *FW_FDT_PATH*.
```
make PLATFORM=generic FW_PAYLOAD_PATH=<linux_build_directory>/arch/riscv/boot/Image
make PLATFORM=sifive/fu540 FW_PAYLOAD_PATH=<linux_build_directory>/arch/riscv/boot/Image
or
(For Linux v5.2 or higher)
make PLATFORM=generic FW_PAYLOAD_PATH=<linux_build_directory>/arch/riscv/boot/Image FW_FDT_PATH=<hifive-unleashed-a00.dtb path from Linux kernel>
make PLATFORM=sifive/fu540 FW_PAYLOAD_PATH=<linux_build_directory>/arch/riscv/boot/Image FW_FDT_PATH=<hifive-unleashed-a00.dtb path from Linux kernel>
```
**U-Boot Payload**
@@ -45,7 +45,7 @@ sifive_fu540_defconfig configuration and with U-Boot v2020.01, and up to
v2021.04. sifive_unleashed_defconfig shall be used with v2021.07 or above.
```
make PLATFORM=generic FW_PAYLOAD_PATH=<u-boot_build_dir>/u-boot-dtb.bin
make PLATFORM=sifive/fu540 FW_PAYLOAD_PATH=<u-boot_build_dir>/u-boot-dtb.bin
```
For U-Boot v2020.07-rc4 or later releases, SPL support was added in U-Boot.
Please refer to the detailed U-Boot booting guide available at [U-Boot].
@@ -64,7 +64,7 @@ That's why the generated firmware binary in above steps should be copied to
the partition of the sdcard with above GUID.
```
dd if=build/platform/generic/firmware/fw_payload.bin of=/dev/disk2s1 bs=1024
dd if=build/platform/sifive/fu540/firmware/fw_payload.bin of=/dev/disk2s1 bs=1024
```
In my case, it is the first partition is **disk2s1** that has been formatted
@@ -161,7 +161,7 @@ U-Boot uses the DTB generated by QEMU, and u-boot.bin should be used as the
payload image, like:
```
make PLATFORM=generic FW_PAYLOAD_PATH=<u-boot_build_dir>/u-boot.bin
make PLATFORM=sifive/fu540 FW_PAYLOAD_PATH=<u-boot_build_dir>/u-boot.bin
```
U-Boot v2020.07 release added SPL support to SiFive HiFive Unleashed board,
@@ -179,12 +179,12 @@ The above errors can be safely ignored as we don't run U-Boot SPL under QEMU.
Run:
```
qemu-system-riscv64 -M sifive_u -m 256M -nographic \
-bios build/platform/generic/firmware/fw_payload.bin
-bios build/platform/sifive/fu540/firmware/fw_payload.bin
```
or
```
qemu-system-riscv64 -M sifive_u -m 256M -nographic \
-bios build/platform/generic/firmware/fw_jump.bin \
-bios build/platform/sifive/fu540/firmware/fw_jump.bin \
-kernel <uboot_build_dir>/u-boot.bin
```

View File

@@ -43,18 +43,7 @@ make PLATFORM=generic FW_PAYLOAD_PATH=<linux_build_directory>/arch/riscv/boot/Im
Run:
```
spike -m256 \
--initrd <path_to_cpio_ramdisk> \
--bootargs 'root=/dev/ram rw console=hvc0 earlycon=sbi' \
build/platform/generic/firmware/fw_payload.elf
```
or
```
spike -m256 \
--kernel <linux_build_directory>/arch/riscv/boot/Image \
--initrd <path_to_cpio_ramdisk> \
--bootargs 'root=/dev/ram rw console=hvc0 earlycon=sbi' \
build/platform/generic/firmware/fw_jump.elf
spike --initrd <path_to_cpio_ramdisk> build/platform/generic/firmware/fw_payload.elf
```
Execution on QEMU RISC-V 64-bit

View File

@@ -16,7 +16,7 @@ The *T-HEAD C9xx* does not have any platform-specific compile options
because it use generic platform.
```
CROSS_COMPILE=riscv64-linux-gnu- PLATFORM=generic /usr/bin/make
CROSS_COMPILE=riscv64-linux-gnu- PLATFORM=generic FW_PIC=y /usr/bin/make
```
The *T-HEAD C9xx* DTB provided to OpenSBI generic firmwares will usually have
@@ -51,18 +51,23 @@ DTS Example1: (Single core, eg: Allwinner D1 - c906)
compatible = "simple-bus";
ranges;
reset: reset-sample {
compatible = "thead,reset-sample";
plic-delegate = <0x0 0x101ffffc>;
};
clint0: clint@14000000 {
compatible = "allwinner,sun20i-d1-clint";
compatible = "riscv,clint0";
interrupts-extended = <
&cpu0_intc 3 &cpu0_intc 7
>;
reg = <0x0 0x14000000 0x0 0x04000000>;
clint,has-no-64bit-mmio;
};
intc: interrupt-controller@10000000 {
#interrupt-cells = <1>;
compatible = "allwinner,sun20i-d1-plic",
"thead,c900-plic";
compatible = "riscv,plic0";
interrupt-controller;
interrupts-extended = <
&cpu0_intc 0xffffffff &cpu0_intc 9
@@ -145,6 +150,7 @@ DTS Example2: (Multi cores with soc reset-regs)
reset: reset-sample {
compatible = "thead,reset-sample";
plic-delegate = <0xff 0xd81ffffc>;
entry-reg = <0xff 0xff019050>;
entry-cnt = <4>;
control-reg = <0xff 0xff015004>;
@@ -162,11 +168,12 @@ DTS Example2: (Multi cores with soc reset-regs)
&cpu4_intc 3 &cpu4_intc 7
>;
reg = <0xff 0xdc000000 0x0 0x04000000>;
clint,has-no-64bit-mmio;
};
intc: interrupt-controller@ffd8000000 {
#interrupt-cells = <1>;
compatible = "thead,c900-plic";
compatible = "riscv,plic0";
interrupt-controller;
interrupts-extended = <
&cpu0_intc 0xffffffff &cpu0_intc 9
@@ -187,6 +194,7 @@ DTS Example2: (Multi cores with old reset csrs)
```
reset: reset-sample {
compatible = "thead,reset-sample";
plic-delegate = <0xff 0xd81ffffc>;
using-csr-reset;
csr-copy = <0x7c0 0x7c1 0x7c2 0x7c3 0x7c5 0x7cc
0x3b0 0x3b1 0x3b2 0x3b3

View File

@@ -17,7 +17,7 @@ the supported platforms. These firmwares are linked against *libplatsbi.a*.
Firmware binaries are installed in
*<install_directory>/platform/<platform_subdir>/bin*. These firmwares can be
used as executable runtime firmwares on the supported platforms as a replacement
for the legacy *riscv-pk* boot loader (BBL).
for the legacy *riskv-pk* boot loader (BBL).
A complete doxygen-style documentation of *struct sbi_platform* and related
APIs is available in the file *include/sbi/sbi_platform.h*.
@@ -25,18 +25,18 @@ APIs is available in the file *include/sbi/sbi_platform.h*.
Adding support for a new platform
---------------------------------
Support for a new platform named *&lt;xyz&gt;* can be added as follows:
Support for a new platform named *<xyz>* can be added as follows:
1. Create a directory named *&lt;xyz&gt;* under the *platform/* directory.
1. Create a directory named *<xyz>* under the *platform/* directory.
2. Create a platform configuration file named *config.mk* under the
*platform/&lt;xyz&gt;/* directory. This configuration file will provide
*platform/<xyz>/* directory. This configuration file will provide
compiler flags, and select firmware options.
3. Create a *platform/&lt;xyz&gt;/objects.mk* file for listing the
3. Create a *platform/<xyz>/objects.mk* file for listing the
platform-specific object files to be compiled.
4. Create a *platform/&lt;xyz&gt;/platform.c* file providing a
*struct sbi_platform* instance.
4. Create a *platform/<xyz>/platform.c* file providing a *struct sbi_platform*
instance.
A platform support code template is available under the *platform/template*
directory. Copying this directory and its content as a new directory named
*&lt;xyz&gt;* under the *platform/* directory will create all the files
mentioned above.
*<xyz>* under the *platform/* directory will create all the files mentioned
above.

View File

@@ -1,100 +0,0 @@
OpenSBI SBI PMU extension support
==================================
SBI PMU extension supports allow supervisor software to configure/start/stop
any performance counter at anytime. Thus, an user can leverage full
capability of performance analysis tools such as perf if SBI PMU extension is
enabled. The OpenSBI implementation makes the following assumptions about the
hardware platform.
* MCOUNTINHIBIT CSR must be implemented in the hardware. Otherwise, SBI PMU
extension will not be enabled.
* The platform must provide information about PMU event to counter mapping
via device tree or platform specific hooks. Otherwise, SBI PMU extension will
not be enabled.
* The platforms should provide information about the PMU event selector values
that should be encoded in the expected value of MHPMEVENTx while configuring
MHPMCOUNTERx for that specific event. This can be done via a device tree or
platform specific hooks. The exact value to be written to he MHPMEVENTx is
completely depends on platform. Generic platform writes the zero-extended event_idx
as the expected value for hardware cache/generic events as suggested by the SBI
specification.
SBI PMU Device Tree Bindings
----------------------------
Platforms may choose to describe PMU event selector and event to counter mapping
values via device tree. The following sections describes the PMU DT node
bindings in details.
* **compatible** (Mandatory) - The compatible string of SBI PMU device tree node.
This DT property must have the value **riscv,pmu**.
* **riscv,event-to-mhpmevent**(Optional) - It represents an ONE-to-ONE mapping
between a PMU event and the event selector value that platform expects to be
written to the MHPMEVENTx CSR for that event. The mapping is encoded in a
table format where each row represents an event. The first column represent the
event idx where the 2nd & 3rd column represent the event selector value that
should be encoded in the expected value to be written in MHPMEVENTx.
This property shouldn't encode any raw hardware event.
* **riscv,event-to-mhpmcounters**(Optional) - It represents a MANY-to-MANY
mapping between a range of events and all the MHPMCOUNTERx in a bitmap format
that can be used to monitor these range of events. The information is encoded in
a table format where each row represent a certain range of events and
corresponding counters. The first column represents starting of the pmu event id
and 2nd column represents the end of the pmu event id. The third column
represent a bitmap of all the MHPMCOUNTERx. This property is mandatory if
event-to-mhpmevent is present. Otherwise, it can be omitted. This property
shouldn't encode any raw event.
* **riscv,raw-event-to-mhpmcounters**(Optional) - It represents an ONE-to-MANY
or MANY-to-MANY mapping between the raw event(s) and all the MHPMCOUNTERx in
a bitmap format that can be used to monitor that raw event. The encoding of the
raw events are platform specific. The information is encoded in a table format
where each row represent the specific raw event(s). The first column is a 64bit
match value where the invariant bits of range of events are set. The second
column is a 64 bit mask that will have all the variant bits of the range of
events cleared. Every other bits should be set in the mask.
The third column is a 32bit value to represent bitmap of all MHPMCOUNTERx that
can monitor these set of event(s).
If a platform directly encodes each raw PMU event as a unique ID, the value of
select_mask must be 0xffffffff_ffffffff.
*Note:* A platform may choose to provide the mapping between event & counters
via platform hooks rather than the device tree.
### Example 1
```
pmu {
compatible = "riscv,pmu";
riscv,event-to-mhpmevent = <0x0000B 0x0000 0x0001>,
riscv,event-to-mhpmcounters = <0x00001 0x00001 0x00000001>,
<0x00002 0x00002 0x00000004>,
<0x00003 0x0000A 0x00000ff8>,
<0x10000 0x10033 0x000ff000>,
/* For event ID 0x0002 */
riscv,raw-event-to-mhpmcounters = <0x0000 0x0002 0xffffffff 0xffffffff 0x00000f8>,
/* For event ID 0-4 */
<0x0 0x0 0xffffffff 0xfffffff0 0x00000ff0>,
/* For event ID 0xffffffff0000000f - 0xffffffff000000ff */
<0xffffffff 0x0 0xffffffff 0xffffff0f 0x00000ff0>,
};
```
### Example 2
```
/*
* For HiFive Unmatched board. The encodings can be found here
* https://sifive.cdn.prismic.io/sifive/1a82e600-1f93-4f41-b2d8-86ed8b16acba_fu740-c000-manual-v1p6.pdf
*/
pmu {
compatible = "riscv,pmu";
riscv,raw-event-to-mhpmcounters = <0x0 0x0 0xffffffff 0xfc0000ff 0xc>,
<0x0 0x1 0xffffffff 0xfff800ff 0xc>,
<0x0 0x2 0xffffffff 0xffffe0ff 0xc>;
};
```

View File

@@ -65,14 +65,14 @@ _try_lottery:
/* Save load address */
lla t0, _load_start
lla t1, _fw_start
lla t1, _start
REG_S t1, 0(t0)
#ifdef FW_PIC
/* relocate the global table content */
lla t0, _link_start
REG_L t0, 0(t0)
/* t1 shall has the address of _fw_start */
/* t1 shall has the address of _start */
sub t2, t1, t0
lla t3, _runtime_offset
REG_S t2, (t3)
@@ -172,7 +172,7 @@ _relocate_copy_to_upper_loop:
blt t0, t1, _relocate_copy_to_upper_loop
jr t4
_wait_relocate_copy_done:
lla t0, _fw_start
lla t0, _start
lla t1, _link_start
REG_L t1, 0(t1)
beq t0, t1, _wait_for_boot_hart
@@ -259,7 +259,7 @@ _bss_zero:
* s8 -> HART Stack Size
*/
lla a4, platform
#if __riscv_xlen > 32
#if __riscv_xlen == 64
lwu s7, SBI_PLATFORM_HART_COUNT_OFFSET(a4)
lwu s8, SBI_PLATFORM_HART_STACK_SIZE_OFFSET(a4)
#else
@@ -278,14 +278,6 @@ _bss_zero:
/* hartid 0 is mandated by ISA */
li t1, 0
_scratch_init:
/*
* The following registers hold values that are computed before
* entering this block, and should remain unchanged.
*
* t3 -> the firmware end address
* s7 -> HART count
* s8 -> HART stack size
*/
add tp, t3, zero
mul a5, s8, t1
sub tp, tp, a5
@@ -295,7 +287,10 @@ _scratch_init:
/* Initialize scratch space */
/* Store fw_start and fw_size in scratch space */
lla a4, _fw_start
sub a5, t3, a4
lla a5, _fw_end
mul t0, s7, s8
add a5, a5, t0
sub a5, a5, a4
REG_S a4, SBI_SCRATCH_FW_START_OFFSET(tp)
REG_S a5, SBI_SCRATCH_FW_SIZE_OFFSET(tp)
/* Store next arg1 in scratch space */
@@ -349,7 +344,8 @@ _scratch_init:
* previous booting stage.
*/
beqz a1, _fdt_reloc_done
/* Mask values in a4 */
/* Mask values in a3 and a4 */
li a3, ~(__SIZEOF_POINTER__ - 1)
li a4, 0xff
/* t1 = destination FDT start address */
MOV_3R s0, a0, s1, a1, s2, a2
@@ -358,8 +354,10 @@ _scratch_init:
MOV_3R a0, s0, a1, s1, a2, s2
beqz t1, _fdt_reloc_done
beq t1, a1, _fdt_reloc_done
and t1, t1, a3
/* t0 = source FDT start address */
add t0, a1, zero
and t0, t0, a3
/* t2 = source FDT size in big-endian */
#if __riscv_xlen == 64
lwu t2, 4(t0)
@@ -503,7 +501,6 @@ _skip_trap_exit_rv32_hyp:
/* We don't expect to reach here hence just hang */
j _start_hang
.data
.align 3
#ifdef FW_PIC
_runtime_offset:
@@ -556,39 +553,12 @@ _start_hang:
.section .entry, "ax", %progbits
.align 3
.globl fw_platform_init
.weak fw_platform_init
fw_platform_init:
add a0, a1, zero
ret
/* Map implicit memcpy() added by compiler to sbi_memcpy() */
.section .text
.align 3
.globl memcpy
memcpy:
tail sbi_memcpy
/* Map implicit memset() added by compiler to sbi_memset() */
.section .text
.align 3
.globl memset
memset:
tail sbi_memset
/* Map implicit memmove() added by compiler to sbi_memmove() */
.section .text
.align 3
.globl memmove
memmove:
tail sbi_memmove
/* Map implicit memcmp() added by compiler to sbi_memcmp() */
.section .text
.align 3
.globl memcmp
memcmp:
tail sbi_memcmp
.macro TRAP_SAVE_AND_SETUP_SP_T0
/* Swap TP and MSCRATCH */
csrrw tp, CSR_MSCRATCH, tp

View File

@@ -8,7 +8,7 @@
*/
. = FW_TEXT_START;
/* Don't add any section between FW_TEXT_START and _fw_start */
PROVIDE(_fw_start = .);
. = ALIGN(0x1000); /* Need this to create proper sections */

View File

@@ -36,7 +36,7 @@ fw_boot_hart:
bgt a0, a1, _bad_dynamic_info
/* Read boot HART id */
li a1, FW_DYNAMIC_INFO_VERSION_2
li a1, 0x2
blt a0, a1, 2f
REG_L a0, FW_DYNAMIC_INFO_BOOT_HART_OFFSET(a2)
ret
@@ -57,6 +57,14 @@ fw_save_info:
lla a4, _dynamic_next_arg1
REG_S a1, (a4)
/* Sanity checks */
li a4, FW_DYNAMIC_INFO_MAGIC_VALUE
REG_L a3, FW_DYNAMIC_INFO_MAGIC_OFFSET(a2)
bne a3, a4, _bad_dynamic_info
li a4, FW_DYNAMIC_INFO_VERSION_MAX
REG_L a3, FW_DYNAMIC_INFO_VERSION_OFFSET(a2)
bgt a3, a4, _bad_dynamic_info
/* Save version == 0x1 fields */
lla a4, _dynamic_next_addr
REG_L a3, FW_DYNAMIC_INFO_NEXT_ADDR_OFFSET(a2)
@@ -69,7 +77,7 @@ fw_save_info:
REG_S a3, (a4)
/* Save version == 0x2 fields */
li a4, FW_DYNAMIC_INFO_VERSION_2
li a4, 0x2
REG_L a3, FW_DYNAMIC_INFO_VERSION_OFFSET(a2)
blt a3, a4, 2f
lla a4, _dynamic_boot_hart

View File

@@ -14,14 +14,14 @@ firmware-asflags-y +=
firmware-ldflags-y +=
ifndef FW_PIC
FW_PIC := $(OPENSBI_LD_PIE)
FW_PIC := y
endif
ifeq ($(FW_PIC),y)
firmware-genflags-y += -DFW_PIC
firmware-asflags-y += -fpic
firmware-cflags-y += -fPIE -pie
firmware-ldflags-y += -Wl,--no-dynamic-linker -Wl,-pie
firmware-ldflags-y += -Wl,--no-dynamic-linker
endif
ifdef FW_TEXT_START

View File

@@ -9,25 +9,24 @@
#include <sbi/sbi_ecall_interface.h>
#define SBI_ECALL(__eid, __fid, __a0, __a1, __a2) \
#define SBI_ECALL(__num, __a0, __a1, __a2) \
({ \
register unsigned long a0 asm("a0") = (unsigned long)(__a0); \
register unsigned long a1 asm("a1") = (unsigned long)(__a1); \
register unsigned long a2 asm("a2") = (unsigned long)(__a2); \
register unsigned long a6 asm("a6") = (unsigned long)(__fid); \
register unsigned long a7 asm("a7") = (unsigned long)(__eid); \
register unsigned long a7 asm("a7") = (unsigned long)(__num); \
asm volatile("ecall" \
: "+r"(a0) \
: "r"(a1), "r"(a2), "r"(a6), "r"(a7) \
: "r"(a1), "r"(a2), "r"(a7) \
: "memory"); \
a0; \
})
#define SBI_ECALL_0(__eid, __fid) SBI_ECALL(__eid, __fid, 0, 0, 0)
#define SBI_ECALL_1(__eid, __fid, __a0) SBI_ECALL(__eid, __fid, __a0, 0, 0)
#define SBI_ECALL_2(__eid, __fid, __a0, __a1) SBI_ECALL(__eid, __fid, __a0, __a1, 0)
#define SBI_ECALL_0(__num) SBI_ECALL(__num, 0, 0, 0)
#define SBI_ECALL_1(__num, __a0) SBI_ECALL(__num, __a0, 0, 0)
#define SBI_ECALL_2(__num, __a0, __a1) SBI_ECALL(__num, __a0, __a1, 0)
#define sbi_ecall_console_putc(c) SBI_ECALL_1(SBI_EXT_0_1_CONSOLE_PUTCHAR, 0, (c))
#define sbi_ecall_console_putc(c) SBI_ECALL_1(SBI_EXT_0_1_CONSOLE_PUTCHAR, (c))
static inline void sbi_ecall_console_puts(const char *str)
{

View File

@@ -15,24 +15,23 @@
/* clang-format off */
/** Offset of magic member in fw_dynamic_info */
#define FW_DYNAMIC_INFO_MAGIC_OFFSET (0 * __SIZEOF_LONG__)
#define FW_DYNAMIC_INFO_MAGIC_OFFSET (0 * __SIZEOF_POINTER__)
/** Offset of version member in fw_dynamic_info */
#define FW_DYNAMIC_INFO_VERSION_OFFSET (1 * __SIZEOF_LONG__)
#define FW_DYNAMIC_INFO_VERSION_OFFSET (1 * __SIZEOF_POINTER__)
/** Offset of next_addr member in fw_dynamic_info (version >= 1) */
#define FW_DYNAMIC_INFO_NEXT_ADDR_OFFSET (2 * __SIZEOF_LONG__)
#define FW_DYNAMIC_INFO_NEXT_ADDR_OFFSET (2 * __SIZEOF_POINTER__)
/** Offset of next_mode member in fw_dynamic_info (version >= 1) */
#define FW_DYNAMIC_INFO_NEXT_MODE_OFFSET (3 * __SIZEOF_LONG__)
#define FW_DYNAMIC_INFO_NEXT_MODE_OFFSET (3 * __SIZEOF_POINTER__)
/** Offset of options member in fw_dynamic_info (version >= 1) */
#define FW_DYNAMIC_INFO_OPTIONS_OFFSET (4 * __SIZEOF_LONG__)
#define FW_DYNAMIC_INFO_OPTIONS_OFFSET (4 * __SIZEOF_POINTER__)
/** Offset of boot_hart member in fw_dynamic_info (version >= 2) */
#define FW_DYNAMIC_INFO_BOOT_HART_OFFSET (5 * __SIZEOF_LONG__)
#define FW_DYNAMIC_INFO_BOOT_HART_OFFSET (5 * __SIZEOF_POINTER__)
/** Expected value of info magic ('OSBI' ascii string in hex) */
#define FW_DYNAMIC_INFO_MAGIC_VALUE 0x4942534f
/** Maximum supported info version */
#define FW_DYNAMIC_INFO_VERSION_2 0x2
#define FW_DYNAMIC_INFO_VERSION_MAX FW_DYNAMIC_INFO_VERSION_2
#define FW_DYNAMIC_INFO_VERSION_MAX 0x2
/** Possible next mode values */
#define FW_DYNAMIC_INFO_NEXT_MODE_U 0x0
@@ -75,41 +74,6 @@ struct fw_dynamic_info {
unsigned long boot_hart;
} __packed;
/**
* Prevent modification of struct fw_dynamic_info from affecting
* FW_DYNAMIC_INFO_xxx_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
#endif

View File

@@ -25,7 +25,7 @@
#define MSTATUS_MPP (_UL(3) << MSTATUS_MPP_SHIFT)
#define MSTATUS_FS _UL(0x00006000)
#define MSTATUS_XS _UL(0x00018000)
#define MSTATUS_VS _UL(0x00000600)
#define MSTATUS_VS _UL(0x01800000)
#define MSTATUS_MPRV _UL(0x00020000)
#define MSTATUS_SUM _UL(0x00040000)
#define MSTATUS_MXR _UL(0x00080000)
@@ -86,7 +86,6 @@
#define IRQ_VS_EXT 10
#define IRQ_M_EXT 11
#define IRQ_S_GEXT 12
#define IRQ_PMU_OVF 13
#define MIP_SSIP (_UL(1) << IRQ_S_SOFT)
#define MIP_VSSIP (_UL(1) << IRQ_VS_SOFT)
@@ -98,7 +97,6 @@
#define MIP_VSEIP (_UL(1) << IRQ_VS_EXT)
#define MIP_MEIP (_UL(1) << IRQ_M_EXT)
#define MIP_SGEIP (_UL(1) << IRQ_S_GEXT)
#define MIP_LCOFIP (_UL(1) << IRQ_PMU_OVF)
#define SIP_SSIP MIP_SSIP
#define SIP_STIP MIP_STIP
@@ -173,52 +171,6 @@
#define HGATP_MODE_SHIFT HGATP32_MODE_SHIFT
#endif
#define TOPI_IID_SHIFT 16
#define TOPI_IID_MASK 0xfff
#define TOPI_IPRIO_MASK 0xff
#if __riscv_xlen == 64
#define MHPMEVENT_OF (_UL(1) << 63)
#define MHPMEVENT_MINH (_UL(1) << 62)
#define MHPMEVENT_SINH (_UL(1) << 61)
#define MHPMEVENT_UINH (_UL(1) << 60)
#define MHPMEVENT_VSINH (_UL(1) << 59)
#define MHPMEVENT_VUINH (_UL(1) << 58)
#else
#define MHPMEVENTH_OF (_ULL(1) << 31)
#define MHPMEVENTH_MINH (_ULL(1) << 30)
#define MHPMEVENTH_SINH (_ULL(1) << 29)
#define MHPMEVENTH_UINH (_ULL(1) << 28)
#define MHPMEVENTH_VSINH (_ULL(1) << 27)
#define MHPMEVENTH_VUINH (_ULL(1) << 26)
#define MHPMEVENT_OF (MHPMEVENTH_OF << 32)
#define MHPMEVENT_MINH (MHPMEVENTH_MINH << 32)
#define MHPMEVENT_SINH (MHPMEVENTH_SINH << 32)
#define MHPMEVENT_UINH (MHPMEVENTH_UINH << 32)
#define MHPMEVENT_VSINH (MHPMEVENTH_VSINH << 32)
#define MHPMEVENT_VUINH (MHPMEVENTH_VUINH << 32)
#endif
#define MHPMEVENT_SSCOF_MASK _ULL(0xFFFF000000000000)
#if __riscv_xlen > 32
#define ENVCFG_STCE (_ULL(1) << 63)
#define ENVCFG_PBMTE (_ULL(1) << 62)
#else
#define ENVCFGH_STCE (_UL(1) << 31)
#define ENVCFGH_PBMTE (_UL(1) << 30)
#endif
#define ENVCFG_CBZE (_UL(1) << 7)
#define ENVCFG_CBCFE (_UL(1) << 6)
#define ENVCFG_CBIE_SHIFT 4
#define ENVCFG_CBIE (_UL(0x3) << ENVCFG_CBIE_SHIFT)
#define ENVCFG_CBIE_ILL _UL(0x0)
#define ENVCFG_CBIE_FLUSH _UL(0x1)
#define ENVCFG_CBIE_INV _UL(0x3)
#define ENVCFG_FIOM _UL(0x1)
/* ===== User-level CSRs ===== */
/* User Trap Setup (N-extension) */
@@ -314,9 +266,6 @@
#define CSR_STVEC 0x105
#define CSR_SCOUNTEREN 0x106
/* Supervisor Configuration */
#define CSR_SENVCFG 0x10a
/* Supervisor Trap Handling */
#define CSR_SSCRATCH 0x140
#define CSR_SEPC 0x141
@@ -324,31 +273,9 @@
#define CSR_STVAL 0x143
#define CSR_SIP 0x144
/* Sstc extension */
#define CSR_STIMECMP 0x14D
#define CSR_STIMECMPH 0x15D
/* Supervisor Protection and Translation */
#define CSR_SATP 0x180
/* Supervisor-Level Window to Indirectly Accessed Registers (AIA) */
#define CSR_SISELECT 0x150
#define CSR_SIREG 0x151
/* Supervisor-Level Interrupts (AIA) */
#define CSR_STOPEI 0x15c
#define CSR_STOPI 0xdb0
/* Supervisor-Level High-Half CSRs (AIA) */
#define CSR_SIEH 0x114
#define CSR_SIPH 0x154
/* Supervisor stateen CSRs */
#define CSR_SSTATEEN0 0x10C
#define CSR_SSTATEEN1 0x10D
#define CSR_SSTATEEN2 0x10E
#define CSR_SSTATEEN3 0x10F
/* ===== Hypervisor-level CSRs ===== */
/* Hypervisor Trap Setup (H-extension) */
@@ -359,10 +286,6 @@
#define CSR_HCOUNTEREN 0x606
#define CSR_HGEIE 0x607
/* Hypervisor Configuration */
#define CSR_HENVCFG 0x60a
#define CSR_HENVCFGH 0x61a
/* Hypervisor Trap Handling (H-extension) */
#define CSR_HTVAL 0x643
#define CSR_HIP 0x644
@@ -388,39 +311,6 @@
#define CSR_VSIP 0x244
#define CSR_VSATP 0x280
/* Virtual Interrupts and Interrupt Priorities (H-extension with AIA) */
#define CSR_HVIEN 0x608
#define CSR_HVICTL 0x609
#define CSR_HVIPRIO1 0x646
#define CSR_HVIPRIO2 0x647
/* VS-Level Window to Indirectly Accessed Registers (H-extension with AIA) */
#define CSR_VSISELECT 0x250
#define CSR_VSIREG 0x251
/* VS-Level Interrupts (H-extension with AIA) */
#define CSR_VSTOPEI 0x25c
#define CSR_VSTOPI 0xeb0
/* Hypervisor and VS-Level High-Half CSRs (H-extension with AIA) */
#define CSR_HIDELEGH 0x613
#define CSR_HVIENH 0x618
#define CSR_HVIPH 0x655
#define CSR_HVIPRIO1H 0x656
#define CSR_HVIPRIO2H 0x657
#define CSR_VSIEH 0x214
#define CSR_VSIPH 0x254
/* Hypervisor stateen CSRs */
#define CSR_HSTATEEN0 0x60C
#define CSR_HSTATEEN0H 0x61C
#define CSR_HSTATEEN1 0x60D
#define CSR_HSTATEEN1H 0x61D
#define CSR_HSTATEEN2 0x60E
#define CSR_HSTATEEN2H 0x61E
#define CSR_HSTATEEN3 0x60F
#define CSR_HSTATEEN3H 0x61F
/* ===== Machine-level CSRs ===== */
/* Machine Information Registers */
@@ -439,10 +329,6 @@
#define CSR_MCOUNTEREN 0x306
#define CSR_MSTATUSH 0x310
/* Machine Configuration */
#define CSR_MENVCFG 0x30a
#define CSR_MENVCFGH 0x31a
/* Machine Trap Handling */
#define CSR_MSCRATCH 0x340
#define CSR_MEPC 0x341
@@ -630,40 +516,6 @@
#define CSR_MHPMEVENT30 0x33e
#define CSR_MHPMEVENT31 0x33f
/* For RV32 */
#define CSR_MHPMEVENT3H 0x723
#define CSR_MHPMEVENT4H 0x724
#define CSR_MHPMEVENT5H 0x725
#define CSR_MHPMEVENT6H 0x726
#define CSR_MHPMEVENT7H 0x727
#define CSR_MHPMEVENT8H 0x728
#define CSR_MHPMEVENT9H 0x729
#define CSR_MHPMEVENT10H 0x72a
#define CSR_MHPMEVENT11H 0x72b
#define CSR_MHPMEVENT12H 0x72c
#define CSR_MHPMEVENT13H 0x72d
#define CSR_MHPMEVENT14H 0x72e
#define CSR_MHPMEVENT15H 0x72f
#define CSR_MHPMEVENT16H 0x730
#define CSR_MHPMEVENT17H 0x731
#define CSR_MHPMEVENT18H 0x732
#define CSR_MHPMEVENT19H 0x733
#define CSR_MHPMEVENT20H 0x734
#define CSR_MHPMEVENT21H 0x735
#define CSR_MHPMEVENT22H 0x736
#define CSR_MHPMEVENT23H 0x737
#define CSR_MHPMEVENT24H 0x738
#define CSR_MHPMEVENT25H 0x739
#define CSR_MHPMEVENT26H 0x73a
#define CSR_MHPMEVENT27H 0x73b
#define CSR_MHPMEVENT28H 0x73c
#define CSR_MHPMEVENT29H 0x73d
#define CSR_MHPMEVENT30H 0x73e
#define CSR_MHPMEVENT31H 0x73f
/* Counter Overflow CSR */
#define CSR_SCOUNTOVF 0xda0
/* Debug/Trace Registers */
#define CSR_TSELECT 0x7a0
#define CSR_TDATA1 0x7a1
@@ -676,36 +528,6 @@
#define CSR_DSCRATCH0 0x7b2
#define CSR_DSCRATCH1 0x7b3
/* Machine-Level Window to Indirectly Accessed Registers (AIA) */
#define CSR_MISELECT 0x350
#define CSR_MIREG 0x351
/* Machine-Level Interrupts (AIA) */
#define CSR_MTOPEI 0x35c
#define CSR_MTOPI 0xfb0
/* Virtual Interrupts for Supervisor Level (AIA) */
#define CSR_MVIEN 0x308
#define CSR_MVIP 0x309
/* Smstateen extension registers */
/* Machine stateen CSRs */
#define CSR_MSTATEEN0 0x30C
#define CSR_MSTATEEN0H 0x31C
#define CSR_MSTATEEN1 0x30D
#define CSR_MSTATEEN1H 0x31D
#define CSR_MSTATEEN2 0x30E
#define CSR_MSTATEEN2H 0x31E
#define CSR_MSTATEEN3 0x30F
#define CSR_MSTATEEN3H 0x31F
/* Machine-Level High-Half CSRs (AIA) */
#define CSR_MIDELEGH 0x313
#define CSR_MIEH 0x314
#define CSR_MVIENH 0x318
#define CSR_MVIPH 0x319
#define CSR_MIPH 0x354
/* ===== Trap/Exception Causes ===== */
#define CAUSE_MISALIGNED_FETCH 0x0
@@ -728,23 +550,6 @@
#define CAUSE_VIRTUAL_INST_FAULT 0x16
#define CAUSE_STORE_GUEST_PAGE_FAULT 0x17
/* Common defines for all smstateen */
#define SMSTATEEN_MAX_COUNT 4
#define SMSTATEEN0_CS_SHIFT 0
#define SMSTATEEN0_CS (_ULL(1) << SMSTATEEN0_CS_SHIFT)
#define SMSTATEEN0_FCSR_SHIFT 1
#define SMSTATEEN0_FCSR (_ULL(1) << SMSTATEEN0_FCSR_SHIFT)
#define SMSTATEEN0_IMSIC_SHIFT 58
#define SMSTATEEN0_IMSIC (_ULL(1) << SMSTATEEN0_IMSIC_SHIFT)
#define SMSTATEEN0_AIA_SHIFT 59
#define SMSTATEEN0_AIA (_ULL(1) << SMSTATEEN0_AIA_SHIFT)
#define SMSTATEEN0_SVSLCT_SHIFT 60
#define SMSTATEEN0_SVSLCT (_ULL(1) << SMSTATEEN0_SVSLCT_SHIFT)
#define SMSTATEEN0_HSENVCFG_SHIFT 62
#define SMSTATEEN0_HSENVCFG (_ULL(1) << SMSTATEEN0_HSENVCFG_SHIFT)
#define SMSTATEEN_STATEN_SHIFT 63
#define SMSTATEEN_STATEN (_ULL(1) << SMSTATEEN_STATEN_SHIFT)
/* ===== Instruction Encodings ===== */
#define INSN_MATCH_LB 0x3
@@ -820,29 +625,6 @@
#define INSN_MASK_WFI 0xffffff00
#define INSN_MATCH_WFI 0x10500000
#define INSN_MASK_FENCE_TSO 0xffffffff
#define INSN_MATCH_FENCE_TSO 0x8330000f
#if __riscv_xlen == 64
/* 64-bit read for VS-stage address translation (RV64) */
#define INSN_PSEUDO_VS_LOAD 0x00003000
/* 64-bit write for VS-stage address translation (RV64) */
#define INSN_PSEUDO_VS_STORE 0x00003020
#elif __riscv_xlen == 32
/* 32-bit read for VS-stage address translation (RV32) */
#define INSN_PSEUDO_VS_LOAD 0x00002000
/* 32-bit write for VS-stage address translation (RV32) */
#define INSN_PSEUDO_VS_STORE 0x00002020
#else
#error "Unexpected __riscv_xlen"
#endif
#define INSN_16BIT_MASK 0x3
#define INSN_32BIT_MASK 0x1c

View File

@@ -42,28 +42,15 @@
: "t0"); \
})
#define init_fp_reg(i) SET_F32_REG((i) << 3, 3, 0, 0)
#if __riscv_xlen == 64
#define GET_F64_REG(insn, pos, regs) \
({ \
register ulong value asm("a0") = SHIFT_RIGHT(insn, (pos)-3) & 0xf8; \
register ulong value asm("a0") = \
SHIFT_RIGHT(insn, (pos)-3) & 0xf8; \
ulong tmp; \
asm("1: auipc %0, %%pcrel_hi(get_f64_reg); add %0, %0, %1; jalr t0, %0, %%pcrel_lo(1b)" \
: "=&r"(tmp), "+&r"(value)::"t0"); \
value; \
sizeof(ulong) == 4 ? *(int64_t *)value : (int64_t)value; \
})
#else
#define GET_F64_REG(insn, pos, regs) \
({ \
u64 value; \
ulong offset = SHIFT_RIGHT(insn, (pos)-3) & 0xf8; \
register ulong ptr asm("a0") = (ulong)&value; \
asm ("1: auipc t1, %%pcrel_hi(get_f64_reg); add t1, t1, %2; jalr t0, t1, %%pcrel_lo(1b)" \
: "=m"(value) : "r"(ptr), "r"(offset) : "t0", "t1"); \
value; \
})
#endif
#define SET_F64_REG(insn, pos, regs, val) \
({ \
uint64_t __val = (val); \

View File

@@ -34,9 +34,9 @@ typedef struct {
#define DEFINE_SPIN_LOCK(x) \
spinlock_t SPIN_LOCK_INIT(x)
bool spin_lock_check(spinlock_t *lock);
int spin_lock_check(spinlock_t *lock);
bool spin_trylock(spinlock_t *lock);
int spin_trylock(spinlock_t *lock);
void spin_lock(spinlock_t *lock);

View File

@@ -37,12 +37,47 @@
(((~0UL) - (1UL << (l)) + 1) & (~0UL >> (BITS_PER_LONG - 1 - (h))))
/**
* sbi_ffs - find first (less-significant) set bit in a long word.
* ffs - Find first bit set
* @x: the word to search
*
* This is defined the same way as
* the libc and compiler builtin ffs routines, therefore
* differs in spirit from the above ffz (man ffs).
*/
static inline int ffs(int x)
{
int r = 1;
if (!x)
return 0;
if (!(x & 0xffff)) {
x >>= 16;
r += 16;
}
if (!(x & 0xff)) {
x >>= 8;
r += 8;
}
if (!(x & 0xf)) {
x >>= 4;
r += 4;
}
if (!(x & 3)) {
x >>= 2;
r += 2;
}
if (!(x & 1))
r += 1;
return r;
}
/**
* __ffs - find first bit in word.
* @word: The word to search
*
* Undefined if no bit exists, so code should check against 0 first.
*/
static inline int sbi_ffs(unsigned long word)
static inline int __ffs(unsigned long word)
{
int num = 0;
@@ -74,20 +109,55 @@ static inline int sbi_ffs(unsigned long word)
}
/*
* sbi_ffz - find first zero in word.
* ffz - find first zero in word.
* @word: The word to search
*
* Undefined if no zero exists, so code should check against ~0UL first.
*/
#define sbi_ffz(x) sbi_ffs(~(x))
#define ffz(x) __ffs(~(x))
/**
* sbi_fls - find last (most-significant) set bit in a long word
* fls - find last (most-significant) bit set
* @x: the word to search
*
* This is defined the same way as ffs.
* Note fls(0) = 0, fls(1) = 1, fls(0x80000000) = 32.
*/
static inline int fls(int x)
{
int r = 32;
if (!x)
return 0;
if (!(x & 0xffff0000u)) {
x <<= 16;
r -= 16;
}
if (!(x & 0xff000000u)) {
x <<= 8;
r -= 8;
}
if (!(x & 0xf0000000u)) {
x <<= 4;
r -= 4;
}
if (!(x & 0xc0000000u)) {
x <<= 2;
r -= 2;
}
if (!(x & 0x80000000u))
r -= 1;
return r;
}
/**
* __fls - find last (most-significant) set bit in a long word
* @word: the word to search
*
* Undefined if no set bit exists, so code should check against 0 first.
*/
static inline unsigned long sbi_fls(unsigned long word)
static inline unsigned long __fls(unsigned long word)
{
int num = BITS_PER_LONG - 1;

View File

@@ -43,8 +43,6 @@ int __printf(1, 2) sbi_printf(const char *format, ...);
int __printf(1, 2) sbi_dprintf(const char *format, ...);
void __printf(1, 2) __attribute__((noreturn)) sbi_panic(const char *format, ...);
const struct sbi_console_device *sbi_console_get_device(void);
void sbi_console_set_device(const struct sbi_console_device *dev);
@@ -53,9 +51,4 @@ struct sbi_scratch;
int sbi_console_init(struct sbi_scratch *scratch);
#define SBI_ASSERT(cond, args) do { \
if (unlikely(!(cond))) \
sbi_panic args; \
} while (0)
#endif

View File

@@ -78,6 +78,8 @@ struct sbi_domain {
unsigned long next_mode;
/** Is domain allowed to reset the system */
bool system_reset_allowed;
/** Is domain allowed to suspend the system */
bool system_suspend_allowed;
};
/** The root domain instance */
@@ -174,9 +176,7 @@ int sbi_domain_register(struct sbi_domain *dom,
* Add a memory region to the root domain
* @param reg pointer to the memory region to be added
*
* @return 0 on success
* @return SBI_EALREADY if memory region conflicts with existing
* @return SBI_EINVAL otherwise
* @return 0 on success and negative error code on failure
*/
int sbi_domain_root_add_memregion(const struct sbi_domain_memregion *reg);

View File

@@ -13,8 +13,8 @@
#include <sbi/sbi_types.h>
#include <sbi/sbi_list.h>
#define SBI_ECALL_VERSION_MAJOR 1
#define SBI_ECALL_VERSION_MINOR 0
#define SBI_ECALL_VERSION_MAJOR 0
#define SBI_ECALL_VERSION_MINOR 3
#define SBI_OPENSBI_IMPID 1
struct sbi_trap_regs;
@@ -39,7 +39,7 @@ extern struct sbi_ecall_extension ecall_ipi;
extern struct sbi_ecall_extension ecall_vendor;
extern struct sbi_ecall_extension ecall_hsm;
extern struct sbi_ecall_extension ecall_srst;
extern struct sbi_ecall_extension ecall_pmu;
extern struct sbi_ecall_extension ecall_susp;
u16 sbi_ecall_version_major(void);

View File

@@ -28,7 +28,7 @@
#define SBI_EXT_RFENCE 0x52464E43
#define SBI_EXT_HSM 0x48534D
#define SBI_EXT_SRST 0x53525354
#define SBI_EXT_PMU 0x504D55
#define SBI_EXT_SUSP 0x53555350
/* SBI function IDs for BASE extension*/
#define SBI_EXT_BASE_GET_SPEC_VERSION 0x0
@@ -38,6 +38,9 @@
#define SBI_EXT_BASE_GET_MVENDORID 0x4
#define SBI_EXT_BASE_GET_MARCHID 0x5
#define SBI_EXT_BASE_GET_MIMPID 0x6
#define SBI_EXT_BASE_RESET_C906L 0x7
#define SBI_EXT_BASE_RST_C906L 0x8
#define SBI_EXT_BASE_UNRST_C906L 0x9
/* SBI function IDs for TIME extension*/
#define SBI_EXT_TIME_SET_TIMER 0x0
@@ -92,139 +95,6 @@
#define SBI_SRST_RESET_REASON_NONE 0x0
#define SBI_SRST_RESET_REASON_SYSFAIL 0x1
/* SBI function IDs for PMU extension */
#define SBI_EXT_PMU_NUM_COUNTERS 0x0
#define SBI_EXT_PMU_COUNTER_GET_INFO 0x1
#define SBI_EXT_PMU_COUNTER_CFG_MATCH 0x2
#define SBI_EXT_PMU_COUNTER_START 0x3
#define SBI_EXT_PMU_COUNTER_STOP 0x4
#define SBI_EXT_PMU_COUNTER_FW_READ 0x5
/** General pmu event codes specified in SBI PMU extension */
enum sbi_pmu_hw_generic_events_t {
SBI_PMU_HW_NO_EVENT = 0,
SBI_PMU_HW_CPU_CYCLES = 1,
SBI_PMU_HW_INSTRUCTIONS = 2,
SBI_PMU_HW_CACHE_REFERENCES = 3,
SBI_PMU_HW_CACHE_MISSES = 4,
SBI_PMU_HW_BRANCH_INSTRUCTIONS = 5,
SBI_PMU_HW_BRANCH_MISSES = 6,
SBI_PMU_HW_BUS_CYCLES = 7,
SBI_PMU_HW_STALLED_CYCLES_FRONTEND = 8,
SBI_PMU_HW_STALLED_CYCLES_BACKEND = 9,
SBI_PMU_HW_REF_CPU_CYCLES = 10,
SBI_PMU_HW_GENERAL_MAX,
};
/**
* Generalized hardware cache events:
*
* { L1-D, L1-I, LLC, ITLB, DTLB, BPU, NODE } x
* { read, write, prefetch } x
* { accesses, misses }
*/
enum sbi_pmu_hw_cache_id {
SBI_PMU_HW_CACHE_L1D = 0,
SBI_PMU_HW_CACHE_L1I = 1,
SBI_PMU_HW_CACHE_LL = 2,
SBI_PMU_HW_CACHE_DTLB = 3,
SBI_PMU_HW_CACHE_ITLB = 4,
SBI_PMU_HW_CACHE_BPU = 5,
SBI_PMU_HW_CACHE_NODE = 6,
SBI_PMU_HW_CACHE_MAX,
};
enum sbi_pmu_hw_cache_op_id {
SBI_PMU_HW_CACHE_OP_READ = 0,
SBI_PMU_HW_CACHE_OP_WRITE = 1,
SBI_PMU_HW_CACHE_OP_PREFETCH = 2,
SBI_PMU_HW_CACHE_OP_MAX,
};
enum sbi_pmu_hw_cache_op_result_id {
SBI_PMU_HW_CACHE_RESULT_ACCESS = 0,
SBI_PMU_HW_CACHE_RESULT_MISS = 1,
SBI_PMU_HW_CACHE_RESULT_MAX,
};
/**
* Special "firmware" events provided by the OpenSBI, even if the hardware
* does not support performance events. These events are encoded as a raw
* event type in Linux kernel perf framework.
*/
enum sbi_pmu_fw_event_code_id {
SBI_PMU_FW_MISALIGNED_LOAD = 0,
SBI_PMU_FW_MISALIGNED_STORE = 1,
SBI_PMU_FW_ACCESS_LOAD = 2,
SBI_PMU_FW_ACCESS_STORE = 3,
SBI_PMU_FW_ILLEGAL_INSN = 4,
SBI_PMU_FW_SET_TIMER = 5,
SBI_PMU_FW_IPI_SENT = 6,
SBI_PMU_FW_IPI_RECVD = 7,
SBI_PMU_FW_FENCE_I_SENT = 8,
SBI_PMU_FW_FENCE_I_RECVD = 9,
SBI_PMU_FW_SFENCE_VMA_SENT = 10,
SBI_PMU_FW_SFENCE_VMA_RCVD = 11,
SBI_PMU_FW_SFENCE_VMA_ASID_SENT = 12,
SBI_PMU_FW_SFENCE_VMA_ASID_RCVD = 13,
SBI_PMU_FW_HFENCE_GVMA_SENT = 14,
SBI_PMU_FW_HFENCE_GVMA_RCVD = 15,
SBI_PMU_FW_HFENCE_GVMA_VMID_SENT = 16,
SBI_PMU_FW_HFENCE_GVMA_VMID_RCVD = 17,
SBI_PMU_FW_HFENCE_VVMA_SENT = 18,
SBI_PMU_FW_HFENCE_VVMA_RCVD = 19,
SBI_PMU_FW_HFENCE_VVMA_ASID_SENT = 20,
SBI_PMU_FW_HFENCE_VVMA_ASID_RCVD = 21,
SBI_PMU_FW_MAX,
};
/** SBI PMU event idx type */
enum sbi_pmu_event_type_id {
SBI_PMU_EVENT_TYPE_HW = 0x0,
SBI_PMU_EVENT_TYPE_HW_CACHE = 0x1,
SBI_PMU_EVENT_TYPE_HW_RAW = 0x2,
SBI_PMU_EVENT_TYPE_FW = 0xf,
SBI_PMU_EVENT_TYPE_MAX,
};
/** SBI PMU counter type */
enum sbi_pmu_ctr_type {
SBI_PMU_CTR_TYPE_HW = 0,
SBI_PMU_CTR_TYPE_FW,
};
/* Helper macros to decode event idx */
#define SBI_PMU_EVENT_IDX_OFFSET 20
#define SBI_PMU_EVENT_IDX_MASK 0xFFFFF
#define SBI_PMU_EVENT_IDX_CODE_MASK 0xFFFF
#define SBI_PMU_EVENT_IDX_TYPE_MASK 0xF0000
#define SBI_PMU_EVENT_RAW_IDX 0x20000
#define SBI_PMU_EVENT_IDX_INVALID 0xFFFFFFFF
/* Flags defined for config matching function */
#define SBI_PMU_CFG_FLAG_SKIP_MATCH (1 << 0)
#define SBI_PMU_CFG_FLAG_CLEAR_VALUE (1 << 1)
#define SBI_PMU_CFG_FLAG_AUTO_START (1 << 2)
#define SBI_PMU_CFG_FLAG_SET_VUINH (1 << 3)
#define SBI_PMU_CFG_FLAG_SET_VSINH (1 << 4)
#define SBI_PMU_CFG_FLAG_SET_UINH (1 << 5)
#define SBI_PMU_CFG_FLAG_SET_SINH (1 << 6)
#define SBI_PMU_CFG_FLAG_SET_MINH (1 << 7)
/* Flags defined for counter start function */
#define SBI_PMU_START_FLAG_SET_INIT_VALUE (1 << 0)
/* Flags defined for counter stop function */
#define SBI_PMU_STOP_FLAG_RESET (1 << 0)
/* 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
@@ -241,10 +111,15 @@ enum sbi_pmu_ctr_type {
#define SBI_ERR_DENIED -4
#define SBI_ERR_INVALID_ADDRESS -5
#define SBI_ERR_ALREADY_AVAILABLE -6
#define SBI_ERR_ALREADY_STARTED -7
#define SBI_ERR_ALREADY_STOPPED -8
#define SBI_LAST_ERR SBI_ERR_ALREADY_STOPPED
/* SBI function IDs for SUSP extension */
#define SBI_EXT_SUSP_SUSPEND 0x0
#define SBI_SUSP_SLEEP_TYPE_SUSPEND 0x0
#define SBI_SUSP_SLEEP_TYPE_LAST SBI_SUSP_SLEEP_TYPE_SUSPEND
#define SBI_SUSP_PLATFORM_SLEEP_START 0x80000000
#define SBI_LAST_ERR SBI_ERR_ALREADY_AVAILABLE
/* clang-format on */

View File

@@ -21,8 +21,6 @@
#define SBI_EDENIED SBI_ERR_DENIED
#define SBI_EINVALID_ADDR SBI_ERR_INVALID_ADDRESS
#define SBI_EALREADY SBI_ERR_ALREADY_AVAILABLE
#define SBI_EALREADY_STARTED SBI_ERR_ALREADY_STARTED
#define SBI_EALREADY_STOPPED SBI_ERR_ALREADY_STOPPED
#define SBI_ENODEV -1000
#define SBI_ENOSYS -1001

View File

@@ -33,8 +33,8 @@ int sbi_fifo_dequeue(struct sbi_fifo *fifo, void *data);
int sbi_fifo_enqueue(struct sbi_fifo *fifo, void *data);
void sbi_fifo_init(struct sbi_fifo *fifo, void *queue_mem, u16 entries,
u16 entry_size);
int sbi_fifo_is_empty(struct sbi_fifo *fifo);
int sbi_fifo_is_full(struct sbi_fifo *fifo);
bool sbi_fifo_is_empty(struct sbi_fifo *fifo);
bool sbi_fifo_is_full(struct sbi_fifo *fifo);
int sbi_fifo_inplace_update(struct sbi_fifo *fifo, void *in,
int (*fptr)(void *in, void *data));
u16 sbi_fifo_avail(struct sbi_fifo *fifo);

View File

@@ -12,33 +12,17 @@
#include <sbi/sbi_types.h>
/** Possible privileged specification versions of a hart */
enum sbi_hart_priv_versions {
/** Unknown privileged specification */
SBI_HART_PRIV_VER_UNKNOWN = 0,
/** Privileged specification v1.10 */
SBI_HART_PRIV_VER_1_10 = 1,
/** Privileged specification v1.11 */
SBI_HART_PRIV_VER_1_11 = 2,
/** Privileged specification v1.12 */
SBI_HART_PRIV_VER_1_12 = 3,
};
/** Possible feature flags of a hart */
enum sbi_hart_features {
/** Hart has S-mode counter enable */
SBI_HART_HAS_SCOUNTEREN = (1 << 0),
/** Hart has M-mode counter enable */
SBI_HART_HAS_MCOUNTEREN = (1 << 1),
/** HART has timer csr implementation in hardware */
SBI_HART_HAS_TIME = (1 << 2),
/** Possible ISA extensions of a hart */
enum sbi_hart_extensions {
/** Hart has Sscofpmt extension */
SBI_HART_EXT_SSCOFPMF = 0,
/** HART has HW time CSR (extension name not available) */
SBI_HART_EXT_TIME,
/** HART has AIA CSRs (extension name not available) */
SBI_HART_EXT_AIA,
/** HART has Smstateen CSR **/
SBI_HART_EXT_SMSTATEEN,
/** HART has Sstc extension */
SBI_HART_EXT_SSTC,
/** Maximum index of Hart extension */
SBI_HART_EXT_MAX,
/** Last index of Hart features*/
SBI_HART_HAS_LAST_FEATURE = SBI_HART_HAS_TIME,
};
struct sbi_scratch;
@@ -58,18 +42,10 @@ void sbi_hart_delegation_dump(struct sbi_scratch *scratch,
unsigned int sbi_hart_pmp_count(struct sbi_scratch *scratch);
unsigned long sbi_hart_pmp_granularity(struct sbi_scratch *scratch);
unsigned int sbi_hart_pmp_addrbits(struct sbi_scratch *scratch);
unsigned int sbi_hart_mhpm_bits(struct sbi_scratch *scratch);
int sbi_hart_pmp_configure(struct sbi_scratch *scratch);
int sbi_hart_priv_version(struct sbi_scratch *scratch);
void sbi_hart_get_priv_version_str(struct sbi_scratch *scratch,
char *version_str, int nvstr);
void sbi_hart_update_extension(struct sbi_scratch *scratch,
enum sbi_hart_extensions ext,
bool enable);
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_feature(struct sbi_scratch *scratch, unsigned long feature);
void sbi_hart_get_features_str(struct sbi_scratch *scratch,
char *features_str, int nfstr);
void __attribute__((noreturn)) sbi_hart_hang(void);

View File

@@ -12,14 +12,13 @@
#define __SBI_FENCE_H__
/** Invalidate Stage2 TLBs for given VMID and guest physical address */
void __sbi_hfence_gvma_vmid_gpa(unsigned long gpa_divby_4,
unsigned long vmid);
void __sbi_hfence_gvma_vmid_gpa(unsigned long gpa, unsigned long vmid);
/** Invalidate Stage2 TLBs for given VMID */
void __sbi_hfence_gvma_vmid(unsigned long vmid);
/** Invalidate Stage2 TLBs for given guest physical address */
void __sbi_hfence_gvma_gpa(unsigned long gpa_divby_4);
void __sbi_hfence_gvma_gpa(unsigned long gpa);
/** Invalidate all possible Stage2 TLBs */
void __sbi_hfence_gvma_all(void);

View File

@@ -34,17 +34,9 @@ struct sbi_hsm_device {
* the hart resumes normal execution.
*
* For successful non-retentive suspend, the hart will resume from
* the warm boot entry point.
* specified resume address
*/
int (*hart_suspend)(u32 suspend_type);
/**
* Perform platform-specific actions to resume from a suspended state.
*
* This includes restoring any platform state that was lost during
* non-retentive suspend.
*/
void (*hart_resume)(void);
int (*hart_suspend)(u32 suspend_type, ulong raddr);
};
struct sbi_domain;
@@ -65,9 +57,13 @@ void sbi_hsm_hart_resume_start(struct sbi_scratch *scratch);
void sbi_hsm_hart_resume_finish(struct sbi_scratch *scratch);
int sbi_hsm_hart_suspend(struct sbi_scratch *scratch, u32 suspend_type,
ulong raddr, ulong rmode, ulong priv);
int sbi_hsm_hart_change_state(struct sbi_scratch *scratch, long oldstate,
long newstate);
int __sbi_hsm_hart_get_state(u32 hartid);
int sbi_hsm_hart_get_state(const struct sbi_domain *dom, u32 hartid);
int sbi_hsm_hart_interruptible_mask(const struct sbi_domain *dom,
ulong hbase, ulong *out_hmask);
void __sbi_hsm_suspend_non_ret_save(struct sbi_scratch *scratch);
void sbi_hsm_prepare_next_jump(struct sbi_scratch *scratch, u32 hartid);
#endif

View File

@@ -1,44 +0,0 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2022 Ventana Micro Systems Inc.
*
* Authors:
* Anup Patel <apatel@ventanamicro.com>
*/
#ifndef __SBI_IRQCHIP_H__
#define __SBI_IRQCHIP_H__
#include <sbi/sbi_types.h>
struct sbi_scratch;
struct sbi_trap_regs;
/**
* Set external interrupt handling function
*
* This function is called by OpenSBI platform code to set a handler for
* external interrupts
*
* @param fn function pointer for handling external irqs
*/
void sbi_irqchip_set_irqfn(int (*fn)(struct sbi_trap_regs *regs));
/**
* Process external interrupts
*
* This function is called by sbi_trap_handler() to handle external
* interrupts.
*
* @param regs pointer for trap registers
*/
int sbi_irqchip_process(struct sbi_trap_regs *regs);
/** Initialize interrupt controllers */
int sbi_irqchip_init(struct sbi_scratch *scratch, bool cold_boot);
/** Exit interrupt controllers */
void sbi_irqchip_exit(struct sbi_scratch *scratch);
#endif

View File

@@ -43,17 +43,6 @@ static inline void __sbi_list_add(struct sbi_dlist *new,
next->prev = new;
}
/**
* Checks if the list is empty or not.
* @param head List head
*
* Retruns TRUE if list is empty, FALSE otherwise.
*/
static inline bool sbi_list_empty(struct sbi_dlist *head)
{
return head->next == head;
}
/**
* Adds the new node after the given head.
* @param new New node that needs to be added to list.

View File

@@ -64,9 +64,6 @@ enum sbi_platform_features {
/** Platform functions */
struct sbi_platform_operations {
/* Platform nascent initialization */
int (*nascent_init)(void);
/** Platform early initialization */
int (*early_init)(bool cold_boot);
/** Platform final initialization */
@@ -89,18 +86,9 @@ struct sbi_platform_operations {
*/
int (*misa_get_xlen)(void);
/** Initialize (or populate) HART extensions for the platform */
int (*extensions_init)(void);
/** Initialize (or populate) domains for the platform */
int (*domains_init)(void);
/** Initialize hw performance counters */
int (*pmu_init)(void);
/** Get platform specific mhpmevent value */
uint64_t (*pmu_xlate_to_mhpmevent)(uint32_t event_idx, uint64_t data);
/** Initialize the platform console */
int (*console_init)(void);
@@ -178,56 +166,6 @@ struct sbi_platform {
const u32 *hart_index2id;
};
/**
* Prevent modification of struct sbi_platform from affecting
* SBI_PLATFORM_xxx_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) \
((const struct sbi_platform *)((__s)->platform_addr))
@@ -355,23 +293,6 @@ static inline bool sbi_platform_hart_invalid(const struct sbi_platform *plat,
return FALSE;
}
/**
* Nascent (very early) initialization for current HART
*
* NOTE: This function can be used to do very early initialization of
* platform specific per-HART CSRs and devices.
*
* @param plat pointer to struct sbi_platform
*
* @return 0 on success and negative error code on failure
*/
static inline int sbi_platform_nascent_init(const struct sbi_platform *plat)
{
if (plat && sbi_platform_ops(plat)->nascent_init)
return sbi_platform_ops(plat)->nascent_init();
return 0;
}
/**
* Early initialization for current HART
*
@@ -456,21 +377,6 @@ static inline int sbi_platform_misa_xlen(const struct sbi_platform *plat)
return -1;
}
/**
* Initialize (or populate) HART extensions for the platform
*
* @param plat pointer to struct sbi_platform
*
* @return 0 on success and negative error code on failure
*/
static inline int sbi_platform_extensions_init(
const struct sbi_platform *plat)
{
if (plat && sbi_platform_ops(plat)->extensions_init)
return sbi_platform_ops(plat)->extensions_init();
return 0;
}
/**
* Initialize (or populate) domains for the platform
*
@@ -485,39 +391,6 @@ static inline int sbi_platform_domains_init(const struct sbi_platform *plat)
return 0;
}
/**
* Setup hw PMU events for the platform
*
* @param plat pointer to struct sbi_platform
*
* @return 0 on success and negative error code on failure
*/
static inline int sbi_platform_pmu_init(const struct sbi_platform *plat)
{
if (plat && sbi_platform_ops(plat)->pmu_init)
return sbi_platform_ops(plat)->pmu_init();
return 0;
}
/**
* Get the value to be written in mhpmeventx for event_idx
*
* @param plat pointer to struct sbi_platform
* @param event_idx ID of the PMU event
* @param data Additional configuration data passed from supervisor software
*
* @return expected value by the platform or 0 if platform doesn't know about
* the event
*/
static inline uint64_t sbi_platform_pmu_xlate_to_mhpmevent(const struct sbi_platform *plat,
uint32_t event_idx, uint64_t data)
{
if (plat && sbi_platform_ops(plat)->pmu_xlate_to_mhpmevent)
return sbi_platform_ops(plat)->pmu_xlate_to_mhpmevent(event_idx,
data);
return 0;
}
/**
* Initialize the platform console
*

View File

@@ -1,74 +0,0 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2021 Western Digital Corporation or its affiliates.
*
* Authors:
* Atish Patra <atish.patra@wdc.com>
*/
#ifndef __SBI_PMU_H__
#define __SBI_PMU_H__
#include <sbi/sbi_types.h>
#include <sbi/sbi_hartmask.h>
#include <sbi/sbi_scratch.h>
#include <sbi/sbi_ecall_interface.h>
/* Event related macros */
/* Maximum number of hardware events that can mapped by OpenSBI */
#define SBI_PMU_HW_EVENT_MAX 256
/* Maximum number of firmware events that can mapped by OpenSBI */
#define SBI_PMU_FW_EVENT_MAX 32
/* Counter related macros */
#define SBI_PMU_FW_CTR_MAX 16
#define SBI_PMU_HW_CTR_MAX 32
#define SBI_PMU_CTR_MAX (SBI_PMU_HW_CTR_MAX + SBI_PMU_FW_CTR_MAX)
#define SBI_PMU_FIXED_CTR_MASK 0x07
/** Initialize PMU */
int sbi_pmu_init(struct sbi_scratch *scratch, bool cold_boot);
/** Reset PMU during hart exit */
void sbi_pmu_exit(struct sbi_scratch *scratch);
/**
* Add the hardware event to counter mapping information. This should be called
* from the platform code to update the mapping table.
* @param eidx_start Start of the event idx range for supported counters
* @param eidx_end End of the event idx range for supported counters
* @param cmap A bitmap representing counters supporting the event range
* @return 0 on success, error otherwise.
*/
int sbi_pmu_add_hw_event_counter_map(u32 eidx_start, u32 eidx_end, u32 cmap);
/**
* Add the raw hardware event selector and supported counter information. This
* should be called from the platform code to update the mapping table.
* @param info a pointer to the hardware event info
* @return 0 on success, error otherwise.
*/
int sbi_pmu_add_raw_event_counter_map(uint64_t select, uint64_t select_mask, u32 cmap);
int sbi_pmu_ctr_read(uint32_t cidx, unsigned long *cval);
int sbi_pmu_ctr_stop(unsigned long cidx_base, unsigned long cidx_mask,
unsigned long flag);
int sbi_pmu_ctr_start(unsigned long cidx_base, unsigned long cidx_mask,
unsigned long flags, uint64_t ival);
int sbi_pmu_ctr_get_info(uint32_t cidx, unsigned long *ctr_info);
unsigned long sbi_pmu_num_ctr(void);
int sbi_pmu_ctr_cfg_match(unsigned long cidx_base, unsigned long cidx_mask,
unsigned long flags, unsigned long event_idx,
uint64_t event_data);
int sbi_pmu_ctr_incr_fw(enum sbi_pmu_fw_event_code_id fw_id);
#endif

View File

@@ -73,66 +73,6 @@ struct sbi_scratch {
unsigned long options;
};
/**
* Prevent modification of struct sbi_scratch from affecting
* SBI_SCRATCH_xxx_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_exit)
== SBI_SCRATCH_TRAP_EXIT_OFFSET,
"struct sbi_scratch definition has changed, please redefine "
"SBI_SCRATCH_TRAP_EXIT_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 {
/** Disable prints during boot */
@@ -158,17 +98,17 @@ int sbi_scratch_init(struct sbi_scratch *scratch);
* @return zero on failure and non-zero (>= SBI_SCRATCH_EXTRA_SPACE_OFFSET)
* on success
*/
unsigned long sbi_scratch_alloc_offset(unsigned long size);
unsigned long sbi_scratch_alloc_offset(unsigned long size, const char *owner);
/** Free-up extra space in sbi_scratch */
void sbi_scratch_free_offset(unsigned long offset);
/** Get pointer from offset in sbi_scratch */
#define sbi_scratch_offset_ptr(scratch, offset) (void *)((char *)(scratch) + (offset))
#define sbi_scratch_offset_ptr(scratch, offset) ((void *)scratch + (offset))
/** Get pointer from offset in sbi_scratch for current HART */
#define sbi_scratch_thishart_offset_ptr(offset) \
(void *)((char *)sbi_scratch_thishart_ptr() + (offset))
((void *)sbi_scratch_thishart_ptr() + (offset))
/** HART id to scratch table */
extern struct sbi_scratch *hartid_to_scratch_table[];

View File

@@ -11,7 +11,6 @@
#define __SBI_SYSTEM_H__
#include <sbi/sbi_types.h>
#include <sbi/sbi_list.h>
/** System reset hardware device */
struct sbi_system_reset_device {
@@ -23,24 +22,40 @@ struct sbi_system_reset_device {
/** Reset the system */
void (*system_reset)(u32 reset_type, u32 reset_reason);
/** List */
struct sbi_dlist node;
};
static inline struct sbi_system_reset_device *to_system_reset_device(
struct sbi_dlist *node)
{
return container_of(node, struct sbi_system_reset_device, node);
}
const struct sbi_system_reset_device *sbi_system_reset_get_device(void);
const struct sbi_system_reset_device *sbi_system_reset_get_device(
u32 reset_type, u32 reset_reason);
void sbi_system_reset_add_device(struct sbi_system_reset_device *dev);
void sbi_system_reset_set_device(const struct sbi_system_reset_device *dev);
bool sbi_system_reset_supported(u32 reset_type, u32 reset_reason);
void __noreturn sbi_system_reset(u32 reset_type, u32 reset_reason);
/** System suspend device */
struct sbi_system_suspend_device {
/** Name of the system suspend device */
char name[32];
/* Check whether sleep type is supported by the device */
int (*system_suspend_check)(u32 sleep_type);
/**
* Suspend the system
*
* @sleep_type: The sleep type identifier passed to the SBI call.
* @mmode_resume_addr:
* This is the same as sbi_scratch.warmboot_addr. Some platforms
* may not be able to return from system_suspend(), so they will
* jump directly to this address instead. Platforms which can
* return from system_suspend() may ignore this parameter.
*/
int (*system_suspend)(u32 sleep_type, unsigned long mmode_resume_addr);
};
const struct sbi_system_suspend_device *sbi_system_suspend_get_device(void);
void sbi_system_suspend_set_device(struct sbi_system_suspend_device *dev);
bool sbi_system_suspend_supported(u32 sleep_type);
int sbi_system_suspend(u32 sleep_type, ulong resume_addr, ulong opaque);
#endif

View File

@@ -17,9 +17,6 @@ struct sbi_timer_device {
/** Name of the timer operations */
char name[32];
/** Frequency of timer in HZ */
unsigned long timer_freq;
/** Get free-running timer value */
u64 (*timer_value)(void);
@@ -32,22 +29,6 @@ struct sbi_timer_device {
struct sbi_scratch;
/** Generic delay loop of desired granularity */
void sbi_timer_delay_loop(ulong units, u64 unit_freq,
void (*delay_fn)(void *), void *opaque);
/** Provide delay in terms of milliseconds */
static inline void sbi_timer_mdelay(ulong msecs)
{
sbi_timer_delay_loop(msecs, 1000, NULL, NULL);
}
/** Provide delay in terms of microseconds */
static inline void sbi_timer_udelay(ulong usecs)
{
sbi_timer_delay_loop(usecs, 1000000, NULL, NULL);
}
/** Get timer value for current HART */
u64 sbi_timer_value(void);

View File

@@ -68,14 +68,8 @@ typedef unsigned long physical_size_t;
#define likely(x) __builtin_expect((x), 1)
#define unlikely(x) __builtin_expect((x), 0)
#ifndef __has_builtin
#define __has_builtin(...) 0
#endif
#undef offsetof
#if __has_builtin(__builtin_offsetof)
#define offsetof(TYPE, MEMBER) __builtin_offsetof(TYPE,MEMBER)
#elif defined(__compiler_offsetof)
#ifdef __compiler_offsetof
#define offsetof(TYPE, MEMBER) __compiler_offsetof(TYPE,MEMBER)
#else
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)

View File

@@ -10,8 +10,8 @@
#ifndef __SBI_VERSION_H__
#define __SBI_VERSION_H__
#define OPENSBI_VERSION_MAJOR 1
#define OPENSBI_VERSION_MINOR 1
#define OPENSBI_VERSION_MAJOR 0
#define OPENSBI_VERSION_MINOR 9
/**
* OpenSBI 32-bit version with:

View File

@@ -21,30 +21,6 @@
*/
void fdt_cpu_fixup(void *fdt);
/**
* Fix up the APLIC nodes in the device tree
*
* This routine disables APLIC nodes which are not accessible to the next
* booting stage based on currently assigned domain.
*
* It is recommended that platform codes call this helper in their final_init()
*
* @param fdt: device tree blob
*/
void fdt_aplic_fixup(void *fdt);
/**
* Fix up the IMSIC nodes in the device tree
*
* This routine disables IMSIC nodes which are not accessible to the next
* booting stage based on currently assigned domain.
*
* It is recommended that platform codes call this helper in their final_init()
*
* @param fdt: device tree blob
*/
void fdt_imsic_fixup(void *fdt);
/**
* Fix up the PLIC node in the device tree
*
@@ -88,9 +64,8 @@ int fdt_reserved_memory_nomap_fixup(void *fdt);
* General device tree fix-up
*
* This routine do all required device tree fix-ups for a typical platform.
* It fixes up the PLIC node, IMSIC nodes, APLIC nodes, and the reserved
* memory node in the device tree by calling the corresponding helper
* routines to accomplish the task.
* It fixes up the PLIC node and the reserved memory node in the device tree
* by calling the corresponding helper routines to accomplish the task.
*
* It is recommended that platform codes call this helper in their final_init()
*

View File

@@ -11,18 +11,10 @@
#define __FDT_HELPER_H__
#include <sbi/sbi_types.h>
#include <sbi/sbi_scratch.h>
struct fdt_match {
const char *compatible;
const void *data;
};
#define FDT_MAX_PHANDLE_ARGS 16
struct fdt_phandle_args {
int node_offset;
int args_count;
u32 args[FDT_MAX_PHANDLE_ARGS];
void *data;
};
struct platform_uart_data {
@@ -31,7 +23,6 @@ struct platform_uart_data {
unsigned long baud;
unsigned long reg_shift;
unsigned long reg_io_width;
unsigned long reg_offset;
};
const struct fdt_match *fdt_match_node(void *fdt, int nodeoff,
@@ -41,23 +32,12 @@ int fdt_find_match(void *fdt, int startoff,
const struct fdt_match *match_table,
const struct fdt_match **out_match);
int fdt_parse_phandle_with_args(void *fdt, int nodeoff,
const char *prop, const char *cells_prop,
int index, struct fdt_phandle_args *out_args);
int fdt_get_node_addr_size(void *fdt, int node, int index,
uint64_t *addr, uint64_t *size);
bool fdt_node_is_enabled(void *fdt, int nodeoff);
int fdt_get_node_addr_size(void *fdt, int node, unsigned long *addr,
unsigned long *size);
int fdt_parse_hart_id(void *fdt, int cpu_offset, u32 *hartid);
int fdt_parse_max_enabled_hart_id(void *fdt, u32 *max_hartid);
int fdt_parse_timebase_frequency(void *fdt, unsigned long *freq);
int fdt_parse_gaisler_uart_node(void *fdt, int nodeoffset,
struct platform_uart_data *uart);
int fdt_parse_max_hart_id(void *fdt, u32 *max_hartid);
int fdt_parse_shakti_uart_node(void *fdt, int nodeoffset,
struct platform_uart_data *uart);
@@ -71,36 +51,18 @@ int fdt_parse_uart8250_node(void *fdt, int nodeoffset,
int fdt_parse_uart8250(void *fdt, struct platform_uart_data *uart,
const char *compatible);
int fdt_parse_xlnx_uartlite_node(void *fdt, int nodeoffset,
struct platform_uart_data *uart);
struct aplic_data;
int fdt_parse_aplic_node(void *fdt, int nodeoff, struct aplic_data *aplic);
struct imsic_data;
bool fdt_check_imsic_mlevel(void *fdt);
int fdt_parse_imsic_node(void *fdt, int nodeoff, struct imsic_data *imsic);
struct plic_data;
int fdt_parse_plic_node(void *fdt, int nodeoffset, struct plic_data *plic);
int fdt_parse_plic(void *fdt, struct plic_data *plic, const char *compat);
int fdt_parse_aclint_node(void *fdt, int nodeoffset, bool for_timer,
unsigned long *out_addr1, unsigned long *out_size1,
unsigned long *out_addr2, unsigned long *out_size2,
u32 *out_first_hartid, u32 *out_hart_count);
struct clint_data;
int fdt_parse_compat_addr(void *fdt, uint64_t *addr,
int fdt_parse_clint_node(void *fdt, int nodeoffset, bool for_timer,
struct clint_data *clint);
int fdt_parse_compat_addr(void *fdt, unsigned long *addr,
const char *compatible);
static inline void *fdt_get_address(void)
{
return sbi_scratch_thishart_arg1_ptr();
}
#endif /* __FDT_HELPER_H__ */

View File

@@ -1,46 +0,0 @@
// SPDX-License-Identifier: BSD-2-Clause
/*
* fdt_pmu.c - Flat Device Tree PMU helper routines
*
* Copyright (c) 2021 Western Digital Corporation or its affiliates.
*
* Authors:
* Atish Patra <atish.patra@wdc.com>
*/
#ifndef __FDT_PMU_H__
#define __FDT_PMU_H__
#include <sbi/sbi_types.h>
/**
* Fix up the PMU node in the device tree
*
* This routine:
* 1. Disables opensbi specific properties from the DT
*
* It is recommended that platform support call this function in
* their final_init() platform operation.
*
* @param fdt device tree blob
*/
void fdt_pmu_fixup(void *fdt);
/**
* Setup PMU data from device tree
*
* @param fdt device tree blob
*
* @return 0 on success and negative error code on failure
*/
int fdt_pmu_setup(void *fdt);
/**
* Get the mhpmevent select value read from DT for a given event
* @param event_idx Event ID of the given event
*
* @return The select value read from DT or 0 if given index was not found
*/
uint64_t fdt_pmu_get_select_value(uint32_t event_idx);
#endif

View File

@@ -1,36 +0,0 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2021 Western Digital Corporation or its affiliates.
*
* Authors:
* Anup Patel <anup.patel@wdc.com>
*/
#ifndef __FDT_GPIO_H__
#define __FDT_GPIO_H__
#include <sbi_utils/gpio/gpio.h>
struct fdt_phandle_args;
/** FDT based GPIO driver */
struct fdt_gpio {
const struct fdt_match *match_table;
int (*xlate)(struct gpio_chip *chip,
const struct fdt_phandle_args *pargs,
struct gpio_pin *out_pin);
int (*init)(void *fdt, int nodeoff, u32 phandle,
const struct fdt_match *match);
};
/** Get a GPIO pin using "gpios" DT property of client DT node */
int fdt_gpio_pin_get(void *fdt, int nodeoff, int index,
struct gpio_pin *out_pin);
/** Simple xlate function to convert two GPIO FDT cells into GPIO pin */
int fdt_gpio_simple_xlate(struct gpio_chip *chip,
const struct fdt_phandle_args *pargs,
struct gpio_pin *out_pin);
#endif

View File

@@ -1,107 +0,0 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2021 Western Digital Corporation or its affiliates.
*
* Authors:
* Anup Patel <anup.patel@wdc.com>
*/
#ifndef __GPIO_H__
#define __GPIO_H__
#include <sbi/sbi_types.h>
#include <sbi/sbi_list.h>
#define GPIO_LINE_DIRECTION_IN 1
#define GPIO_LINE_DIRECTION_OUT 0
/** Representation of a GPIO pin */
struct gpio_pin {
/** Pointer to the GPIO chip */
struct gpio_chip *chip;
/** Identification of GPIO pin within GPIO chip */
unsigned int offset;
/**
* Additional configuration flags of the GPIO pin desired
* by GPIO clients.
*
* NOTE: GPIO chip can have custom configuration flags.
*/
unsigned int flags;
#define GPIO_FLAG_ACTIVE_LOW 0x1
#define GPIO_FLAG_SINGLE_ENDED 0x2
#define GPIO_FLAG_OPEN_DRAIN 0x4
#define GPIO_FLAG_TRANSITORY 0x8
#define GPIO_FLAG_PULL_UP 0x10
#define GPIO_FLAG_PULL_DOWN 0x20
};
/** Representation of a GPIO chip */
struct gpio_chip {
/** Pointer to GPIO driver owning this GPIO chip */
void *driver;
/** Uniquie ID of the GPIO chip assigned by the driver */
unsigned int id;
/** Number of GPIOs supported by the GPIO chip */
unsigned int ngpio;
/**
* Get current direction of GPIO pin
*
* @return 0=output, 1=input, or negative error
*/
int (*get_direction)(struct gpio_pin *gp);
/**
* Set input direction of GPIO pin
*
* @return 0 on success and negative error code on failure
*/
int (*direction_input)(struct gpio_pin *gp);
/**
* Set output direction of GPIO pin with given output value
*
* @return 0 on success and negative error code on failure
*/
int (*direction_output)(struct gpio_pin *gp, int value);
/**
* Get current value of GPIO pin
*
* @return 0=low, 1=high, or negative error
*/
int (*get)(struct gpio_pin *gp);
/** Set output value for GPIO pin */
void (*set)(struct gpio_pin *gp, int value);
/** List */
struct sbi_dlist node;
};
static inline struct gpio_chip *to_gpio_chip(struct sbi_dlist *node)
{
return container_of(node, struct gpio_chip, node);
}
/** Find a registered GPIO chip */
struct gpio_chip *gpio_chip_find(unsigned int id);
/** Register GPIO chip */
int gpio_chip_add(struct gpio_chip *gc);
/** Un-register GPIO chip */
void gpio_chip_remove(struct gpio_chip *gc);
/** Get current direction of GPIO pin */
int gpio_get_direction(struct gpio_pin *gp);
/** Set input direction of GPIO pin */
int gpio_direction_input(struct gpio_pin *gp);
/** Set output direction of GPIO pin */
int gpio_direction_output(struct gpio_pin *gp, int value);
/** Get current value of GPIO pin */
int gpio_get(struct gpio_pin *gp);
/** Set output value of GPIO pin */
int gpio_set(struct gpio_pin *gp, int value);
#endif

View File

@@ -1,26 +0,0 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2021 YADRO
*
* Authors:
* Nikita Shubin <n.shubin@yadro.com>
*/
#ifndef __FDT_I2C_H__
#define __FDT_I2C_H__
#include <sbi_utils/i2c/i2c.h>
/** FDT based I2C adapter driver */
struct fdt_i2c_adapter {
const struct fdt_match *match_table;
int (*init)(void *fdt, int nodeoff,
const struct fdt_match *match);
};
/** Get I2C adapter identified by nodeoff */
int fdt_i2c_adapter_get(void *fdt, int nodeoff,
struct i2c_adapter **out_adapter);
#endif

View File

@@ -1,85 +0,0 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2021 YADRO
*
* Authors:
* Nikita Shubin <n.shubin@yadro.com>
*/
#ifndef __I2C_H__
#define __I2C_H__
#include <sbi/sbi_types.h>
#include <sbi/sbi_list.h>
/** Representation of a I2C adapter */
struct i2c_adapter {
/** Pointer to I2C driver owning this I2C adapter */
void *driver;
/** Unique ID of the I2C adapter assigned by the driver */
int id;
/**
* Send buffer to given address, register
*
* @return 0 on success and negative error code on failure
*/
int (*write)(struct i2c_adapter *ia, uint8_t addr, uint8_t reg,
uint8_t *buffer, int len);
/**
* Read buffer from given address, register
*
* @return 0 on success and negative error code on failure
*/
int (*read)(struct i2c_adapter *ia, uint8_t addr, uint8_t reg,
uint8_t *buffer, int len);
/** List */
struct sbi_dlist node;
};
static inline struct i2c_adapter *to_i2c_adapter(struct sbi_dlist *node)
{
return container_of(node, struct i2c_adapter, node);
}
/** Find a registered I2C adapter */
struct i2c_adapter *i2c_adapter_find(int id);
/** Register I2C adapter */
int i2c_adapter_add(struct i2c_adapter *ia);
/** Un-register I2C adapter */
void i2c_adapter_remove(struct i2c_adapter *ia);
/** Send to device on I2C adapter bus */
int i2c_adapter_write(struct i2c_adapter *ia, uint8_t addr, uint8_t reg,
uint8_t *buffer, int len);
/** Read from device on I2C adapter bus */
int i2c_adapter_read(struct i2c_adapter *ia, uint8_t addr, uint8_t reg,
uint8_t *buffer, int len);
static inline int i2c_adapter_reg_write(struct i2c_adapter *ia, uint8_t addr,
uint8_t reg, uint8_t val)
{
return i2c_adapter_write(ia, addr, reg, &val, 1);
}
static inline int i2c_adapter_reg_read(struct i2c_adapter *ia, uint8_t addr,
uint8_t reg, uint8_t *val)
{
uint8_t buf;
int ret = i2c_adapter_read(ia, addr, reg, &buf, 1);
if (ret)
return ret;
*val = buf;
return 0;
}
#endif

View File

@@ -1,33 +0,0 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2021 Western Digital Corporation or its affiliates.
*
* Authors:
* Anup Patel <anup.patel@wdc.com>
*/
#ifndef __IPI_ACLINT_MSWI_H__
#define __IPI_ACLINT_MSWI_H__
#include <sbi/sbi_types.h>
#define ACLINT_MSWI_ALIGN 0x1000
#define ACLINT_MSWI_SIZE 0x4000
#define ACLINT_MSWI_MAX_HARTS 4095
#define CLINT_MSWI_OFFSET 0x0000
struct aclint_mswi_data {
/* Public details */
unsigned long addr;
unsigned long size;
u32 first_hartid;
u32 hart_count;
};
int aclint_mswi_warm_init(void);
int aclint_mswi_cold_init(struct aclint_mswi_data *mswi);
#endif

View File

@@ -1,47 +0,0 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2021 Western Digital Corporation or its affiliates.
* Copyright (c) 2022 Ventana Micro Systems Inc.
*
* Authors:
* Anup Patel <anup.patel@wdc.com>
*/
#ifndef __IRQCHIP_APLIC_H__
#define __IRQCHIP_APLIC_H__
#include <sbi/sbi_types.h>
#define APLIC_MAX_DELEGATE 16
struct aplic_msicfg_data {
unsigned long lhxs;
unsigned long lhxw;
unsigned long hhxs;
unsigned long hhxw;
unsigned long base_addr;
};
struct aplic_delegate_data {
u32 first_irq;
u32 last_irq;
u32 child_index;
};
struct aplic_data {
unsigned long addr;
unsigned long size;
unsigned long num_idc;
unsigned long num_source;
bool targets_mmode;
bool has_msicfg_mmode;
struct aplic_msicfg_data msicfg_mmode;
bool has_msicfg_smode;
struct aplic_msicfg_data msicfg_smode;
struct aplic_delegate_data delegate[APLIC_MAX_DELEGATE];
};
int aplic_cold_irqchip_init(struct aplic_data *aplic);
#endif

View File

@@ -1,22 +0,0 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2022 Samuel Holland <samuel@sholland.org>
*/
#ifndef __IRQCHIP_FDT_IRQCHIP_PLIC_H__
#define __IRQCHIP_FDT_IRQCHIP_PLIC_H__
#include <sbi/sbi_types.h>
void fdt_plic_priority_save(u8 *priority);
void fdt_plic_priority_restore(const u8 *priority);
void fdt_plic_context_save(bool smode, u32 *enable, u32 *threshold);
void fdt_plic_context_restore(bool smode, const u32 *enable, u32 threshold);
void thead_plic_restore(void);
#endif

View File

@@ -1,50 +0,0 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2021 Western Digital Corporation or its affiliates.
* Copyright (c) 2022 Ventana Micro Systems Inc.
*
* Authors:
* Anup Patel <anup.patel@wdc.com>
*/
#ifndef __IRQCHIP_IMSIC_H__
#define __IRQCHIP_IMSIC_H__
#include <sbi/sbi_types.h>
#define IMSIC_MMIO_PAGE_SHIFT 12
#define IMSIC_MMIO_PAGE_SZ (1UL << IMSIC_MMIO_PAGE_SHIFT)
#define IMSIC_MAX_REGS 16
struct imsic_regs {
unsigned long addr;
unsigned long size;
};
struct imsic_data {
bool targets_mmode;
u32 guest_index_bits;
u32 hart_index_bits;
u32 group_index_bits;
u32 group_index_shift;
unsigned long num_ids;
struct imsic_regs regs[IMSIC_MAX_REGS];
};
int imsic_map_hartid_to_data(u32 hartid, struct imsic_data *imsic, int file);
struct imsic_data *imsic_get_data(u32 hartid);
int imsic_get_target_file(u32 hartid);
void imsic_local_irqchip_init(void);
int imsic_warm_irqchip_init(void);
int imsic_data_check(struct imsic_data *imsic);
int imsic_cold_irqchip_init(struct imsic_data *imsic);
#endif

View File

@@ -17,23 +17,13 @@ struct plic_data {
unsigned long num_src;
};
/* So far, priorities on all consumers of these functions fit in 8 bits. */
void plic_priority_save(const struct plic_data *plic, u8 *priority);
void plic_priority_restore(const struct plic_data *plic, const u8 *priority);
void plic_context_save(const struct plic_data *plic, int context_id,
u32 *enable, u32 *threshold);
void plic_context_restore(const struct plic_data *plic, int context_id,
const u32 *enable, u32 threshold);
int plic_context_init(const struct plic_data *plic, int context_id,
bool enable, u32 threshold);
int plic_warm_irqchip_init(const struct plic_data *plic,
int plic_warm_irqchip_init(struct plic_data *plic,
int m_cntx_id, int s_cntx_id);
int plic_cold_irqchip_init(const struct plic_data *plic);
int plic_cold_irqchip_init(struct plic_data *plic);
void plic_set_thresh(struct plic_data *plic, u32 cntxid, u32 val);
void plic_set_ie(struct plic_data *plic, u32 cntxid, u32 word_index, u32 val);
#endif

View File

@@ -17,16 +17,6 @@ struct fdt_reset {
int (*init)(void *fdt, int nodeoff, const struct fdt_match *match);
};
/**
* fdt_reset_driver_init() - initialize reset driver based on the device-tree
*/
int fdt_reset_driver_init(void *fdt, struct fdt_reset *drv);
/**
* fdt_reset_init() - initialize reset drivers based on the device-tree
*
* This function shall be invoked in final init.
*/
void fdt_reset_init(void);
int fdt_reset_init(void);
#endif

View File

@@ -1,17 +0,0 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2021 Cobham Gaisler AB.
*
* Authors:
* Daniel Cederman <cederman@gaisler.com>
*/
#ifndef __SERIAL_GAISLER_APBUART_H__
#define __SERIAL_GAISLER_APBUART_H__
#include <sbi/sbi_types.h>
int gaisler_uart_init(unsigned long base, u32 in_freq, u32 baudrate);
#endif

View File

@@ -1,17 +0,0 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2021 Gabriel Somlo
*
* Authors:
* Gabriel Somlo <gsomlo@gmail.com>
*/
#ifndef __SERIAL_LITEX_UART_H__
#define __SERIAL_LITEX_UART_H__
#include <sbi/sbi_types.h>
int litex_uart_init(unsigned long base);
#endif

View File

@@ -13,6 +13,6 @@
#include <sbi/sbi_types.h>
int uart8250_init(unsigned long base, u32 in_freq, u32 baudrate, u32 reg_shift,
u32 reg_width, u32 reg_offset);
u32 reg_width);
#endif

View File

@@ -1,16 +0,0 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2022 Western Digital Corporation or its affiliates.
*
* Authors:
* Alistair Francis <alistair.francis@wdc.com>
*/
#ifndef __SERIAL_XLNX_UARTLITE_H__
#define __SERIAL_XLNX_UARTLITE_H__
#include <sbi/sbi_types.h>
int xlnx_uartlite_init(unsigned long base);
#endif

View File

@@ -0,0 +1,41 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2019 Western Digital Corporation or its affiliates.
*
* Authors:
* Anup Patel <anup.patel@wdc.com>
*/
#ifndef __SYS_CLINT_H__
#define __SYS_CLINT_H__
#include <sbi/sbi_types.h>
struct clint_data {
/* Public details */
unsigned long addr;
u32 first_hartid;
u32 hart_count;
bool has_64bit_mmio;
/* Private details (initialized and used by CLINT library)*/
u32 *ipi;
struct clint_data *time_delta_reference;
unsigned long time_delta_computed;
u64 time_delta;
u64 *time_val;
u64 *time_cmp;
u64 (*time_rd)(volatile u64 *addr);
void (*time_wr)(u64 value, volatile u64 *addr);
};
int clint_warm_ipi_init(void);
int clint_cold_ipi_init(struct clint_data *clint);
int clint_warm_timer_init(void);
int clint_cold_timer_init(struct clint_data *clint,
struct clint_data *reference);
#endif

View File

@@ -10,12 +10,8 @@
#include <sbi/sbi_types.h>
int htif_serial_init(bool custom_addr,
unsigned long custom_fromhost_addr,
unsigned long custom_tohost_addr);
int htif_serial_init(void);
int htif_system_reset_init(bool custom_addr,
unsigned long custom_fromhost_addr,
unsigned long custom_tohost_addr);
int htif_system_reset_init(void);
#endif

View File

@@ -1,53 +0,0 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2021 Western Digital Corporation or its affiliates.
*
* Authors:
* Anup Patel <anup.patel@wdc.com>
*/
#ifndef __TIMER_ACLINT_MTIMER_H__
#define __TIMER_ACLINT_MTIMER_H__
#include <sbi/sbi_types.h>
#define ACLINT_MTIMER_ALIGN 0x8
#define ACLINT_MTIMER_MAX_HARTS 4095
#define ACLINT_DEFAULT_MTIME_OFFSET 0x7ff8
#define ACLINT_DEFAULT_MTIME_SIZE 0x8
#define ACLINT_DEFAULT_MTIMECMP_OFFSET 0x0000
#define ACLINT_DEFAULT_MTIMECMP_SIZE 0x7ff8
#define CLINT_MTIMER_OFFSET 0x4000
struct aclint_mtimer_data {
/* Public details */
unsigned long mtime_freq;
unsigned long mtime_addr;
unsigned long mtime_size;
unsigned long mtimecmp_addr;
unsigned long mtimecmp_size;
u32 first_hartid;
u32 hart_count;
bool has_64bit_mmio;
bool has_shared_mtime;
/* Private details (initialized and used by ACLINT MTIMER library) */
struct aclint_mtimer_data *time_delta_reference;
unsigned long time_delta_computed;
u64 (*time_rd)(volatile u64 *addr);
void (*time_wr)(bool timecmp, u64 value, volatile u64 *addr);
};
void aclint_mtimer_sync(struct aclint_mtimer_data *mt);
void aclint_mtimer_set_reference(struct aclint_mtimer_data *mt,
struct aclint_mtimer_data *ref);
int aclint_mtimer_warm_init(void);
int aclint_mtimer_cold_init(struct aclint_mtimer_data *mt,
struct aclint_mtimer_data *reference);
#endif

View File

@@ -20,9 +20,9 @@ libsbi-objs-y += sbi_ecall.o
libsbi-objs-y += sbi_ecall_base.o
libsbi-objs-y += sbi_ecall_hsm.o
libsbi-objs-y += sbi_ecall_legacy.o
libsbi-objs-y += sbi_ecall_pmu.o
libsbi-objs-y += sbi_ecall_replace.o
libsbi-objs-y += sbi_ecall_vendor.o
libsbi-objs-y += sbi_ecall_susp.o
libsbi-objs-y += sbi_emulate_csr.o
libsbi-objs-y += sbi_fifo.o
libsbi-objs-y += sbi_hart.o
@@ -32,10 +32,8 @@ libsbi-objs-y += sbi_hsm.o
libsbi-objs-y += sbi_illegal_insn.o
libsbi-objs-y += sbi_init.o
libsbi-objs-y += sbi_ipi.o
libsbi-objs-y += sbi_irqchip.o
libsbi-objs-y += sbi_misaligned_ldst.o
libsbi-objs-y += sbi_platform.o
libsbi-objs-y += sbi_pmu.o
libsbi-objs-y += sbi_scratch.o
libsbi-objs-y += sbi_string.o
libsbi-objs-y += sbi_system.o

View File

@@ -11,7 +11,6 @@
#include <sbi/riscv_encoding.h>
#include <sbi/sbi_error.h>
#include <sbi/sbi_platform.h>
#include <sbi/sbi_console.h>
/* determine CPU extension, return non-zero support */
int misa_extension_imp(char ext)
@@ -53,7 +52,7 @@ int misa_xlen(void)
void misa_string(int xlen, char *out, unsigned int out_sz)
{
unsigned int i, pos = 0;
const char valid_isa_order[] = "iemafdqclbjtpvnhkorwxyzg";
const char valid_isa_order[] = "iemafdqclbjtpvnsuhkorwxyzg";
if (!out)
return;
@@ -76,8 +75,6 @@ void misa_string(int xlen, char *out, unsigned int out_sz)
out[pos++] = '8';
break;
default:
sbi_panic("%s: Unknown misa.MXL encoding %d",
__func__, xlen);
return;
}
}
@@ -121,36 +118,7 @@ unsigned long csr_read_num(int csr_num)
switch (csr_num) {
switchcase_csr_read_16(CSR_PMPCFG0, ret)
switchcase_csr_read_64(CSR_PMPADDR0, ret)
switchcase_csr_read(CSR_MCYCLE, ret)
switchcase_csr_read(CSR_MINSTRET, ret)
switchcase_csr_read(CSR_MHPMCOUNTER3, ret)
switchcase_csr_read_4(CSR_MHPMCOUNTER4, ret)
switchcase_csr_read_8(CSR_MHPMCOUNTER8, ret)
switchcase_csr_read_16(CSR_MHPMCOUNTER16, ret)
switchcase_csr_read(CSR_MCOUNTINHIBIT, ret)
switchcase_csr_read(CSR_MHPMEVENT3, ret)
switchcase_csr_read_4(CSR_MHPMEVENT4, ret)
switchcase_csr_read_8(CSR_MHPMEVENT8, ret)
switchcase_csr_read_16(CSR_MHPMEVENT16, ret)
#if __riscv_xlen == 32
switchcase_csr_read(CSR_MCYCLEH, ret)
switchcase_csr_read(CSR_MINSTRETH, ret)
switchcase_csr_read(CSR_MHPMCOUNTER3H, ret)
switchcase_csr_read_4(CSR_MHPMCOUNTER4H, ret)
switchcase_csr_read_8(CSR_MHPMCOUNTER8H, ret)
switchcase_csr_read_16(CSR_MHPMCOUNTER16H, ret)
/**
* The CSR range MHPMEVENT[3-16]H are available only if sscofpmf
* extension is present. The caller must ensure that.
*/
switchcase_csr_read(CSR_MHPMEVENT3H, ret)
switchcase_csr_read_4(CSR_MHPMEVENT4H, ret)
switchcase_csr_read_8(CSR_MHPMEVENT8H, ret)
switchcase_csr_read_16(CSR_MHPMEVENT16H, ret)
#endif
default:
sbi_panic("%s: Unknown CSR %#x", __func__, csr_num);
break;
};
@@ -193,32 +161,7 @@ void csr_write_num(int csr_num, unsigned long val)
switch (csr_num) {
switchcase_csr_write_16(CSR_PMPCFG0, val)
switchcase_csr_write_64(CSR_PMPADDR0, val)
switchcase_csr_write(CSR_MCYCLE, val)
switchcase_csr_write(CSR_MINSTRET, val)
switchcase_csr_write(CSR_MHPMCOUNTER3, val)
switchcase_csr_write_4(CSR_MHPMCOUNTER4, val)
switchcase_csr_write_8(CSR_MHPMCOUNTER8, val)
switchcase_csr_write_16(CSR_MHPMCOUNTER16, val)
#if __riscv_xlen == 32
switchcase_csr_write(CSR_MCYCLEH, val)
switchcase_csr_write(CSR_MINSTRETH, val)
switchcase_csr_write(CSR_MHPMCOUNTER3H, val)
switchcase_csr_write_4(CSR_MHPMCOUNTER4H, val)
switchcase_csr_write_8(CSR_MHPMCOUNTER8H, val)
switchcase_csr_write_16(CSR_MHPMCOUNTER16H, val)
switchcase_csr_write(CSR_MHPMEVENT3H, val)
switchcase_csr_write_4(CSR_MHPMEVENT4H, val)
switchcase_csr_write_8(CSR_MHPMEVENT8H, val)
switchcase_csr_write_16(CSR_MHPMEVENT16H, val)
#endif
switchcase_csr_write(CSR_MCOUNTINHIBIT, val)
switchcase_csr_write(CSR_MHPMEVENT3, val)
switchcase_csr_write_4(CSR_MHPMEVENT4, val)
switchcase_csr_write_8(CSR_MHPMEVENT8, val)
switchcase_csr_write_16(CSR_MHPMEVENT16, val)
default:
sbi_panic("%s: Unknown CSR %#x", __func__, csr_num);
break;
};
@@ -235,9 +178,6 @@ static unsigned long ctz(unsigned long x)
{
unsigned long ret = 0;
if (x == 0)
return 8 * sizeof(x);
while (!(x & 1UL)) {
ret++;
x = x >> 1;
@@ -265,12 +205,14 @@ int pmp_set(unsigned int n, unsigned long prot, unsigned long addr,
pmpcfg_csr = (CSR_PMPCFG0 + (n >> 2)) & ~1;
pmpcfg_shift = (n & 7) << 3;
#else
# error "Unexpected __riscv_xlen"
pmpcfg_csr = -1;
pmpcfg_shift = -1;
#endif
pmpaddr_csr = CSR_PMPADDR0 + n;
if (pmpcfg_csr < 0 || pmpcfg_shift < 0)
return SBI_ENOTSUPP;
/* encode PMP config */
prot &= ~PMP_A;
prot |= (log2len == PMP_SHIFT) ? PMP_A_NA4 : PMP_A_NAPOT;
cfgmask = ~(0xffUL << pmpcfg_shift);
pmpcfg = (csr_read_num(pmpcfg_csr) & cfgmask);
@@ -316,9 +258,12 @@ int pmp_get(unsigned int n, unsigned long *prot_out, unsigned long *addr_out,
pmpcfg_csr = (CSR_PMPCFG0 + (n >> 2)) & ~1;
pmpcfg_shift = (n & 7) << 3;
#else
# error "Unexpected __riscv_xlen"
pmpcfg_csr = -1;
pmpcfg_shift = -1;
#endif
pmpaddr_csr = CSR_PMPADDR0 + n;
if (pmpcfg_csr < 0 || pmpcfg_shift < 0)
return SBI_ENOTSUPP;
/* decode PMP config */
cfgmask = (0xffUL << pmpcfg_shift);

View File

@@ -8,7 +8,7 @@
#include <sbi/riscv_barrier.h>
#include <sbi/riscv_locks.h>
static inline bool spin_lock_unlocked(spinlock_t lock)
static inline int spin_lock_unlocked(spinlock_t lock)
{
return lock.owner == lock.next;
}
@@ -19,7 +19,7 @@ bool spin_lock_check(spinlock_t *lock)
return !spin_lock_unlocked(*lock);
}
bool spin_trylock(spinlock_t *lock)
int spin_trylock(spinlock_t *lock)
{
unsigned long inc = 1u << TICKET_SHIFT;
unsigned long mask = 0xffffu << TICKET_SHIFT;
@@ -42,7 +42,7 @@ bool spin_trylock(spinlock_t *lock)
: "r"(inc), "r"(mask), "I"(TICKET_SHIFT)
: "memory");
return l0 == 0;
return !l0;
}
void spin_lock(spinlock_t *lock)

View File

@@ -39,7 +39,7 @@ unsigned long find_first_bit(const unsigned long *addr,
if (tmp == 0UL) /* Are any bits set? */
return result + size; /* Nope. */
found:
return result + sbi_ffs(tmp);
return result + __ffs(tmp);
}
/**
@@ -69,7 +69,7 @@ unsigned long find_first_zero_bit(const unsigned long *addr,
if (tmp == ~0UL) /* Are any bits zero? */
return result + size; /* Nope. */
found:
return result + sbi_ffz(tmp);
return result + ffz(tmp);
}
/**
@@ -100,7 +100,7 @@ unsigned long find_last_bit(const unsigned long *addr,
tmp = addr[--words];
if (tmp) {
found:
return words * BITS_PER_LONG + sbi_fls(tmp);
return words * BITS_PER_LONG + __fls(tmp);
}
}
@@ -150,7 +150,7 @@ found_first:
if (tmp == 0UL) /* Are any bits set? */
return result + size; /* Nope. */
found_middle:
return result + sbi_ffs(tmp);
return result + __ffs(tmp);
}
/**
@@ -196,5 +196,5 @@ found_first:
if (tmp == ~0UL) /* Are any bits zero? */
return result + size; /* Nope. */
found_middle:
return result + sbi_ffz(tmp);
return result + ffz(tmp);
}

View File

@@ -9,7 +9,6 @@
#include <sbi/riscv_locks.h>
#include <sbi/sbi_console.h>
#include <sbi/sbi_hart.h>
#include <sbi/sbi_platform.h>
#include <sbi/sbi_scratch.h>
@@ -388,29 +387,13 @@ int sbi_dprintf(const char *format, ...)
struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
va_start(args, format);
if (scratch->options & SBI_SCRATCH_DEBUG_PRINTS) {
spin_lock(&console_out_lock);
if (scratch->options & SBI_SCRATCH_DEBUG_PRINTS)
retval = print(NULL, NULL, format, args);
spin_unlock(&console_out_lock);
}
va_end(args);
return retval;
}
void sbi_panic(const char *format, ...)
{
va_list args;
spin_lock(&console_out_lock);
va_start(args, format);
print(NULL, NULL, format, args);
va_end(args);
spin_unlock(&console_out_lock);
sbi_hart_hang();
}
const struct sbi_console_device *sbi_console_get_device(void)
{
return console_dev;

View File

@@ -34,6 +34,7 @@ struct sbi_domain root = {
.possible_harts = &root_hmask,
.regions = root_memregs,
.system_reset_allowed = TRUE,
.system_suspend_allowed = TRUE,
};
bool sbi_domain_is_assigned_hart(const struct sbi_domain *dom, u32 hartid)
@@ -159,7 +160,7 @@ static bool is_region_subset(const struct sbi_domain_memregion *regA,
ulong regA_start = regA->base;
ulong regA_end = regA->base + (BIT(regA->order) - 1);
ulong regB_start = regB->base;
ulong regB_end = regB->base + (BIT(regB->order) - 1);
ulong regB_end = regB->base + (BIT(regA->order) - 1);
if ((regB_start <= regA_start) &&
(regA_start < regB_end) &&
@@ -295,7 +296,7 @@ static int sanitize_domain(const struct sbi_platform *plat,
/* Check next address and next mode*/
if (!sbi_domain_check_addr(dom, dom->next_addr, dom->next_mode,
SBI_DOMAIN_EXECUTE)) {
sbi_printf("%s: %s next booting stage address 0x%lx can't "
sbi_printf("%s: %s next booting stage addres 0x%lx can't "
"execute\n", __func__, dom->name, dom->next_addr);
return SBI_EINVAL;
}
@@ -328,7 +329,11 @@ void sbi_domain_dump(const struct sbi_domain *dom, const char *suffix)
rend = (reg->order < __riscv_xlen) ?
rstart + ((1UL << reg->order) - 1) : -1UL;
sbi_printf("Domain%d Region%02d %s: 0x%" PRILX "-0x%" PRILX " ",
#if __riscv_xlen == 32
sbi_printf("Domain%d Region%02d %s: 0x%08lx-0x%08lx ",
#else
sbi_printf("Domain%d Region%02d %s: 0x%016lx-0x%016lx ",
#endif
dom->index, i, suffix, rstart, rend);
k = 0;
@@ -347,10 +352,18 @@ void sbi_domain_dump(const struct sbi_domain *dom, const char *suffix)
i++;
}
sbi_printf("Domain%d Next Address%s: 0x%" PRILX "\n",
#if __riscv_xlen == 32
sbi_printf("Domain%d Next Address%s: 0x%08lx\n",
#else
sbi_printf("Domain%d Next Address%s: 0x%016lx\n",
#endif
dom->index, suffix, dom->next_addr);
sbi_printf("Domain%d Next Arg1 %s: 0x%" PRILX "\n",
#if __riscv_xlen == 32
sbi_printf("Domain%d Next Arg1 %s: 0x%08lx\n",
#else
sbi_printf("Domain%d Next Arg1 %s: 0x%016lx\n",
#endif
dom->index, suffix, dom->next_arg1);
sbi_printf("Domain%d Next Mode %s: ", dom->index, suffix);
@@ -371,6 +384,8 @@ void sbi_domain_dump(const struct sbi_domain *dom, const char *suffix)
sbi_printf("Domain%d SysReset %s: %s\n",
dom->index, suffix, (dom->system_reset_allowed) ? "yes" : "no");
sbi_printf("Domain%d SysSuspend %s: %s\n",
dom->index, suffix, (dom->system_suspend_allowed) ? "yes" : "no");
}
void sbi_domain_dump_all(const char *suffix)
@@ -471,12 +486,8 @@ int sbi_domain_root_add_memregion(const struct sbi_domain_memregion *reg)
/* Check for conflicts */
sbi_domain_for_each_memregion(&root, nreg) {
if (is_region_conflict(reg, nreg)) {
sbi_printf("%s: is_region_conflict check failed"
" 0x%lx conflicts existing 0x%lx\n", __func__,
reg->base, nreg->base);
return SBI_EALREADY;
}
if (is_region_conflict(reg, nreg))
return SBI_EINVAL;
}
/* Append the memregion to root memregions */
@@ -503,8 +514,7 @@ int sbi_domain_root_add_memregion(const struct sbi_domain_memregion *reg)
if (!nreg1->order)
continue;
if (!(nreg->base & (BIT(nreg->order + 1) - 1)) &&
(nreg->base + BIT(nreg->order)) == nreg1->base &&
if ((nreg->base + BIT(nreg->order)) == nreg1->base &&
nreg->order == nreg1->order &&
nreg->flags == nreg1->flags) {
nreg->order++;

View File

@@ -162,15 +162,15 @@ int sbi_ecall_init(void)
if (ret)
return ret;
ret = sbi_ecall_register_extension(&ecall_srst);
if (ret)
return ret;
ret = sbi_ecall_register_extension(&ecall_pmu);
if (ret)
return ret;
ret = sbi_ecall_register_extension(&ecall_legacy);
if (ret)
return ret;
ret = sbi_ecall_register_extension(&ecall_vendor);
if (ret)
return ret;
ret = sbi_ecall_register_extension(&ecall_susp);
if (ret)
return ret;

View File

@@ -14,6 +14,7 @@
#include <sbi/sbi_trap.h>
#include <sbi/sbi_version.h>
#include <sbi/riscv_asm.h>
#include <sbi/riscv_io.h>
static int sbi_ecall_base_probe(unsigned long extid, unsigned long *out_val)
{
@@ -32,6 +33,41 @@ static int sbi_ecall_base_probe(unsigned long extid, unsigned long *out_val)
return 0;
}
#define SEC_SYS_BASE (0x020B0000)
static int sbi_ecall_base_rst_c906l(void)
{
unsigned int value;
value = readl((void *)0x3003024);
writel((value & (~(1 << 6))), (void *)0x3003024);
return 0;
}
static int sbi_ecall_base_unrst_c906l(const unsigned long address)
{
unsigned int value;
value = readl((void *)SEC_SYS_BASE + 0x04);
writel((value | (1 << 13)), (void *)SEC_SYS_BASE + 0x04);
writel(address, (void *)SEC_SYS_BASE + 0x20);
writel((address >> 32), (void *)SEC_SYS_BASE + 0x24);
value = readl((void *)0x3003024);
writel((value | (1 << 6)), (void *)0x3003024);
return 0;
}
static int sbi_ecall_base_reset_c906l(const unsigned long address)
{
sbi_ecall_base_rst_c906l();
sbi_ecall_base_unrst_c906l(address);
return 0;
}
static int sbi_ecall_base_handler(unsigned long extid, unsigned long funcid,
const struct sbi_trap_regs *regs,
unsigned long *out_val,
@@ -65,6 +101,16 @@ static int sbi_ecall_base_handler(unsigned long extid, unsigned long funcid,
case SBI_EXT_BASE_PROBE_EXT:
ret = sbi_ecall_base_probe(regs->a0, out_val);
break;
case SBI_EXT_BASE_RESET_C906L:
ret = sbi_ecall_base_reset_c906l(regs->a0);
*out_val = regs->a0;
break;
case SBI_EXT_BASE_RST_C906L:
ret = sbi_ecall_base_rst_c906l();
break;
case SBI_EXT_BASE_UNRST_C906L:
ret = sbi_ecall_base_unrst_c906l(regs->a0);
break;
default:
ret = SBI_ENOTSUPP;
}

View File

@@ -1,87 +0,0 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2021 Western Digital Corporation or its affiliates.
*
* Authors:
* Atish Patra <atish.patra@wdc.com>
*/
#include <sbi/sbi_ecall.h>
#include <sbi/sbi_ecall_interface.h>
#include <sbi/sbi_error.h>
#include <sbi/sbi_hart.h>
#include <sbi/sbi_trap.h>
#include <sbi/sbi_version.h>
#include <sbi/sbi_pmu.h>
#include <sbi/sbi_scratch.h>
#include <sbi/riscv_asm.h>
static int sbi_ecall_pmu_handler(unsigned long extid, unsigned long funcid,
const struct sbi_trap_regs *regs,
unsigned long *out_val,
struct sbi_trap_info *out_trap)
{
int ret = 0;
uint64_t temp;
switch (funcid) {
case SBI_EXT_PMU_NUM_COUNTERS:
ret = sbi_pmu_num_ctr();
if (ret >= 0) {
*out_val = ret;
ret = 0;
}
break;
case SBI_EXT_PMU_COUNTER_GET_INFO:
ret = sbi_pmu_ctr_get_info(regs->a0, out_val);
break;
case SBI_EXT_PMU_COUNTER_CFG_MATCH:
#if __riscv_xlen == 32
temp = ((uint64_t)regs->a5 << 32) | regs->a4;
#else
temp = regs->a4;
#endif
ret = sbi_pmu_ctr_cfg_match(regs->a0, regs->a1, regs->a2,
regs->a3, temp);
if (ret >= 0) {
*out_val = ret;
ret = 0;
}
break;
case SBI_EXT_PMU_COUNTER_FW_READ:
ret = sbi_pmu_ctr_read(regs->a0, out_val);
break;
case SBI_EXT_PMU_COUNTER_START:
#if __riscv_xlen == 32
temp = ((uint64_t)regs->a4 << 32) | regs->a3;
#else
temp = regs->a3;
#endif
ret = sbi_pmu_ctr_start(regs->a0, regs->a1, regs->a2, temp);
break;
case SBI_EXT_PMU_COUNTER_STOP:
ret = sbi_pmu_ctr_stop(regs->a0, regs->a1, regs->a2);
break;
default:
ret = SBI_ENOTSUPP;
};
return ret;
}
static int sbi_ecall_pmu_probe(unsigned long extid, unsigned long *out_val)
{
/* PMU extension is always enabled */
*out_val = 1;
return 0;
}
struct sbi_ecall_extension ecall_pmu = {
.extid_start = SBI_EXT_PMU,
.extid_end = SBI_EXT_PMU,
.handle = sbi_ecall_pmu_handler,
.probe = sbi_ecall_pmu_probe,
};

View File

@@ -54,8 +54,8 @@ static int sbi_ecall_rfence_handler(unsigned long extid, unsigned long funcid,
struct sbi_tlb_info tlb_info;
u32 source_hart = current_hartid();
if (funcid >= SBI_EXT_RFENCE_REMOTE_HFENCE_GVMA_VMID &&
funcid <= SBI_EXT_RFENCE_REMOTE_HFENCE_VVMA)
if (funcid >= SBI_EXT_RFENCE_REMOTE_HFENCE_GVMA &&
funcid <= SBI_EXT_RFENCE_REMOTE_HFENCE_VVMA_ASID)
if (!misa_extension('H'))
return SBI_ENOTSUPP;
@@ -151,7 +151,7 @@ static int sbi_ecall_srst_handler(unsigned long extid, unsigned long funcid,
case SBI_SRST_RESET_TYPE_WARM_REBOOT:
break;
default:
return SBI_EINVAL;
return SBI_ENOTSUPP;
}
switch (regs->a1) {
@@ -159,7 +159,7 @@ static int sbi_ecall_srst_handler(unsigned long extid, unsigned long funcid,
case SBI_SRST_RESET_REASON_SYSFAIL:
break;
default:
return SBI_EINVAL;
return SBI_ENOTSUPP;
}
if (sbi_system_reset_supported(regs->a0, regs->a1))

60
lib/sbi/sbi_ecall_susp.c Normal file
View File

@@ -0,0 +1,60 @@
// SPDX-License-Identifier: BSD-2-Clause
#include <sbi/sbi_ecall.h>
#include <sbi/sbi_ecall_interface.h>
#include <sbi/sbi_error.h>
#include <sbi/sbi_trap.h>
#include <sbi/sbi_system.h>
static int sbi_ecall_susp_handler(unsigned long extid, unsigned long funcid,
const struct sbi_trap_regs *regs,
unsigned long *out_val,
struct sbi_trap_info *out_trap)
{
int ret = SBI_ENOTSUPP;
if (funcid == SBI_EXT_SUSP_SUSPEND)
ret = sbi_system_suspend(regs->a0, regs->a1, regs->a2);
if (ret >= 0) {
*out_val = ret;
ret = 0;
}
return ret;
}
static bool susp_available(void)
{
u32 type;
/*
* At least one suspend type should be supported by the
* platform for the SBI SUSP extension to be usable.
*/
for (type = 0; type <= SBI_SUSP_SLEEP_TYPE_LAST; type++) {
if (sbi_system_suspend_supported(type))
return true;
}
return false;
}
struct sbi_ecall_extension ecall_susp;
static int sbi_ecall_susp_register_extensions(unsigned long extid, unsigned long *out_val)
{
if (!susp_available()) {
*out_val = 0;
return 0;
}
*out_val = 1;
return 0;
}
struct sbi_ecall_extension ecall_susp = {
.extid_start = SBI_EXT_SUSP,
.extid_end = SBI_EXT_SUSP,
.probe = sbi_ecall_susp_register_extensions,
.handle = sbi_ecall_susp_handler,
};

View File

@@ -24,7 +24,7 @@ static bool hpm_allowed(int hpm_num, ulong prev_mode, bool virt)
struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
if (prev_mode <= PRV_S) {
if (sbi_hart_priv_version(scratch) >= SBI_HART_PRIV_VER_1_10) {
if (sbi_hart_has_feature(scratch, SBI_HART_HAS_MCOUNTEREN)) {
cen &= csr_read(CSR_MCOUNTEREN);
if (virt)
cen &= csr_read(CSR_HCOUNTEREN);
@@ -33,7 +33,7 @@ static bool hpm_allowed(int hpm_num, ulong prev_mode, bool virt)
}
}
if (prev_mode == PRV_U) {
if (sbi_hart_priv_version(scratch) >= SBI_HART_PRIV_VER_1_10)
if (sbi_hart_has_feature(scratch, SBI_HART_HAS_SCOUNTEREN))
cen &= csr_read(CSR_SCOUNTEREN);
else
cen = 0;

View File

@@ -43,13 +43,10 @@ u16 sbi_fifo_avail(struct sbi_fifo *fifo)
return ret;
}
int sbi_fifo_is_full(struct sbi_fifo *fifo)
bool sbi_fifo_is_full(struct sbi_fifo *fifo)
{
bool ret;
if (!fifo)
return SBI_EINVAL;
spin_lock(&fifo->qlock);
ret = __sbi_fifo_is_full(fifo);
spin_unlock(&fifo->qlock);
@@ -66,7 +63,7 @@ static inline void __sbi_fifo_enqueue(struct sbi_fifo *fifo, void *data)
if (head >= fifo->num_entries)
head = head - fifo->num_entries;
sbi_memcpy((char *)fifo->queue + head * fifo->entry_size, data, fifo->entry_size);
sbi_memcpy(fifo->queue + head * fifo->entry_size, data, fifo->entry_size);
fifo->avail++;
}
@@ -78,13 +75,10 @@ static inline bool __sbi_fifo_is_empty(struct sbi_fifo *fifo)
return (fifo->avail == 0) ? TRUE : FALSE;
}
int sbi_fifo_is_empty(struct sbi_fifo *fifo)
bool sbi_fifo_is_empty(struct sbi_fifo *fifo)
{
bool ret;
if (!fifo)
return SBI_EINVAL;
spin_lock(&fifo->qlock);
ret = __sbi_fifo_is_empty(fifo);
spin_unlock(&fifo->qlock);
@@ -124,7 +118,7 @@ bool sbi_fifo_reset(struct sbi_fifo *fifo)
int sbi_fifo_inplace_update(struct sbi_fifo *fifo, void *in,
int (*fptr)(void *in, void *data))
{
int i, index;
int i, index = 0;
int ret = SBI_FIFO_UNCHANGED;
void *entry;
@@ -141,8 +135,8 @@ int sbi_fifo_inplace_update(struct sbi_fifo *fifo, void *in,
for (i = 0; i < fifo->avail; i++) {
index = fifo->tail + i;
if (index >= fifo->num_entries)
index -= fifo->num_entries;
entry = (char *)fifo->queue + (u32)index * fifo->entry_size;
index = index - fifo->num_entries;
entry = (void *)fifo->queue + (u32)index * fifo->entry_size;
ret = fptr(in, entry);
if (ret == SBI_FIFO_SKIP || ret == SBI_FIFO_UPDATED) {
@@ -184,7 +178,7 @@ int sbi_fifo_dequeue(struct sbi_fifo *fifo, void *data)
return SBI_ENOENT;
}
sbi_memcpy(data, (char *)fifo->queue + (u32)fifo->tail * fifo->entry_size,
sbi_memcpy(data, fifo->queue + (u32)fifo->tail * fifo->entry_size,
fifo->entry_size);
fifo->avail--;

View File

@@ -28,24 +28,17 @@ extern void __sbi_expected_trap_hext(void);
void (*sbi_hart_expected_trap)(void) = &__sbi_expected_trap;
struct hart_features {
bool detected;
int priv_version;
unsigned long extensions;
unsigned long features;
unsigned int pmp_count;
unsigned int pmp_addr_bits;
unsigned long pmp_gran;
unsigned int mhpm_count;
unsigned int mhpm_bits;
};
static unsigned long hart_features_offset;
static void mstatus_init(struct sbi_scratch *scratch)
{
unsigned long menvcfg_val, mstatus_val = 0;
int cidx;
unsigned int num_mhpm = sbi_hart_mhpm_count(scratch);
uint64_t mhpmevent_init_val = 0;
uint64_t mstateen_val;
unsigned long mstatus_val = 0;
/* Enable FPU */
if (misa_extension('D') || misa_extension('F'))
@@ -57,117 +50,13 @@ static void mstatus_init(struct sbi_scratch *scratch)
csr_write(CSR_MSTATUS, mstatus_val);
/* Disable user mode usage of all perf counters except default ones (CY, TM, IR) */
/* Enable user/supervisor use of perf counters */
if (misa_extension('S') &&
sbi_hart_priv_version(scratch) >= SBI_HART_PRIV_VER_1_10)
csr_write(CSR_SCOUNTEREN, 7);
/**
* OpenSBI doesn't use any PMU counters in M-mode.
* Supervisor mode usage for all counters are enabled by default
* But counters will not run until mcountinhibit is set.
*/
if (sbi_hart_priv_version(scratch) >= SBI_HART_PRIV_VER_1_10)
sbi_hart_has_feature(scratch, SBI_HART_HAS_SCOUNTEREN))
csr_write(CSR_SCOUNTEREN, -1);
if (sbi_hart_has_feature(scratch, SBI_HART_HAS_MCOUNTEREN))
csr_write(CSR_MCOUNTEREN, -1);
/* All programmable counters will start running at runtime after S-mode request */
if (sbi_hart_priv_version(scratch) >= SBI_HART_PRIV_VER_1_11)
csr_write(CSR_MCOUNTINHIBIT, 0xFFFFFFF8);
/**
* The mhpmeventn[h] CSR should be initialized with interrupt disabled
* and inhibited running in M-mode during init.
* To keep it simple, only contiguous mhpmcounters are supported as a
* platform with discontiguous mhpmcounters may not make much sense.
*/
mhpmevent_init_val |= (MHPMEVENT_OF | MHPMEVENT_MINH);
for (cidx = 0; cidx < num_mhpm; cidx++) {
#if __riscv_xlen == 32
csr_write_num(CSR_MHPMEVENT3 + cidx, mhpmevent_init_val & 0xFFFFFFFF);
if (sbi_hart_has_extension(scratch, SBI_HART_EXT_SSCOFPMF))
csr_write_num(CSR_MHPMEVENT3H + cidx,
mhpmevent_init_val >> BITS_PER_LONG);
#else
csr_write_num(CSR_MHPMEVENT3 + cidx, mhpmevent_init_val);
#endif
}
if (sbi_hart_has_extension(scratch, SBI_HART_EXT_SMSTATEEN)) {
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_HSENVCFG;
if (sbi_hart_has_extension(scratch, SBI_HART_EXT_AIA))
mstateen_val |= (SMSTATEEN0_AIA | SMSTATEEN0_SVSLCT |
SMSTATEEN0_IMSIC);
else
mstateen_val &= ~(SMSTATEEN0_AIA | SMSTATEEN0_SVSLCT |
SMSTATEEN0_IMSIC);
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_read(CSR_MENVCFG);
/*
* Set menvcfg.CBZE == 1
*
* If Zicboz extension is not available then writes to
* menvcfg.CBZE will be ignored because it is a WARL field.
*/
menvcfg_val |= ENVCFG_CBZE;
/*
* Set menvcfg.CBCFE == 1
*
* If Zicbom extension is not available then writes to
* menvcfg.CBCFE will be ignored because it is a WARL field.
*/
menvcfg_val |= ENVCFG_CBCFE;
/*
* Set menvcfg.CBIE == 3
*
* If Zicbom extension is not available then writes to
* menvcfg.CBIE will be ignored because it is a WARL field.
*/
menvcfg_val |= ENVCFG_CBIE_INV << ENVCFG_CBIE_SHIFT;
/*
* Set menvcfg.PBMTE == 1 for RV64 or RV128
*
* If Svpbmt extension is not available then menvcfg.PBMTE
* will be read-only zero.
*/
#if __riscv_xlen > 32
menvcfg_val |= ENVCFG_PBMTE;
#endif
/*
* The spec doesn't explicitly describe the reset value of menvcfg.
* Enable access to stimecmp if sstc extension is present in the
* hardware.
*/
if (sbi_hart_has_extension(scratch, SBI_HART_EXT_SSTC)) {
#if __riscv_xlen == 32
unsigned long menvcfgh_val;
menvcfgh_val = csr_read(CSR_MENVCFGH);
menvcfgh_val |= ENVCFGH_STCE;
csr_write(CSR_MENVCFGH, menvcfgh_val);
#else
menvcfg_val |= ENVCFG_STCE;
#endif
}
csr_write(CSR_MENVCFG, menvcfg_val);
}
/* Disable all interrupts */
csr_write(CSR_MIE, 0);
@@ -208,9 +97,6 @@ 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;
if (sbi_hart_has_extension(scratch, SBI_HART_EXT_SSCOFPMF))
interrupts |= MIP_LCOFIP;
exceptions = (1U << CAUSE_MISALIGNED_FETCH) | (1U << CAUSE_BREAKPOINT) |
(1U << CAUSE_USER_ECALL);
if (sbi_platform_has_mfaults_delegation(plat))
@@ -246,10 +132,17 @@ void sbi_hart_delegation_dump(struct sbi_scratch *scratch,
/* No delegation possible as mideleg does not exist*/
return;
sbi_printf("%sMIDELEG%s: 0x%" PRILX "\n",
#if __riscv_xlen == 32
sbi_printf("%sMIDELEG%s: 0x%08lx\n",
prefix, suffix, csr_read(CSR_MIDELEG));
sbi_printf("%sMEDELEG%s: 0x%" PRILX "\n",
sbi_printf("%sMEDELEG%s: 0x%08lx\n",
prefix, suffix, csr_read(CSR_MEDELEG));
#else
sbi_printf("%sMIDELEG%s: 0x%016lx\n",
prefix, suffix, csr_read(CSR_MIDELEG));
sbi_printf("%sMEDELEG%s: 0x%016lx\n",
prefix, suffix, csr_read(CSR_MEDELEG));
#endif
}
unsigned int sbi_hart_mhpm_count(struct sbi_scratch *scratch)
@@ -284,14 +177,6 @@ unsigned int sbi_hart_pmp_addrbits(struct sbi_scratch *scratch)
return hfeatures->pmp_addr_bits;
}
unsigned int sbi_hart_mhpm_bits(struct sbi_scratch *scratch)
{
struct hart_features *hfeatures =
sbi_scratch_offset_ptr(scratch, hart_features_offset);
return hfeatures->mhpm_bits;
}
int sbi_hart_pmp_configure(struct sbi_scratch *scratch)
{
struct sbi_domain_memregion *reg;
@@ -326,7 +211,7 @@ int sbi_hart_pmp_configure(struct sbi_scratch *scratch)
pmp_set(pmp_idx++, pmp_flags, reg->base, reg->order);
else {
sbi_printf("Can not configure pmp for domain %s", dom->name);
sbi_printf(" because memory region address %lx or size %lx is not in range\n",
sbi_printf("because memory region address %lx or size %lx is not in range\n",
reg->base, reg->order);
}
}
@@ -334,156 +219,97 @@ int sbi_hart_pmp_configure(struct sbi_scratch *scratch)
return 0;
}
int sbi_hart_priv_version(struct sbi_scratch *scratch)
{
struct hart_features *hfeatures =
sbi_scratch_offset_ptr(scratch, hart_features_offset);
return hfeatures->priv_version;
}
void sbi_hart_get_priv_version_str(struct sbi_scratch *scratch,
char *version_str, int nvstr)
{
char *temp;
struct hart_features *hfeatures =
sbi_scratch_offset_ptr(scratch, hart_features_offset);
switch (hfeatures->priv_version) {
case SBI_HART_PRIV_VER_1_10:
temp = "v1.10";
break;
case SBI_HART_PRIV_VER_1_11:
temp = "v1.11";
break;
case SBI_HART_PRIV_VER_1_12:
temp = "v1.12";
break;
default:
temp = "unknown";
break;
}
sbi_snprintf(version_str, nvstr, "%s", temp);
}
static inline void __sbi_hart_update_extension(
struct hart_features *hfeatures,
enum sbi_hart_extensions ext,
bool enable)
{
if (enable)
hfeatures->extensions |= BIT(ext);
else
hfeatures->extensions &= ~BIT(ext);
}
/**
* Enable/Disable a particular hart extension
* Check whether a particular hart feature is available
*
* @param scratch pointer to the HART scratch space
* @param ext the extension number to check
* @param enable new state of hart extension
* @param feature the feature to check
* @returns true (feature available) or false (feature not available)
*/
void sbi_hart_update_extension(struct sbi_scratch *scratch,
enum sbi_hart_extensions ext,
bool enable)
bool sbi_hart_has_feature(struct sbi_scratch *scratch, unsigned long feature)
{
struct hart_features *hfeatures =
sbi_scratch_offset_ptr(scratch, hart_features_offset);
__sbi_hart_update_extension(hfeatures, ext, enable);
}
/**
* Check whether a particular hart extension is available
*
* @param scratch pointer to the HART scratch space
* @param ext the extension number to check
* @returns true (available) or false (not available)
*/
bool sbi_hart_has_extension(struct sbi_scratch *scratch,
enum sbi_hart_extensions ext)
{
struct hart_features *hfeatures =
sbi_scratch_offset_ptr(scratch, hart_features_offset);
if (hfeatures->extensions & BIT(ext))
if (hfeatures->features & feature)
return true;
else
return false;
}
static inline char *sbi_hart_extension_id2string(int ext)
static unsigned long hart_get_features(struct sbi_scratch *scratch)
{
char *estr = NULL;
struct hart_features *hfeatures =
sbi_scratch_offset_ptr(scratch, hart_features_offset);
switch (ext) {
case SBI_HART_EXT_SSCOFPMF:
estr = "sscofpmf";
return hfeatures->features;
}
static inline char *sbi_hart_feature_id2string(unsigned long feature)
{
char *fstr = NULL;
if (!feature)
return NULL;
switch (feature) {
case SBI_HART_HAS_SCOUNTEREN:
fstr = "scounteren";
break;
case SBI_HART_EXT_TIME:
estr = "time";
case SBI_HART_HAS_MCOUNTEREN:
fstr = "mcounteren";
break;
case SBI_HART_EXT_AIA:
estr = "aia";
break;
case SBI_HART_EXT_SSTC:
estr = "sstc";
break;
case SBI_HART_EXT_SMSTATEEN:
estr = "smstateen";
case SBI_HART_HAS_TIME:
fstr = "time";
break;
default:
break;
}
return estr;
return fstr;
}
/**
* Get the hart extensions in string format
* Get the hart features in string format
*
* @param scratch pointer to the HART scratch space
* @param extensions_str pointer to a char array where the extensions string
* will be updated
* @param nestr length of the features_str. The feature string will be
* truncated if nestr is not long enough.
* @param features_str pointer to a char array where the features string will be
* updated
* @param nfstr length of the features_str. The feature string will be truncated
* if nfstr is not long enough.
*/
void sbi_hart_get_extensions_str(struct sbi_scratch *scratch,
char *extensions_str, int nestr)
void sbi_hart_get_features_str(struct sbi_scratch *scratch,
char *features_str, int nfstr)
{
struct hart_features *hfeatures =
sbi_scratch_offset_ptr(scratch, hart_features_offset);
int offset = 0, ext = 0;
unsigned long features, feat = 1UL;
char *temp;
int offset = 0;
if (!extensions_str || nestr <= 0)
if (!features_str || nfstr <= 0)
return;
sbi_memset(extensions_str, 0, nestr);
sbi_memset(features_str, 0, nfstr);
if (!hfeatures->extensions)
features = hart_get_features(scratch);
if (!features)
goto done;
do {
if (hfeatures->extensions & BIT(ext)) {
temp = sbi_hart_extension_id2string(ext);
if (features & feat) {
temp = sbi_hart_feature_id2string(feat);
if (temp) {
sbi_snprintf(extensions_str + offset,
nestr - offset,
sbi_snprintf(features_str + offset, nfstr,
"%s,", temp);
offset = offset + sbi_strlen(temp) + 1;
}
}
ext++;
} while (ext < SBI_HART_EXT_MAX);
feat = feat << 1;
} while (feat <= SBI_HART_HAS_LAST_FEATURE);
done:
if (offset)
extensions_str[offset - 1] = '\0';
features_str[offset - 1] = '\0';
else
sbi_strncpy(extensions_str, "none", nestr);
sbi_strncpy(features_str, "none", nfstr);
}
static unsigned long hart_pmp_get_allowed_addr(void)
@@ -491,11 +317,7 @@ static unsigned long hart_pmp_get_allowed_addr(void)
unsigned long val = 0;
struct sbi_trap_info trap = {0};
csr_write_allowed(CSR_PMPCFG0, (ulong)&trap, 0);
if (trap.cause)
return 0;
csr_write_allowed(CSR_PMPADDR0, (ulong)&trap, PMP_ADDR_MASK);
csr_write_allowed(CSR_PMPADDR0, (ulong)&trap, PMP_ADDR_MASK); \
if (!trap.cause) {
val = csr_read_allowed(CSR_PMPADDR0, (ulong)&trap);
if (trap.cause)
@@ -505,63 +327,27 @@ static unsigned long hart_pmp_get_allowed_addr(void)
return val;
}
static int hart_pmu_get_allowed_bits(void)
{
unsigned long val = ~(0UL);
struct sbi_trap_info trap = {0};
int num_bits = 0;
/**
* It is assumed that platforms will implement same number of bits for
* all the performance counters including mcycle/minstret.
*/
csr_write_allowed(CSR_MHPMCOUNTER3, (ulong)&trap, val);
if (!trap.cause) {
val = csr_read_allowed(CSR_MHPMCOUNTER3, (ulong)&trap);
if (trap.cause)
return 0;
}
num_bits = sbi_fls(val) + 1;
#if __riscv_xlen == 32
csr_write_allowed(CSR_MHPMCOUNTER3H, (ulong)&trap, val);
if (!trap.cause) {
val = csr_read_allowed(CSR_MHPMCOUNTER3H, (ulong)&trap);
if (trap.cause)
return num_bits;
}
num_bits += sbi_fls(val) + 1;
#endif
return num_bits;
}
static int hart_detect_features(struct sbi_scratch *scratch)
static void hart_detect_features(struct sbi_scratch *scratch)
{
struct sbi_trap_info trap = {0};
struct hart_features *hfeatures =
sbi_scratch_offset_ptr(scratch, hart_features_offset);
unsigned long val, oldval;
int rc;
struct hart_features *hfeatures;
unsigned long val;
/* If hart features already detected then do nothing */
if (hfeatures->detected)
return 0;
/* Clear hart features */
hfeatures->extensions = 0;
/* Reset hart features */
hfeatures = sbi_scratch_offset_ptr(scratch, hart_features_offset);
hfeatures->features = 0;
hfeatures->pmp_count = 0;
hfeatures->mhpm_count = 0;
#define __check_csr(__csr, __rdonly, __wrval, __field, __skip) \
oldval = csr_read_allowed(__csr, (ulong)&trap); \
val = csr_read_allowed(__csr, (ulong)&trap); \
if (!trap.cause) { \
if (__rdonly) { \
(hfeatures->__field)++; \
} else { \
csr_write_allowed(__csr, (ulong)&trap, __wrval);\
if (!trap.cause) { \
if (csr_swap(__csr, oldval) == __wrval) \
if (csr_swap(__csr, val) == __wrval) \
(hfeatures->__field)++; \
else \
goto __skip; \
@@ -597,8 +383,8 @@ static int hart_detect_features(struct sbi_scratch *scratch)
*/
val = hart_pmp_get_allowed_addr();
if (val) {
hfeatures->pmp_gran = 1 << (sbi_ffs(val) + 2);
hfeatures->pmp_addr_bits = sbi_fls(val) + 1;
hfeatures->pmp_gran = 1 << (__ffs(val) + 2);
hfeatures->pmp_addr_bits = __fls(val) + 1;
/* Detect number of PMP regions. At least PMPADDR0 should be implemented*/
__check_csr_64(CSR_PMPADDR0, 0, val, pmp_count, __pmp_skip);
}
@@ -606,17 +392,9 @@ __pmp_skip:
/* Detect number of MHPM counters */
__check_csr(CSR_MHPMCOUNTER3, 0, 1UL, mhpm_count, __mhpm_skip);
hfeatures->mhpm_bits = hart_pmu_get_allowed_bits();
__check_csr_4(CSR_MHPMCOUNTER4, 0, 1UL, mhpm_count, __mhpm_skip);
__check_csr_8(CSR_MHPMCOUNTER8, 0, 1UL, mhpm_count, __mhpm_skip);
__check_csr_16(CSR_MHPMCOUNTER16, 0, 1UL, mhpm_count, __mhpm_skip);
/**
* No need to check for MHPMCOUNTERH for RV32 as they are expected to be
* implemented if MHPMCOUNTER is implemented.
*/
__mhpm_skip:
#undef __check_csr_64
@@ -627,69 +405,26 @@ __mhpm_skip:
#undef __check_csr_2
#undef __check_csr
/* Detect if hart supports Priv v1.10 */
val = csr_read_allowed(CSR_MCOUNTEREN, (unsigned long)&trap);
if (!trap.cause)
hfeatures->priv_version = SBI_HART_PRIV_VER_1_10;
/* Detect if hart supports Priv v1.11 */
val = csr_read_allowed(CSR_MCOUNTINHIBIT, (unsigned long)&trap);
if (!trap.cause &&
(hfeatures->priv_version >= SBI_HART_PRIV_VER_1_10))
hfeatures->priv_version = SBI_HART_PRIV_VER_1_11;
/* Detect if hart supports Priv v1.12 */
csr_read_allowed(CSR_MENVCFG, (unsigned long)&trap);
if (!trap.cause &&
(hfeatures->priv_version >= SBI_HART_PRIV_VER_1_11))
hfeatures->priv_version = SBI_HART_PRIV_VER_1_12;
/* Counter overflow/filtering is not useful without mcounter/inhibit */
if (hfeatures->priv_version >= SBI_HART_PRIV_VER_1_12) {
/* Detect if hart supports sscofpmf */
csr_read_allowed(CSR_SCOUNTOVF, (unsigned long)&trap);
/* Detect if hart supports SCOUNTEREN feature */
val = csr_read_allowed(CSR_SCOUNTEREN, (unsigned long)&trap);
if (!trap.cause) {
csr_write_allowed(CSR_SCOUNTEREN, (unsigned long)&trap, val);
if (!trap.cause)
__sbi_hart_update_extension(hfeatures,
SBI_HART_EXT_SSCOFPMF, true);
hfeatures->features |= SBI_HART_HAS_SCOUNTEREN;
}
/* Detect if hart supports MCOUNTEREN feature */
val = csr_read_allowed(CSR_MCOUNTEREN, (unsigned long)&trap);
if (!trap.cause) {
csr_write_allowed(CSR_MCOUNTEREN, (unsigned long)&trap, val);
if (!trap.cause)
hfeatures->features |= SBI_HART_HAS_MCOUNTEREN;
}
/* Detect if hart supports time CSR */
csr_read_allowed(CSR_TIME, (unsigned long)&trap);
if (!trap.cause)
__sbi_hart_update_extension(hfeatures,
SBI_HART_EXT_TIME, true);
/* Detect if hart has AIA local interrupt CSRs */
csr_read_allowed(CSR_MTOPI, (unsigned long)&trap);
if (!trap.cause)
__sbi_hart_update_extension(hfeatures,
SBI_HART_EXT_AIA, true);
/* Detect if hart supports stimecmp CSR(Sstc extension) */
if (hfeatures->priv_version >= SBI_HART_PRIV_VER_1_12) {
csr_read_allowed(CSR_STIMECMP, (unsigned long)&trap);
if (!trap.cause)
__sbi_hart_update_extension(hfeatures,
SBI_HART_EXT_SSTC, true);
}
/* Detect if hart supports mstateen CSRs */
if (hfeatures->priv_version >= SBI_HART_PRIV_VER_1_12) {
val = csr_read_allowed(CSR_MSTATEEN0, (unsigned long)&trap);
if (!trap.cause)
__sbi_hart_update_extension(hfeatures,
SBI_HART_EXT_SMSTATEEN, true);
}
/* Let platform populate extensions */
rc = sbi_platform_extensions_init(sbi_platform_thishart_ptr());
if (rc)
return rc;
/* Mark hart feature detection done */
hfeatures->detected = true;
return 0;
hfeatures->features |= SBI_HART_HAS_TIME;
}
int sbi_hart_reinit(struct sbi_scratch *scratch)
@@ -711,21 +446,18 @@ int sbi_hart_reinit(struct sbi_scratch *scratch)
int sbi_hart_init(struct sbi_scratch *scratch, bool cold_boot)
{
int rc;
if (cold_boot) {
if (misa_extension('H'))
sbi_hart_expected_trap = &__sbi_expected_trap_hext;
hart_features_offset = sbi_scratch_alloc_offset(
sizeof(struct hart_features));
sizeof(struct hart_features),
"HART_FEATURES");
if (!hart_features_offset)
return SBI_ENOMEM;
}
rc = hart_detect_features(scratch);
if (rc)
return rc;
hart_detect_features(scratch);
return sbi_hart_reinit(scratch);
}

View File

@@ -27,7 +27,7 @@
.global __sbi_hfence_gvma_vmid_gpa
__sbi_hfence_gvma_vmid_gpa:
/*
* rs1 = a0 (GPA >> 2)
* rs1 = a0 (GPA)
* rs2 = a1 (VMID)
* HFENCE.GVMA a0, a1
* 0110001 01011 01010 000 00000 1110011
@@ -51,7 +51,7 @@ __sbi_hfence_gvma_vmid:
.global __sbi_hfence_gvma_gpa
__sbi_hfence_gvma_gpa:
/*
* rs1 = a0 (GPA >> 2)
* rs1 = a0 (GPA)
* rs2 = zero
* HFENCE.GVMA a0
* 0110001 00000 01010 000 00000 1110011

View File

@@ -36,8 +36,25 @@ struct sbi_hsm_data {
unsigned long saved_mie;
unsigned long saved_mip;
};
#define __sbi_hsm_hart_change_state(hdata, oldstate, newstate) \
({ \
long state = atomic_cmpxchg(&(hdata)->state, oldstate, newstate); \
if (state != (oldstate)) \
sbi_printf("%s: ERR: The hart is in invalid state [%lu]\n", \
__func__, state); \
state == (oldstate); \
})
static inline int __sbi_hsm_hart_get_state(u32 hartid)
int sbi_hsm_hart_change_state(struct sbi_scratch *scratch, long oldstate,
long newstate)
{
struct sbi_hsm_data *hdata = sbi_scratch_offset_ptr(scratch,
hart_data_offset);
return __sbi_hsm_hart_change_state(hdata, oldstate, newstate);
}
int __sbi_hsm_hart_get_state(u32 hartid)
{
struct sbi_hsm_data *hdata;
struct sbi_scratch *scratch;
@@ -113,8 +130,8 @@ static void sbi_hsm_hart_wait(struct sbi_scratch *scratch, u32 hartid)
/* Save MIE CSR */
saved_mie = csr_read(CSR_MIE);
/* Set MSIE and MEIE bits to receive IPI */
csr_set(CSR_MIE, MIP_MSIP | MIP_MEIP);
/* Set MSIE bit to receive IPI */
csr_set(CSR_MIE, MIP_MSIP);
/* Wait for hart_add call*/
while (atomic_read(&hdata->state) != SBI_HSM_STATE_START_PENDING) {
@@ -171,19 +188,13 @@ static int hsm_device_hart_stop(void)
return SBI_ENOTSUPP;
}
static int hsm_device_hart_suspend(u32 suspend_type)
static int hsm_device_hart_suspend(u32 suspend_type, ulong raddr)
{
if (hsm_dev && hsm_dev->hart_suspend)
return hsm_dev->hart_suspend(suspend_type);
return hsm_dev->hart_suspend(suspend_type, raddr);
return SBI_ENOTSUPP;
}
static void hsm_device_hart_resume(void)
{
if (hsm_dev && hsm_dev->hart_resume)
hsm_dev->hart_resume();
}
int sbi_hsm_init(struct sbi_scratch *scratch, u32 hartid, bool cold_boot)
{
u32 i;
@@ -191,7 +202,8 @@ int sbi_hsm_init(struct sbi_scratch *scratch, u32 hartid, bool cold_boot)
struct sbi_hsm_data *hdata;
if (cold_boot) {
hart_data_offset = sbi_scratch_alloc_offset(sizeof(*hdata));
hart_data_offset = sbi_scratch_alloc_offset(sizeof(*hdata),
"HART_DATA");
if (!hart_data_offset)
return SBI_ENOMEM;
@@ -319,7 +331,7 @@ int sbi_hsm_hart_stop(struct sbi_scratch *scratch, bool exitnow)
return 0;
}
static int __sbi_hsm_suspend_default(struct sbi_scratch *scratch)
static int __sbi_hsm_suspend_ret_default(struct sbi_scratch *scratch)
{
/* Wait for interrupt */
wfi();
@@ -327,7 +339,7 @@ static int __sbi_hsm_suspend_default(struct sbi_scratch *scratch)
return 0;
}
static void __sbi_hsm_suspend_non_ret_save(struct sbi_scratch *scratch)
void __sbi_hsm_suspend_non_ret_save(struct sbi_scratch *scratch)
{
struct sbi_hsm_data *hdata = sbi_scratch_offset_ptr(scratch,
hart_data_offset);
@@ -359,6 +371,29 @@ static void __sbi_hsm_suspend_non_ret_restore(struct sbi_scratch *scratch)
csr_write(CSR_MIP, (hdata->saved_mip & (MIP_SSIP | MIP_STIP)));
}
static int __sbi_hsm_suspend_non_ret_default(struct sbi_scratch *scratch,
ulong raddr)
{
void (*jump_warmboot)(void) = (void (*)(void))scratch->warmboot_addr;
/*
* Save some of the M-mode CSRs which should be restored after
* resuming from suspend state
*/
__sbi_hsm_suspend_non_ret_save(scratch);
/* Wait for interrupt */
wfi();
/*
* Directly jump to warm reboot to simulate resume from a
* non-retentive suspend.
*/
jump_warmboot();
return 0;
}
void sbi_hsm_hart_resume_start(struct sbi_scratch *scratch)
{
int oldstate;
@@ -373,8 +408,6 @@ void sbi_hsm_hart_resume_start(struct sbi_scratch *scratch)
__func__, oldstate);
sbi_hart_hang();
}
hsm_device_hart_resume();
}
void sbi_hsm_hart_resume_finish(struct sbi_scratch *scratch)
@@ -448,36 +481,18 @@ int sbi_hsm_hart_suspend(struct sbi_scratch *scratch, u32 suspend_type,
/* Save the suspend type */
hdata->suspend_type = suspend_type;
/*
* Save context which will be restored after resuming from
* non-retentive suspend.
*/
if (suspend_type & SBI_HSM_SUSP_NON_RET_BIT)
__sbi_hsm_suspend_non_ret_save(scratch);
/* Try platform specific suspend */
ret = hsm_device_hart_suspend(suspend_type);
ret = hsm_device_hart_suspend(suspend_type, scratch->warmboot_addr);
if (ret == SBI_ENOTSUPP) {
/* Try generic implementation of default suspend types */
if (suspend_type == SBI_HSM_SUSPEND_RET_DEFAULT ||
suspend_type == SBI_HSM_SUSPEND_NON_RET_DEFAULT) {
ret = __sbi_hsm_suspend_default(scratch);
if (suspend_type == SBI_HSM_SUSPEND_RET_DEFAULT) {
ret = __sbi_hsm_suspend_ret_default(scratch);
} else if (suspend_type == SBI_HSM_SUSPEND_NON_RET_DEFAULT) {
ret = __sbi_hsm_suspend_non_ret_default(scratch,
scratch->warmboot_addr);
}
}
/*
* The platform may have coordinated a retentive suspend, or it may
* have exited early from a non-retentive suspend. Either way, the
* caller is not expecting a successful return, so jump to the warm
* boot entry point to simulate resume from a non-retentive suspend.
*/
if (ret == 0 && (suspend_type & SBI_HSM_SUSP_NON_RET_BIT)) {
void (*jump_warmboot)(void) =
(void (*)(void))scratch->warmboot_addr;
jump_warmboot();
}
fail_restore_state:
/*
* We might have successfully resumed from retentive suspend

View File

@@ -8,16 +8,13 @@
*/
#include <sbi/riscv_asm.h>
#include <sbi/riscv_barrier.h>
#include <sbi/riscv_encoding.h>
#include <sbi/sbi_bitops.h>
#include <sbi/sbi_emulate_csr.h>
#include <sbi/sbi_error.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>
typedef int (*illegal_insn_func)(ulong insn, struct sbi_trap_regs *regs);
@@ -34,31 +31,13 @@ static int truly_illegal_insn(ulong insn, struct sbi_trap_regs *regs)
return sbi_trap_redirect(regs, &trap);
}
static int misc_mem_opcode_insn(ulong insn, struct sbi_trap_regs *regs)
{
/* Errata workaround: emulate `fence.tso` as `fence rw, rw`. */
if ((insn & INSN_MASK_FENCE_TSO) == INSN_MATCH_FENCE_TSO) {
smp_mb();
return 0;
}
return truly_illegal_insn(insn, regs);
}
static int system_opcode_insn(ulong insn, struct sbi_trap_regs *regs)
{
int do_write, rs1_num = (insn >> 15) & 0x1f;
ulong rs1_val = GET_RS1(insn, regs);
int csr_num = (u32)insn >> 20;
ulong prev_mode = (regs->mstatus & MSTATUS_MPP) >> MSTATUS_MPP_SHIFT;
ulong csr_val, new_csr_val;
if (prev_mode == PRV_M) {
sbi_printf("%s: Failed to access CSR %#x from M-mode",
__func__, csr_num);
return SBI_EFAIL;
}
/* TODO: Ensure that we got CSR read/write instruction */
if (sbi_emulate_csr_read(csr_num, regs, &csr_val))
@@ -100,11 +79,11 @@ static int system_opcode_insn(ulong insn, struct sbi_trap_regs *regs)
return 0;
}
static const illegal_insn_func illegal_insn_table[32] = {
static illegal_insn_func illegal_insn_table[32] = {
truly_illegal_insn, /* 0 */
truly_illegal_insn, /* 1 */
truly_illegal_insn, /* 2 */
misc_mem_opcode_insn, /* 3 */
truly_illegal_insn, /* 3 */
truly_illegal_insn, /* 4 */
truly_illegal_insn, /* 5 */
truly_illegal_insn, /* 6 */
@@ -150,7 +129,6 @@ int sbi_illegal_insn_handler(ulong insn, struct sbi_trap_regs *regs)
* instruction trap.
*/
sbi_pmu_ctr_incr_fw(SBI_PMU_FW_ILLEGAL_INSN);
if (unlikely((insn & 3) != 3)) {
insn = sbi_get_insn(regs->mepc, &uptrap);
if (uptrap.cause) {

View File

@@ -18,9 +18,7 @@
#include <sbi/sbi_hartmask.h>
#include <sbi/sbi_hsm.h>
#include <sbi/sbi_ipi.h>
#include <sbi/sbi_irqchip.h>
#include <sbi/sbi_platform.h>
#include <sbi/sbi_pmu.h>
#include <sbi/sbi_system.h>
#include <sbi/sbi_string.h>
#include <sbi/sbi_timer.h>
@@ -49,14 +47,6 @@ static void sbi_boot_print_banner(struct sbi_scratch *scratch)
OPENSBI_VERSION_MINOR);
#endif
#ifdef OPENSBI_BUILD_TIME_STAMP
sbi_printf("Build time: %s\n", OPENSBI_BUILD_TIME_STAMP);
#endif
#ifdef OPENSBI_BUILD_COMPILER_VERSION
sbi_printf("Build compiler: %s\n", OPENSBI_BUILD_COMPILER_VERSION);
#endif
sbi_printf(BANNER);
}
@@ -68,6 +58,7 @@ static void sbi_boot_print_general(struct sbi_scratch *scratch)
const struct sbi_timer_device *tdev;
const struct sbi_console_device *cdev;
const struct sbi_system_reset_device *srdev;
const struct sbi_system_suspend_device *susp_dev;
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
if (scratch->options & SBI_SCRATCH_NO_BOOT_PRINTS)
@@ -84,21 +75,20 @@ static void sbi_boot_print_general(struct sbi_scratch *scratch)
sbi_printf("Platform IPI Device : %s\n",
(idev) ? idev->name : "---");
tdev = sbi_timer_get_device();
sbi_printf("Platform Timer Device : %s @ %luHz\n",
(tdev) ? tdev->name : "---",
(tdev) ? tdev->timer_freq : 0);
sbi_printf("Platform Timer Device : %s\n",
(tdev) ? tdev->name : "---");
cdev = sbi_console_get_device();
sbi_printf("Platform Console Device : %s\n",
(cdev) ? cdev->name : "---");
hdev = sbi_hsm_get_device();
sbi_printf("Platform HSM Device : %s\n",
(hdev) ? hdev->name : "---");
srdev = sbi_system_reset_get_device(SBI_SRST_RESET_TYPE_COLD_REBOOT, 0);
sbi_printf("Platform Reboot Device : %s\n",
(srdev) ? srdev->name : "---");
srdev = sbi_system_reset_get_device(SBI_SRST_RESET_TYPE_SHUTDOWN, 0);
sbi_printf("Platform Shutdown Device : %s\n",
srdev = sbi_system_reset_get_device();
sbi_printf("Platform SysReset Device : %s\n",
(srdev) ? srdev->name : "---");
susp_dev = sbi_system_suspend_get_device();
sbi_printf("Platform Suspend Device : %s\n",
(susp_dev) ? susp_dev->name : "---");
/* Firmware details */
sbi_printf("Firmware Base : 0x%lx\n", scratch->fw_start);
@@ -139,12 +129,10 @@ static void sbi_boot_print_hart(struct sbi_scratch *scratch, u32 hartid)
/* Boot HART details */
sbi_printf("Boot HART ID : %u\n", hartid);
sbi_printf("Boot HART Domain : %s\n", dom->name);
sbi_hart_get_priv_version_str(scratch, str, sizeof(str));
sbi_printf("Boot HART Priv Version : %s\n", str);
misa_string(xlen, str, sizeof(str));
sbi_printf("Boot HART Base ISA : %s\n", str);
sbi_hart_get_extensions_str(scratch, str, sizeof(str));
sbi_printf("Boot HART ISA Extensions : %s\n", str);
sbi_printf("Boot HART ISA : %s\n", str);
sbi_hart_get_features_str(scratch, str, sizeof(str));
sbi_printf("Boot HART Features : %s\n", str);
sbi_printf("Boot HART PMP Count : %d\n",
sbi_hart_pmp_count(scratch));
sbi_printf("Boot HART PMP Granularity : %lu\n",
@@ -153,6 +141,8 @@ static void sbi_boot_print_hart(struct sbi_scratch *scratch, u32 hartid)
sbi_hart_pmp_addrbits(scratch));
sbi_printf("Boot HART MHPM Count : %d\n",
sbi_hart_mhpm_count(scratch));
sbi_printf("Boot HART MHPM Count : %d\n",
sbi_hart_mhpm_count(scratch));
sbi_hart_delegation_dump(scratch, "Boot HART ", " ");
}
@@ -168,8 +158,8 @@ static void wait_for_coldboot(struct sbi_scratch *scratch, u32 hartid)
/* Save MIE CSR */
saved_mie = csr_read(CSR_MIE);
/* Set MSIE and MEIE bits to receive IPI */
csr_set(CSR_MIE, MIP_MSIP | MIP_MEIP);
/* Set MSIE bit to receive IPI */
csr_set(CSR_MIE, MIP_MSIP);
/* Acquire coldboot lock */
spin_lock(&coldboot_lock);
@@ -185,7 +175,7 @@ static void wait_for_coldboot(struct sbi_scratch *scratch, u32 hartid)
do {
wfi();
cmip = csr_read(CSR_MIP);
} while (!(cmip & (MIP_MSIP | MIP_MEIP)));
} while (!(cmip & MIP_MSIP));
};
/* Acquire coldboot lock */
@@ -219,7 +209,7 @@ static void wake_coldboot_harts(struct sbi_scratch *scratch, u32 hartid)
spin_lock(&coldboot_lock);
/* Send an IPI to all HARTs waiting for coldboot */
for (u32 i = 0; i <= sbi_scratch_last_hartid(); i++) {
for (int i = 0; i <= sbi_scratch_last_hartid(); i++) {
if ((i != hartid) &&
sbi_hartmask_test_hart(i, &coldboot_wait_hmask))
sbi_ipi_raw_send(i);
@@ -235,7 +225,9 @@ static void __noreturn init_coldboot(struct sbi_scratch *scratch, u32 hartid)
{
int rc;
unsigned long *init_count;
#ifndef CONFIG_OPENSBI_FASTBOOT
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
#endif
/* Note: This has to be first thing in coldboot init sequence */
rc = sbi_scratch_init(scratch);
@@ -247,7 +239,8 @@ static void __noreturn init_coldboot(struct sbi_scratch *scratch, u32 hartid)
if (rc)
sbi_hart_hang();
init_count_offset = sbi_scratch_alloc_offset(__SIZEOF_POINTER__);
init_count_offset = sbi_scratch_alloc_offset(__SIZEOF_POINTER__,
"INIT_COUNT");
if (!init_count_offset)
sbi_hart_hang();
@@ -255,27 +248,28 @@ static void __noreturn init_coldboot(struct sbi_scratch *scratch, u32 hartid)
if (rc)
sbi_hart_hang();
#ifndef CONFIG_OPENSBI_FASTBOOT
rc = sbi_platform_early_init(plat, TRUE);
if (rc)
sbi_hart_hang();
#endif
rc = sbi_hart_init(scratch, TRUE);
if (rc)
sbi_hart_hang();
#ifndef CONFIG_OPENSBI_FASTBOOT
rc = sbi_console_init(scratch);
if (rc)
sbi_hart_hang();
rc = sbi_pmu_init(scratch, TRUE);
if (rc)
sbi_hart_hang();
#endif
sbi_boot_print_banner(scratch);
rc = sbi_irqchip_init(scratch, TRUE);
#ifndef CONFIG_OPENSBI_FASTBOOT
rc = sbi_platform_irqchip_init(plat, TRUE);
if (rc) {
sbi_printf("%s: irqchip init failed (error %d)\n",
sbi_printf("%s: platform irqchip init failed (error %d)\n",
__func__, rc);
sbi_hart_hang();
}
@@ -285,6 +279,7 @@ static void __noreturn init_coldboot(struct sbi_scratch *scratch, u32 hartid)
sbi_printf("%s: ipi init failed (error %d)\n", __func__, rc);
sbi_hart_hang();
}
#endif
rc = sbi_tlb_init(scratch, TRUE);
if (rc) {
@@ -304,6 +299,8 @@ static void __noreturn init_coldboot(struct sbi_scratch *scratch, u32 hartid)
sbi_hart_hang();
}
sbi_boot_print_general(scratch);
/*
* Note: Finalize domains after HSM initialization so that we
* can startup non-root domains.
@@ -317,6 +314,8 @@ static void __noreturn init_coldboot(struct sbi_scratch *scratch, u32 hartid)
sbi_hart_hang();
}
sbi_boot_print_domains(scratch);
rc = sbi_hart_pmp_configure(scratch);
if (rc) {
sbi_printf("%s: PMP configure failed (error %d)\n",
@@ -328,16 +327,14 @@ static void __noreturn init_coldboot(struct sbi_scratch *scratch, u32 hartid)
* Note: Platform final initialization should be last so that
* it sees correct domain assignment and PMP configuration.
*/
#ifndef CONFIG_OPENSBI_FASTBOOT
rc = sbi_platform_final_init(plat, TRUE);
if (rc) {
sbi_printf("%s: platform final init failed (error %d)\n",
__func__, rc);
sbi_hart_hang();
}
sbi_boot_print_general(scratch);
sbi_boot_print_domains(scratch);
#endif
sbi_boot_print_hart(scratch, hartid);
@@ -372,11 +369,7 @@ static void init_warm_startup(struct sbi_scratch *scratch, u32 hartid)
if (rc)
sbi_hart_hang();
rc = sbi_pmu_init(scratch, FALSE);
if (rc)
sbi_hart_hang();
rc = sbi_irqchip_init(scratch, FALSE);
rc = sbi_platform_irqchip_init(plat, FALSE);
if (rc)
sbi_hart_hang();
@@ -497,14 +490,6 @@ void __noreturn sbi_init(struct sbi_scratch *scratch)
if (next_mode_supported && atomic_xchg(&coldboot_lottery, 1) == 0)
coldboot = TRUE;
/*
* Do platform specific nascent (very early) initialization so
* that platform can initialize platform specific per-HART CSRs
* or per-HART devices.
*/
if (sbi_platform_nascent_init(plat))
sbi_hart_hang();
if (coldboot)
init_coldboot(scratch, hartid);
else
@@ -547,13 +532,11 @@ void __noreturn sbi_exit(struct sbi_scratch *scratch)
sbi_platform_early_exit(plat);
sbi_pmu_exit(scratch);
sbi_timer_exit(scratch);
sbi_ipi_exit(scratch);
sbi_irqchip_exit(scratch);
sbi_platform_irqchip_exit(plat);
sbi_platform_final_exit(plat);

View File

@@ -19,9 +19,6 @@
#include <sbi/sbi_init.h>
#include <sbi/sbi_ipi.h>
#include <sbi/sbi_platform.h>
#include <sbi/sbi_pmu.h>
#include <sbi/sbi_string.h>
#include <sbi/sbi_tlb.h>
struct sbi_ipi_data {
unsigned long ipi_type;
@@ -67,8 +64,6 @@ static int sbi_ipi_send(struct sbi_scratch *scratch, u32 remote_hartid,
if (ipi_dev && ipi_dev->ipi_send)
ipi_dev->ipi_send(remote_hartid);
sbi_pmu_ctr_incr_fw(SBI_PMU_FW_IPI_SENT);
if (ipi_ops->sync)
ipi_ops->sync(scratch);
@@ -188,7 +183,6 @@ void sbi_ipi_process(void)
sbi_scratch_offset_ptr(scratch, ipi_data_off);
u32 hartid = current_hartid();
sbi_pmu_ctr_incr_fw(SBI_PMU_FW_IPI_RECVD);
if (ipi_dev && ipi_dev->ipi_clear)
ipi_dev->ipi_clear(hartid);
@@ -233,7 +227,8 @@ int sbi_ipi_init(struct sbi_scratch *scratch, bool cold_boot)
struct sbi_ipi_data *ipi_data;
if (cold_boot) {
ipi_data_off = sbi_scratch_alloc_offset(sizeof(*ipi_data));
ipi_data_off = sbi_scratch_alloc_offset(sizeof(*ipi_data),
"IPI_DATA");
if (!ipi_data_off)
return SBI_ENOMEM;
ret = sbi_ipi_event_create(&ipi_smode_ops);

View File

@@ -1,54 +0,0 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2022 Ventana Micro Systems Inc.
*
* Authors:
* Anup Patel <apatel@ventanamicro.com>
*/
#include <sbi/sbi_irqchip.h>
#include <sbi/sbi_platform.h>
static int default_irqfn(struct sbi_trap_regs *regs)
{
return SBI_ENODEV;
}
static int (*ext_irqfn)(struct sbi_trap_regs *regs) = default_irqfn;
void sbi_irqchip_set_irqfn(int (*fn)(struct sbi_trap_regs *regs))
{
if (fn)
ext_irqfn = fn;
}
int sbi_irqchip_process(struct sbi_trap_regs *regs)
{
return ext_irqfn(regs);
}
int sbi_irqchip_init(struct sbi_scratch *scratch, bool cold_boot)
{
int rc;
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
rc = sbi_platform_irqchip_init(plat, cold_boot);
if (rc)
return rc;
if (ext_irqfn != default_irqfn)
csr_set(CSR_MIE, MIP_MEIP);
return 0;
}
void sbi_irqchip_exit(struct sbi_scratch *scratch)
{
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
if (ext_irqfn != default_irqfn)
csr_clear(CSR_MIE, MIP_MEIP);
sbi_platform_irqchip_exit(plat);
}

View File

@@ -12,7 +12,6 @@
#include <sbi/riscv_fp.h>
#include <sbi/sbi_error.h>
#include <sbi/sbi_misaligned_ldst.h>
#include <sbi/sbi_pmu.h>
#include <sbi/sbi_trap.h>
#include <sbi/sbi_unpriv.h>
@@ -22,18 +21,6 @@ union reg_data {
u64 data_u64;
};
static ulong sbi_misaligned_tinst_fixup(ulong orig_tinst, ulong new_tinst,
ulong addr_offset)
{
if (new_tinst == INSN_PSEUDO_VS_LOAD ||
new_tinst == INSN_PSEUDO_VS_STORE)
return new_tinst;
else if (orig_tinst == 0)
return 0UL;
else
return orig_tinst | (addr_offset << SH_RS1);
}
int sbi_misaligned_load_handler(ulong addr, ulong tval2, ulong tinst,
struct sbi_trap_regs *regs)
{
@@ -42,8 +29,6 @@ int sbi_misaligned_load_handler(ulong addr, ulong tval2, ulong tinst,
struct sbi_trap_info uptrap;
int i, fp = 0, shift = 0, len = 0;
sbi_pmu_ctr_incr_fw(SBI_PMU_FW_MISALIGNED_LOAD);
if (tinst & 0x1) {
/*
* Bit[0] == 1 implies trapped instruction value is
@@ -138,8 +123,6 @@ int sbi_misaligned_load_handler(ulong addr, ulong tval2, ulong tinst,
&uptrap);
if (uptrap.cause) {
uptrap.epc = regs->mepc;
uptrap.tinst = sbi_misaligned_tinst_fixup(
tinst, uptrap.tinst, i);
return sbi_trap_redirect(regs, &uptrap);
}
}
@@ -166,8 +149,6 @@ int sbi_misaligned_store_handler(ulong addr, ulong tval2, ulong tinst,
struct sbi_trap_info uptrap;
int i, len = 0;
sbi_pmu_ctr_incr_fw(SBI_PMU_FW_MISALIGNED_STORE);
if (tinst & 0x1) {
/*
* Bit[0] == 1 implies trapped instruction value is
@@ -252,8 +233,6 @@ int sbi_misaligned_store_handler(ulong addr, ulong tval2, ulong tinst,
&uptrap);
if (uptrap.cause) {
uptrap.epc = regs->mepc;
uptrap.tinst = sbi_misaligned_tinst_fixup(
tinst, uptrap.tinst, i);
return sbi_trap_redirect(regs, &uptrap);
}
}

View File

@@ -20,7 +20,7 @@ static inline char *sbi_platform_feature_id2string(unsigned long feature)
switch (feature) {
case SBI_PLATFORM_HAS_MFAULTS_DELEGATION:
fstr = "medeleg";
fstr = "mfdeleg";
break;
default:
break;
@@ -48,18 +48,9 @@ void sbi_platform_get_features_str(const struct sbi_platform *plat,
if (features & feat) {
temp = sbi_platform_feature_id2string(feat);
if (temp) {
int len = sbi_snprintf(features_str + offset,
nfstr - offset,
"%s,", temp);
if (len < 0)
break;
if (offset + len >= nfstr) {
/* No more space for features */
offset = nfstr;
break;
} else
offset = offset + len;
sbi_snprintf(features_str + offset, nfstr,
"%s,", temp);
offset = offset + sbi_strlen(temp) + 1;
}
}
feat = feat << 1;

View File

@@ -1,766 +0,0 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2021 Western Digital Corporation or its affiliates.
*
* Authors:
* Atish Patra <atish.patra@wdc.com>
*/
#include <sbi/riscv_asm.h>
#include <sbi/sbi_bitops.h>
#include <sbi/sbi_console.h>
#include <sbi/sbi_hart.h>
#include <sbi/sbi_platform.h>
#include <sbi/sbi_pmu.h>
#include <sbi/sbi_scratch.h>
#include <sbi/sbi_string.h>
/** Information about hardware counters */
struct sbi_pmu_hw_event {
uint32_t counters;
uint32_t start_idx;
uint32_t end_idx;
/* Event selector value used only for raw events. The event select value
* can be a even id or a selector value for set of events encoded in few
* bits. In case latter, the bits used for encoding of the events should
* be zeroed out in the select value.
*/
uint64_t select;
/**
* The select_mask indicates which bits are encoded for the event(s).
*/
uint64_t select_mask;
};
/** Representation of a firmware event */
struct sbi_pmu_fw_event {
/* Event associated with the particular counter */
uint32_t event_idx;
/* Current value of the counter */
unsigned long curr_count;
/* A flag indicating pmu event monitoring is started */
bool bStarted;
};
/* Information about PMU counters as per SBI specification */
union sbi_pmu_ctr_info {
unsigned long value;
struct {
unsigned long csr:12;
unsigned long width:6;
#if __riscv_xlen == 32
unsigned long reserved:13;
#else
unsigned long reserved:45;
#endif
unsigned long type:1;
};
};
/* Mapping between event range and possible counters */
static struct sbi_pmu_hw_event hw_event_map[SBI_PMU_HW_EVENT_MAX] = {0};
/* counter to enabled event mapping */
static uint32_t active_events[SBI_HARTMASK_MAX_BITS][SBI_PMU_HW_CTR_MAX + SBI_PMU_FW_CTR_MAX];
/* Contains all the information about firmwares events */
static struct sbi_pmu_fw_event fw_event_map[SBI_HARTMASK_MAX_BITS][SBI_PMU_FW_EVENT_MAX] = {0};
/* Maximum number of hardware events available */
static uint32_t num_hw_events;
/* Maximum number of hardware counters available */
static uint32_t num_hw_ctrs;
/* Maximum number of counters available */
static uint32_t total_ctrs;
/* Helper macros to retrieve event idx and code type */
#define get_cidx_type(x) ((x & SBI_PMU_EVENT_IDX_TYPE_MASK) >> 16)
#define get_cidx_code(x) (x & SBI_PMU_EVENT_IDX_CODE_MASK)
/**
* Perform a sanity check on event & counter mappings with event range overlap check
* @param evtA Pointer to the existing hw event structure
* @param evtB Pointer to the new hw event structure
*
* Return FALSE if the range doesn't overlap, TRUE otherwise
*/
static bool pmu_event_range_overlap(struct sbi_pmu_hw_event *evtA,
struct sbi_pmu_hw_event *evtB)
{
/* check if the range of events overlap with a previous entry */
if (((evtA->end_idx < evtB->start_idx) && (evtA->end_idx < evtB->end_idx)) ||
((evtA->start_idx > evtB->start_idx) && (evtA->start_idx > evtB->end_idx)))
return FALSE;
return TRUE;
}
static bool pmu_event_select_overlap(struct sbi_pmu_hw_event *evt,
uint64_t select_val, uint64_t select_mask)
{
if ((evt->select == select_val) && (evt->select_mask == select_mask))
return TRUE;
return FALSE;
}
static int pmu_ctr_validate(uint32_t cidx, uint32_t *event_idx_code)
{
uint32_t event_idx_val;
uint32_t event_idx_type;
u32 hartid = current_hartid();
event_idx_val = active_events[hartid][cidx];
if (cidx >= total_ctrs || (event_idx_val == SBI_PMU_EVENT_IDX_INVALID))
return SBI_EINVAL;
event_idx_type = get_cidx_type(event_idx_val);
if (event_idx_type >= SBI_PMU_EVENT_TYPE_MAX)
return SBI_EINVAL;
*event_idx_code = get_cidx_code(event_idx_val);
return event_idx_type;
}
static int pmu_ctr_read_fw(uint32_t cidx, unsigned long *cval,
uint32_t fw_evt_code)
{
u32 hartid = current_hartid();
struct sbi_pmu_fw_event fevent;
fevent = fw_event_map[hartid][fw_evt_code];
*cval = fevent.curr_count;
return 0;
}
/* Add a hardware counter read for completeness for future purpose */
static int pmu_ctr_read_hw(uint32_t cidx, uint64_t *cval)
{
/* Check for invalid hw counter read requests */
if (unlikely(cidx == 1))
return SBI_EINVAL;
#if __riscv_xlen == 32
uint32_t temp, temph = 0;
temp = csr_read_num(CSR_MCYCLE + cidx);
temph = csr_read_num(CSR_MCYCLEH + cidx);
*cval = ((uint64_t)temph << 32) | temp;
#else
*cval = csr_read_num(CSR_MCYCLE + cidx);
#endif
return 0;
}
int sbi_pmu_ctr_read(uint32_t cidx, unsigned long *cval)
{
int event_idx_type;
uint32_t event_code;
uint64_t cval64;
event_idx_type = pmu_ctr_validate(cidx, &event_code);
if (event_idx_type < 0)
return SBI_EINVAL;
else if (event_idx_type == SBI_PMU_EVENT_TYPE_FW)
pmu_ctr_read_fw(cidx, cval, event_code);
else
pmu_ctr_read_hw(cidx, &cval64);
return 0;
}
static int pmu_add_hw_event_map(u32 eidx_start, u32 eidx_end, u32 cmap,
uint64_t select, uint64_t select_mask)
{
int i = 0;
bool is_overlap;
struct sbi_pmu_hw_event *event = &hw_event_map[num_hw_events];
struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
int hw_ctr_avail = sbi_hart_mhpm_count(scratch);
uint32_t ctr_avail_mask = ((uint32_t)(~0) >> (32 - (hw_ctr_avail + 3)));
/* The first two counters are reserved by priv spec */
if (eidx_start > SBI_PMU_HW_INSTRUCTIONS && (cmap & SBI_PMU_FIXED_CTR_MASK))
return SBI_EDENIED;
if (num_hw_events >= SBI_PMU_HW_EVENT_MAX - 1) {
sbi_printf("Can not handle more than %d perf events\n",
SBI_PMU_HW_EVENT_MAX);
return SBI_EFAIL;
}
event->start_idx = eidx_start;
event->end_idx = eidx_end;
/* Sanity check */
for (i = 0; i < num_hw_events; i++) {
if (eidx_start == SBI_PMU_EVENT_RAW_IDX)
/* All raw events have same event idx. Just do sanity check on select */
is_overlap = pmu_event_select_overlap(&hw_event_map[i],
select, select_mask);
else
is_overlap = pmu_event_range_overlap(&hw_event_map[i], event);
if (is_overlap)
goto reset_event;
}
event->select_mask = select_mask;
/* Map the only the counters that are available in the hardware */
event->counters = cmap & ctr_avail_mask;
event->select = select;
num_hw_events++;
return 0;
reset_event:
event->start_idx = 0;
event->end_idx = 0;
return SBI_EINVAL;
}
/**
* Logical counter ids are assigned to hardware counters are assigned consecutively.
* E.g. counter0 must count MCYCLE where counter2 must count minstret. Similarly,
* counterX will mhpmcounterX.
*/
int sbi_pmu_add_hw_event_counter_map(u32 eidx_start, u32 eidx_end, u32 cmap)
{
if ((eidx_start > eidx_end) || eidx_start == SBI_PMU_EVENT_RAW_IDX ||
eidx_end == SBI_PMU_EVENT_RAW_IDX)
return SBI_EINVAL;
return pmu_add_hw_event_map(eidx_start, eidx_end, cmap, 0, 0);
}
int sbi_pmu_add_raw_event_counter_map(uint64_t select, uint64_t select_mask, u32 cmap)
{
return pmu_add_hw_event_map(SBI_PMU_EVENT_RAW_IDX,
SBI_PMU_EVENT_RAW_IDX, cmap, select, select_mask);
}
static int pmu_ctr_enable_irq_hw(int ctr_idx)
{
unsigned long mhpmevent_csr;
unsigned long mhpmevent_curr;
unsigned long mip_val;
unsigned long of_mask;
if (ctr_idx < 3 || ctr_idx >= SBI_PMU_HW_CTR_MAX)
return SBI_EFAIL;
#if __riscv_xlen == 32
mhpmevent_csr = CSR_MHPMEVENT3H + ctr_idx - 3;
of_mask = (uint32_t)~MHPMEVENTH_OF;
#else
mhpmevent_csr = CSR_MHPMEVENT3 + ctr_idx - 3;
of_mask = ~MHPMEVENT_OF;
#endif
mhpmevent_curr = csr_read_num(mhpmevent_csr);
mip_val = csr_read(CSR_MIP);
/**
* Clear out the OF bit so that next interrupt can be enabled.
* This should be done only when the corresponding overflow interrupt
* bit is cleared. That indicates that software has already handled the
* previous interrupts or the hardware yet to set an overflow interrupt.
* Otherwise, there will be race conditions where we may clear the bit
* the software is yet to handle the interrupt.
*/
if (!(mip_val & MIP_LCOFIP)) {
mhpmevent_curr &= of_mask;
csr_write_num(mhpmevent_csr, mhpmevent_curr);
}
return 0;
}
static void pmu_ctr_write_hw(uint32_t cidx, uint64_t ival)
{
#if __riscv_xlen == 32
csr_write_num(CSR_MCYCLE + cidx, 0);
csr_write_num(CSR_MCYCLE + cidx, ival & 0xFFFFFFFF);
csr_write_num(CSR_MCYCLEH + cidx, ival >> BITS_PER_LONG);
#else
csr_write_num(CSR_MCYCLE + cidx, ival);
#endif
}
static int pmu_ctr_start_hw(uint32_t cidx, uint64_t ival, bool ival_update)
{
struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
unsigned long mctr_inhbt;
/* Make sure the counter index lies within the range and is not TM bit */
if (cidx >= num_hw_ctrs || cidx == 1)
return SBI_EINVAL;
if (sbi_hart_priv_version(scratch) < SBI_HART_PRIV_VER_1_11)
goto skip_inhibit_update;
/*
* Some of the hardware may not support mcountinhibit but perf stat
* still can work if supervisor mode programs the initial value.
*/
mctr_inhbt = csr_read(CSR_MCOUNTINHIBIT);
if (!__test_bit(cidx, &mctr_inhbt))
return SBI_EALREADY_STARTED;
__clear_bit(cidx, &mctr_inhbt);
if (sbi_hart_has_extension(scratch, SBI_HART_EXT_SSCOFPMF))
pmu_ctr_enable_irq_hw(cidx);
csr_write(CSR_MCOUNTINHIBIT, mctr_inhbt);
skip_inhibit_update:
if (ival_update)
pmu_ctr_write_hw(cidx, ival);
return 0;
}
static int pmu_ctr_start_fw(uint32_t cidx, uint32_t fw_evt_code,
uint64_t ival, bool ival_update)
{
u32 hartid = current_hartid();
struct sbi_pmu_fw_event *fevent;
fevent = &fw_event_map[hartid][fw_evt_code];
if (ival_update)
fevent->curr_count = ival;
fevent->bStarted = TRUE;
return 0;
}
int sbi_pmu_ctr_start(unsigned long cbase, unsigned long cmask,
unsigned long flags, uint64_t ival)
{
int event_idx_type;
uint32_t event_code;
unsigned long ctr_mask = cmask << cbase;
int ret = SBI_EINVAL;
bool bUpdate = FALSE;
if (sbi_fls(ctr_mask) >= total_ctrs)
return ret;
if (flags & SBI_PMU_START_FLAG_SET_INIT_VALUE)
bUpdate = TRUE;
for_each_set_bit_from(cbase, &ctr_mask, total_ctrs) {
event_idx_type = pmu_ctr_validate(cbase, &event_code);
if (event_idx_type < 0)
/* Continue the start operation for other counters */
continue;
else if (event_idx_type == SBI_PMU_EVENT_TYPE_FW)
ret = pmu_ctr_start_fw(cbase, event_code, ival, bUpdate);
else
ret = pmu_ctr_start_hw(cbase, ival, bUpdate);
}
return ret;
}
static int pmu_ctr_stop_hw(uint32_t cidx)
{
struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
unsigned long mctr_inhbt;
if (sbi_hart_priv_version(scratch) < SBI_HART_PRIV_VER_1_11)
return 0;
mctr_inhbt = csr_read(CSR_MCOUNTINHIBIT);
/* Make sure the counter index lies within the range and is not TM bit */
if (cidx >= num_hw_ctrs || cidx == 1)
return SBI_EINVAL;
if (!__test_bit(cidx, &mctr_inhbt)) {
__set_bit(cidx, &mctr_inhbt);
csr_write(CSR_MCOUNTINHIBIT, mctr_inhbt);
return 0;
} else
return SBI_EALREADY_STOPPED;
}
static int pmu_ctr_stop_fw(uint32_t cidx, uint32_t fw_evt_code)
{
u32 hartid = current_hartid();
fw_event_map[hartid][fw_evt_code].bStarted = FALSE;
return 0;
}
static int pmu_reset_hw_mhpmevent(int ctr_idx)
{
if (ctr_idx < 3 || ctr_idx >= SBI_PMU_HW_CTR_MAX)
return SBI_EFAIL;
#if __riscv_xlen == 32
csr_write_num(CSR_MHPMEVENT3 + ctr_idx - 3, 0);
if (sbi_hart_has_extension(sbi_scratch_thishart_ptr(),
SBI_HART_EXT_SSCOFPMF))
csr_write_num(CSR_MHPMEVENT3H + ctr_idx - 3, 0);
#else
csr_write_num(CSR_MHPMEVENT3 + ctr_idx - 3, 0);
#endif
return 0;
}
int sbi_pmu_ctr_stop(unsigned long cbase, unsigned long cmask,
unsigned long flag)
{
u32 hartid = current_hartid();
int ret = SBI_EINVAL;
int event_idx_type;
uint32_t event_code;
unsigned long ctr_mask = cmask << cbase;
if (sbi_fls(ctr_mask) >= total_ctrs)
return SBI_EINVAL;
for_each_set_bit_from(cbase, &ctr_mask, total_ctrs) {
event_idx_type = pmu_ctr_validate(cbase, &event_code);
if (event_idx_type < 0)
/* Continue the stop operation for other counters */
continue;
else if (event_idx_type == SBI_PMU_EVENT_TYPE_FW)
ret = pmu_ctr_stop_fw(cbase, event_code);
else
ret = pmu_ctr_stop_hw(cbase);
if (flag & SBI_PMU_STOP_FLAG_RESET) {
active_events[hartid][cbase] = SBI_PMU_EVENT_IDX_INVALID;
pmu_reset_hw_mhpmevent(cbase);
}
}
return ret;
}
static void pmu_update_inhibit_flags(unsigned long flags, uint64_t *mhpmevent_val)
{
if (flags & SBI_PMU_CFG_FLAG_SET_VUINH)
*mhpmevent_val |= MHPMEVENT_VUINH;
if (flags & SBI_PMU_CFG_FLAG_SET_VSINH)
*mhpmevent_val |= MHPMEVENT_VSINH;
if (flags & SBI_PMU_CFG_FLAG_SET_UINH)
*mhpmevent_val |= MHPMEVENT_UINH;
if (flags & SBI_PMU_CFG_FLAG_SET_SINH)
*mhpmevent_val |= MHPMEVENT_SINH;
}
static int pmu_update_hw_mhpmevent(struct sbi_pmu_hw_event *hw_evt, int ctr_idx,
unsigned long flags, unsigned long eindex,
uint64_t data)
{
struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
uint64_t mhpmevent_val;
/* Get the final mhpmevent value to be written from platform */
mhpmevent_val = sbi_platform_pmu_xlate_to_mhpmevent(plat, eindex, data);
if (!mhpmevent_val || ctr_idx < 3 || ctr_idx >= SBI_PMU_HW_CTR_MAX)
return SBI_EFAIL;
/**
* Always set the OVF bit(disable interrupts) and inhibit counting of
* events in M-mode. The OVF bit should be enabled during the start call.
*/
if (sbi_hart_has_extension(scratch, SBI_HART_EXT_SSCOFPMF))
mhpmevent_val = (mhpmevent_val & ~MHPMEVENT_SSCOF_MASK) |
MHPMEVENT_MINH | MHPMEVENT_OF;
/* Update the inhibit flags based on inhibit flags received from supervisor */
pmu_update_inhibit_flags(flags, &mhpmevent_val);
#if __riscv_xlen == 32
csr_write_num(CSR_MHPMEVENT3 + ctr_idx - 3, mhpmevent_val & 0xFFFFFFFF);
if (sbi_hart_has_extension(scratch, SBI_HART_EXT_SSCOFPMF))
csr_write_num(CSR_MHPMEVENT3H + ctr_idx - 3,
mhpmevent_val >> BITS_PER_LONG);
#else
csr_write_num(CSR_MHPMEVENT3 + ctr_idx - 3, mhpmevent_val);
#endif
return 0;
}
static int pmu_ctr_find_fixed_fw(unsigned long evt_idx_code)
{
/* Non-programmables counters are enabled always. No need to do lookup */
if (evt_idx_code == SBI_PMU_HW_CPU_CYCLES)
return 0;
else if (evt_idx_code == SBI_PMU_HW_INSTRUCTIONS)
return 2;
else
return SBI_EINVAL;
}
static int pmu_ctr_find_hw(unsigned long cbase, unsigned long cmask, unsigned long flags,
unsigned long event_idx, uint64_t data)
{
unsigned long ctr_mask;
int i, ret = 0, fixed_ctr, ctr_idx = SBI_ENOTSUPP;
struct sbi_pmu_hw_event *temp;
unsigned long mctr_inhbt = 0;
u32 hartid = current_hartid();
struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
if (cbase >= num_hw_ctrs)
return SBI_EINVAL;
/**
* If Sscof is present try to find the programmable counter for
* cycle/instret as well.
*/
fixed_ctr = pmu_ctr_find_fixed_fw(event_idx);
if (fixed_ctr >= 0 &&
!sbi_hart_has_extension(scratch, SBI_HART_EXT_SSCOFPMF))
return fixed_ctr;
if (sbi_hart_priv_version(scratch) >= SBI_HART_PRIV_VER_1_11)
mctr_inhbt = csr_read(CSR_MCOUNTINHIBIT);
for (i = 0; i < num_hw_events; i++) {
temp = &hw_event_map[i];
if ((temp->start_idx > event_idx && event_idx < temp->end_idx) ||
(temp->start_idx < event_idx && event_idx > temp->end_idx))
continue;
/* For raw events, event data is used as the select value */
if (event_idx == SBI_PMU_EVENT_RAW_IDX) {
uint64_t select_mask = temp->select_mask;
/* The non-event map bits of data should match the selector */
if (temp->select != (data & select_mask))
continue;
}
/* Fixed counters should not be part of the search */
ctr_mask = temp->counters & (cmask << cbase) &
(~SBI_PMU_FIXED_CTR_MASK);
for_each_set_bit_from(cbase, &ctr_mask, SBI_PMU_HW_CTR_MAX) {
/**
* Some of the platform may not support mcountinhibit.
* Checking the active_events is enough for them
*/
if (active_events[hartid][cbase] != SBI_PMU_EVENT_IDX_INVALID)
continue;
/* If mcountinhibit is supported, the bit must be enabled */
if ((sbi_hart_priv_version(scratch) >= SBI_HART_PRIV_VER_1_11) &&
!__test_bit(cbase, &mctr_inhbt))
continue;
/* We found a valid counter that is not started yet */
ctr_idx = cbase;
}
}
if (ctr_idx == SBI_ENOTSUPP) {
/**
* We can't find any programmable counters for cycle/instret.
* Return the fixed counter as they are mandatory anyways.
*/
if (fixed_ctr >= 0)
return fixed_ctr;
else
return SBI_EFAIL;
}
ret = pmu_update_hw_mhpmevent(temp, ctr_idx, flags, event_idx, data);
if (!ret)
ret = ctr_idx;
return ret;
}
/**
* Any firmware counter can map to any firmware event.
* Thus, select the first available fw counter after sanity
* check.
*/
static int pmu_ctr_find_fw(unsigned long cbase, unsigned long cmask, u32 hartid)
{
int i = 0;
int fw_base;
unsigned long ctr_mask = cmask << cbase;
if (cbase < num_hw_ctrs)
fw_base = num_hw_ctrs;
else
fw_base = cbase;
for (i = fw_base; i < total_ctrs; i++)
if ((active_events[hartid][i] == SBI_PMU_EVENT_IDX_INVALID) &&
((1UL << i) & ctr_mask))
return i;
return SBI_ENOTSUPP;
}
int sbi_pmu_ctr_cfg_match(unsigned long cidx_base, unsigned long cidx_mask,
unsigned long flags, unsigned long event_idx,
uint64_t event_data)
{
int ctr_idx = SBI_ENOTSUPP;
u32 hartid = current_hartid();
int event_type = get_cidx_type(event_idx);
struct sbi_pmu_fw_event *fevent;
uint32_t fw_evt_code;
unsigned long tmp = cidx_mask << cidx_base;
/* Do a basic sanity check of counter base & mask */
if (sbi_fls(tmp) >= total_ctrs || event_type >= SBI_PMU_EVENT_TYPE_MAX)
return SBI_EINVAL;
if (flags & SBI_PMU_CFG_FLAG_SKIP_MATCH) {
/* The caller wants to skip the match because it already knows the
* counter idx for the given event. Verify that the counter idx
* is still valid.
*/
if (active_events[hartid][cidx_base] == SBI_PMU_EVENT_IDX_INVALID)
return SBI_EINVAL;
ctr_idx = cidx_base;
goto skip_match;
}
if (event_type == SBI_PMU_EVENT_TYPE_FW) {
/* Any firmware counter can be used track any firmware event */
ctr_idx = pmu_ctr_find_fw(cidx_base, cidx_mask, hartid);
} else {
ctr_idx = pmu_ctr_find_hw(cidx_base, cidx_mask, flags, event_idx,
event_data);
}
if (ctr_idx < 0)
return SBI_ENOTSUPP;
active_events[hartid][ctr_idx] = event_idx;
skip_match:
if (event_type == SBI_PMU_EVENT_TYPE_HW) {
if (flags & SBI_PMU_CFG_FLAG_CLEAR_VALUE)
pmu_ctr_write_hw(ctr_idx, 0);
if (flags & SBI_PMU_CFG_FLAG_AUTO_START)
pmu_ctr_start_hw(ctr_idx, 0, false);
} else if (event_type == SBI_PMU_EVENT_TYPE_FW) {
fw_evt_code = get_cidx_code(event_idx);
fevent = &fw_event_map[hartid][fw_evt_code];
if (flags & SBI_PMU_CFG_FLAG_CLEAR_VALUE)
fevent->curr_count = 0;
if (flags & SBI_PMU_CFG_FLAG_AUTO_START)
fevent->bStarted = TRUE;
}
return ctr_idx;
}
inline int sbi_pmu_ctr_incr_fw(enum sbi_pmu_fw_event_code_id fw_id)
{
u32 hartid = current_hartid();
struct sbi_pmu_fw_event *fevent;
if (unlikely(fw_id >= SBI_PMU_FW_MAX))
return SBI_EINVAL;
fevent = &fw_event_map[hartid][fw_id];
/* PMU counters will be only enabled during performance debugging */
if (unlikely(fevent->bStarted))
fevent->curr_count++;
return 0;
}
unsigned long sbi_pmu_num_ctr(void)
{
return (num_hw_ctrs + SBI_PMU_FW_CTR_MAX);
}
int sbi_pmu_ctr_get_info(uint32_t cidx, unsigned long *ctr_info)
{
union sbi_pmu_ctr_info cinfo = {0};
struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
/* Sanity check. Counter1 is not mapped at all */
if (cidx >= total_ctrs || cidx == 1)
return SBI_EINVAL;
/* We have 31 HW counters with 31 being the last index(MHPMCOUNTER31) */
if (cidx < num_hw_ctrs) {
cinfo.type = SBI_PMU_CTR_TYPE_HW;
cinfo.csr = CSR_CYCLE + cidx;
/* mcycle & minstret are always 64 bit */
if (cidx == 0 || cidx == 2)
cinfo.width = 63;
else
cinfo.width = sbi_hart_mhpm_bits(scratch) - 1;
} else {
/* it's a firmware counter */
cinfo.type = SBI_PMU_CTR_TYPE_FW;
/* Firmware counters are XLEN bits wide */
cinfo.width = BITS_PER_LONG - 1;
}
*ctr_info = cinfo.value;
return 0;
}
static void pmu_reset_event_map(u32 hartid)
{
int j;
/* Initialize the counter to event mapping table */
for (j = 3; j < total_ctrs; j++)
active_events[hartid][j] = SBI_PMU_EVENT_IDX_INVALID;
for (j = 0; j < SBI_PMU_FW_CTR_MAX; j++)
sbi_memset(&fw_event_map[hartid][j], 0,
sizeof(struct sbi_pmu_fw_event));
}
void sbi_pmu_exit(struct sbi_scratch *scratch)
{
u32 hartid = current_hartid();
if (sbi_hart_priv_version(scratch) >= SBI_HART_PRIV_VER_1_11)
csr_write(CSR_MCOUNTINHIBIT, 0xFFFFFFF8);
if (sbi_hart_priv_version(scratch) >= SBI_HART_PRIV_VER_1_10)
csr_write(CSR_MCOUNTEREN, -1);
pmu_reset_event_map(hartid);
}
int sbi_pmu_init(struct sbi_scratch *scratch, bool cold_boot)
{
const struct sbi_platform *plat;
u32 hartid = current_hartid();
if (cold_boot) {
plat = sbi_platform_ptr(scratch);
/* Initialize hw pmu events */
sbi_platform_pmu_init(plat);
/* mcycle & minstret is available always */
num_hw_ctrs = sbi_hart_mhpm_count(scratch) + 3;
total_ctrs = num_hw_ctrs + SBI_PMU_FW_CTR_MAX;
}
pmu_reset_event_map(hartid);
/* First three counters are fixed by the priv spec and we enable it by default */
active_events[hartid][0] = SBI_PMU_EVENT_TYPE_HW << SBI_PMU_EVENT_IDX_OFFSET |
SBI_PMU_HW_CPU_CYCLES;
active_events[hartid][1] = SBI_PMU_EVENT_IDX_INVALID;
active_events[hartid][2] = SBI_PMU_EVENT_TYPE_HW << SBI_PMU_EVENT_IDX_OFFSET |
SBI_PMU_HW_INSTRUCTIONS;
return 0;
}

View File

@@ -14,7 +14,7 @@
#include <sbi/sbi_scratch.h>
#include <sbi/sbi_string.h>
u32 last_hartid_having_scratch = SBI_HARTMASK_MAX_BITS - 1;
u32 last_hartid_having_scratch = SBI_HARTMASK_MAX_BITS;
struct sbi_scratch *hartid_to_scratch_table[SBI_HARTMASK_MAX_BITS] = { 0 };
static spinlock_t extra_lock = SPIN_LOCK_INITIALIZER;
@@ -40,7 +40,7 @@ int sbi_scratch_init(struct sbi_scratch *scratch)
return 0;
}
unsigned long sbi_scratch_alloc_offset(unsigned long size)
unsigned long sbi_scratch_alloc_offset(unsigned long size, const char *owner)
{
u32 i;
void *ptr;
@@ -74,7 +74,7 @@ done:
spin_unlock(&extra_lock);
if (ret) {
for (i = 0; i <= sbi_scratch_last_hartid(); i++) {
for (i = 0; i < sbi_scratch_last_hartid(); i++) {
rscratch = sbi_hartid_to_scratch(i);
if (!rscratch)
continue;

View File

@@ -33,10 +33,6 @@ int sbi_strncmp(const char *a, const char *b, size_t count)
for (; count > 0 && *a == *b && *a != '\0'; a++, b++, count--)
;
/* No difference till the end */
if (!count)
return 0;
return *a - *b;
}
@@ -149,8 +145,8 @@ void *sbi_memmove(void *dest, const void *src, size_t count)
count--;
}
} else {
temp1 = (char *)dest + count - 1;
temp2 = (char *)src + count - 1;
temp1 = dest + count - 1;
temp2 = src + count - 1;
while (count > 0) {
*temp1-- = *temp2--;

View File

@@ -18,50 +18,31 @@
#include <sbi/sbi_ipi.h>
#include <sbi/sbi_init.h>
static SBI_LIST_HEAD(reset_devices_list);
static const struct sbi_system_reset_device *reset_dev = NULL;
const struct sbi_system_reset_device *sbi_system_reset_get_device(
u32 reset_type, u32 reset_reason)
const struct sbi_system_reset_device *sbi_system_reset_get_device(void)
{
struct sbi_system_reset_device *reset_dev = NULL;
struct sbi_dlist *pos;
/** lowest priority - any non zero is our candidate */
int priority = 0;
/* Check each reset device registered for supported reset type */
sbi_list_for_each(pos, &(reset_devices_list)) {
struct sbi_system_reset_device *dev =
to_system_reset_device(pos);
if (dev->system_reset_check) {
int status = dev->system_reset_check(reset_type,
reset_reason);
/** reset_type not supported */
if (status == 0)
continue;
if (status > priority) {
reset_dev = dev;
priority = status;
}
}
}
return reset_dev;
}
void sbi_system_reset_add_device(struct sbi_system_reset_device *dev)
void sbi_system_reset_set_device(const struct sbi_system_reset_device *dev)
{
if (!dev || !dev->system_reset_check)
if (!dev || reset_dev)
return;
sbi_list_add(&(dev->node), &(reset_devices_list));
reset_dev = dev;
}
bool sbi_system_reset_supported(u32 reset_type, u32 reset_reason)
{
return !!sbi_system_reset_get_device(reset_type, reset_reason);
if (reset_dev && reset_dev->system_reset_check &&
reset_dev->system_reset_check(reset_type, reset_reason))
return TRUE;
return FALSE;
}
#include <sbi/riscv_io.h>
void __noreturn sbi_system_reset(u32 reset_type, u32 reset_reason)
{
ulong hbase = 0, hmask;
@@ -82,13 +63,97 @@ void __noreturn sbi_system_reset(u32 reset_type, u32 reset_reason)
sbi_hsm_hart_stop(scratch, FALSE);
/* Platform specific reset if domain allowed system reset */
if (dom->system_reset_allowed) {
const struct sbi_system_reset_device *dev =
sbi_system_reset_get_device(reset_type, reset_reason);
if (dev)
dev->system_reset(reset_type, reset_reason);
}
if (dom->system_reset_allowed &&
reset_dev && reset_dev->system_reset)
reset_dev->system_reset(reset_type, reset_reason);
writew(0x5555, (void *)0x100000); // qemu poweroff
/* If platform specific reset did not work then do sbi_exit() */
sbi_exit(scratch);
}
static const struct sbi_system_suspend_device *suspend_dev;
const struct sbi_system_suspend_device *sbi_system_suspend_get_device(void)
{
return suspend_dev;
}
void sbi_system_suspend_set_device(struct sbi_system_suspend_device *dev)
{
if (!dev || suspend_dev)
return;
suspend_dev = dev;
}
bool sbi_system_suspend_supported(u32 sleep_type)
{
return suspend_dev && suspend_dev->system_suspend_check &&
suspend_dev->system_suspend_check(sleep_type) == 0;
}
int sbi_system_suspend(u32 sleep_type, ulong resume_addr, ulong opaque)
{
const struct sbi_domain *dom = sbi_domain_thishart_ptr();
struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
void (*jump_warmboot)(void) = (void (*)(void))scratch->warmboot_addr;
//unsigned int hartid = current_hartid();
unsigned long prev_mode;
//unsigned long i, j;
int ret;
if (!dom || !dom->system_suspend_allowed)
return SBI_EFAIL;
if (!suspend_dev || !suspend_dev->system_suspend ||
!suspend_dev->system_suspend_check)
return SBI_EFAIL;
ret = suspend_dev->system_suspend_check(sleep_type);
if (ret != SBI_OK)
return ret;
prev_mode = (csr_read(CSR_MSTATUS) & MSTATUS_MPP) >> MSTATUS_MPP_SHIFT;
if (prev_mode != PRV_S && prev_mode != PRV_U)
return SBI_EFAIL;
//FIX ME: hartindex to hart
//sbi_hartmask_for_each_hartindex(j, &dom->assigned_harts) {
// //i = sbi_hartindex_to_hartid(j);
// if (i == hartid)
// continue;
// if (__sbi_hsm_hart_get_state(i) != SBI_HSM_STATE_STOPPED)
// return SBI_ERR_DENIED;
//}
if (!sbi_domain_check_addr(dom, resume_addr, prev_mode,
SBI_DOMAIN_EXECUTE))
return SBI_EINVALID_ADDR;
if (!sbi_hsm_hart_change_state(scratch, SBI_HSM_STATE_STARTED,
SBI_HSM_STATE_SUSPENDED))
return SBI_EFAIL;
/* Prepare for resume */
scratch->next_mode = prev_mode;
scratch->next_addr = resume_addr;
scratch->next_arg1 = opaque;
__sbi_hsm_suspend_non_ret_save(scratch);
/* Suspend */
ret = suspend_dev->system_suspend(sleep_type, scratch->warmboot_addr);
if (ret != SBI_OK) {
if (!sbi_hsm_hart_change_state(scratch, SBI_HSM_STATE_SUSPENDED,
SBI_HSM_STATE_STARTED))
sbi_hart_hang();
return ret;
}
/* Resume */
jump_warmboot();
__builtin_unreachable();
}

View File

@@ -8,13 +8,10 @@
*/
#include <sbi/riscv_asm.h>
#include <sbi/riscv_barrier.h>
#include <sbi/riscv_encoding.h>
#include <sbi/sbi_console.h>
#include <sbi/sbi_error.h>
#include <sbi/sbi_hart.h>
#include <sbi/sbi_platform.h>
#include <sbi/sbi_pmu.h>
#include <sbi/sbi_scratch.h>
#include <sbi/sbi_timer.h>
@@ -44,36 +41,9 @@ static u64 get_ticks(void)
}
#endif
static void nop_delay_fn(void *opaque)
static u64 get_platform_ticks(void)
{
cpu_relax();
}
void sbi_timer_delay_loop(ulong units, u64 unit_freq,
void (*delay_fn)(void *), void *opaque)
{
u64 start_val, delta;
/* Do nothing if we don't have timer device */
if (!timer_dev || !get_time_val) {
sbi_printf("%s: called without timer device\n", __func__);
return;
}
/* Save starting timer value */
start_val = get_time_val();
/* Compute desired timer value delta */
delta = ((u64)timer_dev->timer_freq * (u64)units);
delta = delta / unit_freq;
/* Use NOP delay function if delay function not available */
if (!delay_fn)
delay_fn = nop_delay_fn;
/* Busy loop until desired timer value delta reached */
while ((get_time_val() - start_val) < delta)
delay_fn(opaque);
return timer_dev->timer_value();
}
u64 sbi_timer_value(void)
@@ -118,36 +88,16 @@ void sbi_timer_set_delta_upper(ulong delta_upper)
void sbi_timer_event_start(u64 next_event)
{
sbi_pmu_ctr_incr_fw(SBI_PMU_FW_SET_TIMER);
/**
* Update the stimecmp directly if available. This allows
* the older software to leverage sstc extension on newer hardware.
*/
if (sbi_hart_has_extension(sbi_scratch_thishart_ptr(), SBI_HART_EXT_SSTC)) {
#if __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) {
if (timer_dev && timer_dev->timer_event_start)
timer_dev->timer_event_start(next_event);
csr_clear(CSR_MIP, MIP_STIP);
}
csr_clear(CSR_MIP, MIP_STIP);
csr_set(CSR_MIE, MIP_MTIP);
}
void sbi_timer_process(void)
{
csr_clear(CSR_MIE, MIP_MTIP);
/*
* If sstc extension is available, supervisor can receive the timer
* directly without M-mode come in between. This function should
* only invoked if M-mode programs the timer for its own purpose.
*/
if (!sbi_hart_has_extension(sbi_scratch_thishart_ptr(), SBI_HART_EXT_SSTC))
csr_set(CSR_MIP, MIP_STIP);
csr_set(CSR_MIP, MIP_STIP);
}
const struct sbi_timer_device *sbi_timer_get_device(void)
@@ -162,7 +112,7 @@ void sbi_timer_set_device(const struct sbi_timer_device *dev)
timer_dev = dev;
if (!get_time_val && timer_dev->timer_value)
get_time_val = timer_dev->timer_value;
get_time_val = get_platform_ticks;
}
int sbi_timer_init(struct sbi_scratch *scratch, bool cold_boot)
@@ -171,11 +121,12 @@ int sbi_timer_init(struct sbi_scratch *scratch, bool cold_boot)
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
if (cold_boot) {
time_delta_off = sbi_scratch_alloc_offset(sizeof(*time_delta));
time_delta_off = sbi_scratch_alloc_offset(sizeof(*time_delta),
"TIME_DELTA");
if (!time_delta_off)
return SBI_ENOMEM;
if (sbi_hart_has_extension(scratch, SBI_HART_EXT_TIME))
if (sbi_hart_has_feature(scratch, SBI_HART_HAS_TIME))
get_time_val = get_ticks;
} else {
if (!time_delta_off)

View File

@@ -21,14 +21,13 @@
#include <sbi/sbi_string.h>
#include <sbi/sbi_console.h>
#include <sbi/sbi_platform.h>
#include <sbi/sbi_pmu.h>
static unsigned long tlb_sync_off;
static unsigned long tlb_fifo_off;
static unsigned long tlb_fifo_mem_off;
static unsigned long tlb_range_flush_limit;
static void tlb_flush_all(void)
static void sbi_tlb_flush_all(void)
{
__asm__ __volatile("sfence.vma");
}
@@ -40,8 +39,6 @@ void sbi_tlb_local_hfence_vvma(struct sbi_tlb_info *tinfo)
unsigned long vmid = tinfo->vmid;
unsigned long i, hgatp;
sbi_pmu_ctr_incr_fw(SBI_PMU_FW_HFENCE_VVMA_RCVD);
hgatp = csr_swap(CSR_HGATP,
(vmid << HGATP_VMID_SHIFT) & HGATP_VMID_MASK);
@@ -64,15 +61,13 @@ void sbi_tlb_local_hfence_gvma(struct sbi_tlb_info *tinfo)
unsigned long size = tinfo->size;
unsigned long i;
sbi_pmu_ctr_incr_fw(SBI_PMU_FW_HFENCE_GVMA_RCVD);
if ((start == 0 && size == 0) || (size == SBI_TLB_FLUSH_ALL)) {
__sbi_hfence_gvma_all();
return;
}
for (i = 0; i < size; i += PAGE_SIZE) {
__sbi_hfence_gvma_gpa((start + i) >> 2);
__sbi_hfence_gvma_gpa(start+i);
}
}
@@ -82,10 +77,8 @@ void sbi_tlb_local_sfence_vma(struct sbi_tlb_info *tinfo)
unsigned long size = tinfo->size;
unsigned long i;
sbi_pmu_ctr_incr_fw(SBI_PMU_FW_SFENCE_VMA_RCVD);
if ((start == 0 && size == 0) || (size == SBI_TLB_FLUSH_ALL)) {
tlb_flush_all();
sbi_tlb_flush_all();
return;
}
@@ -105,8 +98,6 @@ void sbi_tlb_local_hfence_vvma_asid(struct sbi_tlb_info *tinfo)
unsigned long vmid = tinfo->vmid;
unsigned long i, hgatp;
sbi_pmu_ctr_incr_fw(SBI_PMU_FW_HFENCE_VVMA_ASID_RCVD);
hgatp = csr_swap(CSR_HGATP,
(vmid << HGATP_VMID_SHIFT) & HGATP_VMID_MASK);
@@ -135,8 +126,6 @@ void sbi_tlb_local_hfence_gvma_vmid(struct sbi_tlb_info *tinfo)
unsigned long vmid = tinfo->vmid;
unsigned long i;
sbi_pmu_ctr_incr_fw(SBI_PMU_FW_HFENCE_GVMA_VMID_RCVD);
if (start == 0 && size == 0) {
__sbi_hfence_gvma_all();
return;
@@ -148,7 +137,7 @@ void sbi_tlb_local_hfence_gvma_vmid(struct sbi_tlb_info *tinfo)
}
for (i = 0; i < size; i += PAGE_SIZE) {
__sbi_hfence_gvma_vmid_gpa((start + i) >> 2, vmid);
__sbi_hfence_gvma_vmid_gpa(start + i, vmid);
}
}
@@ -159,10 +148,8 @@ void sbi_tlb_local_sfence_vma_asid(struct sbi_tlb_info *tinfo)
unsigned long asid = tinfo->asid;
unsigned long i;
sbi_pmu_ctr_incr_fw(SBI_PMU_FW_SFENCE_VMA_ASID_RCVD);
if (start == 0 && size == 0) {
tlb_flush_all();
sbi_tlb_flush_all();
return;
}
@@ -185,33 +172,10 @@ void sbi_tlb_local_sfence_vma_asid(struct sbi_tlb_info *tinfo)
void sbi_tlb_local_fence_i(struct sbi_tlb_info *tinfo)
{
sbi_pmu_ctr_incr_fw(SBI_PMU_FW_FENCE_I_RECVD);
__asm__ __volatile("fence.i");
}
static void tlb_pmu_incr_fw_ctr(struct sbi_tlb_info *data)
{
if (unlikely(!data))
return;
if (data->local_fn == sbi_tlb_local_fence_i)
sbi_pmu_ctr_incr_fw(SBI_PMU_FW_FENCE_I_SENT);
else if (data->local_fn == sbi_tlb_local_sfence_vma)
sbi_pmu_ctr_incr_fw(SBI_PMU_FW_SFENCE_VMA_SENT);
else if (data->local_fn == sbi_tlb_local_sfence_vma_asid)
sbi_pmu_ctr_incr_fw(SBI_PMU_FW_SFENCE_VMA_ASID_SENT);
else if (data->local_fn == sbi_tlb_local_hfence_gvma)
sbi_pmu_ctr_incr_fw(SBI_PMU_FW_HFENCE_GVMA_SENT);
else if (data->local_fn == sbi_tlb_local_hfence_gvma_vmid)
sbi_pmu_ctr_incr_fw(SBI_PMU_FW_HFENCE_GVMA_VMID_SENT);
else if (data->local_fn == sbi_tlb_local_hfence_vvma)
sbi_pmu_ctr_incr_fw(SBI_PMU_FW_HFENCE_VVMA_SENT);
else if (data->local_fn == sbi_tlb_local_hfence_vvma_asid)
sbi_pmu_ctr_incr_fw(SBI_PMU_FW_HFENCE_VVMA_ASID_SENT);
}
static void tlb_entry_process(struct sbi_tlb_info *tinfo)
static void sbi_tlb_entry_process(struct sbi_tlb_info *tinfo)
{
u32 rhartid;
struct sbi_scratch *rscratch = NULL;
@@ -229,15 +193,15 @@ static void tlb_entry_process(struct sbi_tlb_info *tinfo)
}
}
static void tlb_process_count(struct sbi_scratch *scratch, int count)
static void sbi_tlb_process_count(struct sbi_scratch *scratch, int count)
{
struct sbi_tlb_info tinfo;
unsigned int deq_count = 0;
u32 deq_count = 0;
struct sbi_fifo *tlb_fifo =
sbi_scratch_offset_ptr(scratch, tlb_fifo_off);
while (!sbi_fifo_dequeue(tlb_fifo, &tinfo)) {
tlb_entry_process(&tinfo);
sbi_tlb_entry_process(&tinfo);
deq_count++;
if (deq_count > count)
break;
@@ -245,17 +209,17 @@ static void tlb_process_count(struct sbi_scratch *scratch, int count)
}
}
static void tlb_process(struct sbi_scratch *scratch)
static void sbi_tlb_process(struct sbi_scratch *scratch)
{
struct sbi_tlb_info tinfo;
struct sbi_fifo *tlb_fifo =
sbi_scratch_offset_ptr(scratch, tlb_fifo_off);
while (!sbi_fifo_dequeue(tlb_fifo, &tinfo))
tlb_entry_process(&tinfo);
sbi_tlb_entry_process(&tinfo);
}
static void tlb_sync(struct sbi_scratch *scratch)
static void sbi_tlb_sync(struct sbi_scratch *scratch)
{
unsigned long *tlb_sync =
sbi_scratch_offset_ptr(scratch, tlb_sync_off);
@@ -265,13 +229,13 @@ static void tlb_sync(struct sbi_scratch *scratch)
* While we are waiting for remote hart to set the sync,
* consume fifo requests to avoid deadlock.
*/
tlb_process_count(scratch, 1);
sbi_tlb_process_count(scratch, 1);
}
return;
}
static inline int tlb_range_check(struct sbi_tlb_info *curr,
static inline int __sbi_tlb_range_check(struct sbi_tlb_info *curr,
struct sbi_tlb_info *next)
{
unsigned long curr_end;
@@ -314,7 +278,7 @@ static inline int tlb_range_check(struct sbi_tlb_info *curr,
* before continuing the while loop. This method is preferred over wfi/ipi because
* of MMIO cost involved in later method.
*/
static int tlb_update_cb(void *in, void *data)
static int sbi_tlb_update_cb(void *in, void *data)
{
struct sbi_tlb_info *curr;
struct sbi_tlb_info *next;
@@ -329,16 +293,16 @@ static int tlb_update_cb(void *in, void *data)
if (next->local_fn == sbi_tlb_local_sfence_vma_asid &&
curr->local_fn == sbi_tlb_local_sfence_vma_asid) {
if (next->asid == curr->asid)
ret = tlb_range_check(curr, next);
ret = __sbi_tlb_range_check(curr, next);
} else if (next->local_fn == sbi_tlb_local_sfence_vma &&
curr->local_fn == sbi_tlb_local_sfence_vma) {
ret = tlb_range_check(curr, next);
ret = __sbi_tlb_range_check(curr, next);
}
return ret;
}
static int tlb_update(struct sbi_scratch *scratch,
static int sbi_tlb_update(struct sbi_scratch *scratch,
struct sbi_scratch *remote_scratch,
u32 remote_hartid, void *data)
{
@@ -368,7 +332,7 @@ static int tlb_update(struct sbi_scratch *scratch,
tlb_fifo_r = sbi_scratch_offset_ptr(remote_scratch, tlb_fifo_off);
ret = sbi_fifo_inplace_update(tlb_fifo_r, data, tlb_update_cb);
ret = sbi_fifo_inplace_update(tlb_fifo_r, data, sbi_tlb_update_cb);
if (ret != SBI_FIFO_UNCHANGED) {
return 1;
}
@@ -382,7 +346,7 @@ static int tlb_update(struct sbi_scratch *scratch,
* TODO: Introduce a wait/wakeup event mechanism to handle
* this properly.
*/
tlb_process_count(scratch, 1);
sbi_tlb_process_count(scratch, 1);
sbi_dprintf("hart%d: hart%d tlb fifo full\n",
curr_hartid, remote_hartid);
}
@@ -392,9 +356,9 @@ static int tlb_update(struct sbi_scratch *scratch,
static struct sbi_ipi_event_ops tlb_ops = {
.name = "IPI_TLB",
.update = tlb_update,
.sync = tlb_sync,
.process = tlb_process,
.update = sbi_tlb_update,
.sync = sbi_tlb_sync,
.process = sbi_tlb_process,
};
static u32 tlb_event = SBI_IPI_EVENT_MAX;
@@ -404,8 +368,6 @@ int sbi_tlb_request(ulong hmask, ulong hbase, struct sbi_tlb_info *tinfo)
if (!tinfo->local_fn)
return SBI_EINVAL;
tlb_pmu_incr_fw_ctr(tinfo);
return sbi_ipi_send_many(hmask, hbase, tlb_event, tinfo);
}
@@ -418,16 +380,19 @@ int sbi_tlb_init(struct sbi_scratch *scratch, bool cold_boot)
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
if (cold_boot) {
tlb_sync_off = sbi_scratch_alloc_offset(sizeof(*tlb_sync));
tlb_sync_off = sbi_scratch_alloc_offset(sizeof(*tlb_sync),
"IPI_TLB_SYNC");
if (!tlb_sync_off)
return SBI_ENOMEM;
tlb_fifo_off = sbi_scratch_alloc_offset(sizeof(*tlb_q));
tlb_fifo_off = sbi_scratch_alloc_offset(sizeof(*tlb_q),
"IPI_TLB_FIFO");
if (!tlb_fifo_off) {
sbi_scratch_free_offset(tlb_sync_off);
return SBI_ENOMEM;
}
tlb_fifo_mem_off = sbi_scratch_alloc_offset(
SBI_TLB_FIFO_NUM_ENTRIES * SBI_TLB_INFO_SIZE);
SBI_TLB_FIFO_NUM_ENTRIES * SBI_TLB_INFO_SIZE,
"IPI_TLB_FIFO_MEM");
if (!tlb_fifo_mem_off) {
sbi_scratch_free_offset(tlb_fifo_off);
sbi_scratch_free_offset(tlb_sync_off);

View File

@@ -15,9 +15,7 @@
#include <sbi/sbi_hart.h>
#include <sbi/sbi_illegal_insn.h>
#include <sbi/sbi_ipi.h>
#include <sbi/sbi_irqchip.h>
#include <sbi/sbi_misaligned_ldst.h>
#include <sbi/sbi_pmu.h>
#include <sbi/sbi_scratch.h>
#include <sbi/sbi_timer.h>
#include <sbi/sbi_trap.h>
@@ -99,14 +97,17 @@ int sbi_trap_redirect(struct sbi_trap_regs *regs,
if (prev_mode != PRV_S && prev_mode != PRV_U)
return SBI_ENOTSUPP;
/* If exceptions came from VS/VU-mode, redirect to VS-mode if
* delegated in hedeleg
*/
/* For certain exceptions from VS/VU-mode we redirect to VS-mode */
if (misa_extension('H') && prev_virt) {
if ((trap->cause < __riscv_xlen) &&
(csr_read(CSR_HEDELEG) & BIT(trap->cause))) {
switch (trap->cause) {
case CAUSE_FETCH_PAGE_FAULT:
case CAUSE_LOAD_PAGE_FAULT:
case CAUSE_STORE_PAGE_FAULT:
next_virt = TRUE;
}
break;
default:
break;
};
}
/* Update MSTATUS MPV bits */
@@ -193,52 +194,6 @@ int sbi_trap_redirect(struct sbi_trap_regs *regs,
return 0;
}
static int sbi_trap_nonaia_irq(struct sbi_trap_regs *regs, ulong mcause)
{
mcause &= ~(1UL << (__riscv_xlen - 1));
switch (mcause) {
case IRQ_M_TIMER:
sbi_timer_process();
break;
case IRQ_M_SOFT:
sbi_ipi_process();
break;
case IRQ_M_EXT:
return sbi_irqchip_process(regs);
default:
return SBI_ENOENT;
};
return 0;
}
static int sbi_trap_aia_irq(struct sbi_trap_regs *regs, ulong mcause)
{
int rc;
unsigned long mtopi;
while ((mtopi = csr_read(CSR_MTOPI))) {
mtopi = mtopi >> TOPI_IID_SHIFT;
switch (mtopi) {
case IRQ_M_TIMER:
sbi_timer_process();
break;
case IRQ_M_SOFT:
sbi_ipi_process();
break;
case IRQ_M_EXT:
rc = sbi_irqchip_process(regs);
if (rc)
return rc;
break;
default:
return SBI_ENOENT;
}
}
return 0;
}
/**
* Handle trap/interrupt
*
@@ -269,15 +224,18 @@ struct sbi_trap_regs *sbi_trap_handler(struct sbi_trap_regs *regs)
}
if (mcause & (1UL << (__riscv_xlen - 1))) {
if (sbi_hart_has_extension(sbi_scratch_thishart_ptr(),
SBI_HART_EXT_AIA))
rc = sbi_trap_aia_irq(regs, mcause);
else
rc = sbi_trap_nonaia_irq(regs, mcause);
if (rc) {
msg = "unhandled local interrupt";
mcause &= ~(1UL << (__riscv_xlen - 1));
switch (mcause) {
case IRQ_M_TIMER:
sbi_timer_process();
break;
case IRQ_M_SOFT:
sbi_ipi_process();
break;
default:
msg = "unhandled external interrupt";
goto trap_error;
}
};
return regs;
}
@@ -299,11 +257,6 @@ struct sbi_trap_regs *sbi_trap_handler(struct sbi_trap_regs *regs)
rc = sbi_ecall_handler(regs);
msg = "ecall handler failed";
break;
case CAUSE_LOAD_ACCESS:
case CAUSE_STORE_ACCESS:
sbi_pmu_ctr_incr_fw(mcause == CAUSE_LOAD_ACCESS ?
SBI_PMU_FW_ACCESS_LOAD : SBI_PMU_FW_ACCESS_STORE);
/* fallthrough */
default:
/* If the trap came from S or U mode, redirect it there */
trap.epc = regs->mepc;

View File

@@ -83,7 +83,7 @@ DEFINE_UNPRIVILEGED_LOAD_FUNCTION(u32, lwu)
DEFINE_UNPRIVILEGED_LOAD_FUNCTION(u64, ld)
DEFINE_UNPRIVILEGED_STORE_FUNCTION(u64, sd)
DEFINE_UNPRIVILEGED_LOAD_FUNCTION(ulong, ld)
#elif __riscv_xlen == 32
#else
DEFINE_UNPRIVILEGED_LOAD_FUNCTION(u32, lw)
DEFINE_UNPRIVILEGED_LOAD_FUNCTION(ulong, lw)
@@ -112,8 +112,6 @@ void sbi_store_u64(u64 *addr, u64 val,
if (trap->cause)
return;
}
#else
# error "Unexpected __riscv_xlen"
#endif
ulong sbi_get_insn(ulong mepc, struct sbi_trap_info *trap)
@@ -149,17 +147,15 @@ ulong sbi_get_insn(ulong mepc, struct sbi_trap_info *trap)
switch (trap->cause) {
case CAUSE_LOAD_ACCESS:
trap->cause = CAUSE_FETCH_ACCESS;
trap->tinst = 0UL;
trap->tval = mepc;
break;
case CAUSE_LOAD_PAGE_FAULT:
trap->cause = CAUSE_FETCH_PAGE_FAULT;
trap->tinst = 0UL;
trap->tval = mepc;
break;
case CAUSE_LOAD_GUEST_PAGE_FAULT:
trap->cause = CAUSE_FETCH_GUEST_PAGE_FAULT;
if (trap->tinst != INSN_PSEUDO_VS_LOAD &&
trap->tinst != INSN_PSEUDO_VS_STORE)
trap->tinst = 0UL;
trap->tval = mepc;
break;
default:
break;

View File

@@ -9,7 +9,6 @@
*/
#include <libfdt.h>
#include <libfdt_env.h>
#include <sbi/sbi_domain.h>
#include <sbi/sbi_error.h>
#include <sbi/sbi_hartmask.h>
@@ -96,7 +95,7 @@ static int __fixup_find_domain_offset(void *fdt, int doff, void *p)
{
struct __fixup_find_domain_offset_info *fdo = p;
if (!strncmp(fdo->name, fdt_get_name(fdt, doff, NULL), strlen(fdo->name)))
if (!sbi_strcmp(fdo->name, fdt_get_name(fdt, doff, NULL)))
*fdo->doffset = doff;
return 0;
@@ -165,9 +164,6 @@ void fdt_domain_fixup(void *fdt)
if (err)
continue;
if (!fdt_node_is_enabled(fdt, doffset))
continue;
fdt_nop_property(fdt, doffset, "opensbi-domain");
}
@@ -291,7 +287,7 @@ static int __fdt_parse_domain(void *fdt, int domain_offset, void *opaque)
regions = &fdt_regions[fdt_domains_count][0];
/* Read DT node name */
strncpy(dom->name, fdt_get_name(fdt, domain_offset, NULL),
sbi_strncpy(dom->name, fdt_get_name(fdt, domain_offset, NULL),
sizeof(dom->name));
dom->name[sizeof(dom->name) - 1] = '\0';
@@ -311,16 +307,13 @@ static int __fdt_parse_domain(void *fdt, int domain_offset, void *opaque)
if (err)
return err;
if (!fdt_node_is_enabled(fdt, cpu_offset))
continue;
sbi_hartmask_set_hart(val32, mask);
}
}
/* Setup memregions from DT */
val32 = 0;
memset(regions, 0,
sbi_memset(regions, 0,
sizeof(*regions) * (FDT_DOMAIN_REGION_MAX_COUNT + 1));
dom->regions = regions;
err = fdt_iterate_each_memregion(fdt, domain_offset, &val32,
@@ -344,7 +337,7 @@ static int __fdt_parse_domain(void *fdt, int domain_offset, void *opaque)
continue;
if (FDT_DOMAIN_REGION_MAX_COUNT <= val32)
return SBI_EINVAL;
memcpy(&regions[val32++], reg, sizeof(*reg));
sbi_memcpy(&regions[val32++], reg, sizeof(*reg));
}
/* Read "boot-hart" DT property */
@@ -353,7 +346,7 @@ static int __fdt_parse_domain(void *fdt, int domain_offset, void *opaque)
if (val && len >= 4) {
cpu_offset = fdt_node_offset_by_phandle(fdt,
fdt32_to_cpu(*val));
if (cpu_offset >= 0 && fdt_node_is_enabled(fdt, cpu_offset))
if (cpu_offset >= 0)
fdt_parse_hart_id(fdt, cpu_offset, &val32);
} else {
if (domain_offset == *cold_domain_offset)
@@ -405,6 +398,13 @@ static int __fdt_parse_domain(void *fdt, int domain_offset, void *opaque)
else
dom->system_reset_allowed = FALSE;
/* Read "system-suspend-allowed" DT property */
if (fdt_get_property(fdt, domain_offset,
"system-suspend-allowed", NULL))
dom->system_suspend_allowed = TRUE;
else
dom->system_suspend_allowed = FALSE;
/* Find /cpus DT node */
cpus_offset = fdt_path_offset(fdt, "/cpus");
if (cpus_offset < 0)
@@ -420,9 +420,6 @@ static int __fdt_parse_domain(void *fdt, int domain_offset, void *opaque)
if (SBI_HARTMASK_MAX_BITS <= val32)
continue;
if (!fdt_node_is_enabled(fdt, cpu_offset))
continue;
val = fdt_getprop(fdt, cpu_offset, "opensbi-domain", &len);
if (!val || len < 4)
return SBI_EINVAL;
@@ -469,9 +466,6 @@ int fdt_domains_populate(void *fdt)
if (hartid != cold_hartid)
continue;
if (!fdt_node_is_enabled(fdt, cpu_offset))
continue;
val = fdt_getprop(fdt, cpu_offset, "opensbi-domain", &len);
if (val && len >= 4)
cold_domain_offset = fdt_node_offset_by_phandle(fdt,

View File

@@ -15,7 +15,6 @@
#include <sbi/sbi_scratch.h>
#include <sbi/sbi_string.h>
#include <sbi_utils/fdt/fdt_fixup.h>
#include <sbi_utils/fdt/fdt_pmu.h>
#include <sbi_utils/fdt/fdt_helper.h>
void fdt_cpu_fixup(void *fdt)
@@ -38,9 +37,6 @@ void fdt_cpu_fixup(void *fdt)
if (err)
continue;
if (!fdt_node_is_enabled(fdt, cpu_offset))
continue;
/*
* Disable a HART DT node if one of the following is true:
* 1. The HART is not assigned to the current domain
@@ -55,43 +51,6 @@ void fdt_cpu_fixup(void *fdt)
}
}
static void fdt_domain_based_fixup_one(void *fdt, int nodeoff)
{
int rc;
uint64_t reg_addr, reg_size;
struct sbi_domain *dom = sbi_domain_thishart_ptr();
rc = fdt_get_node_addr_size(fdt, nodeoff, 0, &reg_addr, &reg_size);
if (rc < 0 || !reg_addr || !reg_size)
return;
if (!sbi_domain_check_addr(dom, reg_addr, dom->next_mode,
SBI_DOMAIN_READ | SBI_DOMAIN_WRITE)) {
rc = fdt_open_into(fdt, fdt, fdt_totalsize(fdt) + 32);
if (rc < 0)
return;
fdt_setprop_string(fdt, nodeoff, "status", "disabled");
}
}
void fdt_aplic_fixup(void *fdt)
{
int noff = 0;
while ((noff = fdt_node_offset_by_compatible(fdt, noff,
"riscv,aplic")) >= 0)
fdt_domain_based_fixup_one(fdt, noff);
}
void fdt_imsic_fixup(void *fdt)
{
int noff = 0;
while ((noff = fdt_node_offset_by_compatible(fdt, noff,
"riscv,imsics")) >= 0)
fdt_domain_based_fixup_one(fdt, noff);
}
void fdt_plic_fixup(void *fdt)
{
u32 *cells;
@@ -301,12 +260,9 @@ int fdt_reserved_memory_nomap_fixup(void *fdt)
void fdt_fixups(void *fdt)
{
fdt_aplic_fixup(fdt);
fdt_imsic_fixup(fdt);
fdt_plic_fixup(fdt);
fdt_reserved_memory_fixup(fdt);
fdt_pmu_fixup(fdt);
}

View File

@@ -13,23 +13,19 @@
#include <sbi/sbi_platform.h>
#include <sbi/sbi_scratch.h>
#include <sbi_utils/fdt/fdt_helper.h>
#include <sbi_utils/irqchip/aplic.h>
#include <sbi_utils/irqchip/imsic.h>
#include <sbi_utils/irqchip/plic.h>
#include <sbi_utils/sys/clint.h>
#define DEFAULT_UART_FREQ 0
#define DEFAULT_UART_BAUD 115200
#define DEFAULT_UART_REG_SHIFT 0
#define DEFAULT_UART_REG_IO_WIDTH 1
#define DEFAULT_UART_REG_OFFSET 0
#define DEFAULT_SIFIVE_UART_FREQ 0
#define DEFAULT_SIFIVE_UART_BAUD 115200
#define DEFAULT_SIFIVE_UART_REG_SHIFT 0
#define DEFAULT_SIFIVE_UART_REG_IO_WIDTH 4
#define DEFAULT_GAISLER_UART_REG_IO_WIDTH 4
#define DEFAULT_SHAKTI_UART_FREQ 50000000
#define DEFAULT_SHAKTI_UART_BAUD 115200
@@ -75,55 +71,8 @@ int fdt_find_match(void *fdt, int startoff,
return SBI_ENODEV;
}
int fdt_parse_phandle_with_args(void *fdt, int nodeoff,
const char *prop, const char *cells_prop,
int index, struct fdt_phandle_args *out_args)
{
u32 i, pcells;
int len, pnodeoff;
const fdt32_t *list, *list_end, *val;
if (!fdt || (nodeoff < 0) || !prop || !cells_prop || !out_args)
return SBI_EINVAL;
list = fdt_getprop(fdt, nodeoff, prop, &len);
if (!list)
return SBI_ENOENT;
list_end = list + (len / sizeof(*list));
while (list < list_end) {
pnodeoff = fdt_node_offset_by_phandle(fdt,
fdt32_to_cpu(*list));
if (pnodeoff < 0)
return pnodeoff;
list++;
val = fdt_getprop(fdt, pnodeoff, cells_prop, &len);
if (!val)
return SBI_ENOENT;
pcells = fdt32_to_cpu(*val);
if (FDT_MAX_PHANDLE_ARGS < pcells)
return SBI_EINVAL;
if (list + pcells > list_end)
return SBI_ENOENT;
if (index > 0) {
list += pcells;
index--;
} else {
out_args->node_offset = pnodeoff;
out_args->args_count = pcells;
for (i = 0; i < pcells; i++)
out_args->args[i] = fdt32_to_cpu(list[i]);
return 0;
}
}
return SBI_ENOENT;
}
static int fdt_translate_address(void *fdt, uint64_t reg, int parent,
uint64_t *addr)
unsigned long *addr)
{
int i, rlen;
int cell_addr, cell_size;
@@ -160,17 +109,14 @@ static int fdt_translate_address(void *fdt, uint64_t reg, int parent,
return 0;
}
int fdt_get_node_addr_size(void *fdt, int node, int index,
uint64_t *addr, uint64_t *size)
int fdt_get_node_addr_size(void *fdt, int node, unsigned long *addr,
unsigned long *size)
{
int parent, len, i, rc;
int cell_addr, cell_size;
const fdt32_t *prop_addr, *prop_size;
uint64_t temp = 0;
if (!fdt || node < 0 || index < 0)
return SBI_EINVAL;
parent = fdt_parent_offset(fdt, node);
if (parent < 0)
return parent;
@@ -185,11 +131,6 @@ int fdt_get_node_addr_size(void *fdt, int node, int index,
prop_addr = fdt_getprop(fdt, node, "reg", &len);
if (!prop_addr)
return SBI_ENODEV;
if ((len / sizeof(u32)) <= (index * (cell_addr + cell_size)))
return SBI_EINVAL;
prop_addr = prop_addr + (index * (cell_addr + cell_size));
prop_size = prop_addr + cell_addr;
if (addr) {
@@ -216,24 +157,6 @@ int fdt_get_node_addr_size(void *fdt, int node, int index,
return 0;
}
bool fdt_node_is_enabled(void *fdt, int nodeoff)
{
int len;
const void *prop;
prop = fdt_getprop(fdt, nodeoff, "status", &len);
if (!prop)
return true;
if (!strncmp(prop, "okay", strlen("okay")))
return true;
if (!strncmp(prop, "ok", strlen("ok")))
return true;
return false;
}
int fdt_parse_hart_id(void *fdt, int cpu_offset, u32 *hartid)
{
int len;
@@ -262,7 +185,7 @@ int fdt_parse_hart_id(void *fdt, int cpu_offset, u32 *hartid)
return 0;
}
int fdt_parse_max_enabled_hart_id(void *fdt, u32 *max_hartid)
int fdt_parse_max_hart_id(void *fdt, u32 *max_hartid)
{
u32 hartid;
int err, cpu_offset, cpus_offset;
@@ -283,9 +206,6 @@ int fdt_parse_max_enabled_hart_id(void *fdt, u32 *max_hartid)
if (err)
continue;
if (!fdt_node_is_enabled(fdt, cpu_offset))
continue;
if (hartid > *max_hartid)
*max_hartid = hartid;
}
@@ -293,78 +213,17 @@ int fdt_parse_max_enabled_hart_id(void *fdt, u32 *max_hartid)
return 0;
}
int fdt_parse_timebase_frequency(void *fdt, unsigned long *freq)
{
const fdt32_t *val;
int len, cpus_offset;
if (!fdt || !freq)
return SBI_EINVAL;
cpus_offset = fdt_path_offset(fdt, "/cpus");
if (cpus_offset < 0)
return cpus_offset;
val = fdt_getprop(fdt, cpus_offset, "timebase-frequency", &len);
if (len > 0 && val)
*freq = fdt32_to_cpu(*val);
else
return SBI_ENOENT;
return 0;
}
int fdt_parse_gaisler_uart_node(void *fdt, int nodeoffset,
struct platform_uart_data *uart)
{
int len, rc;
const fdt32_t *val;
uint64_t reg_addr, reg_size;
if (nodeoffset < 0 || !uart || !fdt)
return SBI_ENODEV;
rc = fdt_get_node_addr_size(fdt, nodeoffset, 0,
&reg_addr, &reg_size);
if (rc < 0 || !reg_addr || !reg_size)
return SBI_ENODEV;
uart->addr = reg_addr;
/**
* UART address is mandatory. clock-frequency and current-speed
* may not be present. Don't return error.
*/
val = (fdt32_t *)fdt_getprop(fdt, nodeoffset, "clock-frequency", &len);
if (len > 0 && val)
uart->freq = fdt32_to_cpu(*val);
else
uart->freq = DEFAULT_UART_FREQ;
val = (fdt32_t *)fdt_getprop(fdt, nodeoffset, "current-speed", &len);
if (len > 0 && val)
uart->baud = fdt32_to_cpu(*val);
else
uart->baud = DEFAULT_UART_BAUD;
/* For Gaisler APBUART, the reg-shift and reg-io-width are fixed .*/
uart->reg_shift = DEFAULT_UART_REG_SHIFT;
uart->reg_io_width = DEFAULT_GAISLER_UART_REG_IO_WIDTH;
return 0;
}
int fdt_parse_shakti_uart_node(void *fdt, int nodeoffset,
struct platform_uart_data *uart)
{
int len, rc;
const fdt32_t *val;
uint64_t reg_addr, reg_size;
unsigned long reg_addr, reg_size;
if (nodeoffset < 0 || !uart || !fdt)
return SBI_ENODEV;
rc = fdt_get_node_addr_size(fdt, nodeoffset, 0,
&reg_addr, &reg_size);
rc = fdt_get_node_addr_size(fdt, nodeoffset, &reg_addr, &reg_size);
if (rc < 0 || !reg_addr || !reg_size)
return SBI_ENODEV;
uart->addr = reg_addr;
@@ -393,13 +252,12 @@ int fdt_parse_sifive_uart_node(void *fdt, int nodeoffset,
{
int len, rc;
const fdt32_t *val;
uint64_t reg_addr, reg_size;
unsigned long reg_addr, reg_size;
if (nodeoffset < 0 || !uart || !fdt)
return SBI_ENODEV;
rc = fdt_get_node_addr_size(fdt, nodeoffset, 0,
&reg_addr, &reg_size);
rc = fdt_get_node_addr_size(fdt, nodeoffset, &reg_addr, &reg_size);
if (rc < 0 || !reg_addr || !reg_size)
return SBI_ENODEV;
uart->addr = reg_addr;
@@ -432,13 +290,12 @@ int fdt_parse_uart8250_node(void *fdt, int nodeoffset,
{
int len, rc;
const fdt32_t *val;
uint64_t reg_addr, reg_size;
unsigned long reg_addr, reg_size;
if (nodeoffset < 0 || !uart || !fdt)
return SBI_ENODEV;
rc = fdt_get_node_addr_size(fdt, nodeoffset, 0,
&reg_addr, &reg_size);
rc = fdt_get_node_addr_size(fdt, nodeoffset, &reg_addr, &reg_size);
if (rc < 0 || !reg_addr || !reg_size)
return SBI_ENODEV;
uart->addr = reg_addr;
@@ -471,12 +328,6 @@ int fdt_parse_uart8250_node(void *fdt, int nodeoffset,
else
uart->reg_io_width = DEFAULT_UART_REG_IO_WIDTH;
val = (fdt32_t *)fdt_getprop(fdt, nodeoffset, "reg-offset", &len);
if (len > 0 && val)
uart->reg_offset = fdt32_to_cpu(*val);
else
uart->reg_offset = DEFAULT_UART_REG_OFFSET;
return 0;
}
@@ -495,295 +346,16 @@ int fdt_parse_uart8250(void *fdt, struct platform_uart_data *uart,
return fdt_parse_uart8250_node(fdt, nodeoffset, uart);
}
int fdt_parse_xlnx_uartlite_node(void *fdt, int nodeoffset,
struct platform_uart_data *uart)
{
int rc;
uint64_t reg_addr, reg_size;
if (nodeoffset < 0 || !uart || !fdt)
return SBI_ENODEV;
rc = fdt_get_node_addr_size(fdt, nodeoffset, 0,
&reg_addr, &reg_size);
if (rc < 0 || !reg_addr || !reg_size)
return SBI_ENODEV;
uart->addr = reg_addr;
return 0;
}
int fdt_parse_aplic_node(void *fdt, int nodeoff, struct aplic_data *aplic)
{
bool child_found;
const fdt32_t *val;
const fdt32_t *del;
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)
return SBI_ENODEV;
aplic->addr = reg_addr;
aplic->size = reg_size;
val = fdt_getprop(fdt, nodeoff, "riscv,num-sources", &len);
if (len > 0)
aplic->num_source = fdt32_to_cpu(*val);
val = fdt_getprop(fdt, nodeoff, "interrupts-extended", &len);
if (val && len > sizeof(fdt32_t)) {
len = len / sizeof(fdt32_t);
for (i = 0; i < len; i += 2) {
if (fdt32_to_cpu(val[i + 1]) == IRQ_M_EXT) {
aplic->targets_mmode = true;
break;
}
}
aplic->num_idc = len / 2;
goto aplic_msi_parent_done;
}
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;
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];
deleg->first_irq = 0;
deleg->last_irq = 0;
deleg->child_index = 0;
}
del = fdt_getprop(fdt, nodeoff, "riscv,delegate", &len);
if (!del || len < (3 * sizeof(fdt32_t)))
goto skip_delegate_parse;
d = 0;
dcnt = len / sizeof(fdt32_t);
for (i = 0; i < dcnt; i += 3) {
if (d >= APLIC_MAX_DELEGATE)
break;
deleg = &aplic->delegate[d];
deleg->first_irq = fdt32_to_cpu(del[i + 1]);
deleg->last_irq = fdt32_to_cpu(del[i + 2]);
deleg->child_index = 0;
child_found = false;
val = fdt_getprop(fdt, nodeoff, "riscv,children", &len);
if (!val || len < sizeof(fdt32_t)) {
deleg->first_irq = 0;
deleg->last_irq = 0;
deleg->child_index = 0;
continue;
}
len = len / sizeof(fdt32_t);
for (j = 0; j < len; j++) {
if (del[i] != val[j])
continue;
deleg->child_index = j;
child_found = true;
break;
}
if (child_found) {
d++;
} else {
deleg->first_irq = 0;
deleg->last_irq = 0;
deleg->child_index = 0;
}
}
skip_delegate_parse:
return 0;
}
bool fdt_check_imsic_mlevel(void *fdt)
{
const fdt32_t *val;
int i, len, noff = 0;
if (!fdt)
return false;
while ((noff = fdt_node_offset_by_compatible(fdt, noff,
"riscv,imsics")) >= 0) {
val = fdt_getprop(fdt, noff, "interrupts-extended", &len);
if (val && len > sizeof(fdt32_t)) {
len = len / sizeof(fdt32_t);
for (i = 0; i < len; i += 2) {
if (fdt32_to_cpu(val[i + 1]) == IRQ_M_EXT)
return true;
}
}
}
return false;
}
int fdt_parse_imsic_node(void *fdt, int nodeoff, struct imsic_data *imsic)
{
const fdt32_t *val;
struct imsic_regs *regs;
uint64_t reg_addr, reg_size;
int i, rc, len, nr_parent_irqs;
if (nodeoff < 0 || !imsic || !fdt)
return SBI_ENODEV;
imsic->targets_mmode = false;
val = fdt_getprop(fdt, nodeoff, "interrupts-extended", &len);
if (val && len > sizeof(fdt32_t)) {
len = len / sizeof(fdt32_t);
nr_parent_irqs = len / 2;
for (i = 0; i < len; i += 2) {
if (fdt32_to_cpu(val[i + 1]) == IRQ_M_EXT) {
imsic->targets_mmode = true;
break;
}
}
} else
return SBI_EINVAL;
val = fdt_getprop(fdt, nodeoff, "riscv,guest-index-bits", &len);
if (val && len > 0)
imsic->guest_index_bits = fdt32_to_cpu(*val);
else
imsic->guest_index_bits = 0;
val = fdt_getprop(fdt, nodeoff, "riscv,hart-index-bits", &len);
if (val && len > 0) {
imsic->hart_index_bits = fdt32_to_cpu(*val);
} else {
imsic->hart_index_bits = sbi_fls(nr_parent_irqs);
if ((1UL << imsic->hart_index_bits) < nr_parent_irqs)
imsic->hart_index_bits++;
}
val = fdt_getprop(fdt, nodeoff, "riscv,group-index-bits", &len);
if (val && len > 0)
imsic->group_index_bits = fdt32_to_cpu(*val);
else
imsic->group_index_bits = 0;
val = fdt_getprop(fdt, nodeoff, "riscv,group-index-shift", &len);
if (val && len > 0)
imsic->group_index_shift = fdt32_to_cpu(*val);
else
imsic->group_index_shift = 2 * IMSIC_MMIO_PAGE_SHIFT;
val = fdt_getprop(fdt, nodeoff, "riscv,num-ids", &len);
if (val && len > 0)
imsic->num_ids = fdt32_to_cpu(*val);
else
return SBI_EINVAL;
for (i = 0; i < IMSIC_MAX_REGS; i++) {
regs = &imsic->regs[i];
regs->addr = 0;
regs->size = 0;
}
for (i = 0; i < (IMSIC_MAX_REGS - 1); i++) {
regs = &imsic->regs[i];
rc = fdt_get_node_addr_size(fdt, nodeoff, i,
&reg_addr, &reg_size);
if (rc < 0 || !reg_addr || !reg_size)
break;
regs->addr = reg_addr;
regs->size = reg_size;
};
if (!imsic->regs[0].size)
return SBI_EINVAL;
return 0;
}
int fdt_parse_plic_node(void *fdt, int nodeoffset, struct plic_data *plic)
{
int len, rc;
const fdt32_t *val;
uint64_t reg_addr, reg_size;
unsigned long reg_addr, reg_size;
if (nodeoffset < 0 || !plic || !fdt)
return SBI_ENODEV;
rc = fdt_get_node_addr_size(fdt, nodeoffset, 0,
&reg_addr, &reg_size);
rc = fdt_get_node_addr_size(fdt, nodeoffset, &reg_addr, &reg_size);
if (rc < 0 || !reg_addr || !reg_size)
return SBI_ENODEV;
plic->addr = reg_addr;
@@ -809,51 +381,34 @@ int fdt_parse_plic(void *fdt, struct plic_data *plic, const char *compat)
return fdt_parse_plic_node(fdt, nodeoffset, plic);
}
int fdt_parse_aclint_node(void *fdt, int nodeoffset, bool for_timer,
unsigned long *out_addr1, unsigned long *out_size1,
unsigned long *out_addr2, unsigned long *out_size2,
u32 *out_first_hartid, u32 *out_hart_count)
int fdt_parse_clint_node(void *fdt, int nodeoffset, bool for_timer,
struct clint_data *clint)
{
const fdt32_t *val;
uint64_t reg_addr, reg_size;
unsigned long reg_addr, reg_size;
int i, rc, count, cpu_offset, cpu_intc_offset;
u32 phandle, hwirq, hartid, first_hartid, last_hartid, hart_count;
u32 phandle, hwirq, hartid, first_hartid, last_hartid;
u32 match_hwirq = (for_timer) ? IRQ_M_TIMER : IRQ_M_SOFT;
if (nodeoffset < 0 || !fdt ||
!out_addr1 || !out_size1 ||
!out_first_hartid || !out_hart_count)
return SBI_EINVAL;
rc = fdt_get_node_addr_size(fdt, nodeoffset, 0,
&reg_addr, &reg_size);
if (rc < 0 || !reg_size)
if (nodeoffset < 0 || !clint || !fdt)
return SBI_ENODEV;
*out_addr1 = reg_addr;
*out_size1 = reg_size;
rc = fdt_get_node_addr_size(fdt, nodeoffset, 1,
&reg_addr, &reg_size);
if (rc < 0 || !reg_size)
reg_addr = reg_size = 0;
if (out_addr2)
*out_addr2 = reg_addr;
if (out_size2)
*out_size2 = reg_size;
*out_first_hartid = 0;
*out_hart_count = 0;
rc = fdt_get_node_addr_size(fdt, nodeoffset, &reg_addr, &reg_size);
if (rc < 0 || !reg_addr || !reg_size)
return SBI_ENODEV;
clint->addr = reg_addr;
val = fdt_getprop(fdt, nodeoffset, "interrupts-extended", &count);
if (!val || count < sizeof(fdt32_t))
return 0;
return SBI_EINVAL;
count = count / sizeof(fdt32_t);
first_hartid = -1U;
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]);
last_hartid = 0;
clint->hart_count = 0;
for (i = 0; i < count; i += 2) {
phandle = fdt32_to_cpu(val[i]);
hwirq = fdt32_to_cpu(val[i + 1]);
cpu_intc_offset = fdt_node_offset_by_phandle(fdt, phandle);
if (cpu_intc_offset < 0)
@@ -875,20 +430,26 @@ int fdt_parse_aclint_node(void *fdt, int nodeoffset, bool for_timer,
first_hartid = hartid;
if (hartid > last_hartid)
last_hartid = hartid;
hart_count++;
clint->hart_count++;
}
}
if ((last_hartid >= first_hartid) && first_hartid != -1U) {
*out_first_hartid = first_hartid;
count = last_hartid - first_hartid + 1;
*out_hart_count = (hart_count < count) ? hart_count : count;
}
if ((last_hartid < first_hartid) || first_hartid == -1U)
return SBI_ENODEV;
clint->first_hartid = first_hartid;
count = last_hartid - first_hartid + 1;
if (clint->hart_count < count)
clint->hart_count = count;
clint->has_64bit_mmio = TRUE;
if (fdt_getprop(fdt, nodeoffset, "clint,has-no-64bit-mmio", &count))
clint->has_64bit_mmio = FALSE;
return 0;
}
int fdt_parse_compat_addr(void *fdt, uint64_t *addr,
int fdt_parse_compat_addr(void *fdt, unsigned long *addr,
const char *compatible)
{
int nodeoffset, rc;
@@ -897,7 +458,7 @@ int fdt_parse_compat_addr(void *fdt, uint64_t *addr,
if (nodeoffset < 0)
return nodeoffset;
rc = fdt_get_node_addr_size(fdt, nodeoffset, 0, addr, NULL);
rc = fdt_get_node_addr_size(fdt, nodeoffset, addr, NULL);
if (rc < 0 || !addr)
return SBI_ENODEV;

View File

@@ -1,117 +0,0 @@
// SPDX-License-Identifier: BSD-2-Clause
/*
* fdt_pmu.c - Flat Device Tree PMU helper routines
*
* Copyright (c) 2021 Western Digital Corporation or its affiliates.
*
* Authors:
* Atish Patra <atish.patra@wdc.com>
*/
#include <libfdt.h>
#include <sbi/sbi_hart.h>
#include <sbi/sbi_error.h>
#include <sbi/sbi_pmu.h>
#include <sbi_utils/fdt/fdt_helper.h>
#define FDT_PMU_HW_EVENT_MAX (SBI_PMU_HW_EVENT_MAX * 2)
struct fdt_pmu_hw_event_select {
uint32_t eidx;
uint64_t select;
};
static struct fdt_pmu_hw_event_select fdt_pmu_evt_select[FDT_PMU_HW_EVENT_MAX] = {0};
static uint32_t hw_event_count;
uint64_t fdt_pmu_get_select_value(uint32_t event_idx)
{
int i;
struct fdt_pmu_hw_event_select *event;
for (i = 0; i < SBI_PMU_HW_EVENT_MAX; i++) {
event = &fdt_pmu_evt_select[i];
if (event->eidx == event_idx)
return event->select;
}
return 0;
}
int fdt_pmu_fixup(void *fdt)
{
int pmu_offset;
struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
if (!fdt)
return SBI_EINVAL;
pmu_offset = fdt_node_offset_by_compatible(fdt, -1, "riscv,pmu");
if (pmu_offset < 0)
return SBI_EFAIL;
fdt_delprop(fdt, pmu_offset, "riscv,event-to-mhpmcounters");
fdt_delprop(fdt, pmu_offset, "riscv,event-to-mhpmevent");
fdt_delprop(fdt, pmu_offset, "riscv,raw-event-to-mhpmcounters");
if (!sbi_hart_has_extension(scratch, SBI_HART_EXT_SSCOFPMF))
fdt_delprop(fdt, pmu_offset, "interrupts-extended");
return 0;
}
int fdt_pmu_setup(void *fdt)
{
int i, pmu_offset, len, result;
const u32 *event_val;
const u32 *event_ctr_map;
struct fdt_pmu_hw_event_select *event;
uint64_t raw_selector, select_mask;
u32 event_idx_start, event_idx_end, ctr_map;
if (!fdt)
return SBI_EINVAL;
pmu_offset = fdt_node_offset_by_compatible(fdt, -1, "riscv,pmu");
if (pmu_offset < 0)
return SBI_EFAIL;
event_ctr_map = fdt_getprop(fdt, pmu_offset, "riscv,event-to-mhpmcounters", &len);
if (!event_ctr_map || len < 8)
return SBI_EFAIL;
len = len / (sizeof(u32) * 3);
for (i = 0; i < len; i++) {
event_idx_start = fdt32_to_cpu(event_ctr_map[3 * i]);
event_idx_end = fdt32_to_cpu(event_ctr_map[3 * i + 1]);
ctr_map = fdt32_to_cpu(event_ctr_map[3 * i + 2]);
sbi_pmu_add_hw_event_counter_map(event_idx_start, event_idx_end, ctr_map);
}
event_val = fdt_getprop(fdt, pmu_offset, "riscv,event-to-mhpmevent", &len);
if (!event_val || len < 8)
return SBI_EFAIL;
len = len / (sizeof(u32) * 3);
for (i = 0; i < len; 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 || len < 20)
return SBI_EFAIL;
len = len / (sizeof(u32) * 5);
for (i = 0; i < len; i++) {
raw_selector = fdt32_to_cpu(event_val[5 * i]);
raw_selector = (raw_selector << 32) | fdt32_to_cpu(event_val[5 * i + 1]);
select_mask = fdt32_to_cpu(event_val[5 * i + 2]);
select_mask = (select_mask << 32) | fdt32_to_cpu(event_val[5 * i + 3]);
ctr_map = fdt32_to_cpu(event_val[5 * i + 4]);
result = sbi_pmu_add_raw_event_counter_map(raw_selector, select_mask, ctr_map);
if (!result)
hw_event_count++;
}
return 0;
}

View File

@@ -5,6 +5,5 @@
#
libsbiutils-objs-y += fdt/fdt_domain.o
libsbiutils-objs-y += fdt/fdt_pmu.o
libsbiutils-objs-y += fdt/fdt_helper.o
libsbiutils-objs-y += fdt/fdt_fixup.o

View File

@@ -1,133 +0,0 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2021 Western Digital Corporation or its affiliates.
*
* Authors:
* Anup Patel <anup.patel@wdc.com>
*/
#include <libfdt.h>
#include <sbi/sbi_error.h>
#include <sbi_utils/fdt/fdt_helper.h>
#include <sbi_utils/gpio/fdt_gpio.h>
/* List of FDT gpio drivers generated at compile time */
extern struct fdt_gpio *fdt_gpio_drivers[];
extern unsigned long fdt_gpio_drivers_size;
static struct fdt_gpio *fdt_gpio_driver(struct gpio_chip *chip)
{
int pos;
if (!chip)
return NULL;
for (pos = 0; pos < fdt_gpio_drivers_size; pos++) {
if (chip->driver == fdt_gpio_drivers[pos])
return fdt_gpio_drivers[pos];
}
return NULL;
}
static int fdt_gpio_init(void *fdt, u32 phandle)
{
int pos, nodeoff, rc;
struct fdt_gpio *drv;
const struct fdt_match *match;
/* Find node offset */
nodeoff = fdt_node_offset_by_phandle(fdt, phandle);
if (nodeoff < 0)
return nodeoff;
/* Check "gpio-controller" property */
if (!fdt_getprop(fdt, nodeoff, "gpio-controller", &rc))
return SBI_EINVAL;
/* Try all GPIO drivers one-by-one */
for (pos = 0; pos < fdt_gpio_drivers_size; pos++) {
drv = fdt_gpio_drivers[pos];
match = fdt_match_node(fdt, nodeoff, drv->match_table);
if (match && drv->init) {
rc = drv->init(fdt, nodeoff, phandle, match);
if (rc == SBI_ENODEV)
continue;
if (rc)
return rc;
return 0;
}
}
return SBI_ENOSYS;
}
static int fdt_gpio_chip_find(void *fdt, u32 phandle,
struct gpio_chip **out_chip)
{
int rc;
struct gpio_chip *chip = gpio_chip_find(phandle);
if (!chip) {
/* GPIO chip not found so initialize matching driver */
rc = fdt_gpio_init(fdt, phandle);
if (rc)
return rc;
/* Try to find GPIO chip again */
chip = gpio_chip_find(phandle);
if (!chip)
return SBI_ENOSYS;
}
if (out_chip)
*out_chip = chip;
return 0;
}
int fdt_gpio_pin_get(void *fdt, int nodeoff, int index,
struct gpio_pin *out_pin)
{
int rc;
u32 phandle;
struct fdt_gpio *drv;
struct gpio_chip *chip = NULL;
struct fdt_phandle_args pargs;
if (!fdt || (nodeoff < 0) || (index < 0) || !out_pin)
return SBI_EINVAL;
pargs.node_offset = pargs.args_count = 0;
rc = fdt_parse_phandle_with_args(fdt, nodeoff,
"gpios", "#gpio-cells",
index, &pargs);
if (rc)
return rc;
phandle = fdt_get_phandle(fdt, pargs.node_offset);
rc = fdt_gpio_chip_find(fdt, phandle, &chip);
if (rc)
return rc;
drv = fdt_gpio_driver(chip);
if (!drv || !drv->xlate)
return SBI_ENOSYS;
return drv->xlate(chip, &pargs, out_pin);
}
int fdt_gpio_simple_xlate(struct gpio_chip *chip,
const struct fdt_phandle_args *pargs,
struct gpio_pin *out_pin)
{
if ((pargs->args_count < 2) || (chip->ngpio <= pargs->args[0]))
return SBI_EINVAL;
out_pin->chip = chip;
out_pin->offset = pargs->args[0];
out_pin->flags = pargs->args[1];
return 0;
}

View File

@@ -1,3 +0,0 @@
HEADER: sbi_utils/gpio/fdt_gpio.h
TYPE: struct fdt_gpio
NAME: fdt_gpio_drivers

View File

@@ -1,107 +0,0 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2021 SiFive
*
* Authors:
* Green Wan <green.wan@sifive.com>
*/
#include <sbi/riscv_io.h>
#include <sbi/sbi_error.h>
#include <sbi_utils/fdt/fdt_helper.h>
#include <sbi_utils/gpio/fdt_gpio.h>
#define SIFIVE_GPIO_CHIP_MAX 2
#define SIFIVE_GPIO_PINS_MIN 1
#define SIFIVE_GPIO_PINS_MAX 32
#define SIFIVE_GPIO_PINS_DEF 16
#define SIFIVE_GPIO_OUTEN 0x8
#define SIFIVE_GPIO_OUTVAL 0xc
#define SIFIVE_GPIO_BIT(b) (1U << (b))
struct sifive_gpio_chip {
unsigned long addr;
struct gpio_chip chip;
};
static unsigned int sifive_gpio_chip_count;
static struct sifive_gpio_chip sifive_gpio_chip_array[SIFIVE_GPIO_CHIP_MAX];
static int sifive_gpio_direction_output(struct gpio_pin *gp, int value)
{
unsigned int v;
struct sifive_gpio_chip *chip =
container_of(gp->chip, struct sifive_gpio_chip, chip);
v = readl((volatile void *)(chip->addr + SIFIVE_GPIO_OUTEN));
v |= SIFIVE_GPIO_BIT(gp->offset);
writel(v, (volatile void *)(chip->addr + SIFIVE_GPIO_OUTEN));
v = readl((volatile void *)(chip->addr + SIFIVE_GPIO_OUTVAL));
if (!value)
v &= ~SIFIVE_GPIO_BIT(gp->offset);
else
v |= SIFIVE_GPIO_BIT(gp->offset);
writel(v, (volatile void *)(chip->addr + SIFIVE_GPIO_OUTVAL));
return 0;
}
static void sifive_gpio_set(struct gpio_pin *gp, int value)
{
unsigned int v;
struct sifive_gpio_chip *chip =
container_of(gp->chip, struct sifive_gpio_chip, chip);
v = readl((volatile void *)(chip->addr + SIFIVE_GPIO_OUTVAL));
if (!value)
v &= ~SIFIVE_GPIO_BIT(gp->offset);
else
v |= SIFIVE_GPIO_BIT(gp->offset);
writel(v, (volatile void *)(chip->addr + SIFIVE_GPIO_OUTVAL));
}
extern struct fdt_gpio fdt_gpio_sifive;
static int sifive_gpio_init(void *fdt, int nodeoff, u32 phandle,
const struct fdt_match *match)
{
int rc;
struct sifive_gpio_chip *chip;
uint64_t addr;
if (SIFIVE_GPIO_CHIP_MAX <= sifive_gpio_chip_count)
return SBI_ENOSPC;
chip = &sifive_gpio_chip_array[sifive_gpio_chip_count];
rc = fdt_get_node_addr_size(fdt, nodeoff, 0, &addr, NULL);
if (rc)
return rc;
chip->addr = addr;
chip->chip.driver = &fdt_gpio_sifive;
chip->chip.id = phandle;
chip->chip.ngpio = SIFIVE_GPIO_PINS_DEF;
chip->chip.direction_output = sifive_gpio_direction_output;
chip->chip.set = sifive_gpio_set;
rc = gpio_chip_add(&chip->chip);
if (rc)
return rc;
sifive_gpio_chip_count++;
return 0;
}
static const struct fdt_match sifive_gpio_match[] = {
{ .compatible = "sifive,gpio0" },
{ },
};
struct fdt_gpio fdt_gpio_sifive = {
.match_table = sifive_gpio_match,
.xlate = fdt_gpio_simple_xlate,
.init = sifive_gpio_init,
};

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