diff mbox series

[v2,3/3] sysreset: provide SBI based sysreset driver

Message ID 20210721163305.74945-4-xypron.glpk@gmx.de
State Changes Requested
Delegated to: Andes
Headers show
Series riscv: enable SBI system reset | expand

Commit Message

Heinrich Schuchardt July 21, 2021, 4:33 p.m. UTC
Provide sysreset driver using the SBI system reset extension.

Signed-off-by: Heinrich Schuchardt <xypron.glpk@gmx.de>
---
v2:
	remove a superfluous check in sbi_sysreset_request()
---
 MAINTAINERS                     |  1 +
 arch/riscv/cpu/cpu.c            | 13 ++++-
 arch/riscv/include/asm/sbi.h    |  1 +
 arch/riscv/lib/sbi.c            | 21 ++++++--
 drivers/sysreset/Kconfig        | 11 ++++
 drivers/sysreset/Makefile       |  1 +
 drivers/sysreset/sysreset_sbi.c | 96 +++++++++++++++++++++++++++++++++
 lib/efi_loader/Kconfig          |  2 +-
 8 files changed, 140 insertions(+), 6 deletions(-)
 create mode 100644 drivers/sysreset/sysreset_sbi.c

--
2.30.2

Comments

Sean Anderson July 21, 2021, 5:05 p.m. UTC | #1
On 7/21/21 12:33 PM, Heinrich Schuchardt wrote:
> Provide sysreset driver using the SBI system reset extension.
> 
> Signed-off-by: Heinrich Schuchardt <xypron.glpk@gmx.de>
> ---
> v2:
> 	remove a superfluous check in sbi_sysreset_request()
> ---
>   MAINTAINERS                     |  1 +
>   arch/riscv/cpu/cpu.c            | 13 ++++-
>   arch/riscv/include/asm/sbi.h    |  1 +
>   arch/riscv/lib/sbi.c            | 21 ++++++--
>   drivers/sysreset/Kconfig        | 11 ++++
>   drivers/sysreset/Makefile       |  1 +
>   drivers/sysreset/sysreset_sbi.c | 96 +++++++++++++++++++++++++++++++++
>   lib/efi_loader/Kconfig          |  2 +-
>   8 files changed, 140 insertions(+), 6 deletions(-)
>   create mode 100644 drivers/sysreset/sysreset_sbi.c
> 
> diff --git a/MAINTAINERS b/MAINTAINERS
> index a6b49b54b9..29ac9450f5 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -1012,6 +1012,7 @@ T:	git https://source.denx.de/u-boot/custodians/u-boot-riscv.git
>   F:	arch/riscv/
>   F:	cmd/riscv/
>   F:	doc/usage/sbi.rst
> +F:	drivers/sysreset/sysreset_sbi.c
>   F:	drivers/timer/andes_plmt_timer.c
>   F:	drivers/timer/sifive_clint_timer.c
>   F:	tools/prelink-riscv.c
> diff --git a/arch/riscv/cpu/cpu.c b/arch/riscv/cpu/cpu.c
> index c894ac10b5..8e49b6d736 100644
> --- a/arch/riscv/cpu/cpu.c
> +++ b/arch/riscv/cpu/cpu.c
> @@ -6,6 +6,7 @@
>   #include <common.h>
>   #include <cpu.h>
>   #include <dm.h>
> +#include <dm/lists.h>
>   #include <init.h>
>   #include <log.h>
>   #include <asm/encoding.h>
> @@ -138,7 +139,17 @@ int arch_cpu_init_dm(void)
> 
>   int arch_early_init_r(void)
>   {
> -	return riscv_cpu_probe();
> +	int ret;
> +
> +	ret = riscv_cpu_probe();
> +	if (ret)
> +		return ret;
> +
> +	if (IS_ENABLED(CONFIG_SYSRESET_SBI))
> +		device_bind_driver(gd->dm_root, "sbi-sysreset",
> +				   "sbi-sysreset", NULL);
> +
> +	return 0;
>   }
> 
>   /**
> diff --git a/arch/riscv/include/asm/sbi.h b/arch/riscv/include/asm/sbi.h
> index 39d5a022e0..b702fca176 100644
> --- a/arch/riscv/include/asm/sbi.h
> +++ b/arch/riscv/include/asm/sbi.h
> @@ -150,5 +150,6 @@ void sbi_set_timer(uint64_t stime_value);
>   long sbi_get_spec_version(void);
>   int sbi_get_impl_id(void);
>   int sbi_probe_extension(int ext);
> +void sbi_srst_reset(unsigned long type, unsigned long reason);
> 
>   #endif
> diff --git a/arch/riscv/lib/sbi.c b/arch/riscv/lib/sbi.c
> index 77845a73ca..8508041f2a 100644
> --- a/arch/riscv/lib/sbi.c
> +++ b/arch/riscv/lib/sbi.c
> @@ -8,13 +8,14 @@
>    */
> 
>   #include <common.h>
> +#include <efi_loader.h>
>   #include <asm/encoding.h>
>   #include <asm/sbi.h>
> 
> -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 __efi_runtime 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;
> 
> @@ -108,6 +109,18 @@ int sbi_probe_extension(int extid)
>   	return -ENOTSUPP;
>   }
> 
> +/**
> + * sbi_srst_reset() - invoke system reset extension
> + *
> + * @type:	type of reset
> + * @reason:	reason for reset
> + */
> +void __efi_runtime sbi_srst_reset(unsigned long type, unsigned long reason)
> +{
> +	sbi_ecall(SBI_EXT_SRST, SBI_EXT_SRST_RESET, type, reason,
> +		  0, 0, 0, 0);
> +}
> +
>   #ifdef CONFIG_SBI_V01
> 
>   /**
> diff --git a/drivers/sysreset/Kconfig b/drivers/sysreset/Kconfig
> index ac77ffbc8b..e095951166 100644
> --- a/drivers/sysreset/Kconfig
> +++ b/drivers/sysreset/Kconfig
> @@ -85,6 +85,17 @@ config SYSRESET_PSCI
>   	  Enable PSCI SYSTEM_RESET function call.  To use this, PSCI firmware
>   	  must be running on your system.
> 
> +config SYSRESET_SBI
> +	bool "Enable support for SBI System Reset"
> +	depends on RISCV_SMODE && SBI_V02
> +	select SYSRESET_CMD_POWEROFF if CMD_POWEROFF
> +	help
> +	  Enable system reset and poweroff via the SBI system reset extension.
> +	  If the SBI implementation provides the extension, is board specific.
> +	  The extension was introduced in version 0.3 of the SBI specification.
> +	  The SBI system reset driver supports the UEFI ResetSystem() service
> +	  at runtime.
> +
>   config SYSRESET_SOCFPGA
>   	bool "Enable support for Intel SOCFPGA family"
>   	depends on ARCH_SOCFPGA && (TARGET_SOCFPGA_GEN5 || TARGET_SOCFPGA_ARRIA10)
> diff --git a/drivers/sysreset/Makefile b/drivers/sysreset/Makefile
> index de81c399d7..8e00be0779 100644
> --- a/drivers/sysreset/Makefile
> +++ b/drivers/sysreset/Makefile
> @@ -13,6 +13,7 @@ obj-$(CONFIG_SYSRESET_MPC83XX) += sysreset_mpc83xx.o
>   obj-$(CONFIG_SYSRESET_MICROBLAZE) += sysreset_microblaze.o
>   obj-$(CONFIG_SYSRESET_OCTEON) += sysreset_octeon.o
>   obj-$(CONFIG_SYSRESET_PSCI) += sysreset_psci.o
> +obj-$(CONFIG_SYSRESET_SBI) += sysreset_sbi.o
>   obj-$(CONFIG_SYSRESET_SOCFPGA) += sysreset_socfpga.o
>   obj-$(CONFIG_SYSRESET_SOCFPGA_SOC64) += sysreset_socfpga_soc64.o
>   obj-$(CONFIG_SYSRESET_TI_SCI) += sysreset-ti-sci.o
> diff --git a/drivers/sysreset/sysreset_sbi.c b/drivers/sysreset/sysreset_sbi.c
> new file mode 100644
> index 0000000000..fec5a66515
> --- /dev/null
> +++ b/drivers/sysreset/sysreset_sbi.c
> @@ -0,0 +1,96 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +/*
> + * Copyright 2021, Heinrich Schuchardt <xypron.glpk@gmx.de>
> + */
> +
> +#include <common.h>
> +#include <dm.h>
> +#include <errno.h>
> +#include <efi_loader.h>
> +#include <log.h>
> +#include <sysreset.h>
> +#include <asm/sbi.h>
> +
> +static long __efi_runtime_data have_reset;
> +
> +static int sbi_sysreset_request(struct udevice *dev, enum sysreset_t type)
> +{
> +	enum sbi_srst_reset_type reset_type;
> +
> +	switch (type) {
> +	case SYSRESET_WARM:
> +		reset_type = SBI_SRST_RESET_TYPE_WARM_REBOOT;
> +		break;
> +	case SYSRESET_COLD:
> +		reset_type = SBI_SRST_RESET_TYPE_COLD_REBOOT;
> +		break;
> +	case SYSRESET_POWER_OFF:
> +		reset_type = SBI_SRST_RESET_TYPE_SHUTDOWN;
> +		break;
> +	default:
> +		log_err("SBI has no system reset extension\n");
> +		return -ENOSYS;
> +	}
> +
> +	sbi_srst_reset(reset_type, SBI_SRST_RESET_REASON_NONE);
> +
> +	return -EINPROGRESS;
> +}
> +
> +efi_status_t efi_reset_system_init(void)
> +{
> +	return EFI_SUCCESS;
> +}
> +
> +void __efi_runtime EFIAPI efi_reset_system(enum efi_reset_type type,
> +					   efi_status_t reset_status,
> +					   unsigned long data_size,
> +					   void *reset_data)
> +{
> +	enum sbi_srst_reset_type reset_type;
> +	enum sbi_srst_reset_reason reset_reason;
> +
> +	if (have_reset)
> +		switch (type) {
> +		case SYSRESET_COLD:
> +			reset_type = SBI_SRST_RESET_TYPE_COLD_REBOOT;
> +			break;
> +		case SYSRESET_POWER_OFF:
> +			reset_type = SBI_SRST_RESET_TYPE_SHUTDOWN;
> +			break;
> +		default:
> +			reset_type = SBI_SRST_RESET_TYPE_WARM_REBOOT;
> +			break;
> +	}
> +
> +	if (reset_status == EFI_SUCCESS)
> +		reset_reason = SBI_SRST_RESET_REASON_NONE;
> +	else
> +		reset_reason = SBI_SRST_RESET_REASON_SYS_FAILURE;
> +
> +	sbi_srst_reset(reset_type, reset_reason);
> +
> +	while (1)
> +		;
> +}
> +
> +static int sbi_sysreset_probe(struct udevice *dev)
> +{
> +	have_reset = sbi_probe_extension(SBI_EXT_SRST);
> +	if (have_reset)
> +		return 0;
> +
> +	log_warning("SBI has no system reset extension\n");
> +	return -ENOENT;
> +}
> +
> +static struct sysreset_ops sbi_sysreset_ops = {
> +	.request = sbi_sysreset_request,
> +};
> +
> +U_BOOT_DRIVER(sbi_sysreset) = {
> +	.name = "sbi-sysreset",
> +	.id = UCLASS_SYSRESET,
> +	.ops = &sbi_sysreset_ops,
> +	.probe = sbi_sysreset_probe,
> +};
> diff --git a/lib/efi_loader/Kconfig b/lib/efi_loader/Kconfig
> index dacc3b5881..36985fce2c 100644
> --- a/lib/efi_loader/Kconfig
> +++ b/lib/efi_loader/Kconfig
> @@ -297,7 +297,7 @@ config EFI_HAVE_RUNTIME_RESET
>   	bool
>   	default y
>   	depends on ARCH_BCM283X || FSL_LAYERSCAPE || PSCI_RESET || \
> -		   SANDBOX || SYSRESET_X86
> +		   SANDBOX || SYSRESET_SBI || SYSRESET_X86
> 
>   config EFI_GRUB_ARM32_WORKAROUND
>   	bool "Workaround for GRUB on 32bit ARM"
> --
> 2.30.2
> 

Reviewed-by: Sean Anderson <seanga2@gmail.com>
Leo Liang July 26, 2021, 8:12 a.m. UTC | #2
On Thu, Jul 22, 2021 at 12:33:05AM +0800, Heinrich Schuchardt wrote:
> Provide sysreset driver using the SBI system reset extension.
> 
> Signed-off-by: Heinrich Schuchardt <xypron.glpk@gmx.de>
> ---
> v2:
> 	remove a superfluous check in sbi_sysreset_request()
> ---
>  MAINTAINERS                     |  1 +
>  arch/riscv/cpu/cpu.c            | 13 ++++-
>  arch/riscv/include/asm/sbi.h    |  1 +
>  arch/riscv/lib/sbi.c            | 21 ++++++--
>  drivers/sysreset/Kconfig        | 11 ++++
>  drivers/sysreset/Makefile       |  1 +
>  drivers/sysreset/sysreset_sbi.c | 96 +++++++++++++++++++++++++++++++++
>  lib/efi_loader/Kconfig          |  2 +-
>  8 files changed, 140 insertions(+), 6 deletions(-)
>  create mode 100644 drivers/sysreset/sysreset_sbi.c

Reviewed-by: Leo Yu-Chi Liang <ycliang@andestech.com>
diff mbox series

Patch

diff --git a/MAINTAINERS b/MAINTAINERS
index a6b49b54b9..29ac9450f5 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1012,6 +1012,7 @@  T:	git https://source.denx.de/u-boot/custodians/u-boot-riscv.git
 F:	arch/riscv/
 F:	cmd/riscv/
 F:	doc/usage/sbi.rst
+F:	drivers/sysreset/sysreset_sbi.c
 F:	drivers/timer/andes_plmt_timer.c
 F:	drivers/timer/sifive_clint_timer.c
 F:	tools/prelink-riscv.c
diff --git a/arch/riscv/cpu/cpu.c b/arch/riscv/cpu/cpu.c
index c894ac10b5..8e49b6d736 100644
--- a/arch/riscv/cpu/cpu.c
+++ b/arch/riscv/cpu/cpu.c
@@ -6,6 +6,7 @@ 
 #include <common.h>
 #include <cpu.h>
 #include <dm.h>
+#include <dm/lists.h>
 #include <init.h>
 #include <log.h>
 #include <asm/encoding.h>
@@ -138,7 +139,17 @@  int arch_cpu_init_dm(void)

 int arch_early_init_r(void)
 {
-	return riscv_cpu_probe();
+	int ret;
+
+	ret = riscv_cpu_probe();
+	if (ret)
+		return ret;
+
+	if (IS_ENABLED(CONFIG_SYSRESET_SBI))
+		device_bind_driver(gd->dm_root, "sbi-sysreset",
+				   "sbi-sysreset", NULL);
+
+	return 0;
 }

 /**
diff --git a/arch/riscv/include/asm/sbi.h b/arch/riscv/include/asm/sbi.h
index 39d5a022e0..b702fca176 100644
--- a/arch/riscv/include/asm/sbi.h
+++ b/arch/riscv/include/asm/sbi.h
@@ -150,5 +150,6 @@  void sbi_set_timer(uint64_t stime_value);
 long sbi_get_spec_version(void);
 int sbi_get_impl_id(void);
 int sbi_probe_extension(int ext);
+void sbi_srst_reset(unsigned long type, unsigned long reason);

 #endif
diff --git a/arch/riscv/lib/sbi.c b/arch/riscv/lib/sbi.c
index 77845a73ca..8508041f2a 100644
--- a/arch/riscv/lib/sbi.c
+++ b/arch/riscv/lib/sbi.c
@@ -8,13 +8,14 @@ 
  */

 #include <common.h>
+#include <efi_loader.h>
 #include <asm/encoding.h>
 #include <asm/sbi.h>

-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 __efi_runtime 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;

@@ -108,6 +109,18 @@  int sbi_probe_extension(int extid)
 	return -ENOTSUPP;
 }

+/**
+ * sbi_srst_reset() - invoke system reset extension
+ *
+ * @type:	type of reset
+ * @reason:	reason for reset
+ */
+void __efi_runtime sbi_srst_reset(unsigned long type, unsigned long reason)
+{
+	sbi_ecall(SBI_EXT_SRST, SBI_EXT_SRST_RESET, type, reason,
+		  0, 0, 0, 0);
+}
+
 #ifdef CONFIG_SBI_V01

 /**
diff --git a/drivers/sysreset/Kconfig b/drivers/sysreset/Kconfig
index ac77ffbc8b..e095951166 100644
--- a/drivers/sysreset/Kconfig
+++ b/drivers/sysreset/Kconfig
@@ -85,6 +85,17 @@  config SYSRESET_PSCI
 	  Enable PSCI SYSTEM_RESET function call.  To use this, PSCI firmware
 	  must be running on your system.

+config SYSRESET_SBI
+	bool "Enable support for SBI System Reset"
+	depends on RISCV_SMODE && SBI_V02
+	select SYSRESET_CMD_POWEROFF if CMD_POWEROFF
+	help
+	  Enable system reset and poweroff via the SBI system reset extension.
+	  If the SBI implementation provides the extension, is board specific.
+	  The extension was introduced in version 0.3 of the SBI specification.
+	  The SBI system reset driver supports the UEFI ResetSystem() service
+	  at runtime.
+
 config SYSRESET_SOCFPGA
 	bool "Enable support for Intel SOCFPGA family"
 	depends on ARCH_SOCFPGA && (TARGET_SOCFPGA_GEN5 || TARGET_SOCFPGA_ARRIA10)
diff --git a/drivers/sysreset/Makefile b/drivers/sysreset/Makefile
index de81c399d7..8e00be0779 100644
--- a/drivers/sysreset/Makefile
+++ b/drivers/sysreset/Makefile
@@ -13,6 +13,7 @@  obj-$(CONFIG_SYSRESET_MPC83XX) += sysreset_mpc83xx.o
 obj-$(CONFIG_SYSRESET_MICROBLAZE) += sysreset_microblaze.o
 obj-$(CONFIG_SYSRESET_OCTEON) += sysreset_octeon.o
 obj-$(CONFIG_SYSRESET_PSCI) += sysreset_psci.o
+obj-$(CONFIG_SYSRESET_SBI) += sysreset_sbi.o
 obj-$(CONFIG_SYSRESET_SOCFPGA) += sysreset_socfpga.o
 obj-$(CONFIG_SYSRESET_SOCFPGA_SOC64) += sysreset_socfpga_soc64.o
 obj-$(CONFIG_SYSRESET_TI_SCI) += sysreset-ti-sci.o
diff --git a/drivers/sysreset/sysreset_sbi.c b/drivers/sysreset/sysreset_sbi.c
new file mode 100644
index 0000000000..fec5a66515
--- /dev/null
+++ b/drivers/sysreset/sysreset_sbi.c
@@ -0,0 +1,96 @@ 
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2021, Heinrich Schuchardt <xypron.glpk@gmx.de>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <efi_loader.h>
+#include <log.h>
+#include <sysreset.h>
+#include <asm/sbi.h>
+
+static long __efi_runtime_data have_reset;
+
+static int sbi_sysreset_request(struct udevice *dev, enum sysreset_t type)
+{
+	enum sbi_srst_reset_type reset_type;
+
+	switch (type) {
+	case SYSRESET_WARM:
+		reset_type = SBI_SRST_RESET_TYPE_WARM_REBOOT;
+		break;
+	case SYSRESET_COLD:
+		reset_type = SBI_SRST_RESET_TYPE_COLD_REBOOT;
+		break;
+	case SYSRESET_POWER_OFF:
+		reset_type = SBI_SRST_RESET_TYPE_SHUTDOWN;
+		break;
+	default:
+		log_err("SBI has no system reset extension\n");
+		return -ENOSYS;
+	}
+
+	sbi_srst_reset(reset_type, SBI_SRST_RESET_REASON_NONE);
+
+	return -EINPROGRESS;
+}
+
+efi_status_t efi_reset_system_init(void)
+{
+	return EFI_SUCCESS;
+}
+
+void __efi_runtime EFIAPI efi_reset_system(enum efi_reset_type type,
+					   efi_status_t reset_status,
+					   unsigned long data_size,
+					   void *reset_data)
+{
+	enum sbi_srst_reset_type reset_type;
+	enum sbi_srst_reset_reason reset_reason;
+
+	if (have_reset)
+		switch (type) {
+		case SYSRESET_COLD:
+			reset_type = SBI_SRST_RESET_TYPE_COLD_REBOOT;
+			break;
+		case SYSRESET_POWER_OFF:
+			reset_type = SBI_SRST_RESET_TYPE_SHUTDOWN;
+			break;
+		default:
+			reset_type = SBI_SRST_RESET_TYPE_WARM_REBOOT;
+			break;
+	}
+
+	if (reset_status == EFI_SUCCESS)
+		reset_reason = SBI_SRST_RESET_REASON_NONE;
+	else
+		reset_reason = SBI_SRST_RESET_REASON_SYS_FAILURE;
+
+	sbi_srst_reset(reset_type, reset_reason);
+
+	while (1)
+		;
+}
+
+static int sbi_sysreset_probe(struct udevice *dev)
+{
+	have_reset = sbi_probe_extension(SBI_EXT_SRST);
+	if (have_reset)
+		return 0;
+
+	log_warning("SBI has no system reset extension\n");
+	return -ENOENT;
+}
+
+static struct sysreset_ops sbi_sysreset_ops = {
+	.request = sbi_sysreset_request,
+};
+
+U_BOOT_DRIVER(sbi_sysreset) = {
+	.name = "sbi-sysreset",
+	.id = UCLASS_SYSRESET,
+	.ops = &sbi_sysreset_ops,
+	.probe = sbi_sysreset_probe,
+};
diff --git a/lib/efi_loader/Kconfig b/lib/efi_loader/Kconfig
index dacc3b5881..36985fce2c 100644
--- a/lib/efi_loader/Kconfig
+++ b/lib/efi_loader/Kconfig
@@ -297,7 +297,7 @@  config EFI_HAVE_RUNTIME_RESET
 	bool
 	default y
 	depends on ARCH_BCM283X || FSL_LAYERSCAPE || PSCI_RESET || \
-		   SANDBOX || SYSRESET_X86
+		   SANDBOX || SYSRESET_SBI || SYSRESET_X86

 config EFI_GRUB_ARM32_WORKAROUND
 	bool "Workaround for GRUB on 32bit ARM"