[PATCH v3 3/3] sysreset: provide SBI based sysreset driver
Bin Meng
bmeng.cn at gmail.com
Mon Sep 6 03:47:39 CEST 2021
On Mon, Sep 6, 2021 at 1:21 AM Heinrich Schuchardt <xypron.glpk at gmx.de> wrote:
>
> On 9/5/21 7:00 PM, Bin Meng wrote:
> > Hi Heinrich,
> >
> > On Mon, Sep 6, 2021 at 12:50 AM Heinrich Schuchardt <xypron.glpk at gmx.de> wrote:
> >>
> >> On 9/5/21 1:59 PM, Bin Meng wrote:
> >>> On Sun, Sep 5, 2021 at 4:38 PM Heinrich Schuchardt <xypron.glpk at gmx.de> wrote:
> >>>>
> >>>> Provide sysreset driver using the SBI system reset extension.
> >>>>
> >>>
> >>> This patch should be split into 2 patches, one for adding the sysreset
> >>> DM driver, and the other one for EFI support.
> >>>
> >>>> Signed-off-by: Heinrich Schuchardt <xypron.glpk at gmx.de>
> >>>> ---
> >>>> v3:
> >>>> no change
> >>>> ---
> >>>> 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 4cf0c33c5d..88d7aa2bc7 100644
> >>>> --- a/MAINTAINERS
> >>>> +++ b/MAINTAINERS
> >>>> @@ -1017,6 +1017,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 e9caa78d17..69cddda245 100644
> >>>> --- a/arch/riscv/include/asm/sbi.h
> >>>> +++ b/arch/riscv/include/asm/sbi.h
> >>>> @@ -154,5 +154,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..6782331181 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 at 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;
> >>>> +}
> >>>
> >>> Is there a better place for the EFI stuff?
> >>
> >> Bin, thanks for reviewing the series.
> >>
> >> This seems to be related to you comment above about splitting into two
> >> patches.
> >
> > Yep.
> >
> >> We put have the same set of EFI runtime functions for system
> >> reset in:
> >>
> >> drivers/sysreset/sysreset_x86.c
> >> drivers/firmware/psci.c
> >> arch/arm/mach-bcm283x/reset.c
> >> arch/arm/cpu/armv8/fsl-layerscape/cpu.c
> >
> > I didn't realize that. But this does not look correct to me.
> >
> > EFI reset should be independent of the system reset drivers. For
> > example, on RISC-V SRST is optional so not every SBI implements this.
> > On SiFive Unleashed, the "gpio-restart" driver is used for reset (see
> > sysreset_gpio.c).
>
> The EFI functions that you see in this patch are for the runtime, i.e.
> after ExitBootServices().
>
> When you issue the reboot or poweroff command in Linux it will call the
> UEFI runtime. At this point all driver model code is gone. So we cannot
> call any DM U-Boot driver. This is why these two functions are marked as
> __efi_runtime.
The mark of __efi_runtime is troublesome in some cases. I remember on
x86 when booting from U-Boot EFI loader the Linux kernel calls EFI
runtime services would hang which is because we don't mark the
required functions with __efi_runtime in U-Boot. This is not a
scalable solution I think. In the end we may have to mark all U-Boot
functions to __efi_runtime.
> The RISC-V platform specification clearly states that you should use the
> SBI system reset if it exists.
>
> Before ExitBootServices() the U-Boot sysreset driver will be called
> which may be the SBI driver. U-Boot will iterate through all sysreset
> drivers until one actually resets the board.
>
> >
> > With the approach in this patch, we mandate the EFI reset goes through
> > the SBI call hence it does not work on boards like Unleashed.
>
> On the Hifive Unmatched poweroff using OpenSBI just works fine. But
> OpenSBI does not have reset for the HiFive Unmatched due to a missing GPIO.
>
> I have no HiFive Unleashed for testing but calling OpenSBI should work
> out of the box as the device-tree defines the GPIOs both for reboot and
> poweroff that the reset driver looks for in OpenSBI. Do you have access
> to an Unleashed board for testing?
>
> For OpenSBI I created commit e928472e67f8 ("lib: utils: support both of
> gpio-poweroff, gpio-reset") which you will be needed for the Unleashed
> board. The patch is merged into upstream.
>
Regards,
Bin
More information about the U-Boot
mailing list