Quoting Elliot Berman (2024-10-18 12:39:48) > diff --git a/drivers/firmware/psci/psci.c b/drivers/firmware/psci/psci.c > index 2328ca58bba6..60bc285622ce 100644 > --- a/drivers/firmware/psci/psci.c > +++ b/drivers/firmware/psci/psci.c > @@ -29,6 +29,8 @@ > #include <asm/smp_plat.h> > #include <asm/suspend.h> > > +#define REBOOT_PREFIX "mode-" Maybe move this near the function that uses it. > + > /* > * While a 64-bit OS can make calls with SMC32 calling conventions, for some > * calls it is necessary to use SMC64 to pass or return 64-bit values. > @@ -305,9 +315,29 @@ static int get_set_conduit_method(const struct device_node *np) > return 0; > } > > +static void psci_vendor_sys_reset2(unsigned long action, void *data) > +{ > + const char *cmd = data; > + unsigned long ret; > + size_t i; > + > + for (i = 0; i < num_psci_reset_params; i++) { > + if (!strcmp(psci_reset_params[i].mode, cmd)) { > + ret = invoke_psci_fn(PSCI_FN_NATIVE(1_1, SYSTEM_RESET2), > + psci_reset_params[i].reset_type, > + psci_reset_params[i].cookie, 0); > + pr_err("failed to perform reset \"%s\": %ld\n", > + cmd, (long)ret); Do this intentionally return? Should it be some other function that's __noreturn instead and a while (1) if the firmware returns back to the kernel? > + } > + } > +} > + > static int psci_sys_reset(struct notifier_block *nb, unsigned long action, > void *data) > { > + if (data && num_psci_reset_params) > + psci_vendor_sys_reset2(action, data); > + > if ((reboot_mode == REBOOT_WARM || reboot_mode == REBOOT_SOFT) && > psci_system_reset2_supported) { > /* > @@ -750,6 +780,68 @@ static const struct of_device_id psci_of_match[] __initconst = { > {}, > }; > > +static int __init psci_init_system_reset2_modes(void) > +{ > + const size_t len = strlen(REBOOT_PREFIX); > + struct psci_reset_param *param; > + struct device_node *psci_np __free(device_node) = NULL; > + struct device_node *np __free(device_node) = NULL; > + struct property *prop; > + size_t count = 0; > + u32 magic[2]; > + int num; > + > + if (!psci_system_reset2_supported) > + return 0; > + > + psci_np = of_find_matching_node(NULL, psci_of_match); > + if (!psci_np) > + return 0; > + > + np = of_find_node_by_name(psci_np, "reset-types"); > + if (!np) > + return 0; > + > + for_each_property_of_node(np, prop) { > + if (strncmp(prop->name, REBOOT_PREFIX, len)) > + continue; > + num = of_property_count_elems_of_size(np, prop->name, sizeof(magic[0])); Use of_property_count_u32_elems()? > + if (num != 1 && num != 2) > + continue; > + > + count++; > + } > + > + param = psci_reset_params = kcalloc(count, sizeof(*psci_reset_params), GFP_KERNEL); > + if (!psci_reset_params) > + return -ENOMEM; > + > + for_each_property_of_node(np, prop) { > + if (strncmp(prop->name, REBOOT_PREFIX, len)) > + continue; > + > + param->mode = kstrdup_const(prop->name + len, GFP_KERNEL); > + if (!param->mode) > + continue; > + > + num = of_property_read_variable_u32_array(np, prop->name, magic, 1, 2); ARRAY_SIZE(magic)? > + if (num < 0) { Should this be less than 1? > + pr_warn("Failed to parse vendor reboot mode %s\n", param->mode); > + kfree_const(param->mode); > + continue; > + } > + > + /* Force reset type to be in vendor space */ > + param->reset_type = PSCI_1_1_RESET_TYPE_VENDOR_START | magic[0]; > + param->cookie = num == 2 ? magic[1] : 0; ARRAY_SIZE(magic)? > + param++; > + num_psci_reset_params++; > + } > + > + return 0;