2024-05-15 23:10:58

by Elliot Berman

[permalink] [raw]
Subject: [PATCH v3 0/4] Implement vendor resets for PSCI SYSTEM_RESET2

The PSCI SYSTEM_RESET2 call allows vendor firmware to define additional
reset types which could be mapped to the reboot argument.

Setting up reboot on Qualcomm devices can be inconsistent from chipset
to chipset. Generally, there is a PMIC register that gets written to
decide the reboot type. There is also sometimes a cookie that can be
written to indicate that the bootloader should behave differently than a
regular boot. These knobs evolve over product generations and require
more drivers. Qualcomm firmwares are beginning to expose vendor
SYSTEM_RESET2 types to simplify driver requirements from Linux.

Add support in PSCI to statically wire reboot mode commands from
userspace to a vendor reset and cookie value using the device tree. The
DT bindings are similar to reboot mode framework except that 2
integers are accepted (the type and cookie). Also, reboot mode framework
is intended to program the cookies, but not actually reboot the host.
PSCI SYSTEM_RESET2 does both. I've not added support for reading ACPI
tables since I don't have any device which provides them + firmware that
supports vendor SYSTEM_RESET2 types.

Previous discussions around SYSTEM_RESET2:
- https://lore.kernel.org/lkml/[email protected]/T/
- https://lore.kernel.org/all/[email protected]/

Signed-off-by: Elliot Berman <[email protected]>
---
Changes in v3:
- Limit outer number of items to 1 for mode-* properties
- Move the reboot-mode for psci under a subnode "reset-types"
- Fix the DT node in qcm6490-idp so it doesn't overwrite the one from
sc7820.dtsi
- Link to v2: https://lore.kernel.org/r/20240414-arm-psci-system_reset2-vendor-reboots-v2-0-da9a055a648f@quicinc.com

Changes in v2:
- Fixes to schema as suggested by Rob and Krzysztof
- Add qcm6490 idp as first Qualcomm device to support
- Link to v1: https://lore.kernel.org/r/20231117-arm-psci-system_reset2-vendor-reboots-v1-0-03c4612153e2@quicinc.com

Changes in v1:
- Reference reboot-mode bindings as suggeted by Rob.
- Link to RFC: https://lore.kernel.org/r/20231030-arm-psci-system_reset2-vendor-reboots-v1-0-dcdd63352ad1@quicinc.com

---
Elliot Berman (4):
dt-bindings: power: reset: Convert mode-.* properties to array
dt-bindings: arm: Document reboot mode magic
firmware: psci: Read and use vendor reset types
arm64: dts: qcom: Add PSCI SYSTEM_RESET2 types for qcm6490-idp

Documentation/devicetree/bindings/arm/psci.yaml | 43 +++++++++-
.../bindings/power/reset/nvmem-reboot-mode.yaml | 4 +
.../devicetree/bindings/power/reset/qcom,pon.yaml | 4 +
.../bindings/power/reset/reboot-mode.yaml | 14 +++-
.../bindings/power/reset/syscon-reboot-mode.yaml | 4 +
arch/arm64/boot/dts/qcom/qcm6490-idp.dts | 7 ++
arch/arm64/boot/dts/qcom/sc7280.dtsi | 2 +-
drivers/firmware/psci/psci.c | 92 ++++++++++++++++++++++
8 files changed, 165 insertions(+), 5 deletions(-)
---
base-commit: b5d2afe8745bf3eef5a59a13313798d24f2af983
change-id: 20231016-arm-psci-system_reset2-vendor-reboots-cc3ad456c070

Best regards,
--
Elliot Berman <[email protected]>



2024-05-15 23:10:59

by Elliot Berman

[permalink] [raw]
Subject: [PATCH v3 3/4] firmware: psci: Read and use vendor reset types

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.

Signed-off-by: Elliot Berman <[email protected]>
---
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)
+{
+ 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;

--
2.34.1


2024-05-15 23:11:30

by Elliot Berman

[permalink] [raw]
Subject: [PATCH v3 2/4] dt-bindings: arm: Document reboot mode magic

Add bindings to describe vendor-specific reboot modes. Values here
correspond to valid parameters to vendor-specific reset types in PSCI
SYSTEM_RESET2 call.

Signed-off-by: Elliot Berman <[email protected]>
---
Documentation/devicetree/bindings/arm/psci.yaml | 43 +++++++++++++++++++++++--
1 file changed, 41 insertions(+), 2 deletions(-)

diff --git a/Documentation/devicetree/bindings/arm/psci.yaml b/Documentation/devicetree/bindings/arm/psci.yaml
index cbb012e217ab..47b5bbe540ce 100644
--- a/Documentation/devicetree/bindings/arm/psci.yaml
+++ b/Documentation/devicetree/bindings/arm/psci.yaml
@@ -137,8 +137,34 @@ allOf:
required:
- cpu_off
- cpu_on
-
-additionalProperties: false
+ - if:
+ properties:
+ compatible:
+ contains:
+ const: arm,psci-1.0
+ then:
+ properties:
+ reset-types:
+ type: object
+ $ref: /schemas/power/reset/reboot-mode.yaml#
+ properties:
+ # "mode-normal" is just SYSTEM_RESET
+ mode-normal: false
+ patternProperties:
+ "^mode-.*$":
+ items:
+ maxItems: 2
+ description: |
+ Describes a vendor-specific reset type. The string after "mode-"
+ maps a reboot mode to the parameters in the PSCI SYSTEM_RESET2 call.
+
+ Parameters are named mode-xxx = <type[, cookie]>, where xxx
+ is the name of the magic reboot mode, type is the lower 31 bits
+ of the reset_type, and, optionally, the cookie value. If the cookie
+ is not provided, it is defaulted to zero.
+ The 31st bit (vendor-resets) will be implicitly set by the driver.
+
+unevaluatedProperties: false

examples:
- |+
@@ -261,4 +287,17 @@ examples:
domain-idle-states = <&CLUSTER_RET>, <&CLUSTER_PWRDN>;
};
};
+
+ - |+
+
+ // Case 5: SYSTEM_RESET2 vendor resets
+ psci {
+ compatible = "arm,psci-1.0";
+ method = "smc";
+
+ reset-types {
+ mode-edl = <0>;
+ mode-bootloader = <1 2>;
+ };
+ };
...

--
2.34.1


2024-05-15 23:11:46

by Elliot Berman

[permalink] [raw]
Subject: [PATCH v3 4/4] arm64: dts: qcom: Add PSCI SYSTEM_RESET2 types for qcm6490-idp

Add nodes for the vendor-defined system resets. "bootloader" will cause
device to reboot and stop in the bootloader's fastboot mode. "edl" will
cause device to reboot into "emergency download mode", which permits
loading images via the Firehose protocol.

Co-developed-by: Shivendra Pratap <[email protected]>
Signed-off-by: Shivendra Pratap <[email protected]>
Signed-off-by: Elliot Berman <[email protected]>
---
arch/arm64/boot/dts/qcom/qcm6490-idp.dts | 7 +++++++
arch/arm64/boot/dts/qcom/sc7280.dtsi | 2 +-
2 files changed, 8 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/boot/dts/qcom/qcm6490-idp.dts b/arch/arm64/boot/dts/qcom/qcm6490-idp.dts
index e4bfad50a669..fd0a7dd14483 100644
--- a/arch/arm64/boot/dts/qcom/qcm6490-idp.dts
+++ b/arch/arm64/boot/dts/qcom/qcm6490-idp.dts
@@ -448,6 +448,13 @@ led@3 {
};
};

+&psci {
+ reset-types {
+ mode-bootloader = <0x10001 0x2>;
+ mode-edl = <0 0x1>;
+ };
+};
+
&qupv3_id_0 {
status = "okay";
};
diff --git a/arch/arm64/boot/dts/qcom/sc7280.dtsi b/arch/arm64/boot/dts/qcom/sc7280.dtsi
index 7e7f0f0fb41b..da25a3089419 100644
--- a/arch/arm64/boot/dts/qcom/sc7280.dtsi
+++ b/arch/arm64/boot/dts/qcom/sc7280.dtsi
@@ -848,7 +848,7 @@ pmu {
interrupts = <GIC_PPI 7 IRQ_TYPE_LEVEL_LOW>;
};

- psci {
+ psci: psci {
compatible = "arm,psci-1.0";
method = "smc";


--
2.34.1


2024-05-20 19:44:59

by Rob Herring (Arm)

[permalink] [raw]
Subject: Re: [PATCH v3 2/4] dt-bindings: arm: Document reboot mode magic

On Wed, May 15, 2024 at 04:09:45PM -0700, Elliot Berman wrote:
> Add bindings to describe vendor-specific reboot modes. Values here
> correspond to valid parameters to vendor-specific reset types in PSCI
> SYSTEM_RESET2 call.
>
> Signed-off-by: Elliot Berman <[email protected]>
> ---
> Documentation/devicetree/bindings/arm/psci.yaml | 43 +++++++++++++++++++++++--
> 1 file changed, 41 insertions(+), 2 deletions(-)
>
> diff --git a/Documentation/devicetree/bindings/arm/psci.yaml b/Documentation/devicetree/bindings/arm/psci.yaml
> index cbb012e217ab..47b5bbe540ce 100644
> --- a/Documentation/devicetree/bindings/arm/psci.yaml
> +++ b/Documentation/devicetree/bindings/arm/psci.yaml
> @@ -137,8 +137,34 @@ allOf:
> required:
> - cpu_off
> - cpu_on
> -
> -additionalProperties: false
> + - if:
> + properties:
> + compatible:
> + contains:
> + const: arm,psci-1.0
> + then:
> + properties:
> + reset-types:

The normal structure is declare all properties and nodes at the top
level (outside of if/then schemas) and then add restrictions with
if/then schemas.

> + type: object
> + $ref: /schemas/power/reset/reboot-mode.yaml#

additionalProperties: false

and a blank line

> + properties:
> + # "mode-normal" is just SYSTEM_RESET
> + mode-normal: false
> + patternProperties:
> + "^mode-.*$":
> + items:
> + maxItems: 2
> + description: |
> + Describes a vendor-specific reset type. The string after "mode-"
> + maps a reboot mode to the parameters in the PSCI SYSTEM_RESET2 call.
> +
> + Parameters are named mode-xxx = <type[, cookie]>, where xxx
> + is the name of the magic reboot mode, type is the lower 31 bits
> + of the reset_type, and, optionally, the cookie value. If the cookie
> + is not provided, it is defaulted to zero.
> + The 31st bit (vendor-resets) will be implicitly set by the driver.
> +
> +unevaluatedProperties: false
>
> examples:
> - |+
> @@ -261,4 +287,17 @@ examples:
> domain-idle-states = <&CLUSTER_RET>, <&CLUSTER_PWRDN>;
> };
> };
> +
> + - |+
> +
> + // Case 5: SYSTEM_RESET2 vendor resets
> + psci {
> + compatible = "arm,psci-1.0";
> + method = "smc";
> +
> + reset-types {
> + mode-edl = <0>;
> + mode-bootloader = <1 2>;
> + };
> + };
> ...
>
> --
> 2.34.1
>

2024-05-21 19:06:39

by Florian Fainelli

[permalink] [raw]
Subject: Re: [PATCH v3 3/4] firmware: psci: Read and use vendor reset types

On 5/15/24 16:09, 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.
>
> Signed-off-by: Elliot Berman <[email protected]>

Tested-by: Florian Fainelli <[email protected]>

Thanks!
--
Florian


Attachments:
smime.p7s (4.12 kB)
S/MIME Cryptographic Signature