@@ -130,13 +130,6 @@ void machine_restart(char *cmd)
local_irq_disable();
smp_send_stop();
- /*
- * UpdateCapsule() depends on the system being reset via
- * ResetSystem().
- */
- if (efi_enabled(EFI_RUNTIME_SERVICES))
- efi_reboot(reboot_mode, NULL);
-
/* Now call the architecture specific reboot code. */
do_kernel_restart(cmd);
@@ -80,6 +80,28 @@ static bool __init efi_virtmap_init(void)
return true;
}
+static int efi_restart(struct notifier_block *nb, unsigned long action,
+ void *data)
+{
+ /*
+ * UpdateCapsule() depends on the system being reset via
+ * ResetSystem().
+ */
+ efi_reboot(reboot_mode, NULL);
+
+ return NOTIFY_DONE;
+}
+
+static struct notifier_block efi_restart_nb = {
+ .notifier_call = efi_restart,
+ /**
+ * If you are running UEFI based system, you most certainly should let
+ * efi_reboot() do a reset for you. If you think you know better, we
+ * leave you a window of opportunity here by not using maximal priority.
+ */
+ .priority = 251,
+};
+
/*
* Enable the UEFI Runtime Services if all prerequisites are in place, i.e.,
* non-early mapping of the UEFI system table and virtual mappings for all
@@ -148,6 +170,9 @@ static int __init arm_enable_runtime_services(void)
efi_native_runtime_setup();
set_bit(EFI_RUNTIME_SERVICES, &efi.flags);
+ if (IS_ENABLED(CONFIG_ARM64))
+ register_restart_handler(&efi_restart_nb);
+
return 0;
}
early_initcall(arm_enable_runtime_services);
On EFI enabled arm64 systems, efi_reboot was called before do_kernel_restart, completely omitting the reset_handlers functionality. By registering efi_reboot as part of the chain with elevated priority, we make it run before the default handler but still allow plugging in other handlers. This is useful in two scenarios: - Abusing the restart handler as a notification mechanism similar to reboot notifiers, but working in wider spectrum of cases, (notably also at emergency_restart) and just before reset. This is useful for things like in-kernel pwrseq_emmc, or any other place where it is beneficial for an *external* component to know about the restart, but not performing the reset itself. - Providing higher priority reset handler, where resetting the SoC is not enough, and reset of the whole board should be orchestrated by some external component, that the firmware is not aware of (like an FPGA or some PMIC). This change moves the conditional efi_reboot() call from arm64 specific machine_restart() function to an arm efi initialization code where it is registered as a restart handler with a very high (but not the highest) priority, leaving a small window of opportunity for some code to be run prior to the actual reset, like on other architectures. The restart handlers mechanism is proven to work reliably as we depend on it heavily on other platforms so there is almost no cost for this change but it adds flexibility and unifies our infrastructure with other ports (where one can depend on restart handlers working). Signed-off-by: Krzysztof Adamski <krzysztof.adamski@nokia.com> --- While previous attempts got mixed feedback, my explanations did not seen counterarguments so I am trying another round: Changes in v3: - Bump the priority much higher, to almost maximal value - Add a comment discouraging from registering higher prio handlers - Update the commit message to contain some more justifications Changes in v2: - Register the handler in EFI code, instead of arm64 setup.c - Remove the contdition from the handler - it should be run in all cases when it is registered - Bump the priority to 130 to make it completly obious this should be run before PSCI (which has priority of 129) arch/arm64/kernel/process.c | 7 ------- drivers/firmware/efi/arm-runtime.c | 25 +++++++++++++++++++++++++ 2 files changed, 25 insertions(+), 7 deletions(-)