summaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorAhmad Fatoum <a.fatoum@pengutronix.de>2021-04-27 22:23:04 +0200
committerSascha Hauer <s.hauer@pengutronix.de>2021-05-10 09:18:40 +0200
commit6fd5711a111e8c7c4e6ea09d962b6885da09f86b (patch)
tree22b7cc54477502d5199b7caac5ddac8d3b6aa669 /arch
parent60b6da3b17214d0efb27d5b42e804aa641bf5ceb (diff)
downloadbarebox-6fd5711a111e8c7c4e6ea09d962b6885da09f86b.tar.gz
barebox-6fd5711a111e8c7c4e6ea09d962b6885da09f86b.tar.xz
RISC-V: add SBI based cpuinfo
SBI appeared to be especially useful to implement a generic console driver. However, SBI v0.2 removes these services without substitute. We might find other use for it later, but for now, add the bare minimum of querying the version of the running SBI implementation. The cpuinfo command is intentionally kept generic. It can later be extended to support CONFIG_RISCV_M_MODE as well. Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de> Link: https://lore.barebox.org/20210427202309.32077-7-a.fatoum@pengutronix.de Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
Diffstat (limited to 'arch')
-rw-r--r--arch/riscv/include/asm/sbi.h32
-rw-r--r--arch/riscv/lib/Makefile2
-rw-r--r--arch/riscv/lib/cpuinfo.c45
-rw-r--r--arch/riscv/lib/sbi.c62
4 files changed, 135 insertions, 6 deletions
diff --git a/arch/riscv/include/asm/sbi.h b/arch/riscv/include/asm/sbi.h
index 99895d9c3b..ab1fc9a128 100644
--- a/arch/riscv/include/asm/sbi.h
+++ b/arch/riscv/include/asm/sbi.h
@@ -89,11 +89,32 @@ struct sbiret {
long value;
};
-void sbi_init(void);
-struct sbiret sbi_ecall(int ext, int fid, unsigned long arg0,
- unsigned long arg1, unsigned long arg2,
- unsigned long arg3, unsigned long arg4,
- unsigned long arg5);
+static inline struct sbiret sbi_ecall(int ext, int fid, unsigned long arg0,
+ unsigned long arg1, unsigned long arg2,
+ unsigned long arg3, unsigned long arg4,
+ unsigned long arg5)
+{
+ struct sbiret ret;
+
+ register uintptr_t a0 asm ("a0") = (uintptr_t)(arg0);
+ register uintptr_t a1 asm ("a1") = (uintptr_t)(arg1);
+ register uintptr_t a2 asm ("a2") = (uintptr_t)(arg2);
+ register uintptr_t a3 asm ("a3") = (uintptr_t)(arg3);
+ register uintptr_t a4 asm ("a4") = (uintptr_t)(arg4);
+ register uintptr_t a5 asm ("a5") = (uintptr_t)(arg5);
+ register uintptr_t a6 asm ("a6") = (uintptr_t)(fid);
+ register uintptr_t a7 asm ("a7") = (uintptr_t)(ext);
+ asm volatile ("ecall"
+ : "+r" (a0), "+r" (a1)
+ : "r" (a2), "r" (a3), "r" (a4), "r" (a5), "r" (a6), "r" (a7)
+ : "memory");
+ ret.error = a0;
+ ret.value = a1;
+
+ return ret;
+}
+
+long __sbi_base_ecall(int fid);
void sbi_console_putchar(int ch);
int sbi_console_getchar(void);
@@ -148,6 +169,5 @@ static inline unsigned long sbi_minor_version(void)
int sbi_err_map_linux_errno(int err);
#else /* CONFIG_RISCV_SBI */
static inline int sbi_remote_fence_i(const unsigned long *hart_mask) { return -1; }
-static inline void sbi_init(void) {}
#endif /* CONFIG_RISCV_SBI */
#endif /* _ASM_RISCV_SBI_H */
diff --git a/arch/riscv/lib/Makefile b/arch/riscv/lib/Makefile
index a4eaa1005d..49750d576a 100644
--- a/arch/riscv/lib/Makefile
+++ b/arch/riscv/lib/Makefile
@@ -6,3 +6,5 @@ obj-y += dtb.o
obj-pbl-y += sections.o setupc.o reloc.o sections.o runtime-offset.o
obj-$(CONFIG_HAS_ARCH_SJLJ) += setjmp.o longjmp.o
obj-$(CONFIG_RISCV_OPTIMZED_STRING_FUNCTIONS) += memcpy.o memset.o memmove.o
+obj-$(CONFIG_RISCV_SBI) += sbi.o
+obj-$(CONFIG_CMD_RISCV_CPUINFO) += cpuinfo.o
diff --git a/arch/riscv/lib/cpuinfo.c b/arch/riscv/lib/cpuinfo.c
new file mode 100644
index 0000000000..21b99a990a
--- /dev/null
+++ b/arch/riscv/lib/cpuinfo.c
@@ -0,0 +1,45 @@
+// SPDX-License-Identifier: GPL-2.0-only
+#include <common.h>
+#include <command.h>
+#include <asm/sbi.h>
+
+static const char *implementations[] = {
+ [0] = "\"Berkeley Boot Loader (BBL)\" ",
+ [1] = "\"OpenSBI\" ",
+ [2] = "\"Xvisor\" ",
+ [3] = "\"KVM\" ",
+ [4] = "\"RustSBI\" ",
+ [5] = "\"Diosix\" ",
+};
+
+static int do_cpuinfo(int argc, char *argv[])
+{
+ const char *implementation = "";
+ unsigned long impid;
+
+ printf("SBI specification v%lu.%lu detected\n",
+ sbi_major_version(), sbi_minor_version());
+
+ if (sbi_spec_is_0_1())
+ return 0;
+
+ impid = __sbi_base_ecall(SBI_EXT_BASE_GET_IMP_ID);
+ if (impid < ARRAY_SIZE(implementations))
+ implementation = implementations[impid];
+
+ printf("SBI implementation ID=0x%lx %sVersion=0x%lx\n",
+ impid, implementation, __sbi_base_ecall(SBI_EXT_BASE_GET_IMP_VERSION));
+
+ printf("SBI Machine VENDORID=0x%lx ARCHID=0x%lx MIMPID=0x%lx\n",
+ __sbi_base_ecall(SBI_EXT_BASE_GET_MVENDORID),
+ __sbi_base_ecall(SBI_EXT_BASE_GET_MARCHID),
+ __sbi_base_ecall(SBI_EXT_BASE_GET_MIMPID));
+
+ return 0;
+}
+
+BAREBOX_CMD_START(cpuinfo)
+ .cmd = do_cpuinfo,
+BAREBOX_CMD_DESC("show CPU information")
+BAREBOX_CMD_GROUP(CMD_GRP_INFO)
+ BAREBOX_CMD_END
diff --git a/arch/riscv/lib/sbi.c b/arch/riscv/lib/sbi.c
new file mode 100644
index 0000000000..973c9d9d0f
--- /dev/null
+++ b/arch/riscv/lib/sbi.c
@@ -0,0 +1,62 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * SBI initialilization and all extension implementation.
+ *
+ * Copyright (c) 2020 Western Digital Corporation or its affiliates.
+ */
+
+#include <asm/sbi.h>
+#include <linux/export.h>
+#include <errno.h>
+#include <init.h>
+
+/* default SBI version is 0.1 */
+unsigned long sbi_spec_version = SBI_SPEC_VERSION_DEFAULT;
+EXPORT_SYMBOL(sbi_spec_version);
+
+int sbi_err_map_linux_errno(int err)
+{
+ switch (err) {
+ case SBI_SUCCESS:
+ return 0;
+ case SBI_ERR_DENIED:
+ return -EPERM;
+ case SBI_ERR_INVALID_PARAM:
+ return -EINVAL;
+ case SBI_ERR_INVALID_ADDRESS:
+ return -EFAULT;
+ case SBI_ERR_NOT_SUPPORTED:
+ case SBI_ERR_FAILURE:
+ default:
+ return -ENOTSUPP;
+ };
+}
+EXPORT_SYMBOL(sbi_err_map_linux_errno);
+
+long __sbi_base_ecall(int fid)
+{
+ struct sbiret ret;
+
+ ret = sbi_ecall(SBI_EXT_BASE, fid, 0, 0, 0, 0, 0, 0);
+ if (!ret.error)
+ return ret.value;
+ else
+ return sbi_err_map_linux_errno(ret.error);
+}
+
+static inline long sbi_get_spec_version(void)
+{
+ return __sbi_base_ecall(SBI_EXT_BASE_GET_SPEC_VERSION);
+}
+
+static int sbi_init(void)
+{
+ int ret;
+
+ ret = sbi_get_spec_version();
+ if (ret > 0)
+ sbi_spec_version = ret;
+ return 0;
+
+}
+core_initcall(sbi_init);