diff mbox series

[v5,3/4] firmware: psci: Read and use vendor reset types

Message ID 20240617-arm-psci-system_reset2-vendor-reboots-v5-3-086950f650c8@quicinc.com
State New
Headers show
Series None | expand

Commit Message

Elliot Berman June 17, 2024, 5:18 p.m. UTC
SoC vendors have different types of resets and are controlled through
various registers. For instance, Qualcomm chipsets can reboot to a
"download mode" that allows a RAM dump to be collected. Another example
is they also support writing a cookie that can be read by bootloader
during next boot. PSCI offers a mechanism, SYSTEM_RESET2, for these
vendor reset types to be implemented without requiring drivers for every
register/cookie.

Add support in PSCI to statically map reboot mode commands from
userspace to a vendor reset and cookie value using the device tree.

A separate initcall is needed to parse the devicetree, instead of using
psci_dt_init because mm isn't sufficiently set up to allocate memory.

Reboot mode framework is close but doesn't quite fit with the
design and requirements for PSCI SYSTEM_RESET2. Some of these issues can
be solved but doesn't seem reasonable in sum:
 1. reboot mode registers against the reboot_notifier_list, which is too
    early to call SYSTEM_RESET2. PSCI would need to remember the reset
    type from the reboot-mode framework callback and use it
    psci_sys_reset.
 2. reboot mode assumes only one cookie/parameter is described in the
    device tree. SYSTEM_RESET2 uses 2: one for the type and one for
    cookie.
 3. psci cpuidle driver already registers a driver against the
    arm,psci-1.0 compatible. Refactoring would be needed to have both a
    cpuidle and reboot-mode driver.

Tested-by: Florian Fainelli <florian.fainelli@broadcom.com>
Signed-off-by: Elliot Berman <quic_eberman@quicinc.com>
---
 drivers/firmware/psci/psci.c | 92 ++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 92 insertions(+)

Comments

Sudeep Holla June 19, 2024, 1:51 p.m. UTC | #1
On Mon, Jun 17, 2024 at 10:18:09AM -0700, Elliot Berman wrote:
> SoC vendors have different types of resets and are controlled through
> various registers. For instance, Qualcomm chipsets can reboot to a
> "download mode" that allows a RAM dump to be collected. Another example
> is they also support writing a cookie that can be read by bootloader
> during next boot. PSCI offers a mechanism, SYSTEM_RESET2, for these
> vendor reset types to be implemented without requiring drivers for every
> register/cookie.
> 
> Add support in PSCI to statically map reboot mode commands from
> userspace to a vendor reset and cookie value using the device tree.
> 
> A separate initcall is needed to parse the devicetree, instead of using
> psci_dt_init because mm isn't sufficiently set up to allocate memory.
> 
> Reboot mode framework is close but doesn't quite fit with the
> design and requirements for PSCI SYSTEM_RESET2. Some of these issues can
> be solved but doesn't seem reasonable in sum:
>  1. reboot mode registers against the reboot_notifier_list, which is too
>     early to call SYSTEM_RESET2. PSCI would need to remember the reset
>     type from the reboot-mode framework callback and use it
>     psci_sys_reset.
>  2. reboot mode assumes only one cookie/parameter is described in the
>     device tree. SYSTEM_RESET2 uses 2: one for the type and one for
>     cookie.
>  3. psci cpuidle driver already registers a driver against the
>     arm,psci-1.0 compatible. Refactoring would be needed to have both a
>     cpuidle and reboot-mode driver.
>

I need to think through it but when you first introduced the generic
Documentation/devicetree/bindings/power/reset/reboot-mode.yaml bindings
I also looked at drivers/power/reset/reboot-mode.c

I assumed this extension to that binding would reuse the same and
PSCI would just do reboot_mode_register(). I didn't expect to see these
changes. I might have missing something but since the bindings is still
quite generic with additional cells that act as additional cookie for
reboot call, I still think that should be possible.

What am I missing here then ?
Elliot Berman June 19, 2024, 3:28 p.m. UTC | #2
On Wed, Jun 19, 2024 at 02:51:43PM +0100, Sudeep Holla wrote:
> On Mon, Jun 17, 2024 at 10:18:09AM -0700, Elliot Berman wrote:
> > SoC vendors have different types of resets and are controlled through
> > various registers. For instance, Qualcomm chipsets can reboot to a
> > "download mode" that allows a RAM dump to be collected. Another example
> > is they also support writing a cookie that can be read by bootloader
> > during next boot. PSCI offers a mechanism, SYSTEM_RESET2, for these
> > vendor reset types to be implemented without requiring drivers for every
> > register/cookie.
> > 
> > Add support in PSCI to statically map reboot mode commands from
> > userspace to a vendor reset and cookie value using the device tree.
> > 
> > A separate initcall is needed to parse the devicetree, instead of using
> > psci_dt_init because mm isn't sufficiently set up to allocate memory.
> > 
> > Reboot mode framework is close but doesn't quite fit with the
> > design and requirements for PSCI SYSTEM_RESET2. Some of these issues can
> > be solved but doesn't seem reasonable in sum:
> >  1. reboot mode registers against the reboot_notifier_list, which is too
> >     early to call SYSTEM_RESET2. PSCI would need to remember the reset
> >     type from the reboot-mode framework callback and use it
> >     psci_sys_reset.
> >  2. reboot mode assumes only one cookie/parameter is described in the
> >     device tree. SYSTEM_RESET2 uses 2: one for the type and one for
> >     cookie.
> >  3. psci cpuidle driver already registers a driver against the
> >     arm,psci-1.0 compatible. Refactoring would be needed to have both a
> >     cpuidle and reboot-mode driver.
> >
> 
> I need to think through it but when you first introduced the generic
> Documentation/devicetree/bindings/power/reset/reboot-mode.yaml bindings
> I also looked at drivers/power/reset/reboot-mode.c
> 
> I assumed this extension to that binding would reuse the same and
> PSCI would just do reboot_mode_register(). I didn't expect to see these
> changes. I might have missing something but since the bindings is still
> quite generic with additional cells that act as additional cookie for
> reboot call, I still think that should be possible.
> 
> What am I missing here then ?
> 

Right, if that was only thing to "solve" to make it easy to use
reboot-mode framework, I agree we should update reboot mode framework to
work with the additional cells. There are a few other issues I mention
above which, when combined, make me feel that PSCI is different enough
from how reboot mode framework works that we shouldn't try to make PSCI
work with the framework. Issues #1 and #2 are pretty easy to solve
(whether they should be solved is different); I'm not sure a good
approach to issue #3.

Thanks,
Elliot
Elliot Berman June 20, 2024, 11:37 p.m. UTC | #3
Hi Sudeep and Sebastian,

On Wed, Jun 19, 2024 at 08:28:06AM -0700, Elliot Berman wrote:
> On Wed, Jun 19, 2024 at 02:51:43PM +0100, Sudeep Holla wrote:
> > On Mon, Jun 17, 2024 at 10:18:09AM -0700, Elliot Berman wrote:
> > > SoC vendors have different types of resets and are controlled through
> > > various registers. For instance, Qualcomm chipsets can reboot to a
> > > "download mode" that allows a RAM dump to be collected. Another example
> > > is they also support writing a cookie that can be read by bootloader
> > > during next boot. PSCI offers a mechanism, SYSTEM_RESET2, for these
> > > vendor reset types to be implemented without requiring drivers for every
> > > register/cookie.
> > > 
> > > Add support in PSCI to statically map reboot mode commands from
> > > userspace to a vendor reset and cookie value using the device tree.
> > > 
> > > A separate initcall is needed to parse the devicetree, instead of using
> > > psci_dt_init because mm isn't sufficiently set up to allocate memory.
> > > 
> > > Reboot mode framework is close but doesn't quite fit with the
> > > design and requirements for PSCI SYSTEM_RESET2. Some of these issues can
> > > be solved but doesn't seem reasonable in sum:
> > >  1. reboot mode registers against the reboot_notifier_list, which is too
> > >     early to call SYSTEM_RESET2. PSCI would need to remember the reset
> > >     type from the reboot-mode framework callback and use it
> > >     psci_sys_reset.
> > >  2. reboot mode assumes only one cookie/parameter is described in the
> > >     device tree. SYSTEM_RESET2 uses 2: one for the type and one for
> > >     cookie.
> > >  3. psci cpuidle driver already registers a driver against the
> > >     arm,psci-1.0 compatible. Refactoring would be needed to have both a
> > >     cpuidle and reboot-mode driver.
> > >
> > 
> > I need to think through it but when you first introduced the generic
> > Documentation/devicetree/bindings/power/reset/reboot-mode.yaml bindings
> > I also looked at drivers/power/reset/reboot-mode.c
> > 
> > I assumed this extension to that binding would reuse the same and
> > PSCI would just do reboot_mode_register(). I didn't expect to see these
> > changes. I might have missing something but since the bindings is still
> > quite generic with additional cells that act as additional cookie for
> > reboot call, I still think that should be possible.
> > 
> > What am I missing here then ?
> > 
> 
> Right, if that was only thing to "solve" to make it easy to use
> reboot-mode framework, I agree we should update reboot mode framework to
> work with the additional cells. There are a few other issues I mention
> above which, when combined, make me feel that PSCI is different enough
> from how reboot mode framework works that we shouldn't try to make PSCI
> work with the framework. Issues #1 and #2 are pretty easy to solve
> (whether they should be solved is different); I'm not sure a good
> approach to issue #3.
> 

Does the reasoning I mention in the commit text make sense why PSCI should
avoid using the reboot-mode.c framework?

Thanks,
Elliot
Sudeep Holla June 24, 2024, 3:56 p.m. UTC | #4
On Mon, Jun 17, 2024 at 10:18:09AM -0700, Elliot Berman wrote:
> SoC vendors have different types of resets and are controlled through
> various registers. For instance, Qualcomm chipsets can reboot to a
> "download mode" that allows a RAM dump to be collected. Another example
> is they also support writing a cookie that can be read by bootloader
> during next boot. PSCI offers a mechanism, SYSTEM_RESET2, for these
> vendor reset types to be implemented without requiring drivers for every
> register/cookie.
> 
> Add support in PSCI to statically map reboot mode commands from
> userspace to a vendor reset and cookie value using the device tree.
> 
> A separate initcall is needed to parse the devicetree, instead of using
> psci_dt_init because mm isn't sufficiently set up to allocate memory.
> 
> Reboot mode framework is close but doesn't quite fit with the
> design and requirements for PSCI SYSTEM_RESET2. Some of these issues can
> be solved but doesn't seem reasonable in sum:
>  1. reboot mode registers against the reboot_notifier_list, which is too
>     early to call SYSTEM_RESET2. PSCI would need to remember the reset
>     type from the reboot-mode framework callback and use it
>     psci_sys_reset.

Fair enough, good reason but as I mentioned I haven't looked at it in
details to provide any suggestion or to assert it can be solved.

>  2. reboot mode assumes only one cookie/parameter is described in the
>     device tree. SYSTEM_RESET2 uses 2: one for the type and one for
>     cookie.

I assumed it shouldn't be too difficult to extend it to support 2 parameters.

>  3. psci cpuidle driver already registers a driver against the
>     arm,psci-1.0 compatible. Refactoring would be needed to have both a
>     cpuidle and reboot-mode driver.

This one seems not a strong reason in my opinion. It was not designed for
cpuidle and it can't bind to that solely. If this becomes only reason, then
we need to fix that.
Elliot Berman July 2, 2024, 11:06 p.m. UTC | #5
Hi Sudeep,

On Mon, Jun 24, 2024 at 04:41:42PM +0100, Sudeep Holla wrote:
> Sorry, I completely missed to see that you had already answered those
> in your commit message. As mentioned earlier I haven't looked at the
> reboot mode framework completely yet, so I can't comment on it yet.
> 
> I don't want to be blocker though if others are happy with this.

I think folks are satisfied with the other parts of the series and now
looking for your conclusion on the PSCI driver part.

Thanks,
Elliot
Trilok Soni July 2, 2024, 11:42 p.m. UTC | #6
On 7/2/2024 4:06 PM, Elliot Berman wrote:
> Hi Sudeep,
> 
> On Mon, Jun 24, 2024 at 04:41:42PM +0100, Sudeep Holla wrote:
>> Sorry, I completely missed to see that you had already answered those
>> in your commit message. As mentioned earlier I haven't looked at the
>> reboot mode framework completely yet, so I can't comment on it yet.
>>
>> I don't want to be blocker though if others are happy with this.
> 
> I think folks are satisfied with the other parts of the series and now
> looking for your conclusion on the PSCI driver part.

I will be nice to get these patches picked up before 4th July holiday in US :).
Trilok Soni July 9, 2024, 3:50 a.m. UTC | #7
On 7/2/2024 4:42 PM, Trilok Soni wrote:
> On 7/2/2024 4:06 PM, Elliot Berman wrote:
>> Hi Sudeep,
>>
>> On Mon, Jun 24, 2024 at 04:41:42PM +0100, Sudeep Holla wrote:
>>> Sorry, I completely missed to see that you had already answered those
>>> in your commit message. As mentioned earlier I haven't looked at the
>>> reboot mode framework completely yet, so I can't comment on it yet.
>>>
>>> I don't want to be blocker though if others are happy with this.
>>
>> I think folks are satisfied with the other parts of the series and now
>> looking for your conclusion on the PSCI driver part.
> 
> I will be nice to get these patches picked up before 4th July holiday in US :).

Sorry to bug you again Sudeep - but I need confirmation that these patches looks good to you
and you will pick them up. Thanks.
Sudeep Holla July 9, 2024, 11:19 a.m. UTC | #8
On Mon, Jul 08, 2024 at 08:50:58PM -0700, Trilok Soni wrote:
> On 7/2/2024 4:42 PM, Trilok Soni wrote:
> > On 7/2/2024 4:06 PM, Elliot Berman wrote:
> >> Hi Sudeep,
> >>
> >> On Mon, Jun 24, 2024 at 04:41:42PM +0100, Sudeep Holla wrote:
> >>> Sorry, I completely missed to see that you had already answered those
> >>> in your commit message. As mentioned earlier I haven't looked at the
> >>> reboot mode framework completely yet, so I can't comment on it yet.
> >>>
> >>> I don't want to be blocker though if others are happy with this.
> >>
> >> I think folks are satisfied with the other parts of the series and now
> >> looking for your conclusion on the PSCI driver part.
> >
> > I will be nice to get these patches picked up before 4th July holiday in US :).
>

July 3rd was already late to target v6.11 😉, the merge window may open next
Sunday. Ideally we prefer to have code reviewed and merged before previous
-rc6 so that it spends couple of weeks in -next before the merge. If I were
to merge, I freeze my branch by -rc5 and send PR to Arnd after that so that
Arnd gets some time with the integration of all other PRs.

> Sorry to bug you again Sudeep - but I need confirmation that these patches looks good to you
> and you will pick them up. Thanks.

FYI I am not the maintainer of PSCI. I have given my feedback but I haven't
been able to explore reset/reboot core support in much detail to provide
any further useful suggestions to move the code out of PSCI like I would
ideally like to. But that said I don't want to block this series just for
that reason.

--
Regards,
Sudeep
Shivendra Pratap Aug. 6, 2024, 2:38 p.m. UTC | #9
Tested-by: Shivendra Pratap <quic_spratap@quicinc.com> # on QCS6490-RB3GEN2, QCM6490-IDP

Can we take it up now?

On 7/9/2024 4:49 PM, Sudeep Holla wrote:
> On Mon, Jul 08, 2024 at 08:50:58PM -0700, Trilok Soni wrote:
>> On 7/2/2024 4:42 PM, Trilok Soni wrote:
>>> On 7/2/2024 4:06 PM, Elliot Berman wrote:
>>>> Hi Sudeep,
>>>>
>>>> On Mon, Jun 24, 2024 at 04:41:42PM +0100, Sudeep Holla wrote:
>>>>> Sorry, I completely missed to see that you had already answered those
>>>>> in your commit message. As mentioned earlier I haven't looked at the
>>>>> reboot mode framework completely yet, so I can't comment on it yet.
>>>>>
>>>>> I don't want to be blocker though if others are happy with this.
>>>>
>>>> I think folks are satisfied with the other parts of the series and now
>>>> looking for your conclusion on the PSCI driver part.
>>>
>>> I will be nice to get these patches picked up before 4th July holiday in US :).
>>
> 
> July 3rd was already late to target v6.11 😉, the merge window may open next
> Sunday. Ideally we prefer to have code reviewed and merged before previous
> -rc6 so that it spends couple of weeks in -next before the merge. If I were
> to merge, I freeze my branch by -rc5 and send PR to Arnd after that so that
> Arnd gets some time with the integration of all other PRs.
> 
>> Sorry to bug you again Sudeep - but I need confirmation that these patches looks good to you
>> and you will pick them up. Thanks.
> 
> FYI I am not the maintainer of PSCI. I have given my feedback but I haven't
> been able to explore reset/reboot core support in much detail to provide
> any further useful suggestions to move the code out of PSCI like I would
> ideally like to. But that said I don't want to block this series just for
> that reason.
> 
> --
> Regards,
> Sudeep
Lorenzo Pieralisi Aug. 7, 2024, 3:02 p.m. UTC | #10
On Mon, Jun 17, 2024 at 10:18:09AM -0700, Elliot Berman wrote:
> SoC vendors have different types of resets and are controlled through
> various registers. For instance, Qualcomm chipsets can reboot to a
> "download mode" that allows a RAM dump to be collected. Another example
> is they also support writing a cookie that can be read by bootloader
> during next boot. PSCI offers a mechanism, SYSTEM_RESET2, for these
> vendor reset types to be implemented without requiring drivers for every
> register/cookie.
> 
> Add support in PSCI to statically map reboot mode commands from
> userspace to a vendor reset and cookie value using the device tree.
> 
> A separate initcall is needed to parse the devicetree, instead of using
> psci_dt_init because mm isn't sufficiently set up to allocate memory.
> 
> Reboot mode framework is close but doesn't quite fit with the
> design and requirements for PSCI SYSTEM_RESET2. Some of these issues can
> be solved but doesn't seem reasonable in sum:
>  1. reboot mode registers against the reboot_notifier_list, which is too
>     early to call SYSTEM_RESET2.

Please define "too early" (apologies if it has been explained before).

>     PSCI would need to remember the reset type from the reboot-mode
>     framework callback and use it psci_sys_reset.
>  2. reboot mode assumes only one cookie/parameter is described in the
>     device tree. SYSTEM_RESET2 uses 2: one for the type and one for
>     cookie.

That's surmountable I suppose.

>  3. psci cpuidle driver already registers a driver against the
>     arm,psci-1.0 compatible. Refactoring would be needed to have both a
>     cpuidle and reboot-mode driver.

We could put together a PSCI "parent" driver that creates child platform
devices for idle and reboot drivers to match (which actually is not
really pretty but it would make more sense than matching the idle
driver only to the psci compatible string, which is what current code
does).

> Tested-by: Florian Fainelli <florian.fainelli@broadcom.com>
> Signed-off-by: Elliot Berman <quic_eberman@quicinc.com>
> ---
>  drivers/firmware/psci/psci.c | 92 ++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 92 insertions(+)
> 
> diff --git a/drivers/firmware/psci/psci.c b/drivers/firmware/psci/psci.c
> index d9629ff87861..e672b33b71d1 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-"
> +
>  /*
>   * 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.
> @@ -79,6 +81,14 @@ struct psci_0_1_function_ids get_psci_0_1_function_ids(void)
>  static u32 psci_cpu_suspend_feature;
>  static bool psci_system_reset2_supported;
>  
> +struct psci_reset_param {
> +	const char *mode;
> +	u32 reset_type;
> +	u32 cookie;
> +};
> +static struct psci_reset_param *psci_reset_params;
> +static size_t num_psci_reset_params;
> +
>  static inline bool psci_has_ext_power_state(void)
>  {
>  	return psci_cpu_suspend_feature &
> @@ -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)

'action' is unused and therefore it is not really needed.

> +{
> +	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);
> +		}
> +	}
> +}
> +
>  static int psci_sys_reset(struct notifier_block *nb, unsigned long action,
>  			  void *data)
>  {
> +	if (data && num_psci_reset_params)

So, reboot_mode here is basically ignored; if there is a vendor defined
reset, we fire it off.

I think Mark mentioned his concerns earlier related to REBOOT_* mode and
reset type (granted, the context was different):

https://lore.kernel.org/all/20200320120105.GA36658@C02TD0UTHF1T.local/

I would like to understand if this is the right thing to do before
accepting this patchset.

Thanks,
Lorenzo

> +		psci_vendor_sys_reset2(action, data);
> +
>  	if ((reboot_mode == REBOOT_WARM || reboot_mode == REBOOT_SOFT) &&
>  	    psci_system_reset2_supported) {
>  		/*
> @@ -748,6 +778,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]));
> +		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);
> +		if (num < 0) {
> +			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;
> +		param++;
> +		num_psci_reset_params++;
> +	}
> +
> +	return 0;
> +}
> +arch_initcall(psci_init_system_reset2_modes);
> +
>  int __init psci_dt_init(void)
>  {
>  	struct device_node *np;
> 
> -- 
> 2.34.1
>
Elliot Berman Aug. 7, 2024, 6:10 p.m. UTC | #11
On Wed, Aug 07, 2024 at 05:02:38PM +0200, Lorenzo Pieralisi wrote:
> On Mon, Jun 17, 2024 at 10:18:09AM -0700, Elliot Berman wrote:
> > SoC vendors have different types of resets and are controlled through
> > various registers. For instance, Qualcomm chipsets can reboot to a
> > "download mode" that allows a RAM dump to be collected. Another example
> > is they also support writing a cookie that can be read by bootloader
> > during next boot. PSCI offers a mechanism, SYSTEM_RESET2, for these
> > vendor reset types to be implemented without requiring drivers for every
> > register/cookie.
> > 
> > Add support in PSCI to statically map reboot mode commands from
> > userspace to a vendor reset and cookie value using the device tree.
> > 
> > A separate initcall is needed to parse the devicetree, instead of using
> > psci_dt_init because mm isn't sufficiently set up to allocate memory.
> > 
> > Reboot mode framework is close but doesn't quite fit with the
> > design and requirements for PSCI SYSTEM_RESET2. Some of these issues can
> > be solved but doesn't seem reasonable in sum:
> >  1. reboot mode registers against the reboot_notifier_list, which is too
> >     early to call SYSTEM_RESET2.
> 
> Please define "too early" (apologies if it has been explained before).
> 

My understanding is that reboot_notifier_list handlers shouldn't
actually be rebooting the system. I see it's generally used for one last
operation to put system into safer state. A few examples that are quick
to write based on what I see today: watchdogs disable themselves, PMUs
get torn down, xenbus tries to abort any requests. There are a couple
examples of drivers that *do* immediately reboot, but those seem to be
outlier. None of the reboot mode framework clients currently trigger
restart itself: they all set some cookies to give hint to firmware or
hardware what to do.

The restart_handler_list is documented to be a list of handlers that
should try to really restart the system. PSCI driver currently registers
against this.

> >     PSCI would need to remember the reset type from the reboot-mode
> >     framework callback and use it psci_sys_reset.
> >  2. reboot mode assumes only one cookie/parameter is described in the
> >     device tree. SYSTEM_RESET2 uses 2: one for the type and one for
> >     cookie.
> 
> That's surmountable I suppose.
> 
> >  3. psci cpuidle driver already registers a driver against the
> >     arm,psci-1.0 compatible. Refactoring would be needed to have both a
> >     cpuidle and reboot-mode driver.
> 
> We could put together a PSCI "parent" driver that creates child platform
> devices for idle and reboot drivers to match (which actually is not
> really pretty but it would make more sense than matching the idle
> driver only to the psci compatible string, which is what current code
> does).
> 
> > Tested-by: Florian Fainelli <florian.fainelli@broadcom.com>
> > Signed-off-by: Elliot Berman <quic_eberman@quicinc.com>
> > ---
> >  drivers/firmware/psci/psci.c | 92 ++++++++++++++++++++++++++++++++++++++++++++
> >  1 file changed, 92 insertions(+)
> > 
> > diff --git a/drivers/firmware/psci/psci.c b/drivers/firmware/psci/psci.c
> > index d9629ff87861..e672b33b71d1 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-"
> > +
> >  /*
> >   * 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.
> > @@ -79,6 +81,14 @@ struct psci_0_1_function_ids get_psci_0_1_function_ids(void)
> >  static u32 psci_cpu_suspend_feature;
> >  static bool psci_system_reset2_supported;
> >  
> > +struct psci_reset_param {
> > +	const char *mode;
> > +	u32 reset_type;
> > +	u32 cookie;
> > +};
> > +static struct psci_reset_param *psci_reset_params;
> > +static size_t num_psci_reset_params;
> > +
> >  static inline bool psci_has_ext_power_state(void)
> >  {
> >  	return psci_cpu_suspend_feature &
> > @@ -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)
> 
> 'action' is unused and therefore it is not really needed.
> 
> > +{
> > +	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);
> > +		}
> > +	}
> > +}
> > +
> >  static int psci_sys_reset(struct notifier_block *nb, unsigned long action,
> >  			  void *data)
> >  {
> > +	if (data && num_psci_reset_params)
> 
> So, reboot_mode here is basically ignored; if there is a vendor defined
> reset, we fire it off.
> 
> I think Mark mentioned his concerns earlier related to REBOOT_* mode and
> reset type (granted, the context was different):
> 
> https://lore.kernel.org/all/20200320120105.GA36658@C02TD0UTHF1T.local/
> 
> I would like to understand if this is the right thing to do before
> accepting this patchset.
> 

I don't have any concerns to move this part below checking reboot_mode.
Or, I could add reboot_mode == REBOOT_COLD check.

I'm not sure how best to define the behavior if user sets
reboot_mode = REBOOT_WARM and then user does "reboot bootloader". IMO,
"REBOOT_WARM" is at odds with the "bootloader" command. We can have one
take precedence over the other. I chose for the vendor resets to take
priority, since if userspace is providing specific command at reboot
time, that's probably what they want.

Let me know your thoughts and I'm happy to change the behavior around.


Thanks,
Elliot
Lorenzo Pieralisi Aug. 9, 2024, 1:30 p.m. UTC | #12
On Wed, Aug 07, 2024 at 11:10:50AM -0700, Elliot Berman wrote:

[...]

> > > +static void psci_vendor_sys_reset2(unsigned long action, void *data)
> > 
> > 'action' is unused and therefore it is not really needed.
> > 
> > > +{
> > > +	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);
> > > +		}
> > > +	}
> > > +}
> > > +
> > >  static int psci_sys_reset(struct notifier_block *nb, unsigned long action,
> > >  			  void *data)
> > >  {
> > > +	if (data && num_psci_reset_params)
> > 
> > So, reboot_mode here is basically ignored; if there is a vendor defined
> > reset, we fire it off.
> > 
> > I think Mark mentioned his concerns earlier related to REBOOT_* mode and
> > reset type (granted, the context was different):
> > 
> > https://lore.kernel.org/all/20200320120105.GA36658@C02TD0UTHF1T.local/
> > 
> > I would like to understand if this is the right thing to do before
> > accepting this patchset.
> > 
> 
> I don't have any concerns to move this part below checking reboot_mode.
> Or, I could add reboot_mode == REBOOT_COLD check.

The question is how can we map vendor specific reboot magic to Linux
reboot modes sensibly in generic PSCI code - that's by definition
vendor specific.

Thanks,
Lorenzo

> I'm not sure how best to define the behavior if user sets
> reboot_mode = REBOOT_WARM and then user does "reboot bootloader". IMO,
> "REBOOT_WARM" is at odds with the "bootloader" command. We can have one
> take precedence over the other. I chose for the vendor resets to take
> priority, since if userspace is providing specific command at reboot
> time, that's probably what they want.
> 
> Let me know your thoughts and I'm happy to change the behavior around.
> 
> 
> Thanks,
> Elliot
Elliot Berman Aug. 9, 2024, 4:58 p.m. UTC | #13
On Fri, Aug 09, 2024 at 03:30:38PM +0200, Lorenzo Pieralisi wrote:
> On Wed, Aug 07, 2024 at 11:10:50AM -0700, Elliot Berman wrote:
> 
> [...]
> 
> > > > +static void psci_vendor_sys_reset2(unsigned long action, void *data)
> > > 
> > > 'action' is unused and therefore it is not really needed.
> > > 
> > > > +{
> > > > +	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);
> > > > +		}
> > > > +	}
> > > > +}
> > > > +
> > > >  static int psci_sys_reset(struct notifier_block *nb, unsigned long action,
> > > >  			  void *data)
> > > >  {
> > > > +	if (data && num_psci_reset_params)
> > > 
> > > So, reboot_mode here is basically ignored; if there is a vendor defined
> > > reset, we fire it off.
> > > 
> > > I think Mark mentioned his concerns earlier related to REBOOT_* mode and
> > > reset type (granted, the context was different):
> > > 
> > > https://lore.kernel.org/all/20200320120105.GA36658@C02TD0UTHF1T.local/
> > > 
> > > I would like to understand if this is the right thing to do before
> > > accepting this patchset.
> > > 
> > 
> > I don't have any concerns to move this part below checking reboot_mode.
> > Or, I could add reboot_mode == REBOOT_COLD check.
> 
> The question is how can we map vendor specific reboot magic to Linux
> reboot modes sensibly in generic PSCI code - that's by definition
> vendor specific.
> 

I don't think it's a reasonable thing to do. "reboot bootloader" or
"reboot edl" don't make sense to the Linux reboot modes.

I believe the Linux reboot modes enum is oriented to perspective of
Linux itself and the vendor resets are oriented towards behavior of the
SoC.

Thanks,
Elliot
Shivendra Pratap Aug. 12, 2024, 6:16 p.m. UTC | #14
On 8/9/2024 10:28 PM, Elliot Berman wrote:
> On Fri, Aug 09, 2024 at 03:30:38PM +0200, Lorenzo Pieralisi wrote:
>> On Wed, Aug 07, 2024 at 11:10:50AM -0700, Elliot Berman wrote:
>>
>> [...]
>>
>>>>> +static void psci_vendor_sys_reset2(unsigned long action, void *data)
>>>>
>>>> 'action' is unused and therefore it is not really needed.
>>>>
>>>>> +{
>>>>> +	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);
>>>>> +		}
>>>>> +	}
>>>>> +}
>>>>> +
>>>>>  static int psci_sys_reset(struct notifier_block *nb, unsigned long action,
>>>>>  			  void *data)
>>>>>  {
>>>>> +	if (data && num_psci_reset_params)
>>>>
>>>> So, reboot_mode here is basically ignored; if there is a vendor defined
>>>> reset, we fire it off.
>>>>
>>>> I think Mark mentioned his concerns earlier related to REBOOT_* mode and
>>>> reset type (granted, the context was different):
>>>>
>>>> https://lore.kernel.org/all/20200320120105.GA36658@C02TD0UTHF1T.local/
>>>>
>>>> I would like to understand if this is the right thing to do before
>>>> accepting this patchset.
>>>>
>>>
>>> I don't have any concerns to move this part below checking reboot_mode.
>>> Or, I could add reboot_mode == REBOOT_COLD check.
>>
>> The question is how can we map vendor specific reboot magic to Linux
>> reboot modes sensibly in generic PSCI code - that's by definition
>> vendor specific.
>>
> 
> I don't think it's a reasonable thing to do. "reboot bootloader" or
> "reboot edl" don't make sense to the Linux reboot modes.
> 
> I believe the Linux reboot modes enum is oriented to perspective of
> Linux itself and the vendor resets are oriented towards behavior of the
> SoC.
> 
> Thanks,
> Elliot
> 

Agree.

from perspective of linux reboot modes, kernel's current implementation in reset path is like:
Lorenzo Pieralisi Aug. 15, 2024, 2:40 p.m. UTC | #15
On Mon, Aug 12, 2024 at 11:46:08PM +0530, Shivendra Pratap wrote:
> 
> 
> On 8/9/2024 10:28 PM, Elliot Berman wrote:
> > On Fri, Aug 09, 2024 at 03:30:38PM +0200, Lorenzo Pieralisi wrote:
> >> On Wed, Aug 07, 2024 at 11:10:50AM -0700, Elliot Berman wrote:
> >>
> >> [...]
> >>
> >>>>> +static void psci_vendor_sys_reset2(unsigned long action, void *data)
> >>>>
> >>>> 'action' is unused and therefore it is not really needed.
> >>>>
> >>>>> +{
> >>>>> +	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);
> >>>>> +		}
> >>>>> +	}
> >>>>> +}
> >>>>> +
> >>>>>  static int psci_sys_reset(struct notifier_block *nb, unsigned long action,
> >>>>>  			  void *data)
> >>>>>  {
> >>>>> +	if (data && num_psci_reset_params)
> >>>>
> >>>> So, reboot_mode here is basically ignored; if there is a vendor defined
> >>>> reset, we fire it off.
> >>>>
> >>>> I think Mark mentioned his concerns earlier related to REBOOT_* mode and
> >>>> reset type (granted, the context was different):
> >>>>
> >>>> https://lore.kernel.org/all/20200320120105.GA36658@C02TD0UTHF1T.local/
> >>>>
> >>>> I would like to understand if this is the right thing to do before
> >>>> accepting this patchset.
> >>>>
> >>>
> >>> I don't have any concerns to move this part below checking reboot_mode.
> >>> Or, I could add reboot_mode == REBOOT_COLD check.
> >>
> >> The question is how can we map vendor specific reboot magic to Linux
> >> reboot modes sensibly in generic PSCI code - that's by definition
> >> vendor specific.
> >>
> > 
> > I don't think it's a reasonable thing to do. "reboot bootloader" or
> > "reboot edl" don't make sense to the Linux reboot modes.
> > 
> > I believe the Linux reboot modes enum is oriented to perspective of
> > Linux itself and the vendor resets are oriented towards behavior of the
> > SoC.
> > 
> > Thanks,
> > Elliot
> > 
> 
> Agree.
> 
> from perspective of linux reboot modes, kernel's current implementation in reset path is like:
> __
> #1 If reboot_mode is WARM/SOFT and PSCI_SYSRESET2 is supported 
>     Call PSCI - SYSTEM_RESET2 - ARCH RESET
> #2 ELSE
>     Call PSCI - SYSTEM_RESET COLD RESET
> ___
> 
> ARM SPECS for PSCI SYSTEM_RESET2
> This function extends SYSTEM_RESET. It provides:
> • ARCH RESET: set Bit[31] to 0               = > This is already in place in condition #1.
> • vendor-specific resets: set Bit[31] to 1.  = > current patchset adds this part before kernel's reboot_mode reset at #0.
> 
> 
> In current patchset, we see a condition added at #0-psci_vendor_reset2 being called before kernel’s current reboot_mode condition and it can take any action only if all below conditions are satisfied.
> - PSCI SYSTEM_RESET2 is supported.
> - psci dt node defines an entry "bootloader" as a reboot-modes.
> - User issues reboot with a command say - (reboot bootloader).
> - If vendor reset fails, default reboot mode will execute as is.
> 
> Don't see if we will skip or break the kernel reboot_mode flow with this patch. 
> Also if user issues reboot <cmd> and <cmd> is supported on SOC vendor reset psci node, should cmd take precedence over kernel reboot mode enum? may be yes? 
> 

Please wrap lines when replying.

I don't think it is a matter of precedence. reboot_mode and the reboot
command passed to the reboot() syscall are there for different (?)
reasons.

What I am asking is whether it is always safe to execute a PSCI vendor
reset irrispective of the reboot_mode value.

Lorenzo
Elliot Berman Aug. 15, 2024, 6:05 p.m. UTC | #16
On Thu, Aug 15, 2024 at 04:40:55PM +0200, Lorenzo Pieralisi wrote:
> On Mon, Aug 12, 2024 at 11:46:08PM +0530, Shivendra Pratap wrote:
> > 
> > 
> > On 8/9/2024 10:28 PM, Elliot Berman wrote:
> > > On Fri, Aug 09, 2024 at 03:30:38PM +0200, Lorenzo Pieralisi wrote:
> > >> On Wed, Aug 07, 2024 at 11:10:50AM -0700, Elliot Berman wrote:
> > >>
> > >> [...]
> > >>
> > >>>>> +static void psci_vendor_sys_reset2(unsigned long action, void *data)
> > >>>>
> > >>>> 'action' is unused and therefore it is not really needed.
> > >>>>
> > >>>>> +{
> > >>>>> +	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);
> > >>>>> +		}
> > >>>>> +	}
> > >>>>> +}
> > >>>>> +
> > >>>>>  static int psci_sys_reset(struct notifier_block *nb, unsigned long action,
> > >>>>>  			  void *data)
> > >>>>>  {
> > >>>>> +	if (data && num_psci_reset_params)
> > >>>>
> > >>>> So, reboot_mode here is basically ignored; if there is a vendor defined
> > >>>> reset, we fire it off.
> > >>>>
> > >>>> I think Mark mentioned his concerns earlier related to REBOOT_* mode and
> > >>>> reset type (granted, the context was different):
> > >>>>
> > >>>> https://lore.kernel.org/all/20200320120105.GA36658@C02TD0UTHF1T.local/
> > >>>>
> > >>>> I would like to understand if this is the right thing to do before
> > >>>> accepting this patchset.
> > >>>>
> > >>>
> > >>> I don't have any concerns to move this part below checking reboot_mode.
> > >>> Or, I could add reboot_mode == REBOOT_COLD check.
> > >>
> > >> The question is how can we map vendor specific reboot magic to Linux
> > >> reboot modes sensibly in generic PSCI code - that's by definition
> > >> vendor specific.
> > >>
> > > 
> > > I don't think it's a reasonable thing to do. "reboot bootloader" or
> > > "reboot edl" don't make sense to the Linux reboot modes.
> > > 
> > > I believe the Linux reboot modes enum is oriented to perspective of
> > > Linux itself and the vendor resets are oriented towards behavior of the
> > > SoC.
> > > 
> > > Thanks,
> > > Elliot
> > > 
> > 
> > Agree.
> > 
> > from perspective of linux reboot modes, kernel's current
> > implementation in reset path is like:
> >
> > __
> > #1 If reboot_mode is WARM/SOFT and PSCI_SYSRESET2 is supported 
> >     Call PSCI - SYSTEM_RESET2 - ARCH RESET
> > #2 ELSE
> >     Call PSCI - SYSTEM_RESET COLD RESET
> > ___
> > 
> > ARM SPECS for PSCI SYSTEM_RESET2
> > This function extends SYSTEM_RESET. It provides:
> > • ARCH RESET: set Bit[31] to 0               = > This is already in place in condition #1.
> > • vendor-specific resets: set Bit[31] to 1.  = > current patchset adds this part before kernel's reboot_mode reset at #0.
> > 
> > 
> > In current patchset, we see a condition added at
> > #0-psci_vendor_reset2 being called before kernel’s current
> > reboot_mode condition and it can take any action only if all below
> > conditions are satisfied.
> > - PSCI SYSTEM_RESET2 is supported.
> > - psci dt node defines an entry "bootloader" as a reboot-modes.
> > - User issues reboot with a command say - (reboot bootloader).
> > - If vendor reset fails, default reboot mode will execute as is.
> > 
> > Don't see if we will skip or break the kernel reboot_mode flow with
> > this patch.  Also if user issues reboot <cmd> and <cmd> is supported
> > on SOC vendor reset psci node, should cmd take precedence over
> > kernel reboot mode enum? may be yes? 
> > 
> 
> Please wrap lines when replying.
> 
> I don't think it is a matter of precedence. reboot_mode and the reboot
> command passed to the reboot() syscall are there for different (?)
> reasons.
> 
> What I am asking is whether it is always safe to execute a PSCI vendor
> reset irrispective of the reboot_mode value.

The only way I see it to be unsafe is we need some other driver using
the reboot_mode to configure something and then the PSCI vendor reset
being incompatible with whatever that other driver did. I don't see that
happens today, so it is up to us to decide what the policy ought to be.
The PSCI spec doesn't help us here because the reboot_mode enum is
totally a Linux construct. In my opinion, firmware should be able to
deal with whatever the driver did or (less ideal) the driver need to be
aware of the PSCI vendor resets. Thus, it would be always safe to
execute a PSCI vendor reset regardless of the reboot_mode value.

Thanks,
Elliot
Shivendra Pratap Aug. 16, 2024, 6:21 p.m. UTC | #17
On 8/15/2024 11:35 PM, Elliot Berman wrote:
> On Thu, Aug 15, 2024 at 04:40:55PM +0200, Lorenzo Pieralisi wrote:
>> On Mon, Aug 12, 2024 at 11:46:08PM +0530, Shivendra Pratap wrote:
>>>
>>>
>>> On 8/9/2024 10:28 PM, Elliot Berman wrote:
>>>> On Fri, Aug 09, 2024 at 03:30:38PM +0200, Lorenzo Pieralisi wrote:
>>>>> On Wed, Aug 07, 2024 at 11:10:50AM -0700, Elliot Berman wrote:
>>>>>
>>>>> [...]
>>>>>
>>>>>>>> +static void psci_vendor_sys_reset2(unsigned long action, void *data)
>>>>>>>
>>>>>>> 'action' is unused and therefore it is not really needed.
>>>>>>>
>>>>>>>> +{
>>>>>>>> +	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);
>>>>>>>> +		}
>>>>>>>> +	}
>>>>>>>> +}
>>>>>>>> +
>>>>>>>>  static int psci_sys_reset(struct notifier_block *nb, unsigned long action,
>>>>>>>>  			  void *data)
>>>>>>>>  {
>>>>>>>> +	if (data && num_psci_reset_params)
>>>>>>>
>>>>>>> So, reboot_mode here is basically ignored; if there is a vendor defined
>>>>>>> reset, we fire it off.
>>>>>>>
>>>>>>> I think Mark mentioned his concerns earlier related to REBOOT_* mode and
>>>>>>> reset type (granted, the context was different):
>>>>>>>
>>>>>>> https://lore.kernel.org/all/20200320120105.GA36658@C02TD0UTHF1T.local/
>>>>>>>
>>>>>>> I would like to understand if this is the right thing to do before
>>>>>>> accepting this patchset.
>>>>>>>
>>>>>>
>>>>>> I don't have any concerns to move this part below checking reboot_mode.
>>>>>> Or, I could add reboot_mode == REBOOT_COLD check.
>>>>>
>>>>> The question is how can we map vendor specific reboot magic to Linux
>>>>> reboot modes sensibly in generic PSCI code - that's by definition
>>>>> vendor specific.
>>>>>
>>>>
>>>> I don't think it's a reasonable thing to do. "reboot bootloader" or
>>>> "reboot edl" don't make sense to the Linux reboot modes.
>>>>
>>>> I believe the Linux reboot modes enum is oriented to perspective of
>>>> Linux itself and the vendor resets are oriented towards behavior of the
>>>> SoC.
>>>>
>>>> Thanks,
>>>> Elliot
>>>>
>>>
>>> Agree.
>>>
>>> from perspective of linux reboot modes, kernel's current
>>> implementation in reset path is like:
>>>
>>> __
>>> #1 If reboot_mode is WARM/SOFT and PSCI_SYSRESET2 is supported 
>>>     Call PSCI - SYSTEM_RESET2 - ARCH RESET
>>> #2 ELSE
>>>     Call PSCI - SYSTEM_RESET COLD RESET
>>> ___
>>>
>>> ARM SPECS for PSCI SYSTEM_RESET2
>>> This function extends SYSTEM_RESET. It provides:
>>> • ARCH RESET: set Bit[31] to 0               = > This is already in place in condition #1.
>>> • vendor-specific resets: set Bit[31] to 1.  = > current patchset adds this part before kernel's reboot_mode reset at #0.
>>>
>>>
>>> In current patchset, we see a condition added at
>>> #0-psci_vendor_reset2 being called before kernel’s current
>>> reboot_mode condition and it can take any action only if all below
>>> conditions are satisfied.
>>> - PSCI SYSTEM_RESET2 is supported.
>>> - psci dt node defines an entry "bootloader" as a reboot-modes.
>>> - User issues reboot with a command say - (reboot bootloader).
>>> - If vendor reset fails, default reboot mode will execute as is.
>>>
>>> Don't see if we will skip or break the kernel reboot_mode flow with
>>> this patch.  Also if user issues reboot <cmd> and <cmd> is supported
>>> on SOC vendor reset psci node, should cmd take precedence over
>>> kernel reboot mode enum? may be yes? 
>>>
>>
>> Please wrap lines when replying.
sure. will try to take care.
>>
>> I don't think it is a matter of precedence. reboot_mode and the reboot
>> command passed to the reboot() syscall are there for different (?)
>> reasons.
>>
>> What I am asking is whether it is always safe to execute a PSCI vendor
>> reset irrispective of the reboot_mode value.
Valid point, but it depends on how we configure reboot mode and vendor reset.
If the configuration is conflicting in DT, then reboot_mode and vendor reset
may conflict and show non-predictable results.
For instance, on qcs6490, we have have nvmem-reboot-mode driver
which supports "reboot mode bootloader" function via its current DT as the PMIC
registers are accessible for write on this soc. If we enable nvmem-reboot-mode
and then configure vendor_reset2(mode-bootloader) to perform a different
function on reboot, they will conflict and may result in a non-predictable
behavior. The developer or soc vendor has to take care of this in any
case so this may be a invalid scenario?

May be vendor_reset2 gives more flexibility here on how a soc vendor may 
implement reboot modes and other vendor reset types. In case soc vendor
wants to keep some reboot mode register as open access, they can still
use reboot_mode driver and then others reboot/reset modes can be configured
via vendor_reset2.

For instance, on qcs6490, we can use nvmem-reboot-mode driver for 
"reboot mode bootloader" and use the current patch-vendor_reset2 for
"reboot mode edl". This can be configured via DT. Now even if we
enable both current-patch-vendor_reset2(reboot mode bootloader) 
and nvmem-reboot-mode (mode-bootloader) at same time on this soc,
they are harmless to each other and work as desired as both(DT entries)
align with each other and the PMIC registers are accessible to kernel. The
same thing can conflict, if we enable both drivers at same time and configure
them with conflicting parameters in DT for (reboot mode bootloader).

> 
> The only way I see it to be unsafe is we need some other driver using
> the reboot_mode to configure something and then the PSCI vendor reset
> being incompatible with whatever that other driver did. I don't see that
> happens today, so it is up to us to decide what the policy ought to be.
> The PSCI spec doesn't help us here because the reboot_mode enum is
> totally a Linux construct. In my opinion, firmware should be able to
> deal with whatever the driver did or (less ideal) the driver need to be
> aware of the PSCI vendor resets. Thus, it would be always safe to
> execute a PSCI vendor reset regardless of the reboot_mode value.
> 
> Thanks,
> Elliot
>
diff mbox series

Patch

diff --git a/drivers/firmware/psci/psci.c b/drivers/firmware/psci/psci.c
index d9629ff87861..e672b33b71d1 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-"
+
 /*
  * 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.
@@ -79,6 +81,14 @@  struct psci_0_1_function_ids get_psci_0_1_function_ids(void)
 static u32 psci_cpu_suspend_feature;
 static bool psci_system_reset2_supported;
 
+struct psci_reset_param {
+	const char *mode;
+	u32 reset_type;
+	u32 cookie;
+};
+static struct psci_reset_param *psci_reset_params;
+static size_t num_psci_reset_params;
+
 static inline bool psci_has_ext_power_state(void)
 {
 	return psci_cpu_suspend_feature &
@@ -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);
+		}
+	}
+}
+
 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) {
 		/*
@@ -748,6 +778,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]));
+		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);
+		if (num < 0) {
+			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;
+		param++;
+		num_psci_reset_params++;
+	}
+
+	return 0;
+}
+arch_initcall(psci_init_system_reset2_modes);
+
 int __init psci_dt_init(void)
 {
 	struct device_node *np;