* [PATCH 1/4] firmware: xilinx: Add support to clear TF-A PM state
2026-07-23 12:48 [PATCH 0/4] firmware: xilinx: Clean up firmware and TF-A state on kexec Jay Buddhabhatti
@ 2026-07-23 12:48 ` Jay Buddhabhatti
2026-07-23 16:25 ` Pandey, Radhey Shyam
2026-07-23 12:48 ` [PATCH 2/4] firmware: xilinx: Release all peripheral devices from firmware Jay Buddhabhatti
` (2 subsequent siblings)
3 siblings, 1 reply; 9+ messages in thread
From: Jay Buddhabhatti @ 2026-07-23 12:48 UTC (permalink / raw)
To: michal.simek, git; +Cc: linux-arm-kernel, linux-kernel, Jay Buddhabhatti
Currently, during a kexec restart, only the kernel is reloaded, while the
TF-A specific data remain unchanged. This leads to a mismatch between the
kernel state and the TF-A firmware state like SGI number and shutdown
scope variable.
For example, the kernel registers an SGI number with TF-A so that TF-A can
notify the kernel of events via that SGI. TF-A stores this SGI number in
its internal state. After a kexec, the newly loaded kernel re-registers
and may request a different SGI number, but the stale value programmed in
TF-A remains, so event notifications are delivered on the old SGI and are
missed by the new kernel. The shutdown scope variable has a similar stale
state problem.
To resolve this, the TF_A_CLEAR_PM_STATE PM API is introduced to clear
TF-A-specific state during kexec. On a graceful reboot, this API is
triggered by zynqmp_firmware_shutdown(), while in a crash kernel scenario,
it is invoked by zynqmp_firmware_probe() in the reloaded kernel.
Signed-off-by: Jay Buddhabhatti <jay.buddhabhatti@amd.com>
---
drivers/firmware/xilinx/zynqmp.c | 48 +++++++++++++++++++++++++++-
include/linux/firmware/xlnx-zynqmp.h | 3 +-
2 files changed, 49 insertions(+), 2 deletions(-)
diff --git a/drivers/firmware/xilinx/zynqmp.c b/drivers/firmware/xilinx/zynqmp.c
index af838b2dc327..95ffd8f33ce9 100644
--- a/drivers/firmware/xilinx/zynqmp.c
+++ b/drivers/firmware/xilinx/zynqmp.c
@@ -3,7 +3,7 @@
* Xilinx Zynq MPSoC Firmware layer
*
* Copyright (C) 2014-2022 Xilinx, Inc.
- * Copyright (C) 2022 - 2025 Advanced Micro Devices, Inc.
+ * Copyright (C) 2022 - 2026 Advanced Micro Devices, Inc.
*
* Michal Simek <michal.simek@amd.com>
* Davorin Mista <davorin.mista@aggios.com>
@@ -13,6 +13,7 @@
#include <linux/arm-smccc.h>
#include <linux/compiler.h>
+#include <linux/crash_dump.h>
#include <linux/device.h>
#include <linux/init.h>
#include <linux/mfd/core.h>
@@ -2065,6 +2066,42 @@ static struct attribute *zynqmp_firmware_attrs[] = {
ATTRIBUTE_GROUPS(zynqmp_firmware);
+/**
+ * zynqmp_clear_pm_state() - Clear subsystem state
+ * @dev: Device pointer used for logging
+ *
+ * Clears PM specific data in TF-A.
+ *
+ * Return: Returns status, either success or error
+ */
+static int zynqmp_clear_pm_state(struct device *dev)
+{
+ u32 pm_family_code;
+ int ret;
+
+ /* Get the Family code of platform */
+ ret = zynqmp_pm_get_family_info(&pm_family_code);
+ if (ret < 0)
+ return ret;
+
+ if (pm_family_code != PM_ZYNQMP_FAMILY_CODE) {
+ /* Check if the TF-A supports the TF_A_CLEAR_PM_STATE */
+ ret = do_feature_check_call(TF_A_CLEAR_PM_STATE);
+ if (ret >= 0 && ((ret & FIRMWARE_VERSION_MASK) >= PM_API_VERSION_1)) {
+ /* Clear PM specific data in TF-A */
+ ret = zynqmp_pm_invoke_fn(TF_A_CLEAR_PM_STATE, NULL, 0);
+ if (ret)
+ dev_err(dev,
+ "Failed to clear TF-A specific subsystem state: %d\n", ret);
+ } else {
+ dev_warn(dev, "TF_A_CLEAR_PM_STATE is not supported in TF-A: %d\n", ret);
+ ret = 0;
+ }
+ }
+
+ return ret;
+}
+
static int zynqmp_firmware_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@@ -2118,6 +2155,9 @@ static int zynqmp_firmware_probe(struct platform_device *pdev)
if (ret < 0)
return ret;
+ if (is_kdump_kernel())
+ zynqmp_clear_pm_state(dev);
+
/* Check trustzone version number */
ret = zynqmp_pm_get_trustzone_version(&pm_tz_version);
if (ret)
@@ -2151,6 +2191,11 @@ static int zynqmp_firmware_probe(struct platform_device *pdev)
return of_platform_populate(dev->of_node, NULL, NULL, dev);
}
+static void zynqmp_firmware_shutdown(struct platform_device *pdev)
+{
+ zynqmp_clear_pm_state(&pdev->dev);
+}
+
static void zynqmp_firmware_remove(struct platform_device *pdev)
{
struct pm_api_feature_data *feature_data;
@@ -2210,5 +2255,6 @@ static struct platform_driver zynqmp_firmware_driver = {
},
.probe = zynqmp_firmware_probe,
.remove = zynqmp_firmware_remove,
+ .shutdown = zynqmp_firmware_shutdown,
};
module_platform_driver(zynqmp_firmware_driver);
diff --git a/include/linux/firmware/xlnx-zynqmp.h b/include/linux/firmware/xlnx-zynqmp.h
index 7e27b0f7bf7e..baaa88b0b197 100644
--- a/include/linux/firmware/xlnx-zynqmp.h
+++ b/include/linux/firmware/xlnx-zynqmp.h
@@ -3,7 +3,7 @@
* Xilinx Zynq MPSoC Firmware layer
*
* Copyright (C) 2014-2021 Xilinx
- * Copyright (C) 2022 - 2025 Advanced Micro Devices, Inc.
+ * Copyright (C) 2022 - 2026 Advanced Micro Devices, Inc.
*
* Michal Simek <michal.simek@amd.com>
* Davorin Mista <davorin.mista@aggios.com>
@@ -66,6 +66,7 @@
#define FIRMWARE_VERSION_MASK 0xFFFFU
/* ATF only commands */
+#define TF_A_CLEAR_PM_STATE 0xa05
#define TF_A_PM_REGISTER_SGI 0xa04
#define PM_GET_TRUSTZONE_VERSION 0xa03
#define PM_SET_SUSPEND_MODE 0xa02
--
2.34.1
^ permalink raw reply related [flat|nested] 9+ messages in thread* Re: [PATCH 1/4] firmware: xilinx: Add support to clear TF-A PM state
2026-07-23 12:48 ` [PATCH 1/4] firmware: xilinx: Add support to clear TF-A PM state Jay Buddhabhatti
@ 2026-07-23 16:25 ` Pandey, Radhey Shyam
0 siblings, 0 replies; 9+ messages in thread
From: Pandey, Radhey Shyam @ 2026-07-23 16:25 UTC (permalink / raw)
To: Jay Buddhabhatti, michal.simek, git; +Cc: linux-arm-kernel, linux-kernel
On 7/23/2026 6:18 PM, Jay Buddhabhatti wrote:
> Currently, during a kexec restart, only the kernel is reloaded, while the
> TF-A specific data remain unchanged. This leads to a mismatch between the
> kernel state and the TF-A firmware state like SGI number and shutdown
> scope variable.
>
> For example, the kernel registers an SGI number with TF-A so that TF-A can
> notify the kernel of events via that SGI. TF-A stores this SGI number in
> its internal state. After a kexec, the newly loaded kernel re-registers
> and may request a different SGI number, but the stale value programmed in
> TF-A remains, so event notifications are delivered on the old SGI and are
> missed by the new kernel. The shutdown scope variable has a similar stale
> state problem.
>
> To resolve this, the TF_A_CLEAR_PM_STATE PM API is introduced to clear
> TF-A-specific state during kexec. On a graceful reboot, this API is
> triggered by zynqmp_firmware_shutdown(), while in a crash kernel scenario,
> it is invoked by zynqmp_firmware_probe() in the reloaded kernel.
>
> Signed-off-by: Jay Buddhabhatti <jay.buddhabhatti@amd.com>
Reviewed-by: Radhey Shyam Pandey <radhey.shyam.pandey@amd.com>
Thanks!
> ---
> drivers/firmware/xilinx/zynqmp.c | 48 +++++++++++++++++++++++++++-
> include/linux/firmware/xlnx-zynqmp.h | 3 +-
> 2 files changed, 49 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/firmware/xilinx/zynqmp.c b/drivers/firmware/xilinx/zynqmp.c
> index af838b2dc327..95ffd8f33ce9 100644
> --- a/drivers/firmware/xilinx/zynqmp.c
> +++ b/drivers/firmware/xilinx/zynqmp.c
> @@ -3,7 +3,7 @@
> * Xilinx Zynq MPSoC Firmware layer
> *
> * Copyright (C) 2014-2022 Xilinx, Inc.
> - * Copyright (C) 2022 - 2025 Advanced Micro Devices, Inc.
> + * Copyright (C) 2022 - 2026 Advanced Micro Devices, Inc.
> *
> * Michal Simek <michal.simek@amd.com>
> * Davorin Mista <davorin.mista@aggios.com>
> @@ -13,6 +13,7 @@
>
> #include <linux/arm-smccc.h>
> #include <linux/compiler.h>
> +#include <linux/crash_dump.h>
> #include <linux/device.h>
> #include <linux/init.h>
> #include <linux/mfd/core.h>
> @@ -2065,6 +2066,42 @@ static struct attribute *zynqmp_firmware_attrs[] = {
>
> ATTRIBUTE_GROUPS(zynqmp_firmware);
>
> +/**
> + * zynqmp_clear_pm_state() - Clear subsystem state
> + * @dev: Device pointer used for logging
> + *
> + * Clears PM specific data in TF-A.
> + *
> + * Return: Returns status, either success or error
> + */
> +static int zynqmp_clear_pm_state(struct device *dev)
> +{
> + u32 pm_family_code;
> + int ret;
> +
> + /* Get the Family code of platform */
> + ret = zynqmp_pm_get_family_info(&pm_family_code);
> + if (ret < 0)
> + return ret;
> +
> + if (pm_family_code != PM_ZYNQMP_FAMILY_CODE) {
> + /* Check if the TF-A supports the TF_A_CLEAR_PM_STATE */
> + ret = do_feature_check_call(TF_A_CLEAR_PM_STATE);
> + if (ret >= 0 && ((ret & FIRMWARE_VERSION_MASK) >= PM_API_VERSION_1)) {
> + /* Clear PM specific data in TF-A */
> + ret = zynqmp_pm_invoke_fn(TF_A_CLEAR_PM_STATE, NULL, 0);
> + if (ret)
> + dev_err(dev,
> + "Failed to clear TF-A specific subsystem state: %d\n", ret);
> + } else {
> + dev_warn(dev, "TF_A_CLEAR_PM_STATE is not supported in TF-A: %d\n", ret);
> + ret = 0;
> + }
> + }
> +
> + return ret;
> +}
> +
> static int zynqmp_firmware_probe(struct platform_device *pdev)
> {
> struct device *dev = &pdev->dev;
> @@ -2118,6 +2155,9 @@ static int zynqmp_firmware_probe(struct platform_device *pdev)
> if (ret < 0)
> return ret;
>
> + if (is_kdump_kernel())
> + zynqmp_clear_pm_state(dev);
> +
> /* Check trustzone version number */
> ret = zynqmp_pm_get_trustzone_version(&pm_tz_version);
> if (ret)
> @@ -2151,6 +2191,11 @@ static int zynqmp_firmware_probe(struct platform_device *pdev)
> return of_platform_populate(dev->of_node, NULL, NULL, dev);
> }
>
> +static void zynqmp_firmware_shutdown(struct platform_device *pdev)
> +{
> + zynqmp_clear_pm_state(&pdev->dev);
> +}
> +
> static void zynqmp_firmware_remove(struct platform_device *pdev)
> {
> struct pm_api_feature_data *feature_data;
> @@ -2210,5 +2255,6 @@ static struct platform_driver zynqmp_firmware_driver = {
> },
> .probe = zynqmp_firmware_probe,
> .remove = zynqmp_firmware_remove,
> + .shutdown = zynqmp_firmware_shutdown,
> };
> module_platform_driver(zynqmp_firmware_driver);
> diff --git a/include/linux/firmware/xlnx-zynqmp.h b/include/linux/firmware/xlnx-zynqmp.h
> index 7e27b0f7bf7e..baaa88b0b197 100644
> --- a/include/linux/firmware/xlnx-zynqmp.h
> +++ b/include/linux/firmware/xlnx-zynqmp.h
> @@ -3,7 +3,7 @@
> * Xilinx Zynq MPSoC Firmware layer
> *
> * Copyright (C) 2014-2021 Xilinx
> - * Copyright (C) 2022 - 2025 Advanced Micro Devices, Inc.
> + * Copyright (C) 2022 - 2026 Advanced Micro Devices, Inc.
> *
> * Michal Simek <michal.simek@amd.com>
> * Davorin Mista <davorin.mista@aggios.com>
> @@ -66,6 +66,7 @@
> #define FIRMWARE_VERSION_MASK 0xFFFFU
>
> /* ATF only commands */
> +#define TF_A_CLEAR_PM_STATE 0xa05
> #define TF_A_PM_REGISTER_SGI 0xa04
> #define PM_GET_TRUSTZONE_VERSION 0xa03
> #define PM_SET_SUSPEND_MODE 0xa02
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH 2/4] firmware: xilinx: Release all peripheral devices from firmware
2026-07-23 12:48 [PATCH 0/4] firmware: xilinx: Clean up firmware and TF-A state on kexec Jay Buddhabhatti
2026-07-23 12:48 ` [PATCH 1/4] firmware: xilinx: Add support to clear TF-A PM state Jay Buddhabhatti
@ 2026-07-23 12:48 ` Jay Buddhabhatti
2026-07-23 16:25 ` Pandey, Radhey Shyam
2026-07-23 12:48 ` [PATCH 3/4] firmware: xilinx: Clear firmware notifiers across kexec transitions Jay Buddhabhatti
2026-07-23 12:48 ` [PATCH 4/4] firmware: xilinx: Use TF-A feature check for TF-A specific APIs Jay Buddhabhatti
3 siblings, 1 reply; 9+ messages in thread
From: Jay Buddhabhatti @ 2026-07-23 12:48 UTC (permalink / raw)
To: michal.simek, git; +Cc: linux-arm-kernel, linux-kernel, Jay Buddhabhatti
During a kexec restart, only the kernel is reloaded while devices
allocated in firmware persist, causing state mismatches between the
kernel and firmware.
Introduce PM_DEV_ALL_PERIPH node ID (0x18224FFFU) to release all
peripheral devices during kexec. On graceful restarts, this happens in
zynqmp_firmware_shutdown(). On crash kernel restarts, it happens in
zynqmp_firmware_probe() of the reloaded kernel.
Releasing all peripherals depends on firmware support for the
PM_DEV_ALL_PERIPH node ID. On firmware that does not implement it (the
feature check reports a version below PM_API_VERSION_3) the release is
skipped and a warning such as "Bulk device release is not supported by
firmware" is logged, e.g. on Versal NET firmware that predates this API.
Signed-off-by: Jay Buddhabhatti <jay.buddhabhatti@amd.com>
---
drivers/firmware/xilinx/zynqmp.c | 15 ++++++++++++++-
include/linux/firmware/xlnx-zynqmp.h | 4 ++++
2 files changed, 18 insertions(+), 1 deletion(-)
diff --git a/drivers/firmware/xilinx/zynqmp.c b/drivers/firmware/xilinx/zynqmp.c
index 95ffd8f33ce9..64d2109eefd2 100644
--- a/drivers/firmware/xilinx/zynqmp.c
+++ b/drivers/firmware/xilinx/zynqmp.c
@@ -2070,7 +2070,7 @@ ATTRIBUTE_GROUPS(zynqmp_firmware);
* zynqmp_clear_pm_state() - Clear subsystem state
* @dev: Device pointer used for logging
*
- * Clears PM specific data in TF-A.
+ * Clears PM specific data in TF-A and firmware.
*
* Return: Returns status, either success or error
*/
@@ -2097,6 +2097,19 @@ static int zynqmp_clear_pm_state(struct device *dev)
dev_warn(dev, "TF_A_CLEAR_PM_STATE is not supported in TF-A: %d\n", ret);
ret = 0;
}
+
+ /* Check if the firmware supports the PM_DEV_ALL_PERIPH node ID */
+ ret = do_feature_check_call(PM_RELEASE_NODE);
+ if (ret >= 0 && ((ret & FIRMWARE_VERSION_MASK) >= PM_API_VERSION_3)) {
+ /* Attempt to release all peripheral devices via firmware */
+ ret = zynqmp_pm_release_node(PM_DEV_ALL_PERIPH);
+ if (ret)
+ dev_err(dev, "Failed to release all peripheral devices: %d\n", ret);
+ } else {
+ dev_warn(dev,
+ "Bulk device release is not supported by firmware: %d\n", ret);
+ ret = 0;
+ }
}
return ret;
diff --git a/include/linux/firmware/xlnx-zynqmp.h b/include/linux/firmware/xlnx-zynqmp.h
index baaa88b0b197..ac39e5492961 100644
--- a/include/linux/firmware/xlnx-zynqmp.h
+++ b/include/linux/firmware/xlnx-zynqmp.h
@@ -50,6 +50,7 @@
/* PM API versions */
#define PM_API_VERSION_1 1
#define PM_API_VERSION_2 2
+#define PM_API_VERSION_3 3
#define PM_PINCTRL_PARAM_SET_VERSION 2
@@ -145,6 +146,9 @@
#define XPM_EVENT_ERROR_MASK_NOC_NCR BIT(13)
#define XPM_EVENT_ERROR_MASK_NOC_CR BIT(12)
+/* Node ID for all peripheral devices */
+#define PM_DEV_ALL_PERIPH 0x18224FFFU
+
enum pm_module_id {
PM_MODULE_ID = 0x0,
XPM_MODULE_ID = 0x2,
--
2.34.1
^ permalink raw reply related [flat|nested] 9+ messages in thread* Re: [PATCH 2/4] firmware: xilinx: Release all peripheral devices from firmware
2026-07-23 12:48 ` [PATCH 2/4] firmware: xilinx: Release all peripheral devices from firmware Jay Buddhabhatti
@ 2026-07-23 16:25 ` Pandey, Radhey Shyam
0 siblings, 0 replies; 9+ messages in thread
From: Pandey, Radhey Shyam @ 2026-07-23 16:25 UTC (permalink / raw)
To: Jay Buddhabhatti, michal.simek, git; +Cc: linux-arm-kernel, linux-kernel
On 7/23/2026 6:18 PM, Jay Buddhabhatti wrote:
> During a kexec restart, only the kernel is reloaded while devices
> allocated in firmware persist, causing state mismatches between the
> kernel and firmware.
>
> Introduce PM_DEV_ALL_PERIPH node ID (0x18224FFFU) to release all
> peripheral devices during kexec. On graceful restarts, this happens in
> zynqmp_firmware_shutdown(). On crash kernel restarts, it happens in
> zynqmp_firmware_probe() of the reloaded kernel.
>
> Releasing all peripherals depends on firmware support for the
> PM_DEV_ALL_PERIPH node ID. On firmware that does not implement it (the
> feature check reports a version below PM_API_VERSION_3) the release is
> skipped and a warning such as "Bulk device release is not supported by
> firmware" is logged, e.g. on Versal NET firmware that predates this API.
>
> Signed-off-by: Jay Buddhabhatti <jay.buddhabhatti@amd.com>
Reviewed-by: Radhey Shyam Pandey <radhey.shyam.pandey@amd.com>
Thanks!
> ---
> drivers/firmware/xilinx/zynqmp.c | 15 ++++++++++++++-
> include/linux/firmware/xlnx-zynqmp.h | 4 ++++
> 2 files changed, 18 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/firmware/xilinx/zynqmp.c b/drivers/firmware/xilinx/zynqmp.c
> index 95ffd8f33ce9..64d2109eefd2 100644
> --- a/drivers/firmware/xilinx/zynqmp.c
> +++ b/drivers/firmware/xilinx/zynqmp.c
> @@ -2070,7 +2070,7 @@ ATTRIBUTE_GROUPS(zynqmp_firmware);
> * zynqmp_clear_pm_state() - Clear subsystem state
> * @dev: Device pointer used for logging
> *
> - * Clears PM specific data in TF-A.
> + * Clears PM specific data in TF-A and firmware.
> *
> * Return: Returns status, either success or error
> */
> @@ -2097,6 +2097,19 @@ static int zynqmp_clear_pm_state(struct device *dev)
> dev_warn(dev, "TF_A_CLEAR_PM_STATE is not supported in TF-A: %d\n", ret);
> ret = 0;
> }
> +
> + /* Check if the firmware supports the PM_DEV_ALL_PERIPH node ID */
> + ret = do_feature_check_call(PM_RELEASE_NODE);
> + if (ret >= 0 && ((ret & FIRMWARE_VERSION_MASK) >= PM_API_VERSION_3)) {
> + /* Attempt to release all peripheral devices via firmware */
> + ret = zynqmp_pm_release_node(PM_DEV_ALL_PERIPH);
> + if (ret)
> + dev_err(dev, "Failed to release all peripheral devices: %d\n", ret);
> + } else {
> + dev_warn(dev,
> + "Bulk device release is not supported by firmware: %d\n", ret);
> + ret = 0;
> + }
> }
>
> return ret;
> diff --git a/include/linux/firmware/xlnx-zynqmp.h b/include/linux/firmware/xlnx-zynqmp.h
> index baaa88b0b197..ac39e5492961 100644
> --- a/include/linux/firmware/xlnx-zynqmp.h
> +++ b/include/linux/firmware/xlnx-zynqmp.h
> @@ -50,6 +50,7 @@
> /* PM API versions */
> #define PM_API_VERSION_1 1
> #define PM_API_VERSION_2 2
> +#define PM_API_VERSION_3 3
>
> #define PM_PINCTRL_PARAM_SET_VERSION 2
>
> @@ -145,6 +146,9 @@
> #define XPM_EVENT_ERROR_MASK_NOC_NCR BIT(13)
> #define XPM_EVENT_ERROR_MASK_NOC_CR BIT(12)
>
> +/* Node ID for all peripheral devices */
> +#define PM_DEV_ALL_PERIPH 0x18224FFFU
> +
> enum pm_module_id {
> PM_MODULE_ID = 0x0,
> XPM_MODULE_ID = 0x2,
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH 3/4] firmware: xilinx: Clear firmware notifiers across kexec transitions
2026-07-23 12:48 [PATCH 0/4] firmware: xilinx: Clean up firmware and TF-A state on kexec Jay Buddhabhatti
2026-07-23 12:48 ` [PATCH 1/4] firmware: xilinx: Add support to clear TF-A PM state Jay Buddhabhatti
2026-07-23 12:48 ` [PATCH 2/4] firmware: xilinx: Release all peripheral devices from firmware Jay Buddhabhatti
@ 2026-07-23 12:48 ` Jay Buddhabhatti
2026-07-23 16:27 ` Pandey, Radhey Shyam
2026-07-23 12:48 ` [PATCH 4/4] firmware: xilinx: Use TF-A feature check for TF-A specific APIs Jay Buddhabhatti
3 siblings, 1 reply; 9+ messages in thread
From: Jay Buddhabhatti @ 2026-07-23 12:48 UTC (permalink / raw)
To: michal.simek, git; +Cc: linux-arm-kernel, linux-kernel, Jay Buddhabhatti
During a kexec restart, only the kernel is reloaded but notifier callbacks
in firmware persist, causing state mismatches between kernel and firmware.
To address this, introduce PM_ALL_NOTIFIERS node ID to unregister all
notifier callbacks during kexec. On a graceful kexec restart, this occurs
in zynqmp_firmware_shutdown(). On a crash kernel restart, it happens in
zynqmp_firmware_probe() in the reloaded kernel.
Unregistering all notifiers depends on firmware support for the
PM_ALL_NOTIFIERS node ID. On firmware that does not implement it (the
feature check reports a version below PM_API_VERSION_3) the step is
skipped and a warning such as "Firmware doesn't support unregister all
notifiers at once" is logged, e.g. on Versal NET firmware that predates
this API.
Signed-off-by: Jay Buddhabhatti <jay.buddhabhatti@amd.com>
---
drivers/firmware/xilinx/zynqmp.c | 14 ++++++++++++++
include/linux/firmware/xlnx-zynqmp.h | 3 +++
2 files changed, 17 insertions(+)
diff --git a/drivers/firmware/xilinx/zynqmp.c b/drivers/firmware/xilinx/zynqmp.c
index 64d2109eefd2..fc7212f554ee 100644
--- a/drivers/firmware/xilinx/zynqmp.c
+++ b/drivers/firmware/xilinx/zynqmp.c
@@ -2110,6 +2110,20 @@ static int zynqmp_clear_pm_state(struct device *dev)
"Bulk device release is not supported by firmware: %d\n", ret);
ret = 0;
}
+
+ /* Check if the firmware supports the PM_ALL_NOTIFIERS node ID */
+ ret = do_feature_check_call(PM_REGISTER_NOTIFIER);
+ if (ret >= 0 && ((ret & FIRMWARE_VERSION_MASK) >= PM_API_VERSION_3)) {
+ /* Attempt to unregister all notifier callbacks via firmware */
+ ret = zynqmp_pm_register_notifier(PM_ALL_NOTIFIERS, 0, 0, 0);
+ if (ret)
+ dev_err(dev, "Failed to unregister all notifiers: %d\n", ret);
+ } else {
+ dev_warn(dev,
+ "Firmware doesn't support unregister all notifiers at once: %d\n",
+ ret);
+ ret = 0;
+ }
}
return ret;
diff --git a/include/linux/firmware/xlnx-zynqmp.h b/include/linux/firmware/xlnx-zynqmp.h
index ac39e5492961..69a2f74269f3 100644
--- a/include/linux/firmware/xlnx-zynqmp.h
+++ b/include/linux/firmware/xlnx-zynqmp.h
@@ -149,6 +149,9 @@
/* Node ID for all peripheral devices */
#define PM_DEV_ALL_PERIPH 0x18224FFFU
+/* Node ID for all notifier callbacks */
+#define PM_ALL_NOTIFIERS 0xFFFFFFFFU
+
enum pm_module_id {
PM_MODULE_ID = 0x0,
XPM_MODULE_ID = 0x2,
--
2.34.1
^ permalink raw reply related [flat|nested] 9+ messages in thread* Re: [PATCH 3/4] firmware: xilinx: Clear firmware notifiers across kexec transitions
2026-07-23 12:48 ` [PATCH 3/4] firmware: xilinx: Clear firmware notifiers across kexec transitions Jay Buddhabhatti
@ 2026-07-23 16:27 ` Pandey, Radhey Shyam
0 siblings, 0 replies; 9+ messages in thread
From: Pandey, Radhey Shyam @ 2026-07-23 16:27 UTC (permalink / raw)
To: Jay Buddhabhatti, michal.simek, git; +Cc: linux-arm-kernel, linux-kernel
On 7/23/2026 6:18 PM, Jay Buddhabhatti wrote:
> During a kexec restart, only the kernel is reloaded but notifier callbacks
> in firmware persist, causing state mismatches between kernel and firmware.
>
> To address this, introduce PM_ALL_NOTIFIERS node ID to unregister all
> notifier callbacks during kexec. On a graceful kexec restart, this occurs
> in zynqmp_firmware_shutdown(). On a crash kernel restart, it happens in
> zynqmp_firmware_probe() in the reloaded kernel.
>
> Unregistering all notifiers depends on firmware support for the
> PM_ALL_NOTIFIERS node ID. On firmware that does not implement it (the
> feature check reports a version below PM_API_VERSION_3) the step is
> skipped and a warning such as "Firmware doesn't support unregister all
> notifiers at once" is logged, e.g. on Versal NET firmware that predates
> this API.
>
> Signed-off-by: Jay Buddhabhatti <jay.buddhabhatti@amd.com>
Reviewed-by: Radhey Shyam Pandey <radhey.shyam.pandey@amd.com>
Thanks!
> ---
> drivers/firmware/xilinx/zynqmp.c | 14 ++++++++++++++
> include/linux/firmware/xlnx-zynqmp.h | 3 +++
> 2 files changed, 17 insertions(+)
>
> diff --git a/drivers/firmware/xilinx/zynqmp.c b/drivers/firmware/xilinx/zynqmp.c
> index 64d2109eefd2..fc7212f554ee 100644
> --- a/drivers/firmware/xilinx/zynqmp.c
> +++ b/drivers/firmware/xilinx/zynqmp.c
> @@ -2110,6 +2110,20 @@ static int zynqmp_clear_pm_state(struct device *dev)
> "Bulk device release is not supported by firmware: %d\n", ret);
> ret = 0;
> }
> +
> + /* Check if the firmware supports the PM_ALL_NOTIFIERS node ID */
> + ret = do_feature_check_call(PM_REGISTER_NOTIFIER);
> + if (ret >= 0 && ((ret & FIRMWARE_VERSION_MASK) >= PM_API_VERSION_3)) {
> + /* Attempt to unregister all notifier callbacks via firmware */
> + ret = zynqmp_pm_register_notifier(PM_ALL_NOTIFIERS, 0, 0, 0);
> + if (ret)
> + dev_err(dev, "Failed to unregister all notifiers: %d\n", ret);
> + } else {
> + dev_warn(dev,
> + "Firmware doesn't support unregister all notifiers at once: %d\n",
> + ret);
> + ret = 0;
> + }
> }
>
> return ret;
> diff --git a/include/linux/firmware/xlnx-zynqmp.h b/include/linux/firmware/xlnx-zynqmp.h
> index ac39e5492961..69a2f74269f3 100644
> --- a/include/linux/firmware/xlnx-zynqmp.h
> +++ b/include/linux/firmware/xlnx-zynqmp.h
> @@ -149,6 +149,9 @@
> /* Node ID for all peripheral devices */
> #define PM_DEV_ALL_PERIPH 0x18224FFFU
>
> +/* Node ID for all notifier callbacks */
> +#define PM_ALL_NOTIFIERS 0xFFFFFFFFU
> +
> enum pm_module_id {
> PM_MODULE_ID = 0x0,
> XPM_MODULE_ID = 0x2,
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH 4/4] firmware: xilinx: Use TF-A feature check for TF-A specific APIs
2026-07-23 12:48 [PATCH 0/4] firmware: xilinx: Clean up firmware and TF-A state on kexec Jay Buddhabhatti
` (2 preceding siblings ...)
2026-07-23 12:48 ` [PATCH 3/4] firmware: xilinx: Clear firmware notifiers across kexec transitions Jay Buddhabhatti
@ 2026-07-23 12:48 ` Jay Buddhabhatti
2026-07-23 16:28 ` Pandey, Radhey Shyam
3 siblings, 1 reply; 9+ messages in thread
From: Jay Buddhabhatti @ 2026-07-23 12:48 UTC (permalink / raw)
To: michal.simek, git; +Cc: linux-arm-kernel, linux-kernel, Jay Buddhabhatti
Currently, TF-A-specific APIs are validated using the firmware
PM_FEATURE_CHECK API, even though TF-A provides a dedicated mechanism via
PM_API_FEATURES API. Ideally it should use the TF-A feature check
(PM_API_FEATURES) for TF-A specific APIs. Update the feature check logic
for TF-A specific API calls to ensure it is validated using
PM_API_FEATURES. If this check fails, fall back to the legacy
PM_FEATURE_CHECK to support backward compatibility.
When do_fw_call() fails, propagate the errno from zynqmp_pm_ret_code()
instead of always returning -EOPNOTSUPP. This applies to every module ID,
not only TF-A, because the rewrite sat in the common failure path.
Existing callers only test ret < 0 and are unchanged.
Signed-off-by: Jay Buddhabhatti <jay.buddhabhatti@amd.com>
---
drivers/firmware/xilinx/zynqmp.c | 31 +++++++++++++++++--------------
1 file changed, 17 insertions(+), 14 deletions(-)
diff --git a/drivers/firmware/xilinx/zynqmp.c b/drivers/firmware/xilinx/zynqmp.c
index fc7212f554ee..0b6c20a1d8be 100644
--- a/drivers/firmware/xilinx/zynqmp.c
+++ b/drivers/firmware/xilinx/zynqmp.c
@@ -224,34 +224,37 @@ static int __do_feature_check_call(const u32 api_id, u32 *ret_payload)
module_id = FIELD_GET(MODULE_ID_MASK, api_id);
/*
- * Feature check of APIs belonging to PM, XSEM, and TF-A are handled by calling
+ * Feature check of APIs belonging to PM and XSEM are handled by calling
* PM_FEATURE_CHECK API. For other modules, call PM_API_FEATURES API.
*/
- if (module_id == PM_MODULE_ID || module_id == XSEM_MODULE_ID || module_id == TF_A_MODULE_ID)
+ if (module_id == PM_MODULE_ID || module_id == XSEM_MODULE_ID)
feature_check_api_id = PM_FEATURE_CHECK;
else
feature_check_api_id = PM_API_FEATURES;
- /*
- * Feature check of TF-A APIs is done in the TF-A layer and it expects for
- * MODULE_ID_MASK bits of SMC's arg[0] to be the same as PM_MODULE_ID.
- */
- if (module_id == TF_A_MODULE_ID) {
- module_id = PM_MODULE_ID;
+ if (module_id == TF_A_MODULE_ID)
smc_arg[1] = api_id;
- } else {
+ else
smc_arg[1] = (api_id & API_ID_MASK);
- }
smc_arg[0] = PM_SIP_SVC | FIELD_PREP(MODULE_ID_MASK, module_id) | feature_check_api_id;
ret = do_fw_call(ret_payload, 2, smc_arg[0], smc_arg[1]);
+
+ /*
+ * For TF-A APIs, if the feature check with PM_API_FEATURES fails,
+ * retry with the legacy PM_FEATURE_CHECK for backward compatibility.
+ */
+ if (module_id == TF_A_MODULE_ID && ret) {
+ smc_arg[0] = PM_SIP_SVC | FIELD_PREP(MODULE_ID_MASK, PM_MODULE_ID) |
+ PM_FEATURE_CHECK;
+ ret = do_fw_call(ret_payload, 2, smc_arg[0], smc_arg[1]);
+ }
+
if (ret)
- ret = -EOPNOTSUPP;
- else
- ret = ret_payload[1];
+ return ret;
- return ret;
+ return ret_payload[1];
}
static int do_feature_check_call(const u32 api_id)
--
2.34.1
^ permalink raw reply related [flat|nested] 9+ messages in thread* Re: [PATCH 4/4] firmware: xilinx: Use TF-A feature check for TF-A specific APIs
2026-07-23 12:48 ` [PATCH 4/4] firmware: xilinx: Use TF-A feature check for TF-A specific APIs Jay Buddhabhatti
@ 2026-07-23 16:28 ` Pandey, Radhey Shyam
0 siblings, 0 replies; 9+ messages in thread
From: Pandey, Radhey Shyam @ 2026-07-23 16:28 UTC (permalink / raw)
To: Jay Buddhabhatti, michal.simek, git; +Cc: linux-arm-kernel, linux-kernel
On 7/23/2026 6:18 PM, Jay Buddhabhatti wrote:
> Currently, TF-A-specific APIs are validated using the firmware
> PM_FEATURE_CHECK API, even though TF-A provides a dedicated mechanism via
> PM_API_FEATURES API. Ideally it should use the TF-A feature check
> (PM_API_FEATURES) for TF-A specific APIs. Update the feature check logic
> for TF-A specific API calls to ensure it is validated using
> PM_API_FEATURES. If this check fails, fall back to the legacy
> PM_FEATURE_CHECK to support backward compatibility.
>
> When do_fw_call() fails, propagate the errno from zynqmp_pm_ret_code()
> instead of always returning -EOPNOTSUPP. This applies to every module ID,
> not only TF-A, because the rewrite sat in the common failure path.
> Existing callers only test ret < 0 and are unchanged.
>
> Signed-off-by: Jay Buddhabhatti <jay.buddhabhatti@amd.com>
Reviewed-by: Radhey Shyam Pandey <radhey.shyam.pandey@amd.com>
Thanks!
> ---
> drivers/firmware/xilinx/zynqmp.c | 31 +++++++++++++++++--------------
> 1 file changed, 17 insertions(+), 14 deletions(-)
>
> diff --git a/drivers/firmware/xilinx/zynqmp.c b/drivers/firmware/xilinx/zynqmp.c
> index fc7212f554ee..0b6c20a1d8be 100644
> --- a/drivers/firmware/xilinx/zynqmp.c
> +++ b/drivers/firmware/xilinx/zynqmp.c
> @@ -224,34 +224,37 @@ static int __do_feature_check_call(const u32 api_id, u32 *ret_payload)
> module_id = FIELD_GET(MODULE_ID_MASK, api_id);
>
> /*
> - * Feature check of APIs belonging to PM, XSEM, and TF-A are handled by calling
> + * Feature check of APIs belonging to PM and XSEM are handled by calling
> * PM_FEATURE_CHECK API. For other modules, call PM_API_FEATURES API.
> */
> - if (module_id == PM_MODULE_ID || module_id == XSEM_MODULE_ID || module_id == TF_A_MODULE_ID)
> + if (module_id == PM_MODULE_ID || module_id == XSEM_MODULE_ID)
> feature_check_api_id = PM_FEATURE_CHECK;
> else
> feature_check_api_id = PM_API_FEATURES;
>
> - /*
> - * Feature check of TF-A APIs is done in the TF-A layer and it expects for
> - * MODULE_ID_MASK bits of SMC's arg[0] to be the same as PM_MODULE_ID.
> - */
> - if (module_id == TF_A_MODULE_ID) {
> - module_id = PM_MODULE_ID;
> + if (module_id == TF_A_MODULE_ID)
> smc_arg[1] = api_id;
> - } else {
> + else
> smc_arg[1] = (api_id & API_ID_MASK);
> - }
>
> smc_arg[0] = PM_SIP_SVC | FIELD_PREP(MODULE_ID_MASK, module_id) | feature_check_api_id;
>
> ret = do_fw_call(ret_payload, 2, smc_arg[0], smc_arg[1]);
> +
> + /*
> + * For TF-A APIs, if the feature check with PM_API_FEATURES fails,
> + * retry with the legacy PM_FEATURE_CHECK for backward compatibility.
> + */
> + if (module_id == TF_A_MODULE_ID && ret) {
> + smc_arg[0] = PM_SIP_SVC | FIELD_PREP(MODULE_ID_MASK, PM_MODULE_ID) |
> + PM_FEATURE_CHECK;
> + ret = do_fw_call(ret_payload, 2, smc_arg[0], smc_arg[1]);
> + }
> +
> if (ret)
> - ret = -EOPNOTSUPP;
> - else
> - ret = ret_payload[1];
> + return ret;
>
> - return ret;
> + return ret_payload[1];
> }
>
> static int do_feature_check_call(const u32 api_id)
^ permalink raw reply [flat|nested] 9+ messages in thread